Repository: twitter/rubyenterpriseedition187-248 Branch: master Commit: 038589224a2d Files: 2669 Total size: 22.2 MB Directory structure: gitextract_y48zaq3k/ ├── .cvsignore ├── .document ├── .gitignore ├── COPYING ├── COPYING.ja ├── ChangeLog ├── GPL ├── LEGAL ├── LGPL ├── Makefile.in ├── NEWS ├── README ├── README-kiji ├── README.EXT ├── README.EXT.ja ├── README.ja ├── Rakefile ├── ToDo ├── array.c ├── b/ │ └── source/ │ └── stack_free_safe.sh ├── bcc32/ │ ├── Makefile.sub │ ├── README.bcc32 │ ├── configure.bat │ ├── mkexports.rb │ └── setup.mak ├── bignum.c ├── bin/ │ ├── erb │ ├── irb │ ├── rdoc │ ├── ri │ └── testrb ├── class.c ├── common.mk ├── compar.c ├── config.guess ├── config.sub ├── configure.in ├── cygwin/ │ └── GNUmakefile.in ├── defines.h ├── dir.c ├── distro/ │ ├── debian/ │ │ ├── compat │ │ ├── control │ │ ├── postinst │ │ └── prerm │ ├── dependencies.rb │ ├── documentation.txt │ ├── google-perftools-1.7/ │ │ ├── AUTHORS │ │ ├── COPYING │ │ ├── ChangeLog │ │ ├── INSTALL │ │ ├── Makefile.am │ │ ├── Makefile.in │ │ ├── NEWS │ │ ├── README │ │ ├── README_windows.txt │ │ ├── TODO │ │ ├── aclocal.m4 │ │ ├── compile │ │ ├── config.guess │ │ ├── config.sub │ │ ├── configure │ │ ├── configure.ac │ │ ├── depcomp │ │ ├── doc/ │ │ │ ├── cpuprofile-fileformat.html │ │ │ ├── cpuprofile.html │ │ │ ├── designstyle.css │ │ │ ├── heap_checker.html │ │ │ ├── heapprofile.html │ │ │ ├── index.html │ │ │ ├── overview.dot │ │ │ ├── pageheap.dot │ │ │ ├── pprof.1 │ │ │ ├── pprof_remote_servers.html │ │ │ ├── spanmap.dot │ │ │ ├── t-test1.times.txt │ │ │ ├── tcmalloc.html │ │ │ └── threadheap.dot │ │ ├── google-perftools.sln │ │ ├── install-sh │ │ ├── libtool │ │ ├── ltmain.sh │ │ ├── m4/ │ │ │ ├── ac_have_attribute.m4 │ │ │ ├── acx_nanosleep.m4 │ │ │ ├── acx_pthread.m4 │ │ │ ├── compiler_characteristics.m4 │ │ │ ├── install_prefix.m4 │ │ │ ├── libtool.m4 │ │ │ ├── ltoptions.m4 │ │ │ ├── ltsugar.m4 │ │ │ ├── ltversion.m4 │ │ │ ├── lt~obsolete.m4 │ │ │ ├── namespaces.m4 │ │ │ ├── pc_from_ucontext.m4 │ │ │ ├── program_invocation_name.m4 │ │ │ └── stl_namespace.m4 │ │ ├── missing │ │ ├── mkinstalldirs │ │ ├── packages/ │ │ │ ├── deb/ │ │ │ │ ├── README │ │ │ │ ├── changelog │ │ │ │ ├── compat │ │ │ │ ├── control │ │ │ │ ├── copyright │ │ │ │ ├── docs │ │ │ │ ├── libgoogle-perftools-dev.dirs │ │ │ │ ├── libgoogle-perftools-dev.install │ │ │ │ ├── libgoogle-perftools0.dirs │ │ │ │ ├── libgoogle-perftools0.install │ │ │ │ ├── libgoogle-perftools0.manpages │ │ │ │ └── rules │ │ │ ├── deb.sh │ │ │ ├── rpm/ │ │ │ │ └── rpm.spec │ │ │ └── rpm.sh │ │ ├── src/ │ │ │ ├── addressmap-inl.h │ │ │ ├── base/ │ │ │ │ ├── atomicops-internals-arm-gcc.h │ │ │ │ ├── atomicops-internals-linuxppc.h │ │ │ │ ├── atomicops-internals-macosx.h │ │ │ │ ├── atomicops-internals-x86-msvc.h │ │ │ │ ├── atomicops-internals-x86.cc │ │ │ │ ├── atomicops-internals-x86.h │ │ │ │ ├── atomicops.h │ │ │ │ ├── basictypes.h │ │ │ │ ├── commandlineflags.h │ │ │ │ ├── cycleclock.h │ │ │ │ ├── dynamic_annotations.c │ │ │ │ ├── dynamic_annotations.h │ │ │ │ ├── elfcore.h │ │ │ │ ├── googleinit.h │ │ │ │ ├── linux_syscall_support.h │ │ │ │ ├── linuxthreads.cc │ │ │ │ ├── linuxthreads.h │ │ │ │ ├── logging.cc │ │ │ │ ├── logging.h │ │ │ │ ├── low_level_alloc.cc │ │ │ │ ├── low_level_alloc.h │ │ │ │ ├── simple_mutex.h │ │ │ │ ├── spinlock.cc │ │ │ │ ├── spinlock.h │ │ │ │ ├── spinlock_internal.cc │ │ │ │ ├── spinlock_internal.h │ │ │ │ ├── spinlock_linux-inl.h │ │ │ │ ├── spinlock_posix-inl.h │ │ │ │ ├── spinlock_win32-inl.h │ │ │ │ ├── stl_allocator.h │ │ │ │ ├── synchronization_profiling.h │ │ │ │ ├── sysinfo.cc │ │ │ │ ├── sysinfo.h │ │ │ │ ├── thread_annotations.h │ │ │ │ ├── thread_lister.c │ │ │ │ ├── thread_lister.h │ │ │ │ ├── vdso_support.cc │ │ │ │ └── vdso_support.h │ │ │ ├── central_freelist.cc │ │ │ ├── central_freelist.h │ │ │ ├── common.cc │ │ │ ├── common.h │ │ │ ├── config.h.in │ │ │ ├── config_for_unittests.h │ │ │ ├── debugallocation.cc │ │ │ ├── getpc.h │ │ │ ├── google/ │ │ │ │ ├── heap-checker.h │ │ │ │ ├── heap-profiler.h │ │ │ │ ├── malloc_extension.h │ │ │ │ ├── malloc_extension_c.h │ │ │ │ ├── malloc_hook.h │ │ │ │ ├── malloc_hook_c.h │ │ │ │ ├── profiler.h │ │ │ │ ├── stacktrace.h │ │ │ │ └── tcmalloc.h.in │ │ │ ├── heap-checker-bcad.cc │ │ │ ├── heap-checker.cc │ │ │ ├── heap-profile-table.cc │ │ │ ├── heap-profile-table.h │ │ │ ├── heap-profiler.cc │ │ │ ├── internal_logging.cc │ │ │ ├── internal_logging.h │ │ │ ├── linked_list.h │ │ │ ├── malloc_extension.cc │ │ │ ├── malloc_hook-inl.h │ │ │ ├── malloc_hook.cc │ │ │ ├── maybe_threads.cc │ │ │ ├── maybe_threads.h │ │ │ ├── memfs_malloc.cc │ │ │ ├── memory_region_map.cc │ │ │ ├── memory_region_map.h │ │ │ ├── packed-cache-inl.h │ │ │ ├── page_heap.cc │ │ │ ├── page_heap.h │ │ │ ├── page_heap_allocator.h │ │ │ ├── pagemap.h │ │ │ ├── pprof │ │ │ ├── profile-handler.cc │ │ │ ├── profile-handler.h │ │ │ ├── profiledata.cc │ │ │ ├── profiledata.h │ │ │ ├── profiler.cc │ │ │ ├── raw_printer.cc │ │ │ ├── raw_printer.h │ │ │ ├── sampler.cc │ │ │ ├── sampler.h │ │ │ ├── solaris/ │ │ │ │ └── libstdc++.la │ │ │ ├── span.cc │ │ │ ├── span.h │ │ │ ├── stack_trace_table.cc │ │ │ ├── stack_trace_table.h │ │ │ ├── stacktrace.cc │ │ │ ├── stacktrace_config.h │ │ │ ├── stacktrace_generic-inl.h │ │ │ ├── stacktrace_libunwind-inl.h │ │ │ ├── stacktrace_powerpc-inl.h │ │ │ ├── stacktrace_win32-inl.h │ │ │ ├── stacktrace_x86-inl.h │ │ │ ├── stacktrace_x86_64-inl.h │ │ │ ├── static_vars.cc │ │ │ ├── static_vars.h │ │ │ ├── symbolize.cc │ │ │ ├── symbolize.h │ │ │ ├── system-alloc.cc │ │ │ ├── system-alloc.h │ │ │ ├── tcmalloc.cc │ │ │ ├── tcmalloc.h │ │ │ ├── tcmalloc_guard.h │ │ │ ├── tests/ │ │ │ │ ├── addressmap_unittest.cc │ │ │ │ ├── atomicops_unittest.cc │ │ │ │ ├── debugallocation_test.cc │ │ │ │ ├── debugallocation_test.sh │ │ │ │ ├── frag_unittest.cc │ │ │ │ ├── getpc_test.cc │ │ │ │ ├── heap-checker-death_unittest.sh │ │ │ │ ├── heap-checker_unittest.cc │ │ │ │ ├── heap-checker_unittest.sh │ │ │ │ ├── heap-profiler_unittest.cc │ │ │ │ ├── heap-profiler_unittest.sh │ │ │ │ ├── low_level_alloc_unittest.cc │ │ │ │ ├── malloc_extension_c_test.c │ │ │ │ ├── malloc_extension_test.cc │ │ │ │ ├── markidle_unittest.cc │ │ │ │ ├── maybe_threads_unittest.sh │ │ │ │ ├── memalign_unittest.cc │ │ │ │ ├── packed-cache_test.cc │ │ │ │ ├── page_heap_test.cc │ │ │ │ ├── pagemap_unittest.cc │ │ │ │ ├── profile-handler_unittest.cc │ │ │ │ ├── profiledata_unittest.cc │ │ │ │ ├── profiler_unittest.cc │ │ │ │ ├── profiler_unittest.sh │ │ │ │ ├── raw_printer_test.cc │ │ │ │ ├── realloc_unittest.cc │ │ │ │ ├── sampler_test.cc │ │ │ │ ├── sampling_test.cc │ │ │ │ ├── sampling_test.sh │ │ │ │ ├── stack_trace_table_test.cc │ │ │ │ ├── stacktrace_unittest.cc │ │ │ │ ├── system-alloc_unittest.cc │ │ │ │ ├── tcmalloc_large_unittest.cc │ │ │ │ ├── tcmalloc_unittest.cc │ │ │ │ ├── testutil.cc │ │ │ │ ├── testutil.h │ │ │ │ └── thread_dealloc_unittest.cc │ │ │ ├── third_party/ │ │ │ │ └── valgrind.h │ │ │ ├── thread_cache.cc │ │ │ ├── thread_cache.h │ │ │ └── windows/ │ │ │ ├── addr2line-pdb.c │ │ │ ├── get_mangled_names.cc │ │ │ ├── google/ │ │ │ │ └── tcmalloc.h │ │ │ ├── ia32_modrm_map.cc │ │ │ ├── ia32_opcode_map.cc │ │ │ ├── mingw.h │ │ │ ├── mini_disassembler.cc │ │ │ ├── mini_disassembler.h │ │ │ ├── mini_disassembler_types.h │ │ │ ├── nm-pdb.c │ │ │ ├── override_functions.cc │ │ │ ├── patch_functions.cc │ │ │ ├── port.cc │ │ │ ├── port.h │ │ │ ├── preamble_patcher.cc │ │ │ ├── preamble_patcher.h │ │ │ └── preamble_patcher_with_stub.cc │ │ └── vsprojects/ │ │ ├── addr2line-pdb/ │ │ │ └── addr2line-pdb.vcproj │ │ ├── addressmap_unittest/ │ │ │ └── addressmap_unittest.vcproj │ │ ├── frag_unittest/ │ │ │ └── frag_unittest.vcproj │ │ ├── libtcmalloc_minimal/ │ │ │ └── libtcmalloc_minimal.vcproj │ │ ├── low_level_alloc_unittest/ │ │ │ └── low_level_alloc_unittest.vcproj │ │ ├── malloc_extension_test/ │ │ │ └── malloc_extension_test.vcproj │ │ ├── markidle_unittest/ │ │ │ └── markidle_unittest.vcproj │ │ ├── nm-pdb/ │ │ │ └── nm-pdb.vcproj │ │ ├── packed-cache_test/ │ │ │ └── packed-cache_test.vcproj │ │ ├── page_heap_test/ │ │ │ └── page_heap_test.vcproj │ │ ├── pagemap_unittest/ │ │ │ └── pagemap_unittest.vcproj │ │ ├── realloc_unittest/ │ │ │ └── realloc_unittest.vcproj │ │ ├── sampler_test/ │ │ │ └── sampler_test.vcproj │ │ ├── stack_trace_table_test/ │ │ │ └── stack_trace_table_test.vcproj │ │ ├── tcmalloc_minimal_large/ │ │ │ └── tcmalloc_minimal_large_unittest.vcproj │ │ ├── tcmalloc_minimal_unittest/ │ │ │ └── tcmalloc_minimal_unittest.vcproj │ │ ├── thread_dealloc_unittest/ │ │ │ └── thread_dealloc_unittest.vcproj │ │ └── tmu-static/ │ │ └── tmu-static.vcproj │ ├── installer │ ├── installer.rb │ ├── optparse.rb │ ├── platform_info.rb │ ├── runtime/ │ │ ├── FreeBSD-amd64/ │ │ │ └── ruby │ │ ├── FreeBSD-i386/ │ │ │ └── ruby │ │ ├── Linux-i386/ │ │ │ └── ruby │ │ ├── Linux-x86_64/ │ │ │ └── ruby │ │ └── SunOS-sun4v/ │ │ └── ruby │ └── tasks.rb ├── distruby.rb ├── djgpp/ │ ├── GNUmakefile.in │ ├── README.djgpp │ ├── config.hin │ ├── config.sed │ ├── configure.bat │ └── mkver.sed ├── dln.c ├── dln.h ├── dmydln.c ├── dmyext.c ├── doc/ │ ├── ChangeLog-1.8.0 │ ├── NEWS-1.8.0 │ ├── forwardable.rd │ ├── forwardable.rd.ja │ ├── irb/ │ │ ├── irb-tools.rd.ja │ │ ├── irb.rd │ │ └── irb.rd.ja │ ├── shell.rd │ └── shell.rd.ja ├── enum.c ├── enumerator.c ├── env.h ├── error.c ├── eval.c ├── ext/ │ ├── .cvsignore │ ├── .document │ ├── Setup │ ├── Setup.atheos │ ├── Setup.dj │ ├── Setup.emx │ ├── Setup.nt │ ├── Setup.x68 │ ├── Win32API/ │ │ ├── .cvsignore │ │ ├── Win32API.c │ │ ├── depend │ │ ├── extconf.rb │ │ ├── getch.rb │ │ ├── lib/ │ │ │ └── win32/ │ │ │ ├── registry.rb │ │ │ └── resolv.rb │ │ └── point.rb │ ├── bigdecimal/ │ │ ├── .cvsignore │ │ ├── README │ │ ├── bigdecimal.c │ │ ├── bigdecimal.def │ │ ├── bigdecimal.h │ │ ├── bigdecimal_en.html │ │ ├── bigdecimal_ja.html │ │ ├── depend │ │ ├── extconf.rb │ │ ├── lib/ │ │ │ └── bigdecimal/ │ │ │ ├── jacobian.rb │ │ │ ├── ludcmp.rb │ │ │ ├── math.rb │ │ │ ├── newton.rb │ │ │ └── util.rb │ │ └── sample/ │ │ ├── linear.rb │ │ ├── nlsolve.rb │ │ └── pi.rb │ ├── curses/ │ │ ├── .cvsignore │ │ ├── curses.c │ │ ├── depend │ │ ├── extconf.rb │ │ ├── hello.rb │ │ ├── mouse.rb │ │ ├── rain.rb │ │ ├── view.rb │ │ └── view2.rb │ ├── dbm/ │ │ ├── .cvsignore │ │ ├── dbm.c │ │ ├── depend │ │ └── extconf.rb │ ├── digest/ │ │ ├── .cvsignore │ │ ├── bubblebabble/ │ │ │ ├── .cvsignore │ │ │ ├── bubblebabble.c │ │ │ ├── depend │ │ │ └── extconf.rb │ │ ├── defs.h │ │ ├── depend │ │ ├── digest.c │ │ ├── digest.h │ │ ├── extconf.rb │ │ ├── lib/ │ │ │ ├── digest.rb │ │ │ ├── md5.rb │ │ │ └── sha1.rb │ │ ├── md5/ │ │ │ ├── .cvsignore │ │ │ ├── depend │ │ │ ├── extconf.rb │ │ │ ├── md5.c │ │ │ ├── md5.h │ │ │ ├── md5init.c │ │ │ ├── md5ossl.c │ │ │ └── md5ossl.h │ │ ├── rmd160/ │ │ │ ├── .cvsignore │ │ │ ├── depend │ │ │ ├── extconf.rb │ │ │ ├── rmd160.c │ │ │ ├── rmd160.h │ │ │ ├── rmd160init.c │ │ │ ├── rmd160ossl.c │ │ │ └── rmd160ossl.h │ │ ├── sha1/ │ │ │ ├── .cvsignore │ │ │ ├── depend │ │ │ ├── extconf.rb │ │ │ ├── sha1.c │ │ │ ├── sha1.h │ │ │ ├── sha1init.c │ │ │ ├── sha1ossl.c │ │ │ └── sha1ossl.h │ │ ├── sha2/ │ │ │ ├── .cvsignore │ │ │ ├── depend │ │ │ ├── extconf.rb │ │ │ ├── lib/ │ │ │ │ └── sha2.rb │ │ │ ├── sha2.c │ │ │ ├── sha2.h │ │ │ └── sha2init.c │ │ └── test.sh │ ├── dl/ │ │ ├── .cvsignore │ │ ├── depend │ │ ├── dl.c │ │ ├── dl.def │ │ ├── dl.h │ │ ├── doc/ │ │ │ └── dl.txt │ │ ├── extconf.rb │ │ ├── h2rb │ │ ├── handle.c │ │ ├── install.rb │ │ ├── lib/ │ │ │ └── dl/ │ │ │ ├── import.rb │ │ │ ├── struct.rb │ │ │ ├── types.rb │ │ │ └── win32.rb │ │ ├── mkcall.rb │ │ ├── mkcallback.rb │ │ ├── mkcbtable.rb │ │ ├── ptr.c │ │ ├── sample/ │ │ │ ├── c++sample.C │ │ │ ├── c++sample.rb │ │ │ ├── drives.rb │ │ │ ├── getch.rb │ │ │ ├── libc.rb │ │ │ ├── msgbox.rb │ │ │ ├── msgbox2.rb │ │ │ └── stream.rb │ │ ├── sym.c │ │ ├── test/ │ │ │ ├── libtest.def │ │ │ ├── test.c │ │ │ └── test.rb │ │ └── type.rb │ ├── etc/ │ │ ├── .cvsignore │ │ ├── depend │ │ ├── etc.c │ │ ├── etc.txt │ │ ├── etc.txt.ja │ │ └── extconf.rb │ ├── extmk.rb │ ├── fcntl/ │ │ ├── .cvsignore │ │ ├── depend │ │ ├── extconf.rb │ │ └── fcntl.c │ ├── gdbm/ │ │ ├── .cvsignore │ │ ├── README │ │ ├── depend │ │ ├── extconf.rb │ │ └── gdbm.c │ ├── iconv/ │ │ ├── .cvsignore │ │ ├── charset_alias.rb │ │ ├── depend │ │ ├── extconf.rb │ │ └── iconv.c │ ├── io/ │ │ └── wait/ │ │ ├── .cvsignore │ │ ├── extconf.rb │ │ ├── lib/ │ │ │ └── nonblock.rb │ │ └── wait.c │ ├── nkf/ │ │ ├── .cvsignore │ │ ├── depend │ │ ├── extconf.rb │ │ ├── lib/ │ │ │ └── kconv.rb │ │ ├── nkf-utf8/ │ │ │ ├── nkf.c │ │ │ ├── utf8tbl.c │ │ │ └── utf8tbl.h │ │ └── nkf.c │ ├── openssl/ │ │ ├── .cvsignore │ │ ├── extconf.rb │ │ ├── lib/ │ │ │ ├── net/ │ │ │ │ ├── ftptls.rb │ │ │ │ └── telnets.rb │ │ │ ├── openssl/ │ │ │ │ ├── bn.rb │ │ │ │ ├── buffering.rb │ │ │ │ ├── cipher.rb │ │ │ │ ├── digest.rb │ │ │ │ ├── pkcs7.rb │ │ │ │ ├── ssl.rb │ │ │ │ └── x509.rb │ │ │ └── openssl.rb │ │ ├── openssl_missing.c │ │ ├── openssl_missing.h │ │ ├── ossl.c │ │ ├── ossl.h │ │ ├── ossl_asn1.c │ │ ├── ossl_asn1.h │ │ ├── ossl_bio.c │ │ ├── ossl_bio.h │ │ ├── ossl_bn.c │ │ ├── ossl_bn.h │ │ ├── ossl_cipher.c │ │ ├── ossl_cipher.h │ │ ├── ossl_config.c │ │ ├── ossl_config.h │ │ ├── ossl_digest.c │ │ ├── ossl_digest.h │ │ ├── ossl_engine.c │ │ ├── ossl_engine.h │ │ ├── ossl_hmac.c │ │ ├── ossl_hmac.h │ │ ├── ossl_ns_spki.c │ │ ├── ossl_ns_spki.h │ │ ├── ossl_ocsp.c │ │ ├── ossl_ocsp.h │ │ ├── ossl_pkcs12.c │ │ ├── ossl_pkcs12.h │ │ ├── ossl_pkcs5.c │ │ ├── ossl_pkcs5.h │ │ ├── ossl_pkcs7.c │ │ ├── ossl_pkcs7.h │ │ ├── ossl_pkey.c │ │ ├── ossl_pkey.h │ │ ├── ossl_pkey_dh.c │ │ ├── ossl_pkey_dsa.c │ │ ├── ossl_pkey_ec.c │ │ ├── ossl_pkey_rsa.c │ │ ├── ossl_rand.c │ │ ├── ossl_rand.h │ │ ├── ossl_ssl.c │ │ ├── ossl_ssl.h │ │ ├── ossl_ssl_session.c │ │ ├── ossl_version.h │ │ ├── ossl_x509.c │ │ ├── ossl_x509.h │ │ ├── ossl_x509attr.c │ │ ├── ossl_x509cert.c │ │ ├── ossl_x509crl.c │ │ ├── ossl_x509ext.c │ │ ├── ossl_x509name.c │ │ ├── ossl_x509req.c │ │ ├── ossl_x509revoked.c │ │ ├── ossl_x509store.c │ │ └── ruby_missing.h │ ├── pty/ │ │ ├── .cvsignore │ │ ├── README │ │ ├── README.expect │ │ ├── README.expect.ja │ │ ├── README.ja │ │ ├── depend │ │ ├── expect_sample.rb │ │ ├── extconf.rb │ │ ├── lib/ │ │ │ └── expect.rb │ │ ├── pty.c │ │ ├── script.rb │ │ └── shl.rb │ ├── purelib.rb │ ├── racc/ │ │ └── cparse/ │ │ ├── .cvsignore │ │ ├── cparse.c │ │ ├── depend │ │ └── extconf.rb │ ├── rational/ │ │ ├── extconf.rb │ │ ├── lib/ │ │ │ └── rational.rb │ │ └── rational.c │ ├── readline/ │ │ ├── .cvsignore │ │ ├── README │ │ ├── README.ja │ │ ├── depend │ │ ├── extconf.rb │ │ └── readline.c │ ├── sdbm/ │ │ ├── .cvsignore │ │ ├── _sdbm.c │ │ ├── depend │ │ ├── extconf.rb │ │ ├── init.c │ │ └── sdbm.h │ ├── socket/ │ │ ├── .cvsignore │ │ ├── addrinfo.h │ │ ├── depend │ │ ├── extconf.rb │ │ ├── getaddrinfo.c │ │ ├── getnameinfo.c │ │ ├── socket.c │ │ └── sockport.h │ ├── stringio/ │ │ ├── .cvsignore │ │ ├── README │ │ ├── depend │ │ ├── extconf.rb │ │ └── stringio.c │ ├── strscan/ │ │ ├── .cvsignore │ │ ├── depend │ │ ├── extconf.rb │ │ └── strscan.c │ ├── syck/ │ │ ├── .cvsignore │ │ ├── bytecode.c │ │ ├── depend │ │ ├── emitter.c │ │ ├── extconf.rb │ │ ├── gram.c │ │ ├── gram.h │ │ ├── handler.c │ │ ├── implicit.c │ │ ├── node.c │ │ ├── rubyext.c │ │ ├── syck.c │ │ ├── syck.h │ │ ├── token.c │ │ ├── yaml2byte.c │ │ └── yamlbyte.h │ ├── syslog/ │ │ ├── .cvsignore │ │ ├── depend │ │ ├── extconf.rb │ │ ├── syslog.c │ │ ├── syslog.txt │ │ └── test.rb │ ├── thread/ │ │ ├── extconf.rb │ │ ├── lib/ │ │ │ └── thread.rb │ │ └── thread.c │ ├── tk/ │ │ ├── .cvsignore │ │ ├── ChangeLog.tkextlib │ │ ├── MANUAL_tcltklib.eng │ │ ├── MANUAL_tcltklib.eucj │ │ ├── README.1st │ │ ├── README.ActiveTcl │ │ ├── README.fork │ │ ├── README.macosx-aqua │ │ ├── README.tcltklib │ │ ├── depend │ │ ├── extconf.rb │ │ ├── lib/ │ │ │ ├── README │ │ │ ├── multi-tk.rb │ │ │ ├── remote-tk.rb │ │ │ ├── tcltk.rb │ │ │ ├── tk/ │ │ │ │ ├── after.rb │ │ │ │ ├── autoload.rb │ │ │ │ ├── bgerror.rb │ │ │ │ ├── bindtag.rb │ │ │ │ ├── button.rb │ │ │ │ ├── canvas.rb │ │ │ │ ├── canvastag.rb │ │ │ │ ├── checkbutton.rb │ │ │ │ ├── clipboard.rb │ │ │ │ ├── clock.rb │ │ │ │ ├── composite.rb │ │ │ │ ├── console.rb │ │ │ │ ├── dialog.rb │ │ │ │ ├── encodedstr.rb │ │ │ │ ├── entry.rb │ │ │ │ ├── event.rb │ │ │ │ ├── font.rb │ │ │ │ ├── frame.rb │ │ │ │ ├── grid.rb │ │ │ │ ├── image.rb │ │ │ │ ├── itemconfig.rb │ │ │ │ ├── itemfont.rb │ │ │ │ ├── kinput.rb │ │ │ │ ├── label.rb │ │ │ │ ├── labelframe.rb │ │ │ │ ├── listbox.rb │ │ │ │ ├── macpkg.rb │ │ │ │ ├── menu.rb │ │ │ │ ├── menubar.rb │ │ │ │ ├── menuspec.rb │ │ │ │ ├── message.rb │ │ │ │ ├── mngfocus.rb │ │ │ │ ├── msgcat.rb │ │ │ │ ├── namespace.rb │ │ │ │ ├── optiondb.rb │ │ │ │ ├── optionobj.rb │ │ │ │ ├── pack.rb │ │ │ │ ├── package.rb │ │ │ │ ├── palette.rb │ │ │ │ ├── panedwindow.rb │ │ │ │ ├── place.rb │ │ │ │ ├── radiobutton.rb │ │ │ │ ├── root.rb │ │ │ │ ├── scale.rb │ │ │ │ ├── scrollable.rb │ │ │ │ ├── scrollbar.rb │ │ │ │ ├── scrollbox.rb │ │ │ │ ├── selection.rb │ │ │ │ ├── spinbox.rb │ │ │ │ ├── tagfont.rb │ │ │ │ ├── text.rb │ │ │ │ ├── textimage.rb │ │ │ │ ├── textmark.rb │ │ │ │ ├── texttag.rb │ │ │ │ ├── textwindow.rb │ │ │ │ ├── timer.rb │ │ │ │ ├── toplevel.rb │ │ │ │ ├── ttk_selector.rb │ │ │ │ ├── txtwin_abst.rb │ │ │ │ ├── validation.rb │ │ │ │ ├── variable.rb │ │ │ │ ├── virtevent.rb │ │ │ │ ├── winfo.rb │ │ │ │ ├── winpkg.rb │ │ │ │ ├── wm.rb │ │ │ │ └── xim.rb │ │ │ ├── tk.rb │ │ │ ├── tkafter.rb │ │ │ ├── tkbgerror.rb │ │ │ ├── tkcanvas.rb │ │ │ ├── tkclass.rb │ │ │ ├── tkconsole.rb │ │ │ ├── tkdialog.rb │ │ │ ├── tkentry.rb │ │ │ ├── tkextlib/ │ │ │ │ ├── ICONS/ │ │ │ │ │ ├── icons.rb │ │ │ │ │ └── setup.rb │ │ │ │ ├── ICONS.rb │ │ │ │ ├── SUPPORT_STATUS │ │ │ │ ├── blt/ │ │ │ │ │ ├── barchart.rb │ │ │ │ │ ├── bitmap.rb │ │ │ │ │ ├── busy.rb │ │ │ │ │ ├── component.rb │ │ │ │ │ ├── container.rb │ │ │ │ │ ├── cutbuffer.rb │ │ │ │ │ ├── dragdrop.rb │ │ │ │ │ ├── eps.rb │ │ │ │ │ ├── graph.rb │ │ │ │ │ ├── htext.rb │ │ │ │ │ ├── setup.rb │ │ │ │ │ ├── spline.rb │ │ │ │ │ ├── stripchart.rb │ │ │ │ │ ├── table.rb │ │ │ │ │ ├── tabnotebook.rb │ │ │ │ │ ├── tabset.rb │ │ │ │ │ ├── ted.rb │ │ │ │ │ ├── tile/ │ │ │ │ │ │ ├── button.rb │ │ │ │ │ │ ├── checkbutton.rb │ │ │ │ │ │ ├── frame.rb │ │ │ │ │ │ ├── label.rb │ │ │ │ │ │ ├── radiobutton.rb │ │ │ │ │ │ ├── scrollbar.rb │ │ │ │ │ │ └── toplevel.rb │ │ │ │ │ ├── tile.rb │ │ │ │ │ ├── tree.rb │ │ │ │ │ ├── treeview.rb │ │ │ │ │ ├── unix_dnd.rb │ │ │ │ │ ├── vector.rb │ │ │ │ │ ├── watch.rb │ │ │ │ │ ├── win_printer.rb │ │ │ │ │ └── winop.rb │ │ │ │ ├── blt.rb │ │ │ │ ├── bwidget/ │ │ │ │ │ ├── arrowbutton.rb │ │ │ │ │ ├── bitmap.rb │ │ │ │ │ ├── button.rb │ │ │ │ │ ├── buttonbox.rb │ │ │ │ │ ├── combobox.rb │ │ │ │ │ ├── dialog.rb │ │ │ │ │ ├── dragsite.rb │ │ │ │ │ ├── dropsite.rb │ │ │ │ │ ├── dynamichelp.rb │ │ │ │ │ ├── entry.rb │ │ │ │ │ ├── label.rb │ │ │ │ │ ├── labelentry.rb │ │ │ │ │ ├── labelframe.rb │ │ │ │ │ ├── listbox.rb │ │ │ │ │ ├── mainframe.rb │ │ │ │ │ ├── messagedlg.rb │ │ │ │ │ ├── notebook.rb │ │ │ │ │ ├── pagesmanager.rb │ │ │ │ │ ├── panedwindow.rb │ │ │ │ │ ├── panelframe.rb │ │ │ │ │ ├── passwddlg.rb │ │ │ │ │ ├── progressbar.rb │ │ │ │ │ ├── progressdlg.rb │ │ │ │ │ ├── scrollableframe.rb │ │ │ │ │ ├── scrolledwindow.rb │ │ │ │ │ ├── scrollview.rb │ │ │ │ │ ├── selectcolor.rb │ │ │ │ │ ├── selectfont.rb │ │ │ │ │ ├── separator.rb │ │ │ │ │ ├── setup.rb │ │ │ │ │ ├── spinbox.rb │ │ │ │ │ ├── statusbar.rb │ │ │ │ │ ├── titleframe.rb │ │ │ │ │ ├── tree.rb │ │ │ │ │ └── widget.rb │ │ │ │ ├── bwidget.rb │ │ │ │ ├── itcl/ │ │ │ │ │ ├── incr_tcl.rb │ │ │ │ │ └── setup.rb │ │ │ │ ├── itcl.rb │ │ │ │ ├── itk/ │ │ │ │ │ ├── incr_tk.rb │ │ │ │ │ └── setup.rb │ │ │ │ ├── itk.rb │ │ │ │ ├── iwidgets/ │ │ │ │ │ ├── buttonbox.rb │ │ │ │ │ ├── calendar.rb │ │ │ │ │ ├── canvasprintbox.rb │ │ │ │ │ ├── canvasprintdialog.rb │ │ │ │ │ ├── checkbox.rb │ │ │ │ │ ├── combobox.rb │ │ │ │ │ ├── dateentry.rb │ │ │ │ │ ├── datefield.rb │ │ │ │ │ ├── dialog.rb │ │ │ │ │ ├── dialogshell.rb │ │ │ │ │ ├── disjointlistbox.rb │ │ │ │ │ ├── entryfield.rb │ │ │ │ │ ├── extbutton.rb │ │ │ │ │ ├── extfileselectionbox.rb │ │ │ │ │ ├── extfileselectiondialog.rb │ │ │ │ │ ├── feedback.rb │ │ │ │ │ ├── fileselectionbox.rb │ │ │ │ │ ├── fileselectiondialog.rb │ │ │ │ │ ├── finddialog.rb │ │ │ │ │ ├── hierarchy.rb │ │ │ │ │ ├── hyperhelp.rb │ │ │ │ │ ├── labeledframe.rb │ │ │ │ │ ├── labeledwidget.rb │ │ │ │ │ ├── mainwindow.rb │ │ │ │ │ ├── menubar.rb │ │ │ │ │ ├── messagebox.rb │ │ │ │ │ ├── messagedialog.rb │ │ │ │ │ ├── notebook.rb │ │ │ │ │ ├── optionmenu.rb │ │ │ │ │ ├── panedwindow.rb │ │ │ │ │ ├── promptdialog.rb │ │ │ │ │ ├── pushbutton.rb │ │ │ │ │ ├── radiobox.rb │ │ │ │ │ ├── scopedobject.rb │ │ │ │ │ ├── scrolledcanvas.rb │ │ │ │ │ ├── scrolledframe.rb │ │ │ │ │ ├── scrolledhtml.rb │ │ │ │ │ ├── scrolledlistbox.rb │ │ │ │ │ ├── scrolledtext.rb │ │ │ │ │ ├── scrolledwidget.rb │ │ │ │ │ ├── selectionbox.rb │ │ │ │ │ ├── selectiondialog.rb │ │ │ │ │ ├── setup.rb │ │ │ │ │ ├── shell.rb │ │ │ │ │ ├── spindate.rb │ │ │ │ │ ├── spinint.rb │ │ │ │ │ ├── spinner.rb │ │ │ │ │ ├── spintime.rb │ │ │ │ │ ├── tabnotebook.rb │ │ │ │ │ ├── tabset.rb │ │ │ │ │ ├── timeentry.rb │ │ │ │ │ ├── timefield.rb │ │ │ │ │ ├── toolbar.rb │ │ │ │ │ └── watch.rb │ │ │ │ ├── iwidgets.rb │ │ │ │ ├── pkg_checker.rb │ │ │ │ ├── setup.rb │ │ │ │ ├── tcllib/ │ │ │ │ │ ├── README │ │ │ │ │ ├── autoscroll.rb │ │ │ │ │ ├── ctext.rb │ │ │ │ │ ├── cursor.rb │ │ │ │ │ ├── datefield.rb │ │ │ │ │ ├── dialog.rb │ │ │ │ │ ├── getstring.rb │ │ │ │ │ ├── history.rb │ │ │ │ │ ├── ico.rb │ │ │ │ │ ├── ip_entry.rb │ │ │ │ │ ├── panelframe.rb │ │ │ │ │ ├── plotchart.rb │ │ │ │ │ ├── ruler.rb │ │ │ │ │ ├── screenruler.rb │ │ │ │ │ ├── scrollwin.rb │ │ │ │ │ ├── setup.rb │ │ │ │ │ ├── style.rb │ │ │ │ │ ├── superframe.rb │ │ │ │ │ ├── swaplist.rb │ │ │ │ │ ├── tablelist.rb │ │ │ │ │ ├── tablelist_core.rb │ │ │ │ │ ├── tablelist_tile.rb │ │ │ │ │ ├── tkpiechart.rb │ │ │ │ │ ├── tooltip.rb │ │ │ │ │ └── widget.rb │ │ │ │ ├── tcllib.rb │ │ │ │ ├── tclx/ │ │ │ │ │ ├── setup.rb │ │ │ │ │ └── tclx.rb │ │ │ │ ├── tclx.rb │ │ │ │ ├── tile/ │ │ │ │ │ ├── dialog.rb │ │ │ │ │ ├── setup.rb │ │ │ │ │ ├── sizegrip.rb │ │ │ │ │ ├── style.rb │ │ │ │ │ ├── tbutton.rb │ │ │ │ │ ├── tcheckbutton.rb │ │ │ │ │ ├── tcombobox.rb │ │ │ │ │ ├── tentry.rb │ │ │ │ │ ├── tframe.rb │ │ │ │ │ ├── tlabel.rb │ │ │ │ │ ├── tlabelframe.rb │ │ │ │ │ ├── tmenubutton.rb │ │ │ │ │ ├── tnotebook.rb │ │ │ │ │ ├── tpaned.rb │ │ │ │ │ ├── tprogressbar.rb │ │ │ │ │ ├── tradiobutton.rb │ │ │ │ │ ├── treeview.rb │ │ │ │ │ ├── tscale.rb │ │ │ │ │ ├── tscrollbar.rb │ │ │ │ │ ├── tseparator.rb │ │ │ │ │ └── tsquare.rb │ │ │ │ ├── tile.rb │ │ │ │ ├── tkDND/ │ │ │ │ │ ├── setup.rb │ │ │ │ │ ├── shape.rb │ │ │ │ │ └── tkdnd.rb │ │ │ │ ├── tkDND.rb │ │ │ │ ├── tkHTML/ │ │ │ │ │ ├── htmlwidget.rb │ │ │ │ │ └── setup.rb │ │ │ │ ├── tkHTML.rb │ │ │ │ ├── tkimg/ │ │ │ │ │ ├── README │ │ │ │ │ ├── bmp.rb │ │ │ │ │ ├── gif.rb │ │ │ │ │ ├── ico.rb │ │ │ │ │ ├── jpeg.rb │ │ │ │ │ ├── pcx.rb │ │ │ │ │ ├── pixmap.rb │ │ │ │ │ ├── png.rb │ │ │ │ │ ├── ppm.rb │ │ │ │ │ ├── ps.rb │ │ │ │ │ ├── setup.rb │ │ │ │ │ ├── sgi.rb │ │ │ │ │ ├── sun.rb │ │ │ │ │ ├── tga.rb │ │ │ │ │ ├── tiff.rb │ │ │ │ │ ├── window.rb │ │ │ │ │ ├── xbm.rb │ │ │ │ │ └── xpm.rb │ │ │ │ ├── tkimg.rb │ │ │ │ ├── tktable/ │ │ │ │ │ ├── setup.rb │ │ │ │ │ └── tktable.rb │ │ │ │ ├── tktable.rb │ │ │ │ ├── tktrans/ │ │ │ │ │ ├── setup.rb │ │ │ │ │ └── tktrans.rb │ │ │ │ ├── tktrans.rb │ │ │ │ ├── treectrl/ │ │ │ │ │ ├── setup.rb │ │ │ │ │ └── tktreectrl.rb │ │ │ │ ├── treectrl.rb │ │ │ │ ├── trofs/ │ │ │ │ │ ├── setup.rb │ │ │ │ │ └── trofs.rb │ │ │ │ ├── trofs.rb │ │ │ │ ├── version.rb │ │ │ │ ├── vu/ │ │ │ │ │ ├── bargraph.rb │ │ │ │ │ ├── charts.rb │ │ │ │ │ ├── dial.rb │ │ │ │ │ ├── pie.rb │ │ │ │ │ ├── setup.rb │ │ │ │ │ └── spinbox.rb │ │ │ │ ├── vu.rb │ │ │ │ ├── winico/ │ │ │ │ │ ├── setup.rb │ │ │ │ │ └── winico.rb │ │ │ │ └── winico.rb │ │ │ ├── tkfont.rb │ │ │ ├── tkmacpkg.rb │ │ │ ├── tkmenubar.rb │ │ │ ├── tkmngfocus.rb │ │ │ ├── tkpalette.rb │ │ │ ├── tkscrollbox.rb │ │ │ ├── tktext.rb │ │ │ ├── tkvirtevent.rb │ │ │ └── tkwinpkg.rb │ │ ├── old-README.tcltklib.eucj │ │ ├── sample/ │ │ │ ├── 24hr_clock.rb │ │ │ ├── binding_sample.rb │ │ │ ├── bindtag_sample.rb │ │ │ ├── binstr_usage.rb │ │ │ ├── btn_with_frame.rb │ │ │ ├── cd_timer.rb │ │ │ ├── cmd_res_test.rb │ │ │ ├── cmd_resource │ │ │ ├── demos-en/ │ │ │ │ ├── ChangeLog │ │ │ │ ├── ChangeLog.prev │ │ │ │ ├── README │ │ │ │ ├── README.1st │ │ │ │ ├── README.tkencoding │ │ │ │ ├── anilabel.rb │ │ │ │ ├── aniwave.rb │ │ │ │ ├── arrow.rb │ │ │ │ ├── bind.rb │ │ │ │ ├── bitmap.rb │ │ │ │ ├── browse1 │ │ │ │ ├── browse2 │ │ │ │ ├── button.rb │ │ │ │ ├── check.rb │ │ │ │ ├── check2.rb │ │ │ │ ├── clrpick.rb │ │ │ │ ├── colors.rb │ │ │ │ ├── combo.rb │ │ │ │ ├── cscroll.rb │ │ │ │ ├── ctext.rb │ │ │ │ ├── dialog1.rb │ │ │ │ ├── dialog2.rb │ │ │ │ ├── doc.org/ │ │ │ │ │ ├── README │ │ │ │ │ ├── README.JP │ │ │ │ │ ├── README.tk80 │ │ │ │ │ ├── license.terms │ │ │ │ │ └── license.terms.tk80 │ │ │ │ ├── entry1.rb │ │ │ │ ├── entry2.rb │ │ │ │ ├── entry3.rb │ │ │ │ ├── filebox.rb │ │ │ │ ├── floor.rb │ │ │ │ ├── floor2.rb │ │ │ │ ├── form.rb │ │ │ │ ├── goldberg.rb │ │ │ │ ├── hello │ │ │ │ ├── hscale.rb │ │ │ │ ├── icon.rb │ │ │ │ ├── image1.rb │ │ │ │ ├── image2.rb │ │ │ │ ├── image3.rb │ │ │ │ ├── items.rb │ │ │ │ ├── ixset │ │ │ │ ├── ixset2 │ │ │ │ ├── knightstour.rb │ │ │ │ ├── label.rb │ │ │ │ ├── labelframe.rb │ │ │ │ ├── mclist.rb │ │ │ │ ├── menu.rb │ │ │ │ ├── menu84.rb │ │ │ │ ├── menubu.rb │ │ │ │ ├── msgbox.rb │ │ │ │ ├── msgbox2.rb │ │ │ │ ├── paned1.rb │ │ │ │ ├── paned2.rb │ │ │ │ ├── pendulum.rb │ │ │ │ ├── plot.rb │ │ │ │ ├── puzzle.rb │ │ │ │ ├── radio.rb │ │ │ │ ├── radio2.rb │ │ │ │ ├── radio3.rb │ │ │ │ ├── rmt │ │ │ │ ├── rolodex │ │ │ │ ├── ruler.rb │ │ │ │ ├── sayings.rb │ │ │ │ ├── search.rb │ │ │ │ ├── spin.rb │ │ │ │ ├── square │ │ │ │ ├── states.rb │ │ │ │ ├── style.rb │ │ │ │ ├── tcolor │ │ │ │ ├── text.rb │ │ │ │ ├── textpeer.rb │ │ │ │ ├── timer │ │ │ │ ├── tkencoding.rb │ │ │ │ ├── toolbar.rb │ │ │ │ ├── tree.rb │ │ │ │ ├── ttkbut.rb │ │ │ │ ├── ttkmenu.rb │ │ │ │ ├── ttknote.rb │ │ │ │ ├── ttkpane.rb │ │ │ │ ├── ttkprogress.rb │ │ │ │ ├── twind.rb │ │ │ │ ├── twind2.rb │ │ │ │ ├── unicodeout.rb │ │ │ │ ├── vscale.rb │ │ │ │ └── widget │ │ │ ├── demos-jp/ │ │ │ │ ├── README │ │ │ │ ├── README.1st │ │ │ │ ├── anilabel.rb │ │ │ │ ├── aniwave.rb │ │ │ │ ├── arrow.rb │ │ │ │ ├── bind.rb │ │ │ │ ├── bitmap.rb │ │ │ │ ├── browse1 │ │ │ │ ├── browse2 │ │ │ │ ├── button.rb │ │ │ │ ├── check.rb │ │ │ │ ├── check2.rb │ │ │ │ ├── clrpick.rb │ │ │ │ ├── colors.rb │ │ │ │ ├── combo.rb │ │ │ │ ├── cscroll.rb │ │ │ │ ├── ctext.rb │ │ │ │ ├── dialog1.rb │ │ │ │ ├── dialog2.rb │ │ │ │ ├── doc.org/ │ │ │ │ │ ├── README │ │ │ │ │ ├── README.JP │ │ │ │ │ ├── README.tk80 │ │ │ │ │ ├── license.terms │ │ │ │ │ └── license.terms.tk80 │ │ │ │ ├── entry1.rb │ │ │ │ ├── entry2.rb │ │ │ │ ├── entry3.rb │ │ │ │ ├── filebox.rb │ │ │ │ ├── floor.rb │ │ │ │ ├── floor2.rb │ │ │ │ ├── form.rb │ │ │ │ ├── goldberg.rb │ │ │ │ ├── hello │ │ │ │ ├── hscale.rb │ │ │ │ ├── icon.rb │ │ │ │ ├── image1.rb │ │ │ │ ├── image2.rb │ │ │ │ ├── image3.rb │ │ │ │ ├── items.rb │ │ │ │ ├── ixset │ │ │ │ ├── ixset2 │ │ │ │ ├── knightstour.rb │ │ │ │ ├── label.rb │ │ │ │ ├── labelframe.rb │ │ │ │ ├── mclist.rb │ │ │ │ ├── menu.rb │ │ │ │ ├── menu84.rb │ │ │ │ ├── menu8x.rb │ │ │ │ ├── menubu.rb │ │ │ │ ├── msgbox.rb │ │ │ │ ├── msgbox2.rb │ │ │ │ ├── paned1.rb │ │ │ │ ├── paned2.rb │ │ │ │ ├── pendulum.rb │ │ │ │ ├── plot.rb │ │ │ │ ├── puzzle.rb │ │ │ │ ├── radio.rb │ │ │ │ ├── radio2.rb │ │ │ │ ├── radio3.rb │ │ │ │ ├── rmt │ │ │ │ ├── rolodex │ │ │ │ ├── rolodex-j │ │ │ │ ├── ruler.rb │ │ │ │ ├── sayings.rb │ │ │ │ ├── search.rb │ │ │ │ ├── spin.rb │ │ │ │ ├── square │ │ │ │ ├── states.rb │ │ │ │ ├── style.rb │ │ │ │ ├── tcolor │ │ │ │ ├── text.rb │ │ │ │ ├── textpeer.rb │ │ │ │ ├── timer │ │ │ │ ├── toolbar.rb │ │ │ │ ├── tree.rb │ │ │ │ ├── ttkbut.rb │ │ │ │ ├── ttkmenu.rb │ │ │ │ ├── ttknote.rb │ │ │ │ ├── ttkpane.rb │ │ │ │ ├── ttkprogress.rb │ │ │ │ ├── twind.rb │ │ │ │ ├── twind2.rb │ │ │ │ ├── unicodeout.rb │ │ │ │ ├── vscale.rb │ │ │ │ └── widget │ │ │ ├── editable_listbox.rb │ │ │ ├── encstr_usage.rb │ │ │ ├── figmemo_sample.rb │ │ │ ├── images/ │ │ │ │ ├── face.xbm │ │ │ │ ├── flagdown.xbm │ │ │ │ ├── flagup.xbm │ │ │ │ ├── gray25.xbm │ │ │ │ ├── grey.25 │ │ │ │ ├── grey.5 │ │ │ │ ├── letters.xbm │ │ │ │ ├── noletter.xbm │ │ │ │ ├── pattern.xbm │ │ │ │ └── teapot.ppm │ │ │ ├── irbtk.rb │ │ │ ├── irbtkw.rbw │ │ │ ├── iso2022-kr.txt │ │ │ ├── menubar1.rb │ │ │ ├── menubar2.rb │ │ │ ├── msgs_rb/ │ │ │ │ ├── README │ │ │ │ ├── cs.msg │ │ │ │ ├── de.msg │ │ │ │ ├── el.msg │ │ │ │ ├── en.msg │ │ │ │ ├── en_gb.msg │ │ │ │ ├── eo.msg │ │ │ │ ├── es.msg │ │ │ │ ├── fr.msg │ │ │ │ ├── it.msg │ │ │ │ ├── ja.msg │ │ │ │ ├── nl.msg │ │ │ │ ├── pl.msg │ │ │ │ └── ru.msg │ │ │ ├── msgs_rb2/ │ │ │ │ ├── README │ │ │ │ ├── de.msg │ │ │ │ └── ja.msg │ │ │ ├── msgs_tk/ │ │ │ │ ├── README │ │ │ │ ├── cs.msg │ │ │ │ ├── de.msg │ │ │ │ ├── el.msg │ │ │ │ ├── en.msg │ │ │ │ ├── en_gb.msg │ │ │ │ ├── eo.msg │ │ │ │ ├── es.msg │ │ │ │ ├── fr.msg │ │ │ │ ├── it.msg │ │ │ │ ├── ja.msg │ │ │ │ ├── license.terms │ │ │ │ ├── nl.msg │ │ │ │ ├── pl.msg │ │ │ │ └── ru.msg │ │ │ ├── multi-ip_sample.rb │ │ │ ├── multi-ip_sample2.rb │ │ │ ├── optobj_sample.rb │ │ │ ├── propagate.rb │ │ │ ├── remote-ip_sample.rb │ │ │ ├── remote-ip_sample2.rb │ │ │ ├── resource.en │ │ │ ├── resource.ja │ │ │ ├── safe-tk.rb │ │ │ ├── scrollframe.rb │ │ │ ├── tcltklib/ │ │ │ │ ├── lines0.tcl │ │ │ │ ├── lines1.rb │ │ │ │ ├── lines2.rb │ │ │ │ ├── lines3.rb │ │ │ │ ├── lines4.rb │ │ │ │ ├── safeTk.rb │ │ │ │ ├── sample0.rb │ │ │ │ ├── sample1.rb │ │ │ │ └── sample2.rb │ │ │ ├── tkalignbox.rb │ │ │ ├── tkballoonhelp.rb │ │ │ ├── tkbiff.rb │ │ │ ├── tkbrowse.rb │ │ │ ├── tkcombobox.rb │ │ │ ├── tkdialog.rb │ │ │ ├── tkextlib/ │ │ │ │ ├── ICONS/ │ │ │ │ │ ├── Orig_LICENSE.txt │ │ │ │ │ ├── tkIcons │ │ │ │ │ ├── tkIcons-sample.kde │ │ │ │ │ ├── tkIcons.kde │ │ │ │ │ └── viewIcons.rb │ │ │ │ ├── blt/ │ │ │ │ │ ├── barchart5.rb │ │ │ │ │ ├── calendar.rb │ │ │ │ │ ├── graph6.rb │ │ │ │ │ ├── graph7.rb │ │ │ │ │ ├── graph7a.rb │ │ │ │ │ ├── graph7b.rb │ │ │ │ │ ├── graph7c.rb │ │ │ │ │ ├── pareto.rb │ │ │ │ │ ├── plot1.rb │ │ │ │ │ ├── plot1b.rb │ │ │ │ │ ├── readme.txt │ │ │ │ │ ├── scripts/ │ │ │ │ │ │ └── stipples.rb │ │ │ │ │ ├── winop1.rb │ │ │ │ │ └── winop2.rb │ │ │ │ ├── bwidget/ │ │ │ │ │ ├── Orig_LICENSE.txt │ │ │ │ │ ├── basic.rb │ │ │ │ │ ├── bwidget.xbm │ │ │ │ │ ├── demo.rb │ │ │ │ │ ├── dnd.rb │ │ │ │ │ ├── manager.rb │ │ │ │ │ ├── select.rb │ │ │ │ │ ├── tmpldlg.rb │ │ │ │ │ ├── tree.rb │ │ │ │ │ └── x1.xbm │ │ │ │ ├── iwidgets/ │ │ │ │ │ ├── catalog_demo/ │ │ │ │ │ │ ├── Orig_LICENSE.txt │ │ │ │ │ │ └── images/ │ │ │ │ │ │ ├── box.xbm │ │ │ │ │ │ ├── line.xbm │ │ │ │ │ │ ├── oval.xbm │ │ │ │ │ │ ├── points.xbm │ │ │ │ │ │ └── text.xbm │ │ │ │ │ └── sample/ │ │ │ │ │ ├── buttonbox.rb │ │ │ │ │ ├── calendar.rb │ │ │ │ │ ├── canvasprintbox.rb │ │ │ │ │ ├── canvasprintdialog.rb │ │ │ │ │ ├── checkbox.rb │ │ │ │ │ ├── combobox.rb │ │ │ │ │ ├── dateentry.rb │ │ │ │ │ ├── datefield.rb │ │ │ │ │ ├── dialog.rb │ │ │ │ │ ├── dialogshell.rb │ │ │ │ │ ├── disjointlistbox.rb │ │ │ │ │ ├── entryfield-1.rb │ │ │ │ │ ├── entryfield-2.rb │ │ │ │ │ ├── entryfield-3.rb │ │ │ │ │ ├── extbutton.rb │ │ │ │ │ ├── extfileselectionbox.rb │ │ │ │ │ ├── extfileselectiondialog.rb │ │ │ │ │ ├── feedback.rb │ │ │ │ │ ├── fileselectionbox.rb │ │ │ │ │ ├── fileselectiondialog.rb │ │ │ │ │ ├── finddialog.rb │ │ │ │ │ ├── hierarchy.rb │ │ │ │ │ ├── hyperhelp.rb │ │ │ │ │ ├── labeledframe.rb │ │ │ │ │ ├── labeledwidget.rb │ │ │ │ │ ├── mainwindow.rb │ │ │ │ │ ├── menubar.rb │ │ │ │ │ ├── menubar2.rb │ │ │ │ │ ├── messagebox1.rb │ │ │ │ │ ├── messagebox2.rb │ │ │ │ │ ├── messagedialog.rb │ │ │ │ │ ├── notebook.rb │ │ │ │ │ ├── notebook2.rb │ │ │ │ │ ├── optionmenu.rb │ │ │ │ │ ├── panedwindow.rb │ │ │ │ │ ├── panedwindow2.rb │ │ │ │ │ ├── promptdialog.rb │ │ │ │ │ ├── pushbutton.rb │ │ │ │ │ ├── radiobox.rb │ │ │ │ │ ├── scrolledcanvas.rb │ │ │ │ │ ├── scrolledframe.rb │ │ │ │ │ ├── scrolledhtml.rb │ │ │ │ │ ├── scrolledlistbox.rb │ │ │ │ │ ├── scrolledtext.rb │ │ │ │ │ ├── selectionbox.rb │ │ │ │ │ ├── selectiondialog.rb │ │ │ │ │ ├── shell.rb │ │ │ │ │ ├── spindate.rb │ │ │ │ │ ├── spinint.rb │ │ │ │ │ ├── spinner.rb │ │ │ │ │ ├── spintime.rb │ │ │ │ │ ├── tabnotebook.rb │ │ │ │ │ ├── tabnotebook2.rb │ │ │ │ │ ├── tabset.rb │ │ │ │ │ ├── timeentry.rb │ │ │ │ │ ├── timefield.rb │ │ │ │ │ ├── toolbar.rb │ │ │ │ │ └── watch.rb │ │ │ │ ├── tcllib/ │ │ │ │ │ ├── Orig_LICENSE.txt │ │ │ │ │ ├── datefield.rb │ │ │ │ │ ├── plotdemos1.rb │ │ │ │ │ ├── plotdemos2.rb │ │ │ │ │ ├── plotdemos3.rb │ │ │ │ │ └── xyplot.rb │ │ │ │ ├── tile/ │ │ │ │ │ ├── Orig_LICENSE.txt │ │ │ │ │ ├── demo.rb │ │ │ │ │ ├── iconlib.tcl │ │ │ │ │ ├── readme.txt │ │ │ │ │ ├── repeater.tcl │ │ │ │ │ ├── themes/ │ │ │ │ │ │ ├── blue/ │ │ │ │ │ │ │ ├── blue/ │ │ │ │ │ │ │ │ └── button-n.xcf │ │ │ │ │ │ │ ├── blue.tcl │ │ │ │ │ │ │ └── pkgIndex.tcl │ │ │ │ │ │ ├── keramik/ │ │ │ │ │ │ │ ├── keramik.tcl │ │ │ │ │ │ │ └── pkgIndex.tcl │ │ │ │ │ │ ├── kroc/ │ │ │ │ │ │ │ ├── kroc.tcl │ │ │ │ │ │ │ └── pkgIndex.tcl │ │ │ │ │ │ ├── kroc.rb │ │ │ │ │ │ └── plastik/ │ │ │ │ │ │ ├── pkgIndex.tcl │ │ │ │ │ │ └── plastik.tcl │ │ │ │ │ └── toolbutton.tcl │ │ │ │ ├── tkHTML/ │ │ │ │ │ ├── Orig_COPYRIGHT.txt │ │ │ │ │ ├── README │ │ │ │ │ ├── hv.rb │ │ │ │ │ ├── page1/ │ │ │ │ │ │ ├── image1 │ │ │ │ │ │ ├── image10 │ │ │ │ │ │ ├── image11 │ │ │ │ │ │ ├── image12 │ │ │ │ │ │ ├── image13 │ │ │ │ │ │ ├── image14 │ │ │ │ │ │ ├── image2 │ │ │ │ │ │ ├── image3 │ │ │ │ │ │ ├── image4 │ │ │ │ │ │ ├── image5 │ │ │ │ │ │ ├── image6 │ │ │ │ │ │ ├── image7 │ │ │ │ │ │ ├── image8 │ │ │ │ │ │ ├── image9 │ │ │ │ │ │ └── index.html │ │ │ │ │ ├── page2/ │ │ │ │ │ │ ├── image1 │ │ │ │ │ │ ├── image10 │ │ │ │ │ │ ├── image11 │ │ │ │ │ │ ├── image12 │ │ │ │ │ │ ├── image13 │ │ │ │ │ │ ├── image14 │ │ │ │ │ │ ├── image15 │ │ │ │ │ │ ├── image16 │ │ │ │ │ │ ├── image17 │ │ │ │ │ │ ├── image18 │ │ │ │ │ │ ├── image19 │ │ │ │ │ │ ├── image2 │ │ │ │ │ │ ├── image20 │ │ │ │ │ │ ├── image21 │ │ │ │ │ │ ├── image22 │ │ │ │ │ │ ├── image23 │ │ │ │ │ │ ├── image24 │ │ │ │ │ │ ├── image25 │ │ │ │ │ │ ├── image26 │ │ │ │ │ │ ├── image27 │ │ │ │ │ │ ├── image28 │ │ │ │ │ │ ├── image29 │ │ │ │ │ │ ├── image3 │ │ │ │ │ │ ├── image30 │ │ │ │ │ │ ├── image31 │ │ │ │ │ │ ├── image32 │ │ │ │ │ │ ├── image33 │ │ │ │ │ │ ├── image34 │ │ │ │ │ │ ├── image35 │ │ │ │ │ │ ├── image36 │ │ │ │ │ │ ├── image37 │ │ │ │ │ │ ├── image38 │ │ │ │ │ │ ├── image39 │ │ │ │ │ │ ├── image4 │ │ │ │ │ │ ├── image5 │ │ │ │ │ │ ├── image6 │ │ │ │ │ │ ├── image7 │ │ │ │ │ │ ├── image8 │ │ │ │ │ │ ├── image9 │ │ │ │ │ │ └── index.html │ │ │ │ │ ├── page3/ │ │ │ │ │ │ ├── image1 │ │ │ │ │ │ ├── image10 │ │ │ │ │ │ ├── image11 │ │ │ │ │ │ ├── image12 │ │ │ │ │ │ ├── image13 │ │ │ │ │ │ ├── image14 │ │ │ │ │ │ ├── image2 │ │ │ │ │ │ ├── image3 │ │ │ │ │ │ ├── image4 │ │ │ │ │ │ ├── image5 │ │ │ │ │ │ ├── image6 │ │ │ │ │ │ ├── image7 │ │ │ │ │ │ ├── image8 │ │ │ │ │ │ ├── image9 │ │ │ │ │ │ └── index.html │ │ │ │ │ ├── page4/ │ │ │ │ │ │ ├── image1 │ │ │ │ │ │ ├── image2 │ │ │ │ │ │ ├── image3 │ │ │ │ │ │ ├── image4 │ │ │ │ │ │ ├── image5 │ │ │ │ │ │ ├── image6 │ │ │ │ │ │ ├── image7 │ │ │ │ │ │ ├── image8 │ │ │ │ │ │ ├── image9 │ │ │ │ │ │ └── index.html │ │ │ │ │ └── ss.rb │ │ │ │ ├── tkimg/ │ │ │ │ │ ├── demo.rb │ │ │ │ │ ├── license_terms_of_Img_extension │ │ │ │ │ └── readme.txt │ │ │ │ ├── tktable/ │ │ │ │ │ ├── Orig_LICENSE.txt │ │ │ │ │ ├── basic.rb │ │ │ │ │ ├── buttons.rb │ │ │ │ │ ├── command.rb │ │ │ │ │ ├── debug.rb │ │ │ │ │ ├── dynarows.rb │ │ │ │ │ ├── maxsize.rb │ │ │ │ │ ├── spreadsheet.rb │ │ │ │ │ └── valid.rb │ │ │ │ ├── treectrl/ │ │ │ │ │ ├── bitmaps.rb │ │ │ │ │ ├── demo.rb │ │ │ │ │ ├── explorer.rb │ │ │ │ │ ├── help.rb │ │ │ │ │ ├── imovie.rb │ │ │ │ │ ├── layout.rb │ │ │ │ │ ├── mailwasher.rb │ │ │ │ │ ├── outlook-folders.rb │ │ │ │ │ ├── outlook-newgroup.rb │ │ │ │ │ ├── random.rb │ │ │ │ │ ├── readme.txt │ │ │ │ │ └── www-options.rb │ │ │ │ └── vu/ │ │ │ │ ├── Orig_LICENSE.txt │ │ │ │ ├── README.txt │ │ │ │ ├── canvItems.rb │ │ │ │ ├── canvSticker.rb │ │ │ │ ├── canvSticker2.rb │ │ │ │ ├── dial_demo.rb │ │ │ │ ├── m128_000.xbm │ │ │ │ ├── oscilloscope.rb │ │ │ │ ├── pie.rb │ │ │ │ └── vu_demo.rb │ │ │ ├── tkfrom.rb │ │ │ ├── tkhello.rb │ │ │ ├── tkline.rb │ │ │ ├── tkmenubutton.rb │ │ │ ├── tkmsgcat-load_rb.rb │ │ │ ├── tkmsgcat-load_rb2.rb │ │ │ ├── tkmsgcat-load_tk.rb │ │ │ ├── tkmulticolumnlist.rb │ │ │ ├── tkmultilistbox.rb │ │ │ ├── tkmultilistframe.rb │ │ │ ├── tkoptdb-safeTk.rb │ │ │ ├── tkoptdb.rb │ │ │ ├── tkrttimer.rb │ │ │ ├── tksleep_sample.rb │ │ │ ├── tktextframe.rb │ │ │ ├── tktextio.rb │ │ │ ├── tktimer.rb │ │ │ ├── tktimer2.rb │ │ │ ├── tktimer3.rb │ │ │ ├── tktree.rb │ │ │ ├── tktree.tcl │ │ │ └── ttk_wrapper.rb │ │ ├── stubs.c │ │ ├── stubs.h │ │ ├── tcltklib.c │ │ └── tkutil/ │ │ ├── .cvsignore │ │ ├── depend │ │ ├── extconf.rb │ │ └── tkutil.c │ ├── win32ole/ │ │ ├── .cvsignore │ │ ├── depend │ │ ├── doc/ │ │ │ └── win32ole.rd │ │ ├── extconf.rb │ │ ├── lib/ │ │ │ └── win32ole/ │ │ │ └── property.rb │ │ ├── sample/ │ │ │ ├── excel1.rb │ │ │ ├── excel2.rb │ │ │ ├── excel3.rb │ │ │ ├── ie.rb │ │ │ ├── ieconst.rb │ │ │ ├── ienavi.rb │ │ │ ├── oledirs.rb │ │ │ ├── olegen.rb │ │ │ └── xml.rb │ │ ├── tests/ │ │ │ ├── oleserver.rb │ │ │ ├── testNIL2VTEMPTY.rb │ │ │ ├── testOLEMETHOD.rb │ │ │ ├── testOLEPARAM.rb │ │ │ ├── testOLETYPE.rb │ │ │ ├── testOLEVARIABLE.rb │ │ │ ├── testVARIANT.rb │ │ │ ├── testWIN32OLE.rb │ │ │ ├── test_ole_methods.rb │ │ │ ├── test_propertyputref.rb │ │ │ ├── test_win32ole_event.rb │ │ │ ├── test_word.rb │ │ │ └── testall.rb │ │ └── win32ole.c │ └── zlib/ │ ├── .cvsignore │ ├── doc/ │ │ └── zlib.rd │ ├── extconf.rb │ └── zlib.c ├── file.c ├── gc.c ├── hash.c ├── ia64.s ├── inits.c ├── install-sh ├── instruby.rb ├── intern.h ├── io.c ├── keywords ├── kiji-todo ├── lib/ │ ├── .document │ ├── English.rb │ ├── Env.rb │ ├── README │ ├── abbrev.rb │ ├── base64.rb │ ├── benchmark.rb │ ├── cgi/ │ │ ├── .document │ │ ├── session/ │ │ │ └── pstore.rb │ │ └── session.rb │ ├── cgi-lib.rb │ ├── cgi.rb │ ├── complex.rb │ ├── csv.rb │ ├── date/ │ │ └── format.rb │ ├── date.rb │ ├── date2.rb │ ├── debug.rb │ ├── delegate.rb │ ├── drb/ │ │ ├── acl.rb │ │ ├── drb.rb │ │ ├── eq.rb │ │ ├── extserv.rb │ │ ├── extservm.rb │ │ ├── gw.rb │ │ ├── invokemethod.rb │ │ ├── observer.rb │ │ ├── ssl.rb │ │ ├── timeridconv.rb │ │ └── unix.rb │ ├── drb.rb │ ├── e2mmap.rb │ ├── erb.rb │ ├── eregex.rb │ ├── fileutils.rb │ ├── finalize.rb │ ├── find.rb │ ├── forwardable.rb │ ├── ftools.rb │ ├── generator.rb │ ├── getoptlong.rb │ ├── getopts.rb │ ├── gserver.rb │ ├── importenv.rb │ ├── ipaddr.rb │ ├── irb/ │ │ ├── cmd/ │ │ │ ├── chws.rb │ │ │ ├── fork.rb │ │ │ ├── help.rb │ │ │ ├── load.rb │ │ │ ├── nop.rb │ │ │ ├── pushws.rb │ │ │ └── subirb.rb │ │ ├── completion.rb │ │ ├── context.rb │ │ ├── ext/ │ │ │ ├── change-ws.rb │ │ │ ├── history.rb │ │ │ ├── loader.rb │ │ │ ├── math-mode.rb │ │ │ ├── multi-irb.rb │ │ │ ├── save-history.rb │ │ │ ├── tracer.rb │ │ │ ├── use-loader.rb │ │ │ └── workspaces.rb │ │ ├── extend-command.rb │ │ ├── frame.rb │ │ ├── help.rb │ │ ├── init.rb │ │ ├── input-method.rb │ │ ├── lc/ │ │ │ ├── error.rb │ │ │ ├── help-message │ │ │ └── ja/ │ │ │ ├── error.rb │ │ │ └── help-message │ │ ├── locale.rb │ │ ├── notifier.rb │ │ ├── output-method.rb │ │ ├── ruby-lex.rb │ │ ├── ruby-token.rb │ │ ├── slex.rb │ │ ├── version.rb │ │ ├── workspace.rb │ │ ├── ws-for-case-2.rb │ │ └── xmp.rb │ ├── irb.rb │ ├── jcode.rb │ ├── logger.rb │ ├── mailread.rb │ ├── mathn.rb │ ├── matrix.rb │ ├── mkmf.rb │ ├── monitor.rb │ ├── mutex_m.rb │ ├── net/ │ │ ├── ftp.rb │ │ ├── http.rb │ │ ├── https.rb │ │ ├── imap.rb │ │ ├── pop.rb │ │ ├── protocol.rb │ │ ├── smtp.rb │ │ └── telnet.rb │ ├── observer.rb │ ├── open-uri.rb │ ├── open3.rb │ ├── optparse/ │ │ ├── date.rb │ │ ├── shellwords.rb │ │ ├── time.rb │ │ ├── uri.rb │ │ └── version.rb │ ├── optparse.rb │ ├── ostruct.rb │ ├── parsearg.rb │ ├── parsedate.rb │ ├── pathname.rb │ ├── ping.rb │ ├── pp.rb │ ├── prettyprint.rb │ ├── profile.rb │ ├── profiler.rb │ ├── pstore.rb │ ├── racc/ │ │ └── parser.rb │ ├── rdoc/ │ │ ├── README │ │ ├── code_objects.rb │ │ ├── diagram.rb │ │ ├── dot/ │ │ │ └── dot.rb │ │ ├── generators/ │ │ │ ├── chm_generator.rb │ │ │ ├── html_generator.rb │ │ │ ├── ri_generator.rb │ │ │ ├── template/ │ │ │ │ ├── chm/ │ │ │ │ │ └── chm.rb │ │ │ │ ├── html/ │ │ │ │ │ ├── hefss.rb │ │ │ │ │ ├── html.rb │ │ │ │ │ ├── kilmer.rb │ │ │ │ │ ├── old_html.rb │ │ │ │ │ └── one_page_html.rb │ │ │ │ └── xml/ │ │ │ │ ├── rdf.rb │ │ │ │ └── xml.rb │ │ │ └── xml_generator.rb │ │ ├── markup/ │ │ │ ├── .document │ │ │ ├── sample/ │ │ │ │ ├── rdoc2latex.rb │ │ │ │ └── sample.rb │ │ │ ├── simple_markup/ │ │ │ │ ├── fragments.rb │ │ │ │ ├── inline.rb │ │ │ │ ├── lines.rb │ │ │ │ ├── preprocess.rb │ │ │ │ ├── to_flow.rb │ │ │ │ ├── to_html.rb │ │ │ │ └── to_latex.rb │ │ │ ├── simple_markup.rb │ │ │ └── test/ │ │ │ ├── AllTests.rb │ │ │ ├── TestInline.rb │ │ │ └── TestParse.rb │ │ ├── options.rb │ │ ├── parsers/ │ │ │ ├── parse_c.rb │ │ │ ├── parse_f95.rb │ │ │ ├── parse_rb.rb │ │ │ ├── parse_simple.rb │ │ │ └── parserfactory.rb │ │ ├── rdoc.rb │ │ ├── ri/ │ │ │ ├── ri_cache.rb │ │ │ ├── ri_descriptions.rb │ │ │ ├── ri_display.rb │ │ │ ├── ri_driver.rb │ │ │ ├── ri_formatter.rb │ │ │ ├── ri_options.rb │ │ │ ├── ri_paths.rb │ │ │ ├── ri_reader.rb │ │ │ ├── ri_util.rb │ │ │ └── ri_writer.rb │ │ ├── template.rb │ │ ├── tokenstream.rb │ │ └── usage.rb │ ├── readbytes.rb │ ├── resolv-replace.rb │ ├── resolv.rb │ ├── rexml/ │ │ ├── attlistdecl.rb │ │ ├── attribute.rb │ │ ├── cdata.rb │ │ ├── child.rb │ │ ├── comment.rb │ │ ├── doctype.rb │ │ ├── document.rb │ │ ├── dtd/ │ │ │ ├── attlistdecl.rb │ │ │ ├── dtd.rb │ │ │ ├── elementdecl.rb │ │ │ ├── entitydecl.rb │ │ │ └── notationdecl.rb │ │ ├── element.rb │ │ ├── encoding.rb │ │ ├── encodings/ │ │ │ ├── CP-1252.rb │ │ │ ├── EUC-JP.rb │ │ │ ├── ICONV.rb │ │ │ ├── ISO-8859-1.rb │ │ │ ├── ISO-8859-15.rb │ │ │ ├── SHIFT-JIS.rb │ │ │ ├── SHIFT_JIS.rb │ │ │ ├── UNILE.rb │ │ │ ├── US-ASCII.rb │ │ │ ├── UTF-16.rb │ │ │ └── UTF-8.rb │ │ ├── entity.rb │ │ ├── formatters/ │ │ │ ├── default.rb │ │ │ ├── pretty.rb │ │ │ └── transitive.rb │ │ ├── functions.rb │ │ ├── instruction.rb │ │ ├── light/ │ │ │ └── node.rb │ │ ├── namespace.rb │ │ ├── node.rb │ │ ├── output.rb │ │ ├── parent.rb │ │ ├── parseexception.rb │ │ ├── parsers/ │ │ │ ├── baseparser.rb │ │ │ ├── lightparser.rb │ │ │ ├── pullparser.rb │ │ │ ├── sax2parser.rb │ │ │ ├── streamparser.rb │ │ │ ├── treeparser.rb │ │ │ ├── ultralightparser.rb │ │ │ └── xpathparser.rb │ │ ├── quickpath.rb │ │ ├── rexml.rb │ │ ├── sax2listener.rb │ │ ├── source.rb │ │ ├── streamlistener.rb │ │ ├── syncenumerator.rb │ │ ├── text.rb │ │ ├── undefinednamespaceexception.rb │ │ ├── validation/ │ │ │ ├── relaxng.rb │ │ │ ├── validation.rb │ │ │ └── validationexception.rb │ │ ├── xmldecl.rb │ │ ├── xmltokens.rb │ │ ├── xpath.rb │ │ └── xpath_parser.rb │ ├── rinda/ │ │ ├── rinda.rb │ │ ├── ring.rb │ │ └── tuplespace.rb │ ├── rss/ │ │ ├── 0.9.rb │ │ ├── 1.0.rb │ │ ├── 2.0.rb │ │ ├── atom.rb │ │ ├── content/ │ │ │ ├── 1.0.rb │ │ │ └── 2.0.rb │ │ ├── content.rb │ │ ├── converter.rb │ │ ├── dublincore/ │ │ │ ├── 1.0.rb │ │ │ ├── 2.0.rb │ │ │ └── atom.rb │ │ ├── dublincore.rb │ │ ├── image.rb │ │ ├── itunes.rb │ │ ├── maker/ │ │ │ ├── 0.9.rb │ │ │ ├── 1.0.rb │ │ │ ├── 2.0.rb │ │ │ ├── atom.rb │ │ │ ├── base.rb │ │ │ ├── content.rb │ │ │ ├── dublincore.rb │ │ │ ├── entry.rb │ │ │ ├── feed.rb │ │ │ ├── image.rb │ │ │ ├── itunes.rb │ │ │ ├── slash.rb │ │ │ ├── syndication.rb │ │ │ ├── taxonomy.rb │ │ │ └── trackback.rb │ │ ├── maker.rb │ │ ├── parser.rb │ │ ├── rexmlparser.rb │ │ ├── rss.rb │ │ ├── slash.rb │ │ ├── syndication.rb │ │ ├── taxonomy.rb │ │ ├── trackback.rb │ │ ├── utils.rb │ │ ├── xml-stylesheet.rb │ │ ├── xml.rb │ │ ├── xmlparser.rb │ │ └── xmlscanner.rb │ ├── rss.rb │ ├── rubyunit.rb │ ├── runit/ │ │ ├── assert.rb │ │ ├── cui/ │ │ │ └── testrunner.rb │ │ ├── error.rb │ │ ├── testcase.rb │ │ ├── testresult.rb │ │ ├── testsuite.rb │ │ └── topublic.rb │ ├── scanf.rb │ ├── securerandom.rb │ ├── set.rb │ ├── shell/ │ │ ├── builtin-command.rb │ │ ├── command-processor.rb │ │ ├── error.rb │ │ ├── filter.rb │ │ ├── process-controller.rb │ │ ├── system-command.rb │ │ └── version.rb │ ├── shell.rb │ ├── shellwords.rb │ ├── singleton.rb │ ├── soap/ │ │ ├── attachment.rb │ │ ├── baseData.rb │ │ ├── element.rb │ │ ├── encodingstyle/ │ │ │ ├── aspDotNetHandler.rb │ │ │ ├── handler.rb │ │ │ ├── literalHandler.rb │ │ │ └── soapHandler.rb │ │ ├── generator.rb │ │ ├── header/ │ │ │ ├── handler.rb │ │ │ ├── handlerset.rb │ │ │ └── simplehandler.rb │ │ ├── httpconfigloader.rb │ │ ├── mapping/ │ │ │ ├── factory.rb │ │ │ ├── mapping.rb │ │ │ ├── registry.rb │ │ │ ├── rubytypeFactory.rb │ │ │ ├── typeMap.rb │ │ │ ├── wsdlencodedregistry.rb │ │ │ └── wsdlliteralregistry.rb │ │ ├── mapping.rb │ │ ├── marshal.rb │ │ ├── mimemessage.rb │ │ ├── netHttpClient.rb │ │ ├── parser.rb │ │ ├── processor.rb │ │ ├── property.rb │ │ ├── rpc/ │ │ │ ├── cgistub.rb │ │ │ ├── driver.rb │ │ │ ├── element.rb │ │ │ ├── httpserver.rb │ │ │ ├── proxy.rb │ │ │ ├── router.rb │ │ │ ├── rpc.rb │ │ │ ├── soaplet.rb │ │ │ └── standaloneServer.rb │ │ ├── soap.rb │ │ ├── streamHandler.rb │ │ └── wsdlDriver.rb │ ├── sync.rb │ ├── tempfile.rb │ ├── test/ │ │ ├── unit/ │ │ │ ├── assertionfailederror.rb │ │ │ ├── assertions.rb │ │ │ ├── autorunner.rb │ │ │ ├── collector/ │ │ │ │ ├── dir.rb │ │ │ │ └── objectspace.rb │ │ │ ├── collector.rb │ │ │ ├── error.rb │ │ │ ├── failure.rb │ │ │ ├── testcase.rb │ │ │ ├── testresult.rb │ │ │ ├── testsuite.rb │ │ │ ├── ui/ │ │ │ │ ├── console/ │ │ │ │ │ └── testrunner.rb │ │ │ │ ├── fox/ │ │ │ │ │ └── testrunner.rb │ │ │ │ ├── gtk/ │ │ │ │ │ └── testrunner.rb │ │ │ │ ├── gtk2/ │ │ │ │ │ └── testrunner.rb │ │ │ │ ├── testrunnermediator.rb │ │ │ │ ├── testrunnerutilities.rb │ │ │ │ └── tk/ │ │ │ │ └── testrunner.rb │ │ │ └── util/ │ │ │ ├── backtracefilter.rb │ │ │ ├── observable.rb │ │ │ └── procwrapper.rb │ │ └── unit.rb │ ├── thread.rb │ ├── thwait.rb │ ├── time.rb │ ├── timeout.rb │ ├── tmpdir.rb │ ├── tracer.rb │ ├── tsort.rb │ ├── un.rb │ ├── uri/ │ │ ├── common.rb │ │ ├── ftp.rb │ │ ├── generic.rb │ │ ├── http.rb │ │ ├── https.rb │ │ ├── ldap.rb │ │ ├── ldaps.rb │ │ └── mailto.rb │ ├── uri.rb │ ├── weakref.rb │ ├── webrick/ │ │ ├── accesslog.rb │ │ ├── cgi.rb │ │ ├── compat.rb │ │ ├── config.rb │ │ ├── cookie.rb │ │ ├── htmlutils.rb │ │ ├── httpauth/ │ │ │ ├── authenticator.rb │ │ │ ├── basicauth.rb │ │ │ ├── digestauth.rb │ │ │ ├── htdigest.rb │ │ │ ├── htgroup.rb │ │ │ ├── htpasswd.rb │ │ │ └── userdb.rb │ │ ├── httpauth.rb │ │ ├── httpproxy.rb │ │ ├── httprequest.rb │ │ ├── httpresponse.rb │ │ ├── https.rb │ │ ├── httpserver.rb │ │ ├── httpservlet/ │ │ │ ├── abstract.rb │ │ │ ├── cgi_runner.rb │ │ │ ├── cgihandler.rb │ │ │ ├── erbhandler.rb │ │ │ ├── filehandler.rb │ │ │ └── prochandler.rb │ │ ├── httpservlet.rb │ │ ├── httpstatus.rb │ │ ├── httputils.rb │ │ ├── httpversion.rb │ │ ├── log.rb │ │ ├── server.rb │ │ ├── ssl.rb │ │ ├── utils.rb │ │ └── version.rb │ ├── webrick.rb │ ├── wsdl/ │ │ ├── binding.rb │ │ ├── data.rb │ │ ├── definitions.rb │ │ ├── documentation.rb │ │ ├── import.rb │ │ ├── importer.rb │ │ ├── info.rb │ │ ├── message.rb │ │ ├── operation.rb │ │ ├── operationBinding.rb │ │ ├── param.rb │ │ ├── parser.rb │ │ ├── part.rb │ │ ├── port.rb │ │ ├── portType.rb │ │ ├── service.rb │ │ ├── soap/ │ │ │ ├── address.rb │ │ │ ├── binding.rb │ │ │ ├── body.rb │ │ │ ├── cgiStubCreator.rb │ │ │ ├── classDefCreator.rb │ │ │ ├── classDefCreatorSupport.rb │ │ │ ├── clientSkeltonCreator.rb │ │ │ ├── complexType.rb │ │ │ ├── data.rb │ │ │ ├── definitions.rb │ │ │ ├── driverCreator.rb │ │ │ ├── element.rb │ │ │ ├── fault.rb │ │ │ ├── header.rb │ │ │ ├── headerfault.rb │ │ │ ├── mappingRegistryCreator.rb │ │ │ ├── methodDefCreator.rb │ │ │ ├── operation.rb │ │ │ ├── servantSkeltonCreator.rb │ │ │ ├── standaloneServerStubCreator.rb │ │ │ └── wsdl2ruby.rb │ │ ├── types.rb │ │ ├── wsdl.rb │ │ └── xmlSchema/ │ │ ├── all.rb │ │ ├── annotation.rb │ │ ├── any.rb │ │ ├── attribute.rb │ │ ├── choice.rb │ │ ├── complexContent.rb │ │ ├── complexType.rb │ │ ├── content.rb │ │ ├── data.rb │ │ ├── element.rb │ │ ├── enumeration.rb │ │ ├── import.rb │ │ ├── importer.rb │ │ ├── include.rb │ │ ├── length.rb │ │ ├── parser.rb │ │ ├── pattern.rb │ │ ├── schema.rb │ │ ├── sequence.rb │ │ ├── simpleContent.rb │ │ ├── simpleExtension.rb │ │ ├── simpleRestriction.rb │ │ ├── simpleType.rb │ │ ├── unique.rb │ │ └── xsd2ruby.rb │ ├── xmlrpc/ │ │ ├── .document │ │ ├── README.txt │ │ ├── base64.rb │ │ ├── client.rb │ │ ├── config.rb │ │ ├── create.rb │ │ ├── datetime.rb │ │ ├── httpserver.rb │ │ ├── marshal.rb │ │ ├── parser.rb │ │ ├── server.rb │ │ └── utils.rb │ ├── xsd/ │ │ ├── charset.rb │ │ ├── codegen/ │ │ │ ├── classdef.rb │ │ │ ├── commentdef.rb │ │ │ ├── gensupport.rb │ │ │ ├── methoddef.rb │ │ │ └── moduledef.rb │ │ ├── codegen.rb │ │ ├── datatypes.rb │ │ ├── datatypes1999.rb │ │ ├── iconvcharset.rb │ │ ├── mapping.rb │ │ ├── namedelements.rb │ │ ├── ns.rb │ │ ├── qname.rb │ │ ├── xmlparser/ │ │ │ ├── parser.rb │ │ │ ├── rexmlparser.rb │ │ │ ├── xmlparser.rb │ │ │ └── xmlscanner.rb │ │ └── xmlparser.rb │ ├── yaml/ │ │ ├── baseemitter.rb │ │ ├── basenode.rb │ │ ├── constants.rb │ │ ├── dbm.rb │ │ ├── encoding.rb │ │ ├── error.rb │ │ ├── loader.rb │ │ ├── rubytypes.rb │ │ ├── store.rb │ │ ├── stream.rb │ │ ├── stringio.rb │ │ ├── syck.rb │ │ ├── tag.rb │ │ ├── types.rb │ │ ├── yamlnode.rb │ │ └── ypath.rb │ └── yaml.rb ├── main.c ├── marktable.c ├── marktable.h ├── marshal.c ├── math.c ├── mdoc2man.rb ├── misc/ │ ├── README │ ├── inf-ruby.el │ ├── ruby-electric.el │ ├── ruby-mode.el │ ├── ruby-style.el │ ├── rubydb2x.el │ └── rubydb3x.el ├── missing/ │ ├── acosh.c │ ├── alloca.c │ ├── crypt.c │ ├── dup2.c │ ├── erf.c │ ├── file.h │ ├── fileblocks.c │ ├── finite.c │ ├── flock.c │ ├── hypot.c │ ├── isinf.c │ ├── isnan.c │ ├── memcmp.c │ ├── memmove.c │ ├── os2.c │ ├── strcasecmp.c │ ├── strchr.c │ ├── strerror.c │ ├── strftime.c │ ├── strncasecmp.c │ ├── strstr.c │ ├── strtod.c │ ├── strtol.c │ ├── strtoul.c │ ├── vsnprintf.c │ └── x68.c ├── missing.h ├── mkconfig.rb ├── node.h ├── numeric.c ├── object.c ├── pack.c ├── parse.y ├── pointerset.c ├── pointerset.h ├── prec.c ├── process.c ├── random.c ├── range.c ├── re.c ├── re.h ├── regex.c ├── regex.h ├── ruby.1 ├── ruby.c ├── ruby.h ├── rubyio.h ├── rubysig.h ├── rubytest.rb ├── runruby.rb ├── sample/ │ ├── README │ ├── biorhythm.rb │ ├── cal.rb │ ├── cbreak.rb │ ├── clnt.rb │ ├── dbmtest.rb │ ├── dir.rb │ ├── drb/ │ │ ├── README.rd │ │ ├── README.rd.ja │ │ ├── darray.rb │ │ ├── darrayc.rb │ │ ├── dbiff.rb │ │ ├── dcdbiff.rb │ │ ├── dchatc.rb │ │ ├── dchats.rb │ │ ├── dhasen.rb │ │ ├── dhasenc.rb │ │ ├── dlogc.rb │ │ ├── dlogd.rb │ │ ├── dqin.rb │ │ ├── dqlib.rb │ │ ├── dqout.rb │ │ ├── dqueue.rb │ │ ├── drbc.rb │ │ ├── drbch.rb │ │ ├── drbm.rb │ │ ├── drbmc.rb │ │ ├── drbs-acl.rb │ │ ├── drbs.rb │ │ ├── drbssl_c.rb │ │ ├── drbssl_s.rb │ │ ├── extserv_test.rb │ │ ├── gw_ct.rb │ │ ├── gw_cu.rb │ │ ├── gw_s.rb │ │ ├── holderc.rb │ │ ├── holders.rb │ │ ├── http0.rb │ │ ├── http0serv.rb │ │ ├── name.rb │ │ ├── namec.rb │ │ ├── old_tuplespace.rb │ │ ├── rinda_ts.rb │ │ ├── rindac.rb │ │ ├── rindas.rb │ │ ├── ring_echo.rb │ │ ├── ring_inspect.rb │ │ ├── ring_place.rb │ │ ├── simpletuple.rb │ │ ├── speedc.rb │ │ └── speeds.rb │ ├── dualstack-fetch.rb │ ├── dualstack-httpd.rb │ ├── erb/ │ │ └── erb4html.rb │ ├── eval.rb │ ├── export.rb │ ├── exyacc.rb │ ├── fact.rb │ ├── fib.awk │ ├── fib.pl │ ├── fib.py │ ├── fib.rb │ ├── fib.scm │ ├── freq.rb │ ├── from.rb │ ├── fullpath.rb │ ├── getopts.test │ ├── less.rb │ ├── list.rb │ ├── list2.rb │ ├── list3.rb │ ├── logger/ │ │ ├── app.rb │ │ ├── log.rb │ │ └── shifting.rb │ ├── mine.rb │ ├── mkproto.rb │ ├── mpart.rb │ ├── mrshtest.rb │ ├── observ.rb │ ├── occur.pl │ ├── occur.rb │ ├── occur2.rb │ ├── openssl/ │ │ ├── c_rehash.rb │ │ ├── cert2text.rb │ │ ├── cert_store_view.rb │ │ ├── certstore.rb │ │ ├── cipher.rb │ │ ├── crlstore.rb │ │ ├── echo_cli.rb │ │ ├── echo_svr.rb │ │ ├── gen_csr.rb │ │ ├── smime_read.rb │ │ ├── smime_write.rb │ │ └── wget.rb │ ├── optparse/ │ │ ├── opttest.rb │ │ └── subcommand.rb │ ├── philos.rb │ ├── pi.rb │ ├── rcs.awk │ ├── rcs.rb │ ├── regx.rb │ ├── rss/ │ │ ├── blend.rb │ │ ├── convert.rb │ │ ├── list_description.rb │ │ ├── re_read.rb │ │ └── rss_recent.rb │ ├── sieve.rb │ ├── svr.rb │ ├── test.rb │ ├── testunit/ │ │ ├── adder.rb │ │ ├── subtracter.rb │ │ ├── tc_adder.rb │ │ ├── tc_subtracter.rb │ │ └── ts_examples.rb │ ├── time.rb │ ├── trojan.rb │ ├── tsvr.rb │ ├── uumerge.rb │ └── webrick/ │ ├── demo-app.rb │ ├── demo-multipart.cgi │ ├── demo-servlet.rb │ ├── demo-urlencoded.cgi │ ├── hello.cgi │ ├── hello.rb │ ├── httpd.rb │ ├── httpproxy.rb │ └── httpsd.rb ├── signal.c ├── sprintf.c ├── st.c ├── st.h ├── string.c ├── struct.c ├── system_allocator.c ├── test/ │ ├── callerforallthreads/ │ │ └── test_caller_for_each_thread.rb │ ├── csv/ │ │ └── test_csv.rb │ ├── dbm/ │ │ └── test_dbm.rb │ ├── digest/ │ │ └── test_digest.rb │ ├── drb/ │ │ ├── drbtest.rb │ │ ├── ignore_test_drb.rb │ │ ├── test_acl.rb │ │ ├── test_drb.rb │ │ ├── test_drbssl.rb │ │ ├── test_drbunix.rb │ │ ├── ut_array.rb │ │ ├── ut_array_drbssl.rb │ │ ├── ut_array_drbunix.rb │ │ ├── ut_drb.rb │ │ ├── ut_drb_drbssl.rb │ │ ├── ut_drb_drbunix.rb │ │ ├── ut_eval.rb │ │ ├── ut_large.rb │ │ ├── ut_port.rb │ │ ├── ut_safe1.rb │ │ └── ut_timerholder.rb │ ├── erb/ │ │ ├── hello.erb │ │ └── test_erb.rb │ ├── fileutils/ │ │ ├── fileasserts.rb │ │ ├── test_dryrun.rb │ │ ├── test_fileutils.rb │ │ ├── test_nowrite.rb │ │ └── test_verbose.rb │ ├── gdbm/ │ │ └── test_gdbm.rb │ ├── iconv/ │ │ ├── test_basic.rb │ │ ├── test_option.rb │ │ ├── test_partial.rb │ │ └── utils.rb │ ├── io/ │ │ └── nonblock/ │ │ └── test_flush.rb │ ├── logger/ │ │ └── test_logger.rb │ ├── matrix/ │ │ ├── test_matrix.rb │ │ └── test_vector.rb │ ├── monitor/ │ │ └── test_monitor.rb │ ├── net/ │ │ ├── http/ │ │ │ ├── test_connection.rb │ │ │ ├── test_httpheader.rb │ │ │ └── test_https_proxy.rb │ │ ├── imap/ │ │ │ └── test_imap.rb │ │ └── pop/ │ │ └── test_pop.rb │ ├── nkf/ │ │ ├── test_kconv.rb │ │ └── test_nkf.rb │ ├── openssl/ │ │ ├── ssl_server.rb │ │ ├── test_asn1.rb │ │ ├── test_cipher.rb │ │ ├── test_digest.rb │ │ ├── test_ec.rb │ │ ├── test_hmac.rb │ │ ├── test_ns_spki.rb │ │ ├── test_pair.rb │ │ ├── test_pkcs7.rb │ │ ├── test_pkey_rsa.rb │ │ ├── test_ssl.rb │ │ ├── test_x509cert.rb │ │ ├── test_x509crl.rb │ │ ├── test_x509ext.rb │ │ ├── test_x509name.rb │ │ ├── test_x509req.rb │ │ ├── test_x509store.rb │ │ └── utils.rb │ ├── optparse/ │ │ ├── test_getopts.rb │ │ ├── test_noarg.rb │ │ ├── test_optarg.rb │ │ ├── test_optparse.rb │ │ ├── test_placearg.rb │ │ ├── test_reqarg.rb │ │ └── test_summary.rb │ ├── ostruct/ │ │ └── test_ostruct.rb │ ├── pathname/ │ │ └── test_pathname.rb │ ├── rational/ │ │ ├── test_fixnum_gcd.rb │ │ ├── test_rational.rb │ │ └── test_rational2.rb │ ├── rdoc/ │ │ └── parsers/ │ │ └── test_parse_c.rb │ ├── readline/ │ │ └── test_readline.rb │ ├── rexml/ │ │ └── test_document.rb │ ├── rinda/ │ │ └── test_rinda.rb │ ├── rss/ │ │ ├── rss-assertions.rb │ │ ├── rss-testcase.rb │ │ ├── test_1.0.rb │ │ ├── test_2.0.rb │ │ ├── test_accessor.rb │ │ ├── test_atom.rb │ │ ├── test_content.rb │ │ ├── test_dublincore.rb │ │ ├── test_image.rb │ │ ├── test_inherit.rb │ │ ├── test_itunes.rb │ │ ├── test_maker_0.9.rb │ │ ├── test_maker_1.0.rb │ │ ├── test_maker_2.0.rb │ │ ├── test_maker_atom_entry.rb │ │ ├── test_maker_atom_feed.rb │ │ ├── test_maker_content.rb │ │ ├── test_maker_dc.rb │ │ ├── test_maker_image.rb │ │ ├── test_maker_itunes.rb │ │ ├── test_maker_slash.rb │ │ ├── test_maker_sy.rb │ │ ├── test_maker_taxo.rb │ │ ├── test_maker_trackback.rb │ │ ├── test_maker_xml-stylesheet.rb │ │ ├── test_parser.rb │ │ ├── test_parser_1.0.rb │ │ ├── test_parser_2.0.rb │ │ ├── test_parser_atom_entry.rb │ │ ├── test_parser_atom_feed.rb │ │ ├── test_setup_maker_0.9.rb │ │ ├── test_setup_maker_1.0.rb │ │ ├── test_setup_maker_2.0.rb │ │ ├── test_setup_maker_atom_entry.rb │ │ ├── test_setup_maker_atom_feed.rb │ │ ├── test_setup_maker_itunes.rb │ │ ├── test_setup_maker_slash.rb │ │ ├── test_slash.rb │ │ ├── test_syndication.rb │ │ ├── test_taxonomy.rb │ │ ├── test_to_s.rb │ │ ├── test_trackback.rb │ │ ├── test_version.rb │ │ └── test_xml-stylesheet.rb │ ├── ruby/ │ │ ├── beginmainend.rb │ │ ├── endblockwarn.rb │ │ ├── envutil.rb │ │ ├── marshaltestlib.rb │ │ ├── suicide.rb │ │ ├── test_alias.rb │ │ ├── test_array.rb │ │ ├── test_assignment.rb │ │ ├── test_beginendblock.rb │ │ ├── test_bignum.rb │ │ ├── test_call.rb │ │ ├── test_case.rb │ │ ├── test_clone.rb │ │ ├── test_condition.rb │ │ ├── test_const.rb │ │ ├── test_defined.rb │ │ ├── test_dir.rb │ │ ├── test_enum.rb │ │ ├── test_enumerator.rb │ │ ├── test_env.rb │ │ ├── test_eval.rb │ │ ├── test_exception.rb │ │ ├── test_file.rb │ │ ├── test_file_exhaustive.rb │ │ ├── test_fixnum.rb │ │ ├── test_float.rb │ │ ├── test_gc.rb │ │ ├── test_hash.rb │ │ ├── test_ifunless.rb │ │ ├── test_integer.rb │ │ ├── test_io.rb │ │ ├── test_iterator.rb │ │ ├── test_marshal.rb │ │ ├── test_math.rb │ │ ├── test_method.rb │ │ ├── test_objectspace.rb │ │ ├── test_pack.rb │ │ ├── test_path.rb │ │ ├── test_pipe.rb │ │ ├── test_proc.rb │ │ ├── test_process.rb │ │ ├── test_rand.rb │ │ ├── test_range.rb │ │ ├── test_readpartial.rb │ │ ├── test_settracefunc.rb │ │ ├── test_signal.rb │ │ ├── test_sleep.rb │ │ ├── test_string.rb │ │ ├── test_stringchar.rb │ │ ├── test_struct.rb │ │ ├── test_super.rb │ │ ├── test_symbol.rb │ │ ├── test_system.rb │ │ ├── test_time.rb │ │ ├── test_trace.rb │ │ ├── test_variable.rb │ │ ├── test_whileuntil.rb │ │ └── ut_eof.rb │ ├── runner.rb │ ├── sdbm/ │ │ └── test_sdbm.rb │ ├── soap/ │ │ ├── asp.net/ │ │ │ ├── hello.wsdl │ │ │ └── test_aspdotnet.rb │ │ ├── calc/ │ │ │ ├── calc.rb │ │ │ ├── calc2.rb │ │ │ ├── server.cgi │ │ │ ├── server.rb │ │ │ ├── server2.rb │ │ │ ├── test_calc.rb │ │ │ ├── test_calc2.rb │ │ │ └── test_calc_cgi.rb │ │ ├── fault/ │ │ │ └── test_customfault.rb │ │ ├── header/ │ │ │ ├── server.cgi │ │ │ ├── test_authheader.rb │ │ │ ├── test_authheader_cgi.rb │ │ │ └── test_simplehandler.rb │ │ ├── helloworld/ │ │ │ ├── hw_s.rb │ │ │ └── test_helloworld.rb │ │ ├── marshal/ │ │ │ ├── test_digraph.rb │ │ │ ├── test_marshal.rb │ │ │ └── test_struct.rb │ │ ├── ssl/ │ │ │ ├── README │ │ │ ├── ca.cert │ │ │ ├── client.cert │ │ │ ├── client.key │ │ │ ├── server.cert │ │ │ ├── server.key │ │ │ ├── sslsvr.rb │ │ │ ├── subca.cert │ │ │ └── test_ssl.rb │ │ ├── struct/ │ │ │ └── test_struct.rb │ │ ├── swa/ │ │ │ └── test_file.rb │ │ ├── test_basetype.rb │ │ ├── test_envelopenamespace.rb │ │ ├── test_httpconfigloader.rb │ │ ├── test_mapping.rb │ │ ├── test_no_indent.rb │ │ ├── test_property.rb │ │ ├── test_soapelement.rb │ │ ├── test_streamhandler.rb │ │ ├── test_styleuse.rb │ │ └── wsdlDriver/ │ │ ├── README.txt │ │ ├── calc.wsdl │ │ ├── document.wsdl │ │ ├── echo_version.rb │ │ ├── simpletype.wsdl │ │ ├── test_calc.rb │ │ ├── test_document.rb │ │ └── test_simpletype.rb │ ├── socket/ │ │ ├── test_nonblock.rb │ │ ├── test_socket.rb │ │ └── test_unix.rb │ ├── stringio/ │ │ └── test_stringio.rb │ ├── strscan/ │ │ └── test_stringscanner.rb │ ├── testunit/ │ │ ├── collector/ │ │ │ ├── test_dir.rb │ │ │ └── test_objectspace.rb │ │ ├── runit/ │ │ │ ├── test_assert.rb │ │ │ ├── test_testcase.rb │ │ │ ├── test_testresult.rb │ │ │ └── test_testsuite.rb │ │ ├── test_assertions.rb │ │ ├── test_error.rb │ │ ├── test_failure.rb │ │ ├── test_testcase.rb │ │ ├── test_testresult.rb │ │ ├── test_testsuite.rb │ │ └── util/ │ │ ├── test_backtracefilter.rb │ │ ├── test_observable.rb │ │ └── test_procwrapper.rb │ ├── thread/ │ │ ├── lbtest.rb │ │ └── test_thread.rb │ ├── uri/ │ │ ├── test_common.rb │ │ ├── test_ftp.rb │ │ ├── test_generic.rb │ │ ├── test_http.rb │ │ ├── test_ldap.rb │ │ └── test_mailto.rb │ ├── webrick/ │ │ ├── .htaccess │ │ ├── test_cgi.rb │ │ ├── test_cookie.rb │ │ ├── test_filehandler.rb │ │ ├── test_httpauth.rb │ │ ├── test_httprequest.rb │ │ ├── test_httpserver.rb │ │ ├── test_httputils.rb │ │ ├── test_httpversion.rb │ │ ├── test_server.rb │ │ ├── utils.rb │ │ ├── webrick.cgi │ │ └── webrick_long_filename.cgi │ ├── wsdl/ │ │ ├── any/ │ │ │ ├── any.wsdl │ │ │ ├── expectedDriver.rb │ │ │ ├── expectedEcho.rb │ │ │ ├── expectedService.rb │ │ │ └── test_any.rb │ │ ├── axisArray/ │ │ │ ├── axisArray.wsdl │ │ │ ├── itemList.rb │ │ │ └── test_axisarray.rb │ │ ├── datetime/ │ │ │ ├── DatetimeService.rb │ │ │ ├── datetime.rb │ │ │ ├── datetime.wsdl │ │ │ ├── datetimeServant.rb │ │ │ └── test_datetime.rb │ │ ├── document/ │ │ │ ├── document.wsdl │ │ │ ├── echo.rb │ │ │ ├── number.wsdl │ │ │ ├── ping_nosoapaction.wsdl │ │ │ ├── test_nosoapaction.rb │ │ │ ├── test_number.rb │ │ │ └── test_rpc.rb │ │ ├── emptycomplextype.wsdl │ │ ├── map/ │ │ │ ├── map.wsdl │ │ │ ├── map.xml │ │ │ └── test_map.rb │ │ ├── marshal/ │ │ │ ├── person.wsdl │ │ │ ├── person_org.rb │ │ │ └── test_wsdlmarshal.rb │ │ ├── multiplefault.wsdl │ │ ├── qualified/ │ │ │ ├── lp.rb │ │ │ ├── lp.wsdl │ │ │ ├── lp.xsd │ │ │ ├── np.wsdl │ │ │ ├── test_qualified.rb │ │ │ └── test_unqualified.rb │ │ ├── raa/ │ │ │ ├── RAA.rb │ │ │ ├── RAAServant.rb │ │ │ ├── RAAService.rb │ │ │ ├── README.txt │ │ │ ├── raa.wsdl │ │ │ ├── server.rb │ │ │ └── test_raa.rb │ │ ├── ref/ │ │ │ ├── expectedProduct.rb │ │ │ ├── product.wsdl │ │ │ └── test_ref.rb │ │ ├── rpc/ │ │ │ ├── echoDriver.rb │ │ │ ├── echo_serviceClient.rb │ │ │ ├── rpc.wsdl │ │ │ ├── test-rpc-lit.wsdl │ │ │ ├── test-rpc-lit12.wsdl │ │ │ ├── test_rpc.rb │ │ │ └── test_rpc_lit.rb │ │ ├── simpletype/ │ │ │ ├── rpc/ │ │ │ │ ├── expectedClient.rb │ │ │ │ ├── expectedDriver.rb │ │ │ │ ├── expectedEchoVersion.rb │ │ │ │ ├── expectedServant.rb │ │ │ │ ├── expectedService.rb │ │ │ │ ├── rpc.wsdl │ │ │ │ └── test_rpc.rb │ │ │ ├── simpletype.wsdl │ │ │ └── test_simpletype.rb │ │ ├── soap/ │ │ │ ├── soapbodyparts.wsdl │ │ │ └── test_soapbodyparts.rb │ │ ├── test_emptycomplextype.rb │ │ ├── test_fault.rb │ │ └── test_multiplefault.rb │ ├── xmlrpc/ │ │ ├── data/ │ │ │ ├── bug_bool.expected │ │ │ ├── bug_bool.xml │ │ │ ├── bug_cdata.expected │ │ │ ├── bug_cdata.xml │ │ │ ├── bug_covert.expected │ │ │ ├── bug_covert.xml │ │ │ ├── datetime_iso8601.xml │ │ │ ├── fault.xml │ │ │ ├── value.expected │ │ │ ├── value.xml │ │ │ ├── xml1.expected │ │ │ └── xml1.xml │ │ ├── test_cookie.rb │ │ ├── test_datetime.rb │ │ ├── test_features.rb │ │ ├── test_marshal.rb │ │ ├── test_parser.rb │ │ ├── test_webrick_server.rb │ │ └── webrick_testing.rb │ ├── xsd/ │ │ ├── codegen/ │ │ │ └── test_classdef.rb │ │ ├── noencoding.xml │ │ ├── test_noencoding.rb │ │ ├── test_xmlschemaparser.rb │ │ ├── test_xsd.rb │ │ └── xmlschema.xml │ ├── yaml/ │ │ ├── test_yaml.rb │ │ └── test_yamlstore.rb │ └── zlib/ │ └── test_zlib.rb ├── time.c ├── util.c ├── util.h ├── variable.c ├── version.c ├── version.h ├── vms/ │ ├── vms.h │ ├── vmsruby_private.c │ └── vmsruby_private.h ├── win32/ │ ├── Makefile.sub │ ├── README.win32 │ ├── configure.bat │ ├── dir.h │ ├── ifchange.bat │ ├── mkexports.rb │ ├── resource.rb │ ├── rm.bat │ ├── setup.mak │ ├── win32.c │ ├── win32.h │ └── winmain.c ├── wince/ │ ├── Makefile.sub │ ├── README.wince │ ├── assert.c │ ├── assert.h │ ├── configure.bat │ ├── direct.c │ ├── direct.h │ ├── errno.c │ ├── errno.h │ ├── fcntl.h │ ├── io.h │ ├── io_wce.c │ ├── process.h │ ├── process_wce.c │ ├── setup.mak │ ├── signal.h │ ├── signal_wce.c │ ├── stddef.h │ ├── stdio.c │ ├── stdlib.c │ ├── string_wce.c │ ├── sys/ │ │ ├── stat.c │ │ ├── stat.h │ │ ├── timeb.c │ │ ├── timeb.h │ │ ├── types.h │ │ ├── utime.c │ │ └── utime.h │ ├── time.h │ ├── time_wce.c │ ├── varargs.h │ ├── wince.c │ ├── wince.h │ ├── wincemain.c │ ├── wincon.h │ └── winsock2.c └── x68/ ├── _dtos18.c ├── _round.c ├── fconvert.c └── select.c ================================================ FILE CONTENTS ================================================ ================================================ FILE: .cvsignore ================================================ *.bak *.orig *.rej *.sav *~ .*.list .*.time .ccmalloc .ppack .ext .git .svn .pc COPYING.LIB ChangeLog.pre-alpha ChangeLog.pre1_1 Makefile README.fat-patch README.v6 README.atheos archive autom4te*.cache automake beos config.cache config.h config.h.in config.log config.status configure libruby.so.* miniruby newdate.rb newver.rb parse.c patches ppack preview rbconfig.rb repack riscos rubicon ruby ruby-man.rd.gz tmp web y.output y.tab.c ================================================ FILE: .document ================================================ # This file determines which files in the # Ruby hierarchy will be processed by the RDoc # tool when it is given the top-level directory # as an argument # Process all the C source files *.c # the lib/ directory (which has its own .document file) lib # and some of the ext/ directory (which has its own .document file) ext ================================================ FILE: .gitignore ================================================ .ext .installed.list *.o *.so *.bundle *.dSYM autom4te.cache confdefs.h config.h config.log config.status config.status.lineno /configure conftest.c conftest.er1 mkmf.log Makefile largefile.h .rbconfig.time enc.mk encdb.h insns.inc insns_info.inc lex.c lib/doc libruby-static.a miniprelude.c miniruby node_name.inc opt_sc.inc optinsn.inc optunifs.inc parse.c prelude.c rbconfig.rb revision.h /ruby transdb.h vm.inc vmtc.inc yasmdata.rb ext/dl/call.func ext/dl/callback.func ext/dl/cbtable.func ext/dl/dlconfig.h ext/dl/dlconfig.rb ext/openssl/extconf.h ext/win32ole/.document distro/version.txt distro/documentation.html /ruby-enterprise-* distro/rubygems*.tgz ruby-enterprise-*.tar.gz fakeroot !distro/runtime/*/ruby ================================================ FILE: COPYING ================================================ Ruby is copyrighted free software by Yukihiro Matsumoto . You can redistribute it and/or modify it under either the terms of the GPL version 2 (see the file GPL), or the conditions below: 1. You may make and give away verbatim copies of the source form of the software without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may modify your copy of the software in any way, provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or by allowing the author to include your modifications in the software. b) use the modified software only within your corporation or organization. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 3. You may distribute the software in object code or binary form, provided that you do at least ONE of the following: a) distribute the binaries and library files of the software, together with instructions (in the manual page or equivalent) on where to get the original distribution. b) accompany the distribution with the machine-readable source of the software. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 4. You may modify and include the part of the software into any other software (possibly commercial). But some files in the distribution are not written by the author, so that they are not under these terms. For the list of those files and their copying conditions, see the file LEGAL. 5. The scripts and library files supplied as input to or produced as output from the software do not automatically fall under the copyright of the software, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this software. 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ================================================ FILE: COPYING.ja ================================================ $BK\%W%m%0%i%`$O%U%j!<%=%U%H%&%'%"$G$9!%(BGPL(the GNU General Public License)$B$^$?$O0J2<$K<($9>r7o$GK\%W%m%0%i%`$r:FG[I[$G(B $B$-$^$9!%(BGPL$B$K$D$$$F$O(BGPL$B%U%!%$%k$r;2>H$7$F2<$5$$!%(B 1. $BJ#@=$O@)8B$J$/<+M3$G$9!%(B 2. $B0J2<$N>r7o$N$$$:$l$+$rK~$?$9;~$KK\%W%m%0%i%`$N%=!<%9$r(B $B<+M3$KJQ99$G$-$^$9!%(B (a) $B%M%C%H%K%e!<%:$K%]%9%H$7$?$j!$:nA0$rJQ99$9$k!%(B $B$=$N%=%U%H%&%'%"$rG[I[$9$k;~$K$OJQ99A0$NK\%W%m%0%i(B $B%`$bF1;~$KG[I[$9$k!%$^$?$OJQ99A0$NK\%W%m%0%i%`$N%=!<(B $B%9$NF~$NJQ99>r7o$r:nr7o$N$$$:$l$+$rK~$?$9;~$KK\%W%m%0%i%`$r%3%s%Q%$(B $B%k$7$?%*%V%8%'%/%H%3!<%I$dA0$rJQ99$7$?$&$(!$%*%j%8%J(B $B%k$N%=!<%9%3!<%I$NF~$NG[I[>r7o$r:n$N%W%m%0%i%`$X$N0zMQ$O$$$+$J$kL\E*$G$"$l<+M3$G$9!%$?(B $B$@$7!$K\%W%m%0%i%`$K4^$^$l$kB>$N:n$l$N:nl9g$,$"$j$^$9!%(B $B$=$l$i%U%!%$%k$N0lMw$H$=$l$>$l$NG[I[>r7o$J$I$KIU$$$F$O(B LEGAL$B%U%!%$%k$r;2>H$7$F$/$@$5$$!%(B 5. $BK\%W%m%0%i%`$X$NF~NO$H$J$k%9%/%j%W%H$*$h$S!$K\%W%m%0%i(B $B%`$+$i$N=PNO$N8"Mx$OK\%W%m%0%i%`$N:n(B $B$l$NF~=PNO$r@8@.$7$??M$KB0$7$^$9!%$^$?!$K\%W%m%0%i%`$K(B $BAH$_9~$^$l$k$?$a$N3HD%%i%$%V%i%j$K$D$$$F$bF1MM$G$9!%(B 6. $BK\%W%m%0%i%`$OL5J]>Z$G$9!%:n * ext/rational/rational.c: Added to provide a fast implementation of Fixnum#gcd (and maybe some others in the future) in C. The base code was submitted by Kurt Stephens. [Feature #2561] * ext/rational/lib/rational.rb: Moved from lib/rational.rb. Make overall code optimization; submitted by Kurt Stephens. [Feature #2561] * test/rational/test_rational.rb, test/rational/test_rational2.rb: Add tests for Rational, ported from trunk. * test/rational/test_fixnum_gcd.rb: Add a test for Integer#gcd. Case values are only provided for i386 and amd64 at the moment; submitted by Kurt Stephens. [Feature #2561] Wed Feb 3 21:14:59 2010 Nobuyoshi Nakada * lib/net/http.rb (Net::HTTP#request): close @socket only after started. [ruby-core:28028] Sat May 22 19:36:38 2010 Nobuyoshi Nakada * eval.c (proc_invoke): reverted r25975. [ruby-dev:39931] [ruby-dev:40059] * eval.c (rb_mod_define_method): return original block but not bound block. [ruby-core:26984] Thu May 20 16:28:17 2010 Nobuyoshi Nakada * lib/webrick/httpservlet/filehandler.rb (make_partial_content): add bytes-unit. [ruby-dev:40030] Thu May 20 16:17:37 2010 NAKAMURA, Hiroshi * ext/zlib/zlib.c: backport r18029 and r21861 from trunk. * r18029 ext/zlib/zlib.c (rb_deflate_params): flush before deflateParams. [ruby-core:17675] (by mame) * r21861 ext/zlib/zlib.c (zstream_run): desperately guard the variable. [ruby-core:20576] (by usa) * test/zlib/test_zlib.rb: backport deflate tests from trunk. Thu May 20 15:59:14 2010 Kouhei Sutou * lib/rss/maker/base.rb, test/rss/test_maker_0.9.rb: accept any time format in maker. [ruby-core:26923] Thu May 20 15:54:08 2010 Akinori MUSHA * eval.c (recursive_push): Taint internal hash to prevent unexpected SecurityError; fixes #1864. Thu May 20 15:39:26 2010 Nobuyoshi Nakada * io.c (io_fwrite): preserve errno. [ruby-core:27425] Tue Apr 20 08:04:37 2010 NAKAMURA Usaku * io.c (rb_io_s_read): close the IO if an exception is raised on seeking. [ruby-core:27429] Mon Apr 19 22:43:28 2010 Nobuyoshi Nakada * ruby.h (RB_GC_GUARD_PTR): workaround for gcc optimization. [ruby-core:27402] Tue Apr 20 06:40:53 2010 Marc-Andre Lafortune * lib/uri/generic.rb (URI::Generic::eql): Check the class of the compared object. Based on a patch by Peter McLain [ruby-core:27019] Fri Apr 2 03:27:22 2010 NAKAMURA, Hiroshi * lib/net/http.rb (HTTPGenericRequest#send_request_with_body_stream): increased encoding chunk size for POST request with body_stream (1K -> 16K). patched by Brian Candler. #1284. * test/net/http/test_post_io.rb: added for the patch. It's good if a patch comes with a test. Thu Apr 1 05:32:17 2010 NAKAMURA Usaku * string.c (rb_str_inspect): wrong result of UTF-8 inspect because of the mistake of calculation. reported by eban via IRC. Sun Jan 10 19:00:31 2010 Nobuyoshi Nakada * lib/webrick/accesslog.rb : Escape needed. * lib/webrick/httpstatus.rb : ditto. * lib/webrick/httprequest.rb : ditto. * lib/webrick/httputils.rb : ditto. Fri Jan 8 18:51:11 2010 Nobuyoshi Nakada * io.c (io_fwrite): preserve errno. [ruby-core:27425] Thu Dec 24 18:04:27 2009 Nobuyoshi Nakada * configure.in: default ac_cv_prog_CC to CC. Thu Dec 24 17:56:32 2009 Nobuyoshi Nakada * ext/extmk.rb: MINIRUBY is given via make-flag. Thu Dec 24 17:56:32 2009 Nobuyoshi Nakada * common.mk (EXTMK_ARGS): needs MINIRUBY for cross-compile. [ruby-core:20131] Thu Dec 24 17:56:32 2009 NAKAMURA Usaku * common.mk (EXTMK_ARGS): shouldn't use ``\"'' because cmd.exe eat ''\'' in such quotes. Thu Dec 24 17:56:32 2009 Nobuyoshi Nakada * common.mk (EXTMK_ARGS): needs MINIRUBY for cross-compile. [ruby-core:20131] Thu Dec 24 17:56:32 2009 Nobuyoshi Nakada * mkconfig.rb (patchlevel): config.status may not contain PATCHLEVEL even if other version numbers exist. Thu Dec 24 17:50:35 2009 Yusuke Endoh * ext/stringio/stringio.c (strio_init): rewind when reopened. Thu Dec 24 17:06:13 2009 Nobuyoshi Nakada * gc.c (run_final): runs finalizers with the object terminated. * gc.c (rb_gc_call_finalizer_at_exit): ObjectSpace::finalizers needs to scan whole object space, although deprecated. Thu Dec 24 17:06:13 2009 Nobuyoshi Nakada * gc.c (chain_finalized_object): deletes finalizers to be invoked from finalizer_table. * gc.c (rb_gc_call_finalizer_at_exit): warns when could not invoke finalizers. Mon Dec 21 16:09:09 2009 NAKAMURA Usaku * win32/Makefile.sub (LD_SHARED1): typo. Wed Dec 16 20:17:40 2009 NAKAMURA Usaku * win32/win32.c (CreateChild): allocate temporary buffer and use it instead of directly modify the passed string. [ruby-dev:39635] Wed Dec 16 19:49:47 2009 URABE Shyouhei * instruby.rb (with_destdir): revert. [ruby-dev:39885] Mon Dec 14 13:28:48 2009 Nobuyoshi Nakada * lib/test/unit.rb (Test::Unit.run=, Test::Unit.run?): fixed rdoc. [ruby-core:25034] Mon Dec 14 13:21:32 2009 Nobuyoshi Nakada * lib/open3.rb (Open3#popen3): fixed and improved rdoc. [ruby-core:25658] Mon Dec 14 13:09:01 2009 Nobuyoshi Nakada * configure.in (LIBPATHFLAG): use numbered specifier if RPATHFLAG is set. [ruby-talk:322136] Mon Dec 14 12:53:56 2009 Marc-Andre Lafortune * lib/bigdecimal.rb: fix comparison operators [ruby-core:26646] Mon Dec 14 12:40:10 2009 Marc-Andre Lafortune * object.c (rb_Float): Allow results of to_f to be NaN [ruby-core:26733] Mon Dec 14 12:35:21 2009 Nobuyoshi Nakada * eval.c (proc_invoke): unbound block created by define_method cannot call super. [ruby-core:26984] Mon Dec 14 12:06:39 2009 Akinori MUSHA * ext/digest/digest.c (rb_digest_instance_method_unimpl): Do not call rb_inspect() on an object that does not implement necessary methods; reported by NaHi. Mon Dec 14 11:47:31 2009 Nobuyoshi Nakada * eval.c (rb_method_missing): adjusted format and argument number. * eval.c (rb_call): fixed for super in cached method. [ruby-dev:39757] Mon Dec 14 11:40:35 2009 Nobuyoshi Nakada * hash.c (ruby_setenv): get rid of crash in Solaris 8 and 10. [ruby-core:26668] Mon Dec 14 11:31:58 2009 Takeyuki FUJIOKA * lib/cgi.rb: fix command-line option of non-interactive terminal. [ruby-core:23016] Mon Dec 14 03:36:20 2009 Marc-Andre Lafortune * eval.c (method_inspect, method_name, mnew): Bug fix when method created from an alias. Based on a patch by Peter Vanbroekhoven [ruby-core:22040] Mon Dec 14 02:27:32 2009 Yusuke Endoh * hash.c (rb_hash): always return a fixnum value because a return value of rb_hash may be used as a hash value itself and bignums have no unique VALUE. * test/ruby/test_hash.rb: add a test for above. Mon Dec 14 00:42:55 2009 Nobuyoshi Nakada * string.c (rb_str_inspect): get rid of adding garbage to shor UTF-8 string. [ruby-dev:39550] Sun Dec 13 23:54:22 2009 Nobuyoshi Nakada * marshal.c (marshal_load): should set taintness. [ruby-dev:39723] Sun Dec 13 23:54:22 2009 Nobuyoshi Nakada * marshal.c (struct {dump,load}_arg): manage with dfree, instead of using local variable which may be moved by context switch. [ruby-dev:39425] Wed Nov 25 17:42:33 2009 Nobuyoshi Nakada * io.c (io_fwrite): adjust stdio file position after direct write on BSDish platforms. [ruby-core:26300] Wed Nov 25 17:39:28 2009 Nobuyoshi Nakada * test/ostruct/test_ostruct.rb (test_frozen): added assertions. Wed Nov 25 16:43:24 2009 NAKAMURA, Hiroshi * lib/monitor.rb (MonitorMixin.mon_release): ensure the scheduled thread to be alive when a thread is releasing a monitor. #2240 Wed Nov 25 16:28:11 2009 Marc-Andre Lafortune * lib/rexml/element.rb (text=): false should be converted to string. A patch by Teruo Oshida [ruby-dev:38351] Wed Nov 25 16:18:37 2009 Nobuyoshi Nakada * eval.c (rb_clear_cache_for_undef): clear entries for inherited methods. [ruby-core:26074] Tue Nov 24 16:15:18 2009 Nobuyoshi Nakada * ext/iconv/iconv.c (iconv_create): cannot retry with given block. [ruby-dev:39487] Tue Nov 24 16:12:33 2009 Shugo Maeda * lib/net/imap.rb (resp_text_code): accepts response codes without text. backported from trunk. [ruby-core:24194] Tue Nov 24 16:09:41 2009 Shugo Maeda * lib/net/ftp.rb (getaddress): rescue exceptions. [ruby-dev:39451] Tue Nov 24 15:51:07 2009 Marc-Andre Lafortune * ext/curses/curses.c: Many functions of module Curses could cause a crash if the ncurses library was not properly initialized. Fix pointed out by Alexander Beisig [ruby-core:22592] Functions fixed: attroff, attron, attrset, bkgd, bkgdset, can_change_color, close_screen, closed, color_content, curs_set, def_prog_mode, delch, deleteln, getmouse, getstr, has_colors, init_color, init_pair, insertln, keyname, mouseinterval, mousemask, pair_content, pair_number, reset_prog_mode, resizeterm, scrl, setscrreg, standend, standout, start_color, timeout, ungetmouse Fri Nov 20 15:49:59 2009 Tanaka Akira * lib/resolv.rb (Resolv::DNS.bind_random_port): bind to "::" for IPv6. (Resolv::DNS::ConnectedUDP#initialize): specify is_ipv6 argument of bind_random_port. [ruby-core:25970] Thu Nov 19 18:03:31 2009 Takeyuki FUJIOKA * lib/cgi.rb (CGI.unescapeHTML): fix for hex values 80-FF, single-byte hex entity encodings from 80-FF are valid HTML. [ruby-core:25702] Thu Nov 19 15:34:40 2009 Yukihiro Matsumoto * io.c (rb_io_fptr_finalize): free fptr to avoid memory leaks. fixed: #2009 [ruby-core:25173] [ruby-dev:39410] Thu Nov 19 15:27:17 2009 Marc-Andre Lafortune * lib/net/http.rb (transport_request): Handle timeout error by closing socket if exception raised. [ruby-core:20976] Wed Nov 18 14:14:38 2009 Marc-Andre Lafortune * ext/openssl/ossl_config.c (ossl_config_add_value_m, ossl_config_set_section): Check if frozen (or untainted for $SECURE >= 4) [ruby-core:18377] Wed Nov 18 14:13:14 2009 NAKAMURA Usaku * instruby.rb: win32/win32.h exists in srcdir. reported by arton ( http://www.artonx.org/diary/20090919.html#p01 ) Wed Nov 18 14:13:14 2009 NAKAMURA Usaku * win32/win32.c (subtract): if the parameters are same value, should return zero. Wed Nov 18 14:13:14 2009 NAKAMURA Usaku * win32/win32.c (rb_w32_select): of course, need to initialize rest. Wed Nov 18 14:13:14 2009 NAKAMURA Usaku * win32/win32.c (rb_w32_select): wait specified time on select. Wed Nov 18 14:13:14 2009 NAKAMURA Usaku * win32/win32.c (rb_w32_select): on 1.8, we don't need to poll sockets, because our select is never called from multiple threads. Tue Nov 17 16:22:22 2009 Nobuyoshi Nakada * eval.c (rb_thread_start_0, rb_thread_start_1): should call star timer after added new thread to thread list. [ruby-core:25613] Tue Nov 17 16:22:22 2009 Nobuyoshi Nakada * eval.c (rb_thread_start_timer): start to catch SIGVTALRM together with timer thread. [ruby-core:25606] * eval.c (rb_thread_atfork): stop timer thread. Tue Nov 17 16:04:02 2009 Marc-Andre Lafortune * lib/cgi/cookie.rb (value): Keep CGI::Cookie#value in sync with the cookie itself. A patch by Arthur Schreiber [ruby-core:17634] Tue Nov 17 15:49:00 2009 Marc-Andre Lafortune * lib/irb/ext/multi-irb.rb: Fix arguments handling for shell commands in irb; a patch by Yusuke Endoh [ruby-dev:35075] Tue Nov 17 15:32:27 2009 Nobuyoshi Nakada * io.c (rb_io_binmode): check if closed regardless platforms. [ruby-core:25363] Tue Nov 17 15:31:09 2009 Nobuyoshi Nakada * numeric.c (round): added declaration. [ruby-dev:39222] Mon Nov 16 19:58:02 2009 Nobuyoshi Nakada * gc.c (gc_sweep): makes new room if object space is full of finalized objects and has no free objects. [ruby-dev:39201] Mon Nov 16 19:45:27 2009 Tanaka Akira * util.c: suppress strict-aliasing warning with gcc-4.4.0 -O2 to fix infinite loop by ruby -e "1.402e-45" . Mon Nov 16 19:28:23 2009 URABE Shyouhei * ext/bigdecimal/bigdecimal.c (BigDecimal_to_i): revert a part of r23645, which was not a bug fix. [ruby-dev:39474] Fri Sep 11 11:56:53 2009 Akinori MUSHA * class.c (rb_singleton_class_clone): Qnil must be used for a null class reference when we use NIL_P() to check class reference validity. The bug was exposed by the spec test of Sequel. * eval.c (ruby_init): Use NEW_CREF(). Thu Sep 10 10:53:03 2009 NAKAMURA Usaku * io.c (rb_sysopen): workaround for MSVCRT's bug. [ruby-core:24838] Mon Sep 7 19:52:44 2009 Tanaka Akira * eval.c (rb_thread_schedule): need select for WAIT_SELECT, even if already timeout. [ruby-dev:38971] (WAIT_DONE): defined for mark threads which can be runnable. Mon Sep 7 19:52:44 2009 Tanaka Akira * eval.c (rb_thread_schedule): refine previous change. Mon Sep 7 19:52:44 2009 Tanaka Akira * eval.c (rb_thread_schedule): fix condition for making thread runnable. [ruby-core:23515] Sun Sep 6 19:47:10 2009 Nobuyoshi Nakada * eval.c (rb_exc_raise, rb_exc_fatal): require exception object. [ruby-core:24767] Sun Sep 6 01:34:03 2009 NAKAMURA Usaku * win32/win32.c (rb_w32_connect): return value was broken when some error occurred. [ruby-core:24234] Fri Sep 4 10:03:22 2009 Nobuyoshi Nakada * io.c (argf_eof): go to the next file if called after ARGF.close or ARGF.skip. a patch from Mike Kasick at [ruby-core:24561]. Sun Aug 9 17:43:44 2009 Keiju Ishitsuka * lib/irb.rb, lib/irb/init.rb, lib/irb/ext/save-history.rb: add IRB::irb_at_exit. no use finalizer saving history. [ruby-dev-38563] Wed Aug 5 15:29:54 2009 NAKAMURA Usaku * io.c (rb_io_flush): fsync() after buffer is flushed on win32. backported from trunk. [ruby-core:20043] Tue Aug 4 11:00:30 2009 Nobuyoshi Nakada * re.h (RMATCH_REGS): added for compatibility. Mon Aug 3 14:46:53 2009 Yukihiro Matsumoto * lib/complex.rb (Numeric#arg): should return NaN for NaN. [ruby-core:24116] Thu Jul 30 09:27:44 2009 Nobuyoshi Nakada * bignum.c (big_lshift, big_rshift): return Bignum always withou normalization. [ruby-dev:38680] Wed Jul 29 11:19:47 2009 Yukihiro Matsumoto * io.c (argf_close): always call #close method. [ruby-core:23853] * io.c (argf_skip): should close only when current_file is available. Sat Jul 25 21:26:18 2009 Yukihiro Matsumoto * enum.c (first_i): Enumerator#first should consume only what is needed. a patch from Marc-Andre Lafortune. [ruby-core:23661] * enum.c (take_i): ditto. * enum.c (enum_first): call to_int once for an argument. a patch from Marc-Andre Lafortune. Fri Jul 24 17:19:40 2009 Yukihiro Matsumoto * lib/cgi.rb (HTTP_STATUS): typo fixed. [ruby-dev:38538] Wed Jul 22 23:39:34 2009 Yukihiro Matsumoto * lib/rexml/text.rb (REXML::Text.normalize): call to_s for input. [ruby-talk:337069] Tue Jul 21 18:21:47 2009 Nobuyoshi Nakada * lib/mkmf.rb (SRC_EXT): should be flat. http://twitter.com/_tad_/status/1825862632 Sat Jul 18 00:44:43 2009 URABE Shyouhei * gc.c (rb_gc_call_finalizer_at_exit): finalizer_table can be NULL. [ruby-core:24395] Thu Jul 16 09:35:06 2009 Akinori MUSHA * lib/delegate.rb (Delegator#method_missing) (DelegateClass()#method_missing): Properly pass a given block through. [ruby-dev:38390] Wed Jul 15 11:40:34 2009 Nobuyoshi Nakada * file.c (rb_file_join): recursive array has no meaning as path name. [ruby-core:23329] Tue Jul 14 19:57:28 2009 Nobuyoshi Nakada * eval.c (get_ts): use readtime clock. [ruby-dev:38354] * eval.c (rb_thread_stop_timer): clear thread_init while locking. Tue Jul 14 19:57:28 2009 Nobuyoshi Nakada * eval.c (rb_thread_start_timer): guard condition was inverted. [ruby-dev:38319] Tue Jul 14 19:57:28 2009 Nobuyoshi Nakada * eval.c (safe_mutex_lock): pthread_cleanup_push() must not be inside parens. Mon Jul 13 01:36:54 2009 Nobuyoshi Nakada * time.c (time_timeval): rounds subsecond toward zero. Mon Jul 13 01:36:54 2009 Nobuyoshi Nakada * time.c (time_timeval): check out-of-range. [ruby-core:23282] [Bug #1396] Thu Jul 9 17:58:03 2009 Nobuyoshi Nakada * eval.c (proc_invoke): shares dmethod scope local variables. a patch from coderrr at [ruby-core:23050] * gc.c (obj_free): do not free cloned scope local variables. Wed Jul 8 19:28:03 2009 Nobuyoshi Nakada * eval.c (rb_thread_remove): stops timer thread unless other threads exist. [ruby-core:18444] Mon Jul 6 16:01:38 2009 Nobuyoshi Nakada * eval.c (rb_eval): checks for interrupt, stack and finalizers too. [ruby-dev:38208], [Bug #1329] * eval.c (eval): replaces the message if frozen. Sun Jul 5 03:50:52 2009 Nobuyoshi Nakada * lib/test/unit.rb: use Kernel.exit to get rid of using IRB::ExtendCommandBundle#exit. a patch from Dmitry Vazhov by [ruby-core:22986]. Fri Jul 3 09:05:38 2009 Masatoshi SEKI * lib/drb/drb.rb (open_server_inaddr_any): fixed multiple network families problem. a patch from Charl Matthee at [ruby-core:21033]. Wed Jul 1 15:46:30 2009 Tanaka Akira * lib/pathname.rb (Pathname#sub): set $~ in block.binding. [ruby-dev:38173] Mon Jun 29 13:18:42 2009 Yukihiro Matsumoto * lib/fileutils.rb (FileUtils#fu_get_gid): stringify group argument before making regexp match. [ruby-dev:38155] Fri Jun 12 16:36:44 2009 Yukihiro Matsumoto * ext/bigdecimal/bigdecimal.c (VpToString): fixed a bug introduced in r23613. [ruby-talk:338957] Mon Jun 8 10:58:41 2009 NAKAMURA Usaku * eval.c (rb_thread_schedule): mswin32 doesn't have F_GETFD, so check with another method. Mon Jun 8 08:15:36 2009 Yukihiro Matsumoto * ext/bigdecimal/bigdecimal.c (VpAlloc): avoid ALLOCA_N() to avoid segmentation fault caused by (insanely) long decimal values. backported from 1.9. CVE-2009-1904 * ext/bigdecimal/bigdecimal.c (BigDecimal_dump, BigDecimal_to_i, BigDecimal_to_f, BigDecimal_to_s, BigDecimal_split, BigDecimal_inspect): ditto. Mon Jun 8 08:15:36 2009 Yukihiro Matsumoto * ext/bigdecimal/bigdecimal.c (BigDecimal_to_f): returns Inf if exp is bigger than DBL_MANT_DIG. Wed Jun 3 21:16:30 2009 Tanaka Akira * file.c: include fcntl.h for O_RDONLY on Solaris. Wed Jun 3 21:09:56 2009 Nobuyoshi Nakada * util.c (rv_strdup): macro to duplicate nul-terminated string. [ruby-core:22852] * util.c (ruby_dtoa): allocates one more byte to get rid of buffer overrun. a patch from Charlie Savage at [ruby-core:22604]. Wed Jun 3 21:09:56 2009 Nobuyoshi Nakada * util.c (ruby_dtoa): allocates one more byte to get rid of buffer overrun. a patch from Charlie Savage at [ruby-core:22604]. Wed Jun 3 21:05:44 2009 Nobuyoshi Nakada * ext/bigdecimal/bigdecimal.c (gfDebug): uncommented out. [ruby-core:22600] Wed Jun 3 20:54:23 2009 Nobuyoshi Nakada * eval.c (rb_eval): needs to guard intermediate string objects. based on a patch from Brent Roman a [ruby-core:22584]. Tue May 26 21:24:01 2009 URABE Shyouhei * Makefile.in (update-rubyspec, test-rubyspec): Catch up to rubyspec merge. A patch by Brian Ford at [ruby-core:21032] Tue May 26 21:21:49 2009 Akinori MUSHA * lib/soap/mimemessage.rb (MIMEMessage#to_s): Fix a fatal method name typo. [Bug #1173] Tue May 26 21:16:55 2009 Nobuyoshi Nakada * file.c (rb_file_s_extname): fix for spaces before extention. [ruby-dev:38044] Tue May 26 21:09:21 2009 Nobuyoshi Nakada * win32/win32.c (_CrtDbgReportW): prevent from false positive assertions in msvcrtd. [ruby-core:22116] Tue May 26 21:02:13 2009 Nobuyoshi Nakada * lib/ostruct.rb (OpenStruct#new_ostruct_member): checks if frozen. [ruby-talk:328195], [ruby-core:22142] Tue May 26 21:00:08 2009 Nobuyoshi Nakada * lib/ostruct.rb (OpenStruct#inspect): fixed the recursion check. Patch by Kornelius Kalnbach. [ruby-core:20992]. * test/ostruct/test_ostruct.rb: test for inspect. Patch by Kornelius Kalnbach. [ruby-core:20992]. Tue May 26 20:50:32 2009 Tanaka Akira * eval.c (rb_thread_schedule): handle EBADF of select as well. [ruby-core:21264] Wed Apr 8 18:59:52 2009 NAKAMURA Usaku * win32/win32.c (subtruct): check tv_sec. Thu Apr 2 16:06:17 2009 URABE Shyouhei * test/rss/test_atom.rb (RSS::TestAtomCore::assert_atom_content_inline_other_base64_to_s): ditto. [ruby-dev:38248] Thu Apr 2 15:43:46 2009 Kouhei Sutou * test/rss/rss-assertions.rb (RSS::Assertions::assert_atom_content_inline_other_text): newlines are valid for Base64 data. [ruby-dev:38248] Thu Apr 2 14:17:09 2009 Kazuhiro NISHIYAMA * test/openssl/test_ssl.rb (OpenSSL#test_client_session): Debian's openssl 0.9.8g-13 failed at assert(ssl.session_reused?), when use default SSLContext. [ruby-dev:36167] backported r19268 from trunk. [ruby-core:22843] Thu Mar 31 18:18:18 2009 Nobuyoshi Nakada * lib/mkmf.rb (mkintpath): new function which converts native path to format acceptable in Makefile. * lib/mkmf.rb (configuration): leaves PATH_SEPARATOR unchanged. * lib/mkmf.rb (configuration): convers srcdir, topdir and hdrdir. a patch by Alexey Borzenkov at [ruby-core:21448]. Fri Mar 27 19:22:02 2009 Nobuyoshi Nakada * gc.c (run_final): frees zombies only. [ruby-dev:38171] Fri Mar 27 19:22:02 2009 Nobuyoshi Nakada * gc.c (rb_gc_call_finalizer_at_exit): leave Thread objects unfinalized. [ruby-dev:38168] Fri Mar 27 19:22:02 2009 Nobuyoshi Nakada * gc.c (run_final): calls free function. [ruby-core:22578] Mon Mar 23 19:17:06 2009 Nobuyoshi Nakada * ext/thread/thread.c (rb_queue_pop, rb_queue_push): should not lock mutex if got an exception while waiting, and should ensure unlocked after signaled. [ruby-dev:37545] Mon Mar 23 18:26:57 2009 Nobuyoshi Nakada * eval.c (rb_thread_value): missed to change at r17874. [ruby-core:17595] Mon Mar 23 18:26:57 2009 Nobuyoshi Nakada * eval.c (rb_thread_join): new API. * ext/thread/thread.c (wait_mutex, lock_mutex): wait until the locking thread exits. [ruby-dev:34856] Mon Mar 23 17:41:49 2009 Nobuyoshi Nakada * file.c (file_load_ok): checks if regular file, except for the platform disallows to open directories, e.g. dosish. [ruby-dev:38097], [Bug #1221] Mon Mar 9 20:59:24 2009 Shugo Maeda * ext/openssl/ossl_ocsp.c (ossl_ocspbres_verify): OCSP_basic_verify returns positive value on success, not non-zero. [ruby-core:21762] backported r22440 from trunk. Mon Mar 9 10:02:15 2009 Yukihiro Matsumoto * re.c (match_check): check if MatchData is initialized. [ruby-core:18749] Mon Mar 9 09:56:34 2009 Shugo Maeda * lib/rexml/rexml.rb: incremented Ruby::VERSION. Thanks, Jeremy Kemper. [ruby-core:20113] Mon Mar 9 09:52:53 2009 Tanaka Akira * io.c (io_getpartial): fflush after read for updating pos in FILE. not portable, I guess. [ruby-core:21561] Mon Mar 9 09:04:39 2009 Nobuyoshi Nakada * gc.c (define_final): cannot define finalizer for immediate values. [ruby-core:21500] * gc.c (define_final): freezes or hides internal values. Mon Mar 9 08:54:47 2009 Yukihiro Matsumoto * parse.y (IS_BEG): EXPR_CLASS should be treated like EXPR_BEG. [ruby-core:21453] Wed Feb 25 15:15:52 2009 Nobuyoshi Nakada * node.h (rb_thread_raised_clear): should not clear flags other than raised flags. a patch by Tomoyuki Chikanaga at [ruby-dev:37794]. [ruby-dev:37776] Wed Feb 25 15:05:48 2009 Nobuyoshi Nakada * ext/socket/extconf.rb (gai_strerror): checks if available and if returns const pointer. * ext/socket/getaddrinfo.c (gai_strerror): defines only if non available. [ruby-core:21328] Wed Feb 25 14:57:18 2009 Nobuyoshi Nakada * win32/win32.c (open_dir_handle): extracted from rb_w32_opendir. * win32/win32.c (winnt_stat): gets rid of strange behavior of GetFileAttributes(). [ruby-core:21269] Tue Feb 24 02:44:39 2009 Masatoshi SEKI * lib/erb.rb (PercentScanner): remove PercentScanner. fixed % after %> bug. [ruby-dev:37751] [Bug #997] * test/erb/test_erb.rb: ditto Tue Feb 24 02:35:29 2009 Nobuyoshi Nakada * hash.c (rb_hash_s_create): set nil as the value if assoc length is not enough. [ruby-core:21249] Sun Feb 22 22:08:45 2009 Nobuyoshi Nakada * eval.c (stack_extend): streamlined rb_thread_restore_context() to ensure O(1) time. based on a patch by Brent Roman . Sun Feb 22 22:03:40 2009 Nobuyoshi Nakada * eval.c (cc_mark): frees the continuation's stack if its thread is dead to avoid recursive gc that segfaults. [ruby-core:13889] a patch by Brent Roman . * eval.c (rb_cont_check): checks for valid continuation instance. * eval.c (rb_callcc): assigns th->thread before scope_dup() to avoid segfaults if this scope_dup() triggers a gc pass. a patch by Brent Roman . Sun Feb 22 21:43:34 2009 Nobuyoshi Nakada * numeric.c (ruby_float_step): extracted from num_step(). * range.c (range_step): uses ruby_float_step() for float range. [ruby-dev:37691] Sun Feb 22 00:49:36 2009 Nobuyoshi Nakada * ext/extmk.rb (extmake): does not use both of makefile.rb and extconf.rb at the same time. * lib/mkmf.rb (DLLIB): depends on Makefile. [ruby-core:21096] Sun Feb 22 00:19:05 2009 Tanaka Akira * eval.c (rb_thread_schedule): Don't change status of threads which don't run next even if select notify readability/writability. [ruby-core:20446] Fri Feb 20 20:43:13 2009 Nobuyoshi Nakada * lib/optparse.rb (OptionParser::List#summarize): gives priority to latter switches. [ruby-dev:36692] * lib/optparse.rb (OptionParser#summarize): do not append unnecessary line terminator. Fri Feb 20 19:35:08 2009 Takeyuki FUJIOKA * lib/cgi/session.rb: ignore session_id options fixed.[Bug #605] Fri Feb 20 18:06:40 2009 James Edward Gray II Merged 20854 from trunk. * lib/xmlrpc/server.rb: Restricting method inspection to show only non-inherited public methods. [ruby-core:20603] * lib/xmlrpc/server.rb: Fixing method inspection so it doesn't trigger XMLRPC::FaultException when used. [ruby-core:20604] Fri Feb 20 01:41:08 2009 Yukihiro Matsumoto * lib/sync.rb (Sync_m#sync_try_lock): wrong variable name fixed. a patch from [ruby-core:20561] * lib/sync.rb (Sync_m::Err.Fail): turn off Thread.critical before exit. Thu Feb 19 18:02:10 2009 Yuki Sonoda (Yugui) * pack.c (pack_pack): fixed odd act of 'm*', 'M*', and 'P*'. just ignores '*' in these cases. [ruby-dev:37289] Thu Feb 19 17:26:11 2009 Nobuyoshi Nakada * pack.c (pack_pack): fixed length for odd length string. [ruby-dev:37283] Thu Feb 19 17:13:13 2009 Nobuyoshi Nakada * eval.c (rb_yield_0): Qundef means no argument. [ruby-Bugs-22525] Wed Feb 18 22:28:00 2009 NAKAMURA Usaku * win32/win32.c (rb_w32_isatty): check whether fd is valid. Wed Feb 18 22:24:23 2009 NAKAMURA Usaku * win32/win32.c (waitpid): fix bug of checking child slot. * win32/win32.c (FindChildSlotByHandle): new. Wed Feb 18 22:17:04 2009 Yukihiro Matsumoto * pack.c (pack_pack): propagate taint status from format string to result string. Wed Feb 18 22:07:44 2009 Kazuhiro NISHIYAMA * ext/gdbm/gdbm.c: do not set members of RSTRING(str) directly. [ruby-dev:37182] * ext/gdbm/gdbm.c (rb_gdbm_nextkey): fix memory leak. Tue Feb 17 11:58:58 2009 Nobuyoshi Nakada * string.c (str_independent): no independent string points null_str. [ruby-core:20082] Mon Feb 16 23:30:24 2009 Hidetoshi NAGAI * ext/tk/lib/tkextlib/blt.rb, ext/tk/lib/tkextlib/blt/vector.rb: fix NameError bug. Mon Feb 16 23:08:22 2009 Nobuyoshi Nakada * string.c (rb_str_s_alloc, rb_str_replace): use null_str as well as rb_string_value so that extension libraries do not segfault. [ruby-core:19971] * string.c (rb_str_replace): reduced unnecessary malloc and copy. Mon Feb 16 22:45:41 2009 Masatoshi SEKI * test/rinda/test_rinda.rb: fixed fails occasionally [ruby-dev:37119]. thanks, shinichiro.h. Mon Feb 16 22:36:37 2009 Masatoshi SEKI * lib/drb/drb.rb (DRbConn::alive?): fixed NoMethodError problem from NaHi [ruby-dev:37110]. Sun Feb 15 04:21:42 2009 Yukihiro Matsumoto * lib/net/ftp.rb (Net::FTP#open_socket): SOCKSsocket is obsolete. a patch from Alan Johnson in [ruby-core:19982]. Fri Feb 13 19:18:42 2009 Nobuyoshi Nakada * lib/logger.rb (ProgName): fixed for svn, based on a patch from Nobuhiro IMAI at [ruby-dev:37108]. Sun Feb 15 04:17:40 2009 Yukihiro Matsumoto * lib/webrick/httprequest.rb (WEBrick::HTTPRequest#read_request_line): use non-greedy match for path retrieval to avoid huge recursion for insanely long path. Fri Feb 13 19:04:54 2009 Keiju Ishitsuka * shell/command-processor.rb: undefined method `top_level_test' in Shell#test. [ruby-list:45634] Tue Feb 10 20:00:52 2009 Nobuyoshi Nakada * eval.c (load_lock): makes circular require deadlock. [ruby-core:19821] Tue Feb 10 19:40:58 2009 Nobuyoshi Nakada * eval.c (rb_feature_p): returns found feature name if loading. [ruby-core:19798] * eval.c (search_required): ditto. Wed Feb 11 23:37:35 2009 Yukihiro Matsumoto * ext/bigdecimal/bigdecimal.c (VpMidRound): Round method bug pointed by Ryan Platte fixed(Patch to the patch from "NATORI Shin"). [ruby-talk:273360] back ported from 1.9. fix [ruby-core:19791] Mon Feb 9 17:35:38 2009 NAKAMURA Usaku * win32/win32.c (rb_w32_accept): secure fd before accept because if error causes in securing, cannot restore the state of accepted socket. fixed [ruby-core:19728] Mon Feb 9 13:42:15 2009 NAKAMURA Usaku * win32/win32.c (ifs_open_socket): should retry without proto_buffer if cannot find the suitable protocol. a patch from Heesob Park. fixed [ruby-core:19713] Mon Feb 9 13:40:21 2009 Yukihiro Matsumoto * ext/stringio/stringio.c (strio_ungetc): should allow ungetc at the top of the buffer. ref #701 Thu Feb 5 09:38:48 2009 NARUSE, Yui * ext/nkf/nkf-utf8/nkf.c (h_conv): can't guess UTF-8 input in conversion. [ruby-list:45609] Thu Feb 5 09:03:21 2009 Shugo Maeda * lib/rexml/entity.rb (unnormalized): do not call document.record_entity_expansion if document is nil. see . Thanks, Naohisa Goto. backported from trunk. * test/rexml/test_document.rb: ditto. Thu Feb 5 08:55:24 2009 Nobuyoshi Nakada * array.c (rb_ary_join): do not repeat self in a recursive array. [ruby-dev:37019] Wed Feb 4 14:26:58 2009 Yukihiro Matsumoto * dir.c (dir_globs): need taint check. reported by steve Tue Feb 3 14:35:26 2009 Kazuhiro NISHIYAMA * lib/net/pop.rb: check for invalid APOP timestamp. (CVE-2007-1558) [ruby-dev:36631] * test/net/pop/test_pop.rb: ditto. Mon Feb 2 20:03:58 2009 Nobuyoshi Nakada * time.c (time_mdump, time_mload): preserves GMT status. [ruby-core:19252] Mon Feb 2 11:34:51 2009 Nobuyoshi Nakada * variable.c (autoload_delete, autoload_file): should not delete autoload table, since it may be shared with duplicated modules. [ruby-core:19181] Thu Jan 29 11:54:22 2009 Tadayoshi Funaba * lib/date.rb (today,now): should produce own instances. [ruby-talk:317020] Wed Jan 28 22:51:55 2009 Nobuyoshi Nakada * eval.c (rb_mod_modfunc): method undefined in included module may not have nd_body. [ruby-core:18738] Wed Jan 28 20:53:27 2009 Nobuyoshi Nakada * marshal.c (marshal_dump): fixed for check_dump_arg. Tue Jan 27 17:30:11 2009 Nobuyoshi Nakada * marshal.c (marshal_dump): initializes dump_arg before any funcall. [ruby-dev:36648] Tue Jan 27 15:17:35 2009 Nobuyoshi Nakada * ext/socket/socket.c (host_str): numeric address should be unsigned. [ruby-core:18971] Mon Jan 26 11:12:03 2009 NAKAMURA Usaku * lib/tmpdir.rb: setup buffer with nul characters instead of spaces. fixed [ruby-dev:36493] Sun Jan 25 00:07:23 2009 Yukihiro Matsumoto * lib/rexml/formatters/pretty.rb (REXML::Formatters::Pretty#wrap): abandon wrapping if the line contains no space. [ruby-dev:36045] fix: #342 Sun Jan 25 00:02:23 2009 Yuki Sonoda (Yugui) * lib/matrix.rb (Vector#eql?): typo of the method name as "eqn?". (Vector#eqn?): removed. Defined by mistake. Fixes [ruby-dev:36294]. Reported by weda and an anonymous user. * test/matrix/test_matrix.rb: added. * test/matrix/test_vector.rb: added. Fri Jan 23 11:49:45 2009 Shugo Maeda * NEWS: added an entry for REXML. * lib/rexml/document.rb: fixed typo. Fri Jan 23 11:49:45 2009 Shugo Maeda * lib/rexml/document.rb: limit entity expansion. Thanks, Luka Treiber, Mitja Kolsek, and Michael Koziarski. backported from trunk r19033, r19317, r19318. * lib/rexml/entity.rb: ditto. * test/rexml/test_document.rb: ditto. Thu Jan 22 15:19:39 2009 Nobuyoshi Nakada * marshal.c (marshal_load): arg.data is no longer a VALUE but a st_table, and freed in load_ensure. pointed out by pegacorn. [ruby-dev:37008] Thu Jan 22 15:19:39 2009 Nobuyoshi Nakada * gc.c (rb_mark_set): new function to mark keys. * marshal.c (struct dump_arg, struct load_arg): added wrappers to mark data entries. backport from trunk r13527,r13528,r13961,r16533. [ruby-dev:36082] Wed Jan 21 11:12:55 2009 NAKAMURA Usaku * win32/win32.c (filetime_to_timeval): new function, split from gettimeofday(). * win32/win32.c (gettimeofday): use above function. * win32/win32.c (filetime_to_unixtime): ditto. [ruby-dev:36135] Wed Jan 21 11:12:55 2009 NAKAMURA Usaku * win32/win32.c (gettimeofday): tv_usec is usec, not msec. [ruby-dev:36094] Wed Jan 21 11:12:55 2009 NAKAMURA Usaku * win32/win32.c (gettimeofday): calc tv_sec and tv_usec from system time by myself. [ruby-dev:36084] Wed Jan 21 11:12:55 2009 NAKAMURA Usaku * win32/win32.c (gettimeofday): shouldn't use mktime(2) because it's buggy about handling summer time. reported by Yoshikawa at [ruby-dev:36071] Tue Jan 20 12:23:38 2009 Nobuyoshi Nakada * lib/scanf.rb (Scanf::FormatSpecifier#initialize): %i should accept single digit decimal. [ruby-core:18355] Mon Jan 19 18:25:28 2009 Tanaka Akira * configure.in (rb_cv_broken_glibc_ia64_erfc): renamed from rb_broken_glibc_ia64_erfc. [ruby-core:18228] Sat Jan 17 12:16:10 2009 Yukihiro Matsumoto * random.c (Init_Random): always initialize seed. Fri Jan 16 10:59:31 2009 Yukihiro Matsumoto * class.c (clone_method): should copy cbase in cref as well. [ruby-dev:35116] * node.h (NEW_CREF): new NEW_ macro. * eval.c (PUSH_CREF): use NEW_CREF(). Thu Jan 15 14:34:32 2009 Nobuyoshi Nakada * gc.c (STACK_LEVEL_MAX, ruby_stack_length): returns size_t. [ruby-core:18207] Wed Jan 14 10:39:56 2009 Nobuyoshi Nakada * stable/ext/socket/socket.c (NI_MAXHOST, NI_MAXSERV): fixed invalid preprocessor directives. a patch from Peter Bowen at [ruby-core:18211]. Tue Jan 13 04:40:30 2009 Shugo Maeda * lib/net/ftp.rb (login): raise FTPReplyError if passwd or acct is not supplied. backported from trunk. fixed [ruby-core:18058]. Mon Jan 12 00:23:37 2009 Nobuyoshi Nakada * gc.c (gc_sweep, obj_free, run_final): defer finalizers of IO and Data. [ruby-dev:35578] * gc.c (rb_gc_call_finalizer_at_exit): self-referencing finalizers cannot be invoked. [ruby-dev:35681] Sun Jan 11 11:33:27 2009 Shugo Maeda * lib/net/ftp.rb (chdir): handle 5xx errors correctly. backported from trunk. fixed [ruby-core:18057]. Fri Jan 9 19:25:25 2009 Shugo Maeda * lib/net/imap.rb (disconnect): do not refer SSL::SSLSocket for environments without OpenSSL. backported from trunk. fixed [ruby-dev:35755]. Thu Jan 8 13:24:23 2009 Nobuyoshi Nakada * parse.y (deferred_nodes, compstmt, arg, fixup_nodes, range_op): fix up fixnum range literal in conditional as automagical line number comparison. [ruby-core:12124], [ruby-dev:35731] Wed Jan 7 10:09:46 2009 Nobuyoshi Nakada * eval.c (timeofday): use monotonic clock. based on a patch from zimbatm in [ruby-core:16627]. Tue Jan 6 09:03:35 2009 Nobuyoshi Nakada * parse.y (yylex): 8 and 9 in octal integer should cause compile error. [ruby-dev:35729] Mon Jan 5 11:14:39 2009 Nobuyoshi Nakada * eval.c (rb_thread_schedule): runs deferred finalizers. * gc.c (gc_sweep): sets rb_thread_pending to run deferred finalizers. * rubysig.h (CHECK_INTS): now checks rb_thread_pending even on platforms where setitimer is not available. [ruby-core:18045] Mon Jan 5 11:14:39 2009 Nobuyoshi Nakada * rubysig.h (CHECK_INTS): gives the chance to perform to deferred finalizers before explicit GC.start or the process termination. [ruby-core:18045] Sun Jan 4 04:49:01 2009 Nobuyoshi Nakada * win32/win32.c (rb_w32_telldir): just returns loc. * win32/win32.c (rb_w32_rewinddir): needs to intialize loc. [ruby-core:18041] Sun Jan 4 04:45:26 2009 Nobuyoshi Nakada * win32/win32.c (rb_w32_select): recalc the rest of timeout for each iterations. [ruby-core:18015] Fri Jan 2 03:08:47 2009 Kouhei Sutou * test/rss/: use PNG instead of zlib as binary data. [ruby-dev:35666] Tue Nov 11 01:07:32 2008 Kazuhiro NISHIYAMA * configure.in: fix SEGV on Mac OS X 10.5.3 with --enable-pthread. a patch from Wataru Kimura in Bug #193 [ruby-core:17333]. Mon Aug 11 09:37:17 2008 Yukihiro Matsumoto * ext/dl/dl.c (rb_str_to_ptr): should propagate taint to dlptr. * ext/dl/dl.c (rb_ary_to_ptr): ditto. * ext/dl/sym.c (rb_dlsym_call): should check taint of DLPtrData as well. Fri Aug 8 10:53:52 2008 Tanaka Akira * lib/resolv.rb: randomize source port and transaction id. CVE-2008-1447. * lib/resolv-replace.rb (UDPSocket#bind): don't resolv host if host is "". Mon Aug 4 14:49:35 2008 URABE Shyouhei * lib/net/smtp.rb (Net::SMTP::rcptto): fix a typo. a patch from Masao Takaku fix [ruby-dev:35489]. Mon Aug 4 14:13:15 2008 Nobuyoshi Nakada * regex.c (xmalloc, xrealloc, xfree): not to use ruby managed memory. * regex.c (DOUBLE_STACK, re_compile_fastmap0, re_adjust_startpos), (re_search, re_match_exec): check if failed to allocate memory. Mon Aug 4 13:53:42 2008 Nobuyoshi Nakada * bignum.c (rb_big2str0, bigsqr): made interruptible. [ruby-Bugs-20622] Mon Aug 4 13:31:41 2008 NAKAMURA Usaku * numeric.c (check_uint, rb_num2uint, rb_fix2uint): fixed wrong check about 64bit positive value. Mon Aug 4 13:31:41 2008 NAKAMURA Usaku * numeric.c (check_uint, rb_num2uint, rb_fix2uint): strict check. fixed [ruby-dev:33683] Thu Jul 17 21:42:07 2008 URABE Shyouhei * lib/net/smtp.rb (Net::SMTP::start): revert to avoid RFC2821 violation. [ruby-dev:35487] Thu Jul 17 21:32:49 2008 Tanaka Akira * string.c (rb_str_format_m): make tmp volatile to avoid possible GC problem. Thu Jul 17 21:30:55 2008 Nobuyoshi Nakada * lib/optparse.rb (OptionParser#environment): requires shellwords. [ruby-dev:35466] Thu Jul 17 02:05:10 2008 Nobuyoshi Nakada * lib/xmlrpc/client.rb (XMLRPC::Client#do_rpc): requires webrick/cookie. [ ruby-Bugs-21139 ] Thu Jul 17 01:38:31 2008 Yusuke Endoh * ext/zlib/zlib.c (rb_gzfile_set_mtime): fix typo. [ruby-core:17713] Sun Jul 13 00:08:16 2008 Nobuyoshi Nakada * lib/ipaddr.rb (IPAddr#initialize): get rid of ArgumentError in IPAddr#to_range. a patch from okkez in [ruby-dev:35091]. Sun Jul 13 00:04:38 2008 Tanaka Akira * configure.in (erfc): erfc of glibc comes with Debian GNU/Linux Etch on IA64 is broken. erfc(10000.0) aborts. use missing/erf.c instead. http://sources.redhat.com/ml/libc-hacker/2005-08/msg00008.html Thu Jul 10 18:50:48 2008 Tanaka Akira * common.mk (SPEC_GIT_BASE): update RubySpec GIT URL. Thu Jul 10 18:46:28 2008 Nobuyoshi Nakada * file.c (rb_file_s_extname): fix for file name with spaces. [ruby-talk:307404] Thu Jul 10 18:42:37 2008 Masatoshi SEKI * lib/erb.rb (PercentScanner#scan): fix %% line bug. [ruby-core:17491] * test/erb/test_erb.rb (test_percent): ditto. Thu Jul 10 18:40:22 2008 Nobuyoshi Nakada * lib/net/ftp.rb (Net::FTP#sendport): use divmod. [ruby-core:17557] Thu Jul 10 18:36:53 2008 Kazuhiro NISHIYAMA * ruby.c: Mac OS X needs origargc times of '\0' in origargv. [ruby-dev:35308] Thu Jul 10 13:53:08 2008 Tanaka Akira * include/ruby/ruby.h (POSFIXABLE): use FIXNUM_MAX+1 instead of FIXNUM_MAX to make it possible to convert to double accurately. It assumes FLT_RADIX is 2. fix RubyForge bug #14102. backported from 1.9. Mon Jul 7 16:21:38 2008 Yukihiro Matsumoto * lib/net/smtp.rb (Net::SMTP::start): use 'localhost' instead of 'localhost.localdomain'. [ruby-dev:35333] * lib/net/smtp.rb (Net::SMTP::SMTP.start): ditto. Mon Jul 7 15:02:13 2008 Nobuyoshi Nakada * eval.c (rb_longjmp): duplicate the thrown exception to set backtrace if it was frozen. clear all raised flags. * eval.c (stack_check): leave clearing flag to rb_longjmp. * eval.c (rb_thread_set_raised, rb_thread_reset_raised): use generic flags. * eval.c (Init_Proc), gc.c (Init_GC): freeze preallocated special exceptions. * gc.c (rb_memerror): use thread raised flag instead of static flag, and raise nomem_error without backtrace if failed to make backtrace. [ruby-dev:34724] * gc.c (ruby_xmalloc): increase malloc_increase only if malloc succeeds. failed malloc size can be huge. it may increase malloc_limit too big which cause less GC and memory full. (ruby_xrealloc): ditto. Mon Jul 7 12:23:05 2008 Masaki Suketa * ext/win32ole/win32ole.c: avoid creating Ruby object during GC. thanks to arton . [ruby-dev:35313] * ext/win32ole/tests: add test_win32ole_event.rb, remove testOLEEVENT.rb * ext/win32ole/tests/testWIN32OLE.rb(test_convert_bignum): fix test. Mon Jul 7 12:23:05 2008 Masaki Suketa * gc.c: add rb_during_gc(). based on a patch from arton at [ruby-dev:35313]. * intern.h: ditto. Thu Jul 3 20:13:20 2008 Nobuyoshi Nakada * marshal.c (w_object, marshal_dump, r_object0, marshal_load): search public methods only. [ruby-core:17283] * object.c (convert_type): ditto. * lib/singleton.rb (Singleton#_dump): conversion method should be public. Wed Jul 2 19:06:43 2008 Nobuyoshi Nakada * lib/cgi.rb (CGI::QueryExtension.read_multipart): blanks inside double quotes are allowed. [ruby-list:45140] Wed Jul 2 19:03:37 2008 Tanaka Akira * numeric.c (num_coerce): call rb_Float(x) first. don't depend on evaluation order of function arguments. Wed Jul 2 18:57:19 2008 Yukihiro Matsumoto * ext/syslog/syslog.c (syslog_write): syslog operations should be protected from $SAFE level 4. a patch from Keita Yamaguchi . * ext/syslog/syslog.c (mSyslog_close): ditto. * ext/syslog/syslog.c (mSyslog_set_mask): ditto. Wed Jul 2 18:26:20 2008 Tanaka Akira * math.c (domain_check): fix preprocess condition. Wed Jul 2 18:22:52 2008 Nobuyoshi Nakada * lib/tmpdir.rb (@@systmpdir): prior LOCAL_APPDATA if possible, and should be clean. based on a patch from arton at [ruby-dev:35269] Wed Jul 2 18:16:19 2008 Masaki Suketa * ext/win32ole/win32ole.c (date2time_str): fix the overflow in some situation. [ruby-bugs-20793] Tue Jul 1 15:11:14 2008 Nobuyoshi Nakada * array.c (rb_ary_fill): check if beg is too big. Mon Jun 30 20:35:32 2008 Nobuyoshi Nakada * string.c (str_buf_cat): check for self concatenation. Sun Jun 29 21:39:54 2008 Tanaka Akira * eval.c (rb_obj_respond_to): use RTEST to test the result of respond_to? method. Sun Jun 29 21:20:17 2008 URABE Shyouhei * array.c (rb_ary_fill): (compatibility) do not raise ArgumentError on negative length. This behaviour shall change in a future release. Sun Jun 29 20:08:11 2008 Tanaka Akira * time.c (time_timeval): fix rounding negative float. Sun Jun 29 19:19:08 2008 Nobuyoshi Nakada * test/inlinetest.rb (InlineTest.in_progname): workaround for frozen $0. [ruby-dev:35261] * lib/test/unit/ui/console/testrunner.rb (TestRunner#finished): ditto. Sun Jun 29 19:19:08 2008 Nobuyoshi Nakada * ruby.c (set_arg0, ruby_prog_init): freeze $0. a patch from Keita Yamaguchi . Sun Jun 29 18:33:33 2008 Tanaka Akira * process.c: include sys/resource.h if HAVE_SYS_RESOURCE_H is defined. pointed by TOYOFUKU Chikanobu. [ruby-dev:35258] Sun Jun 29 18:26:01 2008 Yukihiro Matsumoto * variable.c (rb_f_trace_var): should not be allowed at safe level 4. a patch from Keita Yamaguchi . * eval.c (rb_call0): wrong condition to check insecure method. a patch from Keita Yamaguchi . Sun Jun 29 18:22:52 2008 Nobuyoshi Nakada * array.c (rb_ary_fill): not depend on unspecified behavior at integer overflow. reported by Vincenzo Iozzo . Sun Jun 29 18:22:06 2008 Masaki Suketa * ext/win32ole/win32ole.c(ole_invoke): fix memory leak. [ruby-bugs-20792] Sun Jun 29 18:19:11 2008 Akinori MUSHA * eval.c (PUSH_FRAME, PUSH_CLASS): Add volatile to avoid a possible optimization bug on OS X/PPC. This at least makes build with gcc -O1 and `make test' pass. Sun Jun 29 17:24:43 2008 Nobuyoshi Nakada * lib/rdoc/parsers/parse_rb.rb (RDoc#collect_first_comment): skip magic comment. Sun Jun 29 17:22:09 2008 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_each, strio_readlines): IO#each and IO#readlines do not affect $_. [ruby-core:17277] Sun Jun 29 17:19:59 2008 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_readline, strio_each) (strio_readlines): set lastline. [ruby-core:17257] Sun Jun 29 17:15:49 2008 NAKAMURA Usaku * ext/openssl/ossl.h: include winsock.h if USE_WINSOCK2 is not defined. a patch from arton in [ruby-dev:35078] Sun Jun 29 17:09:48 2008 wanabe * util.c (ruby_strtod): ruby_strtod don't allow a trailing decimal point like "7.". [ruby-dev:34835] [ruby-dev:35009] Sat Jun 28 19:23:40 2008 URABE Shyouhei * class.c (clone_method): use rb_copy_node_scope. fixed [ruby-list:45102] fixed [ruby-core:17393] Sat Jun 28 18:49:50 2008 URABE Shyouhei * class.c: revert to r15855. Fri Jun 20 18:25:18 2008 Nobuyoshi Nakada * string.c (rb_str_buf_append): should infect. Fri Jun 20 16:33:09 2008 Nobuyoshi Nakada * array.c (rb_ary_store, rb_ary_splice): not depend on unspecified behavior at integer overflow. * string.c (str_buf_cat): ditto. Wed Jun 18 22:24:46 2008 URABE Shyouhei * array.c (ary_new, rb_ary_initialize, rb_ary_store, rb_ary_aplice, rb_ary_times): integer overflows should be checked. based on patches from Drew Yao fixed CVE-2008-2726 * string.c (rb_str_buf_append): fixed unsafe use of alloca, which led memory corruption. based on a patch from Drew Yao fixed CVE-2008-2726 * sprintf.c (rb_str_format): backported from trunk. * intern.h: ditto. Tue Jun 17 15:09:46 2008 Nobuyoshi Nakada * file.c (file_expand_path): no need to expand root path which has no short file name. [ruby-dev:35095] Sun Jun 15 19:27:40 2008 Akinori MUSHA * configure.in: Fix $LOAD_PATH. Properly expand vendor_ruby directories; submitted by Takahiro Kambe in [ruby-dev:35099]. Mon Jun 9 17:56:30 2008 Akinori MUSHA * lib/set.rb (Set#delete_if): Call to_a. (SortedSet#delete_if, TC_SortedSet#test_sortedset): Use super to yield elements in sorted order; [ruby-core:17144] by Arthur Schreiber. (SortedSet#each, SortedSet#each, TC_Set#test_each) (TC_SortedSet#test_sortedset): Return self; [ruby-dev:35002] by Arthur Schreiber. Mon Jun 9 03:28:05 2008 Akinori MUSHA * ext/zlib/zlib.c (rb_deflate_initialize, Init_zlib): Fix up initialize_copy; [ruby-list:45016], [ruby-list:45018]. Mon Jun 9 03:26:03 2008 Kazuhiro NISHIYAMA * NEWS: Mention new constants. Mon Jun 9 03:24:18 2008 Tanaka Akira * hash.c (hash_i): make Hash#hash order insensitive. Mon Jun 9 03:22:43 2008 Nobuyoshi Nakada * configure.in (VENDOR_DIR): use LIBDIR instead of PREFIX as well as SITE_DIR. a patch from Richard Brown in [ruby-core:17129]. Mon Jun 9 03:21:20 2008 Tanaka Akira * gc.c (os_obj_of): assure to not free the scanning heap. Mon Jun 9 03:20:12 2008 NAKAMURA Usaku * io.c (rb_open_file, rb_io_s_sysopen): fmode should be unsigned int. fixed [ruby-dev:34979] Fri Jun 6 21:16:55 2008 NAKAMURA Usaku * win32/Makefile.sub (COMMON_HEADERS): include ws2tcpip.h. * ext/socket/addrinfo.h (addrinfo, getaddrinfo, getnameinfo, freehostent, freeaddrinfo): undef before define because these are macros in some versions of Windows SDK. * win32/setup.mak: maybe commit miss. Fri Jun 6 19:34:22 2008 Akinori MUSHA * mkconfig.rb: hide build path from rbconfig.rb. * util.c (ruby_strtod, dtoa): initialize more variables for error handling. * io.c (rscheck), marshal.c (w_nbyte, w_bytes, w_unique), (path2class, path2module): constified. * pack.c (pack_unpack), process.c (rb_syswait): suppress warnings. * suppress warnings on cygwin, mingw and mswin. Fri Jun 6 19:23:53 2008 Nobuyoshi Nakada * file.c (file_expand_path): fix for non-existent files and SFN of symlinks. [ruby-talk:303736] Fri Jun 6 18:25:43 2008 Nobuyoshi Nakada * test/iconv: Tests fixed. Fri Jun 6 17:04:56 2008 Akinori MUSHA * win32/win32.h: include ws2tcpip.h. fixed [ruby-Bugs-20528] * lib/time.rb (Time.xmlschema): don't use float. fix http://rubyforge.org/tracker/index.php?func=detail&group_id=426&atid=1698&aid=20504 * object.c (rb_obj_alloc): RDoc updated. a patch from Gaston Ramos in [ruby-core:17073]. * lib/rdoc.rb: massive spelling correction patch from Evan Farrar in [ruby-doc:1382] applied. * ext/openssl/ossl_ssl_session.c (ossl_ssl_session_initialize): Add a null check for ssl; submitted by akira yamada in [ruby-dev:34950]. * ext/openssl/ossl_ssl.c (Init_ossl_ssl): Define OP_NO_TICKET if SSL_OP_NO_TICKET is present; submitted by akira yamada in [ruby-dev:34944]. * test/openssl/test_ssl.rb (OpenSSL#test_server_session): Add a workaround for the case where OpenSSL is configured with --enable-tlsext; submitted by akira yamada in [ruby-dev:34944]. Fri Jun 6 16:58:23 2008 Nobuyoshi Nakada * ext/iconv/iconv.c (iconv_iconv): fix for length argument and now allows range. [ruby-core:17092] [ruby-core:17115] Wed Jun 4 17:22:30 2008 Akinori MUSHA * NEWS: Fix typos and move misplaced entries. NEWS: Somehow optflags and warnflags were not actually included in this release. Tue Jun 3 19:33:22 2008 Akinori MUSHA * enumerator.c (enumerator_init_copy): Take care of initialize_copy as well as initialize. * test/ruby/test_enumerator.rb: Pull in the test suite for enumerator from trunk. Tue Jun 3 12:51:57 2008 Akinori MUSHA * enumerator.c (enumerator_allocate, enumerator_ptr): Properly detect if the object is initialized and raise error when appropriate. (enumerator_initialize): Fix a typo in rdoc. [ruby-core:17052] Tue Jun 3 10:16:40 2008 Akinori MUSHA * lib/erb.rb (ERB::Compiler::TrimScanner#scan_line): Fix a bug where tokens are not yilelded one by one. (ERB::Compiler::TrimScanner#explicit_trim_line): Fix without- strscan problems. [ruby_core:17028]. * test/erb/test_erb.rb (TestERBCore#_test_01) (TestERBCore#test_02_safe_04): The expected value should come first for assert_equal(). (TestERBCoreWOStrScan): Add test class for without-strscan. Mon Jun 2 19:47:16 2008 Akinori MUSHA * lib/delegate.rb (DelegateClass, Delegator#respond_to?): respond_to? must take optional second argument. This was a latent bug exposed by a recent internal change of marshal.c to call respond_to? with a second argument; submitted by Jeremy Kemper in [ruby-core:17045]. Sat May 31 23:53:35 2008 Akinori MUSHA * .: Release as Ruby 1.8.7. Sat May 31 23:33:34 2008 Akinori MUSHA * README, README.ja: Add a note about default C flags. Sat May 31 22:11:15 2008 Kazuhiro NISHIYAMA * version.c (ruby_description, ruby_copyright): backported from 1.9. bug#19002, [ruby-dev:34883] * error.c (report_bug): uses ruby_description. Sat May 31 20:56:04 2008 Akinori MUSHA * array.c (rb_ary_delete_if): should return enumerator if no block is given. [ruby-dev:34901] Sat May 31 18:28:17 2008 Nobuyoshi Nakada * suppress warnings with -Wwrite-string. Sat May 31 15:58:08 2008 Nobuyoshi Nakada * Makefile.in, configure.in (warnflags): defaulted to -Wall -Wno-parentheses with gcc. [ruby-dev:34810] Fri May 30 05:28:18 2008 NAKAMURA Usaku * enum.c (count_i, count_iter_i, count_all_i): add prototypes for VC. Fri May 30 04:32:07 2008 Akinori MUSHA * enum.c (count_i, count_iter_i): Sync with trunk. enum.c (enum_count, count_all_i, Init_Enumerable), array.c (rb_ary_count): Sync with trunk. If no argument or block is given, count the number of all elements. Fri May 30 03:12:18 2008 Akinori MUSHA * ext/openssl/ossl_bn.c (ossl_bn_s_rand, ossl_bn_s_pseudo_rand): Int should be enough here. Fri May 30 02:35:00 2008 Akinori MUSHA * ext/openssl/ossl_bn.c (ossl_bn_s_rand, ossl_bn_s_pseudo_rand), ext/openssl/ossl_pkey_dh.c (ossl_dh_s_generate) (ossl_dh_initialize), ext/openssl/ossl_pkey_dsa.c (ossl_dsa_s_generate), ext/openssl/ossl_rand.c (ossl_rand_bytes) (ossl_rand_pseudo_bytes, ossl_rand_egd_bytes), ext/openssl/ossl_x509store.c (ossl_x509stctx_set_error): Do not use FIX2INT() without checking the value type. Use NUM2INT() instead; found by akr in [ruby-dev:34890]. Thu May 29 20:07:45 2008 Akinori MUSHA * configure.in, win32/Makefile.sub, mkconfig.rb, instruby.rb, ruby.c, lib/mkmf.rb, README.EXT, README.EXT.ja: Backport the vendor_ruby directory support. Thu May 29 17:52:31 2008 Nobuyoshi Nakada * ext/zlib/extconf.rb: search zlib1, and regard mswin32 later than VC6 as WIN32. [ruby-core:16984] Wed May 28 17:54:29 2008 Akinori MUSHA * string.c (rb_str_start_with): Remove an unused variable. (rb_str_upto_m): Fix a prototype. Wed May 28 17:48:28 2008 Akinori MUSHA * range.c (range_step): Fix brokenness when a non-integer numeric value is specified as step. [rubyspec] (range_step): Make use of String#step internally if a string (or string-alike) range is given. * string.c (rb_str_upto_m, Init_String): Add an optional second argument to specify if the last value should be included. Wed May 28 16:53:39 2008 Akinori MUSHA * array.c (rb_ary_slice_bang): Call rb_ary_modify_check() at the beginning. [rubyspec] Wed May 28 16:12:44 2008 Akinori MUSHA * lib/webrick/httpservlet/cgihandler.rb (WEBrick::HTTPServlet::CGIHandler#do_GET): Set the HTTP status code to 302 if a Location header field is present and the status code is not valid as a client redirection. cf. RFC 3875 6.2.3, 6.2.4. Wed May 28 15:18:16 2008 Nobuyoshi Nakada * lib/singleton.rb (SingletonClassMethods): _load should be public. Wed May 28 12:52:41 2008 Nobuyoshi Nakada * marshal.c (w_object, marshal_dump, r_object0, marshal_load): search private methods too. [ruby-dev:34671] * object.c (convert_type): ditto. Tue May 27 23:26:49 2008 Yukihiro Matsumoto * error.c (rb_bug): description from rb_bug() should include patchlevel. [ruby-dev:34826] Tue May 27 20:19:22 2008 Akinori MUSHA * array.c (rb_ary_slice_bang): Return an empty array instead of nil when pos is valid and len is adjusted from a valid value to zero; caught by RubySpec. Tue May 27 19:45:20 2008 Akinori MUSHA * numeric.c (flo_divmod): Revert the behavior change; do not suppress an exception when div is NaN or Inf. [ruby-dev:34857] Tue May 27 19:24:40 2008 Akinori MUSHA * enum.c (enum_to_a): Pass arguments through to #each(). (enum_sort): Follow the enum_to_a signature change. (enum_reverse_each): Add #reverse_each(). Tue May 27 18:54:02 2008 Akinori MUSHA * ext/stringio/stringio.c (strio_each_char, Init_stringio): Add StringIO#{each_char,chars}. Tue May 27 17:59:34 2008 Akinori MUSHA * ext/stringio/stringio.c (strio_each): Return an enumerator if no block is given. (strio_each_byte): Return an enumerator if no block is given, and return self if one is given as the rdoc says. * io.c (rb_io_each_byte): Fix rdoc. IO#each_byte returns self, not nil. Tue May 27 16:02:58 2008 Akinori MUSHA * eval.c (rb_mod_module_exec, Init_eval): Add Module#{module_exec,class_exec}. Tue May 27 15:36:37 2008 Akinori MUSHA * io.c (rb_io_each_char, argf_each_char, Init_IO): Add {IO#,ARGF.}{each_char,chars}. Tue May 27 13:46:52 2008 Akinori MUSHA * ext/stringio/stringio.c (Init_stringio): Define StringIO#{getbyte,readbyte}. Tue May 27 13:38:51 2008 Akinori MUSHA * io.c (Init_IO): Define {IO#,ARGF.}{getbyte,readbyte}. Tue May 27 13:26:15 2008 Akinori MUSHA * ext/stringio/stringio.c (Init_stringio): Define #bytes and #lines. Tue May 27 13:20:35 2008 Akinori MUSHA * io.c: (rb_io_lines, rb_io_bytes, Init_IO): Define IO#{lines,bytes} and ARGF.{lines,bytes}. Tue May 27 12:13:17 2008 NAKAMURA Usaku * file.c (BUFCHECK): wrong condition. [ruby-core:16921] * file.c (file_expand_buf): shouldn't use buflen for length of string. Mon May 26 18:24:48 2008 Nobuyoshi Nakada * file.c (BUFCHECK): no resize if enough room. * file.c (file_expand_path): use BUFCHECK. Mon May 26 16:46:19 2008 NAKAMURA Usaku * file.c (ntfs_tail): filename which starts with '.' is valid. * file.c (file_expand_path): cygwin symlink support. Mon May 26 12:16:43 2008 Akinori MUSHA * .: Release as Ruby 1.8.7-preview4. Mon May 26 12:12:26 2008 Akinori MUSHA * marshal.c (dump_ensure, load_ensure): should return values. * eval.c (yield_under, yield_under_i, yield_args_under_i) (specific_eval, rb_obj_instance_exec, Init_eval): Implement Object#instance_exec(), a 1.9 feature. Mon May 26 11:53:21 2008 Akinori MUSHA * eval.c (rb_yield_0, proc_invoke, proc_arity): allow passing a block to a Proc. [ruby-dev:23533]; by nobu; backported from 1.9. This implementation in current shape is known to be buggy/broken, especially with nested block invocation. Take this as an experimental feature. * parse.y (block_par, block_var): ditto. Mon May 26 08:00:52 2008 Akinori MUSHA * marshal.c (r_object0, Init_marshal): Fix the garbled s_call definition; fixes [ruby-dev:34843]. Mon May 26 03:16:20 2008 Akinori MUSHA * hash.c (rb_hash_default): Fix rdoc. (rb_hash_each, env_each_value, env_each_pair): Return an enumerator if no block is given. (rb_hash_update): Update rdoc. (envix): Conditionalize the definition itself. (rb_f_getenv, env_fetch, env_keys, env_values, env_values_at) (env_select, env_inspect, env_to_a, env_empty_p, env_has_key) (env_has_value, env_index, env_indexes, env_to_hash, env_shift) (env_update): Require secure level 4. (env_each_value, env_each_i): Delay variable initialization. (env_each_key, env_each_value, env_reject_bang) (env_clear, env_replace): Omit duplicated secure level check. (env_has_value): Do to_str conversion. Sun May 25 19:48:12 2008 Akinori MUSHA * hash.c (env_delete_if): Return an enumerator if no block is given. (env_each_key): Delay a variable initialization after RETURN_ENUMERATOR(). Sun May 25 05:07:19 2008 Akinori MUSHA * array.c (rb_ary_slice_bang): Be consistent with Array#slice() and String#slice!(). Just return nil when a negative length or out of boundary index is given instead of raising an exception via internal functions. (rb_ary_slice_bang): should not use rb_ary_subseq() which shares internal pointer. splice modifies the receiver right after subseq. [ruby-dev:34005] (rb_ary_slice_bang): should adjust length before making sub-array. * enumerator.c (Init_Enumerator): Override Enumerable::Enumerator#each_with_index with #with_index. Sun May 25 03:13:09 2008 Akinori MUSHA * eval.c (Init_Thread): Initialize recursive_key. Sun May 25 02:45:49 2008 Akinori MUSHA * error.c (syserr_eqq): Use en. Sat May 24 22:32:49 2008 Yukihiro Matsumoto * object.c (rb_cstr_to_dbl): should clear errno before calling strtod(3). [ruby-dev:34834] Sat May 24 22:27:44 2008 Yukihiro Matsumoto * marshal.c (marshal_load): should initialize arg.data used for reentrant check. [ruby-dev:34837] Sat May 24 00:34:59 2008 Tanaka Akira * lib/rational.rb (Rational#to_i): fix rdoc. Rational(-7,4).to_i should be -1. Fri May 23 20:22:44 2008 Yukihiro Matsumoto * marshal.c (reentrant_check): check reentrance via callcc. [ruby-dev:34802] Fri May 23 16:46:28 2008 Akinori MUSHA * enumerator.c (proc_call): Remove an unused static function. Fri May 23 13:46:09 2008 Nobuyoshi Nakada * configure.in (cflags): commit miss. Fri May 23 09:52:21 2008 Nobuyoshi Nakada * configure.in (MINIRUBY), common.mk (RUBYOPT): add purelib.rb. [ruby-core:16642] * ext/extmk.rb: load purelib.rb only when not cross compiling. Fri May 23 08:47:02 2008 Yukihiro Matsumoto * error.c (syserr_eqq): === should be able to handle delegated objects as well. Fri May 23 04:22:19 2008 Hidetoshi NAGAI * ext/tk/tcltklib.c, ext/tk/tkutil/tkutil.c: fix memory leak. * ext/tk/lib/tk.rb: avoid trouble when finalize TclTkIp. * ext/tk/lib/tk.rb, ext/tk/lib/tk/*: help to fix troubles when use Ttk widgets on old Tk scripts. * ext/tk/sample/*: update and add demo scripts. some of them are introduction about new features of Tcl/Tk8.5. Fri May 23 03:48:10 2008 Akinori MUSHA * class.c (clone_method): Just use ruby_cref as cref. Fri May 23 01:03:23 2008 Akinori MUSHA * class.c (rb_singleton_class_clone): Pass Qnil, not 0. Fri May 23 00:51:48 2008 Akinori MUSHA * class.c (clone_method): Totally revamp the previous fix which was incorrect. (rb_mod_init_copy): Ditto. (singleton_class_clone_int): Ditto. Fri May 23 00:48:10 2008 Akinori MUSHA * eval.c (rb_copy_node_scope), node.h: Rename from copy_node_scope and export. Thu May 22 21:24:15 2008 Yukihiro Matsumoto * parse.y (top_local_setup): fixed memory leak bug based on a patch from Roger Pack in [ruby-core:16610]. Thu May 22 14:20:54 2008 Nobuyoshi Nakada * array.c (flatten): check if reentered. [ruby-dev:34798] Thu May 22 08:28:49 2008 Yukihiro Matsumoto * array.c (flatten): free memo hash table before raising exception. [ruby-dev:34789] Thu May 22 06:30:10 2008 Hidetoshi NAGAI * array.c (flatten): fix memory leak. Thu May 22 05:45:30 2008 Yukihiro Matsumoto * proc.c (proc_dup): should copy safe_level from src proc properly. a patch from Keita Yamaguchi Wed May 21 23:31:44 2008 Nobuyoshi Nakada * eval.c (rb_get_method_body, rb_alias, rb_eval): should not cache uninitialized value, since search_method doesn't set origin if the method wasn't found. * eval.c (search_method, remove_method, error_print, rb_alias) (rb_eval, rb_rescue2, search_required, Init_eval, rb_thread_create), gc.c (rb_source_filename, Init_stack), io.c (rb_io_getline), parse.y (rb_id2name, rb_parser_free): suppress warnings. Wed May 21 12:34:51 2008 Nobuyoshi Nakada * hash.c (rb_hash_delete): rdoc fix based on a patch from Gaston Ramos . [ruby-core:16825] Tue May 20 13:15:46 2008 Akinori MUSHA * file.c (lchmod_internal): Remove a compiler warning. Mon May 19 18:22:35 2008 Akinori MUSHA * ext/openssl/ossl_pkcs5.c (ossl_pkcs5_pbkdf2_hmac): Fix the type of md; pointed out by Takahiro Kambe in [ruby-dev:34748]. Mon May 19 14:20:13 2008 NAKAMURA Usaku * sprintf.c (rb_f_sprintf): fixed SEGV on win32 with "% 0e" % 1.0/0.0. Mon May 19 13:29:58 2008 NAKAMURA Usaku * process.c (rb_f_system): set last_status when status == -1 because there is no path to set it on win32. this patch is derived from [ruby-core:16787], submitted by Luis Lavena Mon May 19 13:01:05 2008 Nobuyoshi Nakada * common.mk ({MSPEC,RUBYSPEC}_GIT_URL): moved from Makefine.in. * {win32,bcc32}/Makefile.sub (update-rubyspec): added. Mon May 19 11:53:45 2008 Akinori MUSHA * ext/openssl/openssl_missing.c (HMAC_CTX_copy): adopted prototype change in openssl bundled with newer OpenBSD. a patch from Takahiro Kambe in [ruby-dev:34691]. Mon May 19 06:36:37 2008 Akinori MUSHA * .: Release as Ruby 1.8.7-preview3. Sun May 18 22:26:51 2008 GOTOU Yuuzou * lib/webrick/httpservlet/filehandler.rb: should normalize path name in path_info to prevent script disclosure vulnerability on DOSISH filesystems. (fix: CVE-2008-1891) Note: NTFS/FAT filesystem should not be published by the platforms other than Windows. Pathname interpretation (including short filename) is less than perfect. * lib/webrick/httpservlet/abstract.rb (WEBrick::HTTPServlet::AbstracServlet#redirect_to_directory_uri): should escape the value of Location: header. * lib/webrick/httpservlet/cgi_runner.rb: accept interpreter command line arguments. Sat May 17 23:53:57 2008 Nobuyoshi Nakada * file.c (file_expand_path): fix for short file name on Cygwin. Sat May 17 11:29:11 2008 Nobuyoshi Nakada * file.c (rb_file_s_extname): first dot is not an extension name. Sat May 17 10:18:44 2008 Yukihiro Matsumoto * re.c (rb_reg_search): need to free allocated buffer in re_register. Fri May 16 17:01:44 2008 NAKAMURA Usaku * win32/Makefile.sub (test-rubyspec): added. Fri May 16 16:22:40 2008 Hidetoshi NAGAI * ext/tk/tcltklib.c: sometimes freeze when receive Interrupt signal. Fri May 16 14:54:56 2008 Tanaka Akira * Makefile.in (update-rubyspec): move rubyspec to srcdir. (test-rubyspec): ditto. Fri May 16 14:25:22 2008 Tanaka Akira * Makefile.in (test-rubyspec): use RUNRUBY. suggested by nobu. Fri May 16 13:01:43 2008 Tanaka Akira * Makefile.in (update-rubyspec): new target to download rubyspec. (test-rubyspec): new target to run rubyspec. this doesn't work before install. Fri May 16 08:15:52 2008 Hidetoshi NAGAI * ext/tk/lib/tk.rb: fix memory (object) leak bug. * ext/tk/sample/demos-jp/aniwave.rb, ext/tk/sample/demos-en/aniwave.rb: bug fix. Thu May 15 17:00:22 2008 Akinori MUSHA * string.c (Init_String): Define #bytesize as an alias for #size for compatibility with 1.9. Thu May 15 15:33:59 2008 Nobuyoshi Nakada * file.c (file_expand_path): support for alternative data stream and ignored trailing garbages of NTFS. * file.c (rb_file_s_basename): ditto. * file.c (rb_file_s_extname): ditto. Wed May 14 19:24:59 2008 Akinori MUSHA * array.c (rb_ary_count): Override Enumerable#count for better performance. (rb_ary_nitems): Undo the backport. Use #count {} instead. * enumerator.c (enumerator_iter_i): Remove an unused function. (enumerator_with_index, enumerator_each): Remove unused variables. Wed May 14 17:15:11 2008 NAKAMURA Usaku * ext/tk/tkutil/extronf.rb: check stdndup() because it's not standard function of C. * ext/tk/tkutil/tkutil.c (cbsubst_table_setup): use malloc() and strncpy() instead of strndup() if not available. Wed May 14 09:52:02 2008 Hidetoshi NAGAI * ext/tk/tkutil/tkutil.c: improve handling callback-subst-keys. Now, support longnam-keys (e.g. '%CTT' on tkdnd-2.0; however, still not support tkdnd-2.0 on tkextlib), and symbols of parameters (e.g. :widget=>'%W', :keycode=>'%k', '%x'=>:x, '%X'=>:root_x, and so on; those are attributes of event object). It means that Ruby/Tk accepts not only "widget.bind(ev, '%W', '%k', ...){|w, k, ...| ... }", but also "widget.bind(ev, :widget, :keycode, ...){|w, k, ...| ... }". It is potentially incompatible, when user passes symbols to the arguments of the callback block (the block receives the symbols as strings). I think that is very rare case (probably, used by Ruby/Tk experts only). When causes such trouble, please give strings instead of such symbol parameters (e.g. call Symbol#to_s method). * ext/tk/lib/tk/event.rb, ext/tk/lib/tk/validation.rb, ext/tk/lib/tkextlib/blt/treeview.rb, ext/tk/lib/tkextlib/winico/winico.rb: ditto. * ext/tk/tkutil/tkutil.c: strings are available on subst_tables on TkUtil::CallbackSubst class (it is useful on Ruby 1.9). * ext/tk/lib/tk/spinbox.rb, ext/tk/lib/tkextlib/iwidgets/hierarchy.rb, ext/tk/lib/tkextlib/iwidgets/spinner.rb, ext/tk/lib/tkextlib/iwidgets/entryfield.rb, ext/tk/lib/tkextlib/iwidgets/calendar.rb, ext/tk/lib/tkextlib/blt/dragdrop.rb, ext/tk/lib/tkextlib/tkDND/tkdnd.rb, ext/tk/lib/tkextlib/treectrl/tktreectrl.rb, ext/tk/lib/tkextlib/tktable/tktable.rb: disable code piece became unnecessary by reason of the changes of ext/tk/tkutil/tkutil.c. Tue May 13 15:10:50 2008 Akinori MUSHA * enumerator.c: Update rdoc. (enumerator_initialize): Discourage the use. (enum_each_slice, enum_each_cons, enumerator_each) (enumerator_with_index): Add a note about a call without a block. * NEWS: Intentionally omit enum_slice and enum_cons, which are removed in 1.9. Tue May 13 07:56:36 2008 Yukihiro Matsumoto * string.c (rb_str_cat): fixed buffer overrun reported by Christopher Thompson in [ruby-core:16746] Mon May 12 13:57:19 2008 Yukihiro Matsumoto * eval.c (is_defined): add NODE_OP_ASGN_{OR,AND}. "defined?(a||=1)" should not operate assignment. [ruby-dev:34645] Mon May 12 12:59:23 2008 Hidetoshi NAGAI * ext/tk/lib/tk/wm.rb: Wm#overrideredirect overwrites arguemnt to an invalid value. * ext/tk/sample/ttk_wrapper.rb: support "if __FILE__ == $0" idiom. Mon May 12 12:36:55 2008 NAKAMURA Usaku * win32/win32.c (rb_w32_select): backport from trunk. [ruby-talk:300743] Mon May 12 12:33:21 2008 Nobuyoshi Nakada * common.mk (RUBYLIB, RUBYOPT): clear. Mon May 12 10:41:10 2008 Nobuyoshi Nakada * lib/delegate.rb (SimpleDelegator::dup): removed needless argument. [ruby-list:44910] * lib/delegate.rb (clone, dup): keep relationship with the target object. Sun May 11 23:19:39 2008 Nobuyoshi Nakada * enum.c (all_iter_i, any_iter_i): reduced duplicated code. Sun May 11 17:57:36 2008 Nobuyoshi Nakada * configure.in (MINIRUBY): should not include extension library path. Sun May 11 10:36:10 2008 Kazuhiro NISHIYAMA * eval.c (method_name, method_owner): New methods; backported from 1.9. (UnboundMethod#name, UnboundMethod#owner) Sun May 11 02:48:13 2008 * ext/tk/lib/tk/pack.rb, ext/tk/lib/tk/grid.rb: fail to do pack/grid without options. * ext/tk/lib/tk.rb: add TkWindow#grid_anchor, grid_column, grid_row. Sat May 10 18:19:16 2008 Yukihiro Matsumoto * string.c (rb_str_each_line): RDoc updated. [ruby-dev:34586] Sat May 10 13:17:56 2008 Hidetoshi NAGAI * ext/tk/lib/tk/pack.rb, ext/tk/lib/tk/grid.rb: increase supported parameter patterns of configure method. Sat May 10 09:16:13 2008 Yukihiro Matsumoto * util.c (ruby_strtod): backported from 1.9. a patch from Satoshi Nakagawa in [ruby-dev:34625]. fixed: [ruby-dev:34623] Fri May 9 23:33:25 2008 Hidetoshi NAGAI * ext/tk/lib/tk/wm.rb: methods of Tk::Wm_for_General module cannot pass the given block to methods of Tk::Wm module. * ext/tk/lib/tk/grid.rb: lack of module-method definitions. * ext/tk/lib/tkextlib/tile.rb: lack of autoload definitions. * ext/tk/lib/tkextlib/tile/tnotebook.rb: cannot use kanji (not UTF-8) characters for headings. * ext/tk/tcltklib.c: maybe a little more stable about @encoding value of TclTkIp object. Wed May 7 08:46:44 2008 Yukihiro Matsumoto * struct.c (rb_struct_s_def): to_str should be called only once. [ruby-core:16647] Wed May 7 00:54:25 2008 Yukihiro Matsumoto * ext/zlib/zlib.c (gzreader_gets): may cause infinite loop. a patch from Kouya in [ruby-reference-manual:762]. Sun May 4 09:35:51 2008 Masatoshi SEKI * sample/erb/erb4html.rb (ERB4Html) : add example of ERB#set_eoutvar. ERB4Html is an auto-quote ERB. Sat May 3 22:52:48 2008 Hidetoshi NAGAI * ext/tk/lib/tkextlib/tile.rb, ext/tk/lib/tkextlib/tile/style.rb, ext/tk/sample/ttk_wrapper.rb: improve treating and control themes. add Tk::Tile.themes and Tk::Tile.set_theme(theme). Fri May 2 14:52:33 2008 Yukihiro Matsumoto * misc/ruby-mode.el: move fontifying code from hook. a patch from Phil Hagelberg in [ruby-core:16636]. Fri May 2 13:47:51 2008 Yukihiro Matsumoto * re.c (match_select): restore previous behavior of MatchData#select. RDoc updated as well, mentioning the plan to remove this method in the future. [ruby-dev:34556] Fri May 2 13:04:04 2008 Yukihiro Matsumoto * ext/dbm/dbm.c (Init_dbm): defines DBM::VERSION even when DB_VERSION_STRING is not available. [ruby-dev:34569] Thu May 1 23:57:06 2008 James Edward Gray II Merged 16257 from trunk. * lib/net/telnet.rb: This patch from Brian Candler adds a FailEOF mode which can be activated to have net/telnet raise EOFError exceptions when the remote connection is closed. The default behavior remains unchanged though. Thu May 1 23:43:21 2008 Nobuyoshi Nakada * range.c (range_step): check if step can be converted to an integer. [ruby-dev:34558] * range.c (range_step): allow float step bigger than zero but less than one. [ruby-dev:34557] Wed Apr 30 20:22:40 2008 James Edward Gray II Merged 16241 from trunk. * lib/net/telnet.rb: Fixing a bug where line endings would not be properly escaped when the two character ending was broken up into separate TCP packets. Issue reported and patched by Brian Candler. Wed Apr 30 17:47:21 2008 Nobuyoshi Nakada * re.c (rb_reg_search): use local variable. a patch from wanabe in [ruby-dev:34537]. [ruby-dev:34492] Sat Apr 26 19:40:34 2008 Guy Decoux * class.c (struct clone_method_data): Add cref. (clone_method): Properly handle NODE_BMETHOD and NODE_DMETHOD. (rb_singleton_class_clone, singleton_class_clone_int): Set a proper value to klass and propagate cref. [ruby-core:16238] * eval.c (rb_block_dup, rb_method_dup), intern.h: Add duplicator methods for use from class.c#clone_method(). Fri Apr 25 15:46:37 2008 Hidetoshi NAGAI * ext/tk/lib/tk.rb, ext/tk/lib/tk/scrollbar.rb, ext/tk/lib/tk/scale.rb: improve unknonw-option check when create a widget. * ext/tk/lib/tkextlib/blt/unix_dnd.rb, ext/tk/lib/tkextlib/blt/ted.rb, ext/tk/lib/tkextlib/treectrl/tktreectrl.rb: bug fix on 'cget'. * ext/tk/lib/tk/menuspec.rb: option check will fail when TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ is true. * ext/tk/lib/tk/palette.rb: bug fix. Fri Apr 25 12:37:54 2008 Nobuyoshi Nakada * array.c (flatten): returns an instance of same class. [ruby-core:16554] Thu Apr 24 23:47:50 2008 Kazuhiro NISHIYAMA * lib/net/pop.rb: backported from 1.9. bug#19003 * ext/openssl/lib/openssl/ssl.rb: set_params; backported from 1.9. bug#19552, [ruby-dev:34402] * ext/openssl/ossl_ssl.c: ditto. * test/openssl/test_ssl.rb: ditto. Thu Apr 24 17:06:34 2008 Yukihiro Matsumoto * eval.c (THREAD_SAVE_CONTEXT): remove unnecessary FLUSH_REGISTER_WINDOWS before calling setjmp(). [ruby-core:16285] Thu Apr 24 14:15:11 2008 Nobuyoshi Nakada * dln.c (dln_find_1): prior files with extensions to files sans extensions. [ruby-core:16517] Wed Apr 23 15:39:31 2008 Akinori MUSHA * eval.c (bind_eval): Add Binding#eval, a shorthand method for eval(str, binding, ..); backported from 1.9. Wed Apr 23 15:28:52 2008 Kazuhiro NISHIYAMA * test/gdbm/test_gdbm.rb (TestGDBM#test_s_open_no_create): failed notice moved from comment to assertion message. [ruby-dev:29127] Wed Apr 23 14:00:05 2008 Akinori MUSHA * lib/mkmf.rb (create_makefile): Add a missing dependency on the target directory for each .rb file. This will hopefully fix parallel make (-jN). Tested on FreeBSD. Wed Apr 23 11:49:54 2008 Akinori MUSHA * lib/set.rb (Set#each, SortedSet#each, TC_Set#test_each): Return an enumerator if no block is given. Wed Apr 23 00:42:49 2008 Tanaka Akira * eval.c (error_print): show full stack grace except SystemStackError. backport from 1.9. [ruby-dev:31014] Wed Apr 23 00:18:45 2008 Kazuhiro NISHIYAMA * test/ruby/test_symbol.rb (TestSymbol#test_to_proc): Improve tests of Symbol#to_proc. Tue Apr 22 22:43:05 2008 Akinori MUSHA * eval.c (rb_proc_new, YIELD_FUNC_LAMBDA): Add a new nd_state YIELD_FUNC_LAMBDA which avoids automatic `avalue' conversion for arguments. This fixes a bug where [1,[2,3]].map(&:object_id) fails. * intern.h, object.c: Hide rb_proc_new() from intern.h. It should not be considered an official API function yet. Tue Apr 22 21:24:32 2008 Akinori MUSHA * eval.c (rb_proc_new): Turn the BLOCK_LAMBDA flag on. * object.c (sym_to_proc), test/ruby/test_symbol.rb: Add back Symbol#to_proc, now that it passes the tests. Tue Apr 22 19:35:03 2008 Akinori MUSHA * enumerator.c (enumerator_initialize): Remove an undocumented feature (passing a block to the constructor) that's broken. This is not what I intended. Tue Apr 22 17:49:46 2008 Yukihiro Matsumoto * sprintf.c (rb_f_sprintf): should protect temporary string from GC. [ruby-dev:34480] Tue Apr 22 17:12:05 2008 Yukihiro Matsumoto * regex.c (re_search): string might be NULL. [ruby-core:16478] Tue Apr 22 16:44:00 2008 Kazuhiro NISHIYAMA * object.c (rb_obj_tap): Correct documentation; pointed out by okkez in [ruby-dev:34472]. Tue Apr 22 10:05:51 2008 NAKAMURA Usaku * file.c (eaccess): workaround for recent msvcrt's behavior. [ruby-core:16460] Mon Apr 21 16:06:47 2008 Yukihiro Matsumoto * enumerator.c (enumerator_init): preserve the method name in ID. * enumerator.c (enumerator_each): need not to call rb_to_id(). * enumerator.c (enumerator_with_index): ditto. Mon Apr 21 17:19:52 2008 Akinori MUSHA * eval.c (rb_f_method_name): New gloval function: __method__; backported from matzruby / 1.9. * eval.c (rb_frame_this_func), intern.h: New internal function. * intern.h (RETURN_ENUMERATOR): Use rb_frame_this_func() instead of rb_frame_last_func(), to accommodate the behavior to that of 1.9. Mon Apr 21 15:54:48 2008 Yukihiro Matsumoto * lib/tempfile.rb (Tempfile::_close): check @data before modifying it; backported from 1.9. [ruby-dev:34094] * lib/tempfile.rb (Tempfile::close): clear @data and @tmpname. Mon Apr 21 10:17:17 2008 NAKAMURA Usaku * time.c: should include to refer errno. Mon Apr 21 10:02:43 2008 NAKAMURA Usaku * hash.c (recursive_hash): prototype. Mon Apr 21 10:00:51 2008 NAKAMURA Usaku * time.c (rb_strftime): check errno to detect strftime(3)'s error. this is workaround for recent version of MSVCRT. [ruby-dev:34456] Sun Apr 20 21:10:04 2008 Akinori MUSHA * .: Release as Ruby 1.8.7-preview2. Sun Apr 20 21:02:06 2008 Akinori MUSHA * enumerator.c: Resolve the method every time an enumeration method is run, not once when the enumerator is initialized as it was before, so that method_missing() and method (re)definition afterwards are both in effect; pointed out in: [ruby-core:16441] Sun Apr 20 17:59:25 2008 Akinori MUSHA * object.c, NEWS, test/ruby/test_symbol.rb: Revert Symbol#to_proc since it does not pass the tests. Sun Apr 20 14:29:35 2008 Technorama Ltd. * ext/openssl/ossl_ssl.c: initialize session class. Sat Apr 19 20:54:42 2008 akira yamada * lib/uri/ftp.rb, lib/uri/generic.rb, test/uri/test_common.rb, test/uri/test_ftp.rb, test/uri/test_generic.rb: backported from 1.9. [ruby-dev:31318] Sat Apr 19 20:35:02 2008 Akinori MUSHA * lib/yaml/baseemitter.rb, lib/yaml/encoding.rb: performance tuning around String#gsub. * lib/yaml/tag.rb: Replace nodoc with stopdoc so Module methods get documented. * lib/yaml/store.rb (YAML::load): modified to support empty database. * lib/yaml/store.rb (YAML::Store::marshal_dump_supports_canonical_option?): add a method to support faster PStore. Sat Apr 19 20:16:52 2008 Akinori MUSHA * lib/yaml/types.rb: Likewise, pass self to YAML::quick_emit; merged from 1.9. * lib/yaml.rb (quick_emit): use combination of object_id and hash to identify repeated object references, since GC will reuse memory of objects during output of YAML. [ruby-Bugs-8548] [ruby-Bugs-3698]; merged from 1.9. Sat Apr 19 20:05:39 2008 Akinori MUSHA * array.c (rb_ary_equal, rb_ary_eql, rb_ary_hash, rb_ary_cmp): Make Array#eql?, #hash, #== and #<=> use rb_exec_recursive() and handle recursive data properly. * hash.c (hash_equal, rb_hash_hash): Make Hash#eql?, #hash and #== use rb_exec_recursive() and handle recursive data properly. Sat Apr 19 19:26:09 2008 Akinori MUSHA * intern.h, eval.c (rb_exec_recursive): New internal function to help perform recursive operation; backported from 1.9. Sat Apr 19 18:42:04 2008 Akinori MUSHA * intern.h, hash.c (rb_hash_lookup): New internal function to check if a key exists in a hash, ignoring #default; backported from 1.9. Fri Apr 18 18:56:57 2008 Akinori MUSHA * ext/syck/rubyext.c (syck_genericresolver_node_import): should not set instance variable "@kind" before initializing it. [ruby-dev:32677] * ext/syck/rubyext.c (syck_resolver_initialize, syck_resolver_detect_implicit, syck_emitter_emit): remove unused variables. Fri Apr 18 18:54:57 2008 Akinori MUSHA * ext/syck/rubyext.c: Node#value defined twice. * lib/yaml/: several method redefinitions causing warnings. Fri Apr 18 16:36:16 2008 Akinori MUSHA * lib/rexml/node.rb (REXML::Node::indent): should initialize rv variable. a patch from Tadayoshi Funaba in [ruby-dev:32783]. Fri Apr 18 16:01:37 2008 Akinori MUSHA * lib/rexml: Merge fixes since 1.8.6 made solely on the ruby_1_8_6 branch. Wed Apr 16 06:11:49 2008 Akinori MUSHA * test/ruby/test_settracefunc.rb (TestSetTraceFunc#test_event): Fix tests to reflect the following changes: r15833, r15759. Wed Apr 16 05:03:48 2008 Akinori MUSHA * .: Release as Ruby 1.8.7-preview1. Wed Apr 16 02:09:14 2008 Kouhei Sutou * lib/xmlrpc/client.rb: fix cookie handling. [ruby-dev:34403] * test/xmlrpc/test_cookie.rb: add a test for the above fix. Tue Apr 15 23:48:28 2008 Akinori MUSHA * version.h: Branch off ruby_1_8_7 from ruby_1_8 in preparation for the forthcoming 1.8.7 release. Tue Apr 15 23:40:39 2008 Akinori MUSHA * ext/syck/rubyext.c (rb_syck_mktime): Avoid buffer overflow. Tue Apr 15 20:32:03 2008 Tanaka Akira * re.c (match_inspect): backported from 1.9. Tue Apr 15 19:03:28 2008 Kazuhiro NISHIYAMA * eval.c (method_receiver, method_name, method_owner): New methods; backported from 1.9. bug#19007 Tue Apr 15 18:39:14 2008 Kazuhiro NISHIYAMA * lib/uri.rb, lib/uri/ldaps.rb: added LDAPS scheme; backported from 1.9. bug#19015, [ruby-dev:31896] Tue Apr 15 17:45:43 2008 Kazuhiro NISHIYAMA * lib/net/smtp.rb: backported from 1.9. bug#19003 Tue Apr 15 17:06:12 2008 Kazuhiro NISHIYAMA * test/ruby/test_symbol.rb (TestSymbol#test_to_proc): add tests. Tue Apr 15 16:58:55 2008 Hidetoshi NAGAI * ext/tk/lib/tk/menuspec.rb: option check will fail when TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ is true. * ext/tk/lib/tk/palette.rb: bug fix. Tue Apr 15 16:47:48 2008 Kazuhiro NISHIYAMA * signal.c, gc.c: New methods: GC.stress, GC.stress=; backported from 1.9. a patch from Tadashi Saito in [ruby-dev:34394] and bug#19000 Tue Apr 15 12:35:44 2008 Nobuyoshi Nakada * rubyio.h (rb_io_t): renamed from OpenFile. * ruby.h (struct RHash), file.c, gc.c, io.c, ext/dl/dl.c, ext/io/wait/wait.c, ext/pty/pty.c, ext/readline/readline.c, ext/socket/socket.c: ditto. * win32/win32.h: removed workaround for OpenFile. Tue Apr 15 00:15:29 2008 Hidetoshi NAGAI * ext/tk/lib/tk/text.rb: typo. call a wrong method. * ext/tk/lib/tk/itemconfig.rb: ditto. * ext/tk/sample/ttk_wrapper.rb: bug fix. * ext/tk/sample/tktextio.rb: add binding for 'Ctrl-u' at console mode. * ext/tk/lib/tk.rb, ext/tk/lib/tk/itemfont.rb, ext/tk/lib/font.rb: support __IGNORE_UNKNOWN_CONFIGURE_OPTION__ about font options. * ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb, ext/tk/lib/tkextlib/iwidgets/scrolledlistbox.rb, ext/tk/lib/tkextlib/iwidgets/scrolledtext.rb: bug fix. * ext/tk/lib/tkextlib/tile/tpaned.rb: improve TPaned#add. * ext/tk/lib/tk/timer.rb: add TkTimer#at_end(proc) to register the procedure which called at end of the timer. Mon Apr 14 19:54:21 2008 Akinori MUSHA * array.c (rb_ary_flatten, rb_ary_flatten_bang): Take an optional argument that determines the level of recursion to flatten; backported from 1.9. * array.c (rb_ary_shuffle_bang, rb_ary_shuffle, rb_ary_choice, rb_ary_cycle, rb_ary_permutation, rb_ary_combination, rb_ary_product, rb_ary_take, rb_ary_take_while, rb_ary_drop, rb_ary_drop_while): New methods: Array#shuffle, #shuffle!, #choice, #cycle, #permutation, #combination, #product, #take, #take_while, #drop, #drop_while; backported from 1.9. Mon Apr 14 19:52:35 2008 Akinori MUSHA * ruby.h: New macro: RB_GC_GUARD(). Mon Apr 14 19:49:35 2008 Akinori MUSHA * random.c (rb_genrand_int32, rb_genrand_real), intern.h: Export. * string.c (rb_str_tmp_new), intern.h: New function. Mon Apr 14 19:18:55 2008 NAKAMURA Usaku * enum.c (inject_i, inject_op_i): prototype. Mon Apr 14 19:10:47 2008 Akinori MUSHA * enum.c New methods: Enumerable#take, #take_while, #drop and #drop_while; backported from 1.9. Mon Apr 14 18:50:15 2008 Akinori MUSHA * enum.c: New methods: Enumerable#one?, #none?, #minmax, #min_by, #max_by, #minmax_by and #cycle; backported from 1.9. * enum.c (enum_find_index): Add support for find_index(obj); [ruby-dev:34313]; backported from 1.9. * enum.c (enum_inject): Add support for Enumerable#inject(:binop); backported from 1.9. * enum.c: Alias Enumerable#reject to #inject; backported from 1.9. Mon Apr 14 18:14:19 2008 Akinori MUSHA * enum.c (enum_find, enum_reject): Return an enumerator if no block is given; backported from 1.9. * io.c (rb_io_each_line, rb_io_each_byte, rb_io_s_foreach, argf_each_line, argf_each_byte): Ditto. * string.c (str_gsub): Ditto. Mon Apr 14 18:10:05 2008 NAKAMURA Usaku * enum.c (find_index_i, find_index_iter_i): add prototype for VC. Mon Apr 14 17:55:30 2008 Akinori MUSHA * array.c (rb_ary_collect_bang, rb_ary_select): Return an enumerator if no block is given; backported from 1.9. * dir.c (dir_each, dir_foreach): Ditto. * enum.c (enum_partition, enum_sort_by): Ditto. * gc.c (os_each_obj): Ditto. * hash.c (rb_hash_delete_if, rb_hash_reject_bang, rb_hash_select, rb_hash_each_value, rb_hash_each_key, rb_hash_each_pair, env_each_key, env_each_value, env_each, env_each_pair, env_reject_bang, env_delete_if, env_select): Ditto. * numeric.c (num_step, int_upto, int_downto, int_dotimes): Ditto. Mon Apr 14 16:42:53 2008 Akinori MUSHA * ruby.h (rb_block_call_func): Fix prototype. * enumerator.c (enumerator_iter_i, enumerator_each_i): Ditto. Mon Apr 14 15:49:05 2008 Akinori MUSHA * enum.c (enum_count, enum_find_index): New methods: Enumerable#count and #find_index; backported from 1.9. Mon Apr 14 14:16:08 2008 NAKAMURA Usaku * enumerator.c (enumerator_mark, enumerator_iter_i, enumerator_each_i, enumerator_allocate): add prototype. * enumerator.c (enumerator_each_i): declare unused two arguments. Mon Apr 14 13:58:32 2008 Akinori MUSHA * string.c (rb_str_each_char): New methods: String#chars and #each_char; backported from 1.9. Mon Apr 14 13:42:20 2008 Akinori MUSHA * string.c (rb_str_each_line, rb_str_each_byte): Reflect enumerator integration. #lines and #bytes are now aliases to #each_line and #each_byte, respectively. Mon Apr 14 13:19:36 2008 Akinori MUSHA * range.c (range_each, range_step): Return an enumerator if no block is given; backported from 1.9. * struct.c (rb_struct_each, rb_struct_each_pair): Ditto. Mon Apr 14 13:07:59 2008 Akinori MUSHA * string.c (rb_str_partition, rb_str_rpartition, rb_str_start_with, rb_str_end_with): New methods: String#partition, #rpartition, #start_with? and #end_with?; backported from 1.9. These methods are $KCODE aware unlike #index, #rindex and #include?. Sun Apr 13 15:55:52 2008 Kazuhiro NISHIYAMA * object.c (sym_to_proc): new method Symbol#to_proc; backported from 1.9. bug#19012 Fri Apr 11 19:14:30 2008 Kazuhiro NISHIYAMA * object.c (rb_obj_tap): new method Object#tap; backported from 1.9. bug#19008 Fri Apr 11 18:58:09 2008 Kazuhiro NISHIYAMA * process.c: new method Process.exec; backported from 1.9. bug#19006 Fri Apr 11 12:43:56 2008 Hidetoshi NAGAI * ext/tk/lib/tkextlib/tile.rb, ext/tk/lib/tkextlib/tile/style.rb, ext/tk/sample/tkextlib/tile/demo.rb: previous patch is not complete. Fri Apr 11 10:22:54 2008 Hidetoshi NAGAI * ext/tk/lib/tkextlib/tile.rb: __define_LoadImages_proc_for_compatibility__! do nothing when the Tcl command exists. * ext/tk/lib/tkextlib/tile/style.rb: __define_wrapper_proc_for_compatibility__! do nothing when the Tcl command exists. * ext/tk/sample/tkextlib/tile/demo.rb: don't create 'step' theme if it already exists. Fri Apr 11 08:05:12 2008 Yukihiro Matsumoto * marshal.c (w_object): add volatile to avoid potential GC bug. a patch from Tomoyuki Chikanaga in [ruby-dev:34311]. Thu Apr 10 20:29:13 2008 Akinori MUSHA * misc/rdebug.el, misc/README: Remove rdebug.el as per request from the maintainer and mention the ruby-debug project at RubyForge in README; bug#19043. Thu Apr 10 20:08:37 2008 Akinori MUSHA * enum.c (enum_first, enum_group_by): New methods: Enumerable#first and #group_by; backported from 1.9. Thu Apr 10 19:49:10 2008 Akinori MUSHA * enumerator.c (rb_eStopIteration), eval.c (rb_f_loop), ruby.h: Add a new exception class StopIteration, which breaks Kernel#loop iteration when raised; backported from 1.9. * enumerator.c (enumerator_next, enumerator_rewind): Implement #next and #rewind using the "generator" library. * lib/generator.rb: Implement Enumerable::Enumerator#next and #rewind. Thu Apr 10 19:29:48 2008 Akinori MUSHA * array.c (rb_ary_first, rb_ary_last): Return a shared array when possible. * array.c (rb_ary_pop, rb_ary_pop_m, rb_ary_shift, rb_ary_shift_m): Array#pop and Array#shift can take an optional argument specifying the number of elements to remove and return; backported from 1.9. Thu Apr 10 14:00:44 2008 Tanaka Akira * lib/resolv.rb (Resolv::DNS#each_address): backport from 1.9 for CNAME. [ruby-dev:34200] Thu Apr 10 01:42:25 2008 NAKAMURA Usaku * enum.c (iterate_method): add prototype to avoid warning on VC++. Wed Apr 9 23:12:41 2008 Hidetoshi NAGAI * ext/tk/tcltklib.c: SEGV when tcltk-stubs is enabled. * ext/tk/tcltklib.c: avoid error on a shared object. * ext/tk/extconf.rb: support --with-tcltkversion * ext/tk/README.tcltklib: add document about --with-tcltkversion * ext/tk/sample/demos-jp/widget, ext/tk/sample/demos-en/widget, ext/tk/sample/demos-jp/style.rb, ext/tk/sample/demos-en/style.rb, ext/tk/sample/demos-jp/bind.rb, ext/tk/sample/demos-en/bind.rb: bug fix. Wed Apr 9 21:54:45 2008 Akinori MUSHA * array.c (rb_ary_pop): Do not reallocate too often; backported from 1.9. Wed Apr 9 21:13:05 2008 Akinori MUSHA * array.c (rb_ary_each, rb_ary_each_index, rb_ary_reverse_each, rb_ary_reject, rb_ary_reject_bang): Array#each, #each_index, #reverse_each, #reject, #reject! and #delete_if return an enumerator if no block is given; backported from 1.9. Wed Apr 9 20:47:16 2008 Akinori MUSHA * array.c (rb_ary_index, rb_ary_index): Array#index and #rindex can take a block instead of an argument; backported from 1.9. Wed Apr 9 19:58:31 2008 Akinori MUSHA * enumerator.c, inits.c (rb_call_inits), ruby.h, intern.h, ext/enumerator, common.mk (OBJS, enumerator.$(OBJEXT)): Make the enumerator module built-in. * enumerator.c: New method: Enumerable::Enumerator#with_index. * enum.c (enum_each_with_index): Enumerable#each_with_index now returns an enumerator instead of raising an exception if no block is given. Enumerable#enum_with_index, formerly defined in the enumerator module, is kept as an alias to each_with_index for backward compatibility. Wed Apr 9 19:43:51 2008 Akinori MUSHA * eval.c (rb_obj_method, rb_proc_call), intern.h: Export. Tue Apr 8 11:11:28 2008 Yukihiro Matsumoto * eval.c (EXEC_TAG): remove unnecessary FLUSH_REGISTER_WINDOWS for better performance on SPARC. [ruby-core:16159] Tue Apr 8 10:49:54 2008 Yukihiro Matsumoto * re.c (rb_reg_quote): should always copy the quoting string. [ruby-core:16235] Mon Apr 7 21:35:08 2008 Akinori MUSHA * array.c (rb_ary_nitems): Backport Array#nitems with a block; suggested by Bertram Scharpf in [ruby-talk:134083]. Sun Apr 6 09:45:00 2008 Nobuyoshi Nakada * dir.c (dir_tell): check if closed. [ruby-core:16223] Sat Apr 5 10:05:00 2008 Nobuyoshi Nakada * object.c (rb_check_to_integer): backported for range_step. Fri Apr 4 05:57:11 2008 Yukihiro Matsumoto * lib/net/pop.rb (Net::POP3::do_finish): clear @n_mails and @n_bytes as well. [ruby-core:16144] Fri Apr 4 02:17:06 2008 Yukihiro Matsumoto * range.c (range_step): should not round step into integer if begin and end are numeric. [ruby-core:15990] Tue Apr 1 14:43:38 2008 Nobuyoshi Nakada * configure.in: get rid of empty expansion. * {bcc,win}32/Makefile (config.h): need to define RUBY_SETJMP, etc. Tue Apr 1 11:36:19 2008 Nobuyoshi Nakada * configure.in: _setjmp is available but _longjmp is not on mingw. Tue Apr 1 03:20:40 2008 Nobuyoshi Nakada * configure.in (RUBY_SETJMP, RUBY_LONGJMP, RUBY_JMP_BUF): prefers _setjmp over setjmp and sigsetjmp. [ruby-core:16023] __builtin_setjmp cannot handle a variable. * configure.in (--with-setjmp-type): new option to override the default rule in the above. * eval_intern.h (ruby_setjmp, ruby_longjmp), gc.c (rb_setjmp), vm_core.h (rb_jmpbuf_t): use RUBY_SETJMP, RUBY_LONGJMP and RUBY_JMP_BUF. Tue Apr 1 01:55:52 2008 Nobuyoshi Nakada * lib/resolv.rb (Resolv::Config.default_config_hash): requires win32/resolv to use Win32::Resolv. [ruby-dev:34138] Mon Mar 31 14:51:11 2008 Yukihiro Matsumoto * bignum.c (rb_big_div): Bignum#div should return integer for floating number operand. Sun Mar 30 07:00:32 2008 Nobuyoshi Nakada * ext/tk/tcltklib.c: rb_hash_lookup has not been backported yet. Sat Mar 29 14:18:41 2008 Hidetoshi NAGAI * ext/tk/*: full update Ruby/Tk to support Ruby(1.9|1.8) and Tc/Tk8.5. * ext/tk/lib/tkextlib/tile.rb: [incompatible] remove TileWidgets' instate/state/identify method to avoid the conflict with standard widget options. Those methods are renamed to ttk_instate/ttk_state/ ttk_identify (tile_instate/tile_state/tile_identify are available too). Although I don't recommend, if you realy need old methods, please define "Tk::USE_OBSOLETE_TILE_STATE_METHOD = true" before "require 'tkextlib/tile'". * ext/tk/lib/tkextlib/tile.rb: "Tk::Tile::__Import_Tile_Widgets__!" is obsolete. It outputs warning. To control default widget set, use "Tk.default_widget_set = :Ttk". * ext/tk/lib/tk.rb: __IGNORE_UNKNOWN_CONFIGURE_OPTION__ method and __set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode) method are defind as module methods of TkConfigMethod. It may help users to wrap old Ruby/Tk scripts (use standard widgets) to force to use Ttk widgets. Ttk widgets don't have some options of standard widgets which are control the view of widgets. When set ignore-mode true, configure method tries to ignoure such unknown options with no exception. Of course, it may raise other troubles on the GUI design. So, those are a little danger methods. * ext/tk/lib/tk/itemconfig.rb: __IGNORE_UNKNOWN_CONFIGURE_OPTION__ method and __set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode) method are defind as module methods of TkItemConfigMethod as the same purpose as TkConfigMethod's ones. * ext/tk/sample/ttk_wrapper.rb: A new example. This is a tool for wrapping old Ruby/Tk scripts (which use standard widgets) to use Ttk (Tile) widgets as default. * ext/tk/sample/tkextlib/tile/demo.rb: use ttk_instate/ttk_state method instead of instate/state method. * ext/tk/lib/tk/root, ext/tk/lib/tk/namespace.rb, ext/tk/lib/tk/text.rb, ext/tk/lib/tkextlib/*: some 'instance_eval's are replaced to "instance_exec(self)". * ext/tk/lib/tk/event.rb: bug fix on KEY_TBL and PROC_TBL (?x is not a character code on Ruby1.9). * ext/tk/lib/tk/variable.rb: support new style of operation argument on Tcl/Tk's 'trace' command for variables. * ext/tk/sample/demos-jp/widget, ext/tk/sample/demos-en/widget: bug fix * ext/tk/sammple/demos-jp/textpeer.rb, ext/tk/sammple/demos-en/textpeer.rb: new widget demo. * ext/tk/tcltklib.c: decrase SEGV troubles (probably) * ext/tk/lib/tk.rb: remove Thread.critical access if Ruby1.9 * ext/tk/lib/tk/multi-tk.rb: support Ruby1.9 (probably) * ext/tk/lib/tkextlib/tile.rb: add method to define Tcl/Tk command to make Tcl/Tk theme sources (based on different version of Tile extension) available. (Tk::Tile::__define_LoadImages_proc_for_comaptibility__) * ext/tk/lib/tk.rb, ext/tk/lib/tk/wm.rb: support dockable frames (Tcl/Tk8.5 feature). 'wm' command can treat many kinds of widgets as toplevel widgets. * ext/tk/lib/tkextlib/tile/style.rb: ditto. (Tk::Tile::Style.__define_wrapper_proc_for_compatibility__) * ext/tk/lib/tk/font.rb: add actual_hash and metrics_hash to get properties as a hash. metrics_hash method returns a boolean value for 'fixed' option. But metrics method returns numeric value (0 or 1) for 'fixed' option, because of backward compatibility. * ext/tk/lib/tk/timer.rb: somtimes fail to set callback procedure. * ext/tk/lib/tk.rb: add Tk.sleep and Tk.wakeup method. Tk.sleep doesn't block the eventloop. It will be better to use the method in event callbacks. * ext/tk/sample/tksleep_sample.rb: sample script about Tk.sleep. Sat Mar 29 04:08:59 2008 Yukihiro Matsumoto * class.c (clone_method): should copy cref as well. [ruby-core:15833] Mon Mar 24 20:07:42 2008 Akinori MUSHA * eval.c (rb_eval): Call trace hook for if expression after the condition has been evaluated, not before; submitted by Rocky Bernstein in #18722. Mon Mar 24 19:44:53 2008 Akinori MUSHA * parse.y (yycompile): Always prepare a new array for each file's SCRIPT_LINES__ storage, instead of appending source lines every time a file is re-loaded; submitted by Rocky Bernstein in #18517. Mon Mar 24 10:25:54 2008 Nobuyoshi Nakada * configure.in: sitearch should use target_cpu. [ruby-core:15986] Mon Mar 24 01:24:24 2008 Masatoshi SEKI * lib/erb.rb (result): use proc instead of Thread. [ruby-dev:33692] Fri Mar 21 21:26:52 2008 Nobuyoshi Nakada * lib/resolv.rb (Resolv::Hosts): should not use win32/resolv on cygwin. [ruby-dev:29945], [ruby-dev:34095] * lib/win32/registry.rb (Win32::Registry.expand_environ): try upcased name too for cygwin. [ruby-dev:29945] * lib/win32/resolv.rb (Win32::Resolv.get_hosts_path): use expand_path. Fri Mar 21 21:10:00 2008 Akinori MUSHA * lib/ipaddr.rb: Say that I am the current maintainer. * lib/set.rb: Ditto. * lib/shellwords.rb: Ditto. * ext/syslog/syslog.txt: Ditto. Fri Mar 21 09:24:28 2008 Nobuyoshi Nakada * instruby.rb (open_for_install): write block result and rewrite only if changed from existing file. Wed Mar 19 21:01:08 2008 Nobuyoshi Nakada * dir.c (dir_inspect, dir_path, dir_tell): check for frozen and closed is not needed. [ruby-dev:32640] Wed Mar 19 20:25:40 2008 Nobuyoshi Nakada * dir.c (Init_Dir): define inspect method. [ruby-core:15960] Wed Mar 19 14:59:12 2008 Nobuyoshi Nakada * misc/ruby-style.el (ruby-style-{case,label}-indent): fix for labels inside blocks in switch and function top level. Wed Mar 19 14:36:40 2008 Nobuyoshi Nakada * bignum.c (rb_cstr_to_inum): treat successive underscores as nondigit. [ruby-dev:34089] Wed Mar 19 00:01:23 2008 Masatoshi SEKI * lib/erb.rb (ERB::Compiler): Make some minor code optimization. Mon Mar 17 17:11:13 2008 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-mode): should use `run-mode-hooks' instead of calling `run-hooks' directly to run the mode hook. patch from Chiyuan Zhang in [ruby-core:15915] Mon Mar 17 16:41:08 2008 Nobuyoshi Nakada * configure.in: unset GREP_OPTIONS. [ruby-core:15918] Fri Mar 14 16:59:23 2008 Nobuyoshi Nakada * configure.in (RUBY_LIB_PREFIX): fix for prefix. Fri Mar 14 16:35:11 2008 Yukihiro Matsumoto * lib/cgi.rb (CGI::Cookie::initialize): performance patch from Makoto Kuwata in [ruby-dev:34048]. Fri Mar 14 15:49:05 2008 Nobuyoshi Nakada * configure.in (RUBY_LIB_PREFIX): use libdir. Fri Mar 14 10:12:29 2008 Nobuyoshi Nakada * configure.in (RUBY_CHECK_VARTYPE): should not indent preprocessor directives. Thu Mar 13 00:37:20 2008 Nobuyoshi Nakada * eval.c (rb_call0): yields the last executed node line number at return event. [ruby-core:15855] Wed Mar 12 02:12:20 2008 Kazuhiro NISHIYAMA * lib/delegate.rb: check $@ to avoid NoMethodError. Tue Mar 11 19:48:09 2008 Nobuyoshi Nakada * numeric.c (fix_coerce): try conversion before type check. [ruby-core:15838] Tue Mar 11 17:03:23 2008 Nobuyoshi Nakada * lib/delegate.rb (Delegator#initialize, DelegateClass): skip correct backtrace. [ruby-dev:34019] Tue Mar 11 16:43:53 2008 Nobuyoshi Nakada * win32/win32.c (rb_w32_cmdvector): terminate shrunken command line. Tue Mar 11 12:39:03 2008 Nobuyoshi Nakada * common.mk (clean-local): removes MINOBJS. Sat Mar 8 18:50:57 2008 Nobuyoshi Nakada * file.c (isdirsep): backslash is valid path separator on cygwin too. Fri Mar 7 19:56:10 2008 Nobuyoshi Nakada * lib/mkmf.rb: rdoc added. [ruby-Patches-9762] Thu Mar 6 15:10:21 2008 NAKAMURA Usaku * {bcc32,win32}/Makefile.sub (RUNRUBY): use $(PROGRAM) instead of ruby$(EXEEXT). suggested by KIMURA Koichi . [ruby-dev:34000] Thu Mar 6 12:15:06 2008 Nobuyoshi Nakada * parse.y (opt_block_param): command can start just after block param definition. [ruby-list:44479] Thu Mar 6 00:34:11 2008 Masatoshi SEKI * lib/erb.rb: update RDoc. Thanks Makoto Kuwata [ruby-dev:33702] Mon Mar 3 23:28:34 2008 GOTOU Yuuzou * lib/webrick/httpservlet/filehandler.rb: should normalize path separators in path_info to prevent directory traversal attacks on DOSISH platforms. reported by Digital Security Research Group [DSECRG-08-026]. * lib/webrick/httpservlet/filehandler.rb: pathnames which have not to be published should be checked case-insensitively. Mon Mar 3 16:14:24 2008 Nobuyoshi Nakada * hash.c (rb_any_hash): shrinks all results in Fixnum range. [ruby-core:15713] Sat Mar 1 02:35:08 2008 Nobuyoshi Nakada * bignum.c (big2str_find_n1): check integer overflow. Tue Feb 26 16:06:00 2008 Technorama Ltd. * ext/openssl/ossl_pkey_{ec,dh,dsa,rsa}.c: Remove useless warnings. * ext/openssl/ossl_asn1.c: Simplify code. * ext/openssl/ossl_ssl_session.c Fix compiler warnings. Undefine #id if SSL_SESSION_get_id is not supported. Tue Feb 26 15:43:42 2008 Tanaka Akira * parse.y (tokadd_escape): refactored. [ruby-core:15657] Mon Feb 25 17:30:29 2008 Technorama Ltd. * ext/openssl/digest.c ext/openssl/lib/openssl/digest.rb: Commit patch #9280 from Akinori MUSHA. Simplify the OpenSSL::Digest class and make use of the existing Digest framework. Enhance performance. Mon Feb 25 13:40:03 2008 Tanaka Akira * process.c (Init_process): share bignum objects for RLIM_INFINITY, RLIM_SAVED_MAX and RLIM_SAVED_CUR if they are equal. Sun Feb 24 23:29:48 2008 Nobuyoshi Nakada * common.mk, {bcc,win}32/Makefile.sub (clean-local): remove intermediate files. Sun Feb 24 03:52:58 2008 Nobuyoshi Nakada * util.c (valid_filename): use O_EXCL to get rid of clobbering existing files in race conditions. Fri Feb 22 19:50:19 2008 Nobuyoshi Nakada * bignum.c (BIGZEROP): fix for longer Bignum zeros. [ruby-Bugs-17454] Fri Feb 22 16:09:53 2008 Nobuyoshi Nakada * bignum.c (rb_big_lshift, rb_big_rshift, rb_big_aref): removed excess arguments. Thu Feb 21 00:01:34 2008 Nobuyoshi Nakada * configure.in (RPATHFLAG): -R option of HP-UX ld is not for runtime load path. [ruby-list:44600] Wed Feb 20 23:55:19 2008 Nobuyoshi Nakada * win32/win32.c (rb_w32_map_errno): exported. Wed Feb 20 13:08:52 2008 Nobuyoshi Nakada * instruby.rb (parse_args): added --dir-mode, --script-mode and --cmd-type options. [ruby-dev:33816] * instruby.rb (parse_args): added bin-arch and bin-comm to install type, for compiled files and script files. * instruby.rb (parse_args): deal with make style command line macros, and count as long syle options if prefixed with INSTALL_. * instruby.rb (makedirs): use $dir_mode. [ruby-dev:33805] * instruby.rb (open_for_install): set file mode, which is now permission mode instead of access mode. * instruby.rb (bin-comm): installs scripts with replacing shebang lines. Tue Feb 19 18:34:32 2008 Tanaka Akira * gc.c (STACK_LENGTH) [SPARC] : 0x80 offset removed. [ruby-dev:33857] Tue Feb 19 14:27:32 2008 Nobuyoshi Nakada * ext/readline/readline.c (readline_event): prevent polling. based on a patch from error errorsson in [ruby-Bugs-17675]. Tue Feb 19 12:08:29 2008 Nobuyoshi Nakada * parse.y (yycompile): clear ruby_eval_tree_begin if parse failed. Mon Feb 18 16:23:45 2008 Nobuyoshi Nakada * parse.y (yycompile): clear ruby_eval_tree_begin too before parse. Mon Feb 18 10:17:42 2008 Nobuyoshi Nakada * ext/pty/lib/expect.rb (IO#expect): check if peer is closed. [ruby-Bugs-17940] Fri Feb 15 20:37:06 2008 Tadayoshi Funaba * lib/rational.rb (floor, ceil, truncate, round): do not use definitions of Numeric. * lib/rational.rb (to_i): should returns truncated self. * lib/complex.rb (numerator): requires Integer#{numerator,denominator}. * lib/complex.rb (quo): do not use definition of Numeric. * lib/complex.rb (div, divmod, floor, ceil, truncate, round): undef'ed. Fri Feb 15 15:23:12 2008 Nobuyoshi Nakada * ext/iconv/iconv.c (iconv_convert): check upper bound. a patch from Daniel Luz at [ruby-Bugs-17910]. Fri Feb 15 02:42:25 2008 Nobuyoshi Nakada * configure.in (ftruncate): check if available. * file.c (rb_file_truncate): check if ftruncate instead of truncate. Fri Feb 15 02:40:54 2008 Nobuyoshi Nakada * configure.in (sigsetmask): check when signal semantics is not POSIX. * signal.c (USE_TRAP_MASK): set true if sigprocmask or sigsetmask is available. Thu Feb 14 17:44:32 2008 Yukihiro Matsumoto * ext/dl/ptr.c (dlmem_each_i): typo fixed. a patch from IKOMA Yoshiki in [ruby-dev:33776]. Thu Feb 14 16:02:51 2008 Nobuyoshi Nakada * file.c (rb_file_s_utime): inhibits with secure level 2 or higher. Thu Feb 14 01:43:16 2008 Nobuyoshi Nakada * lib/timeout.rb (Timeout::timeout): made sensitive to location on the stack. [ruby-core:15458] Thu Feb 14 00:49:53 2008 Nobuyoshi Nakada * common.mk (INSTRUBY_ARGS): pass mode to install. [ruby-dev:33766] * instruby.rb (parse_args): added --data-mode and --prog-mode options. Tue Feb 12 11:33:26 2008 Masatoshi SEKI * test/erb/test_erb.rb(TestERBCore): import from erb-2.0.4. * test/erb/hello.erb: ditto Mon Feb 11 17:25:21 2008 Kouhei Sutou * lib/rss/rss.rb (RSS::VERSION), test/rss/test_version.rb, NEWS: 0.2.3 -> 0.2.4. * lib/rss/maker.rb, lib/rss/maker/, test/rss/test_maker_2.0.rb: fixed a bug that RSS::Maker.make("0.9")'s item doesn't make some elements if description is missed. Reported by Michael Auzenne. Thanks!!! * lib/rss/maker/0.9.rb, test/rss/test_maker_0.9.rb: RSS::Maker.make("0.9") generates RSS 0.92 not RSS 0.91. Mon Feb 11 16:57:00 2008 Kazuhiro NISHIYAMA * ChangeLog: format-time-string under C locale. [ruby-dev:33261] Mon Feb 11 16:31:47 2008 URABE Shyouhei * gc.c (rb_newobj): prohibit call of rb_newobj() during gc. Submitted by Sylvain Joyeux [ruby-core:12099]. * ext/dl/ptr.c: do not use LONG2NUM() inside dlptr_free(). Slightly modified fix bassed on a patch by Sylvain Joyeux [ruby-core:12099] [ ruby-bugs-11859 ] [ ruby-bugs-11882 ] [ ruby-patches-13151 ]. Mon Feb 11 00:22:55 2008 NARUSE, Yui * lib/benchmark.rb (Job::Benchmark#item): fix typo. Sat Feb 9 23:22:52 2008 Nobuyoshi Nakada * ext/bigdecimal/extconf.rb: simplified the condition. Sat Feb 9 17:51:24 2008 Nobuyoshi Nakada * ext/bigdecimal/bigdecimal.c (BigDecimal_to_f): use strtod() for more precision. [ruby-talk:290296] * ext/bigdecimal/bigdecimal.c (BASE_FIG): made constant. * ext/bigdecimal/extconf.rb: ditto. [ruby-dev:33658] Sat Feb 9 00:44:52 2008 Nobuyoshi Nakada * lib/irb.rb (IRB::Irb::eval_input): rescues Interrupt and other than SystemExit and SignalException. [ruby-core:15359] Fri Feb 8 15:09:21 2008 Nobuyoshi Nakada * lib/mkmf.rb (xsystem): expand macros like as make. Tue Feb 5 11:14:11 2008 Nobuyoshi Nakada * lib/mkmf.rb (INSTALL_DIRS, install_dirs): added BINDIR. * lib/mkmf.rb (install_files): rejects files matching to $NONINSTALLFILES. * lib/mkmf.rb (init_mkmf): defaults $NONINSTALLFILES to backup and temporary filse. Mon Feb 4 16:44:24 2008 Nobuyoshi Nakada * configure.in (darwin): NSIG is not defined if _XOPEN_SOURCE > 500L. [ruby-dev:33584] Sat Feb 2 20:06:42 2008 Yukihiro Matsumoto * lib/benchmark.rb (Benchmark::realtime): make Benchmark#realtime a bit faster. a patch from Alexander Dymo in [ruby-core:15337]. Sat Feb 2 09:53:39 2008 Nobuyoshi Nakada * configure.in (darwin): disabled fat-binary support which confuses configure much, since ``universal'' implies hidden cross-compiling. TODO: ruby and libruby.bundle might be possible to bound with `lipo' after builds for each archs. Anyway, config.h and rbconfig.rb must be separated definitely at least. Fri Feb 1 21:42:37 2008 Nobuyoshi Nakada * configure.in (darwin): _XOPEN_SOURCE is necessary to make ucontext_t consistent with the library implementation of MacOS X 10.5. [ruby-dev:33461] * configure.in (darwin): ucontext on PowerPC MacOS X 10.5 is broken. Thu Jan 31 08:31:19 2008 Nobuyoshi Nakada * common.mk (ext/extmk.rb, instruby.rb): inlined $(MAKE) so that can be executed even with -n. Thu Jan 31 07:00:19 2008 Masatoshi SEKI * lib/rinda/tuplespace.rb (bin_for_find): should find a symbol by Symbol class. * test/rinda/test_rinda.rb (test_symbol_tuple): ditto. Wed Jan 30 22:07:58 2008 Tadayoshi Funaba * lib/date.rb: refined deprecated methods. Wed Jan 30 22:06:54 2008 Tadayoshi Funaba * bignum.c (rb_cstr_to_inum): '0_2' is a valid representation. Tue Jan 29 22:40:12 2008 Yusuke Endoh * range.c (step_i): rb_funcall receives VALUE as an argument. Tue Jan 29 11:53:05 2008 Nobuyoshi Nakada * configure.in: rm largefile.h. Mon Jan 28 01:21:15 2008 Yukihiro Matsumoto * io.c (rb_open_file): should check NUL in path. . * io.c (rb_io_s_popen): ditto. * io.c (rb_io_reopen): ditto. * io.c (next_argv): ditto. * io.c (rb_io_s_foreach): ditto. * io.c (rb_io_s_readlines): ditto. * io.c (rb_io_s_read): ditto. Fri Jan 25 22:33:38 2008 Yusuke Endoh * math.c: fix comment. [ruby-dev:33276] Fri Jan 25 10:31:58 2008 Nobuyoshi Nakada * */*.bat: set svn:mime-type to text/batch. Thu Jan 24 19:36:22 2008 Nobuyoshi Nakada * lib/uri/generic.rb (URI::Generic::inspect): use Kernel#to_s instead object_id with printf. [ruby-dev:33347] Tue Jan 22 11:22:47 2008 NAKAMURA Usaku * win32/setup.mak ($(ARCH)): if a macro is appended by $(APPEND), a space will be inserted on the top of the line. * win32/Makefile.sub (MKFILES): stop make process if Makefile is updated. Mon Jan 21 17:34:41 2008 Akinori MUSHA * io.c (rb_io_mode_flags, rb_io_mode_modenum): Ignore encoding options for forward compatibility. Mon Jan 21 12:50:02 2008 Nobuyoshi Nakada * eval.c, gc.c (setjmp): sigsetjmp is a macro on cygwin. Sat Jan 19 11:21:53 2008 Nobuyoshi Nakada * configure.in (sigsetjmp): check if available. * eval.c, gc.c (setjmp): do not use _setjmp if sigsetjmp is available. Sat Jan 19 11:10:11 2008 Nobuyoshi Nakada * configure.in: Remove wrong assumptions about Cygwin. a patch from Corinna Vinschen in [ruby-Bugs-17018]. Thu Jan 17 21:06:01 2008 Tadayoshi Funaba * lib/date.rb (Date::Infinity#<=>): didn't work. A patch from Dirkjan Bussink [ruby-core:15098]. This is a bug obviously. However it didn't affect the library's functions. * lib/date.rb, lib/date/format.rb: some trivial changes. Tue Jan 15 15:09:28 2008 Nobuyoshi Nakada * win32/setup.mak: strip out empty lines from CPP output. Tue Jan 15 03:41:42 2008 Nobuyoshi Nakada * eval.c (eval): check if backtrace is empty. [ruby-core:15040] Tue Jan 15 01:28:47 2008 Nobuyoshi Nakada * common.mk: simplified dummy objects dependencies. Mon Jan 14 16:12:58 2008 Yukihiro Matsumoto * lib/shellwords.rb: scape should be an alias to shellescape. a patch from Masahiro Kawato in [ruby-dev:33060]. Mon Jan 14 09:32:40 2008 Tadayoshi Funaba * lib/time.rb: do not reference Time directly from the inside of definitions. [ruby-dev:33059] Sat Jan 12 18:27:41 2008 Nobuyoshi Nakada * eval.c (rb_define_alloc_func, rb_undef_alloc_func): should define/undef on a signleton class. [ruby-core:09959] Sat Jan 12 12:04:14 2008 Tadayoshi Funaba * lib/date.rb, lib/date/format.rb: tuning for performance. Fri Jan 11 12:35:56 2008 Nobuyoshi Nakada * configure.in: moved broken syscall checks from process.c etc. * defines.h (WORDS_BIGENDIAN): honor __BIG_ENDIAN__ than the result of configure. * dln.c: use dlopen on Mac OS X 10.3 or later. backport from trunk. * lib/rdoc/options.rb (check_diagram): more precise check, darwin is not Windows but minwg is on it. Thu Jan 10 10:53:50 2008 Nobuyoshi Nakada * win32/win32.c (rb_w32_open_osfhandle): reverted to old definition. [ ruby-Bugs-16948 ] Tue Jan 8 20:02:08 2008 Nobuyoshi Nakada * win{32,ce}/Makefile.sub: merged. Sun Jan 6 09:39:02 2008 Tadayoshi Funaba * lib/date.rb, lib/date/format.rb: introduced some constants (for internal use). * sample/cal.rb: trivial adjustments. Fri Jan 4 23:08:48 2008 Nobuyoshi Nakada * time.c (time_arg): use converted object. [ruby-core:14759] Fri Jan 4 01:20:21 2008 Nobuyoshi Nakada * win32.h: only VC6 needs extern "C++" for math.h. [ruby-talk:285660] Thu Jan 3 11:28:58 2008 Nobuyoshi Nakada * io.c (fptr_finalize): clear errno first. [ruby-talk:284492] Wed Jan 2 10:18:56 2008 Tadayoshi Funaba * sample/time.rb: use Process.times instead of Time.times. Wed Jan 2 09:18:11 2008 Tadayoshi Funaba * sample/goodfriday.rb: examples for date are enough. retired. Wed Jan 2 09:06:55 2008 Tadayoshi Funaba * sample/cal.rb: just updated with the newest version. Mon Dec 31 06:50:38 2007 Nobuyoshi Nakada * trunk/common.mk: not use -I$(srcdir)/lib with $(MINIRUBY) for cross compiling. * configure.in, {win,bcc}32/Makefile.sub (MINIRUBY): -I$(srcdir)/lib moved. Sun Dec 30 22:48:37 2007 Tadayoshi Funaba * lib/date.rb (_valid_time?): I'm not sure to recommend such an expression. but anyway it is acceptable now. [ruby-core:14580] Fri Dec 28 16:36:33 2007 NARUSE, Yui * lib/resolv.rb (Resolv::DNS#each_address): now returns IPv6 address. Fri Dec 28 13:21:32 2007 Kouhei Sutou * lib/rss/rss.rb, test/rss/test_version.rb, NEWS: 0.2.2 -> 0.2.3. * lib/rss/parser.rb, test/rss/test_parser.rb: supported "-" in tag name. Reported by Ray Chen. Thanks. Thu Dec 27 23:56:01 2007 Nobuyoshi Nakada * mkconfig.rb: should not use the libraries under the source directory at cross compiling. Thu Dec 27 11:02:45 2007 Nobuyoshi Nakada * intern.h, string.c (rb_str_set_len): added for upgrading path from 1.8 to 1.9. [ruby-dev:32807] * string.c (rb_str_lines, rb_str_bytes): ditto. Thu Dec 27 10:47:32 2007 Technorama Ltd. * ext/openssl/ossl_ssl.c: Only show a warning if the default DH callback is actually used. * ext/openssl/ossl_rand.c: New method: random_add(). Wed Dec 26 22:27:45 2007 NARUSE, Yui * lib/resolv.rb (Resolv::DNS::Name.==): fix for other is array of Resolv::DNS::Label::Str. * lib/resolv.rb (Resolv::DNS::MessageEncoder#put_label): String#string is not defined, so replace to_s. * lib/resolv.rb (Resolv::IPv6#to_name): ip6.int is obsoleted by int.arpa. Mon Dec 24 16:18:57 2007 Eric Hodel * lib/rdoc/ri/ri_options.rb: Fix ri --help listing of gem ri paths. Merge of r14567 and r14569 from trunk. * lib/rdoc/ri/ri_paths.rb: Fix duplication of ri data for multiple gems. Merge of r14567 from trunk Mon Dec 24 12:35:03 2007 Nobuyoshi Nakada * win{32,ce}/Makefile.sub (MFLAGS): defaulted to -l. Mon Dec 24 11:56:31 2007 Nobuyoshi Nakada * {bcc32,win{32,ce}}/Makefile.sub (SET_MAKE): set MFLAGS which is not set by default, to get rid of chaotic situation of MFLAGS/MAKEFLAGS. Sat Dec 22 14:49:46 2007 Tadayoshi Funaba * lib/date.rb: don't freeze nil even if 1.8 will not be aware of the issue. [ruby-dev:32677] Wed Dec 19 13:57:43 2007 Nobuyoshi Nakada * configure.in (TIMEZONE_VOID): check whether timezone requires zero arguments. [ruby-dev:32631] Wed Dec 19 12:01:42 2007 Nobuyoshi Nakada * parse.y (f_rest_arg): check if duplicated. [ruby-core:14140] Wed Dec 19 10:52:29 2007 Nobuyoshi Nakada * bignum.c (rb_cstr_to_inum): an underscore succeeding after octal prefix is allowed. [ruby-core:14139] Mon Dec 17 13:43:15 2007 Tanaka Akira * gc.c (stack_end_address): use local variable address instead of __builtin_frame_address(0) to avoid SEGV on SunOS 5.11 on x86 with gcc (GCC) 3.4.3 (csl-sol210-3_4-20050802). stack_end_address returned a frame address of garbage_collect since stack_end_address doesn't create its own frame. So a VALUE stored in a callee saved register, %edi, pushed into the stack at the beginning of garbage_collect was not marked. Mon Dec 17 12:21:25 2007 Nobuyoshi Nakada * Makefile.in (RUNRUBY): added RUNRUBYOPT. Fri Dec 14 12:36:35 2007 Nobuyoshi Nakada * configure.in (RUBY_CHECK_VARTYPE): check if a variable is defined and its type. * configure.in (timezone, altzone): check for recent cygwin. * missing/strftime.c (strftime): fix for timezone. [ruby-dev:32536] * lib/mkmf.rb (try_var): should fail for functions. * ext/readline/extconf.rb: should use have_func for functions instead of have_var. Tue Dec 11 00:04:05 2007 Akinori MUSHA * array.c (rb_ary_slice_bang): If an invalid negative index (< -size) is given, do not raise an exception but return nil just like slice() does. * test/ruby/test_array.rb (TestArray::test_slice, TestArray::test_slice!): Pull in test cases from trunk. Mon Dec 10 21:47:53 2007 Nobuyoshi Nakada * transcode.c (str_transcode): allow non-registered encodings. [ruby-dev:32520] Mon Dec 10 21:00:30 2007 Yukihiro Matsumoto * array.c (rb_ary_slice_bang): should return nil if position out of range. a patch from Akinori MUSHA . [ruby-dev:32518] Mon Dec 10 18:28:06 2007 Yukihiro Matsumoto * lib/uri/common.rb (URI::REGEXP::PATTERN): typo in REG_NAME regular expression. a patch from Ueda Satoshi . [ruby-dev:32514] Sun Dec 9 12:39:01 2007 Nobuyoshi Nakada * lib/cgi.rb (read_multipart): exclude blanks from header values. [ruby-list:44327] Wed Dec 5 23:38:50 2007 Nobuyoshi Nakada * range.c (range_each): followed step_i change. Wed Dec 5 18:08:45 2007 Tanaka Akira * numeric.c (int_odd_p): new method Integer#odd?. (int_even_p): new method Integer#even?. (int_pred): new method Integer#pred. (fix_odd_p): new method Fixnum#odd?. (fix_even_p): new method Fixnum#even?. Wed Dec 5 15:15:21 2007 Nobuyoshi Nakada * range.c (step_i, range_step): support non-fixnum steps. [ruby-talk:282100] Tue Dec 4 11:23:50 2007 Nobuyoshi Nakada * bignum.c (rb_cstr_to_inum): trailing spaces may exist at sqeezing preceeding 0s. [ruby-core:13873] Sun Dec 2 22:43:45 2007 Nobuyoshi Nakada * eval.c (error_print): put newline unless multiple line message ends with a newline. [ruby-dev:32429] Sun Dec 2 15:49:20 2007 Kouhei Sutou * lib/rss/rss.rb, test/rss/test_version.rb, NEWS: 0.2.1 -> 0.2.2. * lib/rss/maker/itunes.rb: fixed new_itunes_category. * lib/rss/maker/taxonomy.rb: new_taxo_topic -> new_topic because of consistency. * test/rss/test_maker_itunes.rb, test/rss/test_itunes.rb: removed needless UTF-8 characters. Sun Dec 2 01:12:15 2007 James Edward Gray II Merged 14070 from trunk. * lib/xmlrpc/server.rb (XMLRPC::Server#server): Improve signal handling so pressing control-c in the controlling terminal or sending SIGTERM stops the XML-RPC server. Sat Dec 1 15:13:33 2007 Yukihiro Matsumoto * lib/resolv.rb: documentation update. backported from 1.9. [ruby-core:13273] Sat Dec 1 03:30:47 2007 Nobuyoshi Nakada * parse.y (newline_node): set line from outermost node before removing NODE_BEGIN. [ruby-dev:32406] Fri Nov 30 21:53:28 2007 Kouhei Sutou * lib/rss/rss.rb, test/rss/test_version.rb: 0.2.0 -> 0.2.1. * lib/rss/content.rb, lib/rss/content/1.0.rb, lib/rss/content/2.0.rb, lib/rss/maker/content.rb, test/rss/rss-testcase.rb, test/rss/test_content.rb, test/rss/test_maker_content.rb: supported content:encoded with RSS 2.0. Suggested by Sam Lown. Thanks. * NEWS: added the above changes. Thu Nov 29 16:59:10 2007 Nobuyoshi Nakada * parse.y (stmt): remove unnecessary NODE_BEGIN. [ruby-core:13814] Wed Nov 28 14:43:14 2007 Nobuyoshi Nakada * ext/extmk.rb (extract_makefile): use dldflags instead of DLDFLAGS to get rid of mixing $LDFLAGS and $ARCH_FLAG. * lib/mkmf.rb (configuration): ditto. * lib/mkmf.rb (create_makefile): support for extensions which has no shared object. Wed Nov 28 09:51:42 2007 Nobuyoshi Nakada * bignum.c (rb_big2str0): do not clobber space for sign. * sprintf.c (remove_sign_bits): extends sign bit first. Wed Nov 21 01:04:12 2007 Yukihiro Matsumoto * object.c (nil_plus): remove unused function. [ruby-core:13737] Sun Nov 18 14:03:44 2007 Nobuyoshi Nakada * eval.c (rb_alias): do not call hook functions until initialization finishes. [ruby-talk:279538] Sun Nov 18 09:09:48 2007 Nobuyoshi Nakada * lib/mkmf.rb (String#tr_cpp): make preprocessor identifiers. Sat Nov 17 13:58:11 2007 Masaki Suketa * ext/win32ole/win32ole.c (ole_invoke): bug fix. [ruby-talk:279100] Fri Nov 16 17:41:34 2007 Nobuyoshi Nakada * ext/iconv/iconv.c (Document-class): moved the simplest example to the top. * ext/iconv/iconv.c (iconv_s_iconv): Document-method: needs class prefix for class method. [ruby-core:13542] * ext/iconv/iconv.c (iconv_iconv): also instance method needs to be qualified. Fri Nov 16 11:16:41 2007 Nobuyoshi Nakada * lib/yaml/rubytypes.rb (String#is_binary_data?): use Integer#fdiv. Thu Nov 15 19:50:46 2007 NAKAMURA Usaku * ext/curses/extconf.rb: check macro if cannot find func. [ruby-list:44224] Thu Nov 15 12:19:14 2007 Yukihiro Matsumoto * lib/cgi/session.rb (CGI::Session::FileStore::restore): use lockfile for exclusive locks. a patch from . [ruby-dev:32296] Wed Nov 14 01:52:59 2007 Tanaka Akira * missing/isinf.c (isinf): don't define if the macro is defined. Wed Nov 14 01:34:42 2007 Nobuyoshi Nakada * numeric.c (round): fallback definition. * numeric.c (flo_divmod, flo_round): use round() always. [ruby-dev:32269] Tue Nov 13 22:02:23 2007 Masatoshi SEKI * lib/drb/drb.rb: remove Thread.exclusive. * lib/drb/extservm.rb: ditto. Tue Nov 13 16:33:07 2007 Nobuyoshi Nakada * numeric.c (flodivmod): work around for infinity. * numeric.c (flo_divmod): work around for platforms have no round(). [ruby-dev:32247] Tue Nov 13 13:58:51 2007 Tanaka Akira * numeric.c (numeric.c): Integer#ord implemented. [ruby-dev:32206] Tue Nov 13 02:57:04 2007 URABE Shyouhei * numeric.c (flo_divmod): round to the nearest integer. [ ruby-Bugs-14540 ] Mon Nov 12 16:52:29 2007 Nobuyoshi Nakada * lib/mkmf.rb (create_makefile): rdoc about srcprefix. a patch from Daniel Berger in [ruby-core:13378]. Mon Nov 12 13:53:06 2007 Yukihiro Matsumoto * misc/ruby-mode.el (ruby-parse-partial): handle stringified symbols properly using ruby-forward-string. Mon Nov 12 12:38:31 2007 Tanaka Akira * Makefile.in (lex.c): don't remove lex.c at first. Fri Nov 9 07:26:04 2007 Yukihiro Matsumoto * random.c: update MT URL.[ruby-core:13305]. Wed Nov 7 03:32:38 2007 Yukihiro Matsumoto * lib/rexml/encodings/SHIFT-JIS.rb (REXML::Encoding): place -x for nkf conversion. a patch from . [ruby-dev:32183] Mon Nov 5 05:17:04 2007 Nobuyoshi Nakada * lib/optparse.rb (OptionParser::Switch::summarize): fix for long form option with very long argument. a patch from Kobayashi Noritada in [ruby-list:44179]. Mon Nov 5 01:20:33 2007 Yukihiro Matsumoto * parse.y (call_args): remove "parenthesize argument(s) for future version" warning. when I added this warning, I had a plan to reimplement the parser that is simpler than the current one. since we abandoned the plan, warning no longer required. Fri Nov 2 00:13:51 2007 Yukihiro Matsumoto * array.c (rb_ary_assoc): check and convert inner arrays (assocs) using #to_ary. * hash.c (rb_hash_s_create): check and convert argument hash using #to_hash. * hash.c (rb_hash_s_create): Hash#[] now takes assocs as source of hash conversion. Thu Nov 1 23:47:43 2007 Masatoshi SEKI * lib/drb/drb.rb (DRbTCPSocket): Improving with multiple network interface. * test/drb/drbtest.rb: ditto. Fri Oct 26 17:14:14 2007 Nobuyoshi Nakada * numeric.c (fix_pow): returns 1.0 for 0**0.0. * numeric.c (fix_pow): returns infinity for 0**-1. [ruby-dev:32084] Wed Oct 25 07:18:09 2007 James Edward Gray II Merged 13781 from trunk. * lib/net/telnet.rb (Net::Telnet#login): Allowing "passphrase" in addition to "password" for Telnet login prompts. [ruby-Bugs-10746] Wed Oct 25 06:46:21 2007 James Edward Gray II Merged 13779 from trunk. * lib/net/telnet.rb (Net::Telnet#login): Making the password prompt pattern case insensitive. [ruby-Bugs-10746] Thu Oct 25 14:19:33 2007 Nobuyoshi Nakada * io.c (rb_io_tell, rb_io_seek): check errno too. [ruby-dev:32093] Wed Oct 25 08:03:53 2007 James Edward Gray II Merged 13767, 13768, 13769, and 13770 from trunk. * lib/xmlrpc/parser.rb (XMLRPC::Convert::dateTime): Fixing a bug that caused time zone conversion to fail for some ISO 8601 date formats. [ruby-Bugs-12677] * lib/xmlrpc/client.rb (XMLRPC::Client#do_rpc): Explicitly start the HTTP connection to support keepalive requests. [ruby-Bugs-9353] * lib/xmlrpc/client.rb (XMLRPC::Client#do_rpc): Improving the error message for Content-Type check failures. [ruby-core:12163] * lib/xmlrpc/utils.rb (XMLRPC::ParseContentType#parse_content_type): Making Content-Type checks case insensitive. [ruby-Bugs-3367] Sun Oct 21 21:16:43 2007 Kouhei Sutou * lib/rss.rb, lib/rss/, test/rss/, sample/rss/: merged from trunk. - 0.1.6 -> 2.0.0. - fixed image module URI. Thanks to Dmitry Borodaenko. - supported Atom. - supported ITunes module. - supported Slash module. * NEWS: added an entry for RSS Parser. Thu Oct 18 10:57:06 2007 Tanaka Akira * ruby.h (RCLASS_IV_TBL): defined. (RCLASS_M_TBL): ditto. (RCLASS_SUPER): ditto. (RMODULE_IV_TBL): ditto. (RMODULE_M_TBL): ditto. (RMODULE_SUPER): ditto. Mon Oct 15 22:08:55 2007 Akinori MUSHA * NEWS: Merge some of the sub-sections, as the differences were unclear. Mon Oct 15 21:57:07 2007 Akinori MUSHA * NEWS: Mention ipaddr enhancements. * lib/ipaddr.rb (in_addr, in6_addr, addr_mask): Make some minor code optimization. * lib/ipaddr.rb (<=>): Implement IPAddr#<=> and make IPAddr comparable. * lib/ipaddr.rb (succ): Implement IPAddr#succ. You can now create a range between two IPAddr's, which (Range) object is enumerable. * lib/ipaddr.rb (to_range): A new method to create a Range object for the (network) address. * lib/ipaddr.rb (coerce_other): Support type coercion and make &, |, == and include? accept a string or an integer instead of an IPAddr object as the argument. * lib/ipaddr.rb (initialize): Give better error messages. * lib/ipaddr.rb: Improve documentation. Mon Oct 15 21:24:25 2007 Akinori MUSHA * NEWS: Mention shellwords and tempfile enhancements. * NEWS: Move the entry about Tk::X_Scrollable to a better section. Mon Oct 15 17:28:20 2007 NAKAMURA Usaku * ext/openssl/lib/openssl/buffering.rb (read, readpartial): revert r12496. handling EOF is a little differnt in ruby 1.8 and ruby 1.9. [ruby-dev:31979] Mon Oct 15 11:45:12 2007 Nobuyoshi Nakada * marshal.c (r_bytes0): refined length check. [ruby-dev:32059] Mon Oct 15 09:58:07 2007 Nobuyoshi Nakada * marshal.c (r_bytes0): check if source has enough data. [ruby-dev:32054] Mon Oct 15 01:15:09 2007 Tanaka Akira * ext/socket/socket.c (s_accept_nonblock): make accepted fd nonblocking. [ruby-talk:274079] Sun Oct 14 04:08:34 2007 Nobuyoshi Nakada * configure.in (AC_SYS_LARGEFILE): keep results also in command options, to vail out of mismatch. [ruby-list:44114] * mkconfig.rb, lib/mkmf.rb (configuration): add DEFS. Sun Oct 14 03:55:52 2007 Nobuyoshi Nakada * win32/mkexports.rb: deal with __fastcall name decorations. [ruby-list:44111] Sat Oct 13 09:02:16 2007 Nobuyoshi Nakada * {bcc,win}32/mkexports.rb: explicit data. [ruby-list:44108] Sat Oct 13 00:35:03 2007 Yukihiro Matsumoto * lib/rexml/source.rb (REXML::SourceFactory::SourceFactory): typo fixed. [ruby-list:44099] Fri Oct 12 11:22:15 2007 Yukihiro Matsumoto * re.c (match_values_at): make #select to be alias to #values_at to adapt RDoc description. [ruby-core:12588] Thu Oct 11 14:32:46 2007 NAKAMURA Usaku * {bcc32,win32}/Makefile.sub (COMMON_MACROS): workaround for old SDK's bug. [ruby-core:12584] Wed Oct 10 23:34:45 2007 Tanaka Akira * lib/securerandom.rb: new file. [ruby-dev:31928] * lib/cgi/session.rb (create_new_id): use securerandom if available. Tue Oct 9 01:01:55 2007 Tanaka Akira * re.c (rb_reg_s_union_m): Regexp.union accepts single argument which is an array of patterns. [ruby-list:44084] Mon Oct 8 20:06:23 2007 GOTOU Yuuzou * lib/net/http.rb, lib/open-uri.rb: remove Net::HTTP#enable_post_connection_check. [ruby-dev:31960] * lib/net/imap.rb: hostname should be verified against server's indentity as persented in the server's certificate. [ruby-dev:31960] * ext/openssl/lib/net/telnets.rb, ext/openssl/lib/net/ftptls.rb: ditto. Sat Oct 6 23:14:54 2007 Yukihiro Matsumoto * string.c (rb_str_to_i): update RDoc since base can be any value between 2 and 36. [ruby-talk:272879] Fri Oct 5 15:44:50 2007 Akinori MUSHA * lib/shellwords.rb: Add shellescape() and shelljoin(). * lib/shellwords.rb: Rename shellwords() to shellsplit() and make the former an alias to the latter. * lib/shellwords.rb: Add escape(), split(), join() as class methods, which are aliases to their respective long names prefixed with `shell'. * lib/shellwords.rb: Add String#shellescape(), String#shellsplit() and Array#shelljoin() for convenience. Fri Oct 5 15:40:04 2007 Akinori MUSHA * lib/tempfile.rb (Tempfile::make_tmpname): Allow to specify a suffix for a temporary file name. * lib/tempfile.rb (Tempfile::make_tmpname): Make temporary file names less predictable by including a random string. [inspired by: akr] Tue Oct 2 21:20:14 2007 NAKAMURA Usaku * win32/win32.c (make_cmdvector): adjust escaped successive double-quote handling. (merge from trunk) Tue Oct 2 20:35:24 2007 NAKAMURA Usaku * win32/win32.c (init_env): initialize HOME and USER environment variables unless set. [ruby-core:12328] (merge from trunk) * win32/win32.c (NtInitialize, getlogin): ditto. * configure.in, win32/Makefile.sub (LIBS): need to link shell32 library for SH* functions on mswin32 and mingw32. Mon Oct 1 12:50:59 2007 Yukihiro Matsumoto * gc.c (id2ref): valid id should not refer T_VALUE nor T_ICLASS. [ruby-dev:31911] Wed Sep 26 23:54:37 2007 Nobuyoshi Nakada * ext/extmk.rb (extmake), lib/mkmf.rb (configuration): top_srcdir should not prefixed with DESTDIR. Wed Sep 26 08:36:31 2007 Nobuyoshi Nakada * Makefile.in (ext/extinit.o): use $(OUTFLAG) as well as other objects. [ruby-Bugs-14228] Wed Sep 26 05:12:17 2007 Nobuyoshi Nakada * parse.y (yyerror): limit error message length. [ruby-dev:31848] * regex.c (re_mbc_startpos): separated from re_adjust_startpos. Tue Sep 25 13:47:38 2007 Yukihiro Matsumoto * eval.c (remove_method): should not remove undef place holder. [ruby-dev:31817] Mon Sep 24 16:52:11 2007 Urabe Shyouhei * lib/net/http.rb: fix typo. Sun Sep 23 21:57:25 2007 GOTOU Yuuzou * lib/net/http.rb: an SSL verification (the server hostname should be matched with its certificate's commonName) is added. this verification can be skipped by "Net::HTTP#enable_post_connection_check=(false)". suggested by Chris Clark * lib/net/open-uri.rb: use Net::HTTP#enable_post_connection_check to perform SSL post connection check. * ext/openssl/lib/openssl/ssl.c (OpenSSL::SSL::SSLSocket#post_connection_check): refine error message. Sun Sep 23 09:05:05 2007 Nobuyoshi Nakada * gc.c (os_obj_of, os_each_obj): hide objects to be finalized. [ruby-dev:31810] Sun Sep 23 08:58:01 2007 Nobuyoshi Nakada * eval_method.ci (rb_attr): should not use alloca for unknowen size input. [ruby-dev:31816] * parse.y (rb_intern_str): prevent str from optimization. Sun Sep 23 05:42:35 2007 URABE Shyouhei * lib/rdoc/options.rb (Options::check_diagram): dot -V output changed. [ ruby-Bugs-11978 ], Thanks Florian Frank. Sat Sep 22 06:02:11 2007 Nobuyoshi Nakada * lib/optparse.rb (OptionParser::List::summarize): use each_line if defined rather than each. [ruby-Patches-14096] Sat Sep 22 05:19:49 2007 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_init): separate from strio_initialize to share with strio_reopen properly. [ruby-Bugs-13919] Fri Sep 21 15:46:20 2007 Nobuyoshi Nakada * process.c (struct rb_exec_arg): proc should be a VALUE. * process.c (rb_f_exec): suppress a warning. Fri Sep 21 03:05:35 2007 Nobuyoshi Nakada * eval.c, intern.h, ext/thread/thread.c: should not free queue while any live threads are waiting. [ruby-dev:30653] Thu Sep 20 17:24:59 2007 Nobuyoshi Nakada * process.c (rb_detach_process): cast for the platforms where size of pointer differs from size of int. * process.c (rb_f_exec, rb_f_system): should not exceptions after fork. [ruby-core:08262] Fri Sep 14 00:34:25 2007 Masatoshi SEKI * lib/drb/extservm.rb (invoke_service): use Thread.exclusive instead of Thread.critical Wed Sep 12 23:12:22 2007 Yukihiro Matsumoto * ruby.c (proc_options): -W should be allowed in RUBYOPT environment variable. [ruby-core:12118] Mon Sep 10 01:05:25 2007 Yukihiro Matsumoto * range.c (range_step): fixed integer overflow. [ruby-dev:31763] Sun Sep 9 09:14:45 2007 Tadayoshi Funaba * lib/date/format.rb (_strptime): now also attaches an element which denotes leftover substring if exists. Sat Sep 8 10:22:20 2007 Yukihiro Matsumoto * struct.c (rb_struct_s_members): should raise TypeError instead of call rb_bug(). [ruby-dev:31709] * marshal.c (r_object0): no nil check require any more. Sat Sep 8 09:38:19 2007 Tadayoshi Funaba * lib/date/format.rb (str[fp]time): now check specifications more strictly. Fri Sep 7 05:36:19 2007 Masatoshi SEKI * test/rinda/test_rinda.rb (MockClock): correct synchronous problems of the MultiThreading. [ruby-dev:31692] Wed Sep 5 22:02:27 2007 Yukihiro Matsumoto * array.c (rb_ary_subseq): need integer overflow check. [ruby-dev:31736] * array.c (rb_ary_splice): ditto. [ruby-dev:31737] * array.c (rb_ary_fill): ditto. [ruby-dev:31738] * string.c (rb_str_splice): integer overflow for length. [ruby-dev:31739] Sun Sep 2 00:48:15 2007 Tadayoshi Funaba * lib/date/format.rb (_parse): improved parsing of ordinal dates. * lib/date/format.rb (_parse): use named character classes in some regular expressions. Sat Sep 1 08:13:36 2007 Masaki Suketa * ext/win32ole/win32ole.c: add WIN32OLE#ole_activex_initialize. Thu Aug 30 13:13:13 2007 Nobuyoshi Nakada * lib/mkmf.rb (try_const, have_const): check for a const is defined. [ruby-core:04422] Thu Aug 30 13:10:57 2007 Nobuyoshi Nakada * configure.in (group_member): check if presents. * configure.in (XCFLAGS): add _GNU_SOURCE on linux. * file.c (group_member): use system routine if available. Thu Aug 30 08:24:18 2007 Tanaka Akira * ruby.h (RHASH_TBL): defined for compatibility to 1.9. * (RHASH_ITER_LEV): ditto. * (RHASH_IFNONE): ditto. * (RHASH_SIZE): ditto. * (RHASH_EMPTY_P): ditto. Wed Aug 29 13:05:59 2007 Yukihiro Matsumoto * include/ruby/defines.h (flush_register_windows): call "ta 0x03" even on Linux/Sparc. [ruby-dev:31674] Tue Aug 28 23:26:12 2007 Masaki Suketa * ext/win32ole/win32ole.c (ole_type_progid, reg_enum_key, reg_get_val, ole_wc2mb): fix the bug. Thanks, arton. [ruby-dev:31576] Mon Aug 27 19:10:50 2007 Yukihiro Matsumoto * ext/etc/etc.c (etc_getlogin): update documentation to note security issue. [ruby-Bugs-11821] Tue Aug 21 21:09:48 2007 Tanaka Akira * lib/tmpdir.rb (Dir.mktmpdir): make directory suffix specifiable. Tue Aug 21 13:57:04 2007 Nobuyoshi Nakada * hash.c (st_foreach_func, rb_foreach_func): typedefed. Mon Aug 20 17:25:33 2007 Yukihiro Matsumoto * eval.c (mnew): should preserve noex as safe_level. * eval.c (rb_call0): tighten security check condition.. Sat Aug 18 21:32:20 2007 Tanaka Akira * lib/tmpdir.rb (Dir.mktmpdir): new method. [ruby-dev:31462] Sat Aug 18 17:44:42 2007 Nobuyoshi Nakada * ext/tk/tcltklib.c (Init_tcltklib): use rb_set_end_proc(). Sat Aug 18 15:59:52 2007 Nobuyoshi Nakada * process.c (detach_process_watcher): should not pass the pointer to an auto variable to the thread to be created. pointed and fix by KUBO Takehiro [ruby-dev:30618] Sat Aug 18 12:24:30 2007 Nobuyoshi Nakada * sample/test.rb, test/ruby/test_system.rb(valid_syntax?): keep comment lines first. Thu Aug 16 20:40:50 2007 Yukihiro Matsumoto * bignum.c (bigtrunc): RBIGNUM(x)->len may be zero. out of bound access. [ruby-dev:31404] Thu Aug 16 16:46:07 2007 Nobuyoshi Nakada * configure.in (aix): enable shared by default. * configure.in (aix): for 64bit-mode AIX. [ruby-dev:31401] + use CC for LDSHARED if non-gcc, + moved -G option from *LDFLAGS to LDSHARED, + set -brtl only in XLDFLAGS. Thu Aug 16 13:06:08 2007 Tanaka Akira * bignum.c (big_lshift): make shift offset long type. (big_rshift): ditto. (rb_big_lshift): ditto. (big_rshift): ditto. [ruby-dev:31434] Thu Aug 16 04:09:19 2007 Masatoshi SEKI * lib/rinda/tuplespace.rb (Rinda::TupleSpace#start_keeper): improve keeper thread. Wed Aug 15 13:50:10 2007 Nobuyoshi Nakada * hash.c (rb_hash_delete_key): delete the entry without calling block. * hash.c (rb_hash_shift): should consider iter_lev too. * hash.c (delete_if_i): use rb_hash_delete_key() so that the block isn't called twice. [ruby-core:11556] Sun Arg 12 03:56:30 2007 Masatoshi SEKI * lib/rinda/tuplespace.rb: fix Rinda::TupleSpace keeper thread bug. the thread is started too early. [ruby-talk:264062] * test/rinda/test_rinda.rb: ditto. Sat Aug 11 07:34:10 2007 Tadayoshi Funaba * lib/date/format.rb: reverted some wrongly erased "o" options (pointed out by nobu). Tue Aug 7 14:58:39 2007 Nobuyoshi Nakada * ext/pty/pty.c (establishShell): handshaking before close slave device. [ruby-talk:263410] * ext/pty/pty.c (MasterDevice, SlaveDevice, deviceNo): constified. * ext/pty/pty.c (SlaveName): removed static buffer. * ext/pty/expect_sample.rb: support for autologin. Tue Aug 7 12:45:13 2007 Nobuyoshi Nakada * configure.in (ac_cv_func_isinf): set yes also on OpenSolaris. [ruby-Bugs-12859] Mon Aug 6 17:36:29 2007 Nobuyoshi Nakada * lib/rexml/encodings/{ISO-8859-15,CP-1252}.rb: fixed invalid syntax. Fri Aug 3 11:05:54 2007 Nobuyoshi Nakada * ext/extmk.rb (extmake): save all CONFIG values. * ext/extmk.rb (extmake): remove mkmf.log at clean, and extconf.h at distclean, respectively. * ext/extmk.rb: remove rdoc at clean, and installed list file at distclean, respectively. Fri Aug 3 07:09:05 2007 Nobuyoshi Nakada * lib/mkmf.rb: more verbose message. [ruby-Bugs-12766] * lib/mkmf.rb (have_type): suppress a warning with -Wall. * lib/mkmf.rb (find_type): new method. Thu Aug 2 13:46:39 2007 Nobuyoshi Nakada * sprintf.c (rb_f_sprintf): should not check positional number as width. [ruby-core:11838] Mon Jul 30 11:16:40 2007 Nobuyoshi Nakada * bignum.c (rb_big_aref): check for Bignum index range. [ruby-dev:31271] Sat Jul 28 09:35:41 2007 Yukihiro Matsumoto * ext/digest/lib/digest.rb (Digest::self.const_missing): avoid infinite recursive const_missing call. [ruby-talk:262193] Thu Jul 26 13:57:45 2007 Nobuyoshi Nakada * dln.c (load_1, dln_find_1): constified. * dln.c (conv_to_posix_path): removed. * ruby.c (usage): constified. * ruby.c (rubylib_mangled_path, rubylib_mangled_path2): return VALUE instead of a pointer to static buffer. * ruby.c (push_include_cygwin): fixed buffer overflow. [ruby-dev:31297] * ruby.c (ruby_init_loadpath): not convert built-in paths. Sun Jul 22 16:07:12 2007 Nobuyoshi Nakada * intern.h (is_ruby_native_thread): removed since declared as an int function in ruby.h already. Sun Jul 22 14:33:40 2007 Nobuyoshi Nakada * file.c (rb_file_s_rename): deleted code to get rid of a bug of old Cygwin. * file.c (rb_file_truncate): added prototype of GetLastError() on cygwin. [ruby-dev:31239] * intern.h (is_ruby_native_thread): prototype. * missing/strftime.c (strftime): fix printf format and actual arguments. * ext/Win32API/Win32API.c (Win32API_initialize): ditto. * ext/tk/tcltklib.c (ip_finalize): ditto. * ext/dl/ptr.c (rb_dlptr_inspect): ditto. [ruby-dev:31268] * ext/dl/sym.c (rb_dlsym_inspect): ditto. * ext/socket/getnameinfo.c: include stdio.h always. * ext/win32ole/win32ole.c (ole_hresult2msg, folevariable_name, folevariable_ole_type, folevariable_ole_type_detail, folevariable_value, folemethod_visible): missing return value. Sat Jul 21 17:48:26 2007 Nobuyoshi Nakada * lib/mkmf.rb (create_makefile): make OBJS depend on RUBY_EXTCONF_H only if extconf.h is created. * bcc32/{Makefile.sub,configure.bat,setup.mak: configure_args support. * bcc32/setup.mak: check runtime version. * win32/win32.c (rb_w32_open_osfhandle): prototype has changed in bcc 5.82. * {win32,wince,bcc32}/setup.mak (-version-): no RUBY_EXTERN magic. * win32/resource.rb: include patchlevel number. Sat Jul 21 12:06:48 2007 Nobuyoshi Nakada * lib/mkmf.rb (init_mkmf): should remove mkmf.log too. Sat Jul 21 01:53:17 2007 Tadayoshi Funaba * lib/date/format.rb (Date._parse): completes calendar week based year. * lib/date/format.rb (Date._parse): detects year of ordinal date in extended format. Fri Jul 20 15:22:51 2007 Nobuyoshi Nakada * ext/openssl/ossl_config.c (ossl_config_set_section): do not initialize aggregations with dynamic values. [ruby-talk:259306] Thu Jul 19 19:24:14 2007 Nobuyoshi Nakada * eval.c (get_backtrace): check the result more. [ruby-dev:31261] [ruby-bugs-12398] Thu Jul 19 14:38:45 2007 Nobuyoshi Nakada * bignum.c (rb_big_lshift, rb_big_rshift): separated functions to get rid of infinite recursion. fixed calculation in edge cases. [ruby-dev:31244] * numeric.c (rb_fix_lshift, rb_fix_rshift): ditto. Wed Jul 18 16:57:41 2007 Nobuyoshi Nakada * bignum.c (rb_big_pow): refine overflow check. [ruby-dev:31242] Wed Jul 18 08:47:09 2007 Yukihiro Matsumoto * time.c (time_succ): Time#succ should return a time object in the same timezone mode to the original. [ruby-talk:260256] Tue Jul 17 00:50:53 2007 Yukihiro Matsumoto * numeric.c (fix_pow): integer power calculation: 0**n => 0, 1**n => 1, -1**n => 1 (n: even) / -1 (n: odd). * test/ruby/test_fixnum.rb (TestFixnum::test_pow): update test suite. pow(-3, 2^64) gives NaN when pow(3, 2^64) gives Inf. Mon Jul 16 23:07:51 2007 Yukihiro Matsumoto * lib/base64.rb (Base64::b64encode): should not specify /o option for regular expression. [ruby-dev:31221] Mon Jul 16 18:29:33 2007 Nobuyoshi Nakada * string.c (rb_str_rindex_m): accept string-like object convertible with #to_str method, as well as rb_str_index_m. [ruby-core:11692] Mon Jul 16 05:45:53 2007 Nobuyoshi Nakada * sprintf.c (rb_f_sprintf): more checks for format argument. [ruby-core:11569], [ruby-core:11570], [ruby-core:11571], [ruby-core:11573] Mon Jul 16 00:26:10 2007 Nobuyoshi Nakada * bignum.c (rb_big_pow): removed invariant variable. [ruby-dev:31236] Sun Jul 15 23:59:57 2007 Nobuyoshi Nakada * bignum.c (rb_big_neg): SIGNED_VALUE isn't in 1.8. Sun Jul 15 22:24:49 2007 pegacorn * ext/digest/digest.c (rb_digest_instance_update, rb_digest_instance_finish, rb_digest_instance_reset, rb_digest_instance_block_length): %s in rb_raise() expects char*. [ruby-dev:31222] * ext/openssl/ossl.h: include ossl_pkcs5.h. [ruby-dev:31231] * ext/openssl/ossl_pkcs5.h: new file for PKCS5. [ruby-dev:31231] * ext/openssl/ossl_x509name.c (ossl_x509name_to_s): use ossl_raise() instead of rb_raise(). [ruby-dev:31222] * ext/sdbm/_sdbm.c: DOSISH platforms need io.h. [ruby-dev:31232] * ext/syck/syck.h: include stdlib.h for malloc() and free(). [ruby-dev:31232] * ext/syck/syck.h (syck_parser_set_input_type): prototype added. [ruby-dev:31231] * win32/win32.c: include mbstring.h for _mbspbrk(). [ruby-dev:31232] * win32.h (rb_w32_getcwd): prototype added. [ruby-dev:31232] Sun Jul 15 21:07:43 2007 Nobuyoshi Nakada * bignum.c (bigtrunc): do not empty Bignum. [ruby-dev:31229] Sun Jul 15 19:05:28 2007 Nobuyoshi Nakada * bignum.c (rb_cstr_to_inum): check leading non-digits. [ruby-core:11691] Sun Jul 15 04:42:20 2007 Nobuyoshi Nakada * bignum.c (get2comp): do nothing for empty Bignum. [ruby-dev:31225] Sat Jul 14 14:04:06 2007 Nobuyoshi Nakada * enum.c (sort_by_cmp): check if reentered. [ruby-dev:24291] Sat Jul 14 12:44:14 2007 NAKAMURA, Hiroshi * test/openssl/test_pkcs7.rb: reverted the previous patch. it should be as it was to check interface compatibility. sorry for bothering with this. Sat Jul 14 12:16:17 2007 NAKAMURA, Hiroshi * test/openssl/test_pkcs7.rb: follow the library change. applied a patch from [ruby-dev:31214]. NOTE: r12496 imports the latest openssl libs from trunk to ruby_1_8 though its's not ChangeLog-ed. maintainer should aware that. Sat Jul 14 02:51:52 2007 Yukihiro Matsumoto * numeric.c (fix_pow): 0**2 should not raise floating point exception. [ruby-dev:31216] Sat Jul 14 02:25:48 2007 Yukihiro Matsumoto * numeric.c (int_pow): wrong overflow detection. [ruby-dev:31213] * numeric.c (int_pow): wrong overflow detection. [ruby-dev:31215] Fri Jul 13 16:10:00 2007 Tanaka Akira * lib/open-uri.rb (URI::Generic#find_proxy): use ENV.to_hash to access http_proxy environment variable to avoid case insensitive environment search. Fri Jul 13 15:02:15 2007 Nobuyoshi Nakada * win32/win32.c (CreateChild): enclose command line except for command.com which can not handle quotes. [ruby-talk:258939] Fri Jul 13 10:10:46 2007 Nobuyoshi Nakada * lib/mkmf.rb (link_command, cc_command, cpp_command): do not expand ::CONFIG which is an alias of MAKEFILE_CONFIG. Thu Jul 12 17:03:15 2007 Nobuyoshi Nakada * struct.c (rb_struct_init_copy): disallow changing the size. [ruby-dev:31168] Wed Jul 11 23:38:14 2007 NAKAMURA, Hiroshi * random.c: documentation fix. srand(0) initializes PRNG with '0', not with random_seed. Tue Jul 10 14:50:01 2007 Nobuyoshi Nakada * bcc32/{Makefile.sub,setup.mak}: remove surplus slash from srcdir. Fri Jul 6 15:22:58 2007 Nobuyoshi Nakada * eval.c (rb_interrupt): suppress a gcc's officious warning. Thu Jul 5 16:44:28 2007 NAKAMURA Usaku * numeric.c (int_pow): fix previous nubu's commit. * test/ruby/test_fixnum.rb: new test. Thu Jul 5 15:56:06 2007 Nobuyoshi Nakada * numeric.c (int_pow): even number multiplication never be negative. Mon Jul 2 14:34:43 2007 Nobuyoshi Nakada * sprintf.c (rb_f_sprintf): sign bit extension should not be done if FPLUS flag is specified. [ruby-list:39224] Sat Jun 30 16:05:41 2007 Yukihiro Matsumoto * array.c (rb_ary_initialize): should call rb_ary_modify() first. [ruby-core:11562] Sat Jun 30 00:17:00 2007 Nobuyoshi Nakada * parse.y (yylex): return non-valid token for an invalid instance/class variable name. a patch from Yusuke ENDOH . [ruby-dev:31095] Fri Jun 29 11:23:09 2007 Nobuyoshi Nakada * parse.y (dsym): return non-null NODE even if yyerror(). based on a patch from Yusuke ENDOH . [ruby-dev:31085] Tue Jun 26 16:35:21 2007 Nobuyoshi Nakada * process.c (ruby_setreuid, ruby_setregid): rename to get rid of name clash. * process.c (proc_exec_v, rb_proc_exec): preserve errno. Sat Jun 23 00:37:46 2007 Yukihiro Matsumoto * hash.c (rb_hash_select): remove unnecessary varargs for rb_hash_select. a patch from Daniel Berger . [ruby-core:11527] * hash.c: ditto. Mon Jun 18 08:47:54 2007 Technorama Ltd. * ext/openssl/{extconf.rb,ossl_ssl_session.c}: Fix ruby-Bugs-11513. * ext/openssl/ossl_pkey_ec.c New methods EC::Point.[eql,make_affine!,invert!,on_curve?,infinity?] By default output the same key form as the openssl command. * ext/openssl/ossl_rand.c New method Random.status? Mon Jun 18 13:54:36 2007 Nobuyoshi Nakada * eval.c (ruby_cleanup): return EXIT_FAILURE if any exceptions occured in at_exit blocks. [ruby-core:11263] Mon Jun 18 01:14:10 2007 Nobuyoshi Nakada * variable.c (rb_path2class): get rid of dangling pointer caused by optimized out value. * variable.c (rb_global_entry, rb_f_untrace_var, rb_alias_variable, rb_generic_ivar_table, generic_ivar_get, generic_ivar_set, generic_ivar_defined, generic_ivar_remove, rb_mark_generic_ivar, rb_free_generic_ivar, rb_copy_generic_ivar, rb_obj_instance_variables): suppress warnings. Fri Jun 15 22:33:29 2007 Nobuyoshi Nakada * common.mk (realclean): separate local and ext. * ext/extmk.rb: not remove unrelated directories. Fri Jun 15 17:01:20 2007 NAKAMURA Usaku * ext/dl/lib/dl/win32.rb: seems that dl doesn't accept void argument. fixed [ruby-bugs:PR#5489]. Thu Jun 14 17:09:48 2007 Nobuyoshi Nakada * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser): handle more extensions. [ruby-dev:30972] Wed Jun 13 06:05:12 2007 Nobuyoshi Nakada * configure.in (darwin): prohibit loading extension libraries to miniruby. Wed Jun 13 05:47:58 2007 Nobuyoshi Nakada * eval.c (rb_kill_thread): renamed in order to get rid of conflict with a BeOS system function. [ruby-core:10830] Tue Jun 12 14:53:51 2007 Nobuyoshi Nakada * lib/mkmf.rb (Logging.quiet, Logging.message): added quiet flag and use it. [ruby-core:10909] * lib/mkmf.rb (find_header): use header names in the message. Sun Jun 10 13:47:36 2007 Nobuyoshi Nakada * test/ruby/test_beginendblock.rb (test_should_propagate_signaled): get rid of invoking shell. [ruby-dev:30942] Thu Jun 7 19:02:48 2007 Tanaka Akira * lib/pp.rb: call original "method" method instead of redefined one. Mon Jun 4 11:11:12 2007 Shugo Maeda * lib/net/imap.rb (ResponseParser#next_token): fixed error message. (backported from HEAD) * lib/net/imap.rb (ResponseParser#parse_error): fixed the condition not to refer @token.symbol unexpectedly. Thanks, Dick Monahan. (backported from HEAD) Thu May 31 17:27:53 2007 Nobuyoshi Nakada * lib/benchmark.rb (Benchmark::Job::item): avoid modifying the argument unintentionally. [ruby-talk:253676] Thu May 31 02:12:32 2007 Masatoshi SEKI * lib/rinda/tuplespace.rb (Rinda::TupleBag): create index on tuple bag by first column. Wed May 30 13:27:40 2007 Shugo Maeda * lib/net/ftp.rb (Net::FTP#transfercmd): skip 2XX responses for some FTP servers. (backported from HEAD) Wed May 30 05:17:55 2007 Nobuyoshi Nakada * eval.c (rb_eval): get rid of SEGV at ZSUPER in a block [ruby-dev:30836] Wed May 30 04:29:43 2007 Nobuyoshi Nakada * eval.c (thread_timer): timer thread should not receive any signals. submitted by Sylvain Joyeux. [ruby-core:08546] Wed May 30 04:18:37 2007 Nobuyoshi Nakada * eval.c (rb_eval_cmd): just return if no exceptions. [ruby-dev:30820] Tue May 29 11:01:06 2007 Nobuyoshi Nakada * win32/win32.c (rb_w32_opendir): store attributes of the second entries or later too. * win32/win32.c (rb_w32_opendir, rb_w32_readdir): eliminate magic numbers. Mon May 28 02:54:05 2007 Masatoshi SEKI * lib/rinda/tuplespace.rb (Rinda::TupleBag#delete): use rindex and delete_at instead of delete for little improvement. Sat May 26 00:05:22 2007 Nobuyoshi Nakada * test/ruby/test_beginendblock.rb (test_should_propagate_signaled): skip tests for exitstatus and termsig on the platforms where signals not supported. Wed May 23 06:51:46 2007 URABE Shyouhei * lib/cgi.rb (CGI#[]): get rid of exceptions being raised. [ruby-dev:30740], Thanks Kentaro KAWAMOTO. Wed May 23 05:49:49 2007 Nobuyoshi Nakada * ext/extmk.rb, ext/purelib.rb, lib/mkmf.rb, runruby.rb: clear default load path to get rid of load pre-installed extensions/libraries. [ruby-core:11017] Sat May 19 10:29:18 2007 Tadayoshi Funaba * lib/date/format.rb (Date._parse): detects some OFX dates (Of course not fully). Fri May 18 23:07:33 2007 Yukihiro Matsumoto * array.c (rb_ary_first): call rb_ary_subseq() instead of pushing values by itself. [ruby-talk:252062] * array.c (rb_ary_first): add negative length check. Fri May 18 17:10:31 2007 Nobuyoshi Nakada * win32/win32.c (move_to_next_entry): loc also must move forward. [ruby-talk:251987] Fri May 18 03:02:40 2007 Nobuyoshi Nakada * win32/mkexports.rb: preserve prefixed underscores for WINAPI symbols. * wince/mkconfig_wce.rb, wince/mkexports.rb: obsolete. Thu May 17 17:03:11 2007 Nobuyoshi Nakada * misc/ruby-style.el (ruby-style-label-indent): for yacc rules. Tue May 15 14:54:07 2007 NAKAMURA Usaku * win32/win32.c (init_stdhandle): stderr should be without buffering, but mswin32 use buffering when stderr is not connected to tty. Mon May 14 13:28:03 2007 Nobuyoshi Nakada * ext/thread/thread.c (wait_list): supress a warning. Thu May 10 15:21:51 2007 NAKAMURA Usaku * ext/iconv/iconv.c (iconv_s_conv): rdoc fix. Thu May 10 10:14:14 2007 Nobuyoshi Nakada * eval.c (rb_thread_priority): rdoc fix; the initial value is inherited from the creating thread. [ruby-core:10607] Wed May 9 12:28:57 2007 Nobuyoshi Nakada * bignum.c (Init_Bignum), numeric.c (Init_Numeric): added fdiv as aliases of quo. [ruby-dev:30771] Wed May 9 11:55:15 2007 Nobuyoshi Nakada * bignum.c (rb_big_quo): now calculate in integer. [ruby-dev:30753] Wed May 9 11:51:06 2007 Nobuyoshi Nakada * bignum.c (rb_big_pow): reduce multiplying for even number. * bignum.c (rb_big_pow): truncate all zero BDIGITs. [ruby-dev:30733] * bignum.c (rb_big_pow): improvement by calculating from MSB and using factorization. * numeric.c (int_pow): calculate power in Fixnum as possible. [ruby-dev:30726] Tue May 8 23:42:51 2007 Tadayoshi Funaba * lib/date/format.rb (Date._parse): revised treatment of hyphened/separatorless dates. * lib/date/format.rb: some trivial adjustments. Tue May 8 20:25:05 2007 Tadayoshi Funaba * lib/date/format.rb: reverted. Sat May 5 16:26:33 2007 Nobuyoshi Nakada * lib/date/format.rb (Format::Bag#method_missing): get rid of modifying orginal argument. [ruby-core:11090] Mon Apr 30 01:17:51 2007 Masatoshi SEKI * lib/rinda/tuplespace.rb (TupleSpace#create_entry, TupleBag#push, delete): extract method, and rename parameter. Fri Apr 27 02:00:17 2007 Ryan Davis * signal.c: Fixed backwards compatibility for 'raise Interrupt'. * lib/yaml/tag.rb: Running rdoc over the 1.8.6 tree skips Module. Patch from James Britt Thu Apr 26 13:54:51 2007 Nobuyoshi Nakada * misc/ruby-style.el: new file. C/C++ style for ruby source code. Wed Apr 25 19:49:16 2007 Tanaka Akira * ext/socket/socket.c (unix_send_io, unix_recv_io): use CMSG_DATA to align file descriptor appropriately. Tue Apr 24 09:33:57 2007 Nobuyoshi Nakada * dir.c (do_stat, do_lstat, do_opendir): should not warn ENOTDIR. [ruby-talk:248288] Mon Apr 23 22:14:42 2007 Nobuyoshi Nakada * ext/extmk.rb ($ruby): add extout directory to include path. [ruby-core:11003] * lib/mkmf.rb (libpathflag): not to append RPATHFLAG to current directory. * lib/mkmf.rb (init_mkmf): add current directory to default library path with highest priority. [ruby-core:10960] * lib/mkmf.rb (LINK_SO): LIBPATH to be placed before DLDFLAGS. Fri Apr 20 16:05:22 2007 Nobuyoshi Nakada * configure.in (LIBPATHFLAG, RPATHFLAG): no needs to be quoted, it is done by libpathflag in mkmf.rb. Fri Apr 20 12:27:04 2007 Nobuyoshi Nakada * lib/optparse.rb: fix to override conv proc. Fri Apr 20 12:17:05 2007 Nobuyoshi Nakada * eval.c (ruby_cleanup): inversed the order of errinfos. Thu Apr 19 14:53:32 2007 Nobuyoshi Nakada * lib/monitor.rb (ConditionVariable#wait, mon_enter, mon_exit_for_cond): ensures Thread.critical to be false. [ruby-talk:248300] Wed Apr 18 10:41:21 2007 Nobuyoshi Nakada * util.c (ruby_strtod): exponent is radix 10. [ruby-talk:248272] Wed Apr 18 02:30:24 2007 Nobuyoshi Nakada * configure.in (LDFLAGS): prepend -L. instead appending it to XLDFLAGS. [ruby-core:10933] * configure.in (Makefile): remove $U for automake from MISSING. [ruby-talk:248171] Tue Apr 17 16:46:46 2007 Yukihiro Matsumoto * eval.c (rb_yield_0): should not clear state on TAG_NEXT when it's invoked from within lambda body. [ruby-talk:248136] * eval.c (proc_invoke): handle TAG_NEXT which would be caused by next in the lambda body as well. Mon Apr 16 22:56:01 2007 Yukihiro Matsumoto * ext/pty/expect_sample.rb: avoid symbolic link representation for expect. a patch from Kazuhiro NISHIYAMA . [ruby-dev:30714] Mon Apr 16 22:51:11 2007 Yukihiro Matsumoto * sample: replace TRUE, FALSE with true, false respectively. a patch from Kazuhiro NISHIYAMA . [ruby-dev:30713] Mon Apr 16 17:08:02 2007 Nobuyoshi Nakada * lib/optparse.rb (make_switch): do not clobber converter if pattern has no convert method. reported by sheepman in [ruby-dev:30709]. Mon Apr 16 16:49:32 2007 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_seek): consistent behavior with IO#seek. patch by sheepman in [ruby-dev:30710]. Mon Apr 16 16:34:08 2007 Yukihiro Matsumoto * parse.y (parser_yylex): should set command_start after block starting "do"s and braces. [ruby-core:10916] Sun Apr 15 09:19:57 2007 Tadayoshi Funaba * lib/date/format.rb: added some zone names. * lib/date/format.rb (_parse): now interprets doted numerical dates as a big endian (except dd.mm.yyyy). Tue Apr 10 17:37:36 2007 NAKAMURA Usaku * win32/win32.c (rb_w32_fclose, rb_w32_close): need to save errno before calling original fclose()/close(). Mon Apr 9 09:30:44 2007 Shugo Maeda * lib/net/imap.rb (disconnect): call shutdown for SSLSocket. Thanks, Technorama Ltd. Thu Apr 5 00:42:48 2007 Nobuyoshi Nakada * error.c (rb_notimplement), io.c (pipe_open): removed definite articles and UNIX manual section from messages. [ruby-dev:30690] Wed Apr 4 17:09:17 2007 Nobuyoshi Nakada * io.c (pipe_open): refined the message of NotImplementedError. [ruby-dev:30685] Wed Apr 4 10:18:04 2007 Nobuyoshi Nakada * io.c (pipe_open): raise NotImplementedError for command "-" on platforms where fork(2) is not available. [ruby-dev:30681] Tue Apr 3 15:45:41 2007 NAKAMURA Usaku * ext/socket/socket.c (s_recv, s_recvfrom): some systems (such as windows) doesn't set fromlen if the socket is connection-oriented. reported by Bram Whillock in [ruby-core:10512] [ruby-Bugs#9061] Sat Mar 24 23:40:29 2007 Nobuyoshi Nakada * node.h (struct rb_thread.locals): explicit as struct. [ruby-core:10585] * eval.c, node.h (enum rb_thread_status, struct rb_thread, rb_curr_thread, rb_main_thread): prefixed. [ruby-core:10586] * file.c (chompdirsep): made an unprefixed name static. * io.c (io_fread): ditto. Sat Mar 24 01:54:03 2007 Nobuyoshi Nakada * eval.c (ruby_cleanup): exit by SystemExit and SignalException in END block. [ruby-core:10609] * test/ruby/test_beginendblock.rb (test_should_propagate_exit_code): test for exit in END block. [ruby-core:10760] * test/ruby/test_beginendblock.rb (test_should_propagate_signaled): test for signal in END block. Thu Mar 22 23:13:17 2007 Nobuyoshi Nakada * eval.c (rb_provided): check for extension library if SOEXT is explicitly given. [ruby-dev:30657] Thu Mar 22 10:29:25 2007 NAKAMURA Usaku * test/ruby/test_bignum.rb (test_to_s): add tests for Bignum#to_s. Wed Mar 21 17:04:30 2007 Nobuyoshi Nakada * bignum.c (rb_big2str0): round up for the most significant digit. [ruby-core:10686] Wed Mar 21 07:21:24 2007 Akinori MUSHA * ext/thread/thread.c (remove_one): Preserve List invariants; submitted by: MenTaLguY in [ruby-core:10598] and [ruby-bugs:PR#9388]. Tue Mar 20 22:54:50 2007 Yukihiro Matsumoto * marshal.c (w_extended): erroneous check condition when dump method is defined. [ruby-core:10646] Tue Mar 20 15:37:24 2007 URABE Shyouhei * distruby.rb: Add zip generation. Tue Mar 20 11:28:41 2007 Akinori MUSHA * lib/matrix.rb (Matrix::inverse_from): adding partial pivoting to the Gauss-Jordan algorithm, making it stable. a patch from Peter Vanbroekhoven. [ruby-core:10641] Mon Mar 19 11:39:29 2007 Minero Aoki * lib/net/protocol.rb (rbuf_read): extend buffer size for speed. Sun Mar 18 04:23:52 2007 Akinori MUSHA * NEWS: Add a note about the new `date' library defining Time#to_date and Time#to_datetime private methods. * NEWS: Inform that the old `thread' library is considered to be stable. * NEWS: Sort library entries in alphabetical order. Fri Mar 16 21:48:11 2007 Akinori MUSHA * ext/dl/dl.c (rb_ary2cary): Fix a bug in type validation; submitted by sheepman in [ruby-dev:30554]. Fri Mar 16 18:28:06 2007 Akinori MUSHA * ext/etc/etc.c (etc_getgrgid): Fix a bug in Etc::getgrgid() always returning the (real) group entry of the running process; reported by: UEDA Hiroyuki in [ruby-dev:30586]. Fri Mar 16 16:33:58 2007 Akinori MUSHA * ext/thread/thread.c (unlock_mutex_inner): Make sure that the given mutex is actually owned by the caller; submitted by: Sylvain Joyeux in [ruby-core:10598]. Fri Mar 16 16:21:35 2007 Akinori MUSHA * ext/thread/thread.c (wait_condvar, lock_mutex): Fix a problem in ConditionVariable#wait that occurs when two threads that are trying to access the condition variable are also in concurrence for the given mutex; submitted by: Sylvain Joyeux and MenTaLguY in [ruby-core:10598]. Fri Mar 16 16:17:27 2007 Akinori MUSHA * test/thread/test_thread.rb: Add a test script for the `thread' library. This should result in failure as of now with ext/thread; submitted by: Sylvain Joyeux in [ruby-core:10598]. Wed Mar 14 12:30:00 2007 Shigeo Kobayashi * ext/bigdecimal/bigdecimal.c: BigDecimal("-.31") is now treated as ("-0.31") not as ("0.31"). Tue Mar 13 09:25:10 2007 Nobuyoshi Nakada * common.mk (clear-installed-list): separated from install-prereq. Tue Mar 13 06:38:43 2007 Akinori MUSHA * NEWS: Reword and improve entries. Tue Mar 13 06:03:46 2007 Akinori MUSHA * stable version 1.8.6 released from the ruby_1_8_6 branch. Tue Mar 13 03:24:07 2007 Nobuyoshi Nakada * runruby.rb: added --pure (turned on by default) and --debugger options. Tue Mar 13 02:50:28 2007 Akinori MUSHA * lib/cgi.rb (CGI::header): IIS >= 5.0 does not need the nph assumption any more; submitted by MIYASAKA Masaru in [ruby-dev:30537]. Mon Mar 12 11:07:44 2007 Akinori MUSHA * ext/openssl/ossl_asn1.c (Init_ossl_asn1): Let rdoc know about externally defined modules; submitted by Technorama Ltd. in [ruby-bugs:PR#4704]. * ext/openssl/ossl_bn.c (Init_ossl_bn): Ditto. * ext/openssl/ossl_cipher.c (Init_ossl_cipher): Ditto. * ext/openssl/ossl_digest.c (Init_ossl_digest): Ditto. * ext/openssl/ossl_hmac.c (Init_ossl_hmac): Ditto. * ext/openssl/ossl_pkey.c (Init_ossl_pkey): Ditto. * ext/openssl/ossl_pkey_dh.c (Init_ossl_dh): Ditto. * ext/openssl/ossl_pkey_dsa.c (Init_ossl_dsa): Ditto. * ext/openssl/ossl_pkey_rsa.c (Init_ossl_rsa): Ditto. * ext/openssl/ossl_rand.c (Init_ossl_rand): Ditto. * ext/openssl/ossl_ssl.c (Init_ossl_ssl): Ditto. Mon Mar 12 01:05:17 2007 Akinori MUSHA * ext/dl/sym.c (rb_dlsym_inspect): Use "0x%x" rather for pointers. This might not be very right but it is commonly used in other parts of the code; submitted by sheepman in [ruby-dev:30532]. * ext/dl/ptr.c (rb_dlptr_inspect): Ditto. Mon Mar 12 00:59:19 2007 Akinori MUSHA * ext/dl/lib/dl/import.rb (DL::Importable::Internal::import, DL::Importable::Internal::callback): Avoid race condition for an instance variable; submitted by sheepman in [ruby-dev:30530]. Sun Mar 11 18:57:50 2007 Akinori MUSHA * misc/README: Add a note about ruby-electric.el. * misc/ruby-mode.el (ruby-non-block-do-re): Fix ruby-non-block-do-re. [ruby-core:03719] * misc/inf-ruby.el: Synchronize the comment section with trunk. * misc/README, misc/rdebug.el: Add rdebug.el, Emacs ruby-debug interface based on rubydb3x.el; submitted by Martin Nordholts in [ruby-bugs:PR#9023]. Sun Mar 11 17:45:51 2007 Akinori MUSHA * ext/dl/mkcallback.rb (mkfunc): Make sure that a callback function is found in the function table before trying to call it; submitted by sheepman in [ruby-dev:30524]. Sun Mar 11 12:09:37 2007 Nobuyoshi Nakada * eval.c (error_handle): no message when exiting by signal. * eval.c (ruby_cleanup): re-send signal. [ruby-dev:30516] * eval.c (rb_thread_interrupt): instantiate SignalException. * eval.c (rb_thread_signal_raise): now takes signal number instead of signal name. * intern.h (rb_thread_signal_raise, ruby_default_signal): prototypes. * signal.c (esignal_init): takes a signal number and an optional signal name. * signal.c (interrupt_init): pass SIGINT always. * signal.c (ruby_default_signal): invoke system default signal handler. * signal.c (rb_signal_exec, trap): handle SIGTERM. [ruby-dev:30505] Tue Mar 6 19:08:46 2007 Akinori MUSHA * ext/digest/lib/md5.rb (MD5::new, MD5::md5): Do not modify Digest::MD5. * ext/digest/lib/sha1.rb (SHA1::new, SHA1::sha1): Ditto. Tue Mar 6 18:58:37 2007 Keiju Ishitsuka * lib/shell/process-controller.rb: fix thread synchronization problem for [ruby-dev:30477]. Tue Mar 6 18:44:26 2007 Akinori MUSHA * ext/digest/lib/md5.rb (MD5::new, MD5::md5): Catch up with Digest's API changes; noted by: Kazuhiro Yoshida in [ruby-dev:30500]. * ext/digest/lib/sha1.rb (SHA1::new, SHA1::sha1): Ditto. Tue Mar 6 18:24:19 2007 Akinori MUSHA * time.c (time_to_s): Back out the format changes; discussed in [ruby-dev:30495]. Tue Mar 6 11:53:25 2007 Hidetoshi NAGAI * ext/tk/sample/irbtkw.rbw: fails to exit process. Mon Mar 5 20:14:49 2007 Akinori MUSHA * time.c (time_to_s): Correct the wrong format which did not really conform to RFC 2822; pointed out by: OHARA Shigeki in [ruby-dev:30487]. Sun Mar 4 23:38:07 2007 Nobuyoshi Nakada * file.c (rb_stat_s_utime): fixed a commit miss for the platforms where utimes() does not exist. * lib/fileutils.rb (touch): ditto. Sun Mar 4 14:46:56 2007 WATANABE Hirofumi * util.c (push_element): should return a int value. Sun Mar 4 01:05:57 2007 Akinori MUSHA * lib/set.rb (Set#^, Set#&): Correct documentation. Those methods return sets, not arrays; noted by Oliver Frank Wittich . Sat Mar 3 23:01:07 2007 Minero Aoki * lib/fileutils.rb (mv): could not move a directory between different filesystems. [ruby-dev:30411] Sat Mar 3 22:57:11 2007 Minero Aoki * lib/fileutils.rb (touch): last commit causes error if :mtime option was not given. Sat Mar 3 22:37:02 2007 Nobuyoshi Nakada * file.c (rb_file_s_utime): allow nil to set the current time. * lib/fileutils.rb (touch): ditto, and added :mtime and :nocreate options. fixed: [ruby-talk:219037] Sat Mar 3 21:17:35 2007 Akinori MUSHA * eval.c (stack_check): Unset inline to fix build with GCC 3.4.6; submitted by: NISHIMATSU Takeshi in [ruby-list:43218]. cf. http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24556 Sat Mar 3 19:05:31 2007 Akinori MUSHA * ext/thread/thread.c (push_list): Use ALLOC(). * ext/thread/thread.c (rb_mutex_alloc): Ditto. * ext/thread/thread.c (rb_condvar_alloc): Ditto. Sat Mar 3 18:53:11 2007 Akinori MUSHA * NEWS: Add a note for String#intern. Sat Mar 3 16:23:13 2007 Akinori MUSHA * env.h (SCOPE_CLONE): Introduce a new scope flag to prevent a local_tbl region from getting freed many times; submitted by Chikanaga Tomoyuki in [ruby-dev:30460]. * eval.c (proc_invoke): Ditto. * gc.c (obj_free): Ditto. * parse.y (top_local_setup_gen): Ditto. Sat Mar 3 16:07:02 2007 Akinori MUSHA * object.c (rb_obj_ivar_set): RDoc updated according to a suggestion from Brian Candler . [ruby-core:10469] Thu Mar 1 21:38:07 2007 Nobuyoshi Nakada * parse.y (stmt, arg): should not omit lhs of OP_ASGN1 even if empty. [ruby-dev:30455] Thu Mar 1 08:55:38 2007 Nobuyoshi Nakada * eval.c (rb_feature_p): check loading_tbl if the given ext is empty. [ruby-dev:30452] * eval.c (rb_feature_p): fix possible buffer overrun. Thu Mar 1 03:30:21 2007 Akinori MUSHA * ext/digest/digest.c (get_digest_base_metadata): Allow inheriting Digest::Base subclasses, which was unintentionally made impossible while restructuring Digest classes. Thu Mar 1 02:05:17 2007 Nobuyoshi Nakada * mkconfig.rb (patchlevel): read from version.h. Thu Mar 1 00:09:39 2007 Nobuyoshi Nakada * eval.c (rb_provided): return true only for features loaded from .rb files, and not search actual library type. [ruby-dev:30414] Wed Feb 28 21:15:00 2007 WATANABE Hirofumi * configure.in (ac_cv_func_fcntl): fcntl support for MinGW. * missing/flock.c: workaround for MinGW. Wed Feb 28 20:51:32 2007 URABE Shyouhei * pack.c (pack_unpack): properly ignore non-base64 octets such as UTF-8 encoded BOMs; submitted by SOUMA Yutaka to fix [ruby-core:10437] Wed Feb 28 18:59:57 2007 Akinori MUSHA * NEWS: Add NEWS, a document file to keep user visible feature changes between releases. Wed Feb 28 18:35:50 2007 NAKAMURA Usaku * ext/openssl/extconf.rb: no need to check unistd.h and sys/time.h. they are already checked at configure. reported by KOBAYASHI Yasuhiro [ruby-list:43225] Wed Feb 28 18:34:48 2007 NAKAMURA Usaku * lib/mkmf.rb ($DEFLIBPATH): default library paths ($(topdir), etc) should be the first elements of library paths list. reported by KOBAYASHI Yasuhiro [ruby-list:43225] Wed Feb 28 18:31:32 2007 Akinori MUSHA * doc/NEWS-1.8.0: Rename NEWS to NEWS-1.8.0. This is way too old NEWS. Wed Feb 28 01:22:58 2007 NAKAMURA Usaku * test/{dbm,gdbm}/test_{dbm,gdbm}.rb: shouldn't use host_os. use target_os instead. reported by KOBAYASHI Yasuhiro [ruby-list:43225] Wed Feb 28 00:08:11 2007 URABE Shyouhei * mkconfig.rb (RbConfig): add CONFIG['PATCHLEVEL'] * common.mk: new target dist * distruby.rb: new file Tue Feb 27 22:18:45 2007 WATANABE Hirofumi * configure.in (--enable-auto-image-base): avoid the neccessity to rebase the shared libs as much as possible; submitted by Corinna Vinschen in [ruby-talk:240964]. Tue Feb 27 21:36:47 2007 WATANABE Hirofumi * util.c (__crt0_glob_function): use ruby_glob() instead of rb_globi(). Tue Feb 27 21:33:04 2007 WATANABE Hirofumi * configure.in (ac_cv_func_setrlimit): workaround for djgpp. Tue Feb 27 19:38:52 2007 Akinori MUSHA * lib/base64.rb (Base64::b64encode): Fix documentation; submitted by David Symonds in [ruby-core:10432]. Tue Feb 27 19:36:57 2007 Akinori MUSHA * regex.c (calculate_must_string, slow_search, re_search): Silence warnings regarding char * vs. unsigned char * mismatch; submitted by Lyle Johnson in [ruby-core:10416]. * ext/bigdecimal/bigdecimal.c (BigDecimal_load): Ditto. * ext/digest/sha1/sha1ossl.c (SHA1_Finish): Ditto. * ext/digest/rmd160/rmd160ossl.c (RMD160_Finish): Ditto. * ext/digest/digest.c (rb_digest_base_finish, rb_digest_base_update): Ditto. * ext/nkf/nkf.c (rb_str_resize, rb_nkf_kconv, rb_nkf_guess1, rb_nkf_guess2): Ditto. Tue Feb 27 03:40:09 2007 Akinori MUSHA * ext/thread/thread.c (wait_list_cleanup, rb_mutex_try_lock): Eliminate rb_thread_critical switching where unnecessary; implied by shugo in [ruby-dev:30412]. * ext/thread/thread.c (set_critical): Merge in thread_exclusive_ensure(). * ext/thread/thread.c: Consistently use 0 and 1 for rb_thread_critical values. Mon Feb 26 15:18:23 2007 Akinori MUSHA * ext/thread/thread.c: Use xmalloc()/xfree() instead of malloc()/free(); pointed out by shugo in [ruby-dev:30412]. Sun Feb 25 23:02:55 2007 Akinori MUSHA * lib/test/unit/autorunner.rb (Test::Unit::AutoRunner::initialize): Initialize @workdir properly to silence a warning under -w. Submitted by in [ruby-dev:30400]. Sun Feb 25 02:47:43 2007 Akinori MUSHA * defines.h: Pull the RUBY_MBCHAR_MAXSIZE definition from trunk, which is necessary for dir.c to compile on djgpp and emx. Sat Feb 24 10:42:01 2007 Minero Aoki * ext/racc/cparse/cparse.c (cparse_params_mark): remove useless rb_gc_mark. Thanks Tomoyuki Chikanaga. [ruby-dev:30405] Fri Feb 23 15:10:46 2007 NAKAMURA Usaku * win32/win32.c (set_pioinfo_extra): new function for VC++8 SP1 workaround. [ruby-core:10259] * win32/win32.c (NtInitialize): call above function. Fri Feb 23 14:19:40 2007 NAKAMURA Usaku * signal.c (sighandler): need to tell to be interrupted to main context when handler is installed. * win32/win32.[ch] (rb_win32_interrupted): new function to listen interrupt. Fri Feb 23 13:02:17 2007 Akinori MUSHA * numeric.c (fix_cmp, fix_equal): Remove FIX2LONG() to optimize. suggested in http://t-a-w.blogspot.com/2007/02/making-ruby-faster.html. [ruby-talk:240223] Fri Feb 23 12:43:17 2007 James Edward Gray II * lib/xmlrpc/client.rb (XMLRPC::Client::do_rpc): Make the Content-Length parameter optional for responses in xmlrpc/client.rb; suggested by Daniel Berger and approved by the maintainer. * lib/xmlrpc/create.rb (XMLRPC::Create::conv2value): Add DateTime support to xmlrpc; approved by the maintainer. Mon Feb 19 18:22:52 2007 Nobuyoshi Nakada * configure.in, defines.h, eval.c (rb_feature_p, rb_provided, load_wait, search_required, rb_require_safe), ext/extmk.rb: Fix a bug where a statically linked extension cannot be autoloaded. [ruby-dev:30023] / [ruby-dev:30239] Mon Feb 19 17:14:28 2007 Yukihiro Matsumoto * ext/socket/socket.c (unix_peeraddr): wrong syscall name in error message for #peeraddr. a patch from Sam Roberts . [ruby-core:10366] Sun Feb 18 19:35:21 2007 Tadayoshi Funaba * lib/date/format.rb: updated based on date2 4.0.3. Fri Feb 16 11:18:21 2007 Eric Hodel * lib/.document: Apply patch for irb, e2mmap and README by Hugh Sasse from [ruby-core:10135] * lib/prettyprint.rb: Suppress RDoc for PrettyPrint test suite. Thu Feb 15 20:26:30 2007 Akinori MUSHA * lib/uri/ftp.rb: Revert the previous change pending discussion. Thu Feb 15 18:08:17 2007 Akinori MUSHA * dir.c (glob_helper): Fix the function declaration. Thu Feb 15 17:13:32 2007 Akinori MUSHA * version.h: Welcome to the post-1.8.6 world. Radical changes are inhibited in the ruby_1_8 branch until the 1.8.6 final release goes out of the door. Thu Feb 15 16:44:14 2007 Akinori MUSHA * lib/uri/generic.rb (URI::Generic::userinfo): Considering how `scheme://user:@...', `scheme://:password@...' and `scheme://:@...' are parsed, an empty user name or password should be allowed and represented as it is. Thu Feb 15 11:46:05 2007 KIMURA Koichi * dir.c, win32/win32.c, win32/dir.h, ruby.h, intern.h: Bring encoding aware globbing support in from trunk. Dir.[] and Dir.glob() can now take many patterns in an array. Minor fixes will follow. Thu Feb 15 11:00:26 2007 Akinori MUSHA * lib/uri/generic.rb (URI::Generic::userinfo): should support empty password. [ruby-core:10290] * lib/uri/generic.rb (URI::Generic::set_password): password can be cleared by nil. [ruby-core:10290] * lib/uri/common.rb (escape): regard second string argument as a character set properly. [ruby-dev:27692] * lib/uri/ftp.rb: Attempt to conform to RFC 1738 with regard to relative/absolute paths. * lib/uri: Lovely RDOC patches from mathew (metaATpoboxDOTcom). Thu Feb 15 10:57:38 2007 Tietew > * lib/cgi.rb (CGI::unescapeHTML): invalid decoding for single unescaped ampersand. a patch from Tietew in [ruby-dev:30292]. fixed: [ruby-dev:30289] Thu Feb 15 10:48:40 2007 MenTaLguY * ext/thread/thread.c: Handle interrupted waits correctly. [ruby-bugs:PR#8663] Wed Feb 14 19:22:15 2007 Akinori MUSHA * ext/digest/lib/digest.rb (Digest::self.const_missing): Drop autoloads for sha2 classes in favor of handling in const_missing(), to work around a problem exposed on OS X. Tue Feb 13 02:21:12 2007 Sam Roberts * io.c (rb_f_syscall): Fix buffer overflow with syscall arguments. [ruby-bugs:PR#8541] Sun Feb 11 07:46:45 2007 Akinori MUSHA * lib/cgi.rb (CGI::QueryExtension::read_multipart): Properly parse a quoted-string in a Content-Disposition value. Sun Feb 11 06:27:54 2007 Akinori MUSHA * configure.in, ext/thread/extconf.rb, lib/thread.rb: Add a configure option `--disable-fastthread', to choose the original, pure ruby version of the "thread" library instead of the new, much faster implementation in ext/thread. Sun Feb 11 06:22:20 2007 Akinori MUSHA * ext/Setup: Add thread except for platforms without threads support. Sun Feb 11 06:15:16 2007 Akinori MUSHA * ext/thread/lib/thread.rb: Add a replacement of thread.rb that loads this extension. Sun Feb 11 05:39:47 2007 Akinori MUSHA * lib/thread.rb: Remove an ineffective part of the code. Sun Feb 11 05:32:54 2007 Akinori MUSHA * ext/thread/thread.c (rb_thread_exclusive): Implement Thread.exclusive. Sun Feb 11 05:26:51 2007 Akinori MUSHA * ext/thread/thread.c: Get rid of use of a dummy function. Sun Feb 11 01:45:31 2007 Hidetoshi NAGAI * ext/thread/thread.c (Init_thread): Define missing aliases: Queue#enq and SizedQueue#enq. Sat Feb 10 09:27:35 2007 Masaki Suketa * ext/win32ole/win32ole.c (ole_variant2val): fix compile error on VC++. Sat Feb 10 07:41:52 2007 Masaki Suketa * ext/win32ole/win32ole.c (ole_variant2val): fix the bug when SAFEARRAY pointer is NULL. Sat Feb 10 00:13:11 2007 Hidetoshi NAGAI * ext/tk/lib/tk.rb: fix typo (TkConfigMethod::__confinfo_cmd, __conv_keyonly_opts). Fri Feb 9 20:44:53 2007 Akinori MUSHA * ext/thread: Make style fixes (mostly de-K&R'ism) to match the rest of the source code. * ext/thread: Make USE_MEM_POOLS an extconf option. Fri Feb 9 20:43:01 2007 Akinori MUSHA * ext/thread: Import the "fastthread" implementation by MenTaLguY in the original form. This module is not hooked into the build yet since it needs some style fixes and adjustments. Fri Feb 9 15:46:09 2007 Akinori MUSHA * ext/bigdecimal: Synchronize with trunk. Better function prototypes, removal of a useless method `!=', and document updates. Tue Feb 06 22:06:45 2007 NARUSE, Yui * ext/nkf/nkf-utf8/{nkf.c,utf8tbl.c}: imported nkf 2007-01-28. * Fixed: can't decode MIME encode JIS string. * Fixed: Fullwitdh-halfwidth conversion. * Support DoCoMo's and Softbank's EMOJI * Support CP932, CP5022x, eucJP-ms UDC * Support UTF-32 encoding * Support beyond BMP [ruby-dev:29700] [ruby-dev:29922] [ruby-dev:30144] Wed Jan 31 14:52:09 2007 Yukihiro Matsumoto * eval.c (rb_iterate): need to PUSH_ITER in proper order. [ruby-core:10125] * test/ruby/test_iterator.rb (TestIterator::test_block_given_within_iterator): add new test. [ruby-core:10125] Tue Jan 30 14:58:51 2007 NAKAMURA Usaku * string.c (rb_str_sub_bang): calling rb_str_modify() should be just before actually modifying the string. fixed: [ruby-dev:30211] (originally reported by zunda) Tue Jan 30 12:05:35 2007 Nobuyoshi Nakada * mkconfig.rb: autoconf 2.61 support. [ruby-core:10016] Sat Jan 27 15:20:11 2007 Yukihiro Matsumoto * parse.y (dyna_var_lookup): should not alter dvar->val not to destroy living value. [ruby-core:10076] * parse.y (dyna_init): ditto. Fri Jan 26 12:03:39 2007 Hidetoshi NAGAI * ext/tk/lib/tk.rb (TkConfigMethod#__confinfo_cmd, __conv_keyonly_optkeys): make them private [ruby-dev:30074]. * ext/tk/lib/tk/txtwin_abst.rb: fix typo [ruby-dev:30073]. * ext/tk/lib/tk/canvas.rb (TkCanvas#scan_dragto): lack of an argument. * ext/tk/lib/tk/canvas.rb: clarify the including module name [ruby-dev:30080]. * ext/tk/lib/tk/scrollable.rb: change primary name of modules [ruby-dev:30080]. Wed Jan 24 18:05:39 2007 Yukihiro Matsumoto * misc/ruby-mode.el (ruby-font-lock-syntactic-keywords): fix regexp font-lock bug. [ruby-talk:235758] Tue Jan 23 11:02:33 2007 Yukihiro Matsumoto * lib/webrick/httprequest.rb (WEBrick::HTTPRequest::read_line): Tue Jan 23 18:26:12 2007 Yukihiro Matsumoto * lib/cgi.rb (CGI::QueryExtension::read_multipart): use == instead of ===. [ruby-dev:30176] Tue Jan 23 10:48:17 2007 Yukihiro Matsumoto * hash.c: added documentation for Hash about how it uses eql? and hash methods for the keys. [ruby-core:09995] Mon Jan 22 14:57:25 2007 Yukihiro Matsumoto * ext/socket/socket.c: fix errors in socket sample code. [ruby-core:09992] Sat Jan 13 23:54:48 2007 Masaki Suketa * ext/win32ole/win32ole.c (ole_free, ole_type_free, olemethod_free, olevariable_free, oleparam_free, ole_event_free): fix memory leak. [ruby-core:09846] Fri Jan 12 11:13:55 2007 Nobuyoshi Nakada * ext/etc/etc.c (etc_getpwuid, etc_getgrgid): fix to correctly convert uid/gid from VALUE. (backport of r11521) Wed Jan 10 18:57:57 2007 Minero Aoki * ext/strscan/strscan.c (strscan_do_scan): should set kcode option before match. [ruby-dev:29914] * test/strscan/test_stringscanner.rb: test it. * re.c: export kcode_set_option and kcode_reset_option (with "rb_" prefix). * intern.h: ditto. Tue Jan 9 17:45:17 2007 NAKAMURA Usaku * file.c (rb_find_file): should not call fpath_check() with NULL. fixed: [ruby-core:09867] Tue Jan 9 03:54:38 2007 Yukihiro Matsumoto * string.c (rb_str_upto): String#upto from empty string makes inifinite loop. [ruby-core:09864] Sun Jan 7 12:13:26 2007 Eric Hodel * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser#find_class_comment): Look for class and module comments above rb_define_class and rb_define_module. Patch by Daniel Berger Sun Jan 7 10:32:12 2007 Eric Hodel * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser#handle_constants): Properly handle escaping of : in comments. * test/rdoc/parsers/test_parse_c.rb: Test RDoc::C_Parser#do_classes and Rdoc::C_Parser#find_class_comment. Sun Jan 7 09:33:02 2007 Tadayoshi Funaba * lib/date/format.rb: updated based on date2 4.0.1. Wed Jan 3 11:36:51 2007 Yukihiro Matsumoto * io.c (ruby_dup): start GC on ENOMEM as well. Mon Jan 1 06:13:11 2007 Eric Hodel * lib/rdoc/parsers/c_parser.rb: Make Rdoc accessible. Update constant value information. Mon Jan 1 06:13:11 2007 Eric Hodel * ext/bigdecimal/bigdecimal.c: Update constant comments to provide values for RDoc. Mon Jan 1 06:05:55 2007 Eric Hodel * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser#handle_constansts): Allow RDoc comment to give friendly value for rb_define_const. Patch by Daniel Berger , [ruby-patches-7499]. * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser#handle_constansts): Fix whitespace handling in constant comments. Sun Dec 31 00:31:16 2006 Tadayoshi Funaba * lib/date.rb, lib/date/format.rb: updated based on date2 4.0. Thu Dec 14 18:29:13 2006 Yukihiro Matsumoto * ext/readline/readline.c: NetBSD editline does not have rl_username_completion_function() and rl_completion_matches(). a patch from Takahiro Kambe . [ruby-dev:30008] Thu Dec 14 18:20:43 2006 Yukihiro Matsumoto * lib/irb/locale.rb (IRB::Locale::puts): typo fixed. a patch from NAKAMURA Usaku . [ruby-dev:30012] Mon Dec 11 11:58:36 2006 Akinori MUSHA * ext/digest/sha2/lib/sha2.rb: Moved one level up from under the superfluous subdirectory digest/. Mon Dec 11 11:46:18 2006 Yukihiro Matsumoto * variable.c (rb_define_const): typo fixed. Mon Dec 11 09:36:29 2006 Yukihiro Matsumoto * string.c (rb_str_aset): index double decode problem. [ruby-core:09695] Sat Dec 9 21:39:24 2006 Nobuyoshi Nakada * eval.c (ruby_cleanup): keep the exception till after END blocks. [ruby-core:09675] Sat Dec 9 11:22:00 2006 Yukihiro Matsumoto * lib/irb/locale.rb (IRB::Locale::search_file): ues File.exist? instead of File.exists?. a patch from Yutaka Kanemoto in [ruby-dev:30000]. Thu Dec 7 09:29:02 2006 Yukihiro Matsumoto * lib/weakref.rb (WeakRef::__setobj__): should support marshaling. [ruby-talk:228508] * lib/delegate.rb (Delegator::marshal_load): need to call __setobj__. Wed Dec 6 23:56:14 2006 Nobuyoshi Nakada * Makefile.in, common.mk (NULLCMD): moved for platforms that empty command does not run. fixed: [ruby-dev:29994] Wed Dec 6 17:17:26 2006 WATANABE Hirofumi * configure.in (SITE_DIR): fixed to emtpy RUBY_SITE_LIB in config.h on NetBSD. fixed: [ruby-dev:29358] Tue Dec 5 00:59:05 2006 Yukihiro Matsumoto * misc/ruby-mode.el (ruby-parse-partial): need to parse "/=" as self assignment operator, not regex. [ruby-talk:227324] Mon Dec 4 10:48:03 2006 Yukihiro Matsumoto * ruby.h (OFFT2NUM): use LONG2NUM() if sizeof(long) equals to sizeof(off_t). Mon Dec 4 10:43:46 2006 Yukihiro Matsumoto * parse.y (dyna_init_gen): dvar initialization only if dvar is assigned inner block. [ruby-talk:227402] Mon Dec 4 08:32:49 2006 Shugo Maeda * lib/cgi.rb (CGI::QueryExtension::read_multipart): should quote boundary. JVN#84798830 Sat Dec 2 07:09:04 2006 GOTOU Yuuzou * ext/openssl/ossl_ocsp.c: OpenSSL::OCSP::OSCPError should be subclass of OpenSSL::OpenSSLError. [ruby-dev:29980] Fri Dec 1 17:01:49 2006 NAKAMURA Usaku * gc.c (ruby_init_stack): decrease "stack level too deep" in Windows. merge from trunk. Fri Dec 1 16:31:53 2006 Hidetoshi NAGAI * ext/tk/tcltklib.c: shouldn't run the killed thread at callback. [ruby-talk: 227408] Mon Nov 27 17:18:27 2006 Yukihiro Matsumoto * sprintf.c (rb_f_sprintf): need not to truncate string if no width specifier given for %s. [ruby-dev:29952] Sun Nov 26 16:36:46 2006 URABE Shyouhei * version.h: addition of RUBY_PATCHLEVEL. * version.c: ditto. Fri Nov 24 10:17:51 2006 Yukihiro Matsumoto * bignum.c (bignorm): avoid segmentation. a patch from Hiroyuki Ito . [ruby-list:43012] Thu Nov 23 10:38:40 2006 Yukihiro Matsumoto * eval.c (rb_mod_define_method): set implicit visibility only when it's called for the target class (ruby_cbase). Wed Nov 22 16:00:49 2006 Hidetoshi NAGAI * ext/tk/extconf.rb: support --with-X11/--without-X11 option. * ext/tk/README.tcltklib: add description about --with-X11-* option [ruby-talk:225166] and --with-X11/--without-X11 option. * ext/tk/tkutil/extconf.rb: able to be called manually [ruby-talk:225950]. Wed Nov 15 23:22:54 2006 Nobuyoshi Nakada * file.c (test_grpowned, rb_stat_grpowned): should honor supplementary group IDs. [ruby-core:09546] Thu Nov 9 03:15:22 2006 Yukihiro Matsumoto * eval.c (BEGIN_CALLARGS): ruby_block may be NULL even when ITER_PRE. Tue Nov 7 18:34:34 2006 Akinori MUSHA * ext/digest/lib/digest/hmac.rb: Keep this out of the 1.8 tree until we reach a consensus that HMAC should be put under Digest. Tue Nov 7 18:05:01 2006 Hidetoshi NAGAI * ext/tk/lib/tk/itemconfig.rb: minor bug fix. Mon Nov 6 20:11:20 2006 Kouhei Sutou * lib/rss/0.9.rb (RSS::Rss): removed needless include. Mon Nov 6 15:41:55 2006 Hidetoshi NAGAI * ext/tk/lib/tk/itemconfig.rb: ext/tk/lib/tk/itemconfig.rb: bug fix on 'itemconfiginfo' method, and modify to make it easy to override 'itemconfiginfo' method. * ext/tk/lib/tkextlib/tile/treeview.rb : support Tile 0.7.8. * ext/tk/lib/tkextlib/version.rb : [new] add Tk::Tkextlib_RELEASE_DATE to get the information from scripts. * ext/tk/lib/tk.rb: load 'tkextlib/version.rb', and update RELEASE_DATE * ext/tk/lib/tkextlib/SUPPORT_STATUS: update. * ext/tk/sample/editable_listbox.rb: [new] the listbox with editable items. It's one of the example about usage of Place geometry manager. * ext/tk/sample/tktextio.rb: improve the functions of TkTextIO class. Those are required by 'irbtkw.rbw'. * ext/tk/sample/irbtkw.rbw: [new] IRB on Ruby/Tk. It doesn't need any real console. IRB works on a text widget without I/O blocking. That is, thread switching on IRB will work properly, even if on Windows. Sun Nov 5 19:53:49 2006 Tadayoshi Funaba * lib/date.rb: updated based on date2 3.9.7. Sat Nov 4 13:13:57 2006 Shugo Maeda * lib/net/imap.rb: accept NOMODSEQ. [ruby-core:9002] (backported from HEAD) Fri Nov 3 00:16:37 2006 Yukihiro Matsumoto * ext/socket/socket.c (ruby_getnameinfo__aix): AF_INET6 workaround for AIX. a patch from Yutaka Kanemoto . [ruby-dev:29744] Thu Nov 2 15:43:39 2006 NAKAMURA Usaku * parse.y (primary): should set NODE even when compstmt is NULL. merge from trunk. fixed: [ruby-dev:29732] Thu Nov 2 14:48:30 2006 Akinori MUSHA * lib/set.rb (Set#^): Fix XOR operation against a container that holds duplicate values. [issue: #6444] Wed Nov 1 02:41:38 2006 Akinori MUSHA * ext/digest/lib/digest/hmac.rb (Digest::HMAC::update): Minor optimization. * ext/digest/digest.c (rb_digest_instance_equal): Allow comparing a digest instance with another of a different class. Wed Nov 1 01:05:13 2006 NAKAMURA Usaku * eval.c (rb_call0): fixed bug of zsuper with both of opt and rest. fixed: [ruby-list:42928] * test/ruby/test_super.rb: add tests to check above bug. Tue Oct 31 17:03:21 2006 Yukihiro Matsumoto * time.c (time_dup): duplicate the class of original time. [ruby-core:09357] * lib/time.rb (Time::make_time, Time::rfc2822, Time::httpdate): should respect subclasses. [ruby-core:09357] Mon Oct 30 23:40:52 2006 Nobuyoshi Nakada * Makefile.in (miniruby): add XLDFLAGS. * configure.in (aix): use -bE option for miniruby. [ruby-dev:29698] * dir.c (glob_helper): get rid of possible memory leak. * win32/win32.c (cmdglob, rb_w32_cmdvector, rb_w32_opendir, rb_w32_get_environ): not to use GC before initialization. Mon Oct 30 19:29:20 2006 NAKAMURA Usaku * bignum.c (rb_big2str0): use better approximation. Mon Oct 30 18:35:33 2006 Yukihiro Matsumoto * bignum.c (rb_big2str0): wrong allocation length. a patch from U.Nakamura [ruby-dev:29710] Mon Oct 30 12:34:02 2006 Yukihiro Matsumoto * eval.c (rb_eval): fix commit miss. [ruby-dev:29707] Mon Oct 30 12:20:58 2006 Yukihiro Matsumoto * bignum.c (rb_big2str0): a bug in length adjustment. Mon Oct 30 11:15:40 2006 Yukihiro Matsumoto * sprintf.c (rb_str_format): should preserve leading zero information for negative %b and %x. [ruby-talk:221347] Thu Oct 26 21:05:58 2006 GOTOU Yuuzou * ext/openssl/ossl_pkcs7.c (ossl_pkcs7_verify): should clear error. (fix http://bugs.debian.org/394336) * ext/openssl/ossl_ns_spki.c (ossl_spki_initialize): ditto. Thu Oct 26 15:21:10 2006 NAKAMURA Usaku * ext/digest/digest.c (Init_digest): typo. Wed Oct 25 17:23:28 2006 Akinori MUSHA * ext/digest, test/digest/test_digest.rb: Merge from trunk: - Introduce versioning in Digest::Base API, and prefix C constants with RUBY_ and C type names with rb_ to avoid name clash in writing extensions. - Introduce Digest::Class and Digest::Instance for ease of implementing subclasses and add-ons. - Digest::Instance module requires and assumes that any instance be resettable and clonable. An instance method #new() is added so digest instances work just like digest classes. - The constructor does no longer take an initial string to feed; digest() and hexdigest() now do, instead. This allows digest classes to take their own hashing parameters. - Make some changes to digest() and hexdigest() class methods, which now take extra arguments, which are passed through to the constructor in an internal call. - Add #digest_length/size/length() and #block_length(), - Add the Digest::SHA2 class to wrap up SHA2 variants: SHA256, SHA384 and SHA512, hoping this module would make a decent example of a digest subclass written in Ruby. - Rip BubbleBabble support out of the base class and have a separate module named digest/bubblebabble. - Remove RD documents in favor of newly written and embedded RDoc documentation. Wed Oct 25 08:03:23 2006 Tadayoshi Funaba * lib/date/format.rb: updated based on date2 3.9.6. [ruby-core:09323] Sun Oct 22 14:48:31 2006 Yukihiro Matsumoto * signal.c (ruby_signal): don't set SA_RESTART. a backport from the HEAD. [ruby-talk:220937] [ruby-talk:147220] * signal.c (Init_signal): avoid duplicated installation of SIGCHLD handler. Sun Oct 22 16:47:56 2006 Nobuyoshi Nakada * string.c (rb_str_substr): should be infected with only original string, but not the shared string. fixed: [ruby-core:09152] * string.c (rb_str_new4): keep shared string untainted when orignal string is tainted. fixed: [ruby-dev:29672] Sun Oct 22 05:20:34 2006 URABE Shyouhei * configure.in: alloca is broken; use C_ALLOCA instead. [ruby-dev:29416] Fri Oct 20 10:47:43 2006 NAKAMURA Usaku * lib/mkmf.rb: fixed the bug of handling COMMON_MACROS. Fri Oct 20 08:42:38 2006 Nobuyoshi Nakada * common.mk (NULLCMD): dummy command. * bcc32/Makefile.sub (post-install-*): Borland make cannot ignore command-less double-colon rules. [ruby-dev:29676] Fri Oct 20 00:37:07 2006 Nobuyoshi Nakada * bcc32/Makefile.sub ($(LIBRUBY_SO)): execute pre-link hook. * ext/extmk.rb: workaround for Borland make. Wed Oct 18 23:02:40 2006 Nobuyoshi Nakada * array.c (rb_ary_shift): shorten copy size. fixed: [ruby-list:42907] * signal.c (Init_signal): handle SIGTERM. fixed: [ruby-list:42895] * win32/win32.c (rb_w32_utime): allow NULL to set the current time. [ruby-talk:219248] Wed Oct 18 00:55:33 2006 Nobuyoshi Nakada * parse.y (parser_yylex): use particular enums. [ruby-core:09221] Mon Oct 16 08:30:43 2006 Nobuyoshi Nakada * mkconfig.rb: *OBJS are not needed for extension libraries. * {bcc32,wince,win32}/Makefile.sub (config.status): fixed typo, missing comma. Sun Oct 15 01:03:08 2006 Nobuyoshi Nakada * lib/test/unit/collector/dir.rb (Collector::Dir#collect): append base directory but not prepend. * lib/test/unit/collector/dir.rb (Collector::Dir#collect_file): do not join with dot. fixed: [ruby-core:09179] Sat Oct 14 23:39:50 2006 Yukihiro Matsumoto * parse.y (singleton): no need to re-create NODE_SELF() again. [ruby-core:09177] Sat Oct 14 23:25:31 2006 Yukihiro Matsumoto * parse.y (parser_warning, parser_warn): some error message may contain format specifiers. a patch from Akinori MUSHA . [ruby-dev:29657] * ext/bigdecimal/bigdecimal.c (VpException): ditto. * ext/dl/handle.c (rb_dlhandle_initialize): ditto. * ext/gdbm/gdbm.c (rb_gdbm_fatal): ditto. Sat Oct 14 08:24:45 2006 Akinori MUSHA * ext/digest/lib/digest/hmac: Back out the addition of digest/hmac for now because the API is too premature for a stable branch. Sat Oct 14 00:55:08 2006 Nobuyoshi Nakada * bcc32/Makefile.sub (post-install-ext): no longer needed. * bcc32/configure.bat: get rid of a quirk of Borland make, which sets empty macro in command line to "1". Fri Oct 13 22:50:43 2006 Tadayoshi Funaba * lib/date.rb: updated based on date2 3.9.5. Fri Oct 13 22:33:28 2006 Minero Aoki * lib/fileutils.rb (FileUtils.cp_r): dereference_root=true is default in Ruby 1.8. This line is wrongly removed in last commit. Fri Oct 13 18:19:31 2006 Yukihiro Matsumoto * object.c: Class#inherited RDoc added. a patch from Daniel Berger [ruby-core:08942] Fri Oct 13 02:30:12 2006 Nobuyoshi Nakada * lib/test/unit/collector/dir.rb (Collector::Dir#collect): prepend base directory to load path. * lib/test/unit/collector/dir.rb (Collector::Dir#collect_file): should use the given File-like interface, but not File directly. * test/testunit/collector/test_dir.rb (TestDir::FileSystem): implement File-like methods correctly. Fri Oct 13 01:48:42 2006 Yukihiro Matsumoto * lib/date.rb (Date::self.complete_hash): need to check if g is nil before dereference. [ruby-core:09116] Fri Oct 13 00:34:26 2006 Yukihiro Matsumoto * object.c (rb_mod_cvar_defined): wrong id check. a patch from Mauricio Fernandez . [ruby-core:09158] * object.c (rb_mod_cvar_get): typo fixed. [ruby-core:09168] * object.c (rb_mod_cvar_set): ditto. Wed Oct 11 22:21:41 2006 Akinori MUSHA * ext/digest: Merge from trunk; metadata location changed, Digest::Base#reset() added, Digest::Base#equal() changed, and digest/hmac added with some modifications made for ruby 1.8. Tue Oct 10 17:24:12 2006 NAKAMURA Usaku * {bcc32,win32,wince}/Makefile.sub (config.status): shouldn't use copy command instead of install. use -run install. Tue Oct 10 16:49:16 2006 Akinori MUSHA * ext/digest/digest.c (hexdigest_str_new, bubblebabble_str_new): Perform StringValue() checks properly. * ext/digest/digest.c: Use RSTRING_{PTR,LEN} macros. Tue Oct 10 13:49:53 2006 Akinori MUSHA * ext/digest: Merge from trunk; apply all changes since the initial import, except for the removal of compatibility stub libraries (md5.rb and sha1.rb). Mon Oct 9 23:46:29 2006 Yukihiro Matsumoto * lib/parsedate.rb: documentation patch from Konrad Meyer . [ruby-doc:1238] * lib/open3.rb, lib/ping.rb: ditto. Mon Oct 9 22:56:12 2006 Yukihiro Matsumoto * lib/rexml/encoding.rb (REXML::Encoding::check_encoding): spaces are allowed around equal sign. [ruby-core:09032] * lib/rexml/parsers/baseparser.rb (REXML::Parsers::BaseParser): ditto. Sat Oct 7 23:53:08 2006 Yukihiro Matsumoto * string.c (rb_str_scan): small documentation fix. [ruby-core:09007] Sat Oct 7 23:44:33 2006 Yukihiro Matsumoto * bignum.c (rb_big_rshift): a bug in right shift of negative bignums. [ruby-core:09020] Sat Oct 7 00:27:58 2006 Yukihiro Matsumoto * class.c (rb_include_module): remove unnecessary check. [ruby-talk:218402] Fri Oct 6 04:30:30 2006 Akinori MUSHA * sample/openssl/c_rehash.rb: Use digest/md5 instead of obsolete md5. Wed Oct 4 18:47:25 2006 Hidetoshi NAGAI * ext/tk/lib/tkextlib/*: bugfix and update (see ext/tk/ChangeLog.tkextlib). Wed Oct 4 17:25:14 2006 Yukihiro Matsumoto * eval.c (rb_call): check protected visibility based on real self, not ruby_frame->self. [ruby-talk:217822] Wed Oct 4 08:52:30 2006 Nobuyoshi Nakada * test/optparse/test_getopts.rb: changed the class name of test case to get rid of conflict with test_optparse.rb. Tue Oct 3 23:32:27 2006 Nobuyoshi Nakada * lib/test/unit/testcase.rb (Test::Unit::TestCase.suite): test name must be string. fixed: [ruby-core:08978] Mon Oct 2 23:47:55 2006 Nobuyoshi Nakada * lib/test/unit/autorunner.rb (Test::Unit::AutoRunner::COLLECTORS): base directory should be lower precedence. fixed: [ruby-dev:29622] * lib/test/unit/autorunner.rb (Test::Unit::AutoRunner#options): typo. * lib/test/unit/collector/dir.rb (Test::Unit::Collector::Dir#collect_file): load expanded path. fixed: [ruby-dev:29621] Mon Oct 2 15:49:19 2006 NAKAMURA Usaku * instruby.rb: batfile should be CRLF'ed. Mon Oct 2 01:24:26 2006 Nobuyoshi Nakada * common.mk (test-all): separate directory where running test cases from source tree. * lib/test/unit/autorunner.rb (options): added --basedir, --workdir and --load-path options. * lib/test/unit/collector/dir.rb (recursive_collect, collect_file): base directory support. Sun Oct 1 23:56:52 2006 Nobuyoshi Nakada * Makefile.in, common.mk, ext/extmk.rb, win{32,ce}/Makefile.in: keep LIBRUBY_SO unless need to be removed. Sun Oct 1 23:12:19 2006 Nobuyoshi Nakada * lib/optparse.rb (OptionParser#make_switch): pass arguments directly. Sat Sep 30 15:12:25 2006 Tadayoshi Funaba * lib/date.rb, lib/date/format.rb: updated based on date2 3.9.4. Fri Sep 29 12:11:04 2006 WATANABE Hirofumi * jcode.rb (succ!): call original succ! if $KCODE == 'n'. fixed: [ruby-talk:216845] Fri Sep 29 11:43:40 2006 Nobuyoshi Nakada * lib/mkmf.rb (try_func): revert fallback checking undeclared function. fixed: [ruby-core:08949] Fri Sep 29 09:56:56 2006 Nobuyoshi Nakada * ext/extmk.rb: extout is needed for also clean. fixed: [ruby-core:08944] * lib/optparse.rb (OptionParser::Switch#conv_arg): unsplat by Proc#call if no conversion is given. Thu Sep 28 23:59:31 2006 Nobuyoshi Nakada * node.h (struct thread): declare win32_exception_list on cygwin and win32 regardless if it is implemented. Provisional fix for [ruby-core:08917]. Thu Sep 28 20:53:16 2006 NAKAMURA Usaku * lib/tmpdir.rb: use return value of getdir.call for length. Wed Sep 27 01:04:49 2006 Nobuyoshi Nakada * lib/mkmf.rb (try_func): check function pointer first and macro next. * lib/mkmf.rb (have_type): simplified with typedef and sizeof. Tue Sep 26 23:57:03 2006 Nobuyoshi Nakada * lib/optparse.rb (OptionParser#getopts): use strings as key. fixed: [ruby-dev:29614] Tue Sep 26 15:31:26 2006 NAKAMURA Usaku * {win32,wince}/Makefile.sub (CPP): check predefined value. Tue Sep 26 07:55:16 2006 Yukihiro Matsumoto * array.c (rb_ary_shift): should not move memory region if array body is shared. a patch from Kent Sibilev . [ruby-core:08922] Mon Sep 25 22:26:26 2006 Nobuyoshi Nakada * file.c (rb_path_end): skip root directory. fixed: [ruby-core:08913] * lib/mkmf.rb (init_mkmf): set default $LDFLAGS. Patch by Michal Suchanek . [ruby-talk:216256] Mon Sep 25 08:14:43 2006 Yukihiro Matsumoto * array.c (rb_ary_shift): should clear shifting top element. [ruby-talk:216055] * array.c (rb_ary_shift): avoid creating shared object if array size is small. Mon Sep 25 08:11:35 2006 Yukihiro Matsumoto * random.c (rb_f_rand): RDoc typo fix. a patch from Frederick Cheung . [ruby-talk:216047] Sun Sep 24 22:28:20 2006 Nobuyoshi Nakada * runruby.rb: extension library scripts moved into common directory. Sun Sep 24 14:59:50 2006 Tanaka Akira * node.h (struct thread): ia64 support is broken by sandbox patch. Sun Sep 24 12:11:16 2006 Tadayoshi Funaba * lib/date.rb, lib/date/format.rb: updated based on date2 3.9.3. Sat Sep 23 23:24:57 2006 why the lucky stiff * eval.c (rb_thread_save_context, rb_thread_restore_context): sandbox hook to save and restore sandbox state. * eval.c (thread_no_ensure): added THREAD_NO_ENSURE thread flag. * eval.c (rb_thread_kill_bang): Thread#kill! uses the above flag to circumvent ensure, in order to prevent endless loops. [ruby-core:08768] * eval.c (rb_thread_kill): fix Thread#kill docs, which returns the thread object in all cases. * node.h: expose the rb_jmpbuf_t and rb_thread_t structs, along with the thread flags. used by the sandbox extension. * ruby.h: extern rb_eThreadError, so sandbox can swap it. Sat Sep 23 21:34:15 2006 Yukihiro Matsumoto * lib/cgi.rb (CGI::QueryExtension::read_multipart): CGI content may be empty. a patch from Jamis Buck . Sat Sep 23 08:35:53 2006 Yukihiro Matsumoto * lib/rdoc/ri/ri_options.rb: prevent NameError. [ruby-dev:29597] Sat Sep 23 01:04:20 2006 Tadayoshi Funaba * lib/date.rb, lib/date/format.rb: updated based on date2 3.9.2. Fri Sep 22 02:06:26 2006 Nobuyoshi Nakada * .cvsignore: ignore timestamp files and installed list file. Fri Sep 22 01:36:34 2006 Nobuyoshi Nakada * instruby.rb: include FileUtils unconditionally. Thu Sep 21 22:56:20 2006 Nobuyoshi Nakada * common.mk (no-install): not install rdoc actually. * common.mk (install-doc, no-install-doc): use instruby.rb. * instruby.rb: rdoc installation. * ext/extmk.rb: expand ruby executable names. Thu Sep 21 13:55:07 2006 Yukihiro Matsumoto * ext/etc/etc.c (etc_getpwuid): uid integer should be wraped in uid_t value. [ruby-core:08897] * ext/etc/etc.c (etc_getpwuid): uid_t may be bigger than plain 'int' type. Wed Sep 20 23:17:41 2006 Nobuyoshi Nakada * common.mk (pre-install-doc): create data directory before install. * lib/mkmf.rb (dir_re): fixed typo. * lib/mkmf.rb (install_dirs): remove extra slash. Wed Sep 20 09:53:38 2006 NAKAMURA Usaku * {bcc32,win32,wince}/Makefile.sub (INSTALLED_LIST): need to define this macro to install. Wed Sep 20 09:43:10 2006 Shugo Maeda * lib/net/imap.rb: allow extra spaces in responses. Thanks, Tom Soderlund. (backported from HEAD) Wed Sep 20 09:25:39 2006 Yukihiro Matsumoto * ext/gdbm/gdbm.c: add RDoc documentation. a patch from Peter Adolphs . [ruby-doc:1223] Tue Sep 19 01:28:00 2006 Minero Aoki * lib/fileutils.rb: backport from HEAD (rev 1.71). * lib/fileutils.rb (FileUtils.cp_r): new option :remove_destination. Tue Sep 19 00:42:15 2006 Nobuyoshi Nakada * object.c (rb_obj_ivar_defined, rb_mod_cvar_defined): new methods, Kernel#instance_variable_defined? and Module#class_variable_defined?. [ruby-dev:29587] * lib/date/format.rb (Date::Bag#method_missing): use new method, instance_variable_defined? to check if an instance variable is defined. fixed: [ruby-dev:29554] -- This didn't fix anything. Sun Sep 17 23:44:58 2006 Nobuyoshi Nakada * lib/rdoc/rdoc.rb (RDoc::RDoc#document): scan only files modified after the previous generation. Sun Sep 17 17:42:13 2006 Nobuyoshi Nakada * common.mk (install-doc): reverted. * instruby.rb: stores file name list without destdir prefix. * lib/rdoc/generators/ri_generator.rb: do not chdir twice. Sat Sep 16 23:14:29 2006 Yukihiro Matsumoto * ext/pty/pty.c (establishShell): remove remaining unused line. Sat Sep 16 16:40:44 2006 Nobuyoshi Nakada * Makefile.in, common.in, instruby.rb, ext/extmk.rb, lib/mkmf.rb: use instruby.rb to install extensions instead of ext/extmk.rb. * instruby.rb: store installed list into the file. * ext/dbm/extconf.rb: allow multiple candidates for dbm-type. * ext/io/wait/extconf.rb: suspicious checking_for. * ext/pty/pty.c (establishShell): parent pid is not used. * ext/pty/pty.c (freeDevice): not used. * ext/pty/pty.c (get_device_once): removed garbage right brace. * lib/mkmf.rb (checking_for): improved the messages. Thu Sep 14 16:11:15 2006 Yukihiro Matsumoto * string.c (rb_str_intern): raise SecurityError only when $SAFE level is greater than zero. [ruby-core:08862] * parse.y (rb_interned_p): new function to check if a string is already interned. * object.c (str_to_id): use rb_str_intern(). Wed Sep 13 18:43:05 2006 Yukihiro Matsumoto * README.EXT: English adjustment. [ruby-core:08851] and [ruby-core:08852] Wed Sep 13 18:25:18 2006 Yukihiro Matsumoto * misc/ruby-mode.el (ruby-parse-partial): better here-doc support. a patch from Marshall T. Vandegrift . [ruby-core:08804] Wed Sep 13 16:43:36 2006 Yukihiro Matsumoto * string.c (rb_str_intern): prohibit interning tainted string. Wed Sep 13 01:14:21 2006 Nobuyoshi Nakada * lib/optparse.rb (OptionParser#getopts): works with pre-registered options. [ruby-core:08826] Sun Sep 10 20:27:13 2006 Tadayoshi Funaba * lib/date.rb, lib/date/format.rb: updated based on date2 3.9.1. Tue Jan 10 09:18:03 2006 Nobuyoshi Nakada * eval.c (stack_extend): fixed prototype. * eval.c (rb_require_safe): prevent extension from loading twice. fixed: [ruby-dev:29523] Sat Sep 9 23:50:38 2006 Yukihiro Matsumoto * bignum.c (rb_big_mul0): bignum multiplication without normalization. * bignum.c (rb_big_pow): use rb_big_mul0(). [ruby-dev:29547] Sat Sep 9 14:08:38 2006 Eric Hodel * lib/test/unit/testcase.rb (Test::Unit::TestCase#run): Rescue Exception in Test::Unit::TestCase#run. [ruby-core:08783] Sat Sep 9 04:55:59 2006 Nobuyoshi Nakada * lib/pstore.rb: open all in binary mode, and get rid of the quirk of msvcrt. fixed: [ruby-dev:29518] Sat Sep 9 04:54:42 2006 Nobuyoshi Nakada * Makefile.in, win32/Makefile.sub (MINIRUBY): append MINIRUBYOPT. * mkconfig.rb, ext/extmk.rb, lib/mkmf.rb, win32/mkexports.rb: suppress warnings with $VERBOSE. * ext/extmk.rb: Proc#call does not pass the block in 1.8. * win32/resource.rb: add more info. Fri Sep 8 10:03:59 2006 GOTOU Yuuzou * lib/webrick/cookie.rb (WEBrick::Cookie.parse_set_cookies): new method to parse multiple cookies per Set-Cookie header. Thanks to Aaron Patterson . [ruby-core:08802] Fri Sep 8 08:59:30 2006 Nobuyoshi Nakada * win32/Makefile.sub, win32/configure.bat win32/setup.mak: program name transform. Fri Sep 8 01:33:08 2006 Yukihiro Matsumoto * ruby.h (RSTRING_PTR): add migration macro. * ruby.h (RARRAY_PTR): ditto. Thu Sep 7 23:27:05 2006 Nobuyoshi Nakada * file.c (path_check_0, fpath_check): disable path check on cygwin. [ruby-talk:213074] Wed Sep 06 12:05:19 2006 NARUSE, Yui * ext/nkf/lib/kconv.rb (Kconv::RegexpEucjp): fix regexp for euc-jp [ruby-dev:29344] * ext/nkf/lib/kconv.rb (Kconv::toeuc): remove -m0 [ruby-dev:29505] Tue Sep 5 06:47:22 2006 Nobuyoshi Nakada * time.c (time_to_s): variable declaration after an execution statement. Tue Sep 5 05:56:51 2006 Nobuyoshi Nakada * numeric.c (flo_hash): improve collision. fixed: [ruby-dev:29352] Tue Sep 5 05:49:41 2006 Nobuyoshi Nakada * file.c (path_check_0): check if sticky bit is set on parent directories for executable path. fixed: [ruby-dev:29415] Tue Sep 5 05:03:46 2006 Yukihiro Matsumoto * numeric.c (fix_plus): addition in Fixnum will never overflow long. a patch from Ondrej Bilka . [ruby-core:08794] * numeric.c (fix_minus): ditto. * bignum.c (rb_big_pow): eagerly truncate resulting bignum. [ruby-core:08794] Mon Sep 4 23:15:34 2006 Yukihiro Matsumoto * time.c (time_to_s): make it conform to RFC2822 date format. [ruby-dev:29467] Mon Sep 4 21:43:57 2006 Nobuyoshi Nakada * ext/dbm/extconf.rb: create makefile according to the result of check for dbm header. fixed: [ruby-dev:29445] Mon Sep 4 21:42:35 2006 Tadayoshi Funaba * lib/date.rb, lib/date/format.rb: updated based on date2 3.9. Mon Sep 4 21:14:20 2006 Nobuyoshi Nakada * time.c (time_strftime): include nul character. fixed: [ruby-dev:29422] Mon Sep 4 16:29:33 2006 Yukihiro Matsumoto * lib/cgi.rb (CGI::out): specify -m0 -x option for nkf. [ruby-dev:29284] Mon Sep 4 16:13:23 2006 Yukihiro Matsumoto * io.c (pipe_open): command name should not contain null bytes. [ruby-dev:29421] * process.c (proc_spawn): ditto. * process.c (proc_spawn_n): ditto. * process.c (rb_f_system): ditto. Sun Sep 3 15:32:44 2006 Nobuyoshi Nakada * lib/mkmf.rb: get rid of nil.to_s. Sun Sep 3 06:24:38 2006 Tanaka Akira * ext/socket/socket.c (ruby_connect): sockerrlen should be socklen_t. Sun Sep 3 04:40:42 2006 Tanaka Akira * ext/socket/extconf.rb: check arpa/inet.h for ntohs. * ext/socket/socket.c: include arpa/inet.h if available. Sun Sep 3 02:34:55 2006 Masatoshi SEKI * lib/drb/unix.rb (DRbUNIXSocket#close): don't get path if client mode. [ruby-dev:29417] Sun Sep 3 01:45:17 2006 Masatoshi SEKI * lib/drb/acl.rb (ACLEntry#initialize): examine whether '*' is included before IPAddr.new. [ruby-dev:29406] Sat Sep 2 13:23:01 2006 Tanaka Akira * common.mk (ia64.o): use the compiler driver to assemble ia64.s to use appropriate ABI. Sat Sep 2 03:36:22 2006 Tanaka Akira * common.mk, configure.in, defines.h, eval.c, gc.c, main.c, numeric.c, ruby.h, ia64.s: backport IA64 HP-UX support. Fri Sep 1 13:52:57 2006 Hidetoshi NAGAI * ext/tk/lib/tk/font.rb: TkFont#current_configinfo() doesn't work on Tcl/Tk8.x. Thu Aug 31 12:46:55 2006 why the lucky stiff * eval.c (ruby_init): rename top_cref to ruby_top_cref and export, along with ruby_cref, for use by the sandbox. [ruby-core:08762] * node.h: ditto. Tue Aug 29 19:10:10 2006 Nobuyoshi Nakada * hash.c (rb_hash_s_create): fixed memory leak, based on the patch by Kent Sibilev . fixed: [ruby-talk:211233] Mon Aug 28 11:36:02 2006 Eric Hodel * lib/rdoc/parsers/parse_rb.rb: Fix typo. Submitted by . [ruby-core:08724] Mon Aug 28 07:53:44 2006 Eric Hodel * lib/rdoc/ri/ri_formatter.rb: Don't unescape HTML in HtmlFormatter. Submitted by Kent Sibilev . [ruby-core:08392]. Mon Aug 28 07:25:45 2006 Eric Hodel * file.c (File#size?): Fix documentation submitted by Rick Ohnemus. ruby-Bugs-5529. [ruby-core:08725] Sat Aug 26 08:07:13 2006 Tadayoshi Funaba * lib/date.rb, lib/date/format.rb: updated based on date2 3.8.2. Fri Aug 25 22:32:04 2006 Nobuyoshi Nakada * lib/rexml/source.rb (REXML::IOSource#initialize): encoding have to be set with the accessor. fixed: [ruby-list:42737] Fri Aug 25 17:15:17 2006 Yukihiro Matsumoto * stable version 1.8.5 released. Fri Aug 25 17:02:06 2006 Yukihiro Matsumoto * gc.c (gc_sweep): typo fixed. Tue Aug 22 18:47:51 2006 Yukihiro Matsumoto * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser::handle_method): rdoc documents C module methods as instance methods. a patch in [ruby-core:08536]. Sat Aug 19 14:15:02 2006 NAKAMURA Usaku * win32/Makefile.sub (config.status): include winsock2.h instead of winsock.h when --with-winsock2 is specified. fixed: [ruby-dev:29296] Sat Aug 19 11:28:08 2006 Nobuyoshi Nakada * file.c (rb_file_s_rename): use errno if set properly. fixed: [ruby-dev:29293] Sat Aug 19 11:09:23 2006 Yukihiro Matsumoto * parse.y (then): remove semicolon warning. [ruby-dev:29299] Thu Aug 17 19:15:16 2006 Nobuyoshi Nakada * file.c (rb_stat_[rRwWxX]): check for super user. fixed: [ruby-core:08616] Thu Aug 17 14:47:06 2006 Nobuyoshi Nakada * lib/mkmf.rb: added rdoc by Daniel Berger. [ruby-core:08177] Thu Aug 17 00:39:05 2006 Masatoshi SEKI * lib/rinda/ring.rb (do_reply): Fix for RingServer fails to find a TupleSpace when TupleSpace resides in the same ruby process with RingServer. a patch from Kent Sibilev. [ruby-core:08453] Wed Aug 16 11:45:36 2006 Nobuyoshi Nakada * process.c (proc_setuid, proc_setgid, proc_seteuid, proc_setegid): get rid of bogus implementations on Mac OS X. Tue Aug 15 19:10:18 2006 Eric Hodel * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser#find_class_comment): Fix broken class-level documentation. Wed Aug 16 11:09:26 2006 Nobuyoshi Nakada * ruby.c (set_arg0): fill argv other than the first with an empty string instead of NULL. Wed Aug 16 11:08:00 2006 Nobuyoshi Nakada * win32/win32.h: removed an excess macro. fixed: [ruby-dev:29258] Tue Aug 8 23:49:06 2006 Yukihiro Matsumoto * lib/irb/extend-command.rb (IRB::ExtendCommandBundle): pacify RDoc. a patch from Eric Hodel . [ruby-core:08522] Tue Aug 8 11:32:54 2006 NAKAMURA Usaku * Makefile.in, common.mk, configure.in: fix for platforms without rm. patches from Yutaka kanemoto . [ruby-dev:29215] Mon Aug 7 17:56:59 2006 Yukihiro Matsumoto * ext/bigdecimal/bigdecimal.c, ext/digest/rmd160/rmd160ossl.c, ext/digest/sha1/sha1ossl.c, ext/readline/readline.c: move incluion of config.h to pacify AIX. a patch from Yutaka Kanemoto . [ruby-dev:29197] Mon Aug 7 15:55:08 2006 Yukihiro Matsumoto * ext/syck/syck.c (syck_move_tokens): should avoid negative memmove. [ruby-list:42625] Mon Aug 7 14:37:48 2006 Yukihiro Matsumoto * configure.in, common.mk: AIX link issue. a patch from Yutaka Kanemoto . [ruby-dev:29190] * ext/socket/socket.c: AIX socket support. [ruby-dev:29190] Mon Aug 7 12:05:28 2006 Yukihiro Matsumoto * dln.c, eval.c, gc.c, regex.c, ruby.h: shut up AIX alloca warning. a patch from Yutaka Kanemoto . [ruby-dev:29191] Sun Aug 6 20:40:41 2006 Tadayoshi Funaba * lib/date/format.rb (str[fp]time): %[EO]U didn't denote %U. Sat Aug 5 17:07:43 2006 Yukihiro Matsumoto * parse.y (top_local_setup): local_vars[-1] should point ruby_scope itself to protect local_tbl from garbage collection. [ruby-dev:29049] Sat Aug 5 13:54:03 2006 Tadayoshi Funaba * lib/date/format.rb (str[fp]time): "%\n" means "\n". Fri Aug 4 15:21:00 2006 Eric Hodel * lib: Merge RDoc and .document from HEAD. * lib/drb/ssl.rb: Close socket on SSLError [ruby-core:7197] Fri Aug 4 19:13:41 2006 Keiju Ishitsuka * lib/irb/{init.rb,ruby-lex.rb,slex.rb}: can't input '\c' for [ruby-core: 7122]. Fri Aug 4 14:02:14 2006 James Edward Gray II * lib/date/format.rb (__strptime, strftime): allow multi-line patterns in Date#strftime the same as Time#strftime accepts. fixed: [ruby-core:08466] Fri Aug 4 13:56:51 2006 Nobuyoshi Nakada * pack.c (pack_pack): check argument overrun for 'P'. based on a patch by rucila . fixed: [ruby-dev:29182] Tue Aug 1 17:44:03 2006 Nobuyoshi Nakada * win32/win32.c (init_stdhandle): assign standard file handles. Tue Aug 1 12:24:58 2006 Nobuyoshi Nakada * eval.c (Init_Binding): fix old commit miss. Mon Jul 31 17:08:20 2006 NAKAMURA Usaku * win32/win32.c (exit_handler): new function; release winsock and environment work area. * win32/win32.c (NTInitialize): setup exit_handler. * win32/win32.c (StartSockets): use exit_handler. * win32/win32.c (rb_w32_getenv): use GetEnvironmentStrings() instead of GetEnvironmentVariable(), because the latter cannot distinguish wheather a null environment variable exists or not. fixed: [ruby-talk:205123] Mon Jul 31 16:15:13 2006 Tanaka Akira * test/ruby/test_process.rb (TestProcess#test_rlimit_nofile): setrlimit may fail with EINVAL. reported by MIYAMUKO Katsuyuki. [ruby-dev:29174] Mon Jul 31 13:38:22 2006 GOTOU Yuuzou * lib/webrick/httprequest.rb (WEBrick::HTTPReuqest#parse_uri): improve for the value of IPv6 address in the Host: header field. Mon Jul 31 09:22:12 2006 Yukihiro Matsumoto * ruby.h: use ifdef (or defined) for macro constants that may or may not be defined to shut up gcc's -Wundef warnings. [ruby-core:08447] Sun Jul 30 23:26:22 2006 Nobuyoshi Nakada * eval.c (rb_call0): trace call/return of method defined from block. fixed: [ruby-core:08329] * eval.c (rb_trap_eval): make the current thread runnable to deal with exceptions which occurred within the trap. fixed: [ruby-dev:27729] * lib/cgi/session.rb, lib/cgi/session/pstore.rb: suppress warnings. fixed: [ruby-talk:204896] Sat Jul 29 06:12:06 2006 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: freeze ip_name for security reason. Sat Jul 29 01:23:52 2006 Yukihiro Matsumoto * lib/logger.rb: improves the amount of documentation that Rdoc picks up when processing logger.rb by moving the require statement back before the comment block. a patch from Hugh Sasse . [ruby-core:08422] Thu Jul 27 22:21:52 2006 Nobuyoshi Nakada * time.c (time_to_s): fixed format mismatch. Thu Jul 27 21:19:54 2006 Yukihiro Matsumoto * math.c (domain_check): a new function to check domain error explicitly for systems that return NaN like FreeBSD. [ruby-core:07019] * math.c (math_acos, math_asin, math_acosh, math_atanh, math_log, math_log10, math_sqrt): use domain_check(). * math.c (math_sqrt): fix documentation flaw. Thu Jul 27 18:12:12 2006 WATANABE Hirofumi * time.c: need to declare time_utc_offset. Thu Jul 27 17:01:01 2006 Yukihiro Matsumoto * io.c (io_close): always calls "close" method of the receiver. [ruby-core:6911] [ruby-core:8112] Thu Jul 27 16:49:01 2006 Yukihiro Matsumoto * time.c (time_to_s): use +0900 style timezone string for local time. [ruby-dev:29143] Thu Jul 27 16:41:15 2006 Yukihiro Matsumoto * ext/openssl/ossl.h: move inclusion point to shut up Solaris compiler. [ruby-core:08114] Wed Jul 26 22:20:59 2006 Yukihiro Matsumoto * configure.in: add support for as and ASFLAGS. [ruby-dev:29138] Wed Jul 26 22:13:45 2006 Minero Aoki * lib/net/http.rb: sync with HEAD (rev 1.132). * lib/net/http.rb (Net::HTTP#post, request_post, request): should set Content-Type: x-www-form-urlencoded by default. * lib/net/http.rb (Net::HTTPHeader#content_type): should return nil when there's no Content-Type. * lib/net/http.rb (Net::HTTPHeader#sub_type): should return nil when there's no sub Content-Type (e.g. "Content-Type: text"). * lib/net/http.rb (Net::HTTPHeader#type_params): wrongly failed when there's no Content-Type. Wed Jul 26 18:35:38 2006 Minero Aoki * ext/strscan/strscan.c: sync with HEAD (rev 1.25). * ext/strscan/strscan.c (strscan_do_scan): StringScanner.new("").scan(//) should return "". [ruby-Bugs:4361] Wed Jul 26 18:14:19 2006 Nobuyoshi Nakada * ext/pty/pty.c (getDevice): retry once after GC on failure. [ruby-core:08282] Wed Jul 26 17:28:16 2006 Nobuyoshi Nakada * sprintf.c (rb_f_sprintf): prepend ".." to %u for negative bignum, but not "-". fixed: [ruby-core:08167] Wed Jul 26 16:39:07 2006 Yukihiro Matsumoto * string.c (rb_str_scan): add string modification check. [ruby-core:7216] Wed Jul 26 16:06:03 2006 Yukihiro Matsumoto * lib/cgi.rb (CGI::QueryExtension::read_multipart): check multipart boundary end. a patch from Fujioka [ruby-dev:28470] Wed Jul 26 01:02:59 2006 Nobuyoshi Nakada * configure.in: suppress warnings by automake 1.8 or later. Tue Jul 25 00:30:06 2006 Eric Hodel * lib/prettyprint.rb: RD to RDoc conversion by Hugh Sasse. Tue Jul 25 14:49:51 2006 NAKAMURA Usaku * lib/mkmf.rb (configuration): typo. Tue Jul 25 13:14:32 2006 Yukihiro Matsumoto * process.c (rb_proc_times): rename hz to hertz to avoid name crash on AIX. [ruby-dev:29126] Mon Jul 24 22:03:40 2006 Nobuyoshi Nakada * eval.c (backtrace): skip frames successive on node and method name. Mon Jul 24 17:55:55 2006 Yukihiro Matsumoto * process.c (rb_f_system): add security check. [ruby-talk:202947] * process.c (rb_f_system): move signal right before fork to avoid signal handler intervention. Mon Jul 24 15:51:52 2006 Tanaka Akira * ext/readline/readline.c (readline_readline): rl_deprep_term_function may be NULL with libedit. reported by Ryan Davis. [ruby-dev:29070] Mon Jul 24 15:19:55 2006 Yukihiro Matsumoto * eval.c (rb_call0): revert last change. [ruby-dev:29112] [ruby-core:08374] Sun Jul 23 22:59:49 2006 Tanaka Akira * test/socket/test_unix.rb: disabled on cygwin. reported by Kouhei Yanagita. [ruby-dev:29080] Fri Jul 21 21:21:08 2006 Nobuyoshi Nakada * eval.c (rb_call0): include funcalled methods in caller list. fixed: [ruby-core:08290] Fri Jul 21 12:11:00 2006 Nobuyoshi Nakada * ext/extmk.rb, lib/mkmf.rb (with_destdir): remove drive letter before prepending destdir on DOSISH. Thu Jul 20 15:07:14 2006 Yukihiro Matsumoto * ruby.h: export classes/modules to implement sandbox. [ruby-core:08283] Thu Jul 20 00:06:29 2006 Keiju Ishitsuka * lib/irb/completion.rb: support for completion of numeric number. [ruby-dev: 29038] Wed Jul 19 23:53:05 2006 Kouhei Sutou * lib/rss/parser.rb, lib/rss/utils.rb: added documents. Tue Jul 18 22:10:13 2006 Yukihiro Matsumoto * process.c (rb_f_system): block SIGCHLD during the process execution, like glibc system(3) does. [ruby-talk:202361] Tue Jul 18 23:12:14 2006 NAKAMURA Usaku * win32/win32.c (open_ifs_socket): should not use plain malloc. * win32/win32.c (rb_w32_opendir): should not use plain realloc. Tue Jul 18 18:05:49 2006 Yukihiro Matsumoto * test/ruby/test_float.rb (TestFloat::test_strtod): update test to conform strtod change. Tue Jul 18 15:49:42 2006 Yukihiro Matsumoto * pack.c (pack_unpack): propagate association array to copied string. [ruby-core:08223] * pack.c (pack_unpack): return referenced string itself if it has same length as specified. a patch from in [ruby-core:08225]. * pack.c (pack_pack): taint 'p' packed strings. Tue Jul 18 14:03:02 2006 Yukihiro Matsumoto * lib/webrick/httpserver.rb (WEBrick::HTTPServer::unmount): remove inpect argument from sprintf. [ruby-dev:29039] Tue Jul 18 10:53:37 2006 Nobuyoshi Nakada * object.c (rb_cstr_to_dbl): limit out-of-range message. * util.c (ruby_strtod): return end pointer even if ERANGE occurred. fixed: [ruby-dev:29041] Mon Jul 18 00:43:05 2006 Nobuyoshi Nakada * util.c (ruby_strtod): stop at dot not followed by digits. fixed: [ruby-dev:29035] Tue Jul 18 00:01:27 2006 Nobuyoshi Nakada * ext/extmk.rb: remove LIBRUBY_SO if static linked extensions exist. Mon Jul 17 23:30:46 2006 Nobuyoshi Nakada * configure.in (rb_cv_msvcrt): defaulted to msvcrt. Workaround for a bug of cygwin 1.5.20. Mon Jul 17 13:43:05 2006 Yukihiro Matsumoto * pack.c (define_swapx): should not use plain malloc. Mon Jul 17 12:58:41 2006 WATANABE Hirofumi * configure.in: should use ac_cv_lib_dl_dlopen=no on MinGW. Sat Jul 15 23:50:12 2006 Nobuyoshi Nakada * eval.c (rb_require_safe): wait for another thread requiring the same feature. fixed: [ruby-core:08229] Sat Jul 15 01:27:13 2006 Nobuyoshi Nakada * dir.c (has_magic): glob names contain alphabets to enable case fold search also for directories. fixed: [ruby-talk:201917] Sat Jul 15 01:09:22 2006 Yukihiro Matsumoto * st.c (malloc): use xmalloc/xcalloc instead of plain malloc/calloc, to detect memory allocation failure. see . * gc.c (rb_memerror): should not raise empty nomem_error. Fri Jul 14 13:08:13 2006 Hidetoshi NAGAI * ext/tk/lib/tk.rb: add methods for new features of latest Tcl/Tk8.5. * ext/tk/lib/tk/namespace.rb: ditto. Fri Jul 14 02:30:12 2006 Yukihiro Matsumoto * lib/monitor.rb: document patch from Hugh Sasse . [ruby-core:08205] Fri Jul 14 01:09:46 2006 Yukihiro Matsumoto * parse.y (then): error in warning action. Fri Jul 14 00:10:15 2006 Yukihiro Matsumoto * array.c (rb_ary_pop): may cause realloc oscillation. a patch from MORITA Naoyuki . [ruby-dev:29028] Thu Jul 13 22:23:56 2006 Hidetoshi NAGAI * ext/tk/lib/tk/composite.rb: improve handling of the classname on the option database for the widget class which includes TkComposite. Thu Jul 13 20:32:19 2006 Kouhei Sutou * lib/rss/parser.rb: updated documents by a patch from Hugh Sasse . [ruby-core:8194] Wed Jul 12 13:54:09 2006 Yukihiro Matsumoto * parse.y (then): we'd like to reserve colon here for the future. warning added. Tue Jul 11 20:58:18 2006 Yukihiro Matsumoto * ruby.h: export rb_cMethod. [ruby-talk:201259] Tue Jul 11 19:13:33 2006 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: remove restriction on the class of pseudo-toplevel. Tue Jul 11 18:00:57 2006 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: security fix. Tue Jul 11 17:33:39 2006 NAKAMURA Usaku * string.c (rb_str_dump): need to extend len for \b. Mon Jul 10 22:00:00 2006 Shigeo Kobayashi * ext/bigdecimal/bigdecimal.c: Allows '_' to appear within digits. [ruby-dev:28872] * ext/bigdecimal/lib/bigdecimal/util.rb: Bug in to_r reported by [ruby-list:42533] fixed. Mon Jul 10 19:22:19 2006 Tanaka Akira * gc.c (gc_sweep): expand heap earlier. reported by MORITA Naoyuki. [ruby-dev:28960] Mon Jul 10 18:59:34 2006 Hidetoshi NAGAI * ext/tk/lib/tk/font.rb: sorry. mistaken to patch. Mon Jul 10 18:46:52 2006 Hidetoshi NAGAI * ext/tk/tcltklib.c: make SEGV risk lower at exit. * ext/tk/lib/tk.rb: ditto. * ext/tk/lib/multi-tk.rb: fail to call function-style methods on slave interpreters. The strategy (MultiTkIp_PseudoToplevel_Evaluable) to fix the problem is a little tricky. You may have to take care of conflicting with it. * ext/tk/lib/tk.rb: a little change for the pseudo-toplevel strategy. * ext/tk/lib/tk/font.rb: ditto. * ext/tk/lib/tk/msgcat.rb: ditto. * ext/tk/lib/tkextlib/itk/incr_tk.rb: ditto. * ext/tk/sample/demos-en/widget: fail to call function-style methods on sample scripts. To fix it, a strategy which similar to the way on MultiTiIp is used. Please take care when re-write and re-run a demo script on the Widget-Demo code viewer. * ext/tk/sample/demos-jp/widget: ditto. Mon Jul 10 13:58:40 2006 Hidetoshi NAGAI * signal.c (ruby_nativethread_signal, posix_nativethread_signal, sigsend_to_ruby_thread, install_nativethread_sighandler): nativethread-support on signal handler. RE-backport from 1.9. * ruby.h (HAVE_NATIVETHREAD_KILL): ditto. * eval.c (ruby_native_thread_kill): ditto. Mon Jul 10 10:54:14 2006 Ryan Davis * lib/rdoc/parsers/parse_f95.rb: massive overhaul from Yasuhiro Morikawa including new file suffixes, function support, public variables and constants, derived-types, defined operators and assignments, namelists, and subroutine and function arguments. Truly massive. * lib/rdoc/diagram.rb: diagrams are now cached. * lib/irb/completion.rb: fixed a crasher when completing against an unnamed class/module. * lib/rdoc/parsers/parse_c.rb: private comment (--/++) support in C-file rdoc. * lib/debug.rb: minor clarification in help. * lib/pp.rb: minor clarification on exception. Mon Jul 10 09:29:12 2006 Nobuyoshi Nakada * eval.c (rb_clear_cache_for_undef): clear entries for included module. fixed: [ruby-core:08180] Mon Jul 10 01:48:38 2006 Yukihiro Matsumoto * st.h (st_data_t): use pointer sized integer for st_data_t. [ruby-dev:28988] Sun Jul 9 18:06:47 2006 Nobuyoshi Nakada * lib/mkmf.rb (try_constant): fix for value 1 at cross compiling. * lib/mkmf.rb (create_makefile): prevent substitution of macro definition. fixed: http://www.yotabanana.com/lab/20060624.html#p02 Sun Jul 9 00:54:34 2006 Nobuyoshi Nakada * eval.c (next_jump): deal with destination of next. fixed: [ruby-core:08169] Fri Jul 7 00:38:49 2006 Yukihiro Matsumoto * hash.c (rb_hash_default): should not call default procedure if no key is given. [ruby-list:42541] Fri Jul 7 00:29:10 2006 Yukihiro Matsumoto * time.c (time_mload): a patch from Daniel Berger . [ruby-core:08128] Thu Jul 6 22:21:57 2006 Nobuyoshi Nakada * process.c (rb_proc_times): use sysconf(_SC_CLK_TCK) value prior to HZ and CLK_TCK. fixed: [ruby-talk:200293] Thu Jul 6 22:17:21 2006 Minero Aoki * ext/racc/cparse/cparse.c: sync with original code, rev 1.8. * ext/racc/cparse/cparse.c: should mark CparseParams objects. * lib/racc/parser.rb: sync with original code, rev 1.8. * lib/racc/parser.rb: update coding style. Mon Jul 3 19:04:38 2006 Hidetoshi NAGAI * ext/tk/tcltklib.c (ip_make_menu_embeddable): help to make a menu widget embeddable (pack, grid, and so on) like as a general widget. However, an embeddable menu may require to be definied some event bindings for general use. * ext/tk/lib/tk/event.rb: [bug fix] Tk.callback_break and Tk.callback_continue don't work on MultiTkIp. * ext/tk/lib/multi-tk.rb: ditto. * ext/tk/lib/tk.rb: lack of Tk.callback_return. * ext/tk/lib/tk/menu.rb: improve creating clone menus. Mon Jul 3 14:42:06 2006 Nobuyoshi Nakada * ext/etc/extconf.rb (PW_UID2VAL, PW_GID2VAL): defaulted to conversion from int, and sys/types.h needs to be included before grp.h. fixed: [ruby-dev:28938] Mon Jul 3 01:14:15 2006 Yukihiro Matsumoto * string.c (rb_str_inspect): encode \b (\010) for escape. [ruby-dev:28927] * string.c (rb_str_dump): ditto. Sun Jul 2 19:17:56 2006 Minero Aoki * ext/racc/cparse/cparse.c: sync with original code (rev 1.7). * ext/racc/cparse/cparse.c: use rb_catch instead of rb_iterate. Giving a block to a Ruby-level method by rb_iterate is obsolete on Ruby 1.9. Note that current cparse.c still includes one rb_iterate call on Ruby 1.8, but it is not a problem (at least just now). Sat Jul 1 15:15:49 2006 Tanaka Akira * test/socket/test_nonblock.rb: add timeout to send/receive an empty UDP packet. [ruby-dev:28820] Fri Jun 30 23:46:23 2006 Yukihiro Matsumoto * configure.in: should test isinf for Solaris with GCC compiler. a patch from . [ruby-core:07791] * configure.in: -shared patch from Andrew Morrow . [ruby-core:08100] Thu Jun 29 18:58:51 2006 Yukihiro Matsumoto * ext/bigdecimal/bigdecimal.c (BigDecimal_version): fix patch failure. Thu Jun 29 18:00:51 2006 Yukihiro Matsumoto * ext/bigdecimal/bigdecimal.c: add RDoc document. a patch from mathew . [ruby-core:07050] Wed Jun 28 15:47:14 2006 Eric Hodel * lib/optparse.rb: RDoc patch from Robin Stocker [ruby-core:08087] Wed Jun 28 19:04:34 2006 Tanaka Akira * test/socket/test_unix.rb: test_seqpacket_pair removed. [ruby-dev:28846] Tue Jun 27 23:03:49 2006 Yukihiro Matsumoto * string.c: RDoc update for =~ method. a patch from Alex Young . [ruby-core:08068] Tue Jun 27 22:47:18 2006 Hidetoshi NAGAI * ext/tk/tcltklib.c: forgot to update TCLTKLIB_RELEASE_DATE. * ext/tk/lib/tk.rb (tk_tcl2ruby): [bug fix] sometimes fail to convert a tcl string to a ruby object if the tcl string includes "\n". Tue Jun 27 16:04:05 2006 WATANABE Hirofumi * win32/win32.h: define isascii on MinGW for msvcrt compatibility. * configure.in: set ac_cv_header_sys_time_h=no on MinGW for msvcrt compatibility. Tue Jun 27 11:36:02 2006 Nobuyoshi Nakada * ext/etc/etc.c (setup_passwd, setup_group): allow bignum uid, gid and so on. [ruby-talk:199102] Mon Jun 26 13:37:27 2006 Eric Hodel * lib/rdoc: Merge from HEAD. Add options to limit the ri search path. Tue Jun 27 00:54:08 2006 Nobuyoshi Nakada * util.c (powersOf10): constified. Mon Jun 26 18:37:44 2006 Hidetoshi NAGAI * ext/tk/tcltklib.c (ip_delete): fix SEGV when a slave-ip is deleted on callback. Mon Jun 26 10:47:42 2006 Yukihiro Matsumoto * io.c (pipe_open): avoid closing uninitialized file descriptors. a patch from [ruby-dev:28600] Mon Jun 26 09:56:22 2006 NAKAMURA Usaku * win32/win32.[ch] (rb_w32_send, rb_w32_sendto): constified. Sun Jun 25 23:02:12 2006 Nobuyoshi Nakada * Makefile.in, mkconfig.rb: catch-up for latest autoconf. Sat Jun 24 06:35:00 2006 Hidetoshi NAGAI * signal.c: revert last change. * ruby.h: ditto. * eval.c: ditto. Thu Jun 22 11:52:02 2006 Yukihiro Matsumoto * lib/net/http.rb (Net::HTTPResponse): duplicated error 501; HTTPInternalServerError should be error 500. [ruby-core:08037] Thu Jun 22 05:15:58 2006 Tanaka Akira * ext/socket/socket.c (sock_s_socketpair): try GC only once. [ruby-dev:28778] Wed Jun 21 21:28:32 2006 Tadayoshi Funaba * lib/date.rb (jd_to_commercial): now works fine even if in mathn-ized context. Wed Jun 21 17:32:31 2006 Hidetoshi NAGAI * signal.c (ruby_nativethread_signal, posix_nativethread_signal, sigsend_to_ruby_thread, install_nativethread_sighandler): nativethread-support on signal handler (backport from 1.9). * ruby.h (HAVE_NATIVETHREAD_KILL): ditto. * eval.c (ruby_native_thread_kill): ditto. Wed Jun 21 08:39:54 2006 Yukihiro Matsumoto * lib/xmlrpc/create.rb (XMLRPC::Create::conv2value): merge Date and Time processing. [ruby-core:08033] Wed Jun 21 01:40:25 2006 Nobuyoshi Nakada * parse.y (yylex, reswords): modifier token is no longer returned in fname state. [ruby-dev:28775] Wed Jun 21 01:12:46 2006 Kouhei Sutou * lib/rss/rss.rb: RSS::Element.def_corresponded_attr_writer supported date type. Tue Jun 20 22:08:36 2006 Kouhei Sutou * test/rss/test_parser.rb: split parser tests into ... * test/rss/test_parser_1.0.rb: ... RSS 1.0 parsing tests and ... * test/rss/test_parser_2.0.rb: ... RSS 2.0 parsing tests. Tue Jun 20 21:19:06 2006 Kouhei Sutou * lib/rss/rss.rb: provided default RSS::Element#children. * lib/rss/0.9.rb: used default RSS::Element#children. * lib/rss/1.0.rb: ditto. * lib/rss/2.0.rb: ditto. * lib/rss/taxonomy.rb: ditto. Tue Jun 20 21:04:33 2006 Kouhei Sutou * lib/rss/rss.rb: provided default RSS::Element#_tags. * lib/rss/0.9.rb: used default RSS::Element#_tags. * lib/rss/1.0.rb: ditto. * lib/rss/2.0.rb: ditto. * lib/rss/image.rb: ditto. * lib/rss/taxonomy.rb: ditto. Tue Jun 20 20:47:07 2006 Kouhei Sutou * lib/rss/rss.rb: hide RSS::Element.install_model. (RSS::Element.install_have_child_element, RSS::Element.install_have_children_element, RSS::Element.install_text_element, RSS::Element.install_date_element): call RSS::Element.install_model internally. * lib/rss/0.9.rb: followed new API. * lib/rss/1.0.rb: ditto. * lib/rss/2.0.rb: ditto. * lib/rss/content.rb: ditto. * lib/rss/dublincore.rb: ditto. * lib/rss/image.rb: ditto. * lib/rss/syndication.rb: ditto. * lib/rss/taxonomy.rb: ditto. * lib/rss/trackback.rb: ditto. Tue Jun 20 20:18:05 2006 GOTOU Yuuzou * ext/openssl/extconf.rb: add check for OBJ_NAME_do_all_sorted. * ext/openssl/ossl_cipher.c (ossl_s_ciphers): new method OpenSSL::Cipher.ciphers. it returns all the cipher names. * ext/openssl/lib/openssl/cipher.rb: - add constants AES128, AES192, AES256. [ruby-dev:28610] - reimplement without eval() * ext/openssl/lib/openssl/digest.rb: reimplement without eval(). * test/openssl/test_cipher.rb, test_digest: fix about reimplemented features. * sample/openssl/cipher.rb: rewrite all. Sat Jun 19 11:21:46 2006 Eric Hodel * lib/test/unit/assertions.rb: Merge RDoc from HEAD. Tue Jun 20 01:06:57 2006 Kouhei Sutou * lib/rss/rss.rb: - cleanup validation mechanism. Now, #XXX_validation is needless. - changed internal variable name RSS::Element::MODEL to RSS::Element::MODELS. - RSS::Element.install_model requires uri. * lib/rss/0.9.rb: followed new validation API. * lib/rss/1.0.rb: ditto. * lib/rss/2.0.rb: ditto. * lib/rss/content.rb: ditto. * lib/rss/dublincore.rb: ditto. * lib/rss/image.rb: ditto. * lib/rss/syndication.rb: ditto. * lib/rss/taxonomy.rb: ditto. * lib/rss/trackback.rb: ditto. Mon Jun 19 23:40:59 2006 NARUSE, Yui * ext/nkf/lib/kconv.rb: remove default -m0 and fix document. * ext/nkf/nkf-8/{nkf.c, config.h, utf8tbl.c, utf8tbl.h}: imported nkf 2.0.7. Mon Jun 19 22:31:59 2006 Kouhei Sutou * lib/rss/rss.rb: - provided default #to_s as RSS::Element#to_s. - removed RSS::Element#other_element. - RSS::Element#tag requires attributes as Hash instead of Array. * lib/rss/0.9.rb: removed #to_s to use RSS::Element#to_s. * lib/rss/1.0.rb: ditto. * lib/rss/image.rb: ditto. * lib/rss/taxonomy.rb: ditto. * lib/rss/trackback.rb: ditto. * lib/rss/2.0.rb: removed #other_element. Mon Jun 19 22:09:16 2006 Masaki Suketa * ext/win32ole/win32ole.c(ole_invoke): support some kind of method of word. [ruby-Bugs#3237] * ext/win32ole/tests/test_word.rb: ditto. * ext/win32ole/tests/testall.rb: ditto. Mon Jun 19 00:02:17 2006 Kouhei Sutou * lib/rss/rss.rb: automatically detected attributes. * lib/rss/0.9.rb: removed #_attrs. * lib/rss/1.0.rb: ditto. * lib/rss/2.0.rb: ditto. * lib/rss/image.rb: ditto. * lib/rss/taxonomy.rb: ditto. * lib/rss/trackback.rb: ditto. * lib/rss/parser.rb: followed new internal API. Mon Jun 19 00:00:17 2006 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: fix bug: initialize improper tables. Sun Jun 18 22:36:13 2006 Kouhei Sutou * lib/rss/rss.rb: RSS::Element#initialize accepts initial attributes. * lib/rss/0.9.rb: ditto. * lib/rss/1.0.rb: ditto. * lib/rss/2.0.rb: ditto. * lib/rss/dublincore.rb: ditto. * lib/rss/image.rb: ditto. * lib/rss/taxonomy.rb: ditto. * lib/rss/trackback.rb: ditto. * lib/rss/utils.rb: added Utils.element_initialize_arguments? to detect backward compatibility initial arguments. * lib/rss/parser.rb: user initial attributes to initialize RSS::Element. Sun Jun 18 18:24:42 2006 Kouhei Sutou * lib/rss/converter.rb: use NKF for Uconv fallback. Sun Jun 18 18:22:04 2006 Kouhei Sutou * test/rss/test_image.rb: shared name space configuration. Sun Jun 18 18:13:25 2006 Kouhei Sutou * lib/rss/rss.rb: improved ignore_unknown_element handling. RSS::NotExpectedTagError provides tag URI. * lib/rss/parser.rb: ditto. * lib/rss/0.9.rb: ditto. * lib/rss/1.0.rb: ditto. * lib/rss/content.rb: ditto. * lib/rss/dublincore.rb: ditto. * lib/rss/image.rb: ditto. * lib/rss/syndication.rb: ditto. * lib/rss/taxonomy.rb: ditto. * lib/rss/trackback.rb: ditto. * test/rss/rss-assertions.rb: checked URI of not expected tag too. * test/rss/test_parser.rb: ditto. Sun Jun 18 18:08:36 2006 Kouhei Sutou * lib/rss/rss.rb: changed empty namespace URI representation to "" from nil. * lib/rss/parser.rb: ditto. * lib/rss/0.9.rb: ditto. * lib/rss/1.0.rb: ditto. * lib/rss/2.0.rb: ditto. Sun Jun 18 18:03:50 2006 Kouhei Sutou * lib/rss/parser.rb: removed a guard for requiring open-uri. Sun Jun 18 18:01:26 2006 Kouhei Sutou * lib/rss/rss.rb: fixed typo: except -> expect * lib/rss/parser.rb: ditto. * test/rss/rss-assertions.rb: ditto. * test/rss/test_parser.rb: ditto. Sun Jun 18 17:52:39 2006 Kouhei Sutou * lib/rss/rss.rb: RSS::Element#calc_indent became to be deprecated. * lib/rss/0.9.rb: ditto. * lib/rss/1.0.rb: ditto. * lib/rss/image.rb: ditto. * lib/rss/taxonomy.rb: ditto. * lib/rss/trackback.rb: ditto. * test/rss/test_1.0.rb: removed RSS::Element.indent_size tests. * test/rss/test_2.0.rb: ditto. Sun Jun 18 00:49:11 2006 Tanaka Akira * ext/socket/socket.c (bsock_recv_nonblock): new method BasicSocket#recv_nonblock. (udp_recvfrom_nonblock): renamed from ip_recvfrom_nonblock. IPSocket#recvfrom_nonblock is moved to UDPSocket#recvfrom_nonblock. (unix_recvfrom_nonblock): removed. UNIXSocket#recvfrom_nonblock is removed. Sat Jun 17 22:17:17 2006 Yukihiro Matsumoto * lib/mathn.rb (Integer::prime_division): raise ZeroDivisionError on zeros. [ruby-dev:28739] Sat Jun 17 14:53:32 2006 Tanaka Akira * lib/pathname.rb: backport from 1.9. (Kernel#Pathname): new method. Sat Jun 17 10:30:41 2006 Kouhei Sutou * lib/rss/rss.rb (Hash#merge, Enumerable#sort_by): removed. * lib/rss/rss.rb (RSS::RootElementMixin#to_xml): added. [ruby-talk:197284] We can convert RSS version easily like the following: rss10 = RSS::Parser.parse(File.read("1.0.rdf")) File.open("2.0.rss", "w") {|f| f.print(rss10.to_xml("2.0"))} * test/rss/test_1.0.rb: added #to_xml test. * test/rss/test_2.0.rb: ditto. * test/rss/rss-testcase.rb: added some helper methods that generates sample RSS 2.0. * sample/rss/convert.rb: added a sample script to convert RSS format. Sat Jun 17 10:23:22 2006 Kouhei Sutou * lib/rss/rss.rb (Kernel#funcall): removed. * lib/rss/parser.rb (Kernel.URI): removed. * lib/rss/maker/: supported xxx.new_yyy do |yyy| yyy.zzz = zzz ... end style and this style became the style of the recommendation. Old style yyy = xxx.new_yyy yyy.zzz = zzz ... is supported too but this style isn't recommended. [ruby-talk:197284] * test/rss/test_*maker*.rb: used new recommended style. Sat Jun 17 09:03:47 2006 Kouhei Sutou * lib/rss, test/rss: backported from trunk. (2005-11-16 - now) * lib/rss/rss.rb (RSS::VERSION): 0.1.5 -> 0.1.6. * test/rss/test_version.rb (RSS::TestVersion#test_version): ditto. * lib/rss/trackback.rb: added TrackBack prefix. * lib/rss/maker/trackback.rb: ditto. * lib/rss/rss.rb : removed needless argument 'prefix'. * lib/rss/parser.rb: ditto. * lib/rss/1.0.rb: added rdf:Bag. * lib/rss/taxonomy.rb: implemented taxonomy module. * test/rss/test_taxonomy.rb: added tests for taxonomy support. * lib/rss/1.0.rb: added convenience method 'resources'. * lib/rss/taxonomy.rb: ditto. * test/rss/rss-assertions.rb: added test for 'resources'. * test/rss/test_taxonomy.rb: ditto. * lib/rss/rss.rb: fixed a indentation bug. * lib/rss/taxonomy.rb: fixed #to_s bug. * test/rss/test_taxonomy.rb: added a #to_s test. * lib/rss/maker/taxonomy.rb: implemented taxonomy module for RSS Maker. * lib/rss/taxonomy.rb: supported RSS Maker. * lib/rss/maker.rb: added taxonomy module support. * lib/rss/rss.rb: adjusted to other element API. * lib/rss/1.0.rb: adjusted to other element API but backward compatibility is reserved. * lib/rss/0.9.rb: ditto. * test/rss/test_maker_taxo.rb: added test case for taxonomy module for RSS Maker. * test/rss/test_setup_maker_1.0.rb: added tests for taxo:topic. * test/rss/test_setup_maker_1.0.rb: added backward compatibility test. * test/rss/test_setup_maker_0.9.rb: ditto. * test/rss/test_setup_maker_2.0.rb: ditto. * test/rss/rss-testcase.rb: added convenience method for setting up taxo:topic. * test/rss/rss-assertions.rb: added assertion for taxo:topic. * sample/rss/blend.rb: followed new API. * lib/rss/taxonomy.rb: changed class or module prefix to Taxonomy from Taxo. * lib/rss/maker/taxonomy.rb: ditto. * test/rss/test_taxonomy.rb: use #reject directory. * lib/rss/: use #__send__ instead of #send. * test/rss/: ditto. * lib/rss/parser.rb: added entity handling type predicate. * lib/rss/rexmlparser.rb: ditto. * lib/rss/xmlparser.rb: ditto. * lib/rss/xmlscanner.rb: ditto. * lib/rss/xmlscanner.rb: more robust entity handling. * test/rss/test_parser.rb: added an entity handling test. * test/rss/test_2.0.rb: added RSS 2.0 tests. * test/rss/rss-assertions.rb: extended XML stylesheet assertion. * lib/rss/0.9.rb: added initialize method. * test/rss/test_1.0.rb: cleanup. * lib/rss/image.rb: added Image prefix. * lib/rss/maker/image.rb: ditto. * lib/rss/rss.rb: improved type conversion. * lib/rss/1.0.rb: ditto. * lib/rss/0.9.rb: ditto. * lib/rss/2.0.rb: ditto. * lib/rss/image.rb: ditto. * lib/rss/syndication.rb: ditto. * test/rss/test_2.0.rb: added type conversion tests. * test/rss/test_accessor.rb: ditto. * test/rss/test_to_s.rb: ditto. * test/rss/test_syndication.rb: ditto. * test/rss/test_setup_maker_2.0.rb: ditto. * test/rss/test_setup_maker_1.0.rb: ditto. * test/rss/test_setup_maker_0.9.rb: ditto. * test/rss/test_maker_sy.rb: ditto. * test/rss/test_maker_image.rb: ditto. * test/rss/test_maker_2.0.rb: ditto. * test/rss/test_maker_0.9.rb: ditto. * test/rss/test_image.rb: ditto. * test/rss/test_maker_1.0.rb: use assert instead of assert_equal. * test/rss/rss-assertions.rb: improved type conversion assertions. * lib/rss/rss.rb: added backward compatibility codes. * lib/rss/parser.rb: ditto. * test/rss/test_parser.rb: ditto. * test/rss/test_2.0.rb: ditto. Sat Jun 17 02:01:00 2006 Tanaka Akira * lib/pp.rb (Kernel#pretty_inspect): defined for pretty printed string. Sat Jun 17 00:23:58 2006 Nobuyoshi Nakada * parse.y (reswords): kDO_BLOCK was missing. fixed: [ruby-core:7995] Sat Jun 17 00:02:15 2006 Masaki Suketa * ext/win32ole/win32ole.c (ole_propertyput): support PROPERTYPUTREF. [ruby-talk:183042] * ext/win32ole/tests/test_propertyputref.rb: ditto. Thu Jun 15 23:02:47 2006 Masaki Suketa * ext/win32ole/win32ole.c (fole_methods): The return value of WIN32OLE#ole_methods should include PROPERTYPUTREF methods. * ext/win32ole/win32ole.c (fole_put_methods): The return value of WIN32OLE#ole_put_methods should include PROPERTYPUTREF methods. * ext/win32ole/tests/test_ole_methods.rb: ditto. * ext/win32ole/tests/testall.rb : ditto. Wed Jun 14 18:23:28 2006 Eric Hodel * enum.c (enum_any): Documentation typo. Wed Jun 14 15:01:09 2006 Eric Hodel * lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser#warn): Don't print warnings when -q is set. Wed Jun 14 23:03:53 2006 Tanaka Akira * configure.in: check sizeof(rlim_t). check setrlimit. * process.c (proc_getrlimit): new method Process.getrlimit. (proc_setrlimit): new method Process.setrlimit. * ruby.h (NUM2ULL): new macro. Mon Jun 12 22:25:09 2006 Yukihiro Matsumoto * sprintf.c (rb_f_sprintf): adjust precision length to prevent splitting multi-byte characters. [ruby-list:42389] Sun Jun 11 23:20:07 2006 Nobuyoshi Nakada * lib/optparse.rb (OptionParser::Arguable#getopts): pass self to the parser. Sun Jun 11 10:00:57 2006 NAKAMURA Usaku * win32/win32.h (write): not need to define on bcc. Sun Jun 11 08:30:33 2006 Nobuyoshi Nakada * lib/optparse.rb (OptionParser#getopts): new methods. Sat Jun 10 18:02:40 2006 Yukihiro Matsumoto * ext/bigdecimal/lib/bigdecimal/newton.rb (Newton::nlsolve): typo fixed: raize -> raise. [ruby-talk:196608] Thu Jun 8 14:19:17 2006 NAKAMURA Usaku * win32/win32.[ch] (rb_w32_read, rb_w32_write): new functions. use recv() and send() when fd is socket. fixed: [ruby-dev:28694] Wed Jun 7 16:22:51 2006 Yukihiro Matsumoto * lib/tempfile.rb (Tempfile::make_tmpname): put dot between basename and pid. [ruby-talk:196272] Wed Jun 7 14:53:04 2006 NAKAMURA Usaku * win32/win32.c (errmap): add some winsock errors. Wed Jun 7 11:34:38 2006 NAKAMURA Usaku * configure.in: add new configure option `--with-winsock2' for mingw. * win32/Makefile.sub (config.h): define USE_WINSOCK2 in config.h instead of in CPPFLAGS. * ext/socket/extconf.rb: determine whether to use winsock2 or not by using with_config. Wed Jun 7 10:45:10 2006 NAKAMURA Usaku * win32/{configure.bat, setup.mak, Makefile.sub, win32.h}: add new configure option `--with-winsock2'. * win32/win32.c (StartSockets): ditto. * ext/socket/extconf.rb: ditto. * win32/win32.c (open_ifs_socket): new function. * win32/win32.c (StartSockets, rb_w32_socket): use open_ifs_socket() instead of socket(). ifs socket support is backported from trunk. Wed Jun 7 09:14:44 2006 Yukihiro Matsumoto * eval.c (rb_call0): binding for the return event hook should have consistent scope. [ruby-core:07928] * eval.c (EXEC_EVENT_HOOK): trace_func may remove itself from event_hooks. no guarantee for arbitrary hook deletion. [ruby-dev:28632] Mon Jun 5 18:12:12 2006 Tanaka Akira * ext/socket/socket.c (sock_s_unpack_sockaddr_in): reject non-AF_INET/AF_INET6 sockaddr. (sock_s_unpack_sockaddr_un): reject non-AF_UNIX sockaddr. [ruby-dev:28691] Sun Jun 4 20:40:19 2006 Tanaka Akira * ext/socket/socket.c: fix sockaddr_un handling. [ruby-dev:28677] Fri Jun 2 22:08:17 2006 Yukihiro Matsumoto * lib/forwardable.rb: RDoc typo fix from Jan Svitok . [ruby-core:07943] Fri Jun 2 19:02:09 2006 GOTOU Yuuzou * ext/openssl/extconf.rb: use create_header. * ext/openssl/ossl.h, ext/openssl/openssl_missing.h: include RUBY_EXTCONF_H. Fri Jun 2 17:16:52 2006 Nobuyoshi Nakada * lib/mkmf.rb (CLEANINGS): remove extconf.h by distclean if created. Fri Jun 2 00:11:19 2006 Tanaka Akira * ext/socket/socket.c (s_recvfrom): alen may be zero with UNIXSocket too. (tested on NetBSD 3.0) (s_recvfrom_nonblock): extracted from sock_recvfrom_nonblock. (sock_recvfrom_nonblock): use s_recvfrom_nonblock. (ip_recvfrom_nonblock): new method: IPSocket#recvfrom_nonblock (unix_recvfrom_nonblock): new method: UNIXSocket#recvfrom_nonblock (s_accept_nonblock): extracted from sock_accept_nonblock. (sock_accept_nonblock): use s_accept_nonblock. (tcp_accept_nonblock): new method: TCPServer#accept_nonblock (unix_accept_nonblock): new method: UNIXServer#accept_nonblock Thu Jun 1 19:12:37 2006 Nobuyoshi Nakada * win32/win32.c (rb_w32_cmdvector): backslashes inside single-quotes no longer has special meanings. fixed: [ruby-list:42311] Thu Jun 1 16:14:41 2006 NAKAMURA Usaku * win32/win32.c (rb_w32_getcwd): runtime's getcwd() will not success if the length of the cwd is longer than MAX_PATH. fixed [ruby-list:42335] Thu Jun 1 11:29:14 2006 NAKAMURA Usaku * win32/win32.c (rb_w32_getcwd): set errno if not set. fixed [ruby-list:42346] Sat May 27 11:29:46 2006 nobuyoshi nakada * ext/extmk.rb (extmake): remove extinit files if no statically linked extensions. Fri May 26 09:05:11 2006 nobuyoshi nakada * ruby.h, lib/mkmf.rb (create_header): clear command line options for macros moved to extconf.h. * ext/extmk.rb (extract_makefile, extmk): made RUBY_EXTCONF_H and EXTSTATIC permanent. * ext/{dbm,digest/*,socket,zlib}/extconf.rb: used $defs and $INCFLAGS. * {bcc32,win32,wince}/Makefile.sub (COMPILE_C, COMPILE_CXX): added $(INCFLAGS). * lib/mkmf.rb (configuration): add $defs unless extconf.h was created. Thu May 25 01:52:07 2006 nobuyoshi nakada * lib/mkmf.rb (pkg_config): particular config commands support. * ext/extmk.rb: deal with $static set in extconf.rb. * mkconfig.rb: merge multiple entries to an entry with multiple lines. * lib/mkmf.rb: allow a series of commands to link. * win32/Makefile.sub: embed manifests. * win32/setup.mak: suffix OS name by runtime version. Wed May 24 23:52:11 2006 nobuyoshi nakada * configure.in (ac_install_sh): ignore dummy install-sh. [ruby-talk:193876] Wed May 24 03:10:48 2006 GOTOU Yuuzou * ext/openssl/lib/openssl/ssl.rb (OpenSSL::SSL::SocketForwarder#setsockopt,getsockopt): typo fixed. Mon May 22 17:54:12 2006 NAKAMURA Usaku * ext/socket/socket.c (sock_recvfrom_nonblock): use rb_read_pending instead of rb_io_read_pending. [ruby-dev:28663] Mon May 22 17:30:04 2006 Tanaka Akira * rubyio.h (rb_io_set_nonblock): declared. * io.c (rb_io_set_nonblock): new function. (io_getpartial): nonblocking read support. (io_read_nonblock): new method: IO#read_nonblock. (io_write_nonblock): new method: IO#write_nonblock. * ext/socket/socket.c (sock_connect_nonblock): new method: Socket#connect_nonblock. (sock_accept_nonblock): new method: Socket#accept_nonblock. (sock_recvfrom_nonblock): new method: Socket#recvfrom_nonblock. [ruby-core:7917] Mon May 22 15:57:39 2006 Yukihiro Matsumoto * eval.c (umethod_bind): should not update original class. [ruby-dev:28636] Mon May 22 13:38:57 2006 Yukihiro Matsumoto * eval.c (ev_const_get): should support constant access from within instance_eval(). [ruby-dev:28327] Thu May 18 17:51:32 2006 Yukihiro Matsumoto * time.c (time_timeval): should round for usec floating number. [ruby-core:07896] * time.c (time_add): ditto. Thu May 18 17:11:45 2006 Yukihiro Matsumoto * lib/cgi.rb (CGI::out): support utf-8. a patch from Fujioka . [ruby-dev:28649] Thu May 18 00:42:12 2006 nobuyoshi nakada * ext/extmk.rb, lib/mkmf.rb: use BUILD_FILE_SEPARATOR in Makefiles. Wed May 17 17:55:26 2006 Yukihiro Matsumoto * dir.c (sys_warning): should not call a vararg function rb_sys_warning() indirectly. [ruby-core:07886] Wed May 17 08:17:15 2006 Yukihiro Matsumoto * util.c (ruby_strtod): try to reduce errors using powersOf10 table. [ruby-dev:28644] Tue May 16 15:34:18 2006 Yukihiro Matsumoto * re.c (rb_reg_initialize): should not allow modifying literal regexps. frozen check moved from rb_reg_initialize_m as well. Tue May 16 09:20:16 2006 Yukihiro Matsumoto * re.c (rb_reg_initialize): should not modify untainted objects in safe levels higher than 3. * re.c (rb_memcmp): type change from char* to const void*. * dir.c (dir_close): should not close untainted dir stream. * dir.c (GetDIR): add tainted/frozen check for each dir operation. Mon May 15 17:42:39 2006 Yukihiro Matsumoto * lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_symbol_arg): typo fixed. a patch from Florian Gross . Sat May 13 16:14:05 2006 Tanaka Akira * lib/pp.rb (PP.mcall): new method. (Struct#pretty_print): call Kernel#class and Struct#members even if overridden. (Struct#pretty_print_cycle): ditto. [ruby-core:7865] Thu May 11 19:57:00 2006 Yukihiro Matsumoto * util.c (ruby_strtod): differ addition to minimize error. [ruby-dev:28619] Fri Aug 11 15:39:25 2006 Eric Hodel * lib/yaml/tag.rb: Replace nodoc with stopdoc so Module methods get documented. Thu May 11 18:10:43 2006 Yukihiro Matsumoto * util.c (ruby_strtod): should not raise ERANGE when the input string does not have any digits. [ruby-dev:28629] Sun May 7 03:09:51 2006 Stephan Maka * lib/resolv.rb (Resolv::DNS::Requester::ConnectedUDP#initialize): Use AF_INET6 for nameservers containing colons. Sat May 6 00:38:42 2006 Yukihiro Matsumoto * signal.c (trap): sig should be less then NSIG. Coverity found this bug. a patch from Kevin Tew . [ruby-core:07823] Thu May 4 02:24:16 2006 Yukihiro Matsumoto * ext/syck/emitter.c (syck_scan_scalar): avoid accessing uninitialized array element. a patch from Pat Eyler . [ruby-core:07809] * array.c (rb_ary_fill): initialize local variables first. a patch from Pat Eyler . [ruby-core:07810] * ext/syck/yaml2byte.c (syck_yaml2byte_handler): need to free type_tag. a patch from Pat Eyler . [ruby-core:07808] Wed May 3 02:12:07 2006 Yukihiro Matsumoto * ext/socket/socket.c (make_hostent_internal): accept ai_family check from Sam Roberts . [ruby-core:07691] Mon May 1 12:23:19 2006 * numeric.c (num_div): use floor rather than rb_Integer(). [ruby-dev:28589] * numeric.c (flo_divmod): the first element of Float#divmod should be an integer. [ruby-dev:28589] * test/ruby/test_float.rb: add tests for divmod, div, modulo and remainder. Sat Apr 29 22:42:08 2006 GOTOU Yuuzou * ext/openssl/ossl_asn1.c (ossl_asn1_decode0): should initialize flag. [ruby-core:07785] Fri Apr 28 10:53:16 2006 Yukihiro Matsumoto * util.c (ruby_strtod): should not cut off 18 digits for no reason. [ruby-core:07796] * util.c (ruby_strtod): fixed wrong conversion. Thu Apr 27 01:38:10 2006 Yukihiro Matsumoto * array.c (rb_ary_fill): internalize local variable "beg" to pacify Coverity. [ruby-core:07770] Wed Apr 26 16:59:24 2006 Yukihiro Matsumoto * pack.c (pack_unpack): now supports CRLF newlines. a patch from . [ruby-dev:28601] Tue Apr 25 18:00:05 2006 Hidetoshi NAGAI * ext/tk/tcltklib.c (delete_slaves): maybe increment the reference count of a NULL Tcl_Obj [ruby-core:07759]. Tue Apr 25 07:55:31 2006 Yukihiro Matsumoto * lib/jcode.rb (String::tr_s): should have translated non squeezing character sequence (i.e. a character) as well. thanks to Hiroshi Ichikawa [ruby-list:42090] Tue Apr 25 00:08:24 2006 Yukihiro Matsumoto * regex.c (re_compile_pattern): should check if c is not a multibyte character. a patch from KIMURA Koichi . [ruby-dev:28598] Fri Apr 21 15:19:13 2006 Hidetoshi NAGAI * ext/tk/tcltklib.c (lib_eventloop_ensure): refer freed pointer [ruby-core:07744] and memory leak. Fri Apr 21 12:14:52 2006 Yukihiro Matsumoto * ext/socket/socket.c: document update patch from Sam Roberts . [ruby-core:07701] Wed Apr 19 13:55:27 2006 Yukihiro Matsumoto * parse.y (arg): too much NEW_LIST() * eval.c (SETUP_ARGS0): remove unnecessary access to nd_alen. Wed Apr 19 11:57:04 2006 Yukihiro Matsumoto * eval.c (rb_eval): use ARGSCAT for NODE_OP_ASGN1. [ruby-dev:28585] * parse.y (list_concat): revert last change. * parse.y (arg): use NODE_ARGSCAT for placeholder. Wed Apr 19 11:13:17 2006 Yukihiro Matsumoto * lib/getoptlong.rb (GetoptLong::get): RDoc update patch from mathew . [ruby-core:07738] Wed Apr 19 10:13:27 2006 Yukihiro Matsumoto * variable.c (rb_const_set): raise error when no target klass is supplied. [ruby-dev:28582] Wed Apr 19 09:49:36 2006 Yukihiro Matsumoto * parse.y (list_concat): should not modify nodes other than NODE_ARRAY. [ruby-dev:28583] Tue Apr 18 17:40:37 2006 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: add a binding to a container for a slave IP. * ext/tk/lib/tk.rb: update RELEASE_DATE. * ext/tk/tcltklib.c: forget to reset a Tcl interpreter. * ext/tk/stubs.c: fix potential bugs about handling rb_argv0. Tue Apr 18 00:11:21 2006 Yukihiro Matsumoto * eval.c: block_unique should be 1, not frame_unique. [ruby-dev:28577] Fri Aug 11 15:39:25 2006 Eric Hodel * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser#find_body): Make RDoc ignore C function prototypes. Patch by Tilman Sauerbeck . [ruby-core:8574] * lib/yaml/tag.rb: Replace nodoc with stopdoc so Module methods get documented. Mon Apr 10 01:03:10 2006 Yukihiro Matsumoto * prec.c (prec_prec_f): documentation patch from . [ruby-core:07689] Sat Apr 8 02:34:34 2006 Yukihiro Matsumoto * bignum.c (rb_big_pow): second operand may be too big even if it's a Fixnum. [ruby-talk:187984] Sat Apr 8 02:12:38 2006 Yukihiro Matsumoto * README.EXT: update symbol description. [ruby-talk:188104] Thu Apr 6 23:28:47 2006 Yukihiro Matsumoto * COPYING: explicitly note GPLv2. [ruby-talk:187922] Thu Apr 6 11:18:37 2006 Hidetoshi NAGAI * ext/tk/lib/tk/panedwindow.rb: lack of arguments. [ruby-core:7681] Thu Apr 6 01:04:47 2006 Hidetoshi NAGAI * ext/tk/tcltklib.c: fix SEGV when embedding to an application. [ruby-core:7600] * ext/tk/tcltklib.c: fix SEGV at exit. [ruby-talk:186489] * ext/tk/tkutil/tkutil.c: follow to changing specification of instance_eval on ruby-1.9.x. * ext/tk/lib/tk.rb: ditto. * ext/tk/lib/multi-tk.rb: ditto. * ext/tk/lib/tk.rb: remove warning about redefinition of methods. * ext/tk/lib/tk/variable.rb: remove warning about unseting Tcl variables. Wed Mar 29 20:54:44 2006 Masaki Suketa * ext/win32ole/win32ole.c (fole_getproperty): WIN32OLE#[] should accept multi arguments. * ext/win32ole/tests/testWIN32OLE.rb (test_setproperty_bracket): ditto. Wed Mar 29 10:07:44 2006 NAKAMURA Usaku * ext/nkf/nkf-utf8/nkf.c (nkf_each_char_to_hex, encode_fallback_subchar, e2w_conv): support C90 compiler. Wed Mar 29 06:48:40 2006 Yukihiro Matsumoto * eval.c (backtrace): reports aliased method names in a generated backtrace. a patch from "U.Nakamura" . [ruby-dev:28471] Mon Mar 27 22:19:09 2006 NARUSE, Yui * ext/nkf/nkf-utf8/{nkf.c, utf8tbl.c, config.h}: imported nkf 2.0.6. * Add --ic / --oc option and mapping tables. * Add fallback option. * Add --no-best-fit-chars option. * Fix some bugs. * ext/nkf/nkf.c (nkf_split_options): added for parse option string. * ext/nkf/lib/kconv.rb (Kconv.to*): add -m0. Note that Kconv.to* still imply -X. Mon Mar 27 03:17:21 2006 Yukihiro Matsumoto * eval.c (rb_call0): insecure calling should be checked for non NODE_SCOPE method invocations too. * eval.c (rb_alias): should preserve the current safe level as well as method definition. Fri Mar 24 23:14:30 2006 Yukihiro Matsumoto * eval.c (yield_under_i): pass self again for instance_eval(). [ruby-dev:28466] Fri Mar 24 17:20:03 2006 Yukihiro Matsumoto * process.c (rb_f_sleep): remove description about SIGALRM which is not valid on the current implementation. [ruby-dev:28464] Thu Mar 23 10:47:03 2006 Yukihiro Matsumoto * eval.c (method_missing): should support argument splat in super. [ruby-talk:185438] Mon Mar 20 12:05:18 2006 Yukihiro Matsumoto * configure.in: Solaris SunPro compiler -rapth patch from . [ruby-dev:28443] Mon Mar 20 09:40:23 2006 Yukihiro Matsumoto * configure.in: remove enable_rpath=no for Solaris. [ruby-dev:28440] Fri Mar 17 19:08:49 2006 GOTOU Yuuzou * ext/openssl/ossl_ssl.c, ext/openssl/ossl_nsspki.c: fix typo. [ruby-core:07571] Wed Mar 15 16:54:21 2006 NAKAMURA Usaku * lib/mkmf.rb (create_makefile): support libraries without *.so. Wed Mar 15 16:35:43 2006 GOTOU Yuuzou * ext/openssl/ossl_ssl.c, ext/openssl/ossl_nsspki.c: should use "rb_str_new(0, 0)" to make empty string. Sat Mar 11 14:24:06 2006 Yukihiro Matsumoto * lib/rdoc/ri/ri_formatter.rb (RI::TextFormatter::wrap): removed space before argument parenthesis. [ruby-talk:183630] * ruby.1: a clarification patch from David Lutterkort . [ruby-core:7508] Sat Mar 4 15:26:40 2006 Tanaka Akira * gc.c (id2ref): fix symbol test. Sat Mar 4 01:08:07 2006 Yukihiro Matsumoto * lib/rdoc/ri/ri_paths.rb (RI::Paths): adding paths from rubygems directories. a patch from Eric Hodel . [ruby-core:07423] Thu Mar 2 19:44:18 2006 Tanaka Akira * gc.c: align VALUE with sizeof(RVALUE) globally. (is_pointer_to_heap): check alignment out of loop. (id2ref): avoid collision between symbols and objects. (rb_obj_id): ditto. moved from object.c. [ruby-talk:178364] [ruby-core:7305] Thu Mar 2 18:58:18 2006 Yukihiro Matsumoto * eval.c (rb_thread_fd_writable): should not re-schedule output from KILLED thread (must be error printing). Thu Mar 2 17:57:49 2006 Hirokazu Yamamoto * gc.c: commited magic for reducing RVALUE size on windows. (24->20byte) [ruby-core:7474] Thu Mar 2 12:59:14 2006 Hirokazu Yamamoto * win32/win32.c (filetime_to_unixtime): should set tm_isdst to -1. stat() didn't treat daylight saving time property on WinNT. [ruby-talk:182100] Thu Mar 2 08:02:42 2006 Yukihiro Matsumoto * gc.c (add_heap): heap_slots may overflow. a patch from Stefan Weil . Wed Mar 1 00:24:31 2006 Hirokazu Yamamoto * lib/rdoc/parsers/parse_rb.rb (read_escape): could not handle /\^/. merged Mr. Ishizuka's lib/irb/ruby-lex.rb 's patch rev 1.29. [ruby-talk:181631] [ruby-dev:28404] Tue Feb 28 09:32:17 2006 NAKAMURA Usaku * lib/drb/extservm.rb (invoke_service_command): cannot invoke command if command name is quoted on mswin32. [ruby-dev:28400] Mon Feb 27 00:19:16 2006 Yukihiro Matsumoto * ruby.h (SYM2ID): should not cast to signed long. [ruby-core:07414] Fri Feb 24 20:07:23 2006 Masatoshi SEKI * test/drb/drbtest.rb (add_service_command): quote pathnames in the server's command line for space contained directory names. Thanks, arton. [ruby-dev:28386] Fri Feb 24 12:11:08 2006 NAKAMURA Usaku * instruby.rb: install *.exe.manifest and *.dll.manifest if exist. It's for VC++8. Fri Feb 24 11:33:52 2006 Hirokazu Yamamoto * bcc32/Makefile.sub (HAVE_HYPOT): bcc32 has hypot(). Fri Feb 24 11:19:58 2006 NAKAMURA Usaku * time.c (time_new_internal): add prototype to tell the compiler arugments types. * win32/win32.c (NtInitialize): need to set a handler for VC++8. Fri Feb 24 08:19:16 2006 NARUSE, Yui * test.rb: Removed. Obsolete by test/nkf. * ext/.document: enabled documents in nkf and kconv * ext/nkf/nkf.c ext/nkf/lib/kconv.rb: Add rdoc. Thu Feb 23 22:39:59 2006 Hirokazu Yamamoto * bcc32/Makefile.sub: use borlndmm.dll if possible. bcc32's RTL internal memory manager cannot handle large memory block properly. ex: 10000.times { "" << "." * 529671; GC.start } # crash [ruby-dev:28230] Thu Feb 23 13:20:28 2006 Hirokazu Yamamoto * eval.c (SETUP_ARGS0): fixed memory corruption. [ruby-dev:28360] Tue Feb 21 02:18:46 2006 NAKAMURA Usaku * configure.in (mingw): have link. [ruby-list:41838] * win32/Makefile.sub (config.h): ditto. Tue Feb 21 02:07:39 2006 Yukihiro Matsumoto * parse.y (f_arglist): should set command_start = Qtrue for command body. [ruby-talk:180648] Mon Feb 20 17:37:26 2006 Tanaka Akira * mkconfig.rb: alias RbConfig for Config. Mon Feb 20 12:27:53 2006 Kent Sibilev * lib/rational.rb (Integer::gcd): small typo fix. [ruby-core:07395] Mon Feb 20 01:05:27 2006 Yukihiro Matsumoto * lib/rational.rb (Integer::gcd): replaced by gcd4 in [ruby-core:07390]. [ruby-core:07377] Mon Feb 20 00:57:02 2006 GOTOU Yuuzou * ext/openssl/ossl.h (OSSL_Debug): should not use __func__. [ruby-dev:28339] Sun Feb 19 04:46:29 2006 Guy Decoux * eval.c: initial value for block_unique must be 1. [ruby-talk:180420] Sat Feb 18 23:58:26 2006 Yukihiro Matsumoto * lib/tracer.rb (Tracer::Tracer.add_filter): turn on tracer mode only when caller() level size is one. [ruby-core:07389] * lib/rdoc/parsers/parse_rb.rb: need not to require "tracer". [ruby-core:07389] * sample/rtags.rb: ditto. Sat Feb 18 12:18:26 2006 Yukihiro Matsumoto * lib/fileutils.rb (FileUtils::fu_world_writable): make it private. [ruby-core:07383] Sat Feb 18 00:22:39 2006 Yukihiro Matsumoto * lib/tracer.rb: merged a minor clarification patch from Daniel Berger . [ruby-core:07376] Fri Feb 17 11:18:42 2006 Hirokazu Yamamoto * util.c (ruby_strtod): Float("1e") should fail. [ruby-core:7330] * pack.c (EXTEND32): unpack("l") did not work where sizeof(long) != 4. [ruby-talk:180024] * pack.c (pack_unpack): fixed integer overflow on template "w". [ruby-talk:180126] Fri Feb 17 09:39:29 2006 Yukihiro Matsumoto * eval.c (rb_thread_wait_for): sleep should always sleep for specified amount of time. [ruby-talk:180067] Thu Feb 16 01:10:48 2006 Yukihiro Matsumoto * eval.c (backtrace): frame->orig_func may not be initialized. [ruby-core:07367] Wed Feb 15 16:52:52 2006 Yukihiro Matsumoto * eval.c (rb_eval): NODE_OP_ASGN1 should allow splat in its argument list. [ruby-core:07366] * parse.y (arg): avoid unnecessary extra argument. [ruby-core:07366] * eval.c (rb_eval): honor visibility on OP_ASGN1 and OP_ASGN2. [ruby-core:07366] Wed Feb 15 10:09:51 2006 Yukihiro Matsumoto * eval.c (yield_under_i): should not pass self as an argument to the block for instance_eval. [ruby-core:07364] Wed Feb 15 09:20:35 2006 Yukihiro Matsumoto * eval.c (rb_obj_instance_eval): should be no singleton classes for true, false, and nil. [ruby-dev:28186] Tue Feb 14 18:48:33 2006 Yukihiro Matsumoto * eval.c (DMETHOD_P): accessing wrong frame. [ruby-dev:28181] * eval.c (proc_invoke): preserve FRAME_DMETH flag. Tue Feb 14 15:13:51 2006 Hirokazu Yamamoto * ext/zlib/zlib.c: supress warning on test/zlib. [ruby-dev:28323] Tue Feb 14 14:01:17 2006 NAKAMURA Usaku * time.c (search_time_t): support non 32bit time_t environments. * win32/Makefile.sub (config.h): VC++8 has ``long long'' type. * win32/Makefile.sub (config.h): VC++8's time_t is 64bit value. * win32/win32.c (rb_w32_utime): drop read-only attribute before changing file time. all changes are backported from CVS HEAD. Tue Feb 14 11:21:38 2006 Yukihiro Matsumoto * io.c (argf_forward): should not use frame->argv. [ruby-core:07358] Mon Feb 13 18:08:12 2006 Yukihiro Matsumoto * eval.c (rb_call0): argument update propagation. [ruby-dev:28044] * env.h: remove argv member from struct FRAME. Mon Feb 13 13:27:00 2006 Yukihiro Matsumoto * eval.c (eval): should push class from binding if supplied. [ruby-core:07347] Mon Feb 13 00:04:00 2006 Masatoshi SEKI * lib/erb.rb (ERB::Compiler): add instance variable @insert_cmd to change <%='s behavior. (backported 1.15 - 1.16) Sat Feb 11 02:04:11 2006 Yukihiro Matsumoto * eval.c (eval): no need to push ruby_class. [ruby-dev:28176] Sat Feb 11 01:57:44 2006 Yukihiro Matsumoto * eval.c (rb_f_autoload): check if ruby_cbase is nil (during instance_eval for objects cannot have singleton classes, e.g. fixnums and symbols). [ruby-dev:28178] Tue Feb 7 23:03:24 2006 Hirokazu Yamamoto * ext/zlib/zlib.c: should not access ruby objects in finalizer. [ruby-dev:28286] Mon Feb 6 16:02:51 2006 WATANABE Hirofumi * file.c (rb_thread_flock): ERROR_NOT_LOCKED is not an error on Cygwin. In such situation, flock() should return 0. Mon Feb 6 00:41:08 2006 Tanaka Akira * ruby.h (RSTRUCT_LEN, RSTRUCT_PTR): defined for source level compatibility with ruby 1.9. Sun Feb 5 21:05:34 2006 Hirokazu Yamamoto * numeric.c (fix_to_s): removed workaround for radix 2. Historically, rb_fix2str could only handle radix 8, 10, 16. (Rev1.37) But for now, it can handle radix 2..36. [ruby-Bugs#3438] [ruby-core:7300] Sun Feb 5 18:55:08 2006 Minero Aoki * lib/net/http.rb: imported from trunk, rev 1.129 * lib/net/http.rb (add_field, get_fields): keep 1.8.2 backward compatibility. * lib/net/https.rb: imported from trunk, rev 1.3. * lib/net/https.rb: #use_ssl? definition moved from net/http.rb. Sun Feb 5 14:22:15 2006 Hirokazu Yamamoto * lib/pstore.rb: should return default value if name is not found. [ruby-core:7304] * lib/pstore.rb: should raise PStore::Error if not in transaction. Sat Feb 4 22:51:43 2006 Tanaka Akira * eval.c: apply the FreeBSD getcontext/setcontext workaround only before FreeBSD 7-CURRENT. Sat Feb 4 21:19:23 2006 NAKAMURA Usaku * win32/win32.c (LK_ERR): ERROR_NOT_LOCKED is not an error. In such situation, flock() should return 0. Sat Feb 4 15:56:37 2006 Hirokazu Yamamoto * numeric.c (fix_to_s): (2**32).to_s(2) fails with exception where sizeof(int) == 4 < sizeof(long). [ruby-core:7300] Fri Feb 3 15:06:50 2006 Hirokazu Yamamoto * ext/syck/syck.c (syck_move_tokens): should reset p->cursor or etc even if skip == 0. This causes buffer overrun. (ex: YAML.load('--- "..' + '\x82\xA0' * 511 + '"')) Thu Feb 2 23:51:18 2006 Hirokazu Yamamoto * ext/syck/emitter.c (syck_emitter_write): should not set '\0' on emitter's marker. if marker points to the end of buffer, this causes buffer overrun. (ex: YAML.dump("." * 12288)) Thu Feb 2 16:01:24 2006 Yukihiro Matsumoto * eval.c (eval): need not to protect $SAFE value. [ruby-core:07177] Thu Feb 2 14:45:53 2006 Ville Mattila * configure.in: The isinf is not regognized by autoconf library guesser on solaris 10. [ruby-core:7138] Wed Feb 1 22:01:47 2006 Hirokazu Yamamoto * configure.in, hash.c (ruby_setenv): use setenv(3) and unsetenv(3) where they are supported. modifing environ variable seems to segfault solaris 10. [ruby-core:7276] [ruby-dev:28270] * ruby.c (set_arg0): if use setenv(3), environ space cannot be used for altering argv[0]. Tue Jan 31 14:46:28 2006 Yukihiro Matsumoto * struct.c (rb_struct_select): update RDoc description. [ruby-core:7254] Tue Jan 31 11:58:51 2006 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: add MultiTkIp#eval and bg_eval. * ext/tk/lib/tk/namespace.rb: TkNamespace#eval was enbugged at the last commit. Now it will return a proper object. Tue Jan 31 00:10:26 2006 Hirokazu Yamamoto * ext/syck/rubyext.c (syck_resolver_transfer): workaround for SEGV. ex: ruby -ryaml -e 'YAML.load("!map:B {}")' [ruby-core:7217] Sat Jan 28 07:56:57 2006 Hirokazu Yamamoto * lib/rdoc/usage.rb: support "a:0:33" style caller[-1]. In this case file name is "a:0". I don't know this really happens though... [ruby-Bugs:3344] Wed Jan 25 22:29:04 2006 Nobuyoshi Nakada * configure.in, dln.c, file.c, intern.h, missing.h (eaccess): use system routine if provided. fixed: [ruby-core:07195] Sun Jan 22 23:27:13 2006 Go Noguchi * lib/test/unit/autorunner.rb (process_args): ignore arguments after '--' so that test scripts can handle them. fixed: [ruby-dev:28258] Sun Jan 22 22:09:52 2006 Tanaka Akira * eval.c (POST_GETCONTEXT): define separately from PRE_GETCONTEXT on IA64 to avoid reusing variable address. Sun Jan 22 20:03:35 2006 Tanaka Akira * eval.c (ruby_setjmp): define PRE_GETCONTEXT and POST_GETCONTEXT instead of FUNCTION_CALL_MAY_RETURN_TWICE. define PRE_GETCONTEXT to clear carry flag for workaround of FreeBSD/i386 getcontext/setcontext bug. [ruby-dev:28263] Sat Jan 21 00:36:47 2006 Tanaka Akira * eval.c (FUNCTION_CALL_MAY_RETURN_TWICE): use only on SPARC and IA64 before gcc 4.0.3. [ruby-dev:28247] Thu Jan 19 22:21:23 2006 Minero Aoki * lib/fileutils.rb (mv): should remove file after copying. [ruby-dev:28223] Wed Jan 18 23:37:06 2006 Tanaka Akira * eval.c (FUNCTION_CALL_MAY_RETURN_TWICE): don't clobber %l7 of SPARC if enable-shared. (ruby_setjmp): call FUNCTION_CALL_MAY_RETURN_TWICE after getcontext too. reported by Pav Lucistnik and Marius Strobl. http://lists.freebsd.org/pipermail/freebsd-sparc64/2006-January/003739.html Tue Jan 17 11:32:46 2006 NAKAMURA Usaku * win32/setup.mak (MAKE): workaround for nmake 8. Tue Jan 17 11:10:21 2006 NAKAMURA Usaku * win32/{Makefile.sub,setup.mak}: invoke .bat via shell. workaround for nmake 8. Mon Jan 16 10:26:23 2006 Hirokazu Yamamoto * ext/syck/emitter.c (syck_emit_seq, syck_emit_map, syck_emit_item): should output complex key mark even if map's key is empty seq/map. [ruby-core:7129] Sat Jan 14 05:37:06 2006 Tanaka Akira * io.c (READ_DATA_PENDING, READ_DATA_PENDING_COUNT): defined for DragonFly BSD 1.4.0. Sat Jan 14 03:43:24 2006 Hirokazu Yamamoto * file.c (rb_file_s_chmod): avoid warning where sizeof(int) != sizeof(void*). Fri Jan 13 19:14:56 2006 Hirokazu Yamamoto * lib/rdoc/diagram.rb: - properly quote bare element attributes - terminates dangling elements (e.g. ,
, , etc) - converts "CVS" to the more HTML-friendly acronym element - adds missing type attributes to style elements based on Paul Duncan's patch [ruby-core:7028] * lib/rdoc/generators/html_generator.rb: ditto. * lib/rdoc/generators/template/html/hefss.rb: ditto. * lib/rdoc/generators/template/html/html.rb: ditto. * lib/rdoc/generators/template/html/kilmer.rb: ditto. Thu Jan 12 11:53:08 2006 Hidetoshi NAGAI * ext/tk/sample/tkballoonhelp.rb: [bug fix] couldn't add to a widget which is constructed with TkComposite module. [new feature] support 'command' option which is called just before popping up the balloon help. Wed Jan 11 15:00:00 2006 Ville Mattila * io.c (READ_PENDING*): Support solaris 64-bit environments. Solaris defines a opaque FILE struct when compiling 64 bit binaries. This means that we dont have access to _ptr etc. members anymore. The solution by Steven Lumos is to define FILE64 that has needed members available. I've modified the origanal patch a bit so that it compiles both with gcc and now free sun studio 11 compiler and both amd64 and sparc. NOTE! We have to 64 bit solaris FILE structure time to time otherwise we'll get breakage. [ruby-core:7106] Tue Jan 10 19:42:33 2006 Tanaka Akira * gc.c (garbage_collect): mark ruby_current_node. if an exception is raised in a finalizer called written in C by rb_gc_call_finalizer_at_exit, ruby_set_current_source may use collected ruby_current_node and mark_source_filename may corrupt memory. Tue Jan 10 13:30:34 2006 akira yamada * ext/syck/rubyext.c (syck_resolver_transfer): should be able to load !ruby/object:Bignum syntax 1.8.3 dumped. [ruby-core:6159] Tue Jan 10 12:47:41 2006 Hirokazu Yamamoto * lib/yaml/rubytypes.rb (Fixnum): Bignum could not be loaded in ruby 1.8.3/1.8.4. [ruby-core:6115] * lib/yaml/rubytypes.rb (Numeric): Subclass of Numeric could not be dumped properly. [ruby-core:7047] Tue Jan 10 12:00:48 2006 Aaron Schrab * lib/yaml/rubytypes.rb (Symbol#yaml_new): YAML loading of quoted Symbols broken. [ruby-Bugs:2535] Mon Jan 9 19:54:35 2006 arton * ext/zlib/extconf.rb: zlib compiled DLL version 1.2.3 distributed by http://www.zlib.net/ has zdll.lib. [ruby-dev:28209] Mon Jan 9 14:17:12 2006 Hirokazu Yamamoto * win32/Makefile.sub (OPTFLAGS): I have experienced trouble on y- flag, (VisualC++6) so use -O2b2xg- if $(MSC_VER) < 1400. [ruby-core:7040] Mon Jan 9 14:17:12 2006 Kero van Gelder * lib/webrick/httpservlet/filehandler.rb: fixed typo. [ruby-core:7075] Sat Jan 7 15:40:07 2006 Nobuyoshi Nakada * parse.y (singleton): get rid of segfault on syntax error. fixed: [ruby-core:07070] Fri Jan 6 10:16:20 2006 Steven Lumos * io.c (READ_DATA_PENDING): defined for 64bit Solaris on SPARC. [ruby-core:7057] (READ_DATA_PENDING_COUNT): ditto. (READ_DATA_PENDING_PTR): ditto. Sun Jan 1 17:07:59 2006 Hirokazu Yamamoto * win32/win32.c (rb_w32_seekdir): should not segfault even if passed the location which rb_w32_telldir didn't return. [ruby-core:7035] (I think HEAD implementation is better. but binary compatibility) * test/ruby/test_dir.rb: added. Sat Dec 31 22:57:00 2005 Nobuyoshi Nakada * eval.c (rb_thread_save_context): should not recycle scope object used in a thread. fixed: [ruby-dev:28177] Fri Dec 30 18:22:42 2005 Nobuyoshi Nakada * gc.c (garbage_collect): mark objects refered from aborting threads. [ruby-dev:28190] * win32/Makefile.sub: VC++8 support. Fri Dec 30 14:24:53 2005 WATANABE Hirofumi * dir.c (glob_helper): do not use TRUE for djgpp. Fri Dec 30 04:54:40 2005 NAKAMURA Usaku * file.c (eaccess): workaround for VC++8 runtime. * win32/win32.c (ioinfo): VC++8 support. Thu Dec 29 23:59:37 2005 Nobuyoshi Nakada * eval.c (rb_gc_mark_threads): leave unmarked threads which won't wake up alone, and mark threads in the loading table. [ruby-dev:28154] * eval.c (rb_gc_abort_threads), gc.c (gc_sweep): kill unmarked threads. [ruby-dev:28172] Thu Dec 29 17:02:07 2005 Tanaka Akira * test/ruby/envutil.rb (EnvUtil.rubybin): search "ruby" instead of "miniruby". [ruby-dev:28140] Tue Dec 27 16:59:52 2005 Yukihiro Matsumoto * test/drb/drbtest.rb (DRbService::self.ext_service): increase timeout limit. a patch from Kazuhiro NISHIYAMA . [ruby-dev:28132] Tue Dec 27 08:29:18 2005 GOTOU Yuuzou * ext/openssl/lib/openssl/ssl.rb (OpenSSL::SSL::SSLSocket#post_connection_chech): treat wildcard character in commonName. [ruby-dev:28121] Mon Dec 26 22:32:47 2005 Nobuyoshi Nakada * eval.c (rb_eval), gc.c (gc_mark_children), node.h (NEW_ALIAS, NEW_VALIAS), parse.y (fitem): allow dynamic symbols to NODE_UNDEF and NODE_ALIAS. backported from trunk. fixed: [ruby-dev:28105] Mon Dec 26 08:50:36 2005 Yukihiro Matsumoto * eval.c (ev_const_get): fixed a bug in constant reference during instance_eval. [yarv-dev:707] * eval.c (ev_const_defined): ditto. * lib/yaml.rb (YAML::add_domain_type): typo fixed. a patch from Joel VanderWerf . [ruby-talk:165285] [ruby-core:6995] Sat Dec 24 18:58:14 2005 Yukihiro Matsumoto * stable version 1.8.4 released. Fri Dec 23 10:30:23 2005 Yukihiro Matsumoto * ext/digest/sha2/sha2.c (ULL): support AIX C. a patch from Kailden . [ruby-core:06984] Wed Dec 21 16:53:06 2005 Hirokazu Yamamoto * file.c (w32_io_info): should return handle because FileIndex is valid only while file is open. [ruby-dev:28088] Wed Dec 21 14:53:26 2005 Tanaka Akira * lib/pathname.rb (test_kernel_open): use File.identical?. [ruby-talk:171804] Tue Dec 20 22:41:17 2005 Nobuyoshi Nakada * eval.c (eval_under_i): evaluate source in caller's frame. [ruby-dev:28076] * eval.c (rb_call_super): use original method name on exception. [ruby-dev:28078] Tue Dec 20 13:11:59 2005 Hirokazu Yamamoto * ext/syck/rubyext.c: fixed GC problem (backported HEAD 1.55 - 1.62) [ruby-dev:27839] * ext/syck/syck.h (S_FREE): small hack. no need to check if pointer is NULL or not before S_FREE. * st.c: uses malloc instead of xmalloc to avoid GC. syck uses st_insert in gram.c to insert node from rb_syck_bad_anchor_handler into SyckParser's hash table. if GC occurs in st_insert, it's not under SyckParser's mark system yet. so RString can be released wrongly. [ruby-dev:28057] Tue Dec 20 12:53:23 2005 why the lucky stiff * ext/syck/rubyext.c (syck_emitter_reset): to ensure compatibility with previous Ruby versions, documents are no longer headless. Tue Dec 20 01:46:48 2005 Tanaka Akira * io.c (rb_f_backquote): fix a GC problem on IA64 with gcc 4.0.3 20051216 (prerelease) -O3. Mon Dec 19 23:32:39 2005 Nobuyoshi Nakada * parse.y (rb_symname_p): fixed wrong validation. [ruby-dev:28047] Sat Dec 17 03:57:01 2005 Tanaka Akira * bignum.c (rb_big_rshift): fix a GC problem on IA64 with gcc 4.0.3 20051216 (prerelease). Sat Dec 17 03:30:23 2005 Tanaka Akira * eval.c (bmcall): fix a GC problem by tail call on IA64 with gcc 4.0.3 20051216 (prerelease). Fri Dec 16 00:54:06 2005 Yukihiro Matsumoto * signal.c (Init_signal): revert C++ style comment. [ruby-dev:28041] Thu Dec 15 12:35:14 2005 Yukihiro Matsumoto * lib/tmpdir.rb: merged RDoc patch from Eric Hodel . [ruby-core:06894] Thu Dec 15 01:33:31 2005 Tanaka Akira * ext/zlib/zlib.c (zstream_run): fix a GC problem by tail call on x86_64 with gcc 4.0.3 20051111 (prerelease) (Debian 4.0.2-4) Wed Dec 14 12:11:46 2005 WATANABE Hirofumi * test/gdbm/test_gdbm.rb: specify pid for the argument of Process.wait. workaround for Cygwin. Wed Dec 14 12:01:26 2005 Tanaka Akira * marshal.c (r_object0): fix a GC problem for reading a bignum on IA64 with gcc 3.3.5 (Debian 1:3.3.5-13). Tue Dec 13 12:23:47 2005 Tanaka Akira * re.c (rb_reg_regcomp): fix a GC problem on x86_64 with gcc 3.3.5 (Debian 1:3.3.5-13). Tue Dec 13 01:44:16 2005 Tanaka Akira * array.c (rb_ary_diff): fix a GC problem on IA64 with gcc 3.3.5 (Debian 1:3.3.5-13). When rb_ary_push is called, there was no register which contains `hash' but `&RHASH(hash)->tbl' instead. Tue Dec 13 00:08:09 2005 Tanaka Akira * sprintf.c (rb_str_format): fix a GC problem. [ruby-dev:28001] Mon Dec 12 15:54:56 2005 GOTOU Yuuzou * test/openssl/test_ssl.rb (test_parallel): call GC.start to close unused files. [ruby-dev:27981] Mon Dec 12 00:33:56 2005 Yukihiro Matsumoto * ext/digest/digest.c (rb_digest_base_s_digest): add volatile to protect temporary context object. [ruby-dev:27979] * ext/iconv/iconv.c (Init_iconv): rb_gc_register_address() should be called before actual variable initialization. [ruby-dev:27986] Fri Dec 9 23:31:02 2005 Nobuyoshi Nakada * lib/rexml/encoding.rb (encoding=): give priority to particular conversion to iconv. [ruby-core:06520] Thu Dec 8 02:07:19 2005 Nobuyoshi Nakada * eval.c (umethod_bind): adjust invoking class for module method. [ruby-dev:27964] Thu Dec 8 00:40:52 2005 Yukihiro Matsumoto * eval.c (call_trace_func): klass parameter should be a class/module that defines calling method. [ruby-talk:169307] Wed Dec 7 17:10:27 2005 Kazuhiro NISHIYAMA * sprintf.c (rb_f_sprintf): [ruby-dev:27967] Wed Dec 7 15:31:35 2005 Yukihiro Matsumoto * sprintf.c (rb_str_format): integer overflow check added. * sprintf.c (GETASTER): ditto. Wed Dec 7 01:02:04 2005 Hidetoshi NAGAI * ext/tk/README.macosx-aqua: [new document] tips to avoid the known bug on platform specific dialogs of Tcl/Tk Aqua on MacOS X. * ext/tk/tcltklib.c: fix bug on switching threads and waiting on the deleted interpreter on vwait and tkwait command. * ext/tk/lib/multi-tk.rb: kill the meaningless loop for the deleted Tk interpreter. * ext/tk/sample/demos-jp/image3.rb: [bug fix] wrong argument. * ext/tk/sample/demos-en/image3.rb: ditto. * ext/tk/sample/demos-jp/menu.rb: fix message for MacOS X. * ext/tk/sample/demos-jp/menu8x.rb: ditto. * ext/tk/sample/demos-en/menu.rb: ditto. Tue Dec 6 16:37:57 2005 Yuya Nishida * eval.c (exec_under): avoid accessing ruby_frame->prev. [ruby-dev:27948] Thu Dec 1 00:50:33 2005 Nobuyoshi Nakada * eval.c (rb_funcall2): allow to call protected methods. fixed: [ruby-dev:27890] Wed Nov 30 23:52:17 2005 Nobuyoshi Nakada * parse.y (NEWHEAP, ADD2HEAP): set count after pointer was set. fixed: [ruby-dev:27896] Wed Nov 30 13:43:07 2005 Yukihiro Matsumoto * misc/ruby-mode.el (ruby-expr-beg): support $! at the end of expression. [ruby-dev:27868] Mon Nov 28 18:55:43 2005 NAKAMURA Usaku * ext/socket/socket.c (init_inetsock_internal): remove setting SO_REUSEADDR option on server socket on Cygwin. fixed: [ruby-core:6765] ([ ruby-Bugs-2872 ]) Mon Nov 28 13:08:54 2005 Hirokazu Yamamoto * win32/win32.c (rb_w32_strerror): remove all CR and LF. (avoid broken error message on bccwin32 + winsock) Mon Nov 28 09:21:49 2005 Hirokazu Yamamoto * lib/mkmf.rb (create_makefile): should not change sodir with dir.gsub!. (bccwin32 failed to install third party exntesions) [ruby-dev:27834] Sun Nov 27 00:56:13 2005 NAKAMURA, Hiroshi * lib/wsdl/xmlSchema/complexContent.rb: missing ComplexContent#elementformdefault method. Sat Nov 26 19:57:45 2005 WATANABE Hirofumi * dln.c (conv_to_posix_path): should initialize posix. Thu Nov 24 21:05:58 2005 NAKAMURA Usaku * configure.in (AC_CHECK_FUNCS): need to check link(). fixed: [ruby-dev:27814] Thu Nov 24 01:22:25 2005 Hirokazu Yamamoto * file.c (w32_io_info): CreateFile failed on Win9x if file was already opened. (FILE_SHARE_READ was needed, but actually I don't understand the flags of CreateFile well...) Wed Nov 23 20:59:01 2005 Hidetoshi NAGAI * ext/tk/lib/tk.rb: add Tk.pkgconfig_list and Tk.pkgconfig_get [Tk8.5 feature]. * ext/tk/lib/tk/text.rb: supports new indices modifires on a Text widget [Tk8.5 feature]. * ext/tk/lib/tk/virtevent.rb: add TkNamedVirtualEvent. * ext/tk/lib/tk/autoload.rb: ditto. * ext/tk/lib/tk/event.rb: add :data key for virtual events [Tk8.5 feature]. Wed Nov 23 18:55:31 2005 Hirokazu Yamamoto * file.c (w32_io_info): should not call GetFileInformationByHandle for pipe. * file.c (w32_io_info): checks return value from rb_w32_get_osfhandle. * file.c (w32_io_info): now can identify directory on WinNT. Wed Nov 23 03:40:49 2005 Guy Decoux * re.c (KR_REHASH): should cast to unsigned for 64bit CPU. [ruby-core:06721] Wed Nov 23 11:01:33 2005 Hirokazu Yamamoto * intern.h, file.c: failed to compile on windows. Wed Nov 23 07:26:44 2005 GOTOU Yuuzou * ext/openssl/extconf.rb: check for X509V3_EXT_nconf_nid. * ext/openssl/ossl_x509ext.c (MakeX509ExtFactory): should use OPENSSL_malloc to allocate X509V3_CTX. * ext/openssl/ossl_x509ext.c (ossl_x509extfactory_create_ext): use X509V3_EXT_nconf_nid to avoid SEGV (and to build extensions which values are placed in separate section). * test/openssl/test_x509ext.rb: new file. Wed Nov 23 01:22:57 2005 Nobuyoshi Nakada * file.c (test_identical): test if two files are identical. * file.c (rb_f_test): support DOSISH systems where st_ino is not reliable. fixed: [ruby-core:06672] * win32.h, win32.c (rb_w32_osid): check the running platform. Tue Nov 22 23:52:06 2005 Nobuyoshi Nakada * lib/optparse.rb: match incomplete (in current enconding) multibyte string. http://inamode6.tokuhirom.dnsalias.org/show/1551 Tue Nov 22 18:36:11 2005 Hirokazu Yamamoto * win32/win32.c (winnt_stat): set mapped errno instead of ENOENT. Tue Nov 22 14:46:57 2005 NAKAMURA Usaku * file.c (rb_file_s_basename): skip slashes just after UNC top slashes. * test/ruby/test_path.rb (test_dirname, test_basename): follow new spec. and add new tests. Tue Nov 22 13:18:32 2005 Hirokazu Yamamoto * win32/win32.c (rb_w32_stat): Dir.chdir('//server/shared'); p Dir.glob('*') should work on WinNT. (implemented our own stat(2) on WinNT) [ruby-list:41552] [ruby-dev:27711] Tue Nov 22 02:31:53 2005 Hidetoshi NAGAI * ext/tk/lib/tkextlib/tile.rb: bug fix (Tk::Tile::USE_TTK_NAMESPACE is not defined). Tue Nov 22 01:45:21 2005 Nobuyoshi Nakada * file.c (rb_file_s_basename): DOSISH_UNC is defined on cygwin but DOSISH is not. fixed: [ruby-dev:27797] Mon Nov 21 22:50:48 2005 Nobuyoshi Nakada * file.c (rb_path_skip_prefix, rb_file_s_basename): UNC without path should not be splitted. fixed: [ruby-dev:27776] [ruby-dev:27786] * parse.y (dsym): prohibit empty symbol literal by interpolation. fixed: [ruby-talk:166529] Mon Nov 21 16:03:48 2005 Nobuyoshi Nakada * win32/setup.mk: findstr doesn't exist on win9x. fixed: [ruby-dev:27756] Sun Nov 20 22:34:06 2005 Nobuyoshi Nakada * parse.y (rb_symname_p): [ not followed by ] is not valid symbol. fixed: [ruby-talk:166520] Sat Nov 19 19:57:54 2005 Yukihiro Matsumoto * lib/fileutils.rb (FileUtils::ln): ln documentation fix. [ruby-core:06661] Sat Nov 19 07:34:32 2005 Hidetoshi NAGAI * ext/tk/lib/tk/font.rb: remove dependency on Ruby's version (1.8 or 1.9). * ext/tk/lib/tkextlib/ICONS/icons.rb: ditto. * ext/tk/sample/tkextlib/treectrl/demo.rb: ditto. Fri Nov 18 17:57:08 2005 NAKAMURA Usaku * file.c (rb_file_s_dirname): should use skipprefix for UNC path. pointed out by nobu ([ruby-dev:27744]). fixed: [ruby-core:5076] Fri Nov 18 17:35:09 2005 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: add restriction to access the entried command table and manipulate other IPs (for reason of security). Now, a IP object can be controlled by only its master IP or the default IP. * ext/tk/lib/remote-tk.rb: add restriction to manipulate. * ext/tk/tcltklib.c (ip_is_slave_of_p): add TclTkIp#slave_of?(ip) to check manipulability. * ext/tk/lib/tk.rb: bug fix on handling of Tcl's namespaces. * ext/tk/lib/tk/namespace.rb: ditto. Fri Nov 18 17:26:06 2005 NAKAMURA Usaku * file.c (rb_file_s_dirname): added checks for some patterns with drive letter. fixed: [ruby-dev:27738] * test/ruby/test_path.rb (test_dirname): added tests for above patterns. Fri Nov 18 12:18:02 2005 Hirokazu Yamamoto * win32/win32.h (S_IFIFO): r,w = IO.pipe; r.stat.pipe? now returns true on VisualC++6. Wed Nov 16 23:24:17 2005 Nobuyoshi Nakada * common.mk (static-ruby): overridable. * ext/extmk.rb (parse_args): force to link extensions statically only if static is given for extstatic. * ext/extmk.rb (RUBY, RUBYW): overridable. Tue Nov 15 23:46:35 2005 Yukihiro Matsumoto * lib/find.rb (Find::find): should not ignore symbolic links to non-existing files. [ruby-talk:165866] Tue Nov 15 16:23:26 2005 Hirokazu Yamamoto * array.c (rb_ary_fill): previous commit disabled this usage: a = [0,1,2,3,4,5,6,7,8,9] a.fill {|i| a[i] * 10} #=> [nil, nil, ...., nil] previous commit has the advantage of early garbage collection, but potensially this would break some script. so I reverted behavior. Tue Nov 15 16:04:10 2005 Hirokazu Yamamoto * array.c (rb_ary_fill): tail elements were vanished when the middle part of array was filled. (ie: [0,1,2,3,4].fill(-1,2,1) => [0,1,-1]) * test/ruby/test_array.rb (test_fill): added. Tue Nov 15 14:39:16 2005 Yukihiro Matsumoto * array.c (rb_ary_fill): should adjust array length correctly when an array is expanded in the fill process. [ruby-core:06625] Mon Nov 14 23:49:57 2005 Nobuyoshi Nakada * file.c (rb_file_s_readlink): ERANGE will occur only on GPFS. [ruby-dev:27699] Mon Nov 14 17:36:22 2005 Yukihiro Matsumoto * array.c (rb_ary_first): RDoc update from Daniel Berger . [ruby-core:06577]. Fri Nov 11 10:31:44 2005 Zach Dennis * ext/socket/socket.c: Socket Documentation. [ruby-core:6552] Fri Nov 11 08:20:56 2005 Nobuyoshi Nakada * Makefile.in (OUTFLAG): keep trailing spaces. [ruby-dev:27666] * mkconfig.rb: substitution refereces added. Fri Nov 11 07:44:18 2005 Hirokazu Yamamoto * configure.in: undef HAVE_LINK on BeOS. (link(2) always returns EINVAL, and this causes error in test/fileutils.) * file.c: overwride chown(2) and fchown(2) on BeOS. (these functions should not change user/group id if -1 is passed as corresponding argument, and this causes error in test/fileutils too) [ruby-dev:27672] * file.c (rb_file_s_link): checks HAVE_LINK. Tue Nov 8 15:32:27 2005 GOTOU Yuuzou * lib/drb/ssl.rb (DRb::SSLConfig#accept): fixed typo. [ruby-dev:27560] [ruby-core:4627] Mon Nov 7 13:43:51 2005 Hidetoshi NAGAI * ext/tk/stubs.c (_nativethread_consistency_check): use simpler (low cost) way to check whether the Tcl interpreter was compiled with threads enabled of not. * ext/tk/tcltklib.c: reduce warnings. * ext/tk/tkutil/tkutil.c: ditto. Mon Nov 7 00:06:58 2005 Hirokazu Yamamoto * lib/yaml.rb: removed :nodoc: to generate Kernel doc. [ruby-core:6324] Sun Nov 6 23:39:13 2005 Nobuyoshi Nakada * ext/iconv/iconv.c (Iconv::BrokenLibrary): exception when detected a bug of underlying library. Sun Nov 6 21:46:59 2005 Hirokazu Yamamoto * ext/tk/stubs.c (ruby_tcl_create_ip_and_stubs_init): should touch interpreter after initialization is done. [ruby-dev:27638] Sun Nov 6 20:13:27 2005 Nobuyoshi Nakada * file.c (rb_file_s_readlink): readlink(2) on AIX fails with ERANGE if buffer size is less than required. fixed: [ruby-dev:27634] Wed Nov 2 20:25:28 2005 Hidetoshi NAGAI * ext/tk/extconf.rb: ext/tk/extconf.rb: change the check parameter for Win32. Wed Nov 2 20:14:53 2005 Hidetoshi NAGAI * ext/tcltklib: merge into ext/tk and remove. Wed Nov 2 19:03:06 2005 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (ip_rbUpdateObjCmd, ip_rb_threadUpdateObjCmd): passed improper flags to DoOneEvent(). * ext/tk/tkutil.c: use rb_obj_respond_to() instead of rb_respond_to(). Tue Nov 1 14:20:11 2005 Yukihiro Matsumoto * eval.c (rb_call_super): should call method_missing if super is called from Kernel method. * eval.c (exec_under): frame during eval should preserve external information. Tue Nov 1 10:50:17 2005 GOTOU Yuuzou * ext/openssl/extconf.rb: should check ERR_peek_last_error(). [ruby-dev:27597] * ext/openssl/ossl.c (ossl_raise): ditto. Mon Oct 31 17:34:46 2005 Yukihiro Matsumoto * configure.in: use proper option for Sun linker. A patch from Shinya Kuwamura . [ruby-dev:27603] Mon Oct 31 11:27:22 2005 NAKAMURA Usaku * test/gdbm/test_gdbm.rb, test/sdbm/test_sdbm.rb (test_s_open_error): skip on Win32/DOS platforms. Mon Oct 31 05:49:23 2005 GOTOU Yuuzou * ext/openssl/ossl_cipher.c (ossl_cipher_update): input data must not be empty. [ruby-talk:161220] * test/openssl/test_cipher.rb: add test for Cipher#update(""). Mon Oct 31 05:37:20 2005 GOTOU Yuuzou * lib/webrick/httpservlet/cgihandler.rb (WEBrick::HTTPServlet::CGIHandler#do_GET): the value of Set-Cookie: header field should be splited into each cookie. [ruby-Bugs:2199] * lib/webrick/cookie.rb (WEBrick::Cookie.parse_set_cookie): new method to parse the value of Set-Cookie: header field. * test/webrick/test_cookie.rb, test/webrick/test_cgi.rb, test/webrick/webrick.cgi: add some test for cookie. Mon Oct 31 03:19:36 2005 Yukihiro Matsumoto * ext/readline/readline.c (readline_readline): type check. [ruby-core:6089] * numeric.c (fix_rshift): RDoc fix. [ruby-core:6351] * util.h (strtod): add #undef for platforms defines strtod() macro. [ruby-dev:27563] Mon Oct 31 02:35:59 2005 Hirokazu Yamamoto * test/ruby/test_float.rb (test_precision): test by assert_in_delta. [ruby-dev:27575] Sat Oct 29 01:58:25 2005 Yukihiro Matsumoto * ext/etc/etc.c: document update from mathew . [ruby-core:06473] * ext/fcntl/fcntl.c: ditto. Thu Oct 27 16:45:31 2005 Yukihiro Matsumoto * string.c (scan_once): wrong condition to use mbclen2(). [ruby-dev:27535] Wed Oct 26 09:27:27 2005 Hirokazu Yamamoto * ext/syck/implicit.c (syck_type_id_to_uri): should return newly allocated memory. otherwise, type_id will be freed twice. [ruby-dev:27384] [ruby-core:6385] Wed Oct 26 09:04:51 2005 Hirokazu Yamamoto * ruby.h (Qfalse, Qtrue, Qnil, Qundef): make sure these immediate values have VALUE type. there is an environment where sizeof(VALUE) != sizeof(int) like IA64. if 32bit integer (Qtrue) is passed to ANYARGS and received by 64bit integer (VALUE), upper bits may have garbage value. [ruby-dev:27513] Wed Oct 26 01:58:19 2005 Nobuyoshi Nakada * configure.in (RUBY_EXTERN): macro to export symbols in shared library. [ruby-core:05528] * defines.h, {bcc32,win32,wince}/Makefile.sub (RUBY_EXTERN): moved to configuration pass. * ext/extmk.rb (extmake): RUBY_EXTERN for static linked extensions. Tue Oct 25 15:32:00 2005 Yukihiro Matsumoto * lib/rational.rb: applied documentation patch from Gavin Sinclair . [ruby-core:06364] * lib/irb.rb (IRB::Irb::eval_input): handle prompts with newlines in irb auto-indentation mode. [ruby-core:06358] Tue Oct 25 02:12:08 2005 Nobuyoshi Nakada * lib/rdoc/markup/simple_markup.rb (SM::SimpleMarkup::LABEL_LIST_RE): reduce redundant backtrack. [ruby-talk:161771] Tue Oct 25 00:27:35 2005 Masatoshi SEKI * lib/rinda/*: RDoc documentation from Eric Hodel added. Mon Oct 24 21:14:29 2005 Nobuyoshi Nakada * configure.in, io.c: use sys/syscall.h if syscall.h is not available. [ruby-core:06247] Mon Oct 24 20:49:45 2005 NAKAMURA Usaku * ext/Win32API/lib/win32/resolv.rb (get_info): support multiple DNS. fixed: [ruby-list:40058], [ruby-dev:27479] Mon Oct 24 07:57:56 2005 Yukihiro Matsumoto * ext/tk/lib/tk/canvas.rb (TkCanvasItemConfig::__item_val2ruby_optkeys): typo fixed. [ruby-talk:162187] * ext/tk/lib/tk/menu.rb (TkMenuEntryConfig::__item_val2ruby_optkeys): ditto. [ruby-core:06359] Sun Oct 23 21:50:15 2005 Yukihiro Matsumoto * ext/enumerator/enumerator.c: applied documentation patch from James Edward Gray II . [ruby-core:06348] Sun Oct 23 07:11:11 2005 Hidetoshi NAGAI * ext/tcltklib/extconf.rb: improve messages [ruby-core:06325]. * ext/tk/lib/tk.rb, ext/tk/lib/tk/canvas.rb, ext/tk/lib/tk/entry.rb, ext/tk/lib/tk/frame.rb, ext/tk/lib/tk/image.rb, ext/tk/lib/tk/itemconfig.rb, ext/tk/lib/tk/labelframe.rb, ext/tk/lib/tk/listbox.rb, ext/tk/lib/tk/menu.rb, ext/tk/lib/tk/radiobutton.rb, ext/tk/lib/tk/scale.rb, ext/tk/lib/tk/spinbox.rb, ext/tk/lib/tk/text.rb, ext/tk/lib/tk/toplevel.rb: improve conversion of option values. * ext/tk/lib/tkextlib/*: ditto. * ext/tk/lib/tkextlib/*: update to support ActiveTcl8.4.11.2. * ext/tk/lib/tkextlib/trofs/*: support Trofs 0.4.3. * ext/tk/lib/tkextlib/tile/*: support Tile 0.7.2. * ext/tk/lib/tkextlib/vu/*: support vu 2.3.0. * ext/tk/lib/tkextlib/tcllib/*: support Tcllib 1.8 (Tklib 0.3). Sat Oct 22 23:54:07 2005 Nobuyoshi Nakada * ext/extmk.rb, lib/mkmf.rb (with_config): support --with-extension options. [ruby-dev:27449] Sat Oct 22 13:26:57 2005 Nobuyoshi Nakada * object.c (sym_inspect), parse.y (parser_yylex, rb_symname_p): check if valid as a symbol name more strictly. [ruby-dev:27478] * test/ruby/test_symbol.rb: tests for [ruby-core:03573]. * time.c (rb_strftime): removed meaningless volatile modifiers, and concatenate successive nul characters at once. [ruby-dev:27472] Fri Oct 21 19:21:56 2005 Hirokazu Yamamoto * rubysig.h (CHECK_INTS): fixed typo. (I believe bit-or is improper) Fri Oct 21 17:49:32 2005 Yukihiro Matsumoto * bin/erb (ERB::Main::run): typo fixed. [ruby-core:06337] Fri Oct 21 15:27:17 2005 Hirokazu Yamamoto * bignum.c (bignew_1): convertion from `int' to `char' discards upper bits, (ie. (char)0xff00 -> 0) so it's better to test if nonzero and set 0 or 1 instead of simply casting ... as a flag usage. (but I believe this won't cause actual bug in current implementation) [ruby-dev:27055] * time.c: should use LONG_LONG instead of `long long'. Thu Oct 20 09:37:15 2005 Hirokazu Yamamoto * lib/mkmf.rb (create_makefile): Borland make seems not to allow empty dependency list. If this change is not good, please correct it. Thu Oct 20 07:55:09 2005 Nobuyoshi Nakada * lib/mkmf.rb (create_makefile): get rid of a restriction of Borland make. fixed: [ruby-dev:27460] Thu Oct 20 00:13:18 2005 NAKAMURA Usaku * rubysig.h (CHECK_INTS): fix typo. Wed Oct 19 23:58:03 2005 Nobuyoshi Nakada * lib/mkmf.rb (create_makefile): do not create unnecessary empty directories. fixed: [ruby-dev:27451] Wed Oct 19 19:26:15 2005 Nobuyoshi Nakada * parse.y (rb_gc_mark_parser): get rid of segfault with old yacc. fixed: [ruby-dev:27439] Wed Oct 19 08:28:32 2005 Nobuyoshi Nakada * file.c (rb_file_join): elements may contain null pointer strings. report and fixed by Lloyd Zusman (hippoman): [ruby-core:06326] Wed Oct 19 02:34:33 2005 Nobuyoshi Nakada * eval.c, gc.c, time.c: made internal symbols static. [ruby-dev:27435] Wed Oct 19 01:27:07 2005 Nobuyoshi Nakada * regex.c (re_compile_pattern): numeric literal inside character class disabled succeeding backtrack. fixed: [ruby-list:41328] Mon Oct 17 21:18:50 2005 Nobuyoshi Nakada * parse.y (parser_heap): byacc never free parser stack. fixed: [ruby-dev:27428] Mon Oct 17 16:04:47 2005 NAKAMURA Usaku * file.c (chmod_internal, lchmod_internal): fixed type of 2nd argument. Sun Oct 16 22:16:51 2005 Nobuyoshi Nakada * ext/extmk.rb: omit non-existing directories. Sun Oct 16 14:30:05 2005 Masatoshi SEKI * lib/rinda/rinda.rb (Rinda::Tuple#initialize): check remote hash tuple. fixed: [ruby-list:41227] * test/rinda/test_rinda.rb: test it. Sun Oct 16 03:38:07 2005 Yukihiro Matsumoto * rubysig.h (CHECK_INTS): prevent signal handler to run during critical section. [ruby-core:04039] * eval.c (load_wait): need not to call rb_thread_schedule() explicitly. [ruby-core:04039] * eval.c (rb_thread_schedule): clear rb_thread_critical. [ruby-core:04039] Sat Oct 15 19:56:38 2005 Masatoshi SEKI * bin/erb: typo fixed, again. thanks, Doug Kearns. Fri Oct 14 22:08:26 2005 NAKAMURA Usaku * win32/win32.c (ioctl): should set errno. Fri Oct 14 16:57:32 2005 GOTOU Yuuzou * lib/webrick/config.rb (Config::FileHandler): :UserDir should be nil. It is harmful to permit the access to ~/public_html by default. suggested by Hiroyuki Iwatsuki. Thu Oct 13 23:29:51 2005 Nobuyoshi Nakada * parse.y (HEAPCNT): bison allocates indivisible size. fixed: [ruby-core:06261] * io.c, pack.c, ext/syck/rubyext.c, ext/syck/syck.h, missing/isinf.c: get rid of warnings. fixed: [ruby-core:06247] Wed Oct 12 12:52:57 2005 GOTOU Yuuzou * ext/openssl/ossl.c (Init_openssl): should call OpenSSL_add_ssl_algorithms(). Wed Oct 12 11:08:54 2005 WATANABE Hirofumi * file.c (rb_f_test): typo in RDoc comments. Tue Oct 11 21:41:58 2005 Nobuyoshi Nakada * eval.c (rb_obj_respond_to): check if obj responds to the given method with the given visibility. [ruby-dev:27408] * eval.c (rb_respond_to): conform to Object#respond_to?. [ruby-dev:27411] Tue Oct 11 00:01:21 2005 Yukihiro Matsumoto * st.c (st_free_table): do not call free() but xfree(). [ruby-core:06205] Sat Oct 8 20:04:40 2005 Nobuyoshi Nakada * eval.c (Init_Binding): add Binding#dup method. [yarv-dev:666] * parse.y (rb_parser_malloc, rb_parser_free): manage parser stack on heap. [ruby-list:41199] * ext/iconv/charset_alias.rb: parse config.charset_alias file directly. Fri Oct 7 09:54:00 2005 Yukihiro Matsumoto * lib/cgi.rb (CGI::Cookie::parse): Cookies from Nokia devices may not be parsed correctly. A patch from August Z. Flatby (augustzf) in [ruby-Patches-2595]. [ruby-core:06183] Thu Oct 6 20:12:16 2005 Minero Aoki * ext/strscan/strscan.c (strscan_free): remove useless code. [ruby-dev:26368] [ruby-dev:27389] (backported from trunk, rev 1.22) Wed Oct 5 04:42:38 2005 GOTOU Yuuzou * lib/xmlrpc/server.rb (XMLRPC::Server#initialize): should mount the servlet on "/". Wed Oct 5 03:59:09 2005 GOTOU Yuuzou * lib/xmlrpc/server.rb (XMLRPC::Server#serve): delete wrong call of "join". Mon Oct 3 00:04:00 2005 Kazuhiro NISHIYAMA * pack.c (EXTEND16): [ruby-dev:27383] Thu Sep 29 10:26:18 2005 Tanaka Akira * ext/dl/dl.c (rb_io_to_ptr): abolish sizeof(FILE). [ruby-dev:27317] Thu Sep 29 07:22:05 2005 Nobuyoshi Nakada * evalc. (rb_f_send): underscores need to be escaped. fixed by Doug Kearns. [ruby-core:06053] Thu Sep 29 00:57:35 2005 Nobuyoshi Nakada * eval.c (ev_const_get), variable.c (rb_const_get_0): retry only when autoload succeeded. * variable.c (rb_autoload_load): now return true if autoload succeeded. fixed: [ruby-dev:27331] Wed Sep 28 23:42:15 2005 Nobuyoshi Nakada * file.c (apply2files): add prototype. * file.c (rb_stat_inspect): constified. * class.c (rb_mod_init_copy, rb_class_init_copy), file.c (rb_stat_init_copy), numeric.c (num_init_copy), object.c (rb_obj_init_copy, Init_Object), re.c (match_init_copy, rb_reg_init_copy), time.c (time_init_copy): undocumented. Wed Sep 28 23:09:23 2005 Yukihiro Matsumoto * lib/delegate.rb: document update from James Edward Gray II . [ruby-core:06027] Wed Sep 28 15:14:19 2005 GOTOU Yuuzou * lib/webrick/cgi.rb (WEBrick::CGI#start): req.query_string should refer the value of QUERY_STRING. [ruby-list:41186] * lib/webrick/httprequest.rb (WEBrick::HTTPRequest#query_string=): add new method. Wed Sep 28 10:45:44 2005 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: cannot compile with Tcl/Tk8.0.x [ruby-dev:27335]. Wed Sep 28 08:12:18 2005 Nobuyoshi Nakada * io.c (read_buffered_data): check if reached EOF. fixed: [ruby-dev:27334] Wed Sep 28 07:56:52 2005 Nobuyoshi Nakada * lib/yaml/basenode.rb (YAML::BaseNode::match_segment): fix typo. [ruby-dev:27237], [ruby-core:05854] * lib/yaml/tag.rb (Module#yaml_as): suppress warnings. * lib/yaml/types.rb (YAML::PrivateType, YAML::DomainType): ditto. Wed Sep 28 03:23:35 2005 NAKAMURA Usaku * rubysig.h: fixed build problem with --enable-pthread on platforms which don't have setitimer(). Mon Sep 26 22:32:13 2005 Yukihiro Matsumoto * eval.c (set_trace_func): add rb_secure(4) to prevent adding tracing function. Sun Sep 25 12:05:10 2005 Masatoshi SEKI * bin/erb: typo fixed. Sun Sep 25 01:46:43 2005 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-calculate-indent): arrange deep-indent closing parenthesis at same column as the opening. Sun Sep 25 00:42:11 2005 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-expr-beg): deal with heredoc separately. fixed: [ruby-list:41168] * misc/ruby-mode.el (ruby-calculate-indent): not to deepen indent level for continuous line inside parentheses. http://nabeken.tdiary.net/20050915.html#p02 Sun Sep 25 00:18:11 2005 Tanaka Akira * eval.c (unknown_node): show more information. [ruby-dev:26196] Sat Sep 24 08:56:01 2005 Minero Aoki * lib/fileutils.rb (cd): no longer accept :noop option, related code is useless (backported from trunk, rev 1.67). [ruby-core:05858] [ruby-Bugs:2494] Sat Sep 24 08:38:07 2005 Minero Aoki * lib/fileutils.rb: fix visibility of FileUtils::NoWrite, Verbose, DryRun (backported from trunk, rev 1.66). [ruby-core:05954] * test/fileutils/test_nowrite.rb: test it. * test/fileutils/test_dryrun.rb: new file. * test/fileutils/test_verbose.rb: new file. Sat Sep 24 02:40:20 2005 Yukihiro Matsumoto * lib/delegate.rb: document update from James Edward Gray II . [ruby-core:05942] Thu Sep 22 23:36:24 2005 Nobuyoshi Nakada * lib/mkmf.rb (find_executable0): default path if environment is not set. [ruby-dev:27281] Thu Sep 22 16:33:12 2005 Shugo Maeda * test/readline/test_readline.rb (TestReadline::replace_stdio): merged the patch of [ruby-dev:25232] instead of [ruby-dev:25223]. Wed Sep 21 23:30:44 2005 Nobuyoshi Nakada * lib/mkmf.rb (configuration): generalized nmake dependent code. Wed Sep 21 09:07:55 2005 Yukihiro Matsumoto * stable version 1.8.3 released. Wed Sep 21 08:52:25 2005 why the lucky stiff * ext/syck/token.c: correctly compute identation of a block scalar's parent node. [ruby-talk:150620] Wed Sep 21 08:20:24 2005 Nobuyoshi Nakada * README.EXT, README.EXT.ja: add new features. Wed Sep 21 07:43:58 2005 Nobuyoshi Nakada * lib/optparse.rb (default_argv, Arguable#options): defaults strings to be parsed to Arguable instance. Wed Sep 21 02:44:09 2005 Yukihiro Matsumoto * file.c (path_check_0): disallow sticky world writable directory in PATH (and $LOAD_PATH). [ruby-dev:27226] * file.c (fpath_check): typo fixed. Tue Sep 20 22:29:49 2005 NAKAMURA, Hiroshi * test/wsdl/simpletype/rpc/test_rpc.rb, test/wsdl/ref/test_ref.rb, test/wsdl/any/test_any.rb test/soap/wsdlDriver/test_calc.rb: suppress deliberate warnings with $VERBOSE = nil. Tue Sep 20 21:26:23 2005 Nobuyoshi Nakada * ext/io/wait/lib/nonblock.rb: disable on platforms non-blocking flag is not available. fixed: [ruby-dev:27187] Tue Sep 20 18:23:04 2005 Tanaka Akira * eval.c (thread_mark): mark th->last_status. [ruby-dev:27179] Tue Sep 20 18:20:33 2005 Yukihiro Matsumoto * lib/yaml.rb: require 'yaml/constants'. [ruby-core:5776] Tue Sep 20 17:48:34 2005 Yukihiro Matsumoto * lib/xmlrpc/client.rb (XMLRPC::Client::do_rpc): add charset information to content-type header.[ruby-core:5127] * lib/xmlrpc/server.rb (CGIServer::serve): ditto. * lib/xmlrpc/server.rb (ModRubyServer::serve): ditto. * lib/xmlrpc/server.rb (WEBrickServlet::service): ditto. Tue Sep 20 17:34:46 2005 Hirokazu Yamamoto * test/webrick/test_cgi.rb: set ENV["PATH"] to CGIEnvPath on windows. bcc32's runtime is not installed into system directory, so it cannot be found without this setting. [ruby-dev:27166] Tue Sep 20 17:10:38 2005 Yukihiro Matsumoto * test/dbm/test_dbm.rb (TestDBM::test_s_open_error): remove test_s_open_error test to detect duplicate open. [ruby-dev:27202] Tue Sep 20 17:08:31 2005 Hirokazu Yamamoto * io.c: PIPE_BUF is not defined on BeOS. use _POSIX_PIPE_BUF instead. [ruby-dev:27185] Tue Sep 20 16:53:53 2005 Yukihiro Matsumoto * test/readline/test_readline.rb (TestReadline::replace_stdio): BSD seek support from [ruby-dev:25223]. fixed: [ruby-dev:27150] Tue Sep 20 15:39:40 2005 why the lucky stiff * ext/syck/emitter.c (syck_scan_scalar): prevent indicators from appearing alone or at the end of plain scalars. [ruby-core:5826] * ext/syck/emitter.c (syck_emit_scalar): treat typed scalar nodes as complex keys. * lib/syck.h: version 0.60. * lib/yaml/basenode.rb (YAML::BaseNode#at): transform keys during key searches. * ext/syck/rubyext.c: loading of binary-typed nodes. prevent emission of plain strings that look like symbols, but which aren't. Tue Sep 20 05:50:22 2005 Hirokazu Yamamoto * test/xmlrpc/test_webrick_server.rb (setup_http_server): should not include 'webrick/https' unless 'use_ssl' because it fails where openssl is not installed. Tue Sep 20 00:34:07 2005 Yukihiro Matsumoto * io.c (io_close): call rb_io_close() directly if io is a T_FILE object. [ruby-dev:27156] Mon Sep 19 19:09:08 2005 Minero Aoki * file.c (rb_file_chown): should accept nil. [ruby-dev:27171] (backport from trunk, rev 1.208) Mon Sep 19 18:35:13 2005 Yukihiro Matsumoto * ext/dl/dl.c (rb_io_to_ptr): fix DragonFlyBSD support. [ruby-dev:27151] Mon Sep 19 14:17:04 2005 Minero Aoki * ext/syck/emitter.c (syck_emit): passing an int* value to the long* parameter causes unaligned access on LP64 systems. [ruby-dev:27161] Mon Sep 19 13:44:03 2005 Masaki Suketa * ext/win32ole/win32ole.c: avoid core dump with WIN32OLE_EVENT. [ruby-dev:27133] Mon Sep 19 10:36:06 2005 Minero Aoki * lib/fileutils.rb (cp_r): default is :dereference_root=>true for backward compatibility. [ruby-dev:27145] * test/fileutils/test_fileutils.rb (test_cp_r): test it. Mon Sep 19 09:57:39 2005 Minero Aoki * test/fileutils/test_fileutils.rb: backported from trunk (1.36). (again) [ruby-dev:27145] Mon Sep 19 07:45:37 2005 GOTOU Yuuzou * ext/openssl/ossl_pkey.h, ossl_pkey_rsa.c, ossl_pkey_dsa.c: an instance variable "private" is added to OpenSSL::PKey class. this ivar is a flag that shows whether there is a private key in the instance. * ext/openssl/ossl_engine.c: (ossl_engine_load_privkey): set private key flag. Mon Sep 19 06:41:32 2005 Minero Aoki * lib/fileutils.rb: backported from trunk (rev 1.65): * lib/fileutils.rb (rm_r): new option :secure. * lib/fileutils.rb (rm_rf): new option :secure. * lib/fileutils.rb: new method #remove_entry_secure. * lib/fileutils.rb (cd): remove option :noop. * lib/fileutils.rb (cp_r): new option :dereference_root. * lib/fileutils.rb (cp_r): new option :dereference_root. * lib/fileutils.rb: new method #remove_entry. * lib/fileutils.rb: new method #chmod_R. * lib/fileutils.rb: new method #chown. * lib/fileutils.rb: new method #chown_R. * lib/fileutils.rb: new method .commands. * lib/fileutils.rb: new method .options. * lib/fileutils.rb: new method .have_option?. * lib/fileutils.rb: new method .options_of. * lib/fileutils.rb: new method .collect_method. * lib/fileutils.rb: use module_function instead of single extend. * test/fileutils/test_fileutils.rb: backported from trunk (1.36). Mon Sep 19 03:17:48 2005 Tanaka Akira * file.c (rb_thread_flock): wrap the flock system call by TRAP_BEG/TRAP_END to enable signals. [ruby-dev:27122] * ext/socket/socket.c (bsock_send): wrap the sendto and send system call by TRAP_BEG/TRAP_END to enable signals when writing to a socket which is full. [ruby-dev:27132] * io.c (rb_io_syswrite): wrap the write system call by TRAP_BEG/TRAP_END to enable signals when writing to a pipe which is full. [ruby-dev:27134] Mon Sep 19 03:02:08 2005 Tanaka Akira * io.c (io_fwrite): wrap the write system call by TRAP_BEG/TRAP_END to enable signals when writing to a pipe which is full. Sun Sep 18 02:10:47 2005 why the lucky stiff * lib/yaml/rubytypes.rb: remove comments that are bungling up the rdoc and ri output. output symbols as plain scalars. * ext/syck/rubyext.c (syck_emitter_reset): emit headless documents always. * ext/syck/emitter.c (syck_scan_scalar): quote scalars with any kind of surrounding line space, tabs or spaces alike. * ext/syck/token.c: accept tabs as whitespace, not for indentation, but strip from plain scalars. * test/yaml/test_yaml.rb: remove outdated tests. Sat Sep 17 23:25:04 2005 sheepman * lib/mathn.rb (Rational::inspect): should preserve original operand. [ruby-core:05806] Sat Sep 17 23:20:27 2005 Yukihiro Matsumoto * lib/cgi.rb (CGI::Cookie): should handle multiple values for a cookie name. [ruby-talk:156140] Sat Sep 17 10:42:13 2005 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: MultiTkIp#eval_string and bg_eval_string should call Kernel.eval on caller's safe-level instead of slave's safe-level (Of course, the given script should be evaluated on slave's safe-level). Sat Sep 17 09:45:26 2005 Yukihiro Matsumoto * string.c (rb_str_substr): should propagate taintness even for empty strings. [ruby-dev:27121] * string.c (rb_str_aref): should infect result if range argument is tainted. [ruby-dev:27121] Sat Sep 17 08:35:39 2005 Kouhei Sutou * lib/rss/maker/base.rb (RSS::Maker::ItemsBase#normalize): fixed strange RSS::Maker::Item#max_size behavior. Thanks to Kazuhiko . * test/rss/test_maker_1.0.rb (RSS::TestMaker10#test_items): ditto. Fri Sep 16 23:09:20 2005 Masaki Suketa * ext/win32ole/win32ole.c (ole_search_event_at): bug fix in ext/win32ole/sample/ienavi.rb. * ext/win32ole/win32ole/tests/testOLEEVENT.rb: ditto. Fri Sep 16 22:41:18 2005 Nobuyoshi Nakada * file.c (rb_file_s_extname): empty string for path name ending with a period. fixed: [ruby-core:05651] * file.c (rb_file_join): smarter behavior at edge cases. fixed: [ruby-core:05706] Fri Sep 16 18:34:01 2005 Yukihiro Matsumoto * ext/syck/node.c (syck_replace_str): was using return from the void function. a patch from MIYAMUKO Katsuyuki . [ruby-dev:27111] Fri Sep 16 14:48:48 2005 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: fix typo on MultiTkIp#bg_eval_string Fri Sep 16 12:02:12 2005 Yukihiro Matsumoto * ext/syck/rubyext.c (syck_resolver_transfer): remove C++ style comment (//). [ruby-core:05793] Fri Sep 16 00:14:14 2005 NAKAMURA, Hiroshi * test/logger/test_logger.rb: unintentionally overwritten changes by Usa. reverted. Fri Sep 16 00:06:18 2005 GOTOU Yuuzou * lib/webrick/cgi.rb (WEBrick::CGI::Socket#initialize): should set $stdout.binmode. Thu Sep 15 23:25:21 2005 NAKAMURA, Hiroshi * lib/{soap,wsdl,xsd}, test/{soap,wsdl,xsd}: imported soap4r/1.5.5. #nnn is a ticket number at http://dev.ctor.org/soap4r * SOAP * allow to configure an envelope namespace of SOAP request. (#124) TemporaryNamespace = 'http://www.w3.org/2003/05/soap-envelope' @client.options["soap.envelope.requestnamespace"] = TemporaryNamespace @client.options["soap.envelope.responsenamespace"] = TemporaryNamespace @client.do_proc(...) * let SOAP request XML indent space configuable. see "soap.envelope.no_indent" option. (#130) * let external CES configuable. ex. client["soap.mapping.external_ces"] = 'SJIS'. $KCODE is used by default. (#133) external CES ::= CES used in Ruby object of client and server internal CES ::= CES used in SOAP/OM * add iso-8859-1 external CES support. (#106) * fixed illegal 'qualified' handling of elements. it caused ASP.NET inteoperability problem. (#144) * added 'soap.envelope.use_numeric_character_reference' (boolean) option to let query XML use numeric character reference in XML, not plain UTF-8 character. !GoogleSearch server seems to not allow plain UTF-8 character since 2005-08-15 update. (#147) * SOAP::Header::SimpleHeader (de)serialization throws an exception on !SimpleHeader.on_(in|out)bound when header is a String. so we could not use a simple single element headerItem. fixed. thanks to emil. (#129) * out parameter of rpc operation did not work. (#132) * follow HTTP redirect only if using http-access2. (#125) (#145) * add a workaround for importing an WSDL whose path begins with drive letter. (#115) * WSDL * SOAP Data which is defined as a simpletype was not mapped correctly to Ruby obj when using wsdl2ruby.rb generated classdef file. (#123) * rpc/literal support. (#118) * re-implemented local element qualify/unqualify control. handles elementFormDefault and form in WSDL. (#119) * Array of an element which has simpleType causes a crash. (#128) * prarmeterOrder may not contain return part so it can be shorter than parts size. Thanks to Hugh. (#139) * Samples * added !BasicAuth client sample. (#117) * added Base64 client/server sample. * added Flickr SOAP interface client sample. (#122) * added !SalesForce client sample. (#135) * updated Thawte CA certificate for !GoogleAdWords sample. * updated a client script with the newer version made by Johan. thanks! * shortened long file names. (#120) * fixed typo in authheader sample. (#129) * updated deprecated method usage. (#138) Thu Sep 15 23:02:57 2005 Hirokazu Yamamoto * win32/win32.h (rb_w32_stat): added prototype. Thu Sep 15 22:35:55 2005 NAKAMURA Usaku * test/ruby/test_signal.rb (test_exit_action): skip the test using fork on fork-less platforms. Thu Sep 15 11:39:18 2005 Hidetoshi NAGAI * ext/tk/lib/tk/dialog.rb: If a dialog does not show up yet, TkDialogObj#name raises an exception. [ruby-talk:156109] Thu Sep 15 01:39:19 2005 Masatoshi SEKI * lib/rinda/tuplespace.rb (Rinda::TemplateEntry::initialize): pull up method. Tabs converted to spaces. Thu Sep 15 00:18:24 2005 Yukihiro Matsumoto * lib/net/telnet.rb (Net::Telnet::waitfor): replace sysread with readpartial. [ruby-talk:127641] Wed Sep 14 22:40:26 2005 Nobuyoshi Nakada * dir.c (ruby_glob): glob function not using ruby exception system. Wed Sep 14 01:26:03 2005 Minero Aoki * lib/net/https.rb: backported from trunk, rev 1.3. [ruby-dev:25673] (again), [ruby-dev:26617] (again), [ruby-dev:27062] * ext/openssl/lib/net/https.rb: removed. * ext/openssl/lib/net/protocols.rb: removed. * lib/net/http.rb: #use_ssl?, #use_ssl are moved from net/https. Tue Sep 13 22:09:40 2005 NAKAMURA, Hiroshi * lib/logger.rb (Logger): added formatter accessor to logger for dictating the way in which the logger should format the messages it displays. Thanks to Nicholas Seckar (cf. [ruby-talk:153391]) and Daniel Berger. * lib/logger.rb (Logger): added VERSION constant. * lib/logger.rb: removed document for LogDevice. It is an implementation detail and is not a public interface. * test/logger/test_logger.rb: added tests. Tue Sep 13 21:47:17 2005 Nobuyoshi Nakada * eval.c (BEGIN_CALLARGS): pop halfly pushed status. fixed: [ruby-dev:26881] Tue Sep 13 16:26:45 2005 Minero Aoki * lib/net/http.rb: backported from trunk, rev 1.128. [ruby-dev:25673] [ruby-dev:26617] * lib/net/protocol.rb: backported from trunk, rev 1.78. * lib/net/protocol.rb: new method #old_open to support net/smtp and net/pop. * lib/net/smtp.rb: use #old_open. * lib/net/pop.rb: ditto. Tue Sep 13 12:33:05 2005 why the lucky stiff * lib/yaml.rb: reworking YAML::Stream to use the new emitter. * lib/yaml/stream.rb: ditto. * lib/yaml/rubytypes.rb: added Object#yaml_new. * lib/yaml/tag.rb: the tag_subclasses? method now shows up in the class. allow taguri to be set using an accessor. continue support of Object#to_yaml_type. * ext/syck/rubyext.c: new emitter code. yaml_new and yaml_initialize get called, should they be present. consolidated all the diaspora of internal node types into the family below YAML::Syck::Node -- Map, Seq, Scalar -- all of whom are SyckNode structs pointing to Ruby data. moved Object#yaml_new into the node_import and made it the default behavior. the target_class is always called wih yaml_new, prepended a parameter, which is the klass. loaded nodes through GenericResolver show their style. new Resolver#tagurize converts type ids to taguris. * ext/syck/implicit.re: were 'y' and 'n' seriously omitted?? * ext/syck/emitter.c: renovated emitter, walks the tree in advance. consolidated redundant block_styles struct into the scalar_style struct. (this means loaded nodes can now be sent back to emitter and preserve at least its very basic formatting.) * ext/syck/gram.c: headless documents of any kind allowed. * ext/syck/node.c: new syck_replace_str methods and syck_empty_* methods for rewriting node contents, while keeping the ID and other setup info. added syck_seq_assign. * ext/syck/syck.h: reflect block_styles and new node functions. Mon Sep 12 20:53:06 2005 GOTOU Yuuzou * test/openssl/test_pkcs7.rb (test_enveloped): skip this test to avoid a bug of PKCS7_enctypt() (only if ext/openssl is compiled with OpenSSL-0.9.7d or earlier versions). http://www.mail-archive.com/openssl-dev@openssl.org/msg17376.html Mon Sep 12 14:03:33 2005 Yukihiro Matsumoto * test/dbm/test_dbm.rb: remove locking test, which may not be supported on some platforms. [ruby-dev:27030] Mon Sep 12 10:45:58 2005 Yukihiro Matsumoto * ext/dl/dl.c (rb_io_to_ptr): merged a patch for DragonFly BSD from Takahiro Kambe . [ruby-dev:27023] Sun Sep 11 22:05:51 2005 Masatoshi SEKI * bin/erb (ERB::Main#run): set ERB#filename so that it is used when reporting syntax/runtime errors. Tabs converted to spaces. Sat Sep 10 10:17:03 2005 GOTOU Yuuzou * ext/openssl/ossl_engine.c (ossl_engine_s_by_id): OpenSSL::Engine.by_id calls given block before calling ENGINE_init (block parameter is the return value of this method itself). this functionality is useful to load dynamic shared engines. the following code is a sample of loading a key using OpenSC PKCS #11 module. require "openssl" pkcs11 = OpenSSL::Engine.by_id("dynamic"){|e| e.ctrl_cmd("SO_PATH", "/usr/lib/opensc/engine_pkcs11.so") e.ctrl_cmd("LIST_ADD", "1") e.ctrl_cmd("LOAD") } pkcs11.ctrl_cmd("PIN", "secret") key = pkcs11.load_private_key * ext/openssl/ossl_engine.c (ossl_engine_ctrl_cmd): new method OpenSSL::Engine#ctrl_cmd. it wraps ENGINE_ctrl_cmd_string. * ext/openssl/ossl_engine.c (ossl_engine_get_cmds): new method OpenSSL::Engine#cmds. it returms engine command definitions. Sat Sep 10 10:09:47 2005 GOTOU Yuuzou * ext/openssl/ossl_asn1.c (asn1str_to_str): new function. * ext/openssl/ossl_pkcs7.c: new class OpenSSL::PKCS7::RecipientInfo. this class wraps PKCS7_RECIP_INFO struct. * ext/openssl/ossl_pkcs7.c: OpenSSL::PKCS7::Signer is renamed to OpenSSL::PKCS7::SignerInfo. ("Signer" remains as an alias of SignerInfo.) * test/openssl/test_pkcs7.rb: new file. Sat Sep 10 10:05:51 2005 GOTOU Yuuzou * ext/openssl/ossl_ns_spki.c (ossl_spki_initialize): assume that the argument is a DER string if Base64 decoding failed. * ext/openssl/ossl_ns_pki.c (ossl_spki_to_der): new method. * test/openssl/test_ns_spki.rb: add new file. Sat Sep 10 09:56:24 2005 GOTOU Yuuzou * ext/openssl/lib/digest.rb: added SHA224, SHA256, SHA384 and SHA512. these features are enabled if this library is compiled with OpenSSL 0.9.8 or later. * test/openssl/test_digest.rb: add test for new digests. Sat Sep 10 09:51:30 2005 GOTOU Yuuzou * ext/openssl/ossl.c (ossl_raise): should use ERR_peek_last_error to get last error on the current thread. And should report errors on the stack while OpenSSL.debug is true. * ext/openssl/ossl.c (ossl_get_errors): new method for debugging this library. * ext/openssl/ossl_ssl.c (ossl_sslctx_set_ciphers): fix error message. * ext/openssl/ossl_x509req.c (ossl_x509req_set_attributes): get rid of unused variable. * ext/openssl/ossl_x509store.c (ossl_x509store_initialize): should set @time to avoid warning. * ext/openssl/ossl_x509store.c (ossl_x509store_set_default_paths, X509_STORE_add_cert, X509_STORE_add_crl): should raise error if wrapped functions failed. * test/openssl/test_x509store.rb: add test for errors. Fri Sep 9 22:13:19 2005 Yukihiro Matsumoto * eval.c (rb_call0): prohibit calling tainted method (>2) when $SAFE == 0. Fri Sep 9 16:45:25 2005 Nobuyoshi Nakada * string.c (rb_str_times): make empty strings to keep taintness, and a little improvement. [ruby-dev:26900] * ext/iconv/iconv.c (iconv_try), ext/iconv/extconf.rb: get rid of meta characters in command line option. fixed: [ruby-talk:155369] Thu Sep 8 14:58:11 2005 Yukihiro Matsumoto * merged a patch from Takahiro Kambe to support DragonFly BSD. [ruby-dev:26984] Wed Sep 7 12:55:08 2005 Tanaka Akira * lib/open-uri.rb: abolish mod === tempfile to avoid a problem [ruby-dev:26967]. Wed Sep 7 10:45:15 2005 Nobuyoshi Nakada * eval.c (rb_thread_switch): convert all exceptions to SystemExit. fixed: [ruby-core:05724] * eval.c (rb_thread_terminated): show backtrace before propagate exceptions to main thread. Wed Sep 7 08:35:04 2005 Nobuyoshi Nakada * Makefile.in, configure.in (MINIOBJS): miniruby on HP-UX can not load extension libraries. * bignum.c (bignew_1, bigadd): K&R style argument actually can't be defined as char. * missing/vsnprintf.c: ANSI compiler supports const keyword. * ext/digest/sha2/extconf.rb: reject platforms which has inttypes.h but no 64bit integer. * lib/mkmf.rb (what_type?): guesstimate type. * ext/etc/etc.c (setup_passwd), ext/etc/extconf.rb: pw_age might be char*. fixed: [ruby-core:05470] Wed Sep 7 08:32:47 2005 Yukihiro Matsumoto * object.c (rb_mod_cvar_get, rb_mod_cvar_set): document fix from sheepman ; a bug in visibility description. [ruby-dev:26965] * sprintf.c (rb_f_sprintf): warn "too many argument" on verbose mode (-v/-w); backported from 1.9. [ruby-dev:26963] Mon Sep 5 17:03:07 2005 Yukihiro Matsumoto * lib/ostruct.rb: a patch from Florian Gross merged to allow recursive inspect (and to_s) for OpenStruct. [ruby-core:05532] Mon Sep 5 07:01:12 2005 GOTOU Yuuzou * ext/openssl/openssl/lib/openssl/buffering.rb (Buffering#do_write): should clear data from the buffer which already been output. Fri Sep 2 23:51:54 2005 Nobuyoshi Nakada * lib: do not use __send__ to access private methods. [ruby-dev:26935] Fri Sep 2 03:29:00 2005 Keiju Ishitsuka * lib/irb/init.rb: make IRB -I option that is same befavior for ruby. [ruby-dev:26872], [ruby-dev: 26920] * lib/irb/locale.rb: support to print help message when OS locale is ja_JP.utf-8. [ruby-dev:26872] Thu Sep 1 17:11:25 2005 Yukihiro Matsumoto * eval.c (rb_call0): wrong condition for $SAFE restoration. Thu Sep 1 14:12:45 2005 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: On Tcl8.5, MultiTkIp#invoke_hidden doesn't work (gives wrong order of arguments). * ext/tk/lib/multi-tk.rb: add MultiTkIp#invoke_hidden_on_namespace to support '-namespace' option of 'interp invokehidden' command on Tcl8.5. Wed Aug 31 14:43:15 2005 NAKAMURA Usaku * win32/Makefile.sub (OPTFLAGS): default global optimization to disabled for all VC++ versions. fixed: [ruby-dev:26897] Wed Aug 31 11:35:43 2005 NAKAMURA Usaku * test/gdbm/test_gdbm.rb (teardown): should remove GDBM temporary file. Wed Aug 31 10:30:56 2005 Hirokazu Yamamoto * process.c (proc_detach, proc_setmaxgroups): missing argument type declaration. (I recommend ANSI-style function) Tue Aug 30 23:20:19 2005 Nobuyoshi Nakada * eval.c (rb_rescue2): initialization miss. fixed: [ruby-dev:26917] * lib/mkmf.rb (xsystem, xpopen): no longer expand by Config. * lib/mkmf.rb (link_command, cc_command, cpp_command): expand variables at once, and quote hdrdir. fixed: [ruby-core:05680] * lib/mkmf.rb (libpathflag): quote paths. Tue Aug 30 19:34:27 2005 GOTOU Yuuzou * ext/digest/md5/md5ossl.h, ext/digest/rmd160/rmd160ossl.h, ext/digest/sha1/sha1ossl.h: include to avoid error in compilation with OpenSSL-0.9.8. [ruby-list:41068] Mon Aug 29 19:54:21 2005 Hirokazu Yamamoto * lib/rdoc/usage.rb: improper exceptions. [ruby-dev:26870] * lib/rdoc/usage.rb: support the case when non-ruby code exists before shebang. (this is needed when ri.bat is executed on windows) Mon Aug 29 17:48:17 2005 Yukihiro Matsumoto * eval.c (method_arity): should return proper arity value. [ruby-dev:26390] Mon Aug 29 01:19:57 2005 Tanaka Akira * lib/time.rb (Time.parse): extract fractional seconds using Date._parse. [ruby-talk:153859] Sat Aug 27 20:20:01 2005 Hirokazu Yamamoto * ext/curses/curses.c ({curses,window}_clrtoeol): added. suggested by Reyn Vlietstra. * ext/curses/curses.c: chtype in curses is not `char', rahter `long'. [ruby-Bugs:2298] * ext/curses/view.rb: String =~ String is deprecated. Wed Aug 24 10:53:28 2005 NAKAMURA Usaku * test/logger/test_logger.rb (test_shifting_size): should close log device before unlink, since some platform cannot unlink opened file. Sun Aug 21 00:13:27 2005 NAKAMURA, Hiroshi * lib/wsdl/xmlSchema/importer.rb (WSDL::XMLSchema::Importer#fetch): add a workaround for importing an WSDL whose path begins with drive letter. [ruby-dev:26242] Sat Aug 20 22:37:13 2005 NAKAMURA, Hiroshi * lib/logger.rb (write, shift_log?, shift_log): file shifting race condition bug fixed. [ruby-dev:26764] * test/logger/test_logger.rb: tests. Fri Aug 19 18:13:39 2005 Tanaka Akira * lib/time.rb (Time.apply_offset): fix a problem with last day of month. reported by Lucas Nussbaum. [ruby-talk:152866] Thu Aug 18 12:46:28 2005 Hirokazu Yamamoto * bcc32/Makefile.sub (COMMON_HEADERS): reverted 1.42.2.24. I misunderstood, bccwin32 on ruby_1_8 uses winsock2 originally. [ruby-dev:26806] * win32/win32.h: include winsock2.h instead of winsock.h. (bcc32) Wed Aug 17 23:58:05 2005 Nobuyoshi Nakada * object.c (rb_to_integer): argument constified. * eval.c (terminate_process): take String message. * eval.c (rb_thread_switch): propagate the exception caused thread termination directly. fixed: [ruby-core:05552] Wed Aug 17 00:05:46 2005 Yukihiro Matsumoto * eval.c (rb_add_method): preserve safe level in the environment where a method is defined . * eval.c (rb_call0): restore preserved safe level in the method execution. Mon Aug 15 00:38:51 2005 Nobuyoshi Nakada * eval.c (rb_rescue2): reduce PUSH_TAG() as well as NODE_RESCUE. [ruby-dev:26800] * range.c (range_check, range_init): reduce useless exceptions. Sat Aug 13 18:51:26 2005 Nobuyoshi Nakada * eval.c (rb_block_pass): distinguish current block from others. fixed: [ruby-dev:26274] * ext/stringio/stringio.c (strio_set_string): disallow nil. http://www.rubyist.net/~nobu/t/20050811.html#c05 Thu Aug 11 23:29:03 2005 Nobuyoshi Nakada * ext/stringio/stringio.c: keep holding string after closed. Thu Aug 11 13:01:48 2005 Kouhei Sutou * lib/rss: fixed sort bug. [ruby-list:41018] * lib/rss/1.0.rb (RSS::RDF::Channel#setup_maker_attributes): removed self. * lib/rss/maker/base.rb (RSS::Maker::ItemsBase#<=>): use #date instead of @date. (RSS::Maker::Base::self.def_array_element): added #size. * lib/rss/maker/1.0.rb (RSS::Maker::RSS10::Channel#to_rss, RSS::Maker::RSS10::Items::Item#to_rss): cleared dc_dates set upped by using #date. * lib/rss/maker/dublincore.rb (RSS::Maker::ChannelBase, RSS::Maker::ItemsBase::ItemBase): fixed opposite alias. * test/rss/test_setup_maker_1.0.rb (RSS::TestSetupMaker10::test_setup_maker_items_sort): added some tests for RSS::Maker::ItemsBase#do_sort. Wed Aug 10 10:29:40 2005 Hidetoshi NAGAI * ext/tk/lib/tk.rb: fix bug on handling __ruby2val_optkeys(). * ext/tk/lib/tk/itemconfig.rb: fix bug on handling __item_ruby2val_optkeys(). * ext/tk/lib/tk/canvas.rb: didn't check __item_ruby2val_optkeys(). * ext/tk/lib/tkextlib/blt/component.rb: ditto. Tue Aug 9 15:12:04 2005 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: remove dangerous 'rb_jump_tag's. * ext/tk/lib/tk.rb: add __val2ruby_optkeys and __ruby2val_optkeys to help to convert option values between ruby and tcl. * ext/tk/lib/tk/itemconfig.rb: add __item_val2ruby_optkeys and __item_ruby2val_optkeys to help to convert option values between ruby and tcl. * ext/tk/lib/tk/radiobutton.rb: use __ruby2val_optkeys for 'variable' option (for the reason of backward compatibility). * ext/tk/lib/tk/composite.rb: clarify the arguments of super(). * ext/tk/lib/tk/spinbox.rb: ditto. * ext/tk/lib/tk/text.rb: ditto. * ext/tk/lib/tk/validation.rb: ditto. * ext/tk/lib/tkextlib/*: support to treat tkvariable-type configure options. Tue Aug 9 20:30:19 2005 Tadashi Saito * bignum.c (rb_big_coerce): allow bignum x bignum coercing. [ruby-dev:26778] Mon Aug 8 20:43:02 2005 NAKAMURA, Hiroshi * test/ruby/test_method.rb: added. [ruby-dev:26761] Sun Aug 7 23:50:14 2005 NAKAMURA, Hiroshi * test/ruby/test_super.rb: added from HEAD. [ruby-dev:26743] Sun Aug 7 01:31:15 2005 Masaki Suketa * ext/win32ole/win32ole.c (WIN32OLE_EVENT#on_event): should set only one event handler. * ext/win32ole/tests/testOLEEVENT.rb: ditto. * ext/win32ole/tests/testOLEPARAM.rb: remove re-defined test_ole_type_detail method. Sat Aug 6 12:35:24 2005 Hidetoshi NAGAI * ext/tk/lib/{tk.rb,tk/itemconfig.rb}: configure creates TkVariable if key name is 'variable' or 'textvariable' by default. [ruby-dev:26749] * ext/tk/lib/tk/{label,radiobutton}.rb: removed its own {variable,textvariable} function. * ext/tk/lib/tk/variable.rb: retains backward conpatibility. Fri Aug 5 12:50:32 2005 Hirokazu Yamamoto * ext/tcltklib/tcltklib.c: fixed memory leak when tk_funcall raised exception. (copies argv into heap in tk_funcall instead of caller) Fri Aug 5 12:42:57 2005 NAKAMURA Usaku * lib/mkmf.rb (create_makefile): need to convert path separetor before invoking install command. Fri Aug 5 00:27:04 2005 Hirokazu Yamamoto * ext/tcltklib/tcltklib.c: refactoring - extract ruby string <-> tcl object conversion as get_str_from_obj and get_obj_from_str. Fri Aug 5 00:19:33 2005 Nobuyoshi Nakada * extmk.rb (extmake): needs to be wrapped in an Array. Thu Aug 4 18:38:36 2005 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: cannot compile for Tcl7.6/Tk4.2. * ext/tcltklib/tcltklib.c: add nativethread consistency check. * ext/tcltklib/stubs.c: ditto. * ext/tk/lib/tk.rb: forgot to define TclTkIp.encoding and encoding= when Tcl is 7.6 or 8.0. * ext/tk/lib/tk/wm.rb: support to make some methods as options of root or toplevel widget. [ruby-talk:150336] * ext/tk/lib/tk/root.rb: ditto. * ext/tk/lib/tk/toplevel.rb: ditto. * ext/tk/lib/tkextlib/SUPPRT_STATUS: update RELEASE_DATE Thu Aug 4 08:03:39 2005 Nobuyoshi Nakada * ext/extmk.rb (extmake): should not modify $mflags for each extentions. Thu Aug 4 00:25:48 2005 Nobuyoshi Nakada * common.mk, Makefile.in, {bcc32,win32,wince}/Makefile.sub: integrated macro definitions. * bcc32/Makefile.sub: LIBRUBY_SO should use DLDOBJS, not EXTOBJS. * {win32,wince}/Makefile.sub: separate config.h for compiler versions. Wed Aug 3 21:59:16 2005 Hidetoshi NAGAI * ext/tk/lib/tk/variable.rb: TkVariable#trace didn't work on TkVariable retrived from TkVariable.new_hash.ref. [ruby-dev:26721] Wed Aug 3 08:22:13 2005 Yukihiro Matsumoto * ext/socket/socket.c (ruby_connect): revert [ruby-talk:111654] changes at 2004-09-07. [ruby-dev:26656] Tue Aug 2 10:20:54 2005 Hirokazu Yamamoto * ext/tcltklib/tcltklib.c: use Tcl_[GS]etVar2Ex instead of Tcl_Obj[GS]etVar2. (avoid Tcl_NewStringObj on supported platforms) * ext/tcltklib/tcltklib.c: use ip_{get,set,unset}_variable2_core from ip_{get,set,unset}_variable. * ext/tcltklib/tcltklib.c: replaced Tcl_Panic with rb_bug. Tue Aug 2 01:41:28 2005 GOTOU Yuuzou * lib/ping.rb (Ping.pingecho): should rescue StandardError. [ruby-dev:26677] Mon Aug 1 19:09:41 2005 Hirokazu Yamamoto * ext/tcltklib/tcltklib.c: refactoring - replaced rb_ivar_defined & rb_ivar_get with single rb_attr_get call. Mon Aug 1 18:45:07 2005 Hirokazu Yamamoto * ext/tcltklib/tcltklib.c (Tcl_GetStringResult): refactoring - define alternative macro on Tcl7.x or earlier. Mon Aug 1 13:57:35 2005 Hirokazu Yamamoto * ext/tcltklib/tcltklib.c (deleted_ip): refactoring - interpreter deletion check. [ruby-dev:26664] Mon Aug 1 01:17:40 2005 Masatoshi SEKI * lib/drb/drb.rb (check_insecure_method): use private_methods and protected_methods instead of respond_to? to check method visibility. [ruby-dev:26616] * test/drb/drbtest.rb: ditto. * test/drb/ut_drb.rb: ditto. Mon Aug 1 00:07:32 2005 Keiju Ishitsuka * lib/irb/context.rb: fix `irb --readline` option. [ruby-list:40955] Fri Jul 29 09:59:38 2005 Nobuyoshi Nakada * eval.c (rb_yield_0): push yielded node instead of yielding. fixed: [yarv-dev:549] Thu Jul 28 18:09:55 2005 Hidetoshi NAGAI * ext/tcltklib/stubs.c: When --enable-tcltk-stubs, the initialize routine creates a Tcl/Tk interpreter and deletes it. However, init cost of Tk's MainWindow is not so small. And that makes it impossible to use libraries written with Tcl functions only on an environment without a graphical display. This changes support delaying initalization of Tk_Stubs until the script needs Tk. * ext/tcltklib/stubs.h: New file. Define prototypes and return codes of functions on stubs.c. * ext/tcltklib/tcltklib.c: Support delaying initalization of Tk_Stubs until the script needs Tk. * ext/tcltklib/tcltklib.c: Show friendly error messages for errors on initialization. * ext/tcltklib/tcltklib.c: Avoid SEGV on ip_finalize() when ruby is exiting and $DEBUG is true. (Not fix. If you know the reason of why, please fix it.) * ext/tk/tkutil.c (ary2list, ary2list2): bug fix on handling of encoding. * ext/tk/lib/multi-tk.rb: MultiTkIp#eval_string and bg_eval_string don't work propery. * ext/tk/lib/tk.rb: Forget extending Tk::Encoding module to Tk. * ext/tk/lib/tk/variable.rb: TkVarAccess fails to initialize the object for an element of a Tcl's array variable. Wed Jul 27 23:23:54 2005 Yukihiro Matsumoto * gc.c (obj_free): make message format consistent with one from gc_mark(). [ruby-talk:149668] Wed Jul 27 22:11:37 2005 Kouhei Sutou * sample/rss/tdiary_plugin: removed. because the plugin is imported in the tDiary plugin packages. Wed Jul 27 10:59:02 2005 Yukihiro Matsumoto * dir.c (dir_each): rewinddir(3) before iteration. [ruby-talk:149628] Tue Jul 26 12:57:49 2005 GOTOU Yuuzou * ext/openssl/openssl_missin.c: include before to avoid compilation error of mswin32. suggested by NAKAMURA Usaku. Mon Jul 25 21:30:46 2005 Nobuyoshi Nakada * {bcc32,win32,wince}/Makefile.sub: moved CPPFLAGS only for ruby source to XCFLAGS. Mon Jul 25 13:45:18 2005 NAJIMA Hiroki * io.c: check HAVE_SYS_IOCTL_H before including the header. [ruby-dev:26610] Mon Jul 25 14:10:02 2005 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: fix en-bugged part in the last commit. Sat Jul 23 16:49:04 2005 GOTOU Yuuzou * ext/openssl/ossl_engine.c (ossl_engine_s_load): should check OPENSSL_NO_STATIC_ENGINE. Fri Jul 22 21:06:08 2005 Tadashi Saito * bignum.c (rb_big_eq): reduce isnan(). [ruby-dev:26600] * numeric.c (flo_eq, flo_gt, flo_ge, flo_lt, flo_le): ditto. Fri Jul 22 15:02:39 2005 Kouhei Sutou * lib/rss/rss.rb: moved copyright description to lib/rss.rb. * lib/rss.rb: added for convenience. * sample/rss/re_read.rb: added #to_s sample. * sample/rss/blend.rb: use 'require "rss"' instead of 'require "rss/*"'. * sample/rss/list_description.rb: ditto. * sample/rss/rss_recent.rb: ditto. * sample/rss/tdiary-plugin/rss-recent.rb: ditto. * sample/rss/tdiary-plugin/rss-recent.rb: 0.0.6 -> 0.0.7. Fri Jul 22 14:37:43 2005 Kouhei Sutou * lib/rss/parser.rb (RSS::Parser#initialize): accept HTTP/FTP URI and local file path too. * test/rss/test_parser.rb (RSS::TestParser#test_parse): test for the above. Fri Jul 22 07:01:42 2005 Hidetoshi NAGAI * ext/tk/tkutil.c (tk_conv_args): forget to revert thread_critical and gc_disable when raise ArgumentError. * ext/tk/lib/remote-tk.rb: RemoteTkIp doesn't need to include TkUtil. * ext/tcltklib/tcltklib.c: add TclTkIp#has_mainwindow? method. * ext/tk/lib/tk.rb: add Tk.has_mainwindow? method. * ext/tk/lib/multi-tk.rb: add MultiTkIp#has_mainwindow? method. * ext/tk/lib/remote-tk.rb: add RemoteTkIp#has_mainwindow? method. * ext/tk/lib/multi-tk.rb: slave IP fail to exit itself when $SAFE==4. * ext/tk/lib/multi-tk.rb: remove constants from MultiTkIp module to avoid access from external. * ext/tk/lib/multi-tk.rb: check_root flag is ignored on slave IPs' mainloop. * ext/tk/lib/multi-tk.rb: hang-up Tk.mainloop called on a slave IP with $SAFE==4. * ext/tk/lib/multi-tk.rb: MultiTkIp#bg_eval_proc doesn't work properly. * ext/tk/lib/multi-tk.rb: add MultiTkIp#set_cb_error(proc) and cb_error(exc) to log errors at callbacks on safe slave IPs. * ext/tk/lib/multi-tk.rb: fail to get an available slave IP object when call Tk.mainloop in the block which is given to new_* method, because cannot finish initialize while the root widget is alive. * ext/tk/lib/multi-tk.rb: fail to control a slave IP when Tk.mainloop runs on the IP. Wed Jul 20 19:20:37 2005 NAKAMURA Usaku * io.c (S_ISREG): need to define S_ISREG before it is used first. Wed Jul 20 18:40:50 2005 Hirokazu Yamamoto * io.c (wsplit_p): patch for the environment where fcntl(F_GETFL, O_NONBLOCK) is not supported. in that case, set FMODE_WSPLIT without fcntl check. [ruby-dev:26566] Wed Jul 20 18:07:11 2005 Tanaka Akira * io.c (rb_io_ctl): update FMODE_WSPLIT_INITIALIZED and FMODE_WSPLIT by F_SETFL. Wed Jul 20 10:04:51 2005 Yukihiro Matsumoto * variable.c (rb_class_path): need to adjust snprintf() len for teminating NUL. [ruby-dev:26581] Wed Jul 20 04:01:55 2005 Hirokazu Yamamoto * ext/socket/socket.c: sorry, BeOS also uses HAVE_CLOSESOCKET, so reverted. * ext/socket/extconf.rb: should not define HAVE_CLOSESOCKET on windows. Wed Jul 20 03:16:43 2005 Hirokazu Yamamoto * ext/socket/socket.c: should not undef close() on win32. it's defined to rb_w32_close(), otherwise handle leaks. [ruby-Bugs-2131] Wed Jul 20 00:48:16 2005 Yukihiro Matsumoto * error.c (syserr_initialize): don't use str before StringValue() check. [ruby-dev:26579] Tue Jul 19 22:47:29 2005 Yukihiro Matsumoto * error.c (syserr_initialize): add 1 byte for snprintf() size for NUL at the end. [ruby-dev:26574] Tue Jul 19 16:39:46 2005 Yukihiro Matsumoto * io.c (rb_io_inspect): replace sprintf() with "%s" format all over the place by snprintf() to avoid integer overflow. Tue Jul 19 14:08:22 2005 Hirokazu Yamamoto * ext/tcltklib/tcltklib.c: rbtk_eventloop_depth is used as int. * ext/tcltklib/tcltklib.c: rbtk_pending_exception is tested with NIL_P, so should assign Qnil instead of 0 (Qfalse). * ext/tcltklib/tcltklib.c (ip_invoke_real): fixed memory leak when ip is deleted. Tue Jul 19 13:19:46 2005 Hidetoshi NAGAI * ext/tk/lib/tk/variable.rb: For symmetry, add TkVariable#string. It returns a string even if the default value type of the TkVariable object is not "string". Mon Jul 18 21:40:20 2005 Hirokazu Yamamoto * eval.c (rb_call0): make the pointer to NODE volatile instead of NODE itself. Mon Jul 18 14:32:21 2005 Tanaka Akira * eval.c (rb_call0): make body volatile to avoid optimization problem. [ruby-dev:26195] Mon Jul 18 12:23:27 2005 Hirokazu Yamamoto * ext/io/wait/wait.c: wrong backport from trunk. fixed: [ruby-dev:26562] Mon Jul 18 09:36:25 2005 Tanaka Akira * rubyio.h (FMODE_WSPLIT, FMODE_WSPLIT_INITIALIZED): new constant. * io.c (wsplit_p): new function. (io_fwrite): split writing data by PIPE_BUF if wsplit_p is true in multi-threaded mode. [ruby-dev:26540] Sun Jul 17 13:46:54 2005 Nobuyoshi Nakada * ext/io/wait/extconf.rb, ext/io/wait/wait.c: Win32 platforms support. Fri Jul 15 23:59:03 2005 Nobuyoshi Nakada * lib/rdoc/parsers/parse_c.rb (handle_class_module): handle a module enclosed in a built-in module. fixed: [ruby-talk:148239] * lib/rdoc/parsers/parse_c.rb (find_body): allow macros as methods. * lib/rdoc/parsers/parse_c.rb (find_call_seq): allow :nodoc: modifier in C. [ruby-core:04572] Fri Jul 15 18:00:01 2005 Hirokazu Yamamoto * bcc32/Makefile.sub (COMMON_HEADERS): ruby_1_8 is using winsock.h. failed to compile ext/socket on bcc5.6.4. [ruby-dev:26193] Fri Jul 15 07:58:56 2005 GOTOU Yuuzou * lib/webrick/server.rb (WEBrick::GenericServer#accept_client): sockets should be non-blocking mode. [ruby-dev:26405] * lib/webrick/utils.rb (WEBrick::Utils.set_non_blocking): new method. * lib/webrick/httprequest.rb (WEBrick::HTTPRequest#read_chunked): should call sock.read repeatedly until the preferred size data is obtained. Thu Jul 14 18:27:16 2005 Hirokazu Yamamoto * win32/win32.c (rb_w32_strerror): should return correct message for ENAMETOOLONG and ENOTEMPTY. (bcc32) [ruby-dev:26533] * win32/win32.c (rb_w32_strerror): stripped CR LF on the tail. (bcc32) [ruby-dev:26533] Thu Jul 14 00:45:42 2005 Nobuyoshi Nakada * LEGAL (ext/nkf/nkf-utf8): updated from nkf1.7 to nkf-utf8. Wed Jul 13 19:37:47 2005 Hirokazu Yamamoto * win32/win32.c (rb_w32_mkdir): should set EEXIST (not EACCES) if file or directory already exists. (bcc32) [ruby-dev:26508] * win32/win32.c (rb_w32_rmdir): should set ENOTDIR (not EINVAL) if it is not directory. (bcc32, win32) * win32/win32.c (rb_w32_rmdir, rb_w32_unlink): restore FILE_ATTRIBUTE_READONLY flag on function failure. Wed Jul 13 12:40:00 2005 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: TclTkLib.do_one_event doesn't work. * ext/tk/lib/tk.rb: Tk.thread_update is available. Tue Jul 12 23:32:11 2005 Nobuyoshi Nakada * lib/mkmf.rb: keep curdir unexpanded. Mon Jul 11 08:31:29 2005 Nobuyoshi Nakada * regex.c (read_special): fix parsing backslashes following \c in regexp. fixed: [ruby-dev:26500] Mon Jul 11 02:53:00 2005 GOTOU Yuuzou * lib/webrick/cgi.rb (WEBrick::CGI::Socket#request_line): mistook in merging the patch of [ruby-dev:26235] at revision 1.4.2.6. Sun Jul 10 23:58:04 2005 Tanaka Akira * lib/pathname.rb (Pathname#unlink): try Dir.unlink first to avoid unlink a directory by root. cf. [ruby-dev:26237] Sun Jul 11 05:18:17 2005 Michael Neumann * lib/xmlrpc/server.rb (XMLRPC::Server): Switch from GServer over to WEBrick. This makes file lib/xmlrpc/httpserver.rb obsolete (at least it is no further used by the XML-RPC library). Sun Jul 10 12:47:01 2005 Nobuyoshi Nakada * lib/debug.rb (debug_command): added a deficient format specifier. fixed: [ruby-core:05419] Sat Jul 9 21:28:46 2005 Masaki Suketa * ext/win32ole/win32ole.c (ole_method_dispid): convert dispid in Ruby and C by INT2NUM and NUM2INT. * ext/win32ole/win32ole.c (ole_invoke2): ditto. * ext/win32ole/test/testWIN32OLE.rb: ditto. * ext/win32ole/test/testOLEMETHOD.rb: ditto. Fri Jul 8 15:45:04 2005 Kouhei Sutou * lib/rss/rss.rb (RSS::VERSION): 0.1.4 -> 0.1.5. * test/rss/test_version.rb (RSS::TestVersion#test_version): ditto. * lib/rss/0.9.rb (RSS::Rss::Channel::Item::Category): domain attribute of is optional. Thanks to Chris Lee . * test/rss/test_parser.rb (RSS::TestParser#test_category20): adjusted test case. Tue Jul 5 23:44:06 2005 Nobuyoshi Nakada * instruby.rb: expand source library path. Tue Jul 5 23:27:14 2005 Nobuyoshi Nakada * array.c (sort_2): get rid of yet another bcc's bug. fixed: [ruby-core:05152] * eval.c (rb_thread_save_context): must not switch contexts during re-allocating stack. fixed: [ruby-core:05219] Tue Jul 5 15:15:10 2005 Hidetoshi NAGAI * ext/tk/tkutil.c: fix typo. Tue Jul 5 14:51:35 2005 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: bug fix on treating Unicode strings. * ext/tcltklib/tcltklib.c: add methods to treat encoding mode. * ext/tcltklib/MANUAL.eng: add description of TclTkLib#encoding, encoding_system, and so on. * ext/tcltklib/MANUAL.euc: ditto. * ext/tk/tkutil.c: fail to create a Tcl's list string from an array including multiple kind of encoded strings. * ext/tk/lib/tk.rb: ditto. * ext/tk/lib/multi-tk.rb: 2nd arg of _{to|from}UTF8 is omissible. * ext/tk/lib/remote-tk.rb: ditto. * ext/tk/lib/tk.rb: override TclTkLib#encoding and encoding= to use TkCore::INTERP.encoding and encoding=. * ext/tk/lib/tk.rb: when "require 'tk'" and $KCODE=='NONE', check DEFAULT_TK_ENCODING to decide Ruby/Tk's system encoding mode. * ext/tk/lib/tk/encodedstr.rb: check both of Tk.encoding and Tk.encoding_system. Tk.encoding has higher priority. * ext/tk/lib/tk/optiondb.rb: ditto. * ext/tk/lib/tk/spinbox.rb: ditto. * ext/tk/lib/tk/validation.rb: ditto. * ext/tk/lib/tk/namespace.rb: arguemnts for TclTkIp#_merge_tklist should be UTF-8 strings. Mon Jul 4 14:35:52 2005 Yukihiro Matsumoto * sample/svr.rb: service can be stopped by ill-behaved client; use tsvr.rb instead. Mon Jul 4 13:25:21 2005 Yukihiro Matsumoto * missing/erf.c: original erf.c by prof. Okumura is confirmed to be public domain. reverted BSD implementation. Mon Jul 4 11:15:37 2005 NAKAMURA Usaku * test/{dbm,gdbm,sdbm}/test_{dbm,gdbm,sdbm}.rb: skip some tests which using fork on fork-less platforms. Sun Jul 3 23:26:30 2005 NAKAMURA, Hiroshi * test/wsdl/document/test_rpc.rb: compare formatted time string of Time objects instead of comparing Time objects itself to avoid unintended conflict of usec part. [ruby-dev:26220] Sat Jul 2 22:41:04 2005 Tanaka Akira * ext/socket/socket.c (unix_send_io, unix_recv_io): support x86-64 and IA64. Sat Jul 2 17:06:23 2005 Tanaka Akira * defines.h (FLUSH_REGISTER_WINDOWS): defined for IA64. (flush_register_windows): declare flush_register_windows. * eval.c (flush_register_windows): new function. Fri Jul 1 17:48:52 2005 Yukihiro Matsumoto * bignum.c (get2comp): revert all prior changes, and calculate proper 2's complement for negative numbers. backported from HEAD. Fri Jul 1 15:50:12 2005 NAKAMURA Usaku * missing/erf.c: need to include some headers for some platforms. * win32/win32.h (copysign, scalb): define for compatibility with other platforms. [ruby-dev:26430] Fri Jul 1 15:37:42 2005 Yukihiro Matsumoto * missing/crypt.c: modified to make it compilable on platforms other than BSD. [ruby-dev:26430] * missing/erf.c: ditto. code from merged. Fri Jul 1 12:44:56 2005 Tanaka Akira * lib/open-uri.rb (OpenURI.open_http): refine post_connection_check call. Fri Jul 1 11:34:08 2005 Yukihiro Matsumoto * missing/crypt.c: replaced with 4.4BSD version. * missing/erf.c: ditto. * missing/vsnprintf.c: removed the third provision from the old BSD license. [ruby-core:05177] Fri Jul 1 01:45:21 2005 Nobuyoshi Nakada * enum.c (enum_min, enum_max): must not return Qundef. fixed: [ruby-core:05299] Fri Jul 1 00:18:40 2005 Yukihiro Matsumoto * lib/delegate.rb (Delegator::respond_to): respond_to? must check destination object. [ruby-talk:146894] Thu Jun 30 19:00:21 2005 Keiju Ishitsuka * lib/irb/ruby-lex.rb (RubyLex::identify_number): alternative implements for [ruby-dev:26410]. And support a numeric form of 0d99999. Thu Jun 30 17:28:10 2005 Yukihiro Matsumoto * lib/irb/ruby-lex.rb (RubyLex::identify_number): should not treat plain zero as an octal number. [ruby-dev:26410] Thu Jun 30 15:13:16 2005 Yukihiro Matsumoto * eval.c (rb_eval): pre-evaluate argument for unambiguous evaluation order. [ruby-dev:26383] Thu Jun 30 09:53:56 2005 Yukihiro Matsumoto * lib/delegate.rb (Delegator::method_missing): forward unknown method to the destination. suggested by . [ruby-talk:146776] Tue Jun 28 21:59:29 2005 Kazuhiro NISHIYAMA * dir.c, eval.c, hash.c, process.c, ruby.c: avoid warning "unused variable" [ruby-dev:26387] Sat Jun 25 17:15:23 2005 GOTOU Yuuzou * lib/webrick/httputils.rb (WEBrick::HTTPUtils.parse_query): should discard if key=val pair is empty. patch from Gary Wright. Sat Jun 25 23:30:51 2005 Yukihiro Matsumoto * process.c (detach_process_watcher): terminate process watcher thread right after rb_waitpid() succeed. [ruby-talk:146430] Sat Jun 25 15:49:18 2005 Nobuyoshi Nakada * enum.c (enum_min, enum_max): do not ignore nil as the first element. Sat Jun 25 14:40:17 2005 Hirokazu Yamamoto * ext/sdbm/init.c (fsdbm_select): SDBM#select had returned the array which contained each elements twice. [ruby-dev:26358] Fri Jun 25 05:06:47 2005 Michael Neumann * lib/xmlrpc/*, test/xmlrpc/*: backported changes from HEAD into 1.8 Fri Jun 24 17:00:00 2005 Shigeo Kobayashi * ext/bigdecimal/bigdecimal.c: patch from "NATORI Shin" (u-tokyo.ac.jp) applied to fix rounding bug. Fri Jun 24 13:06:45 2005 akira yamada * lib/uri/common.rb, lib/uri/generic.rb: fixed typo in documents and replaced some existent domain name with "example.com". Fri Jun 24 12:23:19 2005 Hidetoshi NAGAI * ext/tk/lib/tk.rb: fix typo on Tk.grid_propagate. * ext/tk/lib/tk.rb: Tk.event_generate and TkWindow#event_generate accept TkEvent::Event object as context argument. * ext/tk/lib/tk/event.rb: add TkEvent::Event#valid_fields and valid_for_generate to get field parameters of event_generate. Thu Jun 23 23:55:59 2005 Nobuyoshi Nakada * runruby.rb: should load built rbconfig.rb. Thu Jun 23 16:53:15 2005 Hidetoshi NAGAI * ext/tk/lib/tk/canvastag.rb: TkcGroup.new cannot include given items. TkcGroup#exclude calls wrong method. Add alias TkcGroup#add [ruby-talk:146049]. * ext/tk/lib/tk/canvas.rb: TkCanvas#dtag and some subcommands of TkCanvas#addtag fail to treat a TkcTag argument. * ext/tk/lib/tk/event.rb: add TkEvent::Event#generate to help to send current event to other widgets. Mon Jun 20 18:44:04 2005 Tanaka Akira * eval.c (FUNCTION_CALL_MAY_RETURN_TWICE): DUMMY_SETJMP is replaced because setjmp is not enough to fix getcontext and SPARC register window problem. Mon Jun 20 16:48:36 2005 NAKAMURA Usaku * ext/dbm/dbm.c (fdbm_closed): new method DBM#closed? * ext/gdbm/gdbm.c (fgdbm_closed): new method GDBM#closed? * ext/sdbm/init.c (fsdbm_closed): new method SDBM#closed? * test/dbm/test_dbm.rb, test/gdbm/test_gdbm.rb, test/sdbm/test_sdbm.rb (teardown): close all db objects before deleting data files. * win32/win32.{ch} (unlink): hook runtime function to change file attribute before unlinking. fixed: [ruby-dev:26360] Mon Jun 20 02:15:35 2005 Nobuyoshi Nakada * gc.c (define_final): document fix: finalizers never get called before target object is destroyed. Mon Jun 20 01:26:49 2005 GOTOU Yuuzou * ext/openssl/openssl_missing.c, ext/openssl/ossl.h, ext/openssl/ossl_asn1.c, ext/openssl/ossl_bio.c, ext/openssl/ossl_pkcs12.h, ext/openssl/ossl_x509req.c: avoid compiler warnings. suggested by Michal Rokos. Sun Jun 19 14:09:07 2005 Nobuyoshi Nakada * gc.c (run_final): reduce unnecessary object allocation during finalization. * gc.c (rb_gc_call_finalizer_at_exit): deferred finalizers list should be cleared before calling them. fixed: [ruby-talk:145790] Fri Jun 17 13:01:40 2005 Tanaka Akira * lib/time.rb (Time.parse): fix previous leap seconds support. (Time.rfc2822): ditto. (Time.xmlschema): ditto. Thu Jun 16 15:06:55 2005 Hirokazu Yamamoto * ext/tcltklib/tcltklib.c (ip_rb_threadVwaitCommand): Tcl_Release was missing. Thu Jun 16 13:34:48 2005 Hidetoshi NAGAI * ext/tk/lib/tk.rb: add Tk.getMultiple{Open|Save}File() which return an Array of selected files. Thu Jun 16 12:53:24 2005 Tanaka Akira * lib/time.rb (Time.parse): "Fri Jan 1 08:59:60 +0900 1999" was parsed as "Fri Jan 01 09:00:00 JST 1999" even on an environment which supports leap seconds. (Time.rfc2822): ditto. (Time.xmlschema): ditto. Thu Jun 16 08:29:22 2005 Hirokazu Yamamoto * ext/dl/sym.c (rb_dlsym_call): needs FREE_ARGS before return. fixed memory leak. [ruby-Bugs-2034] Wed Jun 15 18:26:39 2005 Hidetoshi NAGAI * ext/tk/lib/tk.rb: support "tk inactive" sub-command [for Tcl/Tk8.5a3] * ext/tk/lib/tk/namespace.rb: support "namespace path" sub-command and 'namespace ensemble' sub-command [for Tcl/Tk8.5a3] Tue Jun 14 02:02:43 2005 Hidetoshi NAGAI * ext/tk/tkutil.c: add TkUtil::CallbackSubst.subst_arg(m, ...) & _define_attribute_aliases(hash) to get substitution-argument from attributes (e.g. subst_arg(:x,:y,:num,:button) --> "%x %y %b %b "). * ext/tk/lib/tk/event.rb: use _define_attribute_aliases(). Mon Jun 13 13:01:05 2005 Hirokazu Yamamoto * hash.c (ruby_setenv): fixed SEGV. [ruby-dev:26186] Mon Jun 13 01:54:20 2005 Yukihiro Matsumoto * signal.c (sigexit): call rb_thread_signal_exit() instead of rb_exit(). [ruby-dev:26347] * eval.c (rb_thread_signal_exit): a new function to exit on main thread. * eval.c (rb_thread_switch): exit status should be retrieved from ruby_errinfo. * eval.c (rb_f_exit): ensure exit(0) should call exit(EXIT_SUCCESS). Mon Jun 13 01:20:02 2005 Tanaka Akira * eval.c (rb_gc_mark_threads): curr_thread may not be part of the thread list. [ruby-dev:26312] Fri Jun 10 23:35:34 2005 Yukihiro Matsumoto * missing/mkdir.c: remove. [ruby-core:05177] Fri Jun 10 22:54:26 2005 Nobuyoshi Nakada * missing.h: fd_set stuffs need sys/types.h. fixed: [ruby-core:05179] Thu Jun 9 23:58:12 2005 Nobuyoshi Nakada * ext/Win32API/Win32API.c (Win32API_Call): disable global optimization. fixed: [ruby-core:05143] Thu Jun 9 23:35:22 2005 Nobuyoshi Nakada * enum.c (enum_inject): default the result value to Qundef to use first element as initial value if not given. Thu Jun 9 19:55:41 2005 Tanaka Akira * eval.c (ruby_longjmp): new macro to call longjmp, setcontext, etc. (ruby_setjmp): new macro to call setjmp, getcontext, etc. (ruby_setjmp): call setjmp before getcontext to avoid IA64 register stack problem. [ruby-talk:144939] * gc.c (Init_stack): remove IA64_MAGIC_STACK_LIMIT. Thu Jun 9 11:55:34 2005 Yukihiro Matsumoto * lib/delegate.rb (SimpleDelegator::__setobj__): need check for recursive delegation. [ruby-core:04940] Wed Jun 8 18:47:10 2005 Yukihiro Matsumoto * misc/ruby-mode.el (ruby-expr-beg): fix looking point drift. Wed Jun 8 11:11:34 2005 Yukihiro Matsumoto * bignum.c (get2comp): calculate proper 2's complement for negative numbers. a bug in normalizing negative numbers reported from Honda Hiroki . Wed Jun 8 08:33:10 2005 Nobuyoshi Nakada * enum.c (enum_min_by, enum_max_by): return nil if no iteration. fixed: [ruby-dev:26245] * eval.c (rb_need_block): ensure a block is given. * eval.c (backtrace): skip successive frames sharing same node. Wed Jun 8 00:15:08 2005 Yukihiro Matsumoto * ext/socket/socket.c (ruby_getaddrinfo__aix): merged a patch from KUBO Takehiro to support AIX. [ruby-list:40832] Wed Jun 8 00:09:01 2005 Yukihiro Matsumoto * lib/yaml/rubytypes.rb (Array::to_yaml): merged a patch from Tilman Sauerbeck . [ruby-core:05055] * lib/yaml/rubytypes.rb (Hash::to_yaml): ditto. Wed Jun 8 00:00:01 2005 Yukihiro Matsumoto * ext/curses/curses.c (curses_insertln): merged a patch from TAKAHASHI Tamotsu . [ruby-ext:02305] Tue Jun 7 19:34:15 2005 Yukihiro Matsumoto * lib/irb/init.rb (IRB::IRB.rc_file_generators): more flexible IRB.rc_file_generators. [ruby-core:05163] Tue Jun 7 18:39:31 2005 Yukihiro Matsumoto * lib/thread.rb: RDoc documentation from Eric Hodel added. [ruby-core:05148] Tue Jun 7 18:30:04 2005 Nobuyoshi Nakada * lib/mkmf.rb (create_makefile): add .SUFFIXES from depend file. fixed: [ruby-dev:26294] Tue Jun 7 17:39:54 2005 Yukihiro Matsumoto * object.c (rb_mod_cvar_get): Module#class_variable_get(): back ported from CVS HEAD. [ruby-talk:144741] * object.c (rb_mod_cvar_set): Module#class_variable_set(). [ruby-talk:144741] Tue Jun 7 16:32:53 2005 Yukihiro Matsumoto * sprintf.c (rb_f_sprintf): raise exception on debug mode (-d), not verbose mode (-v/-w). [ruby-core:05123] Tue Jun 7 10:30:49 2005 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: slave-ip fails to call procedures delegated by master-ip. Sun Jun 5 23:00:35 2005 Hidetoshi NAGAI * ext/tk/lib/tk/console.rb: create console when required * ext/tk/sample/tkextlib/tile/demo.rb: fix TypeError & create Console Sat Jun 4 14:55:18 2005 Tanaka Akira * test/dbm/test_dbm.rb: merged from ext/dbm/testdbm.rb. * test/gdbm/test_gdbm.rb: merged from ext/gdbm/testgdbm.rb. * test/sdbm/test_sdbm.rb: renamed from ext/sdbm/testsdbm.rb with modification to use test/unit. Fri Jun 3 14:06:12 2005 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: fix typo. Wed Jun 1 11:32:42 2005 Hirokazu Yamamoto * bcc32/Makefile.sub: can use single quote character in DESTDIR. [ruby-dev:26205] Mon May 30 23:48:29 2005 Hidetoshi NAGAI * ext/tk/lib/tk/macpkg.rb: add PACKAGE_NAME information of Tcl/Tk Extension. * ext/tk/lib/tk/msgcat.rb: ditto. * ext/tk/lib/tk/winpkg.rb: ditto. * ext/tk/lib/tkextlib/*: ditto. Sat May 28 16:40:15 2005 GOTOU Yuuzou * test/openssl/test_x509store.rb: add test for expired CRL and refine some assertions. Sat May 28 05:15:51 2005 GOTOU Yuuzou * ext/openssl/ossl_x509store.c (ossl_x509stctx_set_time): should not set internal flag directry. Sat May 28 02:00:11 2005 GOTOU Yuuzou * lib/webrick/cgi.rb (WEBrick::CGI::Socket#request_line): ENV["REQUEST_URI"] is better to get correct Request-URI than ENV["SCRIPT_NAME"] + ENV["PATH_INFO"]. [ruby-dev:26235] Fri May 27 16:32:04 2005 WATANABE Hirofumi * lib/mkmf.rb: use the semicolon as the path separator in the environment of MSYS. fixed: [ruby-dev:26232] Thu May 26 06:08:11 2005 Hidetoshi NAGAI * ext/tk/lib/tk.rb: add shortcut-methods of tk_call + tk_split_list Wed May 25 22:52:42 2005 Shugo Maeda * lib/irb/input-method.rb: do not use Readline::HISTORY.pop. (backported from HEAD) Wed May 25 21:55:40 2005 Shugo Maeda * ext/readline/readline.c: supported libedit. (backported from HEAD) * ext/readline/extconf.rb: ditto. * test/readline/test_readline.rb: ditto. Wed May 25 20:06:27 2005 Hidetoshi NAGAI * ext/tk/lib/tk.rb: TkComm#tk_split_*list fail to split a kind of SJIS strings. To avoid the trouble, add arguments to control converting encoding, and do split on a UTF8 string. * ext/tk/lib/multi-tk.rb: modify to attend encoding. * ext/tk/lib/remote-tk.rb: ditto. * ext/tk/lib/tk/itemconfig.rb: ditto. * ext/tk/lib/tk/listbox.rb: ditto. * ext/tk/lib/tk/namespace.rb: ditto. * ext/tk/lib/tk/panedwindow.rb: ditto. * ext/tk/lib/tk/text.rb: ditto. * ext/tk/lib/tk/textmark.rb: ditto. * ext/tk/lib/tk/texttag.rb: ditto. * ext/tk/lib/tk/variable.rb: ditto. * ext/tk/lib/tk/winfo.rb: ditto. * ext/tk/lib/tkextlib/iwidgets/scrolledlistbox.rb: ditto. * ext/tk/lib/tkextlib/iwidgets/scrolledtext.rb: ditto. * ext/tk/lib/tk.rb: add TkWindow#lower_window/raise_window and Tk#lower_window/raise_window by reason of method-name conflict * ext/tk/lib/tk/canvas.rb: bug fix on TkCanvas#delete when given non-TkcItem arguments. * ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb: ditto. Wed May 25 12:59:48 2005 Tanaka Akira * lib/open-uri.rb (OpenURI::Meta::RE_QUOTED_STRING): a content of quoted-string should be zero or more characters. Tue May 24 23:42:16 2005 Yukihiro Matsumoto * numeric.c (fix_pow): support Fixnum ** Float case directly without coercing. [ruby-talk:142697] [ruby-talk:143054] Tue May 24 16:57:24 2005 Yukihiro Matsumoto * ruby.c (require_libraries): caused SEGV when continuation jumped in to the required library code. Tue May 24 11:56:25 2005 WATANABE Hirofumi * lib/getopts.rb: should warn only if verbose mode. fixed: [ruby-dev:26201] Tue May 24 06:45:31 2005 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-font-lock-syntactic-keywords): string literals to be matched non-greedy. Tue May 24 00:34:32 2005 NAKAMURA, Hiroshi * test/soap/calc: method name 'set' was able to crash with a class Set. [ruby-dev:26210] * test/wsdl/document/test_rpc.rb: dateTime comparison failed under TZ=right/Asia/Tokyo (with leap second.) [ruby-dev:26208] Mon May 23 16:24:05 2005 Hidetoshi NAGAI * ext/tcltklib/extconf.rb: Framework support on MacOS X Tiger. * ext/tcltklib/README.1st: add description of Framework support options. Mon May 23 12:21:37 2005 Yukihiro Matsumoto * re.c (make_regexp): should not return junk address during compile time. [ruby-dev:26206] Sun May 22 21:54:06 2005 NAKAMURA, Hiroshi * lib/{soap,wsdl,xsd}, test/{soap,wsdl,xsd}: imported soap4r/1.5.4. == SOAP client and server == === for both client side and server side === * improved document/literal service support. style(rpc,document)/use(encoding, literal) combination are all supported. for the detail about combination, see test/soap/test_style.rb. * let WSDLEncodedRegistry#soap2obj map SOAP/OM to Ruby according to WSDL as well as obj2soap. closes #70. * let SOAP::Mapping::Object handle XML attribute for doc/lit service. you can set/get XML attribute via accessor methods which as a name 'xmlattr_' prefixed ( -> Foo#xmlattr_name). === client side === * WSDLDriver capitalized name operation bug fixed. from 1.5.3-ruby1.8.2, operation which has capitalized name (such as KeywordSearchRequest in AWS) is defined as a method having uncapitalized name. (converted with GenSupport.safemethodname to handle operation name 'foo-bar'). it introduced serious incompatibility; in the past, it was defined as a capitalized. define capitalized method as well under that circumstance. * added new factory interface 'WSDLDriverFactory#create_rpc_driver' to create RPC::Driver, not WSDLDriver (RPC::Driver and WSDLDriver are merged). 'WSDLDriverFactory#create_driver' still creates WSDLDriver for compatibility but it warns that the method is deprecated. please use create_rpc_driver instead of create_driver. * allow to use an URI object as an endpoint_url even with net/http, not http-access2. === server side === * added mod_ruby support to SOAP::CGIStub. rename a CGI script server.cgi to server.rb and let mod_ruby's RubyHandler handles the script. CGIStub detects if it's running under mod_ruby environment or not. * added fcgi support to SOAP::CGIStub. see the sample at sample/soap/calc/server.fcgi. (almost same as server.cgi but has fcgi handler at the bottom.) * allow to return a SOAPFault object to respond customized SOAP fault. * added the interface 'generate_explicit_type' for server side (CGIStub, HTTPServer). call 'self.generate_explicit_type = true' if you want to return simplified XML even if it's rpc/encoded service. == WSDL == === WSDL definition === * improved XML Schema support such as extension, restriction, simpleType, complexType + simpleContent, ref, length, import, include. * reduced "unknown element/attribute" warnings (warn only 1 time for each QName). * importing XSD file at schemaLocation with xsd:import. === code generation from WSDL === * generator crashed when there's '-' in defined element/attribute name. * added ApacheMap WSDL definition. * sample/{soap,wsdl}: removed. Sun May 22 19:11:35 2005 GOTOU Yuuzou * ext/openssl/lib/openssl/ssl.rb (OpenSSL::SSL::SSLServer#intialize): should initialize session id context. [ruby-core:4663] * ext/openssl/ossl_ssl.c (ossl_sslctx_setup): add session id support. Sat May 21 10:24:21 2005 Hirokazu Yamamoto * bcc32/Makefile.sub: tds files were not deleted when DESTDIR included '\' path delimiter. [ruby-dev:26193] Thu May 19 19:04:29 2005 speakillof * lib/rexml/encodings/SHIFT-JIS.rb: encoding and decoding were swapped. [ruby-core:4772] Wed May 18 23:42:25 2005 Nobuyoshi Nakada * error.c (exc_exception): reverted to call Exception#initialize directly. fixed: [ruby-dev:26177] Wed May 18 23:39:09 2005 Nobuyoshi Nakada * dir.c (glob_helper): get rid of using String. [ruby-dev:26180] * dir.c (push_braces): should skip balanced braces. * eval.c (ruby_options), win32/win32.c (NtInitialize): move argument intialization back. [ruby-dev:26180] Tue May 17 15:31:31 2005 GOTOU Yuuzou * lib/webrick/httpserver.rb (WEBrick::HTTPServer#run): should break the loop if the socket reached to EOF. [ruby-talk:142285] Tue May 17 11:52:18 2005 NAKAMURA Usaku * win32/win32.c (unixtime_to_filetime): use localtime() instead of gmtime() when using FileLocalTimeToFileTime(). Mon May 16 22:28:43 2005 Nobuyoshi Nakada * win32/win32.h, {bcc32,win32,wince}/Makefile.sub: moved rb_[ugp]id_t to get rid of redefinition warnings on mingw. * class.c (rb_class_init_copy): singleton class is disallowed to copy, from its definition. fixed: [ruby-talk:142749] Mon May 16 08:52:29 2005 Hirokazu Yamamoto * win32/win32.{h,c}: define rb_[pgu]id_t. Mon May 16 00:21:02 2005 Tanaka Akira * lib/pathname.rb (Pathname#unlink): use SystemCallError instead of Errno::EISDIR because EISDIR is not portable. [ruby-core:5001] Sun May 15 22:11:33 2005 Masatoshi SEKI * lib/drb/drb.rb (DRbObject#method_missing): use raise(exception). [ruby-dev:26164] Sun May 15 18:56:35 2005 Nobuyoshi Nakada * configure.in, ruby.h: define rb_[pgu]id_t macros instead of typedefs to get rid of types which might not be defined yet. [ruby-dev:26165] Sun May 15 14:35:46 2005 Tanaka Akira * lib/pathname.rb (Pathname#unlink): unlink a symlink to a directory was failed. [ruby-core:4992] Sun May 15 09:57:30 2005 Nobuyoshi Nakada * win32/win32.c (unixtime_to_filetime): deal with DST. [ruby-talk:141817] Sat May 14 23:59:11 2005 Nobuyoshi Nakada * error.c (exc_exception, {exit,name_err,syserr}_initialize): call Execption#initialize. fixed: [ruby-talk:142593] Sat May 14 23:57:26 2005 Erik Huelsmann * configure.in: Check for the availability of pid_t, gid_t and uid_t and remove AC_TYPE_UID_T. fixed: [ruby-core:04745] * defines.h: Remove pid_t typedef. * ruby.h: Define rb_pid_t, rb_gid_t and rb_uid_t in accordance with the available system types. * process.c: Change instances of pid_t and gid_t to their rb_* counterparts. * ext/pty/pty.c: Change pid_t to rb_pid_t. * vms/config.h: Define HAVE_{P,G,U}ID_T to 1. * win32/Makefile.sub: Remove #define for {g,u}id_t. * win32/win32.c: Change pid_t to rb_pid_t. * wince/Makefile.sub: Remove #define for {g,u}id_t. * wince/sys/types.h: Remove definitions of {p,g,u}id_t. Fri May 13 23:44:22 2005 Nobuyoshi Nakada * ext/extmk.rb: keep srcdir unexpanded. * lib/mkmf.rb (create_makefile): quote topdir and hdrdir if necessary. fixed: [ruby-core:04932] * lib/mkmf.rb (configuration), {bcc32,win32,wince}/Makefile.sub: make also INSTALL_PROG and INSTALL_DATA system dependent. fixed: [ruby-core:04931] Fri May 13 17:54:39 2005 Hirokazu Yamamoto * variable.c (generic_ivar_get): rb_attr_get should not warn. [ruby-dev:26010] Fri May 13 12:28:43 2005 Daniel Berger * array.c (rb_ary_select): can remove argc check. [ruby-core:4911] * test/ruby/test_array.rb: add test for find_all. Fri May 13 11:29:00 2005 NAKAMURA Usaku * eval.c (unknown_node): add volatile directive to prototype. Thu May 12 17:08:48 2005 Tanaka Akira * io.c (rb_io_eof, remain_size, read_all, io_read, appendline) (swallow, rb_io_each_byte, rb_io_getc): revert previous change. * io.c (rb_io_eof, io_fread, appendline, swallow, rb_io_each_byte) (rb_io_getc, rb_getc): call clearerr before getc to avoid stdio incompatibility. Thu May 12 16:52:20 2005 Hirokazu Yamamoto * lib/rdoc/parsers/parse_c.rb: more readability for mixing progress "c..." and warning message. Thu May 12 16:31:00 2005 NARUSE, Yui * ext/nkf/nkf-utf8/nkf.c: follow nkf 2.0.5 Thu May 12 16:15:01 2005 Tanaka Akira * io.c (rb_io_eof, remain_size, read_all, io_read, appendline) (swallow, rb_io_each_byte, rb_io_getc): don't rely EOF flag. [ruby-talk:141527] Thu May 12 15:56:20 2005 Tilman Sauerbeck * lib/rdoc/parsers/parse_c.rb: show parsing progress for C files. [ruby-core:4341] Thu May 12 13:47:56 2005 Hirokazu Yamamoto * test/drb/test_drb{ssl,unix}.rb: can test drb before install. (backported from HEAD) [ruby-dev:26146] Thu May 12 09:53:57 2005 Nobuyoshi Nakada * version.c (ruby_show_version): flush for non-tty stdout. Thu May 12 09:07:07 2005 Hirokazu Yamamoto * test/ruby/envutil.rb, test/drb/drbtest.rb: can test drb before install. (backported from HEAD) [ruby-Bugs-1672] Thu May 12 01:23:55 2005 Nobuyoshi Nakada * eval.c (rb_eval), parse.y (arg): reduce fixnum range literal at parser. fixed: [ruby-dev:26113] * eval.c (unknown_node): ignore broken NODE to get rid of accessing possibly inaccessible address. fixed: [ruby-dev:26122] should emit more useful information like [ruby-dev:26126], though. Wed May 11 16:20:01 2005 GOTOU Yuuzou * lib/webrick/cgi.rb: new methods WEBrick::CGI#[], WEBrick::CGI#logger and WEBrick::CGI#config. (backported from HEAD) * lib/webrick/httputils.rb (WEBrick::HTTPUtils.escape_path): should not use String#split("/"). (backported from HEAD) Wed May 11 15:58:39 2005 Yukihiro Matsumoto * eval.c (break_jump): break should not cross functions. [ruby-list:40818] Wed May 11 10:39:37 2005 Hirokazu Yamamoto * lib/tempfile.rb (Tempfile#unlink): fixed typo. Wed May 11 01:03:36 2005 Nobuyoshi Nakada * eval.c (TMP_ALLOC): use macro NEW_NODE() to get rid of warnings on platforms which have no alloca(). fixed: [ruby-talk:141301] Sun May 8 23:17:47 2005 Hidetoshi NAGAI * ext/tk/lib/tk/timer.rb: fix typo. Sun May 8 16:52:56 2005 Hirokazu Yamamoto * lib/profiler.rb: fixed "undefined method `[]' for nil:NilClass" [ruby-core:4775] [ruby-talk:140401] [ruby-dev:26118] Sat May 7 22:58:00 2005 Nobuyoshi Nakada * lib/mkmf.rb (have_var): no libs argument is given. Sun May 1 09:58:11 2005 Nobuyoshi Nakada * ruby.c (process_sflag): replace '-' in variable names with '_'. [ruby-dev:26107] * ruby.c (set_arg0): use also environment variable space for setting $0. [ruby-core:04774] Wed Apr 27 23:42:22 2005 Nobuyoshi Nakada * win32/Makefile.sub (OPTFLAGS): default global optimization to disabled only for VC++6. Tue Apr 26 22:58:00 2005 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (ip_invoke_core): call Tcl's "::unknown" command when can't get information of target command. Mon Apr 25 01:18:43 2005 Tanaka Akira * regex.c: declare rb_warn to have variadic argument. [ruby-core:4751] Sat Apr 23 19:45:59 2005 Hirokazu Yamamoto * ext/tcltklib/tcltklib.c (ip_RubyExitCommand): exit with status code via TclTkIp#_eval didn't work. [ruby-talk:139390] Fri Apr 22 16:41:50 2005 Hirokazu Yamamoto * ext/tcltklib/tcltklib.c (ip_set_exc_message): fixed memory leak. * ext/tcltklib/tcltklib.c: eTkCallbackReturn was not initialized. Thu Apr 21 00:07:50 2005 Nobuyoshi Nakada * lib/mkmf.rb (create_makefile): support platforms have file separator other than /. * {bcc32,win32,wince}/Makefile.sub (BUILD_FILE_SEPARATOR): separator of building platform. * {bcc32,win32,wince}/Makefile.sub (CP, INSTALL): use COPY command. Wed Apr 20 23:22:39 2005 Nobuyoshi Nakada * Makefile.in, common.mk: miniruby depens on MINIOBJS. * dmydln.c (dln_load): dummy function to raise LoadError. * cygwin/GNUmakefile.in, {bcc32,win32,wince}/Makefile.sub: miniruby can't load extensions on Windows. Wed Apr 20 23:01:35 2005 Nobuyoshi Nakada * win32/ifchange.bat: delete testing files. Wed Apr 20 07:27:18 2005 Nobuyoshi Nakada * {bcc32,win32,wince}/configure.bat, {bcc32,win32,wince}/setup.mak: add extout option. * bcc32/setup.mak: make configuration variables overridable. Wed Apr 20 04:15:27 2005 Keiju Ishitsuka * lib/irb.rb lib/irb/* doc/irb: IRB 0.9.5 Tue Apr 19 23:37:09 2005 WATANABE Hirofumi * lib/ftools.rb (File.safe_unlink): do not modify a symlinked file. Tue Apr 19 00:06:20 2005 Nobuyoshi Nakada * ext/extmk.rb: expand path for ext/**/extconf.rb. Mon Apr 18 11:25:14 2005 Hirokazu Yamamoto * ext/zlib/zlib.c (zstream_run): fixed SEGV. [ruby-core:4712] Sun Apr 17 23:57:49 2005 Nobuyoshi Nakada * ext/extmk.rb (extmake, parse_args): do not expand destdir. * ext/extmk.rb (relative_from): treat mere drive letter as an absolute path. Sat Apr 16 17:01:16 2005 Kouhei Sutou * sample/rss/tdiary_plugin/rss-recent.rb (rss_recent_cache_rss): use the first date information of items as site date information if channel doesn't have date information. Sat Apr 16 15:27:03 2005 Nobuyoshi Nakada * configure.in (RUBY_PROG_INSTALL): not add -p option to INSTALL. files need timestamps to be kept are only ar-archive on a few platforms, and be installed by instruby.rb but not INSTALL. fixed: [ruby-core:04721] * mkconfig.rb: purge autoconf value variables. Sat Apr 16 10:36:01 2005 Hirokazu Yamamoto * bcc32/Makefile.sub: quick hack... prepend DESTDIR. still have restriction on DESTDIR ("", "/", "e:") Sat Apr 16 03:59:42 2005 GOTOU Yuuzou * ext/openssl/extconf.rb: check for OPENSSL_cleanse. * ext/openssl/openssl_missing.h: ditto. Thu Apr 14 19:18:30 2005 Minero Aoki * lib/fileutils.rb (remove_file): ignore exceptions caused by chmod. * lib/fileutils.rb (remove_dir): try to get rights to rmdir. [ruby-Bugs:1502] (2 items backportted from HEAD, rev 1.53-54) Thu Apr 14 16:57:40 2005 Nobuyoshi Nakada * bcc32/Makefile.sub: failed to remove debug information files. fixed: [ruby-dev:26034] Wed Apr 13 23:40:21 2005 Kouhei Sutou * lib/rss/rss.rb (RSS::VERSION): 0.1.3 -> 0.1.4. * lib/rss/rss.rb (RSS::Element#converter): fixed converter transmission bug. Wed Apr 13 21:20:35 2005 WATANABE Hirofumi * configure.in (mingw32): extract msvcr*.dll from objdump result. Wed Apr 13 20:24:30 2005 Nobuyoshi Nakada * configure.in (mingw32): use actual runtime DLL name as ruby DLL name and default load path. * win32/Makefile.sub, win32/setup.mak: ditto. Tue Apr 12 15:33:09 2005 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (ip_finalize): better modification than the previous commit [ruby-dev:26029]. Tue Apr 12 12:38:06 2005 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (ip_finalize): fix SEGV when Tcl_GlobalEval() modifies the argument string to eval. Tue Apr 12 02:21:55 2005 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (ip_finalize): add existence check of Tcl commands before calling Tcl_GlobalEval(). Mon Apr 11 23:47:21 2005 Masatoshi SEKI * lib/drb/drb.rb: [druby-ja:123] fix: When reference of my object is loaded, the object is tainted. * test/drb/test_drb.rb: ditto. Mon Apr 11 22:18:23 2005 WATANABE Hirofumi * dir.c, file.c (lstat): avoid warnings for mingw. Mon Apr 11 20:11:06 2005 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (ip_finalize): adhoc patch to avoid SEGV when exit on Tcl/Tk8.3.x. Mon Apr 11 15:26:25 2005 NAKAMURA Usaku * lib/mkmf.rb (configuration): shouldn't output hdrdir twice. Mon Apr 11 12:09:05 2005 Hirokazu Yamamoto * {bcc32,win32,wince}/Makefile.sub: ri data was not installed into correct path. [ruby-dev:26011] * bcc32/Makefile.sub: defaulted install-nodoc. [ruby-dev:26011] Sun Apr 10 10:12:42 2005 Masaki Suketa * ext/win32ole/win32ole.c(ole_invoke): retry after converting Qnil to VT_EMPTY. * ext/win32ole/win32ole/tests/testWIN32OLE.rb: correct error message string "Unknown" => "unknown". Sat Apr 9 18:20:31 2005 Hidetoshi NAGAI * ext/tk/lib/tk/image.rb: support to create TkImage object without creating a new image object on Tk. * ext/tk/lib/tk/menu.rb: use TkCommandNames on create_self() * ext/tk/lib/tk/root.rb: TkRoot.to_eval() returns '.'. * ext/tk/lib/tk/text.rb: add methods to create a TkText::IndexString from (x, y) coords. * ext/tk/lib/tkextlib/tile/: add demo and update support status. Sat Apr 9 14:42:29 2005 Kouhei Sutou * sample/rss/tdiary_plugin/rss-recent.rb: supported configuration via Web browser. Sat Apr 9 11:59:57 2005 Kouhei Sutou * lib/rss: backoported from HEAD. * lib/rss: refactored. - gave a name to 'x'. - undef_method -> remove_method for avoiding a warning in ruby 1.6. * lib/rss/parser.rb: @@setter -> @@setters. * lib/rss/parser.rb (RSS::BaseListener.register_uri) (RSS::BaseListener.uri_registered?) (RSS::BaseListener.install_get_text_element): swapped the first argument and the second argument. * lib/rss/taxonomy.rb: swapped the first argument and the second argument for RSS::BaseListener.install_get_text_element. * lib/rss/image.rb: ditto. * lib/rss/syndication.rb: ditto. * lib/rss/dublincore.rb: ditto. * lib/rss/parser.rb: ditto. * lib/rss/1.0.rb: ditto. * lib/rss/2.0.rb: ditto. * lib/rss/0.9.rb: ditto. * lib/rss/content.rb: ditto. * lib/rss/parser.rb (RSS::BaseListener.install_setter) (RSS::BaseListener.register_uri): changed fallback way. * lib/rss/parser.rb: added class name registry for complex model elements. (ex. have childlen elements, have some attributes and a child element and so on.) * lib/rss/dublincore.rb: supported multiple Dublin Core items. * lib/rss/maker/dublincore.rb: ditto. * lib/rss/maker/image.rb: supproted new Dublin Core API. * lib/rss/maker/base.rb: added default current_element implementation. * lib/rss/trackback.rb (RSS::TrackBackUtils.new_with_value_if_need): moved to RSS::Utils. * lib/rss/utils.rb (RSS::Utils.new_with_value_if_need): moved from RSS::TrackBackUtils. * lib/rss/maker/image.rb: fixed invalid argument of add_need_initialize_variable bug. * lib/rss/maker/trackback.rb: ditto. * lib/rss/rss.rb (Hash#merge): added for ruby 1.6. * lib/rss/rss.rb (RSS::BaseModel.date_writer): changed to accept nil for date value. * test/test_dublincore.rb: added tests for plural accessor and multiple Dublin Core items. * test/test_setup_maker_1.0.rb: fixed swapped actual and expected values. * test/rss/rss-assertions.rb (assert_multiple_dublin_core): added an assertion for testing multiple Dublin Core items. * test/rss/test_maker_dc.rb (test_rss10_multiple): added a test for making multiple Dublin Core items. * test/rss/test_maker_dc.rb (test_date): added a test for #date= and #dc_date=. * sample/rss/tdiary_plugin/rss-recent.rb: new option: @options['rss-recent.use-image-link']: use image as link instread of text if available. * sample/rss/tdiary_plugin/rss-recent.rb (RSS_RECENT_VERSION): 0.0.5 -> 0.0.6. Fri Apr 8 20:17:48 2005 Nobuyoshi Nakada * ext/extmk.rb (extmake): hdrdir needs to be defined also in Config::CONFIG. * lib/mkmf.rb (configuration, create_makefile): get rid of recursive macro reference. Fri Apr 8 18:26:56 2005 GOTOU Yuuzou * ext/openssl/ossl_ssl.c: add callbacks to OpenSSL::SSL::SSLContexts. - SSLContext#client_cert_cb=(aProc). it is called when a client certificate is requested by a server and no certificate was not set for the SSLContext. it must return an Array which includes OpenSSL::X509::Certificate and OpenSSL::PKey::RSA/DSA objects. - SSLContext#tmp_dh_callback=(aProc). it is called in key exchange with DH algorithm. it must return an OpenSSL::PKey::DH object. * ext/openssl/ossl_ssl.c (ossl_sslctx_set_ciphers): ignore the argument if it's nil. * ext/openssl/ossl_pkey.c (GetPrivPKeyPtr, ossl_pkey_sign): should call rb_funcall first. (DupPrivPKeyPtr): new function. * ext/openssl/ossl_pkey_dh.c: add default DH parameters. * ext/openssl/ossl_pkey.h: ditto. Fri Apr 8 01:55:20 2005 Hidetoshi NAGAI * ext/tk/sample/demos-{en,jp}/goldberg.rb: reduced window size. [ruby-dev:25992] Thu Apr 7 23:58:40 2005 Nobuyoshi Nakada * ext/extmk.rb (extmake): keep directory names in Makefile as macros. * lib/mkmf.rb (configuration, create_makefile): ditto. * lib/mkmf.rb (CXX_EXT): separate C++ extensions. Thu Apr 7 17:43:25 2005 Shugo Maeda * eval.c (rb_call0): "return" event hook should be always executed if event_hooks is set. fixed: [ruby-core:04662] (backported from HEAD) Mon Apr 4 23:17:52 2005 Hidetoshi NAGAI * ext/tk/lib/tk.rb (TkComm#array2tk_list): accept enc-mode argument to decide whether convert encoding of each element or not. * ext/tk/lib/tk/variable.rb (TkVariable#value=): fail to convert the encoding of array elements when assign an array to an TkVariable object. Mon Apr 4 10:26:48 2005 Hirokazu Yamamoto * ext/tk/lib/tk/dialog.rb: fixed typo. Sun Apr 3 17:16:33 2005 Hirokazu Yamamoto * win32/win32.{h,c} (rb_w32_fdopen): avoid warning on bcc32. (backported from HEAD) Sat Apr 2 23:38:54 2005 Nobuyoshi Nakada * configure.in (CP, INSTALL): get rid of less portable options. * lib/mkmf.rb (configuration, create_makefile): correct configuration variable. * {bcc32,win32,wince}/{Makefile.sub,setup.mak}: leave prefix empty in config.status for backward compatibility. fixed: [ruby-core:04649] * lib/mkmf.rb (create_makefile): ensure library directories get made before copying libraries there. Sat Apr 2 16:59:46 2005 Hidetoshi NAGAI * ext/tk/lib/tk.rb: forgot to update RELEASE_DATE * ext/tk/lib/tk/variable.rb: fix namespace trouble when autoloading * ext/tk/lib/tk/palette.rb: define Tcl variable 'tkPalette' as global * ext/tk/lib/tk/dialog.rb: use array2tk_list method when calling Tk.ip_eval. * ext/tk/lib/tk/autoload.rb: add autoload entry 'TkDialogObj' and 'TkWarningObj' Sat Apr 2 02:19:11 2005 Hidetoshi NAGAI * ext/tk/lib/tk.rb (TkWindow.initialize): accept 'without_creating' option without 'widgetname' option to allow creating a widget object which is used as an argument of Tcl/Tk's widget allocation commands. * ext/tk/lib/tk/image.rb (TkImage.initialize): accept 'imagename' option to create a image object by the given name. Thu Mar 31 22:23:51 2005 Nobuyoshi Nakada * lib/mkmf.rb (SRC_EXT): exclude just case different suffixes on case insensitive file system platforms. * README.EXT, README.EXT.ja (Appendix C): utility functions. Thu Mar 31 14:15:44 2005 GOTOU Yuuzou * ext/openssl/ossl_engine.c (ossl_engine_s_load): should return value. [ruby-dev:25971] Thu Mar 31 08:25:50 2005 Nobuyoshi Nakada * common.mk (RUBYOPT): clear for the environment RubyGems installed. * common.mk (clean-local): keep $(PREP) files till distclean. * common.mk (check): do all tests. Thu Mar 31 06:00:20 2005 GOTOU Yuuzou * ext/openssl/ossl_engine.c (ossl_engine_s_load): should not raise error even if the specified engine could not be loaded. (Dynamic engines don't have fixed name to load.) Thu Mar 31 00:18:27 2005 Hirokazu Yamamoto * win32/ifchange.bat, win32/rm.bat: backported from HEAD. Wed Mar 30 23:44:50 2005 Nobuyoshi Nakada * Makefile.in, */Makefile.sub, */configure.bat, cygwin/GNUmakefile.in, common.mk, configure.in, ext/extmk.rb, lib/mkmf.rb, instruby.rb, runruby.rb: backport extout. [ruby-dev:25963] Wed Mar 30 17:41:48 2005 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: add TclTkIp#_create_console() method to create a Tcl/Tk's console window. * ext/tk/lib/multi-tk.rb: support TclTkIp#_create_console() method. * ext/tk/lib/remote-tk.rb: ditto. * ext/tk/lib/tk/console.rb: ditto. * ext/tk/lib/tk.rb: update RELEASE_DATE * ext/tk/sample/demo-*/check2.rb: use 'return' in the Proc object. * ext/tk/sample/tkextlib/**: ditto. Tue Mar 29 22:11:56 2005 Masatoshi SEKI * test/rinda/test_rinda.rb: use DRbObject.new_with instead of reinit. [ruby-dev:25961] Mon Mar 28 23:40:40 2005 Masatoshi SEKI * lib/drb/drb.rb: move method DRbObject#reinit to DRbObject.new_with. extract method DRbObject.prepare_backtrace. add DRb.regist_server, remove_server, fetch_server. change server in thread variable if in-proc server. [druby-ja:113] * lib/drb/gw.rb: ditto. Mon Mar 28 20:43:34 2005 Nobuyoshi Nakada * ext/syck/rubyext.c: get rid of warnings caused by a bug of VC. Mon Mar 28 08:39:49 2005 Nobuyoshi Nakada * ext/iconv/iconv.c (iconv_create): Iconv::Failure requires 3 arguments. (pointed out by NaHi) Sat Mar 26 22:51:33 2005 Hidetoshi NAGAI * ext/tk/lib/tk.rb (_callback_entry_class?): add for checking whether a class is available for a callback entry. * ext/tk/lib/tk.rb (after_cancel): add Tk.after_cancel(afterID) method. * ext/tk/lib/tk.rb (array2tk_list): change from private module method of TkComm to public module method. * ext/tk/lib/tk.rb (cget): add check that slot argument is not empty string. * ext/tk/lib/tk.rb (configinfo): ditto. * ext/tk/lib/tk/itemconfig.rb (itemcget): add check that slot argument is not empty string. * ext/tk/lib/tk/itemconfig.rb (itemconfiginfo): ditto. * ext/tk/lib/tk/entry.rb: add TkEntry#icursor and icursor= (alias of cursor and cursor= method). * ext/tk/lib/tk/font.rb: improve font treatment when the font name is empty string. * ext/tk/lib/tk/variable.rb: add :variable, :window and :procedure type. * ext/tk/lib/tk/variable.rb: improve treatment of array-type tkvariable. * ext/tk/lib/tkextlib/blt.rb: add commands for zooming. * ext/tk/lib/tkextlib/blt/*: bug fix. * ext/tk/lib/tkextlib/treectrl/tktreectrl.rb: bug fix and add methods to call TreeCtrl commands for bindings. * ext/tk/sample/tkextlib/blt/*: new sample scripts. * ext/tk/sample/tkextlib/treectrl/*: ditto. Fri Mar 25 10:53:16 2005 WATANABE Hirofumi * configure.in (WIN32_LEAN_AND_MEAN): removed because a lot of troubles. [ruby-list:40721] Thu Mar 24 23:10:44 2005 Nobuyoshi Nakada * lib/mkmf.rb (macro_defined?): try to compile for an old compiler which doesn't bail out at #error directive. [ruby-dev:25818] * lib/mkmf.rb (check_sizeof): refine logging messages. Thu Mar 24 03:57:48 2005 GOTOU Yuuzou * lib/webrick/utils.rb (WEBrick::Utils.create_listeners): - should raise ArgumentError if no port is specified. - even if the specified port is 0, all TCPServers should be initialized with the port given to the first one. * lib/webrick/server.rb (WEBrick::GenericServer#initialize): if :Port parameter is 0, it should be updated with the port number which actually listened. Wed Mar 23 00:35:10 2005 Shugo Maeda * test/ruby/test_settracefunc.rb (test_event): added tests for "class" and "end" and "raise". Tue Mar 22 22:40:18 2005 Shugo Maeda * eval.c (rb_call0): check event_hooks instead of trace_func. Tue Mar 22 17:30:44 2005 Shugo Maeda * eval.c (rb_add_event_hook): new function to add a hook function for interpreter events. (backported form HEAD) Sun Mar 20 22:51:19 2005 Nobuyoshi Nakada * lib/mkmf.rb (mkmf_failed): check if Makefile is created without create_makefile. Sat Mar 19 23:48:10 2005 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-expr-beg): returned true always. fixed: [ruby-list:40683] Sat Mar 19 00:41:02 2005 Hidetoshi NAGAI * ext/tk/lib/tk/font.rb: add some TkFont class methods to get font information without creating a TkFont object. * ext/tk/lib/tkextlib/treectrl/tktreectrl.rb: bug fix and define some classes for components of Tk::TreeCtrl Thu Mar 17 17:42:13 2005 Yukihiro Matsumoto * struct.c (make_struct): allow non local-id field names. [ruby-core:04575] * struct.c (inspect_struct): ditto. Wed Mar 16 23:36:02 2005 Shugo Maeda * eval.c (rb_call0): call_cfunc() should be protected. * test/ruby/test_settracefunc.rb: added test for c-return. Wed Mar 16 22:20:25 2005 Hirokazu Yamamoto * object.c (str_to_id): fixed typo. Wed Mar 16 18:08:32 2005 Yukihiro Matsumoto * eval.c (rb_call0): reorganize "return" event post. Tue Mar 15 23:49:19 2005 Nobuyoshi Nakada * ext/iconv/iconv.c (Init_iconv): InvalidEncoding also should include Iconv::Failure. Tue Mar 15 16:38:11 2005 Hidetoshi NAGAI * ext/tk/tkutil.c (ary2list): give wrong arguments to hash2kv() Mon Mar 14 19:39:33 2005 Hidetoshi NAGAI * ext/tk/lib/tk/timer.rb (TkTimer): forgot to clear @return_value when restarting * ext/tk/lib/tk/sample/cd_timer.rb: new sample of TkRTTimer Mon Mar 14 12:21:03 2005 Hidetoshi NAGAI * ext/tk/lib/tk/timer.rb (TkRTTimer): forgot to reset the callback time. So, 'continue' do all callbacks between 'stop' and 'continue'. Mon Mar 14 08:14:56 2005 Yukihiro Matsumoto * object.c (str_to_id): warn for NUL containing strings. Mon Mar 14 00:13:49 2005 Hidetoshi NAGAI * ext/tk/lib/tk/timer.rb (TkRTTimer): correct calculation of offset value. get a little better accuracy. * ext/tk/sample/demos-en/widget: use a binding with no local variables when eval a sample script. * ext/tk/sample/demos-en/bind.rb: ditto. * ext/tk/sample/demos-en/tcolor: ditto. * ext/tk/sample/demos-jp/widget: ditto. * ext/tk/sample/demos-jp/bind.rb: ditto. * ext/tk/sample/demos-jp/tcolor: ditto. Sun Mar 13 10:04:17 2005 Masatoshi SEKI * test/rinda/test_rinda.rb: remove test_gc. [ruby-dev:25871] Thu Mar 10 19:12:06 2005 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (lib_eventloop_ensure): mis-delete a timer handler when exit from a recursive called eventloop * ext/tk/lib/tk/timer.rb: new TkRTTimer class, which can works for a realtime operation * ext/tk/sample/tkrttimer.rb: sample of TkRTTimer class * ext/tk/lib/tk/textmark.rb: move TkTextMark#+ and TkTextMark#- to TkText::IndexModMethods * ext/tk/lib/tk/text.rb: improve TkTextMark#+ and TkTextMark#-, and add them to TkText::IndexModMethods module * ext/tk/sample/tktextio.rb: add test part of "seek by text index modifiers" Thu Mar 10 08:10:11 2005 Yukihiro Matsumoto * re.c (make_regexp): need to free internal regexp structure when compilation fails. [ruby-talk:133228] Wed Mar 9 20:25:58 2005 GOTOU Yuuzou * ext/openssl/ossl_ssl.c (ossl_start_ssl, ossl_ssl_write): call rb_sys_fail if errno isn't 0. [ruby-dev:25831] * ext/openssl/lib/openssl/cipher.rb: fix typo. [ruby-dev:24285] Wed Mar 9 15:46:35 2005 GOTOU Yuuzou * lib/webrick/server.rb (WEBrick::GenericServer#start): should restore @token if accept failure. suggested by Dominique Brezinski. [ruby-core:04518] Wed Mar 9 13:37:57 2005 Hidetoshi NAGAI * ext/tk/sample/tktextio.rb: fix bug of handling 'end' position. support initial text, overwrite setting and pos_gravity control. Tue Mar 8 18:16:55 2005 Hidetoshi NAGAI * ext/tk/sample/tktextio.rb: New sample script. TkTextIO class in this sample supports to use a text widget as if it is a I/O stream (such like as StringIO class). Tue Mar 8 13:54:40 2005 NAKAMURA Usaku * ext/socket/socket.c: workaround for some of 4.4BSD-Lite derived OSs. Tue Mar 8 12:36:17 2005 Yukihiro Matsumoto * ext/socket/socket.c: document from Sam Roberts for getsockopt and setsockopt is merged. [ruby-doc:824] Tue Mar 8 01:27:00 2005 NARUSE, Yui * ext/nkf/nkf-utf8/nkf.c: follow nkf 1.66 fixed: [ruby-dev:25828] Mon Mar 7 21:35:02 2005 GOTOU Yuuzou * sample/webrick/httpsd.rb: fix typo in comment. suggested by Kazuhiko Shiozaki. Mon Mar 7 14:55:43 2005 Yukihiro Matsumoto * eval.c (block_pass): should not push unique number if a block is not an orphan. [ruby-dev:25808] Wed Feb 16 02:55:21 2005 GOTOU Yuuzou * ext/openssl/ossl_ssl.c (ossl_start_ssl, ossl_ssl_read, ossl_ssl_write): - need to set errno on Win32 platform. - should call rb_sys_fail instead of rasing SSLError if SSL_ERROR_SYSCALL occured. - should wait for that the underlying IO become readable or writable if the error was SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE. [ruby-dev:25795] * ext/openssl/lib/openssl/buffering.rb (Buffering#initialize): should set @eof and @rbuffer. (Buffering#fill_rbuff): should rescue Errno::EAGAIN. (Buffering#consume_rbuf): pointless eof flag resetting is deleted. (Buffering#read): should return an empty string if the specified size is zero. (Buffering#readpartial): new method. (Buffering#readline): fix typo. (Buffering#getc): return the first character of string correctly. (Buffering#each): fix typo. suggested by Brian Ollenberger. (Buffering#readchar): fix typo. (Buffering#eof?): should read again it the input buffer is empty. (Buffering#do_write): should rescue Errno::EAGAIN. (Buffering#puts): use "\n" as the output field separator. * ext/openssl/lib/openssl/ssl.rb: set non-blocking flag to the underlying IO. * ext/openssl/extconf.rb: get rid of GNUmakefile generation. * text/openssl/test_pair.rb: test for IO like methods. * test/ruby/ut_eof.rb: test about empty file. Mon Mar 7 10:22:06 2005 WATANABE Hirofumi * lib/un.rb: should use OptionParser. (backported form HEAD) Mon Mar 7 09:18:42 2005 Yukihiro Matsumoto * string.c (rb_str_cmp_m): should not return false but nil. fixed: [ruby-dev:25811] Mon Mar 7 01:22:14 2005 Hidetoshi NAGAI * ext/tk/tkutil.c: remove the some codes which depend on the difference between Ruby1.8 and 1.9, because st.c on Ruby1.9 was changed. Mon Mar 7 00:01:04 2005 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: fail to call TclTkLib.mainloop when $SAFE==4 Sun Mar 6 16:41:33 2005 Minero Aoki * lib/net/http.rb: HTTPHeader holds its header fields as an array (backport from CVS HEAD rev 1.112-1.123). [ruby-list:40629] * test/net/http/test_httpheader.rb: new file. Sun Mar 6 11:47:10 2005 Sam Roberts * lib/pp.rb: rdoced. [ruby-core:4490] Sun Mar 6 11:36:37 2005 Tanaka Akira * lib/pp.rb (File::Stat#pretty_print): Etc.getpwuid and Etc.getgrgid may return nil. [ruby-talk:129826] reported by Daniel Berger. Sat Mar 5 18:06:21 2005 Hirokazu Yamamoto * dir.c (fnmatch): removed unnecessary code. (ruby_1_8 didn't have String#clear, so [ruby-dev:24749] didn't affect it) * win32/win32.c (NtInitialize): ditto. (by numeric.c 1.101.2.14) Sat Mar 5 16:29:26 2005 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: freeze callback-entry objects * ext/tk/lib/tkextlib/tile.rb: support tile-0.6 Fri Mar 4 19:39:28 2005 Nobuyoshi Nakada * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser#do_includes): replace also locally defined modules. * ext/iconv/iconv.c: backport Iconv::InvalidEncoding from CVS HEAD. * ext/strscan/strscan.c: moved misplaced rdoc. Fri Mar 4 15:58:12 2005 Yukihiro Matsumoto * lib/cgi-lib.rb: add deprecation warning. [ruby-dev:25499] getopts.rb, parsearg.rb, importenv.rb as well. Fri Mar 4 11:17:06 2005 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (ip_rbUpdateCommand): get rid of warnings with Tcl/Tk 8.3 or former (backport from CVS_HEAD). * ext/tcltklib/tcltklib.c (ip_rb_threadUpdateCommand): ditto. Fri Mar 4 10:15:30 2005 Yukihiro Matsumoto * lib/set.rb (SortedSet::setup): a hack to shut up warning. [ruby-talk:132866] Fri Mar 4 07:07:00 2005 NARUSE, Yui * ext/nkf/nkf-utf8/nkf.c: follow nkf 1.63 Thu Mar 3 23:49:00 2005 NARUSE, Yui * ext/nkf/nkf-utf8/nkf.c: follow nkf 1.62 Thu Mar 3 11:49:51 2005 Kouhei Sutou * sample/rss/tdiary_plugin/rss-recent.rb: added site information. Wed Mar 2 19:53:07 2005 Nobuyoshi Nakada * ext/extmk.rb (parse_args): add DESTDIR only when not directed already. fixed: [ruby-dev:25781] Wed Mar 2 17:14:18 2005 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (lib_eventloop_core): fix typo Wed Mar 2 16:00:02 2005 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: enforce thread-check and exception-handling to avoid SEGV trouble. [KNOWN BUG] When supports pthread and running multiple Tk interpreters, an interrupt signal causes SEGV frequently. That may be a trouble of Ruby's signal handler. * ext/tk/tkutil/tkutil.c; fix a bug on converting a SJIS string array to a Tcl's list string. * ext/tk/tcltklib.c: wrap Tcl's original "namespace" command to protect from namespace crash. * ext/tk/lib/multi-tk.rb: enforce exception-handling. * ext/tk/lib/multi-tk.rb: catch IRB_EXIT to work on irb. * ext/tk/lib/tk.rb: ditto. * ext/tk/tcltklib.c: add TclTkLib.mainloop_thread? * ext/tk/lib/multi-tk.rb: (bug fix) callback returns a value. * ext/tk/lib/tk/canvas.rb (delete): bug fix when multiple arguments. * ext/tk/lib/clock.rb: fix 'no method error'. * ext/tk/lib/clock.rb (self.clicks): accept a Symbol argument. * ext/tk/lib/variable.rb: be able to set default_value_type; :numeric, :bool, :string, :symbol, :list, :numlist or nil (default; same to :string). If set a type, TkVariable#value returns a value of the type. * ext/tk/lib/tkextlib/tclx/tclx.rb: add Tk::TclX.signal to warn the risk of using TclX extension's 'signal' command. * ext/tk/sample/irbtk.rb: irb with Ruby/Tk. * ext/tk/sample/demos-*/anilabel.rb: bug fix on 'show code' * ext/tk/sample/demos-*/aniwave.rb: new Ruby/Tk animation demo. * ext/tk/sample/demos-*/pendulum.rb: ditto. * ext/tk/sample/demos-*/goldberg.rb: ditto. * ext/tk/sample/demos-*/widget: add entries of animation demos. Tue Mar 1 00:47:43 2005 Masatoshi SEKI * test/rinda/test_rinda.rb: backport from CVS_HEAD. use MockClock.sleep instead of Kernel.sleep [ruby-dev:25387] Tue Mar 1 00:34:24 2005 Masatoshi SEKI * lib/rinda/tuplespace.rb (Rinda::TupleSpace): improved keeper thread. * test/rinda/test_rinda.rb: ditto. Mon Feb 28 11:42:23 2005 Ian Macdonald * exception error messages updated. [ruby-core:04497] Mon Feb 28 09:03:09 2005 Yukihiro Matsumoto * ext/socket/socket.c (Init_socket): add bunch of Socket constants. Patch from Sam Roberts . [ruby-core:04409] Wed Feb 23 15:04:32 2005 akira yamada * lib/uri/generic.rb (split_userinfo): should split ":pass" into "" and "pass". [ruby-dev:25667] Wed Feb 23 08:00:18 2005 Yukihiro Matsumoto * array.c (rb_ary_s_create): no need for negative argc check. [ruby-core:04463] * array.c (rb_ary_unshift_m): ditto. Wed Feb 23 01:57:46 2005 Shugo Maeda * lib/net/imap.rb (initialize): handle certs correctly. Thanks, NABEYA Kenichi. (backported from CVS HEAD) Tue Feb 22 07:25:18 2005 Nobuyoshi Nakada * parse.y (parser_yylex): identfier after dot must not be a variable. Mon Feb 21 10:04:49 2005 NAKAMURA Usaku * {bcc32,win32,wince}/Makefile.sub (config.h): add fcntl. * win32/win32.[ch] (fcntl): ditto. * win32/win32.c (rb_w32_connect): support nonblocking mode. * ext/socket/socket.c (wait_connectable, ruby_connect): support nonblocking connect on various platforms. all changes are backported from CVS HEAD. [ruby-core:3154], [ruby-core:4364]. Sun Feb 20 00:48:48 2005 Tanaka Akira * lib/open-uri.rb (URI::FTP#buffer_open): access mechanism re-implemented according to RFC 1738. reported by Guillaume Marcais. [ruby-talk:131650] Sat Feb 19 18:11:47 2005 Masatoshi SEKI * lib/drb/drb.rb (DRbObject#respond_to?): take two arguments. [ruby-dev:25722] * test/drb/drbtest.rb: ditto. Sat Feb 19 13:52:02 2005 Tanaka Akira * lib/open-uri.rb: call OpenSSL::SSL::SSLSocket#post_connection_check after connection is made. Sat Feb 19 01:32:03 2005 Hirokazu Yamamoto * ext/bigdecimal/lib/bigdecimal/newton.rb: resolved LoadError. [ruby-dev:25685] * ext/bigdecimal/sample/linear.rb: ditto. * ext/bigdecimal/sample/nlsolve.rb: ditto. * ext/bigdecimal/lib/bigdecimal/nlsolve.rb: removed because this file is sample script and same file exists in ext/bigdecimal/sample. Fri Feb 18 17:14:00 2005 Yukihiro Matsumoto * lib/xmlrpc/parser.rb (XMLRPC::FaultException): make it subclass of StandardError class, not Exception class. [ruby-core:04429] Thu Feb 17 20:11:18 2005 Hirokazu Yamamoto * lib/drb/drb.rb (DRbServer.default_safe_level): fix typo. Thu Feb 17 20:11:18 2005 Nobuyoshi Nakada * test/digest/test_digest.rb: separate test case for each algorithms. [ruby-dev:25412] Thu Feb 17 11:54:00 2005 Nathaniel Talbott * lib/test/unit/collector.rb (collect_file): now deletes paths added to $LOAD_PATH instead of restoring it verbatim. * lib/test/unit/autorunner.rb (AutoRunner.run): fixed so that 'ruby -rtest/unit -rtest1 -rtest2 -e0' will use the objectspace collector again. Also tried to simplify the calling convention. * test/runner.rb: adjusted for new AutoRunner semantics. * lib/test/unit.rb: ditto. Thu Feb 17 04:21:47 2005 Yukihiro Matsumoto * lib/open3.rb (Open3::popen3): $? should not be EXIT_FAILURE. fixed: [ruby-core:04444] Thu Feb 17 00:09:45 2005 Masatoshi SEKI * test/drb/ignore_test_drb.rb: move TestDRbReusePort to new file [ruby-dev:25238] * test/drb/test_drb.rb: add method DRbService.ext_service, move TestDRbReusePort to new file [ruby-dev:25238] * test/drb/test_drb.rb: ditto. * test/drb/test_drbssl.rb: ditto. * test/drb/test_drbunix.rb: ditto. * test/drb/ut_drb.rb: reduce sleep. Thu Feb 17 00:02:27 2005 Yukihiro Matsumoto * eval.c (is_defined): NODE_IASGN is an assignment. Wed Feb 16 23:34:30 2005 Masatoshi SEKI * lib/drb/drb.rb: add lazy stop_service. ([druby-ja:109]) * lib/drb/extserv.rb: ditto. Wed Feb 16 17:07:57 2005 Hidetoshi NAGAI * ext/tk/tkutil.c: Follow the change of st.c (st_foreach) [ruby-list:40623]. Sometimes mis-convert from a Ruby's Array of SJIS Strings, which includes some kind of SJIS characters, to a Tcl's UTF8 list string. Mon Feb 14 23:58:17 2005 Kouhei Sutou * lib/rss/parser.rb (RSS::ListenerMixin::tag_end): fixed invalid namespace handling bug. Mon Feb 14 13:12:38 2005 GOTOU Yuuzou * ext/openssl/lib/openssl/ssl.rb (OpenSSL::SSL::SSLSocket#post_connection_check): new method. Mon Feb 14 00:40:49 2005 Masatoshi SEKI * lib/drb/drb.rb (InvokeMethod.perform): pass DRb info to sub thread. * test/drb/test_drb.rb (test_01_safe1_safe4_eval): fix test case. Sun Feb 13 23:13:46 2005 Kouhei Sutou * lib/rss/dublincore.rb (RSS::DublicCoreModel#date{,=}): added convenient methods. * lib/rss/0.9.rb (RSS::Rss::Channel#date{,=}): ditto. * lib/rss/2.0.rb (RSS::Rss::Channel::Item#date{,=}): ditto. * test/rss/: added tests for the convenient methods. Sun Feb 13 22:43:03 2005 Masatoshi SEKI * lib/drb/drb.rb (DRbServer): add default_safe_level, safe_level, config[:safe_level] ([druby-ja:120]) * test/drb/test_drb.rb, ut_eval.rb, ut_safe1.rb: ditto. Sun Feb 13 16:56:52 2005 GOTOU Yuuzou * lib/webrick/cgi.rb (WEBrick::CGI.start): should set reason-phrase to the value of status header field. ([ruby-dev:40617]) Sun Feb 13 00:52:33 2005 Masatoshi SEKI * lib/erb.rb (ERB::Util.h, u): make it module_function. Sat Feb 12 17:29:19 2005 Tanaka Akira * lib/open-uri.rb (OpenURI.open_loop): send authentication only for the URI directly specified. Sat Feb 12 15:07:23 2005 Nobuyoshi Nakada * random.c (rand_init): suppress warning. Sat Feb 12 13:54:03 2005 Tanaka Akira * lib/open-uri.rb: support https if the platform provides CA certificates. Sat Feb 12 06:18:28 2005 URABE Shyouhei * ext/etc/etc.c (Init_etc): sGroup needs HAVE_ST_GR_PASSWD check. [ruby-dev:25675] Fri Feb 11 17:40:42 2005 GOTOU Yuuzou * ext/openssl/ossl_x509store.c (ossl_x509store_set_default_paths): new method OpenSSL::X509::Store#set_default_paths. Fri Feb 11 11:33:53 2005 Tanaka Akira * lib/open-uri.rb (URI::HTTP#proxy_open): new option supported: :http_basic_authentication. suggested by Kent Sibilev. [ruby-core:4392] Fri Feb 11 06:30:07 2005 George Ogata * misc/ruby-mode.el: ignore parenthesis inside heredoc. [ruby-core:04415] Fri Feb 11 04:54:13 2005 Tilman Sauerbeck * lib/rdoc/generators/html_generator.rb: [ruby-core:04412] * lib/rdoc/generators/ri_generator.rb: ditto. Thu Feb 10 11:14:17 2005 NAKAMURA Usaku * win32/Makefile.sub (COMMON_HEADERS): shouldn't include winsock2.h. * ext/socket/extconf.rb (sockaddr_storage): remove workaround for mswin32. Thu Feb 10 10:29:16 2005 NAKAMURA Usaku * ext/curses/curses.c: don't need to check HAVE_WCOLOR_SET excluding window_color_set(). Thu Feb 10 00:47:25 2005 Yukihiro Matsumoto * struct.c (make_struct): fixed: [ruby-core:04402] Wed Feb 9 08:07:08 2005 Paul Duncan * ext/curses/curses.c (window_color_set): [ruby-core:04393] Tue Feb 8 23:51:47 2005 Masatoshi SEKI * lib/drb/drb.rb: reject :instance_eval, :class_eval, :module_eval [druby-ja:117] Tue Feb 8 13:06:12 2005 Sam Roberts * ext/socket/socket.c (Init_socket): SO_REUSEPORT added. [ruby-talk:130092] Tue Feb 8 09:30:01 2005 Yukihiro Matsumoto * lib/cgi.rb (CGI::Cookie): [ruby-talk:130040] Tue Feb 8 00:19:02 2005 Tanaka Akira * lib/resolv.rb (Resolv::DNS::Name#subdomain_of?): new method. (Resolv::DNS::Name#inspect): ditto. Suggested by Sam Roberts. [ruby-talk:129086] Mon Feb 7 10:06:30 2005 Yukihiro Matsumoto * object.c: [ruby-doc:818] Mon Feb 7 01:56:20 2005 NAKAMURA Usaku * instruby.rb, rubytest.rb (srcdir): no longer embed srcdir into rbconfig.rb. (backported from CVS HEAD) * ext/socket/extconf.rb (sockaddr_storage): winsock2.h have the definition of struct sockaddr_storage, but socket.c doesn't include it because this version of ruby still has binary level compatibility with winsock1. * lib/mkmf.rb (create_makefile): should support header files in depend file. Mon Feb 7 01:21:50 2005 Nobuyoshi Nakada * ext/socket/extconf.rb: check if getaddrinfo() works fine only when wide-getaddrinfo option is not given. fixed: [ruby-dev:25422] * lib/mkmf.rb ($extmk): check if under ext directory. * lib/mkmf.rb (Logging.postpone): allow recursive operation. * lib/mkmf.rb (try_constant): make sure if really a constant, reduce the number of times of compile. * lib/mkmf.rb (have_macro, have_var, byte_order): new functions. * lib/mkmf.rb (find_library): allow directory list with separators. * lib/mkmf.rb (arg_config): manage provided configuration options. * lib/mkmf.rb (dir_config): accept arrays of directory names as default values. * mkconfig.rb: no longer embed srcdir and compile_dir into rbconfig.rb. * lib/mkmf.rb (create_makefile): fix unbalanced parens. Sun Feb 6 19:23:01 2005 NAKAMURA Usaku * eval.c (stack_extend): add prototype because VC++8 doesn't accept __declspec(noinline) with K&R style function definitions. (backported from CVS HEAD) Sun Feb 6 14:14:26 2005 Tadayoshi Funaba * lib/date.rb (new_with_hash): changed messages of exception. * lib/date/format.rb (str[fp]time): undocumented conversion specifications %[1-3] are now deprecated. Sun Feb 6 12:20:11 2005 Akinori MUSHA * bignum.c (rb_big2ulong_pack): One too many arguments are passed to big2ulong(). * re.c (rb_reg_init_copy, rb_reg_initialize_m): One too many arguments are passed to rb_reg_initialize(). Sun Feb 6 03:24:20 2005 Tanaka Akira * lib/resolv.rb (Resolv::DNS::Resource::TXT): multiple strings was not handled. (Resolv::DNS::Resource::TXT#strings): new method to return all strings. (Resolv::DNS::Message::MessageEncoder#put_string_list): new method. (Resolv::DNS::Message::MessageDecoder#get_string_list): ditto. based on [ruby-talk:129732] by Sam Roberts. Fri Feb 4 00:30:45 2005 Kouhei Sutou * lib/rss: supported Image module. http://web.resource.org/rss/1.0/modules/image/ Thu Feb 3 23:42:36 2005 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_close, strio_close_read, strio_close_write): should return nil instead of self as well as IO. [ruby-dev:25623] * ext/stringio/stringio.c (strio_extend, strio_putc): fill with zero extended portion. [ruby-dev:25626] Wed Feb 2 23:52:53 2005 sheepman * ext/stringio/stringio.c (strio_truncate): should MEMZERO an extended part. [ruby-dev:25618] Wed Feb 2 21:56:01 2005 Kouhei Sutou * lib/rss/rss.rb (RSS::Element#convert): added. * lib/rss/rss.rb: convert -> need_convert. * lib/rss/1.0.rb: ditto. * lib/rss/0.9.rb: ditto. * lib/rss/2.0.rb: ditto. * lib/rss/trackback.rb: ditto. Tue Feb 1 22:48:48 2005 Masatoshi SEKI * lib/drb/drb.rb (DRb::DRbObject#respond_to?): check marshal_dump and _dump. Tue Feb 1 00:20:23 2005 Nobuyoshi Nakada * configure.in (aix): fix linker flags on AIX. [ruby-talk:125460] Mon Jan 31 13:33:21 2005 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: add invalid namespace check * ext/tk/lib/multi-tk.rb: add invalid_namespace? method * ext/tk/lib/remote-tk.rb: ditto Mon Jan 31 10:29:18 2005 Yukihiro Matsumoto * lib/irb/context.rb (IRB::Context::initialize): [ruby-core:04330] Sat Jan 29 09:42:12 2005 Sam Roberts * lib/resolv.rb (Resolv::DNS::Resource::IN::SRV): Added RFC2782 SRV resource record for specifying location of services. Fri Jan 28 17:16:55 2005 Tanaka Akira * lib/resolv.rb (Resolv::DNS::Config.parse_resolv_conf): parse options line for ndots option. (Resolv::Hosts#lazy_initialize): return self. (Resolv::DNS#lazy_initialize): ditto. (Resolv::DNS::Config#lazy_initialize): ditto. Suggested by Sam Roberts. Thu Jan 27 13:18:03 2005 Yukihiro Matsumoto * st.c (st_foreach): report success/failure by return value. [ruby-Bugs-1396] Thu Jan 27 00:15:29 2005 Minero Aoki * test/fileutils/test_fileutils.rb (setup): support BSD-style directory group inheritance. (backport from HEAD, rev 1.32) * test/fileutils/fileasserts.rb (assert_same_entry): show entry difference. (backport from HEAD, rev 1.4) Wed Jan 26 23:09:11 2005 Minero Aoki * lib/net/protocol.rb (WriteAdapter#puts): should append \n, not prepend. [ruby-talk:128302] (backport from HEAD, rev 1.75) Wed Jan 26 10:51:50 2005 NAKAMURA Usaku * win32/win32.c (flock_winnt, flock_win95): unlock file even if LOCK_NB is specified. (backported from CVS HEAD) Tue Jan 25 17:11:51 2005 NAKAMURA Usaku * ruby.c (proc_options): correct -T option in RUBYOPT. (backported from CVS HEAD) Tue Jan 25 14:05:52 2005 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: fix SEGV bug; trouble on canceling remained after scripts [ruby-dev:25479]: NULL current namespace when deleting Tk interpreter [ruby-talk:126225] * ext/tcltklib/extconf.rb: bug fix; TCL_ENABLE_THREAD flag is inverted [ruby-talk:126360] * ext/tcltklib/extconf.rb: add yet another native-thread check * ext/tk/tkutil.c: fix SEGV bug; NULL string pointer when finalize Ruby interpreter * ext/tk/lib/multi-tk.rb: avoid warning for deleted safeTk ip frame * ext/tk/lib/tk/bindtag.rb: bug fix; new method of named bindtag doesn't return the created object [ruby-dev:25479] * ext/tk/lib/tk/menu.rb: bug on treating arguments [ruby-dev:25479] * ext/tk/lib/tk.rb: bug fix; cannot accept a callback ID string for a command argument [ruby-dev:25479] * ext/tk/lib/multi-tk.rb: ditto * ext/tk/lib/tk/*.rb: ditto * ext/tk/lib/tkextlib/*.rb: ditto * ext/tk/sample/demos-jp/anilabel.rb: new demo script * ext/tk/sample/demos-en/anilabel.rb: ditto * ext/tk/sample/tkHTML/ss.rb: local variable scope bug fix [ruby-dev:25479] Mon Jan 24 15:44:25 2005 Tilman Sauerbeck * lib/rdoc/parsers/parse_c.rb: allow whitespace after function names. [ruby-core:4296] * lib/rdoc/parsers/parse_simple.rb: adds support for private comments in the "simple" parser. [ruby-core:4301] Mon Jan 24 15:44:25 2005 Charles Mills * lib/rdoc/parsers/parse_c.rb: adds support for constants (rb_define_const), accessors (rb_define_attr), and makes a couple fixes. [ruby-core:4307] Mon Jan 24 15:44:25 2005 Florian Gro * lib/rdoc/parsers/parse_rb.rb: Logic for def Builtin.method() end [ruby-core:4302] Mon Jan 24 15:44:25 2005 Yukihiro Matsumoto * document updates - [ruby-core:04296], [ruby-core:04301], [ruby-core:04302], [ruby-core:04307] Sun Jan 23 12:41:16 2005 NAKAMURA, Hiroshi * lib/soap/wsdlDriver.rb: from 1.5.3-ruby1.8.2, operation which has capitalized name (such as KeywordSearchRequest in AWS) is defined as a method having uncapitalized name. (converted with GenSupport.safemethodname to handle operation name 'foo-bar'). it introduced serious incompatibility; in the past, it was defined as a capitalized. define capitalized method as well under that circumstance. Sun Jan 23 05:24:42 2005 GOTOU Yuuzou * ext/openssl/ossl_ocsp.c (ossl_ocspreq_to_der): should call GetOCSPReq at first. Sat Jan 22 23:09:47 2005 Masatoshi SEKI * lib/drb/ssl.rb (accept): rescue SSLError. [druby-ja:110] Sat Jan 22 22:35:03 2005 Masatoshi SEKI * lib/drb/unix.rb: fail if UNIXFileOwner is set. [druby-ja:111] Fri Jan 21 23:58:42 2005 Yukihiro Matsumoto * ext/stringio/stringio.c (strio_set_pos): clear EOF flag. [ruby-talk:127511] Fri Jan 21 20:07:02 2005 Tanaka Akira * lib/resolv.rb (Resolv::DNS::Config.resolv): don't raise ResolvError. reported by Sam Roberts. [ruby-talk:127133] Fri Jan 21 16:58:10 2005 Yukihiro Matsumoto * dir.c (rb_push_glob): should work for NUL delimited patterns. Fri Jan 21 13:58:37 2005 Shugo Maeda * lib/net/imap.rb (u8tou16): fixed typo. fixed: [ruby-list:40546] (backported from CVS HEAD) Fri Jan 21 09:30:16 2005 NAKAMURA Usaku * rubyio.h (rb_eof_error): should mark as NORETURN. (backported from CVS HEAD) Fri Jan 21 00:31:36 2005 Hirokazu Yamamoto * ext/syck/rubyext.c (syck_parser_bufsize_set): avoid VC++ warning "local variable 'size' used without having been initialized". Thu Jan 20 19:03:24 2005 NAKAMURA Usaku * ext/extmk.rb (extmake): shouldn't set $extflags on mswin32. * win32/Makefile.sub (LIBRUBY_SO): should use $DLDOBJS instead of $EXTOBJS. fixed: [ruby-core:04290] (backported from CVS HEAD) Thu Jan 20 11:42:02 2005 Yukihiro Matsumoto * string.c (rb_str_new4): should propagate taintedness. * struct.c (rb_struct_set): use original method name, not callee name, to retrieve member slot. [ruby-core:04268] * time.c (time_strftime): protect from format modification from GC finalizers. Wed Jan 19 18:06:40 2005 NAKAMURA Usaku * lib/ipaddr.rb (to_s, test_to_s): too many colons with some cases. (backported from CVS HEAD) Wed Jan 19 01:16:30 2005 Tanaka Akira * lib/resolv.rb (Resolv::DNS::Config.parse_resolv_conf): ignore domain and search directive without an argument. reported by Sam Roberts. [ruby-talk:126781] Tue Jan 18 15:03:05 2005 GOTOU Yuuzou * lib/webrick/ssl.rb (WEBrick::Config::SSL): the default value of :SSLEnable is false. * lib/webrick/server.rb (WEBrick::Daemon.start): prepared stdio don't allow changing its mode. * lib/webrick/httpproxy.rb (WEBrick::HTTPProxyServer#proxy_service): should delete trailing LF from the result of pack("m*"). * lib/webrick/httpproxy.rb (WEBrick::HTTPProxyServer#proxy_connect): - should delete trailing LF from the result of pack("m*"). - clear Request-Line not to send the response by HTTPServer#run. * lib/webrick/httputils (WEBrick::HTTPUtils.parse_qvalues): refine regexp (and change the name of a local variable). * lib/webrick/httputils.rb (WEBrick::HTTPUtils#escape_path): add new method to escape URI path component. * lib/webrick/cgi.rb (WEBrick::CGI::Socket#request_line): should escape SCRIPT_NAME and PATH_INFO before being parsed as a URI. * test/webrick/*, sample/webrick/httpproxy.rb: add new file. Mon Jan 17 23:33:46 2005 Nobuyoshi Nakada * configure.in (aix): fix typo. [ruby-talk:126401] Mon Jan 17 07:08:51 2005 Nobuyoshi Nakada * ext/readline/readline.c: suppress warnings. * lib/irb/extend-command.rb (IRB::ContextExtender.def_extend_command): ditto. * lib/irb/ext/history.rb (IRB::Context::set_last_value): ditto. * lib/irb/ext/history.rb (IRB::Context::eval_history): ditto. * lib/irb/locale.rb (IRB::Locale::real_load): ditto. * lib/irb/slex.rb (SLex::Node::create_subnode): remove garbage. Mon Jan 17 00:09:42 2005 WATANABE Hirofumi * lib/uri/common.rb (PORT): typo fix. fixed: [ruby-core:04256] Sat Jan 15 14:57:22 2005 Nobuyoshi Nakada * ruby.c (proc_options): ignore trailing CRs at the end of short options as well as long options. fixed: [ruby-core:04232] Sat Jan 15 13:35:16 2005 Kouhei Sutou * lib/rss/rss.rb (RSS::VERSION): 0.1.2 -> 0.1.3. * lib/rss/rss.rb: accept inheritance. [ruby-talk:126104] Thu Jan 13 04:48:53 2005 Tanaka Akira * io.c (io_fread): don't warn nonblocking behavior by default. Wed Jan 12 00:36:29 2005 Nobuyoshi Nakada * object.c (rb_class_superclass): superclass of singleton class also should be a singleton class. fixed: [ruby-list:40519] Tue Jan 11 09:44:40 2005 Hirokazu Yamamoto * numeric.c (Init_Numeric): turn off floating point exceptions on bcc32. "1e300".to_f had crashed by overflow. Tue Jan 11 03:10:10 2005 Minero Aoki * lib/fileutils.rb (copy_entry): could not copy symbolic link. [ruby-talk:125733] * lib/fileutils.rb (copy_stream): use read/write instead of sysread/syswrite. Mon Jan 10 23:08:15 2005 Nobuyoshi Nakada * variable.c (rb_autoload): hide internal data from ruby level. fixed: [ruby-dev:25435], [ruby-list:40498] Mon Jan 10 01:22:55 2005 Yukihiro Matsumoto * gc.c (rb_data_object_alloc): klass may be NULL. [ruby-list:40498] Sun Jan 9 03:12:58 2005 Tanaka Akira * io.c (io_fread): warn nonblocking behavior. (io_readpartial): new method IO#readpartial. Sat Jan 8 04:38:47 2005 why the lucky stiff * lib/yaml.rb: Kernel#y requires an argument. Fri Jan 7 21:12:29 2005 TAMURA Takashi * random.c (rand_init): use ALLOC_N instead of ALLOCA_N [ruby-dev:25426] Fri Jan 7 18:03:35 2005 Tanaka Akira * gc.c (mark_locations_array): avoid core dump with -O3. [ruby-dev:25424] Thu Jan 6 20:31:07 2005 NAKAMURA Usaku * ext/zlib/zlib.c (zstream_end): should return value. (backported from CVS HEAD) Thu Jan 6 19:55:13 2005 Hirokazu Yamamoto * win32/win32.c (rb_w32_close): didn't close socket handle. [ruby-dev:25414] * win32/win32.c (rb_w32_open_osfhandle): bcc32's _open_osfhandle never set EMFILE. Thu Jan 6 17:14:31 2005 Hirokazu Yamamoto * random.c (random_seed): O_NONBLOCK isn't defined on some platforms. [ruby-dev:25417] Thu Jan 6 13:45:35 2005 Tanaka Akira * lib/time.rb: recognize +00:00 and GMT as a localtime. Thu Jan 6 07:58:28 2005 Dave Thomas * lib/rdoc/usage.rb (RDoc::RDoc.usage_no_exit): Allow for colons in path names on DOS machines. (thanks to Johan Nilsson) Wed Jan 5 20:16:32 2005 Tanaka Akira * random.c (limited_big_rand): didn't work if SIZEOF_BDIGITS == 2. [ruby-dev:25408] * random.c (random_seed): refined. Wed Jan 5 12:49:39 2005 Nobuyoshi Nakada * eval.c (rb_thread_initialize): Thread objects cannot be initialized again. fixed: [ruby-core:04067] Wed Jan 5 10:48:16 2005 NAKAMURA Usaku * dir.c (dir_s_mkdir): win32 special processing doesn't need any longer. (backported from CVS HEAD) * win32/win32.[ch] (rb_w32_mkdir): new function. POSIX.1 compatible interface. (backported from CVS HEAD) * win32/win32.[ch] (rb_w32_rmdir): new function. (backported from CVS HEAD) Wed Jan 5 02:30:11 2005 Tanaka Akira * random.c (init_by_array): imported from mt19937ar-cok.tgz. (genrand_int32): ditto. (genrand_real): replaced with genrand_res53 in mt19937ar-cok. (rand_init): support bignum for longer seed. (random_seed): generate longer seed. (make_mask): new function. (limited_rand): ditto. (limited_big_rand): ditto. (rb_f_rand): call limited_rand and limited_big_rand. [ruby-dev:25403] Tue Jan 4 23:25:29 2005 Yukihiro Matsumoto * bignum.c (rb_big_rand): should return positive random number. [ruby-dev:25401] Tue Jan 4 11:15:29 2005 TAMURA Takashi * bignum.c (rb_big_rand): do not use rb_big_modulo to generate random bignums. [ruby-dev:25396] Mon Jan 3 14:01:54 2005 Tanaka Akira * random.c (random_seed): don't use /dev/urandom if it is not character device. Mon Jan 3 11:37:42 2005 Tanaka Akira * random.c (random_seed): use /dev/urandom if available. [ruby-dev:25392] Mon Jan 3 07:46:42 2005 GOTOU Yuuzou * lib/webrick/httpauth/htpasswd.rb (WEBrick::Htpasswd#reload): raise NotImplementedError if password is encrypted by digest algorithms. This patch is contributed by sheepman. [ruby-list:40467] * lib/webrick/httpauth/digestauth.rb (WEBrick::HTTPAuth::DigestAuth#_authenticate): fix digest calculation. This patch is contributed by sheepman. [ruby-list:40482] * lib/webrick/{httpauth.rb,httpauth/basicauth.rb,httpproxy.rb}: use pack/unpack-template char "m" instead of lib/base64.rb to do base64 encoding/decoding. fixed: [ruby-dev:25336] * test/webrick/test_httpauth.rb: new file. Sat Jan 1 04:20:23 2005 GOTOU Yuuzou * ext/openssl/ossl_ns_spki.c (ossl_spki_set_challenge): should call StringValue before GetSPKI. fixed: [ruby-dev:25359]. Sat Jan 1 01:13:28 2005 Yukihiro Matsumoto * variable.c (rb_autoload): [ruby-dev:25373] Fri Dec 31 14:10:43 2004 Dave Thomas * lib/rdoc/ri/ri_formatter.rb (RI::TextFormatter::display_flow_item): Fix problem if heading contains formatting. Thu Dec 30 00:41:42 2004 Yukihiro Matsumoto * eval.c (svalue_to_avalue): [ruby-dev:25366] * string.c (rb_str_justify): [ruby-dev:25367] Wed Dec 29 11:07:07 2004 Dave Thomas * lib/rdoc/generators/template/html/kilmer.rb: Update to use new sections. Tue Dec 28 22:31:46 2004 Nobuyoshi Nakada * string.c (rb_str_justify): create buffer string after argument type conversion. fixed: [ruby-dev:25341] Tue Dec 28 15:41:48 2004 Nobuyoshi Nakada * ext/nkf/nkf-utf8/nkf.c (reinit): should initialize all static variables. fixed: [ruby-list:40445] Tue Dec 28 15:25:20 2004 Nobuyoshi Nakada * ext/nkf/lib/kconv.rb (Kconv::RegexpEucjp): second byte is up to 0xfe. * ext/nkf/lib/kconv.rb (Kconv#kconv): should handle UTF8 and UTF16 properly. Tue Dec 28 13:35:20 2004 Nobuyoshi Nakada * ext/zlib/zlib.c (rb_deflate_s_deflate, rb_inflate_s_inflate): ensure freeing internal zstreams. fixed: [ruby-dev:25309] * ext/zlib/zlib.c (rb_deflate_init_copy): replace rb_deflate_clone. Tue Dec 28 12:26:45 2004 NAKAMURA Usaku * win32/Makefile.sub, win32/setup.mak (RDOCTARGET, install, install-nodoc, install-doc): rdoc support for mswin32. * win32/configure.bat (--enable-install-doc, --disable-install-doc): ditto. Mon Dec 27 20:02:14 2004 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: fix SEGV bug when deleting Tk interp * ext/tk/lib/multi-tk.rb: ditto Mon Dec 27 16:55:17 2004 GOTOU Yuuzou * ext/openssl/ossl_x509name.c (Init_ossl_x509name): should use rb_hash_new to get exactly a Hash. fix [ruby-dev:25325]. Mon Dec 27 16:29:56 2004 Yukihiro Matsumoto * string.c (rb_str_justify): [ruby-dev:25341] Mon Dec 27 15:47:48 2004 Minero Aoki * test/fileutils/fileasserts.rb: sync with HEAD. * test/fileutils/test_fileutils.rb: ditto. * test/fileutils/test_nowrite.rb: ditto. Mon Dec 27 15:21:07 2004 Minero Aoki * lib/fileutils.rb (mv): should raise error when moving a directory to the (empty) directory. [ruby-talk:124368] (backport from HEAD 1.48) * lib/fileutils.rb (mv): wrongly did not overwrite file on Win32 platforms. (backport from HEAD 1.48) Sat Dec 25 11:11:48 2004 Yukihiro Matsumoto * stable version 1.8.2 released. Sat Dec 25 04:23:49 2004 Minero Aoki * lib/fileutils.rb (mkdir, mkdir_p): should ensure directory permission. (backportted from HEAD, 1.47) * lib/fileutils.rb (traverse, remove_dir): untaint trasted objects. (backportted from HEAD, 1.46) Sat Dec 25 01:28:23 2004 Yukihiro Matsumoto * io.c: cancel io_reopen() change on Dec. 24th. * dln.c: use for NetBSD. [ruby-dev:25313] * io.c (rb_f_select): IO list could be altered. [ruby-dev:25312] Fri Dec 24 23:51:48 2004 Hirokazu Yamamoto * bcc32/Makefile.sub: bcc32 should use RTL dll (backport from HEAD) [ruby-dev:25306] * win32/win32.[ch]: ditto. Fri Dec 24 23:27:18 2004 Hidetoshi NAGAI * ext/tk/lib/tk/image.rb: TkPhotoImage#cget bug fix Fri Dec 24 18:39:25 2004 Hirokazu Yamamoto * win32/win32.[ch]: failed to compile on bcc32 (and probably wince) [ruby-dev:25306] Fri Dec 24 02:52:52 2004 Nobuyoshi Nakada * io.c (io_reopen, rb_io_reopen): prohibit to change access mode for special IO ports. [ruby-dev:25225] Fri Dec 24 02:22:53 2004 Nobuyoshi Nakada * ext/syck/rubyext.c (rb_syck_io_str_read): [ruby-core:03973] * ext/syck/rubyext.c (syck_loader_transfer): check type conversion. * ext/syck/rubyext.c (syck_parser_assign_io, rb_new_syck_node): duck typing. * ext/syck/rubyext.c (syck_parser_s_alloc, syck_parser_initialize): allocation framework. * ext/syck/rubyext.c (syck_emitter_s_alloc, syck_emitter_initialize): ditto. Fri Dec 24 01:21:00 2004 Hidetoshi NAGAI * ext/tk/lib/tkextlib/blt.rb: add BLT extension support * ext/tk/lib/tkextlib/blt/*.rb: ditto * ext/tk/lib/tkextlib/blt/tile/*.rb: ditto Thu Dec 23 23:36:28 2004 Nobuyoshi Nakada * process.c (proc_setgroups): check if the argument lenght is modified. fixed: [ruby-dev:25285] Thu Dec 23 13:13:33 2004 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: define TclTkLib::COMPILE_INFO and RELEASE_DATE * ext/tcltklib/extconf.rb: ditto * ext/tk/tkutil.c: define TkUtil::RELEASE_DATE * ext/tk/lib/tk.rb: define Tk::RELEASE_DATE Thu Dec 23 09:38:31 2004 Nobuyoshi Nakada * io.c (io_reopen): restore exact mode. fixed: [ruby-core:04003] Thu Dec 23 00:16:32 2004 Nobuyoshi Nakada * configure.in (bsdi): use $(CC) for LDSHARED. fixed [ruby-dev:25270] Wed Dec 22 11:14:55 2004 Nobuyoshi Nakada * io.c (rb_io_mode_modenum): replace O_ACCMODE with O_RDWR. fixed: [ruby-dev:25273] Wed Dec 22 08:34:32 2004 Nobuyoshi Nakada * ext/dl/sym.c (rb_dlsym_initialize): extract internal pointers after all argument conversion. fixed: [ruby-dev:25271] Wed Dec 22 00:08:01 2004 NAKAMURA, Hiroshi * lib/soap/*, test/soap/*, sample/soap/authheader/*: eval cleanup. Tue Dec 21 22:07:33 2004 GOTOU Yuuzou * ext/openssl/ossl_asn1.c (ossl_asn1_traverse, ossl_asn1_decode, ossl_asn1_decode_all): temporary value should be marked volatile. Tue Dec 21 14:40:02 2004 GOTOU Yuuzou * ext/openssl/ossl_asn1.c (ossl_asn1_traverse, ossl_asn1_decode, ossl_asn1_decode_all): use rb_str_new4 to avoid SEGV. fix [ruby-dev:25261] * test/openssl/test_asn1.rb: add tests for OpenSSL::ASN1. Tue Dec 21 12:22:40 2004 Nobuyoshi Nakada * io.c (io_reopen): keep duplex pipe in correct mode for exception safeness. fixed: [ruby-dev:25152] Tue Dec 21 12:10:04 2004 Hidetoshi NAGAI * ext/tk/lib/tk/grid.rb: rescue bug of 'grid configure' on Tcl/Tk8.3- Tue Dec 21 00:53:01 2004 Yukihiro Matsumoto * ext/openssl/ossl_asn1.c (ossl_asn1_traverse): [ruby-dev:25261] * ext/openssl/ossl_asn1.c (ossl_asn1_decode): ditto. * ext/openssl/ossl_asn1.c (ossl_asn1_decode_all): ditto. Mon Dec 20 23:22:26 2004 NAKAMURA, Hiroshi * added files: * lib/soap/mapping/wsdl*.rb * lib/wsdl/soap/element.rb * lib/wsdl/xmlSchema/simpleContent.rb * modified files: * lib/soap/* * lib/wsdl/* * lib/xsd/* * test/soap/* * test/wsdl/* * test/xsd/* * sample/soap/* * sample/sdl/* * summary * imported from the soap4r repository. Version: 1.5.3-ruby1.8.2 * added several XSD basetype support: nonPositiveInteger, negativeInteger, nonNegativeInteger, unsignedLong, unsignedInt, unsignedShort, unsignedByte, positiveInteger * HTTP client connection/send/receive timeout support. * HTTP client/server gzipped content encoding support. * improved WSDL schema definition support; still is far from complete, but is making step by step improovement. Mon Dec 20 22:56:39 2004 Tanaka Akira * gc.c (stack_end_address): gcc noinline attribute is available since gcc-3.1. Mon Dec 20 14:07:02 2004 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: supports new features of Tcl/Tk8.5a2 * ext/tk/lib/tk/clock.rb: ditto * ext/tk/lib/tk/text.rb: ditto * ext/tk/lib/tk/panedwindow.rb: ditto Mon Dec 20 12:47:13 2004 GOTOU Yuuzou * ext/openssl/lib/net/https.rb,protocols.rb,telnets.rb: delete doc and code about SSLContext#{key_file,cert_file}. fixed: [ruby-dev:25243] Mon Dec 20 12:42:17 2004 NAKAMURA Usaku * io.c (io_fwrite): workaround for MSVCRT's bug. fixed: [ruby-core:03982] Mon Dec 20 11:21:04 2004 Nobuyoshi Nakada * io.c (rb_io_eof): check if closed before clearerr(). fixed: [ruby-dev:25251] Mon Dec 20 03:30:40 2004 Nobuyoshi Nakada * lib/cgi/session.rb (CGI::Session#initialize): empty session id was used if request had no session key. fixed: [ruby-core:03981] Mon Dec 20 01:51:01 2004 Yukihiro Matsumoto * struct.c (make_struct): [ruby-dev:25249] Mon Dec 20 00:28:20 2004 Kouhei Sutou * lib/rexml/encodings/SHIFT-JIS.rb: backported from CVS HEAD. * lib/rexml/encodings/SHIFT_JIS.rb: ditto. Sun Dec 19 17:19:48 2004 GOTOU Yuuzou * ext/openssl/ossl_x509store.c (ossl_x509store_set_time): add OpenSSL::X509::Store#time=. (ossl_x509stctx_set_time): add OpenSSL::X509::StoreContext#time=. * test/openssl/ossl_x509store.rb: test certificate validity times. * ext/openssl/ossl_x509name.c (ossl_x509name_to_s): add optional second argument to specify the output format (see also X509_NAME_print_ex). * ext/openssl/ossl_x509name.c (ossl_x509name_init): new constants: OpenSSL::X509::Name::COMPAT, OpenSSL::X509::Name::RFC2253, OpenSSL::X509::ONELINE, OpenSSL::X509::MULTILINE. * ext/openssl/lib/openssl/x509.rb (OpenSSL::X509::Name::RFC2253DN): new module to provide the parse for RFC2253 DN format. * ext/openssl/lib/openssl/x509.rb (OpenSSL::X509::Name.parse_rfc2253): new method to parse RFC2253 DN format. * test/openssl/ossl_x509name.rb: add tests about RFC2253 DN. * text/openssl/ssl_server.rb: try to listen ports from 20443 to 20542 while EADDRINUSE is raised. * all changes in this entry are backport from 1.9. Sun Dec 19 17:24:59 2004 Nobuyoshi Nakada * configure.in (enable_rpath): use rpath flag to embed the library path into extensions on ELF environment. [ruby-dev:25035] Sun Dec 19 11:01:25 2004 Nobuyoshi Nakada * lib/test/unit.rb: use standalone runner for -e. * lib/test/unit/autorunner.rb (Test::Unit::AutoRunner#options): accept multiple -p and -x options. * lib/test/unit/collector/dir.rb (Test::Unit::Collector::Dir#recursive_collect): ditto. Sat Dec 18 16:36:23 2004 Nobuyoshi Nakada * ext/zlib/zlib.c (rb_deflate_s_deflate, rb_inflate_s_inflate): disallow interrupt by type conversion. fixed: [ruby-dev:25226] Sat Dec 18 15:16:41 2004 NAKAMURA, Hiroshi * lib/webrick/httpauth.rb, lib/webrick/httpauth/{basicauth.rb,digestauth.rb}: use pack/unpack-template char "m" instead of lib/base64.rb to do base64 encoding/decoding. Sat Dec 18 10:51:01 2004 Yukihiro Matsumoto * dir.c (dir_open_dir): new function. [ruby-dev:25242] Fri Dec 17 18:07:01 2004 Shugo Maeda * test/readline/test_readline.rb: fix for BSD. Thanks, GOTOU Yuuzou. fixed: [ruby-dev:25218] Fri Dec 17 16:28:12 2004 Hidetoshi NAGAI * ext/tk/lib/tk.rb: fix bug on setting up system encoding * ext/tk/lib/tk/event.rb: fix error on require process * ext/tk/lib/tk/font.rb: fix abnormal termination error on Windows * ext/tk/lib/tk/virtevent.rb: TkVirtualEvent::PreDefVirtEvent.new() accepts event-sequence arguments * ext/tk/lib/tk/text.rb: fail to dump embedded images * ext/tk/lib/tk/text.rb: tag_nextrange and tag_prevrange returns wrong types of values * ext/tk/lib/tk/texttag.rb: nextrange and prevrange returns wrong types of values * ext/tk/lib/tk/text.rb: add TkText::IndexModMethods module and TkText::IndexString class to treat text index modifiers * ext/tk/lib/tk/texttag.rb: use TkText::IndexModMethods module * ext/tk/lib/tk/textmark.rb: ditto * ext/tk/lib/tk/textimage.rb: ditto * ext/tk/lib/tk/textwindow.rb: ditto * ext/tk/lib/tk/textimage.rb: wrong gravity of text mark for embedded image * ext/tk/lib/tk/textwindow.rb: wrong gravity of text mark for embedded window Fri Dec 17 13:50:00 2004 Akiyoshi, Masamichi * vms/vmsruby_private.c, vms/vmsruby_private.h: private routines for VMS port are added. * eval.c (ruby_init): change to call VMS private intialization routine. Fri Dec 17 13:33:58 2004 Nobuyoshi Nakada * lib/cgi/session.rb (CGI::Session#initialize): control adding session_id hidden fields. fixed: [ruby-talk:123850] Thu Dec 16 23:25:25 2004 Masatoshi SEKI * lib/drb/drb.rb, lib/drb/ssl.rb: backported from CVS HEAD. [druby-ja:101] * test/drb/test_drb.rb: adjust and reduce sleep (backported from CVS HEAD.) Thu Dec 16 18:44:58 2004 GOTOU Yuuzou * lib/webrick/httpserver.rb (WEBrick::HTTPServer#run): should wait for reading request till data arrive. [ruby-talk:121068] * lib/webrick/server.rb (WEBrick::GenericServer#start_thread): should log about all accepted socket. [ruby-core:03962] * lib/webrick/accesslog.rb (WEBrick::AccessLog#setup_params): "%%" and "%u" are supported. [webricken:135] * lib/webrick/httpservlet/filehandler.rb (WEBrick::HTTPServlet::FileHandler#check_filename): :NondisclosureName is acceptable if it is Enumerable. * lib/webrick/config.rb (WEBrick::Config::FileHandler): default value of :NondisclosureName is [".ht*", "*~"]. Thu Dec 16 18:36:52 2004 GOTOU Yuuzou * ext/openssl/ossl.c (ossl_raise): refine message format. Thu Dec 16 16:29:44 2004 Hidetoshi NAGAI * ext/tk/sample/demos-en/widget: modify version check for supporting features Thu Dec 16 16:03:50 2004 Hidetoshi NAGAI * ext/tk/lib/tk/bindtag.rb: bug fix [ruby-talk: 123667] * ext/tk/lib/tk/timer.rb: accept :idle for the interval argument * ext/tk/lib/tk.rb: add TkComm._callback_entry?() * ext/tk/lib/multi-tk.rb: add MultiTkIp.cb_entry_class * ext/tk/lib/tk/canvas.rb: use TkComm._callback_entry?() * ext/tk/lib/tk/canvastag.rb: ditto * ext/tk/lib/tk/dialog.rb: ditto * ext/tk/lib/tk/optiondb.rb: ditto * ext/tk/lib/tk/text.rb: ditto * ext/tk/lib/tk/texttag.rb: ditto * ext/tk/lib/tk/textwindow.rb: ditto * ext/tk/lib/tk/timer.rb: ditto * ext/tk/lib/tk/validation.rb: ditto * ext/tk/lib/tkextlib/*: ditto Thu Dec 16 03:14:28 2004 Minero Aoki * lib/net/http.rb (basic_encode): return value of pack('m') may include multiple CR/LFs. Backported from main trunk (rev 1.112). [ruby-dev:25212] Thu Dec 16 00:33:37 2004 Yukihiro Matsumoto * hash.c (Init_Hash): remove custom "hash" and "eql?". Wed Dec 15 18:57:01 2004 Yukihiro Matsumoto * lib/set.rb (Set::eql): wrong definition. [ruby-dev:25207] Wed Dec 15 18:48:42 2004 Shugo Maeda * ext/curses/curses.c (window_subwin): call NUM2INT() before GetWINDOW(). (backported from CVS HEAD) Wed Dec 15 17:03:50 2004 NAKAMURA Usaku * win32/win32.[ch] (rb_w32_isatty): new function to replace MSVCRT's isatty because it never sets errno. (backported from CVS HEAD) Wed Dec 15 15:39:32 2004 GOTOU Yuuzou * ext/openssl/ossl_x509name.c (ossl_x509name_to_a): avoid SEGV (rollback the previous commit). Wed Dec 15 16:10:23 2004 Yukihiro Matsumoto * object.c (rb_obj_id_obsolete): warn always. * eval.c (rb_enable_super): ditto. Wed Dec 15 15:31:02 2004 Yukihiro Matsumoto * lib/set.rb (Set#==): [ruby-dev:25206] Wed Dec 15 14:22:10 2004 NAKAMURA Usaku * win32/win32.c (rb_w32_fdisset): check whether the handle is valid. fixed: [ruby-core:03959] Wed Dec 15 10:30:37 2004 Yukihiro Matsumoto * ext/openssl/ossl_digest.c (ossl_digest_initialize): [ruby-dev:25198] Tue Dec 14 17:10:09 2004 NAKAMURA Usaku * win32/win32.c (rb_w32_close): need to reset osfhnd(). Tue Dec 14 14:03:57 2004 GOTOU Yuuzou * ext/openssl/ossl.c (ossl_raise): avoid buffer overrun. [ruby-dev:25187] Tue Dec 14 12:36:04 2004 Yukihiro Matsumoto * lib/cgi/session.rb (CGI::Session::initialize): generate new session if given session_id does not exist. [ruby-list:40368] Mon Dec 13 18:13:52 2004 Tanaka Akira * gc.c (stack_end_address): new function to obtain stack end address. stack_end_address calls __builtin_frame_address(0) to obtain the frame pointer of a stack frame of stack_end_address. The address is the stack pointer of the caller's stack frame. (SET_STACK_END): use stack_end_address. This makes the conservative garbage collector to scan a stack frame of the garbage_collect function itself. This is required because callee-save registers may be stored in the frame. [ruby-dev:25158] Mon Dec 13 00:58:02 2004 Tanaka Akira * lib/pathname.rb (cleanpath_aggressive): make it private. (cleanpath_conservative): ditto. Suggested by Daniel Berger. [ruby-core:3914] Sun Dec 12 20:06:38 2004 Masatoshi SEKI * lib/drb/drb.rb: backported from CVS HEAD. Sun Dec 12 10:35:10 2004 Dave Thomas * lib/rdoc/generators/template/html/html.rb (RDoc::Page): Don't show an accessor's r/w flag if none was specified Sun Dec 12 10:14:03 2004 Dave Thomas * lib/rdoc/rdoc.rb (RDoc::RDoc::parse_files): Never exclude files explicitly given on the command line. Sun Dec 11 23:54:07 2005 Hidetoshi NAGAI * ext/tk/*: update to support libraries in ActiveTcl8.4.12.0 (see ext/tk/ChangeLog.tkextlib). * ext/tk/sample/scrollframe.rb: add a new sample. Sat Dec 11 20:12:21 2004 Masatoshi SEKI * lib/drb/drb.rb: add DRbRemoteError. [ruby-list:40348], [ruby-list:40390] * test/drb/drbtest.rb: ditto. * test/drb/ut_drb.rb: ditto. Sat Dec 11 15:38:14 2004 Yukihiro Matsumoto * lib/jcode.rb (String::succ): [ruby-dev:25156] Sat Dec 11 12:41:55 2004 NAKAMURA Usaku * eval.c (run_trap_eval): prototype; avoid VC++ warnings. * ext/socket/getaddrinfo.c: fix typo. fixed: [ruby-core:03947] * win32/win32.c: need to include dln.h. Sat Dec 11 00:10:18 2004 Yukihiro Matsumoto * io.c (io_reopen): [ruby-dev:25150] Fri Dec 10 08:39:27 2004 Nobuyoshi Nakada * ext/socket/socket.c (sock_listen): get OpenFile just before calling listen(2). fixed: [ruby-dev:25149] Thu Dec 9 17:00:00 2004 Akiyoshi, Masamichi * ext/socket/socket.c, ext/socket/getaddrinfo.c: port to VMS Thu Dec 9 16:31:02 2004 NAKAMURA Usaku * ext/sdbm/init.c (GetDBM): typo. Thu Dec 9 16:05:00 2004 Akiyoshi, Masamichi * defines.h: change path of vms.h * vms/vms.h: delete reference for snprintf() * vms/config.h: new file * vms/config.h_in: deleted Thu Dec 9 14:38:35 2004 Nobuyoshi Nakada * string.c (rb_str_inspect): escape # which starts an expression substitution. fixed: [ruby-core:03922] * string.c (rb_str_dump): not escape # which isn't a substitution. Thu Dec 9 10:54:36 2004 Yukihiro Matsumoto * ext/dbm/dbm.c (fdbm_select): [ruby-dev:25132] * ext/sdbm/init.c: ditto. * ext/gdbm/gdbm.c: ditto. Thu Dec 9 03:08:36 2004 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (ip_init): set root-win title to "ruby" when the running script is '-e one-liner' or '-' (stdin). * ext/tcltklib/extconf.rb: add find_library("#{lib}#{ver}",..) for stub libs * ext/tk/lib/tk/textmark.rb: TkTextMarkCurrent and TkTextMarkAnchor have a wrong parent class. * ext/tk/lib/tk/dialog.rb: rename TkDialog2 --> TkDialogObj and TkWarning2 --> TkWarningObj (old names are changed to alias names) * ext/tk/lib/tk/dialog.rb: bug fix of treatment of 'prev_command' option and hashes for configuration * ext/tk/lib/tk/dialog.rb: add TkDialogObj#name to return the button name * ext/tk/lib/tk/radiobutton.rb: rename enbugged method value() ==> get_value() and value=(val) ==> set_value(val). * ext/tk/lib/tk/menu.rb: add TkMenu.new_menuspec * ext/tk/lib/tk/menu.rb: add alias (TkMenuButton = TkMenubutton, TkOptionMenuButton = TkOptionMenubutton) * ext/tk/lib/tk/event.rb: new method aliases (same as option keys of event_generate) for Event object * ext/tk/lib/tk/font.rb: configinfo returns proper types of values * ext/tk/lib/tk.rb: bind methods accept subst_args + block * ext/tk/lib/tk/canvas.rb: ditto * ext/tk/lib/tk/canvastag.rb: ditto * ext/tk/lib/tk/frame.rb: ditto * ext/tk/lib/tk/text.rb: ditto * ext/tk/lib/tk/texttag.rb: ditto * ext/tk/lib/tk/toplevel.rb: ditto * ext/tk/lib/tkextlib/*: ditto and bug fix Wed Dec 8 23:54:29 2004 Dave Thomas * lib/rdoc/generators/template/html/html.rb (RDoc::Page): Typo meant that h2 tag was invisible. Wed Dec 8 21:56:31 2004 Kouhei Sutou * lib/rss, test/rss, sample/rss: backported from CVS HEAD. Wed Dec 8 14:31:36 2004 Yukihiro Matsumoto * io.c (io_fwrite): change dereference for cosmetic reason. * sprintf.c (rb_f_sprintf): [ruby-dev:25104] Tue Dec 7 19:08:00 2004 Akiyoshi, Masamichi * io.c (io_fwrite): fix offset incrementation (for VMS and Human68k) Tue Dec 7 00:27:37 2004 Yukihiro Matsumoto * process.c (proc_setgroups): [ruby-dev:25081] Mon Dec 6 18:08:10 2004 Yukihiro Matsumoto * re.c (rb_reg_eqq): document fix. [ruby-talk:122541] Mon Dec 6 17:19:13 2004 Nobuyoshi Nakada * rubysig.h (TRAP_BEG, TRAP_END): safe errno around CHECK_INTS. (backported from CVS HEAD) [ruby-dev:24993] Mon Dec 6 10:18:17 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::look_for_directives_in): Oops - 1.8 doesn't have String#clear Mon Dec 6 09:59:23 2004 Yukihiro Matsumoto * ext/socket/socket.c (sock_connect): use rb_str_new4(). [ruby-dev:25052] Mon Dec 6 01:42:08 2004 GOTOU Yuuzou * ext/openssl/ossl_pkey_rsa.c (ossl_rsa_public_encrypt, ossl_rsa_public_decrypt, ossl_rsa_private_encrypt, ossl_rsa_private_decrypt): should take an optional argument to specify padding mode. [ruby-talk:122539] * ext/openssl/ossl_pkey_rsa.c (Init_ossl_rsa): add new constants PKCS1_PADDING, SSLV23_PADDING, NO_PADDING and PKCS1_OAEP_PADDING under OpenSSL::PKey::RSA. * test/openssl/test_pkey_rsa.rb: new file. Sun Dec 5 19:39:17 2004 Nobuyoshi Nakada * lib/optparse.rb (OptionParser::Completion#complete): new parameter to direct case insensitiveness. * lib/optparse.rb (OptionParser#order!): ignore case only for long option. [ruby-dev:25048] Sat Dec 4 22:54:15 2004 Yukihiro Matsumoto * io.c (io_write): remove rb_str_locktmp(). [ruby-dev:25050] * io.c (io_fwrite): takes VALUE string as an argument. [ruby-dev:25050] * ext/socket/socket.c (sock_connect): remove rb_str_locktmp(). [ruby-dev:25050] * ext/socket/socket.c (udp_connect): [ruby-dev:25045] * ext/socket/socket.c (udp_bind): ditto. * ext/socket/socket.c (udp_send): ditto. * ext/socket/socket.c (bsock_send): ditto. * ext/socket/socket.c (s_recvfrom): ditto. * hash.c (rb_hash_hash): should provide "hash" method where "eql?" is redefined. [ruby-talk:122482] Sat Dec 4 14:54:52 2004 WATANABE Hirofumi * eval.c (proc_invoke): use volatile `tmp' rather than `args'. [ruby-core:03882] Sat Dec 4 14:28:56 2004 Dave Thomas * lib/rdoc/code_objects.rb (RDoc::Context::Section::set_comment): Section comments may now be bracketed by lines which are ignored. You can now write # ----------- # :section: Dave's Section # comment material # ----------- The lines before :section: are removed, and identical lines at the end are also removed if present. Sat Dec 4 03:33:45 2004 Shugo Maeda * ext/readline/readline.c: check $SAFE. (backported from CVS HEAD) * test/readline/test_readline.rb: added tests for readline. (backported from CVS HEAD) Sat Dec 4 02:24:00 2004 NARUSE, Yui * ext/nkf/nkf.c: add constant NKF::VERSION * ext/nkf/nkf.c(guess): this becomes an alias of guess2 * ext/nkf/test.rb(mime_out2): add --no-cp932 * ext/nkf/nkf-utf8/nkf.c: original nkf2 revision 1.47 Sat Dec 4 00:35:08 2004 Yukihiro Matsumoto * ext/socket/socket.c (bsock_setsockopt): [ruby-dev:25039] Fri Dec 3 18:57:03 2004 Yukihiro Matsumoto * lib/ostruct.rb: 1.9 marshaling support back-ported. [ruby-core:03871] Fri Dec 3 13:45:20 2004 Yukihiro Matsumoto * eval.c (proc_invoke): copy arguments to frame.argv. [ruby-core:03861] Fri Dec 3 12:25:41 2004 Nobuyoshi Nakada * st.h: fix prototypes. Fri Dec 3 00:21:05 2004 Yukihiro Matsumoto * object.c (convert_type): use rb_respond_to() again. [ruby-dev:25021] * eval.c (rb_respond_to): funcall respond_to? if it's redefined. [ruby-dev:25021] Fri Dec 3 01:55:24 2004 Hidetoshi NAGAI * ext/tk/lib/tk.rb: widget configuration by TkWindow#method_missing returns proper object. "widget.option = val" returns val, and "widget.option(val)" returns self. * ext/tk/lib/tk/font.rb: TkFont#replace accepts only one font argument. * ext/tk/lib/tk/radiobutton.rb: add TkRadiobutton#value and TkRadiobutton#value=(val). * ext/tk/lib/tk/spinbox.rb: callback substitution support on command option. * ext/tk/sample/demos-en/widget: bug fix (wrong image height) * ext/tk/sample/demos-jp/widget: ditto. Fri Dec 3 00:11:48 2004 Yukihiro Matsumoto * io.c (rb_file_initialize): [ruby-dev:25032] Thu Dec 2 16:41:03 2004 Nobuyoshi Nakada * eval.c (rb_protect): prevent continuations created inside from being called from the outside. [ruby-dev:25003] * eval.c (rb_callcc, rb_cont_call): prohibit calling from different signal contexts. [ruby-dev:25022] Thu Dec 2 09:57:24 2004 Yukihiro Matsumoto * lib/ostruct.rb (OpenStruct::Marshaler): OpenStruct can be marshaled again. [ruby-core:03862] Thu Dec 2 09:30:06 2004 Nobuyoshi Nakada * eval.c (thread_mark): mark thread group. [ruby-dev:25020] * eval.c (thgroup_add): check whether the argument is really a Thread. Thu Dec 2 07:57:16 2004 Yukihiro Matsumoto * io.c (rb_io_ctl): [ruby-dev:25019] Wed Dec 1 02:21:02 2004 Yukihiro Matsumoto * signal.c (sighandler): call handler immediately only for default handlers. [ruby-dev:25003] Tue Nov 30 23:38:18 2004 Nobuyoshi Nakada * io.c (io_fread): need not to null terminate. [ruby-dev:24998] * io.c (read_all): remove unnecessary rb_str_resize(). [ruby-dev:24996] (backported from CVS HEAD) * io.c (io_readpartial): ditto. * io.c (io_read): ditto. Tue Nov 30 16:18:50 2004 Yukihiro Matsumoto * io.c (io_fread): need not to null terminate. [ruby-dev:24998] * io.c (read_all): remove unnecessary rb_str_resize(). [ruby-dev:24996] * io.c (io_read): ditto. Tue Nov 30 00:49:08 2004 Yukihiro Matsumoto * io.c (rb_io_sysread): use temporary lock. [ruby-dev:24992] Mon Nov 29 16:06:04 2004 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_write): insufficiently filled string being extended when overwriting. [ruby-core:03836] Mon Nov 29 15:59:05 2004 Yukihiro Matsumoto * lib/ostruct.rb (OpenStruct::method_missing): check method duplication for -d. * lib/ostruct.rb (OpenStruct::initialize): ditto. Mon Nov 29 15:22:28 2004 Nobuyoshi Nakada * test/io/nonblock/test_flush.rb: abandon tests when io/nonblock is not supported. Mon Nov 29 03:08:30 2004 Yukihiro Matsumoto * object.c (convert_type): direct call conversion methods for the performance. [ruby-core:03845] * eval.c (rb_funcall_rescue): new function. * object.c (rb_Array): avoid using rb_respond_to(). * object.c (rb_Integer): ditto. * parse.y (reduce_nodes): empty body should return nil. * string.c (rb_str_aset): the original string should not be affected by modifying duplicated string. [ruby-dev:24981] Mon Nov 29 13:57:38 2004 NAKAMURA Usaku * win32/win32.c (CreateChild): search executable file if no program name given. (backported from CVS HEAD) Mon Nov 29 13:37:54 2004 Nobuyoshi Nakada * io.c (fptr_finalize): must not use FILE after fclose(). [ruby-dev:24985] Mon Nov 29 13:16:31 2004 NAKAMURA Usaku * win32/win32.c (CreateChild): push back the last space before next loop because CharNext() eats it. Mon Nov 29 01:18:18 2004 Tanaka Akira * io.c (rb_io_check_writable): call io_seek regardless of NEED_IO_SEEK_BETWEEN_RW. [ruby-dev:24986] Sat Nov 27 21:43:39 2004 Tanaka Akira * io.c: avoid data lost with nonblocking fd and stdio buffering in sync mode. [ruby-dev:24966] based on matz's patch [ruby-dev:24967] (io_fwrite): new primitive writing function which writes directly if sync mode. (rb_io_fwrite): wrapper for io_fwrite now. (io_write): call io_fwrite instead of rb_io_fwrite. Sat Nov 27 14:44:15 2004 Kent Sibilev * lib/cgi/session.rb (CGI::Session::initialize): create_new_id is now a instance method. [ruby-core:03832] Sat Nov 27 09:41:21 2004 Yukihiro Matsumoto * io.c (io_fread): old rb_io_fread with file closing checking. (rb_io_fread): wrapper for io_fread now. [ruby-dev:24964] Fri Nov 26 18:02:44 2004 Hidetoshi NAGAI * ext/tk/lib/tk.rb: Tk.destroy uses TkWindow#epath * ext/tk/lib/tk/image.rb: bug fix * ext/tk/lib/tk/wm.rb: add 'iconphoto' method(Windows only) * ext/tk/lib/tkextlib/*: some methods uses TkWindow#epath Fri Nov 26 13:49:06 2004 Yukihiro Matsumoto * eval.c (method_missing): raise TypeError for classes do not have allocators. [ruby-core:03752] * lib/erb.rb: add RDoc by James Edward Gray II. [ruby-core:03786] Fri Nov 26 13:29:02 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::look_for_directives_in): Break out of preprocessing when we find a :section: directive (previously cleared out the comment, but this apparently now generates an error in gsub!) Fri Nov 26 00:17:40 2004 Yukihiro Matsumoto * io.c (io_read): move StringValue() check before GetOpenFile(). [ruby-dev:24959] Thu Nov 25 20:14:57 2004 Nobuyoshi Nakada * lib/thwait.rb (ThreadsWait#join_nowait): abnormally terminated threads should be also processed. [ruby-talk:121320] Thu Nov 25 10:14:26 2004 Nobuyoshi Nakada * dir.c (push_braces): do not reuse buffer strings. [ruby-core:03806] Thu Nov 25 07:59:41 2004 Yukihiro Matsumoto * io.c (read_all): stringify non-nil buffer argument, and always taint the result. [ruby-dev:24955] Wed Nov 24 01:01:31 2004 Yukihiro Matsumoto * io.c (io_read): integer conversion should be prior to GetOpenFile(). [ruby-dev:24952] * configure.in, io.c: cancel [ ruby-Patches-1074 ]. Tue Nov 23 08:09:50 2004 Hidetoshi NAGAI * ext/tk/lib/tk/menu.rb: improve usability of TkOptionMenubutton Tue Nov 23 02:00:21 2004 Yukihiro Matsumoto * file.c (rb_file_chown): integer conversion should be prior to GetOpenFile(). [ruby-dev:24949] Tue Nov 23 00:10:48 2004 Yukihiro Matsumoto * file.c (rb_file_chown): integer conversion should be prior to GetOpenFile(). [ruby-dev:24947] * file.c (rb_file_truncate): ditto. * file.c (rb_file_s_truncate): ditto. * dir.c (dir_seek): use NUM2OFFT(). * misc/ruby-mode.el (ruby-non-block-do-re): should not match words start with block keyword and underscore. [ruby-core:03719] Mon Nov 22 22:33:02 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RDoc::parse_require): Don't use names of variables or constants when oarsing 'require' Mon Nov 22 00:13:35 2004 Yukihiro Matsumoto * dir.c (dir_seek): should retrieve dir_data after NUM2INT(). [ruby-dev:24941] Sat Nov 20 23:57:33 2004 Dave Thomas * lib/rdoc/README (et al): Add a new directive, :section:, and change the output format to accomodate. :section: allows to to group together methods, attributes, constants, etc under headings in the output. If used, a table of contents is generated. Sat Nov 20 23:56:54 2004 Dave Thomas * lib/rdoc/options.rb (Options::parse): Force --inline-source if --one-file option given Sat Nov 20 23:55:19 2004 Yukihiro Matsumoto * string.c (rb_str_splice): should place index wrapping after possible modification. [ruby-dev:24940] Sat Nov 20 13:26:03 2004 NARUSE, Yui * ext/nkf/nkf-utf8/utf8tbl.c: original revision 1.7 Sat Nov 20 05:34:24 2004 NARUSE, Yui * ext/nkf/nkf-utf8/nkf.c: original nkf.c rev:1.40 * ext/nkf/test.rb: add test for mime encode/decode Sat Nov 20 01:37:34 2004 Johan Holmberg * eval.c (error_print): nicer traceback at interrupt. [ruby-core:03774] Sat Nov 20 00:07:16 2004 Yukihiro Matsumoto * string.c (str_gsub): internal buffer should not be listed by ObjectSpace.each_object() by String#gsub. [ruby-dev:24931] Fri Nov 19 01:20:22 2004 Yukihiro Matsumoto * lib/cgi/session.rb (CGI::Session::FileStore::initialize): raise exception if data corresponding to session specified from the client does not exist. Fri Nov 19 00:59:31 2004 Yukihiro Matsumoto * string.c (str_gsub): internal buffer should not be listed by ObjectSpace.each_object(). [ruby-dev:24919] Thu Nov 18 18:41:08 2004 Kazuhiro NISHIYAMA * test/ruby/test_stringchar.rb (test_bang): added. * string.c (rb_str_upcase_bang, rb_str_capitalize_bang) (rb_str_swapcase_bang): missing rb_str_modify(). [ruby-dev:24915] Thu Nov 18 00:21:15 2004 Yukihiro Matsumoto * process.c (proc_getpgrp): prohibit for $SAFE=2. [ruby-dev:24899] * process.c (get_pid): ditto. [ruby-dev:24904] * process.c (get_ppid): ditto. * array.c (rb_ary_delete): defer rb_ary_modify() until actual modification. [ruby-dev:24901] Thu Nov 18 10:10:14 2004 Nobuyoshi Nakada * io.c, rubyio.h (rb_io_modenum_flags): exported. * ext/stringio/stringio.c (strio_initialize): allow Fixnum as mode as well as IO.new does. [ruby-dev:24896] Wed Nov 17 23:42:40 2004 NAKAMURA, Hiroshi * test/ruby/test_settracefunc.rb: added. [ruby-dev:24884] Wed Nov 17 13:56:57 2004 Yukihiro Matsumoto * parse.y (newline_node): should not use FL_SET. [ruby-dev:24874] * parse.y (string_content): should not use FL_UNSET. * node.h (NODE_NEWLINE): remove unused bit to utilize flag field in nodes. Wed Nov 17 13:09:40 2004 NAKAMURA Usaku * {bcc32,win32,wince}/Makefile.sub (test): should build ruby.exe before running test. [ruby-core:03756] Wed Nov 17 04:33:01 2004 GOTOU Yuuzou * pack.c: all features are backport from 1.9. [ruby-dev:24826] * bignum.c (rb_big2ulong_pack): new function to pack Bignums. Wed Nov 17 03:42:45 2004 Yukihiro Matsumoto * string.c (rb_str_splice): move rb_str_modify() after StringValue(), which may alter the receiver. [ruby-dev:24878] Tue Nov 16 23:45:07 2004 Yukihiro Matsumoto * numeric.c (flo_divmod): protect float values from GC by assignment to local variables. [ruby-dev:24873] Tue Nov 16 16:30:21 2004 NAKAMURA Usaku * {bcc32,win32,wince}/setup.mak (-epilogue-): remove config.h and config.status to force updating them. Tue Nov 16 16:20:45 2004 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_read): position was ignored when a buffer was passed. http://www.yo.rim.or.jp/~nov/d/?date=20041116#p03 Tue Nov 16 11:19:07 2004 Nobuyoshi Nakada * lib/test/unit/autorunner.rb (Test::Unit::AutoRunner::options): use Regexp conversion. Tue Nov 16 01:41:31 2004 Yukihiro Matsumoto * string.c (str_mod_check): frozen check should be separated. [ruby-core:3742] * array.c (rb_ary_update): pedantic check to detect rb_ary_to_ary() to modify the receiver. [ruby-dev:24861] Mon Nov 15 13:50:52 2004 Yukihiro Matsumoto * string.c (rb_str_justify): typo fixed. [ruby-dev:24851] Mon Nov 15 11:50:32 2004 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-special-char-p, ruby-parse-partial): handle operator symbols. [ruby-talk:120177] Sun Nov 14 13:27:03 2004 Nobuyoshi Nakada * lib/pp.rb (PP#object_address_group): remove odd number of 'f' prefixed to negative address. Sun Nov 14 08:51:04 2004 NAKAMURA, Hiroshi * test/logger/test_logger.rb: Logger just expects Logger#datetime_format to be used for Time#strftime independently of locale. [ruby-dev:24828] Fri Nov 12 15:03:26 2004 NAKAMURA Usaku * eval.c (ruby_options): now we cannot call rb_glob() before ruby_init(), so call rb_w32_cmdvector() at ruby_options(). * win32.{c,h} (rb_w32_cmdvector): rename make_cmdvector() and export it. Fri Nov 12 14:08:01 2004 Hidetoshi NAGAI * ext/tk/lib/tk/event.rb: remove $LOADED_FEATURES trick * ext/tk/lib/tk.rb: ditto Fri Nov 12 00:31:05 2004 Yukihiro Matsumoto * ext/gdbm/gdbm.c (fgdbm_store): StringValue() may alter string pointer. [ruby-dev:24783] Thu Nov 11 17:36:12 2004 Nobuyoshi Nakada * dir.c (rb_globi): also should call back via rb_glob_caller(). [ruby-dev:24775] Thu Nov 11 16:47:21 2004 NAKAMURA Usaku * test/ruby/test_file.rb (test_truncate_wbuf): we want to test only File#truncate, not behaviour of seek(2). Thu Nov 11 09:41:01 2004 Yukihiro Matsumoto * dir.c (push_braces): was confusing VALUE and char*. * dir.c (rb_push_glob): Dir.glob should have called its block. Thu Nov 11 01:52:52 2004 Nobuyoshi Nakada * error.c (syserr_initialize): use stringified object. [ruby-dev:24768] Wed Nov 10 22:49:01 2004 Yukihiro Matsumoto * lib/delegate.rb (SimpleDelegator::dup): wrong number of arguments. * lib/delegate.rb (DelegateClass::dup): ditto. Wed Nov 10 12:31:21 2004 Nobuyoshi Nakada * README.EXT (Example): extconf.rb is indispensable now. Wed Nov 10 03:33:36 2004 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: fix SEGV when compiled with Tcl/Tk8.3.x or older * ext/tk/lib/tkextlib/tile/style.rb: bug fix Tue Nov 9 14:27:18 2004 Nobuyoshi Nakada * lib/optparse.rb (OptionParser::Officious): moved from DefaultList. Tue Nov 9 01:05:04 2004 Yukihiro Matsumoto * dir.c (rb_glob2): do not allocate buffer from heap to avoid memory leaks. use string object for buffering instead. [ruby-dev:24738] * dir.c (join_path): ditto. * io.c (io_read): external input buffer may be modified even after rb_str_locktmp(). [ruby-dev:24735] * dir.c (fnmatch): p or s may be NULL. [ruby-dev:24749] Tue Nov 9 00:53:53 2004 WATANABE Hirofumi * regex.c (slow_match): avoid GCC 3.4.x warnings. Tue Nov 9 00:50:06 2004 Dave Thomas * lib/rdoc/rdoc.rb: Change version numbering of RDoc and ri Mon Nov 8 23:38:35 2004 Masatoshi SEKI * lib/drb/extservm.rb: add DRb::ExtServManager#uri=. [ruby-dev:24743] Mon Nov 8 22:20:19 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_class): Fix bug where parent class wasn't being detected if the child class was defined using the A::B notation. Mon Nov 8 00:14:13 2004 WATANABE Hirofumi * configure.in: add setup for mignw32 cross compiling. [ruby-talk:119413] Sun Nov 7 23:49:26 2004 Hidetoshi NAGAI * ext/tk/lib/tk.rb: bind-event methods accept multi substitution arguments. * ext/tk/lib/tk/canvas.rb: ditto. * ext/tk/lib/tk/canvastag.rb: ditto. * ext/tk/lib/tk/text.rb: ditto. * ext/tk/lib/tk/texttag.rb: ditto. * ext/tk/lib/tkextlib: ditto. Sat Nov 6 14:58:44 2004 GOTOU Yuuzou * lib/webrick/server.rb (WEBrick::HTTPServer#start): remove :DoNotReverseLookup option. (Socket#do_not_reverse_lookup is a ruby 1.9 feature) Sat Nov 6 11:31:04 2004 Tadayoshi Funaba * lib/date.rb (_parse): checks whether zone was given. Sat Nov 6 00:46:27 2004 Yukihiro Matsumoto * string.c (rb_str_locktmp): check STR_TMPLOCK flag before locking. [ruby-dev:24727] Fri Nov 5 18:12:42 2004 Hidetoshi NAGAI * ext/tk/lib/tk/scrollable.rb: divide Scrollable module into X_Scrollable and Y_Scrollable * ext/tk/lib/tk/entry.rb: include X_Scrollable instead of Scrollable * ext/tk/lib/tk/autoload.rb: define autoload for X_Scrollable and Y_Scrollable Fri Nov 5 16:05:32 2004 Hidetoshi NAGAI * ext/tk/lib/tk.rb: TkComm._at() supprts both of "@x,y" and "@x" Fri Nov 5 13:22:58 2004 Hidetoshi NAGAI * ext/tk/lib/tk/text.rb: sorry. bug fix again. Fri Nov 5 13:17:54 2004 Hidetoshi NAGAI * ext/tk/lib/tk/text.rb: bug fix Fri Nov 5 08:52:48 2004 Yukihiro Matsumoto * gc.c (gc_mark): stricter GC stack check. Fri Nov 5 08:52:48 2004 Yukihiro Matsumoto * gc.c (gc_mark): stricter GC stack check. Fri Nov 5 08:34:43 2004 Yukihiro Matsumoto * string.c (str_gsub): should have removed rb_str_unlocktmp(str). [ruby-dev:24708] Thu Nov 4 21:25:38 2004 Yukihiro Matsumoto * string.c (str_gsub): string modify check no longer based on tmplock. [ruby-dev:24706] Thu Nov 4 19:27:46 2004 NAKAMURA Usaku * io.c (rb_f_open): fix typo. Thu Nov 4 15:02:14 2004 Hidetoshi NAGAI * ext/tk/lib/tk/variable.rb: forget to initialize instance_variables of TkVarAccess objects Thu Nov 4 09:11:35 2004 Yukihiro Matsumoto * gc.c (gc_mark): enable GC stack checking. Thu Nov 4 03:11:33 2004 Yukihiro Matsumoto * string.c (str_gsub): lock strings temporarily. [ruby-dev:24687] * ext/socket/socket.c (s_recvfrom): tmplock input buffer. [ruby-dev:24705] Wed Nov 3 22:32:12 2004 NARUSE, Yui * process.c: On NetBSD don't use setruid() and setrgid(). Wed Nov 3 22:24:17 2004 Daigo Moriwaki * lib/webrick/httpauth/digestauth.rb: use Base64.encode64 to avoid warnings. Wed Nov 3 17:19:59 2004 Yukihiro Matsumoto * array.c (rb_ary_uniq_bang): do not push frozen string from hash table. [ruby-dev:24695] * array.c (rb_ary_and): ditto. * array.c (rb_ary_or): ditto. Wed Nov 3 17:13:02 2004 Hidetoshi NAGAI * io.c (pipe_open): fix compile error Wed Nov 3 16:58:07 2004 Hidetoshi NAGAI * ext/tk/lib/tk.rb: support to use different Tcl commands between configure and configinfo * ext/tk/lib/font.rb: ditto. * ext/tk/lib/itemconfig.rb: support to use different Tcl commands between item_configure and item_configinfo * ext/tk/lib/itemfont.rb: ditto. * ext/tk/extconf.rb: install SUPPORT_STATUS * ext/tk/lib/tkextlib: some bug fixes (see ext/tk/ChangeLog.tkextlib) Wed Nov 3 16:30:41 2004 NARUSE, Yui * ext/nkf: follow nkf 2.0.4 Wed Nov 3 15:53:34 2004 Kouhei Sutou * test/rss/test_maker_*.rb: added tests for RSS Maker. * lib/rss/maker.rb: added RSS Maker. * lib/rss/maker/*.rb: ditto. Tue Nov 2 16:35:57 2004 Yukihiro Matsumoto * ext/enumerator/enumerator.c (each_cons_i): pass copy of an internal consequent array. [ruby-talk:118691] Tue Nov 2 16:05:21 2004 Yukihiro Matsumoto * process.c (rb_f_fork): need to flush stdout and stderr before fork(2). [ruby-talk:117715] Tue Nov 2 01:20:09 2004 Yukihiro Matsumoto * eval.c (proc_invoke): nail down dyna_var node when Proc object or continuation is created. [ruby-dev:24671] Mon Nov 1 13:59:28 2004 WATANABE Hirofumi * ext/extmk.rb (MANIFEST): do not use anymore, use extconf.rb instead. * ext/enumerator/extconf.rb, ext/fcntl/extconf.rb, ext/stringio/extconf.rb: added. * MANIFEST, ext/**/MANIFEST: removed. * README.EXT, README.EXT.ja: remove MANIFEST stuff. Mon Nov 1 01:14:52 2004 Yukihiro Matsumoto * io.c (rb_f_open): create copy of popen specifier. [ruby-dev:24656] Mon Nov 1 00:36:48 2004 WATANABE Hirofumi * main.c (_stklen): move to gc.c. Sun Oct 31 00:22:28 2004 Yukihiro Matsumoto * string.c (rb_str_locktmp): lock string temporarily. * string.c (str_independent): add tmplock check. * io.c (io_write): lock output string temporarily. [ruby-dev:24649] * io.c (io_write): use rb_str_locktmp(). * io.c (read_all): ditto. Sat Oct 30 06:53:24 2004 Peter Vanbroekhoven * eval.c (rb_eval): NODE_XSTR should pass copy of literal string. Sat Oct 30 00:19:40 2004 Yukihiro Matsumoto * enum.c (enum_sort_by): protect continuation jump in. [ruby-dev:24642] Fri Oct 29 21:27:51 2004 Nobuyoshi Nakada * io.c (rb_io_check_initialized): new function to check uninitialized object. [ruby-talk:118234] * file.c (rb_file_path), io.c (rb_io_closed): check if initialized. Fri Oct 29 10:00:30 2004 Yukihiro Matsumoto * eval.c (rb_thread_start_0): forget to free some memory chunks. [ruby-core:03611] * eval.c (ruby_cleanup): ruby_finalize_1 may cause exception, should be wrapped by PUSH_TAG/POP_TAG(). [ruby-dev:24627] Thu Oct 28 08:42:02 2004 Tanaka Akira * io.c (argf_forward): use ANSI style. (argf_read): call argf_forward with argv argument. [ruby-dev:24624] Thu Oct 28 23:32:54 2004 akira yamada * ext/zlib/zlib.c (zstream_detach_input): resets klass of z->input if z->input isn't nil. Thu Oct 28 23:19:31 2004 Nobuyoshi Nakada * ext/extmk.rb: prefer relative path. [ruby-talk:93037] Wed Oct 27 18:49:11 2004 NAKAMURA Usaku * gc.c: prototype; rb_io_fptr_finalize() doesn't return any value at this version. Wed Oct 27 17:27:45 2004 Yukihiro Matsumoto * gc.c (gc_sweep): recover ruby_in_compile variable. Wed Oct 27 09:17:30 2004 Nobuyoshi Nakada * string.c (str_gsub): use a string object for exception safeness. [ruby-dev:24601] Tue Oct 26 23:52:32 2004 Nobuyoshi Nakada * io.c (rb_io_getline): rs modification check should not interfere in the loop. Tue Oct 26 23:30:39 2004 Dave Thomas * lib/rdoc/code_objects.rb (RDoc::Context::add_class_or_module): Restore correct :nopdoc: behavior with nested classes and modules. Tue Oct 26 18:21:29 2004 Yukihiro Matsumoto * string.c (RESIZE_CAPA): check string attribute before modifying capacity member of string structure. [ruby-dev:24594] Tue Oct 26 11:33:26 2004 David G. Andersen * ext/zlib/zlib.c (gzreader_gets): use memchr() to to gain performance. [ruby-talk:117701] Tue Oct 26 10:56:55 2004 Yukihiro Matsumoto * sprintf.c (rb_f_sprintf): raise ArgumentError for extra arguments, unless (digit)$ style used. Tue Oct 26 11:33:26 2004 David G. Andersen * ext/zlib/zlib.c (gzreader_gets): use memchr() to to gain performance. [ruby-talk:117701] Tue Oct 26 10:56:55 2004 Yukihiro Matsumoto * sprintf.c (rb_f_sprintf): raise ArgumentError for extra arguments, unless (digit)$ style used. Mon Oct 25 18:35:39 2004 WATANABE Hirofumi * win32/win32.c (isUNCRoot): should check NUL after '.'. [ruby-dev:24590] * win32/win32.c (isUNCRoot): fixed buffer overrun. Mon Oct 25 08:03:26 2004 Nobuyoshi Nakada * eval.c (get_backtrace): ignore illegal backtrace. [ruby-dev:24587] Sun Oct 24 00:41:09 2004 Nobuyoshi Nakada * eval.c (rb_load, search_required, rb_require_safe, rb_require): use frozen shared string to avoid outside modification. [ruby-dev:24580] Sat Oct 23 22:18:32 2004 Guy Decoux * eval.c (frame_free): Guy Decoux solved the leak problem. Thanks. [ruby-core:03549] Sat Oct 23 00:20:55 2004 Yukihiro Matsumoto * ext/zlib/zlib.c (zstream_append_input): clear klass for z->input to avoid potential vulnerability. * ext/zlib/zlib.c (zstream_run): always use zstream_append_input() to avoid SEGV. [ruby-dev:24568] Fri Oct 22 12:02:28 2004 Yukihiro Matsumoto * eval.c (rb_alias): was warning for wrong condition. [ruby-dev:24565] Fri Oct 22 10:36:37 2004 GOTOU Yuuzou * lib/webrick/httprequest.rb (WEBrick::HTTPRequest#meta_vars): should check if path_info is not nil. Fri Oct 22 00:22:31 2004 Yukihiro Matsumoto * ext/zlib/zlib.c (zstream_shift_buffer): should restore class field of a buffer. [ruby-dev:24562] Fri Oct 22 00:20:33 2004 Nobuyoshi Nakada * string.c (rb_str_include): should not treat char as negative value. [ruby-dev:24558] Thu Oct 21 21:32:30 2004 IWATSUKI Hiroyuki * lib/pstore.rb (PStore#transaction): Use the empty content when a file is not found. [ruby-dev:24561] Thu Oct 21 19:06:15 2004 GOTOU Yuuzou * lib/webrick/httpresponse.rb (WEBrick::HTTPResponse#send_body_io): ensure to close @body. (http://bugs.debian.org/277520) Thu Oct 21 00:36:41 2004 Yukihiro Matsumoto * eval.c (rb_alias): should warn on method discarding. [ruby-dev:24546] * ext/zlib/zlib.c (zstream_expand_buffer_into): hide internal string buffer by clearing klass. [ruby-dev:24548] Wed Oct 20 19:45:13 2004 Yukihiro Matsumoto * string.c (str_gsub): reentrant check. [ruby-dev:24432] * backport all SEGV bug fixes from CVS HEAD. [ruby-dev:24536] Wed Oct 20 04:17:55 2004 Yukihiro Matsumoto * ext/dbm/dbm.c (fdbm_delete_if): should check if deleting element is a string. [ruby-dev:24490] * ext/sdbm/init.c (fsdbm_delete_if): ditto. Wed Oct 20 01:37:18 2004 Yukihiro Matsumoto * array.c (rb_ary_times): Array#* should return an instance of the class of right operand. [ruby-dev:24526] * ext/zlib/zlib.c (zstream_detach_buffer): should not expose class-less object to Ruby world. [ruby-dev:24530] * eval.c (proc_dup): provide Proc#dup as well. [ruby-talk:116915] * eval.c (ruby_exec): stack marking position may be higher than expected. thanks to Guy Decoux. [ruby-core:03527] Tue Oct 19 22:43:12 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_attr): If we come across 'attr' in a context where it isn't followed by a symbol, just issue a warning. Tue Oct 19 20:41:37 2004 Masaki Suketa * ext/win32ole.c(ole_invoke): retrieve the result value when retrying the IDispatch::invoke. Tue Oct 19 17:24:11 2004 Yukihiro Matsumoto * io.c (read_all): block string buffer modification during rb_io_fread() by freezing it temporarily. [ruby-dev:24479] * dir.c (rb_push_glob): block call at once the end of method. [ruby-dev:24487] * ext/enumerator/enumerator.c (enum_each_slice): remove rb_gc_force_recycle() to prevent potential SEGV. [ruby-dev:24499] * ext/zlib/zlib.c (zstream_expand_buffer): hide internal string buffer by clearing klass. [ruby-dev:24510] Tue Oct 19 16:12:18 2004 Hidetoshi NAGAI * ext/tk/tkutil.c: backport from CVS HEAD Tue Oct 19 08:54:26 2004 Nobuyoshi Nakada * intern.h, object.c (rb_class_inherited_p): export. Tue Oct 19 08:46:57 2004 Nobuyoshi Nakada * string.c (rb_str_upto): method result must be checked. [ruby-dev:24504] * eval.c (error_print): ditto. [ruby-dev:24519] Mon Oct 18 23:37:05 2004 Nobuyoshi Nakada * marshal.c (r_object0): check inheritance by the internal function. [ruby-dev:24515] Mon Oct 18 15:58:01 2004 NAKAMURA Usaku * range.c (range_step, range_each): need cast. Fri Oct 29 16:34:19 2004 Daiki Ueno * misc/ruby-mode.el (ruby-parse-partial): Parse the rest of the line after opening heredoc identifier. [ruby-dev:24635] Mon Oct 18 07:26:21 2004 Nobuyoshi Nakada * file.c (rb_file_truncate): discard read buffer before truncation. [ruby-dev:24197] Mon Oct 18 02:11:21 2004 GOTOU Yuuzou * lib/webrick/config.rb (WEBrick::Config::General): add default values: - WEBrick::Config[:DoNotReverseLookup] - WEBrick::Config[:RequestCallback] (it used as an alias of :RequestHandler in WEBrick::HTTPServer#run) - WEBrick::Config::FileHandler[:AcceptableLanguages] * lib/webrick/httpservlet/filehandler.rb (WEBrick::HTTPServlet::FileHandler#set_filename): search files having suffix of language-name which Accept-Language header field includes if :AcceptableLanguages options is present. * lib/webrick/httpservlet/filehandler.rb (WEBrick::HTTPServlet::FileHandler#get_servlet): new method to search servlet correspond to the suffix of filename. * lib/webrick/httprequest.rb: add attributes access methods: accept, accept_charset, accept_encoding, accept_language, content_length and content_type. * lib/webrick/httpresponse.rb: add attribute access methods: content_length, content_length=, content_type and content_type=. * lib/webrick/httputils.rb (WEBrick::HTTPUtils.mime_types): use the second suffix to detect media type. (the first suffix may be a language name.) * lib/webrick/httputils.rb (WEBrick::HTTPUtils.parse_qvalues): add method to parse Accept header field. it returns an Array of values sorted by the qvalues. Mon Oct 18 02:04:11 2004 GOTOU Yuuzou * lib/webrick/httpserver.rb (WEBrick::HTTPServer#virtual_host): new method to register virtual hosting servers. * lib/webrick/server.rb (WEBrick::GenericServer#accept): call do_not_reverse_lookup for each socket if :DoNotReverseLookup is set. [ruby-core:02357] Mon Oct 18 00:42:45 2004 Yukihiro Matsumoto * ext/socket/socket.c (sock_s_getservbyaname): protocol string might be altered. [ruby-dev:24503] * string.c (rb_str_upto): check if return value from succ is a string. [ruby-dev:24504] Sun Oct 17 23:03:48 2004 Hidetoshi NAGAI * ext/tk/lib/tk/timer.rb: TkTimer#start and restart accept a block Sun Oct 17 13:05:04 2004 Masaki Suketa * ext/win32ole/win32ole.c (fole_func_methods): correct argument mismatch. * ext/win32ole/win32ole.c (fole_get_methods): ditto. * ext/win32ole/win32ole.c (fole_put_methods): ditto. * ext/win32ole/tests/testWIN32OLE.rb: add test for WIN32OLE#ole_func_methods WIN32OLE#ole_get_methods, WIN32OLE#ole_put_methods Sat Oct 16 14:45:28 2004 Kouhei Sutou * lib/rss/0.9.rb (RSS::Rss#to_s): removed garbage. Sat Oct 16 13:42:49 2004 Kouhei Sutou * lib/rss/: untabified. * test/rss/: untabified. * lib/rss/0.9.rb (RSS::Rss#to_s): inent -> indent. Sat Oct 16 13:34:56 2004 Kouhei Sutou * lib/rss: supported prety print. * test/rss/test_1.0.rb: added test for calculating default indent size. Fri Oct 15 18:04:35 2004 Hidetoshi NAGAI * ext/tk/lib/tk/timer.rb: TkTimer.new(interval, loop){ ... } is acceptable. Add TkTimer.start ( == new + start ). Fri Oct 15 12:43:09 2004 Tanaka Akira * eval.c (Init_stack): make prototype declaration consistent with the definition in gc.c. Thu Oct 14 14:34:01 2004 WATANABE Hirofumi * io.c (MODE_BINMODE, MODE_BINARY): fixed reversed condition. Thu Oct 14 13:33:59 2004 Kouhei Sutou * lib/rss/rss.rb: added link to Tutorial. Mon Oct 11 13:48:20 2004 Hidetoshi NAGAI * ext/tk/lib/tk/*: untabify Sun Oct 10 12:32:08 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RDoc::parse_require): Allow 'require' to be used as a variable name Sat Oct 9 21:23:37 2004 Kouhei Sutou * lib/rss/converter.rb: changed to try to use Iconv for default conversion. * lib/rss/rss.rb: 0.0.9 -> 0.1.0. Sat Oct 9 19:50:36 2004 Nobuyoshi Nakada * io.c (rb_io_getline): should not treat char as negative value. [ruby-dev:24460] Fri Oct 8 09:49:32 2004 Yukihiro Matsumoto * pack.c (pack_pack): pointer modification check before each iteration. [ruby-dev:24445] Fri Oct 8 01:13:05 2004 Hidetoshi NAGAI * ext/tk/lib/tk/optiondb.rb: make it more secure Thu Oct 7 23:47:57 2004 Hidetoshi NAGAI * ext/tk/lib/tk/scrollbar.rb: When 'set' operation, a scrollbar cannot propagate view port information from the source widget (that calls 'set') to other assigned widgets. Thu Oct 7 17:36:25 2004 Hidetoshi NAGAI * ext/tk/lib/tk.rb: When CHILDKILLED and so on, Tk.errorCode returns a Fixnum for 2nd element (it's pid) of the return value. Thu Oct 7 12:55:04 2004 Yukihiro Matsumoto * io.c (io_read): should freeze buffer before thread context switch. [ruby-dev:24442] * pack.c (pack_unpack): string conversion should at the top of the method. [ruby-dev:24439] * io.c (io_read): buffer should be frozen only after the length check. [ruby-dev:24440] Thu Oct 7 02:56:43 2004 Nobuyoshi Nakada * ext/stringio/stringio.c: use FMODE_APPEND. Thu Oct 7 01:05:33 2004 Hidetoshi NAGAI * ext/tk/lib/tk.rb: add Tk.errorInfo and Tk.errorCode Thu Oct 7 00:08:37 2004 Yukihiro Matsumoto * io.c (rb_io_s_sysopen): preserve path in the buffer allocated by ALLOCA_N() to prevent modification. [ruby-dev:24438] Wed Oct 6 09:21:00 2004 Yukihiro Matsumoto * io.c (rb_io_mode_flags): preserve append mode flag. [ruby-dev:24436] * io.c (rb_io_modenum_mode): do not use external output buffer. * string.c (rb_str_justify): differ pointer retrieval to prevent padding string modification. [ruby-dev:24434] * range.c (range_each_func): allow func to terminate loop by returning RANGE_EACH_BREAK. * range.c (member_i): use RANGE_EACH_BREAK. [ruby-talk:114959] Mon Oct 4 14:04:14 2004 Nobuyoshi Nakada * io.c (rb_file_open_internal, rb_io_reopen): fname might be altered while GC. [ruby-dev:24408] Mon Oct 4 12:53:45 2004 Hidetoshi NAGAI * ext/tk/lib/tk/optiondb.rb: support definition of command resources on widgets * ext/tk/lib/tk/image.rb: bug fix Sun Oct 3 21:20:03 2004 Shugo Maeda * lib/net/imap.rb (TEXT_REGEXP): allow 8-bit characters for the german version of Microsoft Exchange Server. (backported from HEAD) * lib/net/imap.rb (RTEXT_REGEXP): ditto. * lib/net/imap.rb (CTEXT_REGEXP): ditto. Sat Oct 2 20:34:22 2004 Nobuyoshi Nakada * node.h (NEW_DVAR): extra semicolon. Sat Oct 2 00:42:20 2004 Yukihiro Matsumoto * marshal.c (r_byte): retrieve pointer from string value for each time. [ruby-dev:24404] * marshal.c (r_bytes0): ditto. * enum.c (sort_by_i): re-entrance check added. [ruby-dev:24399] * io.c (io_read): should freeze all reading buffer. [ruby-dev:24400] * string.c (rb_str_sum): should use bignums when bits is greater than or equals to sizeof(long)*CHAR_BITS. [ruby-dev:24395] * eval.c (specific_eval): defer pointer retrieval to prevent unsafe sourcefile string modification. [ruby-dev:24382] * eval.c (specific_eval): defer pointer retrieval to prevent unsafe sourcefile string modification. [ruby-dev:24382] * string.c (rb_str_sum): wrong cast caused wrong result. [ruby-dev:24385] * enum.c (enum_sort_by): hide temporary array from ObjectSpace.each_object. [ruby-dev:24386] * string.c (rb_str_sum): check was done with false pointer. [ruby-dev:24383] * string.c (rb_str_sum): string may be altered. [ruby-dev:24381] Mon Oct 11 17:51:34 2004 Yukihiro Matsumoto * io.c (rb_io_popen): get mode string via rb_io_flags_mode() to avoid mode string modification. [ruby-dev:24454] * io.c (rb_io_getline_fast): should take delim as unsigned char to distinguish EOF and '\377'. [ruby-dev:24460] * io.c (rb_io_getline): add check for RS modification. [ruby-dev:24461] * enum.c (enum_sort_by): use qsort() directly instead using rb_iterate(). [ruby-dev:24462] * enum.c (enum_each_with_index): remove rb_gc_force_recycle() to prevent access to recycled object (via continuation for example). [ruby-dev:24463] Fri Oct 1 11:40:14 2004 Yukihiro Matsumoto * eval.c (rb_f_eval): defer pointer retrieval to prevent unsafe sourcefile string modification. [ruby-dev:24373] * io.c (io_read): block string buffer modification during rb_io_fread() by freezing it temporarily. [ruby-dev:24366] * io.c (rb_io_s_popen): mode argument may be altered. [ruby-dev:24375] * file.c (rb_file_s_basename): ext argument may be altered. [ruby-dev:24377] * enum.c (enum_sort_by): use NODE instead of 2 element arrays. [ruby-dev:24378] * string.c (rb_str_chomp_bang): StringValue() may change the receiver. [ruby-dev:24371] Fri Oct 1 11:25:20 2004 Hidetoshi NAGAI * ext/tk/lib/tk/grid.rb: revive TkGrid.grid * ext/tk/lib/tk/pack.rb: revive TkPack.pack * ext/tk/lib/tk/place.rb: revive TkPlace.place Thu Sep 30 00:50:44 2004 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (ip_init): bug fix * ext/tk/tkutil.c (get_eval_string_core): accept a Regexp object * ext/tk/lib/multi-tk.rb: fix bug on 'exit' operation * ext/tk/lib/tk/text.rb: 'tksearch' accepts a Regexp object as a matting pattern argument Wed Sep 29 10:58:07 2004 Nobuyoshi Nakada * enum.c (sort_by_i): internally used object must not be changed outside. [ruby-dev:24368] Mon Sep 27 13:46:45 2004 Nobuyoshi Nakada * intern.h, struct.c (rb_struct_s_members, rb_struct_members): public accessors. [ruby-dev:24342] * marshal.c (w_object, r_object0): use accessors. Mon Sep 27 09:14:03 2004 Yukihiro Matsumoto * ext/socket/socket.c (s_accept): don't retry for EWOULDBLOCK. [ruby-talk:113807] Fri Sep 24 16:09:42 2004 Yukihiro Matsumoto * eval.c (proc_invoke): propagate DVAR_DONT_RECYCLE on termination to avoid double call to rb_gc_force_recycle(). [ruby-dev:24311] Fri Sep 24 08:29:45 2004 Yukihiro Matsumoto * array.c (rb_ary_subseq): original object might be modified after sharing data creation. [ruby-dev:24327] * array.c (rb_ary_replace): ditto. * array.c (ary_make_shared): freeze shared array. [ruby-dev:24325] * struct.c (struct_members): always check struct size and size of members list in the class. [ruby-dev:24320] Thu Sep 23 09:29:14 2004 Yukihiro Matsumoto * string.c (rb_str_sub_bang): check if string is not modified during iteration. [ruby-dev:24315] * hash.c (rb_hash_rehash): replace st_foreach() by its deep checking counterpart. [ruby-dev:24310] Wed Sep 22 13:38:12 2004 Yukihiro Matsumoto * hash.c (rb_hash_rehash): add iteration check. [ruby-dev:24301] * st.c (st_foreach): add deep check. Wed Sep 22 13:06:14 2004 NAKAMURA Usaku * win32/win32.c (rb_w32_call_handler): workaround for Ctrl-C. merge from HEAD. Wed Sep 22 00:11:12 2004 Dave Thomas * process.c: Add documentation for fork() Wed Sep 22 09:04:41 2004 Yukihiro Matsumoto * array.c (rb_ary_collect_bang): element size might change during comparison. [ruby-dev:24300] * array.c (rb_ary_reject_bang): ditto. [ruby-dev:24300] * array.c (rb_ary_eql): ditto. [ruby-dev:24300] Tue Sep 21 18:29:49 2004 Yukihiro Matsumoto * array.c (rb_ary_equal): merge miss. * array.c (rb_ary_uniq_bang): element size might change during comparison. [ruby-dev:24298] Mon Sep 20 00:24:19 2004 Yukihiro Matsumoto * enum.c (enum_sort_by): do not use qsort directly. use rb_ary_sort_bang() instead. [ruby-dev:24291] * enum.c (enum_sort_by): pedantic type check added. [ruby-dev:24291] * hash.c (rb_hash_foreach_iter): check iter_lev after each iteration. [ruby-dev:24289] * array.c (rb_ary_and): element size might change during comparison. [ruby-dev:24290] * array.c (rb_ary_or): ditto. [ruby-dev:24292] * array.c (rb_ary_equal): wrong fix. [ruby-dev:24286] Sat Sep 18 15:02:22 2004 Yukihiro Matsumoto * array.c (rb_ary_equal): element size might change during comparison. [ruby-dev:24254] * array.c (rb_ary_diff): ditto. [ruby-dev:24274] * array.c (rb_ary_select): ditto. [ruby-dev:24278] * array.c (rb_ary_delete): ditto. [ruby-dev:24283] * array.c (rb_ary_rindex): ditto. [ruby-dev:24275] * array.c (rb_ary_initialize): element size might change during initializing block. [ruby-dev:24284] Sat Sep 18 14:10:23 2004 Yukihiro Matsumoto * dir.c (dir_s_chdir): avoid memory leak and unnecessary chdir to the original directory when exception has caused in changing direcotry or within block. thanks to Johan Holmberg [ruby-core:03446] Fri Sep 17 20:20:27 2004 Minero Aoki * lib/fileutils.rb (mkdir_p): backport from CVS HEAD 1.45. [ruby-core:03420] Fri Sep 17 17:11:08 2004 Yukihiro Matsumoto * array.c (rb_ary_delete): element comparison might change array size. [ruby-dev:24273] * file.c (rb_file_truncate): clear stdio buffer before truncating the file. [ruby-dev:24191] * ext/digest/digest.c: use rb_obj_class() instead of CLASS_OF which might return singleton class. [ruby-dev:24202] Fri Sep 17 16:07:09 2004 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: improve exit operation Fri Sep 17 15:01:57 2004 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: fix SEGV when (thread_)vwait or (thread_)tkwait * ext/tk/lib/tk.rb: add alias wait_window to wait_destroy * ext/tk/lib/multi-tk.rb: support calling 'mainloop' on slave interpreters (however, the 'real' eventloop must be run on the Default Master IP) * ext/tk/lib/remote-tk.rb: follow the changes of ext/tk/lib/multi-tk.rb * ext/tk/sample/remote-ip_sample2.rb: ditto * ext/tk/sample/tkoptdb-safeTk.rb: ditto Thu Sep 16 18:12:32 2004 GOTOU Yuuzou * lib/webrick/cgi.rb (WEBrick::CGI#start): should set REMOTE_USER to request.user attribute. * lib/webrick/httpservlet/filehandler.rb (WEBrick::HTTPServlet::FileHandler#initialize): should expand the pathname of document root directory. Thu Sep 16 15:49:28 2004 Yukihiro Matsumoto * string.c (rb_str_intern): protect string argument from GC. [ruby-core:03411] Wed Sep 15 20:22:23 2004 Hidetoshi NAGAI * ext/tk/sample/tkoptdb-safeTk.rb: fix a bug depend on the changes of MultiTkIp Tue Sep 14 23:54:11 2004 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: MultiTkIp#eval_string was en-bugged by the previous changes. Tue Sep 14 23:45:44 2004 Dave Thomas * lib/rdoc/ri/ri_formatter.rb (RI::TextFormatter::TextFormatter.for): Add Eric Hodel's simpleformatter. Tue Sep 14 16:59:37 2004 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: fix SEGV * ext/tk/lib/multi-tk.rb: improve safe-level handling of argument proc * ext/tk/sample/multi-ip_sample.rb: rename of old 'safe-tk.rb' * ext/tk/sample/safe-tk.rb: new sample script Tue Sep 14 00:15:15 2004 WATANABE Hirofumi * ext/zlib/zlib.c: backported from HEAD. Mon Sep 13 19:16:33 2004 WATANABE Hirofumi * eval.c (blk_copy_prev): need frame_dup(). [ruby-dev:24103] Mon Sep 13 16:23:27 2004 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: MultiTkIp.new_master and new_slave accept safe-level value argument Mon Sep 13 10:20:45 2004 NAKAMURA Usaku * object.c (nil_inspect): fix typo. Mon Sep 13 01:03:02 2004 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: improve control of preserv/release tcltkip * ext/tcltklib/tcltklib.c: store original 'exit' command * ext/tk/tkutil.c: fix(?) SEGV Sun Sep 12 23:46:23 2004 Hirokazu Yamamoto * util.c (ruby_strdup): remove unnecessary code. (xmalloc never returns NULL.) * util.c (ruby_getcwd): fix memory leak on failure. Sun Sep 12 02:41:58 2004 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: add TclTkIp#allow_ruby_exit? and allow_ruby_exit= * ext/tk/lib/multi-tk.rb: ditto. * ext/tk/lib/remote-tk.rb: ditto. * ext/tcltklib/MANUAL.euc: ditto. * ext/tcltklib/MANUAL.eng: ditto. * ext/tcltklib/tcltklib.c: fix some reasons of SEGV * ext/tk/tkutil.c: ditto. * ext/tk/lib/multi-tk.rb: ditto. * ext/tk/lib/tk/timer.rb: ditto. Sat Sep 11 16:09:46 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb: Fix up cross-file class merging. Fri Sep 10 20:20:53 2004 Hirokazu Yamamoto * ext/tcltklib/tcltklib.c (lib_merge_tklist): fix suspicious pointer conversion. Fri Sep 10 02:43:54 2004 Dave Thomas * lib/rdoc/generators/template/kilmer.rb: James Buck's patch for call-seq. Thu Sep 9 13:58:56 2004 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (ip_init): change flag value for setting 'argv' and 'argv0' variable * ext/tk/lib/remote-tk.rb: follow changes of multi-tk.rb Thu Sep 9 11:46:18 2004 Dave Thomas * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser::do_classes): Allow spaces aroun parameter to define_method_under (James Buck) Wed Sep 8 18:44:03 2004 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_write): zero fill a gap if exsts. [ruby-dev:24190] Wed Sep 8 15:19:49 2004 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (ip_init): cannot create a IP at level 4 * ext/tk/lib/multi-tk.rb: improve 'exit' operation, security check, and error treatment * ext/tk/lib/multi-tk.rb: allow a trusted slave IP to create slave IPs * ext/tk/lib/tk/listbox.rb: add TkListbox#value, value=, clear, and erase * ext/tk/lib/tk/text.rb: add TkText#clear and erase Tue Sep 7 15:17:49 2004 Nobuyoshi Nakada * ext/socket/socket.c (ruby_connect): break immediately if a socket is non-blocking. [ruby-talk:111654] Mon Sep 6 11:08:50 2004 Hirokazu Yamamoto * ext/tk/lib/tk/menu.rb(TkOptionMenubutton#insert): call correct method Mon Sep 6 11:00:47 2004 Yukihiro Matsumoto * dir.c (dir_s_chdir): the patch to shut up false warning when exception occurred within a block. a patch was given from Johan Holmberg . [ruby-core:03292] Mon Sep 6 07:51:42 2004 Yukihiro Matsumoto * eval.c (cvar_cbase): singletons should refer outer cvar scope. [ruby-dev:24223] * eval.c (rb_load): should preserve previous ruby_wrapper value. [ruby-dev:24226] Sat Sep 4 01:14:57 2004 Yukihiro Matsumoto * eval.c (cvar_cbase): class variables cause SEGV in instance_eval() for fixnums and symbols. [ruby-dev:24213] Fri Sep 3 17:47:58 2004 Yukihiro Matsumoto * struct.c (make_struct): remove redefining constant when conflict. [ruby-dev:24210] Fri Sep 3 11:31:44 2004 Hidetoshi NAGAI * ext/tk/lib/tk.rb: Tk.after makes TkCore::INTERP.tk_cmd_tbl grow [ruby-dev:24207] Fri Sep 3 02:12:48 2004 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: fix typo [ruby-talk:111266] * ext/tk/lib/tk/text.rb: fix typo * ext/tk/lib/multi-tk.rb: improve safe-level treatment on slave IPs Fri Sep 3 01:54:20 2004 Nobuyoshi Nakada * ext/extmk.rb: already built-in libraries satisfy dependencies. [ruby-dev:24028] Thu Sep 2 11:36:20 2004 WATANABE Hirofumi * eval.c (rb_obj_instance_eval): backported from HEAD. Wed Sep 1 21:18:25 2004 Hirokazu Yamamoto * ext/tk/lib/tk/spinbox.rb: fix typo Tue Aug 31 18:24:04 2004 Hirokazu Yamamoto * ext/tk/tkutil.c (cbsubst_init): fix memory leak * ext/tk/tkutil.c (cbsubst_get_all_subst_keys): fix SEGV Tue Aug 31 16:04:22 2004 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (ip_delete): when a tcltkip is deleted, destroy its root widget Tue Aug 31 12:30:36 2004 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (del_root): fix SEGV Mon Aug 30 23:11:06 2004 Dave Thomas * lib/rdoc/ri/ri_driver.rb (and others): ri now merges documentation if it finds the same class in multiple places. Mon Aug 30 22:40:30 2004 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: 'restart' method accepts arguments Mon Aug 30 21:50:14 2004 Dave Thomas * object.c: Add RDoc for Module.included. Mon Aug 30 15:10:46 2004 WATANABE Hirofumi * configure.in (GNU/k*BSD): fixed FTBFS on GNU/k*BSD. [ruby-dev:24051] Mon Aug 30 11:29:35 2004 NAKAMURA Usaku * win32/win32.c (CreateChild): strip trailing spaces. [ruby-dev:24143] merge from HEAD. Sun Aug 29 14:08:56 2004 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: compile error on bcc32 [ruby-dev:24081] * ext/tk/lib/multi-tk.rb: MultiTkIp#eval_string does not work Sat Aug 28 23:04:41 2004 Yukihiro Matsumoto * bignum.c (rb_big_and): protect parameters from GC. [ruby-talk:110664] Thu Aug 26 04:38:29 2004 Dave Thomas * eval.c (return_jump): Minor typo in error message. Now reads "return can't jump across threads". Tue Aug 24 17:30:00 2004 Shugo Maeda * lib/cgi/session.rb (CGI::Session::FileStore#initialize): do not use a session id as a filename. (backported from HEAD) * lib/cgi/session/pstore.rb (CGI::Session::PStore#initialize): ditto. * lib/cgi/session/pstore.rb (CGI::Session::PStore#initialize): use Dir::tmpdir. (backported from HEAD) Tue Aug 24 14:40:16 2004 Shugo Maeda * lib/cgi/session.rb (CGI::Session::FileStore#initialize): untaint session id after check. (backported from HEAD) Tue Aug 24 09:09:01 2004 GOTOU Yuuzou * ext/openssl/ossl_x509attr.c (ossl_x509attr_initialize): d2i functions may replace the pointer indicated by the first argument. * ext/openssl/ossl_x509ext.c (ossl_x509ext_initialize): ditto. * ext/openssl/ossl_x509name.c (ossl_x509name_initialize): ditto. Mon Aug 23 14:04:51 2004 GOTOU Yuuzou * ext/openssl/ossl_ssl.c (ossl_ssl_read): - should return an empty string if specified length to read is 0. - should check for pending data and wait for fd before reading. - call underlying IO's sysread if SSL session is not started. [ruby-dev:24072], [ruby-dev:24075] * ext/openssl/ossl_ssl.c (ossl_ssl_write): - call underlying IO's syswrite if SSL session is not started. * ext/openssl/ossl_ssl.c (ossl_ssl_pending): new method OpenSSL::SSL#pending. * ext/openssl/lib/openssl/buffering.rb: should not use select. Mon Aug 23 12:40:56 2004 NAKAMURA Usaku * lib/resolv.rb (Config.default_config_hash): when multiple domains are set, Win32::Resolv.get_resolv_info returns Array. Sun Aug 22 01:15:31 2004 GOTOU Yuuzou * lib/webrick/httpproxy.rb (WEBrick::HTTPProxyServer#proxy_connect): should call :ProxyContentHandler before finishing CONNECT. Sat Aug 21 06:41:16 2004 Nobuyoshi Nakada * ext/tcltklib/extconf.rb (find_tcl, find_tk): find stub library. * lib/mkmf.rb (arg_config, with_config): deal with '-' and '_' uniformly. [ruby-dev:24118] Thu Aug 19 16:29:45 2004 Hidetoshi NAGAI * ext/tk/lib/tk.rb: Fail to treat a hash value of 'font' option. * ext/tk/lib/tk.rb: bindinfo cannot return '%' substiturion infomation. * ext/tk/lib/menu.rb: typo bug. Thu Aug 19 15:15:24 2004 Yukihiro Matsumoto * dir.c (free_dir): fix memory leak. reported by yamamoto madoka. Thu Aug 19 11:00:00 2004 Akiyoshi, Masamichi * dln.c (dln_load): Modify to call lib$find_image_symbol for VMS. * io.c (rb_io_fwrite): Use fputc() for VMS non-stream file. Thu Aug 19 06:07:45 2004 why the lucky stiff * ext/syck/token.c: re2c no longer compiled with bit vectors. caused problems for non-ascii characters. [ruby-core:03280] * ext/syck/implicit.c: ditto. * ext/syck/bytecode.c: ditto. * lib/yaml/baseemitter.rb: folding now handles double-quoted strings, fixed problem with extra line feeds at end of folding, whitespace opening scalar blocks. * lib/yaml/rubytypes.rb: subtelties in handling strings with non-printable characters and odd whitespace patterns. Wed Aug 18 23:41:33 2004 Minero Aoki * lib/net/protocol.rb (rbuf_fill): OpenSSL::SSL::SSLSocket has its own buffer, select(2) might not work. [ruby-dev:24072] Wed Aug 18 17:10:12 2004 WATANABE Hirofumi * ext/tcltklib/stubs.c (ruby_tcltk_stubs): need to call Tcl_FindExecutable() for Tcl/Tk 8.4. Wed Aug 18 12:52:55 2004 Nobuyoshi Nakada * eval.c (rb_obj_instance_eval): evaluates under special singleton classes as for special constants. Tue Aug 17 17:20:59 2004 Yukihiro Matsumoto * io.c (rb_io_reopen): should clear allocated OpenFile. pointed out by Guy Decoux. [ruby-core:03288] Tue Aug 17 01:36:32 2004 Dave Thomas * lib/rdoc/usage.rb: Remove extra indent. Tidy 'ri' option parsing so RDoc::usage plays better with OptionParser. Sat Aug 14 13:09:10 2004 Minero Aoki * lib/fileutils.rb: backport from CVS HEAD (rev1.44). * lib/fileutils.rb: cp_r should copy symlink itself, except cp_r root. * lib/fileutils.rb: new option mv :force. * lib/fileutils.rb: new module FileUtils::DryRun. Sat Aug 14 02:48:16 2004 Dave Thomas * lib/rdoc/usage.rb: Added. Allows command line programs to report usage using their initial RDoc comment. Fri Aug 13 13:23:17 2004 GOTOU Yuuzou * lib/webrick/httputils.rb (WEBrick::HTTPUtils.parse_range_header): fix regex for range-spec. * lib/webrick/httpservlet/filehandler.rb (WEBrick::HTTPServlet::DefaultFileHandler#make_partial_content): multipart/byteranges response was broken. * lib/webrick/httpservlet/erbhandler.rb (WEBrick::HTTPServlet::ERBHandler#do_GET): should select media type by suffix of script filename. * lib/xmlrpc/server.rb: refine example code. Wed Aug 11 17:17:50 2004 WATANABE Hirofumi * configure.in (RPATHFLAG): stop setting RPATHFLAG on Interix. Sun Aug 8 00:43:31 2004 why the lucky stiff * lib/implicit.c: added sexagecimal float#base60. * ext/syck/rubyext.c (yaml_org_handler): ditto. * lib/token.c: indentation absolutely ignored when processing flow collections. plain scalars are trimmed if indentation follows in an ambiguous flow collection. Sat Aug 7 00:50:01 2004 Tanaka Akira * ext/zlib/zlib.c: Zlib::GzipReader#read(0) returns "" instead of nil. Tue Aug 3 13:49:20 2004 Hidetoshi NAGAI * ext/tk/lib/tk/namespace.rb: bug fix * ext/tk/lib/tkextlib/treectrl/tktreectrl.rb: add Tk::TreeCtrl.loupe Mon Aug 2 18:04:21 2004 Hidetoshi NAGAI * ext/tk/lib/tk/msgcat.rb (set_translation): bug fix (fail to set trans_str to the same as src_str when trans_str is not given.) Mon Aug 2 11:53:06 2004 Dave Thomas * lib/rdoc/code_objects.rb (RDoc::Context::find_symbol): Fix infinite recursion looking up some top level symbols (batsman) Mon Aug 2 11:48:29 2004 Dave Thomas * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser::do_methods): Allow '.'s in variable names to support SWIG generated files (Hans Fugal) Sat Jul 31 17:40:16 2004 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-expr-beg, ruby-parse-partial, ruby-calculate-indent, ruby-move-to-block, ruby-forward-sexp, ruby-backward-sexp): keywords must match word-wise. Sat Jul 31 05:47:37 2004 why the lucky stiff * lib/yaml.rb (YAML::load_file, YAML::parse_file): added. * lib/yaml/rubytypes.rb: exceptions were using an older YAML.object_maker. [ruby-core:03080] * ext/syck/token.c (sycklex_yaml_utf8): using newline_len to handline CR-LFs. "\000" was showing up on folded blocks which stopped at EOF. * ext/syck/token.c: re2c compiled with bit vectors now. * ext/syck/implicit.c: ditto. * ext/syck/bytecode.c: ditto. Fri Jul 30 16:10:54 2004 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (lib_fromUTF8_core): raise ArgumentError when the unknown encoding name is given. * ext/tcltklib/tcltklib.c (lib_toUTF8_core): ditto. * ext/tk/lib/tk.rb (Tk::Encoding.encoding_convertfrom): bug fix. * ext/tk/lib/tk.rb (Tk::Encoding.encoding_convertto): ditto. Wed Jul 28 18:59:17 2004 Yukihiro Matsumoto * lib/cgi.rb (CGI::initialize): remove at_exit code for CGI_PARAMS and CGI_COOKIES. they will no longer be used. Wed Jul 28 01:04:44 2004 Yukihiro Matsumoto * gc.c (run_final): wrong order of data. [ruby-dev:23984] Tue Jul 27 07:05:04 2004 Yukihiro Matsumoto * eval.c (rb_eval): copy on write for argument local variable assignment. * eval.c (assign): ditto. * eval.c (rb_call0): update ruby_frame->argv with the default value used for the optional arguments. * object.c (Init_Object): "===" calls rb_obj_equal() directly. [ruby-list:39937] Mon Jul 26 11:22:55 2004 GOTOU Yuuzou * lib/webrick/httputils.rb (WEBrick::HTTPUtils.escape): should escape space. Sun Jul 25 11:05:21 2004 Hirokazu Yamamoto * win32/win32.{h,c} (rb_w32_{f,fd,fs}open): workaround for bcc32's {f,fd,fs}open bug. set errno EMFILE and EBADF. [ruby-dev:23963] Sat Jul 24 13:32:47 2004 Yukihiro Matsumoto * range.c (rb_range_beg_len): returns Qnil only when "beg" points outside of a range. No boundary check for "end". Fri Jul 23 16:40:25 2004 Yukihiro Matsumoto * gc.c (define_final): should not disclose NODE* to Ruby world. [ruby-dev:23957] Fri Jul 23 09:03:16 2004 Shugo Maeda * lib/net/imap.rb (disconnected?): new method. (backported from HEAD) Thu Jul 22 16:41:54 2004 Yukihiro Matsumoto * lib/cgi/session.rb (CGI::Session::FileStore#update): sets the permission of the session data file to 0600. * lib/cgi/session/pstore.rb (CGI::Session::Pstore#initialize): ditto. Thu Jul 22 00:02:21 2004 Masahiro Kitajima * process.c (rb_f_system): not need to call last_status_set() any longer on _WIN32. Tue Jul 20 09:15:17 2004 Hirokazu Yamamoto * test/fileutils/test_fileutils.rb: File.link raises EINVAL on BeOS. Mon Jul 19 01:15:07 2004 GOTOU Yuuzou * lib/webrick/httpservlet/cgihandler.rb (WEBrick::HTTPServlet::CGIhandler#do_GET): set SystemRoot environment variable to CGI process on Windows native platforms. [ruby-dev:23936] * lib/webrick/httpservlet/cgihandler.rb (WEBrick::HTTPServlet::CGIhandler#do_GET): use $?.exitstatus and refine log message. Sun Jul 18 16:14:29 2004 Hidetoshi NAGAI * ext/tk/lib/tk/msgcat.rb (TkMsgCatalog.callback): bug fix ( wrong number of argument ) Sun Jul 18 08:13:58 2004 Nobuyoshi Nakada * sprintf.c (rb_f_sprintf): remove extra sign digit. Sun Jul 18 03:21:42 2004 Akinori MUSHA * dir.c (range): use NULL instead of 0. * dir.c (range): get rid of a gcc 3.4 warning. Sun Jul 18 03:12:11 2004 Shugo Maeda * lib/net/imap.rb (receive_responses): return if a LOGOUT response received. (backported from HEAD) * lib/net/imap.rb (send_string_data): wait command continuation requests before sending octet data of literals. (backported from HEAD) Sat Jul 17 23:54:59 2004 Hidetoshi NAGAI * ext/tk/lib/tk/variable.rb: TkVariable#ref returns a TkVariable object Sat Jul 17 22:04:44 2004 akira yamada * lib/uri/ldap.rb: method hierarchical? should be in URI::LDAP. Sat Jul 17 18:29:07 2004 Nobuyoshi Nakada * parse.y (stmt): not to show same error messages twice. Sat Jul 17 13:13:32 2004 Yukihiro Matsumoto * lib/irb/ruby-lex.rb (RubyLex::identify_string): %s string do not process expression interpolation. [ruby-talk:106691] Sat Jul 17 05:26:27 2004 Dave Thomas * lib/rdoc/diagram.rb: Incorporate Micheal Neuman's client-side imagemao patch Sat Jul 17 01:57:03 2004 Yukihiro Matsumoto * eval.c (THREAD_ALLOC): th->thread should be initialized to NULL. [ruby-talk:106657] The solution was found by Guy Decoux. Fri Jul 16 22:30:28 2004 Michael Neumann * file.c (rb_stat_dev_major): new methods File::Stat#dev_major and #dev_minor. [ruby-core:03195] Fri Jul 16 15:23:53 2004 Nobuyoshi Nakada * eval.c (return_jump, break_jump): raise unexpceted local jump exception directly. [ruby-dev:23740] * lib/base64.rb (Deprecated): super in bound method calls original name method in stable version. [ruby-dev:23916] Fri Jul 16 11:31:49 2004 Hirokazu Yamamoto * lib/test/unit/ui/{fox,gtk,gtk2}/testrunner.rb: remove garbage (patch from akira yamada) [ruby-dev:23911] Fri Jul 16 11:20:00 2004 NAKAMURA Usaku * sprintf.c (rb_f_sprintf): fix output of NaN, Inf and -Inf with "%f" or etc on MSVCRT platforms. (backported from HEAD) Fri Jul 16 11:17:38 2004 Nobuyoshi Nakada * error.c (exit_initialize): use EXIT_SUCCESS instead of 0. [ruby-dev:23913] * error.c (exit_success_p): new method SystemExit#success?. [ruby-dev:23912] * error.c (syserr_initialize): initialization for subclasses. [ruby-dev:23912] Thu Jul 15 23:53:38 2004 Nobuyoshi Nakada * lib/optparse.rb (OptionParser#warn, OptionParser#abort): Exception no longer has to_str method. Thu Jul 15 22:59:48 2004 Shugo Maeda * ext/readline/extconf.rb: added dir_config for curses, ncurses, termcap. (backported from HEAD) Thu Jul 15 20:29:15 2004 Hirokazu Yamamoto * class.c, error.c, eval.c, intern.h, object.c, variable.c: do not set path if it is a singleton class. [ruby-dev:22588] (backport from 1.9) Thu Jul 15 10:15:04 2004 Hidetoshi NAGAI * ext/tk/, ext/tcltklib/: bug fix * ext/tk/lib/tk.rb: better operation for SIGINT when processing callbacks. * ext/tk/lib/tk/msgcat.rb: ditto. * ext/tk/lib/tk/variable.rb: ditto. * ext/tk/lib/tk/timer.rb: ditto. * ext/tk/lib/tk/validation.rb: add Tk::ValidateConfigure.__def_validcmd to define validatecommand methods easier * ext/tk/lib/tk.rb (_genobj_for_tkwidget): support autoload Tk ext classes * ext/tk/lib/tk/canvas.rb and so on: remove the parent widget type check for items (e.g. canvas items; depends on the class) to avoid some troubles on Tk extension widget class definition. * ext/tk/lib/tkextlib/: add Iwidget and TkTable extension support * ext/tk/sample/tkextlib/: add samples of Iwidget and TkTable Wed Jul 14 18:08:37 2004 GOTOU Yuuzou * ext/openssl/ossl_asn1.c (ossl_asn1cons_to_der): fix type of argument. [ruby-dev:23891] * test/openssl/test_x509store.rb: prune tests for CRL checking unless X509::V_FLAG_CRL_CHECK is defined. Wed Jul 14 12:29:07 2004 Hirokazu Yamamoto * util.c (ruby_strtod): should not convert string in the form of "-I.FE-X" which both "I" and "F" are ommitted. [ruby-dev:23883] * test/ruby/test_float.rb (test_strtod): add test for bug fix. Wed Jul 14 00:31:15 2004 Hirokazu Yamamoto * array.c: rdoc patch. merged patch from Johan Holmberg [ruby-core:3170] Tue Jul 13 19:39:12 2004 akira yamada * lib/uri/generic.rb (URI::Generic#merge_path): "URI('http://www.example.com/foo/..') + './'" should return "URI('http://www.example.com/')". [ruby-list:39838] "URI('http://www.example.com/') + './foo/bar/..'" should return "URI('http://www.example.com/foo/')". [ruby-list:39844] * test/uri/test_generic.rb (TestGeneric#test_merge): added tests. Tue Jul 13 15:51:45 2004 Akinori MUSHA * lib/mkmf.rb (init_mkmf): Do not add $(libdir) to $LIBPATH in extmk mode. * lib/mkmf.rb (dir_config): Prepend a new library path instead of appending so it is tried first. Tue Jul 13 00:50:48 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb: Support call-seq: for Ruby files. Mon Jul 12 21:20:36 2004 Dave Thomas * html_generator.rb: Support hyperlinks of the form {any text}[xxx] as well as stuff[xxx] Sat Jul 10 09:30:24 2004 NAKAMURA, Hiroshi * test/soap/marshal/test_struct.rb: use qualified build-tin class name (::Struct) to avoid name crash. Sat Jul 10 04:21:56 2004 Hidetoshi NAGAI * ext/tk/lib/tk.rb: better operation for SIGINT when processing callbacks. * ext/tk/lib/tk/msgcat.rb: ditto. * ext/tk/lib/tk/variable.rb: ditto. * ext/tk/lib/tk/timer.rb: ditto. * ext/tk/lib/tk/validation.rb (__def_validcmd): add a module function of Tk::ValidateConfigure to define validatecommand methods easier Fri Jul 9 22:36:36 2004 Hirokazu Yamamoto * array.c, enum.c, pack.c: rdoc patch from Johan Holmberg [ruby-core:3132] [ruby-core:3136] * numeric.c: rdoc patch. Fri Jul 9 19:26:39 2004 Tanaka Akira * lib/open-uri.rb (URI::HTTPS#proxy_open): raise ArgumentError to notice https is not supported. Fri Jul 9 14:28:54 2004 Nobuyoshi Nakada * eval.c (rb_thread_raise): accept third argument as well as Kernel#raise, and evaluate the arguments to create an exception in the caller's context. [ruby-talk:105507] Fri Jul 9 01:47:08 2004 Hidetoshi NAGAI * ext/tk/lib : bug fix * ext/tk/lib/tkextlib/itcl : add [incr Tcl] support * ext/tk/lib/tkextlib/itk : add [incr Tk] support * ext/tk/lib/tkextlib/iwidgets : midway point of [incr Widgets] support * ext/tk/sample/tkextlib/iwidgets : very simple examples of [incr Widgets] Thu Jul 8 22:52:19 2004 Kouhei Sutou * lib/rss/{rss,parser,0.9,1.0,2.0}.rb: supported RSS 0.9x/2.0 validation and validation which disregard order of elements. * test/rss/test_parser.rb: added tests for RSS 0.9x/2.0 validation. * test/rss/{test_trackback,rss-testcase}.rb: fixed no good method name. Thu Jul 8 00:05:23 2004 akira yamada * lib/tempfile.rb (Tempfile::initialize): got out code of generating tmpname. [ruby-dev:23832][ruby-dev:23837] Wed Jul 7 15:53:14 2004 NAKAMURA Usaku * string.c (rb_str_match): raise TypeError when both arguments are strings. [ruby-dev:22869] (backported from HEAD) * string.c (rb_str_match2): removed. * Makefile.in, bcc32/Makefile.sub, win32/Makefile.sub, wince/Makefile.sub (string.c): now not depend on version.h. Wed Jul 7 00:48:34 2004 WATANABE Hirofumi * ext/tk/lib/tkextlib/tktrans.rb, ext/tk/lib/tkextlib/treectrl.rb: fix syntax errors. Tue Jul 6 18:38:45 2004 Hidetoshi NAGAI * ext/tk/lib : improve framework of developping Tcl/Tk extension wrappers Mon Jul 5 23:56:42 2004 Kouhei Sutou * lib/rss/{trackback,syndication,dublincore,content}.rb: worked with ruby 1.6 again. * test/rss/rss-assertions.rb: ditto. Mon Jul 5 22:54:39 2004 Tanaka Akira * lib/uri/common.rb (Kernel#URI): new global method for parsing URIs. Mon Jul 5 09:02:52 2004 Nobuyoshi Nakada * eval.c (rb_thread_yield, rb_f_catch): 4th argument to rb_yield_0() is a set of bit flags. [ruby-dev:23859] Mon Jul 5 01:27:32 2004 Hirokazu Yamamoto * lib/drb/drb.rb(DRbConn self.open): If socket pool is full, close the socket whose last-access-time is oldest. (and add new one) [ruby-dev:23860] Sun Jul 4 12:24:50 2004 Kouhei Sutou * lib/rss/rss.rb: added copyright header. Sun Jul 4 00:24:40 2004 NAKAMURA, Hiroshi * added files * lib/soap/attachment.rb * lib/soap/header * lib/soap/mimemessage.rb * lib/soap/rpc/httpserver.rb * lib/wsdl/soap/cgiStubCreator.rb * lib/wsdl/soap/classDefCreator.rb * lib/wsdl/soap/classDefCreatorSupport.rb * lib/wsdl/soap/clientSkeltonCreator.rb * lib/wsdl/soap/driverCreator.rb * lib/wsdl/soap/mappingRegistryCreator.rb * lib/wsdl/soap/methodDefCreator.rb * lib/wsdl/soap/servantSkeltonCreator.rb * lib/wsdl/soap/standaloneServerStubCreator.rb * lib/wsdl/xmlSchema/enumeration.rb * lib/wsdl/xmlSchema/simpleRestriction.rb * lib/wsdl/xmlSchema/simpleType.rb * lib/xsd/codegen * lib/xsd/codegen.rb * sample/soap/authheader * sample/soap/raa2.4 * sample/soap/ssl * sample/soap/swa * sample/soap/whois.rb * sample/soap/calc/samplehttpd.conf * sample/soap/exchange/samplehttpd.conf * sample/soap/sampleStruct/samplehttpd.conf * sample/wsdl/raa2.4 * sample/wsdl/googleSearch/samplehttpd.conf * test/openssl/_test_ssl.rb * test/soap/header * test/soap/ssl * test/soap/struct * test/soap/swa * test/soap/wsdlDriver * test/wsdl/multiplefault.wsdl * test/wsdl/simpletype * test/wsdl/test_multiplefault.rb * modified files * lib/soap/baseData.rb * lib/soap/element.rb * lib/soap/generator.rb * lib/soap/marshal.rb * lib/soap/netHttpClient.rb * lib/soap/parser.rb * lib/soap/processor.rb * lib/soap/property.rb * lib/soap/soap.rb * lib/soap/streamHandler.rb * lib/soap/wsdlDriver.rb * lib/soap/encodingstyle/handler.rb * lib/soap/encodingstyle/literalHandler.rb * lib/soap/encodingstyle/soapHandler.rb * lib/soap/mapping/factory.rb * lib/soap/mapping/mapping.rb * lib/soap/mapping/registry.rb * lib/soap/mapping/rubytypeFactory.rb * lib/soap/mapping/wsdlRegistry.rb * lib/soap/rpc/cgistub.rb * lib/soap/rpc/driver.rb * lib/soap/rpc/element.rb * lib/soap/rpc/proxy.rb * lib/soap/rpc/router.rb * lib/soap/rpc/soaplet.rb * lib/soap/rpc/standaloneServer.rb * lib/wsdl/data.rb * lib/wsdl/definitions.rb * lib/wsdl/operation.rb * lib/wsdl/parser.rb * lib/wsdl/soap/definitions.rb * lib/wsdl/xmlSchema/complexContent.rb * lib/wsdl/xmlSchema/complexType.rb * lib/wsdl/xmlSchema/data.rb * lib/wsdl/xmlSchema/parser.rb * lib/wsdl/xmlSchema/schema.rb * lib/xsd/datatypes.rb * lib/xsd/qname.rb * sample/soap/calc/httpd.rb * sample/soap/exchange/httpd.rb * sample/soap/sampleStruct/httpd.rb * sample/soap/sampleStruct/server.rb * sample/wsdl/amazon/AmazonSearch.rb * sample/wsdl/amazon/AmazonSearchDriver.rb * sample/wsdl/googleSearch/httpd.rb * test/soap/test_basetype.rb * test/soap/test_property.rb * test/soap/test_streamhandler.rb * test/soap/calc/test_calc.rb * test/soap/calc/test_calc2.rb * test/soap/calc/test_calc_cgi.rb * test/soap/helloworld/test_helloworld.rb * test/wsdl/test_emptycomplextype.rb * test/wsdl/axisArray/test_axisarray.rb * test/wsdl/datetime/test_datetime.rb * test/wsdl/raa/test_raa.rb * test/xsd/test_xmlschemaparser.rb * test/xsd/test_xsd.rb * summary * add SOAP Header mustUnderstand support. * add HTTP client SSL configuration and Cookies support (works completely with http-access2). * add header handler for handling sending/receiving SOAP Header. * map Ruby's anonymous Struct to common SOAP Struct in SOAP Object Model. it caused error. * add WSDL simpleType support to restrict lexical value space. * add SOAP with Attachment support. Sat Jul 3 17:19:44 2004 WATANABE Hirofumi * ext/tk/lib/tkextlib/tkDND.rb: fix syntax error. Thu Jul 1 23:15:29 2004 Nobuyoshi Nakada * lib/pstore.rb (transaction): safer backup scheme. [ruby-list:39102] * lib/pstore.rb (commit_new): use FileUtils.copy_stream for Cygwin. [ruby-dev:23157] * lib/pstore.rb (transaction): allow overriding dump and load. [ruby-dev:23567] * lib/pstore.rb (PStore#transaction): get rid of opening in write mode when read only transaction. [ruby-dev:23842] * lib/yaml/store.rb: follow lib/pstore.rb's change. Thu Jul 1 18:36:08 2004 Hidetoshi NAGAI * ext/tk/lib/tcltklib : bug fix * ext/tk/lib/tk : bug fix and add Tcl/Tk extension support libraries Thu Jul 1 11:59:45 2004 GOTOU Yuuzou * ext/openssl/extconf.rb: check for EVP_CIPHER_CTX_copy, ENGINE_add, EVP_CIPHER_CTX_set_padding, EVP_CipherFinal_ex, EVP_CipherInit_ex, EVP_DigestFinal_ex and EVP_DigestInit_ex. * ext/openssl/openssl_missing.c (EVP_CIPHER_CTX_copy): new function. * ext/openssl/openssl_missing.h (EVP_DigestInit_ex, EVP_DigestFinal_ex, EVP_CipherInit_ex, EVP_CipherFinal_ex, HMAC_Init_ex): new macro for OpenSSL 0.9.6. * ext/openssl/ossl_cipher.c (ossl_cipher_encrypt, ossl_cipher_decrypt): re-implemnt (the arguments for this method is ). * ext/openssl/ossl_cipher.c (ossl_cipher_pkcs5_keyivgen): new method OpenSSL::Cipher::Cipher#pkcs5_keyivgen. it calls EVP_BytesToKey(). * ext/openssl/ossl_cipher.c (ossl_cipher_alloc, ossl_cipher_initialize, ossl_cipher_copy, ossl_cipher_reset ossl_cipher_final, ossl_cipher_set_key, ossl_cipher_set_iv): replace all EVP_CipherInit and EVP_CipherFinal into EVP_CipherInit_ex and EVP_CipherFinal_ex. and EVP_CIPHER_CTX_init should only be called once. * ext/openssl/ossl_cipher.c (ossl_cipher_set_key_length): new method OpenSSL::Cipher::Cipher#key_len=. * ext/openssl/ossl_cipher.c (ossl_cipher_init_deprecated): new finction; print warning for Cipher#<<. * ext/openssl/ossl_digest.c: replace all EVP_DigestInit and EVP_DigestFinal into EVP_DigestInit_ex and EVP_DigestFinal_ex. and EVP_MD_CTX_init should only be called once. * ext/openssl/ossl_digest.c (digest_final): should call EVP_MD_CTX_cleanup to avoid memory leak. * ext/openssl/ossl_hmac.c (ossl_hmac_initialize): repalce HMAC_init into HMAC_init_ex. and HMAC_CTX_init is moved to ossl_hmac_alloc. * ext/openssl/ossl_hmac.c (hmac_final): should call HMAC_CTX_cleanup to avoid memory leak. * test/openssl/test_cipher.rb, test/openssl/test_digest.rb, test/openssl/test_hmac.rb: new file. Thu Jul 1 04:08:30 2004 GOTOU Yuuzou * ext/openssl/ossl_asn1.c (ossl_i2d_ASN1_TYPE, ossl_ASN1_TYPE_free): workaround for the versions earlier than OpenSSL-0.9.7. Thu Jul 1 03:33:55 2004 GOTOU Yuuzou * ext/openssl/ossl_pkey_dh.c (ossl_dh_initialize): should create empty pkey object if no argument is passed. [ruby-talk:103328] * ext/openssl/ossl_pkey_dsa.c (ossl_dsa_initialize): ditto. * ext/openssl/ossl_pkey_rsa.c (ossl_rsa_initialize): ditto. * ext/openssl/ossl_pkey_dh.c: add new methods: OpenSSL::PKey::DH#p, OpenSSL::PKey::DH#p=, OpenSSL::PKey::DH#g, OpenSSL::PKey::DH#g=, OpenSSL::PKey::DH#pub_key, OpenSSL::PKey::DH#pub_key=, OpenSSL::PKey::DH#priv_key and OpenSSL::PKey::DH#priv_key=. * ext/openssl/ossl_pkey_dsa.c: add new methods: OpenSSL::PKey::DSA#p, OpenSSL::PKey::DSA#p=, OpenSSL::PKey::DSA#q, OpenSSL::PKey::DSA#q=, OpenSSL::PKey::DSA#g, OpenSSL::PKey::DSA#g=, OpenSSL::PKey::DSA#pub_key, OpenSSL::PKey::DSA#pub_key=, OpenSSL::PKey::DSA#priv_key and OpenSSL::PKey::DSA#priv_key=. Thu Jul 1 03:16:09 2004 GOTOU Yuuzou * ext/openssl/ossl_ssl.c (ossl_ssl_read): take optional second argument to specify a string to be written. * ext/openssl/lib/openssl/buffering.rb (OpenSSL::Buffering#read): take optional second argument to specify a string to be written. * ext/openssl/lib/openssl/buffering.rb (OpenSSL::Buffering#gets): refine regexp for end-of-line. * ext/opnessl/lib/openssl/ssl.rb (OpenSSL::SSL::SocketForwarder#listen): fix typo. Wed Jun 30 11:38:51 2004 Mikael Brockman * parse.y (primary): should not be NULL. [ruby-core:03098] Wed Jun 30 02:53:24 2004 why the lucky stiff * ext/syck/rubyext.c (syck_emitter_new): set buffer after Data_Wrap_Struct to avoid possible GC. [ruby-talk:104835] Tue Jun 29 10:31:19 2004 Nobuyoshi Nakada * eval.c (rb_eval_cmd, rb_thread_trap_eval): restore safe level. * gc.c (define_final, run_final): preserve and restore safe level for finalizers. [ruby-core:03058] * signal.c (signal_exec, rb_trap_exit, trap): preserve and restore safe level for signal handlers. [ruby-dev:23829] Mon Jun 28 14:57:56 2004 Jeff Mitchell * configure.in, lib/mkmf.rb (LIBPATHFLAG): use double quotes due to DOSISH compilers. [ruby-core:03107] Mon Jun 28 00:30:19 2004 Masatoshi SEKI * sample/drb/*.rb: using 'DRb.thread.join' instead of 'gets' Sun Jun 27 22:39:51 2004 Kouhei Sutou * sample/rss/tdiary_plugin/rss-recent.rb: supported Hiki. Sun Jun 27 12:19:46 2004 Kouhei Sutou * {lib,sample,test}/rss: added RSS Parser. [ruby-dev:23780] Sat Jun 26 11:07:30 2004 Nobuyoshi Nakada * configure.in (aix): -b must come at the start of the command line, and -e must not appear while testing libraries. [ruby-talk:104501] * lib/mkmf.rb (dir_config): quote directory names if necessary. [ruby-talk:104505] Fri Jun 25 15:33:19 2004 Nobuyoshi Nakada * ext/iconv/extconf.rb: check stricter. [ruby-talk:104501] * ext/iconv/extconf.rb: include iconv.h for libiconv. [ruby-dev:22715] Fri Jun 25 08:31:29 2004 Yukihiro Matsumoto * eval.c (rb_thread_atfork): remove "fork terminates thread" warning. [ruby-dev:23768] * object.c (rb_obj_clone): backport FL_FINALIZE patch from 1.9. [ruby-core:02786][ruby-core:03067] * ext/socket/socket.c (sock_sockaddr): Socket#gethostbyname() should give us packed address, not struct sockaddr. [ruby-core:03053] Fri Jun 25 02:04:23 2004 NAKAMURA Usaku * {bcc32,win32,wince}/setup.mak: remove RUBY_EXTERN lines when including version.h. [ruby-talk:104456] (backported from HEAD) Thu Jun 24 14:23:29 2004 Nobuyoshi Nakada * io.c (rb_io_fread): return already read data when system call is interrupted. [ruby-talk:97206] Thu Jun 24 01:32:43 2004 Shugo Maeda * version.h: added declarations of ruby_version, ruby_release_date, ruby_platform. (backported from HEAD) Wed Jun 23 22:23:37 2004 Dave Thomas * ext/socket/socket.c (sock_s_gethostbyaddr): Work around problem with OS X not returning 'from' parameter to recvfrom for connection-oriented sockets. Wed Jun 23 01:45:27 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RubyLex::identify_quotation): Fix problem with the 'r' being dropped from %r{xxx} Wed Jun 23 00:20:20 2004 Hirokazu Yamamoto * ext/win32ole/win32ole.c (ole_hresult2msg): remove trailing CRs and LFs. (doesn't depend on CR+LF) [ruby-dev:23749] Wed Jun 23 00:00:25 2004 Nobuyoshi Nakada * io.c (rb_io_initialize): should check fcntl result. [ruby-dev:23742] Tue Jun 22 21:11:36 2004 Masaki Suketa * ext/win32ole/win32ole.c (OLE_FREE): should not call CoFreeUnuse- dLibraries(). * ext/win32ole/win32ole.c (ole_event_free): ditto. * ext/win32ole/win32ole.c (ole_hresult2msg): truncate error message before CR. Tue Jun 22 16:47:42 2004 Shugo Maeda * lib/net/ftp.rb (MDTM_REGEXP): fix for demon's ftp server. Thanks, Rutger Nijlunsing. Mon Jun 21 10:19:23 2004 NAKAMURA Usaku * win32/win32.c (rb_w32_opendir): use FindFirstFile()/FindNextFile()/ FindClose() instead of _findfirst()/_findnext()/_findclose(). merge from HEAD. Sat Jun 19 13:24:15 2004 Nobuyoshi Nakada * eval.c (method_call): allow changing $SAFE. [ruby-dev:23713] Fri Jun 18 23:12:22 2004 Nobuyoshi Nakada * eval.c (proc_save_safe_level, rb_set_safe_level, safe_setter): limit safe level. Wed Jun 16 23:05:57 2004 Yukihiro Matsumoto * object.c (rb_mod_freeze): prepare string representation before freezing. [ruby-talk:103646] Wed Jun 16 16:04:40 2004 Nobuyoshi Nakada * object.c (rb_mod_le): singleton class inherits Class rather than its object's class. [ruby-dev:23690] Wed Jun 16 16:01:17 2004 Nobuyoshi Nakada * gc.c (stack_grow_direction): memoize the direction. * gc.c (Init_stack): should always move to end of VALUE. Tue Jun 15 12:10:04 2004 Hidetoshi NAGAI * ext/tk/lib/tk.rb: bug fix (TkWindow#grab) Mon Jun 14 18:23:27 2004 Hidetoshi NAGAI * ext/tk/lib/remote-tk.rb: bug fix Sun Jun 13 00:23:04 2004 Hidetoshi NAGAI * ext/tcltklib/extconf.rb: [EXPERIMENTAL] MacOS X (darwin) support * ext/tcltklib/tcltklib.c: fix thread trouble on callback proc, and eliminate warning about instance variable access * ext/tk/lib/tk/menubar.rb: improve supported menu_spec * ext/tk/lib/tk/menuspec.rb: [add] menu_spec support library * ext/tk/lib/tk/root.rb: add menu_spec support * ext/tk/lib/tk/text.rb: bug fix * ext/tk/lib/tk/toplevel.rb: add menu_spec support * ext/tk/sample/menubar?.rb: [add] sample of menu_spec usage Sat Jun 12 11:15:53 2004 WATANABE Hirofumi * configure.in (target_os): strip -gnu suffix on Linux. Fri Jun 11 17:08:21 2004 Akinori MUSHA * config.guess: Restore a wrongly removed hyphen. Fri Jun 11 14:30:08 2004 Akinori MUSHA * config.guess: Attempt to avoid system name change on Darwin platforms also. Fri Jun 11 14:22:45 2004 Akinori MUSHA * config.guess, config.sub: Attempt to avoid system name change on Linux platforms. We have been using "linux" instead of "linux-gnu" on this branch. Thu Jun 10 19:19:41 2004 Yukihiro Matsumoto * ext/sdbm/init.c (fsdbm_store): sdbm should use StringValue(). [ruby-talk:103062] Wed Jun 9 18:04:14 2004 akira yamada * lib/uri/generic.rb (URI::Generic::merge, URI::Generic::route_from): accepts non-hierarchical URI. [ruby-dev:23631] * test/uri/test_generic.rb (TestGeneric::test_route, TestGeneric::test_merge): added tests for above changes. Wed Jun 9 17:39:37 2004 Akinori MUSHA * config.guess, config.sub: Update to a more recent version as of 2004-01-20. * configure.in: Add support for DragonFly BSD. Wed Jun 2 20:16:03 2004 Nobuyoshi Nakada * string.c (str_new4): should share shared instance if it already exists. [ruby-dev:23665] Wed Jun 2 12:41:53 2004 Yukihiro Matsumoto * io.c (rb_io_gets_m): set lastline ($_) even when read line is nil. [ruby-dev:23663] Fri May 28 11:20:31 2004 Nobuyoshi Nakada * eval.c (rb_eval): bad influence on frame node. * eval.c (eval): reverted wrongly removed condition. [ruby-dev:23638] Thu May 27 23:15:18 2004 NAKAMURA, Hiroshi * lib/logger.rb: leading 0 padding of timestamp usec part. * lib/csv.rb (CSV.parse): [CAUTION] behavior changed. in the past, CSV.parse accepts a filename to be read-opened (it was just a shortcut of CSV.open(filename, 'r')). now CSV.parse accepts a string or a stream to be parsed e.g. CSV.parse("1,2\n3,r") #=> [['1', '2'], ['3', '4']] * lib/csv.rb: CSV::Row and CSV::Cell are deprecated. these classes are removed in the future. in the new csv.rb, row is represented as just an Array. since CSV::Row was a subclass of Array, it won't hurt almost all programs except one which depended CSV::Row#match. and a cell is represented as just a String or nil(NULL). this change will cause widespread destruction. CSV.open("foo.csv", "r") do |row| row.each do |cell| if cell.is_null # using Cell#is_null p "(NULL)" else p cell.data # using Cell#data end end end must be just; CSV.open("foo.csv", "r") do |row| row.each do |cell| if cell.nil? p "(NULL)" else p cell end end end * lib/csv.rb: [CAUTION] record separator(CR, LF, CR+LF) behavior change. CSV.open, CSV.parse, and CSV,generate now do not force opened file binmode. formerly it set binmode explicitly. with CSV.open, binmode of opened file depends the given mode parameter "r", "w", "rb", and "wb". CSV.parse and CSV.generate open file with "r" and "w". setting mode properly is user's responsibility now. * lib/csv.rb: accepts String as a fs (field separator/column separator) and rs (record separator/row separator) * lib/csv.rb (CSV.read, CSV.readlines): added. works as IO.read and IO.readlines in CSV format. * lib/csv.rb: added CSV.foreach(path, rs = nil, &block). CSV.foreach now does not handle "| cmd" as a path different from IO.foreach. needed? * test/csv/test_csv.rb: updated. * test/ruby/test_float.rb: added test_strtod to test Float("0"). Thu May 27 21:37:50 2004 Tanaka Akira * lib/pathname.rb (Pathname#initialize): refine pathname initialization by pathname. Thu May 27 20:22:05 2004 Hirokazu Yamamoto * io.c (rb_io_fwrite): check all case errno != 0 [ruby-dev:23648] Thu May 27 14:53:13 2004 WATANABE Hirofumi * io.c (rb_io_fwrite): workaround for bcc32's fwrite bug. add errno checking. [ruby-dev:23627] Wed May 26 14:19:42 2004 Nobuyoshi Nakada * eval.c (rb_eval, eval): make line number consistent on eval with Proc. [ruby-talk:101253] Wed May 26 13:59:17 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::skip_for_variable): Allow for 'do' after for statement Wed May 26 13:56:03 2004 Dave Thomas * lib/rdoc/generators/html_generator.rb (Generators::MarkUp::style_url): Fix relative path to code CSS file Wed May 26 13:14:52 2004 Nobuyoshi Nakada * io.c (rb_io_init_copy): copy also positions. [ruby-talk:100910] Wed May 26 00:00:00 2004 why the lucky stiff * ext/syck/syck.c (syck_new_parser): clear parser on init. thanks, ts. [ruby-core:02931] * ext/syck/token.c (sycklex_yaml_utf8): buffer underflow. thanks, ts. [ruby-core:02929] * lib/yaml/baseemitter.rb (indent_text): simpler flow block code. * lib/yaml.rb: added rdoc to beginning of lib. Mon May 24 10:46:26 2004 Kazuhiro NISHIYAMA * lib/rdoc/generators/template/html/html.rb: SYSTEM identifiers must be absolute URIs Sat May 22 12:00:04 2004 Nobuyoshi Nakada * MANIFEST: add new encodings in rexml. * ext/tk/MANIFEST: add recent files. Sat May 22 05:37:11 2004 Hidetoshi NAGAI * ext/tk/lib/remote-tk.rb: (NEW library) controll Tk interpreters on the other processes by Tcl/Tk's 'send' command Fri May 21 09:22:05 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_method_parameters): Add ()'s around parameters that don't have them Thu May 20 17:02:03 2004 Nobuyoshi Nakada * lib/mkmf.rb (check_sizeof): define result size. [ruby-core:02911] * lib/mkmf.rb (create_header): macro name should not include equal sign. Thu May 20 15:59:50 2004 Hirokazu Yamamoto * ext/socket/socket.c: fix SEGV. [ruby-dev:23550] Thu May 20 14:35:52 2004 Tanaka Akira * ext/socket/socket.c: check SCM_RIGHTS macro addition to the msg_control field to test existence of file descriptor passing by msg_control. Thu May 20 12:38:06 2004 Yukihiro Matsumoto * numeric.c (flo_eq): always check if operands are NaN. [ruby-list:39685] Thu May 20 12:34:39 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_visibility): At Ryan Davis' suggestion, honor visibility modifers if guarded by a statement modifier Thu May 20 12:22:13 2004 Nobuyoshi Nakada * lib/mkmf.rb (have_type): do not check pointer to incomplete type, which always get compiled. [ruby-list:39683] Wed May 19 11:09:00 2004 Hidetoshi NAGAI * ext/tk/lib/tk.rb: change permition of TkObject#tk_send from private to public Tue May 18 14:00:46 2004 Nobuyoshi Nakada * node.h (NEW_DSTR): adjust list length. * parse.y (literal_concat): ditto. Mon May 17 16:14:25 2004 Hirokazu Yamamoto * numeric.c (flo_to_s): it's preferable that "p 0.0" outputs "0.0" instead of "0.0e+00". [ruby-dev:23480] * numeric.c (flo_to_s): it's preferable that "p 0.00000000000000000001" outputs "1.0e-20" instead of "9.999999999999999e-21". (the precision is considered, but there is assumption DBL_DIG == 15 in current implementation) Mon May 17 10:13:33 2004 Yukihiro Matsumoto * ext/socket/socket.c (setup_domain_and_type): honor duck typing. [ruby-dev:23522] * ext/socket/socket.c (sock_s_getnameinfo): ditto. Mon May 17 01:15:23 2004 why the lucky stiff * lib/yaml.rb: removed fallback to pure Ruby parser. * lib/yaml/baseemitter.rb (indent_text): was forcing a mod value of zero at times, which kept some blocks from getting indentation. * lib/yaml/baseemitter.rb (node_text): rewriting folded scalars. * ext/syck/syck.h: reports style of scalars now, be they plain, block single-, or double-quoted. * ext/syck/syck.c: ditto. * ext/syck/gram.c: ditto. * ext/syck/node.c: ditto. * ext/syck/token.c: ditto. * ext/syck/rubyext.c (yaml_org_handler): symbols loaded only if scalar style is plain. * ext/syck/rubyext.c (yaml_org_handler): some empty strings were loaded as symbols. * test/yaml/test_yaml.rb (test_perl_regexp): updated test to match new regexp serialization. Mon May 17 00:03:00 2004 Gavin Sinclair * lib/drb/drb.rb: Cosmetic documentation changes. Sun May 16 22:36:00 2004 Gavin Sinclair * lib/test/unit.rb: Removed :nodoc: directive (it prevented effective RDoc operation), and added file-level comment. Sun May 16 20:55:49 2004 Tanaka Akira * ext/dbm/dbm.c (fdbm_initialize): accept optional 3rd argument to specify an open flag. (Init_dbm): define open flags: DBM::READER, DBM::WRITER, DBM::WRCREAT and DBM::NEWDB. Sun May 16 13:10:00 2004 Gavin Sinclair * lib/test/unit/**/*.rb: Removed :nodoc: directives (many were generating warnings, many were on private methods). Sat May 15 01:41:34 2004 Yukihiro Matsumoto * eval.c (eval): forgot to restore $SAFE value before evaluating compiled node. [ruby-core:02872] Sat May 15 01:33:12 2004 Yukihiro Matsumoto * range.c (range_each_func): terminates loop if generating value is same to @end. [ruby-talk:100269] Fri May 14 22:08:38 2004 Yukihiro Matsumoto * string.c (rb_str_new4): should not reuse frozen shared string if the original is not an instance of String. [ruby-talk:100193] Fri May 14 18:39:25 2004 Hidetoshi NAGAI * ext/tk/lib/tk/canvas.rb: improve coords support for canvas items. Now, supports all of the followings. TkcLine.new(c, 0, 0, 100, 100, :fill=>'red') TkcLine.new(c, [0, 0, 100, 100], :fill=>'red') TkcLine.new(c, [0, 0], [100, 100], :fill=>'red') TkcLine.new(c, [[0, 0], [100, 100]], :fill=>'red') TkcLine.new(c, :coords=>[0, 0, 100, 100], :fill=>'red') TkcLine.new(c, :coords=>[[0, 0], [100, 100]], :fill=>'red') Fri May 14 12:11:43 2004 Hirokazu Yamamoto * util.c (ruby_strtod): strtod("0", &end); => end should point '\0'. [ruby-dev:23498] Thu May 13 15:47:30 2004 akira yamada * lib/net/telnet.rb (Net::Telnet::login): "options" can specify regexps for login prompt and/or password prompt. Thu May 13 14:23:45 2004 WATANABE Hirofumi * hash.c (delete_if_i): use st_delete_safe() (via rb_hash_delete()) instead of returning ST_DELETE. backport from HEAD. [ruby-dev:23487] Thu May 13 13:01:30 2004 akira yamada * lib/uri/mailto.rb (URI::MailTo::to_s): should include fragment. Thu May 13 11:04:08 2004 Nobuyoshi Nakada * pack.c (pack_pack): always add with null for 'Z'. * pack.c (pack_unpack): terminated by null for 'Z'. [ruby-talk:98281] Wed May 12 19:59:43 2004 Nobuyoshi Nakada * lib/mkmf.rb (have_type, check_sizeof): replace unusable characters. [ruby-talk:99788] Wed May 12 17:41:42 2004 Tanaka Akira * lib/resolv.rb (Resolv::DNS::Config): make it configurable without external file such as /etc/resolv.conf. Wed May 12 14:37:27 2004 GOTOU Yuuzou * ext/openssl/ossl_x509name.c: attribute value of DC (short name of domainComponent) should be IA5String. Wed May 12 13:20:19 2004 Hidetoshi NAGAI * ext/tk/lib/tk/composite.rb: improve configure methods (based on the proposal of [ruby-talk:99671]). Wed May 12 11:51:08 2004 Dave Thomas * class.c (rb_obj_singleton_methods): fix rdoc Mon May 10 21:44:42 2004 Dave Thomas * lib/rdoc/generators/html_generator.rb: Change scheme for looking up symbols in HTML generator. Mon May 10 16:45:21 2004 Yukihiro Matsumoto * eval.c (eval): warning during eval should not cause deadlock. [ruby-talk:98651] * eval.c (rb_eval): raise TypeError exception for superclass mismatch. [ruby-list:39567] Mon May 10 12:11:37 2004 Dave Thomas * lib/rdoc/generators/html_generator.rb: Hack to search parents for unqualified constant names. Mon May 10 12:11:37 2004 Dave Thomas * lib/rdoc/generators/html_generator.rb: Hack to search parents for unqualified constant names. Sun May 9 22:37:00 2004 Gavin Sinclair * lib/net/ftp.rb: improved documentation * lib/net/imap.rb: ditto * lib/net/pop.rb: ditto * lib/net/smtp.rb: ditto * lib/net/telnet.rb: ditto Fri May 7 21:50:21 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RDoc::parse_include): Allow multiple arguments to 'include' Fri May 7 21:31:56 2004 Minero Aoki * lib/fileutils.rb (fu_list): Array() breaks pathes including "\n". [ruby-core:02843] Fri May 7 11:25:53 2004 Hirokazu Yamamoto * util.c (ruby_strtod): "0.0000000000000000001" should be converted to 1.0e-19 instead of 0.0. (leading zeros aren't significant digits) [ruby-talk:99318] [ruby-dev:23465] Fri May 7 10:00:05 2004 Hidetoshi NAGAI * ext/tk/tkutil.c (get_eval_string_core): bug fix. [ruby-dev:23466] Thu May 6 22:13:17 2004 Masatoshi SEKI * ext/socket/socket.c (ippaddr): use NUMERICHOST if can not resolve hostname. Thu May 6 14:22:29 2004 why the lucky stiff * lib/yaml/rubytypes.rb (to_yaml): added instance variable handling for Ranges, Strings, Structs, Regexps. * lib/yaml/rubytypes.rb (to_yaml_fold): new method for setting a String's flow style. * lib/yaml.rb (YAML::object_maker): now uses Object.allocate. * ext/syck/gram.c: fixed transfer methods on structs, broke it last commit. Thu May 6 11:40:28 2004 Shugo Maeda * lib/net/imap.rb (string): accept NIL. * lib/net/imap.rb (body_type_basic): allow body-fields omissions. Thu May 6 01:59:04 2004 Dave Thomas * lib/rdoc/generators/html_generator.rb (Generators::HtmlMethod::params): Don't include the &block parameter if we have explicit yield parameters. Wed May 5 03:40:29 2004 Masatoshi SEKI * lib/rinda/ring.rb: use recv instead of recvfrom. Tue May 4 23:52:00 2004 Gavin Sinclair * lib/gserver.rb: documented Tue May 4 23:46:00 2004 Gavin Sinclair * lib/xmlrpc/README.txt: introduced for documentation purposes Mon May 3 09:47:24 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_method_or_yield_parameters): Fix parsing bug if yield called within 1 line block Sun May 2 01:04:38 2004 Hidetoshi NAGAI * ext/tcltklib, ext/tk: renewal Ruby/Tk Fri Apr 30 20:08:41 2004 WATANABE Hirofumi * time.c (SIZEOF_TIME_T): support SIZEOF_TIME_T == SIZEOF_INT. Tue Apr 27 13:12:42 2004 Yukihiro Matsumoto * eval.c (rb_eval): too many line trace call. (ruby-bugs PR#1320) Tue Apr 27 08:41:28 2004 why the lucky stiff * lib/yaml/rubytypes.rb: passing Range tests. * ext/syck/syck.h: version 0.44. * ext/syck/gram.c: transfers no longer open an indentation. fixed transfers which precede blocks. * ext/syck/token.c: ditto. * ext/syck/syck.c: fixed segfault if an anchor has been released already. * ext/syck/node.c (syck_free_members): organized order of free'd nodes. * ext/syck/rubyext.c (syck_emitter_write_m): test for proper string with StringValue. Mon Apr 26 23:56:54 2004 Daniel Kelley * README.EXT, README.EXT.ja: fixed wrong function signature. [ruby-talk:98349] Mon Apr 26 21:40:09 2004 Dave Thomas * lib/rdoc/code_objects.rb (RDoc::Context::add_alias): Only alias to instance methods. Sat Apr 24 10:38:31 2004 Dave Thomas * lib/rdoc/markup/simple_markup.rb (SM::SimpleMarkup::group_lines): Fix bug where consecutive headings are merged. Fri Apr 23 23:26:13 2004 Nobuyoshi Nakada * lib/mkmf.rb: $hdrdir should not contain macros for backward compatibility. [bruby-dev:28] * version.c (ruby_show_copyright): obtain copyright year from RUBY_RELEASE_YEAR. * win32/resource.rb: ditto. * win32/resource.rb: default rubyw icon to ruby.ico, and let DLL also include them. * win32/resource.rb: include winver.h for older WindowsCE. Fri Apr 23 16:38:46 2004 Tanaka Akira * lib/pathname.rb: sync taint/freeze flag between a pathname object and its internal string object. Fri Apr 23 14:52:08 2004 Nobuyoshi Nakada * parse.y (stmt, arg, aref_args): should not make sole splat into array, in aref_args other than aref with op_asgn. Fri Apr 23 14:14:38 2004 Tanaka Akira * lib/resolv.rb: don't use Regexp#source to embed regexps. [ruby-dev:23432] Thu Apr 22 04:15:36 2004 Nobuyoshi Nakada * parse.y (aref_args): should pass expanded list. [ruby-core:02793] Thu Apr 22 01:12:57 2004 Yukihiro Matsumoto * numeric.c (flo_to_s): tweak output string based to preserve decimal point and to remove trailing zeros. [ruby-talk:97891] * string.c (rb_str_index_m): use unsigned comparison for T_FIXNUM search. [ruby-talk:97342] Wed Apr 21 22:57:27 2004 Masatoshi SEKI * lib/rinda/rinda.rb, test/rinda/test_rinda.rb: check Hash tuple size. Wed Apr 21 20:05:00 2004 Tanaka Akira * lib/open-uri.rb (URI::HTTP#proxy_open): set Host: field explicitly. [ruby-list:39542] Mon Apr 19 18:11:15 2004 Yukihiro Matsumoto * hash.c (rb_hash_equal): returns true if two hashes have same set of key-value set. [ruby-talk:97559] * hash.c (rb_hash_eql): returns true if two hashes are equal and have same default values. Mon Apr 19 08:19:58 2004 Doug Kearns * dln.c, io.c, lib/benchmark.rb, lib/cgi.rb, lib/csv.rb, lib/date.rb, lib/ftools.rb, lib/getoptlong.rb, lib/logger.rb, lib/matrix.rb, lib/monitor.rb, lib/set.rb, lib/thwait.rb, lib/timeout.rb, lib/yaml.rb, lib/drb/drb.rb, lib/irb/workspace.rb, lib/net/ftp.rb, lib/net/http.rb, lib/net/imap.rb, lib/net/telnet.rb, lib/racc/parser.rb, lib/rinda/rinda.rb, lib/rinda/tuplespace.rb, lib/shell/command-processor.rb, lib/soap/rpc/soaplet.rb, lib/test/unit/testcase.rb, lib/test/unit/testsuite.rb: typo fix. Mon Apr 19 08:14:18 2004 Dave Thomas * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser::find_body): Allow for #ifdef HAVE_PROTOTYPES Fri Apr 16 22:33:00 2004 Gavin Sinclair * ext/iconv/iconv.c: nearly finished RDoc comments. Fri Apr 16 17:04:07 2004 Yukihiro Matsumoto * string.c (rb_str_equal): always returns true or false, never returns nil. [ruby-dev:23404] Fri Apr 16 08:27:02 2004 Nobuyoshi Nakada * ext/extmk.rb: skip linking when libraries to be preloaded not compiled. [ruby-list:39561] Thu Apr 15 23:21:52 2004 Nobuyoshi Nakada * process.c (pst_success_p): new method Process::Status#success?. [ruby-dev:23385] Thu Apr 15 17:12:13 2004 Tanaka Akira * ext/gdbm/gdbm.c (Init_gdbm): define GDBM::READER, GDBM::WRITER, GDBM::WRCREAT and GDBM::NEWDB. (fgdbm_initialize): use specified read/write flag. Wed Apr 14 11:29:56 2004 WATANABE Hirofumi * numeric.c (flo_eq): workaround for bcc32's bug. (ruby-bugs-ja:PR#594) Wed Apr 14 13:06:35 2004 Doug Kearns * array.c, enum.c, eval.c, file.c, io.c, numeric.c, object.c, prec.c, process.c, re.c, string.c: typos in RDoc comments. [ruby-core:02783] Wed Apr 14 11:06:38 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::scan): Changed behavior of :enddoc: -- it now unconditionally terminates processing of the current file. Wed Apr 14 11:03:22 2004 Hirokazu Yamamoto * defines.h: include to get fd_set definition in BeOS. Tue Apr 13 23:06:30 2004 Masatoshi SEKI * lib/rinda/rinda.rb: change pattern matching. a === b -> a == b || a === b. [druby-ja:98] * test/rinda/test_rinda.rb: ditto. Tue Apr 13 19:54:29 2004 Minero Aoki * lib/net/http.rb: should not overwrite HTTP request header. [ruby-list:39543] Tue Apr 13 01:30:00 2004 Gavin Sinclair * ext/iconv/iconv.c: RDoc documentation (from RD; nearly finished). * ext/iconv/charset_alias.rb: Prevent from RDoc'ing. Mon Apr 12 19:11:29 2004 Eric Hodel * gc.c (rb_gc_copy_finalizer): typo. [ruby-core:02774] Mon Apr 12 18:52:32 2004 GOTOU Yuuzou * ext/openssl/ossl_x509name.c (ossl_x509name_init_i): should return a value. Mon Apr 12 10:43:47 2004 Hirokazu Yamamoto * dir.c (rb_glob2, rb_glob, rb_globi, push_globs, push_braces, rb_push_glob): fix memory leak. (leaked when block was interrupted) Mon Apr 12 10:27:37 2004 Hirokazu Yamamoto * bcc32/Makefile.sub: backport SIZEOF_TIME_T definition from 1.9. * win32/Makefile.sub: ditto. * wince/Makefile.sub: ditto. Sun Apr 11 19:12:35 2004 Nobuyoshi Nakada * ruby.c (require_libraries): restore source file/line after statically linked extensions initialized. [ruby-dev:23357] Sun Apr 11 10:47:04 2004 Dave Thomas * lib/rdoc/code_objects.rb (RDoc::TopLevel::add_class_or_module): Toplevel classes and modules are a special case too... (handle extending existing classes with or without :enddoc:) Sat Apr 10 23:51:13 2004 Dave Thomas * lib/rdoc/code_objects.rb (RDoc::Context::add_to): Implementation of :enddoc: made one too many assumptions... Sat Apr 10 00:00:19 2004 Dave Thomas * lib/rdoc/markup/simple_markup/inline.rb: Fix problem with \_cat_dog Wed Apr 7 00:19:50 2004 Masatoshi SEKI * lib/rinda/rinda.rb: fix hash tuple bug. * lib/rinda/tuplespace.rb: ditto. * test/rinda/test_rinda.rb Tue Apr 6 18:24:18 2004 Yukihiro Matsumoto * io.c (rb_io_reopen): should use rb_io_check_io(). Tue Apr 6 16:46:09 2004 Tanaka Akira * configure.in: check the size of time_t. * time.c (time_add): new function. (time_plus): use time_add. (time_minus): use time_add. Tue Apr 6 13:21:30 2004 NAKAMURA Usaku * ext/socket/socket.c (make_hostent): must return value. Tue Apr 6 00:05:30 2004 Masatoshi SEKI * lib/rinda/rinda.rb: add require 'drb/drb' Mon Apr 5 08:18:23 2004 Dave Thomas * lib/rdoc/rdoc.rb: Remove leading ./ from file names so that cross references work properly. Sun Apr 4 20:33:42 2004 Minero Aoki * eval.c (Init_load): make $LOADED_FEATURES built-in. [ruby-dev:23299] * ruby.c (ruby_prog_init): make $PROGRAM_NAME built-in. * lib/English.rb: remove $LOADED_FEATURES and $PROGRAM_NAME. Sun Apr 4 14:01:20 2004 Dave Thomas * lib/rdoc/options.rb (Options::parse): Allow multiple -x options to RDoc. Fix bug where files weren't being excluded properly Sat Apr 3 17:11:05 2004 why the lucky stiff * ext/syck/syck.h: version 0.43. * ext/syck/lib/gram.c: allow root-level inline collections. [ruby-talk:94922] * lib/yaml/rubytypes.rb (Symbol#to_yaml): emit symbols as implicits. [ruby-talk:94930] * ext/syck/bytecode.c: turn off default implicit typing. * ext/syck/implicit.c: detect base60 integers. * ext/syck/rubyext.c: handle base60, as well as hex and octal with commas. implicit typing of ruby symbols. Fri Apr 2 17:27:17 2004 Yukihiro Matsumoto * eval.c (top_include): include in the wrapped load is done for the wrapper, not for a singleton class for wrapped main. [ruby-dev:23305] Fri Apr 2 15:13:44 2004 Yukihiro Matsumoto * bignum.c (rb_big_eq): use temporary double variable to save the result (internal float register may be bigger than 64 bits, for example, 80 bits on x86). [ruby-dev:23311] Fri Apr 2 14:35:26 2004 Yukihiro Matsumoto * eval.c (block_pass): should generate unique identifier of the pushing block. [ruby-talk:96363] Fri Apr 2 07:31:38 2004 Yukihiro Matsumoto * ext/socket/socket.c (make_hostent): fix memory leak, based on the patch from HORIKAWA Hisashi . Thu Apr 1 22:55:33 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb: Allow rdoc comments in =begin rdoc/=end * lib/rdoc/parsers/parse_rb.rb: Fix problem with comment in top-level method being taken as file comment. Thu Apr 1 22:55:04 2004 Dave Thomas * lib/rdoc/ri/ri_options.rb: Fix undefined variable warning. Thu Apr 1 19:58:37 2004 NAKAMURA, Hiroshi * lib/soap/mapping/{factory.rb,registry.rb}: fixed illegal mapped URI object with soap/marshal. added URIFactory class for URI mapping. BasetypeFactory checks instance_variables when original mapping is not allowed (ivar must be empty). Instance of URI have instance_variables but it must be llowed whenever original mapping is allowed or not. * lib/xsd/datatypes.rb: check the smallest positive non-zero single-precision float exactly instead of packing with "f". [ruby-talk:88822] * lib/soap/mapping/rubytypeFactory.rb: should not dump singleton class. [ruby-dev:22588] c = class << Object.new; class C; self; end; end; SOAPMarshal.dump(c) Wed Mar 31 19:06:23 2004 Tanaka Akira * time.c (year_leap_p): new function. (timegm_noleapsecond): ditto. (search_time_t): use timegm_noleapsecond instead of mktime for first guess. Wed Mar 31 12:04:04 2004 Nobuyoshi Nakada * lib/delegate.rb (DelegateClass): define internal methods of the result class, but not metaclass of the caller. [ruby-talk:96156] * intern.h: provide proper prototypes. [ruby-core:02724] * ruby.h: missing.h is now prerequisite to intern.h. Tue Mar 30 20:25:34 2004 Tanaka Akira * time.c (search_time_t): limit guess range by mktime if it is available. [ruby-dev:23274] Sun Mar 28 14:16:59 2004 Minero Aoki * lib/net/pop.rb (auth): failed when account/password include "%". [ruby-talk:95933] Sat Mar 27 21:40:41 2004 Tanaka Akira * lib/open-uri.rb: permit extra semicolon in content-type field. Sat Mar 27 10:40:48 2004 Tanaka Akira * (lib/pp.rb, lib/prettyprint.rb): define seplist in PP::PPMethods instead of PrettyPrint. Thu Mar 25 23:28:52 2004 Yukihiro Matsumoto * time.c (time_overflow_p): backport 1.9 usec overflow function. (ruby-bugs PR#1307) Thu Mar 25 23:15:24 2004 Dave Thomas * lib/rdoc/ri/ri_options.rb (RI::Options::show_version): Add --version option Thu Mar 25 04:16:18 2004 Dave Thomas * lib/rdoc/ri/ri_options.rb (RI::Options): Add the --list-names option, which dumps our all known names Thu Mar 25 03:57:47 2004 Dave Thomas * lib/rdoc/ri/ri_util.rb (NameDescriptor::initialize): No longer allow nested classes to be designated using "."--you must now use "::" Thu Mar 25 02:00:18 2004 Dave Thomas * lib/rdoc/generators/template/html/one_page_html.rb (Page): Fix to work with C modules. Wed Mar 24 21:17:00 2004 Gavin Sinclair * lib/uri.rb: Documented (thanks Dmitry V. Sabanin). * lib/uri/common.rb: Ditto. * lib/uri/ftp.rb: Ditto. * lib/uri/generic.rb: Ditto. * lib/uri/http.rb: Ditto. * lib/uri/https.rb: Ditto. * lib/uri/ldap.rb: Ditto. * lib/uri/mailto.rb: Ditto. (All backported from 1.9) Wed Mar 24 18:48:26 2004 Nobuyoshi Nakada * lib/mkmf.rb ($ruby, $topdir, $hdrdir): should not be affected by DESTDIR after installed. * lib/mkmf.rb (RUBY): / is not recognized as path separator on nmake/bmake. [ruby-list:39388] * lib/mkmf.rb (init_mkmf): $INCFLAGS also should be lazy-evaluated. Wed Mar 24 12:32:56 2004 Dave Thomas * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser::handle_class_module): Don't document methods if we don't know for sure the class or module. * lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_class): Don't store documentation for singleton classes if we don't know the real class. Wed Mar 24 11:11:26 2004 Dave Thomas * lib/rdoc/generators/html_generator.rb (Generators::HTMLGenerator::load_html_template): Allow non-RDoc templates by putting a slash in the template name Mon Mar 22 16:19:57 2004 WATANABE Hirofumi * ruby.1: add -width option to .Bl for old groff. Sun Mar 21 21:11:16 2004 Keiju Ishitsuka * lib/shell/*: bug fix for Shell#system(command_line_string). Sat Mar 20 20:57:10 2004 David Black * lib/scanf.rb: Backported 1.9 branch modifications/corrections to 1.8 branch Sat Mar 20 23:51:03 2004 WATANABE Hirofumi * eval.c (rb_require_safe): preserve old ruby_errinfo. [ruby-talk:95409] * eval.c (rb_f_raise): should not clear backtrace information if exception object already have one. Sat Mar 20 15:25:36 2004 Dave Thomas * lib/rdoc/generators/template/html/html.rb (RDoc::Page): Force page background to white. Sat Mar 20 09:52:33 2004 Tadayoshi Funaba * lib/date.rb, lib/date/format.rb: _parse() now accepts fractional part of second minute that follows a comma or a full stop. Fri Mar 19 01:55:57 2004 Mauricio Fernandez * io.c (rb_io_sync): need not to check writable. [ruby-core:02674] Thu Mar 18 21:44:38 2004 Masatoshi SEKI * lib/drb/drb.rb: backport drb.rb 1.16. Fri Mar 18 17:49:51 2005 Yukihiro Matsumoto * struct.c (make_struct): allow const_id for accessor names. [ruby-core:04585] * eval.c (rb_attr): check if attribute name is local_id or const_id. Thu Mar 18 16:22:38 2004 Yukihiro Matsumoto * eval.c (proc_eq): avoid false positive by using scope and dyna_vars. no longer use frame.uniq. Wed Mar 17 14:44:43 2004 Hirokazu Yamamoto * dir.c (range): fix possible "\0" overrun. (in case of "\0-") Mon Mar 15 07:39:13 2004 Yukihiro Matsumoto * eval.c (rb_yield_0): should not re-submit TAG_BREAK if this yield is not break destination. [ruby-dev:23197] Sat Mar 13 14:28:16 2004 Masatoshi SEKI * test/drb/test_drbssl.rb: rescue LoadError. (Barkport from main trunk) * test/drb/test_drbunix.rb: ditto. Wed Mar 10 22:28:09 2004 Minero Aoki * lib/fileutils.rb (remove_dir): should handle symlink correctly. This patch is contributed by Christian Loew. [ruby-talk:94635] (Backport from main trunk) Wed Mar 10 16:28:42 2004 Yukihiro Matsumoto * eval.c (return_jump): set return value to the return destination. separated from localjump_destination(). * eval.c (break_jump): break innermost loop (or thread or proc). * eval.c (rb_yield_0): set exit_value for block break. Wed Mar 10 15:58:43 2004 Ryan Davis * eval.c (eval): Only print backtrace if generating the backtrace doesn't generate an exception. [ruby-core:02621] Tue Mar 9 13:04:26 2004 Yukihiro Matsumoto * io.c (rb_io_ungetc): raise IOError instead of calling rb_sys_fail(). [ruby-talk:23181] Mon Mar 8 19:32:28 2004 akira yamada * lib/uri/common.rb (URI::REGEXP::PATTERN::HOSTPORT): (?:#{PORT}) -> (?::#{PORT}). [ruby-dev:23170] Mon Mar 8 15:31:41 2004 Hirokazu Yamamoto * dir.c (range): treat incomplete '[' as ordinary character (like has_magic does). * dir.c (range): Cancel above change. More discussion is needed. Sun Mar 7 22:37:46 2004 Masatoshi SEKI * test/drb/ut_drb.rb: use 'druby://localhost:0'. [ruby-dev:23078] * test/drb/ut_eval.rb: ditto. * test/drb/ut_large.rb: ditto. * test/drb/ut_safe1.rb: ditto. * test/drb/ut_drb_drbssl.rb: use 'drbssl://localhost:0'. Sun Mar 7 16:22:26 2004 WATANABE Hirofumi * Makefile.in (lex.c): use $? instead of $<. Fri Mar 5 00:54:14 2004 Dave Thomas * lib/test/unit.rb: MOve RDoc documentation so that you can now say 'ri Test::Unit' Tue Mar 2 12:32:59 2004 NAKAMURA Usaku * win32/Makefile.sub, wince/Makefile.sub (config.h): shouldn't check defined? NORETURN. [ruby-dev:23100] Mon Mar 1 12:24:10 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_alias): Allow aliases to have parentheses Sun Feb 29 23:14:53 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_class): Handle :nodoc: on singleton classes. Sat Feb 28 10:58:49 2004 Masatoshi SEKI * MANIFEST: add test_erb.rb * lib/erb.rb, test/erb/test_erb.rb: don't forget filename, if both filename and safe_level given. [ruby-dev:23050] Fri Feb 27 01:00:09 2004 Masatoshi SEKI * lib/drb/drb.rb, test/drb/drbtest.rb: require drb/eq.rb by default Wed Feb 25 21:16:25 2004 Nobuyoshi Nakada * instruby.rb (with_destdir): should return the given argument if no DESTDIR is given. * instruby.rb: use path name expansion of cmd.exe. Wed Feb 25 09:35:22 2004 NAKAMURA Usaku * error.c (NameError::Message): new class for lazy evaluation of message to ensure replaced before marshalling. merge from HEAD. (ruby-bugs-ja:PR#588) * eval.c (rb_method_missing): use NameError::Message. merge from HEAD. (ruby-bugs-ja:PR#588) Tue Feb 24 18:59:37 2004 Hirokazu Yamamoto * dir.c (glob_helper): '**/' should not match leading period unless File::FNM_DOTMATCH is set. (like '*/') [ruby-dev:23014] Tue Feb 24 13:22:21 2004 Dave Thomas * lib/rdoc/rdoc.rb (RDoc::RDoc::normalized_file_list): Attempt to get better heuristics on which files to include and exclude. Now only include non-standard files if they are explicitly named in ARGV. Tue Feb 24 07:23:30 2004 Dave Thomas * lib/rdoc/generators/html_generator.rb: Deal with :stopdoc: when choosing a default main page to display (ie. don't select a page if we don't have documentation for it). Tue Feb 24 06:40:14 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RubyLex::identify_identifier): Handle class variables in code listings Tue Feb 24 06:40:14 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RubyLex::identify_identifier): Handle class variables in code listings Tue Feb 24 06:32:27 2004 Dave Thomas * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser::do_aliases): Handle aliases in C files. Tue Feb 24 06:16:22 2004 Dave Thomas * lib/rdoc/rdoc.rb (RDoc::RDoc::document): Now create op dir _before_ parsing files. Tue Feb 24 06:08:47 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_constant): Start collecting text of constant values earlier: was missing values in output if there was no space after '=' Tue Feb 24 06:08:25 2004 Dave Thomas * lib/rdoc/generators/html_generator.rb: Escape contant values. Tue Feb 24 03:45:06 2004 GOTOU Yuuzou * ext/openssl/ossl_config.c (ossl_config_each): add new method OpenSSL::Config#each. it iterates with section name, field name and value. * ext/openssl/ossl_config.c (Init_ossl_config): include Enumerable. Mon Feb 23 09:16:35 2004 Nobuyoshi Nakada * instruby.rb (DOSISH): embedded path in batch files should not be prefixed by DESTDIR. [ruby-core:02186] Sun Feb 22 09:54:00 2004 Gavin Sinclair * re.c: corrected documentation format (again) Sun Feb 22 09:43:00 2004 Gavin Sinclair * re.c: corrected documentation format (rb_reg_initialize_m) Sat Feb 21 22:36:00 2004 Gavin Sinclair * ext/zlib/zlib.c: documented, but needs more effort. Sat Feb 21 11:12:15 2004 Nobuyoshi Nakada * missing/os2.c, missing/x68.c: typo fix. pointed out by greentea. Fri Feb 20 18:59:47 2004 Yukihiro Matsumoto * lib/irb/init.rb (IRB::IRB.parse_opts): add -I option to irb. [ruby-dev:39243] Thu Feb 19 23:24:16 2004 Dave Thomas * lib/rdoc/generators/html_generator.rb (Generators::HtmlClass::build_attribute_list): Support visibility modifiers for attributes Thu Feb 19 23:24:16 2004 Dave Thomas * lib/rdoc/generators/html_generator.rb (Generators::HtmlClass::build_attribute_list): Support visibility modifiers for attributes Thu Feb 19 22:39:04 2004 NAKAMURA, Hiroshi * test/rinda/test_rinda.rb: DRb.start_service only once in testsuites. DRb.start_service could handle this. Thu Feb 19 22:19:00 2004 Gavin Sinclair * lib/ostruct.rb: documented Thu Feb 19 21:28:00 2004 Gavin Sinclair * ext/strscan/strscan.c: improved documentation Thu Feb 19 03:10:52 2004 Minero Aoki * ext/strscan/strscan.c: synchronized with main trunk (rev 1.11). Thu Feb 19 02:30:34 2004 Minero Aoki * ext/strscan/strscan.c: documentation checked. Thu Feb 19 00:11:05 2004 Dave Thomas * lib/rdoc/markup/simple_markup/preprocess.rb (SM::PreProcess::handle): Strip extraneous space from filenames in :include: Wed Feb 18 22:52:00 2004 Masatoshi SEKI * lib/drb/unix.rb: remove O_NONBLOCK, thanks \ay Wed Feb 18 22:47:00 2004 Gavin Sinclair * ext/strscan/strscan.c: documented Wed Feb 18 22:03:11 2004 NAKAMURA, Hiroshi * test/*: should not depend on $KCODE. Wed Feb 18 17:18:01 2004 WATANABE Hirofumi * ext/win32ole/win32ole.c: need to include on Cygwin. Wed Feb 18 10:40:38 2004 Yukihiro Matsumoto * sprintf.c (rb_f_sprintf): do not prepend dots for negative numbers if FZERO is specified. [ruby-list:39218] Tue Feb 17 23:40:34 2004 Guy Decoux * sprintf.c (rb_f_sprintf): preserve original val for format_integer. [ruby-talk:92975] Tue Feb 17 23:28:45 2004 NAKAMURA, Hiroshi * test/ruby/marshaltestlib.rb: common marshal testcase added. * test/ruby/test_marshal.rb: use above testsuite. * test/soap/marshal/test_marshal.rb: ditto. * test/soap/marshal/cmarshal.rb: removed (not used). Tue Feb 17 10:51:23 2004 NAKAMURA Usaku * ext/syck/rubyext.c (syck_emitter_end_object): takes only one arg. Tue Feb 17 01:35:28 2004 Tanaka Akira * eval.c (rb_eval): care that another thread replace NODE_DREGX_ONCE to NODE_LIT. [ruby-dev:22920] Tue Feb 17 01:24:35 2004 Nobuyoshi Nakada * bcc32/Makefile.sub, win32/Makefile.sub (config.h): define STACK_GROW_DIRECTION. [ruby-dev:22910] * bcc32/Makefile.sub (config.h): add newer checks. * wince/Makefile.sub (config.h): define NEED_IO_SEEK_BETWEEN_RW. Tue Feb 17 00:38:10 2004 Masatoshi SEKI * lib/rinda/tuplespace.rb: TupleSpace#initialize, stop doubling timeout Tue Feb 17 00:18:03 2004 Masatoshi SEKI * test/rinda/test_rinda.rb: import test_rinda.rb Tue Feb 17 00:14:30 2004 Hirokazu Yamamoto * bcc32/Makefile.sub: avoid warning "Redefinition of macro 'HAVE_GETLOGIN'". * vms/config.h_in: ditto. Mon Feb 16 23:28:14 2004 NAKAMURA, Hiroshi * lib/csv.rb: document reduction. [ruby-core:02429] Mon Feb 16 22:08:00 2004 Gavin Sinclair * lib/generator.rb: corrected doc format * lib/rinda/rinda.rb: added documentation (from Hugh Sasse) * lib/rinda/tuplespace.rb: ditto Mon Feb 16 20:41:32 2004 Hirokazu Yamamoto * bcc32/Makefile.sub: show more warnings. (refering to mingw) * bcc32/setup.mak: ditto. Mon Feb 16 13:39:44 2004 Hirokazu Yamamoto * dir.c (rb_glob, rb_globi): add const. * ruby.h: ditto. Mon Feb 16 02:16:33 2004 Hirokazu Yamamoto * bcc32/Makefile.sub: should warn suspicious pointer conversion. * bcc32/setup.mak: ditto. Sun Feb 15 19:06:42 2004 Masatoshi SEKI * lib/rinda/tuplespace.rb: TupleSpace#read(tpl, 0), raise RequestExpiredError if not found. Sun Feb 15 15:56:46 2004 Masaki Suketa * ext/win32ole/win32ole.c: add IDispatch wrapper in val2variant. Thanks, arton. Sun Feb 15 01:46:05 2004 GOTOU Yuuzou * lib/mkmf.rb: absolute path of ruby is assigned to $(RUBY). [ruby-dev:22870] Sat Feb 14 11:29:41 2004 Masatoshi SEKI * sample/drb/*: import lib/drb/sample Sat Feb 14 11:08:23 2004 Masatoshi SEKI * lib/drb/drb.rb: add pretty_print, thanks gotoken. Fri Feb 13 12:35:08 2004 Minero Aoki * test/fileutils/test_fileutils.rb: File.link may raise EINVAL and EACCES on Windows. Thu Feb 12 21:45:00 2004 Gavin Sinclair * lib/ftools.rb: documented Thu Feb 12 21:25:00 2004 Gavin Sinclair * lib/base64.rb: backported from HEAD (modularised and documented) Thu Feb 12 20:31:48 2004 Nobuyoshi Nakada * lib/mkmf.rb (create_tmpsrc): cpp32 of Borland C++ ignores #error directives in DOS line-ending files at all. Thu Feb 12 02:23:56 2004 Tanaka Akira * lib/pathname.rb: use assert_raise instead of assert_raises. * lib/pp.rb: ditto. * lib/time.rb: ditto. * lib/tsort.rb: ditto. use TSortHash and TSortArray instead of Hash and Array in test. Wed Feb 11 20:01:12 2004 akira yamada * test/ruby/test_file.rb (TestFile::test_fnmatch): added tests for File.fnmatch. [ruby-dev:22815][ruby-dev:22819] * test/ruby/test_proc.rb (TestProc::test_eq): added a test. [ruby-dev:22599] * test/ruby/test_proc.rb (TestProc::test_eq): added tests for Proc#==. [ruby-dev:22592], [ruby-dev:22601] Tue Feb 10 16:43:56 2004 Nobuyoshi Nakada * eval.c (umethod_bind): purge unused check. [ruby-dev:22850] Mon Feb 9 17:16:00 2004 WATANABE Hirofumi * lib/rdoc/parsers/parse_c.rb: escape '{' and '}' to avoid warnings. Mon Feb 9 13:00:55 2004 Hirokazu Yamamoto * dir.c (fnmatch): File.fnmatch('*?', 'a') should return true. [ruby-dev:22815] * dir.c (fnmatch): File.fnmatch('\[1\]' , '[1]') should return true. [ruby-dev:22819] Sun Feb 8 16:46:13 2004 Nobuyoshi Nakada * lib/pp.rb (PP::PPMethods::object_address_group): suppress negative sign for higher heap areas. Fri Feb 6 22:48:16 2004 Dave Thomas * lib/rdoc/generators/html_generator.rb (gen_url): Support https in RDoc hyperlinks Fri Feb 6 22:41:22 2004 NAKAMURA, Hiroshi * lib/pp.rb (PPInspectTest#test_to_s_with_iv): rollback the previous commit. [ruby-dev:22813] Fri Feb 6 22:22:50 2004 NAKAMURA, Hiroshi * lib/pp.rb (PPInspectTest#test_to_s_with_iv): remove instance variable which is defined in the test. Fri Feb 6 00:48:37 2004 Tanaka Akira * lib/prettyprint.rb (PrettyPrint#first?): obsoleted. Thu Feb 5 23:56:55 2004 Tanaka Akira * lib/prettyprint.rb (PrettyPrint#seplist): added. * lib/pp.rb (PPMethods#pp_object): use seplist. (PPMethods#pp_hash): ditto. (Array#pretty_print): ditto. (Struct#pretty_print): ditto. (MatchData#pretty_print): ditto. * lib/set.rb (Set#pretty_print): use seplist. Wed Feb 4 02:12:06 2004 Tanaka Akira * file.c (test_l): fix wrong method name in document. (test_S): ditto. (test_b): ditto. (test_c): ditto. (test_suid): ditto. (test_sgid): ditto. (test_sticky): ditto. Tue Feb 3 08:04:57 2004 Tanaka Akira * lib/pp.rb (Struct#pretty_print_cycle): follow 1.8 style. Mon Feb 2 19:33:49 2004 WATANABE Hirofumi * configure.in: backport from 1.9 for Interix. * dln.c (dln_load): ditto. Mon Feb 2 13:31:51 2004 NAKAMURA Usaku * lib/net/http.rb (canonical_each): fix merge miss. Mon Feb 2 01:54:00 2004 Tanaka Akira * lib/pp.rb (Struct#pretty_print): make it 1.8 style. (Numeric#pretty_print, FalseClass#pretty_print) (TrueClass#pretty_print, Module#pretty_print): fix pp for objects with instance variables. [ruby-talk:91157] * lib/open-uri.rb (URI::Generic#find_proxy): return nil on loopback address. * lib/resolv-replace.rb (BasicSocket#send): don't replace because it has no hostname argument. (IPSocket.getaddress): raise SocketError instead of Resolv::ResolvError for errors. (TCPSocket#initialize, UDPSocket#bind, UDPSocket#connect) (SOCKSSocket#initialize): use IPSocket.getaddress instead of Resolv.getaddress. (UDPSocket#send): recognize 3 arguments form. try all addresses on 4 arguments form. Sun Feb 1 18:17:00 2004 Gavin Sinclair * lib/net/http.rb: merged coding style changes from HEAD. Sun Feb 1 16:15:00 2004 Gavin Sinclair * lib/test/unit.rb: rearranged documentation for RDoc's sake. * lib/matrix.rb: improved documentation. * lib/net/http.rb: slight documentation formatting improvement. Sun Feb 1 05:30:06 2004 Tanaka Akira * lib/open-uri.rb (URI::Generic#find_proxy): warn HTTP_PROXY. raise an errror on non-http proxy URI. (OpenURI::Buffer#<<): make a tempfile binmode. [ruby-talk:90793] Sat Jan 31 09:20:32 2004 NAKAMURA, Hiroshi * sample/openssl/gen_csr.rb: wrong usage string. Sat Jan 31 01:00:32 2004 NAKAMURA, Hiroshi * lib/soap/wsdlDriver.rb, lib/wsdl/soap/operation.rb: add support of "parts" attribute of soap:body element in WSDL. * lib/wsdl/xmlSchema/schema.rb: friendly warning message for simpleType element which is not supported for now. * lib/soap/mapping/factory.rb: deleted unused methods. * lib/soap/mapping/rubytypeFactory.rb: do no ignore case while xsi:type string <-> Ruby class name matching. * test/wsdl/soap/{soapbodyparts.wsdl,test_soapbodyparts.wsdl}: new files. Thu Jan 29 23:56:00 2004 WATANABE Hirofumi * util.c (mblen): fix overrun. [ruby-dev:22672] Thu Jan 29 22:41:53 2004 Dave Thomas * lib/rdoc/generators/html_generator.rb: Allow 'link:' in Tidylinks. THis means you can write "see f1[link:files/f1_rb.html]". Thu Jan 29 15:33:23 2004 GOTOU Yuuzou * ext/openssl/ossl_x509hame.c (ossl_x509name_initialize): change second argument. it expected to be a Hash not an Integer. * ext/openssl/ossl_x509name.c (ossl_x509name_add_entry): add new function for OpenSSL::X509::Name#add_entry. * ext/openssl/ossl_x509name.c (ossl_x509name_to_a): append ASN.1 tag number to each element of return value. * ext/openssl/ossl_x509name.c (Init_ossl_x509name): add constants OpenSSL::X509::Name::DEFAULT_OBJECT_TYPE and OBJECT_TYPE_TEMPLATE. * ext/openssl/lib/openssl/x509.rb (OpenSSL::X509::Name#initialize): second argument takes OBJECT_TYPE_TEMPLATE by default. * sample/openssl/gen_csr.rb: use OpenSSL::X509::Name.parse. Wed Jan 28 04:29:41 2004 Eric Schwartz * lib/cgi/session.rb: use LOCK_SH to read, and a few other improvements. [ruby-core:02328] Tue Jan 27 11:09:29 2004 FUKUMOTO Atsushi * ext/socket/socket.c (s_recvfrom): sending length should be an invariant while retrying on EAGAIN. [ruby-talk:89962] Tue Jan 27 10:35:18 2004 NAKAMURA Usaku * ext/win32ole/win32ole.c (set_argv): fix condition. Tue Jan 27 02:26:31 2004 GOTOU Yuuzou * lib/webrick/httputils.rb (WEBrick:HTTPUtils::parse_header): refine regex for header-name. Tue Jan 27 00:30:11 2004 NAKAMURA Usaku * win32/Makefile.sub: rollback. Mon Jan 26 22:53:04 2004 Dave Thomas * io.c: Remove documentation references to $defout. Mon Jan 26 15:11:47 2004 NAKAMURA Usaku * sample/exyacc.rb: escape '}' to avoid warning. Mon Jan 26 14:41:46 2004 Yukihiro Matsumoto * lib/delegate.rb (Delegator::initialize): preserve singleton_method_added method [ruby-dev:22685] * lib/delegate.rb (Delegator::initialize): use Kernel::raise instead of mere raise. [ruby-dev:22681] Mon Jan 26 12:47:17 2004 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: define CONST84 when TCL_MAJOR_VERSION == 7 Mon Jan 26 11:35:23 2004 Nobuyoshi Nakada * ext/extmk.rb: Makefiles should depend on also rbconfig.rb. (ruby-bugs:PR#1256) * ext/win32ole/win32ole.c (set_argv): set real arguments to WIN32OLE::ARGV. [ruby-list:39073] Thu Jan 22 22:54:53 2004 Shugo Maeda * lib/net/imap.rb (BEG_REGEXP): allow 8-bit characters in quoted strings for Novell GroupWise Internet Agent. * lib/net/imap.rb (DATA_REGEXP): ditto. Thu Jan 22 16:21:33 2004 Nobuyoshi Nakada * parse.y (string_content): reset lexical states at the beginning of string contents. [ruby-list:39061] Wed Jan 21 21:55:51 2004 Masatoshi SEKI * lib/drb/drb.rb: remove O_NONBLOCK, thanks \ay * lib/drb/extserv.rb: typo Wed Jan 21 17:57:56 2004 Shugo Maeda * lib/net/imap.rb (envelope): allow NIL. * lib/net/imap.rb (body): ditto. * lib/net/imap.rb (number): ditto. * lib/net/imap.rb (ensure_nz_number): show a detailed error message. Wed Jan 21 16:44:20 2004 Nobuyoshi Nakada * lib/mkmf.rb (merge_libs): squeeze successive same libraries. [ruby-dev:22652] Wed Jan 21 16:01:37 2004 Nobuyoshi Nakada * ext/digest/rmd160/extconf.rb: have_library appends found library. Wed Jan 21 11:36:00 2004 Yukihiro Matsumoto * parse.y (block_append): update nd_end for "real" head node. [ruby-list:39058] Tue Jan 20 14:48:13 2004 GOTOU Yuuzou * ext/openssl/extconf.rb: should check instead of OPENSSL_VERSION_NUMBER. [ruby-list:39056] Tue Jan 20 14:43:17 2004 Dave Thomas * lib/base64.rb: Add RDoc Tue Jan 20 14:25:51 2004 Dave Thomas * lib/abbrev.rb: Add RDoc Tue Jan 20 13:22:39 2004 Dave Thomas * lib/rdoc/generators/html_generator.rb: Document aliases at top-most level. * lib/English.rb: Document English.rb. Tue Jan 20 02:49:22 2004 GOTOU Yuuzou * ext/openssl/extconf.rb: add check for OpenSSL version. [ruby-list:39054] Tue Jan 20 02:38:13 2004 Yukihiro Matsumoto * marshal.c (w_class): should not dump singleton class. [ruby-dev:22631] Tue Jan 20 01:31:36 2004 WATANABE Hirofumi * io.c (lineno): typo fix(FIX2INT -> INT2FIX). Mon Jan 19 21:53:38 2004 akira yamada * io.c, re.c, string.c, time.c: fixed up positions of RDocs. Mon Jan 19 07:09:20 2004 Tadayoshi Funaba * lib/date.rb: zone was wrong when it was behind UTC. Thanks Mark J. Reed. * lib/date/format.rb: %z is now always replaced by four digits with a leading plus or minus sign. * sample/cal.rb: added a class, anyway. Sun Jan 18 20:47:35 2004 WATANABE Hirofumi * ruby.c: use translate_char() on Cygwin. Sun Jan 18 02:33:26 2004 WATANABE Hirofumi * defines.h (_WIN32): undef _WIN32 on Cygwin before defining DOSISH. Sun Jan 18 00:23:55 2004 Nobuyoshi Nakada * marshal.c (class2path): check anonymous class/module before checking referable, and allow singleton classes. Fri Jan 16 14:33:35 2004 Nobuyoshi Nakada * marshal.c (class2path): get class path and check referable. [ruby-dev:22588] Fri Jan 16 09:52:23 2004 Yukihiro Matsumoto * eval.c (proc_eq): Proc with empty body may not be equal. [ruby-dev:22590] Thu Jan 15 13:03:10 2004 Nobuyoshi Nakada * io.c (argf_read): do not append EOF. (ruby-bugs-ja:PR#585) * io.c (rb_io_fwrite): ad-hockery hack to get rid of HP-UX stdio weird behavior. [ruby-dev:22424] Wed Jan 14 13:31:06 2004 Nobuyoshi Nakada * ext/iconv/extconf.rb: wrapper iconv.rb is dependent on platform. Tue Jan 13 18:54:28 2004 NAKAMURA, Hiroshi * lib/logger.rb(Logger#msg2str): no special treatment for the object which responds to :to_str. commited at 2004-01-11T21:46:27 by gsinclair. * lib/logger.rb(LogDevice#initialize): remove type checking if the given object is a String. Kernel.open handles it correctly. commited at 2004-01-11T21:46:27 by gsinclair. * test/logger/test_logger.rb: follow above change (ArgumentError -> TypeError.) follow above commit. Tue Jan 13 14:27:13 2004 Kazuhiro NISHIYAMA * lib/test/unit/ui/testrunnerutilities.rb (TestRunnerUtilities): moved run method which allows output level. [ruby-dev:22554] Tue Jan 13 04:29:52 2004 Dave Thomas * lib/rdoc/ri/ri_driver.rb (RiDriver::report_method_stuff): Show fully-qualified class names in class list. Tue Jan 13 01:04:37 2004 Dave Thomas * lib/rdoc/ri/ri_paths.rb (RI::Paths): First attempt at incorporating DESTDIR in the rdoc installation. Mon Jan 12 23:27:19 2004 Nobuyoshi Nakada * parse.y (primary): fix position after FCALL. [ruby-dev:22574] Mon Jan 12 12:07:22 2004 Dave Thomas * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser::do_methods): Someone changed the "// in eval.c" comments to "/*...*/" style, so the parsing of the source file name broke. * object.c: Remove spurious space in TrueClass documentation. * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser::find_body): Fix bad regexp: if the code before a documented method contained a comment that wasn't terminated by whitespace, that comment and all intervening code was included in the following method's documentation. * lib/rdoc/ri/ri_formatter.rb (RI::HtmlFormatter::break_to_newline): HTML formats need explicit line breaks. Mon Jan 12 11:46:30 2004 Nobuyoshi Nakada * configure.in (LIBPATHFLAG, RPATHFLAG): enclose paths with single quotes. [ruby-dev:22564] * lib/mkmf.rb (libpathflag): do not enclose with quotes always. * {bcc32,win32,wince}/Makefile.sub (LIBPATHFLAG): quoted. Mon Jan 12 02:24:07 2004 Dave Thomas * lib/rdoc/ri/ri_formatter.rb (RI::HtmlFormatter): Add HTML generation support to ri (Elliot Hughes) Mon Jan 12 02:24:07 2004 Dave Thomas * lib/rdoc/ri/ri_formatter.rb (RI::HtmlFormatter): Add HTML generation support to ri (Elliot Hughes) Sun Jan 11 02:07:47 2004 Dave Thomas * lib/rdoc/ri/ri_options.rb (RI::Options::OptionList::OptionList): Also accept command line options via the 'RI' environment variable. Sun Jan 11 02:07:47 2004 Dave Thomas * lib/rdoc/ri/ri_options.rb (RI::Options::OptionList::OptionList): Also accept command line options via the 'RI' environment variable. Sat Jan 10 21:27:41 2004 Yukihiro Matsumoto * eval.c (eval): need to add message delimiter. [ruby-dev:22561] Sat Jan 10 01:54:50 2004 Eric Sunshine * defines.h (__NeXT__): Ensure that all standard S_IRUSR, S_IWGRP, S_IRWXO, etc. macros are defined since future code might require them (even though present code only requires a subset). * defines.h (__NeXT__): Bug fix: WORDS_BIGENDIAN was not being set correctly on Rhapsody when -arch compiler flag was used (via configure's --enable-fat-binary option). Fri Jan 9 10:05:14 2004 Siena. * lib/mkmf.rb (libpathflag): use single quotes. [ruby-dev:22440] Thu Jan 8 23:49:21 2004 WATANABE Hirofumi * configure.in (RDOCTARGET): new macro. if you want to install rdoc documentation, you need to run configure with --enable-install-doc. Thu Jan 8 21:29:43 2004 GOTOU Yuuzou * ext/openssl/ossl_pkey.c (ossl_pkey_to_der): removed; it returns public key only. * ext/openssl/ossl_pkey_dh.c (ossl_dh_to_der): new function for OpenSSL::PKey::DH#to_der. * ext/openssl/ossl_pkey_dsa.c (ossl_dsa_to_der): new function for OpenSSL::PKey::DSA#to_der. * ext/openssl/ossl_pkey_rsa.c (ossl_rsa_to_der): new function for OpenSSL::PKey::RSA#to_der. Thu Jan 8 16:51:04 2004 NAKAMURA, Hiroshi * test/wsdl/datetime/test_datetime.rb: fixed a stupid testcase which dumps "E" at month-end. Thu Jan 8 11:20:01 2004 WATANABE Hirofumi * eval.c, object.c, process.c, re.c: don't use C++ style comments. Thu Jan 8 04:36:21 2004 GOTOU Yuuzou * lib/webrick/cgi.rb (WEBrick::CGI#initialize): should create @config[:Logger] if it was not given. * sample/webrick/*: new files. * MANIFEST: add sample/webrick/* Wed Jan 7 13:00:18 2004 Dave Thomas * lib/rdoc/ri/ri_driver.rb: Fix problem where ri was being too eager to find matches of ambiguous method names (such as "ri Thread.join" would return both Thread.join and ThreadsWait.join) Wed Jan 7 12:35:41 2004 NAKAMURA, Hiroshi * lib/debug.rb: revert command parse regexps. [ruby-list:39014] by Shirai,Kaoru. Wed Jan 7 08:21:04 2004 Dave Thomas * lib/rdoc/parsers/parserfactory.rb: Check for shebang line in files that would otherwise be treated as plain text. Tue Jan 6 22:13:34 2004 Yukihiro Matsumoto * eval.c (rb_mod_modfunc): should break if m has no super class. [ruby-dev:22498] Tue Jan 6 21:55:02 2004 Nobuyoshi Nakada * io.c (fptr_finalize): should save errno just after failure. [ruby-dev:22492] Tue Jan 6 14:53:14 2004 Dave Thomas * bin/ri: split out the display side, making it pluggable. Added new ri_driver and ri_display files in lib/rdoc/ri. Tue Jan 6 06:37:53 2004 Dave Thomas * bin/rdoc: Add --ri-system switch * lib/.document: Update with list of files that seem to have documentation * lib/test/unit.rb: Reorder comment to make it RDoc friendly. * Makefile.in: add install-nodoc target, and make it generate RDoc on default install. * lib/rdoc/ri/ri_options.rb (RI::Options::parse): Add --doc-dir option to ri. Tue Jan 6 00:04:40 2004 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_method_or_yield_parameters): fix parsing if there are braces in a method parameter list Fri Jan 2 14:54:11 2004 Dave Thomas * bin/ri: Add new --classes option, and arrange for help messages to be paged too. * bin/rdoc: Add statistics. * process.c: (MG) Added Process documentation * lib/rdoc/ri/ri_formatter.rb (RI::AttributeFormatter::wrap): Fix problem with labels not displaying in RI labeled lists using BS and ANSI modes. Fri Jan 2 01:50:13 2004 Yukihiro Matsumoto * io.c (argf_eof): ARGF.eof? should not have any side effect. [ruby-dev:22469] Wed Dec 31 17:25:17 2003 Yukihiro Matsumoto * io.c (argf_each_byte): should return self. [ruby-dev:22465] Wed Dec 31 11:20:34 2003 Dave Thomas * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser::do_methods): Make file referenced in "// in sss.c" relative to current file. Wed Dec 31 11:17:37 2003 Dave Thomas * lib/rdoc/generators/html_generator.rb: Fix problem when a public method was aliased, but the alias is then made private, and hence doesn't appear in RDoc output. Wed Dec 31 01:33:05 2003 Dave Thomas * array.c, error.c, eval.c, io.c, prec.c, range.c, re.c, string.c, time.c: Add RDoc for Kernel functions, and tidy. Tue Dec 30 19:39:14 2003 Yukihiro Matsumoto * io.c (rb_f_readline): should raise EOFError at the end of files. [ruby-dev:22458] * io.c (argf_read): should concatenate input files when length argument is nil. [ruby-dev:22450] * io.c (argf_read): should update supplied string buffer (2nd argument) even when IO#read is called multiple times. * io.c: should initialize lineno by zero. [ruby-dev:22460] Tue Dec 30 12:30:30 2003 Dave Thomas * lib/rdoc/code_objects.rb (RDoc::Context::find_symbol): If a class and a method have the same name, finding Xxx.abc was trying to find 'abc' in method 'Xxx', not class 'Xxx'. Tue Dec 30 08:32:32 2003 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_method): Handle undoing nesting of yield parameters correctly for: def each_entry(&b) Dir.foreach(@path) {|f| yield P.new(f) } end Tue Dec 30 08:32:32 2003 Dave Thomas * lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_method): Handle undoing nesting of yield parameters correctly for: def each_entry(&block) Dir.foreach(@path) {|f| yield Pathname.new(f) } end Mon Dec 29 12:51:02 2003 Dave Thomas * eval.c: Add RDoc for Kernel global functions. Mon Dec 29 11:00:16 2003 Dave Thomas * array.c: Tidy up RDoc loose ends. Mon Dec 29 05:05:51 2003 Dave Thomas * struct.c, random: Add RDoc comments Mon Dec 29 02:20:54 2003 Dave Thomas * eval.c: Add RDoc for class Proc, Method, UnboundMethod Mon Dec 29 00:41:44 2003 Dave Thomas * math.c: Add RDoc comments Sun Dec 28 20:19:11 2003 Tanaka Akira * ext/stringio/stringio.c (strio_sysread): StringIO.new.sysread didn't raise EOFError. * ext/zlib/zlib.c (gzreader_gets): don't increment lineno when gzfile_read_all returns "". Sun Dec 28 15:25:08 2003 Dave Thomas * class.c,object.c,parse.y,sprintf.c,variable.c: Document classes Object, Module, etc... Sun Dec 28 11:55:29 2003 NAKAMURA, Hiroshi * test/csv/test_csv.rb: generate bom.csv and mac.csv files on the fly. [ruby-talk:88852] * test/csv/{bom.csv,mac.csv}: removed. Sun Dec 28 08:56:51 2003 Dave Thomas * eval.c: Thead[Group] RDoc (thanks to MG) Sun Dec 28 03:50:05 2003 Dave Thomas * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser::find_override_comment): Escape method names used in regexp Sun Dec 28 01:46:02 2003 Dave Thomas * lib/rdoc/ri/ri_formatter.rb (RI::TextFormatter::display_flow_item): Add support for rules in 'ri' output. Sun Dec 28 01:35:35 2003 Dave Thomas * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser::find_body): Sometimes the Ruby source aliases two otherwise unrelated methods (for example Kernel#object_id and Kernel#hash are both the same C function). Provide a facility to allow the methods to be documented separately. Sun Dec 28 01:05:31 2003 Dave Thomas * marshal.c, signal.c: RDoc collemts added by Elliott Hughes Sun Dec 28 00:48:47 2003 Dave Thomas * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser::find_class_comment): Some source files use lower case class or module names when naming the Init_XXX function in C. Sat Dec 27 23:41:46 2003 WATANABE Hirofumi * configure.in: fix "test: too many arguments" error. Sat Dec 27 15:32:19 2003 Dave Thomas * time.c: RDoc comments added Sat Dec 27 15:07:57 2003 Dave Thomas * object.c: Add RDoc comments for Symbol class. Sat Dec 27 14:42:30 2003 Dave Thomas * numeric.c: Add RDoc comments. Sat Dec 27 00:44:00 2003 Yukihiro Matsumoto * io.c (next_argv): warn always for stdin on inplace edit mode. * io.c (read_all): need to check string value. * io.c (argf_read): allow ARGF.read(nil). [ruby-dev:22433] Fri Dec 26 23:02:09 2003 Yukihiro Matsumoto * io.c (rb_f_backquote): need not to check nil result. [ruby-core:02078] * io.c (rb_io_getline): should return nil when read_all gives empty string, even when nil rs is specified. [ruby-core:02077] Fri Dec 26 18:50:59 2003 Nobuyoshi Nakada * configure.in: check if getcontext and setcontext are available. * eval.c: use presence of getcontext/setcontext. Fri Dec 26 16:40:53 2003 Tanaka Akira * lib/pathname.rb (PathnameTest#test_plus): add 2 assertions. Fri Dec 26 09:26:58 2003 Yukihiro Matsumoto * pack.c (pack_pack): add sign check for 'i', and 'l'. [ruby-dev:22427] * bignum.c (rb_quad_pack): add range check for 'quad int'. Thu Dec 25 22:39:59 2003 NAKAMURA Usaku * string.c (rb_str_update): don't return any value. Thu Dec 25 15:30:17 2003 Yukihiro Matsumoto * string.c (rb_str_update): call rb_str_modify(). Thu Dec 25 05:08:09 2003 Nobuyoshi Nakada * eval.c (search_required): search actual file name once when no extension specified. Thu Dec 25 04:00:44 2003 Yukihiro Matsumoto * stable version 1.8.1 released. Thu Dec 25 00:17:53 2003 Yukihiro Matsumoto * configure.in: check for nanosleep, -lrt if required. [ruby-core:02059] * eval.c (thread_timer): use select(2) if nanosleep(2) is not available. * eval.c: check __stub_getcontext for glibc on some platforms. [ruby-list:38984] Wed Dec 24 23:48:04 2003 NAKAMURA, Hiroshi * test/soap/test_basetype.rb, test/soap/marshal/test_marshal.rb test/xsd/test_xsd.rb: use "(-1.0 / (1.0 / 0.0))" instead of "-0.0" to express -0.0. [ruby-talk:88786] Wed Dec 24 23:29:30 2003 Tanaka Akira * lib/tsort.rb (test_orphaned_break): removed. Wed Dec 24 20:53:06 2003 Hidetoshi NAGAI * ext/tk/sample/tkmulticolumnlist.rb: new sample * ext/tk/sample/tkmultilistframe.rb: bug fix Wed Dec 24 20:37:37 2003 Eric Sunshine * configure.in (LDSHARED): Fixed typographical error in assignment of LDSHARED for Rhapsody which caused linking of extension modules to fail. Wed Dec 24 17:51:18 2003 Yukihiro Matsumoto * file.c (rb_thread_flock): enable thread support again. Wed Dec 24 16:46:08 2003 Yukihiro Matsumoto * eval.c (catch_timer): do not call rb_thread_schedule() inside to avoid pthread_mutex_lock() deadlock. interrupts to system calls are detected by TRAP_END via EINTR error. * eval.c (thread_timer): do not post signal unless it is absolutely necessary. * rubysig.h (TRAP_END): add CHECK_INTS to switch thread. * regex.c (re_compile_pattern): check if nextp is smaller than pend. [ruby-dev:22372] * eval.c (umethod_bind): remove method overridden check. [ruby-dev:22366] Wed Dec 24 16:13:05 2003 GOTOU Yuuzou * ext/openssl/ossl_ssl.c (ossl_ssl_read): should check for error status by SSL_get_error(). * ext/openssl/ossl_ssl.c (ossl_ssl_write): ditto. Wed Dec 24 14:23:27 2003 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_read): clear the buffer argument when returning nil. [ruby-dev:22363] * test/ruby/ut_eof.rb (TestEOF::test_eof_0, TestEOF::test_eof_1): add buffer argument tests. Wed Dec 24 14:07:55 2003 Nobuyoshi Nakada * lib/test/unit/assertions.rb: Modules are allowed to rescue. * lib/test/unit/autorunner.rb: show output_level in order. * lib/test/unit/collector/dir.rb: get rid of successive same directories in load path. * test/testunit/test_assertions.rb (test_assert_nothing_raised, test_assert_raise): test for modules. Wed Dec 24 13:43:34 2003 Shugo Maeda * lib/net/imap.rb (authenticate): remove "\n" from base64 encoded strings. Wed Dec 24 11:26:41 2003 Nobuyoshi Nakada * test/fileutils/test_fileutils.rb: should not create any files or directories in current directory. [ruby-talk:88724] Wed Dec 24 10:29:53 2003 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_read): never return nil at unlimited read. [ruby-dev:22334] * ext/stringio/stringio.c (strio_read): support second argument. [ruby-dev:22350] Wed Dec 24 09:38:49 2003 Nobuyoshi Nakada * parse.y (arg): should return 0 after error. [ruby-dev:22360] Wed Dec 24 00:56:54 2003 Yukihiro Matsumoto * io.c (read_all): do not return nil at the end of file. [ruby-dev:22334] * io.c (argf_read): do not depend on nil at eof behavior of IO#read(). * eval.c (rb_thread_join): dup exception before re-raising it. * io.c (rb_io_eof): call clearerr() to prevent side effect. this patch is supplied by Masahiro Sakai . [ruby-dev:22234] * pack.c (OFF16): get offset for big endian machines. * pack.c (pack_pack): use OFF16 instead of OFF16B. [ruby-dev:22344] * pack.c (pack_unpack): ditto. Tue Dec 23 22:47:14 2003 Yukihiro Matsumoto * io.c (rb_io_check_readable): set FMODE_RBUF always, even if NEED_IO_SEEK_BETWEEN_RW is not defined. [ruby-dev:22340] * io.c (rb_io_check_writable): clear FMODE_RBUF before writing something. Tue Dec 23 22:25:00 2003 Gavin Sinclair * lib/optparse.rb: incomplete RDoc documentation added in place of existing RD comments. Tabs converted to spaces. Tue Dec 23 19:44:47 2003 NAKAMURA, Hiroshi * test/soap/test_streamhandler.rb (test_basic_auth): removed. soap4r + basic_auth is not officially supported in ruby/1.8.1 even though soap4r + basic_auth + http-access2 should run fine. Tue Dec 23 19:42:59 2003 Nobuyoshi Nakada * io.c (rb_io_ungetc): raise an exception at unread stream to avoid unspecified behavior. [ruby-dev:22330] * test/ruby/test_system.rb (test_syntax): glob relatively from __FILE__. Tue Dec 23 18:09:40 2003 Yukihiro Matsumoto * pack.c (pack_pack): remove unnecessary negative value check. [ruby-dev:22329] Tue Dec 23 17:26:55 2003 KONISHI Hiromasa * bcc32/Makefile.sub (config.h): bcc has finite(). [ruby-list:38940] Tue Dec 23 16:08:16 2003 NAKAMURA, Hiroshi * lib/rexml/encodings/US-ASCII.rb: typo. [ruby-talk:88650] * test/ruby/test_system.rb: num of asserts depended on running dir. * test/xsd/test_noencoding.rb: rexml + without iconv/uconv cannot handle euc-jp. install iconv, uconv or xmlscan. Tue Dec 23 14:13:51 2003 akira yamada * lib/uri/generic.rb (URI::Generic::check_userinfo, URI::Generic::check_user, URI::Generic::check_password): tests conflicts/depends with other components closely. * test/uri/test_generic.rb (TestGeneric::test_set_component): added tets. Tue Dec 23 11:08:34 2003 NAKAMURA, Hiroshi * test/xsd/test_noencoding.rb: rescue Errno::EINVAL and do not test. "euc-jp" might not be in supported encoding name list. [ruby-talk:88650] Tue Dec 23 06:10:31 2003 GOTOU Yuuzou * lib/webrick/cgi.rb (CGI): add support for mod_ruby. * lib/webrick/cgi.rb (CGI::Socket): add check for existence of OpenSSL module in all HTTPS related methods. * lib/webrick/cgi.rb (CGI::Socket#cipher): should create similar value to OpenSSL::SSLSocket#cipher. * lib/webrick/httpresponse.rb (HTTPResponse#setup_header): should set "connection: close" if @keep_alive is false. * lib/webrick/https.rb (HTTPrequest#meta_vars): add supprt for SSL_PROTOCOL, SSL_CIPHER_USEKEYSIZE and SSL_CIPHER_ALGKEYSIZE. Mon Dec 22 23:00:05 2003 akira yamada * lib/uri/generic.rb (URI::Generic::check_opaque): fixed typo. Mon Dec 22 21:59:24 2003 Nobuyoshi Nakada * ext/iconv/iconv.c (map_charset): always ensure code is a String. Mon Dec 22 21:15:29 2003 Nobuyoshi Nakada * class.c (rb_mod_init_copy): always copy singleton class. [ruby-dev:22325] Mon Dec 22 20:44:36 2003 akira yamada * lib/uri/generic.rb (URI::Generic#route_from): accepts urls which has no host-part. * test/uri/test_generic.rb (TestGeneric::test_route): added a test. Mon Dec 22 20:38:44 2003 Nobuyoshi Nakada * lib/cgi.rb: reduce eval. * lib/cgi.rb (CGI::QueryExtension::read_multipart): alias path to local_path. [ruby-list:38883] Mon Dec 22 20:09:31 2003 NAKAMURA, Hiroshi * test/soap/test_property.rb: remove duplicated test method. Mon Dec 22 18:22:04 2003 NAKAMURA Usaku * bcc32/Makefile.sub, win32/Makefile.sub (config.h): remove HAVE_ISINF definition to follow previous commits of missing.h and win32/win32.h. Mon Dec 22 17:23:42 2003 Nobuyoshi Nakada * configure.in (ac_cv_func_setitimer): moved from defines.h * defines.h, rubysig.h, signal.c: removed macro handling which should be done in configure. * configure.in (intrinsics.h): check if present. * ruby.h: include intrinsics.h if available. * bignum.c, marshal.c: include ieeefp.h if available. * missing.h (isinf): define as a macro if finite() and isnan() are available. [ruby-core:02032] Mon Dec 22 17:07:31 2003 WATANABE Hirofumi * configure.in (mingw): set isnan, finite and isinf to yes. Mon Dec 22 13:40:19 2003 NAKAMURA, Hiroshi * lib/soap/property.rb: passing block by reference. Mon Dec 22 00:32:43 2003 Yukihiro Matsumoto * eval.c (rb_with_disable_interrupt): use ENABLE_INTS instead of ALLOW_INTS which may switch context. [ruby-dev:22319] * ext/syck/emitter.c (syck_emitter_write): str bigger than e->bufsize causes buffer overflow. [ruby-dev:22307] Sun Dec 21 17:29:00 2003 Nobuyoshi Nakada * class.c (rb_check_inheritable): new function. [ruby-dev:22316] * intern.h: add prototype. * eval.c (superclass): use rb_check_inheritable(). * object.c (rb_class_initialize): check argument validity. Sun Dec 21 16:25:10 2003 Tanaka Akira * lib/pathname.rb (Pathname#+): re-implemented to resolve ".." in beginning of the argument. (Pathname#join): concatenate from the last argument. (Pathname#parent): just use Pathname#+. Sun Dec 21 00:12:37 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: add new methods (TkScrollbar#assign, assign_list) * ext/tk/sample/tkmultilistframe.rb: use TkScrollbar#assign method Sat Dec 20 21:59:03 2003 GOTOU Yuuzou * lib/webrick/httprequest.rb (HTTPRequest#meta_vars): refine regexp. * lib/webrick/cgi.rb (CGI#start): NPH scripts return status line instead of Status: header field. * lib/webrick/cgi.rb (CGI::Socket): refine some coditions. Sat Dec 20 16:07:14 2003 Nobuyoshi Nakada * lib/optparse.rb (OptionParser::Completion::complete): wrong Regexp for word boundary. pointed out by Gavin Sinclair. * lib/optparse.rb (OptionParser::make_switch): [no-] prefix was missing. Sat Dec 20 11:40:10 2003 Nobuyoshi Nakada * lib/yaml.rb (YAML::YAML): adjust Marshal version. Sat Dec 20 03:56:02 2003 Yukihiro Matsumoto * eval.c (rb_with_disable_interrupt): prohibit thread context switch during proc execution. [ruby-dev:21899] Sat Dec 20 02:41:02 2003 GOTOU Yuuzou * lib/webrick/cgi.rb: add file. (yet another CGI library) * MANIFEST: add lib/webrick/cgi.rb. Sat Dec 20 02:18:31 2003 Yukihiro Matsumoto * misc/ruby-mode.el (ruby-calculate-indent): proper indentation inside of parentheses. [ruby-dev:22308] Fri Dec 19 21:24:22 2003 GOTOU Yuuzou * lib/webrick/httprequest.rb (HTTPRequest#meta_vars): should not set HTTP_CONTENT_TYPE and HTTP_CONTENT_LENGTH. * lib/webrick/https.rb (HTTPRequest#parse): should check presence of cert() method to detect SSLSocket. Fri Dec 19 22:56:46 2003 NAKAMURA, Hiroshi * lib/soap/property.rb (SOAP::Property#load): new method for loading property value into existing property tree. * test/soap/test_property.rb: add test. Fri Dec 19 19:21:49 2003 akira yamada * lib/runit/cui/testrunner.rb (RUNIT::CUI::TestRunner::run): should use Test::Unit::UI::{PROGRESS_ONLY,VERBOSE}. Fri Dec 19 17:36:49 2003 Hidetoshi NAGAI * ext/tk/sample/tkmultilistbox.rb: bug fix * ext/tk/sample/tkmultilistframe.rb: new sample script Fri Dec 19 03:44:27 2003 GOTOU Yuuzou * lib/webrick/httputils.rb (parse_form_data): should return an empty Hash if the body is empty. Thu Dec 18 21:47:35 2003 NAKAMURA Usaku * lib/mkmf.rb (create_makefile): should remove deffile if it's made by miniruby. based on nobu's patch. Thu Dec 18 21:44:21 2003 NAKAMURA Usaku * eval.c (stack_extend): ignore inline optimization on VC7. * win32/Makefile.sub (OS, RT): can override. * win32/Makefile.sub (LDFLAGS): ditto. shouldn't use pdb:none option. based on Tietew's patch [ruby-dev:22289] Thu Dec 18 16:38:44 2003 Nobuyoshi Nakada * dir.c (fnmatch): unlike find_dirsep(), rb_path_next() never return NULL. Thu Dec 18 15:27:59 2003 WATANABE Hirofumi * lib/ipaddr.rb (IPSocket::getaddress): merge usa's patch. [ruby-dev:21678] Wed Dec 17 15:15:30 2003 Yukihiro Matsumoto * lib/cgi.rb (CGI::QueryExtension::Value::[]): should work like String#[] if more than one arguments are specified. * lib/delegate.rb: avoid using common instance name as "@obj". * lib/cgi.rb (CGI::QueryExtension::Value): Value is no longer subclass of String, but DelegateClass(String). * ext/curses/extconf.rb: restore function check for init_color. [ruby-list:38905] * Makefile.in: need to specify $(MAINLIBS) for the miniruby generation rule. * configure.in: better FreeBSD -lc_r support. Wed Dec 17 00:16:14 2003 Minero Aoki * ext/strscan/strscan.c: new method StringScanner#beginning_of_line? (alias #bol?) * ext/strscan/strscan.c: new method StringScanner#concat and #<<. * ext/strscan/strscan.c: StringScanner#new(str) does not duplicate nor freeze STR (allow destructive modification). * test/strscan/test_stringscanner.rb: test new methods above. * test/strscan/test_stringscanner.rb: test destructive string modification. Tue Dec 16 21:20:47 2003 Tanaka Akira * lib/pp.rb: don't use local variable `pp'. * lib/prettyprint.rb: ditto. Tue Dec 16 13:20:43 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: condition bug of if statement on {pack,grid}_propagate methods Tue Dec 16 03:17:29 2003 why the lucky stiff * lib/yaml/rubytypes.rb: comments in strings. [ruby-talk:88012] * test/yaml/test_yaml.rb: add test. Tue Dec 16 01:14:44 2003 Nobuyoshi Nakada * eval.c (catch_timer): check rb_thread_crtical in main native thread. * eval.c (thread_timer): just sends signals periodically, to prevent main native thread from receiving them in critical section. [ruby-core:01959] Mon Dec 15 13:32:22 2003 Nobuyoshi Nakada * dir.c (check_dirname): check string safety and remove extraneous trailing directory separators. [ruby-dev:22279] * file.c: renamed and externalized rb_path_next, rb_path_skip_prefix, rb_path_last_separator, rb_path_end. * intern.h: prototypes for rb_path_next, rb_path_skip_prefix, rb_path_last_separator, rb_path_end. Mon Dec 15 09:27:46 2003 NAKAMURA Usaku * ext/openssl/ossl_pkcs12.c (ossl_pkcs12_initialize): first argument of rb_protect should take an argument of VALUE. Sun Dec 14 18:46:48 2003 WATANABE Hirofumi * ext/socket/socket.c (Init_socket): IPv6 is not supported although AF_INET6 is defined on MinGW. * lib/ipaddr.rb (AF_INET6): workaround in the environment which does not support IPv6. Sat Dec 13 18:55:16 2003 Nobuyoshi Nakada * ext/iconv/charset_alias.rb: preserve original order. * ext/iconv/extconf.rb: remove wrapper file at clean. Sat Dec 13 18:09:42 2003 Yukihiro Matsumoto * eval.c (thread_timer): use timer by sub-thread and nanosleep. [ruby-talk:87519] * gc.c (Init_stack): no stack adjustment for THREAD_SAFE. Sat Dec 13 17:17:59 2003 Nobuyoshi Nakada * eval.c (proc_alloc): cache the created object at first time. [ruby-talk:61288], [ruby-dev:22240] Sat Dec 13 09:01:23 2003 Nobuyoshi Nakada * configure.in: check ucontext.h. * eval.c: use getcontext/setcontext() instead of setjmp/longjmp() on ia64 or with native thread enabled. [ruby-core:01932] Sat Dec 13 03:09:14 2003 why the lucky stiff * lib/yaml/rubytypes.rb: anonymous struct fix. [ruby-core:01946] * test/yaml/test_yaml.rb: add test. Fri Dec 12 22:36:44 2003 NAKAMURA, Hiroshi * lib/csv.rb: add Cell#to_str and Cell#to_s for /.../ =~ aCell, "#{aCell}" and so on. * test/csv/test_csv.rb: add tests. Fri Dec 12 19:33:06 2003 Minero Aoki * lib/fileutils.rb (mkdir): remove trailing `/' from pathes. * lib/fileutils.rb (rmdir): ditto. [ruby-dev:22238] * lib/fileutils.rb (rmdir_r): ditto. * lib/fileutils.rb (fu_copy_dir): check if it is a directory after mkdir(2). Fri Dec 12 06:06:09 2003 Nobuyoshi Nakada * eval.c (proc_invoke): fix class name in warning message for define_method. [ruby-dev:22235] Thu Dec 11 21:24:43 2003 GOTOU Yuuzou * ext/openssl/ossl_pkcs12.[ch]: new files. add OpenSSL::PKCS12. * ext/openssl/ossl.[ch]: ditto. * ext/openssl/MANIFEST: add ossl_pkcs12.[ch]. Thu Dec 11 20:54:28 2003 Minero Aoki * lib/fileutils.rb (mkdir_p): remove trailing `/' befere mkdir(2). mkdir("nonexistdir/") does not work on NetBSD/Alpha 1.6.1. * lib/fileutils.rb (fu_list): call to_str for all arguments. Thu Dec 11 20:07:01 2003 WATANABE Hirofumi * lib/ftools.rb (makedirs): sync with fileutils. Thu Dec 11 19:53:03 2003 Minero Aoki * lib/fileutils.rb (mkdir_p): catch all SystemCallErrors. (mkdir("C:\") causes EACCESS on Windows 2000/NTFS) Thu Dec 11 19:08:02 2003 Minero Aoki * lib/fileutils.rb (mkdir_p): check if it is a directory after mkdir(2) instead of before mkdir(2), to avoid race condition. [ruby-talk:87730] Refer: mkinstalldirs sh script, GNU mkdir(1) (coreutils 5.0) Thu Dec 11 18:49:30 2003 Minero Aoki * lib/fileutils.rb: def m( arg ) -> def m(arg). Thu Dec 11 11:39:43 2003 Nobuyoshi Nakada * configure.in (ieeefp.h), numeric.c: needed for finite() on Solaris. [ruby-core:01921] * file.c (rb_stat_inspect): adjust format specifier. * parse.c (arg_prepend): nodetype() is for debug use. * ruby.h (ISASCII, etc): cast to int to get rid of warning. * ruby.h (alloca.h): include even in GCC. [ruby-core:01925] * ext/bigdecimal/bigdecimal.c (GetVpValue): adjust format specifier. * ext/bigdecimal/bigdecimal.c (BigDecimal_prec, BigDecimal_coerce, BigDecimal_divmod): use rb_assoc_new() to suppress memory usage. * ext/bigdecimal/bigdecimal.c (BigDecimal_split): ditto. * ext/dl/sym.c (rb_dlsym_guardcall): guard itself should be volatile. * ext/iconv/iconv.c (iconv_convert): ensure actual parameter with format specifier. * ext/pty/pty.c (MasterDevice, SlaveDevice, deviceNo): do not define unless used. * ext/pty/pty.c (getDevice): get rid of warning. * ext/socket/socket.c (port_str, sock_s_getaddrinfo, sock_s_getnameinfo): FIX2INT() now returns long. * ext/socket/socket.c (init_inetsock_internal): uninitialized variable. * ext/syck/rubyext.c (syck_parser_assign_io): add prototype. * ext/syck/rubyext.c (rb_syck_mktime, yaml_org_handler): use ISDIGIT() instead of isdigit() to avoid warnings and for platforms which don't support non-ascii charater. Wed Dec 10 19:28:56 2003 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_read): set EOF flag at short read. [ruby-dev:22223], [ruby-dev:22224] Wed Dec 10 18:07:25 2003 Minero Aoki * lib/erb.rb: new method ERB#filename(=). [ruby-dev:22208] Wed Dec 10 17:54:51 2003 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_read): do not set EOF flag when requested length is zero. [ruby-dev:22214] Wed Dec 10 17:17:18 2003 Yukihiro Matsumoto * io.c (read_all): should return given string even if data read is empty. [ruby-dev:22207] Wed Dec 10 17:16:06 2003 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_read): adjust behavior at reading beyond EOF to IO. [ruby-dev:22205] * test/ruby/ut_eof.rb (TestEOF::Seek): test behaviors at reading beyond EOF. * test/ruby/test_file.rb, test/stringio/test_stringio.rb: include TestEOF::Seek test case. Wed Dec 10 15:01:19 2003 Shugo Maeda * test/monitor/test_monitor.rb (test_cond): use Queue#deq instead of sleep. Wed Dec 10 14:45:39 2003 WATANABE Hirofumi * ext/pty/pty.c (HAVE_SYS_IOCTL_H): need to include for TIOCSCTTY on *BSD. based on gotoyuzo's patch. (ruby-bugs:PR#1211) * ext/pty/pty.c (establishShell): should close descriptors if fork failed. Wed Dec 10 12:53:05 2003 WATANABE Hirofumi * win32/win32.h: define execv() using do_aspawn(). * process.c (proc_exec_v): remove #ifdef's which stopped needing. Tue Dec 9 23:32:23 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb, ext/tk/lib/tkcanvas.rb, ext/tk/lib/tkdialog.rb, ext/tk/lib/tkentry.rb, ext/tk/lib/tkscrollbox.rb, ext/tk/lib/tktext.rb, ext/tk/sample/tkalignbox.rb, ext/tk/sample/tkcombobox.rb, ext/tk/sample/tkmultilistbox.rb, ext/tk/sample/tkoptdb.rb, ext/tk/sample/tktextframe.rb, ext/tk/sample/demos-en/dialog1.rb, ext/tk/sample/demos-en/dialog2.rb, ext/tk/sample/demos-jp/dialog1.rb, ext/tk/sample/demos-jp/dialog2.rb: overrided instance methods, which are private methods on the super class, are changed to 'private' Tue Dec 9 19:53:02 2003 akira yamada * lib/uri/generic.rb (URI::Generic#route_from0): make case insensitive for host-part. * test/uri/test_generic.rb (test_route): added tests for the above change. Tue Dec 9 14:10:48 2003 Tanaka Akira * io.c (rb_io_check_readable): don't call io_seek if EOF flag is set, to avoid clearing EOF flag. (rb_io_check_writable): ditto. Tue Dec 9 02:53:55 2003 Hidetoshi NAGAI * ext/tk/sample/tkalignbox.rb: new sample script Tue Dec 9 00:45:00 2003 Nathaniel Talbott * lib/test/unit/assertions.rb: renamed #assert_raises to #assert_raise and made the former call the latter. [ruby-core:01890] * test/testunit/test_assertions.rb: ditto. Tue Dec 9 00:07:35 2003 NAKAMURA, Hiroshi * lib/soap/rpc/standaloneServer.rb: add 'shutdown' and 'status' methods as delegates to WEBrick. * test/soap/calc/{test_calc.rb,test_calc2.rb}, test/soap/helloworld/test_helloworld.rb, test/wsdl/datetime/test_datetime.rb, test/wsdl/raa/test_raa.rb: follow the change. Mon Dec 8 22:48:03 2003 Nobuyoshi Nakada * lib/test/unit/autorunner.rb: remove dependency to a particular runner. [ruby-core:01901], [ruby-list:38869] * lib/test/unit/ui/testrunnerutilities.rb: moved output level constants from Console. * lib/test/unit/ui/console/testrunner.rb: ditto. * lib/test/unit/ui/{fox,gtk,gtk2,tk}/testrunner.rb (initialize): accept output_level. Mon Dec 8 15:03:30 2003 Nobuyoshi Nakada * ext/syck/syck.c (syck_io_str_read): get rid of buffer overflow. Mon Dec 8 13:02:11 2003 Minero Aoki * lib/uri/common.rb: new method URI.regexp. [ruby-dev:22121] * test/uri/test_common.rb: add test for URI.regexp. Mon Dec 8 12:44:14 2003 Yukihiro Matsumoto * pack.c: define swap16 and swap32 only if they are not defined. OpenBSD defines these macros. [ruby-dev:22181] Sun Dec 7 20:54:17 2003 Tanaka Akira * ext/iconv/iconv.c (map_charset): make case sensitive. ext/iconv/charset_alias.rb (charset_alias): don't ignore config.charset's information. sort aliases. Sat Dec 6 22:58:03 2003 GOTOU Yuuzou * ext/openssl/ossl_ssl.c (ossl_start_ssl): new function to wrap SSL_connect and SSL_accept; if SSL_connect (or SSL_accept) returned but not finished the handshake process, we should retry it. * ext/openssl/ossl_ssl.c (ossl_ssl_connect): call ossl_start_ssl. * ext/openssl/ossl_ssl.c (ossl_ssl_accept): ditto. * ext/openssl/ossl_ssl.c (ossl_ssl_read): allow signal traps. Sat Dec 6 21:45:10 2003 WATANABE Hirofumi * io.c (flush_before_seek): flush before seek on any platform. * configure.in: ditto. Sat Dec 6 17:23:00 2003 NAKAMURA, Hiroshi * lib/soap/soap.rb(SOAP::Env.getenv): allow upcase environment variable as well as downcase one. * lib/soap/netHttpClient.rb(SOAP::NetHttpClient#proxy=): check URI. Fri Dec 5 23:22:30 2003 Nobuyoshi Nakada * lib/test/unit/assertions.rb (Test::Unit::Assertions::assert_raises, Test::Unit::Assertions::assert_nothing_raised): use the last argument as message unless class object. * test/testunit/test_assertions.rb (test_assert_raises): test for multiple exception list. [ruby-core:01891] * test/testunit/test_assertions.rb (test_assert_nothing_raised): test for non-exception classes. Fri Dec 5 22:23:04 2003 NAKAMURA, Hiroshi * lib/soap/netHttpClient.rb: proxy support did not work. fixed. * lib/soap/property.rb: add class methods for loading property from stream/file/propertyfile. propertyfile is a file which is located at somedir in $:. * lib/soap/soap.rb, lib/soap/wsdlDriver.rb, lib/soap/rpc/driver.rb, lib/wsdl/importer.rb: load property from propertyfile 'soap/property' e.g. /usr/local/lib/ruby/site_ruby/1.8/soap/property. * test/soap/test_property.rb, test/soap/test_streamhandler.rb: new file. Fri Dec 5 17:26:23 2003 Nobuyoshi Nakada * eval.c (rb_exec_end_proc): maintain tmp_end_procs. [ruby-dev:22154] Fri Dec 5 13:36:59 2003 Yukihiro Matsumoto * eval.c (rb_exec_end_proc): should not clear end_procs and ephemeral_end_procs before execution. [ruby-dev:22144] * eval.c (rb_obj_extend): call Module#extended hook after extended_object. [ruby-list:38866] * object.c (Init_Object): Module#extended defined. Fri Dec 5 13:17:30 2003 Tanaka Akira * test/ruby/test_pipe.rb: use IO.pipe instead of IO.popen. Fri Dec 5 11:54:45 2003 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_read): follow IO#read. * test/ruby/ut_eof.rb, test/ruby/test_file.rb, test/ruby/test_pipe.rb, test/stringio/test_stringio.rb: add EOF test. Fri Dec 5 02:49:35 2003 Nobuyoshi Nakada * lib/test/unit/assertions.rb (Test::Unit::Assertions::assert_raises): allow multiple exception list. [ruby-core:01884] * lib/test/unit/assertions.rb (Test::Unit::Assertions::assert_nothing_raised): check whether arguments are subclass of Exception. Thu Dec 4 23:54:00 2003 Rick Ohnemus * dln.c (aix_loaderror): should not use member named 'errno' which might be a macro (e.g. on AIX). Thu Dec 4 23:32:26 2003 Yukihiro Matsumoto * io.c (read_all): do not depend on lseek position. [ruby-dev:22026] Thu Dec 4 22:37:26 2003 Nobuyoshi Nakada * eval.c (rb_eval): preserve $! value when retry happens in the rescue clause. [ruby-talk:86697] Thu Dec 4 21:50:07 2003 Nobuyoshi Nakada * lib/drb/drb.rb (DRb::DRbMessage::send_request, send_reply): should rescue errors and re-raise DRbConnError on write too. [ruby-dev:22132] Thu Dec 4 16:41:17 2003 Nobuyoshi Nakada * parse.y (exc_list): allow expanding list. [ruby-dev:22134] Thu Dec 4 14:09:24 2003 Minero Aoki * test/fileutils/test_fileutils.rb (test_cp): test if the error is kind of SystemCallError. It is needless details that which errno is set on each systems. Thu Dec 4 13:24:13 2003 Shugo Maeda * lib/monitor.rb: use Object#__send__ instead of Object#send. Thu Dec 4 13:17:45 2003 NAKAMURA, Hiroshi * lib/soap/streamHandler.rb: support latest released version of http-access2. Thu Dec 4 13:04:44 2003 NAKAMURA, Hiroshi * lib/soap/soap.rb: add SOAP::Env module for environment repository such as HTTP_PROXY. * lib/soap/property.rb: property implementation. * lib/soap/streamHandler.rb, lib/soap/wsdlDriver.rb, lib/soap/rpc/driver.rb: use soap/property.rb. * lib/wsdl/importer.rb, lib/soap/wsdlDriver.rb, lib/soap/rpc/driver.rb: use SOAP::Env. * lib/soap/netHttpClient.rb: add basic_auth, ssl_config, and cookie management interface, but ignored for now. * lib/xsd/charset.rb: add XSD::Charset.encoding= interface to set wiredump charset explicitly. it was fixed to 'utf-8' when iconv or uconv module was found. Thu Dec 4 10:43:58 2003 NAKAMURA Usaku * ext/dl/sym.c (rb_dlsym_guardcall): __declspec(noinline) is VC7 feature. Thu Dec 4 10:27:12 2003 Minero Aoki * lib/net/http.rb: update hyperlink to the Japanese document. Thu Dec 4 09:12:43 2003 GOTOU Yuuzou * ext/openssl/ossl_asn1.c (asn1time_to_time): should check that the underlying value of ASN1_TIME isn't NULL. [ruby-core:01881] Thu Dec 4 08:29:43 2003 GOTOU Yuuzou * lib/webrick/server.rb (GenericServer#start): should rescue Exception to avoid unexpected aborting. [ruby-core:01853] * lib/webrick/server.rb (GenericServer#start_thread): should check that peeraddr isn't nil before printing. * lib/webrick/httpresponse.rb (HTTPResponse#start_thread): should rescue Exception to avoid unexpected aborting of thread. Thu Dec 4 03:48:59 2003 Tanaka Akira * lib/pathname.rb (Pathname#link, Pathname#symlink): obsoleted. (Pathname#make_link, Pathname#make_symlink): new method. Thu Dec 4 01:45:24 2003 Yukihiro Matsumoto * io.c (argf_read): should not terminate on empty string; wait until real EOF. [ruby-dev:21969] * io.c (argf_read): should adjust length to read, when length is specified and read spans command line argument files. Wed Dec 3 19:38:36 2003 Masatoshi SEKI * lib/drb/drb.rb: correct fcntl parameter. [ruby-dev:22120] Wed Dec 3 13:49:07 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: 'format'==>'Kernel.format' (avoid override trouble) * ext/tk/lib/tkafter.rb: ditto. * ext/tk/lib/tkcanvas.rb: ditto. * ext/tk/lib/tkdialog.rb: ditto. * ext/tk/lib/tktext.rb: ditto. Wed Dec 3 13:28:13 2003 Nobuyoshi Nakada * Makefile.in (lex.c): try gperf first, and copy from the source directory if failed. [ruby-dev:22123] * ext/extmk.rb (MTIMES): let makefiles depend to mkmf.rb. * lib/mkmf.rb (configuration): DLDFLAGS was duplicated. Tue Dec 2 23:18:12 2003 Minero Aoki * lib/net/http.rb: wrote the warning about HTTP_PROXY environment variable. Tue Dec 2 21:31:42 2003 Nobuyoshi Nakada * bin/testrb: new test runner. [ruby-core:01845] * lib/test/unit/autorunner.rb (Test::Unit::AutoRunner.run, Test::Unit::AutoRunner#process_args): take test list to run and options. * lib/test/unit/autorunner.rb (Test::Unit::AutoRunner::RUNNERS, Test::Unit::AutoRunner#run): should not exit inside a library, just return the result instead. * lib/test/unit.rb: ditto. * test/runner.rb: exit with the test result. Tue Dec 2 20:18:48 2003 Eric Sunshine * configure.in (AC_PROG_YACC): AC_DEFINE(OLD_YACC) if Yacc is found instead of Bison or byacc. * parse.y: If OLD_YACC is defined, ensure that YYMAXDEPTH is at least 10000 (Bison's default) since some old versions of Yacc define it as low as 150 by default, which is too low for Ruby to parse some files, such as date/format.rb. Among other issues, the parse problem causes "make test" to fail. Tue Dec 2 20:03:20 2003 Minero Aoki * test/fileutils/test_fileutils.rb: check if Pathnames are usable for arguments. Tue Dec 2 04:22:00 2003 Nathaniel Talbott * lib/test/unit/assertions.rb: fixed #assert_no_match message. * test/testunit/test_assertions.rb: ditto. Tue Dec 2 00:43:00 2003 why the lucky stiff * ext/syck/syck.c: string buffering bug. decrementing by full max_size now. [ruby-core:01834] Mon Dec 1 21:33:08 2003 Yukihiro Matsumoto * numeric.c (num_sadded): prohibit singleton method definition for Numerics. fill yet another gap between Fixnum and Bignum. Mon Dec 1 17:33:47 2003 Yukihiro Matsumoto * pack.c (htov16): converts endian using swap16. htov32(), hton16, hton32 as well. [ruby-talk:85377] * pack.c (swap16): swap 2 bytes no matter how big short is on the platform. swap32() is also prepared. * numeric.c (rb_num2int): returns long to preserve information. rb_fix2int(), rb_num2uint(), rb_fix2uint() as well. [ruby-talk:85377] * numeric.c (rb_num2uint): should not check for value range if the source value is negative. Mon Dec 1 17:14:34 2003 Nobuyoshi Nakada * sample/optparse/opttest.rb: added. Mon Dec 1 16:10:52 2003 Dave Thomas * lib/rdoc/rdoc.rb: (etc) initial merge into main tree. Mon Dec 1 14:17:49 2003 Minero Aoki * lib/fileutils.rb (fu_each_src_dest0): call #to_str to allow Pathname for arguments. [ruby-core:01795] * test/fileutils/test_fileutils.rb: does much strict test on "same" files detecting. Mon Dec 1 09:28:14 2003 NAKAMURA Usaku * bcc32/Makefile.sub, win32/Makefile.sub, wince/Makefile.sub (XCFLAGS): re-export $(XCFLAGS). * bcc32/Makefile.sub, win32/Makefile.sub, wince/Makefile.sub (ARCH_FLAG): export $(ARCH_FLAG) (perhaps empty value). Mon Dec 1 01:03:27 2003 WATANABE Hirofumi * lib/mkmf.rb (TRY_LINK, link_command): added support for DLDFLAGS and ARCH_FLAG. [ruby-dev:22085] Sun Nov 30 20:18:07 2003 WATANABE Hirofumi * configure.in: keep ARCH_FLAG separate. export ARCH_FLAG. [ruby-core:01819] * Makefile.in: add ARCH_FLAG to CFLAGS. * Makefile.in: add @CPPFLAGS@ to CPPFLAGS. * lib/mkmf.rb (link_command, cc_command): use ARCH_FLAG. * lib/mkmf.rb (configuration): add ARCH_FLAG to DLDFLAGS. * Makefile.in: add ARCH_FLAG to DLDFLAGS. * configure.in: should put getcwd in AC_CHECK_FUNCS, not AC_REPLACE_FUNCS. [ruby-core:01826] Sun Nov 30 18:22:48 2003 WATANABE Hirofumi * configure.in: do not override CCDLDFLAGS, LDFLAGS, XLDFLAGS, DLDFLAGS and LDSHARED. * configure.in: XCFLAGS for compiling ruby itself. ARCH_FLAG is reflected in CFLAGS. * lib/mkmf.rb: ditto. do not import XCFLAGS from config.status. Sun Nov 30 17:37:36 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: bug fix [ruby-talk:86746] Sun Nov 30 13:02:00 2003 NAKAMURA, Hiroshi * lib/soap/encodingstyle/soapHandler.rb: refactoring - Simplifying Conditional Expressions. * lib/wsdl/soap/definitions.rb: refactoring - Move Method. * test/xsd/{test_noencoding.rb,noencoding.xml}: new files. test for encoding unspecified XML file parsing. * test/wsdl/{test_fault.rb,map,datetime}: new files. test of SOAPFault, dateTime and Apache's Map. Sun Nov 30 09:35:14 2003 Nobuyoshi Nakada * string.c (rb_str_update): get rid of SEGV at just allocated String. [ruby-core:01812] Fri Nov 28 23:19:34 2003 Yukihiro Matsumoto * gc.c (gc_mark): explicitly check mark recursion levels, instead of unreliable stack length. Fri Nov 28 22:49:56 2003 Masatoshi SEKI * lib/rinda/rinda.rb: fix TupleSpaceProxy#read, read_all. Fri Nov 28 21:44:40 2003 WATANABE Hirofumi * test/fileutils/test_fileutils.rb (test_ln_s): should be a file, not a directory for FreeBSD. Fri Nov 28 19:37:56 2003 Nobuyoshi Nakada * hash.c (env_has_value, env_index): must match exactly. * test/ruby/test_env.rb (test_has_value, test_index): condition for aboves. Fri Nov 28 17:59:20 2003 NAKAMURA Usaku * test/ruby/test_env.rb: add tests for ENV. Fri Nov 28 17:47:46 2003 Masatoshi SEKI * lib/drb/drb.rb (DRbMessage#load): rescue Errno::* and raise DRbConnError. Fri Nov 28 15:41:15 2003 Tanaka Akira * lib/pathname.rb (Pathname#realpath): obsolete the force_absolute argument. Fri Nov 28 14:41:52 2003 NAKAMURA, Hiroshi * lib/soap/streamHandler.rb: drop unused http parameters. * lib/soap/encodingstyle/soapHandler.rb, lib/soap/mapping/factory.rb, lib/soap/mapping/mapping.rb, lib/soap/mapping/registry.rb, lib/wsdl/soap/complexType.rb: ApacheSOAP's map support was broken under WSDL dynanic client environment. fixed. * test/wsdl/raa/*: add tests. * lib/xsd/datatypes.rb: dateTime precision bug fix (at least, I hope.) bug of soap4r. XSDDateTimeImple.to_time passed a Float to Time.local/Time.gm as an usec, and NUM2LONG(rb_num2long for Float) causes rounding error. * test/soap/test_basetype.rb, test/xsd/test_xsd.rb: add tests. Fri Nov 28 04:15:24 2003 Nobuyoshi Nakada * eval.c (method_arity): used wrong Proc object. [ruby-talk:86504] Fri Nov 28 00:47:29 2003 Nobuyoshi Nakada * eval.c (rb_f_exit), process.c (rb_f_exit_bang): treat true as success, false as failure. [ruby-dev:22067] * eval.c (rb_f_abort, rb_thread_switch), process.c (rb_f_system): use ANSI macro instead of hard coded value. * eval.c (rb_f_exit), process.c (rb_f_exit_bang): use VALUEs not but TYPEs. Thu Nov 27 22:05:48 2003 Akinori MUSHA * eval.c, gc.c: FreeBSD/ia64 currently does not have a way for a process to get the base address for the RSE backing store, so hardcode it for the moment. [submitted by: Marcel Moolenaar ] Thu Nov 27 17:36:42 2003 Hidetoshi NAGAI * ext/tk/lib/tkafter.rb: bug fix on TkTimer#cancel_on_exception=(mode). TkTimer#wait recieves the exception of the callback. The exception is kept on @return_value. Thu Nov 27 16:58:48 2003 WATANABE Hirofumi * win32/win32.c (rb_w32_stat): remove _fullpath() for NUL: device. Wed Nov 26 15:38:47 2003 WATANABE Hirofumi * test/fileutils/test_fileutils.rb (test_ln_s): should take the existing symbolic link for OpenBSD. Wed Nov 26 04:48:42 2003 why the lucky stiff * ext/syck/token.c: removed YYTOKTMP references which were causing buffer overflows on large block scalars, comments, quoted scalars and plain scalars. * ext/syck/rubyext.c: dynamic changing of buffer size. * ext/syck/syck.h: default buffer size of 4k. Wed Nov 26 00:55:30 2003 GOTOU Yuuzou * lib/webrick/httpresponse.rb: add HTTPResponse#keep_alive=. * lib/webrick/httpserver.rb (HTTPServer#run): should pass the request's keep_alive flag to the response. Tue Nov 25 21:41:35 2003 NAKAMURA Usaku * defines.h (ENV_IGNORECASE): should define when DOSISH without human68k. [ruby-dev:22047] * hash.c (env_has_value, env_index): don't ignore case of value. [ruby-dev:22048] Tue Nov 25 21:39:37 2003 Yukihiro Matsumoto * file.c (path_check_1): honor sticky bits always. [ruby-talk:86273] Tue Nov 25 20:02:14 2003 Minero Aoki * test/fileutils/test_fileutils.rb: do test in more deep directory. * test/fileutils/test_nowrite.rb: ditto. Tue Nov 25 19:04:23 2003 Tanaka Akira * lib/open-uri.rb (URI::Generic#find_proxy): ENV case sensitivity test refined. Tue Nov 25 18:13:30 2003 Minero Aoki * test/fileutils/test_fileutils.rb: chdir Dir.tmpdir before each test. [ruby-dev:22045] * test/fileutils/test_nowrite.rb: ditto. Tue Nov 25 17:52:11 2003 Tanaka Akira * lib/open-uri.rb (URI::Generic#find_proxy): use http_proxy under CGI if the environment variable is case sensitive. Tue Nov 25 16:41:33 2003 NAKAMURA, Hiroshi * test/wsdl/multiplefault.wsdl, test/wsdl/test_multiplefault.rb: removed. this test requires extra libraries in soap4r/1.5.*. Tue Nov 25 16:24:42 2003 NAKAMURA, Hiroshi * lib/soap/**/*.rb, lib/wsdl/**/*.rb, lib/xsd/**/*.rb: changed license; GPL2 -> Ruby's. * lib/soap/rpc/driver.rb, lib/soap/wsdlDriver.rb, lib/soap/streamHandler.rb: add interface to streamhandler. * lib/soap/marshal.rb: raise error if parse fails. * lib/soap/netHttpClient.rb: add https support. Patched by Oliver M. Bolzer. * lib/soap/netHttpClient.rb: dump HTTP response message body by itself. * lib/soap/rpc/driver.rb, lib/soap/rpc/proxy.rb, lib/soap/wsdlDriver.rb: add driver#mandatorycharset interface to foce using charset for parsing response from buggy server. * lib/soap/encodingstyle/soapHandler.rb: support Apache Axis's half typed multi-ref array. * lib/soap/mapping/factory.rb, lib/soap/mapping/registry.rb: map SOAPStruct which has multi-accessors which name are the same, to an array. * lib/soap/rpc/element.rb: fixed illegal parameter order. * lib/soap/rpc/element.rb: element name of response message could have the name other than 'return'. * lib/wsdl/operation.rb, lib/wsdl/operationBinding.rb, lib/wsdl/soap/classDefCreator.rb, lib/wsdl/soap/methodDefCreator.rb, lib/wsdl/soap/methodDefCreatorSupport.rb: WSDL/1.1 allows plural fault definition in a operation. [ruby-talk:84948] * test/wsdl/multiplefault.wsdl, test/wsdl/test_multiplefault.rb: add test for above fix. * lib/wsdl/soap/complexType.rb: support WSDL array definition with maxOccures="unbound". * lib/xsd/charset.rb: use cp932 under emx. Patched by Siena. / SHINAGAWA, Norihide in [ruby-dev:21972] * lib/xsd/xmlparser/parser.rb: set @charset nil by default. Nil means 'follow encoding declaration in XML'. * sample/soap/digraph.rb, sample/wsdl/amazon/wsdlDriver.rb, sample/wsdl/googleSearch/sampleClient.rb, sample/wsdl/googleSearch/wsdlDriver.rb, test/wsdl/test_emptycomplextype.rb, test/wsdl/marshal/test_wsdlmarshal.rb, test/xsd/test_xmlschemaparser.rb: use File.open(...) { |f| f.read } instead of File.open(...).read. [ruby-dev:21964] * test/wsdl/emptycomplextype.wsdl, test/wsdl/test_emptycomplextype.rb: simplify the test case. * test/wsdl/axisArray/*: add tests for axis's array encoding. Tue Nov 25 16:15:29 2003 WATANABE Hirofumi * ruby.h: don't treat Cygwin as Windows. Tue Nov 25 15:18:28 2003 Hidetoshi NAGAI * configure.in: change default value of --enable-pthread (default: no) Tue Nov 25 07:31:16 2003 Nobuyoshi Nakada * parse.y (primary): allow newlines just before right argument parenthesis. (ruby-bugs:PR#1221) Mon Nov 24 23:32:06 2003 Tanaka Akira * lib/open-uri.rb (OpenURI.open_loop, URI::HTTP#proxy_open): use catch/throw for redirection instead of exception. (OpenURI.open_loop, OpenURI.redirectable?): restrict redirection. Mon Nov 24 19:59:48 2003 Tanaka Akira * lib/open-uri.rb (URI::Generic#find_proxy): use CGI_HTTP_PROXY instead of HTTP_PROXY in the CGI environment. Mon Nov 24 19:32:55 2003 WATANABE Hirofumi * ext/etc/extconf.rb: check for pw_passwd in struct passwd and gr_passwd in struct group for DJGPP. * ext/etc/etc.c: ditto. * ext/Setup.dj: support for curses, etc, zlib. Mon Nov 24 17:00:00 2003 Tanaka Akira * lib/open-uri.rb: validate option names. :content_length_proc and :progress_proc option implemented. Mon Nov 24 14:53:10 2003 NAKAMURA Usaku * bcc32/Makefile.sub, win32/Makefile.sub, wince/Makefile.sub (XCFLAGS): output empty value instead of `-DRUBY_EXPORT'. Sat Nov 22 23:09:45 2003 WATANABE Hirofumi * configure.in: set enable_pthread to no on MinGW. Sat Nov 22 22:56:20 2003 Hidetoshi NAGAI * configure.in: add --enable-pthread option (default: yes) Sat Nov 22 22:48:46 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: add Tk.grab_release and fix bug of TkComposite * ext/tk/lib/tkafter.rb: bug fix of TkAfter#start * ext/tk/sample/tkcombobox.rb: new sample script * ext/tcltklib/tcltklib.c: add native thread check Sat Nov 22 18:49:47 2003 NAKAMURA Usaku * ext/curses/curses.c (window_nodelay): nodelay() of NetBSD's libcruses returns no value, just like keypad(). Sat Nov 22 17:36:36 2003 NAKAMURA Usaku * bcc32/Makefile.sub, win32/Makefile.sub, wince/Makefile.sub (HAVE_GETCWD): output to config.h. * bcc32/Makefile.sub, win32/Makefile.sub, wince/Makefile.sub (XCFLAGS): output to config.status. Sat Nov 22 13:10:10 2003 Minero Aoki * lib/fileutils.rb (have_st_ino?): djgpp has valid st_ino. Sat Nov 22 11:28:48 2003 Yukihiro Matsumoto * gc.c (Init_stack): stack region is far smaller than usual if pthread is used. Sat Nov 22 07:30:00 2003 Nathaniel Talbott * lib/test/unit/util/backtracefilter.rb: fixed a bug that occurred when an exception had no backtrace. * test/testunit/util/test_backtracefilter.rb: ditto. Fri Nov 21 16:44:18 2003 Hidetoshi NAGAI * ext/tk/lib/tkentry.rb: fix the encoding trouble of percent substitutions on validatecommand option of TkEntry widget * ext/tk/lib/tk.rb: fix bug on {pack|grid}_propagate() method Fri Nov 21 16:12:11 2003 Akinori MUSHA * ruby.1: Fix markups and grammar. Fri Nov 21 14:49:42 2003 Minero Aoki * ruby.1: wrote about ruby related environment variables. Fri Nov 21 12:28:03 2003 Yukihiro Matsumoto * marshal.c (w_extended): singleton methods should not be checked when dumping via marshal_dump() or _dump(). [ruby-talk:85909] Fri Nov 21 01:40:00 2003 Hidetoshi NAGAI * configure.in: check * ruby.h: include pthread.h if existence. define is_ruby_native() macro when not HAVE_NATIVETHREAD * eval.c: undef is_ruby_native() function when not HAVE_NATIVETHREAD Fri Nov 21 00:43:00 2003 Nathaniel Talbott * lib/test/unit/assertions.rb: use #__send__ instead of #send. * lib/test/unit/testcase.rb: ditto. Thu Nov 20 19:19:22 2003 WATANABE Hirofumi * configure.in: don't find the Cygwin's pthread library on MinGW. Thu Nov 20 19:15:50 2003 Minero Aoki * lib/fileutils.rb (have_st_ino?): emx (OS/2 with EMX) does not have st_ino (always 0). [ruby-dev:21972] * lib/fileutils.rb (rename_cannot_overwrite_file?): emx does not allow overwriting files by rename(2). * test/fileutils/test_fileutils.rb: windows? -> have_drive_letter?, have_file_perm? Thu Nov 20 17:50:58 2003 Hidetoshi NAGAI * ext/tk/sample/tkballoonhelp.rb: new sample script * ext/tk/sample/tkmultilistbox.rb: ditto * ext/tk/sample/tktextframe.rb: ditto Thu Nov 20 13:37:34 2003 Hidetoshi NAGAI * ruby.h: define is_ruby_native_thread() for no native thread environment * eval.c: ditto Thu Nov 20 12:42:47 2003 Hidetoshi NAGAI * configure.in: always check existence of the pthread library * ruby.h: define macros for ruby's native thread check * eval.c: add ruby's native thread check * gc.c: ditto Wed Nov 19 14:45:18 2003 Minero Aoki * lib/net/http.rb (to_ary): print more friendly warning message. Wed Nov 19 14:32:08 2003 Minero Aoki * lib/fileutils.rb (fu_same?): add djgpp and wince. * lib/fileutils.rb (cannot_overwrite_file?): add wince. Wed Nov 19 11:04:47 2003 NAKAMURA Usaku * lib/fileutils.rb (cannot_overwrite_file?, have_st_ino?): bccwin32 is same as mswin32. Wed Nov 19 07:54:00 2003 Nathaniel Talbott * lib/test/unit.rb: do not run tests if $! is set. * lib/test/unit/assertionfailederror.rb: extend StandardError instead Exception (irb catches the former but not the latter). Tue Nov 18 23:31:36 2003 WATANABE Hirofumi * missing/memmove.c (memmove): take void *, not char *. * missing.h (memmove): ditto. * missing.h (strchr, strrchr): return char *, not int. Tue Nov 18 22:20:10 2003 Minero Aoki * lib/fileutils.rb (fu_same?): temporal fix for windows. Tue Nov 18 19:05:04 2003 Minero Aoki * lib/fileutils.rb (fu_same?): check by inode instead of path name, to detect two hard links pointing to the same content. * test/fileutils.rb: did not create correctly looped symlinks. Tue Nov 18 18:23:05 2003 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_read): behave as IO at empty string. [ruby-dev:21939], [ruby-dev:21941] * ext/stringio/stringio.c (strio_getc, strio_getline): set EOF flag. * ext/stringio/stringio.c (strio_rewind, strio_seek, strio_ungetc): clear EOF flag. * test/stringio/test_stringio.rb: imported from [ruby-dev:21941]. Tue Nov 18 14:06:35 2003 Minero Aoki * lib/fileutils.rb (fu_each_src_dest): raise if src==dest. [ruby-talk:85344] [ruby-core:01699] * lib/fileutils.rb: use Object#is_a? instead of Class#=== to allow e.g. remote objects for receivers. * lib/fileutils.rb: FileTest -> File. * lib/fileutils.rb: put parentheses for arguments of File.xxxx? * test/fileutils/test_fileutils.rb (test_cp): test "cp a a". * test/fileutils/test_fileutils.rb (test_mv): test "mv a a". * test/fileutils/test_fileutils.rb (test_ln): test "ln a a". * test/fileutils/test_fileutils.rb (test_ln_s): test "ln_s a a". * test/fileutils/test_fileutils.rb (test_install): test "install a a". * test/fileutils/fileasserts.rb: new method assert_symlink. * test/fileutils/fileasserts.rb: assert_is_directory -> assert_directory. Mon Nov 17 19:38:49 2003 Yukihiro Matsumoto * file.c (getcwdofdrv): avoid using getcwd() directly, use my_getcwd() instead. * merged NeXT, OpenStep, Rhapsody ports patch from Eric Sunshine . [ruby-core:01596] Mon Nov 17 10:50:27 2003 Nobuyoshi Nakada * lib/optparse.rb (OptionParser::Completion::complete): allow least common completion for three or more candidates. Mon Nov 17 09:41:38 2003 Nobuyoshi Nakada * lib/test/unit/ui/tk/testrunner.rb, lib/test/unit/ui/gtk/testrunner.rb: run GUI main loop in sub thread. * lib/test/unit/ui/gtk2/testrunner.rb: imported from rough. * lib/test/unit/autorunner.rb (keyword_display): sort keywords. Sun Nov 16 18:10:57 2003 Nobuyoshi Nakada * eval.c (rb_eval): iterator should return value from next inside begin/rescue/end. (ruby-bugs:PR#1218) Sun Nov 16 13:26:07 2003 Yukihiro Matsumoto * marshal.c (w_object): LINK check earlier than anything else, i.e. do not dump TYPE_IVAR for already dumped objects. (ruby-bugs:PR#1220) * eval.c (rb_eval): call "inherited" only when a new class is generated; not on reopening. * eval.c (eval): prepend error position in evaluating string to "mesg" attribute string only when it's available and is a string. Sun Nov 16 12:16:10 2003 Minero Aoki * lib/net/protocol.rb: logging response body. [experimental] [ruby-list:38800] Sun Nov 16 10:49:38 2003 Gavin Sinclair * lib/thread.rb (Thread.exclusive): wrap method definition in class Thread to enable rdoc to process. Sun Nov 16 09:45:23 2003 Minero Aoki * lib/net/http.rb (set_debug_output): warn if method is called after #start. [ruby-dev:38798] Sun Nov 16 04:41:33 2003 Yukihiro Matsumoto * eval.c (eval): do not re-raise exception to avoid unnecessary exception copying, instead modify exception and internal information to adjust eval(). * eval.c (backtrace): can return the current frame information only if lev < -1. Sat Nov 15 22:16:42 2003 GOTOU Yuuzou * /ext/openssl/ossl_x509ext.c (ossl_x509extfactory_create_ext): refine error message. Sat Nov 15 10:05:40 2003 Tanaka Akira * lib/open-uri.rb (OpenURI.open_loop, OpenURI::HTTP#proxy_open): refactored to support options. (Buffer): maintain size by this class. Sat Nov 15 07:40:14 2003 Yukihiro Matsumoto * eval.c (rb_method_node): new API to retrieve method body. Fri Nov 14 13:21:30 2003 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: fix (en-bugged at 2003/11/07) * ext/tk/lib/tkdialog.rb: TkDialog.new accepts a parent widget argument [ruby-talk:85066] Thu Nov 13 20:53:35 2003 Tanaka Akira * lib/open-uri.rb (Kernel[#.]open): hard coded URI schemes removed. [ruby-ext:02251] Thu Nov 13 19:17:00 2003 Hidetoshi NAGAI * lib/test/unit/ui/tk/testrunner.rb: use grid and panedwindow (if available) Thu Nov 13 17:56:41 2003 Tanaka Akira * lib/open-uri.rb (OpenURI.open_uri): use File::RDONLY. reported by Take_tk . [ruby-ext:02245] Thu Nov 13 16:45:53 2003 GOTOU Yuuzou * ext/openssl/ossl_x509req.c (ossl_x509req_to_der): add function for X509::Request#to_der. Thu Nov 13 11:31:14 2003 Nobuyoshi Nakada * lib/optparse.rb (OptionParser::Completion#complete): prior shorter name to containing longer name. Thu Nov 13 06:08:54 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: stop freezing some classes * ext/tk/lib/multi-tk.rb: ditto. Wed Nov 12 17:32:49 2003 Nobuyoshi Nakada * lib/test/unit/assertions.rb (assert_throws, assert_nothing_thrown): uncaught throw in sub thread raises ThreadError. * lib/test/unit/ui/tk/testrunner.rb (setup_ui): "expand" is not necessary. Wed Nov 12 14:09:43 2003 Shugo Maeda * test/monitor/test_monitor.rb: fix the timing problem by Queue. Wed Nov 12 12:59:44 2003 Shugo Maeda * test/monitor/test_monitor.rb: added. Wed Nov 12 10:14:28 2003 Shugo Maeda * lib/monitor.rb: refactored. Thanks, Gennady Bystritsky. Wed Nov 12 06:11:39 2003 GOTOU Yuuzou * ext/openssl/ossl.c (ossl_x509_sk2ary, ossl_x509crl_sk2ary): add functions to convert STACK into Array. * ext/openssl/ossl.h: add prototypes. * ext/openssl/ossl_pkcs7.c (ossl_pkcs7_set_certificates, ossl_pkcs7_get_certificates, ossl_pkcs7_get_crls, ossl_pkcs7_set_crls): add functions for PKCS7#certificates= PKCS7#certificates, PKCS7#crls= and PKCS7#crls. Wed Nov 12 00:47:00 2003 Nathaniel Talbott * lib/test/unit/ui/testrunnermediator.rb: should require 'test/unit'. Tue Nov 11 23:54:00 2003 Nathaniel Talbott * lib/test/unit/ui/gtk/testrunner.rb: added a rescue clause to handle the case when the requested font is not available. Tue Nov 11 22:44:08 2003 Yukihiro Matsumoto * io.c (appendline): file may not end with newline. a bug if READ_DATA_PENDING_PTR is defined. [ruby-talk:84925] Tue Nov 11 10:42:41 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: raise an exception when creating TkWindow object, because TkWindow class is an abstract class. Tue Nov 11 03:30:43 2003 GOTOU Yuuzou * lib/ext/openssl/ossl_conf.c (ossl_config_get_value): return nil if the specified value doesn't exist. * lib/ext/openssl/ossl_conf.c (ossl_config_get_section): return a empty hash if the specified section doesn't exist. Mon Nov 10 11:40:29 2003 Shugo Maeda * lib/monitor.rb (wait): return true on signal/broadcastfalse and false on timeout. Thanks Gennady Bystritsky. Mon Nov 10 00:07:10 2003 Nobuyoshi Nakada * parse.y (primary): primary_value may be 0 when syntax error. [ruby-talk:84893] Sun Nov 9 02:05:00 2003 Nathaniel Talbott * lib/test/unit/assertions.rb: un-deprecated #assert_not_nil to maintain symmetry with #assert_nil. Also added better output for #assert_kind_of. * test/testunit/tc_assertions.rb: ditto. Sat Nov 8 18:50:20 2003 NAKAMURA, Hiroshi * test/wsdl/raa/*: add new testcase for WSDL loading, parsing and reading. * test/soap/marshal/*: backport from soap4r/1.5.1. all differences are for ruby/1.6. * lib/soap/*: backport from soap4r/1.5.1. all differences are for ruby/1.6. * lib/wsdl/data.rb, lib/wsdl/xmlSchema/data.rb: move definition of ArrayTypeAttrName from ::WSDL::XMLSchema::* to ::WSDL::*. [ruby-talk:84813] * lib/wsdl/soap/definitions.rb: element name typo in custom exception struct definition which is needed for wsdlDriver; camelCase -> underscore_name. Sat Nov 8 13:49:50 2003 Hidetoshi NAGAI * configure.in: improvement of pthread check Sat Nov 8 13:28:46 2003 Takaaki Tateishi * ext/dl/sym.c: Add DL.win32_last_error and DL.last_error. Thanks, Kaoru Shirai. Sat Nov 8 06:19:38 2003 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: To fix 'pthread-enabled Tcl/Tk' problem, TclTkIp#_eval calls Tcl_Eval() on the mainloop thread only (queueing a handler to the EventQueue). * ext/tcltklib/README.1st: edit the description of '--with-pthread-ext' Fri Nov 7 23:23:04 2003 Tanaka Akira * lib/pathname.rb (Pathname#+): if self or the argument is `.', return another. (Pathname#parent): if self is `.', return `..'. (Pathname#children): if self is `.', don't prepend self for a pathname in a result. (Pathname#join): re-implemented using Pathname#+. (Pathname#find): if self is `.', remove `./' prefix of yielding pathname. Fri Nov 7 10:23:24 2003 Nobuyoshi Nakada * ext/socket/socket.c (make_hostent): get rid of SEGV on aliases lookup failure. (ruby-bugs:PR#1215) Fri Nov 7 04:08:05 2003 UENO Katsuhiro * ext/zlib/zlib.c (Init_zlib): define Zlib::GzipReader#each_line as an alias of Zlib::GzipReader#each. Fri Nov 7 01:03:16 2003 Yukihiro Matsumoto * eval.c (rb_load): save and restore rb_prohibit_interrupt. [ruby-dev:21857] Thu Nov 6 18:05:07 2003 Nobuyoshi Nakada * io.c (rb_io_inspect): show the path also at a closed file. [ruby-dev:21851] Thu Nov 6 11:42:07 2003 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_set_string, strio_reopen): check tainted. * ext/stringio/stringio.c (strio_copy, strio_ungetc, strio_write, strio_putc): add infection. * ext/stringio/stringio.c (strio_path): just nil. [ruby-dev:21846] * ruby.c (proc_options): reserve searched script path in the source file name table. [ruby-list:38765] * lib/optparse.rb (OptionParser::Completion#complete): default not to ignore case on completion. [ruby-talk:84726] * win32/win32.c (make_cmdvector): process backslashes even if a quote is not enclosed. Wed Nov 5 23:49:45 2003 NAKAMURA, Hiroshi * sample/openssl/gen_csr.rb: there (at least) is a CA which does not accept DN in UTF8STRING format. it's a sample. Wed Nov 5 22:55:16 2003 Hidetoshi NAGAI * configure.in, eval.c, signal.c: : add '--with-pthread-ext' option to fix the pthread trouble on 'tcltklib' * ext/tcltklib/README.1st: add the description of '--with-pthread-ext' * ext/tk/lib/tktext.rb : add TkText#text_copy, text_cut, text_paste to support Tcl/Tk8.4's tk_textCopy, tk_textCut, tk_textPaste * ext/tk/lib/tk.rb : add TkMenu#set_focus support Tcl/Tk's tk_menuSetFocus Wed Nov 5 17:33:45 2003 Yukihiro Matsumoto * eval.c (rb_load): allow interrupt during loaded program evaluation. [ruby-dev:21834] * hash.c (rb_hash_fetch): always warn if default argument and a block are supplied at the same time. [ruby-dev:21842] * hash.c (env_fetch): ditto. * array.c (rb_ary_fetch): ditto. Wed Nov 5 19:08:47 2003 Nobuyoshi Nakada * lib/optparse.rb (OptionParser::Switch::PlacedArgument::parse): do not remove next argument if empty value is placed. * test/optparse: added. Wed Nov 5 17:05:18 2003 Nobuyoshi Nakada * lib/test/unit/ui/gtk/testrunner.rb: typo. Wed Nov 5 11:13:32 2003 NAKAMURA Usaku * string.c: add #include "version.h". this file still depends on it. * Makefile.in, bcc32/Makefile.sub, win32/Makefile.sub, wince/Makefile.sub: add version.h dependency to string.c. Wed Nov 5 09:14:23 2003 Shugo Maeda * lib/monitor.rb: revert to the previous revision. Wed Nov 5 08:39:51 2003 GOTOU Yuuzou * lib/webrick/https.rb (HTTPRequest#parse): set @client_cert_chain. * lib/webrick/https.rb (HTTPRequest#meta_vars): create SSL_CLIENT_CERT_CHAIN_n from @client_cert_chain. * ext/openssl/ossl_ssl.c (ossl_ssl_get_peer_cert_chain): return nil if no cert-chain was given. Tue Nov 4 23:44:48 2003 NAKAMURA Usaku * bcc32/Makefile.sub, win32/Makefile.sub, wince/Makefile.sub: remove needless version.h dependency. Tue Nov 4 23:38:43 2003 WATANABE Hirofumi * class.c, hash.c, string.c: remove #include "version.h". * Makefile.in: remove needless version.h dependency. Tue Nov 4 06:54:52 2003 Yukihiro Matsumoto * io.c (read_all): fptr->f may be NULL, if IO is closed in the signal handler. * io.c (io_read): ditto. * string.c (get_pat): remove 1.8.0 warning code. * string.c (rb_str_match): extend warning until 1.8.2. * string.c (rb_str_match2): ditto. * class.c (class_instance_method_list): remove 1.8.0 warnings. method_list now recurs. [ruby-dev:21816] * class.c (rb_obj_singleton_methods): ditto. * array.c (rb_ary_select): remove select with block. [ruby-dev:21824] * hash.c (rb_hash_select): ditto. * hash.c (env_select): ditto. * re.c (match_select): ditto. * struct.c (rb_struct_select): ditto. Mon Nov 3 22:53:21 2003 Minero Aoki * lib/racc/parser.rb: synchronize with Racc 1.4.4. * ext/racc/cparse/cparse.c: ditto. * ext/racc/cparse/cparse.c (parse_main): should abort when the length of LR state stack <=1, not ==0. Mon Nov 3 08:50:47 2003 Yukihiro Matsumoto * process.c (check_uid_switch): remove duplicated error messages. * process.c (check_gid_switch): ditto. Sun Nov 2 02:28:33 2003 GOTOU Yuuzou * lib/webrick/ssl.rb: new option :SSLExtraChainCert. Sun Nov 2 01:02:04 2003 Akinori MUSHA * string.c (rb_str_hash): Update the HASH_PERL alternative hash algorithm in sync with Perl 5.8. * st.c (strhash): Ditto. Sat Nov 1 18:21:09 2003 GOTOU Yuuzou * ext/openssl/ossl_ssl.c (ossl_ssl_peer_cert_chain): add new method SSLSocket#peer_cert_chain. * ext/openssl/ossl_x509req.c (GetX509ReqPtr): new function which returns underlying X509_REQ. * ext/openssl/ossl_x509ext.c (ossl_x509extfactory_set_issuer_cert, ossl_x509extfactory_set_subject_cert, ossl_x509extfactory_set_crl, ossl_x509extfactory_set_subject_req, ossl_x509extfactory_set_config): use underlying C struct without duplication not to leak momory. Sat Nov 1 01:49:03 2003 NAKAMURA, Hiroshi * lib/soap/mapping/factory.rb: mark marshalled basetype objects when @allow_original_mapping is true. multi-referencing basetype node is prohibited in SOAP/1.1 encoding but soap4r's original ruby object mapping requires basetype to be marked to detect self referencing loop. e.g. o = 1; o.instance_eval { @iv = o } soap4r's original mapping is only used through soap/marshal API. * test/soap/marshal/test_marshal.rb: add tests for self referencing immutable objects. * test/soap/calc/test_calc_cgi.rb: fix test name. Fri Oct 31 22:26:29 2003 Takaaki Uematsu * wince/string_wce.c (strrchr): should decrement pointer. * wince/Makefile.sub: correct a range of isdigit(). Fri Oct 31 12:55:24 2003 WATANABE Hirofumi * configure.in, lib/mkmf.rb: add RPATHFLAG for NetBSD. [ruby-dev:21791] * bcc32/Makefile.sub, win32/Makefile.sub, win32/Makefile.sub: ditto. Fri Oct 31 01:38:14 2003 NAKAMURA Usaku * wince/Makefile.sub, win32/Makefile.sub (.y.c): allow white spaces at the beginning of line to remove by sed. (ruby-bugs-ja:PR#580) Fri Oct 31 01:02:24 2003 Yukihiro Matsumoto * compar.c (cmp_equal): protect exceptions from <=> comparison again. returns nil if any exception or error happened during comparison. * eval.c (search_required): should update *featurep when DLEXT2 is defined. (ruby-bugs-ja:PR#581) Thu Oct 30 23:41:04 2003 Masatoshi SEKI * lib/drb/drb.rb: add DRbArray * lib/drb/invokemethod.rb: fix Hash#each problem. [ruby-dev:21773] * lib/drb/unix.rb: add LoadError. [ruby-dev:21743] Thu Oct 30 23:19:11 2003 NAKAMURA, Hiroshi * lib/soap/generator.rb: better XML pretty printing. * lib/soap/encodingstyle/soapHandler.rb: remove unnecessary namespace assignment in the element which has "encodingStyle" attribute, and add necessary namespace assignment for "arrayType" attribute. * test/soap/calc/test_calc_cgi.rb: take over $DEBUG to ruby process through CGI. Thu Oct 30 22:59:39 2003 why the lucky stiff * ext/syck/yaml2byte.c: HASH const too long. Thanks, matz. Thu Oct 30 19:13:53 2003 Akinori MUSHA * ext/syck/MANIFEST: Add yamlbyte.h. Thu Oct 30 14:25:31 2003 Yukihiro Matsumoto * io.c (READ_DATA_BUFFERED): new macro to detect whether stdio buffer filled. * io.c (rb_io_fptr_cleanup): move path deallocation to rb_io_fptr_finalize (finalizer called by GC). Thu Oct 30 13:23:39 2003 Yukihiro Matsumoto * parse.y (logop): left may be NULL. [ruby-talk:84539] * eval.c (rb_eval): NODE_CASE nd_head may be NULL. Thu Oct 30 10:14:51 2003 NAKAMURA, Hiroshi * lib/test/unit/autorunner.rb: make fox runner work. Thu Oct 30 09:32:26 2003 NAKAMURA Usaku * process.c (rb_f_system): fixed lack of security check before calling do_spawn() on win32. [ruby-talk:84555] Thu Oct 30 02:46:35 2003 Yukihiro Matsumoto * eval.c (proc_invoke): single array value to normal Proc#call (i.e. not via lambda call), should be treated just like yield. [ruby-dev:21726] Thu Oct 30 02:25:48 2003 GOTOU Yuuzou * ext/openssl/lib/openssl/buffering.rb (Buffering#initialize): add new method to inherit @sync from @io.sync. * ext/openssl/lib/net/protocols.rb (SSLIO#ssl_connect): no need to set sync flag explicitly. * ext/openssl/ossl_ssl.c (ossl_sslctx_initialize): call super. * ext/openssl/ossl_ssl.c (ossl_sslctx_setup): set extra chain certificates in @extra_chain_cert. Wed Oct 29 22:02:04 2003 NAKAMURA, Hiroshi * test/drb/drbtest.rb: use rbconfig.rb to make the path of ruby interpreter to exec, instead of test/ruby/envutil.rb, Wed Oct 29 19:58:59 2003 NAKAMURA Usaku * ext/tcltklib/tcltklib.c (CONST84): define CONST84 when it is not defined and TCL_MAJOR_VERSION >= 8. * ext/tcltklib/tcltklib.c (VwaitVarProc, WaitVariableProc, rb_threadVwaitProc): use CONST84 instead of CONST. * ext/tcltklib/tcltklib.c (ip_rbTkWaitCommand, ip_rb_threadTkWaitCommand): use CONST84 always. Wed Oct 29 17:27:05 2003 Tanaka Akira * re.c (rb_reg_s_union, Init_Regexp): new method `Regexp.union'. * lib/pathname.rb (realpath): examine Dir.pwd because it may have symlinks. Wed Oct 29 17:16:31 2003 Nobuyoshi Nakada * eval.c (rb_longjmp): must not disturb original jump. [ruby-dev:21733] Wed Oct 29 15:28:34 2003 Yukihiro Matsumoto * eval.c (Init_Proc): taint preallocated exception object sysstack_error. [ruby-talk:84534] Wed Oct 29 11:27:39 2003 Yukihiro Matsumoto * parse.y (ret_args): node may be NULL. [ruby-talk:84530] Tue Oct 28 15:20:12 2003 NAKAMURA Usaku * ext/tcltklib/tcltklib.c (VwaitVarProc, ip_rbVwaitObjCmd, WaitVariableProc, WaitVisibilityProc, WaitWindowProc, ip_rbTkWaitObjCmd, ip_rbTkWaitCommand, rb_threadVwaitProc, rb_threadWaitVisibilityProc, rb_threadWaitWindowProc, ip_rb_threadVwaitObjCmd, ip_rb_threadTkWaitObjCmd): prototype; avoid VC++ warnings. Mon Oct 27 19:19:55 2003 Nobuyoshi Nakada * eval.c (rb_longjmp): ignore reentering error while warning. [ruby-dev:21730] Mon Oct 27 00:23:50 2003 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (ip_ruby): bug fix on Win : hang-up when calling 'exit' in the Tk callback procedure. [ruby-list:38656] Sat Oct 25 09:18:04 2003 Yukihiro Matsumoto * eval.c (rb_method_missing): protect exception from within "inspect". (ruby-bugs:PR#1204) Fri Oct 24 23:26:34 2003 Yukihiro Matsumoto * hash.c (rb_hash_each): Hash#each should yield single value. [ruby-talk:84420] * hash.c (env_each): ditto for ENV.each. Thu Oct 23 20:25:32 2003 GOTOU Yuuzou * lib/webrick/server.rb (GenericServer#start): should rescue IOError from IO::accept. [ruby-dev:21692] Thu Oct 23 17:59:36 2003 Nobuyoshi Nakada * eval.c (ruby_cleanup): initialize stack bottom for embedding. [ruby-dev:21686] * ext/dl/extconf.rb: move list of files to clean from DEPEND file, to get rid of macro redefinitions. Thu Oct 23 13:44:00 2003 Nobuyoshi Nakada * parse.y: integrate operations for stack_type. [ruby-dev:21681] Thu Oct 23 00:41:45 2003 NAKAMURA, Hiroshi * test/soap/calc/*, test/soap/helloworld/*: set logging threshold to ERROR. Wed Oct 22 12:53:31 2003 Nobuyoshi Nakada * lib/test/unit/collector/dir.rb (Test::Unit::Collector::Dir#collect_file): ignore tests which raised LoadError. * test/drb/drbtest.rb, test/ruby/test_beginendblock.rb, test/ruby/test_system.rb: avoid requiring same file twice. * test/drb/test_drbssl.rb, test/drb/test_drbunix.rb: should not use ARGV unless invoked directly. do not create test cases unless required libraries are available. Wed Oct 22 02:31:34 2003 Yukihiro Matsumoto * eval.c (ruby_cleanup): should not ignore exit_value in END execution. [ruby-dev:21670] Tue Oct 21 23:16:26 2003 Yukihiro Matsumoto * eval.c (ruby_cleanup): call finalizers and exit procs before terminating threads. * eval.c (ruby_cleanup): preserve ruby_errinfo before ruby_finalize_0(). Tue Oct 21 15:57:11 2003 Nobuyoshi Nakada * lib/test/unit/collector/dir.rb (Test::Unit::Collector::Dir#collect_file): prepend the directory of target file to the load path. Tue Oct 21 15:08:53 2003 NAKAMURA Usaku * win32/win32.c (do_spawn, do_aspawn): should wait child process even if callded with P_OVERLAY. * win32/win32.c (do_spawn, do_aspawn): should return child's exit status to parent. Tue Oct 21 00:35:02 2003 NAKAMURA, Hiroshi * test/soap/calc/*, test/soap/helloworld/*: catch the exception from test server thread and recover. Tue Oct 21 00:22:57 2003 Masatoshi SEKI * test/drb/*: import drb/runit. Mon Oct 20 23:55:47 2003 Nobuyoshi Nakada * eval.c (rb_eval): set current node after arguments evaluation. [ruby-dev:21632] * eval.c (rb_yield_0): set current node and keep it at local jump. Mon Oct 20 22:01:18 2003 Nobuyoshi Nakada * eval.c (rb_thread_cleanup): keep thread group for main thread. [ruby-dev:21644] Mon Oct 20 18:28:10 2003 Nobuyoshi Nakada * eval.c (rb_catch): backout. Mon Oct 20 17:31:46 2003 Yukihiro Matsumoto * eval.c (PUSH_FRAME): generate unique number to be TAG_JUMP() destination. * eval.c (localjump_destination): use unique number in ruby_frame for localjump destination. Mon Oct 20 11:31:44 2003 Nobuyoshi Nakada * test/ruby/test_signal.rb (test_signal): restore old trap. Mon Oct 20 11:00:46 2003 Yukihiro Matsumoto * gc.c (gc_sweep): loosen page free condition to avoid add_heap() race condition. [ruby-dev:21633] * gc.c (gc_sweep): do not update malloc_limit when malloc_increase is smaller than malloc_limit. Mon Oct 20 09:45:12 2003 NAKAMURA Usaku * lib/debug.rb (debug_command): remove debug print. Wed Oct 20 00:25:41 2004 Nobuyoshi Nakada * eval.c (search_required): required name must not be changed before loading. [ruby-dev:24492] Sun Oct 19 13:12:30 2003 Tanaka Akira * lib/pathname.rb (foreachline, dir_foreach): add obsolete warning. Sun Oct 19 00:14:22 2003 NAKAMURA, Hiroshi * test/soap/calc/*, test/soap/helloworkd/*: changed port# of test server. (17171) Sat Oct 18 23:01:32 2003 WATANABE Hirofumi * missing/acosh.c (DBL_MANT_DIG): typo fix(ifdef -> ifndef). Sat Oct 18 05:48:59 2003 why the lucky stiff * ext/syck/rubyext.c: YAML::Syck::compile method. * ext/syck/syck.c: Buffer edge bug. * ext/syck/yaml2byte.c: YAML to bytecode converter. * ext/syck/yamlbyte.h: Ditto. * ext/syck/bytecode.c: Bytecode parser fixes to empty collections and empty strings. * ext/syck/token.c: Ditto. Fri Oct 17 23:07:38 2003 Akinori MUSHA * ext/enumerator/enumerator.c, ext/enumerator/enumerator.txt: Provide Kernel#to_enum as an alias for Kernel#enum_for. Maybe this is a better name. Fri Oct 17 23:00:30 2003 Akinori MUSHA * lib/generator.rb: Add rdoc documentation. Fri Oct 17 22:16:42 2003 Akinori MUSHA * lib/set.rb: Reword and fix Overview. * lib/set.rb: It is not necessary to require 'test/unit/ui/console/testrunner'. Fri Oct 17 11:15:22 2003 NAKAMURA Usaku * test/ruby/test_range.rb: added. * MANIFEST: add test/ruby/test_range.rb. Fri Oct 17 03:21:23 2003 William Sobel * ext/socket/socket.c (make_hostent): h_aliases may be NULL. (ruby-bugs:PR#1195) * ext/socket/socket.c (sock_s_gethostbyaddr): ditto. Fri Oct 17 00:12:41 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: (bug fix) instance variable @frame was used without initializing on TkComposite module. Thu Oct 16 23:51:04 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: If $DEBUG == true and some exception is caused in a callback operation, Ruby/Tk shows a (verbose) backtrace information on the callback process. Thu Oct 16 17:09:19 2003 Yukihiro Matsumoto * lib/debug.rb (DEBUGGER__::Context::debug_command): do not call debug_silent_eval() when $1 is not set. (ruby-bugs:PR#1194) Thu Oct 16 16:54:57 2003 Yukihiro Matsumoto * string.c (rb_str_upto): ("a"..."a").to_a should return []. [ruby-core:01634] Thu Oct 16 16:40:51 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: Add Tk::EncodedString and Tk::UTF8_String class to support characters using the \uXXXX escape to the UNICODE string. * ext/tk/sample/{demos-en,demos-jp}/unicodeout.rb new demo-scripts (samples of Tk::UTF8_String) * ext/tk/sample/{demos-en,demos-jp}/widget add entries for 'unicodeout.rb' Thu Oct 16 08:38:06 2003 Nobuyoshi Nakada * test/digest/test_digest.rb (test_eq): show failed class. * test/ruby/test_iterator.rb (test_break, test_return_trace_func): test localjump destination. Wed Oct 15 20:22:31 2003 NAKAMURA, Hiroshi * lib/soap/netHttpClient.rb: use URI::HTTP#request_uri instead of instance_eval('path_query'). [ruby-list:38575] Wed Oct 15 17:24:45 2003 URABE Shyouhei * lib/cgi.rb (CGI::Cookie): tiny typo fix. Wed Oct 15 15:00:54 2003 Nobuyoshi Nakada * eval.c (ruby_run): just return FAILURE instead of parse error count. [ruby-list:38569] Wed Oct 15 13:17:02 2003 NAKAMURA Usaku * ext/digest/digest.c (rb_digest_base_alloc): need to initialize buffer. [ruby-dev:21622] Wed Oct 15 11:23:05 2003 Yukihiro Matsumoto * marshal.c (w_object): dump extended modules as well. * marshal.c (r_object0): TYPE_USRMARSHAL should restore extended modules before invoking marshal_load. these two fixes are done by Masatoshi Seki . Wed Oct 15 09:30:34 2003 NAKAMURA Usaku * ext/enumerator/enumerator.c (enumerator_each): avoid VC++ warning. * ext/syck/syck.h: include stdio.h for definition of FILE. Wed Oct 15 08:09:07 2003 why the lucky stiff * ext/syck/bytecode.c: Checkin of YAML bytecode support. * ext/syck/gram.c: Ditto. * ext/syck/syck.c: Ditto. * ext/syck/token.c: Ditto. * ext/syck/handler.c: Ditto. * ext/syck/handler.c: Now using 'tag' rather than 'taguri' in type URIs. * ext/syck/rubyext.c: Ditto (on both counts). Wed Oct 15 05:05:53 2003 Akinori MUSHA * lib/generator.rb: A new library which converts an internal iterator to an external iterator. * lib/abbrev.rb: A new library which creates an abbreviation table from a list. Wed Oct 15 04:31:51 2003 Hidetoshi NAGAI * ext/tk/sample/demos-en/entry3.rb, ext/tk/sample/demos-jp/entry3.rb : new demo-scripts * ext/tk/sample/demos-en/widget, ext/tk/sample/demos-jp/widget : add entries for 'entry3.rb' Wed Oct 15 04:31:47 2003 Akinori MUSHA * test/digest/test_digest.rb: Moved from ext/digest/test.rb. Wed Oct 15 03:53:20 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: fixed trouble on auto-load Tcl commands (enbug on the last commit). Wed Oct 15 00:25:00 2003 Yukihiro Matsumoto * parse.y (yylex): argument parentheses preceded by spaces should be warned; not error. [ruby-talk:84103] Wed Oct 15 00:20:15 2003 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: replace Tcl/Tk's vwait and tkwait to switch on threads smoothly and avoid seg-fault. * ext/tcltklib/tcltklib.c: add TclTkIp._thread_vwait and _thread_tkwait for waiting on a thread. (Because Tcl/Tk's vwait and tkwait command wait on an eventloop.) * ext/tk/lib/multi-tk.rb: support TclTkIp._thread_vwait and _thread_tkwait. * ext/tk/lib/tk.rb: now, TkVariable#wait has 2 arguments. If 1st argument is true, waits on a thread. If false, waits on an eventloop. If 2nd argument is true, checks existence of rootwidgets. If false, doesn't. Default is wait(true, false). * ext/tk/lib/tk.rb: add TkVariable#tkwait(arg) which is equal to TkVariable#wait(arg, true). wait_visibility and wait_destroy have an argument for waiting on a thread or an eventloop. * ext/tk/lib/tk.rb: improve of accessing Tcl/Tk's special variables. * ext/tk/lib/tkafter.rb: support 'wait on a thread' and 'wait on an eventloop'. Wed Oct 15 00:10:24 2003 NAKAMURA, Hiroshi * lib/soap/baseData.rb: Introduce SOAPType as the common ancestor of SOAPBasetype and SOAPCompoundtype. * lib/soap/generator.rb, lib/soap/element.rb, lib/soap/encodingstyle/*: Encoding methods signature change. Pass SOAPGenerator as a parameter. * lib/soap/mapping/*, test/soap/marshal/test_marshal.rb: Refactoring for better marshalling/unmarshalling support. Now I think SOAP marshaller supports all kind of object graph which is supported by Ruby's original marshaller. Of course there could be bugs as always. Find it. :-) * lib/soap/rpc/standaloneServer.rb: Set severity threshould to INFO. DEBUG is too noisy. * lib/xsd/datatypes.rb: DateTime#of is obsoleted. Use DateTime#offset. * test/wsdl/emptycomplextype.wsdl, test/xsd/xmlschema.xml: Avoid useless warning. Tue Oct 14 19:09:35 2003 Nobuyoshi Nakada * eval.c (ruby_finalize_0): return the given exit status unless SystemExit got raised. Tue Oct 14 11:53:49 2003 Nobuyoshi Nakada * intern.h (ruby_stop): never return. * ruby.h (ruby_run): ditto. Tue Oct 14 04:43:55 2003 Tanaka Akira * lib/pathname.rb (realpath): make ELOOP check bit more robust. (children): prepend self by default. (chroot): obsoleted. Tue Oct 14 02:29:31 2003 Nobuyoshi Nakada * eval.c (rb_require_safe): segfault after loading .so. Tue Oct 14 02:05:23 2003 Akinori MUSHA * ext/Setup*, ext/enumerator/*: Add ext/enumerator, a helper module for the Enumerable interface. Mon Oct 13 23:55:59 2003 WATANABE Hirofumi * test/ruby/envutil.rb: use Config::CONFIG["ruby_install_name"], not "ruby". Mon Oct 13 23:57:29 2003 Nobuyoshi Nakada * eval.c (rb_feature_p): match by classified suffix. * eval.c (rb_require_safe): require library in the specified safe level. * variable.c (rb_autoload, rb_autoload_load): restore safe level when autoload was called. [ruby-dev:21338] * intern.h: prototypes; rb_require_safe. * test/runner.rb: accept non-option arguments. Mon Oct 13 20:49:51 2003 Yukihiro Matsumoto * string.c (str_new4): should not preserve FL_TAINT status in the internal shared string. [ruby-dev:21601] * string.c (rb_str_new4): ditto. * eval.c: use EXIT_SUCCESS and EXIT_FAILURE for exit values. * process.c: ditto. [ruby-list:38521] Mon Oct 13 19:51:02 2003 Koji Arai * lib/debug.rb (debug_command): should enter emacs mode when assigned any value to the environment variable "EMACS". On Meadow, (getenv "EMACS") is "meadow". Sun Oct 12 14:45:03 2003 WATANABE Hirofumi * ext/win32ole/extconf.rb: check "windows.h", not "windows". [ruby-talk:84051] Sat Oct 11 20:41:03 2003 Corinna Vinschen * file.c (eaccess): Use access(2) on Cygwin. Sat Oct 11 17:09:21 2003 WATANABE Hirofumi * lib/rexml/quickpath.rb (REXML::QuickPath::match): escape '[' to avoid warning. Sat Oct 11 16:08:41 2003 Tanaka Akira * lib/pathname.rb (realpath): check existence of the file. * lib/pathname.rb (realpath): re-implemented. (realpath_root?, realpath_rec): removed Sat Oct 11 10:19:39 2003 Shugo Maeda * lib/monitor.rb: handle exceptions correctly. Thanks, Gennady Bystritsky. Fri Oct 10 07:50:54 2003 Nobuyoshi Nakada * eval.c (is_defined): inheritance line adjustment as like as rb_call_super(). Fri Oct 10 01:19:00 2003 GOTOU Yuuzou * ext/openssl/ossl_x509name.c (ossl_x509name_initialize): add optional argument to specify the DirectoryString type (ASN1::UTF8STRING by default). RFC3280 deprecates PrintableString for DirectoryString, and strongly requires to use UTF8String for all certificates issued after December, 31 2003. * ext/openssl/lib/openssl/x509.rb (X509::Name::parse): ditto. Thu Oct 9 23:50:21 2003 Nobuyoshi Nakada * eval.c (rb_thread_start_0): prevent thread from GC. [ruby-dev:21572] Thu Oct 9 19:11:44 2003 Nobuyoshi Nakada * eval.c (rb_thread_start_0): non-volatile should be restored from volatile. Thu Oct 9 17:43:36 2003 Nobuyoshi Nakada * eval.c (proc_save_safe_level, proc_get_safe_level, proc_set_safe_level): save/restore safe level 1..4. Thu Oct 9 16:33:23 2003 Yukihiro Matsumoto * marshal.c (r_object0): remove unnecessary iv restoration for USRMARSHAL. [ruby-dev:21582] * marshal.c (w_object): dump generic instance variables from a string from '_dump'. * variable.c (rb_generic_ivar_table): return 0 if obj's FL_EXIVAR is not set. * time.c (time_dump): copy instance variables to dumped string, to be included in the marshaled data. * bignum.c (rb_big2ulong): add range check to ensure round trip. Thu Oct 9 15:45:27 2003 Yukihiro Matsumoto * pack.c (uv_to_utf8): change message to "out of range", since negative values are not "too big". [ruby-dev:21567] Thu Oct 9 14:05:38 2003 Nobuyoshi Nakada * eval.c (rb_set_end_proc, rb_exec_end_proc): restore safe level. [ruby-dev:21557] Thu Oct 9 10:51:04 2003 Nobuyoshi Nakada * eval.c (rb_yield_0): no error if block is empty. Thu Oct 9 06:43:33 2003 Nobuyoshi Nakada * eval.c (localjump_error): id should be ID. * eval.c (rb_eval): nd_rval is set in copy_node_scope(). * eval.c (rb_yield_0): unused variable. * eval.c (rb_yield_0): nothing to do for empty node. * eval.c (call_end_proc, proc_invoke): adjust backtrace in END. [ruby-dev:21551] * eval.c (rb_thread_start_0): set the value by break as the result. [ruby-dev:21552] * eval.c (rb_thread_start_0, rb_thread_raise, rb_callcc): save variables across THREAD_SAVE_CONTEXT. Thu Oct 9 12:05:46 2003 Eric Sunshine * configure.in: revived NextStep, OpenStep, and Rhapsody ports which had become unbuildable; enhanced --enable-fat-binary option so that it accepts a list of desired architectures (rather than assuming a fixed list), or defaults to a platform-appropriate list if user does not provide an explicit list; made the default list of architectures for MAB (fat binary) more comprehensive; now uses -fno-common even when building the interpreter (in addition to using it for extensions), thus allowing the interpreter to be embedded into a plugin module of an external project (in addition to allowing embedding directly into an application); added checks for (needed by `socket' extension) and getcwd(); now ensures that -I/usr/local/include is employed when extensions' extconf.rb scripts invoke have_header() since extension checks on NextStep and OpenStep will fail without it if the desired resource resides in the /usr/local tree; fixed formatting of --help message. * Makefile.in: $(LIBRUBY_A) rule now deletes the archive before invoking $(AR) since `ar' on Apple/NeXT can not "update" MAB archives (see configure's --enable-fat-binary option); added rule for new missing/getcwd.c. * defines.h: fixed endian handling during MAB build (see configure's --enable-fat-binary option) to ensure that all portions of the project see the correct WORDS_BIGENDIAN value (some extension modules were getting the wrong endian setting); added missing constants GETPGRP_VOID, WNOHANG, WUNTRACED, X_OK, and type pid_t for NextStep and OpenStep; removed unnecessary and problematic HAVE_SYS_WAIT_H define in NeXT section. * dir.c: do not allow NAMLEN() macro to trust dirent::d_namlen on NextStep since, on some installations, this value always resolves uselessly to zero. * dln.c: added error reporting to NextStep extension loader since the previous behavior of failing silently was not useful; now ensures that NSLINKMODULE_OPTION_BINDNOW compatibility constant is defined for OpenStep and Rhapsody; no longer includes twice on Rhapsody since this header lacks multiple-include protection, which resulted in "redefinition" compilation errors. * main.c: also create hard reference to objc_msgSend() on NeXT platforms (in addition to Apple platforms). * lib/mkmf.rb: now exports XCFLAGS from configure script to extension makefiles so that extensions can be built MAB (see configure's --enable-fat-binary option); also utilize XCFLAGS in cc_command() (but not cpp_command() because MAB flags are incompatible with direct invocation of `cpp'). * ext/curses/extconf.rb: now additionally checks for presence of these curses functions which are not present on NextStep or Openstep: bkgd(), bkgdset(), color(), curs(), getbkgd(), init(), scrl(), set(), setscrreg(), wattroff(), wattron(), wattrset(), wbkgd(), wbkgdset(), wscrl(), wsetscrreg() * ext/curses/curses.c: added appropriate #ifdef's for additional set of curses functions now checked by extconf.rb; fixed curses_bkgd() and window_bkgd() to correctly return boolean result rather than numeric result; fixed window_getbkgd() to correctly signal an error by returning nil rather than -1. * ext/etc/etc.c: setup_passwd() and setup_group() now check for null pointers before invoking rb_tainted_str_new2() upon fields extracted from `struct passwd' and `struct group' since null pointers in some fields are common on NextStep/OpenStep (especially so for the `pw_comment' field) and rb_tainted_str_new2() throws an exception when it receives a null pointer. * ext/pty/pty.c: include "util.h" for strdup()/ruby_strdup() for platforms such as NextStep and OpenStep which lack strdup(). * ext/socket/getaddrinfo.c: cast first argument of getservbyname(), gethostbyaddr(), and gethostbyname() from (const char*) to non-const (char*) for older platforms such as NextStep and OpenStep. * ext/socket/socket.c: include "util.h" for strdup()/ruby_strdup() for platforms such as NextStep and OpenStep which lack strdup(); include if present for NextStep and OpenStep; cast first argument of gethostbyaddr() and getservbyname() from (const char*) to non-const (char*) for older platforms. * ext/syslog/syslog.c: include "util.h" for strdup()/ruby_strdup() for platforms such as NextStep and OpenStep which lack strdup(). Wed Oct 8 22:19:00 2003 Nathaniel Talbott * lib/test/unit.rb: removed installation instructions. * lib/test/unit/ui/testrunnermediator.rb: moved the run flag to a more central location. * lib/test/unit.rb: ditto. * lib/test/unit.rb: extracted the running code in to AutoRunner. * lib/test/unit/autorunner.rb: added. * lib/test/unit/collector/objectspace.rb: extracted common test collection functionality in to a module. * lib/test/unit/collector.rb: ditto; added. * test/testunit/collector/test_objectspace.rb: ditto. * lib/test/unit/collector/dir.rb: added. Supports collecting tests out of a directory structure. * test/testunit/collector/test_dir.rb: added. * test/runner.rb: simplified to use the new capabilities. Tue Oct 7 15:23:09 2003 NAKAMURA, Hiroshi * test/ruby/test_beginendblock.rb: add tests for nested BEGIN/END. * test/ruby/beginmainend.rb: add tests for nested BEGIN/END. * test/ruby/endblockwarn.rb: new file added to test of END-in-method warning. Tue Oct 7 12:23:47 2003 Tanaka Akira * ext/fcntl/fcntl.c (Init_fcntl): define Fcntl::O_ACCMODE. * ext/socket/extconf.rb: useless assignment removed. Tue Oct 7 09:13:24 2003 Nobuyoshi Nakada * test/ruby/test_beginendblock.rb (test_endinmethod): END{} is now allowed in eval. Tue Oct 7 04:15:25 2003 Nobuyoshi Nakada * parse.y (stmt): should not expand mrhs if lhs is solely starred. Tue Oct 7 02:57:53 2003 Yukihiro Matsumoto * parse.y (stmt): rhs of multiple assignment should not be expanded using "to_a". [ruby-dev:21527] Tue Oct 7 01:42:34 2003 GOTOU Yuuzou * ext/openssl/ossl_asn1.c (ossl_asn1_get_asn1type): use appropriate free function for ASN1_OBJECT. * ext/openssl/ossl_asn1.c (ossl_asn1obj_get_sn): add new function for ASN1::ObjectId#sn; it returns short name text representation of OID. * ext/openssl/ossl_asn1.c (ossl_asn1obj_get_ln): add new function for ASN1::ObjectId#ln; it returns long name text representation of OID. * ext/openssl/ossl_asn1.c (ossl_asn1obj_get_oid): add new function for ASN1::ObjectId#oid; it returns numerical representation of OID. Mon Oct 6 22:59:46 2003 NAKAMURA, Hiroshi * lib/csv.rb (IOReader, BasicWriter): call binmode when a given IO respond_to?(:binmode). record separator was wrong when you gave text mode IO to Reader.parse and Writer.generate. * test/csv/test_csv.rb: add tests for above change. Sun Oct 5 23:27:09 2003 Tanaka Akira * ext/socket/extconf.rb: check recvmsg even if sendmsg is exists. * ext/socket/socket.c (thread_read_select): restored. Mon Oct 6 16:23:38 2003 Nobuyoshi Nakada * marshal.c (w_object): wrong method name in the message. Mon Oct 6 16:02:05 2003 Yukihiro Matsumoto * parse.y (stmt): END in method should cause warning. [ruby-dev:21519] Mon Oct 6 15:17:23 2003 NAKAMURA, Hiroshi * test/ruby/test_iterator.rb (test_block_argument_without_paren): added. (follows sample/test.rb) Mon Oct 6 11:57:06 2003 NAKAMURA, Hiroshi * test/ruby/test_beginendblock.rb, test/ruby/beginmainend.rb: added test for eval-ed BEGIN END order. Mon Oct 6 09:19:54 2003 Yukihiro Matsumoto * marshal.c (w_object): should pass "weak" value to next level. [ruby-dev:21496] * eval.c (proc_alloc): should not use cached object if klass is different. [ruby-talk:83685] Sun Oct 5 23:27:09 2003 Tanaka Akira * lib/pathname.rb: version information is added in document. Sun Oct 5 23:07:03 2003 Nobuyoshi Nakada * eval.c (rb_f_END): block should be given. [ruby-dev:21497] Sun Oct 5 22:51:23 2003 GOTOU Yuuzou * lib/ext/openssl/extconf.rb: add check for some engine functions unavailable in OpenSSL-0.9.6. * lib/ext/openssl/ossl_engine.c: ditto. Sun Oct 5 17:56:30 2003 Nobuyoshi Nakada * eval.c (rb_eval): fix evaluation order. [ruby-list:38431] Sun Oct 5 15:05:06 2003 akira yamada * test/uri/*: translated RUNIT to Test::Unit. Sun Oct 5 14:37:39 2003 NAKAMURA, Hiroshi * lib/xsd/datatypes.rb: Rational -> Decimal string bug fix. * test/soap/marshal/test_marshal.rb: ditto. * test/soap/calc/test_calc_cgi.rb: add Config::CONFIG["EXEEXT"] to RUBYBIN. Sun Oct 5 13:47:22 2003 NAKAMURA, Hiroshi * test/ruby/test_beginendblock.rb, test/ruby/beginmainend.rb: add tests about scope, order and allowed syntax. Sun Oct 5 11:54:29 2003 NAKAMURA, Hiroshi * test/ruby/envutil.rb: added. split "rubybin" from test_system.rb. * test/ruby/test_system.rb: use envutil.rb * test/ruby/test_beginendblock.rb: added. * test/ruby/beginmainend.rb: added. used in test_beginendblock.rb. Sun Oct 5 11:23:00 2003 Nathaniel Talbott * test/testunit/runit/test_testresult.rb: removed some unnecessary cruft. Sun Oct 5 11:14:00 2003 Nathaniel Talbott * lib/rubyunit.rb: aliasing TestCase into the top level is problematic. * lib/runit/assert.rb: fixed a couple of bugs caused by recent refactoring in Test::Unit. * test/testunit/runit/*: added. Sun Oct 5 10:55:29 2003 NAKAMURA, Hiroshi * lib/open-uri.rb (URI::Generic#find_proxy): no_proxy support did not work. [ruby-dev:21484] Sun Oct 5 09:52:00 2003 Nathaniel Talbott * lib/test/unit/assertions.rb: will use pp for output if available. Can be disabled by setting Assertions.use_pp = false. * test/testunit/test_assertions.rb: made a small change to exception formatting. Sun Oct 5 07:42:00 2003 Nathaniel Talbott * lib/test/unit/assertions.rb: made small improvements to assertion messages. Deprecated Assertions#assert_not_nil; use #assert instead. * test/testunit/test_assertions.rb: ditto. * test/testunit/util/test_procwrapper.rb: use #assert instead of #assert_not_nil. Sun Oct 5 04:10:00 2003 Nathaniel Talbott * lib/test/unit/assertions.rb: refactored message building. Sun Oct 5 03:40:22 2003 GOTOU Yuuzou * ext/openssl/ossl_asn1.h: global symbols should be declared as external. Sun Oct 5 03:03:20 2003 akira yamada * test/ruby/test_exception.rb (test_else): added. Sun Oct 5 02:12:00 2003 Nathaniel Talbott * lib/test/unit/assertions.rb: changed assertion messages to rely more heavily on #inspect. Added backtrace filtering for exceptions in assertion messages. * test/testunit/test_assertions.rb: ditto. Sun Oct 5 02:12:00 2003 Masatoshi SEKI * lib/drb/acl.rb, lib/drb/ssl.rb: added. * lib/drb/drb.rb: exit from a thread using 'break'. Sat Oct 4 21:49:14 2003 WATANABE Hirofumi * gc.c (Init_stack): the type of space is changed to unsigned int from double. [ruby-dev:21483] Sat Oct 4 17:52:59 2003 NAKAMURA, Hiroshi * lib/soap/netHttpClient.rb: follow http-access2. hosts which matches ENV['no_proxy'] or ENV['NO_PROXY'] are not proxyed. - [,:] separated. ("ruby-lang.org:rubyist.net") - no regexp. (give "ruby-lang.org", not "*.ruby-lang.org") - if you want specify host by IP address, give full address. ("192.168.1.1, 192.168.1.2") * lib/soap/rpc/cgistub.rb: return "Status: XXX MMM" line. * test/runner.rb: give testsuite name. Sat Oct 4 15:16:02 2003 Yukihiro Matsumoto * marshal.c (w_object): instance variable dump do not cause error for objects that cannot be dumped, if they traversed from marshal_dump. they are just ignored. * gc.c (Init_stack): cast "space" (doble value) into unsigned int. should run on PowerPC. * eval.c (rb_eval): should not execute else part if any exception is caught. [ruby-dev:21482] * parse.y (f_args): should allow unparenthesized block argument. * parse.y (f_rest_arg): should allow unparenthesized rest argument. Sat Oct 4 14:59:51 2003 Tanaka Akira * lib/pathname.rb (initialize): raise ArgumentError if argument has '\0' character. (relative_path_from): new method. (each_entry): new method for replacement of dir_foreach. (foreach, foreachline, dir_foreach, chdir): obsoleted. Sat Oct 4 12:58:48 2003 akira yamada * test/uri/* (6 files): added. Sat Oct 4 12:44:45 2003 akira yamada * lib/uri/ftp.rb, lib/uri/mailto.rb: renamed to #to_s from #to_str. Sat Oct 4 07:33:00 2003 Nathaniel Talbott * lib/test/unit/testsuite.rb: changed #<< to return self, and added #delete. * test/testunit/test_testsuite.rb: ditto. Also slightly refactored #test_size. * lib/test/unit/collector/objectspace.rb: collector now preserves the hierarchy of suites. * test/testunit/collector/test_objectspace.rb: ditto. Sat Oct 4 04:48:49 2003 why the lucky stiff * ext/syck/rubyext.c: default keys handled. * ext/syck/syck.h: lowered default buffer size to 16k for increased performance. * test/yaml: checkin of basic unit tests. Sat Oct 4 04:24:19 2003 GOTOU Yuuzou * ext/openssl/extconf.rb: add check for X509V3_set_nconf. * ext/openssl/ossl_x509ext.c (ossl_x509extfactory_set_config): cannot implement if X509V3_set_nconf doesn't exist. Sat Oct 4 02:12:44 2003 NAKAMURA, Hiroshi * lib/xsd/datatypes.rb: dump sign by itself. under the problematic platform, sprintf("%+.10g", -0.0) => +0. sigh. * sample/wsdl/amazon/*: update schema ver2 to ver3. Sat Oct 4 01:33:46 2003 Tanaka Akira * lib/pathname.rb (initialize): duplicate and freeze argument. (to_s): return duplicated string. (children): new method. (each_line): new alias to foreachline. Fri Oct 3 16:13:19 2003 GOTOU Yuuzou * ext/openssl/ossl_asn1.c: add DER encoder and decoder. * ext/openssl/ossl_asn1.h: add OpenSSL::ASN1 module. * ext/openssl/ossl.c (Init_openssl): call Init_ossl_asn1. * ext/openssl/extconf.rb: check if X509_ATTRIBUTE has field "single". * ext/openssl/ossl_x509attr.c (ossl_x509attr_set_value): accept DER encoded data argument. * ext/openssl/ossl_x509attr.c (ossl_x509attr_get_value): return DER encoded data in OpenSSL::ASN1 types. Fri Oct 3 13:02:00 2003 Nathaniel Talbott * lib/test/unit.rb: refactored to use optparse. * lib/test/unit.rb: added support for selecting the output level from the command-line. * lib/test/unit.rb: added a command-line switch to stop processing the command-line, allowing arguments to be passed to tests. * lib/test/unit.rb: changed the method for specifying a runner or a filter from the command-line. * lib/test/unit/collector/objectspace.rb: fixed a bug causing all tests to be excluded when the filter was set to an empty array. * test/testunit/collector/test_objectspace.rb: ditto. Fri Oct 3 08:14:32 2003 Yukihiro Matsumoto * lib/irb/ruby-lex.rb (RubyLex::identify_identifier): support 'class ::Foo' syntax. [ruby-talk:83514] Fri Oct 3 08:01:00 2003 Nathaniel Talbott * lib/test/unit/assertions.rb: added a default message for #assert, #assert_block, and #flunk. * test/testunit/test_assertions.rb: ditto. * lib/test/unit/failure.rb: failures now show a better trace of where they occurred. * test/testunit/test_failure.rb: ditto (added). * lib/test/unit/testcase.rb: ditto. * test/testunit/test_testcase.rb: ditto. * lib/test/unit/util/backtracefilter.rb: added. * test/testunit/util/test_backtracefilter.rb: added. * lib/test/unit/error.rb: changed to use BacktraceFilter and improved output. * test/testunit/test_error.rb: ditto. Thu Oct 2 20:33:49 2003 Nobuyoshi Nakada * ext/iconv/iconv.c (iconv_failure_initialize): conform with orthodox initialization method. * ext/iconv/iconv.c (iconv_fail): initialize exception instance from the class, and do not share instance variables with the others. [ruby-dev:21470] Thu Oct 2 18:20:27 2003 Nobuyoshi Nakada * time.c (Init_Time): define initialize. [ruby-dev:21469] Thu Oct 2 17:39:38 2003 GOTOU Yuuzou * ext/openssl/ossl_engine.c: add a new module OpenSSL::Engine. it supports OpenSSL hardware cryptographic engine interface. * ext/openssl/ossl_engine.h: ditto. * ext/openssl/MANIFEST: add ossl_engine.c and ossl_engine.h. * ext/openssl/extconf.rb: add check for openssl/engine.h. * ext/openssl/ossl.c: call Init_ossl_engine(). * ext/openssl/ossl.h: include openssl/engine.h. * ext/openssl/ossl_pkey_{rsa,dsa,dh}.c: check if underlying EVP_PKEY referes engine. Thu Oct 2 17:22:37 2003 Yukihiro Matsumoto * time.c (time_load): restore instance variables (if any) before loading from marshaled data. Thu Oct 2 14:19:15 2003 Nobuyoshi Nakada * ext/iconv/iconv.c (iconv_fail): now yield erred substring, and set error object to $!. * ext/iconv/iconv.c (iconv_convert): error handler block should return appended part and the rest. if rest is nil, the conversion stops. Thu Oct 2 12:00:18 2003 Nobuyoshi Nakada * variable.c (rb_const_defined_0): look up constants in Object as well. [ruby-dev:21458] * test/ruby/test_defined.rb (TestDefined::test_defined): test for constants. Thu Oct 2 11:17:00 2003 Nathaniel Talbott * lib/test/unit/assertions.rb: should not capture an AssertionFailedError unless explicitly requested. * test/testunit/test_assertions.rb: ditto. * test/testunit/collector/test_objectspace.rb: fixed a test failure caused by methods being returned in different orders on different platforms by moving test sorting from TestSuite into the locations where suites are constructed. [ruby-talk:83156] * lib/test/unit/testcase.rb: ditto. * lib/test/unit/testsuite.rb: ditto. * lib/test/unit/collector/objectspace.rb: ditto. Thu Oct 2 03:25:01 2003 NAKAMURA Usaku * eval.c (rb_thread_raise): prototype; avoid VC++ warning. Thu Oct 2 01:37:34 2003 Yukihiro Matsumoto * time.c (time_mdump): new marshal dumper. _dump is still available for compatibility. * time.c (time_mload): new marshal loader. * marshal.c (w_object): preserve instance variables for objects with marshal_dump. * marshal.c (r_object0): restore instance variables before calling marshal_load. * error.c (rb_warn_m): always return nil. Thu Oct 2 01:32:46 2003 Yukihiro Matsumoto * eval.c (rb_f_block_given_p): real required condition is ruby_frame->prev->iter == ITER_CUR. * eval.c (rb_block_given_p): ditto. * eval.c (block_pass): update ruby_frame->iter only when previous value is ITER_NOT. Thu Oct 2 01:02:35 2003 Yukihiro Matsumoto * variable.c (rb_const_defined_at): should exclude constants from Object when TYPE(klass) == T_MODULE *and* exclude is on. [ruby-dev:21458] * variable.c (rb_const_get_0): do not lookup constants from Object when TYPE(klass) == T_MODULE *and* exclude is on. Thu Oct 2 00:21:11 2003 NAKAMURA, Hiroshi * test/logger/test_logger.rb: unlinking file before close causes problem under win32 box. * lib/xsd/datatypes.rb(XSDFloat, XSDDouble): add +/- sign explicitly when stringified and embedded into XML instance. Ruby's sprintf may format -0.0 as "0.0" (no minus sign) depending on underlying C sprintf implementation. * test/xsd/test_xsd.rb, test/soap/test_basetype.rb: follow above change. * test/soap/calc/*: give httpd config param "CGIInterpreter". "/usr/bin/env ruby" thing does not work under non-Unix boxes. Sat Oct 2 00:42:20 2004 Yukihiro Matsumoto * marshal.c (r_byte): retrieve pointer from string value for each time. [ruby-dev:24404] * marshal.c (r_bytes0): ditto. * enum.c (sort_by_i): re-entrance check added. [ruby-dev:24399] * io.c (io_read): should freeze all reading buffer. [ruby-dev:24400] * string.c (rb_str_sum): should use bignums when bits is greater than or equals to sizeof(long)*CHAR_BITS. [ruby-dev:24395] * eval.c (specific_eval): defer pointer retrieval to prevent unsafe sourcefile string modification. [ruby-dev:24382] * string.c (rb_str_sum): wrong cast caused wrong result. [ruby-dev:24385] * enum.c (enum_sort_by): hide temporary array from ObjectSpace.each_object. [ruby-dev:24386] * string.c (rb_str_sum): check was done with false pointer. [ruby-dev:24383] * string.c (rb_str_sum): string may be altered. [ruby-dev:24381] Thu Oct 2 00:25:21 2003 Nobuyoshi Nakada * signal.c (ruby_signal_name): adjust to the prototype. * process.c (pst_inspect): ditto. * ext/etc/etc.c (etc_getgrent, Init_etc): typo. Wed Oct 1 20:49:41 2003 Nobuyoshi Nakada * gc.c (heaps): manage slots and limits together. [ruby-dev:21453] * gc.c (add_heap): should not clear heaps slot even if realloc() failed. Wed Oct 1 20:36:49 2003 WATANABE Hirofumi * MANIFEST: add wince/mkconfig_wce.rb. Wed Oct 1 17:22:33 2003 Yukihiro Matsumoto * ext/etc/etc.c: add new functions: setpwent, getpwent, endpwent, setgrent, getgrent, endgrent. * ext/socket/socket.c (sock_s_gethostbyname): do not reverse lookup. Wed Oct 1 17:01:30 2003 Nobuyoshi Nakada * eval.c (rb_load): Object scope had priority over required file scope. [ruby-dev:21415] Wed Oct 1 14:09:53 2003 Takaaki Uematsu * wince/mkconfig_wce.rb: sorry, forget to commit. Wed Oct 1 10:08:42 2003 Takaaki Uematsu * wince/setup.mak: add sigmarionIII SDK support. * wince/Makefile.sub: ditto. * wince/mkexports.rb: fix linker error in SH4. * wince/mkconfig_wce.rb: camouflage RUBY_PLATFORM for compiling ext. Wed Oct 1 08:02:52 2003 Takaaki Uematsu * wince/time_wce.c (time): add zero check. Tue Sep 30 16:11:05 2003 Yukihiro Matsumoto * Makefile.in: copy lex.c from $(srcdir) if it's not the current directory. [ruby-dev:21437] Tue Sep 30 11:29:23 2003 Tanaka Akira * process.c (pst_inspect): describe stopped process "stopped". Tue Sep 30 09:31:56 2003 Nobuyoshi Nakada * test/runner.rb: glob for directories. Tue Sep 30 09:11:43 2003 Yukihiro Matsumoto * eval.c (rb_eval): while/until should not capture break unless they are destination of the break. Tue Sep 30 03:12:02 2003 Minero Aoki * lib/net/http.rb (finish): revert to 1.93. * lib/net/pop.rb (finish): revert to 1.60. * lib/net/smtp.rb (finish): revert to 1.67. * lib/net/http.rb (do_start): ensure to close socket if failed to start session. * lib/net/pop.rb (do_start): ditto. * lib/net/smtp.rb (do_start): ditto. * lib/net/smtp.rb: SMTP#started? wrongly returned false always. Tue Sep 30 02:54:49 2003 Minero Aoki * test/ruby/test_iterator.rb: new test test_break__nested_loop[123]. Mon Sep 29 23:39:13 2003 Minero Aoki * lib/net/http.rb (finish): does not raise IOError even if !started?, to allow closing socket which was opened before session started. * lib/net/pop.rb (finish): ditto. * lib/net/smtp.rb (finish): ditto. Mon Sep 29 19:06:51 2003 WATANABE Hirofumi * ext/win32ole/extconf.rb: add windows.h checking. (ruby-bugs:PR#1185) Mon Sep 29 16:18:30 2003 NAKAMURA, Hiroshi * lib/logger.rb: check if the given logdevice object respond_to :write and :close, not is_a? IO. duck duck. * test/logger/test_logger.rb: self IO.pipe reading/writing may be locked by the flood. use tempfile. * lib/wsdl/xmlSchema/data.rb: wrong constant reference. Mon Sep 29 16:11:23 2003 Minero Aoki * test/fileutils/test_fileutils.rb: clean up temporary symlink. Patched by NaHi. [ruby-dev:21420] Mon Sep 29 11:16:55 2003 Yukihiro Matsumoto * eval.c (rb_thread_atfork): wrong format specifier. [ruby-dev:21428] * process.c (pst_inspect): better description. Mon Sep 29 02:31:44 2003 GOTOU Yuuzou * lib/webrick/utils.rb (Utils::su): use setgid and setuid to set real and effective IDs. and setup group access list by initgroups. Sun Sep 28 11:14:19 2003 Koji Arai * ext/digest/digest.c (Init_digest): `copy_object' was deprecated. `initialize_copy' should be defined. * ext/stringio/stringio.c (Init_stringio): ditto. Sat Sep 27 18:25:13 2003 NAKAMURA, Hiroshi * lib/xsd/charset.rb: XSD::Charset.is_ces did return always true under $KCODE = "NONE" environment. check added. * test/xsd/test_xsd.rb: add tests for above fix. Sat Sep 27 15:58:50 2003 NAKAMURA, Hiroshi * lib/soap/rpc/cgistub.rb: make logging severity threshold higher. * lib/soap/rpc/standaloneServer.rb: defer WEBrick server start to give a chance to reset logging severity threshold. * test/soap/calc/test_*, test/soap/helloworld/test_helloworld.rb: run silent. Sat Sep 27 09:44:18 2003 Minero Aoki * test/fileutils/test_fileutils.rb: clear all errors on Windows. [ruby-dev:21417] * test/fileutils/test_nowrite.rb: ditto. Mon Sep 27 09:14:03 2004 Yukihiro Matsumoto * array.c (rb_ary_delete): comparison may change the capacity. [ruby-dev:24348] * array.c (rb_ary_fill): fill should honor length argument. [ruby-dev:24346] * array.c (rb_ary_replace): should not use ptr from shared array. [ruby-dev:24345] * ext/socket/socket.c (s_accept): don't retry for EWOULDBLOCK. [ruby-talk:113807] Sat Sep 27 04:57:07 2003 NAKAMURA, Hiroshi * test/ruby/test_file.rb: new file. only asserts unlink-before-close behaviour now. * test/soap/marshal/test_digraph.rb: should close before unlink. unlink-before-close pattern is not needed here. Sat Sep 27 03:32:37 2003 NAKAMURA, Hiroshi * test/soap/*, test/wsdl/*, test/xsd/*: move TestCase classes into each module namespace. TestMarshal in test/soap/marshal/test_marshal.rb crashed with test/ruby/test_marshal.rb. Sat Sep 27 01:30:59 2003 NAKAMURA Usaku * ext/socket/socket.c (ruby_connect): on win32, type of the 4th argument of getsockopt is char *. Fri Sep 26 18:35:40 2003 Nobuyoshi Nakada * lib/resolv-replace.rb: 1.8 compliance. [ruby-talk:82946] Fri Sep 26 17:39:27 2003 NAKAMURA, Hiroshi * test/ruby/test_marshal.rb: add test for ruby's objects. Fri Sep 26 09:52:44 2003 Nobuyoshi Nakada * defines.h (flush_register_windows): use volatile only for gcc on Solaris. [ruby-dev:21403] * lib/mkmf.rb (xsystem): use system directly to honor shell meta charaters. Fri Sep 26 00:10:13 2003 NAKAMURA, Hiroshi * lib/README: updated. Thu Sep 25 17:48:10 2003 NAKAMURA Usaku * ext/openssl/ossl.c (ossl_buf2str): fix type of 1st argument for rb_protect. * ext/openssl/ossl_hmac.c (ossl_hmac_digest): should return meaningful value. Thu Sep 25 09:00:00 2003 Nathaniel Talbott * lib/ostruct.rb: Added OpenStruct#==. * test/ostruct/test_ostruct.rb: Added. Thu Sep 25 07:55:26 2003 Nobuyoshi Nakada * ext/win32ole/win32ole.c, ext/openssl/ossl_pkey_dsa.c, ext/openssl/ossl_pkey_rsa.c, ext/bigdecimal/bigdecimal.h: must not use C++ or C99 style comment yet. (ruby-bugs:PR#1184) Thu Sep 25 00:23:22 2003 WATANABE Hirofumi * MANIFEST: add SOAP4R. Thu Sep 25 00:13:15 2003 NAKAMURA, Hiroshi * lib/soap/* (29 files): SOAP4R added. * lib/wsdl/* (42 files): WSDL4R added. * lib/xsd/* (12 files): XSD4R added. * test/soap/* (16 files): added. * test/wsdl/* (2 files): added. * test/xsd/* (3 files): added. * sample/soap/* (27 files): added. * sample/wsdl/* (13 files): added. Wed Sep 24 02:08:11 2003 GOTOU Yuuzou * lib/webrick/httpservlet/cgihandler.rb: conform to mswin32. [ruby-talk:82735], [ruby-talk:82748], [ruby-talk:82818] Tue Sep 23 23:10:16 2003 NAKAMURA, Hiroshi * lib/logger.rb: add Logger#<<(msg) for writing msg without any formatting. * test/logger/test_logger.rb: ditto. Tue Sep 23 20:47:51 2003 Yukihiro Matsumoto * error.c (rb_warn_m): should not warn if -W0 is specified. [ruby-talk:82675] Mon Sep 22 21:28:57 2003 WATANABE Hirofumi * MANIFEST: updated. Mon Sep 22 19:22:26 2003 GOTOU Yuuzou * configure.in (AC_CHECK_FUNCS): add setuid and setgid. Mon Sep 22 12:34:55 2003 Yukihiro Matsumoto * util.c (ruby_strtod): skip preceding zeros before counting digits in the mantissa. (ruby-bugs:PR#1181) Sun Sep 21 04:12:36 2003 GOTOU Yuuzou * ext/openssl/ossl_ocsp.c (ossl_ocspreq_initialize): the argument should be a String. * ext/openssl/ossl_ocsp.c (ossl_ocspres_initialize): ditt. * ext/openssl/ossl_x509attr.c (ossl_x509attr_initialize): ditto. * ext/openssl/ossl_x509ext.c (ossl_x509ext_initialize): ditto. * ext/openssl/ossl_x509ext.c (ossl_x509ext_set_value): ditto. Sat Sep 20 11:49:05 2003 NAKAMURA, Hiroshi * lib/logger.rb: typo fixed. * test/logger/test_logger.rb: new file. Fri Sep 19 11:39:00 2003 Nathaniel Talbott * test/testunit/*: Added. * lib/test/unit.rb: Documentation update. * lib/test/unit/ui/console/testrunner.rb (TestRunner#initialize): Ditto. * lib/test/unit.rb: Factored out an ObjectSpace collector. * lib/test/unit/collector/objectspace.rb: Ditto. * sample/testunit/*: Added. Fri Sep 19 01:00:48 2003 GOTOU Yuuzou * lib/webrick/log.rb (BasicLog#log): get rid of as ineffectual condition. * lib/webrick/log.rb (BasicLog#format): add "\n" to message. Thu Sep 18 22:43:20 2003 Yukihiro Matsumoto * eval.c (proc_invoke): should push PROT_PCALL tag for orphans. * eval.c (proc_invoke): should update "result" for orphans. Thu Sep 18 20:33:03 2003 Tietew * parse.y (str_xquote): do not prepend escapes in backqoute literals. [ruby-list:38409] Thu Sep 18 20:30:17 2003 Tanaka Akira * lib/pathname.rb: update document. Thu Sep 18 15:27:05 2003 NAKAMURA, Hiroshi * lib/logger.rb: new file. Logger, formerly called devel-logger or Devel::Logger. * sample/logger/*: new file. samples of logger.rb. Wed Sep 17 23:41:45 2003 Yukihiro Matsumoto * eval.c (localjump_destination): should not raise ThreadError exception for "break". [ruby-dev:21348] * eval.c (proc_invoke): use result instead of prot_tag->retval. retval is no longer propagated to the ancestors. Wed Sep 17 20:34:00 2003 Nobuyoshi Nakada * parse.y (tokadd_string, parse_string, yylex): escaped terminator is now interpreted as is. [ruby-talk:82206] Wed Sep 17 18:52:36 2003 Minero Aoki * test/fileutils/fileassertions.rb: new file. * test/fileutils/test_fileutils.rb: new file. * test/fileutils/test_nowrite.rb: new file. Wed Sep 17 18:51:02 2003 Minero Aoki * test/strscan/test_stringscanner.rb: require test/unit. Wed Sep 17 18:35:34 2003 Minero Aoki * test/strscan/test_stringscanner.rb: new file. Wed Sep 17 18:03:30 2003 GOTOU Yuuzou * ext/openssl: all files are reviewed to simplify and avoid memory leak. * ext/openssl/extconf.rb: add check for assert.h. * ext/openssl/ossl.c (ossl_buf2str): new function to convert C buffer to String and free buffer. * ext/openssl/ossl.c (ossl_x509_ary2sk): new function to convert Array of OpenSSL::X509 to STACK_OF(X509) with exception safe. * ext/openssl/ossl.c (ossl_to_der, ossl_to_der_if_possible): new functions to convert object to DER string. * ext/openssl/ossl.h: ditto. * ext/openssl/ossl_bio.c (ossl_membio2str): new function to convert BIO to String object and free BIO. * ext/openssl/ossl_bio.h: ditto. * ext/openssl/ossl_pkcs7.c (ossl_pkcs7_to_der): add for "to_der". * ext/openssl/ossl_x509name.c (ossl_x509name_to_der): ditto. * ext/openssl/ossl_x509ext.c (ossl_x509ext_to_der): ditto. * ext/openssl/ossl_x509ext.c (create_ext_from_array): removed and reimplement in openssl/x509.rb. * ext/openssl/ossl_x509attr.c: reimplemented and disable some method temporarily. this class doesn't work fine without ASN.1 data support;-) I'll rewrite in near future. * ext/openssl/lib/openssl/x509.c (X509::Attribute): get rid off unused code. * ext/openssl/lib/openssl/x509.c (X509::ExtensionFactory): refine all. Tue Sep 16 22:25:06 2003 NAKAMURA, Hiroshi * test/csv/test_csv.rb: add negative tests of row_sep. Tue Sep 16 18:02:36 2003 Yukihiro Matsumoto * regex.c (re_compile_pattern): should not translate character class range edge. [ruby-list:38393] Tue Sep 16 16:47:56 2003 WATANABE Hirofumi * MANIFEST: add test/csv/mac.csv. * win32/Makefile.sub, bcc32/Makefile.sub (test): add phony NUL target. Mon Sep 15 19:02:52 2003 NAKAMURA, Hiroshi * lib/csv.rb: add extra pamameter to specify row(record) separater character. To parse Mac's CR separated CSV, do like this. CSV.open("mac.csv", "r", ?,, ?\r) { |row| p row.to_a } The 3rd parameter in this example ?, is for column separater and the 4th ?\r is for row separater. Row separater is nil by default. Nil separater means "\r\n" or "\n". * test/csv/test_csv.rb: add tests for above feature. * test/csv/mac.csv: added. Sample CR separated CSV file. Fri Sep 12 22:41:48 2003 Michal Rokos * ext/openssl/ossl.c: move ASN.1 stuff to ossl_asn1.[ch] * ext/openssl/ossl.c: move BIO stuff to ossl_bio.[ch] * ext/openssl/ossl_asn1.[ch]: new files * ext/openssl/ossl_bio.[ch]: new files Fri Sep 12 12:30:41 2003 Nobuyoshi Nakada * intern.h (rb_disable_super, rb_enable_super): replace with dummy expressions instead of prototypes. the functions remain yet for binary compatibility. [ruby-talk:81758] Fri Sep 12 12:09:54 2003 Yukihiro Matsumoto * bignum.c (rb_big_and): convert argument using 'to_int'. * bignum.c (rb_big_or): ditto. * bignum.c (rb_big_xor): ditto. Fri Sep 12 07:06:14 2003 David Black * lib/scanf.rb: Took out useless @matched_item variable; some small refactoring. Thu Sep 11 08:43:44 2003 Yukihiro Matsumoto * eval.c (rb_f_require): allow "require" on $SAFE>0, if feature name is not tainted. * lib/rexml/parsers/baseparser.rb (REXML::Parsers::BaseParser::stream): Supports StringIO. Wed Sep 10 22:47:30 2003 GOTOU Yuuzou * ext/openssl/ossl.h: add a workaround for win32 platform. libeay32.dll doesn't export functions defined in conf_api.h. * ext/openssl/ossl_config.c (ossl_config_initialize): ditto. * ext/openssl/ossl_config.c (ossl_config_add_value): ditto. * ext/openssl/ossl_config.c (set_conf_section_i): should check if the argument is Array. Wed Sep 10 22:41:54 2003 Tietew * eval.c (win32_get_exception_list): avoid VC7 warning. [ruby-win32:577] Tue Sep 9 10:39:51 2003 Nobuyoshi Nakada * eval.c (struct tag): dst should be VALUE. Tue Sep 9 10:39:51 2003 Nobuyoshi Nakada * eval.c (localjump_destination): stop at the scope where the current block was created. [ruby-dev:21353] Tue Sep 9 05:17:04 2003 GOTOU Yuuzou * ext/openssl/ossl_config.rb: avoid compile error in OpenSSL-0.9.6. Tue Sep 9 02:41:35 2003 Michal Rokos * ext/openssl/ossl_config.c: Refine compatibility. Tue Sep 9 01:50:45 2003 GOTOU Yuuzou * lib/webrick/httpserver.rb (HTTPServer#access_log): add "\n" to the message. * lib/webrick/log.rb (BasicLog#log): add "\n" only if needed. Mon Sep 8 22:15:33 2003 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: modify security check at creating a new interpreter Mon Sep 8 20:00:12 2003 Nobuyoshi Nakada * lib/optparse.rb, lib/optparse/version.rb: search also all capital versions. Mon Sep 8 19:26:33 2003 GOTOU Yuuzou * ext/openssl/ossl.h: include openssl/conf.h and openssl/conf_api.h. * ext/openssl/ossl_config.c: refine all with backward compatibility. * ext/openssl/ossl_config.h: export GetConfigPtr() and DupConfigPtr(). * ext/openssl/ossl_x509.c: added new constants under X509 module. DEFAULT_CERT_AREA, DEFAULT_CERT_DIR, DEFAULT_CERT_FILE, DEFAULT_CERT_DIR_ENV, DEFAULT_CERT_FILE_ENV and DEFAULT_PRIVATE_DIR. * ext/openssl/ossl_x509ext.c (ossl_x509extfactory_free): don't free the members of the struct. it's left to GC. * ext/openssl/ossl_x509ext.c (ossl_x509_set_config): add for config=. * ext/openssl/ossl_x509ext.c (Xossl_x509extfactory_initialize): add attr readers: issuer_certificate, subject_certificate, subject_request, crl and config. Mon Sep 8 18:26:41 2003 GOTOU Yuuzou * lib/webrick/accesslog.rb (AccessLog::setup_params): use req.port instead of config[:Port] or req.request_uri.port. * lib/webrick/httprequest.rb (HTTPRequest#meta_vars): ditto. * lib/webrick/httpservlet/filehandler.rb (FileHandler#dir_list): ditto. * lib/webrick/config.rb: :Listen option never be used. * lib/webrick/server.rb (GenericServer#initialize): don't use :Listen option and add warning message. * lib/webrick/log.rb (BasicLog#<<): shortcut of log(INFO, ...). * lib/webrick/httpserver.rb (HTTPServer#accesslog): use << for logging. Sun Sep 7 16:08:28 2003 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (lib_mainloop_core): fixed signal-trap bug * ext/tk/lib/*.rb : Ruby/Tk works at $SAFE == 4 Sat Sep 6 02:26:34 2003 NAKAMURA, Hiroshi * test/ruby/test_*.rb: assert_same, assert_match, and so on. Sat Sep 6 18:45:46 2003 Mauricio Fernandez * parse.y (assignable): call rb_compile_error(), not rb_bug(). [ruby-core:01523] Sat Sep 6 17:40:41 2003 GOTOU Yuuzou * ext/openssl/ruby_missing.c: rid of unnecessary backward compatibility stuff. and remove DEFINE_ALLOC_WRAPPER from all sources. * ext/openssl/ossl_x509ext.c (X509::Extension.new): new method. * ext/openssl/ossl_x509ext.c (X509::Extension#oid=): new method. * ext/openssl/ossl_x509ext.c (X509::Extension#value=): new method. * ext/openssl/ossl_x509ext.c (X509::Extension#critical=): new method. Sat Sep 6 01:23:22 2003 NAKAMURA Usaku * win32/win32.c (CreateChild): need to quote cmd if RUBYSHELL is set. * win32/win32.c (CreateChild): fix condition about whether to call shell or not. Sat Sep 6 00:36:20 2003 Nobuyoshi Nakada * Makefile.in (test): phony target. * lib/mkmf.rb (have_library, find_library): configure by library name. * lib/optparse.rb (OptionParser#order, #permute, #parse): allow an array as argument. * test/ruby/test_*.rb: moved invariants to left side in assert_equal, and use assert_nil, assert_raises and so on. * win32/win32.c (isInternalCmd): distinguish command.com and cmd.exe. * win32/win32.c (make_cmdvector): a character just after wildcard was ignored. [ruby-core:01518] Fri Sep 5 20:27:08 2003 NAKAMURA, Hiroshi * test/ruby/test_*.rb: replace 'assert(a == b)' with assert_equal(a, b)' Fri Sep 5 18:00:51 2003 GOTOU Yuuzou * ext/openssl/lib/openssl/x509.rb: new method X509::Name::parse. * ext/openssl/ossl_digest.c: add ossl_digest_new(). * ext/openssl/ossl_digest.h: ditto. * ext/openssl/ossl_cipher.c: add ossl_cipher_new(). * ext/openssl/ossl_cipher.h: ditto. Fri Sep 5 15:32:04 2003 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-font-lock-maybe-here-docs): should not search delimiter forward if found in backward. Fri Sep 5 13:32:48 2003 Nobuyoshi Nakada * test/runner.rb: arguments should be keys. Fri Sep 5 12:09:55 2003 WATANABE Hirofumi * test/ruby/test_system.rb (test_system): check existence of ruby interpreter. Fri Sep 5 11:32:17 2003 Nobuyoshi Nakada * lib/optparse.rb (--version): fix assignment/reference order. * lib/optparse.rb (OptionParser#help): new; OptionParser#to_s may be deprecated in future. * lib/optparse/version.rb (OptionParser#show_version): hide Object. * test/runner.rb: fix optparse usage. * test/runner.rb: glob all testsuits if no tests given. Fri Sep 5 10:42:58 2003 NAKAMURA, Hiroshi * test/runner.rb: added. gets testcases from command line and runs it. * test/ruby/test_gc.rb: remove useless part which was for dumping test result. Fri Sep 5 09:28:59 2003 NAKAMURA, Hiroshi * test/ruby/test_gc.rb: added. splitter.rb which I made to split sample/test.rb into test/ruby/test_* kindly removed GC test (the last section in the original test) to reduce things to be worried. Fri Sep 5 03:00:04 2003 Nobuyoshi Nakada * test/ruby/test_iterator.rb (test_block_in_arg): add no block given tests. * test/ruby/test_iterator.rb (test_ljump): uncomment LocalJumpError test. Fri Sep 5 01:10:11 2003 NAKAMURA, Hiroshi * test/ruby: tests for ruby itself. * test/ruby/test_*.rb: split sample/test.rb into 28 test/unit testcases. some tests could not be translates... search '!!' mark to see it. * test/csv/test_csv.rb: should require 'csv', not '../lib/csv'. test runner should set load path correctly. Fri Sep 5 01:03:59 2003 NAKAMURA, Hiroshi * test/csv/test_csv.rb: close opened files for CSV::IOBuf explicitly. opened file cannot be removed under win32 box. Thu Sep 4 23:59:40 2003 Nobuyoshi Nakada * parse.y (tokadd_string): newlines have no special meanings in %w/%W, otherwise they are ignored only when interpolation is enabled. [ruby-dev:21325] Thu Sep 4 19:38:25 2003 NAKAMURA, Hiroshi * ext/io/wait/.cvsignore: added. * ext/openssl/.cvsignore: added. Thu Sep 4 19:28:24 2003 NAKAMURA, Hiroshi * sample/openssl: added. Sample of standard distribution library should be locate in sample/{module_name}/*. * ext/openssl/sample/*: removed. move to sample/openssl/*. Thu Sep 4 18:02:15 2003 NAKAMURA, Hiroshi * test/csv/test_csv.rb: use remove_const to reduce warnings. use Dir.tmpdir to locate working files. Thu Sep 4 17:41:31 2003 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-here-doc-beg-re): underscore also is valid delimiter. * misc/ruby-mode.el (ruby-here-doc-end-match): must quote arbitrary string to use as regexp. * misc/ruby-mode.el (ruby-font-lock-maybe-here-docs): must not call `ruby-here-doc-end-match' unless `ruby-here-doc-beg-re' matched. Thu Sep 4 15:40:07 2003 NAKAMURA, Hiroshi * test/csv/test_csv.rb: run on test/unit original layer. Thu Sep 4 12:54:50 2003 why the lucky stiff * ext/syck/token.c: headerless documents with root-level spacing now honored. Thu Sep 4 00:06:14 2003 Yukihiro Matsumoto * eval.c (mark_frame_adj): need to adjust argv pointer if using system's alloca. [ruby-core:01503] Wed Sep 3 21:33:20 2003 NAKAMURA, Hiroshi * test: add test directory. Test::Unit aware testcases and needed files should be located in this directory. dir/file name convention; test/{module_name}/test_{testcase_name}.rb test/{module_name}/{needed_files} someday, someone will write testrunner which searches test_*.rb and run testcases automatically. * test/csv/*: add testcase for lib/csv.rb. Wed Sep 3 01:37:09 2003 Yukihiro Matsumoto * io.c (rb_f_gets): should call next_argv() before type check current_file. [ruby-list:38336] Tue Sep 2 20:37:15 2003 GOTOU Yuuzou * ext/openssl/lib/net/protocols.rb (SSLIO#ssl_connect): warning for skipping server verification. Tue Sep 2 23:36:57 2003 Yukihiro Matsumoto * eval.c (proc_invoke): should retrieve retval when pcall is true. Tue Sep 2 14:09:20 2003 Yukihiro Matsumoto * ext/socket/extconf.rb: check s6_addr8 in in6_addr (Tru64 UNIX). the patch is submitted by nmu . * ext/socket/getaddrinfo.c (getaddrinfo): should use in6_addr8 on some platforms. * ext/socket/getnameinfo.c (getnameinfo): ditto. Tue Sep 2 14:02:19 2003 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (ip_invoke): fixed bug on passing a exception * ext/tk/lib/{tk.rb, tkcanvas.rb, tkfont.rb, tktext.rb} : bug fix and improvement of font control Tue Sep 2 09:51:36 2003 Nobuyoshi Nakada * eval.c (rb_eval): should not handle exceptions within rescue argument. [ruby-talk:80804] Tue Sep 2 00:44:37 2003 Nobuyoshi Nakada * re.c (rb_memsearch): fix overrun. [ruby-talk:80759] Tue Sep 2 00:41:27 2003 Nobuyoshi Nakada * ext/iconv/iconv.c (map_charset): use lower case keys. * ext/iconv/iconv.c (iconv_fail): just yield error and return the result if a block is given. * ext/iconv/iconv.c (iconv_convert): yield error and append the result if a block is given. * ext/iconv/charset_alias.rb (charset_alias): optional third argument. * ext/iconv/charset_alias.rb (charset_alias): use CP932 instead of SHIFT_JIS on cygwin. Mon Sep 1 18:34:25 2003 Nobuyoshi Nakada * eval.c (rb_eval): make tail recursion in ELSE clause of RESCUE a jump. Mon Sep 1 18:00:02 2003 Yukihiro Matsumoto * parse.y (aref_args): forgot to call NEW_SPLAT(). reported by Dave Butcher. * eval.c (Init_Thread): protect thgroup_default. suggested by Guy Decoux in [ruby-talk:80623] Mon Sep 1 16:59:10 2003 Nobuyoshi Nakada * eval.c (rb_thread_switch): add RESTORE_EXIT; exit by another thread termination. * eval.c (rb_thread_start_0): should not error_print() within terminated thread, because $stderr used by it might be overriden now. [ruby-dev:21280] Sun Aug 31 22:46:55 2003 WATANABE Hirofumi * eval.c (TAG_DST()): take no argument. * process.c (p_gid_sw_ensure): return VALUE. Sun Aug 31 22:27:10 2003 Hidetoshi NAGAI * process.c (p_gid_sw_ensure): lack of function type Sun Aug 31 12:25:06 2003 Nobuyoshi Nakada * lib/optparse.rb: --version takes an optional argument; "all" or a list of package names. Sun Aug 31 10:17:02 2003 Tadayoshi Funaba * lib/date/format.rb: yyyy/mm is not an acceptable format. * lib/time.rb: follow above. Sat Aug 30 14:25:43 2003 Yukihiro Matsumoto * eval.c (rb_iter_break): should not call TAG_JUMP directly. Sat Aug 30 03:58:21 2003 Yukihiro Matsumoto * eval.c (struct BLOCK): remove BLOCKTAG, use scope instead. * eval.c (POP_TAG): no longer propagate retval. retval is now set directly by localjump_destination(). * eval.c (localjump_destination): new function to cast return/break local jump. * eval.c (rb_yield_0): stop TAG_RETURN/TAG_BREAK escaping. Fri Aug 29 22:35:00 2003 Shigeo Kobayashi * bigdecimal.c *.html: The 2nd arg. for add,sub,mult, and div is 0, then result will be the same as +,-,*,/ respectively. Fri Aug 29 17:30:15 2003 Hidetoshi NAGAI * process.c: bug fix * process.c: add rb_secure(2) to methods of Process::{UID,GID,Sys} * process.c: deny handling IDs during evaluating the block given to the Process::{UID,GID}.switch method * ext/tcltklib/tcltklib.c : some methods have no effect if on slave-IP * ext/tcltklib/tcltklib.c : can create a interpreter without Tk * ext/tcltklib/tcltklib.c : bug fix on handling exceptions * ext/tcltklib/MANUAL.euc : modify * ext/tk/lib/tk.rb : freeze some core modules * ext/tk/lib/multi-tk.rb : more secure * ext/tk/lib/tk.rb: TkVariable.new(array) --> treat the array as the Tk's list * ext/tk/lib/tk.rb: improve accessibility of TkVariable object * ext/tk/lib/tk.rb, ext/tk/lib/tkfont.rb, ext/tk/lib/tkcanvas.rb, ext/tk/lib/tktext.rb : fix bug of font handling * ext/tk/lib/tkfont.rb TkFont.new() accepts compound fonts Thu Aug 28 22:07:12 2003 Yukihiro Matsumoto * variable.c (rb_autoload_load): call const_missing if autoloading constant is not defined to allow hook. * eval.c (rb_eval): use rb_const_get_from() instead of rb_const_get_at(). * eval.c (is_defined): forgot to check NODE_COLON3. Thu Aug 28 17:30:24 2003 Yukihiro Matsumoto * variable.c (rb_const_get_0): should check constants defined in included modules, if klass is Object. [ruby-talk:79302] * numeric.c (check_uint): check should be done using UINT_MAX, not INT_MAX. this fix is submitted by Lyle Johnson in [ruby-core:01486] Thu Aug 28 05:02:52 2003 Yukihiro Matsumoto * parse.y (singleton): typo fixed (ruby-bugs-ja:PR#562) Thu Aug 28 02:37:45 2003 Yukihiro Matsumoto * eval.c (rb_eval): *a = [1,2] now assigns [[1,2]] to a. consistent with *a = [1], which set [[1]] to a. * node.h: merge NODE_RESTARY to NODE_SPLAT. * parse.y: rules simplified a bit by removing NODE_RESTARY. * sample/test.rb: updated for new assignment behavior. Wed Aug 27 22:33:24 2003 Nobuyoshi Nakada * error.c (rb_bug): should not use other methods; this function is not for ordinary use. [ruby-dev:21259] Wed Aug 27 15:07:57 2003 Minero Aoki * lib/net/smtp.rb (check_response): AUTH CRAM-MD5 returns 334 response. [ruby-list:38279] Wed Aug 27 05:10:15 2003 NAKAMURA Usaku * win32/win32.c (map_errno): support winsock error. * win32/win32.c (pipe_exec, CreateChild, poll_child_status, waitpid, kill, link, rb_w32_rename, unixtime_to_filetime, rb_w32_utime): pass errno to map_errno(). * win32/win32.c (rb_w32_select, rb_w32_accept, rb_w32_bind, rb_w32_connect, rb_w32_getpeername, rb_w32_getsockname, rb_w32_getsockopt, rb_w32_ioctlsocket, rb_w32_listen, rb_w32_recv, rb_w32_recvfrom, rb_w32_send, rb_w32_sendto, rb_w32_setsockopt, rb_w32_shutdown, rb_w32_socket, rb_w32_gethostbyaddr, rb_w32_gethostbyname, rb_w32_gethostname, rb_w32_getprotobyname, rb_w32_getprotobynumber, rb_w32_getservbyname, rb_w32_getservbyport, rb_w32_fclose, rb_w32_close): use map_errno(). * win32/win32.h: add winsock errors. Tue Aug 26 23:53:23 2003 Yukihiro Matsumoto * lib/ostruct.rb (OpenStruct::method_missing): prohibit modifying frozen OpenStruct. [ruby-talk:80214] Tue Aug 26 20:03:50 2003 Nobuyoshi Nakada * lib/mkmf.rb (create_tmpsrc): add the hook for source. [ruby-list:38122] Tue Aug 26 15:59:53 2003 why the lucky stiff * implicit.c (syck_type_id_to_taguri): corrected detection of x-private types. Sun Aug 24 01:02:48 2003 Nobuyoshi Nakada * file.c (file_expand_path): performance improvement. [ruby-talk:79748] Sat Aug 23 23:41:16 2003 Yukihiro Matsumoto * file.c (rb_file_s_expand_path): avoid calling rb_scan_args() for apparent cases. [ruby-talk:79748] Sat Aug 23 18:56:53 2003 Nobuyoshi Nakada * ext/nkf/nkf.c (rb_nkf_putchar): should use rb_str_resize() to just resize a string, rb_str_cat() disallows NULL. [ruby-dev:21237] Sat Aug 23 16:48:41 2003 Keiju Ishitsuka * lib/irb/ruby-lex.rb: bug fix for "foo" !~ /bar/. [ruby-talk:79942] Sat Aug 23 15:59:58 2003 Nobuyoshi Nakada * eval.c (rb_eval, rb_iterate, block_pass): reduce PUSH/POP_TAG and EXEC_TAG() for retry. [ruby-dev:21216] Sat Aug 23 02:32:33 2003 Yukihiro Matsumoto * eval.c (rb_yield_splat): should check if "values" is array. * enum.c (each_with_index_i): typo. Fri Aug 22 17:07:05 2003 Yukihiro Matsumoto * enum.c (inject_i): use rb_yield_values. * enum.c (each_with_index_i): ditto. * eval.c (rb_yield_splat): new function to call "yield *values". * string.c (rb_str_scan): use rb_yield_splat(). Fri Aug 22 06:13:22 2003 why the lucky stiff * ext/syck/rubyext.c: refactoring of the transfer method dispatch. added yaml_org_handler for faster dispatch of transfers to base types. * lib/yaml/rubytypes.rb: removed handling of builtins from Ruby library. * ext/syck/token.c: quoted and block scalars are now implicit !str * ext/syck/implicit.c: empty string detected as !null. Fri Aug 22 01:00:31 2003 Nobuyoshi Nakada * eval.c (block_pass): improve passing current block. Fri Aug 22 00:13:00 2003 Shigeo Kobayashi * ext/bigdecimal/bigdecimal.c: Int. overflow bug in multiplication fixed, and VpNmlz() speed up. Wed Aug 20 16:44:49 2003 Nobuyoshi Nakada * ext/socket/socket.c (ruby_connect): many systems seem to have a problem in select() after EINPROGRESS. [ruby-list:38080] Wed Aug 20 01:31:17 2003 why the lucky stiff * ext/syck/syck.h: Parser definition problems on HP-UX. [ruby-talk:79389] * ext/syck/handler.c (syck_hdlr_get_anchor): Memory leak. * ext/syck/syck.s (syck_io_file_read): Bad arguments to fread. * ext/syck/rubyext.c: Tainting issues. Tue Aug 19 23:20:00 2003 Shigeo Kobayashi * ext/bigdecimal/bigdecimal.c .h .html: to_s("+") implemented. * ext/bigdecimal/lib/bigdecimal/math.rb: E implemented. Tue Aug 19 07:47:09 2003 GOTOU Yuuzou * lib/webrick/ssl.rb: new file; SSL/TLS enhancement for GenericServer. * lib/webrick/https.rb: SSLSocket handling is moved to webrick/ssl.rb. * lib/webrick/compat.rb (File::fnmatch): remove old migration code. * lib/webrick/httpserver.rb (HTTPServer#run): ditto. * lib/webrick/server.rb (GenericServer#listen): the body of this method is pull out as Utils::create_lisnteners. * lib/webrick/utils.rb (Utils::create_lisnteners): new method. * lib/webrick/server.rb (GenericServer#start): should rescue unknown errors. and refine comments. * ext/openssl/lib/openssl/ssl.rb (SSLServer#accept): should close socket if SSLSocket raises error. Tue Aug 19 11:19:33 2003 Shugo Maeda * io.c (next_argv): should not call GetOpenFile() if rb_stdout is not a IO (T_FILE). Tue Aug 19 07:47:09 2003 GOTOU Yuuzou * ext/openssl/ossl_ssl.c: sync_close is moved to SSLSocket as a builtin. * ext/openssl/lib/openssl/buffering.rb (Buffering#close): ditto. * ext/openssl/lib/openssl/buffering.rb (Buffering#puts): should add a return to the tails of each line. * ext/openssl/lib/openssl/ssl.rb: new class OpenSSL::SSL::SSLServer. * ext/openssl/lib/net/protocols.rb (SSLIO#ssl_connect): use sync_close. * ext/openssl/sample/echo_svr.rb: use SSLServer. * ext/openssl/sample/echo_cli.rb: add example of SSLSocket#sync_close. Tue Aug 19 01:24:34 2003 Nobuyoshi Nakada * ext/curses/curses.c (_XOPEN_SOURCE_EXTENDED): Mac OS X standard headers are inconsistent at this macro. [ruby-core:01432] * ext/curses/extconf.rb: check if _XOPEN_SOURCE_EXTENDED breaks. * ext/tcltklib/stubs.c: Status macro in X11/Xthreads.h bothers winspool.h * instruby.rb: make list at first instead of iterator. [ruby-talk:79347] Mon Aug 18 11:23:11 2003 Nobuyoshi Nakada * dir.c (glob_helper): preserve raw order for **. Sun Aug 17 23:39:55 2003 Nobuyoshi Nakada * ext/openssl/extconf.rb (HAVE_VA_ARGS_MACRO): need to compile. Sun Aug 17 17:10:03 2003 GOTOU Yuuzou * ext/openssl/lib/openssl/ssl.rb (SSLSocket#sync_close=): add a method to specify if the underlying IO will be closed in SSLSocket#close. * ext/openssl/lib/openssl/buffering.rb: add forwarders to setsockopt, getsockopt and fcntl. * ext/openssl/lib/net/protocols.rb: enable sync for SSLSocket. Sun Aug 17 11:32:04 2003 Nobuyoshi Nakada * ext/extmk.rb (extmake): should not force to remake Makefile when installation and so on. Sat Aug 16 23:58:18 2003 Nobuyoshi Nakada * marshal.c (w_symbol, w_object): get rid of warnings. * re.c (rb_memsearch): ditto. * time.c (time_dump): ditto. * ext/extmk.rb (extmake): not continue making when extconf.rb failed. * ext/openssl/extconf.rb: check __VA_ARGS__ macro more precisely. * ext/openssl/ossl.h: remove version.h dependency. * ext/openssl/ruby_missing.h: ditto. * lib/mkmf.rb (pkg_config): use --libs output except with only-L for other options. [ruby-list:38099] * lib/mkmf.rb (create_makefile): separate rule for static library from shared object. * win32/Makefile.sub, bcc32/Makefile.sub, wince/Makefile.sub: define exec_prefix and libdir. Fri Aug 15 23:15:00 2003 Shigeo Kobayashi * ext/bigdecimal/bigdecimal.c .h: Bug in combination of limit & div method fixed. * ext/bigdecimal/lib/bigdecimal/math.rb: atan() & sqrt() added. Fri Aug 15 12:01:43 2003 Nobuyoshi Nakada * configure.in (HUGE_ST_INO): check whether struct stat.st_ino is larger than long. [ruby-dev:21194] http://www.geocities.co.jp/SiliconValley-PaloAlto/1409/ruby/beos.html * error.c (syserr_eqq): errno might exceed Fixnum limit. * error.c (Init_Exception): moved base initialization from init_syserr(). * inits.c (rb_call_inits): postpone initializing errnos until Bignum is available. Fri Aug 15 12:01:43 2003 Nobuyoshi Nakada * ext/curses/curses.c (_XOPEN_SOURCE_EXTENDED): needed to let keyname() and so on be declared. * ext/curses/curses.c (curses_resizeterm, window_resize): arguments conflicted with macros in term.h. * ext/curses/curses.c (Curses module methods): ensure initialized. [ruby-dev:21191] Fri Aug 15 02:08:53 2003 Yukihiro Matsumoto * gc.c (id2ref): recycle check should be done by klass == 0. [ruby-core:01408] Fri Aug 15 01:34:23 2003 Michal Rokos * ext/openssl/ossl_pkey.c: move generate_cb here * ext/openssl/ossl_pkey_{dh|dsa|rsa}.c: adapt to this cb * ext/openssl/openssl_missing.[ch]: add (0.9.6x, x * ext/bigdecimal/bigdecimal.c: Bug in div method fixed. * ext/bigdecimal/lib/bigdecimal/math.rb: Newly added. * ext/bigdecimal/sample/pi.rb: Changed so as to use math.rb. Thu Aug 14 21:19:14 2003 Yukihiro Matsumoto * eval.c (Init_Thread): Continuation#[] added. [ruby-talk:79028] Thu Aug 14 20:03:34 2003 Masaki Suketa * ext/win32ole/win32ole.c (OLE_FREE): should not call ole_message_loop. * ext/win32ole/win32ole.c (ole_event_free): ditto. * ext/win32ole/win32ole.c (ole_initialize): stop calling OleUninitialize at exit. Thu Aug 14 11:27:37 2003 NAKAMURA Usaku * gc.c (rb_data_object_alloc): check type of 1st argument. [ruby-dev:21192] Thu Aug 14 00:21:14 2003 Yukihiro Matsumoto * parse.y (mlhs_node): should allow "::Foo" (colon3) as lhs. * parse.y (lhs): ditto. * parse.y (yylex): should return tCOLON3 right after kCLASS. [ruby-talk:78918] * error.c (exc_initialize): was converting argument to string too eagerly. Only check was needed. [ruby-talk:78958] Wed Aug 13 23:31:00 2003 Shigeo Kobayashi * ext/bigdecimal/bigdecimal.c .h .html: Ambiguity of BigDecimal::limit removed. Wed Aug 13 19:21:34 2003 Christian Neukirchen * lib/webrick/https.rb (HTTPServer#run): should set syncing-mode to SSLSocket. [ruby-talk:78919] Wed Aug 13 18:13:49 2003 Yukihiro Matsumoto * eval.c (POP_BLOCK): turn on BLOCK_LEFT flag when leaving block. * eval.c (proc_invoke): unpack return/break destination when block is already left. Wed Aug 13 15:58:31 2003 WATANABE Hirofumi * object.c (rb_class_s_alloc): add function prototype to avoid VC++ warning. Wed Aug 13 13:50:59 2003 NAKAMURA Usaku * ext/Win32API/Win32API.c (Win32API_initialize): should pass some class to first argument of Data_Wrap_Struct(). (ruby-bugs:PR#1109) Tue Aug 12 16:55:11 2003 Nobuyoshi Nakada * Makefile.in: static link libraries to LIBRUBY_SO with static linked ext. [ruby-dev:21157] * ext/extmk.rb (extmake): sort extension library initialization order. * ext/extmk.rb (extmake): compact $extlibs. Tue Aug 12 02:48:56 2003 Yukihiro Matsumoto * eval.c (THREAD_SAVE_CONTEXT): should explicitly turn off the flag before calling getcontext(2). * eval.c (struct thread): add member to save backing store on IA64. (ruby-bugs PR1086) * eval.c (thread_mark): mark IA64 backing store region. * eval.c (thread_free): free saved IA64 backing store. * eval.c (rb_thread_save_context): save IA64 backing store as well. * eval.c (rb_thread_restore_context): restore IA64 backing store. * eval.c (THREAD_ALLOC): initialize IA64 members. Mon Aug 11 22:31:50 2003 NAKAMURA, Hiroshi * lib/debug.rb(debug_command): inspection command should inspect resulting value even if it's nil. [ruby-dev:21180] by OMAE, jun . * lib/debug.rb(debug_command): incomplete regexp. Mon Aug 11 17:33:07 2003 Yukihiro Matsumoto * eval.c (rb_call_super): do not use rb_block_given_p() for check. [ruby-talk:78656] * eval.c (BEGIN_CALLARGS): push ITER_NOT only when ITER_PRE. Sun Aug 10 10:43:05 2003 GOTOU Yuuzou * ext/openssl/lib/openssl/buffering.rb: increase BLOCK_SIZE from 1k to 16k bytes. [ruby-talk:78603] * ext/openssl/ossl_ssl.c (ossl_sslctx_s_alloc): enable partial write to allow interruption in SSLSocket#write. Sun Aug 10 00:34:16 2003 WATANABE Hirofumi * cygwin/GNUmakefile: remove unnecessary '--drive-name=$(CC)' for ccache. Sat Aug 9 10:36:21 2003 Yukihiro Matsumoto * marshal.c (w_object): do not dump generic instance variable when marshal_dump is defined. Sat Aug 9 00:35:00 2003 Shigeo Kobayashi * ext/bigdecimal.c: F style output(like 1234.56789) implemented to to_s method. * ext/bigdecimal_??.html: F style output(like 1234.56789) implemented to to_s method. Fri Aug 8 12:33:17 2003 WATANABE Hirofumi * bcc32/Makefile.sub: rubyw.exe should be a Windows GUI program. add the -aa option to WLDFLAGS. Fri Aug 8 11:29:26 2003 Koji Arai * marshal.c (w_object): should set `c_arg' at first. Fri Aug 8 03:22:28 2003 GOTOU Yuuzou * lib/webrick/httputils.rb (FormData#list): should not take a side effect for the receiver. Thu Aug 7 14:40:37 2003 WATANABE Hirofumi * cygwin/GNUmakefile: better --disbale-shared option support. * cygwin/GNUmakefile: add forwarding DLL target for cygwin. Thu Aug 7 14:21:05 2003 Corinna Vinschen * configure.in: Fix Cygwin specific naming of libraries to be net distribution compliant. (ruby-bugs:PR#1077) cygwin-ruby18.dll -> cygruby18.dll Thu Aug 7 12:51:38 2003 Yukihiro Matsumoto * eval.c (rb_f_at_exit): should not be called without a block. block_given check added. Thu Aug 7 06:46:06 2003 Yukihiro Matsumoto * eval.c (rb_call0): forgot to pop ruby_class. * eval.c (rb_call0): update ruby_class as well as ruby_cref. (ruby-bugs-ja:PR#540) Thu Aug 7 04:52:50 2003 Yukihiro Matsumoto * eval.c (rb_yield_0): remove ruby_frame->cbase and unify to ruby_cref. [ruby-talk:78141] Thu Aug 7 04:19:15 2003 Akinori MUSHA * gc.c: FreeBSD/ia64's mcontext_t is a bit different from that of Linux/ia64. This makes gc.c compile but miniruby coredumps for the moment. Thu Aug 7 00:15:00 2003 Shigeo Kobayashi * ext/bigdecimal.c: Comparison results adjusted to Float's. * ext/bigdecimal.c: Use rb_num_coerce_????(x,y) instead of own. Wed Aug 6 22:58:00 2003 Nathaniel Talbott * lib/test/unit/testcase.rb: Added equality checking. * lib/test/unit/testsuite.rb: Added equality checking. * lib/test/unit/assertions.rb: Fixed a warning. Wed Aug 6 17:28:10 2003 Nobuyoshi Nakada * ext/extmk.rb (extmake): pass LIBPATH to make ruby. [ruby-dev:21137] * ext/extmk.rb (extmake): set library name as source file name in Init_ext(). [ruby-dev:21137] * lib/mkmf.rb (Logging::postpone): postpone logging messages after heading message as the result of the block. * lib/mkmf.rb (macro_defined?): append newline to src unless ended with it. * lib/mkmf.rb (have_library): treat nil function name as "main". (ruby-bugs:PR#1083) * lib/mkmf.rb (pkg_config): should append additional libraries to $libs but not $LIBS. [ruby-dev:21137] * ext/io/wait/extconf.rb: check DOSISH macro instead of platform. * ext/digest/sha1/extconf.rb: have_library already appends library name. Wed Aug 6 17:23:57 2003 Yukihiro Matsumoto * eval.c: initialize /* OK */ variables by Qnil to stop warnings. Wed Aug 6 04:58:32 2003 NAKAMURA Usaku * ext/Setup*: add io/wait and openssl. Wed Aug 6 01:13:38 2003 Yukihiro Matsumoto * eval.c (rb_f_autoload): use ruby_cbase instead of ruby_class. * eval.c (rb_f_autoload_p): ditto. * class.c (rb_mod_init_copy): no longer implements independent clone and dup methods. override "initialize_copy" instead. [ruby-core:01352] * object.c (rb_class_s_alloc): define Class allocation function. this makes Classes to follow clone framework that uses initialize_copy. * object.c (rb_class_initialize): separate instantiation and initialization. * object.c (rb_obj_alloc): prohibit instantiation from uninitialized class. * object.c (rb_class_superclass): check uninitialized class. * array.c (rb_ary_fill): wrong index processing with block. this fix was done by Koji Arai [ruby-list:38029] * marshal.c (w_object): should preserve generic ivar for nil, true, false, symbols, and fixnums. * marshal.c (w_uclass): base_klass check should be done after rb_class_real(). Wed Aug 6 01:18:50 2003 Minero Aoki * lib/net/http.rb: update document. * lib/net/pop.rb: ditto. * lib/net/protocol.rb: ditto. Wed Aug 6 00:48:37 2003 Koji Arai * marshal.c (w_object): should recommend marshal_dump rather than _dump_data. Tue Aug 5 17:58:57 2003 WATANABE Hirofumi * lib/fileutils.rb (install): should preserve timestamp only. Tue Aug 5 17:31:59 2003 Ian Macdonald * lib/shell/command-processor.rb (Shell::CommandProcessor::rmdir): simple typo. Tue Aug 5 15:47:34 2003 Nobuyoshi Nakada * eval.c (rb_load): should preserve current source file/line. Tue Aug 5 10:04:42 2003 Yukihiro Matsumoto * string.c (str_new4): ptr may refer null_str. Mon Aug 4 17:25:18 2003 Yukihiro Matsumoto * stable version 1.8.0 released. For the changes before 1.8.0, see doc/ChangeLog-1.8.0 Local variables: add-log-time-format: (lambda () (let* ((time (current-time)) (system-time-locale "C") (diff (+ (cadr time) 32400)) (lo (% diff 65536)) (hi (+ (car time) (/ diff 65536)))) (format-time-string "%a %b %e %H:%M:%S %Y" (list hi lo) t))) indent-tabs-mode: t tab-width: 8 end: ================================================ FILE: GPL ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ================================================ FILE: LEGAL ================================================ LEGAL NOTICE INFORMATION ------------------------ All the files in this distribution are covered under either the Ruby's license (see the file COPYING) or public-domain except some files mentioned below. regex.[ch]: These files are under LGPL. Treat them as LGPL says. (See the file LGPL for details) Extended regular expression matching and search library. Copyright (C) 1993, 94, 95, 96, 97, 98 Free Software Foundation, Inc. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file LGPL. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ Multi-byte extension added May, 1993 by t^2 (Takahiro Tanimoto) Last change: May 21, 1993 by t^2 removed gapped buffer support, multiple syntax support by matz Perl5 extension added by matz UTF-8 extension added Jan 16 1999 by Yoshida Masato configure: This file is free software. Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. config.guess: config.sub: parse.c: As long as you distribute these files with the file configure, they are covered under the Ruby's license. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc. This file 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 2 of the License, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception to the GNU General Public License, if you distribute this file as part of a program that contains a configuration script generated by Autoconf, you may include it under the same distribution terms that you use for the rest of that program. util.c (partly): win32/win32.[ch]: You can apply the Artistic License to these files. (or GPL, alternatively) Copyright (c) 1993, Intergraph Corporation You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the perl README file. random.c This file is under the new-style BSD license. A C-program for MT19937, with initialization improved 2002/2/10. Coded by Takuji Nishimura and Makoto Matsumoto. This is a faster version by taking Shawn Cokus's optimization, Matthe Bellew's simplification, Isaku Wada's real version. Before using, initialize the state by using init_genrand(seed) or init_by_array(init_key, key_length). Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Any feedback is very welcome. http://www.math.keio.ac.jp/matumoto/emt.html email: matumoto@math.keio.ac.jp st.[ch]: x68/*: missing/alloca.c: missing/dup2.c: missing/finite.c: missing/hypot.c: missing/isinf.c: missing/isnan.c: missing/memcmp.c: missing/memmove.c: missing/strcasecmp.c: missing/strchr.c: missing/streror.c: missing/strftime.c: missing/strncasecmp.c: missing/strstr.c: missing/strtol.c: ext/digest/sha1/sha1.[ch]: These files are all under public domain. missing/strtod.c: This file will not be used on most platforms depending on how the configure script results. In any case you must not receive any fee with the file itself. Copyright (c) 1988-1993 The Regents of the University of California. Copyright (c) 1994 Sun Microsystems, Inc. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies. The University of California makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. missing/strtoul.c: This file will not be used on most platforms depending on how the configure script results. In any case you must not receive any fee with the file itself. Copyright 1988 Regents of the University of California Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies. The University of California makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. missing/erf.c: missing/crypt.c: missing/vsnprintf.c: This file is under the old-style BSD license. Note that the paragraph 3 below is now null and void. Copyright (c) 1990, 1993 The Regents of the University of California. All rights reserved. This code is derived from software contributed to Berkeley by Chris Torek. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. IMPORTANT NOTE: -------------- From ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change paragraph 3 above is now null and void. ext/digest/md5/md5.[ch]: These files are under the following license. Ruby uses modified versions of them. Copyright (C) 1999, 2000 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com ext/digest/rmd160/rmd160.[ch]: These files have the following copyright information, and by the author we are allowed to use it under the new-style BSD license. AUTHOR: Antoon Bosselaers, ESAT-COSIC (Arranged for libc by Todd C. Miller) DATE: 1 March 1996 Copyright (c) Katholieke Universiteit Leuven 1996, All Rights Reserved ext/digest/rmd160/rmd160hl.c: ext/digest/sha1/sha1hl.c: These files are under the beer-ware license. "THE BEER-WARE LICENSE" (Revision 42): wrote this file. As long as you retain this notice you can do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp ext/digest/sha2/sha2.[ch]: ext/digest/sha2/sha2hl.c: These files are under the new-style BSD license. Copyright 2000 Aaron D. Gifford. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ext/nkf/nkf-utf8/config.h: ext/nkf/nkf-utf8/nkf.c: ext/nkf/nkf-utf8/utf8tbl.c: These files are under the following license. So to speak, it is copyrighted semi-public-domain software. Copyright (C) 1987, Fujitsu LTD. (Itaru ICHIKAWA) Everyone is permitted to do anything on this program including copying, modifying, improving, as long as you don't try to pretend that you wrote it. i.e., the above copyright notice has to appear in all copies. Binary distribution requires original version messages. You don't have to ask before copying, redistribution or publishing. THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. ext/socket/addrinfo.h: ext/socket/getaddrinfo.c: ext/socket/getnameinfo.c: These files are under the new-style BSD license. Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ext/win32ole/win32ole.c: You can apply the Artistic License to this file. (or GPL, alternatively) (c) 1995 Microsoft Corporation. All rights reserved. Developed by ActiveWare Internet Corp., http://www.ActiveWare.com Other modifications Copyright (c) 1997, 1998 by Gurusamy Sarathy and Jan Dubois You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the README file of the Perl distribution. ================================================ FILE: LGPL ================================================ GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ================================================ FILE: Makefile.in ================================================ SHELL = /bin/sh NULLCMD = : #### Start of system configuration section. #### srcdir = @srcdir@ VPATH = $(srcdir):$(srcdir)/missing CC = @CC@ YACC = @YACC@ PURIFY = AUTOCONF = autoconf @SET_MAKE@ MKFILES = @MAKEFILES@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ sbindir = @sbindir@ libdir = @libdir@ libexecdir = @libexecdir@ datarootdir = @datarootdir@ datadir = @datadir@ arch = @arch@ sitearch = @sitearch@ sitedir = @sitedir@ TESTUI = console TESTS = RDOCTARGET = @RDOCTARGET@ EXTOUT = @EXTOUT@ RIDATADIR = $(DESTDIR)$(datadir)/ri/$(MAJOR).$(MINOR)/system empty = OUTFLAG = @OUTFLAG@$(empty) CFLAGS = @CFLAGS@ @XCFLAGS@ @ARCH_FLAG@ cflags = @cflags@ optflags = @optflags@ debugflags = @debugflags@ CPPFLAGS = -I. -I$(srcdir) @CPPFLAGS@ LDFLAGS = @STATIC@ $(CFLAGS) @LDFLAGS@ EXTLDFLAGS = XLDFLAGS = @XLDFLAGS@ $(EXTLDFLAGS) EXTLIBS = LIBS = @LIBS@ $(EXTLIBS) MISSING = @LIBOBJS@ @ALLOCA@ LDSHARED = @LIBRUBY_LDSHARED@ DLDFLAGS = @LIBRUBY_DLDFLAGS@ $(EXTLDFLAGS) @ARCH_FLAG@ SOLIBS = @SOLIBS@ MAINLIBS = @MAINLIBS@ MINIOBJS = @MINIOBJS@ RUBY_INSTALL_NAME=@RUBY_INSTALL_NAME@ RUBY_SO_NAME=@RUBY_SO_NAME@ EXEEXT = @EXEEXT@ PROGRAM=$(RUBY_INSTALL_NAME)$(EXEEXT) RUBY = $(RUBY_INSTALL_NAME) MINIRUBY = @MINIRUBY@ $(MINIRUBYOPT) RUNRUBY = @RUNRUBY@ $(RUNRUBYOPT) -- #### End of system configuration section. #### MAJOR= @MAJOR@ MINOR= @MINOR@ TEENY= @TEENY@ LIBRUBY_A = @LIBRUBY_A@ LIBRUBY_SO = @LIBRUBY_SO@ LIBRUBY_ALIASES= @LIBRUBY_ALIASES@ LIBRUBY = @LIBRUBY@ LIBRUBYARG = @LIBRUBYARG@ LIBRUBYARG_STATIC = @LIBRUBYARG_STATIC@ LIBRUBYARG_SHARED = @LIBRUBYARG_SHARED@ PREP = @PREP@ ARCHFILE = @ARCHFILE@ SETUP = EXTSTATIC = @EXTSTATIC@ RM = rm -f NM = @NM@ AR = @AR@ ARFLAGS = rcu RANLIB = @RANLIB@ AS = @AS@ ASFLAGS = @ASFLAGS@ OBJEXT = @OBJEXT@ MANTYPE = @MANTYPE@ INSTALLED_LIST= .installed.list #### End of variables all: .DEFAULT: all # Prevent GNU make v3 from overflowing arg limit on SysV. .NOEXPORT: miniruby$(EXEEXT): @$(RM) $@ $(PURIFY) $(CC) $(LDFLAGS) $(XLDFLAGS) $(MAINLIBS) $(MAINOBJ) $(MINIOBJS) $(LIBRUBY_A) $(LIBS) $(OUTFLAG)$@ $(PROGRAM): @$(RM) $@ $(PURIFY) $(CC) $(LDFLAGS) $(XLDFLAGS) $(MAINLIBS) $(MAINOBJ) $(EXTOBJS) $(LIBRUBYARG) $(LIBS) $(OUTFLAG)$@ # We must `rm' the library each time this rule is invoked because "updating" a # MAB library on Apple/NeXT (see --enable-fat-binary in configure) is not # supported. $(LIBRUBY_A): @$(RM) $@ $(AR) $(ARFLAGS) $@ $(OBJS) $(DMYEXT) @-$(RANLIB) $@ 2> /dev/null || true $(LIBRUBY_SO): @-$(PRE_LIBRUBY_UPDATE) $(LDSHARED) $(DLDFLAGS) $(OBJS) $(DLDOBJS) $(SOLIBS) $(OUTFLAG)$@ @-$(MINIRUBY) -e 'ARGV.each{|link| File.delete link if File.exist? link; \ File.symlink "$(LIBRUBY_SO)", link}' \ $(LIBRUBY_ALIASES) || true fake.rb: Makefile @echo ' \ class Object; \ CROSS_COMPILING = RUBY_PLATFORM; \ remove_const :RUBY_PLATFORM; \ remove_const :RUBY_VERSION; \ RUBY_PLATFORM = "@arch@"; \ RUBY_VERSION = "@MAJOR@.@MINOR@.@TEENY@"; \ end; \ if RUBY_PLATFORM =~ /mswin|bccwin|mingw/; \ class File; \ remove_const :ALT_SEPARATOR; \ ALT_SEPARATOR = "\\"; \ end; \ end; \ ' > $@ Makefile: $(srcdir)/Makefile.in $(MKFILES): config.status $(srcdir)/common.mk MAKE=$(MAKE) $(SHELL) ./config.status @{ \ echo "all:; -@rm -f conftest.mk"; \ echo "conftest.mk: .force; @echo AUTO_REMAKE"; \ echo ".force:"; \ } > conftest.mk || exit 1; \ $(MAKE) -f conftest.mk | grep '^AUTO_REMAKE$$' >/dev/null 2>&1 || \ { echo "Makefile updated, restart."; exit 1; } config.status: $(srcdir)/configure MINIRUBY="$(MINIRUBY)" $(SHELL) ./config.status --recheck $(srcdir)/configure: $(srcdir)/configure.in cd $(srcdir) && $(AUTOCONF) lex.c: keywords ( gperf -C -p -j1 -i 1 -g -o -t -N rb_reserved_word -k1,3,$$ $? > $@.tmp && mv $@.tmp $@ ) || \ if test -f $@; then \ touch $@ && echo $@ touched.; \ else \ cp $(srcdir)/lex.c $@ && echo $@ copied.; \ fi .y.c: $(YACC) $< sed '/^#/s|y\.tab\.c|$@|' y.tab.c > $@ rm -f y.tab.c .c.@OBJEXT@: $(CC) $(CFLAGS) $(CPPFLAGS) -c $< .s.@OBJEXT@: $(AS) $(ASFLAGS) -o $@ $< clean-local:: @$(RM) ext/extinit.c ext/extinit.$(OBJEXT) distclean-local:: @$(RM) ext/config.cache $(RBCONFIG) ext/extinit.$(OBJEXT): ext/extinit.c $(SETUP) $(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(OUTFLAG)$@ -c ext/extinit.c update-rubyspec: if [ -d $(srcdir)/rubyspec ]; then \ cd $(srcdir)/rubyspec/mspec; \ git pull; \ cd ../spec; \ git pull; \ else \ mkdir $(srcdir)/rubyspec; \ git clone $(MSPEC_GIT_URL) $(srcdir)/rubyspec/mspec; \ git clone $(RUBYSPEC_GIT_URL) $(srcdir)/rubyspec/spec; \ fi test-rubyspec: @if [ ! -d $(srcdir)/rubyspec ]; then echo No rubyspec here. make update-rubyspec first.; exit 1; fi RUBY_EXE="$(RUNRUBY)" $(RUNRUBY) $(srcdir)/rubyspec/mspec/bin/mspec-run --background --prefix $(srcdir)/rubyspec/spec -B $(srcdir)/rubyspec/spec/ruby.$(MAJOR).$(MINOR).mspec ================================================ FILE: NEWS ================================================ = NEWS This document is a list of user visible feature changes made between releases except for bug fixes. Note that each entry is kept so brief that no reason behind or reference information is supplied with. For a full list of changes with all sufficient information, see the ChangeLog file. == Changes since the 1.8.7 release === Lexical changes * empty symbol literal Empty symbol (:"") is allowed. * looser splat opetator You can write things like: x, *y, z = a, *b, c def foo(a, b=1, *c, d); end But when you evaluate them, you will get exceptions. * new hash immediates Ruby 1.9 style hash syntax e.g. { key: value } is now also supported in 1.8. You can also write a method invocation syntax foo bar: baz. === Configuration changes * version specific directories A new configure option --with-ruby-version is added, which allows user to specify the version string (defaulted to "1.8") for version specific directories such as library directories, ri directories and gem directories. === Library updates (outstanding ones only) * builtin classes * Array#try_convert() * Hash#try_convert() * IO#try_convert() * Regexp#try_convert() * String#try_convert() New methods. * Array#sample New method with which replaces #choice. * Enumerable#each_with_object * Enumerator#with_object New methods. * Enumerator.new { |y| ... } Now can generate an enumerator from a block that defines enumeration instead of an enumerable object. * Enumerator#rewind Now calls the "rewind" method of the enclosed object if defined. * Enumerator#inspect Implemented. * Hash#default_proc= New method. * Hash#key Renamed from Hash#index. * ENV.key Renamed from ENV.index. * IO#ungetbyte Added as an alias to #ungetc. * Proc#=== New method primarily for use in the case-when construct. * Range#cover? New alias to #include? for the forward compatibility with 1.9, in which the behavior of Range#include? has changed. * Regexp The regular expression /\s/ now properly matches a vertical tab character (VT: "\v") and /\S/ does not. It was a bug that /\s/ did not match VT when /[\s]/ does. It is clear that VT should always be regarded as white space, not to mention String#strip. * String#getbyte * String#setbyte * String#ord New methods for the forward compatibility with 1.9, in which the behavior of String#[] and String#[]= have changed. String#ord is $KCODE aware. * Symbol#succ * Symbol#next * Symbol#<=> * Symbol#casecmp * Symbol#=~ * Symbol#[] * Symbol#slice * Symbol#length * Symbol#size * Symbol#empty? * Symbol#match * Symbol#upcase * Symbol#downcase * Symbol#capitalize * Symbol#swapcase New methods. * base64 * Base64#strict_encode64 * Base64#strict_decode64 * Base64#urlsafe_encode64 * Base64#urlsafe_decode64 New methods. * dbm DBM#key Renamed from DBM#index. * gdbm GDBM#key Renamed from GDBM#index. * open-uri * Added a lot of new options: * :ftp_active_mode => bool Specify false to enable FTP passive mode. It is adviced that this option should be explicitly set for forward compatibility because the default mode is changed in Ruby >= 1.9. * :read_timeout => seconds * :proxy_http_basic_authentication => [uri, user, password] * :redirect => bool * :ssl_verify_mode => OpenSSL::SSL::VERIFY_* * :ssl_ca_cert => filename * rational * Performace improved by making overall code optimization and introducing Fixnum#gcd implemented in C. * sdbm SDBM#key Renamed from SDBM#index. * securerandom SecureRandom.uuid New method to generate a v4 random UUID. * set Set#classify Set#collect! Set#delete_if Set#delete_if Set#divide Set#reject! Return an enumerator if no block is given. * stringio * StringIO#ungetbyte Added as an alias to #ungetc. * digest * new methods: * Digest::Class.base64digest * Digest::Instance#base64digest * Digest::Instance#base64digest! * rss * 0.2.4 -> 0.2.7. * RSS::Maker.make * raise an exception not returns nil for invalid feed making. * requires block. * RSS::Maker.[] * new method to return maker class. * RSS::Maker.supported?(version) * new method to check whether given version is supported. * RSS::Maker: item.guid.permanent_link? * new alias of item.guid.isPermaLink * RSS::Maker: item.guid.permanent_link= * new alias of item.guid.isPermaLink= * REXML * REXML::Document.entity_expansion_limit= New method to set the entity expansion limit. By default the limit is set to 10000. See the following URL for details. http://www.ruby-lang.org/en/news/2008/08/23/dos-vulnerability-in-rexml/ == Changes since the 1.8.6 release === Configuration changes * vendor_ruby directory A new library directory named `vendor_ruby' is introduced in addition to `site_ruby'. The idea is to separate libraries installed by the package system (`vendor') from manually (`site') installed libraries preventing the former from getting overwritten by the latter, while preserving the user option to override vendor libraries with site libraries. (`site_ruby' takes precedence over `vendor_ruby') If you are a package maintainer, make each library package configure the library passing the `--vendor' option to `extconf.rb' so that the library files will get installed under `vendor_ruby'. You can change the directory locations using configure options such as `--with-sitedir=DIR' and `--with-vendordir=DIR'. === Global constants * new constants * RUBY_COPYRIGHT * RUBY_DESCRIPTION === Library updates (outstanding ones only) * new library * securerandom * builtin classes * Array#flatten * Array#flatten! Takes an optional argument that determines the level of recursion to flatten. * Array#eql? * Array#hash * Array#== * Array#<=> Handle recursive data properly. * Array#index * Array#rindex Take a block instead of an argument. * Array#collect! * Array#map! * Array#each * Array#each_index * Array#reverse_each * Array#reject * Array#reject! * Array#delete_if Return an enumerator if no block is given. Note that #map and #collect still return an array unlike Ruby 1.9 to keep compatibility. * Array#pop * Array#shift Take an optional argument specifying the number of elements to remove. * Array#choice * Array#combination * Array#cycle * Array#drop * Array#drop_while * Array#permutation * Array#product * Array#shuffle * Array#shuffle! * Array#take, * Array#take_while New methods. * Binding#eval New method. * Dir#each * Dir#foreach Return an enumerator if no block is given. * Enumerable::Enumerator New class for various enumeration defined by the enumerator library. * Enumerable#each_slice * Enumerable#each_cons * Object#to_enum * Object#enum_for New methods for various enumeration defined by the enumerator library. * Enumerable#count * Enumerable#cycle * Enumerable#drop * Enumerable#drop_while * Enumerable#find_index * Enumerable#first * Enumerable#group_by * Enumerable#max_by * Enumerable#min_by * Enumerable#minmax * Enumerable#minmax_by * Enumerable#none? * Enumerable#one? * Enumerable#take * Enumerable#take_while New methods. * Enumerable#find * Enumerable#find_all * Enumerable#partition * Enumerable#reject * Enumerable#select * Enumerable#sort_by Return an enumerator if no block is given. Note that #map and #collect still return an array unlike Ruby 1.9 to keep compatibility. * Enumerable#inject Accepts a binary operator instead of a block. * Enumerable#reduce New alias to #inject. * Enumerable#to_a Can take optional arguments and pass them to #each. * Hash#eql? * Hash#hash * Hash#== Handle recursive data properly. * Hash#delete_if * Hash#each * Hash#each_key * Hash#each_pair * Hash#each_value * Hash#reject! * Hash#select * ENV.delete_if * ENV.each * ENV.each_key * ENV.each_pair * ENV.each_value * ENV.reject! * ENV.select Return an enumerator if no block is given. * GC.stress * GC.stress= New methods. * Integer#ord * Integer#odd? * Integer#even? * Integer#pred New methods. * Integer#downto * Integer#times * Integer#upto Return an enumerator if no block is given. * IO#each * IO#each_line * IO#each_byte * IO.foreach * ARGF.each * ARGF.each_line * ARGF.each_byte Return an enumerator if no block is given. * IO#bytes * IO#chars * IO#each_char * IO#getbyte * IO#lines * IO#readbyte * ARGF.bytes * ARGF.chars * ARGF.each_char * ARGF.getbyte * ARGF.lines * ARGF.readbyte New methods. * Method#name * Method#owner * Method#receiver * UnboundMethod#name * UnboundMethod#owner New methods. * Module#class_exec * Module#module_exec New methods. * Numeric#step Return an enumerator if no block is given. * Object#instance_exec * Object#tap New methods. * ObjectSpace.each_object Return an enumerator if no block is given. * Process.exec implemented. * Range#each * Range#step Return an enumerator if no block is given. * Regexp.union accepts an array of patterns. * String#bytes New method * String#bytesize New method, returning the size in bytes. (alias length and size) * String#chars * String#each_char * String#lines * String#partition * String#rpartition * String#start_with? * String#end_with? New methods. These are $KCODE aware unlike #index, #rindex and #include?. * String#each_byte * String#each * String#each_line * String#gsub(pattern) Return an enumerator if no block is given. * String#upto An optional second argument is added to specify if the last value should be included. * StopIteration New exception class that causes Kernel#loop to stop iteration when raised. * Struct#each * Struct#each_pair Return an enumerator if no block is given. * Symbol#to_proc New method. * __method__ New global function that returns the name of the current method as a Symbol. * enumerator * Enumerator is now a built-in module. The #next and #rewind methods are implemented using the "generator" library. Use with care and be aware of the performance loss. * ipaddr * New methods * IPAddr#<=> * IPAddr#succ IPAddr objects are now comparable and enumerable having these methods. This also means that it is possible to have a Range object between two IPAddr objects. * IPAddr#to_range A new method to create a Range object for the (network) address. * Type coercion support * IPAddr#& * IPAddr#| * IPAddr#== * IPAddr#include? These methods now accept a string or an integer instead of an IPAddr object as the argument. * net/smtp * Support SSL/TLS. * openssl * New classes * OpenSSL::PKey::EC * OpenSSL::PKey::EC::Group * OpenSSL::PKey::EC::Point * OpenSSL::PKey::PKCS5 * OpenSSL::SSL::Session * Documentation! * Various new methods (see documentation). * Remove redundant module namespace in Cipher, Digest, PKCS7, PKCS12. Compatibility classes are provided which will be removed in Ruby 1.9. * shellwords * Add methods for escaping shell-unsafe characters: * Shellwords.join * Shellwords.escape * Array#shelljoin * String#shellescape * Add shorthand methods: * Shellwords.split (alias shellwords) * String#shellsplit * stringio * StringIO#getbyte * StringIO#readbyte New methods. (aliases for compatibility with 1.9) * StringIO#each_char * StringIO#chars New methods. * StringIO#each * StringIO#each_line * StringIO#each_byte Return an enumerator if no block is given. * tempfile * Tempfile.open and Tempfile.new now accept a suffix for the temporary file to be created. To specify a suffix, pass an array of [basename, suffix] as the first argument. Tempfile.open(['image', 'jpg']) { |tempfile| ... } * tmpdir * New method: * Dir.mktmpdir * uri * added LDAPS scheme. * Change for RFC3986: * FTP * URI('ftp://example.com/foo').path #=> 'foo' * URI('ftp://example.com/%2Ffoo').path #=> '/foo' * URI::FTP.build([nil, 'example.com', nil, '/foo', 'i').to_s #=> 'ftp://example.com/%2Ffoo;type=i' * URI merge * URI('http://a/b/c/d;p?q').merge('?y') == URI('http://a/b/c/d;p?y') * URI('http://a/b/c/d;p?q').merge('/./g') == URI('http://a/g') * URI('http://a/b/c/d;p?q').merge('/../g') == URI('http://a/g') * URI('http://a/b/c/d;p?q').merge('../../../g') == URI('http://a/g') * URI('http://a/b/c/d;p?q').merge('../../../../g') == URI('http://a/g') * rss * 0.1.6 -> 0.2.4 * Fix image module URI * Atom support * ITunes module support * Slash module support * content:encoded with RSS 2.0 support === Interpreter Implementation * passing a block to a Proc [experimental] This implementation in current shape is known to be buggy/broken, especially with nested block invocation. Take this as an experimental feature. * stack trace On non-SystemStackError exception, full stack trace is shown. === Compatibility issues (excluding feature bug fixes) * String#slice! had some unintentional bugs and they have been fixed because either they disagreed with documentation or their respective behavior of #slice. Unfortunately, this causes some incompatibilities in the following (somewhat rare) cases. * #slice! no longer expands the array when an out-of-boundary value is given. # Ruby 1.8.6 a = [1,2] a.slice!(4,0) #=> nil a #=> [1,2,nil,nil] # Ruby 1.8.7 a = [1,2] a.slice!(4,0) #=> nil a #=> [1,2] * #slice! no longer raises an exception but returns nil when a negative length or out-of-boundary negative position is given. # Ruby 1.8.6 a = [1,2] a.slice!(1,-1) #=> (raises IndexError) a.slice!(-5,1) #=> (raises IndexError) # Ruby 1.8.7 a = [1,2] a.slice!(1,-1) #=> nil a.slice!(-5,1) #=> nil * String#to_i, String#hex and String#oct no longer accept a sequence of underscores (`__') as part of a number. # Ruby 1.8.6 '1__0'.to_i #=> 10 '1__0'.to_i(2) #=> 2 # 0b10 '1__0'.oct #=> 8 # 010 '1__0'.hex #=> 16 # 0x10 # Ruby 1.8.7 '1__0'.to_i #=> 1 '1__0'.to_i(2) #=> 1 '1__0'.oct #=> 1 '1__0'.hex #=> 1 The old behavior was inconsistent with Ruby syntax and considered as a bug. * date * Date.parse '##.##.##' (where each '#' is a digit) is now taken as 'YY.MM.DD' instead of 'MM.DD.YY'. While the change may confuse you, you can always use Date.strptime() when you know what you are dealing with. * stringio * StringIO#each_byte The return value changed from nil to self. This is what the document says and the same as each_line() does. * tempfile * The file name format has changed. No dots are included by default in temporary file names any more. See above for how to specify a suffix. * uri * See above for details. == Changes since the 1.8.5 release === New platforms/build tools support * IA64 HP-UX * Visual C++ 8 SP1 * autoconf 2.6x === Global constants * RUBY_PATCHLEVEL New constant since 1.8.5-p1. === Library updates (outstanding ones only) * builtin classes * New method: Kernel#instance_variable_defined? * New method: Module#class_variable_defined? * New feature: Dir::glob() can now take an array of glob patterns. * date * Updated based on date2 4.0.3. * digest * New internal APIs for C and Ruby. * Support for autoloading. require 'digest' # autoloads digest/md5 md = Digest::MD5.digest("string") * New digest class methods: file * New digest instance methods: clone, reset, new, inspect, digest_length (alias size or length), block_length() * New library: digest/bubblebabble * New function: Digest(name) * fileutils * New option for FileUtils.cp_r(): :remove_destination * nkf * Updated based on nkf as of 2007-01-28. * thread * Replaced with much faster mutex implementation in C. The former implementation, which is slow but considered to be stable, is available with a configure option `--disable-fastthread'. * tk * Updated Tile extension support based on Tile 0.7.8. * Support --without-X11 configure option for non-X11 versions of Tcl/Tk (e.g. Tcl/Tk Aqua). * New sample script: irbtkw.rbw -- IRB on Ruby/Tk. It has no trouble about STDIN blocking on Windows. * webrick * New method: WEBrick::Cookie.parse_set_cookies() === Compatibility issues (excluding feature bug fixes) * builtin classes * String#intern now raises SecurityError when $SAFE level is greater than zero. * date * Time#to_date and Time#to_datetime are added as private methods. They cause name conflict error in ActiveSupport 1.4.1 and prior, which comes with Rails 1.2.2 and prior. Updating ActiveSupport and/or Rails to the latest versions fixes the problem. * digest * The constructor does no longer take an initial string to feed. The following examples show how to migrate: # Before md = Digest::MD5.new("string") # After (works with any version) md = Digest::MD5.new.update("string") # Before hd = Digest::MD5.new("string").hexdigest # After (works with any version) hd = Digest::MD5.hexdigest("string") * fileutils * A minor implementation change breaks Rake <=0.7.1. Updating Rake to 0.7.2 or higher fixes the problem. * tk * Tk::X_Scrollable (Y_Scrollable) is renamed to Tk::XScrollable (YScrollable). Tk::X_Scrollable (Y_Scrollable) is still available, but it is an alias name. ================================================ FILE: README ================================================ * What's Ruby Ruby is the interpreted scripting language for quick and easy object-oriented programming. It has many features to process text files and to do system management tasks (as in Perl). It is simple, straight-forward, and extensible. * Features of Ruby + Simple Syntax + *Normal* Object-Oriented features(ex. class, method calls) + *Advanced* Object-Oriented features(ex. Mix-in, Singleton-method) + Operator Overloading + Exception Handling + Iterators and Closures + Garbage Collection + Dynamic Loading of Object files(on some architecture) + Highly Portable(works on many UNIX machines, and on DOS, Windows, Mac, BeOS etc.) * How to get Ruby The Ruby distribution files can be found in the following FTP site: ftp://ftp.ruby-lang.org/pub/ruby/ The latest source code of this version series can be checked out through SVN with the following command: $ svn co http://svn.ruby-lang.org/repos/ruby/branches/ruby_1_8/ The trunk of the Ruby source tree can be checked out with the following command: $ svn co http://svn.ruby-lang.org/repos/ruby/trunk/ ruby There are some other branches under development. Try the following command and see the list of branches: $ svn ls http://svn.ruby-lang.org/repos/ruby/branches/ * Ruby home-page The URL of the Ruby home-page is: http://www.ruby-lang.org/ * Mailing list There is a mailing list to talk about Ruby. To subscribe this list, please send the following phrase subscribe YourFirstName YourFamilyName e.g. subscribe Joseph Smith in the mail body (not subject) to the address . * How to compile and install This is what you need to do to compile and install Ruby: 1. If ./configure does not exist or is older than configure.in, run autoconf to (re)generate configure. 2. Run ./configure, which will generate config.h and Makefile. Some C compiler flags may be added by default depending on your environment. Specify optflags=.. and warnflags=.. as necessary to override them. 3. Edit defines.h if you need. Usually this step will not be needed. 4. Remove comment mark(#) before the module names from ext/Setup (or add module names if not present), if you want to link modules statically. If you don't want to compile non static extension modules (probably on architectures which does not allow dynamic loading), remove comment mark from the line "#option nodynamic" in ext/Setup. 5. Run make. 6. Optionally, run 'make test' to check whether the compiled Ruby interpreter works well. If you see the message "test succeeded", your ruby works as it should (hopefully). 7. Run 'make install' You may have to be a super user to install ruby. If you fail to compile ruby, please send the detailed error report with the error log and machine/OS type, to help others. * Copying See the file COPYING. * The Author Feel free to send comments and bug reports to the author. Here is the author's latest mail address: matz@netlab.jp ------------------------------------------------------- created at: Thu Aug 3 11:57:36 JST 1995 Local variables: mode: indented-text end: ================================================ FILE: README-kiji ================================================ What is Kiji ============ Kiji is a version of the Ruby Enterprise Edition runtime specifically improved for execution of large long-running programs, such as servers. The changes in Kiji are mostly concerned with MRI's garbage collection algorithm, which used to take a large portion of the execution time. MRI only uses one heap for all objects. Kiji uses two, named "eden" and "longlife". Longlife heap stores all AST nodes (parsed representations of the source code) as well as most constant strings. Longlife is collected much less frequently, allowing for CPU time savings. Build instructions ================== The build instructions provided in Ruby's master README file are perfectly appropriate for Kiji as well. However, at Twitter we're actually linking it with [Google's tcmalloc library](http://code.google.com/p/google-perftools/). After you install Google Perftools, you can produce the same binary as we use at Twitter with these commands for configuration: export CFLAGS='-O2 -g -Wall -fPIC -fno-builtin-malloc \ -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free \ -fno-stack-protector' export LIBS='-ltcmalloc_minimal' ./configure --disable-pthread --disable-shared --disable-ucontext Environment variables ===================== MRI's memory management could be configured using environment variables. Kiji preserves this approach, although the set of available variables is different. Memory sizing variables ----------------------- * `RUBY_GC_HEAP_SIZE=number` is the size, in object slots, of each heap slab. Kiji does away with increasing slab sizes, and heap is always allocated in same increments. One heap object slot is 40 bytes in the current version. Default value is 32768, or (calculating with a 40 byte slot) 1280KiB. * `RUBY_GC_EDEN_HEAPS=number` is the target size of the eden heap, in heap slabs. The runtime starts up with a single allocated heap slab, and whenever it fills up and is collected, adds a new one until it reaches the target size. This gradual allocation lessens the memory fragmentation within the heap slabs. Once it reached the target size, it will never shrink below it. It will grow above it if it needs to, but those heap slabs allocated above the target size will be released when they become vacant. Default value is 24, which, if used with default slab size, gives the target eden heap size of 30MB. * `RUBY_GC_LONGLIFE_LAZINESS=0..1` is the "laziness" factor used to govern the allocation strategy of the longlife heap slabs. It is a decimal value between 0 and 1 denoting a ratio. After a longlife GC, if the proportion of empty object slots to total object slots is higher than this setting, the runtime will release vacant heap slabs. Also, if the proportion is higher than this setting, then the runtime will allocate a new longlife heap slab. Default value is 0.05, corresponding to 5%. GC debugging variables ---------------------- The following settings can be used to produce diagnostic output from the garbage collector: * `RUBY_GC_DEBUG=1` turns GC debug log output on. * `RUBY_GC_DATA_FILE=path/to/file` specifies the file where GC debug output is written. Defaults to stderr. Advanced GC debugging variables ------------------------------- There are some advanced GC debugging options too, but in order for them to work, you must build a debug version of the executable. To do that, pass the `--enable-gc-debug` flag to `./configure`. With such an executable, in conjunction with `RUBY_GC_DEBUG=1` you can use the following environment variables: * `RUBY_GC_DEBUG_SUMMARY=1` will print summary statistics about every GC and a histograms of types of objects that remained alive and were freed in the GC log. * `RUBY_GC_DEBUG_DUMP=1` will write files with detailed allocation information: what objects and how many of them were allocated at a particular location in the program (with full backtrace - locations invoked through different paths are distinguished). The files are overwritten after each GC cycle. By default, the files are: * `/tmp/rb_gc_debug_objects.eden.freed.txt`, * `/tmp/rb_gc_debug_objects.eden.live.txt`, * `/tmp/rb_gc_debug_objects.longlife.freed.txt`, and * `/tmp/rb_gc_debug_objects.longlife.live.txt`. * `RUBY_GC_DUMP_FILE_PATTERN=c-printf-pattern` specifies a C printf() compliant pattern for naming the allocation tracing files. By default, it is `/tmp/rb_gc_debug_objects.%s.%s.txt`. The output of `RUBY_GC_DEBUG_DUMP` is fairly verbose, but you can easily post-process it. We ourselves use the following UNIX command line pipe to summarize the traces, sort them, and take the top few entries: cat /tmp/rb_gc_debug_objects.eden.live.txt | awk 'BEGIN {} { sums[$2," ", $3, " ", $4, " ", $5, " ", $6, " ", $7, " ", $8] += $1 } END { for (i in sums) { print sums[i], i } }' | sort -rni | head -n 30 | ruby -e "STDIN.readlines.each {|l| puts l.split}" GC stressing variables ---------------------- Finally, there are some variables that force the GC into a very non-economical, highly-stressing behavior. We used them internally to diagnose bugs within the memory management (or, alternatively, to reasonably assure ourselves there are none). You probably will not use them, but they're still there in the unlikely case you need them (i.e. to reproduce a bug). These variables also only work in an `--enable-gc-debug` build, but they do not need `RUBY_GC_DEBUG=1`, as they do not produce diagnostic output. * `RUBY_GC_DEBUG_LONGLIFE_DISABLE=1` turns off longlife heap, effectively reestablishing the MRI's single heap. Useful to measure the performance difference between having and not having a longlife heap, as well as for ruling out that some undesired behavior is due to using longlife heap. * `RUBY_GC_DEBUG_STRESS=1` runs full GC (both longlife and eden) after each allocation. Extremely heavy. * `RUBY_GC_DEBUG_ALWAYS_MARK=1` marking the eden is allowed to follow edges into the longlife heap (ordinarily, it stops there). Very obscure and unlikely to ever be needed by anyone. New APIs ======== Kiji exposes few new APIs: * `ObjectSpace.allocated_objects` is the number of objects allocated since the Ruby VM started up - it only increases. Objects have the following two new properties: * `Object.moved?` is true if an object is on the longlife heap, or if its members (if it is a hash or array) are strings that have been moved to the longlife heap. * `Object.longlived?` is true if the object is on the longlife heap. Executables built with `--enable-gc-debug` expose the following APIs: * `GC.exorcise` cleans ghost references from the call stack. Call stack is not by default wiped when methods return, causing some objects pointed to from it to be retained longer than they should. * `GC.stress` returns whether full GCs run after every allocation * `GC.stress=` sets whether full GCs run after every allocation. Its default value comes from the `RUBY_GC_DEBUG_STRESS` variable. * `GC.log(msg)` writes a message to the GC log file. ================================================ FILE: README.EXT ================================================ .\" README.EXT - -*- Text -*- created at: Mon Aug 7 16:45:54 JST 1995 This document explains how to make extension libraries for Ruby. 1. Basic knowledge In C, variables have types and data do not have types. In contrast, Ruby variables do not have a static type, and data themselves have types, so data will need to be converted between the languages. Data in Ruby are represented by the C type `VALUE'. Each VALUE data has its data-type. To retrieve C data from a VALUE, you need to: (1) Identify the VALUE's data type (2) Convert the VALUE into C data Converting to the wrong data type may cause serious problems. 1.1 Data-types The Ruby interpreter has the following data types: T_NIL nil T_OBJECT ordinary object T_CLASS class T_MODULE module T_FLOAT floating point number T_STRING string T_REGEXP regular expression T_ARRAY array T_FIXNUM Fixnum(31bit integer) T_HASH associative array T_STRUCT (Ruby) structure T_BIGNUM multi precision integer T_FILE IO T_TRUE true T_FALSE false T_DATA data T_SYMBOL symbol In addition, there are several other types used internally: T_ICLASS T_MATCH T_UNDEF T_VARMAP T_SCOPE T_NODE Most of the types are represented by C structures. 1.2 Check Data Type of the VALUE The macro TYPE() defined in ruby.h shows the data type of the VALUE. TYPE() returns the constant number T_XXXX described above. To handle data types, your code will look something like this: switch (TYPE(obj)) { case T_FIXNUM: /* process Fixnum */ break; case T_STRING: /* process String */ break; case T_ARRAY: /* process Array */ break; default: /* raise exception */ rb_raise(rb_eTypeError, "not valid value"); break; } There is the data-type check function void Check_Type(VALUE value, int type) which raises an exception if the VALUE does not have the type specified. There are also faster check macros for fixnums and nil. FIXNUM_P(obj) NIL_P(obj) 1.3 Convert VALUE into C data The data for type T_NIL, T_FALSE, T_TRUE are nil, true, false respectively. They are singletons for the data type. The T_FIXNUM data is a 31bit length fixed integer (63bit length on some machines), which can be converted to a C integer by using the FIX2INT() macro. There is also NUM2INT() which converts any Ruby numbers into C integers. The NUM2INT() macro includes a type check, so an exception will be raised if the conversion failed. NUM2DBL() can be used to retrieve the double float value in the same way. In version 1.7 or later it is recommended that you use the new macros StringValue() and StringValuePtr() to get a char* from a VALUE. StringValue(var) replaces var's value with the result of "var.to_str()". StringValuePtr(var) does same replacement and returns char* representation of var. These macros will skip the replacement if var is a String. Notice that the macros take only the lvalue as their argument, to change the value of var in place. In version 1.6 or earlier, STR2CSTR() was used to do the same thing but now it is deprecated in version 1.7, because STR2CSTR() has a risk of a dangling pointer problem in the to_str() impliclit conversion. Other data types have corresponding C structures, e.g. struct RArray for T_ARRAY etc. The VALUE of the type which has the corresponding structure can be cast to retrieve the pointer to the struct. The casting macro will be of the form RXXXX for each data type; for instance, RARRAY(obj). See "ruby.h". For example, `RSTRING(str)->len' is the way to get the size of the Ruby String object. The allocated region can be accessed by `RSTRING(str)->ptr'. For arrays, use `RARRAY(ary)->len' and `RARRAY(ary)->ptr' respectively. Notice: Do not change the value of the structure directly, unless you are responsible for the result. This ends up being the cause of interesting bugs. 1.4 Convert C data into VALUE To convert C data to Ruby values: * FIXNUM left shift 1 bit, and turn on LSB. * Other pointer values cast to VALUE. You can determine whether a VALUE is pointer or not by checking its LSB. Notice Ruby does not allow arbitrary pointer values to be a VALUE. They should be pointers to the structures which Ruby knows about. The known structures are defined in . To convert C numbers to Ruby values, use these macros. INT2FIX() for integers within 31bits. INT2NUM() for arbitrary sized integer. INT2NUM() converts an integer into a Bignum if it is out of the FIXNUM range, but is a bit slower. 1.5 Manipulating Ruby data As I already mentioned, it is not recommended to modify an object's internal structure. To manipulate objects, use the functions supplied by the Ruby interpreter. Some (not all) of the useful functions are listed below: String functions rb_str_new(const char *ptr, long len) Creates a new Ruby string. rb_str_new2(const char *ptr) Creates a new Ruby string from a C string. This is equivalent to rb_str_new(ptr, strlen(ptr)). rb_tainted_str_new(const char *ptr, long len) Creates a new tainted Ruby string. Strings from external data sources should be tainted. rb_tainted_str_new2(const char *ptr) Creates a new tainted Ruby string from a C string. rb_str_cat(VALUE str, const char *ptr, long len) Appends len bytes of data from ptr to the Ruby string. Array functions rb_ary_new() Creates an array with no elements. rb_ary_new2(long len) Creates an array with no elements, allocating internal buffer for len elements. rb_ary_new3(long n, ...) Creates an n-element array from the arguments. rb_ary_new4(long n, VALUE *elts) Creates an n-element array from a C array. rb_ary_push(VALUE ary, VALUE val) rb_ary_pop(VALUE ary) rb_ary_shift(VALUE ary) rb_ary_unshift(VALUE ary, VALUE val) Array operations. The first argument to each functions must be an array. They may dump core if other types are given. 2. Extending Ruby with C 2.1 Addding new features to Ruby You can add new features (classes, methods, etc.) to the Ruby interpreter. Ruby provides APIs for defining the following things: * Classes, Modules * Methods, Singleton Methods * Constants 2.1.1 Class/module definition To define a class or module, use the functions below: VALUE rb_define_class(const char *name, VALUE super) VALUE rb_define_module(const char *name) These functions return the newly created class or module. You may want to save this reference into a variable to use later. To define nested classes or modules, use the functions below: VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super) VALUE rb_define_module_under(VALUE outer, const char *name) 2.1.2 Method/singleton method definition To define methods or singleton methods, use these functions: void rb_define_method(VALUE klass, const char *name, VALUE (*func)(), int argc) void rb_define_singleton_method(VALUE object, const char *name, VALUE (*func)(), int argc) The `argc' represents the number of the arguments to the C function, which must be less than 17. But I doubt you'll need that many. If `argc' is negative, it specifies the calling sequence, not number of the arguments. If argc is -1, the function will be called as: VALUE func(int argc, VALUE *argv, VALUE obj) where argc is the actual number of arguments, argv is the C array of the arguments, and obj is the receiver. If argc is -2, the arguments are passed in a Ruby array. The function will be called like: VALUE func(VALUE obj, VALUE args) where obj is the receiver, and args is the Ruby array containing actual arguments. There are two more functions to define methods. One is to define private methods: void rb_define_private_method(VALUE klass, const char *name, VALUE (*func)(), int argc) The other is to define module functions, which are private AND singleton methods of the module. For example, sqrt is the module function defined in Math module. It can be called in the following way: Math.sqrt(4) or include Math sqrt(4) To define module functions, use: void rb_define_module_function(VALUE module, const char *name, VALUE (*func)(), int argc) Oh, in addition, function-like methods, which are private methods defined in the Kernel module, can be defined using: void rb_define_global_function(const char *name, VALUE (*func)(), int argc) To define an alias for the method, void rb_define_alias(VALUE module, const char* new, const char* old); To define and undefine the `allocate' class method, void rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE klass)); void rb_undef_alloc_func(VALUE klass); func have to take the klass as the argument and return a newly allocated instance. This instance should be empty as possible, without any expensive (including external) resources. 2.1.3 Constant definition We have 2 functions to define constants: void rb_define_const(VALUE klass, const char *name, VALUE val) void rb_define_global_const(const char *name, VALUE val) The former is to define a constant under specified class/module. The latter is to define a global constant. 2.2 Use Ruby features from C There are several ways to invoke Ruby's features from C code. 2.2.1 Evaluate Ruby Programs in a String The easiest way to use Ruby's functionality from a C program is to evaluate the string as Ruby program. This function will do the job: VALUE rb_eval_string(const char *str) Evaluation is done under the current context, thus current local variables of the innermost method (which is defined by Ruby) can be accessed. 2.2.2 ID or Symbol You can invoke methods directly, without parsing the string. First I need to explain about ID. ID is the integer number to represent Ruby's identifiers such as variable names. The Ruby data type corresponding to ID is Symbol. It can be accessed from Ruby in the form: :Identifier You can get the ID value from a string within C code by using rb_intern(const char *name) You can retrieve ID from Ruby object (Symbol or String) given as an argument by using rb_to_id(VALUE symbol) You can convert C ID to Ruby Symbol by using VALUE ID2SYM(ID id) and to convert Ruby Symbol object to ID, use ID SYM2ID(VALUE symbol) 2.2.3 Invoke Ruby method from C To invoke methods directly, you can use the function below VALUE rb_funcall(VALUE recv, ID mid, int argc, ...) This function invokes a method on the recv, with the method name specified by the symbol mid. 2.2.4 Accessing the variables and constants You can access class variables and instance variables using access functions. Also, global variables can be shared between both environments. There's no way to access Ruby's local variables. The functions to access/modify instance variables are below: VALUE rb_ivar_get(VALUE obj, ID id) VALUE rb_ivar_set(VALUE obj, ID id, VALUE val) id must be the symbol, which can be retrieved by rb_intern(). To access the constants of the class/module: VALUE rb_const_get(VALUE obj, ID id) See 2.1.3 for defining new constant. 3. Information sharing between Ruby and C 3.1 Ruby constants that C can be accessed from C The following Ruby constants can be referred from C. Qtrue Qfalse Boolean values. Qfalse is false in C also (i.e. 0). Qnil Ruby nil in C scope. 3.2 Global variables shared between C and Ruby Information can be shared between the two environments using shared global variables. To define them, you can use functions listed below: void rb_define_variable(const char *name, VALUE *var) This function defines the variable which is shared by both environments. The value of the global variable pointed to by `var' can be accessed through Ruby's global variable named `name'. You can define read-only (from Ruby, of course) variables using the function below. void rb_define_readonly_variable(const char *name, VALUE *var) You can defined hooked variables. The accessor functions (getter and setter) are called on access to the hooked variables. void rb_define_hooked_variable(constchar *name, VALUE *var, VALUE (*getter)(), void (*setter)()) If you need to supply either setter or getter, just supply 0 for the hook you don't need. If both hooks are 0, rb_define_hooked_variable() works just like rb_define_variable(). void rb_define_virtual_variable(const char *name, VALUE (*getter)(), void (*setter)()) This function defines a Ruby global variable without a corresponding C variable. The value of the variable will be set/get only by hooks. The prototypes of the getter and setter functions are as follows: (*getter)(ID id, void *data, struct global_entry* entry); (*setter)(VALUE val, ID id, void *data, struct global_entry* entry); 3.3 Encapsulate C data into a Ruby object To wrap and objectify a C pointer as a Ruby object (so called DATA), use Data_Wrap_Struct(). Data_Wrap_Struct(klass, mark, free, ptr) Data_Wrap_Struct() returns a created DATA object. The klass argument is the class for the DATA object. The mark argument is the function to mark Ruby objects pointed by this data. The free argument is the function to free the pointer allocation. If this is -1, the pointer will be just freed. The functions mark and free will be called from garbage collector. You can allocate and wrap the structure in one step. Data_Make_Struct(klass, type, mark, free, sval) This macro returns an allocated Data object, wrapping the pointer to the structure, which is also allocated. This macro works like: (sval = ALLOC(type), Data_Wrap_Struct(klass, mark, free, sval)) Arguments klass, mark, and free work like their counterparts in Data_Wrap_Struct(). A pointer to the allocated structure will be assigned to sval, which should be a pointer of the type specified. To retrieve the C pointer from the Data object, use the macro Data_Get_Struct(). Data_Get_Struct(obj, type, sval) A pointer to the structure will be assigned to the variable sval. See the example below for details. 4. Example - Creating dbm extension OK, here's the example of making an extension library. This is the extension to access DBMs. The full source is included in the ext/ directory in the Ruby's source tree. (1) make the directory % mkdir ext/dbm Make a directory for the extension library under ext directory. (2) design the library You need to design the library features, before making it. (3) write C code. You need to write C code for your extension library. If your library has only one source file, choosing ``LIBRARY.c'' as a file name is preferred. On the other hand, in case your library has multiple source files, avoid choosing ``LIBRARY.c'' for a file name. It may conflict with an intermediate file ``LIBRARY.o'' on some platforms. Ruby will execute the initializing function named ``Init_LIBRARY'' in the library. For example, ``Init_dbm()'' will be executed when loading the library. Here's the example of an initializing function. -- Init_dbm() { /* define DBM class */ cDBM = rb_define_class("DBM", rb_cObject); /* DBM includes Enumerate module */ rb_include_module(cDBM, rb_mEnumerable); /* DBM has class method open(): arguments are received as C array */ rb_define_singleton_method(cDBM, "open", fdbm_s_open, -1); /* DBM instance method close(): no args */ rb_define_method(cDBM, "close", fdbm_close, 0); /* DBM instance method []: 1 argument */ rb_define_method(cDBM, "[]", fdbm_fetch, 1); : /* ID for a instance variable to store DBM data */ id_dbm = rb_intern("dbm"); } -- The dbm extension wraps the dbm struct in the C environment using Data_Make_Struct. -- struct dbmdata { int di_size; DBM *di_dbm; }; obj = Data_Make_Struct(klass, struct dbmdata, 0, free_dbm, dbmp); -- This code wraps the dbmdata structure into a Ruby object. We avoid wrapping DBM* directly, because we want to cache size information. To retrieve the dbmdata structure from a Ruby object, we define the following macro: -- #define GetDBM(obj, dbmp) {\ Data_Get_Struct(obj, struct dbmdata, dbmp);\ if (dbmp->di_dbm == 0) closed_dbm();\ } -- This sort of complicated macro does the retrieving and close checking for the DBM. There are three kinds of way to receive method arguments. First, methods with a fixed number of arguments receive arguments like this: -- static VALUE fdbm_delete(obj, keystr) VALUE obj, keystr; { : } -- The first argument of the C function is the self, the rest are the arguments to the method. Second, methods with an arbitrary number of arguments receive arguments like this: -- static VALUE fdbm_s_open(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { : if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) { mode = 0666; /* default value */ } : } -- The first argument is the number of method arguments, the second argument is the C array of the method arguments, and the third argument is the receiver of the method. You can use the function rb_scan_args() to check and retrieve the arguments. For example, "11" means that the method requires at least one argument, and at most receives two arguments. Methods with an arbitrary number of arguments can receive arguments by Ruby's array, like this: -- static VALUE fdbm_indexes(obj, args) VALUE obj, args; { : } -- The first argument is the receiver, the second one is the Ruby array which contains the arguments to the method. ** Notice GC should know about global variables which refer to Ruby's objects, but are not exported to the Ruby world. You need to protect them by void rb_global_variable(VALUE *var) (4) prepare extconf.rb If the file named extconf.rb exists, it will be executed to generate Makefile. extconf.rb is the file for checking compilation conditions etc. You need to put require 'mkmf' at the top of the file. You can use the functions below to check various conditions. have_library(lib, func): check whether library containing function exists. have_func(func, header): check whether function exists have_header(header): check whether header file exists create_makefile(target): generate Makefile The value of the variables below will affect the Makefile. $CFLAGS: included in CFLAGS make variable (such as -O) $CPPFLAGS: included in CPPFLAGS make variable (such as -I, -D) $LDFLAGS: included in LDFLAGS make variable (such as -L) $objs: list of object file names Normally, the object files list is automatically generated by searching source files, but you must define them explicitly if any sources will be generated while building. If a compilation condition is not fulfilled, you should not call ``create_makefile''. The Makefile will not be generated, compilation will not be done. (5) prepare depend (optional) If the file named depend exists, Makefile will include that file to check dependencies. You can make this file by invoking % gcc -MM *.c > depend It's harmless. Prepare it. (6) generate Makefile Try generating the Makefile by: ruby extconf.rb If the library should be installed under vendor_ruby directory instead of site_ruby directory, use --vendor option as follows. ruby extconf.rb --vendor You don't need this step if you put the extension library under the ext directory of the ruby source tree. In that case, compilation of the interpreter will do this step for you. (7) make Type make to compile your extension. You don't need this step either if you have put the extension library under the ext directory of the ruby source tree. (8) debug You may need to rb_debug the extension. Extensions can be linked statically by adding the directory name in the ext/Setup file so that you can inspect the extension with the debugger. (9) done, now you have the extension library You can do anything you want with your library. The author of Ruby will not claim any restrictions on your code depending on the Ruby API. Feel free to use, modify, distribute or sell your program. Appendix A. Ruby source files overview ruby language core class.c error.c eval.c gc.c object.c parse.y variable.c utility functions dln.c regex.c st.c util.c ruby interpreter implementation dmyext.c inits.c main.c ruby.c version.c class library array.c bignum.c compar.c dir.c enum.c file.c hash.c io.c marshal.c math.c numeric.c pack.c prec.c process.c random.c range.c re.c signal.c sprintf.c string.c struct.c time.c Appendix B. Ruby extension API reference ** Types VALUE The type for the Ruby object. Actual structures are defined in ruby.h, such as struct RString, etc. To refer the values in structures, use casting macros like RSTRING(obj). ** Variables and constants Qnil const: nil object Qtrue const: true object(default true value) Qfalse const: false object ** C pointer wrapping Data_Wrap_Struct(VALUE klass, void (*mark)(), void (*free)(), void *sval) Wrap a C pointer into a Ruby object. If object has references to other Ruby objects, they should be marked by using the mark function during the GC process. Otherwise, mark should be 0. When this object is no longer referred by anywhere, the pointer will be discarded by free function. Data_Make_Struct(klass, type, mark, free, sval) This macro allocates memory using malloc(), assigns it to the variable sval, and returns the DATA encapsulating the pointer to memory region. Data_Get_Struct(data, type, sval) This macro retrieves the pointer value from DATA, and assigns it to the variable sval. ** Checking data types TYPE(value) FIXNUM_P(value) NIL_P(value) void Check_Type(VALUE value, int type) void Check_SafeStr(VALUE value) ** Data type conversion FIX2INT(value) INT2FIX(i) NUM2INT(value) INT2NUM(i) NUM2DBL(value) rb_float_new(f) StringValue(value) StringValuePtr(value) StringValueCStr(value) rb_str_new2(s) ** defining class/module VALUE rb_define_class(const char *name, VALUE super) Defines a new Ruby class as a subclass of super. VALUE rb_define_class_under(VALUE module, const char *name, VALUE super) Creates a new Ruby class as a subclass of super, under the module's namespace. VALUE rb_define_module(const char *name) Defines a new Ruby module. VALUE rb_define_module_under(VALUE module, const char *name) Defines a new Ruby module under the module's namespace. void rb_include_module(VALUE klass, VALUE module) Includes module into class. If class already includes it, just ignored. void rb_extend_object(VALUE object, VALUE module) Extend the object with the module's attributes. ** Defining Global Variables void rb_define_variable(const char *name, VALUE *var) Defines a global variable which is shared between C and Ruby. If name contains a character which is not allowed to be part of the symbol, it can't be seen from Ruby programs. void rb_define_readonly_variable(const char *name, VALUE *var) Defines a read-only global variable. Works just like rb_define_variable(), except the defined variable is read-only. void rb_define_virtual_variable(const char *name, VALUE (*getter)(), VALUE (*setter)()) Defines a virtual variable, whose behavior is defined by a pair of C functions. The getter function is called when the variable is referenced. The setter function is called when the variable is set to a value. The prototype for getter/setter functions are: VALUE getter(ID id) void setter(VALUE val, ID id) The getter function must return the value for the access. void rb_define_hooked_variable(const char *name, VALUE *var, VALUE (*getter)(), VALUE (*setter)()) Defines hooked variable. It's a virtual variable with a C variable. The getter is called as VALUE getter(ID id, VALUE *var) returning a new value. The setter is called as void setter(VALUE val, ID id, VALUE *var) GC requires C global variables which hold Ruby values to be marked. void rb_global_variable(VALUE *var) Tells GC to protect these variables. ** Constant Definition void rb_define_const(VALUE klass, const char *name, VALUE val) Defines a new constant under the class/module. void rb_define_global_const(const char *name, VALUE val) Defines a global constant. This is just the same as rb_define_const(cKernal, name, val) ** Method Definition rb_define_method(VALUE klass, const char *name, VALUE (*func)(), int argc) Defines a method for the class. func is the function pointer. argc is the number of arguments. if argc is -1, the function will receive 3 arguments: argc, argv, and self. if argc is -2, the function will receive 2 arguments, self and args, where args is a Ruby array of the method arguments. rb_define_private_method(VALUE klass, const char *name, VALUE (*func)(), int argc) Defines a private method for the class. Arguments are same as rb_define_method(). rb_define_singleton_method(VALUE klass, const char *name, VALUE (*func)(), int argc) Defines a singleton method. Arguments are same as rb_define_method(). rb_scan_args(int argc, VALUE *argv, const char *fmt, ...) Retrieve argument from argc, argv. The fmt is the format string for the arguments, such as "12" for 1 non-optional argument, 2 optional arguments. If `*' appears at the end of fmt, it means the rest of the arguments are assigned to the corresponding variable, packed in an array. ** Invoking Ruby method VALUE rb_funcall(VALUE recv, ID mid, int narg, ...) Invokes a method. To retrieve mid from a method name, use rb_intern(). VALUE rb_funcall2(VALUE recv, ID mid, int argc, VALUE *argv) Invokes a method, passing arguments by an array of values. VALUE rb_eval_string(const char *str) Compiles and executes the string as a Ruby program. ID rb_intern(const char *name) Returns ID corresponding to the name. char *rb_id2name(ID id) Returns the name corresponding ID. char *rb_class2name(VALUE klass) Returns the name of the class. int rb_respond_to(VALUE object, ID id) Returns true if the object responds to the message specified by id. ** Instance Variables VALUE rb_iv_get(VALUE obj, const char *name) Retrieve the value of the instance variable. If the name is not prefixed by `@', that variable shall be inaccessible from Ruby. VALUE rb_iv_set(VALUE obj, const char *name, VALUE val) Sets the value of the instance variable. ** Control Structure VALUE rb_iterate(VALUE (*func1)(), void *arg1, VALUE (*func2)(), void *arg2) Calls the function func1, supplying func2 as the block. func1 will be called with the argument arg1. func2 receives the value from yield as the first argument, arg2 as the second argument. VALUE rb_yield(VALUE val) Evaluates the block with value val. VALUE rb_rescue(VALUE (*func1)(), void *arg1, VALUE (*func2)(), void *arg2) Calls the function func1, with arg1 as the argument. If an exception occurs during func1, it calls func2 with arg2 as the argument. The return value of rb_rescue() is the return value from func1 if no exception occurs, from func2 otherwise. VALUE rb_ensure(VALUE (*func1)(), void *arg1, void (*func2)(), void *arg2) Calls the function func1 with arg1 as the argument, then calls func2 with arg2 if execution terminated. The return value from rb_ensure() is that of func1. ** Exceptions and Errors void rb_warn(const char *fmt, ...) Prints a warning message according to a printf-like format. void rb_warning(const char *fmt, ...) Prints a warning message according to a printf-like format, if $VERBOSE is true. void rb_raise(rb_eRuntimeError, const char *fmt, ...) Raises RuntimeError. The fmt is a format string just like printf(). void rb_raise(VALUE exception, const char *fmt, ...) Raises a class exception. The fmt is a format string just like printf(). void rb_fatal(const char *fmt, ...) Raises a fatal error, terminates the interpreter. No exception handling will be done for fatal errors, but ensure blocks will be executed. void rb_bug(const char *fmt, ...) Terminates the interpreter immediately. This function should be called under the situation caused by the bug in the interpreter. No exception handling nor ensure execution will be done. ** Initialize and Start the Interpreter The embedding API functions are below (not needed for extension libraries): void ruby_init() Initializes the interpreter. void ruby_options(int argc, char **argv) Process command line arguments for the interpreter. void ruby_run() Starts execution of the interpreter. void ruby_script(char *name) Specifies the name of the script ($0). ** Hooks for the Interpreter Events void rb_add_event_hook(rb_event_hook_func_t func, rb_event_t events) Adds a hook function for the specified interpreter events. events should be Or'ed value of: RUBY_EVENT_LINE RUBY_EVENT_CLASS RUBY_EVENT_END RUBY_EVENT_CALL RUBY_EVENT_RETURN RUBY_EVENT_C_CALL RUBY_EVENT_C_RETURN RUBY_EVENT_RAISE RUBY_EVENT_ALL The definition of rb_event_hook_func_t is below: typedef void (*rb_event_hook_func_t)(rb_event_t event, NODE *node, VALUE self, ID id, VALUE klass) int rb_remove_event_hook(rb_event_hook_func_t func) Removes the specified hook function. Appendix C. Functions Available in extconf.rb These functions are available in extconf.rb: have_macro(macro, headers) Checks whether macro is defined with header. Returns true if the macro is defined. have_library(lib, func) Checks whether the library exists, containing the specified function. Returns true if the library exists. find_library(lib, func, path...) Checks whether a library which contains the specified function exists in path. Returns true if the library exists. have_func(func, header) Checks whether func exists with header. Returns true if the function exists. To check functions in an additional library, you need to check that library first using have_library(). have_var(var, header) Checks whether var exists with header. Returns true if the variable exists. To check variables in an additional library, you need to check that library first using have_library(). have_header(header) Checks whether header exists. Returns true if the header file exists. find_header(header, path...) Checks whether header exists in path. Returns true if the header file exists. have_struct_member(type, member, header) Checks whether type has member with header. Returns true if the type is defined and has the member. have_type(type, header, opt) Checks whether type is defined with header. Returns true if the type is defined. check_sizeof(type, header) Checks the size of type in char with header. Returns the size if the type is defined, otherwise nil. create_makefile(target) Generates the Makefile for the extension library. If you don't invoke this method, the compilation will not be done. find_executable(bin, path) Finds command in path, which is File::PATH_SEPARATOR-separated list of directories. If path is nil or omitted, environment varialbe PATH will be used. Returns the path name of the command if it is found, otherwise nil. with_config(withval[, default=nil]) Parses the command line options and returns the value specified by --with-. enable_config(config, *defaults) disable_config(config, *defaults) Parses the command line options for boolean. Returns true if --enable- is given, or false if --disable- is given. Otherwise, yields defaults to the given block and returns the result if it is called with a block, or returns defaults. dir_config(target[, default_dir]) dir_config(target[, default_include, default_lib]) Parses the command line options and adds the directories specified by --with--dir, --with--include, and/or --with--lib to $CFLAGS and/or $LDFLAGS. --with--dir=/path is equivalent to --with--include=/path/include --with--lib=/path/lib. Returns an array of the added directories ([include_dir, lib_dir]). pkg_config(pkg) Obtains the information for pkg by pkg-config command. The actual command name can be overriden by --with-pkg-config command line option. /* * Local variables: * fill-column: 70 * end: */ ================================================ FILE: README.EXT.ja ================================================ .\" README.EXT.ja - -*- Text -*- created at: Mon Aug 7 16:45:54 JST 1995 Rubyγĥ饤֥κޤ 1μ CѿˤϷꡤǡˤϷޤ󡥤Ǥ顤 ȤХݥ󥿤intѿȡͤȤƼ 갷ޤդRubyѿˤϷʤǡ˷ ΰ㤤ΤᡤCRubyߤѴʤСߤ ǡ򥢥Ǥޤ RubyΥǡVALUEȤCηɽޤVALUEΥǡ ϤΥǡפʬΤäƤޤΥǡפ Τϥǡ(֥)μºݤι¤̣ƤơRuby Υ饹ȤϤޤäΤǤ VALUECˤȤäựΤǡФˤ (1) VALUEΥǡפΤ (2) VALUECΥǡѴ ξɬפǤ(1)˺ȴְäǡѴԤ ơǰץबcore dumpޤ 1.1 ǡ Rubyˤϥ桼ȤǽΤʲΥפޤ T_NIL nil T_OBJECT ̾Υ֥ T_CLASS 饹 T_MODULE ⥸塼 T_FLOAT ư T_STRING ʸ T_REGEXP ɽ T_ARRAY T_FIXNUM Fixnum(31bitĹ) T_HASH Ϣ T_STRUCT (Ruby)¤ T_BIGNUM ¿Ĺ T_FILE T_TRUE T_FALSE T_DATA ǡ T_SYMBOL ܥ ¾ѤƤʲΥפޤ T_ICLASS T_MATCH T_UNDEF T_VARMAP T_SCOPE T_NODE ۤȤɤΥפCι¤ΤǼƤޤ 1.2 VALUEΥǡפå ruby.hǤTYPE()ȤޥƤơVALUEΥǡ פΤ뤳ȤޤTYPE()ޥϾǾҲ𤷤T_XXXX η֤ޤVALUEΥǡפ˱ƽ ˤϡTYPE()ͤʬ뤳Ȥˤʤޤ switch (TYPE(obj)) { case T_FIXNUM: /* FIXNUMν */ break; case T_STRING: /* ʸν */ break; case T_ARRAY: /* ν */ break; default: /* 㳰ȯ */ rb_raise(rb_eTypeError, "not valid value"); break; } ȥǡפåơʤ㳰ȯ ؿѰդƤޤ void Check_Type(VALUE value, int type) δؿvaluetype̵С㳰ȯޤ Ϳ줿VALUEΥǡפɤå 뤿ˤϡδؿȤޤ FIXNUMNIL˴ؤƤϤ®Ƚ̥ޥѰդƤޤ FIXNUM_P(obj) NIL_P(obj) 1.3 VALUECΥǡѴ ǡפT_NIL, T_FALSE, T_TRUEǤǡϤ줾 nil, false, trueǤΥǡפΥ֥ȤϤҤ ĤĤ¸ߤޤ ǡפT_FIXNUMλ31bitΥ FIXNUMCѴ뤿ˤϥޥFIX2INT()פ ޤ줫顤FIXNUM˸¤餺RubyΥǡѴ NUM2INT()פȤޥޤΥޥϥǡ פΥå̵ǻȤޤ(ѴǤʤˤ㳰 ȯ)Ʊͤ˥å̵ǻȤѴޥdouble ФNUM2DBL()פޤ char* Ф硢version 1.6 ǤϡSTR2CSTR()פ ޥȤäƤޤ to_str() ˤۤ Ѵ̤ GC ǽ뤿ᡢversion 1.7 ʹߤǤ obsolete Ȥʤꡢ StringValue() StringValuePtr() Ȥ侩ƤޤStringValue(var) var String Ǥв⤻Ǥʤ var var.to_str() η̤ ֤ޥStringValuePtr(var) Ʊͤ var ֤ Ƥ var ʸɽФ char* ֤ޥǤvar Ƥľ֤Τǡvar lvalue Ǥɬפ ޤ ʳΥǡפбCι¤Τޤб 빽¤ΤΤVALUEϤΤޤޥ㥹(Ѵ)й¤Τ ݥ󥿤ѴǤޤ ¤Τϡstruct RXxxxxפȤ̾ruby.hƤ 㤨ʸϡstruct RStringפǤºݤ˻Ȥǽ Τʸ󤯤餤Ȼפޤ ruby.hǤϹ¤Τإ㥹ȤޥRXXXXX()(ʸ ˤ)Ȥ̾󶡤Ƥޤ(: RSTRING()) 㤨СʸstrĹ뤿ˤϡRSTRING(str)->lenפ ʸstrchar*Ȥ뤿ˤϡRSTRING(str)->ptr Ȥޤξˤϡ줾RARRAY(ary)->lenס RARRAY(ary)->ptrפȤʤޤ Rubyι¤Τľܥ˵ĤʤФʤʤ Ȥϡʸι¤ΤȤϻȤǡľѹ ʤȤǤľѹ硤֥ȤƤ Ȥʤʤäơפ̥Хθˤʤޤ 1.4 CΥǡVALUEѴ VALUEμºݤι¤ * FIXNUMξ 1bitեȤơLSBΩƤ롥 * ¾Υݥ󥿤ξ ΤޤVALUE˥㥹Ȥ롥 ȤʤäƤޤäơLSBåVALUEFIXNUM 狼櫓Ǥ(ݥ󥿤LSBΩäƤʤȤꤷ ) Ǥ顤FIXNUMʳRubyΥ֥Ȥι¤ΤñVALUE ˥㥹ȤVALUEѴޤǤդι¤ ΤVALUE˥㥹Ƚ櫓ǤϤޤ󡥥㥹Ȥ RubyΤäƤ빽¤(ruby.hƤstruct RXxxx Τ)Ǥ FIXNUM˴ؤƤѴޥͳɬפޤC VALUEѴޥϰʲΤΤޤɬפ˱ ƻȤʬƤ INT2FIX() Ȥ31bit˼ޤ뼫 INT2NUM() ǤդVALUE INT2NUM()FIXNUMϰϤ˼ޤʤ硤BignumѴ Ƥޤ(٤) 1.5 RubyΥǡ Ҥ٤̤ꡤRubyι¤Τ򥢥Ƥι ԤȤϴޤ󡥤ǡRubyΥǡˤ RubyѰդƤؿѤƤ ǤϤäȤȤǤʸ/ ؿ򤢤ޤ(ǤϤʤǤ) ʸФؿ rb_str_new(const char *ptr, long len) Rubyʸ롥 rb_str_new2(const char *ptr) Cʸ󤫤Rubyʸ롥δؿεǽ rb_str_new(ptr, strlen(ptr))ƱǤ롥 rb_tainted_str_new(const char *ptr, long len) ޡղä줿Rubyʸ롥 Υǡ˴Ťʸˤϱޡղä٤ Ǥ롥 rb_tainted_str_new2(const char *ptr) Cʸ󤫤ޡղä줿Rubyʸ롥 rb_str_cat(VALUE str, const char *ptr, long len) RubyʸstrlenХȤʸptrɲä롥 Фؿ rb_ary_new() Ǥ0롥 rb_ary_new2(long len) Ǥ0롥lenʬΰ򤢤餫 ƤƤ rb_ary_new3(long n, ...) ǻꤷnǤޤ롥 rb_ary_new4(long n, VALUE *elts) ͿnǤ롥 rb_ary_push(VALUE ary, VALUE val) rb_ary_pop(VALUE ary) rb_ary_shift(VALUE ary) rb_ary_unshift(VALUE ary, VALUE val) ArrayƱ̾Υ᥽åɤƱƯ򤹤ؿ1ɬ ǤʤФʤʤ 2RubyεǽȤ ŪRubyǽ񤱤뤳ȤCǤ񤱤ޤRubyΤΤCǵ ҤƤǤ顤ȤʤǤɡ Rubyγĥ˻ȤȤ¿ͽ¬뵡ǽ濴˾ 𤷤ޤ 2.1 Ruby˵ǽɲä Ruby󶡤ƤؿȤRuby󥿥ץ꥿˿ǽ ɲä뤳ȤǤޤRubyǤϰʲεǽɲäؿ 󶡤Ƥޤ * 饹⥸塼 * ᥽åɡðۥ᥽åɤʤ * ǤϽ˾Ҳ𤷤ޤ 2.1.1 饹/⥸塼 饹⥸塼뤿ˤϡʲδؿȤޤ VALUE rb_define_class(const char *name, VALUE super) VALUE rb_define_module(const char *name) δؿϿ줿饹⥸塼֤ޤ ᥽åɤˤͤɬפʤΤǡۤȤɤξ ͤѿ˳ǼƤɬפǤ礦 饹⥸塼¾Υ饹˥ͥȤ ϰʲδؿȤޤ VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super) VALUE rb_define_module_under(VALUE outer, const char *name) 2.1.2 ᥽å/ðۥ᥽å ᥽åɤðۥ᥽åɤˤϰʲδؿȤޤ void rb_define_method(VALUE klass, const char *name, VALUE (*func)(), int argc) void rb_define_singleton_method(VALUE object, const char *name, VALUE (*func)(), int argc) ǰΤȡðۥ᥽åɡפȤϡΥ֥ ȤФƤͭʥ᥽åɤǤRubyǤϤ褯Smalltalkˤ 륯饹᥽åɤȤơ饹Фðۥ᥽åɤȤ ޤ δؿ argcȤCδؿϤο( )ޤargc0ʾλϴؿ˰Ϥο ̣ޤ16İʾΰϻȤޤ(פޤ͡ ʤ)ºݤδؿˤƬΰȤselfͿޤ ǡꤷ1¿ĤȤˤʤޤ argcλϰοǤϤʤꤷȤˤʤޤ argc-1λϰϤޤargc-2λϰ RubyȤϤޤ ᥽åɤؿϤ⤦ĤޤҤȤĤprivate åɤؿǡrb_define_method()ƱǤ void rb_define_private_method(VALUE klass, const char *name, VALUE (*func)(), int argc) private᥽åɤȤϴؿǤƤӽФȤνʤ᥽ ɤǤ ⤦ҤȤĤϥ⥸塼ؿΤǤ⥸塼ؿ Ȥϥ⥸塼ðۥ᥽åɤǤꡤƱprivate᥽åɤ ⤢ΤǤ򤢤Math⥸塼sqrt()ʤɤ ޤΥ᥽åɤ Math.sqrt(4) ȤǤ include Math sqrt(4) ȤǤȤޤ⥸塼ؿؿϰʲ ̤Ǥ void rb_define_module_function(VALUE module, const char *name, VALUE (*func)(), int argc) ؿŪ᥽å(Kernel⥸塼private method)뤿 δؿϰʲ̤Ǥ void rb_define_global_function(const char *name, VALUE (*func)(), int argc) ᥽åɤ̾뤿δؿϰʲ̤Ǥ void rb_define_alias(VALUE module, const char* new, const char* old); 饹᥽åallocateꤹ뤿δؿ ʲ̤Ǥ void rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE klass)); void rb_undef_alloc_func(VALUE klass); funcϥ饹ȤƼäơƤ줿 󥹤֤ʤƤϤʤޤ󡣤Υ󥹥󥹤ϡ ʤɤޤޤʤǤֶפΤޤޤˤƤۤ 褤Ǥ礦 2.1.3 ĥ饤֥꤬ɬפϤ餫Ƥɤ Ǥ礦ؿĤޤ void rb_define_const(VALUE klass, const char *name, VALUE val) void rb_define_global_const(const char *name, VALUE val) ԤΥ饹/⥸塼°Ρ ԤϥХΤǤ 2.2 RubyεǽCƤӽФ ˡ1.5 RubyΥǡ٤ǰҲ𤷤褦ʴؿ ȤСRubyεǽ¸ƤؿľܸƤӽФȤ ޤ # Τ褦ʴؿΰɽϤޤΤȤޤ󡥥 # 뤷ʤǤ͡ ʳˤRubyεǽƤӽФˡϤĤޤ 2.2.1 RubyΥץeval CRubyεǽƤӽФäȤñˡȤơʸ Ϳ줿RubyΥץɾʲδؿޤ VALUE rb_eval_string(const char *str) ɾϸߤδĶǹԤޤĤޤꡤߤΥѿ ʤɤѤޤ 2.2.2 IDޤϥܥ CʸͳRubyΥ᥽åɤƤӽФȤǤ ˡRuby󥿥ץ꥿ǥ᥽åɤѿ̾ꤹ ˻ȤƤIDˤĤƤޤ礦 IDȤѿ̾᥽å̾ɽǤRubyǤIDб ֥ȤȤƥܥ(Symbol)ꡤ :̻ ǥǤޤC餳뤿ˤϴؿ rb_intern(const char *name) ȤޤRubyȤͿ줿ܥ(ޤʸ )IDѴˤϰʲδؿȤޤ rb_to_id(VALUE symbol) ID饷ܥ뤿ˤϰʲΥޥȤޤ VALUE ID2SYM(ID id) ܥ뤫ID뤿ˤϰʲΥޥȤޤ ID SYM2ID(VALUE symbol) 2.2.3 CRubyΥ᥽åɤƤӽФ CʸͳRubyΥ᥽åɤƤӽФˤϰʲ δؿȤޤ VALUE rb_funcall(VALUE recv, ID mid, int argc, ...) δؿϥ֥recvmidǻꤵ᥽åɤƤӽ ޤ¾˰λλ㤦ʲδؿ⤢ޤ VALUE rb_funcall2(VALUE recv, ID mid, int argc, VALUE *argv) VALUE rb_apply(VALUE recv, ID mid, VALUE args) applyˤϰȤRubyͿޤ 2.2.4 ѿ/򻲾/ CؿȤäƻȡǤΤϡ󥹥 ǤѿϰΤΤCѿȤƥǤ ޤѿ򻲾ȤˡϸƤޤ ֥ȤΥ󥹥ѿ򻲾ȡؿϰʲ Ǥ VALUE rb_ivar_get(VALUE obj, ID id) VALUE rb_ivar_set(VALUE obj, ID id, VALUE val) idrb_intern()ΤȤäƤ 򻲾ȤˤϰʲδؿȤäƤ VALUE rb_const_get(VALUE obj, ID id) 򿷤뤿ˤϡ2.1.3 ٤ǾҲ ƤؿȤäƤ 3RubyCȤξͭ CRubyδ֤ǾͭˡˤĤƲ⤷ޤ 3.1 C黲ȤǤRuby ʲRubyCΥ٥뤫黲ȤǤޤ Qtrue Qfalse ͡QfalseCǤ⵶Ȥߤʤޤ(Ĥޤ0) Qnil C줫鸫nilס 3.2 CRubyǶͭѿ CRubyѿȤäƾͭǤޤͭǤ ѿˤϤĤμबޤΤʤǤäȤɤȤ ȻפΤrb_define_variable()Ǥ void rb_define_variable(const char *name, VALUE *var) δؿRubyCȤǶͭѿޤѿ̾ `$'ǻϤޤʤˤϼưŪɲäޤѿͤ ȼưŪRubyбѿͤѤޤ ޤRuby¦ϹǤʤѿ⤢ޤread only ѿϰʲδؿޤ void rb_define_readonly_variable(const char *name, VALUE *var) ѿ¾hookĤѿǤޤhookդ ѿϰʲδؿѤޤhookդѿ ͤλȤhookǹԤɬפޤ void rb_define_hooked_variable(const char *name, VALUE *var, VALUE (*getter)(), void (*setter)()) δؿCδؿˤähookΤĤ줿ѿ ѿȤ줿ˤϴؿgetterѿͤåȤ ˤϴؿsetterƤФ롥hookꤷʤgetter setter0ꤷޤ # gettersetter0ʤrb_define_variable()Ʊˤʤ롥 줫顤CδؿˤäƼ¸Rubyѿ ؿޤ void rb_define_virtual_variable(const char *name, VALUE (*getter)(), void (*setter)()) δؿˤä줿RubyѿȤ줿ˤ getterѿͤåȤ줿ˤsetterƤФޤ gettersetterλͤϰʲ̤Ǥ (*getter)(ID id, void *data, struct global_entry* entry); (*setter)(VALUE val, ID id, void *data, struct global_entry* entry); 3.3 CΥǡRuby֥Ȥˤ C줿ǡ(¤)RubyΥ֥ȤȤ 갷礬ꤨޤΤ褦ʾˤϡDataȤ Ruby֥ȤCι¤(ؤΥݥ)򤯤ळȤRuby ֥ȤȤƼ갷褦ˤʤޤ Data֥Ȥƹ¤ΤRuby֥Ȥ˥ץ 뤿ˤϡʲΥޥȤޤ Data_Wrap_Struct(klass, mark, free, ptr) Υޥͤ줿Data֥ȤǤ klassϤData֥ȤΥ饹Ǥptrϥץ벽 Cι¤ΤؤΥݥ󥿤ǤmarkϤι¤ΤRubyΥ֥ ȤؤλȤ˻ȤؿǤΤ褦ʻȤޤޤʤ ˤ0ꤷޤ # Τ褦ʻȤϴޤ freeϤι¤Τ⤦פˤʤä˸ƤФؿǤ ؿ١쥯ƤФޤ줬-1ξϡñ ˳ޤ Cι¤ΤγData֥ȤƱ˹Ԥޥ ưʲΤΤ󶡤Ƥޤ Data_Make_Struct(klass, type, mark, free, sval) Υޥͤ줿Data֥ȤǤ klass, mark, freeData_Wrap_StructƱƯ򤷤ޤtype ϳƤC¤ΤηǤƤ줿¤Τѿsval ޤѿη (type*) Ǥɬפޤ Data֥Ȥݥ󥿤ФΤϰʲΥޥѤ ޤ Data_Get_Struct(obj, type, sval) Cι¤ΤؤΥݥ󥿤ѿsvalޤ DataλȤϤäʬˤΤǡ 򻲾ȤƤ 4 - dbmѥå ޤǤǤȤꤢĥ饤֥ϺϤǤ Rubyextǥ쥯ȥˤǤ˴ޤޤƤdbm饤֥ ʳŪޤ (1) ǥ쥯ȥ % mkdir ext/dbm Ruby 1.1ǤդΥǥ쥯ȥǥʥߥå饤֥ 뤳ȤǤ褦ˤʤޤRubyŪ˥󥯤 RubyŸǥ쥯ȥβextǥ쥯ȥ˳ĥ 饤֥ѤΥǥ쥯ȥɬפޤ̾Ŭ ǹޤ (2) ߷פ ޤʤǤɡɤǽ¸뤫ɤޤ פɬפޤɤʥ饹Ĥ뤫Υ饹ˤ ɤʥ᥽åɤ뤫饹󶡤ʤɤˤĤ߷ ޤ (3) Cɤ ĥ饤֥ΤȤʤCΥ񤭤ޤCΥ ҤȤĤλˤϡ֥饤֥̾.cפ֤ɤǤ礦C Υʣξˤϵդˡ֥饤֥̾.cפȤե ̾򤱤ɬפޤ֥ȥեȥ⥸塼 Ū֥饤֥̾.oפȤե Ȥͤ뤫Ǥ Rubyϳĥ饤֥ɤˡInit_饤֥̾פ ؿưŪ˼¹Ԥޤdbm饤֥ξInit_dbm Ǥδؿǥ饹⥸塼롤᥽åɡʤɤ Ԥޤdbm.cѤޤ -- Init_dbm() { /* DBM饹 */ cDBM = rb_define_class("DBM", rb_cObject); /* DBMEnumerate⥸塼򥤥󥯥롼ɤ */ rb_include_module(cDBM, rb_mEnumerable); /* DBM饹Υ饹᥽åopen(): CǼ */ rb_define_singleton_method(cDBM, "open", fdbm_s_open, -1); /* DBM饹Υ᥽åclose(): Ϥʤ */ rb_define_method(cDBM, "close", fdbm_close, 0); /* DBM饹Υ᥽å[]: 1 */ rb_define_method(cDBM, "[]", fdbm_fetch, 1); : /* DBMǡǼ륤󥹥ѿ̾ΤID */ id_dbm = rb_intern("dbm"); } -- DBM饤֥dbmΥǡб륪֥ȤˤʤϤ 顤CdbmRuby˼ɬפޤ dbm.cǤData_Make_StructʲΤ褦˻ȤäƤޤ -- struct dbmdata { int di_size; DBM *di_dbm; }; obj = Data_Make_Struct(klass, struct dbmdata, 0, free_dbm, dbmp); -- Ǥdbmstruct¤ΤؤΥݥ󥿤Data˥ץ벽Ƥ ޤDBM*ľܥץ벽ʤΤclose()ν ƤΤȤǤ Data֥Ȥdbmstruct¤ΤΥݥ󥿤Ф ˰ʲΥޥȤäƤޤ -- #define GetDBM(obj, dbmp) {\ Data_Get_Struct(obj, struct dbmdata, dbmp);\ if (dbmp->di_dbm == 0) closed_dbm();\ } -- äʣʥޥǤפdbmdata¤ΤΥݥ μФȡcloseƤ뤫ɤΥåޤȤƤ Ǥ DBM饹ˤϤ᥽åɤޤʬह3 μޤҤȤĤϰοΤΤǡ Ƥdelete᥽åɤޤdelete᥽åɤƤ fdbm_delete()ϤΤ褦ˤʤäƤޤ -- static VALUE fdbm_delete(obj, keystr) VALUE obj, keystr; { : } -- οΥפ1self2ʹߤ᥽å ΰȤʤޤ οΤΤCǼΤRubyǼ ΤȤޤdbm饤֥ǡCǼ DBMΥ饹᥽åɤǤopen()ǤƤ fdbm_s_open()ϤʤäƤޤ -- static VALUE fdbm_s_open(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { : if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) { mode = 0666; /* default value */ } : } -- Υפδؿ1Ϳ줿ο2Ϳ 줿äƤˤʤޤself3ȤͿ ޤ Ϳ줿Ϥ뤿δؿopen()ǤȤ Ƥrb_scan_args()Ǥ3˻ꤷեޥåȤ 4ѿʹߤ˻ꤷѿͤƤޤ եޥåȤϡ1ʸܤάǤʤο2ʸܤ άǤο3ʸܤб̵꤬ޤΰ 뤫ɤ򼨤"*"Ǥ2ʸܤ3ʸܤϾάǤ dbm.cǤϡեޥåȤ"11"Ǥ顤Ϻ1 ǡ2ĤޤǵȤ̣ˤʤޤάƤ ѿͤnil(CΥ٥ǤQnil)ˤʤޤ RubyǰΤindexesޤϤ Ǥ -- static VALUE fdbm_indexes(obj, args) VALUE obj, args; { : } -- 1self2RubyǤ ** ջ RubyȶͭϤʤRubyΥ֥ȤǼǽΤ CѿϰʲδؿȤäRuby󥿥ץ꥿ѿ¸ 򶵤ƤƤǤʤGCǥȥ֥򵯤ޤ void rb_global_variable(VALUE *var) (4) extconf.rbѰդ Makefileοˤʤextconf.rbȤե ޤextconf.rbϥ饤֥ΥѥɬפʾΥ ʤɤԤȤŪǤޤ require 'mkmf' extconf.rbƬ֤ޤextconf.rbǤϰʲRuby ȤȤޤ have_library(lib, func): 饤֥¸ߥå have_func(func, header): ؿ¸ߥå have_header(header): إåե¸ߥå create_makefile(target): Makefile ʲѿȤȤǤޤ $CFLAGS: ѥɲŪ˻ꤹե饰(-Oʤ) $CPPFLAGS: ץץåɲŪ˻ꤹե饰(-I-Dʤ) $LDFLAGS: 󥯻ɲŪ˻ꤹե饰(-Lʤ) $objs: 󥯤륪֥ȥե̾Υꥹ ֥ȥեΥꥹȤϡ̾ϥե򸡺 ƼưŪޤmakeǥ褦 Ū˻ꤹɬפޤ 饤֥򥳥ѥ뤹郎·鷺Υ饤֥򥳥 ѥ뤷ʤˤcreate_makefileƤФʤMakefile 줺ѥԤޤ (5) dependѰդ ⤷ǥ쥯ȥdependȤե뤬¸ߤС Makefile¸طåƤޤ % gcc -MM *.c > depend ʤɤǺ뤳Ȥޤä»̵Ǥ礦 (6) Makefile Makefileºݤ뤿ˤ ruby extconf.rb Ȥޤextconf.rb require 'mkmf' ιԤʤˤϥ顼 ˤʤޤΤǡɲä ruby -r mkmf extconf.rb ȤƤ site_ruby ǥ쥯ȥǤʤ vendor_ruby ǥ쥯ȥ˥󥹥ȡ뤹ˤ ʲΤ褦 --vendor ץäƤ ruby extconf.rb --vendor ǥ쥯ȥextʲѰդˤRubyΤmakeλ ưŪMakefileޤΤǡΥƥåפפǤ (7) make ưŪ󥯥饤֥ˤϤξmakeƤ ɬפǤ make install ǥ󥹥ȡ뤵ޤ extʲ˥ǥ쥯ȥѰդϡRubyΥǥ쥯ȥ make¹ԤMakefilemakeɬפˤäƤϤΥ 塼RubyؤΥ󥯤ޤǼưŪ˼¹ԤƤޤ extconf.rb񤭴ʤɤMakefileκɬפʻϤ Rubyǥ쥯ȥmakeƤ ĥ饤֥make installRuby饤֥Υǥ쥯ȥ ˥ԡޤ⤷ĥ饤֥ȶĴƻȤRubyǵ Ҥ줿ץबꡤRuby饤֥֤ˤϡ ĥ饤֥ѤΥǥ쥯ȥβ lib Ȥǥ쥯ȥ ꡤ ĥ .rb Υե֤ƤƱ˥ ȡ뤵ޤ (8) ǥХå ޤǥХåʤưʤǤ礦͡ext/Setup˥ǥ ȥ̾񤯤Ū˥󥯤ΤǥǥХåȤ褦ˤ ޤʬѥ뤬٤ʤޤɡ (9) Ǥ ϤäȤʤꡤʤꡤʤꡤͳˤ ȤRubyκԤϳĥ饤֥˴ؤưڤθ ĥޤ Appendix A. RubyΥɤʬ RubyΥϤĤʬह뤳ȤޤΤ 饤֥ʬϴŪ˳ĥ饤֥Ʊˤʤ ƤޤΥϺޤǤǤۤȤǤ פޤ RubyΥ class.c error.c eval.c gc.c object.c parse.y variable.c 桼ƥƥؿ dln.c regex.c st.c util.c Rubyޥɤμ dmyext.c inits.c main.c ruby.c version.c 饹饤֥ array.c bignum.c compar.c dir.c enum.c file.c hash.c io.c marshal.c math.c numeric.c pack.c prec.c process.c random.c range.c re.c signal.c sprintf.c string.c struct.c time.c Appendix B. ĥѴؿե C줫RubyεǽѤAPIϰʲ̤Ǥ롥 ** VALUE Ruby֥Ȥɽ뷿ɬפ˱ƥ㥹ȤѤ롥 Ȥ߹߷ɽCηruby.h˵ҤƤRǻϤޤ빽¤ ΤǤ롥VALUE򤳤˥㥹Ȥ뤿RǻϤޤ빽¤ ̾ʸˤ̾ΥޥѰդƤ롥 ** ѿ Qnil : nil֥ Qtrue : true֥(Υǥե) Qfalse : false֥ ** CǡΥץ벽 Data_Wrap_Struct(VALUE klass, void (*mark)(), void (*free)(), void *sval) CǤդΥݥ󥿤򥫥ץ벽Ruby֥Ȥ֤ Υݥ󥿤Ruby饢ʤʤäfreeǻꤷ ؿƤФ롥ޤΥݥ󥿤λؤǡ¾Ruby ȤؤƤ硤mark˻ꤹؿǥޡɬ 롥 Data_Make_Struct(klass, type, mark, free, sval) typeΥmallocѿsval塤򥫥ץ 벽ǡ֤ޥ Data_Get_Struct(data, type, sval) datatypeΥݥ󥿤Фѿsvalޥ ** å TYPE(value) FIXNUM_P(value) NIL_P(value) void Check_Type(VALUE value, int type) void Check_SafeStr(VALUE value) ** Ѵ FIX2INT(value) INT2FIX(i) NUM2INT(value) INT2NUM(i) NUM2DBL(value) rb_float_new(f) StringValue(value) StringValuePtr(value) StringValueCStr(value) rb_str_new2(s) ** 饹/⥸塼 VALUE rb_define_class(const char *name, VALUE super) superΥ֥饹ȤƿRuby饹롥 VALUE rb_define_class_under(VALUE module, const char *name, VALUE super) superΥ֥饹ȤƿRuby饹module Ȥ롥 VALUE rb_define_module(const char *name) Ruby⥸塼롥 VALUE rb_define_module_under(VALUE module, const char *name) Ruby⥸塼moduleȤ롥 void rb_include_module(VALUE klass, VALUE module) ⥸塼򥤥󥯥롼ɤ롥classǤmodule򥤥 롼ɤƤˤϲ⤷ʤ(¿ť󥯥롼ɤζػ) void rb_extend_object(VALUE object, VALUE module) ֥Ȥ⥸塼(Ƥ᥽å)dzĥ롥 ** ѿ void rb_define_variable(const char *name, VALUE *var) RubyCȤǶͭ륰Хѿ롥ѿ̾`$' ϤޤʤˤϼưŪɲä롥nameȤRubyμ̻ ȤƵʤʸ(㤨` ')ޤˤRubyץ फϸʤʤ롥 void rb_define_readonly_variable(const char *name, VALUE *var) RubyCȤǶͭread onlyΥХѿ롥 read onlyǤ뤳Ȱʳrb_define_variable()Ʊ void rb_define_virtual_variable(const char *name, VALUE (*getter)(), void (*setter)()) ؿˤäƼ¸Rubyѿ롥ѿȤ줿 ˤgetterѿͤåȤ줿ˤsetterƤФ 롥 void rb_define_hooked_variable(const char *name, VALUE *var, VALUE (*getter)(), void (*setter)()) ؿˤähookΤĤ줿Хѿ롥ѿ Ȥ줿ˤgetterؿͤåȤ줿ˤ setterƤФ롥gettersetter0ꤷˤhook ꤷʤΤƱˤʤ롥 void rb_global_variable(VALUE *var) GCΤᡤRubyץफϥʤ, Ruby Ȥޤѿޡ롥 ** void rb_define_const(VALUE klass, const char *name, VALUE val) 롥 void rb_define_global_const(const char *name, VALUE val) 롥 rb_define_const(rb_cObject, name, val) Ʊ̣ ** ᥽å rb_define_method(VALUE klass, const char *name, VALUE (*func)(), int argc) ᥽åɤ롥argcselfοargc-1λ, ؿˤϰο(selfޤޤʤ)1, 2 ȤͿ(3self)argc-2λ, 1self, 2args(argsϰޤRuby) Ϳ롥 rb_define_private_method(VALUE klass, const char *name, VALUE (*func)(), int argc) private᥽åɤ롥rb_define_method()Ʊ rb_define_singleton_method(VALUE klass, const char *name, VALUE (*func)(), int argc) ðۥ᥽åɤ롥rb_define_method()Ʊ rb_scan_args(int argc, VALUE *argv, const char *fmt, ...) argc, argvͿ줿ʬ򤹤롥fmtɬܰο, ղðο, Ĥΰ뤫ꤹʸ, " *"ȤǤ롥 2 ܤο"*"Ϥ줾ά ǽǤ롥ɬܰĤʤ0ꤹ롥3 ߤѿؤΥݥ󥿤, Ǥѿ˳Ǽ롥 ղðбͿƤʤѿQnil 롥 ** Ruby᥽åɸƤӽФ VALUE rb_funcall(VALUE recv, ID mid, int narg, ...) ᥽åɸƤӽФʸ󤫤mid뤿ˤrb_intern() Ȥ VALUE rb_funcall2(VALUE recv, ID mid, int argc, VALUE *argv) ᥽åɸƤӽФargc, argvϤ VALUE rb_eval_string(const char *str) ʸRubyץȤȤƥѥ롦¹Ԥ롥 ID rb_intern(const char *name) ʸбID֤ char *rb_id2name(ID id) IDбʸ֤(ǥХå) char *rb_class2name(VALUE klass) 饹֤̾(ǥХå)饹̾ʤˤ, ̤ä̾ĥ饹֤̾ int rb_respond_to(VALUE obj, ID id) objidǼ᥽åɤĤɤ֤ ** 󥹥ѿ VALUE rb_iv_get(VALUE obj, const char *name) objΥ󥹥ѿͤ롥`@'ǻϤޤʤ󥹥 ѿ Rubyץफ饢Ǥʤֱ줿ץ ѿˤʤ롥ʸ̾ĥ饹(ޤ ⥸塼)Υ󥹥ѿȤƼƤ롥 VALUE rb_iv_set(VALUE obj, const char *name, VALUE val) objΥ󥹥ѿval˥åȤ롥 ** 湽¤ VALUE rb_iterate(VALUE (*func1)(), VALUE arg1, VALUE (*func2)(), VALUE arg2) func2֥åȤꤷ, func1򥤥ƥ졼ȤƸƤ֡ func1ˤ arg1ȤϤ, func2ˤ1˥ƥ졼 Ϳ줿, 2arg2Ϥ롥 VALUE rb_yield(VALUE val) valͤȤƥƥ졼֥åƤӽФ VALUE rb_rescue(VALUE (*func1)(), VALUE arg1, VALUE (*func2)(), VALUE arg2) ؿfunc1arg1˸ƤӽФfunc1μ¹㳰ȯ ˤ func2arg2ȤƸƤ֡ͤ㳰ȯ ʤäfunc1, 㳰ȯˤfunc2 ͤǤ롥 VALUE rb_ensure(VALUE (*func1)(), VALUE arg1, void (*func2)(), VALUE arg2) ؿfunc1arg1ȤƼ¹Ԥ, ¹Խλ(Ȥ㳰 ȯƤ) func2arg2ȤƼ¹Ԥ롥ͤfunc1 ͤǤ(㳰ȯʤ) ** 㳰顼 void rb_warning(const char *fmt, ...) rb_verboseɸ२顼Ϥ˷ٹɽ롥 printf()Ʊ void rb_raise(rb_eRuntimeError, const char *fmt, ...) RuntimeError㳰ȯ롥printf()Ʊ void rb_raise(VALUE exception, const char *fmt, ...) exceptionǻꤷ㳰ȯ롥fmtʲΰ printf()Ʊ void rb_fatal(const char *fmt, ...) ̿Ū㳰ȯ롥̾㳰ϹԤʤ줺, 󥿡 ץ꥿λ(ensureǻꤵ줿ɤϽλ ¹Ԥ) void rb_bug(const char *fmt, ...) 󥿡ץ꥿ʤɥץΥХǤȯϤΤʤ λƤ֡󥿡ץ꥿ϥפľ˽λ롥 㳰ϰڹԤʤʤ ** Rubyν¹ Ruby򥢥ץꥱˤϰʲΥ󥿥ե Ȥ̾γĥ饤֥ˤɬפʤ void ruby_init() Ruby󥿥ץ꥿νԤʤ void ruby_options(int argc, char **argv) Ruby󥿥ץ꥿Υޥɥ饤νԤʤ void ruby_run() Ruby󥿥ץ꥿¹Ԥ롥 void ruby_script(char *name) RubyΥץ̾($0)ꤹ롥 Appendix C. extconf.rbǻȤؿ extconf.rbǤѲǽʥѥåδؿϰ ̤Ǥ롥 have_macro(macro, headers) إåեheader򥤥󥯥롼ɤƥޥmacro Ƥ뤫ɤå롥ޥƤtrue ֤ have_library(lib, func) ؿfuncƤ饤֥lib¸ߤå롥 饤֥꤬¸ߤtrue֤ find_library(lib, func, path...) ؿfuncƤ饤֥lib¸ߤ -Lpath ɲ ʤå롥饤֥꤬դätrue֤ have_func(func, header) إåեheader򥤥󥯥롼ɤƴؿfunc¸ߤ 롥funcɸǤϥ󥯤ʤ饤֥ΤΤǤ ˤhave_libraryǤΥ饤֥åƤ ؿ¸ߤtrue֤ have_var(var, header) إåեheader򥤥󥯥롼ɤѿvar¸ߤ 롥varɸǤϥ󥯤ʤ饤֥ΤΤǤ ˤhave_libraryǤΥ饤֥åƤ ѿ¸ߤtrue֤ have_header(header) إåե¸ߤå롥إåե뤬¸ߤ true֤ find_header(header, path...) إåեheader¸ߤ -Ipath ɲäʤå 롥إåե뤬դätrue֤ have_struct_member(type, member, header) إåեheader򥤥󥯥롼ɤƷtype˥member ¸ߤ뤫å롥typeƤơmember Ĥtrue֤ have_type(type, header, opt) إåեheader򥤥󥯥롼ɤƷtype¸ߤ뤫 å롥typeƤtrue֤ check_sizeof(type, header) إåեheader򥤥󥯥롼ɤƷtypecharñ̥ Ĵ٤롥typeƤΥ֤ ƤʤȤnil֤ create_makefile(target) ĥ饤֥ѤMakefile롥δؿƤФʤ ФΥ饤֥ϥѥ뤵ʤtargetϥ⥸塼̾ ɽ find_executable(command, path) ޥcommandFile::PATH_SEPARATORǶڤ줿ѥ̾ ꥹpathõpathnilޤϾά줿ϡĶ ѿPATHͤѤ롥¹ԲǽʥޥɤĤä ϥѥޤե̾Ĥʤänil֤ with_config(withval[, default=nil]) ޥɥ饤--with-ǻꤵ줿ץͤ롥 enable_config(config, *defaults) disable_config(config, *defaults) ޥɥ饤--enable-ޤ --disable-ǻꤵ줿ͤ롥 --enable-ꤵƤtrue --disable-ꤵƤfalse֤ ɤꤵƤʤϡ֥åĤǸƤӽФƤ *defaultsyield̡֥åʤʤ*defaults֤ dir_config(target[, default_dir]) dir_config(target[, default_include, default_lib]) ޥɥ饤--with--dir, --with--include, --with--libΤ줫ǻꤵǥ쥯ȥ $CFLAGS $LDFLAGS ɲä롥--with--dir=/path --with--include=/path/include --with--lib=/path/lib Ǥ롥ɲä줿 include ǥ쥯ȥ lib ǥ쥯ȥ ֤ ([include_dir, lib_dir]) pkg_config(pkg) pkg-configޥɤѥåpkgξ롥 pkg-configμºݤΥޥ̾ϡ--with-pkg-configޥ 饤󥪥ץǻǽ /* * Local variables: * fill-column: 60 * end: */ ================================================ FILE: README.ja ================================================ * RubyȤ Rubyϥץ뤫ĶϤʥ֥ȻظץȸǤ RubyϺǽ餫ʥ֥ȻظȤ߷פƤ 顤֥Ȼظץߥ󥰤ڤ˹Ԥ ̾μ³Υץߥ󥰤ǽǤ RubyϥƥȽطǽϤʤɤͥ졤PerlƱ餤 Ǥ˥ץʸˡȡ㳰䥤ƥ졼ʤɤε ˤäơʬ䤹ץߥ󥰤ޤ * RubyĹ + ץʸˡ + ̤Υ֥Ȼظǽ(饹᥽åɥʤ) + üʥ֥Ȼظǽ(Mixin, ðۥ᥽åɤʤ) + 黻ҥС + 㳰ǽ + ƥ졼ȥ + ١쥯 + ʥߥåǥ (ƥˤ) + ܿ⤤¿UNIXưǤʤDOSWindows MacBeOSʤɤξǤư * ˡ ** FTP ʲξˤƤޤ ftp://ftp.ruby-lang.org/pub/ruby/ ** Subversion ܥ֥RubyκǿΥɤϼΥޥɤǼǤޤ $ svn co http://svn.ruby-lang.org/repos/ruby/branches/ruby_1_8/ ȯüΥɤϼΥޥɤǼǤޤ $ svn co http://svn.ruby-lang.org/repos/ruby/trunk/ ruby ¾˳ȯΥ֥ΰϼΥޥɤǸޤ $ svn ls http://svn.ruby-lang.org/repos/ruby/branches/ * ۡڡ RubyΥۡڡURL http://www.ruby-lang.org/ Ǥ * ᡼󥰥ꥹ RubyΥ᡼󥰥ꥹȤޤô˾ ruby-list-ctl@ruby-lang.org ޤʸ subscribe YourFirstName YourFamilyName Ƚ񤤤äƲ RubyȯԸ᡼󥰥ꥹȤ⤢ޤǤrubyΥ λͳĥʤɼˤĤƵƤޤ ô˾ ruby-dev-ctl@ruby-lang.org ޤruby-listƱͤˡǥ᡼뤷Ƥ Rubyĥ⥸塼ˤĤä礦ruby-ext᡼󥰥ꥹȤ شطˤĤä礦ruby-math᡼󥰥ꥹȤ Ѹä礦ruby-talk᡼󥰥ꥹȤ⤢ޤˡ ϤɤƱǤ * ѥ롦󥹥ȡ ʲμǹԤäƤ 1. ⤷configureե뤬Ĥʤ⤷ configure.inŤ褦ʤ顢autoconf¹Ԥ configure 2. configure¹ԤMakefileʤɤ ĶˤäƤϥǥեȤCѥѥץդ ޤconfigureץ optflags=.. warnflags=.. Ǿ񤭤Ǥޤ 3. (ɬפʤ)defines.hԽ ¿ʬɬ̵Ȼפޤ 4. (ɬפʤ)ext/SetupŪ˥󥯤ĥ⥸塼 ꤹ ext/Setup˵Ҥ⥸塼Ū˥󥯤ޤ ʥߥåǥ󥰤򥵥ݡȤƤʤƥ ǤSetup1ܤΡoption nodynamicפȤԤΥ Ȥ򳰤ɬפޤޤΥƥ ĥ⥸塼Ѥ뤿ˤϡ餫Ū˥ Ƥɬפޤ 5. make¹Ԥƥѥ뤹 6. make testǥƥȤԤ test succeededפɽǤƥ ƤⴰݾڤƤǤϤޤ 7. make install rootǺȤɬפ뤫⤷ޤ ⤷ѥ˥顼ȯˤϥ顼Υȥ OSμޤǤܤݡȤԤäƤ ¾Τˤʤޤ * ܿ UNIXǤconfigureۤȤɤκۤۼƤϤ פ̸Ȥä(˰㤤ʤ)Ԥˤ ȤݡȤСǤ뤫Τޤ ƥˤäȤ¸ΤGCǤRubyGCо Υƥ㤬setjmp()ˤäƤΥ쥸 jmp_buf Ǽ뤳Ȥȡjmp_bufȥå32bit饤Ȥ 뤳ȤꤷƤޤäԤΩʤб ˺Ǥ礦ԤβŪñǡgc.cǥå ޡƤʬ˥饤ȤΥХȿ餷ƥޡ 륳ɤɲäǺѤߤޤdefined(THINK_C)פ Ƥʬ򻲹ͤˤƤ # ºݤˤRubyThink CǤϥѥǤޤ 쥸ɥCPUǤϡ쥸ɥ򥹥 ˥եå夹륢֥饳ɤɲäɬפ뤫 ޤ * ۾ COPYING.jaե򻲾ȤƤ * ȡХݡȤ¾ matz@netlab.jp ޤǡ ------------------------------------------------------- created at: Thu Aug 3 11:57:36 JST 1995 Local variables: mode: indented-text end: ================================================ FILE: Rakefile ================================================ require 'distro/tasks' ================================================ FILE: ToDo ================================================ Language Spec. - Class#allocate - basicNew - class Foo::Bar RubyGems? * resumable Exception via Exception#resume. * method combination, e.g. before, after, around, etc. * .. or something like defadvice in Emacs. * property - for methods, or for objects in general. * "in" modifier, to annotate, or to encourage assertion. * selector namespace - something like generic-flet in CLOS, to help RubyBehavior * private instance variable (as in Python?) @_foo in class Foo => @_Foo_foo * warn/error "bare word" method, like "foo", you should type "foo()" * clarify evaluation order of operator argument (=~, .., ...) * :symbol => value hash in the form of {symbol: value, ...} ?? Hacking Interpreter - generational GC * non-blocking open (e.g. for named pipe) for thread * avoid blocking with gethostbyname/gethostbyaddr (use fork ???) * objectify interpreters ??? * remove rb_eval() recursions * syntax tree -> bytecode ??? * scrambled script, or script filter * setuid ruby * performance tune for in-block (dynamic) local variables. * give warnings to assign magic variables. * export rb_io_{addstr,printf,puts,print} * autoload should work with threads [ruby-talk:4589] * remove stdio dependency from IOs. * warn for inconsistent local variable usage (lv m and method m at the same time). * MicroRuby * Built-in Interactive Ruby. * Parser API * trap every method invocation, which can be enabled by e.g. trap_call :method. * unify Errno exceptions of same errno, or new exception comparison scheme. * 2.times{|i| if i==0 then a = 15 else puts eval("a") end} should print nil. * Thread#max_stack_size attribute (possible??) Standard Libraries - Module#define_method which takes a name and a body (block, proc or method). - Enume#inject - Array#fetch - IO::for_fd - Process::waitall [ruby-talk:4557] - Process::Status - File::lchown, File::lchmod; xxx - still need work for non existing platforms - move Time::times to Process. - Enumerable#sort_by for Schwartzian transformation - fork_and_kill_other_threads. - signal list (Signal::trap, Signal::list). - move NameError under StandardError. - Integer#to_s(base) - Hash::new{default} - hash etc. should handle self referenceing array/hash - Array#select(n1,n2...) works like Array#indexes(n1,n2...) - use Mersenne Twister RNG for random. - deprecate Array#indexes, and Array#indices. - remove dependency on MAXPATHLEN. * String#scanf(?) * Object#fmt(?) * Time::strptime * Integer[num], Float[num]; Fixnum[num]? * method to retrieve non-number trailer for to_i/to_f. * Stream or Port, abstract superclass of IO ? * String#{pred,prev}, String#downto * optional stepsize argument for succ() * Ruby module -- Ruby::Version, Ruby::Interpreter * introduce Boolean class; super of TrueClass, FalseClass * synchronized method - synchronized{...}, synchronized :foo, :bar * Array#&, Array#| to allow duplication. ??? * way to specify immortal (fork endurance) thread; * or raise ForkException to every thread but fork caller. * new user-defined marshal scheme. _dump(dumper), _load(restorer) * library to load per-user profile seeking .ruby_profile or ruby.ini file. * warning framework (warn, warning for Ruby level) * marshal should not depend on sprintf (works bad with locale). * ternary arg pow: a.pow(b,c) == a**b%c * new caller(), e.g. call_stack; needs better name. * pointer share mechanism similar to one in String for Array. * require "1.6" etc. by /usr/lib/ruby/1.6/1.6.rb ;-) * save both "feature names" and "normalized path" in $" * implement Mutex_m (or MutexMixin) using Mutex. Extension Libraries * ptk.rb pTk wrapper that is compatible to tk.rb * Berkeley DB extension * BitVector * thread-safe fcgi Ruby Libraries * urllib.rb, nttplib.rb, etc. * format like perl's Tools * freeze or undump to bundle everything * bundle using zlib ================================================ FILE: array.c ================================================ /********************************************************************** array.c - $Author$ $Date$ created at: Fri Aug 6 09:46:12 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto Copyright (C) 2000 Network Applied Communication Laboratory, Inc. Copyright (C) 2000 Information-technology Promotion Agency, Japan **********************************************************************/ #include "ruby.h" #include "util.h" #include "st.h" VALUE rb_cArray; static ID id_cmp; #define ARY_DEFAULT_SIZE 16 #define ARY_MAX_SIZE (LONG_MAX / sizeof(VALUE)) void rb_mem_clear(mem, size) register VALUE *mem; register long size; { while (size--) { *mem++ = Qnil; } } static inline void memfill(mem, size, val) register VALUE *mem; register long size; register VALUE val; { while (size--) { *mem++ = val; } } #define ARY_TMPLOCK FL_USER1 static inline void rb_ary_modify_check(ary) VALUE ary; { if (OBJ_FROZEN(ary)) rb_error_frozen("array"); if (FL_TEST(ary, ARY_TMPLOCK)) rb_raise(rb_eRuntimeError, "can't modify array during iteration"); if (!OBJ_TAINTED(ary) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify array"); } static void rb_ary_modify(ary) VALUE ary; { VALUE *ptr; rb_ary_modify_check(ary); if (FL_TEST(ary, ELTS_SHARED)) { ptr = ALLOC_N(VALUE, RARRAY(ary)->len); FL_UNSET(ary, ELTS_SHARED); RARRAY(ary)->aux.capa = RARRAY(ary)->len; MEMCPY(ptr, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len); RARRAY(ary)->ptr = ptr; } } VALUE rb_ary_freeze(ary) VALUE ary; { return rb_obj_freeze(ary); } /* * call-seq: * array.frozen? -> true or false * * Return true if this array is frozen (or temporarily frozen * while being sorted). */ static VALUE rb_ary_frozen_p(ary) VALUE ary; { if (OBJ_FROZEN(ary)) return Qtrue; if (FL_TEST(ary, ARY_TMPLOCK)) return Qtrue; return Qfalse; } static VALUE ary_alloc _((VALUE)); static VALUE ary_alloc(klass) VALUE klass; { NEWOBJ(ary, struct RArray); OBJSETUP(ary, klass, T_ARRAY); ary->len = 0; ary->ptr = 0; ary->aux.capa = 0; return (VALUE)ary; } static VALUE ary_new(klass, len) VALUE klass; long len; { VALUE ary = ary_alloc(klass); if (len < 0) { rb_raise(rb_eArgError, "negative array size (or size too big)"); } if (len > ARY_MAX_SIZE) { rb_raise(rb_eArgError, "array size too big"); } if (len == 0) len++; RARRAY(ary)->ptr = ALLOC_N(VALUE, len); RARRAY(ary)->aux.capa = len; return ary; } VALUE rb_ary_new2(len) long len; { return ary_new(rb_cArray, len); } VALUE rb_ary_new() { return rb_ary_new2(ARY_DEFAULT_SIZE); } #ifdef HAVE_STDARG_PROTOTYPES #include #define va_init_list(a,b) va_start(a,b) #else #include #define va_init_list(a,b) va_start(a) #endif VALUE #ifdef HAVE_STDARG_PROTOTYPES rb_ary_new3(long n, ...) #else rb_ary_new3(n, va_alist) long n; va_dcl #endif { va_list ar; VALUE ary; long i; ary = rb_ary_new2(n); va_init_list(ar, n); for (i=0; iptr[i] = va_arg(ar, VALUE); } va_end(ar); RARRAY(ary)->len = n; return ary; } VALUE rb_ary_new4(n, elts) long n; const VALUE *elts; { VALUE ary; ary = rb_ary_new2(n); if (n > 0 && elts) { MEMCPY(RARRAY(ary)->ptr, elts, VALUE, n); } /* This assignment to len will be moved to the above "if" block in Ruby 1.9 */ RARRAY(ary)->len = n; return ary; } static VALUE ary_make_shared(ary) VALUE ary; { if (!FL_TEST(ary, ELTS_SHARED)) { NEWOBJ(shared, struct RArray); OBJSETUP(shared, rb_cArray, T_ARRAY); shared->len = RARRAY(ary)->len; shared->ptr = RARRAY(ary)->ptr; shared->aux.capa = RARRAY(ary)->aux.capa; RARRAY(ary)->aux.shared = (VALUE)shared; FL_SET(ary, ELTS_SHARED); OBJ_FREEZE(shared); return (VALUE)shared; } else { return RARRAY(ary)->aux.shared; } } VALUE rb_assoc_new(car, cdr) VALUE car, cdr; { VALUE ary; ary = rb_ary_new2(2); RARRAY(ary)->ptr[0] = car; RARRAY(ary)->ptr[1] = cdr; RARRAY(ary)->len = 2; return ary; } static VALUE to_ary(ary) VALUE ary; { return rb_convert_type(ary, T_ARRAY, "Array", "to_ary"); } VALUE rb_check_array_type(ary) VALUE ary; { return rb_check_convert_type(ary, T_ARRAY, "Array", "to_ary"); } static VALUE rb_ary_replace _((VALUE, VALUE)); /* * call-seq: * Array.new(size=0, obj=nil) * Array.new(array) * Array.new(size) {|index| block } * * Returns a new array. In the first form, the new array is * empty. In the second it is created with _size_ copies of _obj_ * (that is, _size_ references to the same * _obj_). The third form creates a copy of the array * passed as a parameter (the array is generated by calling * to_ary on the parameter). In the last form, an array * of the given size is created. Each element in this array is * calculated by passing the element's index to the given block and * storing the return value. * * Array.new * Array.new(2) * Array.new(5, "A") * * # only one copy of the object is created * a = Array.new(2, Hash.new) * a[0]['cat'] = 'feline' * a * a[1]['cat'] = 'Felix' * a * * # here multiple copies are created * a = Array.new(2) { Hash.new } * a[0]['cat'] = 'feline' * a * * squares = Array.new(5) {|i| i*i} * squares * * copy = Array.new(squares) */ static VALUE rb_ary_initialize(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { long len; VALUE size, val; rb_ary_modify(ary); if (rb_scan_args(argc, argv, "02", &size, &val) == 0) { RARRAY(ary)->len = 0; if (rb_block_given_p()) { rb_warning("given block not used"); } return ary; } if (argc == 1 && !FIXNUM_P(size)) { val = rb_check_array_type(size); if (!NIL_P(val)) { rb_ary_replace(ary, val); return ary; } } len = NUM2LONG(size); if (len < 0) { rb_raise(rb_eArgError, "negative array size"); } if (len > ARY_MAX_SIZE) { rb_raise(rb_eArgError, "array size too big"); } if (len > RARRAY(ary)->aux.capa) { REALLOC_N(RARRAY(ary)->ptr, VALUE, len); RARRAY(ary)->aux.capa = len; } if (rb_block_given_p()) { long i; if (argc == 2) { rb_warn("block supersedes default value argument"); } for (i=0; ilen = i + 1; } } else { memfill(RARRAY(ary)->ptr, len, val); RARRAY(ary)->len = len; } return ary; } /* * Returns a new array populated with the given objects. * * Array.[]( 1, 'a', /^A/ ) * Array[ 1, 'a', /^A/ ] * [ 1, 'a', /^A/ ] */ static VALUE rb_ary_s_create(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { VALUE ary = ary_alloc(klass); if (argc > 0) { RARRAY(ary)->ptr = ALLOC_N(VALUE, argc); MEMCPY(RARRAY(ary)->ptr, argv, VALUE, argc); } RARRAY(ary)->len = RARRAY(ary)->aux.capa = argc; return ary; } void rb_ary_store(ary, idx, val) VALUE ary; long idx; VALUE val; { if (idx < 0) { idx += RARRAY(ary)->len; if (idx < 0) { rb_raise(rb_eIndexError, "index %ld out of array", idx - RARRAY(ary)->len); } } else if (idx >= ARY_MAX_SIZE) { rb_raise(rb_eIndexError, "index %ld too big", idx); } rb_ary_modify(ary); if (idx >= RARRAY(ary)->aux.capa) { long new_capa = RARRAY(ary)->aux.capa / 2; if (new_capa < ARY_DEFAULT_SIZE) { new_capa = ARY_DEFAULT_SIZE; } if (new_capa >= ARY_MAX_SIZE - idx) { new_capa = (ARY_MAX_SIZE - idx) / 2; } new_capa += idx; REALLOC_N(RARRAY(ary)->ptr, VALUE, new_capa); RARRAY(ary)->aux.capa = new_capa; } if (idx > RARRAY(ary)->len) { rb_mem_clear(RARRAY(ary)->ptr + RARRAY(ary)->len, idx-RARRAY(ary)->len + 1); } if (idx >= RARRAY(ary)->len) { RARRAY(ary)->len = idx + 1; } RARRAY(ary)->ptr[idx] = val; } static VALUE ary_shared_array(klass, ary) VALUE klass; VALUE ary; { VALUE val = ary_alloc(klass); ary_make_shared(ary); RARRAY(val)->ptr = RARRAY(ary)->ptr; RARRAY(val)->len = RARRAY(ary)->len; RARRAY(val)->aux.shared = RARRAY(ary)->aux.shared; FL_SET(val, ELTS_SHARED); return val; } static VALUE ary_shared_first(argc, argv, ary, last) int argc; VALUE *argv; VALUE ary; int last; { VALUE nv, result; long n; long offset = 0; rb_scan_args(argc, argv, "1", &nv); n = NUM2LONG(nv); if (n > RARRAY(ary)->len) { n = RARRAY(ary)->len; } else if (n < 0) { rb_raise(rb_eArgError, "negative array size"); } if (last) { offset = RARRAY(ary)->len - n; } result = ary_shared_array(rb_cArray, ary); RARRAY(result)->ptr += offset; RARRAY(result)->len = n; return result; } /* * call-seq: * array << obj -> array * * Append---Pushes the given object on to the end of this array. This * expression returns the array itself, so several appends * may be chained together. * * [ 1, 2 ] << "c" << "d" << [ 3, 4 ] * #=> [ 1, 2, "c", "d", [ 3, 4 ] ] * */ VALUE rb_ary_push(ary, item) VALUE ary; VALUE item; { rb_ary_store(ary, RARRAY(ary)->len, item); return ary; } /* * call-seq: * array.push(obj, ... ) -> array * * Append---Pushes the given object(s) on to the end of this array. This * expression returns the array itself, so several appends * may be chained together. * * a = [ "a", "b", "c" ] * a.push("d", "e", "f") * #=> ["a", "b", "c", "d", "e", "f"] */ static VALUE rb_ary_push_m(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { while (argc--) { rb_ary_push(ary, *argv++); } return ary; } VALUE rb_ary_pop(ary) VALUE ary; { rb_ary_modify_check(ary); if (RARRAY(ary)->len == 0) return Qnil; if (!FL_TEST(ary, ELTS_SHARED) && RARRAY(ary)->len * 3 < RARRAY(ary)->aux.capa && RARRAY(ary)->aux.capa > ARY_DEFAULT_SIZE) { RARRAY(ary)->aux.capa = RARRAY(ary)->len * 2; REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa); } return RARRAY(ary)->ptr[--RARRAY(ary)->len]; } /* * call-seq: * array.pop -> obj or nil * array.pop(n) -> array * * Removes the last element from self and returns it, or * nil if the array is empty. * * If a number _n_ is given, returns an array of the last n elements * (or less) just like array.slice!(-n, n) does. * * a = [ "a", "b", "c", "d" ] * a.pop #=> "d" * a.pop(2) #=> ["b", "c"] * a #=> ["a"] */ static VALUE rb_ary_pop_m(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { VALUE result; if (argc == 0) { return rb_ary_pop(ary); } rb_ary_modify_check(ary); result = ary_shared_first(argc, argv, ary, Qtrue); RARRAY(ary)->len -= RARRAY(result)->len; return result; } VALUE rb_ary_shift(ary) VALUE ary; { VALUE top; rb_ary_modify_check(ary); if (RARRAY(ary)->len == 0) return Qnil; top = RARRAY(ary)->ptr[0]; if (!FL_TEST(ary, ELTS_SHARED)) { if (RARRAY(ary)->len < ARY_DEFAULT_SIZE) { MEMMOVE(RARRAY(ary)->ptr, RARRAY(ary)->ptr+1, VALUE, RARRAY(ary)->len-1); RARRAY(ary)->len--; return top; } RARRAY(ary)->ptr[0] = Qnil; ary_make_shared(ary); } RARRAY(ary)->ptr++; /* shift ptr */ RARRAY(ary)->len--; return top; } /* * call-seq: * array.shift -> obj or nil * array.shift(n) -> array * * Returns the first element of self and removes it (shifting all * other elements down by one). Returns nil if the array * is empty. * * If a number _n_ is given, returns an array of the first n elements * (or less) just like array.slice!(0, n) does. * * args = [ "-m", "-q", "filename" ] * args.shift #=> "-m" * args #=> ["-q", "filename"] * * args = [ "-m", "-q", "filename" ] * args.shift(2) #=> ["-m", "-q"] * args #=> ["filename"] */ static VALUE rb_ary_shift_m(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { VALUE result; long n; if (argc == 0) { return rb_ary_shift(ary); } rb_ary_modify_check(ary); result = ary_shared_first(argc, argv, ary, Qfalse); n = RARRAY(result)->len; if (FL_TEST(ary, ELTS_SHARED)) { RARRAY(ary)->ptr += n; RARRAY(ary)->len -= n; } else { MEMMOVE(RARRAY(ary)->ptr, RARRAY(ary)->ptr+n, VALUE, RARRAY(ary)->len-n); RARRAY(ary)->len -= n; } return result; } VALUE rb_ary_unshift(ary, item) VALUE ary, item; { rb_ary_modify(ary); if (RARRAY(ary)->len == RARRAY(ary)->aux.capa) { long capa_inc = RARRAY(ary)->aux.capa / 2; if (capa_inc < ARY_DEFAULT_SIZE) { capa_inc = ARY_DEFAULT_SIZE; } RARRAY(ary)->aux.capa += capa_inc; REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa); } /* sliding items */ MEMMOVE(RARRAY(ary)->ptr + 1, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len); RARRAY(ary)->len++; RARRAY(ary)->ptr[0] = item; return ary; } /* * call-seq: * array.unshift(obj, ...) -> array * * Prepends objects to the front of array. * other elements up one. * * a = [ "b", "c", "d" ] * a.unshift("a") #=> ["a", "b", "c", "d"] * a.unshift(1, 2) #=> [ 1, 2, "a", "b", "c", "d"] */ static VALUE rb_ary_unshift_m(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { long len = RARRAY(ary)->len; if (argc == 0) return ary; /* make rooms by setting the last item */ rb_ary_store(ary, len + argc - 1, Qnil); /* sliding items */ MEMMOVE(RARRAY(ary)->ptr + argc, RARRAY(ary)->ptr, VALUE, len); MEMCPY(RARRAY(ary)->ptr, argv, VALUE, argc); return ary; } /* faster version - use this if you don't need to treat negative offset */ static inline VALUE rb_ary_elt(ary, offset) VALUE ary; long offset; { if (RARRAY(ary)->len == 0) return Qnil; if (offset < 0 || RARRAY(ary)->len <= offset) { return Qnil; } return RARRAY(ary)->ptr[offset]; } VALUE rb_ary_entry(ary, offset) VALUE ary; long offset; { if (offset < 0) { offset += RARRAY(ary)->len; } return rb_ary_elt(ary, offset); } static VALUE rb_ary_subseq(ary, beg, len) VALUE ary; long beg, len; { VALUE klass, ary2, shared; VALUE *ptr; if (beg > RARRAY(ary)->len) return Qnil; if (beg < 0 || len < 0) return Qnil; if (RARRAY(ary)->len < len || RARRAY(ary)->len < beg + len) { len = RARRAY(ary)->len - beg; if (len < 0) len = 0; } klass = rb_obj_class(ary); if (len == 0) return ary_new(klass, 0); shared = ary_make_shared(ary); ptr = RARRAY(ary)->ptr; ary2 = ary_alloc(klass); RARRAY(ary2)->ptr = ptr + beg; RARRAY(ary2)->len = len; RARRAY(ary2)->aux.shared = shared; FL_SET(ary2, ELTS_SHARED); return ary2; } /* * call-seq: * array[index] -> obj or nil * array[start, length] -> an_array or nil * array[range] -> an_array or nil * array.slice(index) -> obj or nil * array.slice(start, length) -> an_array or nil * array.slice(range) -> an_array or nil * * Element Reference---Returns the element at _index_, * or returns a subarray starting at _start_ and * continuing for _length_ elements, or returns a subarray * specified by _range_. * Negative indices count backward from the end of the * array (-1 is the last element). Returns nil if the index * (or starting index) are out of range. * * a = [ "a", "b", "c", "d", "e" ] * a[2] + a[0] + a[1] #=> "cab" * a[6] #=> nil * a[1, 2] #=> [ "b", "c" ] * a[1..3] #=> [ "b", "c", "d" ] * a[4..7] #=> [ "e" ] * a[6..10] #=> nil * a[-3, 3] #=> [ "c", "d", "e" ] * # special cases * a[5] #=> nil * a[5, 1] #=> [] * a[5..10] #=> [] * */ VALUE rb_ary_aref(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { VALUE arg; long beg, len; if (argc == 2) { if (SYMBOL_P(argv[0])) { rb_raise(rb_eTypeError, "Symbol as array index"); } beg = NUM2LONG(argv[0]); len = NUM2LONG(argv[1]); if (beg < 0) { beg += RARRAY(ary)->len; } return rb_ary_subseq(ary, beg, len); } if (argc != 1) { rb_scan_args(argc, argv, "11", 0, 0); } arg = argv[0]; /* special case - speeding up */ if (FIXNUM_P(arg)) { return rb_ary_entry(ary, FIX2LONG(arg)); } if (SYMBOL_P(arg)) { rb_raise(rb_eTypeError, "Symbol as array index"); } /* check if idx is Range */ switch (rb_range_beg_len(arg, &beg, &len, RARRAY(ary)->len, 0)) { case Qfalse: break; case Qnil: return Qnil; default: return rb_ary_subseq(ary, beg, len); } return rb_ary_entry(ary, NUM2LONG(arg)); } /* * call-seq: * array.at(index) -> obj or nil * * Returns the element at _index_. A * negative index counts from the end of _self_. Returns +nil+ * if the index is out of range. See also Array#[]. * (Array#at is slightly faster than Array#[], * as it does not accept ranges and so on.) * * a = [ "a", "b", "c", "d", "e" ] * a.at(0) #=> "a" * a.at(-1) #=> "e" */ static VALUE rb_ary_at(ary, pos) VALUE ary, pos; { return rb_ary_entry(ary, NUM2LONG(pos)); } /* * call-seq: * array.first -> obj or nil * array.first(n) -> an_array * * Returns the first element, or the first +n+ elements, of the array. * If the array is empty, the first form returns nil, and the * second form returns an empty array. * * a = [ "q", "r", "s", "t" ] * a.first #=> "q" * a.first(1) #=> ["q"] * a.first(3) #=> ["q", "r", "s"] */ static VALUE rb_ary_first(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { if (argc == 0) { if (RARRAY(ary)->len == 0) return Qnil; return RARRAY(ary)->ptr[0]; } else { return ary_shared_first(argc, argv, ary, Qfalse); } } /* * call-seq: * array.last -> obj or nil * array.last(n) -> an_array * * Returns the last element(s) of self. If the array is empty, * the first form returns nil. * * [ "w", "x", "y", "z" ].last #=> "z" */ static VALUE rb_ary_last(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { if (argc == 0) { if (RARRAY(ary)->len == 0) return Qnil; return RARRAY(ary)->ptr[RARRAY(ary)->len-1]; } else { return ary_shared_first(argc, argv, ary, Qtrue); } } /* * call-seq: * array.fetch(index) -> obj * array.fetch(index, default ) -> obj * array.fetch(index) {|index| block } -> obj * * Tries to return the element at position index. If the index * lies outside the array, the first form throws an * IndexError exception, the second form returns * default, and the third form returns the value of invoking * the block, passing in the index. Negative values of index * count from the end of the array. * * a = [ 11, 22, 33, 44 ] * a.fetch(1) #=> 22 * a.fetch(-1) #=> 44 * a.fetch(4, 'cat') #=> "cat" * a.fetch(4) { |i| i*i } #=> 16 */ static VALUE rb_ary_fetch(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { VALUE pos, ifnone; long block_given; long idx; rb_scan_args(argc, argv, "11", &pos, &ifnone); block_given = rb_block_given_p(); if (block_given && argc == 2) { rb_warn("block supersedes default value argument"); } idx = NUM2LONG(pos); if (idx < 0) { idx += RARRAY(ary)->len; } if (idx < 0 || RARRAY(ary)->len <= idx) { if (block_given) return rb_yield(pos); if (argc == 1) { rb_raise(rb_eIndexError, "index %ld out of array", idx); } return ifnone; } return RARRAY(ary)->ptr[idx]; } /* * call-seq: * array.index(obj) -> int or nil * array.index {|item| block} -> int or nil * * Returns the index of the first object in self such that is * == to obj. If a block is given instead of an * argument, returns first object for which block is true. * Returns nil if no match is found. * * a = [ "a", "b", "c" ] * a.index("b") #=> 1 * a.index("z") #=> nil * a.index{|x|x=="b"} #=> 1 * * This is an alias of #find_index. */ static VALUE rb_ary_index(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { VALUE val; long i; if (argc == 0) { RETURN_ENUMERATOR(ary, 0, 0); for (i=0; ilen; i++) { if (RTEST(rb_yield(RARRAY(ary)->ptr[i]))) { return LONG2NUM(i); } } return Qnil; } rb_scan_args(argc, argv, "01", &val); for (i=0; ilen; i++) { if (rb_equal(RARRAY(ary)->ptr[i], val)) return LONG2NUM(i); } return Qnil; } /* * call-seq: * array.rindex(obj) -> int or nil * * Returns the index of the last object in array * == to obj. If a block is given instead of an * argument, returns first object for which block is * true. Returns nil if no match is found. * * a = [ "a", "b", "b", "b", "c" ] * a.rindex("b") #=> 3 * a.rindex("z") #=> nil * a.rindex{|x|x=="b"} #=> 3 */ static VALUE rb_ary_rindex(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { VALUE val; long i = RARRAY(ary)->len; if (argc == 0) { RETURN_ENUMERATOR(ary, 0, 0); while (i--) { if (RTEST(rb_yield(RARRAY(ary)->ptr[i]))) return LONG2NUM(i); if (i > RARRAY(ary)->len) { i = RARRAY(ary)->len; } } return Qnil; } rb_scan_args(argc, argv, "01", &val); while (i--) { if (rb_equal(RARRAY(ary)->ptr[i], val)) return LONG2NUM(i); if (i > RARRAY(ary)->len) { i = RARRAY(ary)->len; } } return Qnil; } /* * call-seq: * array.indexes( i1, i2, ... iN ) -> an_array * array.indices( i1, i2, ... iN ) -> an_array * * Deprecated; use Array#values_at. */ static VALUE rb_ary_indexes(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { VALUE new_ary; long i; rb_warn("Array#%s is deprecated; use Array#values_at", rb_id2name(rb_frame_last_func())); new_ary = rb_ary_new2(argc); for (i=0; ilen; if (beg < 0) { beg -= RARRAY(ary)->len; rb_raise(rb_eIndexError, "index %ld out of array", beg); } } if (RARRAY(ary)->len < len || RARRAY(ary)->len < beg + len) { len = RARRAY(ary)->len - beg; } if (NIL_P(rpl)) { rlen = 0; } else { rpl = rb_ary_to_ary(rpl); rlen = RARRAY(rpl)->len; } rb_ary_modify(ary); if (beg >= RARRAY(ary)->len) { if (beg > ARY_MAX_SIZE - rlen) { rb_raise(rb_eIndexError, "index %ld too big", beg); } len = beg + rlen; if (len >= RARRAY(ary)->aux.capa) { REALLOC_N(RARRAY(ary)->ptr, VALUE, len); RARRAY(ary)->aux.capa = len; } rb_mem_clear(RARRAY(ary)->ptr + RARRAY(ary)->len, beg - RARRAY(ary)->len); if (rlen > 0) { MEMCPY(RARRAY(ary)->ptr + beg, RARRAY(rpl)->ptr, VALUE, rlen); } RARRAY(ary)->len = len; } else { long alen; if (beg + len > RARRAY(ary)->len) { len = RARRAY(ary)->len - beg; } alen = RARRAY(ary)->len + rlen - len; if (alen >= RARRAY(ary)->aux.capa) { REALLOC_N(RARRAY(ary)->ptr, VALUE, alen); RARRAY(ary)->aux.capa = alen; } if (len != rlen) { MEMMOVE(RARRAY(ary)->ptr + beg + rlen, RARRAY(ary)->ptr + beg + len, VALUE, RARRAY(ary)->len - (beg + len)); RARRAY(ary)->len = alen; } if (rlen > 0) { MEMMOVE(RARRAY(ary)->ptr + beg, RARRAY(rpl)->ptr, VALUE, rlen); } } } /* * call-seq: * array[index] = obj -> obj * array[start, length] = obj or an_array or nil -> obj or an_array or nil * array[range] = obj or an_array or nil -> obj or an_array or nil * * Element Assignment---Sets the element at _index_, * or replaces a subarray starting at _start_ and * continuing for _length_ elements, or replaces a subarray * specified by _range_. If indices are greater than * the current capacity of the array, the array grows * automatically. A negative indices will count backward * from the end of the array. Inserts elements if _length_ is * zero. If +nil+ is used in the second and third form, * deletes elements from _self_. An +IndexError+ is raised if a * negative index points past the beginning of the array. See also * Array#push, and Array#unshift. * * a = Array.new * a[4] = "4"; #=> [nil, nil, nil, nil, "4"] * a[0, 3] = [ 'a', 'b', 'c' ] #=> ["a", "b", "c", nil, "4"] * a[1..2] = [ 1, 2 ] #=> ["a", 1, 2, nil, "4"] * a[0, 2] = "?" #=> ["?", 2, nil, "4"] * a[0..2] = "A" #=> ["A", "4"] * a[-1] = "Z" #=> ["A", "Z"] * a[1..-1] = nil #=> ["A"] */ static VALUE rb_ary_aset(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { long offset, beg, len; if (argc == 3) { if (SYMBOL_P(argv[0])) { rb_raise(rb_eTypeError, "Symbol as array index"); } if (SYMBOL_P(argv[1])) { rb_raise(rb_eTypeError, "Symbol as subarray length"); } rb_ary_splice(ary, NUM2LONG(argv[0]), NUM2LONG(argv[1]), argv[2]); return argv[2]; } if (argc != 2) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)", argc); } if (FIXNUM_P(argv[0])) { offset = FIX2LONG(argv[0]); goto fixnum; } if (SYMBOL_P(argv[0])) { rb_raise(rb_eTypeError, "Symbol as array index"); } if (rb_range_beg_len(argv[0], &beg, &len, RARRAY(ary)->len, 1)) { /* check if idx is Range */ rb_ary_splice(ary, beg, len, argv[1]); return argv[1]; } offset = NUM2LONG(argv[0]); fixnum: rb_ary_store(ary, offset, argv[1]); return argv[1]; } /* * call-seq: * array.insert(index, obj...) -> array * * Inserts the given values before the element with the given index * (which may be negative). * * a = %w{ a b c d } * a.insert(2, 99) #=> ["a", "b", 99, "c", "d"] * a.insert(-2, 1, 2, 3) #=> ["a", "b", 99, "c", 1, 2, 3, "d"] */ static VALUE rb_ary_insert(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { long pos; if (argc == 1) return ary; if (argc < 1) { rb_raise(rb_eArgError, "wrong number of arguments (at least 1)"); } pos = NUM2LONG(argv[0]); if (pos == -1) { pos = RARRAY(ary)->len; } if (pos < 0) { pos++; } rb_ary_splice(ary, pos, 0, rb_ary_new4(argc - 1, argv + 1)); return ary; } /* * call-seq: * array.each {|item| block } -> array * * Calls block once for each element in self, passing that * element as a parameter. * * a = [ "a", "b", "c" ] * a.each {|x| print x, " -- " } * * produces: * * a -- b -- c -- */ VALUE rb_ary_each(ary) VALUE ary; { long i; RETURN_ENUMERATOR(ary, 0, 0); for (i=0; ilen; i++) { rb_yield(RARRAY(ary)->ptr[i]); } return ary; } /* * call-seq: * array.each_index {|index| block } -> array * * Same as Array#each, but passes the index of the element * instead of the element itself. * * a = [ "a", "b", "c" ] * a.each_index {|x| print x, " -- " } * * produces: * * 0 -- 1 -- 2 -- */ static VALUE rb_ary_each_index(ary) VALUE ary; { long i; RETURN_ENUMERATOR(ary, 0, 0); for (i=0; ilen; i++) { rb_yield(LONG2NUM(i)); } return ary; } /* * call-seq: * array.reverse_each {|item| block } * * Same as Array#each, but traverses self in reverse * order. * * a = [ "a", "b", "c" ] * a.reverse_each {|x| print x, " " } * * produces: * * c b a */ static VALUE rb_ary_reverse_each(ary) VALUE ary; { long len; RETURN_ENUMERATOR(ary, 0, 0); len = RARRAY(ary)->len; while (len--) { rb_yield(RARRAY(ary)->ptr[len]); if (RARRAY(ary)->len < len) { len = RARRAY(ary)->len; } } return ary; } /* * call-seq: * array.length -> int * * Returns the number of elements in self. May be zero. * * [ 1, 2, 3, 4, 5 ].length #=> 5 */ static VALUE rb_ary_length(ary) VALUE ary; { return LONG2NUM(RARRAY(ary)->len); } /* * call-seq: * array.empty? -> true or false * * Returns true if self array contains no elements. * * [].empty? #=> true */ static VALUE rb_ary_empty_p(ary) VALUE ary; { if (RARRAY(ary)->len == 0) return Qtrue; return Qfalse; } VALUE rb_ary_dup(ary) VALUE ary; { VALUE dup = rb_ary_new2(RARRAY(ary)->len); DUPSETUP(dup, ary); MEMCPY(RARRAY(dup)->ptr, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len); RARRAY(dup)->len = RARRAY(ary)->len; return dup; } extern VALUE rb_output_fs; static VALUE inspect_join(ary, arg) VALUE ary; VALUE *arg; { return rb_ary_join(arg[0], arg[1]); } VALUE rb_ary_join(ary, sep) VALUE ary, sep; { long len = 1, i; int taint = Qfalse; VALUE result, tmp; if (RARRAY(ary)->len == 0) return rb_str_new(0, 0); if (OBJ_TAINTED(ary) || OBJ_TAINTED(sep)) taint = Qtrue; for (i=0; ilen; i++) { tmp = rb_check_string_type(RARRAY(ary)->ptr[i]); len += NIL_P(tmp) ? 10 : RSTRING(tmp)->len; } if (!NIL_P(sep)) { StringValue(sep); len += RSTRING(sep)->len * (RARRAY(ary)->len - 1); } result = rb_str_buf_new(len); for (i=0; ilen; i++) { tmp = RARRAY(ary)->ptr[i]; switch (TYPE(tmp)) { case T_STRING: break; case T_ARRAY: if (tmp == ary || rb_inspecting_p(tmp)) { tmp = rb_str_new2("[...]"); } else { VALUE args[2]; args[0] = tmp; args[1] = sep; tmp = rb_protect_inspect(inspect_join, ary, (VALUE)args); } break; default: tmp = rb_obj_as_string(tmp); } if (i > 0 && !NIL_P(sep)) rb_str_buf_append(result, sep); rb_str_buf_append(result, tmp); if (OBJ_TAINTED(tmp)) taint = Qtrue; } if (taint) OBJ_TAINT(result); return result; } /* * call-seq: * array.join(sep=$,) -> str * * Returns a string created by converting each element of the array to * a string, separated by sep. * * [ "a", "b", "c" ].join #=> "abc" * [ "a", "b", "c" ].join("-") #=> "a-b-c" */ static VALUE rb_ary_join_m(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { VALUE sep; rb_scan_args(argc, argv, "01", &sep); if (NIL_P(sep)) sep = rb_output_fs; return rb_ary_join(ary, sep); } /* * call-seq: * array.to_s -> string * * Returns _self_.join. * * [ "a", "e", "i", "o" ].to_s #=> "aeio" * */ VALUE rb_ary_to_s(ary) VALUE ary; { if (RARRAY(ary)->len == 0) return rb_str_new(0, 0); return rb_ary_join(ary, rb_output_fs); } static ID inspect_key; struct inspect_arg { VALUE (*func)(); VALUE arg1, arg2; }; static VALUE inspect_call(arg) struct inspect_arg *arg; { return (*arg->func)(arg->arg1, arg->arg2); } static VALUE get_inspect_tbl(create) int create; { VALUE inspect_tbl = rb_thread_local_aref(rb_thread_current(), inspect_key); if (NIL_P(inspect_tbl)) { if (create) { tbl_init: inspect_tbl = rb_ary_new(); rb_thread_local_aset(rb_thread_current(), inspect_key, inspect_tbl); } } else if (TYPE(inspect_tbl) != T_ARRAY) { rb_warn("invalid inspect_tbl value"); if (create) goto tbl_init; rb_thread_local_aset(rb_thread_current(), inspect_key, Qnil); return Qnil; } return inspect_tbl; } static VALUE inspect_ensure(obj) VALUE obj; { VALUE inspect_tbl; inspect_tbl = get_inspect_tbl(Qfalse); if (!NIL_P(inspect_tbl)) { rb_ary_pop(inspect_tbl); } return 0; } VALUE rb_protect_inspect(func, obj, arg) VALUE (*func)(ANYARGS); VALUE obj, arg; { struct inspect_arg iarg; VALUE inspect_tbl; VALUE id; inspect_tbl = get_inspect_tbl(Qtrue); id = rb_obj_id(obj); if (rb_ary_includes(inspect_tbl, id)) { return (*func)(obj, arg); } rb_ary_push(inspect_tbl, id); iarg.func = func; iarg.arg1 = obj; iarg.arg2 = arg; return rb_ensure(inspect_call, (VALUE)&iarg, inspect_ensure, obj); } VALUE rb_inspecting_p(obj) VALUE obj; { VALUE inspect_tbl; inspect_tbl = get_inspect_tbl(Qfalse); if (NIL_P(inspect_tbl)) return Qfalse; return rb_ary_includes(inspect_tbl, rb_obj_id(obj)); } static VALUE inspect_ary(ary) VALUE ary; { int tainted = OBJ_TAINTED(ary); long i; VALUE s, str; str = rb_str_buf_new2("["); for (i=0; ilen; i++) { s = rb_inspect(RARRAY(ary)->ptr[i]); if (OBJ_TAINTED(s)) tainted = Qtrue; if (i > 0) rb_str_buf_cat2(str, ", "); rb_str_buf_append(str, s); } rb_str_buf_cat2(str, "]"); if (tainted) OBJ_TAINT(str); return str; } /* * call-seq: * array.inspect -> string * * Create a printable version of array. */ static VALUE rb_ary_inspect(ary) VALUE ary; { if (RARRAY(ary)->len == 0) return rb_str_new2("[]"); if (rb_inspecting_p(ary)) return rb_str_new2("[...]"); return rb_protect_inspect(inspect_ary, ary, 0); } /* * call-seq: * array.to_a -> array * * Returns _self_. If called on a subclass of Array, converts * the receiver to an Array object. */ static VALUE rb_ary_to_a(ary) VALUE ary; { if (rb_obj_class(ary) != rb_cArray) { VALUE dup = rb_ary_new2(RARRAY(ary)->len); rb_ary_replace(dup, ary); return dup; } return ary; } /* * call-seq: * array.to_ary -> array * * Returns _self_. */ static VALUE rb_ary_to_ary_m(ary) VALUE ary; { return ary; } VALUE rb_ary_reverse(ary) VALUE ary; { VALUE *p1, *p2; VALUE tmp; rb_ary_modify(ary); if (RARRAY(ary)->len > 1) { p1 = RARRAY(ary)->ptr; p2 = p1 + RARRAY(ary)->len - 1; /* points last item */ while (p1 < p2) { tmp = *p1; *p1++ = *p2; *p2-- = tmp; } } return ary; } /* * call-seq: * array.reverse! -> array * * Reverses _self_ in place. * * a = [ "a", "b", "c" ] * a.reverse! #=> ["c", "b", "a"] * a #=> ["c", "b", "a"] */ static VALUE rb_ary_reverse_bang(ary) VALUE ary; { return rb_ary_reverse(ary); } /* * call-seq: * array.reverse -> an_array * * Returns a new array containing self's elements in reverse order. * * [ "a", "b", "c" ].reverse #=> ["c", "b", "a"] * [ 1 ].reverse #=> [1] */ static VALUE rb_ary_reverse_m(ary) VALUE ary; { return rb_ary_reverse(rb_ary_dup(ary)); } struct ary_sort_data { VALUE ary; VALUE *ptr; long len; }; static void ary_sort_check(data) struct ary_sort_data *data; { if (RARRAY(data->ary)->ptr != data->ptr || RARRAY(data->ary)->len != data->len) { rb_raise(rb_eArgError, "array modified during sort"); } } static int sort_1(a, b, data) VALUE *a, *b; struct ary_sort_data *data; { VALUE retval = rb_yield_values(2, *a, *b); int n; n = rb_cmpint(retval, *a, *b); ary_sort_check(data); return n; } static int sort_2(ap, bp, data) VALUE *ap, *bp; struct ary_sort_data *data; { VALUE retval; VALUE a = *ap, b = *bp; int n; if (FIXNUM_P(a) && FIXNUM_P(b)) { if ((long)a > (long)b) return 1; if ((long)a < (long)b) return -1; return 0; } if (TYPE(a) == T_STRING) { if (TYPE(b) == T_STRING) return rb_str_cmp(a, b); } retval = rb_funcall(a, id_cmp, 1, b); n = rb_cmpint(retval, a, b); ary_sort_check(data); return n; } static VALUE sort_internal(ary) VALUE ary; { struct ary_sort_data data; data.ary = ary; data.ptr = RARRAY(ary)->ptr; data.len = RARRAY(ary)->len; qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE), rb_block_given_p()?sort_1:sort_2, &data); return ary; } static VALUE sort_unlock(ary) VALUE ary; { FL_UNSET(ary, ARY_TMPLOCK); return ary; } /* * call-seq: * array.sort! -> array * array.sort! {| a,b | block } -> array * * Sorts _self_. Comparisons for * the sort will be done using the <=> operator or using * an optional code block. The block implements a comparison between * a and b, returning -1, 0, or +1. See also * Enumerable#sort_by. * * a = [ "d", "a", "e", "c", "b" ] * a.sort #=> ["a", "b", "c", "d", "e"] * a.sort {|x,y| y <=> x } #=> ["e", "d", "c", "b", "a"] */ VALUE rb_ary_sort_bang(ary) VALUE ary; { rb_ary_modify(ary); if (RARRAY(ary)->len > 1) { FL_SET(ary, ARY_TMPLOCK); /* prohibit modification during sort */ rb_ensure(sort_internal, ary, sort_unlock, ary); } return ary; } /* * call-seq: * array.sort -> an_array * array.sort {| a,b | block } -> an_array * * Returns a new array created by sorting self. Comparisons for * the sort will be done using the <=> operator or using * an optional code block. The block implements a comparison between * a and b, returning -1, 0, or +1. See also * Enumerable#sort_by. * * a = [ "d", "a", "e", "c", "b" ] * a.sort #=> ["a", "b", "c", "d", "e"] * a.sort {|x,y| y <=> x } #=> ["e", "d", "c", "b", "a"] */ VALUE rb_ary_sort(ary) VALUE ary; { ary = rb_ary_dup(ary); rb_ary_sort_bang(ary); return ary; } /* * call-seq: * array.collect {|item| block } -> an_array * array.map {|item| block } -> an_array * * Invokes block once for each element of self. Creates a * new array containing the values returned by the block. * See also Enumerable#collect. * * a = [ "a", "b", "c", "d" ] * a.collect {|x| x + "!" } #=> ["a!", "b!", "c!", "d!"] * a #=> ["a", "b", "c", "d"] */ static VALUE rb_ary_collect(ary) VALUE ary; { long i; VALUE collect; if (!rb_block_given_p()) { return rb_ary_new4(RARRAY(ary)->len, RARRAY(ary)->ptr); } collect = rb_ary_new2(RARRAY(ary)->len); for (i = 0; i < RARRAY(ary)->len; i++) { rb_ary_push(collect, rb_yield(RARRAY(ary)->ptr[i])); } return collect; } /* * call-seq: * array.collect! {|item| block } -> array * array.map! {|item| block } -> array * * Invokes the block once for each element of _self_, replacing the * element with the value returned by _block_. * See also Enumerable#collect. * * a = [ "a", "b", "c", "d" ] * a.collect! {|x| x + "!" } * a #=> [ "a!", "b!", "c!", "d!" ] */ static VALUE rb_ary_collect_bang(ary) VALUE ary; { long i; RETURN_ENUMERATOR(ary, 0, 0); rb_ary_modify(ary); for (i = 0; i < RARRAY(ary)->len; i++) { rb_ary_store(ary, i, rb_yield(RARRAY(ary)->ptr[i])); } return ary; } VALUE rb_values_at(obj, olen, argc, argv, func) VALUE obj; long olen; int argc; VALUE *argv; VALUE (*func) _((VALUE,long)); { VALUE result = rb_ary_new2(argc); long beg, len, i, j; for (i=0; i an_array * * Returns an array containing the elements in * _self_ corresponding to the given selector(s). The selectors * may be either integer indices or ranges. * See also Array#select. * * a = %w{ a b c d e f } * a.values_at(1, 3, 5) * a.values_at(1, 3, 5, 7) * a.values_at(-1, -3, -5, -7) * a.values_at(1..3, 2...5) */ static VALUE rb_ary_values_at(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { return rb_values_at(ary, RARRAY(ary)->len, argc, argv, rb_ary_entry); } /* * call-seq: * array.select {|item| block } -> an_array * * Invokes the block passing in successive elements from array, * returning an array containing those elements for which the block * returns a true value (equivalent to Enumerable#select). * * a = %w{ a b c d e f } * a.select {|v| v =~ /[aeiou]/} #=> ["a", "e"] */ static VALUE rb_ary_select(ary) VALUE ary; { VALUE result; long i; RETURN_ENUMERATOR(ary, 0, 0); result = rb_ary_new2(RARRAY(ary)->len); for (i = 0; i < RARRAY(ary)->len; i++) { if (RTEST(rb_yield(RARRAY(ary)->ptr[i]))) { rb_ary_push(result, rb_ary_elt(ary, i)); } } return result; } /* * call-seq: * array.delete(obj) -> obj or nil * array.delete(obj) { block } -> obj or nil * * Deletes items from self that are equal to obj. If * the item is not found, returns nil. If the optional * code block is given, returns the result of block if the item * is not found. * * a = [ "a", "b", "b", "b", "c" ] * a.delete("b") #=> "b" * a #=> ["a", "c"] * a.delete("z") #=> nil * a.delete("z") { "not found" } #=> "not found" */ VALUE rb_ary_delete(ary, item) VALUE ary; VALUE item; { long i1, i2; for (i1 = i2 = 0; i1 < RARRAY(ary)->len; i1++) { VALUE e = RARRAY(ary)->ptr[i1]; if (rb_equal(e, item)) continue; if (i1 != i2) { rb_ary_store(ary, i2, e); } i2++; } if (RARRAY(ary)->len == i2) { if (rb_block_given_p()) { return rb_yield(item); } return Qnil; } rb_ary_modify(ary); if (RARRAY(ary)->len > i2) { RARRAY(ary)->len = i2; if (i2 * 2 < RARRAY(ary)->aux.capa && RARRAY(ary)->aux.capa > ARY_DEFAULT_SIZE) { REALLOC_N(RARRAY(ary)->ptr, VALUE, i2 * 2); RARRAY(ary)->aux.capa = i2 * 2; } } return item; } VALUE rb_ary_delete_at(ary, pos) VALUE ary; long pos; { long i, len = RARRAY(ary)->len; VALUE del; if (pos >= len) return Qnil; if (pos < 0) { pos += len; if (pos < 0) return Qnil; } rb_ary_modify(ary); del = RARRAY(ary)->ptr[pos]; for (i = pos + 1; i < len; i++, pos++) { RARRAY(ary)->ptr[pos] = RARRAY(ary)->ptr[i]; } RARRAY(ary)->len = pos; return del; } /* * call-seq: * array.delete_at(index) -> obj or nil * * Deletes the element at the specified index, returning that element, * or nil if the index is out of range. See also * Array#slice!. * * a = %w( ant bat cat dog ) * a.delete_at(2) #=> "cat" * a #=> ["ant", "bat", "dog"] * a.delete_at(99) #=> nil */ static VALUE rb_ary_delete_at_m(ary, pos) VALUE ary, pos; { return rb_ary_delete_at(ary, NUM2LONG(pos)); } /* * call-seq: * array.slice!(index) -> obj or nil * array.slice!(start, length) -> sub_array or nil * array.slice!(range) -> sub_array or nil * * Deletes the element(s) given by an index (optionally with a length) * or by a range. Returns the deleted object, subarray, or * nil if the index is out of range. Equivalent to: * * def slice!(*args) * result = self[*args] * self[*args] = nil * result * end * * a = [ "a", "b", "c" ] * a.slice!(1) #=> "b" * a #=> ["a", "c"] * a.slice!(-1) #=> "c" * a #=> ["a"] * a.slice!(100) #=> nil * a #=> ["a"] */ static VALUE rb_ary_slice_bang(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { VALUE arg1, arg2; long pos, len, orig_len; rb_ary_modify_check(ary); if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2) { pos = NUM2LONG(arg1); len = NUM2LONG(arg2); delete_pos_len: if (len < 0) return Qnil; orig_len = RARRAY_LEN(ary); if (pos < 0) { pos += orig_len; if (pos < 0) return Qnil; } else if (orig_len < pos) return Qnil; if (orig_len < pos + len) { len = orig_len - pos; } if (len == 0) return rb_ary_new2(0); arg2 = rb_ary_new4(len, RARRAY_PTR(ary)+pos); RBASIC(arg2)->klass = rb_obj_class(ary); rb_ary_splice(ary, pos, len, Qnil); /* Qundef in 1.9 */ return arg2; } if (!FIXNUM_P(arg1)) { switch (rb_range_beg_len(arg1, &pos, &len, RARRAY_LEN(ary), 0)) { case Qtrue: /* valid range */ goto delete_pos_len; case Qnil: /* invalid range */ return Qnil; default: /* not a range */ break; } } return rb_ary_delete_at(ary, NUM2LONG(arg1)); } /* * call-seq: * array.reject! {|item| block } -> array or nil * * Equivalent to Array#delete_if, deleting elements from * _self_ for which the block evaluates to true, but returns * nil if no changes were made. Also see * Enumerable#reject. */ static VALUE rb_ary_reject_bang(ary) VALUE ary; { long i1, i2; RETURN_ENUMERATOR(ary, 0, 0); rb_ary_modify(ary); for (i1 = i2 = 0; i1 < RARRAY(ary)->len; i1++) { VALUE v = RARRAY(ary)->ptr[i1]; if (RTEST(rb_yield(v))) continue; if (i1 != i2) { rb_ary_store(ary, i2, v); } i2++; } if (RARRAY(ary)->len == i2) return Qnil; if (i2 < RARRAY(ary)->len) RARRAY(ary)->len = i2; return ary; } /* * call-seq: * array.reject {|item| block } -> an_array * * Returns a new array containing the items in _self_ * for which the block is not true. */ static VALUE rb_ary_reject(ary) VALUE ary; { RETURN_ENUMERATOR(ary, 0, 0); ary = rb_ary_dup(ary); rb_ary_reject_bang(ary); return ary; } /* * call-seq: * array.delete_if {|item| block } -> array * * Deletes every element of self for which block evaluates * to true. * * a = [ "a", "b", "c" ] * a.delete_if {|x| x >= "b" } #=> ["a"] */ static VALUE rb_ary_delete_if(ary) VALUE ary; { RETURN_ENUMERATOR(ary, 0, 0); rb_ary_reject_bang(ary); return ary; } /* * call-seq: * array.zip(arg, ...) -> an_array * array.zip(arg, ...) {| arr | block } -> nil * * Converts any arguments to arrays, then merges elements of * self with corresponding elements from each argument. This * generates a sequence of self.size n-element * arrays, where n is one more that the count of arguments. If * the size of any argument is less than enumObj.size, * nil values are supplied. If a block given, it is * invoked for each output array, otherwise an array of arrays is * returned. * * a = [ 4, 5, 6 ] * b = [ 7, 8, 9 ] * * [1,2,3].zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]] * [1,2].zip(a,b) #=> [[1, 4, 7], [2, 5, 8]] * a.zip([1,2],[8]) #=> [[4,1,8], [5,2,nil], [6,nil,nil]] */ static VALUE rb_ary_zip(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { int i, j; long len; VALUE result; for (i=0; ilen; i++) { VALUE tmp = rb_ary_new2(argc+1); rb_ary_push(tmp, rb_ary_elt(ary, i)); for (j=0; jlen; result = rb_ary_new2(len); for (i=0; i an_array * * Assumes that self is an array of arrays and transposes the * rows and columns. * * a = [[1,2], [3,4], [5,6]] * a.transpose #=> [[1, 3, 5], [2, 4, 6]] */ static VALUE rb_ary_transpose(ary) VALUE ary; { long elen = -1, alen, i, j; VALUE tmp, result = 0; alen = RARRAY(ary)->len; if (alen == 0) return rb_ary_dup(ary); for (i=0; ilen; result = rb_ary_new2(elen); for (j=0; jlen) { rb_raise(rb_eIndexError, "element size differs (%d should be %d)", RARRAY(tmp)->len, elen); } for (j=0; j array * * Replaces the contents of self with the contents of * other_array, truncating or expanding if necessary. * * a = [ "a", "b", "c", "d", "e" ] * a.replace([ "x", "y", "z" ]) #=> ["x", "y", "z"] * a #=> ["x", "y", "z"] */ static VALUE rb_ary_replace(copy, orig) VALUE copy, orig; { VALUE shared; rb_ary_modify(copy); orig = to_ary(orig); if (copy == orig) return copy; shared = ary_make_shared(orig); if (RARRAY(copy)->ptr && !FL_TEST(copy, ELTS_SHARED)) free(RARRAY(copy)->ptr); RARRAY(copy)->ptr = RARRAY(orig)->ptr; RARRAY(copy)->len = RARRAY(orig)->len; RARRAY(copy)->aux.shared = shared; FL_SET(copy, ELTS_SHARED); return copy; } /* * call-seq: * array.clear -> array * * Removes all elements from _self_. * * a = [ "a", "b", "c", "d", "e" ] * a.clear #=> [ ] */ VALUE rb_ary_clear(ary) VALUE ary; { rb_ary_modify(ary); RARRAY(ary)->len = 0; if (ARY_DEFAULT_SIZE * 2 < RARRAY(ary)->aux.capa) { REALLOC_N(RARRAY(ary)->ptr, VALUE, ARY_DEFAULT_SIZE * 2); RARRAY(ary)->aux.capa = ARY_DEFAULT_SIZE * 2; } return ary; } /* * call-seq: * array.fill(obj) -> array * array.fill(obj, start [, length]) -> array * array.fill(obj, range ) -> array * array.fill {|index| block } -> array * array.fill(start [, length] ) {|index| block } -> array * array.fill(range) {|index| block } -> array * * The first three forms set the selected elements of self (which * may be the entire array) to obj. A start of * nil is equivalent to zero. A length of * nil is equivalent to self.length. The last three * forms fill the array with the value of the block. The block is * passed the absolute index of each element to be filled. * * a = [ "a", "b", "c", "d" ] * a.fill("x") #=> ["x", "x", "x", "x"] * a.fill("z", 2, 2) #=> ["x", "x", "z", "z"] * a.fill("y", 0..1) #=> ["y", "y", "z", "z"] * a.fill {|i| i*i} #=> [0, 1, 4, 9] * a.fill(-2) {|i| i*i*i} #=> [0, 1, 8, 27] */ static VALUE rb_ary_fill(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { VALUE item, arg1, arg2; long beg = 0, end = 0, len = 0; VALUE *p, *pend; int block_p = Qfalse; if (rb_block_given_p()) { block_p = Qtrue; rb_scan_args(argc, argv, "02", &arg1, &arg2); argc += 1; /* hackish */ } else { rb_scan_args(argc, argv, "12", &item, &arg1, &arg2); } switch (argc) { case 1: beg = 0; len = RARRAY(ary)->len; break; case 2: if (rb_range_beg_len(arg1, &beg, &len, RARRAY(ary)->len, 1)) { break; } /* fall through */ case 3: beg = NIL_P(arg1) ? 0 : NUM2LONG(arg1); if (beg < 0) { beg = RARRAY(ary)->len + beg; if (beg < 0) beg = 0; } len = NIL_P(arg2) ? RARRAY(ary)->len - beg : NUM2LONG(arg2); break; } rb_ary_modify(ary); if (len < 0) { return ary; } if (beg >= ARY_MAX_SIZE || len > ARY_MAX_SIZE - beg) { rb_raise(rb_eArgError, "argument too big"); } end = beg + len; if (end > RARRAY(ary)->len) { if (end >= RARRAY(ary)->aux.capa) { REALLOC_N(RARRAY(ary)->ptr, VALUE, end); RARRAY(ary)->aux.capa = end; } rb_mem_clear(RARRAY(ary)->ptr + RARRAY(ary)->len, end - RARRAY(ary)->len); RARRAY(ary)->len = end; } if (block_p) { VALUE v; long i; for (i=beg; i=RARRAY(ary)->len) break; RARRAY(ary)->ptr[i] = v; } } else { p = RARRAY(ary)->ptr + beg; pend = p + len; while (p < pend) { *p++ = item; } } return ary; } /* * call-seq: * array + other_array -> an_array * * Concatenation---Returns a new array built by concatenating the * two arrays together to produce a third array. * * [ 1, 2, 3 ] + [ 4, 5 ] #=> [ 1, 2, 3, 4, 5 ] */ VALUE rb_ary_plus(x, y) VALUE x, y; { VALUE z; long len; y = to_ary(y); len = RARRAY(x)->len + RARRAY(y)->len; z = rb_ary_new2(len); MEMCPY(RARRAY(z)->ptr, RARRAY(x)->ptr, VALUE, RARRAY(x)->len); MEMCPY(RARRAY(z)->ptr + RARRAY(x)->len, RARRAY(y)->ptr, VALUE, RARRAY(y)->len); RARRAY(z)->len = len; return z; } /* * call-seq: * array.concat(other_array) -> array * * Appends the elements in other_array to _self_. * * [ "a", "b" ].concat( ["c", "d"] ) #=> [ "a", "b", "c", "d" ] */ VALUE rb_ary_concat(x, y) VALUE x, y; { y = to_ary(y); if (RARRAY(y)->len > 0) { rb_ary_splice(x, RARRAY(x)->len, 0, y); } return x; } /* * call-seq: * array * int -> an_array * array * str -> a_string * * Repetition---With a String argument, equivalent to * self.join(str). Otherwise, returns a new array * built by concatenating the _int_ copies of _self_. * * * [ 1, 2, 3 ] * 3 #=> [ 1, 2, 3, 1, 2, 3, 1, 2, 3 ] * [ 1, 2, 3 ] * "," #=> "1,2,3" * */ static VALUE rb_ary_times(ary, times) VALUE ary, times; { VALUE ary2, tmp; long i, len; tmp = rb_check_string_type(times); if (!NIL_P(tmp)) { return rb_ary_join(ary, tmp); } len = NUM2LONG(times); if (len == 0) return ary_new(rb_obj_class(ary), 0); if (len < 0) { rb_raise(rb_eArgError, "negative argument"); } if (ARY_MAX_SIZE/len < RARRAY(ary)->len) { rb_raise(rb_eArgError, "argument too big"); } len *= RARRAY(ary)->len; ary2 = ary_new(rb_obj_class(ary), len); RARRAY(ary2)->len = len; for (i=0; ilen) { MEMCPY(RARRAY(ary2)->ptr+i, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len); } OBJ_INFECT(ary2, ary); return ary2; } /* * call-seq: * array.assoc(obj) -> an_array or nil * * Searches through an array whose elements are also arrays * comparing _obj_ with the first element of each contained array * using obj.==. * Returns the first contained array that matches (that * is, the first associated array), * or +nil+ if no match is found. * See also Array#rassoc. * * s1 = [ "colors", "red", "blue", "green" ] * s2 = [ "letters", "a", "b", "c" ] * s3 = "foo" * a = [ s1, s2, s3 ] * a.assoc("letters") #=> [ "letters", "a", "b", "c" ] * a.assoc("foo") #=> nil */ VALUE rb_ary_assoc(ary, key) VALUE ary, key; { long i; VALUE v; for (i = 0; i < RARRAY(ary)->len; ++i) { v = rb_check_array_type(RARRAY(ary)->ptr[i]); if (!NIL_P(v) && RARRAY(v)->len > 0 && rb_equal(RARRAY(v)->ptr[0], key)) return v; } return Qnil; } /* * call-seq: * array.rassoc(key) -> an_array or nil * * Searches through the array whose elements are also arrays. Compares * key with the second element of each contained array using * ==. Returns the first contained array that matches. See * also Array#assoc. * * a = [ [ 1, "one"], [2, "two"], [3, "three"], ["ii", "two"] ] * a.rassoc("two") #=> [2, "two"] * a.rassoc("four") #=> nil */ VALUE rb_ary_rassoc(ary, value) VALUE ary, value; { long i; VALUE v; for (i = 0; i < RARRAY(ary)->len; ++i) { v = RARRAY(ary)->ptr[i]; if (TYPE(v) == T_ARRAY && RARRAY(v)->len > 1 && rb_equal(RARRAY(v)->ptr[1], value)) return v; } return Qnil; } static VALUE recursive_equal _((VALUE, VALUE, int)); static VALUE recursive_equal(ary1, ary2, recur) VALUE ary1, ary2; int recur; { long i; if (recur) return Qfalse; for (i=0; ilen; i++) { if (!rb_equal(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i))) return Qfalse; } return Qtrue; } /* * call-seq: * array == other_array -> bool * * Equality---Two arrays are equal if they contain the same number * of elements and if each element is equal to (according to * Object.==) the corresponding element in the other array. * * [ "a", "c" ] == [ "a", "c", 7 ] #=> false * [ "a", "c", 7 ] == [ "a", "c", 7 ] #=> true * [ "a", "c", 7 ] == [ "a", "d", "f" ] #=> false * */ static VALUE rb_ary_equal(ary1, ary2) VALUE ary1, ary2; { if (ary1 == ary2) return Qtrue; if (TYPE(ary2) != T_ARRAY) { if (!rb_respond_to(ary2, rb_intern("to_ary"))) { return Qfalse; } return rb_equal(ary2, ary1); } if (RARRAY(ary1)->len != RARRAY(ary2)->len) return Qfalse; return rb_exec_recursive(recursive_equal, ary1, ary2); } static VALUE recursive_eql _((VALUE, VALUE, int)); static VALUE recursive_eql(ary1, ary2, recur) VALUE ary1, ary2; int recur; { long i; if (recur) return Qfalse; for (i=0; ilen; i++) { if (!rb_eql(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i))) return Qfalse; } return Qtrue; } /* * call-seq: * array.eql?(other) -> true or false * * Returns true if _array_ and _other_ are the same object, * or are both arrays with the same content. */ static VALUE rb_ary_eql(ary1, ary2) VALUE ary1, ary2; { if (ary1 == ary2) return Qtrue; if (TYPE(ary2) != T_ARRAY) return Qfalse; if (RARRAY(ary1)->len != RARRAY(ary2)->len) return Qfalse; return rb_exec_recursive(recursive_eql, ary1, ary2); } static VALUE recursive_hash _((VALUE, VALUE, int)); static VALUE recursive_hash(ary, dummy, recur) VALUE ary; VALUE dummy; int recur; { long i, h; VALUE n; if (recur) { return LONG2FIX(0); } h = RARRAY(ary)->len; for (i=0; ilen; i++) { h = (h << 1) | (h<0 ? 1 : 0); n = rb_hash(RARRAY(ary)->ptr[i]); h ^= NUM2LONG(n); } return LONG2FIX(h); } /* * call-seq: * array.hash -> fixnum * * Compute a hash-code for this array. Two arrays with the same content * will have the same hash code (and will compare using eql?). */ static VALUE rb_ary_hash(ary) VALUE ary; { return rb_exec_recursive(recursive_hash, ary, 0); } /* * call-seq: * array.include?(obj) -> true or false * * Returns true if the given object is present in * self (that is, if any object == anObject), * false otherwise. * * a = [ "a", "b", "c" ] * a.include?("b") #=> true * a.include?("z") #=> false */ VALUE rb_ary_includes(ary, item) VALUE ary; VALUE item; { long i; for (i=0; ilen; i++) { if (rb_equal(RARRAY(ary)->ptr[i], item)) { return Qtrue; } } return Qfalse; } static VALUE recursive_cmp _((VALUE, VALUE, int)); static VALUE recursive_cmp(ary1, ary2, recur) VALUE ary1; VALUE ary2; int recur; { long i, len; if (recur) return Qnil; len = RARRAY(ary1)->len; if (len > RARRAY(ary2)->len) { len = RARRAY(ary2)->len; } for (i=0; i other_array -> -1, 0, +1 * * Comparison---Returns an integer (-1, 0, * or +1) if this array is less than, equal to, or greater than * other_array. Each object in each array is compared * (using <=>). If any value isn't * equal, then that inequality is the return value. If all the * values found are equal, then the return is based on a * comparison of the array lengths. Thus, two arrays are * ``equal'' according to Array#<=> if and only if they have * the same length and the value of each element is equal to the * value of the corresponding element in the other array. * * [ "a", "a", "c" ] <=> [ "a", "b", "c" ] #=> -1 * [ 1, 2, 3, 4, 5, 6 ] <=> [ 1, 2 ] #=> +1 * */ VALUE rb_ary_cmp(ary1, ary2) VALUE ary1, ary2; { long len; VALUE v; ary2 = to_ary(ary2); if (ary1 == ary2) return INT2FIX(0); v = rb_exec_recursive(recursive_cmp, ary1, ary2); if (v != Qundef) return v; len = RARRAY(ary1)->len - RARRAY(ary2)->len; if (len == 0) return INT2FIX(0); if (len > 0) return INT2FIX(1); return INT2FIX(-1); } static VALUE ary_make_hash(ary1, ary2) VALUE ary1, ary2; { VALUE hash = rb_hash_new(); long i; for (i=0; ilen; i++) { rb_hash_aset(hash, RARRAY(ary1)->ptr[i], Qtrue); } if (ary2) { for (i=0; ilen; i++) { rb_hash_aset(hash, RARRAY(ary2)->ptr[i], Qtrue); } } return hash; } /* * call-seq: * array - other_array -> an_array * * Array Difference---Returns a new array that is a copy of * the original array, removing any items that also appear in * other_array. (If you need set-like behavior, see the * library class Set.) * * [ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ] #=> [ 3, 3, 5 ] */ static VALUE rb_ary_diff(ary1, ary2) VALUE ary1, ary2; { VALUE ary3; volatile VALUE hash; long i; hash = ary_make_hash(to_ary(ary2), 0); ary3 = rb_ary_new(); for (i=0; ilen; i++) { if (st_lookup(RHASH(hash)->tbl, RARRAY(ary1)->ptr[i], 0)) continue; rb_ary_push(ary3, rb_ary_elt(ary1, i)); } return ary3; } /* * call-seq: * array & other_array * * Set Intersection---Returns a new array * containing elements common to the two arrays, with no duplicates. * * [ 1, 1, 3, 5 ] & [ 1, 2, 3 ] #=> [ 1, 3 ] */ static VALUE rb_ary_and(ary1, ary2) VALUE ary1, ary2; { VALUE hash, ary3, v, vv; long i; ary2 = to_ary(ary2); ary3 = rb_ary_new2(RARRAY(ary1)->len < RARRAY(ary2)->len ? RARRAY(ary1)->len : RARRAY(ary2)->len); hash = ary_make_hash(ary2, 0); for (i=0; ilen; i++) { v = vv = rb_ary_elt(ary1, i); if (st_delete(RHASH(hash)->tbl, (st_data_t*)&vv, 0)) { rb_ary_push(ary3, v); } } return ary3; } /* * call-seq: * array | other_array -> an_array * * Set Union---Returns a new array by joining this array with * other_array, removing duplicates. * * [ "a", "b", "c" ] | [ "c", "d", "a" ] * #=> [ "a", "b", "c", "d" ] */ static VALUE rb_ary_or(ary1, ary2) VALUE ary1, ary2; { VALUE hash, ary3; VALUE v, vv; long i; ary2 = to_ary(ary2); ary3 = rb_ary_new2(RARRAY(ary1)->len+RARRAY(ary2)->len); hash = ary_make_hash(ary1, ary2); for (i=0; ilen; i++) { v = vv = rb_ary_elt(ary1, i); if (st_delete(RHASH(hash)->tbl, (st_data_t*)&vv, 0)) { rb_ary_push(ary3, v); } } for (i=0; ilen; i++) { v = vv = rb_ary_elt(ary2, i); if (st_delete(RHASH(hash)->tbl, (st_data_t*)&vv, 0)) { rb_ary_push(ary3, v); } } return ary3; } /* * call-seq: * array.uniq! -> array or nil * * Removes duplicate elements from _self_. * Returns nil if no changes are made (that is, no * duplicates are found). * * a = [ "a", "a", "b", "b", "c" ] * a.uniq! #=> ["a", "b", "c"] * b = [ "a", "b", "c" ] * b.uniq! #=> nil */ static VALUE rb_ary_uniq_bang(ary) VALUE ary; { VALUE hash, v, vv; long i, j; hash = ary_make_hash(ary, 0); if (RARRAY(ary)->len == RHASH(hash)->tbl->num_entries) { return Qnil; } for (i=j=0; ilen; i++) { v = vv = rb_ary_elt(ary, i); if (st_delete(RHASH(hash)->tbl, (st_data_t*)&vv, 0)) { rb_ary_store(ary, j++, v); } } RARRAY(ary)->len = j; return ary; } /* * call-seq: * array.uniq -> an_array * * Returns a new array by removing duplicate values in self. * * a = [ "a", "a", "b", "b", "c" ] * a.uniq #=> ["a", "b", "c"] */ static VALUE rb_ary_uniq(ary) VALUE ary; { ary = rb_ary_dup(ary); rb_ary_uniq_bang(ary); return ary; } /* * call-seq: * array.compact! -> array or nil * * Removes +nil+ elements from array. * Returns +nil+ if no changes were made. * * [ "a", nil, "b", nil, "c" ].compact! #=> [ "a", "b", "c" ] * [ "a", "b", "c" ].compact! #=> nil */ static VALUE rb_ary_compact_bang(ary) VALUE ary; { VALUE *p, *t, *end; rb_ary_modify(ary); p = t = RARRAY(ary)->ptr; end = p + RARRAY(ary)->len; while (t < end) { if (NIL_P(*t)) t++; else *p++ = *t++; } if (RARRAY(ary)->len == (p - RARRAY(ary)->ptr)) { return Qnil; } RARRAY(ary)->len = RARRAY(ary)->aux.capa = (p - RARRAY(ary)->ptr); REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len); return ary; } /* * call-seq: * array.compact -> an_array * * Returns a copy of _self_ with all +nil+ elements removed. * * [ "a", nil, "b", nil, "c", nil ].compact * #=> [ "a", "b", "c" ] */ static VALUE rb_ary_compact(ary) VALUE ary; { ary = rb_ary_dup(ary); rb_ary_compact_bang(ary); return ary; } /* * call-seq: * array.nitems -> int * * Returns the number of non-nil elements in _self_. * * May be zero. * * [ 1, nil, 3, nil, 5 ].nitems #=> 3 */ static VALUE rb_ary_nitems(ary) VALUE ary; { long n = 0; VALUE *p, *pend; for (p = RARRAY(ary)->ptr, pend = p + RARRAY(ary)->len; p < pend; p++) { if (!NIL_P(*p)) n++; } return LONG2NUM(n); } /* * call-seq: * array.count -> int * array.count(obj) -> int * array.count { |item| block } -> int * * Returns the number of elements. If an argument is given, counts * the number of elements which equals to obj. If a block is * given, counts the number of elements yielding a true value. * * ary = [1, 2, 4, 2] * ary.count # => 4 * ary.count(2) # => 2 * ary.count{|x|x%2==0} # => 3 * */ static VALUE rb_ary_count(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { long n = 0; if (argc == 0) { VALUE *p, *pend; if (!rb_block_given_p()) return LONG2NUM(RARRAY_LEN(ary)); for (p = RARRAY_PTR(ary), pend = p + RARRAY_LEN(ary); p < pend; p++) { if (RTEST(rb_yield(*p))) n++; } } else { VALUE obj, *p, *pend; rb_scan_args(argc, argv, "1", &obj); if (rb_block_given_p()) { rb_warn("given block not used"); } for (p = RARRAY_PTR(ary), pend = p + RARRAY_LEN(ary); p < pend; p++) { if (rb_equal(*p, obj)) n++; } } return LONG2NUM(n); } static VALUE flatten(ary, level, modified) VALUE ary; int level; int *modified; { long i = 0; VALUE stack, result, tmp, elt; st_table *memo; st_data_t id; stack = ary_new(0, ARY_DEFAULT_SIZE); result = ary_new(0, RARRAY_LEN(ary)); memo = st_init_numtable(); st_insert(memo, (st_data_t)ary, (st_data_t)Qtrue); *modified = 0; while (1) { while (i < RARRAY(ary)->len) { elt = RARRAY(ary)->ptr[i++]; tmp = rb_check_array_type(elt); if (RBASIC(result)->klass) { rb_raise(rb_eRuntimeError, "flatten reentered"); } if (NIL_P(tmp) || (level >= 0 && RARRAY(stack)->len / 2 >= level)) { rb_ary_push(result, elt); } else { *modified = 1; id = (st_data_t)tmp; if (st_lookup(memo, id, 0)) { st_free_table(memo); rb_raise(rb_eArgError, "tried to flatten recursive array"); } st_insert(memo, id, (st_data_t)Qtrue); rb_ary_push(stack, ary); rb_ary_push(stack, LONG2NUM(i)); ary = tmp; i = 0; } } if (RARRAY(stack)->len == 0) { break; } id = (st_data_t)ary; st_delete(memo, &id, 0); tmp = rb_ary_pop(stack); i = NUM2LONG(tmp); ary = rb_ary_pop(stack); } st_free_table(memo); RBASIC(result)->klass = rb_class_of(ary); return result; } /* * call-seq: * array.flatten! -> array or nil * array.flatten!(level) -> array or nil * * Flattens _self_ in place. * Returns nil if no modifications were made (i.e., * array contains no subarrays.) If the optional level * argument determines the level of recursion to flatten. * * a = [ 1, 2, [3, [4, 5] ] ] * a.flatten! #=> [1, 2, 3, 4, 5] * a.flatten! #=> nil * a #=> [1, 2, 3, 4, 5] * a = [ 1, 2, [3, [4, 5] ] ] * a.flatten!(1) #=> [1, 2, 3, [4, 5]] */ static VALUE rb_ary_flatten_bang(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { int mod = 0, level = -1; VALUE result, lv; rb_scan_args(argc, argv, "01", &lv); if (!NIL_P(lv)) level = NUM2INT(lv); if (level == 0) return ary; result = flatten(ary, level, &mod); if (mod == 0) return Qnil; rb_ary_replace(ary, result); return ary; } /* * call-seq: * array.flatten -> an_array * array.flatten(level) -> an_array * * Returns a new array that is a one-dimensional flattening of this * array (recursively). That is, for every element that is an array, * extract its elements into the new array. If the optional * level argument determines the level of recursion to flatten. * * s = [ 1, 2, 3 ] #=> [1, 2, 3] * t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]] * a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10] * a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] * a = [ 1, 2, [3, [4, 5] ] ] * a.flatten(1) #=> [1, 2, 3, [4, 5]] */ static VALUE rb_ary_flatten(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { int mod = 0, level = -1; VALUE result, lv; rb_scan_args(argc, argv, "01", &lv); if (!NIL_P(lv)) level = NUM2INT(lv); if (level == 0) return ary; result = flatten(ary, level, &mod); if (OBJ_TAINTED(ary)) OBJ_TAINT(result); return result; } /* * call-seq: * array.shuffle! -> array or nil * * Shuffles elements in _self_ in place. */ static VALUE rb_ary_shuffle_bang(ary) VALUE ary; { long i = RARRAY(ary)->len; rb_ary_modify(ary); while (i) { long j = rb_genrand_real()*i; VALUE tmp = RARRAY(ary)->ptr[--i]; RARRAY(ary)->ptr[i] = RARRAY(ary)->ptr[j]; RARRAY(ary)->ptr[j] = tmp; } return ary; } /* * call-seq: * array.shuffle -> an_array * * Returns a new array with elements of this array shuffled. * * a = [ 1, 2, 3 ] #=> [1, 2, 3] * a.shuffle #=> [2, 3, 1] */ static VALUE rb_ary_shuffle(VALUE ary) { ary = rb_ary_dup(ary); rb_ary_shuffle_bang(ary); return ary; } /* * call-seq: * array.choice -> obj * * Choose a random element from an array. */ static VALUE rb_ary_choice(ary) VALUE ary; { long i, j; i = RARRAY(ary)->len; if (i == 0) return Qnil; j = rb_genrand_real()*i; return RARRAY(ary)->ptr[j]; } /* * call-seq: * ary.cycle {|obj| block } * ary.cycle(n) {|obj| block } * * Calls block for each element repeatedly _n_ times or * forever if none or nil is given. If a non-positive number is * given or the array is empty, does nothing. Returns nil if the * loop has finished without getting interrupted. * * a = ["a", "b", "c"] * a.cycle {|x| puts x } # print, a, b, c, a, b, c,.. forever. * a.cycle(2) {|x| puts x } # print, a, b, c, a, b, c. * */ static VALUE rb_ary_cycle(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { long n, i; VALUE nv = Qnil; rb_scan_args(argc, argv, "01", &nv); RETURN_ENUMERATOR(ary, argc, argv); if (NIL_P(nv)) { n = -1; } else { n = NUM2LONG(nv); if (n <= 0) return Qnil; } while (RARRAY(ary)->len > 0 && (n < 0 || 0 < n--)) { for (i=0; ilen; i++) { rb_yield(RARRAY(ary)->ptr[i]); } } return Qnil; } #define tmpbuf(n, size) rb_str_tmp_new((n)*(size)) /* * Recursively compute permutations of r elements of the set [0..n-1]. * When we have a complete permutation of array indexes, copy the values * at those indexes into a new array and yield that array. * * n: the size of the set * r: the number of elements in each permutation * p: the array (of size r) that we're filling in * index: what index we're filling in now * used: an array of booleans: whether a given index is already used * values: the Ruby array that holds the actual values to permute */ static void permute0(n, r, p, index, used, values) long n, r, *p, index; int *used; VALUE values; { long i,j; for (i = 0; i < n; i++) { if (used[i] == 0) { p[index] = i; if (index < r-1) { /* if not done yet */ used[i] = 1; /* mark index used */ permute0(n, r, p, index+1, /* recurse */ used, values); used[i] = 0; /* index unused */ } else { /* We have a complete permutation of array indexes */ /* Build a ruby array of the corresponding values */ /* And yield it to the associated block */ VALUE result = rb_ary_new2(r); VALUE *result_array = RARRAY(result)->ptr; const VALUE *values_array = RARRAY(values)->ptr; for (j = 0; j < r; j++) result_array[j] = values_array[p[j]]; RARRAY(result)->len = r; rb_yield(result); } } } } /* * call-seq: * ary.permutation { |p| block } -> array * ary.permutation -> enumerator * ary.permutation(n) { |p| block } -> array * ary.permutation(n) -> enumerator * * When invoked with a block, yield all permutations of length n * of the elements of ary, then return the array itself. * If n is not specified, yield all permutations of all elements. * The implementation makes no guarantees about the order in which * the permutations are yielded. * * When invoked without a block, return an enumerator object instead. * * Examples: * * a = [1, 2, 3] * a.permutation.to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] * a.permutation(1).to_a #=> [[1],[2],[3]] * a.permutation(2).to_a #=> [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]] * a.permutation(3).to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] * a.permutation(0).to_a #=> [[]] # one permutation of length 0 * a.permutation(4).to_a #=> [] # no permutations of length 4 */ static VALUE rb_ary_permutation(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { VALUE num; long r, n, i; n = RARRAY(ary)->len; /* Array length */ RETURN_ENUMERATOR(ary, argc, argv); /* Return enumerator if no block */ rb_scan_args(argc, argv, "01", &num); r = NIL_P(num) ? n : NUM2LONG(num); /* Permutation size from argument */ if (r < 0 || n < r) { /* no permutations: yield nothing */ } else if (r == 0) { /* exactly one permutation: the zero-length array */ rb_yield(rb_ary_new2(0)); } else if (r == 1) { /* this is a special, easy case */ for (i = 0; i < RARRAY(ary)->len; i++) { rb_yield(rb_ary_new3(1, RARRAY(ary)->ptr[i])); } } else { /* this is the general case */ volatile VALUE t0 = tmpbuf(n,sizeof(long)); long *p = (long*)RSTRING(t0)->ptr; volatile VALUE t1 = tmpbuf(n,sizeof(int)); int *used = (int*)RSTRING(t1)->ptr; VALUE ary0 = ary_make_shared(ary); /* private defensive copy of ary */ for (i = 0; i < n; i++) used[i] = 0; /* initialize array */ permute0(n, r, p, 0, used, ary0); /* compute and yield permutations */ RB_GC_GUARD(t0); RB_GC_GUARD(t1); } return ary; } static long combi_len(n, k) long n, k; { long i, val = 1; if (k*2 > n) k = n-k; if (k == 0) return 1; if (k < 0) return 0; val = 1; for (i=1; i <= k; i++,n--) { long m = val; val *= n; if (val < m) { rb_raise(rb_eRangeError, "too big for combination"); } val /= i; } return val; } /* * call-seq: * ary.combination(n) { |c| block } -> ary * ary.combination(n) -> enumerator * * When invoked with a block, yields all combinations of length n * of elements from ary and then returns ary itself. * The implementation makes no guarantees about the order in which * the combinations are yielded. * * When invoked without a block, returns an enumerator object instead. * * Examples: * * a = [1, 2, 3, 4] * a.combination(1).to_a #=> [[1],[2],[3],[4]] * a.combination(2).to_a #=> [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]] * a.combination(3).to_a #=> [[1,2,3],[1,2,4],[1,3,4],[2,3,4]] * a.combination(4).to_a #=> [[1,2,3,4]] * a.combination(0).to_a #=> [[]] # one combination of length 0 * a.combination(5).to_a #=> [] # no combinations of length 5 * */ static VALUE rb_ary_combination(ary, num) VALUE ary; VALUE num; { long n, i, len; n = NUM2LONG(num); RETURN_ENUMERATOR(ary, 1, &num); len = RARRAY(ary)->len; if (n < 0 || len < n) { /* yield nothing */ } else if (n == 0) { rb_yield(rb_ary_new2(0)); } else if (n == 1) { for (i = 0; i < len; i++) { rb_yield(rb_ary_new3(1, RARRAY(ary)->ptr[i])); } } else { volatile VALUE t0 = tmpbuf(n+1, sizeof(long)); long *stack = (long*)RSTRING(t0)->ptr; long nlen = combi_len(len, n); volatile VALUE cc = rb_ary_new2(n); VALUE *chosen = RARRAY(cc)->ptr; long lev = 0; RBASIC(cc)->klass = 0; MEMZERO(stack, long, n); stack[0] = -1; for (i = 0; i < nlen; i++) { chosen[lev] = RARRAY(ary)->ptr[stack[lev+1]]; for (lev++; lev < n; lev++) { chosen[lev] = RARRAY(ary)->ptr[stack[lev+1] = stack[lev]+1]; } rb_yield(rb_ary_new4(n, chosen)); do { stack[lev--]++; } while (lev && (stack[lev+1]+n == len+lev+1)); } } return ary; } /* * call-seq: * ary.product(other_ary, ...) * * Returns an array of all combinations of elements from all arrays. * The length of the returned array is the product of the length * of ary and the argument arrays * * [1,2,3].product([4,5]) # => [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]] * [1,2].product([1,2]) # => [[1,1],[1,2],[2,1],[2,2]] * [1,2].product([3,4],[5,6]) # => [[1,3,5],[1,3,6],[1,4,5],[1,4,6], * # [2,3,5],[2,3,6],[2,4,5],[2,4,6]] * [1,2].product() # => [[1],[2]] * [1,2].product([]) # => [] */ static VALUE rb_ary_product(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { int n = argc+1; /* How many arrays we're operating on */ volatile VALUE t0 = tmpbuf(n, sizeof(VALUE)); volatile VALUE t1 = tmpbuf(n, sizeof(int)); VALUE *arrays = (VALUE*)RSTRING(t0)->ptr; /* The arrays we're computing the product of */ int *counters = (int*)RSTRING(t1)->ptr; /* The current position in each one */ VALUE result; /* The array we'll be returning */ long i,j; long resultlen = 1; RBASIC(t0)->klass = 0; RBASIC(t1)->klass = 0; /* initialize the arrays of arrays */ arrays[0] = ary; for (i = 1; i < n; i++) arrays[i] = to_ary(argv[i-1]); /* initialize the counters for the arrays */ for (i = 0; i < n; i++) counters[i] = 0; /* Compute the length of the result array; return [] if any is empty */ for (i = 0; i < n; i++) { long k = RARRAY(arrays[i])->len, l = resultlen; if (k == 0) return rb_ary_new2(0); resultlen *= k; if (resultlen < k || resultlen < l || resultlen / k != l) { rb_raise(rb_eRangeError, "too big to product"); } } /* Otherwise, allocate and fill in an array of results */ result = rb_ary_new2(resultlen); for (i = 0; i < resultlen; i++) { int m; /* fill in one subarray */ VALUE subarray = rb_ary_new2(n); for (j = 0; j < n; j++) { rb_ary_push(subarray, rb_ary_entry(arrays[j], counters[j])); } /* put it on the result array */ rb_ary_push(result, subarray); /* * Increment the last counter. If it overflows, reset to 0 * and increment the one before it. */ m = n-1; counters[m]++; while (m > 0 && counters[m] == RARRAY(arrays[m])->len) { counters[m] = 0; m--; counters[m]++; } } return result; } /* * call-seq: * ary.take(n) => array * * Returns first n elements from ary. * * a = [1, 2, 3, 4, 5, 0] * a.take(3) # => [1, 2, 3] * */ static VALUE rb_ary_take(obj, n) VALUE obj; VALUE n; { long len = NUM2LONG(n); if (len < 0) { rb_raise(rb_eArgError, "attempt to take negative size"); } return rb_ary_subseq(obj, 0, len); } /* * call-seq: * ary.take_while {|arr| block } => array * * Passes elements to the block until the block returns nil or false, * then stops iterating and returns an array of all prior elements. * * a = [1, 2, 3, 4, 5, 0] * a.take_while {|i| i < 3 } # => [1, 2] * */ static VALUE rb_ary_take_while(ary) VALUE ary; { long i; RETURN_ENUMERATOR(ary, 0, 0); for (i = 0; i < RARRAY(ary)->len; i++) { if (!RTEST(rb_yield(RARRAY(ary)->ptr[i]))) break; } return rb_ary_take(ary, LONG2FIX(i)); } /* * call-seq: * ary.drop(n) => array * * Drops first n elements from ary, and returns rest elements * in an array. * * a = [1, 2, 3, 4, 5, 0] * a.drop(3) # => [4, 5, 0] * */ static VALUE rb_ary_drop(ary, n) VALUE ary; VALUE n; { VALUE result; long pos = NUM2LONG(n); if (pos < 0) { rb_raise(rb_eArgError, "attempt to drop negative size"); } result = rb_ary_subseq(ary, pos, RARRAY(ary)->len); if (result == Qnil) result = rb_ary_new(); return result; } /* * call-seq: * ary.drop_while {|arr| block } => array * * Drops elements up to, but not including, the first element for * which the block returns nil or false and returns an array * containing the remaining elements. * * a = [1, 2, 3, 4, 5, 0] * a.drop_while {|i| i < 3 } # => [3, 4, 5, 0] * */ static VALUE rb_ary_drop_while(ary) VALUE ary; { long i; RETURN_ENUMERATOR(ary, 0, 0); for (i = 0; i < RARRAY(ary)->len; i++) { if (!RTEST(rb_yield(RARRAY(ary)->ptr[i]))) break; } return rb_ary_drop(ary, LONG2FIX(i)); } /* Arrays are ordered, integer-indexed collections of any object. * Array indexing starts at 0, as in C or Java. A negative index is * assumed to be relative to the end of the array---that is, an index of -1 * indicates the last element of the array, -2 is the next to last * element in the array, and so on. */ void Init_Array() { rb_cArray = rb_define_class("Array", rb_cObject); rb_include_module(rb_cArray, rb_mEnumerable); rb_define_alloc_func(rb_cArray, ary_alloc); rb_define_singleton_method(rb_cArray, "[]", rb_ary_s_create, -1); rb_define_method(rb_cArray, "initialize", rb_ary_initialize, -1); rb_define_method(rb_cArray, "initialize_copy", rb_ary_replace, 1); rb_define_method(rb_cArray, "to_s", rb_ary_to_s, 0); rb_define_method(rb_cArray, "inspect", rb_ary_inspect, 0); rb_define_method(rb_cArray, "to_a", rb_ary_to_a, 0); rb_define_method(rb_cArray, "to_ary", rb_ary_to_ary_m, 0); rb_define_method(rb_cArray, "frozen?", rb_ary_frozen_p, 0); rb_define_method(rb_cArray, "==", rb_ary_equal, 1); rb_define_method(rb_cArray, "eql?", rb_ary_eql, 1); rb_define_method(rb_cArray, "hash", rb_ary_hash, 0); rb_define_method(rb_cArray, "[]", rb_ary_aref, -1); rb_define_method(rb_cArray, "[]=", rb_ary_aset, -1); rb_define_method(rb_cArray, "at", rb_ary_at, 1); rb_define_method(rb_cArray, "fetch", rb_ary_fetch, -1); rb_define_method(rb_cArray, "first", rb_ary_first, -1); rb_define_method(rb_cArray, "last", rb_ary_last, -1); rb_define_method(rb_cArray, "concat", rb_ary_concat, 1); rb_define_method(rb_cArray, "<<", rb_ary_push, 1); rb_define_method(rb_cArray, "push", rb_ary_push_m, -1); rb_define_method(rb_cArray, "pop", rb_ary_pop_m, -1); rb_define_method(rb_cArray, "shift", rb_ary_shift_m, -1); rb_define_method(rb_cArray, "unshift", rb_ary_unshift_m, -1); rb_define_method(rb_cArray, "insert", rb_ary_insert, -1); rb_define_method(rb_cArray, "each", rb_ary_each, 0); rb_define_method(rb_cArray, "each_index", rb_ary_each_index, 0); rb_define_method(rb_cArray, "reverse_each", rb_ary_reverse_each, 0); rb_define_method(rb_cArray, "length", rb_ary_length, 0); rb_define_alias(rb_cArray, "size", "length"); rb_define_method(rb_cArray, "empty?", rb_ary_empty_p, 0); rb_define_method(rb_cArray, "find_index", rb_ary_index, -1); rb_define_method(rb_cArray, "index", rb_ary_index, -1); rb_define_method(rb_cArray, "rindex", rb_ary_rindex, -1); rb_define_method(rb_cArray, "indexes", rb_ary_indexes, -1); rb_define_method(rb_cArray, "indices", rb_ary_indexes, -1); rb_define_method(rb_cArray, "join", rb_ary_join_m, -1); rb_define_method(rb_cArray, "reverse", rb_ary_reverse_m, 0); rb_define_method(rb_cArray, "reverse!", rb_ary_reverse_bang, 0); rb_define_method(rb_cArray, "sort", rb_ary_sort, 0); rb_define_method(rb_cArray, "sort!", rb_ary_sort_bang, 0); rb_define_method(rb_cArray, "collect", rb_ary_collect, 0); rb_define_method(rb_cArray, "collect!", rb_ary_collect_bang, 0); rb_define_method(rb_cArray, "map", rb_ary_collect, 0); rb_define_method(rb_cArray, "map!", rb_ary_collect_bang, 0); rb_define_method(rb_cArray, "select", rb_ary_select, 0); rb_define_method(rb_cArray, "values_at", rb_ary_values_at, -1); rb_define_method(rb_cArray, "delete", rb_ary_delete, 1); rb_define_method(rb_cArray, "delete_at", rb_ary_delete_at_m, 1); rb_define_method(rb_cArray, "delete_if", rb_ary_delete_if, 0); rb_define_method(rb_cArray, "reject", rb_ary_reject, 0); rb_define_method(rb_cArray, "reject!", rb_ary_reject_bang, 0); rb_define_method(rb_cArray, "zip", rb_ary_zip, -1); rb_define_method(rb_cArray, "transpose", rb_ary_transpose, 0); rb_define_method(rb_cArray, "replace", rb_ary_replace, 1); rb_define_method(rb_cArray, "clear", rb_ary_clear, 0); rb_define_method(rb_cArray, "fill", rb_ary_fill, -1); rb_define_method(rb_cArray, "include?", rb_ary_includes, 1); rb_define_method(rb_cArray, "<=>", rb_ary_cmp, 1); rb_define_method(rb_cArray, "slice", rb_ary_aref, -1); rb_define_method(rb_cArray, "slice!", rb_ary_slice_bang, -1); rb_define_method(rb_cArray, "assoc", rb_ary_assoc, 1); rb_define_method(rb_cArray, "rassoc", rb_ary_rassoc, 1); rb_define_method(rb_cArray, "+", rb_ary_plus, 1); rb_define_method(rb_cArray, "*", rb_ary_times, 1); rb_define_method(rb_cArray, "-", rb_ary_diff, 1); rb_define_method(rb_cArray, "&", rb_ary_and, 1); rb_define_method(rb_cArray, "|", rb_ary_or, 1); rb_define_method(rb_cArray, "uniq", rb_ary_uniq, 0); rb_define_method(rb_cArray, "uniq!", rb_ary_uniq_bang, 0); rb_define_method(rb_cArray, "compact", rb_ary_compact, 0); rb_define_method(rb_cArray, "compact!", rb_ary_compact_bang, 0); rb_define_method(rb_cArray, "flatten", rb_ary_flatten, -1); rb_define_method(rb_cArray, "flatten!", rb_ary_flatten_bang, -1); rb_define_method(rb_cArray, "nitems", rb_ary_nitems, 0); rb_define_method(rb_cArray, "count", rb_ary_count, -1); rb_define_method(rb_cArray, "shuffle!", rb_ary_shuffle_bang, 0); rb_define_method(rb_cArray, "shuffle", rb_ary_shuffle, 0); rb_define_method(rb_cArray, "choice", rb_ary_choice, 0); rb_define_method(rb_cArray, "cycle", rb_ary_cycle, -1); rb_define_method(rb_cArray, "permutation", rb_ary_permutation, -1); rb_define_method(rb_cArray, "combination", rb_ary_combination, 1); rb_define_method(rb_cArray, "product", rb_ary_product, -1); rb_define_method(rb_cArray, "take", rb_ary_take, 1); rb_define_method(rb_cArray, "take_while", rb_ary_take_while, 0); rb_define_method(rb_cArray, "drop", rb_ary_drop, 1); rb_define_method(rb_cArray, "drop_while", rb_ary_drop_while, 0); id_cmp = rb_intern("<=>"); inspect_key = rb_intern("__inspect_key__"); } ================================================ FILE: b/source/stack_free_safe.sh ================================================ #!/bin/bash set -x set -e; make optflags='-DSTACK_FREE_SAFE_DEBUG=1' && sudo make install; set +e #set -e; make optflags='-DXXXSTACK_FREE_SAFE_DEBUG=1' && sudo make install; set +e PATH="/cnu/PACKAGES/ruby-ree-1.8.7-p253-thread-2-debian5/bin:$PATH" make test-all 2>&1 | tee log.txt grep 'calling stack_free' log.txt | wc -l grep 'calling stack_free' log.txt | grep stack_free_safe_all_dead_threads | wc -l ================================================ FILE: bcc32/Makefile.sub ================================================ # -*- makefile -*- SHELL = $(COMSPEC) MKFILES = Makefile #### Start of system configuration section. #### !ifndef OS OS = bccwin32 !endif !if !defined(RT) !error RT not defined. Retry from configure pass. !endif ## variables may be overridden by $(compile_dir)/Makefile !ifndef srcdir srcdir = .. !endif !ifndef RUBY_INSTALL_NAME RUBY_INSTALL_NAME = ruby !endif !ifndef RUBYW_INSTALL_NAME RUBYW_INSTALL_NAME = $(RUBY_INSTALL_NAME:ruby=rubyw) !elif "$(RUBYW_INSTALL_NAME)" == "$(RUBY_INSTALL_NAME)" RUBYW_INSTALL_NAME = $(RUBY_INSTALL_NAME:ruby=rubyw) !endif !if "$(RUBYW_INSTALL_NAME)" == "$(RUBY_INSTALL_NAME)" RUBYW_INSTALL_NAME = $(RUBY_INSTALL_NAME)w !endif !ifndef RUBY_SO_NAME RUBY_SO_NAME = $(RT)-$(RUBY_INSTALL_NAME)$(MAJOR)$(MINOR) !endif !ifndef icondirs !ifdef ICONDIRS icondirs=$(ICONDIRS) !endif !endif !ifdef icondirs icondirs=$(icondirs:\=/) iconinc=-I$(icondirs: = -I) !endif ############### VPATH = $(srcdir):$(srcdir)/missing .SUFFIXES: .y !ifndef CC CC = bcc32 !endif !ifndef CPP CPP = cpp32 !endif !ifndef RC RC = brcc32 !endif !ifndef YACC YACC = byacc !endif !ifndef AR AR = tlib !endif PURIFY = AUTOCONF = autoconf RM = $(srcdir:/=\)\win32\rm.bat !if !defined(PROCESSOR_ARCHITECTURE) PROCESSOR_ARCHITECTURE = x86 !endif MACHINE = $(PROCESSOR_ARCHITECTURE) !if "$(PROCESSOR_ARCHITECTURE)" == "x86" !ifndef PROCESSOR_LEVEL PROCESSOR_LEVEL = 5 !endif !if 6 < $(PROCESSOR_LEVEL) PROCESSOR_LEVEL = 6 !endif PROCESSOR_FLAG = -$(PROCESSOR_LEVEL) CPU = i$(PROCESSOR_LEVEL)86 ARCH = i386 !else CPU = $(PROCESSOR_ARCHITECTURE) ARCH = $(PROCESSOR_ARCHITECTURE) !endif !ifndef DEBUGFLAGS DEBUGFLAGS = !endif !ifndef OPTFLAGS OPTFLAGS = -O !endif !ifndef prefix prefix = /usr !endif !ifndef exec_prefix exec_prefix = $(prefix) !endif !ifndef libdir libdir = $(exec_prefix)/lib !endif !if !defined(datadir) datadir = /share !endif !ifndef EXTOUT EXTOUT = .ext !endif !ifndef RIDATADIR RIDATADIR = $(DESTDIR)$(datadir)/ri/$(MAJOR).$(MINOR)/system !endif !ifndef TESTUI TESTUI = console !endif !ifndef TESTS TESTS = !endif !ifndef RDOCTARGET RDOCTARGET = install-nodoc !endif OUTFLAG = -o !ifndef CFLAGS CFLAGS = -q -tWR -tWC $(DEBUGFLAGS) $(OPTFLAGS) $(PROCESSOR_FLAG) -w- -wsus -wcpt -wdup -wext -wrng -wrpt -wzdi !endif !ifndef LDFLAGS LDFLAGS = -S:$(STACK) !endif !ifndef RFLAGS RFLAGS = $(iconinc) !endif !ifndef EXTLIBS EXTLIBS = !endif !ifndef MEMLIB MEMLIB = !endif LIBS = $(MEMLIB) cw32i.lib import32.lib ws2_32.lib $(EXTLIBS) MISSING = acosh.obj crypt.obj erf.obj win32.obj !ifndef STACK STACK = 0x2000000 !endif XCFLAGS = -DRUBY_EXPORT -I. -I$(srcdir) -I$(srcdir)/missing ARFLAGS = /a /p32 LD = ilink32 -q -Gn LDSHARED = $(LD) XLDFLAGS = -Tpe c0x32.obj WLDFLAGS = -aa -Tpe c0w32.obj DLDFLAGS = -Tpd c0d32.obj LIBRUBY_LDSHARED = $(LDSHARED) LIBRUBY_DLDFLAGS = -Gi $(DLDFLAGS) $(EXTLDFLAGS) LDOBJECTS = $(MAINOBJ) SOLIBS = EXEEXT = .exe PROGRAM=$(RUBY_INSTALL_NAME)$(EXEEXT) WPROGRAM=$(RUBYW_INSTALL_NAME)$(EXEEXT) RUBYDEF = $(RUBY_SO_NAME).def MINIRUBY = .\miniruby$(EXEEXT) -I$(srcdir)/lib $(MINIRUBYOPT) RUNRUBY = .\$(PROGRAM) "$(srcdir)/runruby.rb" --extout="$(EXTOUT)" -- ORGLIBPATH = $(LIB) #### End of system configuration section. #### LIBRUBY_A = $(RUBY_SO_NAME)-static.lib LIBRUBY_SO = $(RUBY_SO_NAME).dll LIBRUBY = $(RUBY_SO_NAME).lib LIBRUBYARG = $(LIBRUBY) PREP = miniruby$(EXEEXT) OBJEXT = obj INSTALLED_LIST= .installed.list WINMAINOBJ = winmain.$(OBJEXT) MINIOBJS = dmydln.$(OBJEXT) .path.c = .;$(srcdir);$(srcdir)/win32;$(srcdir)/missing .path.h = .;$(srcdir);$(srcdir)/win32;$(srcdir)/missing .path.y = $(srcdir) .path. = $(srcdir) .c.obj: $(CC) $(CFLAGS) $(XCFLAGS) -I. $(CPPFLAGS) -c $(<:/=\) .rc.res: $(RC) $(RFLAGS) -I. -I$( $(@F) @del y.tab.c all: $(srcdir)/bcc32/Makefile.sub $(srcdir)/common.mk ruby: $(PROGRAM) rubyw: $(WPROGRAM) !include $(srcdir)/common.mk $(MKFILES): $(srcdir)/bcc32/Makefile.sub $(srcdir)/bcc32/configure.bat $(srcdir)/bcc32/setup.mak $(COMSPEC) /C $(srcdir:/=\)\bcc32\configure.bat $(configure_args) @echo $(MKFILES) should be updated, re-run $(MAKE). @$(MAKE) > nul -q -f &&| PHONY: nul @exit | CONFIG_H = ./.config.h.time config: config.status config.status: $(CONFIG_H) $(CONFIG_H): $(MKFILES) $(srcdir)/bcc32/Makefile.sub @$(srcdir:/=\)\win32\ifchange.bat config.h &&| \#define HAVE_SYS_TYPES_H 1 \#define HAVE_SYS_STAT_H 1 \#define HAVE_STDLIB_H 1 \#define HAVE_STRING_H 1 \#define HAVE_MEMORY_H 1 \#define HAVE_OFF_T 1 \#define SIZEOF_INT 4 \#define SIZEOF_SHORT 2 \#define SIZEOF_LONG 4 \#define SIZEOF_LONG_LONG 0 \#define SIZEOF___INT64 8 \#define SIZEOF_OFF_T 4 \#define SIZEOF_VOIDP 4 \#define SIZEOF_FLOAT 4 \#define SIZEOF_DOUBLE 8 \#define SIZEOF_TIME_T 4 \#define HAVE_PROTOTYPES 1 \#define TOKEN_PASTE(x,y) x\#\#y \#define HAVE_STDARG_PROTOTYPES 1 \#define NORETURN(x) x \#define RUBY_EXTERN extern __declspec(dllimport) \#define HAVE_DECL_SYS_NERR 1 \#define HAVE_LIMITS_H 1 \#define HAVE_FCNTL_H 1 \#define HAVE_UTIME_H 1 \#define HAVE_FLOAT_H 1 \#define rb_uid_t uid_t \#define rb_gid_t gid_t \#define rb_pid_t int \#define HAVE_STRUCT_STAT_ST_RDEV 1 \#define HAVE_ST_RDEV 1 \#define GETGROUPS_T int \#define RETSIGTYPE void \#define HAVE_ALLOCA 1 \#define HAVE_DUP2 1 \#define HAVE_MEMMOVE 1 \#define HAVE_MKDIR 1 \#define HAVE_STRCASECMP 1 \#define HAVE_STRNCASECMP 1 \#define HAVE_STRERROR 1 \#define HAVE_STRFTIME 1 \#define HAVE_STRCHR 1 \#define HAVE_STRSTR 1 \#define HAVE_STRTOD 1 \#define HAVE_STRTOL 1 \#define HAVE_STRTOUL 1 \#define HAVE_VSNPRINTF 1 \#define HAVE_ISNAN 1 \#define HAVE_FINITE 1 \#define HAVE_HYPOT 1 \#define HAVE_FMOD 1 \#define HAVE_WAITPID 1 \#define HAVE_FSYNC 1 \#define HAVE_GETCWD 1 \#define HAVE_CHSIZE 1 \#define HAVE_TIMES 1 \#define HAVE_FCNTL 1 \#define HAVE_LINK 1 \#define HAVE_TELLDIR 1 \#define HAVE_SEEKDIR 1 \#define HAVE_COSH 1 \#define HAVE_SINH 1 \#define HAVE_TANH 1 \#define RSHIFT(x,y) ((x)>>(int)y) \#define FILE_COUNT level \#define FILE_READPTR curp \#define RUBY_SETJMP(env) _setjmp(env) \#define RUBY_LONGJMP(env,val) longjmp(env,val) \#define RUBY_JMP_BUF jmp_buf \#define inline __inline \#define NEED_IO_SEEK_BETWEEN_RW 1 \#define STACK_GROW_DIRECTION -1 \#define DEFAULT_KCODE KCODE_NONE \#define DLEXT ".so" \#define RUBY_LIB "/lib/ruby/$(MAJOR).$(MINOR)" \#define RUBY_SITE_LIB "/lib/ruby/site_ruby" \#define RUBY_SITE_LIB2 "/lib/ruby/site_ruby/$(MAJOR).$(MINOR)" \#define RUBY_VENDOR_LIB "/lib/ruby/vendor_ruby" \#define RUBY_VENDOR_LIB2 "/lib/ruby/vendor_ruby/$(MAJOR).$(MINOR)" \#define RUBY_PLATFORM "$(ARCH)-$(OS)" \#define RUBY_ARCHLIB "/lib/ruby/$(MAJOR).$(MINOR)/$(ARCH)-$(OS)" \#define RUBY_SITE_ARCHLIB "/lib/ruby/site_ruby/$(MAJOR).$(MINOR)/$(ARCH)-$(OS)" \#define RUBY_VENDOR_ARCHLIB "/lib/ruby/vendor_ruby/$(MAJOR).$(MINOR)/$(ARCH)-$(OS)" | @exit > $@ config.status: $(MKFILES) $(srcdir)/bcc32/Makefile.sub $(srcdir)/common.mk @echo Creating $@ @type > $@ &&| # Generated automatically by Makefile.sub. s,@SHELL@,$$(COMSPEC),;t t s,@BUILD_FILE_SEPARATOR@,\,;t t s,@PATH_SEPARATOR@,;,;t t s,@CFLAGS@,$(CFLAGS),;t t s,@CPPFLAGS@,$(CPPFLAGS),;t t s,@CXXFLAGS@,$(CXXFLAGS),;t t s,@FFLAGS@,$(FFLAGS),;t t s,@LDFLAGS@,,;t t s,@LIBS@,$(LIBS),;t t s,@exec_prefix@,$${prefix},;t t s,@prefix@,,;t t s,@program_transform_name@,s,,,,;t t s,@bindir@,$${exec_prefix}/bin,;t t s,@sbindir@,$${exec_prefix}/sbin,;t t s,@libexecdir@,$${exec_prefix}/libexec,;t t s,@datadir@,$${prefix}/share,;t t s,@sysconfdir@,$${prefix}/etc,;t t s,@sharedstatedir@,/etc,;t t s,@localstatedir@,/var,;t t s,@libdir@,$${exec_prefix}/lib,;t t s,@includedir@,$${prefix}/include,;t t s,@oldincludedir@,/usr/include,;t t s,@infodir@,$${prefix}/info,;t t s,@mandir@,$${prefix}/man,;t t s,@build@,$(CPU)-pc-$(OS),;t t s,@build_alias@,$(CPU)-$(OS),;t t s,@build_cpu@,$(CPU),;t t s,@build_vendor@,pc,;t t s,@build_os@,$(OS),;t t s,@host@,$(CPU)-pc-$(OS),;t t s,@host_alias@,$(CPU)-$(OS),;t t s,@host_cpu@,$(CPU),;t t s,@host_vendor@,pc,;t t s,@host_os@,$(OS),;t t s,@target@,$(ARCH)-pc-$(OS),;t t s,@target_alias@,$(ARCH)-$(OS),;t t s,@target_cpu@,$(ARCH),;t t s,@target_vendor@,pc,;t t s,@target_os@,$(OS),;t t s,@CC@,$(CC),;t t s,@CPP@,cpp32,;t t s,@YACC@,$(YACC),;t t s,@RANLIB@,,;t t s,@AR@,$(AR),;t t s,@ARFLAGS@,$(ARFLAGS) ,;t t s,@LN_S@,$(LN_S),;t t s,@SET_MAKE@,MFLAGS = -$$(MAKEFLAGS),;t t s,@CP@,copy > nul,;t t s,@LIBOBJS@, acosh.obj crypt.obj erf.obj win32.obj,;t t s,@ALLOCA@,$(ALLOCA),;t t s,@DEFAULT_KCODE@,$(DEFAULT_KCODE),;t t s,@EXEEXT@,.exe,;t t s,@OBJEXT@,obj,;t t s,@XCFLAGS@,$(XCFLAGS),;t t s,@XLDFLAGS@,$(XLDFLAGS),;t t s,@DLDFLAGS@,$(DLDFLAGS),;t t s,@ARCH_FLAG@,$(ARCH_FLAG),;t t s,@STATIC@,$(STATIC),;t t s,@CCDLFLAGS@,,;t t s,@LDSHARED@,$(LDSHARED),;t t s,@DLEXT@,so,;t t s,@LIBEXT@,lib,;t t s,@STRIP@,$(STRIP),;t t s,@EXTSTATIC@,$(EXTSTATIC),;t t s,@setup@,Setup,;t t s,@MINIRUBY@,$(MINIRUBY),;t t s,@PREP@,miniruby$(EXEEXT),;t t s,@RUNRUBY@,$(RUNRUBY),;t t s,@EXTOUT@,$(EXTOUT),;t t s,@ARCHFILE@,,;t t s,@RDOCTARGET@,,;t t s,@LIBRUBY_LDSHARED@,$$(LDSHARED),;t t s,@LIBRUBY_DLDFLAGS@,-Gi $$(DLDFLAGS),;t t s,@RUBY_INSTALL_NAME@,$(RUBY_INSTALL_NAME),;t t s,@rubyw_install_name@,$(RUBYW_INSTALL_NAME),;t t s,@RUBYW_INSTALL_NAME@,$(RUBYW_INSTALL_NAME),;t t s,@RUBY_SO_NAME@,$(RUBY_SO_NAME),;t t s,@LIBRUBY_A@,$$(RUBY_SO_NAME)-static.lib,;t t s,@LIBRUBY_SO@,$$(RUBY_SO_NAME).dll,;t t s,@LIBRUBY_ALIASES@,$(LIBRUBY_ALIASES),;t t s,@LIBRUBY@,$$(RUBY_SO_NAME).lib,;t t s,@LIBRUBYARG@,$$(LIBRUBYARG_SHARED),;t t s,@LIBRUBYARG_STATIC@,$$(LIBRUBY_A),;t t s,@LIBRUBYARG_SHARED@,$$(LIBRUBY),;t t s,@SOLIBS@,$(SOLIBS),;t t s,@DLDLIBS@,$(DLDLIBS),;t t s,@ENABLE_SHARED@,yes,;t t s,@OUTFLAG@,$(OUTFLAG),;t t s,@CPPOUTFILE@,,;t t s,@LIBPATHFLAG@, -L"%s",;t t s,@RPATHFLAG@,,;t t s,@LIBARG@,%s.lib,;t t s,@LINK_SO@,$$(LDSHARED) $$(DLDFLAGS) $$(LIBPATH) $$(OBJS), $$(@:/=\), nul, $$(LIBS) $$(LOCAL_LIBS), $$(DEFFILE), $$(RESFILE),;t t s,@COMPILE_C@,$$(CC) $$(INCFLAGS) $$(CFLAGS) $$(CPPFLAGS) -c $$(<:/=\),;t t s,@COMPILE_CXX@,$$(CXX) $$(INCFLAGS) $$(CXXFLAGS) $$(CPPFLAGS) -P -c $$(<:/=\),;t t s,@COMPILE_RULES@,{$$(srcdir)}.%s{}.%s: {$$(topdir)}.%s{}.%s: {$$(hdrdir)}.%s{}.%s: .%s.%s:,;t t s,@RULE_SUBST@,{.;$$(VPATH)}%s,;t t s,@COMMON_LIBS@,m advapi32 avicap32 avifil32 cap comctl32 comdlg32 dlcapi gdi32 glu32 imagehlp imm32 inetmib1 kernel32 loadperf lsapi32 lz32 mapi32 mgmtapi mpr msacm32 msvfw32 nddeapi netapi32 ole32 oleaut32 oledlg olepro32 opengl32 pdh pkpd32 rasapi32 rasdlg rassapi rpcrt4 setupapi shell32 shfolder snmpapi sporder tapi32 url user32 vdmdbg version win32spl winmm wintrust wsock32,;t t s,@COMMON_MACROS@,WIN32_LEAN_AND_MEAN WIN32,;t t s,@COMMON_HEADERS@,winsock2.h windows.h,;t t s,@TRY_LINK@,$$(CC) -oconftest $$(INCFLAGS) -I$$(hdrdir) $$(CPPFLAGS) $$(CFLAGS) $$(LIBPATH) $$(LDFLAGS) $$(src) $$(LOCAL_LIBS) $$(LIBS),;t t s,@EXPORT_PREFIX@,_,;t t s,@arch@,$(ARCH)-$(OS),;t t s,@sitearch@,$(ARCH)-$(OS),;t t s,@sitedir@,$${prefix}/lib/ruby/site_ruby,;t t s,@vendordir@,$${prefix}/lib/ruby/vendor_ruby,;t t s,@configure_args@,--enable-shared $(configure_args),;t t s,@configure_input@,$$configure_input,;t t s,@srcdir@,$(srcdir),;t t s,@top_srcdir@,$(srcdir),;t t | miniruby$(EXEEXT): @echo $(LIBS) $(LD) $(LDFLAGS) $(XLDFLAGS) $(MAINOBJ) $(MINIOBJS),$@,nul,$(LIBRUBY_A) $(LIBS) $(PROGRAM): $(MAINOBJ) $(LIBRUBY_SO) $(RUBY_INSTALL_NAME).res $(LD) $(LDFLAGS) $(XLDFLAGS) $(MAINOBJ),$@,nul,$(LIBRUBYARG) $(LIBS),,$(RUBY_INSTALL_NAME).res $(WPROGRAM): $(MAINOBJ) $(WINMAINOBJ) $(LIBRUBY_SO) $(RUBYW_INSTALL_NAME).res $(LD) $(LDFLAGS) $(WLDFLAGS) $(MAINOBJ) $(WINMAINOBJ),$@,nul,$(LIBRUBYARG) $(LIBS),,$(RUBYW_INSTALL_NAME).res $(LIBRUBY_A): $(OBJS) $(DMYEXT) @-if exist $@ del $@ $(AR) $(ARFLAGS) "$@" $(OBJS) $(DMYEXT) # $(LIBRUBY): $(LIBRUBY_SO) # implib $@ $(LIBRUBY_SO) $(LIBRUBY_SO): $(LIBRUBY_A) $(DLDOBJS) $(RUBYDEF) $(RUBY_SO_NAME).res @echo $(DLDOBJS) @$(PRE_LIBRUBY_UPDATE) $(LIBRUBY_LDSHARED) $(LIBRUBY_DLDFLAGS) $(DLDOBJS:/=\),$(LIBRUBY_SO),nul,$(LIBRUBY_A) $(LIBS),$(RUBYDEF),$(RUBY_SO_NAME).res $(LIBRUBY): $(LIBRUBY_SO) $(RUBYDEF): $(LIBRUBY_A) $(PREP) $(MINIRUBY) $(srcdir)/bcc32/mkexports.rb -output=$@ -base=$(RUBY_SO_NAME) $(LIBRUBY_A) $(RUBY_INSTALL_NAME).rc $(RUBYW_INSTALL_NAME).rc $(RUBY_SO_NAME).rc: rbconfig.rb @$(MINIRUBY) $(srcdir)/win32/resource.rb \ -ruby_name=$(RUBY_INSTALL_NAME) \ -rubyw_name=$(RUBYW_INSTALL_NAME) \ -so_name=$(RUBY_SO_NAME) \ . $(icondirs) $(srcdir)/win32 post-install-bin:: @$(NULLCMD) post-install-lib:: @$(NULLCMD) post-install-ext-comm:: @$(NULLCMD) post-install-ext-arch:: @$(NULLCMD) post-install-man:: @$(NULLCMD) post-install-doc:: @$(NULLCMD) clean-local:: @$(RM) $(WINMAINOBJ) ext\extinit.c ext\extinit.$(OBJEXT) *.tds *.il? $(RUBY_SO_NAME).lib @$(RM) $(RUBY_INSTALL_NAME).res $(RUBYW_INSTALL_NAME).res $(RUBY_SO_NAME).res @$(RM) *.map *.pdb *.ilk *.exp $(RUBYDEF) distclean-local:: @$(RM) ext\config.cache $(RBCONFIG:/=\) @$(RM) $(RUBY_INSTALL_NAME).rc $(RUBYW_INSTALL_NAME).rc $(RUBY_SO_NAME).rc update-rubyspec: @echo SPEC_EXISTS=0 > $@.mk @if exist $(srcdir:/=\)\rubyspec\nul echo SPEC_EXISTS=1 >> $@.mk @type >> $@.mk &&| $()update-rubyspec: $() @del $@.mk $()!if $$(SPEC_EXISTS) $() cd $(srcdir:/=\)\rubyspec\mspec $() git pull $() cd ..\spec\rubyspec $() git pull $()!else $() git clone $(MSPEC_GIT_URL) $(srcdir)/rubyspec/mspec $() git clone $(RUBYSPEC_GIT_URL) $(srcdir)/rubyspec/spec/rubyspec $()!endif | @$(MAKE) -$(MAKEFLAGS)$(MFLAGS) -f $@.mk test-rubyspec: @echo SPEC_EXISTS=0 > $@.mk @if exist $(srcdir:/=\)\rubyspec\nul echo SPEC_EXISTS=1 >> $@.mk @type >> $@.mk &&| $()test-rubyspec: $()!if $$(SPEC_EXISTS) $() $(RUNRUBY) $(srcdir)/rubyspec/mspec/bin/mspec -r$(srcdir)/ext/purelib.rb $(srcdir)/rubyspec/spec/rubyspec/$(MAJOR).$(MINOR) $()!else $() @echo No rubyspec here. put rubyspec to srcdir first. $() @cd $(srcdir:/=\)\rubyspec $()!endif | @$(MAKE) -$(MAKEFLAGS) -f $@.mk ext/extinit.obj: ext/extinit.c $(SETUP) $(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -o$@ -c ext/extinit.c main.$(OBJEXT): win32.h array.$(OBJEXT): win32.h bignum.$(OBJEXT): win32.h class.$(OBJEXT): win32.h compar.$(OBJEXT): win32.h dir.$(OBJEXT): dir.h win32.h dln.$(OBJEXT): win32.h enum.$(OBJEXT): win32.h error.$(OBJEXT): win32.h eval.$(OBJEXT): win32.h file.$(OBJEXT): win32.h gc.$(OBJEXT): win32.h hash.$(OBJEXT): win32.h inits.$(OBJEXT): win32.h io.$(OBJEXT): win32.h marshal.$(OBJEXT): win32.h math.$(OBJEXT): win32.h numeric.$(OBJEXT): win32.h object.$(OBJEXT): win32.h pack.$(OBJEXT): win32.h parse.$(OBJEXT): win32.h process.$(OBJEXT): win32.h prec.$(OBJEXT): win32.h random.$(OBJEXT): win32.h range.$(OBJEXT): win32.h re.$(OBJEXT): win32.h regex.$(OBJEXT): win32.h ruby.$(OBJEXT): win32.h signal.$(OBJEXT): win32.h sprintf.$(OBJEXT): win32.h st.$(OBJEXT): win32.h string.$(OBJEXT): win32.h struct.$(OBJEXT): win32.h time.$(OBJEXT): win32.h util.$(OBJEXT): win32.h variable.$(OBJEXT): win32.h version.$(OBJEXT): win32.h ================================================ FILE: bcc32/README.bcc32 ================================================ =begin = How to build ruby using Borland C++ == Requirement (1) Borland C++ 5.0 or later. (2) Please set environment variable (({PATH})) to run required commands properly from the command line. Note: building ruby requires following commands. * make * bcc32 * tlib * ilink32 (3) If you want to build from CVS source, following commands are required. * byacc (()) * sed (()) (4) We strongly recommend to build ruby on C++Builder, to link following files. * usebormm.lib * memmgr.lib RTL's internal memory manager cannot handle large memory block properly, so we should use borlndmm.dll instead. 10000.times { "" << "." * 529671; GC.start } # crash == How to compile and install (1) Execute bcc32\configure.bat on your build directory. ex. c:\ruby-1.6.7>bcc32\configure.bat (2) Change ((|RUBY_INSTALL_NAME|)) and ((|RUBY_SO_NAME|)) in (({Makefile})) if you want to change the name of the executable files. And add ((|RUBYW_INSTALL_NAME|)) to change the name of the executable without console window if also you want. (3) Run `((%make%))' (4) Run `((%make test%))' (5) Run `((%make DESTDIR= install%))' This command will create following directories and install files onto them. * \bin * \lib * \lib\ruby * \lib\ruby\. * \lib\ruby\.\ * \lib\ruby\site_ruby * \lib\ruby\site_ruby\. * \lib\ruby\site_ruby\.\ * \man\man1 If Ruby's version is `x.y.z', the ((||)) is `x' and the ((||)) is `y'. The ((||)) is usually `(({i586-bccwin32}))'. (6) Requires dynamic RTL (cc3250.dll on C++Builder5) and borlndmm.dll (If built with usebormm.lib) to use installed binary. These files are ordinary in bcc32's bin directory. == Icons Any icon files(*.ico) in the build directory, directories specified with ((|icondirs|)) make variable and (({win32})) directory under the ruby source directory will be included in DLL or executable files, according to their base names. $(RUBY_INSTALL_NAME).ico or ruby.ico --> $(RUBY_INSTALL_NAME).exe $(RUBYW_INSTALL_NAME).ico or rubyw.ico --> $(RUBYW_INSTALL_NAME).exe the others --> $(RUBY_SO_NAME).dll Although no icons are distributed with the ruby source or in the official site, you can use anything you like. For example, followings are written in Japanese, but you can download at least. * (()) or (()) * (()) or (()) == Build examples * Build on the ruby source directory. ex.) ruby source directory: C:\ruby build directory: C:\ruby install directory: C:\usr\local C: cd \ruby bcc32\configure make make test make DESTDIR=/usr/local install * Build on the relative directory from the ruby source directory and CPU type i386. ex.) ruby source directory: C:\ruby build directory: C:\ruby\bccwin32 install directory: C:\usr\local CPU i386 C: cd \ruby mkdir bccwin32 cd bccwin32 ..\bcc32\configure target i386-bccwin32 make make test make DESTDIR=/usr/local install * Build on the different drive. ex.) ruby source directory: C:\src\ruby build directory: D:\build\ruby install directory: C:\usr\local D: cd D:\build\ruby C:\src\ruby\bcc32\configure make make test make DESTDIR=C:/usr/local install == Bugs You can ((*NOT*)) use a path name contains any white space characters as the ruby source directory, this restriction comes from the behavior of (({!INCLUDE})) directives of (({MAKE})). ((- you may call it a bug. -)) =end ================================================ FILE: bcc32/configure.bat ================================================ @echo off ::: Don't set environment variable in batch file other than autoexec.bat ::: to avoid "Out of environment space" problem on Windows 95/98. ::: set TMPMAKE=~tmp~.mak echo> ~tmp~.mak #### echo>> ~tmp~.mak conf = %0 echo>> ~tmp~.mak $(conf:\=/): nul echo>> ~tmp~.mak @del ~setup~.mak echo>> ~tmp~.mak @-$(MAKE) -l$(MAKEFLAGS) -f $(@D)setup.mak \ if exist pathlist.tmp del pathlist.tmp if exist confargs.mk del confargs.mk :loop if "%1" == "" goto :end if "%1" == "--prefix" goto :prefix if "%1" == "prefix" goto :prefix if "%1" == "--srcdir" goto :srcdir if "%1" == "srcdir" goto :srcdir if "%1" == "--target" goto :target if "%1" == "target" goto :target if "%1" == "--with-static-linked-ext" goto :extstatic if "%1" == "--program-suffix" goto :suffix if "%1" == "RUBY_SUFFIX" goto :suffix if "%1" == "--program-name" goto :installname if "%1" == "--install-name" goto :installname if "%1" == "RUBY_INSTALL_NAME" goto :installname if "%1" == "--so-name" goto :soname if "%1" == "RUBY_SO_NAME" goto :soname if "%1" == "--enable-install-doc" goto :enable-rdoc if "%1" == "--disable-install-doc" goto :disable-rdoc if "%1" == "--extout" goto :extout if "%1" == "EXTOUT" goto :extout if "%1" == "--path" goto :path if "%1" == "-h" goto :help if "%1" == "--help" goto :help echo>>confargs.tmp %1 \ shift goto :loop :srcdir echo>> ~tmp~.mak -Dsrcdir=%2 \ echo>>confargs.tmp --srcdir=%2 \ shift shift goto :loop :prefix echo>> ~tmp~.mak -Dprefix=%2 \ echo>>confargs.tmp %1=%2 \ shift shift goto :loop :suffix echo>>confargs.mk !ifndef RUBY_SUFFIX echo>>confargs.mk RUBY_SUFFIX = %2 echo>>confargs.mk !endif echo>>confargs.tmp %1=%2 \ shift shift goto :loop :installname echo>>confargs.mk !ifndef RUBY_INSTALL_NAME echo>>confargs.mk RUBY_INSTALL_NAME = %2 echo>>confargs.mk !endif echo>>confargs.tmp %1=%2 \ shift shift goto :loop :soname echo>>confargs.mk !ifndef RUBY_SO_NAME echo>>confargs.mk RUBY_SO_NAME = %2 echo>>confargs.mk !endif echo>>confargs.tmp %1=%2 \ shift shift goto :loop :target echo>> ~tmp~.mak %2 \ echo>>confargs.tmp --target=%2 \ shift shift goto :loop :extstatic echo>>confargs.mk !ifndef EXTSTATIC echo>>confargs.mk EXTSTATIC = static echo>>confargs.mk !endif echo>>confargs.tmp %1 \ shift goto :loop :enable-rdoc echo>>confargs.mk !ifndef RDOCTARGET echo>>confargs.mk RDOCTARGET = install-doc echo>>confargs.mk !endif echo>>confargs.tmp %1 \ shift goto :loop :disable-rdoc echo>>confargs.mk !ifndef RDOCTARGET echo>>confargs.mk RDOCTARGET = install-nodoc echo>>confargs.mk !endif echo>>confargs.tmp %1 \ shift goto :loop :extout echo>>confargs.mk !ifndef EXTOUT echo>>confargs.mk EXTOUT = %2 echo>>confargs.mk !endif echo>>confargs.tmp %1=%2 \ shift shift goto :loop :path echo>>pathlist.tmp %2;\ echo>>confargs.tmp %1=%2 \ shift shift goto :loop :help echo Configuration: echo --help display this help echo --srcdir=DIR find the sources in DIR [configure dir or `..'] echo Installation directories: echo --prefix=PREFIX install files in PREFIX (ignored currently) echo System types: echo --target=TARGET configure for TARGET [i386-bccwin32] echo Optional Package: echo --with-static-linked-ext link external modules statically echo --disable-install-doc install rdoc indexes during install del *.tmp del ~tmp~.mak goto :exit :end echo>> ~tmp~.mak -Dbcc32dir=$(@D) if not exist confargs.tmp goto :noconfargs echo>>confargs.mk configure_args = \ type>>confargs.mk confargs.tmp echo.>>confargs.mk echo>>confargs.mk #### :noconfargs if not exist pathlist.tmp goto :nopathlist echo>>confargs.mk pathlist = \ type>>confargs.mk pathlist.tmp echo.>>confargs.mk echo>>confargs.mk #### echo>>confargs.mk PATH = $(pathlist:;=/bin;)$(PATH) echo>>confargs.mk INCLUDE = $(pathlist:;=/include;) echo>>confargs.mk LIB = $(pathlist:;=/lib;) :nopathlist if exist confargs.mk copy confargs.mk ~setup~.mak > nul type>>~setup~.mak ~tmp~.mak del *.tmp > nul del ~tmp~.mak > nul make -s -f ~setup~.mak :exit ================================================ FILE: bcc32/mkexports.rb ================================================ #!./miniruby -s $name = $library = $description = nil SYM = {} STDIN.reopen(open("nul")) ARGV.each do |obj| IO.foreach("|tdump -q -oiPUBDEF -oiPUBD32 #{obj.tr('/', '\\')}") do |l| next unless /(?:PUBDEF|PUBD32)/ =~ l SYM[$1] = true if /'(.*?)'/ =~ l end end exports = [] if $name exports << "Name " + $name elsif $library exports << "Library " + $library end exports << "Description " + $description.dump if $description exports << "EXPORTS" << SYM.keys.sort if $output open($output, 'w') {|f| f.puts exports.join("\n")} else puts exports.join("\n") end ================================================ FILE: bcc32/setup.mak ================================================ # -*- makefile -*- !if "$(srcdir)" != "" bcc32dir = $(srcdir)/bcc32 !elseif "$(bcc32dir)" == "bcc32/" srcdir = . !elseif "$(bcc32dir:/bcc32/=)/bcc32/" == "$(bcc32dir)" srcdir = $(bcc32dir:/bcc32/=) !else srcdir = $(bcc32dir)/.. !endif !ifndef prefix prefix = /usr !endif OS = bccwin32 RT = $(OS) BANG = ! APPEND = echo>>$(MAKEFILE) !ifdef MAKEFILE MAKE = $(MAKE) -f $(MAKEFILE) !else MAKEFILE = Makefile !endif all: Makefile Makefile: -prologue- -generic- -epilogue- i386-$(OS): -prologue- -i386- -epilogue- i486-$(OS): -prologue- -i486- -epilogue- i586-$(OS): -prologue- -i586- -epilogue- i686-$(OS): -prologue- -i686- -epilogue- alpha-$(OS): -prologue- -alpha- -epilogue- -prologue-: -basic-vars- -version- -system-vars- -basic-vars-: nul @echo Creating $(MAKEFILE) @type > $(MAKEFILE) &&| \#\#\# Makefile for ruby $(OS) \#\#\# $(BANG)ifndef srcdir srcdir = $(srcdir:\=/) $(BANG)endif $(BANG)ifndef prefix prefix = $(prefix:\=/) $(BANG)endif | !if exist(confargs.mk) @type confargs.mk >> $(MAKEFILE) @del confargs.mk !endif -system-vars-: -runtime- -bormm- -bormm-: nul @-ilink32 -q -Gn -x usebormm.lib > nul @-if exist usebormm.tds $(APPEND) MEMLIB = usebormm.lib @if exist usebormm.* del usebormm.* -osname-: nul @echo OS = >>$(MAKEFILE) -runtime-: nul type > conftest.c &&| \#include int main(){printf("");return 0;} | bcc32 conftest.c cw32i.lib > nul tdump conftest.exe < nul > conftest.i grep "^Imports from CC" conftest.i > conftest.c cpp32 -P- -DFile=\# -DImports=RTNAME -Dfrom== conftest.c > nul $(MAKE) > nul -DBANG=$(BANG) -f &&| -runtime-: nul $(BANG)include conftest.i RT = $$(RTNAME:.DLL=) OS = $$(RT:CC32=) -runtime-: del conftest.* $(BANG)if "$$(OS)" == "50" echo OS = bccwin32 >> $(MAKEFILE) $(BANG)else echo OS = bccwin32_$$(OS) >> $(MAKEFILE) $(BANG)endif | @echo RT = $$(OS) >> $(MAKEFILE) -version-: nul @cpp32 -I$(srcdir) -P- -o$(MAKEFILE) > nul &&| \#include "version.h" MAJOR = RUBY_VERSION_MAJOR MINOR = RUBY_VERSION_MINOR TEENY = RUBY_VERSION_TEENY BORLANDC = __BORLANDC__ | @$(MAKE) > nul -DBANG=$(BANG) -f &&, -version-: nul $(BANG)include $(MAKEFILE) $(BANG)include $(MAKEFILE).i -version-: @del $(MAKEFILE).i @type >> $(MAKEFILE) &&| MAJOR = $$(MAJOR) MINOR = $$(MINOR) TEENY = $$(TEENY) BORLANDC = $$(BORLANDC) | , -generic-: nul !if defined(PROCESSOR_ARCHITECTURE) || defined(PROCESSOR_LEVEL) @type >> $(MAKEFILE) &&| !if defined(PROCESSOR_ARCHITECTURE) $(BANG)ifndef PROCESSOR_ARCHITECTURE PROCESSOR_ARCHITECTURE = $(PROCESSOR_ARCHITECTURE) $(BANG)endif !endif !if defined(PROCESSOR_LEVEL) $(BANG)ifndef PROCESSOR_LEVEL PROCESSOR_LEVEL = $(PROCESSOR_LEVEL) $(BANG)endif !endif | !endif -alpha-: nul @$(APPEND) !ifndef PROCESSOR_ARCHITECTURE @$(APPEND) PROCESSOR_ARCHITECTURE = alpha @$(APPEND) !endif -ix86-: nul @$(APPEND) !ifndef PROCESSOR_ARCHITECTURE @$(APPEND) PROCESSOR_ARCHITECTURE = x86 @$(APPEND) !endif -i386-: -ix86- @$(APPEND) !ifndef PROCESSOR_LEVEL @$(APPEND) PROCESSOR_LEVEL = 3 @$(APPEND) !endif -i486-: -ix86- @$(APPEND) !ifndef PROCESSOR_LEVEL @$(APPEND) PROCESSOR_LEVEL = 4 @$(APPEND) !endif -i586-: -ix86- @$(APPEND) !ifndef PROCESSOR_LEVEL @$(APPEND) PROCESSOR_LEVEL = 5 @$(APPEND) !endif -i686-: -ix86- @$(APPEND) !ifndef PROCESSOR_LEVEL @$(APPEND) PROCESSOR_LEVEL = 6 @$(APPEND) !endif -epilogue-: nul @type >> $(MAKEFILE) &&| \# RUBY_INSTALL_NAME = ruby \# RUBY_SO_NAME = $$(RT)-$$(RUBY_INSTALL_NAME)$$(MAJOR)$$(MINOR) \# CFLAGS = -q $$(DEBUGFLAGS) $$(OPTFLAGS) $$(PROCESSOR_FLAG) -w- -wsus -wcpt -wdup -wext -wrng -wrpt -wzdi \# CPPFLAGS = -I. -I$$(srcdir) -I$$(srcdir)/missing -DLIBRUBY_SO=\"$$(LIBRUBY_SO)\" \# STACK = 0x2000000 \# LDFLAGS = -S:$$(STACK) \# RFLAGS = $$(iconinc) \# EXTLIBS = cw32.lib import32.lib user32.lib kernel32.lib $(BANG)include $$(srcdir)/bcc32/Makefile.sub | @echo type "`$(MAKE)'" to make ruby for $(OS). ================================================ FILE: bignum.c ================================================ /********************************************************************** bignum.c - $Author$ $Date$ created at: Fri Jun 10 00:48:55 JST 1994 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #include "ruby.h" #include "rubysig.h" #include #include #include #ifdef HAVE_IEEEFP_H #include #endif VALUE rb_cBignum; #if defined __MINGW32__ #define USHORT _USHORT #endif #define BDIGITS(x) ((BDIGIT*)RBIGNUM(x)->digits) #define BITSPERDIG (SIZEOF_BDIGITS*CHAR_BIT) #define BIGRAD ((BDIGIT_DBL)1 << BITSPERDIG) #define DIGSPERLONG ((unsigned int)(SIZEOF_LONG/SIZEOF_BDIGITS)) #if HAVE_LONG_LONG # define DIGSPERLL ((unsigned int)(SIZEOF_LONG_LONG/SIZEOF_BDIGITS)) #endif #define BIGUP(x) ((BDIGIT_DBL)(x) << BITSPERDIG) #define BIGDN(x) RSHIFT(x,BITSPERDIG) #define BIGLO(x) ((BDIGIT)((x) & (BIGRAD-1))) #define BDIGMAX ((BDIGIT)-1) #define BIGZEROP(x) (RBIGNUM(x)->len == 0 || \ (BDIGITS(x)[0] == 0 && \ (RBIGNUM(x)->len == 1 || bigzero_p(x)))) static int bigzero_p(VALUE); static int bigzero_p(x) VALUE x; { long i; for (i = 0; i < RBIGNUM(x)->len; ++i) { if (BDIGITS(x)[i]) return 0; } return 1; } static VALUE bignew_1(klass, len, sign) VALUE klass; long len; int sign; { NEWOBJ(big, struct RBignum); OBJSETUP(big, klass, T_BIGNUM); big->sign = sign?1:0; big->len = len; big->digits = ALLOC_N(BDIGIT, len); return (VALUE)big; } #define bignew(len,sign) bignew_1(rb_cBignum,len,sign) VALUE rb_big_clone(x) VALUE x; { VALUE z = bignew_1(CLASS_OF(x), RBIGNUM(x)->len, RBIGNUM(x)->sign); MEMCPY(BDIGITS(z), BDIGITS(x), BDIGIT, RBIGNUM(x)->len); return z; } /* modify a bignum by 2's complement */ static void get2comp(x) VALUE x; { long i = RBIGNUM(x)->len; BDIGIT *ds = BDIGITS(x); BDIGIT_DBL num; if (!i) return; while (i--) ds[i] = ~ds[i]; i = 0; num = 1; do { num += ds[i]; ds[i++] = BIGLO(num); num = BIGDN(num); } while (i < RBIGNUM(x)->len); if (num != 0) { REALLOC_N(RBIGNUM(x)->digits, BDIGIT, ++RBIGNUM(x)->len); ds = BDIGITS(x); ds[RBIGNUM(x)->len-1] = RBIGNUM(x)->sign ? ~0 : 1; } } void rb_big_2comp(x) /* get 2's complement */ VALUE x; { get2comp(x); } static VALUE bigtrunc(x) VALUE x; { long len = RBIGNUM(x)->len; BDIGIT *ds = BDIGITS(x); if (len == 0) return x; while (--len && !ds[len]); RBIGNUM(x)->len = ++len; return x; } static VALUE bigfixize(x) VALUE x; { long len = RBIGNUM(x)->len; BDIGIT *ds = BDIGITS(x); if (len*SIZEOF_BDIGITS <= sizeof(VALUE)) { long num = 0; while (len--) { num = BIGUP(num) + ds[len]; } if (num >= 0) { if (RBIGNUM(x)->sign) { if (POSFIXABLE(num)) return LONG2FIX(num); } else { if (NEGFIXABLE(-(long)num)) return LONG2FIX(-(long)num); } } } return x; } static VALUE bignorm(x) VALUE x; { if (!FIXNUM_P(x) && TYPE(x) == T_BIGNUM) { x = bigfixize(bigtrunc(x)); } return x; } VALUE rb_big_norm(x) VALUE x; { return bignorm(x); } VALUE rb_uint2big(n) unsigned long n; { BDIGIT_DBL num = n; long i = 0; BDIGIT *digits; VALUE big; big = bignew(DIGSPERLONG, 1); digits = BDIGITS(big); while (i < DIGSPERLONG) { digits[i++] = BIGLO(num); num = BIGDN(num); } i = DIGSPERLONG; while (--i && !digits[i]) ; RBIGNUM(big)->len = i+1; return big; } VALUE rb_int2big(n) long n; { long neg = 0; VALUE big; if (n < 0) { n = -n; neg = 1; } big = rb_uint2big(n); if (neg) { RBIGNUM(big)->sign = 0; } return big; } VALUE rb_uint2inum(n) unsigned long n; { if (POSFIXABLE(n)) return LONG2FIX(n); return rb_uint2big(n); } VALUE rb_int2inum(n) long n; { if (FIXABLE(n)) return LONG2FIX(n); return rb_int2big(n); } #ifdef HAVE_LONG_LONG void rb_quad_pack(buf, val) char *buf; VALUE val; { LONG_LONG q; val = rb_to_int(val); if (FIXNUM_P(val)) { q = FIX2LONG(val); } else { long len = RBIGNUM(val)->len; BDIGIT *ds; if (len > SIZEOF_LONG_LONG/SIZEOF_BDIGITS) rb_raise(rb_eRangeError, "bignum too big to convert into `quad int'"); ds = BDIGITS(val); q = 0; while (len--) { q = BIGUP(q); q += ds[len]; } if (!RBIGNUM(val)->sign) q = -q; } memcpy(buf, (char*)&q, SIZEOF_LONG_LONG); } VALUE rb_quad_unpack(buf, sign) const char *buf; int sign; { unsigned LONG_LONG q; long neg = 0; long i; BDIGIT *digits; VALUE big; memcpy(&q, buf, SIZEOF_LONG_LONG); if (sign) { if (FIXABLE((LONG_LONG)q)) return LONG2FIX((LONG_LONG)q); if ((LONG_LONG)q < 0) { q = -(LONG_LONG)q; neg = 1; } } else { if (POSFIXABLE(q)) return LONG2FIX(q); } i = 0; big = bignew(DIGSPERLL, 1); digits = BDIGITS(big); while (i < DIGSPERLL) { digits[i++] = BIGLO(q); q = BIGDN(q); } i = DIGSPERLL; while (i-- && !digits[i]) ; RBIGNUM(big)->len = i+1; if (neg) { RBIGNUM(big)->sign = 0; } return bignorm(big); } #else #define QUAD_SIZE 8 void rb_quad_pack(buf, val) char *buf; VALUE val; { long len; memset(buf, 0, QUAD_SIZE); val = rb_to_int(val); if (FIXNUM_P(val)) { val = rb_int2big(FIX2LONG(val)); } len = RBIGNUM(val)->len * SIZEOF_BDIGITS; if (len > QUAD_SIZE) { rb_raise(rb_eRangeError, "bignum too big to convert into `quad int'"); } memcpy(buf, (char*)BDIGITS(val), len); if (!RBIGNUM(val)->sign) { len = QUAD_SIZE; while (len--) { *buf = ~*buf; buf++; } } } #define BNEG(b) (RSHIFT(((BDIGIT*)b)[QUAD_SIZE/SIZEOF_BDIGITS-1],BITSPERDIG-1) != 0) VALUE rb_quad_unpack(buf, sign) const char *buf; int sign; { VALUE big = bignew(QUAD_SIZE/SIZEOF_BDIGITS, 1); memcpy((char*)BDIGITS(big), buf, QUAD_SIZE); if (sign && BNEG(buf)) { long len = QUAD_SIZE; char *tmp = (char*)BDIGITS(big); RBIGNUM(big)->sign = 0; while (len--) { *tmp = ~*tmp; tmp++; } } return bignorm(big); } #endif VALUE rb_cstr_to_inum(str, base, badcheck) const char *str; int base; int badcheck; { const char *s = str; char *end; char sign = 1, nondigit = 0; int c; BDIGIT_DBL num; long len, blen = 1; long i; VALUE z; BDIGIT *zds; #define conv_digit(c) \ (!ISASCII(c) ? -1 : \ isdigit(c) ? ((c) - '0') : \ islower(c) ? ((c) - 'a' + 10) : \ isupper(c) ? ((c) - 'A' + 10) : \ -1) if (!str) { if (badcheck) goto bad; return INT2FIX(0); } if (badcheck) { while (ISSPACE(*str)) str++; } else { while (ISSPACE(*str) || *str == '_') str++; } if (str[0] == '+') { str++; } else if (str[0] == '-') { str++; sign = 0; } if (str[0] == '+' || str[0] == '-') { if (badcheck) goto bad; return INT2FIX(0); } if (base <= 0) { if (str[0] == '0') { switch (str[1]) { case 'x': case 'X': base = 16; break; case 'b': case 'B': base = 2; break; case 'o': case 'O': base = 8; break; case 'd': case 'D': base = 10; break; default: base = 8; } } else if (base < -1) { base = -base; } else { base = 10; } } switch (base) { case 2: len = 1; if (str[0] == '0' && (str[1] == 'b'||str[1] == 'B')) { str += 2; } break; case 3: len = 2; break; case 8: if (str[0] == '0' && (str[1] == 'o'||str[1] == 'O')) { str += 2; } case 4: case 5: case 6: case 7: len = 3; break; case 10: if (str[0] == '0' && (str[1] == 'd'||str[1] == 'D')) { str += 2; } case 9: case 11: case 12: case 13: case 14: case 15: len = 4; break; case 16: len = 4; if (str[0] == '0' && (str[1] == 'x'||str[1] == 'X')) { str += 2; } break; default: if (base < 2 || 36 < base) { rb_raise(rb_eArgError, "illegal radix %d", base); } if (base <= 32) { len = 5; } else { len = 6; } break; } if (*str == '0') { /* squeeze preceeding 0s */ int us = 0; while ((c = *++str) == '0' || c == '_') { if (c == '_') { if (++us >= 2) break; } else us = 0; } if (!(c = *str) || ISSPACE(c)) --str; } c = *str; c = conv_digit(c); if (c < 0 || c >= base) { if (badcheck) goto bad; return INT2FIX(0); } len *= strlen(str)*sizeof(char); if (len <= (sizeof(VALUE)*CHAR_BIT)) { unsigned long val = strtoul((char*)str, &end, base); if (*end == '_') goto bigparse; if (badcheck) { if (end == str) goto bad; /* no number */ while (*end && ISSPACE(*end)) end++; if (*end) goto bad; /* trailing garbage */ } if (POSFIXABLE(val)) { if (sign) return LONG2FIX(val); else { long result = -(long)val; return LONG2FIX(result); } } else { VALUE big = rb_uint2big(val); RBIGNUM(big)->sign = sign; return bignorm(big); } } bigparse: len = (len/BITSPERDIG)+1; if (badcheck && *str == '_') goto bad; z = bignew(len, sign); zds = BDIGITS(z); for (i=len;i--;) zds[i]=0; while ((c = *str++) != 0) { if (c == '_') { if (nondigit) { if (badcheck) goto bad; break; } nondigit = c; continue; } else if ((c = conv_digit(c)) < 0) { break; } if (c >= base) break; nondigit = 0; i = 0; num = c; for (;;) { while (iptr; } if (s) { len = RSTRING(str)->len; if (s[len]) { /* no sentinel somehow */ char *p = ALLOCA_N(char, len+1); MEMCPY(p, s, char, len); p[len] = '\0'; s = p; } } return rb_cstr_to_inum(s, base, badcheck); } #if HAVE_LONG_LONG VALUE rb_ull2big(n) unsigned LONG_LONG n; { BDIGIT_DBL num = n; long i = 0; BDIGIT *digits; VALUE big; big = bignew(DIGSPERLL, 1); digits = BDIGITS(big); while (i < DIGSPERLL) { digits[i++] = BIGLO(num); num = BIGDN(num); } i = DIGSPERLL; while (i-- && !digits[i]) ; RBIGNUM(big)->len = i+1; return big; } VALUE rb_ll2big(n) LONG_LONG n; { long neg = 0; VALUE big; if (n < 0) { n = -n; neg = 1; } big = rb_ull2big(n); if (neg) { RBIGNUM(big)->sign = 0; } return big; } VALUE rb_ull2inum(n) unsigned LONG_LONG n; { if (POSFIXABLE(n)) return LONG2FIX(n); return rb_ull2big(n); } VALUE rb_ll2inum(n) LONG_LONG n; { if (FIXABLE(n)) return LONG2FIX(n); return rb_ll2big(n); } #endif /* HAVE_LONG_LONG */ VALUE rb_cstr2inum(str, base) const char *str; int base; { return rb_cstr_to_inum(str, base, base==0); } VALUE rb_str2inum(str, base) VALUE str; int base; { return rb_str_to_inum(str, base, base==0); } const char ruby_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz"; VALUE rb_big2str0(x, base, trim) VALUE x; int base; int trim; { volatile VALUE t; BDIGIT *ds; long i, j, hbase; VALUE ss; char *s; if (FIXNUM_P(x)) { return rb_fix2str(x, base); } i = RBIGNUM(x)->len; if (BIGZEROP(x)) { return rb_str_new2("0"); } if (i >= LONG_MAX/SIZEOF_BDIGITS/CHAR_BIT) { rb_raise(rb_eRangeError, "bignum too big to convert into `string'"); } j = SIZEOF_BDIGITS*CHAR_BIT*i; switch (base) { case 2: break; case 3: j = j * 53L / 84 + 1; break; case 4: case 5: case 6: case 7: j = (j + 1) / 2; break; case 8: case 9: j = (j + 2) / 3; break; case 10: case 11: case 12: case 13: case 14: case 15: j = j * 28L / 93 + 1; break; case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: j = (j + 3) / 4; break; case 32: case 33: case 34: case 35: case 36: j = (j + 4) / 5; break; default: rb_raise(rb_eArgError, "illegal radix %d", base); break; } j++; /* space for sign */ hbase = base * base; #if SIZEOF_BDIGITS > 2 hbase *= hbase; #endif t = rb_big_clone(x); ds = BDIGITS(t); ss = rb_str_new(0, j+1); s = RSTRING(ss)->ptr; s[0] = RBIGNUM(x)->sign ? '+' : '-'; TRAP_BEG; while (i && j > 1) { long k = i; BDIGIT_DBL num = 0; while (k--) { num = BIGUP(num) + ds[k]; ds[k] = (BDIGIT)(num / hbase); num %= hbase; } if (trim && ds[i-1] == 0) i--; k = SIZEOF_BDIGITS; while (k--) { s[--j] = ruby_digitmap[num % base]; num /= base; if (!trim && j <= 1) break; if (trim && i == 0 && num == 0) break; } } if (trim) {while (s[j] == '0') j++;} i = RSTRING(ss)->len - j; if (RBIGNUM(x)->sign) { memmove(s, s+j, i); RSTRING(ss)->len = i-1; } else { memmove(s+1, s+j, i); RSTRING(ss)->len = i; } s[RSTRING(ss)->len] = '\0'; TRAP_END; return ss; } VALUE rb_big2str(VALUE x, int base) { return rb_big2str0(x, base, Qtrue); } /* * call-seq: * big.to_s(base=10) => string * * Returns a string containing the representation of big radix * base (2 through 36). * * 12345654321.to_s #=> "12345654321" * 12345654321.to_s(2) #=> "1011011111110110111011110000110001" * 12345654321.to_s(8) #=> "133766736061" * 12345654321.to_s(16) #=> "2dfdbbc31" * 78546939656932.to_s(36) #=> "rubyrules" */ static VALUE rb_big_to_s(argc, argv, x) int argc; VALUE *argv; VALUE x; { VALUE b; int base; rb_scan_args(argc, argv, "01", &b); if (argc == 0) base = 10; else base = NUM2INT(b); return rb_big2str(x, base); } static unsigned long big2ulong(x, type) VALUE x; char *type; { long len = RBIGNUM(x)->len; BDIGIT_DBL num; BDIGIT *ds; if (len > SIZEOF_LONG/SIZEOF_BDIGITS) rb_raise(rb_eRangeError, "bignum too big to convert into `%s'", type); ds = BDIGITS(x); num = 0; while (len--) { num = BIGUP(num); num += ds[len]; } return num; } unsigned long rb_big2ulong_pack(x) VALUE x; { unsigned long num = big2ulong(x, "unsigned long"); if (!RBIGNUM(x)->sign) { return -num; } return num; } unsigned long rb_big2ulong(x) VALUE x; { unsigned long num = big2ulong(x, "unsigned long"); if (!RBIGNUM(x)->sign) { if ((long)num < 0) { rb_raise(rb_eRangeError, "bignum out of range of unsigned long"); } return -num; } return num; } long rb_big2long(x) VALUE x; { unsigned long num = big2ulong(x, "long"); if ((long)num < 0 && (RBIGNUM(x)->sign || (long)num != LONG_MIN)) { rb_raise(rb_eRangeError, "bignum too big to convert into `long'"); } if (!RBIGNUM(x)->sign) return -(long)num; return num; } #if HAVE_LONG_LONG static unsigned LONG_LONG big2ull(x, type) VALUE x; char *type; { long len = RBIGNUM(x)->len; BDIGIT_DBL num; BDIGIT *ds; if (len > SIZEOF_LONG_LONG/SIZEOF_BDIGITS) rb_raise(rb_eRangeError, "bignum too big to convert into `%s'", type); ds = BDIGITS(x); num = 0; while (len--) { num = BIGUP(num); num += ds[len]; } return num; } unsigned LONG_LONG rb_big2ull(x) VALUE x; { unsigned LONG_LONG num = big2ull(x, "unsigned long long"); if (!RBIGNUM(x)->sign) return -num; return num; } LONG_LONG rb_big2ll(x) VALUE x; { unsigned LONG_LONG num = big2ull(x, "long long"); if ((LONG_LONG)num < 0 && (RBIGNUM(x)->sign || (LONG_LONG)num != LLONG_MIN)) { rb_raise(rb_eRangeError, "bignum too big to convert into `long long'"); } if (!RBIGNUM(x)->sign) return -(LONG_LONG)num; return num; } #endif /* HAVE_LONG_LONG */ static VALUE dbl2big(d) double d; { long i = 0; BDIGIT c; BDIGIT *digits; VALUE z; double u = (d < 0)?-d:d; if (isinf(d)) { rb_raise(rb_eFloatDomainError, d < 0 ? "-Infinity" : "Infinity"); } if (isnan(d)) { rb_raise(rb_eFloatDomainError, "NaN"); } while (!POSFIXABLE(u) || 0 != (long)u) { u /= (double)(BIGRAD); i++; } z = bignew(i, d>=0); digits = BDIGITS(z); while (i--) { u *= BIGRAD; c = (BDIGIT)u; u -= c; digits[i] = c; } return z; } VALUE rb_dbl2big(d) double d; { return bignorm(dbl2big(d)); } static double big2dbl(x) VALUE x; { double d = 0.0; long i = RBIGNUM(x)->len; BDIGIT *ds = BDIGITS(x); while (i--) { d = ds[i] + BIGRAD*d; } if (!RBIGNUM(x)->sign) d = -d; return d; } double rb_big2dbl(x) VALUE x; { double d = big2dbl(x); if (isinf(d)) { rb_warn("Bignum out of Float range"); d = HUGE_VAL; } return d; } /* * call-seq: * big.to_f -> float * * Converts big to a Float. If big doesn't * fit in a Float, the result is infinity. * */ static VALUE rb_big_to_f(x) VALUE x; { return rb_float_new(rb_big2dbl(x)); } /* * call-seq: * big <=> numeric => -1, 0, +1 * * Comparison---Returns -1, 0, or +1 depending on whether big is * less than, equal to, or greater than numeric. This is the * basis for the tests in Comparable. * */ static VALUE rb_big_cmp(x, y) VALUE x, y; { long xlen = RBIGNUM(x)->len; switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); break; case T_BIGNUM: break; case T_FLOAT: return rb_dbl_cmp(rb_big2dbl(x), RFLOAT(y)->value); default: return rb_num_coerce_cmp(x, y); } if (RBIGNUM(x)->sign > RBIGNUM(y)->sign) return INT2FIX(1); if (RBIGNUM(x)->sign < RBIGNUM(y)->sign) return INT2FIX(-1); if (xlen < RBIGNUM(y)->len) return (RBIGNUM(x)->sign) ? INT2FIX(-1) : INT2FIX(1); if (xlen > RBIGNUM(y)->len) return (RBIGNUM(x)->sign) ? INT2FIX(1) : INT2FIX(-1); while(xlen-- && (BDIGITS(x)[xlen]==BDIGITS(y)[xlen])); if (-1 == xlen) return INT2FIX(0); return (BDIGITS(x)[xlen] > BDIGITS(y)[xlen]) ? (RBIGNUM(x)->sign ? INT2FIX(1) : INT2FIX(-1)) : (RBIGNUM(x)->sign ? INT2FIX(-1) : INT2FIX(1)); } /* * call-seq: * big == obj => true or false * * Returns true only if obj has the same value * as big. Contrast this with Bignum#eql?, which * requires obj to be a Bignum. * * 68719476736 == 68719476736.0 #=> true */ static VALUE rb_big_eq(x, y) VALUE x, y; { switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); break; case T_BIGNUM: break; case T_FLOAT: { volatile double a, b; a = RFLOAT(y)->value; if (isnan(a)) return Qfalse; b = rb_big2dbl(x); return (a == b)?Qtrue:Qfalse; } default: return rb_equal(y, x); } if (RBIGNUM(x)->sign != RBIGNUM(y)->sign) return Qfalse; if (RBIGNUM(x)->len != RBIGNUM(y)->len) return Qfalse; if (MEMCMP(BDIGITS(x),BDIGITS(y),BDIGIT,RBIGNUM(y)->len) != 0) return Qfalse; return Qtrue; } /* * call-seq: * big.eql?(obj) => true or false * * Returns true only if obj is a * Bignum with the same value as big. Contrast this * with Bignum#==, which performs type conversions. * * 68719476736.eql?(68719476736.0) #=> false */ static VALUE rb_big_eql(x, y) VALUE x, y; { if (TYPE(y) != T_BIGNUM) return Qfalse; if (RBIGNUM(x)->sign != RBIGNUM(y)->sign) return Qfalse; if (RBIGNUM(x)->len != RBIGNUM(y)->len) return Qfalse; if (MEMCMP(BDIGITS(x),BDIGITS(y),BDIGIT,RBIGNUM(y)->len) != 0) return Qfalse; return Qtrue; } /* * call-seq: * -big => other_big * * Unary minus (returns a new Bignum whose value is 0-big) */ static VALUE rb_big_uminus(x) VALUE x; { VALUE z = rb_big_clone(x); RBIGNUM(z)->sign = !RBIGNUM(x)->sign; return bignorm(z); } /* * call-seq: * ~big => integer * * Inverts the bits in big. As Bignums are conceptually infinite * length, the result acts as if it had an infinite number of one * bits to the left. In hex representations, this is displayed * as two periods to the left of the digits. * * sprintf("%X", ~0x1122334455) #=> "..FEEDDCCBBAA" */ static VALUE rb_big_neg(x) VALUE x; { VALUE z = rb_big_clone(x); long i; BDIGIT *ds; if (!RBIGNUM(x)->sign) get2comp(z); ds = BDIGITS(z); i = RBIGNUM(x)->len; if (!i) return INT2FIX(~0); while (i--) ds[i] = ~ds[i]; RBIGNUM(z)->sign = !RBIGNUM(z)->sign; if (RBIGNUM(x)->sign) get2comp(z); return bignorm(z); } static VALUE bigsub(x, y) VALUE x, y; { VALUE z = 0; BDIGIT *zds; BDIGIT_DBL_SIGNED num; long i = RBIGNUM(x)->len; /* if x is larger than y, swap */ if (RBIGNUM(x)->len < RBIGNUM(y)->len) { z = x; x = y; y = z; /* swap x y */ } else if (RBIGNUM(x)->len == RBIGNUM(y)->len) { while (i > 0) { i--; if (BDIGITS(x)[i] > BDIGITS(y)[i]) { break; } if (BDIGITS(x)[i] < BDIGITS(y)[i]) { z = x; x = y; y = z; /* swap x y */ break; } } } z = bignew(RBIGNUM(x)->len, z==0); zds = BDIGITS(z); for (i = 0, num = 0; i < RBIGNUM(y)->len; i++) { num += (BDIGIT_DBL_SIGNED)BDIGITS(x)[i] - BDIGITS(y)[i]; zds[i] = BIGLO(num); num = BIGDN(num); } while (num && i < RBIGNUM(x)->len) { num += BDIGITS(x)[i]; zds[i++] = BIGLO(num); num = BIGDN(num); } while (i < RBIGNUM(x)->len) { zds[i] = BDIGITS(x)[i]; i++; } return z; } static VALUE bigadd(x, y, sign) VALUE x, y; int sign; { VALUE z; BDIGIT_DBL num; long i, len; sign = (sign == RBIGNUM(y)->sign); if (RBIGNUM(x)->sign != sign) { if (sign) return bigsub(y, x); return bigsub(x, y); } if (RBIGNUM(x)->len > RBIGNUM(y)->len) { len = RBIGNUM(x)->len + 1; z = x; x = y; y = z; } else { len = RBIGNUM(y)->len + 1; } z = bignew(len, sign); len = RBIGNUM(x)->len; for (i = 0, num = 0; i < len; i++) { num += (BDIGIT_DBL)BDIGITS(x)[i] + BDIGITS(y)[i]; BDIGITS(z)[i] = BIGLO(num); num = BIGDN(num); } len = RBIGNUM(y)->len; while (num && i < len) { num += BDIGITS(y)[i]; BDIGITS(z)[i++] = BIGLO(num); num = BIGDN(num); } while (i < len) { BDIGITS(z)[i] = BDIGITS(y)[i]; i++; } BDIGITS(z)[i] = (BDIGIT)num; return z; } /* * call-seq: * big + other => Numeric * * Adds big and other, returning the result. */ VALUE rb_big_plus(x, y) VALUE x, y; { switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); /* fall through */ case T_BIGNUM: return bignorm(bigadd(x, y, 1)); case T_FLOAT: return rb_float_new(rb_big2dbl(x) + RFLOAT(y)->value); default: return rb_num_coerce_bin(x, y); } } /* * call-seq: * big - other => Numeric * * Subtracts other from big, returning the result. */ VALUE rb_big_minus(x, y) VALUE x, y; { switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); /* fall through */ case T_BIGNUM: return bignorm(bigadd(x, y, 0)); case T_FLOAT: return rb_float_new(rb_big2dbl(x) - RFLOAT(y)->value); default: return rb_num_coerce_bin(x, y); } } VALUE rb_big_mul0(x, y) VALUE x, y; { long i, j; BDIGIT_DBL n = 0; VALUE z; BDIGIT *zds; if (FIXNUM_P(x)) x = rb_int2big(FIX2LONG(x)); switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); break; case T_BIGNUM: break; case T_FLOAT: return rb_float_new(rb_big2dbl(x) * RFLOAT(y)->value); default: return rb_num_coerce_bin(x, y); } j = RBIGNUM(x)->len + RBIGNUM(y)->len + 1; z = bignew(j, RBIGNUM(x)->sign==RBIGNUM(y)->sign); zds = BDIGITS(z); while (j--) zds[j] = 0; for (i = 0; i < RBIGNUM(x)->len; i++) { BDIGIT_DBL dd = BDIGITS(x)[i]; if (dd == 0) continue; n = 0; for (j = 0; j < RBIGNUM(y)->len; j++) { BDIGIT_DBL ee = n + (BDIGIT_DBL)dd * BDIGITS(y)[j]; n = zds[i + j] + ee; if (ee) zds[i + j] = BIGLO(n); n = BIGDN(n); } if (n) { zds[i + j] = n; } } return z; } /* * call-seq: * big * other => Numeric * * Multiplies big and other, returning the result. */ VALUE rb_big_mul(x, y) VALUE x, y; { return bignorm(rb_big_mul0(x, y)); } static void bigdivrem(x, y, divp, modp) VALUE x, y; VALUE *divp, *modp; { long nx = RBIGNUM(x)->len, ny = RBIGNUM(y)->len; long i, j; VALUE yy, z; BDIGIT *xds, *yds, *zds, *tds; BDIGIT_DBL t2; BDIGIT_DBL_SIGNED num; BDIGIT dd, q; if (BIGZEROP(y)) rb_num_zerodiv(); yds = BDIGITS(y); if (nx < ny || (nx == ny && BDIGITS(x)[nx - 1] < BDIGITS(y)[ny - 1])) { if (divp) *divp = rb_int2big(0); if (modp) *modp = x; return; } xds = BDIGITS(x); if (ny == 1) { dd = yds[0]; z = rb_big_clone(x); zds = BDIGITS(z); t2 = 0; i = nx; while (i--) { t2 = BIGUP(t2) + zds[i]; zds[i] = (BDIGIT)(t2 / dd); t2 %= dd; } RBIGNUM(z)->sign = RBIGNUM(x)->sign==RBIGNUM(y)->sign; if (modp) { *modp = rb_uint2big((unsigned long)t2); RBIGNUM(*modp)->sign = RBIGNUM(x)->sign; } if (divp) *divp = z; return; } z = bignew(nx==ny?nx+2:nx+1, RBIGNUM(x)->sign==RBIGNUM(y)->sign); zds = BDIGITS(z); if (nx==ny) zds[nx+1] = 0; while (!yds[ny-1]) ny--; dd = 0; q = yds[ny-1]; while ((q & (1U<<(BITSPERDIG-1))) == 0) { q <<= 1; dd++; } if (dd) { yy = rb_big_clone(y); tds = BDIGITS(yy); j = 0; t2 = 0; while (j= ny); if (divp) { /* move quotient down in z */ *divp = rb_big_clone(z); zds = BDIGITS(*divp); j = (nx==ny ? nx+2 : nx+1) - ny; for (i = 0;i < j;i++) zds[i] = zds[i+ny]; RBIGNUM(*divp)->len = i; } if (modp) { /* normalize remainder */ *modp = rb_big_clone(z); zds = BDIGITS(*modp); while (--ny && !zds[ny]); ++ny; if (dd) { t2 = 0; i = ny; while(i--) { t2 = (t2 | zds[i]) >> dd; q = zds[i]; zds[i] = BIGLO(t2); t2 = BIGUP(q); } } RBIGNUM(*modp)->len = ny; RBIGNUM(*modp)->sign = RBIGNUM(x)->sign; } } static void bigdivmod(x, y, divp, modp) VALUE x, y; VALUE *divp, *modp; { VALUE mod; bigdivrem(x, y, divp, &mod); if (RBIGNUM(x)->sign != RBIGNUM(y)->sign && !BIGZEROP(mod)) { if (divp) *divp = bigadd(*divp, rb_int2big(1), 0); if (modp) *modp = bigadd(mod, y, 1); } else { if (divp) *divp = *divp; if (modp) *modp = mod; } } /* * call-seq: * big / other => Numeric * big.div(other) => Numeric * * Divides big by other, returning the result. */ static VALUE rb_big_div(x, y) VALUE x, y; { VALUE z; switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); break; case T_BIGNUM: break; default: return rb_num_coerce_bin(x, y); } bigdivmod(x, y, &z, 0); return bignorm(z); } /* * call-seq: * big % other => Numeric * big.modulo(other) => Numeric * * Returns big modulo other. See Numeric.divmod for more * information. */ static VALUE rb_big_modulo(x, y) VALUE x, y; { VALUE z; switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); break; case T_BIGNUM: break; default: return rb_num_coerce_bin(x, y); } bigdivmod(x, y, 0, &z); return bignorm(z); } /* * call-seq: * big.remainder(numeric) => number * * Returns the remainder after dividing big by numeric. * * -1234567890987654321.remainder(13731) #=> -6966 * -1234567890987654321.remainder(13731.24) #=> -9906.22531493148 */ static VALUE rb_big_remainder(x, y) VALUE x, y; { VALUE z; switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); break; case T_BIGNUM: break; default: return rb_num_coerce_bin(x, y); } bigdivrem(x, y, 0, &z); return bignorm(z); } static int bdigbitsize(BDIGIT x) { int size = 1; int nb = BITSPERDIG / 2; BDIGIT bits = (~0 << nb); if (!x) return 0; while (x > 1) { if (x & bits) { size += nb; x >>= nb; } x &= ~bits; nb /= 2; bits >>= nb; } return size; } static VALUE big_lshift _((VALUE, unsigned long)); static VALUE big_rshift _((VALUE, unsigned long)); static VALUE big_shift(x, n) VALUE x; int n; { if (n < 0) return big_lshift(x, (unsigned int)n); else if (n > 0) return big_rshift(x, (unsigned int)n); return x; } /* * call-seq: * big.divmod(numeric) => array * * See Numeric#divmod. * */ VALUE rb_big_divmod(x, y) VALUE x, y; { VALUE div, mod; switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); break; case T_BIGNUM: break; default: return rb_num_coerce_bin(x, y); } bigdivmod(x, y, &div, &mod); return rb_assoc_new(bignorm(div), bignorm(mod)); } /* * call-seq: * big.quo(numeric) -> float * big.fdiv(numeric) -> float * * Returns the floating point result of dividing big by * numeric. * * -1234567890987654321.quo(13731) #=> -89910996357705.5 * -1234567890987654321.quo(13731.24) #=> -89909424858035.7 * */ static VALUE rb_big_quo(x, y) VALUE x, y; { double dx = big2dbl(x); double dy; if (isinf(dx)) { #define DBL_BIGDIG ((DBL_MANT_DIG + BITSPERDIG) / BITSPERDIG) VALUE z; int ex, ey; ex = (RBIGNUM(bigtrunc(x))->len - 1) * BITSPERDIG; ex += bdigbitsize(BDIGITS(x)[RBIGNUM(x)->len - 1]); ex -= 2 * DBL_BIGDIG * BITSPERDIG; if (ex) x = big_shift(x, ex); switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); case T_BIGNUM: { ey = (RBIGNUM(bigtrunc(y))->len - 1) * BITSPERDIG; ey += bdigbitsize(BDIGITS(y)[RBIGNUM(y)->len - 1]); ey -= DBL_BIGDIG * BITSPERDIG; if (ey) y = big_shift(y, ey); bignum: bigdivrem(x, y, &z, 0); return rb_float_new(ldexp(big2dbl(z), ex - ey)); } case T_FLOAT: y = dbl2big(ldexp(frexp(RFLOAT(y)->value, &ey), DBL_MANT_DIG)); ey -= DBL_MANT_DIG; goto bignum; } } switch (TYPE(y)) { case T_FIXNUM: dy = (double)FIX2LONG(y); break; case T_BIGNUM: dy = rb_big2dbl(y); break; case T_FLOAT: dy = RFLOAT(y)->value; break; default: return rb_num_coerce_bin(x, y); } return rb_float_new(dx / dy); } static VALUE bigsqr(x) VALUE x; { long len = RBIGNUM(x)->len, k = len / 2, i; VALUE a, b, a2, z; BDIGIT_DBL num; if (len < 4000 / BITSPERDIG) { return rb_big_mul0(x, x); } a = bignew(len - k, 1); MEMCPY(BDIGITS(a), BDIGITS(x) + k, BDIGIT, len - k); b = bignew(k, 1); MEMCPY(BDIGITS(b), BDIGITS(x), BDIGIT, k); a2 = bigtrunc(bigsqr(a)); z = bigsqr(b); REALLOC_N(RBIGNUM(z)->digits, BDIGIT, (len = 2 * k + RBIGNUM(a2)->len) + 1); while (RBIGNUM(z)->len < 2 * k) BDIGITS(z)[RBIGNUM(z)->len++] = 0; MEMCPY(BDIGITS(z) + 2 * k, BDIGITS(a2), BDIGIT, RBIGNUM(a2)->len); RBIGNUM(z)->len = len; a2 = bigtrunc(rb_big_mul0(a, b)); len = RBIGNUM(a2)->len; TRAP_BEG; for (i = 0, num = 0; i < len; i++) { num += (BDIGIT_DBL)BDIGITS(z)[i + k] + ((BDIGIT_DBL)BDIGITS(a2)[i] << 1); BDIGITS(z)[i + k] = BIGLO(num); num = BIGDN(num); } TRAP_END; if (num) { len = RBIGNUM(z)->len; for (i += k; i < len && num; ++i) { num += (BDIGIT_DBL)BDIGITS(z)[i]; BDIGITS(z)[i] = BIGLO(num); num = BIGDN(num); } if (num) { BDIGITS(z)[RBIGNUM(z)->len++] = BIGLO(num); } } return bigtrunc(z); } /* * call-seq: * big ** exponent #=> numeric * * Raises _big_ to the _exponent_ power (which may be an integer, float, * or anything that will coerce to a number). The result may be * a Fixnum, Bignum, or Float * * 123456789 ** 2 #=> 15241578750190521 * 123456789 ** 1.2 #=> 5126464716.09932 * 123456789 ** -2 #=> 6.5610001194102e-17 */ VALUE rb_big_pow(x, y) VALUE x, y; { double d; long yy; if (y == INT2FIX(0)) return INT2FIX(1); switch (TYPE(y)) { case T_FLOAT: d = RFLOAT(y)->value; break; case T_BIGNUM: rb_warn("in a**b, b may be too big"); d = rb_big2dbl(y); break; case T_FIXNUM: yy = FIX2LONG(y); if (yy > 0) { VALUE z = 0; long mask; const long BIGLEN_LIMIT = 1024*1024 / SIZEOF_BDIGITS; if ((RBIGNUM(x)->len > BIGLEN_LIMIT) || (RBIGNUM(x)->len > BIGLEN_LIMIT / yy)) { rb_warn("in a**b, b may be too big"); d = (double)yy; break; } for (mask = FIXNUM_MAX + 1; mask; mask >>= 1) { if (z) z = bigtrunc(bigsqr(z)); if (yy & mask) { z = z ? bigtrunc(rb_big_mul0(z, x)) : x; } } return bignorm(z); } d = (double)yy; break; default: return rb_num_coerce_bin(x, y); } return rb_float_new(pow(rb_big2dbl(x), d)); } /* * call-seq: * big & numeric => integer * * Performs bitwise +and+ between _big_ and _numeric_. */ VALUE rb_big_and(xx, yy) VALUE xx, yy; { volatile VALUE x, y, z; BDIGIT *ds1, *ds2, *zds; long i, l1, l2; char sign; x = xx; y = rb_to_int(yy); if (FIXNUM_P(y)) { y = rb_int2big(FIX2LONG(y)); } if (!RBIGNUM(y)->sign) { y = rb_big_clone(y); get2comp(y); } if (!RBIGNUM(x)->sign) { x = rb_big_clone(x); get2comp(x); } if (RBIGNUM(x)->len > RBIGNUM(y)->len) { l1 = RBIGNUM(y)->len; l2 = RBIGNUM(x)->len; ds1 = BDIGITS(y); ds2 = BDIGITS(x); sign = RBIGNUM(y)->sign; } else { l1 = RBIGNUM(x)->len; l2 = RBIGNUM(y)->len; ds1 = BDIGITS(x); ds2 = BDIGITS(y); sign = RBIGNUM(x)->sign; } z = bignew(l2, RBIGNUM(x)->sign || RBIGNUM(y)->sign); zds = BDIGITS(z); for (i=0; isign) get2comp(z); return bignorm(z); } /* * call-seq: * big | numeric => integer * * Performs bitwise +or+ between _big_ and _numeric_. */ VALUE rb_big_or(xx, yy) VALUE xx, yy; { volatile VALUE x, y, z; BDIGIT *ds1, *ds2, *zds; long i, l1, l2; char sign; x = xx; y = rb_to_int(yy); if (FIXNUM_P(y)) { y = rb_int2big(FIX2LONG(y)); } if (!RBIGNUM(y)->sign) { y = rb_big_clone(y); get2comp(y); } if (!RBIGNUM(x)->sign) { x = rb_big_clone(x); get2comp(x); } if (RBIGNUM(x)->len > RBIGNUM(y)->len) { l1 = RBIGNUM(y)->len; l2 = RBIGNUM(x)->len; ds1 = BDIGITS(y); ds2 = BDIGITS(x); sign = RBIGNUM(y)->sign; } else { l1 = RBIGNUM(x)->len; l2 = RBIGNUM(y)->len; ds1 = BDIGITS(x); ds2 = BDIGITS(y); sign = RBIGNUM(x)->sign; } z = bignew(l2, RBIGNUM(x)->sign && RBIGNUM(y)->sign); zds = BDIGITS(z); for (i=0; isign) get2comp(z); return bignorm(z); } /* * call-seq: * big ^ numeric => integer * * Performs bitwise +exclusive or+ between _big_ and _numeric_. */ VALUE rb_big_xor(xx, yy) VALUE xx, yy; { volatile VALUE x, y; VALUE z; BDIGIT *ds1, *ds2, *zds; long i, l1, l2; char sign; x = xx; y = rb_to_int(yy); if (FIXNUM_P(y)) { y = rb_int2big(FIX2LONG(y)); } if (!RBIGNUM(y)->sign) { y = rb_big_clone(y); get2comp(y); } if (!RBIGNUM(x)->sign) { x = rb_big_clone(x); get2comp(x); } if (RBIGNUM(x)->len > RBIGNUM(y)->len) { l1 = RBIGNUM(y)->len; l2 = RBIGNUM(x)->len; ds1 = BDIGITS(y); ds2 = BDIGITS(x); sign = RBIGNUM(y)->sign; } else { l1 = RBIGNUM(x)->len; l2 = RBIGNUM(y)->len; ds1 = BDIGITS(x); ds2 = BDIGITS(y); sign = RBIGNUM(x)->sign; } RBIGNUM(x)->sign = RBIGNUM(x)->sign?1:0; RBIGNUM(y)->sign = RBIGNUM(y)->sign?1:0; z = bignew(l2, !(RBIGNUM(x)->sign ^ RBIGNUM(y)->sign)); zds = BDIGITS(z); for (i=0; isign) get2comp(z); return bignorm(z); } static VALUE check_shiftdown(VALUE y, VALUE x) { if (!RBIGNUM(x)->len) return INT2FIX(0); if (RBIGNUM(y)->len > SIZEOF_LONG / SIZEOF_BDIGITS) { return RBIGNUM(x)->sign ? INT2FIX(0) : INT2FIX(-1); } return Qnil; } /* * call-seq: * big << numeric => integer * * Shifts big left _numeric_ positions (right if _numeric_ is negative). */ VALUE rb_big_lshift(x, y) VALUE x, y; { long shift; int neg = 0; for (;;) { if (FIXNUM_P(y)) { shift = FIX2LONG(y); if (shift < 0) { neg = 1; shift = -shift; } break; } else if (TYPE(y) == T_BIGNUM) { if (!RBIGNUM(y)->sign) { VALUE t = check_shiftdown(y, x); if (!NIL_P(t)) return t; neg = 1; } shift = big2ulong(y, "long"); break; } y = rb_to_int(y); } x = neg ? big_rshift(x, shift) : big_lshift(x, shift); return bignorm(x); } static VALUE big_lshift(x, shift) VALUE x; unsigned long shift; { BDIGIT *xds, *zds; long s1 = shift/BITSPERDIG; int s2 = shift%BITSPERDIG; VALUE z; BDIGIT_DBL num = 0; long len, i; len = RBIGNUM(x)->len; z = bignew(len+s1+1, RBIGNUM(x)->sign); zds = BDIGITS(z); for (i=0; i> numeric => integer * * Shifts big right _numeric_ positions (left if _numeric_ is negative). */ VALUE rb_big_rshift(x, y) VALUE x, y; { long shift; int neg = 0; for (;;) { if (FIXNUM_P(y)) { shift = FIX2LONG(y); if (shift < 0) { neg = 1; shift = -shift; } break; } else if (TYPE(y) == T_BIGNUM) { if (RBIGNUM(y)->sign) { VALUE t = check_shiftdown(y, x); if (!NIL_P(t)) return t; } else { neg = 1; } shift = big2ulong(y, "long"); break; } y = rb_to_int(y); } x = neg ? big_lshift(x, shift) : big_rshift(x, shift); return bignorm(x); } static VALUE big_rshift(x, shift) VALUE x; unsigned long shift; { BDIGIT *xds, *zds; long s1 = shift/BITSPERDIG; int s2 = shift%BITSPERDIG; VALUE z; BDIGIT_DBL num = 0; long i, j; volatile VALUE save_x; if (s1 > RBIGNUM(x)->len) { if (RBIGNUM(x)->sign) return INT2FIX(0); else return INT2FIX(-1); } if (!RBIGNUM(x)->sign) { save_x = x = rb_big_clone(x); get2comp(x); } xds = BDIGITS(x); i = RBIGNUM(x)->len; j = i - s1; if (j == 0) { if (RBIGNUM(x)->sign) return INT2FIX(0); else return INT2FIX(-1); } z = bignew(j, RBIGNUM(x)->sign); if (!RBIGNUM(x)->sign) { num = ((BDIGIT_DBL)~0) << BITSPERDIG; } zds = BDIGITS(z); while (i--, j--) { num = (num | xds[i]) >> s2; zds[j] = BIGLO(num); num = BIGUP(xds[i]); } if (!RBIGNUM(x)->sign) { get2comp(z); } return z; } /* * call-seq: * big[n] -> 0, 1 * * Bit Reference---Returns the nth bit in the (assumed) binary * representation of big, where big[0] is the least * significant bit. * * a = 9**15 * 50.downto(0) do |n| * print a[n] * end * * produces: * * 000101110110100000111000011110010100111100010111001 * */ static VALUE rb_big_aref(x, y) VALUE x, y; { BDIGIT *xds; BDIGIT_DBL num; unsigned long shift; long i, s1, s2; if (TYPE(y) == T_BIGNUM) { if (!RBIGNUM(y)->sign) return INT2FIX(0); if (RBIGNUM(bigtrunc(y))->len > SIZEOF_LONG/SIZEOF_BDIGITS) { out_of_range: return RBIGNUM(x)->sign ? INT2FIX(0) : INT2FIX(1); } shift = big2ulong(y, "long"); } else { i = NUM2LONG(y); if (i < 0) return INT2FIX(0); shift = (VALUE)i; } s1 = shift/BITSPERDIG; s2 = shift%BITSPERDIG; if (s1 >= RBIGNUM(x)->len) goto out_of_range; if (!RBIGNUM(x)->sign) { xds = BDIGITS(x); i = 0; num = 1; while (num += ~xds[i], ++i <= s1) { num = BIGDN(num); } } else { num = BDIGITS(x)[s1]; } if (num & ((BDIGIT_DBL)1< fixnum * * Compute a hash based on the value of _big_. */ static VALUE rb_big_hash(x) VALUE x; { long i, len, key; BDIGIT *digits; key = 0; digits = BDIGITS(x); len = RBIGNUM(x)->len; for (i=0; i aBignum * * Returns the absolute value of big. * * -1234567890987654321.abs #=> 1234567890987654321 */ static VALUE rb_big_abs(x) VALUE x; { if (!RBIGNUM(x)->sign) { x = rb_big_clone(x); RBIGNUM(x)->sign = 1; } return x; } VALUE rb_big_rand(max, rand_buf) VALUE max; double *rand_buf; { VALUE v; long len = RBIGNUM(max)->len; if (BIGZEROP(max)) { return rb_float_new(rand_buf[0]); } v = bignew(len,1); len--; BDIGITS(v)[len] = BDIGITS(max)[len] * rand_buf[len]; while (len--) { BDIGITS(v)[len] = ((BDIGIT)~0) * rand_buf[len]; } return v; } /* * call-seq: * big.size -> integer * * Returns the number of bytes in the machine representation of * big. * * (256**10 - 1).size #=> 12 * (256**20 - 1).size #=> 20 * (256**40 - 1).size #=> 40 */ static VALUE rb_big_size(big) VALUE big; { return LONG2FIX(RBIGNUM(big)->len*SIZEOF_BDIGITS); } /* * Bignum objects hold integers outside the range of * Fixnum. Bignum objects are created * automatically when integer calculations would otherwise overflow a * Fixnum. When a calculation involving * Bignum objects returns a result that will fit in a * Fixnum, the result is automatically converted. * * For the purposes of the bitwise operations and [], a * Bignum is treated as if it were an infinite-length * bitstring with 2's complement representation. * * While Fixnum values are immediate, Bignum * objects are not---assignment and parameter passing work with * references to objects, not the objects themselves. * */ void Init_Bignum() { rb_cBignum = rb_define_class("Bignum", rb_cInteger); rb_define_method(rb_cBignum, "to_s", rb_big_to_s, -1); rb_define_method(rb_cBignum, "coerce", rb_big_coerce, 1); rb_define_method(rb_cBignum, "-@", rb_big_uminus, 0); rb_define_method(rb_cBignum, "+", rb_big_plus, 1); rb_define_method(rb_cBignum, "-", rb_big_minus, 1); rb_define_method(rb_cBignum, "*", rb_big_mul, 1); rb_define_method(rb_cBignum, "/", rb_big_div, 1); rb_define_method(rb_cBignum, "%", rb_big_modulo, 1); rb_define_method(rb_cBignum, "div", rb_big_div, 1); rb_define_method(rb_cBignum, "divmod", rb_big_divmod, 1); rb_define_method(rb_cBignum, "modulo", rb_big_modulo, 1); rb_define_method(rb_cBignum, "remainder", rb_big_remainder, 1); rb_define_method(rb_cBignum, "quo", rb_big_quo, 1); rb_define_method(rb_cBignum, "fdiv", rb_big_quo, 1); rb_define_method(rb_cBignum, "**", rb_big_pow, 1); rb_define_method(rb_cBignum, "&", rb_big_and, 1); rb_define_method(rb_cBignum, "|", rb_big_or, 1); rb_define_method(rb_cBignum, "^", rb_big_xor, 1); rb_define_method(rb_cBignum, "~", rb_big_neg, 0); rb_define_method(rb_cBignum, "<<", rb_big_lshift, 1); rb_define_method(rb_cBignum, ">>", rb_big_rshift, 1); rb_define_method(rb_cBignum, "[]", rb_big_aref, 1); rb_define_method(rb_cBignum, "<=>", rb_big_cmp, 1); rb_define_method(rb_cBignum, "==", rb_big_eq, 1); rb_define_method(rb_cBignum, "eql?", rb_big_eql, 1); rb_define_method(rb_cBignum, "hash", rb_big_hash, 0); rb_define_method(rb_cBignum, "to_f", rb_big_to_f, 0); rb_define_method(rb_cBignum, "abs", rb_big_abs, 0); rb_define_method(rb_cBignum, "size", rb_big_size, 0); } ================================================ FILE: bin/erb ================================================ #!/usr/bin/env ruby # Tiny eRuby --- ERB2 # Copyright (c) 1999-2000,2002 Masatoshi SEKI # You can redistribute it and/or modify it under the same terms as Ruby. require 'erb' class ERB module Main def ARGV.switch return nil if self.empty? arg = self.shift return nil if arg == '--' if arg =~ /^-(.)(.*)/ return arg if $1 == '-' raise 'unknown switch "-"' if $2.index('-') self.unshift "-#{$2}" if $2.size > 0 "-#{$1}" else self.unshift arg nil end end def ARGV.req_arg self.shift || raise('missing argument') end def trim_mode_opt(trim_mode, disable_percent) return trim_mode if disable_percent case trim_mode when 0 return '%' when 1 return '%>' when 2 return '%<>' when '-' return '%-' end end module_function :trim_mode_opt def run(factory=ERB) trim_mode = 0 disable_percent = false begin while switch = ARGV.switch case switch when '-x' # ruby source output = true when '-n' # line number number = true when '-v' # verbose $VERBOSE = true when '--version' # version STDERR.puts factory.version exit when '-d', '--debug' # debug $DEBUG = true when '-r' # require require ARGV.req_arg when '-S' # security level arg = ARGV.req_arg raise "invalid safe_level #{arg.dump}" unless arg =~ /^[0-4]$/ safe_level = arg.to_i when '-T' # trim mode arg = ARGV.req_arg if arg == '-' trim_mode = arg next end raise "invalid trim mode #{arg.dump}" unless arg =~ /^[0-2]$/ trim_mode = arg.to_i when '-K' # KCODE arg = ARGV.req_arg case arg.downcase when 'e', '-e', 'euc' $KCODE = 'EUC' when 's', '-s', 'sjis' $KCODE = 'SJIS' when 'u', '-u', 'utf8' $KCODE = 'UTF8' when 'n', '-n', 'none' $KCODE = 'NONE' else raise "invalid KCODE #{arg.dump}" end when '-P' disable_percent = true when '--help' raise "print this help" else raise "unknown switch #{switch.dump}" end end rescue # usage STDERR.puts $!.to_s STDERR.puts File.basename($0) + " [switches] [inputfile]" STDERR.puts </lib/ruby/site_ruby//rdoc... # # Now that RDoc is part of the distribution, it's installed into # /lib/ruby/, which unfortunately appears later in the # search path. This means that if you have previously installed RDoc, # and then install from ruby-lang, you'll pick up the old one by # default. This hack checks for the condition, and readjusts the # search path if necessary. def adjust_for_existing_rdoc(path) $stderr.puts %{ It seems as if you have a previously-installed RDoc in the directory #{path}. Because this is now out-of-date, you might want to consider removing the directories: #{File.join(path, "rdoc")} and #{File.join(path, "markup")} } # Move all the site_ruby directories to the end p $: $:.replace($:.partition {|path| /site_ruby/ !~ path}.flatten) p $: end $:.each do |path| if /site_ruby/ =~ path rdoc_path = File.join(path, 'rdoc', 'rdoc.rb') if File.exists?(rdoc_path) adjust_for_existing_rdoc(path) break end end end ## End of Transitional Hack ## require 'rdoc/rdoc' begin r = RDoc::RDoc.new r.document(ARGV) rescue RDoc::RDocError => e $stderr.puts e.message exit(1) end ================================================ FILE: bin/ri ================================================ #!/usr/bin/env ruby # usage: # # ri name... # # where name can be # # Class | Class::method | Class#method | Class.method | method # # All names may be abbreviated to their minimum unbiguous form. If a name # _is_ ambiguous, all valid options will be listed. # # The form '.' method matches either class or instance methods, while # #method matches only instance and ::method matches only class methods. # # # == Installing Documentation # # 'ri' uses a database of documentation built by the RDoc utility. # # So, how do you install this documentation on your system? # It depends on how you installed Ruby. # # If you installed Ruby from source files (that is, if it some point # you typed 'make' during the process :), you can install the RDoc # documentation yourself. Just go back to the place where you have # your Ruby source and type # # make install-doc # # You'll probably need to do this as a superuser, as the documentation # is installed in the Ruby target tree (normally somewhere under # /usr/local. # # If you installed Ruby from a binary distribution (perhaps # using a one-click installer, or using some other packaging system), # then the team that produced the package probably forgot to package # the documentation as well. Contact them, and see if they can add # it to the next release. # require 'rdoc/ri/ri_driver' ###################################################################### ri = RiDriver.new ri.process_args ================================================ FILE: bin/testrb ================================================ #!/usr/bin/env ruby require 'test/unit' (r = Test::Unit::AutoRunner.new(true)).process_args(ARGV) or abort r.options.banner + " tests..." exit r.run ================================================ FILE: class.c ================================================ /********************************************************************** class.c - $Author$ $Date$ created at: Tue Aug 10 15:05:44 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #include "ruby.h" #include "rubysig.h" #include "node.h" #include "st.h" #include extern st_table *rb_class_tbl; VALUE rb_class_boot(super) VALUE super; { NEWOBJ(klass, struct RClass); OBJSETUP(klass, rb_cClass, T_CLASS); klass->super = super; klass->iv_tbl = 0; klass->m_tbl = 0; /* safe GC */ klass->m_tbl = st_init_numtable(); OBJ_INFECT(klass, super); return (VALUE)klass; } VALUE rb_class_new(super) VALUE super; { Check_Type(super, T_CLASS); if (super == rb_cClass) { rb_raise(rb_eTypeError, "can't make subclass of Class"); } if (FL_TEST(super, FL_SINGLETON)) { rb_raise(rb_eTypeError, "can't make subclass of virtual class"); } return rb_class_boot(super); } struct clone_method_data { st_table *tbl; VALUE klass; }; static int clone_method(mid, body, data) ID mid; NODE *body; struct clone_method_data *data; { NODE *fbody = body->nd_body; if (fbody && nd_type(fbody) == NODE_SCOPE) { NODE *cref = (NODE*)fbody->nd_rval; if (cref) cref = cref->nd_next; fbody = rb_copy_node_scope(fbody, NEW_CREF(data->klass, cref)); } st_insert(data->tbl, mid, (st_data_t)NEW_METHOD(fbody, body->nd_noex)); return ST_CONTINUE; } /* :nodoc: */ VALUE rb_mod_init_copy(clone, orig) VALUE clone, orig; { rb_obj_init_copy(clone, orig); if (!FL_TEST(CLASS_OF(clone), FL_SINGLETON)) { RBASIC(clone)->klass = RBASIC(orig)->klass; RBASIC(clone)->klass = rb_singleton_class_clone(clone); } RCLASS(clone)->super = RCLASS(orig)->super; if (RCLASS(orig)->iv_tbl) { ID id; RCLASS(clone)->iv_tbl = st_copy(RCLASS(orig)->iv_tbl); id = rb_intern("__classpath__"); st_delete(RCLASS(clone)->iv_tbl, (st_data_t*)&id, 0); id = rb_intern("__classid__"); st_delete(RCLASS(clone)->iv_tbl, (st_data_t*)&id, 0); } if (RCLASS(orig)->m_tbl) { struct clone_method_data data; data.tbl = RCLASS(clone)->m_tbl = st_init_numtable(); data.klass = (VALUE)clone; st_foreach(RCLASS(orig)->m_tbl, clone_method, (st_data_t)&data); } return clone; } /* :nodoc: */ VALUE rb_class_init_copy(clone, orig) VALUE clone, orig; { if (RCLASS(clone)->super != 0) { rb_raise(rb_eTypeError, "already initialized class"); } if (FL_TEST(orig, FL_SINGLETON)) { rb_raise(rb_eTypeError, "can't copy singleton class"); } return rb_mod_init_copy(clone, orig); } VALUE rb_singleton_class_clone(obj) VALUE obj; { VALUE klass = RBASIC(obj)->klass; if (!FL_TEST(klass, FL_SINGLETON)) return klass; else { /* copy singleton(unnamed) class */ NEWOBJ(clone, struct RClass); OBJSETUP(clone, 0, RBASIC(klass)->flags); if (BUILTIN_TYPE(obj) == T_CLASS) { RBASIC(clone)->klass = (VALUE)clone; } else { RBASIC(clone)->klass = rb_singleton_class_clone(klass); } clone->super = RCLASS(klass)->super; clone->iv_tbl = 0; clone->m_tbl = 0; if (RCLASS(klass)->iv_tbl) { clone->iv_tbl = st_copy(RCLASS(klass)->iv_tbl); } { struct clone_method_data data; data.tbl = clone->m_tbl = st_init_numtable(); switch (TYPE(obj)) { case T_CLASS: case T_MODULE: data.klass = obj; break; default: data.klass = Qnil; break; } st_foreach(RCLASS(klass)->m_tbl, clone_method, (st_data_t)&data); } rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone); FL_SET(clone, FL_SINGLETON); return (VALUE)clone; } } void rb_singleton_class_attached(klass, obj) VALUE klass, obj; { if (FL_TEST(klass, FL_SINGLETON)) { if (!RCLASS(klass)->iv_tbl) { RCLASS(klass)->iv_tbl = st_init_numtable(); } st_insert(RCLASS(klass)->iv_tbl, rb_intern("__attached__"), obj); } } VALUE rb_make_metaclass(obj, super) VALUE obj, super; { VALUE klass = rb_class_boot(super); FL_SET(klass, FL_SINGLETON); RBASIC(obj)->klass = klass; rb_singleton_class_attached(klass, obj); if (BUILTIN_TYPE(obj) == T_CLASS && FL_TEST(obj, FL_SINGLETON)) { RBASIC(klass)->klass = klass; RCLASS(klass)->super = RBASIC(rb_class_real(RCLASS(obj)->super))->klass; } else { VALUE metasuper = RBASIC(rb_class_real(super))->klass; /* metaclass of a superclass may be NULL at boot time */ if (metasuper) { RBASIC(klass)->klass = metasuper; } } return klass; } VALUE rb_define_class_id(id, super) ID id; VALUE super; { VALUE klass; if (!super) super = rb_cObject; klass = rb_class_new(super); rb_make_metaclass(klass, RBASIC(super)->klass); return klass; } void rb_check_inheritable(super) VALUE super; { if (TYPE(super) != T_CLASS) { rb_raise(rb_eTypeError, "superclass must be a Class (%s given)", rb_obj_classname(super)); } if (RBASIC(super)->flags & FL_SINGLETON) { rb_raise(rb_eTypeError, "can't make subclass of virtual class"); } } VALUE rb_class_inherited(super, klass) VALUE super, klass; { if (!super) super = rb_cObject; return rb_funcall(super, rb_intern("inherited"), 1, klass); } VALUE rb_define_class(name, super) const char *name; VALUE super; { VALUE klass; ID id; id = rb_intern(name); if (rb_const_defined(rb_cObject, id)) { klass = rb_const_get(rb_cObject, id); if (TYPE(klass) != T_CLASS) { rb_raise(rb_eTypeError, "%s is not a class", name); } if (rb_class_real(RCLASS(klass)->super) != super) { rb_name_error(id, "%s is already defined", name); } return klass; } if (!super) { rb_warn("no super class for `%s', Object assumed", name); } klass = rb_define_class_id(id, super); st_add_direct(rb_class_tbl, id, klass); rb_name_class(klass, id); rb_const_set(rb_cObject, id, klass); rb_class_inherited(super, klass); return klass; } VALUE rb_define_class_under(outer, name, super) VALUE outer; const char *name; VALUE super; { VALUE klass; ID id; id = rb_intern(name); if (rb_const_defined_at(outer, id)) { klass = rb_const_get_at(outer, id); if (TYPE(klass) != T_CLASS) { rb_raise(rb_eTypeError, "%s is not a class", name); } if (rb_class_real(RCLASS(klass)->super) != super) { rb_name_error(id, "%s is already defined", name); } return klass; } if (!super) { rb_warn("no super class for `%s::%s', Object assumed", rb_class2name(outer), name); } klass = rb_define_class_id(id, super); rb_set_class_path(klass, outer, name); rb_const_set(outer, id, klass); rb_class_inherited(super, klass); return klass; } VALUE rb_module_new() { NEWOBJ(mdl, struct RClass); OBJSETUP(mdl, rb_cModule, T_MODULE); mdl->super = 0; mdl->iv_tbl = 0; mdl->m_tbl = 0; mdl->m_tbl = st_init_numtable(); return (VALUE)mdl; } VALUE rb_define_module_id(id) ID id; { VALUE mdl; mdl = rb_module_new(); rb_name_class(mdl, id); return mdl; } VALUE rb_define_module(name) const char *name; { VALUE module; ID id; id = rb_intern(name); if (rb_const_defined(rb_cObject, id)) { module = rb_const_get(rb_cObject, id); if (TYPE(module) == T_MODULE) return module; rb_raise(rb_eTypeError, "%s is not a module", rb_obj_classname(module)); } module = rb_define_module_id(id); st_add_direct(rb_class_tbl, id, module); rb_const_set(rb_cObject, id, module); return module; } VALUE rb_define_module_under(outer, name) VALUE outer; const char *name; { VALUE module; ID id; id = rb_intern(name); if (rb_const_defined_at(outer, id)) { module = rb_const_get_at(outer, id); if (TYPE(module) == T_MODULE) return module; rb_raise(rb_eTypeError, "%s::%s is not a module", rb_class2name(outer), rb_obj_classname(module)); } module = rb_define_module_id(id); rb_const_set(outer, id, module); rb_set_class_path(module, outer, name); return module; } static VALUE include_class_new(module, super) VALUE module, super; { NEWOBJ(klass, struct RClass); OBJSETUP(klass, rb_cClass, T_ICLASS); if (BUILTIN_TYPE(module) == T_ICLASS) { module = RBASIC(module)->klass; } if (!RCLASS(module)->iv_tbl) { RCLASS(module)->iv_tbl = st_init_numtable(); } klass->iv_tbl = RCLASS(module)->iv_tbl; klass->m_tbl = RCLASS(module)->m_tbl; klass->super = super; if (TYPE(module) == T_ICLASS) { RBASIC(klass)->klass = RBASIC(module)->klass; } else { RBASIC(klass)->klass = module; } OBJ_INFECT(klass, module); OBJ_INFECT(klass, super); return (VALUE)klass; } void rb_include_module(klass, module) VALUE klass, module; { VALUE p, c; int changed = 0; rb_frozen_class_p(klass); if (!OBJ_TAINTED(klass)) { rb_secure(4); } if (TYPE(module) != T_MODULE) { Check_Type(module, T_MODULE); } OBJ_INFECT(klass, module); c = klass; while (module) { int superclass_seen = Qfalse; if (RCLASS(klass)->m_tbl == RCLASS(module)->m_tbl) rb_raise(rb_eArgError, "cyclic include detected"); /* ignore if the module included already in superclasses */ for (p = RCLASS(klass)->super; p; p = RCLASS(p)->super) { switch (BUILTIN_TYPE(p)) { case T_ICLASS: if (RCLASS(p)->m_tbl == RCLASS(module)->m_tbl) { if (!superclass_seen) { c = p; /* move insertion point */ } goto skip; } break; case T_CLASS: superclass_seen = Qtrue; break; } } c = RCLASS(c)->super = include_class_new(module, RCLASS(c)->super); changed = 1; skip: module = RCLASS(module)->super; } if (changed) rb_clear_cache(); } /* * call-seq: * mod.included_modules -> array * * Returns the list of modules included in mod. * * module Mixin * end * * module Outer * include Mixin * end * * Mixin.included_modules #=> [] * Outer.included_modules #=> [Mixin] */ VALUE rb_mod_included_modules(mod) VALUE mod; { VALUE ary = rb_ary_new(); VALUE p; for (p = RCLASS(mod)->super; p; p = RCLASS(p)->super) { if (BUILTIN_TYPE(p) == T_ICLASS) { rb_ary_push(ary, RBASIC(p)->klass); } } return ary; } /* * call-seq: * mod.include?(module) => true or false * * Returns true if module is included in * mod or one of mod's ancestors. * * module A * end * class B * include A * end * class C < B * end * B.include?(A) #=> true * C.include?(A) #=> true * A.include?(A) #=> false */ VALUE rb_mod_include_p(mod, mod2) VALUE mod; VALUE mod2; { VALUE p; Check_Type(mod2, T_MODULE); for (p = RCLASS(mod)->super; p; p = RCLASS(p)->super) { if (BUILTIN_TYPE(p) == T_ICLASS) { if (RBASIC(p)->klass == mod2) return Qtrue; } } return Qfalse; } /* * call-seq: * mod.ancestors -> array * * Returns a list of modules included in mod (including * mod itself). * * module Mod * include Math * include Comparable * end * * Mod.ancestors #=> [Mod, Comparable, Math] * Math.ancestors #=> [Math] */ VALUE rb_mod_ancestors(mod) VALUE mod; { VALUE p, ary = rb_ary_new(); for (p = mod; p; p = RCLASS(p)->super) { if (FL_TEST(p, FL_SINGLETON)) continue; if (BUILTIN_TYPE(p) == T_ICLASS) { rb_ary_push(ary, RBASIC(p)->klass); } else { rb_ary_push(ary, p); } } return ary; } #define VISI(x) ((x)&NOEX_MASK) #define VISI_CHECK(x,f) (VISI(x) == (f)) static int ins_methods_push(name, type, ary, visi) ID name; long type; VALUE ary; long visi; { if (type == -1) return ST_CONTINUE; switch (visi) { case NOEX_PRIVATE: case NOEX_PROTECTED: case NOEX_PUBLIC: visi = (type == visi); break; default: visi = (type != NOEX_PRIVATE); break; } if (visi) { rb_ary_push(ary, rb_str_new2(rb_id2name(name))); } return ST_CONTINUE; } static int ins_methods_i(name, type, ary) ID name; long type; VALUE ary; { return ins_methods_push(name, type, ary, -1); /* everything but private */ } static int ins_methods_prot_i(name, type, ary) ID name; long type; VALUE ary; { return ins_methods_push(name, type, ary, NOEX_PROTECTED); } static int ins_methods_priv_i(name, type, ary) ID name; long type; VALUE ary; { return ins_methods_push(name, type, ary, NOEX_PRIVATE); } static int ins_methods_pub_i(name, type, ary) ID name; long type; VALUE ary; { return ins_methods_push(name, type, ary, NOEX_PUBLIC); } static int method_entry(key, body, list) ID key; NODE *body; st_table *list; { long type; if (key == ID_ALLOCATOR) return ST_CONTINUE; if (!st_lookup(list, key, 0)) { if (!body->nd_body) type = -1; /* none */ else type = VISI(body->nd_noex); st_add_direct(list, key, type); } return ST_CONTINUE; } static VALUE class_instance_method_list(argc, argv, mod, func) int argc; VALUE *argv; VALUE mod; int (*func) _((ID, long, VALUE)); { VALUE ary; int recur; st_table *list; if (argc == 0) { recur = Qtrue; } else { VALUE r; rb_scan_args(argc, argv, "01", &r); recur = RTEST(r); } list = st_init_numtable(); for (; mod; mod = RCLASS(mod)->super) { st_foreach(RCLASS(mod)->m_tbl, method_entry, (st_data_t)list); if (BUILTIN_TYPE(mod) == T_ICLASS) continue; if (FL_TEST(mod, FL_SINGLETON)) continue; if (!recur) break; } ary = rb_ary_new(); st_foreach(list, func, ary); st_free_table(list); return ary; } /* * call-seq: * mod.instance_methods(include_super=true) => array * * Returns an array containing the names of public instance methods in * the receiver. For a module, these are the public methods; for a * class, they are the instance (not singleton) methods. With no * argument, or with an argument that is false, the * instance methods in mod are returned, otherwise the methods * in mod and mod's superclasses are returned. * * module A * def method1() end * end * class B * def method2() end * end * class C < B * def method3() end * end * * A.instance_methods #=> ["method1"] * B.instance_methods(false) #=> ["method2"] * C.instance_methods(false) #=> ["method3"] * C.instance_methods(true).length #=> 43 */ VALUE rb_class_instance_methods(argc, argv, mod) int argc; VALUE *argv; VALUE mod; { return class_instance_method_list(argc, argv, mod, ins_methods_i); } /* * call-seq: * mod.protected_instance_methods(include_super=true) => array * * Returns a list of the protected instance methods defined in * mod. If the optional parameter is not false, the * methods of any ancestors are included. */ VALUE rb_class_protected_instance_methods(argc, argv, mod) int argc; VALUE *argv; VALUE mod; { return class_instance_method_list(argc, argv, mod, ins_methods_prot_i); } /* * call-seq: * mod.private_instance_methods(include_super=true) => array * * Returns a list of the private instance methods defined in * mod. If the optional parameter is not false, the * methods of any ancestors are included. * * module Mod * def method1() end * private :method1 * def method2() end * end * Mod.instance_methods #=> ["method2"] * Mod.private_instance_methods #=> ["method1"] */ VALUE rb_class_private_instance_methods(argc, argv, mod) int argc; VALUE *argv; VALUE mod; { return class_instance_method_list(argc, argv, mod, ins_methods_priv_i); } /* * call-seq: * mod.public_instance_methods(include_super=true) => array * * Returns a list of the public instance methods defined in mod. * If the optional parameter is not false, the methods of * any ancestors are included. */ VALUE rb_class_public_instance_methods(argc, argv, mod) int argc; VALUE *argv; VALUE mod; { return class_instance_method_list(argc, argv, mod, ins_methods_pub_i); } /* * call-seq: * obj.singleton_methods(all=true) => array * * Returns an array of the names of singleton methods for obj. * If the optional all parameter is true, the list will include * methods in modules included in obj. * * module Other * def three() end * end * * class Single * def Single.four() end * end * * a = Single.new * * def a.one() * end * * class << a * include Other * def two() * end * end * * Single.singleton_methods #=> ["four"] * a.singleton_methods(false) #=> ["two", "one"] * a.singleton_methods #=> ["two", "one", "three"] */ VALUE rb_obj_singleton_methods(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE recur, ary, klass; st_table *list; rb_scan_args(argc, argv, "01", &recur); if (argc == 0) { recur = Qtrue; } klass = CLASS_OF(obj); list = st_init_numtable(); if (klass && FL_TEST(klass, FL_SINGLETON)) { st_foreach(RCLASS(klass)->m_tbl, method_entry, (st_data_t)list); klass = RCLASS(klass)->super; } if (RTEST(recur)) { while (klass && (FL_TEST(klass, FL_SINGLETON) || TYPE(klass) == T_ICLASS)) { st_foreach(RCLASS(klass)->m_tbl, method_entry, (st_data_t)list); klass = RCLASS(klass)->super; } } ary = rb_ary_new(); st_foreach(list, ins_methods_i, ary); st_free_table(list); return ary; } void rb_define_method_id(klass, name, func, argc) VALUE klass; ID name; VALUE (*func)(); int argc; { rb_add_method(klass, name, NEW_CFUNC(func,argc), NOEX_PUBLIC); } void rb_define_method(klass, name, func, argc) VALUE klass; const char *name; VALUE (*func)(); int argc; { ID id = rb_intern(name); int ex = NOEX_PUBLIC; rb_add_method(klass, id, NEW_CFUNC(func, argc), ex); } void rb_define_protected_method(klass, name, func, argc) VALUE klass; const char *name; VALUE (*func)(); int argc; { rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc), NOEX_PROTECTED); } void rb_define_private_method(klass, name, func, argc) VALUE klass; const char *name; VALUE (*func)(); int argc; { rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc), NOEX_PRIVATE); } void rb_undef_method(klass, name) VALUE klass; const char *name; { rb_add_method(klass, rb_intern(name), 0, NOEX_UNDEF); } #define SPECIAL_SINGLETON(x,c) do {\ if (obj == (x)) {\ return c;\ }\ } while (0) VALUE rb_singleton_class(obj) VALUE obj; { VALUE klass; if (FIXNUM_P(obj) || SYMBOL_P(obj)) { rb_raise(rb_eTypeError, "can't define singleton"); } if (rb_special_const_p(obj)) { SPECIAL_SINGLETON(Qnil, rb_cNilClass); SPECIAL_SINGLETON(Qfalse, rb_cFalseClass); SPECIAL_SINGLETON(Qtrue, rb_cTrueClass); rb_bug("unknown immediate %ld", obj); } DEFER_INTS; if (FL_TEST(RBASIC(obj)->klass, FL_SINGLETON) && rb_iv_get(RBASIC(obj)->klass, "__attached__") == obj) { klass = RBASIC(obj)->klass; } else { klass = rb_make_metaclass(obj, RBASIC(obj)->klass); } if (OBJ_TAINTED(obj)) { OBJ_TAINT(klass); } else { FL_UNSET(klass, FL_TAINT); } if (OBJ_FROZEN(obj)) OBJ_FREEZE(klass); ALLOW_INTS; return klass; } void rb_define_singleton_method(obj, name, func, argc) VALUE obj; const char *name; VALUE (*func)(); int argc; { rb_define_method(rb_singleton_class(obj), name, func, argc); } void rb_define_module_function(module, name, func, argc) VALUE module; const char *name; VALUE (*func)(); int argc; { rb_define_private_method(module, name, func, argc); rb_define_singleton_method(module, name, func, argc); } void rb_define_global_function(name, func, argc) const char *name; VALUE (*func)(); int argc; { rb_define_module_function(rb_mKernel, name, func, argc); } void rb_define_alias(klass, name1, name2) VALUE klass; const char *name1, *name2; { rb_alias(klass, rb_intern(name1), rb_intern(name2)); } void rb_define_attr(klass, name, read, write) VALUE klass; const char *name; int read, write; { rb_attr(klass, rb_intern(name), read, write, Qfalse); } #ifdef HAVE_STDARG_PROTOTYPES #include #define va_init_list(a,b) va_start(a,b) #else #include #define va_init_list(a,b) va_start(a) #endif int #ifdef HAVE_STDARG_PROTOTYPES rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...) #else rb_scan_args(argc, argv, fmt, va_alist) int argc; const VALUE *argv; const char *fmt; va_dcl #endif { int n, i = 0; const char *p = fmt; VALUE *var; va_list vargs; va_init_list(vargs, fmt); if (*p == '*') goto rest_arg; if (ISDIGIT(*p)) { n = *p - '0'; if (n > argc) rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, n); for (i=0; i i) { if (var) *var = argv[i]; } else { if (var) *var = Qnil; } } p++; } if(*p == '*') { rest_arg: var = va_arg(vargs, VALUE*); if (argc > i) { if (var) *var = rb_ary_new4(argc-i, argv+i); i = argc; } else { if (var) *var = rb_ary_new(); } p++; } if (*p == '&') { var = va_arg(vargs, VALUE*); if (rb_block_given_p()) { *var = rb_block_proc(); } else { *var = Qnil; } p++; } va_end(vargs); if (*p != '\0') { goto error; } if (argc > i) { rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, i); } return argc; error: rb_fatal("bad scan arg format: %s", fmt); return 0; } ================================================ FILE: common.mk ================================================ bin: $(PROGRAM) $(WPROGRAM) lib: $(LIBRUBY) dll: $(LIBRUBY_SO) RUBYLIB = - RUBYOPT = - SPEC_GIT_BASE = git://github.com/rubyspec MSPEC_GIT_URL = $(SPEC_GIT_BASE)/mspec.git RUBYSPEC_GIT_URL = $(SPEC_GIT_BASE)/rubyspec.git STATIC_RUBY = static-ruby EXTCONF = extconf.rb RBCONFIG = ./.rbconfig.time LIBRUBY_EXTS = ./.libruby-with-ext.time RDOCOUT = $(EXTOUT)/rdoc DMYEXT = dmyext.$(OBJEXT) MAINOBJ = main.$(OBJEXT) EXTOBJS = DLDOBJS = $(DMYEXT) OBJS = array.$(OBJEXT) \ bignum.$(OBJEXT) \ class.$(OBJEXT) \ compar.$(OBJEXT) \ dir.$(OBJEXT) \ dln.$(OBJEXT) \ enum.$(OBJEXT) \ enumerator.$(OBJEXT) \ error.$(OBJEXT) \ eval.$(OBJEXT) \ file.$(OBJEXT) \ gc.$(OBJEXT) \ hash.$(OBJEXT) \ inits.$(OBJEXT) \ io.$(OBJEXT) \ marshal.$(OBJEXT) \ math.$(OBJEXT) \ numeric.$(OBJEXT) \ object.$(OBJEXT) \ pack.$(OBJEXT) \ parse.$(OBJEXT) \ pointerset.$(OBJEXT) \ process.$(OBJEXT) \ prec.$(OBJEXT) \ random.$(OBJEXT) \ range.$(OBJEXT) \ re.$(OBJEXT) \ regex.$(OBJEXT) \ ruby.$(OBJEXT) \ signal.$(OBJEXT) \ sprintf.$(OBJEXT) \ st.$(OBJEXT) \ string.$(OBJEXT) \ struct.$(OBJEXT) \ time.$(OBJEXT) \ util.$(OBJEXT) \ variable.$(OBJEXT) \ version.$(OBJEXT) \ $(MISSING) SCRIPT_ARGS = --dest-dir="$(DESTDIR)" \ --extout="$(EXTOUT)" \ --mflags="$(MFLAGS)" \ --make-flags="$(MAKEFLAGS)" EXTMK_ARGS = $(SCRIPT_ARGS) --extension $(EXTS) --extstatic $(EXTSTATIC) \ --make-flags="MINIRUBY='$(MINIRUBY)'" -- INSTRUBY_ARGS = $(SCRIPT_ARGS) \ --data-mode=$(INSTALL_DATA_MODE) \ --prog-mode=$(INSTALL_PROG_MODE) \ --installed-list $(INSTALLED_LIST) INSTALL_PROG_MODE = 0755 INSTALL_DATA_MODE = 0644 PRE_LIBRUBY_UPDATE = $(MINIRUBY) -e 'ARGV[1] or File.unlink(ARGV[0]) rescue nil' -- \ $(LIBRUBY_EXTS) $(LIBRUBY_SO_UPDATE) TESTSDIR = $(srcdir)/test TESTWORKDIR = testwork all: $(MKFILES) $(PREP) $(RBCONFIG) $(LIBRUBY) @$(MINIRUBY) $(srcdir)/ext/extmk.rb --make="$(MAKE)" $(EXTMK_ARGS) prog: $(PROGRAM) $(WPROGRAM) miniruby$(EXEEXT): config.status $(LIBRUBY_A) $(MAINOBJ) $(MINIOBJS) $(OBJS) $(DMYEXT) $(PROGRAM): $(LIBRUBY) $(MAINOBJ) $(OBJS) $(EXTOBJS) $(SETUP) $(PREP) $(LIBRUBY_A): $(OBJS) $(DMYEXT) $(ARCHFILE) $(LIBRUBY_SO): $(OBJS) $(DLDOBJS) $(LIBRUBY_A) $(PREP) $(LIBRUBY_SO_UPDATE) $(LIBRUBY_EXTS): @exit > $@ $(STATIC_RUBY)$(EXEEXT): $(MAINOBJ) $(DLDOBJS) $(EXTOBJS) $(LIBRUBY_A) @$(RM) $@ $(PURIFY) $(CC) $(MAINOBJ) $(DLDOBJS) $(EXTOBJS) $(LIBRUBY_A) $(MAINLIBS) $(EXTLIBS) $(LIBS) $(OUTFLAG)$@ $(LDFLAGS) $(XLDFLAGS) ruby.imp: $(OBJS) @$(NM) -Pgp $(OBJS) | awk 'BEGIN{print "#!"}; $$2~/^[BD]$$/{print $$1}' | sort -u -o $@ install: install-nodoc $(RDOCTARGET) install-all: install-nodoc install-doc install-nodoc: pre-install-nodoc do-install-nodoc post-install-nodoc pre-install-nodoc:: pre-install-local pre-install-ext do-install-nodoc: $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --mantype="$(MANTYPE)" post-install-nodoc:: post-install-local post-install-ext install-local: pre-install-local do-install-local post-install-local pre-install-local:: pre-install-bin pre-install-lib pre-install-man do-install-local: $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=local --mantype="$(MANTYPE)" loadpath: $(PREP) $(MINIRUBY) -e 'p $$:' post-install-local:: post-install-bin post-install-lib post-install-man install-ext: pre-install-ext do-install-ext post-install-ext pre-install-ext:: pre-install-ext-arch pre-install-ext-comm do-install-ext: $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=ext post-install-ext:: post-install-ext-arch post-install-ext-comm install-arch: pre-install-arch do-install-arch post-install-arch pre-install-arch:: pre-install-bin pre-install-ext-arch do-install-arch: $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=bin --install=ext-arch post-install-arch:: post-install-bin post-install-ext-arch install-comm: pre-install-comm do-install-comm post-install-comm pre-install-comm:: pre-install-lib pre-install-ext-comm pre-install-man do-install-comm: $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=lib --install=ext-comm --install=man post-install-comm:: post-install-lib post-install-ext-comm post-install-man install-bin: pre-install-bin do-install-bin post-install-bin pre-install-bin:: install-prereq do-install-bin: $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=bin post-install-bin:: @$(NULLCMD) install-lib: pre-install-lib do-install-lib post-install-lib pre-install-lib:: install-prereq do-install-lib: $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=lib post-install-lib:: @$(NULLCMD) install-ext-comm: pre-install-ext-comm do-install-ext-comm post-install-ext-comm pre-install-ext-comm:: install-prereq do-install-ext-comm: $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=ext-comm post-install-ext-comm:: @$(NULLCMD) install-ext-arch: pre-install-ext-arch do-install-ext-arch post-install-ext-arch pre-install-ext-arch:: install-prereq do-install-ext-arch: $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=ext-arch post-install-ext-arch:: @$(NULLCMD) install-man: pre-install-man do-install-man post-install-man pre-install-man:: install-prereq do-install-man: $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=man --mantype="$(MANTYPE)" post-install-man:: @$(NULLCMD) what-where: no-install no-install: no-install-nodoc no-install-doc what-where-all: no-install-all no-install-all: no-install-nodoc what-where-nodoc: no-install-nodoc no-install-nodoc: pre-no-install-nodoc dont-install-nodoc post-no-install-nodoc pre-no-install-nodoc:: pre-no-install-local pre-no-install-ext dont-install-nodoc: $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --mantype="$(MANTYPE)" post-no-install-nodoc:: post-no-install-local post-no-install-ext what-where-local: no-install-local no-install-local: pre-no-install-local dont-install-local post-no-install-local pre-no-install-local:: pre-no-install-bin pre-no-install-lib pre-no-install-man dont-install-local: $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=local --mantype="$(MANTYPE)" post-no-install-local:: post-no-install-bin post-no-install-lib post-no-install-man what-where-ext: no-install-ext no-install-ext: pre-no-install-ext dont-install-ext post-no-install-ext pre-no-install-ext:: pre-no-install-ext-arch pre-no-install-ext-comm dont-install-ext: $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=ext post-no-install-ext:: post-no-install-ext-arch post-no-install-ext-comm what-where-arch: no-install-arch no-install-arch: pre-no-install-arch dont-install-arch post-no-install-arch pre-no-install-arch:: pre-no-install-bin pre-no-install-ext-arch dont-install-arch: $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=bin --install=ext-arch post-no-install-arch:: post-no-install-lib post-no-install-man post-no-install-ext-arch what-where-comm: no-install-comm no-install-comm: pre-no-install-comm dont-install-comm post-no-install-comm pre-no-install-comm:: pre-no-install-lib pre-no-install-ext-comm pre-no-install-man dont-install-comm: $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=lib --install=ext-comm --install=man post-no-install-comm:: post-no-install-lib post-no-install-ext-comm post-no-install-man what-where-bin: no-install-bin no-install-bin: pre-no-install-bin dont-install-bin post-no-install-bin pre-no-install-bin:: install-prereq dont-install-bin: $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=bin post-no-install-bin:: @$(NULLCMD) what-where-lib: no-install-lib no-install-lib: pre-no-install-lib dont-install-lib post-no-install-lib pre-no-install-lib:: install-prereq dont-install-lib: $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=lib post-no-install-lib:: @$(NULLCMD) what-where-ext-comm: no-install-ext-comm no-install-ext-comm: pre-no-install-ext-comm dont-install-ext-comm post-no-install-ext-comm pre-no-install-ext-comm:: install-prereq dont-install-ext-comm: $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=ext-comm post-no-install-ext-comm:: @$(NULLCMD) what-where-ext-arch: no-install-ext-arch no-install-ext-arch: pre-no-install-ext-arch dont-install-ext-arch post-no-install-ext-arch pre-no-install-ext-arch:: install-prereq dont-install-ext-arch: $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=ext-arch post-no-install-ext-arch:: @$(NULLCMD) what-where-man: no-install-man no-install-man: pre-no-install-man dont-install-man post-no-install-man pre-no-install-man:: install-prereq dont-install-man: $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=man --mantype="$(MANTYPE)" post-no-install-man:: @$(NULLCMD) install-doc: rdoc pre-install-doc do-install-doc post-install-doc pre-install-doc:: install-prereq do-install-doc: $(PROGRAM) $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=rdoc --rdoc-output="$(RDOCOUT)" post-install-doc:: @$(NULLCMD) rdoc: $(PROGRAM) PHONY @echo Generating RDoc documentation $(RUNRUBY) "$(srcdir)/bin/rdoc" --all --ri --op "$(RDOCOUT)" "$(srcdir)" what-where-doc: no-install-doc no-install-doc: pre-no-install-doc dont-install-doc post-no-install-doc pre-no-install-doc:: install-prereq dont-install-doc:: $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=rdoc --rdoc-output="$(RDOCOUT)" post-no-install-doc:: @$(NULLCMD) CLEAR_INSTALLED_LIST = clear-installed-list install-prereq: $(CLEAR_INSTALLED_LIST) clear-installed-list: @exit > $(INSTALLED_LIST) clean: clean-ext clean-local clean-local:: @$(RM) $(OBJS) $(MINIOBJS) $(MAINOBJ) $(LIBRUBY_A) $(LIBRUBY_SO) $(LIBRUBY) $(LIBRUBY_ALIASES) @$(RM) $(PROGRAM) $(WPROGRAM) miniruby$(EXEEXT) dmyext.$(OBJEXT) $(ARCHFILE) .*.time @$(RM) y.tab.c y.output clean-ext: @-$(MINIRUBY) $(srcdir)/ext/extmk.rb --make="$(MAKE)" $(EXTMK_ARGS) clean distclean: distclean-ext distclean-local distclean-local:: clean-local @$(RM) $(MKFILES) config.h rbconfig.rb @$(RM) config.cache config.log config.status @$(RM) *~ *.bak *.stackdump core *.core gmon.out $(PREP) distclean-ext: @-$(MINIRUBY) $(srcdir)/ext/extmk.rb --make="$(MAKE)" $(EXTMK_ARGS) distclean realclean:: realclean-ext realclean-local realclean-local:: distclean-local @$(RM) parse.c lex.c realclean-ext:: @-$(MINIRUBY) $(srcdir)/ext/extmk.rb --make="$(MAKE)" $(EXTMK_ARGS) realclean check: test test-all test: miniruby$(EXEEXT) $(RBCONFIG) $(PROGRAM) PHONY @$(MINIRUBY) $(srcdir)/rubytest.rb test-all: $(RUNRUBY) "$(srcdir)/test/runner.rb" --basedir="$(TESTSDIR)" --runner=$(TESTUI) $(TESTS) extconf: $(MINIRUBY) -run -e mkdir -- -p "$(EXTCONFDIR)" $(RUNRUBY) -C "$(EXTCONFDIR)" $(EXTCONF) $(EXTCONFARGS) $(RBCONFIG): $(srcdir)/mkconfig.rb config.status $(PREP) @$(MINIRUBY) $(srcdir)/mkconfig.rb -timestamp=$@ \ -install_name=$(RUBY_INSTALL_NAME) \ -so_name=$(RUBY_SO_NAME) rbconfig.rb .PRECIOUS: $(MKFILES) .PHONY: test install install-nodoc install-doc dist PHONY: {$(VPATH)}parse.c: parse.y acosh.$(OBJEXT): {$(VPATH)}acosh.c alloca.$(OBJEXT): {$(VPATH)}alloca.c crypt.$(OBJEXT): {$(VPATH)}crypt.c dup2.$(OBJEXT): {$(VPATH)}dup2.c erf.$(OBJEXT): {$(VPATH)}erf.c finite.$(OBJEXT): {$(VPATH)}finite.c flock.$(OBJEXT): {$(VPATH)}flock.c memcmp.$(OBJEXT): {$(VPATH)}memcmp.c memmove.$(OBJEXT): {$(VPATH)}memmove.c mkdir.$(OBJEXT): {$(VPATH)}mkdir.c vsnprintf.$(OBJEXT): {$(VPATH)}vsnprintf.c strcasecmp.$(OBJEXT): {$(VPATH)}strcasecmp.c strncasecmp.$(OBJEXT): {$(VPATH)}strncasecmp.c strchr.$(OBJEXT): {$(VPATH)}strchr.c strdup.$(OBJEXT): {$(VPATH)}strdup.c strerror.$(OBJEXT): {$(VPATH)}strerror.c strftime.$(OBJEXT): {$(VPATH)}strftime.c strstr.$(OBJEXT): {$(VPATH)}strstr.c strtod.$(OBJEXT): {$(VPATH)}strtod.c strtol.$(OBJEXT): {$(VPATH)}strtol.c strtoul.$(OBJEXT): {$(VPATH)}strtoul.c nt.$(OBJEXT): {$(VPATH)}nt.c x68.$(OBJEXT): {$(VPATH)}x68.c os2.$(OBJEXT): {$(VPATH)}os2.c dl_os2.$(OBJEXT): {$(VPATH)}dl_os2.c ia64.$(OBJEXT): {$(VPATH)}ia64.s $(CC) $(CFLAGS) -c $< # when I use -I., there is confliction at "OpenFile" # so, set . into environment varible "include" win32.$(OBJEXT): {$(VPATH)}win32.c ### array.$(OBJEXT): {$(VPATH)}array.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}util.h {$(VPATH)}st.h bignum.$(OBJEXT): {$(VPATH)}bignum.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}rubysig.h class.$(OBJEXT): {$(VPATH)}class.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}rubysig.h {$(VPATH)}node.h {$(VPATH)}st.h compar.$(OBJEXT): {$(VPATH)}compar.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h dir.$(OBJEXT): {$(VPATH)}dir.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}util.h dln.$(OBJEXT): {$(VPATH)}dln.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}dln.h dmydln.$(OBJEXT): {$(VPATH)}dmydln.c dln.$(OBJEXT) dmyext.$(OBJEXT): {$(VPATH)}dmyext.c enum.$(OBJEXT): {$(VPATH)}enum.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}node.h {$(VPATH)}util.h enumerator.$(OBJEXT): {$(VPATH)}enumerator.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h error.$(OBJEXT): {$(VPATH)}error.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}env.h {$(VPATH)}st.h eval.$(OBJEXT): {$(VPATH)}eval.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}node.h {$(VPATH)}env.h {$(VPATH)}util.h \ {$(VPATH)}rubysig.h {$(VPATH)}st.h {$(VPATH)}dln.h file.$(OBJEXT): {$(VPATH)}file.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}rubyio.h {$(VPATH)}rubysig.h {$(VPATH)}util.h \ {$(VPATH)}dln.h gc.$(OBJEXT): {$(VPATH)}gc.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}rubysig.h {$(VPATH)}st.h {$(VPATH)}node.h \ {$(VPATH)}env.h {$(VPATH)}re.h {$(VPATH)}regex.h \ {$(VPATH)}pointerset.h {$(VPATH)}marktable.h \ {$(VPATH)}marktable.c hash.$(OBJEXT): {$(VPATH)}hash.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}st.h {$(VPATH)}util.h {$(VPATH)}rubysig.h inits.$(OBJEXT): {$(VPATH)}inits.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h io.$(OBJEXT): {$(VPATH)}io.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}rubyio.h {$(VPATH)}rubysig.h {$(VPATH)}util.h \ {$(VPATH)}env.h main.$(OBJEXT): {$(VPATH)}main.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h marshal.$(OBJEXT): {$(VPATH)}marshal.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}rubyio.h {$(VPATH)}st.h {$(VPATH)}util.h math.$(OBJEXT): {$(VPATH)}math.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h numeric.$(OBJEXT): {$(VPATH)}numeric.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}env.h {$(VPATH)}defines.h {$(VPATH)}intern.h \ {$(VPATH)}missing.h object.$(OBJEXT): {$(VPATH)}object.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}st.h {$(VPATH)}util.h pack.$(OBJEXT): {$(VPATH)}pack.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h parse.$(OBJEXT): {$(VPATH)}parse.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}env.h {$(VPATH)}node.h {$(VPATH)}st.h \ {$(VPATH)}regex.h {$(VPATH)}util.h {$(VPATH)}lex.c pointerset.$(OBJEXT): {$(VPATH)}pointerset.c {$(VPATH)}pointerset.h prec.$(OBJEXT): {$(VPATH)}prec.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h process.$(OBJEXT): {$(VPATH)}process.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}rubysig.h {$(VPATH)}st.h random.$(OBJEXT): {$(VPATH)}random.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h range.$(OBJEXT): {$(VPATH)}range.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h re.$(OBJEXT): {$(VPATH)}re.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}re.h {$(VPATH)}regex.h regex.$(OBJEXT): {$(VPATH)}regex.c config.h {$(VPATH)}regex.h ruby.$(OBJEXT): {$(VPATH)}ruby.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}dln.h {$(VPATH)}node.h {$(VPATH)}util.h signal.$(OBJEXT): {$(VPATH)}signal.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}rubysig.h sprintf.$(OBJEXT): {$(VPATH)}sprintf.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h st.$(OBJEXT): {$(VPATH)}st.c config.h {$(VPATH)}st.h string.$(OBJEXT): {$(VPATH)}string.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}re.h {$(VPATH)}regex.h struct.$(OBJEXT): {$(VPATH)}struct.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h time.$(OBJEXT): {$(VPATH)}time.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h util.$(OBJEXT): {$(VPATH)}util.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}util.h variable.$(OBJEXT): {$(VPATH)}variable.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}env.h {$(VPATH)}node.h {$(VPATH)}st.h {$(VPATH)}util.h version.$(OBJEXT): {$(VPATH)}version.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}version.h dist: $(PROGRAM) $(RUNRUBY) $(srcdir)/distruby.rb ================================================ FILE: compar.c ================================================ /********************************************************************** compar.c - $Author$ $Date$ created at: Thu Aug 26 14:39:48 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #include "ruby.h" VALUE rb_mComparable; static ID cmp; int rb_cmpint(val, a, b) VALUE val, a, b; { if (NIL_P(val)) { rb_cmperr(a, b); } if (FIXNUM_P(val)) return FIX2INT(val); if (TYPE(val) == T_BIGNUM) { if (RBIGNUM(val)->sign) return 1; return -1; } if (RTEST(rb_funcall(val, '>', 1, INT2FIX(0)))) return 1; if (RTEST(rb_funcall(val, '<', 1, INT2FIX(0)))) return -1; return 0; } void rb_cmperr(x, y) VALUE x, y; { const char *classname; if (SPECIAL_CONST_P(y)) { y = rb_inspect(y); classname = StringValuePtr(y); } else { classname = rb_obj_classname(y); } rb_raise(rb_eArgError, "comparison of %s with %s failed", rb_obj_classname(x), classname); } #define cmperr() (rb_cmperr(x, y), Qnil) static VALUE cmp_eq(a) VALUE *a; { VALUE c = rb_funcall(a[0], cmp, 1, a[1]); if (NIL_P(c)) return Qnil; if (rb_cmpint(c, a[0], a[1]) == 0) return Qtrue; return Qfalse; } static VALUE cmp_failed() { return Qnil; } /* * call-seq: * obj == other => true or false * * Compares two objects based on the receiver's <=> * method, returning true if it returns 0. Also returns true if * _obj_ and _other_ are the same object. */ static VALUE cmp_equal(x, y) VALUE x, y; { VALUE a[2]; if (x == y) return Qtrue; a[0] = x; a[1] = y; return rb_rescue(cmp_eq, (VALUE)a, cmp_failed, 0); } /* * call-seq: * obj > other => true or false * * Compares two objects based on the receiver's <=> * method, returning true if it returns 1. */ static VALUE cmp_gt(x, y) VALUE x, y; { VALUE c = rb_funcall(x, cmp, 1, y); if (NIL_P(c)) return cmperr(); if (rb_cmpint(c, x, y) > 0) return Qtrue; return Qfalse; } /* * call-seq: * obj >= other => true or false * * Compares two objects based on the receiver's <=> * method, returning true if it returns 0 or 1. */ static VALUE cmp_ge(x, y) VALUE x, y; { VALUE c = rb_funcall(x, cmp, 1, y); if (NIL_P(c)) return cmperr(); if (rb_cmpint(c, x, y) >= 0) return Qtrue; return Qfalse; } /* * call-seq: * obj < other => true or false * * Compares two objects based on the receiver's <=> * method, returning true if it returns -1. */ static VALUE cmp_lt(x, y) VALUE x, y; { VALUE c = rb_funcall(x, cmp, 1, y); if (NIL_P(c)) return cmperr(); if (rb_cmpint(c, x, y) < 0) return Qtrue; return Qfalse; } /* * call-seq: * obj <= other => true or false * * Compares two objects based on the receiver's <=> * method, returning true if it returns -1 or 0. */ static VALUE cmp_le(x, y) VALUE x, y; { VALUE c = rb_funcall(x, cmp, 1, y); if (NIL_P(c)) return cmperr(); if (rb_cmpint(c, x, y) <= 0) return Qtrue; return Qfalse; } /* * call-seq: * obj.between?(min, max) => true or false * * Returns false if obj <=> * min is less than zero or if anObject <=> * max is greater than zero, true otherwise. * * 3.between?(1, 5) #=> true * 6.between?(1, 5) #=> false * 'cat'.between?('ant', 'dog') #=> true * 'gnu'.between?('ant', 'dog') #=> false * */ static VALUE cmp_between(x, min, max) VALUE x, min, max; { if (RTEST(cmp_lt(x, min))) return Qfalse; if (RTEST(cmp_gt(x, max))) return Qfalse; return Qtrue; } /* * The Comparable mixin is used by classes whose objects * may be ordered. The class must define the <=> operator, * which compares the receiver against another object, returning -1, 0, * or +1 depending on whether the receiver is less than, equal to, or * greater than the other object. Comparable uses * <=> to implement the conventional comparison operators * (<, <=, ==, >=, * and >) and the method between?. * * class SizeMatters * include Comparable * attr :str * def <=>(anOther) * str.size <=> anOther.str.size * end * def initialize(str) * @str = str * end * def inspect * @str * end * end * * s1 = SizeMatters.new("Z") * s2 = SizeMatters.new("YY") * s3 = SizeMatters.new("XXX") * s4 = SizeMatters.new("WWWW") * s5 = SizeMatters.new("VVVVV") * * s1 < s2 #=> true * s4.between?(s1, s3) #=> false * s4.between?(s3, s5) #=> true * [ s3, s2, s5, s4, s1 ].sort #=> [Z, YY, XXX, WWWW, VVVVV] * */ void Init_Comparable() { rb_mComparable = rb_define_module("Comparable"); rb_define_method(rb_mComparable, "==", cmp_equal, 1); rb_define_method(rb_mComparable, ">", cmp_gt, 1); rb_define_method(rb_mComparable, ">=", cmp_ge, 1); rb_define_method(rb_mComparable, "<", cmp_lt, 1); rb_define_method(rb_mComparable, "<=", cmp_le, 1); rb_define_method(rb_mComparable, "between?", cmp_between, 2); cmp = rb_intern("<=>"); } ================================================ FILE: config.guess ================================================ #! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003 Free Software Foundation, Inc. timestamp='2004-06-11' # This file 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 2 of the License, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit 0 ;; amd64:OpenBSD:*:*) echo x86_64-unknown-openbsd${UNAME_RELEASE} exit 0 ;; amiga:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; arc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; cats:OpenBSD:*:*) echo arm-unknown-openbsd${UNAME_RELEASE} exit 0 ;; hp300:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; luna88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mac68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; macppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvmeppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; pmax:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sgi:OpenBSD:*:*) echo mipseb-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sun3:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; wgrisc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:OpenBSD:*:*) echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit 0 ;; macppc:MirBSD:*:*) echo powerppc-unknown-mirbsd${UNAME_RELEASE} exit 0 ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit 0 ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit 0 ;; Alpha*:OpenVMS:*:*) echo alpha-hp-vms exit 0 ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit 0 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit 0 ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit 0;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit 0 ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit 0 ;; *:OS/390:*:*) echo i370-ibm-openedition exit 0 ;; *:OS400:*:*) echo powerpc-ibm-os400 exit 0 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit 0;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit 0;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit 0 ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit 0 ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit 0 ;; DRS?6000:UNIX_SV:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7 && exit 0 ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit 0 ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit 0 ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit 0 ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit 0 ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit 0 ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit 0 ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit 0 ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit 0 ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit 0 ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit 0 ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit 0 ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit 0 ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit 0 ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c \ && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ && exit 0 echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit 0 ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit 0 ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit 0 ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit 0 ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit 0 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit 0 ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit 0 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit 0 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit 0 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit 0 ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit 0 ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit 0 ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo rs6000-ibm-aix3.2.5 elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit 0 ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:*:*) echo rs6000-ibm-aix exit 0 ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit 0 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit 0 ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit 0 ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit 0 ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit 0 ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit 0 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then # avoid double evaluation of $set_cc_for_build test -n "$CC_FOR_BUILD" || eval $set_cc_for_build if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit 0 ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit 0 ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo unknown-hitachi-hiuxwe2 exit 0 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit 0 ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit 0 ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit 0 ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit 0 ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit 0 ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit 0 ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit 0 ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit 0 ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit 0 ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit 0 ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit 0 ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; *:UNICOS/mp:*:*) echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit 0 ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:FreeBSD:*:*) # Determine whether the default compiler uses glibc. eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #if __GLIBC__ >= 2 LIBC=gnu #else LIBC= #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` # GNU/KFreeBSD systems have a "k" prefix to indicate we are using # FreeBSD's kernel, but not the complete OS. case ${LIBC} in gnu) kernel_only='k' ;; esac echo ${UNAME_MACHINE}-unknown-${kernel_only}freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} exit 0 ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit 0 ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit 0 ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit 0 ;; x86:Interix*:[34]*) echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' exit 0 ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit 0 ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit 0 ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit 0 ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit 0 ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit 0 ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit 0 ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit 0 ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit 0 ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit 0 ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit 0 ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit 0 ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit 0 ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit 0 ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit 0 ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit 0 ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit 0 ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit 0 ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #ifdef __INTEL_COMPILER LIBC=gnu #else LIBC=gnuaout #endif #endif #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit 0 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit 0 ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit 0 ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit 0 ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit 0 ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit 0 ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit 0 ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit 0 ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit 0 ;; i*86:*:5:[78]*) case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit 0 ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit 0 ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit 0 ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit 0 ;; paragon:*:*:*) echo i860-intel-osf1 exit 0 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit 0 ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit 0 ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit 0 ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit 0 ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4.3${OS_REL} && exit 0 /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4 && exit 0 ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit 0 ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit 0 ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit 0 ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit 0 ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit 0 ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit 0 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit 0 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit 0 ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit 0 ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit 0 ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit 0 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit 0 ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit 0 ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit 0 ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit 0 ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit 0 ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit 0 ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit 0 ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Darwin:*:*) case `uname -p` in *86) UNAME_PROCESSOR=i686 ;; powerpc) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit 0 ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit 0 ;; *:QNX:*:4*) echo i386-pc-qnx exit 0 ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit 0 ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit 0 ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit 0 ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit 0 ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit 0 ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit 0 ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit 0 ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit 0 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit 0 ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit 0 ;; *:ITS:*:*) echo pdp10-unknown-its exit 0 ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit 0 ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit 0 ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0 # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit 0 ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; c34*) echo c34-convex-bsd exit 0 ;; c38*) echo c38-convex-bsd exit 0 ;; c4*) echo c4-convex-bsd exit 0 ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: ================================================ FILE: config.sub ================================================ #! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003 Free Software Foundation, Inc. timestamp='2004-06-11' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file 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 2 of the License, 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., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit 0;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | m32r | m68000 | m68k | m88k | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | msp430 \ | ns16k | ns32k \ | openrisc | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xscale | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* \ | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | m32r-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | msp430-* \ | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ | xtensa-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; crds | unos) basic_machine=m68k-crds ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; mmix*) basic_machine=mmix-knuth os=-mmixware ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nv1) basic_machine=nv1-cray os=-unicosmp ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; or32 | or32-*) basic_machine=or32-unknown os=-coff ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sh64) basic_machine=sh64-unknown ;; sparc | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -netbsd* | -openbsd* | -kfreebsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=-linux ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: ================================================ FILE: configure.in ================================================ dnl Process this file with autoconf to produce a configure script. AC_INIT() AC_PREREQ(2.58) AC_DEFUN([RUBY_MINGW32], [case "$host_os" in cygwin*) AC_CACHE_CHECK(for mingw32 environment, rb_cv_mingw32, [AC_TRY_CPP([ #ifndef __MINGW32__ # error #endif ], rb_cv_mingw32=yes,rb_cv_mingw32=no) rm -f conftest*]) test "$rb_cv_mingw32" = yes && target_os="mingw32" ;; esac]) AC_DEFUN([RUBY_CPPOUTFILE], [AC_CACHE_CHECK(whether ${CPP} accepts -o, rb_cv_cppoutfile, [cppflags=$CPPFLAGS CPPFLAGS='-o conftest.i' AC_TRY_CPP([], rb_cv_cppoutfile=yes, rb_cv_cppoutfile=no) CPPFLAGS=$cppflags rm -f conftest*]) if test "$rb_cv_cppoutfile" = yes; then CPPOUTFILE='-o conftest.i' elif test "$rb_cv_cppoutfile" = no; then CPPOUTFILE='> conftest.i' elif test -n "$rb_cv_cppoutfile"; then CPPOUTFILE="$rb_cv_cppoutfile" fi AC_SUBST(CPPOUTFILE)]) AC_DEFUN([RUBY_PROG_GNU_LD], [AC_CACHE_CHECK(whether the linker is GNU ld, rb_cv_prog_gnu_ld, [if `$CC $CFLAGS $CPPFLAGS $LDFLAGS --print-prog-name=ld 2>&1` -v 2>&1 | grep "GNU ld" > /dev/null; then rb_cv_prog_gnu_ld=yes else rb_cv_prog_gnu_ld=no fi ]) GNU_LD=$rb_cv_prog_gnu_ld AC_SUBST(GNU_LD)]) unset GREP_OPTIONS rb_version=`grep RUBY_VERSION $srcdir/version.h` MAJOR=`expr "$rb_version" : '#define RUBY_VERSION "\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*"'` MINOR=`expr "$rb_version" : '#define RUBY_VERSION "[0-9][0-9]*\.\([0-9][0-9]*\)\.[0-9][0-9]*"'` TEENY=`expr "$rb_version" : '#define RUBY_VERSION "[0-9][0-9]*\.[0-9][0-9]*\.\([0-9][0-9]*\)"'` if test "$MAJOR" = ""; then AC_MSG_ERROR(could not determine MAJOR number from version.h) fi if test "$MINOR" = ""; then AC_MSG_ERROR(could not determine MINOR number from version.h) fi if test "$TEENY" = ""; then AC_MSG_ERROR(could not determine TEENY number from version.h) fi AC_SUBST(MAJOR) AC_SUBST(MINOR) AC_SUBST(TEENY) dnl checks for alternative programs AC_ARG_WITH(gcc, [ --without-gcc never use gcc], [ case $withval in no) : ${CC=cc} ;; yes) : ${CC=gcc} ;; *) CC=$withval ;; esac]) dnl If the user switches compilers, we can't believe the cache if test ! -z "$ac_cv_prog_CC" -a ! -z "$CC" -a "$CC" != "$ac_cv_prog_CC" then AC_MSG_ERROR(cached CC is different -- throw away $cache_file (it is also a good idea to do 'make clean' before compiling)) fi test -z "$CC" || ac_cv_prog_CC="$CC" if test "$program_prefix" = NONE; then program_prefix= fi AC_CANONICAL_TARGET target_os=`echo $target_os | sed 's/linux-gnu$/linux/;s/linux-gnu/linux-/'` ac_install_sh='' # unusable for extension libraries. ifelse(currently,disabled, [ dnl checks for fat-binary AC_ARG_ENABLE(fat-binary, [ --enable-fat-binary=ARCHS build an Apple/NeXT Multi Architecture Binary (MAB); ARCHS is a comma-delimited list of architectures for which to build; if ARCHS is omitted, then the package will be built for all architectures supported by the platform ("ppc" for MacOS/X and Darwin; "ppc,i386" for Rhapsody; "m68k,i386,sparc" for OpenStep; "m68k,i386,sparc,hppa" for NextStep); if this option is disabled or omitted entirely, then the package will be built only for the target platform], [fat_binary=$enableval], [fat_binary=no]) if test "$fat_binary" != no; then AC_MSG_CHECKING([target architectures]) # Respect TARGET_ARCHS setting from environment if available. if test -z "$TARGET_ARCHS"; then # Respect ARCH given to --enable-fat-binary if present. if test "$fat_binary" != yes; then TARGET_ARCHS=`echo "$fat_binary" | tr ',' ' '` else # Choose a default set of architectures based upon platform. case "$target_os" in darwin*) TARGET_ARCHS="ppc" ;; rhapsody*) TARGET_ARCHS="ppc i386" ;; openstep*) TARGET_ARCHS="m68k i386 sparc" ;; nextstep*) TARGET_ARCHS="m68k i386 sparc hppa" ;; *) TARGET_ARCHS=`arch` esac fi fi AC_MSG_RESULT([$TARGET_ARCHS]) # /usr/lib/arch_tool -archify_list $TARGET_ARCHS ARCH_FLAG= for archs in $TARGET_ARCHS do ARCH_FLAG="$ARCH_FLAG -arch $archs" done AC_DEFINE(NEXT_FAT_BINARY) fi ], [fat_binary=no]) case $target_cpu in i?86) frame_address=yes;; *) frame_address=no;; esac AC_ARG_ENABLE(frame-address, [ --enable-frame-address use GCC __builtin_frame_address(). ], [frame_address=$enableval]) if test $frame_address = yes; then AC_DEFINE(USE_BUILTIN_FRAME_ADDRESS) fi AC_ARG_ENABLE(gc-debug, [ --enable-gc-debug enable additional GC API methods, debugging, and statistics. ], [gc_debug=$enableval]) if test "$gc_debug" = yes; then AC_DEFINE(GC_DEBUG) fi AC_ARG_WITH(wipe-sites, [ --with-wipe-sites=MASK override default STACK_WIPES_SITES mask in rubysig.h], [wipe_sites=$withval]) if test "$wipe_sites" != ""; then case $wipe_sites in none|no) wipe_sites=0x0;; yes) wipe_sites=;; esac if test -n "$wipe_sites"; then AC_DEFINE_UNQUOTED(STACK_WIPE_SITES,$wipe_sites) fi fi AC_ARG_PROGRAM dnl Checks for programs. if test x"${build}" != x"${host}"; then AC_CHECK_TOOL(CC, gcc) fi AC_PROG_CC AC_PROG_GCC_TRADITIONAL if test "$GCC" = yes; then linker_flag=-Wl, else linker_flag= fi RUBY_PROG_GNU_LD RUBY_CPPOUTFILE : ${OUTFLAG='-o '} AC_SUBST(OUTFLAG) RUBY_MINGW32 AC_PROG_YACC if test "$YACC" = "yacc"; then AC_DEFINE([OLD_YACC]) fi AC_CHECK_TOOL(RANLIB, ranlib, :) AC_CHECK_TOOL(AR, ar) if test -z "$AR"; then AC_CHECK_PROGS(AR, aal, ar) fi AC_CHECK_TOOL(AS, as) ASFLAGS=$ASFLAGS AC_SUBST(ASFLAGS) case "$target_os" in cygwin*|mingw*) AC_CHECK_TOOL(NM, nm) AC_CHECK_TOOL(WINDRES, windres) AC_CHECK_TOOL(DLLWRAP, dllwrap) target_cpu=`echo $target_cpu | sed s/i.86/i386/` case "$target_os" in mingw*) test "$rb_cv_msvcrt" = "" && unset rb_cv_msvcrt AC_CHECK_TOOL(OBJDUMP, objdump) AC_CACHE_CHECK(for mingw32 runtime DLL, rb_cv_msvcrt, [ AC_TRY_LINK([#include ], [FILE* volatile f = stdin; return 0;], [rb_cv_msvcrt=`$OBJDUMP -p conftest$ac_exeext | tr A-Z a-z | sed -n '/^[[ ]]*dll name: \(msvc.*\)\.dll$/{s//\1/p;q;}'`], [rb_cv_msvcrt=msvcrt]) test "$rb_cv_msvcrt" = "" && rb_cv_msvcrt=msvcrt]) AC_ARG_WITH(winsock2, [ --with-winsock2 link winsock2 (MinGW only)], [ case $withval in yes) with_winsock2=yes;; *) with_winsock2=no;; esac], [with_winsock2=no]) if test "$with_winsock2" = yes; then AC_DEFINE(USE_WINSOCK2) fi esac : ${enable_shared=yes} ;; aix*) AC_CHECK_TOOL(NM, nm, /usr/ccs/bin/nm, /usr/ccs/bin:$PATH) ;; hiuxmpp*) # by TOYODA Eizi AC_DEFINE(__HIUX_MPP__) ;; esac AC_PROG_LN_S AC_PROG_MAKE_SET AC_PROG_INSTALL # checks for UNIX variants that set C preprocessor variables AC_AIX AC_MINIX AC_SUBST(RM, ['rm -f']) AC_SUBST(CP, ['cp']) if $as_mkdir_p; then AC_SUBST(MAKEDIRS, ['mkdir -p']) else AC_SUBST(MAKEDIRS, ['install -d']) fi dnl check for large file stuff mv confdefs.h confdefs1.h : > confdefs.h AC_SYS_LARGEFILE mv confdefs.h largefile.h mv confdefs1.h confdefs.h cat largefile.h >> confdefs.h AC_CHECK_TYPES([long long, off_t]) AC_CHECK_SIZEOF(int, 4) AC_CHECK_SIZEOF(short, 2) AC_CHECK_SIZEOF(long, 4) AC_CHECK_SIZEOF(long long, 0) AC_CHECK_SIZEOF(__int64, 0) AC_CHECK_SIZEOF(off_t, 0) AC_CHECK_SIZEOF(void*, 4) AC_CHECK_SIZEOF(float, 4) AC_CHECK_SIZEOF(double, 8) AC_CHECK_SIZEOF(time_t, 0) for id in pid_t gid_t uid_t; do AC_CHECK_TYPE($id, [typ=$id], [typ=int]) AC_DEFINE_UNQUOTED(rb_$id, $typ) done AC_CACHE_CHECK(for prototypes, rb_cv_have_prototypes, [AC_TRY_COMPILE([int foo(int x) { return 0; }], [return foo(10);], rb_cv_have_prototypes=yes, rb_cv_have_prototypes=no)]) if test "$rb_cv_have_prototypes" = yes; then AC_DEFINE(HAVE_PROTOTYPES) fi AC_CACHE_CHECK(token paste string, rb_cv_tokenpaste, [AC_TRY_COMPILE([#define paste(a,b) a##b], [int xy = 1; return paste(x,y);], rb_cv_tokenpaste=ansi, rb_cv_tokenpaste=knr)]) if test "$rb_cv_tokenpaste" = ansi; then AC_DEFINE(TOKEN_PASTE(x,y),[x##y]) else AC_DEFINE(TOKEN_PASTE(x,y),[x/**/y]) fi AC_CACHE_CHECK(for variable length prototypes and stdarg.h, rb_cv_stdarg, [AC_TRY_COMPILE([ #include int foo(int x, ...) { va_list va; va_start(va, x); va_arg(va, int); va_arg(va, char *); va_arg(va, double); return 0; } ], [return foo(10, "", 3.14);], rb_cv_stdarg=yes, rb_cv_stdarg=no)]) if test "$rb_cv_stdarg" = yes; then AC_DEFINE(HAVE_STDARG_PROTOTYPES) fi AC_DEFUN([RUBY_FUNC_ATTRIBUTE], [dnl m4_ifval([$2], dnl [AS_VAR_PUSHDEF([attrib],[$2])], dnl [AS_VAR_PUSHDEF([attrib],[FUNC_]AS_TR_CPP($1))] dnl )dnl m4_ifval([$3], dnl [AS_VAR_PUSHDEF([rbcv],[$3])], dnl [AS_VAR_PUSHDEF([rbcv],[rb_cv_func_][$1])]dnl )dnl AC_CACHE_CHECK(for [$1] function attribute, rbcv, [rbcv=x if test "${ac_c_werror_flag+set}"; then rb_c_werror_flag="$ac_c_werror_flag" else unset rb_c_werror_flag fi ac_c_werror_flag=yes for mac in "__attribute__ (($1)) x" "x __attribute__ (($1))" "__declspec($1) x" x; do AC_TRY_COMPILE( [#define ]attrib[(x) $mac ]attrib[(void conftest_attribute_check(void));], [], [rbcv="$mac"; break]) done if test "${rb_c_werror_flag+set}"; then ac_c_werror_flag="$rb_c_werror_flag" else unset ac_c_werror_flag fi ]) AC_DEFINE_UNQUOTED(attrib[(x)], $rbcv) AS_VAR_POPDEF([attrib]) AS_VAR_POPDEF([rbcv]) ]) RUBY_FUNC_ATTRIBUTE(noreturn, NORETURN) RUBY_FUNC_ATTRIBUTE(noinline, NOINLINE) AC_CACHE_CHECK([for RUBY_EXTERN], rb_cv_ruby_extern, [rb_cv_ruby_extern=no for mac in "__attribute__((dllimport))" "__declspec(dllimport)"; do AC_TRY_COMPILE( [extern $mac void conftest(void);], [rb_cv_ruby_extern="extern $mac"; break]) done]) test "x$rb_cv_ruby_extern" = xno || AC_DEFINE_UNQUOTED(RUBY_EXTERN, $rb_cv_ruby_extern) XCFLAGS="$XCFLAGS -DRUBY_EXPORT" dnl Check whether we need to define sys_nerr locally AC_CHECK_DECLS([sys_nerr], [], [], [$ac_includes_default #include ]) dnl whether link libc_r or not AC_ARG_WITH(libc_r, [ --with-libc_r link libc_r if possible (FreeBSD only)], [ case $withval in yes) with_libc_r=yes;; *) with_libc_r=no;; esac], [with_libc_r=no]) AC_ARG_ENABLE(ucontext, [ --disable-ucontext do not use getcontext()/setcontext().], [disable_ucontext=yes], [disable_ucontext=no]) AC_ARG_ENABLE(pthread, [ --enable-pthread use pthread library.], [enable_pthread=$enableval], [enable_pthread=no]) AC_ARG_ENABLE(fastthread, [ --disable-fastthread do not use the fastthread mutex], [ : handled by ext/thread/extconf.rb ]) dnl Checks for libraries. case "$target_os" in nextstep*) ;; openstep*) ;; rhapsody*) ;; darwin*) LIBS="-lobjc $LIBS" CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE" AC_TRY_CPP([#include #if MAC_OS_X_VERSION_MAX_ALLOWED <= 1040 #error pre OS X 10.4 [!<===== pre OS X 10.4 =====>] #endif ], [ test "x$target_cpu" = xpowerpc && ac_cv_header_ucontext_h=no ], [ AC_DEFINE(BROKEN_SETREUID, 1) AC_DEFINE(BROKEN_SETREGID, 1) ]) ;; hpux*) LIBS="-lm $LIBS" ac_cv_c_inline=no;; human*) ac_cv_func_getpgrp_void=yes ac_cv_func_setitimer=no ;; beos*) ac_cv_func_link=no;; cygwin*) ;; mingw*) if test "$with_winsock2" = yes; then LIBS="-lws2_32 $LIBS" else LIBS="-lwsock32 $LIBS" fi LIBS="-lshell32 $LIBS" ac_cv_header_a_out_h=no ac_cv_header_pwd_h=no ac_cv_header_utime_h=no ac_cv_header_sys_ioctl_h=no ac_cv_header_sys_param_h=no ac_cv_header_sys_resource_h=no ac_cv_header_sys_select_h=no ac_cv_header_sys_time_h=no ac_cv_header_sys_times_h=no ac_cv_func_times=yes ac_cv_func_waitpid=yes ac_cv_func_fsync=yes ac_cv_func_vsnprintf=yes ac_cv_func_seekdir=yes ac_cv_func_telldir=yes ac_cv_func_isinf=yes ac_cv_func_isnan=yes ac_cv_func_finite=yes ac_cv_func_link=yes ac_cv_lib_crypt_crypt=no ac_cv_func_getpgrp_void=no ac_cv_func_setpgrp_void=yes ac_cv_func_memcmp_working=yes ac_cv_lib_dl_dlopen=no rb_cv_binary_elf=no rb_cv_negative_time_t=no enable_pthread=no ac_cv_func_fcntl=yes ;; os2-emx*) LIBS="-lm $LIBS" ac_cv_lib_dir_opendir=no;; msdosdjgpp*) LIBS="-lm $LIBS" ac_cv_func_getpgrp_void=yes ac_cv_func_setitimer=no ac_cv_sizeof_rlim_t=4 ac_cv_func_setrlimit=no ;; bsdi*) LIBS="-lm $LIBS" AC_DEFINE(BROKEN_SETREUID, 1) AC_DEFINE(BROKEN_SETREGID, 1) ac_cv_sizeof_rlim_t=8;; freebsd*) LIBS="-lm $LIBS" AC_CACHE_CHECK([whether -lxpg4 has to be linked], rb_cv_lib_xpg4_needed, [AC_TRY_CPP([ #include #if __FreeBSD_version < 400020 || \ (__FreeBSD_version >= 500000 && __FreeBSD_version < 500005) #error needs libxpg4 #endif ], rb_cv_lib_xpg4_needed=no, rb_cv_lib_xpg4_needed=yes, rb_cv_lib_xpg4_needed=yes)]) if test "$rb_cv_lib_xpg4_needed" = yes; then AC_CHECK_LIB(xpg4, setlocale) fi if test "$with_libc_r" = yes; then AC_CACHE_CHECK([whether libc_r is supplementary to libc], rb_cv_supplementary_lib_c_r, [AC_TRY_CPP([ #include #if 500016 <= __FreeBSD_version #error libc_r is supplementary to libc #endif ], rb_cv_supplementary_lib_c_r=no, rb_cv_supplementary_lib_c_r=yes, rb_cv_supplementary_lib_c_r=yes)]) if test "$rb_cv_supplementary_lib_c_r" = yes; then MAINLIBS="-lc_r $MAINLIBS" fi fi ;; dragonfly*) LIBS="-lm $LIBS" ;; bow) ac_cv_func_setitimer=no ;; superux*) ac_cv_func_setitimer=no ;; solaris*2.1*) if test -z "$GCC"; then ac_cv_func_isinf=yes fi LIBS="-lm $LIBS" ;; *) LIBS="-lm $LIBS";; esac AC_CHECK_LIB(crypt, crypt) AC_CHECK_LIB(dl, dlopen) # Dynamic linking for SunOS/Solaris and SYSV AC_CHECK_LIB(dld, shl_load) # Dynamic linking for HP-UX AC_CHECK_LIB(rt, clock_gettime) # GNU/Linux case "$target_cpu" in alpha*) case "$target_os"::"$GCC" in *::yes) CFLAGS="-mieee $CFLAGS" ;; # gcc osf*) CFLAGS="-ieee $CFLAGS" ;; # ccc esac ;; esac dnl Checks for header files. AC_HEADER_DIRENT AC_HEADER_STDC AC_HEADER_SYS_WAIT AC_CHECK_HEADERS(stdlib.h string.h unistd.h limits.h sys/file.h sys/ioctl.h sys/syscall.h\ fcntl.h sys/fcntl.h sys/select.h sys/time.h sys/times.h sys/param.h\ syscall.h pwd.h grp.h a.out.h utime.h memory.h direct.h sys/resource.h \ sys/mkdev.h sys/utime.h netinet/in_systm.h float.h ieeefp.h pthread.h \ ucontext.h intrinsics.h) dnl Check additional types. AC_CHECK_SIZEOF(rlim_t, 0, [ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_TIME_H # include #endif #ifdef HAVE_SYS_RESOURCE_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #include ]) dnl Checks for typedefs, structures, and compiler characteristics. AC_TYPE_SIZE_T AC_STRUCT_ST_BLKSIZE AC_STRUCT_ST_BLOCKS AC_STRUCT_ST_RDEV dnl Checks for library functions. AC_TYPE_GETGROUPS AC_TYPE_SIGNAL case "${target_cpu}-${target_os}" in powerpc-darwin*) AC_LIBSOURCES(alloca.c) AC_SUBST([ALLOCA], [\${LIBOBJDIR}alloca.${ac_objext}]) AC_DEFINE(C_ALLOCA) AC_DEFINE_UNQUOTED(alloca, alloca) ;; *) AC_FUNC_ALLOCA ;; esac AC_FUNC_MEMCMP AC_FUNC_FSEEKO AC_CHECK_FUNCS(ftello) # http://sources.redhat.com/ml/libc-hacker/2005-08/msg00008.html # Debian GNU/Linux Etch's libc6.1 2.3.6.ds1-13etch5 has this problem. # Debian GNU/Linux Lenny's libc6.1 2.7-10 has no problem. AC_CACHE_CHECK(for broken erfc of glibc-2.3.6 on IA64, rb_cv_broken_glibc_ia64_erfc, [AC_TRY_RUN([ #include int main() { erfc(10000.0); return 0; } ], rb_cv_broken_glibc_ia64_erfc=no, rb_cv_broken_glibc_ia64_erfc=yes, rb_cv_broken_glibc_ia64_erfc=no)]) case $rb_cv_broken_glibc_ia64_erfc in yes) ac_cv_func_erf=no;; esac AC_REPLACE_FUNCS(dup2 memmove strcasecmp strncasecmp strerror strftime\ strchr strstr strtoul crypt flock vsnprintf\ isnan finite isinf hypot acosh erf) AC_CHECK_FUNCS(fmod killpg wait4 waitpid syscall chroot fsync getcwd eaccess\ truncate ftruncate chsize times utimes fcntl lockf lstat symlink link\ readlink setitimer setruid seteuid setreuid setresuid\ setproctitle setrgid setegid setregid setresgid issetugid pause\ lchown lchmod getpgrp setpgrp getpgid setpgid initgroups\ getgroups setgroups getpriority getrlimit setrlimit sysconf\ group_member dlopen sigprocmask\ sigaction sigsetjmp _setjmp _longjmp setsid telldir seekdir fchmod\ mktime timegm gettimeofday\ cosh sinh tanh round setuid setgid setenv unsetenv) AC_CACHE_CHECK(for __builtin_setjmp, ac_cv_func___builtin_setjmp, [AC_TRY_LINK([@%:@include jmp_buf jb; void t(v) int v; {__builtin_longjmp(jb, v);}], [__builtin_setjmp(jb);], [ac_cv_func___builtin_setjmp=yes], [ac_cv_func___builtin_setjmp=no]) ]) test x$ac_cv_func__longjmp = xno && ac_cv_func__setjmp=no AC_MSG_CHECKING(for setjmp type) AC_ARG_WITH(setjmp-type, [ --with-setjmp-type select setjmp type], [ case $withval in __builtin_setjmp) setjmp_prefix=__builtin_;; _setjmp) setjmp_prefix=_;; sigsetjmp) setjmp_prefix=sig;; setjmp) setjmp_prefix=;; '') unset setjmp_prefix;; *) AC_MSG_ERROR(invalid setjmp type: $withval);; esac], [unset setjmp_prefix]) if test ${setjmp_prefix+set}; then if test "${setjmp_prefix}" && eval test '$ac_cv_func_'${setjmp_prefix}setjmp = no; then AC_MSG_ERROR(${setjmp_prefix}setjmp is not available) fi elif test "$ac_cv_func___builtin_setjmp" = yes; then setjmp_prefix=__builtin_ elif test "$ac_cv_func__setjmp" = yes; then setjmp_prefix=_ elif test "$ac_cv_func_sigsetjmp" = yes; then case $target_os in solaris*|cygwin*) setjmp_prefix=;; *) setjmp_prefix=sig;; esac else setjmp_prefix= fi if test x$setjmp_prefix = xsig; then setjmp_sigmask=yes else unset setjmp_sigmask fi AC_MSG_RESULT(${setjmp_prefix}setjmp) AC_DEFINE_UNQUOTED([RUBY_SETJMP(env)], [${setjmp_prefix}setjmp(env${setjmp_sigmask+,0})]) AC_DEFINE_UNQUOTED([RUBY_LONGJMP(env,val)], [${setjmp_prefix}longjmp(env,val)]) AC_DEFINE_UNQUOTED(RUBY_JMP_BUF, ${setjmp_sigmask+${setjmp_prefix}}jmp_buf) AC_ARG_ENABLE(setreuid, [ --enable-setreuid use setreuid()/setregid() according to need even if obsolete.], [use_setreuid=$enableval]) if test "$use_setreuid" = yes; then AC_DEFINE(USE_SETREUID) AC_DEFINE(USE_SETREGID) fi AC_STRUCT_TIMEZONE AC_CACHE_CHECK(for struct tm.tm_gmtoff, rb_cv_member_struct_tm_tm_gmtoff, [AC_TRY_COMPILE([#include ], [struct tm t; t.tm_gmtoff = 3600;], [rb_cv_member_struct_tm_tm_gmtoff=yes], [rb_cv_member_struct_tm_tm_gmtoff=no])]) if test "$rb_cv_member_struct_tm_tm_gmtoff" = yes; then AC_DEFINE(HAVE_STRUCT_TM_TM_GMTOFF) fi AC_CACHE_CHECK(for external int daylight, rb_cv_have_daylight, [AC_TRY_LINK([#include int i;], [i = daylight;], rb_cv_have_daylight=yes, rb_cv_have_daylight=no)]) if test "$rb_cv_have_daylight" = yes; then AC_DEFINE(HAVE_DAYLIGHT) fi AC_DEFUN([RUBY_CHECK_VARTYPE], [dnl AC_CACHE_CHECK([for external $1], rb_cv_var_$1, [rb_cv_var_$1=no AC_TRY_COMPILE([ #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 1 #endif $2 ; const volatile void *volatile t;], [t = &(&$1)[0];], [for t in $3; do AC_TRY_COMPILE([ #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 1 #endif $2 ; extern $t $1; const volatile void *volatile t;], [t = &(&$1)[0];], [rb_cv_var_$1=$t; break]) done])]) if test "[$rb_cv_var_]$1" != no; then AC_DEFINE([HAVE_VAR_]m4_toupper($1)) AC_DEFINE_UNQUOTED([TYPEOF_VAR_]m4_toupper($1), $rb_cv_var_$1) fi]) RUBY_CHECK_VARTYPE(timezone, [@%:@include ], [long int]) RUBY_CHECK_VARTYPE(altzone, [@%:@include ], [long int]) if test "$rb_cv_var_timezone" = no; then AC_CHECK_FUNCS(timezone) if test "$ac_cv_func_timezone" = yes; then AC_CACHE_CHECK([whether timezone requires zero arguments], rb_cv_func_timezone_void, [AC_TRY_COMPILE([@%:@include ], [(void)timezone(0, 0);], [rb_cv_func_timezone_void=no], [rb_cv_func_timezone_void=yes])] ) if test $rb_cv_func_timezone_void = yes; then AC_DEFINE(TIMEZONE_VOID) fi fi fi AC_CACHE_CHECK(for negative time_t for gmtime(3), rb_cv_negative_time_t, [AC_TRY_RUN([ #include void check(tm, y, m, d, h, s) struct tm *tm; int y, m, d, h, s; { if (!tm || tm->tm_year != y || tm->tm_mon != m-1 || tm->tm_mday != d || tm->tm_hour != h || tm->tm_sec != s) { exit(1); } } int main() { time_t t = -1; struct tm *tm; check(gmtime(&t), 69, 12, 31, 23, 59); t = ~(time_t)0 << 31; check(gmtime(&t), 1, 12, 13, 20, 52); return 0; } ], rb_cv_negative_time_t=yes, rb_cv_negative_time_t=no, rb_cv_negative_time_t=yes)]) if test "$rb_cv_negative_time_t" = yes; then AC_DEFINE(NEGATIVE_TIME_T) fi if test "$ac_cv_func_sigprocmask" = yes && test "$ac_cv_func_sigaction" = yes; then AC_DEFINE(POSIX_SIGNAL) else AC_CHECK_FUNCS(sigsetmask) AC_CACHE_CHECK(for BSD signal semantics, rb_cv_bsd_signal, [AC_TRY_RUN([ #include #include void sig_handler(dummy) int dummy; { } int main() { signal(SIGINT, sig_handler); kill(getpid(), SIGINT); kill(getpid(), SIGINT); return 0; } ], rb_cv_bsd_signal=yes, rb_cv_bsd_signal=no, rb_cv_bsd_signal=$ac_cv_func_sigsetmask)]) if test "$rb_cv_bsd_signal" = yes; then AC_DEFINE(BSD_SIGNAL) fi fi AC_FUNC_GETPGRP AC_FUNC_SETPGRP AC_C_BIGENDIAN AC_C_CONST AC_C_CHAR_UNSIGNED AC_C_INLINE AC_C_VOLATILE if test x"$target_cpu" = xia64; then AC_LIBOBJ([ia64]) AC_CACHE_CHECK(for __libc_ia64_register_backing_store_base, rb_cv___libc_ia64_register_backing_store_base, [rb_cv___libc_ia64_register_backing_store_base=no AC_TRY_LINK( [extern unsigned long __libc_ia64_register_backing_store_base;], [unsigned long p = __libc_ia64_register_backing_store_base; printf("%ld\n", p);], [rb_cv___libc_ia64_register_backing_store_base=yes])]) if test $rb_cv___libc_ia64_register_backing_store_base = yes; then AC_DEFINE(HAVE___LIBC_IA64_REGISTER_BACKING_STORE_BASE) fi fi AC_CACHE_CHECK(whether right shift preserve sign bit, rb_cv_rshift_sign, [AC_TRY_RUN([ int main() { if (-1==(-1>>1)) return 0; return 1; } ], rb_cv_rshift_sign=yes, rb_cv_rshift_sign=no, rb_cv_rshift_sign=yes)]) if test "$rb_cv_rshift_sign" = yes; then AC_DEFINE(RSHIFT(x,y), ((x)>>(int)y)) else AC_DEFINE(RSHIFT(x,y), (((x)<0) ? ~((~(x))>>y) : (x)>>y)) fi AC_MSG_CHECKING(read count field in FILE structures) AC_CACHE_VAL(rb_cv_fcnt, [for fcnt in dnl _cnt dnl __cnt dnl _r dnl readCount dnl _rcount dnl for emx0.9c ; do AC_TRY_COMPILE([#include ], [FILE *f = stdin; f->$fcnt = 0;], rb_cv_fcnt="$fcnt"; break, rb_cv_fcnt="not found") done]) if test "$rb_cv_fcnt" = "not found"; then AC_MSG_RESULT([not found(OK if using GNU libc)]) else AC_MSG_RESULT($rb_cv_fcnt) AC_DEFINE_UNQUOTED(FILE_COUNT, $rb_cv_fcnt) fi AC_MSG_CHECKING(read buffer ptr field in FILE structures) AC_CACHE_VAL(rb_cv_frptr, [for frptr in dnl _IO_read_ptr dnl _ptr dnl __ptr dnl bufpos dnl _p dnl ; do AC_TRY_COMPILE([#include ], [FILE *f = stdin; char buf[256]; f->$frptr = buf;], rb_cv_frptr="$frptr"; break, rb_cv_frptr="not found") done]) if test "$rb_cv_frptr" = "not found"; then AC_MSG_RESULT([not found]) else AC_MSG_RESULT($rb_cv_frptr) AC_DEFINE_UNQUOTED(FILE_READPTR, $rb_cv_frptr) if test "$rb_cv_fcnt" = "not found"; then AC_MSG_CHECKING(read buffer end field in FILE structures) AC_CACHE_VAL(rb_cv_frend, [for frend in dnl _IO_read_end dnl bufread dnl ; do AC_TRY_COMPILE([#include ], [FILE *f = stdin; char buf[256]; f->$frend = buf;], rb_cv_frend="$frend"; break, rb_cv_frend="not found") done]) if test "$rb_cv_frend" = "not found"; then AC_MSG_RESULT([not found]) else AC_MSG_RESULT($rb_cv_frend) AC_DEFINE_UNQUOTED(FILE_READEND, $rb_cv_frend) fi fi fi AC_DEFUN([RUBY_CHECK_IO_NEED], [AC_CACHE_CHECK(whether need to [$1], [$2], [AC_TRY_RUN([ #include #ifndef SEEK_SET #define SEEK_SET 0 #endif #ifndef SEEK_CUR #define SEEK_CUR 1 #endif #define before_seek(f) ]ifelse(index($2,flush_before_seek),-1,[fflush(f)],[(f,0)])[ #define reset_rw(f) ]ifelse(index($2,seek_between_rw),-1,[do_seek(f,SEEK_CUR)],[(f,0)])[ #define do_seek(f, w) (before_seek(f), fseek(f,0,w)) char *fn = "conftest.dat"; char *wombat = "wombat\n"; char *koara = "koara\n"; char *kangaroo = "kangaroo\n"; int main() { char buf[BUFSIZ]; FILE *f; int r = 1; if (!(f = fopen(fn, "w+"))) return 1; fputs(wombat, f); do_seek(f, SEEK_SET); if (!fgets(buf, BUFSIZ, f) || strcmp(buf, wombat)) goto fail; reset_rw(f); fputs(koara, f); fputs(kangaroo, f); do_seek(f, SEEK_SET); if (!fgets(buf, BUFSIZ, f) || strcmp(buf, wombat)) goto fail; if (!fgets(buf, BUFSIZ, f) || strcmp(buf, koara)) goto fail; if (!fgets(buf, BUFSIZ, f) || strcmp(buf, kangaroo)) goto fail; do_seek(f, SEEK_SET); if (!fgets(buf, BUFSIZ, f) || strcmp(buf, wombat)) goto fail; reset_rw(f); fputc('X', f); reset_rw(f); if (!fgets(buf, BUFSIZ, f) || strcmp(buf, koara+1)) goto fail; if (!fgets(buf, BUFSIZ, f) || strcmp(buf, kangaroo)) goto fail; do_seek(f, SEEK_SET); if (!fgets(buf, BUFSIZ, f) || strcmp(buf, wombat)) goto fail; if (!fgets(buf, BUFSIZ, f) || buf[0] != 'X' || strcmp(buf+1, koara+1)) goto fail; if (!fgets(buf, BUFSIZ, f) || strcmp(buf, kangaroo)) goto fail; r = 0; fail: fclose(f); unlink(fn); return r; } ], [$2]=no, [$2]=yes, [$2]=[$3])])]) RUBY_CHECK_IO_NEED(seek between R/W, rb_cv_need_io_seek_between_rw, yes) if test "$rb_cv_need_io_seek_between_rw" = yes; then AC_DEFINE(NEED_IO_SEEK_BETWEEN_RW, 1) fi dnl RUBY_CHECK_IO_NEED(flush before seek, rb_cv_need_io_flush_before_seek, no) dnl if test "$rb_cv_need_io_flush_before_seek" = yes; then dnl AC_DEFINE(NEED_IO_FLUSH_BEFORE_SEEK, 1) dnl fi AC_CACHE_CHECK([whether st_ino is huge], rb_cv_huge_st_ino, [AC_COMPILE_IFELSE([AC_LANG_BOOL_COMPILE_TRY([ #include struct stat test_stat; ], [sizeof(test_stat.st_ino)>sizeof(long)])], rb_cv_huge_st_ino=yes, rb_cv_huge_st_ino=no) ]) if test $rb_cv_huge_st_ino = yes; then AC_DEFINE(HUGE_ST_INO) fi if test "$ac_cv_func_sysconf" = yes; then AC_DEFUN([RUBY_CHECK_SYSCONF], [dnl AC_CACHE_CHECK([whether _SC_$1 is supported], rb_cv_have_sc_[]m4_tolower($1), [AC_TRY_COMPILE([#include ], [_SC_$1 >= 0], rb_cv_have_sc_[]m4_tolower($1)=yes, rb_cv_have_sc_[]m4_tolower($1)=no) ]) if test "$rb_cv_have_sc_[]m4_tolower($1)" = yes; then AC_DEFINE(HAVE__SC_$1) fi ]) RUBY_CHECK_SYSCONF(CLK_TCK) fi case "$target_cpu" in m68*|i?86|ia64|sparc*|alpha*) rb_cv_stack_grow_dir=-1;; hppa*) rb_cv_stack_grow_dir=+1;; esac AC_CACHE_CHECK(stack growing direction, rb_cv_stack_grow_dir, [AC_TRY_RUN([ /* recurse to get rid of inlining */ static int stack_growup_p(addr, n) volatile int *addr, n; { volatile int end; if (n > 0) return *addr = stack_growup_p(addr, n - 1); else return (&end > addr); } int main() { int x; return stack_growup_p(&x, 10); } ], rb_cv_stack_grow_dir=-1, rb_cv_stack_grow_dir=+1, rb_cv_stack_grow_dir=0)]) AC_DEFINE_UNQUOTED(STACK_GROW_DIRECTION, $rb_cv_stack_grow_dir) if test x"$enable_pthread" = xyes; then for pthread_lib in pthread pthreads c c_r; do AC_CHECK_LIB($pthread_lib, pthread_kill, rb_with_pthread=yes, rb_with_pthread=no) if test "$rb_with_pthread" = "yes"; then break; fi done if test x"$rb_with_pthread" = xyes; then AC_DEFINE(_REENTRANT) AC_DEFINE(_THREAD_SAFE) AC_DEFINE(HAVE_LIBPTHREAD) case $pthread_lib in c) ;; c_r) MAINLIBS="-pthread $MAINLIBS" ;; *) LIBS="-l$pthread_lib $LIBS" ;; esac else AC_MSG_WARN("Don't know how to find pthread library on your system -- thread support disabled") fi AC_CHECK_FUNCS(nanosleep) if test x"$ac_cv_func_nanosleep" = xno; then AC_CHECK_LIB(rt, nanosleep) if test x"$ac_cv_lib_rt_nanosleep" = xyes; then AC_DEFINE(HAVE_NANOSLEEP) fi fi fi if test x"$ac_cv_header_ucontext_h" = xyes && test x"$disable_ucontext" = xno; then if test x"$rb_with_pthread" = xyes; then AC_CHECK_FUNCS(getcontext setcontext) fi fi dnl default value for $KANJI DEFAULT_KCODE="KCODE_NONE" AC_ARG_WITH(default-kcode, [ --with-default-kcode=CODE specify default value for \$KCODE (utf8|euc|sjis|none)], [case $withval in utf8) DEFAULT_KCODE="KCODE_UTF8";; euc) DEFAULT_KCODE="KCODE_EUC";; sjis) DEFAULT_KCODE="KCODE_SJIS";; none) DEFAULT_KCODE="KCODE_NONE";; *) AC_MSG_WARN($withval is not valid kcode; ignored);; esac]) AC_DEFINE_UNQUOTED(DEFAULT_KCODE, $DEFAULT_KCODE) dnl wheather use dln_a_out or not AC_ARG_WITH(dln-a-out, [ --with-dln-a-out use dln_a_out if possible], [ case $withval in yes) with_dln_a_out=yes;; *) with_dln_a_out=no;; esac], [with_dln_a_out=no]) AC_CACHE_CHECK(whether ELF binaries are produced, rb_cv_binary_elf, [AC_TRY_RUN([ /* Test for whether ELF binaries are produced */ #include #include main() { char buffer[4]; int i=open("conftest",O_RDONLY); if(i==-1) exit(1); /* fail */ if(read(i,&buffer[0],4)<4) exit(1); /* fail */ if(buffer[0] != 127 || buffer[1] != 'E' || buffer[2] != 'L' || buffer[3] != 'F') exit(1); /* fail */ exit(0); /* succeed (yes, it's ELF) */ } ], rb_cv_binary_elf=yes, rb_cv_binary_elf=no, rb_cv_binary_elf=yes)]) if test "$rb_cv_binary_elf" = yes; then AC_DEFINE(USE_ELF) fi case "$target_os" in linux* | gnu* | k*bsd*-gnu | bsdi*) if test "$rb_cv_binary_elf" = no; then with_dln_a_out=yes else LDFLAGS="$LDFLAGS -rdynamic" fi;; esac LIBEXT=a AC_SUBST(DLDFLAGS)dnl AC_SUBST(ARCH_FLAG)dnl AC_SUBST(STATIC)dnl AC_SUBST(CCDLFLAGS)dnl AC_SUBST(LDSHARED)dnl AC_SUBST(DLEXT)dnl AC_SUBST(DLEXT2)dnl AC_SUBST(LIBEXT)dnl STATIC= : ${PATHFLAG=''} if test "$with_dln_a_out" != yes; then rb_cv_dlopen=unknown AC_MSG_CHECKING(whether OS depend dynamic link works) if test "$GCC" = yes; then case "$target_os" in nextstep*) CCDLFLAGS="$CCDLFLAGS -fno-common";; openstep*) CCDLFLAGS="$CCDLFLAGS -fno-common";; rhapsody*) CCDLFLAGS="$CCDLFLAGS -fno-common";; darwin*) CCDLFLAGS="$CCDLFLAGS -fno-common";; human*|bsdi*|beos*|cygwin*|mingw*|aix*|interix*) ;; *) CCDLFLAGS="$CCDLFLAGS -fPIC";; esac else case "$target_os" in hpux*) CCDLFLAGS="$CCDLFLAGS +Z";; solaris*|irix*) CCDLFLAGS="$CCDLFLAGS -KPIC" ;; sunos*) CCDLFLAGS="$CCDLFLAGS -PIC" ;; esix*|uxpds*) CCDLFLAGS="$CCDLFLAGS -KPIC" ;; *) : ${CCDLFLAGS=""} ;; esac fi AC_ARG_ENABLE(rpath, [ --disable-rpath embed run path into extension libraries.], [enable_rpath=$enableval], [enable_rpath="$rb_cv_binary_elf"]) if test "$enable_rpath" = yes; then RPATHFLAG=" ${linker_flag}-R%1\$-s" fi case "$target_os" in hpux*) DLDFLAGS="$DLDFLAGS -E" : ${LDSHARED='ld -b'} XLDFLAGS="$XLDFLAGS -Wl,-E" : ${LIBPATHENV=SHLIB_PATH} if test "$rb_cv_prog_gnu_ld" = no; then RPATHFLAG=' +b %1$-s' fi rb_cv_dlopen=yes;; solaris*) if test "$GCC" = yes; then : ${LDSHARED='$(CC) -shared'} if test "$rb_cv_prog_gnu_ld" = yes; then LDFLAGS="$LDFLAGS -Wl,-E" fi else : ${LDSHARED='ld -G'} fi rb_cv_dlopen=yes;; sunos*) : ${LDSHARED='ld -assert nodefinitions'} rb_cv_dlopen=yes;; irix*) : ${LDSHARED='ld -shared'} rb_cv_dlopen=yes;; sysv4*) : ${LDSHARED='ld -G'} rb_cv_dlopen=yes;; nto-qnx*) : ${LDSHARED="qcc -shared"} rb_cv_dlopen=yes ;; esix*|uxpds*) : ${LDSHARED="ld -G"} rb_cv_dlopen=yes ;; osf*) : ${LDSHARED="ld -shared -expect_unresolved \"*\""} rb_cv_dlopen=yes ;; bsdi3*) case "$CC" in *shlicc*) : ${LDSHARED="$CC -r"} rb_cv_dlopen=yes ;; esac ;; linux* | gnu* | k*bsd*-gnu | netbsd* | bsdi*) : ${LDSHARED='${CC} -shared'} if test "$rb_cv_binary_elf" = yes; then LDFLAGS="$LDFLAGS -Wl,-export-dynamic" fi rb_cv_dlopen=yes ;; interix*) : ${LDSHARED="$CC -shared"} XLDFLAGS="$XLDFLAGS -Wl,-E" LIBPATHFLAG=" -L%1\$-s" rb_cv_dlopen=yes ;; freebsd*|dragonfly*) : ${LDSHARED="$CC -shared"} if test "$rb_cv_binary_elf" = yes; then LDFLAGS="$LDFLAGS -rdynamic" DLDFLAGS="$DLDFLAGS "'-Wl,-soname,$(.TARGET)' else test "$GCC" = yes && test "$rb_cv_prog_gnu_ld" = yes || LDSHARED="ld -Bshareable" fi rb_cv_dlopen=yes ;; openbsd*) : ${LDSHARED="\$(CC) -shared ${CCDLFLAGS}"} if test "$rb_cv_binary_elf" = yes; then LDFLAGS="$LDFLAGS -Wl,-E" fi rb_cv_dlopen=yes ;; nextstep*) : ${LDSHARED='cc -r -nostdlib'} LDFLAGS="$LDFLAGS -u libsys_s" rb_cv_dlopen=yes ;; openstep*) : ${LDSHARED='cc -dynamic -bundle -undefined suppress'} : ${LDFLAGS=""} rb_cv_dlopen=yes ;; rhapsody*) : ${LDSHARED='cc -dynamic -bundle -undefined suppress'} : ${LDFLAGS=""} rb_cv_dlopen=yes ;; darwin*) : ${LDSHARED='cc -dynamic -bundle -undefined suppress -flat_namespace'} : ${LDFLAGS=""} : ${LIBPATHENV=DYLD_LIBRARY_PATH} rb_cv_dlopen=yes ;; aix*) if test "$GCC" = yes; then : ${LDSHARED='$(CC) -shared'} else : ${LDSHARED='$(CC)'} fi LDSHARED="$LDSHARED ${linker_flag}-G" DLDFLAGS='-eInit_$(TARGET)' XLDFLAGS="${linker_flag}-bE:ruby.imp ${linker_flag}-brtl" : ${ARCHFILE="ruby.imp"} TRY_LINK='$(CC) $(LDFLAGS) -oconftest $(INCFLAGS) -I$(hdrdir) $(CPPFLAGS)' TRY_LINK="$TRY_LINK"' $(CFLAGS) $(src) $(LIBPATH) $(LOCAL_LIBS) $(LIBS)' : ${LIBPATHENV=SHLIB_PATH} rb_cv_dlopen=yes ;; human*) : ${DLDFLAGS=''} : ${LDSHARED=''} : ${LDFLAGS=''} : ${LINK_SO='ar cru $@ $(OBJS)'} rb_cv_dlopen=yes ;; beos*) case "$target_cpu" in powerpc*) : ${LDSHARED="ld -xms"} DLDFLAGS="$DLDFLAGS "'-export Init_$(TARGET) -lbe -lroot glue-noinit.a init_term_dyn.o start_dyn.o' ;; i586*) : ${LDSHARED="ld -shared"} DLDFLAGS="$DLDFLAGS -L/boot/develop/lib/x86 -lbe -lroot" ;; esac : ${LIBPATHENV=LIBRARY_PATH} rb_cv_dlopen=yes ;; nto-qnx*) DLDFLAGS="$DLDFLAGS -L/lib -L/usr/lib -L/usr/local/lib" : ${LDSHARED='ld -Bshareable -x'} LDFLAGS="$LDFLAGS -L/lib -L/usr/lib -L/usr/local/lib" rb_cv_dlopen=yes;; cygwin*|mingw*) : ${LDSHARED="${CC} -shared -s"} XLDFLAGS="$XLDFLAGS -Wl,--stack,0x02000000" DLDFLAGS="${DLDFLAGS} -Wl,--enable-auto-image-base,--enable-auto-import,--export-all" : ${LIBPATHENV=""} rb_cv_dlopen=yes ;; hiuxmpp) : ${LDSHARED='ld -r'} ;; atheos*) : ${LDSHARED="$CC -shared"} rb_cv_dlopen=yes ;; os2-emx*) LDFLAGS="$LDFLAGS -Zbsd-signals" ;; *) : ${LDSHARED='ld'} ;; esac AC_MSG_RESULT($rb_cv_dlopen) fi case ${RPATHFLAG} in *'%1$'*) : ${LIBPATHFLAG=' -L%1$-s'};; *) : ${LIBPATHFLAG=' -L%s'};; esac AC_SUBST(LINK_SO) AC_SUBST(LIBPATHFLAG) AC_SUBST(RPATHFLAG) AC_SUBST(LIBPATHENV, "${LIBPATHENV-LD_LIBRARY_PATH}") AC_SUBST(TRY_LINK) dln_a_out_works=no if test "$ac_cv_header_a_out_h" = yes; then if test "$with_dln_a_out" = yes || test "$rb_cv_dlopen" = unknown; then cat confdefs.h > config.h AC_CACHE_CHECK(whether matz's dln works, rb_cv_dln_a_out, [AC_TRY_COMPILE([ #define USE_DLN_A_OUT #include "dln.c" ], [], rb_cv_dln_a_out=yes, rb_cv_dln_a_out=no)]) if test "$rb_cv_dln_a_out" = yes; then dln_a_out_works=yes AC_DEFINE(USE_DLN_A_OUT) fi fi fi if test "$dln_a_out_works" = yes; then if test "$GCC" = yes; then STATIC=-static else STATIC=-Bstatic fi DLEXT=so CCDLFLAGS= else case "$target_os" in hpux*) DLEXT=sl;; nextstep*|openstep*|rhapsody*|darwin*) DLEXT=bundle;; os2-emx*) DLEXT=dll;; cygwin*|mingw*) DLEXT=so DLEXT2=dll;; *) DLEXT=so;; esac fi len=2 # .rb n=`expr "$DLEXT" : '.*'`; test "$n" -gt "$len" && len=$n n=`expr "$DLEXT2" : '.*'`; test "$n" -gt "$len" && len=$n AC_DEFINE_UNQUOTED(DLEXT_MAXLEN, `expr $len + 1`) test ".$DLEXT" = "." || AC_DEFINE_UNQUOTED(DLEXT, ".$DLEXT") test ".$DLEXT2" = "." || AC_DEFINE_UNQUOTED(DLEXT2, ".$DLEXT2") AC_SUBST(STRIP)dnl if test "$with_dln_a_out" = yes; then STRIP=true else STRIP=strip fi case "$target_os" in linux* | gnu* | k*bsd*-gnu) STRIP='strip -S -x';; nextstep*) STRIP='strip -A -n';; openstep*) STRIP='strip -A -n';; rhapsody*) STRIP='strip -A -n';; darwin*) STRIP='strip -A -n';; esac EXTSTATIC= AC_SUBST(EXTSTATIC)dnl AC_ARG_WITH(static-linked-ext, [ --with-static-linked-ext link external modules statically], [case $withval in yes) STATIC= EXTSTATIC=static;; *) ;; esac]) case "$target_os" in human*) AC_CHECK_LIB(signal, _harderr) AC_CHECK_LIB(hmem, hmemset) AC_CHECK_FUNCS(select) AC_CACHE_CHECK(whether PD libc _dtos18 fail to convert big number, rb_cv_missing__dtos18, [AC_TRY_RUN( changequote(<<, >>)dnl << #include main () { char buf[256]; sprintf (buf, "%g", 1e+300); exit (strcmp (buf, "1e+300") ? 0 : 1); } >>, changequote([, ])dnl rb_cv_missing__dtos18=yes, rb_cv_missing__dtos18=no, rb_cv_missing__dtos18=no)]) if test "$rb_cv_missing__dtos18" = yes; then AC_DEFINE(MISSING__DTOS18) fi AC_CACHE_CHECK(whether PD libc fconvert fail to round, rb_cv_missing_fconvert, [AC_TRY_RUN( changequote(<<, >>)dnl << #include #include main () { char buf[256]; sprintf (buf, "%f", log(exp(1.0))); exit (strcmp (buf, "1.000000") ? 0 : 1); } >>, changequote([, ])dnl rb_cv_missing_fconvert=yes, rb_cv_missing_fconvert=no, rb_cv_missing_fconvert=no)]) if test "$rb_cv_missing_fconvert" = yes; then AC_DEFINE(MISSING_FCONVERT) fi AC_LIBOBJ([x68.o]) CFLAGS="$CFLAGS -fansi-only" XCFLAGS="$XCFLAGS -cc1-stack=262144 -cpp-stack=2694144" EXEEXT=.x OBJEXT=o setup=Setup.x68 ;; dnl OS/2 environment w/ Autoconf 2.1x for EMX os2-emx) AC_LIBOBJ([os2]) setup=Setup.emx ;; *djgpp*) setup=Setup.dj ;; *) setup=Setup ;; esac AC_SUBST(setup) if test "$prefix" = NONE; then prefix=$ac_default_prefix fi #if test "$fat_binary" != no ; then # CFLAGS="$CFLAGS $ARCH_FLAG" #fi if test x"$cross_compiling" = xyes; then test x"$MINIRUBY" = x && MINIRUBY="${RUBY-ruby} -I`pwd` -rfake" PREP=fake.rb RUNRUBY='$(MINIRUBY) -I`cd $(srcdir)/lib; pwd`' else MINIRUBY='./miniruby$(EXEEXT) -I$(srcdir)/lib' MINIRUBY="$MINIRUBY"' -I$(EXTOUT)/common -I./- -r$(srcdir)/ext/purelib.rb' PREP='miniruby$(EXEEXT)' RUNRUBY='$(MINIRUBY) $(srcdir)/runruby.rb --extout=$(EXTOUT)' fi AC_SUBST(MINIRUBY) AC_SUBST(PREP) AC_SUBST(RUNRUBY) AC_SUBST(EXTOUT, [${EXTOUT-.ext}]) FIRSTMAKEFILE="" LIBRUBY_A='lib$(RUBY_SO_NAME)-static.a' LIBRUBY='$(LIBRUBY_A)' LIBRUBYARG_STATIC='-l$(RUBY_SO_NAME)-static' LIBRUBYARG='$(LIBRUBYARG_STATIC)' SOLIBS= case "$target_os" in cygwin*|mingw*|beos*|openstep*|nextstep*|rhapsody*|darwin*|os2-emx*) : ${DLDLIBS=""} ;; *) DLDLIBS="$DLDLIBS -lc" ;; esac RUBY_SO_NAME='$(RUBY_INSTALL_NAME)' LIBRUBY_LDSHARED=$LDSHARED LIBRUBY_DLDFLAGS=$DLDFLAGS LIBRUBY_SO='lib$(RUBY_SO_NAME).so.$(MAJOR).$(MINOR).$(TEENY)' LIBRUBY_ALIASES='lib$(RUBY_SO_NAME).so' ENABLE_SHARED=no AC_ARG_ENABLE(shared, [ --enable-shared build a shared library for Ruby. ], [enable_shared=$enableval]) if test "$enable_shared" = 'yes'; then LIBRUBY='$(LIBRUBY_SO)' LIBRUBYARG_SHARED='-l$(RUBY_SO_NAME)' LIBRUBYARG='$(LIBRUBYARG_SHARED)' CFLAGS="$CFLAGS $CCDLFLAGS" ENABLE_SHARED=yes if test "$rb_cv_binary_elf" = yes; then SOLIBS='$(LIBS)' fi case "$target_os" in sunos4*) LIBRUBY_ALIASES='lib$(RUBY_SO_NAME).so.$(MAJOR).$(MINOR) lib$(RUBY_SO_NAME).so' ;; linux* | gnu* | k*bsd*-gnu | atheos*) LIBRUBY_DLDFLAGS='-Wl,-soname,lib$(RUBY_SO_NAME).so.$(MAJOR).$(MINOR)' LIBRUBY_ALIASES='lib$(RUBY_SO_NAME).so.$(MAJOR).$(MINOR) lib$(RUBY_SO_NAME).so' ;; freebsd*|dragonfly*) SOLIBS='$(LIBS)' LIBRUBY_SO='lib$(RUBY_SO_NAME).so.$(MAJOR)$(MINOR)' if test "$rb_cv_binary_elf" != "yes" ; then LIBRUBY_SO="$LIBRUBY_SO.\$(TEENY)" LIBRUBY_ALIASES='' fi ;; netbsd*) SOLIBS='$(LIBS)' LIBRUBY_SO='lib$(RUBY_SO_NAME).so.$(MAJOR)$(MINOR).$(TEENY)' LIBRUBY_DLDFLAGS='-Wl,-soname,lib$(RUBY_SO_NAME).so.$(MAJOR)$(MINOR)' if test "$rb_cv_binary_elf" = yes; then # ELF platforms LIBRUBY_ALIASES='lib$(RUBY_SO_NAME).so.$(MAJOR)$(MINOR) lib$(RUBY_SO_NAME).so' else # a.out platforms LIBRUBY_ALIASES="" fi ;; openbsd*) SOLIBS='$(LIBS)' LIBRUBY_SO='lib$(RUBY_INSTALL_NAME).so.$(MAJOR).'`expr ${MINOR} \* 10 + ${TEENY}` ;; solaris*) SOLIBS='$(LIBS)' LIBRUBY_SO='lib$(RUBY_SO_NAME).so.$(MAJOR)' LIBRUBY_ALIASES='lib$(RUBY_SO_NAME).so.$(MAJOR).$(MINOR).$(TEENY) lib$(RUBY_SO_NAME).so' if test "$GCC" = yes; then LIBRUBY_DLDFLAGS="$DLDFLAGS "'-Wl,-h,$(@F)' fi XLDFLAGS="$XLDFLAGS "'-R${libdir}' ;; hpux*) XLDFLAGS="$XLDFLAGS "'-Wl,+s,+b,$(libdir)' LIBRUBY_SO='lib$(RUBY_SO_NAME).sl.$(MAJOR).$(MINOR).$(TEENY)' LIBRUBY_ALIASES='lib$(RUBY_SO_NAME).sl.$(MAJOR).$(MINOR) lib$(RUBY_SO_NAME).sl' ;; aix*) LIBRUBY_DLDFLAGS="${linker_flag}-bnoentry $XLDFLAGS" LIBRUBYARG_SHARED='-L${libdir} -l${RUBY_SO_NAME}' SOLIBS='-lm -lc' ;; beos*) case "$target_cpu" in powerpc*) LIBRUBY_DLDFLAGS='-f ruby.exp -lnet -lbe -lroot glue-noinit.a init_term_dyn.o start_dyn.o' ;; esac ;; darwin*) LIBRUBY_SO='lib$(RUBY_SO_NAME).$(MAJOR).$(MINOR).$(TEENY).dylib' LIBRUBY_LDSHARED='cc -dynamiclib -undefined suppress -flat_namespace' LIBRUBY_DLDFLAGS='-install_name $(libdir)/lib$(RUBY_SO_NAME).dylib -current_version $(MAJOR).$(MINOR).$(TEENY) -compatibility_version $(MAJOR).$(MINOR)' LIBRUBY_ALIASES='lib$(RUBY_SO_NAME).$(MAJOR).$(MINOR).dylib lib$(RUBY_SO_NAME).dylib' ;; interix*) LIBRUBYARG_SHARED='-L. -L${libdir} -l$(RUBY_SO_NAME)' ;; *) ;; esac fi if test "$enable_rpath" = yes; then LIBRUBYARG_SHARED="${linker_flag}-R ${linker_flag}\$(libdir) -L\$(libdir) $LIBRUBYARG_SHARED" fi LDFLAGS="-L. $LDFLAGS" AC_SUBST(ARCHFILE) dnl build rdoc index if requested RDOCTARGET="" AC_ARG_ENABLE(install-doc, [ --enable-install-doc build and install rdoc indexes during install ], [install_doc=$enableval], [install_doc=no]) if test "$install_doc" != no; then RDOCTARGET="install-doc" fi AC_SUBST(RDOCTARGET) case "$target_os" in linux*) XCFLAGS="$XCFLAGS -D_GNU_SOURCE=1" ;; netbsd*) CFLAGS="$CFLAGS -pipe" ;; nextstep*|openstep*) # The -fno-common is needed if we wish to embed the Ruby interpreter # into a plugin module of some project (as opposed to embedding it # within the project's application). The -I/usr/local/include is # needed because CPP as discovered by configure (cc -E -traditional) # fails to consult /usr/local/include by default. This causes # mkmf.rb's have_header() to fail if the desired resource happens to be # installed in the /usr/local tree. CFLAGS="$CFLAGS -pipe -fno-common" CPPFLAGS="$CPPFLAGS -I/usr/local/include" ;; rhapsody*) CFLAGS="$CFLAGS -pipe -no-precomp -fno-common" ;; darwin*) CFLAGS="$CFLAGS -pipe -fno-common" MINIOBJS=dmydln.o ;; os2-emx) CFLAGS="$CFLAGS -DOS2 -Zmts" LIBRUBY_A=`echo $LIBRUBY_A | sed 's/^lib//'` LIBRUBY_SO=`echo $LIBRUBY_SO | sed 's/^lib//'` LIBRUBY_ALIASES=`for i in $LIBRUBY_ALIASES; do echo "$i"; done | sed 's/^lib//'` ;; osf*) if test "$GCC" != "yes" ; then # compile something small: taint.c is fine for this. # the main point is the '-v' flag of 'cc'. case "`cc -v -I. -c main.c -o /tmp/main.o 2>&1`" in */gemc_cc*) # we have the new DEC GEM CC CFLAGS="$CFLAGS -oldc" ;; *) # we have the old MIPS CC ;; esac # cleanup rm -f /tmp/main.o CFLAGS="$CFLAGS -std" fi ;; beos*) case "$target_cpu" in powerpc*) CFLAGS="$CFLAGS -relax_pointers" ;; esac ;; cygwin*|mingw*) case "$target_os" in cygwin*) if test x"$enable_shared" = xyes; then LIBRUBY_SO='cyg$(RUBY_SO_NAME)'${MAJOR}${MINOR}.dll LIBRUBY='lib$(RUBY_SO_NAME).dll.a' fi ;; mingw*) RUBY_SO_NAME=${rb_cv_msvcrt}-'$(RUBY_INSTALL_NAME)'${MAJOR}${MINOR} if test x"$enable_shared" = xyes; then LIBRUBY_SO='$(RUBY_SO_NAME)'.dll LIBRUBY='lib$(LIBRUBY_SO).a' fi AC_LIBOBJ([win32]) COMMON_LIBS=m # COMMON_MACROS="WIN32_LEAN_AND_MEAN=" COMMON_HEADERS="windows.h winsock.h" ;; esac LIBRUBY_DLDFLAGS="${DLDFLAGS}"' -Wl,--out-implib=$(LIBRUBY)' LIBRUBY_ALIASES='' FIRSTMAKEFILE=GNUmakefile:cygwin/GNUmakefile.in SOLIBS='$(LIBS)' if test x"$enable_shared" = xno; then LIBRUBY_SO=dummy LIBRUBY='lib$(RUBY_SO_NAME).a' LIBRUBYARG='-l$(RUBY_SO_NAME)' fi MINIOBJS=dmydln.o ;; hpux*) case "$YACC" in *yacc*) XCFLAGS="$XCFLAGS -DYYMAXDEPTH=300" YACC="$YACC -Nl40000 -Nm40000" ;; esac MINIOBJS=dmydln.o ;; *) ;; esac case "$build_os" in *msdosdjgpp*) FIRSTMAKEFILE=GNUmakefile:djgpp/GNUmakefile.in;; esac CPPFLAGS="$CPPFLAGS "'$(DEFS)' test -z "$CFLAGS" || CFLAGS="$CFLAGS "; CFLAGS="$CFLAGS"'${cflags}' test -z "$CPPFLAGS" || CPPFLAGS="$CPPFLAGS "; CPPFLAGS="$CPPFLAGS"'${cppflags}' AC_SUBST(cppflags, [])dnl AC_SUBST(cflags, ['${optflags} ${debugflags}'])dnl AC_SUBST(optflags)dnl AC_SUBST(debugflags)dnl AC_SUBST(XCFLAGS)dnl AC_SUBST(XLDFLAGS)dnl AC_SUBST(LIBRUBY_LDSHARED) AC_SUBST(LIBRUBY_DLDFLAGS) AC_SUBST(RUBY_INSTALL_NAME) AC_SUBST(rubyw_install_name) AC_SUBST(RUBYW_INSTALL_NAME) AC_SUBST(RUBY_SO_NAME) AC_SUBST(LIBRUBY_A) AC_SUBST(LIBRUBY_SO) AC_SUBST(LIBRUBY_ALIASES) AC_SUBST(LIBRUBY) AC_SUBST(LIBRUBYARG) AC_SUBST(LIBRUBYARG_STATIC) AC_SUBST(LIBRUBYARG_SHARED) AC_SUBST(SOLIBS) AC_SUBST(DLDLIBS) AC_SUBST(ENABLE_SHARED) AC_SUBST(MAINLIBS) AC_SUBST(COMMON_LIBS) AC_SUBST(COMMON_MACROS) AC_SUBST(COMMON_HEADERS) AC_SUBST(EXPORT_PREFIX) AC_SUBST(MINIOBJS) MAKEFILES="Makefile `echo $FIRSTMAKEFILE | sed 's/:.*//'`" MAKEFILES="`echo $MAKEFILES`" AC_SUBST(MAKEFILES) ri_prefix= test "$program_prefix" != NONE && ri_prefix=$program_prefix ri_suffix= test "$program_suffix" != NONE && ri_suffix=$program_suffix RUBY_INSTALL_NAME="${ri_prefix}ruby${ri_suffix}" case "$target_os" in cygwin*|mingw*) RUBYW_INSTALL_NAME="${ri_prefix}rubyw${ri_suffix}" rubyw_install_name="$RUBYW_INSTALL_NAME" ;; esac RUBY_LIB_PREFIX=`eval echo \\"${libdir}/ruby\\"` AC_ARG_WITH(sitedir, [ --with-sitedir=DIR site libraries in DIR [[LIBDIR/ruby/site_ruby]]], [sitedir=$withval], [sitedir='${libdir}/ruby/site_ruby']) SITE_DIR=`eval echo \\"${sitedir}\\"` case "$target_os" in cygwin*|mingw*|*djgpp*|os2-emx*) RUBY_LIB_PREFIX="`eval echo "$RUBY_LIB_PREFIX" | sed 's|^NONE/|/|;s|^'"$prefix"'/|/|'`" RUBY_SITE_LIB_PATH="`eval echo "$SITE_DIR" | sed 's|^NONE/|/|;s|^'"$prefix"'/|/|'`" ;; *) RUBY_LIB_PREFIX="`eval echo \\"$RUBY_LIB_PREFIX\\" | sed 's|^NONE/|'"$prefix"'/|'`" RUBY_SITE_LIB_PATH="`eval echo \\"$SITE_DIR\\" | sed 's|^NONE/|'"$prefix"'/|'`" ;; esac RUBY_LIB_PATH="${RUBY_LIB_PREFIX}/${MAJOR}.${MINOR}" RUBY_SITE_LIB_PATH2="${RUBY_SITE_LIB_PATH}/${MAJOR}.${MINOR}" AC_DEFINE_UNQUOTED(RUBY_LIB, "${RUBY_LIB_PATH}") AC_DEFINE_UNQUOTED(RUBY_SITE_LIB, "${RUBY_SITE_LIB_PATH}") AC_DEFINE_UNQUOTED(RUBY_SITE_LIB2, "${RUBY_SITE_LIB_PATH2}") AC_ARG_WITH(vendordir, [ --with-vendordir=DIR vendor libraries in DIR [[LIBDIR/ruby/vendor_ruby]]], [vendordir=$withval], [vendordir='${libdir}/ruby/vendor_ruby']) VENDOR_DIR=`eval echo \\"${vendordir}\\"` case "$target_os" in cygwin*|mingw*|*djgpp*|os2-emx*) RUBY_VENDOR_LIB_PATH="`eval echo "$VENDOR_DIR" | sed 's|^NONE/|/|;s|^'"$prefix"'/|/|'`" ;; *) RUBY_VENDOR_LIB_PATH="`eval echo \\"$VENDOR_DIR\\" | sed 's|^NONE/|'"$prefix"'/|'`" ;; esac RUBY_VENDOR_LIB_PATH2="${RUBY_VENDOR_LIB_PATH}/${MAJOR}.${MINOR}" AC_DEFINE_UNQUOTED(RUBY_VENDOR_LIB, "${RUBY_VENDOR_LIB_PATH}") AC_DEFINE_UNQUOTED(RUBY_VENDOR_LIB2, "${RUBY_VENDOR_LIB_PATH2}") AC_SUBST(arch)dnl AC_SUBST(sitearch)dnl AC_SUBST(sitedir)dnl AC_SUBST(vendordir)dnl configure_args=$ac_configure_args AC_SUBST(configure_args)dnl if test "$fat_binary" != no ; then arch="fat-${target_os}" AC_DEFINE_UNQUOTED(RUBY_THIN_ARCHLIB, "${RUBY_LIB_PATH}/" __ARCHITECTURE__ "-${target_os}") AC_DEFINE_UNQUOTED(RUBY_SITE_THIN_ARCHLIB, "${RUBY_SITE_LIB_PATH}/" __ARCHITECTURE__ "-${target_os}") AC_DEFINE_UNQUOTED(RUBY_VENDOR_THIN_ARCHLIB, "${RUBY_VENDOR_LIB_PATH}/" __ARCHITECTURE__ "-${target_os}") AC_DEFINE_UNQUOTED(RUBY_PLATFORM, __ARCHITECTURE__ "-${target_os}") else arch="${target_cpu}-${target_os}" AC_DEFINE_UNQUOTED(RUBY_PLATFORM, "${arch}") fi case "$target_os" in mingw*) sitearch="$target_cpu-$rb_cv_msvcrt" ;; *) sitearch="${arch}" ;; esac AC_DEFINE_UNQUOTED(RUBY_ARCHLIB, "${RUBY_LIB_PATH}/${arch}") AC_DEFINE_UNQUOTED(RUBY_SITE_ARCHLIB, "${RUBY_SITE_LIB_PATH2}/${sitearch}") AC_DEFINE_UNQUOTED(RUBY_VENDOR_ARCHLIB, "${RUBY_VENDOR_LIB_PATH2}/${sitearch}") AC_ARG_WITH(search-path, [ --with-search-path=DIR specify the additional search path], [search_path=$withval]) if test "$search_path" != ""; then AC_DEFINE_UNQUOTED(RUBY_SEARCH_PATH,"$search_path") fi AC_ARG_WITH(mantype, [ --with-mantype=TYPE specify man page type; TYPE is one of man and doc], [ case "$withval" in man|doc) MANTYPE=$withval ;; *) AC_MSG_ERROR(invalid man type: $withval) ;; esac ]) if test -z "$MANTYPE"; then AC_PATH_PROGS(NROFF, nroff awf, /bin/false, "/usr/bin:/usr/ucb") if ${NROFF} -mdoc ${srcdir}/ruby.1 >/dev/null 2>&1; then MANTYPE=doc else MANTYPE=man fi fi AC_SUBST(MANTYPE) if test -f config.h && tr -d '\015' < confdefs.h | cmp -s config.h -; then echo "config.h unchanged" else echo "creating config.h" tr -d '\015' < confdefs.h > config.h fi tr -d '\015' < largefile.h > confdefs.h rm largefile.h AC_CONFIG_FILES($FIRSTMAKEFILE) AC_CONFIG_FILES(Makefile, [{ sed '/^MISSING/s/\$U\././g' Makefile echo; test x"$EXEEXT" = x || echo 'miniruby: miniruby$(EXEEXT)' test "$RUBY_INSTALL_NAME$EXEEXT" = ruby || echo 'ruby: $(PROGRAM);' sed ['s/{\$([^(){}]*)[^{}]*}//g'] ${srcdir}/common.mk } >> confmk$$.tmp && mv -f confmk$$.tmp Makefile], [RUBY_INSTALL_NAME=$RUBY_INSTALL_NAME EXEEXT=$EXEEXT]) AC_OUTPUT ================================================ FILE: cygwin/GNUmakefile.in ================================================ include Makefile ENABLE_SHARED=@ENABLE_SHARED@ DLLWRAP = @DLLWRAP@ --target=@target_os@ ifeq (@target_os@,cygwin) DLL_BASE_NAME := $(subst .dll,,$(LIBRUBY_SO)) else DLL_BASE_NAME := $(RUBY_SO_NAME) DLLWRAP += -mno-cygwin VPATH += $(srcdir)/win32 endif ifneq ($(ENABLE_SHARED),yes) RUBY_EXP = $(RUBY_INSTALL_NAME).exp EXTOBJS = $(RUBY_EXP) LIBRUBYARG = $(LIBRUBY_A) LIBRUBY_SO = endif ifeq ($(RUBY_INSTALL_NAME),ruby) RUBYW_INSTALL_NAME = $(RUBY_INSTALL_NAME)w else RUBYW_INSTALL_NAME = $(subst ruby,rubyw,$(RUBY_INSTALL_NAME)) endif WPROGRAM = $(RUBYW_INSTALL_NAME)$(EXEEXT) SOLIBS := $(DLL_BASE_NAME).res.@OBJEXT@ $(SOLIBS) EXTOBJS += $(@:$(EXEEXT)=.res.@OBJEXT@) RCFILES = $(RUBY_INSTALL_NAME).rc $(RUBYW_INSTALL_NAME).rc $(DLL_BASE_NAME).rc ruby: $(PROGRAM) rubyw: $(WPROGRAM) $(LIBRUBY): $(RUBY_EXP) $(LIBRUBY_SO) $(RUBY_EXP) $(LIBRUBY_SO): $(DLL_BASE_NAME).res.@OBJEXT@ %.res.@OBJEXT@: %.rc @WINDRES@ --include-dir . --include-dir $(rubydll.def @DLLWRAP@ -s --def=rubydll.def -o $@ @rm -f rubydll.def endif clean-local:: @$(RM) $(RUBY_EXP) $(RCFILES:.rc=.res.@OBJEXT@) distclean-local:: @$(RM) $(RCFILES) ================================================ FILE: defines.h ================================================ /************************************************ defines.h - $Author$ $Date$ created at: Wed May 18 00:21:44 JST 1994 ************************************************/ #ifndef DEFINES_H #define DEFINES_H #define RUBY #ifdef __cplusplus # ifndef HAVE_PROTOTYPES # define HAVE_PROTOTYPES 1 # endif # ifndef HAVE_STDARG_PROTOTYPES # define HAVE_STDARG_PROTOTYPES 1 # endif #endif #undef _ #ifdef HAVE_PROTOTYPES # define _(args) args #else # define _(args) () #endif #undef __ #ifdef HAVE_STDARG_PROTOTYPES # define __(args) args #else # define __(args) () #endif #ifdef __cplusplus #define ANYARGS ... #else #define ANYARGS #endif #define xmalloc ruby_xmalloc #define xcalloc ruby_xcalloc #define xrealloc ruby_xrealloc #define xfree ruby_xfree void *xmalloc _((long)); void *xcalloc _((long,long)); void *xrealloc _((void*,long)); void xfree _((void*)); #define likely(x) __builtin_expect((x),1) #define unlikely(x) __builtin_expect((x),0) #if defined(__APPLE__) #define USING_SYSTEM_ALLOCATOR_LIBRARY #endif /* See system_allocator.c for documentation. */ #ifdef USING_SYSTEM_ALLOCATOR_LIBRARY void *system_malloc(long size); void system_free(void *ptr); #else #define system_malloc(size) malloc(size) #define system_free(ptr) free(ptr) #endif #if SIZEOF_LONG_LONG > 0 # define LONG_LONG long long #elif SIZEOF___INT64 > 0 # define HAVE_LONG_LONG 1 # define LONG_LONG __int64 # undef SIZEOF_LONG_LONG # define SIZEOF_LONG_LONG SIZEOF___INT64 #endif #if SIZEOF_INT*2 <= SIZEOF_LONG_LONG # define BDIGIT unsigned int # define SIZEOF_BDIGITS SIZEOF_INT # define BDIGIT_DBL unsigned LONG_LONG # define BDIGIT_DBL_SIGNED LONG_LONG #elif SIZEOF_INT*2 <= SIZEOF_LONG # define BDIGIT unsigned int # define SIZEOF_BDIGITS SIZEOF_INT # define BDIGIT_DBL unsigned long # define BDIGIT_DBL_SIGNED long #elif SIZEOF_SHORT*2 <= SIZEOF_LONG # define BDIGIT unsigned short # define SIZEOF_BDIGITS SIZEOF_SHORT # define BDIGIT_DBL unsigned long # define BDIGIT_DBL_SIGNED long #else # define BDIGIT unsigned short # define SIZEOF_BDIGITS (SIZEOF_LONG/2) # define BDIGIT_DBL unsigned long # define BDIGIT_DBL_SIGNED long #endif #ifdef __CYGWIN__ #undef _WIN32 #endif #if defined(MSDOS) || defined(_WIN32) || defined(__human68k__) || defined(__EMX__) #define DOSISH 1 #ifndef _WIN32_WCE # define DOSISH_DRIVE_LETTER #endif #endif /* define RUBY_USE_EUC/SJIS for default kanji-code */ #ifndef DEFAULT_KCODE #if defined(DOSISH) || defined(__CYGWIN__) || defined(__MACOS__) || defined(OS2) #define DEFAULT_KCODE KCODE_SJIS #else #define DEFAULT_KCODE KCODE_EUC #endif #endif #if defined(__NeXT__) || defined(__APPLE__) /* Do not trust WORDS_BIGENDIAN from configure since -arch compiler flag may result in a different endian. Instead trust __BIG_ENDIAN__ and __LITTLE_ENDIAN__ which are set correctly by -arch. */ #undef WORDS_BIGENDIAN #ifdef __BIG_ENDIAN__ #define WORDS_BIGENDIAN #endif #endif #ifdef __NeXT__ /* NextStep, OpenStep, Rhapsody */ #ifndef S_IRUSR #define S_IRUSR 0000400 /* read permission, owner */ #endif #ifndef S_IRGRP #define S_IRGRP 0000040 /* read permission, group */ #endif #ifndef S_IROTH #define S_IROTH 0000004 /* read permission, other */ #endif #ifndef S_IWUSR #define S_IWUSR 0000200 /* write permission, owner */ #endif #ifndef S_IWGRP #define S_IWGRP 0000020 /* write permission, group */ #endif #ifndef S_IWOTH #define S_IWOTH 0000002 /* write permission, other */ #endif #ifndef S_IXUSR #define S_IXUSR 0000100 /* execute/search permission, owner */ #endif #ifndef S_IXGRP #define S_IXGRP 0000010 /* execute/search permission, group */ #endif #ifndef S_IXOTH #define S_IXOTH 0000001 /* execute/search permission, other */ #endif #ifndef S_IRWXU #define S_IRWXU 0000700 /* read, write, execute permissions, owner */ #endif #ifndef S_IRWXG #define S_IRWXG 0000070 /* read, write, execute permissions, group */ #endif #ifndef S_IRWXO #define S_IRWXO 0000007 /* read, write, execute permissions, other */ #endif #ifndef S_ISBLK #define S_ISBLK(mode) (((mode) & (0170000)) == (0060000)) #endif #ifndef S_ISCHR #define S_ISCHR(mode) (((mode) & (0170000)) == (0020000)) #endif #ifndef S_ISDIR #define S_ISDIR(mode) (((mode) & (0170000)) == (0040000)) #endif #ifndef S_ISFIFO #define S_ISFIFO(mode) (((mode) & (0170000)) == (0010000)) #endif #ifndef S_ISREG #define S_ISREG(mode) (((mode) & (0170000)) == (0100000)) #endif #ifndef __APPLE__ /* NextStep, OpenStep (but not Rhapsody) */ #ifndef GETPGRP_VOID #define GETPGRP_VOID 1 #endif #ifndef WNOHANG #define WNOHANG 01 #endif #ifndef WUNTRACED #define WUNTRACED 02 #endif #ifndef X_OK #define X_OK 1 #endif #endif /* __APPLE__ */ #endif /* NeXT */ #ifdef _WIN32 #include "win32/win32.h" #endif #if defined(__VMS) #include "vms.h" #endif #if defined(__BEOS__) #include /* intern.h needs fd_set definition */ #endif #ifdef RUBY_EXPORT #undef RUBY_EXTERN #endif #ifndef RUBY_EXTERN #define RUBY_EXTERN extern #endif #ifndef EXTERN #define EXTERN RUBY_EXTERN /* deprecated */ #endif #ifndef RUBY_MBCHAR_MAXSIZE #define RUBY_MBCHAR_MAXSIZE INT_MAX /* MB_CUR_MAX will not work well in C locale */ #endif #if defined(sparc) || defined(__sparc__) static inline void flush_register_windows(void) { asm #ifdef __GNUC__ volatile #endif # if defined(__sparc_v9__) || defined(__sparcv9) || defined(__arch64__) ("flushw") # else ("ta 0x03") # endif /* trap always to flush register windows if we are on a Sparc system */ ; } # define FLUSH_REGISTER_WINDOWS flush_register_windows() #elif defined(__ia64) void *rb_ia64_bsp(void); void rb_ia64_flushrs(void); # define FLUSH_REGISTER_WINDOWS rb_ia64_flushrs() #else # define FLUSH_REGISTER_WINDOWS ((void)0) #endif #if defined(DOSISH) #define PATH_SEP ";" #elif defined(riscos) #define PATH_SEP "," #else #define PATH_SEP ":" #endif #define PATH_SEP_CHAR PATH_SEP[0] #if defined(__human68k__) #define PATH_ENV "path" #else #define PATH_ENV "PATH" #endif #if defined(DOSISH) && !defined(__human68k__) && !defined(__EMX__) #define ENV_IGNORECASE #endif #ifndef CASEFOLD_FILESYSTEM # if defined DOSISH || defined __VMS # define CASEFOLD_FILESYSTEM 1 # else # define CASEFOLD_FILESYSTEM 0 # endif #endif #ifndef DLEXT_MAXLEN #define DLEXT_MAXLEN 4 #endif #ifndef RUBY_PLATFORM #define RUBY_PLATFORM "unknown-unknown" #endif #endif ================================================ FILE: dir.c ================================================ /********************************************************************** dir.c - $Author$ $Date$ created at: Wed Jan 5 09:51:01 JST 1994 Copyright (C) 1993-2003 Yukihiro Matsumoto Copyright (C) 2000 Network Applied Communication Laboratory, Inc. Copyright (C) 2000 Information-technology Promotion Agency, Japan **********************************************************************/ #include "ruby.h" #include #include #ifdef HAVE_UNISTD_H #include #endif #if defined HAVE_DIRENT_H && !defined _WIN32 # include # define NAMLEN(dirent) strlen((dirent)->d_name) #elif defined HAVE_DIRECT_H && !defined _WIN32 # include # define NAMLEN(dirent) strlen((dirent)->d_name) #else # define dirent direct # if !defined __NeXT__ # define NAMLEN(dirent) (dirent)->d_namlen # else # /* On some versions of NextStep, d_namlen is always zero, so avoid it. */ # define NAMLEN(dirent) strlen((dirent)->d_name) # endif # if HAVE_SYS_NDIR_H # include # endif # if HAVE_SYS_DIR_H # include # endif # if HAVE_NDIR_H # include # endif # ifdef _WIN32 # include "win32/dir.h" # endif #endif #include #ifndef HAVE_STDLIB_H char *getenv(); #endif #ifndef HAVE_STRING_H char *strchr _((char*,char)); #endif #include #include "util.h" #if !defined HAVE_LSTAT && !defined lstat #define lstat stat #endif #ifndef CASEFOLD_FILESYSTEM # if defined DOSISH || defined __VMS # define CASEFOLD_FILESYSTEM 1 # else # define CASEFOLD_FILESYSTEM 0 # endif #endif #define FNM_NOESCAPE 0x01 #define FNM_PATHNAME 0x02 #define FNM_DOTMATCH 0x04 #define FNM_CASEFOLD 0x08 #if CASEFOLD_FILESYSTEM #define FNM_SYSCASE FNM_CASEFOLD #else #define FNM_SYSCASE 0 #endif #define FNM_NOMATCH 1 #define FNM_ERROR 2 #define downcase(c) (nocase && ISUPPER(c) ? tolower(c) : (c)) #define compare(c1, c2) (((unsigned char)(c1)) - ((unsigned char)(c2))) /* caution: in case *p == '\0' Next(p) == p + 1 in single byte environment Next(p) == p in multi byte environment */ #if defined(CharNext) # define Next(p) CharNext(p) #elif defined(DJGPP) # define Next(p) ((p) + mblen(p, RUBY_MBCHAR_MAXSIZE)) #elif defined(__EMX__) # define Next(p) ((p) + emx_mblen(p)) static inline int emx_mblen(const char *p) { int n = mblen(p, RUBY_MBCHAR_MAXSIZE); return (n < 0) ? 1 : n; } #endif #ifndef Next /* single byte environment */ # define Next(p) ((p) + 1) # define Inc(p) (++(p)) # define Compare(p1, p2) (compare(downcase(*(p1)), downcase(*(p2)))) #else /* multi byte environment */ # define Inc(p) ((p) = Next(p)) # define Compare(p1, p2) (CompareImpl(p1, p2, nocase)) static int CompareImpl(const char *p1, const char *p2, int nocase) { const int len1 = Next(p1) - p1; const int len2 = Next(p2) - p2; #ifdef _WIN32 char buf1[10], buf2[10]; /* large enough? */ #endif if (len1 < 0 || len2 < 0) { rb_fatal("CompareImpl: negative len"); } if (len1 == 0) return len2; if (len2 == 0) return -len1; #ifdef _WIN32 if (nocase && rb_w32_iswinnt()) { if (len1 > 1) { if (len1 >= sizeof(buf1)) { rb_fatal("CompareImpl: too large len"); } memcpy(buf1, p1, len1); buf1[len1] = '\0'; CharLower(buf1); p1 = buf1; /* trick */ } if (len2 > 1) { if (len2 >= sizeof(buf2)) { rb_fatal("CompareImpl: too large len"); } memcpy(buf2, p2, len2); buf2[len2] = '\0'; CharLower(buf2); p2 = buf2; /* trick */ } } #endif if (len1 == 1) if (len2 == 1) return compare(downcase(*p1), downcase(*p2)); else { const int ret = compare(downcase(*p1), *p2); return ret ? ret : -1; } else if (len2 == 1) { const int ret = compare(*p1, downcase(*p2)); return ret ? ret : 1; } else { const int ret = memcmp(p1, p2, len1 < len2 ? len1 : len2); return ret ? ret : len1 - len2; } } #endif /* environment */ static char * bracket(p, s, flags) const char *p; /* pattern (next to '[') */ const char *s; /* string */ int flags; { const int nocase = flags & FNM_CASEFOLD; const int escape = !(flags & FNM_NOESCAPE); int ok = 0, not = 0; if (*p == '!' || *p == '^') { not = 1; p++; } while (*p != ']') { const char *t1 = p; if (escape && *t1 == '\\') t1++; if (!*t1) return NULL; p = Next(t1); if (p[0] == '-' && p[1] != ']') { const char *t2 = p + 1; if (escape && *t2 == '\\') t2++; if (!*t2) return NULL; p = Next(t2); if (!ok && Compare(t1, s) <= 0 && Compare(s, t2) <= 0) ok = 1; } else if (!ok && Compare(t1, s) == 0) ok = 1; } return ok == not ? NULL : (char *)p + 1; } /* If FNM_PATHNAME is set, only path element will be matched. (upto '/' or '\0') Otherwise, entire string will be matched. End marker itself won't be compared. And if function succeeds, *pcur reaches end marker. */ #define UNESCAPE(p) (escape && *(p) == '\\' ? (p) + 1 : (p)) #define ISEND(p) (!*(p) || (pathname && *(p) == '/')) #define RETURN(val) return *pcur = p, *scur = s, (val); static int fnmatch_helper(pcur, scur, flags) const char **pcur; /* pattern */ const char **scur; /* string */ int flags; { const int period = !(flags & FNM_DOTMATCH); const int pathname = flags & FNM_PATHNAME; const int escape = !(flags & FNM_NOESCAPE); const int nocase = flags & FNM_CASEFOLD; const char *ptmp = 0; const char *stmp = 0; const char *p = *pcur; const char *s = *scur; if (period && *s == '.' && *UNESCAPE(p) != '.') /* leading period */ RETURN(FNM_NOMATCH); while (1) { switch (*p) { case '*': do { p++; } while (*p == '*'); if (ISEND(UNESCAPE(p))) { p = UNESCAPE(p); RETURN(0); } if (ISEND(s)) RETURN(FNM_NOMATCH); ptmp = p; stmp = s; continue; case '?': if (ISEND(s)) RETURN(FNM_NOMATCH); p++; Inc(s); continue; case '[': { const char *t; if (ISEND(s)) RETURN(FNM_NOMATCH); if ((t = bracket(p + 1, s, flags)) != 0) { p = t; Inc(s); continue; } goto failed; } } /* ordinary */ p = UNESCAPE(p); if (ISEND(s)) RETURN(ISEND(p) ? 0 : FNM_NOMATCH); if (ISEND(p)) goto failed; if (Compare(p, s) != 0) goto failed; Inc(p); Inc(s); continue; failed: /* try next '*' position */ if (ptmp && stmp) { p = ptmp; Inc(stmp); /* !ISEND(*stmp) */ s = stmp; continue; } RETURN(FNM_NOMATCH); } } static int fnmatch(p, s, flags) const char *p; /* pattern */ const char *s; /* string */ int flags; { const int period = !(flags & FNM_DOTMATCH); const int pathname = flags & FNM_PATHNAME; const char *ptmp = 0; const char *stmp = 0; if (pathname) { while (1) { if (p[0] == '*' && p[1] == '*' && p[2] == '/') { do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/'); ptmp = p; stmp = s; } if (fnmatch_helper(&p, &s, flags) == 0) { while (*s && *s != '/') Inc(s); if (*p && *s) { p++; s++; continue; } if (!*p && !*s) return 0; } /* failed : try next recursion */ if (ptmp && stmp && !(period && *stmp == '.')) { while (*stmp && *stmp != '/') Inc(stmp); if (*stmp) { p = ptmp; stmp++; s = stmp; continue; } } return FNM_NOMATCH; } } else return fnmatch_helper(&p, &s, flags); } VALUE rb_cDir; struct dir_data { DIR *dir; char *path; }; static void free_dir(dir) struct dir_data *dir; { if (dir) { if (dir->dir) closedir(dir->dir); if (dir->path) free(dir->path); } free(dir); } static VALUE dir_close _((VALUE)); static VALUE dir_s_alloc _((VALUE)); static VALUE dir_s_alloc(klass) VALUE klass; { struct dir_data *dirp; VALUE obj = Data_Make_Struct(klass, struct dir_data, 0, free_dir, dirp); dirp->dir = NULL; dirp->path = NULL; return obj; } /* * call-seq: * Dir.new( string ) -> aDir * * Returns a new directory object for the named directory. */ static VALUE dir_initialize(dir, dirname) VALUE dir, dirname; { struct dir_data *dp; SafeStringValue(dirname); Data_Get_Struct(dir, struct dir_data, dp); if (dp->dir) closedir(dp->dir); if (dp->path) free(dp->path); dp->dir = NULL; dp->path = NULL; dp->dir = opendir(RSTRING(dirname)->ptr); if (dp->dir == NULL) { if (errno == EMFILE || errno == ENFILE) { rb_gc(); dp->dir = opendir(RSTRING(dirname)->ptr); } if (dp->dir == NULL) { rb_sys_fail(RSTRING(dirname)->ptr); } } dp->path = strdup(RSTRING(dirname)->ptr); return dir; } /* * call-seq: * Dir.open( string ) => aDir * Dir.open( string ) {| aDir | block } => anObject * * With no block, open is a synonym for * Dir::new. If a block is present, it is passed * aDir as a parameter. The directory is closed at the end of * the block, and Dir::open returns the value of the * block. */ static VALUE dir_s_open(klass, dirname) VALUE klass, dirname; { struct dir_data *dp; VALUE dir = Data_Make_Struct(klass, struct dir_data, 0, free_dir, dp); dir_initialize(dir, dirname); if (rb_block_given_p()) { return rb_ensure(rb_yield, dir, dir_close, dir); } return dir; } static void dir_closed() { rb_raise(rb_eIOError, "closed directory"); } static void dir_check(dir) VALUE dir; { if (!OBJ_TAINTED(dir) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: operation on untainted Dir"); rb_check_frozen(dir); } #define GetDIR(obj, dirp) do {\ dir_check(dir);\ Data_Get_Struct(obj, struct dir_data, dirp);\ if (dirp->dir == NULL) dir_closed();\ } while (0) /* * call-seq: * dir.inspect => string * * Return a string describing this Dir object. */ static VALUE dir_inspect(dir) VALUE dir; { struct dir_data *dirp; Data_Get_Struct(dir, struct dir_data, dirp); if (dirp->path) { const char *c = rb_obj_classname(dir); int len = strlen(c) + strlen(dirp->path) + 4; VALUE s = rb_str_new(0, len); snprintf(RSTRING_PTR(s), len+1, "#<%s:%s>", c, dirp->path); return s; } return rb_funcall(dir, rb_intern("to_s"), 0, 0); } /* * call-seq: * dir.path => string or nil * * Returns the path parameter passed to dir's constructor. * * d = Dir.new("..") * d.path #=> ".." */ static VALUE dir_path(dir) VALUE dir; { struct dir_data *dirp; Data_Get_Struct(dir, struct dir_data, dirp); if (!dirp->path) return Qnil; return rb_str_new2(dirp->path); } /* * call-seq: * dir.read => string or nil * * Reads the next entry from dir and returns it as a string. * Returns nil at the end of the stream. * * d = Dir.new("testdir") * d.read #=> "." * d.read #=> ".." * d.read #=> "config.h" */ static VALUE dir_read(dir) VALUE dir; { struct dir_data *dirp; struct dirent *dp; GetDIR(dir, dirp); errno = 0; dp = readdir(dirp->dir); if (dp) { return rb_tainted_str_new(dp->d_name, NAMLEN(dp)); } else if (errno == 0) { /* end of stream */ return Qnil; } else { rb_sys_fail(0); } return Qnil; /* not reached */ } /* * call-seq: * dir.each { |filename| block } => dir * * Calls the block once for each entry in this directory, passing the * filename of each entry as a parameter to the block. * * d = Dir.new("testdir") * d.each {|x| puts "Got #{x}" } * * produces: * * Got . * Got .. * Got config.h * Got main.rb */ static VALUE dir_each(dir) VALUE dir; { struct dir_data *dirp; struct dirent *dp; RETURN_ENUMERATOR(dir, 0, 0); GetDIR(dir, dirp); rewinddir(dirp->dir); for (dp = readdir(dirp->dir); dp != NULL; dp = readdir(dirp->dir)) { rb_yield(rb_tainted_str_new(dp->d_name, NAMLEN(dp))); if (dirp->dir == NULL) dir_closed(); } return dir; } /* * call-seq: * dir.pos => integer * dir.tell => integer * * Returns the current position in dir. See also * Dir#seek. * * d = Dir.new("testdir") * d.tell #=> 0 * d.read #=> "." * d.tell #=> 12 */ static VALUE dir_tell(dir) VALUE dir; { #ifdef HAVE_TELLDIR struct dir_data *dirp; long pos; GetDIR(dir, dirp); pos = telldir(dirp->dir); return rb_int2inum(pos); #else rb_notimplement(); #endif } /* * call-seq: * dir.seek( integer ) => dir * * Seeks to a particular location in dir. integer * must be a value returned by Dir#tell. * * d = Dir.new("testdir") #=> # * d.read #=> "." * i = d.tell #=> 12 * d.read #=> ".." * d.seek(i) #=> # * d.read #=> ".." */ static VALUE dir_seek(dir, pos) VALUE dir, pos; { struct dir_data *dirp; off_t p = NUM2OFFT(pos); GetDIR(dir, dirp); #ifdef HAVE_SEEKDIR seekdir(dirp->dir, p); return dir; #else rb_notimplement(); #endif } /* * call-seq: * dir.pos( integer ) => integer * * Synonym for Dir#seek, but returns the position * parameter. * * d = Dir.new("testdir") #=> # * d.read #=> "." * i = d.pos #=> 12 * d.read #=> ".." * d.pos = i #=> 12 * d.read #=> ".." */ static VALUE dir_set_pos(dir, pos) VALUE dir, pos; { dir_seek(dir, pos); return pos; } /* * call-seq: * dir.rewind => dir * * Repositions dir to the first entry. * * d = Dir.new("testdir") * d.read #=> "." * d.rewind #=> # * d.read #=> "." */ static VALUE dir_rewind(dir) VALUE dir; { struct dir_data *dirp; if (rb_safe_level() >= 4 && !OBJ_TAINTED(dir)) { rb_raise(rb_eSecurityError, "Insecure: can't close"); } GetDIR(dir, dirp); rewinddir(dirp->dir); return dir; } /* * call-seq: * dir.close => nil * * Closes the directory stream. Any further attempts to access * dir will raise an IOError. * * d = Dir.new("testdir") * d.close #=> nil */ static VALUE dir_close(dir) VALUE dir; { struct dir_data *dirp; GetDIR(dir, dirp); closedir(dirp->dir); dirp->dir = NULL; return Qnil; } static void dir_chdir(path) VALUE path; { if (chdir(RSTRING(path)->ptr) < 0) rb_sys_fail(RSTRING(path)->ptr); } static int chdir_blocking = 0; static VALUE chdir_thread = Qnil; struct chdir_data { VALUE old_path, new_path; int done; }; static VALUE chdir_yield(args) struct chdir_data *args; { dir_chdir(args->new_path); args->done = Qtrue; chdir_blocking++; if (chdir_thread == Qnil) chdir_thread = rb_thread_current(); return rb_yield(args->new_path); } static VALUE chdir_restore(args) struct chdir_data *args; { if (args->done) { chdir_blocking--; if (chdir_blocking == 0) chdir_thread = Qnil; dir_chdir(args->old_path); } return Qnil; } /* * call-seq: * Dir.chdir( [ string] ) => 0 * Dir.chdir( [ string] ) {| path | block } => anObject * * Changes the current working directory of the process to the given * string. When called without an argument, changes the directory to * the value of the environment variable HOME, or * LOGDIR. SystemCallError (probably * Errno::ENOENT) if the target directory does not exist. * * If a block is given, it is passed the name of the new current * directory, and the block is executed with that as the current * directory. The original working directory is restored when the block * exits. The return value of chdir is the value of the * block. chdir blocks can be nested, but in a * multi-threaded program an error will be raised if a thread attempts * to open a chdir block while another thread has one * open. * * Dir.chdir("/var/spool/mail") * puts Dir.pwd * Dir.chdir("/tmp") do * puts Dir.pwd * Dir.chdir("/usr") do * puts Dir.pwd * end * puts Dir.pwd * end * puts Dir.pwd * * produces: * * /var/spool/mail * /tmp * /usr * /tmp * /var/spool/mail */ static VALUE dir_s_chdir(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE path = Qnil; rb_secure(2); if (rb_scan_args(argc, argv, "01", &path) == 1) { SafeStringValue(path); } else { const char *dist = getenv("HOME"); if (!dist) { dist = getenv("LOGDIR"); if (!dist) rb_raise(rb_eArgError, "HOME/LOGDIR not set"); } path = rb_str_new2(dist); } if (chdir_blocking > 0) { if (!rb_block_given_p() || rb_thread_current() != chdir_thread) rb_warn("conflicting chdir during another chdir block"); } if (rb_block_given_p()) { struct chdir_data args; char *cwd = my_getcwd(); args.old_path = rb_tainted_str_new2(cwd); free(cwd); args.new_path = path; args.done = Qfalse; return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args); } dir_chdir(path); return INT2FIX(0); } /* * call-seq: * Dir.getwd => string * Dir.pwd => string * * Returns the path to the current working directory of this process as * a string. * * Dir.chdir("/tmp") #=> 0 * Dir.getwd #=> "/tmp" */ static VALUE dir_s_getwd(dir) VALUE dir; { char *path; VALUE cwd; rb_secure(4); path = my_getcwd(); cwd = rb_tainted_str_new2(path); free(path); return cwd; } static void check_dirname _((volatile VALUE *)); static void check_dirname(dir) volatile VALUE *dir; { char *path, *pend; SafeStringValue(*dir); rb_secure(2); path = RSTRING(*dir)->ptr; if (path && *(pend = rb_path_end(rb_path_skip_prefix(path)))) { *dir = rb_str_new(path, pend - path); } } /* * call-seq: * Dir.chroot( string ) => 0 * * Changes this process's idea of the file system root. Only a * privileged process may make this call. Not available on all * platforms. On Unix systems, see chroot(2) for more * information. */ static VALUE dir_s_chroot(dir, path) VALUE dir, path; { #if defined(HAVE_CHROOT) && !defined(__CHECKER__) check_dirname(&path); if (chroot(RSTRING(path)->ptr) == -1) rb_sys_fail(RSTRING(path)->ptr); return INT2FIX(0); #else rb_notimplement(); return Qnil; /* not reached */ #endif } /* * call-seq: * Dir.mkdir( string [, integer] ) => 0 * * Makes a new directory named by string, with permissions * specified by the optional parameter anInteger. The * permissions may be modified by the value of * File::umask, and are ignored on NT. Raises a * SystemCallError if the directory cannot be created. See * also the discussion of permissions in the class documentation for * File. * */ static VALUE dir_s_mkdir(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE path, vmode; int mode; if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) { mode = NUM2INT(vmode); } else { mode = 0777; } check_dirname(&path); if (mkdir(RSTRING(path)->ptr, mode) == -1) rb_sys_fail(RSTRING(path)->ptr); return INT2FIX(0); } /* * call-seq: * Dir.delete( string ) => 0 * Dir.rmdir( string ) => 0 * Dir.unlink( string ) => 0 * * Deletes the named directory. Raises a subclass of * SystemCallError if the directory isn't empty. */ static VALUE dir_s_rmdir(obj, dir) VALUE obj, dir; { check_dirname(&dir); if (rmdir(RSTRING(dir)->ptr) < 0) rb_sys_fail(RSTRING(dir)->ptr); return INT2FIX(0); } static void sys_warning_1(mesg) const char* mesg; { rb_sys_warning("%s", mesg); } #define GLOB_VERBOSE (1UL << (sizeof(int) * CHAR_BIT - 1)) #define sys_warning(val) \ (void)((flags & GLOB_VERBOSE) && rb_protect((VALUE (*)_((VALUE)))sys_warning_1, (VALUE)(val), 0)) #define GLOB_ALLOC(type) (type *)malloc(sizeof(type)) #define GLOB_ALLOC_N(type, n) (type *)malloc(sizeof(type) * (n)) #define GLOB_JUMP_TAG(status) ((status == -1) ? rb_memerror() : rb_jump_tag(status)) /* * ENOTDIR can be returned by stat(2) if a non-leaf element of the path * is not a directory. */ #define to_be_ignored(e) ((e) == ENOENT || (e) == ENOTDIR) /* System call with warning */ static int do_stat(const char *path, struct stat *pst, int flags) { int ret = stat(path, pst); if (ret < 0 && !to_be_ignored(errno)) sys_warning(path); return ret; } static int do_lstat(const char *path, struct stat *pst, int flags) { int ret = lstat(path, pst); if (ret < 0 && !to_be_ignored(errno)) sys_warning(path); return ret; } static DIR * do_opendir(const char *path, int flags) { DIR *dirp = opendir(path); if (dirp == NULL && !to_be_ignored(errno)) sys_warning(path); return dirp; } /* Return nonzero if S has any special globbing chars in it. */ static int has_magic(s, flags) const char *s; int flags; { const int escape = !(flags & FNM_NOESCAPE); const int nocase = flags & FNM_CASEFOLD; register const char *p = s; register char c; while ((c = *p++) != 0) { switch (c) { case '*': case '?': case '[': return 1; case '\\': if (escape && !(c = *p++)) return 0; continue; default: if (!FNM_SYSCASE && ISALPHA(c) && nocase) return 1; } p = Next(p-1); } return 0; } /* Find separator in globbing pattern. */ static char * find_dirsep(const char *s, int flags) { const int escape = !(flags & FNM_NOESCAPE); register const char *p = s; register char c; int open = 0; while ((c = *p++) != 0) { switch (c) { case '[': open = 1; continue; case ']': open = 0; continue; case '/': if (!open) return (char *)p-1; continue; case '\\': if (escape && !(c = *p++)) return (char *)p-1; continue; } p = Next(p-1); } return (char *)p-1; } /* Remove escaping backslashes */ static void remove_backslashes(p) char *p; { char *t = p; char *s = p; while (*p) { if (*p == '\\') { if (t != s) memmove(t, s, p - s); t += p - s; s = ++p; if (!*p) break; } Inc(p); } while (*p++); if (t != s) memmove(t, s, p - s); /* move '\0' too */ } /* Globing pattern */ enum glob_pattern_type { PLAIN, MAGICAL, RECURSIVE, MATCH_ALL, MATCH_DIR }; struct glob_pattern { char *str; enum glob_pattern_type type; struct glob_pattern *next; }; static void glob_free_pattern(struct glob_pattern *list); static struct glob_pattern * glob_make_pattern(const char *p, int flags) { struct glob_pattern *list, *tmp, **tail = &list; int dirsep = 0; /* pattern is terminated with '/' */ while (*p) { tmp = GLOB_ALLOC(struct glob_pattern); if (!tmp) goto error; if (p[0] == '*' && p[1] == '*' && p[2] == '/') { /* fold continuous RECURSIVEs (needed in glob_helper) */ do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/'); tmp->type = RECURSIVE; tmp->str = 0; dirsep = 1; } else { const char *m = find_dirsep(p, flags); char *buf = GLOB_ALLOC_N(char, m-p+1); if (!buf) { free(tmp); goto error; } memcpy(buf, p, m-p); buf[m-p] = '\0'; tmp->type = has_magic(buf, flags) ? MAGICAL : PLAIN; tmp->str = buf; if (*m) { dirsep = 1; p = m + 1; } else { dirsep = 0; p = m; } } *tail = tmp; tail = &tmp->next; } tmp = GLOB_ALLOC(struct glob_pattern); if (!tmp) { error: *tail = 0; glob_free_pattern(list); return 0; } tmp->type = dirsep ? MATCH_DIR : MATCH_ALL; tmp->str = 0; *tail = tmp; tmp->next = 0; return list; } static void glob_free_pattern(struct glob_pattern *list) { while (list) { struct glob_pattern *tmp = list; list = list->next; if (tmp->str) free(tmp->str); free(tmp); } } static char * join_path(const char *path, int dirsep, const char *name) { long len = strlen(path); char *buf = GLOB_ALLOC_N(char, len+strlen(name)+(dirsep?1:0)+1); if (!buf) return 0; memcpy(buf, path, len); if (dirsep) { strcpy(buf+len, "/"); len++; } strcpy(buf+len, name); return buf; } enum answer { YES, NO, UNKNOWN }; #ifndef S_ISLNK # ifndef S_IFLNK # define S_ISLNK(m) (0) # else # define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK) # endif #endif #ifndef S_ISDIR # define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) #endif struct glob_args { void (*func) _((const char*, VALUE)); const char *c; VALUE v; }; static VALUE glob_func_caller _((VALUE)); static VALUE glob_func_caller(val) VALUE val; { struct glob_args *args = (struct glob_args *)val; (*args->func)(args->c, args->v); return Qnil; } #define glob_call_func(func, path, arg) (*func)(path, arg) static int glob_helper _((const char *, int, enum answer, enum answer, struct glob_pattern **, struct glob_pattern **, int, ruby_glob_func *, VALUE)); static int glob_helper(path, dirsep, exist, isdir, beg, end, flags, func, arg) const char *path; int dirsep; /* '/' should be placed before appending child entry's name to 'path'. */ enum answer exist; /* Does 'path' indicate an existing entry? */ enum answer isdir; /* Does 'path' indicate a directory or a symlink to a directory? */ struct glob_pattern **beg; struct glob_pattern **end; int flags; ruby_glob_func *func; VALUE arg; { struct stat st; int status = 0; struct glob_pattern **cur, **new_beg, **new_end; int plain = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0; int escape = !(flags & FNM_NOESCAPE); for (cur = beg; cur < end; ++cur) { struct glob_pattern *p = *cur; if (p->type == RECURSIVE) { recursive = 1; p = p->next; } switch (p->type) { case PLAIN: plain = 1; break; case MAGICAL: magical = 1; break; case MATCH_ALL: match_all = 1; break; case MATCH_DIR: match_dir = 1; break; case RECURSIVE: rb_bug("continuous RECURSIVEs"); } } if (*path) { if (match_all && exist == UNKNOWN) { if (do_lstat(path, &st, flags) == 0) { exist = YES; isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO; } else { exist = NO; isdir = NO; } } if (match_dir && isdir == UNKNOWN) { if (do_stat(path, &st, flags) == 0) { exist = YES; isdir = S_ISDIR(st.st_mode) ? YES : NO; } else { exist = NO; isdir = NO; } } if (match_all && exist == YES) { status = glob_call_func(func, path, arg); if (status) return status; } if (match_dir && isdir == YES) { char *tmp = join_path(path, dirsep, ""); if (!tmp) return -1; status = glob_call_func(func, tmp, arg); free(tmp); if (status) return status; } } if (exist == NO || isdir == NO) return 0; if (magical || recursive) { struct dirent *dp; DIR *dirp = do_opendir(*path ? path : ".", flags); if (dirp == NULL) return 0; for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { char *buf = join_path(path, dirsep, dp->d_name); enum answer new_isdir = UNKNOWN; if (!buf) { status = -1; break; } if (recursive && strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0 && fnmatch("*", dp->d_name, flags) == 0) { #ifndef _WIN32 if (do_lstat(buf, &st, flags) == 0) new_isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO; else new_isdir = NO; #else new_isdir = dp->d_isdir ? (!dp->d_isrep ? YES : UNKNOWN) : NO; #endif } new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, (end - beg) * 2); if (!new_beg) { status = -1; break; } for (cur = beg; cur < end; ++cur) { struct glob_pattern *p = *cur; if (p->type == RECURSIVE) { if (new_isdir == YES) /* not symlink but real directory */ *new_end++ = p; /* append recursive pattern */ p = p->next; /* 0 times recursion */ } if (p->type == PLAIN || p->type == MAGICAL) { if (fnmatch(p->str, dp->d_name, flags) == 0) *new_end++ = p->next; } } status = glob_helper(buf, 1, YES, new_isdir, new_beg, new_end, flags, func, arg); free(buf); free(new_beg); if (status) break; } closedir(dirp); } else if (plain) { struct glob_pattern **copy_beg, **copy_end, **cur2; copy_beg = copy_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg); if (!copy_beg) return -1; for (cur = beg; cur < end; ++cur) *copy_end++ = (*cur)->type == PLAIN ? *cur : 0; for (cur = copy_beg; cur < copy_end; ++cur) { if (*cur) { char *buf; char *name; name = GLOB_ALLOC_N(char, strlen((*cur)->str) + 1); if (!name) { status = -1; break; } strcpy(name, (*cur)->str); if (escape) remove_backslashes(name); new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg); if (!new_beg) { free(name); status = -1; break; } *new_end++ = (*cur)->next; for (cur2 = cur + 1; cur2 < copy_end; ++cur2) { if (*cur2 && fnmatch((*cur2)->str, name, flags) == 0) { *new_end++ = (*cur2)->next; *cur2 = 0; } } buf = join_path(path, dirsep, name); free(name); if (!buf) { free(new_beg); status = -1; break; } status = glob_helper(buf, 1, UNKNOWN, UNKNOWN, new_beg, new_end, flags, func, arg); free(buf); free(new_beg); if (status) break; } } free(copy_beg); } return status; } static int ruby_glob0(path, flags, func, arg) const char *path; int flags; ruby_glob_func *func; VALUE arg; { struct glob_pattern *list; const char *root, *start; char *buf; int n; int status; start = root = path; flags |= FNM_SYSCASE; #if defined DOSISH root = rb_path_skip_prefix(root); #endif if (root && *root == '/') root++; n = root - start; buf = GLOB_ALLOC_N(char, n + 1); if (!buf) return -1; MEMCPY(buf, start, char, n); buf[n] = '\0'; list = glob_make_pattern(root, flags); if (!list) { free(buf); return -1; } status = glob_helper(buf, 0, UNKNOWN, UNKNOWN, &list, &list + 1, flags, func, arg); glob_free_pattern(list); free(buf); return status; } int ruby_glob(path, flags, func, arg) const char *path; int flags; ruby_glob_func *func; VALUE arg; { return ruby_glob0(path, flags & ~GLOB_VERBOSE, func, arg); } static int rb_glob_caller _((const char *, VALUE)); static int rb_glob_caller(path, a) const char *path; VALUE a; { int status; struct glob_args *args = (struct glob_args *)a; args->c = path; rb_protect(glob_func_caller, a, &status); return status; } static int rb_glob2(path, flags, func, arg) const char *path; int flags; void (*func) _((const char *, VALUE)); VALUE arg; { struct glob_args args; args.func = func; args.v = arg; if (flags & FNM_SYSCASE) { rb_warning("Dir.glob() ignores File::FNM_CASEFOLD"); } return ruby_glob0(path, flags | GLOB_VERBOSE, rb_glob_caller, (VALUE)&args); } void rb_glob(path, func, arg) const char *path; void (*func) _((const char*, VALUE)); VALUE arg; { int status = rb_glob2(path, 0, func, arg); if (status) GLOB_JUMP_TAG(status); } static void push_pattern _((const char* path, VALUE ary)); static void push_pattern(path, ary) const char *path; VALUE ary; { rb_ary_push(ary, rb_tainted_str_new2(path)); } int ruby_brace_expand(str, flags, func, arg) const char *str; int flags; ruby_glob_func *func; VALUE arg; { const int escape = !(flags & FNM_NOESCAPE); const char *p = str; const char *s = p; const char *lbrace = 0, *rbrace = 0; int nest = 0, status = 0; while (*p) { if (*p == '{' && nest++ == 0) { lbrace = p; } if (*p == '}' && --nest <= 0) { rbrace = p; break; } if (*p == '\\' && escape) { if (!*++p) break; } Inc(p); } if (lbrace && rbrace) { char *buf = GLOB_ALLOC_N(char, strlen(s) + 1); long shift; if (!buf) return -1; memcpy(buf, s, lbrace-s); shift = (lbrace-s); p = lbrace; while (p < rbrace) { const char *t = ++p; nest = 0; while (p < rbrace && !(*p == ',' && nest == 0)) { if (*p == '{') nest++; if (*p == '}') nest--; if (*p == '\\' && escape) { if (++p == rbrace) break; } Inc(p); } memcpy(buf+shift, t, p-t); strcpy(buf+shift+(p-t), rbrace+1); status = ruby_brace_expand(buf, flags, func, arg); if (status) break; } free(buf); } else if (!lbrace && !rbrace) { status = (*func)(s, arg); } return status; } struct brace_args { ruby_glob_func *func; VALUE value; int flags; }; static int glob_brace _((const char *, VALUE)); static int glob_brace(path, val) const char *path; VALUE val; { struct brace_args *arg = (struct brace_args *)val; return ruby_glob0(path, arg->flags, arg->func, arg->value); } static int ruby_brace_glob0(str, flags, func, arg) const char *str; int flags; ruby_glob_func *func; VALUE arg; { struct brace_args args; args.func = func; args.value = arg; args.flags = flags; return ruby_brace_expand(str, flags, glob_brace, (VALUE)&args); } int ruby_brace_glob(str, flags, func, arg) const char *str; int flags; ruby_glob_func *func; VALUE arg; { return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg); } static int push_glob(VALUE ary, const char *str, int flags) { struct glob_args args; args.func = push_pattern; args.v = ary; return ruby_brace_glob0(str, flags | GLOB_VERBOSE, rb_glob_caller, (VALUE)&args); } static VALUE rb_push_glob(str, flags) /* '\0' is delimiter */ VALUE str; int flags; { long offset = 0; VALUE ary; ary = rb_ary_new(); SafeStringValue(str); while (offset < RSTRING_LEN(str)) { int status = push_glob(ary, RSTRING(str)->ptr + offset, flags); char *p, *pend; if (status) GLOB_JUMP_TAG(status); if (offset >= RSTRING_LEN(str)) break; p = RSTRING(str)->ptr + offset; p += strlen(p) + 1; pend = RSTRING(str)->ptr + RSTRING_LEN(str); while (p < pend && !*p) p++; offset = p - RSTRING(str)->ptr; } return ary; } static VALUE dir_globs(argc, argv, flags) long argc; VALUE *argv; int flags; { VALUE ary = rb_ary_new(); long i; for (i = 0; i < argc; ++i) { int status; VALUE str = argv[i]; SafeStringValue(str); status = push_glob(ary, RSTRING(str)->ptr, flags); if (status) GLOB_JUMP_TAG(status); } return ary; } /* * call-seq: * Dir[ array ] => array * Dir[ string [, string ...] ] => array * * Equivalent to calling * Dir.glob(array,0) and * Dir.glob([string,...],0). * */ static VALUE dir_s_aref(int argc, VALUE *argv, VALUE obj) { if (argc == 1) { return rb_push_glob(argv[0], 0); } return dir_globs(argc, argv, 0); } /* * call-seq: * Dir.glob( pattern, [flags] ) => array * Dir.glob( pattern, [flags] ) {| filename | block } => nil * * Returns the filenames found by expanding pattern which is * an +Array+ of the patterns or the pattern +String+, either as an * array or as parameters to the block. Note that this pattern * is not a regexp (it's closer to a shell glob). See * File::fnmatch for the meaning of the flags * parameter. Note that case sensitivity depends on your system (so * File::FNM_CASEFOLD is ignored) * * *:: Matches any file. Can be restricted by * other values in the glob. * * will match all files; c* will * match all files beginning with * c; *c will match * all files ending with c; and * *c* will match all files that * have c in them (including at * the beginning or end). Equivalent to * / .* /x in regexp. * **:: Matches directories recursively. * ?:: Matches any one character. Equivalent to * /.{1}/ in regexp. * [set]:: Matches any one character in +set+. * Behaves exactly like character sets in * Regexp, including set negation * ([^a-z]). * {p,q}:: Matches either literal p or * literal q. Matching literals * may be more than one character in length. * More than two literals may be specified. * Equivalent to pattern alternation in * regexp. * \:: Escapes the next metacharacter. * * Dir["config.?"] #=> ["config.h"] * Dir.glob("config.?") #=> ["config.h"] * Dir.glob("*.[a-z][a-z]") #=> ["main.rb"] * Dir.glob("*.[^r]*") #=> ["config.h"] * Dir.glob("*.{rb,h}") #=> ["main.rb", "config.h"] * Dir.glob("*") #=> ["config.h", "main.rb"] * Dir.glob("*", File::FNM_DOTMATCH) #=> [".", "..", "config.h", "main.rb"] * * rbfiles = File.join("**", "*.rb") * Dir.glob(rbfiles) #=> ["main.rb", * "lib/song.rb", * "lib/song/karaoke.rb"] * libdirs = File.join("**", "lib") * Dir.glob(libdirs) #=> ["lib"] * * librbfiles = File.join("**", "lib", "**", "*.rb") * Dir.glob(librbfiles) #=> ["lib/song.rb", * "lib/song/karaoke.rb"] * * librbfiles = File.join("**", "lib", "*.rb") * Dir.glob(librbfiles) #=> ["lib/song.rb"] */ static VALUE dir_s_glob(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE str, rflags, ary; int flags; if (rb_scan_args(argc, argv, "11", &str, &rflags) == 2) flags = NUM2INT(rflags); else flags = 0; ary = rb_check_array_type(str); if (NIL_P(ary)) { ary = rb_push_glob(str, flags); } else { volatile VALUE v = ary; ary = dir_globs(RARRAY_LEN(v), RARRAY_PTR(v), flags); } if (rb_block_given_p()) { rb_ary_each(ary); return Qnil; } return ary; } static VALUE dir_open_dir(path) VALUE path; { VALUE dir = rb_funcall(rb_cDir, rb_intern("open"), 1, path); if (TYPE(dir) != T_DATA || RDATA(dir)->dfree != (RUBY_DATA_FUNC)free_dir) { rb_raise(rb_eTypeError, "wrong argument type %s (expected Dir)", rb_obj_classname(dir)); } return dir; } /* * call-seq: * Dir.foreach( dirname ) {| filename | block } => nil * * Calls the block once for each entry in the named directory, passing * the filename of each entry as a parameter to the block. * * Dir.foreach("testdir") {|x| puts "Got #{x}" } * * produces: * * Got . * Got .. * Got config.h * Got main.rb * */ static VALUE dir_foreach(io, dirname) VALUE io, dirname; { VALUE dir; RETURN_ENUMERATOR(io, 1, &dirname); dir = dir_open_dir(dirname); rb_ensure(dir_each, dir, dir_close, dir); return Qnil; } /* * call-seq: * Dir.entries( dirname ) => array * * Returns an array containing all of the filenames in the given * directory. Will raise a SystemCallError if the named * directory doesn't exist. * * Dir.entries("testdir") #=> [".", "..", "config.h", "main.rb"] * */ static VALUE dir_entries(io, dirname) VALUE io, dirname; { VALUE dir; dir = dir_open_dir(dirname); return rb_ensure(rb_Array, dir, dir_close, dir); } /* * call-seq: * File.fnmatch( pattern, path, [flags] ) => (true or false) * File.fnmatch?( pattern, path, [flags] ) => (true or false) * * Returns true if path matches against pattern The * pattern is not a regular expression; instead it follows rules * similar to shell filename globbing. It may contain the following * metacharacters: * * *:: Matches any file. Can be restricted by * other values in the glob. * * will match all files; c* will * match all files beginning with * c; *c will match * all files ending with c; and * *c* will match all files that * have c in them (including at * the beginning or end). Equivalent to * / .* /x in regexp. * **:: Matches directories recursively or files * expansively. * ?:: Matches any one character. Equivalent to * /.{1}/ in regexp. * [set]:: Matches any one character in +set+. * Behaves exactly like character sets in * Regexp, including set negation * ([^a-z]). * \:: Escapes the next metacharacter. * * flags is a bitwise OR of the FNM_xxx * parameters. The same glob pattern and flags are used by * Dir::glob. * * File.fnmatch('cat', 'cat') #=> true : match entire string * File.fnmatch('cat', 'category') #=> false : only match partial string * File.fnmatch('c{at,ub}s', 'cats') #=> false : { } isn't supported * * File.fnmatch('c?t', 'cat') #=> true : '?' match only 1 character * File.fnmatch('c??t', 'cat') #=> false : ditto * File.fnmatch('c*', 'cats') #=> true : '*' match 0 or more characters * File.fnmatch('c*t', 'c/a/b/t') #=> true : ditto * File.fnmatch('ca[a-z]', 'cat') #=> true : inclusive bracket expression * File.fnmatch('ca[^t]', 'cat') #=> false : exclusive bracket expression ('^' or '!') * * File.fnmatch('cat', 'CAT') #=> false : case sensitive * File.fnmatch('cat', 'CAT', File::FNM_CASEFOLD) #=> true : case insensitive * * File.fnmatch('?', '/', File::FNM_PATHNAME) #=> false : wildcard doesn't match '/' on FNM_PATHNAME * File.fnmatch('*', '/', File::FNM_PATHNAME) #=> false : ditto * File.fnmatch('[/]', '/', File::FNM_PATHNAME) #=> false : ditto * * File.fnmatch('\?', '?') #=> true : escaped wildcard becomes ordinary * File.fnmatch('\a', 'a') #=> true : escaped ordinary remains ordinary * File.fnmatch('\a', '\a', File::FNM_NOESCAPE) #=> true : FNM_NOESACPE makes '\' ordinary * File.fnmatch('[\?]', '?') #=> true : can escape inside bracket expression * * File.fnmatch('*', '.profile') #=> false : wildcard doesn't match leading * File.fnmatch('*', '.profile', File::FNM_DOTMATCH) #=> true period by default. * File.fnmatch('.*', '.profile') #=> true * * rbfiles = '**' '/' '*.rb' # you don't have to do like this. just write in single string. * File.fnmatch(rbfiles, 'main.rb') #=> false * File.fnmatch(rbfiles, './main.rb') #=> false * File.fnmatch(rbfiles, 'lib/song.rb') #=> true * File.fnmatch('**.rb', 'main.rb') #=> true * File.fnmatch('**.rb', './main.rb') #=> false * File.fnmatch('**.rb', 'lib/song.rb') #=> true * File.fnmatch('*', 'dave/.profile') #=> true * * pattern = '*' '/' '*' * File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME) #=> false * File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true * * pattern = '**' '/' 'foo' * File.fnmatch(pattern, 'a/b/c/foo', File::FNM_PATHNAME) #=> true * File.fnmatch(pattern, '/a/b/c/foo', File::FNM_PATHNAME) #=> true * File.fnmatch(pattern, 'c:/a/b/c/foo', File::FNM_PATHNAME) #=> true * File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME) #=> false * File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true */ static VALUE file_s_fnmatch(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE pattern, path; VALUE rflags; int flags; if (rb_scan_args(argc, argv, "21", &pattern, &path, &rflags) == 3) flags = NUM2INT(rflags); else flags = 0; StringValue(pattern); StringValue(path); if (fnmatch(RSTRING(pattern)->ptr, RSTRING(path)->ptr, flags) == 0) return Qtrue; return Qfalse; } /* * Objects of class Dir are directory streams representing * directories in the underlying file system. They provide a variety of * ways to list directories and their contents. See also * File. * * The directory used in these examples contains the two regular files * (config.h and main.rb), the parent * directory (..), and the directory itself * (.). */ void Init_Dir() { rb_cDir = rb_define_class("Dir", rb_cObject); rb_include_module(rb_cDir, rb_mEnumerable); rb_define_alloc_func(rb_cDir, dir_s_alloc); rb_define_singleton_method(rb_cDir, "open", dir_s_open, 1); rb_define_singleton_method(rb_cDir, "foreach", dir_foreach, 1); rb_define_singleton_method(rb_cDir, "entries", dir_entries, 1); rb_define_method(rb_cDir,"initialize", dir_initialize, 1); rb_define_method(rb_cDir,"path", dir_path, 0); rb_define_method(rb_cDir,"inspect", dir_inspect, 0); rb_define_method(rb_cDir,"read", dir_read, 0); rb_define_method(rb_cDir,"each", dir_each, 0); rb_define_method(rb_cDir,"rewind", dir_rewind, 0); rb_define_method(rb_cDir,"tell", dir_tell, 0); rb_define_method(rb_cDir,"seek", dir_seek, 1); rb_define_method(rb_cDir,"pos", dir_tell, 0); rb_define_method(rb_cDir,"pos=", dir_set_pos, 1); rb_define_method(rb_cDir,"close", dir_close, 0); rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1); rb_define_singleton_method(rb_cDir,"getwd", dir_s_getwd, 0); rb_define_singleton_method(rb_cDir,"pwd", dir_s_getwd, 0); rb_define_singleton_method(rb_cDir,"chroot", dir_s_chroot, 1); rb_define_singleton_method(rb_cDir,"mkdir", dir_s_mkdir, -1); rb_define_singleton_method(rb_cDir,"rmdir", dir_s_rmdir, 1); rb_define_singleton_method(rb_cDir,"delete", dir_s_rmdir, 1); rb_define_singleton_method(rb_cDir,"unlink", dir_s_rmdir, 1); rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, -1); rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, -1); rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1); rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1); rb_file_const("FNM_NOESCAPE", INT2FIX(FNM_NOESCAPE)); rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME)); rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH)); rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD)); rb_file_const("FNM_SYSCASE", INT2FIX(FNM_SYSCASE)); } ================================================ FILE: distro/debian/compat ================================================ 5 ================================================ FILE: distro/debian/control ================================================ Package: ruby-enterprise Version: <%= VENDOR_RUBY_VERSION %>-<%= REE_VERSION %> Section: interpreters Priority: optional Architecture: <%= arch %> Essential: no Depends: libc6 (>= 2.6.1-1) Maintainer: Hongli Lai Installed-Size: <%= installed_size %> Description: Ruby Enterprise Edition. ================================================ FILE: distro/debian/postinst ================================================ #!/bin/sh ================================================ FILE: distro/debian/prerm ================================================ #!/bin/sh ================================================ FILE: distro/dependencies.rb ================================================ require "#{File.dirname(__FILE__)}/platform_info" module RubyEnterpriseEdition # Represents a dependency software that Ruby Enterprise Edition requires. It's used by the # installer to check whether all dependencies are available. A Dependency object # contains full information about a dependency, such as its name, code for # detecting whether it is installed, and installation instructions for the # current platform. class Dependency # :nodoc: all [:name, :install_command, :install_instructions, :install_comments, :website, :website_comments, :provides].each do |attr_name| attr_writer attr_name define_method(attr_name) do call_init_block return instance_variable_get("@#{attr_name}") end end def initialize(&block) @included_by = [] @init_block = block end def define_checker(&block) @checker = block end def check call_init_block result = Result.new @checker.call(result) return result end private class Result def found(filename_or_boolean = nil) if filename_or_boolean.nil? @found = true else @found = filename_or_boolean end end def not_found found(false) end def found? return !@found.nil? && @found end def found_at if @found.is_a?(TrueClass) || @found.is_a?(FalseClass) return nil else return @found end end end def call_init_block if @init_block init_block = @init_block @init_block = nil init_block.call(self) end end end # Namespace which contains the different dependencies that Ruby Enterprise Edition may require. # See Dependency for more information. module Dependencies # :nodoc: all include PlatformInfo CC = Dependency.new do |dep| dep.name = "C compiler" dep.define_checker do |result| if PlatformInfo::CC.nil? result.not_found else result.found(PlatformInfo::CC) end end if RUBY_PLATFORM =~ /linux/ case LINUX_DISTRO when :ubuntu, :debian dep.install_command = "apt-get install build-essential" when :rhel, :fedora, :centos dep.install_command = "yum install gcc-c++" when :gentoo dep.install_command = "emerge -av gcc" end elsif RUBY_PLATFORM =~ /darwin/ dep.install_instructions = "Please install the Apple Development Tools: http://developer.apple.com/tools/" end dep.website = "http://gcc.gnu.org/" end CXX = Dependency.new do |dep| dep.name = "C++ compiler" dep.define_checker do |result| if PlatformInfo::CXX.nil? result.not_found else result.found(PlatformInfo::CXX) end end if RUBY_PLATFORM =~ /linux/ case LINUX_DISTRO when :ubuntu, :debian dep.install_command = "apt-get install build-essential" when :rhel, :fedora, :centos dep.install_command = "yum install gcc-c++" when :gentoo dep.install_command = "emerge -av gcc" end elsif RUBY_PLATFORM =~ /darwin/ dep.install_instructions = "Please install the Apple Development Tools: http://developer.apple.com/tools/" end dep.website = "http://gcc.gnu.org/" end Make = Dependency.new do |dep| dep.name = "The 'make' tool" dep.define_checker do |result| make = PlatformInfo.find_command('make') if make result.found(make) else result.not_found end end if RUBY_PLATFORM =~ /linux/ case LINUX_DISTRO when :ubuntu, :debian dep.install_command = "apt-get install build-essential" when :rhel, :fedora, :centos dep.install_command = "yum install make" end elsif RUBY_PLATFORM =~ /darwin/ dep.install_instructions = "Please install the Apple Development Tools: http://developer.apple.com/tools/" end dep.website = "http://www.gnu.org/software/make/" end Patch = Dependency.new do |dep| dep.name = "The 'patch' tool" dep.define_checker do |result| patch = PlatformInfo.find_command('patch') if patch result.found(patch) else result.not_found end end if RUBY_PLATFORM =~ /linux/ case LINUX_DISTRO when :ubuntu, :debian dep.install_command = "apt-get install patch" when :rhel, :fedora, :centos dep.install_command = "yum install patch" end end dep.website = "http://www.gnu.org/software/diffutils/" end Zlib_Dev = Dependency.new do |dep| dep.name = "Zlib development headers" dep.define_checker do |result| begin File.open('/tmp/r8ee-check.c', 'w') do |f| f.write("#include ") end Dir.chdir('/tmp') do if system("(#{PlatformInfo::CC || 'gcc'} #{ENV['CFLAGS']} -c r8ee-check.c) >/dev/null 2>/dev/null") result.found else result.not_found end end ensure File.unlink('/tmp/r8ee-check.c') rescue nil File.unlink('/tmp/r8ee-check.o') rescue nil end end if RUBY_PLATFORM =~ /linux/ case LINUX_DISTRO when :ubuntu, :debian dep.install_command = "apt-get install zlib1g-dev" when :rhel, :fedora, :centos dep.install_command = "yum install zlib-devel" end end dep.website = "http://www.zlib.net/" end OpenSSL_Dev = Dependency.new do |dep| dep.name = "OpenSSL development headers" dep.define_checker do |result| begin File.open('/tmp/r8ee-check.c', 'w') do |f| f.write("#include ") end Dir.chdir('/tmp') do if system("(#{PlatformInfo::CC || 'gcc'} #{ENV['CFLAGS']} -c r8ee-check.c) >/dev/null 2>/dev/null") result.found else result.not_found end end ensure File.unlink('/tmp/r8ee-check.c') rescue nil File.unlink('/tmp/r8ee-check.o') rescue nil end end if RUBY_PLATFORM =~ /linux/ case LINUX_DISTRO when :ubuntu, :debian dep.install_command = "apt-get install libssl-dev" when :rhel, :fedora, :centos dep.install_command = "yum install openssl-devel" end end dep.website = "http://www.openssl.org/" end Readline_Dev = Dependency.new do |dep| dep.name = "GNU Readline development headers" dep.define_checker do |result| begin File.open('/tmp/r8ee-check.c', 'w') do |f| # readline.h doesn't work on OS X unless we #include stdio.h f.puts("#include ") f.puts("#include ") end Dir.chdir('/tmp') do if system("(#{PlatformInfo::CC || 'gcc'} #{ENV['CFLAGS']} -c r8ee-check.c) >/dev/null 2>/dev/null") result.found else result.not_found end end ensure File.unlink('/tmp/r8ee-check.c') rescue nil File.unlink('/tmp/r8ee-check.o') rescue nil end end if RUBY_PLATFORM =~ /linux/ case LINUX_DISTRO when :ubuntu, :debian dep.install_command = "apt-get install libreadline5-dev" when :rhel, :fedora, :centos dep.install_command = "yum install readline-devel" end end dep.website = "http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html" end end end # module RubyEnterpriseEdition ================================================ FILE: distro/documentation.txt ================================================ = Ruby Enterprise Edition Features Guide == Overview of Ruby Enterprise Edition (REE) Ruby Enterprise Edition (REE) is a server-oriented distribution of the official Ruby interpreter, and includes various additional enhancements: - A copy-on-write friendly garbage collector. Phusion Passenger uses this, in combination with a technique called preforking, to reduce Ruby on Rails applications' memory usage by 33% on average. - An improved memory allocator called tcmalloc, which improves performance quite a bit. - The ability to tweak garbage collector settings for maximum server performance. - The ability to inspect the garbage collector's state and the object heap state, for debugging purposes. - The ability to obtain backtraces for all running threads, making it easier for one to debug multithreaded applications. - Thread scheduler bug fixes and performance improvements. Threading on Ruby Enterprise Edition can be more than 10 times faster than official Ruby 1.8. - Various memory management tweaks so that the Ruby interpreter uses less memory on average, even when copy-on-write is not utilized. Some of these features are gathered from third party Ruby patches: link:http://railsbench.rubyforge.org/[RailsBench], http://rubyforge.org/tracker/download.php/426/1700/11497/2087/ruby-track-alloc.patch[Sylvain Joyeux's object allocation patch], link:http://ph7spot.com/articles/caller_for_all_threads[caller_for_all_threads], Darryl Gove's and Miriam Blatt's link:http://blogs.sun.com/d/entry/ruby_performance_gains_on_sparc[Sparc optimization patches], Joe Damato's and Aman Gupta's http://timetobleed.com/fixing-threads-in-ruby-18-a-2-10x-performance-boost/[zero-copy context switching patch], Brent Roman's http://sites.google.com/site/brentsrubypatches[MBARI patch set]. == Installation and uninstallation === Installation via Debian package or source tarball To install REE, download either the source tarball or the Debian package from the REE website. The source tarball contains a cross-platform installer. Installation instructions are available on the download page. Note that this installer is written in Ruby, and thus requires a Ruby interpreter to run. Because not all systems come with a Ruby interpreter by default, the source tarball also contains a number of precompiled Ruby interpreters for various platforms, with the purpose of running the installer. The `installer` script will automatically use a precompiled Ruby binary for the current platform, if available. Precompiled Ruby interpreters for the following platforms are included: - x86 Linux - x86_64 Linux - x86 FreeBSD 6 - Solaris MacOS X and most FreeBSD systems already come with a Ruby interpreter by default. So if you notice that the installer fails to start, please install Ruby first, then re-run the installer. WARNING: It is not recommended to install REE into '/usr' because it can overwrite your existing Ruby installation in a way that the system doesn't expect. You should install REE into an isolated place such as '/opt'. ==== Installation options ===== Disabling tcmalloc If you experience problems with the tcmalloc memory allocator, then you can install REE without tcmalloc by passing `--no-tcmalloc` to the installer. ===== Non-interactive installation You can install REE non-interactively either by using the Debian package, or by passing `--auto=DIRECTORY` to the REE installer. The latter will instruct the installer to non-interactively install REE into the specified target directory. ===== More options You can read about all of the available installation options by passing `--help` to the REE installer. === Manual installation (for experts) If you wish to install REE from source, but do not wish to use the included installer, or if the installer doesn't work, then you can install REE manually. Please follow the instructions below. Note that these instructions do not cover installing RubyGems. ==== Prerequisites You need to have the following dependencies installed: 1. A C and C++ compiler, preferrably gcc. 2. The 'make' tool. 3. The 'patch' tool. 4. C development headers for zlib. 5. C development headers for OpenSSL. 6. C development headers for GNU Readline. 7. yacc or bison. ==== Step 1: Download and extract the source tarball Type: -------------------------- tar xzvf ruby-enterprise-x.x.x.tar.gz -------------------------- A directory called 'ruby-enterprise-x.x.x' will now appear. ==== Step 2: Decide the prefix you want to install REE to Please decide on a prefix to install REE to, and put this directory name into the `PREFIX` environment variable. We'll need this value later in these instructions. For example, if you want to install REE into /opt/ruby-enterprise, then run: ------------------------------------- PREFIX=/opt/ruby-enterprise ------------------------------------- Please note that the rest of this document assumes that REE is installed into '/opt/ruby-enterprise'. If you installed REE into a different directory then just replace '/opt/ruby-enterprise' with whatever the real prefix is. ==== Step 3: Apply or unapply the (experimental) fast threading patch The fast threading patch potentially improves Ruby threading performance, but it's experimental at this time. By default, the patch is applied on the source code provided in the tarball; the installer however does not install fast threading by default by reverse-patching the source code. If you want to install REE with the fast threading patch, then you can continue to step 4. If you do not want to install with the fast threading patch, then you must first reverse-patch the source code as follows: ------------------------------ cd ruby-enterprise-x.x.x/source patch -p1 -R < ../fast-threading.patch cd ../.. ------------------------------ Please note that the fast threading patch only works on x86 and x86_64. On other architectures it will result in a compilation failure. ==== Step 4: Install tcmalloc Tcmalloc is a memory allocator which is usually more efficient than the platform's native memory allocator. REE doesn't require tcmalloc, but it will work better if tcmalloc is installed. Compile tcmalloc as follows: -------------------------- cd ruby-enterprise-x.x.x/source/distro/google-perftools-* ./configure --prefix=$PREFIX --disable-dependency-tracking make libtcmalloc_minimal.la -------------------------- If compilation fails, then skip to step 5. REE will work fine without tcmalloc. After compilation, install tcmalloc as follows: -------------------------- sudo mkdir -p $PREFIX/lib sudo rm -f $PREFIX/lib/libtcmalloc_minimal*.so* sudo cp -Rpf .libs/libtcmalloc_minimal*.so* $PREFIX/lib/ -------------------------- .MacOS X note NOTE: Instead of typing 'libtcmalloc_minimal*.so*', type 'libtcmalloc_minimal*.bundle*'. NOTE: The reason why we don't instruct you to type 'make' and 'make install' is because compiling tcmalloc with 'make' usually doesn't work on 64-bit platforms. The above instructions are a little bit more complex, but they work on all platforms where tcmalloc is supported. ==== Step 5: Configure REE Change the current working directory to 'ruby-enterprise-x.x.x/source'. If you were previously in the google-perftools directory, then type: -------------------------- cd ../.. -------------------------- Run the configure script: -------------------------- ./configure --prefix=$PREFIX --enable-mbari-api CFLAGS='-g -O2' -------------------------- ==== Step 6: Compiling and installing the system_allocator library (MacOS X only) If you are on MacOS X, then compile and install the 'system_allocator' library: -------------------------- gcc -dynamiclib system_allocator.c -install_name @rpath/libsystem_allocator.dylib -o libsystem_allocator.dylib sudo install libsystem_allocator.dylib $PREFIX/lib/ -------------------------- ==== Step 7: compiling and installing REE Open 'Makefile'. Search for a line which starts with: -------------------------- LIBS = -------------------------- Append the string '$(PRELIBS)' to the part after the '=' sign. For example, on Ubuntu 8.04, the 'LIBS = ' line becomes: -------------------------- LIBS = $(PRELIBS) -ldl -lcrypt -lm $(EXTLIBS) -------------------------- Save the file. Now we can proceed with compiling REE: -------------------------- make PRELIBS="-Wl,-rpath,$PREFIX/lib -L$PREFIX/lib -ltcmalloc_minimal" -------------------------- Notes: - If you did not install tcmalloc, then you can omit the '-ltcmalloc_minimal' part. - If you are on MacOS X, then you need to append '-lsystem_allocator' to the 'PRELIBS' option. - If you are on FreeBSD, then you need to append '-lpthread' to the 'PRELIBS' option. Now that REE has been compiled, install it with: -------------------------- sudo make install -------------------------- === RubyCocoa compatibility and `--enable-shared` In order to use RubyCocoa, the Ruby interpreter must be compiled with `--enable-shared`. By default, Ruby Enterprise Edition's interpreter is not compiled with `--enable-shared`. You can compile the Ruby Enterprise Edition interpreter with this flag by passing `-c --enable-shared` to its installer, like this: --------------------------------------------------------- ./ruby-enterprise-X.X.X/installer -c --enable-shared --------------------------------------------------------- Please note that enabling `--enable-shared` will make the Ruby interpreter about 20% slower. It is for this reason that we don't recommend enabling `--enable-shared` on server environments, although it's fine for desktop environments. === Tcl/Tk compatibility and `--enable-pthread` In order to use Tcl/Tk with threading support, the Ruby interpreter must be compiled with `--enable-pthread`. By default, Ruby Enterprise Edition's interpreter is not compiled with `--enable-pthread`. You can compile the Ruby Enterprise Edition interpreter with this flag by passing `-c --enable-pthread` to its installer, like this: --------------------------------------------------------- ./ruby-enterprise-X.X.X/installer -c --enable-pthread --------------------------------------------------------- Please note that enabling `--enable-pthread` will make the Ruby interpreter about 50% slower. It is for this reason that we don't recommend enabling `--enable-shared` on server environments, although it's fine for desktop environments. === How REE installs itself into the system By default, REE installs itself into a directory in '/opt'. If you already had a Ruby interpreter installed (typically in '/usr'; let's call this 'the system Ruby interpreter'), then REE will have no effect on it: REE lives in isolation and in parallel to the system Ruby interpreter. This also means that: - If you have any software which depends on the system Ruby interpreter, then that software will not break. It will continue to work like before. - REE has its own set of Ruby libraries, and its own set of gems and its own set of commands. If you install a new gem using the system Ruby interpreter, then that gem will not show up in REE's gem list, and vice versa. - When running Ruby programs, the system Ruby interpreter will be used unless you explicitly configure the system to use REE by default. ==== Why doesn't REE use the system Ruby interpreter's gems? REE does not use the system Ruby interpreter's gems because it can cause problems with native extensions, e.g. RMagick, Mongrel, Hpricot, etc. A native extension compiled for one Ruby installation might crash when used in a different Ruby installation. This is why you must reinstall your gems in REE. === Upgrading To upgrade REE through the Debian package, just install the Debian package. To upgrade REE through the source tarball, run the installer in the source tarball and specify the same destination prefix directory that REE is currently installed in. For example, if REE is currently installed in '/opt/ruby-enterprise-20081215', then specify '/opt/ruby-enterprise-20081215' in the upgrade source tarball's installer. === Uninstallation If you installed REE through a Debian package, then uninstall the Debian package with 'dpkg' or with 'apt-get'. If you installed REE through the source tarball, then you can uninstall it by deleting the directory in which REE is installed. For example, if REE was installed to '/opt/ruby-enterprise-X.X.X' (the default), then just delete that directory. It is for this reason why we recommend installing REE into its own directory. == Using Ruby Enterprise Edition === General usage Normally one would run a Ruby program by invoking the Ruby interpreter with a source file as its first argument: -------------------------- $ ruby some_program.rb -------------------------- To run the same program in REE, invoke the equivalent command in REE's 'bin' folder: -------------------------------------------------------- $ /opt/ruby-enterprise-X.X.X/bin/ruby some_program.rb -------------------------------------------------------- The same applies to other Ruby commands such as 'gem', 'irb' and 'rake'. For example, if you want to install Ruby on Rails for REE, invoke: -------------------------------------------------------- $ /opt/ruby-enterprise-X.X.X/bin/gem install rails -------------------------------------------------------- === Using REE with Phusion Passenger To use REE in combination with Phusion Passenger, you must run the Passenger Apache 2 module installer that's associated with REE. The REE installer installs the Passenger gem by default, so you just have to run the Passenger Apache 2 module installer: ------------------------------------------------- /opt/ruby-enterprise-X.X.X/bin/passenger-install-apache2-module ------------------------------------------------- Then follow the instructions that the installer gives you. === Configuring REE as the default Ruby interpreter It is possible to configure REE as the default Ruby interpreter, so that when you type 'ruby', 'gem', 'irb', 'rake' or other Ruby commands, REE's version is invoked instead of the system Ruby's version. To do this, you must add REE's 'bin' directory to the beginning of the `PATH` environment variable. This environment variable specifies the command shell's command search path. For example, you can do this on the command-line: ------------------------------------- $ ruby some_program.rb # <--- some_program.rb is being run # in the system Ruby interpreter. $ export PATH=/opt/ruby-enterprise-X.X.X/bin:$PATH $ ruby some_program.rb # <--- some_program.rb will now be run in REE! ------------------------------------- Invoking `export PATH=...` on the command-line has no permanent effect: its effects disappear as soon as you exit the shell. To make the effect permanent, add an entry to the file `/etc/environment` instead. On Ubuntu Linux, `/etc/environment` looks like this: ------------------------------------- PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games" LANG="en_US.UTF-8" LANGUAGE="en_US:en" ------------------------------------- Add REE's 'bin' directory to the PATH environment variable, like this: ------------------------------------- PATH="/opt/ruby-enterprise-x.x.x/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games" LANG="en_US.UTF-8" LANGUAGE="en_US:en" ------------------------------------- == Garbage collector and object space === Copy-on-write friendliness By default, REE's garbage collector is not copy-on-write-friendly, just like a stock Ruby interpreter. Copy-on-write-friendliness can be turned on during runtime by calling: [source, ruby] ----------------------------------------------- GC.copy_on_write_friendly = true ----------------------------------------------- Note that Phusion Passenger automatically turns on the copy-on-write-friendly mode whenever it detects that it's running in REE. With the following method, one can check whether the garbage collector is in copy-on-write-friendly mode: [source, ruby] ----------------------------------------------- GC.copy_on_write_friendly? ----------------------------------------------- === Garbage collector performance tuning Ruby's garbage collector tries to adapt memory usage to the amount of memory used by the program by dynamically growing or shrinking the allocated heap as it sees fit. For long running server applications, this approach isn't always the most efficient one. The performance very much depends on the ratio `heap_size / program_size`. It behaves somewhat erratic: adding code can actually make your program run faster. With REE, one can tune the garbage collector's behavior for better server performance. It is possible to specify the initial heap size to start with. The heap size will never drop below the initial size. By carefully selecting the initial heap size one can decrease startup time and increase throughput of server applications. Garbage collector behavior is controlled through the following environment variables. These environment variables must be set prior to invoking the Ruby interpreter. *`RUBY_HEAP_MIN_SLOTS`*:: This specifies the initial number of heap slots. The default is '10000'. *`RUBY_HEAP_SLOTS_INCREMENT`*:: The number of additional heap slots to allocate when Ruby needs to allocate new heap slots for the first time. The default is '10000'. + For example, suppose that the default GC settings are in effect, and 10000 Ruby objects exist on the heap (= 10000 used heap slots). When the program creates another object, Ruby will allocate a new heap with 10000 heap slots in it. There are now 20000 heap slots in total, of which 10001 are used and 9999 are unused. *`RUBY_HEAP_SLOTS_GROWTH_FACTOR`*:: Multiplicator used for calculating the number of new heaps slots to allocate next time Ruby needs new heap slots. The default is '1.8'. + Take the program in the last example. Suppose that the program creates 10000 more objects. Upon creating the 10000th object, Ruby needs to allocate another heap. This heap will have `10000 * 1.8 = 18000` heap slots. There are now `20000 + 18000 = 38000` heap slots in total, of which 20001 are used and 17999 are unused. + The next time Ruby needs to allocate a new heap, that heap will have `18000 * 1.8 = 32400` heap slots. *`RUBY_GC_MALLOC_LIMIT`*:: The amount of C data structures which can be allocated without triggering a garbage collection. If this is set too low, then the garbage collector will be started even if there are empty heap slots available. The default value is '8000000'. *`RUBY_HEAP_FREE_MIN`*:: The number of heap slots that should be available after a garbage collector run. If fewer heap slots are available, then Ruby will allocate a new heap according to the `RUBY_HEAP_SLOTS_INCREMENT` and `RUBY_HEAP_SLOTS_GROWTH_FACTOR` parameters. The default value is '4096'. The best settings varies from application to application. You should try experimenting with the values. link:http://www.37signals.com[37signals] uses the following settings in production: ---------------------------------- RUBY_HEAP_MIN_SLOTS=600000 RUBY_GC_MALLOC_LIMIT=59000000 RUBY_HEAP_FREE_MIN=100000 ---------------------------------- link:http://www.twitter.com[Twitter] uses the following settings in production: ---------------------------------- RUBY_HEAP_MIN_SLOTS=500000 RUBY_HEAP_SLOTS_INCREMENT=250000 RUBY_HEAP_SLOTS_GROWTH_FACTOR=1 RUBY_GC_MALLOC_LIMIT=50000000 ---------------------------------- Twitter's settings mean: * Start with enough memory to hold the application (Ruby's default is very low, lower than what a Rails application typically needs). * Increase it linearly if you need more (Ruby's default is exponential increase). * Only garbage-collect every 50 million `malloc` calls (Ruby's default is 6x smaller). Twitter link:http://blog.evanweaver.com/articles/2009/04/09/ruby-gc-tuning/[claims] that these settings give them about 20% to 40% average performance improvement, at the cost of slightly higher peak memory usage. === Garbage collector statistics One can inspect various garbage collector statistics by calling certain methods. Statistics collection is disabled by default, so before one can obtain the statistics, statistics collection must be enabled by calling: [source,ruby] -------------------------- GC.enable_stats -------------------------- There's a very minor performance penalty when statistics collection is enabled. Statistics collection can be disabled by calling: [source,ruby] -------------------------- GC.disable_stats -------------------------- The following methods are available for obtaining the collected statistics information: *`GC.collections`*:: Returns the number of garbage collections that have been performed since GC statistics collection was enabled. + [source, ruby] ---------------------------- GC.enable_stats do_something GC.collections # => 20 ---------------------------- *`GC.time`*:: Returns the total amount of time that has been spent on garbage collection since GC statistics collection was enabled, in microseconds. + [source, ruby] ---------------------------- GC.enable_stats do_something GC.time # => 3000000 ---------------------------- *`GC.growth`*:: Returns the number of bytes that have been allocated since the last garbage collection run. *`GC.dump`*:: Dumps information about the current GC data structures to the GC log file, to `stderr` if no GC log file is specified. One can specify the GC log file in the `RUBY_GC_DATA_FILE` environment variable, which must be set before starting the Ruby interpreter. + At this moment, the only thing that this method does is printing the size of each Ruby heap. The collected statistics information can be cleared by calling: [source,ruby] -------------------------- GC.clear_stats -------------------------- === Memory allocation and object heap statistics One can obtain various statistics about object allocation. Some of the statistics methods listed here require one to explicitly enable statistics collection, just like the garbage collection statistics methods. The following methods are available: *`GC.allocated_size`*:: Returns the amount of memory (in bytes) that has been allocated since GC statistics collection was enabled. This is the total amount of bytes that has been passed to the C function `ruby_xmalloc()` so far. + [source, ruby] -------------------------------- GC.allocated_size #=> 4070 -------------------------------- *`GC.num_allocations`*:: Returns the number of memory allocation requests that have been performed since GC statistics collection was enabled. This is the number of times that the C function `ruby_xmalloc()` has been called. + [source, ruby] -------------------------------- GC.num_allocations #=> 4070 -------------------------------- *`ObjectSpace.live_objects`*:: Returns the number of objects that are currently allocated in the system. This value usually goes down after the garbage collector runs. This method does not require one to enable statistics collection. + [source, ruby] -------------------------------- ObjectSpace.live_objects #=> 30873 -------------------------------- *`ObjectSpace.allocated_objects`*:: Returns the number of objects that have been allocated since the Ruby interpreter started. This number can only increase. To know how many objects are currently allocated, use `ObjectSpace.live_objects` instead. + [source, ruby] -------------------------------- ObjectSpace.allocated_objects #=> 33266 -------------------------------- == Obtaining the backtrace of all threads The method `caller_for_all_threads` returns a Hash which maps each currently running thread to the thread's backtrace. A backtrace is an array of strings, in the same format as the return value of the method `caller`. For example, consider the following program `test.rb`: [source, ruby] --------------------------------- require 'thread' require 'pp' def foo bar end def bar sleep 10 end thread1 = Thread.new do foo end thread2 = Thread.new do STDIN.readline end # Give other threads some chance to run. sleep 0.1 pp caller_for_all_threads --------------------------------- This program will print: --------------------------------- {#=> ["test.rb:9:in `bar'", "test.rb:5:in `foo'", "test.rb:13", "test.rb:12:in `initialize'", "test.rb:12:in `new'", "test.rb:12"], #=>["test.rb:23"], #=> ["test.rb:17", "test.rb:16:in `initialize'", "test.rb:16:in `new'", "test.rb:16"]} --------------------------------- === Phusion Passenger integration `caller_for_all_threads` support is integrated into Phusion Passenger version 2.1 (which at the time of writing hasn't been released yet). Upon sending a 'SIGQUIT' signal to a Phusion Passenger backend process, it will print the backtrace of all threads to the Apache error log. This feature is also documented in the Phusion Passenger users guide. == Obtaining the source filename and line of arbitrary methods and blocks All Method and Proc objects provide the `__file__` and `__line__` methods for obtaining the source filename and line on which said method or proc was defined. This is extremely useful for debugging applications or frameworks that rely on heavily on meta-programming. For example, consider a Ruby on Rails application which has a User model. The `users` database table has a `username` field, so ActiveRecord automatically generates a `username` method for the User class. By calling `__file__` and `__line__` one can see where in the ActiveRecord source code the method is defined: ------------------------------- >> method = User.new.method(:username) => # >> method.__file__ => "/opt/ruby-enterprise/lib/ruby/gems/1.8/gems/activerecord-2.3.2/lib/active_record/attribute_methods.rb" >> method.__line__ => 211 ------------------------------- A simpler example that doesn't involve Ruby on Rails: [source, ruby] ------------------------------- # foo.rb class Foo def foo end end foo = Foo.new method = foo.method(:foo) method.__file__ # => foo.rb method.__line__ # => 4 ------------------------------- ================================================ FILE: distro/google-perftools-1.7/AUTHORS ================================================ opensource@google.com ================================================ FILE: distro/google-perftools-1.7/COPYING ================================================ Copyright (c) 2005, Google Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: distro/google-perftools-1.7/ChangeLog ================================================ Fri Feb 04 15:54:31 2011 Google Inc. * google-perftools: version 1.7 release * Reduce page map key size under x86_64 by 4.4MB (rus) * Remove a flaky malloc-extension test (fdabek) * Improve the performance of PageHeap::New (ond..., csilvers) * Improve sampling_test with no-inline additions/etc (fdabek) * 16-byte align debug allocs (jyasskin) * Change FillProcSelfMaps to detect out-of-buffer-space (csilvers) * Document the need for sampling to use GetHeapSample (csilvers) * Try to read TSC frequency from tsc_freq_khs (adurbin) * Do better at figuring out if tests are running under gdb (ppluzhnikov) * Improve spinlock contention performance (ruemmler) * Better internal-function list for pprof's /contention (ruemmler) * Speed up GoogleOnce (m3b) * Limit number of incoming/outgoing edges in pprof (sanjay) * Add pprof --evince to go along with --gv (csilvers) * Document the various ways to get heap-profiling information (csilvers) * Separate out synchronization profiling routines (ruemmler) * Improve malloc-stats output to be more understandable (csilvers) * Add support for census profiler in pporf (nabeelmian) * Document how pprof's /symbol must support GET requests (csilvers) * Improve acx_pthread.m4 (ssuomi, liujisi) * Speed up pprof's ExtractSymbols (csilvers) * Ignore some known-leaky (java) libraries in the heap checker (davidyu) * Make kHideMask use all 64 bits in tests (ppluzhnikov) * Clean up pprof input-file handling (csilvers) * BUGFIX: Don't crash if __environ is NULL (csilvers) * BUGFIX: Fix totally broken debugallocation tests (csilvers) * BUGFIX: Fix up fake_VDSO handling for unittest (ppluzhnikov) * BUGFIX: Suppress all large allocs when report threshold is 0 (lexie) * BUGFIX: mmap2 on i386 takes an off_t, not off64_t (csilvers) * PORTING: Add missing PERFTOOLS_DLL_DECL (csilvers) * PORTING: Add stddef.h to make newer gcc's happy (csilvers) * PORTING: Document some tricks for working under OS X (csilvers) * PORTING: Don't try to check valgrind for windows (csilvers) * PORTING: Make array-size a var to compile under clang (chandlerc) * PORTING: No longer hook _aligned_malloc and _aligned_free (csilvers) * PORTING: Quiet some gcc warnings (csilvers) * PORTING: Replace %PRIxPTR with %p to be more portable (csilvers) * PORTING: Support systems that capitalize /proc weirdly (sanek) * PORTING: Treat arm3 the same as arm5t in cycletimer (csilvers) * PORTING: Update windows logging to not allocate memory (csilvers) * PORTING: avoid double-patching newer windows DLLs (roger.orr) * PORTING: get dynamic_annotations.c to work on windows (csilvers) * Add pkg-config .pc files for the 5 libraries we produce (csilvers) * Added proper libtool versioning, so this lib will be 0.1.0 (csilvers) * Moved from autoconf 2.64 to 2.65 Thu Aug 5 12:48:03 PDT 2010 Google Inc. * google-perftools: version 1.6 release * Add tc_malloc_usable_size for compatibility with glibc (csilvers) * Override malloc_usable_size with tc_malloc_usable_size (csilvers) * Default to no automatic heap sampling in tcmalloc (csilvers) * Add -DTCMALLOC_LARGE_PAGES, a possibly faster tcmalloc (rus) * Make some functions extern "C" to avoid false ODR warnings (jyasskin) * pprof: Add SVG-based output (rsc) * pprof: Extend pprof --tools to allow per-tool configs (csilvers) * pprof: Improve support of 64-bit and big-endian profiles (csilvers) * pprof: Add interactive callgrind suport (weidenri...) * pprof: Improve address->function mapping a bit (dpeng) * Better detection of when we're running under valgrind (csilvers) * Better CPU-speed detection under valgrind (saito) * Use, and recommend, -fno-builtin-malloc when compiling (csilvers) * Avoid false-sharing of memory between caches (bmaurer) * BUGFIX: Fix heap sampling to use correct alloc size (bmauer) * BUGFIX: Avoid gcc 4.0.x bug by making hook-clearing atomic (csilvers) * BUGFIX: Avoid gcc 4.5.x optimization bug (csilvers) * BUGFIX: Work around deps-determining bug in libtool 1.5.26 (csilvers) * BUGFIX: Fixed test to use HAVE_PTHREAD, not HAVE_PTHREADS (csilvers) * BUGFIX: Fix tls callback behavior on windows when using wpo (wtc) * BUGFIX: properly align allocation sizes on Windows (antonm) * BUGFIX: Fix prototypes for tcmalloc/debugalloc wrt throw() (csilvers) * DOC: Updated heap-checker doc to match reality better (fischman) * DOC: Document ProfilerFlush, ProfilerStartWithOptions (csilvers) * DOC: Update docs for heap-profiler functions (csilvers) * DOC: Clean up documentation around tcmalloc.slack_bytes (fikes) * DOC: Renamed README.windows to README_windows.txt (csilvers) * DOC: Update the NEWS file to be non-empty (csilvers) * PORTING: Fix windows addr2line and nm with proper rc code (csilvers) * PORTING: Add CycleClock and atomicops support for arm 5 (sanek) * PORTING: Improve PC finding on cygwin and redhat 7 (csilvers) * PORTING: speed up function-patching under windows (csilvers) Tue Jan 19 14:46:12 2010 Google Inc. * google-perftools: version 1.5 release * Add tc_set_new_mode (willchan) * Make memalign functions + realloc respect tc_set_new_mode (willchan) * Add ReleaseToSystem(num_bytes) (kash) * Handle zero-length symbols a bit better in pprof (csilvers) * Prefer __environ to /proc/self/environ in cpu profiler (csilvers) * Add HEAP_CHECK_MAX_LEAKS flag to control #leaks to report (glider) * Add two new numeric pageheap properties to MallocExtension (fikes) * Print alloc size when mmap fails (hakon) * Add ITIMER_REAL support to cpu profiler (csilvers, nabeelmian) * Speed up symbolizer in heap-checker reporting (glider) * Speed up futexes with FUTEX_PRIVATE_FLAG (m3b) * Speed up tcmalloc but doing better span coalescing (sanjay) * Better support for different wget's and addr2maps in pprof (csilvres) * Implement a nothrow version of delete and delete[] (csilvers) * BUGFIX: fix a race on module_libcs[i] in windows patching (csilvers) * BUGFIX: Fix debugallocation to call cpp_alloc for new (willchan) * BUGFIX: A simple bugfix for --raw mode (mrabkin) * BUGFIX: Fix C shims to actually be valid C (csilvers) * BUGFIX: Fix recursively-unmapped-region accounting (ppluzhnikov) * BUGFIX: better distinguish real and fake vdso (ppluzhnikov) * WINDOWS: replace debugmodule with more reliable psai (andrey) * PORTING: Add .bundle as another shared library extension (csilvers) * PORTING: Fixed a typo bug in the ocnfigure PRIxx m4 macro (csilvers) * PORTING: Augment sysinfo to work on 64-bit OS X (csilvers) * PORTING: Use sys/ucontext.h to fix compiing on OS X 10.6 (csilvers) * PORTING: Fix sysinfo libname reporting for solaris x86 (jeffrey) * PORTING: Use libunwind for i386 when using --omitfp (ppluzhnikov) Thu Sep 10 13:51:15 2009 Google Inc. * google-perftools: version 1.4 release * Add debugallocation library, to catch memory leaks, stomping, etc * Add --raw mode to allow for delayed processing of pprof files * Use less memory when reading CPU profiles * New environment variables to control kernel-allocs (sbrk, memfs, etc) * Add MarkThreadBusy(): performance improvement * Remove static thread-cache-size code; all is dynamic now * Add new HiddenPointer class to heap checker * BUGFIX: pvalloc(0) allocates now (found by new debugalloc library) * BUGFIX: valloc test (not implementation) no longer overruns memory * BUGFIX: GetHeapProfile no longer deadlocks * BUGFIX: Support unmapping memory regions before main * BUGFIX: Fix some malloc-stats formatting * BUGFIX: Don't crash as often when freeing libc-allocated memory * BUGFIX: Deal better with incorrect PPROF_PATH when symbolizing * BUGFIX: weaken new/delete/etc in addition to malloc/free/etc * BUGFIX: Fix return value of GetAllocatedSize * PORTING: Fix mmap-#define problem on some 64-bit systems * PORTING: Call ranlib again (some OS X versions need it) * PORTING: Fix a leak when building with LLVM * PORTING: Remove some unneeded bash-ishs from testing scripts * WINDOWS: Support library unloading as well as loading * WINDOWS/BUGFIX: Set page to 'xrw' instead of 'rw' when patching Tue Jun 9 18:19:06 2009 Google Inc. * google-perftools: version 1.3 release * Provide our own name for memory functions: tc_malloc, etc (csilvers) * Weaken memory-alloc functions so user can override them (csilvers) * Remove meaningless delete(nothrow) and delete[](nothrow) (csilvers) * BUILD: replace clever libtcmalloc/profiler.a with a new .a (csilvers) * PORTING: improve windows port by using google spinlocks (csilvers) * PORTING: Fix RedHat 9 memory allocation in heapchecker (csilvers) * PORTING: Rename OS_WINDOWS macro to PLATFORM_WINDOWS (mbelshe) * PORTING/BUGFIX: Make sure we don't clobber GetLastError (mbelshe) * BUGFIX: get rid of useless data for callgrind (weidenrinde) * BUGFIX: Modify windows patching to deadlock sometimes (csilvers) * BUGFIX: an improved fix for hook handling during fork (csilvers) * BUGFIX: revamp profiler_unittest.sh, which was very broken (csilvers) Fri Apr 17 16:40:48 2009 Google Inc. * google-perftools: version 1.2 release * Allow large_alloc_threshold=0 to turn it off entirely (csilvers) * Die more helpfully when out of memory for internal data (csilvers) * Refactor profile-data gathering, add a new unittest (cgd, nabeelmian) * BUGFIX: fix rounding errors with static thread-size caches (addi) * BUGFIX: disable hooks better when forking in leak-checker (csilvers) * BUGFIX: fix realloc of crt pointers on windows (csilvers) * BUGFIX: do a better job of finding binaries in .sh tests (csilvers) * WINDOWS: allow overriding malloc/etc instead of patching (mbelshe) * PORTING: fix compilation error in a ppc-specific file (csilvers) * PORTING: deal with quirks in cygwin's /proc/self/maps (csilvers) * PORTING: use 'A' version of functions for ascii input (mbelshe) * PORTING: generate .so's on cygwin and mingw (ajenjo) * PORTING: disable profiler methods on cygwin (jperkins) * Updated autoconf version to 2.61 and libtool version to 1.5.26 Wed Mar 11 11:25:34 2009 Google Inc. * google-perftools: version 1.1 release * Dynamically resize thread caches -- nice perf. improvement (kash) * Add VDSO support to give better stacktraces in linux (ppluzhnikov) * Improve heap-profiling sampling algorithm (ford) * Rewrite leak-checking code: should be faster and more robust (sanjay) * Use ps2 instead of ps for dot: better page cropping for gv (csilvers) * Disable malloc-failure warning messages by default (csilvers) * Update config/Makefile to disable tests on a per-OS basis (csilvers) * PORTING: Get perftools compiling under MSVC 7.1 again (csilvers) * PORTING: Get perftools compiling under cygwin again (csilvers) * PORTING: automatically set library flags for solaris x86 (csilvers) * Add TCMALLOC_SKIP_SBRK to mirror TCMALLOC_SKIP_MMAP (csilvers) * Add --enable flags to allow selective building (csilvers) * Put addr2line-pdb and nm-pdb in proper output directory (csilvers) * Remove deprecated DisableChecksIn (sanjay) * DOCUMENTATION: Document most MallocExtension routines (csilvers) Tue Jan 6 13:58:56 2009 Google Inc. * google-perftools: version 1.0 release * Exactly the same as 1.0rc2 Sun Dec 14 17:10:35 2008 Google Inc. * google-perftools: version 1.0rc2 release * Fix compile error on 64-bit systems (casting ptr to int) (csilvers) Thu Dec 11 16:01:32 2008 Google Inc. * google-perftools: version 1.0rc1 release * Replace API for selectively disabling heap-checker in code (sanjay) * Add a pre-mmap hook (daven, adlr) * Add MallocExtension interface to set memory-releasing rate (fikes) * Augment pprof to allow any string ending in /pprof/profile (csilvers) * PORTING: Rewrite -- and fix -- malloc patching for windows (dvitek) * PORTING: Add nm-pdb and addr2line-pdb for use by pprof (dvitek) * PORTING: Improve cygwin and mingw support (jperkins, csilvers) * PORTING: Fix pprof for mac os x, other pprof improvements (csilvers) * PORTING: Fix some PPC bugs in our locking code (anton.blanchard) * A new unittest, smapling_test, to verify tcmalloc-profiles (csilvers) * Turn off TLS for gcc < 4.1.2, due to a TLS + -fPIC bug (csilvers) * Prefer __builtin_frame_address to assembly for stacktraces (nlewycky) * Separate tcmalloc.cc out into multiple files -- finally! (kash) * Make our locking code work with -fPIC on 32-bit x86 (aruns) * Fix an initialization-ordering bug for tcmalloc/profiling (csilvers) * Use "initial exec" model of TLS to speed up tcmalloc (csilvers) * Enforce 16-byte alignment for tcmalloc, for SSE (sanjay) Tue Sep 23 08:56:31 2008 Google Inc. * google-perftools: version 0.99.2 release * COMPILE FIX: add #include needed for FreeBSD and OS X (csilvers) Sat Sep 20 09:37:18 2008 Google Inc. * google-perftools: version 0.99.1 release * BUG FIX: look for nm, etc in /usr/bin, not /usr/crosstool (csilvers) Thu Sep 18 16:00:27 2008 Google Inc. * google-perftools: version 0.99 release * Add IsHeapProfileRunning (csilvers) * Add C shims for some of the C++ header files (csilvers) * Fix heap profile file clean-up logic (maxim) * Rename linuxthreads.c to .cc for better compiler support (csilvers) * Add source info to disassembly in pprof (sanjay) * Use open instead of fopen to avoid memory alloc (csilvers) * Disable malloc extensions when running under valgrind (kcc) * BUG FIX: Fix out-of-bound error by reordering a check (larryz) * Add Options struct to ProfileData (cgd) * Correct PC-handling of --base in pprof (csilvers) * Handle 1 function occurring twice in an image (sanjay) * Improve stack-data cleaning (maxim) * Use 'struct Foo' to make header C compatible (csilvers) * Add 'total' line to pprof --text (csilvers) * Pre-allocate buffer for heap-profiler to avoid OOM errors (csilvers) * Allow a few more env-settings to control tcmalloc (csilvers) * Document some of the issues involving thread-local storage (csilvers) * BUG FIX: Define strtoll and friends for windows (csilvers) Mon Jun 9 16:47:03 2008 Google Inc. * google-perftools: version 0.98 release * Add ProfilerStartWithOptions() (cgd) * Change tcmalloc_minimal to not do any stack-tracing at all (csilvers) * Prefer mmap to sbrk for 64-buit debug mode (sanjay) * Fix accounting for some tcmalloc stats (sanjay) * Use setrlimit() to keep unittests from killing the machine (odo) * Fix a bug when sbrk-ing near address 4G (csilvers) * Make MallocHook thread-safe (jyasskin) * Fix windows build for MemoryBarrier (jyasskin) * Fix CPU-profiler docs to mention correct libs (csilvers) * Fix for GetHeapProfile() when heap-profiling is off (maxim) * Avoid realloc resizing ping-pongs using hysteresis (csilvers) * Add --callgrind output support to pprof (klimek) * Fix profiler.h and heap-profiler.h to be C-compatible (csilvers) * Break malloc_hook.h into two parts to reduce dependencies (csilvers) * Better handle systems that don't implement mmap (csilvers) * PORTING: disable system_alloc_unittest for msvc (csilvers) * PORTING: Makefile tweaks to build better on cygwin (csilvers) Mon Apr 21 15:20:52 2008 Google Inc. * google-perftools: version 0.97 release * Refactor GetHeapProfile to avoid using malloc (maxim) * Fix heap-checker and heap-profiler hook interactions (maxim) * Fix a data race in MemoryRegionMap::Lock (jyasskin) * Improve thread-safety of leak checker (maxim) * Fix mmap profile to no longer deadlock (maxim) * Fix rpm to have devel package depend on non-devel (csilvers) * PORTING: Fix clock-speed detection for Mac OS X (csilvers) Tue Mar 18 14:30:44 2008 Google Inc. * google-perftools: version 0.96 release * major atomicops rewrite; fixed atomic ops code for linux/ppc (vchen) * nix the stacktrace library; now build structure is simpler (csilvers) * Speed up heap-checker, and reduce extraneous logging (maxim) * Improve itimer code for NPTL case (cgd) * Add source code annotations for use by valgrind, etc (kcc) * PORTING: Fix high resolution timers for Mac OS X (adlr) Tue Feb 19 12:01:31 2008 Google Inc. * google-perftools: version 0.95.1 release (bugfix release) * x86_64 compile-fix: nix pread64 and pwrite64 (csilvers) * more heap-checker debug logging (maxim) * minor improvement to x86_64 CycleClock (gpike) Tue Feb 12 12:28:32 2008 Google Inc. * google-perftools: version 0.95 release * Better -- not perfect -- support for linux-ppc (csilvers) * Fix race condition in libunwind stacktrace (aruns) * Speed up x86 spinlock locking (m3b) * Improve heap-checker performance (maxim) * Heap checker traverses more ptrs inside heap-alloced objects (maxim) * Remove deprecated ProfilerThreadState function (cgd) * Update libunwind documentation for statically linked binaries (aruns) Mon Dec 3 23:51:54 2007 Google Inc. * google-perftools: version 0.94.1 release (bugfix release) * Fix missing #includes for x86_64 compile using libunwind (csilvers) Thu Nov 29 07:59:43 2007 Google Inc. * google-perftools: version 0.94 release * PORTING: MinGW/Msys support -- runs same code as MSVC does (csilvers) * PORTING: Add NumCPUs support for Mac OS X (csilvers) * Work around a sscanf bug in glibc(?) (waldemar) * Fix Windows MSVC bug triggered by thread deletion (csilvers) * Fix bug that triggers in MSVC /O2: missing volatile (gpike) * March-of-time support: quiet warnings/errors for gcc 4.2, OS X 10.5 * Modify pprof so it works without nm: useful for windows (csilvers) * pprof: Support filtering for CPU profiles (cgd) * Bugfix: have realloc report to hooks in all situations (maxim) * Speed improvement: replace slow memcpy with std::copy (soren) * Speed: better iterator efficiency in RecordRegionRemoval (soren) * Speed: minor speed improvements via better bitfield alignment (gpike) * Documentation: add documentation of binary profile output (cgd) Fri Aug 17 12:32:56 2007 Google Inc. * google-perftools: version 0.93 release * PORTING: everything compiles on Solaris, OS X, FreeBSD (see INSTALL) * PORTING: cpu-profiler works on most platforms (much better GetPC()) * PORTING: heap-profiler works on most platforms * PORTING: improved windows support, including release builds * No longer build or run ptmalloc tests by default * Add support for using memfs filesystem to allocate memory in linux * WINDOWS: give debug library and release library different names Tue Jul 17 22:26:27 2007 Google Inc. * google-perftools: version 0.92 release * PERFORMANCE: use a packed cache to speed up tcmalloc * PORTING: preliminary windows support! (see README.windows) * PORTING: better support for solaris, OS X, FreeBSD (see INSTALL) * Envvar support for running the heap-checker under gdb * Add weak declarations to maybe_threads to fix no-pthreads compile bugs * Some 64bit fixes, especially with pprof * Better heap-checker support for some low-level allocations * Fix bug where heap-profiles would sometimes get truncated * New documentation about how to handle common heap leak situations * Use computed includes for hash_map/set: easier config * Added all used .m4 templates to the distribution Wed Apr 18 16:43:55 2007 Google Inc. * google-perftools: version 0.91 release * Brown-paper-bag bugfix: compilation error on some x86-64 machines Fri Apr 13 14:50:51 2007 Google Inc. * google-perftools: version 0.90 release * (As the version-number jump hints, this is a major new release: almost every piece of functionality was rewritten. I can't do justice to all the changes, but will concentrate on highlights.) *** USER-VISIBLE CHANGES: * Ability to "release" unused memory added to tcmalloc * Exposed more tweaking knobs via environment variables (see docs) * pprof tries harder to map addresses to functions * tcmalloc_minimal compiles and runs on FreeBSD 6.0 and Solaris 10 *** INTERNAL CHANGES: * Much better 64-bit support * Better multiple-processor support (e.g. multicore contention tweaks) * Support for recent kernel ABI changes (e.g. new arg to mremap) * Addition of spinlocks to tcmalloc to reduce contention cost * Speed up tcmalloc by using __thread on systems that support TLS * Total redesign of heap-checker to improve liveness checking * More portable stack-frame analysis -- no more hard-coded constants! * Disentangled heap-profiler code and heap-checker code * Several new unittests to test, e.g., thread-contention costs * Lots of small (but important!) bug fixes: e.g., fixing GetPC on amd64 *** KNOWN PROBLEMS: * CPU-profiling may crash on x86_64 (64-bit) systems. See the README * Profiling/heap-checking may deadlock on x86_64 systems. See README Wed Jun 14 15:11:14 2006 Google Inc. * google-perftools: version 0.8 release * Experimental support for remote profiling added to pprof (many) * Fixed race condition in ProfileData::FlushTable (etune) * Better support for weird /proc maps (maxim, mec) * Fix heap-checker interaction with gdb (markus) * Better 64-bit support in pprof (aruns) * Reduce scavenging cost in tcmalloc by capping NumMoveSize (sanjay) * Cast syscall(SYS_mmap); works on more 64-bit systems now (menage) * Document the text output of pprof! (csilvers) * Better compiler support for no-THREADS and for old compilers (csilvers) * Make libunwind the default stack unwinder for x86-64 (aruns) * Somehow the COPYING file got erased. Regenerate it (csilvers) Thu Apr 13 20:59:09 2006 Google Inc. * google-perftools: version 0.7 release * Major rewrite of thread introspection for new kernels (markus) * Major rewrite of heap-checker to use new thread tools (maxim) * Add proper support for following data in thread registers (maxim) * Syscall support for older kernels, including _syscall6 (markus) * Support PIC mode (markus, mbland, iant) * Better support for running in non-threaded contexts (csilvers) Fri Jan 27 14:04:27 2006 Google Inc. * google-perftools: version 0.6 release * More sophisticated stacktrace usage, possibly using libunwind (aruns) * Update pprof to handle 64-bit profiles (dehnert) * Fix GetStackTrace to correctly return top stackframe (sanjay) * Add ANSI compliance for new and new[], including new_handler (jkearney) * More accuracy by reading ELF files directly rather than objdump (mec) * Add readline support for pprof (addi) * Add #includes for PPC (csilvers) * New PC-detection routine for ibook powerpc (asbestoshead) * Vastly improved tcmalloc unittest (csilvers) * Move documentation from /usr/doc to /usr/share/doc Mon Nov 14 17:28:59 2005 Google Inc. * google-perftools: version 0.5 release * Add va_start/va_end calls around vsnprintf() (csilvers) * Write our own __syscall_return(), since it's not defined consistently on all 64-bit linux distros (markus) Wed Oct 26 15:19:16 2005 Google Inc. * google-perftools: version 0.4 release * Decrease fragmentation in tcmalloc (lefevere) * Support for ARM in some of the thread-specific code (markus) * Turn off heap-checker for statically-linked binaries, which cause error leak reports now (etune) * Many pprof improvements, including a command-line interface (jeff) * CPU profiling now automatically affects all threads in linux 2.6. (Kernel bugs break CPU profiling and threads in linux 2.4 a bit.) ProfilerEnable() and ProfilerDisable() are deprecated. (sanjay) * tcmalloc now correctly intercepts memalign (m3b, maxim) * Syntax fix: added missing va_end()s. Helps non-gcc compiling (etune) * Fixed a few coredumper bugs: race condition after PTRACE_DETACH, ignore non-aligned stackframe pointers (markus, menage) * 64-bit cleanup, especially for spinlock code (etune) and mmap (sanjay) * Better support for finding threads in linux (markus) * tcmalloc now tracks those stack traces that allocate memory (sanjay) * Work around a weird setspecific problem (sanjay) * Fix tcmalloc overflow problems when an alloc is close to 2G/4G (sanjay) Fri Jun 24 18:02:26 2005 Google Inc. * google-perftools: version 0.3 release * Add missing errno include for one of the unittests (csilvers) * Reduce tcmalloc startup memory from 5M to 256K (sanjay) * Add support for mallopt() and mallinfo (sanjay) * Improve stacktrace's performance on some 64-bit systems (etune) * Improve the stacktrace unittest (etune) Tue May 31 08:14:38 2005 Google Inc. * google-perftools: version 0.2 release * Use mmap2() instead of mmap(), to map more memory (menage) * Do correct pthread-local checking in heap-checker! (maxim) * Avoid overflow on 64-bit machines in pprof (sanjay) * Add a few more GetPC() functions, including for AMD (csilvers) * Better method for overriding pthread functions (menage) * (Hacky) fix to avoid overwriting profile files after fork() (csilvers) * Crashing bugfix involving dumping heaps on small-stack threads (tudor) * Allow library versions with letters at the end (csilvers) * Config fixes for systems that don't define PATH_MAX (csilvers) * Confix fixes so we no longer need config.h after install (csilvers) * Fix to pprof to correctly read very big cpu profiles (csilvers) * Fix to pprof to deal with new commandline flags in modern gv's * Better error reporting when we can't access /proc/maps (etune) * Get rid of the libc-preallocate code (which could crash on some systems); no longer needed with local-threads fix (csilvers) Tue Feb 8 09:57:17 2005 Google Inc. * google-perftools: initial release: The google-perftools package contains some utilities to improve and analyze the performance of C++ programs. This includes an optimized thread-caching malloc() and cpu and heap profiling utilities. ================================================ FILE: distro/google-perftools-1.7/INSTALL ================================================ Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Perftools-Specific Install Notes ================================ *** NOTE FOR 64-BIT LINUX SYSTEMS The glibc built-in stack-unwinder on 64-bit systems has some problems with the perftools libraries. (In particular, the cpu/heap profiler may be in the middle of malloc, holding some malloc-related locks when they invoke the stack unwinder. The built-in stack unwinder may call malloc recursively, which may require the thread to acquire a lock it already holds: deadlock.) For that reason, if you use a 64-bit system, we strongly recommend you install libunwind before trying to configure or install google perftools. libunwind can be found at http://download.savannah.gnu.org/releases/libunwind/libunwind-0.99-beta.tar.gz Even if you already have libunwind installed, you should check the version. Versions older than this will not work properly; too-new versions introduce new code that does not work well with perftools (because libunwind can call malloc, which will lead to deadlock). CAUTION: if you install libunwind from the url above, be aware that you may have trouble if you try to statically link your binary with perftools: that is, if you link with 'gcc -static -lgcc_eh ...'. This is because both libunwind and libgcc implement the same C++ exception handling APIs, but they implement them differently on some platforms. This is not likely to be a problem on ia64, but may be on x86-64. Also, if you link binaries statically, make sure that you add -Wl,--eh-frame-hdr to your linker options. This is required so that libunwind can find the information generated by the compiler required for stack unwinding. Using -static is rare, though, so unless you know this will affect you it probably won't. If you cannot or do not wish to install libunwind, you can still try to use the built-in stack unwinder. The built-in stack unwinder requires that your application, the tcmalloc library, and system libraries like libc, all be compiled with a frame pointer. This is *not* the default for x86-64. If you are on x86-64 system, know that you have a set of system libraries with frame-pointers enabled, and compile all your applications with -fno-omit-frame-pointer, then you can enable the built-in perftools stack unwinder by passing the --enable-frame-pointers flag to configure. Even with the use of libunwind, there are still known problems with stack unwinding on 64-bit systems, particularly x86-64. See the "64-BIT ISSUES" section in README. If you encounter problems, try compiling perftools with './configure --enable-frame-pointers'. Note you will need to compile your application with frame pointers (via 'gcc -fno-omit-frame-pointer ...') in this case. *** TCMALLOC LARGE PAGES: TRADING TIME FOR SPACE Internally, tcmalloc divides its memory into "pages." The default page size is chosen to minimize memory use by reducing fragmentation. The cost is that keeping track of these pages can cost tcmalloc time. We've added a new, experimental flag to tcmalloc that enables a larger page size. In general, this will increase the memory needs of applications using tcmalloc. However, in many cases it will speed up the applications as well, particularly if they allocate and free a lot of memory. We've seen average speedups of 3-5% on Google applications. This feature is still very experimental; it's not even a configure flag yet. To build libtcmalloc with large pages, run ./configure CXXFLAGS=-DTCMALLOC_LARGE_PAGES (or add -DTCMALLOC_LARGE_PAGES to your existing CXXFLAGS argument). *** NOTE FOR ___tls_get_addr ERROR When compiling perftools on some old systems, like RedHat 8, you may get an error like this: ___tls_get_addr: symbol not found This means that you have a system where some parts are updated enough to support Thread Local Storage, but others are not. The perftools configure script can't always detect this kind of case, leading to that error. To fix it, just comment out the line #define HAVE_TLS 1 in your config.h file before building. *** TCMALLOC AND DLOPEN To improve performance, we use the "initial exec" model of Thread Local Storage in tcmalloc. The price for this is the library will not work correctly if it is loaded via dlopen(). This should not be a problem, since loading a malloc-replacement library via dlopen is asking for trouble in any case: some data will be allocated with one malloc, some with another. If, for some reason, you *do* need to use dlopen on tcmalloc, the easiest way is to use a version of tcmalloc with TLS turned off; see the ___tls_get_addr note above. *** COMPILING ON NON-LINUX SYSTEMS Perftools has been tested on the following systems: FreeBSD 6.0 (x86) Linux Fedora Core 3 (x86) Linux Fedora Core 4 (x86) Linux Fedora Core 5 (x86) Linux Fedora Core 6 (x86) Linux Ubuntu 6.06.1 (x86) Linux Ubuntu 6.06.1 (x86_64) Linux RedHat 9 (x86) Linux Debian 4.0 (PPC) Mac OS X 10.3.9 (Panther) (PowerPC) Mac OS X 10.4.8 (Tiger) (PowerPC) Mac OS X 10.4.8 (Tiger) (x86) Mac OS X 10.5 (Leopard) (x86) Solaris 10 (x86) Windows XP, Visual Studio 2003 (VC++ 7) (x86) Windows XP, Visual Studio 2005 (VC++ 8) (x86) Windows XP, MinGW 5.1.3 (x86) Windows XP, Cygwin 5.1 (x86) It works in its full generality on the Linux systems tested (though see 64-bit notes above). Portions of perftools work on the other systems. The basic memory-allocation library, tcmalloc_minimal, works on all systems. The cpu-profiler also works fairly widely. However, the heap-profiler and heap-checker are not yet as widely supported. In general, the 'configure' script will detect what OS you are building for, and only build the components that work on that OS. Note that tcmalloc_minimal is perfectly usable as a malloc/new replacement, so it is possible to use tcmalloc on all the systems above, by linking in libtcmalloc_minimal. ** FreeBSD: The following binaries build and run successfully (creating libtcmalloc_minimal.so and libprofile.so in the process): % ./configure % make tcmalloc_minimal_unittest tcmalloc_minimal_large_unittest \ addressmap_unittest atomicops_unittest frag_unittest \ low_level_alloc_unittest markidle_unittest memalign_unittest \ packed_cache_test stacktrace_unittest system_alloc_unittest \ thread_dealloc_unittest profiler_unittest.sh % ./tcmalloc_minimal_unittest # to run this test % [etc] # to run other tests Three caveats: first, frag_unittest tries to allocate 400M of memory, and if you have less virtual memory on your system, the test may fail with a bad_alloc exception. Second, profiler_unittest.sh sometimes fails in the "fork" test. This is because stray SIGPROF signals from the parent process are making their way into the child process. (This may be a kernel bug that only exists in older kernels.) The profiling code itself is working fine. This only affects programs that call fork(); for most programs, the cpu profiler is entirely safe to use. Third, perftools depends on /proc to get shared library information. If you are running a FreeBSD system without proc, perftools will not be able to map addresses to functions. Some unittests will fail as a result. Finally, the new test introduced in perftools-1.2, profile_handler_unittest, fails on FreeBSD. It has something to do with how the itimer works. The cpu profiler test passes, so I believe the functionality is correct and the issue is with the test somehow. If anybody is an expert on itimers and SIGPROF in FreeBSD, and would like to debug this, I'd be glad to hear the results! libtcmalloc.so successfully builds, and the "advanced" tcmalloc functionality all works except for the leak-checker, which has Linux-specific code: % make heap-profiler_unittest.sh maybe_threads_unittest.sh \ tcmalloc_unittest tcmalloc_both_unittest \ tcmalloc_large_unittest # THESE WORK % make -k heap-checker_unittest.sh \ heap-checker-death_unittest.sh # THESE DO NOT Note that unless you specify --enable-heap-checker explicitly, 'make' will not build the heap-checker unittests on a FreeBSD system. I have not tested other *BSD systems, but they are probably similar. ** Mac OS X: I've tested OS X 10.5 [Leopard], OS X 10.4 [Tiger] and OS X 10.3 [Panther] on both intel (x86) and PowerPC systems. For Panther systems, perftools does not work at all: it depends on a header file, OSAtomic.h, which is new in 10.4. (It's possible to get the code working for Panther/i386 without too much work; if you're interested in exploring this, drop an e-mail.) For the other seven systems, the binaries and libraries that successfully build are exactly the same as for FreeBSD. See that section for a list of binaries and instructions on building them. In addition, it appears OS X regularly fails profiler_unittest.sh in the "thread" test (in addition to occassionally failing in the "fork" test). It looks like OS X often delivers the profiling signal to the main thread, even when it's sleeping, rather than spawned threads that are doing actual work. If anyone knows details of how OS X handles SIGPROF (via setitimer()) events with threads, and has insight into this problem, please send mail to google-perftools@googlegroups.com. ** Solaris 10 x86: I've only tested using the GNU C++ compiler, not the Sun C++ compiler. Using g++ requires setting the PATH appropriately when configuring. % PATH=${PATH}:/usr/sfw/bin/:/usr/ccs/bin ./configure % PATH=${PATH}:/usr/sfw/bin/:/usr/ccs/bin make [...] Again, the binaries and libraries that successfully build are exactly the same as for FreeBSD. (However, while libprofiler.so can be used to generate profiles, pprof is not very successful at reading them -- necessary helper programs like nm don't seem to be installed by default on Solaris, or perhaps are only installed as part of the Sun C++ compiler package.) See that section for a list of binaries, and instructions on building them. ** Windows: Work on Windows is rather preliminary: we haven't found a good way to get stack traces in release mode on windows (that is, when FPO is enabled), so the heap profiling may not be reliable in that case. Also, heap-checking and CPU profiling do not yet work at all. But as in other ports, the basic tcmalloc library functionality, overriding malloc and new and such (and even windows-specific functions like _aligned_malloc!), is working fine, at least with VC++ 7.1 (Visual Studio 2003) and VC++ 8.0 (Visual Studio 2005), in both debug and release modes. See README.windows for instructions on how to install on Windows using Visual Studio. Cygwin can compile some but not all of perftools. Furthermore, there is a problem with exception-unwinding in cygwin (it can call malloc, which can call the exception-unwinding-setup code, which can lead to an infinite loop). I've comitted a workaround to the exception unwinding problem, but it only works in debug mode and when statically linking in tcmalloc. I hope to have a more proper fix in a later release. To configure under cygwin, run ./configure --disable-shared CXXFLAGS=-g && make Most of cygwin will compile (cygwin doesn't allow weak symbols, so the heap-checker and a few other pieces of functionality will not compile). 'make' will compile those libraries and tests that can be compiled. You can run 'make check' to make sure the basic functionality is working. I've heard reports that some versions of cygwin fail calls to pthread_join() with EINVAL, causing several tests to fail. If you have any insight into this, please mail google-perftools@googlegroups.com. This Windows functionality is also available using MinGW and Msys, In this case, you can use the regular './configure && make' process. 'make install' should also work. The Makefile will limit itself to those libraries and binaries that work on windows. Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale cache files.) If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You only need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not support the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the `--target=TYPE' option to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc will cause the specified gcc to be used as the C compiler (unless it is overridden in the site shell script). `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. ================================================ FILE: distro/google-perftools-1.7/Makefile.am ================================================ ## Process this file with automake to produce Makefile.in # Note: for every library we create, we're explicit about what symbols # we export. In order to avoid complications with C++ mangling, we always # use the regexp for of specifying symbols. # Make sure that when we re-make ./configure, we get the macros we need ACLOCAL_AMFLAGS = -I m4 # This is so we can #include AM_CPPFLAGS = -I$(top_srcdir)/src if !WITH_STACK_TRACE AM_CPPFLAGS += -DNO_TCMALLOC_SAMPLES endif !WITH_STACK_TRACE # This is mostly based on configure options AM_CXXFLAGS = # These are good warnings to turn on by default. We also tell gcc # that malloc, free, realloc, mmap, etc. are not builtins (these flags # are supported since gcc 3.1.1). gcc doesn't think most of them are # builtins now in any case, but it's best to be explicit in case that # changes one day. gcc ignores functions it doesn't understand. if GCC AM_CXXFLAGS += -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare \ -fno-builtin-malloc -fno-builtin-free -fno-builtin-realloc \ -fno-builtin-calloc -fno-builtin-cfree \ -fno-builtin-memalign -fno-builtin-posix_memalign \ -fno-builtin-valloc -fno-builtin-pvalloc endif GCC # The -no-undefined flag allows libtool to generate shared libraries for # Cygwin and MinGW. LIBSTDCXX_LA_LINKER_FLAG is used to fix a Solaris bug. AM_LDFLAGS = -no-undefined $(LIBSTDCXX_LA_LINKER_FLAG) # We know our low-level code cannot trigger an exception. On some # systems, such as cygwin, it would be disastrous if they did, because # the exception handler might call malloc! If our low-level routines # raised an exception within the malloc, they'd deadlock. Luckily, # we control all this code, and do not need exceptions for it. if GCC NO_EXCEPTIONS = -fno-exceptions else !GCC NO_EXCEPTIONS = endif !GCC # These are x86-specific, having to do with frame-pointers. In # particular, some x86_64 systems do not insert frame pointers by # default (all i386 systems that I know of, do. I don't know about # non-x86 chips). We need to tell perftools what to do about that. if X86_64_AND_NO_FP_BY_DEFAULT if ENABLE_FRAME_POINTERS AM_CXXFLAGS += -fno-omit-frame-pointer else # TODO(csilvers): check if -fomit-frame-pointer might be in $(CXXFLAGS), # before setting this. AM_CXXFLAGS += -DNO_FRAME_POINTER endif !ENABLE_FRAME_POINTERS endif X86_64_AND_NO_FP_BY_DEFAULT # For windows systems (at least, mingw), we need to tell all our # tests to link in libtcmalloc using -u. This is because libtcmalloc # accomplishes its tasks via patching, leaving no work for the linker # to identify, so the linker will ignore libtcmalloc by default unless # we explicitly create a dependency via -u. TCMALLOC_FLAGS = if MINGW TCMALLOC_FLAGS += -Wl,-u__tcmalloc endif MINGW # If we have objcopy, make malloc/free/etc weak symbols. That way folks # can override our malloc if they want to (they can still use tc_malloc). # Note: the weird-looking symbols are the c++ memory functions: # (in order) new, new(nothrow), new[], new[](nothrow), delete, delete[] # In theory this will break if mangling changes, but that seems pretty # unlikely at this point. Just in case, I throw in versions with an # extra underscore as well, which may help on OS X. if HAVE_OBJCOPY_WEAKEN WEAKEN = $(OBJCOPY) -W malloc -W free -W realloc -W calloc -W cfree \ -W memalign -W posix_memalign -W valloc -W pvalloc \ -W malloc_stats -W mallopt -W mallinfo \ -W _Znwm -W _ZnwmRKSt9nothrow_t -W _Znam -W _ZnamRKSt9nothrow_t \ -W _ZdlPv -W _ZdaPv \ -W __Znwm -W __ZnwmRKSt9nothrow_t -W __Znam -W __ZnamRKSt9nothrow_t \ -W __ZdlPv -W __ZdaPv else WEAKEN = : endif !HAVE_OBJCOPY_WEAKEN LIBS_TO_WEAKEN = googleincludedir = $(includedir)/google # The .h files you want to install (that is, .h files that people # who install this package can include in their own applications.) # We'll add to this later, on a library-by-library basis googleinclude_HEADERS = # tcmalloc.h is a special case, because it's a .h.in file nodist_googleinclude_HEADERS = src/google/tcmalloc.h noinst_HEADERS = src/google/tcmalloc.h.in docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION) # This is for HTML and other documentation you want to install. # Add your documentation files (in doc/) in addition to these # top-level boilerplate files. Also add a TODO file if you have one. # We'll add to this later, on a library-by-library basis dist_doc_DATA = AUTHORS COPYING ChangeLog INSTALL NEWS README README_windows.txt \ TODO # The libraries (.so's) you want to install # We'll add to this later, on a library-by-library basis lib_LTLIBRARIES = # This is for 'convenience libraries' -- basically just a container for sources noinst_LTLIBRARIES = ## The location of the windows project file for each binary we make WINDOWS_PROJECTS = google-perftools.sln # unittests you want to run when people type 'make check'. # Note: tests cannot take any arguments! # In theory, unittests that are scripts should be added to check_SCRIPTS # instead. But check_SCRIPTS is definitely a second-class testing mechanims: # it don't get TESTS_ENVIRONMENT, and it doesn't get success/failure counting # (in fact, a script failure aborts all the rest of the tests, even with -k). # So, for scripts, we add the script to tests, and also put in an empty # rule so automake doesn't try to build the script as a C binary. TESTS = # TESTS_ENVIRONMENT sets environment variables for when you run unittest. # We always get "srcdir" set for free. # We'll add to this later, on a library-by-library basis. TESTS_ENVIRONMENT = # All script tests should be added here noinst_SCRIPTS = # If your test calls another program that, like the test itself, shouldn't # be installed, add it here. (Stuff in TESTS is automatically added later). noinst_PROGRAMS = # Binaries we might build that should be installed bin_PROGRAMS = # This is my own var, used for extra libraries I make that I need installed EXTRA_INSTALL = ## vvvv RULES TO MAKE THE LIBRARIES, BINARIES, AND UNITTESTS dist_doc_DATA += doc/index.html doc/designstyle.css ### ------- library routines, in src/base # This is a 'convenience library' -- it's not actually installed or anything LOGGING_INCLUDES = src/base/logging.h \ src/base/commandlineflags.h \ src/base/basictypes.h \ src/base/dynamic_annotations.h \ src/third_party/valgrind.h noinst_LTLIBRARIES += liblogging.la liblogging_la_SOURCES = src/base/logging.cc \ src/base/dynamic_annotations.c \ $(LOGGING_INCLUDES) SYSINFO_INCLUDES = src/base/sysinfo.h \ src/base/logging.h \ src/base/commandlineflags.h \ src/base/cycleclock.h \ src/base/basictypes.h noinst_LTLIBRARIES += libsysinfo.la libsysinfo_la_SOURCES = src/base/sysinfo.cc \ $(SYSINFO_INCLUDES) libsysinfo_la_LIBADD = $(NANOSLEEP_LIBS) # For MinGW, we use also have to use libwindows Luckily, we need the # windows.a library in exactly the same place we need spinlock.a # (pretty much everywhere), so we can use the same variable name for # each. We can also optimize the MinGW rule a bit by leaving out # files we know aren't used on windows, such as # atomicops-internals-x86.cc. libwindows also obsoletes the need for # other files like system_alloc.cc. if MINGW WINDOWS_INCLUDES = src/windows/port.h \ src/windows/mingw.h \ src/windows/mini_disassembler.h \ src/windows/mini_disassembler_types.h \ src/windows/preamble_patcher.h noinst_LTLIBRARIES += libwindows.la libwindows_la_SOURCES = $(WINDOWS_INCLUDES) \ src/windows/port.cc \ src/windows/ia32_modrm_map.cc \ src/windows/ia32_opcode_map.cc \ src/windows/mini_disassembler.cc \ src/windows/patch_functions.cc \ src/windows/preamble_patcher.cc \ src/windows/preamble_patcher_with_stub.cc # patch_functions.cc uses Psapi.lib. MSVC has a #pragma for that, but not us. libwindows_la_LIBADD = -lPsapi SPINLOCK_INCLUDES = src/base/spinlock.h \ src/base/spinlock_internal.h \ src/base/spinlock_win32-inl.h \ src/base/spinlock_linux-inl.h \ src/base/spinlock_posix-inl.h \ src/base/synchronization_profiling.h \ src/base/atomicops-internals-macosx.h \ src/base/atomicops-internals-linuxppc.h \ src/base/atomicops-internals-arm-gcc.h \ src/base/atomicops-internals-x86-msvc.h \ src/base/atomicops-internals-x86.h noinst_LTLIBRARIES += libspinlock.la libspinlock_la_SOURCES = src/base/spinlock.cc \ src/base/spinlock_internal.cc \ $(SPINLOCK_INCLUDES) LIBSPINLOCK = libwindows.la libspinlock.la libsysinfo.la liblogging.la # We also need to tell mingw that sysinfo.cc needs shlwapi.lib. # (We do this via a #pragma for msvc, but need to do it here for mingw). libsysinfo_la_LIBADD += -lshlwapi # patch_functions.cc #includes tcmalloc.cc, so no need to link it in. TCMALLOC_CC = # windows has its own system for threads and system memory allocation. MAYBE_THREADS_CC = SYSTEM_ALLOC_CC = else !MINGW # spinlock is the only code that uses atomicops. SPINLOCK_INCLUDES = src/base/spinlock.h \ src/base/spinlock_internal.h \ src/base/atomicops.h \ src/base/atomicops-internals-macosx.h \ src/base/atomicops-internals-linuxppc.h \ src/base/atomicops-internals-x86-msvc.h \ src/base/atomicops-internals-x86.h noinst_LTLIBRARIES += libspinlock.la libspinlock_la_SOURCES = src/base/spinlock.cc \ src/base/spinlock_internal.cc \ src/base/atomicops-internals-x86.cc \ $(SPINLOCK_INCLUDES) libspinlock_la_LIBADD = $(NANOSLEEP_LIBS) # spinlock also needs NumCPUs, from libsysinfo, which in turn needs liblogging LIBSPINLOCK = libspinlock.la libsysinfo.la liblogging.la TCMALLOC_CC = src/tcmalloc.cc MAYBE_THREADS_CC = src/maybe_threads.cc SYSTEM_ALLOC_CC = src/system-alloc.cc endif !MINGW ### Unittests TESTS += low_level_alloc_unittest WINDOWS_PROJECTS += vsprojects/low_level_alloc_unittest/low_level_alloc_unittest.vcproj LOW_LEVEL_ALLOC_UNITTEST_INCLUDES = src/base/low_level_alloc.h \ src/base/basictypes.h \ src/google/malloc_hook.h \ src/google/malloc_hook_c.h \ src/malloc_hook-inl.h \ $(SPINLOCK_INCLUDES) \ $(LOGGING_INCLUDES) low_level_alloc_unittest_SOURCES = src/base/low_level_alloc.cc \ src/malloc_hook.cc \ src/tests/low_level_alloc_unittest.cc \ $(LOW_LEVEL_ALLOC_UNITTEST_INCLUDES) # By default, MallocHook takes stack traces for use by the heap-checker. # We don't need that functionality here, so we turn it off to reduce deps. low_level_alloc_unittest_CXXFLAGS = -DNO_TCMALLOC_SAMPLES low_level_alloc_unittest_LDADD = $(LIBSPINLOCK) TESTS += atomicops_unittest ATOMICOPS_UNITTEST_INCLUDES = src/base/atomicops.h \ src/base/atomicops-internals-macosx.h \ src/base/atomicops-internals-x86-msvc.h \ src/base/atomicops-internals-x86.h \ $(LOGGING_INCLUDES) atomicops_unittest_SOURCES = src/tests/atomicops_unittest.cc \ $(ATOMICOPS_UNITTEST_INCLUDES) atomicops_unittest_LDADD = $(LIBSPINLOCK) ### ------- stack trace if WITH_STACK_TRACE ### The header files we use. We divide into categories based on directory S_STACKTRACE_INCLUDES = src/stacktrace_config.h \ src/stacktrace_generic-inl.h \ src/stacktrace_libunwind-inl.h \ src/stacktrace_powerpc-inl.h \ src/stacktrace_x86_64-inl.h \ src/stacktrace_x86-inl.h \ src/stacktrace_win32-inl.h \ src/base/vdso_support.h SG_STACKTRACE_INCLUDES = src/google/stacktrace.h STACKTRACE_INCLUDES = $(S_STACKTRACE_INCLUDES) $(SG_STACKTRACE_INCLUDES) googleinclude_HEADERS += $(SG_STACKTRACE_INCLUDES) ### Making the library noinst_LTLIBRARIES += libstacktrace.la libstacktrace_la_SOURCES = src/stacktrace.cc \ src/base/vdso_support.cc \ $(STACKTRACE_INCLUDES) libstacktrace_la_LIBADD = $(UNWIND_LIBS) $(LIBSPINLOCK) STACKTRACE_SYMBOLS = '(GetStackTrace|GetStackFrames|GetStackTraceWithContext|GetStackFramesWithContext)' libstacktrace_la_LDFLAGS = -export-symbols-regex $(STACKTRACE_SYMBOLS) ### Unittests TESTS += stacktrace_unittest STACKTRACE_UNITTEST_INLCUDES = src/config_for_unittests.h \ src/base/commandlineflags.h \ $(STACKTRACE_INCLUDES) \ $(LOGGING_INCLUDES) stacktrace_unittest_SOURCES = src/tests/stacktrace_unittest.cc \ $(STACKTRACE_UNITTEST_INLCUDES) stacktrace_unittest_LDADD = libstacktrace.la liblogging.la ### Documentation dist_doc_DATA += endif WITH_STACK_TRACE ### ------- pprof # If we are not compiling with stacktrace support, pprof is worthless if WITH_STACK_TRACE bin_SCRIPTS = src/pprof ### Unittests check_SCRIPTS = pprof_unittest pprof_unittest: $(top_srcdir)/src/pprof $(top_srcdir)/src/pprof -test # Let unittests find pprof if they need to run it TESTS_ENVIRONMENT += PPROF_PATH=$(top_srcdir)/src/pprof ### Documentation dist_man_MANS = doc/pprof.1 dist_doc_DATA += doc/pprof_remote_servers.html # On MSVC, we need our own versions of addr2line and nm to work with pprof. WINDOWS_PROJECTS += vsprojects/nm-pdb/nm-pdb.vcproj WINDOWS_PROJECTS += vsprojects/addr2line-pdb/addr2line-pdb.vcproj # This is a slight abuse of WINDOWS_PROJECTS, but not much WINDOWS_PROJECTS += src/windows/nm-pdb.c \ src/windows/addr2line-pdb.c endif WITH_STACK_TRACE ### ------- tcmalloc_minimal (thread-caching malloc) ### The header files we use. We divide into categories based on directory S_TCMALLOC_MINIMAL_INCLUDES = src/common.h \ src/internal_logging.h \ src/system-alloc.h \ src/packed-cache-inl.h \ $(SPINLOCK_INCLUDES) \ src/tcmalloc_guard.h \ src/base/commandlineflags.h \ src/base/basictypes.h \ src/pagemap.h \ src/sampler.h \ src/central_freelist.h \ src/linked_list.h \ src/page_heap.h \ src/page_heap_allocator.h \ src/span.h \ src/static_vars.h \ src/symbolize.h \ src/thread_cache.h \ src/stack_trace_table.h \ src/base/thread_annotations.h \ src/malloc_hook-inl.h \ src/maybe_threads.h SG_TCMALLOC_MINIMAL_INCLUDES = src/google/malloc_hook.h \ src/google/malloc_hook_c.h \ src/google/malloc_extension.h \ src/google/malloc_extension_c.h \ src/google/stacktrace.h TCMALLOC_MINIMAL_INCLUDES = $(S_TCMALLOC_MINIMAL_INCLUDES) $(SG_TCMALLOC_MINIMAL_INCLUDES) googleinclude_HEADERS += $(SG_TCMALLOC_MINIMAL_INCLUDES) ### Making the library # As we describe at the top of this file, we want to turn off exceptions # for all files in this library -- except tcmalloc.cc which needs them # to fulfill its API. Automake doesn't allow per-file CXXFLAGS, so we need # to separate into two libraries. noinst_LTLIBRARIES += libtcmalloc_minimal_internal.la libtcmalloc_minimal_internal_la_SOURCES = src/common.cc \ src/internal_logging.cc \ $(SYSTEM_ALLOC_CC) \ src/memfs_malloc.cc \ src/central_freelist.cc \ src/page_heap.cc \ src/sampler.cc \ src/span.cc \ src/stack_trace_table.cc \ src/static_vars.cc \ src/symbolize.cc \ src/thread_cache.cc \ src/malloc_hook.cc \ src/malloc_extension.cc \ $(MAYBE_THREADS_CC) \ $(TCMALLOC_MINIMAL_INCLUDES) # We #define NO_TCMALLOC_SAMPLES, since sampling is turned off for _minimal. libtcmalloc_minimal_internal_la_CXXFLAGS = -DNO_TCMALLOC_SAMPLES \ -DNO_HEAP_CHECK \ $(PTHREAD_CFLAGS) -DNDEBUG \ $(AM_CXXFLAGS) $(NO_EXCEPTIONS) libtcmalloc_minimal_internal_la_LDFLAGS = $(PTHREAD_CFLAGS) libtcmalloc_minimal_internal_la_LIBADD = $(PTHREAD_LIBS) $(LIBSPINLOCK) lib_LTLIBRARIES += libtcmalloc_minimal.la WINDOWS_PROJECTS += vsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcproj libtcmalloc_minimal_la_SOURCES = $(TCMALLOC_CC) $(TCMALLOC_MINIMAL_INCLUDES) libtcmalloc_minimal_la_CXXFLAGS = -DNO_TCMALLOC_SAMPLES \ $(PTHREAD_CFLAGS) -DNDEBUG $(AM_CXXFLAGS) # -version-info gets passed to libtool libtcmalloc_minimal_la_LDFLAGS = $(PTHREAD_CFLAGS) -version-info @TCMALLOC_SO_VERSION@ libtcmalloc_minimal_la_LIBADD = libtcmalloc_minimal_internal.la $(PTHREAD_LIBS) # For windows, we're playing around with trying to do some stacktrace # support even with libtcmalloc_minimal. For everyone else, though, # we turn off all stack-trace activity for libtcmalloc_minimal. # TODO(csilvers): when we're done experimenting, do something principled here if MINGW LIBTCMALLOC_MINIMAL = libtcmalloc_minimal.la libstacktrace.la else !MINGW LIBTCMALLOC_MINIMAL = libtcmalloc_minimal.la endif !MINGW LIBS_TO_WEAKEN += libtcmalloc_minimal.la ### Unittests # Commented out for the moment because malloc(very_big_num) is broken in # standard libc! At least, in some situations, some of the time. ## TESTS += malloc_unittest ## MALLOC_UNITEST_INCLUDES = src/google/malloc_extension.h \ ## src/google/malloc_hook.h \ ## src/google/malloc_hook_c.h \ ## src/malloc_hook-inl.h \ ## src/base/basictypes.h \ ## src/maybe_threads.h ## malloc_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \ ## src/malloc_hook.cc \ ## src/malloc_extension.cc \ ## $(MAYBE_THREADS_CC) \ ## $(MALLOC_UNITTEST_INCLUDES) ## malloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) ## malloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS) ## malloc_unittest_LDADD = $(PTHREAD_LIBS) TESTS += tcmalloc_minimal_unittest WINDOWS_PROJECTS += vsprojects/tcmalloc_minimal_unittest/tcmalloc_minimal_unittest.vcproj WINDOWS_PROJECTS += vsprojects/tmu-static/tmu-static.vcproj tcmalloc_minimal_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \ src/tests/testutil.h src/tests/testutil.cc \ $(TCMALLOC_UNITTEST_INCLUDES) tcmalloc_minimal_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) tcmalloc_minimal_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) # We want libtcmalloc last on the link line, but due to a bug in # libtool involving convenience libs, they need to come last on the # link line in order to get dependency ordering right. This is ok: # convenience libraries are .a's, so tcmalloc is still the last .so. # We also put pthreads after tcmalloc, because some pthread # implementations define their own malloc, and we need to go on the # first linkline to make sure our malloc 'wins'. tcmalloc_minimal_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) \ liblogging.la $(PTHREAD_LIBS) TESTS += tcmalloc_minimal_large_unittest WINDOWS_PROJECTS += vsprojects/tcmalloc_minimal_large/tcmalloc_minimal_large_unittest.vcproj tcmalloc_minimal_large_unittest_SOURCES = src/tests/tcmalloc_large_unittest.cc tcmalloc_minimal_large_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) tcmalloc_minimal_large_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) tcmalloc_minimal_large_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) # This tests it works to LD_PRELOAD libtcmalloc (tests maybe_threads.cc) # In theory this should work under mingw, but mingw has trouble running # shell scripts that end in .exe. And it doesn't seem to build shared # libraries anyway (so can't be LD_PRELOADed) -- in fact, anybody who # chooses not to build shared libraries won't be able to run this test. # TODO(csilvers): figure out how to nix ".exe" or otherwise work under mingw if !MINGW if !ENABLE_STATIC TESTS += maybe_threads_unittest.sh$(EXEEXT) maybe_threads_unittest_sh_SOURCES = src/tests/maybe_threads_unittest.sh noinst_SCRIPTS += $(maybe_threads_unittest_sh_SOURCES) # This script preloads libtcmalloc, and calls two other binaries as well # TODO(csilvers): replace by 'if ! cmp $^ $@ >/dev/null 2>&; then ...; fi' maybe_threads_unittest.sh$(EXEEXT): $(top_srcdir)/$(maybe_threads_unittest_sh_SOURCES) \ $(LIBTCMALLOC_MINIMAL) \ low_level_alloc_unittest rm -f $@ cp -p $(top_srcdir)/$(maybe_threads_unittest_sh_SOURCES) $@ endif !ENABLE_STATIC endif !MINGW # These all tests components of tcmalloc_minimal TESTS += addressmap_unittest WINDOWS_PROJECTS += vsprojects/addressmap_unittest/addressmap_unittest.vcproj ADDRESSMAP_UNITTEST_INCLUDES = src/addressmap-inl.h \ src/base/commandlineflags.h \ $(LOGGING_INCLUDES) addressmap_unittest_SOURCES = src/tests/addressmap_unittest.cc \ $(ADDRESSMAP_UNITTEST_INCLUDES) if MINGW addressmap_unittest_SOURCES += src/windows/port.h src/windows/port.cc endif MINGW addressmap_unittest_CXXFLAGS = -g $(AM_CXXFLAGS) addressmap_unittest_LDADD = liblogging.la if !MINGW TESTS += system_alloc_unittest system_alloc_unittest_SOURCES = src/config_for_unittests.h \ src/tests/system-alloc_unittest.cc system_alloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) system_alloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) system_alloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) endif !MINGW TESTS += packed_cache_test WINDOWS_PROJECTS += vsprojects/packed-cache_test/packed-cache_test.vcproj packed_cache_test_SOURCES = src/tests/packed-cache_test.cc packed_cache_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) packed_cache_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) packed_cache_test_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) TESTS += frag_unittest WINDOWS_PROJECTS += vsprojects/frag_unittest/frag_unittest.vcproj frag_unittest_SOURCES = src/tests/frag_unittest.cc src/config_for_unittests.h frag_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) frag_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) frag_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) TESTS += markidle_unittest WINDOWS_PROJECTS += vsprojects/markidle_unittest/markidle_unittest.vcproj markidle_unittest_SOURCES = src/tests/markidle_unittest.cc \ src/config_for_unittests.h \ src/tests/testutil.h src/tests/testutil.cc markidle_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) markidle_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) markidle_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) TESTS += malloc_extension_test WINDOWS_PROJECTS += vsprojects/malloc_extension_test/malloc_extension_test.vcproj malloc_extension_test_SOURCES = src/tests/malloc_extension_test.cc \ src/config_for_unittests.h \ src/base/logging.h \ src/google/malloc_extension.h \ src/google/malloc_extension_c.h malloc_extension_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) malloc_extension_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) malloc_extension_test_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) # This doesn't work with static linkage, because libtcmalloc.a isn't # happy with C linkage (it misses the stdc++ library). Likewise with # mingw, which links foo.a even though it doesn't set ENABLE_STATIC. # TODO(csilvers): set enable_static=true in configure.ac:36? if !MINGW if !ENABLE_STATIC TESTS += malloc_extension_c_test malloc_extension_c_test_SOURCES = src/tests/malloc_extension_c_test.c \ src/google/malloc_extension.h \ src/google/malloc_extension_c.h malloc_extension_c_test_CFLAGS = $(PTHREAD_CFLAGS) $(AM_CFLAGS) # -ansi here is just to help ensure the code is bog-standard C. if GCC malloc_extension_c_test_CFLAGS += -ansi endif GCC malloc_extension_c_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) malloc_extension_c_test_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) endif !ENABLE_STATIC endif !MINGW if !MINGW TESTS += memalign_unittest memalign_unittest_SOURCES = src/tests/memalign_unittest.cc \ src/tcmalloc.h \ src/config_for_unittests.h \ src/tests/testutil.h src/tests/testutil.cc memalign_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) memalign_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) memalign_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) endif !MINGW TESTS += page_heap_test WINDOWS_PROJECTS += vsprojects/page_heap_test/page_heap_test.vcproj page_heap_test_SOURCES = src/tests/page_heap_test.cc \ src/config_for_unittests.h \ src/base/logging.h \ src/common.h \ src/page_heap.h page_heap_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) page_heap_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) page_heap_test_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) TESTS += pagemap_unittest WINDOWS_PROJECTS += vsprojects/pagemap_unittest/pagemap_unittest.vcproj pagemap_unittest_SOURCES = src/tests/pagemap_unittest.cc \ src/config_for_unittests.h \ src/base/logging.h \ src/pagemap.h pagemap_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) pagemap_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) pagemap_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) TESTS += realloc_unittest WINDOWS_PROJECTS += vsprojects/realloc_unittest/realloc_unittest.vcproj realloc_unittest_SOURCES = src/tests/realloc_unittest.cc \ src/config_for_unittests.h \ src/base/logging.h realloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) realloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) realloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) TESTS += stack_trace_table_test WINDOWS_PROJECTS += vsprojects/stack_trace_table_test/stack_trace_table_test.vcproj stack_trace_table_test_SOURCES = src/tests/stack_trace_table_test.cc \ src/config_for_unittests.h stack_trace_table_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) stack_trace_table_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) stack_trace_table_test_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) TESTS += thread_dealloc_unittest WINDOWS_PROJECTS += vsprojects/thread_dealloc_unittest/thread_dealloc_unittest.vcproj thread_dealloc_unittest_SOURCES = src/tests/thread_dealloc_unittest.cc \ src/config_for_unittests.h \ src/tests/testutil.h src/tests/testutil.cc thread_dealloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) thread_dealloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) thread_dealloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) ### Documentation dist_doc_DATA += doc/tcmalloc.html \ doc/overview.gif \ doc/pageheap.gif \ doc/spanmap.gif \ doc/threadheap.gif \ doc/t-test1.times.txt \ doc/tcmalloc-opspercpusec.vs.threads.1024.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.128.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.131072.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.16384.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.2048.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.256.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.32768.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.4096.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.512.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.64.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.65536.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.8192.bytes.png \ doc/tcmalloc-opspersec.vs.size.1.threads.png \ doc/tcmalloc-opspersec.vs.size.12.threads.png \ doc/tcmalloc-opspersec.vs.size.16.threads.png \ doc/tcmalloc-opspersec.vs.size.2.threads.png \ doc/tcmalloc-opspersec.vs.size.20.threads.png \ doc/tcmalloc-opspersec.vs.size.3.threads.png \ doc/tcmalloc-opspersec.vs.size.4.threads.png \ doc/tcmalloc-opspersec.vs.size.5.threads.png \ doc/tcmalloc-opspersec.vs.size.8.threads.png # I don't know how to say "distribute the .dot files but don't install them"; # noinst doesn't seem to work with data. I separate them out anyway, in case # one day we figure it out. Regardless, installing the dot files isn't the # end of the world. dist_doc_DATA += doc/overview.dot \ doc/pageheap.dot \ doc/spanmap.dot \ doc/threadheap.dot ### ------- tcmalloc_minimal_debug (thread-caching malloc with debugallocation) # Like tcmalloc.cc, debugallocation.cc needs exceptions to fulfill its # API. Luckily, we can reuse everything else from tcmalloc_minimal. if WITH_DEBUGALLOC lib_LTLIBRARIES += libtcmalloc_minimal_debug.la libtcmalloc_minimal_debug_la_SOURCES = src/debugallocation.cc \ $(TCMALLOC_MINIMAL_INCLUDES) libtcmalloc_minimal_debug_la_CXXFLAGS = $(libtcmalloc_minimal_la_CXXFLAGS) \ -DTCMALLOC_FOR_DEBUGALLOCATION # version_info gets passed to libtool libtcmalloc_minimal_debug_la_LDFLAGS = $(libtcmalloc_minimal_la_LDFLAGS) \ -version-info @TCMALLOC_SO_VERSION@ libtcmalloc_minimal_debug_la_LIBADD = $(libtcmalloc_minimal_la_LIBADD) LIBS_TO_WEAKEN += libtcmalloc_minimal_debug.la ### Unittests TESTS += tcmalloc_minimal_debug_unittest tcmalloc_minimal_debug_unittest_SOURCES = $(tcmalloc_minimal_unittest_SOURCES) tcmalloc_minimal_debug_unittest_CXXFLAGS = $(tcmalloc_minimal_unittest_CXXFLAGS) \ -DDEBUGALLOCATION tcmalloc_minimal_debug_unittest_LDFLAGS = $(tcmalloc_minimal_unittest_LDFLAGS) tcmalloc_minimal_debug_unittest_LDADD = libtcmalloc_minimal_debug.la $(PTHREAD_LIBS) TESTS += malloc_extension_debug_test malloc_extension_debug_test_SOURCES = $(malloc_extension_test_SOURCES) malloc_extension_debug_test_CXXFLAGS = $(malloc_extension_test_CXXFLAGS) malloc_extension_debug_test_LDFLAGS = $(malloc_extension_test_LDFLAGS) malloc_extension_debug_test_LDADD = libtcmalloc_minimal_debug.la $(PTHREAD_LIBS) TESTS += memalign_debug_unittest memalign_debug_unittest_SOURCES = $(memalign_unittest_SOURCES) memalign_debug_unittest_CXXFLAGS = $(memalign_unittest_CXXFLAGS) memalign_debug_unittest_LDFLAGS = $(memalign_unittest_LDFLAGS) memalign_debug_unittest_LDADD = libtcmalloc_minimal_debug.la $(PTHREAD_LIBS) TESTS += realloc_debug_unittest realloc_debug_unittest_SOURCES = $(realloc_unittest_SOURCES) realloc_debug_unittest_CXXFLAGS = $(realloc_unittest_CXXFLAGS) realloc_debug_unittest_LDFLAGS = $(realloc_unittest_LDFLAGS) realloc_debug_unittest_LDADD = libtcmalloc_minimal_debug.la $(PTHREAD_LIBS) TESTS += debugallocation_test.sh$(EXEEXT) debugallocation_test_sh_SOURCES = src/tests/debugallocation_test.sh noinst_SCRIPTS += $(debugallocation_test_sh_SOURCES) debugallocation_test.sh$(EXEEXT): $(top_srcdir)/$(debugallocation_test_sh_SOURCES) \ debugallocation_test rm -f $@ cp -p $(top_srcdir)/$(debugallocation_test_sh_SOURCES) $@ # This is the sub-program used by debugallocation_test.sh noinst_PROGRAMS += debugallocation_test debugallocation_test_SOURCES = src/tests/debugallocation_test.cc debugallocation_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) debugallocation_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) debugallocation_test_LDADD = libtcmalloc_debug.la $(PTHREAD_LIBS) endif WITH_DEBUGALLOC ### ------- tcmalloc (thread-caching malloc + heap profiler + heap checker) if WITH_HEAP_PROFILER_OR_CHECKER ### The header files we use. We divide into categories based on directory S_TCMALLOC_INCLUDES = $(S_TCMALLOC_MINIMAL_INCLUDES) \ $(LOGGING_INCLUDES) \ src/addressmap-inl.h \ src/raw_printer.h \ src/base/elfcore.h \ src/base/googleinit.h \ src/base/linux_syscall_support.h \ src/base/linuxthreads.h \ src/base/stl_allocator.h \ src/base/sysinfo.h \ src/base/thread_lister.h \ src/heap-profile-table.h SG_TCMALLOC_INCLUDES = $(SG_TCMALLOC_MINIMAL_INCLUDES) \ src/google/heap-profiler.h \ src/google/heap-checker.h TCMALLOC_INCLUDES = $(S_TCMALLOC_INCLUDES) $(SG_TCMALLOC_INCLUDES) googleinclude_HEADERS += $(SG_TCMALLOC_INCLUDES) ### Making the library # As we describe at the top of this file, we want to turn off exceptions # for all files in this library -- except tcmalloc.cc which needs them # to fulfill its API. Automake doesn't allow per-file CXXFLAGS, so we need # to separate into two libraries. noinst_LTLIBRARIES += libtcmalloc_internal.la libtcmalloc_internal_la_SOURCES = $(libtcmalloc_minimal_internal_la_SOURCES) \ $(TCMALLOC_INCLUDES) \ src/base/low_level_alloc.cc \ src/heap-profile-table.cc \ src/heap-profiler.cc \ src/raw_printer.cc \ src/memory_region_map.cc libtcmalloc_internal_la_CXXFLAGS = $(PTHREAD_CFLAGS) -DNDEBUG \ $(AM_CXXFLAGS) $(NO_EXCEPTIONS) libtcmalloc_internal_la_LDFLAGS = $(PTHREAD_CFLAGS) libtcmalloc_internal_la_LIBADD = libstacktrace.la $(PTHREAD_LIBS) lib_LTLIBRARIES += libtcmalloc.la libtcmalloc_la_SOURCES = $(TCMALLOC_CC) $(TCMALLOC_INCLUDES) libtcmalloc_la_CXXFLAGS = $(PTHREAD_CFLAGS) -DNDEBUG $(AM_CXXFLAGS) libtcmalloc_la_LDFLAGS = $(PTHREAD_CFLAGS) -version-info @TCMALLOC_SO_VERSION@ libtcmalloc_la_LIBADD = libtcmalloc_internal.la $(PTHREAD_LIBS) if WITH_HEAP_CHECKER # heap-checker-bcad is last, in hopes its global ctor will run first. # (Note this is added to libtcmalloc.la, not libtcmalloc_internal.la, # but that's ok; the internal/external distinction is only useful for # cygwin, and cygwin doesn't use HEAP_CHECKER anyway.) HEAP_CHECKER_SOURCES = src/base/thread_lister.c \ src/base/linuxthreads.cc \ src/heap-checker.cc \ src/heap-checker-bcad.cc libtcmalloc_la_SOURCES += $(HEAP_CHECKER_SOURCES) else !WITH_HEAP_CHECKER HEAP_CHECKER_SOURCES = libtcmalloc_internal_la_CXXFLAGS += -DNO_HEAP_CHECK libtcmalloc_la_CXXFLAGS += -DNO_HEAP_CHECK endif !WITH_HEAP_CHECKER LIBTCMALLOC = libtcmalloc.la LIBS_TO_WEAKEN += libtcmalloc.la ### Unittests TESTS += tcmalloc_unittest TCMALLOC_UNITTEST_INCLUDES = src/config_for_unittests.h \ src/google/malloc_extension.h tcmalloc_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \ src/tcmalloc.h \ src/tests/testutil.h src/tests/testutil.cc \ $(TCMALLOC_UNITTEST_INCLUDES) tcmalloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) tcmalloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) # We want libtcmalloc last on the link line, but due to a bug in # libtool involving convenience libs, they need to come last on the # link line in order to get dependency ordering right. This is ok: # convenience libraries are .a's, so tcmalloc is still the last .so. # We also put pthreads after tcmalloc, because some pthread # implementations define their own malloc, and we need to go on the # first linkline to make sure our malloc 'wins'. tcmalloc_unittest_LDADD = $(LIBTCMALLOC) liblogging.la $(PTHREAD_LIBS) # This makes sure it's safe to link in both tcmalloc and # tcmalloc_minimal. (One would never do this on purpose, but perhaps # by accident...) When we can compile libprofiler, we also link it in # to make sure that works too. TESTS += tcmalloc_both_unittest tcmalloc_both_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \ src/tests/testutil.h src/tests/testutil.cc \ $(TCMALLOC_UNITTEST_INCLUDES) tcmalloc_both_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) tcmalloc_both_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) if WITH_CPU_PROFILER # We want libtcmalloc last on the link line, but due to a bug in # libtool involving convenience libs, they need to come last on the # link line in order to get dependency ordering right. This is ok: # convenience libraries are .a's, so tcmalloc is still the last .so. # We also put pthreads after tcmalloc, because some pthread # implementations define their own malloc, and we need to go on the # first linkline to make sure our malloc 'wins'. tcmalloc_both_unittest_LDADD = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \ libprofiler.la liblogging.la $(PTHREAD_LIBS) else tcmalloc_both_unittest_LDADD = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \ liblogging.la $(PTHREAD_LIBS) endif !WITH_CPU_PROFILER TESTS += tcmalloc_large_unittest tcmalloc_large_unittest_SOURCES = src/tests/tcmalloc_large_unittest.cc tcmalloc_large_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) tcmalloc_large_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) tcmalloc_large_unittest_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS) TESTS += raw_printer_test raw_printer_test_SOURCES = src/tests/raw_printer_test.cc raw_printer_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) raw_printer_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) raw_printer_test_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS) # sampler_test and sampling_test both require sampling to be turned # on, which it's not by default. Use the "standard" value of 2^19. TESTS_ENVIRONMENT += TCMALLOC_SAMPLE_PARAMETER=524288 TESTS += sampler_test WINDOWS_PROJECTS += vsprojects/sampler_test/sampler_test.vcproj sampler_test_SOURCES = src/tests/sampler_test.cc \ src/config_for_unittests.h sampler_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) sampler_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) sampler_test_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS) -lm # These unittests often need to run binaries. They're in the current dir TESTS_ENVIRONMENT += BINDIR=. TESTS_ENVIRONMENT += TMPDIR=/tmp/perftools TESTS += sampling_test.sh$(EXEEXT) sampling_test_sh_SOURCES = src/tests/sampling_test.sh noinst_SCRIPTS += $(sampling_test_sh_SOURCES) sampling_test.sh$(EXEEXT): $(top_srcdir)/$(sampling_test_sh_SOURCES) \ sampling_test rm -f $@ cp -p $(top_srcdir)/$(sampling_test_sh_SOURCES) $@ # This is the sub-program used by sampling_test.sh # The -g is so pprof can get symbol information. noinst_PROGRAMS += sampling_test SAMPLING_TEST_INCLUDES = src/config_for_unittests.h \ src/base/logging.h \ src/google/malloc_extension.h sampling_test_SOURCES = src/tests/sampling_test.cc \ $(SAMPLING_TEST_INCLUDES) sampling_test_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) sampling_test_LDFLAGS = -g $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) sampling_test_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS) endif WITH_HEAP_PROFILER_OR_CHECKER if WITH_HEAP_PROFILER TESTS += heap-profiler_unittest.sh$(EXEEXT) heap_profiler_unittest_sh_SOURCES = src/tests/heap-profiler_unittest.sh noinst_SCRIPTS += $(heap_profiler_unittest_sh_SOURCES) heap-profiler_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) \ heap-profiler_unittest rm -f $@ cp -p $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) $@ # These are sub-programs used by heap-profiler_unittest.sh noinst_PROGRAMS += heap-profiler_unittest HEAP_PROFILER_UNITTEST_INCLUDES = src/config_for_unittests.h \ src/google/heap-profiler.h heap_profiler_unittest_SOURCES = src/tests/heap-profiler_unittest.cc \ $(HEAP_PROFILER_UNITTEST_INCLUDES) heap_profiler_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) heap_profiler_unittest_LDFLAGS = -g $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) heap_profiler_unittest_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS) endif WITH_HEAP_PROFILER if WITH_HEAP_CHECKER TESTS += heap-checker_unittest.sh$(EXEEXT) heap_checker_unittest_sh_SOURCES = src/tests/heap-checker_unittest.sh noinst_SCRIPTS += $(heap_checker_unittest_sh_SOURCES) heap-checker_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_checker_unittest_sh_SOURCES) \ heap-checker_unittest rm -f $@ cp -p $(top_srcdir)/$(heap_checker_unittest_sh_SOURCES) $@ TESTS += heap-checker-death_unittest.sh$(EXEEXT) heap_checker_death_unittest_sh_SOURCES = src/tests/heap-checker-death_unittest.sh noinst_SCRIPTS += $(top_srcdir)/$(heap_checker_death_unittest_sh_SOURCES) heap-checker-death_unittest.sh$(EXEEXT): $(heap_checker_death_unittest_sh_SOURCES) \ heap-checker_unittest rm -f $@ cp -p $(top_srcdir)/$(heap_checker_death_unittest_sh_SOURCES) $@ # These are sub-programs used by heap-checker_unittest.sh noinst_PROGRAMS += heap-checker_unittest HEAP_CHECKER_UNITTEST_INCLUDES = src/config_for_unittests.h \ src/memory_region_map.h \ src/base/commandlineflags.h \ src/base/googleinit.h \ src/google/heap-checker.h \ $(LOGGING_INCLUDES) heap_checker_unittest_SOURCES = src/tests/heap-checker_unittest.cc \ $(HEAP_CHECKER_UNITTEST_INCLUDES) heap_checker_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) heap_checker_unittest_LDFLAGS = -g $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) # We want libtcmalloc last on the link line, but due to a bug in # libtool involving convenience libs, they need to come last on the # link line in order to get dependency ordering right. This is ok: # convenience libraries are .a's, so tcmalloc is still the last .so. # We also put pthreads after tcmalloc, because some pthread # implementations define their own malloc, and we need to go on the # first linkline to make sure our malloc 'wins'. heap_checker_unittest_LDADD = $(LIBTCMALLOC) liblogging.la $(PTHREAD_LIBS) endif WITH_HEAP_CHECKER ### Documentation (above and beyond tcmalloc_minimal documentation) if WITH_HEAP_PROFILER dist_doc_DATA += doc/heapprofile.html doc/heap-example1.png endif WITH_HEAP_PROFILER if WITH_HEAP_CHECKER dist_doc_DATA += doc/heap_checker.html endif WITH_HEAP_CHECKER ### ------- tcmalloc with debugallocation if WITH_DEBUGALLOC if WITH_HEAP_PROFILER_OR_CHECKER lib_LTLIBRARIES += libtcmalloc_debug.la libtcmalloc_debug_la_SOURCES = src/debugallocation.cc $(HEAP_CHECKER_SOURCES) \ $(TCMALLOC_INCLUDES) libtcmalloc_debug_la_CXXFLAGS = $(libtcmalloc_la_CXXFLAGS) \ -DTCMALLOC_FOR_DEBUGALLOCATION libtcmalloc_debug_la_LDFLAGS = $(libtcmalloc_la_LDFLAGS) \ -version-info @TCMALLOC_SO_VERSION@ libtcmalloc_debug_la_LIBADD = $(libtcmalloc_la_LIBADD) LIBS_TO_WEAKEN += libtcmalloc_debug.la ### Unittests TESTS += tcmalloc_debug_unittest tcmalloc_debug_unittest_SOURCES = $(tcmalloc_unittest_SOURCES) tcmalloc_debug_unittest_CXXFLAGS = $(tcmalloc_unittest_CXXFLAGS) \ -DDEBUGALLOCATION tcmalloc_debug_unittest_LDFLAGS = $(tcmalloc_unittest_LDFLAGS) tcmalloc_debug_unittest_LDADD = libtcmalloc_debug.la $(PTHREAD_LIBS) TESTS += sampler_debug_test sampler_debug_test_SOURCES = $(sampler_test_SOURCES) sampler_debug_test_CXXFLAGS = $(samples_test_CXXFLAGS) sampler_debug_test_LDFLAGS = $(sampler_test_LDFLAGS) sampler_debug_test_LDADD = libtcmalloc_debug.la $(PTHREAD_LIBS) -lm TESTS += sampling_debug_test.sh$(EXEEXT) sampling_debug_test_sh_SOURCES = src/tests/sampling_test.sh sampling_debug_test.sh$(EXEEXT): $(top_srcdir)/$(sampling_test_sh_SOURCES) \ sampling_debug_test rm -f $@ cp -p $(top_srcdir)/$(sampling_test_sh_SOURCES) $@ # This is the sub-program using by sampling_debug_test.sh # The -g is so pprof can get symbol information. noinst_PROGRAMS += sampling_debug_test sampling_debug_test_SOURCES = $(sampling_test_SOURCES) sampling_debug_test_CXXFLAGS = $(sampling_test_CXXFLAGS) sampling_debug_test_LDFLAGS = $(sampling_test_LDFLAGS) sampling_debug_test_LDADD = libtcmalloc_debug.la $(PTHREAD_LIBS) endif WITH_HEAP_PROFILER_OR_CHECKER if WITH_HEAP_PROFILER TESTS += heap-profiler_debug_unittest.sh$(EXEEXT) heap_profiler_debug_unittest_sh_SOURCES = src/tests/heap-profiler_unittest.sh heap-profiler_debug_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) \ heap-profiler_debug_unittest rm -f $@ cp -p $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) $@ # These are sub-programs used by heap-profiler_debug_unittest.sh noinst_PROGRAMS += heap-profiler_debug_unittest heap_profiler_debug_unittest_SOURCES = $(heap_profiler_unittest_SOURCES) heap_profiler_debug_unittest_CXXFLAGS = $(heap_profiler_unittest_CXXFLAGS) heap_profiler_debug_unittest_LDFLAGS = $(heap_profiler_unittest_LDFLAGS) heap_profiler_debug_unittest_LDADD = libtcmalloc_debug.la $(PTHREAD_LIBS) endif WITH_HEAP_PROFILER if WITH_HEAP_CHECKER TESTS += heap-checker_debug_unittest.sh$(EXEEXT) heap_checker_debug_unittest_sh_SOURCES = src/tests/heap-checker_unittest.sh heap-checker_debug_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_checker_unittest_sh_SOURCES) \ heap-checker_debug_unittest rm -f $@ cp -p $(top_srcdir)/$(heap_checker_unittest_sh_SOURCES) $@ # These are sub-programs used by heap-checker_debug_unittest.sh noinst_PROGRAMS += heap-checker_debug_unittest heap_checker_debug_unittest_SOURCES = $(heap_checker_unittest_SOURCES) heap_checker_debug_unittest_CXXFLAGS = $(heap_checker_unittest_CXXFLAGS) heap_checker_debug_unittest_LDFLAGS = $(heap_checker_unittest_LDFLAGS) # We want libtcmalloc last on the link line, but due to a bug in # libtool involving convenience libs, they need to come last on the # link line in order to get dependency ordering right. This is ok: # convenience libraries are .a's, so tcmalloc is still the last .so. heap_checker_debug_unittest_LDADD = libtcmalloc_debug.la liblogging.la \ $(PTHREAD_LIBS) endif WITH_HEAP_CHECKER endif WITH_DEBUGALLOC ### ------- CPU profiler if WITH_CPU_PROFILER ### The header files we use. We divide into categories based on directory S_CPU_PROFILER_INCLUDES = src/profiledata.h \ src/profile-handler.h \ src/getpc.h \ src/base/basictypes.h \ src/base/commandlineflags.h \ src/base/googleinit.h \ src/base/logging.h \ src/base/simple_mutex.h \ src/base/sysinfo.h \ $(SPINLOCK_INCLUDES) \ $(LOGGING_INCLUDES) SG_CPU_PROFILER_INCLUDES = src/google/profiler.h \ src/google/stacktrace.h CPU_PROFILER_INCLUDES = $(S_CPU_PROFILER_INCLUDES) $(SG_CPU_PROFILER_INCLUDES) googleinclude_HEADERS += $(SG_CPU_PROFILER_INCLUDES) ### Making the library lib_LTLIBRARIES += libprofiler.la libprofiler_la_SOURCES = src/profiler.cc \ src/profile-handler.cc \ src/profiledata.cc \ $(CPU_PROFILER_INCLUDES) libprofiler_la_LIBADD = libstacktrace.la # We have to include ProfileData for profiledata_unittest CPU_PROFILER_SYMBOLS = '(ProfilerStart|ProfilerStartWithOptions|ProfilerStop|ProfilerFlush|ProfilerEnable|ProfilerDisable|ProfilingIsEnabledForAllThreads|ProfilerRegisterThread|ProfilerGetCurrentState|ProfilerState|ProfileData|ProfileHandler)' libprofiler_la_LDFLAGS = -export-symbols-regex $(CPU_PROFILER_SYMBOLS) \ -version-info @PROFILER_SO_VERSION@ # See discussion above (under LIBTCMALLOC_MINIMAL) for why we do this. # Basically it's to work around systems where --rpath doesn't work right. LIBPROFILER = libstacktrace.la libprofiler.la ### Unittests TESTS += getpc_test #WINDOWS_PROJECTS += vsprojects/getpc_test/getpc_test.vcproj getpc_test_SOURCES = src/tests/getpc_test.cc src/getpc.h TESTS += profiledata_unittest #WINDOWS_PROJECTS += vsprojects/profiledata_unittest/profiledata_unittest.vcproj profiledata_unittest_SOURCES = src/tests/profiledata_unittest.cc \ src/profiledata.h \ src/base/commandlineflags.h \ src/base/logging.h \ src/base/basictypes.h profiledata_unittest_LDADD = $(LIBPROFILER) TESTS += profile_handler_unittest profile_handler_unittest_SOURCES = src/tests/profile-handler_unittest.cc \ src/profile-handler.h profile_handler_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) profile_handler_unittest_LDFLAGS = $(PTHREAD_CFLAGS) profile_handler_unittest_LDADD = $(LIBPROFILER) $(PTHREAD_LIBS) TESTS += profiler_unittest.sh$(EXEEXT) profiler_unittest_sh_SOURCES = src/tests/profiler_unittest.sh noinst_SCRIPTS += $(profiler_unittest_sh_SOURCES) profiler_unittest.sh$(EXEEXT): $(top_srcdir)/$(profiler_unittest_sh_SOURCES) \ profiler1_unittest profiler2_unittest \ profiler3_unittest profiler4_unittest rm -f $@ cp -p $(top_srcdir)/$(profiler_unittest_sh_SOURCES) $@ # These are sub-programs used by profiler_unittest.sh noinst_PROGRAMS += profiler1_unittest profiler2_unittest profiler3_unittest \ profiler4_unittest PROFILER_UNITTEST_INCLUDES = src/config_for_unittests.h \ src/google/profiler.h PROFILER_UNITTEST_SRCS = src/tests/profiler_unittest.cc \ src/tests/testutil.h src/tests/testutil.cc \ $(PROFILER_UNITTEST_INCLUDES) profiler1_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS) profiler1_unittest_CXXFLAGS = -g -DNO_THREADS $(AM_CXXFLAGS) profiler1_unittest_LDADD = $(LIBPROFILER) profiler2_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS) profiler2_unittest_CXXFLAGS = -g -DNO_THREADS $(AM_CXXFLAGS) profiler2_unittest_LDADD = -lstacktrace -lprofiler # We depend on -lprofiler but haven't yet said how to build it. Do so now. profiler2_unittest_DEPENDENCIES = $(LIBPROFILER) profiler3_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS) profiler3_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) profiler3_unittest_LDFLAGS = $(PTHREAD_CFLAGS) profiler3_unittest_LDADD = $(LIBPROFILER) $(PTHREAD_LIBS) profiler4_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS) profiler4_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) profiler4_unittest_LDFLAGS = $(PTHREAD_CFLAGS) profiler4_unittest_LDADD = -lstacktrace -lprofiler $(PTHREAD_LIBS) # We depend on -lprofiler but haven't yet said how to build it. Do so now. profiler4_unittest_DEPENDENCIES = $(LIBPROFILER) ### Documentation dist_doc_DATA += doc/cpuprofile.html \ doc/cpuprofile-fileformat.html \ doc/pprof-test-big.gif \ doc/pprof-test.gif \ doc/pprof-vsnprintf-big.gif \ doc/pprof-vsnprintf.gif endif WITH_CPU_PROFILER ### ------- CPU profiler and heap checker, in one! # Ideally, folks who wanted to use both tcmalloc and libprofiler, # could just link them both into their application. But while this # works fine for .so files, it does not for .a files. The easiest way # around this -- and I've tried a bunch of the hard ways -- is to just # to create another set of libraries that has both functionality in it. if WITH_HEAP_PROFILER_OR_CHECKER if WITH_CPU_PROFILER lib_LTLIBRARIES += libtcmalloc_and_profiler.la libtcmalloc_and_profiler_la_SOURCES = $(libtcmalloc_la_SOURCES) $(libprofiler_la_SOURCES) libtcmalloc_and_profiler_la_CXXFLAGS = $(libtcmalloc_la_CXXFLAGS) $(libprofiler_la_CXXFLAGS) # Since this library is meant to be used as a .a, I don't worry as much # about .so versioning. I just give the libtcmalloc version number. # TODO(csilvers): use -export-symbols-regex? libtcmalloc_and_profiler_la_LDFLAGS = $(PTHREAD_CFLAGS) \ -version-info @TCMALLOC_SO_VERSION@ # We don't include libprofiler_la_LIBADD here because all it adds is # libstacktrace.la, which we already get via libtcmalloc. Trying to # specify it twice causes link-time duplicate-definition errors. :-( libtcmalloc_and_profiler_la_LIBADD = $(libtcmalloc_la_LIBADD) TESTS += tcmalloc_and_profiler_unittest tcmalloc_and_profiler_unittest_SOURCES = $(tcmalloc_both_unittest_SOURCES) tcmalloc_and_profiler_unittest_CXXFLAGS = $(tcmalloc_both_unittest_CXXFLAGS) tcmalloc_and_profiler_unittest_LDFLAGS = $(tcmalloc_both_unittest_LDFLAGS) tcmalloc_and_profiler_unittest_LDADD = libtcmalloc_and_profiler.la LIBS_TO_WEAKEN += libtcmalloc_and_profiler.la endif WITH_CPU_PROFILER endif WITH_HEAP_PROFILER_OR_CHECKER ## ^^^^ END OF RULES TO MAKE YOUR LIBRARIES, BINARIES, AND UNITTESTS # Do the weakening on some exported libtcmalloc symbols. install-exec-local: all-local all-local: $(LIBS_TO_WEAKEN) for la in $(LIBS_TO_WEAKEN); do lib=".libs/`basename $$la .la`.a"; [ ! -f "$$lib" ] || $(WEAKEN) "$$lib"; done # This should always include $(TESTS), but may also include other # binaries that you compile but don't want automatically installed. # We'll add to this later, on a library-by-library basis noinst_PROGRAMS += $(TESTS) rpm: dist-gzip packages/rpm.sh packages/rpm/rpm.spec @cd packages && ./rpm.sh ${PACKAGE} ${VERSION} deb: dist-gzip packages/deb.sh packages/deb/* @cd packages && ./deb.sh ${PACKAGE} ${VERSION} # http://linux.die.net/man/1/pkg-config, http://pkg-config.freedesktop.org/wiki pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libtcmalloc.pc libtcmalloc_minimal.pc \ libtcmalloc_debug.pc libtcmalloc_minimal_debug.pc \ libprofiler.pc CLEANFILES = $(pkgconfig_DATA) # I get the description and URL lines from the rpm spec. I use sed to # try to rewrite exec_prefix, libdir, and includedir in terms of # prefix, if possible. libtcmalloc.pc: Makefile packages/rpm/rpm.spec echo 'prefix=$(prefix)' > "$@".tmp echo 'exec_prefix='`echo '$(exec_prefix)' | sed 's@^$(prefix)@$${prefix}@'` >> "$@".tmp echo 'libdir='`echo '$(libdir)' | sed 's@^$(exec_prefix)@$${exec_prefix}@'` >> "$@".tmp echo 'includedir='`echo '$(includedir)' | sed 's@^$(prefix)@$${prefix}@'` >> "$@".tmp echo '' >> "$@".tmp echo 'Name: $(PACKAGE)' >> "$@".tmp echo 'Version: $(VERSION)' >> "$@".tmp -grep '^Summary:' packages/rpm/rpm.spec | sed s/^Summary:/Description:/ | head -n1 >> "$@".tmp -grep '^URL: ' packages/rpm/rpm.spec >> "$@".tmp echo 'Requires:' >> "$@".tmp echo 'Libs: -L$${libdir} -ltcmalloc' >> "$@".tmp echo 'Libs.private: $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)' >> "$@".tmp echo 'Cflags: -I$${includedir}' >> "$@".tmp mv -f "$@".tmp "$@" # The other versions are mostly the same. libtcmalloc_minimal.pc: libtcmalloc.pc cat libtcmalloc.pc | sed s/-ltcmalloc/-ltcmalloc_minimal/ > "$@" libtcmalloc_debug.pc: libtcmalloc.pc cat libtcmalloc.pc | sed s/-ltcmalloc/-ltcmalloc_debug/ > "$@" libtcmalloc_minimal_debug.pc: libtcmalloc.pc cat libtcmalloc.pc | sed s/-ltcmalloc/-ltcmalloc_minimal_debug/ > "$@" libprofiler.pc: libtcmalloc.pc cat libtcmalloc.pc | sed s/-ltcmalloc/-lprofiler/ > "$@" libtool: $(LIBTOOL_DEPS) $(SHELL) ./config.status --recheck # Windows wants write permission to .vcproj files and maybe even sln files. dist-hook: test -e "$(distdir)/vsprojects" \ && chmod -R u+w $(distdir)/*.sln $(distdir)/vsprojects/ EXTRA_DIST = packages/rpm.sh packages/rpm/rpm.spec packages/deb.sh packages/deb \ $(SCRIPTS) libtool \ src/windows/get_mangled_names.cc src/windows/override_functions.cc \ src/windows/config.h src/windows/google/tcmalloc.h \ $(WINDOWS_PROJECTS) \ src/solaris/libstdc++.la ================================================ FILE: distro/google-perftools-1.7/Makefile.in ================================================ # Makefile.in generated by automake 1.9.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Note: for every library we create, we're explicit about what symbols # we export. In order to avoid complications with C++ mangling, we always # use the regexp for of specifying symbols. srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = . am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @WITH_STACK_TRACE_FALSE@am__append_1 = -DNO_TCMALLOC_SAMPLES # These are good warnings to turn on by default. We also tell gcc # that malloc, free, realloc, mmap, etc. are not builtins (these flags # are supported since gcc 3.1.1). gcc doesn't think most of them are # builtins now in any case, but it's best to be explicit in case that # changes one day. gcc ignores functions it doesn't understand. @GCC_TRUE@am__append_2 = -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare \ @GCC_TRUE@ -fno-builtin-malloc -fno-builtin-free -fno-builtin-realloc \ @GCC_TRUE@ -fno-builtin-calloc -fno-builtin-cfree \ @GCC_TRUE@ -fno-builtin-memalign -fno-builtin-posix_memalign \ @GCC_TRUE@ -fno-builtin-valloc -fno-builtin-pvalloc # These are x86-specific, having to do with frame-pointers. In # particular, some x86_64 systems do not insert frame pointers by # default (all i386 systems that I know of, do. I don't know about # non-x86 chips). We need to tell perftools what to do about that. @ENABLE_FRAME_POINTERS_TRUE@@X86_64_AND_NO_FP_BY_DEFAULT_TRUE@am__append_3 = -fno-omit-frame-pointer @ENABLE_FRAME_POINTERS_FALSE@@X86_64_AND_NO_FP_BY_DEFAULT_TRUE@am__append_4 = -DNO_FRAME_POINTER @MINGW_TRUE@am__append_5 = -Wl,-u__tcmalloc noinst_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \ $(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_23) bin_PROGRAMS = @MINGW_TRUE@am__append_6 = libwindows.la libspinlock.la # We also need to tell mingw that sysinfo.cc needs shlwapi.lib. # (We do this via a #pragma for msvc, but need to do it here for mingw). @MINGW_TRUE@am__append_7 = -lshlwapi @MINGW_FALSE@am__append_8 = libspinlock.la @WITH_STACK_TRACE_TRUE@am__append_9 = $(SG_STACKTRACE_INCLUDES) ### Making the library @WITH_STACK_TRACE_TRUE@am__append_10 = libstacktrace.la ### Unittests @WITH_STACK_TRACE_TRUE@am__append_11 = stacktrace_unittest ### Documentation @WITH_STACK_TRACE_TRUE@am__append_12 = doc/pprof_remote_servers.html # Let unittests find pprof if they need to run it @WITH_STACK_TRACE_TRUE@am__append_13 = PPROF_PATH=$(top_srcdir)/src/pprof # On MSVC, we need our own versions of addr2line and nm to work with pprof. # This is a slight abuse of WINDOWS_PROJECTS, but not much @WITH_STACK_TRACE_TRUE@am__append_14 = \ @WITH_STACK_TRACE_TRUE@ vsprojects/nm-pdb/nm-pdb.vcproj \ @WITH_STACK_TRACE_TRUE@ vsprojects/addr2line-pdb/addr2line-pdb.vcproj \ @WITH_STACK_TRACE_TRUE@ src/windows/nm-pdb.c \ @WITH_STACK_TRACE_TRUE@ src/windows/addr2line-pdb.c # This tests it works to LD_PRELOAD libtcmalloc (tests maybe_threads.cc) # In theory this should work under mingw, but mingw has trouble running # shell scripts that end in .exe. And it doesn't seem to build shared # libraries anyway (so can't be LD_PRELOADed) -- in fact, anybody who # chooses not to build shared libraries won't be able to run this test. # TODO(csilvers): figure out how to nix ".exe" or otherwise work under mingw @ENABLE_STATIC_FALSE@@MINGW_FALSE@am__append_15 = maybe_threads_unittest.sh$(EXEEXT) @ENABLE_STATIC_FALSE@@MINGW_FALSE@am__append_16 = $(maybe_threads_unittest_sh_SOURCES) @MINGW_TRUE@am__append_17 = src/windows/port.h src/windows/port.cc @MINGW_FALSE@am__append_18 = system_alloc_unittest # This doesn't work with static linkage, because libtcmalloc.a isn't # happy with C linkage (it misses the stdc++ library). Likewise with # mingw, which links foo.a even though it doesn't set ENABLE_STATIC. # TODO(csilvers): set enable_static=true in configure.ac:36? @ENABLE_STATIC_FALSE@@MINGW_FALSE@am__append_19 = malloc_extension_c_test # -ansi here is just to help ensure the code is bog-standard C. @ENABLE_STATIC_FALSE@@GCC_TRUE@@MINGW_FALSE@am__append_20 = -ansi @MINGW_FALSE@am__append_21 = memalign_unittest ### ------- tcmalloc_minimal_debug (thread-caching malloc with debugallocation) # Like tcmalloc.cc, debugallocation.cc needs exceptions to fulfill its # API. Luckily, we can reuse everything else from tcmalloc_minimal. @WITH_DEBUGALLOC_TRUE@am__append_22 = libtcmalloc_minimal_debug.la @WITH_DEBUGALLOC_TRUE@am__append_23 = libtcmalloc_minimal_debug.la ### Unittests @WITH_DEBUGALLOC_TRUE@am__append_24 = tcmalloc_minimal_debug_unittest \ @WITH_DEBUGALLOC_TRUE@ malloc_extension_debug_test \ @WITH_DEBUGALLOC_TRUE@ memalign_debug_unittest \ @WITH_DEBUGALLOC_TRUE@ realloc_debug_unittest \ @WITH_DEBUGALLOC_TRUE@ debugallocation_test.sh$(EXEEXT) @WITH_DEBUGALLOC_TRUE@am__append_25 = $(debugallocation_test_sh_SOURCES) # This is the sub-program used by debugallocation_test.sh @WITH_DEBUGALLOC_TRUE@am__append_26 = debugallocation_test @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_27 = $(SG_TCMALLOC_INCLUDES) ### Making the library # As we describe at the top of this file, we want to turn off exceptions # for all files in this library -- except tcmalloc.cc which needs them # to fulfill its API. Automake doesn't allow per-file CXXFLAGS, so we need # to separate into two libraries. @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_28 = libtcmalloc_internal.la @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_29 = libtcmalloc.la @WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_30 = $(HEAP_CHECKER_SOURCES) @WITH_HEAP_CHECKER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_31 = -DNO_HEAP_CHECK @WITH_HEAP_CHECKER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_32 = -DNO_HEAP_CHECK @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_33 = libtcmalloc.la ### Unittests # This makes sure it's safe to link in both tcmalloc and # tcmalloc_minimal. (One would never do this on purpose, but perhaps # by accident...) When we can compile libprofiler, we also link it in # to make sure that works too. @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_34 = tcmalloc_unittest \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_both_unittest \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_large_unittest \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ raw_printer_test \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampler_test \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampling_test.sh$(EXEEXT) # sampler_test and sampling_test both require sampling to be turned # on, which it's not by default. Use the "standard" value of 2^19. # These unittests often need to run binaries. They're in the current dir @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_35 = TCMALLOC_SAMPLE_PARAMETER=524288 \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ BINDIR=. \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ TMPDIR=/tmp/perftools @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_36 = vsprojects/sampler_test/sampler_test.vcproj @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_37 = $(sampling_test_sh_SOURCES) # This is the sub-program used by sampling_test.sh # The -g is so pprof can get symbol information. @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_38 = sampling_test @WITH_HEAP_PROFILER_TRUE@am__append_39 = heap-profiler_unittest.sh$(EXEEXT) @WITH_HEAP_PROFILER_TRUE@am__append_40 = $(heap_profiler_unittest_sh_SOURCES) # These are sub-programs used by heap-profiler_unittest.sh @WITH_HEAP_PROFILER_TRUE@am__append_41 = heap-profiler_unittest @WITH_HEAP_CHECKER_TRUE@am__append_42 = \ @WITH_HEAP_CHECKER_TRUE@ heap-checker_unittest.sh$(EXEEXT) \ @WITH_HEAP_CHECKER_TRUE@ heap-checker-death_unittest.sh$(EXEEXT) @WITH_HEAP_CHECKER_TRUE@am__append_43 = \ @WITH_HEAP_CHECKER_TRUE@ $(heap_checker_unittest_sh_SOURCES) \ @WITH_HEAP_CHECKER_TRUE@ $(top_srcdir)/$(heap_checker_death_unittest_sh_SOURCES) # These are sub-programs used by heap-checker_unittest.sh @WITH_HEAP_CHECKER_TRUE@am__append_44 = heap-checker_unittest ### Documentation (above and beyond tcmalloc_minimal documentation) @WITH_HEAP_PROFILER_TRUE@am__append_45 = doc/heapprofile.html doc/heap-example1.png @WITH_HEAP_CHECKER_TRUE@am__append_46 = doc/heap_checker.html ### ------- tcmalloc with debugallocation @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_47 = libtcmalloc_debug.la @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_48 = libtcmalloc_debug.la ### Unittests @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_49 = tcmalloc_debug_unittest \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampler_debug_test \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampling_debug_test.sh$(EXEEXT) # This is the sub-program using by sampling_debug_test.sh # The -g is so pprof can get symbol information. @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_50 = sampling_debug_test @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@am__append_51 = heap-profiler_debug_unittest.sh$(EXEEXT) # These are sub-programs used by heap-profiler_debug_unittest.sh @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@am__append_52 = heap-profiler_debug_unittest @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@am__append_53 = heap-checker_debug_unittest.sh$(EXEEXT) # These are sub-programs used by heap-checker_debug_unittest.sh @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@am__append_54 = heap-checker_debug_unittest @WITH_CPU_PROFILER_TRUE@am__append_55 = $(SG_CPU_PROFILER_INCLUDES) ### Making the library @WITH_CPU_PROFILER_TRUE@am__append_56 = libprofiler.la ### Unittests @WITH_CPU_PROFILER_TRUE@am__append_57 = getpc_test \ @WITH_CPU_PROFILER_TRUE@ profiledata_unittest \ @WITH_CPU_PROFILER_TRUE@ profile_handler_unittest \ @WITH_CPU_PROFILER_TRUE@ profiler_unittest.sh$(EXEEXT) @WITH_CPU_PROFILER_TRUE@am__append_58 = $(profiler_unittest_sh_SOURCES) # These are sub-programs used by profiler_unittest.sh @WITH_CPU_PROFILER_TRUE@am__append_59 = profiler1_unittest profiler2_unittest profiler3_unittest \ @WITH_CPU_PROFILER_TRUE@ profiler4_unittest @WITH_CPU_PROFILER_FALSE@profiler2_unittest_DEPENDENCIES = ### Documentation @WITH_CPU_PROFILER_TRUE@am__append_60 = doc/cpuprofile.html \ @WITH_CPU_PROFILER_TRUE@ doc/cpuprofile-fileformat.html \ @WITH_CPU_PROFILER_TRUE@ doc/pprof-test-big.gif \ @WITH_CPU_PROFILER_TRUE@ doc/pprof-test.gif \ @WITH_CPU_PROFILER_TRUE@ doc/pprof-vsnprintf-big.gif \ @WITH_CPU_PROFILER_TRUE@ doc/pprof-vsnprintf.gif ### ------- CPU profiler and heap checker, in one! # Ideally, folks who wanted to use both tcmalloc and libprofiler, # could just link them both into their application. But while this # works fine for .so files, it does not for .a files. The easiest way # around this -- and I've tried a bunch of the hard ways -- is to just # to create another set of libraries that has both functionality in it. @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_61 = libtcmalloc_and_profiler.la @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_62 = tcmalloc_and_profiler_unittest @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_63 = libtcmalloc_and_profiler.la DIST_COMMON = README $(am__configure_deps) $(am__dist_doc_DATA_DIST) \ $(am__googleinclude_HEADERS_DIST) $(dist_man_MANS) \ $(noinst_HEADERS) $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(top_srcdir)/configure $(top_srcdir)/src/config.h.in \ $(top_srcdir)/src/google/tcmalloc.h.in AUTHORS COPYING \ ChangeLog INSTALL NEWS TODO compile config.guess config.sub \ depcomp install-sh ltmain.sh missing mkinstalldirs subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ac_have_attribute.m4 \ $(top_srcdir)/m4/acx_nanosleep.m4 \ $(top_srcdir)/m4/acx_pthread.m4 \ $(top_srcdir)/m4/compiler_characteristics.m4 \ $(top_srcdir)/m4/install_prefix.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/namespaces.m4 \ $(top_srcdir)/m4/pc_from_ucontext.m4 \ $(top_srcdir)/m4/program_invocation_name.m4 \ $(top_srcdir)/m4/stl_namespace.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno configure.status.lineno mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/src/config.h CONFIG_CLEAN_FILES = src/google/tcmalloc.h am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" \ "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgconfigdir)" \ "$(DESTDIR)$(googleincludedir)" \ "$(DESTDIR)$(googleincludedir)" libLTLIBRARIES_INSTALL = $(INSTALL) LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) liblogging_la_LIBADD = am__objects_1 = am_liblogging_la_OBJECTS = logging.lo dynamic_annotations.lo \ $(am__objects_1) liblogging_la_OBJECTS = $(am_liblogging_la_OBJECTS) @WITH_CPU_PROFILER_TRUE@libprofiler_la_DEPENDENCIES = \ @WITH_CPU_PROFILER_TRUE@ libstacktrace.la am__libprofiler_la_SOURCES_DIST = src/profiler.cc \ src/profile-handler.cc src/profiledata.cc src/profiledata.h \ src/profile-handler.h src/getpc.h src/base/basictypes.h \ src/base/commandlineflags.h src/base/googleinit.h \ src/base/logging.h src/base/simple_mutex.h src/base/sysinfo.h \ src/base/spinlock.h src/base/spinlock_internal.h \ src/base/atomicops.h src/base/atomicops-internals-macosx.h \ src/base/atomicops-internals-linuxppc.h \ src/base/atomicops-internals-x86-msvc.h \ src/base/atomicops-internals-x86.h \ src/base/spinlock_win32-inl.h src/base/spinlock_linux-inl.h \ src/base/spinlock_posix-inl.h \ src/base/synchronization_profiling.h \ src/base/atomicops-internals-arm-gcc.h \ src/base/dynamic_annotations.h src/third_party/valgrind.h \ src/google/profiler.h src/google/stacktrace.h @WITH_CPU_PROFILER_TRUE@am__objects_2 = $(am__objects_1) \ @WITH_CPU_PROFILER_TRUE@ $(am__objects_1) @WITH_CPU_PROFILER_TRUE@am__objects_3 = $(am__objects_2) \ @WITH_CPU_PROFILER_TRUE@ $(am__objects_1) @WITH_CPU_PROFILER_TRUE@am_libprofiler_la_OBJECTS = profiler.lo \ @WITH_CPU_PROFILER_TRUE@ profile-handler.lo profiledata.lo \ @WITH_CPU_PROFILER_TRUE@ $(am__objects_3) libprofiler_la_OBJECTS = $(am_libprofiler_la_OBJECTS) @WITH_CPU_PROFILER_TRUE@am_libprofiler_la_rpath = -rpath $(libdir) am__DEPENDENCIES_1 = @MINGW_FALSE@libspinlock_la_DEPENDENCIES = $(am__DEPENDENCIES_1) am__libspinlock_la_SOURCES_DIST = src/base/spinlock.cc \ src/base/spinlock_internal.cc \ src/base/atomicops-internals-x86.cc src/base/spinlock.h \ src/base/spinlock_internal.h src/base/atomicops.h \ src/base/atomicops-internals-macosx.h \ src/base/atomicops-internals-linuxppc.h \ src/base/atomicops-internals-x86-msvc.h \ src/base/atomicops-internals-x86.h \ src/base/spinlock_win32-inl.h src/base/spinlock_linux-inl.h \ src/base/spinlock_posix-inl.h \ src/base/synchronization_profiling.h \ src/base/atomicops-internals-arm-gcc.h @MINGW_FALSE@am_libspinlock_la_OBJECTS = spinlock.lo \ @MINGW_FALSE@ spinlock_internal.lo atomicops-internals-x86.lo \ @MINGW_FALSE@ $(am__objects_1) @MINGW_TRUE@am_libspinlock_la_OBJECTS = spinlock.lo \ @MINGW_TRUE@ spinlock_internal.lo $(am__objects_1) libspinlock_la_OBJECTS = $(am_libspinlock_la_OBJECTS) @MINGW_FALSE@am_libspinlock_la_rpath = @MINGW_TRUE@am_libspinlock_la_rpath = @MINGW_FALSE@am__DEPENDENCIES_2 = libspinlock.la libsysinfo.la \ @MINGW_FALSE@ liblogging.la @MINGW_TRUE@am__DEPENDENCIES_2 = libwindows.la libspinlock.la \ @MINGW_TRUE@ libsysinfo.la liblogging.la @WITH_STACK_TRACE_TRUE@libstacktrace_la_DEPENDENCIES = \ @WITH_STACK_TRACE_TRUE@ $(am__DEPENDENCIES_1) \ @WITH_STACK_TRACE_TRUE@ $(am__DEPENDENCIES_2) am__libstacktrace_la_SOURCES_DIST = src/stacktrace.cc \ src/base/vdso_support.cc src/stacktrace_config.h \ src/stacktrace_generic-inl.h src/stacktrace_libunwind-inl.h \ src/stacktrace_powerpc-inl.h src/stacktrace_x86_64-inl.h \ src/stacktrace_x86-inl.h src/stacktrace_win32-inl.h \ src/base/vdso_support.h src/google/stacktrace.h @WITH_STACK_TRACE_TRUE@am__objects_4 = $(am__objects_1) \ @WITH_STACK_TRACE_TRUE@ $(am__objects_1) @WITH_STACK_TRACE_TRUE@am_libstacktrace_la_OBJECTS = stacktrace.lo \ @WITH_STACK_TRACE_TRUE@ vdso_support.lo $(am__objects_4) libstacktrace_la_OBJECTS = $(am_libstacktrace_la_OBJECTS) @WITH_STACK_TRACE_TRUE@am_libstacktrace_la_rpath = libsysinfo_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) am_libsysinfo_la_OBJECTS = sysinfo.lo $(am__objects_1) libsysinfo_la_OBJECTS = $(am_libsysinfo_la_OBJECTS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_DEPENDENCIES = \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_internal.la \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1) am__libtcmalloc_la_SOURCES_DIST = src/tcmalloc.cc src/common.h \ src/internal_logging.h src/system-alloc.h \ src/packed-cache-inl.h src/base/spinlock.h \ src/base/spinlock_internal.h src/base/atomicops.h \ src/base/atomicops-internals-macosx.h \ src/base/atomicops-internals-linuxppc.h \ src/base/atomicops-internals-x86-msvc.h \ src/base/atomicops-internals-x86.h \ src/base/spinlock_win32-inl.h src/base/spinlock_linux-inl.h \ src/base/spinlock_posix-inl.h \ src/base/synchronization_profiling.h \ src/base/atomicops-internals-arm-gcc.h src/tcmalloc_guard.h \ src/base/commandlineflags.h src/base/basictypes.h \ src/pagemap.h src/sampler.h src/central_freelist.h \ src/linked_list.h src/page_heap.h src/page_heap_allocator.h \ src/span.h src/static_vars.h src/symbolize.h \ src/thread_cache.h src/stack_trace_table.h \ src/base/thread_annotations.h src/malloc_hook-inl.h \ src/maybe_threads.h src/base/logging.h \ src/base/dynamic_annotations.h src/third_party/valgrind.h \ src/addressmap-inl.h src/raw_printer.h src/base/elfcore.h \ src/base/googleinit.h src/base/linux_syscall_support.h \ src/base/linuxthreads.h src/base/stl_allocator.h \ src/base/sysinfo.h src/base/thread_lister.h \ src/heap-profile-table.h src/google/malloc_hook.h \ src/google/malloc_hook_c.h src/google/malloc_extension.h \ src/google/malloc_extension_c.h src/google/stacktrace.h \ src/google/heap-profiler.h src/google/heap-checker.h \ src/base/thread_lister.c src/base/linuxthreads.cc \ src/heap-checker.cc src/heap-checker-bcad.cc @MINGW_FALSE@am__objects_5 = libtcmalloc_la-tcmalloc.lo am__objects_6 = $(am__objects_1) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_7 = $(am__objects_6) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_1) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_8 = $(am__objects_1) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_9 = $(am__objects_7) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_8) @WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_10 = thread_lister.lo \ @WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_la-linuxthreads.lo \ @WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_la-heap-checker.lo \ @WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_la-heap-checker-bcad.lo @WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_11 = $(am__objects_10) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_libtcmalloc_la_OBJECTS = \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_5) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_9) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_11) libtcmalloc_la_OBJECTS = $(am_libtcmalloc_la_OBJECTS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_libtcmalloc_la_rpath = -rpath \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(libdir) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__DEPENDENCIES_3 = \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_internal.la \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1) @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_and_profiler_la_DEPENDENCIES = $(am__DEPENDENCIES_3) am__libtcmalloc_and_profiler_la_SOURCES_DIST = src/tcmalloc.cc \ src/common.h src/internal_logging.h src/system-alloc.h \ src/packed-cache-inl.h src/base/spinlock.h \ src/base/spinlock_internal.h src/base/atomicops.h \ src/base/atomicops-internals-macosx.h \ src/base/atomicops-internals-linuxppc.h \ src/base/atomicops-internals-x86-msvc.h \ src/base/atomicops-internals-x86.h \ src/base/spinlock_win32-inl.h src/base/spinlock_linux-inl.h \ src/base/spinlock_posix-inl.h \ src/base/synchronization_profiling.h \ src/base/atomicops-internals-arm-gcc.h src/tcmalloc_guard.h \ src/base/commandlineflags.h src/base/basictypes.h \ src/pagemap.h src/sampler.h src/central_freelist.h \ src/linked_list.h src/page_heap.h src/page_heap_allocator.h \ src/span.h src/static_vars.h src/symbolize.h \ src/thread_cache.h src/stack_trace_table.h \ src/base/thread_annotations.h src/malloc_hook-inl.h \ src/maybe_threads.h src/base/logging.h \ src/base/dynamic_annotations.h src/third_party/valgrind.h \ src/addressmap-inl.h src/raw_printer.h src/base/elfcore.h \ src/base/googleinit.h src/base/linux_syscall_support.h \ src/base/linuxthreads.h src/base/stl_allocator.h \ src/base/sysinfo.h src/base/thread_lister.h \ src/heap-profile-table.h src/google/malloc_hook.h \ src/google/malloc_hook_c.h src/google/malloc_extension.h \ src/google/malloc_extension_c.h src/google/stacktrace.h \ src/google/heap-profiler.h src/google/heap-checker.h \ src/base/thread_lister.c src/base/linuxthreads.cc \ src/heap-checker.cc src/heap-checker-bcad.cc src/profiler.cc \ src/profile-handler.cc src/profiledata.cc src/profiledata.h \ src/profile-handler.h src/getpc.h src/base/simple_mutex.h \ src/google/profiler.h @MINGW_FALSE@am__objects_12 = libtcmalloc_and_profiler_la-tcmalloc.lo @WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_13 = thread_lister.lo \ @WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_and_profiler_la-linuxthreads.lo \ @WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_and_profiler_la-heap-checker.lo \ @WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_and_profiler_la-heap-checker-bcad.lo @WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_14 = $(am__objects_13) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_15 = \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_12) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_9) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_14) @WITH_CPU_PROFILER_TRUE@am__objects_16 = libtcmalloc_and_profiler_la-profiler.lo \ @WITH_CPU_PROFILER_TRUE@ libtcmalloc_and_profiler_la-profile-handler.lo \ @WITH_CPU_PROFILER_TRUE@ libtcmalloc_and_profiler_la-profiledata.lo \ @WITH_CPU_PROFILER_TRUE@ $(am__objects_3) @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_libtcmalloc_and_profiler_la_OBJECTS = $(am__objects_15) \ @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_16) libtcmalloc_and_profiler_la_OBJECTS = \ $(am_libtcmalloc_and_profiler_la_OBJECTS) @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_libtcmalloc_and_profiler_la_rpath = -rpath \ @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(libdir) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_debug_la_DEPENDENCIES = $(am__DEPENDENCIES_3) am__libtcmalloc_debug_la_SOURCES_DIST = src/debugallocation.cc \ src/base/thread_lister.c src/base/linuxthreads.cc \ src/heap-checker.cc src/heap-checker-bcad.cc src/common.h \ src/internal_logging.h src/system-alloc.h \ src/packed-cache-inl.h src/base/spinlock.h \ src/base/spinlock_internal.h src/base/atomicops.h \ src/base/atomicops-internals-macosx.h \ src/base/atomicops-internals-linuxppc.h \ src/base/atomicops-internals-x86-msvc.h \ src/base/atomicops-internals-x86.h \ src/base/spinlock_win32-inl.h src/base/spinlock_linux-inl.h \ src/base/spinlock_posix-inl.h \ src/base/synchronization_profiling.h \ src/base/atomicops-internals-arm-gcc.h src/tcmalloc_guard.h \ src/base/commandlineflags.h src/base/basictypes.h \ src/pagemap.h src/sampler.h src/central_freelist.h \ src/linked_list.h src/page_heap.h src/page_heap_allocator.h \ src/span.h src/static_vars.h src/symbolize.h \ src/thread_cache.h src/stack_trace_table.h \ src/base/thread_annotations.h src/malloc_hook-inl.h \ src/maybe_threads.h src/base/logging.h \ src/base/dynamic_annotations.h src/third_party/valgrind.h \ src/addressmap-inl.h src/raw_printer.h src/base/elfcore.h \ src/base/googleinit.h src/base/linux_syscall_support.h \ src/base/linuxthreads.h src/base/stl_allocator.h \ src/base/sysinfo.h src/base/thread_lister.h \ src/heap-profile-table.h src/google/malloc_hook.h \ src/google/malloc_hook_c.h src/google/malloc_extension.h \ src/google/malloc_extension_c.h src/google/stacktrace.h \ src/google/heap-profiler.h src/google/heap-checker.h @WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_17 = thread_lister.lo \ @WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_debug_la-linuxthreads.lo \ @WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_debug_la-heap-checker.lo \ @WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_debug_la-heap-checker-bcad.lo @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_libtcmalloc_debug_la_OBJECTS = libtcmalloc_debug_la-debugallocation.lo \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_17) \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_9) libtcmalloc_debug_la_OBJECTS = $(am_libtcmalloc_debug_la_OBJECTS) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_libtcmalloc_debug_la_rpath = -rpath \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(libdir) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_internal_la_DEPENDENCIES = \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libstacktrace.la \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1) am__libtcmalloc_internal_la_SOURCES_DIST = src/common.cc \ src/internal_logging.cc src/system-alloc.cc \ src/memfs_malloc.cc src/central_freelist.cc src/page_heap.cc \ src/sampler.cc src/span.cc src/stack_trace_table.cc \ src/static_vars.cc src/symbolize.cc src/thread_cache.cc \ src/malloc_hook.cc src/malloc_extension.cc \ src/maybe_threads.cc src/common.h src/internal_logging.h \ src/system-alloc.h src/packed-cache-inl.h src/base/spinlock.h \ src/base/spinlock_internal.h src/base/atomicops.h \ src/base/atomicops-internals-macosx.h \ src/base/atomicops-internals-linuxppc.h \ src/base/atomicops-internals-x86-msvc.h \ src/base/atomicops-internals-x86.h \ src/base/spinlock_win32-inl.h src/base/spinlock_linux-inl.h \ src/base/spinlock_posix-inl.h \ src/base/synchronization_profiling.h \ src/base/atomicops-internals-arm-gcc.h src/tcmalloc_guard.h \ src/base/commandlineflags.h src/base/basictypes.h \ src/pagemap.h src/sampler.h src/central_freelist.h \ src/linked_list.h src/page_heap.h src/page_heap_allocator.h \ src/span.h src/static_vars.h src/symbolize.h \ src/thread_cache.h src/stack_trace_table.h \ src/base/thread_annotations.h src/malloc_hook-inl.h \ src/maybe_threads.h src/google/malloc_hook.h \ src/google/malloc_hook_c.h src/google/malloc_extension.h \ src/google/malloc_extension_c.h src/google/stacktrace.h \ src/base/logging.h src/base/dynamic_annotations.h \ src/third_party/valgrind.h src/addressmap-inl.h \ src/raw_printer.h src/base/elfcore.h src/base/googleinit.h \ src/base/linux_syscall_support.h src/base/linuxthreads.h \ src/base/stl_allocator.h src/base/sysinfo.h \ src/base/thread_lister.h src/heap-profile-table.h \ src/google/heap-profiler.h src/google/heap-checker.h \ src/base/low_level_alloc.cc src/heap-profile-table.cc \ src/heap-profiler.cc src/raw_printer.cc \ src/memory_region_map.cc @MINGW_FALSE@am__objects_18 = libtcmalloc_internal_la-system-alloc.lo @MINGW_FALSE@am__objects_19 = \ @MINGW_FALSE@ libtcmalloc_internal_la-maybe_threads.lo am__objects_20 = $(am__objects_6) $(am__objects_1) am__objects_21 = libtcmalloc_internal_la-common.lo \ libtcmalloc_internal_la-internal_logging.lo $(am__objects_18) \ libtcmalloc_internal_la-memfs_malloc.lo \ libtcmalloc_internal_la-central_freelist.lo \ libtcmalloc_internal_la-page_heap.lo \ libtcmalloc_internal_la-sampler.lo \ libtcmalloc_internal_la-span.lo \ libtcmalloc_internal_la-stack_trace_table.lo \ libtcmalloc_internal_la-static_vars.lo \ libtcmalloc_internal_la-symbolize.lo \ libtcmalloc_internal_la-thread_cache.lo \ libtcmalloc_internal_la-malloc_hook.lo \ libtcmalloc_internal_la-malloc_extension.lo $(am__objects_19) \ $(am__objects_20) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_libtcmalloc_internal_la_OBJECTS = \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_21) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_9) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_internal_la-low_level_alloc.lo \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_internal_la-heap-profile-table.lo \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_internal_la-heap-profiler.lo \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_internal_la-raw_printer.lo \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_internal_la-memory_region_map.lo libtcmalloc_internal_la_OBJECTS = \ $(am_libtcmalloc_internal_la_OBJECTS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_libtcmalloc_internal_la_rpath = libtcmalloc_minimal_la_DEPENDENCIES = libtcmalloc_minimal_internal.la \ $(am__DEPENDENCIES_1) am__libtcmalloc_minimal_la_SOURCES_DIST = src/tcmalloc.cc src/common.h \ src/internal_logging.h src/system-alloc.h \ src/packed-cache-inl.h src/base/spinlock.h \ src/base/spinlock_internal.h src/base/atomicops.h \ src/base/atomicops-internals-macosx.h \ src/base/atomicops-internals-linuxppc.h \ src/base/atomicops-internals-x86-msvc.h \ src/base/atomicops-internals-x86.h \ src/base/spinlock_win32-inl.h src/base/spinlock_linux-inl.h \ src/base/spinlock_posix-inl.h \ src/base/synchronization_profiling.h \ src/base/atomicops-internals-arm-gcc.h src/tcmalloc_guard.h \ src/base/commandlineflags.h src/base/basictypes.h \ src/pagemap.h src/sampler.h src/central_freelist.h \ src/linked_list.h src/page_heap.h src/page_heap_allocator.h \ src/span.h src/static_vars.h src/symbolize.h \ src/thread_cache.h src/stack_trace_table.h \ src/base/thread_annotations.h src/malloc_hook-inl.h \ src/maybe_threads.h src/google/malloc_hook.h \ src/google/malloc_hook_c.h src/google/malloc_extension.h \ src/google/malloc_extension_c.h src/google/stacktrace.h @MINGW_FALSE@am__objects_22 = libtcmalloc_minimal_la-tcmalloc.lo am_libtcmalloc_minimal_la_OBJECTS = $(am__objects_22) \ $(am__objects_20) libtcmalloc_minimal_la_OBJECTS = $(am_libtcmalloc_minimal_la_OBJECTS) am__DEPENDENCIES_4 = libtcmalloc_minimal_internal.la \ $(am__DEPENDENCIES_1) @WITH_DEBUGALLOC_TRUE@libtcmalloc_minimal_debug_la_DEPENDENCIES = \ @WITH_DEBUGALLOC_TRUE@ $(am__DEPENDENCIES_4) am__libtcmalloc_minimal_debug_la_SOURCES_DIST = \ src/debugallocation.cc src/common.h src/internal_logging.h \ src/system-alloc.h src/packed-cache-inl.h src/base/spinlock.h \ src/base/spinlock_internal.h src/base/atomicops.h \ src/base/atomicops-internals-macosx.h \ src/base/atomicops-internals-linuxppc.h \ src/base/atomicops-internals-x86-msvc.h \ src/base/atomicops-internals-x86.h \ src/base/spinlock_win32-inl.h src/base/spinlock_linux-inl.h \ src/base/spinlock_posix-inl.h \ src/base/synchronization_profiling.h \ src/base/atomicops-internals-arm-gcc.h src/tcmalloc_guard.h \ src/base/commandlineflags.h src/base/basictypes.h \ src/pagemap.h src/sampler.h src/central_freelist.h \ src/linked_list.h src/page_heap.h src/page_heap_allocator.h \ src/span.h src/static_vars.h src/symbolize.h \ src/thread_cache.h src/stack_trace_table.h \ src/base/thread_annotations.h src/malloc_hook-inl.h \ src/maybe_threads.h src/google/malloc_hook.h \ src/google/malloc_hook_c.h src/google/malloc_extension.h \ src/google/malloc_extension_c.h src/google/stacktrace.h @WITH_DEBUGALLOC_TRUE@am_libtcmalloc_minimal_debug_la_OBJECTS = libtcmalloc_minimal_debug_la-debugallocation.lo \ @WITH_DEBUGALLOC_TRUE@ $(am__objects_20) libtcmalloc_minimal_debug_la_OBJECTS = \ $(am_libtcmalloc_minimal_debug_la_OBJECTS) @WITH_DEBUGALLOC_TRUE@am_libtcmalloc_minimal_debug_la_rpath = -rpath \ @WITH_DEBUGALLOC_TRUE@ $(libdir) libtcmalloc_minimal_internal_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am__libtcmalloc_minimal_internal_la_SOURCES_DIST = src/common.cc \ src/internal_logging.cc src/system-alloc.cc \ src/memfs_malloc.cc src/central_freelist.cc src/page_heap.cc \ src/sampler.cc src/span.cc src/stack_trace_table.cc \ src/static_vars.cc src/symbolize.cc src/thread_cache.cc \ src/malloc_hook.cc src/malloc_extension.cc \ src/maybe_threads.cc src/common.h src/internal_logging.h \ src/system-alloc.h src/packed-cache-inl.h src/base/spinlock.h \ src/base/spinlock_internal.h src/base/atomicops.h \ src/base/atomicops-internals-macosx.h \ src/base/atomicops-internals-linuxppc.h \ src/base/atomicops-internals-x86-msvc.h \ src/base/atomicops-internals-x86.h \ src/base/spinlock_win32-inl.h src/base/spinlock_linux-inl.h \ src/base/spinlock_posix-inl.h \ src/base/synchronization_profiling.h \ src/base/atomicops-internals-arm-gcc.h src/tcmalloc_guard.h \ src/base/commandlineflags.h src/base/basictypes.h \ src/pagemap.h src/sampler.h src/central_freelist.h \ src/linked_list.h src/page_heap.h src/page_heap_allocator.h \ src/span.h src/static_vars.h src/symbolize.h \ src/thread_cache.h src/stack_trace_table.h \ src/base/thread_annotations.h src/malloc_hook-inl.h \ src/maybe_threads.h src/google/malloc_hook.h \ src/google/malloc_hook_c.h src/google/malloc_extension.h \ src/google/malloc_extension_c.h src/google/stacktrace.h @MINGW_FALSE@am__objects_23 = \ @MINGW_FALSE@ libtcmalloc_minimal_internal_la-system-alloc.lo @MINGW_FALSE@am__objects_24 = \ @MINGW_FALSE@ libtcmalloc_minimal_internal_la-maybe_threads.lo am_libtcmalloc_minimal_internal_la_OBJECTS = \ libtcmalloc_minimal_internal_la-common.lo \ libtcmalloc_minimal_internal_la-internal_logging.lo \ $(am__objects_23) \ libtcmalloc_minimal_internal_la-memfs_malloc.lo \ libtcmalloc_minimal_internal_la-central_freelist.lo \ libtcmalloc_minimal_internal_la-page_heap.lo \ libtcmalloc_minimal_internal_la-sampler.lo \ libtcmalloc_minimal_internal_la-span.lo \ libtcmalloc_minimal_internal_la-stack_trace_table.lo \ libtcmalloc_minimal_internal_la-static_vars.lo \ libtcmalloc_minimal_internal_la-symbolize.lo \ libtcmalloc_minimal_internal_la-thread_cache.lo \ libtcmalloc_minimal_internal_la-malloc_hook.lo \ libtcmalloc_minimal_internal_la-malloc_extension.lo \ $(am__objects_24) $(am__objects_20) libtcmalloc_minimal_internal_la_OBJECTS = \ $(am_libtcmalloc_minimal_internal_la_OBJECTS) libwindows_la_DEPENDENCIES = am__libwindows_la_SOURCES_DIST = src/windows/port.h \ src/windows/mingw.h src/windows/mini_disassembler.h \ src/windows/mini_disassembler_types.h \ src/windows/preamble_patcher.h src/windows/port.cc \ src/windows/ia32_modrm_map.cc src/windows/ia32_opcode_map.cc \ src/windows/mini_disassembler.cc \ src/windows/patch_functions.cc src/windows/preamble_patcher.cc \ src/windows/preamble_patcher_with_stub.cc @MINGW_TRUE@am_libwindows_la_OBJECTS = $(am__objects_1) port.lo \ @MINGW_TRUE@ ia32_modrm_map.lo ia32_opcode_map.lo \ @MINGW_TRUE@ mini_disassembler.lo patch_functions.lo \ @MINGW_TRUE@ preamble_patcher.lo preamble_patcher_with_stub.lo libwindows_la_OBJECTS = $(am_libwindows_la_OBJECTS) @MINGW_TRUE@am_libwindows_la_rpath = binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) @WITH_DEBUGALLOC_TRUE@am__EXEEXT_1 = debugallocation_test$(EXEEXT) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_2 = \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampling_test$(EXEEXT) @WITH_HEAP_PROFILER_TRUE@am__EXEEXT_3 = \ @WITH_HEAP_PROFILER_TRUE@ heap-profiler_unittest$(EXEEXT) @WITH_HEAP_CHECKER_TRUE@am__EXEEXT_4 = heap-checker_unittest$(EXEEXT) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_5 = sampling_debug_test$(EXEEXT) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@am__EXEEXT_6 = heap-profiler_debug_unittest$(EXEEXT) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@am__EXEEXT_7 = heap-checker_debug_unittest$(EXEEXT) @WITH_CPU_PROFILER_TRUE@am__EXEEXT_8 = profiler1_unittest$(EXEEXT) \ @WITH_CPU_PROFILER_TRUE@ profiler2_unittest$(EXEEXT) \ @WITH_CPU_PROFILER_TRUE@ profiler3_unittest$(EXEEXT) \ @WITH_CPU_PROFILER_TRUE@ profiler4_unittest$(EXEEXT) @WITH_STACK_TRACE_TRUE@am__EXEEXT_9 = stacktrace_unittest$(EXEEXT) @ENABLE_STATIC_FALSE@@MINGW_FALSE@am__EXEEXT_10 = maybe_threads_unittest.sh$(EXEEXT) @MINGW_FALSE@am__EXEEXT_11 = system_alloc_unittest$(EXEEXT) @ENABLE_STATIC_FALSE@@MINGW_FALSE@am__EXEEXT_12 = malloc_extension_c_test$(EXEEXT) @MINGW_FALSE@am__EXEEXT_13 = memalign_unittest$(EXEEXT) @WITH_DEBUGALLOC_TRUE@am__EXEEXT_14 = tcmalloc_minimal_debug_unittest$(EXEEXT) \ @WITH_DEBUGALLOC_TRUE@ malloc_extension_debug_test$(EXEEXT) \ @WITH_DEBUGALLOC_TRUE@ memalign_debug_unittest$(EXEEXT) \ @WITH_DEBUGALLOC_TRUE@ realloc_debug_unittest$(EXEEXT) \ @WITH_DEBUGALLOC_TRUE@ debugallocation_test.sh$(EXEEXT) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_15 = tcmalloc_unittest$(EXEEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_both_unittest$(EXEEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_large_unittest$(EXEEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ raw_printer_test$(EXEEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampler_test$(EXEEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampling_test.sh$(EXEEXT) @WITH_HEAP_PROFILER_TRUE@am__EXEEXT_16 = \ @WITH_HEAP_PROFILER_TRUE@ heap-profiler_unittest.sh$(EXEEXT) @WITH_HEAP_CHECKER_TRUE@am__EXEEXT_17 = \ @WITH_HEAP_CHECKER_TRUE@ heap-checker_unittest.sh$(EXEEXT) \ @WITH_HEAP_CHECKER_TRUE@ heap-checker-death_unittest.sh$(EXEEXT) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_18 = tcmalloc_debug_unittest$(EXEEXT) \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampler_debug_test$(EXEEXT) \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampling_debug_test.sh$(EXEEXT) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@am__EXEEXT_19 = heap-profiler_debug_unittest.sh$(EXEEXT) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@am__EXEEXT_20 = heap-checker_debug_unittest.sh$(EXEEXT) @WITH_CPU_PROFILER_TRUE@am__EXEEXT_21 = getpc_test$(EXEEXT) \ @WITH_CPU_PROFILER_TRUE@ profiledata_unittest$(EXEEXT) \ @WITH_CPU_PROFILER_TRUE@ profile_handler_unittest$(EXEEXT) \ @WITH_CPU_PROFILER_TRUE@ profiler_unittest.sh$(EXEEXT) @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_22 = tcmalloc_and_profiler_unittest$(EXEEXT) am__EXEEXT_23 = low_level_alloc_unittest$(EXEEXT) \ atomicops_unittest$(EXEEXT) $(am__EXEEXT_9) \ tcmalloc_minimal_unittest$(EXEEXT) \ tcmalloc_minimal_large_unittest$(EXEEXT) $(am__EXEEXT_10) \ addressmap_unittest$(EXEEXT) $(am__EXEEXT_11) \ packed_cache_test$(EXEEXT) frag_unittest$(EXEEXT) \ markidle_unittest$(EXEEXT) malloc_extension_test$(EXEEXT) \ $(am__EXEEXT_12) $(am__EXEEXT_13) page_heap_test$(EXEEXT) \ pagemap_unittest$(EXEEXT) realloc_unittest$(EXEEXT) \ stack_trace_table_test$(EXEEXT) \ thread_dealloc_unittest$(EXEEXT) $(am__EXEEXT_14) \ $(am__EXEEXT_15) $(am__EXEEXT_16) $(am__EXEEXT_17) \ $(am__EXEEXT_18) $(am__EXEEXT_19) $(am__EXEEXT_20) \ $(am__EXEEXT_21) $(am__EXEEXT_22) PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) am__addressmap_unittest_SOURCES_DIST = \ src/tests/addressmap_unittest.cc src/addressmap-inl.h \ src/base/commandlineflags.h src/base/logging.h \ src/base/basictypes.h src/base/dynamic_annotations.h \ src/third_party/valgrind.h src/windows/port.h \ src/windows/port.cc @MINGW_TRUE@am__objects_25 = addressmap_unittest-port.$(OBJEXT) am_addressmap_unittest_OBJECTS = \ addressmap_unittest-addressmap_unittest.$(OBJEXT) \ $(am__objects_6) $(am__objects_25) addressmap_unittest_OBJECTS = $(am_addressmap_unittest_OBJECTS) addressmap_unittest_DEPENDENCIES = liblogging.la am_atomicops_unittest_OBJECTS = atomicops_unittest.$(OBJEXT) \ $(am__objects_6) atomicops_unittest_OBJECTS = $(am_atomicops_unittest_OBJECTS) atomicops_unittest_DEPENDENCIES = $(am__DEPENDENCIES_2) am__debugallocation_test_SOURCES_DIST = \ src/tests/debugallocation_test.cc @WITH_DEBUGALLOC_TRUE@am_debugallocation_test_OBJECTS = debugallocation_test-debugallocation_test.$(OBJEXT) debugallocation_test_OBJECTS = $(am_debugallocation_test_OBJECTS) @WITH_DEBUGALLOC_TRUE@debugallocation_test_DEPENDENCIES = \ @WITH_DEBUGALLOC_TRUE@ libtcmalloc_debug.la \ @WITH_DEBUGALLOC_TRUE@ $(am__DEPENDENCIES_1) am__debugallocation_test_sh_SOURCES_DIST = \ src/tests/debugallocation_test.sh am_debugallocation_test_sh_OBJECTS = debugallocation_test_sh_OBJECTS = \ $(am_debugallocation_test_sh_OBJECTS) debugallocation_test_sh_LDADD = $(LDADD) am_frag_unittest_OBJECTS = frag_unittest-frag_unittest.$(OBJEXT) frag_unittest_OBJECTS = $(am_frag_unittest_OBJECTS) @MINGW_FALSE@am__DEPENDENCIES_5 = libtcmalloc_minimal.la @MINGW_TRUE@am__DEPENDENCIES_5 = libtcmalloc_minimal.la \ @MINGW_TRUE@ libstacktrace.la frag_unittest_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_1) am__getpc_test_SOURCES_DIST = src/tests/getpc_test.cc src/getpc.h @WITH_CPU_PROFILER_TRUE@am_getpc_test_OBJECTS = getpc_test.$(OBJEXT) getpc_test_OBJECTS = $(am_getpc_test_OBJECTS) getpc_test_LDADD = $(LDADD) am__heap_checker_death_unittest_sh_SOURCES_DIST = \ src/tests/heap-checker-death_unittest.sh am_heap_checker_death_unittest_sh_OBJECTS = heap_checker_death_unittest_sh_OBJECTS = \ $(am_heap_checker_death_unittest_sh_OBJECTS) heap_checker_death_unittest_sh_LDADD = $(LDADD) am__heap_checker_debug_unittest_SOURCES_DIST = \ src/tests/heap-checker_unittest.cc src/config_for_unittests.h \ src/memory_region_map.h src/base/commandlineflags.h \ src/base/googleinit.h src/google/heap-checker.h \ src/base/logging.h src/base/basictypes.h \ src/base/dynamic_annotations.h src/third_party/valgrind.h @WITH_HEAP_CHECKER_TRUE@am__objects_26 = $(am__objects_1) @WITH_HEAP_CHECKER_TRUE@am__objects_27 = heap_checker_debug_unittest-heap-checker_unittest.$(OBJEXT) \ @WITH_HEAP_CHECKER_TRUE@ $(am__objects_26) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@am_heap_checker_debug_unittest_OBJECTS = $(am__objects_27) heap_checker_debug_unittest_OBJECTS = \ $(am_heap_checker_debug_unittest_OBJECTS) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@heap_checker_debug_unittest_DEPENDENCIES = libtcmalloc_debug.la \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@ liblogging.la \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@ $(am__DEPENDENCIES_1) am__heap_checker_debug_unittest_sh_SOURCES_DIST = \ src/tests/heap-checker_unittest.sh am_heap_checker_debug_unittest_sh_OBJECTS = heap_checker_debug_unittest_sh_OBJECTS = \ $(am_heap_checker_debug_unittest_sh_OBJECTS) heap_checker_debug_unittest_sh_LDADD = $(LDADD) am__heap_checker_unittest_SOURCES_DIST = \ src/tests/heap-checker_unittest.cc src/config_for_unittests.h \ src/memory_region_map.h src/base/commandlineflags.h \ src/base/googleinit.h src/google/heap-checker.h \ src/base/logging.h src/base/basictypes.h \ src/base/dynamic_annotations.h src/third_party/valgrind.h @WITH_HEAP_CHECKER_TRUE@am_heap_checker_unittest_OBJECTS = heap_checker_unittest-heap-checker_unittest.$(OBJEXT) \ @WITH_HEAP_CHECKER_TRUE@ $(am__objects_26) heap_checker_unittest_OBJECTS = $(am_heap_checker_unittest_OBJECTS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__DEPENDENCIES_6 = \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc.la @WITH_HEAP_CHECKER_TRUE@heap_checker_unittest_DEPENDENCIES = \ @WITH_HEAP_CHECKER_TRUE@ $(am__DEPENDENCIES_6) liblogging.la \ @WITH_HEAP_CHECKER_TRUE@ $(am__DEPENDENCIES_1) am__heap_checker_unittest_sh_SOURCES_DIST = \ src/tests/heap-checker_unittest.sh am_heap_checker_unittest_sh_OBJECTS = heap_checker_unittest_sh_OBJECTS = \ $(am_heap_checker_unittest_sh_OBJECTS) heap_checker_unittest_sh_LDADD = $(LDADD) am__heap_profiler_debug_unittest_SOURCES_DIST = \ src/tests/heap-profiler_unittest.cc src/config_for_unittests.h \ src/google/heap-profiler.h @WITH_HEAP_PROFILER_TRUE@am__objects_28 = heap_profiler_debug_unittest-heap-profiler_unittest.$(OBJEXT) \ @WITH_HEAP_PROFILER_TRUE@ $(am__objects_1) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@am_heap_profiler_debug_unittest_OBJECTS = $(am__objects_28) heap_profiler_debug_unittest_OBJECTS = \ $(am_heap_profiler_debug_unittest_OBJECTS) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@heap_profiler_debug_unittest_DEPENDENCIES = libtcmalloc_debug.la \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@ $(am__DEPENDENCIES_1) am__heap_profiler_debug_unittest_sh_SOURCES_DIST = \ src/tests/heap-profiler_unittest.sh am_heap_profiler_debug_unittest_sh_OBJECTS = heap_profiler_debug_unittest_sh_OBJECTS = \ $(am_heap_profiler_debug_unittest_sh_OBJECTS) heap_profiler_debug_unittest_sh_LDADD = $(LDADD) am__heap_profiler_unittest_SOURCES_DIST = \ src/tests/heap-profiler_unittest.cc src/config_for_unittests.h \ src/google/heap-profiler.h @WITH_HEAP_PROFILER_TRUE@am_heap_profiler_unittest_OBJECTS = heap_profiler_unittest-heap-profiler_unittest.$(OBJEXT) \ @WITH_HEAP_PROFILER_TRUE@ $(am__objects_1) heap_profiler_unittest_OBJECTS = $(am_heap_profiler_unittest_OBJECTS) @WITH_HEAP_PROFILER_TRUE@heap_profiler_unittest_DEPENDENCIES = \ @WITH_HEAP_PROFILER_TRUE@ $(am__DEPENDENCIES_6) \ @WITH_HEAP_PROFILER_TRUE@ $(am__DEPENDENCIES_1) am__heap_profiler_unittest_sh_SOURCES_DIST = \ src/tests/heap-profiler_unittest.sh am_heap_profiler_unittest_sh_OBJECTS = heap_profiler_unittest_sh_OBJECTS = \ $(am_heap_profiler_unittest_sh_OBJECTS) heap_profiler_unittest_sh_LDADD = $(LDADD) am__low_level_alloc_unittest_SOURCES_DIST = \ src/base/low_level_alloc.cc src/malloc_hook.cc \ src/tests/low_level_alloc_unittest.cc \ src/base/low_level_alloc.h src/base/basictypes.h \ src/google/malloc_hook.h src/google/malloc_hook_c.h \ src/malloc_hook-inl.h src/base/spinlock.h \ src/base/spinlock_internal.h src/base/atomicops.h \ src/base/atomicops-internals-macosx.h \ src/base/atomicops-internals-linuxppc.h \ src/base/atomicops-internals-x86-msvc.h \ src/base/atomicops-internals-x86.h \ src/base/spinlock_win32-inl.h src/base/spinlock_linux-inl.h \ src/base/spinlock_posix-inl.h \ src/base/synchronization_profiling.h \ src/base/atomicops-internals-arm-gcc.h src/base/logging.h \ src/base/commandlineflags.h src/base/dynamic_annotations.h \ src/third_party/valgrind.h am__objects_29 = $(am__objects_1) $(am__objects_1) am_low_level_alloc_unittest_OBJECTS = \ low_level_alloc_unittest-low_level_alloc.$(OBJEXT) \ low_level_alloc_unittest-malloc_hook.$(OBJEXT) \ low_level_alloc_unittest-low_level_alloc_unittest.$(OBJEXT) \ $(am__objects_29) low_level_alloc_unittest_OBJECTS = \ $(am_low_level_alloc_unittest_OBJECTS) low_level_alloc_unittest_DEPENDENCIES = $(am__DEPENDENCIES_2) am__malloc_extension_c_test_SOURCES_DIST = \ src/tests/malloc_extension_c_test.c \ src/google/malloc_extension.h src/google/malloc_extension_c.h @ENABLE_STATIC_FALSE@@MINGW_FALSE@am_malloc_extension_c_test_OBJECTS = malloc_extension_c_test-malloc_extension_c_test.$(OBJEXT) malloc_extension_c_test_OBJECTS = \ $(am_malloc_extension_c_test_OBJECTS) @ENABLE_STATIC_FALSE@@MINGW_FALSE@malloc_extension_c_test_DEPENDENCIES = \ @ENABLE_STATIC_FALSE@@MINGW_FALSE@ $(am__DEPENDENCIES_5) \ @ENABLE_STATIC_FALSE@@MINGW_FALSE@ $(am__DEPENDENCIES_1) am__malloc_extension_debug_test_SOURCES_DIST = \ src/tests/malloc_extension_test.cc src/config_for_unittests.h \ src/base/logging.h src/google/malloc_extension.h \ src/google/malloc_extension_c.h am__objects_30 = \ malloc_extension_debug_test-malloc_extension_test.$(OBJEXT) @WITH_DEBUGALLOC_TRUE@am_malloc_extension_debug_test_OBJECTS = \ @WITH_DEBUGALLOC_TRUE@ $(am__objects_30) malloc_extension_debug_test_OBJECTS = \ $(am_malloc_extension_debug_test_OBJECTS) @WITH_DEBUGALLOC_TRUE@malloc_extension_debug_test_DEPENDENCIES = \ @WITH_DEBUGALLOC_TRUE@ libtcmalloc_minimal_debug.la \ @WITH_DEBUGALLOC_TRUE@ $(am__DEPENDENCIES_1) am_malloc_extension_test_OBJECTS = \ malloc_extension_test-malloc_extension_test.$(OBJEXT) malloc_extension_test_OBJECTS = $(am_malloc_extension_test_OBJECTS) malloc_extension_test_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_1) am_markidle_unittest_OBJECTS = \ markidle_unittest-markidle_unittest.$(OBJEXT) \ markidle_unittest-testutil.$(OBJEXT) markidle_unittest_OBJECTS = $(am_markidle_unittest_OBJECTS) markidle_unittest_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_1) am__maybe_threads_unittest_sh_SOURCES_DIST = \ src/tests/maybe_threads_unittest.sh am_maybe_threads_unittest_sh_OBJECTS = maybe_threads_unittest_sh_OBJECTS = \ $(am_maybe_threads_unittest_sh_OBJECTS) maybe_threads_unittest_sh_LDADD = $(LDADD) am__memalign_debug_unittest_SOURCES_DIST = \ src/tests/memalign_unittest.cc src/tcmalloc.h \ src/config_for_unittests.h src/tests/testutil.h \ src/tests/testutil.cc @MINGW_FALSE@am__objects_31 = memalign_debug_unittest-memalign_unittest.$(OBJEXT) \ @MINGW_FALSE@ memalign_debug_unittest-testutil.$(OBJEXT) @WITH_DEBUGALLOC_TRUE@am_memalign_debug_unittest_OBJECTS = \ @WITH_DEBUGALLOC_TRUE@ $(am__objects_31) memalign_debug_unittest_OBJECTS = \ $(am_memalign_debug_unittest_OBJECTS) @WITH_DEBUGALLOC_TRUE@memalign_debug_unittest_DEPENDENCIES = \ @WITH_DEBUGALLOC_TRUE@ libtcmalloc_minimal_debug.la \ @WITH_DEBUGALLOC_TRUE@ $(am__DEPENDENCIES_1) am__memalign_unittest_SOURCES_DIST = src/tests/memalign_unittest.cc \ src/tcmalloc.h src/config_for_unittests.h src/tests/testutil.h \ src/tests/testutil.cc @MINGW_FALSE@am_memalign_unittest_OBJECTS = \ @MINGW_FALSE@ memalign_unittest-memalign_unittest.$(OBJEXT) \ @MINGW_FALSE@ memalign_unittest-testutil.$(OBJEXT) memalign_unittest_OBJECTS = $(am_memalign_unittest_OBJECTS) @MINGW_FALSE@memalign_unittest_DEPENDENCIES = $(am__DEPENDENCIES_5) \ @MINGW_FALSE@ $(am__DEPENDENCIES_1) am_packed_cache_test_OBJECTS = \ packed_cache_test-packed-cache_test.$(OBJEXT) packed_cache_test_OBJECTS = $(am_packed_cache_test_OBJECTS) packed_cache_test_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_1) am_page_heap_test_OBJECTS = page_heap_test-page_heap_test.$(OBJEXT) page_heap_test_OBJECTS = $(am_page_heap_test_OBJECTS) page_heap_test_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_1) am_pagemap_unittest_OBJECTS = \ pagemap_unittest-pagemap_unittest.$(OBJEXT) pagemap_unittest_OBJECTS = $(am_pagemap_unittest_OBJECTS) pagemap_unittest_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_1) am__profile_handler_unittest_SOURCES_DIST = \ src/tests/profile-handler_unittest.cc src/profile-handler.h @WITH_CPU_PROFILER_TRUE@am_profile_handler_unittest_OBJECTS = profile_handler_unittest-profile-handler_unittest.$(OBJEXT) profile_handler_unittest_OBJECTS = \ $(am_profile_handler_unittest_OBJECTS) @WITH_CPU_PROFILER_TRUE@am__DEPENDENCIES_7 = libstacktrace.la \ @WITH_CPU_PROFILER_TRUE@ libprofiler.la @WITH_CPU_PROFILER_TRUE@profile_handler_unittest_DEPENDENCIES = \ @WITH_CPU_PROFILER_TRUE@ $(am__DEPENDENCIES_7) \ @WITH_CPU_PROFILER_TRUE@ $(am__DEPENDENCIES_1) am__profiledata_unittest_SOURCES_DIST = \ src/tests/profiledata_unittest.cc src/profiledata.h \ src/base/commandlineflags.h src/base/logging.h \ src/base/basictypes.h @WITH_CPU_PROFILER_TRUE@am_profiledata_unittest_OBJECTS = \ @WITH_CPU_PROFILER_TRUE@ profiledata_unittest.$(OBJEXT) profiledata_unittest_OBJECTS = $(am_profiledata_unittest_OBJECTS) @WITH_CPU_PROFILER_TRUE@profiledata_unittest_DEPENDENCIES = \ @WITH_CPU_PROFILER_TRUE@ $(am__DEPENDENCIES_7) am__profiler1_unittest_SOURCES_DIST = src/tests/profiler_unittest.cc \ src/tests/testutil.h src/tests/testutil.cc \ src/config_for_unittests.h src/google/profiler.h @WITH_CPU_PROFILER_TRUE@am__objects_32 = profiler1_unittest-profiler_unittest.$(OBJEXT) \ @WITH_CPU_PROFILER_TRUE@ profiler1_unittest-testutil.$(OBJEXT) \ @WITH_CPU_PROFILER_TRUE@ $(am__objects_1) @WITH_CPU_PROFILER_TRUE@am_profiler1_unittest_OBJECTS = \ @WITH_CPU_PROFILER_TRUE@ $(am__objects_32) profiler1_unittest_OBJECTS = $(am_profiler1_unittest_OBJECTS) @WITH_CPU_PROFILER_TRUE@profiler1_unittest_DEPENDENCIES = \ @WITH_CPU_PROFILER_TRUE@ $(am__DEPENDENCIES_7) am__profiler2_unittest_SOURCES_DIST = src/tests/profiler_unittest.cc \ src/tests/testutil.h src/tests/testutil.cc \ src/config_for_unittests.h src/google/profiler.h @WITH_CPU_PROFILER_TRUE@am__objects_33 = profiler2_unittest-profiler_unittest.$(OBJEXT) \ @WITH_CPU_PROFILER_TRUE@ profiler2_unittest-testutil.$(OBJEXT) \ @WITH_CPU_PROFILER_TRUE@ $(am__objects_1) @WITH_CPU_PROFILER_TRUE@am_profiler2_unittest_OBJECTS = \ @WITH_CPU_PROFILER_TRUE@ $(am__objects_33) profiler2_unittest_OBJECTS = $(am_profiler2_unittest_OBJECTS) am__profiler3_unittest_SOURCES_DIST = src/tests/profiler_unittest.cc \ src/tests/testutil.h src/tests/testutil.cc \ src/config_for_unittests.h src/google/profiler.h @WITH_CPU_PROFILER_TRUE@am__objects_34 = profiler3_unittest-profiler_unittest.$(OBJEXT) \ @WITH_CPU_PROFILER_TRUE@ profiler3_unittest-testutil.$(OBJEXT) \ @WITH_CPU_PROFILER_TRUE@ $(am__objects_1) @WITH_CPU_PROFILER_TRUE@am_profiler3_unittest_OBJECTS = \ @WITH_CPU_PROFILER_TRUE@ $(am__objects_34) profiler3_unittest_OBJECTS = $(am_profiler3_unittest_OBJECTS) @WITH_CPU_PROFILER_TRUE@profiler3_unittest_DEPENDENCIES = \ @WITH_CPU_PROFILER_TRUE@ $(am__DEPENDENCIES_7) \ @WITH_CPU_PROFILER_TRUE@ $(am__DEPENDENCIES_1) am__profiler4_unittest_SOURCES_DIST = src/tests/profiler_unittest.cc \ src/tests/testutil.h src/tests/testutil.cc \ src/config_for_unittests.h src/google/profiler.h @WITH_CPU_PROFILER_TRUE@am__objects_35 = profiler4_unittest-profiler_unittest.$(OBJEXT) \ @WITH_CPU_PROFILER_TRUE@ profiler4_unittest-testutil.$(OBJEXT) \ @WITH_CPU_PROFILER_TRUE@ $(am__objects_1) @WITH_CPU_PROFILER_TRUE@am_profiler4_unittest_OBJECTS = \ @WITH_CPU_PROFILER_TRUE@ $(am__objects_35) profiler4_unittest_OBJECTS = $(am_profiler4_unittest_OBJECTS) am__profiler_unittest_sh_SOURCES_DIST = \ src/tests/profiler_unittest.sh am_profiler_unittest_sh_OBJECTS = profiler_unittest_sh_OBJECTS = $(am_profiler_unittest_sh_OBJECTS) profiler_unittest_sh_LDADD = $(LDADD) am__raw_printer_test_SOURCES_DIST = src/tests/raw_printer_test.cc @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_raw_printer_test_OBJECTS = raw_printer_test-raw_printer_test.$(OBJEXT) raw_printer_test_OBJECTS = $(am_raw_printer_test_OBJECTS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@raw_printer_test_DEPENDENCIES = \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_6) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1) am__realloc_debug_unittest_SOURCES_DIST = \ src/tests/realloc_unittest.cc src/config_for_unittests.h \ src/base/logging.h am__objects_36 = realloc_debug_unittest-realloc_unittest.$(OBJEXT) @WITH_DEBUGALLOC_TRUE@am_realloc_debug_unittest_OBJECTS = \ @WITH_DEBUGALLOC_TRUE@ $(am__objects_36) realloc_debug_unittest_OBJECTS = $(am_realloc_debug_unittest_OBJECTS) @WITH_DEBUGALLOC_TRUE@realloc_debug_unittest_DEPENDENCIES = \ @WITH_DEBUGALLOC_TRUE@ libtcmalloc_minimal_debug.la \ @WITH_DEBUGALLOC_TRUE@ $(am__DEPENDENCIES_1) am_realloc_unittest_OBJECTS = \ realloc_unittest-realloc_unittest.$(OBJEXT) realloc_unittest_OBJECTS = $(am_realloc_unittest_OBJECTS) realloc_unittest_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_1) am__sampler_debug_test_SOURCES_DIST = src/tests/sampler_test.cc \ src/config_for_unittests.h @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_37 = sampler_debug_test-sampler_test.$(OBJEXT) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_sampler_debug_test_OBJECTS = $(am__objects_37) sampler_debug_test_OBJECTS = $(am_sampler_debug_test_OBJECTS) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampler_debug_test_DEPENDENCIES = libtcmalloc_debug.la \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1) am__sampler_test_SOURCES_DIST = src/tests/sampler_test.cc \ src/config_for_unittests.h @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_sampler_test_OBJECTS = sampler_test-sampler_test.$(OBJEXT) sampler_test_OBJECTS = $(am_sampler_test_OBJECTS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampler_test_DEPENDENCIES = \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_6) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1) am__sampling_debug_test_SOURCES_DIST = src/tests/sampling_test.cc \ src/config_for_unittests.h src/base/logging.h \ src/google/malloc_extension.h @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_38 = sampling_debug_test-sampling_test.$(OBJEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_1) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_sampling_debug_test_OBJECTS = $(am__objects_38) sampling_debug_test_OBJECTS = $(am_sampling_debug_test_OBJECTS) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_debug_test_DEPENDENCIES = libtcmalloc_debug.la \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1) am__sampling_debug_test_sh_SOURCES_DIST = src/tests/sampling_test.sh am_sampling_debug_test_sh_OBJECTS = sampling_debug_test_sh_OBJECTS = $(am_sampling_debug_test_sh_OBJECTS) sampling_debug_test_sh_LDADD = $(LDADD) am__sampling_test_SOURCES_DIST = src/tests/sampling_test.cc \ src/config_for_unittests.h src/base/logging.h \ src/google/malloc_extension.h @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_sampling_test_OBJECTS = sampling_test-sampling_test.$(OBJEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_1) sampling_test_OBJECTS = $(am_sampling_test_OBJECTS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_test_DEPENDENCIES = \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_6) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1) am__sampling_test_sh_SOURCES_DIST = src/tests/sampling_test.sh am_sampling_test_sh_OBJECTS = sampling_test_sh_OBJECTS = $(am_sampling_test_sh_OBJECTS) sampling_test_sh_LDADD = $(LDADD) am_stack_trace_table_test_OBJECTS = \ stack_trace_table_test-stack_trace_table_test.$(OBJEXT) stack_trace_table_test_OBJECTS = $(am_stack_trace_table_test_OBJECTS) stack_trace_table_test_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_1) am__stacktrace_unittest_SOURCES_DIST = \ src/tests/stacktrace_unittest.cc src/config_for_unittests.h \ src/base/commandlineflags.h src/stacktrace_config.h \ src/stacktrace_generic-inl.h src/stacktrace_libunwind-inl.h \ src/stacktrace_powerpc-inl.h src/stacktrace_x86_64-inl.h \ src/stacktrace_x86-inl.h src/stacktrace_win32-inl.h \ src/base/vdso_support.h src/google/stacktrace.h \ src/base/logging.h src/base/basictypes.h \ src/base/dynamic_annotations.h src/third_party/valgrind.h @WITH_STACK_TRACE_TRUE@am__objects_39 = $(am__objects_4) \ @WITH_STACK_TRACE_TRUE@ $(am__objects_1) @WITH_STACK_TRACE_TRUE@am_stacktrace_unittest_OBJECTS = \ @WITH_STACK_TRACE_TRUE@ stacktrace_unittest.$(OBJEXT) \ @WITH_STACK_TRACE_TRUE@ $(am__objects_39) stacktrace_unittest_OBJECTS = $(am_stacktrace_unittest_OBJECTS) @WITH_STACK_TRACE_TRUE@stacktrace_unittest_DEPENDENCIES = \ @WITH_STACK_TRACE_TRUE@ libstacktrace.la liblogging.la am__system_alloc_unittest_SOURCES_DIST = src/config_for_unittests.h \ src/tests/system-alloc_unittest.cc @MINGW_FALSE@am_system_alloc_unittest_OBJECTS = system_alloc_unittest-system-alloc_unittest.$(OBJEXT) system_alloc_unittest_OBJECTS = $(am_system_alloc_unittest_OBJECTS) @MINGW_FALSE@system_alloc_unittest_DEPENDENCIES = \ @MINGW_FALSE@ $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_1) am__tcmalloc_and_profiler_unittest_SOURCES_DIST = \ src/tests/tcmalloc_unittest.cc src/tests/testutil.h \ src/tests/testutil.cc src/config_for_unittests.h \ src/google/malloc_extension.h @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_40 = tcmalloc_and_profiler_unittest-tcmalloc_unittest.$(OBJEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_and_profiler_unittest-testutil.$(OBJEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_1) @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_tcmalloc_and_profiler_unittest_OBJECTS = $(am__objects_40) tcmalloc_and_profiler_unittest_OBJECTS = \ $(am_tcmalloc_and_profiler_unittest_OBJECTS) @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_and_profiler_unittest_DEPENDENCIES = libtcmalloc_and_profiler.la am__tcmalloc_both_unittest_SOURCES_DIST = \ src/tests/tcmalloc_unittest.cc src/tests/testutil.h \ src/tests/testutil.cc src/config_for_unittests.h \ src/google/malloc_extension.h @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_tcmalloc_both_unittest_OBJECTS = tcmalloc_both_unittest-tcmalloc_unittest.$(OBJEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_both_unittest-testutil.$(OBJEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_1) tcmalloc_both_unittest_OBJECTS = $(am_tcmalloc_both_unittest_OBJECTS) @WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_DEPENDENCIES = $(am__DEPENDENCIES_6) \ @WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_5) \ @WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ liblogging.la \ @WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1) @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_DEPENDENCIES = $(am__DEPENDENCIES_6) \ @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_5) \ @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libprofiler.la \ @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ liblogging.la \ @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1) am__tcmalloc_debug_unittest_SOURCES_DIST = \ src/tests/tcmalloc_unittest.cc src/tcmalloc.h \ src/tests/testutil.h src/tests/testutil.cc \ src/config_for_unittests.h src/google/malloc_extension.h @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_41 = tcmalloc_debug_unittest-tcmalloc_unittest.$(OBJEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_debug_unittest-testutil.$(OBJEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_1) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_tcmalloc_debug_unittest_OBJECTS = $(am__objects_41) tcmalloc_debug_unittest_OBJECTS = \ $(am_tcmalloc_debug_unittest_OBJECTS) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_debug_unittest_DEPENDENCIES = libtcmalloc_debug.la \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1) am__tcmalloc_large_unittest_SOURCES_DIST = \ src/tests/tcmalloc_large_unittest.cc @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_tcmalloc_large_unittest_OBJECTS = tcmalloc_large_unittest-tcmalloc_large_unittest.$(OBJEXT) tcmalloc_large_unittest_OBJECTS = \ $(am_tcmalloc_large_unittest_OBJECTS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_large_unittest_DEPENDENCIES = \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_6) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1) am__tcmalloc_minimal_debug_unittest_SOURCES_DIST = \ src/tests/tcmalloc_unittest.cc src/tests/testutil.h \ src/tests/testutil.cc src/config_for_unittests.h \ src/google/malloc_extension.h am__objects_42 = \ tcmalloc_minimal_debug_unittest-tcmalloc_unittest.$(OBJEXT) \ tcmalloc_minimal_debug_unittest-testutil.$(OBJEXT) \ $(am__objects_1) @WITH_DEBUGALLOC_TRUE@am_tcmalloc_minimal_debug_unittest_OBJECTS = \ @WITH_DEBUGALLOC_TRUE@ $(am__objects_42) tcmalloc_minimal_debug_unittest_OBJECTS = \ $(am_tcmalloc_minimal_debug_unittest_OBJECTS) @WITH_DEBUGALLOC_TRUE@tcmalloc_minimal_debug_unittest_DEPENDENCIES = \ @WITH_DEBUGALLOC_TRUE@ libtcmalloc_minimal_debug.la \ @WITH_DEBUGALLOC_TRUE@ $(am__DEPENDENCIES_1) am_tcmalloc_minimal_large_unittest_OBJECTS = tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.$(OBJEXT) tcmalloc_minimal_large_unittest_OBJECTS = \ $(am_tcmalloc_minimal_large_unittest_OBJECTS) tcmalloc_minimal_large_unittest_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_1) am__tcmalloc_minimal_unittest_SOURCES_DIST = \ src/tests/tcmalloc_unittest.cc src/tests/testutil.h \ src/tests/testutil.cc src/config_for_unittests.h \ src/google/malloc_extension.h am_tcmalloc_minimal_unittest_OBJECTS = \ tcmalloc_minimal_unittest-tcmalloc_unittest.$(OBJEXT) \ tcmalloc_minimal_unittest-testutil.$(OBJEXT) $(am__objects_1) tcmalloc_minimal_unittest_OBJECTS = \ $(am_tcmalloc_minimal_unittest_OBJECTS) tcmalloc_minimal_unittest_DEPENDENCIES = $(am__DEPENDENCIES_5) \ liblogging.la $(am__DEPENDENCIES_1) am__tcmalloc_unittest_SOURCES_DIST = src/tests/tcmalloc_unittest.cc \ src/tcmalloc.h src/tests/testutil.h src/tests/testutil.cc \ src/config_for_unittests.h src/google/malloc_extension.h @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_tcmalloc_unittest_OBJECTS = tcmalloc_unittest-tcmalloc_unittest.$(OBJEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_unittest-testutil.$(OBJEXT) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_1) tcmalloc_unittest_OBJECTS = $(am_tcmalloc_unittest_OBJECTS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_unittest_DEPENDENCIES = \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_6) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ liblogging.la \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1) am_thread_dealloc_unittest_OBJECTS = \ thread_dealloc_unittest-thread_dealloc_unittest.$(OBJEXT) \ thread_dealloc_unittest-testutil.$(OBJEXT) thread_dealloc_unittest_OBJECTS = \ $(am_thread_dealloc_unittest_OBJECTS) thread_dealloc_unittest_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_1) binSCRIPT_INSTALL = $(INSTALL_SCRIPT) SCRIPTS = $(bin_SCRIPTS) $(noinst_SCRIPTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/src depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(liblogging_la_SOURCES) $(libprofiler_la_SOURCES) \ $(libspinlock_la_SOURCES) $(libstacktrace_la_SOURCES) \ $(libsysinfo_la_SOURCES) $(libtcmalloc_la_SOURCES) \ $(libtcmalloc_and_profiler_la_SOURCES) \ $(libtcmalloc_debug_la_SOURCES) \ $(libtcmalloc_internal_la_SOURCES) \ $(libtcmalloc_minimal_la_SOURCES) \ $(libtcmalloc_minimal_debug_la_SOURCES) \ $(libtcmalloc_minimal_internal_la_SOURCES) \ $(libwindows_la_SOURCES) $(addressmap_unittest_SOURCES) \ $(atomicops_unittest_SOURCES) $(debugallocation_test_SOURCES) \ $(debugallocation_test_sh_SOURCES) $(frag_unittest_SOURCES) \ $(getpc_test_SOURCES) \ $(heap_checker_death_unittest_sh_SOURCES) \ $(heap_checker_debug_unittest_SOURCES) \ $(heap_checker_debug_unittest_sh_SOURCES) \ $(heap_checker_unittest_SOURCES) \ $(heap_checker_unittest_sh_SOURCES) \ $(heap_profiler_debug_unittest_SOURCES) \ $(heap_profiler_debug_unittest_sh_SOURCES) \ $(heap_profiler_unittest_SOURCES) \ $(heap_profiler_unittest_sh_SOURCES) \ $(low_level_alloc_unittest_SOURCES) \ $(malloc_extension_c_test_SOURCES) \ $(malloc_extension_debug_test_SOURCES) \ $(malloc_extension_test_SOURCES) $(markidle_unittest_SOURCES) \ $(maybe_threads_unittest_sh_SOURCES) \ $(memalign_debug_unittest_SOURCES) \ $(memalign_unittest_SOURCES) $(packed_cache_test_SOURCES) \ $(page_heap_test_SOURCES) $(pagemap_unittest_SOURCES) \ $(profile_handler_unittest_SOURCES) \ $(profiledata_unittest_SOURCES) $(profiler1_unittest_SOURCES) \ $(profiler2_unittest_SOURCES) $(profiler3_unittest_SOURCES) \ $(profiler4_unittest_SOURCES) $(profiler_unittest_sh_SOURCES) \ $(raw_printer_test_SOURCES) $(realloc_debug_unittest_SOURCES) \ $(realloc_unittest_SOURCES) $(sampler_debug_test_SOURCES) \ $(sampler_test_SOURCES) $(sampling_debug_test_SOURCES) \ $(sampling_debug_test_sh_SOURCES) $(sampling_test_SOURCES) \ $(sampling_test_sh_SOURCES) $(stack_trace_table_test_SOURCES) \ $(stacktrace_unittest_SOURCES) \ $(system_alloc_unittest_SOURCES) \ $(tcmalloc_and_profiler_unittest_SOURCES) \ $(tcmalloc_both_unittest_SOURCES) \ $(tcmalloc_debug_unittest_SOURCES) \ $(tcmalloc_large_unittest_SOURCES) \ $(tcmalloc_minimal_debug_unittest_SOURCES) \ $(tcmalloc_minimal_large_unittest_SOURCES) \ $(tcmalloc_minimal_unittest_SOURCES) \ $(tcmalloc_unittest_SOURCES) \ $(thread_dealloc_unittest_SOURCES) DIST_SOURCES = $(liblogging_la_SOURCES) \ $(am__libprofiler_la_SOURCES_DIST) \ $(am__libspinlock_la_SOURCES_DIST) \ $(am__libstacktrace_la_SOURCES_DIST) $(libsysinfo_la_SOURCES) \ $(am__libtcmalloc_la_SOURCES_DIST) \ $(am__libtcmalloc_and_profiler_la_SOURCES_DIST) \ $(am__libtcmalloc_debug_la_SOURCES_DIST) \ $(am__libtcmalloc_internal_la_SOURCES_DIST) \ $(am__libtcmalloc_minimal_la_SOURCES_DIST) \ $(am__libtcmalloc_minimal_debug_la_SOURCES_DIST) \ $(am__libtcmalloc_minimal_internal_la_SOURCES_DIST) \ $(am__libwindows_la_SOURCES_DIST) \ $(am__addressmap_unittest_SOURCES_DIST) \ $(atomicops_unittest_SOURCES) \ $(am__debugallocation_test_SOURCES_DIST) \ $(am__debugallocation_test_sh_SOURCES_DIST) \ $(frag_unittest_SOURCES) $(am__getpc_test_SOURCES_DIST) \ $(am__heap_checker_death_unittest_sh_SOURCES_DIST) \ $(am__heap_checker_debug_unittest_SOURCES_DIST) \ $(am__heap_checker_debug_unittest_sh_SOURCES_DIST) \ $(am__heap_checker_unittest_SOURCES_DIST) \ $(am__heap_checker_unittest_sh_SOURCES_DIST) \ $(am__heap_profiler_debug_unittest_SOURCES_DIST) \ $(am__heap_profiler_debug_unittest_sh_SOURCES_DIST) \ $(am__heap_profiler_unittest_SOURCES_DIST) \ $(am__heap_profiler_unittest_sh_SOURCES_DIST) \ $(am__low_level_alloc_unittest_SOURCES_DIST) \ $(am__malloc_extension_c_test_SOURCES_DIST) \ $(am__malloc_extension_debug_test_SOURCES_DIST) \ $(malloc_extension_test_SOURCES) $(markidle_unittest_SOURCES) \ $(am__maybe_threads_unittest_sh_SOURCES_DIST) \ $(am__memalign_debug_unittest_SOURCES_DIST) \ $(am__memalign_unittest_SOURCES_DIST) \ $(packed_cache_test_SOURCES) $(page_heap_test_SOURCES) \ $(pagemap_unittest_SOURCES) \ $(am__profile_handler_unittest_SOURCES_DIST) \ $(am__profiledata_unittest_SOURCES_DIST) \ $(am__profiler1_unittest_SOURCES_DIST) \ $(am__profiler2_unittest_SOURCES_DIST) \ $(am__profiler3_unittest_SOURCES_DIST) \ $(am__profiler4_unittest_SOURCES_DIST) \ $(am__profiler_unittest_sh_SOURCES_DIST) \ $(am__raw_printer_test_SOURCES_DIST) \ $(am__realloc_debug_unittest_SOURCES_DIST) \ $(realloc_unittest_SOURCES) \ $(am__sampler_debug_test_SOURCES_DIST) \ $(am__sampler_test_SOURCES_DIST) \ $(am__sampling_debug_test_SOURCES_DIST) \ $(am__sampling_debug_test_sh_SOURCES_DIST) \ $(am__sampling_test_SOURCES_DIST) \ $(am__sampling_test_sh_SOURCES_DIST) \ $(stack_trace_table_test_SOURCES) \ $(am__stacktrace_unittest_SOURCES_DIST) \ $(am__system_alloc_unittest_SOURCES_DIST) \ $(am__tcmalloc_and_profiler_unittest_SOURCES_DIST) \ $(am__tcmalloc_both_unittest_SOURCES_DIST) \ $(am__tcmalloc_debug_unittest_SOURCES_DIST) \ $(am__tcmalloc_large_unittest_SOURCES_DIST) \ $(am__tcmalloc_minimal_debug_unittest_SOURCES_DIST) \ $(tcmalloc_minimal_large_unittest_SOURCES) \ $(am__tcmalloc_minimal_unittest_SOURCES_DIST) \ $(am__tcmalloc_unittest_SOURCES_DIST) \ $(thread_dealloc_unittest_SOURCES) man1dir = $(mandir)/man1 NROFF = nroff MANS = $(dist_man_MANS) am__dist_doc_DATA_DIST = AUTHORS COPYING ChangeLog INSTALL NEWS README \ README_windows.txt TODO doc/index.html doc/designstyle.css \ doc/pprof_remote_servers.html doc/tcmalloc.html \ doc/overview.gif doc/pageheap.gif doc/spanmap.gif \ doc/threadheap.gif doc/t-test1.times.txt \ doc/tcmalloc-opspercpusec.vs.threads.1024.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.128.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.131072.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.16384.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.2048.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.256.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.32768.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.4096.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.512.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.64.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.65536.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.8192.bytes.png \ doc/tcmalloc-opspersec.vs.size.1.threads.png \ doc/tcmalloc-opspersec.vs.size.12.threads.png \ doc/tcmalloc-opspersec.vs.size.16.threads.png \ doc/tcmalloc-opspersec.vs.size.2.threads.png \ doc/tcmalloc-opspersec.vs.size.20.threads.png \ doc/tcmalloc-opspersec.vs.size.3.threads.png \ doc/tcmalloc-opspersec.vs.size.4.threads.png \ doc/tcmalloc-opspersec.vs.size.5.threads.png \ doc/tcmalloc-opspersec.vs.size.8.threads.png doc/overview.dot \ doc/pageheap.dot doc/spanmap.dot doc/threadheap.dot \ doc/heapprofile.html doc/heap-example1.png \ doc/heap_checker.html doc/cpuprofile.html \ doc/cpuprofile-fileformat.html doc/pprof-test-big.gif \ doc/pprof-test.gif doc/pprof-vsnprintf-big.gif \ doc/pprof-vsnprintf.gif dist_docDATA_INSTALL = $(INSTALL_DATA) pkgconfigDATA_INSTALL = $(INSTALL_DATA) DATA = $(dist_doc_DATA) $(pkgconfig_DATA) am__googleinclude_HEADERS_DIST = src/google/stacktrace.h \ src/google/malloc_hook.h src/google/malloc_hook_c.h \ src/google/malloc_extension.h src/google/malloc_extension_c.h \ src/google/heap-profiler.h src/google/heap-checker.h \ src/google/profiler.h googleincludeHEADERS_INSTALL = $(INSTALL_HEADER) nodist_googleincludeHEADERS_INSTALL = $(INSTALL_HEADER) HEADERS = $(googleinclude_HEADERS) $(nodist_googleinclude_HEADERS) \ $(noinst_HEADERS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ { test ! -d $(distdir) \ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -fr $(distdir); }; } DIST_ARCHIVES = $(distdir).tar.gz $(distdir).zip GZIP_ENV = --best distuninstallcheck_listfiles = find . -type f -print distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ENABLE_FRAME_POINTERS_FALSE = @ENABLE_FRAME_POINTERS_FALSE@ ENABLE_FRAME_POINTERS_TRUE = @ENABLE_FRAME_POINTERS_TRUE@ ENABLE_STATIC_FALSE = @ENABLE_STATIC_FALSE@ ENABLE_STATIC_TRUE = @ENABLE_STATIC_TRUE@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GCC_FALSE = @GCC_FALSE@ GCC_TRUE = @GCC_TRUE@ GREP = @GREP@ HAVE_OBJCOPY_WEAKEN_FALSE = @HAVE_OBJCOPY_WEAKEN_FALSE@ HAVE_OBJCOPY_WEAKEN_TRUE = @HAVE_OBJCOPY_WEAKEN_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBSTDCXX_LA_LINKER_FLAG = @LIBSTDCXX_LA_LINKER_FLAG@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MINGW_FALSE = @MINGW_FALSE@ MINGW_TRUE = @MINGW_TRUE@ NANOSLEEP_LIBS = @NANOSLEEP_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJCOPY = @OBJCOPY@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PROFILER_SO_VERSION = @PROFILER_SO_VERSION@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TCMALLOC_SO_VERSION = @TCMALLOC_SO_VERSION@ TC_VERSION_MAJOR = @TC_VERSION_MAJOR@ TC_VERSION_MINOR = @TC_VERSION_MINOR@ TC_VERSION_PATCH = @TC_VERSION_PATCH@ UNWIND_LIBS = @UNWIND_LIBS@ USE_LIBTOOL_FALSE = @USE_LIBTOOL_FALSE@ USE_LIBTOOL_TRUE = @USE_LIBTOOL_TRUE@ VERSION = @VERSION@ WITH_CPU_PROFILER_FALSE = @WITH_CPU_PROFILER_FALSE@ WITH_CPU_PROFILER_TRUE = @WITH_CPU_PROFILER_TRUE@ WITH_DEBUGALLOC_FALSE = @WITH_DEBUGALLOC_FALSE@ WITH_DEBUGALLOC_TRUE = @WITH_DEBUGALLOC_TRUE@ WITH_HEAP_CHECKER_FALSE = @WITH_HEAP_CHECKER_FALSE@ WITH_HEAP_CHECKER_TRUE = @WITH_HEAP_CHECKER_TRUE@ WITH_HEAP_PROFILER_FALSE = @WITH_HEAP_PROFILER_FALSE@ WITH_HEAP_PROFILER_OR_CHECKER_FALSE = @WITH_HEAP_PROFILER_OR_CHECKER_FALSE@ WITH_HEAP_PROFILER_OR_CHECKER_TRUE = @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ WITH_HEAP_PROFILER_TRUE = @WITH_HEAP_PROFILER_TRUE@ WITH_STACK_TRACE_FALSE = @WITH_STACK_TRACE_FALSE@ WITH_STACK_TRACE_TRUE = @WITH_STACK_TRACE_TRUE@ X86_64_AND_NO_FP_BY_DEFAULT_FALSE = @X86_64_AND_NO_FP_BY_DEFAULT_FALSE@ X86_64_AND_NO_FP_BY_DEFAULT_TRUE = @X86_64_AND_NO_FP_BY_DEFAULT_TRUE@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_cv_have_struct_mallinfo = @ac_cv_have_struct_mallinfo@ acx_pthread_config = @acx_pthread_config@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION) dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ # Make sure that when we re-make ./configure, we get the macros we need ACLOCAL_AMFLAGS = -I m4 # This is so we can #include AM_CPPFLAGS = -I$(top_srcdir)/src $(am__append_1) # This is mostly based on configure options AM_CXXFLAGS = $(am__append_2) $(am__append_3) $(am__append_4) # The -no-undefined flag allows libtool to generate shared libraries for # Cygwin and MinGW. LIBSTDCXX_LA_LINKER_FLAG is used to fix a Solaris bug. AM_LDFLAGS = -no-undefined $(LIBSTDCXX_LA_LINKER_FLAG) @GCC_FALSE@NO_EXCEPTIONS = # We know our low-level code cannot trigger an exception. On some # systems, such as cygwin, it would be disastrous if they did, because # the exception handler might call malloc! If our low-level routines # raised an exception within the malloc, they'd deadlock. Luckily, # we control all this code, and do not need exceptions for it. @GCC_TRUE@NO_EXCEPTIONS = -fno-exceptions # For windows systems (at least, mingw), we need to tell all our # tests to link in libtcmalloc using -u. This is because libtcmalloc # accomplishes its tasks via patching, leaving no work for the linker # to identify, so the linker will ignore libtcmalloc by default unless # we explicitly create a dependency via -u. TCMALLOC_FLAGS = $(am__append_5) @HAVE_OBJCOPY_WEAKEN_FALSE@WEAKEN = : # If we have objcopy, make malloc/free/etc weak symbols. That way folks # can override our malloc if they want to (they can still use tc_malloc). # Note: the weird-looking symbols are the c++ memory functions: # (in order) new, new(nothrow), new[], new[](nothrow), delete, delete[] # In theory this will break if mangling changes, but that seems pretty # unlikely at this point. Just in case, I throw in versions with an # extra underscore as well, which may help on OS X. @HAVE_OBJCOPY_WEAKEN_TRUE@WEAKEN = $(OBJCOPY) -W malloc -W free -W realloc -W calloc -W cfree \ @HAVE_OBJCOPY_WEAKEN_TRUE@ -W memalign -W posix_memalign -W valloc -W pvalloc \ @HAVE_OBJCOPY_WEAKEN_TRUE@ -W malloc_stats -W mallopt -W mallinfo \ @HAVE_OBJCOPY_WEAKEN_TRUE@ -W _Znwm -W _ZnwmRKSt9nothrow_t -W _Znam -W _ZnamRKSt9nothrow_t \ @HAVE_OBJCOPY_WEAKEN_TRUE@ -W _ZdlPv -W _ZdaPv \ @HAVE_OBJCOPY_WEAKEN_TRUE@ -W __Znwm -W __ZnwmRKSt9nothrow_t -W __Znam -W __ZnamRKSt9nothrow_t \ @HAVE_OBJCOPY_WEAKEN_TRUE@ -W __ZdlPv -W __ZdaPv LIBS_TO_WEAKEN = libtcmalloc_minimal.la $(am__append_23) \ $(am__append_33) $(am__append_48) $(am__append_63) googleincludedir = $(includedir)/google # The .h files you want to install (that is, .h files that people # who install this package can include in their own applications.) # We'll add to this later, on a library-by-library basis googleinclude_HEADERS = $(am__append_9) \ $(SG_TCMALLOC_MINIMAL_INCLUDES) $(am__append_27) \ $(am__append_55) # tcmalloc.h is a special case, because it's a .h.in file nodist_googleinclude_HEADERS = src/google/tcmalloc.h noinst_HEADERS = src/google/tcmalloc.h.in # This is for HTML and other documentation you want to install. # Add your documentation files (in doc/) in addition to these # top-level boilerplate files. Also add a TODO file if you have one. # We'll add to this later, on a library-by-library basis ### Documentation # I don't know how to say "distribute the .dot files but don't install them"; # noinst doesn't seem to work with data. I separate them out anyway, in case # one day we figure it out. Regardless, installing the dot files isn't the # end of the world. dist_doc_DATA = AUTHORS COPYING ChangeLog INSTALL NEWS README \ README_windows.txt TODO doc/index.html doc/designstyle.css \ $(am__append_12) doc/tcmalloc.html doc/overview.gif \ doc/pageheap.gif doc/spanmap.gif doc/threadheap.gif \ doc/t-test1.times.txt \ doc/tcmalloc-opspercpusec.vs.threads.1024.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.128.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.131072.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.16384.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.2048.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.256.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.32768.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.4096.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.512.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.64.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.65536.bytes.png \ doc/tcmalloc-opspercpusec.vs.threads.8192.bytes.png \ doc/tcmalloc-opspersec.vs.size.1.threads.png \ doc/tcmalloc-opspersec.vs.size.12.threads.png \ doc/tcmalloc-opspersec.vs.size.16.threads.png \ doc/tcmalloc-opspersec.vs.size.2.threads.png \ doc/tcmalloc-opspersec.vs.size.20.threads.png \ doc/tcmalloc-opspersec.vs.size.3.threads.png \ doc/tcmalloc-opspersec.vs.size.4.threads.png \ doc/tcmalloc-opspersec.vs.size.5.threads.png \ doc/tcmalloc-opspersec.vs.size.8.threads.png doc/overview.dot \ doc/pageheap.dot doc/spanmap.dot doc/threadheap.dot \ $(am__append_45) $(am__append_46) $(am__append_60) # The libraries (.so's) you want to install # We'll add to this later, on a library-by-library basis lib_LTLIBRARIES = libtcmalloc_minimal.la $(am__append_22) \ $(am__append_29) $(am__append_47) $(am__append_56) \ $(am__append_61) # This is for 'convenience libraries' -- basically just a container for sources ### Making the library # As we describe at the top of this file, we want to turn off exceptions # for all files in this library -- except tcmalloc.cc which needs them # to fulfill its API. Automake doesn't allow per-file CXXFLAGS, so we need # to separate into two libraries. noinst_LTLIBRARIES = liblogging.la libsysinfo.la $(am__append_6) \ $(am__append_8) $(am__append_10) \ libtcmalloc_minimal_internal.la $(am__append_28) WINDOWS_PROJECTS = google-perftools.sln \ vsprojects/low_level_alloc_unittest/low_level_alloc_unittest.vcproj \ $(am__append_14) \ vsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcproj \ vsprojects/tcmalloc_minimal_unittest/tcmalloc_minimal_unittest.vcproj \ vsprojects/tmu-static/tmu-static.vcproj \ vsprojects/tcmalloc_minimal_large/tcmalloc_minimal_large_unittest.vcproj \ vsprojects/addressmap_unittest/addressmap_unittest.vcproj \ vsprojects/packed-cache_test/packed-cache_test.vcproj \ vsprojects/frag_unittest/frag_unittest.vcproj \ vsprojects/markidle_unittest/markidle_unittest.vcproj \ vsprojects/malloc_extension_test/malloc_extension_test.vcproj \ vsprojects/page_heap_test/page_heap_test.vcproj \ vsprojects/pagemap_unittest/pagemap_unittest.vcproj \ vsprojects/realloc_unittest/realloc_unittest.vcproj \ vsprojects/stack_trace_table_test/stack_trace_table_test.vcproj \ vsprojects/thread_dealloc_unittest/thread_dealloc_unittest.vcproj \ $(am__append_36) # unittests you want to run when people type 'make check'. # Note: tests cannot take any arguments! # In theory, unittests that are scripts should be added to check_SCRIPTS # instead. But check_SCRIPTS is definitely a second-class testing mechanims: # it don't get TESTS_ENVIRONMENT, and it doesn't get success/failure counting # (in fact, a script failure aborts all the rest of the tests, even with -k). # So, for scripts, we add the script to tests, and also put in an empty # rule so automake doesn't try to build the script as a C binary. ### Unittests ### Unittests # Commented out for the moment because malloc(very_big_num) is broken in # standard libc! At least, in some situations, some of the time. # These all tests components of tcmalloc_minimal TESTS = low_level_alloc_unittest atomicops_unittest $(am__append_11) \ tcmalloc_minimal_unittest tcmalloc_minimal_large_unittest \ $(am__append_15) addressmap_unittest $(am__append_18) \ packed_cache_test frag_unittest markidle_unittest \ malloc_extension_test $(am__append_19) $(am__append_21) \ page_heap_test pagemap_unittest realloc_unittest \ stack_trace_table_test thread_dealloc_unittest \ $(am__append_24) $(am__append_34) $(am__append_39) \ $(am__append_42) $(am__append_49) $(am__append_51) \ $(am__append_53) $(am__append_57) $(am__append_62) # TESTS_ENVIRONMENT sets environment variables for when you run unittest. # We always get "srcdir" set for free. # We'll add to this later, on a library-by-library basis. TESTS_ENVIRONMENT = $(am__append_13) $(am__append_35) # All script tests should be added here noinst_SCRIPTS = $(am__append_16) $(am__append_25) $(am__append_37) \ $(am__append_40) $(am__append_43) $(am__append_58) # This is my own var, used for extra libraries I make that I need installed EXTRA_INSTALL = ### ------- library routines, in src/base # This is a 'convenience library' -- it's not actually installed or anything LOGGING_INCLUDES = src/base/logging.h \ src/base/commandlineflags.h \ src/base/basictypes.h \ src/base/dynamic_annotations.h \ src/third_party/valgrind.h liblogging_la_SOURCES = src/base/logging.cc \ src/base/dynamic_annotations.c \ $(LOGGING_INCLUDES) SYSINFO_INCLUDES = src/base/sysinfo.h \ src/base/logging.h \ src/base/commandlineflags.h \ src/base/cycleclock.h \ src/base/basictypes.h libsysinfo_la_SOURCES = src/base/sysinfo.cc \ $(SYSINFO_INCLUDES) libsysinfo_la_LIBADD = $(NANOSLEEP_LIBS) $(am__append_7) # For MinGW, we use also have to use libwindows Luckily, we need the # windows.a library in exactly the same place we need spinlock.a # (pretty much everywhere), so we can use the same variable name for # each. We can also optimize the MinGW rule a bit by leaving out # files we know aren't used on windows, such as # atomicops-internals-x86.cc. libwindows also obsoletes the need for # other files like system_alloc.cc. @MINGW_TRUE@WINDOWS_INCLUDES = src/windows/port.h \ @MINGW_TRUE@ src/windows/mingw.h \ @MINGW_TRUE@ src/windows/mini_disassembler.h \ @MINGW_TRUE@ src/windows/mini_disassembler_types.h \ @MINGW_TRUE@ src/windows/preamble_patcher.h @MINGW_TRUE@libwindows_la_SOURCES = $(WINDOWS_INCLUDES) \ @MINGW_TRUE@ src/windows/port.cc \ @MINGW_TRUE@ src/windows/ia32_modrm_map.cc \ @MINGW_TRUE@ src/windows/ia32_opcode_map.cc \ @MINGW_TRUE@ src/windows/mini_disassembler.cc \ @MINGW_TRUE@ src/windows/patch_functions.cc \ @MINGW_TRUE@ src/windows/preamble_patcher.cc \ @MINGW_TRUE@ src/windows/preamble_patcher_with_stub.cc # patch_functions.cc uses Psapi.lib. MSVC has a #pragma for that, but not us. @MINGW_TRUE@libwindows_la_LIBADD = -lPsapi # spinlock is the only code that uses atomicops. @MINGW_FALSE@SPINLOCK_INCLUDES = src/base/spinlock.h \ @MINGW_FALSE@ src/base/spinlock_internal.h \ @MINGW_FALSE@ src/base/atomicops.h \ @MINGW_FALSE@ src/base/atomicops-internals-macosx.h \ @MINGW_FALSE@ src/base/atomicops-internals-linuxppc.h \ @MINGW_FALSE@ src/base/atomicops-internals-x86-msvc.h \ @MINGW_FALSE@ src/base/atomicops-internals-x86.h @MINGW_TRUE@SPINLOCK_INCLUDES = src/base/spinlock.h \ @MINGW_TRUE@ src/base/spinlock_internal.h \ @MINGW_TRUE@ src/base/spinlock_win32-inl.h \ @MINGW_TRUE@ src/base/spinlock_linux-inl.h \ @MINGW_TRUE@ src/base/spinlock_posix-inl.h \ @MINGW_TRUE@ src/base/synchronization_profiling.h \ @MINGW_TRUE@ src/base/atomicops-internals-macosx.h \ @MINGW_TRUE@ src/base/atomicops-internals-linuxppc.h \ @MINGW_TRUE@ src/base/atomicops-internals-arm-gcc.h \ @MINGW_TRUE@ src/base/atomicops-internals-x86-msvc.h \ @MINGW_TRUE@ src/base/atomicops-internals-x86.h @MINGW_FALSE@libspinlock_la_SOURCES = src/base/spinlock.cc \ @MINGW_FALSE@ src/base/spinlock_internal.cc \ @MINGW_FALSE@ src/base/atomicops-internals-x86.cc \ @MINGW_FALSE@ $(SPINLOCK_INCLUDES) @MINGW_TRUE@libspinlock_la_SOURCES = src/base/spinlock.cc \ @MINGW_TRUE@ src/base/spinlock_internal.cc \ @MINGW_TRUE@ $(SPINLOCK_INCLUDES) # spinlock also needs NumCPUs, from libsysinfo, which in turn needs liblogging @MINGW_FALSE@LIBSPINLOCK = libspinlock.la libsysinfo.la liblogging.la @MINGW_TRUE@LIBSPINLOCK = libwindows.la libspinlock.la libsysinfo.la liblogging.la @MINGW_FALSE@TCMALLOC_CC = src/tcmalloc.cc # patch_functions.cc #includes tcmalloc.cc, so no need to link it in. @MINGW_TRUE@TCMALLOC_CC = @MINGW_FALSE@MAYBE_THREADS_CC = src/maybe_threads.cc # windows has its own system for threads and system memory allocation. @MINGW_TRUE@MAYBE_THREADS_CC = @MINGW_FALSE@SYSTEM_ALLOC_CC = src/system-alloc.cc @MINGW_TRUE@SYSTEM_ALLOC_CC = @MINGW_FALSE@libspinlock_la_LIBADD = $(NANOSLEEP_LIBS) LOW_LEVEL_ALLOC_UNITTEST_INCLUDES = src/base/low_level_alloc.h \ src/base/basictypes.h \ src/google/malloc_hook.h \ src/google/malloc_hook_c.h \ src/malloc_hook-inl.h \ $(SPINLOCK_INCLUDES) \ $(LOGGING_INCLUDES) low_level_alloc_unittest_SOURCES = src/base/low_level_alloc.cc \ src/malloc_hook.cc \ src/tests/low_level_alloc_unittest.cc \ $(LOW_LEVEL_ALLOC_UNITTEST_INCLUDES) # By default, MallocHook takes stack traces for use by the heap-checker. # We don't need that functionality here, so we turn it off to reduce deps. low_level_alloc_unittest_CXXFLAGS = -DNO_TCMALLOC_SAMPLES low_level_alloc_unittest_LDADD = $(LIBSPINLOCK) ATOMICOPS_UNITTEST_INCLUDES = src/base/atomicops.h \ src/base/atomicops-internals-macosx.h \ src/base/atomicops-internals-x86-msvc.h \ src/base/atomicops-internals-x86.h \ $(LOGGING_INCLUDES) atomicops_unittest_SOURCES = src/tests/atomicops_unittest.cc \ $(ATOMICOPS_UNITTEST_INCLUDES) atomicops_unittest_LDADD = $(LIBSPINLOCK) ### ------- stack trace ### The header files we use. We divide into categories based on directory @WITH_STACK_TRACE_TRUE@S_STACKTRACE_INCLUDES = src/stacktrace_config.h \ @WITH_STACK_TRACE_TRUE@ src/stacktrace_generic-inl.h \ @WITH_STACK_TRACE_TRUE@ src/stacktrace_libunwind-inl.h \ @WITH_STACK_TRACE_TRUE@ src/stacktrace_powerpc-inl.h \ @WITH_STACK_TRACE_TRUE@ src/stacktrace_x86_64-inl.h \ @WITH_STACK_TRACE_TRUE@ src/stacktrace_x86-inl.h \ @WITH_STACK_TRACE_TRUE@ src/stacktrace_win32-inl.h \ @WITH_STACK_TRACE_TRUE@ src/base/vdso_support.h @WITH_STACK_TRACE_TRUE@SG_STACKTRACE_INCLUDES = src/google/stacktrace.h @WITH_STACK_TRACE_TRUE@STACKTRACE_INCLUDES = $(S_STACKTRACE_INCLUDES) $(SG_STACKTRACE_INCLUDES) @WITH_STACK_TRACE_TRUE@libstacktrace_la_SOURCES = src/stacktrace.cc \ @WITH_STACK_TRACE_TRUE@ src/base/vdso_support.cc \ @WITH_STACK_TRACE_TRUE@ $(STACKTRACE_INCLUDES) @WITH_STACK_TRACE_TRUE@libstacktrace_la_LIBADD = $(UNWIND_LIBS) $(LIBSPINLOCK) @WITH_STACK_TRACE_TRUE@STACKTRACE_SYMBOLS = '(GetStackTrace|GetStackFrames|GetStackTraceWithContext|GetStackFramesWithContext)' @WITH_STACK_TRACE_TRUE@libstacktrace_la_LDFLAGS = -export-symbols-regex $(STACKTRACE_SYMBOLS) @WITH_STACK_TRACE_TRUE@STACKTRACE_UNITTEST_INLCUDES = src/config_for_unittests.h \ @WITH_STACK_TRACE_TRUE@ src/base/commandlineflags.h \ @WITH_STACK_TRACE_TRUE@ $(STACKTRACE_INCLUDES) \ @WITH_STACK_TRACE_TRUE@ $(LOGGING_INCLUDES) @WITH_STACK_TRACE_TRUE@stacktrace_unittest_SOURCES = src/tests/stacktrace_unittest.cc \ @WITH_STACK_TRACE_TRUE@ $(STACKTRACE_UNITTEST_INLCUDES) @WITH_STACK_TRACE_TRUE@stacktrace_unittest_LDADD = libstacktrace.la liblogging.la ### ------- pprof # If we are not compiling with stacktrace support, pprof is worthless @WITH_STACK_TRACE_TRUE@bin_SCRIPTS = src/pprof ### Unittests @WITH_STACK_TRACE_TRUE@check_SCRIPTS = pprof_unittest ### Documentation @WITH_STACK_TRACE_TRUE@dist_man_MANS = doc/pprof.1 ### ------- tcmalloc_minimal (thread-caching malloc) ### The header files we use. We divide into categories based on directory S_TCMALLOC_MINIMAL_INCLUDES = src/common.h \ src/internal_logging.h \ src/system-alloc.h \ src/packed-cache-inl.h \ $(SPINLOCK_INCLUDES) \ src/tcmalloc_guard.h \ src/base/commandlineflags.h \ src/base/basictypes.h \ src/pagemap.h \ src/sampler.h \ src/central_freelist.h \ src/linked_list.h \ src/page_heap.h \ src/page_heap_allocator.h \ src/span.h \ src/static_vars.h \ src/symbolize.h \ src/thread_cache.h \ src/stack_trace_table.h \ src/base/thread_annotations.h \ src/malloc_hook-inl.h \ src/maybe_threads.h SG_TCMALLOC_MINIMAL_INCLUDES = src/google/malloc_hook.h \ src/google/malloc_hook_c.h \ src/google/malloc_extension.h \ src/google/malloc_extension_c.h \ src/google/stacktrace.h TCMALLOC_MINIMAL_INCLUDES = $(S_TCMALLOC_MINIMAL_INCLUDES) $(SG_TCMALLOC_MINIMAL_INCLUDES) libtcmalloc_minimal_internal_la_SOURCES = src/common.cc \ src/internal_logging.cc \ $(SYSTEM_ALLOC_CC) \ src/memfs_malloc.cc \ src/central_freelist.cc \ src/page_heap.cc \ src/sampler.cc \ src/span.cc \ src/stack_trace_table.cc \ src/static_vars.cc \ src/symbolize.cc \ src/thread_cache.cc \ src/malloc_hook.cc \ src/malloc_extension.cc \ $(MAYBE_THREADS_CC) \ $(TCMALLOC_MINIMAL_INCLUDES) # We #define NO_TCMALLOC_SAMPLES, since sampling is turned off for _minimal. libtcmalloc_minimal_internal_la_CXXFLAGS = -DNO_TCMALLOC_SAMPLES \ -DNO_HEAP_CHECK \ $(PTHREAD_CFLAGS) -DNDEBUG \ $(AM_CXXFLAGS) $(NO_EXCEPTIONS) libtcmalloc_minimal_internal_la_LDFLAGS = $(PTHREAD_CFLAGS) libtcmalloc_minimal_internal_la_LIBADD = $(PTHREAD_LIBS) $(LIBSPINLOCK) libtcmalloc_minimal_la_SOURCES = $(TCMALLOC_CC) $(TCMALLOC_MINIMAL_INCLUDES) libtcmalloc_minimal_la_CXXFLAGS = -DNO_TCMALLOC_SAMPLES \ $(PTHREAD_CFLAGS) -DNDEBUG $(AM_CXXFLAGS) # -version-info gets passed to libtool libtcmalloc_minimal_la_LDFLAGS = $(PTHREAD_CFLAGS) -version-info @TCMALLOC_SO_VERSION@ libtcmalloc_minimal_la_LIBADD = libtcmalloc_minimal_internal.la $(PTHREAD_LIBS) @MINGW_FALSE@LIBTCMALLOC_MINIMAL = libtcmalloc_minimal.la # For windows, we're playing around with trying to do some stacktrace # support even with libtcmalloc_minimal. For everyone else, though, # we turn off all stack-trace activity for libtcmalloc_minimal. # TODO(csilvers): when we're done experimenting, do something principled here @MINGW_TRUE@LIBTCMALLOC_MINIMAL = libtcmalloc_minimal.la libstacktrace.la tcmalloc_minimal_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \ src/tests/testutil.h src/tests/testutil.cc \ $(TCMALLOC_UNITTEST_INCLUDES) tcmalloc_minimal_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) tcmalloc_minimal_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) # We want libtcmalloc last on the link line, but due to a bug in # libtool involving convenience libs, they need to come last on the # link line in order to get dependency ordering right. This is ok: # convenience libraries are .a's, so tcmalloc is still the last .so. # We also put pthreads after tcmalloc, because some pthread # implementations define their own malloc, and we need to go on the # first linkline to make sure our malloc 'wins'. tcmalloc_minimal_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) \ liblogging.la $(PTHREAD_LIBS) tcmalloc_minimal_large_unittest_SOURCES = src/tests/tcmalloc_large_unittest.cc tcmalloc_minimal_large_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) tcmalloc_minimal_large_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) tcmalloc_minimal_large_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) @ENABLE_STATIC_FALSE@@MINGW_FALSE@maybe_threads_unittest_sh_SOURCES = src/tests/maybe_threads_unittest.sh ADDRESSMAP_UNITTEST_INCLUDES = src/addressmap-inl.h \ src/base/commandlineflags.h \ $(LOGGING_INCLUDES) addressmap_unittest_SOURCES = src/tests/addressmap_unittest.cc \ $(ADDRESSMAP_UNITTEST_INCLUDES) $(am__append_17) addressmap_unittest_CXXFLAGS = -g $(AM_CXXFLAGS) addressmap_unittest_LDADD = liblogging.la @MINGW_FALSE@system_alloc_unittest_SOURCES = src/config_for_unittests.h \ @MINGW_FALSE@ src/tests/system-alloc_unittest.cc @MINGW_FALSE@system_alloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) @MINGW_FALSE@system_alloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) @MINGW_FALSE@system_alloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) packed_cache_test_SOURCES = src/tests/packed-cache_test.cc packed_cache_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) packed_cache_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) packed_cache_test_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) frag_unittest_SOURCES = src/tests/frag_unittest.cc src/config_for_unittests.h frag_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) frag_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) frag_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) markidle_unittest_SOURCES = src/tests/markidle_unittest.cc \ src/config_for_unittests.h \ src/tests/testutil.h src/tests/testutil.cc markidle_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) markidle_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) markidle_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) malloc_extension_test_SOURCES = src/tests/malloc_extension_test.cc \ src/config_for_unittests.h \ src/base/logging.h \ src/google/malloc_extension.h \ src/google/malloc_extension_c.h malloc_extension_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) malloc_extension_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) malloc_extension_test_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) @ENABLE_STATIC_FALSE@@MINGW_FALSE@malloc_extension_c_test_SOURCES = src/tests/malloc_extension_c_test.c \ @ENABLE_STATIC_FALSE@@MINGW_FALSE@ src/google/malloc_extension.h \ @ENABLE_STATIC_FALSE@@MINGW_FALSE@ src/google/malloc_extension_c.h @ENABLE_STATIC_FALSE@@MINGW_FALSE@malloc_extension_c_test_CFLAGS = \ @ENABLE_STATIC_FALSE@@MINGW_FALSE@ $(PTHREAD_CFLAGS) \ @ENABLE_STATIC_FALSE@@MINGW_FALSE@ $(AM_CFLAGS) \ @ENABLE_STATIC_FALSE@@MINGW_FALSE@ $(am__append_20) @ENABLE_STATIC_FALSE@@MINGW_FALSE@malloc_extension_c_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) @ENABLE_STATIC_FALSE@@MINGW_FALSE@malloc_extension_c_test_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) @MINGW_FALSE@memalign_unittest_SOURCES = src/tests/memalign_unittest.cc \ @MINGW_FALSE@ src/tcmalloc.h \ @MINGW_FALSE@ src/config_for_unittests.h \ @MINGW_FALSE@ src/tests/testutil.h src/tests/testutil.cc @MINGW_FALSE@memalign_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) @MINGW_FALSE@memalign_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) @MINGW_FALSE@memalign_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) page_heap_test_SOURCES = src/tests/page_heap_test.cc \ src/config_for_unittests.h \ src/base/logging.h \ src/common.h \ src/page_heap.h page_heap_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) page_heap_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) page_heap_test_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) pagemap_unittest_SOURCES = src/tests/pagemap_unittest.cc \ src/config_for_unittests.h \ src/base/logging.h \ src/pagemap.h pagemap_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) pagemap_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) pagemap_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) realloc_unittest_SOURCES = src/tests/realloc_unittest.cc \ src/config_for_unittests.h \ src/base/logging.h realloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) realloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) realloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) stack_trace_table_test_SOURCES = src/tests/stack_trace_table_test.cc \ src/config_for_unittests.h stack_trace_table_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) stack_trace_table_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) stack_trace_table_test_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) thread_dealloc_unittest_SOURCES = src/tests/thread_dealloc_unittest.cc \ src/config_for_unittests.h \ src/tests/testutil.h src/tests/testutil.cc thread_dealloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) thread_dealloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) thread_dealloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) @WITH_DEBUGALLOC_TRUE@libtcmalloc_minimal_debug_la_SOURCES = src/debugallocation.cc \ @WITH_DEBUGALLOC_TRUE@ $(TCMALLOC_MINIMAL_INCLUDES) @WITH_DEBUGALLOC_TRUE@libtcmalloc_minimal_debug_la_CXXFLAGS = $(libtcmalloc_minimal_la_CXXFLAGS) \ @WITH_DEBUGALLOC_TRUE@ -DTCMALLOC_FOR_DEBUGALLOCATION # version_info gets passed to libtool @WITH_DEBUGALLOC_TRUE@libtcmalloc_minimal_debug_la_LDFLAGS = $(libtcmalloc_minimal_la_LDFLAGS) \ @WITH_DEBUGALLOC_TRUE@ -version-info @TCMALLOC_SO_VERSION@ @WITH_DEBUGALLOC_TRUE@libtcmalloc_minimal_debug_la_LIBADD = $(libtcmalloc_minimal_la_LIBADD) @WITH_DEBUGALLOC_TRUE@tcmalloc_minimal_debug_unittest_SOURCES = $(tcmalloc_minimal_unittest_SOURCES) @WITH_DEBUGALLOC_TRUE@tcmalloc_minimal_debug_unittest_CXXFLAGS = $(tcmalloc_minimal_unittest_CXXFLAGS) \ @WITH_DEBUGALLOC_TRUE@ -DDEBUGALLOCATION @WITH_DEBUGALLOC_TRUE@tcmalloc_minimal_debug_unittest_LDFLAGS = $(tcmalloc_minimal_unittest_LDFLAGS) @WITH_DEBUGALLOC_TRUE@tcmalloc_minimal_debug_unittest_LDADD = libtcmalloc_minimal_debug.la $(PTHREAD_LIBS) @WITH_DEBUGALLOC_TRUE@malloc_extension_debug_test_SOURCES = $(malloc_extension_test_SOURCES) @WITH_DEBUGALLOC_TRUE@malloc_extension_debug_test_CXXFLAGS = $(malloc_extension_test_CXXFLAGS) @WITH_DEBUGALLOC_TRUE@malloc_extension_debug_test_LDFLAGS = $(malloc_extension_test_LDFLAGS) @WITH_DEBUGALLOC_TRUE@malloc_extension_debug_test_LDADD = libtcmalloc_minimal_debug.la $(PTHREAD_LIBS) @WITH_DEBUGALLOC_TRUE@memalign_debug_unittest_SOURCES = $(memalign_unittest_SOURCES) @WITH_DEBUGALLOC_TRUE@memalign_debug_unittest_CXXFLAGS = $(memalign_unittest_CXXFLAGS) @WITH_DEBUGALLOC_TRUE@memalign_debug_unittest_LDFLAGS = $(memalign_unittest_LDFLAGS) @WITH_DEBUGALLOC_TRUE@memalign_debug_unittest_LDADD = libtcmalloc_minimal_debug.la $(PTHREAD_LIBS) @WITH_DEBUGALLOC_TRUE@realloc_debug_unittest_SOURCES = $(realloc_unittest_SOURCES) @WITH_DEBUGALLOC_TRUE@realloc_debug_unittest_CXXFLAGS = $(realloc_unittest_CXXFLAGS) @WITH_DEBUGALLOC_TRUE@realloc_debug_unittest_LDFLAGS = $(realloc_unittest_LDFLAGS) @WITH_DEBUGALLOC_TRUE@realloc_debug_unittest_LDADD = libtcmalloc_minimal_debug.la $(PTHREAD_LIBS) @WITH_DEBUGALLOC_TRUE@debugallocation_test_sh_SOURCES = src/tests/debugallocation_test.sh @WITH_DEBUGALLOC_TRUE@debugallocation_test_SOURCES = src/tests/debugallocation_test.cc @WITH_DEBUGALLOC_TRUE@debugallocation_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) @WITH_DEBUGALLOC_TRUE@debugallocation_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) @WITH_DEBUGALLOC_TRUE@debugallocation_test_LDADD = libtcmalloc_debug.la $(PTHREAD_LIBS) ### ------- tcmalloc (thread-caching malloc + heap profiler + heap checker) ### The header files we use. We divide into categories based on directory @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@S_TCMALLOC_INCLUDES = $(S_TCMALLOC_MINIMAL_INCLUDES) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(LOGGING_INCLUDES) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/addressmap-inl.h \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/raw_printer.h \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/elfcore.h \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/googleinit.h \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/linux_syscall_support.h \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/linuxthreads.h \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/stl_allocator.h \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/sysinfo.h \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/thread_lister.h \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/heap-profile-table.h @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@SG_TCMALLOC_INCLUDES = $(SG_TCMALLOC_MINIMAL_INCLUDES) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/google/heap-profiler.h \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/google/heap-checker.h @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@TCMALLOC_INCLUDES = $(S_TCMALLOC_INCLUDES) $(SG_TCMALLOC_INCLUDES) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_internal_la_SOURCES = $(libtcmalloc_minimal_internal_la_SOURCES) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(TCMALLOC_INCLUDES) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/low_level_alloc.cc \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/heap-profile-table.cc \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/heap-profiler.cc \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/raw_printer.cc \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/memory_region_map.cc @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_internal_la_CXXFLAGS = \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(PTHREAD_CFLAGS) -DNDEBUG \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(AM_CXXFLAGS) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(NO_EXCEPTIONS) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__append_31) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_internal_la_LDFLAGS = $(PTHREAD_CFLAGS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_internal_la_LIBADD = libstacktrace.la $(PTHREAD_LIBS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_SOURCES = \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(TCMALLOC_CC) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(TCMALLOC_INCLUDES) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__append_30) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_CXXFLAGS = \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(PTHREAD_CFLAGS) -DNDEBUG \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(AM_CXXFLAGS) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__append_32) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_LDFLAGS = $(PTHREAD_CFLAGS) -version-info @TCMALLOC_SO_VERSION@ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_LIBADD = libtcmalloc_internal.la $(PTHREAD_LIBS) @WITH_HEAP_CHECKER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@HEAP_CHECKER_SOURCES = # heap-checker-bcad is last, in hopes its global ctor will run first. # (Note this is added to libtcmalloc.la, not libtcmalloc_internal.la, # but that's ok; the internal/external distinction is only useful for # cygwin, and cygwin doesn't use HEAP_CHECKER anyway.) @WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@HEAP_CHECKER_SOURCES = src/base/thread_lister.c \ @WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/linuxthreads.cc \ @WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/heap-checker.cc \ @WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/heap-checker-bcad.cc @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@LIBTCMALLOC = libtcmalloc.la @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@TCMALLOC_UNITTEST_INCLUDES = src/config_for_unittests.h \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/google/malloc_extension.h @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/tcmalloc.h \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/tests/testutil.h src/tests/testutil.cc \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(TCMALLOC_UNITTEST_INCLUDES) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) # We want libtcmalloc last on the link line, but due to a bug in # libtool involving convenience libs, they need to come last on the # link line in order to get dependency ordering right. This is ok: # convenience libraries are .a's, so tcmalloc is still the last .so. # We also put pthreads after tcmalloc, because some pthread # implementations define their own malloc, and we need to go on the # first linkline to make sure our malloc 'wins'. @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_unittest_LDADD = $(LIBTCMALLOC) liblogging.la $(PTHREAD_LIBS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/tests/testutil.h src/tests/testutil.cc \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(TCMALLOC_UNITTEST_INCLUDES) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) @WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_LDADD = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \ @WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ liblogging.la $(PTHREAD_LIBS) # We want libtcmalloc last on the link line, but due to a bug in # libtool involving convenience libs, they need to come last on the # link line in order to get dependency ordering right. This is ok: # convenience libraries are .a's, so tcmalloc is still the last .so. # We also put pthreads after tcmalloc, because some pthread # implementations define their own malloc, and we need to go on the # first linkline to make sure our malloc 'wins'. @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_LDADD = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \ @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libprofiler.la liblogging.la $(PTHREAD_LIBS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_large_unittest_SOURCES = src/tests/tcmalloc_large_unittest.cc @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_large_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_large_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_large_unittest_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@raw_printer_test_SOURCES = src/tests/raw_printer_test.cc @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@raw_printer_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@raw_printer_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@raw_printer_test_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampler_test_SOURCES = src/tests/sampler_test.cc \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/config_for_unittests.h @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampler_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampler_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampler_test_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS) -lm @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_test_sh_SOURCES = src/tests/sampling_test.sh @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@SAMPLING_TEST_INCLUDES = src/config_for_unittests.h \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/logging.h \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/google/malloc_extension.h @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_test_SOURCES = src/tests/sampling_test.cc \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(SAMPLING_TEST_INCLUDES) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_test_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_test_LDFLAGS = -g $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_test_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS) @WITH_HEAP_PROFILER_TRUE@heap_profiler_unittest_sh_SOURCES = src/tests/heap-profiler_unittest.sh @WITH_HEAP_PROFILER_TRUE@HEAP_PROFILER_UNITTEST_INCLUDES = src/config_for_unittests.h \ @WITH_HEAP_PROFILER_TRUE@ src/google/heap-profiler.h @WITH_HEAP_PROFILER_TRUE@heap_profiler_unittest_SOURCES = src/tests/heap-profiler_unittest.cc \ @WITH_HEAP_PROFILER_TRUE@ $(HEAP_PROFILER_UNITTEST_INCLUDES) @WITH_HEAP_PROFILER_TRUE@heap_profiler_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) @WITH_HEAP_PROFILER_TRUE@heap_profiler_unittest_LDFLAGS = -g $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) @WITH_HEAP_PROFILER_TRUE@heap_profiler_unittest_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS) @WITH_HEAP_CHECKER_TRUE@heap_checker_unittest_sh_SOURCES = src/tests/heap-checker_unittest.sh @WITH_HEAP_CHECKER_TRUE@heap_checker_death_unittest_sh_SOURCES = src/tests/heap-checker-death_unittest.sh @WITH_HEAP_CHECKER_TRUE@HEAP_CHECKER_UNITTEST_INCLUDES = src/config_for_unittests.h \ @WITH_HEAP_CHECKER_TRUE@ src/memory_region_map.h \ @WITH_HEAP_CHECKER_TRUE@ src/base/commandlineflags.h \ @WITH_HEAP_CHECKER_TRUE@ src/base/googleinit.h \ @WITH_HEAP_CHECKER_TRUE@ src/google/heap-checker.h \ @WITH_HEAP_CHECKER_TRUE@ $(LOGGING_INCLUDES) @WITH_HEAP_CHECKER_TRUE@heap_checker_unittest_SOURCES = src/tests/heap-checker_unittest.cc \ @WITH_HEAP_CHECKER_TRUE@ $(HEAP_CHECKER_UNITTEST_INCLUDES) @WITH_HEAP_CHECKER_TRUE@heap_checker_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) @WITH_HEAP_CHECKER_TRUE@heap_checker_unittest_LDFLAGS = -g $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) # We want libtcmalloc last on the link line, but due to a bug in # libtool involving convenience libs, they need to come last on the # link line in order to get dependency ordering right. This is ok: # convenience libraries are .a's, so tcmalloc is still the last .so. # We also put pthreads after tcmalloc, because some pthread # implementations define their own malloc, and we need to go on the # first linkline to make sure our malloc 'wins'. @WITH_HEAP_CHECKER_TRUE@heap_checker_unittest_LDADD = $(LIBTCMALLOC) liblogging.la $(PTHREAD_LIBS) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_debug_la_SOURCES = src/debugallocation.cc $(HEAP_CHECKER_SOURCES) \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(TCMALLOC_INCLUDES) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_debug_la_CXXFLAGS = $(libtcmalloc_la_CXXFLAGS) \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ -DTCMALLOC_FOR_DEBUGALLOCATION @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_debug_la_LDFLAGS = $(libtcmalloc_la_LDFLAGS) \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ -version-info @TCMALLOC_SO_VERSION@ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_debug_la_LIBADD = $(libtcmalloc_la_LIBADD) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_debug_unittest_SOURCES = $(tcmalloc_unittest_SOURCES) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_debug_unittest_CXXFLAGS = $(tcmalloc_unittest_CXXFLAGS) \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ -DDEBUGALLOCATION @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_debug_unittest_LDFLAGS = $(tcmalloc_unittest_LDFLAGS) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_debug_unittest_LDADD = libtcmalloc_debug.la $(PTHREAD_LIBS) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampler_debug_test_SOURCES = $(sampler_test_SOURCES) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampler_debug_test_CXXFLAGS = $(samples_test_CXXFLAGS) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampler_debug_test_LDFLAGS = $(sampler_test_LDFLAGS) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampler_debug_test_LDADD = libtcmalloc_debug.la $(PTHREAD_LIBS) -lm @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_debug_test_sh_SOURCES = src/tests/sampling_test.sh @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_debug_test_SOURCES = $(sampling_test_SOURCES) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_debug_test_CXXFLAGS = $(sampling_test_CXXFLAGS) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_debug_test_LDFLAGS = $(sampling_test_LDFLAGS) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_debug_test_LDADD = libtcmalloc_debug.la $(PTHREAD_LIBS) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@heap_profiler_debug_unittest_sh_SOURCES = src/tests/heap-profiler_unittest.sh @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@heap_profiler_debug_unittest_SOURCES = $(heap_profiler_unittest_SOURCES) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@heap_profiler_debug_unittest_CXXFLAGS = $(heap_profiler_unittest_CXXFLAGS) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@heap_profiler_debug_unittest_LDFLAGS = $(heap_profiler_unittest_LDFLAGS) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@heap_profiler_debug_unittest_LDADD = libtcmalloc_debug.la $(PTHREAD_LIBS) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@heap_checker_debug_unittest_sh_SOURCES = src/tests/heap-checker_unittest.sh @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@heap_checker_debug_unittest_SOURCES = $(heap_checker_unittest_SOURCES) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@heap_checker_debug_unittest_CXXFLAGS = $(heap_checker_unittest_CXXFLAGS) @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@heap_checker_debug_unittest_LDFLAGS = $(heap_checker_unittest_LDFLAGS) # We want libtcmalloc last on the link line, but due to a bug in # libtool involving convenience libs, they need to come last on the # link line in order to get dependency ordering right. This is ok: # convenience libraries are .a's, so tcmalloc is still the last .so. @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@heap_checker_debug_unittest_LDADD = libtcmalloc_debug.la liblogging.la \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@ $(PTHREAD_LIBS) ### ------- CPU profiler ### The header files we use. We divide into categories based on directory @WITH_CPU_PROFILER_TRUE@S_CPU_PROFILER_INCLUDES = src/profiledata.h \ @WITH_CPU_PROFILER_TRUE@ src/profile-handler.h \ @WITH_CPU_PROFILER_TRUE@ src/getpc.h \ @WITH_CPU_PROFILER_TRUE@ src/base/basictypes.h \ @WITH_CPU_PROFILER_TRUE@ src/base/commandlineflags.h \ @WITH_CPU_PROFILER_TRUE@ src/base/googleinit.h \ @WITH_CPU_PROFILER_TRUE@ src/base/logging.h \ @WITH_CPU_PROFILER_TRUE@ src/base/simple_mutex.h \ @WITH_CPU_PROFILER_TRUE@ src/base/sysinfo.h \ @WITH_CPU_PROFILER_TRUE@ $(SPINLOCK_INCLUDES) \ @WITH_CPU_PROFILER_TRUE@ $(LOGGING_INCLUDES) @WITH_CPU_PROFILER_TRUE@SG_CPU_PROFILER_INCLUDES = src/google/profiler.h \ @WITH_CPU_PROFILER_TRUE@ src/google/stacktrace.h @WITH_CPU_PROFILER_TRUE@CPU_PROFILER_INCLUDES = $(S_CPU_PROFILER_INCLUDES) $(SG_CPU_PROFILER_INCLUDES) @WITH_CPU_PROFILER_TRUE@libprofiler_la_SOURCES = src/profiler.cc \ @WITH_CPU_PROFILER_TRUE@ src/profile-handler.cc \ @WITH_CPU_PROFILER_TRUE@ src/profiledata.cc \ @WITH_CPU_PROFILER_TRUE@ $(CPU_PROFILER_INCLUDES) @WITH_CPU_PROFILER_TRUE@libprofiler_la_LIBADD = libstacktrace.la # We have to include ProfileData for profiledata_unittest @WITH_CPU_PROFILER_TRUE@CPU_PROFILER_SYMBOLS = '(ProfilerStart|ProfilerStartWithOptions|ProfilerStop|ProfilerFlush|ProfilerEnable|ProfilerDisable|ProfilingIsEnabledForAllThreads|ProfilerRegisterThread|ProfilerGetCurrentState|ProfilerState|ProfileData|ProfileHandler)' @WITH_CPU_PROFILER_TRUE@libprofiler_la_LDFLAGS = -export-symbols-regex $(CPU_PROFILER_SYMBOLS) \ @WITH_CPU_PROFILER_TRUE@ -version-info @PROFILER_SO_VERSION@ # See discussion above (under LIBTCMALLOC_MINIMAL) for why we do this. # Basically it's to work around systems where --rpath doesn't work right. @WITH_CPU_PROFILER_TRUE@LIBPROFILER = libstacktrace.la libprofiler.la #WINDOWS_PROJECTS += vsprojects/getpc_test/getpc_test.vcproj @WITH_CPU_PROFILER_TRUE@getpc_test_SOURCES = src/tests/getpc_test.cc src/getpc.h #WINDOWS_PROJECTS += vsprojects/profiledata_unittest/profiledata_unittest.vcproj @WITH_CPU_PROFILER_TRUE@profiledata_unittest_SOURCES = src/tests/profiledata_unittest.cc \ @WITH_CPU_PROFILER_TRUE@ src/profiledata.h \ @WITH_CPU_PROFILER_TRUE@ src/base/commandlineflags.h \ @WITH_CPU_PROFILER_TRUE@ src/base/logging.h \ @WITH_CPU_PROFILER_TRUE@ src/base/basictypes.h @WITH_CPU_PROFILER_TRUE@profiledata_unittest_LDADD = $(LIBPROFILER) @WITH_CPU_PROFILER_TRUE@profile_handler_unittest_SOURCES = src/tests/profile-handler_unittest.cc \ @WITH_CPU_PROFILER_TRUE@ src/profile-handler.h @WITH_CPU_PROFILER_TRUE@profile_handler_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) @WITH_CPU_PROFILER_TRUE@profile_handler_unittest_LDFLAGS = $(PTHREAD_CFLAGS) @WITH_CPU_PROFILER_TRUE@profile_handler_unittest_LDADD = $(LIBPROFILER) $(PTHREAD_LIBS) @WITH_CPU_PROFILER_TRUE@profiler_unittest_sh_SOURCES = src/tests/profiler_unittest.sh @WITH_CPU_PROFILER_TRUE@PROFILER_UNITTEST_INCLUDES = src/config_for_unittests.h \ @WITH_CPU_PROFILER_TRUE@ src/google/profiler.h @WITH_CPU_PROFILER_TRUE@PROFILER_UNITTEST_SRCS = src/tests/profiler_unittest.cc \ @WITH_CPU_PROFILER_TRUE@ src/tests/testutil.h src/tests/testutil.cc \ @WITH_CPU_PROFILER_TRUE@ $(PROFILER_UNITTEST_INCLUDES) @WITH_CPU_PROFILER_TRUE@profiler1_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS) @WITH_CPU_PROFILER_TRUE@profiler1_unittest_CXXFLAGS = -g -DNO_THREADS $(AM_CXXFLAGS) @WITH_CPU_PROFILER_TRUE@profiler1_unittest_LDADD = $(LIBPROFILER) @WITH_CPU_PROFILER_TRUE@profiler2_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS) @WITH_CPU_PROFILER_TRUE@profiler2_unittest_CXXFLAGS = -g -DNO_THREADS $(AM_CXXFLAGS) @WITH_CPU_PROFILER_TRUE@profiler2_unittest_LDADD = -lstacktrace -lprofiler # We depend on -lprofiler but haven't yet said how to build it. Do so now. @WITH_CPU_PROFILER_TRUE@profiler2_unittest_DEPENDENCIES = $(LIBPROFILER) @WITH_CPU_PROFILER_TRUE@profiler3_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS) @WITH_CPU_PROFILER_TRUE@profiler3_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) @WITH_CPU_PROFILER_TRUE@profiler3_unittest_LDFLAGS = $(PTHREAD_CFLAGS) @WITH_CPU_PROFILER_TRUE@profiler3_unittest_LDADD = $(LIBPROFILER) $(PTHREAD_LIBS) @WITH_CPU_PROFILER_TRUE@profiler4_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS) @WITH_CPU_PROFILER_TRUE@profiler4_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) @WITH_CPU_PROFILER_TRUE@profiler4_unittest_LDFLAGS = $(PTHREAD_CFLAGS) @WITH_CPU_PROFILER_TRUE@profiler4_unittest_LDADD = -lstacktrace -lprofiler $(PTHREAD_LIBS) # We depend on -lprofiler but haven't yet said how to build it. Do so now. @WITH_CPU_PROFILER_TRUE@profiler4_unittest_DEPENDENCIES = $(LIBPROFILER) @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_and_profiler_la_SOURCES = $(libtcmalloc_la_SOURCES) $(libprofiler_la_SOURCES) @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_and_profiler_la_CXXFLAGS = $(libtcmalloc_la_CXXFLAGS) $(libprofiler_la_CXXFLAGS) # Since this library is meant to be used as a .a, I don't worry as much # about .so versioning. I just give the libtcmalloc version number. # TODO(csilvers): use -export-symbols-regex? @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_and_profiler_la_LDFLAGS = $(PTHREAD_CFLAGS) \ @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ -version-info @TCMALLOC_SO_VERSION@ # We don't include libprofiler_la_LIBADD here because all it adds is # libstacktrace.la, which we already get via libtcmalloc. Trying to # specify it twice causes link-time duplicate-definition errors. :-( @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_and_profiler_la_LIBADD = $(libtcmalloc_la_LIBADD) @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_and_profiler_unittest_SOURCES = $(tcmalloc_both_unittest_SOURCES) @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_and_profiler_unittest_CXXFLAGS = $(tcmalloc_both_unittest_CXXFLAGS) @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_and_profiler_unittest_LDFLAGS = $(tcmalloc_both_unittest_LDFLAGS) @WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_and_profiler_unittest_LDADD = libtcmalloc_and_profiler.la # http://linux.die.net/man/1/pkg-config, http://pkg-config.freedesktop.org/wiki pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libtcmalloc.pc libtcmalloc_minimal.pc \ libtcmalloc_debug.pc libtcmalloc_minimal_debug.pc \ libprofiler.pc CLEANFILES = $(pkgconfig_DATA) EXTRA_DIST = packages/rpm.sh packages/rpm/rpm.spec packages/deb.sh packages/deb \ $(SCRIPTS) libtool \ src/windows/get_mangled_names.cc src/windows/override_functions.cc \ src/windows/config.h src/windows/google/tcmalloc.h \ $(WINDOWS_PROJECTS) \ src/solaris/libstdc++.la all: all-am .SUFFIXES: .SUFFIXES: .c .cc .lo .o .obj am--refresh: @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \ cd $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) cd $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) src/config.h: src/stamp-h1 @if test ! -f $@; then \ rm -f src/stamp-h1; \ $(MAKE) src/stamp-h1; \ else :; fi src/stamp-h1: $(top_srcdir)/src/config.h.in $(top_builddir)/config.status @rm -f src/stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status src/config.h $(top_srcdir)/src/config.h.in: $(am__configure_deps) cd $(top_srcdir) && $(AUTOHEADER) rm -f src/stamp-h1 touch $@ distclean-hdr: -rm -f src/config.h src/stamp-h1 src/google/tcmalloc.h: $(top_builddir)/config.status $(top_srcdir)/src/google/tcmalloc.h.in cd $(top_builddir) && $(SHELL) ./config.status $@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ if test -f $$p; then \ f=$(am__strip_dir) \ echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ else :; fi; \ done uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \ p=$(am__strip_dir) \ echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done liblogging.la: $(liblogging_la_OBJECTS) $(liblogging_la_DEPENDENCIES) $(CXXLINK) $(liblogging_la_LDFLAGS) $(liblogging_la_OBJECTS) $(liblogging_la_LIBADD) $(LIBS) libprofiler.la: $(libprofiler_la_OBJECTS) $(libprofiler_la_DEPENDENCIES) $(CXXLINK) $(am_libprofiler_la_rpath) $(libprofiler_la_LDFLAGS) $(libprofiler_la_OBJECTS) $(libprofiler_la_LIBADD) $(LIBS) libspinlock.la: $(libspinlock_la_OBJECTS) $(libspinlock_la_DEPENDENCIES) $(CXXLINK) $(am_libspinlock_la_rpath) $(libspinlock_la_LDFLAGS) $(libspinlock_la_OBJECTS) $(libspinlock_la_LIBADD) $(LIBS) libstacktrace.la: $(libstacktrace_la_OBJECTS) $(libstacktrace_la_DEPENDENCIES) $(CXXLINK) $(am_libstacktrace_la_rpath) $(libstacktrace_la_LDFLAGS) $(libstacktrace_la_OBJECTS) $(libstacktrace_la_LIBADD) $(LIBS) libsysinfo.la: $(libsysinfo_la_OBJECTS) $(libsysinfo_la_DEPENDENCIES) $(CXXLINK) $(libsysinfo_la_LDFLAGS) $(libsysinfo_la_OBJECTS) $(libsysinfo_la_LIBADD) $(LIBS) libtcmalloc.la: $(libtcmalloc_la_OBJECTS) $(libtcmalloc_la_DEPENDENCIES) $(CXXLINK) $(am_libtcmalloc_la_rpath) $(libtcmalloc_la_LDFLAGS) $(libtcmalloc_la_OBJECTS) $(libtcmalloc_la_LIBADD) $(LIBS) libtcmalloc_and_profiler.la: $(libtcmalloc_and_profiler_la_OBJECTS) $(libtcmalloc_and_profiler_la_DEPENDENCIES) $(CXXLINK) $(am_libtcmalloc_and_profiler_la_rpath) $(libtcmalloc_and_profiler_la_LDFLAGS) $(libtcmalloc_and_profiler_la_OBJECTS) $(libtcmalloc_and_profiler_la_LIBADD) $(LIBS) libtcmalloc_debug.la: $(libtcmalloc_debug_la_OBJECTS) $(libtcmalloc_debug_la_DEPENDENCIES) $(CXXLINK) $(am_libtcmalloc_debug_la_rpath) $(libtcmalloc_debug_la_LDFLAGS) $(libtcmalloc_debug_la_OBJECTS) $(libtcmalloc_debug_la_LIBADD) $(LIBS) libtcmalloc_internal.la: $(libtcmalloc_internal_la_OBJECTS) $(libtcmalloc_internal_la_DEPENDENCIES) $(CXXLINK) $(am_libtcmalloc_internal_la_rpath) $(libtcmalloc_internal_la_LDFLAGS) $(libtcmalloc_internal_la_OBJECTS) $(libtcmalloc_internal_la_LIBADD) $(LIBS) libtcmalloc_minimal.la: $(libtcmalloc_minimal_la_OBJECTS) $(libtcmalloc_minimal_la_DEPENDENCIES) $(CXXLINK) -rpath $(libdir) $(libtcmalloc_minimal_la_LDFLAGS) $(libtcmalloc_minimal_la_OBJECTS) $(libtcmalloc_minimal_la_LIBADD) $(LIBS) libtcmalloc_minimal_debug.la: $(libtcmalloc_minimal_debug_la_OBJECTS) $(libtcmalloc_minimal_debug_la_DEPENDENCIES) $(CXXLINK) $(am_libtcmalloc_minimal_debug_la_rpath) $(libtcmalloc_minimal_debug_la_LDFLAGS) $(libtcmalloc_minimal_debug_la_OBJECTS) $(libtcmalloc_minimal_debug_la_LIBADD) $(LIBS) libtcmalloc_minimal_internal.la: $(libtcmalloc_minimal_internal_la_OBJECTS) $(libtcmalloc_minimal_internal_la_DEPENDENCIES) $(CXXLINK) $(libtcmalloc_minimal_internal_la_LDFLAGS) $(libtcmalloc_minimal_internal_la_OBJECTS) $(libtcmalloc_minimal_internal_la_LIBADD) $(LIBS) libwindows.la: $(libwindows_la_OBJECTS) $(libwindows_la_DEPENDENCIES) $(CXXLINK) $(am_libwindows_la_rpath) $(libwindows_la_LDFLAGS) $(libwindows_la_OBJECTS) $(libwindows_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; for p in $$list; do \ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ if test -f $$p \ || test -f $$p1 \ ; then \ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ else :; fi; \ done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; for p in $$list; do \ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ rm -f "$(DESTDIR)$(bindir)/$$f"; \ done clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; for p in $$list; do \ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ echo " rm -f $$p $$f"; \ rm -f $$p $$f ; \ done clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; for p in $$list; do \ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ echo " rm -f $$p $$f"; \ rm -f $$p $$f ; \ done addressmap_unittest$(EXEEXT): $(addressmap_unittest_OBJECTS) $(addressmap_unittest_DEPENDENCIES) @rm -f addressmap_unittest$(EXEEXT) $(CXXLINK) $(addressmap_unittest_LDFLAGS) $(addressmap_unittest_OBJECTS) $(addressmap_unittest_LDADD) $(LIBS) atomicops_unittest$(EXEEXT): $(atomicops_unittest_OBJECTS) $(atomicops_unittest_DEPENDENCIES) @rm -f atomicops_unittest$(EXEEXT) $(CXXLINK) $(atomicops_unittest_LDFLAGS) $(atomicops_unittest_OBJECTS) $(atomicops_unittest_LDADD) $(LIBS) debugallocation_test$(EXEEXT): $(debugallocation_test_OBJECTS) $(debugallocation_test_DEPENDENCIES) @rm -f debugallocation_test$(EXEEXT) $(CXXLINK) $(debugallocation_test_LDFLAGS) $(debugallocation_test_OBJECTS) $(debugallocation_test_LDADD) $(LIBS) @WITH_DEBUGALLOC_FALSE@debugallocation_test.sh$(EXEEXT): $(debugallocation_test_sh_OBJECTS) $(debugallocation_test_sh_DEPENDENCIES) @WITH_DEBUGALLOC_FALSE@ @rm -f debugallocation_test.sh$(EXEEXT) @WITH_DEBUGALLOC_FALSE@ $(LINK) $(debugallocation_test_sh_LDFLAGS) $(debugallocation_test_sh_OBJECTS) $(debugallocation_test_sh_LDADD) $(LIBS) frag_unittest$(EXEEXT): $(frag_unittest_OBJECTS) $(frag_unittest_DEPENDENCIES) @rm -f frag_unittest$(EXEEXT) $(CXXLINK) $(frag_unittest_LDFLAGS) $(frag_unittest_OBJECTS) $(frag_unittest_LDADD) $(LIBS) getpc_test$(EXEEXT): $(getpc_test_OBJECTS) $(getpc_test_DEPENDENCIES) @rm -f getpc_test$(EXEEXT) $(CXXLINK) $(getpc_test_LDFLAGS) $(getpc_test_OBJECTS) $(getpc_test_LDADD) $(LIBS) @WITH_HEAP_CHECKER_FALSE@heap-checker-death_unittest.sh$(EXEEXT): $(heap_checker_death_unittest_sh_OBJECTS) $(heap_checker_death_unittest_sh_DEPENDENCIES) @WITH_HEAP_CHECKER_FALSE@ @rm -f heap-checker-death_unittest.sh$(EXEEXT) @WITH_HEAP_CHECKER_FALSE@ $(LINK) $(heap_checker_death_unittest_sh_LDFLAGS) $(heap_checker_death_unittest_sh_OBJECTS) $(heap_checker_death_unittest_sh_LDADD) $(LIBS) heap-checker_debug_unittest$(EXEEXT): $(heap_checker_debug_unittest_OBJECTS) $(heap_checker_debug_unittest_DEPENDENCIES) @rm -f heap-checker_debug_unittest$(EXEEXT) $(CXXLINK) $(heap_checker_debug_unittest_LDFLAGS) $(heap_checker_debug_unittest_OBJECTS) $(heap_checker_debug_unittest_LDADD) $(LIBS) @WITH_DEBUGALLOC_FALSE@heap-checker_debug_unittest.sh$(EXEEXT): $(heap_checker_debug_unittest_sh_OBJECTS) $(heap_checker_debug_unittest_sh_DEPENDENCIES) @WITH_DEBUGALLOC_FALSE@ @rm -f heap-checker_debug_unittest.sh$(EXEEXT) @WITH_DEBUGALLOC_FALSE@ $(LINK) $(heap_checker_debug_unittest_sh_LDFLAGS) $(heap_checker_debug_unittest_sh_OBJECTS) $(heap_checker_debug_unittest_sh_LDADD) $(LIBS) @WITH_HEAP_CHECKER_FALSE@heap-checker_debug_unittest.sh$(EXEEXT): $(heap_checker_debug_unittest_sh_OBJECTS) $(heap_checker_debug_unittest_sh_DEPENDENCIES) @WITH_HEAP_CHECKER_FALSE@ @rm -f heap-checker_debug_unittest.sh$(EXEEXT) @WITH_HEAP_CHECKER_FALSE@ $(LINK) $(heap_checker_debug_unittest_sh_LDFLAGS) $(heap_checker_debug_unittest_sh_OBJECTS) $(heap_checker_debug_unittest_sh_LDADD) $(LIBS) heap-checker_unittest$(EXEEXT): $(heap_checker_unittest_OBJECTS) $(heap_checker_unittest_DEPENDENCIES) @rm -f heap-checker_unittest$(EXEEXT) $(CXXLINK) $(heap_checker_unittest_LDFLAGS) $(heap_checker_unittest_OBJECTS) $(heap_checker_unittest_LDADD) $(LIBS) @WITH_HEAP_CHECKER_FALSE@heap-checker_unittest.sh$(EXEEXT): $(heap_checker_unittest_sh_OBJECTS) $(heap_checker_unittest_sh_DEPENDENCIES) @WITH_HEAP_CHECKER_FALSE@ @rm -f heap-checker_unittest.sh$(EXEEXT) @WITH_HEAP_CHECKER_FALSE@ $(LINK) $(heap_checker_unittest_sh_LDFLAGS) $(heap_checker_unittest_sh_OBJECTS) $(heap_checker_unittest_sh_LDADD) $(LIBS) heap-profiler_debug_unittest$(EXEEXT): $(heap_profiler_debug_unittest_OBJECTS) $(heap_profiler_debug_unittest_DEPENDENCIES) @rm -f heap-profiler_debug_unittest$(EXEEXT) $(CXXLINK) $(heap_profiler_debug_unittest_LDFLAGS) $(heap_profiler_debug_unittest_OBJECTS) $(heap_profiler_debug_unittest_LDADD) $(LIBS) @WITH_DEBUGALLOC_FALSE@heap-profiler_debug_unittest.sh$(EXEEXT): $(heap_profiler_debug_unittest_sh_OBJECTS) $(heap_profiler_debug_unittest_sh_DEPENDENCIES) @WITH_DEBUGALLOC_FALSE@ @rm -f heap-profiler_debug_unittest.sh$(EXEEXT) @WITH_DEBUGALLOC_FALSE@ $(LINK) $(heap_profiler_debug_unittest_sh_LDFLAGS) $(heap_profiler_debug_unittest_sh_OBJECTS) $(heap_profiler_debug_unittest_sh_LDADD) $(LIBS) @WITH_HEAP_PROFILER_FALSE@heap-profiler_debug_unittest.sh$(EXEEXT): $(heap_profiler_debug_unittest_sh_OBJECTS) $(heap_profiler_debug_unittest_sh_DEPENDENCIES) @WITH_HEAP_PROFILER_FALSE@ @rm -f heap-profiler_debug_unittest.sh$(EXEEXT) @WITH_HEAP_PROFILER_FALSE@ $(LINK) $(heap_profiler_debug_unittest_sh_LDFLAGS) $(heap_profiler_debug_unittest_sh_OBJECTS) $(heap_profiler_debug_unittest_sh_LDADD) $(LIBS) heap-profiler_unittest$(EXEEXT): $(heap_profiler_unittest_OBJECTS) $(heap_profiler_unittest_DEPENDENCIES) @rm -f heap-profiler_unittest$(EXEEXT) $(CXXLINK) $(heap_profiler_unittest_LDFLAGS) $(heap_profiler_unittest_OBJECTS) $(heap_profiler_unittest_LDADD) $(LIBS) @WITH_HEAP_PROFILER_FALSE@heap-profiler_unittest.sh$(EXEEXT): $(heap_profiler_unittest_sh_OBJECTS) $(heap_profiler_unittest_sh_DEPENDENCIES) @WITH_HEAP_PROFILER_FALSE@ @rm -f heap-profiler_unittest.sh$(EXEEXT) @WITH_HEAP_PROFILER_FALSE@ $(LINK) $(heap_profiler_unittest_sh_LDFLAGS) $(heap_profiler_unittest_sh_OBJECTS) $(heap_profiler_unittest_sh_LDADD) $(LIBS) low_level_alloc_unittest$(EXEEXT): $(low_level_alloc_unittest_OBJECTS) $(low_level_alloc_unittest_DEPENDENCIES) @rm -f low_level_alloc_unittest$(EXEEXT) $(CXXLINK) $(low_level_alloc_unittest_LDFLAGS) $(low_level_alloc_unittest_OBJECTS) $(low_level_alloc_unittest_LDADD) $(LIBS) malloc_extension_c_test$(EXEEXT): $(malloc_extension_c_test_OBJECTS) $(malloc_extension_c_test_DEPENDENCIES) @rm -f malloc_extension_c_test$(EXEEXT) $(LINK) $(malloc_extension_c_test_LDFLAGS) $(malloc_extension_c_test_OBJECTS) $(malloc_extension_c_test_LDADD) $(LIBS) malloc_extension_debug_test$(EXEEXT): $(malloc_extension_debug_test_OBJECTS) $(malloc_extension_debug_test_DEPENDENCIES) @rm -f malloc_extension_debug_test$(EXEEXT) $(CXXLINK) $(malloc_extension_debug_test_LDFLAGS) $(malloc_extension_debug_test_OBJECTS) $(malloc_extension_debug_test_LDADD) $(LIBS) malloc_extension_test$(EXEEXT): $(malloc_extension_test_OBJECTS) $(malloc_extension_test_DEPENDENCIES) @rm -f malloc_extension_test$(EXEEXT) $(CXXLINK) $(malloc_extension_test_LDFLAGS) $(malloc_extension_test_OBJECTS) $(malloc_extension_test_LDADD) $(LIBS) markidle_unittest$(EXEEXT): $(markidle_unittest_OBJECTS) $(markidle_unittest_DEPENDENCIES) @rm -f markidle_unittest$(EXEEXT) $(CXXLINK) $(markidle_unittest_LDFLAGS) $(markidle_unittest_OBJECTS) $(markidle_unittest_LDADD) $(LIBS) @ENABLE_STATIC_TRUE@maybe_threads_unittest.sh$(EXEEXT): $(maybe_threads_unittest_sh_OBJECTS) $(maybe_threads_unittest_sh_DEPENDENCIES) @ENABLE_STATIC_TRUE@ @rm -f maybe_threads_unittest.sh$(EXEEXT) @ENABLE_STATIC_TRUE@ $(LINK) $(maybe_threads_unittest_sh_LDFLAGS) $(maybe_threads_unittest_sh_OBJECTS) $(maybe_threads_unittest_sh_LDADD) $(LIBS) @MINGW_TRUE@maybe_threads_unittest.sh$(EXEEXT): $(maybe_threads_unittest_sh_OBJECTS) $(maybe_threads_unittest_sh_DEPENDENCIES) @MINGW_TRUE@ @rm -f maybe_threads_unittest.sh$(EXEEXT) @MINGW_TRUE@ $(LINK) $(maybe_threads_unittest_sh_LDFLAGS) $(maybe_threads_unittest_sh_OBJECTS) $(maybe_threads_unittest_sh_LDADD) $(LIBS) memalign_debug_unittest$(EXEEXT): $(memalign_debug_unittest_OBJECTS) $(memalign_debug_unittest_DEPENDENCIES) @rm -f memalign_debug_unittest$(EXEEXT) $(CXXLINK) $(memalign_debug_unittest_LDFLAGS) $(memalign_debug_unittest_OBJECTS) $(memalign_debug_unittest_LDADD) $(LIBS) memalign_unittest$(EXEEXT): $(memalign_unittest_OBJECTS) $(memalign_unittest_DEPENDENCIES) @rm -f memalign_unittest$(EXEEXT) $(CXXLINK) $(memalign_unittest_LDFLAGS) $(memalign_unittest_OBJECTS) $(memalign_unittest_LDADD) $(LIBS) packed_cache_test$(EXEEXT): $(packed_cache_test_OBJECTS) $(packed_cache_test_DEPENDENCIES) @rm -f packed_cache_test$(EXEEXT) $(CXXLINK) $(packed_cache_test_LDFLAGS) $(packed_cache_test_OBJECTS) $(packed_cache_test_LDADD) $(LIBS) page_heap_test$(EXEEXT): $(page_heap_test_OBJECTS) $(page_heap_test_DEPENDENCIES) @rm -f page_heap_test$(EXEEXT) $(CXXLINK) $(page_heap_test_LDFLAGS) $(page_heap_test_OBJECTS) $(page_heap_test_LDADD) $(LIBS) pagemap_unittest$(EXEEXT): $(pagemap_unittest_OBJECTS) $(pagemap_unittest_DEPENDENCIES) @rm -f pagemap_unittest$(EXEEXT) $(CXXLINK) $(pagemap_unittest_LDFLAGS) $(pagemap_unittest_OBJECTS) $(pagemap_unittest_LDADD) $(LIBS) profile_handler_unittest$(EXEEXT): $(profile_handler_unittest_OBJECTS) $(profile_handler_unittest_DEPENDENCIES) @rm -f profile_handler_unittest$(EXEEXT) $(CXXLINK) $(profile_handler_unittest_LDFLAGS) $(profile_handler_unittest_OBJECTS) $(profile_handler_unittest_LDADD) $(LIBS) profiledata_unittest$(EXEEXT): $(profiledata_unittest_OBJECTS) $(profiledata_unittest_DEPENDENCIES) @rm -f profiledata_unittest$(EXEEXT) $(CXXLINK) $(profiledata_unittest_LDFLAGS) $(profiledata_unittest_OBJECTS) $(profiledata_unittest_LDADD) $(LIBS) profiler1_unittest$(EXEEXT): $(profiler1_unittest_OBJECTS) $(profiler1_unittest_DEPENDENCIES) @rm -f profiler1_unittest$(EXEEXT) $(CXXLINK) $(profiler1_unittest_LDFLAGS) $(profiler1_unittest_OBJECTS) $(profiler1_unittest_LDADD) $(LIBS) profiler2_unittest$(EXEEXT): $(profiler2_unittest_OBJECTS) $(profiler2_unittest_DEPENDENCIES) @rm -f profiler2_unittest$(EXEEXT) $(CXXLINK) $(profiler2_unittest_LDFLAGS) $(profiler2_unittest_OBJECTS) $(profiler2_unittest_LDADD) $(LIBS) profiler3_unittest$(EXEEXT): $(profiler3_unittest_OBJECTS) $(profiler3_unittest_DEPENDENCIES) @rm -f profiler3_unittest$(EXEEXT) $(CXXLINK) $(profiler3_unittest_LDFLAGS) $(profiler3_unittest_OBJECTS) $(profiler3_unittest_LDADD) $(LIBS) profiler4_unittest$(EXEEXT): $(profiler4_unittest_OBJECTS) $(profiler4_unittest_DEPENDENCIES) @rm -f profiler4_unittest$(EXEEXT) $(CXXLINK) $(profiler4_unittest_LDFLAGS) $(profiler4_unittest_OBJECTS) $(profiler4_unittest_LDADD) $(LIBS) @WITH_CPU_PROFILER_FALSE@profiler_unittest.sh$(EXEEXT): $(profiler_unittest_sh_OBJECTS) $(profiler_unittest_sh_DEPENDENCIES) @WITH_CPU_PROFILER_FALSE@ @rm -f profiler_unittest.sh$(EXEEXT) @WITH_CPU_PROFILER_FALSE@ $(LINK) $(profiler_unittest_sh_LDFLAGS) $(profiler_unittest_sh_OBJECTS) $(profiler_unittest_sh_LDADD) $(LIBS) raw_printer_test$(EXEEXT): $(raw_printer_test_OBJECTS) $(raw_printer_test_DEPENDENCIES) @rm -f raw_printer_test$(EXEEXT) $(CXXLINK) $(raw_printer_test_LDFLAGS) $(raw_printer_test_OBJECTS) $(raw_printer_test_LDADD) $(LIBS) realloc_debug_unittest$(EXEEXT): $(realloc_debug_unittest_OBJECTS) $(realloc_debug_unittest_DEPENDENCIES) @rm -f realloc_debug_unittest$(EXEEXT) $(CXXLINK) $(realloc_debug_unittest_LDFLAGS) $(realloc_debug_unittest_OBJECTS) $(realloc_debug_unittest_LDADD) $(LIBS) realloc_unittest$(EXEEXT): $(realloc_unittest_OBJECTS) $(realloc_unittest_DEPENDENCIES) @rm -f realloc_unittest$(EXEEXT) $(CXXLINK) $(realloc_unittest_LDFLAGS) $(realloc_unittest_OBJECTS) $(realloc_unittest_LDADD) $(LIBS) sampler_debug_test$(EXEEXT): $(sampler_debug_test_OBJECTS) $(sampler_debug_test_DEPENDENCIES) @rm -f sampler_debug_test$(EXEEXT) $(CXXLINK) $(sampler_debug_test_LDFLAGS) $(sampler_debug_test_OBJECTS) $(sampler_debug_test_LDADD) $(LIBS) sampler_test$(EXEEXT): $(sampler_test_OBJECTS) $(sampler_test_DEPENDENCIES) @rm -f sampler_test$(EXEEXT) $(CXXLINK) $(sampler_test_LDFLAGS) $(sampler_test_OBJECTS) $(sampler_test_LDADD) $(LIBS) sampling_debug_test$(EXEEXT): $(sampling_debug_test_OBJECTS) $(sampling_debug_test_DEPENDENCIES) @rm -f sampling_debug_test$(EXEEXT) $(CXXLINK) $(sampling_debug_test_LDFLAGS) $(sampling_debug_test_OBJECTS) $(sampling_debug_test_LDADD) $(LIBS) @WITH_DEBUGALLOC_FALSE@sampling_debug_test.sh$(EXEEXT): $(sampling_debug_test_sh_OBJECTS) $(sampling_debug_test_sh_DEPENDENCIES) @WITH_DEBUGALLOC_FALSE@ @rm -f sampling_debug_test.sh$(EXEEXT) @WITH_DEBUGALLOC_FALSE@ $(LINK) $(sampling_debug_test_sh_LDFLAGS) $(sampling_debug_test_sh_OBJECTS) $(sampling_debug_test_sh_LDADD) $(LIBS) @WITH_HEAP_PROFILER_OR_CHECKER_FALSE@sampling_debug_test.sh$(EXEEXT): $(sampling_debug_test_sh_OBJECTS) $(sampling_debug_test_sh_DEPENDENCIES) @WITH_HEAP_PROFILER_OR_CHECKER_FALSE@ @rm -f sampling_debug_test.sh$(EXEEXT) @WITH_HEAP_PROFILER_OR_CHECKER_FALSE@ $(LINK) $(sampling_debug_test_sh_LDFLAGS) $(sampling_debug_test_sh_OBJECTS) $(sampling_debug_test_sh_LDADD) $(LIBS) sampling_test$(EXEEXT): $(sampling_test_OBJECTS) $(sampling_test_DEPENDENCIES) @rm -f sampling_test$(EXEEXT) $(CXXLINK) $(sampling_test_LDFLAGS) $(sampling_test_OBJECTS) $(sampling_test_LDADD) $(LIBS) @WITH_HEAP_PROFILER_OR_CHECKER_FALSE@sampling_test.sh$(EXEEXT): $(sampling_test_sh_OBJECTS) $(sampling_test_sh_DEPENDENCIES) @WITH_HEAP_PROFILER_OR_CHECKER_FALSE@ @rm -f sampling_test.sh$(EXEEXT) @WITH_HEAP_PROFILER_OR_CHECKER_FALSE@ $(LINK) $(sampling_test_sh_LDFLAGS) $(sampling_test_sh_OBJECTS) $(sampling_test_sh_LDADD) $(LIBS) stack_trace_table_test$(EXEEXT): $(stack_trace_table_test_OBJECTS) $(stack_trace_table_test_DEPENDENCIES) @rm -f stack_trace_table_test$(EXEEXT) $(CXXLINK) $(stack_trace_table_test_LDFLAGS) $(stack_trace_table_test_OBJECTS) $(stack_trace_table_test_LDADD) $(LIBS) stacktrace_unittest$(EXEEXT): $(stacktrace_unittest_OBJECTS) $(stacktrace_unittest_DEPENDENCIES) @rm -f stacktrace_unittest$(EXEEXT) $(CXXLINK) $(stacktrace_unittest_LDFLAGS) $(stacktrace_unittest_OBJECTS) $(stacktrace_unittest_LDADD) $(LIBS) system_alloc_unittest$(EXEEXT): $(system_alloc_unittest_OBJECTS) $(system_alloc_unittest_DEPENDENCIES) @rm -f system_alloc_unittest$(EXEEXT) $(CXXLINK) $(system_alloc_unittest_LDFLAGS) $(system_alloc_unittest_OBJECTS) $(system_alloc_unittest_LDADD) $(LIBS) tcmalloc_and_profiler_unittest$(EXEEXT): $(tcmalloc_and_profiler_unittest_OBJECTS) $(tcmalloc_and_profiler_unittest_DEPENDENCIES) @rm -f tcmalloc_and_profiler_unittest$(EXEEXT) $(CXXLINK) $(tcmalloc_and_profiler_unittest_LDFLAGS) $(tcmalloc_and_profiler_unittest_OBJECTS) $(tcmalloc_and_profiler_unittest_LDADD) $(LIBS) tcmalloc_both_unittest$(EXEEXT): $(tcmalloc_both_unittest_OBJECTS) $(tcmalloc_both_unittest_DEPENDENCIES) @rm -f tcmalloc_both_unittest$(EXEEXT) $(CXXLINK) $(tcmalloc_both_unittest_LDFLAGS) $(tcmalloc_both_unittest_OBJECTS) $(tcmalloc_both_unittest_LDADD) $(LIBS) tcmalloc_debug_unittest$(EXEEXT): $(tcmalloc_debug_unittest_OBJECTS) $(tcmalloc_debug_unittest_DEPENDENCIES) @rm -f tcmalloc_debug_unittest$(EXEEXT) $(CXXLINK) $(tcmalloc_debug_unittest_LDFLAGS) $(tcmalloc_debug_unittest_OBJECTS) $(tcmalloc_debug_unittest_LDADD) $(LIBS) tcmalloc_large_unittest$(EXEEXT): $(tcmalloc_large_unittest_OBJECTS) $(tcmalloc_large_unittest_DEPENDENCIES) @rm -f tcmalloc_large_unittest$(EXEEXT) $(CXXLINK) $(tcmalloc_large_unittest_LDFLAGS) $(tcmalloc_large_unittest_OBJECTS) $(tcmalloc_large_unittest_LDADD) $(LIBS) tcmalloc_minimal_debug_unittest$(EXEEXT): $(tcmalloc_minimal_debug_unittest_OBJECTS) $(tcmalloc_minimal_debug_unittest_DEPENDENCIES) @rm -f tcmalloc_minimal_debug_unittest$(EXEEXT) $(CXXLINK) $(tcmalloc_minimal_debug_unittest_LDFLAGS) $(tcmalloc_minimal_debug_unittest_OBJECTS) $(tcmalloc_minimal_debug_unittest_LDADD) $(LIBS) tcmalloc_minimal_large_unittest$(EXEEXT): $(tcmalloc_minimal_large_unittest_OBJECTS) $(tcmalloc_minimal_large_unittest_DEPENDENCIES) @rm -f tcmalloc_minimal_large_unittest$(EXEEXT) $(CXXLINK) $(tcmalloc_minimal_large_unittest_LDFLAGS) $(tcmalloc_minimal_large_unittest_OBJECTS) $(tcmalloc_minimal_large_unittest_LDADD) $(LIBS) tcmalloc_minimal_unittest$(EXEEXT): $(tcmalloc_minimal_unittest_OBJECTS) $(tcmalloc_minimal_unittest_DEPENDENCIES) @rm -f tcmalloc_minimal_unittest$(EXEEXT) $(CXXLINK) $(tcmalloc_minimal_unittest_LDFLAGS) $(tcmalloc_minimal_unittest_OBJECTS) $(tcmalloc_minimal_unittest_LDADD) $(LIBS) tcmalloc_unittest$(EXEEXT): $(tcmalloc_unittest_OBJECTS) $(tcmalloc_unittest_DEPENDENCIES) @rm -f tcmalloc_unittest$(EXEEXT) $(CXXLINK) $(tcmalloc_unittest_LDFLAGS) $(tcmalloc_unittest_OBJECTS) $(tcmalloc_unittest_LDADD) $(LIBS) thread_dealloc_unittest$(EXEEXT): $(thread_dealloc_unittest_OBJECTS) $(thread_dealloc_unittest_DEPENDENCIES) @rm -f thread_dealloc_unittest$(EXEEXT) $(CXXLINK) $(thread_dealloc_unittest_LDFLAGS) $(thread_dealloc_unittest_OBJECTS) $(thread_dealloc_unittest_LDADD) $(LIBS) install-binSCRIPTS: $(bin_SCRIPTS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" @list='$(bin_SCRIPTS)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f $$d$$p; then \ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ echo " $(binSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(bindir)/$$f'"; \ $(binSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(bindir)/$$f"; \ else :; fi; \ done uninstall-binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(bin_SCRIPTS)'; for p in $$list; do \ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ rm -f "$(DESTDIR)$(bindir)/$$f"; \ done mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/addressmap_unittest-addressmap_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/addressmap_unittest-port.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atomicops-internals-x86.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atomicops_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debugallocation_test-debugallocation_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dynamic_annotations.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/frag_unittest-frag_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getpc_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heap_checker_debug_unittest-heap-checker_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heap_checker_unittest-heap-checker_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heap_profiler_debug_unittest-heap-profiler_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heap_profiler_unittest-heap-profiler_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ia32_modrm_map.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ia32_opcode_map.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_and_profiler_la-heap-checker-bcad.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_and_profiler_la-heap-checker.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_and_profiler_la-linuxthreads.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_and_profiler_la-profile-handler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_and_profiler_la-profiledata.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_and_profiler_la-profiler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_and_profiler_la-tcmalloc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_debug_la-debugallocation.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_debug_la-heap-checker-bcad.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_debug_la-heap-checker.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_debug_la-linuxthreads.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-central_freelist.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-common.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-heap-profile-table.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-heap-profiler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-internal_logging.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-low_level_alloc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-malloc_extension.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-malloc_hook.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-maybe_threads.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-memfs_malloc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-memory_region_map.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-page_heap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-raw_printer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-sampler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-span.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-stack_trace_table.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-static_vars.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-symbolize.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-system-alloc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-thread_cache.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-heap-checker-bcad.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-heap-checker.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-linuxthreads.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-tcmalloc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_debug_la-debugallocation.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-central_freelist.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-common.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-internal_logging.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-malloc_extension.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-malloc_hook.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-maybe_threads.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-memfs_malloc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-page_heap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-sampler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-span.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-stack_trace_table.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-static_vars.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-symbolize.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-system-alloc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-thread_cache.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_la-tcmalloc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logging.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/low_level_alloc_unittest-low_level_alloc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/low_level_alloc_unittest-low_level_alloc_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/low_level_alloc_unittest-malloc_hook.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/malloc_extension_c_test-malloc_extension_c_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/malloc_extension_debug_test-malloc_extension_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/malloc_extension_test-malloc_extension_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/markidle_unittest-markidle_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/markidle_unittest-testutil.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memalign_debug_unittest-memalign_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memalign_debug_unittest-testutil.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memalign_unittest-memalign_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memalign_unittest-testutil.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mini_disassembler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packed_cache_test-packed-cache_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/page_heap_test-page_heap_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pagemap_unittest-pagemap_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/patch_functions.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/port.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/preamble_patcher.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/preamble_patcher_with_stub.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profile-handler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profile_handler_unittest-profile-handler_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profiledata.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profiledata_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profiler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profiler1_unittest-profiler_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profiler1_unittest-testutil.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profiler2_unittest-profiler_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profiler2_unittest-testutil.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profiler3_unittest-profiler_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profiler3_unittest-testutil.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profiler4_unittest-profiler_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profiler4_unittest-testutil.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/raw_printer_test-raw_printer_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/realloc_debug_unittest-realloc_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/realloc_unittest-realloc_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sampler_debug_test-sampler_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sampler_test-sampler_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sampling_debug_test-sampling_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sampling_test-sampling_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spinlock.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spinlock_internal.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stack_trace_table_test-stack_trace_table_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stacktrace.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stacktrace_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sysinfo.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/system_alloc_unittest-system-alloc_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcmalloc_and_profiler_unittest-tcmalloc_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcmalloc_and_profiler_unittest-testutil.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcmalloc_both_unittest-tcmalloc_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcmalloc_both_unittest-testutil.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcmalloc_debug_unittest-tcmalloc_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcmalloc_debug_unittest-testutil.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcmalloc_large_unittest-tcmalloc_large_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcmalloc_minimal_debug_unittest-tcmalloc_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcmalloc_minimal_debug_unittest-testutil.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcmalloc_minimal_unittest-tcmalloc_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcmalloc_minimal_unittest-testutil.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcmalloc_unittest-tcmalloc_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcmalloc_unittest-testutil.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread_dealloc_unittest-testutil.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread_dealloc_unittest-thread_dealloc_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread_lister.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vdso_support.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< dynamic_annotations.lo: src/base/dynamic_annotations.c @am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dynamic_annotations.lo -MD -MP -MF "$(DEPDIR)/dynamic_annotations.Tpo" -c -o dynamic_annotations.lo `test -f 'src/base/dynamic_annotations.c' || echo '$(srcdir)/'`src/base/dynamic_annotations.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dynamic_annotations.Tpo" "$(DEPDIR)/dynamic_annotations.Plo"; else rm -f "$(DEPDIR)/dynamic_annotations.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='src/base/dynamic_annotations.c' object='dynamic_annotations.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dynamic_annotations.lo `test -f 'src/base/dynamic_annotations.c' || echo '$(srcdir)/'`src/base/dynamic_annotations.c thread_lister.lo: src/base/thread_lister.c @am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread_lister.lo -MD -MP -MF "$(DEPDIR)/thread_lister.Tpo" -c -o thread_lister.lo `test -f 'src/base/thread_lister.c' || echo '$(srcdir)/'`src/base/thread_lister.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/thread_lister.Tpo" "$(DEPDIR)/thread_lister.Plo"; else rm -f "$(DEPDIR)/thread_lister.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='src/base/thread_lister.c' object='thread_lister.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o thread_lister.lo `test -f 'src/base/thread_lister.c' || echo '$(srcdir)/'`src/base/thread_lister.c malloc_extension_c_test-malloc_extension_c_test.o: src/tests/malloc_extension_c_test.c @am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(malloc_extension_c_test_CFLAGS) $(CFLAGS) -MT malloc_extension_c_test-malloc_extension_c_test.o -MD -MP -MF "$(DEPDIR)/malloc_extension_c_test-malloc_extension_c_test.Tpo" -c -o malloc_extension_c_test-malloc_extension_c_test.o `test -f 'src/tests/malloc_extension_c_test.c' || echo '$(srcdir)/'`src/tests/malloc_extension_c_test.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/malloc_extension_c_test-malloc_extension_c_test.Tpo" "$(DEPDIR)/malloc_extension_c_test-malloc_extension_c_test.Po"; else rm -f "$(DEPDIR)/malloc_extension_c_test-malloc_extension_c_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='src/tests/malloc_extension_c_test.c' object='malloc_extension_c_test-malloc_extension_c_test.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(malloc_extension_c_test_CFLAGS) $(CFLAGS) -c -o malloc_extension_c_test-malloc_extension_c_test.o `test -f 'src/tests/malloc_extension_c_test.c' || echo '$(srcdir)/'`src/tests/malloc_extension_c_test.c malloc_extension_c_test-malloc_extension_c_test.obj: src/tests/malloc_extension_c_test.c @am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(malloc_extension_c_test_CFLAGS) $(CFLAGS) -MT malloc_extension_c_test-malloc_extension_c_test.obj -MD -MP -MF "$(DEPDIR)/malloc_extension_c_test-malloc_extension_c_test.Tpo" -c -o malloc_extension_c_test-malloc_extension_c_test.obj `if test -f 'src/tests/malloc_extension_c_test.c'; then $(CYGPATH_W) 'src/tests/malloc_extension_c_test.c'; else $(CYGPATH_W) '$(srcdir)/src/tests/malloc_extension_c_test.c'; fi`; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/malloc_extension_c_test-malloc_extension_c_test.Tpo" "$(DEPDIR)/malloc_extension_c_test-malloc_extension_c_test.Po"; else rm -f "$(DEPDIR)/malloc_extension_c_test-malloc_extension_c_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='src/tests/malloc_extension_c_test.c' object='malloc_extension_c_test-malloc_extension_c_test.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(malloc_extension_c_test_CFLAGS) $(CFLAGS) -c -o malloc_extension_c_test-malloc_extension_c_test.obj `if test -f 'src/tests/malloc_extension_c_test.c'; then $(CYGPATH_W) 'src/tests/malloc_extension_c_test.c'; else $(CYGPATH_W) '$(srcdir)/src/tests/malloc_extension_c_test.c'; fi` .cc.o: @am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cc.obj: @am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cc.lo: @am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< logging.lo: src/base/logging.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT logging.lo -MD -MP -MF "$(DEPDIR)/logging.Tpo" -c -o logging.lo `test -f 'src/base/logging.cc' || echo '$(srcdir)/'`src/base/logging.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/logging.Tpo" "$(DEPDIR)/logging.Plo"; else rm -f "$(DEPDIR)/logging.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/logging.cc' object='logging.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o logging.lo `test -f 'src/base/logging.cc' || echo '$(srcdir)/'`src/base/logging.cc profiler.lo: src/profiler.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT profiler.lo -MD -MP -MF "$(DEPDIR)/profiler.Tpo" -c -o profiler.lo `test -f 'src/profiler.cc' || echo '$(srcdir)/'`src/profiler.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiler.Tpo" "$(DEPDIR)/profiler.Plo"; else rm -f "$(DEPDIR)/profiler.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/profiler.cc' object='profiler.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o profiler.lo `test -f 'src/profiler.cc' || echo '$(srcdir)/'`src/profiler.cc profile-handler.lo: src/profile-handler.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT profile-handler.lo -MD -MP -MF "$(DEPDIR)/profile-handler.Tpo" -c -o profile-handler.lo `test -f 'src/profile-handler.cc' || echo '$(srcdir)/'`src/profile-handler.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profile-handler.Tpo" "$(DEPDIR)/profile-handler.Plo"; else rm -f "$(DEPDIR)/profile-handler.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/profile-handler.cc' object='profile-handler.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o profile-handler.lo `test -f 'src/profile-handler.cc' || echo '$(srcdir)/'`src/profile-handler.cc profiledata.lo: src/profiledata.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT profiledata.lo -MD -MP -MF "$(DEPDIR)/profiledata.Tpo" -c -o profiledata.lo `test -f 'src/profiledata.cc' || echo '$(srcdir)/'`src/profiledata.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiledata.Tpo" "$(DEPDIR)/profiledata.Plo"; else rm -f "$(DEPDIR)/profiledata.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/profiledata.cc' object='profiledata.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o profiledata.lo `test -f 'src/profiledata.cc' || echo '$(srcdir)/'`src/profiledata.cc spinlock.lo: src/base/spinlock.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT spinlock.lo -MD -MP -MF "$(DEPDIR)/spinlock.Tpo" -c -o spinlock.lo `test -f 'src/base/spinlock.cc' || echo '$(srcdir)/'`src/base/spinlock.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/spinlock.Tpo" "$(DEPDIR)/spinlock.Plo"; else rm -f "$(DEPDIR)/spinlock.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/spinlock.cc' object='spinlock.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o spinlock.lo `test -f 'src/base/spinlock.cc' || echo '$(srcdir)/'`src/base/spinlock.cc spinlock_internal.lo: src/base/spinlock_internal.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT spinlock_internal.lo -MD -MP -MF "$(DEPDIR)/spinlock_internal.Tpo" -c -o spinlock_internal.lo `test -f 'src/base/spinlock_internal.cc' || echo '$(srcdir)/'`src/base/spinlock_internal.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/spinlock_internal.Tpo" "$(DEPDIR)/spinlock_internal.Plo"; else rm -f "$(DEPDIR)/spinlock_internal.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/spinlock_internal.cc' object='spinlock_internal.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o spinlock_internal.lo `test -f 'src/base/spinlock_internal.cc' || echo '$(srcdir)/'`src/base/spinlock_internal.cc atomicops-internals-x86.lo: src/base/atomicops-internals-x86.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT atomicops-internals-x86.lo -MD -MP -MF "$(DEPDIR)/atomicops-internals-x86.Tpo" -c -o atomicops-internals-x86.lo `test -f 'src/base/atomicops-internals-x86.cc' || echo '$(srcdir)/'`src/base/atomicops-internals-x86.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/atomicops-internals-x86.Tpo" "$(DEPDIR)/atomicops-internals-x86.Plo"; else rm -f "$(DEPDIR)/atomicops-internals-x86.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/atomicops-internals-x86.cc' object='atomicops-internals-x86.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o atomicops-internals-x86.lo `test -f 'src/base/atomicops-internals-x86.cc' || echo '$(srcdir)/'`src/base/atomicops-internals-x86.cc stacktrace.lo: src/stacktrace.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT stacktrace.lo -MD -MP -MF "$(DEPDIR)/stacktrace.Tpo" -c -o stacktrace.lo `test -f 'src/stacktrace.cc' || echo '$(srcdir)/'`src/stacktrace.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/stacktrace.Tpo" "$(DEPDIR)/stacktrace.Plo"; else rm -f "$(DEPDIR)/stacktrace.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/stacktrace.cc' object='stacktrace.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o stacktrace.lo `test -f 'src/stacktrace.cc' || echo '$(srcdir)/'`src/stacktrace.cc vdso_support.lo: src/base/vdso_support.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT vdso_support.lo -MD -MP -MF "$(DEPDIR)/vdso_support.Tpo" -c -o vdso_support.lo `test -f 'src/base/vdso_support.cc' || echo '$(srcdir)/'`src/base/vdso_support.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/vdso_support.Tpo" "$(DEPDIR)/vdso_support.Plo"; else rm -f "$(DEPDIR)/vdso_support.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/vdso_support.cc' object='vdso_support.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o vdso_support.lo `test -f 'src/base/vdso_support.cc' || echo '$(srcdir)/'`src/base/vdso_support.cc sysinfo.lo: src/base/sysinfo.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sysinfo.lo -MD -MP -MF "$(DEPDIR)/sysinfo.Tpo" -c -o sysinfo.lo `test -f 'src/base/sysinfo.cc' || echo '$(srcdir)/'`src/base/sysinfo.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/sysinfo.Tpo" "$(DEPDIR)/sysinfo.Plo"; else rm -f "$(DEPDIR)/sysinfo.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/sysinfo.cc' object='sysinfo.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sysinfo.lo `test -f 'src/base/sysinfo.cc' || echo '$(srcdir)/'`src/base/sysinfo.cc libtcmalloc_la-tcmalloc.lo: src/tcmalloc.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-tcmalloc.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-tcmalloc.Tpo" -c -o libtcmalloc_la-tcmalloc.lo `test -f 'src/tcmalloc.cc' || echo '$(srcdir)/'`src/tcmalloc.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-tcmalloc.Tpo" "$(DEPDIR)/libtcmalloc_la-tcmalloc.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-tcmalloc.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tcmalloc.cc' object='libtcmalloc_la-tcmalloc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-tcmalloc.lo `test -f 'src/tcmalloc.cc' || echo '$(srcdir)/'`src/tcmalloc.cc libtcmalloc_la-linuxthreads.lo: src/base/linuxthreads.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-linuxthreads.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-linuxthreads.Tpo" -c -o libtcmalloc_la-linuxthreads.lo `test -f 'src/base/linuxthreads.cc' || echo '$(srcdir)/'`src/base/linuxthreads.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-linuxthreads.Tpo" "$(DEPDIR)/libtcmalloc_la-linuxthreads.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-linuxthreads.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/linuxthreads.cc' object='libtcmalloc_la-linuxthreads.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-linuxthreads.lo `test -f 'src/base/linuxthreads.cc' || echo '$(srcdir)/'`src/base/linuxthreads.cc libtcmalloc_la-heap-checker.lo: src/heap-checker.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-heap-checker.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-heap-checker.Tpo" -c -o libtcmalloc_la-heap-checker.lo `test -f 'src/heap-checker.cc' || echo '$(srcdir)/'`src/heap-checker.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-heap-checker.Tpo" "$(DEPDIR)/libtcmalloc_la-heap-checker.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-heap-checker.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/heap-checker.cc' object='libtcmalloc_la-heap-checker.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-heap-checker.lo `test -f 'src/heap-checker.cc' || echo '$(srcdir)/'`src/heap-checker.cc libtcmalloc_la-heap-checker-bcad.lo: src/heap-checker-bcad.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-heap-checker-bcad.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-heap-checker-bcad.Tpo" -c -o libtcmalloc_la-heap-checker-bcad.lo `test -f 'src/heap-checker-bcad.cc' || echo '$(srcdir)/'`src/heap-checker-bcad.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-heap-checker-bcad.Tpo" "$(DEPDIR)/libtcmalloc_la-heap-checker-bcad.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-heap-checker-bcad.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/heap-checker-bcad.cc' object='libtcmalloc_la-heap-checker-bcad.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-heap-checker-bcad.lo `test -f 'src/heap-checker-bcad.cc' || echo '$(srcdir)/'`src/heap-checker-bcad.cc libtcmalloc_and_profiler_la-tcmalloc.lo: src/tcmalloc.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_and_profiler_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_and_profiler_la-tcmalloc.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_and_profiler_la-tcmalloc.Tpo" -c -o libtcmalloc_and_profiler_la-tcmalloc.lo `test -f 'src/tcmalloc.cc' || echo '$(srcdir)/'`src/tcmalloc.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_and_profiler_la-tcmalloc.Tpo" "$(DEPDIR)/libtcmalloc_and_profiler_la-tcmalloc.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_and_profiler_la-tcmalloc.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tcmalloc.cc' object='libtcmalloc_and_profiler_la-tcmalloc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_and_profiler_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_and_profiler_la-tcmalloc.lo `test -f 'src/tcmalloc.cc' || echo '$(srcdir)/'`src/tcmalloc.cc libtcmalloc_and_profiler_la-linuxthreads.lo: src/base/linuxthreads.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_and_profiler_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_and_profiler_la-linuxthreads.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_and_profiler_la-linuxthreads.Tpo" -c -o libtcmalloc_and_profiler_la-linuxthreads.lo `test -f 'src/base/linuxthreads.cc' || echo '$(srcdir)/'`src/base/linuxthreads.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_and_profiler_la-linuxthreads.Tpo" "$(DEPDIR)/libtcmalloc_and_profiler_la-linuxthreads.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_and_profiler_la-linuxthreads.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/linuxthreads.cc' object='libtcmalloc_and_profiler_la-linuxthreads.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_and_profiler_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_and_profiler_la-linuxthreads.lo `test -f 'src/base/linuxthreads.cc' || echo '$(srcdir)/'`src/base/linuxthreads.cc libtcmalloc_and_profiler_la-heap-checker.lo: src/heap-checker.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_and_profiler_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_and_profiler_la-heap-checker.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_and_profiler_la-heap-checker.Tpo" -c -o libtcmalloc_and_profiler_la-heap-checker.lo `test -f 'src/heap-checker.cc' || echo '$(srcdir)/'`src/heap-checker.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_and_profiler_la-heap-checker.Tpo" "$(DEPDIR)/libtcmalloc_and_profiler_la-heap-checker.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_and_profiler_la-heap-checker.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/heap-checker.cc' object='libtcmalloc_and_profiler_la-heap-checker.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_and_profiler_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_and_profiler_la-heap-checker.lo `test -f 'src/heap-checker.cc' || echo '$(srcdir)/'`src/heap-checker.cc libtcmalloc_and_profiler_la-heap-checker-bcad.lo: src/heap-checker-bcad.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_and_profiler_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_and_profiler_la-heap-checker-bcad.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_and_profiler_la-heap-checker-bcad.Tpo" -c -o libtcmalloc_and_profiler_la-heap-checker-bcad.lo `test -f 'src/heap-checker-bcad.cc' || echo '$(srcdir)/'`src/heap-checker-bcad.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_and_profiler_la-heap-checker-bcad.Tpo" "$(DEPDIR)/libtcmalloc_and_profiler_la-heap-checker-bcad.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_and_profiler_la-heap-checker-bcad.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/heap-checker-bcad.cc' object='libtcmalloc_and_profiler_la-heap-checker-bcad.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_and_profiler_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_and_profiler_la-heap-checker-bcad.lo `test -f 'src/heap-checker-bcad.cc' || echo '$(srcdir)/'`src/heap-checker-bcad.cc libtcmalloc_and_profiler_la-profiler.lo: src/profiler.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_and_profiler_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_and_profiler_la-profiler.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_and_profiler_la-profiler.Tpo" -c -o libtcmalloc_and_profiler_la-profiler.lo `test -f 'src/profiler.cc' || echo '$(srcdir)/'`src/profiler.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_and_profiler_la-profiler.Tpo" "$(DEPDIR)/libtcmalloc_and_profiler_la-profiler.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_and_profiler_la-profiler.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/profiler.cc' object='libtcmalloc_and_profiler_la-profiler.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_and_profiler_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_and_profiler_la-profiler.lo `test -f 'src/profiler.cc' || echo '$(srcdir)/'`src/profiler.cc libtcmalloc_and_profiler_la-profile-handler.lo: src/profile-handler.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_and_profiler_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_and_profiler_la-profile-handler.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_and_profiler_la-profile-handler.Tpo" -c -o libtcmalloc_and_profiler_la-profile-handler.lo `test -f 'src/profile-handler.cc' || echo '$(srcdir)/'`src/profile-handler.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_and_profiler_la-profile-handler.Tpo" "$(DEPDIR)/libtcmalloc_and_profiler_la-profile-handler.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_and_profiler_la-profile-handler.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/profile-handler.cc' object='libtcmalloc_and_profiler_la-profile-handler.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_and_profiler_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_and_profiler_la-profile-handler.lo `test -f 'src/profile-handler.cc' || echo '$(srcdir)/'`src/profile-handler.cc libtcmalloc_and_profiler_la-profiledata.lo: src/profiledata.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_and_profiler_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_and_profiler_la-profiledata.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_and_profiler_la-profiledata.Tpo" -c -o libtcmalloc_and_profiler_la-profiledata.lo `test -f 'src/profiledata.cc' || echo '$(srcdir)/'`src/profiledata.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_and_profiler_la-profiledata.Tpo" "$(DEPDIR)/libtcmalloc_and_profiler_la-profiledata.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_and_profiler_la-profiledata.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/profiledata.cc' object='libtcmalloc_and_profiler_la-profiledata.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_and_profiler_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_and_profiler_la-profiledata.lo `test -f 'src/profiledata.cc' || echo '$(srcdir)/'`src/profiledata.cc libtcmalloc_debug_la-debugallocation.lo: src/debugallocation.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_debug_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_debug_la-debugallocation.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_debug_la-debugallocation.Tpo" -c -o libtcmalloc_debug_la-debugallocation.lo `test -f 'src/debugallocation.cc' || echo '$(srcdir)/'`src/debugallocation.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_debug_la-debugallocation.Tpo" "$(DEPDIR)/libtcmalloc_debug_la-debugallocation.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_debug_la-debugallocation.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/debugallocation.cc' object='libtcmalloc_debug_la-debugallocation.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_debug_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_debug_la-debugallocation.lo `test -f 'src/debugallocation.cc' || echo '$(srcdir)/'`src/debugallocation.cc libtcmalloc_debug_la-linuxthreads.lo: src/base/linuxthreads.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_debug_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_debug_la-linuxthreads.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_debug_la-linuxthreads.Tpo" -c -o libtcmalloc_debug_la-linuxthreads.lo `test -f 'src/base/linuxthreads.cc' || echo '$(srcdir)/'`src/base/linuxthreads.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_debug_la-linuxthreads.Tpo" "$(DEPDIR)/libtcmalloc_debug_la-linuxthreads.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_debug_la-linuxthreads.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/linuxthreads.cc' object='libtcmalloc_debug_la-linuxthreads.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_debug_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_debug_la-linuxthreads.lo `test -f 'src/base/linuxthreads.cc' || echo '$(srcdir)/'`src/base/linuxthreads.cc libtcmalloc_debug_la-heap-checker.lo: src/heap-checker.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_debug_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_debug_la-heap-checker.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_debug_la-heap-checker.Tpo" -c -o libtcmalloc_debug_la-heap-checker.lo `test -f 'src/heap-checker.cc' || echo '$(srcdir)/'`src/heap-checker.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_debug_la-heap-checker.Tpo" "$(DEPDIR)/libtcmalloc_debug_la-heap-checker.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_debug_la-heap-checker.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/heap-checker.cc' object='libtcmalloc_debug_la-heap-checker.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_debug_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_debug_la-heap-checker.lo `test -f 'src/heap-checker.cc' || echo '$(srcdir)/'`src/heap-checker.cc libtcmalloc_debug_la-heap-checker-bcad.lo: src/heap-checker-bcad.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_debug_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_debug_la-heap-checker-bcad.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_debug_la-heap-checker-bcad.Tpo" -c -o libtcmalloc_debug_la-heap-checker-bcad.lo `test -f 'src/heap-checker-bcad.cc' || echo '$(srcdir)/'`src/heap-checker-bcad.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_debug_la-heap-checker-bcad.Tpo" "$(DEPDIR)/libtcmalloc_debug_la-heap-checker-bcad.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_debug_la-heap-checker-bcad.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/heap-checker-bcad.cc' object='libtcmalloc_debug_la-heap-checker-bcad.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_debug_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_debug_la-heap-checker-bcad.lo `test -f 'src/heap-checker-bcad.cc' || echo '$(srcdir)/'`src/heap-checker-bcad.cc libtcmalloc_internal_la-common.lo: src/common.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-common.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-common.Tpo" -c -o libtcmalloc_internal_la-common.lo `test -f 'src/common.cc' || echo '$(srcdir)/'`src/common.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-common.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-common.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-common.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/common.cc' object='libtcmalloc_internal_la-common.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-common.lo `test -f 'src/common.cc' || echo '$(srcdir)/'`src/common.cc libtcmalloc_internal_la-internal_logging.lo: src/internal_logging.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-internal_logging.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-internal_logging.Tpo" -c -o libtcmalloc_internal_la-internal_logging.lo `test -f 'src/internal_logging.cc' || echo '$(srcdir)/'`src/internal_logging.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-internal_logging.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-internal_logging.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-internal_logging.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/internal_logging.cc' object='libtcmalloc_internal_la-internal_logging.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-internal_logging.lo `test -f 'src/internal_logging.cc' || echo '$(srcdir)/'`src/internal_logging.cc libtcmalloc_internal_la-system-alloc.lo: src/system-alloc.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-system-alloc.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-system-alloc.Tpo" -c -o libtcmalloc_internal_la-system-alloc.lo `test -f 'src/system-alloc.cc' || echo '$(srcdir)/'`src/system-alloc.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-system-alloc.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-system-alloc.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-system-alloc.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/system-alloc.cc' object='libtcmalloc_internal_la-system-alloc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-system-alloc.lo `test -f 'src/system-alloc.cc' || echo '$(srcdir)/'`src/system-alloc.cc libtcmalloc_internal_la-memfs_malloc.lo: src/memfs_malloc.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-memfs_malloc.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-memfs_malloc.Tpo" -c -o libtcmalloc_internal_la-memfs_malloc.lo `test -f 'src/memfs_malloc.cc' || echo '$(srcdir)/'`src/memfs_malloc.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-memfs_malloc.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-memfs_malloc.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-memfs_malloc.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/memfs_malloc.cc' object='libtcmalloc_internal_la-memfs_malloc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-memfs_malloc.lo `test -f 'src/memfs_malloc.cc' || echo '$(srcdir)/'`src/memfs_malloc.cc libtcmalloc_internal_la-central_freelist.lo: src/central_freelist.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-central_freelist.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-central_freelist.Tpo" -c -o libtcmalloc_internal_la-central_freelist.lo `test -f 'src/central_freelist.cc' || echo '$(srcdir)/'`src/central_freelist.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-central_freelist.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-central_freelist.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-central_freelist.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/central_freelist.cc' object='libtcmalloc_internal_la-central_freelist.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-central_freelist.lo `test -f 'src/central_freelist.cc' || echo '$(srcdir)/'`src/central_freelist.cc libtcmalloc_internal_la-page_heap.lo: src/page_heap.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-page_heap.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-page_heap.Tpo" -c -o libtcmalloc_internal_la-page_heap.lo `test -f 'src/page_heap.cc' || echo '$(srcdir)/'`src/page_heap.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-page_heap.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-page_heap.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-page_heap.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/page_heap.cc' object='libtcmalloc_internal_la-page_heap.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-page_heap.lo `test -f 'src/page_heap.cc' || echo '$(srcdir)/'`src/page_heap.cc libtcmalloc_internal_la-sampler.lo: src/sampler.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-sampler.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-sampler.Tpo" -c -o libtcmalloc_internal_la-sampler.lo `test -f 'src/sampler.cc' || echo '$(srcdir)/'`src/sampler.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-sampler.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-sampler.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-sampler.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/sampler.cc' object='libtcmalloc_internal_la-sampler.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-sampler.lo `test -f 'src/sampler.cc' || echo '$(srcdir)/'`src/sampler.cc libtcmalloc_internal_la-span.lo: src/span.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-span.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-span.Tpo" -c -o libtcmalloc_internal_la-span.lo `test -f 'src/span.cc' || echo '$(srcdir)/'`src/span.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-span.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-span.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-span.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/span.cc' object='libtcmalloc_internal_la-span.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-span.lo `test -f 'src/span.cc' || echo '$(srcdir)/'`src/span.cc libtcmalloc_internal_la-stack_trace_table.lo: src/stack_trace_table.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-stack_trace_table.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-stack_trace_table.Tpo" -c -o libtcmalloc_internal_la-stack_trace_table.lo `test -f 'src/stack_trace_table.cc' || echo '$(srcdir)/'`src/stack_trace_table.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-stack_trace_table.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-stack_trace_table.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-stack_trace_table.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/stack_trace_table.cc' object='libtcmalloc_internal_la-stack_trace_table.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-stack_trace_table.lo `test -f 'src/stack_trace_table.cc' || echo '$(srcdir)/'`src/stack_trace_table.cc libtcmalloc_internal_la-static_vars.lo: src/static_vars.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-static_vars.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-static_vars.Tpo" -c -o libtcmalloc_internal_la-static_vars.lo `test -f 'src/static_vars.cc' || echo '$(srcdir)/'`src/static_vars.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-static_vars.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-static_vars.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-static_vars.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/static_vars.cc' object='libtcmalloc_internal_la-static_vars.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-static_vars.lo `test -f 'src/static_vars.cc' || echo '$(srcdir)/'`src/static_vars.cc libtcmalloc_internal_la-symbolize.lo: src/symbolize.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-symbolize.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-symbolize.Tpo" -c -o libtcmalloc_internal_la-symbolize.lo `test -f 'src/symbolize.cc' || echo '$(srcdir)/'`src/symbolize.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-symbolize.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-symbolize.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-symbolize.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/symbolize.cc' object='libtcmalloc_internal_la-symbolize.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-symbolize.lo `test -f 'src/symbolize.cc' || echo '$(srcdir)/'`src/symbolize.cc libtcmalloc_internal_la-thread_cache.lo: src/thread_cache.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-thread_cache.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-thread_cache.Tpo" -c -o libtcmalloc_internal_la-thread_cache.lo `test -f 'src/thread_cache.cc' || echo '$(srcdir)/'`src/thread_cache.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-thread_cache.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-thread_cache.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-thread_cache.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/thread_cache.cc' object='libtcmalloc_internal_la-thread_cache.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-thread_cache.lo `test -f 'src/thread_cache.cc' || echo '$(srcdir)/'`src/thread_cache.cc libtcmalloc_internal_la-malloc_hook.lo: src/malloc_hook.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-malloc_hook.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-malloc_hook.Tpo" -c -o libtcmalloc_internal_la-malloc_hook.lo `test -f 'src/malloc_hook.cc' || echo '$(srcdir)/'`src/malloc_hook.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-malloc_hook.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-malloc_hook.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-malloc_hook.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/malloc_hook.cc' object='libtcmalloc_internal_la-malloc_hook.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-malloc_hook.lo `test -f 'src/malloc_hook.cc' || echo '$(srcdir)/'`src/malloc_hook.cc libtcmalloc_internal_la-malloc_extension.lo: src/malloc_extension.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-malloc_extension.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-malloc_extension.Tpo" -c -o libtcmalloc_internal_la-malloc_extension.lo `test -f 'src/malloc_extension.cc' || echo '$(srcdir)/'`src/malloc_extension.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-malloc_extension.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-malloc_extension.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-malloc_extension.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/malloc_extension.cc' object='libtcmalloc_internal_la-malloc_extension.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-malloc_extension.lo `test -f 'src/malloc_extension.cc' || echo '$(srcdir)/'`src/malloc_extension.cc libtcmalloc_internal_la-maybe_threads.lo: src/maybe_threads.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-maybe_threads.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-maybe_threads.Tpo" -c -o libtcmalloc_internal_la-maybe_threads.lo `test -f 'src/maybe_threads.cc' || echo '$(srcdir)/'`src/maybe_threads.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-maybe_threads.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-maybe_threads.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-maybe_threads.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/maybe_threads.cc' object='libtcmalloc_internal_la-maybe_threads.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-maybe_threads.lo `test -f 'src/maybe_threads.cc' || echo '$(srcdir)/'`src/maybe_threads.cc libtcmalloc_internal_la-low_level_alloc.lo: src/base/low_level_alloc.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-low_level_alloc.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-low_level_alloc.Tpo" -c -o libtcmalloc_internal_la-low_level_alloc.lo `test -f 'src/base/low_level_alloc.cc' || echo '$(srcdir)/'`src/base/low_level_alloc.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-low_level_alloc.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-low_level_alloc.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-low_level_alloc.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/low_level_alloc.cc' object='libtcmalloc_internal_la-low_level_alloc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-low_level_alloc.lo `test -f 'src/base/low_level_alloc.cc' || echo '$(srcdir)/'`src/base/low_level_alloc.cc libtcmalloc_internal_la-heap-profile-table.lo: src/heap-profile-table.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-heap-profile-table.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-heap-profile-table.Tpo" -c -o libtcmalloc_internal_la-heap-profile-table.lo `test -f 'src/heap-profile-table.cc' || echo '$(srcdir)/'`src/heap-profile-table.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-heap-profile-table.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-heap-profile-table.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-heap-profile-table.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/heap-profile-table.cc' object='libtcmalloc_internal_la-heap-profile-table.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-heap-profile-table.lo `test -f 'src/heap-profile-table.cc' || echo '$(srcdir)/'`src/heap-profile-table.cc libtcmalloc_internal_la-heap-profiler.lo: src/heap-profiler.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-heap-profiler.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-heap-profiler.Tpo" -c -o libtcmalloc_internal_la-heap-profiler.lo `test -f 'src/heap-profiler.cc' || echo '$(srcdir)/'`src/heap-profiler.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-heap-profiler.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-heap-profiler.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-heap-profiler.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/heap-profiler.cc' object='libtcmalloc_internal_la-heap-profiler.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-heap-profiler.lo `test -f 'src/heap-profiler.cc' || echo '$(srcdir)/'`src/heap-profiler.cc libtcmalloc_internal_la-raw_printer.lo: src/raw_printer.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-raw_printer.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-raw_printer.Tpo" -c -o libtcmalloc_internal_la-raw_printer.lo `test -f 'src/raw_printer.cc' || echo '$(srcdir)/'`src/raw_printer.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-raw_printer.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-raw_printer.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-raw_printer.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/raw_printer.cc' object='libtcmalloc_internal_la-raw_printer.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-raw_printer.lo `test -f 'src/raw_printer.cc' || echo '$(srcdir)/'`src/raw_printer.cc libtcmalloc_internal_la-memory_region_map.lo: src/memory_region_map.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-memory_region_map.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-memory_region_map.Tpo" -c -o libtcmalloc_internal_la-memory_region_map.lo `test -f 'src/memory_region_map.cc' || echo '$(srcdir)/'`src/memory_region_map.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-memory_region_map.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-memory_region_map.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-memory_region_map.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/memory_region_map.cc' object='libtcmalloc_internal_la-memory_region_map.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-memory_region_map.lo `test -f 'src/memory_region_map.cc' || echo '$(srcdir)/'`src/memory_region_map.cc libtcmalloc_minimal_la-tcmalloc.lo: src/tcmalloc.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_la-tcmalloc.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_la-tcmalloc.Tpo" -c -o libtcmalloc_minimal_la-tcmalloc.lo `test -f 'src/tcmalloc.cc' || echo '$(srcdir)/'`src/tcmalloc.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_la-tcmalloc.Tpo" "$(DEPDIR)/libtcmalloc_minimal_la-tcmalloc.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_la-tcmalloc.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tcmalloc.cc' object='libtcmalloc_minimal_la-tcmalloc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_la-tcmalloc.lo `test -f 'src/tcmalloc.cc' || echo '$(srcdir)/'`src/tcmalloc.cc libtcmalloc_minimal_debug_la-debugallocation.lo: src/debugallocation.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_debug_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_debug_la-debugallocation.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_debug_la-debugallocation.Tpo" -c -o libtcmalloc_minimal_debug_la-debugallocation.lo `test -f 'src/debugallocation.cc' || echo '$(srcdir)/'`src/debugallocation.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_debug_la-debugallocation.Tpo" "$(DEPDIR)/libtcmalloc_minimal_debug_la-debugallocation.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_debug_la-debugallocation.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/debugallocation.cc' object='libtcmalloc_minimal_debug_la-debugallocation.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_debug_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_debug_la-debugallocation.lo `test -f 'src/debugallocation.cc' || echo '$(srcdir)/'`src/debugallocation.cc libtcmalloc_minimal_internal_la-common.lo: src/common.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_internal_la-common.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_internal_la-common.Tpo" -c -o libtcmalloc_minimal_internal_la-common.lo `test -f 'src/common.cc' || echo '$(srcdir)/'`src/common.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-common.Tpo" "$(DEPDIR)/libtcmalloc_minimal_internal_la-common.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-common.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/common.cc' object='libtcmalloc_minimal_internal_la-common.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_internal_la-common.lo `test -f 'src/common.cc' || echo '$(srcdir)/'`src/common.cc libtcmalloc_minimal_internal_la-internal_logging.lo: src/internal_logging.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_internal_la-internal_logging.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_internal_la-internal_logging.Tpo" -c -o libtcmalloc_minimal_internal_la-internal_logging.lo `test -f 'src/internal_logging.cc' || echo '$(srcdir)/'`src/internal_logging.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-internal_logging.Tpo" "$(DEPDIR)/libtcmalloc_minimal_internal_la-internal_logging.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-internal_logging.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/internal_logging.cc' object='libtcmalloc_minimal_internal_la-internal_logging.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_internal_la-internal_logging.lo `test -f 'src/internal_logging.cc' || echo '$(srcdir)/'`src/internal_logging.cc libtcmalloc_minimal_internal_la-system-alloc.lo: src/system-alloc.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_internal_la-system-alloc.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_internal_la-system-alloc.Tpo" -c -o libtcmalloc_minimal_internal_la-system-alloc.lo `test -f 'src/system-alloc.cc' || echo '$(srcdir)/'`src/system-alloc.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-system-alloc.Tpo" "$(DEPDIR)/libtcmalloc_minimal_internal_la-system-alloc.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-system-alloc.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/system-alloc.cc' object='libtcmalloc_minimal_internal_la-system-alloc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_internal_la-system-alloc.lo `test -f 'src/system-alloc.cc' || echo '$(srcdir)/'`src/system-alloc.cc libtcmalloc_minimal_internal_la-memfs_malloc.lo: src/memfs_malloc.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_internal_la-memfs_malloc.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_internal_la-memfs_malloc.Tpo" -c -o libtcmalloc_minimal_internal_la-memfs_malloc.lo `test -f 'src/memfs_malloc.cc' || echo '$(srcdir)/'`src/memfs_malloc.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-memfs_malloc.Tpo" "$(DEPDIR)/libtcmalloc_minimal_internal_la-memfs_malloc.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-memfs_malloc.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/memfs_malloc.cc' object='libtcmalloc_minimal_internal_la-memfs_malloc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_internal_la-memfs_malloc.lo `test -f 'src/memfs_malloc.cc' || echo '$(srcdir)/'`src/memfs_malloc.cc libtcmalloc_minimal_internal_la-central_freelist.lo: src/central_freelist.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_internal_la-central_freelist.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_internal_la-central_freelist.Tpo" -c -o libtcmalloc_minimal_internal_la-central_freelist.lo `test -f 'src/central_freelist.cc' || echo '$(srcdir)/'`src/central_freelist.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-central_freelist.Tpo" "$(DEPDIR)/libtcmalloc_minimal_internal_la-central_freelist.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-central_freelist.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/central_freelist.cc' object='libtcmalloc_minimal_internal_la-central_freelist.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_internal_la-central_freelist.lo `test -f 'src/central_freelist.cc' || echo '$(srcdir)/'`src/central_freelist.cc libtcmalloc_minimal_internal_la-page_heap.lo: src/page_heap.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_internal_la-page_heap.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_internal_la-page_heap.Tpo" -c -o libtcmalloc_minimal_internal_la-page_heap.lo `test -f 'src/page_heap.cc' || echo '$(srcdir)/'`src/page_heap.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-page_heap.Tpo" "$(DEPDIR)/libtcmalloc_minimal_internal_la-page_heap.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-page_heap.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/page_heap.cc' object='libtcmalloc_minimal_internal_la-page_heap.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_internal_la-page_heap.lo `test -f 'src/page_heap.cc' || echo '$(srcdir)/'`src/page_heap.cc libtcmalloc_minimal_internal_la-sampler.lo: src/sampler.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_internal_la-sampler.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_internal_la-sampler.Tpo" -c -o libtcmalloc_minimal_internal_la-sampler.lo `test -f 'src/sampler.cc' || echo '$(srcdir)/'`src/sampler.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-sampler.Tpo" "$(DEPDIR)/libtcmalloc_minimal_internal_la-sampler.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-sampler.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/sampler.cc' object='libtcmalloc_minimal_internal_la-sampler.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_internal_la-sampler.lo `test -f 'src/sampler.cc' || echo '$(srcdir)/'`src/sampler.cc libtcmalloc_minimal_internal_la-span.lo: src/span.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_internal_la-span.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_internal_la-span.Tpo" -c -o libtcmalloc_minimal_internal_la-span.lo `test -f 'src/span.cc' || echo '$(srcdir)/'`src/span.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-span.Tpo" "$(DEPDIR)/libtcmalloc_minimal_internal_la-span.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-span.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/span.cc' object='libtcmalloc_minimal_internal_la-span.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_internal_la-span.lo `test -f 'src/span.cc' || echo '$(srcdir)/'`src/span.cc libtcmalloc_minimal_internal_la-stack_trace_table.lo: src/stack_trace_table.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_internal_la-stack_trace_table.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_internal_la-stack_trace_table.Tpo" -c -o libtcmalloc_minimal_internal_la-stack_trace_table.lo `test -f 'src/stack_trace_table.cc' || echo '$(srcdir)/'`src/stack_trace_table.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-stack_trace_table.Tpo" "$(DEPDIR)/libtcmalloc_minimal_internal_la-stack_trace_table.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-stack_trace_table.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/stack_trace_table.cc' object='libtcmalloc_minimal_internal_la-stack_trace_table.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_internal_la-stack_trace_table.lo `test -f 'src/stack_trace_table.cc' || echo '$(srcdir)/'`src/stack_trace_table.cc libtcmalloc_minimal_internal_la-static_vars.lo: src/static_vars.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_internal_la-static_vars.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_internal_la-static_vars.Tpo" -c -o libtcmalloc_minimal_internal_la-static_vars.lo `test -f 'src/static_vars.cc' || echo '$(srcdir)/'`src/static_vars.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-static_vars.Tpo" "$(DEPDIR)/libtcmalloc_minimal_internal_la-static_vars.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-static_vars.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/static_vars.cc' object='libtcmalloc_minimal_internal_la-static_vars.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_internal_la-static_vars.lo `test -f 'src/static_vars.cc' || echo '$(srcdir)/'`src/static_vars.cc libtcmalloc_minimal_internal_la-symbolize.lo: src/symbolize.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_internal_la-symbolize.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_internal_la-symbolize.Tpo" -c -o libtcmalloc_minimal_internal_la-symbolize.lo `test -f 'src/symbolize.cc' || echo '$(srcdir)/'`src/symbolize.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-symbolize.Tpo" "$(DEPDIR)/libtcmalloc_minimal_internal_la-symbolize.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-symbolize.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/symbolize.cc' object='libtcmalloc_minimal_internal_la-symbolize.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_internal_la-symbolize.lo `test -f 'src/symbolize.cc' || echo '$(srcdir)/'`src/symbolize.cc libtcmalloc_minimal_internal_la-thread_cache.lo: src/thread_cache.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_internal_la-thread_cache.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_internal_la-thread_cache.Tpo" -c -o libtcmalloc_minimal_internal_la-thread_cache.lo `test -f 'src/thread_cache.cc' || echo '$(srcdir)/'`src/thread_cache.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-thread_cache.Tpo" "$(DEPDIR)/libtcmalloc_minimal_internal_la-thread_cache.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-thread_cache.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/thread_cache.cc' object='libtcmalloc_minimal_internal_la-thread_cache.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_internal_la-thread_cache.lo `test -f 'src/thread_cache.cc' || echo '$(srcdir)/'`src/thread_cache.cc libtcmalloc_minimal_internal_la-malloc_hook.lo: src/malloc_hook.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_internal_la-malloc_hook.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_internal_la-malloc_hook.Tpo" -c -o libtcmalloc_minimal_internal_la-malloc_hook.lo `test -f 'src/malloc_hook.cc' || echo '$(srcdir)/'`src/malloc_hook.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-malloc_hook.Tpo" "$(DEPDIR)/libtcmalloc_minimal_internal_la-malloc_hook.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-malloc_hook.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/malloc_hook.cc' object='libtcmalloc_minimal_internal_la-malloc_hook.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_internal_la-malloc_hook.lo `test -f 'src/malloc_hook.cc' || echo '$(srcdir)/'`src/malloc_hook.cc libtcmalloc_minimal_internal_la-malloc_extension.lo: src/malloc_extension.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_internal_la-malloc_extension.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_internal_la-malloc_extension.Tpo" -c -o libtcmalloc_minimal_internal_la-malloc_extension.lo `test -f 'src/malloc_extension.cc' || echo '$(srcdir)/'`src/malloc_extension.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-malloc_extension.Tpo" "$(DEPDIR)/libtcmalloc_minimal_internal_la-malloc_extension.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-malloc_extension.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/malloc_extension.cc' object='libtcmalloc_minimal_internal_la-malloc_extension.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_internal_la-malloc_extension.lo `test -f 'src/malloc_extension.cc' || echo '$(srcdir)/'`src/malloc_extension.cc libtcmalloc_minimal_internal_la-maybe_threads.lo: src/maybe_threads.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_internal_la-maybe_threads.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_internal_la-maybe_threads.Tpo" -c -o libtcmalloc_minimal_internal_la-maybe_threads.lo `test -f 'src/maybe_threads.cc' || echo '$(srcdir)/'`src/maybe_threads.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-maybe_threads.Tpo" "$(DEPDIR)/libtcmalloc_minimal_internal_la-maybe_threads.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-maybe_threads.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/maybe_threads.cc' object='libtcmalloc_minimal_internal_la-maybe_threads.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_internal_la-maybe_threads.lo `test -f 'src/maybe_threads.cc' || echo '$(srcdir)/'`src/maybe_threads.cc port.lo: src/windows/port.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT port.lo -MD -MP -MF "$(DEPDIR)/port.Tpo" -c -o port.lo `test -f 'src/windows/port.cc' || echo '$(srcdir)/'`src/windows/port.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/port.Tpo" "$(DEPDIR)/port.Plo"; else rm -f "$(DEPDIR)/port.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/windows/port.cc' object='port.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o port.lo `test -f 'src/windows/port.cc' || echo '$(srcdir)/'`src/windows/port.cc ia32_modrm_map.lo: src/windows/ia32_modrm_map.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ia32_modrm_map.lo -MD -MP -MF "$(DEPDIR)/ia32_modrm_map.Tpo" -c -o ia32_modrm_map.lo `test -f 'src/windows/ia32_modrm_map.cc' || echo '$(srcdir)/'`src/windows/ia32_modrm_map.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ia32_modrm_map.Tpo" "$(DEPDIR)/ia32_modrm_map.Plo"; else rm -f "$(DEPDIR)/ia32_modrm_map.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/windows/ia32_modrm_map.cc' object='ia32_modrm_map.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ia32_modrm_map.lo `test -f 'src/windows/ia32_modrm_map.cc' || echo '$(srcdir)/'`src/windows/ia32_modrm_map.cc ia32_opcode_map.lo: src/windows/ia32_opcode_map.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ia32_opcode_map.lo -MD -MP -MF "$(DEPDIR)/ia32_opcode_map.Tpo" -c -o ia32_opcode_map.lo `test -f 'src/windows/ia32_opcode_map.cc' || echo '$(srcdir)/'`src/windows/ia32_opcode_map.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ia32_opcode_map.Tpo" "$(DEPDIR)/ia32_opcode_map.Plo"; else rm -f "$(DEPDIR)/ia32_opcode_map.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/windows/ia32_opcode_map.cc' object='ia32_opcode_map.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ia32_opcode_map.lo `test -f 'src/windows/ia32_opcode_map.cc' || echo '$(srcdir)/'`src/windows/ia32_opcode_map.cc mini_disassembler.lo: src/windows/mini_disassembler.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mini_disassembler.lo -MD -MP -MF "$(DEPDIR)/mini_disassembler.Tpo" -c -o mini_disassembler.lo `test -f 'src/windows/mini_disassembler.cc' || echo '$(srcdir)/'`src/windows/mini_disassembler.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/mini_disassembler.Tpo" "$(DEPDIR)/mini_disassembler.Plo"; else rm -f "$(DEPDIR)/mini_disassembler.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/windows/mini_disassembler.cc' object='mini_disassembler.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mini_disassembler.lo `test -f 'src/windows/mini_disassembler.cc' || echo '$(srcdir)/'`src/windows/mini_disassembler.cc patch_functions.lo: src/windows/patch_functions.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT patch_functions.lo -MD -MP -MF "$(DEPDIR)/patch_functions.Tpo" -c -o patch_functions.lo `test -f 'src/windows/patch_functions.cc' || echo '$(srcdir)/'`src/windows/patch_functions.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/patch_functions.Tpo" "$(DEPDIR)/patch_functions.Plo"; else rm -f "$(DEPDIR)/patch_functions.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/windows/patch_functions.cc' object='patch_functions.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o patch_functions.lo `test -f 'src/windows/patch_functions.cc' || echo '$(srcdir)/'`src/windows/patch_functions.cc preamble_patcher.lo: src/windows/preamble_patcher.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT preamble_patcher.lo -MD -MP -MF "$(DEPDIR)/preamble_patcher.Tpo" -c -o preamble_patcher.lo `test -f 'src/windows/preamble_patcher.cc' || echo '$(srcdir)/'`src/windows/preamble_patcher.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/preamble_patcher.Tpo" "$(DEPDIR)/preamble_patcher.Plo"; else rm -f "$(DEPDIR)/preamble_patcher.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/windows/preamble_patcher.cc' object='preamble_patcher.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o preamble_patcher.lo `test -f 'src/windows/preamble_patcher.cc' || echo '$(srcdir)/'`src/windows/preamble_patcher.cc preamble_patcher_with_stub.lo: src/windows/preamble_patcher_with_stub.cc @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT preamble_patcher_with_stub.lo -MD -MP -MF "$(DEPDIR)/preamble_patcher_with_stub.Tpo" -c -o preamble_patcher_with_stub.lo `test -f 'src/windows/preamble_patcher_with_stub.cc' || echo '$(srcdir)/'`src/windows/preamble_patcher_with_stub.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/preamble_patcher_with_stub.Tpo" "$(DEPDIR)/preamble_patcher_with_stub.Plo"; else rm -f "$(DEPDIR)/preamble_patcher_with_stub.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/windows/preamble_patcher_with_stub.cc' object='preamble_patcher_with_stub.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o preamble_patcher_with_stub.lo `test -f 'src/windows/preamble_patcher_with_stub.cc' || echo '$(srcdir)/'`src/windows/preamble_patcher_with_stub.cc addressmap_unittest-addressmap_unittest.o: src/tests/addressmap_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(addressmap_unittest_CXXFLAGS) $(CXXFLAGS) -MT addressmap_unittest-addressmap_unittest.o -MD -MP -MF "$(DEPDIR)/addressmap_unittest-addressmap_unittest.Tpo" -c -o addressmap_unittest-addressmap_unittest.o `test -f 'src/tests/addressmap_unittest.cc' || echo '$(srcdir)/'`src/tests/addressmap_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/addressmap_unittest-addressmap_unittest.Tpo" "$(DEPDIR)/addressmap_unittest-addressmap_unittest.Po"; else rm -f "$(DEPDIR)/addressmap_unittest-addressmap_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/addressmap_unittest.cc' object='addressmap_unittest-addressmap_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(addressmap_unittest_CXXFLAGS) $(CXXFLAGS) -c -o addressmap_unittest-addressmap_unittest.o `test -f 'src/tests/addressmap_unittest.cc' || echo '$(srcdir)/'`src/tests/addressmap_unittest.cc addressmap_unittest-addressmap_unittest.obj: src/tests/addressmap_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(addressmap_unittest_CXXFLAGS) $(CXXFLAGS) -MT addressmap_unittest-addressmap_unittest.obj -MD -MP -MF "$(DEPDIR)/addressmap_unittest-addressmap_unittest.Tpo" -c -o addressmap_unittest-addressmap_unittest.obj `if test -f 'src/tests/addressmap_unittest.cc'; then $(CYGPATH_W) 'src/tests/addressmap_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/addressmap_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/addressmap_unittest-addressmap_unittest.Tpo" "$(DEPDIR)/addressmap_unittest-addressmap_unittest.Po"; else rm -f "$(DEPDIR)/addressmap_unittest-addressmap_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/addressmap_unittest.cc' object='addressmap_unittest-addressmap_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(addressmap_unittest_CXXFLAGS) $(CXXFLAGS) -c -o addressmap_unittest-addressmap_unittest.obj `if test -f 'src/tests/addressmap_unittest.cc'; then $(CYGPATH_W) 'src/tests/addressmap_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/addressmap_unittest.cc'; fi` addressmap_unittest-port.o: src/windows/port.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(addressmap_unittest_CXXFLAGS) $(CXXFLAGS) -MT addressmap_unittest-port.o -MD -MP -MF "$(DEPDIR)/addressmap_unittest-port.Tpo" -c -o addressmap_unittest-port.o `test -f 'src/windows/port.cc' || echo '$(srcdir)/'`src/windows/port.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/addressmap_unittest-port.Tpo" "$(DEPDIR)/addressmap_unittest-port.Po"; else rm -f "$(DEPDIR)/addressmap_unittest-port.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/windows/port.cc' object='addressmap_unittest-port.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(addressmap_unittest_CXXFLAGS) $(CXXFLAGS) -c -o addressmap_unittest-port.o `test -f 'src/windows/port.cc' || echo '$(srcdir)/'`src/windows/port.cc addressmap_unittest-port.obj: src/windows/port.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(addressmap_unittest_CXXFLAGS) $(CXXFLAGS) -MT addressmap_unittest-port.obj -MD -MP -MF "$(DEPDIR)/addressmap_unittest-port.Tpo" -c -o addressmap_unittest-port.obj `if test -f 'src/windows/port.cc'; then $(CYGPATH_W) 'src/windows/port.cc'; else $(CYGPATH_W) '$(srcdir)/src/windows/port.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/addressmap_unittest-port.Tpo" "$(DEPDIR)/addressmap_unittest-port.Po"; else rm -f "$(DEPDIR)/addressmap_unittest-port.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/windows/port.cc' object='addressmap_unittest-port.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(addressmap_unittest_CXXFLAGS) $(CXXFLAGS) -c -o addressmap_unittest-port.obj `if test -f 'src/windows/port.cc'; then $(CYGPATH_W) 'src/windows/port.cc'; else $(CYGPATH_W) '$(srcdir)/src/windows/port.cc'; fi` atomicops_unittest.o: src/tests/atomicops_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT atomicops_unittest.o -MD -MP -MF "$(DEPDIR)/atomicops_unittest.Tpo" -c -o atomicops_unittest.o `test -f 'src/tests/atomicops_unittest.cc' || echo '$(srcdir)/'`src/tests/atomicops_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/atomicops_unittest.Tpo" "$(DEPDIR)/atomicops_unittest.Po"; else rm -f "$(DEPDIR)/atomicops_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/atomicops_unittest.cc' object='atomicops_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o atomicops_unittest.o `test -f 'src/tests/atomicops_unittest.cc' || echo '$(srcdir)/'`src/tests/atomicops_unittest.cc atomicops_unittest.obj: src/tests/atomicops_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT atomicops_unittest.obj -MD -MP -MF "$(DEPDIR)/atomicops_unittest.Tpo" -c -o atomicops_unittest.obj `if test -f 'src/tests/atomicops_unittest.cc'; then $(CYGPATH_W) 'src/tests/atomicops_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/atomicops_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/atomicops_unittest.Tpo" "$(DEPDIR)/atomicops_unittest.Po"; else rm -f "$(DEPDIR)/atomicops_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/atomicops_unittest.cc' object='atomicops_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o atomicops_unittest.obj `if test -f 'src/tests/atomicops_unittest.cc'; then $(CYGPATH_W) 'src/tests/atomicops_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/atomicops_unittest.cc'; fi` debugallocation_test-debugallocation_test.o: src/tests/debugallocation_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(debugallocation_test_CXXFLAGS) $(CXXFLAGS) -MT debugallocation_test-debugallocation_test.o -MD -MP -MF "$(DEPDIR)/debugallocation_test-debugallocation_test.Tpo" -c -o debugallocation_test-debugallocation_test.o `test -f 'src/tests/debugallocation_test.cc' || echo '$(srcdir)/'`src/tests/debugallocation_test.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/debugallocation_test-debugallocation_test.Tpo" "$(DEPDIR)/debugallocation_test-debugallocation_test.Po"; else rm -f "$(DEPDIR)/debugallocation_test-debugallocation_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/debugallocation_test.cc' object='debugallocation_test-debugallocation_test.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(debugallocation_test_CXXFLAGS) $(CXXFLAGS) -c -o debugallocation_test-debugallocation_test.o `test -f 'src/tests/debugallocation_test.cc' || echo '$(srcdir)/'`src/tests/debugallocation_test.cc debugallocation_test-debugallocation_test.obj: src/tests/debugallocation_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(debugallocation_test_CXXFLAGS) $(CXXFLAGS) -MT debugallocation_test-debugallocation_test.obj -MD -MP -MF "$(DEPDIR)/debugallocation_test-debugallocation_test.Tpo" -c -o debugallocation_test-debugallocation_test.obj `if test -f 'src/tests/debugallocation_test.cc'; then $(CYGPATH_W) 'src/tests/debugallocation_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/debugallocation_test.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/debugallocation_test-debugallocation_test.Tpo" "$(DEPDIR)/debugallocation_test-debugallocation_test.Po"; else rm -f "$(DEPDIR)/debugallocation_test-debugallocation_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/debugallocation_test.cc' object='debugallocation_test-debugallocation_test.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(debugallocation_test_CXXFLAGS) $(CXXFLAGS) -c -o debugallocation_test-debugallocation_test.obj `if test -f 'src/tests/debugallocation_test.cc'; then $(CYGPATH_W) 'src/tests/debugallocation_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/debugallocation_test.cc'; fi` frag_unittest-frag_unittest.o: src/tests/frag_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(frag_unittest_CXXFLAGS) $(CXXFLAGS) -MT frag_unittest-frag_unittest.o -MD -MP -MF "$(DEPDIR)/frag_unittest-frag_unittest.Tpo" -c -o frag_unittest-frag_unittest.o `test -f 'src/tests/frag_unittest.cc' || echo '$(srcdir)/'`src/tests/frag_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/frag_unittest-frag_unittest.Tpo" "$(DEPDIR)/frag_unittest-frag_unittest.Po"; else rm -f "$(DEPDIR)/frag_unittest-frag_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/frag_unittest.cc' object='frag_unittest-frag_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(frag_unittest_CXXFLAGS) $(CXXFLAGS) -c -o frag_unittest-frag_unittest.o `test -f 'src/tests/frag_unittest.cc' || echo '$(srcdir)/'`src/tests/frag_unittest.cc frag_unittest-frag_unittest.obj: src/tests/frag_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(frag_unittest_CXXFLAGS) $(CXXFLAGS) -MT frag_unittest-frag_unittest.obj -MD -MP -MF "$(DEPDIR)/frag_unittest-frag_unittest.Tpo" -c -o frag_unittest-frag_unittest.obj `if test -f 'src/tests/frag_unittest.cc'; then $(CYGPATH_W) 'src/tests/frag_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/frag_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/frag_unittest-frag_unittest.Tpo" "$(DEPDIR)/frag_unittest-frag_unittest.Po"; else rm -f "$(DEPDIR)/frag_unittest-frag_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/frag_unittest.cc' object='frag_unittest-frag_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(frag_unittest_CXXFLAGS) $(CXXFLAGS) -c -o frag_unittest-frag_unittest.obj `if test -f 'src/tests/frag_unittest.cc'; then $(CYGPATH_W) 'src/tests/frag_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/frag_unittest.cc'; fi` getpc_test.o: src/tests/getpc_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT getpc_test.o -MD -MP -MF "$(DEPDIR)/getpc_test.Tpo" -c -o getpc_test.o `test -f 'src/tests/getpc_test.cc' || echo '$(srcdir)/'`src/tests/getpc_test.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/getpc_test.Tpo" "$(DEPDIR)/getpc_test.Po"; else rm -f "$(DEPDIR)/getpc_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/getpc_test.cc' object='getpc_test.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o getpc_test.o `test -f 'src/tests/getpc_test.cc' || echo '$(srcdir)/'`src/tests/getpc_test.cc getpc_test.obj: src/tests/getpc_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT getpc_test.obj -MD -MP -MF "$(DEPDIR)/getpc_test.Tpo" -c -o getpc_test.obj `if test -f 'src/tests/getpc_test.cc'; then $(CYGPATH_W) 'src/tests/getpc_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/getpc_test.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/getpc_test.Tpo" "$(DEPDIR)/getpc_test.Po"; else rm -f "$(DEPDIR)/getpc_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/getpc_test.cc' object='getpc_test.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o getpc_test.obj `if test -f 'src/tests/getpc_test.cc'; then $(CYGPATH_W) 'src/tests/getpc_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/getpc_test.cc'; fi` heap_checker_debug_unittest-heap-checker_unittest.o: src/tests/heap-checker_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(heap_checker_debug_unittest_CXXFLAGS) $(CXXFLAGS) -MT heap_checker_debug_unittest-heap-checker_unittest.o -MD -MP -MF "$(DEPDIR)/heap_checker_debug_unittest-heap-checker_unittest.Tpo" -c -o heap_checker_debug_unittest-heap-checker_unittest.o `test -f 'src/tests/heap-checker_unittest.cc' || echo '$(srcdir)/'`src/tests/heap-checker_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/heap_checker_debug_unittest-heap-checker_unittest.Tpo" "$(DEPDIR)/heap_checker_debug_unittest-heap-checker_unittest.Po"; else rm -f "$(DEPDIR)/heap_checker_debug_unittest-heap-checker_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/heap-checker_unittest.cc' object='heap_checker_debug_unittest-heap-checker_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(heap_checker_debug_unittest_CXXFLAGS) $(CXXFLAGS) -c -o heap_checker_debug_unittest-heap-checker_unittest.o `test -f 'src/tests/heap-checker_unittest.cc' || echo '$(srcdir)/'`src/tests/heap-checker_unittest.cc heap_checker_debug_unittest-heap-checker_unittest.obj: src/tests/heap-checker_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(heap_checker_debug_unittest_CXXFLAGS) $(CXXFLAGS) -MT heap_checker_debug_unittest-heap-checker_unittest.obj -MD -MP -MF "$(DEPDIR)/heap_checker_debug_unittest-heap-checker_unittest.Tpo" -c -o heap_checker_debug_unittest-heap-checker_unittest.obj `if test -f 'src/tests/heap-checker_unittest.cc'; then $(CYGPATH_W) 'src/tests/heap-checker_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/heap-checker_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/heap_checker_debug_unittest-heap-checker_unittest.Tpo" "$(DEPDIR)/heap_checker_debug_unittest-heap-checker_unittest.Po"; else rm -f "$(DEPDIR)/heap_checker_debug_unittest-heap-checker_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/heap-checker_unittest.cc' object='heap_checker_debug_unittest-heap-checker_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(heap_checker_debug_unittest_CXXFLAGS) $(CXXFLAGS) -c -o heap_checker_debug_unittest-heap-checker_unittest.obj `if test -f 'src/tests/heap-checker_unittest.cc'; then $(CYGPATH_W) 'src/tests/heap-checker_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/heap-checker_unittest.cc'; fi` heap_checker_unittest-heap-checker_unittest.o: src/tests/heap-checker_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(heap_checker_unittest_CXXFLAGS) $(CXXFLAGS) -MT heap_checker_unittest-heap-checker_unittest.o -MD -MP -MF "$(DEPDIR)/heap_checker_unittest-heap-checker_unittest.Tpo" -c -o heap_checker_unittest-heap-checker_unittest.o `test -f 'src/tests/heap-checker_unittest.cc' || echo '$(srcdir)/'`src/tests/heap-checker_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/heap_checker_unittest-heap-checker_unittest.Tpo" "$(DEPDIR)/heap_checker_unittest-heap-checker_unittest.Po"; else rm -f "$(DEPDIR)/heap_checker_unittest-heap-checker_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/heap-checker_unittest.cc' object='heap_checker_unittest-heap-checker_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(heap_checker_unittest_CXXFLAGS) $(CXXFLAGS) -c -o heap_checker_unittest-heap-checker_unittest.o `test -f 'src/tests/heap-checker_unittest.cc' || echo '$(srcdir)/'`src/tests/heap-checker_unittest.cc heap_checker_unittest-heap-checker_unittest.obj: src/tests/heap-checker_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(heap_checker_unittest_CXXFLAGS) $(CXXFLAGS) -MT heap_checker_unittest-heap-checker_unittest.obj -MD -MP -MF "$(DEPDIR)/heap_checker_unittest-heap-checker_unittest.Tpo" -c -o heap_checker_unittest-heap-checker_unittest.obj `if test -f 'src/tests/heap-checker_unittest.cc'; then $(CYGPATH_W) 'src/tests/heap-checker_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/heap-checker_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/heap_checker_unittest-heap-checker_unittest.Tpo" "$(DEPDIR)/heap_checker_unittest-heap-checker_unittest.Po"; else rm -f "$(DEPDIR)/heap_checker_unittest-heap-checker_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/heap-checker_unittest.cc' object='heap_checker_unittest-heap-checker_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(heap_checker_unittest_CXXFLAGS) $(CXXFLAGS) -c -o heap_checker_unittest-heap-checker_unittest.obj `if test -f 'src/tests/heap-checker_unittest.cc'; then $(CYGPATH_W) 'src/tests/heap-checker_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/heap-checker_unittest.cc'; fi` heap_profiler_debug_unittest-heap-profiler_unittest.o: src/tests/heap-profiler_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(heap_profiler_debug_unittest_CXXFLAGS) $(CXXFLAGS) -MT heap_profiler_debug_unittest-heap-profiler_unittest.o -MD -MP -MF "$(DEPDIR)/heap_profiler_debug_unittest-heap-profiler_unittest.Tpo" -c -o heap_profiler_debug_unittest-heap-profiler_unittest.o `test -f 'src/tests/heap-profiler_unittest.cc' || echo '$(srcdir)/'`src/tests/heap-profiler_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/heap_profiler_debug_unittest-heap-profiler_unittest.Tpo" "$(DEPDIR)/heap_profiler_debug_unittest-heap-profiler_unittest.Po"; else rm -f "$(DEPDIR)/heap_profiler_debug_unittest-heap-profiler_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/heap-profiler_unittest.cc' object='heap_profiler_debug_unittest-heap-profiler_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(heap_profiler_debug_unittest_CXXFLAGS) $(CXXFLAGS) -c -o heap_profiler_debug_unittest-heap-profiler_unittest.o `test -f 'src/tests/heap-profiler_unittest.cc' || echo '$(srcdir)/'`src/tests/heap-profiler_unittest.cc heap_profiler_debug_unittest-heap-profiler_unittest.obj: src/tests/heap-profiler_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(heap_profiler_debug_unittest_CXXFLAGS) $(CXXFLAGS) -MT heap_profiler_debug_unittest-heap-profiler_unittest.obj -MD -MP -MF "$(DEPDIR)/heap_profiler_debug_unittest-heap-profiler_unittest.Tpo" -c -o heap_profiler_debug_unittest-heap-profiler_unittest.obj `if test -f 'src/tests/heap-profiler_unittest.cc'; then $(CYGPATH_W) 'src/tests/heap-profiler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/heap-profiler_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/heap_profiler_debug_unittest-heap-profiler_unittest.Tpo" "$(DEPDIR)/heap_profiler_debug_unittest-heap-profiler_unittest.Po"; else rm -f "$(DEPDIR)/heap_profiler_debug_unittest-heap-profiler_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/heap-profiler_unittest.cc' object='heap_profiler_debug_unittest-heap-profiler_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(heap_profiler_debug_unittest_CXXFLAGS) $(CXXFLAGS) -c -o heap_profiler_debug_unittest-heap-profiler_unittest.obj `if test -f 'src/tests/heap-profiler_unittest.cc'; then $(CYGPATH_W) 'src/tests/heap-profiler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/heap-profiler_unittest.cc'; fi` heap_profiler_unittest-heap-profiler_unittest.o: src/tests/heap-profiler_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(heap_profiler_unittest_CXXFLAGS) $(CXXFLAGS) -MT heap_profiler_unittest-heap-profiler_unittest.o -MD -MP -MF "$(DEPDIR)/heap_profiler_unittest-heap-profiler_unittest.Tpo" -c -o heap_profiler_unittest-heap-profiler_unittest.o `test -f 'src/tests/heap-profiler_unittest.cc' || echo '$(srcdir)/'`src/tests/heap-profiler_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/heap_profiler_unittest-heap-profiler_unittest.Tpo" "$(DEPDIR)/heap_profiler_unittest-heap-profiler_unittest.Po"; else rm -f "$(DEPDIR)/heap_profiler_unittest-heap-profiler_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/heap-profiler_unittest.cc' object='heap_profiler_unittest-heap-profiler_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(heap_profiler_unittest_CXXFLAGS) $(CXXFLAGS) -c -o heap_profiler_unittest-heap-profiler_unittest.o `test -f 'src/tests/heap-profiler_unittest.cc' || echo '$(srcdir)/'`src/tests/heap-profiler_unittest.cc heap_profiler_unittest-heap-profiler_unittest.obj: src/tests/heap-profiler_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(heap_profiler_unittest_CXXFLAGS) $(CXXFLAGS) -MT heap_profiler_unittest-heap-profiler_unittest.obj -MD -MP -MF "$(DEPDIR)/heap_profiler_unittest-heap-profiler_unittest.Tpo" -c -o heap_profiler_unittest-heap-profiler_unittest.obj `if test -f 'src/tests/heap-profiler_unittest.cc'; then $(CYGPATH_W) 'src/tests/heap-profiler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/heap-profiler_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/heap_profiler_unittest-heap-profiler_unittest.Tpo" "$(DEPDIR)/heap_profiler_unittest-heap-profiler_unittest.Po"; else rm -f "$(DEPDIR)/heap_profiler_unittest-heap-profiler_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/heap-profiler_unittest.cc' object='heap_profiler_unittest-heap-profiler_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(heap_profiler_unittest_CXXFLAGS) $(CXXFLAGS) -c -o heap_profiler_unittest-heap-profiler_unittest.obj `if test -f 'src/tests/heap-profiler_unittest.cc'; then $(CYGPATH_W) 'src/tests/heap-profiler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/heap-profiler_unittest.cc'; fi` low_level_alloc_unittest-low_level_alloc.o: src/base/low_level_alloc.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT low_level_alloc_unittest-low_level_alloc.o -MD -MP -MF "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc.Tpo" -c -o low_level_alloc_unittest-low_level_alloc.o `test -f 'src/base/low_level_alloc.cc' || echo '$(srcdir)/'`src/base/low_level_alloc.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc.Tpo" "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc.Po"; else rm -f "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/low_level_alloc.cc' object='low_level_alloc_unittest-low_level_alloc.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o low_level_alloc_unittest-low_level_alloc.o `test -f 'src/base/low_level_alloc.cc' || echo '$(srcdir)/'`src/base/low_level_alloc.cc low_level_alloc_unittest-low_level_alloc.obj: src/base/low_level_alloc.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT low_level_alloc_unittest-low_level_alloc.obj -MD -MP -MF "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc.Tpo" -c -o low_level_alloc_unittest-low_level_alloc.obj `if test -f 'src/base/low_level_alloc.cc'; then $(CYGPATH_W) 'src/base/low_level_alloc.cc'; else $(CYGPATH_W) '$(srcdir)/src/base/low_level_alloc.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc.Tpo" "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc.Po"; else rm -f "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/low_level_alloc.cc' object='low_level_alloc_unittest-low_level_alloc.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o low_level_alloc_unittest-low_level_alloc.obj `if test -f 'src/base/low_level_alloc.cc'; then $(CYGPATH_W) 'src/base/low_level_alloc.cc'; else $(CYGPATH_W) '$(srcdir)/src/base/low_level_alloc.cc'; fi` low_level_alloc_unittest-malloc_hook.o: src/malloc_hook.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT low_level_alloc_unittest-malloc_hook.o -MD -MP -MF "$(DEPDIR)/low_level_alloc_unittest-malloc_hook.Tpo" -c -o low_level_alloc_unittest-malloc_hook.o `test -f 'src/malloc_hook.cc' || echo '$(srcdir)/'`src/malloc_hook.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/low_level_alloc_unittest-malloc_hook.Tpo" "$(DEPDIR)/low_level_alloc_unittest-malloc_hook.Po"; else rm -f "$(DEPDIR)/low_level_alloc_unittest-malloc_hook.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/malloc_hook.cc' object='low_level_alloc_unittest-malloc_hook.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o low_level_alloc_unittest-malloc_hook.o `test -f 'src/malloc_hook.cc' || echo '$(srcdir)/'`src/malloc_hook.cc low_level_alloc_unittest-malloc_hook.obj: src/malloc_hook.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT low_level_alloc_unittest-malloc_hook.obj -MD -MP -MF "$(DEPDIR)/low_level_alloc_unittest-malloc_hook.Tpo" -c -o low_level_alloc_unittest-malloc_hook.obj `if test -f 'src/malloc_hook.cc'; then $(CYGPATH_W) 'src/malloc_hook.cc'; else $(CYGPATH_W) '$(srcdir)/src/malloc_hook.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/low_level_alloc_unittest-malloc_hook.Tpo" "$(DEPDIR)/low_level_alloc_unittest-malloc_hook.Po"; else rm -f "$(DEPDIR)/low_level_alloc_unittest-malloc_hook.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/malloc_hook.cc' object='low_level_alloc_unittest-malloc_hook.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o low_level_alloc_unittest-malloc_hook.obj `if test -f 'src/malloc_hook.cc'; then $(CYGPATH_W) 'src/malloc_hook.cc'; else $(CYGPATH_W) '$(srcdir)/src/malloc_hook.cc'; fi` low_level_alloc_unittest-low_level_alloc_unittest.o: src/tests/low_level_alloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT low_level_alloc_unittest-low_level_alloc_unittest.o -MD -MP -MF "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc_unittest.Tpo" -c -o low_level_alloc_unittest-low_level_alloc_unittest.o `test -f 'src/tests/low_level_alloc_unittest.cc' || echo '$(srcdir)/'`src/tests/low_level_alloc_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc_unittest.Tpo" "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc_unittest.Po"; else rm -f "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/low_level_alloc_unittest.cc' object='low_level_alloc_unittest-low_level_alloc_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o low_level_alloc_unittest-low_level_alloc_unittest.o `test -f 'src/tests/low_level_alloc_unittest.cc' || echo '$(srcdir)/'`src/tests/low_level_alloc_unittest.cc low_level_alloc_unittest-low_level_alloc_unittest.obj: src/tests/low_level_alloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT low_level_alloc_unittest-low_level_alloc_unittest.obj -MD -MP -MF "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc_unittest.Tpo" -c -o low_level_alloc_unittest-low_level_alloc_unittest.obj `if test -f 'src/tests/low_level_alloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/low_level_alloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/low_level_alloc_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc_unittest.Tpo" "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc_unittest.Po"; else rm -f "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/low_level_alloc_unittest.cc' object='low_level_alloc_unittest-low_level_alloc_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o low_level_alloc_unittest-low_level_alloc_unittest.obj `if test -f 'src/tests/low_level_alloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/low_level_alloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/low_level_alloc_unittest.cc'; fi` malloc_extension_debug_test-malloc_extension_test.o: src/tests/malloc_extension_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(malloc_extension_debug_test_CXXFLAGS) $(CXXFLAGS) -MT malloc_extension_debug_test-malloc_extension_test.o -MD -MP -MF "$(DEPDIR)/malloc_extension_debug_test-malloc_extension_test.Tpo" -c -o malloc_extension_debug_test-malloc_extension_test.o `test -f 'src/tests/malloc_extension_test.cc' || echo '$(srcdir)/'`src/tests/malloc_extension_test.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/malloc_extension_debug_test-malloc_extension_test.Tpo" "$(DEPDIR)/malloc_extension_debug_test-malloc_extension_test.Po"; else rm -f "$(DEPDIR)/malloc_extension_debug_test-malloc_extension_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/malloc_extension_test.cc' object='malloc_extension_debug_test-malloc_extension_test.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(malloc_extension_debug_test_CXXFLAGS) $(CXXFLAGS) -c -o malloc_extension_debug_test-malloc_extension_test.o `test -f 'src/tests/malloc_extension_test.cc' || echo '$(srcdir)/'`src/tests/malloc_extension_test.cc malloc_extension_debug_test-malloc_extension_test.obj: src/tests/malloc_extension_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(malloc_extension_debug_test_CXXFLAGS) $(CXXFLAGS) -MT malloc_extension_debug_test-malloc_extension_test.obj -MD -MP -MF "$(DEPDIR)/malloc_extension_debug_test-malloc_extension_test.Tpo" -c -o malloc_extension_debug_test-malloc_extension_test.obj `if test -f 'src/tests/malloc_extension_test.cc'; then $(CYGPATH_W) 'src/tests/malloc_extension_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/malloc_extension_test.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/malloc_extension_debug_test-malloc_extension_test.Tpo" "$(DEPDIR)/malloc_extension_debug_test-malloc_extension_test.Po"; else rm -f "$(DEPDIR)/malloc_extension_debug_test-malloc_extension_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/malloc_extension_test.cc' object='malloc_extension_debug_test-malloc_extension_test.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(malloc_extension_debug_test_CXXFLAGS) $(CXXFLAGS) -c -o malloc_extension_debug_test-malloc_extension_test.obj `if test -f 'src/tests/malloc_extension_test.cc'; then $(CYGPATH_W) 'src/tests/malloc_extension_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/malloc_extension_test.cc'; fi` malloc_extension_test-malloc_extension_test.o: src/tests/malloc_extension_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(malloc_extension_test_CXXFLAGS) $(CXXFLAGS) -MT malloc_extension_test-malloc_extension_test.o -MD -MP -MF "$(DEPDIR)/malloc_extension_test-malloc_extension_test.Tpo" -c -o malloc_extension_test-malloc_extension_test.o `test -f 'src/tests/malloc_extension_test.cc' || echo '$(srcdir)/'`src/tests/malloc_extension_test.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/malloc_extension_test-malloc_extension_test.Tpo" "$(DEPDIR)/malloc_extension_test-malloc_extension_test.Po"; else rm -f "$(DEPDIR)/malloc_extension_test-malloc_extension_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/malloc_extension_test.cc' object='malloc_extension_test-malloc_extension_test.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(malloc_extension_test_CXXFLAGS) $(CXXFLAGS) -c -o malloc_extension_test-malloc_extension_test.o `test -f 'src/tests/malloc_extension_test.cc' || echo '$(srcdir)/'`src/tests/malloc_extension_test.cc malloc_extension_test-malloc_extension_test.obj: src/tests/malloc_extension_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(malloc_extension_test_CXXFLAGS) $(CXXFLAGS) -MT malloc_extension_test-malloc_extension_test.obj -MD -MP -MF "$(DEPDIR)/malloc_extension_test-malloc_extension_test.Tpo" -c -o malloc_extension_test-malloc_extension_test.obj `if test -f 'src/tests/malloc_extension_test.cc'; then $(CYGPATH_W) 'src/tests/malloc_extension_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/malloc_extension_test.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/malloc_extension_test-malloc_extension_test.Tpo" "$(DEPDIR)/malloc_extension_test-malloc_extension_test.Po"; else rm -f "$(DEPDIR)/malloc_extension_test-malloc_extension_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/malloc_extension_test.cc' object='malloc_extension_test-malloc_extension_test.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(malloc_extension_test_CXXFLAGS) $(CXXFLAGS) -c -o malloc_extension_test-malloc_extension_test.obj `if test -f 'src/tests/malloc_extension_test.cc'; then $(CYGPATH_W) 'src/tests/malloc_extension_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/malloc_extension_test.cc'; fi` markidle_unittest-markidle_unittest.o: src/tests/markidle_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(markidle_unittest_CXXFLAGS) $(CXXFLAGS) -MT markidle_unittest-markidle_unittest.o -MD -MP -MF "$(DEPDIR)/markidle_unittest-markidle_unittest.Tpo" -c -o markidle_unittest-markidle_unittest.o `test -f 'src/tests/markidle_unittest.cc' || echo '$(srcdir)/'`src/tests/markidle_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/markidle_unittest-markidle_unittest.Tpo" "$(DEPDIR)/markidle_unittest-markidle_unittest.Po"; else rm -f "$(DEPDIR)/markidle_unittest-markidle_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/markidle_unittest.cc' object='markidle_unittest-markidle_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(markidle_unittest_CXXFLAGS) $(CXXFLAGS) -c -o markidle_unittest-markidle_unittest.o `test -f 'src/tests/markidle_unittest.cc' || echo '$(srcdir)/'`src/tests/markidle_unittest.cc markidle_unittest-markidle_unittest.obj: src/tests/markidle_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(markidle_unittest_CXXFLAGS) $(CXXFLAGS) -MT markidle_unittest-markidle_unittest.obj -MD -MP -MF "$(DEPDIR)/markidle_unittest-markidle_unittest.Tpo" -c -o markidle_unittest-markidle_unittest.obj `if test -f 'src/tests/markidle_unittest.cc'; then $(CYGPATH_W) 'src/tests/markidle_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/markidle_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/markidle_unittest-markidle_unittest.Tpo" "$(DEPDIR)/markidle_unittest-markidle_unittest.Po"; else rm -f "$(DEPDIR)/markidle_unittest-markidle_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/markidle_unittest.cc' object='markidle_unittest-markidle_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(markidle_unittest_CXXFLAGS) $(CXXFLAGS) -c -o markidle_unittest-markidle_unittest.obj `if test -f 'src/tests/markidle_unittest.cc'; then $(CYGPATH_W) 'src/tests/markidle_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/markidle_unittest.cc'; fi` markidle_unittest-testutil.o: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(markidle_unittest_CXXFLAGS) $(CXXFLAGS) -MT markidle_unittest-testutil.o -MD -MP -MF "$(DEPDIR)/markidle_unittest-testutil.Tpo" -c -o markidle_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/markidle_unittest-testutil.Tpo" "$(DEPDIR)/markidle_unittest-testutil.Po"; else rm -f "$(DEPDIR)/markidle_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='markidle_unittest-testutil.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(markidle_unittest_CXXFLAGS) $(CXXFLAGS) -c -o markidle_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc markidle_unittest-testutil.obj: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(markidle_unittest_CXXFLAGS) $(CXXFLAGS) -MT markidle_unittest-testutil.obj -MD -MP -MF "$(DEPDIR)/markidle_unittest-testutil.Tpo" -c -o markidle_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/markidle_unittest-testutil.Tpo" "$(DEPDIR)/markidle_unittest-testutil.Po"; else rm -f "$(DEPDIR)/markidle_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='markidle_unittest-testutil.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(markidle_unittest_CXXFLAGS) $(CXXFLAGS) -c -o markidle_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi` memalign_debug_unittest-memalign_unittest.o: src/tests/memalign_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(memalign_debug_unittest_CXXFLAGS) $(CXXFLAGS) -MT memalign_debug_unittest-memalign_unittest.o -MD -MP -MF "$(DEPDIR)/memalign_debug_unittest-memalign_unittest.Tpo" -c -o memalign_debug_unittest-memalign_unittest.o `test -f 'src/tests/memalign_unittest.cc' || echo '$(srcdir)/'`src/tests/memalign_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/memalign_debug_unittest-memalign_unittest.Tpo" "$(DEPDIR)/memalign_debug_unittest-memalign_unittest.Po"; else rm -f "$(DEPDIR)/memalign_debug_unittest-memalign_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/memalign_unittest.cc' object='memalign_debug_unittest-memalign_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(memalign_debug_unittest_CXXFLAGS) $(CXXFLAGS) -c -o memalign_debug_unittest-memalign_unittest.o `test -f 'src/tests/memalign_unittest.cc' || echo '$(srcdir)/'`src/tests/memalign_unittest.cc memalign_debug_unittest-memalign_unittest.obj: src/tests/memalign_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(memalign_debug_unittest_CXXFLAGS) $(CXXFLAGS) -MT memalign_debug_unittest-memalign_unittest.obj -MD -MP -MF "$(DEPDIR)/memalign_debug_unittest-memalign_unittest.Tpo" -c -o memalign_debug_unittest-memalign_unittest.obj `if test -f 'src/tests/memalign_unittest.cc'; then $(CYGPATH_W) 'src/tests/memalign_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/memalign_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/memalign_debug_unittest-memalign_unittest.Tpo" "$(DEPDIR)/memalign_debug_unittest-memalign_unittest.Po"; else rm -f "$(DEPDIR)/memalign_debug_unittest-memalign_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/memalign_unittest.cc' object='memalign_debug_unittest-memalign_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(memalign_debug_unittest_CXXFLAGS) $(CXXFLAGS) -c -o memalign_debug_unittest-memalign_unittest.obj `if test -f 'src/tests/memalign_unittest.cc'; then $(CYGPATH_W) 'src/tests/memalign_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/memalign_unittest.cc'; fi` memalign_debug_unittest-testutil.o: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(memalign_debug_unittest_CXXFLAGS) $(CXXFLAGS) -MT memalign_debug_unittest-testutil.o -MD -MP -MF "$(DEPDIR)/memalign_debug_unittest-testutil.Tpo" -c -o memalign_debug_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/memalign_debug_unittest-testutil.Tpo" "$(DEPDIR)/memalign_debug_unittest-testutil.Po"; else rm -f "$(DEPDIR)/memalign_debug_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='memalign_debug_unittest-testutil.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(memalign_debug_unittest_CXXFLAGS) $(CXXFLAGS) -c -o memalign_debug_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc memalign_debug_unittest-testutil.obj: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(memalign_debug_unittest_CXXFLAGS) $(CXXFLAGS) -MT memalign_debug_unittest-testutil.obj -MD -MP -MF "$(DEPDIR)/memalign_debug_unittest-testutil.Tpo" -c -o memalign_debug_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/memalign_debug_unittest-testutil.Tpo" "$(DEPDIR)/memalign_debug_unittest-testutil.Po"; else rm -f "$(DEPDIR)/memalign_debug_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='memalign_debug_unittest-testutil.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(memalign_debug_unittest_CXXFLAGS) $(CXXFLAGS) -c -o memalign_debug_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi` memalign_unittest-memalign_unittest.o: src/tests/memalign_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(memalign_unittest_CXXFLAGS) $(CXXFLAGS) -MT memalign_unittest-memalign_unittest.o -MD -MP -MF "$(DEPDIR)/memalign_unittest-memalign_unittest.Tpo" -c -o memalign_unittest-memalign_unittest.o `test -f 'src/tests/memalign_unittest.cc' || echo '$(srcdir)/'`src/tests/memalign_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/memalign_unittest-memalign_unittest.Tpo" "$(DEPDIR)/memalign_unittest-memalign_unittest.Po"; else rm -f "$(DEPDIR)/memalign_unittest-memalign_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/memalign_unittest.cc' object='memalign_unittest-memalign_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(memalign_unittest_CXXFLAGS) $(CXXFLAGS) -c -o memalign_unittest-memalign_unittest.o `test -f 'src/tests/memalign_unittest.cc' || echo '$(srcdir)/'`src/tests/memalign_unittest.cc memalign_unittest-memalign_unittest.obj: src/tests/memalign_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(memalign_unittest_CXXFLAGS) $(CXXFLAGS) -MT memalign_unittest-memalign_unittest.obj -MD -MP -MF "$(DEPDIR)/memalign_unittest-memalign_unittest.Tpo" -c -o memalign_unittest-memalign_unittest.obj `if test -f 'src/tests/memalign_unittest.cc'; then $(CYGPATH_W) 'src/tests/memalign_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/memalign_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/memalign_unittest-memalign_unittest.Tpo" "$(DEPDIR)/memalign_unittest-memalign_unittest.Po"; else rm -f "$(DEPDIR)/memalign_unittest-memalign_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/memalign_unittest.cc' object='memalign_unittest-memalign_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(memalign_unittest_CXXFLAGS) $(CXXFLAGS) -c -o memalign_unittest-memalign_unittest.obj `if test -f 'src/tests/memalign_unittest.cc'; then $(CYGPATH_W) 'src/tests/memalign_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/memalign_unittest.cc'; fi` memalign_unittest-testutil.o: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(memalign_unittest_CXXFLAGS) $(CXXFLAGS) -MT memalign_unittest-testutil.o -MD -MP -MF "$(DEPDIR)/memalign_unittest-testutil.Tpo" -c -o memalign_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/memalign_unittest-testutil.Tpo" "$(DEPDIR)/memalign_unittest-testutil.Po"; else rm -f "$(DEPDIR)/memalign_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='memalign_unittest-testutil.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(memalign_unittest_CXXFLAGS) $(CXXFLAGS) -c -o memalign_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc memalign_unittest-testutil.obj: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(memalign_unittest_CXXFLAGS) $(CXXFLAGS) -MT memalign_unittest-testutil.obj -MD -MP -MF "$(DEPDIR)/memalign_unittest-testutil.Tpo" -c -o memalign_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/memalign_unittest-testutil.Tpo" "$(DEPDIR)/memalign_unittest-testutil.Po"; else rm -f "$(DEPDIR)/memalign_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='memalign_unittest-testutil.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(memalign_unittest_CXXFLAGS) $(CXXFLAGS) -c -o memalign_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi` packed_cache_test-packed-cache_test.o: src/tests/packed-cache_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(packed_cache_test_CXXFLAGS) $(CXXFLAGS) -MT packed_cache_test-packed-cache_test.o -MD -MP -MF "$(DEPDIR)/packed_cache_test-packed-cache_test.Tpo" -c -o packed_cache_test-packed-cache_test.o `test -f 'src/tests/packed-cache_test.cc' || echo '$(srcdir)/'`src/tests/packed-cache_test.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/packed_cache_test-packed-cache_test.Tpo" "$(DEPDIR)/packed_cache_test-packed-cache_test.Po"; else rm -f "$(DEPDIR)/packed_cache_test-packed-cache_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/packed-cache_test.cc' object='packed_cache_test-packed-cache_test.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(packed_cache_test_CXXFLAGS) $(CXXFLAGS) -c -o packed_cache_test-packed-cache_test.o `test -f 'src/tests/packed-cache_test.cc' || echo '$(srcdir)/'`src/tests/packed-cache_test.cc packed_cache_test-packed-cache_test.obj: src/tests/packed-cache_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(packed_cache_test_CXXFLAGS) $(CXXFLAGS) -MT packed_cache_test-packed-cache_test.obj -MD -MP -MF "$(DEPDIR)/packed_cache_test-packed-cache_test.Tpo" -c -o packed_cache_test-packed-cache_test.obj `if test -f 'src/tests/packed-cache_test.cc'; then $(CYGPATH_W) 'src/tests/packed-cache_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/packed-cache_test.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/packed_cache_test-packed-cache_test.Tpo" "$(DEPDIR)/packed_cache_test-packed-cache_test.Po"; else rm -f "$(DEPDIR)/packed_cache_test-packed-cache_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/packed-cache_test.cc' object='packed_cache_test-packed-cache_test.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(packed_cache_test_CXXFLAGS) $(CXXFLAGS) -c -o packed_cache_test-packed-cache_test.obj `if test -f 'src/tests/packed-cache_test.cc'; then $(CYGPATH_W) 'src/tests/packed-cache_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/packed-cache_test.cc'; fi` page_heap_test-page_heap_test.o: src/tests/page_heap_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(page_heap_test_CXXFLAGS) $(CXXFLAGS) -MT page_heap_test-page_heap_test.o -MD -MP -MF "$(DEPDIR)/page_heap_test-page_heap_test.Tpo" -c -o page_heap_test-page_heap_test.o `test -f 'src/tests/page_heap_test.cc' || echo '$(srcdir)/'`src/tests/page_heap_test.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/page_heap_test-page_heap_test.Tpo" "$(DEPDIR)/page_heap_test-page_heap_test.Po"; else rm -f "$(DEPDIR)/page_heap_test-page_heap_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/page_heap_test.cc' object='page_heap_test-page_heap_test.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(page_heap_test_CXXFLAGS) $(CXXFLAGS) -c -o page_heap_test-page_heap_test.o `test -f 'src/tests/page_heap_test.cc' || echo '$(srcdir)/'`src/tests/page_heap_test.cc page_heap_test-page_heap_test.obj: src/tests/page_heap_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(page_heap_test_CXXFLAGS) $(CXXFLAGS) -MT page_heap_test-page_heap_test.obj -MD -MP -MF "$(DEPDIR)/page_heap_test-page_heap_test.Tpo" -c -o page_heap_test-page_heap_test.obj `if test -f 'src/tests/page_heap_test.cc'; then $(CYGPATH_W) 'src/tests/page_heap_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/page_heap_test.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/page_heap_test-page_heap_test.Tpo" "$(DEPDIR)/page_heap_test-page_heap_test.Po"; else rm -f "$(DEPDIR)/page_heap_test-page_heap_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/page_heap_test.cc' object='page_heap_test-page_heap_test.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(page_heap_test_CXXFLAGS) $(CXXFLAGS) -c -o page_heap_test-page_heap_test.obj `if test -f 'src/tests/page_heap_test.cc'; then $(CYGPATH_W) 'src/tests/page_heap_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/page_heap_test.cc'; fi` pagemap_unittest-pagemap_unittest.o: src/tests/pagemap_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pagemap_unittest_CXXFLAGS) $(CXXFLAGS) -MT pagemap_unittest-pagemap_unittest.o -MD -MP -MF "$(DEPDIR)/pagemap_unittest-pagemap_unittest.Tpo" -c -o pagemap_unittest-pagemap_unittest.o `test -f 'src/tests/pagemap_unittest.cc' || echo '$(srcdir)/'`src/tests/pagemap_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/pagemap_unittest-pagemap_unittest.Tpo" "$(DEPDIR)/pagemap_unittest-pagemap_unittest.Po"; else rm -f "$(DEPDIR)/pagemap_unittest-pagemap_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/pagemap_unittest.cc' object='pagemap_unittest-pagemap_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pagemap_unittest_CXXFLAGS) $(CXXFLAGS) -c -o pagemap_unittest-pagemap_unittest.o `test -f 'src/tests/pagemap_unittest.cc' || echo '$(srcdir)/'`src/tests/pagemap_unittest.cc pagemap_unittest-pagemap_unittest.obj: src/tests/pagemap_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pagemap_unittest_CXXFLAGS) $(CXXFLAGS) -MT pagemap_unittest-pagemap_unittest.obj -MD -MP -MF "$(DEPDIR)/pagemap_unittest-pagemap_unittest.Tpo" -c -o pagemap_unittest-pagemap_unittest.obj `if test -f 'src/tests/pagemap_unittest.cc'; then $(CYGPATH_W) 'src/tests/pagemap_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/pagemap_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/pagemap_unittest-pagemap_unittest.Tpo" "$(DEPDIR)/pagemap_unittest-pagemap_unittest.Po"; else rm -f "$(DEPDIR)/pagemap_unittest-pagemap_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/pagemap_unittest.cc' object='pagemap_unittest-pagemap_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pagemap_unittest_CXXFLAGS) $(CXXFLAGS) -c -o pagemap_unittest-pagemap_unittest.obj `if test -f 'src/tests/pagemap_unittest.cc'; then $(CYGPATH_W) 'src/tests/pagemap_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/pagemap_unittest.cc'; fi` profile_handler_unittest-profile-handler_unittest.o: src/tests/profile-handler_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profile_handler_unittest_CXXFLAGS) $(CXXFLAGS) -MT profile_handler_unittest-profile-handler_unittest.o -MD -MP -MF "$(DEPDIR)/profile_handler_unittest-profile-handler_unittest.Tpo" -c -o profile_handler_unittest-profile-handler_unittest.o `test -f 'src/tests/profile-handler_unittest.cc' || echo '$(srcdir)/'`src/tests/profile-handler_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profile_handler_unittest-profile-handler_unittest.Tpo" "$(DEPDIR)/profile_handler_unittest-profile-handler_unittest.Po"; else rm -f "$(DEPDIR)/profile_handler_unittest-profile-handler_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/profile-handler_unittest.cc' object='profile_handler_unittest-profile-handler_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profile_handler_unittest_CXXFLAGS) $(CXXFLAGS) -c -o profile_handler_unittest-profile-handler_unittest.o `test -f 'src/tests/profile-handler_unittest.cc' || echo '$(srcdir)/'`src/tests/profile-handler_unittest.cc profile_handler_unittest-profile-handler_unittest.obj: src/tests/profile-handler_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profile_handler_unittest_CXXFLAGS) $(CXXFLAGS) -MT profile_handler_unittest-profile-handler_unittest.obj -MD -MP -MF "$(DEPDIR)/profile_handler_unittest-profile-handler_unittest.Tpo" -c -o profile_handler_unittest-profile-handler_unittest.obj `if test -f 'src/tests/profile-handler_unittest.cc'; then $(CYGPATH_W) 'src/tests/profile-handler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/profile-handler_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profile_handler_unittest-profile-handler_unittest.Tpo" "$(DEPDIR)/profile_handler_unittest-profile-handler_unittest.Po"; else rm -f "$(DEPDIR)/profile_handler_unittest-profile-handler_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/profile-handler_unittest.cc' object='profile_handler_unittest-profile-handler_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profile_handler_unittest_CXXFLAGS) $(CXXFLAGS) -c -o profile_handler_unittest-profile-handler_unittest.obj `if test -f 'src/tests/profile-handler_unittest.cc'; then $(CYGPATH_W) 'src/tests/profile-handler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/profile-handler_unittest.cc'; fi` profiledata_unittest.o: src/tests/profiledata_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT profiledata_unittest.o -MD -MP -MF "$(DEPDIR)/profiledata_unittest.Tpo" -c -o profiledata_unittest.o `test -f 'src/tests/profiledata_unittest.cc' || echo '$(srcdir)/'`src/tests/profiledata_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiledata_unittest.Tpo" "$(DEPDIR)/profiledata_unittest.Po"; else rm -f "$(DEPDIR)/profiledata_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/profiledata_unittest.cc' object='profiledata_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o profiledata_unittest.o `test -f 'src/tests/profiledata_unittest.cc' || echo '$(srcdir)/'`src/tests/profiledata_unittest.cc profiledata_unittest.obj: src/tests/profiledata_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT profiledata_unittest.obj -MD -MP -MF "$(DEPDIR)/profiledata_unittest.Tpo" -c -o profiledata_unittest.obj `if test -f 'src/tests/profiledata_unittest.cc'; then $(CYGPATH_W) 'src/tests/profiledata_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/profiledata_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiledata_unittest.Tpo" "$(DEPDIR)/profiledata_unittest.Po"; else rm -f "$(DEPDIR)/profiledata_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/profiledata_unittest.cc' object='profiledata_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o profiledata_unittest.obj `if test -f 'src/tests/profiledata_unittest.cc'; then $(CYGPATH_W) 'src/tests/profiledata_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/profiledata_unittest.cc'; fi` profiler1_unittest-profiler_unittest.o: src/tests/profiler_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler1_unittest_CXXFLAGS) $(CXXFLAGS) -MT profiler1_unittest-profiler_unittest.o -MD -MP -MF "$(DEPDIR)/profiler1_unittest-profiler_unittest.Tpo" -c -o profiler1_unittest-profiler_unittest.o `test -f 'src/tests/profiler_unittest.cc' || echo '$(srcdir)/'`src/tests/profiler_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiler1_unittest-profiler_unittest.Tpo" "$(DEPDIR)/profiler1_unittest-profiler_unittest.Po"; else rm -f "$(DEPDIR)/profiler1_unittest-profiler_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/profiler_unittest.cc' object='profiler1_unittest-profiler_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler1_unittest_CXXFLAGS) $(CXXFLAGS) -c -o profiler1_unittest-profiler_unittest.o `test -f 'src/tests/profiler_unittest.cc' || echo '$(srcdir)/'`src/tests/profiler_unittest.cc profiler1_unittest-profiler_unittest.obj: src/tests/profiler_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler1_unittest_CXXFLAGS) $(CXXFLAGS) -MT profiler1_unittest-profiler_unittest.obj -MD -MP -MF "$(DEPDIR)/profiler1_unittest-profiler_unittest.Tpo" -c -o profiler1_unittest-profiler_unittest.obj `if test -f 'src/tests/profiler_unittest.cc'; then $(CYGPATH_W) 'src/tests/profiler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/profiler_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiler1_unittest-profiler_unittest.Tpo" "$(DEPDIR)/profiler1_unittest-profiler_unittest.Po"; else rm -f "$(DEPDIR)/profiler1_unittest-profiler_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/profiler_unittest.cc' object='profiler1_unittest-profiler_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler1_unittest_CXXFLAGS) $(CXXFLAGS) -c -o profiler1_unittest-profiler_unittest.obj `if test -f 'src/tests/profiler_unittest.cc'; then $(CYGPATH_W) 'src/tests/profiler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/profiler_unittest.cc'; fi` profiler1_unittest-testutil.o: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler1_unittest_CXXFLAGS) $(CXXFLAGS) -MT profiler1_unittest-testutil.o -MD -MP -MF "$(DEPDIR)/profiler1_unittest-testutil.Tpo" -c -o profiler1_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiler1_unittest-testutil.Tpo" "$(DEPDIR)/profiler1_unittest-testutil.Po"; else rm -f "$(DEPDIR)/profiler1_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='profiler1_unittest-testutil.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler1_unittest_CXXFLAGS) $(CXXFLAGS) -c -o profiler1_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc profiler1_unittest-testutil.obj: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler1_unittest_CXXFLAGS) $(CXXFLAGS) -MT profiler1_unittest-testutil.obj -MD -MP -MF "$(DEPDIR)/profiler1_unittest-testutil.Tpo" -c -o profiler1_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiler1_unittest-testutil.Tpo" "$(DEPDIR)/profiler1_unittest-testutil.Po"; else rm -f "$(DEPDIR)/profiler1_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='profiler1_unittest-testutil.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler1_unittest_CXXFLAGS) $(CXXFLAGS) -c -o profiler1_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi` profiler2_unittest-profiler_unittest.o: src/tests/profiler_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler2_unittest_CXXFLAGS) $(CXXFLAGS) -MT profiler2_unittest-profiler_unittest.o -MD -MP -MF "$(DEPDIR)/profiler2_unittest-profiler_unittest.Tpo" -c -o profiler2_unittest-profiler_unittest.o `test -f 'src/tests/profiler_unittest.cc' || echo '$(srcdir)/'`src/tests/profiler_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiler2_unittest-profiler_unittest.Tpo" "$(DEPDIR)/profiler2_unittest-profiler_unittest.Po"; else rm -f "$(DEPDIR)/profiler2_unittest-profiler_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/profiler_unittest.cc' object='profiler2_unittest-profiler_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler2_unittest_CXXFLAGS) $(CXXFLAGS) -c -o profiler2_unittest-profiler_unittest.o `test -f 'src/tests/profiler_unittest.cc' || echo '$(srcdir)/'`src/tests/profiler_unittest.cc profiler2_unittest-profiler_unittest.obj: src/tests/profiler_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler2_unittest_CXXFLAGS) $(CXXFLAGS) -MT profiler2_unittest-profiler_unittest.obj -MD -MP -MF "$(DEPDIR)/profiler2_unittest-profiler_unittest.Tpo" -c -o profiler2_unittest-profiler_unittest.obj `if test -f 'src/tests/profiler_unittest.cc'; then $(CYGPATH_W) 'src/tests/profiler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/profiler_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiler2_unittest-profiler_unittest.Tpo" "$(DEPDIR)/profiler2_unittest-profiler_unittest.Po"; else rm -f "$(DEPDIR)/profiler2_unittest-profiler_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/profiler_unittest.cc' object='profiler2_unittest-profiler_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler2_unittest_CXXFLAGS) $(CXXFLAGS) -c -o profiler2_unittest-profiler_unittest.obj `if test -f 'src/tests/profiler_unittest.cc'; then $(CYGPATH_W) 'src/tests/profiler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/profiler_unittest.cc'; fi` profiler2_unittest-testutil.o: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler2_unittest_CXXFLAGS) $(CXXFLAGS) -MT profiler2_unittest-testutil.o -MD -MP -MF "$(DEPDIR)/profiler2_unittest-testutil.Tpo" -c -o profiler2_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiler2_unittest-testutil.Tpo" "$(DEPDIR)/profiler2_unittest-testutil.Po"; else rm -f "$(DEPDIR)/profiler2_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='profiler2_unittest-testutil.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler2_unittest_CXXFLAGS) $(CXXFLAGS) -c -o profiler2_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc profiler2_unittest-testutil.obj: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler2_unittest_CXXFLAGS) $(CXXFLAGS) -MT profiler2_unittest-testutil.obj -MD -MP -MF "$(DEPDIR)/profiler2_unittest-testutil.Tpo" -c -o profiler2_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiler2_unittest-testutil.Tpo" "$(DEPDIR)/profiler2_unittest-testutil.Po"; else rm -f "$(DEPDIR)/profiler2_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='profiler2_unittest-testutil.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler2_unittest_CXXFLAGS) $(CXXFLAGS) -c -o profiler2_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi` profiler3_unittest-profiler_unittest.o: src/tests/profiler_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler3_unittest_CXXFLAGS) $(CXXFLAGS) -MT profiler3_unittest-profiler_unittest.o -MD -MP -MF "$(DEPDIR)/profiler3_unittest-profiler_unittest.Tpo" -c -o profiler3_unittest-profiler_unittest.o `test -f 'src/tests/profiler_unittest.cc' || echo '$(srcdir)/'`src/tests/profiler_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiler3_unittest-profiler_unittest.Tpo" "$(DEPDIR)/profiler3_unittest-profiler_unittest.Po"; else rm -f "$(DEPDIR)/profiler3_unittest-profiler_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/profiler_unittest.cc' object='profiler3_unittest-profiler_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler3_unittest_CXXFLAGS) $(CXXFLAGS) -c -o profiler3_unittest-profiler_unittest.o `test -f 'src/tests/profiler_unittest.cc' || echo '$(srcdir)/'`src/tests/profiler_unittest.cc profiler3_unittest-profiler_unittest.obj: src/tests/profiler_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler3_unittest_CXXFLAGS) $(CXXFLAGS) -MT profiler3_unittest-profiler_unittest.obj -MD -MP -MF "$(DEPDIR)/profiler3_unittest-profiler_unittest.Tpo" -c -o profiler3_unittest-profiler_unittest.obj `if test -f 'src/tests/profiler_unittest.cc'; then $(CYGPATH_W) 'src/tests/profiler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/profiler_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiler3_unittest-profiler_unittest.Tpo" "$(DEPDIR)/profiler3_unittest-profiler_unittest.Po"; else rm -f "$(DEPDIR)/profiler3_unittest-profiler_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/profiler_unittest.cc' object='profiler3_unittest-profiler_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler3_unittest_CXXFLAGS) $(CXXFLAGS) -c -o profiler3_unittest-profiler_unittest.obj `if test -f 'src/tests/profiler_unittest.cc'; then $(CYGPATH_W) 'src/tests/profiler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/profiler_unittest.cc'; fi` profiler3_unittest-testutil.o: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler3_unittest_CXXFLAGS) $(CXXFLAGS) -MT profiler3_unittest-testutil.o -MD -MP -MF "$(DEPDIR)/profiler3_unittest-testutil.Tpo" -c -o profiler3_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiler3_unittest-testutil.Tpo" "$(DEPDIR)/profiler3_unittest-testutil.Po"; else rm -f "$(DEPDIR)/profiler3_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='profiler3_unittest-testutil.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler3_unittest_CXXFLAGS) $(CXXFLAGS) -c -o profiler3_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc profiler3_unittest-testutil.obj: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler3_unittest_CXXFLAGS) $(CXXFLAGS) -MT profiler3_unittest-testutil.obj -MD -MP -MF "$(DEPDIR)/profiler3_unittest-testutil.Tpo" -c -o profiler3_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiler3_unittest-testutil.Tpo" "$(DEPDIR)/profiler3_unittest-testutil.Po"; else rm -f "$(DEPDIR)/profiler3_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='profiler3_unittest-testutil.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler3_unittest_CXXFLAGS) $(CXXFLAGS) -c -o profiler3_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi` profiler4_unittest-profiler_unittest.o: src/tests/profiler_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler4_unittest_CXXFLAGS) $(CXXFLAGS) -MT profiler4_unittest-profiler_unittest.o -MD -MP -MF "$(DEPDIR)/profiler4_unittest-profiler_unittest.Tpo" -c -o profiler4_unittest-profiler_unittest.o `test -f 'src/tests/profiler_unittest.cc' || echo '$(srcdir)/'`src/tests/profiler_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiler4_unittest-profiler_unittest.Tpo" "$(DEPDIR)/profiler4_unittest-profiler_unittest.Po"; else rm -f "$(DEPDIR)/profiler4_unittest-profiler_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/profiler_unittest.cc' object='profiler4_unittest-profiler_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler4_unittest_CXXFLAGS) $(CXXFLAGS) -c -o profiler4_unittest-profiler_unittest.o `test -f 'src/tests/profiler_unittest.cc' || echo '$(srcdir)/'`src/tests/profiler_unittest.cc profiler4_unittest-profiler_unittest.obj: src/tests/profiler_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler4_unittest_CXXFLAGS) $(CXXFLAGS) -MT profiler4_unittest-profiler_unittest.obj -MD -MP -MF "$(DEPDIR)/profiler4_unittest-profiler_unittest.Tpo" -c -o profiler4_unittest-profiler_unittest.obj `if test -f 'src/tests/profiler_unittest.cc'; then $(CYGPATH_W) 'src/tests/profiler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/profiler_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiler4_unittest-profiler_unittest.Tpo" "$(DEPDIR)/profiler4_unittest-profiler_unittest.Po"; else rm -f "$(DEPDIR)/profiler4_unittest-profiler_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/profiler_unittest.cc' object='profiler4_unittest-profiler_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler4_unittest_CXXFLAGS) $(CXXFLAGS) -c -o profiler4_unittest-profiler_unittest.obj `if test -f 'src/tests/profiler_unittest.cc'; then $(CYGPATH_W) 'src/tests/profiler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/profiler_unittest.cc'; fi` profiler4_unittest-testutil.o: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler4_unittest_CXXFLAGS) $(CXXFLAGS) -MT profiler4_unittest-testutil.o -MD -MP -MF "$(DEPDIR)/profiler4_unittest-testutil.Tpo" -c -o profiler4_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiler4_unittest-testutil.Tpo" "$(DEPDIR)/profiler4_unittest-testutil.Po"; else rm -f "$(DEPDIR)/profiler4_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='profiler4_unittest-testutil.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler4_unittest_CXXFLAGS) $(CXXFLAGS) -c -o profiler4_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc profiler4_unittest-testutil.obj: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler4_unittest_CXXFLAGS) $(CXXFLAGS) -MT profiler4_unittest-testutil.obj -MD -MP -MF "$(DEPDIR)/profiler4_unittest-testutil.Tpo" -c -o profiler4_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiler4_unittest-testutil.Tpo" "$(DEPDIR)/profiler4_unittest-testutil.Po"; else rm -f "$(DEPDIR)/profiler4_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='profiler4_unittest-testutil.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler4_unittest_CXXFLAGS) $(CXXFLAGS) -c -o profiler4_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi` raw_printer_test-raw_printer_test.o: src/tests/raw_printer_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(raw_printer_test_CXXFLAGS) $(CXXFLAGS) -MT raw_printer_test-raw_printer_test.o -MD -MP -MF "$(DEPDIR)/raw_printer_test-raw_printer_test.Tpo" -c -o raw_printer_test-raw_printer_test.o `test -f 'src/tests/raw_printer_test.cc' || echo '$(srcdir)/'`src/tests/raw_printer_test.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/raw_printer_test-raw_printer_test.Tpo" "$(DEPDIR)/raw_printer_test-raw_printer_test.Po"; else rm -f "$(DEPDIR)/raw_printer_test-raw_printer_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/raw_printer_test.cc' object='raw_printer_test-raw_printer_test.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(raw_printer_test_CXXFLAGS) $(CXXFLAGS) -c -o raw_printer_test-raw_printer_test.o `test -f 'src/tests/raw_printer_test.cc' || echo '$(srcdir)/'`src/tests/raw_printer_test.cc raw_printer_test-raw_printer_test.obj: src/tests/raw_printer_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(raw_printer_test_CXXFLAGS) $(CXXFLAGS) -MT raw_printer_test-raw_printer_test.obj -MD -MP -MF "$(DEPDIR)/raw_printer_test-raw_printer_test.Tpo" -c -o raw_printer_test-raw_printer_test.obj `if test -f 'src/tests/raw_printer_test.cc'; then $(CYGPATH_W) 'src/tests/raw_printer_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/raw_printer_test.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/raw_printer_test-raw_printer_test.Tpo" "$(DEPDIR)/raw_printer_test-raw_printer_test.Po"; else rm -f "$(DEPDIR)/raw_printer_test-raw_printer_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/raw_printer_test.cc' object='raw_printer_test-raw_printer_test.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(raw_printer_test_CXXFLAGS) $(CXXFLAGS) -c -o raw_printer_test-raw_printer_test.obj `if test -f 'src/tests/raw_printer_test.cc'; then $(CYGPATH_W) 'src/tests/raw_printer_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/raw_printer_test.cc'; fi` realloc_debug_unittest-realloc_unittest.o: src/tests/realloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(realloc_debug_unittest_CXXFLAGS) $(CXXFLAGS) -MT realloc_debug_unittest-realloc_unittest.o -MD -MP -MF "$(DEPDIR)/realloc_debug_unittest-realloc_unittest.Tpo" -c -o realloc_debug_unittest-realloc_unittest.o `test -f 'src/tests/realloc_unittest.cc' || echo '$(srcdir)/'`src/tests/realloc_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/realloc_debug_unittest-realloc_unittest.Tpo" "$(DEPDIR)/realloc_debug_unittest-realloc_unittest.Po"; else rm -f "$(DEPDIR)/realloc_debug_unittest-realloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/realloc_unittest.cc' object='realloc_debug_unittest-realloc_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(realloc_debug_unittest_CXXFLAGS) $(CXXFLAGS) -c -o realloc_debug_unittest-realloc_unittest.o `test -f 'src/tests/realloc_unittest.cc' || echo '$(srcdir)/'`src/tests/realloc_unittest.cc realloc_debug_unittest-realloc_unittest.obj: src/tests/realloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(realloc_debug_unittest_CXXFLAGS) $(CXXFLAGS) -MT realloc_debug_unittest-realloc_unittest.obj -MD -MP -MF "$(DEPDIR)/realloc_debug_unittest-realloc_unittest.Tpo" -c -o realloc_debug_unittest-realloc_unittest.obj `if test -f 'src/tests/realloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/realloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/realloc_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/realloc_debug_unittest-realloc_unittest.Tpo" "$(DEPDIR)/realloc_debug_unittest-realloc_unittest.Po"; else rm -f "$(DEPDIR)/realloc_debug_unittest-realloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/realloc_unittest.cc' object='realloc_debug_unittest-realloc_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(realloc_debug_unittest_CXXFLAGS) $(CXXFLAGS) -c -o realloc_debug_unittest-realloc_unittest.obj `if test -f 'src/tests/realloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/realloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/realloc_unittest.cc'; fi` realloc_unittest-realloc_unittest.o: src/tests/realloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(realloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT realloc_unittest-realloc_unittest.o -MD -MP -MF "$(DEPDIR)/realloc_unittest-realloc_unittest.Tpo" -c -o realloc_unittest-realloc_unittest.o `test -f 'src/tests/realloc_unittest.cc' || echo '$(srcdir)/'`src/tests/realloc_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/realloc_unittest-realloc_unittest.Tpo" "$(DEPDIR)/realloc_unittest-realloc_unittest.Po"; else rm -f "$(DEPDIR)/realloc_unittest-realloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/realloc_unittest.cc' object='realloc_unittest-realloc_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(realloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o realloc_unittest-realloc_unittest.o `test -f 'src/tests/realloc_unittest.cc' || echo '$(srcdir)/'`src/tests/realloc_unittest.cc realloc_unittest-realloc_unittest.obj: src/tests/realloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(realloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT realloc_unittest-realloc_unittest.obj -MD -MP -MF "$(DEPDIR)/realloc_unittest-realloc_unittest.Tpo" -c -o realloc_unittest-realloc_unittest.obj `if test -f 'src/tests/realloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/realloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/realloc_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/realloc_unittest-realloc_unittest.Tpo" "$(DEPDIR)/realloc_unittest-realloc_unittest.Po"; else rm -f "$(DEPDIR)/realloc_unittest-realloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/realloc_unittest.cc' object='realloc_unittest-realloc_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(realloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o realloc_unittest-realloc_unittest.obj `if test -f 'src/tests/realloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/realloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/realloc_unittest.cc'; fi` sampler_debug_test-sampler_test.o: src/tests/sampler_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampler_debug_test_CXXFLAGS) $(CXXFLAGS) -MT sampler_debug_test-sampler_test.o -MD -MP -MF "$(DEPDIR)/sampler_debug_test-sampler_test.Tpo" -c -o sampler_debug_test-sampler_test.o `test -f 'src/tests/sampler_test.cc' || echo '$(srcdir)/'`src/tests/sampler_test.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/sampler_debug_test-sampler_test.Tpo" "$(DEPDIR)/sampler_debug_test-sampler_test.Po"; else rm -f "$(DEPDIR)/sampler_debug_test-sampler_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/sampler_test.cc' object='sampler_debug_test-sampler_test.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampler_debug_test_CXXFLAGS) $(CXXFLAGS) -c -o sampler_debug_test-sampler_test.o `test -f 'src/tests/sampler_test.cc' || echo '$(srcdir)/'`src/tests/sampler_test.cc sampler_debug_test-sampler_test.obj: src/tests/sampler_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampler_debug_test_CXXFLAGS) $(CXXFLAGS) -MT sampler_debug_test-sampler_test.obj -MD -MP -MF "$(DEPDIR)/sampler_debug_test-sampler_test.Tpo" -c -o sampler_debug_test-sampler_test.obj `if test -f 'src/tests/sampler_test.cc'; then $(CYGPATH_W) 'src/tests/sampler_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/sampler_test.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/sampler_debug_test-sampler_test.Tpo" "$(DEPDIR)/sampler_debug_test-sampler_test.Po"; else rm -f "$(DEPDIR)/sampler_debug_test-sampler_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/sampler_test.cc' object='sampler_debug_test-sampler_test.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampler_debug_test_CXXFLAGS) $(CXXFLAGS) -c -o sampler_debug_test-sampler_test.obj `if test -f 'src/tests/sampler_test.cc'; then $(CYGPATH_W) 'src/tests/sampler_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/sampler_test.cc'; fi` sampler_test-sampler_test.o: src/tests/sampler_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampler_test_CXXFLAGS) $(CXXFLAGS) -MT sampler_test-sampler_test.o -MD -MP -MF "$(DEPDIR)/sampler_test-sampler_test.Tpo" -c -o sampler_test-sampler_test.o `test -f 'src/tests/sampler_test.cc' || echo '$(srcdir)/'`src/tests/sampler_test.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/sampler_test-sampler_test.Tpo" "$(DEPDIR)/sampler_test-sampler_test.Po"; else rm -f "$(DEPDIR)/sampler_test-sampler_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/sampler_test.cc' object='sampler_test-sampler_test.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampler_test_CXXFLAGS) $(CXXFLAGS) -c -o sampler_test-sampler_test.o `test -f 'src/tests/sampler_test.cc' || echo '$(srcdir)/'`src/tests/sampler_test.cc sampler_test-sampler_test.obj: src/tests/sampler_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampler_test_CXXFLAGS) $(CXXFLAGS) -MT sampler_test-sampler_test.obj -MD -MP -MF "$(DEPDIR)/sampler_test-sampler_test.Tpo" -c -o sampler_test-sampler_test.obj `if test -f 'src/tests/sampler_test.cc'; then $(CYGPATH_W) 'src/tests/sampler_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/sampler_test.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/sampler_test-sampler_test.Tpo" "$(DEPDIR)/sampler_test-sampler_test.Po"; else rm -f "$(DEPDIR)/sampler_test-sampler_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/sampler_test.cc' object='sampler_test-sampler_test.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampler_test_CXXFLAGS) $(CXXFLAGS) -c -o sampler_test-sampler_test.obj `if test -f 'src/tests/sampler_test.cc'; then $(CYGPATH_W) 'src/tests/sampler_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/sampler_test.cc'; fi` sampling_debug_test-sampling_test.o: src/tests/sampling_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampling_debug_test_CXXFLAGS) $(CXXFLAGS) -MT sampling_debug_test-sampling_test.o -MD -MP -MF "$(DEPDIR)/sampling_debug_test-sampling_test.Tpo" -c -o sampling_debug_test-sampling_test.o `test -f 'src/tests/sampling_test.cc' || echo '$(srcdir)/'`src/tests/sampling_test.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/sampling_debug_test-sampling_test.Tpo" "$(DEPDIR)/sampling_debug_test-sampling_test.Po"; else rm -f "$(DEPDIR)/sampling_debug_test-sampling_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/sampling_test.cc' object='sampling_debug_test-sampling_test.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampling_debug_test_CXXFLAGS) $(CXXFLAGS) -c -o sampling_debug_test-sampling_test.o `test -f 'src/tests/sampling_test.cc' || echo '$(srcdir)/'`src/tests/sampling_test.cc sampling_debug_test-sampling_test.obj: src/tests/sampling_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampling_debug_test_CXXFLAGS) $(CXXFLAGS) -MT sampling_debug_test-sampling_test.obj -MD -MP -MF "$(DEPDIR)/sampling_debug_test-sampling_test.Tpo" -c -o sampling_debug_test-sampling_test.obj `if test -f 'src/tests/sampling_test.cc'; then $(CYGPATH_W) 'src/tests/sampling_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/sampling_test.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/sampling_debug_test-sampling_test.Tpo" "$(DEPDIR)/sampling_debug_test-sampling_test.Po"; else rm -f "$(DEPDIR)/sampling_debug_test-sampling_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/sampling_test.cc' object='sampling_debug_test-sampling_test.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampling_debug_test_CXXFLAGS) $(CXXFLAGS) -c -o sampling_debug_test-sampling_test.obj `if test -f 'src/tests/sampling_test.cc'; then $(CYGPATH_W) 'src/tests/sampling_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/sampling_test.cc'; fi` sampling_test-sampling_test.o: src/tests/sampling_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampling_test_CXXFLAGS) $(CXXFLAGS) -MT sampling_test-sampling_test.o -MD -MP -MF "$(DEPDIR)/sampling_test-sampling_test.Tpo" -c -o sampling_test-sampling_test.o `test -f 'src/tests/sampling_test.cc' || echo '$(srcdir)/'`src/tests/sampling_test.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/sampling_test-sampling_test.Tpo" "$(DEPDIR)/sampling_test-sampling_test.Po"; else rm -f "$(DEPDIR)/sampling_test-sampling_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/sampling_test.cc' object='sampling_test-sampling_test.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampling_test_CXXFLAGS) $(CXXFLAGS) -c -o sampling_test-sampling_test.o `test -f 'src/tests/sampling_test.cc' || echo '$(srcdir)/'`src/tests/sampling_test.cc sampling_test-sampling_test.obj: src/tests/sampling_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampling_test_CXXFLAGS) $(CXXFLAGS) -MT sampling_test-sampling_test.obj -MD -MP -MF "$(DEPDIR)/sampling_test-sampling_test.Tpo" -c -o sampling_test-sampling_test.obj `if test -f 'src/tests/sampling_test.cc'; then $(CYGPATH_W) 'src/tests/sampling_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/sampling_test.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/sampling_test-sampling_test.Tpo" "$(DEPDIR)/sampling_test-sampling_test.Po"; else rm -f "$(DEPDIR)/sampling_test-sampling_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/sampling_test.cc' object='sampling_test-sampling_test.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampling_test_CXXFLAGS) $(CXXFLAGS) -c -o sampling_test-sampling_test.obj `if test -f 'src/tests/sampling_test.cc'; then $(CYGPATH_W) 'src/tests/sampling_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/sampling_test.cc'; fi` stack_trace_table_test-stack_trace_table_test.o: src/tests/stack_trace_table_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stack_trace_table_test_CXXFLAGS) $(CXXFLAGS) -MT stack_trace_table_test-stack_trace_table_test.o -MD -MP -MF "$(DEPDIR)/stack_trace_table_test-stack_trace_table_test.Tpo" -c -o stack_trace_table_test-stack_trace_table_test.o `test -f 'src/tests/stack_trace_table_test.cc' || echo '$(srcdir)/'`src/tests/stack_trace_table_test.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/stack_trace_table_test-stack_trace_table_test.Tpo" "$(DEPDIR)/stack_trace_table_test-stack_trace_table_test.Po"; else rm -f "$(DEPDIR)/stack_trace_table_test-stack_trace_table_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/stack_trace_table_test.cc' object='stack_trace_table_test-stack_trace_table_test.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stack_trace_table_test_CXXFLAGS) $(CXXFLAGS) -c -o stack_trace_table_test-stack_trace_table_test.o `test -f 'src/tests/stack_trace_table_test.cc' || echo '$(srcdir)/'`src/tests/stack_trace_table_test.cc stack_trace_table_test-stack_trace_table_test.obj: src/tests/stack_trace_table_test.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stack_trace_table_test_CXXFLAGS) $(CXXFLAGS) -MT stack_trace_table_test-stack_trace_table_test.obj -MD -MP -MF "$(DEPDIR)/stack_trace_table_test-stack_trace_table_test.Tpo" -c -o stack_trace_table_test-stack_trace_table_test.obj `if test -f 'src/tests/stack_trace_table_test.cc'; then $(CYGPATH_W) 'src/tests/stack_trace_table_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/stack_trace_table_test.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/stack_trace_table_test-stack_trace_table_test.Tpo" "$(DEPDIR)/stack_trace_table_test-stack_trace_table_test.Po"; else rm -f "$(DEPDIR)/stack_trace_table_test-stack_trace_table_test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/stack_trace_table_test.cc' object='stack_trace_table_test-stack_trace_table_test.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stack_trace_table_test_CXXFLAGS) $(CXXFLAGS) -c -o stack_trace_table_test-stack_trace_table_test.obj `if test -f 'src/tests/stack_trace_table_test.cc'; then $(CYGPATH_W) 'src/tests/stack_trace_table_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/stack_trace_table_test.cc'; fi` stacktrace_unittest.o: src/tests/stacktrace_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT stacktrace_unittest.o -MD -MP -MF "$(DEPDIR)/stacktrace_unittest.Tpo" -c -o stacktrace_unittest.o `test -f 'src/tests/stacktrace_unittest.cc' || echo '$(srcdir)/'`src/tests/stacktrace_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/stacktrace_unittest.Tpo" "$(DEPDIR)/stacktrace_unittest.Po"; else rm -f "$(DEPDIR)/stacktrace_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/stacktrace_unittest.cc' object='stacktrace_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o stacktrace_unittest.o `test -f 'src/tests/stacktrace_unittest.cc' || echo '$(srcdir)/'`src/tests/stacktrace_unittest.cc stacktrace_unittest.obj: src/tests/stacktrace_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT stacktrace_unittest.obj -MD -MP -MF "$(DEPDIR)/stacktrace_unittest.Tpo" -c -o stacktrace_unittest.obj `if test -f 'src/tests/stacktrace_unittest.cc'; then $(CYGPATH_W) 'src/tests/stacktrace_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/stacktrace_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/stacktrace_unittest.Tpo" "$(DEPDIR)/stacktrace_unittest.Po"; else rm -f "$(DEPDIR)/stacktrace_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/stacktrace_unittest.cc' object='stacktrace_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o stacktrace_unittest.obj `if test -f 'src/tests/stacktrace_unittest.cc'; then $(CYGPATH_W) 'src/tests/stacktrace_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/stacktrace_unittest.cc'; fi` system_alloc_unittest-system-alloc_unittest.o: src/tests/system-alloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(system_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT system_alloc_unittest-system-alloc_unittest.o -MD -MP -MF "$(DEPDIR)/system_alloc_unittest-system-alloc_unittest.Tpo" -c -o system_alloc_unittest-system-alloc_unittest.o `test -f 'src/tests/system-alloc_unittest.cc' || echo '$(srcdir)/'`src/tests/system-alloc_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/system_alloc_unittest-system-alloc_unittest.Tpo" "$(DEPDIR)/system_alloc_unittest-system-alloc_unittest.Po"; else rm -f "$(DEPDIR)/system_alloc_unittest-system-alloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/system-alloc_unittest.cc' object='system_alloc_unittest-system-alloc_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(system_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o system_alloc_unittest-system-alloc_unittest.o `test -f 'src/tests/system-alloc_unittest.cc' || echo '$(srcdir)/'`src/tests/system-alloc_unittest.cc system_alloc_unittest-system-alloc_unittest.obj: src/tests/system-alloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(system_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT system_alloc_unittest-system-alloc_unittest.obj -MD -MP -MF "$(DEPDIR)/system_alloc_unittest-system-alloc_unittest.Tpo" -c -o system_alloc_unittest-system-alloc_unittest.obj `if test -f 'src/tests/system-alloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/system-alloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/system-alloc_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/system_alloc_unittest-system-alloc_unittest.Tpo" "$(DEPDIR)/system_alloc_unittest-system-alloc_unittest.Po"; else rm -f "$(DEPDIR)/system_alloc_unittest-system-alloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/system-alloc_unittest.cc' object='system_alloc_unittest-system-alloc_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(system_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o system_alloc_unittest-system-alloc_unittest.obj `if test -f 'src/tests/system-alloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/system-alloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/system-alloc_unittest.cc'; fi` tcmalloc_and_profiler_unittest-tcmalloc_unittest.o: src/tests/tcmalloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_and_profiler_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_and_profiler_unittest-tcmalloc_unittest.o -MD -MP -MF "$(DEPDIR)/tcmalloc_and_profiler_unittest-tcmalloc_unittest.Tpo" -c -o tcmalloc_and_profiler_unittest-tcmalloc_unittest.o `test -f 'src/tests/tcmalloc_unittest.cc' || echo '$(srcdir)/'`src/tests/tcmalloc_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_and_profiler_unittest-tcmalloc_unittest.Tpo" "$(DEPDIR)/tcmalloc_and_profiler_unittest-tcmalloc_unittest.Po"; else rm -f "$(DEPDIR)/tcmalloc_and_profiler_unittest-tcmalloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/tcmalloc_unittest.cc' object='tcmalloc_and_profiler_unittest-tcmalloc_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_and_profiler_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_and_profiler_unittest-tcmalloc_unittest.o `test -f 'src/tests/tcmalloc_unittest.cc' || echo '$(srcdir)/'`src/tests/tcmalloc_unittest.cc tcmalloc_and_profiler_unittest-tcmalloc_unittest.obj: src/tests/tcmalloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_and_profiler_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_and_profiler_unittest-tcmalloc_unittest.obj -MD -MP -MF "$(DEPDIR)/tcmalloc_and_profiler_unittest-tcmalloc_unittest.Tpo" -c -o tcmalloc_and_profiler_unittest-tcmalloc_unittest.obj `if test -f 'src/tests/tcmalloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/tcmalloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/tcmalloc_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_and_profiler_unittest-tcmalloc_unittest.Tpo" "$(DEPDIR)/tcmalloc_and_profiler_unittest-tcmalloc_unittest.Po"; else rm -f "$(DEPDIR)/tcmalloc_and_profiler_unittest-tcmalloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/tcmalloc_unittest.cc' object='tcmalloc_and_profiler_unittest-tcmalloc_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_and_profiler_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_and_profiler_unittest-tcmalloc_unittest.obj `if test -f 'src/tests/tcmalloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/tcmalloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/tcmalloc_unittest.cc'; fi` tcmalloc_and_profiler_unittest-testutil.o: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_and_profiler_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_and_profiler_unittest-testutil.o -MD -MP -MF "$(DEPDIR)/tcmalloc_and_profiler_unittest-testutil.Tpo" -c -o tcmalloc_and_profiler_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_and_profiler_unittest-testutil.Tpo" "$(DEPDIR)/tcmalloc_and_profiler_unittest-testutil.Po"; else rm -f "$(DEPDIR)/tcmalloc_and_profiler_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='tcmalloc_and_profiler_unittest-testutil.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_and_profiler_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_and_profiler_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc tcmalloc_and_profiler_unittest-testutil.obj: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_and_profiler_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_and_profiler_unittest-testutil.obj -MD -MP -MF "$(DEPDIR)/tcmalloc_and_profiler_unittest-testutil.Tpo" -c -o tcmalloc_and_profiler_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_and_profiler_unittest-testutil.Tpo" "$(DEPDIR)/tcmalloc_and_profiler_unittest-testutil.Po"; else rm -f "$(DEPDIR)/tcmalloc_and_profiler_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='tcmalloc_and_profiler_unittest-testutil.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_and_profiler_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_and_profiler_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi` tcmalloc_both_unittest-tcmalloc_unittest.o: src/tests/tcmalloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_both_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_both_unittest-tcmalloc_unittest.o -MD -MP -MF "$(DEPDIR)/tcmalloc_both_unittest-tcmalloc_unittest.Tpo" -c -o tcmalloc_both_unittest-tcmalloc_unittest.o `test -f 'src/tests/tcmalloc_unittest.cc' || echo '$(srcdir)/'`src/tests/tcmalloc_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_both_unittest-tcmalloc_unittest.Tpo" "$(DEPDIR)/tcmalloc_both_unittest-tcmalloc_unittest.Po"; else rm -f "$(DEPDIR)/tcmalloc_both_unittest-tcmalloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/tcmalloc_unittest.cc' object='tcmalloc_both_unittest-tcmalloc_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_both_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_both_unittest-tcmalloc_unittest.o `test -f 'src/tests/tcmalloc_unittest.cc' || echo '$(srcdir)/'`src/tests/tcmalloc_unittest.cc tcmalloc_both_unittest-tcmalloc_unittest.obj: src/tests/tcmalloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_both_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_both_unittest-tcmalloc_unittest.obj -MD -MP -MF "$(DEPDIR)/tcmalloc_both_unittest-tcmalloc_unittest.Tpo" -c -o tcmalloc_both_unittest-tcmalloc_unittest.obj `if test -f 'src/tests/tcmalloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/tcmalloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/tcmalloc_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_both_unittest-tcmalloc_unittest.Tpo" "$(DEPDIR)/tcmalloc_both_unittest-tcmalloc_unittest.Po"; else rm -f "$(DEPDIR)/tcmalloc_both_unittest-tcmalloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/tcmalloc_unittest.cc' object='tcmalloc_both_unittest-tcmalloc_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_both_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_both_unittest-tcmalloc_unittest.obj `if test -f 'src/tests/tcmalloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/tcmalloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/tcmalloc_unittest.cc'; fi` tcmalloc_both_unittest-testutil.o: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_both_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_both_unittest-testutil.o -MD -MP -MF "$(DEPDIR)/tcmalloc_both_unittest-testutil.Tpo" -c -o tcmalloc_both_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_both_unittest-testutil.Tpo" "$(DEPDIR)/tcmalloc_both_unittest-testutil.Po"; else rm -f "$(DEPDIR)/tcmalloc_both_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='tcmalloc_both_unittest-testutil.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_both_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_both_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc tcmalloc_both_unittest-testutil.obj: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_both_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_both_unittest-testutil.obj -MD -MP -MF "$(DEPDIR)/tcmalloc_both_unittest-testutil.Tpo" -c -o tcmalloc_both_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_both_unittest-testutil.Tpo" "$(DEPDIR)/tcmalloc_both_unittest-testutil.Po"; else rm -f "$(DEPDIR)/tcmalloc_both_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='tcmalloc_both_unittest-testutil.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_both_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_both_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi` tcmalloc_debug_unittest-tcmalloc_unittest.o: src/tests/tcmalloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_debug_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_debug_unittest-tcmalloc_unittest.o -MD -MP -MF "$(DEPDIR)/tcmalloc_debug_unittest-tcmalloc_unittest.Tpo" -c -o tcmalloc_debug_unittest-tcmalloc_unittest.o `test -f 'src/tests/tcmalloc_unittest.cc' || echo '$(srcdir)/'`src/tests/tcmalloc_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_debug_unittest-tcmalloc_unittest.Tpo" "$(DEPDIR)/tcmalloc_debug_unittest-tcmalloc_unittest.Po"; else rm -f "$(DEPDIR)/tcmalloc_debug_unittest-tcmalloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/tcmalloc_unittest.cc' object='tcmalloc_debug_unittest-tcmalloc_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_debug_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_debug_unittest-tcmalloc_unittest.o `test -f 'src/tests/tcmalloc_unittest.cc' || echo '$(srcdir)/'`src/tests/tcmalloc_unittest.cc tcmalloc_debug_unittest-tcmalloc_unittest.obj: src/tests/tcmalloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_debug_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_debug_unittest-tcmalloc_unittest.obj -MD -MP -MF "$(DEPDIR)/tcmalloc_debug_unittest-tcmalloc_unittest.Tpo" -c -o tcmalloc_debug_unittest-tcmalloc_unittest.obj `if test -f 'src/tests/tcmalloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/tcmalloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/tcmalloc_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_debug_unittest-tcmalloc_unittest.Tpo" "$(DEPDIR)/tcmalloc_debug_unittest-tcmalloc_unittest.Po"; else rm -f "$(DEPDIR)/tcmalloc_debug_unittest-tcmalloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/tcmalloc_unittest.cc' object='tcmalloc_debug_unittest-tcmalloc_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_debug_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_debug_unittest-tcmalloc_unittest.obj `if test -f 'src/tests/tcmalloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/tcmalloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/tcmalloc_unittest.cc'; fi` tcmalloc_debug_unittest-testutil.o: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_debug_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_debug_unittest-testutil.o -MD -MP -MF "$(DEPDIR)/tcmalloc_debug_unittest-testutil.Tpo" -c -o tcmalloc_debug_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_debug_unittest-testutil.Tpo" "$(DEPDIR)/tcmalloc_debug_unittest-testutil.Po"; else rm -f "$(DEPDIR)/tcmalloc_debug_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='tcmalloc_debug_unittest-testutil.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_debug_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_debug_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc tcmalloc_debug_unittest-testutil.obj: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_debug_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_debug_unittest-testutil.obj -MD -MP -MF "$(DEPDIR)/tcmalloc_debug_unittest-testutil.Tpo" -c -o tcmalloc_debug_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_debug_unittest-testutil.Tpo" "$(DEPDIR)/tcmalloc_debug_unittest-testutil.Po"; else rm -f "$(DEPDIR)/tcmalloc_debug_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='tcmalloc_debug_unittest-testutil.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_debug_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_debug_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi` tcmalloc_large_unittest-tcmalloc_large_unittest.o: src/tests/tcmalloc_large_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_large_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_large_unittest-tcmalloc_large_unittest.o -MD -MP -MF "$(DEPDIR)/tcmalloc_large_unittest-tcmalloc_large_unittest.Tpo" -c -o tcmalloc_large_unittest-tcmalloc_large_unittest.o `test -f 'src/tests/tcmalloc_large_unittest.cc' || echo '$(srcdir)/'`src/tests/tcmalloc_large_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_large_unittest-tcmalloc_large_unittest.Tpo" "$(DEPDIR)/tcmalloc_large_unittest-tcmalloc_large_unittest.Po"; else rm -f "$(DEPDIR)/tcmalloc_large_unittest-tcmalloc_large_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/tcmalloc_large_unittest.cc' object='tcmalloc_large_unittest-tcmalloc_large_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_large_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_large_unittest-tcmalloc_large_unittest.o `test -f 'src/tests/tcmalloc_large_unittest.cc' || echo '$(srcdir)/'`src/tests/tcmalloc_large_unittest.cc tcmalloc_large_unittest-tcmalloc_large_unittest.obj: src/tests/tcmalloc_large_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_large_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_large_unittest-tcmalloc_large_unittest.obj -MD -MP -MF "$(DEPDIR)/tcmalloc_large_unittest-tcmalloc_large_unittest.Tpo" -c -o tcmalloc_large_unittest-tcmalloc_large_unittest.obj `if test -f 'src/tests/tcmalloc_large_unittest.cc'; then $(CYGPATH_W) 'src/tests/tcmalloc_large_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/tcmalloc_large_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_large_unittest-tcmalloc_large_unittest.Tpo" "$(DEPDIR)/tcmalloc_large_unittest-tcmalloc_large_unittest.Po"; else rm -f "$(DEPDIR)/tcmalloc_large_unittest-tcmalloc_large_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/tcmalloc_large_unittest.cc' object='tcmalloc_large_unittest-tcmalloc_large_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_large_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_large_unittest-tcmalloc_large_unittest.obj `if test -f 'src/tests/tcmalloc_large_unittest.cc'; then $(CYGPATH_W) 'src/tests/tcmalloc_large_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/tcmalloc_large_unittest.cc'; fi` tcmalloc_minimal_debug_unittest-tcmalloc_unittest.o: src/tests/tcmalloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_debug_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_minimal_debug_unittest-tcmalloc_unittest.o -MD -MP -MF "$(DEPDIR)/tcmalloc_minimal_debug_unittest-tcmalloc_unittest.Tpo" -c -o tcmalloc_minimal_debug_unittest-tcmalloc_unittest.o `test -f 'src/tests/tcmalloc_unittest.cc' || echo '$(srcdir)/'`src/tests/tcmalloc_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_minimal_debug_unittest-tcmalloc_unittest.Tpo" "$(DEPDIR)/tcmalloc_minimal_debug_unittest-tcmalloc_unittest.Po"; else rm -f "$(DEPDIR)/tcmalloc_minimal_debug_unittest-tcmalloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/tcmalloc_unittest.cc' object='tcmalloc_minimal_debug_unittest-tcmalloc_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_debug_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_minimal_debug_unittest-tcmalloc_unittest.o `test -f 'src/tests/tcmalloc_unittest.cc' || echo '$(srcdir)/'`src/tests/tcmalloc_unittest.cc tcmalloc_minimal_debug_unittest-tcmalloc_unittest.obj: src/tests/tcmalloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_debug_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_minimal_debug_unittest-tcmalloc_unittest.obj -MD -MP -MF "$(DEPDIR)/tcmalloc_minimal_debug_unittest-tcmalloc_unittest.Tpo" -c -o tcmalloc_minimal_debug_unittest-tcmalloc_unittest.obj `if test -f 'src/tests/tcmalloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/tcmalloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/tcmalloc_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_minimal_debug_unittest-tcmalloc_unittest.Tpo" "$(DEPDIR)/tcmalloc_minimal_debug_unittest-tcmalloc_unittest.Po"; else rm -f "$(DEPDIR)/tcmalloc_minimal_debug_unittest-tcmalloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/tcmalloc_unittest.cc' object='tcmalloc_minimal_debug_unittest-tcmalloc_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_debug_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_minimal_debug_unittest-tcmalloc_unittest.obj `if test -f 'src/tests/tcmalloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/tcmalloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/tcmalloc_unittest.cc'; fi` tcmalloc_minimal_debug_unittest-testutil.o: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_debug_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_minimal_debug_unittest-testutil.o -MD -MP -MF "$(DEPDIR)/tcmalloc_minimal_debug_unittest-testutil.Tpo" -c -o tcmalloc_minimal_debug_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_minimal_debug_unittest-testutil.Tpo" "$(DEPDIR)/tcmalloc_minimal_debug_unittest-testutil.Po"; else rm -f "$(DEPDIR)/tcmalloc_minimal_debug_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='tcmalloc_minimal_debug_unittest-testutil.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_debug_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_minimal_debug_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc tcmalloc_minimal_debug_unittest-testutil.obj: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_debug_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_minimal_debug_unittest-testutil.obj -MD -MP -MF "$(DEPDIR)/tcmalloc_minimal_debug_unittest-testutil.Tpo" -c -o tcmalloc_minimal_debug_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_minimal_debug_unittest-testutil.Tpo" "$(DEPDIR)/tcmalloc_minimal_debug_unittest-testutil.Po"; else rm -f "$(DEPDIR)/tcmalloc_minimal_debug_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='tcmalloc_minimal_debug_unittest-testutil.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_debug_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_minimal_debug_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi` tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.o: src/tests/tcmalloc_large_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_large_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.o -MD -MP -MF "$(DEPDIR)/tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.Tpo" -c -o tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.o `test -f 'src/tests/tcmalloc_large_unittest.cc' || echo '$(srcdir)/'`src/tests/tcmalloc_large_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.Tpo" "$(DEPDIR)/tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.Po"; else rm -f "$(DEPDIR)/tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/tcmalloc_large_unittest.cc' object='tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_large_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.o `test -f 'src/tests/tcmalloc_large_unittest.cc' || echo '$(srcdir)/'`src/tests/tcmalloc_large_unittest.cc tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.obj: src/tests/tcmalloc_large_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_large_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.obj -MD -MP -MF "$(DEPDIR)/tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.Tpo" -c -o tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.obj `if test -f 'src/tests/tcmalloc_large_unittest.cc'; then $(CYGPATH_W) 'src/tests/tcmalloc_large_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/tcmalloc_large_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.Tpo" "$(DEPDIR)/tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.Po"; else rm -f "$(DEPDIR)/tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/tcmalloc_large_unittest.cc' object='tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_large_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.obj `if test -f 'src/tests/tcmalloc_large_unittest.cc'; then $(CYGPATH_W) 'src/tests/tcmalloc_large_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/tcmalloc_large_unittest.cc'; fi` tcmalloc_minimal_unittest-tcmalloc_unittest.o: src/tests/tcmalloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_minimal_unittest-tcmalloc_unittest.o -MD -MP -MF "$(DEPDIR)/tcmalloc_minimal_unittest-tcmalloc_unittest.Tpo" -c -o tcmalloc_minimal_unittest-tcmalloc_unittest.o `test -f 'src/tests/tcmalloc_unittest.cc' || echo '$(srcdir)/'`src/tests/tcmalloc_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_minimal_unittest-tcmalloc_unittest.Tpo" "$(DEPDIR)/tcmalloc_minimal_unittest-tcmalloc_unittest.Po"; else rm -f "$(DEPDIR)/tcmalloc_minimal_unittest-tcmalloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/tcmalloc_unittest.cc' object='tcmalloc_minimal_unittest-tcmalloc_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_minimal_unittest-tcmalloc_unittest.o `test -f 'src/tests/tcmalloc_unittest.cc' || echo '$(srcdir)/'`src/tests/tcmalloc_unittest.cc tcmalloc_minimal_unittest-tcmalloc_unittest.obj: src/tests/tcmalloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_minimal_unittest-tcmalloc_unittest.obj -MD -MP -MF "$(DEPDIR)/tcmalloc_minimal_unittest-tcmalloc_unittest.Tpo" -c -o tcmalloc_minimal_unittest-tcmalloc_unittest.obj `if test -f 'src/tests/tcmalloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/tcmalloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/tcmalloc_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_minimal_unittest-tcmalloc_unittest.Tpo" "$(DEPDIR)/tcmalloc_minimal_unittest-tcmalloc_unittest.Po"; else rm -f "$(DEPDIR)/tcmalloc_minimal_unittest-tcmalloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/tcmalloc_unittest.cc' object='tcmalloc_minimal_unittest-tcmalloc_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_minimal_unittest-tcmalloc_unittest.obj `if test -f 'src/tests/tcmalloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/tcmalloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/tcmalloc_unittest.cc'; fi` tcmalloc_minimal_unittest-testutil.o: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_minimal_unittest-testutil.o -MD -MP -MF "$(DEPDIR)/tcmalloc_minimal_unittest-testutil.Tpo" -c -o tcmalloc_minimal_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_minimal_unittest-testutil.Tpo" "$(DEPDIR)/tcmalloc_minimal_unittest-testutil.Po"; else rm -f "$(DEPDIR)/tcmalloc_minimal_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='tcmalloc_minimal_unittest-testutil.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_minimal_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc tcmalloc_minimal_unittest-testutil.obj: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_minimal_unittest-testutil.obj -MD -MP -MF "$(DEPDIR)/tcmalloc_minimal_unittest-testutil.Tpo" -c -o tcmalloc_minimal_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_minimal_unittest-testutil.Tpo" "$(DEPDIR)/tcmalloc_minimal_unittest-testutil.Po"; else rm -f "$(DEPDIR)/tcmalloc_minimal_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='tcmalloc_minimal_unittest-testutil.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_minimal_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_minimal_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi` tcmalloc_unittest-tcmalloc_unittest.o: src/tests/tcmalloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_unittest-tcmalloc_unittest.o -MD -MP -MF "$(DEPDIR)/tcmalloc_unittest-tcmalloc_unittest.Tpo" -c -o tcmalloc_unittest-tcmalloc_unittest.o `test -f 'src/tests/tcmalloc_unittest.cc' || echo '$(srcdir)/'`src/tests/tcmalloc_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_unittest-tcmalloc_unittest.Tpo" "$(DEPDIR)/tcmalloc_unittest-tcmalloc_unittest.Po"; else rm -f "$(DEPDIR)/tcmalloc_unittest-tcmalloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/tcmalloc_unittest.cc' object='tcmalloc_unittest-tcmalloc_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_unittest-tcmalloc_unittest.o `test -f 'src/tests/tcmalloc_unittest.cc' || echo '$(srcdir)/'`src/tests/tcmalloc_unittest.cc tcmalloc_unittest-tcmalloc_unittest.obj: src/tests/tcmalloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_unittest-tcmalloc_unittest.obj -MD -MP -MF "$(DEPDIR)/tcmalloc_unittest-tcmalloc_unittest.Tpo" -c -o tcmalloc_unittest-tcmalloc_unittest.obj `if test -f 'src/tests/tcmalloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/tcmalloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/tcmalloc_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_unittest-tcmalloc_unittest.Tpo" "$(DEPDIR)/tcmalloc_unittest-tcmalloc_unittest.Po"; else rm -f "$(DEPDIR)/tcmalloc_unittest-tcmalloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/tcmalloc_unittest.cc' object='tcmalloc_unittest-tcmalloc_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_unittest-tcmalloc_unittest.obj `if test -f 'src/tests/tcmalloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/tcmalloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/tcmalloc_unittest.cc'; fi` tcmalloc_unittest-testutil.o: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_unittest-testutil.o -MD -MP -MF "$(DEPDIR)/tcmalloc_unittest-testutil.Tpo" -c -o tcmalloc_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_unittest-testutil.Tpo" "$(DEPDIR)/tcmalloc_unittest-testutil.Po"; else rm -f "$(DEPDIR)/tcmalloc_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='tcmalloc_unittest-testutil.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc tcmalloc_unittest-testutil.obj: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT tcmalloc_unittest-testutil.obj -MD -MP -MF "$(DEPDIR)/tcmalloc_unittest-testutil.Tpo" -c -o tcmalloc_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/tcmalloc_unittest-testutil.Tpo" "$(DEPDIR)/tcmalloc_unittest-testutil.Po"; else rm -f "$(DEPDIR)/tcmalloc_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='tcmalloc_unittest-testutil.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tcmalloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o tcmalloc_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi` thread_dealloc_unittest-thread_dealloc_unittest.o: src/tests/thread_dealloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thread_dealloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT thread_dealloc_unittest-thread_dealloc_unittest.o -MD -MP -MF "$(DEPDIR)/thread_dealloc_unittest-thread_dealloc_unittest.Tpo" -c -o thread_dealloc_unittest-thread_dealloc_unittest.o `test -f 'src/tests/thread_dealloc_unittest.cc' || echo '$(srcdir)/'`src/tests/thread_dealloc_unittest.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/thread_dealloc_unittest-thread_dealloc_unittest.Tpo" "$(DEPDIR)/thread_dealloc_unittest-thread_dealloc_unittest.Po"; else rm -f "$(DEPDIR)/thread_dealloc_unittest-thread_dealloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/thread_dealloc_unittest.cc' object='thread_dealloc_unittest-thread_dealloc_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thread_dealloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o thread_dealloc_unittest-thread_dealloc_unittest.o `test -f 'src/tests/thread_dealloc_unittest.cc' || echo '$(srcdir)/'`src/tests/thread_dealloc_unittest.cc thread_dealloc_unittest-thread_dealloc_unittest.obj: src/tests/thread_dealloc_unittest.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thread_dealloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT thread_dealloc_unittest-thread_dealloc_unittest.obj -MD -MP -MF "$(DEPDIR)/thread_dealloc_unittest-thread_dealloc_unittest.Tpo" -c -o thread_dealloc_unittest-thread_dealloc_unittest.obj `if test -f 'src/tests/thread_dealloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/thread_dealloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/thread_dealloc_unittest.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/thread_dealloc_unittest-thread_dealloc_unittest.Tpo" "$(DEPDIR)/thread_dealloc_unittest-thread_dealloc_unittest.Po"; else rm -f "$(DEPDIR)/thread_dealloc_unittest-thread_dealloc_unittest.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/thread_dealloc_unittest.cc' object='thread_dealloc_unittest-thread_dealloc_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thread_dealloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o thread_dealloc_unittest-thread_dealloc_unittest.obj `if test -f 'src/tests/thread_dealloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/thread_dealloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/thread_dealloc_unittest.cc'; fi` thread_dealloc_unittest-testutil.o: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thread_dealloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT thread_dealloc_unittest-testutil.o -MD -MP -MF "$(DEPDIR)/thread_dealloc_unittest-testutil.Tpo" -c -o thread_dealloc_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/thread_dealloc_unittest-testutil.Tpo" "$(DEPDIR)/thread_dealloc_unittest-testutil.Po"; else rm -f "$(DEPDIR)/thread_dealloc_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='thread_dealloc_unittest-testutil.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thread_dealloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o thread_dealloc_unittest-testutil.o `test -f 'src/tests/testutil.cc' || echo '$(srcdir)/'`src/tests/testutil.cc thread_dealloc_unittest-testutil.obj: src/tests/testutil.cc @am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thread_dealloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT thread_dealloc_unittest-testutil.obj -MD -MP -MF "$(DEPDIR)/thread_dealloc_unittest-testutil.Tpo" -c -o thread_dealloc_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/thread_dealloc_unittest-testutil.Tpo" "$(DEPDIR)/thread_dealloc_unittest-testutil.Po"; else rm -f "$(DEPDIR)/thread_dealloc_unittest-testutil.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/testutil.cc' object='thread_dealloc_unittest-testutil.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(thread_dealloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o thread_dealloc_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: install-man1: $(man1_MANS) $(man_MANS) @$(NORMAL_INSTALL) test -z "$(man1dir)" || $(mkdir_p) "$(DESTDIR)$(man1dir)" @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.1*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ else file=$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 1*) ;; \ *) ext='1' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \ done uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.1*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 1*) ;; \ *) ext='1' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \ rm -f "$(DESTDIR)$(man1dir)/$$inst"; \ done install-dist_docDATA: $(dist_doc_DATA) @$(NORMAL_INSTALL) test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" @list='$(dist_doc_DATA)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ done uninstall-dist_docDATA: @$(NORMAL_UNINSTALL) @list='$(dist_doc_DATA)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ rm -f "$(DESTDIR)$(docdir)/$$f"; \ done install-pkgconfigDATA: $(pkgconfig_DATA) @$(NORMAL_INSTALL) test -z "$(pkgconfigdir)" || $(mkdir_p) "$(DESTDIR)$(pkgconfigdir)" @list='$(pkgconfig_DATA)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(pkgconfigDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgconfigdir)/$$f'"; \ $(pkgconfigDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgconfigdir)/$$f"; \ done uninstall-pkgconfigDATA: @$(NORMAL_UNINSTALL) @list='$(pkgconfig_DATA)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(pkgconfigdir)/$$f'"; \ rm -f "$(DESTDIR)$(pkgconfigdir)/$$f"; \ done install-googleincludeHEADERS: $(googleinclude_HEADERS) @$(NORMAL_INSTALL) test -z "$(googleincludedir)" || $(mkdir_p) "$(DESTDIR)$(googleincludedir)" @list='$(googleinclude_HEADERS)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(googleincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(googleincludedir)/$$f'"; \ $(googleincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(googleincludedir)/$$f"; \ done uninstall-googleincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(googleinclude_HEADERS)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(googleincludedir)/$$f'"; \ rm -f "$(DESTDIR)$(googleincludedir)/$$f"; \ done install-nodist_googleincludeHEADERS: $(nodist_googleinclude_HEADERS) @$(NORMAL_INSTALL) test -z "$(googleincludedir)" || $(mkdir_p) "$(DESTDIR)$(googleincludedir)" @list='$(nodist_googleinclude_HEADERS)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(nodist_googleincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(googleincludedir)/$$f'"; \ $(nodist_googleincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(googleincludedir)/$$f"; \ done uninstall-nodist_googleincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(nodist_googleinclude_HEADERS)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(googleincludedir)/$$f'"; \ rm -f "$(DESTDIR)$(googleincludedir)/$$f"; \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list='$(TESTS)'; \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *" $$tst "*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ echo "XPASS: $$tst"; \ ;; \ *) \ echo "PASS: $$tst"; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *" $$tst "*) \ xfail=`expr $$xfail + 1`; \ echo "XFAIL: $$tst"; \ ;; \ *) \ failed=`expr $$failed + 1`; \ echo "FAIL: $$tst"; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ echo "SKIP: $$tst"; \ fi; \ done; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="All $$all tests passed"; \ else \ banner="All $$all tests behaved as expected ($$xfail expected failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all tests failed"; \ else \ banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ skipped="($$skip tests were not run)"; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ echo "$$dashes"; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) $(am__remove_distdir) mkdir $(distdir) $(mkdir_p) $(distdir)/$(top_srcdir) $(distdir)/doc $(distdir)/m4 $(distdir)/packages $(distdir)/packages/rpm $(distdir)/src $(distdir)/src/google $(distdir)/src/solaris $(distdir)/src/tests $(distdir)/src/windows $(distdir)/src/windows/google $(distdir)/vsprojects/addr2line-pdb $(distdir)/vsprojects/addressmap_unittest $(distdir)/vsprojects/frag_unittest $(distdir)/vsprojects/libtcmalloc_minimal $(distdir)/vsprojects/low_level_alloc_unittest $(distdir)/vsprojects/malloc_extension_test $(distdir)/vsprojects/markidle_unittest $(distdir)/vsprojects/nm-pdb $(distdir)/vsprojects/packed-cache_test $(distdir)/vsprojects/page_heap_test $(distdir)/vsprojects/pagemap_unittest $(distdir)/vsprojects/realloc_unittest $(distdir)/vsprojects/sampler_test $(distdir)/vsprojects/stack_trace_table_test $(distdir)/vsprojects/tcmalloc_minimal_large $(distdir)/vsprojects/tcmalloc_minimal_unittest $(distdir)/vsprojects/thread_dealloc_unittest $(distdir)/vsprojects/tmu-static @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-hook -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r $(distdir) dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 $(am__remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__remove_distdir) dist dist-all: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir); chmod a+w $(distdir) mkdir $(distdir)/_build mkdir $(distdir)/_inst chmod a-w $(distdir) dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && cd $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck $(am__remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}' distuninstallcheck: @cd $(distuninstallcheck_dir) \ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_SCRIPTS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(SCRIPTS) $(MANS) $(DATA) \ $(HEADERS) all-local install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(googleincludedir)" "$(DESTDIR)$(googleincludedir)"; do \ test -z "$$dir" || $(mkdir_p) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool clean-noinstLTLIBRARIES clean-noinstPROGRAMS \ mostlyclean-am distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-dist_docDATA install-googleincludeHEADERS \ install-man install-nodist_googleincludeHEADERS \ install-pkgconfigDATA install-exec-am: install-binPROGRAMS install-binSCRIPTS \ install-exec-local install-libLTLIBRARIES install-info: install-info-am install-man: install-man1 installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \ uninstall-dist_docDATA uninstall-googleincludeHEADERS \ uninstall-info-am uninstall-libLTLIBRARIES uninstall-man \ uninstall-nodist_googleincludeHEADERS uninstall-pkgconfigDATA uninstall-man: uninstall-man1 .PHONY: CTAGS GTAGS all all-am all-local am--refresh check check-TESTS \ check-am clean clean-binPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-noinstLTLIBRARIES \ clean-noinstPROGRAMS ctags dist dist-all dist-bzip2 dist-gzip \ dist-hook dist-shar dist-tarZ dist-zip distcheck distclean \ distclean-compile distclean-generic distclean-hdr \ distclean-libtool distclean-tags distcleancheck distdir \ distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-binSCRIPTS \ install-data install-data-am install-dist_docDATA install-exec \ install-exec-am install-exec-local \ install-googleincludeHEADERS install-info install-info-am \ install-libLTLIBRARIES install-man install-man1 \ install-nodist_googleincludeHEADERS install-pkgconfigDATA \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-binSCRIPTS \ uninstall-dist_docDATA uninstall-googleincludeHEADERS \ uninstall-info-am uninstall-libLTLIBRARIES uninstall-man \ uninstall-man1 uninstall-nodist_googleincludeHEADERS \ uninstall-pkgconfigDATA @ENABLE_FRAME_POINTERS_FALSE@@X86_64_AND_NO_FP_BY_DEFAULT_TRUE@ # TODO(csilvers): check if -fomit-frame-pointer might be in $(CXXFLAGS), @ENABLE_FRAME_POINTERS_FALSE@@X86_64_AND_NO_FP_BY_DEFAULT_TRUE@ # before setting this. @WITH_STACK_TRACE_TRUE@pprof_unittest: $(top_srcdir)/src/pprof @WITH_STACK_TRACE_TRUE@ $(top_srcdir)/src/pprof -test # This script preloads libtcmalloc, and calls two other binaries as well # TODO(csilvers): replace by 'if ! cmp $^ $@ >/dev/null 2>&; then ...; fi' @ENABLE_STATIC_FALSE@@MINGW_FALSE@maybe_threads_unittest.sh$(EXEEXT): $(top_srcdir)/$(maybe_threads_unittest_sh_SOURCES) \ @ENABLE_STATIC_FALSE@@MINGW_FALSE@ $(LIBTCMALLOC_MINIMAL) \ @ENABLE_STATIC_FALSE@@MINGW_FALSE@ low_level_alloc_unittest @ENABLE_STATIC_FALSE@@MINGW_FALSE@ rm -f $@ @ENABLE_STATIC_FALSE@@MINGW_FALSE@ cp -p $(top_srcdir)/$(maybe_threads_unittest_sh_SOURCES) $@ @WITH_DEBUGALLOC_TRUE@debugallocation_test.sh$(EXEEXT): $(top_srcdir)/$(debugallocation_test_sh_SOURCES) \ @WITH_DEBUGALLOC_TRUE@ debugallocation_test @WITH_DEBUGALLOC_TRUE@ rm -f $@ @WITH_DEBUGALLOC_TRUE@ cp -p $(top_srcdir)/$(debugallocation_test_sh_SOURCES) $@ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_test.sh$(EXEEXT): $(top_srcdir)/$(sampling_test_sh_SOURCES) \ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampling_test @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ rm -f $@ @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ cp -p $(top_srcdir)/$(sampling_test_sh_SOURCES) $@ @WITH_HEAP_PROFILER_TRUE@heap-profiler_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) \ @WITH_HEAP_PROFILER_TRUE@ heap-profiler_unittest @WITH_HEAP_PROFILER_TRUE@ rm -f $@ @WITH_HEAP_PROFILER_TRUE@ cp -p $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) $@ @WITH_HEAP_CHECKER_TRUE@heap-checker_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_checker_unittest_sh_SOURCES) \ @WITH_HEAP_CHECKER_TRUE@ heap-checker_unittest @WITH_HEAP_CHECKER_TRUE@ rm -f $@ @WITH_HEAP_CHECKER_TRUE@ cp -p $(top_srcdir)/$(heap_checker_unittest_sh_SOURCES) $@ @WITH_HEAP_CHECKER_TRUE@heap-checker-death_unittest.sh$(EXEEXT): $(heap_checker_death_unittest_sh_SOURCES) \ @WITH_HEAP_CHECKER_TRUE@ heap-checker_unittest @WITH_HEAP_CHECKER_TRUE@ rm -f $@ @WITH_HEAP_CHECKER_TRUE@ cp -p $(top_srcdir)/$(heap_checker_death_unittest_sh_SOURCES) $@ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_debug_test.sh$(EXEEXT): $(top_srcdir)/$(sampling_test_sh_SOURCES) \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampling_debug_test @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ rm -f $@ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ cp -p $(top_srcdir)/$(sampling_test_sh_SOURCES) $@ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@heap-profiler_debug_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@ heap-profiler_debug_unittest @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@ rm -f $@ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@ cp -p $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) $@ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@heap-checker_debug_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_checker_unittest_sh_SOURCES) \ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@ heap-checker_debug_unittest @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@ rm -f $@ @WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@ cp -p $(top_srcdir)/$(heap_checker_unittest_sh_SOURCES) $@ @WITH_CPU_PROFILER_TRUE@profiler_unittest.sh$(EXEEXT): $(top_srcdir)/$(profiler_unittest_sh_SOURCES) \ @WITH_CPU_PROFILER_TRUE@ profiler1_unittest profiler2_unittest \ @WITH_CPU_PROFILER_TRUE@ profiler3_unittest profiler4_unittest @WITH_CPU_PROFILER_TRUE@ rm -f $@ @WITH_CPU_PROFILER_TRUE@ cp -p $(top_srcdir)/$(profiler_unittest_sh_SOURCES) $@ # Do the weakening on some exported libtcmalloc symbols. install-exec-local: all-local all-local: $(LIBS_TO_WEAKEN) for la in $(LIBS_TO_WEAKEN); do lib=".libs/`basename $$la .la`.a"; [ ! -f "$$lib" ] || $(WEAKEN) "$$lib"; done rpm: dist-gzip packages/rpm.sh packages/rpm/rpm.spec @cd packages && ./rpm.sh ${PACKAGE} ${VERSION} deb: dist-gzip packages/deb.sh packages/deb/* @cd packages && ./deb.sh ${PACKAGE} ${VERSION} # I get the description and URL lines from the rpm spec. I use sed to # try to rewrite exec_prefix, libdir, and includedir in terms of # prefix, if possible. libtcmalloc.pc: Makefile packages/rpm/rpm.spec echo 'prefix=$(prefix)' > "$@".tmp echo 'exec_prefix='`echo '$(exec_prefix)' | sed 's@^$(prefix)@$${prefix}@'` >> "$@".tmp echo 'libdir='`echo '$(libdir)' | sed 's@^$(exec_prefix)@$${exec_prefix}@'` >> "$@".tmp echo 'includedir='`echo '$(includedir)' | sed 's@^$(prefix)@$${prefix}@'` >> "$@".tmp echo '' >> "$@".tmp echo 'Name: $(PACKAGE)' >> "$@".tmp echo 'Version: $(VERSION)' >> "$@".tmp -grep '^Summary:' packages/rpm/rpm.spec | sed s/^Summary:/Description:/ | head -n1 >> "$@".tmp -grep '^URL: ' packages/rpm/rpm.spec >> "$@".tmp echo 'Requires:' >> "$@".tmp echo 'Libs: -L$${libdir} -ltcmalloc' >> "$@".tmp echo 'Libs.private: $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)' >> "$@".tmp echo 'Cflags: -I$${includedir}' >> "$@".tmp mv -f "$@".tmp "$@" # The other versions are mostly the same. libtcmalloc_minimal.pc: libtcmalloc.pc cat libtcmalloc.pc | sed s/-ltcmalloc/-ltcmalloc_minimal/ > "$@" libtcmalloc_debug.pc: libtcmalloc.pc cat libtcmalloc.pc | sed s/-ltcmalloc/-ltcmalloc_debug/ > "$@" libtcmalloc_minimal_debug.pc: libtcmalloc.pc cat libtcmalloc.pc | sed s/-ltcmalloc/-ltcmalloc_minimal_debug/ > "$@" libprofiler.pc: libtcmalloc.pc cat libtcmalloc.pc | sed s/-ltcmalloc/-lprofiler/ > "$@" libtool: $(LIBTOOL_DEPS) $(SHELL) ./config.status --recheck # Windows wants write permission to .vcproj files and maybe even sln files. dist-hook: test -e "$(distdir)/vsprojects" \ && chmod -R u+w $(distdir)/*.sln $(distdir)/vsprojects/ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: ================================================ FILE: distro/google-perftools-1.7/NEWS ================================================ == 04 February 2011 == I've just released perftools 1.7 I apologize for the delay since the last release; so many great new patches and bugfixes kept coming in (and are still coming in; I also apologize to those folks who have to slip until the next release). I picked this arbitrary time to make a cut. Among the many new features in this release is a multi-megabyte reduction in the amount of tcmalloc overhead uder x86_64, improved performance in the case of contention, and many many bugfixes, especially architecture-specific bugfixes. See the [http://google-perftools.googlecode.com/svn/tags/perftools-1.7/ChangeLog ChangeLog] for full details. One architecture-specific change of note is added comments in the [http://google-perftools.googlecode.com/svn/tags/perftools-1.7/README README] for using tcmalloc under OS X. I'm trying to get my head around the exact behavior of the OS X linker, and hope to have more improvements for the next release, but I hope these notes help folks who have been having trouble with tcmalloc on OS X. *Windows users*: I've heard reports that some unittests fail on Windows when compiled with MSVC 10 in Release mode. All tests pass in Debug mode. I've not heard of any problems with earlier versions of MSVC. I don't know if this is a problem with the runtime patching (so the static patching discussed in README_windows.txt will still work), a problem with perftools more generally, or a bug in MSVC 10. Anyone with windows expertise that can debug this, I'd be glad to hear from! === 5 August 2010 === I've just released perftools 1.6 This version also has a large number of minor changes, including support for `malloc_usable_size()` as a glibc-compatible alias to `malloc_size()`, the addition of SVG-based output to `pprof`, and experimental support for tcmalloc large pages, which may speed up tcmalloc at the cost of greater memory use. To use tcmalloc large pages, see the [http://google-perftools.googlecode.com/svn/tags/perftools-1.6/INSTALL INSTALL file]; for all changes, see the [http://google-perftools.googlecode.com/svn/tags/perftools-1.6/ChangeLog ChangeLog]. OS X NOTE: improvements in the profiler unittest have turned up an OS X issue: in multithreaded programs, it seems that OS X often delivers the profiling signal (from sigitimer()) to the main thread, even when it's sleeping, rather than spawned threads that are doing actual work. If anyone knows details of how OS X handles SIGPROF events (from setitimer) in threaded programs, and has insight into this problem, please send mail to google-perftools@googlegroups.com. To see if you're affected by this, look for profiling time that pprof attributes to `___semwait_signal`. This is work being done in other threads, that is being attributed to sleeping-time in the main thread. === 20 January 2010 === I've just released perftools 1.5 This version has a slew of changes, leading to somewhat faster performance and improvements in portability. It adds features like `ITIMER_REAL` support to the cpu profiler, and `tc_set_new_mode` to mimic the windows function of the same name. Full details are in the [http://google-perftools.googlecode.com/svn/tags/perftools-1.5/ChangeLog ChangeLog]. === 11 September 2009 === I've just released perftools 1.4 The major change this release is the addition of a debugging malloc library! If you link with `libtcmalloc_debug.so` instead of `libtcmalloc.so` (and likewise for the `minimal` variants) you'll get a debugging malloc, which will catch double-frees, writes to freed data, `free`/`delete` and `delete`/`delete[]` mismatches, and even (optionally) writes past the end of an allocated block. We plan to do more with this library in the future, including supporting it on Windows, and adding the ability to use the debugging library with your default malloc in addition to using it with tcmalloc. There are also the usual complement of bug fixes, documented in the ChangeLog, and a few minor user-tunable knobs added to components like the system allocator. === 9 June 2009 === I've just released perftools 1.3 Like 1.2, this has a variety of bug fixes, especially related to the Windows build. One of my bugfixes is to undo the weird `ld -r` fix to `.a` files that I introduced in perftools 1.2: it caused problems on too many platforms. I've reverted back to normal `.a` files. To work around the original problem that prompted the `ld -r` fix, I now provide `libtcmalloc_and_profiler.a`, for folks who want to link in both. The most interesting API change is that I now not only override `malloc`/`free`/etc, I also expose them via a unique set of symbols: `tc_malloc`/`tc_free`/etc. This enables clients to write their own memory wrappers that use tcmalloc: {{{ void* malloc(size_t size) { void* r = tc_malloc(size); Log(r); return r; } }}} === 17 April 2009 === I've just released perftools 1.2. This is mostly a bugfix release. The major change is internal: I have a new system for creating packages, which allows me to create 64-bit packages. (I still don't do that for perftools, because there is still no great 64-bit solution, with libunwind still giving problems and --disable-frame-pointers not practical in every environment.) Another interesting change involves Windows: a [http://code.google.com/p/google-perftools/issues/detail?id=126 new patch] allows users to choose to override malloc/free/etc on Windows rather than patching, as is done now. This can be used to create custom CRTs. My fix for this [http://groups.google.com/group/google-perftools/browse_thread/thread/1ff9b50043090d9d/a59210c4206f2060?lnk=gst&q=dynamic#a59210c4206f2060 bug involving static linking] ended up being to make libtcmalloc.a and libperftools.a a big .o file, rather than a true `ar` archive. This should not yield any problems in practice -- in fact, it should be better, since the heap profiler, leak checker, and cpu profiler will now all work even with the static libraries -- but if you find it does, please file a bug report. Finally, the profile_handler_unittest provided in the perftools testsuite (new in this release) is failing on FreeBSD. The end-to-end test that uses the profile-handler is passing, so I suspect the problem may be with the test, not the perftools code itself. However, I do not know enough about how itimers work on FreeBSD to be able to debug it. If you can figure it out, please let me know! === 11 March 2009 === I've just released perftools 1.1! It has many changes since perftools 1.0 including * Faster performance due to dynamically sized thread caches * Better heap-sampling for more realistic profiles * Improved support on Windows (MSVC 7.1 and cygwin) * Better stacktraces in linux (using VDSO) * Many bug fixes and feature requests Note: if you use the CPU-profiler with applications that fork without doing an exec right afterwards, please see the README. Recent testing has shown that profiles are unreliable in that case. The problem has existed since the first release of perftools. We expect to have a fix for perftools 1.2. For more details, see [http://code.google.com/p/google-perftools/issues/detail?id=105 issue 105]. Everyone who uses perftools 1.0 is encouraged to upgrade to perftools 1.1. If you see any problems with the new release, please file a bug report at http://code.google.com/p/google-perftools/issues/list. Enjoy! ================================================ FILE: distro/google-perftools-1.7/README ================================================ IMPORTANT NOTE FOR 64-BIT USERS ------------------------------- There are known issues with some perftools functionality on x86_64 systems. See 64-BIT ISSUES, below. TCMALLOC -------- Just link in -ltcmalloc or -ltcmalloc_minimal to get the advantages of tcmalloc -- a replacement for malloc and new. See below for some environment variables you can use with tcmalloc, as well. tcmalloc functionality is available on all systems we've tested; see INSTALL for more details. See README_windows.txt for instructions on using tcmalloc on Windows. NOTE: When compiling with programs with gcc, that you plan to link with libtcmalloc, it's safest to pass in the flags -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free when compiling. gcc makes some optimizations assuming it is using its own, built-in malloc; that assumption obviously isn't true with tcmalloc. In practice, we haven't seen any problems with this, but the expected risk is highest for users who register their own malloc hooks with tcmalloc (using google/malloc_hook.h). The risk is lowest for folks who use tcmalloc_minimal (or, of course, who pass in the above flags :-) ). HEAP PROFILER ------------- See doc/heap-profiler.html for information about how to use tcmalloc's heap profiler and analyze its output. As a quick-start, do the following after installing this package: 1) Link your executable with -ltcmalloc 2) Run your executable with the HEAPPROFILE environment var set: $ HEAPPROFILE=/tmp/heapprof [binary args] 3) Run pprof to analyze the heap usage $ pprof /tmp/heapprof.0045.heap # run 'ls' to see options $ pprof --gv /tmp/heapprof.0045.heap You can also use LD_PRELOAD to heap-profile an executable that you didn't compile. There are other environment variables, besides HEAPPROFILE, you can set to adjust the heap-profiler behavior; c.f. "ENVIRONMENT VARIABLES" below. The heap profiler is available on all unix-based systems we've tested; see INSTALL for more details. It is not currently available on Windows. HEAP CHECKER ------------ See doc/heap-checker.html for information about how to use tcmalloc's heap checker. In order to catch all heap leaks, tcmalloc must be linked *last* into your executable. The heap checker may mischaracterize some memory accesses in libraries listed after it on the link line. For instance, it may report these libraries as leaking memory when they're not. (See the source code for more details.) Here's a quick-start for how to use: As a quick-start, do the following after installing this package: 1) Link your executable with -ltcmalloc 2) Run your executable with the HEAPCHECK environment var set: $ HEAPCHECK=1 [binary args] Other values for HEAPCHECK: normal (equivalent to "1"), strict, draconian You can also use LD_PRELOAD to heap-check an executable that you didn't compile. The heap checker is only available on Linux at this time; see INSTALL for more details. CPU PROFILER ------------ See doc/cpu-profiler.html for information about how to use the CPU profiler and analyze its output. As a quick-start, do the following after installing this package: 1) Link your executable with -lprofiler 2) Run your executable with the CPUPROFILE environment var set: $ CPUPROFILE=/tmp/prof.out [binary args] 3) Run pprof to analyze the CPU usage $ pprof /tmp/prof.out # -pg-like text output $ pprof --gv /tmp/prof.out # really cool graphical output There are other environment variables, besides CPUPROFILE, you can set to adjust the cpu-profiler behavior; cf "ENVIRONMENT VARIABLES" below. The CPU profiler is available on all unix-based systems we've tested; see INSTALL for more details. It is not currently available on Windows. NOTE: CPU profiling doesn't work after fork (unless you immediately do an exec()-like call afterwards). Furthermore, if you do fork, and the child calls exit(), it may corrupt the profile data. You can use _exit() to work around this. We hope to have a fix for both problems in the next release of perftools (hopefully perftools 1.2). EVERYTHING IN ONE ----------------- If you want the CPU profiler, heap profiler, and heap leak-checker to all be available for your application, you can do: gcc -o myapp ... -lprofiler -ltcmalloc However, if you have a reason to use the static versions of the library, this two-library linking won't work: gcc -o myapp ... /usr/lib/libprofiler.a /usr/lib/libtcmalloc.a # errors! Instead, use the special libtcmalloc_and_profiler library, which we make for just this purpose: gcc -o myapp ... /usr/lib/libtcmalloc_and_profiler.a ENVIRONMENT VARIABLES --------------------- The cpu profiler, heap checker, and heap profiler will lie dormant, using no memory or CPU, until you turn them on. (Thus, there's no harm in linking -lprofiler into every application, and also -ltcmalloc assuming you're ok using the non-libc malloc library.) The easiest way to turn them on is by setting the appropriate environment variables. We have several variables that let you enable/disable features as well as tweak parameters. Here are some of the most important variables: HEAPPROFILE=
 -- turns on heap profiling and dumps data using this prefix
HEAPCHECK=  -- turns on heap checking with strictness 'type'
CPUPROFILE= -- turns on cpu profiling and dumps data to this file.
PROFILESELECTED=1 -- if set, cpu-profiler will only profile regions of code
                     surrounded with ProfilerEnable()/ProfilerDisable().
PROFILEFREQUENCY=x-- how many interrupts/second the cpu-profiler samples.

TCMALLOC_DEBUG= -- the higher level, the more messages malloc emits
MALLOCSTATS=    -- prints memory-use stats at program-exit

For a full list of variables, see the documentation pages:
   doc/cpuprofile.html
   doc/heapprofile.html
   doc/heap_checker.html


COMPILING ON NON-LINUX SYSTEMS
------------------------------

Perftools was developed and tested on x86 Linux systems, and it works
in its full generality only on those systems.  However, we've
successfully ported much of the tcmalloc library to FreeBSD, Solaris
x86, and Darwin (Mac OS X) x86 and ppc; and we've ported the basic
functionality in tcmalloc_minimal to Windows.  See INSTALL for details.
See README_windows.txt for details on the Windows port.


PERFORMANCE
-----------

If you're interested in some third-party comparisons of tcmalloc to
other malloc libraries, here are a few web pages that have been
brought to our attention.  The first discusses the effect of using
various malloc libraries on OpenLDAP.  The second compares tcmalloc to
win32's malloc.
  http://www.highlandsun.com/hyc/malloc/
  http://gaiacrtn.free.fr/articles/win32perftools.html

It's possible to build tcmalloc in a way that trades off faster
performance (particularly for deletes) at the cost of more memory
fragmentation (that is, more unusable memory on your system).  See the
INSTALL file for details.


OLD SYSTEM ISSUES
-----------------

When compiling perftools on some old systems, like RedHat 8, you may
get an error like this:
    ___tls_get_addr: symbol not found

This means that you have a system where some parts are updated enough
to support Thread Local Storage, but others are not.  The perftools
configure script can't always detect this kind of case, leading to
that error.  To fix it, just comment out (or delete) the line
   #define HAVE_TLS 1
in your config.h file before building.


OS X ISSUES
-----------

You may need to set the environment variable DYLD_FORCE_FLAT_NAMESPACE
to use perftools with OS X.  Because of how OS X does symbol binding,
libc routines will use libc malloc even when the binary is linked with
-ltcmalloc.  This is not usually a problem, but becomes one if the
application is responsible for freeing that memory: the application
will use tcmalloc's free() to try to free memory allocated with libc's
malloc(), which will cause no end of confusion.

One (or both) of these workaround may fix the problem:
    DYLD_FORCE_FLAT_NAMESPACE=1 myapp
    DYLD_INSERT_LIBRARIES=path/to/libtcmalloc.dylib myapp

The best solution may depend on the version of OS X being used.
Neither solution is likely to work if you dlopen() libraries from
within your application.  If you have any experience with this, we'd
appreciate you sharing it at
   http://groups.google.com/group/google-perftools


64-BIT ISSUES
-------------

There are two issues that can cause program hangs or crashes on x86_64
64-bit systems, which use the libunwind library to get stack-traces.
Neither issue should affect the core tcmalloc library; they both
affect the perftools tools such as cpu-profiler, heap-checker, and
heap-profiler.

1) Some libc's -- at least glibc 2.4 on x86_64 -- have a bug where the
libc function dl_iterate_phdr() acquires its locks in the wrong
order.  This bug should not affect tcmalloc, but may cause occasional
deadlock with the cpu-profiler, heap-profiler, and heap-checker.
Its likeliness increases the more dlopen() commands an executable has.
Most executables don't have any, though several library routines like
getgrgid() call dlopen() behind the scenes.

2) On x86-64 64-bit systems, while tcmalloc itself works fine, the
cpu-profiler tool is unreliable: it will sometimes work, but sometimes
cause a segfault.  I'll explain the problem first, and then some
workarounds.

Note that this only affects the cpu-profiler, which is a
google-perftools feature you must turn on manually by setting the
CPUPROFILE environment variable.  If you do not turn on cpu-profiling,
you shouldn't see any crashes due to perftools.

The gory details: The underlying problem is in the backtrace()
function, which is a built-in function in libc.
Backtracing is fairly straightforward in the normal case, but can run
into problems when having to backtrace across a signal frame.
Unfortunately, the cpu-profiler uses signals in order to register a
profiling event, so every backtrace that the profiler does crosses a
signal frame.

In our experience, the only time there is trouble is when the signal
fires in the middle of pthread_mutex_lock.  pthread_mutex_lock is
called quite a bit from system libraries, particularly at program
startup and when creating a new thread.

The solution: The dwarf debugging format has support for 'cfi
annotations', which make it easy to recognize a signal frame.  Some OS
distributions, such as Fedora and gentoo 2007.0, already have added
cfi annotations to their libc.  A future version of libunwind should
recognize these annotations; these systems should not see any
crashses.

Workarounds: If you see problems with crashes when running the
cpu-profiler, consider inserting ProfilerStart()/ProfilerStop() into
your code, rather than setting CPUPROFILE.  This will profile only
those sections of the codebase.  Though we haven't done much testing,
in theory this should reduce the chance of crashes by limiting the
signal generation to only a small part of the codebase.  Ideally, you
would not use ProfilerStart()/ProfilerStop() around code that spawns
new threads, or is otherwise likely to cause a call to
pthread_mutex_lock!

---
11 January 2011


================================================
FILE: distro/google-perftools-1.7/README_windows.txt
================================================
--- COMPILING

This project has begun being ported to Windows.  A working solution
file exists in this directory:
    google-perftools.sln

You can load this solution file into either VC++ 7.1 (Visual Studio
2003) or VC++ 8.0 (Visual Studio 2005) -- in the latter case, it will
automatically convert the files to the latest format for you.

When you build the solution, it will create a number of unittests,
which you can run by hand (or, more easily, under the Visual Studio
debugger) to make sure everything is working properly on your system.
The binaries will end up in a directory called "debug" or "release" in
the top-level directory (next to the .sln file).  It will also create
two binaries, nm-pdb and addr2line-pdb, which you should install in
the same directory you install the 'pprof' perl script.

I don't know very much about how to install DLLs on Windows, so you'll
have to figure out that part for yourself.  If you choose to just
re-use the existing .sln, make sure you set the IncludeDir's
appropriately!  Look at the properties for libtcmalloc_minimal.dll.

Note that these systems are set to build in Debug mode by default.
You may want to change them to Release mode.

To use tcmalloc_minimal in your own projects, you should only need to
build the dll and install it someplace, so you can link it into
further binaries.  To use the dll, you need to add the following to
the linker line of your executable:
   "libtcmalloc_minimal.lib" /INCLUDE:"__tcmalloc" 

Here is how to accomplish this in Visual Studio 2005 (VC8):

1) Have your executable depend on the tcmalloc library by selecting
   "Project Dependencies..." from the "Project" menu.  Your executable
   should depend on "libtcmalloc_minimal".

2) Have your executable depend on a tcmalloc symbol -- this is
   necessary so the linker doesn't "optimize out" the libtcmalloc
   dependency -- by right-clicking on your executable's project (in
   the solution explorer), selecting Properties from the pull-down
   menu, then selecting "Configuration Properties" -> "Linker" ->
   "Input".  Then, in the "Force Symbol References" field, enter the
   text "__tcmalloc" (without the quotes).  Be sure to do this for both
   debug and release modes!

You can also link tcmalloc code in statically -- see the example
project tcmalloc_minimal_unittest-static, which does this.  For this
to work, you'll need to add "/D PERFTOOLS_DLL_DECL=" to the compile
line of every perftools .cc file.  You do not need to depend on the
tcmalloc symbol in this case (that is, you don't need to do either
step 1 or step 2 from above).

An alternative to all the above is to statically link your application
with libc, and then replace its malloc with tcmalloc.  This allows you
to just build and link your program normally; the tcmalloc support
comes in a post-processing step.  This is more reliable than the above
technique (which depends on run-time patching, which is inherently
fragile), though more work to set up.  For details, see
https://groups.google.com/group/google-perftools/browse_thread/thread/41cd3710af85e57b


--- THE HEAP-PROFILER

The heap-profiler has had a preliminary port to Windows.  It has not
been well tested, and probably does not work at all when Frame Pointer
Optimization (FPO) is enabled -- that is, in release mode.  The other
features of perftools, such as the cpu-profiler and leak-checker, have
not yet been ported to Windows at all.


--- ISSUES

NOTE FOR WIN2K USERS: According to reports
(http://code.google.com/p/google-perftools/issues/detail?id=127)
the stack-tracing necessary for the heap-profiler does not work on
Win2K.  The best workaround is, if you are building on a Win2k system
is to add "/D NO_TCMALLOC_SAMPLES=" to your build, to turn off the
stack-tracing.  You will not be able to use the heap-profiler if you
do this.

NOTE ON _MSIZE and _RECALLOC: The tcmalloc version of _msize returns
the size of the region tcmalloc allocated for you -- which is at least
as many bytes you asked for, but may be more.  (btw, these *are* bytes
you own, even if you didn't ask for all of them, so it's correct code
to access all of them if you want.)  Unfortunately, the Windows CRT
_recalloc() routine assumes that _msize returns exactly as many bytes
as were requested.  As a result, _recalloc() may not zero out new
bytes correctly.  IT'S SAFEST NOT TO USE _RECALLOC WITH TCMALLOC.
_recalloc() is a tricky routine to use in any case (it's not safe to
use with realloc, for instance).


I have little experience with Windows programming, so there may be
better ways to set this up than I've done!  If you run across any
problems, please post to the google-perftools Google Group, or report
them on the google-perftools Google Code site:
   http://groups.google.com/group/google-perftools
   http://code.google.com/p/google-perftools/issues/list

-- craig

Last modified: 3 February 2010


================================================
FILE: distro/google-perftools-1.7/TODO
================================================
HEAP PROFILER

1) Fix heap profiling under all STLs
   * Find out how to force non-glibc STL libraries to call new() and
     delete() for every allocation / deallocation.
   * Make heap profiler ignore STL-internal allocations for those
     libraries under which we cannot profile accurately, so we only
     see object-level leaks.
2) Remove dependency on tcmalloc?
3) Port to non-linux O/Ses (right now code uses /proc for library info)
4) Port to non-x86 architectures (locking code in spinlock is x86-specific)
5) Port to C?
6) Figure out how to get setenv() to work properly before main() in
   shared libaries, and get rid of the profile-naming hack once we
   do.  (See HeapProfiler::Init().)


HEAP CHECKER

1) Remove requirement that the heap-checker must be linked last into
   an application (hard! -- it needs its global constructor to run
   first)

TCMALLOC

1) Implement mallinfo/mallopt
2) Have tcmalloc work correctly when libpthread is not linked in
   (currently working for glibc, could use other libc's too)
3) Return memory to the system when requirements drop
4) Explore coloring allocated objects to avoid cache conflicts
5) Explore biasing reclamation to larger addresses
6) Add contention stats to a synchronization.cc (can do spinlocks,
   but threads? -- may have to provide our own thread implementation)

CPU PROFILER

1) Figure out how to get setenv() to work properly before main() in
   shared libaries(), and get rid of the profile-naming hack once we
   do.  (See Profiler::GetUniquePathFromEnv().)
2) Resolve crashing problems on x86_64 (see README)

STACKTRACE

1) Remove dependency on linux/x86

---
11 March 2008


================================================
FILE: distro/google-perftools-1.7/aclocal.m4
================================================
# generated automatically by aclocal 1.9.6 -*- Autoconf -*-

# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
# 2005  Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.

# Copyright (C) 2002, 2003, 2005  Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# AM_AUTOMAKE_VERSION(VERSION)
# ----------------------------
# Automake X.Y traces this macro to ensure aclocal.m4 has been
# generated from the m4 files accompanying Automake X.Y.
AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"])

# AM_SET_CURRENT_AUTOMAKE_VERSION
# -------------------------------
# Call AM_AUTOMAKE_VERSION so it can be traced.
# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
	 [AM_AUTOMAKE_VERSION([1.9.6])])

# AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-

# Copyright (C) 2001, 2003, 2005  Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
# $ac_aux_dir to `$srcdir/foo'.  In other projects, it is set to
# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
#
# Of course, Automake must honor this variable whenever it calls a
# tool from the auxiliary directory.  The problem is that $srcdir (and
# therefore $ac_aux_dir as well) can be either absolute or relative,
# depending on how configure is run.  This is pretty annoying, since
# it makes $ac_aux_dir quite unusable in subdirectories: in the top
# source directory, any form will work fine, but in subdirectories a
# relative path needs to be adjusted first.
#
# $ac_aux_dir/missing
#    fails when called from a subdirectory if $ac_aux_dir is relative
# $top_srcdir/$ac_aux_dir/missing
#    fails if $ac_aux_dir is absolute,
#    fails when called from a subdirectory in a VPATH build with
#          a relative $ac_aux_dir
#
# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
# are both prefixed by $srcdir.  In an in-source build this is usually
# harmless because $srcdir is `.', but things will broke when you
# start a VPATH build or use an absolute $srcdir.
#
# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
# iff we strip the leading $srcdir from $ac_aux_dir.  That would be:
#   am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
# and then we would define $MISSING as
#   MISSING="\${SHELL} $am_aux_dir/missing"
# This will work as long as MISSING is not called from configure, because
# unfortunately $(top_srcdir) has no meaning in configure.
# However there are other variables, like CC, which are often used in
# configure, and could therefore not use this "fixed" $ac_aux_dir.
#
# Another solution, used here, is to always expand $ac_aux_dir to an
# absolute PATH.  The drawback is that using absolute paths prevent a
# configured tree to be moved without reconfiguration.

AC_DEFUN([AM_AUX_DIR_EXPAND],
[dnl Rely on autoconf to set up CDPATH properly.
AC_PREREQ([2.50])dnl
# expand $ac_aux_dir to an absolute path
am_aux_dir=`cd $ac_aux_dir && pwd`
])

# AM_CONDITIONAL                                            -*- Autoconf -*-

# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# serial 7

# AM_CONDITIONAL(NAME, SHELL-CONDITION)
# -------------------------------------
# Define a conditional.
AC_DEFUN([AM_CONDITIONAL],
[AC_PREREQ(2.52)dnl
 ifelse([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],
	[$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
AC_SUBST([$1_TRUE])
AC_SUBST([$1_FALSE])
if $2; then
  $1_TRUE=
  $1_FALSE='#'
else
  $1_TRUE='#'
  $1_FALSE=
fi
AC_CONFIG_COMMANDS_PRE(
[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
  AC_MSG_ERROR([[conditional "$1" was never defined.
Usually this means the macro was only invoked conditionally.]])
fi])])


# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# serial 8

# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
# written in clear, in which case automake, when reading aclocal.m4,
# will think it sees a *use*, and therefore will trigger all it's
# C support machinery.  Also note that it means that autoscan, seeing
# CC etc. in the Makefile, will ask for an AC_PROG_CC use...


# _AM_DEPENDENCIES(NAME)
# ----------------------
# See how the compiler implements dependency checking.
# NAME is "CC", "CXX", "GCJ", or "OBJC".
# We try a few techniques and use that to set a single cache variable.
#
# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
# dependency, and given that the user is not expected to run this macro,
# just rely on AC_PROG_CC.
AC_DEFUN([_AM_DEPENDENCIES],
[AC_REQUIRE([AM_SET_DEPDIR])dnl
AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
AC_REQUIRE([AM_MAKE_INCLUDE])dnl
AC_REQUIRE([AM_DEP_TRACK])dnl

ifelse([$1], CC,   [depcc="$CC"   am_compiler_list=],
       [$1], CXX,  [depcc="$CXX"  am_compiler_list=],
       [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
       [$1], GCJ,  [depcc="$GCJ"  am_compiler_list='gcc3 gcc'],
                   [depcc="$$1"   am_compiler_list=])

AC_CACHE_CHECK([dependency style of $depcc],
               [am_cv_$1_dependencies_compiler_type],
[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
  # We make a subdir and do the tests there.  Otherwise we can end up
  # making bogus files that we don't know about and never remove.  For
  # instance it was reported that on HP-UX the gcc test will end up
  # making a dummy file named `D' -- because `-MD' means `put the output
  # in D'.
  mkdir conftest.dir
  # Copy depcomp to subdir because otherwise we won't find it if we're
  # using a relative directory.
  cp "$am_depcomp" conftest.dir
  cd conftest.dir
  # We will build objects and dependencies in a subdirectory because
  # it helps to detect inapplicable dependency modes.  For instance
  # both Tru64's cc and ICC support -MD to output dependencies as a
  # side effect of compilation, but ICC will put the dependencies in
  # the current directory while Tru64 will put them in the object
  # directory.
  mkdir sub

  am_cv_$1_dependencies_compiler_type=none
  if test "$am_compiler_list" = ""; then
     am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
  fi
  for depmode in $am_compiler_list; do
    # Setup a source with many dependencies, because some compilers
    # like to wrap large dependency lists on column 80 (with \), and
    # we should not choose a depcomp mode which is confused by this.
    #
    # We need to recreate these files for each test, as the compiler may
    # overwrite some of them when testing with obscure command lines.
    # This happens at least with the AIX C compiler.
    : > sub/conftest.c
    for i in 1 2 3 4 5 6; do
      echo '#include "conftst'$i'.h"' >> sub/conftest.c
      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
      # Solaris 8's {/usr,}/bin/sh.
      touch sub/conftst$i.h
    done
    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf

    case $depmode in
    nosideeffect)
      # after this tag, mechanisms are not by side-effect, so they'll
      # only be used when explicitly requested
      if test "x$enable_dependency_tracking" = xyes; then
	continue
      else
	break
      fi
      ;;
    none) break ;;
    esac
    # We check with `-c' and `-o' for the sake of the "dashmstdout"
    # mode.  It turns out that the SunPro C++ compiler does not properly
    # handle `-M -o', and we need to detect this.
    if depmode=$depmode \
       source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
       $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
         >/dev/null 2>conftest.err &&
       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
       grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
      # icc doesn't choke on unknown options, it will just issue warnings
      # or remarks (even with -Werror).  So we grep stderr for any message
      # that says an option was ignored or not supported.
      # When given -MP, icc 7.0 and 7.1 complain thusly:
      #   icc: Command line warning: ignoring option '-M'; no argument required
      # The diagnosis changed in icc 8.0:
      #   icc: Command line remark: option '-MP' not supported
      if (grep 'ignoring option' conftest.err ||
          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
        am_cv_$1_dependencies_compiler_type=$depmode
        break
      fi
    fi
  done

  cd ..
  rm -rf conftest.dir
else
  am_cv_$1_dependencies_compiler_type=none
fi
])
AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
AM_CONDITIONAL([am__fastdep$1], [
  test "x$enable_dependency_tracking" != xno \
  && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
])


# AM_SET_DEPDIR
# -------------
# Choose a directory name for dependency files.
# This macro is AC_REQUIREd in _AM_DEPENDENCIES
AC_DEFUN([AM_SET_DEPDIR],
[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
])


# AM_DEP_TRACK
# ------------
AC_DEFUN([AM_DEP_TRACK],
[AC_ARG_ENABLE(dependency-tracking,
[  --disable-dependency-tracking  speeds up one-time build
  --enable-dependency-tracking   do not reject slow dependency extractors])
if test "x$enable_dependency_tracking" != xno; then
  am_depcomp="$ac_aux_dir/depcomp"
  AMDEPBACKSLASH='\'
fi
AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
AC_SUBST([AMDEPBACKSLASH])
])

# Generate code to set up dependency tracking.              -*- Autoconf -*-

# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

#serial 3

# _AM_OUTPUT_DEPENDENCY_COMMANDS
# ------------------------------
AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
[for mf in $CONFIG_FILES; do
  # Strip MF so we end up with the name of the file.
  mf=`echo "$mf" | sed -e 's/:.*$//'`
  # Check whether this is an Automake generated Makefile or not.
  # We used to match only the files named `Makefile.in', but
  # some people rename them; so instead we look at the file content.
  # Grep'ing the first line is not enough: some people post-process
  # each Makefile.in and add a new line on top of each file to say so.
  # So let's grep whole file.
  if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
    dirpart=`AS_DIRNAME("$mf")`
  else
    continue
  fi
  # Extract the definition of DEPDIR, am__include, and am__quote
  # from the Makefile without running `make'.
  DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
  test -z "$DEPDIR" && continue
  am__include=`sed -n 's/^am__include = //p' < "$mf"`
  test -z "am__include" && continue
  am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
  # When using ansi2knr, U may be empty or an underscore; expand it
  U=`sed -n 's/^U = //p' < "$mf"`
  # Find all dependency output files, they are included files with
  # $(DEPDIR) in their names.  We invoke sed twice because it is the
  # simplest approach to changing $(DEPDIR) to its actual value in the
  # expansion.
  for file in `sed -n "
    s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
       sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
    # Make sure the directory exists.
    test -f "$dirpart/$file" && continue
    fdir=`AS_DIRNAME(["$file"])`
    AS_MKDIR_P([$dirpart/$fdir])
    # echo "creating $dirpart/$file"
    echo '# dummy' > "$dirpart/$file"
  done
done
])# _AM_OUTPUT_DEPENDENCY_COMMANDS


# AM_OUTPUT_DEPENDENCY_COMMANDS
# -----------------------------
# This macro should only be invoked once -- use via AC_REQUIRE.
#
# This code is only required when automatic dependency tracking
# is enabled.  FIXME.  This creates each `.P' file that we will
# need in order to bootstrap the dependency handling code.
AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
[AC_CONFIG_COMMANDS([depfiles],
     [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
     [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
])

# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# serial 8

# AM_CONFIG_HEADER is obsolete.  It has been replaced by AC_CONFIG_HEADERS.
AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)])

# Do all the work for Automake.                             -*- Autoconf -*-

# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# serial 12

# This macro actually does too much.  Some checks are only needed if
# your package does certain things.  But this isn't really a big deal.

# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
# AM_INIT_AUTOMAKE([OPTIONS])
# -----------------------------------------------
# The call with PACKAGE and VERSION arguments is the old style
# call (pre autoconf-2.50), which is being phased out.  PACKAGE
# and VERSION should now be passed to AC_INIT and removed from
# the call to AM_INIT_AUTOMAKE.
# We support both call styles for the transition.  After
# the next Automake release, Autoconf can make the AC_INIT
# arguments mandatory, and then we can depend on a new Autoconf
# release and drop the old call support.
AC_DEFUN([AM_INIT_AUTOMAKE],
[AC_PREREQ([2.58])dnl
dnl Autoconf wants to disallow AM_ names.  We explicitly allow
dnl the ones we care about.
m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
AC_REQUIRE([AC_PROG_INSTALL])dnl
# test to see if srcdir already configured
if test "`cd $srcdir && pwd`" != "`pwd`" &&
   test -f $srcdir/config.status; then
  AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
fi

# test whether we have cygpath
if test -z "$CYGPATH_W"; then
  if (cygpath --version) >/dev/null 2>/dev/null; then
    CYGPATH_W='cygpath -w'
  else
    CYGPATH_W=echo
  fi
fi
AC_SUBST([CYGPATH_W])

# Define the identity of the package.
dnl Distinguish between old-style and new-style calls.
m4_ifval([$2],
[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
 AC_SUBST([PACKAGE], [$1])dnl
 AC_SUBST([VERSION], [$2])],
[_AM_SET_OPTIONS([$1])dnl
 AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
 AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl

_AM_IF_OPTION([no-define],,
[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
 AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl

# Some tools Automake needs.
AC_REQUIRE([AM_SANITY_CHECK])dnl
AC_REQUIRE([AC_ARG_PROGRAM])dnl
AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
AM_MISSING_PROG(AUTOCONF, autoconf)
AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
AM_MISSING_PROG(AUTOHEADER, autoheader)
AM_MISSING_PROG(MAKEINFO, makeinfo)
AM_PROG_INSTALL_SH
AM_PROG_INSTALL_STRIP
AC_REQUIRE([AM_PROG_MKDIR_P])dnl
# We need awk for the "check" target.  The system "awk" is bad on
# some platforms.
AC_REQUIRE([AC_PROG_AWK])dnl
AC_REQUIRE([AC_PROG_MAKE_SET])dnl
AC_REQUIRE([AM_SET_LEADING_DOT])dnl
_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
              [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
	      		     [_AM_PROG_TAR([v7])])])
_AM_IF_OPTION([no-dependencies],,
[AC_PROVIDE_IFELSE([AC_PROG_CC],
                  [_AM_DEPENDENCIES(CC)],
                  [define([AC_PROG_CC],
                          defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
AC_PROVIDE_IFELSE([AC_PROG_CXX],
                  [_AM_DEPENDENCIES(CXX)],
                  [define([AC_PROG_CXX],
                          defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
])
])


# When config.status generates a header, we must update the stamp-h file.
# This file resides in the same directory as the config header
# that is generated.  The stamp files are numbered to have different names.

# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
# loop where config.status creates the headers, so we can generate
# our stamp files there.
AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
[# Compute $1's index in $config_headers.
_am_stamp_count=1
for _am_header in $config_headers :; do
  case $_am_header in
    $1 | $1:* )
      break ;;
    * )
      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
  esac
done
echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])

# Copyright (C) 2001, 2003, 2005  Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# AM_PROG_INSTALL_SH
# ------------------
# Define $install_sh.
AC_DEFUN([AM_PROG_INSTALL_SH],
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
install_sh=${install_sh-"$am_aux_dir/install-sh"}
AC_SUBST(install_sh)])

# Copyright (C) 2003, 2005  Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# serial 2

# Check whether the underlying file-system supports filenames
# with a leading dot.  For instance MS-DOS doesn't.
AC_DEFUN([AM_SET_LEADING_DOT],
[rm -rf .tst 2>/dev/null
mkdir .tst 2>/dev/null
if test -d .tst; then
  am__leading_dot=.
else
  am__leading_dot=_
fi
rmdir .tst 2>/dev/null
AC_SUBST([am__leading_dot])])

# Check to see how 'make' treats includes.	            -*- Autoconf -*-

# Copyright (C) 2001, 2002, 2003, 2005  Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# serial 3

# AM_MAKE_INCLUDE()
# -----------------
# Check to see how make treats includes.
AC_DEFUN([AM_MAKE_INCLUDE],
[am_make=${MAKE-make}
cat > confinc << 'END'
am__doit:
	@echo done
.PHONY: am__doit
END
# If we don't find an include directive, just comment out the code.
AC_MSG_CHECKING([for style of include used by $am_make])
am__include="#"
am__quote=
_am_result=none
# First try GNU make style include.
echo "include confinc" > confmf
# We grep out `Entering directory' and `Leaving directory'
# messages which can occur if `w' ends up in MAKEFLAGS.
# In particular we don't look at `^make:' because GNU make might
# be invoked under some other name (usually "gmake"), in which
# case it prints its new name instead of `make'.
if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
   am__include=include
   am__quote=
   _am_result=GNU
fi
# Now try BSD make style include.
if test "$am__include" = "#"; then
   echo '.include "confinc"' > confmf
   if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
      am__include=.include
      am__quote="\""
      _am_result=BSD
   fi
fi
AC_SUBST([am__include])
AC_SUBST([am__quote])
AC_MSG_RESULT([$_am_result])
rm -f confinc confmf
])

# Copyright (C) 1999, 2000, 2001, 2003, 2005  Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# serial 3

# AM_PROG_CC_C_O
# --------------
# Like AC_PROG_CC_C_O, but changed for automake.
AC_DEFUN([AM_PROG_CC_C_O],
[AC_REQUIRE([AC_PROG_CC_C_O])dnl
AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
# FIXME: we rely on the cache variable name because
# there is no other way.
set dummy $CC
ac_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']`
if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" != yes"; then
   # Losing compiler, so override with the script.
   # FIXME: It is wrong to rewrite CC.
   # But if we don't then we get into trouble of one sort or another.
   # A longer-term fix would be to have automake use am__CC in this case,
   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
   CC="$am_aux_dir/compile $CC"
fi
])

# Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-

# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# serial 4

# AM_MISSING_PROG(NAME, PROGRAM)
# ------------------------------
AC_DEFUN([AM_MISSING_PROG],
[AC_REQUIRE([AM_MISSING_HAS_RUN])
$1=${$1-"${am_missing_run}$2"}
AC_SUBST($1)])


# AM_MISSING_HAS_RUN
# ------------------
# Define MISSING if not defined so far and test if it supports --run.
# If it does, set am_missing_run to use it, otherwise, to nothing.
AC_DEFUN([AM_MISSING_HAS_RUN],
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
# Use eval to expand $SHELL
if eval "$MISSING --run true"; then
  am_missing_run="$MISSING --run "
else
  am_missing_run=
  AC_MSG_WARN([`missing' script is too old or missing])
fi
])

# Copyright (C) 2003, 2004, 2005  Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# AM_PROG_MKDIR_P
# ---------------
# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise.
#
# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories
# created by `make install' are always world readable, even if the
# installer happens to have an overly restrictive umask (e.g. 077).
# This was a mistake.  There are at least two reasons why we must not
# use `-m 0755':
#   - it causes special bits like SGID to be ignored,
#   - it may be too restrictive (some setups expect 775 directories).
#
# Do not use -m 0755 and let people choose whatever they expect by
# setting umask.
#
# We cannot accept any implementation of `mkdir' that recognizes `-p'.
# Some implementations (such as Solaris 8's) are not thread-safe: if a
# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c'
# concurrently, both version can detect that a/ is missing, but only
# one can create it and the other will error out.  Consequently we
# restrict ourselves to GNU make (using the --version option ensures
# this.)
AC_DEFUN([AM_PROG_MKDIR_P],
[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
  # We used to keeping the `.' as first argument, in order to
  # allow $(mkdir_p) to be used without argument.  As in
  #   $(mkdir_p) $(somedir)
  # where $(somedir) is conditionally defined.  However this is wrong
  # for two reasons:
  #  1. if the package is installed by a user who cannot write `.'
  #     make install will fail,
  #  2. the above comment should most certainly read
  #     $(mkdir_p) $(DESTDIR)$(somedir)
  #     so it does not work when $(somedir) is undefined and
  #     $(DESTDIR) is not.
  #  To support the latter case, we have to write
  #     test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
  #  so the `.' trick is pointless.
  mkdir_p='mkdir -p --'
else
  # On NextStep and OpenStep, the `mkdir' command does not
  # recognize any option.  It will interpret all options as
  # directories to create, and then abort because `.' already
  # exists.
  for d in ./-p ./--version;
  do
    test -d $d && rmdir $d
  done
  # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
  if test -f "$ac_aux_dir/mkinstalldirs"; then
    mkdir_p='$(mkinstalldirs)'
  else
    mkdir_p='$(install_sh) -d'
  fi
fi
AC_SUBST([mkdir_p])])

# Helper functions for option handling.                     -*- Autoconf -*-

# Copyright (C) 2001, 2002, 2003, 2005  Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# serial 3

# _AM_MANGLE_OPTION(NAME)
# -----------------------
AC_DEFUN([_AM_MANGLE_OPTION],
[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])

# _AM_SET_OPTION(NAME)
# ------------------------------
# Set option NAME.  Presently that only means defining a flag for this option.
AC_DEFUN([_AM_SET_OPTION],
[m4_define(_AM_MANGLE_OPTION([$1]), 1)])

# _AM_SET_OPTIONS(OPTIONS)
# ----------------------------------
# OPTIONS is a space-separated list of Automake options.
AC_DEFUN([_AM_SET_OPTIONS],
[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])

# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
# -------------------------------------------
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
AC_DEFUN([_AM_IF_OPTION],
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])

# Check to make sure that the build environment is sane.    -*- Autoconf -*-

# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# serial 4

# AM_SANITY_CHECK
# ---------------
AC_DEFUN([AM_SANITY_CHECK],
[AC_MSG_CHECKING([whether build environment is sane])
# Just in case
sleep 1
echo timestamp > conftest.file
# Do `set' in a subshell so we don't clobber the current shell's
# arguments.  Must try -L first in case configure is actually a
# symlink; some systems play weird games with the mod time of symlinks
# (eg FreeBSD returns the mod time of the symlink's containing
# directory).
if (
   set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
   if test "$[*]" = "X"; then
      # -L didn't work.
      set X `ls -t $srcdir/configure conftest.file`
   fi
   rm -f conftest.file
   if test "$[*]" != "X $srcdir/configure conftest.file" \
      && test "$[*]" != "X conftest.file $srcdir/configure"; then

      # If neither matched, then we have a broken ls.  This can happen
      # if, for instance, CONFIG_SHELL is bash and it inherits a
      # broken ls alias from the environment.  This has actually
      # happened.  Such a system could not be considered "sane".
      AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
alias in your environment])
   fi

   test "$[2]" = conftest.file
   )
then
   # Ok.
   :
else
   AC_MSG_ERROR([newly created file is older than distributed files!
Check your system clock])
fi
AC_MSG_RESULT(yes)])

# Copyright (C) 2001, 2003, 2005  Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# AM_PROG_INSTALL_STRIP
# ---------------------
# One issue with vendor `install' (even GNU) is that you can't
# specify the program used to strip binaries.  This is especially
# annoying in cross-compiling environments, where the build's strip
# is unlikely to handle the host's binaries.
# Fortunately install-sh will honor a STRIPPROG variable, so we
# always use install-sh in `make install-strip', and initialize
# STRIPPROG with the value of the STRIP variable (set by the user).
AC_DEFUN([AM_PROG_INSTALL_STRIP],
[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
# Installed binaries are usually stripped using `strip' when the user
# run `make install-strip'.  However `strip' might not be the right
# tool to use in cross-compilation environments, therefore Automake
# will honor the `STRIP' environment variable to overrule this program.
dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
if test "$cross_compiling" != no; then
  AC_CHECK_TOOL([STRIP], [strip], :)
fi
INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
AC_SUBST([INSTALL_STRIP_PROGRAM])])

# Check how to create a tarball.                            -*- Autoconf -*-

# Copyright (C) 2004, 2005  Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# serial 2

# _AM_PROG_TAR(FORMAT)
# --------------------
# Check how to create a tarball in format FORMAT.
# FORMAT should be one of `v7', `ustar', or `pax'.
#
# Substitute a variable $(am__tar) that is a command
# writing to stdout a FORMAT-tarball containing the directory
# $tardir.
#     tardir=directory && $(am__tar) > result.tar
#
# Substitute a variable $(am__untar) that extract such
# a tarball read from stdin.
#     $(am__untar) < result.tar
AC_DEFUN([_AM_PROG_TAR],
[# Always define AMTAR for backward compatibility.
AM_MISSING_PROG([AMTAR], [tar])
m4_if([$1], [v7],
     [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
     [m4_case([$1], [ustar],, [pax],,
              [m4_fatal([Unknown tar format])])
AC_MSG_CHECKING([how to create a $1 tar archive])
# Loop over all known methods to create a tar archive until one works.
_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
_am_tools=${am_cv_prog_tar_$1-$_am_tools}
# Do not fold the above two line into one, because Tru64 sh and
# Solaris sh will not grok spaces in the rhs of `-'.
for _am_tool in $_am_tools
do
  case $_am_tool in
  gnutar)
    for _am_tar in tar gnutar gtar;
    do
      AM_RUN_LOG([$_am_tar --version]) && break
    done
    am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
    am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
    am__untar="$_am_tar -xf -"
    ;;
  plaintar)
    # Must skip GNU tar: if it does not support --format= it doesn't create
    # ustar tarball either.
    (tar --version) >/dev/null 2>&1 && continue
    am__tar='tar chf - "$$tardir"'
    am__tar_='tar chf - "$tardir"'
    am__untar='tar xf -'
    ;;
  pax)
    am__tar='pax -L -x $1 -w "$$tardir"'
    am__tar_='pax -L -x $1 -w "$tardir"'
    am__untar='pax -r'
    ;;
  cpio)
    am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
    am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
    am__untar='cpio -i -H $1 -d'
    ;;
  none)
    am__tar=false
    am__tar_=false
    am__untar=false
    ;;
  esac

  # If the value was cached, stop now.  We just wanted to have am__tar
  # and am__untar set.
  test -n "${am_cv_prog_tar_$1}" && break

  # tar/untar a dummy directory, and stop if the command works
  rm -rf conftest.dir
  mkdir conftest.dir
  echo GrepMe > conftest.dir/file
  AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
  rm -rf conftest.dir
  if test -s conftest.tar; then
    AM_RUN_LOG([$am__untar /dev/null 2>&1 && break
  fi
done
rm -rf conftest.dir

AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
AC_MSG_RESULT([$am_cv_prog_tar_$1])])
AC_SUBST([am__tar])
AC_SUBST([am__untar])
]) # _AM_PROG_TAR

m4_include([m4/ac_have_attribute.m4])
m4_include([m4/acx_nanosleep.m4])
m4_include([m4/acx_pthread.m4])
m4_include([m4/compiler_characteristics.m4])
m4_include([m4/install_prefix.m4])
m4_include([m4/libtool.m4])
m4_include([m4/ltoptions.m4])
m4_include([m4/ltsugar.m4])
m4_include([m4/ltversion.m4])
m4_include([m4/lt~obsolete.m4])
m4_include([m4/namespaces.m4])
m4_include([m4/pc_from_ucontext.m4])
m4_include([m4/program_invocation_name.m4])
m4_include([m4/stl_namespace.m4])


================================================
FILE: distro/google-perftools-1.7/compile
================================================
#! /bin/sh
# Wrapper for compilers which do not understand `-c -o'.

scriptversion=2005-05-14.22

# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
# Written by Tom Tromey .
#
# 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 2, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.

# This file is maintained in Automake, please report
# bugs to  or send patches to
# .

case $1 in
  '')
     echo "$0: No command.  Try \`$0 --help' for more information." 1>&2
     exit 1;
     ;;
  -h | --h*)
    cat <<\EOF
Usage: compile [--help] [--version] PROGRAM [ARGS]

Wrapper for compilers which do not understand `-c -o'.
Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
arguments, and rename the output as expected.

If you are trying to build a whole package this is not the
right script to run: please start by reading the file `INSTALL'.

Report bugs to .
EOF
    exit $?
    ;;
  -v | --v*)
    echo "compile $scriptversion"
    exit $?
    ;;
esac

ofile=
cfile=
eat=

for arg
do
  if test -n "$eat"; then
    eat=
  else
    case $1 in
      -o)
	# configure might choose to run compile as `compile cc -o foo foo.c'.
	# So we strip `-o arg' only if arg is an object.
	eat=1
	case $2 in
	  *.o | *.obj)
	    ofile=$2
	    ;;
	  *)
	    set x "$@" -o "$2"
	    shift
	    ;;
	esac
	;;
      *.c)
	cfile=$1
	set x "$@" "$1"
	shift
	;;
      *)
	set x "$@" "$1"
	shift
	;;
    esac
  fi
  shift
done

if test -z "$ofile" || test -z "$cfile"; then
  # If no `-o' option was seen then we might have been invoked from a
  # pattern rule where we don't need one.  That is ok -- this is a
  # normal compilation that the losing compiler can handle.  If no
  # `.c' file was seen then we are probably linking.  That is also
  # ok.
  exec "$@"
fi

# Name of file we expect compiler to create.
cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'`

# Create the lock directory.
# Note: use `[/.-]' here to ensure that we don't use the same name
# that we are using for the .o file.  Also, base the name on the expected
# object file name, since that is what matters with a parallel build.
lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d
while true; do
  if mkdir "$lockdir" >/dev/null 2>&1; then
    break
  fi
  sleep 1
done
# FIXME: race condition here if user kills between mkdir and trap.
trap "rmdir '$lockdir'; exit 1" 1 2 15

# Run the compile.
"$@"
ret=$?

if test -f "$cofile"; then
  mv "$cofile" "$ofile"
elif test -f "${cofile}bj"; then
  mv "${cofile}bj" "$ofile"
fi

rmdir "$lockdir"
exit $ret

# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:


================================================
FILE: distro/google-perftools-1.7/config.guess
================================================
#! /bin/sh
# Attempt to guess a canonical system name.
#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
#   2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
#   Inc.

timestamp='2007-07-22'

# This file 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 2 of the License, 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., 51 Franklin Street - Fifth Floor, Boston, MA
# 02110-1301, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.


# Originally written by Per Bothner .
# Please send patches to .  Submit a context
# diff and a properly formatted ChangeLog entry.
#
# This script attempts to guess a canonical system name similar to
# config.sub.  If it succeeds, it prints the system name on stdout, and
# exits with 0.  Otherwise, it exits with 1.
#
# The plan is that this can be called by configure scripts if you
# don't specify an explicit build system type.

me=`echo "$0" | sed -e 's,.*/,,'`

usage="\
Usage: $0 [OPTION]

Output the configuration name of the system \`$me' is run on.

Operation modes:
  -h, --help         print this help, then exit
  -t, --time-stamp   print date of last modification, then exit
  -v, --version      print version number, then exit

Report bugs and patches to ."

version="\
GNU config.guess ($timestamp)

Originally written by Per Bothner.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.

This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."

help="
Try \`$me --help' for more information."

# Parse command line
while test $# -gt 0 ; do
  case $1 in
    --time-stamp | --time* | -t )
       echo "$timestamp" ; exit ;;
    --version | -v )
       echo "$version" ; exit ;;
    --help | --h* | -h )
       echo "$usage"; exit ;;
    -- )     # Stop option processing
       shift; break ;;
    - )	# Use stdin as input.
       break ;;
    -* )
       echo "$me: invalid option $1$help" >&2
       exit 1 ;;
    * )
       break ;;
  esac
done

if test $# != 0; then
  echo "$me: too many arguments$help" >&2
  exit 1
fi

trap 'exit 1' 1 2 15

# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
# compiler to aid in system detection is discouraged as it requires
# temporary files to be created and, as you can see below, it is a
# headache to deal with in a portable fashion.

# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
# use `HOST_CC' if defined, but it is deprecated.

# Portable tmp directory creation inspired by the Autoconf team.

set_cc_for_build='
trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
: ${TMPDIR=/tmp} ;
 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
 { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
 { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
 { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
dummy=$tmp/dummy ;
tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
case $CC_FOR_BUILD,$HOST_CC,$CC in
 ,,)    echo "int x;" > $dummy.c ;
	for c in cc gcc c89 c99 ; do
	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
	     CC_FOR_BUILD="$c"; break ;
	  fi ;
	done ;
	if test x"$CC_FOR_BUILD" = x ; then
	  CC_FOR_BUILD=no_compiler_found ;
	fi
	;;
 ,,*)   CC_FOR_BUILD=$CC ;;
 ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
esac ; set_cc_for_build= ;'

# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
# (ghazi@noc.rutgers.edu 1994-08-24)
if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
	PATH=$PATH:/.attbin ; export PATH
fi

UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown

# Note: order is significant - the case branches are not exclusive.

case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
    *:NetBSD:*:*)
	# NetBSD (nbsd) targets should (where applicable) match one or
	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
	# switched to ELF, *-*-netbsd* would select the old
	# object file format.  This provides both forward
	# compatibility and a consistent mechanism for selecting the
	# object file format.
	#
	# Note: NetBSD doesn't particularly care about the vendor
	# portion of the name.  We always set it to "unknown".
	sysctl="sysctl -n hw.machine_arch"
	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
	case "${UNAME_MACHINE_ARCH}" in
	    armeb) machine=armeb-unknown ;;
	    arm*) machine=arm-unknown ;;
	    sh3el) machine=shl-unknown ;;
	    sh3eb) machine=sh-unknown ;;
	    sh5el) machine=sh5le-unknown ;;
	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
	esac
	# The Operating System including object format, if it has switched
	# to ELF recently, or will in the future.
	case "${UNAME_MACHINE_ARCH}" in
	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
		eval $set_cc_for_build
		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
			| grep __ELF__ >/dev/null
		then
		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
		    # Return netbsd for either.  FIX?
		    os=netbsd
		else
		    os=netbsdelf
		fi
		;;
	    *)
	        os=netbsd
		;;
	esac
	# The OS release
	# Debian GNU/NetBSD machines have a different userland, and
	# thus, need a distinct triplet. However, they do not need
	# kernel version information, so it can be replaced with a
	# suitable tag, in the style of linux-gnu.
	case "${UNAME_VERSION}" in
	    Debian*)
		release='-gnu'
		;;
	    *)
		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
		;;
	esac
	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
	# contains redundant information, the shorter form:
	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
	echo "${machine}-${os}${release}"
	exit ;;
    *:OpenBSD:*:*)
	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
	exit ;;
    *:ekkoBSD:*:*)
	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
	exit ;;
    *:SolidBSD:*:*)
	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
	exit ;;
    macppc:MirBSD:*:*)
	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
	exit ;;
    *:MirBSD:*:*)
	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
	exit ;;
    alpha:OSF1:*:*)
	case $UNAME_RELEASE in
	*4.0)
		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
		;;
	*5.*)
	        UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
		;;
	esac
	# According to Compaq, /usr/sbin/psrinfo has been available on
	# OSF/1 and Tru64 systems produced since 1995.  I hope that
	# covers most systems running today.  This code pipes the CPU
	# types through head -n 1, so we only detect the type of CPU 0.
	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
	case "$ALPHA_CPU_TYPE" in
	    "EV4 (21064)")
		UNAME_MACHINE="alpha" ;;
	    "EV4.5 (21064)")
		UNAME_MACHINE="alpha" ;;
	    "LCA4 (21066/21068)")
		UNAME_MACHINE="alpha" ;;
	    "EV5 (21164)")
		UNAME_MACHINE="alphaev5" ;;
	    "EV5.6 (21164A)")
		UNAME_MACHINE="alphaev56" ;;
	    "EV5.6 (21164PC)")
		UNAME_MACHINE="alphapca56" ;;
	    "EV5.7 (21164PC)")
		UNAME_MACHINE="alphapca57" ;;
	    "EV6 (21264)")
		UNAME_MACHINE="alphaev6" ;;
	    "EV6.7 (21264A)")
		UNAME_MACHINE="alphaev67" ;;
	    "EV6.8CB (21264C)")
		UNAME_MACHINE="alphaev68" ;;
	    "EV6.8AL (21264B)")
		UNAME_MACHINE="alphaev68" ;;
	    "EV6.8CX (21264D)")
		UNAME_MACHINE="alphaev68" ;;
	    "EV6.9A (21264/EV69A)")
		UNAME_MACHINE="alphaev69" ;;
	    "EV7 (21364)")
		UNAME_MACHINE="alphaev7" ;;
	    "EV7.9 (21364A)")
		UNAME_MACHINE="alphaev79" ;;
	esac
	# A Pn.n version is a patched version.
	# A Vn.n version is a released version.
	# A Tn.n version is a released field test version.
	# A Xn.n version is an unreleased experimental baselevel.
	# 1.2 uses "1.2" for uname -r.
	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
	exit ;;
    Alpha\ *:Windows_NT*:*)
	# How do we know it's Interix rather than the generic POSIX subsystem?
	# Should we change UNAME_MACHINE based on the output of uname instead
	# of the specific Alpha model?
	echo alpha-pc-interix
	exit ;;
    21064:Windows_NT:50:3)
	echo alpha-dec-winnt3.5
	exit ;;
    Amiga*:UNIX_System_V:4.0:*)
	echo m68k-unknown-sysv4
	exit ;;
    *:[Aa]miga[Oo][Ss]:*:*)
	echo ${UNAME_MACHINE}-unknown-amigaos
	exit ;;
    *:[Mm]orph[Oo][Ss]:*:*)
	echo ${UNAME_MACHINE}-unknown-morphos
	exit ;;
    *:OS/390:*:*)
	echo i370-ibm-openedition
	exit ;;
    *:z/VM:*:*)
	echo s390-ibm-zvmoe
	exit ;;
    *:OS400:*:*)
        echo powerpc-ibm-os400
	exit ;;
    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
	echo arm-acorn-riscix${UNAME_RELEASE}
	exit ;;
    arm:riscos:*:*|arm:RISCOS:*:*)
	echo arm-unknown-riscos
	exit ;;
    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
	echo hppa1.1-hitachi-hiuxmpp
	exit ;;
    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
	if test "`(/bin/universe) 2>/dev/null`" = att ; then
		echo pyramid-pyramid-sysv3
	else
		echo pyramid-pyramid-bsd
	fi
	exit ;;
    NILE*:*:*:dcosx)
	echo pyramid-pyramid-svr4
	exit ;;
    DRS?6000:unix:4.0:6*)
	echo sparc-icl-nx6
	exit ;;
    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
	case `/usr/bin/uname -p` in
	    sparc) echo sparc-icl-nx7; exit ;;
	esac ;;
    sun4H:SunOS:5.*:*)
	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
	echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    sun4*:SunOS:6*:*)
	# According to config.sub, this is the proper way to canonicalize
	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
	# it's likely to be more like Solaris than SunOS4.
	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    sun4*:SunOS:*:*)
	case "`/usr/bin/arch -k`" in
	    Series*|S4*)
		UNAME_RELEASE=`uname -v`
		;;
	esac
	# Japanese Language versions have a version number like `4.1.3-JL'.
	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
	exit ;;
    sun3*:SunOS:*:*)
	echo m68k-sun-sunos${UNAME_RELEASE}
	exit ;;
    sun*:*:4.2BSD:*)
	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
	case "`/bin/arch`" in
	    sun3)
		echo m68k-sun-sunos${UNAME_RELEASE}
		;;
	    sun4)
		echo sparc-sun-sunos${UNAME_RELEASE}
		;;
	esac
	exit ;;
    aushp:SunOS:*:*)
	echo sparc-auspex-sunos${UNAME_RELEASE}
	exit ;;
    # The situation for MiNT is a little confusing.  The machine name
    # can be virtually everything (everything which is not
    # "atarist" or "atariste" at least should have a processor
    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
    # to the lowercase version "mint" (or "freemint").  Finally
    # the system name "TOS" denotes a system which is actually not
    # MiNT.  But MiNT is downward compatible to TOS, so this should
    # be no problem.
    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
        echo m68k-atari-mint${UNAME_RELEASE}
	exit ;;
    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
	echo m68k-atari-mint${UNAME_RELEASE}
        exit ;;
    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
        echo m68k-atari-mint${UNAME_RELEASE}
	exit ;;
    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
        echo m68k-milan-mint${UNAME_RELEASE}
        exit ;;
    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
        echo m68k-hades-mint${UNAME_RELEASE}
        exit ;;
    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
        echo m68k-unknown-mint${UNAME_RELEASE}
        exit ;;
    m68k:machten:*:*)
	echo m68k-apple-machten${UNAME_RELEASE}
	exit ;;
    powerpc:machten:*:*)
	echo powerpc-apple-machten${UNAME_RELEASE}
	exit ;;
    RISC*:Mach:*:*)
	echo mips-dec-mach_bsd4.3
	exit ;;
    RISC*:ULTRIX:*:*)
	echo mips-dec-ultrix${UNAME_RELEASE}
	exit ;;
    VAX*:ULTRIX*:*:*)
	echo vax-dec-ultrix${UNAME_RELEASE}
	exit ;;
    2020:CLIX:*:* | 2430:CLIX:*:*)
	echo clipper-intergraph-clix${UNAME_RELEASE}
	exit ;;
    mips:*:*:UMIPS | mips:*:*:RISCos)
	eval $set_cc_for_build
	sed 's/^	//' << EOF >$dummy.c
#ifdef __cplusplus
#include   /* for printf() prototype */
	int main (int argc, char *argv[]) {
#else
	int main (argc, argv) int argc; char *argv[]; {
#endif
	#if defined (host_mips) && defined (MIPSEB)
	#if defined (SYSTYPE_SYSV)
	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
	#endif
	#if defined (SYSTYPE_SVR4)
	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
	#endif
	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
	#endif
	#endif
	  exit (-1);
	}
EOF
	$CC_FOR_BUILD -o $dummy $dummy.c &&
	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
	  SYSTEM_NAME=`$dummy $dummyarg` &&
	    { echo "$SYSTEM_NAME"; exit; }
	echo mips-mips-riscos${UNAME_RELEASE}
	exit ;;
    Motorola:PowerMAX_OS:*:*)
	echo powerpc-motorola-powermax
	exit ;;
    Motorola:*:4.3:PL8-*)
	echo powerpc-harris-powermax
	exit ;;
    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
	echo powerpc-harris-powermax
	exit ;;
    Night_Hawk:Power_UNIX:*:*)
	echo powerpc-harris-powerunix
	exit ;;
    m88k:CX/UX:7*:*)
	echo m88k-harris-cxux7
	exit ;;
    m88k:*:4*:R4*)
	echo m88k-motorola-sysv4
	exit ;;
    m88k:*:3*:R3*)
	echo m88k-motorola-sysv3
	exit ;;
    AViiON:dgux:*:*)
        # DG/UX returns AViiON for all architectures
        UNAME_PROCESSOR=`/usr/bin/uname -p`
	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
	then
	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
	       [ ${TARGET_BINARY_INTERFACE}x = x ]
	    then
		echo m88k-dg-dgux${UNAME_RELEASE}
	    else
		echo m88k-dg-dguxbcs${UNAME_RELEASE}
	    fi
	else
	    echo i586-dg-dgux${UNAME_RELEASE}
	fi
 	exit ;;
    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
	echo m88k-dolphin-sysv3
	exit ;;
    M88*:*:R3*:*)
	# Delta 88k system running SVR3
	echo m88k-motorola-sysv3
	exit ;;
    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
	echo m88k-tektronix-sysv3
	exit ;;
    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
	echo m68k-tektronix-bsd
	exit ;;
    *:IRIX*:*:*)
	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
	exit ;;
    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
    i*86:AIX:*:*)
	echo i386-ibm-aix
	exit ;;
    ia64:AIX:*:*)
	if [ -x /usr/bin/oslevel ] ; then
		IBM_REV=`/usr/bin/oslevel`
	else
		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
	fi
	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
	exit ;;
    *:AIX:2:3)
	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
		eval $set_cc_for_build
		sed 's/^		//' << EOF >$dummy.c
		#include 

		main()
			{
			if (!__power_pc())
				exit(1);
			puts("powerpc-ibm-aix3.2.5");
			exit(0);
			}
EOF
		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
		then
			echo "$SYSTEM_NAME"
		else
			echo rs6000-ibm-aix3.2.5
		fi
	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
		echo rs6000-ibm-aix3.2.4
	else
		echo rs6000-ibm-aix3.2
	fi
	exit ;;
    *:AIX:*:[45])
	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
		IBM_ARCH=rs6000
	else
		IBM_ARCH=powerpc
	fi
	if [ -x /usr/bin/oslevel ] ; then
		IBM_REV=`/usr/bin/oslevel`
	else
		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
	fi
	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
	exit ;;
    *:AIX:*:*)
	echo rs6000-ibm-aix
	exit ;;
    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
	echo romp-ibm-bsd4.4
	exit ;;
    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
	exit ;;                             # report: romp-ibm BSD 4.3
    *:BOSX:*:*)
	echo rs6000-bull-bosx
	exit ;;
    DPX/2?00:B.O.S.:*:*)
	echo m68k-bull-sysv3
	exit ;;
    9000/[34]??:4.3bsd:1.*:*)
	echo m68k-hp-bsd
	exit ;;
    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
	echo m68k-hp-bsd4.4
	exit ;;
    9000/[34678]??:HP-UX:*:*)
	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
	case "${UNAME_MACHINE}" in
	    9000/31? )            HP_ARCH=m68000 ;;
	    9000/[34]?? )         HP_ARCH=m68k ;;
	    9000/[678][0-9][0-9])
		if [ -x /usr/bin/getconf ]; then
		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
                    case "${sc_cpu_version}" in
                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
                      532)                      # CPU_PA_RISC2_0
                        case "${sc_kernel_bits}" in
                          32) HP_ARCH="hppa2.0n" ;;
                          64) HP_ARCH="hppa2.0w" ;;
			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
                        esac ;;
                    esac
		fi
		if [ "${HP_ARCH}" = "" ]; then
		    eval $set_cc_for_build
		    sed 's/^              //' << EOF >$dummy.c

              #define _HPUX_SOURCE
              #include 
              #include 

              int main ()
              {
              #if defined(_SC_KERNEL_BITS)
                  long bits = sysconf(_SC_KERNEL_BITS);
              #endif
                  long cpu  = sysconf (_SC_CPU_VERSION);

                  switch (cpu)
              	{
              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
              	case CPU_PA_RISC2_0:
              #if defined(_SC_KERNEL_BITS)
              	    switch (bits)
              		{
              		case 64: puts ("hppa2.0w"); break;
              		case 32: puts ("hppa2.0n"); break;
              		default: puts ("hppa2.0"); break;
              		} break;
              #else  /* !defined(_SC_KERNEL_BITS) */
              	    puts ("hppa2.0"); break;
              #endif
              	default: puts ("hppa1.0"); break;
              	}
                  exit (0);
              }
EOF
		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
		    test -z "$HP_ARCH" && HP_ARCH=hppa
		fi ;;
	esac
	if [ ${HP_ARCH} = "hppa2.0w" ]
	then
	    eval $set_cc_for_build

	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
	    # generating 64-bit code.  GNU and HP use different nomenclature:
	    #
	    # $ CC_FOR_BUILD=cc ./config.guess
	    # => hppa2.0w-hp-hpux11.23
	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
	    # => hppa64-hp-hpux11.23

	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
		grep __LP64__ >/dev/null
	    then
		HP_ARCH="hppa2.0w"
	    else
		HP_ARCH="hppa64"
	    fi
	fi
	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
	exit ;;
    ia64:HP-UX:*:*)
	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
	echo ia64-hp-hpux${HPUX_REV}
	exit ;;
    3050*:HI-UX:*:*)
	eval $set_cc_for_build
	sed 's/^	//' << EOF >$dummy.c
	#include 
	int
	main ()
	{
	  long cpu = sysconf (_SC_CPU_VERSION);
	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
	     results, however.  */
	  if (CPU_IS_PA_RISC (cpu))
	    {
	      switch (cpu)
		{
		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
		  default: puts ("hppa-hitachi-hiuxwe2"); break;
		}
	    }
	  else if (CPU_IS_HP_MC68K (cpu))
	    puts ("m68k-hitachi-hiuxwe2");
	  else puts ("unknown-hitachi-hiuxwe2");
	  exit (0);
	}
EOF
	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
		{ echo "$SYSTEM_NAME"; exit; }
	echo unknown-hitachi-hiuxwe2
	exit ;;
    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
	echo hppa1.1-hp-bsd
	exit ;;
    9000/8??:4.3bsd:*:*)
	echo hppa1.0-hp-bsd
	exit ;;
    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
	echo hppa1.0-hp-mpeix
	exit ;;
    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
	echo hppa1.1-hp-osf
	exit ;;
    hp8??:OSF1:*:*)
	echo hppa1.0-hp-osf
	exit ;;
    i*86:OSF1:*:*)
	if [ -x /usr/sbin/sysversion ] ; then
	    echo ${UNAME_MACHINE}-unknown-osf1mk
	else
	    echo ${UNAME_MACHINE}-unknown-osf1
	fi
	exit ;;
    parisc*:Lites*:*:*)
	echo hppa1.1-hp-lites
	exit ;;
    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
	echo c1-convex-bsd
        exit ;;
    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
	if getsysinfo -f scalar_acc
	then echo c32-convex-bsd
	else echo c2-convex-bsd
	fi
        exit ;;
    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
	echo c34-convex-bsd
        exit ;;
    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
	echo c38-convex-bsd
        exit ;;
    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
	echo c4-convex-bsd
        exit ;;
    CRAY*Y-MP:*:*:*)
	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    CRAY*[A-Z]90:*:*:*)
	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
	      -e 's/\.[^.]*$/.X/'
	exit ;;
    CRAY*TS:*:*:*)
	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    CRAY*T3E:*:*:*)
	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    CRAY*SV1:*:*:*)
	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    *:UNICOS/mp:*:*)
	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
        exit ;;
    5000:UNIX_System_V:4.*:*)
        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
        FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
	exit ;;
    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
	exit ;;
    sparc*:BSD/OS:*:*)
	echo sparc-unknown-bsdi${UNAME_RELEASE}
	exit ;;
    *:BSD/OS:*:*)
	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
	exit ;;
    *:FreeBSD:*:*)
	case ${UNAME_MACHINE} in
	    pc98)
		echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
	    amd64)
		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
	    *)
		echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
	esac
	exit ;;
    i*:CYGWIN*:*)
	echo ${UNAME_MACHINE}-pc-cygwin
	exit ;;
    *:MINGW*:*)
	echo ${UNAME_MACHINE}-pc-mingw32
	exit ;;
    i*:windows32*:*)
    	# uname -m includes "-pc" on this system.
    	echo ${UNAME_MACHINE}-mingw32
	exit ;;
    i*:PW*:*)
	echo ${UNAME_MACHINE}-pc-pw32
	exit ;;
    *:Interix*:[3456]*)
    	case ${UNAME_MACHINE} in
	    x86)
		echo i586-pc-interix${UNAME_RELEASE}
		exit ;;
	    EM64T | authenticamd)
		echo x86_64-unknown-interix${UNAME_RELEASE}
		exit ;;
	esac ;;
    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
	echo i${UNAME_MACHINE}-pc-mks
	exit ;;
    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
	# How do we know it's Interix rather than the generic POSIX subsystem?
	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
	# UNAME_MACHINE based on the output of uname instead of i386?
	echo i586-pc-interix
	exit ;;
    i*:UWIN*:*)
	echo ${UNAME_MACHINE}-pc-uwin
	exit ;;
    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
	echo x86_64-unknown-cygwin
	exit ;;
    p*:CYGWIN*:*)
	echo powerpcle-unknown-cygwin
	exit ;;
    prep*:SunOS:5.*:*)
	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    *:GNU:*:*)
	# the GNU system
	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
	exit ;;
    *:GNU/*:*:*)
	# other systems with GNU libc and userland
	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
	exit ;;
    i*86:Minix:*:*)
	echo ${UNAME_MACHINE}-pc-minix
	exit ;;
    arm*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-gnu
	exit ;;
    avr32*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-gnu
	exit ;;
    cris:Linux:*:*)
	echo cris-axis-linux-gnu
	exit ;;
    crisv32:Linux:*:*)
	echo crisv32-axis-linux-gnu
	exit ;;
    frv:Linux:*:*)
    	echo frv-unknown-linux-gnu
	exit ;;
    ia64:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-gnu
	exit ;;
    m32r*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-gnu
	exit ;;
    m68*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-gnu
	exit ;;
    mips:Linux:*:*)
	eval $set_cc_for_build
	sed 's/^	//' << EOF >$dummy.c
	#undef CPU
	#undef mips
	#undef mipsel
	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
	CPU=mipsel
	#else
	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
	CPU=mips
	#else
	CPU=
	#endif
	#endif
EOF
	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
	    /^CPU/{
		s: ::g
		p
	    }'`"
	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
	;;
    mips64:Linux:*:*)
	eval $set_cc_for_build
	sed 's/^	//' << EOF >$dummy.c
	#undef CPU
	#undef mips64
	#undef mips64el
	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
	CPU=mips64el
	#else
	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
	CPU=mips64
	#else
	CPU=
	#endif
	#endif
EOF
	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
	    /^CPU/{
		s: ::g
		p
	    }'`"
	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
	;;
    or32:Linux:*:*)
	echo or32-unknown-linux-gnu
	exit ;;
    ppc:Linux:*:*)
	echo powerpc-unknown-linux-gnu
	exit ;;
    ppc64:Linux:*:*)
	echo powerpc64-unknown-linux-gnu
	exit ;;
    alpha:Linux:*:*)
	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
	  EV5)   UNAME_MACHINE=alphaev5 ;;
	  EV56)  UNAME_MACHINE=alphaev56 ;;
	  PCA56) UNAME_MACHINE=alphapca56 ;;
	  PCA57) UNAME_MACHINE=alphapca56 ;;
	  EV6)   UNAME_MACHINE=alphaev6 ;;
	  EV67)  UNAME_MACHINE=alphaev67 ;;
	  EV68*) UNAME_MACHINE=alphaev68 ;;
        esac
	objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
	exit ;;
    parisc:Linux:*:* | hppa:Linux:*:*)
	# Look for CPU level
	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
	  *)    echo hppa-unknown-linux-gnu ;;
	esac
	exit ;;
    parisc64:Linux:*:* | hppa64:Linux:*:*)
	echo hppa64-unknown-linux-gnu
	exit ;;
    s390:Linux:*:* | s390x:Linux:*:*)
	echo ${UNAME_MACHINE}-ibm-linux
	exit ;;
    sh64*:Linux:*:*)
    	echo ${UNAME_MACHINE}-unknown-linux-gnu
	exit ;;
    sh*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-gnu
	exit ;;
    sparc:Linux:*:* | sparc64:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-gnu
	exit ;;
    vax:Linux:*:*)
	echo ${UNAME_MACHINE}-dec-linux-gnu
	exit ;;
    x86_64:Linux:*:*)
	echo x86_64-unknown-linux-gnu
	exit ;;
    xtensa:Linux:*:*)
    	echo xtensa-unknown-linux-gnu
	exit ;;
    i*86:Linux:*:*)
	# The BFD linker knows what the default object file format is, so
	# first see if it will tell us. cd to the root directory to prevent
	# problems with other programs or directories called `ld' in the path.
	# Set LC_ALL=C to ensure ld outputs messages in English.
	ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
			 | sed -ne '/supported targets:/!d
				    s/[ 	][ 	]*/ /g
				    s/.*supported targets: *//
				    s/ .*//
				    p'`
        case "$ld_supported_targets" in
	  elf32-i386)
		TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
		;;
	  a.out-i386-linux)
		echo "${UNAME_MACHINE}-pc-linux-gnuaout"
		exit ;;
	  coff-i386)
		echo "${UNAME_MACHINE}-pc-linux-gnucoff"
		exit ;;
	  "")
		# Either a pre-BFD a.out linker (linux-gnuoldld) or
		# one that does not give us useful --help.
		echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
		exit ;;
	esac
	# Determine whether the default compiler is a.out or elf
	eval $set_cc_for_build
	sed 's/^	//' << EOF >$dummy.c
	#include 
	#ifdef __ELF__
	# ifdef __GLIBC__
	#  if __GLIBC__ >= 2
	LIBC=gnu
	#  else
	LIBC=gnulibc1
	#  endif
	# else
	LIBC=gnulibc1
	# endif
	#else
	#if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
	LIBC=gnu
	#else
	LIBC=gnuaout
	#endif
	#endif
	#ifdef __dietlibc__
	LIBC=dietlibc
	#endif
EOF
	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
	    /^LIBC/{
		s: ::g
		p
	    }'`"
	test x"${LIBC}" != x && {
		echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
		exit
	}
	test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
	;;
    i*86:DYNIX/ptx:4*:*)
	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
	# earlier versions are messed up and put the nodename in both
	# sysname and nodename.
	echo i386-sequent-sysv4
	exit ;;
    i*86:UNIX_SV:4.2MP:2.*)
        # Unixware is an offshoot of SVR4, but it has its own version
        # number series starting with 2...
        # I am not positive that other SVR4 systems won't match this,
	# I just have to hope.  -- rms.
        # Use sysv4.2uw... so that sysv4* matches it.
	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
	exit ;;
    i*86:OS/2:*:*)
	# If we were able to find `uname', then EMX Unix compatibility
	# is probably installed.
	echo ${UNAME_MACHINE}-pc-os2-emx
	exit ;;
    i*86:XTS-300:*:STOP)
	echo ${UNAME_MACHINE}-unknown-stop
	exit ;;
    i*86:atheos:*:*)
	echo ${UNAME_MACHINE}-unknown-atheos
	exit ;;
    i*86:syllable:*:*)
	echo ${UNAME_MACHINE}-pc-syllable
	exit ;;
    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
	echo i386-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    i*86:*DOS:*:*)
	echo ${UNAME_MACHINE}-pc-msdosdjgpp
	exit ;;
    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
	else
		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
	fi
	exit ;;
    i*86:*:5:[678]*)
    	# UnixWare 7.x, OpenUNIX and OpenServer 6.
	case `/bin/uname -X | grep "^Machine"` in
	    *486*)	     UNAME_MACHINE=i486 ;;
	    *Pentium)	     UNAME_MACHINE=i586 ;;
	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
	esac
	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
	exit ;;
    i*86:*:3.2:*)
	if test -f /usr/options/cb.name; then
		UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then
		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
			&& UNAME_MACHINE=i586
		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
			&& UNAME_MACHINE=i686
		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
			&& UNAME_MACHINE=i686
		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
	else
		echo ${UNAME_MACHINE}-pc-sysv32
	fi
	exit ;;
    pc:*:*:*)
	# Left here for compatibility:
        # uname -m prints for DJGPP always 'pc', but it prints nothing about
        # the processor, so we play safe by assuming i386.
	echo i386-pc-msdosdjgpp
        exit ;;
    Intel:Mach:3*:*)
	echo i386-pc-mach3
	exit ;;
    paragon:*:*:*)
	echo i860-intel-osf1
	exit ;;
    i860:*:4.*:*) # i860-SVR4
	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
	else # Add other i860-SVR4 vendors below as they are discovered.
	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
	fi
	exit ;;
    mini*:CTIX:SYS*5:*)
	# "miniframe"
	echo m68010-convergent-sysv
	exit ;;
    mc68k:UNIX:SYSTEM5:3.51m)
	echo m68k-convergent-sysv
	exit ;;
    M680?0:D-NIX:5.3:*)
	echo m68k-diab-dnix
	exit ;;
    M68*:*:R3V[5678]*:*)
	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
	OS_REL=''
	test -r /etc/.relid \
	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
          && { echo i486-ncr-sysv4; exit; } ;;
    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
	echo m68k-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    mc68030:UNIX_System_V:4.*:*)
	echo m68k-atari-sysv4
	exit ;;
    TSUNAMI:LynxOS:2.*:*)
	echo sparc-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    rs6000:LynxOS:2.*:*)
	echo rs6000-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
	echo powerpc-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    SM[BE]S:UNIX_SV:*:*)
	echo mips-dde-sysv${UNAME_RELEASE}
	exit ;;
    RM*:ReliantUNIX-*:*:*)
	echo mips-sni-sysv4
	exit ;;
    RM*:SINIX-*:*:*)
	echo mips-sni-sysv4
	exit ;;
    *:SINIX-*:*:*)
	if uname -p 2>/dev/null >/dev/null ; then
		UNAME_MACHINE=`(uname -p) 2>/dev/null`
		echo ${UNAME_MACHINE}-sni-sysv4
	else
		echo ns32k-sni-sysv
	fi
	exit ;;
    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
                      # says 
        echo i586-unisys-sysv4
        exit ;;
    *:UNIX_System_V:4*:FTX*)
	# From Gerald Hewes .
	# How about differentiating between stratus architectures? -djm
	echo hppa1.1-stratus-sysv4
	exit ;;
    *:*:*:FTX*)
	# From seanf@swdc.stratus.com.
	echo i860-stratus-sysv4
	exit ;;
    i*86:VOS:*:*)
	# From Paul.Green@stratus.com.
	echo ${UNAME_MACHINE}-stratus-vos
	exit ;;
    *:VOS:*:*)
	# From Paul.Green@stratus.com.
	echo hppa1.1-stratus-vos
	exit ;;
    mc68*:A/UX:*:*)
	echo m68k-apple-aux${UNAME_RELEASE}
	exit ;;
    news*:NEWS-OS:6*:*)
	echo mips-sony-newsos6
	exit ;;
    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
	if [ -d /usr/nec ]; then
	        echo mips-nec-sysv${UNAME_RELEASE}
	else
	        echo mips-unknown-sysv${UNAME_RELEASE}
	fi
        exit ;;
    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
	echo powerpc-be-beos
	exit ;;
    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
	echo powerpc-apple-beos
	exit ;;
    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
	echo i586-pc-beos
	exit ;;
    SX-4:SUPER-UX:*:*)
	echo sx4-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-5:SUPER-UX:*:*)
	echo sx5-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-6:SUPER-UX:*:*)
	echo sx6-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-7:SUPER-UX:*:*)
	echo sx7-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-8:SUPER-UX:*:*)
	echo sx8-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-8R:SUPER-UX:*:*)
	echo sx8r-nec-superux${UNAME_RELEASE}
	exit ;;
    Power*:Rhapsody:*:*)
	echo powerpc-apple-rhapsody${UNAME_RELEASE}
	exit ;;
    *:Rhapsody:*:*)
	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
	exit ;;
    *:Darwin:*:*)
	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
	case $UNAME_PROCESSOR in
	    unknown) UNAME_PROCESSOR=powerpc ;;
	esac
	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
	exit ;;
    *:procnto*:*:* | *:QNX:[0123456789]*:*)
	UNAME_PROCESSOR=`uname -p`
	if test "$UNAME_PROCESSOR" = "x86"; then
		UNAME_PROCESSOR=i386
		UNAME_MACHINE=pc
	fi
	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
	exit ;;
    *:QNX:*:4*)
	echo i386-pc-qnx
	exit ;;
    NSE-?:NONSTOP_KERNEL:*:*)
	echo nse-tandem-nsk${UNAME_RELEASE}
	exit ;;
    NSR-?:NONSTOP_KERNEL:*:*)
	echo nsr-tandem-nsk${UNAME_RELEASE}
	exit ;;
    *:NonStop-UX:*:*)
	echo mips-compaq-nonstopux
	exit ;;
    BS2000:POSIX*:*:*)
	echo bs2000-siemens-sysv
	exit ;;
    DS/*:UNIX_System_V:*:*)
	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
	exit ;;
    *:Plan9:*:*)
	# "uname -m" is not consistent, so use $cputype instead. 386
	# is converted to i386 for consistency with other x86
	# operating systems.
	if test "$cputype" = "386"; then
	    UNAME_MACHINE=i386
	else
	    UNAME_MACHINE="$cputype"
	fi
	echo ${UNAME_MACHINE}-unknown-plan9
	exit ;;
    *:TOPS-10:*:*)
	echo pdp10-unknown-tops10
	exit ;;
    *:TENEX:*:*)
	echo pdp10-unknown-tenex
	exit ;;
    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
	echo pdp10-dec-tops20
	exit ;;
    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
	echo pdp10-xkl-tops20
	exit ;;
    *:TOPS-20:*:*)
	echo pdp10-unknown-tops20
	exit ;;
    *:ITS:*:*)
	echo pdp10-unknown-its
	exit ;;
    SEI:*:*:SEIUX)
        echo mips-sei-seiux${UNAME_RELEASE}
	exit ;;
    *:DragonFly:*:*)
	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
	exit ;;
    *:*VMS:*:*)
    	UNAME_MACHINE=`(uname -p) 2>/dev/null`
	case "${UNAME_MACHINE}" in
	    A*) echo alpha-dec-vms ; exit ;;
	    I*) echo ia64-dec-vms ; exit ;;
	    V*) echo vax-dec-vms ; exit ;;
	esac ;;
    *:XENIX:*:SysV)
	echo i386-pc-xenix
	exit ;;
    i*86:skyos:*:*)
	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
	exit ;;
    i*86:rdos:*:*)
	echo ${UNAME_MACHINE}-pc-rdos
	exit ;;
esac

#echo '(No uname command or uname output not recognized.)' 1>&2
#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2

eval $set_cc_for_build
cat >$dummy.c <
# include 
#endif
main ()
{
#if defined (sony)
#if defined (MIPSEB)
  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
     I don't know....  */
  printf ("mips-sony-bsd\n"); exit (0);
#else
#include 
  printf ("m68k-sony-newsos%s\n",
#ifdef NEWSOS4
          "4"
#else
	  ""
#endif
         ); exit (0);
#endif
#endif

#if defined (__arm) && defined (__acorn) && defined (__unix)
  printf ("arm-acorn-riscix\n"); exit (0);
#endif

#if defined (hp300) && !defined (hpux)
  printf ("m68k-hp-bsd\n"); exit (0);
#endif

#if defined (NeXT)
#if !defined (__ARCHITECTURE__)
#define __ARCHITECTURE__ "m68k"
#endif
  int version;
  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
  if (version < 4)
    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
  else
    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
  exit (0);
#endif

#if defined (MULTIMAX) || defined (n16)
#if defined (UMAXV)
  printf ("ns32k-encore-sysv\n"); exit (0);
#else
#if defined (CMU)
  printf ("ns32k-encore-mach\n"); exit (0);
#else
  printf ("ns32k-encore-bsd\n"); exit (0);
#endif
#endif
#endif

#if defined (__386BSD__)
  printf ("i386-pc-bsd\n"); exit (0);
#endif

#if defined (sequent)
#if defined (i386)
  printf ("i386-sequent-dynix\n"); exit (0);
#endif
#if defined (ns32000)
  printf ("ns32k-sequent-dynix\n"); exit (0);
#endif
#endif

#if defined (_SEQUENT_)
    struct utsname un;

    uname(&un);

    if (strncmp(un.version, "V2", 2) == 0) {
	printf ("i386-sequent-ptx2\n"); exit (0);
    }
    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
	printf ("i386-sequent-ptx1\n"); exit (0);
    }
    printf ("i386-sequent-ptx\n"); exit (0);

#endif

#if defined (vax)
# if !defined (ultrix)
#  include 
#  if defined (BSD)
#   if BSD == 43
      printf ("vax-dec-bsd4.3\n"); exit (0);
#   else
#    if BSD == 199006
      printf ("vax-dec-bsd4.3reno\n"); exit (0);
#    else
      printf ("vax-dec-bsd\n"); exit (0);
#    endif
#   endif
#  else
    printf ("vax-dec-bsd\n"); exit (0);
#  endif
# else
    printf ("vax-dec-ultrix\n"); exit (0);
# endif
#endif

#if defined (alliant) && defined (i860)
  printf ("i860-alliant-bsd\n"); exit (0);
#endif

  exit (1);
}
EOF

$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
	{ echo "$SYSTEM_NAME"; exit; }

# Apollos put the system type in the environment.

test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }

# Convex versions that predate uname can use getsysinfo(1)

if [ -x /usr/convex/getsysinfo ]
then
    case `getsysinfo -f cpu_type` in
    c1*)
	echo c1-convex-bsd
	exit ;;
    c2*)
	if getsysinfo -f scalar_acc
	then echo c32-convex-bsd
	else echo c2-convex-bsd
	fi
	exit ;;
    c34*)
	echo c34-convex-bsd
	exit ;;
    c38*)
	echo c38-convex-bsd
	exit ;;
    c4*)
	echo c4-convex-bsd
	exit ;;
    esac
fi

cat >&2 < in order to provide the needed
information to handle your system.

config.guess timestamp = $timestamp

uname -m = `(uname -m) 2>/dev/null || echo unknown`
uname -r = `(uname -r) 2>/dev/null || echo unknown`
uname -s = `(uname -s) 2>/dev/null || echo unknown`
uname -v = `(uname -v) 2>/dev/null || echo unknown`

/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`

hostinfo               = `(hostinfo) 2>/dev/null`
/bin/universe          = `(/bin/universe) 2>/dev/null`
/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
/bin/arch              = `(/bin/arch) 2>/dev/null`
/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`

UNAME_MACHINE = ${UNAME_MACHINE}
UNAME_RELEASE = ${UNAME_RELEASE}
UNAME_SYSTEM  = ${UNAME_SYSTEM}
UNAME_VERSION = ${UNAME_VERSION}
EOF

exit 1

# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "timestamp='"
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
# End:


================================================
FILE: distro/google-perftools-1.7/config.sub
================================================
#! /bin/sh
# Configuration validation subroutine script.
#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
#   2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
#   Inc.

timestamp='2007-06-28'

# This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software
# can handle that machine.  It does not imply ALL GNU software can.
#
# This file 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 2 of the License, 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., 51 Franklin Street - Fifth Floor, Boston, MA
# 02110-1301, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.


# Please send patches to .  Submit a context
# diff and a properly formatted ChangeLog entry.
#
# Configuration subroutine to validate and canonicalize a configuration type.
# Supply the specified configuration type as an argument.
# If it is invalid, we print an error message on stderr and exit with code 1.
# Otherwise, we print the canonical config type on stdout and succeed.

# This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases
# that are meaningful with *any* GNU software.
# Each package is responsible for reporting which valid configurations
# it does not support.  The user should be able to distinguish
# a failure to support a valid configuration from a meaningless
# configuration.

# The goal of this file is to map all the various variations of a given
# machine specification into a single specification in the form:
#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
# or in some cases, the newer four-part form:
#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
# It is wrong to echo any other type of specification.

me=`echo "$0" | sed -e 's,.*/,,'`

usage="\
Usage: $0 [OPTION] CPU-MFR-OPSYS
       $0 [OPTION] ALIAS

Canonicalize a configuration name.

Operation modes:
  -h, --help         print this help, then exit
  -t, --time-stamp   print date of last modification, then exit
  -v, --version      print version number, then exit

Report bugs and patches to ."

version="\
GNU config.sub ($timestamp)

Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.

This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."

help="
Try \`$me --help' for more information."

# Parse command line
while test $# -gt 0 ; do
  case $1 in
    --time-stamp | --time* | -t )
       echo "$timestamp" ; exit ;;
    --version | -v )
       echo "$version" ; exit ;;
    --help | --h* | -h )
       echo "$usage"; exit ;;
    -- )     # Stop option processing
       shift; break ;;
    - )	# Use stdin as input.
       break ;;
    -* )
       echo "$me: invalid option $1$help"
       exit 1 ;;

    *local*)
       # First pass through any local machine types.
       echo $1
       exit ;;

    * )
       break ;;
  esac
done

case $# in
 0) echo "$me: missing argument$help" >&2
    exit 1;;
 1) ;;
 *) echo "$me: too many arguments$help" >&2
    exit 1;;
esac

# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
  nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
  uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
  storm-chaos* | os2-emx* | rtmk-nova*)
    os=-$maybe_os
    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
    ;;
  *)
    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
    if [ $basic_machine != $1 ]
    then os=`echo $1 | sed 's/.*-/-/'`
    else os=; fi
    ;;
esac

### Let's recognize common machines as not being operating systems so
### that things like config.sub decstation-3100 work.  We also
### recognize some manufacturers as not being operating systems, so we
### can provide default operating systems below.
case $os in
	-sun*os*)
		# Prevent following clause from handling this invalid input.
		;;
	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
	-apple | -axis | -knuth | -cray)
		os=
		basic_machine=$1
		;;
	-sim | -cisco | -oki | -wec | -winbond)
		os=
		basic_machine=$1
		;;
	-scout)
		;;
	-wrs)
		os=-vxworks
		basic_machine=$1
		;;
	-chorusos*)
		os=-chorusos
		basic_machine=$1
		;;
 	-chorusrdb)
 		os=-chorusrdb
		basic_machine=$1
 		;;
	-hiux*)
		os=-hiuxwe2
		;;
	-sco6)
		os=-sco5v6
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco5)
		os=-sco3.2v5
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco4)
		os=-sco3.2v4
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco3.2.[4-9]*)
		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco3.2v[4-9]*)
		# Don't forget version if it is 3.2v4 or newer.
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco5v6*)
		# Don't forget version if it is 3.2v4 or newer.
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco*)
		os=-sco3.2v2
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-udk*)
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-isc)
		os=-isc2.2
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-clix*)
		basic_machine=clipper-intergraph
		;;
	-isc*)
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-lynx*)
		os=-lynxos
		;;
	-ptx*)
		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
		;;
	-windowsnt*)
		os=`echo $os | sed -e 's/windowsnt/winnt/'`
		;;
	-psos*)
		os=-psos
		;;
	-mint | -mint[0-9]*)
		basic_machine=m68k-atari
		os=-mint
		;;
esac

# Decode aliases for certain CPU-COMPANY combinations.
case $basic_machine in
	# Recognize the basic CPU types without company name.
	# Some are omitted here because they have special meanings below.
	1750a | 580 \
	| a29k \
	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
	| am33_2.0 \
	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
	| bfin \
	| c4x | clipper \
	| d10v | d30v | dlx | dsp16xx \
	| fido | fr30 | frv \
	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
	| i370 | i860 | i960 | ia64 \
	| ip2k | iq2000 \
	| m32c | m32r | m32rle | m68000 | m68k | m88k \
	| maxq | mb | microblaze | mcore | mep \
	| mips | mipsbe | mipseb | mipsel | mipsle \
	| mips16 \
	| mips64 | mips64el \
	| mips64vr | mips64vrel \
	| mips64orion | mips64orionel \
	| mips64vr4100 | mips64vr4100el \
	| mips64vr4300 | mips64vr4300el \
	| mips64vr5000 | mips64vr5000el \
	| mips64vr5900 | mips64vr5900el \
	| mipsisa32 | mipsisa32el \
	| mipsisa32r2 | mipsisa32r2el \
	| mipsisa64 | mipsisa64el \
	| mipsisa64r2 | mipsisa64r2el \
	| mipsisa64sb1 | mipsisa64sb1el \
	| mipsisa64sr71k | mipsisa64sr71kel \
	| mipstx39 | mipstx39el \
	| mn10200 | mn10300 \
	| mt \
	| msp430 \
	| nios | nios2 \
	| ns16k | ns32k \
	| or32 \
	| pdp10 | pdp11 | pj | pjl \
	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
	| pyramid \
	| score \
	| sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
	| sh64 | sh64le \
	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
	| spu | strongarm \
	| tahoe | thumb | tic4x | tic80 | tron \
	| v850 | v850e \
	| we32k \
	| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
	| z8k)
		basic_machine=$basic_machine-unknown
		;;
	m6811 | m68hc11 | m6812 | m68hc12)
		# Motorola 68HC11/12.
		basic_machine=$basic_machine-unknown
		os=-none
		;;
	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
		;;
	ms1)
		basic_machine=mt-unknown
		;;

	# We use `pc' rather than `unknown'
	# because (1) that's what they normally are, and
	# (2) the word "unknown" tends to confuse beginning users.
	i*86 | x86_64)
	  basic_machine=$basic_machine-pc
	  ;;
	# Object if more than one company name word.
	*-*-*)
		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
		exit 1
		;;
	# Recognize the basic CPU types with company name.
	580-* \
	| a29k-* \
	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
	| avr-* | avr32-* \
	| bfin-* | bs2000-* \
	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
	| clipper-* | craynv-* | cydra-* \
	| d10v-* | d30v-* | dlx-* \
	| elxsi-* \
	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
	| h8300-* | h8500-* \
	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
	| i*86-* | i860-* | i960-* | ia64-* \
	| ip2k-* | iq2000-* \
	| m32c-* | m32r-* | m32rle-* \
	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
	| m88110-* | m88k-* | maxq-* | mcore-* \
	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
	| mips16-* \
	| mips64-* | mips64el-* \
	| mips64vr-* | mips64vrel-* \
	| mips64orion-* | mips64orionel-* \
	| mips64vr4100-* | mips64vr4100el-* \
	| mips64vr4300-* | mips64vr4300el-* \
	| mips64vr5000-* | mips64vr5000el-* \
	| mips64vr5900-* | mips64vr5900el-* \
	| mipsisa32-* | mipsisa32el-* \
	| mipsisa32r2-* | mipsisa32r2el-* \
	| mipsisa64-* | mipsisa64el-* \
	| mipsisa64r2-* | mipsisa64r2el-* \
	| mipsisa64sb1-* | mipsisa64sb1el-* \
	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
	| mipstx39-* | mipstx39el-* \
	| mmix-* \
	| mt-* \
	| msp430-* \
	| nios-* | nios2-* \
	| none-* | np1-* | ns16k-* | ns32k-* \
	| orion-* \
	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
	| pyramid-* \
	| romp-* | rs6000-* \
	| sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
	| sparclite-* \
	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
	| tahoe-* | thumb-* \
	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
	| tron-* \
	| v850-* | v850e-* | vax-* \
	| we32k-* \
	| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
	| xstormy16-* | xtensa-* \
	| ymp-* \
	| z8k-*)
		;;
	# Recognize the various machine names and aliases which stand
	# for a CPU type and a company and sometimes even an OS.
	386bsd)
		basic_machine=i386-unknown
		os=-bsd
		;;
	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
		basic_machine=m68000-att
		;;
	3b*)
		basic_machine=we32k-att
		;;
	a29khif)
		basic_machine=a29k-amd
		os=-udi
		;;
    	abacus)
		basic_machine=abacus-unknown
		;;
	adobe68k)
		basic_machine=m68010-adobe
		os=-scout
		;;
	alliant | fx80)
		basic_machine=fx80-alliant
		;;
	altos | altos3068)
		basic_machine=m68k-altos
		;;
	am29k)
		basic_machine=a29k-none
		os=-bsd
		;;
	amd64)
		basic_machine=x86_64-pc
		;;
	amd64-*)
		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	amdahl)
		basic_machine=580-amdahl
		os=-sysv
		;;
	amiga | amiga-*)
		basic_machine=m68k-unknown
		;;
	amigaos | amigados)
		basic_machine=m68k-unknown
		os=-amigaos
		;;
	amigaunix | amix)
		basic_machine=m68k-unknown
		os=-sysv4
		;;
	apollo68)
		basic_machine=m68k-apollo
		os=-sysv
		;;
	apollo68bsd)
		basic_machine=m68k-apollo
		os=-bsd
		;;
	aux)
		basic_machine=m68k-apple
		os=-aux
		;;
	balance)
		basic_machine=ns32k-sequent
		os=-dynix
		;;
	c90)
		basic_machine=c90-cray
		os=-unicos
		;;
	convex-c1)
		basic_machine=c1-convex
		os=-bsd
		;;
	convex-c2)
		basic_machine=c2-convex
		os=-bsd
		;;
	convex-c32)
		basic_machine=c32-convex
		os=-bsd
		;;
	convex-c34)
		basic_machine=c34-convex
		os=-bsd
		;;
	convex-c38)
		basic_machine=c38-convex
		os=-bsd
		;;
	cray | j90)
		basic_machine=j90-cray
		os=-unicos
		;;
	craynv)
		basic_machine=craynv-cray
		os=-unicosmp
		;;
	cr16)
		basic_machine=cr16-unknown
		os=-elf
		;;
	crds | unos)
		basic_machine=m68k-crds
		;;
	crisv32 | crisv32-* | etraxfs*)
		basic_machine=crisv32-axis
		;;
	cris | cris-* | etrax*)
		basic_machine=cris-axis
		;;
	crx)
		basic_machine=crx-unknown
		os=-elf
		;;
	da30 | da30-*)
		basic_machine=m68k-da30
		;;
	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
		basic_machine=mips-dec
		;;
	decsystem10* | dec10*)
		basic_machine=pdp10-dec
		os=-tops10
		;;
	decsystem20* | dec20*)
		basic_machine=pdp10-dec
		os=-tops20
		;;
	delta | 3300 | motorola-3300 | motorola-delta \
	      | 3300-motorola | delta-motorola)
		basic_machine=m68k-motorola
		;;
	delta88)
		basic_machine=m88k-motorola
		os=-sysv3
		;;
	djgpp)
		basic_machine=i586-pc
		os=-msdosdjgpp
		;;
	dpx20 | dpx20-*)
		basic_machine=rs6000-bull
		os=-bosx
		;;
	dpx2* | dpx2*-bull)
		basic_machine=m68k-bull
		os=-sysv3
		;;
	ebmon29k)
		basic_machine=a29k-amd
		os=-ebmon
		;;
	elxsi)
		basic_machine=elxsi-elxsi
		os=-bsd
		;;
	encore | umax | mmax)
		basic_machine=ns32k-encore
		;;
	es1800 | OSE68k | ose68k | ose | OSE)
		basic_machine=m68k-ericsson
		os=-ose
		;;
	fx2800)
		basic_machine=i860-alliant
		;;
	genix)
		basic_machine=ns32k-ns
		;;
	gmicro)
		basic_machine=tron-gmicro
		os=-sysv
		;;
	go32)
		basic_machine=i386-pc
		os=-go32
		;;
	h3050r* | hiux*)
		basic_machine=hppa1.1-hitachi
		os=-hiuxwe2
		;;
	h8300hms)
		basic_machine=h8300-hitachi
		os=-hms
		;;
	h8300xray)
		basic_machine=h8300-hitachi
		os=-xray
		;;
	h8500hms)
		basic_machine=h8500-hitachi
		os=-hms
		;;
	harris)
		basic_machine=m88k-harris
		os=-sysv3
		;;
	hp300-*)
		basic_machine=m68k-hp
		;;
	hp300bsd)
		basic_machine=m68k-hp
		os=-bsd
		;;
	hp300hpux)
		basic_machine=m68k-hp
		os=-hpux
		;;
	hp3k9[0-9][0-9] | hp9[0-9][0-9])
		basic_machine=hppa1.0-hp
		;;
	hp9k2[0-9][0-9] | hp9k31[0-9])
		basic_machine=m68000-hp
		;;
	hp9k3[2-9][0-9])
		basic_machine=m68k-hp
		;;
	hp9k6[0-9][0-9] | hp6[0-9][0-9])
		basic_machine=hppa1.0-hp
		;;
	hp9k7[0-79][0-9] | hp7[0-79][0-9])
		basic_machine=hppa1.1-hp
		;;
	hp9k78[0-9] | hp78[0-9])
		# FIXME: really hppa2.0-hp
		basic_machine=hppa1.1-hp
		;;
	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
		# FIXME: really hppa2.0-hp
		basic_machine=hppa1.1-hp
		;;
	hp9k8[0-9][13679] | hp8[0-9][13679])
		basic_machine=hppa1.1-hp
		;;
	hp9k8[0-9][0-9] | hp8[0-9][0-9])
		basic_machine=hppa1.0-hp
		;;
	hppa-next)
		os=-nextstep3
		;;
	hppaosf)
		basic_machine=hppa1.1-hp
		os=-osf
		;;
	hppro)
		basic_machine=hppa1.1-hp
		os=-proelf
		;;
	i370-ibm* | ibm*)
		basic_machine=i370-ibm
		;;
# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
	i*86v32)
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
		os=-sysv32
		;;
	i*86v4*)
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
		os=-sysv4
		;;
	i*86v)
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
		os=-sysv
		;;
	i*86sol2)
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
		os=-solaris2
		;;
	i386mach)
		basic_machine=i386-mach
		os=-mach
		;;
	i386-vsta | vsta)
		basic_machine=i386-unknown
		os=-vsta
		;;
	iris | iris4d)
		basic_machine=mips-sgi
		case $os in
		    -irix*)
			;;
		    *)
			os=-irix4
			;;
		esac
		;;
	isi68 | isi)
		basic_machine=m68k-isi
		os=-sysv
		;;
	m88k-omron*)
		basic_machine=m88k-omron
		;;
	magnum | m3230)
		basic_machine=mips-mips
		os=-sysv
		;;
	merlin)
		basic_machine=ns32k-utek
		os=-sysv
		;;
	mingw32)
		basic_machine=i386-pc
		os=-mingw32
		;;
	mingw32ce)
		basic_machine=arm-unknown
		os=-mingw32ce
		;;
	miniframe)
		basic_machine=m68000-convergent
		;;
	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
		basic_machine=m68k-atari
		os=-mint
		;;
	mips3*-*)
		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
		;;
	mips3*)
		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
		;;
	monitor)
		basic_machine=m68k-rom68k
		os=-coff
		;;
	morphos)
		basic_machine=powerpc-unknown
		os=-morphos
		;;
	msdos)
		basic_machine=i386-pc
		os=-msdos
		;;
	ms1-*)
		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
		;;
	mvs)
		basic_machine=i370-ibm
		os=-mvs
		;;
	ncr3000)
		basic_machine=i486-ncr
		os=-sysv4
		;;
	netbsd386)
		basic_machine=i386-unknown
		os=-netbsd
		;;
	netwinder)
		basic_machine=armv4l-rebel
		os=-linux
		;;
	news | news700 | news800 | news900)
		basic_machine=m68k-sony
		os=-newsos
		;;
	news1000)
		basic_machine=m68030-sony
		os=-newsos
		;;
	news-3600 | risc-news)
		basic_machine=mips-sony
		os=-newsos
		;;
	necv70)
		basic_machine=v70-nec
		os=-sysv
		;;
	next | m*-next )
		basic_machine=m68k-next
		case $os in
		    -nextstep* )
			;;
		    -ns2*)
		      os=-nextstep2
			;;
		    *)
		      os=-nextstep3
			;;
		esac
		;;
	nh3000)
		basic_machine=m68k-harris
		os=-cxux
		;;
	nh[45]000)
		basic_machine=m88k-harris
		os=-cxux
		;;
	nindy960)
		basic_machine=i960-intel
		os=-nindy
		;;
	mon960)
		basic_machine=i960-intel
		os=-mon960
		;;
	nonstopux)
		basic_machine=mips-compaq
		os=-nonstopux
		;;
	np1)
		basic_machine=np1-gould
		;;
	nsr-tandem)
		basic_machine=nsr-tandem
		;;
	op50n-* | op60c-*)
		basic_machine=hppa1.1-oki
		os=-proelf
		;;
	openrisc | openrisc-*)
		basic_machine=or32-unknown
		;;
	os400)
		basic_machine=powerpc-ibm
		os=-os400
		;;
	OSE68000 | ose68000)
		basic_machine=m68000-ericsson
		os=-ose
		;;
	os68k)
		basic_machine=m68k-none
		os=-os68k
		;;
	pa-hitachi)
		basic_machine=hppa1.1-hitachi
		os=-hiuxwe2
		;;
	paragon)
		basic_machine=i860-intel
		os=-osf
		;;
	pbd)
		basic_machine=sparc-tti
		;;
	pbb)
		basic_machine=m68k-tti
		;;
	pc532 | pc532-*)
		basic_machine=ns32k-pc532
		;;
	pc98)
		basic_machine=i386-pc
		;;
	pc98-*)
		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pentium | p5 | k5 | k6 | nexgen | viac3)
		basic_machine=i586-pc
		;;
	pentiumpro | p6 | 6x86 | athlon | athlon_*)
		basic_machine=i686-pc
		;;
	pentiumii | pentium2 | pentiumiii | pentium3)
		basic_machine=i686-pc
		;;
	pentium4)
		basic_machine=i786-pc
		;;
	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pentiumpro-* | p6-* | 6x86-* | athlon-*)
		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pentium4-*)
		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pn)
		basic_machine=pn-gould
		;;
	power)	basic_machine=power-ibm
		;;
	ppc)	basic_machine=powerpc-unknown
		;;
	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	ppcle | powerpclittle | ppc-le | powerpc-little)
		basic_machine=powerpcle-unknown
		;;
	ppcle-* | powerpclittle-*)
		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	ppc64)	basic_machine=powerpc64-unknown
		;;
	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
		basic_machine=powerpc64le-unknown
		;;
	ppc64le-* | powerpc64little-*)
		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	ps2)
		basic_machine=i386-ibm
		;;
	pw32)
		basic_machine=i586-unknown
		os=-pw32
		;;
	rdos)
		basic_machine=i386-pc
		os=-rdos
		;;
	rom68k)
		basic_machine=m68k-rom68k
		os=-coff
		;;
	rm[46]00)
		basic_machine=mips-siemens
		;;
	rtpc | rtpc-*)
		basic_machine=romp-ibm
		;;
	s390 | s390-*)
		basic_machine=s390-ibm
		;;
	s390x | s390x-*)
		basic_machine=s390x-ibm
		;;
	sa29200)
		basic_machine=a29k-amd
		os=-udi
		;;
	sb1)
		basic_machine=mipsisa64sb1-unknown
		;;
	sb1el)
		basic_machine=mipsisa64sb1el-unknown
		;;
	sde)
		basic_machine=mipsisa32-sde
		os=-elf
		;;
	sei)
		basic_machine=mips-sei
		os=-seiux
		;;
	sequent)
		basic_machine=i386-sequent
		;;
	sh)
		basic_machine=sh-hitachi
		os=-hms
		;;
	sh5el)
		basic_machine=sh5le-unknown
		;;
	sh64)
		basic_machine=sh64-unknown
		;;
	sparclite-wrs | simso-wrs)
		basic_machine=sparclite-wrs
		os=-vxworks
		;;
	sps7)
		basic_machine=m68k-bull
		os=-sysv2
		;;
	spur)
		basic_machine=spur-unknown
		;;
	st2000)
		basic_machine=m68k-tandem
		;;
	stratus)
		basic_machine=i860-stratus
		os=-sysv4
		;;
	sun2)
		basic_machine=m68000-sun
		;;
	sun2os3)
		basic_machine=m68000-sun
		os=-sunos3
		;;
	sun2os4)
		basic_machine=m68000-sun
		os=-sunos4
		;;
	sun3os3)
		basic_machine=m68k-sun
		os=-sunos3
		;;
	sun3os4)
		basic_machine=m68k-sun
		os=-sunos4
		;;
	sun4os3)
		basic_machine=sparc-sun
		os=-sunos3
		;;
	sun4os4)
		basic_machine=sparc-sun
		os=-sunos4
		;;
	sun4sol2)
		basic_machine=sparc-sun
		os=-solaris2
		;;
	sun3 | sun3-*)
		basic_machine=m68k-sun
		;;
	sun4)
		basic_machine=sparc-sun
		;;
	sun386 | sun386i | roadrunner)
		basic_machine=i386-sun
		;;
	sv1)
		basic_machine=sv1-cray
		os=-unicos
		;;
	symmetry)
		basic_machine=i386-sequent
		os=-dynix
		;;
	t3e)
		basic_machine=alphaev5-cray
		os=-unicos
		;;
	t90)
		basic_machine=t90-cray
		os=-unicos
		;;
	tic54x | c54x*)
		basic_machine=tic54x-unknown
		os=-coff
		;;
	tic55x | c55x*)
		basic_machine=tic55x-unknown
		os=-coff
		;;
	tic6x | c6x*)
		basic_machine=tic6x-unknown
		os=-coff
		;;
	tx39)
		basic_machine=mipstx39-unknown
		;;
	tx39el)
		basic_machine=mipstx39el-unknown
		;;
	toad1)
		basic_machine=pdp10-xkl
		os=-tops20
		;;
	tower | tower-32)
		basic_machine=m68k-ncr
		;;
	tpf)
		basic_machine=s390x-ibm
		os=-tpf
		;;
	udi29k)
		basic_machine=a29k-amd
		os=-udi
		;;
	ultra3)
		basic_machine=a29k-nyu
		os=-sym1
		;;
	v810 | necv810)
		basic_machine=v810-nec
		os=-none
		;;
	vaxv)
		basic_machine=vax-dec
		os=-sysv
		;;
	vms)
		basic_machine=vax-dec
		os=-vms
		;;
	vpp*|vx|vx-*)
		basic_machine=f301-fujitsu
		;;
	vxworks960)
		basic_machine=i960-wrs
		os=-vxworks
		;;
	vxworks68)
		basic_machine=m68k-wrs
		os=-vxworks
		;;
	vxworks29k)
		basic_machine=a29k-wrs
		os=-vxworks
		;;
	w65*)
		basic_machine=w65-wdc
		os=-none
		;;
	w89k-*)
		basic_machine=hppa1.1-winbond
		os=-proelf
		;;
	xbox)
		basic_machine=i686-pc
		os=-mingw32
		;;
	xps | xps100)
		basic_machine=xps100-honeywell
		;;
	ymp)
		basic_machine=ymp-cray
		os=-unicos
		;;
	z8k-*-coff)
		basic_machine=z8k-unknown
		os=-sim
		;;
	none)
		basic_machine=none-none
		os=-none
		;;

# Here we handle the default manufacturer of certain CPU types.  It is in
# some cases the only manufacturer, in others, it is the most popular.
	w89k)
		basic_machine=hppa1.1-winbond
		;;
	op50n)
		basic_machine=hppa1.1-oki
		;;
	op60c)
		basic_machine=hppa1.1-oki
		;;
	romp)
		basic_machine=romp-ibm
		;;
	mmix)
		basic_machine=mmix-knuth
		;;
	rs6000)
		basic_machine=rs6000-ibm
		;;
	vax)
		basic_machine=vax-dec
		;;
	pdp10)
		# there are many clones, so DEC is not a safe bet
		basic_machine=pdp10-unknown
		;;
	pdp11)
		basic_machine=pdp11-dec
		;;
	we32k)
		basic_machine=we32k-att
		;;
	sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
		basic_machine=sh-unknown
		;;
	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
		basic_machine=sparc-sun
		;;
	cydra)
		basic_machine=cydra-cydrome
		;;
	orion)
		basic_machine=orion-highlevel
		;;
	orion105)
		basic_machine=clipper-highlevel
		;;
	mac | mpw | mac-mpw)
		basic_machine=m68k-apple
		;;
	pmac | pmac-mpw)
		basic_machine=powerpc-apple
		;;
	*-unknown)
		# Make sure to match an already-canonicalized machine name.
		;;
	*)
		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
		exit 1
		;;
esac

# Here we canonicalize certain aliases for manufacturers.
case $basic_machine in
	*-digital*)
		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
		;;
	*-commodore*)
		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
		;;
	*)
		;;
esac

# Decode manufacturer-specific aliases for certain operating systems.

if [ x"$os" != x"" ]
then
case $os in
        # First match some system type aliases
        # that might get confused with valid system types.
	# -solaris* is a basic system type, with this one exception.
	-solaris1 | -solaris1.*)
		os=`echo $os | sed -e 's|solaris1|sunos4|'`
		;;
	-solaris)
		os=-solaris2
		;;
	-svr4*)
		os=-sysv4
		;;
	-unixware*)
		os=-sysv4.2uw
		;;
	-gnu/linux*)
		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
		;;
	# First accept the basic system types.
	# The portable systems comes first.
	# Each alternative MUST END IN A *, to match a version number.
	# -sysv* is not here because it comes later, after sysvr4.
	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
	      | -aos* \
	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
	      | -openbsd* | -solidbsd* \
	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
	      | -chorusos* | -chorusrdb* \
	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
	      | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
	      | -uxpv* | -beos* | -mpeix* | -udk* \
	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
	# Remember, each alternative MUST END IN *, to match a version number.
		;;
	-qnx*)
		case $basic_machine in
		    x86-* | i*86-*)
			;;
		    *)
			os=-nto$os
			;;
		esac
		;;
	-nto-qnx*)
		;;
	-nto*)
		os=`echo $os | sed -e 's|nto|nto-qnx|'`
		;;
	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
		;;
	-mac*)
		os=`echo $os | sed -e 's|mac|macos|'`
		;;
	-linux-dietlibc)
		os=-linux-dietlibc
		;;
	-linux*)
		os=`echo $os | sed -e 's|linux|linux-gnu|'`
		;;
	-sunos5*)
		os=`echo $os | sed -e 's|sunos5|solaris2|'`
		;;
	-sunos6*)
		os=`echo $os | sed -e 's|sunos6|solaris3|'`
		;;
	-opened*)
		os=-openedition
		;;
        -os400*)
		os=-os400
		;;
	-wince*)
		os=-wince
		;;
	-osfrose*)
		os=-osfrose
		;;
	-osf*)
		os=-osf
		;;
	-utek*)
		os=-bsd
		;;
	-dynix*)
		os=-bsd
		;;
	-acis*)
		os=-aos
		;;
	-atheos*)
		os=-atheos
		;;
	-syllable*)
		os=-syllable
		;;
	-386bsd)
		os=-bsd
		;;
	-ctix* | -uts*)
		os=-sysv
		;;
	-nova*)
		os=-rtmk-nova
		;;
	-ns2 )
		os=-nextstep2
		;;
	-nsk*)
		os=-nsk
		;;
	# Preserve the version number of sinix5.
	-sinix5.*)
		os=`echo $os | sed -e 's|sinix|sysv|'`
		;;
	-sinix*)
		os=-sysv4
		;;
        -tpf*)
		os=-tpf
		;;
	-triton*)
		os=-sysv3
		;;
	-oss*)
		os=-sysv3
		;;
	-svr4)
		os=-sysv4
		;;
	-svr3)
		os=-sysv3
		;;
	-sysvr4)
		os=-sysv4
		;;
	# This must come after -sysvr4.
	-sysv*)
		;;
	-ose*)
		os=-ose
		;;
	-es1800*)
		os=-ose
		;;
	-xenix)
		os=-xenix
		;;
	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
		os=-mint
		;;
	-aros*)
		os=-aros
		;;
	-kaos*)
		os=-kaos
		;;
	-zvmoe)
		os=-zvmoe
		;;
	-none)
		;;
	*)
		# Get rid of the `-' at the beginning of $os.
		os=`echo $os | sed 's/[^-]*-//'`
		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
		exit 1
		;;
esac
else

# Here we handle the default operating systems that come with various machines.
# The value should be what the vendor currently ships out the door with their
# machine or put another way, the most popular os provided with the machine.

# Note that if you're going to try to match "-MANUFACTURER" here (say,
# "-sun"), then you have to tell the case statement up towards the top
# that MANUFACTURER isn't an operating system.  Otherwise, code above
# will signal an error saying that MANUFACTURER isn't an operating
# system, and we'll never get to this point.

case $basic_machine in
        score-*)
		os=-elf
		;;
        spu-*)
		os=-elf
		;;
	*-acorn)
		os=-riscix1.2
		;;
	arm*-rebel)
		os=-linux
		;;
	arm*-semi)
		os=-aout
		;;
        c4x-* | tic4x-*)
        	os=-coff
		;;
	# This must come before the *-dec entry.
	pdp10-*)
		os=-tops20
		;;
	pdp11-*)
		os=-none
		;;
	*-dec | vax-*)
		os=-ultrix4.2
		;;
	m68*-apollo)
		os=-domain
		;;
	i386-sun)
		os=-sunos4.0.2
		;;
	m68000-sun)
		os=-sunos3
		# This also exists in the configure program, but was not the
		# default.
		# os=-sunos4
		;;
	m68*-cisco)
		os=-aout
		;;
        mep-*)
		os=-elf
		;;
	mips*-cisco)
		os=-elf
		;;
	mips*-*)
		os=-elf
		;;
	or32-*)
		os=-coff
		;;
	*-tti)	# must be before sparc entry or we get the wrong os.
		os=-sysv3
		;;
	sparc-* | *-sun)
		os=-sunos4.1.1
		;;
	*-be)
		os=-beos
		;;
	*-haiku)
		os=-haiku
		;;
	*-ibm)
		os=-aix
		;;
    	*-knuth)
		os=-mmixware
		;;
	*-wec)
		os=-proelf
		;;
	*-winbond)
		os=-proelf
		;;
	*-oki)
		os=-proelf
		;;
	*-hp)
		os=-hpux
		;;
	*-hitachi)
		os=-hiux
		;;
	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
		os=-sysv
		;;
	*-cbm)
		os=-amigaos
		;;
	*-dg)
		os=-dgux
		;;
	*-dolphin)
		os=-sysv3
		;;
	m68k-ccur)
		os=-rtu
		;;
	m88k-omron*)
		os=-luna
		;;
	*-next )
		os=-nextstep
		;;
	*-sequent)
		os=-ptx
		;;
	*-crds)
		os=-unos
		;;
	*-ns)
		os=-genix
		;;
	i370-*)
		os=-mvs
		;;
	*-next)
		os=-nextstep3
		;;
	*-gould)
		os=-sysv
		;;
	*-highlevel)
		os=-bsd
		;;
	*-encore)
		os=-bsd
		;;
	*-sgi)
		os=-irix
		;;
	*-siemens)
		os=-sysv4
		;;
	*-masscomp)
		os=-rtu
		;;
	f30[01]-fujitsu | f700-fujitsu)
		os=-uxpv
		;;
	*-rom68k)
		os=-coff
		;;
	*-*bug)
		os=-coff
		;;
	*-apple)
		os=-macos
		;;
	*-atari*)
		os=-mint
		;;
	*)
		os=-none
		;;
esac
fi

# Here we handle the case where we know the os, and the CPU type, but not the
# manufacturer.  We pick the logical manufacturer.
vendor=unknown
case $basic_machine in
	*-unknown)
		case $os in
			-riscix*)
				vendor=acorn
				;;
			-sunos*)
				vendor=sun
				;;
			-aix*)
				vendor=ibm
				;;
			-beos*)
				vendor=be
				;;
			-hpux*)
				vendor=hp
				;;
			-mpeix*)
				vendor=hp
				;;
			-hiux*)
				vendor=hitachi
				;;
			-unos*)
				vendor=crds
				;;
			-dgux*)
				vendor=dg
				;;
			-luna*)
				vendor=omron
				;;
			-genix*)
				vendor=ns
				;;
			-mvs* | -opened*)
				vendor=ibm
				;;
			-os400*)
				vendor=ibm
				;;
			-ptx*)
				vendor=sequent
				;;
			-tpf*)
				vendor=ibm
				;;
			-vxsim* | -vxworks* | -windiss*)
				vendor=wrs
				;;
			-aux*)
				vendor=apple
				;;
			-hms*)
				vendor=hitachi
				;;
			-mpw* | -macos*)
				vendor=apple
				;;
			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
				vendor=atari
				;;
			-vos*)
				vendor=stratus
				;;
		esac
		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
		;;
esac

echo $basic_machine$os
exit

# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "timestamp='"
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
# End:


================================================
FILE: distro/google-perftools-1.7/configure
================================================
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.65 for google-perftools 1.7.
#
# Report bugs to .
#
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
# Inc.
#
#
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
## -------------------- ##
## M4sh Initialization. ##
## -------------------- ##

# Be more Bourne compatible
DUALCASE=1; export DUALCASE # for MKS sh
if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
  emulate sh
  NULLCMD=:
  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
  # is contrary to our usage.  Disable this feature.
  alias -g '${1+"$@"}'='"$@"'
  setopt NO_GLOB_SUBST
else
  case `(set -o) 2>/dev/null` in #(
  *posix*) :
    set -o posix ;; #(
  *) :
     ;;
esac
fi


as_nl='
'
export as_nl
# Printing a long string crashes Solaris 7 /usr/bin/printf.
as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
# Prefer a ksh shell builtin over an external printf program on Solaris,
# but without wasting forks for bash or zsh.
if test -z "$BASH_VERSION$ZSH_VERSION" \
    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
  as_echo='print -r --'
  as_echo_n='print -rn --'
elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
  as_echo='printf %s\n'
  as_echo_n='printf %s'
else
  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
    as_echo_n='/usr/ucb/echo -n'
  else
    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
    as_echo_n_body='eval
      arg=$1;
      case $arg in #(
      *"$as_nl"*)
	expr "X$arg" : "X\\(.*\\)$as_nl";
	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
      esac;
      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
    '
    export as_echo_n_body
    as_echo_n='sh -c $as_echo_n_body as_echo'
  fi
  export as_echo_body
  as_echo='sh -c $as_echo_body as_echo'
fi

# The user is always right.
if test "${PATH_SEPARATOR+set}" != set; then
  PATH_SEPARATOR=:
  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
      PATH_SEPARATOR=';'
  }
fi


# IFS
# We need space, tab and new line, in precisely that order.  Quoting is
# there to prevent editors from complaining about space-tab.
# (If _AS_PATH_WALK were called with IFS unset, it would disable word
# splitting by setting IFS to empty value.)
IFS=" ""	$as_nl"

# Find who we are.  Look in the path if we contain no directory separator.
case $0 in #((
  *[\\/]* ) as_myself=$0 ;;
  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
  done
IFS=$as_save_IFS

     ;;
esac
# We did not find ourselves, most probably we were run as `sh COMMAND'
# in which case we are not to be found in the path.
if test "x$as_myself" = x; then
  as_myself=$0
fi
if test ! -f "$as_myself"; then
  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
  exit 1
fi

# Unset variables that we do not need and which cause bugs (e.g. in
# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
# suppresses any "Segmentation fault" message there.  '((' could
# trigger a bug in pdksh 5.2.14.
for as_var in BASH_ENV ENV MAIL MAILPATH
do eval test x\${$as_var+set} = xset \
  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
done
PS1='$ '
PS2='> '
PS4='+ '

# NLS nuisances.
LC_ALL=C
export LC_ALL
LANGUAGE=C
export LANGUAGE

# CDPATH.
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH

if test "x$CONFIG_SHELL" = x; then
  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
  emulate sh
  NULLCMD=:
  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
  # is contrary to our usage.  Disable this feature.
  alias -g '\${1+\"\$@\"}'='\"\$@\"'
  setopt NO_GLOB_SUBST
else
  case \`(set -o) 2>/dev/null\` in #(
  *posix*) :
    set -o posix ;; #(
  *) :
     ;;
esac
fi
"
  as_required="as_fn_return () { (exit \$1); }
as_fn_success () { as_fn_return 0; }
as_fn_failure () { as_fn_return 1; }
as_fn_ret_success () { return 0; }
as_fn_ret_failure () { return 1; }

exitcode=0
as_fn_success || { exitcode=1; echo as_fn_success failed.; }
as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :

else
  exitcode=1; echo positional parameters were not saved.
fi
test x\$exitcode = x0 || exit 1"
  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
test \$(( 1 + 1 )) = 2 || exit 1"
  if (eval "$as_required") 2>/dev/null; then :
  as_have_required=yes
else
  as_have_required=no
fi
  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :

else
  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
as_found=false
for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
  as_found=:
  case $as_dir in #(
	 /*)
	   for as_base in sh bash ksh sh5; do
	     # Try only shells that exist, to save several forks.
	     as_shell=$as_dir/$as_base
	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
  CONFIG_SHELL=$as_shell as_have_required=yes
		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
  break 2
fi
fi
	   done;;
       esac
  as_found=false
done
$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
  CONFIG_SHELL=$SHELL as_have_required=yes
fi; }
IFS=$as_save_IFS


      if test "x$CONFIG_SHELL" != x; then :
  # We cannot yet assume a decent shell, so we have to provide a
	# neutralization value for shells without unset; and this also
	# works around shells that cannot unset nonexistent variables.
	BASH_ENV=/dev/null
	ENV=/dev/null
	(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
	export CONFIG_SHELL
	exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
fi

    if test x$as_have_required = xno; then :
  $as_echo "$0: This script requires a shell more modern than all"
  $as_echo "$0: the shells that I found on your system."
  if test x${ZSH_VERSION+set} = xset ; then
    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
  else
    $as_echo "$0: Please tell bug-autoconf@gnu.org and
$0: opensource@google.com about your system, including any
$0: error possibly output before this message. Then install
$0: a modern shell, or manually run the script under such a
$0: shell if you do have one."
  fi
  exit 1
fi
fi
fi
SHELL=${CONFIG_SHELL-/bin/sh}
export SHELL
# Unset more variables known to interfere with behavior of common tools.
CLICOLOR_FORCE= GREP_OPTIONS=
unset CLICOLOR_FORCE GREP_OPTIONS

## --------------------- ##
## M4sh Shell Functions. ##
## --------------------- ##
# as_fn_unset VAR
# ---------------
# Portably unset VAR.
as_fn_unset ()
{
  { eval $1=; unset $1;}
}
as_unset=as_fn_unset

# as_fn_set_status STATUS
# -----------------------
# Set $? to STATUS, without forking.
as_fn_set_status ()
{
  return $1
} # as_fn_set_status

# as_fn_exit STATUS
# -----------------
# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
as_fn_exit ()
{
  set +e
  as_fn_set_status $1
  exit $1
} # as_fn_exit

# as_fn_mkdir_p
# -------------
# Create "$as_dir" as a directory, including parents if necessary.
as_fn_mkdir_p ()
{

  case $as_dir in #(
  -*) as_dir=./$as_dir;;
  esac
  test -d "$as_dir" || eval $as_mkdir_p || {
    as_dirs=
    while :; do
      case $as_dir in #(
      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
      *) as_qdir=$as_dir;;
      esac
      as_dirs="'$as_qdir' $as_dirs"
      as_dir=`$as_dirname -- "$as_dir" ||
$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
	 X"$as_dir" : 'X\(//\)[^/]' \| \
	 X"$as_dir" : 'X\(//\)$' \| \
	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$as_dir" |
    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)[^/].*/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`
      test -d "$as_dir" && break
    done
    test -z "$as_dirs" || eval "mkdir $as_dirs"
  } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir"


} # as_fn_mkdir_p
# as_fn_append VAR VALUE
# ----------------------
# Append the text in VALUE to the end of the definition contained in VAR. Take
# advantage of any shell optimizations that allow amortized linear growth over
# repeated appends, instead of the typical quadratic growth present in naive
# implementations.
if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
  eval 'as_fn_append ()
  {
    eval $1+=\$2
  }'
else
  as_fn_append ()
  {
    eval $1=\$$1\$2
  }
fi # as_fn_append

# as_fn_arith ARG...
# ------------------
# Perform arithmetic evaluation on the ARGs, and store the result in the
# global $as_val. Take advantage of shells that can avoid forks. The arguments
# must be portable across $(()) and expr.
if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
  eval 'as_fn_arith ()
  {
    as_val=$(( $* ))
  }'
else
  as_fn_arith ()
  {
    as_val=`expr "$@" || test $? -eq 1`
  }
fi # as_fn_arith


# as_fn_error ERROR [LINENO LOG_FD]
# ---------------------------------
# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
# script with status $?, using 1 if that was 0.
as_fn_error ()
{
  as_status=$?; test $as_status -eq 0 && as_status=1
  if test "$3"; then
    as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
    $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3
  fi
  $as_echo "$as_me: error: $1" >&2
  as_fn_exit $as_status
} # as_fn_error

if expr a : '\(a\)' >/dev/null 2>&1 &&
   test "X`expr 00001 : '.*\(...\)'`" = X001; then
  as_expr=expr
else
  as_expr=false
fi

if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
  as_basename=basename
else
  as_basename=false
fi

if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
  as_dirname=dirname
else
  as_dirname=false
fi

as_me=`$as_basename -- "$0" ||
$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
	 X"$0" : 'X\(//\)$' \| \
	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X/"$0" |
    sed '/^.*\/\([^/][^/]*\)\/*$/{
	    s//\1/
	    q
	  }
	  /^X\/\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\/\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`

# Avoid depending upon Character Ranges.
as_cr_letters='abcdefghijklmnopqrstuvwxyz'
as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
as_cr_Letters=$as_cr_letters$as_cr_LETTERS
as_cr_digits='0123456789'
as_cr_alnum=$as_cr_Letters$as_cr_digits


  as_lineno_1=$LINENO as_lineno_1a=$LINENO
  as_lineno_2=$LINENO as_lineno_2a=$LINENO
  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
  sed -n '
    p
    /[$]LINENO/=
  ' <$as_myself |
    sed '
      s/[$]LINENO.*/&-/
      t lineno
      b
      :lineno
      N
      :loop
      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
      t loop
      s/-\n.*//
    ' >$as_me.lineno &&
  chmod +x "$as_me.lineno" ||
    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }

  # Don't try to exec as it changes $[0], causing all sort of problems
  # (the dirname of $[0] is not the place where we might find the
  # original and so on.  Autoconf is especially sensitive to this).
  . "./$as_me.lineno"
  # Exit status is that of the last command.
  exit
}

ECHO_C= ECHO_N= ECHO_T=
case `echo -n x` in #(((((
-n*)
  case `echo 'xy\c'` in
  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
  xy)  ECHO_C='\c';;
  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
       ECHO_T='	';;
  esac;;
*)
  ECHO_N='-n';;
esac

rm -f conf$$ conf$$.exe conf$$.file
if test -d conf$$.dir; then
  rm -f conf$$.dir/conf$$.file
else
  rm -f conf$$.dir
  mkdir conf$$.dir 2>/dev/null
fi
if (echo >conf$$.file) 2>/dev/null; then
  if ln -s conf$$.file conf$$ 2>/dev/null; then
    as_ln_s='ln -s'
    # ... but there are two gotchas:
    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
    # In both cases, we have to default to `cp -p'.
    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
      as_ln_s='cp -p'
  elif ln conf$$.file conf$$ 2>/dev/null; then
    as_ln_s=ln
  else
    as_ln_s='cp -p'
  fi
else
  as_ln_s='cp -p'
fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null

if mkdir -p . 2>/dev/null; then
  as_mkdir_p='mkdir -p "$as_dir"'
else
  test -d ./-p && rmdir ./-p
  as_mkdir_p=false
fi

if test -x / >/dev/null 2>&1; then
  as_test_x='test -x'
else
  if ls -dL / >/dev/null 2>&1; then
    as_ls_L_option=L
  else
    as_ls_L_option=
  fi
  as_test_x='
    eval sh -c '\''
      if test -d "$1"; then
	test -d "$1/.";
      else
	case $1 in #(
	-*)set "./$1";;
	esac;
	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
	???[sx]*):;;*)false;;esac;fi
    '\'' sh
  '
fi
as_executable_p=$as_test_x

# Sed expression to map a string onto a valid CPP name.
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"

# Sed expression to map a string onto a valid variable name.
as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"



# Check that we are running under the correct shell.
SHELL=${CONFIG_SHELL-/bin/sh}

case X$lt_ECHO in
X*--fallback-echo)
  # Remove one level of quotation (which was required for Make).
  ECHO=`echo "$lt_ECHO" | sed 's,\\\\\$\\$0,'$0','`
  ;;
esac

ECHO=${lt_ECHO-echo}
if test "X$1" = X--no-reexec; then
  # Discard the --no-reexec flag, and continue.
  shift
elif test "X$1" = X--fallback-echo; then
  # Avoid inline document here, it may be left over
  :
elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then
  # Yippee, $ECHO works!
  :
else
  # Restart under the correct shell.
  exec $SHELL "$0" --no-reexec ${1+"$@"}
fi

if test "X$1" = X--fallback-echo; then
  # used as fallback echo
  shift
  cat <<_LT_EOF
$*
_LT_EOF
  exit 0
fi

# The HP-UX ksh and POSIX shell print the target directory to stdout
# if CDPATH is set.
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH

if test -z "$lt_ECHO"; then
  if test "X${echo_test_string+set}" != Xset; then
    # find a string as large as possible, as long as the shell can cope with it
    for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do
      # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
      if { echo_test_string=`eval $cmd`; } 2>/dev/null &&
	 { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null
      then
        break
      fi
    done
  fi

  if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
     echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
     test "X$echo_testing_string" = "X$echo_test_string"; then
    :
  else
    # The Solaris, AIX, and Digital Unix default echo programs unquote
    # backslashes.  This makes it impossible to quote backslashes using
    #   echo "$something" | sed 's/\\/\\\\/g'
    #
    # So, first we look for a working echo in the user's PATH.

    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
    for dir in $PATH /usr/ucb; do
      IFS="$lt_save_ifs"
      if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
         test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
         echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
         test "X$echo_testing_string" = "X$echo_test_string"; then
        ECHO="$dir/echo"
        break
      fi
    done
    IFS="$lt_save_ifs"

    if test "X$ECHO" = Xecho; then
      # We didn't find a better echo, so look for alternatives.
      if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' &&
         echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` &&
         test "X$echo_testing_string" = "X$echo_test_string"; then
        # This shell has a builtin print -r that does the trick.
        ECHO='print -r'
      elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } &&
	   test "X$CONFIG_SHELL" != X/bin/ksh; then
        # If we have ksh, try running configure again with it.
        ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
        export ORIGINAL_CONFIG_SHELL
        CONFIG_SHELL=/bin/ksh
        export CONFIG_SHELL
        exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"}
      else
        # Try using printf.
        ECHO='printf %s\n'
        if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
	   echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
	   test "X$echo_testing_string" = "X$echo_test_string"; then
	  # Cool, printf works
	  :
        elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
	     test "X$echo_testing_string" = 'X\t' &&
	     echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
	     test "X$echo_testing_string" = "X$echo_test_string"; then
	  CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
	  export CONFIG_SHELL
	  SHELL="$CONFIG_SHELL"
	  export SHELL
	  ECHO="$CONFIG_SHELL $0 --fallback-echo"
        elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
	     test "X$echo_testing_string" = 'X\t' &&
	     echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
	     test "X$echo_testing_string" = "X$echo_test_string"; then
	  ECHO="$CONFIG_SHELL $0 --fallback-echo"
        else
	  # maybe with a smaller string...
	  prev=:

	  for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do
	    if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null
	    then
	      break
	    fi
	    prev="$cmd"
	  done

	  if test "$prev" != 'sed 50q "$0"'; then
	    echo_test_string=`eval $prev`
	    export echo_test_string
	    exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"}
	  else
	    # Oops.  We lost completely, so just stick with echo.
	    ECHO=echo
	  fi
        fi
      fi
    fi
  fi
fi

# Copy echo and quote the copy suitably for passing to libtool from
# the Makefile, instead of quoting the original, which is used later.
lt_ECHO=$ECHO
if test "X$lt_ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then
   lt_ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo"
fi




test -n "$DJDIR" || exec 7<&0 &1

# Name of the host.
# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
# so uname gets run too.
ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`

#
# Initializations.
#
ac_default_prefix=/usr/local
ac_clean_files=
ac_config_libobj_dir=.
LIBOBJS=
cross_compiling=no
subdirs=
MFLAGS=
MAKEFLAGS=

# Identity of this package.
PACKAGE_NAME='google-perftools'
PACKAGE_TARNAME='google-perftools'
PACKAGE_VERSION='1.7'
PACKAGE_STRING='google-perftools 1.7'
PACKAGE_BUGREPORT='opensource@google.com'
PACKAGE_URL=''

ac_unique_file="README"
# Factoring default headers for most tests.
ac_includes_default="\
#include 
#ifdef HAVE_SYS_TYPES_H
# include 
#endif
#ifdef HAVE_SYS_STAT_H
# include 
#endif
#ifdef STDC_HEADERS
# include 
# include 
#else
# ifdef HAVE_STDLIB_H
#  include 
# endif
#endif
#ifdef HAVE_STRING_H
# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
#  include 
# endif
# include 
#endif
#ifdef HAVE_STRINGS_H
# include 
#endif
#ifdef HAVE_INTTYPES_H
# include 
#endif
#ifdef HAVE_STDINT_H
# include 
#endif
#ifdef HAVE_UNISTD_H
# include 
#endif"

ac_header_list=
ac_subst_vars='LTLIBOBJS
LIBOBJS
WITH_STACK_TRACE_FALSE
WITH_STACK_TRACE_TRUE
WITH_HEAP_PROFILER_OR_CHECKER_FALSE
WITH_HEAP_PROFILER_OR_CHECKER_TRUE
WITH_DEBUGALLOC_FALSE
WITH_DEBUGALLOC_TRUE
WITH_HEAP_CHECKER_FALSE
WITH_HEAP_CHECKER_TRUE
WITH_HEAP_PROFILER_FALSE
WITH_HEAP_PROFILER_TRUE
WITH_CPU_PROFILER_FALSE
WITH_CPU_PROFILER_TRUE
MINGW_FALSE
MINGW_TRUE
PTHREAD_CFLAGS
PTHREAD_LIBS
PTHREAD_CC
acx_pthread_config
LIBSTDCXX_LA_LINKER_FLAG
NANOSLEEP_LIBS
X86_64_AND_NO_FP_BY_DEFAULT_FALSE
X86_64_AND_NO_FP_BY_DEFAULT_TRUE
ENABLE_FRAME_POINTERS_FALSE
ENABLE_FRAME_POINTERS_TRUE
UNWIND_LIBS
ENABLE_STATIC_FALSE
ENABLE_STATIC_TRUE
ac_cv_have_struct_mallinfo
USE_LIBTOOL_FALSE
USE_LIBTOOL_TRUE
LIBTOOL_DEPS
CXXCPP
OTOOL64
OTOOL
LIPO
NMEDIT
DSYMUTIL
lt_ECHO
RANLIB
AR
OBJDUMP
LN_S
NM
ac_ct_DUMPBIN
DUMPBIN
LD
FGREP
EGREP
GREP
SED
LIBTOOL
HAVE_OBJCOPY_WEAKEN_FALSE
HAVE_OBJCOPY_WEAKEN_TRUE
OBJCOPY
GCC_FALSE
GCC_TRUE
am__fastdepCXX_FALSE
am__fastdepCXX_TRUE
CXXDEPMODE
ac_ct_CXX
CXXFLAGS
CXX
CPP
am__fastdepCC_FALSE
am__fastdepCC_TRUE
CCDEPMODE
AMDEPBACKSLASH
AMDEP_FALSE
AMDEP_TRUE
am__quote
am__include
DEPDIR
OBJEXT
EXEEXT
ac_ct_CC
CPPFLAGS
LDFLAGS
CFLAGS
CC
TC_VERSION_PATCH
TC_VERSION_MINOR
TC_VERSION_MAJOR
am__untar
am__tar
AMTAR
am__leading_dot
SET_MAKE
AWK
mkdir_p
INSTALL_STRIP_PROGRAM
STRIP
install_sh
MAKEINFO
AUTOHEADER
AUTOMAKE
AUTOCONF
ACLOCAL
VERSION
PACKAGE
CYGPATH_W
INSTALL_DATA
INSTALL_SCRIPT
INSTALL_PROGRAM
host_os
host_vendor
host_cpu
host
build_os
build_vendor
build_cpu
build
PROFILER_SO_VERSION
TCMALLOC_SO_VERSION
target_alias
host_alias
build_alias
LIBS
ECHO_T
ECHO_N
ECHO_C
DEFS
mandir
localedir
libdir
psdir
pdfdir
dvidir
htmldir
infodir
docdir
oldincludedir
includedir
localstatedir
sharedstatedir
sysconfdir
datadir
datarootdir
libexecdir
sbindir
bindir
program_transform_name
prefix
exec_prefix
PACKAGE_URL
PACKAGE_BUGREPORT
PACKAGE_STRING
PACKAGE_VERSION
PACKAGE_TARNAME
PACKAGE_NAME
PATH_SEPARATOR
SHELL'
ac_subst_files=''
ac_user_opts='
enable_option_checking
enable_cpu_profiler
enable_heap_profiler
enable_heap_checker
enable_debugalloc
enable_minimal
enable_dependency_tracking
enable_fast_install
enable_shared
enable_static
with_pic
with_gnu_ld
enable_libtool_lock
enable_frame_pointers
'
      ac_precious_vars='build_alias
host_alias
target_alias
CC
CFLAGS
LDFLAGS
LIBS
CPPFLAGS
CPP
CXX
CXXFLAGS
CCC
CXXCPP'


# Initialize some variables set by options.
ac_init_help=
ac_init_version=false
ac_unrecognized_opts=
ac_unrecognized_sep=
# The variables have the same names as the options, with
# dashes changed to underlines.
cache_file=/dev/null
exec_prefix=NONE
no_create=
no_recursion=
prefix=NONE
program_prefix=NONE
program_suffix=NONE
program_transform_name=s,x,x,
silent=
site=
srcdir=
verbose=
x_includes=NONE
x_libraries=NONE

# Installation directory options.
# These are left unexpanded so users can "make install exec_prefix=/foo"
# and all the variables that are supposed to be based on exec_prefix
# by default will actually change.
# Use braces instead of parens because sh, perl, etc. also accept them.
# (The list follows the same order as the GNU Coding Standards.)
bindir='${exec_prefix}/bin'
sbindir='${exec_prefix}/sbin'
libexecdir='${exec_prefix}/libexec'
datarootdir='${prefix}/share'
datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
infodir='${datarootdir}/info'
htmldir='${docdir}'
dvidir='${docdir}'
pdfdir='${docdir}'
psdir='${docdir}'
libdir='${exec_prefix}/lib'
localedir='${datarootdir}/locale'
mandir='${datarootdir}/man'

ac_prev=
ac_dashdash=
for ac_option
do
  # If the previous option needs an argument, assign it.
  if test -n "$ac_prev"; then
    eval $ac_prev=\$ac_option
    ac_prev=
    continue
  fi

  case $ac_option in
  *=*)	ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
  *)	ac_optarg=yes ;;
  esac

  # Accept the important Cygnus configure options, so we can diagnose typos.

  case $ac_dashdash$ac_option in
  --)
    ac_dashdash=yes ;;

  -bindir | --bindir | --bindi | --bind | --bin | --bi)
    ac_prev=bindir ;;
  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
    bindir=$ac_optarg ;;

  -build | --build | --buil | --bui | --bu)
    ac_prev=build_alias ;;
  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
    build_alias=$ac_optarg ;;

  -cache-file | --cache-file | --cache-fil | --cache-fi \
  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
    ac_prev=cache_file ;;
  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
    cache_file=$ac_optarg ;;

  --config-cache | -C)
    cache_file=config.cache ;;

  -datadir | --datadir | --datadi | --datad)
    ac_prev=datadir ;;
  -datadir=* | --datadir=* | --datadi=* | --datad=*)
    datadir=$ac_optarg ;;

  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
  | --dataroo | --dataro | --datar)
    ac_prev=datarootdir ;;
  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
    datarootdir=$ac_optarg ;;

  -disable-* | --disable-*)
    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
    # Reject names that are not valid shell variable names.
    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
      as_fn_error "invalid feature name: $ac_useropt"
    ac_useropt_orig=$ac_useropt
    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
    case $ac_user_opts in
      *"
"enable_$ac_useropt"
"*) ;;
      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
	 ac_unrecognized_sep=', ';;
    esac
    eval enable_$ac_useropt=no ;;

  -docdir | --docdir | --docdi | --doc | --do)
    ac_prev=docdir ;;
  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
    docdir=$ac_optarg ;;

  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
    ac_prev=dvidir ;;
  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
    dvidir=$ac_optarg ;;

  -enable-* | --enable-*)
    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
    # Reject names that are not valid shell variable names.
    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
      as_fn_error "invalid feature name: $ac_useropt"
    ac_useropt_orig=$ac_useropt
    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
    case $ac_user_opts in
      *"
"enable_$ac_useropt"
"*) ;;
      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
	 ac_unrecognized_sep=', ';;
    esac
    eval enable_$ac_useropt=\$ac_optarg ;;

  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
  | --exec | --exe | --ex)
    ac_prev=exec_prefix ;;
  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
  | --exec=* | --exe=* | --ex=*)
    exec_prefix=$ac_optarg ;;

  -gas | --gas | --ga | --g)
    # Obsolete; use --with-gas.
    with_gas=yes ;;

  -help | --help | --hel | --he | -h)
    ac_init_help=long ;;
  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
    ac_init_help=recursive ;;
  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
    ac_init_help=short ;;

  -host | --host | --hos | --ho)
    ac_prev=host_alias ;;
  -host=* | --host=* | --hos=* | --ho=*)
    host_alias=$ac_optarg ;;

  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
    ac_prev=htmldir ;;
  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
  | --ht=*)
    htmldir=$ac_optarg ;;

  -includedir | --includedir | --includedi | --included | --include \
  | --includ | --inclu | --incl | --inc)
    ac_prev=includedir ;;
  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
  | --includ=* | --inclu=* | --incl=* | --inc=*)
    includedir=$ac_optarg ;;

  -infodir | --infodir | --infodi | --infod | --info | --inf)
    ac_prev=infodir ;;
  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
    infodir=$ac_optarg ;;

  -libdir | --libdir | --libdi | --libd)
    ac_prev=libdir ;;
  -libdir=* | --libdir=* | --libdi=* | --libd=*)
    libdir=$ac_optarg ;;

  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
  | --libexe | --libex | --libe)
    ac_prev=libexecdir ;;
  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
  | --libexe=* | --libex=* | --libe=*)
    libexecdir=$ac_optarg ;;

  -localedir | --localedir | --localedi | --localed | --locale)
    ac_prev=localedir ;;
  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
    localedir=$ac_optarg ;;

  -localstatedir | --localstatedir | --localstatedi | --localstated \
  | --localstate | --localstat | --localsta | --localst | --locals)
    ac_prev=localstatedir ;;
  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
    localstatedir=$ac_optarg ;;

  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
    ac_prev=mandir ;;
  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
    mandir=$ac_optarg ;;

  -nfp | --nfp | --nf)
    # Obsolete; use --without-fp.
    with_fp=no ;;

  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
  | --no-cr | --no-c | -n)
    no_create=yes ;;

  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
    no_recursion=yes ;;

  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
  | --oldin | --oldi | --old | --ol | --o)
    ac_prev=oldincludedir ;;
  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
    oldincludedir=$ac_optarg ;;

  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
    ac_prev=prefix ;;
  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
    prefix=$ac_optarg ;;

  -program-prefix | --program-prefix | --program-prefi | --program-pref \
  | --program-pre | --program-pr | --program-p)
    ac_prev=program_prefix ;;
  -program-prefix=* | --program-prefix=* | --program-prefi=* \
  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
    program_prefix=$ac_optarg ;;

  -program-suffix | --program-suffix | --program-suffi | --program-suff \
  | --program-suf | --program-su | --program-s)
    ac_prev=program_suffix ;;
  -program-suffix=* | --program-suffix=* | --program-suffi=* \
  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
    program_suffix=$ac_optarg ;;

  -program-transform-name | --program-transform-name \
  | --program-transform-nam | --program-transform-na \
  | --program-transform-n | --program-transform- \
  | --program-transform | --program-transfor \
  | --program-transfo | --program-transf \
  | --program-trans | --program-tran \
  | --progr-tra | --program-tr | --program-t)
    ac_prev=program_transform_name ;;
  -program-transform-name=* | --program-transform-name=* \
  | --program-transform-nam=* | --program-transform-na=* \
  | --program-transform-n=* | --program-transform-=* \
  | --program-transform=* | --program-transfor=* \
  | --program-transfo=* | --program-transf=* \
  | --program-trans=* | --program-tran=* \
  | --progr-tra=* | --program-tr=* | --program-t=*)
    program_transform_name=$ac_optarg ;;

  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
    ac_prev=pdfdir ;;
  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
    pdfdir=$ac_optarg ;;

  -psdir | --psdir | --psdi | --psd | --ps)
    ac_prev=psdir ;;
  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
    psdir=$ac_optarg ;;

  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
  | -silent | --silent | --silen | --sile | --sil)
    silent=yes ;;

  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
    ac_prev=sbindir ;;
  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
  | --sbi=* | --sb=*)
    sbindir=$ac_optarg ;;

  -sharedstatedir | --sharedstatedir | --sharedstatedi \
  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
  | --sharedst | --shareds | --shared | --share | --shar \
  | --sha | --sh)
    ac_prev=sharedstatedir ;;
  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
  | --sha=* | --sh=*)
    sharedstatedir=$ac_optarg ;;

  -site | --site | --sit)
    ac_prev=site ;;
  -site=* | --site=* | --sit=*)
    site=$ac_optarg ;;

  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
    ac_prev=srcdir ;;
  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
    srcdir=$ac_optarg ;;

  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
  | --syscon | --sysco | --sysc | --sys | --sy)
    ac_prev=sysconfdir ;;
  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
    sysconfdir=$ac_optarg ;;

  -target | --target | --targe | --targ | --tar | --ta | --t)
    ac_prev=target_alias ;;
  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
    target_alias=$ac_optarg ;;

  -v | -verbose | --verbose | --verbos | --verbo | --verb)
    verbose=yes ;;

  -version | --version | --versio | --versi | --vers | -V)
    ac_init_version=: ;;

  -with-* | --with-*)
    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
    # Reject names that are not valid shell variable names.
    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
      as_fn_error "invalid package name: $ac_useropt"
    ac_useropt_orig=$ac_useropt
    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
    case $ac_user_opts in
      *"
"with_$ac_useropt"
"*) ;;
      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
	 ac_unrecognized_sep=', ';;
    esac
    eval with_$ac_useropt=\$ac_optarg ;;

  -without-* | --without-*)
    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
    # Reject names that are not valid shell variable names.
    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
      as_fn_error "invalid package name: $ac_useropt"
    ac_useropt_orig=$ac_useropt
    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
    case $ac_user_opts in
      *"
"with_$ac_useropt"
"*) ;;
      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
	 ac_unrecognized_sep=', ';;
    esac
    eval with_$ac_useropt=no ;;

  --x)
    # Obsolete; use --with-x.
    with_x=yes ;;

  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
  | --x-incl | --x-inc | --x-in | --x-i)
    ac_prev=x_includes ;;
  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
    x_includes=$ac_optarg ;;

  -x-libraries | --x-libraries | --x-librarie | --x-librari \
  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
    ac_prev=x_libraries ;;
  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
    x_libraries=$ac_optarg ;;

  -*) as_fn_error "unrecognized option: \`$ac_option'
Try \`$0 --help' for more information."
    ;;

  *=*)
    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
    # Reject names that are not valid shell variable names.
    case $ac_envvar in #(
      '' | [0-9]* | *[!_$as_cr_alnum]* )
      as_fn_error "invalid variable name: \`$ac_envvar'" ;;
    esac
    eval $ac_envvar=\$ac_optarg
    export $ac_envvar ;;

  *)
    # FIXME: should be removed in autoconf 3.0.
    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
    ;;

  esac
done

if test -n "$ac_prev"; then
  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
  as_fn_error "missing argument to $ac_option"
fi

if test -n "$ac_unrecognized_opts"; then
  case $enable_option_checking in
    no) ;;
    fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;;
    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
  esac
fi

# Check all directory arguments for consistency.
for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
		datadir sysconfdir sharedstatedir localstatedir includedir \
		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
		libdir localedir mandir
do
  eval ac_val=\$$ac_var
  # Remove trailing slashes.
  case $ac_val in
    */ )
      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
      eval $ac_var=\$ac_val;;
  esac
  # Be sure to have absolute directory names.
  case $ac_val in
    [\\/$]* | ?:[\\/]* )  continue;;
    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
  esac
  as_fn_error "expected an absolute directory name for --$ac_var: $ac_val"
done

# There might be people who depend on the old broken behavior: `$host'
# used to hold the argument of --host etc.
# FIXME: To remove some day.
build=$build_alias
host=$host_alias
target=$target_alias

# FIXME: To remove some day.
if test "x$host_alias" != x; then
  if test "x$build_alias" = x; then
    cross_compiling=maybe
    $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
    If a cross compiler is detected then cross compile mode will be used." >&2
  elif test "x$build_alias" != "x$host_alias"; then
    cross_compiling=yes
  fi
fi

ac_tool_prefix=
test -n "$host_alias" && ac_tool_prefix=$host_alias-

test "$silent" = yes && exec 6>/dev/null


ac_pwd=`pwd` && test -n "$ac_pwd" &&
ac_ls_di=`ls -di .` &&
ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
  as_fn_error "working directory cannot be determined"
test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
  as_fn_error "pwd does not report name of working directory"


# Find the source files, if location was not specified.
if test -z "$srcdir"; then
  ac_srcdir_defaulted=yes
  # Try the directory containing this script, then the parent directory.
  ac_confdir=`$as_dirname -- "$as_myself" ||
$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
	 X"$as_myself" : 'X\(//\)[^/]' \| \
	 X"$as_myself" : 'X\(//\)$' \| \
	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$as_myself" |
    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)[^/].*/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`
  srcdir=$ac_confdir
  if test ! -r "$srcdir/$ac_unique_file"; then
    srcdir=..
  fi
else
  ac_srcdir_defaulted=no
fi
if test ! -r "$srcdir/$ac_unique_file"; then
  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
  as_fn_error "cannot find sources ($ac_unique_file) in $srcdir"
fi
ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
ac_abs_confdir=`(
	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg"
	pwd)`
# When building in place, set srcdir=.
if test "$ac_abs_confdir" = "$ac_pwd"; then
  srcdir=.
fi
# Remove unnecessary trailing slashes from srcdir.
# Double slashes in file names in object file debugging info
# mess up M-x gdb in Emacs.
case $srcdir in
*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
esac
for ac_var in $ac_precious_vars; do
  eval ac_env_${ac_var}_set=\${${ac_var}+set}
  eval ac_env_${ac_var}_value=\$${ac_var}
  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
  eval ac_cv_env_${ac_var}_value=\$${ac_var}
done

#
# Report the --help message.
#
if test "$ac_init_help" = "long"; then
  # Omit some internal or obsolete options to make the list less imposing.
  # This message is too long to be a string in the A/UX 3.1 sh.
  cat <<_ACEOF
\`configure' configures google-perftools 1.7 to adapt to many kinds of systems.

Usage: $0 [OPTION]... [VAR=VALUE]...

To assign environment variables (e.g., CC, CFLAGS...), specify them as
VAR=VALUE.  See below for descriptions of some of the useful variables.

Defaults for the options are specified in brackets.

Configuration:
  -h, --help              display this help and exit
      --help=short        display options specific to this package
      --help=recursive    display the short help of all the included packages
  -V, --version           display version information and exit
  -q, --quiet, --silent   do not print \`checking...' messages
      --cache-file=FILE   cache test results in FILE [disabled]
  -C, --config-cache      alias for \`--cache-file=config.cache'
  -n, --no-create         do not create output files
      --srcdir=DIR        find the sources in DIR [configure dir or \`..']

Installation directories:
  --prefix=PREFIX         install architecture-independent files in PREFIX
                          [$ac_default_prefix]
  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
                          [PREFIX]

By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
an installation prefix other than \`$ac_default_prefix' using \`--prefix',
for instance \`--prefix=\$HOME'.

For better control, use the options below.

Fine tuning of the installation directories:
  --bindir=DIR            user executables [EPREFIX/bin]
  --sbindir=DIR           system admin executables [EPREFIX/sbin]
  --libexecdir=DIR        program executables [EPREFIX/libexec]
  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
  --libdir=DIR            object code libraries [EPREFIX/lib]
  --includedir=DIR        C header files [PREFIX/include]
  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
  --infodir=DIR           info documentation [DATAROOTDIR/info]
  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
  --mandir=DIR            man documentation [DATAROOTDIR/man]
  --docdir=DIR            documentation root
                          [DATAROOTDIR/doc/google-perftools]
  --htmldir=DIR           html documentation [DOCDIR]
  --dvidir=DIR            dvi documentation [DOCDIR]
  --pdfdir=DIR            pdf documentation [DOCDIR]
  --psdir=DIR             ps documentation [DOCDIR]
_ACEOF

  cat <<\_ACEOF

Program names:
  --program-prefix=PREFIX            prepend PREFIX to installed program names
  --program-suffix=SUFFIX            append SUFFIX to installed program names
  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names

System types:
  --build=BUILD     configure for building on BUILD [guessed]
  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
_ACEOF
fi

if test -n "$ac_init_help"; then
  case $ac_init_help in
     short | recursive ) echo "Configuration of google-perftools 1.7:";;
   esac
  cat <<\_ACEOF

Optional Features:
  --disable-option-checking  ignore unrecognized --enable/--with options
  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
  --disable-cpu-profiler  do not build the cpu profiler
  --disable-heap-profiler do not build the heap profiler
  --disable-heap-checker  do not build the heap checker
  --disable-debugalloc    do not build versions of libs with debugalloc
  --enable-minimal        build only tcmalloc-minimal (and maybe
                          tcmalloc-minimal-debug)
  --disable-dependency-tracking  speeds up one-time build
  --enable-dependency-tracking   do not reject slow dependency extractors
  --enable-fast-install[=PKGS]
                          optimize for fast installation [default=no]
  --enable-shared[=PKGS]  build shared libraries [default=yes]
  --enable-static[=PKGS]  build static libraries [default=yes]
  --disable-libtool-lock  avoid locking (might break parallel builds)
  --enable-frame-pointers On x86_64 systems, compile with
                          -fno-omit-frame-pointer (see INSTALL)

Optional Packages:
  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
  --with-pic              try to use only PIC/non-PIC objects [default=use
                          both]
  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]

Some influential environment variables:
  CC          C compiler command
  CFLAGS      C compiler flags
  LDFLAGS     linker flags, e.g. -L if you have libraries in a
              nonstandard directory 
  LIBS        libraries to pass to the linker, e.g. -l
  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I if
              you have headers in a nonstandard directory 
  CPP         C preprocessor
  CXX         C++ compiler command
  CXXFLAGS    C++ compiler flags
  CXXCPP      C++ preprocessor

Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.

Report bugs to .
_ACEOF
ac_status=$?
fi

if test "$ac_init_help" = "recursive"; then
  # If there are subdirs, report their specific --help.
  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
    test -d "$ac_dir" ||
      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
      continue
    ac_builddir=.

case "$ac_dir" in
.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
*)
  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
  # A ".." for each directory in $ac_dir_suffix.
  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
  case $ac_top_builddir_sub in
  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
  esac ;;
esac
ac_abs_top_builddir=$ac_pwd
ac_abs_builddir=$ac_pwd$ac_dir_suffix
# for backward compatibility:
ac_top_builddir=$ac_top_build_prefix

case $srcdir in
  .)  # We are building in place.
    ac_srcdir=.
    ac_top_srcdir=$ac_top_builddir_sub
    ac_abs_top_srcdir=$ac_pwd ;;
  [\\/]* | ?:[\\/]* )  # Absolute name.
    ac_srcdir=$srcdir$ac_dir_suffix;
    ac_top_srcdir=$srcdir
    ac_abs_top_srcdir=$srcdir ;;
  *) # Relative name.
    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
    ac_top_srcdir=$ac_top_build_prefix$srcdir
    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
esac
ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix

    cd "$ac_dir" || { ac_status=$?; continue; }
    # Check for guested configure.
    if test -f "$ac_srcdir/configure.gnu"; then
      echo &&
      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
    elif test -f "$ac_srcdir/configure"; then
      echo &&
      $SHELL "$ac_srcdir/configure" --help=recursive
    else
      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
    fi || ac_status=$?
    cd "$ac_pwd" || { ac_status=$?; break; }
  done
fi

test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
  cat <<\_ACEOF
google-perftools configure 1.7
generated by GNU Autoconf 2.65

Copyright (C) 2009 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
  exit
fi

## ------------------------ ##
## Autoconf initialization. ##
## ------------------------ ##

# ac_fn_c_try_compile LINENO
# --------------------------
# Try to compile conftest.$ac_ext, and return whether this succeeded.
ac_fn_c_try_compile ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  rm -f conftest.$ac_objext
  if { { ac_try="$ac_compile"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_compile") 2>conftest.err
  ac_status=$?
  if test -s conftest.err; then
    grep -v '^ *+' conftest.err >conftest.er1
    cat conftest.er1 >&5
    mv -f conftest.er1 conftest.err
  fi
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } && {
	 test -z "$ac_c_werror_flag" ||
	 test ! -s conftest.err
       } && test -s conftest.$ac_objext; then :
  ac_retval=0
else
  $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

	ac_retval=1
fi
  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
  as_fn_set_status $ac_retval

} # ac_fn_c_try_compile

# ac_fn_c_try_cpp LINENO
# ----------------------
# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
ac_fn_c_try_cpp ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  if { { ac_try="$ac_cpp conftest.$ac_ext"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
  ac_status=$?
  if test -s conftest.err; then
    grep -v '^ *+' conftest.err >conftest.er1
    cat conftest.er1 >&5
    mv -f conftest.er1 conftest.err
  fi
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } >/dev/null && {
	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
	 test ! -s conftest.err
       }; then :
  ac_retval=0
else
  $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

    ac_retval=1
fi
  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
  as_fn_set_status $ac_retval

} # ac_fn_c_try_cpp

# ac_fn_cxx_try_compile LINENO
# ----------------------------
# Try to compile conftest.$ac_ext, and return whether this succeeded.
ac_fn_cxx_try_compile ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  rm -f conftest.$ac_objext
  if { { ac_try="$ac_compile"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_compile") 2>conftest.err
  ac_status=$?
  if test -s conftest.err; then
    grep -v '^ *+' conftest.err >conftest.er1
    cat conftest.er1 >&5
    mv -f conftest.er1 conftest.err
  fi
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } && {
	 test -z "$ac_cxx_werror_flag" ||
	 test ! -s conftest.err
       } && test -s conftest.$ac_objext; then :
  ac_retval=0
else
  $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

	ac_retval=1
fi
  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
  as_fn_set_status $ac_retval

} # ac_fn_cxx_try_compile

# ac_fn_c_try_link LINENO
# -----------------------
# Try to link conftest.$ac_ext, and return whether this succeeded.
ac_fn_c_try_link ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  rm -f conftest.$ac_objext conftest$ac_exeext
  if { { ac_try="$ac_link"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_link") 2>conftest.err
  ac_status=$?
  if test -s conftest.err; then
    grep -v '^ *+' conftest.err >conftest.er1
    cat conftest.er1 >&5
    mv -f conftest.er1 conftest.err
  fi
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } && {
	 test -z "$ac_c_werror_flag" ||
	 test ! -s conftest.err
       } && test -s conftest$ac_exeext && {
	 test "$cross_compiling" = yes ||
	 $as_test_x conftest$ac_exeext
       }; then :
  ac_retval=0
else
  $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

	ac_retval=1
fi
  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
  # interfere with the next link command; also delete a directory that is
  # left behind by Apple's compiler.  We do this before executing the actions.
  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
  as_fn_set_status $ac_retval

} # ac_fn_c_try_link

# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
# -------------------------------------------------------
# Tests whether HEADER exists and can be compiled using the include files in
# INCLUDES, setting the cache variable VAR accordingly.
ac_fn_c_check_header_compile ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
$4
#include <$2>
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  eval "$3=yes"
else
  eval "$3=no"
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
eval ac_res=\$$3
	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}

} # ac_fn_c_check_header_compile

# ac_fn_c_try_run LINENO
# ----------------------
# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
# that executables *can* be run.
ac_fn_c_try_run ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  if { { ac_try="$ac_link"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_link") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
  { { case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_try") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; }; then :
  ac_retval=0
else
  $as_echo "$as_me: program exited with status $ac_status" >&5
       $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

       ac_retval=$ac_status
fi
  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
  as_fn_set_status $ac_retval

} # ac_fn_c_try_run

# ac_fn_c_check_func LINENO FUNC VAR
# ----------------------------------
# Tests whether FUNC exists, setting the cache variable VAR accordingly
ac_fn_c_check_func ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
/* Define $2 to an innocuous variant, in case  declares $2.
   For example, HP-UX 11i  declares gettimeofday.  */
#define $2 innocuous_$2

/* System header to define __stub macros and hopefully few prototypes,
    which can conflict with char $2 (); below.
    Prefer  to  if __STDC__ is defined, since
     exists even on freestanding compilers.  */

#ifdef __STDC__
# include 
#else
# include 
#endif

#undef $2

/* Override any GCC internal prototype to avoid an error.
   Use char because int might match the return type of a GCC
   builtin and then its argument prototype would still apply.  */
#ifdef __cplusplus
extern "C"
#endif
char $2 ();
/* The GNU C library defines this for functions which it implements
    to always fail with ENOSYS.  Some functions are actually named
    something starting with __ and the normal name is an alias.  */
#if defined __stub_$2 || defined __stub___$2
choke me
#endif

int
main ()
{
return $2 ();
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  eval "$3=yes"
else
  eval "$3=no"
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
fi
eval ac_res=\$$3
	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}

} # ac_fn_c_check_func

# ac_fn_cxx_try_cpp LINENO
# ------------------------
# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
ac_fn_cxx_try_cpp ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  if { { ac_try="$ac_cpp conftest.$ac_ext"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
  ac_status=$?
  if test -s conftest.err; then
    grep -v '^ *+' conftest.err >conftest.er1
    cat conftest.er1 >&5
    mv -f conftest.er1 conftest.err
  fi
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } >/dev/null && {
	 test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
	 test ! -s conftest.err
       }; then :
  ac_retval=0
else
  $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

    ac_retval=1
fi
  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
  as_fn_set_status $ac_retval

} # ac_fn_cxx_try_cpp

# ac_fn_cxx_try_link LINENO
# -------------------------
# Try to link conftest.$ac_ext, and return whether this succeeded.
ac_fn_cxx_try_link ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  rm -f conftest.$ac_objext conftest$ac_exeext
  if { { ac_try="$ac_link"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_link") 2>conftest.err
  ac_status=$?
  if test -s conftest.err; then
    grep -v '^ *+' conftest.err >conftest.er1
    cat conftest.er1 >&5
    mv -f conftest.er1 conftest.err
  fi
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } && {
	 test -z "$ac_cxx_werror_flag" ||
	 test ! -s conftest.err
       } && test -s conftest$ac_exeext && {
	 test "$cross_compiling" = yes ||
	 $as_test_x conftest$ac_exeext
       }; then :
  ac_retval=0
else
  $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

	ac_retval=1
fi
  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
  # interfere with the next link command; also delete a directory that is
  # left behind by Apple's compiler.  We do this before executing the actions.
  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
  as_fn_set_status $ac_retval

} # ac_fn_cxx_try_link

# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
# -------------------------------------------
# Tests whether TYPE exists after having included INCLUDES, setting cache
# variable VAR accordingly.
ac_fn_c_check_type ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
  $as_echo_n "(cached) " >&6
else
  eval "$3=no"
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
$4
int
main ()
{
if (sizeof ($2))
	 return 0;
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
$4
int
main ()
{
if (sizeof (($2)))
	    return 0;
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :

else
  eval "$3=yes"
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
eval ac_res=\$$3
	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}

} # ac_fn_c_check_type

# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
# -------------------------------------------------------
# Tests whether HEADER exists, giving a warning if it cannot be compiled using
# the include files in INCLUDES and setting the cache variable VAR
# accordingly.
ac_fn_c_check_header_mongrel ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
  $as_echo_n "(cached) " >&6
fi
eval ac_res=\$$3
	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
else
  # Is the header compilable?
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
$as_echo_n "checking $2 usability... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
$4
#include <$2>
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_header_compiler=yes
else
  ac_header_compiler=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
$as_echo "$ac_header_compiler" >&6; }

# Is the header present?
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
$as_echo_n "checking $2 presence... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <$2>
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :
  ac_header_preproc=yes
else
  ac_header_preproc=no
fi
rm -f conftest.err conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
$as_echo "$ac_header_preproc" >&6; }

# So?  What about this header?
case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
  yes:no: )
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
    ;;
  no:yes:* )
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
( cat <<\_ASBOX
## ------------------------------------ ##
## Report this to opensource@google.com ##
## ------------------------------------ ##
_ASBOX
     ) | sed "s/^/$as_me: WARNING:     /" >&2
    ;;
esac
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
  $as_echo_n "(cached) " >&6
else
  eval "$3=\$ac_header_compiler"
fi
eval ac_res=\$$3
	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
fi
  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}

} # ac_fn_c_check_header_mongrel

# ac_fn_c_check_decl LINENO SYMBOL VAR
# ------------------------------------
# Tests whether SYMBOL is declared, setting cache variable VAR accordingly.
ac_fn_c_check_decl ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $2 is declared" >&5
$as_echo_n "checking whether $2 is declared... " >&6; }
if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
$4
int
main ()
{
#ifndef $2
  (void) $2;
#endif

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  eval "$3=yes"
else
  eval "$3=no"
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
eval ac_res=\$$3
	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}

} # ac_fn_c_check_decl
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.

It was created by google-perftools $as_me 1.7, which was
generated by GNU Autoconf 2.65.  Invocation command line was

  $ $0 $@

_ACEOF
exec 5>>config.log
{
cat <<_ASUNAME
## --------- ##
## Platform. ##
## --------- ##

hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
uname -m = `(uname -m) 2>/dev/null || echo unknown`
uname -r = `(uname -r) 2>/dev/null || echo unknown`
uname -s = `(uname -s) 2>/dev/null || echo unknown`
uname -v = `(uname -v) 2>/dev/null || echo unknown`

/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`

/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`

_ASUNAME

as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    $as_echo "PATH: $as_dir"
  done
IFS=$as_save_IFS

} >&5

cat >&5 <<_ACEOF


## ----------- ##
## Core tests. ##
## ----------- ##

_ACEOF


# Keep a trace of the command line.
# Strip out --no-create and --no-recursion so they do not pile up.
# Strip out --silent because we don't want to record it for future runs.
# Also quote any args containing shell meta-characters.
# Make two passes to allow for proper duplicate-argument suppression.
ac_configure_args=
ac_configure_args0=
ac_configure_args1=
ac_must_keep_next=false
for ac_pass in 1 2
do
  for ac_arg
  do
    case $ac_arg in
    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
    | -silent | --silent | --silen | --sile | --sil)
      continue ;;
    *\'*)
      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
    esac
    case $ac_pass in
    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
    2)
      as_fn_append ac_configure_args1 " '$ac_arg'"
      if test $ac_must_keep_next = true; then
	ac_must_keep_next=false # Got value, back to normal.
      else
	case $ac_arg in
	  *=* | --config-cache | -C | -disable-* | --disable-* \
	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
	  | -with-* | --with-* | -without-* | --without-* | --x)
	    case "$ac_configure_args0 " in
	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
	    esac
	    ;;
	  -* ) ac_must_keep_next=true ;;
	esac
      fi
      as_fn_append ac_configure_args " '$ac_arg'"
      ;;
    esac
  done
done
{ ac_configure_args0=; unset ac_configure_args0;}
{ ac_configure_args1=; unset ac_configure_args1;}

# When interrupted or exit'd, cleanup temporary files, and complete
# config.log.  We remove comments because anyway the quotes in there
# would cause problems or look ugly.
# WARNING: Use '\'' to represent an apostrophe within the trap.
# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
trap 'exit_status=$?
  # Save into config.log some information that might help in debugging.
  {
    echo

    cat <<\_ASBOX
## ---------------- ##
## Cache variables. ##
## ---------------- ##
_ASBOX
    echo
    # The following way of writing the cache mishandles newlines in values,
(
  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
    eval ac_val=\$$ac_var
    case $ac_val in #(
    *${as_nl}*)
      case $ac_var in #(
      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
      esac
      case $ac_var in #(
      _ | IFS | as_nl) ;; #(
      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
      *) { eval $ac_var=; unset $ac_var;} ;;
      esac ;;
    esac
  done
  (set) 2>&1 |
    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
    *${as_nl}ac_space=\ *)
      sed -n \
	"s/'\''/'\''\\\\'\'''\''/g;
	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
      ;; #(
    *)
      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
      ;;
    esac |
    sort
)
    echo

    cat <<\_ASBOX
## ----------------- ##
## Output variables. ##
## ----------------- ##
_ASBOX
    echo
    for ac_var in $ac_subst_vars
    do
      eval ac_val=\$$ac_var
      case $ac_val in
      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
      esac
      $as_echo "$ac_var='\''$ac_val'\''"
    done | sort
    echo

    if test -n "$ac_subst_files"; then
      cat <<\_ASBOX
## ------------------- ##
## File substitutions. ##
## ------------------- ##
_ASBOX
      echo
      for ac_var in $ac_subst_files
      do
	eval ac_val=\$$ac_var
	case $ac_val in
	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
	esac
	$as_echo "$ac_var='\''$ac_val'\''"
      done | sort
      echo
    fi

    if test -s confdefs.h; then
      cat <<\_ASBOX
## ----------- ##
## confdefs.h. ##
## ----------- ##
_ASBOX
      echo
      cat confdefs.h
      echo
    fi
    test "$ac_signal" != 0 &&
      $as_echo "$as_me: caught signal $ac_signal"
    $as_echo "$as_me: exit $exit_status"
  } >&5
  rm -f core *.core core.conftest.* &&
    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
    exit $exit_status
' 0
for ac_signal in 1 2 13 15; do
  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
done
ac_signal=0

# confdefs.h avoids OS command line length limits that DEFS can exceed.
rm -f -r conftest* confdefs.h

$as_echo "/* confdefs.h */" > confdefs.h

# Predefined preprocessor variables.

cat >>confdefs.h <<_ACEOF
#define PACKAGE_NAME "$PACKAGE_NAME"
_ACEOF

cat >>confdefs.h <<_ACEOF
#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
_ACEOF

cat >>confdefs.h <<_ACEOF
#define PACKAGE_VERSION "$PACKAGE_VERSION"
_ACEOF

cat >>confdefs.h <<_ACEOF
#define PACKAGE_STRING "$PACKAGE_STRING"
_ACEOF

cat >>confdefs.h <<_ACEOF
#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
_ACEOF

cat >>confdefs.h <<_ACEOF
#define PACKAGE_URL "$PACKAGE_URL"
_ACEOF


# Let the site file select an alternate cache file if it wants to.
# Prefer an explicitly selected file to automatically selected ones.
ac_site_file1=NONE
ac_site_file2=NONE
if test -n "$CONFIG_SITE"; then
  ac_site_file1=$CONFIG_SITE
elif test "x$prefix" != xNONE; then
  ac_site_file1=$prefix/share/config.site
  ac_site_file2=$prefix/etc/config.site
else
  ac_site_file1=$ac_default_prefix/share/config.site
  ac_site_file2=$ac_default_prefix/etc/config.site
fi
for ac_site_file in "$ac_site_file1" "$ac_site_file2"
do
  test "x$ac_site_file" = xNONE && continue
  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
$as_echo "$as_me: loading site script $ac_site_file" >&6;}
    sed 's/^/| /' "$ac_site_file" >&5
    . "$ac_site_file"
  fi
done

if test -r "$cache_file"; then
  # Some versions of bash will fail to source /dev/null (special files
  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
$as_echo "$as_me: loading cache $cache_file" >&6;}
    case $cache_file in
      [\\/]* | ?:[\\/]* ) . "$cache_file";;
      *)                      . "./$cache_file";;
    esac
  fi
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
$as_echo "$as_me: creating cache $cache_file" >&6;}
  >$cache_file
fi

as_fn_append ac_header_list " stdlib.h"
as_fn_append ac_header_list " unistd.h"
as_fn_append ac_header_list " sys/param.h"
# Check that the precious variables saved in the cache have kept the same
# value.
ac_cache_corrupted=false
for ac_var in $ac_precious_vars; do
  eval ac_old_set=\$ac_cv_env_${ac_var}_set
  eval ac_new_set=\$ac_env_${ac_var}_set
  eval ac_old_val=\$ac_cv_env_${ac_var}_value
  eval ac_new_val=\$ac_env_${ac_var}_value
  case $ac_old_set,$ac_new_set in
    set,)
      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
      ac_cache_corrupted=: ;;
    ,set)
      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
      ac_cache_corrupted=: ;;
    ,);;
    *)
      if test "x$ac_old_val" != "x$ac_new_val"; then
	# differences in whitespace do not lead to failure.
	ac_old_val_w=`echo x $ac_old_val`
	ac_new_val_w=`echo x $ac_new_val`
	if test "$ac_old_val_w" != "$ac_new_val_w"; then
	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
	  ac_cache_corrupted=:
	else
	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
	  eval $ac_var=\$ac_old_val
	fi
	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
      fi;;
  esac
  # Pass precious variables to config.status.
  if test "$ac_new_set" = set; then
    case $ac_new_val in
    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
    *) ac_arg=$ac_var=$ac_new_val ;;
    esac
    case " $ac_configure_args " in
      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
    esac
  fi
done
if $ac_cache_corrupted; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
  as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
fi
## -------------------- ##
## Main body of script. ##
## -------------------- ##

ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu


# Update this value for every release!  (A:B:C will map to foo.so.(A-C).C.B)
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
TCMALLOC_SO_VERSION=1:0:1
PROFILER_SO_VERSION=1:0:1




# The argument here is just something that should be in the current directory
# (for sanity checking)


ac_aux_dir=
for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
  for ac_t in install-sh install.sh shtool; do
    if test -f "$ac_dir/$ac_t"; then
      ac_aux_dir=$ac_dir
      ac_install_sh="$ac_aux_dir/$ac_t -c"
      break 2
    fi
  done
done
if test -z "$ac_aux_dir"; then
  as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
fi

# These three variables are undocumented and unsupported,
# and are intended to be withdrawn in a future Autoconf release.
# They can cause serious problems if a builder's source tree is in a directory
# whose full name contains unusual characters.
ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.


# Make sure we can run config.sub.
$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
  as_fn_error "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
$as_echo_n "checking build system type... " >&6; }
if test "${ac_cv_build+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  ac_build_alias=$build_alias
test "x$ac_build_alias" = x &&
  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
test "x$ac_build_alias" = x &&
  as_fn_error "cannot guess build type; you must specify one" "$LINENO" 5
ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
  as_fn_error "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
$as_echo "$ac_cv_build" >&6; }
case $ac_cv_build in
*-*-*) ;;
*) as_fn_error "invalid value of canonical build" "$LINENO" 5;;
esac
build=$ac_cv_build
ac_save_IFS=$IFS; IFS='-'
set x $ac_cv_build
shift
build_cpu=$1
build_vendor=$2
shift; shift
# Remember, the first character of IFS is used to create $*,
# except with old shells:
build_os=$*
IFS=$ac_save_IFS
case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac


{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
$as_echo_n "checking host system type... " >&6; }
if test "${ac_cv_host+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test "x$host_alias" = x; then
  ac_cv_host=$ac_cv_build
else
  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
    as_fn_error "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
fi

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
$as_echo "$ac_cv_host" >&6; }
case $ac_cv_host in
*-*-*) ;;
*) as_fn_error "invalid value of canonical host" "$LINENO" 5;;
esac
host=$ac_cv_host
ac_save_IFS=$IFS; IFS='-'
set x $ac_cv_host
shift
host_cpu=$1
host_vendor=$2
shift; shift
# Remember, the first character of IFS is used to create $*,
# except with old shells:
host_os=$*
IFS=$ac_save_IFS
case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac


am__api_version="1.9"
# Find a good install program.  We prefer a C program (faster),
# so one script is as good as another.  But avoid the broken or
# incompatible versions:
# SysV /etc/install, /usr/sbin/install
# SunOS /usr/etc/install
# IRIX /sbin/install
# AIX /bin/install
# AmigaOS /C/install, which installs bootblocks on floppy discs
# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
# AFS /usr/afsws/bin/install, which mishandles nonexistent args
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
# OS/2's system install, which has a completely different semantic
# ./install, which can be erroneously created by make from ./install.sh.
# Reject install programs that cannot install multiple files.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
$as_echo_n "checking for a BSD-compatible install... " >&6; }
if test -z "$INSTALL"; then
if test "${ac_cv_path_install+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    # Account for people who put trailing slashes in PATH elements.
case $as_dir/ in #((
  ./ | .// | /[cC]/* | \
  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
  /usr/ucb/* ) ;;
  *)
    # OSF1 and SCO ODT 3.0 have their own names for install.
    # Don't use installbsd from OSF since it installs stuff as root
    # by default.
    for ac_prog in ginstall scoinst install; do
      for ac_exec_ext in '' $ac_executable_extensions; do
	if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
	  if test $ac_prog = install &&
	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
	    # AIX install.  It has an incompatible calling convention.
	    :
	  elif test $ac_prog = install &&
	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
	    # program-specific install script used by HP pwplus--don't use.
	    :
	  else
	    rm -rf conftest.one conftest.two conftest.dir
	    echo one > conftest.one
	    echo two > conftest.two
	    mkdir conftest.dir
	    if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
	      test -s conftest.one && test -s conftest.two &&
	      test -s conftest.dir/conftest.one &&
	      test -s conftest.dir/conftest.two
	    then
	      ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
	      break 3
	    fi
	  fi
	fi
      done
    done
    ;;
esac

  done
IFS=$as_save_IFS

rm -rf conftest.one conftest.two conftest.dir

fi
  if test "${ac_cv_path_install+set}" = set; then
    INSTALL=$ac_cv_path_install
  else
    # As a last resort, use the slow shell script.  Don't cache a
    # value for INSTALL within a source directory, because that will
    # break other packages using the cache if that directory is
    # removed, or if the value is a relative name.
    INSTALL=$ac_install_sh
  fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
$as_echo "$INSTALL" >&6; }

# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
# It thinks the first close brace ends the variable substitution.
test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'

test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'

test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
$as_echo_n "checking whether build environment is sane... " >&6; }
# Just in case
sleep 1
echo timestamp > conftest.file
# Do `set' in a subshell so we don't clobber the current shell's
# arguments.  Must try -L first in case configure is actually a
# symlink; some systems play weird games with the mod time of symlinks
# (eg FreeBSD returns the mod time of the symlink's containing
# directory).
if (
   set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
   if test "$*" = "X"; then
      # -L didn't work.
      set X `ls -t $srcdir/configure conftest.file`
   fi
   rm -f conftest.file
   if test "$*" != "X $srcdir/configure conftest.file" \
      && test "$*" != "X conftest.file $srcdir/configure"; then

      # If neither matched, then we have a broken ls.  This can happen
      # if, for instance, CONFIG_SHELL is bash and it inherits a
      # broken ls alias from the environment.  This has actually
      # happened.  Such a system could not be considered "sane".
      as_fn_error "ls -t appears to fail.  Make sure there is not a broken
alias in your environment" "$LINENO" 5
   fi

   test "$2" = conftest.file
   )
then
   # Ok.
   :
else
   as_fn_error "newly created file is older than distributed files!
Check your system clock" "$LINENO" 5
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
test "$program_prefix" != NONE &&
  program_transform_name="s&^&$program_prefix&;$program_transform_name"
# Use a double $ so make ignores it.
test "$program_suffix" != NONE &&
  program_transform_name="s&\$&$program_suffix&;$program_transform_name"
# Double any \ or $.
# By default was `s,x,x', remove it if useless.
ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`

# expand $ac_aux_dir to an absolute path
am_aux_dir=`cd $ac_aux_dir && pwd`

test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
# Use eval to expand $SHELL
if eval "$MISSING --run true"; then
  am_missing_run="$MISSING --run "
else
  am_missing_run=
  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5
$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
fi

if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
  # We used to keeping the `.' as first argument, in order to
  # allow $(mkdir_p) to be used without argument.  As in
  #   $(mkdir_p) $(somedir)
  # where $(somedir) is conditionally defined.  However this is wrong
  # for two reasons:
  #  1. if the package is installed by a user who cannot write `.'
  #     make install will fail,
  #  2. the above comment should most certainly read
  #     $(mkdir_p) $(DESTDIR)$(somedir)
  #     so it does not work when $(somedir) is undefined and
  #     $(DESTDIR) is not.
  #  To support the latter case, we have to write
  #     test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
  #  so the `.' trick is pointless.
  mkdir_p='mkdir -p --'
else
  # On NextStep and OpenStep, the `mkdir' command does not
  # recognize any option.  It will interpret all options as
  # directories to create, and then abort because `.' already
  # exists.
  for d in ./-p ./--version;
  do
    test -d $d && rmdir $d
  done
  # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
  if test -f "$ac_aux_dir/mkinstalldirs"; then
    mkdir_p='$(mkinstalldirs)'
  else
    mkdir_p='$(install_sh) -d'
  fi
fi

for ac_prog in gawk mawk nawk awk
do
  # Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_AWK+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$AWK"; then
  ac_cv_prog_AWK="$AWK" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_AWK="$ac_prog"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
AWK=$ac_cv_prog_AWK
if test -n "$AWK"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
$as_echo "$AWK" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


  test -n "$AWK" && break
done

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
set x ${MAKE-make}
ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then :
  $as_echo_n "(cached) " >&6
else
  cat >conftest.make <<\_ACEOF
SHELL = /bin/sh
all:
	@echo '@@@%%%=$(MAKE)=@@@%%%'
_ACEOF
# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
case `${MAKE-make} -f conftest.make 2>/dev/null` in
  *@@@%%%=?*=@@@%%%*)
    eval ac_cv_prog_make_${ac_make}_set=yes;;
  *)
    eval ac_cv_prog_make_${ac_make}_set=no;;
esac
rm -f conftest.make
fi
if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
  SET_MAKE=
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
  SET_MAKE="MAKE=${MAKE-make}"
fi

rm -rf .tst 2>/dev/null
mkdir .tst 2>/dev/null
if test -d .tst; then
  am__leading_dot=.
else
  am__leading_dot=_
fi
rmdir .tst 2>/dev/null

# test to see if srcdir already configured
if test "`cd $srcdir && pwd`" != "`pwd`" &&
   test -f $srcdir/config.status; then
  as_fn_error "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
fi

# test whether we have cygpath
if test -z "$CYGPATH_W"; then
  if (cygpath --version) >/dev/null 2>/dev/null; then
    CYGPATH_W='cygpath -w'
  else
    CYGPATH_W=echo
  fi
fi


# Define the identity of the package.
 PACKAGE='google-perftools'
 VERSION='1.7'


cat >>confdefs.h <<_ACEOF
#define PACKAGE "$PACKAGE"
_ACEOF


cat >>confdefs.h <<_ACEOF
#define VERSION "$VERSION"
_ACEOF

# Some tools Automake needs.

ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}


AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}


AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}


AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}


MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}

install_sh=${install_sh-"$am_aux_dir/install-sh"}

# Installed binaries are usually stripped using `strip' when the user
# run `make install-strip'.  However `strip' might not be the right
# tool to use in cross-compilation environments, therefore Automake
# will honor the `STRIP' environment variable to overrule this program.
if test "$cross_compiling" != no; then
  if test -n "$ac_tool_prefix"; then
  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
set dummy ${ac_tool_prefix}strip; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_STRIP+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$STRIP"; then
  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
STRIP=$ac_cv_prog_STRIP
if test -n "$STRIP"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
$as_echo "$STRIP" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


fi
if test -z "$ac_cv_prog_STRIP"; then
  ac_ct_STRIP=$STRIP
  # Extract the first word of "strip", so it can be a program name with args.
set dummy strip; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_STRIP"; then
  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_ac_ct_STRIP="strip"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
if test -n "$ac_ct_STRIP"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
$as_echo "$ac_ct_STRIP" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi

  if test "x$ac_ct_STRIP" = x; then
    STRIP=":"
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    STRIP=$ac_ct_STRIP
  fi
else
  STRIP="$ac_cv_prog_STRIP"
fi

fi
INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"

# We need awk for the "check" target.  The system "awk" is bad on
# some platforms.
# Always define AMTAR for backward compatibility.

AMTAR=${AMTAR-"${am_missing_run}tar"}

am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'





ac_config_headers="$ac_config_headers src/config.h"


# Export the version information (for tc_version and friends)
TC_VERSION_MAJOR=`expr "$PACKAGE_VERSION" : '\([0-9]*\)'`
TC_VERSION_MINOR=`expr "$PACKAGE_VERSION" : '[^.]*\.\([0-9]*\)'`
TC_VERSION_PATCH=`expr "$PACKAGE_VERSION" : '[^.0-9]*\([^0-9]*\)$'`





# The user can choose not to compile in the heap-profiler, the
# heap-checker, or the cpu-profiler.  There's also the possibility
# for a 'fully minimal' compile, which leaves out the stacktrace
# code as well.  By default, we include all of these that the
# target system supports.
default_enable_cpu_profiler=yes
default_enable_heap_profiler=yes
default_enable_heap_checker=yes
default_enable_debugalloc=yes
default_enable_minimal=no
need_nanosleep=yes   # Used later, to decide if to run ACX_NANOSLEEP
case "$host" in
   *-mingw*) default_enable_minimal=yes; default_enable_debugalloc=no;
             need_nanosleep=no;;
   *-cygwin*) default_enable_heap_checker=no; default_enable_cpu_profiler=no;;
   *-freebsd*) default_enable_heap_checker=no;;
   *-darwin*) default_enable_heap_checker=no;;
esac

# Check whether --enable-cpu-profiler was given.
if test "${enable_cpu_profiler+set}" = set; then :
  enableval=$enable_cpu_profiler;
else
  enable_cpu_profiler="$default_enable_cpu_profiler"
fi

# Check whether --enable-heap-profiler was given.
if test "${enable_heap_profiler+set}" = set; then :
  enableval=$enable_heap_profiler;
else
  enable_heap_profiler="$default_enable_heap_profiler"
fi

# Check whether --enable-heap-checker was given.
if test "${enable_heap_checker+set}" = set; then :
  enableval=$enable_heap_checker;
else
  enable_heap_checker="$default_enable_heap_checker"
fi

# Check whether --enable-debugalloc was given.
if test "${enable_debugalloc+set}" = set; then :
  enableval=$enable_debugalloc;
else
  enable_debugalloc="$default_enable_debugalloc"
fi

# Check whether --enable-minimal was given.
if test "${enable_minimal+set}" = set; then :
  enableval=$enable_minimal;
else
  enable_minimal="$default_enable_minimal"
fi

if test "$enable_minimal" = yes; then
  enable_cpu_profiler=no
  enable_heap_profiler=no
  enable_heap_checker=no
fi


# Checks for programs.
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
if test -n "$ac_tool_prefix"; then
  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
set dummy ${ac_tool_prefix}gcc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_CC+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$CC"; then
  ac_cv_prog_CC="$CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_CC="${ac_tool_prefix}gcc"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
$as_echo "$CC" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


fi
if test -z "$ac_cv_prog_CC"; then
  ac_ct_CC=$CC
  # Extract the first word of "gcc", so it can be a program name with args.
set dummy gcc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_CC"; then
  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_ac_ct_CC="gcc"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_CC=$ac_cv_prog_ac_ct_CC
if test -n "$ac_ct_CC"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
$as_echo "$ac_ct_CC" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi

  if test "x$ac_ct_CC" = x; then
    CC=""
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    CC=$ac_ct_CC
  fi
else
  CC="$ac_cv_prog_CC"
fi

if test -z "$CC"; then
          if test -n "$ac_tool_prefix"; then
    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_CC+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$CC"; then
  ac_cv_prog_CC="$CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_CC="${ac_tool_prefix}cc"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
$as_echo "$CC" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


  fi
fi
if test -z "$CC"; then
  # Extract the first word of "cc", so it can be a program name with args.
set dummy cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_CC+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$CC"; then
  ac_cv_prog_CC="$CC" # Let the user override the test.
else
  ac_prog_rejected=no
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
       ac_prog_rejected=yes
       continue
     fi
    ac_cv_prog_CC="cc"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

if test $ac_prog_rejected = yes; then
  # We found a bogon in the path, so make sure we never use it.
  set dummy $ac_cv_prog_CC
  shift
  if test $# != 0; then
    # We chose a different compiler from the bogus one.
    # However, it has the same basename, so the bogon will be chosen
    # first if we set CC to just the basename; use the full file name.
    shift
    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
  fi
fi
fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
$as_echo "$CC" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


fi
if test -z "$CC"; then
  if test -n "$ac_tool_prefix"; then
  for ac_prog in cl.exe
  do
    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_CC+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$CC"; then
  ac_cv_prog_CC="$CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
$as_echo "$CC" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


    test -n "$CC" && break
  done
fi
if test -z "$CC"; then
  ac_ct_CC=$CC
  for ac_prog in cl.exe
do
  # Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_CC"; then
  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_ac_ct_CC="$ac_prog"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_CC=$ac_cv_prog_ac_ct_CC
if test -n "$ac_ct_CC"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
$as_echo "$ac_ct_CC" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


  test -n "$ac_ct_CC" && break
done

  if test "x$ac_ct_CC" = x; then
    CC=""
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    CC=$ac_ct_CC
  fi
fi

fi


test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error "no acceptable C compiler found in \$PATH
See \`config.log' for more details." "$LINENO" 5; }

# Provide some information about the compiler.
$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
set X $ac_compile
ac_compiler=$2
for ac_option in --version -v -V -qversion; do
  { { ac_try="$ac_compiler $ac_option >&5"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
  ac_status=$?
  if test -s conftest.err; then
    sed '10a\
... rest of stderr output deleted ...
         10q' conftest.err >conftest.er1
    cat conftest.er1 >&5
  fi
  rm -f conftest.er1 conftest.err
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }
done

cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
ac_clean_files_save=$ac_clean_files
ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
# Try to create an executable without -o first, disregard a.out.
# It will help us diagnose broken compilers, and finding out an intuition
# of exeext.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
$as_echo_n "checking whether the C compiler works... " >&6; }
ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`

# The possible output files:
ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"

ac_rmfiles=
for ac_file in $ac_files
do
  case $ac_file in
    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
  esac
done
rm -f $ac_rmfiles

if { { ac_try="$ac_link_default"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_link_default") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; then :
  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
# in a Makefile.  We should not override ac_cv_exeext if it was cached,
# so that the user can short-circuit this test for compilers unknown to
# Autoconf.
for ac_file in $ac_files ''
do
  test -f "$ac_file" || continue
  case $ac_file in
    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
	;;
    [ab].out )
	# We found the default executable, but exeext='' is most
	# certainly right.
	break;;
    *.* )
	if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
	then :; else
	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
	fi
	# We set ac_cv_exeext here because the later test for it is not
	# safe: cross compilers may not add the suffix if given an `-o'
	# argument, so we may need to know it at that point already.
	# Even if this section looks crufty: it has the advantage of
	# actually working.
	break;;
    * )
	break;;
  esac
done
test "$ac_cv_exeext" = no && ac_cv_exeext=

else
  ac_file=''
fi
if test -z "$ac_file"; then :
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
$as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
{ as_fn_set_status 77
as_fn_error "C compiler cannot create executables
See \`config.log' for more details." "$LINENO" 5; }; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
$as_echo_n "checking for C compiler default output file name... " >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
$as_echo "$ac_file" >&6; }
ac_exeext=$ac_cv_exeext

rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
ac_clean_files=$ac_clean_files_save
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
$as_echo_n "checking for suffix of executables... " >&6; }
if { { ac_try="$ac_link"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_link") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; then :
  # If both `conftest.exe' and `conftest' are `present' (well, observable)
# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
# work properly (i.e., refer to `conftest.exe'), while it won't with
# `rm'.
for ac_file in conftest.exe conftest conftest.*; do
  test -f "$ac_file" || continue
  case $ac_file in
    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
	  break;;
    * ) break;;
  esac
done
else
  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error "cannot compute suffix of executables: cannot compile and link
See \`config.log' for more details." "$LINENO" 5; }
fi
rm -f conftest conftest$ac_cv_exeext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
$as_echo "$ac_cv_exeext" >&6; }

rm -f conftest.$ac_ext
EXEEXT=$ac_cv_exeext
ac_exeext=$EXEEXT
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
int
main ()
{
FILE *f = fopen ("conftest.out", "w");
 return ferror (f) || fclose (f) != 0;

  ;
  return 0;
}
_ACEOF
ac_clean_files="$ac_clean_files conftest.out"
# Check that the compiler produces executables we can run.  If not, either
# the compiler is broken, or we cross compile.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
$as_echo_n "checking whether we are cross compiling... " >&6; }
if test "$cross_compiling" != yes; then
  { { ac_try="$ac_link"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_link") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }
  if { ac_try='./conftest$ac_cv_exeext'
  { { case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_try") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; }; then
    cross_compiling=no
  else
    if test "$cross_compiling" = maybe; then
	cross_compiling=yes
    else
	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error "cannot run C compiled programs.
If you meant to cross compile, use \`--host'.
See \`config.log' for more details." "$LINENO" 5; }
    fi
  fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
$as_echo "$cross_compiling" >&6; }

rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
ac_clean_files=$ac_clean_files_save
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
$as_echo_n "checking for suffix of object files... " >&6; }
if test "${ac_cv_objext+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
rm -f conftest.o conftest.obj
if { { ac_try="$ac_compile"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_compile") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; then :
  for ac_file in conftest.o conftest.obj conftest.*; do
  test -f "$ac_file" || continue;
  case $ac_file in
    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
       break;;
  esac
done
else
  $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error "cannot compute suffix of object files: cannot compile
See \`config.log' for more details." "$LINENO" 5; }
fi
rm -f conftest.$ac_cv_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
$as_echo "$ac_cv_objext" >&6; }
OBJEXT=$ac_cv_objext
ac_objext=$OBJEXT
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
if test "${ac_cv_c_compiler_gnu+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{
#ifndef __GNUC__
       choke me
#endif

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_compiler_gnu=yes
else
  ac_compiler_gnu=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
ac_cv_c_compiler_gnu=$ac_compiler_gnu

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
$as_echo "$ac_cv_c_compiler_gnu" >&6; }
if test $ac_compiler_gnu = yes; then
  GCC=yes
else
  GCC=
fi
ac_test_CFLAGS=${CFLAGS+set}
ac_save_CFLAGS=$CFLAGS
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
$as_echo_n "checking whether $CC accepts -g... " >&6; }
if test "${ac_cv_prog_cc_g+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  ac_save_c_werror_flag=$ac_c_werror_flag
   ac_c_werror_flag=yes
   ac_cv_prog_cc_g=no
   CFLAGS="-g"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_cv_prog_cc_g=yes
else
  CFLAGS=""
      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :

else
  ac_c_werror_flag=$ac_save_c_werror_flag
	 CFLAGS="-g"
	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_cv_prog_cc_g=yes
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
   ac_c_werror_flag=$ac_save_c_werror_flag
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
$as_echo "$ac_cv_prog_cc_g" >&6; }
if test "$ac_test_CFLAGS" = set; then
  CFLAGS=$ac_save_CFLAGS
elif test $ac_cv_prog_cc_g = yes; then
  if test "$GCC" = yes; then
    CFLAGS="-g -O2"
  else
    CFLAGS="-g"
  fi
else
  if test "$GCC" = yes; then
    CFLAGS="-O2"
  else
    CFLAGS=
  fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
if test "${ac_cv_prog_cc_c89+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  ac_cv_prog_cc_c89=no
ac_save_CC=$CC
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
#include 
#include 
#include 
/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
struct buf { int x; };
FILE * (*rcsopen) (struct buf *, struct stat *, int);
static char *e (p, i)
     char **p;
     int i;
{
  return p[i];
}
static char *f (char * (*g) (char **, int), char **p, ...)
{
  char *s;
  va_list v;
  va_start (v,p);
  s = g (p, va_arg (v,int));
  va_end (v);
  return s;
}

/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
   function prototypes and stuff, but not '\xHH' hex character constants.
   These don't provoke an error unfortunately, instead are silently treated
   as 'x'.  The following induces an error, until -std is added to get
   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
   array size at least.  It's necessary to write '\x00'==0 to get something
   that's true only with -std.  */
int osf4_cc_array ['\x00' == 0 ? 1 : -1];

/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
   inside strings and character constants.  */
#define FOO(x) 'x'
int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];

int test (int i, double x);
struct s1 {int (*f) (int a);};
struct s2 {int (*f) (double a);};
int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
int argc;
char **argv;
int
main ()
{
return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
  ;
  return 0;
}
_ACEOF
for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
do
  CC="$ac_save_CC $ac_arg"
  if ac_fn_c_try_compile "$LINENO"; then :
  ac_cv_prog_cc_c89=$ac_arg
fi
rm -f core conftest.err conftest.$ac_objext
  test "x$ac_cv_prog_cc_c89" != "xno" && break
done
rm -f conftest.$ac_ext
CC=$ac_save_CC

fi
# AC_CACHE_VAL
case "x$ac_cv_prog_cc_c89" in
  x)
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
$as_echo "none needed" >&6; } ;;
  xno)
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
$as_echo "unsupported" >&6; } ;;
  *)
    CC="$CC $ac_cv_prog_cc_c89"
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
esac
if test "x$ac_cv_prog_cc_c89" != xno; then :

fi

ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
DEPDIR="${am__leading_dot}deps"

ac_config_commands="$ac_config_commands depfiles"


am_make=${MAKE-make}
cat > confinc << 'END'
am__doit:
	@echo done
.PHONY: am__doit
END
# If we don't find an include directive, just comment out the code.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
$as_echo_n "checking for style of include used by $am_make... " >&6; }
am__include="#"
am__quote=
_am_result=none
# First try GNU make style include.
echo "include confinc" > confmf
# We grep out `Entering directory' and `Leaving directory'
# messages which can occur if `w' ends up in MAKEFLAGS.
# In particular we don't look at `^make:' because GNU make might
# be invoked under some other name (usually "gmake"), in which
# case it prints its new name instead of `make'.
if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
   am__include=include
   am__quote=
   _am_result=GNU
fi
# Now try BSD make style include.
if test "$am__include" = "#"; then
   echo '.include "confinc"' > confmf
   if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
      am__include=.include
      am__quote="\""
      _am_result=BSD
   fi
fi


{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
$as_echo "$_am_result" >&6; }
rm -f confinc confmf

# Check whether --enable-dependency-tracking was given.
if test "${enable_dependency_tracking+set}" = set; then :
  enableval=$enable_dependency_tracking;
fi

if test "x$enable_dependency_tracking" != xno; then
  am_depcomp="$ac_aux_dir/depcomp"
  AMDEPBACKSLASH='\'
fi


if test "x$enable_dependency_tracking" != xno; then
  AMDEP_TRUE=
  AMDEP_FALSE='#'
else
  AMDEP_TRUE='#'
  AMDEP_FALSE=
fi




depcc="$CC"   am_compiler_list=

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
$as_echo_n "checking dependency style of $depcc... " >&6; }
if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
  # We make a subdir and do the tests there.  Otherwise we can end up
  # making bogus files that we don't know about and never remove.  For
  # instance it was reported that on HP-UX the gcc test will end up
  # making a dummy file named `D' -- because `-MD' means `put the output
  # in D'.
  mkdir conftest.dir
  # Copy depcomp to subdir because otherwise we won't find it if we're
  # using a relative directory.
  cp "$am_depcomp" conftest.dir
  cd conftest.dir
  # We will build objects and dependencies in a subdirectory because
  # it helps to detect inapplicable dependency modes.  For instance
  # both Tru64's cc and ICC support -MD to output dependencies as a
  # side effect of compilation, but ICC will put the dependencies in
  # the current directory while Tru64 will put them in the object
  # directory.
  mkdir sub

  am_cv_CC_dependencies_compiler_type=none
  if test "$am_compiler_list" = ""; then
     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
  fi
  for depmode in $am_compiler_list; do
    # Setup a source with many dependencies, because some compilers
    # like to wrap large dependency lists on column 80 (with \), and
    # we should not choose a depcomp mode which is confused by this.
    #
    # We need to recreate these files for each test, as the compiler may
    # overwrite some of them when testing with obscure command lines.
    # This happens at least with the AIX C compiler.
    : > sub/conftest.c
    for i in 1 2 3 4 5 6; do
      echo '#include "conftst'$i'.h"' >> sub/conftest.c
      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
      # Solaris 8's {/usr,}/bin/sh.
      touch sub/conftst$i.h
    done
    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf

    case $depmode in
    nosideeffect)
      # after this tag, mechanisms are not by side-effect, so they'll
      # only be used when explicitly requested
      if test "x$enable_dependency_tracking" = xyes; then
	continue
      else
	break
      fi
      ;;
    none) break ;;
    esac
    # We check with `-c' and `-o' for the sake of the "dashmstdout"
    # mode.  It turns out that the SunPro C++ compiler does not properly
    # handle `-M -o', and we need to detect this.
    if depmode=$depmode \
       source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
       $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
         >/dev/null 2>conftest.err &&
       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
       grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
      # icc doesn't choke on unknown options, it will just issue warnings
      # or remarks (even with -Werror).  So we grep stderr for any message
      # that says an option was ignored or not supported.
      # When given -MP, icc 7.0 and 7.1 complain thusly:
      #   icc: Command line warning: ignoring option '-M'; no argument required
      # The diagnosis changed in icc 8.0:
      #   icc: Command line remark: option '-MP' not supported
      if (grep 'ignoring option' conftest.err ||
          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
        am_cv_CC_dependencies_compiler_type=$depmode
        break
      fi
    fi
  done

  cd ..
  rm -rf conftest.dir
else
  am_cv_CC_dependencies_compiler_type=none
fi

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type



if
  test "x$enable_dependency_tracking" != xno \
  && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
  am__fastdepCC_TRUE=
  am__fastdepCC_FALSE='#'
else
  am__fastdepCC_TRUE='#'
  am__fastdepCC_FALSE=
fi


ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
$as_echo_n "checking how to run the C preprocessor... " >&6; }
# On Suns, sometimes $CPP names a directory.
if test -n "$CPP" && test -d "$CPP"; then
  CPP=
fi
if test -z "$CPP"; then
  if test "${ac_cv_prog_CPP+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
      # Double quotes because CPP needs to be expanded
    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
    do
      ac_preproc_ok=false
for ac_c_preproc_warn_flag in '' yes
do
  # Use a header file that comes with gcc, so configuring glibc
  # with a fresh cross-compiler works.
  # Prefer  to  if __STDC__ is defined, since
  #  exists even on freestanding compilers.
  # On the NeXT, cc -E runs the code through the compiler's parser,
  # not just through cpp. "Syntax error" is here to catch this case.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#ifdef __STDC__
# include 
#else
# include 
#endif
		     Syntax error
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :

else
  # Broken: fails on valid input.
continue
fi
rm -f conftest.err conftest.$ac_ext

  # OK, works on sane cases.  Now check whether nonexistent headers
  # can be detected and how.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :
  # Broken: success on invalid input.
continue
else
  # Passes both tests.
ac_preproc_ok=:
break
fi
rm -f conftest.err conftest.$ac_ext

done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
rm -f conftest.err conftest.$ac_ext
if $ac_preproc_ok; then :
  break
fi

    done
    ac_cv_prog_CPP=$CPP

fi
  CPP=$ac_cv_prog_CPP
else
  ac_cv_prog_CPP=$CPP
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
$as_echo "$CPP" >&6; }
ac_preproc_ok=false
for ac_c_preproc_warn_flag in '' yes
do
  # Use a header file that comes with gcc, so configuring glibc
  # with a fresh cross-compiler works.
  # Prefer  to  if __STDC__ is defined, since
  #  exists even on freestanding compilers.
  # On the NeXT, cc -E runs the code through the compiler's parser,
  # not just through cpp. "Syntax error" is here to catch this case.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#ifdef __STDC__
# include 
#else
# include 
#endif
		     Syntax error
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :

else
  # Broken: fails on valid input.
continue
fi
rm -f conftest.err conftest.$ac_ext

  # OK, works on sane cases.  Now check whether nonexistent headers
  # can be detected and how.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :
  # Broken: success on invalid input.
continue
else
  # Passes both tests.
ac_preproc_ok=:
break
fi
rm -f conftest.err conftest.$ac_ext

done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
rm -f conftest.err conftest.$ac_ext
if $ac_preproc_ok; then :

else
  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error "C preprocessor \"$CPP\" fails sanity check
See \`config.log' for more details." "$LINENO" 5; }
fi

ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu

ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
if test -z "$CXX"; then
  if test -n "$CCC"; then
    CXX=$CCC
  else
    if test -n "$ac_tool_prefix"; then
  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
  do
    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_CXX+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$CXX"; then
  ac_cv_prog_CXX="$CXX" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
CXX=$ac_cv_prog_CXX
if test -n "$CXX"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
$as_echo "$CXX" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


    test -n "$CXX" && break
  done
fi
if test -z "$CXX"; then
  ac_ct_CXX=$CXX
  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
do
  # Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_CXX"; then
  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_ac_ct_CXX="$ac_prog"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
if test -n "$ac_ct_CXX"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
$as_echo "$ac_ct_CXX" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


  test -n "$ac_ct_CXX" && break
done

  if test "x$ac_ct_CXX" = x; then
    CXX="g++"
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    CXX=$ac_ct_CXX
  fi
fi

  fi
fi
# Provide some information about the compiler.
$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
set X $ac_compile
ac_compiler=$2
for ac_option in --version -v -V -qversion; do
  { { ac_try="$ac_compiler $ac_option >&5"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
  ac_status=$?
  if test -s conftest.err; then
    sed '10a\
... rest of stderr output deleted ...
         10q' conftest.err >conftest.er1
    cat conftest.er1 >&5
  fi
  rm -f conftest.er1 conftest.err
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }
done

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
if test "${ac_cv_cxx_compiler_gnu+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{
#ifndef __GNUC__
       choke me
#endif

  ;
  return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
  ac_compiler_gnu=yes
else
  ac_compiler_gnu=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
ac_cv_cxx_compiler_gnu=$ac_compiler_gnu

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
if test $ac_compiler_gnu = yes; then
  GXX=yes
else
  GXX=
fi
ac_test_CXXFLAGS=${CXXFLAGS+set}
ac_save_CXXFLAGS=$CXXFLAGS
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
$as_echo_n "checking whether $CXX accepts -g... " >&6; }
if test "${ac_cv_prog_cxx_g+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  ac_save_cxx_werror_flag=$ac_cxx_werror_flag
   ac_cxx_werror_flag=yes
   ac_cv_prog_cxx_g=no
   CXXFLAGS="-g"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
  ac_cv_prog_cxx_g=yes
else
  CXXFLAGS=""
      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :

else
  ac_cxx_werror_flag=$ac_save_cxx_werror_flag
	 CXXFLAGS="-g"
	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
  ac_cv_prog_cxx_g=yes
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
   ac_cxx_werror_flag=$ac_save_cxx_werror_flag
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
$as_echo "$ac_cv_prog_cxx_g" >&6; }
if test "$ac_test_CXXFLAGS" = set; then
  CXXFLAGS=$ac_save_CXXFLAGS
elif test $ac_cv_prog_cxx_g = yes; then
  if test "$GXX" = yes; then
    CXXFLAGS="-g -O2"
  else
    CXXFLAGS="-g"
  fi
else
  if test "$GXX" = yes; then
    CXXFLAGS="-O2"
  else
    CXXFLAGS=
  fi
fi
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu

depcc="$CXX"  am_compiler_list=

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
$as_echo_n "checking dependency style of $depcc... " >&6; }
if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
  # We make a subdir and do the tests there.  Otherwise we can end up
  # making bogus files that we don't know about and never remove.  For
  # instance it was reported that on HP-UX the gcc test will end up
  # making a dummy file named `D' -- because `-MD' means `put the output
  # in D'.
  mkdir conftest.dir
  # Copy depcomp to subdir because otherwise we won't find it if we're
  # using a relative directory.
  cp "$am_depcomp" conftest.dir
  cd conftest.dir
  # We will build objects and dependencies in a subdirectory because
  # it helps to detect inapplicable dependency modes.  For instance
  # both Tru64's cc and ICC support -MD to output dependencies as a
  # side effect of compilation, but ICC will put the dependencies in
  # the current directory while Tru64 will put them in the object
  # directory.
  mkdir sub

  am_cv_CXX_dependencies_compiler_type=none
  if test "$am_compiler_list" = ""; then
     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
  fi
  for depmode in $am_compiler_list; do
    # Setup a source with many dependencies, because some compilers
    # like to wrap large dependency lists on column 80 (with \), and
    # we should not choose a depcomp mode which is confused by this.
    #
    # We need to recreate these files for each test, as the compiler may
    # overwrite some of them when testing with obscure command lines.
    # This happens at least with the AIX C compiler.
    : > sub/conftest.c
    for i in 1 2 3 4 5 6; do
      echo '#include "conftst'$i'.h"' >> sub/conftest.c
      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
      # Solaris 8's {/usr,}/bin/sh.
      touch sub/conftst$i.h
    done
    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf

    case $depmode in
    nosideeffect)
      # after this tag, mechanisms are not by side-effect, so they'll
      # only be used when explicitly requested
      if test "x$enable_dependency_tracking" = xyes; then
	continue
      else
	break
      fi
      ;;
    none) break ;;
    esac
    # We check with `-c' and `-o' for the sake of the "dashmstdout"
    # mode.  It turns out that the SunPro C++ compiler does not properly
    # handle `-M -o', and we need to detect this.
    if depmode=$depmode \
       source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
       $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
         >/dev/null 2>conftest.err &&
       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
       grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
      # icc doesn't choke on unknown options, it will just issue warnings
      # or remarks (even with -Werror).  So we grep stderr for any message
      # that says an option was ignored or not supported.
      # When given -MP, icc 7.0 and 7.1 complain thusly:
      #   icc: Command line warning: ignoring option '-M'; no argument required
      # The diagnosis changed in icc 8.0:
      #   icc: Command line remark: option '-MP' not supported
      if (grep 'ignoring option' conftest.err ||
          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
        am_cv_CXX_dependencies_compiler_type=$depmode
        break
      fi
    fi
  done

  cd ..
  rm -rf conftest.dir
else
  am_cv_CXX_dependencies_compiler_type=none
fi

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5
$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; }
CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type



if
  test "x$enable_dependency_tracking" != xno \
  && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then
  am__fastdepCXX_TRUE=
  am__fastdepCXX_FALSE='#'
else
  am__fastdepCXX_TRUE='#'
  am__fastdepCXX_FALSE=
fi




if test "$GCC" = yes; then
  GCC_TRUE=
  GCC_FALSE='#'
else
  GCC_TRUE='#'
  GCC_FALSE=
fi
   # let the Makefile know if we're gcc
if test "x$CC" != xcc; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC and cc understand -c and -o together" >&5
$as_echo_n "checking whether $CC and cc understand -c and -o together... " >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether cc understands -c and -o together" >&5
$as_echo_n "checking whether cc understands -c and -o together... " >&6; }
fi
set dummy $CC; ac_cc=`$as_echo "$2" |
		      sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'`
if { as_var=ac_cv_prog_cc_${ac_cc}_c_o; eval "test \"\${$as_var+set}\" = set"; }; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
# Make sure it works both with $CC and with simple cc.
# We do the test twice because some compilers refuse to overwrite an
# existing .o file with -o, though they will create one.
ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5'
rm -f conftest2.*
if { { case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_try") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } &&
   test -f conftest2.$ac_objext && { { case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_try") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; };
then
  eval ac_cv_prog_cc_${ac_cc}_c_o=yes
  if test "x$CC" != xcc; then
    # Test first that cc exists at all.
    if { ac_try='cc -c conftest.$ac_ext >&5'
  { { case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_try") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; }; then
      ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5'
      rm -f conftest2.*
      if { { case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_try") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } &&
	 test -f conftest2.$ac_objext && { { case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_try") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; };
      then
	# cc works too.
	:
      else
	# cc exists but doesn't like -o.
	eval ac_cv_prog_cc_${ac_cc}_c_o=no
      fi
    fi
  fi
else
  eval ac_cv_prog_cc_${ac_cc}_c_o=no
fi
rm -f core conftest*

fi
if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }

$as_echo "#define NO_MINUS_C_MINUS_O 1" >>confdefs.h

fi

# FIXME: we rely on the cache variable name because
# there is no other way.
set dummy $CC
ac_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'`
if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" != yes"; then
   # Losing compiler, so override with the script.
   # FIXME: It is wrong to rewrite CC.
   # But if we don't then we get into trouble of one sort or another.
   # A longer-term fix would be to have automake use am__CC in this case,
   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
   CC="$am_aux_dir/compile $CC"
fi
      # shrug: autogen.sh suddenly needs this for some reason

# Check if we have an objcopy installed that supports -W
if test -n "$ac_tool_prefix"; then
  # Extract the first word of "${ac_tool_prefix}objcopy", so it can be a program name with args.
set dummy ${ac_tool_prefix}objcopy; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_OBJCOPY+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$OBJCOPY"; then
  ac_cv_prog_OBJCOPY="$OBJCOPY" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_OBJCOPY="${ac_tool_prefix}objcopy"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
OBJCOPY=$ac_cv_prog_OBJCOPY
if test -n "$OBJCOPY"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJCOPY" >&5
$as_echo "$OBJCOPY" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


fi
if test -z "$ac_cv_prog_OBJCOPY"; then
  ac_ct_OBJCOPY=$OBJCOPY
  # Extract the first word of "objcopy", so it can be a program name with args.
set dummy objcopy; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_ac_ct_OBJCOPY+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_OBJCOPY"; then
  ac_cv_prog_ac_ct_OBJCOPY="$ac_ct_OBJCOPY" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_ac_ct_OBJCOPY="objcopy"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_OBJCOPY=$ac_cv_prog_ac_ct_OBJCOPY
if test -n "$ac_ct_OBJCOPY"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJCOPY" >&5
$as_echo "$ac_ct_OBJCOPY" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi

  if test "x$ac_ct_OBJCOPY" = x; then
    OBJCOPY=""
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    OBJCOPY=$ac_ct_OBJCOPY
  fi
else
  OBJCOPY="$ac_cv_prog_OBJCOPY"
fi



if "$OBJCOPY" -W malloc /bin/ls /dev/null; then
  HAVE_OBJCOPY_WEAKEN_TRUE=
  HAVE_OBJCOPY_WEAKEN_FALSE='#'
else
  HAVE_OBJCOPY_WEAKEN_TRUE='#'
  HAVE_OBJCOPY_WEAKEN_FALSE=
fi


case $host_os in
  *mingw*)
    # Disabling fast install keeps libtool from creating wrapper scripts
    # around the executables it builds.  Such scripts have caused failures on
    # MinGW.  Using this option means an extra link step is executed during
    # "make install".
    # Check whether --enable-fast-install was given.
if test "${enable_fast_install+set}" = set; then :
  enableval=$enable_fast_install; p=${PACKAGE-default}
    case $enableval in
    yes) enable_fast_install=yes ;;
    no) enable_fast_install=no ;;
    *)
      enable_fast_install=no
      # Look at the argument we got.  We use all the common list separators.
      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
      for pkg in $enableval; do
	IFS="$lt_save_ifs"
	if test "X$pkg" = "X$p"; then
	  enable_fast_install=yes
	fi
      done
      IFS="$lt_save_ifs"
      ;;
    esac
else
  enable_fast_install=no
fi









    ;;
   *)
    # Check whether --enable-fast-install was given.
if test "${enable_fast_install+set}" = set; then :
  enableval=$enable_fast_install; p=${PACKAGE-default}
    case $enableval in
    yes) enable_fast_install=yes ;;
    no) enable_fast_install=no ;;
    *)
      enable_fast_install=no
      # Look at the argument we got.  We use all the common list separators.
      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
      for pkg in $enableval; do
	IFS="$lt_save_ifs"
	if test "X$pkg" = "X$p"; then
	  enable_fast_install=yes
	fi
      done
      IFS="$lt_save_ifs"
      ;;
    esac
else
  enable_fast_install=yes
fi






    ;;
esac

case `pwd` in
  *\ * | *\	*)
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
esac



macro_version='2.2.6b'
macro_revision='1.3017'













ltmain="$ac_aux_dir/ltmain.sh"

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
$as_echo_n "checking for a sed that does not truncate output... " >&6; }
if test "${ac_cv_path_SED+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
            ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
     for ac_i in 1 2 3 4 5 6 7; do
       ac_script="$ac_script$as_nl$ac_script"
     done
     echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
     { ac_script=; unset ac_script;}
     if test -z "$SED"; then
  ac_path_SED_found=false
  # Loop through the user's path and test for each of PROGNAME-LIST
  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_prog in sed gsed; do
    for ac_exec_ext in '' $ac_executable_extensions; do
      ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
      { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue
# Check for GNU ac_path_SED and select it if it is found.
  # Check for GNU $ac_path_SED
case `"$ac_path_SED" --version 2>&1` in
*GNU*)
  ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
*)
  ac_count=0
  $as_echo_n 0123456789 >"conftest.in"
  while :
  do
    cat "conftest.in" "conftest.in" >"conftest.tmp"
    mv "conftest.tmp" "conftest.in"
    cp "conftest.in" "conftest.nl"
    $as_echo '' >> "conftest.nl"
    "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
    as_fn_arith $ac_count + 1 && ac_count=$as_val
    if test $ac_count -gt ${ac_path_SED_max-0}; then
      # Best one so far, save it but keep looking for a better one
      ac_cv_path_SED="$ac_path_SED"
      ac_path_SED_max=$ac_count
    fi
    # 10*(2^10) chars as input seems more than enough
    test $ac_count -gt 10 && break
  done
  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
esac

      $ac_path_SED_found && break 3
    done
  done
  done
IFS=$as_save_IFS
  if test -z "$ac_cv_path_SED"; then
    as_fn_error "no acceptable sed could be found in \$PATH" "$LINENO" 5
  fi
else
  ac_cv_path_SED=$SED
fi

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
$as_echo "$ac_cv_path_SED" >&6; }
 SED="$ac_cv_path_SED"
  rm -f conftest.sed

test -z "$SED" && SED=sed
Xsed="$SED -e 1s/^X//"











{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
if test "${ac_cv_path_GREP+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -z "$GREP"; then
  ac_path_GREP_found=false
  # Loop through the user's path and test for each of PROGNAME-LIST
  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_prog in grep ggrep; do
    for ac_exec_ext in '' $ac_executable_extensions; do
      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
# Check for GNU ac_path_GREP and select it if it is found.
  # Check for GNU $ac_path_GREP
case `"$ac_path_GREP" --version 2>&1` in
*GNU*)
  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
*)
  ac_count=0
  $as_echo_n 0123456789 >"conftest.in"
  while :
  do
    cat "conftest.in" "conftest.in" >"conftest.tmp"
    mv "conftest.tmp" "conftest.in"
    cp "conftest.in" "conftest.nl"
    $as_echo 'GREP' >> "conftest.nl"
    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
    as_fn_arith $ac_count + 1 && ac_count=$as_val
    if test $ac_count -gt ${ac_path_GREP_max-0}; then
      # Best one so far, save it but keep looking for a better one
      ac_cv_path_GREP="$ac_path_GREP"
      ac_path_GREP_max=$ac_count
    fi
    # 10*(2^10) chars as input seems more than enough
    test $ac_count -gt 10 && break
  done
  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
esac

      $ac_path_GREP_found && break 3
    done
  done
  done
IFS=$as_save_IFS
  if test -z "$ac_cv_path_GREP"; then
    as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
  fi
else
  ac_cv_path_GREP=$GREP
fi

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
$as_echo "$ac_cv_path_GREP" >&6; }
 GREP="$ac_cv_path_GREP"


{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
$as_echo_n "checking for egrep... " >&6; }
if test "${ac_cv_path_EGREP+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
   then ac_cv_path_EGREP="$GREP -E"
   else
     if test -z "$EGREP"; then
  ac_path_EGREP_found=false
  # Loop through the user's path and test for each of PROGNAME-LIST
  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_prog in egrep; do
    for ac_exec_ext in '' $ac_executable_extensions; do
      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
# Check for GNU ac_path_EGREP and select it if it is found.
  # Check for GNU $ac_path_EGREP
case `"$ac_path_EGREP" --version 2>&1` in
*GNU*)
  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
*)
  ac_count=0
  $as_echo_n 0123456789 >"conftest.in"
  while :
  do
    cat "conftest.in" "conftest.in" >"conftest.tmp"
    mv "conftest.tmp" "conftest.in"
    cp "conftest.in" "conftest.nl"
    $as_echo 'EGREP' >> "conftest.nl"
    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
    as_fn_arith $ac_count + 1 && ac_count=$as_val
    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
      # Best one so far, save it but keep looking for a better one
      ac_cv_path_EGREP="$ac_path_EGREP"
      ac_path_EGREP_max=$ac_count
    fi
    # 10*(2^10) chars as input seems more than enough
    test $ac_count -gt 10 && break
  done
  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
esac

      $ac_path_EGREP_found && break 3
    done
  done
  done
IFS=$as_save_IFS
  if test -z "$ac_cv_path_EGREP"; then
    as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
  fi
else
  ac_cv_path_EGREP=$EGREP
fi

   fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
$as_echo "$ac_cv_path_EGREP" >&6; }
 EGREP="$ac_cv_path_EGREP"


{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
$as_echo_n "checking for fgrep... " >&6; }
if test "${ac_cv_path_FGREP+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
   then ac_cv_path_FGREP="$GREP -F"
   else
     if test -z "$FGREP"; then
  ac_path_FGREP_found=false
  # Loop through the user's path and test for each of PROGNAME-LIST
  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_prog in fgrep; do
    for ac_exec_ext in '' $ac_executable_extensions; do
      ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
      { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue
# Check for GNU ac_path_FGREP and select it if it is found.
  # Check for GNU $ac_path_FGREP
case `"$ac_path_FGREP" --version 2>&1` in
*GNU*)
  ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
*)
  ac_count=0
  $as_echo_n 0123456789 >"conftest.in"
  while :
  do
    cat "conftest.in" "conftest.in" >"conftest.tmp"
    mv "conftest.tmp" "conftest.in"
    cp "conftest.in" "conftest.nl"
    $as_echo 'FGREP' >> "conftest.nl"
    "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
    as_fn_arith $ac_count + 1 && ac_count=$as_val
    if test $ac_count -gt ${ac_path_FGREP_max-0}; then
      # Best one so far, save it but keep looking for a better one
      ac_cv_path_FGREP="$ac_path_FGREP"
      ac_path_FGREP_max=$ac_count
    fi
    # 10*(2^10) chars as input seems more than enough
    test $ac_count -gt 10 && break
  done
  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
esac

      $ac_path_FGREP_found && break 3
    done
  done
  done
IFS=$as_save_IFS
  if test -z "$ac_cv_path_FGREP"; then
    as_fn_error "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
  fi
else
  ac_cv_path_FGREP=$FGREP
fi

   fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
$as_echo "$ac_cv_path_FGREP" >&6; }
 FGREP="$ac_cv_path_FGREP"


test -z "$GREP" && GREP=grep



















# Check whether --with-gnu-ld was given.
if test "${with_gnu_ld+set}" = set; then :
  withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
else
  with_gnu_ld=no
fi

ac_prog=ld
if test "$GCC" = yes; then
  # Check if gcc -print-prog-name=ld gives a path.
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
$as_echo_n "checking for ld used by $CC... " >&6; }
  case $host in
  *-*-mingw*)
    # gcc leaves a trailing carriage return which upsets mingw
    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
  *)
    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
  esac
  case $ac_prog in
    # Accept absolute paths.
    [\\/]* | ?:[\\/]*)
      re_direlt='/[^/][^/]*/\.\./'
      # Canonicalize the pathname of ld
      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
      done
      test -z "$LD" && LD="$ac_prog"
      ;;
  "")
    # If it fails, then pretend we aren't using GCC.
    ac_prog=ld
    ;;
  *)
    # If it is relative, then search for the first ld in PATH.
    with_gnu_ld=unknown
    ;;
  esac
elif test "$with_gnu_ld" = yes; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
$as_echo_n "checking for GNU ld... " >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
$as_echo_n "checking for non-GNU ld... " >&6; }
fi
if test "${lt_cv_path_LD+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -z "$LD"; then
  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
  for ac_dir in $PATH; do
    IFS="$lt_save_ifs"
    test -z "$ac_dir" && ac_dir=.
    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
      lt_cv_path_LD="$ac_dir/$ac_prog"
      # Check to see if the program is GNU ld.  I'd rather use --version,
      # but apparently some variants of GNU ld only accept -v.
      # Break only if it was the GNU/non-GNU ld that we prefer.
      case `"$lt_cv_path_LD" -v 2>&1 &5
$as_echo "$LD" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
test -z "$LD" && as_fn_error "no acceptable ld found in \$PATH" "$LINENO" 5
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
if test "${lt_cv_prog_gnu_ld+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  # I'd rather use --version here, but apparently some GNU lds only accept -v.
case `$LD -v 2>&1 &5
$as_echo "$lt_cv_prog_gnu_ld" >&6; }
with_gnu_ld=$lt_cv_prog_gnu_ld









{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
if test "${lt_cv_path_NM+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$NM"; then
  # Let the user override the test.
  lt_cv_path_NM="$NM"
else
  lt_nm_to_check="${ac_tool_prefix}nm"
  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
    lt_nm_to_check="$lt_nm_to_check nm"
  fi
  for lt_tmp_nm in $lt_nm_to_check; do
    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
      IFS="$lt_save_ifs"
      test -z "$ac_dir" && ac_dir=.
      tmp_nm="$ac_dir/$lt_tmp_nm"
      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
	# Check to see if the nm accepts a BSD-compat flag.
	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
	#   nm: unknown option "B" ignored
	# Tru64's nm complains that /dev/null is an invalid object file
	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
	*/dev/null* | *'Invalid file or object type'*)
	  lt_cv_path_NM="$tmp_nm -B"
	  break
	  ;;
	*)
	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
	  */dev/null*)
	    lt_cv_path_NM="$tmp_nm -p"
	    break
	    ;;
	  *)
	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
	    continue # so that we can try to find one that supports BSD flags
	    ;;
	  esac
	  ;;
	esac
      fi
    done
    IFS="$lt_save_ifs"
  done
  : ${lt_cv_path_NM=no}
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
$as_echo "$lt_cv_path_NM" >&6; }
if test "$lt_cv_path_NM" != "no"; then
  NM="$lt_cv_path_NM"
else
  # Didn't find any BSD compatible name lister, look for dumpbin.
  if test -n "$ac_tool_prefix"; then
  for ac_prog in "dumpbin -symbols" "link -dump -symbols"
  do
    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_DUMPBIN+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$DUMPBIN"; then
  ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
DUMPBIN=$ac_cv_prog_DUMPBIN
if test -n "$DUMPBIN"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
$as_echo "$DUMPBIN" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


    test -n "$DUMPBIN" && break
  done
fi
if test -z "$DUMPBIN"; then
  ac_ct_DUMPBIN=$DUMPBIN
  for ac_prog in "dumpbin -symbols" "link -dump -symbols"
do
  # Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_DUMPBIN"; then
  ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
if test -n "$ac_ct_DUMPBIN"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
$as_echo "$ac_ct_DUMPBIN" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


  test -n "$ac_ct_DUMPBIN" && break
done

  if test "x$ac_ct_DUMPBIN" = x; then
    DUMPBIN=":"
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    DUMPBIN=$ac_ct_DUMPBIN
  fi
fi


  if test "$DUMPBIN" != ":"; then
    NM="$DUMPBIN"
  fi
fi
test -z "$NM" && NM=nm






{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
$as_echo_n "checking the name lister ($NM) interface... " >&6; }
if test "${lt_cv_nm_interface+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  lt_cv_nm_interface="BSD nm"
  echo "int some_variable = 0;" > conftest.$ac_ext
  (eval echo "\"\$as_me:5584: $ac_compile\"" >&5)
  (eval "$ac_compile" 2>conftest.err)
  cat conftest.err >&5
  (eval echo "\"\$as_me:5587: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
  cat conftest.err >&5
  (eval echo "\"\$as_me:5590: output\"" >&5)
  cat conftest.out >&5
  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
    lt_cv_nm_interface="MS dumpbin"
  fi
  rm -f conftest*
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
$as_echo "$lt_cv_nm_interface" >&6; }

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
$as_echo_n "checking whether ln -s works... " >&6; }
LN_S=$as_ln_s
if test "$LN_S" = "ln -s"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
$as_echo "no, using $LN_S" >&6; }
fi

# find the maximum length of command line arguments
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
$as_echo_n "checking the maximum length of command line arguments... " >&6; }
if test "${lt_cv_sys_max_cmd_len+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
    i=0
  teststring="ABCD"

  case $build_os in
  msdosdjgpp*)
    # On DJGPP, this test can blow up pretty badly due to problems in libc
    # (any single argument exceeding 2000 bytes causes a buffer overrun
    # during glob expansion).  Even if it were fixed, the result of this
    # check would be larger than it should be.
    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
    ;;

  gnu*)
    # Under GNU Hurd, this test is not required because there is
    # no limit to the length of command line arguments.
    # Libtool will interpret -1 as no limit whatsoever
    lt_cv_sys_max_cmd_len=-1;
    ;;

  cygwin* | mingw* | cegcc*)
    # On Win9x/ME, this test blows up -- it succeeds, but takes
    # about 5 minutes as the teststring grows exponentially.
    # Worse, since 9x/ME are not pre-emptively multitasking,
    # you end up with a "frozen" computer, even though with patience
    # the test eventually succeeds (with a max line length of 256k).
    # Instead, let's just punt: use the minimum linelength reported by
    # all of the supported platforms: 8192 (on NT/2K/XP).
    lt_cv_sys_max_cmd_len=8192;
    ;;

  amigaos*)
    # On AmigaOS with pdksh, this test takes hours, literally.
    # So we just punt and use a minimum line length of 8192.
    lt_cv_sys_max_cmd_len=8192;
    ;;

  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
    # This has been around since 386BSD, at least.  Likely further.
    if test -x /sbin/sysctl; then
      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
    elif test -x /usr/sbin/sysctl; then
      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
    else
      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
    fi
    # And add a safety zone
    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
    ;;

  interix*)
    # We know the value 262144 and hardcode it with a safety zone (like BSD)
    lt_cv_sys_max_cmd_len=196608
    ;;

  osf*)
    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
    # nice to cause kernel panics so lets avoid the loop below.
    # First set a reasonable default.
    lt_cv_sys_max_cmd_len=16384
    #
    if test -x /sbin/sysconfig; then
      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
        *1*) lt_cv_sys_max_cmd_len=-1 ;;
      esac
    fi
    ;;
  sco3.2v5*)
    lt_cv_sys_max_cmd_len=102400
    ;;
  sysv5* | sco5v6* | sysv4.2uw2*)
    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
    if test -n "$kargmax"; then
      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[	 ]//'`
    else
      lt_cv_sys_max_cmd_len=32768
    fi
    ;;
  *)
    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
    if test -n "$lt_cv_sys_max_cmd_len"; then
      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
    else
      # Make teststring a little bigger before we do anything with it.
      # a 1K string should be a reasonable start.
      for i in 1 2 3 4 5 6 7 8 ; do
        teststring=$teststring$teststring
      done
      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
      # If test is not a shell built-in, we'll probably end up computing a
      # maximum length that is only half of the actual maximum length, but
      # we can't tell.
      while { test "X"`$SHELL $0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \
	         = "XX$teststring$teststring"; } >/dev/null 2>&1 &&
	      test $i != 17 # 1/2 MB should be enough
      do
        i=`expr $i + 1`
        teststring=$teststring$teststring
      done
      # Only check the string length outside the loop.
      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
      teststring=
      # Add a significant safety factor because C++ compilers can tack on
      # massive amounts of additional arguments before passing them to the
      # linker.  It appears as though 1/2 is a usable value.
      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
    fi
    ;;
  esac

fi

if test -n $lt_cv_sys_max_cmd_len ; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
$as_echo "none" >&6; }
fi
max_cmd_len=$lt_cv_sys_max_cmd_len






: ${CP="cp -f"}
: ${MV="mv -f"}
: ${RM="rm -f"}

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5
$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; }
# Try some XSI features
xsi_shell=no
( _lt_dummy="a/b/c"
  test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \
      = c,a/b,, \
    && eval 'test $(( 1 + 1 )) -eq 2 \
    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
  && xsi_shell=yes
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5
$as_echo "$xsi_shell" >&6; }


{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5
$as_echo_n "checking whether the shell understands \"+=\"... " >&6; }
lt_shell_append=no
( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \
    >/dev/null 2>&1 \
  && lt_shell_append=yes
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5
$as_echo "$lt_shell_append" >&6; }


if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
  lt_unset=unset
else
  lt_unset=false
fi





# test EBCDIC or ASCII
case `echo X|tr X '\101'` in
 A) # ASCII based system
    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
  lt_SP2NL='tr \040 \012'
  lt_NL2SP='tr \015\012 \040\040'
  ;;
 *) # EBCDIC based system
  lt_SP2NL='tr \100 \n'
  lt_NL2SP='tr \r\n \100\100'
  ;;
esac









{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
$as_echo_n "checking for $LD option to reload object files... " >&6; }
if test "${lt_cv_ld_reload_flag+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  lt_cv_ld_reload_flag='-r'
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
$as_echo "$lt_cv_ld_reload_flag" >&6; }
reload_flag=$lt_cv_ld_reload_flag
case $reload_flag in
"" | " "*) ;;
*) reload_flag=" $reload_flag" ;;
esac
reload_cmds='$LD$reload_flag -o $output$reload_objs'
case $host_os in
  darwin*)
    if test "$GCC" = yes; then
      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
    else
      reload_cmds='$LD$reload_flag -o $output$reload_objs'
    fi
    ;;
esac









if test -n "$ac_tool_prefix"; then
  # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
set dummy ${ac_tool_prefix}objdump; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_OBJDUMP+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$OBJDUMP"; then
  ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
OBJDUMP=$ac_cv_prog_OBJDUMP
if test -n "$OBJDUMP"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
$as_echo "$OBJDUMP" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


fi
if test -z "$ac_cv_prog_OBJDUMP"; then
  ac_ct_OBJDUMP=$OBJDUMP
  # Extract the first word of "objdump", so it can be a program name with args.
set dummy objdump; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_OBJDUMP"; then
  ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_ac_ct_OBJDUMP="objdump"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
if test -n "$ac_ct_OBJDUMP"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
$as_echo "$ac_ct_OBJDUMP" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi

  if test "x$ac_ct_OBJDUMP" = x; then
    OBJDUMP="false"
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    OBJDUMP=$ac_ct_OBJDUMP
  fi
else
  OBJDUMP="$ac_cv_prog_OBJDUMP"
fi

test -z "$OBJDUMP" && OBJDUMP=objdump









{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
$as_echo_n "checking how to recognize dependent libraries... " >&6; }
if test "${lt_cv_deplibs_check_method+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  lt_cv_file_magic_cmd='$MAGIC_CMD'
lt_cv_file_magic_test_file=
lt_cv_deplibs_check_method='unknown'
# Need to set the preceding variable on all platforms that support
# interlibrary dependencies.
# 'none' -- dependencies not supported.
# `unknown' -- same as none, but documents that we really don't know.
# 'pass_all' -- all dependencies passed with no checks.
# 'test_compile' -- check by making test program.
# 'file_magic [[regex]]' -- check by looking for files in library path
# which responds to the $file_magic_cmd with a given extended regex.
# If you have `file' or equivalent on your system and you're not sure
# whether `pass_all' will *always* work, you probably want this one.

case $host_os in
aix[4-9]*)
  lt_cv_deplibs_check_method=pass_all
  ;;

beos*)
  lt_cv_deplibs_check_method=pass_all
  ;;

bsdi[45]*)
  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
  lt_cv_file_magic_cmd='/usr/bin/file -L'
  lt_cv_file_magic_test_file=/shlib/libc.so
  ;;

cygwin*)
  # func_win32_libid is a shell function defined in ltmain.sh
  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
  lt_cv_file_magic_cmd='func_win32_libid'
  ;;

mingw* | pw32*)
  # Base MSYS/MinGW do not provide the 'file' command needed by
  # func_win32_libid shell function, so use a weaker test based on 'objdump',
  # unless we find 'file', for example because we are cross-compiling.
  if ( file / ) >/dev/null 2>&1; then
    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
    lt_cv_file_magic_cmd='func_win32_libid'
  else
    lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
    lt_cv_file_magic_cmd='$OBJDUMP -f'
  fi
  ;;

cegcc)
  # use the weaker test based on 'objdump'. See mingw*.
  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
  lt_cv_file_magic_cmd='$OBJDUMP -f'
  ;;

darwin* | rhapsody*)
  lt_cv_deplibs_check_method=pass_all
  ;;

freebsd* | dragonfly*)
  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
    case $host_cpu in
    i*86 )
      # Not sure whether the presence of OpenBSD here was a mistake.
      # Let's accept both of them until this is cleared up.
      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
      lt_cv_file_magic_cmd=/usr/bin/file
      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
      ;;
    esac
  else
    lt_cv_deplibs_check_method=pass_all
  fi
  ;;

gnu*)
  lt_cv_deplibs_check_method=pass_all
  ;;

hpux10.20* | hpux11*)
  lt_cv_file_magic_cmd=/usr/bin/file
  case $host_cpu in
  ia64*)
    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
    ;;
  hppa*64*)
    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'
    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
    ;;
  *)
    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library'
    lt_cv_file_magic_test_file=/usr/lib/libc.sl
    ;;
  esac
  ;;

interix[3-9]*)
  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
  lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
  ;;

irix5* | irix6* | nonstopux*)
  case $LD in
  *-32|*"-32 ") libmagic=32-bit;;
  *-n32|*"-n32 ") libmagic=N32;;
  *-64|*"-64 ") libmagic=64-bit;;
  *) libmagic=never-match;;
  esac
  lt_cv_deplibs_check_method=pass_all
  ;;

# This must be Linux ELF.
linux* | k*bsd*-gnu | kopensolaris*-gnu)
  lt_cv_deplibs_check_method=pass_all
  ;;

netbsd* | netbsdelf*-gnu)
  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
  else
    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
  fi
  ;;

newos6*)
  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
  lt_cv_file_magic_cmd=/usr/bin/file
  lt_cv_file_magic_test_file=/usr/lib/libnls.so
  ;;

*nto* | *qnx*)
  lt_cv_deplibs_check_method=pass_all
  ;;

openbsd*)
  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
  else
    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
  fi
  ;;

osf3* | osf4* | osf5*)
  lt_cv_deplibs_check_method=pass_all
  ;;

rdos*)
  lt_cv_deplibs_check_method=pass_all
  ;;

solaris*)
  lt_cv_deplibs_check_method=pass_all
  ;;

sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
  lt_cv_deplibs_check_method=pass_all
  ;;

sysv4 | sysv4.3*)
  case $host_vendor in
  motorola)
    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
    ;;
  ncr)
    lt_cv_deplibs_check_method=pass_all
    ;;
  sequent)
    lt_cv_file_magic_cmd='/bin/file'
    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
    ;;
  sni)
    lt_cv_file_magic_cmd='/bin/file'
    lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
    lt_cv_file_magic_test_file=/lib/libc.so
    ;;
  siemens)
    lt_cv_deplibs_check_method=pass_all
    ;;
  pc)
    lt_cv_deplibs_check_method=pass_all
    ;;
  esac
  ;;

tpf*)
  lt_cv_deplibs_check_method=pass_all
  ;;
esac

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
$as_echo "$lt_cv_deplibs_check_method" >&6; }
file_magic_cmd=$lt_cv_file_magic_cmd
deplibs_check_method=$lt_cv_deplibs_check_method
test -z "$deplibs_check_method" && deplibs_check_method=unknown












if test -n "$ac_tool_prefix"; then
  # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
set dummy ${ac_tool_prefix}ar; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_AR+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$AR"; then
  ac_cv_prog_AR="$AR" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_AR="${ac_tool_prefix}ar"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
AR=$ac_cv_prog_AR
if test -n "$AR"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
$as_echo "$AR" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


fi
if test -z "$ac_cv_prog_AR"; then
  ac_ct_AR=$AR
  # Extract the first word of "ar", so it can be a program name with args.
set dummy ar; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_ac_ct_AR+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_AR"; then
  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_ac_ct_AR="ar"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_AR=$ac_cv_prog_ac_ct_AR
if test -n "$ac_ct_AR"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
$as_echo "$ac_ct_AR" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi

  if test "x$ac_ct_AR" = x; then
    AR="false"
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    AR=$ac_ct_AR
  fi
else
  AR="$ac_cv_prog_AR"
fi

test -z "$AR" && AR=ar
test -z "$AR_FLAGS" && AR_FLAGS=cru











if test -n "$ac_tool_prefix"; then
  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
set dummy ${ac_tool_prefix}strip; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_STRIP+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$STRIP"; then
  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
STRIP=$ac_cv_prog_STRIP
if test -n "$STRIP"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
$as_echo "$STRIP" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


fi
if test -z "$ac_cv_prog_STRIP"; then
  ac_ct_STRIP=$STRIP
  # Extract the first word of "strip", so it can be a program name with args.
set dummy strip; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_STRIP"; then
  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_ac_ct_STRIP="strip"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
if test -n "$ac_ct_STRIP"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
$as_echo "$ac_ct_STRIP" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi

  if test "x$ac_ct_STRIP" = x; then
    STRIP=":"
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    STRIP=$ac_ct_STRIP
  fi
else
  STRIP="$ac_cv_prog_STRIP"
fi

test -z "$STRIP" && STRIP=:






if test -n "$ac_tool_prefix"; then
  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
set dummy ${ac_tool_prefix}ranlib; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_RANLIB+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$RANLIB"; then
  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
RANLIB=$ac_cv_prog_RANLIB
if test -n "$RANLIB"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
$as_echo "$RANLIB" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


fi
if test -z "$ac_cv_prog_RANLIB"; then
  ac_ct_RANLIB=$RANLIB
  # Extract the first word of "ranlib", so it can be a program name with args.
set dummy ranlib; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_RANLIB"; then
  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_ac_ct_RANLIB="ranlib"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
if test -n "$ac_ct_RANLIB"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
$as_echo "$ac_ct_RANLIB" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi

  if test "x$ac_ct_RANLIB" = x; then
    RANLIB=":"
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    RANLIB=$ac_ct_RANLIB
  fi
else
  RANLIB="$ac_cv_prog_RANLIB"
fi

test -z "$RANLIB" && RANLIB=:






# Determine commands to create old-style static archives.
old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
old_postinstall_cmds='chmod 644 $oldlib'
old_postuninstall_cmds=

if test -n "$RANLIB"; then
  case $host_os in
  openbsd*)
    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
    ;;
  *)
    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
    ;;
  esac
  old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
fi


































# If no C compiler was specified, use CC.
LTCC=${LTCC-"$CC"}

# If no C compiler flags were specified, use CFLAGS.
LTCFLAGS=${LTCFLAGS-"$CFLAGS"}

# Allow CC to be a program name with arguments.
compiler=$CC


# Check for command to grab the raw symbol name followed by C symbol from nm.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then :
  $as_echo_n "(cached) " >&6
else

# These are sane defaults that work on at least a few old systems.
# [They come from Ultrix.  What could be older than Ultrix?!! ;)]

# Character class describing NM global symbol codes.
symcode='[BCDEGRST]'

# Regexp to match symbols that can be accessed directly from C.
sympat='\([_A-Za-z][_A-Za-z0-9]*\)'

# Define system-specific variables.
case $host_os in
aix*)
  symcode='[BCDT]'
  ;;
cygwin* | mingw* | pw32* | cegcc*)
  symcode='[ABCDGISTW]'
  ;;
hpux*)
  if test "$host_cpu" = ia64; then
    symcode='[ABCDEGRST]'
  fi
  ;;
irix* | nonstopux*)
  symcode='[BCDEGRST]'
  ;;
osf*)
  symcode='[BCDEGQRST]'
  ;;
solaris*)
  symcode='[BDRT]'
  ;;
sco3.2v5*)
  symcode='[DT]'
  ;;
sysv4.2uw2*)
  symcode='[DT]'
  ;;
sysv5* | sco5v6* | unixware* | OpenUNIX*)
  symcode='[ABDT]'
  ;;
sysv4)
  symcode='[DFNSTU]'
  ;;
esac

# If we're using GNU nm, then use its standard symbol codes.
case `$NM -V 2>&1` in
*GNU* | *'with BFD'*)
  symcode='[ABCDGIRSTW]' ;;
esac

# Transform an extracted symbol line into a proper C declaration.
# Some systems (esp. on ia64) link data and code symbols differently,
# so use this general approach.
lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"

# Transform an extracted symbol line into symbol name and symbol address
lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/  {\"\2\", (void *) \&\2},/p'"
lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/  {\"lib\2\", (void *) \&\2},/p'"

# Handle CRLF in mingw tool chain
opt_cr=
case $build_os in
mingw*)
  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
  ;;
esac

# Try without a prefix underscore, then with it.
for ac_symprfx in "" "_"; do

  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
  symxfrm="\\1 $ac_symprfx\\2 \\2"

  # Write the raw and C identifiers.
  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
    # Fake it for dumpbin and say T for any non-static function
    # and D for any global variable.
    # Also find C++ and __fastcall symbols from MSVC++,
    # which start with @ or ?.
    lt_cv_sys_global_symbol_pipe="$AWK '"\
"     {last_section=section; section=\$ 3};"\
"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
"     \$ 0!~/External *\|/{next};"\
"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
"     {if(hide[section]) next};"\
"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
"     ' prfx=^$ac_symprfx"
  else
    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[	 ]\($symcode$symcode*\)[	 ][	 ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
  fi

  # Check to see that the pipe works correctly.
  pipe_works=no

  rm -f conftest*
  cat > conftest.$ac_ext <<_LT_EOF
#ifdef __cplusplus
extern "C" {
#endif
char nm_test_var;
void nm_test_func(void);
void nm_test_func(void){}
#ifdef __cplusplus
}
#endif
int main(){nm_test_var='a';nm_test_func();return(0);}
_LT_EOF

  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
  (eval $ac_compile) 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; then
    # Now try to grab the symbols.
    nlist=conftest.nm
    if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\""; } >&5
  (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } && test -s "$nlist"; then
      # Try sorting and uniquifying the output.
      if sort "$nlist" | uniq > "$nlist"T; then
	mv -f "$nlist"T "$nlist"
      else
	rm -f "$nlist"T
      fi

      # Make sure that we snagged all the symbols we need.
      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
	  cat <<_LT_EOF > conftest.$ac_ext
#ifdef __cplusplus
extern "C" {
#endif

_LT_EOF
	  # Now generate the symbol file.
	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'

	  cat <<_LT_EOF >> conftest.$ac_ext

/* The mapping between symbol names and symbols.  */
const struct {
  const char *name;
  void       *address;
}
lt__PROGRAM__LTX_preloaded_symbols[] =
{
  { "@PROGRAM@", (void *) 0 },
_LT_EOF
	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
	  cat <<\_LT_EOF >> conftest.$ac_ext
  {0, (void *) 0}
};

/* This works around a problem in FreeBSD linker */
#ifdef FREEBSD_WORKAROUND
static const void *lt_preloaded_setup() {
  return lt__PROGRAM__LTX_preloaded_symbols;
}
#endif

#ifdef __cplusplus
}
#endif
_LT_EOF
	  # Now try linking the two files.
	  mv conftest.$ac_objext conftstm.$ac_objext
	  lt_save_LIBS="$LIBS"
	  lt_save_CFLAGS="$CFLAGS"
	  LIBS="conftstm.$ac_objext"
	  CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
  (eval $ac_link) 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } && test -s conftest${ac_exeext}; then
	    pipe_works=yes
	  fi
	  LIBS="$lt_save_LIBS"
	  CFLAGS="$lt_save_CFLAGS"
	else
	  echo "cannot find nm_test_func in $nlist" >&5
	fi
      else
	echo "cannot find nm_test_var in $nlist" >&5
      fi
    else
      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
    fi
  else
    echo "$progname: failed program was:" >&5
    cat conftest.$ac_ext >&5
  fi
  rm -rf conftest* conftst*

  # Do not use the global_symbol_pipe unless it works.
  if test "$pipe_works" = yes; then
    break
  else
    lt_cv_sys_global_symbol_pipe=
  fi
done

fi

if test -z "$lt_cv_sys_global_symbol_pipe"; then
  lt_cv_sys_global_symbol_to_cdecl=
fi
if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
$as_echo "failed" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
$as_echo "ok" >&6; }
fi























# Check whether --enable-libtool-lock was given.
if test "${enable_libtool_lock+set}" = set; then :
  enableval=$enable_libtool_lock;
fi

test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes

# Some flags need to be propagated to the compiler or linker for good
# libtool support.
case $host in
ia64-*-hpux*)
  # Find out which ABI we are using.
  echo 'int i;' > conftest.$ac_ext
  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
  (eval $ac_compile) 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; then
    case `/usr/bin/file conftest.$ac_objext` in
      *ELF-32*)
	HPUX_IA64_MODE="32"
	;;
      *ELF-64*)
	HPUX_IA64_MODE="64"
	;;
    esac
  fi
  rm -rf conftest*
  ;;
*-*-irix6*)
  # Find out which ABI we are using.
  echo '#line 6796 "configure"' > conftest.$ac_ext
  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
  (eval $ac_compile) 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; then
    if test "$lt_cv_prog_gnu_ld" = yes; then
      case `/usr/bin/file conftest.$ac_objext` in
	*32-bit*)
	  LD="${LD-ld} -melf32bsmip"
	  ;;
	*N32*)
	  LD="${LD-ld} -melf32bmipn32"
	  ;;
	*64-bit*)
	  LD="${LD-ld} -melf64bmip"
	;;
      esac
    else
      case `/usr/bin/file conftest.$ac_objext` in
	*32-bit*)
	  LD="${LD-ld} -32"
	  ;;
	*N32*)
	  LD="${LD-ld} -n32"
	  ;;
	*64-bit*)
	  LD="${LD-ld} -64"
	  ;;
      esac
    fi
  fi
  rm -rf conftest*
  ;;

x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
  # Find out which ABI we are using.
  echo 'int i;' > conftest.$ac_ext
  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
  (eval $ac_compile) 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; then
    case `/usr/bin/file conftest.o` in
      *32-bit*)
	case $host in
	  x86_64-*kfreebsd*-gnu)
	    LD="${LD-ld} -m elf_i386_fbsd"
	    ;;
	  x86_64-*linux*)
	    LD="${LD-ld} -m elf_i386"
	    ;;
	  ppc64-*linux*|powerpc64-*linux*)
	    LD="${LD-ld} -m elf32ppclinux"
	    ;;
	  s390x-*linux*)
	    LD="${LD-ld} -m elf_s390"
	    ;;
	  sparc64-*linux*)
	    LD="${LD-ld} -m elf32_sparc"
	    ;;
	esac
	;;
      *64-bit*)
	case $host in
	  x86_64-*kfreebsd*-gnu)
	    LD="${LD-ld} -m elf_x86_64_fbsd"
	    ;;
	  x86_64-*linux*)
	    LD="${LD-ld} -m elf_x86_64"
	    ;;
	  ppc*-*linux*|powerpc*-*linux*)
	    LD="${LD-ld} -m elf64ppc"
	    ;;
	  s390*-*linux*|s390*-*tpf*)
	    LD="${LD-ld} -m elf64_s390"
	    ;;
	  sparc*-*linux*)
	    LD="${LD-ld} -m elf64_sparc"
	    ;;
	esac
	;;
    esac
  fi
  rm -rf conftest*
  ;;

*-*-sco3.2v5*)
  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
  SAVE_CFLAGS="$CFLAGS"
  CFLAGS="$CFLAGS -belf"
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
if test "${lt_cv_cc_needs_belf+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu

     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  lt_cv_cc_needs_belf=yes
else
  lt_cv_cc_needs_belf=no
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
     ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
$as_echo "$lt_cv_cc_needs_belf" >&6; }
  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
    CFLAGS="$SAVE_CFLAGS"
  fi
  ;;
sparc*-*solaris*)
  # Find out which ABI we are using.
  echo 'int i;' > conftest.$ac_ext
  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
  (eval $ac_compile) 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; then
    case `/usr/bin/file conftest.o` in
    *64-bit*)
      case $lt_cv_prog_gnu_ld in
      yes*) LD="${LD-ld} -m elf64_sparc" ;;
      *)
	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
	  LD="${LD-ld} -64"
	fi
	;;
      esac
      ;;
    esac
  fi
  rm -rf conftest*
  ;;
esac

need_locks="$enable_libtool_lock"


  case $host_os in
    rhapsody* | darwin*)
    if test -n "$ac_tool_prefix"; then
  # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_DSYMUTIL+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$DSYMUTIL"; then
  ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
DSYMUTIL=$ac_cv_prog_DSYMUTIL
if test -n "$DSYMUTIL"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
$as_echo "$DSYMUTIL" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


fi
if test -z "$ac_cv_prog_DSYMUTIL"; then
  ac_ct_DSYMUTIL=$DSYMUTIL
  # Extract the first word of "dsymutil", so it can be a program name with args.
set dummy dsymutil; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_DSYMUTIL"; then
  ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
if test -n "$ac_ct_DSYMUTIL"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
$as_echo "$ac_ct_DSYMUTIL" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi

  if test "x$ac_ct_DSYMUTIL" = x; then
    DSYMUTIL=":"
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    DSYMUTIL=$ac_ct_DSYMUTIL
  fi
else
  DSYMUTIL="$ac_cv_prog_DSYMUTIL"
fi

    if test -n "$ac_tool_prefix"; then
  # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
set dummy ${ac_tool_prefix}nmedit; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_NMEDIT+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$NMEDIT"; then
  ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
NMEDIT=$ac_cv_prog_NMEDIT
if test -n "$NMEDIT"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
$as_echo "$NMEDIT" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


fi
if test -z "$ac_cv_prog_NMEDIT"; then
  ac_ct_NMEDIT=$NMEDIT
  # Extract the first word of "nmedit", so it can be a program name with args.
set dummy nmedit; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_NMEDIT"; then
  ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_ac_ct_NMEDIT="nmedit"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
if test -n "$ac_ct_NMEDIT"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
$as_echo "$ac_ct_NMEDIT" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi

  if test "x$ac_ct_NMEDIT" = x; then
    NMEDIT=":"
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    NMEDIT=$ac_ct_NMEDIT
  fi
else
  NMEDIT="$ac_cv_prog_NMEDIT"
fi

    if test -n "$ac_tool_prefix"; then
  # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
set dummy ${ac_tool_prefix}lipo; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_LIPO+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$LIPO"; then
  ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
LIPO=$ac_cv_prog_LIPO
if test -n "$LIPO"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
$as_echo "$LIPO" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


fi
if test -z "$ac_cv_prog_LIPO"; then
  ac_ct_LIPO=$LIPO
  # Extract the first word of "lipo", so it can be a program name with args.
set dummy lipo; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_LIPO"; then
  ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_ac_ct_LIPO="lipo"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
if test -n "$ac_ct_LIPO"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
$as_echo "$ac_ct_LIPO" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi

  if test "x$ac_ct_LIPO" = x; then
    LIPO=":"
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    LIPO=$ac_ct_LIPO
  fi
else
  LIPO="$ac_cv_prog_LIPO"
fi

    if test -n "$ac_tool_prefix"; then
  # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
set dummy ${ac_tool_prefix}otool; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_OTOOL+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$OTOOL"; then
  ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
OTOOL=$ac_cv_prog_OTOOL
if test -n "$OTOOL"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
$as_echo "$OTOOL" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


fi
if test -z "$ac_cv_prog_OTOOL"; then
  ac_ct_OTOOL=$OTOOL
  # Extract the first word of "otool", so it can be a program name with args.
set dummy otool; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_ac_ct_OTOOL+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_OTOOL"; then
  ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_ac_ct_OTOOL="otool"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
if test -n "$ac_ct_OTOOL"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
$as_echo "$ac_ct_OTOOL" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi

  if test "x$ac_ct_OTOOL" = x; then
    OTOOL=":"
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    OTOOL=$ac_ct_OTOOL
  fi
else
  OTOOL="$ac_cv_prog_OTOOL"
fi

    if test -n "$ac_tool_prefix"; then
  # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
set dummy ${ac_tool_prefix}otool64; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_OTOOL64+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$OTOOL64"; then
  ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
OTOOL64=$ac_cv_prog_OTOOL64
if test -n "$OTOOL64"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
$as_echo "$OTOOL64" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


fi
if test -z "$ac_cv_prog_OTOOL64"; then
  ac_ct_OTOOL64=$OTOOL64
  # Extract the first word of "otool64", so it can be a program name with args.
set dummy otool64; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_ac_ct_OTOOL64+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_OTOOL64"; then
  ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_ac_ct_OTOOL64="otool64"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
if test -n "$ac_ct_OTOOL64"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
$as_echo "$ac_ct_OTOOL64" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi

  if test "x$ac_ct_OTOOL64" = x; then
    OTOOL64=":"
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    OTOOL64=$ac_ct_OTOOL64
  fi
else
  OTOOL64="$ac_cv_prog_OTOOL64"
fi



























    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
$as_echo_n "checking for -single_module linker flag... " >&6; }
if test "${lt_cv_apple_cc_single_mod+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  lt_cv_apple_cc_single_mod=no
      if test -z "${LT_MULTI_MODULE}"; then
	# By default we will add the -single_module flag. You can override
	# by either setting the environment variable LT_MULTI_MODULE
	# non-empty at configure time, or by adding -multi_module to the
	# link flags.
	rm -rf libconftest.dylib*
	echo "int foo(void){return 1;}" > conftest.c
	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
-dynamiclib -Wl,-single_module conftest.c" >&5
	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
        _lt_result=$?
	if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then
	  lt_cv_apple_cc_single_mod=yes
	else
	  cat conftest.err >&5
	fi
	rm -rf libconftest.dylib*
	rm -f conftest.*
      fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
if test "${lt_cv_ld_exported_symbols_list+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  lt_cv_ld_exported_symbols_list=no
      save_LDFLAGS=$LDFLAGS
      echo "_main" > conftest.sym
      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  lt_cv_ld_exported_symbols_list=yes
else
  lt_cv_ld_exported_symbols_list=no
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
	LDFLAGS="$save_LDFLAGS"

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
    case $host_os in
    rhapsody* | darwin1.[012])
      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
    darwin1.*)
      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
    darwin*) # darwin 5.x on
      # if running on 10.5 or later, the deployment target defaults
      # to the OS version, if on x86, and 10.4, the deployment
      # target defaults to 10.4. Don't you love it?
      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
	10.0,*86*-darwin8*|10.0,*-darwin[91]*)
	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
	10.[012]*)
	  _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
	10.*)
	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
      esac
    ;;
  esac
    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
      _lt_dar_single_mod='$single_module'
    fi
    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
    else
      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
    fi
    if test "$DSYMUTIL" != ":"; then
      _lt_dsymutil='~$DSYMUTIL $lib || :'
    else
      _lt_dsymutil=
    fi
    ;;
  esac


{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
$as_echo_n "checking for ANSI C header files... " >&6; }
if test "${ac_cv_header_stdc+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
#include 
#include 
#include 

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_cv_header_stdc=yes
else
  ac_cv_header_stdc=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext

if test $ac_cv_header_stdc = yes; then
  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 

_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
  $EGREP "memchr" >/dev/null 2>&1; then :

else
  ac_cv_header_stdc=no
fi
rm -f conftest*

fi

if test $ac_cv_header_stdc = yes; then
  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 

_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
  $EGREP "free" >/dev/null 2>&1; then :

else
  ac_cv_header_stdc=no
fi
rm -f conftest*

fi

if test $ac_cv_header_stdc = yes; then
  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
  if test "$cross_compiling" = yes; then :
  :
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
#include 
#if ((' ' & 0x0FF) == 0x020)
# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
#else
# define ISLOWER(c) \
		   (('a' <= (c) && (c) <= 'i') \
		     || ('j' <= (c) && (c) <= 'r') \
		     || ('s' <= (c) && (c) <= 'z'))
# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
#endif

#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
int
main ()
{
  int i;
  for (i = 0; i < 256; i++)
    if (XOR (islower (i), ISLOWER (i))
	|| toupper (i) != TOUPPER (i))
      return 2;
  return 0;
}
_ACEOF
if ac_fn_c_try_run "$LINENO"; then :

else
  ac_cv_header_stdc=no
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
  conftest.$ac_objext conftest.beam conftest.$ac_ext
fi

fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
$as_echo "$ac_cv_header_stdc" >&6; }
if test $ac_cv_header_stdc = yes; then

$as_echo "#define STDC_HEADERS 1" >>confdefs.h

fi

# On IRIX 5.3, sys/types and inttypes.h are conflicting.
for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
		  inttypes.h stdint.h unistd.h
do :
  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
"
eval as_val=\$$as_ac_Header
   if test "x$as_val" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
_ACEOF

fi

done


for ac_header in dlfcn.h
do :
  ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
"
if test "x$ac_cv_header_dlfcn_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_DLFCN_H 1
_ACEOF

fi

done



ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
if test -z "$CXX"; then
  if test -n "$CCC"; then
    CXX=$CCC
  else
    if test -n "$ac_tool_prefix"; then
  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
  do
    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_CXX+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$CXX"; then
  ac_cv_prog_CXX="$CXX" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
CXX=$ac_cv_prog_CXX
if test -n "$CXX"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
$as_echo "$CXX" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


    test -n "$CXX" && break
  done
fi
if test -z "$CXX"; then
  ac_ct_CXX=$CXX
  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
do
  # Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_CXX"; then
  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_ac_ct_CXX="$ac_prog"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
if test -n "$ac_ct_CXX"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
$as_echo "$ac_ct_CXX" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


  test -n "$ac_ct_CXX" && break
done

  if test "x$ac_ct_CXX" = x; then
    CXX="g++"
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    CXX=$ac_ct_CXX
  fi
fi

  fi
fi
# Provide some information about the compiler.
$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
set X $ac_compile
ac_compiler=$2
for ac_option in --version -v -V -qversion; do
  { { ac_try="$ac_compiler $ac_option >&5"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
  ac_status=$?
  if test -s conftest.err; then
    sed '10a\
... rest of stderr output deleted ...
         10q' conftest.err >conftest.er1
    cat conftest.er1 >&5
  fi
  rm -f conftest.er1 conftest.err
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }
done

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
if test "${ac_cv_cxx_compiler_gnu+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{
#ifndef __GNUC__
       choke me
#endif

  ;
  return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
  ac_compiler_gnu=yes
else
  ac_compiler_gnu=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
ac_cv_cxx_compiler_gnu=$ac_compiler_gnu

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
if test $ac_compiler_gnu = yes; then
  GXX=yes
else
  GXX=
fi
ac_test_CXXFLAGS=${CXXFLAGS+set}
ac_save_CXXFLAGS=$CXXFLAGS
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
$as_echo_n "checking whether $CXX accepts -g... " >&6; }
if test "${ac_cv_prog_cxx_g+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  ac_save_cxx_werror_flag=$ac_cxx_werror_flag
   ac_cxx_werror_flag=yes
   ac_cv_prog_cxx_g=no
   CXXFLAGS="-g"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
  ac_cv_prog_cxx_g=yes
else
  CXXFLAGS=""
      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :

else
  ac_cxx_werror_flag=$ac_save_cxx_werror_flag
	 CXXFLAGS="-g"
	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
  ac_cv_prog_cxx_g=yes
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
   ac_cxx_werror_flag=$ac_save_cxx_werror_flag
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
$as_echo "$ac_cv_prog_cxx_g" >&6; }
if test "$ac_test_CXXFLAGS" = set; then
  CXXFLAGS=$ac_save_CXXFLAGS
elif test $ac_cv_prog_cxx_g = yes; then
  if test "$GXX" = yes; then
    CXXFLAGS="-g -O2"
  else
    CXXFLAGS="-g"
  fi
else
  if test "$GXX" = yes; then
    CXXFLAGS="-O2"
  else
    CXXFLAGS=
  fi
fi
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu

depcc="$CXX"  am_compiler_list=

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
$as_echo_n "checking dependency style of $depcc... " >&6; }
if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
  # We make a subdir and do the tests there.  Otherwise we can end up
  # making bogus files that we don't know about and never remove.  For
  # instance it was reported that on HP-UX the gcc test will end up
  # making a dummy file named `D' -- because `-MD' means `put the output
  # in D'.
  mkdir conftest.dir
  # Copy depcomp to subdir because otherwise we won't find it if we're
  # using a relative directory.
  cp "$am_depcomp" conftest.dir
  cd conftest.dir
  # We will build objects and dependencies in a subdirectory because
  # it helps to detect inapplicable dependency modes.  For instance
  # both Tru64's cc and ICC support -MD to output dependencies as a
  # side effect of compilation, but ICC will put the dependencies in
  # the current directory while Tru64 will put them in the object
  # directory.
  mkdir sub

  am_cv_CXX_dependencies_compiler_type=none
  if test "$am_compiler_list" = ""; then
     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
  fi
  for depmode in $am_compiler_list; do
    # Setup a source with many dependencies, because some compilers
    # like to wrap large dependency lists on column 80 (with \), and
    # we should not choose a depcomp mode which is confused by this.
    #
    # We need to recreate these files for each test, as the compiler may
    # overwrite some of them when testing with obscure command lines.
    # This happens at least with the AIX C compiler.
    : > sub/conftest.c
    for i in 1 2 3 4 5 6; do
      echo '#include "conftst'$i'.h"' >> sub/conftest.c
      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
      # Solaris 8's {/usr,}/bin/sh.
      touch sub/conftst$i.h
    done
    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf

    case $depmode in
    nosideeffect)
      # after this tag, mechanisms are not by side-effect, so they'll
      # only be used when explicitly requested
      if test "x$enable_dependency_tracking" = xyes; then
	continue
      else
	break
      fi
      ;;
    none) break ;;
    esac
    # We check with `-c' and `-o' for the sake of the "dashmstdout"
    # mode.  It turns out that the SunPro C++ compiler does not properly
    # handle `-M -o', and we need to detect this.
    if depmode=$depmode \
       source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
       $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
         >/dev/null 2>conftest.err &&
       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
       grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
      # icc doesn't choke on unknown options, it will just issue warnings
      # or remarks (even with -Werror).  So we grep stderr for any message
      # that says an option was ignored or not supported.
      # When given -MP, icc 7.0 and 7.1 complain thusly:
      #   icc: Command line warning: ignoring option '-M'; no argument required
      # The diagnosis changed in icc 8.0:
      #   icc: Command line remark: option '-MP' not supported
      if (grep 'ignoring option' conftest.err ||
          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
        am_cv_CXX_dependencies_compiler_type=$depmode
        break
      fi
    fi
  done

  cd ..
  rm -rf conftest.dir
else
  am_cv_CXX_dependencies_compiler_type=none
fi

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5
$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; }
CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type



if
  test "x$enable_dependency_tracking" != xno \
  && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then
  am__fastdepCXX_TRUE=
  am__fastdepCXX_FALSE='#'
else
  am__fastdepCXX_TRUE='#'
  am__fastdepCXX_FALSE=
fi


if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
    (test "X$CXX" != "Xg++"))) ; then
  ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5
$as_echo_n "checking how to run the C++ preprocessor... " >&6; }
if test -z "$CXXCPP"; then
  if test "${ac_cv_prog_CXXCPP+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
      # Double quotes because CXXCPP needs to be expanded
    for CXXCPP in "$CXX -E" "/lib/cpp"
    do
      ac_preproc_ok=false
for ac_cxx_preproc_warn_flag in '' yes
do
  # Use a header file that comes with gcc, so configuring glibc
  # with a fresh cross-compiler works.
  # Prefer  to  if __STDC__ is defined, since
  #  exists even on freestanding compilers.
  # On the NeXT, cc -E runs the code through the compiler's parser,
  # not just through cpp. "Syntax error" is here to catch this case.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#ifdef __STDC__
# include 
#else
# include 
#endif
		     Syntax error
_ACEOF
if ac_fn_cxx_try_cpp "$LINENO"; then :

else
  # Broken: fails on valid input.
continue
fi
rm -f conftest.err conftest.$ac_ext

  # OK, works on sane cases.  Now check whether nonexistent headers
  # can be detected and how.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
_ACEOF
if ac_fn_cxx_try_cpp "$LINENO"; then :
  # Broken: success on invalid input.
continue
else
  # Passes both tests.
ac_preproc_ok=:
break
fi
rm -f conftest.err conftest.$ac_ext

done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
rm -f conftest.err conftest.$ac_ext
if $ac_preproc_ok; then :
  break
fi

    done
    ac_cv_prog_CXXCPP=$CXXCPP

fi
  CXXCPP=$ac_cv_prog_CXXCPP
else
  ac_cv_prog_CXXCPP=$CXXCPP
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5
$as_echo "$CXXCPP" >&6; }
ac_preproc_ok=false
for ac_cxx_preproc_warn_flag in '' yes
do
  # Use a header file that comes with gcc, so configuring glibc
  # with a fresh cross-compiler works.
  # Prefer  to  if __STDC__ is defined, since
  #  exists even on freestanding compilers.
  # On the NeXT, cc -E runs the code through the compiler's parser,
  # not just through cpp. "Syntax error" is here to catch this case.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#ifdef __STDC__
# include 
#else
# include 
#endif
		     Syntax error
_ACEOF
if ac_fn_cxx_try_cpp "$LINENO"; then :

else
  # Broken: fails on valid input.
continue
fi
rm -f conftest.err conftest.$ac_ext

  # OK, works on sane cases.  Now check whether nonexistent headers
  # can be detected and how.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
_ACEOF
if ac_fn_cxx_try_cpp "$LINENO"; then :
  # Broken: success on invalid input.
continue
else
  # Passes both tests.
ac_preproc_ok=:
break
fi
rm -f conftest.err conftest.$ac_ext

done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
rm -f conftest.err conftest.$ac_ext
if $ac_preproc_ok; then :

else
  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
_lt_caught_CXX_error=yes; }
fi

ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu

else
  _lt_caught_CXX_error=yes
fi





# Set options



        enable_dlopen=no


  enable_win32_dll=no


            # Check whether --enable-shared was given.
if test "${enable_shared+set}" = set; then :
  enableval=$enable_shared; p=${PACKAGE-default}
    case $enableval in
    yes) enable_shared=yes ;;
    no) enable_shared=no ;;
    *)
      enable_shared=no
      # Look at the argument we got.  We use all the common list separators.
      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
      for pkg in $enableval; do
	IFS="$lt_save_ifs"
	if test "X$pkg" = "X$p"; then
	  enable_shared=yes
	fi
      done
      IFS="$lt_save_ifs"
      ;;
    esac
else
  enable_shared=yes
fi









  # Check whether --enable-static was given.
if test "${enable_static+set}" = set; then :
  enableval=$enable_static; p=${PACKAGE-default}
    case $enableval in
    yes) enable_static=yes ;;
    no) enable_static=no ;;
    *)
     enable_static=no
      # Look at the argument we got.  We use all the common list separators.
      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
      for pkg in $enableval; do
	IFS="$lt_save_ifs"
	if test "X$pkg" = "X$p"; then
	  enable_static=yes
	fi
      done
      IFS="$lt_save_ifs"
      ;;
    esac
else
  enable_static=yes
fi










# Check whether --with-pic was given.
if test "${with_pic+set}" = set; then :
  withval=$with_pic; pic_mode="$withval"
else
  pic_mode=default
fi


test -z "$pic_mode" && pic_mode=default











# This can be used to rebuild libtool when needed
LIBTOOL_DEPS="$ltmain"

# Always use our own libtool.
LIBTOOL='$(SHELL) $(top_builddir)/libtool'

























test -z "$LN_S" && LN_S="ln -s"














if test -n "${ZSH_VERSION+set}" ; then
   setopt NO_GLOB_SUBST
fi

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
$as_echo_n "checking for objdir... " >&6; }
if test "${lt_cv_objdir+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  rm -f .libs 2>/dev/null
mkdir .libs 2>/dev/null
if test -d .libs; then
  lt_cv_objdir=.libs
else
  # MS-DOS does not allow filenames that begin with a dot.
  lt_cv_objdir=_libs
fi
rmdir .libs 2>/dev/null
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
$as_echo "$lt_cv_objdir" >&6; }
objdir=$lt_cv_objdir





cat >>confdefs.h <<_ACEOF
#define LT_OBJDIR "$lt_cv_objdir/"
_ACEOF

















case $host_os in
aix3*)
  # AIX sometimes has problems with the GCC collect2 program.  For some
  # reason, if we set the COLLECT_NAMES environment variable, the problems
  # vanish in a puff of smoke.
  if test "X${COLLECT_NAMES+set}" != Xset; then
    COLLECT_NAMES=
    export COLLECT_NAMES
  fi
  ;;
esac

# Sed substitution that helps us do robust quoting.  It backslashifies
# metacharacters that are still active within double-quoted strings.
sed_quote_subst='s/\(["`$\\]\)/\\\1/g'

# Same as above, but do not quote variable references.
double_quote_subst='s/\(["`\\]\)/\\\1/g'

# Sed substitution to delay expansion of an escaped shell variable in a
# double_quote_subst'ed string.
delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'

# Sed substitution to delay expansion of an escaped single quote.
delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'

# Sed substitution to avoid accidental globbing in evaled expressions
no_glob_subst='s/\*/\\\*/g'

# Global variables:
ofile=libtool
can_build_shared=yes

# All known linkers require a `.a' archive for static linking (except MSVC,
# which needs '.lib').
libext=a

with_gnu_ld="$lt_cv_prog_gnu_ld"

old_CC="$CC"
old_CFLAGS="$CFLAGS"

# Set sane defaults for various variables
test -z "$CC" && CC=cc
test -z "$LTCC" && LTCC=$CC
test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
test -z "$LD" && LD=ld
test -z "$ac_objext" && ac_objext=o

for cc_temp in $compiler""; do
  case $cc_temp in
    compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
    distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
    \-*) ;;
    *) break;;
  esac
done
cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`


# Only perform the check for file, if the check method requires it
test -z "$MAGIC_CMD" && MAGIC_CMD=file
case $deplibs_check_method in
file_magic*)
  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
if test "${lt_cv_path_MAGIC_CMD+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  case $MAGIC_CMD in
[\\/*] |  ?:[\\/]*)
  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
  ;;
*)
  lt_save_MAGIC_CMD="$MAGIC_CMD"
  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
  for ac_dir in $ac_dummy; do
    IFS="$lt_save_ifs"
    test -z "$ac_dir" && ac_dir=.
    if test -f $ac_dir/${ac_tool_prefix}file; then
      lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
      if test -n "$file_magic_test_file"; then
	case $deplibs_check_method in
	"file_magic "*)
	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
	    $EGREP "$file_magic_regex" > /dev/null; then
	    :
	  else
	    cat <<_LT_EOF 1>&2

*** Warning: the command libtool uses to detect shared libraries,
*** $file_magic_cmd, produces output that libtool cannot recognize.
*** The result is that libtool may fail to recognize shared libraries
*** as such.  This will affect the creation of libtool libraries that
*** depend on shared libraries, but programs linked with such libtool
*** libraries will work regardless of this problem.  Nevertheless, you
*** may want to report the problem to your system manager and/or to
*** bug-libtool@gnu.org

_LT_EOF
	  fi ;;
	esac
      fi
      break
    fi
  done
  IFS="$lt_save_ifs"
  MAGIC_CMD="$lt_save_MAGIC_CMD"
  ;;
esac
fi

MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
if test -n "$MAGIC_CMD"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
$as_echo "$MAGIC_CMD" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi





if test -z "$lt_cv_path_MAGIC_CMD"; then
  if test -n "$ac_tool_prefix"; then
    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
$as_echo_n "checking for file... " >&6; }
if test "${lt_cv_path_MAGIC_CMD+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  case $MAGIC_CMD in
[\\/*] |  ?:[\\/]*)
  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
  ;;
*)
  lt_save_MAGIC_CMD="$MAGIC_CMD"
  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
  for ac_dir in $ac_dummy; do
    IFS="$lt_save_ifs"
    test -z "$ac_dir" && ac_dir=.
    if test -f $ac_dir/file; then
      lt_cv_path_MAGIC_CMD="$ac_dir/file"
      if test -n "$file_magic_test_file"; then
	case $deplibs_check_method in
	"file_magic "*)
	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
	    $EGREP "$file_magic_regex" > /dev/null; then
	    :
	  else
	    cat <<_LT_EOF 1>&2

*** Warning: the command libtool uses to detect shared libraries,
*** $file_magic_cmd, produces output that libtool cannot recognize.
*** The result is that libtool may fail to recognize shared libraries
*** as such.  This will affect the creation of libtool libraries that
*** depend on shared libraries, but programs linked with such libtool
*** libraries will work regardless of this problem.  Nevertheless, you
*** may want to report the problem to your system manager and/or to
*** bug-libtool@gnu.org

_LT_EOF
	  fi ;;
	esac
      fi
      break
    fi
  done
  IFS="$lt_save_ifs"
  MAGIC_CMD="$lt_save_MAGIC_CMD"
  ;;
esac
fi

MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
if test -n "$MAGIC_CMD"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
$as_echo "$MAGIC_CMD" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


  else
    MAGIC_CMD=:
  fi
fi

  fi
  ;;
esac

# Use C for the default configuration in the libtool script

lt_save_CC="$CC"
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu


# Source file extension for C test sources.
ac_ext=c

# Object file extension for compiled C test sources.
objext=o
objext=$objext

# Code to be used in simple compile tests
lt_simple_compile_test_code="int some_variable = 0;"

# Code to be used in simple link tests
lt_simple_link_test_code='int main(){return(0);}'







# If no C compiler was specified, use CC.
LTCC=${LTCC-"$CC"}

# If no C compiler flags were specified, use CFLAGS.
LTCFLAGS=${LTCFLAGS-"$CFLAGS"}

# Allow CC to be a program name with arguments.
compiler=$CC

# Save the default compiler, since it gets overwritten when the other
# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
compiler_DEFAULT=$CC

# save warnings/boilerplate of simple test code
ac_outfile=conftest.$ac_objext
echo "$lt_simple_compile_test_code" >conftest.$ac_ext
eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
_lt_compiler_boilerplate=`cat conftest.err`
$RM conftest*

ac_outfile=conftest.$ac_objext
echo "$lt_simple_link_test_code" >conftest.$ac_ext
eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
_lt_linker_boilerplate=`cat conftest.err`
$RM -r conftest*


## CAVEAT EMPTOR:
## There is no encapsulation within the following macros, do not change
## the running order or otherwise move them around unless you know exactly
## what you are doing...
if test -n "$compiler"; then

lt_prog_compiler_no_builtin_flag=

if test "$GCC" = yes; then
  lt_prog_compiler_no_builtin_flag=' -fno-builtin'

  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  lt_cv_prog_compiler_rtti_exceptions=no
   ac_outfile=conftest.$ac_objext
   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
   lt_compiler_flag="-fno-rtti -fno-exceptions"
   # Insert the option either (1) after the last *FLAGS variable, or
   # (2) before a word containing "conftest.", or (3) at the end.
   # Note that $ac_compile itself does not contain backslashes and begins
   # with a dollar sign (not a hyphen), so the echo should work correctly.
   # The option is referenced via a variable to avoid confusing sed.
   lt_compile=`echo "$ac_compile" | $SED \
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
   -e 's:$: $lt_compiler_flag:'`
   (eval echo "\"\$as_me:8669: $lt_compile\"" >&5)
   (eval "$lt_compile" 2>conftest.err)
   ac_status=$?
   cat conftest.err >&5
   echo "$as_me:8673: \$? = $ac_status" >&5
   if (exit $ac_status) && test -s "$ac_outfile"; then
     # The compiler can only warn and ignore the option if not recognized
     # So say no if there are warnings other than the usual output.
     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
       lt_cv_prog_compiler_rtti_exceptions=yes
     fi
   fi
   $RM conftest*

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }

if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
    lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
else
    :
fi

fi






  lt_prog_compiler_wl=
lt_prog_compiler_pic=
lt_prog_compiler_static=

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
$as_echo_n "checking for $compiler option to produce PIC... " >&6; }

  if test "$GCC" = yes; then
    lt_prog_compiler_wl='-Wl,'
    lt_prog_compiler_static='-static'

    case $host_os in
      aix*)
      # All AIX code is PIC.
      if test "$host_cpu" = ia64; then
	# AIX 5 now supports IA64 processor
	lt_prog_compiler_static='-Bstatic'
      fi
      ;;

    amigaos*)
      case $host_cpu in
      powerpc)
            # see comment about AmigaOS4 .so support
            lt_prog_compiler_pic='-fPIC'
        ;;
      m68k)
            # FIXME: we need at least 68020 code to build shared libraries, but
            # adding the `-m68020' flag to GCC prevents building anything better,
            # like `-m68040'.
            lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
        ;;
      esac
      ;;

    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
      # PIC is the default for these OSes.
      ;;

    mingw* | cygwin* | pw32* | os2* | cegcc*)
      # This hack is so that the source file can tell whether it is being
      # built for inclusion in a dll (and should export symbols for example).
      # Although the cygwin gcc ignores -fPIC, still need this for old-style
      # (--disable-auto-import) libraries
      lt_prog_compiler_pic='-DDLL_EXPORT'
      ;;

    darwin* | rhapsody*)
      # PIC is the default on this platform
      # Common symbols not allowed in MH_DYLIB files
      lt_prog_compiler_pic='-fno-common'
      ;;

    hpux*)
      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
      # sets the default TLS model and affects inlining.
      case $host_cpu in
      hppa*64*)
	# +Z the default
	;;
      *)
	lt_prog_compiler_pic='-fPIC'
	;;
      esac
      ;;

    interix[3-9]*)
      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
      # Instead, we relocate shared libraries at runtime.
      ;;

    msdosdjgpp*)
      # Just because we use GCC doesn't mean we suddenly get shared libraries
      # on systems that don't support them.
      lt_prog_compiler_can_build_shared=no
      enable_shared=no
      ;;

    *nto* | *qnx*)
      # QNX uses GNU C++, but need to define -shared option too, otherwise
      # it will coredump.
      lt_prog_compiler_pic='-fPIC -shared'
      ;;

    sysv4*MP*)
      if test -d /usr/nec; then
	lt_prog_compiler_pic=-Kconform_pic
      fi
      ;;

    *)
      lt_prog_compiler_pic='-fPIC'
      ;;
    esac
  else
    # PORTME Check for flag to pass linker flags through the system compiler.
    case $host_os in
    aix*)
      lt_prog_compiler_wl='-Wl,'
      if test "$host_cpu" = ia64; then
	# AIX 5 now supports IA64 processor
	lt_prog_compiler_static='-Bstatic'
      else
	lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
      fi
      ;;

    mingw* | cygwin* | pw32* | os2* | cegcc*)
      # This hack is so that the source file can tell whether it is being
      # built for inclusion in a dll (and should export symbols for example).
      lt_prog_compiler_pic='-DDLL_EXPORT'
      ;;

    hpux9* | hpux10* | hpux11*)
      lt_prog_compiler_wl='-Wl,'
      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
      # not for PA HP-UX.
      case $host_cpu in
      hppa*64*|ia64*)
	# +Z the default
	;;
      *)
	lt_prog_compiler_pic='+Z'
	;;
      esac
      # Is there a better lt_prog_compiler_static that works with the bundled CC?
      lt_prog_compiler_static='${wl}-a ${wl}archive'
      ;;

    irix5* | irix6* | nonstopux*)
      lt_prog_compiler_wl='-Wl,'
      # PIC (with -KPIC) is the default.
      lt_prog_compiler_static='-non_shared'
      ;;

    linux* | k*bsd*-gnu | kopensolaris*-gnu)
      case $cc_basename in
      # old Intel for x86_64 which still supported -KPIC.
      ecc*)
	lt_prog_compiler_wl='-Wl,'
	lt_prog_compiler_pic='-KPIC'
	lt_prog_compiler_static='-static'
        ;;
      # icc used to be incompatible with GCC.
      # ICC 10 doesn't accept -KPIC any more.
      icc* | ifort*)
	lt_prog_compiler_wl='-Wl,'
	lt_prog_compiler_pic='-fPIC'
	lt_prog_compiler_static='-static'
        ;;
      # Lahey Fortran 8.1.
      lf95*)
	lt_prog_compiler_wl='-Wl,'
	lt_prog_compiler_pic='--shared'
	lt_prog_compiler_static='--static'
	;;
      pgcc* | pgf77* | pgf90* | pgf95*)
        # Portland Group compilers (*not* the Pentium gcc compiler,
	# which looks to be a dead project)
	lt_prog_compiler_wl='-Wl,'
	lt_prog_compiler_pic='-fpic'
	lt_prog_compiler_static='-Bstatic'
        ;;
      ccc*)
        lt_prog_compiler_wl='-Wl,'
        # All Alpha code is PIC.
        lt_prog_compiler_static='-non_shared'
        ;;
      xl*)
	# IBM XL C 8.0/Fortran 10.1 on PPC
	lt_prog_compiler_wl='-Wl,'
	lt_prog_compiler_pic='-qpic'
	lt_prog_compiler_static='-qstaticlink'
	;;
      *)
	case `$CC -V 2>&1 | sed 5q` in
	*Sun\ C*)
	  # Sun C 5.9
	  lt_prog_compiler_pic='-KPIC'
	  lt_prog_compiler_static='-Bstatic'
	  lt_prog_compiler_wl='-Wl,'
	  ;;
	*Sun\ F*)
	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
	  lt_prog_compiler_pic='-KPIC'
	  lt_prog_compiler_static='-Bstatic'
	  lt_prog_compiler_wl=''
	  ;;
	esac
	;;
      esac
      ;;

    newsos6)
      lt_prog_compiler_pic='-KPIC'
      lt_prog_compiler_static='-Bstatic'
      ;;

    *nto* | *qnx*)
      # QNX uses GNU C++, but need to define -shared option too, otherwise
      # it will coredump.
      lt_prog_compiler_pic='-fPIC -shared'
      ;;

    osf3* | osf4* | osf5*)
      lt_prog_compiler_wl='-Wl,'
      # All OSF/1 code is PIC.
      lt_prog_compiler_static='-non_shared'
      ;;

    rdos*)
      lt_prog_compiler_static='-non_shared'
      ;;

    solaris*)
      lt_prog_compiler_pic='-KPIC'
      lt_prog_compiler_static='-Bstatic'
      case $cc_basename in
      f77* | f90* | f95*)
	lt_prog_compiler_wl='-Qoption ld ';;
      *)
	lt_prog_compiler_wl='-Wl,';;
      esac
      ;;

    sunos4*)
      lt_prog_compiler_wl='-Qoption ld '
      lt_prog_compiler_pic='-PIC'
      lt_prog_compiler_static='-Bstatic'
      ;;

    sysv4 | sysv4.2uw2* | sysv4.3*)
      lt_prog_compiler_wl='-Wl,'
      lt_prog_compiler_pic='-KPIC'
      lt_prog_compiler_static='-Bstatic'
      ;;

    sysv4*MP*)
      if test -d /usr/nec ;then
	lt_prog_compiler_pic='-Kconform_pic'
	lt_prog_compiler_static='-Bstatic'
      fi
      ;;

    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
      lt_prog_compiler_wl='-Wl,'
      lt_prog_compiler_pic='-KPIC'
      lt_prog_compiler_static='-Bstatic'
      ;;

    unicos*)
      lt_prog_compiler_wl='-Wl,'
      lt_prog_compiler_can_build_shared=no
      ;;

    uts4*)
      lt_prog_compiler_pic='-pic'
      lt_prog_compiler_static='-Bstatic'
      ;;

    *)
      lt_prog_compiler_can_build_shared=no
      ;;
    esac
  fi

case $host_os in
  # For platforms which do not support PIC, -DPIC is meaningless:
  *djgpp*)
    lt_prog_compiler_pic=
    ;;
  *)
    lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
    ;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5
$as_echo "$lt_prog_compiler_pic" >&6; }






#
# Check to make sure the PIC flag actually works.
#
if test -n "$lt_prog_compiler_pic"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
if test "${lt_cv_prog_compiler_pic_works+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  lt_cv_prog_compiler_pic_works=no
   ac_outfile=conftest.$ac_objext
   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
   lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
   # Insert the option either (1) after the last *FLAGS variable, or
   # (2) before a word containing "conftest.", or (3) at the end.
   # Note that $ac_compile itself does not contain backslashes and begins
   # with a dollar sign (not a hyphen), so the echo should work correctly.
   # The option is referenced via a variable to avoid confusing sed.
   lt_compile=`echo "$ac_compile" | $SED \
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
   -e 's:$: $lt_compiler_flag:'`
   (eval echo "\"\$as_me:9008: $lt_compile\"" >&5)
   (eval "$lt_compile" 2>conftest.err)
   ac_status=$?
   cat conftest.err >&5
   echo "$as_me:9012: \$? = $ac_status" >&5
   if (exit $ac_status) && test -s "$ac_outfile"; then
     # The compiler can only warn and ignore the option if not recognized
     # So say no if there are warnings other than the usual output.
     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
       lt_cv_prog_compiler_pic_works=yes
     fi
   fi
   $RM conftest*

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }

if test x"$lt_cv_prog_compiler_pic_works" = xyes; then
    case $lt_prog_compiler_pic in
     "" | " "*) ;;
     *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
     esac
else
    lt_prog_compiler_pic=
     lt_prog_compiler_can_build_shared=no
fi

fi






#
# Check to make sure the static flag actually works.
#
wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
if test "${lt_cv_prog_compiler_static_works+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  lt_cv_prog_compiler_static_works=no
   save_LDFLAGS="$LDFLAGS"
   LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
   echo "$lt_simple_link_test_code" > conftest.$ac_ext
   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
     # The linker can only warn and ignore the option if not recognized
     # So say no if there are warnings
     if test -s conftest.err; then
       # Append any errors to the config.log.
       cat conftest.err 1>&5
       $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
       if diff conftest.exp conftest.er2 >/dev/null; then
         lt_cv_prog_compiler_static_works=yes
       fi
     else
       lt_cv_prog_compiler_static_works=yes
     fi
   fi
   $RM -r conftest*
   LDFLAGS="$save_LDFLAGS"

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
$as_echo "$lt_cv_prog_compiler_static_works" >&6; }

if test x"$lt_cv_prog_compiler_static_works" = xyes; then
    :
else
    lt_prog_compiler_static=
fi







  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
if test "${lt_cv_prog_compiler_c_o+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  lt_cv_prog_compiler_c_o=no
   $RM -r conftest 2>/dev/null
   mkdir conftest
   cd conftest
   mkdir out
   echo "$lt_simple_compile_test_code" > conftest.$ac_ext

   lt_compiler_flag="-o out/conftest2.$ac_objext"
   # Insert the option either (1) after the last *FLAGS variable, or
   # (2) before a word containing "conftest.", or (3) at the end.
   # Note that $ac_compile itself does not contain backslashes and begins
   # with a dollar sign (not a hyphen), so the echo should work correctly.
   lt_compile=`echo "$ac_compile" | $SED \
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
   -e 's:$: $lt_compiler_flag:'`
   (eval echo "\"\$as_me:9113: $lt_compile\"" >&5)
   (eval "$lt_compile" 2>out/conftest.err)
   ac_status=$?
   cat out/conftest.err >&5
   echo "$as_me:9117: \$? = $ac_status" >&5
   if (exit $ac_status) && test -s out/conftest2.$ac_objext
   then
     # The compiler can only warn and ignore the option if not recognized
     # So say no if there are warnings
     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
       lt_cv_prog_compiler_c_o=yes
     fi
   fi
   chmod u+w . 2>&5
   $RM conftest*
   # SGI C++ compiler will create directory out/ii_files/ for
   # template instantiation
   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
   $RM out/* && rmdir out
   cd ..
   $RM -r conftest
   $RM conftest*

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
$as_echo "$lt_cv_prog_compiler_c_o" >&6; }






  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
if test "${lt_cv_prog_compiler_c_o+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  lt_cv_prog_compiler_c_o=no
   $RM -r conftest 2>/dev/null
   mkdir conftest
   cd conftest
   mkdir out
   echo "$lt_simple_compile_test_code" > conftest.$ac_ext

   lt_compiler_flag="-o out/conftest2.$ac_objext"
   # Insert the option either (1) after the last *FLAGS variable, or
   # (2) before a word containing "conftest.", or (3) at the end.
   # Note that $ac_compile itself does not contain backslashes and begins
   # with a dollar sign (not a hyphen), so the echo should work correctly.
   lt_compile=`echo "$ac_compile" | $SED \
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
   -e 's:$: $lt_compiler_flag:'`
   (eval echo "\"\$as_me:9168: $lt_compile\"" >&5)
   (eval "$lt_compile" 2>out/conftest.err)
   ac_status=$?
   cat out/conftest.err >&5
   echo "$as_me:9172: \$? = $ac_status" >&5
   if (exit $ac_status) && test -s out/conftest2.$ac_objext
   then
     # The compiler can only warn and ignore the option if not recognized
     # So say no if there are warnings
     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
       lt_cv_prog_compiler_c_o=yes
     fi
   fi
   chmod u+w . 2>&5
   $RM conftest*
   # SGI C++ compiler will create directory out/ii_files/ for
   # template instantiation
   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
   $RM out/* && rmdir out
   cd ..
   $RM -r conftest
   $RM conftest*

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
$as_echo "$lt_cv_prog_compiler_c_o" >&6; }




hard_links="nottested"
if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
  # do not overwrite the value of need_locks provided by the user
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
$as_echo_n "checking if we can lock with hard links... " >&6; }
  hard_links=yes
  $RM conftest*
  ln conftest.a conftest.b 2>/dev/null && hard_links=no
  touch conftest.a
  ln conftest.a conftest.b 2>&5 || hard_links=no
  ln conftest.a conftest.b 2>/dev/null && hard_links=no
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
$as_echo "$hard_links" >&6; }
  if test "$hard_links" = no; then
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
    need_locks=warn
  fi
else
  need_locks=no
fi






  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }

  runpath_var=
  allow_undefined_flag=
  always_export_symbols=no
  archive_cmds=
  archive_expsym_cmds=
  compiler_needs_object=no
  enable_shared_with_static_runtimes=no
  export_dynamic_flag_spec=
  export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
  hardcode_automatic=no
  hardcode_direct=no
  hardcode_direct_absolute=no
  hardcode_libdir_flag_spec=
  hardcode_libdir_flag_spec_ld=
  hardcode_libdir_separator=
  hardcode_minus_L=no
  hardcode_shlibpath_var=unsupported
  inherit_rpath=no
  link_all_deplibs=unknown
  module_cmds=
  module_expsym_cmds=
  old_archive_from_new_cmds=
  old_archive_from_expsyms_cmds=
  thread_safe_flag_spec=
  whole_archive_flag_spec=
  # include_expsyms should be a list of space-separated symbols to be *always*
  # included in the symbol list
  include_expsyms=
  # exclude_expsyms can be an extended regexp of symbols to exclude
  # it will be wrapped by ` (' and `)$', so one must not match beginning or
  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
  # as well as any symbol that contains `d'.
  exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
  # platforms (ab)use it in PIC code, but their linkers get confused if
  # the symbol is explicitly referenced.  Since portable code cannot
  # rely on this symbol name, it's probably fine to never include it in
  # preloaded symbol tables.
  # Exclude shared library initialization/finalization symbols.
  extract_expsyms_cmds=

  case $host_os in
  cygwin* | mingw* | pw32* | cegcc*)
    # FIXME: the MSVC++ port hasn't been tested in a loooong time
    # When not using gcc, we currently assume that we are using
    # Microsoft Visual C++.
    if test "$GCC" != yes; then
      with_gnu_ld=no
    fi
    ;;
  interix*)
    # we just hope/assume this is gcc and not c89 (= MSVC++)
    with_gnu_ld=yes
    ;;
  openbsd*)
    with_gnu_ld=no
    ;;
  linux* | k*bsd*-gnu)
    link_all_deplibs=no
    ;;
  esac

  ld_shlibs=yes
  if test "$with_gnu_ld" = yes; then
    # If archive_cmds runs LD, not CC, wlarc should be empty
    wlarc='${wl}'

    # Set some defaults for GNU ld with shared library support. These
    # are reset later if shared libraries are not supported. Putting them
    # here allows them to be overridden if necessary.
    runpath_var=LD_RUN_PATH
    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
    export_dynamic_flag_spec='${wl}--export-dynamic'
    # ancient GNU ld didn't support --whole-archive et. al.
    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
      whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
    else
      whole_archive_flag_spec=
    fi
    supports_anon_versioning=no
    case `$LD -v 2>&1` in
      *GNU\ gold*) supports_anon_versioning=yes ;;
      *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
      *\ 2.11.*) ;; # other 2.11 versions
      *) supports_anon_versioning=yes ;;
    esac

    # See if GNU ld supports shared libraries.
    case $host_os in
    aix[3-9]*)
      # On AIX/PPC, the GNU linker is very broken
      if test "$host_cpu" != ia64; then
	ld_shlibs=no
	cat <<_LT_EOF 1>&2

*** Warning: the GNU linker, at least up to release 2.9.1, is reported
*** to be unable to reliably create shared libraries on AIX.
*** Therefore, libtool is disabling shared libraries support.  If you
*** really care for shared libraries, you may want to modify your PATH
*** so that a non-GNU linker is found, and then restart.

_LT_EOF
      fi
      ;;

    amigaos*)
      case $host_cpu in
      powerpc)
            # see comment about AmigaOS4 .so support
            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
            archive_expsym_cmds=''
        ;;
      m68k)
            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
            hardcode_libdir_flag_spec='-L$libdir'
            hardcode_minus_L=yes
        ;;
      esac
      ;;

    beos*)
      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
	allow_undefined_flag=unsupported
	# Joseph Beckenbach  says some releases of gcc
	# support --undefined.  This deserves some investigation.  FIXME
	archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
      else
	ld_shlibs=no
      fi
      ;;

    cygwin* | mingw* | pw32* | cegcc*)
      # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
      # as there is no search path for DLLs.
      hardcode_libdir_flag_spec='-L$libdir'
      allow_undefined_flag=unsupported
      always_export_symbols=no
      enable_shared_with_static_runtimes=yes
      export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'

      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
        archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
	# If the export-symbols file already is a .def file (1st line
	# is EXPORTS), use it as is; otherwise, prepend...
	archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
	  cp $export_symbols $output_objdir/$soname.def;
	else
	  echo EXPORTS > $output_objdir/$soname.def;
	  cat $export_symbols >> $output_objdir/$soname.def;
	fi~
	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
      else
	ld_shlibs=no
      fi
      ;;

    interix[3-9]*)
      hardcode_direct=no
      hardcode_shlibpath_var=no
      hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
      export_dynamic_flag_spec='${wl}-E'
      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
      # Instead, shared libraries are loaded at an image base (0x10000000 by
      # default) and relocated if they conflict, which is a slow very memory
      # consuming and fragmenting process.  To avoid this, we pick a random,
      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
      archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
      archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
      ;;

    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
      tmp_diet=no
      if test "$host_os" = linux-dietlibc; then
	case $cc_basename in
	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
	esac
      fi
      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
	 && test "$tmp_diet" = no
      then
	tmp_addflag=
	tmp_sharedflag='-shared'
	case $cc_basename,$host_cpu in
        pgcc*)				# Portland Group C compiler
	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
	  tmp_addflag=' $pic_flag'
	  ;;
	pgf77* | pgf90* | pgf95*)	# Portland Group f77 and f90 compilers
	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
	  tmp_addflag=' $pic_flag -Mnomain' ;;
	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
	  tmp_addflag=' -i_dynamic' ;;
	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
	  tmp_addflag=' -i_dynamic -nofor_main' ;;
	ifc* | ifort*)			# Intel Fortran compiler
	  tmp_addflag=' -nofor_main' ;;
	lf95*)				# Lahey Fortran 8.1
	  whole_archive_flag_spec=
	  tmp_sharedflag='--shared' ;;
	xl[cC]*)			# IBM XL C 8.0 on PPC (deal with xlf below)
	  tmp_sharedflag='-qmkshrobj'
	  tmp_addflag= ;;
	esac
	case `$CC -V 2>&1 | sed 5q` in
	*Sun\ C*)			# Sun C 5.9
	  whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
	  compiler_needs_object=yes
	  tmp_sharedflag='-G' ;;
	*Sun\ F*)			# Sun Fortran 8.3
	  tmp_sharedflag='-G' ;;
	esac
	archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'

        if test "x$supports_anon_versioning" = xyes; then
          archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
	    cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
	    echo "local: *; };" >> $output_objdir/$libname.ver~
	    $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
        fi

	case $cc_basename in
	xlf*)
	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
	  whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
	  hardcode_libdir_flag_spec=
	  hardcode_libdir_flag_spec_ld='-rpath $libdir'
	  archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib'
	  if test "x$supports_anon_versioning" = xyes; then
	    archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
	      cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
	      echo "local: *; };" >> $output_objdir/$libname.ver~
	      $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
	  fi
	  ;;
	esac
      else
        ld_shlibs=no
      fi
      ;;

    netbsd* | netbsdelf*-gnu)
      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
	archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
	wlarc=
      else
	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
      fi
      ;;

    solaris*)
      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
	ld_shlibs=no
	cat <<_LT_EOF 1>&2

*** Warning: The releases 2.8.* of the GNU linker cannot reliably
*** create shared libraries on Solaris systems.  Therefore, libtool
*** is disabling shared libraries support.  We urge you to upgrade GNU
*** binutils to release 2.9.1 or newer.  Another option is to modify
*** your PATH or compiler configuration so that the native linker is
*** used, and then restart.

_LT_EOF
      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
      else
	ld_shlibs=no
      fi
      ;;

    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
      case `$LD -v 2>&1` in
        *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
	ld_shlibs=no
	cat <<_LT_EOF 1>&2

*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
*** reliably create shared libraries on SCO systems.  Therefore, libtool
*** is disabling shared libraries support.  We urge you to upgrade GNU
*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
*** your PATH or compiler configuration so that the native linker is
*** used, and then restart.

_LT_EOF
	;;
	*)
	  # For security reasons, it is highly recommended that you always
	  # use absolute paths for naming shared libraries, and exclude the
	  # DT_RUNPATH tag from executables and libraries.  But doing so
	  # requires that you compile everything twice, which is a pain.
	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
	    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
	    archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
	    archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
	  else
	    ld_shlibs=no
	  fi
	;;
      esac
      ;;

    sunos4*)
      archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
      wlarc=
      hardcode_direct=yes
      hardcode_shlibpath_var=no
      ;;

    *)
      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
      else
	ld_shlibs=no
      fi
      ;;
    esac

    if test "$ld_shlibs" = no; then
      runpath_var=
      hardcode_libdir_flag_spec=
      export_dynamic_flag_spec=
      whole_archive_flag_spec=
    fi
  else
    # PORTME fill in a description of your system's linker (not GNU ld)
    case $host_os in
    aix3*)
      allow_undefined_flag=unsupported
      always_export_symbols=yes
      archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
      # Note: this linker hardcodes the directories in LIBPATH if there
      # are no directories specified by -L.
      hardcode_minus_L=yes
      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
	# Neither direct hardcoding nor static linking is supported with a
	# broken collect2.
	hardcode_direct=unsupported
      fi
      ;;

    aix[4-9]*)
      if test "$host_cpu" = ia64; then
	# On IA64, the linker does run time linking by default, so we don't
	# have to do anything special.
	aix_use_runtimelinking=no
	exp_sym_flag='-Bexport'
	no_entry_flag=""
      else
	# If we're using GNU nm, then we don't want the "-C" option.
	# -C means demangle to AIX nm, but means don't demangle with GNU nm
	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
	else
	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
	fi
	aix_use_runtimelinking=no

	# Test if we are trying to use run time linking or normal
	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
	# need to do runtime linking.
	case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
	  for ld_flag in $LDFLAGS; do
	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
	    aix_use_runtimelinking=yes
	    break
	  fi
	  done
	  ;;
	esac

	exp_sym_flag='-bexport'
	no_entry_flag='-bnoentry'
      fi

      # When large executables or shared objects are built, AIX ld can
      # have problems creating the table of contents.  If linking a library
      # or program results in "error TOC overflow" add -mminimal-toc to
      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.

      archive_cmds=''
      hardcode_direct=yes
      hardcode_direct_absolute=yes
      hardcode_libdir_separator=':'
      link_all_deplibs=yes
      file_list_spec='${wl}-f,'

      if test "$GCC" = yes; then
	case $host_os in aix4.[012]|aix4.[012].*)
	# We only want to do this on AIX 4.2 and lower, the check
	# below for broken collect2 doesn't work under 4.3+
	  collect2name=`${CC} -print-prog-name=collect2`
	  if test -f "$collect2name" &&
	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
	  then
	  # We have reworked collect2
	  :
	  else
	  # We have old collect2
	  hardcode_direct=unsupported
	  # It fails to find uninstalled libraries when the uninstalled
	  # path is not listed in the libpath.  Setting hardcode_minus_L
	  # to unsupported forces relinking
	  hardcode_minus_L=yes
	  hardcode_libdir_flag_spec='-L$libdir'
	  hardcode_libdir_separator=
	  fi
	  ;;
	esac
	shared_flag='-shared'
	if test "$aix_use_runtimelinking" = yes; then
	  shared_flag="$shared_flag "'${wl}-G'
	fi
	link_all_deplibs=no
      else
	# not using gcc
	if test "$host_cpu" = ia64; then
	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
	# chokes on -Wl,-G. The following line is correct:
	  shared_flag='-G'
	else
	  if test "$aix_use_runtimelinking" = yes; then
	    shared_flag='${wl}-G'
	  else
	    shared_flag='${wl}-bM:SRE'
	  fi
	fi
      fi

      export_dynamic_flag_spec='${wl}-bexpall'
      # It seems that -bexpall does not export symbols beginning with
      # underscore (_), so it is better to generate a list of symbols to export.
      always_export_symbols=yes
      if test "$aix_use_runtimelinking" = yes; then
	# Warning - without using the other runtime loading flags (-brtl),
	# -berok will link without error, but may produce a broken library.
	allow_undefined_flag='-berok'
        # Determine the default libpath from the value encoded in an
        # empty executable.
        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :

lt_aix_libpath_sed='
    /Import File Strings/,/^$/ {
	/^0/ {
	    s/^0  *\(.*\)$/\1/
	    p
	}
    }'
aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
# Check for a 64-bit object if we didn't find anything.
if test -z "$aix_libpath"; then
  aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
fi
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi

        hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
        archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
      else
	if test "$host_cpu" = ia64; then
	  hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
	  allow_undefined_flag="-z nodefs"
	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
	else
	 # Determine the default libpath from the value encoded in an
	 # empty executable.
	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :

lt_aix_libpath_sed='
    /Import File Strings/,/^$/ {
	/^0/ {
	    s/^0  *\(.*\)$/\1/
	    p
	}
    }'
aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
# Check for a 64-bit object if we didn't find anything.
if test -z "$aix_libpath"; then
  aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
fi
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi

	 hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
	  # Warning - without using the other run time loading flags,
	  # -berok will link without error, but may produce a broken library.
	  no_undefined_flag=' ${wl}-bernotok'
	  allow_undefined_flag=' ${wl}-berok'
	  # Exported symbols can be pulled into shared objects from archives
	  whole_archive_flag_spec='$convenience'
	  archive_cmds_need_lc=yes
	  # This is similar to how AIX traditionally builds its shared libraries.
	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
	fi
      fi
      ;;

    amigaos*)
      case $host_cpu in
      powerpc)
            # see comment about AmigaOS4 .so support
            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
            archive_expsym_cmds=''
        ;;
      m68k)
            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
            hardcode_libdir_flag_spec='-L$libdir'
            hardcode_minus_L=yes
        ;;
      esac
      ;;

    bsdi[45]*)
      export_dynamic_flag_spec=-rdynamic
      ;;

    cygwin* | mingw* | pw32* | cegcc*)
      # When not using gcc, we currently assume that we are using
      # Microsoft Visual C++.
      # hardcode_libdir_flag_spec is actually meaningless, as there is
      # no search path for DLLs.
      hardcode_libdir_flag_spec=' '
      allow_undefined_flag=unsupported
      # Tell ltmain to make .lib files, not .a files.
      libext=lib
      # Tell ltmain to make .dll files, not .so files.
      shrext_cmds=".dll"
      # FIXME: Setting linknames here is a bad hack.
      archive_cmds='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames='
      # The linker will automatically build a .lib file if we build a DLL.
      old_archive_from_new_cmds='true'
      # FIXME: Should let the user specify the lib program.
      old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
      fix_srcfile_path='`cygpath -w "$srcfile"`'
      enable_shared_with_static_runtimes=yes
      ;;

    darwin* | rhapsody*)


  archive_cmds_need_lc=no
  hardcode_direct=no
  hardcode_automatic=yes
  hardcode_shlibpath_var=unsupported
  whole_archive_flag_spec=''
  link_all_deplibs=yes
  allow_undefined_flag="$_lt_dar_allow_undefined"
  case $cc_basename in
     ifort*) _lt_dar_can_shared=yes ;;
     *) _lt_dar_can_shared=$GCC ;;
  esac
  if test "$_lt_dar_can_shared" = "yes"; then
    output_verbose_link_cmd=echo
    archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
    module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
    archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
    module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"

  else
  ld_shlibs=no
  fi

      ;;

    dgux*)
      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
      hardcode_libdir_flag_spec='-L$libdir'
      hardcode_shlibpath_var=no
      ;;

    freebsd1*)
      ld_shlibs=no
      ;;

    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
    # support.  Future versions do this automatically, but an explicit c++rt0.o
    # does not break anything, and helps significantly (at the cost of a little
    # extra space).
    freebsd2.2*)
      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
      hardcode_libdir_flag_spec='-R$libdir'
      hardcode_direct=yes
      hardcode_shlibpath_var=no
      ;;

    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
    freebsd2*)
      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
      hardcode_direct=yes
      hardcode_minus_L=yes
      hardcode_shlibpath_var=no
      ;;

    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
    freebsd* | dragonfly*)
      archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
      hardcode_libdir_flag_spec='-R$libdir'
      hardcode_direct=yes
      hardcode_shlibpath_var=no
      ;;

    hpux9*)
      if test "$GCC" = yes; then
	archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
      else
	archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
      fi
      hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
      hardcode_libdir_separator=:
      hardcode_direct=yes

      # hardcode_minus_L: Not really in the search PATH,
      # but as the default location of the library.
      hardcode_minus_L=yes
      export_dynamic_flag_spec='${wl}-E'
      ;;

    hpux10*)
      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
	archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
      else
	archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
      fi
      if test "$with_gnu_ld" = no; then
	hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
	hardcode_libdir_flag_spec_ld='+b $libdir'
	hardcode_libdir_separator=:
	hardcode_direct=yes
	hardcode_direct_absolute=yes
	export_dynamic_flag_spec='${wl}-E'
	# hardcode_minus_L: Not really in the search PATH,
	# but as the default location of the library.
	hardcode_minus_L=yes
      fi
      ;;

    hpux11*)
      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
	case $host_cpu in
	hppa*64*)
	  archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
	  ;;
	ia64*)
	  archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
	  ;;
	*)
	  archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
	  ;;
	esac
      else
	case $host_cpu in
	hppa*64*)
	  archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
	  ;;
	ia64*)
	  archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
	  ;;
	*)
	  archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
	  ;;
	esac
      fi
      if test "$with_gnu_ld" = no; then
	hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
	hardcode_libdir_separator=:

	case $host_cpu in
	hppa*64*|ia64*)
	  hardcode_direct=no
	  hardcode_shlibpath_var=no
	  ;;
	*)
	  hardcode_direct=yes
	  hardcode_direct_absolute=yes
	  export_dynamic_flag_spec='${wl}-E'

	  # hardcode_minus_L: Not really in the search PATH,
	  # but as the default location of the library.
	  hardcode_minus_L=yes
	  ;;
	esac
      fi
      ;;

    irix5* | irix6* | nonstopux*)
      if test "$GCC" = yes; then
	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
	# Try to use the -exported_symbol ld option, if it does not
	# work, assume that -exports_file does not work either and
	# implicitly export all symbols.
        save_LDFLAGS="$LDFLAGS"
        LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
int foo(void) {}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'

fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
        LDFLAGS="$save_LDFLAGS"
      else
	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
      fi
      archive_cmds_need_lc='no'
      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
      hardcode_libdir_separator=:
      inherit_rpath=yes
      link_all_deplibs=yes
      ;;

    netbsd* | netbsdelf*-gnu)
      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
	archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
      else
	archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
      fi
      hardcode_libdir_flag_spec='-R$libdir'
      hardcode_direct=yes
      hardcode_shlibpath_var=no
      ;;

    newsos6)
      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
      hardcode_direct=yes
      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
      hardcode_libdir_separator=:
      hardcode_shlibpath_var=no
      ;;

    *nto* | *qnx*)
      ;;

    openbsd*)
      if test -f /usr/libexec/ld.so; then
	hardcode_direct=yes
	hardcode_shlibpath_var=no
	hardcode_direct_absolute=yes
	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
	  archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
	  archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
	  hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
	  export_dynamic_flag_spec='${wl}-E'
	else
	  case $host_os in
	   openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
	     archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
	     hardcode_libdir_flag_spec='-R$libdir'
	     ;;
	   *)
	     archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
	     hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
	     ;;
	  esac
	fi
      else
	ld_shlibs=no
      fi
      ;;

    os2*)
      hardcode_libdir_flag_spec='-L$libdir'
      hardcode_minus_L=yes
      allow_undefined_flag=unsupported
      archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
      old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
      ;;

    osf3*)
      if test "$GCC" = yes; then
	allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
      else
	allow_undefined_flag=' -expect_unresolved \*'
	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
      fi
      archive_cmds_need_lc='no'
      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
      hardcode_libdir_separator=:
      ;;

    osf4* | osf5*)	# as osf3* with the addition of -msym flag
      if test "$GCC" = yes; then
	allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
	hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
      else
	allow_undefined_flag=' -expect_unresolved \*'
	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
	archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
	$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'

	# Both c and cxx compiler support -rpath directly
	hardcode_libdir_flag_spec='-rpath $libdir'
      fi
      archive_cmds_need_lc='no'
      hardcode_libdir_separator=:
      ;;

    solaris*)
      no_undefined_flag=' -z defs'
      if test "$GCC" = yes; then
	wlarc='${wl}'
	archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
	archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
	  $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
      else
	case `$CC -V 2>&1` in
	*"Compilers 5.0"*)
	  wlarc=''
	  archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
	  $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
	  ;;
	*)
	  wlarc='${wl}'
	  archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
	  $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
	  ;;
	esac
      fi
      hardcode_libdir_flag_spec='-R$libdir'
      hardcode_shlibpath_var=no
      case $host_os in
      solaris2.[0-5] | solaris2.[0-5].*) ;;
      *)
	# The compiler driver will combine and reorder linker options,
	# but understands `-z linker_flag'.  GCC discards it without `$wl',
	# but is careful enough not to reorder.
	# Supported since Solaris 2.6 (maybe 2.5.1?)
	if test "$GCC" = yes; then
	  whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
	else
	  whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
	fi
	;;
      esac
      link_all_deplibs=yes
      ;;

    sunos4*)
      if test "x$host_vendor" = xsequent; then
	# Use $CC to link under sequent, because it throws in some extra .o
	# files that make .init and .fini sections work.
	archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
      else
	archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
      fi
      hardcode_libdir_flag_spec='-L$libdir'
      hardcode_direct=yes
      hardcode_minus_L=yes
      hardcode_shlibpath_var=no
      ;;

    sysv4)
      case $host_vendor in
	sni)
	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
	  hardcode_direct=yes # is this really true???
	;;
	siemens)
	  ## LD is ld it makes a PLAMLIB
	  ## CC just makes a GrossModule.
	  archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
	  reload_cmds='$CC -r -o $output$reload_objs'
	  hardcode_direct=no
        ;;
	motorola)
	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
	  hardcode_direct=no #Motorola manual says yes, but my tests say they lie
	;;
      esac
      runpath_var='LD_RUN_PATH'
      hardcode_shlibpath_var=no
      ;;

    sysv4.3*)
      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
      hardcode_shlibpath_var=no
      export_dynamic_flag_spec='-Bexport'
      ;;

    sysv4*MP*)
      if test -d /usr/nec; then
	archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
	hardcode_shlibpath_var=no
	runpath_var=LD_RUN_PATH
	hardcode_runpath_var=yes
	ld_shlibs=yes
      fi
      ;;

    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
      no_undefined_flag='${wl}-z,text'
      archive_cmds_need_lc=no
      hardcode_shlibpath_var=no
      runpath_var='LD_RUN_PATH'

      if test "$GCC" = yes; then
	archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
	archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
      else
	archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
	archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
      fi
      ;;

    sysv5* | sco3.2v5* | sco5v6*)
      # Note: We can NOT use -z defs as we might desire, because we do not
      # link with -lc, and that would cause any symbols used from libc to
      # always be unresolved, which means just about no library would
      # ever link correctly.  If we're not using GNU ld we use -z text
      # though, which does catch some bad symbols but isn't as heavy-handed
      # as -z defs.
      no_undefined_flag='${wl}-z,text'
      allow_undefined_flag='${wl}-z,nodefs'
      archive_cmds_need_lc=no
      hardcode_shlibpath_var=no
      hardcode_libdir_flag_spec='${wl}-R,$libdir'
      hardcode_libdir_separator=':'
      link_all_deplibs=yes
      export_dynamic_flag_spec='${wl}-Bexport'
      runpath_var='LD_RUN_PATH'

      if test "$GCC" = yes; then
	archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
	archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
      else
	archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
	archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
      fi
      ;;

    uts4*)
      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
      hardcode_libdir_flag_spec='-L$libdir'
      hardcode_shlibpath_var=no
      ;;

    *)
      ld_shlibs=no
      ;;
    esac

    if test x$host_vendor = xsni; then
      case $host in
      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
	export_dynamic_flag_spec='${wl}-Blargedynsym'
	;;
      esac
    fi
  fi

{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
$as_echo "$ld_shlibs" >&6; }
test "$ld_shlibs" = no && can_build_shared=no

with_gnu_ld=$with_gnu_ld















#
# Do we need to explicitly link libc?
#
case "x$archive_cmds_need_lc" in
x|xyes)
  # Assume -lc should be added
  archive_cmds_need_lc=yes

  if test "$enable_shared" = yes && test "$GCC" = yes; then
    case $archive_cmds in
    *'~'*)
      # FIXME: we may have to deal with multi-command sequences.
      ;;
    '$CC '*)
      # Test whether the compiler implicitly links with -lc since on some
      # systems, -lgcc has to come before -lc. If gcc already passes -lc
      # to ld, don't add -lc before -lgcc.
      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
      $RM conftest*
      echo "$lt_simple_compile_test_code" > conftest.$ac_ext

      if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
  (eval $ac_compile) 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } 2>conftest.err; then
        soname=conftest
        lib=conftest
        libobjs=conftest.$ac_objext
        deplibs=
        wl=$lt_prog_compiler_wl
	pic_flag=$lt_prog_compiler_pic
        compiler_flags=-v
        linker_flags=-v
        verstring=
        output_objdir=.
        libname=conftest
        lt_save_allow_undefined_flag=$allow_undefined_flag
        allow_undefined_flag=
        if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
  (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }
        then
	  archive_cmds_need_lc=no
        else
	  archive_cmds_need_lc=yes
        fi
        allow_undefined_flag=$lt_save_allow_undefined_flag
      else
        cat conftest.err 1>&5
      fi
      $RM conftest*
      { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc" >&5
$as_echo "$archive_cmds_need_lc" >&6; }
      ;;
    esac
  fi
  ;;
esac





























































































































































  { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
$as_echo_n "checking dynamic linker characteristics... " >&6; }

if test "$GCC" = yes; then
  case $host_os in
    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
    *) lt_awk_arg="/^libraries:/" ;;
  esac
  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"`
  if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then
    # if the path contains ";" then we assume it to be the separator
    # otherwise default to the standard path separator (i.e. ":") - it is
    # assumed that no part of a normal pathname contains ";" but that should
    # okay in the real world where ";" in dirpaths is itself problematic.
    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'`
  else
    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
  fi
  # Ok, now we have the path, separated by spaces, we can step through it
  # and add multilib dir if necessary.
  lt_tmp_lt_search_path_spec=
  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
  for lt_sys_path in $lt_search_path_spec; do
    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
    else
      test -d "$lt_sys_path" && \
	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
    fi
  done
  lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk '
BEGIN {RS=" "; FS="/|\n";} {
  lt_foo="";
  lt_count=0;
  for (lt_i = NF; lt_i > 0; lt_i--) {
    if ($lt_i != "" && $lt_i != ".") {
      if ($lt_i == "..") {
        lt_count++;
      } else {
        if (lt_count == 0) {
          lt_foo="/" $lt_i lt_foo;
        } else {
          lt_count--;
        }
      }
    }
  }
  if (lt_foo != "") { lt_freq[lt_foo]++; }
  if (lt_freq[lt_foo] == 1) { print lt_foo; }
}'`
  sys_lib_search_path_spec=`$ECHO $lt_search_path_spec`
else
  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
fi
library_names_spec=
libname_spec='lib$name'
soname_spec=
shrext_cmds=".so"
postinstall_cmds=
postuninstall_cmds=
finish_cmds=
finish_eval=
shlibpath_var=
shlibpath_overrides_runpath=unknown
version_type=none
dynamic_linker="$host_os ld.so"
sys_lib_dlsearch_path_spec="/lib /usr/lib"
need_lib_prefix=unknown
hardcode_into_libs=no

# when you set need_version to no, make sure it does not cause -set_version
# flags to be left without arguments
need_version=unknown

case $host_os in
aix3*)
  version_type=linux
  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
  shlibpath_var=LIBPATH

  # AIX 3 has no versioning support, so we append a major version to the name.
  soname_spec='${libname}${release}${shared_ext}$major'
  ;;

aix[4-9]*)
  version_type=linux
  need_lib_prefix=no
  need_version=no
  hardcode_into_libs=yes
  if test "$host_cpu" = ia64; then
    # AIX 5 supports IA64
    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
    shlibpath_var=LD_LIBRARY_PATH
  else
    # With GCC up to 2.95.x, collect2 would create an import file
    # for dependence libraries.  The import file would start with
    # the line `#! .'.  This would cause the generated library to
    # depend on `.', always an invalid library.  This was fixed in
    # development snapshots of GCC prior to 3.0.
    case $host_os in
      aix4 | aix4.[01] | aix4.[01].*)
      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
	   echo ' yes '
	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
	:
      else
	can_build_shared=no
      fi
      ;;
    esac
    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
    # soname into executable. Probably we can add versioning support to
    # collect2, so additional links can be useful in future.
    if test "$aix_use_runtimelinking" = yes; then
      # If using run time linking (on AIX 4.2 or later) use lib.so
      # instead of lib.a to let people know that these are not
      # typical AIX shared libraries.
      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
    else
      # We preserve .a as extension for shared libraries through AIX4.2
      # and later when we are not doing run time linking.
      library_names_spec='${libname}${release}.a $libname.a'
      soname_spec='${libname}${release}${shared_ext}$major'
    fi
    shlibpath_var=LIBPATH
  fi
  ;;

amigaos*)
  case $host_cpu in
  powerpc)
    # Since July 2007 AmigaOS4 officially supports .so libraries.
    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
    ;;
  m68k)
    library_names_spec='$libname.ixlibrary $libname.a'
    # Create ${libname}_ixlibrary.a entries in /sys/libs.
    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
    ;;
  esac
  ;;

beos*)
  library_names_spec='${libname}${shared_ext}'
  dynamic_linker="$host_os ld.so"
  shlibpath_var=LIBRARY_PATH
  ;;

bsdi[45]*)
  version_type=linux
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
  shlibpath_var=LD_LIBRARY_PATH
  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
  # the default ld.so.conf also contains /usr/contrib/lib and
  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
  # libtool to hard-code these into programs
  ;;

cygwin* | mingw* | pw32* | cegcc*)
  version_type=windows
  shrext_cmds=".dll"
  need_version=no
  need_lib_prefix=no

  case $GCC,$host_os in
  yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*)
    library_names_spec='$libname.dll.a'
    # DLL is installed to $(libdir)/../bin by postinstall_cmds
    postinstall_cmds='base_file=`basename \${file}`~
      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
      dldir=$destdir/`dirname \$dlpath`~
      test -d \$dldir || mkdir -p \$dldir~
      $install_prog $dir/$dlname \$dldir/$dlname~
      chmod a+x \$dldir/$dlname~
      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
      fi'
    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
      dlpath=$dir/\$dldll~
       $RM \$dlpath'
    shlibpath_overrides_runpath=yes

    case $host_os in
    cygwin*)
      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
      ;;
    mingw* | cegcc*)
      # MinGW DLLs use traditional 'lib' prefix
      soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
      sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
      if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
        # It is most probably a Windows format PATH printed by
        # mingw gcc, but we are running on Cygwin. Gcc prints its search
        # path with ; separators, and with drive letters. We can handle the
        # drive letters (cygwin fileutils understands them), so leave them,
        # especially as we might pass files found there to a mingw objdump,
        # which wouldn't understand a cygwinified path. Ahh.
        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
      else
        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
      fi
      ;;
    pw32*)
      # pw32 DLLs use 'pw' prefix rather than 'lib'
      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
      ;;
    esac
    ;;

  *)
    library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
    ;;
  esac
  dynamic_linker='Win32 ld.exe'
  # FIXME: first we should search . and the directory the executable is in
  shlibpath_var=PATH
  ;;

darwin* | rhapsody*)
  dynamic_linker="$host_os dyld"
  version_type=darwin
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
  soname_spec='${libname}${release}${major}$shared_ext'
  shlibpath_overrides_runpath=yes
  shlibpath_var=DYLD_LIBRARY_PATH
  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'

  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
  ;;

dgux*)
  version_type=linux
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
  soname_spec='${libname}${release}${shared_ext}$major'
  shlibpath_var=LD_LIBRARY_PATH
  ;;

freebsd1*)
  dynamic_linker=no
  ;;

freebsd* | dragonfly*)
  # DragonFly does not have aout.  When/if they implement a new
  # versioning mechanism, adjust this.
  if test -x /usr/bin/objformat; then
    objformat=`/usr/bin/objformat`
  else
    case $host_os in
    freebsd[123]*) objformat=aout ;;
    *) objformat=elf ;;
    esac
  fi
  version_type=freebsd-$objformat
  case $version_type in
    freebsd-elf*)
      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
      need_version=no
      need_lib_prefix=no
      ;;
    freebsd-*)
      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
      need_version=yes
      ;;
  esac
  shlibpath_var=LD_LIBRARY_PATH
  case $host_os in
  freebsd2*)
    shlibpath_overrides_runpath=yes
    ;;
  freebsd3.[01]* | freebsdelf3.[01]*)
    shlibpath_overrides_runpath=yes
    hardcode_into_libs=yes
    ;;
  freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
  freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
    shlibpath_overrides_runpath=no
    hardcode_into_libs=yes
    ;;
  *) # from 4.6 on, and DragonFly
    shlibpath_overrides_runpath=yes
    hardcode_into_libs=yes
    ;;
  esac
  ;;

gnu*)
  version_type=linux
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  shlibpath_var=LD_LIBRARY_PATH
  hardcode_into_libs=yes
  ;;

hpux9* | hpux10* | hpux11*)
  # Give a soname corresponding to the major version so that dld.sl refuses to
  # link against other versions.
  version_type=sunos
  need_lib_prefix=no
  need_version=no
  case $host_cpu in
  ia64*)
    shrext_cmds='.so'
    hardcode_into_libs=yes
    dynamic_linker="$host_os dld.so"
    shlibpath_var=LD_LIBRARY_PATH
    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
    soname_spec='${libname}${release}${shared_ext}$major'
    if test "X$HPUX_IA64_MODE" = X32; then
      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
    else
      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
    fi
    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
    ;;
  hppa*64*)
    shrext_cmds='.sl'
    hardcode_into_libs=yes
    dynamic_linker="$host_os dld.sl"
    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
    soname_spec='${libname}${release}${shared_ext}$major'
    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
    ;;
  *)
    shrext_cmds='.sl'
    dynamic_linker="$host_os dld.sl"
    shlibpath_var=SHLIB_PATH
    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
    soname_spec='${libname}${release}${shared_ext}$major'
    ;;
  esac
  # HP-UX runs *really* slowly unless shared libraries are mode 555.
  postinstall_cmds='chmod 555 $lib'
  ;;

interix[3-9]*)
  version_type=linux
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=no
  hardcode_into_libs=yes
  ;;

irix5* | irix6* | nonstopux*)
  case $host_os in
    nonstopux*) version_type=nonstopux ;;
    *)
	if test "$lt_cv_prog_gnu_ld" = yes; then
		version_type=linux
	else
		version_type=irix
	fi ;;
  esac
  need_lib_prefix=no
  need_version=no
  soname_spec='${libname}${release}${shared_ext}$major'
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
  case $host_os in
  irix5* | nonstopux*)
    libsuff= shlibsuff=
    ;;
  *)
    case $LD in # libtool.m4 will add one of these switches to LD
    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
      libsuff= shlibsuff= libmagic=32-bit;;
    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
      libsuff=32 shlibsuff=N32 libmagic=N32;;
    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
      libsuff=64 shlibsuff=64 libmagic=64-bit;;
    *) libsuff= shlibsuff= libmagic=never-match;;
    esac
    ;;
  esac
  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
  shlibpath_overrides_runpath=no
  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
  hardcode_into_libs=yes
  ;;

# No shared lib support for Linux oldld, aout, or coff.
linux*oldld* | linux*aout* | linux*coff*)
  dynamic_linker=no
  ;;

# This must be Linux ELF.
linux* | k*bsd*-gnu | kopensolaris*-gnu)
  version_type=linux
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=no
  # Some binutils ld are patched to set DT_RUNPATH
  save_LDFLAGS=$LDFLAGS
  save_libdir=$libdir
  eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
       LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  if  ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
  shlibpath_overrides_runpath=yes
fi
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
  LDFLAGS=$save_LDFLAGS
  libdir=$save_libdir

  # This implies no fast_install, which is unacceptable.
  # Some rework will be needed to allow for fast_install
  # before this can be enabled.
  hardcode_into_libs=yes

  # Append ld.so.conf contents to the search path
  if test -f /etc/ld.so.conf; then
    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
  fi

  # We used to test for /lib/ld.so.1 and disable shared libraries on
  # powerpc, because MkLinux only supported shared libraries with the
  # GNU dynamic linker.  Since this was broken with cross compilers,
  # most powerpc-linux boxes support dynamic linking these days and
  # people can always --disable-shared, the test was removed, and we
  # assume the GNU/Linux dynamic linker is in use.
  dynamic_linker='GNU/Linux ld.so'
  ;;

netbsdelf*-gnu)
  version_type=linux
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=no
  hardcode_into_libs=yes
  dynamic_linker='NetBSD ld.elf_so'
  ;;

netbsd*)
  version_type=sunos
  need_lib_prefix=no
  need_version=no
  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
    dynamic_linker='NetBSD (a.out) ld.so'
  else
    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
    soname_spec='${libname}${release}${shared_ext}$major'
    dynamic_linker='NetBSD ld.elf_so'
  fi
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=yes
  hardcode_into_libs=yes
  ;;

newsos6)
  version_type=linux
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=yes
  ;;

*nto* | *qnx*)
  version_type=qnx
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=no
  hardcode_into_libs=yes
  dynamic_linker='ldqnx.so'
  ;;

openbsd*)
  version_type=sunos
  sys_lib_dlsearch_path_spec="/usr/lib"
  need_lib_prefix=no
  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
  case $host_os in
    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
    *)				need_version=no  ;;
  esac
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
  shlibpath_var=LD_LIBRARY_PATH
  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
    case $host_os in
      openbsd2.[89] | openbsd2.[89].*)
	shlibpath_overrides_runpath=no
	;;
      *)
	shlibpath_overrides_runpath=yes
	;;
      esac
  else
    shlibpath_overrides_runpath=yes
  fi
  ;;

os2*)
  libname_spec='$name'
  shrext_cmds=".dll"
  need_lib_prefix=no
  library_names_spec='$libname${shared_ext} $libname.a'
  dynamic_linker='OS/2 ld.exe'
  shlibpath_var=LIBPATH
  ;;

osf3* | osf4* | osf5*)
  version_type=osf
  need_lib_prefix=no
  need_version=no
  soname_spec='${libname}${release}${shared_ext}$major'
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
  shlibpath_var=LD_LIBRARY_PATH
  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
  ;;

rdos*)
  dynamic_linker=no
  ;;

solaris*)
  version_type=linux
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=yes
  hardcode_into_libs=yes
  # ldd complains unless libraries are executable
  postinstall_cmds='chmod +x $lib'
  ;;

sunos4*)
  version_type=sunos
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=yes
  if test "$with_gnu_ld" = yes; then
    need_lib_prefix=no
  fi
  need_version=yes
  ;;

sysv4 | sysv4.3*)
  version_type=linux
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  shlibpath_var=LD_LIBRARY_PATH
  case $host_vendor in
    sni)
      shlibpath_overrides_runpath=no
      need_lib_prefix=no
      runpath_var=LD_RUN_PATH
      ;;
    siemens)
      need_lib_prefix=no
      ;;
    motorola)
      need_lib_prefix=no
      need_version=no
      shlibpath_overrides_runpath=no
      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
      ;;
  esac
  ;;

sysv4*MP*)
  if test -d /usr/nec ;then
    version_type=linux
    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
    soname_spec='$libname${shared_ext}.$major'
    shlibpath_var=LD_LIBRARY_PATH
  fi
  ;;

sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
  version_type=freebsd-elf
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=yes
  hardcode_into_libs=yes
  if test "$with_gnu_ld" = yes; then
    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
  else
    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
    case $host_os in
      sco3.2v5*)
        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
	;;
    esac
  fi
  sys_lib_dlsearch_path_spec='/usr/lib'
  ;;

tpf*)
  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
  version_type=linux
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=no
  hardcode_into_libs=yes
  ;;

uts4*)
  version_type=linux
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  shlibpath_var=LD_LIBRARY_PATH
  ;;

*)
  dynamic_linker=no
  ;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
$as_echo "$dynamic_linker" >&6; }
test "$dynamic_linker" = no && can_build_shared=no

variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
if test "$GCC" = yes; then
  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
fi

if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
fi
if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
fi























































































  { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
hardcode_action=
if test -n "$hardcode_libdir_flag_spec" ||
   test -n "$runpath_var" ||
   test "X$hardcode_automatic" = "Xyes" ; then

  # We can hardcode non-existent directories.
  if test "$hardcode_direct" != no &&
     # If the only mechanism to avoid hardcoding is shlibpath_var, we
     # have to relink, otherwise we might link with an installed library
     # when we should be linking with a yet-to-be-installed one
     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no &&
     test "$hardcode_minus_L" != no; then
    # Linking always hardcodes the temporary library directory.
    hardcode_action=relink
  else
    # We can link without hardcoding, and we can hardcode nonexisting dirs.
    hardcode_action=immediate
  fi
else
  # We cannot hardcode anything, or else we can only hardcode existing
  # directories.
  hardcode_action=unsupported
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
$as_echo "$hardcode_action" >&6; }

if test "$hardcode_action" = relink ||
   test "$inherit_rpath" = yes; then
  # Fast installation is not supported
  enable_fast_install=no
elif test "$shlibpath_overrides_runpath" = yes ||
     test "$enable_shared" = no; then
  # Fast installation is not necessary
  enable_fast_install=needless
fi






  if test "x$enable_dlopen" != xyes; then
  enable_dlopen=unknown
  enable_dlopen_self=unknown
  enable_dlopen_self_static=unknown
else
  lt_cv_dlopen=no
  lt_cv_dlopen_libs=

  case $host_os in
  beos*)
    lt_cv_dlopen="load_add_on"
    lt_cv_dlopen_libs=
    lt_cv_dlopen_self=yes
    ;;

  mingw* | pw32* | cegcc*)
    lt_cv_dlopen="LoadLibrary"
    lt_cv_dlopen_libs=
    ;;

  cygwin*)
    lt_cv_dlopen="dlopen"
    lt_cv_dlopen_libs=
    ;;

  darwin*)
  # if libdl is installed we need to link against it
    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
$as_echo_n "checking for dlopen in -ldl... " >&6; }
if test "${ac_cv_lib_dl_dlopen+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  ac_check_lib_save_LIBS=$LIBS
LIBS="-ldl  $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

/* Override any GCC internal prototype to avoid an error.
   Use char because int might match the return type of a GCC
   builtin and then its argument prototype would still apply.  */
#ifdef __cplusplus
extern "C"
#endif
char dlopen ();
int
main ()
{
return dlopen ();
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  ac_cv_lib_dl_dlopen=yes
else
  ac_cv_lib_dl_dlopen=no
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
if test "x$ac_cv_lib_dl_dlopen" = x""yes; then :
  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
else

    lt_cv_dlopen="dyld"
    lt_cv_dlopen_libs=
    lt_cv_dlopen_self=yes

fi

    ;;

  *)
    ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
if test "x$ac_cv_func_shl_load" = x""yes; then :
  lt_cv_dlopen="shl_load"
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
$as_echo_n "checking for shl_load in -ldld... " >&6; }
if test "${ac_cv_lib_dld_shl_load+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  ac_check_lib_save_LIBS=$LIBS
LIBS="-ldld  $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

/* Override any GCC internal prototype to avoid an error.
   Use char because int might match the return type of a GCC
   builtin and then its argument prototype would still apply.  */
#ifdef __cplusplus
extern "C"
#endif
char shl_load ();
int
main ()
{
return shl_load ();
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  ac_cv_lib_dld_shl_load=yes
else
  ac_cv_lib_dld_shl_load=no
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
if test "x$ac_cv_lib_dld_shl_load" = x""yes; then :
  lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
else
  ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
if test "x$ac_cv_func_dlopen" = x""yes; then :
  lt_cv_dlopen="dlopen"
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
$as_echo_n "checking for dlopen in -ldl... " >&6; }
if test "${ac_cv_lib_dl_dlopen+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  ac_check_lib_save_LIBS=$LIBS
LIBS="-ldl  $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

/* Override any GCC internal prototype to avoid an error.
   Use char because int might match the return type of a GCC
   builtin and then its argument prototype would still apply.  */
#ifdef __cplusplus
extern "C"
#endif
char dlopen ();
int
main ()
{
return dlopen ();
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  ac_cv_lib_dl_dlopen=yes
else
  ac_cv_lib_dl_dlopen=no
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
if test "x$ac_cv_lib_dl_dlopen" = x""yes; then :
  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
$as_echo_n "checking for dlopen in -lsvld... " >&6; }
if test "${ac_cv_lib_svld_dlopen+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  ac_check_lib_save_LIBS=$LIBS
LIBS="-lsvld  $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

/* Override any GCC internal prototype to avoid an error.
   Use char because int might match the return type of a GCC
   builtin and then its argument prototype would still apply.  */
#ifdef __cplusplus
extern "C"
#endif
char dlopen ();
int
main ()
{
return dlopen ();
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  ac_cv_lib_svld_dlopen=yes
else
  ac_cv_lib_svld_dlopen=no
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
if test "x$ac_cv_lib_svld_dlopen" = x""yes; then :
  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
$as_echo_n "checking for dld_link in -ldld... " >&6; }
if test "${ac_cv_lib_dld_dld_link+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  ac_check_lib_save_LIBS=$LIBS
LIBS="-ldld  $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

/* Override any GCC internal prototype to avoid an error.
   Use char because int might match the return type of a GCC
   builtin and then its argument prototype would still apply.  */
#ifdef __cplusplus
extern "C"
#endif
char dld_link ();
int
main ()
{
return dld_link ();
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  ac_cv_lib_dld_dld_link=yes
else
  ac_cv_lib_dld_dld_link=no
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
if test "x$ac_cv_lib_dld_dld_link" = x""yes; then :
  lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
fi


fi


fi


fi


fi


fi

    ;;
  esac

  if test "x$lt_cv_dlopen" != xno; then
    enable_dlopen=yes
  else
    enable_dlopen=no
  fi

  case $lt_cv_dlopen in
  dlopen)
    save_CPPFLAGS="$CPPFLAGS"
    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"

    save_LDFLAGS="$LDFLAGS"
    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"

    save_LIBS="$LIBS"
    LIBS="$lt_cv_dlopen_libs $LIBS"

    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
$as_echo_n "checking whether a program can dlopen itself... " >&6; }
if test "${lt_cv_dlopen_self+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  	  if test "$cross_compiling" = yes; then :
  lt_cv_dlopen_self=cross
else
  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
  lt_status=$lt_dlunknown
  cat > conftest.$ac_ext <<_LT_EOF
#line 11552 "configure"
#include "confdefs.h"

#if HAVE_DLFCN_H
#include 
#endif

#include 

#ifdef RTLD_GLOBAL
#  define LT_DLGLOBAL		RTLD_GLOBAL
#else
#  ifdef DL_GLOBAL
#    define LT_DLGLOBAL		DL_GLOBAL
#  else
#    define LT_DLGLOBAL		0
#  endif
#endif

/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
   find out it does not work in some platform. */
#ifndef LT_DLLAZY_OR_NOW
#  ifdef RTLD_LAZY
#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
#  else
#    ifdef DL_LAZY
#      define LT_DLLAZY_OR_NOW		DL_LAZY
#    else
#      ifdef RTLD_NOW
#        define LT_DLLAZY_OR_NOW	RTLD_NOW
#      else
#        ifdef DL_NOW
#          define LT_DLLAZY_OR_NOW	DL_NOW
#        else
#          define LT_DLLAZY_OR_NOW	0
#        endif
#      endif
#    endif
#  endif
#endif

void fnord() { int i=42;}
int main ()
{
  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
  int status = $lt_dlunknown;

  if (self)
    {
      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
      /* dlclose (self); */
    }
  else
    puts (dlerror ());

  return status;
}
_LT_EOF
  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
  (eval $ac_link) 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
    (./conftest; exit; ) >&5 2>/dev/null
    lt_status=$?
    case x$lt_status in
      x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
      x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
      x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
    esac
  else :
    # compilation failed
    lt_cv_dlopen_self=no
  fi
fi
rm -fr conftest*


fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
$as_echo "$lt_cv_dlopen_self" >&6; }

    if test "x$lt_cv_dlopen_self" = xyes; then
      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
if test "${lt_cv_dlopen_self_static+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  	  if test "$cross_compiling" = yes; then :
  lt_cv_dlopen_self_static=cross
else
  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
  lt_status=$lt_dlunknown
  cat > conftest.$ac_ext <<_LT_EOF
#line 11648 "configure"
#include "confdefs.h"

#if HAVE_DLFCN_H
#include 
#endif

#include 

#ifdef RTLD_GLOBAL
#  define LT_DLGLOBAL		RTLD_GLOBAL
#else
#  ifdef DL_GLOBAL
#    define LT_DLGLOBAL		DL_GLOBAL
#  else
#    define LT_DLGLOBAL		0
#  endif
#endif

/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
   find out it does not work in some platform. */
#ifndef LT_DLLAZY_OR_NOW
#  ifdef RTLD_LAZY
#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
#  else
#    ifdef DL_LAZY
#      define LT_DLLAZY_OR_NOW		DL_LAZY
#    else
#      ifdef RTLD_NOW
#        define LT_DLLAZY_OR_NOW	RTLD_NOW
#      else
#        ifdef DL_NOW
#          define LT_DLLAZY_OR_NOW	DL_NOW
#        else
#          define LT_DLLAZY_OR_NOW	0
#        endif
#      endif
#    endif
#  endif
#endif

void fnord() { int i=42;}
int main ()
{
  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
  int status = $lt_dlunknown;

  if (self)
    {
      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
      /* dlclose (self); */
    }
  else
    puts (dlerror ());

  return status;
}
_LT_EOF
  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
  (eval $ac_link) 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
    (./conftest; exit; ) >&5 2>/dev/null
    lt_status=$?
    case x$lt_status in
      x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
      x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
      x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
    esac
  else :
    # compilation failed
    lt_cv_dlopen_self_static=no
  fi
fi
rm -fr conftest*


fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
$as_echo "$lt_cv_dlopen_self_static" >&6; }
    fi

    CPPFLAGS="$save_CPPFLAGS"
    LDFLAGS="$save_LDFLAGS"
    LIBS="$save_LIBS"
    ;;
  esac

  case $lt_cv_dlopen_self in
  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
  *) enable_dlopen_self=unknown ;;
  esac

  case $lt_cv_dlopen_self_static in
  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
  *) enable_dlopen_self_static=unknown ;;
  esac
fi

















striplib=
old_striplib=
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
$as_echo_n "checking whether stripping libraries is possible... " >&6; }
if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
# FIXME - insert some real tests, host_os isn't really good enough
  case $host_os in
  darwin*)
    if test -n "$STRIP" ; then
      striplib="$STRIP -x"
      old_striplib="$STRIP -S"
      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
    else
      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
    fi
    ;;
  *)
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
    ;;
  esac
fi












  # Report which library types will actually be built
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
$as_echo_n "checking if libtool supports shared libraries... " >&6; }
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
$as_echo "$can_build_shared" >&6; }

  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
$as_echo_n "checking whether to build shared libraries... " >&6; }
  test "$can_build_shared" = "no" && enable_shared=no

  # On AIX, shared libraries and static libraries use the same namespace, and
  # are all built from PIC.
  case $host_os in
  aix3*)
    test "$enable_shared" = yes && enable_static=no
    if test -n "$RANLIB"; then
      archive_cmds="$archive_cmds~\$RANLIB \$lib"
      postinstall_cmds='$RANLIB $lib'
    fi
    ;;

  aix[4-9]*)
    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
      test "$enable_shared" = yes && enable_static=no
    fi
    ;;
  esac
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
$as_echo "$enable_shared" >&6; }

  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
$as_echo_n "checking whether to build static libraries... " >&6; }
  # Make sure either enable_shared or enable_static is yes.
  test "$enable_shared" = yes || enable_static=yes
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
$as_echo "$enable_static" >&6; }




fi
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu

CC="$lt_save_CC"


ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu

archive_cmds_need_lc_CXX=no
allow_undefined_flag_CXX=
always_export_symbols_CXX=no
archive_expsym_cmds_CXX=
compiler_needs_object_CXX=no
export_dynamic_flag_spec_CXX=
hardcode_direct_CXX=no
hardcode_direct_absolute_CXX=no
hardcode_libdir_flag_spec_CXX=
hardcode_libdir_flag_spec_ld_CXX=
hardcode_libdir_separator_CXX=
hardcode_minus_L_CXX=no
hardcode_shlibpath_var_CXX=unsupported
hardcode_automatic_CXX=no
inherit_rpath_CXX=no
module_cmds_CXX=
module_expsym_cmds_CXX=
link_all_deplibs_CXX=unknown
old_archive_cmds_CXX=$old_archive_cmds
no_undefined_flag_CXX=
whole_archive_flag_spec_CXX=
enable_shared_with_static_runtimes_CXX=no

# Source file extension for C++ test sources.
ac_ext=cpp

# Object file extension for compiled C++ test sources.
objext=o
objext_CXX=$objext

# No sense in running all these tests if we already determined that
# the CXX compiler isn't working.  Some variables (like enable_shared)
# are currently assumed to apply to all compilers on this platform,
# and will be corrupted by setting them based on a non-working compiler.
if test "$_lt_caught_CXX_error" != yes; then
  # Code to be used in simple compile tests
  lt_simple_compile_test_code="int some_variable = 0;"

  # Code to be used in simple link tests
  lt_simple_link_test_code='int main(int, char *[]) { return(0); }'

  # ltmain only uses $CC for tagged configurations so make sure $CC is set.






# If no C compiler was specified, use CC.
LTCC=${LTCC-"$CC"}

# If no C compiler flags were specified, use CFLAGS.
LTCFLAGS=${LTCFLAGS-"$CFLAGS"}

# Allow CC to be a program name with arguments.
compiler=$CC


  # save warnings/boilerplate of simple test code
  ac_outfile=conftest.$ac_objext
echo "$lt_simple_compile_test_code" >conftest.$ac_ext
eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
_lt_compiler_boilerplate=`cat conftest.err`
$RM conftest*

  ac_outfile=conftest.$ac_objext
echo "$lt_simple_link_test_code" >conftest.$ac_ext
eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
_lt_linker_boilerplate=`cat conftest.err`
$RM -r conftest*


  # Allow CC to be a program name with arguments.
  lt_save_CC=$CC
  lt_save_LD=$LD
  lt_save_GCC=$GCC
  GCC=$GXX
  lt_save_with_gnu_ld=$with_gnu_ld
  lt_save_path_LD=$lt_cv_path_LD
  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
  else
    $as_unset lt_cv_prog_gnu_ld
  fi
  if test -n "${lt_cv_path_LDCXX+set}"; then
    lt_cv_path_LD=$lt_cv_path_LDCXX
  else
    $as_unset lt_cv_path_LD
  fi
  test -z "${LDCXX+set}" || LD=$LDCXX
  CC=${CXX-"c++"}
  compiler=$CC
  compiler_CXX=$CC
  for cc_temp in $compiler""; do
  case $cc_temp in
    compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
    distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
    \-*) ;;
    *) break;;
  esac
done
cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`


  if test -n "$compiler"; then
    # We don't want -fno-exception when compiling C++ code, so set the
    # no_builtin_flag separately
    if test "$GXX" = yes; then
      lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin'
    else
      lt_prog_compiler_no_builtin_flag_CXX=
    fi

    if test "$GXX" = yes; then
      # Set up default GNU C++ configuration



# Check whether --with-gnu-ld was given.
if test "${with_gnu_ld+set}" = set; then :
  withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
else
  with_gnu_ld=no
fi

ac_prog=ld
if test "$GCC" = yes; then
  # Check if gcc -print-prog-name=ld gives a path.
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
$as_echo_n "checking for ld used by $CC... " >&6; }
  case $host in
  *-*-mingw*)
    # gcc leaves a trailing carriage return which upsets mingw
    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
  *)
    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
  esac
  case $ac_prog in
    # Accept absolute paths.
    [\\/]* | ?:[\\/]*)
      re_direlt='/[^/][^/]*/\.\./'
      # Canonicalize the pathname of ld
      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
      done
      test -z "$LD" && LD="$ac_prog"
      ;;
  "")
    # If it fails, then pretend we aren't using GCC.
    ac_prog=ld
    ;;
  *)
    # If it is relative, then search for the first ld in PATH.
    with_gnu_ld=unknown
    ;;
  esac
elif test "$with_gnu_ld" = yes; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
$as_echo_n "checking for GNU ld... " >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
$as_echo_n "checking for non-GNU ld... " >&6; }
fi
if test "${lt_cv_path_LD+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -z "$LD"; then
  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
  for ac_dir in $PATH; do
    IFS="$lt_save_ifs"
    test -z "$ac_dir" && ac_dir=.
    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
      lt_cv_path_LD="$ac_dir/$ac_prog"
      # Check to see if the program is GNU ld.  I'd rather use --version,
      # but apparently some variants of GNU ld only accept -v.
      # Break only if it was the GNU/non-GNU ld that we prefer.
      case `"$lt_cv_path_LD" -v 2>&1 &5
$as_echo "$LD" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
test -z "$LD" && as_fn_error "no acceptable ld found in \$PATH" "$LINENO" 5
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
if test "${lt_cv_prog_gnu_ld+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  # I'd rather use --version here, but apparently some GNU lds only accept -v.
case `$LD -v 2>&1 &5
$as_echo "$lt_cv_prog_gnu_ld" >&6; }
with_gnu_ld=$lt_cv_prog_gnu_ld







      # Check if GNU C++ uses GNU ld as the underlying linker, since the
      # archiving commands below assume that GNU ld is being used.
      if test "$with_gnu_ld" = yes; then
        archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
        archive_expsym_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'

        hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
        export_dynamic_flag_spec_CXX='${wl}--export-dynamic'

        # If archive_cmds runs LD, not CC, wlarc should be empty
        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
        #     investigate it a little bit more. (MM)
        wlarc='${wl}'

        # ancient GNU ld didn't support --whole-archive et. al.
        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
	  $GREP 'no-whole-archive' > /dev/null; then
          whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
        else
          whole_archive_flag_spec_CXX=
        fi
      else
        with_gnu_ld=no
        wlarc=

        # A generic and very simple default shared library creation
        # command for GNU C++ for the case where it uses the native
        # linker, instead of GNU ld.  If possible, this setting should
        # overridden to take advantage of the native linker features on
        # the platform it is being used on.
        archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
      fi

      # Commands to make compiler produce verbose output that lists
      # what "hidden" libraries, object files and flags are used when
      # linking a shared library.
      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'

    else
      GXX=no
      with_gnu_ld=no
      wlarc=
    fi

    # PORTME: fill in a description of your system's C++ link characteristics
    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
    ld_shlibs_CXX=yes
    case $host_os in
      aix3*)
        # FIXME: insert proper C++ library support
        ld_shlibs_CXX=no
        ;;
      aix[4-9]*)
        if test "$host_cpu" = ia64; then
          # On IA64, the linker does run time linking by default, so we don't
          # have to do anything special.
          aix_use_runtimelinking=no
          exp_sym_flag='-Bexport'
          no_entry_flag=""
        else
          aix_use_runtimelinking=no

          # Test if we are trying to use run time linking or normal
          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
          # need to do runtime linking.
          case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
	    for ld_flag in $LDFLAGS; do
	      case $ld_flag in
	      *-brtl*)
	        aix_use_runtimelinking=yes
	        break
	        ;;
	      esac
	    done
	    ;;
          esac

          exp_sym_flag='-bexport'
          no_entry_flag='-bnoentry'
        fi

        # When large executables or shared objects are built, AIX ld can
        # have problems creating the table of contents.  If linking a library
        # or program results in "error TOC overflow" add -mminimal-toc to
        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.

        archive_cmds_CXX=''
        hardcode_direct_CXX=yes
        hardcode_direct_absolute_CXX=yes
        hardcode_libdir_separator_CXX=':'
        link_all_deplibs_CXX=yes
        file_list_spec_CXX='${wl}-f,'

        if test "$GXX" = yes; then
          case $host_os in aix4.[012]|aix4.[012].*)
          # We only want to do this on AIX 4.2 and lower, the check
          # below for broken collect2 doesn't work under 4.3+
	  collect2name=`${CC} -print-prog-name=collect2`
	  if test -f "$collect2name" &&
	     strings "$collect2name" | $GREP resolve_lib_name >/dev/null
	  then
	    # We have reworked collect2
	    :
	  else
	    # We have old collect2
	    hardcode_direct_CXX=unsupported
	    # It fails to find uninstalled libraries when the uninstalled
	    # path is not listed in the libpath.  Setting hardcode_minus_L
	    # to unsupported forces relinking
	    hardcode_minus_L_CXX=yes
	    hardcode_libdir_flag_spec_CXX='-L$libdir'
	    hardcode_libdir_separator_CXX=
	  fi
          esac
          shared_flag='-shared'
	  if test "$aix_use_runtimelinking" = yes; then
	    shared_flag="$shared_flag "'${wl}-G'
	  fi
        else
          # not using gcc
          if test "$host_cpu" = ia64; then
	  # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
	  # chokes on -Wl,-G. The following line is correct:
	  shared_flag='-G'
          else
	    if test "$aix_use_runtimelinking" = yes; then
	      shared_flag='${wl}-G'
	    else
	      shared_flag='${wl}-bM:SRE'
	    fi
          fi
        fi

        export_dynamic_flag_spec_CXX='${wl}-bexpall'
        # It seems that -bexpall does not export symbols beginning with
        # underscore (_), so it is better to generate a list of symbols to
	# export.
        always_export_symbols_CXX=yes
        if test "$aix_use_runtimelinking" = yes; then
          # Warning - without using the other runtime loading flags (-brtl),
          # -berok will link without error, but may produce a broken library.
          allow_undefined_flag_CXX='-berok'
          # Determine the default libpath from the value encoded in an empty
          # executable.
          cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_cxx_try_link "$LINENO"; then :

lt_aix_libpath_sed='
    /Import File Strings/,/^$/ {
	/^0/ {
	    s/^0  *\(.*\)$/\1/
	    p
	}
    }'
aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
# Check for a 64-bit object if we didn't find anything.
if test -z "$aix_libpath"; then
  aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
fi
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi

          hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"

          archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
        else
          if test "$host_cpu" = ia64; then
	    hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib'
	    allow_undefined_flag_CXX="-z nodefs"
	    archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
          else
	    # Determine the default libpath from the value encoded in an
	    # empty executable.
	    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_cxx_try_link "$LINENO"; then :

lt_aix_libpath_sed='
    /Import File Strings/,/^$/ {
	/^0/ {
	    s/^0  *\(.*\)$/\1/
	    p
	}
    }'
aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
# Check for a 64-bit object if we didn't find anything.
if test -z "$aix_libpath"; then
  aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
fi
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi

	    hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
	    # Warning - without using the other run time loading flags,
	    # -berok will link without error, but may produce a broken library.
	    no_undefined_flag_CXX=' ${wl}-bernotok'
	    allow_undefined_flag_CXX=' ${wl}-berok'
	    # Exported symbols can be pulled into shared objects from archives
	    whole_archive_flag_spec_CXX='$convenience'
	    archive_cmds_need_lc_CXX=yes
	    # This is similar to how AIX traditionally builds its shared
	    # libraries.
	    archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
          fi
        fi
        ;;

      beos*)
	if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
	  allow_undefined_flag_CXX=unsupported
	  # Joseph Beckenbach  says some releases of gcc
	  # support --undefined.  This deserves some investigation.  FIXME
	  archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
	else
	  ld_shlibs_CXX=no
	fi
	;;

      chorus*)
        case $cc_basename in
          *)
	  # FIXME: insert proper C++ library support
	  ld_shlibs_CXX=no
	  ;;
        esac
        ;;

      cygwin* | mingw* | pw32* | cegcc*)
        # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless,
        # as there is no search path for DLLs.
        hardcode_libdir_flag_spec_CXX='-L$libdir'
        allow_undefined_flag_CXX=unsupported
        always_export_symbols_CXX=no
        enable_shared_with_static_runtimes_CXX=yes

        if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
          archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
          # If the export-symbols file already is a .def file (1st line
          # is EXPORTS), use it as is; otherwise, prepend...
          archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
	    cp $export_symbols $output_objdir/$soname.def;
          else
	    echo EXPORTS > $output_objdir/$soname.def;
	    cat $export_symbols >> $output_objdir/$soname.def;
          fi~
          $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
        else
          ld_shlibs_CXX=no
        fi
        ;;
      darwin* | rhapsody*)


  archive_cmds_need_lc_CXX=no
  hardcode_direct_CXX=no
  hardcode_automatic_CXX=yes
  hardcode_shlibpath_var_CXX=unsupported
  whole_archive_flag_spec_CXX=''
  link_all_deplibs_CXX=yes
  allow_undefined_flag_CXX="$_lt_dar_allow_undefined"
  case $cc_basename in
     ifort*) _lt_dar_can_shared=yes ;;
     *) _lt_dar_can_shared=$GCC ;;
  esac
  if test "$_lt_dar_can_shared" = "yes"; then
    output_verbose_link_cmd=echo
    archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
    module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
    archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
    module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
       if test "$lt_cv_apple_cc_single_mod" != "yes"; then
      archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
      archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
    fi

  else
  ld_shlibs_CXX=no
  fi

	;;

      dgux*)
        case $cc_basename in
          ec++*)
	    # FIXME: insert proper C++ library support
	    ld_shlibs_CXX=no
	    ;;
          ghcx*)
	    # Green Hills C++ Compiler
	    # FIXME: insert proper C++ library support
	    ld_shlibs_CXX=no
	    ;;
          *)
	    # FIXME: insert proper C++ library support
	    ld_shlibs_CXX=no
	    ;;
        esac
        ;;

      freebsd[12]*)
        # C++ shared libraries reported to be fairly broken before
	# switch to ELF
        ld_shlibs_CXX=no
        ;;

      freebsd-elf*)
        archive_cmds_need_lc_CXX=no
        ;;

      freebsd* | dragonfly*)
        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
        # conventions
        ld_shlibs_CXX=yes
        ;;

      gnu*)
        ;;

      hpux9*)
        hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
        hardcode_libdir_separator_CXX=:
        export_dynamic_flag_spec_CXX='${wl}-E'
        hardcode_direct_CXX=yes
        hardcode_minus_L_CXX=yes # Not in the search PATH,
				             # but as the default
				             # location of the library.

        case $cc_basename in
          CC*)
            # FIXME: insert proper C++ library support
            ld_shlibs_CXX=no
            ;;
          aCC*)
            archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
            # Commands to make compiler produce verbose output that lists
            # what "hidden" libraries, object files and flags are used when
            # linking a shared library.
            #
            # There doesn't appear to be a way to prevent this compiler from
            # explicitly linking system object files so we need to strip them
            # from the output so that they don't get included in the library
            # dependencies.
            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
            ;;
          *)
            if test "$GXX" = yes; then
              archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
            else
              # FIXME: insert proper C++ library support
              ld_shlibs_CXX=no
            fi
            ;;
        esac
        ;;

      hpux10*|hpux11*)
        if test $with_gnu_ld = no; then
	  hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
	  hardcode_libdir_separator_CXX=:

          case $host_cpu in
            hppa*64*|ia64*)
              ;;
            *)
	      export_dynamic_flag_spec_CXX='${wl}-E'
              ;;
          esac
        fi
        case $host_cpu in
          hppa*64*|ia64*)
            hardcode_direct_CXX=no
            hardcode_shlibpath_var_CXX=no
            ;;
          *)
            hardcode_direct_CXX=yes
            hardcode_direct_absolute_CXX=yes
            hardcode_minus_L_CXX=yes # Not in the search PATH,
					         # but as the default
					         # location of the library.
            ;;
        esac

        case $cc_basename in
          CC*)
	    # FIXME: insert proper C++ library support
	    ld_shlibs_CXX=no
	    ;;
          aCC*)
	    case $host_cpu in
	      hppa*64*)
	        archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
	        ;;
	      ia64*)
	        archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
	        ;;
	      *)
	        archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
	        ;;
	    esac
	    # Commands to make compiler produce verbose output that lists
	    # what "hidden" libraries, object files and flags are used when
	    # linking a shared library.
	    #
	    # There doesn't appear to be a way to prevent this compiler from
	    # explicitly linking system object files so we need to strip them
	    # from the output so that they don't get included in the library
	    # dependencies.
	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
	    ;;
          *)
	    if test "$GXX" = yes; then
	      if test $with_gnu_ld = no; then
	        case $host_cpu in
	          hppa*64*)
	            archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
	            ;;
	          ia64*)
	            archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
	            ;;
	          *)
	            archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
	            ;;
	        esac
	      fi
	    else
	      # FIXME: insert proper C++ library support
	      ld_shlibs_CXX=no
	    fi
	    ;;
        esac
        ;;

      interix[3-9]*)
	hardcode_direct_CXX=no
	hardcode_shlibpath_var_CXX=no
	hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
	export_dynamic_flag_spec_CXX='${wl}-E'
	# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
	# Instead, shared libraries are loaded at an image base (0x10000000 by
	# default) and relocated if they conflict, which is a slow very memory
	# consuming and fragmenting process.  To avoid this, we pick a random,
	# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
	# time.  Moving up from 0x10000000 also allows more sbrk(2) space.
	archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
	archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
	;;
      irix5* | irix6*)
        case $cc_basename in
          CC*)
	    # SGI C++
	    archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'

	    # Archives containing C++ object files must be created using
	    # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
	    # necessary to make sure instantiated templates are included
	    # in the archive.
	    old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs'
	    ;;
          *)
	    if test "$GXX" = yes; then
	      if test "$with_gnu_ld" = no; then
	        archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
	      else
	        archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib'
	      fi
	    fi
	    link_all_deplibs_CXX=yes
	    ;;
        esac
        hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
        hardcode_libdir_separator_CXX=:
        inherit_rpath_CXX=yes
        ;;

      linux* | k*bsd*-gnu | kopensolaris*-gnu)
        case $cc_basename in
          KCC*)
	    # Kuck and Associates, Inc. (KAI) C++ Compiler

	    # KCC will only create a shared library if the output file
	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
	    # to its proper name (with version) after linking.
	    archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
	    archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
	    # Commands to make compiler produce verbose output that lists
	    # what "hidden" libraries, object files and flags are used when
	    # linking a shared library.
	    #
	    # There doesn't appear to be a way to prevent this compiler from
	    # explicitly linking system object files so we need to strip them
	    # from the output so that they don't get included in the library
	    # dependencies.
	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'

	    hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
	    export_dynamic_flag_spec_CXX='${wl}--export-dynamic'

	    # Archives containing C++ object files must be created using
	    # "CC -Bstatic", where "CC" is the KAI C++ compiler.
	    old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs'
	    ;;
	  icpc* | ecpc* )
	    # Intel C++
	    with_gnu_ld=yes
	    # version 8.0 and above of icpc choke on multiply defined symbols
	    # if we add $predep_objects and $postdep_objects, however 7.1 and
	    # earlier do not add the objects themselves.
	    case `$CC -V 2>&1` in
	      *"Version 7."*)
	        archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
		archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
		;;
	      *)  # Version 8.0 or newer
	        tmp_idyn=
	        case $host_cpu in
		  ia64*) tmp_idyn=' -i_dynamic';;
		esac
	        archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
		archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
		;;
	    esac
	    archive_cmds_need_lc_CXX=no
	    hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
	    export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
	    whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
	    ;;
          pgCC* | pgcpp*)
            # Portland Group C++ compiler
	    case `$CC -V` in
	    *pgCC\ [1-5]* | *pgcpp\ [1-5]*)
	      prelink_cmds_CXX='tpldir=Template.dir~
		rm -rf $tpldir~
		$CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
		compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
	      old_archive_cmds_CXX='tpldir=Template.dir~
		rm -rf $tpldir~
		$CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
		$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
		$RANLIB $oldlib'
	      archive_cmds_CXX='tpldir=Template.dir~
		rm -rf $tpldir~
		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
	      archive_expsym_cmds_CXX='tpldir=Template.dir~
		rm -rf $tpldir~
		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
	      ;;
	    *) # Version 6 will use weak symbols
	      archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
	      archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
	      ;;
	    esac

	    hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir'
	    export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
	    whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
            ;;
	  cxx*)
	    # Compaq C++
	    archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
	    archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'

	    runpath_var=LD_RUN_PATH
	    hardcode_libdir_flag_spec_CXX='-rpath $libdir'
	    hardcode_libdir_separator_CXX=:

	    # Commands to make compiler produce verbose output that lists
	    # what "hidden" libraries, object files and flags are used when
	    # linking a shared library.
	    #
	    # There doesn't appear to be a way to prevent this compiler from
	    # explicitly linking system object files so we need to strip them
	    # from the output so that they don't get included in the library
	    # dependencies.
	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
	    ;;
	  xl*)
	    # IBM XL 8.0 on PPC, with GNU ld
	    hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
	    export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
	    archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
	    if test "x$supports_anon_versioning" = xyes; then
	      archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~
		cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
		echo "local: *; };" >> $output_objdir/$libname.ver~
		$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
	    fi
	    ;;
	  *)
	    case `$CC -V 2>&1 | sed 5q` in
	    *Sun\ C*)
	      # Sun C++ 5.9
	      no_undefined_flag_CXX=' -zdefs'
	      archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
	      archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
	      hardcode_libdir_flag_spec_CXX='-R$libdir'
	      whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
	      compiler_needs_object_CXX=yes

	      # Not sure whether something based on
	      # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
	      # would be better.
	      output_verbose_link_cmd='echo'

	      # Archives containing C++ object files must be created using
	      # "CC -xar", where "CC" is the Sun C++ compiler.  This is
	      # necessary to make sure instantiated templates are included
	      # in the archive.
	      old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
	      ;;
	    esac
	    ;;
	esac
	;;

      lynxos*)
        # FIXME: insert proper C++ library support
	ld_shlibs_CXX=no
	;;

      m88k*)
        # FIXME: insert proper C++ library support
        ld_shlibs_CXX=no
	;;

      mvs*)
        case $cc_basename in
          cxx*)
	    # FIXME: insert proper C++ library support
	    ld_shlibs_CXX=no
	    ;;
	  *)
	    # FIXME: insert proper C++ library support
	    ld_shlibs_CXX=no
	    ;;
	esac
	;;

      netbsd*)
        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
	  archive_cmds_CXX='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
	  wlarc=
	  hardcode_libdir_flag_spec_CXX='-R$libdir'
	  hardcode_direct_CXX=yes
	  hardcode_shlibpath_var_CXX=no
	fi
	# Workaround some broken pre-1.5 toolchains
	output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
	;;

      *nto* | *qnx*)
        ld_shlibs_CXX=yes
	;;

      openbsd2*)
        # C++ shared libraries are fairly broken
	ld_shlibs_CXX=no
	;;

      openbsd*)
	if test -f /usr/libexec/ld.so; then
	  hardcode_direct_CXX=yes
	  hardcode_shlibpath_var_CXX=no
	  hardcode_direct_absolute_CXX=yes
	  archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
	  hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
	    archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
	    export_dynamic_flag_spec_CXX='${wl}-E'
	    whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
	  fi
	  output_verbose_link_cmd=echo
	else
	  ld_shlibs_CXX=no
	fi
	;;

      osf3* | osf4* | osf5*)
        case $cc_basename in
          KCC*)
	    # Kuck and Associates, Inc. (KAI) C++ Compiler

	    # KCC will only create a shared library if the output file
	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
	    # to its proper name (with version) after linking.
	    archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'

	    hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
	    hardcode_libdir_separator_CXX=:

	    # Archives containing C++ object files must be created using
	    # the KAI C++ compiler.
	    case $host in
	      osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;;
	      *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;;
	    esac
	    ;;
          RCC*)
	    # Rational C++ 2.4.1
	    # FIXME: insert proper C++ library support
	    ld_shlibs_CXX=no
	    ;;
          cxx*)
	    case $host in
	      osf3*)
	        allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
	        archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
	        hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
		;;
	      *)
	        allow_undefined_flag_CXX=' -expect_unresolved \*'
	        archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
	        archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
	          echo "-hidden">> $lib.exp~
	          $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp  `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~
	          $RM $lib.exp'
	        hardcode_libdir_flag_spec_CXX='-rpath $libdir'
		;;
	    esac

	    hardcode_libdir_separator_CXX=:

	    # Commands to make compiler produce verbose output that lists
	    # what "hidden" libraries, object files and flags are used when
	    # linking a shared library.
	    #
	    # There doesn't appear to be a way to prevent this compiler from
	    # explicitly linking system object files so we need to strip them
	    # from the output so that they don't get included in the library
	    # dependencies.
	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
	    ;;
	  *)
	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
	      allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
	      case $host in
	        osf3*)
	          archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
		  ;;
	        *)
	          archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
		  ;;
	      esac

	      hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
	      hardcode_libdir_separator_CXX=:

	      # Commands to make compiler produce verbose output that lists
	      # what "hidden" libraries, object files and flags are used when
	      # linking a shared library.
	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'

	    else
	      # FIXME: insert proper C++ library support
	      ld_shlibs_CXX=no
	    fi
	    ;;
        esac
        ;;

      psos*)
        # FIXME: insert proper C++ library support
        ld_shlibs_CXX=no
        ;;

      sunos4*)
        case $cc_basename in
          CC*)
	    # Sun C++ 4.x
	    # FIXME: insert proper C++ library support
	    ld_shlibs_CXX=no
	    ;;
          lcc*)
	    # Lucid
	    # FIXME: insert proper C++ library support
	    ld_shlibs_CXX=no
	    ;;
          *)
	    # FIXME: insert proper C++ library support
	    ld_shlibs_CXX=no
	    ;;
        esac
        ;;

      solaris*)
        case $cc_basename in
          CC*)
	    # Sun C++ 4.2, 5.x and Centerline C++
            archive_cmds_need_lc_CXX=yes
	    no_undefined_flag_CXX=' -zdefs'
	    archive_cmds_CXX='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
	    archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
	      $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'

	    hardcode_libdir_flag_spec_CXX='-R$libdir'
	    hardcode_shlibpath_var_CXX=no
	    case $host_os in
	      solaris2.[0-5] | solaris2.[0-5].*) ;;
	      *)
		# The compiler driver will combine and reorder linker options,
		# but understands `-z linker_flag'.
	        # Supported since Solaris 2.6 (maybe 2.5.1?)
		whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract'
	        ;;
	    esac
	    link_all_deplibs_CXX=yes

	    output_verbose_link_cmd='echo'

	    # Archives containing C++ object files must be created using
	    # "CC -xar", where "CC" is the Sun C++ compiler.  This is
	    # necessary to make sure instantiated templates are included
	    # in the archive.
	    old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
	    ;;
          gcx*)
	    # Green Hills C++ Compiler
	    archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'

	    # The C++ compiler must be used to create the archive.
	    old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
	    ;;
          *)
	    # GNU C++ compiler with Solaris linker
	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
	      no_undefined_flag_CXX=' ${wl}-z ${wl}defs'
	      if $CC --version | $GREP -v '^2\.7' > /dev/null; then
	        archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
	        archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
		  $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'

	        # Commands to make compiler produce verbose output that lists
	        # what "hidden" libraries, object files and flags are used when
	        # linking a shared library.
	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
	      else
	        # g++ 2.7 appears to require `-G' NOT `-shared' on this
	        # platform.
	        archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
	        archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
		  $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'

	        # Commands to make compiler produce verbose output that lists
	        # what "hidden" libraries, object files and flags are used when
	        # linking a shared library.
	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
	      fi

	      hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir'
	      case $host_os in
		solaris2.[0-5] | solaris2.[0-5].*) ;;
		*)
		  whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
		  ;;
	      esac
	    fi
	    ;;
        esac
        ;;

    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
      no_undefined_flag_CXX='${wl}-z,text'
      archive_cmds_need_lc_CXX=no
      hardcode_shlibpath_var_CXX=no
      runpath_var='LD_RUN_PATH'

      case $cc_basename in
        CC*)
	  archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
	  archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
	  ;;
	*)
	  archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
	  archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
	  ;;
      esac
      ;;

      sysv5* | sco3.2v5* | sco5v6*)
	# Note: We can NOT use -z defs as we might desire, because we do not
	# link with -lc, and that would cause any symbols used from libc to
	# always be unresolved, which means just about no library would
	# ever link correctly.  If we're not using GNU ld we use -z text
	# though, which does catch some bad symbols but isn't as heavy-handed
	# as -z defs.
	no_undefined_flag_CXX='${wl}-z,text'
	allow_undefined_flag_CXX='${wl}-z,nodefs'
	archive_cmds_need_lc_CXX=no
	hardcode_shlibpath_var_CXX=no
	hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir'
	hardcode_libdir_separator_CXX=':'
	link_all_deplibs_CXX=yes
	export_dynamic_flag_spec_CXX='${wl}-Bexport'
	runpath_var='LD_RUN_PATH'

	case $cc_basename in
          CC*)
	    archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
	    archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
	    ;;
	  *)
	    archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
	    archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
	    ;;
	esac
      ;;

      tandem*)
        case $cc_basename in
          NCC*)
	    # NonStop-UX NCC 3.20
	    # FIXME: insert proper C++ library support
	    ld_shlibs_CXX=no
	    ;;
          *)
	    # FIXME: insert proper C++ library support
	    ld_shlibs_CXX=no
	    ;;
        esac
        ;;

      vxworks*)
        # FIXME: insert proper C++ library support
        ld_shlibs_CXX=no
        ;;

      *)
        # FIXME: insert proper C++ library support
        ld_shlibs_CXX=no
        ;;
    esac

    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
$as_echo "$ld_shlibs_CXX" >&6; }
    test "$ld_shlibs_CXX" = no && can_build_shared=no

    GCC_CXX="$GXX"
    LD_CXX="$LD"

    ## CAVEAT EMPTOR:
    ## There is no encapsulation within the following macros, do not change
    ## the running order or otherwise move them around unless you know exactly
    ## what you are doing...
    # Dependencies to place before and after the object being linked:
predep_objects_CXX=
postdep_objects_CXX=
predeps_CXX=
postdeps_CXX=
compiler_lib_search_path_CXX=

cat > conftest.$ac_ext <<_LT_EOF
class Foo
{
public:
  Foo (void) { a = 0; }
private:
  int a;
};
_LT_EOF

if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
  (eval $ac_compile) 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; then
  # Parse the compiler output and extract the necessary
  # objects, libraries and library flags.

  # Sentinel used to keep track of whether or not we are before
  # the conftest object file.
  pre_test_object_deps_done=no

  for p in `eval "$output_verbose_link_cmd"`; do
    case $p in

    -L* | -R* | -l*)
       # Some compilers place space between "-{L,R}" and the path.
       # Remove the space.
       if test $p = "-L" ||
          test $p = "-R"; then
	 prev=$p
	 continue
       else
	 prev=
       fi

       if test "$pre_test_object_deps_done" = no; then
	 case $p in
	 -L* | -R*)
	   # Internal compiler library paths should come after those
	   # provided the user.  The postdeps already come after the
	   # user supplied libs so there is no need to process them.
	   if test -z "$compiler_lib_search_path_CXX"; then
	     compiler_lib_search_path_CXX="${prev}${p}"
	   else
	     compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}"
	   fi
	   ;;
	 # The "-l" case would never come before the object being
	 # linked, so don't bother handling this case.
	 esac
       else
	 if test -z "$postdeps_CXX"; then
	   postdeps_CXX="${prev}${p}"
	 else
	   postdeps_CXX="${postdeps_CXX} ${prev}${p}"
	 fi
       fi
       ;;

    *.$objext)
       # This assumes that the test object file only shows up
       # once in the compiler output.
       if test "$p" = "conftest.$objext"; then
	 pre_test_object_deps_done=yes
	 continue
       fi

       if test "$pre_test_object_deps_done" = no; then
	 if test -z "$predep_objects_CXX"; then
	   predep_objects_CXX="$p"
	 else
	   predep_objects_CXX="$predep_objects_CXX $p"
	 fi
       else
	 if test -z "$postdep_objects_CXX"; then
	   postdep_objects_CXX="$p"
	 else
	   postdep_objects_CXX="$postdep_objects_CXX $p"
	 fi
       fi
       ;;

    *) ;; # Ignore the rest.

    esac
  done

  # Clean up.
  rm -f a.out a.exe
else
  echo "libtool.m4: error: problem compiling CXX test program"
fi

$RM -f confest.$objext

# PORTME: override above test on systems where it is broken
case $host_os in
interix[3-9]*)
  # Interix 3.5 installs completely hosed .la files for C++, so rather than
  # hack all around it, let's just trust "g++" to DTRT.
  predep_objects_CXX=
  postdep_objects_CXX=
  postdeps_CXX=
  ;;

linux*)
  case `$CC -V 2>&1 | sed 5q` in
  *Sun\ C*)
    # Sun C++ 5.9

    # The more standards-conforming stlport4 library is
    # incompatible with the Cstd library. Avoid specifying
    # it if it's in CXXFLAGS. Ignore libCrun as
    # -library=stlport4 depends on it.
    case " $CXX $CXXFLAGS " in
    *" -library=stlport4 "*)
      solaris_use_stlport4=yes
      ;;
    esac

    if test "$solaris_use_stlport4" != yes; then
      postdeps_CXX='-library=Cstd -library=Crun'
    fi
    ;;
  esac
  ;;

solaris*)
  case $cc_basename in
  CC*)
    # The more standards-conforming stlport4 library is
    # incompatible with the Cstd library. Avoid specifying
    # it if it's in CXXFLAGS. Ignore libCrun as
    # -library=stlport4 depends on it.
    case " $CXX $CXXFLAGS " in
    *" -library=stlport4 "*)
      solaris_use_stlport4=yes
      ;;
    esac

    # Adding this requires a known-good setup of shared libraries for
    # Sun compiler versions before 5.6, else PIC objects from an old
    # archive will be linked into the output, leading to subtle bugs.
    if test "$solaris_use_stlport4" != yes; then
      postdeps_CXX='-library=Cstd -library=Crun'
    fi
    ;;
  esac
  ;;
esac


case " $postdeps_CXX " in
*" -lc "*) archive_cmds_need_lc_CXX=no ;;
esac
 compiler_lib_search_dirs_CXX=
if test -n "${compiler_lib_search_path_CXX}"; then
 compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
fi































    lt_prog_compiler_wl_CXX=
lt_prog_compiler_pic_CXX=
lt_prog_compiler_static_CXX=

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
$as_echo_n "checking for $compiler option to produce PIC... " >&6; }

  # C++ specific cases for pic, static, wl, etc.
  if test "$GXX" = yes; then
    lt_prog_compiler_wl_CXX='-Wl,'
    lt_prog_compiler_static_CXX='-static'

    case $host_os in
    aix*)
      # All AIX code is PIC.
      if test "$host_cpu" = ia64; then
	# AIX 5 now supports IA64 processor
	lt_prog_compiler_static_CXX='-Bstatic'
      fi
      ;;

    amigaos*)
      case $host_cpu in
      powerpc)
            # see comment about AmigaOS4 .so support
            lt_prog_compiler_pic_CXX='-fPIC'
        ;;
      m68k)
            # FIXME: we need at least 68020 code to build shared libraries, but
            # adding the `-m68020' flag to GCC prevents building anything better,
            # like `-m68040'.
            lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4'
        ;;
      esac
      ;;

    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
      # PIC is the default for these OSes.
      ;;
    mingw* | cygwin* | os2* | pw32* | cegcc*)
      # This hack is so that the source file can tell whether it is being
      # built for inclusion in a dll (and should export symbols for example).
      # Although the cygwin gcc ignores -fPIC, still need this for old-style
      # (--disable-auto-import) libraries
      lt_prog_compiler_pic_CXX='-DDLL_EXPORT'
      ;;
    darwin* | rhapsody*)
      # PIC is the default on this platform
      # Common symbols not allowed in MH_DYLIB files
      lt_prog_compiler_pic_CXX='-fno-common'
      ;;
    *djgpp*)
      # DJGPP does not support shared libraries at all
      lt_prog_compiler_pic_CXX=
      ;;
    interix[3-9]*)
      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
      # Instead, we relocate shared libraries at runtime.
      ;;
    sysv4*MP*)
      if test -d /usr/nec; then
	lt_prog_compiler_pic_CXX=-Kconform_pic
      fi
      ;;
    hpux*)
      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
      # sets the default TLS model and affects inlining.
      case $host_cpu in
      hppa*64*)
	;;
      *)
	lt_prog_compiler_pic_CXX='-fPIC'
	;;
      esac
      ;;
    *qnx* | *nto*)
      # QNX uses GNU C++, but need to define -shared option too, otherwise
      # it will coredump.
      lt_prog_compiler_pic_CXX='-fPIC -shared'
      ;;
    *)
      lt_prog_compiler_pic_CXX='-fPIC'
      ;;
    esac
  else
    case $host_os in
      aix[4-9]*)
	# All AIX code is PIC.
	if test "$host_cpu" = ia64; then
	  # AIX 5 now supports IA64 processor
	  lt_prog_compiler_static_CXX='-Bstatic'
	else
	  lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp'
	fi
	;;
      chorus*)
	case $cc_basename in
	cxch68*)
	  # Green Hills C++ Compiler
	  # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
	  ;;
	esac
	;;
      dgux*)
	case $cc_basename in
	  ec++*)
	    lt_prog_compiler_pic_CXX='-KPIC'
	    ;;
	  ghcx*)
	    # Green Hills C++ Compiler
	    lt_prog_compiler_pic_CXX='-pic'
	    ;;
	  *)
	    ;;
	esac
	;;
      freebsd* | dragonfly*)
	# FreeBSD uses GNU C++
	;;
      hpux9* | hpux10* | hpux11*)
	case $cc_basename in
	  CC*)
	    lt_prog_compiler_wl_CXX='-Wl,'
	    lt_prog_compiler_static_CXX='${wl}-a ${wl}archive'
	    if test "$host_cpu" != ia64; then
	      lt_prog_compiler_pic_CXX='+Z'
	    fi
	    ;;
	  aCC*)
	    lt_prog_compiler_wl_CXX='-Wl,'
	    lt_prog_compiler_static_CXX='${wl}-a ${wl}archive'
	    case $host_cpu in
	    hppa*64*|ia64*)
	      # +Z the default
	      ;;
	    *)
	      lt_prog_compiler_pic_CXX='+Z'
	      ;;
	    esac
	    ;;
	  *)
	    ;;
	esac
	;;
      interix*)
	# This is c89, which is MS Visual C++ (no shared libs)
	# Anyone wants to do a port?
	;;
      irix5* | irix6* | nonstopux*)
	case $cc_basename in
	  CC*)
	    lt_prog_compiler_wl_CXX='-Wl,'
	    lt_prog_compiler_static_CXX='-non_shared'
	    # CC pic flag -KPIC is the default.
	    ;;
	  *)
	    ;;
	esac
	;;
      linux* | k*bsd*-gnu | kopensolaris*-gnu)
	case $cc_basename in
	  KCC*)
	    # KAI C++ Compiler
	    lt_prog_compiler_wl_CXX='--backend -Wl,'
	    lt_prog_compiler_pic_CXX='-fPIC'
	    ;;
	  ecpc* )
	    # old Intel C++ for x86_64 which still supported -KPIC.
	    lt_prog_compiler_wl_CXX='-Wl,'
	    lt_prog_compiler_pic_CXX='-KPIC'
	    lt_prog_compiler_static_CXX='-static'
	    ;;
	  icpc* )
	    # Intel C++, used to be incompatible with GCC.
	    # ICC 10 doesn't accept -KPIC any more.
	    lt_prog_compiler_wl_CXX='-Wl,'
	    lt_prog_compiler_pic_CXX='-fPIC'
	    lt_prog_compiler_static_CXX='-static'
	    ;;
	  pgCC* | pgcpp*)
	    # Portland Group C++ compiler
	    lt_prog_compiler_wl_CXX='-Wl,'
	    lt_prog_compiler_pic_CXX='-fpic'
	    lt_prog_compiler_static_CXX='-Bstatic'
	    ;;
	  cxx*)
	    # Compaq C++
	    # Make sure the PIC flag is empty.  It appears that all Alpha
	    # Linux and Compaq Tru64 Unix objects are PIC.
	    lt_prog_compiler_pic_CXX=
	    lt_prog_compiler_static_CXX='-non_shared'
	    ;;
	  xlc* | xlC*)
	    # IBM XL 8.0 on PPC
	    lt_prog_compiler_wl_CXX='-Wl,'
	    lt_prog_compiler_pic_CXX='-qpic'
	    lt_prog_compiler_static_CXX='-qstaticlink'
	    ;;
	  *)
	    case `$CC -V 2>&1 | sed 5q` in
	    *Sun\ C*)
	      # Sun C++ 5.9
	      lt_prog_compiler_pic_CXX='-KPIC'
	      lt_prog_compiler_static_CXX='-Bstatic'
	      lt_prog_compiler_wl_CXX='-Qoption ld '
	      ;;
	    esac
	    ;;
	esac
	;;
      lynxos*)
	;;
      m88k*)
	;;
      mvs*)
	case $cc_basename in
	  cxx*)
	    lt_prog_compiler_pic_CXX='-W c,exportall'
	    ;;
	  *)
	    ;;
	esac
	;;
      netbsd* | netbsdelf*-gnu)
	;;
      *qnx* | *nto*)
        # QNX uses GNU C++, but need to define -shared option too, otherwise
        # it will coredump.
        lt_prog_compiler_pic_CXX='-fPIC -shared'
        ;;
      osf3* | osf4* | osf5*)
	case $cc_basename in
	  KCC*)
	    lt_prog_compiler_wl_CXX='--backend -Wl,'
	    ;;
	  RCC*)
	    # Rational C++ 2.4.1
	    lt_prog_compiler_pic_CXX='-pic'
	    ;;
	  cxx*)
	    # Digital/Compaq C++
	    lt_prog_compiler_wl_CXX='-Wl,'
	    # Make sure the PIC flag is empty.  It appears that all Alpha
	    # Linux and Compaq Tru64 Unix objects are PIC.
	    lt_prog_compiler_pic_CXX=
	    lt_prog_compiler_static_CXX='-non_shared'
	    ;;
	  *)
	    ;;
	esac
	;;
      psos*)
	;;
      solaris*)
	case $cc_basename in
	  CC*)
	    # Sun C++ 4.2, 5.x and Centerline C++
	    lt_prog_compiler_pic_CXX='-KPIC'
	    lt_prog_compiler_static_CXX='-Bstatic'
	    lt_prog_compiler_wl_CXX='-Qoption ld '
	    ;;
	  gcx*)
	    # Green Hills C++ Compiler
	    lt_prog_compiler_pic_CXX='-PIC'
	    ;;
	  *)
	    ;;
	esac
	;;
      sunos4*)
	case $cc_basename in
	  CC*)
	    # Sun C++ 4.x
	    lt_prog_compiler_pic_CXX='-pic'
	    lt_prog_compiler_static_CXX='-Bstatic'
	    ;;
	  lcc*)
	    # Lucid
	    lt_prog_compiler_pic_CXX='-pic'
	    ;;
	  *)
	    ;;
	esac
	;;
      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
	case $cc_basename in
	  CC*)
	    lt_prog_compiler_wl_CXX='-Wl,'
	    lt_prog_compiler_pic_CXX='-KPIC'
	    lt_prog_compiler_static_CXX='-Bstatic'
	    ;;
	esac
	;;
      tandem*)
	case $cc_basename in
	  NCC*)
	    # NonStop-UX NCC 3.20
	    lt_prog_compiler_pic_CXX='-KPIC'
	    ;;
	  *)
	    ;;
	esac
	;;
      vxworks*)
	;;
      *)
	lt_prog_compiler_can_build_shared_CXX=no
	;;
    esac
  fi

case $host_os in
  # For platforms which do not support PIC, -DPIC is meaningless:
  *djgpp*)
    lt_prog_compiler_pic_CXX=
    ;;
  *)
    lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC"
    ;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_CXX" >&5
$as_echo "$lt_prog_compiler_pic_CXX" >&6; }



#
# Check to make sure the PIC flag actually works.
#
if test -n "$lt_prog_compiler_pic_CXX"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5
$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; }
if test "${lt_cv_prog_compiler_pic_works_CXX+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  lt_cv_prog_compiler_pic_works_CXX=no
   ac_outfile=conftest.$ac_objext
   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
   lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC"
   # Insert the option either (1) after the last *FLAGS variable, or
   # (2) before a word containing "conftest.", or (3) at the end.
   # Note that $ac_compile itself does not contain backslashes and begins
   # with a dollar sign (not a hyphen), so the echo should work correctly.
   # The option is referenced via a variable to avoid confusing sed.
   lt_compile=`echo "$ac_compile" | $SED \
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
   -e 's:$: $lt_compiler_flag:'`
   (eval echo "\"\$as_me:13604: $lt_compile\"" >&5)
   (eval "$lt_compile" 2>conftest.err)
   ac_status=$?
   cat conftest.err >&5
   echo "$as_me:13608: \$? = $ac_status" >&5
   if (exit $ac_status) && test -s "$ac_outfile"; then
     # The compiler can only warn and ignore the option if not recognized
     # So say no if there are warnings other than the usual output.
     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
       lt_cv_prog_compiler_pic_works_CXX=yes
     fi
   fi
   $RM conftest*

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5
$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; }

if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then
    case $lt_prog_compiler_pic_CXX in
     "" | " "*) ;;
     *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;;
     esac
else
    lt_prog_compiler_pic_CXX=
     lt_prog_compiler_can_build_shared_CXX=no
fi

fi



#
# Check to make sure the static flag actually works.
#
wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
if test "${lt_cv_prog_compiler_static_works_CXX+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  lt_cv_prog_compiler_static_works_CXX=no
   save_LDFLAGS="$LDFLAGS"
   LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
   echo "$lt_simple_link_test_code" > conftest.$ac_ext
   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
     # The linker can only warn and ignore the option if not recognized
     # So say no if there are warnings
     if test -s conftest.err; then
       # Append any errors to the config.log.
       cat conftest.err 1>&5
       $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
       if diff conftest.exp conftest.er2 >/dev/null; then
         lt_cv_prog_compiler_static_works_CXX=yes
       fi
     else
       lt_cv_prog_compiler_static_works_CXX=yes
     fi
   fi
   $RM -r conftest*
   LDFLAGS="$save_LDFLAGS"

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5
$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; }

if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then
    :
else
    lt_prog_compiler_static_CXX=
fi




    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  lt_cv_prog_compiler_c_o_CXX=no
   $RM -r conftest 2>/dev/null
   mkdir conftest
   cd conftest
   mkdir out
   echo "$lt_simple_compile_test_code" > conftest.$ac_ext

   lt_compiler_flag="-o out/conftest2.$ac_objext"
   # Insert the option either (1) after the last *FLAGS variable, or
   # (2) before a word containing "conftest.", or (3) at the end.
   # Note that $ac_compile itself does not contain backslashes and begins
   # with a dollar sign (not a hyphen), so the echo should work correctly.
   lt_compile=`echo "$ac_compile" | $SED \
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
   -e 's:$: $lt_compiler_flag:'`
   (eval echo "\"\$as_me:13703: $lt_compile\"" >&5)
   (eval "$lt_compile" 2>out/conftest.err)
   ac_status=$?
   cat out/conftest.err >&5
   echo "$as_me:13707: \$? = $ac_status" >&5
   if (exit $ac_status) && test -s out/conftest2.$ac_objext
   then
     # The compiler can only warn and ignore the option if not recognized
     # So say no if there are warnings
     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
       lt_cv_prog_compiler_c_o_CXX=yes
     fi
   fi
   chmod u+w . 2>&5
   $RM conftest*
   # SGI C++ compiler will create directory out/ii_files/ for
   # template instantiation
   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
   $RM out/* && rmdir out
   cd ..
   $RM -r conftest
   $RM conftest*

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5
$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }



    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  lt_cv_prog_compiler_c_o_CXX=no
   $RM -r conftest 2>/dev/null
   mkdir conftest
   cd conftest
   mkdir out
   echo "$lt_simple_compile_test_code" > conftest.$ac_ext

   lt_compiler_flag="-o out/conftest2.$ac_objext"
   # Insert the option either (1) after the last *FLAGS variable, or
   # (2) before a word containing "conftest.", or (3) at the end.
   # Note that $ac_compile itself does not contain backslashes and begins
   # with a dollar sign (not a hyphen), so the echo should work correctly.
   lt_compile=`echo "$ac_compile" | $SED \
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
   -e 's:$: $lt_compiler_flag:'`
   (eval echo "\"\$as_me:13755: $lt_compile\"" >&5)
   (eval "$lt_compile" 2>out/conftest.err)
   ac_status=$?
   cat out/conftest.err >&5
   echo "$as_me:13759: \$? = $ac_status" >&5
   if (exit $ac_status) && test -s out/conftest2.$ac_objext
   then
     # The compiler can only warn and ignore the option if not recognized
     # So say no if there are warnings
     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
       lt_cv_prog_compiler_c_o_CXX=yes
     fi
   fi
   chmod u+w . 2>&5
   $RM conftest*
   # SGI C++ compiler will create directory out/ii_files/ for
   # template instantiation
   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
   $RM out/* && rmdir out
   cd ..
   $RM -r conftest
   $RM conftest*

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5
$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }




hard_links="nottested"
if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then
  # do not overwrite the value of need_locks provided by the user
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
$as_echo_n "checking if we can lock with hard links... " >&6; }
  hard_links=yes
  $RM conftest*
  ln conftest.a conftest.b 2>/dev/null && hard_links=no
  touch conftest.a
  ln conftest.a conftest.b 2>&5 || hard_links=no
  ln conftest.a conftest.b 2>/dev/null && hard_links=no
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
$as_echo "$hard_links" >&6; }
  if test "$hard_links" = no; then
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
    need_locks=warn
  fi
else
  need_locks=no
fi



    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }

  export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
  case $host_os in
  aix[4-9]*)
    # If we're using GNU nm, then we don't want the "-C" option.
    # -C means demangle to AIX nm, but means don't demangle with GNU nm
    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
      export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
    else
      export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
    fi
    ;;
  pw32*)
    export_symbols_cmds_CXX="$ltdll_cmds"
  ;;
  cygwin* | mingw* | cegcc*)
    export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;/^.*[ ]__nm__/s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
  ;;
  linux* | k*bsd*-gnu)
    link_all_deplibs_CXX=no
  ;;
  *)
    export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
  ;;
  esac
  exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'

{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
$as_echo "$ld_shlibs_CXX" >&6; }
test "$ld_shlibs_CXX" = no && can_build_shared=no

with_gnu_ld_CXX=$with_gnu_ld






#
# Do we need to explicitly link libc?
#
case "x$archive_cmds_need_lc_CXX" in
x|xyes)
  # Assume -lc should be added
  archive_cmds_need_lc_CXX=yes

  if test "$enable_shared" = yes && test "$GCC" = yes; then
    case $archive_cmds_CXX in
    *'~'*)
      # FIXME: we may have to deal with multi-command sequences.
      ;;
    '$CC '*)
      # Test whether the compiler implicitly links with -lc since on some
      # systems, -lgcc has to come before -lc. If gcc already passes -lc
      # to ld, don't add -lc before -lgcc.
      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
      $RM conftest*
      echo "$lt_simple_compile_test_code" > conftest.$ac_ext

      if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
  (eval $ac_compile) 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } 2>conftest.err; then
        soname=conftest
        lib=conftest
        libobjs=conftest.$ac_objext
        deplibs=
        wl=$lt_prog_compiler_wl_CXX
	pic_flag=$lt_prog_compiler_pic_CXX
        compiler_flags=-v
        linker_flags=-v
        verstring=
        output_objdir=.
        libname=conftest
        lt_save_allow_undefined_flag=$allow_undefined_flag_CXX
        allow_undefined_flag_CXX=
        if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
  (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }
        then
	  archive_cmds_need_lc_CXX=no
        else
	  archive_cmds_need_lc_CXX=yes
        fi
        allow_undefined_flag_CXX=$lt_save_allow_undefined_flag
      else
        cat conftest.err 1>&5
      fi
      $RM conftest*
      { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc_CXX" >&5
$as_echo "$archive_cmds_need_lc_CXX" >&6; }
      ;;
    esac
  fi
  ;;
esac
































































    { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
$as_echo_n "checking dynamic linker characteristics... " >&6; }

library_names_spec=
libname_spec='lib$name'
soname_spec=
shrext_cmds=".so"
postinstall_cmds=
postuninstall_cmds=
finish_cmds=
finish_eval=
shlibpath_var=
shlibpath_overrides_runpath=unknown
version_type=none
dynamic_linker="$host_os ld.so"
sys_lib_dlsearch_path_spec="/lib /usr/lib"
need_lib_prefix=unknown
hardcode_into_libs=no

# when you set need_version to no, make sure it does not cause -set_version
# flags to be left without arguments
need_version=unknown

case $host_os in
aix3*)
  version_type=linux
  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
  shlibpath_var=LIBPATH

  # AIX 3 has no versioning support, so we append a major version to the name.
  soname_spec='${libname}${release}${shared_ext}$major'
  ;;

aix[4-9]*)
  version_type=linux
  need_lib_prefix=no
  need_version=no
  hardcode_into_libs=yes
  if test "$host_cpu" = ia64; then
    # AIX 5 supports IA64
    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
    shlibpath_var=LD_LIBRARY_PATH
  else
    # With GCC up to 2.95.x, collect2 would create an import file
    # for dependence libraries.  The import file would start with
    # the line `#! .'.  This would cause the generated library to
    # depend on `.', always an invalid library.  This was fixed in
    # development snapshots of GCC prior to 3.0.
    case $host_os in
      aix4 | aix4.[01] | aix4.[01].*)
      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
	   echo ' yes '
	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
	:
      else
	can_build_shared=no
      fi
      ;;
    esac
    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
    # soname into executable. Probably we can add versioning support to
    # collect2, so additional links can be useful in future.
    if test "$aix_use_runtimelinking" = yes; then
      # If using run time linking (on AIX 4.2 or later) use lib.so
      # instead of lib.a to let people know that these are not
      # typical AIX shared libraries.
      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
    else
      # We preserve .a as extension for shared libraries through AIX4.2
      # and later when we are not doing run time linking.
      library_names_spec='${libname}${release}.a $libname.a'
      soname_spec='${libname}${release}${shared_ext}$major'
    fi
    shlibpath_var=LIBPATH
  fi
  ;;

amigaos*)
  case $host_cpu in
  powerpc)
    # Since July 2007 AmigaOS4 officially supports .so libraries.
    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
    ;;
  m68k)
    library_names_spec='$libname.ixlibrary $libname.a'
    # Create ${libname}_ixlibrary.a entries in /sys/libs.
    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
    ;;
  esac
  ;;

beos*)
  library_names_spec='${libname}${shared_ext}'
  dynamic_linker="$host_os ld.so"
  shlibpath_var=LIBRARY_PATH
  ;;

bsdi[45]*)
  version_type=linux
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
  shlibpath_var=LD_LIBRARY_PATH
  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
  # the default ld.so.conf also contains /usr/contrib/lib and
  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
  # libtool to hard-code these into programs
  ;;

cygwin* | mingw* | pw32* | cegcc*)
  version_type=windows
  shrext_cmds=".dll"
  need_version=no
  need_lib_prefix=no

  case $GCC,$host_os in
  yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*)
    library_names_spec='$libname.dll.a'
    # DLL is installed to $(libdir)/../bin by postinstall_cmds
    postinstall_cmds='base_file=`basename \${file}`~
      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
      dldir=$destdir/`dirname \$dlpath`~
      test -d \$dldir || mkdir -p \$dldir~
      $install_prog $dir/$dlname \$dldir/$dlname~
      chmod a+x \$dldir/$dlname~
      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
      fi'
    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
      dlpath=$dir/\$dldll~
       $RM \$dlpath'
    shlibpath_overrides_runpath=yes

    case $host_os in
    cygwin*)
      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
      ;;
    mingw* | cegcc*)
      # MinGW DLLs use traditional 'lib' prefix
      soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
      sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
      if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
        # It is most probably a Windows format PATH printed by
        # mingw gcc, but we are running on Cygwin. Gcc prints its search
        # path with ; separators, and with drive letters. We can handle the
        # drive letters (cygwin fileutils understands them), so leave them,
        # especially as we might pass files found there to a mingw objdump,
        # which wouldn't understand a cygwinified path. Ahh.
        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
      else
        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
      fi
      ;;
    pw32*)
      # pw32 DLLs use 'pw' prefix rather than 'lib'
      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
      ;;
    esac
    ;;

  *)
    library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
    ;;
  esac
  dynamic_linker='Win32 ld.exe'
  # FIXME: first we should search . and the directory the executable is in
  shlibpath_var=PATH
  ;;

darwin* | rhapsody*)
  dynamic_linker="$host_os dyld"
  version_type=darwin
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
  soname_spec='${libname}${release}${major}$shared_ext'
  shlibpath_overrides_runpath=yes
  shlibpath_var=DYLD_LIBRARY_PATH
  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'

  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
  ;;

dgux*)
  version_type=linux
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
  soname_spec='${libname}${release}${shared_ext}$major'
  shlibpath_var=LD_LIBRARY_PATH
  ;;

freebsd1*)
  dynamic_linker=no
  ;;

freebsd* | dragonfly*)
  # DragonFly does not have aout.  When/if they implement a new
  # versioning mechanism, adjust this.
  if test -x /usr/bin/objformat; then
    objformat=`/usr/bin/objformat`
  else
    case $host_os in
    freebsd[123]*) objformat=aout ;;
    *) objformat=elf ;;
    esac
  fi
  version_type=freebsd-$objformat
  case $version_type in
    freebsd-elf*)
      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
      need_version=no
      need_lib_prefix=no
      ;;
    freebsd-*)
      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
      need_version=yes
      ;;
  esac
  shlibpath_var=LD_LIBRARY_PATH
  case $host_os in
  freebsd2*)
    shlibpath_overrides_runpath=yes
    ;;
  freebsd3.[01]* | freebsdelf3.[01]*)
    shlibpath_overrides_runpath=yes
    hardcode_into_libs=yes
    ;;
  freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
  freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
    shlibpath_overrides_runpath=no
    hardcode_into_libs=yes
    ;;
  *) # from 4.6 on, and DragonFly
    shlibpath_overrides_runpath=yes
    hardcode_into_libs=yes
    ;;
  esac
  ;;

gnu*)
  version_type=linux
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  shlibpath_var=LD_LIBRARY_PATH
  hardcode_into_libs=yes
  ;;

hpux9* | hpux10* | hpux11*)
  # Give a soname corresponding to the major version so that dld.sl refuses to
  # link against other versions.
  version_type=sunos
  need_lib_prefix=no
  need_version=no
  case $host_cpu in
  ia64*)
    shrext_cmds='.so'
    hardcode_into_libs=yes
    dynamic_linker="$host_os dld.so"
    shlibpath_var=LD_LIBRARY_PATH
    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
    soname_spec='${libname}${release}${shared_ext}$major'
    if test "X$HPUX_IA64_MODE" = X32; then
      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
    else
      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
    fi
    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
    ;;
  hppa*64*)
    shrext_cmds='.sl'
    hardcode_into_libs=yes
    dynamic_linker="$host_os dld.sl"
    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
    soname_spec='${libname}${release}${shared_ext}$major'
    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
    ;;
  *)
    shrext_cmds='.sl'
    dynamic_linker="$host_os dld.sl"
    shlibpath_var=SHLIB_PATH
    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
    soname_spec='${libname}${release}${shared_ext}$major'
    ;;
  esac
  # HP-UX runs *really* slowly unless shared libraries are mode 555.
  postinstall_cmds='chmod 555 $lib'
  ;;

interix[3-9]*)
  version_type=linux
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=no
  hardcode_into_libs=yes
  ;;

irix5* | irix6* | nonstopux*)
  case $host_os in
    nonstopux*) version_type=nonstopux ;;
    *)
	if test "$lt_cv_prog_gnu_ld" = yes; then
		version_type=linux
	else
		version_type=irix
	fi ;;
  esac
  need_lib_prefix=no
  need_version=no
  soname_spec='${libname}${release}${shared_ext}$major'
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
  case $host_os in
  irix5* | nonstopux*)
    libsuff= shlibsuff=
    ;;
  *)
    case $LD in # libtool.m4 will add one of these switches to LD
    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
      libsuff= shlibsuff= libmagic=32-bit;;
    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
      libsuff=32 shlibsuff=N32 libmagic=N32;;
    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
      libsuff=64 shlibsuff=64 libmagic=64-bit;;
    *) libsuff= shlibsuff= libmagic=never-match;;
    esac
    ;;
  esac
  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
  shlibpath_overrides_runpath=no
  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
  hardcode_into_libs=yes
  ;;

# No shared lib support for Linux oldld, aout, or coff.
linux*oldld* | linux*aout* | linux*coff*)
  dynamic_linker=no
  ;;

# This must be Linux ELF.
linux* | k*bsd*-gnu | kopensolaris*-gnu)
  version_type=linux
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=no
  # Some binutils ld are patched to set DT_RUNPATH
  save_LDFLAGS=$LDFLAGS
  save_libdir=$libdir
  eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \
       LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\""
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_cxx_try_link "$LINENO"; then :
  if  ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
  shlibpath_overrides_runpath=yes
fi
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
  LDFLAGS=$save_LDFLAGS
  libdir=$save_libdir

  # This implies no fast_install, which is unacceptable.
  # Some rework will be needed to allow for fast_install
  # before this can be enabled.
  hardcode_into_libs=yes

  # Append ld.so.conf contents to the search path
  if test -f /etc/ld.so.conf; then
    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
  fi

  # We used to test for /lib/ld.so.1 and disable shared libraries on
  # powerpc, because MkLinux only supported shared libraries with the
  # GNU dynamic linker.  Since this was broken with cross compilers,
  # most powerpc-linux boxes support dynamic linking these days and
  # people can always --disable-shared, the test was removed, and we
  # assume the GNU/Linux dynamic linker is in use.
  dynamic_linker='GNU/Linux ld.so'
  ;;

netbsdelf*-gnu)
  version_type=linux
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=no
  hardcode_into_libs=yes
  dynamic_linker='NetBSD ld.elf_so'
  ;;

netbsd*)
  version_type=sunos
  need_lib_prefix=no
  need_version=no
  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
    dynamic_linker='NetBSD (a.out) ld.so'
  else
    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
    soname_spec='${libname}${release}${shared_ext}$major'
    dynamic_linker='NetBSD ld.elf_so'
  fi
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=yes
  hardcode_into_libs=yes
  ;;

newsos6)
  version_type=linux
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=yes
  ;;

*nto* | *qnx*)
  version_type=qnx
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=no
  hardcode_into_libs=yes
  dynamic_linker='ldqnx.so'
  ;;

openbsd*)
  version_type=sunos
  sys_lib_dlsearch_path_spec="/usr/lib"
  need_lib_prefix=no
  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
  case $host_os in
    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
    *)				need_version=no  ;;
  esac
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
  shlibpath_var=LD_LIBRARY_PATH
  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
    case $host_os in
      openbsd2.[89] | openbsd2.[89].*)
	shlibpath_overrides_runpath=no
	;;
      *)
	shlibpath_overrides_runpath=yes
	;;
      esac
  else
    shlibpath_overrides_runpath=yes
  fi
  ;;

os2*)
  libname_spec='$name'
  shrext_cmds=".dll"
  need_lib_prefix=no
  library_names_spec='$libname${shared_ext} $libname.a'
  dynamic_linker='OS/2 ld.exe'
  shlibpath_var=LIBPATH
  ;;

osf3* | osf4* | osf5*)
  version_type=osf
  need_lib_prefix=no
  need_version=no
  soname_spec='${libname}${release}${shared_ext}$major'
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
  shlibpath_var=LD_LIBRARY_PATH
  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
  ;;

rdos*)
  dynamic_linker=no
  ;;

solaris*)
  version_type=linux
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=yes
  hardcode_into_libs=yes
  # ldd complains unless libraries are executable
  postinstall_cmds='chmod +x $lib'
  ;;

sunos4*)
  version_type=sunos
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=yes
  if test "$with_gnu_ld" = yes; then
    need_lib_prefix=no
  fi
  need_version=yes
  ;;

sysv4 | sysv4.3*)
  version_type=linux
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  shlibpath_var=LD_LIBRARY_PATH
  case $host_vendor in
    sni)
      shlibpath_overrides_runpath=no
      need_lib_prefix=no
      runpath_var=LD_RUN_PATH
      ;;
    siemens)
      need_lib_prefix=no
      ;;
    motorola)
      need_lib_prefix=no
      need_version=no
      shlibpath_overrides_runpath=no
      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
      ;;
  esac
  ;;

sysv4*MP*)
  if test -d /usr/nec ;then
    version_type=linux
    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
    soname_spec='$libname${shared_ext}.$major'
    shlibpath_var=LD_LIBRARY_PATH
  fi
  ;;

sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
  version_type=freebsd-elf
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=yes
  hardcode_into_libs=yes
  if test "$with_gnu_ld" = yes; then
    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
  else
    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
    case $host_os in
      sco3.2v5*)
        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
	;;
    esac
  fi
  sys_lib_dlsearch_path_spec='/usr/lib'
  ;;

tpf*)
  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
  version_type=linux
  need_lib_prefix=no
  need_version=no
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
  shlibpath_var=LD_LIBRARY_PATH
  shlibpath_overrides_runpath=no
  hardcode_into_libs=yes
  ;;

uts4*)
  version_type=linux
  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
  soname_spec='${libname}${release}${shared_ext}$major'
  shlibpath_var=LD_LIBRARY_PATH
  ;;

*)
  dynamic_linker=no
  ;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
$as_echo "$dynamic_linker" >&6; }
test "$dynamic_linker" = no && can_build_shared=no

variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
if test "$GCC" = yes; then
  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
fi

if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
fi
if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
fi




































    { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
hardcode_action_CXX=
if test -n "$hardcode_libdir_flag_spec_CXX" ||
   test -n "$runpath_var_CXX" ||
   test "X$hardcode_automatic_CXX" = "Xyes" ; then

  # We can hardcode non-existent directories.
  if test "$hardcode_direct_CXX" != no &&
     # If the only mechanism to avoid hardcoding is shlibpath_var, we
     # have to relink, otherwise we might link with an installed library
     # when we should be linking with a yet-to-be-installed one
     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no &&
     test "$hardcode_minus_L_CXX" != no; then
    # Linking always hardcodes the temporary library directory.
    hardcode_action_CXX=relink
  else
    # We can link without hardcoding, and we can hardcode nonexisting dirs.
    hardcode_action_CXX=immediate
  fi
else
  # We cannot hardcode anything, or else we can only hardcode existing
  # directories.
  hardcode_action_CXX=unsupported
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5
$as_echo "$hardcode_action_CXX" >&6; }

if test "$hardcode_action_CXX" = relink ||
   test "$inherit_rpath_CXX" = yes; then
  # Fast installation is not supported
  enable_fast_install=no
elif test "$shlibpath_overrides_runpath" = yes ||
     test "$enable_shared" = no; then
  # Fast installation is not necessary
  enable_fast_install=needless
fi







  fi # test -n "$compiler"

  CC=$lt_save_CC
  LDCXX=$LD
  LD=$lt_save_LD
  GCC=$lt_save_GCC
  with_gnu_ld=$lt_save_with_gnu_ld
  lt_cv_path_LDCXX=$lt_cv_path_LD
  lt_cv_path_LD=$lt_save_path_LD
  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
fi # test "$_lt_caught_CXX_error" != yes

ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu













        ac_config_commands="$ac_config_commands libtool"




# Only expand once:





if test "x$LIBTOOL" != "x"; then
  USE_LIBTOOL_TRUE=
  USE_LIBTOOL_FALSE='#'
else
  USE_LIBTOOL_TRUE='#'
  USE_LIBTOOL_FALSE=
fi


{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
$as_echo_n "checking for inline... " >&6; }
if test "${ac_cv_c_inline+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  ac_cv_c_inline=no
for ac_kw in inline __inline__ __inline; do
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#ifndef __cplusplus
typedef int foo_t;
static $ac_kw foo_t static_foo () {return 0; }
$ac_kw foo_t foo () {return 0; }
#endif

_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_cv_c_inline=$ac_kw
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
  test "$ac_cv_c_inline" != no && break
done

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
$as_echo "$ac_cv_c_inline" >&6; }

case $ac_cv_c_inline in
  inline | yes) ;;
  *)
    case $ac_cv_c_inline in
      no) ac_val=;;
      *) ac_val=$ac_cv_c_inline;;
    esac
    cat >>confdefs.h <<_ACEOF
#ifndef __cplusplus
#define inline $ac_val
#endif
_ACEOF
    ;;
esac


  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__" >&5
$as_echo_n "checking for __attribute__... " >&6; }
  if test "${ac_cv___attribute__+set}" = set; then :
  $as_echo_n "(cached) " >&6
else

    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
       static void foo(void) __attribute__ ((unused));
       void foo(void) { exit(1); }
int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_cv___attribute__=yes
else
  ac_cv___attribute__=no

fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi

  if test "$ac_cv___attribute__" = "yes"; then

$as_echo "#define HAVE___ATTRIBUTE__ 1" >>confdefs.h

  fi
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv___attribute__" >&5
$as_echo "$ac_cv___attribute__" >&6; }


# Check whether some low-level functions/files are available
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
$as_echo_n "checking for ANSI C header files... " >&6; }
if test "${ac_cv_header_stdc+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
#include 
#include 
#include 

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_cv_header_stdc=yes
else
  ac_cv_header_stdc=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext

if test $ac_cv_header_stdc = yes; then
  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 

_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
  $EGREP "memchr" >/dev/null 2>&1; then :

else
  ac_cv_header_stdc=no
fi
rm -f conftest*

fi

if test $ac_cv_header_stdc = yes; then
  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 

_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
  $EGREP "free" >/dev/null 2>&1; then :

else
  ac_cv_header_stdc=no
fi
rm -f conftest*

fi

if test $ac_cv_header_stdc = yes; then
  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
  if test "$cross_compiling" = yes; then :
  :
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
#include 
#if ((' ' & 0x0FF) == 0x020)
# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
#else
# define ISLOWER(c) \
		   (('a' <= (c) && (c) <= 'i') \
		     || ('j' <= (c) && (c) <= 'r') \
		     || ('s' <= (c) && (c) <= 'z'))
# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
#endif

#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
int
main ()
{
  int i;
  for (i = 0; i < 256; i++)
    if (XOR (islower (i), ISLOWER (i))
	|| toupper (i) != TOUPPER (i))
      return 2;
  return 0;
}
_ACEOF
if ac_fn_c_try_run "$LINENO"; then :

else
  ac_cv_header_stdc=no
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
  conftest.$ac_objext conftest.beam conftest.$ac_ext
fi

fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
$as_echo "$ac_cv_header_stdc" >&6; }
if test $ac_cv_header_stdc = yes; then

$as_echo "#define STDC_HEADERS 1" >>confdefs.h

fi


# TODO(csilvers): we could remove a lot when WITH_CPU_PROFILER etc is "no".
ac_fn_c_check_type "$LINENO" "__int64" "ac_cv_type___int64" "$ac_includes_default"
if test "x$ac_cv_type___int64" = x""yes; then :

cat >>confdefs.h <<_ACEOF
#define HAVE___INT64 1
_ACEOF


fi
       # defined in some windows platforms
ac_fn_c_check_type "$LINENO" "struct mallinfo" "ac_cv_type_struct_mallinfo" "#include 
"
if test "x$ac_cv_type_struct_mallinfo" = x""yes; then :

cat >>confdefs.h <<_ACEOF
#define HAVE_STRUCT_MALLINFO 1
_ACEOF


fi

ac_fn_c_check_type "$LINENO" "Elf32_Versym" "ac_cv_type_Elf32_Versym" "#include 
"
if test "x$ac_cv_type_Elf32_Versym" = x""yes; then :

cat >>confdefs.h <<_ACEOF
#define HAVE_ELF32_VERSYM 1
_ACEOF


fi
   # for vdso_support.h
for ac_func in sbrk
do :
  ac_fn_c_check_func "$LINENO" "sbrk" "ac_cv_func_sbrk"
if test "x$ac_cv_func_sbrk" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_SBRK 1
_ACEOF

fi
done
            # for tcmalloc to get memory
for ac_func in geteuid
do :
  ac_fn_c_check_func "$LINENO" "geteuid" "ac_cv_func_geteuid"
if test "x$ac_cv_func_geteuid" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_GETEUID 1
_ACEOF

fi
done
         # for turning off services when run as root
for ac_header in features.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "features.h" "ac_cv_header_features_h" "$ac_includes_default"
if test "x$ac_cv_header_features_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_FEATURES_H 1
_ACEOF

fi

done
    # for vdso_support.h
for ac_header in malloc.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "malloc.h" "ac_cv_header_malloc_h" "$ac_includes_default"
if test "x$ac_cv_header_malloc_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_MALLOC_H 1
_ACEOF

fi

done
      # some systems define stuff there, others not
for ac_header in glob.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "glob.h" "ac_cv_header_glob_h" "$ac_includes_default"
if test "x$ac_cv_header_glob_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_GLOB_H 1
_ACEOF

fi

done
        # for heap-profile-table (cleaning up profiles)
for ac_header in execinfo.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default"
if test "x$ac_cv_header_execinfo_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_EXECINFO_H 1
_ACEOF

fi

done
    # for stacktrace? and heapchecker_unittest
for ac_header in libunwind.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "libunwind.h" "ac_cv_header_libunwind_h" "$ac_includes_default"
if test "x$ac_cv_header_libunwind_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_LIBUNWIND_H 1
_ACEOF

fi

done
   # for stacktrace
for ac_header in unwind.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "unwind.h" "ac_cv_header_unwind_h" "$ac_includes_default"
if test "x$ac_cv_header_unwind_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_UNWIND_H 1
_ACEOF

fi

done
      # for stacktrace
for ac_header in sched.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "sched.h" "ac_cv_header_sched_h" "$ac_includes_default"
if test "x$ac_cv_header_sched_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_SCHED_H 1
_ACEOF

fi

done
       # for being nice in our spinlock code
for ac_header in conflict-signal.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "conflict-signal.h" "ac_cv_header_conflict_signal_h" "$ac_includes_default"
if test "x$ac_cv_header_conflict_signal_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_CONFLICT_SIGNAL_H 1
_ACEOF

fi

done
      # defined on some windows platforms?
for ac_header in sys/prctl.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "sys/prctl.h" "ac_cv_header_sys_prctl_h" "$ac_includes_default"
if test "x$ac_cv_header_sys_prctl_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_SYS_PRCTL_H 1
_ACEOF

fi

done
   # for thread_lister (needed by leak-checker)
for ac_header in linux/ptrace.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "linux/ptrace.h" "ac_cv_header_linux_ptrace_h" "$ac_includes_default"
if test "x$ac_cv_header_linux_ptrace_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_LINUX_PTRACE_H 1
_ACEOF

fi

done
# also needed by leak-checker
for ac_header in sys/syscall.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "sys/syscall.h" "ac_cv_header_sys_syscall_h" "$ac_includes_default"
if test "x$ac_cv_header_sys_syscall_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_SYS_SYSCALL_H 1
_ACEOF

fi

done

for ac_header in sys/socket.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default"
if test "x$ac_cv_header_sys_socket_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_SYS_SOCKET_H 1
_ACEOF

fi

done
  # optional; for forking out to symbolizer
for ac_header in sys/wait.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "sys/wait.h" "ac_cv_header_sys_wait_h" "$ac_includes_default"
if test "x$ac_cv_header_sys_wait_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_SYS_WAIT_H 1
_ACEOF

fi

done
    # optional; for forking out to symbolizer
for ac_header in poll.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "poll.h" "ac_cv_header_poll_h" "$ac_includes_default"
if test "x$ac_cv_header_poll_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_POLL_H 1
_ACEOF

fi

done
        # optional; for forking out to symbolizer
for ac_header in fcntl.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "fcntl.h" "ac_cv_header_fcntl_h" "$ac_includes_default"
if test "x$ac_cv_header_fcntl_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_FCNTL_H 1
_ACEOF

fi

done
       # for tcmalloc_unittest
for ac_header in grp.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "grp.h" "ac_cv_header_grp_h" "$ac_includes_default"
if test "x$ac_cv_header_grp_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_GRP_H 1
_ACEOF

fi

done
         # for heapchecker_unittest
for ac_header in pwd.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "pwd.h" "ac_cv_header_pwd_h" "$ac_includes_default"
if test "x$ac_cv_header_pwd_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_PWD_H 1
_ACEOF

fi

done
         # for heapchecker_unittest
for ac_header in sys/resource.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "sys/resource.h" "ac_cv_header_sys_resource_h" "$ac_includes_default"
if test "x$ac_cv_header_sys_resource_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_SYS_RESOURCE_H 1
_ACEOF

fi

done
         # for memalign_unittest.cc
for ac_header in valgrind.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "valgrind.h" "ac_cv_header_valgrind_h" "$ac_includes_default"
if test "x$ac_cv_header_valgrind_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_VALGRIND_H 1
_ACEOF

fi

done
    # we have a local copy if this isn't found
# We also need /, but we get those from
# AC_PC_FROM_UCONTEXT, below.

# We override a lot of memory allocation routines, not all of which are
# standard.  For those the system doesn't declare, we'll declare ourselves.
ac_fn_c_check_decl "$LINENO" "cfree" "ac_cv_have_decl_cfree" "#define _XOPEN_SOURCE 600
                #include 
                #include 
"
if test "x$ac_cv_have_decl_cfree" = x""yes; then :
  ac_have_decl=1
else
  ac_have_decl=0
fi

cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_CFREE $ac_have_decl
_ACEOF
ac_fn_c_check_decl "$LINENO" "posix_memalign" "ac_cv_have_decl_posix_memalign" "#define _XOPEN_SOURCE 600
                #include 
                #include 
"
if test "x$ac_cv_have_decl_posix_memalign" = x""yes; then :
  ac_have_decl=1
else
  ac_have_decl=0
fi

cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_POSIX_MEMALIGN $ac_have_decl
_ACEOF
ac_fn_c_check_decl "$LINENO" "memalign" "ac_cv_have_decl_memalign" "#define _XOPEN_SOURCE 600
                #include 
                #include 
"
if test "x$ac_cv_have_decl_memalign" = x""yes; then :
  ac_have_decl=1
else
  ac_have_decl=0
fi

cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_MEMALIGN $ac_have_decl
_ACEOF
ac_fn_c_check_decl "$LINENO" "valloc" "ac_cv_have_decl_valloc" "#define _XOPEN_SOURCE 600
                #include 
                #include 
"
if test "x$ac_cv_have_decl_valloc" = x""yes; then :
  ac_have_decl=1
else
  ac_have_decl=0
fi

cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_VALLOC $ac_have_decl
_ACEOF
ac_fn_c_check_decl "$LINENO" "pvalloc" "ac_cv_have_decl_pvalloc" "#define _XOPEN_SOURCE 600
                #include 
                #include 
"
if test "x$ac_cv_have_decl_pvalloc" = x""yes; then :
  ac_have_decl=1
else
  ac_have_decl=0
fi

cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_PVALLOC $ac_have_decl
_ACEOF


if test "$ac_cv_type_struct_mallinfo" = yes; then
  ac_cv_have_struct_mallinfo=1
   # google/tcmalloc.h needs this
else
  ac_cv_have_struct_mallinfo=0

fi

# We need to check for mmap.  cygwin supports mmap, but the autoconf
# test doesn't work on cygwin:
#    http://www.cygwin.com/ml/cygwin/2002-04/msg00412.html
# This workaround comes from
#    http://cygwin.com/ml/cygwin/2004-11/msg00138.html
case "$host" in
  *-*-cygwin*) ac_cv_func_mmap_fixed_mapped=yes

$as_echo "#define HAVE_MMAP 1" >>confdefs.h

               ;;
            *)


  for ac_header in $ac_header_list
do :
  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
"
eval as_val=\$$as_ac_Header
   if test "x$as_val" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
_ACEOF

fi

done








for ac_func in getpagesize
do :
  ac_fn_c_check_func "$LINENO" "getpagesize" "ac_cv_func_getpagesize"
if test "x$ac_cv_func_getpagesize" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_GETPAGESIZE 1
_ACEOF

fi
done

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working mmap" >&5
$as_echo_n "checking for working mmap... " >&6; }
if test "${ac_cv_func_mmap_fixed_mapped+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test "$cross_compiling" = yes; then :
  ac_cv_func_mmap_fixed_mapped=no
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
$ac_includes_default
/* malloc might have been renamed as rpl_malloc. */
#undef malloc

/* Thanks to Mike Haertel and Jim Avera for this test.
   Here is a matrix of mmap possibilities:
	mmap private not fixed
	mmap private fixed at somewhere currently unmapped
	mmap private fixed at somewhere already mapped
	mmap shared not fixed
	mmap shared fixed at somewhere currently unmapped
	mmap shared fixed at somewhere already mapped
   For private mappings, we should verify that changes cannot be read()
   back from the file, nor mmap's back from the file at a different
   address.  (There have been systems where private was not correctly
   implemented like the infamous i386 svr4.0, and systems where the
   VM page cache was not coherent with the file system buffer cache
   like early versions of FreeBSD and possibly contemporary NetBSD.)
   For shared mappings, we should conversely verify that changes get
   propagated back to all the places they're supposed to be.

   Grep wants private fixed already mapped.
   The main things grep needs to know about mmap are:
   * does it exist and is it safe to write into the mmap'd area
   * how to use it (BSD variants)  */

#include 
#include 

#if !defined STDC_HEADERS && !defined HAVE_STDLIB_H
char *malloc ();
#endif

/* This mess was copied from the GNU getpagesize.h.  */
#ifndef HAVE_GETPAGESIZE
# ifdef _SC_PAGESIZE
#  define getpagesize() sysconf(_SC_PAGESIZE)
# else /* no _SC_PAGESIZE */
#  ifdef HAVE_SYS_PARAM_H
#   include 
#   ifdef EXEC_PAGESIZE
#    define getpagesize() EXEC_PAGESIZE
#   else /* no EXEC_PAGESIZE */
#    ifdef NBPG
#     define getpagesize() NBPG * CLSIZE
#     ifndef CLSIZE
#      define CLSIZE 1
#     endif /* no CLSIZE */
#    else /* no NBPG */
#     ifdef NBPC
#      define getpagesize() NBPC
#     else /* no NBPC */
#      ifdef PAGESIZE
#       define getpagesize() PAGESIZE
#      endif /* PAGESIZE */
#     endif /* no NBPC */
#    endif /* no NBPG */
#   endif /* no EXEC_PAGESIZE */
#  else /* no HAVE_SYS_PARAM_H */
#   define getpagesize() 8192	/* punt totally */
#  endif /* no HAVE_SYS_PARAM_H */
# endif /* no _SC_PAGESIZE */

#endif /* no HAVE_GETPAGESIZE */

int
main ()
{
  char *data, *data2, *data3;
  const char *cdata2;
  int i, pagesize;
  int fd, fd2;

  pagesize = getpagesize ();

  /* First, make a file with some known garbage in it. */
  data = (char *) malloc (pagesize);
  if (!data)
    return 1;
  for (i = 0; i < pagesize; ++i)
    *(data + i) = rand ();
  umask (0);
  fd = creat ("conftest.mmap", 0600);
  if (fd < 0)
    return 2;
  if (write (fd, data, pagesize) != pagesize)
    return 3;
  close (fd);

  /* Next, check that the tail of a page is zero-filled.  File must have
     non-zero length, otherwise we risk SIGBUS for entire page.  */
  fd2 = open ("conftest.txt", O_RDWR | O_CREAT | O_TRUNC, 0600);
  if (fd2 < 0)
    return 4;
  cdata2 = "";
  if (write (fd2, cdata2, 1) != 1)
    return 5;
  data2 = (char *) mmap (0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, 0L);
  if (data2 == MAP_FAILED)
    return 6;
  for (i = 0; i < pagesize; ++i)
    if (*(data2 + i))
      return 7;
  close (fd2);
  if (munmap (data2, pagesize))
    return 8;

  /* Next, try to mmap the file at a fixed address which already has
     something else allocated at it.  If we can, also make sure that
     we see the same garbage.  */
  fd = open ("conftest.mmap", O_RDWR);
  if (fd < 0)
    return 9;
  if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE,
		     MAP_PRIVATE | MAP_FIXED, fd, 0L))
    return 10;
  for (i = 0; i < pagesize; ++i)
    if (*(data + i) != *(data2 + i))
      return 11;

  /* Finally, make sure that changes to the mapped area do not
     percolate back to the file as seen by read().  (This is a bug on
     some variants of i386 svr4.0.)  */
  for (i = 0; i < pagesize; ++i)
    *(data2 + i) = *(data2 + i) + 1;
  data3 = (char *) malloc (pagesize);
  if (!data3)
    return 12;
  if (read (fd, data3, pagesize) != pagesize)
    return 13;
  for (i = 0; i < pagesize; ++i)
    if (*(data + i) != *(data3 + i))
      return 14;
  close (fd);
  return 0;
}
_ACEOF
if ac_fn_c_try_run "$LINENO"; then :
  ac_cv_func_mmap_fixed_mapped=yes
else
  ac_cv_func_mmap_fixed_mapped=no
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
  conftest.$ac_objext conftest.beam conftest.$ac_ext
fi

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_fixed_mapped" >&5
$as_echo "$ac_cv_func_mmap_fixed_mapped" >&6; }
if test $ac_cv_func_mmap_fixed_mapped = yes; then

$as_echo "#define HAVE_MMAP 1" >>confdefs.h

fi
rm -f conftest.mmap conftest.txt

               ;;
esac

# If AtomicWord != Atomic32, we need to define two versions of all the
# atomicops functions.  If they're the same, we want to define only one.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if int32_t is the same type as intptr_t" >&5
$as_echo_n "checking if int32_t is the same type as intptr_t... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
int
main ()
{
int32_t v1 = 0; intptr_t v2 = 0; return (&v1 - &v2)
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :

$as_echo "#define INT32_EQUALS_INTPTR 1" >>confdefs.h

                { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext

# We want to access the "PC" (Program Counter) register from a struct
# ucontext.  Every system has its own way of doing that.  We try all the
# possibilities we know about.  Note REG_PC should come first (REG_RIP
# is also defined on solaris, but does the wrong thing).  But don't
# bother if we're not doing cpu-profiling.
# [*] means that we've not actually tested one of these systems
if test "$enable_cpu_profiler" = yes; then
  for ac_header in ucontext.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "ucontext.h" "ac_cv_header_ucontext_h" "$ac_includes_default"
if test "x$ac_cv_header_ucontext_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_UCONTEXT_H 1
_ACEOF

fi

done

   # Redhat 7 has , but it barfs if we #include it directly
   # (this was fixed in later redhats).   works fine, so use that.
   if grep "Red Hat Linux release 7" /etc/redhat-release >/dev/null 2>&1; then

$as_echo "#define HAVE_SYS_UCONTEXT_H 0" >>confdefs.h

     ac_cv_header_sys_ucontext_h=no
   else
     for ac_header in sys/ucontext.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "sys/ucontext.h" "ac_cv_header_sys_ucontext_h" "$ac_includes_default"
if test "x$ac_cv_header_sys_ucontext_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_SYS_UCONTEXT_H 1
_ACEOF

fi

done
       # ucontext on OS X 10.6 (at least)
   fi
   for ac_header in cygwin/signal.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "cygwin/signal.h" "ac_cv_header_cygwin_signal_h" "$ac_includes_default"
if test "x$ac_cv_header_cygwin_signal_h" = x""yes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_CYGWIN_SIGNAL_H 1
_ACEOF

fi

done
        # ucontext on cywgin
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to access the program counter from a struct ucontext" >&5
$as_echo_n "checking how to access the program counter from a struct ucontext... " >&6; }
   pc_fields="           uc_mcontext.gregs[REG_PC]"  # Solaris x86 (32 + 64 bit)
   pc_fields="$pc_fields uc_mcontext.gregs[REG_EIP]" # Linux (i386)
   pc_fields="$pc_fields uc_mcontext.gregs[REG_RIP]" # Linux (x86_64)
   pc_fields="$pc_fields uc_mcontext.sc_ip"            # Linux (ia64)
   pc_fields="$pc_fields uc_mcontext.uc_regs->gregs[PT_NIP]" # Linux (ppc)
   pc_fields="$pc_fields uc_mcontext.gregs[R15]"     # Linux (arm old [untested])
   pc_fields="$pc_fields uc_mcontext.arm_pc"           # Linux (arm arch 5)
   pc_fields="$pc_fields uc_mcontext.gp_regs[PT_NIP]"  # Suse SLES 11 (ppc64)
   pc_fields="$pc_fields uc_mcontext.mc_eip"           # FreeBSD (i386)
   pc_fields="$pc_fields uc_mcontext.mc_rip"           # FreeBSD (x86_64 [untested])
   pc_fields="$pc_fields uc_mcontext.__gregs[_REG_EIP]"  # NetBSD (i386)
   pc_fields="$pc_fields uc_mcontext.__gregs[_REG_RIP]"  # NetBSD (x86_64)
   pc_fields="$pc_fields uc_mcontext->ss.eip"          # OS X (i386, <=10.4)
   pc_fields="$pc_fields uc_mcontext->__ss.__eip"      # OS X (i386, >=10.5)
   pc_fields="$pc_fields uc_mcontext->ss.rip"          # OS X (x86_64)
   pc_fields="$pc_fields uc_mcontext->__ss.__rip"      # OS X (>=10.5 [untested])
   pc_fields="$pc_fields uc_mcontext->ss.srr0"         # OS X (ppc, ppc64 [untested])
   pc_fields="$pc_fields uc_mcontext->__ss.__srr0"     # OS X (>=10.5 [untested])
   pc_field_found=false
   for pc_field in $pc_fields; do
     if ! $pc_field_found; then
       # Prefer sys/ucontext.h to ucontext.h, for OS X's sake.
       if test "x$ac_cv_header_cygwin_signal_h" = xyes; then
         cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#define _GNU_SOURCE 1
                         #include 
int
main ()
{
ucontext_t u; return u.$pc_field == 0;
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :

cat >>confdefs.h <<_ACEOF
#define PC_FROM_UCONTEXT $pc_field
_ACEOF

                        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pc_field" >&5
$as_echo "$pc_field" >&6; }
                        pc_field_found=true
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
       elif test "x$ac_cv_header_sys_ucontext_h" = xyes; then
         cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#define _GNU_SOURCE 1
                         #include 
int
main ()
{
ucontext_t u; return u.$pc_field == 0;
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :

cat >>confdefs.h <<_ACEOF
#define PC_FROM_UCONTEXT $pc_field
_ACEOF

                        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pc_field" >&5
$as_echo "$pc_field" >&6; }
                        pc_field_found=true
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
       elif test "x$ac_cv_header_ucontext_h" = xyes; then
         cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#define _GNU_SOURCE 1
                         #include 
int
main ()
{
ucontext_t u; return u.$pc_field == 0;
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :

cat >>confdefs.h <<_ACEOF
#define PC_FROM_UCONTEXT $pc_field
_ACEOF

                        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pc_field" >&5
$as_echo "$pc_field" >&6; }
                        pc_field_found=true
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
       else     # hope some standard header gives it to us
         cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{
ucontext_t u; return u.$pc_field == 0;
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :

cat >>confdefs.h <<_ACEOF
#define PC_FROM_UCONTEXT $pc_field
_ACEOF

                        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pc_field" >&5
$as_echo "$pc_field" >&6; }
                        pc_field_found=true
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
       fi
     fi
   done
   if ! $pc_field_found; then
     pc_fields="           sc_eip"  # OpenBSD (i386)
     pc_fields="$pc_fields sc_rip"  # OpenBSD (x86_64)
     for pc_field in $pc_fields; do
       if ! $pc_field_found; then
         cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
int
main ()
{
ucontext_t u; return u.$pc_field == 0;
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :

cat >>confdefs.h <<_ACEOF
#define PC_FROM_UCONTEXT $pc_field
_ACEOF

                        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pc_field" >&5
$as_echo "$pc_field" >&6; }
                        pc_field_found=true
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
       fi
     done
   fi
   if ! $pc_field_found; then
     { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not find the PC.  Will not try to compile libprofiler..." >&5
$as_echo "$as_me: WARNING: Could not find the PC.  Will not try to compile libprofiler..." >&2;};
                      enable_cpu_profiler=no
   fi
fi

# Some tests test the behavior of .so files, and only make sense for dynamic.


if test "$enable_static" = yes; then
  ENABLE_STATIC_TRUE=
  ENABLE_STATIC_FALSE='#'
else
  ENABLE_STATIC_TRUE='#'
  ENABLE_STATIC_FALSE=
fi


# We want to link in libunwind if it exists
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for backtrace in -lunwind" >&5
$as_echo_n "checking for backtrace in -lunwind... " >&6; }
if test "${ac_cv_lib_unwind_backtrace+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  ac_check_lib_save_LIBS=$LIBS
LIBS="-lunwind  $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

/* Override any GCC internal prototype to avoid an error.
   Use char because int might match the return type of a GCC
   builtin and then its argument prototype would still apply.  */
#ifdef __cplusplus
extern "C"
#endif
char backtrace ();
int
main ()
{
return backtrace ();
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  ac_cv_lib_unwind_backtrace=yes
else
  ac_cv_lib_unwind_backtrace=no
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_unwind_backtrace" >&5
$as_echo "$ac_cv_lib_unwind_backtrace" >&6; }
if test "x$ac_cv_lib_unwind_backtrace" = x""yes; then :
  UNWIND_LIBS=-lunwind
else
  UNWIND_LIBS=
fi



# On x86_64, instead of libunwind, we can choose to compile with frame-pointers
# (This isn't needed on i386, where -fno-omit-frame-pointer is the default).
# Check whether --enable-frame_pointers was given.
if test "${enable_frame_pointers+set}" = set; then :
  enableval=$enable_frame_pointers;
else
  enable_frame_pointers=no
fi



if test "$enable_frame_pointers" = yes; then
  ENABLE_FRAME_POINTERS_TRUE=
  ENABLE_FRAME_POINTERS_FALSE='#'
else
  ENABLE_FRAME_POINTERS_TRUE='#'
  ENABLE_FRAME_POINTERS_FALSE=
fi


# Some x86_64 systems do not insert frame pointers by default (all
# i386 systems that I know of, do.  I don't know about non-x86 chips).
# We want to see if the current system is one of those.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{
return __x86_64__ == 1 ? 0 : 1
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  is_x86_64=yes
else
  is_x86_64=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
OLD_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -S -O2 -o fp.s"
# This test will always fail because we don't name our output file properly.
# We do our own determination of success/failure in the grep, below.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
int f(int x) {return x;}
int
main ()
{
return f(0);
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  :
else
  :
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext


if test "$is_x86_64" = yes && ! grep 'mov.*rsp.*rbp' fp.s >/dev/null 2>&1; then
  X86_64_AND_NO_FP_BY_DEFAULT_TRUE=
  X86_64_AND_NO_FP_BY_DEFAULT_FALSE='#'
else
  X86_64_AND_NO_FP_BY_DEFAULT_TRUE='#'
  X86_64_AND_NO_FP_BY_DEFAULT_FALSE=
fi

rm fp.s
CFLAGS="$OLD_CFLAGS"


# Defines PRIuS
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking printf format code for printing a size_t and ssize_t" >&5
$as_echo_n "checking printf format code for printing a size_t and ssize_t... " >&6; }
if test "${ac_cv_formatting_prius_prefix+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
int
main ()
{
unsigned int v1 = 0; size_t v2 = 0; return (&v1 - &v2)
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_cv_formatting_prius_prefix=; ac_cv_prius_defined=1
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
int
main ()
{
unsigned long v1 = 0; size_t v2 = 0; return (&v1 - &v2)
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_cv_formatting_prius_prefix=l; ac_cv_prius_defined=1
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
int
main ()
{
unsigned long long v1 = 0; size_t v2 = 0; return (&v1 - &v2)
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_cv_formatting_prius_prefix=ll; ac_cv_prius_defined=1

fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_formatting_prius_prefix" >&5
$as_echo "$ac_cv_formatting_prius_prefix" >&6; }
   if test -z "$ac_cv_prius_defined"; then
      ac_cv_formatting_prius_prefix=z;
   fi

cat >>confdefs.h <<_ACEOF
#define PRIuS "${ac_cv_formatting_prius_prefix}u"
_ACEOF


cat >>confdefs.h <<_ACEOF
#define PRIxS "${ac_cv_formatting_prius_prefix}x"
_ACEOF


cat >>confdefs.h <<_ACEOF
#define PRIdS "${ac_cv_formatting_prius_prefix}d"
_ACEOF



# Also make sure we get standard PRI... definitions, even with glibc.
# We have to use AH_VERBATIM because we need the #ifdef guard (gcc buglet)


# Check if __builtin_stack_pointer() is available (for elfcore.h)
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_stack_pointer()" >&5
$as_echo_n "checking for __builtin_stack_pointer()... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{
void *sp = __builtin_stack_pointer()
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :

$as_echo "#define HAVE_BUILTIN_STACK_POINTER 1" >>confdefs.h

                { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext

# Check if __environ is available (for GetenvBeforeMain)
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __environ" >&5
$as_echo_n "checking for __environ... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
int
main ()
{
char **env = __environ
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :

$as_echo "#define HAVE___ENVIRON 1" >>confdefs.h

                { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext

# If we support __thread, that can speed up tcmalloc a bit.
# Note, however, that our code tickles a bug in gcc < 4.1.2
# involving TLS and -fPIC (which our libraries will use) on x86:
#   http://gcc.gnu.org/ml/gcc-bugs/2006-09/msg02275.html
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __thread" >&5
$as_echo_n "checking for __thread... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 1) || (__GNUC__ == 4 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ < 2))
#error gcc has this bug: http://gcc.gnu.org/ml/gcc-bugs/2006-09/msg02275.html
#endif
int
main ()
{
static __thread int p = 0
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :

$as_echo "#define HAVE_TLS 1" >>confdefs.h

                { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext

# Nanosleep requires extra libraries on some architectures (solaris).
# This sets NANOSLEEP_LIBS.  nanosleep doesn't exist on mingw, which
# is fine for us because we don't compile libspinlock, which uses it.
if test "$need_nanosleep" = yes; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if nanosleep requires any libraries" >&5
$as_echo_n "checking if nanosleep requires any libraries... " >&6; }

 ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu

 acx_nanosleep_ok="no"
 NANOSLEEP_LIBS=
 # For most folks, this should just work
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
int
main ()
{
static struct timespec ts; nanosleep(&ts, NULL);
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  acx_nanosleep_ok=yes
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
 # For solaris, we may  need -lrt
 if test "x$acx_nanosleep_ok" != "xyes"; then
   OLD_LIBS="$LIBS"
   LIBS="-lrt $LIBS"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
int
main ()
{
static struct timespec ts; nanosleep(&ts, NULL);
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  acx_nanosleep_ok=yes
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
   if test "x$acx_nanosleep_ok" = "xyes"; then
     NANOSLEEP_LIBS="-lrt"
   fi
   LIBS="$OLD_LIBS"
 fi
 if test "x$acx_nanosleep_ok" != "xyes"; then
   as_fn_error "cannot find the nanosleep function" "$LINENO" 5
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${NANOSLEEP_LIBS:-no}" >&5
$as_echo "${NANOSLEEP_LIBS:-no}" >&6; }
 fi
 ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu



fi

# Solaris 10 6/06 has a bug where /usr/sfw/lib/libstdc++.la is empty.
# If so, we replace it with our own version.
LIBSTDCXX_LA_LINKER_FLAG=
if test -f /usr/sfw/lib/libstdc++.la && ! test -s /usr/sfw/lib/libstdc++.la
then
  LIBSTDCXX_LA_LINKER_FLAG='-L$(top_srcdir)/src/solaris'
fi


# We also need to check if the kernel supports __thread, which requires uname()
ac_fn_c_check_decl "$LINENO" "uname" "ac_cv_have_decl_uname" "#include 
"
if test "x$ac_cv_have_decl_uname" = x""yes; then :
  ac_have_decl=1
else
  ac_have_decl=0
fi

cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_UNAME $ac_have_decl
_ACEOF


# In fact, a lot of the code in this directory depends on pthreads



ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu

acx_pthread_ok=no

# We used to check for pthread.h first, but this fails if pthread.h
# requires special compiler flags (e.g. on True64 or Sequent).
# It gets checked for in the link test anyway.

# First of all, check if the user has set any of the PTHREAD_LIBS,
# etcetera environment variables, and if threads linking works using
# them:
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
        save_CFLAGS="$CFLAGS"
        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
        save_LIBS="$LIBS"
        LIBS="$PTHREAD_LIBS $LIBS"
        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS" >&5
$as_echo_n "checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS... " >&6; }
        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

/* Override any GCC internal prototype to avoid an error.
   Use char because int might match the return type of a GCC
   builtin and then its argument prototype would still apply.  */
#ifdef __cplusplus
extern "C"
#endif
char pthread_join ();
int
main ()
{
return pthread_join ();
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  acx_pthread_ok=yes
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_ok" >&5
$as_echo "$acx_pthread_ok" >&6; }
        if test x"$acx_pthread_ok" = xno; then
                PTHREAD_LIBS=""
                PTHREAD_CFLAGS=""
        fi
        LIBS="$save_LIBS"
        CFLAGS="$save_CFLAGS"
fi

# We must check for the threads library under a number of different
# names; the ordering is very important because some systems
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
# libraries is broken (non-POSIX).

# Create a list of thread flags to try.  Items starting with a "-" are
# C compiler flags, and other items are library names, except for "none"
# which indicates that we try without any flags at all, and "pthread-config"
# which is a program returning the flags for the Pth emulation library.

acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"

# The ordering *is* (sometimes) important.  Some notes on the
# individual items follow:

# pthreads: AIX (must check this before -lpthread)
# none: in case threads are in libc; should be tried before -Kthread and
#       other compiler flags to prevent continual compiler warnings
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
# -pthreads: Solaris/gcc
# -mthreads: Mingw32/gcc, Lynx/gcc
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
#      doesn't hurt to check since this sometimes defines pthreads too;
#      also defines -D_REENTRANT)
#      ... -mt is also the pthreads flag for HP/aCC
# pthread: Linux, etcetera
# --thread-safe: KAI C++
# pthread-config: use pthread-config program (for GNU Pth library)

case "${host_cpu}-${host_os}" in
        *solaris*)

        # On Solaris (at least, for some versions), libc contains stubbed
        # (non-functional) versions of the pthreads routines, so link-based
        # tests will erroneously succeed.  (We need to link with -pthreads/-mt/
        # -lpthread.)  (The stubs are missing pthread_cleanup_push, or rather
        # a function called by this macro, so we could check for that, but
        # who knows whether they'll stub that too in a future libc.)  So,
        # we'll just look for -pthreads and -lpthread first:

        acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags"
        ;;
esac

if test x"$acx_pthread_ok" = xno; then
for flag in $acx_pthread_flags; do

        case $flag in
                none)
                { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5
$as_echo_n "checking whether pthreads work without any flags... " >&6; }
                ;;

                -*)
                { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $flag" >&5
$as_echo_n "checking whether pthreads work with $flag... " >&6; }
                PTHREAD_CFLAGS="$flag"
                ;;

		pthread-config)
		# Extract the first word of "pthread-config", so it can be a program name with args.
set dummy pthread-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_acx_pthread_config+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$acx_pthread_config"; then
  ac_cv_prog_acx_pthread_config="$acx_pthread_config" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_acx_pthread_config="yes"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

  test -z "$ac_cv_prog_acx_pthread_config" && ac_cv_prog_acx_pthread_config="no"
fi
fi
acx_pthread_config=$ac_cv_prog_acx_pthread_config
if test -n "$acx_pthread_config"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_config" >&5
$as_echo "$acx_pthread_config" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


		if test x"$acx_pthread_config" = xno; then continue; fi
		PTHREAD_CFLAGS="`pthread-config --cflags`"
		PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
		;;

                *)
                { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$flag" >&5
$as_echo_n "checking for the pthreads library -l$flag... " >&6; }
                PTHREAD_LIBS="-l$flag"
                ;;
        esac

        save_LIBS="$LIBS"
        save_CFLAGS="$CFLAGS"
        LIBS="$PTHREAD_LIBS $LIBS"
        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"

        # Check for various functions.  We must include pthread.h,
        # since some functions may be macros.  (On the Sequent, we
        # need a special flag -Kthread to make this header compile.)
        # We check for pthread_join because it is in -lpthread on IRIX
        # while pthread_create is in libc.  We check for pthread_attr_init
        # due to DEC craziness with -lpthreads.  We check for
        # pthread_cleanup_push because it is one of the few pthread
        # functions on Solaris that doesn't have a non-functional libc stub.
        # We try pthread_create on general principles.
        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
int
main ()
{
pthread_t th; pthread_join(th, 0);
                     pthread_attr_init(0); pthread_cleanup_push(0, 0);
                     pthread_create(0,0,0,0); pthread_cleanup_pop(0);
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  acx_pthread_ok=yes
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext

        LIBS="$save_LIBS"
        CFLAGS="$save_CFLAGS"

        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_ok" >&5
$as_echo "$acx_pthread_ok" >&6; }
        if test "x$acx_pthread_ok" = xyes; then
                break;
        fi

        PTHREAD_LIBS=""
        PTHREAD_CFLAGS=""
done
fi

# Various other checks:
if test "x$acx_pthread_ok" = xyes; then
        save_LIBS="$LIBS"
        LIBS="$PTHREAD_LIBS $LIBS"
        save_CFLAGS="$CFLAGS"
        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"

        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5
$as_echo_n "checking for joinable pthread attribute... " >&6; }
	attr_name=unknown
	for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
	    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
int
main ()
{
int attr=$attr; return attr;
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  attr_name=$attr; break
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
	done
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $attr_name" >&5
$as_echo "$attr_name" >&6; }
        if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then

cat >>confdefs.h <<_ACEOF
#define PTHREAD_CREATE_JOINABLE $attr_name
_ACEOF

        fi

        { $as_echo "$as_me:${as_lineno-$LINENO}: checking if more special flags are required for pthreads" >&5
$as_echo_n "checking if more special flags are required for pthreads... " >&6; }
        flag=no
        case "${host_cpu}-${host_os}" in
            *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
            *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
        esac
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${flag}" >&5
$as_echo "${flag}" >&6; }
        if test "x$flag" != xno; then
            PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
        fi

        LIBS="$save_LIBS"
        CFLAGS="$save_CFLAGS"
        # More AIX lossage: must compile with xlc_r or cc_r
	if test x"$GCC" != xyes; then
          for ac_prog in xlc_r cc_r
do
  # Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_PTHREAD_CC+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$PTHREAD_CC"; then
  ac_cv_prog_PTHREAD_CC="$PTHREAD_CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_PTHREAD_CC="$ac_prog"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
PTHREAD_CC=$ac_cv_prog_PTHREAD_CC
if test -n "$PTHREAD_CC"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CC" >&5
$as_echo "$PTHREAD_CC" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


  test -n "$PTHREAD_CC" && break
done
test -n "$PTHREAD_CC" || PTHREAD_CC="${CC}"

        else
          PTHREAD_CC=$CC
	fi

	# The next part tries to detect GCC inconsistency with -shared on some
	# architectures and systems. The problem is that in certain
	# configurations, when -shared is specified, GCC "forgets" to
	# internally use various flags which are still necessary.

	#
	# Prepare the flags
	#
	save_CFLAGS="$CFLAGS"
	save_LIBS="$LIBS"
	save_CC="$CC"

	# Try with the flags determined by the earlier checks.
	#
	# -Wl,-z,defs forces link-time symbol resolution, so that the
	# linking checks with -shared actually have any value
	#
	# FIXME: -fPIC is required for -shared on many architectures,
	# so we specify it here, but the right way would probably be to
	# properly detect whether it is actually required.
	CFLAGS="-shared -fPIC -Wl,-z,defs $CFLAGS $PTHREAD_CFLAGS"
	LIBS="$PTHREAD_LIBS $LIBS"
	CC="$PTHREAD_CC"

	# In order not to create several levels of indentation, we test
	# the value of "$done" until we find the cure or run out of ideas.
	done="no"

	# First, make sure the CFLAGS we added are actually accepted by our
	# compiler.  If not (and OS X's ld, for instance, does not accept -z),
	# then we can't do this test.
	if test x"$done" = xno; then
	   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to check for GCC pthread/shared inconsistencies" >&5
$as_echo_n "checking whether to check for GCC pthread/shared inconsistencies... " >&6; }
	   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :

else
  done=yes
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext

	   if test "x$done" = xyes ; then
	      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
	   else
	      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
	   fi
	fi

	if test x"$done" = xno; then
	   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -pthread is sufficient with -shared" >&5
$as_echo_n "checking whether -pthread is sufficient with -shared... " >&6; }
	   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
int
main ()
{
pthread_t th; pthread_join(th, 0);
	      pthread_attr_init(0); pthread_cleanup_push(0, 0);
	      pthread_create(0,0,0,0); pthread_cleanup_pop(0);
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  done=yes
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext

	   if test "x$done" = xyes; then
	      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
	   else
	      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
	   fi
	fi

	#
	# Linux gcc on some architectures such as mips/mipsel forgets
	# about -lpthread
	#
	if test x"$done" = xno; then
	   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lpthread fixes that" >&5
$as_echo_n "checking whether -lpthread fixes that... " >&6; }
	   LIBS="-lpthread $PTHREAD_LIBS $save_LIBS"
	   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
int
main ()
{
pthread_t th; pthread_join(th, 0);
	      pthread_attr_init(0); pthread_cleanup_push(0, 0);
	      pthread_create(0,0,0,0); pthread_cleanup_pop(0);
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  done=yes
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext

	   if test "x$done" = xyes; then
	      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
	      PTHREAD_LIBS="-lpthread $PTHREAD_LIBS"
	   else
	      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
	   fi
	fi
	#
	# FreeBSD 4.10 gcc forgets to use -lc_r instead of -lc
	#
	if test x"$done" = xno; then
	   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc_r fixes that" >&5
$as_echo_n "checking whether -lc_r fixes that... " >&6; }
	   LIBS="-lc_r $PTHREAD_LIBS $save_LIBS"
	   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
int
main ()
{
pthread_t th; pthread_join(th, 0);
	        pthread_attr_init(0); pthread_cleanup_push(0, 0);
	        pthread_create(0,0,0,0); pthread_cleanup_pop(0);
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  done=yes
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext

	   if test "x$done" = xyes; then
	      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
	      PTHREAD_LIBS="-lc_r $PTHREAD_LIBS"
	   else
	      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
	   fi
	fi
	if test x"$done" = xno; then
	   # OK, we have run out of ideas
	   { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Impossible to determine how to use pthreads with shared libraries" >&5
$as_echo "$as_me: WARNING: Impossible to determine how to use pthreads with shared libraries" >&2;}

	   # so it's not safe to assume that we may use pthreads
	   acx_pthread_ok=no
	fi

	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether what we have so far is sufficient with -nostdlib" >&5
$as_echo_n "checking whether what we have so far is sufficient with -nostdlib... " >&6; }
	CFLAGS="-nostdlib $CFLAGS"
	# we need c with nostdlib
	LIBS="$LIBS -lc"
	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
int
main ()
{
pthread_t th; pthread_join(th, 0);
	       pthread_attr_init(0); pthread_cleanup_push(0, 0);
	       pthread_create(0,0,0,0); pthread_cleanup_pop(0);
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  done=yes
else
  done=no
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext

	if test "x$done" = xyes; then
	   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
	else
	   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
	fi

	if test x"$done" = xno; then
	   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lpthread saves the day" >&5
$as_echo_n "checking whether -lpthread saves the day... " >&6; }
	   LIBS="-lpthread $LIBS"
	   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
int
main ()
{
pthread_t th; pthread_join(th, 0);
	       pthread_attr_init(0); pthread_cleanup_push(0, 0);
	       pthread_create(0,0,0,0); pthread_cleanup_pop(0);
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  done=yes
else
  done=no
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext

	   if test "x$done" = xyes; then
	      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
	      PTHREAD_LIBS="$PTHREAD_LIBS -lpthread"
	   else
	      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
	      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Impossible to determine how to use pthreads with shared libraries and -nostdlib" >&5
$as_echo "$as_me: WARNING: Impossible to determine how to use pthreads with shared libraries and -nostdlib" >&2;}
	   fi
	fi

	CFLAGS="$save_CFLAGS"
	LIBS="$save_LIBS"
	CC="$save_CC"
else
        PTHREAD_CC="$CC"
fi





# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test x"$acx_pthread_ok" = xyes; then

$as_echo "#define HAVE_PTHREAD 1" >>confdefs.h

        :
else
        acx_pthread_ok=no

fi
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu



# Find out what namespace 'normal' STL code lives in
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler implements namespaces" >&5
$as_echo_n "checking whether the compiler implements namespaces... " >&6; }
if test "${ac_cv_cxx_namespaces+set}" = set; then :
  $as_echo_n "(cached) " >&6
else

                  ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu

                  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
namespace Outer {
                                    namespace Inner { int i = 0; }}
int
main ()
{
using namespace Outer::Inner; return i;
  ;
  return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
  ac_cv_cxx_namespaces=yes
else
  ac_cv_cxx_namespaces=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
                  ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_namespaces" >&5
$as_echo "$ac_cv_cxx_namespaces" >&6; }
  if test "$ac_cv_cxx_namespaces" = yes; then

$as_echo "#define HAVE_NAMESPACES 1" >>confdefs.h

  fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking what namespace STL code is in" >&5
$as_echo_n "checking what namespace STL code is in... " >&6; }
if test "${ac_cv_cxx_stl_namespace+set}" = set; then :
  $as_echo_n "(cached) " >&6
else


      ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu

      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
int
main ()
{
vector t; return 0;
  ;
  return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
  ac_cv_cxx_stl_namespace=none
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include 
int
main ()
{
std::vector t; return 0;
  ;
  return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
  ac_cv_cxx_stl_namespace=std
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
      ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_stl_namespace" >&5
$as_echo "$ac_cv_cxx_stl_namespace" >&6; }
   if test "$ac_cv_cxx_stl_namespace" = none; then

$as_echo "#define STL_NAMESPACE /**/" >>confdefs.h

   fi
   if test "$ac_cv_cxx_stl_namespace" = std; then

$as_echo "#define STL_NAMESPACE std" >>confdefs.h

   fi


# Figure out where libc has program_invocation_name
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for program_invocation_name" >&5
$as_echo_n "checking for program_invocation_name... " >&6; }
if test "${ac_cv_have_program_invocation_name+set}" = set; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
extern char* program_invocation_name;
int
main ()
{
return *program_invocation_name;
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  ac_cv_have_program_invocation_name=yes
else
  ac_cv_have_program_invocation_name=no
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_program_invocation_name" >&5
$as_echo "$ac_cv_have_program_invocation_name" >&6; }
   if test "$ac_cv_have_program_invocation_name" = "yes"; then

$as_echo "#define HAVE_PROGRAM_INVOCATION_NAME 1" >>confdefs.h

   fi


# Make the install prefix available, to figure out where to look for pprof
ac_cv_install_prefix="$prefix";
   if test x"$ac_cv_install_prefix" = x"NONE" ; then
     ac_cv_install_prefix="$ac_default_prefix";
   fi

cat >>confdefs.h <<_ACEOF
#define INSTALL_PREFIX "$ac_cv_install_prefix"
_ACEOF



# For windows, this has a non-trivial value (__declspec(export)), but any
# system that uses configure wants this to be the empty string.

$as_echo "#define PERFTOOLS_DLL_DECL /**/" >>confdefs.h


# In theory, config.h files shouldn't need a header guard, but we do,
# because we (maybe) #include windows/mingw.h from within config.h,
# and it #includes other .h files.  These all have header guards, so
# the end result is if config.h is #included twice, its #undefs get
# evaluated twice, but all the ones in mingw.h/etc only get evaluated
# once, potentially causing trouble.  c.f.
#   http://code.google.com/p/google-perftools/issues/detail?id=246


# MinGW uses autoconf, but also needs the windows shim routines
# (since it doesn't have its own support for, say, pthreads).
# This requires us to #include a special header file, and also to
# link in some windows versions of .o's instead of the unix versions.



if expr $host : '.*-mingw' >/dev/null 2>&1; then
  MINGW_TRUE=
  MINGW_FALSE='#'
else
  MINGW_TRUE='#'
  MINGW_FALSE=
fi


# Redhat 7 (and below?) has sys/ucontext.h, but if you try to #include
# it directly, the compiler gets upset.  So we pretend we don't have
# it.
if cat /etc/redhat-release 2>/dev/null | grep "Red Hat Linux release 7" >/dev/null 2>&1; then

$as_echo "#define HAVE_SYS_UCONTEXT_H 0" >>confdefs.h

fi

# Export the --enable flags we set above.  We do this at the end so
# other configure rules can enable or disable targets based on what
# they find.


if test "$enable_cpu_profiler" = yes; then
  WITH_CPU_PROFILER_TRUE=
  WITH_CPU_PROFILER_FALSE='#'
else
  WITH_CPU_PROFILER_TRUE='#'
  WITH_CPU_PROFILER_FALSE=
fi



if test "$enable_heap_profiler" = yes; then
  WITH_HEAP_PROFILER_TRUE=
  WITH_HEAP_PROFILER_FALSE='#'
else
  WITH_HEAP_PROFILER_TRUE='#'
  WITH_HEAP_PROFILER_FALSE=
fi



if test "$enable_heap_checker" = yes; then
  WITH_HEAP_CHECKER_TRUE=
  WITH_HEAP_CHECKER_FALSE='#'
else
  WITH_HEAP_CHECKER_TRUE='#'
  WITH_HEAP_CHECKER_FALSE=
fi



if test "$enable_debugalloc" = yes; then
  WITH_DEBUGALLOC_TRUE=
  WITH_DEBUGALLOC_FALSE='#'
else
  WITH_DEBUGALLOC_TRUE='#'
  WITH_DEBUGALLOC_FALSE=
fi

# We make tcmalloc.so if either heap-profiler or heap-checker is asked for.


if test "$enable_heap_profiler" = yes -o \
                    "$enable_heap_checker" = yes; then
  WITH_HEAP_PROFILER_OR_CHECKER_TRUE=
  WITH_HEAP_PROFILER_OR_CHECKER_FALSE='#'
else
  WITH_HEAP_PROFILER_OR_CHECKER_TRUE='#'
  WITH_HEAP_PROFILER_OR_CHECKER_FALSE=
fi

# If we don't use any profilers, we don't need stack traces (or pprof)


if test "$enable_cpu_profiler" = yes -o \
                                      "$enable_heap_profiler" = yes -o \
                                      "$enable_heap_checker" = yes; then
  WITH_STACK_TRACE_TRUE=
  WITH_STACK_TRACE_FALSE='#'
else
  WITH_STACK_TRACE_TRUE='#'
  WITH_STACK_TRACE_FALSE=
fi


# Write generated configuration file
ac_config_files="$ac_config_files Makefile src/google/tcmalloc.h"

cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
# scripts and configure runs, see configure's option --config-cache.
# It is not useful on other systems.  If it contains results you don't
# want to keep, you may remove or edit it.
#
# config.status only pays attention to the cache file if you give it
# the --recheck option to rerun configure.
#
# `ac_cv_env_foo' variables (set or unset) will be overridden when
# loading this file, other *unset* `ac_cv_foo' will be assigned the
# following values.

_ACEOF

# The following way of writing the cache mishandles newlines in values,
# but we know of no workaround that is simple, portable, and efficient.
# So, we kill variables containing newlines.
# Ultrix sh set writes to stderr and can't be redirected directly,
# and sets the high bit in the cache file unless we assign to the vars.
(
  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
    eval ac_val=\$$ac_var
    case $ac_val in #(
    *${as_nl}*)
      case $ac_var in #(
      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
      esac
      case $ac_var in #(
      _ | IFS | as_nl) ;; #(
      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
      *) { eval $ac_var=; unset $ac_var;} ;;
      esac ;;
    esac
  done

  (set) 2>&1 |
    case $as_nl`(ac_space=' '; set) 2>&1` in #(
    *${as_nl}ac_space=\ *)
      # `set' does not quote correctly, so add quotes: double-quote
      # substitution turns \\\\ into \\, and sed turns \\ into \.
      sed -n \
	"s/'/'\\\\''/g;
	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
      ;; #(
    *)
      # `set' quotes correctly as required by POSIX, so do not add quotes.
      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
      ;;
    esac |
    sort
) |
  sed '
     /^ac_cv_env_/b end
     t clear
     :clear
     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
     t end
     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
     :end' >>confcache
if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
  if test -w "$cache_file"; then
    test "x$cache_file" != "x/dev/null" &&
      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
$as_echo "$as_me: updating cache $cache_file" >&6;}
    cat confcache >$cache_file
  else
    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
  fi
fi
rm -f confcache

test "x$prefix" = xNONE && prefix=$ac_default_prefix
# Let make expand exec_prefix.
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'

DEFS=-DHAVE_CONFIG_H

ac_libobjs=
ac_ltlibobjs=
for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
  # 1. Remove the extension, and $U if already installed.
  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
  #    will be set to the directory where LIBOBJS objects are built.
  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
done
LIBOBJS=$ac_libobjs

LTLIBOBJS=$ac_ltlibobjs


if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
  as_fn_error "conditional \"AMDEP\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
  as_fn_error "conditional \"am__fastdepCC\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then
  as_fn_error "conditional \"am__fastdepCXX\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${GCC_TRUE}" && test -z "${GCC_FALSE}"; then
  as_fn_error "conditional \"GCC\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${HAVE_OBJCOPY_WEAKEN_TRUE}" && test -z "${HAVE_OBJCOPY_WEAKEN_FALSE}"; then
  as_fn_error "conditional \"HAVE_OBJCOPY_WEAKEN\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then
  as_fn_error "conditional \"am__fastdepCXX\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${USE_LIBTOOL_TRUE}" && test -z "${USE_LIBTOOL_FALSE}"; then
  as_fn_error "conditional \"USE_LIBTOOL\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${ENABLE_STATIC_TRUE}" && test -z "${ENABLE_STATIC_FALSE}"; then
  as_fn_error "conditional \"ENABLE_STATIC\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${ENABLE_FRAME_POINTERS_TRUE}" && test -z "${ENABLE_FRAME_POINTERS_FALSE}"; then
  as_fn_error "conditional \"ENABLE_FRAME_POINTERS\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${X86_64_AND_NO_FP_BY_DEFAULT_TRUE}" && test -z "${X86_64_AND_NO_FP_BY_DEFAULT_FALSE}"; then
  as_fn_error "conditional \"X86_64_AND_NO_FP_BY_DEFAULT\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${MINGW_TRUE}" && test -z "${MINGW_FALSE}"; then
  as_fn_error "conditional \"MINGW\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${WITH_CPU_PROFILER_TRUE}" && test -z "${WITH_CPU_PROFILER_FALSE}"; then
  as_fn_error "conditional \"WITH_CPU_PROFILER\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${WITH_HEAP_PROFILER_TRUE}" && test -z "${WITH_HEAP_PROFILER_FALSE}"; then
  as_fn_error "conditional \"WITH_HEAP_PROFILER\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${WITH_HEAP_CHECKER_TRUE}" && test -z "${WITH_HEAP_CHECKER_FALSE}"; then
  as_fn_error "conditional \"WITH_HEAP_CHECKER\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${WITH_DEBUGALLOC_TRUE}" && test -z "${WITH_DEBUGALLOC_FALSE}"; then
  as_fn_error "conditional \"WITH_DEBUGALLOC\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${WITH_HEAP_PROFILER_OR_CHECKER_TRUE}" && test -z "${WITH_HEAP_PROFILER_OR_CHECKER_FALSE}"; then
  as_fn_error "conditional \"WITH_HEAP_PROFILER_OR_CHECKER\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${WITH_STACK_TRACE_TRUE}" && test -z "${WITH_STACK_TRACE_FALSE}"; then
  as_fn_error "conditional \"WITH_STACK_TRACE\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi

: ${CONFIG_STATUS=./config.status}
ac_write_fail=0
ac_clean_files_save=$ac_clean_files
ac_clean_files="$ac_clean_files $CONFIG_STATUS"
{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
as_write_fail=0
cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
#! $SHELL
# Generated by $as_me.
# Run this file to recreate the current configuration.
# Compiler output produced by configure, useful for debugging
# configure, is in config.log if it exists.

debug=false
ac_cs_recheck=false
ac_cs_silent=false

SHELL=\${CONFIG_SHELL-$SHELL}
export SHELL
_ASEOF
cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
## -------------------- ##
## M4sh Initialization. ##
## -------------------- ##

# Be more Bourne compatible
DUALCASE=1; export DUALCASE # for MKS sh
if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
  emulate sh
  NULLCMD=:
  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
  # is contrary to our usage.  Disable this feature.
  alias -g '${1+"$@"}'='"$@"'
  setopt NO_GLOB_SUBST
else
  case `(set -o) 2>/dev/null` in #(
  *posix*) :
    set -o posix ;; #(
  *) :
     ;;
esac
fi


as_nl='
'
export as_nl
# Printing a long string crashes Solaris 7 /usr/bin/printf.
as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
# Prefer a ksh shell builtin over an external printf program on Solaris,
# but without wasting forks for bash or zsh.
if test -z "$BASH_VERSION$ZSH_VERSION" \
    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
  as_echo='print -r --'
  as_echo_n='print -rn --'
elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
  as_echo='printf %s\n'
  as_echo_n='printf %s'
else
  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
    as_echo_n='/usr/ucb/echo -n'
  else
    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
    as_echo_n_body='eval
      arg=$1;
      case $arg in #(
      *"$as_nl"*)
	expr "X$arg" : "X\\(.*\\)$as_nl";
	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
      esac;
      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
    '
    export as_echo_n_body
    as_echo_n='sh -c $as_echo_n_body as_echo'
  fi
  export as_echo_body
  as_echo='sh -c $as_echo_body as_echo'
fi

# The user is always right.
if test "${PATH_SEPARATOR+set}" != set; then
  PATH_SEPARATOR=:
  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
      PATH_SEPARATOR=';'
  }
fi


# IFS
# We need space, tab and new line, in precisely that order.  Quoting is
# there to prevent editors from complaining about space-tab.
# (If _AS_PATH_WALK were called with IFS unset, it would disable word
# splitting by setting IFS to empty value.)
IFS=" ""	$as_nl"

# Find who we are.  Look in the path if we contain no directory separator.
case $0 in #((
  *[\\/]* ) as_myself=$0 ;;
  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
  done
IFS=$as_save_IFS

     ;;
esac
# We did not find ourselves, most probably we were run as `sh COMMAND'
# in which case we are not to be found in the path.
if test "x$as_myself" = x; then
  as_myself=$0
fi
if test ! -f "$as_myself"; then
  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
  exit 1
fi

# Unset variables that we do not need and which cause bugs (e.g. in
# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
# suppresses any "Segmentation fault" message there.  '((' could
# trigger a bug in pdksh 5.2.14.
for as_var in BASH_ENV ENV MAIL MAILPATH
do eval test x\${$as_var+set} = xset \
  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
done
PS1='$ '
PS2='> '
PS4='+ '

# NLS nuisances.
LC_ALL=C
export LC_ALL
LANGUAGE=C
export LANGUAGE

# CDPATH.
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH


# as_fn_error ERROR [LINENO LOG_FD]
# ---------------------------------
# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
# script with status $?, using 1 if that was 0.
as_fn_error ()
{
  as_status=$?; test $as_status -eq 0 && as_status=1
  if test "$3"; then
    as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
    $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3
  fi
  $as_echo "$as_me: error: $1" >&2
  as_fn_exit $as_status
} # as_fn_error


# as_fn_set_status STATUS
# -----------------------
# Set $? to STATUS, without forking.
as_fn_set_status ()
{
  return $1
} # as_fn_set_status

# as_fn_exit STATUS
# -----------------
# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
as_fn_exit ()
{
  set +e
  as_fn_set_status $1
  exit $1
} # as_fn_exit

# as_fn_unset VAR
# ---------------
# Portably unset VAR.
as_fn_unset ()
{
  { eval $1=; unset $1;}
}
as_unset=as_fn_unset
# as_fn_append VAR VALUE
# ----------------------
# Append the text in VALUE to the end of the definition contained in VAR. Take
# advantage of any shell optimizations that allow amortized linear growth over
# repeated appends, instead of the typical quadratic growth present in naive
# implementations.
if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
  eval 'as_fn_append ()
  {
    eval $1+=\$2
  }'
else
  as_fn_append ()
  {
    eval $1=\$$1\$2
  }
fi # as_fn_append

# as_fn_arith ARG...
# ------------------
# Perform arithmetic evaluation on the ARGs, and store the result in the
# global $as_val. Take advantage of shells that can avoid forks. The arguments
# must be portable across $(()) and expr.
if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
  eval 'as_fn_arith ()
  {
    as_val=$(( $* ))
  }'
else
  as_fn_arith ()
  {
    as_val=`expr "$@" || test $? -eq 1`
  }
fi # as_fn_arith


if expr a : '\(a\)' >/dev/null 2>&1 &&
   test "X`expr 00001 : '.*\(...\)'`" = X001; then
  as_expr=expr
else
  as_expr=false
fi

if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
  as_basename=basename
else
  as_basename=false
fi

if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
  as_dirname=dirname
else
  as_dirname=false
fi

as_me=`$as_basename -- "$0" ||
$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
	 X"$0" : 'X\(//\)$' \| \
	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X/"$0" |
    sed '/^.*\/\([^/][^/]*\)\/*$/{
	    s//\1/
	    q
	  }
	  /^X\/\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\/\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`

# Avoid depending upon Character Ranges.
as_cr_letters='abcdefghijklmnopqrstuvwxyz'
as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
as_cr_Letters=$as_cr_letters$as_cr_LETTERS
as_cr_digits='0123456789'
as_cr_alnum=$as_cr_Letters$as_cr_digits

ECHO_C= ECHO_N= ECHO_T=
case `echo -n x` in #(((((
-n*)
  case `echo 'xy\c'` in
  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
  xy)  ECHO_C='\c';;
  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
       ECHO_T='	';;
  esac;;
*)
  ECHO_N='-n';;
esac

rm -f conf$$ conf$$.exe conf$$.file
if test -d conf$$.dir; then
  rm -f conf$$.dir/conf$$.file
else
  rm -f conf$$.dir
  mkdir conf$$.dir 2>/dev/null
fi
if (echo >conf$$.file) 2>/dev/null; then
  if ln -s conf$$.file conf$$ 2>/dev/null; then
    as_ln_s='ln -s'
    # ... but there are two gotchas:
    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
    # In both cases, we have to default to `cp -p'.
    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
      as_ln_s='cp -p'
  elif ln conf$$.file conf$$ 2>/dev/null; then
    as_ln_s=ln
  else
    as_ln_s='cp -p'
  fi
else
  as_ln_s='cp -p'
fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null


# as_fn_mkdir_p
# -------------
# Create "$as_dir" as a directory, including parents if necessary.
as_fn_mkdir_p ()
{

  case $as_dir in #(
  -*) as_dir=./$as_dir;;
  esac
  test -d "$as_dir" || eval $as_mkdir_p || {
    as_dirs=
    while :; do
      case $as_dir in #(
      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
      *) as_qdir=$as_dir;;
      esac
      as_dirs="'$as_qdir' $as_dirs"
      as_dir=`$as_dirname -- "$as_dir" ||
$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
	 X"$as_dir" : 'X\(//\)[^/]' \| \
	 X"$as_dir" : 'X\(//\)$' \| \
	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$as_dir" |
    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)[^/].*/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`
      test -d "$as_dir" && break
    done
    test -z "$as_dirs" || eval "mkdir $as_dirs"
  } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir"


} # as_fn_mkdir_p
if mkdir -p . 2>/dev/null; then
  as_mkdir_p='mkdir -p "$as_dir"'
else
  test -d ./-p && rmdir ./-p
  as_mkdir_p=false
fi

if test -x / >/dev/null 2>&1; then
  as_test_x='test -x'
else
  if ls -dL / >/dev/null 2>&1; then
    as_ls_L_option=L
  else
    as_ls_L_option=
  fi
  as_test_x='
    eval sh -c '\''
      if test -d "$1"; then
	test -d "$1/.";
      else
	case $1 in #(
	-*)set "./$1";;
	esac;
	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
	???[sx]*):;;*)false;;esac;fi
    '\'' sh
  '
fi
as_executable_p=$as_test_x

# Sed expression to map a string onto a valid CPP name.
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"

# Sed expression to map a string onto a valid variable name.
as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"


exec 6>&1
## ----------------------------------- ##
## Main body of $CONFIG_STATUS script. ##
## ----------------------------------- ##
_ASEOF
test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# Save the log message, to keep $0 and so on meaningful, and to
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by google-perftools $as_me 1.7, which was
generated by GNU Autoconf 2.65.  Invocation command line was

  CONFIG_FILES    = $CONFIG_FILES
  CONFIG_HEADERS  = $CONFIG_HEADERS
  CONFIG_LINKS    = $CONFIG_LINKS
  CONFIG_COMMANDS = $CONFIG_COMMANDS
  $ $0 $@

on `(hostname || uname -n) 2>/dev/null | sed 1q`
"

_ACEOF

case $ac_config_files in *"
"*) set x $ac_config_files; shift; ac_config_files=$*;;
esac

case $ac_config_headers in *"
"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
esac


cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
# Files that config.status was made for.
config_files="$ac_config_files"
config_headers="$ac_config_headers"
config_commands="$ac_config_commands"

_ACEOF

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
ac_cs_usage="\
\`$as_me' instantiates files and other configuration actions
from templates according to the current configuration.  Unless the files
and actions are specified as TAGs, all are instantiated by default.

Usage: $0 [OPTION]... [TAG]...

  -h, --help       print this help, then exit
  -V, --version    print version number and configuration settings, then exit
      --config     print configuration, then exit
  -q, --quiet, --silent
                   do not print progress messages
  -d, --debug      don't remove temporary files
      --recheck    update $as_me by reconfiguring in the same conditions
      --file=FILE[:TEMPLATE]
                   instantiate the configuration file FILE
      --header=FILE[:TEMPLATE]
                   instantiate the configuration header FILE

Configuration files:
$config_files

Configuration headers:
$config_headers

Configuration commands:
$config_commands

Report bugs to ."

_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
google-perftools config.status 1.7
configured by $0, generated by GNU Autoconf 2.65,
  with options \\"\$ac_cs_config\\"

Copyright (C) 2009 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."

ac_pwd='$ac_pwd'
srcdir='$srcdir'
INSTALL='$INSTALL'
AWK='$AWK'
test -n "\$AWK" || AWK=awk
_ACEOF

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# The default lists apply if the user does not specify any file.
ac_need_defaults=:
while test $# != 0
do
  case $1 in
  --*=*)
    ac_option=`expr "X$1" : 'X\([^=]*\)='`
    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
    ac_shift=:
    ;;
  *)
    ac_option=$1
    ac_optarg=$2
    ac_shift=shift
    ;;
  esac

  case $ac_option in
  # Handling of the options.
  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
    ac_cs_recheck=: ;;
  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
    $as_echo "$ac_cs_version"; exit ;;
  --config | --confi | --conf | --con | --co | --c )
    $as_echo "$ac_cs_config"; exit ;;
  --debug | --debu | --deb | --de | --d | -d )
    debug=: ;;
  --file | --fil | --fi | --f )
    $ac_shift
    case $ac_optarg in
    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
    esac
    as_fn_append CONFIG_FILES " '$ac_optarg'"
    ac_need_defaults=false;;
  --header | --heade | --head | --hea )
    $ac_shift
    case $ac_optarg in
    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
    esac
    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
    ac_need_defaults=false;;
  --he | --h)
    # Conflict between --help and --header
    as_fn_error "ambiguous option: \`$1'
Try \`$0 --help' for more information.";;
  --help | --hel | -h )
    $as_echo "$ac_cs_usage"; exit ;;
  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
  | -silent | --silent | --silen | --sile | --sil | --si | --s)
    ac_cs_silent=: ;;

  # This is an error.
  -*) as_fn_error "unrecognized option: \`$1'
Try \`$0 --help' for more information." ;;

  *) as_fn_append ac_config_targets " $1"
     ac_need_defaults=false ;;

  esac
  shift
done

ac_configure_extra_args=

if $ac_cs_silent; then
  exec 6>/dev/null
  ac_configure_extra_args="$ac_configure_extra_args --silent"
fi

_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
if \$ac_cs_recheck; then
  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
  shift
  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
  CONFIG_SHELL='$SHELL'
  export CONFIG_SHELL
  exec "\$@"
fi

_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
exec 5>>config.log
{
  echo
  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
## Running $as_me. ##
_ASBOX
  $as_echo "$ac_log"
} >&5

_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
#
# INIT-COMMANDS
#
AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"


# The HP-UX ksh and POSIX shell print the target directory to stdout
# if CDPATH is set.
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH

sed_quote_subst='$sed_quote_subst'
double_quote_subst='$double_quote_subst'
delay_variable_subst='$delay_variable_subst'
enable_fast_install='`$ECHO "X$enable_fast_install" | $Xsed -e "$delay_single_quote_subst"`'
macro_version='`$ECHO "X$macro_version" | $Xsed -e "$delay_single_quote_subst"`'
macro_revision='`$ECHO "X$macro_revision" | $Xsed -e "$delay_single_quote_subst"`'
enable_shared='`$ECHO "X$enable_shared" | $Xsed -e "$delay_single_quote_subst"`'
enable_static='`$ECHO "X$enable_static" | $Xsed -e "$delay_single_quote_subst"`'
pic_mode='`$ECHO "X$pic_mode" | $Xsed -e "$delay_single_quote_subst"`'
host_alias='`$ECHO "X$host_alias" | $Xsed -e "$delay_single_quote_subst"`'
host='`$ECHO "X$host" | $Xsed -e "$delay_single_quote_subst"`'
host_os='`$ECHO "X$host_os" | $Xsed -e "$delay_single_quote_subst"`'
build_alias='`$ECHO "X$build_alias" | $Xsed -e "$delay_single_quote_subst"`'
build='`$ECHO "X$build" | $Xsed -e "$delay_single_quote_subst"`'
build_os='`$ECHO "X$build_os" | $Xsed -e "$delay_single_quote_subst"`'
SED='`$ECHO "X$SED" | $Xsed -e "$delay_single_quote_subst"`'
Xsed='`$ECHO "X$Xsed" | $Xsed -e "$delay_single_quote_subst"`'
GREP='`$ECHO "X$GREP" | $Xsed -e "$delay_single_quote_subst"`'
EGREP='`$ECHO "X$EGREP" | $Xsed -e "$delay_single_quote_subst"`'
FGREP='`$ECHO "X$FGREP" | $Xsed -e "$delay_single_quote_subst"`'
LD='`$ECHO "X$LD" | $Xsed -e "$delay_single_quote_subst"`'
NM='`$ECHO "X$NM" | $Xsed -e "$delay_single_quote_subst"`'
LN_S='`$ECHO "X$LN_S" | $Xsed -e "$delay_single_quote_subst"`'
max_cmd_len='`$ECHO "X$max_cmd_len" | $Xsed -e "$delay_single_quote_subst"`'
ac_objext='`$ECHO "X$ac_objext" | $Xsed -e "$delay_single_quote_subst"`'
exeext='`$ECHO "X$exeext" | $Xsed -e "$delay_single_quote_subst"`'
lt_unset='`$ECHO "X$lt_unset" | $Xsed -e "$delay_single_quote_subst"`'
lt_SP2NL='`$ECHO "X$lt_SP2NL" | $Xsed -e "$delay_single_quote_subst"`'
lt_NL2SP='`$ECHO "X$lt_NL2SP" | $Xsed -e "$delay_single_quote_subst"`'
reload_flag='`$ECHO "X$reload_flag" | $Xsed -e "$delay_single_quote_subst"`'
reload_cmds='`$ECHO "X$reload_cmds" | $Xsed -e "$delay_single_quote_subst"`'
OBJDUMP='`$ECHO "X$OBJDUMP" | $Xsed -e "$delay_single_quote_subst"`'
deplibs_check_method='`$ECHO "X$deplibs_check_method" | $Xsed -e "$delay_single_quote_subst"`'
file_magic_cmd='`$ECHO "X$file_magic_cmd" | $Xsed -e "$delay_single_quote_subst"`'
AR='`$ECHO "X$AR" | $Xsed -e "$delay_single_quote_subst"`'
AR_FLAGS='`$ECHO "X$AR_FLAGS" | $Xsed -e "$delay_single_quote_subst"`'
STRIP='`$ECHO "X$STRIP" | $Xsed -e "$delay_single_quote_subst"`'
RANLIB='`$ECHO "X$RANLIB" | $Xsed -e "$delay_single_quote_subst"`'
old_postinstall_cmds='`$ECHO "X$old_postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
old_postuninstall_cmds='`$ECHO "X$old_postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
old_archive_cmds='`$ECHO "X$old_archive_cmds" | $Xsed -e "$delay_single_quote_subst"`'
CC='`$ECHO "X$CC" | $Xsed -e "$delay_single_quote_subst"`'
CFLAGS='`$ECHO "X$CFLAGS" | $Xsed -e "$delay_single_quote_subst"`'
compiler='`$ECHO "X$compiler" | $Xsed -e "$delay_single_quote_subst"`'
GCC='`$ECHO "X$GCC" | $Xsed -e "$delay_single_quote_subst"`'
lt_cv_sys_global_symbol_pipe='`$ECHO "X$lt_cv_sys_global_symbol_pipe" | $Xsed -e "$delay_single_quote_subst"`'
lt_cv_sys_global_symbol_to_cdecl='`$ECHO "X$lt_cv_sys_global_symbol_to_cdecl" | $Xsed -e "$delay_single_quote_subst"`'
lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address" | $Xsed -e "$delay_single_quote_subst"`'
lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`'
objdir='`$ECHO "X$objdir" | $Xsed -e "$delay_single_quote_subst"`'
SHELL='`$ECHO "X$SHELL" | $Xsed -e "$delay_single_quote_subst"`'
ECHO='`$ECHO "X$ECHO" | $Xsed -e "$delay_single_quote_subst"`'
MAGIC_CMD='`$ECHO "X$MAGIC_CMD" | $Xsed -e "$delay_single_quote_subst"`'
lt_prog_compiler_no_builtin_flag='`$ECHO "X$lt_prog_compiler_no_builtin_flag" | $Xsed -e "$delay_single_quote_subst"`'
lt_prog_compiler_wl='`$ECHO "X$lt_prog_compiler_wl" | $Xsed -e "$delay_single_quote_subst"`'
lt_prog_compiler_pic='`$ECHO "X$lt_prog_compiler_pic" | $Xsed -e "$delay_single_quote_subst"`'
lt_prog_compiler_static='`$ECHO "X$lt_prog_compiler_static" | $Xsed -e "$delay_single_quote_subst"`'
lt_cv_prog_compiler_c_o='`$ECHO "X$lt_cv_prog_compiler_c_o" | $Xsed -e "$delay_single_quote_subst"`'
need_locks='`$ECHO "X$need_locks" | $Xsed -e "$delay_single_quote_subst"`'
DSYMUTIL='`$ECHO "X$DSYMUTIL" | $Xsed -e "$delay_single_quote_subst"`'
NMEDIT='`$ECHO "X$NMEDIT" | $Xsed -e "$delay_single_quote_subst"`'
LIPO='`$ECHO "X$LIPO" | $Xsed -e "$delay_single_quote_subst"`'
OTOOL='`$ECHO "X$OTOOL" | $Xsed -e "$delay_single_quote_subst"`'
OTOOL64='`$ECHO "X$OTOOL64" | $Xsed -e "$delay_single_quote_subst"`'
libext='`$ECHO "X$libext" | $Xsed -e "$delay_single_quote_subst"`'
shrext_cmds='`$ECHO "X$shrext_cmds" | $Xsed -e "$delay_single_quote_subst"`'
extract_expsyms_cmds='`$ECHO "X$extract_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`'
archive_cmds_need_lc='`$ECHO "X$archive_cmds_need_lc" | $Xsed -e "$delay_single_quote_subst"`'
enable_shared_with_static_runtimes='`$ECHO "X$enable_shared_with_static_runtimes" | $Xsed -e "$delay_single_quote_subst"`'
export_dynamic_flag_spec='`$ECHO "X$export_dynamic_flag_spec" | $Xsed -e "$delay_single_quote_subst"`'
whole_archive_flag_spec='`$ECHO "X$whole_archive_flag_spec" | $Xsed -e "$delay_single_quote_subst"`'
compiler_needs_object='`$ECHO "X$compiler_needs_object" | $Xsed -e "$delay_single_quote_subst"`'
old_archive_from_new_cmds='`$ECHO "X$old_archive_from_new_cmds" | $Xsed -e "$delay_single_quote_subst"`'
old_archive_from_expsyms_cmds='`$ECHO "X$old_archive_from_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`'
archive_cmds='`$ECHO "X$archive_cmds" | $Xsed -e "$delay_single_quote_subst"`'
archive_expsym_cmds='`$ECHO "X$archive_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`'
module_cmds='`$ECHO "X$module_cmds" | $Xsed -e "$delay_single_quote_subst"`'
module_expsym_cmds='`$ECHO "X$module_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`'
with_gnu_ld='`$ECHO "X$with_gnu_ld" | $Xsed -e "$delay_single_quote_subst"`'
allow_undefined_flag='`$ECHO "X$allow_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`'
no_undefined_flag='`$ECHO "X$no_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`'
hardcode_libdir_flag_spec='`$ECHO "X$hardcode_libdir_flag_spec" | $Xsed -e "$delay_single_quote_subst"`'
hardcode_libdir_flag_spec_ld='`$ECHO "X$hardcode_libdir_flag_spec_ld" | $Xsed -e "$delay_single_quote_subst"`'
hardcode_libdir_separator='`$ECHO "X$hardcode_libdir_separator" | $Xsed -e "$delay_single_quote_subst"`'
hardcode_direct='`$ECHO "X$hardcode_direct" | $Xsed -e "$delay_single_quote_subst"`'
hardcode_direct_absolute='`$ECHO "X$hardcode_direct_absolute" | $Xsed -e "$delay_single_quote_subst"`'
hardcode_minus_L='`$ECHO "X$hardcode_minus_L" | $Xsed -e "$delay_single_quote_subst"`'
hardcode_shlibpath_var='`$ECHO "X$hardcode_shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`'
hardcode_automatic='`$ECHO "X$hardcode_automatic" | $Xsed -e "$delay_single_quote_subst"`'
inherit_rpath='`$ECHO "X$inherit_rpath" | $Xsed -e "$delay_single_quote_subst"`'
link_all_deplibs='`$ECHO "X$link_all_deplibs" | $Xsed -e "$delay_single_quote_subst"`'
fix_srcfile_path='`$ECHO "X$fix_srcfile_path" | $Xsed -e "$delay_single_quote_subst"`'
always_export_symbols='`$ECHO "X$always_export_symbols" | $Xsed -e "$delay_single_quote_subst"`'
export_symbols_cmds='`$ECHO "X$export_symbols_cmds" | $Xsed -e "$delay_single_quote_subst"`'
exclude_expsyms='`$ECHO "X$exclude_expsyms" | $Xsed -e "$delay_single_quote_subst"`'
include_expsyms='`$ECHO "X$include_expsyms" | $Xsed -e "$delay_single_quote_subst"`'
prelink_cmds='`$ECHO "X$prelink_cmds" | $Xsed -e "$delay_single_quote_subst"`'
file_list_spec='`$ECHO "X$file_list_spec" | $Xsed -e "$delay_single_quote_subst"`'
variables_saved_for_relink='`$ECHO "X$variables_saved_for_relink" | $Xsed -e "$delay_single_quote_subst"`'
need_lib_prefix='`$ECHO "X$need_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`'
need_version='`$ECHO "X$need_version" | $Xsed -e "$delay_single_quote_subst"`'
version_type='`$ECHO "X$version_type" | $Xsed -e "$delay_single_quote_subst"`'
runpath_var='`$ECHO "X$runpath_var" | $Xsed -e "$delay_single_quote_subst"`'
shlibpath_var='`$ECHO "X$shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`'
shlibpath_overrides_runpath='`$ECHO "X$shlibpath_overrides_runpath" | $Xsed -e "$delay_single_quote_subst"`'
libname_spec='`$ECHO "X$libname_spec" | $Xsed -e "$delay_single_quote_subst"`'
library_names_spec='`$ECHO "X$library_names_spec" | $Xsed -e "$delay_single_quote_subst"`'
soname_spec='`$ECHO "X$soname_spec" | $Xsed -e "$delay_single_quote_subst"`'
postinstall_cmds='`$ECHO "X$postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
postuninstall_cmds='`$ECHO "X$postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
finish_cmds='`$ECHO "X$finish_cmds" | $Xsed -e "$delay_single_quote_subst"`'
finish_eval='`$ECHO "X$finish_eval" | $Xsed -e "$delay_single_quote_subst"`'
hardcode_into_libs='`$ECHO "X$hardcode_into_libs" | $Xsed -e "$delay_single_quote_subst"`'
sys_lib_search_path_spec='`$ECHO "X$sys_lib_search_path_spec" | $Xsed -e "$delay_single_quote_subst"`'
sys_lib_dlsearch_path_spec='`$ECHO "X$sys_lib_dlsearch_path_spec" | $Xsed -e "$delay_single_quote_subst"`'
hardcode_action='`$ECHO "X$hardcode_action" | $Xsed -e "$delay_single_quote_subst"`'
enable_dlopen='`$ECHO "X$enable_dlopen" | $Xsed -e "$delay_single_quote_subst"`'
enable_dlopen_self='`$ECHO "X$enable_dlopen_self" | $Xsed -e "$delay_single_quote_subst"`'
enable_dlopen_self_static='`$ECHO "X$enable_dlopen_self_static" | $Xsed -e "$delay_single_quote_subst"`'
old_striplib='`$ECHO "X$old_striplib" | $Xsed -e "$delay_single_quote_subst"`'
striplib='`$ECHO "X$striplib" | $Xsed -e "$delay_single_quote_subst"`'
compiler_lib_search_dirs='`$ECHO "X$compiler_lib_search_dirs" | $Xsed -e "$delay_single_quote_subst"`'
predep_objects='`$ECHO "X$predep_objects" | $Xsed -e "$delay_single_quote_subst"`'
postdep_objects='`$ECHO "X$postdep_objects" | $Xsed -e "$delay_single_quote_subst"`'
predeps='`$ECHO "X$predeps" | $Xsed -e "$delay_single_quote_subst"`'
postdeps='`$ECHO "X$postdeps" | $Xsed -e "$delay_single_quote_subst"`'
compiler_lib_search_path='`$ECHO "X$compiler_lib_search_path" | $Xsed -e "$delay_single_quote_subst"`'
LD_CXX='`$ECHO "X$LD_CXX" | $Xsed -e "$delay_single_quote_subst"`'
old_archive_cmds_CXX='`$ECHO "X$old_archive_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`'
compiler_CXX='`$ECHO "X$compiler_CXX" | $Xsed -e "$delay_single_quote_subst"`'
GCC_CXX='`$ECHO "X$GCC_CXX" | $Xsed -e "$delay_single_quote_subst"`'
lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "X$lt_prog_compiler_no_builtin_flag_CXX" | $Xsed -e "$delay_single_quote_subst"`'
lt_prog_compiler_wl_CXX='`$ECHO "X$lt_prog_compiler_wl_CXX" | $Xsed -e "$delay_single_quote_subst"`'
lt_prog_compiler_pic_CXX='`$ECHO "X$lt_prog_compiler_pic_CXX" | $Xsed -e "$delay_single_quote_subst"`'
lt_prog_compiler_static_CXX='`$ECHO "X$lt_prog_compiler_static_CXX" | $Xsed -e "$delay_single_quote_subst"`'
lt_cv_prog_compiler_c_o_CXX='`$ECHO "X$lt_cv_prog_compiler_c_o_CXX" | $Xsed -e "$delay_single_quote_subst"`'
archive_cmds_need_lc_CXX='`$ECHO "X$archive_cmds_need_lc_CXX" | $Xsed -e "$delay_single_quote_subst"`'
enable_shared_with_static_runtimes_CXX='`$ECHO "X$enable_shared_with_static_runtimes_CXX" | $Xsed -e "$delay_single_quote_subst"`'
export_dynamic_flag_spec_CXX='`$ECHO "X$export_dynamic_flag_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`'
whole_archive_flag_spec_CXX='`$ECHO "X$whole_archive_flag_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`'
compiler_needs_object_CXX='`$ECHO "X$compiler_needs_object_CXX" | $Xsed -e "$delay_single_quote_subst"`'
old_archive_from_new_cmds_CXX='`$ECHO "X$old_archive_from_new_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`'
old_archive_from_expsyms_cmds_CXX='`$ECHO "X$old_archive_from_expsyms_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`'
archive_cmds_CXX='`$ECHO "X$archive_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`'
archive_expsym_cmds_CXX='`$ECHO "X$archive_expsym_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`'
module_cmds_CXX='`$ECHO "X$module_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`'
module_expsym_cmds_CXX='`$ECHO "X$module_expsym_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`'
with_gnu_ld_CXX='`$ECHO "X$with_gnu_ld_CXX" | $Xsed -e "$delay_single_quote_subst"`'
allow_undefined_flag_CXX='`$ECHO "X$allow_undefined_flag_CXX" | $Xsed -e "$delay_single_quote_subst"`'
no_undefined_flag_CXX='`$ECHO "X$no_undefined_flag_CXX" | $Xsed -e "$delay_single_quote_subst"`'
hardcode_libdir_flag_spec_CXX='`$ECHO "X$hardcode_libdir_flag_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`'
hardcode_libdir_flag_spec_ld_CXX='`$ECHO "X$hardcode_libdir_flag_spec_ld_CXX" | $Xsed -e "$delay_single_quote_subst"`'
hardcode_libdir_separator_CXX='`$ECHO "X$hardcode_libdir_separator_CXX" | $Xsed -e "$delay_single_quote_subst"`'
hardcode_direct_CXX='`$ECHO "X$hardcode_direct_CXX" | $Xsed -e "$delay_single_quote_subst"`'
hardcode_direct_absolute_CXX='`$ECHO "X$hardcode_direct_absolute_CXX" | $Xsed -e "$delay_single_quote_subst"`'
hardcode_minus_L_CXX='`$ECHO "X$hardcode_minus_L_CXX" | $Xsed -e "$delay_single_quote_subst"`'
hardcode_shlibpath_var_CXX='`$ECHO "X$hardcode_shlibpath_var_CXX" | $Xsed -e "$delay_single_quote_subst"`'
hardcode_automatic_CXX='`$ECHO "X$hardcode_automatic_CXX" | $Xsed -e "$delay_single_quote_subst"`'
inherit_rpath_CXX='`$ECHO "X$inherit_rpath_CXX" | $Xsed -e "$delay_single_quote_subst"`'
link_all_deplibs_CXX='`$ECHO "X$link_all_deplibs_CXX" | $Xsed -e "$delay_single_quote_subst"`'
fix_srcfile_path_CXX='`$ECHO "X$fix_srcfile_path_CXX" | $Xsed -e "$delay_single_quote_subst"`'
always_export_symbols_CXX='`$ECHO "X$always_export_symbols_CXX" | $Xsed -e "$delay_single_quote_subst"`'
export_symbols_cmds_CXX='`$ECHO "X$export_symbols_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`'
exclude_expsyms_CXX='`$ECHO "X$exclude_expsyms_CXX" | $Xsed -e "$delay_single_quote_subst"`'
include_expsyms_CXX='`$ECHO "X$include_expsyms_CXX" | $Xsed -e "$delay_single_quote_subst"`'
prelink_cmds_CXX='`$ECHO "X$prelink_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`'
file_list_spec_CXX='`$ECHO "X$file_list_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`'
hardcode_action_CXX='`$ECHO "X$hardcode_action_CXX" | $Xsed -e "$delay_single_quote_subst"`'
compiler_lib_search_dirs_CXX='`$ECHO "X$compiler_lib_search_dirs_CXX" | $Xsed -e "$delay_single_quote_subst"`'
predep_objects_CXX='`$ECHO "X$predep_objects_CXX" | $Xsed -e "$delay_single_quote_subst"`'
postdep_objects_CXX='`$ECHO "X$postdep_objects_CXX" | $Xsed -e "$delay_single_quote_subst"`'
predeps_CXX='`$ECHO "X$predeps_CXX" | $Xsed -e "$delay_single_quote_subst"`'
postdeps_CXX='`$ECHO "X$postdeps_CXX" | $Xsed -e "$delay_single_quote_subst"`'
compiler_lib_search_path_CXX='`$ECHO "X$compiler_lib_search_path_CXX" | $Xsed -e "$delay_single_quote_subst"`'

LTCC='$LTCC'
LTCFLAGS='$LTCFLAGS'
compiler='$compiler_DEFAULT'

# Quote evaled strings.
for var in SED \
GREP \
EGREP \
FGREP \
LD \
NM \
LN_S \
lt_SP2NL \
lt_NL2SP \
reload_flag \
OBJDUMP \
deplibs_check_method \
file_magic_cmd \
AR \
AR_FLAGS \
STRIP \
RANLIB \
CC \
CFLAGS \
compiler \
lt_cv_sys_global_symbol_pipe \
lt_cv_sys_global_symbol_to_cdecl \
lt_cv_sys_global_symbol_to_c_name_address \
lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
SHELL \
ECHO \
lt_prog_compiler_no_builtin_flag \
lt_prog_compiler_wl \
lt_prog_compiler_pic \
lt_prog_compiler_static \
lt_cv_prog_compiler_c_o \
need_locks \
DSYMUTIL \
NMEDIT \
LIPO \
OTOOL \
OTOOL64 \
shrext_cmds \
export_dynamic_flag_spec \
whole_archive_flag_spec \
compiler_needs_object \
with_gnu_ld \
allow_undefined_flag \
no_undefined_flag \
hardcode_libdir_flag_spec \
hardcode_libdir_flag_spec_ld \
hardcode_libdir_separator \
fix_srcfile_path \
exclude_expsyms \
include_expsyms \
file_list_spec \
variables_saved_for_relink \
libname_spec \
library_names_spec \
soname_spec \
finish_eval \
old_striplib \
striplib \
compiler_lib_search_dirs \
predep_objects \
postdep_objects \
predeps \
postdeps \
compiler_lib_search_path \
LD_CXX \
compiler_CXX \
lt_prog_compiler_no_builtin_flag_CXX \
lt_prog_compiler_wl_CXX \
lt_prog_compiler_pic_CXX \
lt_prog_compiler_static_CXX \
lt_cv_prog_compiler_c_o_CXX \
export_dynamic_flag_spec_CXX \
whole_archive_flag_spec_CXX \
compiler_needs_object_CXX \
with_gnu_ld_CXX \
allow_undefined_flag_CXX \
no_undefined_flag_CXX \
hardcode_libdir_flag_spec_CXX \
hardcode_libdir_flag_spec_ld_CXX \
hardcode_libdir_separator_CXX \
fix_srcfile_path_CXX \
exclude_expsyms_CXX \
include_expsyms_CXX \
file_list_spec_CXX \
compiler_lib_search_dirs_CXX \
predep_objects_CXX \
postdep_objects_CXX \
predeps_CXX \
postdeps_CXX \
compiler_lib_search_path_CXX; do
    case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
    *[\\\\\\\`\\"\\\$]*)
      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
      ;;
    *)
      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
      ;;
    esac
done

# Double-quote double-evaled strings.
for var in reload_cmds \
old_postinstall_cmds \
old_postuninstall_cmds \
old_archive_cmds \
extract_expsyms_cmds \
old_archive_from_new_cmds \
old_archive_from_expsyms_cmds \
archive_cmds \
archive_expsym_cmds \
module_cmds \
module_expsym_cmds \
export_symbols_cmds \
prelink_cmds \
postinstall_cmds \
postuninstall_cmds \
finish_cmds \
sys_lib_search_path_spec \
sys_lib_dlsearch_path_spec \
old_archive_cmds_CXX \
old_archive_from_new_cmds_CXX \
old_archive_from_expsyms_cmds_CXX \
archive_cmds_CXX \
archive_expsym_cmds_CXX \
module_cmds_CXX \
module_expsym_cmds_CXX \
export_symbols_cmds_CXX \
prelink_cmds_CXX; do
    case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
    *[\\\\\\\`\\"\\\$]*)
      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
      ;;
    *)
      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
      ;;
    esac
done

# Fix-up fallback echo if it was mangled by the above quoting rules.
case \$lt_ECHO in
*'\\\$0 --fallback-echo"')  lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\$0 --fallback-echo"\$/\$0 --fallback-echo"/'\`
  ;;
esac

ac_aux_dir='$ac_aux_dir'
xsi_shell='$xsi_shell'
lt_shell_append='$lt_shell_append'

# See if we are running on zsh, and set the options which allow our
# commands through without removal of \ escapes INIT.
if test -n "\${ZSH_VERSION+set}" ; then
   setopt NO_GLOB_SUBST
fi


    PACKAGE='$PACKAGE'
    VERSION='$VERSION'
    TIMESTAMP='$TIMESTAMP'
    RM='$RM'
    ofile='$ofile'






_ACEOF

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1

# Handling of arguments.
for ac_config_target in $ac_config_targets
do
  case $ac_config_target in
    "src/config.h") CONFIG_HEADERS="$CONFIG_HEADERS src/config.h" ;;
    "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
    "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
    "src/google/tcmalloc.h") CONFIG_FILES="$CONFIG_FILES src/google/tcmalloc.h" ;;

  *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
  esac
done


# If the user did not use the arguments to specify the items to instantiate,
# then the envvar interface is used.  Set only those that are not.
# We use the long form for the default assignment because of an extremely
# bizarre bug on SunOS 4.1.3.
if $ac_need_defaults; then
  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
fi

# Have a temporary directory for convenience.  Make it in the build tree
# simply because there is no reason against having it here, and in addition,
# creating and moving files from /tmp can sometimes cause problems.
# Hook for its removal unless debugging.
# Note that there is a small window in which the directory will not be cleaned:
# after its creation but before its name has been assigned to `$tmp'.
$debug ||
{
  tmp=
  trap 'exit_status=$?
  { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
' 0
  trap 'as_fn_exit 1' 1 2 13 15
}
# Create a (secure) tmp directory for tmp files.

{
  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
  test -n "$tmp" && test -d "$tmp"
}  ||
{
  tmp=./conf$$-$RANDOM
  (umask 077 && mkdir "$tmp")
} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5

# Set up the scripts for CONFIG_FILES section.
# No need to generate them if there are no CONFIG_FILES.
# This happens for instance with `./config.status config.h'.
if test -n "$CONFIG_FILES"; then


ac_cr=`echo X | tr X '\015'`
# On cygwin, bash can eat \r inside `` if the user requested igncr.
# But we know of no other shell where ac_cr would be empty at this
# point, so we can use a bashism as a fallback.
if test "x$ac_cr" = x; then
  eval ac_cr=\$\'\\r\'
fi
ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null`
if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
  ac_cs_awk_cr='\r'
else
  ac_cs_awk_cr=$ac_cr
fi

echo 'BEGIN {' >"$tmp/subs1.awk" &&
_ACEOF


{
  echo "cat >conf$$subs.awk <<_ACEOF" &&
  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
  echo "_ACEOF"
} >conf$$subs.sh ||
  as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'`
ac_delim='%!_!# '
for ac_last_try in false false false false false :; do
  . ./conf$$subs.sh ||
    as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5

  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
  if test $ac_delim_n = $ac_delim_num; then
    break
  elif $ac_last_try; then
    as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
  else
    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
  fi
done
rm -f conf$$subs.sh

cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&
_ACEOF
sed -n '
h
s/^/S["/; s/!.*/"]=/
p
g
s/^[^!]*!//
:repl
t repl
s/'"$ac_delim"'$//
t delim
:nl
h
s/\(.\{148\}\)..*/\1/
t more1
s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
p
n
b repl
:more1
s/["\\]/\\&/g; s/^/"/; s/$/"\\/
p
g
s/.\{148\}//
t nl
:delim
h
s/\(.\{148\}\)..*/\1/
t more2
s/["\\]/\\&/g; s/^/"/; s/$/"/
p
b
:more2
s/["\\]/\\&/g; s/^/"/; s/$/"\\/
p
g
s/.\{148\}//
t delim
' >$CONFIG_STATUS || ac_write_fail=1
rm -f conf$$subs.awk
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
_ACAWK
cat >>"\$tmp/subs1.awk" <<_ACAWK &&
  for (key in S) S_is_set[key] = 1
  FS = ""

}
{
  line = $ 0
  nfields = split(line, field, "@")
  substed = 0
  len = length(field[1])
  for (i = 2; i < nfields; i++) {
    key = field[i]
    keylen = length(key)
    if (S_is_set[key]) {
      value = S[key]
      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
      len += length(value) + length(field[++i])
      substed = 1
    } else
      len += 1 + keylen
  }

  print line
}

_ACAWK
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
else
  cat
fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
  || as_fn_error "could not setup config files machinery" "$LINENO" 5
_ACEOF

# VPATH may cause trouble with some makes, so we remove $(srcdir),
# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
# trailing colons and then remove the whole line if VPATH becomes empty
# (actually we leave an empty line to preserve line numbers).
if test "x$srcdir" = x.; then
  ac_vpsub='/^[	 ]*VPATH[	 ]*=/{
s/:*\$(srcdir):*/:/
s/:*\${srcdir}:*/:/
s/:*@srcdir@:*/:/
s/^\([^=]*=[	 ]*\):*/\1/
s/:*$//
s/^[^=]*=[	 ]*$//
}'
fi

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
fi # test -n "$CONFIG_FILES"

# Set up the scripts for CONFIG_HEADERS section.
# No need to generate them if there are no CONFIG_HEADERS.
# This happens for instance with `./config.status Makefile'.
if test -n "$CONFIG_HEADERS"; then
cat >"$tmp/defines.awk" <<\_ACAWK ||
BEGIN {
_ACEOF

# Transform confdefs.h into an awk script `defines.awk', embedded as
# here-document in config.status, that substitutes the proper values into
# config.h.in to produce config.h.

# Create a delimiter string that does not exist in confdefs.h, to ease
# handling of long lines.
ac_delim='%!_!# '
for ac_last_try in false false :; do
  ac_t=`sed -n "/$ac_delim/p" confdefs.h`
  if test -z "$ac_t"; then
    break
  elif $ac_last_try; then
    as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5
  else
    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
  fi
done

# For the awk script, D is an array of macro values keyed by name,
# likewise P contains macro parameters if any.  Preserve backslash
# newline sequences.

ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
sed -n '
s/.\{148\}/&'"$ac_delim"'/g
t rset
:rset
s/^[	 ]*#[	 ]*define[	 ][	 ]*/ /
t def
d
:def
s/\\$//
t bsnl
s/["\\]/\\&/g
s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
D["\1"]=" \3"/p
s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2"/p
d
:bsnl
s/["\\]/\\&/g
s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
D["\1"]=" \3\\\\\\n"\\/p
t cont
s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
t cont
d
:cont
n
s/.\{148\}/&'"$ac_delim"'/g
t clear
:clear
s/\\$//
t bsnlc
s/["\\]/\\&/g; s/^/"/; s/$/"/p
d
:bsnlc
s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
b cont
' >$CONFIG_STATUS || ac_write_fail=1

cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
  for (key in D) D_is_set[key] = 1
  FS = ""
}
/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
  line = \$ 0
  split(line, arg, " ")
  if (arg[1] == "#") {
    defundef = arg[2]
    mac1 = arg[3]
  } else {
    defundef = substr(arg[1], 2)
    mac1 = arg[2]
  }
  split(mac1, mac2, "(") #)
  macro = mac2[1]
  prefix = substr(line, 1, index(line, defundef) - 1)
  if (D_is_set[macro]) {
    # Preserve the white space surrounding the "#".
    print prefix "define", macro P[macro] D[macro]
    next
  } else {
    # Replace #undef with comments.  This is necessary, for example,
    # in the case of _POSIX_SOURCE, which is predefined and required
    # on some systems where configure will not decide to define it.
    if (defundef == "undef") {
      print "/*", prefix defundef, macro, "*/"
      next
    }
  }
}
{ print }
_ACAWK
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
  as_fn_error "could not setup config headers machinery" "$LINENO" 5
fi # test -n "$CONFIG_HEADERS"


eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    :C $CONFIG_COMMANDS"
shift
for ac_tag
do
  case $ac_tag in
  :[FHLC]) ac_mode=$ac_tag; continue;;
  esac
  case $ac_mode$ac_tag in
  :[FHL]*:*);;
  :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;;
  :[FH]-) ac_tag=-:-;;
  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
  esac
  ac_save_IFS=$IFS
  IFS=:
  set x $ac_tag
  IFS=$ac_save_IFS
  shift
  ac_file=$1
  shift

  case $ac_mode in
  :L) ac_source=$1;;
  :[FH])
    ac_file_inputs=
    for ac_f
    do
      case $ac_f in
      -) ac_f="$tmp/stdin";;
      *) # Look for the file first in the build tree, then in the source tree
	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
	 # because $ac_f cannot contain `:'.
	 test -f "$ac_f" ||
	   case $ac_f in
	   [\\/$]*) false;;
	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
	   esac ||
	   as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;;
      esac
      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
      as_fn_append ac_file_inputs " '$ac_f'"
    done

    # Let's still pretend it is `configure' which instantiates (i.e., don't
    # use $as_me), people would be surprised to read:
    #    /* config.h.  Generated by config.status.  */
    configure_input='Generated from '`
	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
	`' by configure.'
    if test x"$ac_file" != x-; then
      configure_input="$ac_file.  $configure_input"
      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
$as_echo "$as_me: creating $ac_file" >&6;}
    fi
    # Neutralize special characters interpreted by sed in replacement strings.
    case $configure_input in #(
    *\&* | *\|* | *\\* )
       ac_sed_conf_input=`$as_echo "$configure_input" |
       sed 's/[\\\\&|]/\\\\&/g'`;; #(
    *) ac_sed_conf_input=$configure_input;;
    esac

    case $ac_tag in
    *:-:* | *:-) cat >"$tmp/stdin" \
      || as_fn_error "could not create $ac_file" "$LINENO" 5 ;;
    esac
    ;;
  esac

  ac_dir=`$as_dirname -- "$ac_file" ||
$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
	 X"$ac_file" : 'X\(//\)[^/]' \| \
	 X"$ac_file" : 'X\(//\)$' \| \
	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$ac_file" |
    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)[^/].*/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`
  as_dir="$ac_dir"; as_fn_mkdir_p
  ac_builddir=.

case "$ac_dir" in
.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
*)
  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
  # A ".." for each directory in $ac_dir_suffix.
  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
  case $ac_top_builddir_sub in
  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
  esac ;;
esac
ac_abs_top_builddir=$ac_pwd
ac_abs_builddir=$ac_pwd$ac_dir_suffix
# for backward compatibility:
ac_top_builddir=$ac_top_build_prefix

case $srcdir in
  .)  # We are building in place.
    ac_srcdir=.
    ac_top_srcdir=$ac_top_builddir_sub
    ac_abs_top_srcdir=$ac_pwd ;;
  [\\/]* | ?:[\\/]* )  # Absolute name.
    ac_srcdir=$srcdir$ac_dir_suffix;
    ac_top_srcdir=$srcdir
    ac_abs_top_srcdir=$srcdir ;;
  *) # Relative name.
    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
    ac_top_srcdir=$ac_top_build_prefix$srcdir
    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
esac
ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix


  case $ac_mode in
  :F)
  #
  # CONFIG_FILE
  #

  case $INSTALL in
  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
  esac
_ACEOF

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# If the template does not know about datarootdir, expand it.
# FIXME: This hack should be removed a few years after 2.60.
ac_datarootdir_hack=; ac_datarootdir_seen=
ac_sed_dataroot='
/datarootdir/ {
  p
  q
}
/@datadir@/p
/@docdir@/p
/@infodir@/p
/@localedir@/p
/@mandir@/p'
case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
*datarootdir*) ac_datarootdir_seen=yes;;
*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
  ac_datarootdir_hack='
  s&@datadir@&$datadir&g
  s&@docdir@&$docdir&g
  s&@infodir@&$infodir&g
  s&@localedir@&$localedir&g
  s&@mandir@&$mandir&g
  s&\\\${datarootdir}&$datarootdir&g' ;;
esac
_ACEOF

# Neutralize VPATH when `$srcdir' = `.'.
# Shell code in configure.ac might set extrasub.
# FIXME: do we really want to maintain this feature?
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_sed_extra="$ac_vpsub
$extrasub
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
:t
/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
s|@configure_input@|$ac_sed_conf_input|;t t
s&@top_builddir@&$ac_top_builddir_sub&;t t
s&@top_build_prefix@&$ac_top_build_prefix&;t t
s&@srcdir@&$ac_srcdir&;t t
s&@abs_srcdir@&$ac_abs_srcdir&;t t
s&@top_srcdir@&$ac_top_srcdir&;t t
s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
s&@builddir@&$ac_builddir&;t t
s&@abs_builddir@&$ac_abs_builddir&;t t
s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
s&@INSTALL@&$ac_INSTALL&;t t
$ac_datarootdir_hack
"
eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
  || as_fn_error "could not create $ac_file" "$LINENO" 5

test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
  { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
which seems to be undefined.  Please make sure it is defined." >&5
$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
which seems to be undefined.  Please make sure it is defined." >&2;}

  rm -f "$tmp/stdin"
  case $ac_file in
  -) cat "$tmp/out" && rm -f "$tmp/out";;
  *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
  esac \
  || as_fn_error "could not create $ac_file" "$LINENO" 5
 ;;
  :H)
  #
  # CONFIG_HEADER
  #
  if test x"$ac_file" != x-; then
    {
      $as_echo "/* $configure_input  */" \
      && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs"
    } >"$tmp/config.h" \
      || as_fn_error "could not create $ac_file" "$LINENO" 5
    if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then
      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
$as_echo "$as_me: $ac_file is unchanged" >&6;}
    else
      rm -f "$ac_file"
      mv "$tmp/config.h" "$ac_file" \
	|| as_fn_error "could not create $ac_file" "$LINENO" 5
    fi
  else
    $as_echo "/* $configure_input  */" \
      && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \
      || as_fn_error "could not create -" "$LINENO" 5
  fi
# Compute "$ac_file"'s index in $config_headers.
_am_stamp_count=1
for _am_header in $config_headers :; do
  case $_am_header in
    "$ac_file" | "$ac_file":* )
      break ;;
    * )
      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
  esac
done
echo "timestamp for "$ac_file"" >`$as_dirname -- "$ac_file" ||
$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
	 X"$ac_file" : 'X\(//\)[^/]' \| \
	 X"$ac_file" : 'X\(//\)$' \| \
	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$ac_file" |
    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)[^/].*/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`/stamp-h$_am_stamp_count
 ;;

  :C)  { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
$as_echo "$as_me: executing $ac_file commands" >&6;}
 ;;
  esac


  case $ac_file$ac_mode in
    "depfiles":C) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do
  # Strip MF so we end up with the name of the file.
  mf=`echo "$mf" | sed -e 's/:.*$//'`
  # Check whether this is an Automake generated Makefile or not.
  # We used to match only the files named `Makefile.in', but
  # some people rename them; so instead we look at the file content.
  # Grep'ing the first line is not enough: some people post-process
  # each Makefile.in and add a new line on top of each file to say so.
  # So let's grep whole file.
  if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
    dirpart=`$as_dirname -- "$mf" ||
$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
	 X"$mf" : 'X\(//\)[^/]' \| \
	 X"$mf" : 'X\(//\)$' \| \
	 X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$mf" |
    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)[^/].*/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`
  else
    continue
  fi
  # Extract the definition of DEPDIR, am__include, and am__quote
  # from the Makefile without running `make'.
  DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
  test -z "$DEPDIR" && continue
  am__include=`sed -n 's/^am__include = //p' < "$mf"`
  test -z "am__include" && continue
  am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
  # When using ansi2knr, U may be empty or an underscore; expand it
  U=`sed -n 's/^U = //p' < "$mf"`
  # Find all dependency output files, they are included files with
  # $(DEPDIR) in their names.  We invoke sed twice because it is the
  # simplest approach to changing $(DEPDIR) to its actual value in the
  # expansion.
  for file in `sed -n "
    s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
       sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
    # Make sure the directory exists.
    test -f "$dirpart/$file" && continue
    fdir=`$as_dirname -- "$file" ||
$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
	 X"$file" : 'X\(//\)[^/]' \| \
	 X"$file" : 'X\(//\)$' \| \
	 X"$file" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$file" |
    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)[^/].*/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`
    as_dir=$dirpart/$fdir; as_fn_mkdir_p
    # echo "creating $dirpart/$file"
    echo '# dummy' > "$dirpart/$file"
  done
done
 ;;
    "libtool":C)

    # See if we are running on zsh, and set the options which allow our
    # commands through without removal of \ escapes.
    if test -n "${ZSH_VERSION+set}" ; then
      setopt NO_GLOB_SUBST
    fi

    cfgfile="${ofile}T"
    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
    $RM "$cfgfile"

    cat <<_LT_EOF >> "$cfgfile"
#! $SHELL

# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
# NOTE: Changes made to this file will be lost: look at ltmain.sh.
#
#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
#                 2006, 2007, 2008 Free Software Foundation, Inc.
#   Written by Gordon Matzigkeit, 1996
#
#   This file is part of GNU Libtool.
#
# GNU Libtool 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 2 of
# the License, or (at your option) any later version.
#
# As a special exception to the GNU General Public License,
# if you distribute this file as part of a program or library that
# is built using GNU Libtool, you may include this file under the
# same distribution terms that you use for the rest of that program.
#
# GNU Libtool 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 GNU Libtool; see the file COPYING.  If not, a copy
# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
# obtained by writing to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.


# The names of the tagged configurations supported by this script.
available_tags="CXX "

# ### BEGIN LIBTOOL CONFIG

# Whether or not to optimize for fast installation.
fast_install=$enable_fast_install

# Which release of libtool.m4 was used?
macro_version=$macro_version
macro_revision=$macro_revision

# Whether or not to build shared libraries.
build_libtool_libs=$enable_shared

# Whether or not to build static libraries.
build_old_libs=$enable_static

# What type of objects to build.
pic_mode=$pic_mode

# The host system.
host_alias=$host_alias
host=$host
host_os=$host_os

# The build system.
build_alias=$build_alias
build=$build
build_os=$build_os

# A sed program that does not truncate output.
SED=$lt_SED

# Sed that helps us avoid accidentally triggering echo(1) options like -n.
Xsed="\$SED -e 1s/^X//"

# A grep program that handles long lines.
GREP=$lt_GREP

# An ERE matcher.
EGREP=$lt_EGREP

# A literal string matcher.
FGREP=$lt_FGREP

# A BSD- or MS-compatible name lister.
NM=$lt_NM

# Whether we need soft or hard links.
LN_S=$lt_LN_S

# What is the maximum length of a command?
max_cmd_len=$max_cmd_len

# Object file suffix (normally "o").
objext=$ac_objext

# Executable file suffix (normally "").
exeext=$exeext

# whether the shell understands "unset".
lt_unset=$lt_unset

# turn spaces into newlines.
SP2NL=$lt_lt_SP2NL

# turn newlines into spaces.
NL2SP=$lt_lt_NL2SP

# How to create reloadable object files.
reload_flag=$lt_reload_flag
reload_cmds=$lt_reload_cmds

# An object symbol dumper.
OBJDUMP=$lt_OBJDUMP

# Method to check whether dependent libraries are shared objects.
deplibs_check_method=$lt_deplibs_check_method

# Command to use when deplibs_check_method == "file_magic".
file_magic_cmd=$lt_file_magic_cmd

# The archiver.
AR=$lt_AR
AR_FLAGS=$lt_AR_FLAGS

# A symbol stripping program.
STRIP=$lt_STRIP

# Commands used to install an old-style archive.
RANLIB=$lt_RANLIB
old_postinstall_cmds=$lt_old_postinstall_cmds
old_postuninstall_cmds=$lt_old_postuninstall_cmds

# A C compiler.
LTCC=$lt_CC

# LTCC compiler flags.
LTCFLAGS=$lt_CFLAGS

# Take the output of nm and produce a listing of raw symbols and C names.
global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe

# Transform the output of nm in a proper C declaration.
global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl

# Transform the output of nm in a C name address pair.
global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address

# Transform the output of nm in a C name address pair when lib prefix is needed.
global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix

# The name of the directory that contains temporary libtool files.
objdir=$objdir

# Shell to use when invoking shell scripts.
SHELL=$lt_SHELL

# An echo program that does not interpret backslashes.
ECHO=$lt_ECHO

# Used to examine libraries when file_magic_cmd begins with "file".
MAGIC_CMD=$MAGIC_CMD

# Must we lock files when doing compilation?
need_locks=$lt_need_locks

# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
DSYMUTIL=$lt_DSYMUTIL

# Tool to change global to local symbols on Mac OS X.
NMEDIT=$lt_NMEDIT

# Tool to manipulate fat objects and archives on Mac OS X.
LIPO=$lt_LIPO

# ldd/readelf like tool for Mach-O binaries on Mac OS X.
OTOOL=$lt_OTOOL

# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
OTOOL64=$lt_OTOOL64

# Old archive suffix (normally "a").
libext=$libext

# Shared library suffix (normally ".so").
shrext_cmds=$lt_shrext_cmds

# The commands to extract the exported symbol list from a shared archive.
extract_expsyms_cmds=$lt_extract_expsyms_cmds

# Variables whose values should be saved in libtool wrapper scripts and
# restored at link time.
variables_saved_for_relink=$lt_variables_saved_for_relink

# Do we need the "lib" prefix for modules?
need_lib_prefix=$need_lib_prefix

# Do we need a version for libraries?
need_version=$need_version

# Library versioning type.
version_type=$version_type

# Shared library runtime path variable.
runpath_var=$runpath_var

# Shared library path variable.
shlibpath_var=$shlibpath_var

# Is shlibpath searched before the hard-coded library search path?
shlibpath_overrides_runpath=$shlibpath_overrides_runpath

# Format of library name prefix.
libname_spec=$lt_libname_spec

# List of archive names.  First name is the real one, the rest are links.
# The last name is the one that the linker finds with -lNAME
library_names_spec=$lt_library_names_spec

# The coded name of the library, if different from the real name.
soname_spec=$lt_soname_spec

# Command to use after installation of a shared archive.
postinstall_cmds=$lt_postinstall_cmds

# Command to use after uninstallation of a shared archive.
postuninstall_cmds=$lt_postuninstall_cmds

# Commands used to finish a libtool library installation in a directory.
finish_cmds=$lt_finish_cmds

# As "finish_cmds", except a single script fragment to be evaled but
# not shown.
finish_eval=$lt_finish_eval

# Whether we should hardcode library paths into libraries.
hardcode_into_libs=$hardcode_into_libs

# Compile-time system search path for libraries.
sys_lib_search_path_spec=$lt_sys_lib_search_path_spec

# Run-time system search path for libraries.
sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec

# Whether dlopen is supported.
dlopen_support=$enable_dlopen

# Whether dlopen of programs is supported.
dlopen_self=$enable_dlopen_self

# Whether dlopen of statically linked programs is supported.
dlopen_self_static=$enable_dlopen_self_static

# Commands to strip libraries.
old_striplib=$lt_old_striplib
striplib=$lt_striplib


# The linker used to build libraries.
LD=$lt_LD

# Commands used to build an old-style archive.
old_archive_cmds=$lt_old_archive_cmds

# A language specific compiler.
CC=$lt_compiler

# Is the compiler the GNU compiler?
with_gcc=$GCC

# Compiler flag to turn off builtin functions.
no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag

# How to pass a linker flag through the compiler.
wl=$lt_lt_prog_compiler_wl

# Additional compiler flags for building library objects.
pic_flag=$lt_lt_prog_compiler_pic

# Compiler flag to prevent dynamic linking.
link_static_flag=$lt_lt_prog_compiler_static

# Does compiler simultaneously support -c and -o options?
compiler_c_o=$lt_lt_cv_prog_compiler_c_o

# Whether or not to add -lc for building shared libraries.
build_libtool_need_lc=$archive_cmds_need_lc

# Whether or not to disallow shared libs when runtime libs are static.
allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes

# Compiler flag to allow reflexive dlopens.
export_dynamic_flag_spec=$lt_export_dynamic_flag_spec

# Compiler flag to generate shared objects directly from archives.
whole_archive_flag_spec=$lt_whole_archive_flag_spec

# Whether the compiler copes with passing no objects directly.
compiler_needs_object=$lt_compiler_needs_object

# Create an old-style archive from a shared archive.
old_archive_from_new_cmds=$lt_old_archive_from_new_cmds

# Create a temporary old-style archive to link instead of a shared archive.
old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds

# Commands used to build a shared archive.
archive_cmds=$lt_archive_cmds
archive_expsym_cmds=$lt_archive_expsym_cmds

# Commands used to build a loadable module if different from building
# a shared archive.
module_cmds=$lt_module_cmds
module_expsym_cmds=$lt_module_expsym_cmds

# Whether we are building with GNU ld or not.
with_gnu_ld=$lt_with_gnu_ld

# Flag that allows shared libraries with undefined symbols to be built.
allow_undefined_flag=$lt_allow_undefined_flag

# Flag that enforces no undefined symbols.
no_undefined_flag=$lt_no_undefined_flag

# Flag to hardcode \$libdir into a binary during linking.
# This must work even if \$libdir does not exist
hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec

# If ld is used when linking, flag to hardcode \$libdir into a binary
# during linking.  This must work even if \$libdir does not exist.
hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld

# Whether we need a single "-rpath" flag with a separated argument.
hardcode_libdir_separator=$lt_hardcode_libdir_separator

# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
# DIR into the resulting binary.
hardcode_direct=$hardcode_direct

# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
# DIR into the resulting binary and the resulting library dependency is
# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
# library is relocated.
hardcode_direct_absolute=$hardcode_direct_absolute

# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
# into the resulting binary.
hardcode_minus_L=$hardcode_minus_L

# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
# into the resulting binary.
hardcode_shlibpath_var=$hardcode_shlibpath_var

# Set to "yes" if building a shared library automatically hardcodes DIR
# into the library and all subsequent libraries and executables linked
# against it.
hardcode_automatic=$hardcode_automatic

# Set to yes if linker adds runtime paths of dependent libraries
# to runtime path list.
inherit_rpath=$inherit_rpath

# Whether libtool must link a program against all its dependency libraries.
link_all_deplibs=$link_all_deplibs

# Fix the shell variable \$srcfile for the compiler.
fix_srcfile_path=$lt_fix_srcfile_path

# Set to "yes" if exported symbols are required.
always_export_symbols=$always_export_symbols

# The commands to list exported symbols.
export_symbols_cmds=$lt_export_symbols_cmds

# Symbols that should not be listed in the preloaded symbols.
exclude_expsyms=$lt_exclude_expsyms

# Symbols that must always be exported.
include_expsyms=$lt_include_expsyms

# Commands necessary for linking programs (against libraries) with templates.
prelink_cmds=$lt_prelink_cmds

# Specify filename containing input files.
file_list_spec=$lt_file_list_spec

# How to hardcode a shared library path into an executable.
hardcode_action=$hardcode_action

# The directories searched by this compiler when creating a shared library.
compiler_lib_search_dirs=$lt_compiler_lib_search_dirs

# Dependencies to place before and after the objects being linked to
# create a shared library.
predep_objects=$lt_predep_objects
postdep_objects=$lt_postdep_objects
predeps=$lt_predeps
postdeps=$lt_postdeps

# The library search path used internally by the compiler when linking
# a shared library.
compiler_lib_search_path=$lt_compiler_lib_search_path

# ### END LIBTOOL CONFIG

_LT_EOF

  case $host_os in
  aix3*)
    cat <<\_LT_EOF >> "$cfgfile"
# AIX sometimes has problems with the GCC collect2 program.  For some
# reason, if we set the COLLECT_NAMES environment variable, the problems
# vanish in a puff of smoke.
if test "X${COLLECT_NAMES+set}" != Xset; then
  COLLECT_NAMES=
  export COLLECT_NAMES
fi
_LT_EOF
    ;;
  esac


ltmain="$ac_aux_dir/ltmain.sh"


  # We use sed instead of cat because bash on DJGPP gets confused if
  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
  # text mode, it properly converts lines to CR/LF.  This bash problem
  # is reportedly fixed, but why not run on old versions too?
  sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \
    || (rm -f "$cfgfile"; exit 1)

  case $xsi_shell in
  yes)
    cat << \_LT_EOF >> "$cfgfile"

# func_dirname file append nondir_replacement
# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
# otherwise set result to NONDIR_REPLACEMENT.
func_dirname ()
{
  case ${1} in
    */*) func_dirname_result="${1%/*}${2}" ;;
    *  ) func_dirname_result="${3}" ;;
  esac
}

# func_basename file
func_basename ()
{
  func_basename_result="${1##*/}"
}

# func_dirname_and_basename file append nondir_replacement
# perform func_basename and func_dirname in a single function
# call:
#   dirname:  Compute the dirname of FILE.  If nonempty,
#             add APPEND to the result, otherwise set result
#             to NONDIR_REPLACEMENT.
#             value returned in "$func_dirname_result"
#   basename: Compute filename of FILE.
#             value retuned in "$func_basename_result"
# Implementation must be kept synchronized with func_dirname
# and func_basename. For efficiency, we do not delegate to
# those functions but instead duplicate the functionality here.
func_dirname_and_basename ()
{
  case ${1} in
    */*) func_dirname_result="${1%/*}${2}" ;;
    *  ) func_dirname_result="${3}" ;;
  esac
  func_basename_result="${1##*/}"
}

# func_stripname prefix suffix name
# strip PREFIX and SUFFIX off of NAME.
# PREFIX and SUFFIX must not contain globbing or regex special
# characters, hashes, percent signs, but SUFFIX may contain a leading
# dot (in which case that matches only a dot).
func_stripname ()
{
  # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
  # positional parameters, so assign one to ordinary parameter first.
  func_stripname_result=${3}
  func_stripname_result=${func_stripname_result#"${1}"}
  func_stripname_result=${func_stripname_result%"${2}"}
}

# func_opt_split
func_opt_split ()
{
  func_opt_split_opt=${1%%=*}
  func_opt_split_arg=${1#*=}
}

# func_lo2o object
func_lo2o ()
{
  case ${1} in
    *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
    *)    func_lo2o_result=${1} ;;
  esac
}

# func_xform libobj-or-source
func_xform ()
{
  func_xform_result=${1%.*}.lo
}

# func_arith arithmetic-term...
func_arith ()
{
  func_arith_result=$(( $* ))
}

# func_len string
# STRING may not start with a hyphen.
func_len ()
{
  func_len_result=${#1}
}

_LT_EOF
    ;;
  *) # Bourne compatible functions.
    cat << \_LT_EOF >> "$cfgfile"

# func_dirname file append nondir_replacement
# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
# otherwise set result to NONDIR_REPLACEMENT.
func_dirname ()
{
  # Extract subdirectory from the argument.
  func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"`
  if test "X$func_dirname_result" = "X${1}"; then
    func_dirname_result="${3}"
  else
    func_dirname_result="$func_dirname_result${2}"
  fi
}

# func_basename file
func_basename ()
{
  func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"`
}


# func_stripname prefix suffix name
# strip PREFIX and SUFFIX off of NAME.
# PREFIX and SUFFIX must not contain globbing or regex special
# characters, hashes, percent signs, but SUFFIX may contain a leading
# dot (in which case that matches only a dot).
# func_strip_suffix prefix name
func_stripname ()
{
  case ${2} in
    .*) func_stripname_result=`$ECHO "X${3}" \
           | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;;
    *)  func_stripname_result=`$ECHO "X${3}" \
           | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;;
  esac
}

# sed scripts:
my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q'
my_sed_long_arg='1s/^-[^=]*=//'

# func_opt_split
func_opt_split ()
{
  func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"`
  func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"`
}

# func_lo2o object
func_lo2o ()
{
  func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"`
}

# func_xform libobj-or-source
func_xform ()
{
  func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[^.]*$/.lo/'`
}

# func_arith arithmetic-term...
func_arith ()
{
  func_arith_result=`expr "$@"`
}

# func_len string
# STRING may not start with a hyphen.
func_len ()
{
  func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len`
}

_LT_EOF
esac

case $lt_shell_append in
  yes)
    cat << \_LT_EOF >> "$cfgfile"

# func_append var value
# Append VALUE to the end of shell variable VAR.
func_append ()
{
  eval "$1+=\$2"
}
_LT_EOF
    ;;
  *)
    cat << \_LT_EOF >> "$cfgfile"

# func_append var value
# Append VALUE to the end of shell variable VAR.
func_append ()
{
  eval "$1=\$$1\$2"
}

_LT_EOF
    ;;
  esac


  sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \
    || (rm -f "$cfgfile"; exit 1)

  mv -f "$cfgfile" "$ofile" ||
    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
  chmod +x "$ofile"


    cat <<_LT_EOF >> "$ofile"

# ### BEGIN LIBTOOL TAG CONFIG: CXX

# The linker used to build libraries.
LD=$lt_LD_CXX

# Commands used to build an old-style archive.
old_archive_cmds=$lt_old_archive_cmds_CXX

# A language specific compiler.
CC=$lt_compiler_CXX

# Is the compiler the GNU compiler?
with_gcc=$GCC_CXX

# Compiler flag to turn off builtin functions.
no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX

# How to pass a linker flag through the compiler.
wl=$lt_lt_prog_compiler_wl_CXX

# Additional compiler flags for building library objects.
pic_flag=$lt_lt_prog_compiler_pic_CXX

# Compiler flag to prevent dynamic linking.
link_static_flag=$lt_lt_prog_compiler_static_CXX

# Does compiler simultaneously support -c and -o options?
compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX

# Whether or not to add -lc for building shared libraries.
build_libtool_need_lc=$archive_cmds_need_lc_CXX

# Whether or not to disallow shared libs when runtime libs are static.
allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX

# Compiler flag to allow reflexive dlopens.
export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX

# Compiler flag to generate shared objects directly from archives.
whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX

# Whether the compiler copes with passing no objects directly.
compiler_needs_object=$lt_compiler_needs_object_CXX

# Create an old-style archive from a shared archive.
old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX

# Create a temporary old-style archive to link instead of a shared archive.
old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX

# Commands used to build a shared archive.
archive_cmds=$lt_archive_cmds_CXX
archive_expsym_cmds=$lt_archive_expsym_cmds_CXX

# Commands used to build a loadable module if different from building
# a shared archive.
module_cmds=$lt_module_cmds_CXX
module_expsym_cmds=$lt_module_expsym_cmds_CXX

# Whether we are building with GNU ld or not.
with_gnu_ld=$lt_with_gnu_ld_CXX

# Flag that allows shared libraries with undefined symbols to be built.
allow_undefined_flag=$lt_allow_undefined_flag_CXX

# Flag that enforces no undefined symbols.
no_undefined_flag=$lt_no_undefined_flag_CXX

# Flag to hardcode \$libdir into a binary during linking.
# This must work even if \$libdir does not exist
hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX

# If ld is used when linking, flag to hardcode \$libdir into a binary
# during linking.  This must work even if \$libdir does not exist.
hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX

# Whether we need a single "-rpath" flag with a separated argument.
hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX

# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
# DIR into the resulting binary.
hardcode_direct=$hardcode_direct_CXX

# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
# DIR into the resulting binary and the resulting library dependency is
# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
# library is relocated.
hardcode_direct_absolute=$hardcode_direct_absolute_CXX

# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
# into the resulting binary.
hardcode_minus_L=$hardcode_minus_L_CXX

# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
# into the resulting binary.
hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX

# Set to "yes" if building a shared library automatically hardcodes DIR
# into the library and all subsequent libraries and executables linked
# against it.
hardcode_automatic=$hardcode_automatic_CXX

# Set to yes if linker adds runtime paths of dependent libraries
# to runtime path list.
inherit_rpath=$inherit_rpath_CXX

# Whether libtool must link a program against all its dependency libraries.
link_all_deplibs=$link_all_deplibs_CXX

# Fix the shell variable \$srcfile for the compiler.
fix_srcfile_path=$lt_fix_srcfile_path_CXX

# Set to "yes" if exported symbols are required.
always_export_symbols=$always_export_symbols_CXX

# The commands to list exported symbols.
export_symbols_cmds=$lt_export_symbols_cmds_CXX

# Symbols that should not be listed in the preloaded symbols.
exclude_expsyms=$lt_exclude_expsyms_CXX

# Symbols that must always be exported.
include_expsyms=$lt_include_expsyms_CXX

# Commands necessary for linking programs (against libraries) with templates.
prelink_cmds=$lt_prelink_cmds_CXX

# Specify filename containing input files.
file_list_spec=$lt_file_list_spec_CXX

# How to hardcode a shared library path into an executable.
hardcode_action=$hardcode_action_CXX

# The directories searched by this compiler when creating a shared library.
compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX

# Dependencies to place before and after the objects being linked to
# create a shared library.
predep_objects=$lt_predep_objects_CXX
postdep_objects=$lt_postdep_objects_CXX
predeps=$lt_predeps_CXX
postdeps=$lt_postdeps_CXX

# The library search path used internally by the compiler when linking
# a shared library.
compiler_lib_search_path=$lt_compiler_lib_search_path_CXX

# ### END LIBTOOL TAG CONFIG: CXX
_LT_EOF

 ;;

  esac
done # for ac_tag


as_fn_exit 0
_ACEOF
ac_clean_files=$ac_clean_files_save

test $ac_write_fail = 0 ||
  as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5


# configure is writing to config.log, and then calls config.status.
# config.status does its own redirection, appending to config.log.
# Unfortunately, on DOS this fails, as config.log is still kept open
# by configure, so config.status won't be able to write to it; its
# output is simply discarded.  So we exec the FD to /dev/null,
# effectively closing config.log, so it can be properly (re)opened and
# appended to by config.status.  When coming back to configure, we
# need to make the FD available again.
if test "$no_create" != yes; then
  ac_cs_success=:
  ac_config_status_args=
  test "$silent" = yes &&
    ac_config_status_args="$ac_config_status_args --quiet"
  exec 5>/dev/null
  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
  exec 5>>config.log
  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
  # would make configure fail if this is the last instruction.
  $ac_cs_success || as_fn_exit $?
fi
if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
fi



================================================
FILE: distro/google-perftools-1.7/configure.ac
================================================
## Process this file with autoconf to produce configure.
## In general, the safest way to proceed is to run ./autogen.sh

# make sure we're interpreted by some minimal autoconf
AC_PREREQ(2.57)

AC_INIT(google-perftools, 1.7, opensource@google.com)
# Update this value for every release!  (A:B:C will map to foo.so.(A-C).C.B)
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
TCMALLOC_SO_VERSION=1:0:1
PROFILER_SO_VERSION=1:0:1

AC_SUBST(TCMALLOC_SO_VERSION)
AC_SUBST(PROFILER_SO_VERSION)

# The argument here is just something that should be in the current directory
# (for sanity checking)
AC_CONFIG_SRCDIR(README)
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_HOST
AM_INIT_AUTOMAKE([dist-zip])
AM_CONFIG_HEADER(src/config.h)

# Export the version information (for tc_version and friends)
TC_VERSION_MAJOR=`expr "$PACKAGE_VERSION" : '\([[0-9]]*\)'`
TC_VERSION_MINOR=`expr "$PACKAGE_VERSION" : '[[^.]]*\.\([[0-9]]*\)'`
TC_VERSION_PATCH=`expr "$PACKAGE_VERSION" : '[[^.0-9]]*\([[^0-9]]*\)$'`
AC_SUBST(TC_VERSION_MAJOR)
AC_SUBST(TC_VERSION_MINOR)
AC_SUBST(TC_VERSION_PATCH)
AC_SUBST(PACKAGE_STRING)

# The user can choose not to compile in the heap-profiler, the
# heap-checker, or the cpu-profiler.  There's also the possibility
# for a 'fully minimal' compile, which leaves out the stacktrace
# code as well.  By default, we include all of these that the
# target system supports.
default_enable_cpu_profiler=yes
default_enable_heap_profiler=yes
default_enable_heap_checker=yes
default_enable_debugalloc=yes
default_enable_minimal=no
need_nanosleep=yes   # Used later, to decide if to run ACX_NANOSLEEP
case "$host" in
   *-mingw*) default_enable_minimal=yes; default_enable_debugalloc=no;
             need_nanosleep=no;;
   *-cygwin*) default_enable_heap_checker=no; default_enable_cpu_profiler=no;;
   *-freebsd*) default_enable_heap_checker=no;;
   *-darwin*) default_enable_heap_checker=no;;
esac

AC_ARG_ENABLE([cpu-profiler],
              [AS_HELP_STRING([--disable-cpu-profiler],
                              [do not build the cpu profiler])],
              [],
              [enable_cpu_profiler="$default_enable_cpu_profiler"])
AC_ARG_ENABLE([heap-profiler],
              [AS_HELP_STRING([--disable-heap-profiler],
                              [do not build the heap profiler])],
              [],
              [enable_heap_profiler="$default_enable_heap_profiler"])
AC_ARG_ENABLE([heap-checker],
              [AS_HELP_STRING([--disable-heap-checker],
                              [do not build the heap checker])],
              [],
              [enable_heap_checker="$default_enable_heap_checker"])
AC_ARG_ENABLE([debugalloc],
              [AS_HELP_STRING([--disable-debugalloc],
                              [do not build versions of libs with debugalloc])],
              [],
              [enable_debugalloc="$default_enable_debugalloc"])
AC_ARG_ENABLE([minimal],
              [AS_HELP_STRING([--enable-minimal],
                              [build only tcmalloc-minimal (and maybe tcmalloc-minimal-debug)])],
              [],
              [enable_minimal="$default_enable_minimal"])
if test "$enable_minimal" = yes; then
  enable_cpu_profiler=no
  enable_heap_profiler=no
  enable_heap_checker=no
fi


# Checks for programs.
AC_PROG_CC
AC_PROG_CPP
AC_PROG_CXX
AM_CONDITIONAL(GCC, test "$GCC" = yes)   # let the Makefile know if we're gcc
AM_PROG_CC_C_O      # shrug: autogen.sh suddenly needs this for some reason

# Check if we have an objcopy installed that supports -W
AC_CHECK_TOOL([OBJCOPY], [objcopy], [])
AM_CONDITIONAL(HAVE_OBJCOPY_WEAKEN, ["$OBJCOPY" -W malloc /bin/ls /dev/null])

case $host_os in
  *mingw*)
    # Disabling fast install keeps libtool from creating wrapper scripts
    # around the executables it builds.  Such scripts have caused failures on
    # MinGW.  Using this option means an extra link step is executed during
    # "make install".
    AC_DISABLE_FAST_INSTALL
    ;;
   *)
    AC_ENABLE_FAST_INSTALL
    ;;
esac

AC_PROG_LIBTOOL
AC_SUBST(LIBTOOL_DEPS)
AM_CONDITIONAL(USE_LIBTOOL, test "x$LIBTOOL" != "x")

AC_C_INLINE
AX_C___ATTRIBUTE__

# Check whether some low-level functions/files are available
AC_HEADER_STDC

# TODO(csilvers): we could remove a lot when WITH_CPU_PROFILER etc is "no".
AC_CHECK_TYPES([__int64])       # defined in some windows platforms
AC_CHECK_TYPES([struct mallinfo],,, [#include ])
AC_CHECK_TYPES([Elf32_Versym],,, [#include ])   # for vdso_support.h
AC_CHECK_FUNCS(sbrk)            # for tcmalloc to get memory
AC_CHECK_FUNCS(geteuid)         # for turning off services when run as root
AC_CHECK_HEADERS(features.h)    # for vdso_support.h
AC_CHECK_HEADERS(malloc.h)      # some systems define stuff there, others not
AC_CHECK_HEADERS(glob.h)        # for heap-profile-table (cleaning up profiles)
AC_CHECK_HEADERS(execinfo.h)    # for stacktrace? and heapchecker_unittest
AC_CHECK_HEADERS(libunwind.h)   # for stacktrace
AC_CHECK_HEADERS(unwind.h)      # for stacktrace
AC_CHECK_HEADERS(sched.h)       # for being nice in our spinlock code
AC_CHECK_HEADERS(conflict-signal.h)      # defined on some windows platforms?
AC_CHECK_HEADERS(sys/prctl.h)   # for thread_lister (needed by leak-checker)
AC_CHECK_HEADERS(linux/ptrace.h)# also needed by leak-checker
AC_CHECK_HEADERS(sys/syscall.h)
AC_CHECK_HEADERS(sys/socket.h)  # optional; for forking out to symbolizer
AC_CHECK_HEADERS(sys/wait.h)    # optional; for forking out to symbolizer
AC_CHECK_HEADERS(poll.h)        # optional; for forking out to symbolizer
AC_CHECK_HEADERS(fcntl.h)       # for tcmalloc_unittest
AC_CHECK_HEADERS(grp.h)         # for heapchecker_unittest
AC_CHECK_HEADERS(pwd.h)         # for heapchecker_unittest
AC_CHECK_HEADERS(sys/resource.h)         # for memalign_unittest.cc
AC_CHECK_HEADERS(valgrind.h)    # we have a local copy if this isn't found
# We also need /, but we get those from
# AC_PC_FROM_UCONTEXT, below.

# We override a lot of memory allocation routines, not all of which are
# standard.  For those the system doesn't declare, we'll declare ourselves.
AC_CHECK_DECLS([cfree,
                posix_memalign,
                memalign,
                valloc,
                pvalloc],,,
               [#define _XOPEN_SOURCE 600
                #include 
                #include ])

if test "$ac_cv_type_struct_mallinfo" = yes; then
  AC_SUBST(ac_cv_have_struct_mallinfo, 1)   # google/tcmalloc.h needs this
else
  AC_SUBST(ac_cv_have_struct_mallinfo, 0)
fi

# We need to check for mmap.  cygwin supports mmap, but the autoconf
# test doesn't work on cygwin:
#    http://www.cygwin.com/ml/cygwin/2002-04/msg00412.html
# This workaround comes from
#    http://cygwin.com/ml/cygwin/2004-11/msg00138.html
case "$host" in
  *-*-cygwin*) ac_cv_func_mmap_fixed_mapped=yes
               AC_DEFINE(HAVE_MMAP, 1,
                         [Define to 1 if you have a working `mmap' system call.])
               ;;
            *) AC_FUNC_MMAP
               ;;
esac

# If AtomicWord != Atomic32, we need to define two versions of all the
# atomicops functions.  If they're the same, we want to define only one.
AC_MSG_CHECKING([if int32_t is the same type as intptr_t])
AC_TRY_COMPILE([#include ],
	       [int32_t v1 = 0; intptr_t v2 = 0; return (&v1 - &v2)],
               [AC_DEFINE(INT32_EQUALS_INTPTR, 1,
                          Define to 1 if int32_t is equivalent to intptr_t)
                AC_MSG_RESULT([yes])],
               [AC_MSG_RESULT([no])])

# We want to access the "PC" (Program Counter) register from a struct
# ucontext.  Every system has its own way of doing that.  We try all the
# possibilities we know about.  Note REG_PC should come first (REG_RIP
# is also defined on solaris, but does the wrong thing).  But don't
# bother if we're not doing cpu-profiling.
# [*] means that we've not actually tested one of these systems
if test "$enable_cpu_profiler" = yes; then
  AC_PC_FROM_UCONTEXT(AC_MSG_WARN(Could not find the PC.  Will not try to compile libprofiler...);
                      enable_cpu_profiler=no)
fi

# Some tests test the behavior of .so files, and only make sense for dynamic.
AM_CONDITIONAL(ENABLE_STATIC, test "$enable_static" = yes)

# We want to link in libunwind if it exists
AC_CHECK_LIB(unwind, backtrace, UNWIND_LIBS=-lunwind, UNWIND_LIBS=)
AC_SUBST(UNWIND_LIBS)

# On x86_64, instead of libunwind, we can choose to compile with frame-pointers
# (This isn't needed on i386, where -fno-omit-frame-pointer is the default).
AC_ARG_ENABLE(frame_pointers,
              AS_HELP_STRING([--enable-frame-pointers],
                             [On x86_64 systems, compile with -fno-omit-frame-pointer (see INSTALL)]),
	      , enable_frame_pointers=no)
AM_CONDITIONAL(ENABLE_FRAME_POINTERS, test "$enable_frame_pointers" = yes)

# Some x86_64 systems do not insert frame pointers by default (all
# i386 systems that I know of, do.  I don't know about non-x86 chips).
# We want to see if the current system is one of those.
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(, [return __x86_64__ == 1 ? 0 : 1])],
                  [is_x86_64=yes], [is_x86_64=no])
OLD_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -S -O2 -o fp.s"
# This test will always fail because we don't name our output file properly.
# We do our own determination of success/failure in the grep, below.
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int f(int x) {return x;}], [return f(0);])],
                  [:], [:])
AM_CONDITIONAL(X86_64_AND_NO_FP_BY_DEFAULT,
               test "$is_x86_64" = yes && ! grep 'mov.*rsp.*rbp' fp.s >/dev/null 2>&1)
rm fp.s
CFLAGS="$OLD_CFLAGS"


# Defines PRIuS
AC_COMPILER_CHARACTERISTICS

# Also make sure we get standard PRI... definitions, even with glibc.
# We have to use AH_VERBATIM because we need the #ifdef guard (gcc buglet)
AH_VERBATIM([__STDC_FORMAT_MACROS],
            [/* C99 says: define this to get the PRI... macros from stdint.h */
#ifndef __STDC_FORMAT_MACROS
# define __STDC_FORMAT_MACROS 1
#endif])

# Check if __builtin_stack_pointer() is available (for elfcore.h)
AC_MSG_CHECKING([for __builtin_stack_pointer()])
AC_LINK_IFELSE([AC_LANG_PROGRAM(, [void *sp = __builtin_stack_pointer()])],
               [AC_DEFINE(HAVE_BUILTIN_STACK_POINTER, 1,
                      Define to 1 if compiler supports __builtin_stack_pointer)
                AC_MSG_RESULT([yes])],
               [AC_MSG_RESULT([no])])

# Check if __environ is available (for GetenvBeforeMain)
AC_MSG_CHECKING([for __environ])
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ],
                                [char **env = __environ])],
               [AC_DEFINE(HAVE___ENVIRON, 1,
                          [Define to 1 if compiler supports __environ])
                AC_MSG_RESULT([yes])],
               [AC_MSG_RESULT([no])])

# If we support __thread, that can speed up tcmalloc a bit.
# Note, however, that our code tickles a bug in gcc < 4.1.2
# involving TLS and -fPIC (which our libraries will use) on x86:
#   http://gcc.gnu.org/ml/gcc-bugs/2006-09/msg02275.html
AC_MSG_CHECKING([for __thread])
AC_LINK_IFELSE([AC_LANG_PROGRAM([#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 1) || (__GNUC__ == 4 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ < 2))
#error gcc has this bug: http://gcc.gnu.org/ml/gcc-bugs/2006-09/msg02275.html
#endif], [static __thread int p = 0])],
               [AC_DEFINE(HAVE_TLS, 1,
                      Define to 1 if compiler supports __thread)
                AC_MSG_RESULT([yes])],
               [AC_MSG_RESULT([no])])

# Nanosleep requires extra libraries on some architectures (solaris).
# This sets NANOSLEEP_LIBS.  nanosleep doesn't exist on mingw, which
# is fine for us because we don't compile libspinlock, which uses it.
if test "$need_nanosleep" = yes; then
  ACX_NANOSLEEP
  AC_SUBST(NANOSLEEP_LIBS)
fi

# Solaris 10 6/06 has a bug where /usr/sfw/lib/libstdc++.la is empty.
# If so, we replace it with our own version.
LIBSTDCXX_LA_LINKER_FLAG=
if test -f /usr/sfw/lib/libstdc++.la && ! test -s /usr/sfw/lib/libstdc++.la
then
  LIBSTDCXX_LA_LINKER_FLAG='-L$(top_srcdir)/src/solaris'
fi
AC_SUBST(LIBSTDCXX_LA_LINKER_FLAG)

# We also need to check if the kernel supports __thread, which requires uname()
AC_CHECK_DECLS(uname,,, [#include ])

# In fact, a lot of the code in this directory depends on pthreads
ACX_PTHREAD

# Find out what namespace 'normal' STL code lives in
AC_CXX_STL_NAMESPACE

# Figure out where libc has program_invocation_name
AC_PROGRAM_INVOCATION_NAME

# Make the install prefix available, to figure out where to look for pprof
AC_INSTALL_PREFIX

# For windows, this has a non-trivial value (__declspec(export)), but any
# system that uses configure wants this to be the empty string.
AC_DEFINE(PERFTOOLS_DLL_DECL,,
          [Always the empty-string on non-windows systems.
           On windows, should be "__declspec(dllexport)".
	   This way, when we compile the dll, we export our functions/classes.
	   It's safe to define this here because config.h is only used
	   internally, to compile the DLL, and every DLL source file
	   #includes "config.h" before anything else.])

# In theory, config.h files shouldn't need a header guard, but we do,
# because we (maybe) #include windows/mingw.h from within config.h,
# and it #includes other .h files.  These all have header guards, so
# the end result is if config.h is #included twice, its #undefs get
# evaluated twice, but all the ones in mingw.h/etc only get evaluated
# once, potentially causing trouble.  c.f.
#   http://code.google.com/p/google-perftools/issues/detail?id=246
AH_TOP([
#ifndef GOOGLE_PERFTOOLS_CONFIG_H_
#define GOOGLE_PERFTOOLS_CONFIG_H_
])

# MinGW uses autoconf, but also needs the windows shim routines
# (since it doesn't have its own support for, say, pthreads).
# This requires us to #include a special header file, and also to
# link in some windows versions of .o's instead of the unix versions.
AH_BOTTOM([
#ifdef __MINGW32__
#include "windows/mingw.h"
#endif

#endif  /* #ifndef GOOGLE_PERFTOOLS_CONFIG_H_ */
])
AM_CONDITIONAL(MINGW, expr $host : '.*-mingw' >/dev/null 2>&1)

# Redhat 7 (and below?) has sys/ucontext.h, but if you try to #include
# it directly, the compiler gets upset.  So we pretend we don't have
# it.
if cat /etc/redhat-release 2>/dev/null | grep "Red Hat Linux release 7" >/dev/null 2>&1; then
AC_DEFINE(HAVE_SYS_UCONTEXT_H, 0, [ is broken on redhat 7])
fi

# Export the --enable flags we set above.  We do this at the end so
# other configure rules can enable or disable targets based on what
# they find.
AM_CONDITIONAL(WITH_CPU_PROFILER, test "$enable_cpu_profiler" = yes)
AM_CONDITIONAL(WITH_HEAP_PROFILER, test "$enable_heap_profiler" = yes)
AM_CONDITIONAL(WITH_HEAP_CHECKER, test "$enable_heap_checker" = yes)
AM_CONDITIONAL(WITH_DEBUGALLOC, test "$enable_debugalloc" = yes)
# We make tcmalloc.so if either heap-profiler or heap-checker is asked for.
AM_CONDITIONAL(WITH_HEAP_PROFILER_OR_CHECKER,
               test "$enable_heap_profiler" = yes -o \
                    "$enable_heap_checker" = yes)
# If we don't use any profilers, we don't need stack traces (or pprof)
AM_CONDITIONAL(WITH_STACK_TRACE, test "$enable_cpu_profiler" = yes -o \
                                      "$enable_heap_profiler" = yes -o \
                                      "$enable_heap_checker" = yes)

# Write generated configuration file
AC_CONFIG_FILES([Makefile src/google/tcmalloc.h])
AC_OUTPUT


================================================
FILE: distro/google-perftools-1.7/depcomp
================================================
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects

scriptversion=2005-07-09.11

# Copyright (C) 1999, 2000, 2003, 2004, 2005 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 2, 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., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.

# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.

# Originally written by Alexandre Oliva .

case $1 in
  '')
     echo "$0: No command.  Try \`$0 --help' for more information." 1>&2
     exit 1;
     ;;
  -h | --h*)
    cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]

Run PROGRAMS ARGS to compile a file, generating dependencies
as side-effects.

Environment variables:
  depmode     Dependency tracking mode.
  source      Source file read by `PROGRAMS ARGS'.
  object      Object file output by `PROGRAMS ARGS'.
  DEPDIR      directory where to store dependencies.
  depfile     Dependency file to output.
  tmpdepfile  Temporary file to use when outputing dependencies.
  libtool     Whether libtool is used (yes/no).

Report bugs to .
EOF
    exit $?
    ;;
  -v | --v*)
    echo "depcomp $scriptversion"
    exit $?
    ;;
esac

if test -z "$depmode" || test -z "$source" || test -z "$object"; then
  echo "depcomp: Variables source, object and depmode must be set" 1>&2
  exit 1
fi

# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
depfile=${depfile-`echo "$object" |
  sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}

rm -f "$tmpdepfile"

# Some modes work just like other modes, but use different flags.  We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write.  Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
  # HP compiler uses -M and no extra arg.
  gccflag=-M
  depmode=gcc
fi

if test "$depmode" = dashXmstdout; then
   # This is just like dashmstdout with a different argument.
   dashmflag=-xM
   depmode=dashmstdout
fi

case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want.  Yay!  Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff.  Hmm.
  "$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
  stat=$?
  if test $stat -eq 0; then :
  else
    rm -f "$tmpdepfile"
    exit $stat
  fi
  mv "$tmpdepfile" "$depfile"
  ;;

gcc)
## There are various ways to get dependency output from gcc.  Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
##   up in a subdir.  Having to rename by hand is ugly.
##   (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
##   -MM, not -M (despite what the docs say).
## - Using -M directly means running the compiler twice (even worse
##   than renaming).
  if test -z "$gccflag"; then
    gccflag=-MD,
  fi
  "$@" -Wp,"$gccflag$tmpdepfile"
  stat=$?
  if test $stat -eq 0; then :
  else
    rm -f "$tmpdepfile"
    exit $stat
  fi
  rm -f "$depfile"
  echo "$object : \\" > "$depfile"
  alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
## The second -e expression handles DOS-style file names with drive letters.
  sed -e 's/^[^:]*: / /' \
      -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the `deleted header file' problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header).  We avoid this by adding
## dummy dependencies for each header file.  Too bad gcc doesn't do
## this for us directly.
  tr ' ' '
' < "$tmpdepfile" |
## Some versions of gcc put a space before the `:'.  On the theory
## that the space means something, we add a space to the output as
## well.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly.  Breaking it into two sed invocations is a workaround.
    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
  rm -f "$tmpdepfile"
  ;;

hp)
  # This case exists only to let depend.m4 do its work.  It works by
  # looking at the text of this script.  This case will never be run,
  # since it is checked for above.
  exit 1
  ;;

sgi)
  if test "$libtool" = yes; then
    "$@" "-Wp,-MDupdate,$tmpdepfile"
  else
    "$@" -MDupdate "$tmpdepfile"
  fi
  stat=$?
  if test $stat -eq 0; then :
  else
    rm -f "$tmpdepfile"
    exit $stat
  fi
  rm -f "$depfile"

  if test -f "$tmpdepfile"; then  # yes, the sourcefile depend on other files
    echo "$object : \\" > "$depfile"

    # Clip off the initial element (the dependent).  Don't try to be
    # clever and replace this with sed code, as IRIX sed won't handle
    # lines with more than a fixed number of characters (4096 in
    # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;
    # the IRIX cc adds comments like `#:fec' to the end of the
    # dependency line.
    tr ' ' '
' < "$tmpdepfile" \
    | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
    tr '
' ' ' >> $depfile
    echo >> $depfile

    # The second pass generates a dummy entry for each header file.
    tr ' ' '
' < "$tmpdepfile" \
   | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
   >> $depfile
  else
    # The sourcefile does not contain any dependencies, so just
    # store a dummy comment line, to avoid errors with the Makefile
    # "include basename.Plo" scheme.
    echo "#dummy" > "$depfile"
  fi
  rm -f "$tmpdepfile"
  ;;

aix)
  # The C for AIX Compiler uses -M and outputs the dependencies
  # in a .u file.  In older versions, this file always lives in the
  # current directory.  Also, the AIX compiler puts `$object:' at the
  # start of each line; $object doesn't have directory information.
  # Version 6 uses the directory in both cases.
  stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'`
  tmpdepfile="$stripped.u"
  if test "$libtool" = yes; then
    "$@" -Wc,-M
  else
    "$@" -M
  fi
  stat=$?

  if test -f "$tmpdepfile"; then :
  else
    stripped=`echo "$stripped" | sed 's,^.*/,,'`
    tmpdepfile="$stripped.u"
  fi

  if test $stat -eq 0; then :
  else
    rm -f "$tmpdepfile"
    exit $stat
  fi

  if test -f "$tmpdepfile"; then
    outname="$stripped.o"
    # Each line is of the form `foo.o: dependent.h'.
    # Do two passes, one to just change these to
    # `$object: dependent.h' and one to simply `dependent.h:'.
    sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
    sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
  else
    # The sourcefile does not contain any dependencies, so just
    # store a dummy comment line, to avoid errors with the Makefile
    # "include basename.Plo" scheme.
    echo "#dummy" > "$depfile"
  fi
  rm -f "$tmpdepfile"
  ;;

icc)
  # Intel's C compiler understands `-MD -MF file'.  However on
  #    icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
  # ICC 7.0 will fill foo.d with something like
  #    foo.o: sub/foo.c
  #    foo.o: sub/foo.h
  # which is wrong.  We want:
  #    sub/foo.o: sub/foo.c
  #    sub/foo.o: sub/foo.h
  #    sub/foo.c:
  #    sub/foo.h:
  # ICC 7.1 will output
  #    foo.o: sub/foo.c sub/foo.h
  # and will wrap long lines using \ :
  #    foo.o: sub/foo.c ... \
  #     sub/foo.h ... \
  #     ...

  "$@" -MD -MF "$tmpdepfile"
  stat=$?
  if test $stat -eq 0; then :
  else
    rm -f "$tmpdepfile"
    exit $stat
  fi
  rm -f "$depfile"
  # Each line is of the form `foo.o: dependent.h',
  # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
  # Do two passes, one to just change these to
  # `$object: dependent.h' and one to simply `dependent.h:'.
  sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
  # Some versions of the HPUX 10.20 sed can't process this invocation
  # correctly.  Breaking it into two sed invocations is a workaround.
  sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
    sed -e 's/$/ :/' >> "$depfile"
  rm -f "$tmpdepfile"
  ;;

tru64)
   # The Tru64 compiler uses -MD to generate dependencies as a side
   # effect.  `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
   # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
   # dependencies in `foo.d' instead, so we check for that too.
   # Subdirectories are respected.
   dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
   test "x$dir" = "x$object" && dir=
   base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`

   if test "$libtool" = yes; then
      # With Tru64 cc, shared objects can also be used to make a
      # static library.  This mecanism is used in libtool 1.4 series to
      # handle both shared and static libraries in a single compilation.
      # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
      #
      # With libtool 1.5 this exception was removed, and libtool now
      # generates 2 separate objects for the 2 libraries.  These two
      # compilations output dependencies in in $dir.libs/$base.o.d and
      # in $dir$base.o.d.  We have to check for both files, because
      # one of the two compilations can be disabled.  We should prefer
      # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
      # automatically cleaned when .libs/ is deleted, while ignoring
      # the former would cause a distcleancheck panic.
      tmpdepfile1=$dir.libs/$base.lo.d   # libtool 1.4
      tmpdepfile2=$dir$base.o.d          # libtool 1.5
      tmpdepfile3=$dir.libs/$base.o.d    # libtool 1.5
      tmpdepfile4=$dir.libs/$base.d      # Compaq CCC V6.2-504
      "$@" -Wc,-MD
   else
      tmpdepfile1=$dir$base.o.d
      tmpdepfile2=$dir$base.d
      tmpdepfile3=$dir$base.d
      tmpdepfile4=$dir$base.d
      "$@" -MD
   fi

   stat=$?
   if test $stat -eq 0; then :
   else
      rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
      exit $stat
   fi

   for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
   do
     test -f "$tmpdepfile" && break
   done
   if test -f "$tmpdepfile"; then
      sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
      # That's a tab and a space in the [].
      sed -e 's,^.*\.[a-z]*:[	 ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
   else
      echo "#dummy" > "$depfile"
   fi
   rm -f "$tmpdepfile"
   ;;

#nosideeffect)
  # This comment above is used by automake to tell side-effect
  # dependency tracking mechanisms from slower ones.

dashmstdout)
  # Important note: in order to support this mode, a compiler *must*
  # always write the preprocessed file to stdout, regardless of -o.
  "$@" || exit $?

  # Remove the call to Libtool.
  if test "$libtool" = yes; then
    while test $1 != '--mode=compile'; do
      shift
    done
    shift
  fi

  # Remove `-o $object'.
  IFS=" "
  for arg
  do
    case $arg in
    -o)
      shift
      ;;
    $object)
      shift
      ;;
    *)
      set fnord "$@" "$arg"
      shift # fnord
      shift # $arg
      ;;
    esac
  done

  test -z "$dashmflag" && dashmflag=-M
  # Require at least two characters before searching for `:'
  # in the target name.  This is to cope with DOS-style filenames:
  # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
  "$@" $dashmflag |
    sed 's:^[  ]*[^: ][^:][^:]*\:[    ]*:'"$object"'\: :' > "$tmpdepfile"
  rm -f "$depfile"
  cat < "$tmpdepfile" > "$depfile"
  tr ' ' '
' < "$tmpdepfile" | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly.  Breaking it into two sed invocations is a workaround.
    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
  rm -f "$tmpdepfile"
  ;;

dashXmstdout)
  # This case only exists to satisfy depend.m4.  It is never actually
  # run, as this mode is specially recognized in the preamble.
  exit 1
  ;;

makedepend)
  "$@" || exit $?
  # Remove any Libtool call
  if test "$libtool" = yes; then
    while test $1 != '--mode=compile'; do
      shift
    done
    shift
  fi
  # X makedepend
  shift
  cleared=no
  for arg in "$@"; do
    case $cleared in
    no)
      set ""; shift
      cleared=yes ;;
    esac
    case "$arg" in
    -D*|-I*)
      set fnord "$@" "$arg"; shift ;;
    # Strip any option that makedepend may not understand.  Remove
    # the object too, otherwise makedepend will parse it as a source file.
    -*|$object)
      ;;
    *)
      set fnord "$@" "$arg"; shift ;;
    esac
  done
  obj_suffix="`echo $object | sed 's/^.*\././'`"
  touch "$tmpdepfile"
  ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
  rm -f "$depfile"
  cat < "$tmpdepfile" > "$depfile"
  sed '1,2d' "$tmpdepfile" | tr ' ' '
' | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly.  Breaking it into two sed invocations is a workaround.
    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
  rm -f "$tmpdepfile" "$tmpdepfile".bak
  ;;

cpp)
  # Important note: in order to support this mode, a compiler *must*
  # always write the preprocessed file to stdout.
  "$@" || exit $?

  # Remove the call to Libtool.
  if test "$libtool" = yes; then
    while test $1 != '--mode=compile'; do
      shift
    done
    shift
  fi

  # Remove `-o $object'.
  IFS=" "
  for arg
  do
    case $arg in
    -o)
      shift
      ;;
    $object)
      shift
      ;;
    *)
      set fnord "$@" "$arg"
      shift # fnord
      shift # $arg
      ;;
    esac
  done

  "$@" -E |
    sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
       -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
    sed '$ s: \\$::' > "$tmpdepfile"
  rm -f "$depfile"
  echo "$object : \\" > "$depfile"
  cat < "$tmpdepfile" >> "$depfile"
  sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
  rm -f "$tmpdepfile"
  ;;

msvisualcpp)
  # Important note: in order to support this mode, a compiler *must*
  # always write the preprocessed file to stdout, regardless of -o,
  # because we must use -o when running libtool.
  "$@" || exit $?
  IFS=" "
  for arg
  do
    case "$arg" in
    "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
	set fnord "$@"
	shift
	shift
	;;
    *)
	set fnord "$@" "$arg"
	shift
	shift
	;;
    esac
  done
  "$@" -E |
  sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
  rm -f "$depfile"
  echo "$object : \\" > "$depfile"
  . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::	\1 \\:p' >> "$depfile"
  echo "	" >> "$depfile"
  . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
  rm -f "$tmpdepfile"
  ;;

none)
  exec "$@"
  ;;

*)
  echo "Unknown depmode $depmode" 1>&2
  exit 1
  ;;
esac

exit 0

# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:


================================================
FILE: distro/google-perftools-1.7/doc/cpuprofile-fileformat.html
================================================




  
  Google CPU Profiler Binary Data File Format




Google CPU Profiler Binary Data File Format

Last modified

This file documents the binary data file format produced by the Google CPU Profiler. For information about using the CPU Profiler, see its user guide.

The profiler source code, which generates files using this format, is at src/profiler.cc.

CPU Profile Data File Structure

CPU profile data files each consist of four parts, in order:

  • Binary header
  • Binary profile records
  • Binary trailer
  • Text list of mapped objects

The binary data is expressed in terms of "slots." These are words large enough to hold the program's pointer type, i.e., for 32-bit programs they are 4 bytes in size, and for 64-bit programs they are 8 bytes. They are stored in the profile data file in the native byte order (i.e., little-endian for x86 and x86_64).

Binary Header

The binary header format is show below. Values written by the profiler, along with requirements currently enforced by the analysis tools, are shown in parentheses.

slot data
0 header count (0; must be 0)
1 header slots after this one (3; must be >= 3)
2 format version (0; must be 0)
3 sampling period, in microseconds
4 padding (0)

The headers currently generated for 32-bit and 64-bit little-endian (x86 and x86_64) profiles are shown below, for comparison.

hdr count hdr words version sampling period pad
32-bit or 64-bit (slots) 0 3 0 10000 0
32-bit (4-byte words in file) 0x00000 0x00003 0x00000 0x02710 0x00000
64-bit LE (4-byte words in file) 0x00000 0x00000 0x00003 0x00000 0x00000 0x00000 0x02710 0x00000 0x00000 0x00000

The contents are shown in terms of slots, and in terms of 4-byte words in the profile data file. The slot contents for 32-bit and 64-bit headers are identical. For 32-bit profiles, the 4-byte word view matches the slot view. For 64-bit profiles, each (8-byte) slot is shown as two 4-byte words, ordered as they would appear in the file.

The profiling tools examine the contents of the file and use the expected locations and values of the header words field to detect whether the file is 32-bit or 64-bit.

Binary Profile Records

The binary profile record format is shown below.

slot data
0 sample count, must be >= 1
1 number of call chain PCs (num_pcs), must be >= 1
2 .. (num_pcs + 1) call chain PCs, most-recently-called function first.

The total length of a given record is 2 + num_pcs.

Note that multiple profile records can be emitted by the profiler having an identical call chain. In that case, analysis tools should sum the counts of all records having identical call chains.

Note: Some profile analysis tools terminate if they see any profile record with a call chain with its first entry having the address 0. (This is similar to the binary trailer.)

Example

This example shows the slots contained in a sample profile record.

5 3 0xa0000 0xc0000 0xe0000

In this example, 5 ticks were received at PC 0xa0000, whose function had been called by the function containing 0xc0000, which had been called from the function containing 0xe0000.

Binary Trailer

The binary trailer consists of three slots of data with fixed values, shown below.

slot value
0 0
1 1
2 0

Note that this is the same data that would contained in a profile record with sample count = 0, num_pcs = 1, and a one-element call chain containing the address 0.

Text List of Mapped Objects

The binary data in the file is followed immediately by a list of mapped objects. This list consists of lines of text separated by newline characters.

Each line is one of the following types:

  • Build specifier, starting with "build=". For example:
      build=/path/to/binary
    Leading spaces on the line are ignored.
  • Mapping line from ProcMapsIterator::FormatLine. For example:
      40000000-40015000 r-xp 00000000 03:01 12845071   /lib/ld-2.3.2.so
    The first address must start at the beginning of the line.

Unrecognized lines should be ignored by analysis tools.

When processing the paths see in mapping lines, occurrences of $build followed by a non-word character (i.e., characters other than underscore or alphanumeric characters), should be replaced by the path given on the last build specifier line.


Chris Demetriou
Last modified: Mon Aug 27 12:18:26 PDT 2007 (cgd)
================================================ FILE: distro/google-perftools-1.7/doc/cpuprofile.html ================================================ Google CPU Profiler

Last modified

This is the CPU profiler we use at Google. There are three parts to using it: linking the library into an application, running the code, and analyzing the output.

On the off-chance that you should need to understand it, the CPU profiler data file format is documented separately, here.

Linking in the Library

To install the CPU profiler into your executable, add -lprofiler to the link-time step for your executable. (It's also probably possible to add in the profiler at run-time using LD_PRELOAD, e.g. % env LD_PRELOAD="/usr/lib/libprofiler.so" <binary>, but this isn't necessarily recommended.)

This does not turn on CPU profiling; it just inserts the code. For that reason, it's practical to just always link -lprofiler into a binary while developing; that's what we do at Google. (However, since any user can turn on the profiler by setting an environment variable, it's not necessarily recommended to install profiler-linked binaries into a production, running system.)

Running the Code

There are several alternatives to actually turn on CPU profiling for a given run of an executable:

  1. Define the environment variable CPUPROFILE to the filename to dump the profile to. For instance, to profile /usr/local/bin/my_binary_compiled_with_libprofiler_so:

    % env CPUPROFILE=/tmp/mybin.prof /usr/local/bin/my_binary_compiled_with_libprofiler_so
  2. In your code, bracket the code you want profiled in calls to ProfilerStart() and ProfilerStop(). (These functions are declared in <google/profiler.h>.) ProfilerStart() will take the profile-filename as an argument.

In Linux 2.6 and above, profiling works correctly with threads, automatically profiling all threads. In Linux 2.4, profiling only profiles the main thread (due to a kernel bug involving itimers and threads). Profiling works correctly with sub-processes: each child process gets its own profile with its own name (generated by combining CPUPROFILE with the child's process id).

For security reasons, CPU profiling will not write to a file -- and is thus not usable -- for setuid programs.

See the include-file google/profiler.h for advanced-use functions, including ProfilerFlush() and ProfilerStartWithOptions().

Modifying Runtime Behavior

You can more finely control the behavior of the CPU profiler via environment variables.

CPUPROFILE_FREQUENCY=x default: 100 How many interrupts/second the cpu-profiler samples.
CPUPROFILE_REALTIME=1 default: [not set] If set to any value (including 0 or the empty string), use ITIMER_REAL instead of ITIMER_PROF to gather profiles. In general, ITIMER_REAL is not as accurate as ITIMER_PROF, and also interacts badly with use of alarm(), so prefer ITIMER_PROF unless you have a reason prefer ITIMER_REAL.

Analyzing the Output

pprof is the script used to analyze a profile. It has many output modes, both textual and graphical. Some give just raw numbers, much like the -pg output of gcc, and others show the data in the form of a dependency graph.

pprof requires perl5 to be installed to run. It also requires dot to be installed for any of the graphical output routines, and gv to be installed for --gv mode (described below).

Here are some ways to call pprof. These are described in more detail below.

% pprof /bin/ls ls.prof
                       Enters "interactive" mode
% pprof --text /bin/ls ls.prof
                       Outputs one line per procedure
% pprof --gv /bin/ls ls.prof
                       Displays annotated call-graph via 'gv'
% pprof --gv --focus=Mutex /bin/ls ls.prof
                       Restricts to code paths including a .*Mutex.* entry
% pprof --gv --focus=Mutex --ignore=string /bin/ls ls.prof
                       Code paths including Mutex but not string
% pprof --list=getdir /bin/ls ls.prof
                       (Per-line) annotated source listing for getdir()
% pprof --disasm=getdir /bin/ls ls.prof
                       (Per-PC) annotated disassembly for getdir()
% pprof --text localhost:1234
                       Outputs one line per procedure for localhost:1234
% pprof --callgrind /bin/ls ls.prof
                       Outputs the call information in callgrind format

Analyzing Text Output

Text mode has lines of output that look like this:

       14   2.1%  17.2%       58   8.7% std::_Rb_tree::find

Here is how to interpret the columns:

  1. Number of profiling samples in this function
  2. Percentage of profiling samples in this function
  3. Percentage of profiling samples in the functions printed so far
  4. Number of profiling samples in this function and its callees
  5. Percentage of profiling samples in this function and its callees
  6. Function name

Analyzing Callgrind Output

Use kcachegrind to analyze your callgrind output:

% pprof --callgrind /bin/ls ls.prof > ls.callgrind
% kcachegrind ls.callgrind

The cost is specified in 'hits', i.e. how many times a function appears in the recorded call stack information. The 'calls' from function a to b record how many times function b was found in the stack traces directly below function a.

Tip: if you use a debug build the output will include file and line number information and kcachegrind will show an annotated source code view.

Node Information

In the various graphical modes of pprof, the output is a call graph annotated with timing information, like so:

Each node represents a procedure. The directed edges indicate caller to callee relations. Each node is formatted as follows:

Class Name
Method Name
local (percentage)
of cumulative (percentage)

The last one or two lines contains the timing information. (The profiling is done via a sampling method, where by default we take 100 samples a second. Therefor one unit of time in the output corresponds to about 10 milliseconds of execution time.) The "local" time is the time spent executing the instructions directly contained in the procedure (and in any other procedures that were inlined into the procedure). The "cumulative" time is the sum of the "local" time and the time spent in any callees. If the cumulative time is the same as the local time, it is not printed.

For instance, the timing information for test_main_thread() indicates that 155 units (about 1.55 seconds) were spent executing the code in test_main_thread() and 200 units were spent while executing test_main_thread() and its callees such as snprintf().

The size of the node is proportional to the local count. The percentage displayed in the node corresponds to the count divided by the total run time of the program (that is, the cumulative count for main()).

Edge Information

An edge from one node to another indicates a caller to callee relationship. Each edge is labelled with the time spent by the callee on behalf of the caller. E.g, the edge from test_main_thread() to snprintf() indicates that of the 200 samples in test_main_thread(), 37 are because of calls to snprintf().

Note that test_main_thread() has an edge to vsnprintf(), even though test_main_thread() doesn't call that function directly. This is because the code was compiled with -O2; the profile reflects the optimized control flow.

Meta Information

The top of the display should contain some meta information like:

      /tmp/profiler2_unittest
      Total samples: 202
      Focusing on: 202
      Dropped nodes with <= 1 abs(samples)
      Dropped edges with <= 0 samples

This section contains the name of the program, and the total samples collected during the profiling run. If the --focus option is on (see the Focus section below), the legend also contains the number of samples being shown in the focused display. Furthermore, some unimportant nodes and edges are dropped to reduce clutter. The characteristics of the dropped nodes and edges are also displayed in the legend.

Focus and Ignore

You can ask pprof to generate a display focused on a particular piece of the program. You specify a regular expression. Any portion of the call-graph that is on a path which contains at least one node matching the regular expression is preserved. The rest of the call-graph is dropped on the floor. For example, you can focus on the vsnprintf() libc call in profiler2_unittest as follows:

% pprof --gv --focus=vsnprintf /tmp/profiler2_unittest test.prof

Similarly, you can supply the --ignore option to ignore samples that match a specified regular expression. E.g., if you are interested in everything except calls to snprintf(), you can say:

% pprof --gv --ignore=snprintf /tmp/profiler2_unittest test.prof

Interactive mode

By default -- if you don't specify any flags to the contrary -- pprof runs in interactive mode. At the (pprof) prompt, you can run many of the commands described above. You can type help for a list of what commands are available in interactive mode.

pprof Options

For a complete list of pprof options, you can run pprof --help.

Output Type

--text Produces a textual listing. (Note: If you have an X display, and dot and gv installed, you will probably be happier with the --gv output.)
--gv Generates annotated call-graph, converts to postscript, and displays via gv (requres dot and gv be installed).
--dot Generates the annotated call-graph in dot format and emits to stdout (requres dot be installed).
--ps Generates the annotated call-graph in Postscript format and emits to stdout (requres dot be installed).
--pdf Generates the annotated call-graph in PDF format and emits to stdout (requires dot and ps2pdf be installed).
--gif Generates the annotated call-graph in GIF format and emits to stdout (requres dot be installed).
--list=<regexp>

Outputs source-code listing of routines whose name matches <regexp>. Each line in the listing is annotated with flat and cumulative sample counts.

In the presence of inlined calls, the samples associated with inlined code tend to get assigned to a line that follows the location of the inlined call. A more precise accounting can be obtained by disassembling the routine using the --disasm flag.

--disasm=<regexp> Generates disassembly of routines that match <regexp>, annotated with flat and cumulative sample counts and emits to stdout.

Reporting Granularity

By default, pprof produces one entry per procedure. However you can use one of the following options to change the granularity of the output. The --files option seems to be particularly useless, and may be removed eventually.

--addresses Produce one node per program address.
--lines Produce one node per source line.
--functions Produce one node per function (this is the default).
--files Produce one node per source file.

Controlling the Call Graph Display

Some nodes and edges are dropped to reduce clutter in the output display. The following options control this effect:

--nodecount=<n> This option controls the number of displayed nodes. The nodes are first sorted by decreasing cumulative count, and then only the top N nodes are kept. The default value is 80.
--nodefraction=<f> This option provides another mechanism for discarding nodes from the display. If the cumulative count for a node is less than this option's value multiplied by the total count for the profile, the node is dropped. The default value is 0.005; i.e. nodes that account for less than half a percent of the total time are dropped. A node is dropped if either this condition is satisfied, or the --nodecount condition is satisfied.
--edgefraction=<f> This option controls the number of displayed edges. First of all, an edge is dropped if either its source or destination node is dropped. Otherwise, the edge is dropped if the sample count along the edge is less than this option's value multiplied by the total count for the profile. The default value is 0.001; i.e., edges that account for less than 0.1% of the total time are dropped.
--focus=<re> This option controls what region of the graph is displayed based on the regular expression supplied with the option. For any path in the callgraph, we check all nodes in the path against the supplied regular expression. If none of the nodes match, the path is dropped from the output.
--ignore=<re> This option controls what region of the graph is displayed based on the regular expression supplied with the option. For any path in the callgraph, we check all nodes in the path against the supplied regular expression. If any of the nodes match, the path is dropped from the output.

The dropped edges and nodes account for some count mismatches in the display. For example, the cumulative count for snprintf() in the first diagram above was 41. However the local count (1) and the count along the outgoing edges (12+1+20+6) add up to only 40.

Caveats

  • If the program exits because of a signal, the generated profile will be incomplete, and may perhaps be completely empty.
  • The displayed graph may have disconnected regions because of the edge-dropping heuristics described above.
  • If the program linked in a library that was not compiled with enough symbolic information, all samples associated with the library may be charged to the last symbol found in the program before the library. This will artificially inflate the count for that symbol.
  • If you run the program on one machine, and profile it on another, and the shared libraries are different on the two machines, the profiling output may be confusing: samples that fall within shared libaries may be assigned to arbitrary procedures.
  • If your program forks, the children will also be profiled (since they inherit the same CPUPROFILE setting). Each process is profiled separately; to distinguish the child profiles from the parent profile and from each other, all children will have their process-id appended to the CPUPROFILE name.
  • Due to a hack we make to work around a possible gcc bug, your profiles may end up named strangely if the first character of your CPUPROFILE variable has ascii value greater than 127. This should be exceedingly rare, but if you need to use such a name, just set prepend ./ to your filename: CPUPROFILE=./Ägypten.

Sanjay Ghemawat
Last modified: Fri May 9 14:41:29 PDT 2008
================================================ FILE: distro/google-perftools-1.7/doc/designstyle.css ================================================ body { background-color: #ffffff; color: black; margin-right: 1in; margin-left: 1in; } h1, h2, h3, h4, h5, h6 { color: #3366ff; font-family: sans-serif; } @media print { /* Darker version for printing */ h1, h2, h3, h4, h5, h6 { color: #000080; font-family: helvetica, sans-serif; } } h1 { text-align: center; font-size: 18pt; } h2 { margin-left: -0.5in; } h3 { margin-left: -0.25in; } h4 { margin-left: -0.125in; } hr { margin-left: -1in; } /* Definition lists: definition term bold */ dt { font-weight: bold; } address { text-align: right; } /* Use the tag for bits of code and for variables and objects. */ code,pre,samp,var { color: #006000; } /* Use the tag for file and directory paths and names. */ file { color: #905050; font-family: monospace; } /* Use the tag for stuff the user should type. */ kbd { color: #600000; } div.note p { float: right; width: 3in; margin-right: 0%; padding: 1px; border: 2px solid #6060a0; background-color: #fffff0; } UL.nobullets { list-style-type: none; list-style-image: none; margin-left: -1em; } /* body:after { content: "Google Confidential"; } */ /* pretty printing styles. See prettify.js */ .str { color: #080; } .kwd { color: #008; } .com { color: #800; } .typ { color: #606; } .lit { color: #066; } .pun { color: #660; } .pln { color: #000; } .tag { color: #008; } .atn { color: #606; } .atv { color: #080; } pre.prettyprint { padding: 2px; border: 1px solid #888; } .embsrc { background: #eee; } @media print { .str { color: #060; } .kwd { color: #006; font-weight: bold; } .com { color: #600; font-style: italic; } .typ { color: #404; font-weight: bold; } .lit { color: #044; } .pun { color: #440; } .pln { color: #000; } .tag { color: #006; font-weight: bold; } .atn { color: #404; } .atv { color: #060; } } /* Table Column Headers */ .hdr { color: #006; font-weight: bold; background-color: #dddddd; } .hdr2 { color: #006; background-color: #eeeeee; } ================================================ FILE: distro/google-perftools-1.7/doc/heap_checker.html ================================================ Google Heap Leak Checker

Last modified

This is the heap checker we use at Google to detect memory leaks in C++ programs. There are three parts to using it: linking the library into an application, running the code, and analyzing the output.

Linking in the Library

The heap-checker is part of tcmalloc, so to install the heap checker into your executable, add -ltcmalloc to the link-time step for your executable. Also, while we don't necessarily recommend this form of usage, it's possible to add in the profiler at run-time using LD_PRELOAD:

% env LD_PRELOAD="/usr/lib/libtcmalloc.so" 

This does not turn on heap checking; it just inserts the code. For that reason, it's practical to just always link -ltcmalloc into a binary while developing; that's what we do at Google. (However, since any user can turn on the profiler by setting an environment variable, it's not necessarily recommended to install heapchecker-linked binaries into a production, running system.) Note that if you wish to use the heap checker, you must also use the tcmalloc memory-allocation library. There is no way currently to use the heap checker separate from tcmalloc.

Running the Code

Note: For security reasons, heap profiling will not write to a file -- and is thus not usable -- for setuid programs.

Whole-program Heap Leak Checking

The recommended way to use the heap checker is in "whole program" mode. In this case, the heap-checker starts tracking memory allocations before the start of main(), and checks again at program-exit. If it finds any memory leaks -- that is, any memory not pointed to by objects that are still "live" at program-exit -- it aborts the program (via exit(1)) and prints a message describing how to track down the memory leak (using pprof).

The heap-checker records the stack trace for each allocation while it is active. This causes a significant increase in memory usage, in addition to slowing your program down.

Here's how to run a program with whole-program heap checking:

  1. Define the environment variable HEAPCHECK to the type of heap-checking to do. For instance, to heap-check /usr/local/bin/my_binary_compiled_with_tcmalloc:

    % env HEAPCHECK=normal /usr/local/bin/my_binary_compiled_with_tcmalloc

No other action is required.

Note that since the heap-checker uses the heap-profiling framework internally, it is not possible to run both the heap-checker and heap profiler at the same time.

Flavors of Heap Checking

These are the legal values when running a whole-program heap check:

  1. minimal
  2. normal
  3. strict
  4. draconian

"Minimal" heap-checking starts as late as possible in a initialization, meaning you can leak some memory in your initialization routines (that run before main(), say), and not trigger a leak message. If you frequently (and purposefully) leak data in one-time global initializers, "minimal" mode is useful for you. Otherwise, you should avoid it for stricter modes.

"Normal" heap-checking tracks live objects and reports a leak for any data that is not reachable via a live object when the program exits.

"Strict" heap-checking is much like "normal" but has a few extra checks that memory isn't lost in global destructors. In particular, if you have a global variable that allocates memory during program execution, and then "forgets" about the memory in the global destructor (say, by setting the pointer to it to NULL) without freeing it, that will prompt a leak message in "strict" mode, though not in "normal" mode.

"Draconian" heap-checking is appropriate for those who like to be very precise about their memory management, and want the heap-checker to help them enforce it. In "draconian" mode, the heap-checker does not do "live object" checking at all, so it reports a leak unless all allocated memory is freed before program exit. (However, you can use IgnoreObject() to re-enable liveness-checking on an object-by-object basis.)

"Normal" mode, as the name implies, is the one used most often at Google. It's appropriate for everyday heap-checking use.

In addition, there are two other possible modes:

  • as-is
  • local

as-is is the most flexible mode; it allows you to specify the various knobs of the heap checker explicitly. local activates the explicit heap-check instrumentation, but does not turn on any whole-program leak checking.

Tweaking whole-program checking

In some cases you want to check the whole program for memory leaks, but waiting for after main() exits to do the first whole-program leak check is waiting too long: e.g. in a long-running server one might wish to simply periodically check for leaks while the server is running. In this case, you can call the static method NoGlobalLeaks(), to verify no global leaks have happened as of that point in the program.

Alternately, doing the check after main() exits might be too late. Perhaps you have some objects that are known not to clean up properly at exit. You'd like to do the "at exit" check before those objects are destroyed (since while they're live, any memory they point to will not be considered a leak). In that case, you can call NoGlobalLeaks() manually, near the end of main(), and then call CancelGlobalCheck() to turn off the automatic post-main() check.

Finally, there's a helper macro for "strict" and "draconian" modes, which require all global memory to be freed before program exit. This freeing can be time-consuming and is often unnecessary, since libc cleans up all memory at program-exit for you. If you want the benefits of "strict"/"draconian" modes without the cost of all that freeing, look at REGISTER_HEAPCHECK_CLEANUP (in heap-checker.h). This macro allows you to mark specific cleanup code as active only when the heap-checker is turned on.

Explicit (Partial-program) Heap Leak Checking

Instead of whole-program checking, you can check certain parts of your code to verify they do not have memory leaks. This check verifies that between two parts of a program, no memory is allocated without being freed.

To use this kind of checking code, bracket the code you want checked by creating a HeapLeakChecker object at the beginning of the code segment, and call NoLeaks() at the end. These functions, and all others referred to in this file, are declared in <google/heap-checker.h>.

Here's an example:

  HeapLeakChecker heap_checker("test_foo");
  {
    code that exercises some foo functionality;
    this code should not leak memory;
  }
  if (!heap_checker.NoLeaks()) assert(NULL == "heap memory leak");

Note that adding in the HeapLeakChecker object merely instruments the code for leak-checking. To actually turn on this leak-checking on a particular run of the executable, you must still run with the heap-checker turned on:

% env HEAPCHECK=local /usr/local/bin/my_binary_compiled_with_tcmalloc

If you want to do whole-program leak checking in addition to this manual leak checking, you can run in normal or some other mode instead: they'll run the "local" checks in addition to the whole-program check.

Disabling Heap-checking of Known Leaks

Sometimes your code has leaks that you know about and are willing to accept. You would like the heap checker to ignore them when checking your program. You can do this by bracketing the code in question with an appropriate heap-checking construct:

   ...
   {
     HeapLeakChecker::Disabler disabler;
     <leaky code>
   }
   ...
Any objects allocated by leaky code (including inside any routines called by leaky code) and any objects reachable from such objects are not reported as leaks.

Alternately, you can use IgnoreObject(), which takes a pointer to an object to ignore. That memory, and everything reachable from it (by following pointers), is ignored for the purposes of leak checking. You can call UnIgnoreObject() to undo the effects of IgnoreObject().

Tuning the Heap Checker

The heap leak checker has many options, some that trade off running time and accuracy, and others that increase the sensitivity at the risk of returning false positives. For most uses, the range covered by the heap-check flavors is enough, but in specialized cases more control can be helpful.

These options are specified via environment varaiables.

This first set of options controls sensitivity and accuracy. These options are ignored unless you run the heap checker in as-is mode.
HEAP_CHECK_AFTER_DESTRUCTORS Default: false When true, do the final leak check after all other global destructors have run. When false, do it after all REGISTER_HEAPCHECK_CLEANUP, typically much earlier in the global-destructor process.
HEAP_CHECK_IGNORE_THREAD_LIVE Default: true If true, ignore objects reachable from thread stacks and registers (that is, do not report them as leaks).
HEAP_CHECK_IGNORE_GLOBAL_LIVE Default: true If true, ignore objects reachable from global variables and data (that is, do not report them as leaks).

These options modify the behavior of whole-program leak checking.

HEAP_CHECK_MAX_LEAKS Default: 20 The maximum number of leaks to be printed to stderr (all leaks are still emitted to file output for pprof to visualize). If negative or zero, print all the leaks found.

These options apply to all types of leak checking.

HEAP_CHECK_IDENTIFY_LEAKS Default: false If true, generate the addresses of the leaked objects in the generated memory leak profile files.
HEAP_CHECK_TEST_POINTER_ALIGNMENT Default: false If true, check all leaks to see if they might be due to the use of unaligned pointers.
HEAP_CHECK_POINTER_SOURCE_ALIGNMENT Default: sizeof(void*) Alignment at which all pointers in memory are supposed to be located. Use 1 if any alignment is ok.
PPROF_PATH Default: pprof The location of the pprof executable.
HEAP_CHECK_DUMP_DIRECTORY Default: /tmp Where the heap-profile files are kept while the program is running.

Tips for Handling Detected Leaks

What do you do when the heap leak checker detects a memory leak? First, you should run the reported pprof command; hopefully, that is enough to track down the location where the leak occurs.

If the leak is a real leak, you should fix it!

If you are sure that the reported leaks are not dangerous and there is no good way to fix them, then you can use HeapLeakChecker::Disabler and/or HeapLeakChecker::IgnoreObject() to disable heap-checking for certain parts of the codebase.

In "strict" or "draconian" mode, leaks may be due to incomplete cleanup in the destructors of global variables. If you don't wish to augment the cleanup routines, but still want to run in "strict" or "draconian" mode, consider using REGISTER_HEAPCHECK_CLEANUP.

Hints for Debugging Detected Leaks

Sometimes it can be useful to not only know the exact code that allocates the leaked objects, but also the addresses of the leaked objects. Combining this e.g. with additional logging in the program one can then track which subset of the allocations made at a certain spot in the code are leaked.
To get the addresses of all leaked objects define the environment variable HEAP_CHECK_IDENTIFY_LEAKS to be 1. The object addresses will be reported in the form of addresses of fake immediate callers of the memory allocation routines. Note that the performance of doing leak-checking in this mode can be noticeably worse than the default mode.

One relatively common class of leaks that don't look real is the case of multiple initialization. In such cases the reported leaks are typically things that are linked from some global objects, which are initialized and say never modified again. The non-obvious cause of the leak is frequently the fact that the initialization code for these objects executes more than once.
E.g. if the code of some .cc file is made to be included twice into the binary, then the constructors for global objects defined in that file will execute twice thus leaking the things allocated on the first run.
Similar problems can occur if object initialization is done more explicitly e.g. on demand by a slightly buggy code that does not always ensure only-once initialization.

A more rare but even more puzzling problem can be use of not properly aligned pointers (maybe inside of not properly aligned objects). Normally such pointers are not followed by the leak checker, hence the objects reachable only via such pointers are reported as leaks. If you suspect this case define the environment variable HEAP_CHECK_TEST_POINTER_ALIGNMENT to be 1 and then look closely at the generated leak report messages.

How It Works

When a HeapLeakChecker object is constructed, it dumps a memory-usage profile named <prefix>.<name>-beg.heap to a temporary directory. When NoLeaks() is called (for whole-program checking, this happens automatically at program-exit), it dumps another profile, named <prefix>.<name>-end.heap. (<prefix> is typically determined automatically, and <name> is typically argv[0].) It then compares the two profiles. If the second profile shows more memory use than the first, the NoLeaks() function will return false. For "whole program" profiling, this will cause the executable to abort (via exit(1)). In all cases, it will print a message on how to process the dumped profiles to locate leaks.

Detecting Live Objects

At any point during a program's execution, all memory that is accessible at that time is considered "live." This includes global variables, and also any memory that is reachable by following pointers from a global variable. It also includes all memory reachable from the current stack frame and from current CPU registers (this captures local variables). Finally, it includes the thread equivalents of these: thread-local storage and thread heaps, memory reachable from thread-local storage and thread heaps, and memory reachable from thread CPU registers.

In all modes except "draconian," live memory is not considered to be a leak. We detect this by doing a liveness flood, traversing pointers to heap objects starting from some initial memory regions we know to potentially contain live pointer data. Note that this flood might potentially not find some (global) live data region to start the flood from. If you find such, please file a bug.

The liveness flood attempts to treat any properly aligned byte sequences as pointers to heap objects and thinks that it found a good pointer whenever the current heap memory map contains an object with the address whose byte representation we found. Some pointers into not-at-start of object will also work here.

As a result of this simple approach, it's possible (though unlikely) for the flood to be inexact and occasionally result in leaked objects being erroneously determined to be live. For instance, random bit patterns can happen to look like pointers to leaked heap objects. More likely, stale pointer data not corresponding to any live program variables can be still present in memory regions, especially in thread stacks. For instance, depending on how the local malloc is implemented, it may reuse a heap object address:

    char* p = new char[1];   // new might return 0x80000000, say.
    delete p;
    new char[1];             // new might return 0x80000000 again
    // This last new is a leak, but doesn't seem it: p looks like it points to it

In other words, imprecisions in the liveness flood mean that for any heap leak check we might miss some memory leaks. This means that for local leak checks, we might report a memory leak in the local area, even though the leak actually happened before the HeapLeakChecker object was constructed. Note that for whole-program checks, a leak report does always correspond to a real leak (since there's no "before" to have created a false-live object).

While this liveness flood approach is not very portable and not 100% accurate, it works in most cases and saves us from writing a lot of explicit clean up code and other hassles when dealing with thread data.

Visualizing Leak with pprof

The heap checker automatically prints basic leak info with stack traces of leaked objects' allocation sites, as well as a pprof command line that can be used to visualize the call-graph involved in these allocations. The latter can be much more useful for a human to see where/why the leaks happened, especially if the leaks are numerous.

Leak-checking and Threads

At the time of HeapLeakChecker's construction and during NoLeaks() calls, we grab a lock and then pause all other threads so other threads do not interfere with recording or analyzing the state of the heap.

In general, leak checking works correctly in the presence of threads. However, thread stack data liveness determination (via base/thread_lister.h) does not work when the program is running under GDB, because the ptrace functionality needed for finding threads is already hooked to by GDB. Conversely, leak checker's ptrace attempts might also interfere with GDB. As a result, GDB can result in potentially false leak reports. For this reason, the heap-checker turns itself off when running under GDB.

Also, thread_lister only works for Linux pthreads; leak checking is unlikely to handle other thread implementations correctly.

As mentioned in the discussion of liveness flooding, thread-stack liveness determination might mis-classify as reachable objects that very recently became unreachable (leaked). This can happen when the pointers to now-logically-unreachable objects are present in the active thread stack frame. In other words, trivial code like the following might not produce the expected leak checking outcome depending on how the compiled code works with the stack:

  int* foo = new int [20];
  HeapLeakChecker check("a_check");
  foo = NULL;
  // May fail to trigger.
  if (!heap_checker.NoLeaks()) assert(NULL == "heap memory leak");

Maxim Lifantsev
Last modified: Fri Jul 13 13:14:33 PDT 2007
================================================ FILE: distro/google-perftools-1.7/doc/heapprofile.html ================================================ Google Heap Profiler

Last modified

This is the heap profiler we use at Google, to explore how C++ programs manage memory. This facility can be useful for

  • Figuring out what is in the program heap at any given time
  • Locating memory leaks
  • Finding places that do a lot of allocation

The profiling system instruments all allocations and frees. It keeps track of various pieces of information per allocation site. An allocation site is defined as the active stack trace at the call to malloc, calloc, realloc, or, new.

There are three parts to using it: linking the library into an application, running the code, and analyzing the output.

Linking in the Library

To install the heap profiler into your executable, add -ltcmalloc to the link-time step for your executable. Also, while we don't necessarily recommend this form of usage, it's possible to add in the profiler at run-time using LD_PRELOAD:

% env LD_PRELOAD="/usr/lib/libtcmalloc.so" <binary>

This does not turn on heap profiling; it just inserts the code. For that reason, it's practical to just always link -ltcmalloc into a binary while developing; that's what we do at Google. (However, since any user can turn on the profiler by setting an environment variable, it's not necessarily recommended to install profiler-linked binaries into a production, running system.) Note that if you wish to use the heap profiler, you must also use the tcmalloc memory-allocation library. There is no way currently to use the heap profiler separate from tcmalloc.

Running the Code

There are several alternatives to actually turn on heap profiling for a given run of an executable:

  1. Define the environment variable HEAPPROFILE to the filename to dump the profile to. For instance, to profile /usr/local/bin/my_binary_compiled_with_tcmalloc:

    % env HEAPPROFILE=/tmp/mybin.hprof /usr/local/bin/my_binary_compiled_with_tcmalloc
  2. In your code, bracket the code you want profiled in calls to HeapProfilerStart() and HeapProfilerStop(). (These functions are declared in <google/heap-profiler.h>.) HeapProfilerStart() will take the profile-filename-prefix as an argument. Then, as often as you'd like before calling HeapProfilerStop(), you can use HeapProfilerDump() or GetHeapProfile() to examine the profile. In case it's useful, IsHeapProfilerRunning() will tell you whether you've already called HeapProfilerStart() or not.

For security reasons, heap profiling will not write to a file -- and is thus not usable -- for setuid programs.

Modifying Runtime Behavior

You can more finely control the behavior of the heap profiler via environment variables.

HEAP_PROFILE_ALLOCATION_INTERVAL default: 1073741824 (1 Gb) Dump heap profiling information once every specified number of bytes has been allocated by the program.
HEAP_PROFILE_INUSE_INTERVAL default: 104857600 (100 Mb) Dump heap profiling information whenever the high-water memory usage mark increases by the specified number of bytes.
HEAP_PROFILE_MMAP default: false Profile mmap, mremap and sbrk calls in addition to malloc, calloc, realloc, and new. NOTE: this causes the profiler to profile calls internal to tcmalloc, since tcmalloc and friends use mmap and sbrk internally for allocations. One partial solution is to filter these allocations out when running pprof, with something like pprof --ignore='DoAllocWithArena|SbrkSysAllocator::Alloc|MmapSysAllocator::Alloc.
HEAP_PROFILE_MMAP_ONLY default: false Only profile mmap, mremap, and sbrk calls; do not profile malloc, calloc, realloc, or new.
HEAP_PROFILE_MMAP_LOG default: false Log mmap/munmap calls.

Checking for Leaks

You can use the heap profiler to manually check for leaks, for instance by reading the profiler output and looking for large allocations. However, for that task, it's easier to use the automatic heap-checking facility built into tcmalloc.

Analyzing the Output

If heap-profiling is turned on in a program, the program will periodically write profiles to the filesystem. The sequence of profiles will be named:

           <prefix>.0000.heap
           <prefix>.0001.heap
           <prefix>.0002.heap
           ...

where <prefix> is the filename-prefix supplied when running the code (e.g. via the HEAPPROFILE environment variable). Note that if the supplied prefix does not start with a /, the profile files will be written to the program's working directory.

The profile output can be viewed by passing it to the pprof tool -- the same tool that's used to analyze CPU profiles.

Here are some examples. These examples assume the binary is named gfs_master, and a sequence of heap profile files can be found in files named:

  /tmp/profile.0001.heap
  /tmp/profile.0002.heap
  ...
  /tmp/profile.0100.heap

Why is a process so big

    % pprof --gv gfs_master /tmp/profile.0100.heap

This command will pop-up a gv window that displays the profile information as a directed graph. Here is a portion of the resulting output:

A few explanations:
  • GFS_MasterChunk::AddServer accounts for 255.6 MB of the live memory, which is 25% of the total live memory.
  • GFS_MasterChunkTable::UpdateState is directly accountable for 176.2 MB of the live memory (i.e., it directly allocated 176.2 MB that has not been freed yet). Furthermore, it and its callees are responsible for 729.9 MB. The labels on the outgoing edges give a good indication of the amount allocated by each callee.

Comparing Profiles

You often want to skip allocations during the initialization phase of a program so you can find gradual memory leaks. One simple way to do this is to compare two profiles -- both collected after the program has been running for a while. Specify the name of the first profile using the --base option. For example:

   % pprof --base=/tmp/profile.0004.heap gfs_master /tmp/profile.0100.heap

The memory-usage in /tmp/profile.0004.heap will be subtracted from the memory-usage in /tmp/profile.0100.heap and the result will be displayed.

Text display

% pprof --text gfs_master /tmp/profile.0100.heap
   255.6  24.7%  24.7%    255.6  24.7% GFS_MasterChunk::AddServer
   184.6  17.8%  42.5%    298.8  28.8% GFS_MasterChunkTable::Create
   176.2  17.0%  59.5%    729.9  70.5% GFS_MasterChunkTable::UpdateState
   169.8  16.4%  75.9%    169.8  16.4% PendingClone::PendingClone
    76.3   7.4%  83.3%     76.3   7.4% __default_alloc_template::_S_chunk_alloc
    49.5   4.8%  88.0%     49.5   4.8% hashtable::resize
   ...

  • The first column contains the direct memory use in MB.
  • The fourth column contains memory use by the procedure and all of its callees.
  • The second and fifth columns are just percentage representations of the numbers in the first and fourth columns.
  • The third column is a cumulative sum of the second column (i.e., the kth entry in the third column is the sum of the first k entries in the second column.)

Ignoring or focusing on specific regions

The following command will give a graphical display of a subset of the call-graph. Only paths in the call-graph that match the regular expression DataBuffer are included:

% pprof --gv --focus=DataBuffer gfs_master /tmp/profile.0100.heap

Similarly, the following command will omit all paths subset of the call-graph. All paths in the call-graph that match the regular expression DataBuffer are discarded:

% pprof --gv --ignore=DataBuffer gfs_master /tmp/profile.0100.heap

Total allocations + object-level information

All of the previous examples have displayed the amount of in-use space. I.e., the number of bytes that have been allocated but not freed. You can also get other types of information by supplying a flag to pprof:

--inuse_space Display the number of in-use megabytes (i.e. space that has been allocated but not freed). This is the default.
--inuse_objects Display the number of in-use objects (i.e. number of objects that have been allocated but not freed).
--alloc_space Display the number of allocated megabytes. This includes the space that has since been de-allocated. Use this if you want to find the main allocation sites in the program.
--alloc_objects Display the number of allocated objects. This includes the objects that have since been de-allocated. Use this if you want to find the main allocation sites in the program.

Interactive mode

By default -- if you don't specify any flags to the contrary -- pprof runs in interactive mode. At the (pprof) prompt, you can run many of the commands described above. You can type help for a list of what commands are available in interactive mode.

Caveats

  • Heap profiling requires the use of libtcmalloc. This requirement may be removed in a future version of the heap profiler, and the heap profiler separated out into its own library.
  • If the program linked in a library that was not compiled with enough symbolic information, all samples associated with the library may be charged to the last symbol found in the program before the libary. This will artificially inflate the count for that symbol.
  • If you run the program on one machine, and profile it on another, and the shared libraries are different on the two machines, the profiling output may be confusing: samples that fall within the shared libaries may be assigned to arbitrary procedures.
  • Several libraries, such as some STL implementations, do their own memory management. This may cause strange profiling results. We have code in libtcmalloc to cause STL to use tcmalloc for memory management (which in our tests is better than STL's internal management), though it only works for some STL implementations.
  • If your program forks, the children will also be profiled (since they inherit the same HEAPPROFILE setting). Each process is profiled separately; to distinguish the child profiles from the parent profile and from each other, all children will have their process-id attached to the HEAPPROFILE name.
  • Due to a hack we make to work around a possible gcc bug, your profiles may end up named strangely if the first character of your HEAPPROFILE variable has ascii value greater than 127. This should be exceedingly rare, but if you need to use such a name, just set prepend ./ to your filename: HEAPPROFILE=./Ägypten.

Sanjay Ghemawat
Last modified: Sat Feb 24 14:33:15 PST 2007 (csilvers)
================================================ FILE: distro/google-perftools-1.7/doc/index.html ================================================ Google Performance Tools
Last modified: Wed Mar 21 22:46:51 PDT 2007 ================================================ FILE: distro/google-perftools-1.7/doc/overview.dot ================================================ digraph Overview { node [shape = box] {rank=same T1 [label="Thread Cache"] Tsep [label="...", shape=plaintext] Tn [label="Thread Cache"] T1 -> Tsep -> Tn [style=invis] } C [label="Central\nHeap"] T1 -> C [dir=both] Tn -> C [dir=both] } ================================================ FILE: distro/google-perftools-1.7/doc/pageheap.dot ================================================ digraph PageHeap { rankdir=LR node [shape=box, width=0.3, height=0.3] nodesep=.05 heap [shape=record, height=3, label="1 page|2 pages|3 pages|...|255 pages|rest"] O0 [shape=record, label=""] O1 [shape=record, label=""] O2 [shape=record, label="{|}"] O3 [shape=record, label="{|}"] O4 [shape=record, label="{||}"] O5 [shape=record, label="{||}"] O6 [shape=record, label="{|...|}"] O7 [shape=record, label="{|...|}"] O8 [shape=record, label="{|.....|}"] O9 [shape=record, label="{|.....|}"] sep1 [shape=plaintext, label="..."] sep2 [shape=plaintext, label="..."] sep3 [shape=plaintext, label="..."] sep4 [shape=plaintext, label="..."] sep5 [shape=plaintext, label="..."] heap:f0 -> O0 -> O1 -> sep1 heap:f1 -> O2 -> O3 -> sep2 heap:f2 -> O4 -> O5 -> sep3 heap:f255 -> O6 -> O7 -> sep4 heap:frest -> O8 -> O9 -> sep5 } ================================================ FILE: distro/google-perftools-1.7/doc/pprof.1 ================================================ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.23. .TH PPROF "1" "February 2005" "pprof (part of google-perftools)" Google .SH NAME pprof \- manual page for pprof (part of google-perftools) .SH SYNOPSIS .B pprof [\fIoptions\fR] \fI \fR .SH DESCRIPTION .IP Prints specified cpu- or heap-profile .SH OPTIONS .TP \fB\-\-cum\fR Sort by cumulative data .TP \fB\-\-base=\fR Subtract from before display .SS "Reporting Granularity:" .TP \fB\-\-addresses\fR Report at address level .TP \fB\-\-lines\fR Report at source line level .TP \fB\-\-functions\fR Report at function level [default] .TP \fB\-\-files\fR Report at source file level .SS "Output type:" .TP \fB\-\-text\fR Generate text report [default] .TP \fB\-\-gv\fR Generate Postscript and display .TP \fB\-\-list=\fR Generate source listing of matching routines .TP \fB\-\-disasm=\fR Generate disassembly of matching routines .TP \fB\-\-dot\fR Generate DOT file to stdout .TP \fB\-\-ps\fR Generate Postcript to stdout .TP \fB\-\-pdf\fR Generate PDF to stdout .TP \fB\-\-gif\fR Generate GIF to stdout .SS "Heap-Profile Options:" .TP \fB\-\-inuse_space\fR Display in-use (mega)bytes [default] .TP \fB\-\-inuse_objects\fR Display in-use objects .TP \fB\-\-alloc_space\fR Display allocated (mega)bytes .TP \fB\-\-alloc_objects\fR Display allocated objects .TP \fB\-\-show_bytes\fR Display space in bytes .TP \fB\-\-drop_negative\fR Ignore negaive differences .SS "Call-graph Options:" .TP \fB\-\-nodecount=\fR Show at most so many nodes [default=80] .TP \fB\-\-nodefraction=\fR Hide nodes below *total [default=.005] .TP \fB\-\-edgefraction=\fR Hide edges below *total [default=.001] .TP \fB\-\-focus=\fR Focus on nodes matching .TP \fB\-\-ignore=\fR Ignore nodes matching .TP \fB\-\-scale=\fR Set GV scaling [default=0] .SH EXAMPLES pprof /bin/ls ls.prof .IP Outputs one line per procedure .PP pprof \fB\-\-gv\fR /bin/ls ls.prof .IP Displays annotated call-graph via 'gv' .PP pprof \fB\-\-gv\fR \fB\-\-focus\fR=\fIMutex\fR /bin/ls ls.prof .IP Restricts to code paths including a .*Mutex.* entry .PP pprof \fB\-\-gv\fR \fB\-\-focus\fR=\fIMutex\fR \fB\-\-ignore\fR=\fIstring\fR /bin/ls ls.prof .IP Code paths including Mutex but not string .PP pprof \fB\-\-list\fR=\fIgetdir\fR /bin/ls ls.prof .IP Dissassembly (with per-line annotations) for getdir() .PP pprof \fB\-\-disasm\fR=\fIgetdir\fR /bin/ls ls.prof .IP Dissassembly (with per-PC annotations) for getdir() .SH COPYRIGHT Copyright \(co 2005 Google Inc. .SH "SEE ALSO" Further documentation for .B pprof is maintained as a web page called .B cpu_profiler.html and is likely installed at one of the following locations: .IP .B /usr/share/google-perftools/cpu_profiler.html .br .B /usr/local/share/google-perftools/cpu_profiler.html .PP ================================================ FILE: distro/google-perftools-1.7/doc/pprof_remote_servers.html ================================================ pprof and Remote Servers

pprof and Remote Servers

In mid-2006, we added an experimental facility to pprof, the tool that analyzes CPU and heap profiles. This facility allows you to collect profile information from running applications. It makes it easy to collect profile information without having to stop the program first, and without having to log into the machine where the application is running. This is meant to be used on webservers, but will work on any application that can be modified to accept TCP connections on a port of its choosing, and to respond to HTTP requests on that port.

We do not currently have infrastructure, such as apache modules, that you can pop into a webserver or other application to get the necessary functionality "for free." However, it's easy to generate the necessary data, which should allow the interested developer to add the necessary support into his or her applications.

To use pprof in this experimental "server" mode, you give the script a host and port it should query, replacing the normal commandline arguments of application + profile file:

   % pprof internalweb.mycompany.com:80

The host must be listening on that port, and be able to accept HTTP/1.0 requests -- sent via wget and curl -- for several urls. The following sections list the urls that pprof can send, and the responses it expects in return.

Here are examples that pprof will recognize, when you give them on the commandline, are urls. In general, you specify the host and a port (the port-number is required), and put the service-name at the end of the url.:

http://myhost:80/pprof/heap            # retrieves a heap profile
http://myhost:8008/pprof/profile       # retrieves a CPU profile
http://myhost:80                       # retrieves a CPU profile (the default)
http://myhost:8080/                    # retrieves a CPU profile (the default)
myhost:8088/pprof/growth               # "http://" is optional, but port is not
http://myhost:80/myservice/pprof/heap  # /pprof/heap just has to come at the end
http://myhost:80/pprof/pmuprofile      # CPU profile using performance counters

/pprof/heap

pprof asks for the url /pprof/heap to get heap information. The actual url is controlled via the variable HEAP_PAGE in the pprof script, so you can change it if you'd like.

There are two ways to get this data. The first is to call

    MallocExtension::instance()->GetHeapSample(&output);

and have the server send output back as an HTTP response to pprof. MallocExtension is defined in the header file google/malloc_extension.h.

Note this will only only work if the binary is being run with sampling turned on (which is not the default). To do this, set the environment variable TCMALLOC_SAMPLE_PARAMETER to a positive value, such as 524288, before running.

The other way is to call HeapProfileStart(filename) (from heap-profiler.h), continue to do work, and then, some number of seconds later, call GetHeapProfile() (followed by HeapProfilerStop()). The server can send the output of GetHeapProfile back as the HTTP response to pprof. (Note you must free() this data after using it.) This is similar to how profile requests are handled, below. This technique does not require the application to run with sampling turned on.

Here's an example of what the output should look like:

heap profile:   1923: 127923432 [  1923: 127923432] @ heap_v2/524288
     1:      312 [     1:      312] @ 0x2aaaabaf5ccc 0x2aaaaba4cd2c 0x2aaaac08c09a
   928: 122586016 [   928: 122586016] @ 0x2aaaabaf682c 0x400680 0x400bdd 0x2aaaab1c368a 0x2aaaab1c8f77 0x2aaaab1c0396 0x2aaaab1c86ed 0x4007ff 0x2aaaaca62afa
     1:       16 [     1:       16] @ 0x2aaaabaf5ccc 0x2aaaabb04bac 0x2aaaabc1b262 0x2aaaabc21496 0x2aaaabc214bb
[...]

Older code may produce "version 1" heap profiles which look like this:

heap profile:  14933: 791700132 [ 14933: 791700132] @ heap
     1:   848688 [     1:   848688] @ 0xa4b142 0x7f5bfc 0x87065e 0x4056e9 0x4125f8 0x42b4f1 0x45b1ba 0x463248 0x460871 0x45cb7c 0x5f1744 0x607cee 0x5f4a5e 0x40080f 0x2aaaabad7afa
     1:  1048576 [     1:  1048576] @ 0xa4a9b2 0x7fd025 0x4ca6d8 0x4ca814 0x4caa88 0x2aaaab104cf0 0x404e20 0x4125f8 0x42b4f1 0x45b1ba 0x463248 0x460871 0x45cb7c 0x5f1744 0x607cee 0x5f4a5e 0x40080f 0x2aaaabad7afa
  2942: 388629374 [  2942: 388629374] @ 0xa4b142 0x4006a0 0x400bed 0x5f0cfa 0x5f1744 0x607cee 0x5f4a5e 0x40080f 0x2aaaabad7afa
[...]

pprof accepts both old and new heap profiles and automatically detects which one you are using.

/pprof/growth

pprof asks for the url /pprof/growth to get heap-profiling delta (growth) information. The actual url is controlled via the variable GROWTH_PAGE in the pprof script, so you can change it if you'd like.

The server should respond by calling

    MallocExtension::instance()->GetHeapGrowthStacks(&output);

and sending output back as an HTTP response to pprof. MallocExtension is defined in the header file google/malloc_extension.h.

Here's an example, from an actual Google webserver, of what the output should look like:

heap profile:    741: 812122112 [   741: 812122112] @ growth
     1:  1572864 [     1:  1572864] @ 0x87da564 0x87db8a3 0x84787a4 0x846e851 0x836d12f 0x834cd1c 0x8349ba5 0x10a3177 0x8349961
     1:  1048576 [     1:  1048576] @ 0x87d92e8 0x87d9213 0x87d9178 0x87d94d3 0x87da9da 0x8a364ff 0x8a437e7 0x8ab7d23 0x8ab7da9 0x8ac7454 0x8348465 0x10a3161 0x8349961
[...]

/pprof/profile

pprof asks for the url /pprof/profile?seconds=XX to get cpu-profiling information. The actual url is controlled via the variable PROFILE_PAGE in the pprof script, so you can change it if you'd like.

The server should respond by calling ProfilerStart(filename), continuing to do its work, and then, XX seconds later, calling ProfilerStop(). (These functions are declared in google/profiler.h.) The application is responsible for picking a unique filename for ProfilerStart(). After calling ProfilerStop(), the server should read the contents of filename and send them back as an HTTP response to pprof.

Obviously, to get useful profile information the application must continue to run in the XX seconds that the profiler is running. Thus, the profile start-stop calls should be done in a separate thread, or be otherwise non-blocking.

The profiler output file is binary, but near the end of it, it should have lines of text somewhat like this:

01016000-01017000 rw-p 00015000 03:01 59314      /lib/ld-2.2.2.so

/pprof/pmuprofile

pprof asks for a url of the form /pprof/pmuprofile?event=hw_event:unit_mask&period=nnn&seconds=xxx to get cpu-profiling information. The actual url is controlled via the variable PMUPROFILE_PAGE in the pprof script, so you can change it if you'd like.

This is similar to pprof, but is meant to be used with your CPU's hardware performance counters. The server could be implemented on top of a library such as libpfm. It should collect a sample every nnn occurences of the event and stop the sampling after xxx seconds. Much of the code for /pprof/profile can be reused for this purpose.

The server side routines (the equivalent of ProfilerStart/ProfilerStart) are not available as part of perftools, so this URL is unlikely to be that useful.

/pprof/contention

This is intended to be able to profile (thread) lock contention in addition to CPU and memory use. It's not yet usable.

/pprof/cmdline

pprof asks for the url /pprof/cmdline to figure out what application it's profiling. The actual url is controlled via the variable PROGRAM_NAME_PAGE in the pprof script, so you can change it if you'd like.

The server should respond by reading the contents of /proc/self/cmdline, converting all internal NUL (\0) characters to newlines, and sending the result back as an HTTP response to pprof.

Here's an example return value:

/root/server/custom_webserver
80
--configfile=/root/server/ws.config

/pprof/symbol

pprof asks for the url /pprof/symbol to map from hex addresses to variable names. The actual url is controlled via the variable SYMBOL_PAGE in the pprof script, so you can change it if you'd like.

When the server receives a GET request for /pprof/symbol, it should return a line formatted like so:

   num_symbols: ###

where ### is the number of symbols found in the binary. (For now, the only important distinction is whether the value is 0, which it is for executables that lack debug information, or not-0).

This is perhaps the hardest request to write code for, because in addition to the GET request for this url, the server must accept POST requests. This means that after the HTTP headers, pprof will pass in a list of hex addresses connected by +, like so:

   curl -d '0x0824d061+0x0824d1cf' http://remote_host:80/pprof/symbol

The server should read the POST data, which will be in one line, and for each hex value, should write one line of output to the output stream, like so:

<hex address><tab><function name>

For instance:

0x08b2dabd    _Update

The other reason this is the most difficult request to implement, is that the application will have to figure out for itself how to map from address to function name. One possibility is to run nm -C -n <program name> to get the mappings at program-compile-time. Another, at least on Linux, is to call out to addr2line for every pprof/symbol call, for instance addr2line -Cfse /proc//exe 0x12345678 0x876543210 (presumably with some caching!)

pprof itself does just this for local profiles (not ones that talk to remote servers); look at the subroutine GetProcedureBoundaries.


Last modified: Mon Jun 12 21:30:14 PDT 2006 ================================================ FILE: distro/google-perftools-1.7/doc/spanmap.dot ================================================ digraph SpanMap { node [shape=box, width=0.3, height=0.3] nodesep=.05 map [shape=record, width=6, label="||||||||||"] S0 [label="a"] S1 [label="b"] S2 [label="c"] S3 [label="d"] map:f0 -> S0 map:f1 -> S0 map:f2 -> S1 map:f3 -> S2 map:f4 -> S2 map:f5 -> S2 map:f6 -> S2 map:f7 -> S2 map:f8 -> S3 map:f9 -> S3 map:f10 -> S3 } ================================================ FILE: distro/google-perftools-1.7/doc/t-test1.times.txt ================================================ time.1.ptmalloc.64:0.56 user 0.02 system 0.57 elapsed 100% CPU time.1.tcmalloc.64:0.38 user 0.02 system 0.40 elapsed 98% CPU time.1.ptmalloc.128:0.61 user 0.01 system 0.61 elapsed 101% CPU time.1.tcmalloc.128:0.35 user 0.00 system 0.35 elapsed 99% CPU time.1.ptmalloc.256:0.59 user 0.01 system 0.60 elapsed 100% CPU time.1.tcmalloc.256:0.27 user 0.02 system 0.28 elapsed 102% CPU time.1.ptmalloc.512:0.57 user 0.00 system 0.57 elapsed 100% CPU time.1.tcmalloc.512:0.25 user 0.01 system 0.25 elapsed 101% CPU time.1.ptmalloc.1024:0.52 user 0.00 system 0.52 elapsed 99% CPU time.1.tcmalloc.1024:0.22 user 0.02 system 0.24 elapsed 97% CPU time.1.ptmalloc.2048:0.47 user 0.00 system 0.47 elapsed 99% CPU time.1.tcmalloc.2048:0.22 user 0.02 system 0.25 elapsed 95% CPU time.1.ptmalloc.4096:0.48 user 0.01 system 0.48 elapsed 100% CPU time.1.tcmalloc.4096:0.25 user 0.01 system 0.25 elapsed 100% CPU time.1.ptmalloc.8192:0.49 user 0.02 system 0.49 elapsed 102% CPU time.1.tcmalloc.8192:0.27 user 0.02 system 0.28 elapsed 101% CPU time.1.ptmalloc.16384:0.51 user 0.04 system 0.55 elapsed 99% CPU time.1.tcmalloc.16384:0.35 user 0.02 system 0.37 elapsed 100% CPU time.1.ptmalloc.32768:0.53 user 0.14 system 0.66 elapsed 100% CPU time.1.tcmalloc.32768:0.67 user 0.02 system 0.69 elapsed 99% CPU time.1.ptmalloc.65536:0.68 user 0.31 system 0.98 elapsed 100% CPU time.1.tcmalloc.65536:0.71 user 0.01 system 0.72 elapsed 99% CPU time.1.ptmalloc.131072:0.90 user 0.72 system 1.62 elapsed 99% CPU time.1.tcmalloc.131072:0.94 user 0.03 system 0.97 elapsed 99% CPU time.2.ptmalloc.64:1.05 user 0.00 system 0.53 elapsed 196% CPU time.2.tcmalloc.64:0.66 user 0.03 system 0.37 elapsed 185% CPU time.2.ptmalloc.128:1.77 user 0.01 system 0.89 elapsed 198% CPU time.2.tcmalloc.128:0.53 user 0.01 system 0.29 elapsed 184% CPU time.2.ptmalloc.256:1.14 user 0.01 system 0.62 elapsed 182% CPU time.2.tcmalloc.256:0.45 user 0.02 system 0.26 elapsed 180% CPU time.2.ptmalloc.512:1.26 user 0.40 system 1.79 elapsed 92% CPU time.2.tcmalloc.512:0.43 user 0.02 system 0.27 elapsed 166% CPU time.2.ptmalloc.1024:0.98 user 0.03 system 0.56 elapsed 179% CPU time.2.tcmalloc.1024:0.44 user 0.02 system 0.34 elapsed 134% CPU time.2.ptmalloc.2048:0.87 user 0.02 system 0.44 elapsed 199% CPU time.2.tcmalloc.2048:0.49 user 0.02 system 0.34 elapsed 148% CPU time.2.ptmalloc.4096:0.92 user 0.03 system 0.48 elapsed 196% CPU time.2.tcmalloc.4096:0.50 user 0.02 system 0.49 elapsed 105% CPU time.2.ptmalloc.8192:1.05 user 0.04 system 0.55 elapsed 196% CPU time.2.tcmalloc.8192:0.59 user 0.01 system 0.51 elapsed 116% CPU time.2.ptmalloc.16384:1.30 user 0.14 system 0.72 elapsed 198% CPU time.2.tcmalloc.16384:0.63 user 0.03 system 0.68 elapsed 96% CPU time.2.ptmalloc.32768:1.33 user 0.56 system 1.00 elapsed 189% CPU time.2.tcmalloc.32768:1.16 user 0.01 system 1.17 elapsed 99% CPU time.2.ptmalloc.65536:1.86 user 1.79 system 2.01 elapsed 181% CPU time.2.tcmalloc.65536:1.35 user 0.01 system 1.35 elapsed 100% CPU time.2.ptmalloc.131072:2.61 user 5.19 system 4.81 elapsed 162% CPU time.2.tcmalloc.131072:1.86 user 0.04 system 1.90 elapsed 100% CPU time.3.ptmalloc.64:1.79 user 0.03 system 0.67 elapsed 268% CPU time.3.tcmalloc.64:1.58 user 0.04 system 0.62 elapsed 260% CPU time.3.ptmalloc.128:2.77 user 1.34 system 3.07 elapsed 133% CPU time.3.tcmalloc.128:1.19 user 0.01 system 0.50 elapsed 236% CPU time.3.ptmalloc.256:2.14 user 0.02 system 0.85 elapsed 252% CPU time.3.tcmalloc.256:0.96 user 0.01 system 0.41 elapsed 236% CPU time.3.ptmalloc.512:3.37 user 1.31 system 3.33 elapsed 140% CPU time.3.tcmalloc.512:0.93 user 0.04 system 0.39 elapsed 243% CPU time.3.ptmalloc.1024:1.66 user 0.01 system 0.64 elapsed 260% CPU time.3.tcmalloc.1024:0.81 user 0.02 system 0.44 elapsed 187% CPU time.3.ptmalloc.2048:2.07 user 0.01 system 0.82 elapsed 252% CPU time.3.tcmalloc.2048:1.10 user 0.04 system 0.59 elapsed 191% CPU time.3.ptmalloc.4096:2.01 user 0.03 system 0.79 elapsed 258% CPU time.3.tcmalloc.4096:0.87 user 0.03 system 0.65 elapsed 137% CPU time.3.ptmalloc.8192:2.22 user 0.11 system 0.83 elapsed 280% CPU time.3.tcmalloc.8192:0.96 user 0.06 system 0.75 elapsed 135% CPU time.3.ptmalloc.16384:2.56 user 0.47 system 1.02 elapsed 295% CPU time.3.tcmalloc.16384:0.99 user 0.04 system 1.03 elapsed 99% CPU time.3.ptmalloc.32768:3.29 user 1.75 system 1.96 elapsed 256% CPU time.3.tcmalloc.32768:1.67 user 0.02 system 1.69 elapsed 99% CPU time.3.ptmalloc.65536:4.04 user 6.62 system 4.92 elapsed 216% CPU time.3.tcmalloc.65536:1.91 user 0.02 system 1.98 elapsed 97% CPU time.3.ptmalloc.131072:5.55 user 17.86 system 12.44 elapsed 188% CPU time.3.tcmalloc.131072:2.78 user 0.02 system 2.82 elapsed 99% CPU time.4.ptmalloc.64:3.42 user 1.36 system 3.20 elapsed 149% CPU time.4.tcmalloc.64:2.42 user 0.02 system 0.71 elapsed 341% CPU time.4.ptmalloc.128:3.98 user 1.79 system 3.89 elapsed 148% CPU time.4.tcmalloc.128:1.87 user 0.02 system 0.58 elapsed 325% CPU time.4.ptmalloc.256:4.06 user 2.14 system 4.12 elapsed 150% CPU time.4.tcmalloc.256:1.69 user 0.02 system 0.51 elapsed 331% CPU time.4.ptmalloc.512:4.48 user 2.15 system 4.39 elapsed 150% CPU time.4.tcmalloc.512:1.62 user 0.03 system 0.52 elapsed 314% CPU time.4.ptmalloc.1024:3.18 user 0.03 system 0.84 elapsed 381% CPU time.4.tcmalloc.1024:1.53 user 0.02 system 0.56 elapsed 274% CPU time.4.ptmalloc.2048:3.24 user 0.02 system 0.84 elapsed 384% CPU time.4.tcmalloc.2048:1.44 user 0.04 system 0.66 elapsed 221% CPU time.4.ptmalloc.4096:3.50 user 0.04 system 0.91 elapsed 389% CPU time.4.tcmalloc.4096:1.31 user 0.01 system 0.89 elapsed 148% CPU time.4.ptmalloc.8192:6.77 user 3.85 system 4.14 elapsed 256% CPU time.4.tcmalloc.8192:1.20 user 0.05 system 0.97 elapsed 127% CPU time.4.ptmalloc.16384:7.08 user 5.06 system 4.63 elapsed 262% CPU time.4.tcmalloc.16384:1.27 user 0.03 system 1.25 elapsed 103% CPU time.4.ptmalloc.32768:5.57 user 4.22 system 3.31 elapsed 295% CPU time.4.tcmalloc.32768:2.17 user 0.03 system 2.25 elapsed 97% CPU time.4.ptmalloc.65536:6.11 user 15.05 system 9.19 elapsed 230% CPU time.4.tcmalloc.65536:2.51 user 0.02 system 2.57 elapsed 98% CPU time.4.ptmalloc.131072:7.58 user 33.15 system 21.28 elapsed 191% CPU time.4.tcmalloc.131072:3.57 user 0.07 system 3.66 elapsed 99% CPU time.5.ptmalloc.64:4.44 user 2.08 system 4.37 elapsed 148% CPU time.5.tcmalloc.64:2.87 user 0.02 system 0.79 elapsed 361% CPU time.5.ptmalloc.128:4.77 user 2.77 system 5.14 elapsed 146% CPU time.5.tcmalloc.128:2.65 user 0.03 system 0.72 elapsed 367% CPU time.5.ptmalloc.256:5.82 user 2.88 system 5.49 elapsed 158% CPU time.5.tcmalloc.256:2.33 user 0.01 system 0.66 elapsed 352% CPU time.5.ptmalloc.512:6.27 user 3.11 system 5.34 elapsed 175% CPU time.5.tcmalloc.512:2.14 user 0.03 system 0.70 elapsed 307% CPU time.5.ptmalloc.1024:6.82 user 3.18 system 5.23 elapsed 191% CPU time.5.tcmalloc.1024:2.20 user 0.02 system 0.70 elapsed 313% CPU time.5.ptmalloc.2048:6.57 user 3.46 system 5.22 elapsed 192% CPU time.5.tcmalloc.2048:2.15 user 0.03 system 0.82 elapsed 264% CPU time.5.ptmalloc.4096:8.75 user 5.09 system 5.26 elapsed 263% CPU time.5.tcmalloc.4096:1.68 user 0.03 system 1.08 elapsed 158% CPU time.5.ptmalloc.8192:4.48 user 0.61 system 1.51 elapsed 335% CPU time.5.tcmalloc.8192:1.47 user 0.07 system 1.18 elapsed 129% CPU time.5.ptmalloc.16384:5.71 user 1.98 system 2.14 elapsed 358% CPU time.5.tcmalloc.16384:1.58 user 0.03 system 1.52 elapsed 105% CPU time.5.ptmalloc.32768:7.19 user 7.81 system 5.53 elapsed 270% CPU time.5.tcmalloc.32768:2.63 user 0.05 system 2.72 elapsed 98% CPU time.5.ptmalloc.65536:8.45 user 23.51 system 14.30 elapsed 223% CPU time.5.tcmalloc.65536:3.12 user 0.05 system 3.21 elapsed 98% CPU time.5.ptmalloc.131072:10.22 user 43.63 system 27.84 elapsed 193% CPU time.5.tcmalloc.131072:4.42 user 0.07 system 4.51 elapsed 99% CPU time.6.ptmalloc.64:5.57 user 2.56 system 5.08 elapsed 159% CPU time.6.tcmalloc.64:3.20 user 0.01 system 0.89 elapsed 360% CPU time.6.ptmalloc.128:5.98 user 3.52 system 5.71 elapsed 166% CPU time.6.tcmalloc.128:2.76 user 0.02 system 0.78 elapsed 355% CPU time.6.ptmalloc.256:4.61 user 0.02 system 1.19 elapsed 389% CPU time.6.tcmalloc.256:2.65 user 0.02 system 0.74 elapsed 356% CPU time.6.ptmalloc.512:8.28 user 3.88 system 6.61 elapsed 183% CPU time.6.tcmalloc.512:2.60 user 0.02 system 0.72 elapsed 362% CPU time.6.ptmalloc.1024:4.75 user 0.00 system 1.22 elapsed 387% CPU time.6.tcmalloc.1024:2.56 user 0.02 system 0.79 elapsed 325% CPU time.6.ptmalloc.2048:8.90 user 4.59 system 6.15 elapsed 219% CPU time.6.tcmalloc.2048:2.37 user 0.06 system 0.96 elapsed 250% CPU time.6.ptmalloc.4096:11.41 user 7.02 system 6.31 elapsed 291% CPU time.6.tcmalloc.4096:1.82 user 0.03 system 1.19 elapsed 154% CPU time.6.ptmalloc.8192:11.64 user 8.25 system 5.97 elapsed 332% CPU time.6.tcmalloc.8192:1.83 user 0.07 system 1.38 elapsed 136% CPU time.6.ptmalloc.16384:7.44 user 2.98 system 3.01 elapsed 345% CPU time.6.tcmalloc.16384:1.83 user 0.08 system 1.80 elapsed 105% CPU time.6.ptmalloc.32768:8.69 user 12.35 system 8.04 elapsed 261% CPU time.6.tcmalloc.32768:3.14 user 0.06 system 3.24 elapsed 98% CPU time.6.ptmalloc.65536:10.52 user 35.43 system 20.75 elapsed 221% CPU time.6.tcmalloc.65536:3.62 user 0.03 system 3.72 elapsed 98% CPU time.6.ptmalloc.131072:11.74 user 59.00 system 36.93 elapsed 191% CPU time.6.tcmalloc.131072:5.33 user 0.04 system 5.42 elapsed 98% CPU time.7.ptmalloc.64:6.60 user 3.45 system 6.01 elapsed 167% CPU time.7.tcmalloc.64:3.50 user 0.04 system 0.94 elapsed 376% CPU time.7.ptmalloc.128:7.09 user 4.25 system 6.69 elapsed 169% CPU time.7.tcmalloc.128:3.13 user 0.03 system 0.84 elapsed 374% CPU time.7.ptmalloc.256:9.28 user 4.85 system 7.20 elapsed 196% CPU time.7.tcmalloc.256:3.06 user 0.02 system 0.82 elapsed 375% CPU time.7.ptmalloc.512:9.13 user 4.78 system 6.79 elapsed 204% CPU time.7.tcmalloc.512:2.99 user 0.03 system 0.83 elapsed 359% CPU time.7.ptmalloc.1024:10.85 user 6.41 system 7.52 elapsed 229% CPU time.7.tcmalloc.1024:3.05 user 0.04 system 0.89 elapsed 345% CPU time.7.ptmalloc.2048:5.65 user 0.08 system 1.47 elapsed 388% CPU time.7.tcmalloc.2048:3.01 user 0.01 system 0.98 elapsed 306% CPU time.7.ptmalloc.4096:6.09 user 0.08 system 1.58 elapsed 389% CPU time.7.tcmalloc.4096:2.25 user 0.03 system 1.32 elapsed 171% CPU time.7.ptmalloc.8192:6.73 user 0.85 system 1.99 elapsed 379% CPU time.7.tcmalloc.8192:2.22 user 0.08 system 1.61 elapsed 142% CPU time.7.ptmalloc.16384:8.87 user 4.66 system 4.04 elapsed 334% CPU time.7.tcmalloc.16384:2.07 user 0.07 system 2.07 elapsed 103% CPU time.7.ptmalloc.32768:10.61 user 17.85 system 11.22 elapsed 253% CPU time.7.tcmalloc.32768:3.68 user 0.06 system 3.79 elapsed 98% CPU time.7.ptmalloc.65536:13.05 user 45.97 system 27.28 elapsed 216% CPU time.7.tcmalloc.65536:4.16 user 0.07 system 4.31 elapsed 98% CPU time.7.ptmalloc.131072:13.22 user 62.67 system 41.33 elapsed 183% CPU time.7.tcmalloc.131072:6.10 user 0.06 system 6.25 elapsed 98% CPU time.8.ptmalloc.64:7.31 user 3.92 system 6.39 elapsed 175% CPU time.8.tcmalloc.64:4.00 user 0.01 system 1.04 elapsed 383% CPU time.8.ptmalloc.128:9.40 user 5.41 system 7.67 elapsed 192% CPU time.8.tcmalloc.128:3.61 user 0.02 system 0.94 elapsed 386% CPU time.8.ptmalloc.256:10.61 user 6.35 system 7.96 elapsed 212% CPU time.8.tcmalloc.256:3.30 user 0.02 system 0.99 elapsed 335% CPU time.8.ptmalloc.512:12.42 user 7.10 system 8.79 elapsed 221% CPU time.8.tcmalloc.512:3.35 user 0.04 system 0.94 elapsed 358% CPU time.8.ptmalloc.1024:13.63 user 8.54 system 8.95 elapsed 247% CPU time.8.tcmalloc.1024:3.44 user 0.02 system 0.96 elapsed 359% CPU time.8.ptmalloc.2048:6.45 user 0.03 system 1.67 elapsed 386% CPU time.8.tcmalloc.2048:3.55 user 0.05 system 1.09 elapsed 328% CPU time.8.ptmalloc.4096:6.83 user 0.26 system 1.80 elapsed 393% CPU time.8.tcmalloc.4096:2.78 user 0.06 system 1.53 elapsed 185% CPU time.8.ptmalloc.8192:7.59 user 1.29 system 2.36 elapsed 376% CPU time.8.tcmalloc.8192:2.57 user 0.07 system 1.84 elapsed 142% CPU time.8.ptmalloc.16384:10.15 user 6.20 system 5.20 elapsed 314% CPU time.8.tcmalloc.16384:2.40 user 0.05 system 2.42 elapsed 101% CPU time.8.ptmalloc.32768:11.82 user 24.48 system 14.60 elapsed 248% CPU time.8.tcmalloc.32768:4.37 user 0.05 system 4.47 elapsed 98% CPU time.8.ptmalloc.65536:15.41 user 58.94 system 34.42 elapsed 215% CPU time.8.tcmalloc.65536:4.90 user 0.04 system 4.96 elapsed 99% CPU time.8.ptmalloc.131072:16.07 user 82.93 system 52.51 elapsed 188% CPU time.8.tcmalloc.131072:7.13 user 0.04 system 7.19 elapsed 99% CPU time.9.ptmalloc.64:8.44 user 4.59 system 6.92 elapsed 188% CPU time.9.tcmalloc.64:4.00 user 0.02 system 1.05 elapsed 382% CPU time.9.ptmalloc.128:10.92 user 6.14 system 8.31 elapsed 205% CPU time.9.tcmalloc.128:3.88 user 0.02 system 1.01 elapsed 382% CPU time.9.ptmalloc.256:13.01 user 7.75 system 9.12 elapsed 227% CPU time.9.tcmalloc.256:3.89 user 0.01 system 1.00 elapsed 386% CPU time.9.ptmalloc.512:14.96 user 8.89 system 9.73 elapsed 244% CPU time.9.tcmalloc.512:3.80 user 0.03 system 1.01 elapsed 377% CPU time.9.ptmalloc.1024:15.42 user 10.20 system 9.80 elapsed 261% CPU time.9.tcmalloc.1024:3.86 user 0.03 system 1.19 elapsed 325% CPU time.9.ptmalloc.2048:7.24 user 0.02 system 1.87 elapsed 388% CPU time.9.tcmalloc.2048:3.98 user 0.05 system 1.26 elapsed 319% CPU time.9.ptmalloc.4096:7.96 user 0.18 system 2.06 elapsed 394% CPU time.9.tcmalloc.4096:3.27 user 0.04 system 1.69 elapsed 195% CPU time.9.ptmalloc.8192:9.00 user 1.63 system 2.79 elapsed 380% CPU time.9.tcmalloc.8192:3.00 user 0.06 system 2.05 elapsed 148% CPU time.9.ptmalloc.16384:12.07 user 8.13 system 6.55 elapsed 308% CPU time.9.tcmalloc.16384:2.85 user 0.05 system 2.75 elapsed 105% CPU time.9.ptmalloc.32768:13.99 user 29.65 system 18.02 elapsed 242% CPU time.9.tcmalloc.32768:4.98 user 0.06 system 5.13 elapsed 98% CPU time.9.ptmalloc.65536:16.89 user 70.42 system 42.11 elapsed 207% CPU time.9.tcmalloc.65536:5.55 user 0.04 system 5.65 elapsed 98% CPU time.9.ptmalloc.131072:18.53 user 94.11 system 61.17 elapsed 184% CPU time.9.tcmalloc.131072:8.06 user 0.04 system 8.16 elapsed 99% CPU time.10.ptmalloc.64:9.81 user 5.70 system 7.42 elapsed 208% CPU time.10.tcmalloc.64:4.43 user 0.03 system 1.20 elapsed 370% CPU time.10.ptmalloc.128:12.69 user 7.81 system 9.02 elapsed 227% CPU time.10.tcmalloc.128:4.27 user 0.02 system 1.13 elapsed 378% CPU time.10.ptmalloc.256:15.04 user 9.53 system 9.92 elapsed 247% CPU time.10.tcmalloc.256:4.23 user 0.02 system 1.09 elapsed 388% CPU time.10.ptmalloc.512:17.30 user 10.46 system 10.61 elapsed 261% CPU time.10.tcmalloc.512:4.14 user 0.05 system 1.10 elapsed 379% CPU time.10.ptmalloc.1024:16.96 user 9.38 system 9.30 elapsed 283% CPU time.10.tcmalloc.1024:4.27 user 0.06 system 1.18 elapsed 366% CPU time.10.ptmalloc.2048:8.07 user 0.03 system 2.06 elapsed 393% CPU time.10.tcmalloc.2048:4.49 user 0.07 system 1.33 elapsed 342% CPU time.10.ptmalloc.4096:8.66 user 0.25 system 2.25 elapsed 394% CPU time.10.tcmalloc.4096:3.61 user 0.05 system 1.78 elapsed 205% CPU time.10.ptmalloc.8192:21.52 user 17.43 system 10.41 elapsed 374% CPU time.10.tcmalloc.8192:3.59 user 0.10 system 2.33 elapsed 158% CPU time.10.ptmalloc.16384:20.55 user 24.85 system 12.55 elapsed 361% CPU time.10.tcmalloc.16384:3.29 user 0.04 system 3.22 elapsed 103% CPU time.10.ptmalloc.32768:15.23 user 38.13 system 22.49 elapsed 237% CPU time.10.tcmalloc.32768:5.62 user 0.05 system 5.72 elapsed 99% CPU time.10.ptmalloc.65536:19.80 user 85.42 system 49.98 elapsed 210% CPU time.10.tcmalloc.65536:6.23 user 0.09 system 6.36 elapsed 99% CPU time.10.ptmalloc.131072:20.91 user 106.97 system 69.08 elapsed 185% CPU time.10.tcmalloc.131072:8.94 user 0.09 system 9.09 elapsed 99% CPU time.11.ptmalloc.64:10.82 user 6.34 system 7.92 elapsed 216% CPU time.11.tcmalloc.64:4.80 user 0.03 system 1.24 elapsed 387% CPU time.11.ptmalloc.128:14.58 user 8.61 system 9.81 elapsed 236% CPU time.11.tcmalloc.128:4.65 user 0.03 system 1.21 elapsed 384% CPU time.11.ptmalloc.256:17.38 user 10.98 system 10.75 elapsed 263% CPU time.11.tcmalloc.256:4.51 user 0.03 system 1.18 elapsed 384% CPU time.11.ptmalloc.512:19.18 user 11.71 system 10.95 elapsed 282% CPU time.11.tcmalloc.512:4.57 user 0.02 system 1.19 elapsed 384% CPU time.11.ptmalloc.1024:19.94 user 12.41 system 10.48 elapsed 308% CPU time.11.tcmalloc.1024:4.71 user 0.05 system 1.29 elapsed 367% CPU time.11.ptmalloc.2048:8.70 user 0.04 system 2.35 elapsed 371% CPU time.11.tcmalloc.2048:4.97 user 0.07 system 1.43 elapsed 350% CPU time.11.ptmalloc.4096:22.47 user 18.43 system 10.82 elapsed 377% CPU time.11.tcmalloc.4096:4.22 user 0.03 system 1.91 elapsed 221% CPU time.11.ptmalloc.8192:11.61 user 2.38 system 3.73 elapsed 374% CPU time.11.tcmalloc.8192:3.74 user 0.09 system 2.46 elapsed 155% CPU time.11.ptmalloc.16384:14.13 user 13.38 system 9.60 elapsed 286% CPU time.11.tcmalloc.16384:3.61 user 0.03 system 3.63 elapsed 100% CPU time.11.ptmalloc.32768:17.92 user 43.84 system 26.74 elapsed 230% CPU time.11.tcmalloc.32768:6.31 user 0.03 system 6.45 elapsed 98% CPU time.11.ptmalloc.65536:22.40 user 96.38 system 58.30 elapsed 203% CPU time.11.tcmalloc.65536:6.92 user 0.12 system 6.98 elapsed 100% CPU time.11.ptmalloc.131072:21.03 user 108.04 system 72.78 elapsed 177% CPU time.11.tcmalloc.131072:9.79 user 0.08 system 9.94 elapsed 99% CPU time.12.ptmalloc.64:12.23 user 7.16 system 8.38 elapsed 231% CPU time.12.tcmalloc.64:5.21 user 0.05 system 1.41 elapsed 371% CPU time.12.ptmalloc.128:16.97 user 10.19 system 10.47 elapsed 259% CPU time.12.tcmalloc.128:5.10 user 0.02 system 1.31 elapsed 390% CPU time.12.ptmalloc.256:19.99 user 12.10 system 11.57 elapsed 277% CPU time.12.tcmalloc.256:5.01 user 0.03 system 1.29 elapsed 390% CPU time.12.ptmalloc.512:21.85 user 12.66 system 11.46 elapsed 300% CPU time.12.tcmalloc.512:5.05 user 0.00 system 1.32 elapsed 379% CPU time.12.ptmalloc.1024:9.40 user 0.04 system 2.40 elapsed 393% CPU time.12.tcmalloc.1024:5.14 user 0.02 system 1.39 elapsed 369% CPU time.12.ptmalloc.2048:9.72 user 0.04 system 2.49 elapsed 391% CPU time.12.tcmalloc.2048:5.74 user 0.05 system 1.62 elapsed 355% CPU time.12.ptmalloc.4096:10.64 user 0.20 system 2.75 elapsed 393% CPU time.12.tcmalloc.4096:4.45 user 0.03 system 2.04 elapsed 218% CPU time.12.ptmalloc.8192:12.66 user 3.30 system 4.30 elapsed 371% CPU time.12.tcmalloc.8192:4.21 user 0.13 system 2.65 elapsed 163% CPU time.12.ptmalloc.16384:15.73 user 15.68 system 11.14 elapsed 281% CPU time.12.tcmalloc.16384:4.17 user 0.06 system 4.10 elapsed 102% CPU time.12.ptmalloc.32768:19.45 user 56.00 system 32.74 elapsed 230% CPU time.12.tcmalloc.32768:6.96 user 0.08 system 7.14 elapsed 98% CPU time.12.ptmalloc.65536:23.33 user 110.45 system 65.06 elapsed 205% CPU time.12.tcmalloc.65536:7.77 user 0.15 system 7.72 elapsed 102% CPU time.12.ptmalloc.131072:24.03 user 124.74 system 82.94 elapsed 179% CPU time.12.tcmalloc.131072:10.81 user 0.06 system 10.94 elapsed 99% CPU time.13.ptmalloc.64:14.08 user 7.60 system 8.85 elapsed 244% CPU time.13.tcmalloc.64:5.51 user 0.01 system 1.47 elapsed 375% CPU time.13.ptmalloc.128:18.20 user 10.98 system 10.99 elapsed 265% CPU time.13.tcmalloc.128:5.34 user 0.01 system 1.39 elapsed 382% CPU time.13.ptmalloc.256:21.48 user 13.94 system 12.25 elapsed 289% CPU time.13.tcmalloc.256:5.33 user 0.01 system 1.39 elapsed 381% CPU time.13.ptmalloc.512:24.22 user 14.84 system 12.97 elapsed 301% CPU time.13.tcmalloc.512:5.49 user 0.02 system 1.41 elapsed 389% CPU time.13.ptmalloc.1024:25.26 user 17.03 system 12.85 elapsed 328% CPU time.13.tcmalloc.1024:5.65 user 0.04 system 1.50 elapsed 378% CPU time.13.ptmalloc.2048:10.41 user 0.03 system 2.69 elapsed 387% CPU time.13.tcmalloc.2048:5.93 user 0.10 system 1.77 elapsed 339% CPU time.13.ptmalloc.4096:11.37 user 0.52 system 3.04 elapsed 391% CPU time.13.tcmalloc.4096:5.08 user 0.11 system 2.22 elapsed 233% CPU time.13.ptmalloc.8192:21.76 user 18.54 system 10.58 elapsed 380% CPU time.13.tcmalloc.8192:5.04 user 0.16 system 2.93 elapsed 177% CPU time.13.ptmalloc.16384:26.35 user 34.47 system 17.01 elapsed 357% CPU time.13.tcmalloc.16384:4.66 user 0.04 system 4.66 elapsed 100% CPU time.13.ptmalloc.32768:21.41 user 63.59 system 38.14 elapsed 222% CPU time.13.tcmalloc.32768:7.71 user 0.03 system 7.83 elapsed 98% CPU time.13.ptmalloc.65536:24.99 user 120.80 system 71.59 elapsed 203% CPU time.13.tcmalloc.65536:8.87 user 0.64 system 8.37 elapsed 113% CPU time.13.ptmalloc.131072:25.97 user 142.27 system 96.00 elapsed 175% CPU time.13.tcmalloc.131072:11.48 user 0.06 system 11.67 elapsed 98% CPU time.14.ptmalloc.64:15.01 user 9.11 system 9.41 elapsed 256% CPU time.14.tcmalloc.64:5.98 user 0.02 system 1.58 elapsed 378% CPU time.14.ptmalloc.128:20.34 user 12.72 system 11.62 elapsed 284% CPU time.14.tcmalloc.128:5.88 user 0.04 system 1.51 elapsed 392% CPU time.14.ptmalloc.256:24.26 user 14.95 system 12.92 elapsed 303% CPU time.14.tcmalloc.256:5.72 user 0.02 system 1.50 elapsed 381% CPU time.14.ptmalloc.512:27.28 user 16.45 system 13.89 elapsed 314% CPU time.14.tcmalloc.512:5.99 user 0.02 system 1.54 elapsed 388% CPU time.14.ptmalloc.1024:25.84 user 16.99 system 12.61 elapsed 339% CPU time.14.tcmalloc.1024:5.94 user 0.06 system 1.59 elapsed 375% CPU time.14.ptmalloc.2048:11.96 user 0.01 system 3.12 elapsed 382% CPU time.14.tcmalloc.2048:6.39 user 0.07 system 1.79 elapsed 359% CPU time.14.ptmalloc.4096:20.19 user 11.77 system 8.26 elapsed 386% CPU time.14.tcmalloc.4096:5.65 user 0.05 system 2.32 elapsed 244% CPU time.14.ptmalloc.8192:22.01 user 16.39 system 9.89 elapsed 387% CPU time.14.tcmalloc.8192:5.44 user 0.11 system 3.07 elapsed 180% CPU time.14.ptmalloc.16384:18.15 user 22.40 system 15.02 elapsed 269% CPU time.14.tcmalloc.16384:5.29 user 0.08 system 5.34 elapsed 100% CPU time.14.ptmalloc.32768:24.29 user 72.07 system 42.63 elapsed 225% CPU time.14.tcmalloc.32768:8.47 user 0.02 system 8.62 elapsed 98% CPU time.14.ptmalloc.65536:27.63 user 130.56 system 78.64 elapsed 201% CPU time.14.tcmalloc.65536:9.85 user 1.61 system 9.04 elapsed 126% CPU time.14.ptmalloc.131072:28.87 user 146.38 system 100.54 elapsed 174% CPU time.14.tcmalloc.131072:12.46 user 0.11 system 12.71 elapsed 98% CPU time.15.ptmalloc.64:16.25 user 10.05 system 9.82 elapsed 267% CPU time.15.tcmalloc.64:6.30 user 0.02 system 1.64 elapsed 385% CPU time.15.ptmalloc.128:22.33 user 13.23 system 12.24 elapsed 290% CPU time.15.tcmalloc.128:6.08 user 0.03 system 1.59 elapsed 384% CPU time.15.ptmalloc.256:26.56 user 16.57 system 13.70 elapsed 314% CPU time.15.tcmalloc.256:6.14 user 0.03 system 1.61 elapsed 382% CPU time.15.ptmalloc.512:29.68 user 18.08 system 14.56 elapsed 327% CPU time.15.tcmalloc.512:6.12 user 0.04 system 1.68 elapsed 364% CPU time.15.ptmalloc.1024:17.07 user 6.22 system 6.26 elapsed 371% CPU time.15.tcmalloc.1024:6.38 user 0.02 system 1.75 elapsed 364% CPU time.15.ptmalloc.2048:26.64 user 17.25 system 11.51 elapsed 381% CPU time.15.tcmalloc.2048:6.77 user 0.18 system 1.92 elapsed 361% CPU time.15.ptmalloc.4096:13.21 user 0.74 system 3.57 elapsed 390% CPU time.15.tcmalloc.4096:6.03 user 0.09 system 2.36 elapsed 258% CPU time.15.ptmalloc.8192:22.92 user 17.51 system 10.50 elapsed 385% CPU time.15.tcmalloc.8192:5.96 user 0.12 system 3.36 elapsed 180% CPU time.15.ptmalloc.16384:19.37 user 24.87 system 16.69 elapsed 264% CPU time.15.tcmalloc.16384:5.88 user 0.07 system 5.84 elapsed 101% CPU time.15.ptmalloc.32768:25.43 user 82.30 system 48.98 elapsed 219% CPU time.15.tcmalloc.32768:9.11 user 0.05 system 9.30 elapsed 98% CPU time.15.ptmalloc.65536:29.31 user 140.07 system 83.78 elapsed 202% CPU time.15.tcmalloc.65536:8.51 user 1.59 system 9.75 elapsed 103% CPU time.15.ptmalloc.131072:30.22 user 163.15 system 109.50 elapsed 176% CPU time.15.tcmalloc.131072:13.35 user 0.10 system 13.54 elapsed 99% CPU time.16.ptmalloc.64:17.69 user 10.11 system 10.11 elapsed 274% CPU time.16.tcmalloc.64:6.63 user 0.04 system 1.72 elapsed 387% CPU time.16.ptmalloc.128:23.05 user 14.37 system 12.75 elapsed 293% CPU time.16.tcmalloc.128:6.61 user 0.02 system 1.71 elapsed 387% CPU time.16.ptmalloc.256:29.11 user 19.35 system 14.57 elapsed 332% CPU time.16.tcmalloc.256:6.62 user 0.03 system 1.73 elapsed 382% CPU time.16.ptmalloc.512:31.65 user 18.71 system 14.71 elapsed 342% CPU time.16.tcmalloc.512:6.63 user 0.04 system 1.73 elapsed 383% CPU time.16.ptmalloc.1024:31.99 user 21.22 system 14.87 elapsed 357% CPU time.16.tcmalloc.1024:6.81 user 0.04 system 1.79 elapsed 382% CPU time.16.ptmalloc.2048:30.35 user 21.36 system 13.30 elapsed 388% CPU time.16.tcmalloc.2048:6.91 user 0.50 system 2.01 elapsed 367% CPU time.16.ptmalloc.4096:18.85 user 7.18 system 6.61 elapsed 393% CPU time.16.tcmalloc.4096:6.70 user 0.10 system 2.62 elapsed 259% CPU time.16.ptmalloc.8192:22.19 user 14.30 system 9.37 elapsed 389% CPU time.16.tcmalloc.8192:6.18 user 0.19 system 3.58 elapsed 177% CPU time.16.ptmalloc.16384:31.22 user 46.78 system 22.92 elapsed 340% CPU time.16.tcmalloc.16384:6.79 user 0.07 system 6.86 elapsed 99% CPU time.16.ptmalloc.32768:27.31 user 87.32 system 52.00 elapsed 220% CPU time.16.tcmalloc.32768:9.85 user 0.06 system 10.07 elapsed 98% CPU time.16.ptmalloc.65536:32.83 user 160.62 system 95.67 elapsed 202% CPU time.16.tcmalloc.65536:10.18 user 0.09 system 10.41 elapsed 98% CPU time.16.ptmalloc.131072:31.99 user 173.41 system 115.98 elapsed 177% CPU time.16.tcmalloc.131072:14.52 user 0.05 system 14.67 elapsed 99% CPU time.17.ptmalloc.64:19.38 user 11.61 system 10.61 elapsed 291% CPU time.17.tcmalloc.64:7.11 user 0.02 system 1.84 elapsed 386% CPU time.17.ptmalloc.128:26.25 user 16.15 system 13.53 elapsed 313% CPU time.17.tcmalloc.128:6.97 user 0.02 system 1.78 elapsed 390% CPU time.17.ptmalloc.256:30.66 user 18.36 system 14.97 elapsed 327% CPU time.17.tcmalloc.256:6.94 user 0.04 system 1.80 elapsed 387% CPU time.17.ptmalloc.512:33.71 user 22.79 system 15.95 elapsed 354% CPU time.17.tcmalloc.512:7.00 user 0.02 system 1.83 elapsed 381% CPU time.17.ptmalloc.1024:33.49 user 22.47 system 15.00 elapsed 373% CPU time.17.tcmalloc.1024:7.20 user 0.03 system 1.90 elapsed 380% CPU time.17.ptmalloc.2048:23.87 user 11.92 system 9.26 elapsed 386% CPU time.17.tcmalloc.2048:6.01 user 1.83 system 2.15 elapsed 363% CPU time.17.ptmalloc.4096:14.69 user 0.95 system 3.98 elapsed 392% CPU time.17.tcmalloc.4096:7.25 user 0.10 system 2.62 elapsed 279% CPU time.17.ptmalloc.8192:22.44 user 13.52 system 9.39 elapsed 382% CPU time.17.tcmalloc.8192:7.21 user 0.24 system 3.95 elapsed 188% CPU time.17.ptmalloc.16384:23.33 user 33.67 system 21.89 elapsed 260% CPU time.17.tcmalloc.16384:7.28 user 0.06 system 7.10 elapsed 103% CPU time.17.ptmalloc.32768:29.35 user 103.11 system 60.36 elapsed 219% CPU time.17.tcmalloc.32768:10.53 user 0.07 system 10.71 elapsed 98% CPU time.17.ptmalloc.65536:33.21 user 170.89 system 100.84 elapsed 202% CPU time.17.tcmalloc.65536:10.85 user 0.05 system 11.04 elapsed 98% CPU time.17.ptmalloc.131072:34.98 user 182.87 system 122.05 elapsed 178% CPU time.17.tcmalloc.131072:15.27 user 0.09 system 15.49 elapsed 99% CPU time.18.ptmalloc.64:21.08 user 12.15 system 11.43 elapsed 290% CPU time.18.tcmalloc.64:7.45 user 0.03 system 1.95 elapsed 383% CPU time.18.ptmalloc.128:27.65 user 17.26 system 14.03 elapsed 320% CPU time.18.tcmalloc.128:7.46 user 0.03 system 1.92 elapsed 389% CPU time.18.ptmalloc.256:32.78 user 20.55 system 15.70 elapsed 339% CPU time.18.tcmalloc.256:7.31 user 0.02 system 1.88 elapsed 389% CPU time.18.ptmalloc.512:33.31 user 20.06 system 15.05 elapsed 354% CPU time.18.tcmalloc.512:7.33 user 0.02 system 1.91 elapsed 383% CPU time.18.ptmalloc.1024:35.46 user 24.83 system 16.30 elapsed 369% CPU time.18.tcmalloc.1024:7.60 user 0.06 system 2.05 elapsed 373% CPU time.18.ptmalloc.2048:19.98 user 6.80 system 6.76 elapsed 395% CPU time.18.tcmalloc.2048:6.89 user 1.29 system 2.28 elapsed 357% CPU time.18.ptmalloc.4096:15.99 user 0.93 system 4.32 elapsed 391% CPU time.18.tcmalloc.4096:7.70 user 0.10 system 2.77 elapsed 280% CPU time.18.ptmalloc.8192:23.51 user 14.84 system 9.97 elapsed 384% CPU time.18.tcmalloc.8192:8.16 user 0.27 system 4.25 elapsed 197% CPU time.18.ptmalloc.16384:35.79 user 52.41 system 26.47 elapsed 333% CPU time.18.tcmalloc.16384:7.81 user 0.07 system 7.61 elapsed 103% CPU time.18.ptmalloc.32768:33.17 user 116.07 system 68.64 elapsed 217% CPU time.18.tcmalloc.32768:11.34 user 0.13 system 11.57 elapsed 99% CPU time.18.ptmalloc.65536:35.91 user 177.82 system 106.75 elapsed 200% CPU time.18.tcmalloc.65536:11.54 user 0.06 system 11.74 elapsed 98% CPU time.18.ptmalloc.131072:36.38 user 187.18 system 126.91 elapsed 176% CPU time.18.tcmalloc.131072:16.34 user 0.05 system 16.43 elapsed 99% CPU time.19.ptmalloc.64:22.90 user 13.23 system 11.82 elapsed 305% CPU time.19.tcmalloc.64:7.81 user 0.02 system 2.01 elapsed 388% CPU time.19.ptmalloc.128:30.13 user 18.58 system 14.77 elapsed 329% CPU time.19.tcmalloc.128:7.74 user 0.02 system 2.01 elapsed 386% CPU time.19.ptmalloc.256:35.33 user 21.41 system 16.35 elapsed 347% CPU time.19.tcmalloc.256:7.79 user 0.04 system 2.04 elapsed 382% CPU time.19.ptmalloc.512:39.30 user 26.22 system 17.84 elapsed 367% CPU time.19.tcmalloc.512:7.80 user 0.06 system 2.05 elapsed 381% CPU time.19.ptmalloc.1024:35.70 user 23.90 system 15.66 elapsed 380% CPU time.19.tcmalloc.1024:8.08 user 0.06 system 2.16 elapsed 376% CPU time.19.ptmalloc.2048:18.33 user 3.28 system 5.47 elapsed 394% CPU time.19.tcmalloc.2048:8.71 user 0.05 system 2.40 elapsed 363% CPU time.19.ptmalloc.4096:16.94 user 0.89 system 4.64 elapsed 383% CPU time.19.tcmalloc.4096:8.21 user 0.07 system 2.85 elapsed 289% CPU time.19.ptmalloc.8192:25.61 user 17.15 system 11.33 elapsed 377% CPU time.19.tcmalloc.8192:8.79 user 0.30 system 4.58 elapsed 198% CPU time.19.ptmalloc.16384:27.11 user 46.66 system 29.67 elapsed 248% CPU time.19.tcmalloc.16384:8.64 user 0.05 system 8.58 elapsed 101% CPU time.19.ptmalloc.32768:33.80 user 117.69 system 70.65 elapsed 214% CPU time.19.tcmalloc.32768:11.88 user 0.07 system 12.04 elapsed 99% CPU time.19.ptmalloc.65536:36.90 user 180.21 system 109.01 elapsed 199% CPU time.19.tcmalloc.65536:12.17 user 0.07 system 12.40 elapsed 98% CPU time.19.ptmalloc.131072:38.50 user 195.15 system 132.81 elapsed 175% CPU time.19.tcmalloc.131072:17.44 user 0.10 system 17.65 elapsed 99% CPU time.20.ptmalloc.64:23.37 user 13.74 system 11.86 elapsed 312% CPU time.20.tcmalloc.64:8.18 user 0.02 system 2.10 elapsed 389% CPU time.20.ptmalloc.128:31.29 user 19.97 system 15.53 elapsed 329% CPU time.20.tcmalloc.128:8.03 user 0.02 system 2.12 elapsed 378% CPU time.20.ptmalloc.256:38.40 user 25.65 system 18.25 elapsed 350% CPU time.20.tcmalloc.256:8.05 user 0.05 system 2.12 elapsed 380% CPU time.20.ptmalloc.512:40.60 user 27.70 system 18.46 elapsed 369% CPU time.20.tcmalloc.512:8.22 user 0.08 system 2.20 elapsed 375% CPU time.20.ptmalloc.1024:40.02 user 28.52 system 17.56 elapsed 390% CPU time.20.tcmalloc.1024:8.50 user 0.07 system 2.19 elapsed 391% CPU time.20.ptmalloc.2048:16.13 user 0.23 system 4.23 elapsed 386% CPU time.20.tcmalloc.2048:8.98 user 0.03 system 2.45 elapsed 367% CPU time.20.ptmalloc.4096:17.14 user 0.87 system 4.60 elapsed 391% CPU time.20.tcmalloc.4096:8.93 user 0.20 system 2.97 elapsed 306% CPU time.20.ptmalloc.8192:25.24 user 17.16 system 11.14 elapsed 380% CPU time.20.tcmalloc.8192:9.78 user 0.30 system 5.14 elapsed 195% CPU time.20.ptmalloc.16384:39.93 user 60.36 system 30.24 elapsed 331% CPU time.20.tcmalloc.16384:9.57 user 0.09 system 9.43 elapsed 102% CPU time.20.ptmalloc.32768:36.44 user 130.23 system 76.79 elapsed 217% CPU time.20.tcmalloc.32768:12.71 user 0.09 system 12.97 elapsed 98% CPU time.20.ptmalloc.65536:39.79 user 202.09 system 120.34 elapsed 200% CPU time.20.tcmalloc.65536:12.93 user 0.06 system 13.15 elapsed 98% CPU time.20.ptmalloc.131072:41.91 user 202.76 system 138.51 elapsed 176% CPU time.20.tcmalloc.131072:18.23 user 0.07 system 18.42 elapsed 99% CPU ================================================ FILE: distro/google-perftools-1.7/doc/tcmalloc.html ================================================ TCMalloc : Thread-Caching Malloc

TCMalloc : Thread-Caching Malloc

Sanjay Ghemawat

Motivation

TCMalloc is faster than the glibc 2.3 malloc (available as a separate library called ptmalloc2) and other mallocs that I have tested. ptmalloc2 takes approximately 300 nanoseconds to execute a malloc/free pair on a 2.8 GHz P4 (for small objects). The TCMalloc implementation takes approximately 50 nanoseconds for the same operation pair. Speed is important for a malloc implementation because if malloc is not fast enough, application writers are inclined to write their own custom free lists on top of malloc. This can lead to extra complexity, and more memory usage unless the application writer is very careful to appropriately size the free lists and scavenge idle objects out of the free list.

TCMalloc also reduces lock contention for multi-threaded programs. For small objects, there is virtually zero contention. For large objects, TCMalloc tries to use fine grained and efficient spinlocks. ptmalloc2 also reduces lock contention by using per-thread arenas but there is a big problem with ptmalloc2's use of per-thread arenas. In ptmalloc2 memory can never move from one arena to another. This can lead to huge amounts of wasted space. For example, in one Google application, the first phase would allocate approximately 300MB of memory for its URL canonicalization data structures. When the first phase finished, a second phase would be started in the same address space. If this second phase was assigned a different arena than the one used by the first phase, this phase would not reuse any of the memory left after the first phase and would add another 300MB to the address space. Similar memory blowup problems were also noticed in other applications.

Another benefit of TCMalloc is space-efficient representation of small objects. For example, N 8-byte objects can be allocated while using space approximately 8N * 1.01 bytes. I.e., a one-percent space overhead. ptmalloc2 uses a four-byte header for each object and (I think) rounds up the size to a multiple of 8 bytes and ends up using 16N bytes.

Usage

To use TCMalloc, just link TCMalloc into your application via the "-ltcmalloc" linker flag.

You can use TCMalloc in applications you didn't compile yourself, by using LD_PRELOAD:

   $ LD_PRELOAD="/usr/lib/libtcmalloc.so" 

LD_PRELOAD is tricky, and we don't necessarily recommend this mode of usage.

TCMalloc includes a heap checker and heap profiler as well.

If you'd rather link in a version of TCMalloc that does not include the heap profiler and checker (perhaps to reduce binary size for a static binary), you can link in libtcmalloc_minimal instead.

Overview

TCMalloc assigns each thread a thread-local cache. Small allocations are satisfied from the thread-local cache. Objects are moved from central data structures into a thread-local cache as needed, and periodic garbage collections are used to migrate memory back from a thread-local cache into the central data structures.

TCMalloc treats objects with size <= 32K ("small" objects) differently from larger objects. Large objects are allocated directly from the central heap using a page-level allocator (a page is a 4K aligned region of memory). I.e., a large object is always page-aligned and occupies an integral number of pages.

A run of pages can be carved up into a sequence of small objects, each equally sized. For example a run of one page (4K) can be carved up into 32 objects of size 128 bytes each.

Small Object Allocation

Each small object size maps to one of approximately 60 allocatable size-classes. For example, all allocations in the range 833 to 1024 bytes are rounded up to 1024. The size-classes are spaced so that small sizes are separated by 8 bytes, larger sizes by 16 bytes, even larger sizes by 32 bytes, and so forth. The maximal spacing is controlled so that not too much space is wasted when an allocation request falls just past the end of a size class and has to be rounded up to the next class.

A thread cache contains a singly linked list of free objects per size-class.

When allocating a small object: (1) We map its size to the corresponding size-class. (2) Look in the corresponding free list in the thread cache for the current thread. (3) If the free list is not empty, we remove the first object from the list and return it. When following this fast path, TCMalloc acquires no locks at all. This helps speed-up allocation significantly because a lock/unlock pair takes approximately 100 nanoseconds on a 2.8 GHz Xeon.

If the free list is empty: (1) We fetch a bunch of objects from a central free list for this size-class (the central free list is shared by all threads). (2) Place them in the thread-local free list. (3) Return one of the newly fetched objects to the applications.

If the central free list is also empty: (1) We allocate a run of pages from the central page allocator. (2) Split the run into a set of objects of this size-class. (3) Place the new objects on the central free list. (4) As before, move some of these objects to the thread-local free list.

Sizing Thread Cache Free Lists

It is important to size the thread cache free lists correctly. If the free list is too small, we'll need to go to the central free list too often. If the free list is too big, we'll waste memory as objects sit idle in the free list.

Note that the thread caches are just as important for deallocation as they are for allocation. Without a cache, each deallocation would require moving the memory to the central free list. Also, some threads have asymmetric alloc/free behavior (e.g. producer and consumer threads), so sizing the free list correctly gets trickier.

To size the free lists appropriately, we use a slow-start algorithm to determine the maximum length of each individual free list. As the free list is used more frequently, its maximum length grows. However, if a free list is used more for deallocation than allocation, its maximum length will grow only up to a point where the whole list can be efficiently moved to the central free list at once.

The psuedo-code below illustrates this slow-start algorithm. Note that num_objects_to_move is specific to each size class. By moving a list of objects with a well-known length, the central cache can efficiently pass these lists between thread caches. If a thread cache wants fewer than num_objects_to_move, the operation on the central free list has linear time complexity. The downside of always using num_objects_to_move as the number of objects to transfer to and from the central cache is that it wastes memory in threads that don't need all of those objects.

Start each freelist max_length at 1.

Allocation
  if freelist empty {
    fetch min(max_length, num_objects_to_move) from central list;
    if max_length < num_objects_to_move {  // slow-start
      max_length++;
    } else {
      max_length += num_objects_to_move;
    }
  }

Deallocation
  if length > max_length {
    // Don't try to release num_objects_to_move if we don't have that many.
    release min(max_length, num_objects_to_move) objects to central list
    if max_length < num_objects_to_move {
      // Slow-start up to num_objects_to_move.
      max_length++;
    } else if max_length > num_objects_to_move {
      // If we consistently go over max_length, shrink max_length.
      overages++;
      if overages > kMaxOverages {
        max_length -= num_objects_to_move;
        overages = 0;
      }
    }
  }
See also the section on Garbage Collection to see how it affects the max_length.

Large Object Allocation

A large object size (> 32K) is rounded up to a page size (4K) and is handled by a central page heap. The central page heap is again an array of free lists. For i < 256, the kth entry is a free list of runs that consist of k pages. The 256th entry is a free list of runs that have length >= 256 pages:

An allocation for k pages is satisfied by looking in the kth free list. If that free list is empty, we look in the next free list, and so forth. Eventually, we look in the last free list if necessary. If that fails, we fetch memory from the system (using sbrk, mmap, or by mapping in portions of /dev/mem).

If an allocation for k pages is satisfied by a run of pages of length > k, the remainder of the run is re-inserted back into the appropriate free list in the page heap.

Spans

The heap managed by TCMalloc consists of a set of pages. A run of contiguous pages is represented by a Span object. A span can either be allocated, or free. If free, the span is one of the entries in a page heap linked-list. If allocated, it is either a large object that has been handed off to the application, or a run of pages that have been split up into a sequence of small objects. If split into small objects, the size-class of the objects is recorded in the span.

A central array indexed by page number can be used to find the span to which a page belongs. For example, span a below occupies 2 pages, span b occupies 1 page, span c occupies 5 pages and span d occupies 3 pages.

In a 32-bit address space, the central array is represented by a a 2-level radix tree where the root contains 32 entries and each leaf contains 2^15 entries (a 32-bit address spave has 2^20 4K pages, and the first level of tree divides the 2^20 pages by 2^5). This leads to a starting memory usage of 128KB of space (2^15*4 bytes) for the central array, which seems acceptable.

On 64-bit machines, we use a 3-level radix tree.

Deallocation

When an object is deallocated, we compute its page number and look it up in the central array to find the corresponding span object. The span tells us whether or not the object is small, and its size-class if it is small. If the object is small, we insert it into the appropriate free list in the current thread's thread cache. If the thread cache now exceeds a predetermined size (2MB by default), we run a garbage collector that moves unused objects from the thread cache into central free lists.

If the object is large, the span tells us the range of pages covered by the object. Suppose this range is [p,q]. We also lookup the spans for pages p-1 and q+1. If either of these neighboring spans are free, we coalesce them with the [p,q] span. The resulting span is inserted into the appropriate free list in the page heap.

Central Free Lists for Small Objects

As mentioned before, we keep a central free list for each size-class. Each central free list is organized as a two-level data structure: a set of spans, and a linked list of free objects per span.

An object is allocated from a central free list by removing the first entry from the linked list of some span. (If all spans have empty linked lists, a suitably sized span is first allocated from the central page heap.)

An object is returned to a central free list by adding it to the linked list of its containing span. If the linked list length now equals the total number of small objects in the span, this span is now completely free and is returned to the page heap.

Garbage Collection of Thread Caches

Garbage collecting objects from a thread cache keeps the size of the cache under control and returns unused objects to the central free lists. Some threads need large caches to perform well while others can get by with little or no cache at all. When a thread cache goes over its max_size, garbage collection kicks in and then the thread competes with the other threads for a larger cache.

Garbage collection is run only during a deallocation. We walk over all free lists in the cache and move some number of objects from the free list to the corresponding central list.

The number of objects to be moved from a free list is determined using a per-list low-water-mark L. L records the minimum length of the list since the last garbage collection. Note that we could have shortened the list by L objects at the last garbage collection without requiring any extra accesses to the central list. We use this past history as a predictor of future accesses and move L/2 objects from the thread cache free list to the corresponding central free list. This algorithm has the nice property that if a thread stops using a particular size, all objects of that size will quickly move from the thread cache to the central free list where they can be used by other threads.

If a thread consistently deallocates more objects of a certain size than it allocates, this L/2 behavior will cause at least L/2 objects to always sit in the free list. To avoid wasting memory this way, we shrink the maximum length of the freelist to converge on num_objects_to_move (see also Sizing Thread Cache Free Lists).

Garbage Collection
  if (L != 0 && max_length > num_objects_to_move) {
    max_length = max(max_length - num_objects_to_move, num_objects_to_move)
  }

The fact that the thread cache went over its max_size is an indication that the thread would benefit from a larger cache. Simply increasing max_size would use an inordinate amount of memory in programs that have lots of active threads. Developers can bound the memory used with the flag --tcmalloc_max_total_thread_cache_bytes.

Each thread cache starts with a small max_size (e.g. 64KB) so that idle threads won't pre-allocate memory they don't need. Each time the cache runs a garbage collection, it will also try to grow its max_size. If the sum of the thread cache sizes is less than --tcmalloc_max_total_thread_cache_bytes, max_size grows easily. If not, thread cache 1 will try to steal from thread cache 2 (picked round-robin) by decreasing thread cache 2's max_size. In this way, threads that are more active will steal memory from other threads more often than they are have memory stolen from themselves. Mostly idle threads end up with small caches and active threads end up with big caches. Note that this stealing can cause the sum of the thread cache sizes to be greater than --tcmalloc_max_total_thread_cache_bytes until thread cache 2 deallocates some memory to trigger a garbage collection.

Performance Notes

PTMalloc2 unittest

The PTMalloc2 package (now part of glibc) contains a unittest program t-test1.c. This forks a number of threads and performs a series of allocations and deallocations in each thread; the threads do not communicate other than by synchronization in the memory allocator.

t-test1 (included in tests/tcmalloc/, and compiled as ptmalloc_unittest1) was run with a varying numbers of threads (1-20) and maximum allocation sizes (64 bytes - 32Kbytes). These tests were run on a 2.4GHz dual Xeon system with hyper-threading enabled, using Linux glibc-2.3.2 from RedHat 9, with one million operations per thread in each test. In each case, the test was run once normally, and once with LD_PRELOAD=libtcmalloc.so.

The graphs below show the performance of TCMalloc vs PTMalloc2 for several different metrics. Firstly, total operations (millions) per elapsed second vs max allocation size, for varying numbers of threads. The raw data used to generate these graphs (the output of the time utility) is available in t-test1.times.txt.

  • TCMalloc is much more consistently scalable than PTMalloc2 - for all thread counts >1 it achieves ~7-9 million ops/sec for small allocations, falling to ~2 million ops/sec for larger allocations. The single-thread case is an obvious outlier, since it is only able to keep a single processor busy and hence can achieve fewer ops/sec. PTMalloc2 has a much higher variance on operations/sec - peaking somewhere around 4 million ops/sec for small allocations and falling to <1 million ops/sec for larger allocations.
  • TCMalloc is faster than PTMalloc2 in the vast majority of cases, and particularly for small allocations. Contention between threads is less of a problem in TCMalloc.
  • TCMalloc's performance drops off as the allocation size increases. This is because the per-thread cache is garbage-collected when it hits a threshold (defaulting to 2MB). With larger allocation sizes, fewer objects can be stored in the cache before it is garbage-collected.
  • There is a noticeable drop in TCMalloc's performance at ~32K maximum allocation size; at larger sizes performance drops less quickly. This is due to the 32K maximum size of objects in the per-thread caches; for objects larger than this TCMalloc allocates from the central page heap.

Next, operations (millions) per second of CPU time vs number of threads, for max allocation size 64 bytes - 128 Kbytes.

Here we see again that TCMalloc is both more consistent and more efficient than PTMalloc2. For max allocation sizes <32K, TCMalloc typically achieves ~2-2.5 million ops per second of CPU time with a large number of threads, whereas PTMalloc achieves generally 0.5-1 million ops per second of CPU time, with a lot of cases achieving much less than this figure. Above 32K max allocation size, TCMalloc drops to 1-1.5 million ops per second of CPU time, and PTMalloc drops almost to zero for large numbers of threads (i.e. with PTMalloc, lots of CPU time is being burned spinning waiting for locks in the heavily multi-threaded case).

Modifying Runtime Behavior

You can more finely control the behavior of the tcmalloc via environment variables.

Generally useful flags:

TCMALLOC_SAMPLE_PARAMETER default: 0 The approximate gap between sampling actions. That is, we take one sample approximately once every tcmalloc_sample_parmeter bytes of allocation. This sampled heap information is available via MallocExtension::GetHeapSample() or MallocExtension::ReadStackTraces(). A reasonable value is 524288.
TCMALLOC_RELEASE_RATE default: 1.0 Rate at which we release unused memory to the system, via madvise(MADV_DONTNEED), on systems that support it. Zero means we never release memory back to the system. Increase this flag to return memory faster; decrease it to return memory slower. Reasonable rates are in the range [0,10].
TCMALLOC_LARGE_ALLOC_REPORT_THRESHOLD default: 1073741824 Allocations larger than this value cause a stack trace to be dumped to stderr. The threshold for dumping stack traces is increased by a factor of 1.125 every time we print a message so that the threshold automatically goes up by a factor of ~1000 every 60 messages. This bounds the amount of extra logging generated by this flag. Default value of this flag is very large and therefore you should see no extra logging unless the flag is overridden.
TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES=x default: 16777216 Bound on the total amount of bytes allocated to thread caches. This bound is not strict, so it is possible for the cache to go over this bound in certain circumstances. This value defaults to 16MB. For applications with many threads, this may not be a large enough cache, which can affect performance. If you suspect your application is not scaling to many threads due to lock contention in TCMalloc, you can try increasing this value. This may improve performance, at a cost of extra memory use by TCMalloc. See Garbage Collection for more details.

Advanced "tweaking" flags, that control more precisely how tcmalloc tries to allocate memory from the kernel.

TCMALLOC_SKIP_MMAP default: false If true, do not try to use mmap to obtain memory from the kernel.
TCMALLOC_SKIP_SBRK default: false If true, do not try to use sbrk to obtain memory from the kernel.
TCMALLOC_DEVMEM_START default: 0 Physical memory starting location in MB for /dev/mem allocation. Setting this to 0 disables /dev/mem allocation.
TCMALLOC_DEVMEM_LIMIT default: 0 Physical memory limit location in MB for /dev/mem allocation. Setting this to 0 means no limit.
TCMALLOC_DEVMEM_DEVICE default: /dev/mem Device to use for allocating unmanaged memory.
TCMALLOC_MEMFS_MALLOC_PATH default: "" If set, specify a path where hugetlbfs or tmpfs is mounted. This may allow for speedier allocations.
TCMALLOC_MEMFS_LIMIT_MB default: 0 Limit total memfs allocation size to specified number of MB. 0 means "no limit".
TCMALLOC_MEMFS_ABORT_ON_FAIL default: false If true, abort() whenever memfs_malloc fails to satisfy an allocation.
TCMALLOC_MEMFS_IGNORE_MMAP_FAIL default: false If true, ignore failures from mmap.

Modifying Behavior In Code

The MallocExtension class, in malloc_extension.h, provides a few knobs that you can tweak in your program, to affect tcmalloc's behavior.

Releasing Memory Back to the System

By default, tcmalloc will release no-longer-used memory back to the kernel gradually, over time. The tcmalloc_release_rate flag controls how quickly this happens. You can also force a release at a given point in the progam execution like so:

   MallocExtension::instance()->ReleaseFreeMemory();

You can also call SetMemoryReleaseRate() to change the tcmalloc_release_rate value at runtime, or GetMemoryReleaseRate to see what the current release rate is.

Memory Introspection

There are several routines for getting a human-readable form of the current memory usage:

   MallocExtension::instance()->GetStats(buffer, buffer_length);
   MallocExtension::instance()->GetHeapSample(&string);
   MallocExtension::instance()->GetHeapGrowthStacks(&string);

The last two create files in the same format as the heap-profiler, and can be passed as data files to pprof. The first is human-readable and is meant for debugging.

Generic Tcmalloc Status

TCMalloc has support for setting and retrieving arbitrary 'properties':

   MallocExtension::instance()->SetNumericProperty(property_name, value);
   MallocExtension::instance()->GetNumericProperty(property_name, &value);

It is possible for an application to set and get these properties, but the most useful is when a library sets the properties so the application can read them. Here are the properties TCMalloc defines; you can access them with a call like MallocExtension::instance()->GetNumericProperty("generic.heap_size", &value);:

generic.current_allocated_bytes Number of bytes used by the application. This will not typically match the memory use reported by the OS, because it does not include TCMalloc overhead or memory fragmentation.
generic.heap_size Bytes of system memory reserved by TCMalloc.
tcmalloc.pageheap_free_bytes Number of bytes in free, mapped pages in page heap. These bytes can be used to fulfill allocation requests. They always count towards virtual memory usage, and unless the underlying memory is swapped out by the OS, they also count towards physical memory usage.
tcmalloc.pageheap_unmapped_bytes Number of bytes in free, unmapped pages in page heap. These are bytes that have been released back to the OS, possibly by one of the MallocExtension "Release" calls. They can be used to fulfill allocation requests, but typically incur a page fault. They always count towards virtual memory usage, and depending on the OS, typically do not count towards physical memory usage.
tcmalloc.slack_bytes Sum of pageheap_free_bytes and pageheap_unmapped_bytes. Provided for backwards compatibility only. Do not use.
tcmalloc.max_total_thread_cache_bytes A limit to how much memory TCMalloc dedicates for small objects. Higher numbers trade off more memory use for -- in some situations -- improved efficiency.
tcmalloc.current_total_thread_cache_bytes A measure of some of the memory TCMalloc is using (for small objects).

Caveats

For some systems, TCMalloc may not work correctly with applications that aren't linked against libpthread.so (or the equivalent on your OS). It should work on Linux using glibc 2.3, but other OS/libc combinations have not been tested.

TCMalloc may be somewhat more memory hungry than other mallocs, (but tends not to have the huge blowups that can happen with other mallocs). In particular, at startup TCMalloc allocates approximately 240KB of internal memory.

Don't try to load TCMalloc into a running binary (e.g., using JNI in Java programs). The binary will have allocated some objects using the system malloc, and may try to pass them to TCMalloc for deallocation. TCMalloc will not be able to handle such objects.


Sanjay Ghemawat, Paul Menage
Last modified: Sat Feb 24 13:11:38 PST 2007 (csilvers)
================================================ FILE: distro/google-perftools-1.7/doc/threadheap.dot ================================================ digraph ThreadHeap { rankdir=LR node [shape=box, width=0.3, height=0.3] nodesep=.05 heap [shape=record, height=2, label="class 0|class 1|class 2|..."] O0 [label=""] O1 [label=""] O2 [label=""] O3 [label=""] O4 [label=""] O5 [label=""] sep1 [shape=plaintext, label="..."] sep2 [shape=plaintext, label="..."] sep3 [shape=plaintext, label="..."] heap:f0 -> O0 -> O1 -> sep1 heap:f1 -> O2 -> O3 -> sep2 heap:f2 -> O4 -> O5 -> sep3 } ================================================ FILE: distro/google-perftools-1.7/google-perftools.sln ================================================ Microsoft Visual Studio Solution File, Format Version 8.00 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtcmalloc_minimal", "vsprojects\libtcmalloc_minimal\libtcmalloc_minimal.vcproj", "{55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tcmalloc_minimal_unittest", "vsprojects\tcmalloc_minimal_unittest\tcmalloc_minimal_unittest.vcproj", "{7CC73D97-C057-43A6-82EF-E6B567488D02}" ProjectSection(ProjectDependencies) = postProject {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} = {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tcmalloc_minimal_large_unittest", "vsprojects\tcmalloc_minimal_large\tcmalloc_minimal_large_unittest.vcproj", "{2D8B9599-C74C-4298-B723-6CF6077563E3}" ProjectSection(ProjectDependencies) = postProject {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} = {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "addressmap_unittest", "vsprojects\addressmap_unittest\addressmap_unittest.vcproj", "{32EECEB6-7D18-477E-BC7A-30CE98457A88}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "frag_unittest", "vsprojects\frag_unittest\frag_unittest.vcproj", "{24754725-DE0D-4214-8979-324247AAD78E}" ProjectSection(ProjectDependencies) = postProject {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} = {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "low_level_alloc_unittest", "vsprojects\low_level_alloc_unittest\low_level_alloc_unittest.vcproj", "{A765198D-5305-4AB0-9A21-A0CD8201EB2A}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "malloc_extension_test", "vsprojects\malloc_extension_test\malloc_extension_test.vcproj", "{3765198D-5305-4AB0-9A21-A0CD8201EB2A}" ProjectSection(ProjectDependencies) = postProject {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} = {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "markidle_unittest", "vsprojects\markidle_unittest\markidle_unittest.vcproj", "{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}" ProjectSection(ProjectDependencies) = postProject {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} = {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "packed-cache_test", "vsprojects\packed-cache_test\packed-cache_test.vcproj", "{605D3CED-B530-424E-B7D2-2A31F14FD570}" ProjectSection(ProjectDependencies) = postProject {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} = {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pagemap_unittest", "vsprojects\pagemap_unittest\pagemap_unittest.vcproj", "{9765198D-5305-4AB0-9A21-A0CD8201EB2A}" ProjectSection(ProjectDependencies) = postProject {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} = {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "page_heap_test", "vsprojects\page_heap_test\page_heap_test.vcproj", "{9765198D-5305-4AB0-9A21-A0CD8201EB2B}" ProjectSection(ProjectDependencies) = postProject {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} = {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "realloc_unittest", "vsprojects\realloc_unittest\realloc_unittest.vcproj", "{4765198D-5305-4AB0-9A21-A0CD8201EB2A}" ProjectSection(ProjectDependencies) = postProject {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} = {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sampler_test", "vsprojects\sampler_test\sampler_test.vcproj", "{B765198D-5305-4AB0-9A21-A0CD8201EB2A}" ProjectSection(ProjectDependencies) = postProject {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} = {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stack_trace_table_test", "vsprojects\stack_trace_table_test\stack_trace_table_test.vcproj", "{A4754725-DE0D-4214-8979-324247AAD78E}" ProjectSection(ProjectDependencies) = postProject {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} = {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "thread_dealloc_unittest", "vsprojects\thread_dealloc_unittest\thread_dealloc_unittest.vcproj", "{6CFFBD0F-09E3-4282-A711-0564451FDF74}" ProjectSection(ProjectDependencies) = postProject {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} = {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tmu-static", "vsprojects\tmu-static\tmu-static.vcproj", "{8F708DCB-7EE4-4BA0-81AA-A52A0BA73B74}" ProjectSection(ProjectDependencies) = postProject EndProjectSection ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "addr2line-pdb", "vsprojects\addr2line-pdb\addr2line-pdb.vcproj", "{81CA712E-90B8-4AE5-9E89-5B436578D6DA}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nm-pdb", "vsprojects\nm-pdb\nm-pdb.vcproj", "{3A559C75-FD26-4300-B86B-165FD43EE1CE}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug Release = Release EndGlobalSection GlobalSection(ProjectDependencies) = postSolution EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}.Debug.ActiveCfg = Debug|Win32 {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}.Debug.Build.0 = Debug|Win32 {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}.Release.ActiveCfg = Release|Win32 {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}.Release.Build.0 = Release|Win32 {7CC73D97-C057-43A6-82EF-E6B567488D02}.Debug.ActiveCfg = Debug|Win32 {7CC73D97-C057-43A6-82EF-E6B567488D02}.Debug.Build.0 = Debug|Win32 {7CC73D97-C057-43A6-82EF-E6B567488D02}.Release.ActiveCfg = Release|Win32 {7CC73D97-C057-43A6-82EF-E6B567488D02}.Release.Build.0 = Release|Win32 {2D8B9599-C74C-4298-B723-6CF6077563E3}.Debug.ActiveCfg = Debug|Win32 {2D8B9599-C74C-4298-B723-6CF6077563E3}.Debug.Build.0 = Debug|Win32 {2D8B9599-C74C-4298-B723-6CF6077563E3}.Release.ActiveCfg = Release|Win32 {2D8B9599-C74C-4298-B723-6CF6077563E3}.Release.Build.0 = Release|Win32 {32EECEB6-7D18-477E-BC7A-30CE98457A88}.Debug.ActiveCfg = Debug|Win32 {32EECEB6-7D18-477E-BC7A-30CE98457A88}.Debug.Build.0 = Debug|Win32 {32EECEB6-7D18-477E-BC7A-30CE98457A88}.Release.ActiveCfg = Release|Win32 {32EECEB6-7D18-477E-BC7A-30CE98457A88}.Release.Build.0 = Release|Win32 {24754725-DE0D-4214-8979-324247AAD78E}.Debug.ActiveCfg = Debug|Win32 {24754725-DE0D-4214-8979-324247AAD78E}.Debug.Build.0 = Debug|Win32 {24754725-DE0D-4214-8979-324247AAD78E}.Release.ActiveCfg = Release|Win32 {24754725-DE0D-4214-8979-324247AAD78E}.Release.Build.0 = Release|Win32 {A765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.ActiveCfg = Debug|Win32 {A765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.Build.0 = Debug|Win32 {A765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.ActiveCfg = Release|Win32 {A765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.Build.0 = Release|Win32 {3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.ActiveCfg = Debug|Win32 {3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.Build.0 = Debug|Win32 {3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.ActiveCfg = Release|Win32 {3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.Build.0 = Release|Win32 {4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Debug.ActiveCfg = Debug|Win32 {4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Debug.Build.0 = Debug|Win32 {4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Release.ActiveCfg = Release|Win32 {4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Release.Build.0 = Release|Win32 {605D3CED-B530-424E-B7D2-2A31F14FD570}.Debug.ActiveCfg = Debug|Win32 {605D3CED-B530-424E-B7D2-2A31F14FD570}.Debug.Build.0 = Debug|Win32 {605D3CED-B530-424E-B7D2-2A31F14FD570}.Release.ActiveCfg = Release|Win32 {605D3CED-B530-424E-B7D2-2A31F14FD570}.Release.Build.0 = Release|Win32 {9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.ActiveCfg = Debug|Win32 {9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.Build.0 = Debug|Win32 {9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.ActiveCfg = Release|Win32 {9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.Build.0 = Release|Win32 {9765198D-5305-4AB0-9A21-A0CD8201EB2B}.Debug.ActiveCfg = Debug|Win32 {9765198D-5305-4AB0-9A21-A0CD8201EB2B}.Debug.Build.0 = Debug|Win32 {9765198D-5305-4AB0-9A21-A0CD8201EB2B}.Release.ActiveCfg = Release|Win32 {9765198D-5305-4AB0-9A21-A0CD8201EB2B}.Release.Build.0 = Release|Win32 {4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.ActiveCfg = Debug|Win32 {4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.Build.0 = Debug|Win32 {4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.ActiveCfg = Release|Win32 {4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.Build.0 = Release|Win32 {B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.ActiveCfg = Debug|Win32 {B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.Build.0 = Debug|Win32 {B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.ActiveCfg = Release|Win32 {B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.Build.0 = Release|Win32 {A4754725-DE0D-4214-8979-324247AAD78E}.Debug.ActiveCfg = Debug|Win32 {A4754725-DE0D-4214-8979-324247AAD78E}.Debug.Build.0 = Debug|Win32 {A4754725-DE0D-4214-8979-324247AAD78E}.Release.ActiveCfg = Release|Win32 {A4754725-DE0D-4214-8979-324247AAD78E}.Release.Build.0 = Release|Win32 {6CFFBD0F-09E3-4282-A711-0564451FDF74}.Debug.ActiveCfg = Debug|Win32 {6CFFBD0F-09E3-4282-A711-0564451FDF74}.Debug.Build.0 = Debug|Win32 {6CFFBD0F-09E3-4282-A711-0564451FDF74}.Release.ActiveCfg = Release|Win32 {6CFFBD0F-09E3-4282-A711-0564451FDF74}.Release.Build.0 = Release|Win32 {8F708DCB-7EE4-4BA0-81AA-A52A0BA73B74}.Debug.ActiveCfg = Debug|Win32 {8F708DCB-7EE4-4BA0-81AA-A52A0BA73B74}.Debug.Build.0 = Debug|Win32 {8F708DCB-7EE4-4BA0-81AA-A52A0BA73B74}.Release.ActiveCfg = Release|Win32 {8F708DCB-7EE4-4BA0-81AA-A52A0BA73B74}.Release.Build.0 = Release|Win32 {81CA712E-90B8-4AE5-9E89-5B436578D6DA}.Debug.ActiveCfg = Debug|Win32 {81CA712E-90B8-4AE5-9E89-5B436578D6DA}.Debug.Build.0 = Debug|Win32 {81CA712E-90B8-4AE5-9E89-5B436578D6DA}.Release.ActiveCfg = Release|Win32 {81CA712E-90B8-4AE5-9E89-5B436578D6DA}.Release.Build.0 = Release|Win32 {3A559C75-FD26-4300-B86B-165FD43EE1CE}.Debug.ActiveCfg = Debug|Win32 {3A559C75-FD26-4300-B86B-165FD43EE1CE}.Debug.Build.0 = Debug|Win32 {3A559C75-FD26-4300-B86B-165FD43EE1CE}.Release.ActiveCfg = Release|Win32 {3A559C75-FD26-4300-B86B-165FD43EE1CE}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection GlobalSection(ExtensibilityAddIns) = postSolution EndGlobalSection EndGlobal ================================================ FILE: distro/google-perftools-1.7/install-sh ================================================ #!/bin/sh # install - install a program, script, or datafile scriptversion=2005-05-14.22 # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" chmodcmd="$chmodprog 0755" chowncmd= chgrpcmd= stripcmd= rmcmd="$rmprog -f" mvcmd="$mvprog" src= dst= dir_arg= dstarg= no_target_directory= usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: -c (ignored) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. --help display this help and exit. --version display version info and exit. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test -n "$1"; do case $1 in -c) shift continue;; -d) dir_arg=true shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; --help) echo "$usage"; exit $?;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -s) stripcmd=$stripprog shift continue;; -t) dstarg=$2 shift shift continue;; -T) no_target_directory=true shift continue;; --version) echo "$0 $scriptversion"; exit $?;; *) # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. test -n "$dir_arg$dstarg" && break # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dstarg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dstarg" shift # fnord fi shift # arg dstarg=$arg done break;; esac done if test -z "$1"; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi for src do # Protect names starting with `-'. case $src in -*) src=./$src ;; esac if test -n "$dir_arg"; then dst=$src src= if test -d "$dst"; then mkdircmd=: chmodcmd= else mkdircmd=$mkdirprog fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dstarg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dstarg # Protect names starting with `-'. case $dst in -*) dst=./$dst ;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dstarg: Is a directory" >&2 exit 1 fi dst=$dst/`basename "$src"` fi fi # This sed command emulates the dirname command. dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` # Make sure that the destination directory exists. # Skip lots of stat calls in the usual case. if test ! -d "$dstdir"; then defaultIFS=' ' IFS="${IFS-$defaultIFS}" oIFS=$IFS # Some sh's can't handle IFS=/ for some reason. IFS='%' set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` shift IFS=$oIFS pathcomp= while test $# -ne 0 ; do pathcomp=$pathcomp$1 shift if test ! -d "$pathcomp"; then $mkdirprog "$pathcomp" # mkdir can fail with a `File exist' error in case several # install-sh are creating the directory concurrently. This # is OK. test -d "$pathcomp" || exit fi pathcomp=$pathcomp/ done fi if test -n "$dir_arg"; then $doit $mkdircmd "$dst" \ && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } else dstfile=`basename "$dst"` # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 trap '(exit $?); exit' 1 2 13 15 # Copy the file name to the temp name. $doit $cpprog "$src" "$dsttmp" && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && # Now rename the file to the real destination. { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ || { # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { if test -f "$dstdir/$dstfile"; then $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ || { echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 (exit 1); exit 1 } else : fi } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" } } fi || { (exit 1); exit 1; } done # The final little trick to "correctly" pass the exit status to the exit trap. { (exit 0); exit 0 } # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: ================================================ FILE: distro/google-perftools-1.7/libtool ================================================ #! /bin/sh # libtool - Provide generalized library-building support services. # Generated automatically by config.status (google-perftools) 1.7 # Libtool was configured on host meta.mtv.corp.google.com: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool 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 2 of # the License, or (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # The names of the tagged configurations supported by this script. available_tags="CXX " # ### BEGIN LIBTOOL CONFIG # Whether or not to optimize for fast installation. fast_install=yes # Which release of libtool.m4 was used? macro_version=2.2.6b macro_revision=1.3017 # Whether or not to build shared libraries. build_libtool_libs=yes # Whether or not to build static libraries. build_old_libs=yes # What type of objects to build. pic_mode=default # The host system. host_alias= host=x86_64-unknown-linux-gnu host_os=linux-gnu # The build system. build_alias= build=x86_64-unknown-linux-gnu build_os=linux-gnu # A sed program that does not truncate output. SED="/bin/sed" # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="$SED -e 1s/^X//" # A grep program that handles long lines. GREP="/bin/grep" # An ERE matcher. EGREP="/bin/grep -E" # A literal string matcher. FGREP="/bin/grep -F" # A BSD- or MS-compatible name lister. NM="/usr/bin/nm -B" # Whether we need soft or hard links. LN_S="ln -s" # What is the maximum length of a command? max_cmd_len=3458764513820540925 # Object file suffix (normally "o"). objext=o # Executable file suffix (normally ""). exeext= # whether the shell understands "unset". lt_unset=unset # turn spaces into newlines. SP2NL="tr \\040 \\012" # turn newlines into spaces. NL2SP="tr \\015\\012 \\040\\040" # How to create reloadable object files. reload_flag=" -r" reload_cmds="\$LD\$reload_flag -o \$output\$reload_objs" # An object symbol dumper. OBJDUMP="objdump" # Method to check whether dependent libraries are shared objects. deplibs_check_method="pass_all" # Command to use when deplibs_check_method == "file_magic". file_magic_cmd="\$MAGIC_CMD" # The archiver. AR="ar" AR_FLAGS="cru" # A symbol stripping program. STRIP="strip" # Commands used to install an old-style archive. RANLIB="ranlib" old_postinstall_cmds="chmod 644 \$oldlib~\$RANLIB \$oldlib" old_postuninstall_cmds="" # A C compiler. LTCC="gcc" # LTCC compiler flags. LTCFLAGS="-g -O2" # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe="sed -n -e 's/^.*[ ]\\([ABCDGIRSTW][ABCDGIRSTW]*\\)[ ][ ]*\\([_A-Za-z][_A-Za-z0-9]*\\)\$/\\1 \\2 \\2/p'" # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl="sed -n -e 's/^T .* \\(.*\\)\$/extern int \\1();/p' -e 's/^[ABCDGIRSTW]* .* \\(.*\\)\$/extern char \\1;/p'" # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address="sed -n -e 's/^: \\([^ ]*\\) \$/ {\\\"\\1\\\", (void *) 0},/p' -e 's/^[ABCDGIRSTW]* \\([^ ]*\\) \\([^ ]*\\)\$/ {\"\\2\", (void *) \\&\\2},/p'" # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \\([^ ]*\\) \$/ {\\\"\\1\\\", (void *) 0},/p' -e 's/^[ABCDGIRSTW]* \\([^ ]*\\) \\(lib[^ ]*\\)\$/ {\"\\2\", (void *) \\&\\2},/p' -e 's/^[ABCDGIRSTW]* \\([^ ]*\\) \\([^ ]*\\)\$/ {\"lib\\2\", (void *) \\&\\2},/p'" # The name of the directory that contains temporary libtool files. objdir=.libs # Shell to use when invoking shell scripts. SHELL="/bin/sh" # An echo program that does not interpret backslashes. ECHO="echo" # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=file # Must we lock files when doing compilation? need_locks="no" # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL="" # Tool to change global to local symbols on Mac OS X. NMEDIT="" # Tool to manipulate fat objects and archives on Mac OS X. LIPO="" # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL="" # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64="" # Old archive suffix (normally "a"). libext=a # Shared library suffix (normally ".so"). shrext_cmds=".so" # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds="" # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink="PATH LD_LIBRARY_PATH LD_RUN_PATH GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" # Do we need the "lib" prefix for modules? need_lib_prefix=no # Do we need a version for libraries? need_version=no # Library versioning type. version_type=linux # Shared library runtime path variable. runpath_var=LD_RUN_PATH # Shared library path variable. shlibpath_var=LD_LIBRARY_PATH # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=no # Format of library name prefix. libname_spec="lib\$name" # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME library_names_spec="\${libname}\${release}\${shared_ext}\$versuffix \${libname}\${release}\${shared_ext}\$major \$libname\${shared_ext}" # The coded name of the library, if different from the real name. soname_spec="\${libname}\${release}\${shared_ext}\$major" # Command to use after installation of a shared archive. postinstall_cmds="" # Command to use after uninstallation of a shared archive. postuninstall_cmds="" # Commands used to finish a libtool library installation in a directory. finish_cmds="PATH=\\\"\\\$PATH:/sbin\\\" ldconfig -n \$libdir" # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval="" # Whether we should hardcode library paths into libraries. hardcode_into_libs=yes # Compile-time system search path for libraries. sys_lib_search_path_spec="/usr/lib/gcc/x86_64-linux-gnu/4.4.3 /usr/lib /lib /usr/lib/x86_64-linux-gnu" # Run-time system search path for libraries. sys_lib_dlsearch_path_spec="/lib /usr/lib /usr/lib/nvidia-current /usr/lib32/nvidia-current /usr/lib32/alsa-lib /usr/lib/alsa-lib /usr/local/lib /lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu " # Whether dlopen is supported. dlopen_support=unknown # Whether dlopen of programs is supported. dlopen_self=unknown # Whether dlopen of statically linked programs is supported. dlopen_self_static=unknown # Commands to strip libraries. old_striplib="strip --strip-debug" striplib="strip --strip-unneeded" # The linker used to build libraries. LD="/usr/bin/ld -m elf_x86_64" # Commands used to build an old-style archive. old_archive_cmds="\$AR \$AR_FLAGS \$oldlib\$oldobjs~\$RANLIB \$oldlib" # A language specific compiler. CC="gcc" # Is the compiler the GNU compiler? with_gcc=yes # Compiler flag to turn off builtin functions. no_builtin_flag=" -fno-builtin" # How to pass a linker flag through the compiler. wl="-Wl," # Additional compiler flags for building library objects. pic_flag=" -fPIC -DPIC" # Compiler flag to prevent dynamic linking. link_static_flag="-static" # Does compiler simultaneously support -c and -o options? compiler_c_o="yes" # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=no # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=no # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec="\${wl}--export-dynamic" # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec="\${wl}--whole-archive\$convenience \${wl}--no-whole-archive" # Whether the compiler copes with passing no objects directly. compiler_needs_object="no" # Create an old-style archive from a shared archive. old_archive_from_new_cmds="" # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds="" # Commands used to build a shared archive. archive_cmds="\$CC -shared \$libobjs \$deplibs \$compiler_flags \${wl}-soname \$wl\$soname -o \$lib" archive_expsym_cmds="echo \\\"{ global:\\\" > \$output_objdir/\$libname.ver~ cat \$export_symbols | sed -e \\\"s/\\\\(.*\\\\)/\\\\1;/\\\" >> \$output_objdir/\$libname.ver~ echo \\\"local: *; };\\\" >> \$output_objdir/\$libname.ver~ \$CC -shared \$libobjs \$deplibs \$compiler_flags \${wl}-soname \$wl\$soname \${wl}-version-script \${wl}\$output_objdir/\$libname.ver -o \$lib" # Commands used to build a loadable module if different from building # a shared archive. module_cmds="" module_expsym_cmds="" # Whether we are building with GNU ld or not. with_gnu_ld="yes" # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag="" # Flag that enforces no undefined symbols. no_undefined_flag="" # Flag to hardcode $libdir into a binary during linking. # This must work even if $libdir does not exist hardcode_libdir_flag_spec="\${wl}-rpath \${wl}\$libdir" # If ld is used when linking, flag to hardcode $libdir into a binary # during linking. This must work even if $libdir does not exist. hardcode_libdir_flag_spec_ld="" # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator="" # Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=no # Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting ${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=no # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=no # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=unsupported # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=no # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=no # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=no # Fix the shell variable $srcfile for the compiler. fix_srcfile_path="" # Set to "yes" if exported symbols are required. always_export_symbols=no # The commands to list exported symbols. export_symbols_cmds="\$NM \$libobjs \$convenience | \$global_symbol_pipe | \$SED 's/.* //' | sort | uniq > \$export_symbols" # Symbols that should not be listed in the preloaded symbols. exclude_expsyms="_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*" # Symbols that must always be exported. include_expsyms="" # Commands necessary for linking programs (against libraries) with templates. prelink_cmds="" # Specify filename containing input files. file_list_spec="" # How to hardcode a shared library path into an executable. hardcode_action=immediate # The directories searched by this compiler when creating a shared library. compiler_lib_search_dirs="" # Dependencies to place before and after the objects being linked to # create a shared library. predep_objects="" postdep_objects="" predeps="" postdeps="" # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path="" # ### END LIBTOOL CONFIG # Generated from ltmain.m4sh. # ltmain.sh (GNU libtool) 2.2.6b # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 2008 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool 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 2 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, # or obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Usage: $progname [OPTION]... [MODE-ARG]... # # Provide generalized library-building support services. # # --config show all configuration variables # --debug enable verbose shell tracing # -n, --dry-run display commands without modifying any files # --features display basic configuration information and exit # --mode=MODE use operation mode MODE # --preserve-dup-deps don't remove duplicate dependency libraries # --quiet, --silent don't print informational messages # --tag=TAG use configuration variables from tag TAG # -v, --verbose print informational messages (default) # --version print version information # -h, --help print short or long help message # # MODE must be one of the following: # # clean remove files from the build directory # compile compile a source file into a libtool object # execute automatically set library path, then run a program # finish complete the installation of libtool libraries # install install libraries or executables # link create a library or an executable # uninstall remove libraries from an installed directory # # MODE-ARGS vary depending on the MODE. # Try `$progname --help --mode=MODE' for a more detailed description of MODE. # # When reporting a bug, please describe a test case to reproduce it and # include the following information: # # host-triplet: $host # shell: $SHELL # compiler: $LTCC # compiler flags: $LTCFLAGS # linker: $LD (gnu? $with_gnu_ld) # $progname: (GNU libtool) 2.2.6b Debian-2.2.6b-2ubuntu1 # automake: $automake_version # autoconf: $autoconf_version # # Report bugs to . PROGRAM=ltmain.sh PACKAGE=libtool VERSION="2.2.6b Debian-2.2.6b-2ubuntu1" TIMESTAMP="" package_revision=1.3017 # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # NLS nuisances: We save the old values to restore during execute mode. # Only set LANG and LC_ALL to C if already set. # These must not be set unconditionally because not all systems understand # e.g. LANG=C (notably SCO). lt_user_locale= lt_safe_locale= for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${$lt_var+set}\" = set; then save_$lt_var=\$$lt_var $lt_var=C export $lt_var lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" fi" done $lt_unset CDPATH : ${CP="cp -f"} : ${ECHO="echo"} : ${EGREP="/bin/grep -E"} : ${FGREP="/bin/grep -F"} : ${GREP="/bin/grep"} : ${LN_S="ln -s"} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SED="/bin/sed"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} : ${Xsed="$SED -e 1s/^X//"} # Global variables: EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. exit_status=$EXIT_SUCCESS # Make sure IFS has a sensible default lt_nl=' ' IFS=" $lt_nl" dirname="s,/[^/]*$,," basename="s,^.*/,," # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` } # Generated shell functions inserted here. # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac } # func_basename file func_basename () { func_basename_result="${1##*/}" } # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}" } # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). func_stripname () { # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"} } # func_opt_split func_opt_split () { func_opt_split_opt=${1%%=*} func_opt_split_arg=${1#*=} } # func_lo2o object func_lo2o () { case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac } # func_xform libobj-or-source func_xform () { func_xform_result=${1%.*}.lo } # func_arith arithmetic-term... func_arith () { func_arith_result=$(( $* )) } # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=${#1} } # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "$1+=\$2" } # Generated shell functions inserted here. # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath="$0" # The name of this program: # In the unlikely event $progname began with a '-', it would play havoc with # func_echo (imagine progname=-n), so we prepend ./ in that case: func_dirname_and_basename "$progpath" progname=$func_basename_result case $progname in -*) progname=./$progname ;; esac # Make sure we have an absolute path for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=$func_dirname_result progdir=`cd "$progdir" && pwd` progpath="$progdir/$progname" ;; *) save_IFS="$IFS" IFS=: for progdir in $PATH; do IFS="$save_IFS" test -x "$progdir/$progname" && break done IFS="$save_IFS" test -n "$progdir" || progdir=`pwd` progpath="$progdir/$progname" ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed="${SED}"' -e 1s/^X//' sed_quote_subst='s/\([`"$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Re-`\' parameter expansions in output of double_quote_subst that were # `\'-ed in input to the same. If an odd number of `\' preceded a '$' # in input to double_quote_subst, that '$' was protected from expansion. # Since each input `\' is now two `\'s, look for any number of runs of # four `\'s followed by two `\'s and then a '$'. `\' that '$'. bs='\\' bs2='\\\\' bs4='\\\\\\\\' dollar='\$' sed_double_backslash="\ s/$bs4/&\\ /g s/^$bs2$dollar/$bs&/ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g s/\n//g" # Standard options: opt_dry_run=false opt_help=false opt_quiet=false opt_verbose=false opt_warning=: # func_echo arg... # Echo program name prefixed message, along with the current mode # name if it has been set yet. func_echo () { $ECHO "$progname${mode+: }$mode: $*" } # func_verbose arg... # Echo program name prefixed message in verbose mode only. func_verbose () { $opt_verbose && func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_error arg... # Echo program name prefixed message to standard error. func_error () { $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2 } # func_warning arg... # Echo program name prefixed warning message to standard error. func_warning () { $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2 # bash bug again: : } # func_fatal_error arg... # Echo program name prefixed message to standard error, and exit. func_fatal_error () { func_error ${1+"$@"} exit $EXIT_FAILURE } # func_fatal_help arg... # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { func_error ${1+"$@"} func_fatal_error "$help" } help="Try \`$progname --help' for more information." ## default # func_grep expression filename # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $GREP "$1" "$2" >/dev/null 2>&1 } # func_mkdir_p directory-path # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { my_directory_path="$1" my_dir_list= if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then # Protect directory names starting with `-' case $my_directory_path in -*) my_directory_path="./$my_directory_path" ;; esac # While some portion of DIR does not yet exist... while test ! -d "$my_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. my_dir_list="$my_directory_path:$my_dir_list" # If the last portion added has no slash in it, the list is done case $my_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop my_directory_path=`$ECHO "X$my_directory_path" | $Xsed -e "$dirname"` done my_dir_list=`$ECHO "X$my_dir_list" | $Xsed -e 's,:*$,,'` save_mkdir_p_IFS="$IFS"; IFS=':' for my_dir in $my_dir_list; do IFS="$save_mkdir_p_IFS" # mkdir can fail with a `File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$my_dir" 2>/dev/null || : done IFS="$save_mkdir_p_IFS" # Bail out if we (or some other process) failed to create a directory. test -d "$my_directory_path" || \ func_fatal_error "Failed to create \`$1'" fi } # func_mktempdir [string] # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, STRING is the basename for that directory. func_mktempdir () { my_template="${TMPDIR-/tmp}/${1-$progname}" if test "$opt_dry_run" = ":"; then # Return a directory name, but don't create it in dry-run mode my_tmpdir="${my_template}-$$" else # If mktemp works, use that first and foremost my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` if test ! -d "$my_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race my_tmpdir="${my_template}-${RANDOM-0}$$" save_mktempdir_umask=`umask` umask 0077 $MKDIR "$my_tmpdir" umask $save_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$my_tmpdir" || \ func_fatal_error "cannot create temporary directory \`$my_tmpdir'" fi $ECHO "X$my_tmpdir" | $Xsed } # func_quote_for_eval arg # Aesthetically quote ARG to be evaled later. # This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT # is double-quoted, suitable for a subsequent eval, whereas # FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters # which are still active within double quotes backslashified. func_quote_for_eval () { case $1 in *[\\\`\"\$]*) func_quote_for_eval_unquoted_result=`$ECHO "X$1" | $Xsed -e "$sed_quote_subst"` ;; *) func_quote_for_eval_unquoted_result="$1" ;; esac case $func_quote_for_eval_unquoted_result in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and and variable # expansion for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" ;; *) func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" esac } # func_quote_for_expand arg # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { case $1 in *[\\\`\"]*) my_arg=`$ECHO "X$1" | $Xsed \ -e "$double_quote_subst" -e "$sed_double_backslash"` ;; *) my_arg="$1" ;; esac case $my_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") my_arg="\"$my_arg\"" ;; esac func_quote_for_expand_result="$my_arg" } # func_show_eval cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$my_cmd" my_status=$? if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_show_eval_locale cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$lt_user_locale $my_cmd" my_status=$? eval "$lt_safe_locale" if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_version # Echo version message to standard output and exit. func_version () { $SED -n '/^# '$PROGRAM' (GNU /,/# warranty; / { s/^# // s/^# *$// s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ p }' < "$progpath" exit $? } # func_usage # Echo short help message to standard output and exit. func_usage () { $SED -n '/^# Usage:/,/# -h/ { s/^# // s/^# *$// s/\$progname/'$progname'/ p }' < "$progpath" $ECHO $ECHO "run \`$progname --help | more' for full usage" exit $? } # func_help # Echo long help message to standard output and exit. func_help () { $SED -n '/^# Usage:/,/# Report bugs to/ { s/^# // s/^# *$// s*\$progname*'$progname'* s*\$host*'"$host"'* s*\$SHELL*'"$SHELL"'* s*\$LTCC*'"$LTCC"'* s*\$LTCFLAGS*'"$LTCFLAGS"'* s*\$LD*'"$LD"'* s/\$with_gnu_ld/'"$with_gnu_ld"'/ s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/ s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/ p }' < "$progpath" exit $? } # func_missing_arg argname # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { func_error "missing argument for $1" exit_cmd=exit } exit_cmd=: # Check that we have a working $ECHO. if test "X$1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X$1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then # Yippee, $ECHO works! : else # Restart under the correct shell, and then maybe $ECHO will work. exec $SHELL "$progpath" --no-reexec ${1+"$@"} fi if test "X$1" = X--fallback-echo; then # used as fallback echo shift cat </dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # Parse options once, thoroughly. This comes as soon as possible in # the script to make things like `libtool --version' happen quickly. { # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; esac # Parse non-mode specific arguments: while test "$#" -gt 0; do opt="$1" shift case $opt in --config) func_config ;; --debug) preserve_args="$preserve_args $opt" func_echo "enabling shell trace mode" opt_debug='set -x' $opt_debug ;; -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break execute_dlfiles="$execute_dlfiles $1" shift ;; --dry-run | -n) opt_dry_run=: ;; --features) func_features ;; --finish) mode="finish" ;; --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break case $1 in # Valid mode arguments: clean) ;; compile) ;; execute) ;; finish) ;; install) ;; link) ;; relink) ;; uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $opt" exit_cmd=exit break ;; esac mode="$1" shift ;; --preserve-dup-deps) opt_duplicate_deps=: ;; --quiet|--silent) preserve_args="$preserve_args $opt" opt_silent=: ;; --verbose| -v) preserve_args="$preserve_args $opt" opt_silent=false ;; --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break preserve_args="$preserve_args $opt $1" func_enable_tag "$1" # tagname is set here shift ;; # Separate optargs to long options: -dlopen=*|--mode=*|--tag=*) func_opt_split "$opt" set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"} shift ;; -\?|-h) func_usage ;; --help) opt_help=: ;; --version) func_version ;; -*) func_fatal_help "unrecognized option \`$opt'" ;; *) nonopt="$opt" break ;; esac done case $host in *cygwin* | *mingw* | *pw32* | *cegcc*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_duplicate_deps ;; esac # Having warned about all mis-specified options, bail out if # anything was wrong. $exit_cmd $EXIT_FAILURE } # func_check_version_match # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } ## ----------- ## ## Main. ## ## ----------- ## $opt_help || { # Sanity checks first: func_check_version_match if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then func_fatal_configuration "not configured to build any kind of library" fi test -z "$mode" && func_fatal_error "error: you must specify a MODE." # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$execute_dlfiles" && test "$mode" != execute; then func_error "unrecognized option \`-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$progname --help --mode=$mode' for more information." } # func_lalib_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null \ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_unsafe_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if `file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case "$lalib_p_line" in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test "$lalib_p" = yes } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { func_lalib_p "$1" } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_ltwrapper_scriptname_result="" if func_ltwrapper_executable_p "$1"; then func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" fi } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $opt_debug save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$save_ifs eval cmd=\"$cmd\" func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # `FILE.' does not work on cygwin managed mounts. func_source () { $opt_debug case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $opt_debug if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_quote_for_eval "$arg" CC_quoted="$CC_quoted $func_quote_for_eval_result" done case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_quote_for_eval "$arg" CC_quoted="$CC_quoted $func_quote_for_eval_result" done case "$@ " in " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with \`--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=${1} if test "$build_libtool_libs" = yes; then write_lobj=\'${2}\' else write_lobj=none fi if test "$build_old_libs" = yes; then write_oldobj=\'${3}\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T <?"'"'"' &()|`$[]' \ && func_warning "libobj name \`$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname="$func_basename_result" xdir="$func_dirname_result" lobj=${xdir}$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$ECHO "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi removelist="$removelist $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist removelist="$removelist $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 if test -n "$fix_srcfile_path"; then eval srcfile=\"$fix_srcfile_path\" fi func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test "$pic_mode" != no; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir command="$command -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test "$suppress_opt" = yes; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then if test "$pic_mode" != yes; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test "$compiler_c_o" = yes; then command="$command -o $obj" fi # Suppress compiler output if we already did a PIC compilation. command="$command$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test "$need_locks" != no; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test "$mode" = compile && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to building PIC objects only -prefer-non-pic try to building non-PIC objects only -shared do not build a \`.o' file suitable for static linking -static only build a \`.o' file suitable for static linking COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE Use a list of object files found in FILE to specify objects -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode \`$mode'" ;; esac $ECHO $ECHO "Try \`$progname --help' for more information about other modes." exit $? } # Now that we've collected a possible --mode arg, show help if necessary $opt_help && func_mode_help # func_mode_execute arg... func_mode_execute () { $opt_debug # The first argument is the command name. cmd="$nonopt" test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $execute_dlfiles; do test -f "$file" \ || func_fatal_help "\`$file' is not a file" dir= case $file in *.la) # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "\`$file' was not linked with \`-export-dynamic'" continue fi func_dirname "$file" "" "." dir="$func_dirname_result" if test -f "$dir/$objdir/$dlname"; then dir="$dir/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir="$func_dirname_result" ;; *) func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -*) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file="$progdir/$program" elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). func_quote_for_eval "$file" args="$args $func_quote_for_eval_result" done if test "X$opt_dry_run" = Xfalse; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" $ECHO "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS fi } test "$mode" = execute && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $opt_debug libdirs="$nonopt" admincmds= if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for dir do libdirs="$libdirs $dir" done for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || admincmds="$admincmds $cmds" fi done fi # Exit here if they wanted silent mode. $opt_silent && exit $EXIT_SUCCESS $ECHO "X----------------------------------------------------------------------" | $Xsed $ECHO "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done $ECHO $ECHO "If you ever happen to want to link against installed libraries" $ECHO "in a given directory, LIBDIR, you must either use libtool, and" $ECHO "specify the full pathname of the library, or use the \`-LLIBDIR'" $ECHO "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then $ECHO " - add LIBDIR to the \`$shlibpath_var' environment variable" $ECHO " during execution" fi if test -n "$runpath_var"; then $ECHO " - add LIBDIR to the \`$runpath_var' environment variable" $ECHO " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then $ECHO " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi $ECHO $ECHO "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) $ECHO "more information, such as the ld(1), crle(1) and ld.so(8) manual" $ECHO "pages." ;; *) $ECHO "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac $ECHO "X----------------------------------------------------------------------" | $Xsed exit $EXIT_SUCCESS } test "$mode" = finish && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $opt_debug # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. $ECHO "X$nonopt" | $GREP shtool >/dev/null; then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" install_prog="$install_prog$func_quote_for_eval_result" # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= for arg do if test -n "$dest"; then files="$files $dest" dest=$arg continue fi case $arg in -d) isdir=yes ;; -f) case " $install_prog " in *[\\\ /]cp\ *) ;; *) prev=$arg ;; esac ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" install_prog="$install_prog $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the \`$prev' option requires an argument" if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else func_dirname_and_basename "$dest" "" "." destdir="$func_dirname_result" destname="$func_basename_result" # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "\`$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "\`$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. staticlibs="$staticlibs $file" ;; *.la) # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) current_libdirs="$current_libdirs $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) future_libdirs="$future_libdirs $libdir" ;; esac fi func_dirname "$file" "/" "" dir="$func_dirname_result" dir="$dir$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "X$destdir" | $Xsed -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%%"` fi func_warning "relinking \`$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname="$1" shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. func_show_eval "$install_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme="$stripme" case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme="" ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try `ln -sf' first, because the `ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib="$destdir/$realname" func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name="$func_basename_result" instname="$dir/$name"i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest="$destfile" destfile= ;; *) func_fatal_help "cannot copy a libtool object to \`$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext="" case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=".exe" fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script \`$wrapper'" finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile="$libdir/"`$ECHO "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then func_warning "\`$lib' has not been installed in \`$libdir'" finalize=no fi done relink_command= func_source "$wrapper" outputname= if test "$fast_install" = no && test -n "$relink_command"; then $opt_dry_run || { if test "$finalize" = yes; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file="$func_basename_result" outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$ECHO "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` $opt_silent || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink \`$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file="$outputname" else func_warning "cannot relink \`$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name="$func_basename_result" # Set up the ranlib parameters. oldlib="$destdir/$name" func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run \`$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test "$mode" = install && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $opt_debug my_outputname="$1" my_originator="$2" my_pic_p="${3-no}" my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms="${my_outputname}S.c" else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${my_outputname}.nm" func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then func_verbose "generating symbol list for \`$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` for progfile in $progfiles; do func_verbose "extracting global C symbols from \`$progfile'" $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$outputname.exp" $opt_dry_run || { $RM $export_symbols eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from \`$dlprefile'" func_basename "$dlprefile" name="$func_basename_result" $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'" } done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else $ECHO '/* NONE */' >> "$output_objdir/$my_dlsyms" fi $ECHO >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; " case $host in *cygwin* | *mingw* | *cegcc* ) $ECHO >> "$output_objdir/$my_dlsyms" "\ /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */" lt_dlsym_const= ;; *osf5*) echo >> "$output_objdir/$my_dlsyms" "\ /* This system does not cope well with relocations in const data */" lt_dlsym_const= ;; *) lt_dlsym_const=const ;; esac $ECHO >> "$output_objdir/$my_dlsyms" "\ extern $lt_dlsym_const lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[]; $lt_dlsym_const lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = {\ { \"$my_originator\", (void *) 0 }," case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac $ECHO >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) if test "X$my_pic_p" != Xno; then pic_flag_for_symtable=" $pic_flag" fi ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) symtab_cflags="$symtab_cflags $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' # Transform the symbol file into the correct name. symfileobj="$output_objdir/${my_outputname}S.$objext" case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for \`$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` fi } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. func_win32_libid () { $opt_debug win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then win32_nmres=`eval $NM -f posix -A $1 | $SED -n -e ' 1,100{ / I /{ s,.*,import, p q } }'` case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_extract_an_archive dir oldlib func_extract_an_archive () { $opt_debug f_ex_an_ar_dir="$1"; shift f_ex_an_ar_oldlib="$1" func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" 'exit $?' if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $opt_debug my_gentop="$1"; shift my_oldlibs=${1+"$@"} my_oldobjs="" my_xlib="" my_xabs="" my_xdir="" for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib="$func_basename_result" my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir="$my_gentop/$my_xlib_u" func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` darwin_base_archive=`basename "$darwin_archive"` darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches ; do func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" func_extract_an_archive "`pwd`" "${darwin_base_archive}" cd "$darwin_curdir" $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` done func_extract_archives_result="$my_oldobjs" } # func_emit_wrapper_part1 [arg=no] # # Emit the first part of a libtool wrapper script on stdout. # For more information, see the description associated with # func_emit_wrapper(), below. func_emit_wrapper_part1 () { func_emit_wrapper_part1_arg1=no if test -n "$1" ; then func_emit_wrapper_part1_arg1=$1 fi $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed='${SED} -e 1s/^X//' sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then ECHO=\"$qecho\" file=\"\$0\" # Make sure echo works. if test \"X\$1\" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test \"X\`{ \$ECHO '\t'; } 2>/dev/null\`\" = 'X\t'; then # Yippee, \$ECHO works! : else # Restart under the correct shell, and then maybe \$ECHO will work. exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} fi fi\ " $ECHO "\ # Find the directory that this script lives in. thisdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"X\$file\" | \$Xsed -e 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` done " } # end: func_emit_wrapper_part1 # func_emit_wrapper_part2 [arg=no] # # Emit the second part of a libtool wrapper script on stdout. # For more information, see the description associated with # func_emit_wrapper(), below. func_emit_wrapper_part2 () { func_emit_wrapper_part2_arg1=no if test -n "$1" ; then func_emit_wrapper_part2_arg1=$1 fi $ECHO "\ # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_part2_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"X\$thisdir\" | \$Xsed -e 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` export $shlibpath_var " fi # fixup the dll searchpath if we need to. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 fi else # The program doesn't exist. \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 $ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # end: func_emit_wrapper_part2 # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory in which it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=no if test -n "$1" ; then func_emit_wrapper_arg1=$1 fi # split this up so that func_emit_cwrapperexe_src # can call each part independently. func_emit_wrapper_part1 "${func_emit_wrapper_arg1}" func_emit_wrapper_part2 "${func_emit_wrapper_arg1}" } # func_to_host_path arg # # Convert paths to host format when used with build tools. # Intended for use with "native" mingw (where libtool itself # is running under the msys shell), or in the following cross- # build environments: # $build $host # mingw (msys) mingw [e.g. native] # cygwin mingw # *nix + wine mingw # where wine is equipped with the `winepath' executable. # In the native mingw case, the (msys) shell automatically # converts paths for any non-msys applications it launches, # but that facility isn't available from inside the cwrapper. # Similar accommodations are necessary for $host mingw and # $build cygwin. Calling this function does no harm for other # $host/$build combinations not listed above. # # ARG is the path (on $build) that should be converted to # the proper representation for $host. The result is stored # in $func_to_host_path_result. func_to_host_path () { func_to_host_path_result="$1" if test -n "$1" ; then case $host in *mingw* ) lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' case $build in *mingw* ) # actually, msys # awkward: cmd appends spaces to result lt_sed_strip_trailing_spaces="s/[ ]*\$//" func_to_host_path_tmp1=`( cmd //c echo "$1" |\ $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ $SED -e "$lt_sed_naive_backslashify"` ;; *cygwin* ) func_to_host_path_tmp1=`cygpath -w "$1"` func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ $SED -e "$lt_sed_naive_backslashify"` ;; * ) # Unfortunately, winepath does not exit with a non-zero # error code, so we are forced to check the contents of # stdout. On the other hand, if the command is not # found, the shell will set an exit code of 127 and print # *an error message* to stdout. So we must check for both # error code of zero AND non-empty stdout, which explains # the odd construction: func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null` if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ $SED -e "$lt_sed_naive_backslashify"` else # Allow warning below. func_to_host_path_result="" fi ;; esac if test -z "$func_to_host_path_result" ; then func_error "Could not determine host path corresponding to" func_error " '$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_path_result="$1" fi ;; esac fi } # end: func_to_host_path # func_to_host_pathlist arg # # Convert pathlists to host format when used with build tools. # See func_to_host_path(), above. This function supports the # following $build/$host combinations (but does no harm for # combinations not listed here): # $build $host # mingw (msys) mingw [e.g. native] # cygwin mingw # *nix + wine mingw # # Path separators are also converted from $build format to # $host format. If ARG begins or ends with a path separator # character, it is preserved (but converted to $host format) # on output. # # ARG is a pathlist (on $build) that should be converted to # the proper representation on $host. The result is stored # in $func_to_host_pathlist_result. func_to_host_pathlist () { func_to_host_pathlist_result="$1" if test -n "$1" ; then case $host in *mingw* ) lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_to_host_pathlist_tmp2="$1" # Once set for this call, this variable should not be # reassigned. It is used in tha fallback case. func_to_host_pathlist_tmp1=`echo "$func_to_host_pathlist_tmp2" |\ $SED -e 's|^:*||' -e 's|:*$||'` case $build in *mingw* ) # Actually, msys. # Awkward: cmd appends spaces to result. lt_sed_strip_trailing_spaces="s/[ ]*\$//" func_to_host_pathlist_tmp2=`( cmd //c echo "$func_to_host_pathlist_tmp1" |\ $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ $SED -e "$lt_sed_naive_backslashify"` ;; *cygwin* ) func_to_host_pathlist_tmp2=`cygpath -w -p "$func_to_host_pathlist_tmp1"` func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ $SED -e "$lt_sed_naive_backslashify"` ;; * ) # unfortunately, winepath doesn't convert pathlists func_to_host_pathlist_result="" func_to_host_pathlist_oldIFS=$IFS IFS=: for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do IFS=$func_to_host_pathlist_oldIFS if test -n "$func_to_host_pathlist_f" ; then func_to_host_path "$func_to_host_pathlist_f" if test -n "$func_to_host_path_result" ; then if test -z "$func_to_host_pathlist_result" ; then func_to_host_pathlist_result="$func_to_host_path_result" else func_to_host_pathlist_result="$func_to_host_pathlist_result;$func_to_host_path_result" fi fi fi IFS=: done IFS=$func_to_host_pathlist_oldIFS ;; esac if test -z "$func_to_host_pathlist_result" ; then func_error "Could not determine the host path(s) corresponding to" func_error " '$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This may break if $1 contains DOS-style drive # specifications. The fix is not to complicate the expression # below, but for the user to provide a working wine installation # with winepath so that path translation in the cross-to-mingw # case works properly. lt_replace_pathsep_nix_to_dos="s|:|;|g" func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\ $SED -e "$lt_replace_pathsep_nix_to_dos"` fi # Now, add the leading and trailing path separators back case "$1" in :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result" ;; esac case "$1" in *: ) func_to_host_pathlist_result="$func_to_host_pathlist_result;" ;; esac ;; esac fi } # end: func_to_host_pathlist # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include # define setmode _setmode #else # include # include # ifdef __CYGWIN__ # include # define HAVE_SETENV # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif # endif #endif #include #include #include #include #include #include #include #include #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif #ifdef _MSC_VER # define S_IXUSR _S_IEXEC # define stat _stat # ifndef _INTPTR_T_DEFINED # define intptr_t int # endif #endif #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifdef __CYGWIN__ # define FOPEN_WB "wb" #endif #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free ((void *) stale); stale = 0; } \ } while (0) #undef LTWRAPPER_DEBUGPRINTF #if defined DEBUGWRAPPER # define LTWRAPPER_DEBUGPRINTF(args) ltwrapper_debugprintf args static void ltwrapper_debugprintf (const char *fmt, ...) { va_list args; va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } #else # define LTWRAPPER_DEBUGPRINTF(args) #endif const char *program_name = NULL; void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_fatal (const char *message, ...); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_opt_process_env_set (const char *arg); void lt_opt_process_env_prepend (const char *arg); void lt_opt_process_env_append (const char *arg); int lt_split_name_value (const char *arg, char** name, char** value); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); static const char *script_text_part1 = EOF func_emit_wrapper_part1 yes | $SED -e 's/\([\\"]\)/\\\1/g' \ -e 's/^/ "/' -e 's/$/\\n"/' echo ";" cat <"))); for (i = 0; i < newargc; i++) { LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d] : %s\n", i, (newargz[i] ? newargz[i] : ""))); } EOF case $host_os in mingw*) cat <<"EOF" /* execv doesn't actually work on mingw as expected on unix */ rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz); if (rval == -1) { /* failed to start process */ LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno)); return 127; } return rval; EOF ;; *) cat <<"EOF" execv (lt_argv_zero, newargz); return rval; /* =127, but avoids unused variable warning */ EOF ;; esac cat <<"EOF" } void * xmalloc (size_t num) { void *p = (void *) malloc (num); if (!p) lt_fatal ("Memory exhausted"); return p; } char * xstrdup (const char *string) { return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL; } const char * base_name (const char *name) { const char *base; #if defined (HAVE_DOS_BASED_FILE_SYSTEM) /* Skip over the disk name in MSDOS pathnames. */ if (isalpha ((unsigned char) name[0]) && name[1] == ':') name += 2; #endif for (base = name; *name; name++) if (IS_DIR_SEPARATOR (*name)) base = name + 1; return base; } int check_executable (const char *path) { struct stat st; LTWRAPPER_DEBUGPRINTF (("(check_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!")); if ((!path) || (!*path)) return 0; if ((stat (path, &st) >= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; LTWRAPPER_DEBUGPRINTF (("(make_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!")); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; int tmp_len; char *concat_name; LTWRAPPER_DEBUGPRINTF (("(find_executable) : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!")); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined (HAVE_DOS_BASED_FILE_SYSTEM) } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = q - p; p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal ("getcwd failed"); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal ("getcwd failed"); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { LTWRAPPER_DEBUGPRINTF (("checking path component for symlinks: %s\n", tmp_pathspec)); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { char *errstr = strerror (errno); lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal ("Could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (strcmp (str, pat) == 0) *str = '\0'; } return str; } static void lt_error_core (int exit_status, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s: %s: ", program_name, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, "FATAL", message, ap); va_end (ap); } void lt_setenv (const char *name, const char *value) { LTWRAPPER_DEBUGPRINTF (("(lt_setenv) setting '%s' to '%s'\n", (name ? name : ""), (value ? value : ""))); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else int len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { int orig_value_len = strlen (orig_value); int add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } int lt_split_name_value (const char *arg, char** name, char** value) { const char *p; int len; if (!arg || !*arg) return 1; p = strchr (arg, (int)'='); if (!p) return 1; *value = xstrdup (++p); len = strlen (arg) - strlen (*value); *name = XMALLOC (char, len); strncpy (*name, arg, len-1); (*name)[len - 1] = '\0'; return 0; } void lt_opt_process_env_set (const char *arg) { char *name = NULL; char *value = NULL; if (lt_split_name_value (arg, &name, &value) != 0) { XFREE (name); XFREE (value); lt_fatal ("bad argument for %s: '%s'", env_set_opt, arg); } lt_setenv (name, value); XFREE (name); XFREE (value); } void lt_opt_process_env_prepend (const char *arg) { char *name = NULL; char *value = NULL; char *new_value = NULL; if (lt_split_name_value (arg, &name, &value) != 0) { XFREE (name); XFREE (value); lt_fatal ("bad argument for %s: '%s'", env_prepend_opt, arg); } new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); XFREE (name); XFREE (value); } void lt_opt_process_env_append (const char *arg) { char *name = NULL; char *value = NULL; char *new_value = NULL; if (lt_split_name_value (arg, &name, &value) != 0) { XFREE (name); XFREE (value); lt_fatal ("bad argument for %s: '%s'", env_append_opt, arg); } new_value = lt_extend_str (getenv (name), value, 1); lt_setenv (name, new_value); XFREE (new_value); XFREE (name); XFREE (value); } void lt_update_exe_path (const char *name, const char *value) { LTWRAPPER_DEBUGPRINTF (("(lt_update_exe_path) modifying '%s' by prepending '%s'\n", (name ? name : ""), (value ? value : ""))); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ int len = strlen (new_value); while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[len-1] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { LTWRAPPER_DEBUGPRINTF (("(lt_update_lib_path) modifying '%s' by prepending '%s'\n", (name ? name : ""), (value ? value : ""))); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF } # end: func_emit_cwrapperexe_src # func_mode_link arg... func_mode_link () { $opt_debug case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll which has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=no prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module="${wl}-single_module" func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg="$1" shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then dlfiles="$dlfiles $arg" else dlprefiles="$dlprefiles $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" test -f "$arg" \ || func_fatal_error "symbol file \`$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) deplibs="$deplibs $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # moreargs="$moreargs $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then dlfiles="$dlfiles $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. dlprefiles="$dlprefiles $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file \`$arg' does not exist" fi arg=$save_arg prev= continue ;; precious_regex) precious_files_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) rpath="$rpath $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) xrpath="$xrpath $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds="$arg" prev= continue ;; weak) weak_libs="$weak_libs $arg" prev= continue ;; xcclinker) linker_flags="$linker_flags $qarg" compiler_flags="$compiler_flags $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) compiler_flags="$compiler_flags $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) linker_flags="$linker_flags $qarg" compiler_flags="$compiler_flags $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "\`-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname '-L' '' "$arg" dir=$func_stripname_result if test -z "$dir"; then if test "$#" -gt 0; then func_fatal_error "require no space between \`-L' and \`$1'" else func_fatal_error "need path for \`-L' option" fi fi # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of \`$dir'" dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "*) ;; *) deplibs="$deplibs -L$dir" lib_search_path="$lib_search_path $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "X$dir" | $Xsed -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) dllsearchpath="$dllsearchpath:$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) dllsearchpath="$dllsearchpath:$testbindir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework deplibs="$deplibs System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test "X$arg" = "X-lc" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test "X$arg" = "X-lc" && continue ;; esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi deplibs="$deplibs $arg" continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot) compiler_flags="$compiler_flags $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) compiler_flags="$compiler_flags $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;; esac continue ;; -multi_module) single_module="${wl}-multi_module" continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "\`-no-install' is ignored for $host" func_warning "assuming \`-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) xrpath="$xrpath $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" arg="$arg $wl$func_quote_for_eval_result" compiler_flags="$compiler_flags $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" arg="$arg $wl$func_quote_for_eval_result" compiler_flags="$compiler_flags $wl$func_quote_for_eval_result" linker_flags="$linker_flags $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; # -64, -mips[0-9] enable 64-bit mode on the SGI compiler # -r[0-9][0-9]* specifies the processor on the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler # +DA*, +DD* enable 64-bit mode on the HP compiler # -q* pass through compiler args for the IBM compiler # -m*, -t[45]*, -txscale* pass through architecture-specific # compiler args for GCC # -F/path gives path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC # @file GCC response files -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" func_append compile_command " $arg" func_append finalize_command " $arg" compiler_flags="$compiler_flags $arg" continue ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; *.$objext) # A standard object. objs="$objs $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then dlfiles="$dlfiles $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. dlprefiles="$dlprefiles $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. deplibs="$deplibs $arg" old_deplibs="$old_deplibs $arg" continue ;; *.la) # A libtool-controlled library. if test "$prev" = dlfiles; then # This library was specified with -dlopen. dlfiles="$dlfiles $arg" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. dlprefiles="$dlprefiles $arg" prev= else deplibs="$deplibs $arg" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the \`$prevarg' option requires an argument" if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname="$func_basename_result" libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" func_dirname "$output" "/" "" output_objdir="$func_dirname_result$objdir" # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_duplicate_deps ; then case "$libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi libs="$libs $deplib" done if test "$linkmode" = lib; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; esac pre_post_deps="$pre_post_deps $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test "$linkmode,$pass" = "lib,link"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs="$tmp_deplibs" fi if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS%" test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" ;; esac fi if test "$linkmode,$pass" = "lib,dlpreopen"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= case $lib in *.la) func_source "$lib" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do deplib_base=`$ECHO "X$deplib" | $Xsed -e "$basename"` case " $weak_libs " in *" $deplib_base "*) ;; *) deplibs="$deplibs $deplib" ;; esac done done libs="$dlprefiles" fi if test "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else compiler_flags="$compiler_flags $deplib" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; esac fi fi continue ;; -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then func_warning "\`-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test "$linkmode" = lib; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" if test -f "$lib"; then if test "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll="$l" done if test "X$ll" = "X$old_library" ; then # only static version available found=no func_dirname "$lib" "" "." ladir="$func_dirname_result" lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l *.ltframework) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" newlib_search_path="$newlib_search_path $func_stripname_result" ;; prog) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" newlib_search_path="$newlib_search_path $func_stripname_result" ;; *) func_warning "\`-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test "$pass" = link; then func_stripname '-R' '' "$deplib" dir=$func_stripname_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) xrpath="$xrpath $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) lib="$deplib" ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=no case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"X$deplib\"" 2>/dev/null | $Xsed -e 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=yes fi ;; pass_all) valid_a_lib=yes ;; esac if test "$valid_a_lib" != yes; then $ECHO $ECHO "*** Warning: Trying to link with static lib archive $deplib." $ECHO "*** I have the capability to make that library automatically link in when" $ECHO "*** you link to this library. But I can only do this if you have a" $ECHO "*** shared version of the library, which you do not appear to have" $ECHO "*** because the file extensions .$libext of this argument makes me believe" $ECHO "*** that it is just a static archive that I should not use here." else $ECHO $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi ;; esac continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. newdlprefiles="$newdlprefiles $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else newdlfiles="$newdlfiles $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" fi # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "\`$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir="$func_dirname_result" dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "X$inherited_linker_flags" | $Xsed -e 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO "X $dependency_libs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && dlfiles="$dlfiles $dlopen" test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" fi if test "$pass" = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # It is a libtool convenience library, so add in its objects. convenience="$convenience $ladir/$objdir/$old_library" old_convenience="$old_convenience $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_duplicate_deps ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done elif test "$linkmode" != prog && test "$linkmode" != lib; then func_fatal_error "\`$lib' is not a convenience library" fi continue fi # $pass = conv # Get the name of the library we link against. linklib= for l in $old_library $library_names; do linklib="$l" done if test -z "$linklib"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # This library was specified with -dlopen. if test "$pass" = dlopen; then if test -z "$libdir"; then func_fatal_error "cannot -dlopen a convenience library: \`$lib'" fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. dlprefiles="$dlprefiles $lib $dependency_libs" else newdlfiles="$newdlfiles $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of \`$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir="$ladir" fi ;; esac func_basename "$lib" laname="$func_basename_result" # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library \`$lib' was moved." dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$libdir" absdir="$libdir" fi test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir="$ladir" absdir="$abs_ladir" # Remove this search path later notinst_path="$notinst_path $abs_ladir" else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later notinst_path="$notinst_path $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test "$pass" = dlpreopen; then if test -z "$libdir" && test "$linkmode" = prog; then func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" fi # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then newdlprefiles="$newdlprefiles $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then newdlprefiles="$newdlprefiles $dir/$dlname" else newdlprefiles="$newdlprefiles $dir/$linklib" fi fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test "$linkmode" = prog && test "$pass" != link; then newlib_search_path="$newlib_search_path $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" newlib_search_path="$newlib_search_path $func_stripname_result" ;; esac # Need to link against all dependency_libs? if test "$linkalldeplibs" = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_duplicate_deps ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done # for deplib continue fi # $linkmode = prog... if test "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { { test "$prefer_static_libs" = no || test "$prefer_static_libs,$installed" = "built,yes"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then # Make sure the rpath contains only unique directories. case "$temp_rpath:" in *"$absdir:"*) ;; *) temp_rpath="$temp_rpath$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) compile_rpath="$compile_rpath $absdir" esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" esac ;; esac fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test "$use_static_libs" = built && test "$installed" = yes; then use_static_libs=no fi if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded notinst_deplibs="$notinst_deplibs $lib" need_relink=no ;; *) if test "$installed" = no; then notinst_deplibs="$notinst_deplibs $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule="" for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule="$dlpremoduletest" break fi done if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then $ECHO if test "$linkmode" = prog; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test "$linkmode" = lib && test "$hardcode_into_libs" = yes; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) compile_rpath="$compile_rpath $absdir" esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname="$1" shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc*) func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" func_basename "$soroot" soname="$func_basename_result" func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from \`$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for \`$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test "$linkmode" = prog || test "$mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" case $host in *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; *-*-sysv4*uw2*) add_dir="-L$dir" ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir="-L$dir" ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we can not # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null ; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library" ; then $ECHO $ECHO "*** And there doesn't seem to be a static archive available" $ECHO "*** The link will probably fail, sorry" else add="$dir/$old_library" fi elif test -n "$old_library"; then add="$dir/$old_library" fi fi esac elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$dir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) add_dir="$add_dir -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && test "$hardcode_minus_L" != yes && test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then add="$inst_prefix_dir$libdir/$linklib" else add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) add_dir="$add_dir -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" fi if test "$linkmode" = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test "$linkmode" = prog; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. $ECHO $ECHO "*** Warning: This system can not link to static lib archive $lib." $ECHO "*** I have the capability to make that library automatically link in when" $ECHO "*** you link to this library. But I can only do this if you have a" $ECHO "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then $ECHO "*** But as you try to build a module library, libtool will still create " $ECHO "*** a static module, that should work as long as the dlopening application" $ECHO "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then $ECHO $ECHO "*** However, this would only work if libtool was able to extract symbol" $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" $ECHO "*** not find such a program. So, this module is probably useless." $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) xrpath="$xrpath $temp_xrpath";; esac;; *) temp_deplibs="$temp_deplibs $libdir";; esac done dependency_libs="$temp_deplibs" fi newlib_search_path="$newlib_search_path $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" if $opt_duplicate_deps ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path="$deplib" ;; *.la) func_dirname "$deplib" "" "." dir="$func_dirname_result" # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of \`$dir'" absdir="$dir" fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl" ; then depdepl="$absdir/$objdir/$depdepl" darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}" path= fi fi ;; *) path="-L$absdir/$objdir" ;; esac else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "\`$deplib' seems to be moved" path="-L$absdir" fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test "$pass" = link; then if test "$linkmode" = "prog"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs="$newdependency_libs" if test "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) lib_search_path="$lib_search_path $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) tmp_libs="$tmp_libs $deplib" ;; esac ;; *) tmp_libs="$tmp_libs $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs ; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i="" ;; esac if test -n "$i" ; then tmp_libs="$tmp_libs $i" fi done dependency_libs=$tmp_libs done # for pass if test "$linkmode" = prog; then dlfiles="$newdlfiles" fi if test "$linkmode" = prog || test "$linkmode" = lib; then dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "\`-R' is ignored for archives" test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "\`-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "\`-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" objs="$objs$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test "$module" = no && \ func_fatal_help "libtool library \`$output' must begin with \`lib'" if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" else $ECHO $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" libobjs="$libobjs $objs" fi fi test "$dlself" != no && \ func_warning "\`-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test "$#" -gt 1 && \ func_warning "ignoring multiple \`-rpath's for a libtool library" install_libdir="$1" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. # Some compilers have problems with a `.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "\`-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 shift IFS="$save_ifs" test -n "$7" && \ func_fatal_help "too many parameters to \`-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major="$1" number_minor="$2" number_revision="$3" # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # which has an extra 1 added just for fun # case $version_type in darwin|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|sunos) current="$number_major" revision="$number_minor" age="0" ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_minor" lt_irix_increment=no ;; *) func_fatal_configuration "$modename: unknown library version type \`$version_type'" ;; esac ;; no) current="$1" revision="$2" age="$3" ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT \`$current' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION \`$revision' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE \`$age' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE \`$age' is greater than the current interface number \`$current'" func_fatal_error "\`$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current" ;; irix | nonstopux) if test "X$lt_irix_increment" = "Xno"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test "$loop" -ne 0; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test "$loop" -ne 0; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring:${iface}.0" done # Make executables depend on our current version. verstring="$verstring:${current}.0" ;; qnx) major=".$current" versuffix=".$current" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; *) func_fatal_configuration "unknown library version type \`$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then func_warning "undefined symbols not allowed in $host shared libraries" build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi func_generate_dlsyms "$libname" "$libname" "yes" libobjs="$libobjs $symfileobj" test "X$libobjs" = "X " && libobjs= if test "$mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) if test "X$precious_files_regex" != "X"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi removelist="$removelist $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then oldlibs="$oldlibs $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "X$lib_search_path " | $Xsed -e "s% $path % %g"` # deplibs=`$ECHO "X$deplibs " | $Xsed -e "s% -L$path % %g"` # dependency_libs=`$ECHO "X$dependency_libs " | $Xsed -e "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do temp_xrpath="$temp_xrpath -R$libdir" case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) dlfiles="$dlfiles $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) dlprefiles="$dlprefiles $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework deplibs="$deplibs System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then deplibs="$deplibs -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$ECHO "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes $ECHO $ECHO "*** Warning: linker path does not have real file for library $a_deplib." $ECHO "*** I have the capability to make that library automatically link in when" $ECHO "*** you link to this library. But I can only do this if you have a" $ECHO "*** shared version of the library, which you do not appear to have" $ECHO "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) newdeplibs="$newdeplibs $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test if eval "\$ECHO \"X$potent_lib\"" 2>/dev/null | $Xsed -e 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes $ECHO $ECHO "*** Warning: linker path does not have real file for library $a_deplib." $ECHO "*** I have the capability to make that library automatically link in when" $ECHO "*** you link to this library. But I can only do this if you have a" $ECHO "*** shared version of the library, which you do not appear to have" $ECHO "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" tmp_deplibs=`$ECHO "X $deplibs" | $Xsed \ -e 's/ -lc$//' -e 's/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO "X $tmp_deplibs" | $Xsed -e "s,$i,,"` done fi if $ECHO "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' | $GREP . >/dev/null; then $ECHO if test "X$deplibs_check_method" = "Xnone"; then $ECHO "*** Warning: inter-library dependencies are not supported in this platform." else $ECHO "*** Warning: inter-library dependencies are not known to be supported." fi $ECHO "*** All declared inter-library dependencies are being dropped." droppeddeps=yes fi ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's/ -lc / System.ltframework /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then $ECHO $ECHO "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" $ECHO "*** a static module, that should work as long as the dlopening" $ECHO "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then $ECHO $ECHO "*** However, this would only work if libtool was able to extract symbol" $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" $ECHO "*** not find such a program. So, this module is probably useless." $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else $ECHO "*** The inter-library dependencies that have been dropped here will be" $ECHO "*** automatically added whenever a program is linked with this library" $ECHO "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then $ECHO $ECHO "*** Since this library must not contain undefined symbols," $ECHO "*** because either the platform does not support them or" $ECHO "*** it was explicitly requested with -no-undefined," $ECHO "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO "X $deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) new_libs="$new_libs -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$new_libs $deplib" ;; esac ;; *) new_libs="$new_libs $deplib" ;; esac done deplibs="$new_libs" # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" dep_rpath="$dep_rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" if test -n "$hardcode_libdir_flag_spec_ld"; then eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" else eval dep_rpath=\"$hardcode_libdir_flag_spec\" fi fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname="$1" shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi if test -z "$dlname"; then dlname=$soname fi lib="$output_objdir/$realname" linknames= for link do linknames="$linknames $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols="$output_objdir/$libname.uexp" delfiles="$delfiles $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile if test "x`$SED 1q $export_symbols`" != xEXPORTS; then # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols="$export_symbols" export_symbols= always_export_symbols=yes fi fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" func_len " $cmd" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then func_show_eval "$cmd" 'exit $?' skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS="$save_ifs" if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' fi if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) tmp_deplibs="$tmp_deplibs $test_deplib" ;; esac done deplibs="$tmp_deplibs" if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test "$compiler_needs_object" = yes && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $convenience libobjs="$libobjs $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" linker_flags="$linker_flags $flag" fi # Make a backup of the uninstalled library when relinking if test "$mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test "X$skipped_export" != "X:" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output output_la=`$ECHO "X$output" | $Xsed -e "$basename"` # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then output=${output_objdir}/${output_la}.lnkscript func_verbose "creating GNU ld script: $output" $ECHO 'INPUT (' > $output for obj in $save_libobjs do $ECHO "$obj" >> $output done $ECHO ')' >> $output delfiles="$delfiles $output" elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then output=${output_objdir}/${output_la}.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test "$compiler_needs_object" = yes; then firstobj="$1 " shift fi for obj do $ECHO "$obj" >> $output done delfiles="$delfiles $output" output=$firstobj\"$file_list_spec$output\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-${k}.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test "X$objlist" = X || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. eval concat_cmds=\"$reload_cmds $objlist $last_robj\" else # All subsequent reloadable object files will link in # the last one created. eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-${k}.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-${k}.$objext objlist=$obj func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" if test -n "$last_robj"; then eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" fi delfiles="$delfiles $output" else output= fi if ${skipped_export-false}; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi fi test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs="$IFS"; IFS='~' for cmd in $concat_cmds; do IFS="$save_ifs" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi if ${skipped_export-false}; then if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi fi libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $dlprefiles libobjs="$libobjs $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "\`-R' is ignored for objects" test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for objects" test -n "$release" && \ func_warning "\`-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object \`$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec and hope we can get by with # turning comma into space.. wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" reload_conv_objs=$reload_objs\ `$ECHO "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'` else gentop="$output_objdir/${obj}x" generated="$generated $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # Create the old-style object. reload_objs="$objs$old_deplibs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for programs" test -n "$release" && \ func_warning "\`-release' is ignored for programs" test "$preload" = yes \ && test "$dlopen_support" = unknown \ && test "$dlopen_self" = unknown \ && test "$dlopen_self_static" = unknown && \ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test "$tagname" = CXX ; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) compile_command="$compile_command ${wl}-bind_at_load" finalize_command="$finalize_command ${wl}-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) new_libs="$new_libs -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$new_libs $deplib" ;; esac ;; *) new_libs="$new_libs $deplib" ;; esac done compile_deplibs="$new_libs" compile_command="$compile_command $compile_deplibs" finalize_command="$finalize_command $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) dllsearchpath="$dllsearchpath:$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) dllsearchpath="$dllsearchpath:$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$ECHO "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` finalize_command=`$ECHO "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" "no" # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=yes case $host in *cygwin* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; *cegcc) # Disable wrappers for cegcc, we are cross compiling anyway. wrappers_required=no ;; *) if test "$need_relink" = no || test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; esac if test "$wrappers_required" = no; then # Replace the output file specification. compile_command=`$ECHO "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' # Delete the generated files. if test -f "$output_objdir/${outputname}S.${objext}"; then func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' fi exit $exit_status fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do rpath="$rpath$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' exit $EXIT_SUCCESS fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" func_warning "this platform does not like uninstalled shared libraries" func_warning "\`$output' will be relinked during installation" else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$ECHO "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` fi # Quote $ECHO for shipping. if test "X$ECHO" = "X$SHELL $progpath --fallback-echo"; then case $progpath in [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; esac qecho=`$ECHO "X$qecho" | $Xsed -e "$sed_quote_subst"` else qecho=`$ECHO "X$ECHO" | $Xsed -e "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource="$output_path/$objdir/lt-$output_name.c" cwrapper="$output_path/$output_name.exe" $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host" ; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save $symfileobj" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" if test "$preload" = yes && test -f "$symfileobj"; then oldobjs="$oldobjs $symfileobj" fi fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $addlibs oldobjs="$oldobjs $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $dlprefiles oldobjs="$oldobjs $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else $ECHO "copying selected object files to avoid basename conflicts..." gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase="$func_basename_result" case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" oldobjs="$oldobjs $gentop/$newobj" ;; *) oldobjs="$oldobjs $obj" ;; esac done fi eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test "X$oldobjs" = "X" ; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` if test "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" newdependency_libs="$newdependency_libs $libdir/$name" ;; *) newdependency_libs="$newdependency_libs $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" newdlfiles="$newdlfiles $libdir/$name" ;; *) newdlfiles="$newdlfiles $lib" ;; esac done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" newdlprefiles="$newdlprefiles $libdir/$name" ;; esac done dlprefiles="$newdlprefiles" else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac newdlfiles="$newdlfiles $abs" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac newdlprefiles="$newdlprefiles $abs" done dlprefiles="$newdlprefiles" fi $RM $output # place dlname in correct position for cygwin tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that can not go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test "$need_relink" = yes; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } { test "$mode" = link || test "$mode" = relink; } && func_mode_link ${1+"$@"} # func_mode_uninstall arg... func_mode_uninstall () { $opt_debug RM="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) RM="$RM $arg"; rmforce=yes ;; -*) RM="$RM $arg" ;; *) files="$files $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= origobjdir="$objdir" for file in $files; do func_dirname "$file" "" "." dir="$func_dirname_result" if test "X$dir" = X.; then objdir="$origobjdir" else objdir="$dir/$origobjdir" fi func_basename "$file" name="$func_basename_result" test "$mode" = uninstall && objdir="$dir" # Remember objdir for removal later, being careful to avoid duplicates if test "$mode" = clean; then case " $rmdirs " in *" $objdir "*) ;; *) rmdirs="$rmdirs $objdir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do rmfiles="$rmfiles $objdir/$n" done test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" case "$mode" in clean) case " $library_names " in # " " in the beginning catches empty $dlname *" $dlname "*) ;; *) rmfiles="$rmfiles $objdir/$dlname" ;; esac test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test "$pic_object" != none; then rmfiles="$rmfiles $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test "$non_pic_object" != none; then rmfiles="$rmfiles $dir/$non_pic_object" fi fi ;; *) if test "$mode" = clean ; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe rmfiles="$rmfiles $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result rmfiles="$rmfiles $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then rmfiles="$rmfiles $objdir/lt-$name" fi if test "X$noexename" != "X$name" ; then rmfiles="$rmfiles $objdir/lt-${noexename}.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done objdir="$origobjdir" # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } { test "$mode" = uninstall || test "$mode" = clean; } && func_mode_uninstall ${1+"$@"} test -z "$mode" && { help="$generic_help" func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode \`$mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: # vi:sw=2 # ### BEGIN LIBTOOL TAG CONFIG: CXX # The linker used to build libraries. LD="/usr/bin/ld -m elf_x86_64" # Commands used to build an old-style archive. old_archive_cmds="\$AR \$AR_FLAGS \$oldlib\$oldobjs~\$RANLIB \$oldlib" # A language specific compiler. CC="g++" # Is the compiler the GNU compiler? with_gcc=yes # Compiler flag to turn off builtin functions. no_builtin_flag=" -fno-builtin" # How to pass a linker flag through the compiler. wl="-Wl," # Additional compiler flags for building library objects. pic_flag=" -fPIC -DPIC" # Compiler flag to prevent dynamic linking. link_static_flag="-static" # Does compiler simultaneously support -c and -o options? compiler_c_o="yes" # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=no # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=no # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec="\${wl}--export-dynamic" # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec="\${wl}--whole-archive\$convenience \${wl}--no-whole-archive" # Whether the compiler copes with passing no objects directly. compiler_needs_object="no" # Create an old-style archive from a shared archive. old_archive_from_new_cmds="" # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds="" # Commands used to build a shared archive. archive_cmds="\$CC -shared -nostdlib \$predep_objects \$libobjs \$deplibs \$postdep_objects \$compiler_flags \${wl}-soname \$wl\$soname -o \$lib" archive_expsym_cmds="\$CC -shared -nostdlib \$predep_objects \$libobjs \$deplibs \$postdep_objects \$compiler_flags \${wl}-soname \$wl\$soname \${wl}-retain-symbols-file \$wl\$export_symbols -o \$lib" # Commands used to build a loadable module if different from building # a shared archive. module_cmds="" module_expsym_cmds="" # Whether we are building with GNU ld or not. with_gnu_ld="yes" # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag="" # Flag that enforces no undefined symbols. no_undefined_flag="" # Flag to hardcode $libdir into a binary during linking. # This must work even if $libdir does not exist hardcode_libdir_flag_spec="\${wl}-rpath \${wl}\$libdir" # If ld is used when linking, flag to hardcode $libdir into a binary # during linking. This must work even if $libdir does not exist. hardcode_libdir_flag_spec_ld="" # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator="" # Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=no # Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting ${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=no # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=no # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=unsupported # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=no # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=no # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=no # Fix the shell variable $srcfile for the compiler. fix_srcfile_path="" # Set to "yes" if exported symbols are required. always_export_symbols=no # The commands to list exported symbols. export_symbols_cmds="\$NM \$libobjs \$convenience | \$global_symbol_pipe | \$SED 's/.* //' | sort | uniq > \$export_symbols" # Symbols that should not be listed in the preloaded symbols. exclude_expsyms="_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*" # Symbols that must always be exported. include_expsyms="" # Commands necessary for linking programs (against libraries) with templates. prelink_cmds="" # Specify filename containing input files. file_list_spec="" # How to hardcode a shared library path into an executable. hardcode_action=immediate # The directories searched by this compiler when creating a shared library. compiler_lib_search_dirs="/usr/lib/gcc/x86_64-linux-gnu/4.4.3 /usr/lib/gcc/x86_64-linux-gnu/4.4.3 /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../lib /lib/../lib /usr/lib/../lib /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../.. /usr/lib/x86_64-linux-gnu" # Dependencies to place before and after the objects being linked to # create a shared library. predep_objects="/usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../lib/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.4.3/crtbeginS.o" postdep_objects="/usr/lib/gcc/x86_64-linux-gnu/4.4.3/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../lib/crtn.o" predeps="" postdeps="-lstdc++ -lm -lgcc_s -lc -lgcc_s" # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path="-L/usr/lib/gcc/x86_64-linux-gnu/4.4.3 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.3 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../.. -L/usr/lib/x86_64-linux-gnu" # ### END LIBTOOL TAG CONFIG: CXX ================================================ FILE: distro/google-perftools-1.7/ltmain.sh ================================================ # Generated from ltmain.m4sh. # ltmain.sh (GNU libtool) 2.2.6b # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 2008 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool 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 2 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, # or obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Usage: $progname [OPTION]... [MODE-ARG]... # # Provide generalized library-building support services. # # --config show all configuration variables # --debug enable verbose shell tracing # -n, --dry-run display commands without modifying any files # --features display basic configuration information and exit # --mode=MODE use operation mode MODE # --preserve-dup-deps don't remove duplicate dependency libraries # --quiet, --silent don't print informational messages # --tag=TAG use configuration variables from tag TAG # -v, --verbose print informational messages (default) # --version print version information # -h, --help print short or long help message # # MODE must be one of the following: # # clean remove files from the build directory # compile compile a source file into a libtool object # execute automatically set library path, then run a program # finish complete the installation of libtool libraries # install install libraries or executables # link create a library or an executable # uninstall remove libraries from an installed directory # # MODE-ARGS vary depending on the MODE. # Try `$progname --help --mode=MODE' for a more detailed description of MODE. # # When reporting a bug, please describe a test case to reproduce it and # include the following information: # # host-triplet: $host # shell: $SHELL # compiler: $LTCC # compiler flags: $LTCFLAGS # linker: $LD (gnu? $with_gnu_ld) # $progname: (GNU libtool) 2.2.6b Debian-2.2.6b-2ubuntu1 # automake: $automake_version # autoconf: $autoconf_version # # Report bugs to . PROGRAM=ltmain.sh PACKAGE=libtool VERSION="2.2.6b Debian-2.2.6b-2ubuntu1" TIMESTAMP="" package_revision=1.3017 # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # NLS nuisances: We save the old values to restore during execute mode. # Only set LANG and LC_ALL to C if already set. # These must not be set unconditionally because not all systems understand # e.g. LANG=C (notably SCO). lt_user_locale= lt_safe_locale= for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${$lt_var+set}\" = set; then save_$lt_var=\$$lt_var $lt_var=C export $lt_var lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" fi" done $lt_unset CDPATH : ${CP="cp -f"} : ${ECHO="echo"} : ${EGREP="/bin/grep -E"} : ${FGREP="/bin/grep -F"} : ${GREP="/bin/grep"} : ${LN_S="ln -s"} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SED="/bin/sed"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} : ${Xsed="$SED -e 1s/^X//"} # Global variables: EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. exit_status=$EXIT_SUCCESS # Make sure IFS has a sensible default lt_nl=' ' IFS=" $lt_nl" dirname="s,/[^/]*$,," basename="s,^.*/,," # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` } # Generated shell functions inserted here. # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath="$0" # The name of this program: # In the unlikely event $progname began with a '-', it would play havoc with # func_echo (imagine progname=-n), so we prepend ./ in that case: func_dirname_and_basename "$progpath" progname=$func_basename_result case $progname in -*) progname=./$progname ;; esac # Make sure we have an absolute path for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=$func_dirname_result progdir=`cd "$progdir" && pwd` progpath="$progdir/$progname" ;; *) save_IFS="$IFS" IFS=: for progdir in $PATH; do IFS="$save_IFS" test -x "$progdir/$progname" && break done IFS="$save_IFS" test -n "$progdir" || progdir=`pwd` progpath="$progdir/$progname" ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed="${SED}"' -e 1s/^X//' sed_quote_subst='s/\([`"$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Re-`\' parameter expansions in output of double_quote_subst that were # `\'-ed in input to the same. If an odd number of `\' preceded a '$' # in input to double_quote_subst, that '$' was protected from expansion. # Since each input `\' is now two `\'s, look for any number of runs of # four `\'s followed by two `\'s and then a '$'. `\' that '$'. bs='\\' bs2='\\\\' bs4='\\\\\\\\' dollar='\$' sed_double_backslash="\ s/$bs4/&\\ /g s/^$bs2$dollar/$bs&/ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g s/\n//g" # Standard options: opt_dry_run=false opt_help=false opt_quiet=false opt_verbose=false opt_warning=: # func_echo arg... # Echo program name prefixed message, along with the current mode # name if it has been set yet. func_echo () { $ECHO "$progname${mode+: }$mode: $*" } # func_verbose arg... # Echo program name prefixed message in verbose mode only. func_verbose () { $opt_verbose && func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_error arg... # Echo program name prefixed message to standard error. func_error () { $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2 } # func_warning arg... # Echo program name prefixed warning message to standard error. func_warning () { $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2 # bash bug again: : } # func_fatal_error arg... # Echo program name prefixed message to standard error, and exit. func_fatal_error () { func_error ${1+"$@"} exit $EXIT_FAILURE } # func_fatal_help arg... # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { func_error ${1+"$@"} func_fatal_error "$help" } help="Try \`$progname --help' for more information." ## default # func_grep expression filename # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $GREP "$1" "$2" >/dev/null 2>&1 } # func_mkdir_p directory-path # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { my_directory_path="$1" my_dir_list= if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then # Protect directory names starting with `-' case $my_directory_path in -*) my_directory_path="./$my_directory_path" ;; esac # While some portion of DIR does not yet exist... while test ! -d "$my_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. my_dir_list="$my_directory_path:$my_dir_list" # If the last portion added has no slash in it, the list is done case $my_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop my_directory_path=`$ECHO "X$my_directory_path" | $Xsed -e "$dirname"` done my_dir_list=`$ECHO "X$my_dir_list" | $Xsed -e 's,:*$,,'` save_mkdir_p_IFS="$IFS"; IFS=':' for my_dir in $my_dir_list; do IFS="$save_mkdir_p_IFS" # mkdir can fail with a `File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$my_dir" 2>/dev/null || : done IFS="$save_mkdir_p_IFS" # Bail out if we (or some other process) failed to create a directory. test -d "$my_directory_path" || \ func_fatal_error "Failed to create \`$1'" fi } # func_mktempdir [string] # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, STRING is the basename for that directory. func_mktempdir () { my_template="${TMPDIR-/tmp}/${1-$progname}" if test "$opt_dry_run" = ":"; then # Return a directory name, but don't create it in dry-run mode my_tmpdir="${my_template}-$$" else # If mktemp works, use that first and foremost my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` if test ! -d "$my_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race my_tmpdir="${my_template}-${RANDOM-0}$$" save_mktempdir_umask=`umask` umask 0077 $MKDIR "$my_tmpdir" umask $save_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$my_tmpdir" || \ func_fatal_error "cannot create temporary directory \`$my_tmpdir'" fi $ECHO "X$my_tmpdir" | $Xsed } # func_quote_for_eval arg # Aesthetically quote ARG to be evaled later. # This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT # is double-quoted, suitable for a subsequent eval, whereas # FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters # which are still active within double quotes backslashified. func_quote_for_eval () { case $1 in *[\\\`\"\$]*) func_quote_for_eval_unquoted_result=`$ECHO "X$1" | $Xsed -e "$sed_quote_subst"` ;; *) func_quote_for_eval_unquoted_result="$1" ;; esac case $func_quote_for_eval_unquoted_result in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and and variable # expansion for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" ;; *) func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" esac } # func_quote_for_expand arg # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { case $1 in *[\\\`\"]*) my_arg=`$ECHO "X$1" | $Xsed \ -e "$double_quote_subst" -e "$sed_double_backslash"` ;; *) my_arg="$1" ;; esac case $my_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") my_arg="\"$my_arg\"" ;; esac func_quote_for_expand_result="$my_arg" } # func_show_eval cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$my_cmd" my_status=$? if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_show_eval_locale cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$lt_user_locale $my_cmd" my_status=$? eval "$lt_safe_locale" if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_version # Echo version message to standard output and exit. func_version () { $SED -n '/^# '$PROGRAM' (GNU /,/# warranty; / { s/^# // s/^# *$// s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ p }' < "$progpath" exit $? } # func_usage # Echo short help message to standard output and exit. func_usage () { $SED -n '/^# Usage:/,/# -h/ { s/^# // s/^# *$// s/\$progname/'$progname'/ p }' < "$progpath" $ECHO $ECHO "run \`$progname --help | more' for full usage" exit $? } # func_help # Echo long help message to standard output and exit. func_help () { $SED -n '/^# Usage:/,/# Report bugs to/ { s/^# // s/^# *$// s*\$progname*'$progname'* s*\$host*'"$host"'* s*\$SHELL*'"$SHELL"'* s*\$LTCC*'"$LTCC"'* s*\$LTCFLAGS*'"$LTCFLAGS"'* s*\$LD*'"$LD"'* s/\$with_gnu_ld/'"$with_gnu_ld"'/ s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/ s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/ p }' < "$progpath" exit $? } # func_missing_arg argname # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { func_error "missing argument for $1" exit_cmd=exit } exit_cmd=: # Check that we have a working $ECHO. if test "X$1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X$1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then # Yippee, $ECHO works! : else # Restart under the correct shell, and then maybe $ECHO will work. exec $SHELL "$progpath" --no-reexec ${1+"$@"} fi if test "X$1" = X--fallback-echo; then # used as fallback echo shift cat </dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # Parse options once, thoroughly. This comes as soon as possible in # the script to make things like `libtool --version' happen quickly. { # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; esac # Parse non-mode specific arguments: while test "$#" -gt 0; do opt="$1" shift case $opt in --config) func_config ;; --debug) preserve_args="$preserve_args $opt" func_echo "enabling shell trace mode" opt_debug='set -x' $opt_debug ;; -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break execute_dlfiles="$execute_dlfiles $1" shift ;; --dry-run | -n) opt_dry_run=: ;; --features) func_features ;; --finish) mode="finish" ;; --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break case $1 in # Valid mode arguments: clean) ;; compile) ;; execute) ;; finish) ;; install) ;; link) ;; relink) ;; uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $opt" exit_cmd=exit break ;; esac mode="$1" shift ;; --preserve-dup-deps) opt_duplicate_deps=: ;; --quiet|--silent) preserve_args="$preserve_args $opt" opt_silent=: ;; --verbose| -v) preserve_args="$preserve_args $opt" opt_silent=false ;; --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break preserve_args="$preserve_args $opt $1" func_enable_tag "$1" # tagname is set here shift ;; # Separate optargs to long options: -dlopen=*|--mode=*|--tag=*) func_opt_split "$opt" set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"} shift ;; -\?|-h) func_usage ;; --help) opt_help=: ;; --version) func_version ;; -*) func_fatal_help "unrecognized option \`$opt'" ;; *) nonopt="$opt" break ;; esac done case $host in *cygwin* | *mingw* | *pw32* | *cegcc*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_duplicate_deps ;; esac # Having warned about all mis-specified options, bail out if # anything was wrong. $exit_cmd $EXIT_FAILURE } # func_check_version_match # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } ## ----------- ## ## Main. ## ## ----------- ## $opt_help || { # Sanity checks first: func_check_version_match if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then func_fatal_configuration "not configured to build any kind of library" fi test -z "$mode" && func_fatal_error "error: you must specify a MODE." # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$execute_dlfiles" && test "$mode" != execute; then func_error "unrecognized option \`-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$progname --help --mode=$mode' for more information." } # func_lalib_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null \ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_unsafe_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if `file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case "$lalib_p_line" in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test "$lalib_p" = yes } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { func_lalib_p "$1" } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_ltwrapper_scriptname_result="" if func_ltwrapper_executable_p "$1"; then func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" fi } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $opt_debug save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$save_ifs eval cmd=\"$cmd\" func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # `FILE.' does not work on cygwin managed mounts. func_source () { $opt_debug case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $opt_debug if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_quote_for_eval "$arg" CC_quoted="$CC_quoted $func_quote_for_eval_result" done case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_quote_for_eval "$arg" CC_quoted="$CC_quoted $func_quote_for_eval_result" done case "$@ " in " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with \`--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=${1} if test "$build_libtool_libs" = yes; then write_lobj=\'${2}\' else write_lobj=none fi if test "$build_old_libs" = yes; then write_oldobj=\'${3}\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T <?"'"'"' &()|`$[]' \ && func_warning "libobj name \`$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname="$func_basename_result" xdir="$func_dirname_result" lobj=${xdir}$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$ECHO "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi removelist="$removelist $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist removelist="$removelist $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 if test -n "$fix_srcfile_path"; then eval srcfile=\"$fix_srcfile_path\" fi func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test "$pic_mode" != no; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir command="$command -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test "$suppress_opt" = yes; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then if test "$pic_mode" != yes; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test "$compiler_c_o" = yes; then command="$command -o $obj" fi # Suppress compiler output if we already did a PIC compilation. command="$command$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test "$need_locks" != no; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test "$mode" = compile && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to building PIC objects only -prefer-non-pic try to building non-PIC objects only -shared do not build a \`.o' file suitable for static linking -static only build a \`.o' file suitable for static linking COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE Use a list of object files found in FILE to specify objects -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode \`$mode'" ;; esac $ECHO $ECHO "Try \`$progname --help' for more information about other modes." exit $? } # Now that we've collected a possible --mode arg, show help if necessary $opt_help && func_mode_help # func_mode_execute arg... func_mode_execute () { $opt_debug # The first argument is the command name. cmd="$nonopt" test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $execute_dlfiles; do test -f "$file" \ || func_fatal_help "\`$file' is not a file" dir= case $file in *.la) # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "\`$file' was not linked with \`-export-dynamic'" continue fi func_dirname "$file" "" "." dir="$func_dirname_result" if test -f "$dir/$objdir/$dlname"; then dir="$dir/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir="$func_dirname_result" ;; *) func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -*) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file="$progdir/$program" elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). func_quote_for_eval "$file" args="$args $func_quote_for_eval_result" done if test "X$opt_dry_run" = Xfalse; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" $ECHO "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS fi } test "$mode" = execute && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $opt_debug libdirs="$nonopt" admincmds= if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for dir do libdirs="$libdirs $dir" done for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || admincmds="$admincmds $cmds" fi done fi # Exit here if they wanted silent mode. $opt_silent && exit $EXIT_SUCCESS $ECHO "X----------------------------------------------------------------------" | $Xsed $ECHO "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done $ECHO $ECHO "If you ever happen to want to link against installed libraries" $ECHO "in a given directory, LIBDIR, you must either use libtool, and" $ECHO "specify the full pathname of the library, or use the \`-LLIBDIR'" $ECHO "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then $ECHO " - add LIBDIR to the \`$shlibpath_var' environment variable" $ECHO " during execution" fi if test -n "$runpath_var"; then $ECHO " - add LIBDIR to the \`$runpath_var' environment variable" $ECHO " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then $ECHO " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi $ECHO $ECHO "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) $ECHO "more information, such as the ld(1), crle(1) and ld.so(8) manual" $ECHO "pages." ;; *) $ECHO "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac $ECHO "X----------------------------------------------------------------------" | $Xsed exit $EXIT_SUCCESS } test "$mode" = finish && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $opt_debug # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. $ECHO "X$nonopt" | $GREP shtool >/dev/null; then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" install_prog="$install_prog$func_quote_for_eval_result" # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= for arg do if test -n "$dest"; then files="$files $dest" dest=$arg continue fi case $arg in -d) isdir=yes ;; -f) case " $install_prog " in *[\\\ /]cp\ *) ;; *) prev=$arg ;; esac ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" install_prog="$install_prog $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the \`$prev' option requires an argument" if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else func_dirname_and_basename "$dest" "" "." destdir="$func_dirname_result" destname="$func_basename_result" # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "\`$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "\`$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. staticlibs="$staticlibs $file" ;; *.la) # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) current_libdirs="$current_libdirs $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) future_libdirs="$future_libdirs $libdir" ;; esac fi func_dirname "$file" "/" "" dir="$func_dirname_result" dir="$dir$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "X$destdir" | $Xsed -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%%"` fi func_warning "relinking \`$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname="$1" shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. func_show_eval "$install_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme="$stripme" case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme="" ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try `ln -sf' first, because the `ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib="$destdir/$realname" func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name="$func_basename_result" instname="$dir/$name"i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest="$destfile" destfile= ;; *) func_fatal_help "cannot copy a libtool object to \`$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext="" case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=".exe" fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script \`$wrapper'" finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile="$libdir/"`$ECHO "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then func_warning "\`$lib' has not been installed in \`$libdir'" finalize=no fi done relink_command= func_source "$wrapper" outputname= if test "$fast_install" = no && test -n "$relink_command"; then $opt_dry_run || { if test "$finalize" = yes; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file="$func_basename_result" outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$ECHO "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` $opt_silent || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink \`$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file="$outputname" else func_warning "cannot relink \`$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name="$func_basename_result" # Set up the ranlib parameters. oldlib="$destdir/$name" func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run \`$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test "$mode" = install && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $opt_debug my_outputname="$1" my_originator="$2" my_pic_p="${3-no}" my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms="${my_outputname}S.c" else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${my_outputname}.nm" func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then func_verbose "generating symbol list for \`$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` for progfile in $progfiles; do func_verbose "extracting global C symbols from \`$progfile'" $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$outputname.exp" $opt_dry_run || { $RM $export_symbols eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from \`$dlprefile'" func_basename "$dlprefile" name="$func_basename_result" $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'" } done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else $ECHO '/* NONE */' >> "$output_objdir/$my_dlsyms" fi $ECHO >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; " case $host in *cygwin* | *mingw* | *cegcc* ) $ECHO >> "$output_objdir/$my_dlsyms" "\ /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */" lt_dlsym_const= ;; *osf5*) echo >> "$output_objdir/$my_dlsyms" "\ /* This system does not cope well with relocations in const data */" lt_dlsym_const= ;; *) lt_dlsym_const=const ;; esac $ECHO >> "$output_objdir/$my_dlsyms" "\ extern $lt_dlsym_const lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[]; $lt_dlsym_const lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = {\ { \"$my_originator\", (void *) 0 }," case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac $ECHO >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) if test "X$my_pic_p" != Xno; then pic_flag_for_symtable=" $pic_flag" fi ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) symtab_cflags="$symtab_cflags $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' # Transform the symbol file into the correct name. symfileobj="$output_objdir/${my_outputname}S.$objext" case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for \`$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` fi } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. func_win32_libid () { $opt_debug win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then win32_nmres=`eval $NM -f posix -A $1 | $SED -n -e ' 1,100{ / I /{ s,.*,import, p q } }'` case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_extract_an_archive dir oldlib func_extract_an_archive () { $opt_debug f_ex_an_ar_dir="$1"; shift f_ex_an_ar_oldlib="$1" func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" 'exit $?' if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $opt_debug my_gentop="$1"; shift my_oldlibs=${1+"$@"} my_oldobjs="" my_xlib="" my_xabs="" my_xdir="" for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib="$func_basename_result" my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir="$my_gentop/$my_xlib_u" func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` darwin_base_archive=`basename "$darwin_archive"` darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches ; do func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" func_extract_an_archive "`pwd`" "${darwin_base_archive}" cd "$darwin_curdir" $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` done func_extract_archives_result="$my_oldobjs" } # func_emit_wrapper_part1 [arg=no] # # Emit the first part of a libtool wrapper script on stdout. # For more information, see the description associated with # func_emit_wrapper(), below. func_emit_wrapper_part1 () { func_emit_wrapper_part1_arg1=no if test -n "$1" ; then func_emit_wrapper_part1_arg1=$1 fi $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed='${SED} -e 1s/^X//' sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then ECHO=\"$qecho\" file=\"\$0\" # Make sure echo works. if test \"X\$1\" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test \"X\`{ \$ECHO '\t'; } 2>/dev/null\`\" = 'X\t'; then # Yippee, \$ECHO works! : else # Restart under the correct shell, and then maybe \$ECHO will work. exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} fi fi\ " $ECHO "\ # Find the directory that this script lives in. thisdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"X\$file\" | \$Xsed -e 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` done " } # end: func_emit_wrapper_part1 # func_emit_wrapper_part2 [arg=no] # # Emit the second part of a libtool wrapper script on stdout. # For more information, see the description associated with # func_emit_wrapper(), below. func_emit_wrapper_part2 () { func_emit_wrapper_part2_arg1=no if test -n "$1" ; then func_emit_wrapper_part2_arg1=$1 fi $ECHO "\ # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_part2_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"X\$thisdir\" | \$Xsed -e 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` export $shlibpath_var " fi # fixup the dll searchpath if we need to. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 fi else # The program doesn't exist. \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 $ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # end: func_emit_wrapper_part2 # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory in which it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=no if test -n "$1" ; then func_emit_wrapper_arg1=$1 fi # split this up so that func_emit_cwrapperexe_src # can call each part independently. func_emit_wrapper_part1 "${func_emit_wrapper_arg1}" func_emit_wrapper_part2 "${func_emit_wrapper_arg1}" } # func_to_host_path arg # # Convert paths to host format when used with build tools. # Intended for use with "native" mingw (where libtool itself # is running under the msys shell), or in the following cross- # build environments: # $build $host # mingw (msys) mingw [e.g. native] # cygwin mingw # *nix + wine mingw # where wine is equipped with the `winepath' executable. # In the native mingw case, the (msys) shell automatically # converts paths for any non-msys applications it launches, # but that facility isn't available from inside the cwrapper. # Similar accommodations are necessary for $host mingw and # $build cygwin. Calling this function does no harm for other # $host/$build combinations not listed above. # # ARG is the path (on $build) that should be converted to # the proper representation for $host. The result is stored # in $func_to_host_path_result. func_to_host_path () { func_to_host_path_result="$1" if test -n "$1" ; then case $host in *mingw* ) lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' case $build in *mingw* ) # actually, msys # awkward: cmd appends spaces to result lt_sed_strip_trailing_spaces="s/[ ]*\$//" func_to_host_path_tmp1=`( cmd //c echo "$1" |\ $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ $SED -e "$lt_sed_naive_backslashify"` ;; *cygwin* ) func_to_host_path_tmp1=`cygpath -w "$1"` func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ $SED -e "$lt_sed_naive_backslashify"` ;; * ) # Unfortunately, winepath does not exit with a non-zero # error code, so we are forced to check the contents of # stdout. On the other hand, if the command is not # found, the shell will set an exit code of 127 and print # *an error message* to stdout. So we must check for both # error code of zero AND non-empty stdout, which explains # the odd construction: func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null` if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ $SED -e "$lt_sed_naive_backslashify"` else # Allow warning below. func_to_host_path_result="" fi ;; esac if test -z "$func_to_host_path_result" ; then func_error "Could not determine host path corresponding to" func_error " '$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_path_result="$1" fi ;; esac fi } # end: func_to_host_path # func_to_host_pathlist arg # # Convert pathlists to host format when used with build tools. # See func_to_host_path(), above. This function supports the # following $build/$host combinations (but does no harm for # combinations not listed here): # $build $host # mingw (msys) mingw [e.g. native] # cygwin mingw # *nix + wine mingw # # Path separators are also converted from $build format to # $host format. If ARG begins or ends with a path separator # character, it is preserved (but converted to $host format) # on output. # # ARG is a pathlist (on $build) that should be converted to # the proper representation on $host. The result is stored # in $func_to_host_pathlist_result. func_to_host_pathlist () { func_to_host_pathlist_result="$1" if test -n "$1" ; then case $host in *mingw* ) lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_to_host_pathlist_tmp2="$1" # Once set for this call, this variable should not be # reassigned. It is used in tha fallback case. func_to_host_pathlist_tmp1=`echo "$func_to_host_pathlist_tmp2" |\ $SED -e 's|^:*||' -e 's|:*$||'` case $build in *mingw* ) # Actually, msys. # Awkward: cmd appends spaces to result. lt_sed_strip_trailing_spaces="s/[ ]*\$//" func_to_host_pathlist_tmp2=`( cmd //c echo "$func_to_host_pathlist_tmp1" |\ $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ $SED -e "$lt_sed_naive_backslashify"` ;; *cygwin* ) func_to_host_pathlist_tmp2=`cygpath -w -p "$func_to_host_pathlist_tmp1"` func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ $SED -e "$lt_sed_naive_backslashify"` ;; * ) # unfortunately, winepath doesn't convert pathlists func_to_host_pathlist_result="" func_to_host_pathlist_oldIFS=$IFS IFS=: for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do IFS=$func_to_host_pathlist_oldIFS if test -n "$func_to_host_pathlist_f" ; then func_to_host_path "$func_to_host_pathlist_f" if test -n "$func_to_host_path_result" ; then if test -z "$func_to_host_pathlist_result" ; then func_to_host_pathlist_result="$func_to_host_path_result" else func_to_host_pathlist_result="$func_to_host_pathlist_result;$func_to_host_path_result" fi fi fi IFS=: done IFS=$func_to_host_pathlist_oldIFS ;; esac if test -z "$func_to_host_pathlist_result" ; then func_error "Could not determine the host path(s) corresponding to" func_error " '$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This may break if $1 contains DOS-style drive # specifications. The fix is not to complicate the expression # below, but for the user to provide a working wine installation # with winepath so that path translation in the cross-to-mingw # case works properly. lt_replace_pathsep_nix_to_dos="s|:|;|g" func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\ $SED -e "$lt_replace_pathsep_nix_to_dos"` fi # Now, add the leading and trailing path separators back case "$1" in :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result" ;; esac case "$1" in *: ) func_to_host_pathlist_result="$func_to_host_pathlist_result;" ;; esac ;; esac fi } # end: func_to_host_pathlist # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include # define setmode _setmode #else # include # include # ifdef __CYGWIN__ # include # define HAVE_SETENV # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif # endif #endif #include #include #include #include #include #include #include #include #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif #ifdef _MSC_VER # define S_IXUSR _S_IEXEC # define stat _stat # ifndef _INTPTR_T_DEFINED # define intptr_t int # endif #endif #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifdef __CYGWIN__ # define FOPEN_WB "wb" #endif #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free ((void *) stale); stale = 0; } \ } while (0) #undef LTWRAPPER_DEBUGPRINTF #if defined DEBUGWRAPPER # define LTWRAPPER_DEBUGPRINTF(args) ltwrapper_debugprintf args static void ltwrapper_debugprintf (const char *fmt, ...) { va_list args; va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } #else # define LTWRAPPER_DEBUGPRINTF(args) #endif const char *program_name = NULL; void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_fatal (const char *message, ...); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_opt_process_env_set (const char *arg); void lt_opt_process_env_prepend (const char *arg); void lt_opt_process_env_append (const char *arg); int lt_split_name_value (const char *arg, char** name, char** value); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); static const char *script_text_part1 = EOF func_emit_wrapper_part1 yes | $SED -e 's/\([\\"]\)/\\\1/g' \ -e 's/^/ "/' -e 's/$/\\n"/' echo ";" cat <"))); for (i = 0; i < newargc; i++) { LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d] : %s\n", i, (newargz[i] ? newargz[i] : ""))); } EOF case $host_os in mingw*) cat <<"EOF" /* execv doesn't actually work on mingw as expected on unix */ rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz); if (rval == -1) { /* failed to start process */ LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno)); return 127; } return rval; EOF ;; *) cat <<"EOF" execv (lt_argv_zero, newargz); return rval; /* =127, but avoids unused variable warning */ EOF ;; esac cat <<"EOF" } void * xmalloc (size_t num) { void *p = (void *) malloc (num); if (!p) lt_fatal ("Memory exhausted"); return p; } char * xstrdup (const char *string) { return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL; } const char * base_name (const char *name) { const char *base; #if defined (HAVE_DOS_BASED_FILE_SYSTEM) /* Skip over the disk name in MSDOS pathnames. */ if (isalpha ((unsigned char) name[0]) && name[1] == ':') name += 2; #endif for (base = name; *name; name++) if (IS_DIR_SEPARATOR (*name)) base = name + 1; return base; } int check_executable (const char *path) { struct stat st; LTWRAPPER_DEBUGPRINTF (("(check_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!")); if ((!path) || (!*path)) return 0; if ((stat (path, &st) >= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; LTWRAPPER_DEBUGPRINTF (("(make_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!")); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; int tmp_len; char *concat_name; LTWRAPPER_DEBUGPRINTF (("(find_executable) : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!")); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined (HAVE_DOS_BASED_FILE_SYSTEM) } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = q - p; p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal ("getcwd failed"); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal ("getcwd failed"); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { LTWRAPPER_DEBUGPRINTF (("checking path component for symlinks: %s\n", tmp_pathspec)); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { char *errstr = strerror (errno); lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal ("Could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (strcmp (str, pat) == 0) *str = '\0'; } return str; } static void lt_error_core (int exit_status, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s: %s: ", program_name, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, "FATAL", message, ap); va_end (ap); } void lt_setenv (const char *name, const char *value) { LTWRAPPER_DEBUGPRINTF (("(lt_setenv) setting '%s' to '%s'\n", (name ? name : ""), (value ? value : ""))); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else int len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { int orig_value_len = strlen (orig_value); int add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } int lt_split_name_value (const char *arg, char** name, char** value) { const char *p; int len; if (!arg || !*arg) return 1; p = strchr (arg, (int)'='); if (!p) return 1; *value = xstrdup (++p); len = strlen (arg) - strlen (*value); *name = XMALLOC (char, len); strncpy (*name, arg, len-1); (*name)[len - 1] = '\0'; return 0; } void lt_opt_process_env_set (const char *arg) { char *name = NULL; char *value = NULL; if (lt_split_name_value (arg, &name, &value) != 0) { XFREE (name); XFREE (value); lt_fatal ("bad argument for %s: '%s'", env_set_opt, arg); } lt_setenv (name, value); XFREE (name); XFREE (value); } void lt_opt_process_env_prepend (const char *arg) { char *name = NULL; char *value = NULL; char *new_value = NULL; if (lt_split_name_value (arg, &name, &value) != 0) { XFREE (name); XFREE (value); lt_fatal ("bad argument for %s: '%s'", env_prepend_opt, arg); } new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); XFREE (name); XFREE (value); } void lt_opt_process_env_append (const char *arg) { char *name = NULL; char *value = NULL; char *new_value = NULL; if (lt_split_name_value (arg, &name, &value) != 0) { XFREE (name); XFREE (value); lt_fatal ("bad argument for %s: '%s'", env_append_opt, arg); } new_value = lt_extend_str (getenv (name), value, 1); lt_setenv (name, new_value); XFREE (new_value); XFREE (name); XFREE (value); } void lt_update_exe_path (const char *name, const char *value) { LTWRAPPER_DEBUGPRINTF (("(lt_update_exe_path) modifying '%s' by prepending '%s'\n", (name ? name : ""), (value ? value : ""))); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ int len = strlen (new_value); while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[len-1] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { LTWRAPPER_DEBUGPRINTF (("(lt_update_lib_path) modifying '%s' by prepending '%s'\n", (name ? name : ""), (value ? value : ""))); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF } # end: func_emit_cwrapperexe_src # func_mode_link arg... func_mode_link () { $opt_debug case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll which has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=no prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module="${wl}-single_module" func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg="$1" shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then dlfiles="$dlfiles $arg" else dlprefiles="$dlprefiles $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" test -f "$arg" \ || func_fatal_error "symbol file \`$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) deplibs="$deplibs $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # moreargs="$moreargs $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then dlfiles="$dlfiles $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. dlprefiles="$dlprefiles $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file \`$arg' does not exist" fi arg=$save_arg prev= continue ;; precious_regex) precious_files_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) rpath="$rpath $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) xrpath="$xrpath $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds="$arg" prev= continue ;; weak) weak_libs="$weak_libs $arg" prev= continue ;; xcclinker) linker_flags="$linker_flags $qarg" compiler_flags="$compiler_flags $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) compiler_flags="$compiler_flags $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) linker_flags="$linker_flags $qarg" compiler_flags="$compiler_flags $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "\`-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname '-L' '' "$arg" dir=$func_stripname_result if test -z "$dir"; then if test "$#" -gt 0; then func_fatal_error "require no space between \`-L' and \`$1'" else func_fatal_error "need path for \`-L' option" fi fi # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of \`$dir'" dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "*) ;; *) deplibs="$deplibs -L$dir" lib_search_path="$lib_search_path $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "X$dir" | $Xsed -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) dllsearchpath="$dllsearchpath:$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) dllsearchpath="$dllsearchpath:$testbindir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework deplibs="$deplibs System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test "X$arg" = "X-lc" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test "X$arg" = "X-lc" && continue ;; esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi deplibs="$deplibs $arg" continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot) compiler_flags="$compiler_flags $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) compiler_flags="$compiler_flags $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;; esac continue ;; -multi_module) single_module="${wl}-multi_module" continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "\`-no-install' is ignored for $host" func_warning "assuming \`-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) xrpath="$xrpath $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" arg="$arg $wl$func_quote_for_eval_result" compiler_flags="$compiler_flags $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" arg="$arg $wl$func_quote_for_eval_result" compiler_flags="$compiler_flags $wl$func_quote_for_eval_result" linker_flags="$linker_flags $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; # -64, -mips[0-9] enable 64-bit mode on the SGI compiler # -r[0-9][0-9]* specifies the processor on the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler # +DA*, +DD* enable 64-bit mode on the HP compiler # -q* pass through compiler args for the IBM compiler # -m*, -t[45]*, -txscale* pass through architecture-specific # compiler args for GCC # -F/path gives path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC # @file GCC response files -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" func_append compile_command " $arg" func_append finalize_command " $arg" compiler_flags="$compiler_flags $arg" continue ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; *.$objext) # A standard object. objs="$objs $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then dlfiles="$dlfiles $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. dlprefiles="$dlprefiles $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. deplibs="$deplibs $arg" old_deplibs="$old_deplibs $arg" continue ;; *.la) # A libtool-controlled library. if test "$prev" = dlfiles; then # This library was specified with -dlopen. dlfiles="$dlfiles $arg" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. dlprefiles="$dlprefiles $arg" prev= else deplibs="$deplibs $arg" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the \`$prevarg' option requires an argument" if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname="$func_basename_result" libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" func_dirname "$output" "/" "" output_objdir="$func_dirname_result$objdir" # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_duplicate_deps ; then case "$libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi libs="$libs $deplib" done if test "$linkmode" = lib; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; esac pre_post_deps="$pre_post_deps $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test "$linkmode,$pass" = "lib,link"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs="$tmp_deplibs" fi if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS%" test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" ;; esac fi if test "$linkmode,$pass" = "lib,dlpreopen"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= case $lib in *.la) func_source "$lib" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do deplib_base=`$ECHO "X$deplib" | $Xsed -e "$basename"` case " $weak_libs " in *" $deplib_base "*) ;; *) deplibs="$deplibs $deplib" ;; esac done done libs="$dlprefiles" fi if test "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else compiler_flags="$compiler_flags $deplib" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; esac fi fi continue ;; -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then func_warning "\`-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test "$linkmode" = lib; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" if test -f "$lib"; then if test "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll="$l" done if test "X$ll" = "X$old_library" ; then # only static version available found=no func_dirname "$lib" "" "." ladir="$func_dirname_result" lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l *.ltframework) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" newlib_search_path="$newlib_search_path $func_stripname_result" ;; prog) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" newlib_search_path="$newlib_search_path $func_stripname_result" ;; *) func_warning "\`-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test "$pass" = link; then func_stripname '-R' '' "$deplib" dir=$func_stripname_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) xrpath="$xrpath $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) lib="$deplib" ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=no case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"X$deplib\"" 2>/dev/null | $Xsed -e 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=yes fi ;; pass_all) valid_a_lib=yes ;; esac if test "$valid_a_lib" != yes; then $ECHO $ECHO "*** Warning: Trying to link with static lib archive $deplib." $ECHO "*** I have the capability to make that library automatically link in when" $ECHO "*** you link to this library. But I can only do this if you have a" $ECHO "*** shared version of the library, which you do not appear to have" $ECHO "*** because the file extensions .$libext of this argument makes me believe" $ECHO "*** that it is just a static archive that I should not use here." else $ECHO $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi ;; esac continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. newdlprefiles="$newdlprefiles $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else newdlfiles="$newdlfiles $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" fi # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "\`$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir="$func_dirname_result" dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "X$inherited_linker_flags" | $Xsed -e 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO "X $dependency_libs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && dlfiles="$dlfiles $dlopen" test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" fi if test "$pass" = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # It is a libtool convenience library, so add in its objects. convenience="$convenience $ladir/$objdir/$old_library" old_convenience="$old_convenience $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_duplicate_deps ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done elif test "$linkmode" != prog && test "$linkmode" != lib; then func_fatal_error "\`$lib' is not a convenience library" fi continue fi # $pass = conv # Get the name of the library we link against. linklib= for l in $old_library $library_names; do linklib="$l" done if test -z "$linklib"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # This library was specified with -dlopen. if test "$pass" = dlopen; then if test -z "$libdir"; then func_fatal_error "cannot -dlopen a convenience library: \`$lib'" fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. dlprefiles="$dlprefiles $lib $dependency_libs" else newdlfiles="$newdlfiles $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of \`$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir="$ladir" fi ;; esac func_basename "$lib" laname="$func_basename_result" # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library \`$lib' was moved." dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$libdir" absdir="$libdir" fi test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir="$ladir" absdir="$abs_ladir" # Remove this search path later notinst_path="$notinst_path $abs_ladir" else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later notinst_path="$notinst_path $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test "$pass" = dlpreopen; then if test -z "$libdir" && test "$linkmode" = prog; then func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" fi # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then newdlprefiles="$newdlprefiles $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then newdlprefiles="$newdlprefiles $dir/$dlname" else newdlprefiles="$newdlprefiles $dir/$linklib" fi fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test "$linkmode" = prog && test "$pass" != link; then newlib_search_path="$newlib_search_path $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" newlib_search_path="$newlib_search_path $func_stripname_result" ;; esac # Need to link against all dependency_libs? if test "$linkalldeplibs" = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_duplicate_deps ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done # for deplib continue fi # $linkmode = prog... if test "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { { test "$prefer_static_libs" = no || test "$prefer_static_libs,$installed" = "built,yes"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then # Make sure the rpath contains only unique directories. case "$temp_rpath:" in *"$absdir:"*) ;; *) temp_rpath="$temp_rpath$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) compile_rpath="$compile_rpath $absdir" esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" esac ;; esac fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test "$use_static_libs" = built && test "$installed" = yes; then use_static_libs=no fi if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded notinst_deplibs="$notinst_deplibs $lib" need_relink=no ;; *) if test "$installed" = no; then notinst_deplibs="$notinst_deplibs $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule="" for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule="$dlpremoduletest" break fi done if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then $ECHO if test "$linkmode" = prog; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test "$linkmode" = lib && test "$hardcode_into_libs" = yes; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) compile_rpath="$compile_rpath $absdir" esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname="$1" shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc*) func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" func_basename "$soroot" soname="$func_basename_result" func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from \`$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for \`$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test "$linkmode" = prog || test "$mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" case $host in *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; *-*-sysv4*uw2*) add_dir="-L$dir" ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir="-L$dir" ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we can not # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null ; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library" ; then $ECHO $ECHO "*** And there doesn't seem to be a static archive available" $ECHO "*** The link will probably fail, sorry" else add="$dir/$old_library" fi elif test -n "$old_library"; then add="$dir/$old_library" fi fi esac elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$dir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) add_dir="$add_dir -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && test "$hardcode_minus_L" != yes && test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then add="$inst_prefix_dir$libdir/$linklib" else add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) add_dir="$add_dir -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" fi if test "$linkmode" = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test "$linkmode" = prog; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. $ECHO $ECHO "*** Warning: This system can not link to static lib archive $lib." $ECHO "*** I have the capability to make that library automatically link in when" $ECHO "*** you link to this library. But I can only do this if you have a" $ECHO "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then $ECHO "*** But as you try to build a module library, libtool will still create " $ECHO "*** a static module, that should work as long as the dlopening application" $ECHO "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then $ECHO $ECHO "*** However, this would only work if libtool was able to extract symbol" $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" $ECHO "*** not find such a program. So, this module is probably useless." $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) xrpath="$xrpath $temp_xrpath";; esac;; *) temp_deplibs="$temp_deplibs $libdir";; esac done dependency_libs="$temp_deplibs" fi newlib_search_path="$newlib_search_path $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" if $opt_duplicate_deps ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path="$deplib" ;; *.la) func_dirname "$deplib" "" "." dir="$func_dirname_result" # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of \`$dir'" absdir="$dir" fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl" ; then depdepl="$absdir/$objdir/$depdepl" darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}" path= fi fi ;; *) path="-L$absdir/$objdir" ;; esac else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "\`$deplib' seems to be moved" path="-L$absdir" fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test "$pass" = link; then if test "$linkmode" = "prog"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs="$newdependency_libs" if test "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) lib_search_path="$lib_search_path $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) tmp_libs="$tmp_libs $deplib" ;; esac ;; *) tmp_libs="$tmp_libs $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs ; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i="" ;; esac if test -n "$i" ; then tmp_libs="$tmp_libs $i" fi done dependency_libs=$tmp_libs done # for pass if test "$linkmode" = prog; then dlfiles="$newdlfiles" fi if test "$linkmode" = prog || test "$linkmode" = lib; then dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "\`-R' is ignored for archives" test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "\`-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "\`-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" objs="$objs$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test "$module" = no && \ func_fatal_help "libtool library \`$output' must begin with \`lib'" if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" else $ECHO $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" libobjs="$libobjs $objs" fi fi test "$dlself" != no && \ func_warning "\`-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test "$#" -gt 1 && \ func_warning "ignoring multiple \`-rpath's for a libtool library" install_libdir="$1" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. # Some compilers have problems with a `.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "\`-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 shift IFS="$save_ifs" test -n "$7" && \ func_fatal_help "too many parameters to \`-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major="$1" number_minor="$2" number_revision="$3" # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # which has an extra 1 added just for fun # case $version_type in darwin|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|sunos) current="$number_major" revision="$number_minor" age="0" ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_minor" lt_irix_increment=no ;; *) func_fatal_configuration "$modename: unknown library version type \`$version_type'" ;; esac ;; no) current="$1" revision="$2" age="$3" ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT \`$current' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION \`$revision' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE \`$age' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE \`$age' is greater than the current interface number \`$current'" func_fatal_error "\`$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current" ;; irix | nonstopux) if test "X$lt_irix_increment" = "Xno"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test "$loop" -ne 0; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test "$loop" -ne 0; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring:${iface}.0" done # Make executables depend on our current version. verstring="$verstring:${current}.0" ;; qnx) major=".$current" versuffix=".$current" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; *) func_fatal_configuration "unknown library version type \`$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then func_warning "undefined symbols not allowed in $host shared libraries" build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi func_generate_dlsyms "$libname" "$libname" "yes" libobjs="$libobjs $symfileobj" test "X$libobjs" = "X " && libobjs= if test "$mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) if test "X$precious_files_regex" != "X"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi removelist="$removelist $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then oldlibs="$oldlibs $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "X$lib_search_path " | $Xsed -e "s% $path % %g"` # deplibs=`$ECHO "X$deplibs " | $Xsed -e "s% -L$path % %g"` # dependency_libs=`$ECHO "X$dependency_libs " | $Xsed -e "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do temp_xrpath="$temp_xrpath -R$libdir" case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) dlfiles="$dlfiles $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) dlprefiles="$dlprefiles $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework deplibs="$deplibs System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then deplibs="$deplibs -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$ECHO "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes $ECHO $ECHO "*** Warning: linker path does not have real file for library $a_deplib." $ECHO "*** I have the capability to make that library automatically link in when" $ECHO "*** you link to this library. But I can only do this if you have a" $ECHO "*** shared version of the library, which you do not appear to have" $ECHO "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) newdeplibs="$newdeplibs $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test if eval "\$ECHO \"X$potent_lib\"" 2>/dev/null | $Xsed -e 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes $ECHO $ECHO "*** Warning: linker path does not have real file for library $a_deplib." $ECHO "*** I have the capability to make that library automatically link in when" $ECHO "*** you link to this library. But I can only do this if you have a" $ECHO "*** shared version of the library, which you do not appear to have" $ECHO "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" tmp_deplibs=`$ECHO "X $deplibs" | $Xsed \ -e 's/ -lc$//' -e 's/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO "X $tmp_deplibs" | $Xsed -e "s,$i,,"` done fi if $ECHO "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' | $GREP . >/dev/null; then $ECHO if test "X$deplibs_check_method" = "Xnone"; then $ECHO "*** Warning: inter-library dependencies are not supported in this platform." else $ECHO "*** Warning: inter-library dependencies are not known to be supported." fi $ECHO "*** All declared inter-library dependencies are being dropped." droppeddeps=yes fi ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's/ -lc / System.ltframework /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then $ECHO $ECHO "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" $ECHO "*** a static module, that should work as long as the dlopening" $ECHO "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then $ECHO $ECHO "*** However, this would only work if libtool was able to extract symbol" $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" $ECHO "*** not find such a program. So, this module is probably useless." $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else $ECHO "*** The inter-library dependencies that have been dropped here will be" $ECHO "*** automatically added whenever a program is linked with this library" $ECHO "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then $ECHO $ECHO "*** Since this library must not contain undefined symbols," $ECHO "*** because either the platform does not support them or" $ECHO "*** it was explicitly requested with -no-undefined," $ECHO "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO "X $deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) new_libs="$new_libs -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$new_libs $deplib" ;; esac ;; *) new_libs="$new_libs $deplib" ;; esac done deplibs="$new_libs" # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" dep_rpath="$dep_rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" if test -n "$hardcode_libdir_flag_spec_ld"; then eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" else eval dep_rpath=\"$hardcode_libdir_flag_spec\" fi fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname="$1" shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi if test -z "$dlname"; then dlname=$soname fi lib="$output_objdir/$realname" linknames= for link do linknames="$linknames $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols="$output_objdir/$libname.uexp" delfiles="$delfiles $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile if test "x`$SED 1q $export_symbols`" != xEXPORTS; then # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols="$export_symbols" export_symbols= always_export_symbols=yes fi fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" func_len " $cmd" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then func_show_eval "$cmd" 'exit $?' skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS="$save_ifs" if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' fi if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) tmp_deplibs="$tmp_deplibs $test_deplib" ;; esac done deplibs="$tmp_deplibs" if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test "$compiler_needs_object" = yes && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $convenience libobjs="$libobjs $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" linker_flags="$linker_flags $flag" fi # Make a backup of the uninstalled library when relinking if test "$mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test "X$skipped_export" != "X:" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output output_la=`$ECHO "X$output" | $Xsed -e "$basename"` # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then output=${output_objdir}/${output_la}.lnkscript func_verbose "creating GNU ld script: $output" $ECHO 'INPUT (' > $output for obj in $save_libobjs do $ECHO "$obj" >> $output done $ECHO ')' >> $output delfiles="$delfiles $output" elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then output=${output_objdir}/${output_la}.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test "$compiler_needs_object" = yes; then firstobj="$1 " shift fi for obj do $ECHO "$obj" >> $output done delfiles="$delfiles $output" output=$firstobj\"$file_list_spec$output\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-${k}.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test "X$objlist" = X || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. eval concat_cmds=\"$reload_cmds $objlist $last_robj\" else # All subsequent reloadable object files will link in # the last one created. eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-${k}.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-${k}.$objext objlist=$obj func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" if test -n "$last_robj"; then eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" fi delfiles="$delfiles $output" else output= fi if ${skipped_export-false}; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi fi test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs="$IFS"; IFS='~' for cmd in $concat_cmds; do IFS="$save_ifs" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi if ${skipped_export-false}; then if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi fi libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $dlprefiles libobjs="$libobjs $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "\`-R' is ignored for objects" test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for objects" test -n "$release" && \ func_warning "\`-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object \`$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec and hope we can get by with # turning comma into space.. wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" reload_conv_objs=$reload_objs\ `$ECHO "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'` else gentop="$output_objdir/${obj}x" generated="$generated $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # Create the old-style object. reload_objs="$objs$old_deplibs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for programs" test -n "$release" && \ func_warning "\`-release' is ignored for programs" test "$preload" = yes \ && test "$dlopen_support" = unknown \ && test "$dlopen_self" = unknown \ && test "$dlopen_self_static" = unknown && \ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test "$tagname" = CXX ; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) compile_command="$compile_command ${wl}-bind_at_load" finalize_command="$finalize_command ${wl}-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) new_libs="$new_libs -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$new_libs $deplib" ;; esac ;; *) new_libs="$new_libs $deplib" ;; esac done compile_deplibs="$new_libs" compile_command="$compile_command $compile_deplibs" finalize_command="$finalize_command $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) dllsearchpath="$dllsearchpath:$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) dllsearchpath="$dllsearchpath:$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$ECHO "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` finalize_command=`$ECHO "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" "no" # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=yes case $host in *cygwin* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; *cegcc) # Disable wrappers for cegcc, we are cross compiling anyway. wrappers_required=no ;; *) if test "$need_relink" = no || test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; esac if test "$wrappers_required" = no; then # Replace the output file specification. compile_command=`$ECHO "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' # Delete the generated files. if test -f "$output_objdir/${outputname}S.${objext}"; then func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' fi exit $exit_status fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do rpath="$rpath$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' exit $EXIT_SUCCESS fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" func_warning "this platform does not like uninstalled shared libraries" func_warning "\`$output' will be relinked during installation" else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$ECHO "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` fi # Quote $ECHO for shipping. if test "X$ECHO" = "X$SHELL $progpath --fallback-echo"; then case $progpath in [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; esac qecho=`$ECHO "X$qecho" | $Xsed -e "$sed_quote_subst"` else qecho=`$ECHO "X$ECHO" | $Xsed -e "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource="$output_path/$objdir/lt-$output_name.c" cwrapper="$output_path/$output_name.exe" $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host" ; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save $symfileobj" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" if test "$preload" = yes && test -f "$symfileobj"; then oldobjs="$oldobjs $symfileobj" fi fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $addlibs oldobjs="$oldobjs $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $dlprefiles oldobjs="$oldobjs $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else $ECHO "copying selected object files to avoid basename conflicts..." gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase="$func_basename_result" case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" oldobjs="$oldobjs $gentop/$newobj" ;; *) oldobjs="$oldobjs $obj" ;; esac done fi eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test "X$oldobjs" = "X" ; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` if test "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" newdependency_libs="$newdependency_libs $libdir/$name" ;; *) newdependency_libs="$newdependency_libs $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" newdlfiles="$newdlfiles $libdir/$name" ;; *) newdlfiles="$newdlfiles $lib" ;; esac done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" newdlprefiles="$newdlprefiles $libdir/$name" ;; esac done dlprefiles="$newdlprefiles" else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac newdlfiles="$newdlfiles $abs" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac newdlprefiles="$newdlprefiles $abs" done dlprefiles="$newdlprefiles" fi $RM $output # place dlname in correct position for cygwin tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that can not go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test "$need_relink" = yes; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } { test "$mode" = link || test "$mode" = relink; } && func_mode_link ${1+"$@"} # func_mode_uninstall arg... func_mode_uninstall () { $opt_debug RM="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) RM="$RM $arg"; rmforce=yes ;; -*) RM="$RM $arg" ;; *) files="$files $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= origobjdir="$objdir" for file in $files; do func_dirname "$file" "" "." dir="$func_dirname_result" if test "X$dir" = X.; then objdir="$origobjdir" else objdir="$dir/$origobjdir" fi func_basename "$file" name="$func_basename_result" test "$mode" = uninstall && objdir="$dir" # Remember objdir for removal later, being careful to avoid duplicates if test "$mode" = clean; then case " $rmdirs " in *" $objdir "*) ;; *) rmdirs="$rmdirs $objdir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do rmfiles="$rmfiles $objdir/$n" done test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" case "$mode" in clean) case " $library_names " in # " " in the beginning catches empty $dlname *" $dlname "*) ;; *) rmfiles="$rmfiles $objdir/$dlname" ;; esac test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test "$pic_object" != none; then rmfiles="$rmfiles $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test "$non_pic_object" != none; then rmfiles="$rmfiles $dir/$non_pic_object" fi fi ;; *) if test "$mode" = clean ; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe rmfiles="$rmfiles $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result rmfiles="$rmfiles $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then rmfiles="$rmfiles $objdir/lt-$name" fi if test "X$noexename" != "X$name" ; then rmfiles="$rmfiles $objdir/lt-${noexename}.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done objdir="$origobjdir" # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } { test "$mode" = uninstall || test "$mode" = clean; } && func_mode_uninstall ${1+"$@"} test -z "$mode" && { help="$generic_help" func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode \`$mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: # vi:sw=2 ================================================ FILE: distro/google-perftools-1.7/m4/ac_have_attribute.m4 ================================================ AC_DEFUN([AX_C___ATTRIBUTE__], [ AC_MSG_CHECKING(for __attribute__) AC_CACHE_VAL(ac_cv___attribute__, [ AC_TRY_COMPILE( [#include static void foo(void) __attribute__ ((unused)); void foo(void) { exit(1); }], [], ac_cv___attribute__=yes, ac_cv___attribute__=no )]) if test "$ac_cv___attribute__" = "yes"; then AC_DEFINE(HAVE___ATTRIBUTE__, 1, [define if your compiler has __attribute__]) fi AC_MSG_RESULT($ac_cv___attribute__) ]) ================================================ FILE: distro/google-perftools-1.7/m4/acx_nanosleep.m4 ================================================ # Check for support for nanosleep. It's defined in , but on # some systems, such as solaris, you need to link in a library to use it. # We set acx_nanosleep_ok if nanosleep is supported; in that case, # NANOSLEEP_LIBS is set to whatever libraries are needed to support # nanosleep. AC_DEFUN([ACX_NANOSLEEP], [AC_MSG_CHECKING(if nanosleep requires any libraries) AC_LANG_SAVE AC_LANG_C acx_nanosleep_ok="no" NANOSLEEP_LIBS= # For most folks, this should just work AC_TRY_LINK([#include ], [static struct timespec ts; nanosleep(&ts, NULL);], [acx_nanosleep_ok=yes]) # For solaris, we may need -lrt if test "x$acx_nanosleep_ok" != "xyes"; then OLD_LIBS="$LIBS" LIBS="-lrt $LIBS" AC_TRY_LINK([#include ], [static struct timespec ts; nanosleep(&ts, NULL);], [acx_nanosleep_ok=yes]) if test "x$acx_nanosleep_ok" = "xyes"; then NANOSLEEP_LIBS="-lrt" fi LIBS="$OLD_LIBS" fi if test "x$acx_nanosleep_ok" != "xyes"; then AC_MSG_ERROR([cannot find the nanosleep function]) else AC_MSG_RESULT(${NANOSLEEP_LIBS:-no}) fi AC_LANG_RESTORE ]) ================================================ FILE: distro/google-perftools-1.7/m4/acx_pthread.m4 ================================================ # This was retrieved from # http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?revision=1277&root=avahi # See also (perhaps for new versions?) # http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?root=avahi # # We've rewritten the inconsistency check code (from avahi), to work # more broadly. In particular, it no longer assumes ld accepts -zdefs. # This caused a restructing of the code, but the functionality has only # changed a little. dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) dnl dnl @summary figure out how to build C programs using POSIX threads dnl dnl This macro figures out how to build C programs using POSIX threads. dnl It sets the PTHREAD_LIBS output variable to the threads library and dnl linker flags, and the PTHREAD_CFLAGS output variable to any special dnl C compiler flags that are needed. (The user can also force certain dnl compiler flags/libs to be tested by setting these environment dnl variables.) dnl dnl Also sets PTHREAD_CC to any special C compiler that is needed for dnl multi-threaded programs (defaults to the value of CC otherwise). dnl (This is necessary on AIX to use the special cc_r compiler alias.) dnl dnl NOTE: You are assumed to not only compile your program with these dnl flags, but also link it with them as well. e.g. you should link dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS dnl $LIBS dnl dnl If you are only building threads programs, you may wish to use dnl these variables in your default LIBS, CFLAGS, and CC: dnl dnl LIBS="$PTHREAD_LIBS $LIBS" dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" dnl CC="$PTHREAD_CC" dnl dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). dnl dnl ACTION-IF-FOUND is a list of shell commands to run if a threads dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the dnl default action will define HAVE_PTHREAD. dnl dnl Please let the authors know if this macro fails on any platform, or dnl if you have any other suggestions or comments. This macro was based dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros dnl posted by Alejandro Forero Cuervo to the autoconf macro repository. dnl We are also grateful for the helpful feedback of numerous users. dnl dnl @category InstalledPackages dnl @author Steven G. Johnson dnl @version 2006-05-29 dnl @license GPLWithACException dnl dnl Checks for GCC shared/pthread inconsistency based on work by dnl Marcin Owsiany AC_DEFUN([ACX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_SAVE AC_LANG_C acx_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) AC_MSG_RESULT($acx_pthread_ok) if test x"$acx_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case "${host_cpu}-${host_os}" in *solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" ;; esac if test x"$acx_pthread_ok" = xno; then for flag in $acx_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) if test x"$acx_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [acx_pthread_ok=yes]) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT($acx_pthread_ok) if test "x$acx_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$acx_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_TRY_LINK([#include ], [int attr=$attr; return attr;], [attr_name=$attr; break]) done AC_MSG_RESULT($attr_name) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case "${host_cpu}-${host_os}" in *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; esac AC_MSG_RESULT(${flag}) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with xlc_r or cc_r if test x"$GCC" != xyes; then AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) else PTHREAD_CC=$CC fi # The next part tries to detect GCC inconsistency with -shared on some # architectures and systems. The problem is that in certain # configurations, when -shared is specified, GCC "forgets" to # internally use various flags which are still necessary. # # Prepare the flags # save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_CC="$CC" # Try with the flags determined by the earlier checks. # # -Wl,-z,defs forces link-time symbol resolution, so that the # linking checks with -shared actually have any value # # FIXME: -fPIC is required for -shared on many architectures, # so we specify it here, but the right way would probably be to # properly detect whether it is actually required. CFLAGS="-shared -fPIC -Wl,-z,defs $CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CC="$PTHREAD_CC" # In order not to create several levels of indentation, we test # the value of "$done" until we find the cure or run out of ideas. done="no" # First, make sure the CFLAGS we added are actually accepted by our # compiler. If not (and OS X's ld, for instance, does not accept -z), # then we can't do this test. if test x"$done" = xno; then AC_MSG_CHECKING([whether to check for GCC pthread/shared inconsistencies]) AC_TRY_LINK(,, , [done=yes]) if test "x$done" = xyes ; then AC_MSG_RESULT([no]) else AC_MSG_RESULT([yes]) fi fi if test x"$done" = xno; then AC_MSG_CHECKING([whether -pthread is sufficient with -shared]) AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [done=yes]) if test "x$done" = xyes; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi # # Linux gcc on some architectures such as mips/mipsel forgets # about -lpthread # if test x"$done" = xno; then AC_MSG_CHECKING([whether -lpthread fixes that]) LIBS="-lpthread $PTHREAD_LIBS $save_LIBS" AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [done=yes]) if test "x$done" = xyes; then AC_MSG_RESULT([yes]) PTHREAD_LIBS="-lpthread $PTHREAD_LIBS" else AC_MSG_RESULT([no]) fi fi # # FreeBSD 4.10 gcc forgets to use -lc_r instead of -lc # if test x"$done" = xno; then AC_MSG_CHECKING([whether -lc_r fixes that]) LIBS="-lc_r $PTHREAD_LIBS $save_LIBS" AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [done=yes]) if test "x$done" = xyes; then AC_MSG_RESULT([yes]) PTHREAD_LIBS="-lc_r $PTHREAD_LIBS" else AC_MSG_RESULT([no]) fi fi if test x"$done" = xno; then # OK, we have run out of ideas AC_MSG_WARN([Impossible to determine how to use pthreads with shared libraries]) # so it's not safe to assume that we may use pthreads acx_pthread_ok=no fi AC_MSG_CHECKING([whether what we have so far is sufficient with -nostdlib]) CFLAGS="-nostdlib $CFLAGS" # we need c with nostdlib LIBS="$LIBS -lc" AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [done=yes],[done=no]) if test "x$done" = xyes; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi if test x"$done" = xno; then AC_MSG_CHECKING([whether -lpthread saves the day]) LIBS="-lpthread $LIBS" AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [done=yes],[done=no]) if test "x$done" = xyes; then AC_MSG_RESULT([yes]) PTHREAD_LIBS="$PTHREAD_LIBS -lpthread" else AC_MSG_RESULT([no]) AC_MSG_WARN([Impossible to determine how to use pthreads with shared libraries and -nostdlib]) fi fi CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" CC="$save_CC" else PTHREAD_CC="$CC" fi AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_CC) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$acx_pthread_ok" = xyes; then ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) : else acx_pthread_ok=no $2 fi AC_LANG_RESTORE ])dnl ACX_PTHREAD ================================================ FILE: distro/google-perftools-1.7/m4/compiler_characteristics.m4 ================================================ # Check compiler characteristics (e.g. type sizes, PRIxx macros, ...) # If types $1 and $2 are compatible, perform action $3 AC_DEFUN([AC_TYPES_COMPATIBLE], [AC_TRY_COMPILE([#include ], [$1 v1 = 0; $2 v2 = 0; return (&v1 - &v2)], $3)]) define(AC_PRIUS_COMMENT, [printf format code for printing a size_t and ssize_t]) AC_DEFUN([AC_COMPILER_CHARACTERISTICS], [AC_CACHE_CHECK(AC_PRIUS_COMMENT, ac_cv_formatting_prius_prefix, [AC_TYPES_COMPATIBLE(unsigned int, size_t, ac_cv_formatting_prius_prefix=; ac_cv_prius_defined=1) AC_TYPES_COMPATIBLE(unsigned long, size_t, ac_cv_formatting_prius_prefix=l; ac_cv_prius_defined=1) AC_TYPES_COMPATIBLE(unsigned long long, size_t, ac_cv_formatting_prius_prefix=ll; ac_cv_prius_defined=1 )]) if test -z "$ac_cv_prius_defined"; then ac_cv_formatting_prius_prefix=z; fi AC_DEFINE_UNQUOTED(PRIuS, "${ac_cv_formatting_prius_prefix}u", AC_PRIUS_COMMENT) AC_DEFINE_UNQUOTED(PRIxS, "${ac_cv_formatting_prius_prefix}x", AC_PRIUS_COMMENT) AC_DEFINE_UNQUOTED(PRIdS, "${ac_cv_formatting_prius_prefix}d", AC_PRIUS_COMMENT) ]) ================================================ FILE: distro/google-perftools-1.7/m4/install_prefix.m4 ================================================ AC_DEFUN([AC_INSTALL_PREFIX], [ac_cv_install_prefix="$prefix"; if test x"$ac_cv_install_prefix" = x"NONE" ; then ac_cv_install_prefix="$ac_default_prefix"; fi AC_DEFINE_UNQUOTED(INSTALL_PREFIX, "$ac_cv_install_prefix", [prefix where we look for installed files]) ]) ================================================ FILE: distro/google-perftools-1.7/m4/libtool.m4 ================================================ # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool 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 2 of # the License, or (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) # serial 56 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. m4_defun([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl _LT_PROG_ECHO_BACKSLASH case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from `configure', and `config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # `config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain="$ac_aux_dir/ltmain.sh" ])# _LT_PROG_LTMAIN ## ------------------------------------- ## ## Accumulate code for creating libtool. ## ## ------------------------------------- ## # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the `libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) ## ------------------------ ## ## FIXME: Eliminate VARNAME ## ## ------------------------ ## # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to `config.status' so that its # declaration there will have the same value as in `configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "X$" | $Xsed -e "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags="_LT_TAGS"dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the `libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into `config.status', and then the shell code to quote escape them in # for loops in `config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Fix-up fallback echo if it was mangled by the above quoting rules. case \$lt_ECHO in *'\\\[$]0 --fallback-echo"')dnl " lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\` ;; esac _LT_OUTPUT_LIBTOOL_INIT ]) # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) cat >"$CONFIG_LT" <<_LTEOF #! $SHELL # Generated by $as_me. # Run this file to recreate a libtool stub with the current configuration. lt_cl_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ \`$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2008 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test $[#] != 0 do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try \`$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try \`$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. if test "$no_create" != yes; then lt_cl_success=: test "$silent" = yes && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) fi ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # _LT_COPYING _LT_LIBTOOL_TAGS # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) _LT_PROG_XSI_SHELLFNS sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS="$save_LDFLAGS" ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[[012]]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES # -------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(whole_archive_flag_spec, $1)='' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=echo _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" m4_if([$1], [CXX], [ if test "$lt_cv_apple_cc_single_mod" != "yes"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX # ----------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl AC_LINK_IFELSE(AC_LANG_PROGRAM,[ lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/ p } }' aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [ifdef([AC_DIVERSION_NOTICE], [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], [AC_DIVERT_PUSH(NOTICE)]) $1 AC_DIVERT_POP ])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Add some code to the start of the generated configure script which # will find an echo command which doesn't interpret backslashes. m4_defun([_LT_PROG_ECHO_BACKSLASH], [_LT_SHELL_INIT([ # Check that we are running under the correct shell. SHELL=${CONFIG_SHELL-/bin/sh} case X$lt_ECHO in X*--fallback-echo) # Remove one level of quotation (which was required for Make). ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` ;; esac ECHO=${lt_ECHO-echo} if test "X[$]1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X[$]1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then # Yippee, $ECHO works! : else # Restart under the correct shell. exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} fi if test "X[$]1" = X--fallback-echo; then # used as fallback echo shift cat <<_LT_EOF [$]* _LT_EOF exit 0 fi # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test -z "$lt_ECHO"; then if test "X${echo_test_string+set}" != Xset; then # find a string as large as possible, as long as the shell can cope with it for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... if { echo_test_string=`eval $cmd`; } 2>/dev/null && { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null then break fi done fi if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then : else # The Solaris, AIX, and Digital Unix default echo programs unquote # backslashes. This makes it impossible to quote backslashes using # echo "$something" | sed 's/\\/\\\\/g' # # So, first we look for a working echo in the user's PATH. lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for dir in $PATH /usr/ucb; do IFS="$lt_save_ifs" if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then ECHO="$dir/echo" break fi done IFS="$lt_save_ifs" if test "X$ECHO" = Xecho; then # We didn't find a better echo, so look for alternatives. if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # This shell has a builtin print -r that does the trick. ECHO='print -r' elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && test "X$CONFIG_SHELL" != X/bin/ksh; then # If we have ksh, try running configure again with it. ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} export ORIGINAL_CONFIG_SHELL CONFIG_SHELL=/bin/ksh export CONFIG_SHELL exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} else # Try using printf. ECHO='printf %s\n' if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # Cool, printf works : elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL export CONFIG_SHELL SHELL="$CONFIG_SHELL" export SHELL ECHO="$CONFIG_SHELL [$]0 --fallback-echo" elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then ECHO="$CONFIG_SHELL [$]0 --fallback-echo" else # maybe with a smaller string... prev=: for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null then break fi prev="$cmd" done if test "$prev" != 'sed 50q "[$]0"'; then echo_test_string=`eval $prev` export echo_test_string exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} else # Oops. We lost completely, so just stick with echo. ECHO=echo fi fi fi fi fi fi # Copy echo and quote the copy suitably for passing to libtool from # the Makefile, instead of quoting the original, which is used later. lt_ECHO=$ECHO if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" fi AC_SUBST(lt_ECHO) ]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that does not interpret backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line __oline__ "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; sparc*-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) LD="${LD-ld} -m elf64_sparc" ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" ])# _LT_ENABLE_LOCK # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [AC_CHECK_TOOL(AR, ar, false) test -z "$AR" && AR=ar test -z "$AR_FLAGS" && AR_FLAGS=cru _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1]) AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" fi _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test x"[$]$2" = xyes; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ = "XX$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line __oline__ "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links="nottested" if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", [Define to the sub-directory in which libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existent directories. if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` else lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[[4-9]]*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[123]]*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; interix[[3-9]]*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([], [sys_lib_dlsearch_path_spec], [2], [Run-time system search path for libraries]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program which can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program which can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be Linux ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method == "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi]) if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :) AC_SUBST([DUMPBIN]) if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ const struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_save_LIBS="$LIBS" lt_save_CFLAGS="$CFLAGS" LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS="$lt_save_LIBS" CFLAGS="$lt_save_CFLAGS" else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= AC_MSG_CHECKING([for $compiler option to produce PIC]) m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC*) # IBM XL 8.0 on PPC _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; pgcc* | pgf77* | pgf90* | pgf95*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl*) # IBM XL C 8.0/Fortran 10.1 on PPC _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Sun\ F*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' ;; linux* | k*bsd*-gnu) _LT_TAGVAR(link_all_deplibs, $1)=no ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu) _LT_TAGVAR(link_all_deplibs, $1)=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag= tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; xl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi _LT_TAGVAR(link_all_deplibs, $1)=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; freebsd1*) _LT_TAGVAR(ld_shlibs, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" AC_LINK_IFELSE(int foo(void) {}, _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' ) LDFLAGS="$save_LDFLAGS" else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_MSG_CHECKING([whether -lc should be explicitly linked in]) $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then _LT_TAGVAR(archive_cmds_need_lc, $1)=no else _LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)]) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1], [[If ld is used when linking, flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting ${shlibpath_var} if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [fix_srcfile_path], [1], [Fix the shell variable $srcfile for the compiler]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report which library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC="$lt_save_CC" ])# _LT_LANG_C_CONFIG # _LT_PROG_CXX # ------------ # Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++ # compiler, we have our own version here. m4_defun([_LT_PROG_CXX], [ pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes]) AC_PROG_CXX if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi popdef([AC_MSG_ERROR]) ])# _LT_PROG_CXX dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([_LT_PROG_CXX], []) # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [AC_REQUIRE([_LT_PROG_CXX])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared # libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd[[12]]*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; gnu*) ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; *) if test "$GXX" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 will use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; xl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='echo' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd2*) # C++ shared libraries are fairly broken _LT_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=echo else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='echo' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(GCC, $1)="$GXX" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ]) dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case $p in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue else prev= fi if test "$pre_test_object_deps_done" = no; then case $p in -L* | -R*) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)="${prev}${p}" else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" fi fi ;; *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)="$p" else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)="$p" else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_PROG_F77 # ------------ # Since AC_PROG_F77 is broken, in that it returns the empty string # if there is no fortran compiler, we have our own version here. m4_defun([_LT_PROG_F77], [ pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes]) AC_PROG_F77 if test -z "$F77" || test "X$F77" = "Xno"; then _lt_disable_F77=yes fi popdef([AC_MSG_ERROR]) ])# _LT_PROG_F77 dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([_LT_PROG_F77], []) # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_REQUIRE([_LT_PROG_F77])dnl AC_LANG_PUSH(Fortran 77) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_F77" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC CC=${F77-"f77"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$G77" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" fi # test "$_lt_disable_F77" != yes AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_PROG_FC # ----------- # Since AC_PROG_FC is broken, in that it returns the empty string # if there is no fortran compiler, we have our own version here. m4_defun([_LT_PROG_FC], [ pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes]) AC_PROG_FC if test -z "$FC" || test "X$FC" = "Xno"; then _lt_disable_FC=yes fi popdef([AC_MSG_ERROR]) ])# _LT_PROG_FC dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([_LT_PROG_FC], []) # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_REQUIRE([_LT_PROG_FC])dnl AC_LANG_PUSH(Fortran) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_FC" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC CC=${FC-"f95"} compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" fi # test "$_lt_disable_FC" != yes AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC="$lt_save_CC" ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC GCC= CC=${RC-"windres"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC="$lt_save_CC" ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [AC_MSG_CHECKING([whether the shell understands some XSI constructs]) # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes AC_MSG_RESULT([$xsi_shell]) _LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) AC_MSG_CHECKING([whether the shell understands "+="]) lt_shell_append=no ( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes AC_MSG_RESULT([$lt_shell_append]) _LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PROG_XSI_SHELLFNS # --------------------- # Bourne and XSI compatible variants of some useful shell functions. m4_defun([_LT_PROG_XSI_SHELLFNS], [case $xsi_shell in yes) cat << \_LT_EOF >> "$cfgfile" # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac } # func_basename file func_basename () { func_basename_result="${1##*/}" } # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}" } # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). func_stripname () { # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"} } # func_opt_split func_opt_split () { func_opt_split_opt=${1%%=*} func_opt_split_arg=${1#*=} } # func_lo2o object func_lo2o () { case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac } # func_xform libobj-or-source func_xform () { func_xform_result=${1%.*}.lo } # func_arith arithmetic-term... func_arith () { func_arith_result=$(( $[*] )) } # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=${#1} } _LT_EOF ;; *) # Bourne compatible functions. cat << \_LT_EOF >> "$cfgfile" # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi } # func_basename file func_basename () { func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` } dnl func_dirname_and_basename dnl A portable version of this function is already defined in general.m4sh dnl so there is no need for it here. # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # func_strip_suffix prefix name func_stripname () { case ${2} in .*) func_stripname_result=`$ECHO "X${3}" \ | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "X${3}" \ | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; esac } # sed scripts: my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q' my_sed_long_arg='1s/^-[[^=]]*=//' # func_opt_split func_opt_split () { func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` } # func_lo2o object func_lo2o () { func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` } # func_xform libobj-or-source func_xform () { func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'` } # func_arith arithmetic-term... func_arith () { func_arith_result=`expr "$[@]"` } # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len` } _LT_EOF esac case $lt_shell_append in yes) cat << \_LT_EOF >> "$cfgfile" # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "$[1]+=\$[2]" } _LT_EOF ;; *) cat << \_LT_EOF >> "$cfgfile" # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "$[1]=\$$[1]\$[2]" } _LT_EOF ;; esac ]) ================================================ FILE: distro/google-perftools-1.7/m4/ltoptions.m4 ================================================ # Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option `$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl `shared' nor `disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) ]) ])# _LT_SET_OPTIONS ## --------------------------------- ## ## Macros to handle LT_INIT options. ## ## --------------------------------- ## # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [0], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the `shared' and # `disable-shared' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the `static' and # `disable-static' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the `fast-install' # and `disable-fast-install' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the `pic-only' and `no-pic' # LT_INIT options. # MODE is either `yes' or `no'. If omitted, it defaults to `both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [pic_mode="$withval"], [pic_mode=default]) test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) ## ----------------- ## ## LTDL_INIT Options ## ## ----------------- ## m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) ================================================ FILE: distro/google-perftools-1.7/m4/ltsugar.m4 ================================================ # ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59 which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) ================================================ FILE: distro/google-perftools-1.7/m4/ltversion.m4 ================================================ # ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # Generated from ltversion.in. # serial 3017 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.2.6b]) m4_define([LT_PACKAGE_REVISION], [1.3017]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.2.6b' macro_revision='1.3017' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) ================================================ FILE: distro/google-perftools-1.7/m4/lt~obsolete.m4 ================================================ # lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 4 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) ================================================ FILE: distro/google-perftools-1.7/m4/namespaces.m4 ================================================ # Checks whether the compiler implements namespaces AC_DEFUN([AC_CXX_NAMESPACES], [AC_CACHE_CHECK(whether the compiler implements namespaces, ac_cv_cxx_namespaces, [AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_COMPILE([namespace Outer { namespace Inner { int i = 0; }}], [using namespace Outer::Inner; return i;], ac_cv_cxx_namespaces=yes, ac_cv_cxx_namespaces=no) AC_LANG_RESTORE]) if test "$ac_cv_cxx_namespaces" = yes; then AC_DEFINE(HAVE_NAMESPACES, 1, [define if the compiler implements namespaces]) fi]) ================================================ FILE: distro/google-perftools-1.7/m4/pc_from_ucontext.m4 ================================================ # We want to access the "PC" (Program Counter) register from a struct # ucontext. Every system has its own way of doing that. We try all the # possibilities we know about. Note REG_PC should come first (REG_RIP # is also defined on solaris, but does the wrong thing). # OpenBSD doesn't have ucontext.h, but we can get PC from ucontext_t # by using signal.h. # The first argument of AC_PC_FROM_UCONTEXT will be invoked when we # cannot find a way to obtain PC from ucontext. AC_DEFUN([AC_PC_FROM_UCONTEXT], [AC_CHECK_HEADERS(ucontext.h) # Redhat 7 has , but it barfs if we #include it directly # (this was fixed in later redhats). works fine, so use that. if grep "Red Hat Linux release 7" /etc/redhat-release >/dev/null 2>&1; then AC_DEFINE(HAVE_SYS_UCONTEXT_H, 0, [ is broken on redhat 7]) ac_cv_header_sys_ucontext_h=no else AC_CHECK_HEADERS(sys/ucontext.h) # ucontext on OS X 10.6 (at least) fi AC_CHECK_HEADERS(cygwin/signal.h) # ucontext on cywgin AC_MSG_CHECKING([how to access the program counter from a struct ucontext]) pc_fields=" uc_mcontext.gregs[[REG_PC]]" # Solaris x86 (32 + 64 bit) pc_fields="$pc_fields uc_mcontext.gregs[[REG_EIP]]" # Linux (i386) pc_fields="$pc_fields uc_mcontext.gregs[[REG_RIP]]" # Linux (x86_64) pc_fields="$pc_fields uc_mcontext.sc_ip" # Linux (ia64) pc_fields="$pc_fields uc_mcontext.uc_regs->gregs[[PT_NIP]]" # Linux (ppc) pc_fields="$pc_fields uc_mcontext.gregs[[R15]]" # Linux (arm old [untested]) pc_fields="$pc_fields uc_mcontext.arm_pc" # Linux (arm arch 5) pc_fields="$pc_fields uc_mcontext.gp_regs[[PT_NIP]]" # Suse SLES 11 (ppc64) pc_fields="$pc_fields uc_mcontext.mc_eip" # FreeBSD (i386) pc_fields="$pc_fields uc_mcontext.mc_rip" # FreeBSD (x86_64 [untested]) pc_fields="$pc_fields uc_mcontext.__gregs[[_REG_EIP]]" # NetBSD (i386) pc_fields="$pc_fields uc_mcontext.__gregs[[_REG_RIP]]" # NetBSD (x86_64) pc_fields="$pc_fields uc_mcontext->ss.eip" # OS X (i386, <=10.4) pc_fields="$pc_fields uc_mcontext->__ss.__eip" # OS X (i386, >=10.5) pc_fields="$pc_fields uc_mcontext->ss.rip" # OS X (x86_64) pc_fields="$pc_fields uc_mcontext->__ss.__rip" # OS X (>=10.5 [untested]) pc_fields="$pc_fields uc_mcontext->ss.srr0" # OS X (ppc, ppc64 [untested]) pc_fields="$pc_fields uc_mcontext->__ss.__srr0" # OS X (>=10.5 [untested]) pc_field_found=false for pc_field in $pc_fields; do if ! $pc_field_found; then # Prefer sys/ucontext.h to ucontext.h, for OS X's sake. if test "x$ac_cv_header_cygwin_signal_h" = xyes; then AC_TRY_COMPILE([#define _GNU_SOURCE 1 #include ], [ucontext_t u; return u.$pc_field == 0;], AC_DEFINE_UNQUOTED(PC_FROM_UCONTEXT, $pc_field, How to access the PC from a struct ucontext) AC_MSG_RESULT([$pc_field]) pc_field_found=true) elif test "x$ac_cv_header_sys_ucontext_h" = xyes; then AC_TRY_COMPILE([#define _GNU_SOURCE 1 #include ], [ucontext_t u; return u.$pc_field == 0;], AC_DEFINE_UNQUOTED(PC_FROM_UCONTEXT, $pc_field, How to access the PC from a struct ucontext) AC_MSG_RESULT([$pc_field]) pc_field_found=true) elif test "x$ac_cv_header_ucontext_h" = xyes; then AC_TRY_COMPILE([#define _GNU_SOURCE 1 #include ], [ucontext_t u; return u.$pc_field == 0;], AC_DEFINE_UNQUOTED(PC_FROM_UCONTEXT, $pc_field, How to access the PC from a struct ucontext) AC_MSG_RESULT([$pc_field]) pc_field_found=true) else # hope some standard header gives it to us AC_TRY_COMPILE([], [ucontext_t u; return u.$pc_field == 0;], AC_DEFINE_UNQUOTED(PC_FROM_UCONTEXT, $pc_field, How to access the PC from a struct ucontext) AC_MSG_RESULT([$pc_field]) pc_field_found=true) fi fi done if ! $pc_field_found; then pc_fields=" sc_eip" # OpenBSD (i386) pc_fields="$pc_fields sc_rip" # OpenBSD (x86_64) for pc_field in $pc_fields; do if ! $pc_field_found; then AC_TRY_COMPILE([#include ], [ucontext_t u; return u.$pc_field == 0;], AC_DEFINE_UNQUOTED(PC_FROM_UCONTEXT, $pc_field, How to access the PC from a struct ucontext) AC_MSG_RESULT([$pc_field]) pc_field_found=true) fi done fi if ! $pc_field_found; then [$1] fi]) ================================================ FILE: distro/google-perftools-1.7/m4/program_invocation_name.m4 ================================================ # We need to be careful to avoid having the reference to # program_invocation_name optimized out. We do that by # returning the value. AC_DEFUN([AC_PROGRAM_INVOCATION_NAME], [AC_CACHE_CHECK( for program_invocation_name, ac_cv_have_program_invocation_name, AC_TRY_LINK([extern char* program_invocation_name;], [return *program_invocation_name;], [ac_cv_have_program_invocation_name=yes], [ac_cv_have_program_invocation_name=no]) ) if test "$ac_cv_have_program_invocation_name" = "yes"; then AC_DEFINE(HAVE_PROGRAM_INVOCATION_NAME, 1, [define if libc has program_invocation_name]) fi ]) ================================================ FILE: distro/google-perftools-1.7/m4/stl_namespace.m4 ================================================ # We check what namespace stl code like vector expects to be executed in AC_DEFUN([AC_CXX_STL_NAMESPACE], [AC_CACHE_CHECK( what namespace STL code is in, ac_cv_cxx_stl_namespace, [AC_REQUIRE([AC_CXX_NAMESPACES]) AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_COMPILE([#include ], [vector t; return 0;], ac_cv_cxx_stl_namespace=none) AC_TRY_COMPILE([#include ], [std::vector t; return 0;], ac_cv_cxx_stl_namespace=std) AC_LANG_RESTORE]) if test "$ac_cv_cxx_stl_namespace" = none; then AC_DEFINE(STL_NAMESPACE,, [the namespace where STL code like vector<> is defined]) fi if test "$ac_cv_cxx_stl_namespace" = std; then AC_DEFINE(STL_NAMESPACE,std, [the namespace where STL code like vector<> is defined]) fi ]) ================================================ FILE: distro/google-perftools-1.7/missing ================================================ #! /bin/sh # Common stub for a few missing GNU programs while installing. scriptversion=2005-06-08.21 # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005 # Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # 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 2, 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., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi msg="missing on your system" case "$1" in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 # Exit code 63 means version mismatch. This often happens # when the user try to use an ancient version of a tool on # a file that requires a minimum version. In this case we # we should proceed has if the program had been absent, or # if --run hadn't been passed. if test $? = 63; then run=: msg="probably too old" fi ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file tar try tar, gnutar, gtar, then tar without non-portable flags yacc create \`y.tab.[ch]', if possible, from existing .[ch] Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; esac # Now exit if we have it, but it failed. Also exit now if we # don't have it and --version was passed (most likely to detect # the program). case "$1" in lex|yacc) # Not GNU programs, they don't have --version. ;; tar) if test -n "$run"; then echo 1>&2 "ERROR: \`tar' requires --run" exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then exit 1 fi ;; *) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then # Could not run --version or --help. This is probably someone # running `$TOOL --version' or `$TOOL --help' to check whether # $TOOL exists and not knowing $TOOL uses missing. exit 1 fi ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case "$1" in aclocal*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case "$f" in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te) echo 1>&2 "\ WARNING: \`$1' is needed, but is $msg. You might have modified some files without having the proper tools for further handling them. You can get \`$1' as part of \`Autoconf' from any GNU archive site." file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison|yacc) echo 1>&2 "\ WARNING: \`$1' $msg. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.h fi ;; esac fi if [ ! -f y.tab.h ]; then echo >y.tab.h fi if [ ! -f y.tab.c ]; then echo 'main() { return 0; }' >y.tab.c fi ;; lex|flex) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if [ ! -f lex.yy.c ]; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` fi if [ -f "$file" ]; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit 1 fi ;; makeinfo) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." # The file to touch is that specified with -o ... file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then # ... or it is the one specified with @setfilename ... infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile` # ... or it is derived from the source name (dir/f.texi becomes f.info) test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info fi # If the file does not exist, the user really needs makeinfo; # let's fail without touching anything. test -f $file || exit 1 touch $file ;; tar) shift # We have already tried tar in the generic part. # Look for gnutar/gtar before invocation to avoid ugly error # messages. if (gnutar --version > /dev/null 2>&1); then gnutar "$@" && exit 0 fi if (gtar --version > /dev/null 2>&1); then gtar "$@" && exit 0 fi firstarg="$1" if shift; then case "$firstarg" in *o*) firstarg=`echo "$firstarg" | sed s/o//` tar "$firstarg" "$@" && exit 0 ;; esac case "$firstarg" in *h*) firstarg=`echo "$firstarg" | sed s/h//` tar "$firstarg" "$@" && exit 0 ;; esac fi echo 1>&2 "\ WARNING: I can't seem to be able to run \`tar' with the given arguments. You may want to install GNU tar or Free paxutils, or check the command line arguments." exit 1 ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and is $msg. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: ================================================ FILE: distro/google-perftools-1.7/mkinstalldirs ================================================ #! /bin/sh # mkinstalldirs --- make directory hierarchy scriptversion=2005-06-29.22 # Original author: Noah Friedman # Created: 1993-05-16 # Public domain. # # This file is maintained in Automake, please report # bugs to or send patches to # . errstatus=0 dirmode= usage="\ Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... Create each directory DIR (with mode MODE, if specified), including all leading file name components. Report bugs to ." # process command line arguments while test $# -gt 0 ; do case $1 in -h | --help | --h*) # -h for help echo "$usage" exit $? ;; -m) # -m PERM arg shift test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } dirmode=$1 shift ;; --version) echo "$0 $scriptversion" exit $? ;; --) # stop option processing shift break ;; -*) # unknown option echo "$usage" 1>&2 exit 1 ;; *) # first non-opt arg break ;; esac done for file do if test -d "$file"; then shift else break fi done case $# in 0) exit 0 ;; esac # Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and # mkdir -p a/c at the same time, both will detect that a is missing, # one will create a, then the other will try to create a and die with # a "File exists" error. This is a problem when calling mkinstalldirs # from a parallel make. We use --version in the probe to restrict # ourselves to GNU mkdir, which is thread-safe. case $dirmode in '') if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then echo "mkdir -p -- $*" exec mkdir -p -- "$@" else # On NextStep and OpenStep, the `mkdir' command does not # recognize any option. It will interpret all options as # directories to create, and then abort because `.' already # exists. test -d ./-p && rmdir ./-p test -d ./--version && rmdir ./--version fi ;; *) if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && test ! -d ./--version; then echo "mkdir -m $dirmode -p -- $*" exec mkdir -m "$dirmode" -p -- "$@" else # Clean up after NextStep and OpenStep mkdir. for d in ./-m ./-p ./--version "./$dirmode"; do test -d $d && rmdir $d done fi ;; esac for file do case $file in /*) pathcomp=/ ;; *) pathcomp= ;; esac oIFS=$IFS IFS=/ set fnord $file shift IFS=$oIFS for d do test "x$d" = x && continue pathcomp=$pathcomp$d case $pathcomp in -*) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr else if test ! -z "$dirmode"; then echo "chmod $dirmode $pathcomp" lasterr= chmod "$dirmode" "$pathcomp" || lasterr=$? if test ! -z "$lasterr"; then errstatus=$lasterr fi fi fi fi pathcomp=$pathcomp/ done done exit $errstatus # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: ================================================ FILE: distro/google-perftools-1.7/packages/deb/README ================================================ The list of files here isn't complete. For a step-by-step guide on how to set this package up correctly, check out http://www.debian.org/doc/maint-guide/ Most of the files that are in this directory are boilerplate. However, you may need to change the list of binary-arch dependencies in 'rules'. ================================================ FILE: distro/google-perftools-1.7/packages/deb/changelog ================================================ google-perftools (1.7-1) unstable; urgency=low * New upstream release. -- Google Inc. Fri, 04 Feb 2011 15:54:31 -0800 google-perftools (1.6-1) unstable; urgency=low * New upstream release. -- Google Inc. Thu, 05 Aug 2010 12:48:03 -0700 google-perftools (1.5-1) unstable; urgency=low * New upstream release. -- Google Inc. Tue, 19 Jan 2010 14:46:12 -0800 google-perftools (1.4-1) unstable; urgency=low * New upstream release. -- Google Inc. Thu, 10 Sep 2009 13:51:15 -0700 google-perftools (1.3-1) unstable; urgency=low * New upstream release. -- Google Inc. Tue, 09 Jun 2009 18:19:06 -0700 google-perftools (1.2-1) unstable; urgency=low * New upstream release. -- Google Inc. Fri, 17 Apr 2009 16:40:48 -0700 google-perftools (1.1-1) unstable; urgency=low * New upstream release. -- Google Inc. Wed, 11 Mar 2009 11:25:34 -0700 google-perftools (1.0-1) unstable; urgency=low * New upstream release. -- Google Inc. Tue, 06 Jan 2009 13:58:56 -0800 google-perftools (1.0rc1-1) unstable; urgency=low * New upstream release. -- Google Inc. Thu, 11 Dec 2008 16:01:32 -0800 google-perftools (0.99.1-1) unstable; urgency=low * New upstream release. -- Google Inc. Sat, 20 Sep 2008 09:37:18 -0700 google-perftools (0.99-1) unstable; urgency=low * New upstream release. -- Google Inc. Thu, 18 Sep 2008 16:00:27 -0700 google-perftools (0.98-1) unstable; urgency=low * New upstream release. -- Google Inc. Mon, 09 Jun 2008 16:47:03 -0700 google-perftools (0.97-1) unstable; urgency=low * New upstream release. -- Google Inc. Mon, 21 Apr 2008 15:20:52 -0700 google-perftools (0.96-1) unstable; urgency=low * New upstream release. -- Google Inc. Tue, 18 Mar 2008 14:30:44 -0700 google-perftools (0.95-1) unstable; urgency=low * New upstream release. -- Google Inc. Tue, 12 Feb 2008 12:28:32 -0800 google-perftools (0.94-1) unstable; urgency=low * New upstream release. -- Google Inc. Thu, 29 Nov 2007 07:59:43 -0800 google-perftools (0.93-1) unstable; urgency=low * New upstream release. -- Google Inc. Fri, 17 Aug 2007 12:32:56 -0700 google-perftools (0.92-1) unstable; urgency=low * New upstream release. -- Google Inc. Tue, 17 Jul 2007 22:26:27 -0700 google-perftools (0.91-1) unstable; urgency=low * New upstream release. -- Google Inc. Wed, 18 Apr 2007 16:43:55 -0700 google-perftools (0.90-1) unstable; urgency=low * New upstream release. -- Google Inc. Fri, 13 Apr 2007 14:50:51 -0700 google-perftools (0.8-1) unstable; urgency=low * New upstream release. -- Google Inc. Wed, 14 Jun 2006 15:11:14 -0700 google-perftools (0.7-1) unstable; urgency=low * New upstream release. -- Google Inc. Thu, 13 Apr 2006 20:59:09 -0700 google-perftools (0.6-1) unstable; urgency=low * New upstream release. -- Google Inc. Fri, 27 Jan 2006 14:04:27 -0800 google-perftools (0.5-1) unstable; urgency=low * New upstream release. -- Google Inc. Mon Nov 14 17:28:59 2005 google-perftools (0.4-1) unstable; urgency=low * New upstream release. -- Google Inc. Wed, 26 Oct 2005 15:19:16 -0700 google-perftools (0.3-1) unstable; urgency=low * New upstream release. -- Google Inc. Fri, 24 Jun 2005 18:02:26 -0700 google-perftools (0.2-1) unstable; urgency=low * New upstream release. -- Google Inc. Tue, 31 May 2005 08:14:38 -0700 google-perftools (0.1-1) unstable; urgency=low * Initial release. The google-perftools package contains some utilities to improve and analyze the performance of C++ programs. This includes an optimized thread-caching malloc() and cpu and heap profiling utilities. -- Google Inc. Fri, 11 Mar 2005 08:07:33 -0800 ================================================ FILE: distro/google-perftools-1.7/packages/deb/compat ================================================ 4 ================================================ FILE: distro/google-perftools-1.7/packages/deb/control ================================================ Source: google-perftools Priority: optional Maintainer: Google Inc. Build-Depends: debhelper (>= 4.0.0), binutils Standards-Version: 3.6.1 Package: libgoogle-perftools-dev Section: libdevel Architecture: any Depends: libgoogle-perftools0 (= ${Source-Version}) Description: libraries for CPU and heap analysis, plus an efficient thread-caching malloc The google-perftools package contains some utilities to improve and analyze the performance of C++ programs. This includes an optimized thread-caching malloc() and cpu and heap profiling utilities. The devel package contains static and debug libraries and header files for developing applications that use the google-perftools package. Package: libgoogle-perftools0 Section: libs Architecture: any Depends: ${shlibs:Depends} Description: libraries for CPU and heap analysis, plus an efficient thread-caching malloc The google-perftools package contains some utilities to improve and analyze the performance of C++ programs. This includes an optimized thread-caching malloc() and cpu and heap profiling utilities. ================================================ FILE: distro/google-perftools-1.7/packages/deb/copyright ================================================ This package was debianized by Google Inc. on 15 February 2005. It was downloaded from http://code.google.com/ Upstream Author: opensource@google.com Copyright (c) 2005, Google Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: distro/google-perftools-1.7/packages/deb/docs ================================================ AUTHORS COPYING ChangeLog INSTALL NEWS README TODO doc/cpuprofile.html doc/cpuprofile-fileformat.html doc/designstyle.css doc/heap-example1.png doc/heap_checker.html doc/heapprofile.html doc/index.html doc/overview.gif doc/pageheap.gif doc/pprof-test-big.gif doc/pprof-test.gif doc/pprof-vsnprintf-big.gif doc/pprof-vsnprintf.gif doc/pprof.1 doc/pprof_remote_servers.html doc/spanmap.gif doc/t-test1.times.txt doc/tcmalloc-opspercpusec.vs.threads.1024.bytes.png doc/tcmalloc-opspercpusec.vs.threads.128.bytes.png doc/tcmalloc-opspercpusec.vs.threads.131072.bytes.png doc/tcmalloc-opspercpusec.vs.threads.16384.bytes.png doc/tcmalloc-opspercpusec.vs.threads.2048.bytes.png doc/tcmalloc-opspercpusec.vs.threads.256.bytes.png doc/tcmalloc-opspercpusec.vs.threads.32768.bytes.png doc/tcmalloc-opspercpusec.vs.threads.4096.bytes.png doc/tcmalloc-opspercpusec.vs.threads.512.bytes.png doc/tcmalloc-opspercpusec.vs.threads.64.bytes.png doc/tcmalloc-opspercpusec.vs.threads.65536.bytes.png doc/tcmalloc-opspercpusec.vs.threads.8192.bytes.png doc/tcmalloc-opspersec.vs.size.1.threads.png doc/tcmalloc-opspersec.vs.size.12.threads.png doc/tcmalloc-opspersec.vs.size.16.threads.png doc/tcmalloc-opspersec.vs.size.2.threads.png doc/tcmalloc-opspersec.vs.size.20.threads.png doc/tcmalloc-opspersec.vs.size.3.threads.png doc/tcmalloc-opspersec.vs.size.4.threads.png doc/tcmalloc-opspersec.vs.size.5.threads.png doc/tcmalloc-opspersec.vs.size.8.threads.png doc/tcmalloc.html doc/threadheap.gif ================================================ FILE: distro/google-perftools-1.7/packages/deb/libgoogle-perftools-dev.dirs ================================================ usr/lib usr/lib/pkgconfig usr/include usr/include/google ================================================ FILE: distro/google-perftools-1.7/packages/deb/libgoogle-perftools-dev.install ================================================ usr/include/google/* usr/lib/lib*.so usr/lib/lib*.a usr/lib/*.la usr/lib/pkgconfig/*.pc debian/tmp/usr/include/google/* debian/tmp/usr/lib/lib*.so debian/tmp/usr/lib/lib*.a debian/tmp/usr/lib/*.la debian/tmp/usr/lib/pkgconfig/*.pc ================================================ FILE: distro/google-perftools-1.7/packages/deb/libgoogle-perftools0.dirs ================================================ usr/lib usr/bin ================================================ FILE: distro/google-perftools-1.7/packages/deb/libgoogle-perftools0.install ================================================ usr/lib/lib*.so.* usr/bin/pprof* debian/tmp/usr/lib/lib*.so.* debian/tmp/usr/bin/pprof* ================================================ FILE: distro/google-perftools-1.7/packages/deb/libgoogle-perftools0.manpages ================================================ doc/pprof.1 ================================================ FILE: distro/google-perftools-1.7/packages/deb/rules ================================================ #!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # This file was originally written by Joey Hess and Craig Small. # As a special exception, when this file is copied by dh-make into a # dh-make output file, you may use that output file without restriction. # This special exception was added by Craig Small in version 0.37 of dh-make. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 # These are used for cross-compiling and for saving the configure script # from having to guess our platform (since we know it already) DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) CFLAGS = -Wall -g ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) CFLAGS += -O0 else CFLAGS += -O2 endif ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) INSTALL_PROGRAM += -s endif # shared library versions, option 1 #version=2.0.5 #major=2 # option 2, assuming the library is created as src/.libs/libfoo.so.2.0.5 or so version=`ls src/.libs/lib*.so.* | \ awk '{if (match($$0,/[0-9]+\.[0-9]+\.[0-9]+$$/)) print substr($$0,RSTART)}'` major=`ls src/.libs/lib*.so.* | \ awk '{if (match($$0,/\.so\.[0-9]+$$/)) print substr($$0,RSTART+4)}'` config.status: configure dh_testdir # Add here commands to configure the package. CFLAGS="$(CFLAGS)" ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info build: build-stamp build-stamp: config.status dh_testdir # Add here commands to compile the package. $(MAKE) touch build-stamp clean: dh_testdir dh_testroot rm -f build-stamp # Add here commands to clean up after the build process. -$(MAKE) distclean ifneq "$(wildcard /usr/share/misc/config.sub)" "" cp -f /usr/share/misc/config.sub config.sub endif ifneq "$(wildcard /usr/share/misc/config.guess)" "" cp -f /usr/share/misc/config.guess config.guess endif dh_clean install: build dh_testdir dh_testroot dh_clean -k dh_installdirs # Add here commands to install the package into debian/tmp $(MAKE) install DESTDIR=$(CURDIR)/debian/tmp # Build architecture-independent files here. binary-indep: build install # We have nothing to do by default. # Build architecture-dependent files here. binary-arch: build install dh_testdir dh_testroot dh_installchangelogs ChangeLog dh_installdocs dh_installexamples dh_install --sourcedir=debian/tmp # dh_installmenu # dh_installdebconf # dh_installlogrotate # dh_installemacsen # dh_installpam # dh_installmime # dh_installinit # dh_installcron # dh_installinfo dh_installman dh_link dh_strip dh_compress dh_fixperms # dh_perl # dh_python dh_makeshlibs dh_installdeb dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install ================================================ FILE: distro/google-perftools-1.7/packages/deb.sh ================================================ #!/bin/bash -e # This takes one commandline argument, the name of the package. If no # name is given, then we'll end up just using the name associated with # an arbitrary .tar.gz file in the rootdir. That's fine: there's probably # only one. # # Run this from the 'packages' directory, just under rootdir ## Set LIB to lib if exporting a library, empty-string else LIB= #LIB=lib PACKAGE="$1" VERSION="$2" # We can only build Debian packages, if the Debian build tools are installed if [ \! -x /usr/bin/debuild ]; then echo "Cannot find /usr/bin/debuild. Not building Debian packages." 1>&2 exit 0 fi # Double-check we're in the packages directory, just under rootdir if [ \! -r ../Makefile -a \! -r ../INSTALL ]; then echo "Must run $0 in the 'packages' directory, under the root directory." 1>&2 echo "Also, you must run \"make dist\" before running this script." 1>&2 exit 0 fi # Find the top directory for this package topdir="${PWD%/*}" # Find the tar archive built by "make dist" archive="${PACKAGE}-${VERSION}" archive_with_underscore="${PACKAGE}_${VERSION}" if [ -z "${archive}" ]; then echo "Cannot find ../$PACKAGE*.tar.gz. Run \"make dist\" first." 1>&2 exit 0 fi # Create a pristine directory for building the Debian package files trap 'rm -rf '`pwd`/tmp'; exit $?' EXIT SIGHUP SIGINT SIGTERM rm -rf tmp mkdir -p tmp cd tmp # Debian has very specific requirements about the naming of build # directories, and tar archives. It also wants to write all generated # packages to the parent of the source directory. We accommodate these # requirements by building directly from the tar file. ln -s "${topdir}/${archive}.tar.gz" "${LIB}${archive}.orig.tar.gz" # Some version of debuilder want foo.orig.tar.gz with _ between versions. ln -s "${topdir}/${archive}.tar.gz" "${LIB}${archive_with_underscore}.orig.tar.gz" tar zfx "${LIB}${archive}.orig.tar.gz" [ -n "${LIB}" ] && mv "${archive}" "${LIB}${archive}" cd "${LIB}${archive}" # This is one of those 'specific requirements': where the deb control files live cp -a "packages/deb" "debian" # Now, we can call Debian's standard build tool debuild -uc -us cd ../.. # get back to the original top-level dir # We'll put the result in a subdirectory that's named after the OS version # we've made this .deb file for. destdir="debian-$(cat /etc/debian_version 2>/dev/null || echo UNKNOWN)" rm -rf "$destdir" mkdir -p "$destdir" mv $(find tmp -mindepth 1 -maxdepth 1 -type f) "$destdir" echo echo "The Debian package files are located in $PWD/$destdir" ================================================ FILE: distro/google-perftools-1.7/packages/rpm/rpm.spec ================================================ %define RELEASE 1 %define rel %{?CUSTOM_RELEASE} %{!?CUSTOM_RELEASE:%RELEASE} %define prefix /usr Name: %NAME Summary: Performance tools for C++ Version: %VERSION Release: %rel Group: Development/Libraries URL: http://code.google.com/p/google-perftools/ License: BSD Vendor: Google Packager: Google Source: http://%{NAME}.googlecode.com/files/%{NAME}-%{VERSION}.tar.gz Distribution: Redhat 7 and above. Buildroot: %{_tmppath}/%{name}-root Prefix: %prefix %description The %name packages contains some utilities to improve and analyze the performance of C++ programs. This includes an optimized thread-caching malloc() and cpu and heap profiling utilities. %package devel Summary: Performance tools for C++ Group: Development/Libraries Requires: %{NAME} = %{VERSION} %description devel The %name-devel package contains static and debug libraries and header files for developing applications that use the %name package. %changelog * Mon Apr 20 2009 - Change build rule to use a configure line more like '%configure' - Change install to use DESTDIR instead of prefix for configure - Use wildcards for doc/ and lib/ directories * Fri Mar 11 2005 - First draft %prep %setup %build # I can't use '% configure', because it defines -m32 which breaks some # of the low-level atomicops files in this package. But I do take # as much from % configure (in /usr/lib/rpm/macros) as I can. ./configure --prefix=%{_prefix} --exec-prefix=%{_exec_prefix} --bindir=%{_bindir} --sbindir=%{_sbindir} --sysconfdir=%{_sysconfdir} --datadir=%{_datadir} --includedir=%{_includedir} --libdir=%{_libdir} --libexecdir=%{_libexecdir} --localstatedir=%{_localstatedir} --sharedstatedir=%{_sharedstatedir} --mandir=%{_mandir} --infodir=%{_infodir} make %install rm -rf $RPM_BUILD_ROOT make DESTDIR=$RPM_BUILD_ROOT install %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %docdir %{prefix}/share/doc/%{NAME}-%{VERSION} %{prefix}/share/doc/%{NAME}-%{VERSION}/* %{_libdir}/*.so.* %{_bindir}/pprof %{_mandir}/man1/pprof.1* %files devel %defattr(-,root,root) %{_includedir}/google %{_libdir}/*.a %{_libdir}/*.la %{_libdir}/*.so %{_libdir}/pkgconfig/*.pc ================================================ FILE: distro/google-perftools-1.7/packages/rpm.sh ================================================ #!/bin/sh -e # Run this from the 'packages' directory, just under rootdir # We can only build rpm packages, if the rpm build tools are installed if [ \! -x /usr/bin/rpmbuild ] then echo "Cannot find /usr/bin/rpmbuild. Not building an rpm." 1>&2 exit 0 fi # Check the commandline flags PACKAGE="$1" VERSION="$2" fullname="${PACKAGE}-${VERSION}" archive=../$fullname.tar.gz if [ -z "$1" -o -z "$2" ] then echo "Usage: $0 " 1>&2 exit 0 fi # Double-check we're in the packages directory, just under rootdir if [ \! -r ../Makefile -a \! -r ../INSTALL ] then echo "Must run $0 in the 'packages' directory, under the root directory." 1>&2 echo "Also, you must run \"make dist\" before running this script." 1>&2 exit 0 fi if [ \! -r "$archive" ] then echo "Cannot find $archive. Run \"make dist\" first." 1>&2 exit 0 fi # Create the directory where the input lives, and where the output should live RPM_SOURCE_DIR="/tmp/rpmsource-$fullname" RPM_BUILD_DIR="/tmp/rpmbuild-$fullname" trap 'rm -rf $RPM_SOURCE_DIR $RPM_BUILD_DIR; exit $?' EXIT SIGHUP SIGINT SIGTERM rm -rf "$RPM_SOURCE_DIR" "$RPM_BUILD_DIR" mkdir "$RPM_SOURCE_DIR" mkdir "$RPM_BUILD_DIR" cp "$archive" "$RPM_SOURCE_DIR" # rpmbuild -- as far as I can tell -- asks the OS what CPU it has. # This may differ from what kind of binaries gcc produces. dpkg # does a better job of this, so if we can run 'dpkg --print-architecture' # to get the build CPU, we use that in preference of the rpmbuild # default. target=`dpkg --print-architecture 2>/dev/null` # "" if dpkg isn't found if [ -n "$target" ] then target=" --target $target" fi rpmbuild -bb rpm/rpm.spec $target \ --define "NAME $PACKAGE" \ --define "VERSION $VERSION" \ --define "_sourcedir $RPM_SOURCE_DIR" \ --define "_builddir $RPM_BUILD_DIR" \ --define "_rpmdir $RPM_SOURCE_DIR" # We put the output in a directory based on what system we've built for destdir=rpm-unknown if [ -r /etc/issue ] then grep "Red Hat.*release 7" /etc/issue >/dev/null 2>&1 && destdir=rh7 grep "Red Hat.*release 8" /etc/issue >/dev/null 2>&1 && destdir=rh8 grep "Red Hat.*release 9" /etc/issue >/dev/null 2>&1 && destdir=rh9 grep "Fedora Core.*release 1" /etc/issue >/dev/null 2>&1 && destdir=fc1 grep "Fedora Core.*release 2" /etc/issue >/dev/null 2>&1 && destdir=fc2 grep "Fedora Core.*release 3" /etc/issue >/dev/null 2>&1 && destdir=fc3 fi rm -rf "$destdir" mkdir -p "$destdir" # We want to get not only the main package but devel etc, hence the middle * mv "$RPM_SOURCE_DIR"/*/"${PACKAGE}"-*"${VERSION}"*.rpm "$destdir" echo echo "The rpm package file(s) are located in $PWD/$destdir" ================================================ FILE: distro/google-perftools-1.7/src/addressmap-inl.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // A fast map from addresses to values. Assumes that addresses are // clustered. The main use is intended to be for heap-profiling. // May be too memory-hungry for other uses. // // We use a user-defined allocator/de-allocator so that we can use // this data structure during heap-profiling. // // IMPLEMENTATION DETAIL: // // Some default definitions/parameters: // * Block -- aligned 128-byte region of the address space // * Cluster -- aligned 1-MB region of the address space // * Block-ID -- block-number within a cluster // * Cluster-ID -- Starting address of cluster divided by cluster size // // We use a three-level map to represent the state: // 1. A hash-table maps from a cluster-ID to the data for that cluster. // 2. For each non-empty cluster we keep an array indexed by // block-ID tht points to the first entry in the linked-list // for the block. // 3. At the bottom, we keep a singly-linked list of all // entries in a block (for non-empty blocks). // // hash table // +-------------+ // | id->cluster |---> ... // | ... | // | id->cluster |---> Cluster // +-------------+ +-------+ Data for one block // | nil | +------------------------------------+ // | ----+---|->[addr/value]-->[addr/value]-->... | // | nil | +------------------------------------+ // | ----+--> ... // | nil | // | ... | // +-------+ // // Note that we require zero-bytes of overhead for completely empty // clusters. The minimum space requirement for a cluster is the size // of the hash-table entry plus a pointer value for each block in // the cluster. Empty blocks impose no extra space requirement. // // The cost of a lookup is: // a. A hash-table lookup to find the cluster // b. An array access in the cluster structure // c. A traversal over the linked-list for a block #ifndef BASE_ADDRESSMAP_INL_H_ #define BASE_ADDRESSMAP_INL_H_ #include "config.h" #include #include #if defined HAVE_STDINT_H #include // to get uint16_t (ISO naming madness) #elif defined HAVE_INTTYPES_H #include // another place uint16_t might be defined #else #include // our last best hope #endif // This class is thread-unsafe -- that is, instances of this class can // not be accessed concurrently by multiple threads -- because the // callback function for Iterate() may mutate contained values. If the // callback functions you pass do not mutate their Value* argument, // AddressMap can be treated as thread-compatible -- that is, it's // safe for multiple threads to call "const" methods on this class, // but not safe for one thread to call const methods on this class // while another thread is calling non-const methods on the class. template class AddressMap { public: typedef void* (*Allocator)(size_t size); typedef void (*DeAllocator)(void* ptr); typedef const void* Key; // Create an AddressMap that uses the specified allocator/deallocator. // The allocator/deallocator should behave like malloc/free. // For instance, the allocator does not need to return initialized memory. AddressMap(Allocator alloc, DeAllocator dealloc); ~AddressMap(); // If the map contains an entry for "key", return it. Else return NULL. inline const Value* Find(Key key) const; inline Value* FindMutable(Key key); // Insert into the map. Any old value associated // with key is forgotten. void Insert(Key key, Value value); // Remove any entry for key in the map. If an entry was found // and removed, stores the associated value in "*removed_value" // and returns true. Else returns false. bool FindAndRemove(Key key, Value* removed_value); // Similar to Find but we assume that keys are addresses of non-overlapping // memory ranges whose sizes are given by size_func. // If the map contains a range into which "key" points // (at its start or inside of it, but not at the end), // return the address of the associated value // and store its key in "*res_key". // Else return NULL. // max_size specifies largest range size possibly in existence now. typedef size_t (*ValueSizeFunc)(const Value& v); const Value* FindInside(ValueSizeFunc size_func, size_t max_size, Key key, Key* res_key); // Iterate over the address map calling 'callback' // for all stored key-value pairs and passing 'arg' to it. // We don't use full Closure/Callback machinery not to add // unnecessary dependencies to this class with low-level uses. template inline void Iterate(void (*callback)(Key, Value*, Type), Type arg) const; private: typedef uintptr_t Number; // The implementation assumes that addresses inserted into the map // will be clustered. We take advantage of this fact by splitting // up the address-space into blocks and using a linked-list entry // for each block. // Size of each block. There is one linked-list for each block, so // do not make the block-size too big. Oterwise, a lot of time // will be spent traversing linked lists. static const int kBlockBits = 7; static const int kBlockSize = 1 << kBlockBits; // Entry kept in per-block linked-list struct Entry { Entry* next; Key key; Value value; }; // We further group a sequence of consecutive blocks into a cluster. // The data for a cluster is represented as a dense array of // linked-lists, one list per contained block. static const int kClusterBits = 13; static const Number kClusterSize = 1 << (kBlockBits + kClusterBits); static const int kClusterBlocks = 1 << kClusterBits; // We use a simple chaining hash-table to represent the clusters. struct Cluster { Cluster* next; // Next cluster in hash table chain Number id; // Cluster ID Entry* blocks[kClusterBlocks]; // Per-block linked-lists }; // Number of hash-table entries. With the block-size/cluster-size // defined above, each cluster covers 1 MB, so an 4K entry // hash-table will give an average hash-chain length of 1 for 4GB of // in-use memory. static const int kHashBits = 12; static const int kHashSize = 1 << 12; // Number of entry objects allocated at a time static const int ALLOC_COUNT = 64; Cluster** hashtable_; // The hash-table Entry* free_; // Free list of unused Entry objects // Multiplicative hash function: // The value "kHashMultiplier" is the bottom 32 bits of // int((sqrt(5)-1)/2 * 2^32) // This is a good multiplier as suggested in CLR, Knuth. The hash // value is taken to be the top "k" bits of the bottom 32 bits // of the muliplied value. static const uint32_t kHashMultiplier = 2654435769u; static int HashInt(Number x) { // Multiply by a constant and take the top bits of the result. const uint32_t m = static_cast(x) * kHashMultiplier; return static_cast(m >> (32 - kHashBits)); } // Find cluster object for specified address. If not found // and "create" is true, create the object. If not found // and "create" is false, return NULL. // // This method is bitwise-const if create is false. Cluster* FindCluster(Number address, bool create) { // Look in hashtable const Number cluster_id = address >> (kBlockBits + kClusterBits); const int h = HashInt(cluster_id); for (Cluster* c = hashtable_[h]; c != NULL; c = c->next) { if (c->id == cluster_id) { return c; } } // Create cluster if necessary if (create) { Cluster* c = New(1); c->id = cluster_id; c->next = hashtable_[h]; hashtable_[h] = c; return c; } return NULL; } // Return the block ID for an address within its cluster static int BlockID(Number address) { return (address >> kBlockBits) & (kClusterBlocks - 1); } //-------------------------------------------------------------- // Memory management -- we keep all objects we allocate linked // together in a singly linked list so we can get rid of them // when we are all done. Furthermore, we allow the client to // pass in custom memory allocator/deallocator routines. //-------------------------------------------------------------- struct Object { Object* next; // The real data starts here }; Allocator alloc_; // The allocator DeAllocator dealloc_; // The deallocator Object* allocated_; // List of allocated objects // Allocates a zeroed array of T with length "num". Also inserts // the allocated block into a linked list so it can be deallocated // when we are all done. template T* New(int num) { void* ptr = (*alloc_)(sizeof(Object) + num*sizeof(T)); memset(ptr, 0, sizeof(Object) + num*sizeof(T)); Object* obj = reinterpret_cast(ptr); obj->next = allocated_; allocated_ = obj; return reinterpret_cast(reinterpret_cast(ptr) + 1); } }; // More implementation details follow: template AddressMap::AddressMap(Allocator alloc, DeAllocator dealloc) : free_(NULL), alloc_(alloc), dealloc_(dealloc), allocated_(NULL) { hashtable_ = New(kHashSize); } template AddressMap::~AddressMap() { // De-allocate all of the objects we allocated for (Object* obj = allocated_; obj != NULL; /**/) { Object* next = obj->next; (*dealloc_)(obj); obj = next; } } template inline const Value* AddressMap::Find(Key key) const { return const_cast(this)->FindMutable(key); } template inline Value* AddressMap::FindMutable(Key key) { const Number num = reinterpret_cast(key); const Cluster* const c = FindCluster(num, false/*do not create*/); if (c != NULL) { for (Entry* e = c->blocks[BlockID(num)]; e != NULL; e = e->next) { if (e->key == key) { return &e->value; } } } return NULL; } template void AddressMap::Insert(Key key, Value value) { const Number num = reinterpret_cast(key); Cluster* const c = FindCluster(num, true/*create*/); // Look in linked-list for this block const int block = BlockID(num); for (Entry* e = c->blocks[block]; e != NULL; e = e->next) { if (e->key == key) { e->value = value; return; } } // Create entry if (free_ == NULL) { // Allocate a new batch of entries and add to free-list Entry* array = New(ALLOC_COUNT); for (int i = 0; i < ALLOC_COUNT-1; i++) { array[i].next = &array[i+1]; } array[ALLOC_COUNT-1].next = free_; free_ = &array[0]; } Entry* e = free_; free_ = e->next; e->key = key; e->value = value; e->next = c->blocks[block]; c->blocks[block] = e; } template bool AddressMap::FindAndRemove(Key key, Value* removed_value) { const Number num = reinterpret_cast(key); Cluster* const c = FindCluster(num, false/*do not create*/); if (c != NULL) { for (Entry** p = &c->blocks[BlockID(num)]; *p != NULL; p = &(*p)->next) { Entry* e = *p; if (e->key == key) { *removed_value = e->value; *p = e->next; // Remove e from linked-list e->next = free_; // Add e to free-list free_ = e; return true; } } } return false; } template const Value* AddressMap::FindInside(ValueSizeFunc size_func, size_t max_size, Key key, Key* res_key) { const Number key_num = reinterpret_cast(key); Number num = key_num; // we'll move this to move back through the clusters while (1) { const Cluster* c = FindCluster(num, false/*do not create*/); if (c != NULL) { while (1) { const int block = BlockID(num); bool had_smaller_key = false; for (const Entry* e = c->blocks[block]; e != NULL; e = e->next) { const Number e_num = reinterpret_cast(e->key); if (e_num <= key_num) { if (e_num == key_num || // to handle 0-sized ranges key_num < e_num + (*size_func)(e->value)) { *res_key = e->key; return &e->value; } had_smaller_key = true; } } if (had_smaller_key) return NULL; // got a range before 'key' // and it did not contain 'key' if (block == 0) break; // try address-wise previous block num |= kBlockSize - 1; // start at the last addr of prev block num -= kBlockSize; if (key_num - num > max_size) return NULL; } } if (num < kClusterSize) return NULL; // first cluster // go to address-wise previous cluster to try num |= kClusterSize - 1; // start at the last block of previous cluster num -= kClusterSize; if (key_num - num > max_size) return NULL; // Having max_size to limit the search is crucial: else // we have to traverse a lot of empty clusters (or blocks). // We can avoid needing max_size if we put clusters into // a search tree, but performance suffers considerably // if we use this approach by using stl::set. } } template template inline void AddressMap::Iterate(void (*callback)(Key, Value*, Type), Type arg) const { // We could optimize this by traversing only non-empty clusters and/or blocks // but it does not speed up heap-checker noticeably. for (int h = 0; h < kHashSize; ++h) { for (const Cluster* c = hashtable_[h]; c != NULL; c = c->next) { for (int b = 0; b < kClusterBlocks; ++b) { for (Entry* e = c->blocks[b]; e != NULL; e = e->next) { callback(e->key, &e->value, arg); } } } } } #endif // BASE_ADDRESSMAP_INL_H_ ================================================ FILE: distro/google-perftools-1.7/src/base/atomicops-internals-arm-gcc.h ================================================ /* Copyright (c) 2010, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Lei Zhang, Sasha Levitskiy */ // This file is an internal atomic implementation, use base/atomicops.h instead. // // LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears. #ifndef BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_ #define BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_ #include #include "base/basictypes.h" // For COMPILE_ASSERT typedef int32_t Atomic32; namespace base { namespace subtle { typedef int64_t Atomic64; // 0xffff0fc0 is the hard coded address of a function provided by // the kernel which implements an atomic compare-exchange. On older // ARM architecture revisions (pre-v6) this may be implemented using // a syscall. This address is stable, and in active use (hard coded) // by at least glibc-2.7 and the Android C library. // pLinuxKernelCmpxchg has both acquire and release barrier sematincs. typedef Atomic32 (*LinuxKernelCmpxchgFunc)(Atomic32 old_value, Atomic32 new_value, volatile Atomic32* ptr); LinuxKernelCmpxchgFunc pLinuxKernelCmpxchg __attribute__((weak)) = (LinuxKernelCmpxchgFunc) 0xffff0fc0; typedef void (*LinuxKernelMemoryBarrierFunc)(void); LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) = (LinuxKernelMemoryBarrierFunc) 0xffff0fa0; inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, Atomic32 new_value) { Atomic32 prev_value = *ptr; do { if (!pLinuxKernelCmpxchg(old_value, new_value, const_cast(ptr))) { return old_value; } prev_value = *ptr; } while (prev_value == old_value); return prev_value; } inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value) { Atomic32 old_value; do { old_value = *ptr; } while (pLinuxKernelCmpxchg(old_value, new_value, const_cast(ptr))); return old_value; } inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment) { for (;;) { // Atomic exchange the old value with an incremented one. Atomic32 old_value = *ptr; Atomic32 new_value = old_value + increment; if (pLinuxKernelCmpxchg(old_value, new_value, const_cast(ptr)) == 0) { // The exchange took place as expected. return new_value; } // Otherwise, *ptr changed mid-loop and we need to retry. } } inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment) { return Barrier_AtomicIncrement(ptr, increment); } inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, Atomic32 new_value) { return NoBarrier_CompareAndSwap(ptr, old_value, new_value); } inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, Atomic32 new_value) { return NoBarrier_CompareAndSwap(ptr, old_value, new_value); } inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { *ptr = value; } inline void MemoryBarrier() { pLinuxKernelMemoryBarrier(); } inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { *ptr = value; MemoryBarrier(); } inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { MemoryBarrier(); *ptr = value; } inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { return *ptr; } inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { Atomic32 value = *ptr; MemoryBarrier(); return value; } inline Atomic32 Release_Load(volatile const Atomic32* ptr) { MemoryBarrier(); return *ptr; } // 64-bit versions are not implemented yet. inline void NotImplementedFatalError(const char *function_name) { fprintf(stderr, "64-bit %s() not implemented on this platform\n", function_name); abort(); } inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, Atomic64 new_value) { NotImplementedFatalError("NoBarrier_CompareAndSwap"); return 0; } inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value) { NotImplementedFatalError("NoBarrier_AtomicExchange"); return 0; } inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment) { NotImplementedFatalError("NoBarrier_AtomicIncrement"); return 0; } inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment) { NotImplementedFatalError("Barrier_AtomicIncrement"); return 0; } inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { NotImplementedFatalError("NoBarrier_Store"); } inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) { NoBarrier_AtomicExchange(ptr, value); // acts as a barrier in this implementation } inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) { NotImplementedFatalError("Release_Store"); } inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { NotImplementedFatalError("NoBarrier_Load"); return 0; } inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) { Atomic64 value = NoBarrier_Load(ptr); return value; } inline Atomic64 Release_Load(volatile const Atomic64* ptr) { MemoryBarrier(); return NoBarrier_Load(ptr); } inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, Atomic64 new_value) { return NoBarrier_CompareAndSwap(ptr, old_value, new_value); } inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, Atomic64 new_value) { return NoBarrier_CompareAndSwap(ptr, old_value, new_value); } } // namespace base::subtle } // namespace base #endif // BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_ ================================================ FILE: distro/google-perftools-1.7/src/base/atomicops-internals-linuxppc.h ================================================ /* Copyright (c) 2008, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- */ // Implementation of atomic operations for ppc-linux. This file should not // be included directly. Clients should instead include // "base/atomicops.h". #ifndef BASE_ATOMICOPS_INTERNALS_LINUXPPC_H_ #define BASE_ATOMICOPS_INTERNALS_LINUXPPC_H_ typedef int32_t Atomic32; #ifdef __PPC64__ #define BASE_HAS_ATOMIC64 1 #endif namespace base { namespace subtle { static inline void _sync(void) { __asm__ __volatile__("sync": : : "memory"); } static inline void _lwsync(void) { // gcc defines __NO_LWSYNC__ when appropriate; see // http://gcc.gnu.org/ml/gcc-patches/2006-11/msg01238.html #ifdef __NO_LWSYNC__ __asm__ __volatile__("msync": : : "memory"); #else __asm__ __volatile__("lwsync": : : "memory"); #endif } static inline void _isync(void) { __asm__ __volatile__("isync": : : "memory"); } static inline Atomic32 OSAtomicAdd32(Atomic32 amount, Atomic32 *value) { Atomic32 t; __asm__ __volatile__( "1: lwarx %0,0,%3\n\ add %0,%2,%0\n\ stwcx. %0,0,%3 \n\ bne- 1b" : "=&r" (t), "+m" (*value) : "r" (amount), "r" (value) : "cc"); return t; } static inline Atomic32 OSAtomicAdd32Barrier(Atomic32 amount, Atomic32 *value) { Atomic32 t; _lwsync(); t = OSAtomicAdd32(amount, value); // This is based on the code snippet in the architecture manual (Vol // 2, Appendix B). It's a little tricky: correctness depends on the // fact that the code right before this (in OSAtomicAdd32) has a // conditional branch with a data dependency on the update. // Otherwise, we'd have to use sync. _isync(); return t; } static inline bool OSAtomicCompareAndSwap32(Atomic32 old_value, Atomic32 new_value, Atomic32 *value) { Atomic32 prev; __asm__ __volatile__( "1: lwarx %0,0,%2\n\ cmpw 0,%0,%3\n\ bne- 2f\n\ stwcx. %4,0,%2\n\ bne- 1b\n\ 2:" : "=&r" (prev), "+m" (*value) : "r" (value), "r" (old_value), "r" (new_value) : "cc"); return prev == old_value; } static inline Atomic32 OSAtomicCompareAndSwap32Acquire(Atomic32 old_value, Atomic32 new_value, Atomic32 *value) { Atomic32 t; t = OSAtomicCompareAndSwap32(old_value, new_value, value); // This is based on the code snippet in the architecture manual (Vol // 2, Appendix B). It's a little tricky: correctness depends on the // fact that the code right before this (in // OSAtomicCompareAndSwap32) has a conditional branch with a data // dependency on the update. Otherwise, we'd have to use sync. _isync(); return t; } static inline Atomic32 OSAtomicCompareAndSwap32Release(Atomic32 old_value, Atomic32 new_value, Atomic32 *value) { _lwsync(); return OSAtomicCompareAndSwap32(old_value, new_value, value); } typedef int64_t Atomic64; inline void MemoryBarrier() { // This can't be _lwsync(); we need to order the immediately // preceding stores against any load that may follow, but lwsync // doesn't guarantee that. _sync(); } // 32-bit Versions. inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr, Atomic32 old_value, Atomic32 new_value) { Atomic32 prev_value; do { if (OSAtomicCompareAndSwap32(old_value, new_value, const_cast(ptr))) { return old_value; } prev_value = *ptr; } while (prev_value == old_value); return prev_value; } inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr, Atomic32 new_value) { Atomic32 old_value; do { old_value = *ptr; } while (!OSAtomicCompareAndSwap32(old_value, new_value, const_cast(ptr))); return old_value; } inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr, Atomic32 increment) { return OSAtomicAdd32(increment, const_cast(ptr)); } inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr, Atomic32 increment) { return OSAtomicAdd32Barrier(increment, const_cast(ptr)); } inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr, Atomic32 old_value, Atomic32 new_value) { Atomic32 prev_value; do { if (OSAtomicCompareAndSwap32Acquire(old_value, new_value, const_cast(ptr))) { return old_value; } prev_value = *ptr; } while (prev_value == old_value); return prev_value; } inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr, Atomic32 old_value, Atomic32 new_value) { Atomic32 prev_value; do { if (OSAtomicCompareAndSwap32Release(old_value, new_value, const_cast(ptr))) { return old_value; } prev_value = *ptr; } while (prev_value == old_value); return prev_value; } #ifdef __PPC64__ // 64-bit Versions. static inline Atomic64 OSAtomicAdd64(Atomic64 amount, Atomic64 *value) { Atomic64 t; __asm__ __volatile__( "1: ldarx %0,0,%3\n\ add %0,%2,%0\n\ stdcx. %0,0,%3 \n\ bne- 1b" : "=&r" (t), "+m" (*value) : "r" (amount), "r" (value) : "cc"); return t; } static inline Atomic64 OSAtomicAdd64Barrier(Atomic64 amount, Atomic64 *value) { Atomic64 t; _lwsync(); t = OSAtomicAdd64(amount, value); // This is based on the code snippet in the architecture manual (Vol // 2, Appendix B). It's a little tricky: correctness depends on the // fact that the code right before this (in OSAtomicAdd64) has a // conditional branch with a data dependency on the update. // Otherwise, we'd have to use sync. _isync(); return t; } static inline bool OSAtomicCompareAndSwap64(Atomic64 old_value, Atomic64 new_value, Atomic64 *value) { Atomic64 prev; __asm__ __volatile__( "1: ldarx %0,0,%2\n\ cmpw 0,%0,%3\n\ bne- 2f\n\ stdcx. %4,0,%2\n\ bne- 1b\n\ 2:" : "=&r" (prev), "+m" (*value) : "r" (value), "r" (old_value), "r" (new_value) : "cc"); return prev == old_value; } static inline Atomic64 OSAtomicCompareAndSwap64Acquire(Atomic64 old_value, Atomic64 new_value, Atomic64 *value) { Atomic64 t; t = OSAtomicCompareAndSwap64(old_value, new_value, value); // This is based on the code snippet in the architecture manual (Vol // 2, Appendix B). It's a little tricky: correctness depends on the // fact that the code right before this (in // OSAtomicCompareAndSwap64) has a conditional branch with a data // dependency on the update. Otherwise, we'd have to use sync. _isync(); return t; } static inline Atomic64 OSAtomicCompareAndSwap64Release(Atomic64 old_value, Atomic64 new_value, Atomic64 *value) { _lwsync(); return OSAtomicCompareAndSwap64(old_value, new_value, value); } inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr, Atomic64 old_value, Atomic64 new_value) { Atomic64 prev_value; do { if (OSAtomicCompareAndSwap64(old_value, new_value, const_cast(ptr))) { return old_value; } prev_value = *ptr; } while (prev_value == old_value); return prev_value; } inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr, Atomic64 new_value) { Atomic64 old_value; do { old_value = *ptr; } while (!OSAtomicCompareAndSwap64(old_value, new_value, const_cast(ptr))); return old_value; } inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr, Atomic64 increment) { return OSAtomicAdd64(increment, const_cast(ptr)); } inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr, Atomic64 increment) { return OSAtomicAdd64Barrier(increment, const_cast(ptr)); } inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr, Atomic64 old_value, Atomic64 new_value) { Atomic64 prev_value; do { if (OSAtomicCompareAndSwap64Acquire(old_value, new_value, const_cast(ptr))) { return old_value; } prev_value = *ptr; } while (prev_value == old_value); return prev_value; } inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr, Atomic64 old_value, Atomic64 new_value) { Atomic64 prev_value; do { if (OSAtomicCompareAndSwap64Release(old_value, new_value, const_cast(ptr))) { return old_value; } prev_value = *ptr; } while (prev_value == old_value); return prev_value; } #endif inline void NoBarrier_Store(volatile Atomic32 *ptr, Atomic32 value) { *ptr = value; } inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) { *ptr = value; // This can't be _lwsync(); we need to order the immediately // preceding stores against any load that may follow, but lwsync // doesn't guarantee that. _sync(); } inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) { _lwsync(); *ptr = value; } inline Atomic32 NoBarrier_Load(volatile const Atomic32 *ptr) { return *ptr; } inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) { Atomic32 value = *ptr; _lwsync(); return value; } inline Atomic32 Release_Load(volatile const Atomic32 *ptr) { // This can't be _lwsync(); we need to order the immediately // preceding stores against any load that may follow, but lwsync // doesn't guarantee that. _sync(); return *ptr; } #ifdef __PPC64__ // 64-bit Versions. inline void NoBarrier_Store(volatile Atomic64 *ptr, Atomic64 value) { *ptr = value; } inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) { *ptr = value; // This can't be _lwsync(); we need to order the immediately // preceding stores against any load that may follow, but lwsync // doesn't guarantee that. _sync(); } inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) { _lwsync(); *ptr = value; } inline Atomic64 NoBarrier_Load(volatile const Atomic64 *ptr) { return *ptr; } inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) { Atomic64 value = *ptr; _lwsync(); return value; } inline Atomic64 Release_Load(volatile const Atomic64 *ptr) { // This can't be _lwsync(); we need to order the immediately // preceding stores against any load that may follow, but lwsync // doesn't guarantee that. _sync(); return *ptr; } #endif } // namespace base::subtle } // namespace base #endif // BASE_ATOMICOPS_INTERNALS_LINUXPPC_H_ ================================================ FILE: distro/google-perftools-1.7/src/base/atomicops-internals-macosx.h ================================================ /* Copyright (c) 2006, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Implementation of atomic operations for Mac OS X. This file should not // be included directly. Clients should instead include // "base/atomicops.h". #ifndef BASE_ATOMICOPS_INTERNALS_MACOSX_H_ #define BASE_ATOMICOPS_INTERNALS_MACOSX_H_ typedef int32_t Atomic32; // MacOS uses long for intptr_t, AtomicWord and Atomic32 are always different // on the Mac, even when they are the same size. Similarly, on __ppc64__, // AtomicWord and Atomic64 are always different. Thus, we need explicit // casting. #ifdef __LP64__ #define AtomicWordCastType base::subtle::Atomic64 #else #define AtomicWordCastType Atomic32 #endif #if defined(__LP64__) || defined(__i386__) #define BASE_HAS_ATOMIC64 1 // Use only in tests and base/atomic* #endif #include namespace base { namespace subtle { #if !defined(__LP64__) && defined(__ppc__) // The Mac 64-bit OSAtomic implementations are not available for 32-bit PowerPC, // while the underlying assembly instructions are available only some // implementations of PowerPC. // The following inline functions will fail with the error message at compile // time ONLY IF they are called. So it is safe to use this header if user // code only calls AtomicWord and Atomic32 operations. // // NOTE(vchen): Implementation notes to implement the atomic ops below may // be found in "PowerPC Virtual Environment Architecture, Book II, // Version 2.02", January 28, 2005, Appendix B, page 46. Unfortunately, // extra care must be taken to ensure data are properly 8-byte aligned, and // that data are returned correctly according to Mac OS X ABI specs. inline int64_t OSAtomicCompareAndSwap64( int64_t oldValue, int64_t newValue, int64_t *theValue) { __asm__ __volatile__( "_OSAtomicCompareAndSwap64_not_supported_for_32_bit_ppc\n\t"); return 0; } inline int64_t OSAtomicAdd64(int64_t theAmount, int64_t *theValue) { __asm__ __volatile__( "_OSAtomicAdd64_not_supported_for_32_bit_ppc\n\t"); return 0; } inline int64_t OSAtomicCompareAndSwap64Barrier( int64_t oldValue, int64_t newValue, int64_t *theValue) { int64_t prev = OSAtomicCompareAndSwap64(oldValue, newValue, theValue); OSMemoryBarrier(); return prev; } inline int64_t OSAtomicAdd64Barrier( int64_t theAmount, int64_t *theValue) { int64_t new_val = OSAtomicAdd64(theAmount, theValue); OSMemoryBarrier(); return new_val; } #endif typedef int64_t Atomic64; inline void MemoryBarrier() { OSMemoryBarrier(); } // 32-bit Versions. inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr, Atomic32 old_value, Atomic32 new_value) { Atomic32 prev_value; do { if (OSAtomicCompareAndSwap32(old_value, new_value, const_cast(ptr))) { return old_value; } prev_value = *ptr; } while (prev_value == old_value); return prev_value; } inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr, Atomic32 new_value) { Atomic32 old_value; do { old_value = *ptr; } while (!OSAtomicCompareAndSwap32(old_value, new_value, const_cast(ptr))); return old_value; } inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr, Atomic32 increment) { return OSAtomicAdd32(increment, const_cast(ptr)); } inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr, Atomic32 increment) { return OSAtomicAdd32Barrier(increment, const_cast(ptr)); } inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr, Atomic32 old_value, Atomic32 new_value) { Atomic32 prev_value; do { if (OSAtomicCompareAndSwap32Barrier(old_value, new_value, const_cast(ptr))) { return old_value; } prev_value = *ptr; } while (prev_value == old_value); return prev_value; } inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr, Atomic32 old_value, Atomic32 new_value) { return Acquire_CompareAndSwap(ptr, old_value, new_value); } inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { *ptr = value; } inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) { *ptr = value; MemoryBarrier(); } inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) { MemoryBarrier(); *ptr = value; } inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { return *ptr; } inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) { Atomic32 value = *ptr; MemoryBarrier(); return value; } inline Atomic32 Release_Load(volatile const Atomic32 *ptr) { MemoryBarrier(); return *ptr; } // 64-bit version inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr, Atomic64 old_value, Atomic64 new_value) { Atomic64 prev_value; do { if (OSAtomicCompareAndSwap64(old_value, new_value, const_cast(ptr))) { return old_value; } prev_value = *ptr; } while (prev_value == old_value); return prev_value; } inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr, Atomic64 new_value) { Atomic64 old_value; do { old_value = *ptr; } while (!OSAtomicCompareAndSwap64(old_value, new_value, const_cast(ptr))); return old_value; } inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr, Atomic64 increment) { return OSAtomicAdd64(increment, const_cast(ptr)); } inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr, Atomic64 increment) { return OSAtomicAdd64Barrier(increment, const_cast(ptr)); } inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr, Atomic64 old_value, Atomic64 new_value) { Atomic64 prev_value; do { if (OSAtomicCompareAndSwap64Barrier(old_value, new_value, const_cast(ptr))) { return old_value; } prev_value = *ptr; } while (prev_value == old_value); return prev_value; } inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr, Atomic64 old_value, Atomic64 new_value) { // The lib kern interface does not distinguish between // Acquire and Release memory barriers; they are equivalent. return Acquire_CompareAndSwap(ptr, old_value, new_value); } #ifdef __LP64__ // 64-bit implementation on 64-bit platform inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { *ptr = value; } inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) { *ptr = value; MemoryBarrier(); } inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) { MemoryBarrier(); *ptr = value; } inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { return *ptr; } inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) { Atomic64 value = *ptr; MemoryBarrier(); return value; } inline Atomic64 Release_Load(volatile const Atomic64 *ptr) { MemoryBarrier(); return *ptr; } #else // 64-bit implementation on 32-bit platform #if defined(__ppc__) inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { __asm__ __volatile__( "_NoBarrier_Store_not_supported_for_32_bit_ppc\n\t"); } inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { __asm__ __volatile__( "_NoBarrier_Load_not_supported_for_32_bit_ppc\n\t"); return 0; } #elif defined(__i386__) inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { __asm__ __volatile__("movq %1, %%mm0\n\t" // Use mmx reg for 64-bit atomic "movq %%mm0, %0\n\t" // moves (ptr could be read-only) "emms\n\t" // Reset FP registers : "=m" (*ptr) : "m" (value) : // mark the FP stack and mmx registers as clobbered "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7"); } inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { Atomic64 value; __asm__ __volatile__("movq %1, %%mm0\n\t" // Use mmx reg for 64-bit atomic "movq %%mm0, %0\n\t" // moves (ptr could be read-only) "emms\n\t" // Reset FP registers : "=m" (value) : "m" (*ptr) : // mark the FP stack and mmx registers as clobbered "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7"); return value; } #endif inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) { NoBarrier_Store(ptr, value); MemoryBarrier(); } inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) { MemoryBarrier(); NoBarrier_Store(ptr, value); } inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) { Atomic64 value = NoBarrier_Load(ptr); MemoryBarrier(); return value; } inline Atomic64 Release_Load(volatile const Atomic64 *ptr) { MemoryBarrier(); return NoBarrier_Load(ptr); } #endif // __LP64__ } // namespace base::subtle } // namespace base #endif // BASE_ATOMICOPS_INTERNALS_MACOSX_H_ ================================================ FILE: distro/google-perftools-1.7/src/base/atomicops-internals-x86-msvc.h ================================================ /* Copyright (c) 2006, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Sanjay Ghemawat */ // Implementation of atomic operations for x86. This file should not // be included directly. Clients should instead include // "base/atomicops.h". #ifndef BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_ #define BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_ #include #include #include "base/basictypes.h" // For COMPILE_ASSERT typedef int32 Atomic32; #if defined(_WIN64) #define BASE_HAS_ATOMIC64 1 // Use only in tests and base/atomic* #endif namespace base { namespace subtle { typedef int64 Atomic64; // 32-bit low-level operations on any platform // MinGW has a bug in the header files where it doesn't indicate the // first argument is volatile -- they're not up to date. See // http://readlist.com/lists/lists.sourceforge.net/mingw-users/0/3861.html // We have to const_cast away the volatile to avoid compiler warnings. // TODO(csilvers): remove this once MinGW has updated MinGW/include/winbase.h #ifdef __MINGW32__ inline LONG InterlockedCompareExchange(volatile LONG* ptr, LONG newval, LONG oldval) { return ::InterlockedCompareExchange(const_cast(ptr), newval, oldval); } inline LONG InterlockedExchange(volatile LONG* ptr, LONG newval) { return ::InterlockedExchange(const_cast(ptr), newval); } inline LONG InterlockedExchangeAdd(volatile LONG* ptr, LONG increment) { return ::InterlockedExchangeAdd(const_cast(ptr), increment); } #endif // ifdef __MINGW32__ inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, Atomic32 new_value) { LONG result = InterlockedCompareExchange( reinterpret_cast(ptr), static_cast(new_value), static_cast(old_value)); return static_cast(result); } inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value) { LONG result = InterlockedExchange( reinterpret_cast(ptr), static_cast(new_value)); return static_cast(result); } inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment) { return InterlockedExchangeAdd( reinterpret_cast(ptr), static_cast(increment)) + increment; } inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment) { return Barrier_AtomicIncrement(ptr, increment); } } // namespace base::subtle } // namespace base // In msvc8/vs2005, winnt.h already contains a definition for // MemoryBarrier in the global namespace. Add it there for earlier // versions and forward to it from within the namespace. #if !(defined(_MSC_VER) && _MSC_VER >= 1400) inline void MemoryBarrier() { Atomic32 value = 0; base::subtle::NoBarrier_AtomicExchange(&value, 0); // actually acts as a barrier in thisd implementation } #endif namespace base { namespace subtle { inline void MemoryBarrier() { ::MemoryBarrier(); } inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, Atomic32 new_value) { return NoBarrier_CompareAndSwap(ptr, old_value, new_value); } inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, Atomic32 new_value) { return NoBarrier_CompareAndSwap(ptr, old_value, new_value); } inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { *ptr = value; } inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { NoBarrier_AtomicExchange(ptr, value); // acts as a barrier in this implementation } inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { *ptr = value; // works w/o barrier for current Intel chips as of June 2005 // See comments in Atomic64 version of Release_Store() below. } inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { return *ptr; } inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { Atomic32 value = *ptr; return value; } inline Atomic32 Release_Load(volatile const Atomic32* ptr) { MemoryBarrier(); return *ptr; } // 64-bit operations #if defined(_WIN64) || defined(__MINGW64__) // 64-bit low-level operations on 64-bit platform. COMPILE_ASSERT(sizeof(Atomic64) == sizeof(PVOID), atomic_word_is_atomic); // Like for the __MINGW32__ case above, this works around a header // error in mingw, where it's missing 'volatile'. #ifdef __MINGW64__ inline PVOID InterlockedCompareExchangePointer(volatile PVOID* ptr, PVOID newval, PVOID oldval) { return ::InterlockedCompareExchangePointer(const_cast(ptr), newval, oldval); } inline PVOID InterlockedExchangePointer(volatile PVOID* ptr, PVOID newval) { return ::InterlockedExchangePointer(const_cast(ptr), newval); } inline LONGLONG InterlockedExchangeAdd64(volatile LONGLONG* ptr, LONGLONG increment) { return ::InterlockedExchangeAdd64(const_cast(ptr), increment); } #endif // ifdef __MINGW64__ inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, Atomic64 new_value) { PVOID result = InterlockedCompareExchangePointer( reinterpret_cast(ptr), reinterpret_cast(new_value), reinterpret_cast(old_value)); return reinterpret_cast(result); } inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value) { PVOID result = InterlockedExchangePointer( reinterpret_cast(ptr), reinterpret_cast(new_value)); return reinterpret_cast(result); } inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment) { return InterlockedExchangeAdd64( reinterpret_cast(ptr), static_cast(increment)) + increment; } inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment) { return Barrier_AtomicIncrement(ptr, increment); } inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { *ptr = value; } inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) { NoBarrier_AtomicExchange(ptr, value); // acts as a barrier in this implementation } inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) { *ptr = value; // works w/o barrier for current Intel chips as of June 2005 // When new chips come out, check: // IA-32 Intel Architecture Software Developer's Manual, Volume 3: // System Programming Guide, Chatper 7: Multiple-processor management, // Section 7.2, Memory Ordering. // Last seen at: // http://developer.intel.com/design/pentium4/manuals/index_new.htm } inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { return *ptr; } inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) { Atomic64 value = *ptr; return value; } inline Atomic64 Release_Load(volatile const Atomic64* ptr) { MemoryBarrier(); return *ptr; } #else // defined(_WIN64) || defined(__MINGW64__) // 64-bit low-level operations on 32-bit platform // TBD(vchen): The GNU assembly below must be converted to MSVC inline // assembly. inline void NotImplementedFatalError(const char *function_name) { fprintf(stderr, "64-bit %s() not implemented on this platform\n", function_name); abort(); } inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, Atomic64 new_value) { #if 0 // Not implemented Atomic64 prev; __asm__ __volatile__("movl (%3), %%ebx\n\t" // Move 64-bit new_value into "movl 4(%3), %%ecx\n\t" // ecx:ebx "lock; cmpxchg8b %1\n\t" // If edx:eax (old_value) same : "=A" (prev) // as contents of ptr: : "m" (*ptr), // ecx:ebx => ptr "0" (old_value), // else: "r" (&new_value) // old *ptr => edx:eax : "memory", "%ebx", "%ecx"); return prev; #else NotImplementedFatalError("NoBarrier_CompareAndSwap"); return 0; #endif } inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value) { #if 0 // Not implemented __asm__ __volatile__( "movl (%2), %%ebx\n\t" // Move 64-bit new_value into "movl 4(%2), %%ecx\n\t" // ecx:ebx "0:\n\t" "movl %1, %%eax\n\t" // Read contents of ptr into "movl 4%1, %%edx\n\t" // edx:eax "lock; cmpxchg8b %1\n\t" // Attempt cmpxchg; if *ptr "jnz 0b\n\t" // is no longer edx:eax, loop : "=A" (new_value) : "m" (*ptr), "r" (&new_value) : "memory", "%ebx", "%ecx"); return new_value; // Now it's the previous value. #else NotImplementedFatalError("NoBarrier_AtomicExchange"); return 0; #endif } inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment) { #if 0 // Not implemented Atomic64 temp = increment; __asm__ __volatile__( "0:\n\t" "movl (%3), %%ebx\n\t" // Move 64-bit increment into "movl 4(%3), %%ecx\n\t" // ecx:ebx "movl (%2), %%eax\n\t" // Read contents of ptr into "movl 4(%2), %%edx\n\t" // edx:eax "add %%eax, %%ebx\n\t" // sum => ecx:ebx "adc %%edx, %%ecx\n\t" // edx:eax still has old *ptr "lock; cmpxchg8b (%2)\n\t"// Attempt cmpxchg; if *ptr "jnz 0b\n\t" // is no longer edx:eax, loop : "=A"(temp), "+m"(*ptr) : "D" (ptr), "S" (&increment) : "memory", "%ebx", "%ecx"); // temp now contains the previous value of *ptr return temp + increment; #else NotImplementedFatalError("NoBarrier_AtomicIncrement"); return 0; #endif } inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment) { #if 0 // Not implemented Atomic64 new_val = NoBarrier_AtomicIncrement(ptr, increment); if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { __asm__ __volatile__("lfence" : : : "memory"); } return new_val; #else NotImplementedFatalError("Barrier_AtomicIncrement"); return 0; #endif } inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { #if 0 // Not implemented __asm { mov mm0, value; // Use mmx reg for 64-bit atomic moves mov ptr, mm0; emms; // Empty mmx state to enable FP registers } #else NotImplementedFatalError("NoBarrier_Store"); #endif } inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) { NoBarrier_AtomicExchange(ptr, value); // acts as a barrier in this implementation } inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) { NoBarrier_Store(ptr, value); } inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { #if 0 // Not implemented Atomic64 value; __asm { mov mm0, ptr; // Use mmx reg for 64-bit atomic moves mov value, mm0; emms; // Empty mmx state to enable FP registers } return value; #else NotImplementedFatalError("NoBarrier_Store"); return 0; #endif } inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) { Atomic64 value = NoBarrier_Load(ptr); return value; } inline Atomic64 Release_Load(volatile const Atomic64* ptr) { MemoryBarrier(); return NoBarrier_Load(ptr); } #endif // defined(_WIN64) || defined(__MINGW64__) inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, Atomic64 new_value) { return NoBarrier_CompareAndSwap(ptr, old_value, new_value); } inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, Atomic64 new_value) { return NoBarrier_CompareAndSwap(ptr, old_value, new_value); } } // namespace base::subtle } // namespace base #endif // BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_ ================================================ FILE: distro/google-perftools-1.7/src/base/atomicops-internals-x86.cc ================================================ /* Copyright (c) 2007, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * This module gets enough CPU information to optimize the * atomicops module on x86. */ #include "base/atomicops.h" #include "base/basictypes.h" #include "base/googleinit.h" #include "base/logging.h" #include // This file only makes sense with atomicops-internals-x86.h -- it // depends on structs that are defined in that file. If atomicops.h // doesn't sub-include that file, then we aren't needed, and shouldn't // try to do anything. #ifdef BASE_ATOMICOPS_INTERNALS_X86_H_ // Inline cpuid instruction. In PIC compilations, %ebx contains the address // of the global offset table. To avoid breaking such executables, this code // must preserve that register's value across cpuid instructions. #if defined(__i386__) #define cpuid(a, b, c, d, inp) \ asm ("mov %%ebx, %%edi\n" \ "cpuid\n" \ "xchg %%edi, %%ebx\n" \ : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp)) #elif defined (__x86_64__) #define cpuid(a, b, c, d, inp) \ asm ("mov %%rbx, %%rdi\n" \ "cpuid\n" \ "xchg %%rdi, %%rbx\n" \ : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp)) #endif #if defined(cpuid) // initialize the struct only on x86 // Set the flags so that code will run correctly and conservatively // until InitGoogle() is called. struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures = { false, // bug can't exist before process spawns multiple threads false, // no SSE2 false, // no cmpxchg16b }; // Initialize the AtomicOps_Internalx86CPUFeatures struct. static void AtomicOps_Internalx86CPUFeaturesInit() { uint32 eax; uint32 ebx; uint32 ecx; uint32 edx; // Get vendor string (issue CPUID with eax = 0) cpuid(eax, ebx, ecx, edx, 0); char vendor[13]; memcpy(vendor, &ebx, 4); memcpy(vendor + 4, &edx, 4); memcpy(vendor + 8, &ecx, 4); vendor[12] = 0; // get feature flags in ecx/edx, and family/model in eax cpuid(eax, ebx, ecx, edx, 1); int family = (eax >> 8) & 0xf; // family and model fields int model = (eax >> 4) & 0xf; if (family == 0xf) { // use extended family and model fields family += (eax >> 20) & 0xff; model += ((eax >> 16) & 0xf) << 4; } // Opteron Rev E has a bug in which on very rare occasions a locked // instruction doesn't act as a read-acquire barrier if followed by a // non-locked read-modify-write instruction. Rev F has this bug in // pre-release versions, but not in versions released to customers, // so we test only for Rev E, which is family 15, model 32..63 inclusive. if (strcmp(vendor, "AuthenticAMD") == 0 && // AMD family == 15 && 32 <= model && model <= 63) { AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = true; } else { AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = false; } // edx bit 26 is SSE2 which we use to tell use whether we can use mfence AtomicOps_Internalx86CPUFeatures.has_sse2 = ((edx >> 26) & 1); // ecx bit 13 indicates whether the cmpxchg16b instruction is supported AtomicOps_Internalx86CPUFeatures.has_cmpxchg16b = ((ecx >> 13) & 1); } REGISTER_MODULE_INITIALIZER(atomicops_x86, { AtomicOps_Internalx86CPUFeaturesInit(); }); #endif #endif /* ifdef BASE_ATOMICOPS_INTERNALS_X86_H_ */ ================================================ FILE: distro/google-perftools-1.7/src/base/atomicops-internals-x86.h ================================================ /* Copyright (c) 2006, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Sanjay Ghemawat */ // Implementation of atomic operations for x86. This file should not // be included directly. Clients should instead include // "base/atomicops.h". #ifndef BASE_ATOMICOPS_INTERNALS_X86_H_ #define BASE_ATOMICOPS_INTERNALS_X86_H_ typedef int32_t Atomic32; #define BASE_HAS_ATOMIC64 1 // Use only in tests and base/atomic* // NOTE(vchen): x86 does not need to define AtomicWordCastType, because it // already matches Atomic32 or Atomic64, depending on the platform. // This struct is not part of the public API of this module; clients may not // use it. // Features of this x86. Values may not be correct before main() is run, // but are set conservatively. struct AtomicOps_x86CPUFeatureStruct { bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence // after acquire compare-and-swap. bool has_sse2; // Processor has SSE2. bool has_cmpxchg16b; // Processor supports cmpxchg16b instruction. }; extern struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures; #define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory") namespace base { namespace subtle { typedef int64_t Atomic64; // 32-bit low-level operations on any platform. inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, Atomic32 new_value) { Atomic32 prev; __asm__ __volatile__("lock; cmpxchgl %1,%2" : "=a" (prev) : "q" (new_value), "m" (*ptr), "0" (old_value) : "memory"); return prev; } inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value) { __asm__ __volatile__("xchgl %1,%0" // The lock prefix is implicit for xchg. : "=r" (new_value) : "m" (*ptr), "0" (new_value) : "memory"); return new_value; // Now it's the previous value. } inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment) { Atomic32 temp = increment; __asm__ __volatile__("lock; xaddl %0,%1" : "+r" (temp), "+m" (*ptr) : : "memory"); // temp now holds the old value of *ptr return temp + increment; } inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment) { Atomic32 temp = increment; __asm__ __volatile__("lock; xaddl %0,%1" : "+r" (temp), "+m" (*ptr) : : "memory"); // temp now holds the old value of *ptr if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { __asm__ __volatile__("lfence" : : : "memory"); } return temp + increment; } inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, Atomic32 new_value) { Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value); if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { __asm__ __volatile__("lfence" : : : "memory"); } return x; } inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, Atomic32 new_value) { return NoBarrier_CompareAndSwap(ptr, old_value, new_value); } inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { *ptr = value; } #if defined(__x86_64__) // 64-bit implementations of memory barrier can be simpler, because it // "mfence" is guaranteed to exist. inline void MemoryBarrier() { __asm__ __volatile__("mfence" : : : "memory"); } inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { *ptr = value; MemoryBarrier(); } #else inline void MemoryBarrier() { if (AtomicOps_Internalx86CPUFeatures.has_sse2) { __asm__ __volatile__("mfence" : : : "memory"); } else { // mfence is faster but not present on PIII Atomic32 x = 0; NoBarrier_AtomicExchange(&x, 0); // acts as a barrier on PIII } } inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { if (AtomicOps_Internalx86CPUFeatures.has_sse2) { *ptr = value; __asm__ __volatile__("mfence" : : : "memory"); } else { NoBarrier_AtomicExchange(ptr, value); // acts as a barrier on PIII } } #endif inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { ATOMICOPS_COMPILER_BARRIER(); *ptr = value; // An x86 store acts as a release barrier. // See comments in Atomic64 version of Release_Store(), below. } inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { return *ptr; } inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { Atomic32 value = *ptr; // An x86 load acts as a acquire barrier. // See comments in Atomic64 version of Release_Store(), below. ATOMICOPS_COMPILER_BARRIER(); return value; } inline Atomic32 Release_Load(volatile const Atomic32* ptr) { MemoryBarrier(); return *ptr; } #if defined(__x86_64__) // 64-bit low-level operations on 64-bit platform. inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, Atomic64 new_value) { Atomic64 prev; __asm__ __volatile__("lock; cmpxchgq %1,%2" : "=a" (prev) : "q" (new_value), "m" (*ptr), "0" (old_value) : "memory"); return prev; } inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value) { __asm__ __volatile__("xchgq %1,%0" // The lock prefix is implicit for xchg. : "=r" (new_value) : "m" (*ptr), "0" (new_value) : "memory"); return new_value; // Now it's the previous value. } inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment) { Atomic64 temp = increment; __asm__ __volatile__("lock; xaddq %0,%1" : "+r" (temp), "+m" (*ptr) : : "memory"); // temp now contains the previous value of *ptr return temp + increment; } inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment) { Atomic64 temp = increment; __asm__ __volatile__("lock; xaddq %0,%1" : "+r" (temp), "+m" (*ptr) : : "memory"); // temp now contains the previous value of *ptr if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { __asm__ __volatile__("lfence" : : : "memory"); } return temp + increment; } inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { *ptr = value; } inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) { *ptr = value; MemoryBarrier(); } inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) { ATOMICOPS_COMPILER_BARRIER(); *ptr = value; // An x86 store acts as a release barrier // for current AMD/Intel chips as of Jan 2008. // See also Acquire_Load(), below. // When new chips come out, check: // IA-32 Intel Architecture Software Developer's Manual, Volume 3: // System Programming Guide, Chatper 7: Multiple-processor management, // Section 7.2, Memory Ordering. // Last seen at: // http://developer.intel.com/design/pentium4/manuals/index_new.htm // // x86 stores/loads fail to act as barriers for a few instructions (clflush // maskmovdqu maskmovq movntdq movnti movntpd movntps movntq) but these are // not generated by the compiler, and are rare. Users of these instructions // need to know about cache behaviour in any case since all of these involve // either flushing cache lines or non-temporal cache hints. } inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { return *ptr; } inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) { Atomic64 value = *ptr; // An x86 load acts as a acquire barrier, // for current AMD/Intel chips as of Jan 2008. // See also Release_Store(), above. ATOMICOPS_COMPILER_BARRIER(); return value; } inline Atomic64 Release_Load(volatile const Atomic64* ptr) { MemoryBarrier(); return *ptr; } #else // defined(__x86_64__) // 64-bit low-level operations on 32-bit platform. #if !((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) // For compilers older than gcc 4.1, we use inline asm. // // Potential pitfalls: // // 1. %ebx points to Global offset table (GOT) with -fPIC. // We need to preserve this register. // 2. When explicit registers are used in inline asm, the // compiler may not be aware of it and might try to reuse // the same register for another argument which has constraints // that allow it ("r" for example). inline Atomic64 __sync_val_compare_and_swap(volatile Atomic64* ptr, Atomic64 old_value, Atomic64 new_value) { Atomic64 prev; __asm__ __volatile__("push %%ebx\n\t" "movl (%3), %%ebx\n\t" // Move 64-bit new_value into "movl 4(%3), %%ecx\n\t" // ecx:ebx "lock; cmpxchg8b (%1)\n\t"// If edx:eax (old_value) same "pop %%ebx\n\t" : "=A" (prev) // as contents of ptr: : "D" (ptr), // ecx:ebx => ptr "0" (old_value), // else: "S" (&new_value) // old *ptr => edx:eax : "memory", "%ecx"); return prev; } #endif // Compiler < gcc-4.1 inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_val, Atomic64 new_val) { return __sync_val_compare_and_swap(ptr, old_val, new_val); } inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_val) { Atomic64 old_val; do { old_val = *ptr; } while (__sync_val_compare_and_swap(ptr, old_val, new_val) != old_val); return old_val; } inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment) { Atomic64 old_val, new_val; do { old_val = *ptr; new_val = old_val + increment; } while (__sync_val_compare_and_swap(ptr, old_val, new_val) != old_val); return old_val + increment; } inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment) { Atomic64 new_val = NoBarrier_AtomicIncrement(ptr, increment); if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { __asm__ __volatile__("lfence" : : : "memory"); } return new_val; } inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { __asm__ __volatile__("movq %1, %%mm0\n\t" // Use mmx reg for 64-bit atomic "movq %%mm0, %0\n\t" // moves (ptr could be read-only) "emms\n\t" // Empty mmx state/Reset FP regs : "=m" (*ptr) : "m" (value) : // mark the FP stack and mmx registers as clobbered "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7"); } inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) { NoBarrier_Store(ptr, value); MemoryBarrier(); } inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) { ATOMICOPS_COMPILER_BARRIER(); NoBarrier_Store(ptr, value); } inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { Atomic64 value; __asm__ __volatile__("movq %1, %%mm0\n\t" // Use mmx reg for 64-bit atomic "movq %%mm0, %0\n\t" // moves (ptr could be read-only) "emms\n\t" // Empty mmx state/Reset FP regs : "=m" (value) : "m" (*ptr) : // mark the FP stack and mmx registers as clobbered "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7"); return value; } inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) { Atomic64 value = NoBarrier_Load(ptr); ATOMICOPS_COMPILER_BARRIER(); return value; } inline Atomic64 Release_Load(volatile const Atomic64* ptr) { MemoryBarrier(); return NoBarrier_Load(ptr); } #endif // defined(__x86_64__) inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, Atomic64 new_value) { Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value); if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { __asm__ __volatile__("lfence" : : : "memory"); } return x; } inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, Atomic64 new_value) { return NoBarrier_CompareAndSwap(ptr, old_value, new_value); } } // namespace base::subtle } // namespace base #undef ATOMICOPS_COMPILER_BARRIER #endif // BASE_ATOMICOPS_INTERNALS_X86_H_ ================================================ FILE: distro/google-perftools-1.7/src/base/atomicops.h ================================================ /* Copyright (c) 2006, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Sanjay Ghemawat */ // For atomic operations on statistics counters, see atomic_stats_counter.h. // For atomic operations on sequence numbers, see atomic_sequence_num.h. // For atomic operations on reference counts, see atomic_refcount.h. // Some fast atomic operations -- typically with machine-dependent // implementations. This file may need editing as Google code is // ported to different architectures. // The routines exported by this module are subtle. If you use them, even if // you get the code right, it will depend on careful reasoning about atomicity // and memory ordering; it will be less readable, and harder to maintain. If // you plan to use these routines, you should have a good reason, such as solid // evidence that performance would otherwise suffer, or there being no // alternative. You should assume only properties explicitly guaranteed by the // specifications in this file. You are almost certainly _not_ writing code // just for the x86; if you assume x86 semantics, x86 hardware bugs and // implementations on other archtectures will cause your code to break. If you // do not know what you are doing, avoid these routines, and use a Mutex. // // It is incorrect to make direct assignments to/from an atomic variable. // You should use one of the Load or Store routines. The NoBarrier // versions are provided when no barriers are needed: // NoBarrier_Store() // NoBarrier_Load() // Although there are currently no compiler enforcement, you are encouraged // to use these. Moreover, if you choose to use base::subtle::Atomic64 type, // you MUST use one of the Load or Store routines to get correct behavior // on 32-bit platforms. // // The intent is eventually to put all of these routines in namespace // base::subtle #ifndef THREAD_ATOMICOPS_H_ #define THREAD_ATOMICOPS_H_ #include #ifdef HAVE_STDINT_H #include #endif // ------------------------------------------------------------------------ // Include the platform specific implementations of the types // and operations listed below. Implementations are to provide Atomic32 // and Atomic64 operations. If there is a mismatch between intptr_t and // the Atomic32 or Atomic64 types for a platform, the platform-specific header // should define the macro, AtomicWordCastType in a clause similar to the // following: // #if ...pointers are 64 bits... // # define AtomicWordCastType base::subtle::Atomic64 // #else // # define AtomicWordCastType Atomic32 // #endif // TODO(csilvers): figure out ARCH_PIII/ARCH_K8 (perhaps via ./configure?) // ------------------------------------------------------------------------ // TODO(csilvers): match piii, not just __i386. Also, match k8 #if defined(__MACH__) && defined(__APPLE__) #include "base/atomicops-internals-macosx.h" #elif defined(__GNUC__) && defined(__ARM_ARCH_5T__) #include "base/atomicops-internals-arm-gcc.h" #elif defined(_MSC_VER) && defined(_M_IX86) #include "base/atomicops-internals-x86-msvc.h" #elif defined(__MINGW32__) && defined(__i386__) #include "base/atomicops-internals-x86-msvc.h" #elif defined(__GNUC__) && (defined(__i386) || defined(ARCH_K8)) #include "base/atomicops-internals-x86.h" #elif defined(__linux__) && defined(__PPC__) #include "base/atomicops-internals-linuxppc.h" #else // Assume x86 for now. If you need to support a new architecture and // don't know how to implement atomic ops, you can probably get away // with using pthreads, since atomicops is only used by spinlock.h/cc //#error You need to implement atomic operations for this architecture #include "base/atomicops-internals-x86.h" #endif // Signed type that can hold a pointer and supports the atomic ops below, as // well as atomic loads and stores. Instances must be naturally-aligned. typedef intptr_t AtomicWord; #ifdef AtomicWordCastType // ------------------------------------------------------------------------ // This section is needed only when explicit type casting is required to // cast AtomicWord to one of the basic atomic types (Atomic64 or Atomic32). // It also serves to document the AtomicWord interface. // ------------------------------------------------------------------------ namespace base { namespace subtle { // Atomically execute: // result = *ptr; // if (*ptr == old_value) // *ptr = new_value; // return result; // // I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value". // Always return the old value of "*ptr" // // This routine implies no memory barriers. inline AtomicWord NoBarrier_CompareAndSwap(volatile AtomicWord* ptr, AtomicWord old_value, AtomicWord new_value) { return NoBarrier_CompareAndSwap( reinterpret_cast(ptr), old_value, new_value); } // Atomically store new_value into *ptr, returning the previous value held in // *ptr. This routine implies no memory barriers. inline AtomicWord NoBarrier_AtomicExchange(volatile AtomicWord* ptr, AtomicWord new_value) { return NoBarrier_AtomicExchange( reinterpret_cast(ptr), new_value); } // Atomically increment *ptr by "increment". Returns the new value of // *ptr with the increment applied. This routine implies no memory // barriers. inline AtomicWord NoBarrier_AtomicIncrement(volatile AtomicWord* ptr, AtomicWord increment) { return NoBarrier_AtomicIncrement( reinterpret_cast(ptr), increment); } inline AtomicWord Barrier_AtomicIncrement(volatile AtomicWord* ptr, AtomicWord increment) { return Barrier_AtomicIncrement( reinterpret_cast(ptr), increment); } // ------------------------------------------------------------------------ // These following lower-level operations are typically useful only to people // implementing higher-level synchronization operations like spinlocks, // mutexes, and condition-variables. They combine CompareAndSwap(), a load, or // a store with appropriate memory-ordering instructions. "Acquire" operations // ensure that no later memory access can be reordered ahead of the operation. // "Release" operations ensure that no previous memory access can be reordered // after the operation. "Barrier" operations have both "Acquire" and "Release" // semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory // access. // ------------------------------------------------------------------------ inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr, AtomicWord old_value, AtomicWord new_value) { return base::subtle::Acquire_CompareAndSwap( reinterpret_cast(ptr), old_value, new_value); } inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr, AtomicWord old_value, AtomicWord new_value) { return base::subtle::Release_CompareAndSwap( reinterpret_cast(ptr), old_value, new_value); } inline void NoBarrier_Store(volatile AtomicWord *ptr, AtomicWord value) { NoBarrier_Store( reinterpret_cast(ptr), value); } inline void Acquire_Store(volatile AtomicWord* ptr, AtomicWord value) { return base::subtle::Acquire_Store( reinterpret_cast(ptr), value); } inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) { return base::subtle::Release_Store( reinterpret_cast(ptr), value); } inline AtomicWord NoBarrier_Load(volatile const AtomicWord *ptr) { return NoBarrier_Load( reinterpret_cast(ptr)); } inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) { return base::subtle::Acquire_Load( reinterpret_cast(ptr)); } inline AtomicWord Release_Load(volatile const AtomicWord* ptr) { return base::subtle::Release_Load( reinterpret_cast(ptr)); } } // namespace base::subtle } // namespace base #endif // AtomicWordCastType // ------------------------------------------------------------------------ // Commented out type definitions and method declarations for documentation // of the interface provided by this module. // ------------------------------------------------------------------------ #if 0 // Signed 32-bit type that supports the atomic ops below, as well as atomic // loads and stores. Instances must be naturally aligned. This type differs // from AtomicWord in 64-bit binaries where AtomicWord is 64-bits. typedef int32_t Atomic32; // Corresponding operations on Atomic32 namespace base { namespace subtle { // Signed 64-bit type that supports the atomic ops below, as well as atomic // loads and stores. Instances must be naturally aligned. This type differs // from AtomicWord in 32-bit binaries where AtomicWord is 32-bits. typedef int64_t Atomic64; Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, Atomic32 new_value); Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value); Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment); Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment); Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, Atomic32 new_value); Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, Atomic32 new_value); void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value); void Acquire_Store(volatile Atomic32* ptr, Atomic32 value); void Release_Store(volatile Atomic32* ptr, Atomic32 value); Atomic32 NoBarrier_Load(volatile const Atomic32* ptr); Atomic32 Acquire_Load(volatile const Atomic32* ptr); Atomic32 Release_Load(volatile const Atomic32* ptr); // Corresponding operations on Atomic64 Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, Atomic64 new_value); Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value); Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment); Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment); Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, Atomic64 new_value); Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, Atomic64 new_value); void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value); void Acquire_Store(volatile Atomic64* ptr, Atomic64 value); void Release_Store(volatile Atomic64* ptr, Atomic64 value); Atomic64 NoBarrier_Load(volatile const Atomic64* ptr); Atomic64 Acquire_Load(volatile const Atomic64* ptr); Atomic64 Release_Load(volatile const Atomic64* ptr); } // namespace base::subtle } // namespace base void MemoryBarrier(); #endif // 0 // ------------------------------------------------------------------------ // The following are to be deprecated when all uses have been changed to // use the base::subtle namespace. // ------------------------------------------------------------------------ #ifdef AtomicWordCastType // AtomicWord versions to be deprecated inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr, AtomicWord old_value, AtomicWord new_value) { return base::subtle::Acquire_CompareAndSwap(ptr, old_value, new_value); } inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr, AtomicWord old_value, AtomicWord new_value) { return base::subtle::Release_CompareAndSwap(ptr, old_value, new_value); } inline void Acquire_Store(volatile AtomicWord* ptr, AtomicWord value) { return base::subtle::Acquire_Store(ptr, value); } inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) { return base::subtle::Release_Store(ptr, value); } inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) { return base::subtle::Acquire_Load(ptr); } inline AtomicWord Release_Load(volatile const AtomicWord* ptr) { return base::subtle::Release_Load(ptr); } #endif // AtomicWordCastType // 32-bit Acquire/Release operations to be deprecated. inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, Atomic32 new_value) { return base::subtle::Acquire_CompareAndSwap(ptr, old_value, new_value); } inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, Atomic32 new_value) { return base::subtle::Release_CompareAndSwap(ptr, old_value, new_value); } inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { base::subtle::Acquire_Store(ptr, value); } inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { return base::subtle::Release_Store(ptr, value); } inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { return base::subtle::Acquire_Load(ptr); } inline Atomic32 Release_Load(volatile const Atomic32* ptr) { return base::subtle::Release_Load(ptr); } #ifdef BASE_HAS_ATOMIC64 // 64-bit Acquire/Release operations to be deprecated. inline base::subtle::Atomic64 Acquire_CompareAndSwap( volatile base::subtle::Atomic64* ptr, base::subtle::Atomic64 old_value, base::subtle::Atomic64 new_value) { return base::subtle::Acquire_CompareAndSwap(ptr, old_value, new_value); } inline base::subtle::Atomic64 Release_CompareAndSwap( volatile base::subtle::Atomic64* ptr, base::subtle::Atomic64 old_value, base::subtle::Atomic64 new_value) { return base::subtle::Release_CompareAndSwap(ptr, old_value, new_value); } inline void Acquire_Store( volatile base::subtle::Atomic64* ptr, base::subtle::Atomic64 value) { base::subtle::Acquire_Store(ptr, value); } inline void Release_Store( volatile base::subtle::Atomic64* ptr, base::subtle::Atomic64 value) { return base::subtle::Release_Store(ptr, value); } inline base::subtle::Atomic64 Acquire_Load( volatile const base::subtle::Atomic64* ptr) { return base::subtle::Acquire_Load(ptr); } inline base::subtle::Atomic64 Release_Load( volatile const base::subtle::Atomic64* ptr) { return base::subtle::Release_Load(ptr); } #endif // BASE_HAS_ATOMIC64 #endif // THREAD_ATOMICOPS_H_ ================================================ FILE: distro/google-perftools-1.7/src/base/basictypes.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef _BASICTYPES_H_ #define _BASICTYPES_H_ #include #ifdef HAVE_INTTYPES_H #include // gets us PRId64, etc #endif // To use this in an autoconf setting, make sure you run the following // autoconf macros: // AC_HEADER_STDC /* for stdint_h and inttypes_h */ // AC_CHECK_TYPES([__int64]) /* defined in some windows platforms */ #ifdef HAVE_INTTYPES_H #include // uint16_t might be here; PRId64 too. #endif #ifdef HAVE_STDINT_H #include // to get uint16_t (ISO naming madness) #endif #include // our last best hope for uint16_t // Standard typedefs // All Google code is compiled with -funsigned-char to make "char" // unsigned. Google code therefore doesn't need a "uchar" type. // TODO(csilvers): how do we make sure unsigned-char works on non-gcc systems? typedef signed char schar; typedef int8_t int8; typedef int16_t int16; typedef int32_t int32; typedef int64_t int64; // NOTE: unsigned types are DANGEROUS in loops and other arithmetical // places. Use the signed types unless your variable represents a bit // pattern (eg a hash value) or you really need the extra bit. Do NOT // use 'unsigned' to express "this value should always be positive"; // use assertions for this. typedef uint8_t uint8; typedef uint16_t uint16; typedef uint32_t uint32; typedef uint64_t uint64; const uint16 kuint16max = ( (uint16) 0xFFFF); const uint32 kuint32max = ( (uint32) 0xFFFFFFFF); const uint64 kuint64max = ( (((uint64) kuint32max) << 32) | kuint32max ); const int8 kint8max = ( ( int8) 0x7F); const int16 kint16max = ( ( int16) 0x7FFF); const int32 kint32max = ( ( int32) 0x7FFFFFFF); const int64 kint64max = ( ((( int64) kint32max) << 32) | kuint32max ); const int8 kint8min = ( ( int8) 0x80); const int16 kint16min = ( ( int16) 0x8000); const int32 kint32min = ( ( int32) 0x80000000); const int64 kint64min = ( ((( int64) kint32min) << 32) | 0 ); // Define the "portable" printf and scanf macros, if they're not // already there (via the inttypes.h we #included above, hopefully). // Mostly it's old systems that don't support inttypes.h, so we assume // they're 32 bit. #ifndef PRIx64 #define PRIx64 "llx" #endif #ifndef SCNx64 #define SCNx64 "llx" #endif #ifndef PRId64 #define PRId64 "lld" #endif #ifndef SCNd64 #define SCNd64 "lld" #endif #ifndef PRIu64 #define PRIu64 "llu" #endif #ifndef PRIxPTR #define PRIxPTR "lx" #endif // Also allow for printing of a pthread_t. #define GPRIuPTHREAD "lu" #define GPRIxPTHREAD "lx" #if defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__APPLE__) || defined(__FreeBSD__) #define PRINTABLE_PTHREAD(pthreadt) reinterpret_cast(pthreadt) #else #define PRINTABLE_PTHREAD(pthreadt) pthreadt #endif // A macro to disallow the evil copy constructor and operator= functions // This should be used in the private: declarations for a class #define DISALLOW_EVIL_CONSTRUCTORS(TypeName) \ TypeName(const TypeName&); \ void operator=(const TypeName&) // An alternate name that leaves out the moral judgment... :-) #define DISALLOW_COPY_AND_ASSIGN(TypeName) DISALLOW_EVIL_CONSTRUCTORS(TypeName) // The COMPILE_ASSERT macro can be used to verify that a compile time // expression is true. For example, you could use it to verify the // size of a static array: // // COMPILE_ASSERT(sizeof(num_content_type_names) == sizeof(int), // content_type_names_incorrect_size); // // or to make sure a struct is smaller than a certain size: // // COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large); // // The second argument to the macro is the name of the variable. If // the expression is false, most compilers will issue a warning/error // containing the name of the variable. // // Implementation details of COMPILE_ASSERT: // // - COMPILE_ASSERT works by defining an array type that has -1 // elements (and thus is invalid) when the expression is false. // // - The simpler definition // // #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1] // // does not work, as gcc supports variable-length arrays whose sizes // are determined at run-time (this is gcc's extension and not part // of the C++ standard). As a result, gcc fails to reject the // following code with the simple definition: // // int foo; // COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is // // not a compile-time constant. // // - By using the type CompileAssert<(bool(expr))>, we ensures that // expr is a compile-time constant. (Template arguments must be // determined at compile-time.) // // - The outter parentheses in CompileAssert<(bool(expr))> are necessary // to work around a bug in gcc 3.4.4 and 4.0.1. If we had written // // CompileAssert // // instead, these compilers will refuse to compile // // COMPILE_ASSERT(5 > 0, some_message); // // (They seem to think the ">" in "5 > 0" marks the end of the // template argument list.) // // - The array size is (bool(expr) ? 1 : -1), instead of simply // // ((expr) ? 1 : -1). // // This is to avoid running into a bug in MS VC 7.1, which // causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. template struct CompileAssert { }; #define COMPILE_ASSERT(expr, msg) \ typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] #define arraysize(a) (sizeof(a) / sizeof(*(a))) #define OFFSETOF_MEMBER(strct, field) \ (reinterpret_cast(&reinterpret_cast(16)->field) - \ reinterpret_cast(16)) #ifdef HAVE___ATTRIBUTE__ # define ATTRIBUTE_WEAK __attribute__((weak)) # define ATTRIBUTE_NOINLINE __attribute__((noinline)) #else # define ATTRIBUTE_WEAK # define ATTRIBUTE_NOINLINE #endif // Section attributes are supported for both ELF and Mach-O, but in // very different ways. Here's the API we provide: // 1) ATTRIBUTE_SECTION: put this with the declaration of all functions // you want to be in the same linker section // 2) DEFINE_ATTRIBUTE_SECTION_VARS: must be called once per unique // name. You want to make sure this is executed before any // DECLARE_ATTRIBUTE_SECTION_VARS; the easiest way is to put them // in the same .cc file. Put this call at the global level. // 3) INIT_ATTRIBUTE_SECTION_VARS: you can scatter calls to this in // multiple places to help ensure execution before any // DECLARE_ATTRIBUTE_SECTION_VARS. You must have at least one // DEFINE, but you can have many INITs. Put each in its own scope. // 4) DECLARE_ATTRIBUTE_SECTION_VARS: must be called before using // ATTRIBUTE_SECTION_START or ATTRIBUTE_SECTION_STOP on a name. // Put this call at the global level. // 5) ATTRIBUTE_SECTION_START/ATTRIBUTE_SECTION_STOP: call this to say // where in memory a given section is. All functions declared with // ATTRIBUTE_SECTION are guaranteed to be between START and STOP. #if defined(HAVE___ATTRIBUTE__) && defined(__ELF__) # define ATTRIBUTE_SECTION(name) __attribute__ ((section (#name))) // Weak section declaration to be used as a global declaration // for ATTRIBUTE_SECTION_START|STOP(name) to compile and link // even without functions with ATTRIBUTE_SECTION(name). # define DECLARE_ATTRIBUTE_SECTION_VARS(name) \ extern char __start_##name[] ATTRIBUTE_WEAK; \ extern char __stop_##name[] ATTRIBUTE_WEAK # define INIT_ATTRIBUTE_SECTION_VARS(name) // no-op for ELF # define DEFINE_ATTRIBUTE_SECTION_VARS(name) // no-op for ELF // Return void* pointers to start/end of a section of code with functions // having ATTRIBUTE_SECTION(name), or 0 if no such function exists. // One must DECLARE_ATTRIBUTE_SECTION(name) for this to compile and link. # define ATTRIBUTE_SECTION_START(name) (reinterpret_cast(__start_##name)) # define ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast(__stop_##name)) # define HAVE_ATTRIBUTE_SECTION_START 1 #elif defined(HAVE___ATTRIBUTE__) && defined(__MACH__) # define ATTRIBUTE_SECTION(name) __attribute__ ((section ("__TEXT, " #name))) #include #include class AssignAttributeStartEnd { public: AssignAttributeStartEnd(const char* name, char** pstart, char** pend) { // Find out what dynamic library name is defined in if (_dyld_present()) { for (int i = _dyld_image_count() - 1; i >= 0; --i) { const mach_header* hdr = _dyld_get_image_header(i); #ifdef MH_MAGIC_64 if (hdr->magic == MH_MAGIC_64) { uint64_t len; *pstart = getsectdatafromheader_64((mach_header_64*)hdr, "__TEXT", name, &len); if (*pstart) { // NULL if not defined in this dynamic library *pstart += _dyld_get_image_vmaddr_slide(i); // correct for reloc *pend = *pstart + len; return; } } #endif if (hdr->magic == MH_MAGIC) { uint32_t len; *pstart = getsectdatafromheader(hdr, "__TEXT", name, &len); if (*pstart) { // NULL if not defined in this dynamic library *pstart += _dyld_get_image_vmaddr_slide(i); // correct for reloc *pend = *pstart + len; return; } } } } // If we get here, not defined in a dll at all. See if defined statically. unsigned long len; // don't ask me why this type isn't uint32_t too... *pstart = getsectdata("__TEXT", name, &len); *pend = *pstart + len; } }; #define DECLARE_ATTRIBUTE_SECTION_VARS(name) \ extern char* __start_##name; \ extern char* __stop_##name #define INIT_ATTRIBUTE_SECTION_VARS(name) \ DECLARE_ATTRIBUTE_SECTION_VARS(name); \ static const AssignAttributeStartEnd __assign_##name( \ #name, &__start_##name, &__stop_##name) #define DEFINE_ATTRIBUTE_SECTION_VARS(name) \ char* __start_##name, *__stop_##name; \ INIT_ATTRIBUTE_SECTION_VARS(name) # define ATTRIBUTE_SECTION_START(name) (reinterpret_cast(__start_##name)) # define ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast(__stop_##name)) # define HAVE_ATTRIBUTE_SECTION_START 1 #else // not HAVE___ATTRIBUTE__ && __ELF__, nor HAVE___ATTRIBUTE__ && __MACH__ # define ATTRIBUTE_SECTION(name) # define DECLARE_ATTRIBUTE_SECTION_VARS(name) # define INIT_ATTRIBUTE_SECTION_VARS(name) # define DEFINE_ATTRIBUTE_SECTION_VARS(name) # define ATTRIBUTE_SECTION_START(name) (reinterpret_cast(0)) # define ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast(0)) #endif // HAVE___ATTRIBUTE__ and __ELF__ or __MACH__ #if defined(HAVE___ATTRIBUTE__) && (defined(__i386__) || defined(__x86_64__)) # define CACHELINE_SIZE 64 # define CACHELINE_ALIGNED __attribute__((aligned(CACHELINE_SIZE))) #else # define CACHELINE_ALIGNED #endif // defined(HAVE___ATTRIBUTE__) && (__i386__ || __x86_64__) // The following enum should be used only as a constructor argument to indicate // that the variable has static storage class, and that the constructor should // do nothing to its state. It indicates to the reader that it is legal to // declare a static nistance of the class, provided the constructor is given // the base::LINKER_INITIALIZED argument. Normally, it is unsafe to declare a // static variable that has a constructor or a destructor because invocation // order is undefined. However, IF the type can be initialized by filling with // zeroes (which the loader does for static variables), AND the destructor also // does nothing to the storage, then a constructor declared as // explicit MyClass(base::LinkerInitialized x) {} // and invoked as // static MyClass my_variable_name(base::LINKER_INITIALIZED); namespace base { enum LinkerInitialized { LINKER_INITIALIZED }; } #endif // _BASICTYPES_H_ ================================================ FILE: distro/google-perftools-1.7/src/base/commandlineflags.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // This file is a compatibility layer that defines Google's version of // command line flags that are used for configuration. // // We put flags into their own namespace. It is purposefully // named in an opaque way that people should have trouble typing // directly. The idea is that DEFINE puts the flag in the weird // namespace, and DECLARE imports the flag from there into the // current namespace. The net result is to force people to use // DECLARE to get access to a flag, rather than saying // extern bool FLAGS_logtostderr; // or some such instead. We want this so we can put extra // functionality (like sanity-checking) in DECLARE if we want, // and make sure it is picked up everywhere. // // We also put the type of the variable in the namespace, so that // people can't DECLARE_int32 something that they DEFINE_bool'd // elsewhere. #ifndef BASE_COMMANDLINEFLAGS_H_ #define BASE_COMMANDLINEFLAGS_H_ #include #include #include // for memchr #include // for getenv #include "base/basictypes.h" #define DECLARE_VARIABLE(type, name) \ namespace FLAG__namespace_do_not_use_directly_use_DECLARE_##type##_instead { \ extern PERFTOOLS_DLL_DECL type FLAGS_##name; \ } \ using FLAG__namespace_do_not_use_directly_use_DECLARE_##type##_instead::FLAGS_##name #define DEFINE_VARIABLE(type, name, value, meaning) \ namespace FLAG__namespace_do_not_use_directly_use_DECLARE_##type##_instead { \ PERFTOOLS_DLL_DECL type FLAGS_##name(value); \ char FLAGS_no##name; \ } \ using FLAG__namespace_do_not_use_directly_use_DECLARE_##type##_instead::FLAGS_##name // bool specialization #define DECLARE_bool(name) \ DECLARE_VARIABLE(bool, name) #define DEFINE_bool(name, value, meaning) \ DEFINE_VARIABLE(bool, name, value, meaning) // int32 specialization #define DECLARE_int32(name) \ DECLARE_VARIABLE(int32, name) #define DEFINE_int32(name, value, meaning) \ DEFINE_VARIABLE(int32, name, value, meaning) // int64 specialization #define DECLARE_int64(name) \ DECLARE_VARIABLE(int64, name) #define DEFINE_int64(name, value, meaning) \ DEFINE_VARIABLE(int64, name, value, meaning) #define DECLARE_uint64(name) \ DECLARE_VARIABLE(uint64, name) #define DEFINE_uint64(name, value, meaning) \ DEFINE_VARIABLE(uint64, name, value, meaning) // double specialization #define DECLARE_double(name) \ DECLARE_VARIABLE(double, name) #define DEFINE_double(name, value, meaning) \ DEFINE_VARIABLE(double, name, value, meaning) // Special case for string, because we have to specify the namespace // std::string, which doesn't play nicely with our FLAG__namespace hackery. #define DECLARE_string(name) \ namespace FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead { \ extern std::string FLAGS_##name; \ } \ using FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead::FLAGS_##name #define DEFINE_string(name, value, meaning) \ namespace FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead { \ std::string FLAGS_##name(value); \ char FLAGS_no##name; \ } \ using FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead::FLAGS_##name // These macros (could be functions, but I don't want to bother with a .cc // file), make it easier to initialize flags from the environment. #define EnvToString(envname, dflt) \ (!getenv(envname) ? (dflt) : getenv(envname)) #define EnvToBool(envname, dflt) \ (!getenv(envname) ? (dflt) : memchr("tTyY1\0", getenv(envname)[0], 6) != NULL) #define EnvToInt(envname, dflt) \ (!getenv(envname) ? (dflt) : strtol(getenv(envname), NULL, 10)) #define EnvToInt64(envname, dflt) \ (!getenv(envname) ? (dflt) : strtoll(getenv(envname), NULL, 10)) #define EnvToDouble(envname, dflt) \ (!getenv(envname) ? (dflt) : strtod(getenv(envname), NULL)) #endif // BASE_COMMANDLINEFLAGS_H_ ================================================ FILE: distro/google-perftools-1.7/src/base/cycleclock.h ================================================ // Copyright (c) 2004, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ---------------------------------------------------------------------- // CycleClock // A CycleClock tells you the current time in Cycles. The "time" // is actually time since power-on. This is like time() but doesn't // involve a system call and is much more precise. // // NOTE: Not all cpu/platform/kernel combinations guarantee that this // clock increments at a constant rate or is synchronized across all logical // cpus in a system. // // Also, in some out of order CPU implementations, the CycleClock is not // serializing. So if you're trying to count at cycles granularity, your // data might be inaccurate due to out of order instruction execution. // ---------------------------------------------------------------------- #ifndef GOOGLE_BASE_CYCLECLOCK_H_ #define GOOGLE_BASE_CYCLECLOCK_H_ #include "base/basictypes.h" // make sure we get the def for int64 #if defined(__MACH__) && defined(__APPLE__) # include #elif defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_3__) # include #endif // NOTE: only i386 and x86_64 have been well tested. // PPC, sparc, alpha, and ia64 are based on // http://peter.kuscsik.com/wordpress/?p=14 // with modifications by m3b. See also // https://setisvn.ssl.berkeley.edu/svn/lib/fftw-3.0.1/kernel/cycle.h struct CycleClock { // This should return the number of cycles since power-on. Thread-safe. static inline int64 Now() { #if defined(__MACH__) && defined(__APPLE__) // this goes at the top because we need ALL Macs, regardless of // architecture, to return the number of "mach time units" that // have passed since startup. See sysinfo.cc where // InitializeSystemInfo() sets the supposed cpu clock frequency of // macs to the number of mach time units per second, not actual // CPU clock frequency (which can change in the face of CPU // frequency scaling). Also note that when the Mac sleeps, this // counter pauses; it does not continue counting, nor does it // reset to zero. return mach_absolute_time(); #elif defined(__i386__) int64 ret; __asm__ volatile ("rdtsc" : "=A" (ret) ); return ret; #elif defined(__x86_64__) || defined(__amd64__) uint64 low, high; __asm__ volatile ("rdtsc" : "=a" (low), "=d" (high)); return (high << 32) | low; #elif defined(__powerpc__) || defined(__ppc__) // This returns a time-base, which is not always precisely a cycle-count. int64 tbl, tbu0, tbu1; asm("mftbu %0" : "=r" (tbu0)); asm("mftb %0" : "=r" (tbl)); asm("mftbu %0" : "=r" (tbu1)); tbl &= -static_cast(tbu0 == tbu1); // high 32 bits in tbu1; low 32 bits in tbl (tbu0 is garbage) return (tbu1 << 32) | tbl; #elif defined(__sparc__) int64 tick; asm(".byte 0x83, 0x41, 0x00, 0x00"); asm("mov %%g1, %0" : "=r" (tick)); return tick; #elif defined(__ia64__) int64 itc; asm("mov %0 = ar.itc" : "=r" (itc)); return itc; #elif defined(_MSC_VER) && defined(_M_IX86) _asm rdtsc // If none of the above cases trigger, we use a solution based on // a system call (gettimeofday or similar). We do these in order // from fastest to slowest. We do not have an '#else' catch-all // case here that just calls gettimeofday(); that system call is // slow, and this function is expected to be fast, so we don't want // to use it without an explicit decision that it's the only way. #elif defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_3__) struct timeval tv; gettimeofday(&tv, NULL); return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; #else // We could define __alpha here as well, but it only has a 32-bit // timer (good for like 4 seconds), which isn't very useful. #error You need to define CycleTimer for your O/S and CPU #endif } }; #endif // GOOGLE_BASE_CYCLECLOCK_H_ ================================================ FILE: distro/google-perftools-1.7/src/base/dynamic_annotations.c ================================================ /* Copyright (c) 2008-2009, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Kostya Serebryany */ #ifdef __cplusplus # error "This file should be built as pure C to avoid name mangling" #endif #include "config.h" #include #include #include "base/dynamic_annotations.h" #ifdef __GNUC__ /* valgrind.h uses gcc extensions so it won't build with other compilers */ # ifdef HAVE_VALGRIND_H /* prefer the user's copy if they have it */ # include # else /* otherwise just use the copy that we have */ # include "third_party/valgrind.h" # endif #endif /* Each function is empty and called (via a macro) only in debug mode. The arguments are captured by dynamic tools at runtime. */ #if DYNAMIC_ANNOTATIONS_ENABLED == 1 void AnnotateRWLockCreate(const char *file, int line, const volatile void *lock){} void AnnotateRWLockDestroy(const char *file, int line, const volatile void *lock){} void AnnotateRWLockAcquired(const char *file, int line, const volatile void *lock, long is_w){} void AnnotateRWLockReleased(const char *file, int line, const volatile void *lock, long is_w){} void AnnotateBarrierInit(const char *file, int line, const volatile void *barrier, long count, long reinitialization_allowed) {} void AnnotateBarrierWaitBefore(const char *file, int line, const volatile void *barrier) {} void AnnotateBarrierWaitAfter(const char *file, int line, const volatile void *barrier) {} void AnnotateBarrierDestroy(const char *file, int line, const volatile void *barrier) {} void AnnotateCondVarWait(const char *file, int line, const volatile void *cv, const volatile void *lock){} void AnnotateCondVarSignal(const char *file, int line, const volatile void *cv){} void AnnotateCondVarSignalAll(const char *file, int line, const volatile void *cv){} void AnnotatePublishMemoryRange(const char *file, int line, const volatile void *address, long size){} void AnnotateUnpublishMemoryRange(const char *file, int line, const volatile void *address, long size){} void AnnotatePCQCreate(const char *file, int line, const volatile void *pcq){} void AnnotatePCQDestroy(const char *file, int line, const volatile void *pcq){} void AnnotatePCQPut(const char *file, int line, const volatile void *pcq){} void AnnotatePCQGet(const char *file, int line, const volatile void *pcq){} void AnnotateNewMemory(const char *file, int line, const volatile void *mem, long size){} void AnnotateExpectRace(const char *file, int line, const volatile void *mem, const char *description){} void AnnotateBenignRace(const char *file, int line, const volatile void *mem, const char *description){} void AnnotateBenignRaceSized(const char *file, int line, const volatile void *mem, long size, const char *description) {} void AnnotateMutexIsUsedAsCondVar(const char *file, int line, const volatile void *mu){} void AnnotateTraceMemory(const char *file, int line, const volatile void *arg){} void AnnotateThreadName(const char *file, int line, const char *name){} void AnnotateIgnoreReadsBegin(const char *file, int line){} void AnnotateIgnoreReadsEnd(const char *file, int line){} void AnnotateIgnoreWritesBegin(const char *file, int line){} void AnnotateIgnoreWritesEnd(const char *file, int line){} void AnnotateEnableRaceDetection(const char *file, int line, int enable){} void AnnotateNoOp(const char *file, int line, const volatile void *arg){} void AnnotateFlushState(const char *file, int line){} #endif /* DYNAMIC_ANNOTATIONS_ENABLED == 1 */ static int GetRunningOnValgrind(void) { #ifdef RUNNING_ON_VALGRIND if (RUNNING_ON_VALGRIND) return 1; #endif #ifdef _MSC_VER /* Visual Studio can complain about getenv, so use a windows equivalent. */ char value[100] = "1"; /* something that is not "0" */ int res = GetEnvironmentVariableA("RUNNING_ON_VALGRIND", value, sizeof(value)); /* value will remain "1" if the called failed for some reason. */ return (res > 0 && strcmp(value, "0") != 0); #else /* TODO(csilvers): use GetenvBeforeMain() instead? Will need to * change it to be extern "C". */ char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND"); if (running_on_valgrind_str) { return strcmp(running_on_valgrind_str, "0") != 0; } return 0; #endif } /* See the comments in dynamic_annotations.h */ int RunningOnValgrind(void) { static volatile int running_on_valgrind = -1; int local_running_on_valgrind = running_on_valgrind; /* C doesn't have thread-safe initialization of statics, and we don't want to depend on pthread_once here, so hack it. */ ANNOTATE_BENIGN_RACE(&running_on_valgrind, "safe hack"); if (local_running_on_valgrind == -1) running_on_valgrind = local_running_on_valgrind = GetRunningOnValgrind(); return local_running_on_valgrind; } /* See the comments in dynamic_annotations.h */ double ValgrindSlowdown(void) { /* Same initialization hack as in RunningOnValgrind(). */ static volatile double slowdown = 0.0; double local_slowdown = slowdown; ANNOTATE_BENIGN_RACE(&slowdown, "safe hack"); if (RunningOnValgrind() == 0) { return 1.0; } if (local_slowdown == 0.0) { char *env = getenv("VALGRIND_SLOWDOWN"); slowdown = local_slowdown = env ? atof(env) : 50.0; } return local_slowdown; } ================================================ FILE: distro/google-perftools-1.7/src/base/dynamic_annotations.h ================================================ /* Copyright (c) 2008, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Kostya Serebryany */ /* This file defines dynamic annotations for use with dynamic analysis tool such as valgrind, PIN, etc. Dynamic annotation is a source code annotation that affects the generated code (that is, the annotation is not a comment). Each such annotation is attached to a particular instruction and/or to a particular object (address) in the program. The annotations that should be used by users are macros in all upper-case (e.g., ANNOTATE_NEW_MEMORY). Actual implementation of these macros may differ depending on the dynamic analysis tool being used. See http://code.google.com/p/data-race-test/ for more information. This file supports the following dynamic analysis tools: - None (DYNAMIC_ANNOTATIONS_ENABLED is not defined or zero). Macros are defined empty. - ThreadSanitizer, Helgrind, DRD (DYNAMIC_ANNOTATIONS_ENABLED is 1). Macros are defined as calls to non-inlinable empty functions that are intercepted by Valgrind. */ #ifndef BASE_DYNAMIC_ANNOTATIONS_H_ #define BASE_DYNAMIC_ANNOTATIONS_H_ #ifndef DYNAMIC_ANNOTATIONS_ENABLED # define DYNAMIC_ANNOTATIONS_ENABLED 0 #endif #if DYNAMIC_ANNOTATIONS_ENABLED != 0 /* ------------------------------------------------------------- Annotations useful when implementing condition variables such as CondVar, using conditional critical sections (Await/LockWhen) and when constructing user-defined synchronization mechanisms. The annotations ANNOTATE_HAPPENS_BEFORE() and ANNOTATE_HAPPENS_AFTER() can be used to define happens-before arcs in user-defined synchronization mechanisms: the race detector will infer an arc from the former to the latter when they share the same argument pointer. Example 1 (reference counting): void Unref() { ANNOTATE_HAPPENS_BEFORE(&refcount_); if (AtomicDecrementByOne(&refcount_) == 0) { ANNOTATE_HAPPENS_AFTER(&refcount_); delete this; } } Example 2 (message queue): void MyQueue::Put(Type *e) { MutexLock lock(&mu_); ANNOTATE_HAPPENS_BEFORE(e); PutElementIntoMyQueue(e); } Type *MyQueue::Get() { MutexLock lock(&mu_); Type *e = GetElementFromMyQueue(); ANNOTATE_HAPPENS_AFTER(e); return e; } Note: when possible, please use the existing reference counting and message queue implementations instead of inventing new ones. */ /* Report that wait on the condition variable at address "cv" has succeeded and the lock at address "lock" is held. */ #define ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) \ AnnotateCondVarWait(__FILE__, __LINE__, cv, lock) /* Report that wait on the condition variable at "cv" has succeeded. Variant w/o lock. */ #define ANNOTATE_CONDVAR_WAIT(cv) \ AnnotateCondVarWait(__FILE__, __LINE__, cv, NULL) /* Report that we are about to signal on the condition variable at address "cv". */ #define ANNOTATE_CONDVAR_SIGNAL(cv) \ AnnotateCondVarSignal(__FILE__, __LINE__, cv) /* Report that we are about to signal_all on the condition variable at "cv". */ #define ANNOTATE_CONDVAR_SIGNAL_ALL(cv) \ AnnotateCondVarSignalAll(__FILE__, __LINE__, cv) /* Annotations for user-defined synchronization mechanisms. */ #define ANNOTATE_HAPPENS_BEFORE(obj) ANNOTATE_CONDVAR_SIGNAL(obj) #define ANNOTATE_HAPPENS_AFTER(obj) ANNOTATE_CONDVAR_WAIT(obj) /* Report that the bytes in the range [pointer, pointer+size) are about to be published safely. The race checker will create a happens-before arc from the call ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) to subsequent accesses to this memory. Note: this annotation may not work properly if the race detector uses sampling, i.e. does not observe all memory accesses. */ #define ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) \ AnnotatePublishMemoryRange(__FILE__, __LINE__, pointer, size) /* DEPRECATED. Don't use it. */ #define ANNOTATE_UNPUBLISH_MEMORY_RANGE(pointer, size) \ AnnotateUnpublishMemoryRange(__FILE__, __LINE__, pointer, size) /* DEPRECATED. Don't use it. */ #define ANNOTATE_SWAP_MEMORY_RANGE(pointer, size) \ do { \ ANNOTATE_UNPUBLISH_MEMORY_RANGE(pointer, size); \ ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size); \ } while (0) /* Instruct the tool to create a happens-before arc between mu->Unlock() and mu->Lock(). This annotation may slow down the race detector and hide real races. Normally it is used only when it would be difficult to annotate each of the mutex's critical sections individually using the annotations above. This annotation makes sense only for hybrid race detectors. For pure happens-before detectors this is a no-op. For more details see http://code.google.com/p/data-race-test/wiki/PureHappensBeforeVsHybrid . */ #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) \ AnnotateMutexIsUsedAsCondVar(__FILE__, __LINE__, mu) /* Deprecated. Use ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX. */ #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) \ AnnotateMutexIsUsedAsCondVar(__FILE__, __LINE__, mu) /* ------------------------------------------------------------- Annotations useful when defining memory allocators, or when memory that was protected in one way starts to be protected in another. */ /* Report that a new memory at "address" of size "size" has been allocated. This might be used when the memory has been retrieved from a free list and is about to be reused, or when a the locking discipline for a variable changes. */ #define ANNOTATE_NEW_MEMORY(address, size) \ AnnotateNewMemory(__FILE__, __LINE__, address, size) /* ------------------------------------------------------------- Annotations useful when defining FIFO queues that transfer data between threads. */ /* Report that the producer-consumer queue (such as ProducerConsumerQueue) at address "pcq" has been created. The ANNOTATE_PCQ_* annotations should be used only for FIFO queues. For non-FIFO queues use ANNOTATE_HAPPENS_BEFORE (for put) and ANNOTATE_HAPPENS_AFTER (for get). */ #define ANNOTATE_PCQ_CREATE(pcq) \ AnnotatePCQCreate(__FILE__, __LINE__, pcq) /* Report that the queue at address "pcq" is about to be destroyed. */ #define ANNOTATE_PCQ_DESTROY(pcq) \ AnnotatePCQDestroy(__FILE__, __LINE__, pcq) /* Report that we are about to put an element into a FIFO queue at address "pcq". */ #define ANNOTATE_PCQ_PUT(pcq) \ AnnotatePCQPut(__FILE__, __LINE__, pcq) /* Report that we've just got an element from a FIFO queue at address "pcq". */ #define ANNOTATE_PCQ_GET(pcq) \ AnnotatePCQGet(__FILE__, __LINE__, pcq) /* ------------------------------------------------------------- Annotations that suppress errors. It is usually better to express the program's synchronization using the other annotations, but these can be used when all else fails. */ /* Report that we may have a benign race at "pointer", with size "sizeof(*(pointer))". "pointer" must be a non-void* pointer. Insert at the point where "pointer" has been allocated, preferably close to the point where the race happens. See also ANNOTATE_BENIGN_RACE_STATIC. */ #define ANNOTATE_BENIGN_RACE(pointer, description) \ AnnotateBenignRaceSized(__FILE__, __LINE__, pointer, \ sizeof(*(pointer)), description) /* Same as ANNOTATE_BENIGN_RACE(address, description), but applies to the memory range [address, address+size). */ #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \ AnnotateBenignRaceSized(__FILE__, __LINE__, address, size, description) /* Request the analysis tool to ignore all reads in the current thread until ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey reads, while still checking other reads and all writes. See also ANNOTATE_UNPROTECTED_READ. */ #define ANNOTATE_IGNORE_READS_BEGIN() \ AnnotateIgnoreReadsBegin(__FILE__, __LINE__) /* Stop ignoring reads. */ #define ANNOTATE_IGNORE_READS_END() \ AnnotateIgnoreReadsEnd(__FILE__, __LINE__) /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes. */ #define ANNOTATE_IGNORE_WRITES_BEGIN() \ AnnotateIgnoreWritesBegin(__FILE__, __LINE__) /* Stop ignoring writes. */ #define ANNOTATE_IGNORE_WRITES_END() \ AnnotateIgnoreWritesEnd(__FILE__, __LINE__) /* Start ignoring all memory accesses (reads and writes). */ #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \ do {\ ANNOTATE_IGNORE_READS_BEGIN();\ ANNOTATE_IGNORE_WRITES_BEGIN();\ }while(0)\ /* Stop ignoring all memory accesses. */ #define ANNOTATE_IGNORE_READS_AND_WRITES_END() \ do {\ ANNOTATE_IGNORE_WRITES_END();\ ANNOTATE_IGNORE_READS_END();\ }while(0)\ /* Enable (enable!=0) or disable (enable==0) race detection for all threads. This annotation could be useful if you want to skip expensive race analysis during some period of program execution, e.g. during initialization. */ #define ANNOTATE_ENABLE_RACE_DETECTION(enable) \ AnnotateEnableRaceDetection(__FILE__, __LINE__, enable) /* ------------------------------------------------------------- Annotations useful for debugging. */ /* Request to trace every access to "address". */ #define ANNOTATE_TRACE_MEMORY(address) \ AnnotateTraceMemory(__FILE__, __LINE__, address) /* Report the current thread name to a race detector. */ #define ANNOTATE_THREAD_NAME(name) \ AnnotateThreadName(__FILE__, __LINE__, name) /* ------------------------------------------------------------- Annotations useful when implementing locks. They are not normally needed by modules that merely use locks. The "lock" argument is a pointer to the lock object. */ /* Report that a lock has been created at address "lock". */ #define ANNOTATE_RWLOCK_CREATE(lock) \ AnnotateRWLockCreate(__FILE__, __LINE__, lock) /* Report that the lock at address "lock" is about to be destroyed. */ #define ANNOTATE_RWLOCK_DESTROY(lock) \ AnnotateRWLockDestroy(__FILE__, __LINE__, lock) /* Report that the lock at address "lock" has been acquired. is_w=1 for writer lock, is_w=0 for reader lock. */ #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \ AnnotateRWLockAcquired(__FILE__, __LINE__, lock, is_w) /* Report that the lock at address "lock" is about to be released. */ #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \ AnnotateRWLockReleased(__FILE__, __LINE__, lock, is_w) /* ------------------------------------------------------------- Annotations useful when implementing barriers. They are not normally needed by modules that merely use barriers. The "barrier" argument is a pointer to the barrier object. */ /* Report that the "barrier" has been initialized with initial "count". If 'reinitialization_allowed' is true, initialization is allowed to happen multiple times w/o calling barrier_destroy() */ #define ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) \ AnnotateBarrierInit(__FILE__, __LINE__, barrier, count, \ reinitialization_allowed) /* Report that we are about to enter barrier_wait("barrier"). */ #define ANNOTATE_BARRIER_WAIT_BEFORE(barrier) \ AnnotateBarrierWaitBefore(__FILE__, __LINE__, barrier) /* Report that we just exited barrier_wait("barrier"). */ #define ANNOTATE_BARRIER_WAIT_AFTER(barrier) \ AnnotateBarrierWaitAfter(__FILE__, __LINE__, barrier) /* Report that the "barrier" has been destroyed. */ #define ANNOTATE_BARRIER_DESTROY(barrier) \ AnnotateBarrierDestroy(__FILE__, __LINE__, barrier) /* ------------------------------------------------------------- Annotations useful for testing race detectors. */ /* Report that we expect a race on the variable at "address". Use only in unit tests for a race detector. */ #define ANNOTATE_EXPECT_RACE(address, description) \ AnnotateExpectRace(__FILE__, __LINE__, address, description) /* A no-op. Insert where you like to test the interceptors. */ #define ANNOTATE_NO_OP(arg) \ AnnotateNoOp(__FILE__, __LINE__, arg) /* Force the race detector to flush its state. The actual effect depends on * the implementation of the detector. */ #define ANNOTATE_FLUSH_STATE() \ AnnotateFlushState(__FILE__, __LINE__) #else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */ #define ANNOTATE_RWLOCK_CREATE(lock) /* empty */ #define ANNOTATE_RWLOCK_DESTROY(lock) /* empty */ #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */ #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */ #define ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) /* */ #define ANNOTATE_BARRIER_WAIT_BEFORE(barrier) /* empty */ #define ANNOTATE_BARRIER_WAIT_AFTER(barrier) /* empty */ #define ANNOTATE_BARRIER_DESTROY(barrier) /* empty */ #define ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) /* empty */ #define ANNOTATE_CONDVAR_WAIT(cv) /* empty */ #define ANNOTATE_CONDVAR_SIGNAL(cv) /* empty */ #define ANNOTATE_CONDVAR_SIGNAL_ALL(cv) /* empty */ #define ANNOTATE_HAPPENS_BEFORE(obj) /* empty */ #define ANNOTATE_HAPPENS_AFTER(obj) /* empty */ #define ANNOTATE_PUBLISH_MEMORY_RANGE(address, size) /* empty */ #define ANNOTATE_UNPUBLISH_MEMORY_RANGE(address, size) /* empty */ #define ANNOTATE_SWAP_MEMORY_RANGE(address, size) /* empty */ #define ANNOTATE_PCQ_CREATE(pcq) /* empty */ #define ANNOTATE_PCQ_DESTROY(pcq) /* empty */ #define ANNOTATE_PCQ_PUT(pcq) /* empty */ #define ANNOTATE_PCQ_GET(pcq) /* empty */ #define ANNOTATE_NEW_MEMORY(address, size) /* empty */ #define ANNOTATE_EXPECT_RACE(address, description) /* empty */ #define ANNOTATE_BENIGN_RACE(address, description) /* empty */ #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */ #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) /* empty */ #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) /* empty */ #define ANNOTATE_TRACE_MEMORY(arg) /* empty */ #define ANNOTATE_THREAD_NAME(name) /* empty */ #define ANNOTATE_IGNORE_READS_BEGIN() /* empty */ #define ANNOTATE_IGNORE_READS_END() /* empty */ #define ANNOTATE_IGNORE_WRITES_BEGIN() /* empty */ #define ANNOTATE_IGNORE_WRITES_END() /* empty */ #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() /* empty */ #define ANNOTATE_IGNORE_READS_AND_WRITES_END() /* empty */ #define ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */ #define ANNOTATE_NO_OP(arg) /* empty */ #define ANNOTATE_FLUSH_STATE() /* empty */ #endif /* DYNAMIC_ANNOTATIONS_ENABLED */ /* Macro definitions for GCC attributes that allow static thread safety analysis to recognize and use some of the dynamic annotations as escape hatches. TODO(lcwu): remove the check for __SUPPORT_DYN_ANNOTATION__ once the default crosstool/GCC supports these GCC attributes. */ #define ANNOTALYSIS_STATIC_INLINE #define ANNOTALYSIS_SEMICOLON_OR_EMPTY_BODY ; #if defined(__GNUC__) && defined(__SUPPORT_TS_ANNOTATION__) \ && (!defined(SWIG)) && defined(__SUPPORT_DYN_ANNOTATION__) #if DYNAMIC_ANNOTATIONS_ENABLED == 0 #define ANNOTALYSIS_ONLY 1 #undef ANNOTALYSIS_STATIC_INLINE #define ANNOTALYSIS_STATIC_INLINE static inline #undef ANNOTALYSIS_SEMICOLON_OR_EMPTY_BODY #define ANNOTALYSIS_SEMICOLON_OR_EMPTY_BODY {} #endif #define ANNOTALYSIS_IGNORE_READS_BEGIN __attribute__ ((ignore_reads_begin)) #define ANNOTALYSIS_IGNORE_READS_END __attribute__ ((ignore_reads_end)) #define ANNOTALYSIS_IGNORE_WRITES_BEGIN __attribute__ ((ignore_writes_begin)) #define ANNOTALYSIS_IGNORE_WRITES_END __attribute__ ((ignore_writes_end)) #define ANNOTALYSIS_UNPROTECTED_READ __attribute__ ((unprotected_read)) #else #define ANNOTALYSIS_IGNORE_READS_BEGIN #define ANNOTALYSIS_IGNORE_READS_END #define ANNOTALYSIS_IGNORE_WRITES_BEGIN #define ANNOTALYSIS_IGNORE_WRITES_END #define ANNOTALYSIS_UNPROTECTED_READ #endif /* Use the macros above rather than using these functions directly. */ #ifdef __cplusplus extern "C" { #endif void AnnotateRWLockCreate(const char *file, int line, const volatile void *lock); void AnnotateRWLockDestroy(const char *file, int line, const volatile void *lock); void AnnotateRWLockAcquired(const char *file, int line, const volatile void *lock, long is_w); void AnnotateRWLockReleased(const char *file, int line, const volatile void *lock, long is_w); void AnnotateBarrierInit(const char *file, int line, const volatile void *barrier, long count, long reinitialization_allowed); void AnnotateBarrierWaitBefore(const char *file, int line, const volatile void *barrier); void AnnotateBarrierWaitAfter(const char *file, int line, const volatile void *barrier); void AnnotateBarrierDestroy(const char *file, int line, const volatile void *barrier); void AnnotateCondVarWait(const char *file, int line, const volatile void *cv, const volatile void *lock); void AnnotateCondVarSignal(const char *file, int line, const volatile void *cv); void AnnotateCondVarSignalAll(const char *file, int line, const volatile void *cv); void AnnotatePublishMemoryRange(const char *file, int line, const volatile void *address, long size); void AnnotateUnpublishMemoryRange(const char *file, int line, const volatile void *address, long size); void AnnotatePCQCreate(const char *file, int line, const volatile void *pcq); void AnnotatePCQDestroy(const char *file, int line, const volatile void *pcq); void AnnotatePCQPut(const char *file, int line, const volatile void *pcq); void AnnotatePCQGet(const char *file, int line, const volatile void *pcq); void AnnotateNewMemory(const char *file, int line, const volatile void *address, long size); void AnnotateExpectRace(const char *file, int line, const volatile void *address, const char *description); void AnnotateBenignRace(const char *file, int line, const volatile void *address, const char *description); void AnnotateBenignRaceSized(const char *file, int line, const volatile void *address, long size, const char *description); void AnnotateMutexIsUsedAsCondVar(const char *file, int line, const volatile void *mu); void AnnotateTraceMemory(const char *file, int line, const volatile void *arg); void AnnotateThreadName(const char *file, int line, const char *name); ANNOTALYSIS_STATIC_INLINE void AnnotateIgnoreReadsBegin(const char *file, int line) ANNOTALYSIS_IGNORE_READS_BEGIN ANNOTALYSIS_SEMICOLON_OR_EMPTY_BODY ANNOTALYSIS_STATIC_INLINE void AnnotateIgnoreReadsEnd(const char *file, int line) ANNOTALYSIS_IGNORE_READS_END ANNOTALYSIS_SEMICOLON_OR_EMPTY_BODY ANNOTALYSIS_STATIC_INLINE void AnnotateIgnoreWritesBegin(const char *file, int line) ANNOTALYSIS_IGNORE_WRITES_BEGIN ANNOTALYSIS_SEMICOLON_OR_EMPTY_BODY ANNOTALYSIS_STATIC_INLINE void AnnotateIgnoreWritesEnd(const char *file, int line) ANNOTALYSIS_IGNORE_WRITES_END ANNOTALYSIS_SEMICOLON_OR_EMPTY_BODY void AnnotateEnableRaceDetection(const char *file, int line, int enable); void AnnotateNoOp(const char *file, int line, const volatile void *arg); void AnnotateFlushState(const char *file, int line); /* Return non-zero value if running under valgrind. If "valgrind.h" is included into dynamic_annotations.c, the regular valgrind mechanism will be used. See http://valgrind.org/docs/manual/manual-core-adv.html about RUNNING_ON_VALGRIND and other valgrind "client requests". The file "valgrind.h" may be obtained by doing svn co svn://svn.valgrind.org/valgrind/trunk/include If for some reason you can't use "valgrind.h" or want to fake valgrind, there are two ways to make this function return non-zero: - Use environment variable: export RUNNING_ON_VALGRIND=1 - Make your tool intercept the function RunningOnValgrind() and change its return value. */ int RunningOnValgrind(void); /* ValgrindSlowdown returns: * 1.0, if (RunningOnValgrind() == 0) * 50.0, if (RunningOnValgrind() != 0 && getenv("VALGRIND_SLOWDOWN") == NULL) * atof(getenv("VALGRIND_SLOWDOWN")) otherwise This function can be used to scale timeout values: EXAMPLE: for (;;) { DoExpensiveBackgroundTask(); SleepForSeconds(5 * ValgrindSlowdown()); } */ double ValgrindSlowdown(void); #ifdef __cplusplus } #endif #if DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus) /* ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads. Instead of doing ANNOTATE_IGNORE_READS_BEGIN(); ... = x; ANNOTATE_IGNORE_READS_END(); one can use ... = ANNOTATE_UNPROTECTED_READ(x); */ template inline T ANNOTATE_UNPROTECTED_READ(const volatile T &x) ANNOTALYSIS_UNPROTECTED_READ { ANNOTATE_IGNORE_READS_BEGIN(); T res = x; ANNOTATE_IGNORE_READS_END(); return res; } /* Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable. */ #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \ namespace { \ class static_var ## _annotator { \ public: \ static_var ## _annotator() { \ ANNOTATE_BENIGN_RACE_SIZED(&static_var, \ sizeof(static_var), \ # static_var ": " description); \ } \ }; \ static static_var ## _annotator the ## static_var ## _annotator;\ } #else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */ #define ANNOTATE_UNPROTECTED_READ(x) (x) #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) /* empty */ #endif /* DYNAMIC_ANNOTATIONS_ENABLED */ /* Annotalysis, a GCC based static analyzer, is able to understand and use some of the dynamic annotations defined in this file. However, dynamic annotations are usually disabled in the opt mode (to avoid additional runtime overheads) while Annotalysis only works in the opt mode. In order for Annotalysis to use these dynamic annotations when they are disabled, we re-define these annotations here. Note that unlike the original macro definitions above, these macros are expanded to calls to static inline functions so that the compiler will be able to remove the calls after the analysis. */ #ifdef ANNOTALYSIS_ONLY #undef ANNOTALYSIS_ONLY /* Undefine and re-define the macros that the static analyzer understands. */ #undef ANNOTATE_IGNORE_READS_BEGIN #define ANNOTATE_IGNORE_READS_BEGIN() \ AnnotateIgnoreReadsBegin(__FILE__, __LINE__) #undef ANNOTATE_IGNORE_READS_END #define ANNOTATE_IGNORE_READS_END() \ AnnotateIgnoreReadsEnd(__FILE__, __LINE__) #undef ANNOTATE_IGNORE_WRITES_BEGIN #define ANNOTATE_IGNORE_WRITES_BEGIN() \ AnnotateIgnoreWritesBegin(__FILE__, __LINE__) #undef ANNOTATE_IGNORE_WRITES_END #define ANNOTATE_IGNORE_WRITES_END() \ AnnotateIgnoreWritesEnd(__FILE__, __LINE__) #undef ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \ do { \ ANNOTATE_IGNORE_READS_BEGIN(); \ ANNOTATE_IGNORE_WRITES_BEGIN(); \ }while(0) \ #undef ANNOTATE_IGNORE_READS_AND_WRITES_END #define ANNOTATE_IGNORE_READS_AND_WRITES_END() \ do { \ ANNOTATE_IGNORE_WRITES_END(); \ ANNOTATE_IGNORE_READS_END(); \ }while(0) \ #if defined(__cplusplus) #undef ANNOTATE_UNPROTECTED_READ template inline T ANNOTATE_UNPROTECTED_READ(const volatile T &x) __attribute__ ((unprotected_read)) { ANNOTATE_IGNORE_READS_BEGIN(); T res = x; ANNOTATE_IGNORE_READS_END(); return res; } #endif /* __cplusplus */ #endif /* ANNOTALYSIS_ONLY */ /* Undefine the macros intended only in this file. */ #undef ANNOTALYSIS_STATIC_INLINE #undef ANNOTALYSIS_SEMICOLON_OR_EMPTY_BODY #endif /* BASE_DYNAMIC_ANNOTATIONS_H_ */ ================================================ FILE: distro/google-perftools-1.7/src/base/elfcore.h ================================================ /* Copyright (c) 2005-2008, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Markus Gutschke, Carl Crous */ #ifndef _ELFCORE_H #define _ELFCORE_H #ifdef __cplusplus extern "C" { #endif /* We currently only support x86-32, x86-64, ARM, and MIPS on Linux. * Porting to other related platforms should not be difficult. */ #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) || \ defined(__mips__)) && defined(__linux) #include #include #include #include /* Define the DUMPER symbol to make sure that there is exactly one * core dumper built into the library. */ #define DUMPER "ELF" /* By the time that we get a chance to read CPU registers in the * calling thread, they are already in a not particularly useful * state. Besides, there will be multiple frames on the stack that are * just making the core file confusing. To fix this problem, we take a * snapshot of the frame pointer, stack pointer, and instruction * pointer at an earlier time, and then insert these values into the * core file. */ #if defined(__i386__) || defined(__x86_64__) typedef struct i386_regs { /* Normal (non-FPU) CPU registers */ #ifdef __x86_64__ #define BP rbp #define SP rsp #define IP rip uint64_t r15,r14,r13,r12,rbp,rbx,r11,r10; uint64_t r9,r8,rax,rcx,rdx,rsi,rdi,orig_rax; uint64_t rip,cs,eflags; uint64_t rsp,ss; uint64_t fs_base, gs_base; uint64_t ds,es,fs,gs; #else #define BP ebp #define SP esp #define IP eip uint32_t ebx, ecx, edx, esi, edi, ebp, eax; uint16_t ds, __ds, es, __es; uint16_t fs, __fs, gs, __gs; uint32_t orig_eax, eip; uint16_t cs, __cs; uint32_t eflags, esp; uint16_t ss, __ss; #endif } i386_regs; #elif defined(__ARM_ARCH_3__) typedef struct arm_regs { /* General purpose registers */ #define BP uregs[11] /* Frame pointer */ #define SP uregs[13] /* Stack pointer */ #define IP uregs[15] /* Program counter */ #define LR uregs[14] /* Link register */ long uregs[18]; } arm_regs; #elif defined(__mips__) typedef struct mips_regs { unsigned long pad[6]; /* Unused padding to match kernel structures */ unsigned long uregs[32]; /* General purpose registers. */ unsigned long hi; /* Used for multiplication and division. */ unsigned long lo; unsigned long cp0_epc; /* Program counter. */ unsigned long cp0_badvaddr; unsigned long cp0_status; unsigned long cp0_cause; unsigned long unused; } mips_regs; #endif #if defined(__i386__) && defined(__GNUC__) /* On x86 we provide an optimized version of the FRAME() macro, if the * compiler supports a GCC-style asm() directive. This results in somewhat * more accurate values for CPU registers. */ typedef struct Frame { struct i386_regs uregs; int errno_; pid_t tid; } Frame; #define FRAME(f) Frame f; \ do { \ f.errno_ = errno; \ f.tid = sys_gettid(); \ __asm__ volatile ( \ "push %%ebp\n" \ "push %%ebx\n" \ "mov %%ebx,0(%%eax)\n" \ "mov %%ecx,4(%%eax)\n" \ "mov %%edx,8(%%eax)\n" \ "mov %%esi,12(%%eax)\n" \ "mov %%edi,16(%%eax)\n" \ "mov %%ebp,20(%%eax)\n" \ "mov %%eax,24(%%eax)\n" \ "mov %%ds,%%ebx\n" \ "mov %%ebx,28(%%eax)\n" \ "mov %%es,%%ebx\n" \ "mov %%ebx,32(%%eax)\n" \ "mov %%fs,%%ebx\n" \ "mov %%ebx,36(%%eax)\n" \ "mov %%gs,%%ebx\n" \ "mov %%ebx, 40(%%eax)\n" \ "call 0f\n" \ "0:pop %%ebx\n" \ "add $1f-0b,%%ebx\n" \ "mov %%ebx,48(%%eax)\n" \ "mov %%cs,%%ebx\n" \ "mov %%ebx,52(%%eax)\n" \ "pushf\n" \ "pop %%ebx\n" \ "mov %%ebx,56(%%eax)\n" \ "mov %%esp,%%ebx\n" \ "add $8,%%ebx\n" \ "mov %%ebx,60(%%eax)\n" \ "mov %%ss,%%ebx\n" \ "mov %%ebx,64(%%eax)\n" \ "pop %%ebx\n" \ "pop %%ebp\n" \ "1:" \ : : "a" (&f) : "memory"); \ } while (0) #define SET_FRAME(f,r) \ do { \ errno = (f).errno_; \ (r) = (f).uregs; \ } while (0) #elif defined(__x86_64__) && defined(__GNUC__) /* The FRAME and SET_FRAME macros for x86_64. */ typedef struct Frame { struct i386_regs uregs; int errno_; pid_t tid; } Frame; #define FRAME(f) Frame f; \ do { \ f.errno_ = errno; \ f.tid = sys_gettid(); \ __asm__ volatile ( \ "push %%rbp\n" \ "push %%rbx\n" \ "mov %%r15,0(%%rax)\n" \ "mov %%r14,8(%%rax)\n" \ "mov %%r13,16(%%rax)\n" \ "mov %%r12,24(%%rax)\n" \ "mov %%rbp,32(%%rax)\n" \ "mov %%rbx,40(%%rax)\n" \ "mov %%r11,48(%%rax)\n" \ "mov %%r10,56(%%rax)\n" \ "mov %%r9,64(%%rax)\n" \ "mov %%r8,72(%%rax)\n" \ "mov %%rax,80(%%rax)\n" \ "mov %%rcx,88(%%rax)\n" \ "mov %%rdx,96(%%rax)\n" \ "mov %%rsi,104(%%rax)\n" \ "mov %%rdi,112(%%rax)\n" \ "mov %%ds,%%rbx\n" \ "mov %%rbx,184(%%rax)\n" \ "mov %%es,%%rbx\n" \ "mov %%rbx,192(%%rax)\n" \ "mov %%fs,%%rbx\n" \ "mov %%rbx,200(%%rax)\n" \ "mov %%gs,%%rbx\n" \ "mov %%rbx,208(%%rax)\n" \ "call 0f\n" \ "0:pop %%rbx\n" \ "add $1f-0b,%%rbx\n" \ "mov %%rbx,128(%%rax)\n" \ "mov %%cs,%%rbx\n" \ "mov %%rbx,136(%%rax)\n" \ "pushf\n" \ "pop %%rbx\n" \ "mov %%rbx,144(%%rax)\n" \ "mov %%rsp,%%rbx\n" \ "add $16,%%ebx\n" \ "mov %%rbx,152(%%rax)\n" \ "mov %%ss,%%rbx\n" \ "mov %%rbx,160(%%rax)\n" \ "pop %%rbx\n" \ "pop %%rbp\n" \ "1:" \ : : "a" (&f) : "memory"); \ } while (0) #define SET_FRAME(f,r) \ do { \ errno = (f).errno_; \ (f).uregs.fs_base = (r).fs_base; \ (f).uregs.gs_base = (r).gs_base; \ (r) = (f).uregs; \ } while (0) #elif defined(__ARM_ARCH_3__) && defined(__GNUC__) /* ARM calling conventions are a little more tricky. A little assembly * helps in obtaining an accurate snapshot of all registers. */ typedef struct Frame { struct arm_regs arm; int errno_; pid_t tid; } Frame; #define FRAME(f) Frame f; \ do { \ long cpsr; \ f.errno_ = errno; \ f.tid = sys_gettid(); \ __asm__ volatile( \ "stmia %0, {r0-r15}\n" /* All integer regs */\ : : "r"(&f.arm) : "memory"); \ f.arm.uregs[16] = 0; \ __asm__ volatile( \ "mrs %0, cpsr\n" /* Condition code reg */\ : "=r"(cpsr)); \ f.arm.uregs[17] = cpsr; \ } while (0) #define SET_FRAME(f,r) \ do { \ /* Don't override the FPU status register. */\ /* Use the value obtained from ptrace(). This*/\ /* works, because our code does not perform */\ /* any FPU operations, itself. */\ long fps = (f).arm.uregs[16]; \ errno = (f).errno_; \ (r) = (f).arm; \ (r).uregs[16] = fps; \ } while (0) #elif defined(__mips__) && defined(__GNUC__) typedef struct Frame { struct mips_regs mips_regs; int errno_; pid_t tid; } Frame; #define MIPSREG(n) ({ register unsigned long r __asm__("$"#n); r; }) #define FRAME(f) Frame f = { 0 }; \ do { \ unsigned long hi, lo; \ register unsigned long pc __asm__("$31"); \ f.mips_regs.uregs[ 0] = MIPSREG( 0); \ f.mips_regs.uregs[ 1] = MIPSREG( 1); \ f.mips_regs.uregs[ 2] = MIPSREG( 2); \ f.mips_regs.uregs[ 3] = MIPSREG( 3); \ f.mips_regs.uregs[ 4] = MIPSREG( 4); \ f.mips_regs.uregs[ 5] = MIPSREG( 5); \ f.mips_regs.uregs[ 6] = MIPSREG( 6); \ f.mips_regs.uregs[ 7] = MIPSREG( 7); \ f.mips_regs.uregs[ 8] = MIPSREG( 8); \ f.mips_regs.uregs[ 9] = MIPSREG( 9); \ f.mips_regs.uregs[10] = MIPSREG(10); \ f.mips_regs.uregs[11] = MIPSREG(11); \ f.mips_regs.uregs[12] = MIPSREG(12); \ f.mips_regs.uregs[13] = MIPSREG(13); \ f.mips_regs.uregs[14] = MIPSREG(14); \ f.mips_regs.uregs[15] = MIPSREG(15); \ f.mips_regs.uregs[16] = MIPSREG(16); \ f.mips_regs.uregs[17] = MIPSREG(17); \ f.mips_regs.uregs[18] = MIPSREG(18); \ f.mips_regs.uregs[19] = MIPSREG(19); \ f.mips_regs.uregs[20] = MIPSREG(20); \ f.mips_regs.uregs[21] = MIPSREG(21); \ f.mips_regs.uregs[22] = MIPSREG(22); \ f.mips_regs.uregs[23] = MIPSREG(23); \ f.mips_regs.uregs[24] = MIPSREG(24); \ f.mips_regs.uregs[25] = MIPSREG(25); \ f.mips_regs.uregs[26] = MIPSREG(26); \ f.mips_regs.uregs[27] = MIPSREG(27); \ f.mips_regs.uregs[28] = MIPSREG(28); \ f.mips_regs.uregs[29] = MIPSREG(29); \ f.mips_regs.uregs[30] = MIPSREG(30); \ f.mips_regs.uregs[31] = MIPSREG(31); \ __asm__ volatile ("mfhi %0" : "=r"(hi)); \ __asm__ volatile ("mflo %0" : "=r"(lo)); \ __asm__ volatile ("jal 1f; 1:nop" : "=r"(pc)); \ f.mips_regs.hi = hi; \ f.mips_regs.lo = lo; \ f.mips_regs.cp0_epc = pc; \ f.errno_ = errno; \ f.tid = sys_gettid(); \ } while (0) #define SET_FRAME(f,r) \ do { \ errno = (f).errno_; \ memcpy((r).uregs, (f).mips_regs.uregs, \ 32*sizeof(unsigned long)); \ (r).hi = (f).mips_regs.hi; \ (r).lo = (f).mips_regs.lo; \ (r).cp0_epc = (f).mips_regs.cp0_epc; \ } while (0) #else /* If we do not have a hand-optimized assembly version of the FRAME() * macro, we cannot reliably unroll the stack. So, we show a few additional * stack frames for the coredumper. */ typedef struct Frame { pid_t tid; } Frame; #define FRAME(f) Frame f; do { f.tid = sys_gettid(); } while (0) #define SET_FRAME(f,r) do { } while (0) #endif /* Internal function for generating a core file. This API can change without * notice and is only supposed to be used internally by the core dumper. * * This function works for both single- and multi-threaded core * dumps. If called as * * FRAME(frame); * InternalGetCoreDump(&frame, 0, NULL, ap); * * it creates a core file that only contains information about the * calling thread. * * Optionally, the caller can provide information about other threads * by passing their process ids in "thread_pids". The process id of * the caller should not be included in this array. All of the threads * must have been attached to with ptrace(), prior to calling this * function. They will be detached when "InternalGetCoreDump()" returns. * * This function either returns a file handle that can be read for obtaining * a core dump, or "-1" in case of an error. In the latter case, "errno" * will be set appropriately. * * While "InternalGetCoreDump()" is not technically async signal safe, you * might be tempted to invoke it from a signal handler. The code goes to * great lengths to make a best effort that this will actually work. But in * any case, you must make sure that you preserve the value of "errno" * yourself. It is guaranteed to be clobbered otherwise. * * Also, "InternalGetCoreDump" is not strictly speaking re-entrant. Again, * it makes a best effort to behave reasonably when called in a multi- * threaded environment, but it is ultimately the caller's responsibility * to provide locking. */ int InternalGetCoreDump(void *frame, int num_threads, pid_t *thread_pids, va_list ap /* const struct CoreDumpParameters *params, const char *file_name, const char *PATH */); #endif #ifdef __cplusplus } #endif #endif /* _ELFCORE_H */ ================================================ FILE: distro/google-perftools-1.7/src/base/googleinit.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Jacob Hoffman-Andrews #ifndef _GOOGLEINIT_H #define _GOOGLEINIT_H class GoogleInitializer { public: typedef void (*void_function)(void); GoogleInitializer(const char* name, void_function f) { f(); } }; #define REGISTER_MODULE_INITIALIZER(name, body) \ namespace { \ static void google_init_module_##name () { body; } \ GoogleInitializer google_initializer_module_##name(#name, \ google_init_module_##name); \ } #endif /* _GOOGLEINIT_H */ ================================================ FILE: distro/google-perftools-1.7/src/base/linux_syscall_support.h ================================================ /* Copyright (c) 2005-2008, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Markus Gutschke */ /* This file includes Linux-specific support functions common to the * coredumper and the thread lister; primarily, this is a collection * of direct system calls, and a couple of symbols missing from * standard header files. * There are a few options that the including file can set to control * the behavior of this file: * * SYS_CPLUSPLUS: * The entire header file will normally be wrapped in 'extern "C" { }", * making it suitable for compilation as both C and C++ source. If you * do not want to do this, you can set the SYS_CPLUSPLUS macro to inhibit * the wrapping. N.B. doing so will suppress inclusion of all prerequisite * system header files, too. It is the caller's responsibility to provide * the necessary definitions. * * SYS_ERRNO: * All system calls will update "errno" unless overriden by setting the * SYS_ERRNO macro prior to including this file. SYS_ERRNO should be * an l-value. * * SYS_INLINE: * New symbols will be defined "static inline", unless overridden by * the SYS_INLINE macro. * * SYS_LINUX_SYSCALL_SUPPORT_H * This macro is used to avoid multiple inclusions of this header file. * If you need to include this file more than once, make sure to * unset SYS_LINUX_SYSCALL_SUPPORT_H before each inclusion. * * SYS_PREFIX: * New system calls will have a prefix of "sys_" unless overridden by * the SYS_PREFIX macro. Valid values for this macro are [0..9] which * results in prefixes "sys[0..9]_". It is also possible to set this * macro to -1, which avoids all prefixes. * * This file defines a few internal symbols that all start with "LSS_". * Do not access these symbols from outside this file. They are not part * of the supported API. */ #ifndef SYS_LINUX_SYSCALL_SUPPORT_H #define SYS_LINUX_SYSCALL_SUPPORT_H /* We currently only support x86-32, x86-64, ARM, MIPS, and PPC on Linux. * Porting to other related platforms should not be difficult. */ #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) || \ defined(__mips__) || defined(__PPC__)) && defined(__linux) #ifndef SYS_CPLUSPLUS #ifdef __cplusplus /* Some system header files in older versions of gcc neglect to properly * handle being included from C++. As it appears to be harmless to have * multiple nested 'extern "C"' blocks, just add another one here. */ extern "C" { #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __mips__ /* Include definitions of the ABI currently in use. */ #include #endif #endif /* As glibc often provides subtly incompatible data structures (and implicit * wrapper functions that convert them), we provide our own kernel data * structures for use by the system calls. * These structures have been developed by using Linux 2.6.23 headers for * reference. Note though, we do not care about exact API compatibility * with the kernel, and in fact the kernel often does not have a single * API that works across architectures. Instead, we try to mimic the glibc * API where reasonable, and only guarantee ABI compatibility with the * kernel headers. * Most notably, here are a few changes that were made to the structures * defined by kernel headers: * * - we only define structures, but not symbolic names for kernel data * types. For the latter, we directly use the native C datatype * (i.e. "unsigned" instead of "mode_t"). * - in a few cases, it is possible to define identical structures for * both 32bit (e.g. i386) and 64bit (e.g. x86-64) platforms by * standardizing on the 64bit version of the data types. In particular, * this means that we use "unsigned" where the 32bit headers say * "unsigned long". * - overall, we try to minimize the number of cases where we need to * conditionally define different structures. * - the "struct kernel_sigaction" class of structures have been * modified to more closely mimic glibc's API by introducing an * anonymous union for the function pointer. * - a small number of field names had to have an underscore appended to * them, because glibc defines a global macro by the same name. */ /* include/linux/dirent.h */ struct kernel_dirent64 { unsigned long long d_ino; long long d_off; unsigned short d_reclen; unsigned char d_type; char d_name[256]; }; /* include/linux/dirent.h */ struct kernel_dirent { long d_ino; long d_off; unsigned short d_reclen; char d_name[256]; }; /* include/linux/uio.h */ struct kernel_iovec { void *iov_base; unsigned long iov_len; }; /* include/linux/socket.h */ struct kernel_msghdr { void *msg_name; int msg_namelen; struct kernel_iovec*msg_iov; unsigned long msg_iovlen; void *msg_control; unsigned long msg_controllen; unsigned msg_flags; }; /* include/asm-generic/poll.h */ struct kernel_pollfd { int fd; short events; short revents; }; /* include/linux/resource.h */ struct kernel_rlimit { unsigned long rlim_cur; unsigned long rlim_max; }; /* include/linux/time.h */ struct kernel_timespec { long tv_sec; long tv_nsec; }; /* include/linux/time.h */ struct kernel_timeval { long tv_sec; long tv_usec; }; /* include/linux/resource.h */ struct kernel_rusage { struct kernel_timeval ru_utime; struct kernel_timeval ru_stime; long ru_maxrss; long ru_ixrss; long ru_idrss; long ru_isrss; long ru_minflt; long ru_majflt; long ru_nswap; long ru_inblock; long ru_oublock; long ru_msgsnd; long ru_msgrcv; long ru_nsignals; long ru_nvcsw; long ru_nivcsw; }; struct siginfo; #if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__PPC__) /* include/asm-{arm,i386,mips,ppc}/signal.h */ struct kernel_old_sigaction { union { void (*sa_handler_)(int); void (*sa_sigaction_)(int, struct siginfo *, void *); }; unsigned long sa_mask; unsigned long sa_flags; void (*sa_restorer)(void); } __attribute__((packed,aligned(4))); #elif (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) #define kernel_old_sigaction kernel_sigaction #endif /* Some kernel functions (e.g. sigaction() in 2.6.23) require that the * exactly match the size of the signal set, even though the API was * intended to be extensible. We define our own KERNEL_NSIG to deal with * this. * Please note that glibc provides signals [1.._NSIG-1], whereas the * kernel (and this header) provides the range [1..KERNEL_NSIG]. The * actual number of signals is obviously the same, but the constants * differ by one. */ #ifdef __mips__ #define KERNEL_NSIG 128 #else #define KERNEL_NSIG 64 #endif /* include/asm-{arm,i386,mips,x86_64}/signal.h */ struct kernel_sigset_t { unsigned long sig[(KERNEL_NSIG + 8*sizeof(unsigned long) - 1)/ (8*sizeof(unsigned long))]; }; /* include/asm-{arm,i386,mips,x86_64,ppc}/signal.h */ struct kernel_sigaction { #ifdef __mips__ unsigned long sa_flags; union { void (*sa_handler_)(int); void (*sa_sigaction_)(int, struct siginfo *, void *); }; struct kernel_sigset_t sa_mask; #else union { void (*sa_handler_)(int); void (*sa_sigaction_)(int, struct siginfo *, void *); }; unsigned long sa_flags; void (*sa_restorer)(void); struct kernel_sigset_t sa_mask; #endif }; /* include/linux/socket.h */ struct kernel_sockaddr { unsigned short sa_family; char sa_data[14]; }; /* include/asm-{arm,i386,mips,ppc}/stat.h */ #ifdef __mips__ #if _MIPS_SIM == _MIPS_SIM_ABI64 struct kernel_stat { #else struct kernel_stat64 { #endif unsigned st_dev; unsigned __pad0[3]; unsigned long long st_ino; unsigned st_mode; unsigned st_nlink; unsigned st_uid; unsigned st_gid; unsigned st_rdev; unsigned __pad1[3]; long long st_size; unsigned st_atime_; unsigned st_atime_nsec_; unsigned st_mtime_; unsigned st_mtime_nsec_; unsigned st_ctime_; unsigned st_ctime_nsec_; unsigned st_blksize; unsigned __pad2; unsigned long long st_blocks; }; #elif defined __PPC__ struct kernel_stat64 { unsigned long long st_dev; unsigned long long st_ino; unsigned st_mode; unsigned st_nlink; unsigned st_uid; unsigned st_gid; unsigned long long st_rdev; unsigned short int __pad2; long long st_size; long st_blksize; long long st_blocks; long st_atime_; unsigned long st_atime_nsec_; long st_mtime_; unsigned long st_mtime_nsec_; long st_ctime_; unsigned long st_ctime_nsec_; unsigned long __unused4; unsigned long __unused5; }; #else struct kernel_stat64 { unsigned long long st_dev; unsigned char __pad0[4]; unsigned __st_ino; unsigned st_mode; unsigned st_nlink; unsigned st_uid; unsigned st_gid; unsigned long long st_rdev; unsigned char __pad3[4]; long long st_size; unsigned st_blksize; unsigned long long st_blocks; unsigned st_atime_; unsigned st_atime_nsec_; unsigned st_mtime_; unsigned st_mtime_nsec_; unsigned st_ctime_; unsigned st_ctime_nsec_; unsigned long long st_ino; }; #endif /* include/asm-{arm,i386,mips,x86_64,ppc}/stat.h */ #if defined(__i386__) || defined(__ARM_ARCH_3__) struct kernel_stat { /* The kernel headers suggest that st_dev and st_rdev should be 32bit * quantities encoding 12bit major and 20bit minor numbers in an interleaved * format. In reality, we do not see useful data in the top bits. So, * we'll leave the padding in here, until we find a better solution. */ unsigned short st_dev; short pad1; unsigned st_ino; unsigned short st_mode; unsigned short st_nlink; unsigned short st_uid; unsigned short st_gid; unsigned short st_rdev; short pad2; unsigned st_size; unsigned st_blksize; unsigned st_blocks; unsigned st_atime_; unsigned st_atime_nsec_; unsigned st_mtime_; unsigned st_mtime_nsec_; unsigned st_ctime_; unsigned st_ctime_nsec_; unsigned __unused4; unsigned __unused5; }; #elif defined(__x86_64__) struct kernel_stat { unsigned long st_dev; unsigned long st_ino; unsigned long st_nlink; unsigned st_mode; unsigned st_uid; unsigned st_gid; unsigned __pad0; unsigned long st_rdev; long st_size; long st_blksize; long st_blocks; unsigned long st_atime_; unsigned long st_atime_nsec_; unsigned long st_mtime_; unsigned long st_mtime_nsec_; unsigned long st_ctime_; unsigned long st_ctime_nsec_; long __unused[3]; }; #elif defined(__PPC__) struct kernel_stat { unsigned st_dev; unsigned long st_ino; // ino_t unsigned long st_mode; // mode_t unsigned short st_nlink; // nlink_t unsigned st_uid; // uid_t unsigned st_gid; // gid_t unsigned st_rdev; long st_size; // off_t unsigned long st_blksize; unsigned long st_blocks; unsigned long st_atime_; unsigned long st_atime_nsec_; unsigned long st_mtime_; unsigned long st_mtime_nsec_; unsigned long st_ctime_; unsigned long st_ctime_nsec_; unsigned long __unused4; unsigned long __unused5; }; #elif (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI64) struct kernel_stat { unsigned st_dev; int st_pad1[3]; unsigned st_ino; unsigned st_mode; unsigned st_nlink; unsigned st_uid; unsigned st_gid; unsigned st_rdev; int st_pad2[2]; long st_size; int st_pad3; long st_atime_; long st_atime_nsec_; long st_mtime_; long st_mtime_nsec_; long st_ctime_; long st_ctime_nsec_; int st_blksize; int st_blocks; int st_pad4[14]; }; #endif /* include/asm-{arm,i386,mips,x86_64,ppc}/statfs.h */ #ifdef __mips__ #if _MIPS_SIM != _MIPS_SIM_ABI64 struct kernel_statfs64 { unsigned long f_type; unsigned long f_bsize; unsigned long f_frsize; unsigned long __pad; unsigned long long f_blocks; unsigned long long f_bfree; unsigned long long f_files; unsigned long long f_ffree; unsigned long long f_bavail; struct { int val[2]; } f_fsid; unsigned long f_namelen; unsigned long f_spare[6]; }; #endif #elif !defined(__x86_64__) struct kernel_statfs64 { unsigned long f_type; unsigned long f_bsize; unsigned long long f_blocks; unsigned long long f_bfree; unsigned long long f_bavail; unsigned long long f_files; unsigned long long f_ffree; struct { int val[2]; } f_fsid; unsigned long f_namelen; unsigned long f_frsize; unsigned long f_spare[5]; }; #endif /* include/asm-{arm,i386,mips,x86_64,ppc,generic}/statfs.h */ #ifdef __mips__ struct kernel_statfs { long f_type; long f_bsize; long f_frsize; long f_blocks; long f_bfree; long f_files; long f_ffree; long f_bavail; struct { int val[2]; } f_fsid; long f_namelen; long f_spare[6]; }; #else struct kernel_statfs { /* x86_64 actually defines all these fields as signed, whereas all other */ /* platforms define them as unsigned. Leaving them at unsigned should not */ /* cause any problems. */ unsigned long f_type; unsigned long f_bsize; unsigned long f_blocks; unsigned long f_bfree; unsigned long f_bavail; unsigned long f_files; unsigned long f_ffree; struct { int val[2]; } f_fsid; unsigned long f_namelen; unsigned long f_frsize; unsigned long f_spare[5]; }; #endif /* Definitions missing from the standard header files */ #ifndef O_DIRECTORY #if defined(__ARM_ARCH_3__) #define O_DIRECTORY 0040000 #else #define O_DIRECTORY 0200000 #endif #endif #ifndef NT_PRXFPREG #define NT_PRXFPREG 0x46e62b7f #endif #ifndef PTRACE_GETFPXREGS #define PTRACE_GETFPXREGS ((enum __ptrace_request)18) #endif #ifndef PR_GET_DUMPABLE #define PR_GET_DUMPABLE 3 #endif #ifndef PR_SET_DUMPABLE #define PR_SET_DUMPABLE 4 #endif #ifndef AT_FDCWD #define AT_FDCWD (-100) #endif #ifndef AT_SYMLINK_NOFOLLOW #define AT_SYMLINK_NOFOLLOW 0x100 #endif #ifndef AT_REMOVEDIR #define AT_REMOVEDIR 0x200 #endif #ifndef MREMAP_FIXED #define MREMAP_FIXED 2 #endif #ifndef SA_RESTORER #define SA_RESTORER 0x04000000 #endif #ifndef CPUCLOCK_PROF #define CPUCLOCK_PROF 0 #endif #ifndef CPUCLOCK_VIRT #define CPUCLOCK_VIRT 1 #endif #ifndef CPUCLOCK_SCHED #define CPUCLOCK_SCHED 2 #endif #ifndef CPUCLOCK_PERTHREAD_MASK #define CPUCLOCK_PERTHREAD_MASK 4 #endif #ifndef MAKE_PROCESS_CPUCLOCK #define MAKE_PROCESS_CPUCLOCK(pid, clock) \ ((~(int)(pid) << 3) | (int)(clock)) #endif #ifndef MAKE_THREAD_CPUCLOCK #define MAKE_THREAD_CPUCLOCK(tid, clock) \ ((~(int)(tid) << 3) | (int)((clock) | CPUCLOCK_PERTHREAD_MASK)) #endif #if defined(__i386__) #ifndef __NR_setresuid #define __NR_setresuid 164 #define __NR_setresgid 170 #endif #ifndef __NR_rt_sigaction #define __NR_rt_sigaction 174 #define __NR_rt_sigprocmask 175 #define __NR_rt_sigpending 176 #define __NR_rt_sigsuspend 179 #endif #ifndef __NR_pread64 #define __NR_pread64 180 #endif #ifndef __NR_pwrite64 #define __NR_pwrite64 181 #endif #ifndef __NR_ugetrlimit #define __NR_ugetrlimit 191 #endif #ifndef __NR_stat64 #define __NR_stat64 195 #endif #ifndef __NR_fstat64 #define __NR_fstat64 197 #endif #ifndef __NR_setresuid32 #define __NR_setresuid32 208 #define __NR_setresgid32 210 #endif #ifndef __NR_setfsuid32 #define __NR_setfsuid32 215 #define __NR_setfsgid32 216 #endif #ifndef __NR_getdents64 #define __NR_getdents64 220 #endif #ifndef __NR_gettid #define __NR_gettid 224 #endif #ifndef __NR_readahead #define __NR_readahead 225 #endif #ifndef __NR_setxattr #define __NR_setxattr 226 #endif #ifndef __NR_lsetxattr #define __NR_lsetxattr 227 #endif #ifndef __NR_getxattr #define __NR_getxattr 229 #endif #ifndef __NR_lgetxattr #define __NR_lgetxattr 230 #endif #ifndef __NR_listxattr #define __NR_listxattr 232 #endif #ifndef __NR_llistxattr #define __NR_llistxattr 233 #endif #ifndef __NR_futex #define __NR_futex 240 #endif #ifndef __NR_sched_setaffinity #define __NR_sched_setaffinity 241 #define __NR_sched_getaffinity 242 #endif #ifndef __NR_set_tid_address #define __NR_set_tid_address 258 #endif #ifndef __NR_clock_gettime #define __NR_clock_gettime 265 #endif #ifndef __NR_clock_getres #define __NR_clock_getres 266 #endif #ifndef __NR_statfs64 #define __NR_statfs64 268 #endif #ifndef __NR_fstatfs64 #define __NR_fstatfs64 269 #endif #ifndef __NR_fadvise64_64 #define __NR_fadvise64_64 272 #endif #ifndef __NR_ioprio_set #define __NR_ioprio_set 289 #endif #ifndef __NR_ioprio_get #define __NR_ioprio_get 290 #endif #ifndef __NR_openat #define __NR_openat 295 #endif #ifndef __NR_fstatat64 #define __NR_fstatat64 300 #endif #ifndef __NR_unlinkat #define __NR_unlinkat 301 #endif #ifndef __NR_move_pages #define __NR_move_pages 317 #endif #ifndef __NR_getcpu #define __NR_getcpu 318 #endif #ifndef __NR_fallocate #define __NR_fallocate 324 #endif /* End of i386 definitions */ #elif defined(__ARM_ARCH_3__) #ifndef __NR_setresuid #define __NR_setresuid (__NR_SYSCALL_BASE + 164) #define __NR_setresgid (__NR_SYSCALL_BASE + 170) #endif #ifndef __NR_rt_sigaction #define __NR_rt_sigaction (__NR_SYSCALL_BASE + 174) #define __NR_rt_sigprocmask (__NR_SYSCALL_BASE + 175) #define __NR_rt_sigpending (__NR_SYSCALL_BASE + 176) #define __NR_rt_sigsuspend (__NR_SYSCALL_BASE + 179) #endif #ifndef __NR_pread64 #define __NR_pread64 (__NR_SYSCALL_BASE + 180) #endif #ifndef __NR_pwrite64 #define __NR_pwrite64 (__NR_SYSCALL_BASE + 181) #endif #ifndef __NR_ugetrlimit #define __NR_ugetrlimit (__NR_SYSCALL_BASE + 191) #endif #ifndef __NR_stat64 #define __NR_stat64 (__NR_SYSCALL_BASE + 195) #endif #ifndef __NR_fstat64 #define __NR_fstat64 (__NR_SYSCALL_BASE + 197) #endif #ifndef __NR_setresuid32 #define __NR_setresuid32 (__NR_SYSCALL_BASE + 208) #define __NR_setresgid32 (__NR_SYSCALL_BASE + 210) #endif #ifndef __NR_setfsuid32 #define __NR_setfsuid32 (__NR_SYSCALL_BASE + 215) #define __NR_setfsgid32 (__NR_SYSCALL_BASE + 216) #endif #ifndef __NR_getdents64 #define __NR_getdents64 (__NR_SYSCALL_BASE + 217) #endif #ifndef __NR_gettid #define __NR_gettid (__NR_SYSCALL_BASE + 224) #endif #ifndef __NR_readahead #define __NR_readahead (__NR_SYSCALL_BASE + 225) #endif #ifndef __NR_setxattr #define __NR_setxattr (__NR_SYSCALL_BASE + 226) #endif #ifndef __NR_lsetxattr #define __NR_lsetxattr (__NR_SYSCALL_BASE + 227) #endif #ifndef __NR_getxattr #define __NR_getxattr (__NR_SYSCALL_BASE + 229) #endif #ifndef __NR_lgetxattr #define __NR_lgetxattr (__NR_SYSCALL_BASE + 230) #endif #ifndef __NR_listxattr #define __NR_listxattr (__NR_SYSCALL_BASE + 232) #endif #ifndef __NR_llistxattr #define __NR_llistxattr (__NR_SYSCALL_BASE + 233) #endif #ifndef __NR_futex #define __NR_futex (__NR_SYSCALL_BASE + 240) #endif #ifndef __NR_sched_setaffinity #define __NR_sched_setaffinity (__NR_SYSCALL_BASE + 241) #define __NR_sched_getaffinity (__NR_SYSCALL_BASE + 242) #endif #ifndef __NR_set_tid_address #define __NR_set_tid_address (__NR_SYSCALL_BASE + 256) #endif #ifndef __NR_clock_gettime #define __NR_clock_gettime (__NR_SYSCALL_BASE + 263) #endif #ifndef __NR_clock_getres #define __NR_clock_getres (__NR_SYSCALL_BASE + 264) #endif #ifndef __NR_statfs64 #define __NR_statfs64 (__NR_SYSCALL_BASE + 266) #endif #ifndef __NR_fstatfs64 #define __NR_fstatfs64 (__NR_SYSCALL_BASE + 267) #endif #ifndef __NR_ioprio_set #define __NR_ioprio_set (__NR_SYSCALL_BASE + 314) #endif #ifndef __NR_ioprio_get #define __NR_ioprio_get (__NR_SYSCALL_BASE + 315) #endif #ifndef __NR_move_pages #define __NR_move_pages (__NR_SYSCALL_BASE + 344) #endif #ifndef __NR_getcpu #define __NR_getcpu (__NR_SYSCALL_BASE + 345) #endif /* End of ARM 3 definitions */ #elif defined(__x86_64__) #ifndef __NR_pread64 #define __NR_pread64 17 #endif #ifndef __NR_pwrite64 #define __NR_pwrite64 18 #endif #ifndef __NR_setresuid #define __NR_setresuid 117 #define __NR_setresgid 119 #endif #ifndef __NR_gettid #define __NR_gettid 186 #endif #ifndef __NR_readahead #define __NR_readahead 187 #endif #ifndef __NR_setxattr #define __NR_setxattr 188 #endif #ifndef __NR_lsetxattr #define __NR_lsetxattr 189 #endif #ifndef __NR_getxattr #define __NR_getxattr 191 #endif #ifndef __NR_lgetxattr #define __NR_lgetxattr 192 #endif #ifndef __NR_listxattr #define __NR_listxattr 194 #endif #ifndef __NR_llistxattr #define __NR_llistxattr 195 #endif #ifndef __NR_futex #define __NR_futex 202 #endif #ifndef __NR_sched_setaffinity #define __NR_sched_setaffinity 203 #define __NR_sched_getaffinity 204 #endif #ifndef __NR_getdents64 #define __NR_getdents64 217 #endif #ifndef __NR_set_tid_address #define __NR_set_tid_address 218 #endif #ifndef __NR_fadvise64 #define __NR_fadvise64 221 #endif #ifndef __NR_clock_gettime #define __NR_clock_gettime 228 #endif #ifndef __NR_clock_getres #define __NR_clock_getres 229 #endif #ifndef __NR_ioprio_set #define __NR_ioprio_set 251 #endif #ifndef __NR_ioprio_get #define __NR_ioprio_get 252 #endif #ifndef __NR_openat #define __NR_openat 257 #endif #ifndef __NR_newfstatat #define __NR_newfstatat 262 #endif #ifndef __NR_unlinkat #define __NR_unlinkat 263 #endif #ifndef __NR_move_pages #define __NR_move_pages 279 #endif #ifndef __NR_fallocate #define __NR_fallocate 285 #endif /* End of x86-64 definitions */ #elif defined(__mips__) #if _MIPS_SIM == _MIPS_SIM_ABI32 #ifndef __NR_setresuid #define __NR_setresuid (__NR_Linux + 185) #define __NR_setresgid (__NR_Linux + 190) #endif #ifndef __NR_rt_sigaction #define __NR_rt_sigaction (__NR_Linux + 194) #define __NR_rt_sigprocmask (__NR_Linux + 195) #define __NR_rt_sigpending (__NR_Linux + 196) #define __NR_rt_sigsuspend (__NR_Linux + 199) #endif #ifndef __NR_pread64 #define __NR_pread64 (__NR_Linux + 200) #endif #ifndef __NR_pwrite64 #define __NR_pwrite64 (__NR_Linux + 201) #endif #ifndef __NR_stat64 #define __NR_stat64 (__NR_Linux + 213) #endif #ifndef __NR_fstat64 #define __NR_fstat64 (__NR_Linux + 215) #endif #ifndef __NR_getdents64 #define __NR_getdents64 (__NR_Linux + 219) #endif #ifndef __NR_gettid #define __NR_gettid (__NR_Linux + 222) #endif #ifndef __NR_readahead #define __NR_readahead (__NR_Linux + 223) #endif #ifndef __NR_setxattr #define __NR_setxattr (__NR_Linux + 224) #endif #ifndef __NR_lsetxattr #define __NR_lsetxattr (__NR_Linux + 225) #endif #ifndef __NR_getxattr #define __NR_getxattr (__NR_Linux + 227) #endif #ifndef __NR_lgetxattr #define __NR_lgetxattr (__NR_Linux + 228) #endif #ifndef __NR_listxattr #define __NR_listxattr (__NR_Linux + 230) #endif #ifndef __NR_llistxattr #define __NR_llistxattr (__NR_Linux + 231) #endif #ifndef __NR_futex #define __NR_futex (__NR_Linux + 238) #endif #ifndef __NR_sched_setaffinity #define __NR_sched_setaffinity (__NR_Linux + 239) #define __NR_sched_getaffinity (__NR_Linux + 240) #endif #ifndef __NR_set_tid_address #define __NR_set_tid_address (__NR_Linux + 252) #endif #ifndef __NR_statfs64 #define __NR_statfs64 (__NR_Linux + 255) #endif #ifndef __NR_fstatfs64 #define __NR_fstatfs64 (__NR_Linux + 256) #endif #ifndef __NR_clock_gettime #define __NR_clock_gettime (__NR_Linux + 263) #endif #ifndef __NR_clock_getres #define __NR_clock_getres (__NR_Linux + 264) #endif #ifndef __NR_openat #define __NR_openat (__NR_Linux + 288) #endif #ifndef __NR_fstatat #define __NR_fstatat (__NR_Linux + 293) #endif #ifndef __NR_unlinkat #define __NR_unlinkat (__NR_Linux + 294) #endif #ifndef __NR_move_pages #define __NR_move_pages (__NR_Linux + 308) #endif #ifndef __NR_getcpu #define __NR_getcpu (__NR_Linux + 312) #endif #ifndef __NR_ioprio_set #define __NR_ioprio_set (__NR_Linux + 314) #endif #ifndef __NR_ioprio_get #define __NR_ioprio_get (__NR_Linux + 315) #endif /* End of MIPS (old 32bit API) definitions */ #elif _MIPS_SIM == _MIPS_SIM_ABI64 #ifndef __NR_pread64 #define __NR_pread64 (__NR_Linux + 16) #endif #ifndef __NR_pwrite64 #define __NR_pwrite64 (__NR_Linux + 17) #endif #ifndef __NR_setresuid #define __NR_setresuid (__NR_Linux + 115) #define __NR_setresgid (__NR_Linux + 117) #endif #ifndef __NR_gettid #define __NR_gettid (__NR_Linux + 178) #endif #ifndef __NR_readahead #define __NR_readahead (__NR_Linux + 179) #endif #ifndef __NR_setxattr #define __NR_setxattr (__NR_Linux + 180) #endif #ifndef __NR_lsetxattr #define __NR_lsetxattr (__NR_Linux + 181) #endif #ifndef __NR_getxattr #define __NR_getxattr (__NR_Linux + 183) #endif #ifndef __NR_lgetxattr #define __NR_lgetxattr (__NR_Linux + 184) #endif #ifndef __NR_listxattr #define __NR_listxattr (__NR_Linux + 186) #endif #ifndef __NR_llistxattr #define __NR_llistxattr (__NR_Linux + 187) #endif #ifndef __NR_futex #define __NR_futex (__NR_Linux + 194) #endif #ifndef __NR_sched_setaffinity #define __NR_sched_setaffinity (__NR_Linux + 195) #define __NR_sched_getaffinity (__NR_Linux + 196) #endif #ifndef __NR_set_tid_address #define __NR_set_tid_address (__NR_Linux + 212) #endif #ifndef __NR_clock_gettime #define __NR_clock_gettime (__NR_Linux + 222) #endif #ifndef __NR_clock_getres #define __NR_clock_getres (__NR_Linux + 223) #endif #ifndef __NR_openat #define __NR_openat (__NR_Linux + 247) #endif #ifndef __NR_fstatat #define __NR_fstatat (__NR_Linux + 252) #endif #ifndef __NR_unlinkat #define __NR_unlinkat (__NR_Linux + 253) #endif #ifndef __NR_move_pages #define __NR_move_pages (__NR_Linux + 267) #endif #ifndef __NR_getcpu #define __NR_getcpu (__NR_Linux + 271) #endif #ifndef __NR_ioprio_set #define __NR_ioprio_set (__NR_Linux + 273) #endif #ifndef __NR_ioprio_get #define __NR_ioprio_get (__NR_Linux + 274) #endif /* End of MIPS (64bit API) definitions */ #else #ifndef __NR_setresuid #define __NR_setresuid (__NR_Linux + 115) #define __NR_setresgid (__NR_Linux + 117) #endif #ifndef __NR_gettid #define __NR_gettid (__NR_Linux + 178) #endif #ifndef __NR_readahead #define __NR_readahead (__NR_Linux + 179) #endif #ifndef __NR_setxattr #define __NR_setxattr (__NR_Linux + 180) #endif #ifndef __NR_lsetxattr #define __NR_lsetxattr (__NR_Linux + 181) #endif #ifndef __NR_getxattr #define __NR_getxattr (__NR_Linux + 183) #endif #ifndef __NR_lgetxattr #define __NR_lgetxattr (__NR_Linux + 184) #endif #ifndef __NR_listxattr #define __NR_listxattr (__NR_Linux + 186) #endif #ifndef __NR_llistxattr #define __NR_llistxattr (__NR_Linux + 187) #endif #ifndef __NR_futex #define __NR_futex (__NR_Linux + 194) #endif #ifndef __NR_sched_setaffinity #define __NR_sched_setaffinity (__NR_Linux + 195) #define __NR_sched_getaffinity (__NR_Linux + 196) #endif #ifndef __NR_set_tid_address #define __NR_set_tid_address (__NR_Linux + 213) #endif #ifndef __NR_statfs64 #define __NR_statfs64 (__NR_Linux + 217) #endif #ifndef __NR_fstatfs64 #define __NR_fstatfs64 (__NR_Linux + 218) #endif #ifndef __NR_clock_gettime #define __NR_clock_gettime (__NR_Linux + 226) #endif #ifndef __NR_clock_getres #define __NR_clock_getres (__NR_Linux + 227) #endif #ifndef __NR_openat #define __NR_openat (__NR_Linux + 251) #endif #ifndef __NR_fstatat #define __NR_fstatat (__NR_Linux + 256) #endif #ifndef __NR_unlinkat #define __NR_unlinkat (__NR_Linux + 257) #endif #ifndef __NR_move_pages #define __NR_move_pages (__NR_Linux + 271) #endif #ifndef __NR_getcpu #define __NR_getcpu (__NR_Linux + 275) #endif #ifndef __NR_ioprio_set #define __NR_ioprio_set (__NR_Linux + 277) #endif #ifndef __NR_ioprio_get #define __NR_ioprio_get (__NR_Linux + 278) #endif /* End of MIPS (new 32bit API) definitions */ #endif /* End of MIPS definitions */ #elif defined(__PPC__) #ifndef __NR_setfsuid #define __NR_setfsuid 138 #define __NR_setfsgid 139 #endif #ifndef __NR_setresuid #define __NR_setresuid 164 #define __NR_setresgid 169 #endif #ifndef __NR_rt_sigaction #define __NR_rt_sigaction 173 #define __NR_rt_sigprocmask 174 #define __NR_rt_sigpending 175 #define __NR_rt_sigsuspend 178 #endif #ifndef __NR_pread64 #define __NR_pread64 179 #endif #ifndef __NR_pwrite64 #define __NR_pwrite64 180 #endif #ifndef __NR_ugetrlimit #define __NR_ugetrlimit 190 #endif #ifndef __NR_readahead #define __NR_readahead 191 #endif #ifndef __NR_stat64 #define __NR_stat64 195 #endif #ifndef __NR_fstat64 #define __NR_fstat64 197 #endif #ifndef __NR_getdents64 #define __NR_getdents64 202 #endif #ifndef __NR_gettid #define __NR_gettid 207 #endif #ifndef __NR_setxattr #define __NR_setxattr 209 #endif #ifndef __NR_lsetxattr #define __NR_lsetxattr 210 #endif #ifndef __NR_getxattr #define __NR_getxattr 212 #endif #ifndef __NR_lgetxattr #define __NR_lgetxattr 213 #endif #ifndef __NR_listxattr #define __NR_listxattr 215 #endif #ifndef __NR_llistxattr #define __NR_llistxattr 216 #endif #ifndef __NR_futex #define __NR_futex 221 #endif #ifndef __NR_sched_setaffinity #define __NR_sched_setaffinity 222 #define __NR_sched_getaffinity 223 #endif #ifndef __NR_set_tid_address #define __NR_set_tid_address 232 #endif #ifndef __NR_clock_gettime #define __NR_clock_gettime 246 #endif #ifndef __NR_clock_getres #define __NR_clock_getres 247 #endif #ifndef __NR_statfs64 #define __NR_statfs64 252 #endif #ifndef __NR_fstatfs64 #define __NR_fstatfs64 253 #endif #ifndef __NR_fadvise64_64 #define __NR_fadvise64_64 254 #endif #ifndef __NR_ioprio_set #define __NR_ioprio_set 273 #endif #ifndef __NR_ioprio_get #define __NR_ioprio_get 274 #endif #ifndef __NR_openat #define __NR_openat 286 #endif #ifndef __NR_fstatat64 #define __NR_fstatat64 291 #endif #ifndef __NR_unlinkat #define __NR_unlinkat 292 #endif #ifndef __NR_move_pages #define __NR_move_pages 301 #endif #ifndef __NR_getcpu #define __NR_getcpu 302 #endif /* End of powerpc defininitions */ #endif /* After forking, we must make sure to only call system calls. */ #if __BOUNDED_POINTERS__ #error "Need to port invocations of syscalls for bounded ptrs" #else /* The core dumper and the thread lister get executed after threads * have been suspended. As a consequence, we cannot call any functions * that acquire locks. Unfortunately, libc wraps most system calls * (e.g. in order to implement pthread_atfork, and to make calls * cancellable), which means we cannot call these functions. Instead, * we have to call syscall() directly. */ #undef LSS_ERRNO #ifdef SYS_ERRNO /* Allow the including file to override the location of errno. This can * be useful when using clone() with the CLONE_VM option. */ #define LSS_ERRNO SYS_ERRNO #else #define LSS_ERRNO errno #endif #undef LSS_INLINE #ifdef SYS_INLINE #define LSS_INLINE SYS_INLINE #else #define LSS_INLINE static inline #endif /* Allow the including file to override the prefix used for all new * system calls. By default, it will be set to "sys_". */ #undef LSS_NAME #ifndef SYS_PREFIX #define LSS_NAME(name) sys_##name #elif SYS_PREFIX < 0 #define LSS_NAME(name) name #elif SYS_PREFIX == 0 #define LSS_NAME(name) sys0_##name #elif SYS_PREFIX == 1 #define LSS_NAME(name) sys1_##name #elif SYS_PREFIX == 2 #define LSS_NAME(name) sys2_##name #elif SYS_PREFIX == 3 #define LSS_NAME(name) sys3_##name #elif SYS_PREFIX == 4 #define LSS_NAME(name) sys4_##name #elif SYS_PREFIX == 5 #define LSS_NAME(name) sys5_##name #elif SYS_PREFIX == 6 #define LSS_NAME(name) sys6_##name #elif SYS_PREFIX == 7 #define LSS_NAME(name) sys7_##name #elif SYS_PREFIX == 8 #define LSS_NAME(name) sys8_##name #elif SYS_PREFIX == 9 #define LSS_NAME(name) sys9_##name #endif #undef LSS_RETURN #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__)) /* Failing system calls return a negative result in the range of * -1..-4095. These are "errno" values with the sign inverted. */ #define LSS_RETURN(type, res) \ do { \ if ((unsigned long)(res) >= (unsigned long)(-4095)) { \ LSS_ERRNO = -(res); \ res = -1; \ } \ return (type) (res); \ } while (0) #elif defined(__mips__) /* On MIPS, failing system calls return -1, and set errno in a * separate CPU register. */ #define LSS_RETURN(type, res, err) \ do { \ if (err) { \ LSS_ERRNO = (res); \ res = -1; \ } \ return (type) (res); \ } while (0) #elif defined(__PPC__) /* On PPC, failing system calls return -1, and set errno in a * separate CPU register. See linux/unistd.h. */ #define LSS_RETURN(type, res, err) \ do { \ if (err & 0x10000000 ) { \ LSS_ERRNO = (res); \ res = -1; \ } \ return (type) (res); \ } while (0) #endif #if defined(__i386__) /* In PIC mode (e.g. when building shared libraries), gcc for i386 * reserves ebx. Unfortunately, most distribution ship with implementations * of _syscallX() which clobber ebx. * Also, most definitions of _syscallX() neglect to mark "memory" as being * clobbered. This causes problems with compilers, that do a better job * at optimizing across __asm__ calls. * So, we just have to redefine all of the _syscallX() macros. */ #undef LSS_BODY #define LSS_BODY(type,args...) \ long __res; \ __asm__ __volatile__("push %%ebx\n" \ "movl %2,%%ebx\n" \ "int $0x80\n" \ "pop %%ebx" \ args \ : "memory"); \ LSS_RETURN(type,__res) #undef _syscall0 #define _syscall0(type,name) \ type LSS_NAME(name)(void) { \ long __res; \ __asm__ volatile("int $0x80" \ : "=a" (__res) \ : "0" (__NR_##name) \ : "memory"); \ LSS_RETURN(type,__res); \ } #undef _syscall1 #define _syscall1(type,name,type1,arg1) \ type LSS_NAME(name)(type1 arg1) { \ LSS_BODY(type, \ : "=a" (__res) \ : "0" (__NR_##name), "ri" ((long)(arg1))); \ } #undef _syscall2 #define _syscall2(type,name,type1,arg1,type2,arg2) \ type LSS_NAME(name)(type1 arg1,type2 arg2) { \ LSS_BODY(type, \ : "=a" (__res) \ : "0" (__NR_##name),"ri" ((long)(arg1)), "c" ((long)(arg2))); \ } #undef _syscall3 #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ type LSS_NAME(name)(type1 arg1,type2 arg2,type3 arg3) { \ LSS_BODY(type, \ : "=a" (__res) \ : "0" (__NR_##name), "ri" ((long)(arg1)), "c" ((long)(arg2)), \ "d" ((long)(arg3))); \ } #undef _syscall4 #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ LSS_BODY(type, \ : "=a" (__res) \ : "0" (__NR_##name), "ri" ((long)(arg1)), "c" ((long)(arg2)), \ "d" ((long)(arg3)),"S" ((long)(arg4))); \ } #undef _syscall5 #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ type5,arg5) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ type5 arg5) { \ long __res; \ __asm__ __volatile__("push %%ebx\n" \ "movl %2,%%ebx\n" \ "movl %1,%%eax\n" \ "int $0x80\n" \ "pop %%ebx" \ : "=a" (__res) \ : "i" (__NR_##name), "ri" ((long)(arg1)), \ "c" ((long)(arg2)), "d" ((long)(arg3)), \ "S" ((long)(arg4)), "D" ((long)(arg5)) \ : "memory"); \ LSS_RETURN(type,__res); \ } #undef _syscall6 #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ type5,arg5,type6,arg6) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ type5 arg5, type6 arg6) { \ long __res; \ struct { long __a1; long __a6; } __s = { (long)arg1, (long) arg6 }; \ __asm__ __volatile__("push %%ebp\n" \ "push %%ebx\n" \ "movl 4(%2),%%ebp\n" \ "movl 0(%2), %%ebx\n" \ "movl %1,%%eax\n" \ "int $0x80\n" \ "pop %%ebx\n" \ "pop %%ebp" \ : "=a" (__res) \ : "i" (__NR_##name), "0" ((long)(&__s)), \ "c" ((long)(arg2)), "d" ((long)(arg3)), \ "S" ((long)(arg4)), "D" ((long)(arg5)) \ : "memory"); \ LSS_RETURN(type,__res); \ } LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr) { long __res; __asm__ __volatile__(/* if (fn == NULL) * return -EINVAL; */ "movl %3,%%ecx\n" "jecxz 1f\n" /* if (child_stack == NULL) * return -EINVAL; */ "movl %4,%%ecx\n" "jecxz 1f\n" /* Set up alignment of the child stack: * child_stack = (child_stack & ~0xF) - 20; */ "andl $-16,%%ecx\n" "subl $20,%%ecx\n" /* Push "arg" and "fn" onto the stack that will be * used by the child. */ "movl %6,%%eax\n" "movl %%eax,4(%%ecx)\n" "movl %3,%%eax\n" "movl %%eax,(%%ecx)\n" /* %eax = syscall(%eax = __NR_clone, * %ebx = flags, * %ecx = child_stack, * %edx = parent_tidptr, * %esi = newtls, * %edi = child_tidptr) * Also, make sure that %ebx gets preserved as it is * used in PIC mode. */ "movl %8,%%esi\n" "movl %7,%%edx\n" "movl %5,%%eax\n" "movl %9,%%edi\n" "pushl %%ebx\n" "movl %%eax,%%ebx\n" "movl %2,%%eax\n" "int $0x80\n" /* In the parent: restore %ebx * In the child: move "fn" into %ebx */ "popl %%ebx\n" /* if (%eax != 0) * return %eax; */ "test %%eax,%%eax\n" "jnz 1f\n" /* In the child, now. Terminate frame pointer chain. */ "movl $0,%%ebp\n" /* Call "fn". "arg" is already on the stack. */ "call *%%ebx\n" /* Call _exit(%ebx). Unfortunately older versions * of gcc restrict the number of arguments that can * be passed to asm(). So, we need to hard-code the * system call number. */ "movl %%eax,%%ebx\n" "movl $1,%%eax\n" "int $0x80\n" /* Return to parent. */ "1:\n" : "=a" (__res) : "0"(-EINVAL), "i"(__NR_clone), "m"(fn), "m"(child_stack), "m"(flags), "m"(arg), "m"(parent_tidptr), "m"(newtls), "m"(child_tidptr) : "memory", "ecx", "edx", "esi", "edi"); LSS_RETURN(int, __res); } #define __NR__fadvise64_64 __NR_fadvise64_64 LSS_INLINE _syscall6(int, _fadvise64_64, int, fd, unsigned, offset_lo, unsigned, offset_hi, unsigned, len_lo, unsigned, len_hi, int, advice) LSS_INLINE int LSS_NAME(fadvise64)(int fd, loff_t offset, loff_t len, int advice) { return LSS_NAME(_fadvise64_64)(fd, (unsigned)offset, (unsigned)(offset >>32), (unsigned)len, (unsigned)(len >> 32), advice); } #define __NR__fallocate __NR_fallocate LSS_INLINE _syscall6(int, _fallocate, int, fd, int, mode, unsigned, offset_lo, unsigned, offset_hi, unsigned, len_lo, unsigned, len_hi) LSS_INLINE int LSS_NAME(fallocate)(int fd, int mode, loff_t offset, loff_t len) { union { loff_t off; unsigned w[2]; } o = { offset }, l = { len }; return LSS_NAME(_fallocate)(fd, mode, o.w[0], o.w[1], l.w[0], l.w[1]); } LSS_INLINE void (*LSS_NAME(restore_rt)(void))(void) { /* On i386, the kernel does not know how to return from a signal * handler. Instead, it relies on user space to provide a * restorer function that calls the {rt_,}sigreturn() system call. * Unfortunately, we cannot just reference the glibc version of this * function, as glibc goes out of its way to make it inaccessible. */ void (*res)(void); __asm__ __volatile__("call 2f\n" "0:.align 16\n" "1:movl %1,%%eax\n" "int $0x80\n" "2:popl %0\n" "addl $(1b-0b),%0\n" : "=a" (res) : "i" (__NR_rt_sigreturn)); return res; } LSS_INLINE void (*LSS_NAME(restore)(void))(void) { /* On i386, the kernel does not know how to return from a signal * handler. Instead, it relies on user space to provide a * restorer function that calls the {rt_,}sigreturn() system call. * Unfortunately, we cannot just reference the glibc version of this * function, as glibc goes out of its way to make it inaccessible. */ void (*res)(void); __asm__ __volatile__("call 2f\n" "0:.align 16\n" "1:pop %%eax\n" "movl %1,%%eax\n" "int $0x80\n" "2:popl %0\n" "addl $(1b-0b),%0\n" : "=a" (res) : "i" (__NR_sigreturn)); return res; } #elif defined(__x86_64__) /* There are no known problems with any of the _syscallX() macros * currently shipping for x86_64, but we still need to be able to define * our own version so that we can override the location of the errno * location (e.g. when using the clone() system call with the CLONE_VM * option). */ #undef LSS_BODY #define LSS_BODY(type,name, ...) \ long __res; \ __asm__ __volatile__("syscall" : "=a" (__res) : "0" (__NR_##name), \ ##__VA_ARGS__ : "r11", "rcx", "memory"); \ LSS_RETURN(type, __res) #undef _syscall0 #define _syscall0(type,name) \ type LSS_NAME(name)() { \ LSS_BODY(type, name); \ } #undef _syscall1 #define _syscall1(type,name,type1,arg1) \ type LSS_NAME(name)(type1 arg1) { \ LSS_BODY(type, name, "D" ((long)(arg1))); \ } #undef _syscall2 #define _syscall2(type,name,type1,arg1,type2,arg2) \ type LSS_NAME(name)(type1 arg1, type2 arg2) { \ LSS_BODY(type, name, "D" ((long)(arg1)), "S" ((long)(arg2))); \ } #undef _syscall3 #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ LSS_BODY(type, name, "D" ((long)(arg1)), "S" ((long)(arg2)), \ "d" ((long)(arg3))); \ } #undef _syscall4 #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ long __res; \ __asm__ __volatile__("movq %5,%%r10; syscall" : \ "=a" (__res) : "0" (__NR_##name), \ "D" ((long)(arg1)), "S" ((long)(arg2)), "d" ((long)(arg3)), \ "g" ((long)(arg4)) : "r10", "r11", "rcx", "memory"); \ LSS_RETURN(type, __res); \ } #undef _syscall5 #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ type5,arg5) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ type5 arg5) { \ long __res; \ __asm__ __volatile__("movq %5,%%r10; movq %6,%%r8; syscall" : \ "=a" (__res) : "0" (__NR_##name), \ "D" ((long)(arg1)), "S" ((long)(arg2)), "d" ((long)(arg3)), \ "g" ((long)(arg4)), "g" ((long)(arg5)) : \ "r8", "r10", "r11", "rcx", "memory"); \ LSS_RETURN(type, __res); \ } #undef _syscall6 #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ type5,arg5,type6,arg6) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ type5 arg5, type6 arg6) { \ long __res; \ __asm__ __volatile__("movq %5,%%r10; movq %6,%%r8; movq %7,%%r9;" \ "syscall" : \ "=a" (__res) : "0" (__NR_##name), \ "D" ((long)(arg1)), "S" ((long)(arg2)), "d" ((long)(arg3)), \ "g" ((long)(arg4)), "g" ((long)(arg5)), "g" ((long)(arg6)) : \ "r8", "r9", "r10", "r11", "rcx", "memory"); \ LSS_RETURN(type, __res); \ } LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr) { long __res; { register void *__tls __asm__("r8") = newtls; register int *__ctid __asm__("r10") = child_tidptr; __asm__ __volatile__(/* if (fn == NULL) * return -EINVAL; */ "testq %4,%4\n" "jz 1f\n" /* if (child_stack == NULL) * return -EINVAL; */ "testq %5,%5\n" "jz 1f\n" /* childstack -= 2*sizeof(void *); */ "subq $16,%5\n" /* Push "arg" and "fn" onto the stack that will be * used by the child. */ "movq %7,8(%5)\n" "movq %4,0(%5)\n" /* %rax = syscall(%rax = __NR_clone, * %rdi = flags, * %rsi = child_stack, * %rdx = parent_tidptr, * %r8 = new_tls, * %r10 = child_tidptr) */ "movq %2,%%rax\n" "syscall\n" /* if (%rax != 0) * return; */ "testq %%rax,%%rax\n" "jnz 1f\n" /* In the child. Terminate frame pointer chain. */ "xorq %%rbp,%%rbp\n" /* Call "fn(arg)". */ "popq %%rax\n" "popq %%rdi\n" "call *%%rax\n" /* Call _exit(%ebx). */ "movq %%rax,%%rdi\n" "movq %3,%%rax\n" "syscall\n" /* Return to parent. */ "1:\n" : "=a" (__res) : "0"(-EINVAL), "i"(__NR_clone), "i"(__NR_exit), "r"(fn), "S"(child_stack), "D"(flags), "r"(arg), "d"(parent_tidptr), "r"(__tls), "r"(__ctid) : "memory", "r11", "rcx"); } LSS_RETURN(int, __res); } LSS_INLINE _syscall4(int, fadvise64, int, fd, loff_t, offset, loff_t, len, int, advice) LSS_INLINE void (*LSS_NAME(restore_rt)(void))(void) { /* On x86-64, the kernel does not know how to return from * a signal handler. Instead, it relies on user space to provide a * restorer function that calls the rt_sigreturn() system call. * Unfortunately, we cannot just reference the glibc version of this * function, as glibc goes out of its way to make it inaccessible. */ void (*res)(void); __asm__ __volatile__("call 2f\n" "0:.align 16\n" "1:movq %1,%%rax\n" "syscall\n" "2:popq %0\n" "addq $(1b-0b),%0\n" : "=a" (res) : "i" (__NR_rt_sigreturn)); return res; } #elif defined(__ARM_ARCH_3__) /* Most definitions of _syscallX() neglect to mark "memory" as being * clobbered. This causes problems with compilers, that do a better job * at optimizing across __asm__ calls. * So, we just have to redefine all fo the _syscallX() macros. */ #undef LSS_REG #define LSS_REG(r,a) register long __r##r __asm__("r"#r) = (long)a #undef LSS_BODY #define LSS_BODY(type,name,args...) \ register long __res_r0 __asm__("r0"); \ long __res; \ __asm__ __volatile__ (__syscall(name) \ : "=r"(__res_r0) : args : "lr", "memory"); \ __res = __res_r0; \ LSS_RETURN(type, __res) #undef _syscall0 #define _syscall0(type, name) \ type LSS_NAME(name)() { \ LSS_BODY(type, name); \ } #undef _syscall1 #define _syscall1(type, name, type1, arg1) \ type LSS_NAME(name)(type1 arg1) { \ LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \ } #undef _syscall2 #define _syscall2(type, name, type1, arg1, type2, arg2) \ type LSS_NAME(name)(type1 arg1, type2 arg2) { \ LSS_REG(0, arg1); LSS_REG(1, arg2); \ LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \ } #undef _syscall3 #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \ } #undef _syscall4 #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ LSS_REG(3, arg4); \ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \ } #undef _syscall5 #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ type5,arg5) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ type5 arg5) { \ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ LSS_REG(3, arg4); LSS_REG(4, arg5); \ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ "r"(__r4)); \ } #undef _syscall6 #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ type5,arg5,type6,arg6) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ type5 arg5, type6 arg6) { \ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ "r"(__r4), "r"(__r5)); \ } LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr) { long __res; { register int __flags __asm__("r0") = flags; register void *__stack __asm__("r1") = child_stack; register void *__ptid __asm__("r2") = parent_tidptr; register void *__tls __asm__("r3") = newtls; register int *__ctid __asm__("r4") = child_tidptr; __asm__ __volatile__(/* if (fn == NULL || child_stack == NULL) * return -EINVAL; */ "cmp %2,#0\n" "cmpne %3,#0\n" "moveq %0,%1\n" "beq 1f\n" /* Push "arg" and "fn" onto the stack that will be * used by the child. */ "str %5,[%3,#-4]!\n" "str %2,[%3,#-4]!\n" /* %r0 = syscall(%r0 = flags, * %r1 = child_stack, * %r2 = parent_tidptr, * %r3 = newtls, * %r4 = child_tidptr) */ __syscall(clone)"\n" /* if (%r0 != 0) * return %r0; */ "movs %0,r0\n" "bne 1f\n" /* In the child, now. Call "fn(arg)". */ "ldr r0,[sp, #4]\n" "mov lr,pc\n" "ldr pc,[sp]\n" /* Call _exit(%r0). */ __syscall(exit)"\n" "1:\n" : "=r" (__res) : "i"(-EINVAL), "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), "r"(__ptid), "r"(__tls), "r"(__ctid) : "lr", "memory"); } LSS_RETURN(int, __res); } #elif defined(__mips__) #undef LSS_REG #define LSS_REG(r,a) register unsigned long __r##r __asm__("$"#r) = \ (unsigned long)(a) #undef LSS_BODY #define LSS_BODY(type,name,r7,...) \ register unsigned long __v0 __asm__("$2") = __NR_##name; \ __asm__ __volatile__ ("syscall\n" \ : "=&r"(__v0), r7 (__r7) \ : "0"(__v0), ##__VA_ARGS__ \ : "$8", "$9", "$10", "$11", "$12", \ "$13", "$14", "$15", "$24", "memory"); \ LSS_RETURN(type, __v0, __r7) #undef _syscall0 #define _syscall0(type, name) \ type LSS_NAME(name)() { \ register unsigned long __r7 __asm__("$7"); \ LSS_BODY(type, name, "=r"); \ } #undef _syscall1 #define _syscall1(type, name, type1, arg1) \ type LSS_NAME(name)(type1 arg1) { \ register unsigned long __r7 __asm__("$7"); \ LSS_REG(4, arg1); LSS_BODY(type, name, "=r", "r"(__r4)); \ } #undef _syscall2 #define _syscall2(type, name, type1, arg1, type2, arg2) \ type LSS_NAME(name)(type1 arg1, type2 arg2) { \ register unsigned long __r7 __asm__("$7"); \ LSS_REG(4, arg1); LSS_REG(5, arg2); \ LSS_BODY(type, name, "=r", "r"(__r4), "r"(__r5)); \ } #undef _syscall3 #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ register unsigned long __r7 __asm__("$7"); \ LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ LSS_BODY(type, name, "=r", "r"(__r4), "r"(__r5), "r"(__r6)); \ } #undef _syscall4 #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ LSS_REG(7, arg4); \ LSS_BODY(type, name, "+r", "r"(__r4), "r"(__r5), "r"(__r6)); \ } #undef _syscall5 #if _MIPS_SIM == _MIPS_SIM_ABI32 /* The old 32bit MIPS system call API passes the fifth and sixth argument * on the stack, whereas the new APIs use registers "r8" and "r9". */ #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ type5,arg5) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ type5 arg5) { \ LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ LSS_REG(7, arg4); \ register unsigned long __v0 __asm__("$2"); \ __asm__ __volatile__ (".set noreorder\n" \ "lw $2, %6\n" \ "subu $29, 32\n" \ "sw $2, 16($29)\n" \ "li $2, %2\n" \ "syscall\n" \ "addiu $29, 32\n" \ ".set reorder\n" \ : "=&r"(__v0), "+r" (__r7) \ : "i" (__NR_##name), "r"(__r4), "r"(__r5), \ "r"(__r6), "m" ((unsigned long)arg5) \ : "$8", "$9", "$10", "$11", "$12", \ "$13", "$14", "$15", "$24", "memory"); \ LSS_RETURN(type, __v0, __r7); \ } #else #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ type5,arg5) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ type5 arg5) { \ LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ LSS_REG(7, arg4); LSS_REG(8, arg5); \ LSS_BODY(type, name, "+r", "r"(__r4), "r"(__r5), "r"(__r6), \ "r"(__r8)); \ } #endif #undef _syscall6 #if _MIPS_SIM == _MIPS_SIM_ABI32 /* The old 32bit MIPS system call API passes the fifth and sixth argument * on the stack, whereas the new APIs use registers "r8" and "r9". */ #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ type5,arg5,type6,arg6) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ type5 arg5, type6 arg6) { \ LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ LSS_REG(7, arg4); \ register unsigned long __v0 __asm__("$2"); \ __asm__ __volatile__ (".set noreorder\n" \ "lw $2, %6\n" \ "lw $8, %7\n" \ "subu $29, 32\n" \ "sw $2, 16($29)\n" \ "sw $8, 20($29)\n" \ "li $2, %2\n" \ "syscall\n" \ "addiu $29, 32\n" \ ".set reorder\n" \ : "=&r"(__v0), "+r" (__r7) \ : "i" (__NR_##name), "r"(__r4), "r"(__r5), \ "r"(__r6), "r" ((unsigned long)arg5), \ "r" ((unsigned long)arg6) \ : "$8", "$9", "$10", "$11", "$12", \ "$13", "$14", "$15", "$24", "memory"); \ LSS_RETURN(type, __v0, __r7); \ } #else #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ type5,arg5,type6,arg6) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ type5 arg5,type6 arg6) { \ LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ LSS_REG(7, arg4); LSS_REG(8, arg5); LSS_REG(9, arg6); \ LSS_BODY(type, name, "+r", "r"(__r4), "r"(__r5), "r"(__r6), \ "r"(__r8), "r"(__r9)); \ } #endif LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr) { register unsigned long __v0 __asm__("$2"); register unsigned long __r7 __asm__("$7") = (unsigned long)newtls; { register int __flags __asm__("$4") = flags; register void *__stack __asm__("$5") = child_stack; register void *__ptid __asm__("$6") = parent_tidptr; register int *__ctid __asm__("$8") = child_tidptr; __asm__ __volatile__( #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32 "subu $29,24\n" #elif _MIPS_SIM == _MIPS_SIM_NABI32 "sub $29,16\n" #else "dsubu $29,16\n" #endif /* if (fn == NULL || child_stack == NULL) * return -EINVAL; */ "li %0,%2\n" "beqz %5,1f\n" "beqz %6,1f\n" /* Push "arg" and "fn" onto the stack that will be * used by the child. */ #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32 "subu %6,32\n" "sw %5,0(%6)\n" "sw %8,4(%6)\n" #elif _MIPS_SIM == _MIPS_SIM_NABI32 "sub %6,32\n" "sw %5,0(%6)\n" "sw %8,8(%6)\n" #else "dsubu %6,32\n" "sd %5,0(%6)\n" "sd %8,8(%6)\n" #endif /* $7 = syscall($4 = flags, * $5 = child_stack, * $6 = parent_tidptr, * $7 = newtls, * $8 = child_tidptr) */ "li $2,%3\n" "syscall\n" /* if ($7 != 0) * return $2; */ "bnez $7,1f\n" "bnez $2,1f\n" /* In the child, now. Call "fn(arg)". */ #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32 "lw $25,0($29)\n" "lw $4,4($29)\n" #elif _MIPS_SIM == _MIPS_SIM_NABI32 "lw $25,0($29)\n" "lw $4,8($29)\n" #else "ld $25,0($29)\n" "ld $4,8($29)\n" #endif "jalr $25\n" /* Call _exit($2) */ "move $4,$2\n" "li $2,%4\n" "syscall\n" "1:\n" #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32 "addu $29, 24\n" #elif _MIPS_SIM == _MIPS_SIM_NABI32 "add $29, 16\n" #else "daddu $29,16\n" #endif : "=&r" (__v0), "=r" (__r7) : "i"(-EINVAL), "i"(__NR_clone), "i"(__NR_exit), "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), "r"(__ptid), "r"(__r7), "r"(__ctid) : "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", "memory"); } LSS_RETURN(int, __v0, __r7); } #elif defined (__PPC__) #undef LSS_LOADARGS_0 #define LSS_LOADARGS_0(name, dummy...) \ __sc_0 = __NR_##name #undef LSS_LOADARGS_1 #define LSS_LOADARGS_1(name, arg1) \ LSS_LOADARGS_0(name); \ __sc_3 = (unsigned long) (arg1) #undef LSS_LOADARGS_2 #define LSS_LOADARGS_2(name, arg1, arg2) \ LSS_LOADARGS_1(name, arg1); \ __sc_4 = (unsigned long) (arg2) #undef LSS_LOADARGS_3 #define LSS_LOADARGS_3(name, arg1, arg2, arg3) \ LSS_LOADARGS_2(name, arg1, arg2); \ __sc_5 = (unsigned long) (arg3) #undef LSS_LOADARGS_4 #define LSS_LOADARGS_4(name, arg1, arg2, arg3, arg4) \ LSS_LOADARGS_3(name, arg1, arg2, arg3); \ __sc_6 = (unsigned long) (arg4) #undef LSS_LOADARGS_5 #define LSS_LOADARGS_5(name, arg1, arg2, arg3, arg4, arg5) \ LSS_LOADARGS_4(name, arg1, arg2, arg3, arg4); \ __sc_7 = (unsigned long) (arg5) #undef LSS_LOADARGS_6 #define LSS_LOADARGS_6(name, arg1, arg2, arg3, arg4, arg5, arg6) \ LSS_LOADARGS_5(name, arg1, arg2, arg3, arg4, arg5); \ __sc_8 = (unsigned long) (arg6) #undef LSS_ASMINPUT_0 #define LSS_ASMINPUT_0 "0" (__sc_0) #undef LSS_ASMINPUT_1 #define LSS_ASMINPUT_1 LSS_ASMINPUT_0, "1" (__sc_3) #undef LSS_ASMINPUT_2 #define LSS_ASMINPUT_2 LSS_ASMINPUT_1, "2" (__sc_4) #undef LSS_ASMINPUT_3 #define LSS_ASMINPUT_3 LSS_ASMINPUT_2, "3" (__sc_5) #undef LSS_ASMINPUT_4 #define LSS_ASMINPUT_4 LSS_ASMINPUT_3, "4" (__sc_6) #undef LSS_ASMINPUT_5 #define LSS_ASMINPUT_5 LSS_ASMINPUT_4, "5" (__sc_7) #undef LSS_ASMINPUT_6 #define LSS_ASMINPUT_6 LSS_ASMINPUT_5, "6" (__sc_8) #undef LSS_BODY #define LSS_BODY(nr, type, name, args...) \ long __sc_ret, __sc_err; \ { \ register unsigned long __sc_0 __asm__ ("r0"); \ register unsigned long __sc_3 __asm__ ("r3"); \ register unsigned long __sc_4 __asm__ ("r4"); \ register unsigned long __sc_5 __asm__ ("r5"); \ register unsigned long __sc_6 __asm__ ("r6"); \ register unsigned long __sc_7 __asm__ ("r7"); \ register unsigned long __sc_8 __asm__ ("r8"); \ \ LSS_LOADARGS_##nr(name, args); \ __asm__ __volatile__ \ ("sc\n\t" \ "mfcr %0" \ : "=&r" (__sc_0), \ "=&r" (__sc_3), "=&r" (__sc_4), \ "=&r" (__sc_5), "=&r" (__sc_6), \ "=&r" (__sc_7), "=&r" (__sc_8) \ : LSS_ASMINPUT_##nr \ : "cr0", "ctr", "memory", \ "r9", "r10", "r11", "r12"); \ __sc_ret = __sc_3; \ __sc_err = __sc_0; \ } \ LSS_RETURN(type, __sc_ret, __sc_err) #undef _syscall0 #define _syscall0(type, name) \ type LSS_NAME(name)(void) { \ LSS_BODY(0, type, name); \ } #undef _syscall1 #define _syscall1(type, name, type1, arg1) \ type LSS_NAME(name)(type1 arg1) { \ LSS_BODY(1, type, name, arg1); \ } #undef _syscall2 #define _syscall2(type, name, type1, arg1, type2, arg2) \ type LSS_NAME(name)(type1 arg1, type2 arg2) { \ LSS_BODY(2, type, name, arg1, arg2); \ } #undef _syscall3 #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ LSS_BODY(3, type, name, arg1, arg2, arg3); \ } #undef _syscall4 #define _syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \ type4, arg4) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ LSS_BODY(4, type, name, arg1, arg2, arg3, arg4); \ } #undef _syscall5 #define _syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \ type4, arg4, type5, arg5) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ type5 arg5) { \ LSS_BODY(5, type, name, arg1, arg2, arg3, arg4, arg5); \ } #undef _syscall6 #define _syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \ type4, arg4, type5, arg5, type6, arg6) \ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ type5 arg5, type6 arg6) { \ LSS_BODY(6, type, name, arg1, arg2, arg3, arg4, arg5, arg6); \ } /* clone function adapted from glibc 2.3.6 clone.S */ /* TODO(csilvers): consider wrapping some args up in a struct, like we * do for i386's _syscall6, so we can compile successfully on gcc 2.95 */ LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr) { long __ret, __err; { register int (*__fn)(void *) __asm__ ("r8") = fn; register void *__cstack __asm__ ("r4") = child_stack; register int __flags __asm__ ("r3") = flags; register void * __arg __asm__ ("r9") = arg; register int * __ptidptr __asm__ ("r5") = parent_tidptr; register void * __newtls __asm__ ("r6") = newtls; register int * __ctidptr __asm__ ("r7") = child_tidptr; __asm__ __volatile__( /* check for fn == NULL * and child_stack == NULL */ "cmpwi cr0, %6, 0\n\t" "cmpwi cr1, %7, 0\n\t" "cror cr0*4+eq, cr1*4+eq, cr0*4+eq\n\t" "beq- cr0, 1f\n\t" /* set up stack frame for child */ "clrrwi %7, %7, 4\n\t" "li 0, 0\n\t" "stwu 0, -16(%7)\n\t" /* fn, arg, child_stack are saved across the syscall: r28-30 */ "mr 28, %6\n\t" "mr 29, %7\n\t" "mr 27, %9\n\t" /* syscall */ "li 0, %4\n\t" /* flags already in r3 * child_stack already in r4 * ptidptr already in r5 * newtls already in r6 * ctidptr already in r7 */ "sc\n\t" /* Test if syscall was successful */ "cmpwi cr1, 3, 0\n\t" "crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t" "bne- cr1, 1f\n\t" /* Do the function call */ "mtctr 28\n\t" "mr 3, 27\n\t" "bctrl\n\t" /* Call _exit(r3) */ "li 0, %5\n\t" "sc\n\t" /* Return to parent */ "1:\n" "mfcr %1\n\t" "mr %0, 3\n\t" : "=r" (__ret), "=r" (__err) : "0" (-1), "1" (EINVAL), "i" (__NR_clone), "i" (__NR_exit), "r" (__fn), "r" (__cstack), "r" (__flags), "r" (__arg), "r" (__ptidptr), "r" (__newtls), "r" (__ctidptr) : "cr0", "cr1", "memory", "ctr", "r0", "r29", "r27", "r28"); } LSS_RETURN(int, __ret, __err); } #endif #define __NR__exit __NR_exit #define __NR__gettid __NR_gettid #define __NR__mremap __NR_mremap LSS_INLINE _syscall1(int, chdir, const char *,p) LSS_INLINE _syscall1(int, close, int, f) LSS_INLINE _syscall2(int, clock_getres, int, c, struct kernel_timespec*, t) LSS_INLINE _syscall2(int, clock_gettime, int, c, struct kernel_timespec*, t) LSS_INLINE _syscall1(int, dup, int, f) LSS_INLINE _syscall2(int, dup2, int, s, int, d) LSS_INLINE _syscall3(int, execve, const char*, f, const char*const*,a,const char*const*, e) LSS_INLINE _syscall1(int, _exit, int, e) LSS_INLINE _syscall3(int, fcntl, int, f, int, c, long, a) LSS_INLINE _syscall0(pid_t, fork) LSS_INLINE _syscall2(int, fstat, int, f, struct kernel_stat*, b) LSS_INLINE _syscall2(int, fstatfs, int, f, struct kernel_statfs*, b) LSS_INLINE _syscall4(int, futex, int*, a, int, o, int, v, struct kernel_timespec*, t) LSS_INLINE _syscall3(int, getdents, int, f, struct kernel_dirent*, d, int, c) LSS_INLINE _syscall3(int, getdents64, int, f, struct kernel_dirent64*, d, int, c) LSS_INLINE _syscall0(gid_t, getegid) LSS_INLINE _syscall0(uid_t, geteuid) LSS_INLINE _syscall0(pid_t, getpgrp) LSS_INLINE _syscall0(pid_t, getpid) LSS_INLINE _syscall0(pid_t, getppid) LSS_INLINE _syscall2(int, getpriority, int, a, int, b) LSS_INLINE _syscall2(int, getrlimit, int, r, struct kernel_rlimit*, l) LSS_INLINE _syscall1(pid_t, getsid, pid_t, p) LSS_INLINE _syscall0(pid_t, _gettid) LSS_INLINE _syscall5(int, setxattr, const char *,p, const char *, n, const void *,v, size_t, s, int, f) LSS_INLINE _syscall5(int, lsetxattr, const char *,p, const char *, n, const void *,v, size_t, s, int, f) LSS_INLINE _syscall4(ssize_t, getxattr, const char *,p, const char *, n, void *, v, size_t, s) LSS_INLINE _syscall4(ssize_t, lgetxattr, const char *,p, const char *, n, void *, v, size_t, s) LSS_INLINE _syscall3(ssize_t, listxattr, const char *,p, char *, l, size_t, s) LSS_INLINE _syscall3(ssize_t, llistxattr, const char *,p, char *, l, size_t, s) LSS_INLINE _syscall2(int, ioprio_get, int, which, int, who) LSS_INLINE _syscall3(int, ioprio_set, int, which, int, who, int, ioprio) LSS_INLINE _syscall2(int, kill, pid_t, p, int, s) LSS_INLINE _syscall3(off_t, lseek, int, f, off_t, o, int, w) LSS_INLINE _syscall2(int, munmap, void*, s, size_t, l) LSS_INLINE _syscall6(long, move_pages, pid_t, p, unsigned long, n, void **,g, int *, d, int *, s, int, f) LSS_INLINE _syscall5(void*, _mremap, void*, o, size_t, os, size_t, ns, unsigned long, f, void *, a) LSS_INLINE _syscall3(int, open, const char*, p, int, f, int, m) LSS_INLINE _syscall3(int, poll, struct kernel_pollfd*, u, unsigned int, n, int, t) LSS_INLINE _syscall2(int, prctl, int, o, long, a) LSS_INLINE _syscall4(long, ptrace, int, r, pid_t, p, void *, a, void *, d) LSS_INLINE _syscall3(ssize_t, read, int, f, void *, b, size_t, c) LSS_INLINE _syscall3(int, readlink, const char*, p, char*, b, size_t, s) LSS_INLINE _syscall4(int, rt_sigaction, int, s, const struct kernel_sigaction*, a, struct kernel_sigaction*, o, size_t, c) LSS_INLINE _syscall2(int, rt_sigpending, struct kernel_sigset_t *, s, size_t, c) LSS_INLINE _syscall4(int, rt_sigprocmask, int, h, const struct kernel_sigset_t*, s, struct kernel_sigset_t*, o, size_t, c); LSS_INLINE _syscall2(int, rt_sigsuspend, const struct kernel_sigset_t*, s, size_t, c); LSS_INLINE _syscall3(int, sched_getaffinity,pid_t, p, unsigned int, l, unsigned long *, m) LSS_INLINE _syscall3(int, sched_setaffinity,pid_t, p, unsigned int, l, unsigned long *, m) LSS_INLINE _syscall0(int, sched_yield) LSS_INLINE _syscall1(long, set_tid_address, int *, t) LSS_INLINE _syscall1(int, setfsgid, gid_t, g) LSS_INLINE _syscall1(int, setfsuid, uid_t, u) LSS_INLINE _syscall1(int, setuid, uid_t, u) LSS_INLINE _syscall1(int, setgid, gid_t, g) LSS_INLINE _syscall2(int, setpgid, pid_t, p, pid_t, g) LSS_INLINE _syscall3(int, setpriority, int, a, int, b, int, p) LSS_INLINE _syscall3(int, setresgid, gid_t, r, gid_t, e, gid_t, s) LSS_INLINE _syscall3(int, setresuid, uid_t, r, uid_t, e, uid_t, s) LSS_INLINE _syscall2(int, setrlimit, int, r, const struct kernel_rlimit*, l) LSS_INLINE _syscall0(pid_t, setsid) LSS_INLINE _syscall2(int, sigaltstack, const stack_t*, s, const stack_t*, o) LSS_INLINE _syscall2(int, stat, const char*, f, struct kernel_stat*, b) LSS_INLINE _syscall2(int, statfs, const char*, f, struct kernel_statfs*, b) LSS_INLINE _syscall3(ssize_t, write, int, f, const void *, b, size_t, c) LSS_INLINE _syscall3(ssize_t, writev, int, f, const struct kernel_iovec*, v, size_t, c) #if defined(__NR_getcpu) LSS_INLINE _syscall3(long, getcpu, unsigned *, cpu, unsigned *, node, void *, unused); #endif #if defined(__x86_64__) || \ (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI32) LSS_INLINE _syscall3(int, recvmsg, int, s, struct kernel_msghdr*, m, int, f) LSS_INLINE _syscall3(int, sendmsg, int, s, const struct kernel_msghdr*, m, int, f) LSS_INLINE _syscall6(int, sendto, int, s, const void*, m, size_t, l, int, f, const struct kernel_sockaddr*, a, int, t) LSS_INLINE _syscall2(int, shutdown, int, s, int, h) LSS_INLINE _syscall3(int, socket, int, d, int, t, int, p) LSS_INLINE _syscall4(int, socketpair, int, d, int, t, int, p, int*, s) #endif #if defined(__x86_64__) LSS_INLINE _syscall4(int, fallocate, int, fd, int, mode, loff_t, offset, loff_t, len) LSS_INLINE _syscall6(void*, mmap, void*, s, size_t, l, int, p, int, f, int, d, __off64_t, o) LSS_INLINE _syscall4(int, newfstatat, int, d, const char *, p, struct kernel_stat*, b, int, f) LSS_INLINE int LSS_NAME(setfsgid32)(gid_t gid) { return LSS_NAME(setfsgid)(gid); } LSS_INLINE int LSS_NAME(setfsuid32)(uid_t uid) { return LSS_NAME(setfsuid)(uid); } LSS_INLINE int LSS_NAME(setresgid32)(gid_t rgid, gid_t egid, gid_t sgid) { return LSS_NAME(setresgid)(rgid, egid, sgid); } LSS_INLINE int LSS_NAME(setresuid32)(uid_t ruid, uid_t euid, uid_t suid) { return LSS_NAME(setresuid)(ruid, euid, suid); } LSS_INLINE int LSS_NAME(sigaction)(int signum, const struct kernel_sigaction *act, struct kernel_sigaction *oldact) { /* On x86_64, the kernel requires us to always set our own * SA_RESTORER in order to be able to return from a signal handler. * This function must have a "magic" signature that the "gdb" * (and maybe the kernel?) can recognize. */ if (act != NULL && !(act->sa_flags & SA_RESTORER)) { struct kernel_sigaction a = *act; a.sa_flags |= SA_RESTORER; a.sa_restorer = LSS_NAME(restore_rt)(); return LSS_NAME(rt_sigaction)(signum, &a, oldact, (KERNEL_NSIG+7)/8); } else { return LSS_NAME(rt_sigaction)(signum, act, oldact, (KERNEL_NSIG+7)/8); } } LSS_INLINE int LSS_NAME(sigpending)(struct kernel_sigset_t *set) { return LSS_NAME(rt_sigpending)(set, (KERNEL_NSIG+7)/8); } LSS_INLINE int LSS_NAME(sigprocmask)(int how, const struct kernel_sigset_t *set, struct kernel_sigset_t *oldset) { return LSS_NAME(rt_sigprocmask)(how, set, oldset, (KERNEL_NSIG+7)/8); } LSS_INLINE int LSS_NAME(sigsuspend)(const struct kernel_sigset_t *set) { return LSS_NAME(rt_sigsuspend)(set, (KERNEL_NSIG+7)/8); } #endif #if defined(__x86_64__) || defined(__ARM_ARCH_3__) || \ (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI32) LSS_INLINE _syscall4(pid_t, wait4, pid_t, p, int*, s, int, o, struct kernel_rusage*, r) LSS_INLINE pid_t LSS_NAME(waitpid)(pid_t pid, int *status, int options){ return LSS_NAME(wait4)(pid, status, options, 0); } #endif #if defined(__i386__) || defined(__x86_64__) LSS_INLINE _syscall4(int, openat, int, d, const char *, p, int, f, int, m) LSS_INLINE _syscall3(int, unlinkat, int, d, const char *, p, int, f) #endif #if defined(__i386__) || defined(__ARM_ARCH_3__) #define __NR__setfsgid32 __NR_setfsgid32 #define __NR__setfsuid32 __NR_setfsuid32 #define __NR__setresgid32 __NR_setresgid32 #define __NR__setresuid32 __NR_setresuid32 LSS_INLINE _syscall2(int, ugetrlimit, int, r, struct kernel_rlimit*, l) LSS_INLINE _syscall1(int, _setfsgid32, gid_t, f) LSS_INLINE _syscall1(int, _setfsuid32, uid_t, f) LSS_INLINE _syscall3(int, _setresgid32, gid_t, r, gid_t, e, gid_t, s) LSS_INLINE _syscall3(int, _setresuid32, uid_t, r, uid_t, e, uid_t, s) LSS_INLINE int LSS_NAME(setfsgid32)(gid_t gid) { int rc; if ((rc = LSS_NAME(_setfsgid32)(gid)) < 0 && LSS_ERRNO == ENOSYS) { if ((unsigned int)gid & ~0xFFFFu) { rc = EINVAL; } else { rc = LSS_NAME(setfsgid)(gid); } } return rc; } LSS_INLINE int LSS_NAME(setfsuid32)(uid_t uid) { int rc; if ((rc = LSS_NAME(_setfsuid32)(uid)) < 0 && LSS_ERRNO == ENOSYS) { if ((unsigned int)uid & ~0xFFFFu) { rc = EINVAL; } else { rc = LSS_NAME(setfsuid)(uid); } } return rc; } LSS_INLINE int LSS_NAME(setresgid32)(gid_t rgid, gid_t egid, gid_t sgid) { int rc; if ((rc = LSS_NAME(_setresgid32)(rgid, egid, sgid)) < 0 && LSS_ERRNO == ENOSYS) { if ((unsigned int)rgid & ~0xFFFFu || (unsigned int)egid & ~0xFFFFu || (unsigned int)sgid & ~0xFFFFu) { rc = EINVAL; } else { rc = LSS_NAME(setresgid)(rgid, egid, sgid); } } return rc; } LSS_INLINE int LSS_NAME(setresuid32)(uid_t ruid, uid_t euid, uid_t suid) { int rc; if ((rc = LSS_NAME(_setresuid32)(ruid, euid, suid)) < 0 && LSS_ERRNO == ENOSYS) { if ((unsigned int)ruid & ~0xFFFFu || (unsigned int)euid & ~0xFFFFu || (unsigned int)suid & ~0xFFFFu) { rc = EINVAL; } else { rc = LSS_NAME(setresuid)(ruid, euid, suid); } } return rc; } #endif LSS_INLINE int LSS_NAME(sigemptyset)(struct kernel_sigset_t *set) { memset(&set->sig, 0, sizeof(set->sig)); return 0; } LSS_INLINE int LSS_NAME(sigfillset)(struct kernel_sigset_t *set) { memset(&set->sig, -1, sizeof(set->sig)); return 0; } LSS_INLINE int LSS_NAME(sigaddset)(struct kernel_sigset_t *set, int signum) { if (signum < 1 || signum > (int)(8*sizeof(set->sig))) { LSS_ERRNO = EINVAL; return -1; } else { set->sig[(signum - 1)/(8*sizeof(set->sig[0]))] |= 1UL << ((signum - 1) % (8*sizeof(set->sig[0]))); return 0; } } LSS_INLINE int LSS_NAME(sigdelset)(struct kernel_sigset_t *set, int signum) { if (signum < 1 || signum > (int)(8*sizeof(set->sig))) { LSS_ERRNO = EINVAL; return -1; } else { set->sig[(signum - 1)/(8*sizeof(set->sig[0]))] &= ~(1UL << ((signum - 1) % (8*sizeof(set->sig[0])))); return 0; } } LSS_INLINE int LSS_NAME(sigismember)(struct kernel_sigset_t *set, int signum) { if (signum < 1 || signum > (int)(8*sizeof(set->sig))) { LSS_ERRNO = EINVAL; return -1; } else { return !!(set->sig[(signum - 1)/(8*sizeof(set->sig[0]))] & (1UL << ((signum - 1) % (8*sizeof(set->sig[0]))))); } } #if defined(__i386__) || defined(__ARM_ARCH_3__) || \ (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || defined(__PPC__) #define __NR__sigaction __NR_sigaction #define __NR__sigpending __NR_sigpending #define __NR__sigprocmask __NR_sigprocmask #define __NR__sigsuspend __NR_sigsuspend #define __NR__socketcall __NR_socketcall LSS_INLINE _syscall2(int, fstat64, int, f, struct kernel_stat64 *, b) LSS_INLINE _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh) LSS_INLINE _syscall1(void*, mmap, void*, a) #ifndef __PPC64__ LSS_INLINE _syscall6(void*, mmap2, void*, s, size_t, l, int, p, int, f, int, d, off_t, o) #endif LSS_INLINE _syscall3(int, _sigaction, int, s, const struct kernel_old_sigaction*, a, struct kernel_old_sigaction*, o) LSS_INLINE _syscall1(int, _sigpending, unsigned long*, s) LSS_INLINE _syscall3(int, _sigprocmask, int, h, const unsigned long*, s, unsigned long*, o) #ifdef __PPC__ LSS_INLINE _syscall1(int, _sigsuspend, unsigned long, s) #else LSS_INLINE _syscall3(int, _sigsuspend, const void*, a, int, b, unsigned long, s) #endif LSS_INLINE _syscall2(int, stat64, const char *, p, struct kernel_stat64 *, b) LSS_INLINE int LSS_NAME(sigaction)(int signum, const struct kernel_sigaction *act, struct kernel_sigaction *oldact) { int old_errno = LSS_ERRNO; int rc; struct kernel_sigaction a; if (act != NULL) { a = *act; #ifdef __i386__ /* On i386, the kernel requires us to always set our own * SA_RESTORER when using realtime signals. Otherwise, it does not * know how to return from a signal handler. This function must have * a "magic" signature that the "gdb" (and maybe the kernel?) can * recognize. * Apparently, a SA_RESTORER is implicitly set by the kernel, when * using non-realtime signals. * * TODO: Test whether ARM needs a restorer */ if (!(a.sa_flags & SA_RESTORER)) { a.sa_flags |= SA_RESTORER; a.sa_restorer = (a.sa_flags & SA_SIGINFO) ? LSS_NAME(restore_rt)() : LSS_NAME(restore)(); } #endif } rc = LSS_NAME(rt_sigaction)(signum, act ? &a : act, oldact, (KERNEL_NSIG+7)/8); if (rc < 0 && LSS_ERRNO == ENOSYS) { struct kernel_old_sigaction oa, ooa, *ptr_a = &oa, *ptr_oa = &ooa; if (!act) { ptr_a = NULL; } else { oa.sa_handler_ = act->sa_handler_; memcpy(&oa.sa_mask, &act->sa_mask, sizeof(oa.sa_mask)); #ifndef __mips__ oa.sa_restorer = act->sa_restorer; #endif oa.sa_flags = act->sa_flags; } if (!oldact) { ptr_oa = NULL; } LSS_ERRNO = old_errno; rc = LSS_NAME(_sigaction)(signum, ptr_a, ptr_oa); if (rc == 0 && oldact) { if (act) { memcpy(oldact, act, sizeof(*act)); } else { memset(oldact, 0, sizeof(*oldact)); } oldact->sa_handler_ = ptr_oa->sa_handler_; oldact->sa_flags = ptr_oa->sa_flags; memcpy(&oldact->sa_mask, &ptr_oa->sa_mask, sizeof(ptr_oa->sa_mask)); #ifndef __mips__ oldact->sa_restorer = ptr_oa->sa_restorer; #endif } } return rc; } LSS_INLINE int LSS_NAME(sigpending)(struct kernel_sigset_t *set) { int old_errno = LSS_ERRNO; int rc = LSS_NAME(rt_sigpending)(set, (KERNEL_NSIG+7)/8); if (rc < 0 && LSS_ERRNO == ENOSYS) { LSS_ERRNO = old_errno; LSS_NAME(sigemptyset)(set); rc = LSS_NAME(_sigpending)(&set->sig[0]); } return rc; } LSS_INLINE int LSS_NAME(sigprocmask)(int how, const struct kernel_sigset_t *set, struct kernel_sigset_t *oldset) { int olderrno = LSS_ERRNO; int rc = LSS_NAME(rt_sigprocmask)(how, set, oldset, (KERNEL_NSIG+7)/8); if (rc < 0 && LSS_ERRNO == ENOSYS) { LSS_ERRNO = olderrno; if (oldset) { LSS_NAME(sigemptyset)(oldset); } rc = LSS_NAME(_sigprocmask)(how, set ? &set->sig[0] : NULL, oldset ? &oldset->sig[0] : NULL); } return rc; } LSS_INLINE int LSS_NAME(sigsuspend)(const struct kernel_sigset_t *set) { int olderrno = LSS_ERRNO; int rc = LSS_NAME(rt_sigsuspend)(set, (KERNEL_NSIG+7)/8); if (rc < 0 && LSS_ERRNO == ENOSYS) { LSS_ERRNO = olderrno; rc = LSS_NAME(_sigsuspend)( #ifndef __PPC__ set, 0, #endif set->sig[0]); } return rc; } #endif #if defined(__PPC__) #undef LSS_SC_LOADARGS_0 #define LSS_SC_LOADARGS_0(dummy...) #undef LSS_SC_LOADARGS_1 #define LSS_SC_LOADARGS_1(arg1) \ __sc_4 = (unsigned long) (arg1) #undef LSS_SC_LOADARGS_2 #define LSS_SC_LOADARGS_2(arg1, arg2) \ LSS_SC_LOADARGS_1(arg1); \ __sc_5 = (unsigned long) (arg2) #undef LSS_SC_LOADARGS_3 #define LSS_SC_LOADARGS_3(arg1, arg2, arg3) \ LSS_SC_LOADARGS_2(arg1, arg2); \ __sc_6 = (unsigned long) (arg3) #undef LSS_SC_LOADARGS_4 #define LSS_SC_LOADARGS_4(arg1, arg2, arg3, arg4) \ LSS_SC_LOADARGS_3(arg1, arg2, arg3); \ __sc_7 = (unsigned long) (arg4) #undef LSS_SC_LOADARGS_5 #define LSS_SC_LOADARGS_5(arg1, arg2, arg3, arg4, arg5) \ LSS_SC_LOADARGS_4(arg1, arg2, arg3, arg4); \ __sc_8 = (unsigned long) (arg5) #undef LSS_SC_BODY #define LSS_SC_BODY(nr, type, opt, args...) \ long __sc_ret, __sc_err; \ { \ register unsigned long __sc_0 __asm__ ("r0") = __NR_socketcall; \ register unsigned long __sc_3 __asm__ ("r3") = opt; \ register unsigned long __sc_4 __asm__ ("r4"); \ register unsigned long __sc_5 __asm__ ("r5"); \ register unsigned long __sc_6 __asm__ ("r6"); \ register unsigned long __sc_7 __asm__ ("r7"); \ register unsigned long __sc_8 __asm__ ("r8"); \ LSS_SC_LOADARGS_##nr(args); \ __asm__ __volatile__ \ ("stwu 1, -48(1)\n\t" \ "stw 4, 20(1)\n\t" \ "stw 5, 24(1)\n\t" \ "stw 6, 28(1)\n\t" \ "stw 7, 32(1)\n\t" \ "stw 8, 36(1)\n\t" \ "addi 4, 1, 20\n\t" \ "sc\n\t" \ "mfcr %0" \ : "=&r" (__sc_0), \ "=&r" (__sc_3), "=&r" (__sc_4), \ "=&r" (__sc_5), "=&r" (__sc_6), \ "=&r" (__sc_7), "=&r" (__sc_8) \ : LSS_ASMINPUT_##nr \ : "cr0", "ctr", "memory"); \ __sc_ret = __sc_3; \ __sc_err = __sc_0; \ } \ LSS_RETURN(type, __sc_ret, __sc_err) LSS_INLINE ssize_t LSS_NAME(recvmsg)(int s,struct kernel_msghdr *msg, int flags){ LSS_SC_BODY(3, ssize_t, 17, s, msg, flags); } LSS_INLINE ssize_t LSS_NAME(sendmsg)(int s, const struct kernel_msghdr *msg, int flags) { LSS_SC_BODY(3, ssize_t, 16, s, msg, flags); } // TODO(csilvers): why is this ifdef'ed out? #if 0 LSS_INLINE ssize_t LSS_NAME(sendto)(int s, const void *buf, size_t len, int flags, const struct kernel_sockaddr *to, unsigned int tolen) { LSS_BODY(6, ssize_t, 11, s, buf, len, flags, to, tolen); } #endif LSS_INLINE int LSS_NAME(shutdown)(int s, int how) { LSS_SC_BODY(2, int, 13, s, how); } LSS_INLINE int LSS_NAME(socket)(int domain, int type, int protocol) { LSS_SC_BODY(3, int, 1, domain, type, protocol); } LSS_INLINE int LSS_NAME(socketpair)(int d, int type, int protocol, int sv[2]) { LSS_SC_BODY(4, int, 8, d, type, protocol, sv); } #endif #if defined(__i386__) || defined(__ARM_ARCH_3__) || \ (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) #define __NR__socketcall __NR_socketcall LSS_INLINE _syscall2(int, _socketcall, int, c, va_list, a) LSS_INLINE int LSS_NAME(socketcall)(int op, ...) { int rc; va_list ap; va_start(ap, op); rc = LSS_NAME(_socketcall)(op, ap); va_end(ap); return rc; } LSS_INLINE ssize_t LSS_NAME(recvmsg)(int s,struct kernel_msghdr *msg, int flags){ return (ssize_t)LSS_NAME(socketcall)(17, s, msg, flags); } LSS_INLINE ssize_t LSS_NAME(sendmsg)(int s, const struct kernel_msghdr *msg, int flags) { return (ssize_t)LSS_NAME(socketcall)(16, s, msg, flags); } LSS_INLINE ssize_t LSS_NAME(sendto)(int s, const void *buf, size_t len, int flags, const struct kernel_sockaddr *to, unsigned int tolen) { return (ssize_t)LSS_NAME(socketcall)(11, s, buf, len, flags, to, tolen); } LSS_INLINE int LSS_NAME(shutdown)(int s, int how) { return LSS_NAME(socketcall)(13, s, how); } LSS_INLINE int LSS_NAME(socket)(int domain, int type, int protocol) { return LSS_NAME(socketcall)(1, domain, type, protocol); } LSS_INLINE int LSS_NAME(socketpair)(int d, int type, int protocol, int sv[2]) { return LSS_NAME(socketcall)(8, d, type, protocol, sv); } #endif #if defined(__i386__) || defined(__PPC__) LSS_INLINE _syscall4(int, fstatat64, int, d, const char *, p, struct kernel_stat64 *, b, int, f) #endif #if defined(__i386__) || defined(__PPC__) || \ (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) LSS_INLINE _syscall3(pid_t, waitpid, pid_t, p, int*, s, int, o) #endif #if defined(__mips__) /* sys_pipe() on MIPS has non-standard calling conventions, as it returns * both file handles through CPU registers. */ LSS_INLINE int LSS_NAME(pipe)(int *p) { register unsigned long __v0 __asm__("$2") = __NR_pipe; register unsigned long __v1 __asm__("$3"); register unsigned long __r7 __asm__("$7"); __asm__ __volatile__ ("syscall\n" : "=&r"(__v0), "=&r"(__v1), "+r" (__r7) : "0"(__v0) : "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", "memory"); if (__r7) { LSS_ERRNO = __v0; return -1; } else { p[0] = __v0; p[1] = __v1; return 0; } } #else LSS_INLINE _syscall1(int, pipe, int *, p) #endif /* TODO(csilvers): see if ppc can/should support this as well */ #if defined(__i386__) || defined(__ARM_ARCH_3__) || \ (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI64) #define __NR__statfs64 __NR_statfs64 #define __NR__fstatfs64 __NR_fstatfs64 LSS_INLINE _syscall3(int, _statfs64, const char*, p, size_t, s,struct kernel_statfs64*, b) LSS_INLINE _syscall3(int, _fstatfs64, int, f, size_t, s,struct kernel_statfs64*, b) LSS_INLINE int LSS_NAME(statfs64)(const char *p, struct kernel_statfs64 *b) { return LSS_NAME(_statfs64)(p, sizeof(*b), b); } LSS_INLINE int LSS_NAME(fstatfs64)(int f,struct kernel_statfs64 *b) { return LSS_NAME(_fstatfs64)(f, sizeof(*b), b); } #endif LSS_INLINE int LSS_NAME(execv)(const char *path, const char *const argv[]) { extern char **environ; return LSS_NAME(execve)(path, argv, (const char *const *)environ); } LSS_INLINE pid_t LSS_NAME(gettid)() { pid_t tid = LSS_NAME(_gettid)(); if (tid != -1) { return tid; } return LSS_NAME(getpid)(); } LSS_INLINE void *LSS_NAME(mremap)(void *old_address, size_t old_size, size_t new_size, int flags, ...) { va_list ap; void *new_address, *rc; va_start(ap, flags); new_address = va_arg(ap, void *); rc = LSS_NAME(_mremap)(old_address, old_size, new_size, flags, new_address); va_end(ap); return rc; } LSS_INLINE int LSS_NAME(ptrace_detach)(pid_t pid) { /* PTRACE_DETACH can sometimes forget to wake up the tracee and it * then sends job control signals to the real parent, rather than to * the tracer. We reduce the risk of this happening by starting a * whole new time slice, and then quickly sending a SIGCONT signal * right after detaching from the tracee. */ int rc, err; LSS_NAME(sched_yield)(); rc = LSS_NAME(ptrace)(PTRACE_DETACH, pid, (void *)0, (void *)0); err = LSS_ERRNO; LSS_NAME(kill)(pid, SIGCONT); LSS_ERRNO = err; return rc; } LSS_INLINE int LSS_NAME(raise)(int sig) { return LSS_NAME(kill)(LSS_NAME(getpid)(), sig); } LSS_INLINE int LSS_NAME(setpgrp)() { return LSS_NAME(setpgid)(0, 0); } LSS_INLINE int LSS_NAME(sysconf)(int name) { extern int __getpagesize(void); switch (name) { case _SC_OPEN_MAX: { struct kernel_rlimit limit; return LSS_NAME(getrlimit)(RLIMIT_NOFILE, &limit) < 0 ? 8192 : limit.rlim_cur; } case _SC_PAGESIZE: return __getpagesize(); default: errno = ENOSYS; return -1; } } #if defined(__x86_64__) || \ (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI64) LSS_INLINE _syscall4(ssize_t, pread64, int, f, void *, b, size_t, c, loff_t, o) LSS_INLINE _syscall4(ssize_t, pwrite64, int, f, const void *, b, size_t, c, loff_t, o) LSS_INLINE _syscall3(int, readahead, int, f, loff_t, o, unsigned, c) #else #define __NR__pread64 __NR_pread64 #define __NR__pwrite64 __NR_pwrite64 #define __NR__readahead __NR_readahead LSS_INLINE _syscall5(ssize_t, _pread64, int, f, void *, b, size_t, c, unsigned, o1, unsigned, o2) LSS_INLINE _syscall5(ssize_t, _pwrite64, int, f, const void *, b, size_t, c, unsigned, o1, long, o2) LSS_INLINE _syscall4(int, _readahead, int, f, unsigned, o1, unsigned, o2, size_t, c); /* We force 64bit-wide parameters onto the stack, then access each * 32-bit component individually. This guarantees that we build the * correct parameters independent of the native byte-order of the * underlying architecture. */ LSS_INLINE ssize_t LSS_NAME(pread64)(int fd, void *buf, size_t count, loff_t off) { union { loff_t off; unsigned arg[2]; } o = { off }; return LSS_NAME(_pread64)(fd, buf, count, o.arg[0], o.arg[1]); } LSS_INLINE ssize_t LSS_NAME(pwrite64)(int fd, const void *buf, size_t count, loff_t off) { union { loff_t off; unsigned arg[2]; } o = { off }; return LSS_NAME(_pwrite64)(fd, buf, count, o.arg[0], o.arg[1]); } LSS_INLINE int LSS_NAME(readahead)(int fd, loff_t off, int len) { union { loff_t off; unsigned arg[2]; } o = { off }; return LSS_NAME(_readahead)(fd, o.arg[0], o.arg[1], len); } #endif #endif #if defined(__cplusplus) && !defined(SYS_CPLUSPLUS) } #endif #endif #endif ================================================ FILE: distro/google-perftools-1.7/src/base/linuxthreads.cc ================================================ /* Copyright (c) 2005-2007, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Markus Gutschke */ #include "base/linuxthreads.h" #ifdef THREADS #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include #include #include "base/linux_syscall_support.h" #include "base/thread_lister.h" #ifndef CLONE_UNTRACED #define CLONE_UNTRACED 0x00800000 #endif /* Synchronous signals that should not be blocked while in the lister thread. */ static const int sync_signals[] = { SIGABRT, SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGXCPU, SIGXFSZ }; /* itoa() is not a standard function, and we cannot safely call printf() * after suspending threads. So, we just implement our own copy. A * recursive approach is the easiest here. */ static char *local_itoa(char *buf, int i) { if (i < 0) { *buf++ = '-'; return local_itoa(buf, -i); } else { if (i >= 10) buf = local_itoa(buf, i/10); *buf++ = (i%10) + '0'; *buf = '\000'; return buf; } } /* Wrapper around clone() that runs "fn" on the same stack as the * caller! Unlike fork(), the cloned thread shares the same address space. * The caller must be careful to use only minimal amounts of stack until * the cloned thread has returned. * There is a good chance that the cloned thread and the caller will share * the same copy of errno! */ #ifdef __GNUC__ #if __GNUC__ == 3 && __GNUC_MINOR__ >= 1 || __GNUC__ > 3 /* Try to force this function into a separate stack frame, and make sure * that arguments are passed on the stack. */ static int local_clone (int (*fn)(void *), void *arg, ...) __attribute__ ((noinline)); #endif #endif static int local_clone (int (*fn)(void *), void *arg, ...) { /* Leave 4kB of gap between the callers stack and the new clone. This * should be more than sufficient for the caller to call waitpid() until * the cloned thread terminates. * * It is important that we set the CLONE_UNTRACED flag, because newer * versions of "gdb" otherwise attempt to attach to our thread, and will * attempt to reap its status codes. This subsequently results in the * caller hanging indefinitely in waitpid(), waiting for a change in * status that will never happen. By setting the CLONE_UNTRACED flag, we * prevent "gdb" from stealing events, but we still expect the thread * lister to fail, because it cannot PTRACE_ATTACH to the process that * is being debugged. This is OK and the error code will be reported * correctly. */ return sys_clone(fn, (char *)&arg - 4096, CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_UNTRACED, arg, 0, 0, 0); } /* Local substitute for the atoi() function, which is not necessarily safe * to call once threads are suspended (depending on whether libc looks up * locale information, when executing atoi()). */ static int local_atoi(const char *s) { int n = 0; int neg = *s == '-'; if (neg) s++; while (*s >= '0' && *s <= '9') n = 10*n + (*s++ - '0'); return neg ? -n : n; } /* Re-runs fn until it doesn't cause EINTR */ #define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR) /* Wrap a class around system calls, in order to give us access to * a private copy of errno. This only works in C++, but it has the * advantage of not needing nested functions, which are a non-standard * language extension. */ #ifdef __cplusplus namespace { class SysCalls { public: #define SYS_CPLUSPLUS #define SYS_ERRNO my_errno #define SYS_INLINE inline #define SYS_PREFIX -1 #undef SYS_LINUX_SYSCALL_SUPPORT_H #include "linux_syscall_support.h" SysCalls() : my_errno(0) { } int my_errno; }; } #define ERRNO sys.my_errno #else #define ERRNO my_errno #endif /* Wrapper for open() which is guaranteed to never return EINTR. */ static int c_open(const char *fname, int flags, int mode) { ssize_t rc; NO_INTR(rc = sys_open(fname, flags, mode)); return rc; } /* abort() is not safely reentrant, and changes it's behavior each time * it is called. This means, if the main application ever called abort() * we cannot safely call it again. This would happen if we were called * from a SIGABRT signal handler in the main application. So, document * that calling SIGABRT from the thread lister makes it not signal safe * (and vice-versa). * Also, since we share address space with the main application, we * cannot call abort() from the callback and expect the main application * to behave correctly afterwards. In fact, the only thing we can do, is * to terminate the main application with extreme prejudice (aka * PTRACE_KILL). * We set up our own SIGABRT handler to do this. * In order to find the main application from the signal handler, we * need to store information about it in global variables. This is * safe, because the main application should be suspended at this * time. If the callback ever called ResumeAllProcessThreads(), then * we are running a higher risk, though. So, try to avoid calling * abort() after calling ResumeAllProcessThreads. */ static volatile int *sig_pids, sig_num_threads, sig_proc, sig_marker; /* Signal handler to help us recover from dying while we are attached to * other threads. */ static void SignalHandler(int signum, siginfo_t *si, void *data) { if (sig_pids != NULL) { if (signum == SIGABRT) { while (sig_num_threads-- > 0) { /* Not sure if sched_yield is really necessary here, but it does not */ /* hurt, and it might be necessary for the same reasons that we have */ /* to do so in sys_ptrace_detach(). */ sys_sched_yield(); sys_ptrace(PTRACE_KILL, sig_pids[sig_num_threads], 0, 0); } } else if (sig_num_threads > 0) { ResumeAllProcessThreads(sig_num_threads, (int *)sig_pids); } } sig_pids = NULL; if (sig_marker >= 0) NO_INTR(sys_close(sig_marker)); sig_marker = -1; if (sig_proc >= 0) NO_INTR(sys_close(sig_proc)); sig_proc = -1; sys__exit(signum == SIGABRT ? 1 : 2); } /* Try to dirty the stack, and hope that the compiler is not smart enough * to optimize this function away. Or worse, the compiler could inline the * function and permanently allocate the data on the stack. */ static void DirtyStack(size_t amount) { char buf[amount]; memset(buf, 0, amount); sys_read(-1, buf, amount); } /* Data structure for passing arguments to the lister thread. */ #define ALT_STACKSIZE (MINSIGSTKSZ + 4096) struct ListerParams { int result, err; char *altstack_mem; ListAllProcessThreadsCallBack callback; void *parameter; va_list ap; }; static void ListerThread(struct ListerParams *args) { int found_parent = 0; pid_t clone_pid = sys_gettid(), ppid = sys_getppid(); char proc_self_task[80], marker_name[48], *marker_path; const char *proc_paths[3]; const char *const *proc_path = proc_paths; int proc = -1, marker = -1, num_threads = 0; int max_threads = 0, sig; struct kernel_stat marker_sb, proc_sb; stack_t altstack; /* Create "marker" that we can use to detect threads sharing the same * address space and the same file handles. By setting the FD_CLOEXEC flag * we minimize the risk of misidentifying child processes as threads; * and since there is still a race condition, we will filter those out * later, anyway. */ if ((marker = sys_socket(PF_LOCAL, SOCK_DGRAM, 0)) < 0 || sys_fcntl(marker, F_SETFD, FD_CLOEXEC) < 0) { failure: args->result = -1; args->err = errno; if (marker >= 0) NO_INTR(sys_close(marker)); sig_marker = marker = -1; if (proc >= 0) NO_INTR(sys_close(proc)); sig_proc = proc = -1; sys__exit(1); } /* Compute search paths for finding thread directories in /proc */ local_itoa(strrchr(strcpy(proc_self_task, "/proc/"), '\000'), ppid); strcpy(marker_name, proc_self_task); marker_path = marker_name + strlen(marker_name); strcat(proc_self_task, "/task/"); proc_paths[0] = proc_self_task; /* /proc/$$/task/ */ proc_paths[1] = "/proc/"; /* /proc/ */ proc_paths[2] = NULL; /* Compute path for marker socket in /proc */ local_itoa(strcpy(marker_path, "/fd/") + 4, marker); if (sys_stat(marker_name, &marker_sb) < 0) { goto failure; } /* Catch signals on an alternate pre-allocated stack. This way, we can * safely execute the signal handler even if we ran out of memory. */ memset(&altstack, 0, sizeof(altstack)); altstack.ss_sp = args->altstack_mem; altstack.ss_flags = 0; altstack.ss_size = ALT_STACKSIZE; sys_sigaltstack(&altstack, (const stack_t *)NULL); /* Some kernels forget to wake up traced processes, when the * tracer dies. So, intercept synchronous signals and make sure * that we wake up our tracees before dying. It is the caller's * responsibility to ensure that asynchronous signals do not * interfere with this function. */ sig_marker = marker; sig_proc = -1; for (sig = 0; sig < sizeof(sync_signals)/sizeof(*sync_signals); sig++) { struct kernel_sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_sigaction_ = SignalHandler; sys_sigfillset(&sa.sa_mask); sa.sa_flags = SA_ONSTACK|SA_SIGINFO|SA_RESETHAND; sys_sigaction(sync_signals[sig], &sa, (struct kernel_sigaction *)NULL); } /* Read process directories in /proc/... */ for (;;) { /* Some kernels know about threads, and hide them in "/proc" * (although they are still there, if you know the process * id). Threads are moved into a separate "task" directory. We * check there first, and then fall back on the older naming * convention if necessary. */ if ((sig_proc = proc = c_open(*proc_path, O_RDONLY|O_DIRECTORY, 0)) < 0) { if (*++proc_path != NULL) continue; goto failure; } if (sys_fstat(proc, &proc_sb) < 0) goto failure; /* Since we are suspending threads, we cannot call any libc * functions that might acquire locks. Most notably, we cannot * call malloc(). So, we have to allocate memory on the stack, * instead. Since we do not know how much memory we need, we * make a best guess. And if we guessed incorrectly we retry on * a second iteration (by jumping to "detach_threads"). * * Unless the number of threads is increasing very rapidly, we * should never need to do so, though, as our guestimate is very * conservative. */ if (max_threads < proc_sb.st_nlink + 100) max_threads = proc_sb.st_nlink + 100; /* scope */ { pid_t pids[max_threads]; int added_entries = 0; sig_num_threads = num_threads; sig_pids = pids; for (;;) { struct kernel_dirent *entry; char buf[4096]; ssize_t nbytes = sys_getdents(proc, (struct kernel_dirent *)buf, sizeof(buf)); if (nbytes < 0) goto failure; else if (nbytes == 0) { if (added_entries) { /* Need to keep iterating over "/proc" in multiple * passes until we no longer find any more threads. This * algorithm eventually completes, when all threads have * been suspended. */ added_entries = 0; sys_lseek(proc, 0, SEEK_SET); continue; } break; } for (entry = (struct kernel_dirent *)buf; entry < (struct kernel_dirent *)&buf[nbytes]; entry = (struct kernel_dirent *)((char *)entry+entry->d_reclen)) { if (entry->d_ino != 0) { const char *ptr = entry->d_name; pid_t pid; /* Some kernels hide threads by preceding the pid with a '.' */ if (*ptr == '.') ptr++; /* If the directory is not numeric, it cannot be a * process/thread */ if (*ptr < '0' || *ptr > '9') continue; pid = local_atoi(ptr); /* Attach (and suspend) all threads */ if (pid && pid != clone_pid) { struct kernel_stat tmp_sb; char fname[entry->d_reclen + 48]; strcat(strcat(strcpy(fname, "/proc/"), entry->d_name), marker_path); /* Check if the marker is identical to the one we created */ if (sys_stat(fname, &tmp_sb) >= 0 && marker_sb.st_ino == tmp_sb.st_ino) { long i, j; /* Found one of our threads, make sure it is no duplicate */ for (i = 0; i < num_threads; i++) { /* Linear search is slow, but should not matter much for * the typically small number of threads. */ if (pids[i] == pid) { /* Found a duplicate; most likely on second pass */ goto next_entry; } } /* Check whether data structure needs growing */ if (num_threads >= max_threads) { /* Back to square one, this time with more memory */ NO_INTR(sys_close(proc)); goto detach_threads; } /* Attaching to thread suspends it */ pids[num_threads++] = pid; sig_num_threads = num_threads; if (sys_ptrace(PTRACE_ATTACH, pid, (void *)0, (void *)0) < 0) { /* If operation failed, ignore thread. Maybe it * just died? There might also be a race * condition with a concurrent core dumper or * with a debugger. In that case, we will just * make a best effort, rather than failing * entirely. */ num_threads--; sig_num_threads = num_threads; goto next_entry; } while (sys_waitpid(pid, (int *)0, __WALL) < 0) { if (errno != EINTR) { sys_ptrace_detach(pid); num_threads--; sig_num_threads = num_threads; goto next_entry; } } if (sys_ptrace(PTRACE_PEEKDATA, pid, &i, &j) || i++ != j || sys_ptrace(PTRACE_PEEKDATA, pid, &i, &j) || i != j) { /* Address spaces are distinct, even though both * processes show the "marker". This is probably * a forked child process rather than a thread. */ sys_ptrace_detach(pid); num_threads--; sig_num_threads = num_threads; } else { found_parent |= pid == ppid; added_entries++; } } } } next_entry:; } } NO_INTR(sys_close(proc)); sig_proc = proc = -1; /* If we failed to find any threads, try looking somewhere else in * /proc. Maybe, threads are reported differently on this system. */ if (num_threads > 1 || !*++proc_path) { NO_INTR(sys_close(marker)); sig_marker = marker = -1; /* If we never found the parent process, something is very wrong. * Most likely, we are running in debugger. Any attempt to operate * on the threads would be very incomplete. Let's just report an * error to the caller. */ if (!found_parent) { ResumeAllProcessThreads(num_threads, pids); sys__exit(3); } /* Now we are ready to call the callback, * which takes care of resuming the threads for us. */ args->result = args->callback(args->parameter, num_threads, pids, args->ap); args->err = errno; /* Callback should have resumed threads, but better safe than sorry */ if (ResumeAllProcessThreads(num_threads, pids)) { /* Callback forgot to resume at least one thread, report error */ args->err = EINVAL; args->result = -1; } sys__exit(0); } detach_threads: /* Resume all threads prior to retrying the operation */ ResumeAllProcessThreads(num_threads, pids); sig_pids = NULL; num_threads = 0; sig_num_threads = num_threads; max_threads += 100; } } } /* This function gets the list of all linux threads of the current process * passes them to the 'callback' along with the 'parameter' pointer; at the * call back call time all the threads are paused via * PTRACE_ATTACH. * The callback is executed from a separate thread which shares only the * address space, the filesystem, and the filehandles with the caller. Most * notably, it does not share the same pid and ppid; and if it terminates, * the rest of the application is still there. 'callback' is supposed to do * or arrange for ResumeAllProcessThreads. This happens automatically, if * the thread raises a synchronous signal (e.g. SIGSEGV); asynchronous * signals are blocked. If the 'callback' decides to unblock them, it must * ensure that they cannot terminate the application, or that * ResumeAllProcessThreads will get called. * It is an error for the 'callback' to make any library calls that could * acquire locks. Most notably, this means that most system calls have to * avoid going through libc. Also, this means that it is not legal to call * exit() or abort(). * We return -1 on error and the return value of 'callback' on success. */ int ListAllProcessThreads(void *parameter, ListAllProcessThreadsCallBack callback, ...) { char altstack_mem[ALT_STACKSIZE]; struct ListerParams args; pid_t clone_pid; int dumpable = 1, sig; struct kernel_sigset_t sig_blocked, sig_old; va_start(args.ap, callback); /* If we are short on virtual memory, initializing the alternate stack * might trigger a SIGSEGV. Let's do this early, before it could get us * into more trouble (i.e. before signal handlers try to use the alternate * stack, and before we attach to other threads). */ memset(altstack_mem, 0, sizeof(altstack_mem)); /* Some of our cleanup functions could conceivable use more stack space. * Try to touch the stack right now. This could be defeated by the compiler * being too smart for it's own good, so try really hard. */ DirtyStack(32768); /* Make this process "dumpable". This is necessary in order to ptrace() * after having called setuid(). */ dumpable = sys_prctl(PR_GET_DUMPABLE, 0); if (!dumpable) sys_prctl(PR_SET_DUMPABLE, 1); /* Fill in argument block for dumper thread */ args.result = -1; args.err = 0; args.altstack_mem = altstack_mem; args.parameter = parameter; args.callback = callback; /* Before cloning the thread lister, block all asynchronous signals, as we */ /* are not prepared to handle them. */ sys_sigfillset(&sig_blocked); for (sig = 0; sig < sizeof(sync_signals)/sizeof(*sync_signals); sig++) { sys_sigdelset(&sig_blocked, sync_signals[sig]); } if (sys_sigprocmask(SIG_BLOCK, &sig_blocked, &sig_old)) { args.err = errno; args.result = -1; goto failed; } /* scope */ { /* After cloning, both the parent and the child share the same instance * of errno. We must make sure that at least one of these processes * (in our case, the parent) uses modified syscall macros that update * a local copy of errno, instead. */ #ifdef __cplusplus #define sys0_sigprocmask sys.sigprocmask #define sys0_waitpid sys.waitpid SysCalls sys; #else int my_errno; #define SYS_ERRNO my_errno #define SYS_INLINE inline #define SYS_PREFIX 0 #undef SYS_LINUX_SYSCALL_SUPPORT_H #include "linux_syscall_support.h" #endif int clone_errno; clone_pid = local_clone((int (*)(void *))ListerThread, &args); clone_errno = errno; sys_sigprocmask(SIG_SETMASK, &sig_old, &sig_old); if (clone_pid >= 0) { int status, rc; while ((rc = sys0_waitpid(clone_pid, &status, __WALL)) < 0 && ERRNO == EINTR) { /* Keep waiting */ } if (rc < 0) { args.err = ERRNO; args.result = -1; } else if (WIFEXITED(status)) { switch (WEXITSTATUS(status)) { case 0: break; /* Normal process termination */ case 2: args.err = EFAULT; /* Some fault (e.g. SIGSEGV) detected */ args.result = -1; break; case 3: args.err = EPERM; /* Process is already being traced */ args.result = -1; break; default:args.err = ECHILD; /* Child died unexpectedly */ args.result = -1; break; } } else if (!WIFEXITED(status)) { args.err = EFAULT; /* Terminated due to an unhandled signal*/ args.result = -1; } } else { args.result = -1; args.err = clone_errno; } } /* Restore the "dumpable" state of the process */ failed: if (!dumpable) sys_prctl(PR_SET_DUMPABLE, dumpable); va_end(args.ap); errno = args.err; return args.result; } /* This function resumes the list of all linux threads that * ListAllProcessThreads pauses before giving to its callback. * The function returns non-zero if at least one thread was * suspended and has now been resumed. */ int ResumeAllProcessThreads(int num_threads, pid_t *thread_pids) { int detached_at_least_one = 0; while (num_threads-- > 0) { detached_at_least_one |= sys_ptrace_detach(thread_pids[num_threads]) >= 0; } return detached_at_least_one; } #ifdef __cplusplus } #endif #endif ================================================ FILE: distro/google-perftools-1.7/src/base/linuxthreads.h ================================================ /* Copyright (c) 2005-2007, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Markus Gutschke */ #ifndef _LINUXTHREADS_H #define _LINUXTHREADS_H /* Include thread_lister.h to get the interface that we implement for linux. */ /* We currently only support x86-32 and x86-64 on Linux. Porting to other * related platforms should not be difficult. */ #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) || \ defined(__mips__) || defined(__PPC__)) && defined(__linux) /* Define the THREADS symbol to make sure that there is exactly one core dumper * built into the library. */ #define THREADS "Linux /proc" #endif #endif /* _LINUXTHREADS_H */ ================================================ FILE: distro/google-perftools-1.7/src/base/logging.cc ================================================ // Copyright (c) 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // This file just provides storage for FLAGS_verbose. #include #include "base/logging.h" #include "base/commandlineflags.h" DEFINE_int32(verbose, EnvToInt("PERFTOOLS_VERBOSE", 0), "Set to numbers >0 for more verbose output, or <0 for less. " "--verbose == -4 means we log fatal errors only."); #if defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) // While windows does have a POSIX-compatible API // (_open/_write/_close), it acquires memory. Using this lower-level // windows API is the closest we can get to being "raw". RawFD RawOpenForWriting(const char* filename) { // CreateFile allocates memory if file_name isn't absolute, so if // that ever becomes a problem then we ought to compute the absolute // path on its behalf (perhaps the ntdll/kernel function isn't aware // of the working directory?) RawFD fd = CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); if (fd != kIllegalRawFD && GetLastError() == ERROR_ALREADY_EXISTS) SetEndOfFile(fd); // truncate the existing file return fd; } void RawWrite(RawFD handle, const char* buf, size_t len) { while (len > 0) { DWORD wrote; BOOL ok = WriteFile(handle, buf, len, &wrote, NULL); // We do not use an asynchronous file handle, so ok==false means an error if (!ok) break; buf += wrote; len -= wrote; } } void RawClose(RawFD handle) { CloseHandle(handle); } #else // _WIN32 || __CYGWIN__ || __CYGWIN32__ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_FCNTL_H #include #endif // Re-run fn until it doesn't cause EINTR. #define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR) RawFD RawOpenForWriting(const char* filename) { return open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0664); } void RawWrite(RawFD fd, const char* buf, size_t len) { while (len > 0) { ssize_t r; NO_INTR(r = write(fd, buf, len)); if (r <= 0) break; buf += r; len -= r; } } void RawClose(RawFD fd) { NO_INTR(close(fd)); } #endif // _WIN32 || __CYGWIN__ || __CYGWIN32__ ================================================ FILE: distro/google-perftools-1.7/src/base/logging.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // This file contains #include information about logging-related stuff. // Pretty much everybody needs to #include this file so that they can // log various happenings. // #ifndef _LOGGING_H_ #define _LOGGING_H_ #include #include #include #include #ifdef HAVE_UNISTD_H #include // for write() #endif #include // for strlen(), strcmp() #include #include // for errno #include "base/commandlineflags.h" // On some systems (like freebsd), we can't call write() at all in a // global constructor, perhaps because errno hasn't been set up. // (In windows, we can't call it because it might call malloc.) // Calling the write syscall is safer (it doesn't set errno), so we // prefer that. Note we don't care about errno for logging: we just // do logging on a best-effort basis. #if defined(_MSC_VER) #define WRITE_TO_STDERR(buf, len) WriteToStderr(buf, len); // in port.cc #elif defined(HAVE_SYS_SYSCALL_H) #include #define WRITE_TO_STDERR(buf, len) syscall(SYS_write, STDERR_FILENO, buf, len) #else #define WRITE_TO_STDERR(buf, len) write(STDERR_FILENO, buf, len) #endif // We log all messages at this log-level and below. // INFO == -1, WARNING == -2, ERROR == -3, FATAL == -4 DECLARE_int32(verbose); // CHECK dies with a fatal error if condition is not true. It is *not* // controlled by NDEBUG, so the check will be executed regardless of // compilation mode. Therefore, it is safe to do things like: // CHECK(fp->Write(x) == 4) // Note we use write instead of printf/puts to avoid the risk we'll // call malloc(). #define CHECK(condition) \ do { \ if (!(condition)) { \ WRITE_TO_STDERR("Check failed: " #condition "\n", \ sizeof("Check failed: " #condition "\n")-1); \ exit(1); \ } \ } while (0) // This takes a message to print. The name is historical. #define RAW_CHECK(condition, message) \ do { \ if (!(condition)) { \ WRITE_TO_STDERR("Check failed: " #condition ": " message "\n", \ sizeof("Check failed: " #condition ": " message "\n")-1);\ exit(1); \ } \ } while (0) // This is like RAW_CHECK, but only in debug-mode #ifdef NDEBUG enum { DEBUG_MODE = 0 }; #define RAW_DCHECK(condition, message) #else enum { DEBUG_MODE = 1 }; #define RAW_DCHECK(condition, message) RAW_CHECK(condition, message) #endif // This prints errno as well. Note we use write instead of printf/puts to // avoid the risk we'll call malloc(). #define PCHECK(condition) \ do { \ if (!(condition)) { \ const int err_no = errno; \ WRITE_TO_STDERR("Check failed: " #condition ": ", \ sizeof("Check failed: " #condition ": ")-1); \ WRITE_TO_STDERR(strerror(err_no), strlen(strerror(err_no))); \ WRITE_TO_STDERR("\n", sizeof("\n")-1); \ exit(1); \ } \ } while (0) // Helper macro for binary operators; prints the two values on error // Don't use this macro directly in your code, use CHECK_EQ et al below // WARNING: These don't compile correctly if one of the arguments is a pointer // and the other is NULL. To work around this, simply static_cast NULL to the // type of the desired pointer. // TODO(jandrews): Also print the values in case of failure. Requires some // sort of type-sensitive ToString() function. #define CHECK_OP(op, val1, val2) \ do { \ if (!((val1) op (val2))) { \ fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2); \ exit(1); \ } \ } while (0) #define CHECK_EQ(val1, val2) CHECK_OP(==, val1, val2) #define CHECK_NE(val1, val2) CHECK_OP(!=, val1, val2) #define CHECK_LE(val1, val2) CHECK_OP(<=, val1, val2) #define CHECK_LT(val1, val2) CHECK_OP(< , val1, val2) #define CHECK_GE(val1, val2) CHECK_OP(>=, val1, val2) #define CHECK_GT(val1, val2) CHECK_OP(> , val1, val2) // Synonyms for CHECK_* that are used in some unittests. #define EXPECT_EQ(val1, val2) CHECK_EQ(val1, val2) #define EXPECT_NE(val1, val2) CHECK_NE(val1, val2) #define EXPECT_LE(val1, val2) CHECK_LE(val1, val2) #define EXPECT_LT(val1, val2) CHECK_LT(val1, val2) #define EXPECT_GE(val1, val2) CHECK_GE(val1, val2) #define EXPECT_GT(val1, val2) CHECK_GT(val1, val2) #define ASSERT_EQ(val1, val2) EXPECT_EQ(val1, val2) #define ASSERT_NE(val1, val2) EXPECT_NE(val1, val2) #define ASSERT_LE(val1, val2) EXPECT_LE(val1, val2) #define ASSERT_LT(val1, val2) EXPECT_LT(val1, val2) #define ASSERT_GE(val1, val2) EXPECT_GE(val1, val2) #define ASSERT_GT(val1, val2) EXPECT_GT(val1, val2) // As are these variants. #define EXPECT_TRUE(cond) CHECK(cond) #define EXPECT_FALSE(cond) CHECK(!(cond)) #define EXPECT_STREQ(a, b) CHECK(strcmp(a, b) == 0) #define ASSERT_TRUE(cond) EXPECT_TRUE(cond) #define ASSERT_FALSE(cond) EXPECT_FALSE(cond) #define ASSERT_STREQ(a, b) EXPECT_STREQ(a, b) // Used for (libc) functions that return -1 and set errno #define CHECK_ERR(invocation) PCHECK((invocation) != -1) // A few more checks that only happen in debug mode #ifdef NDEBUG #define DCHECK_EQ(val1, val2) #define DCHECK_NE(val1, val2) #define DCHECK_LE(val1, val2) #define DCHECK_LT(val1, val2) #define DCHECK_GE(val1, val2) #define DCHECK_GT(val1, val2) #else #define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2) #define DCHECK_NE(val1, val2) CHECK_NE(val1, val2) #define DCHECK_LE(val1, val2) CHECK_LE(val1, val2) #define DCHECK_LT(val1, val2) CHECK_LT(val1, val2) #define DCHECK_GE(val1, val2) CHECK_GE(val1, val2) #define DCHECK_GT(val1, val2) CHECK_GT(val1, val2) #endif #ifdef ERROR #undef ERROR // may conflict with ERROR macro on windows #endif enum LogSeverity {INFO = -1, WARNING = -2, ERROR = -3, FATAL = -4}; // NOTE: we add a newline to the end of the output if it's not there already inline void LogPrintf(int severity, const char* pat, va_list ap) { // We write directly to the stderr file descriptor and avoid FILE // buffering because that may invoke malloc() char buf[600]; vsnprintf(buf, sizeof(buf)-1, pat, ap); if (buf[0] != '\0' && buf[strlen(buf)-1] != '\n') { assert(strlen(buf)+1 < sizeof(buf)); strcat(buf, "\n"); } WRITE_TO_STDERR(buf, strlen(buf)); if ((severity) == FATAL) abort(); // LOG(FATAL) indicates a big problem, so don't run atexit() calls } // Note that since the order of global constructors is unspecified, // global code that calls RAW_LOG may execute before FLAGS_verbose is set. // Such code will run with verbosity == 0 no matter what. #define VLOG_IS_ON(severity) (FLAGS_verbose >= severity) // In a better world, we'd use __VA_ARGS__, but VC++ 7 doesn't support it. #define LOG_PRINTF(severity, pat) do { \ if (VLOG_IS_ON(severity)) { \ va_list ap; \ va_start(ap, pat); \ LogPrintf(severity, pat, ap); \ va_end(ap); \ } \ } while (0) // RAW_LOG is the main function; some synonyms are used in unittests. inline void RAW_LOG(int lvl, const char* pat, ...) { LOG_PRINTF(lvl, pat); } inline void RAW_VLOG(int lvl, const char* pat, ...) { LOG_PRINTF(lvl, pat); } inline void LOG(int lvl, const char* pat, ...) { LOG_PRINTF(lvl, pat); } inline void VLOG(int lvl, const char* pat, ...) { LOG_PRINTF(lvl, pat); } inline void LOG_IF(int lvl, bool cond, const char* pat, ...) { if (cond) LOG_PRINTF(lvl, pat); } // This isn't technically logging, but it's also IO and also is an // attempt to be "raw" -- that is, to not use any higher-level libc // routines that might allocate memory or (ideally) try to allocate // locks. We use an opaque file handle (not necessarily an int) // to allow even more low-level stuff in the future. // Like other "raw" routines, these functions are best effort, and // thus don't return error codes (except RawOpenForWriting()). #if defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) #define NOMINMAX // @#!$& windows #include typedef HANDLE RawFD; const RawFD kIllegalRawFD = INVALID_HANDLE_VALUE; #else typedef int RawFD; const RawFD kIllegalRawFD = -1; // what open returns if it fails #endif // defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) RawFD RawOpenForWriting(const char* filename); // uses default permissions void RawWrite(RawFD fd, const char* buf, size_t len); void RawClose(RawFD fd); #endif // _LOGGING_H_ ================================================ FILE: distro/google-perftools-1.7/src/base/low_level_alloc.cc ================================================ /* Copyright (c) 2006, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // A low-level allocator that can be used by other low-level // modules without introducing dependency cycles. // This allocator is slow and wasteful of memory; // it should not be used when performance is key. #include "base/low_level_alloc.h" #include "base/dynamic_annotations.h" #include "base/spinlock.h" #include "base/logging.h" #include "malloc_hook-inl.h" #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_MMAP #include #endif #include // for placement-new // On systems (like freebsd) that don't define MAP_ANONYMOUS, use the old // form of the name instead. #ifndef MAP_ANONYMOUS # define MAP_ANONYMOUS MAP_ANON #endif // A first-fit allocator with amortized logarithmic free() time. // --------------------------------------------------------------------------- static const int kMaxLevel = 30; // We put this class-only struct in a namespace to avoid polluting the // global namespace with this struct name (thus risking an ODR violation). namespace low_level_alloc_internal { // This struct describes one allocated block, or one free block. struct AllocList { struct Header { intptr_t size; // size of entire region, including this field. Must be // first. Valid in both allocated and unallocated blocks intptr_t magic; // kMagicAllocated or kMagicUnallocated xor this LowLevelAlloc::Arena *arena; // pointer to parent arena void *dummy_for_alignment; // aligns regions to 0 mod 2*sizeof(void*) } header; // Next two fields: in unallocated blocks: freelist skiplist data // in allocated blocks: overlaps with client data int levels; // levels in skiplist used AllocList *next[kMaxLevel]; // actually has levels elements. // The AllocList node may not have room for // all kMaxLevel entries. See max_fit in // LLA_SkiplistLevels() }; } using low_level_alloc_internal::AllocList; // --------------------------------------------------------------------------- // A trivial skiplist implementation. This is used to keep the freelist // in address order while taking only logarithmic time per insert and delete. // An integer approximation of log2(size/base) // Requires size >= base. static int IntLog2(size_t size, size_t base) { int result = 0; for (size_t i = size; i > base; i >>= 1) { // i == floor(size/2**result) result++; } // floor(size / 2**result) <= base < floor(size / 2**(result-1)) // => log2(size/(base+1)) <= result < 1+log2(size/base) // => result ~= log2(size/base) return result; } // Return a random integer n: p(n)=1/(2**n) if 1 <= n; p(n)=0 if n < 1. static int Random() { static int32 r = 1; // no locking---it's not critical ANNOTATE_BENIGN_RACE(&r, "benign race, not critical."); int result = 1; while ((((r = r*1103515245 + 12345) >> 30) & 1) == 0) { result++; } return result; } // Return a number of skiplist levels for a node of size bytes, where // base is the minimum node size. Compute level=log2(size / base)+n // where n is 1 if random is false and otherwise a random number generated with // the standard distribution for a skiplist: See Random() above. // Bigger nodes tend to have more skiplist levels due to the log2(size / base) // term, so first-fit searches touch fewer nodes. "level" is clipped so // level max_fit) level = max_fit; if (level > kMaxLevel-1) level = kMaxLevel - 1; RAW_CHECK(level >= 1, "block not big enough for even one level"); return level; } // Return "atleast", the first element of AllocList *head s.t. *atleast >= *e. // For 0 <= i < head->levels, set prev[i] to "no_greater", where no_greater // points to the last element at level i in the AllocList less than *e, or is // head if no such element exists. static AllocList *LLA_SkiplistSearch(AllocList *head, AllocList *e, AllocList **prev) { AllocList *p = head; for (int level = head->levels - 1; level >= 0; level--) { for (AllocList *n; (n = p->next[level]) != 0 && n < e; p = n) { } prev[level] = p; } return (head->levels == 0) ? 0 : prev[0]->next[0]; } // Insert element *e into AllocList *head. Set prev[] as LLA_SkiplistSearch. // Requires that e->levels be previously set by the caller (using // LLA_SkiplistLevels()) static void LLA_SkiplistInsert(AllocList *head, AllocList *e, AllocList **prev) { LLA_SkiplistSearch(head, e, prev); for (; head->levels < e->levels; head->levels++) { // extend prev pointers prev[head->levels] = head; // to all *e's levels } for (int i = 0; i != e->levels; i++) { // add element to list e->next[i] = prev[i]->next[i]; prev[i]->next[i] = e; } } // Remove element *e from AllocList *head. Set prev[] as LLA_SkiplistSearch(). // Requires that e->levels be previous set by the caller (using // LLA_SkiplistLevels()) static void LLA_SkiplistDelete(AllocList *head, AllocList *e, AllocList **prev) { AllocList *found = LLA_SkiplistSearch(head, e, prev); RAW_CHECK(e == found, "element not in freelist"); for (int i = 0; i != e->levels && prev[i]->next[i] == e; i++) { prev[i]->next[i] = e->next[i]; } while (head->levels > 0 && head->next[head->levels - 1] == 0) { head->levels--; // reduce head->levels if level unused } } // --------------------------------------------------------------------------- // Arena implementation struct LowLevelAlloc::Arena { Arena() : mu(SpinLock::LINKER_INITIALIZED) {} // does nothing; for static init explicit Arena(int) : pagesize(0) {} // set pagesize to zero explicitly // for non-static init SpinLock mu; // protects freelist, allocation_count, // pagesize, roundup, min_size AllocList freelist; // head of free list; sorted by addr (under mu) int32 allocation_count; // count of allocated blocks (under mu) int32 flags; // flags passed to NewArena (ro after init) size_t pagesize; // ==getpagesize() (init under mu, then ro) size_t roundup; // lowest power of 2 >= max(16,sizeof (AllocList)) // (init under mu, then ro) size_t min_size; // smallest allocation block size // (init under mu, then ro) }; // The default arena, which is used when 0 is passed instead of an Arena // pointer. static struct LowLevelAlloc::Arena default_arena; // Non-malloc-hooked arenas: used only to allocate metadata for arenas that // do not want malloc hook reporting, so that for them there's no malloc hook // reporting even during arena creation. static struct LowLevelAlloc::Arena unhooked_arena; static struct LowLevelAlloc::Arena unhooked_async_sig_safe_arena; // magic numbers to identify allocated and unallocated blocks static const intptr_t kMagicAllocated = 0x4c833e95; static const intptr_t kMagicUnallocated = ~kMagicAllocated; namespace { class ArenaLock { public: explicit ArenaLock(LowLevelAlloc::Arena *arena) EXCLUSIVE_LOCK_FUNCTION(arena->mu) : left_(false), mask_valid_(false), arena_(arena) { if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) { // We've decided not to support async-signal-safe arena use until // there a demonstrated need. Here's how one could do it though // (would need to be made more portable). #if 0 sigset_t all; sigfillset(&all); this->mask_valid_ = (pthread_sigmask(SIG_BLOCK, &all, &this->mask_) == 0); #else RAW_CHECK(false, "We do not yet support async-signal-safe arena."); #endif } this->arena_->mu.Lock(); } ~ArenaLock() { RAW_CHECK(this->left_, "haven't left Arena region"); } void Leave() UNLOCK_FUNCTION(arena_->mu) { this->arena_->mu.Unlock(); #if 0 if (this->mask_valid_) { pthread_sigmask(SIG_SETMASK, &this->mask_, 0); } #endif this->left_ = true; } private: bool left_; // whether left region bool mask_valid_; #if 0 sigset_t mask_; // old mask of blocked signals #endif LowLevelAlloc::Arena *arena_; DISALLOW_COPY_AND_ASSIGN(ArenaLock); }; } // anonymous namespace // create an appropriate magic number for an object at "ptr" // "magic" should be kMagicAllocated or kMagicUnallocated inline static intptr_t Magic(intptr_t magic, AllocList::Header *ptr) { return magic ^ reinterpret_cast(ptr); } // Initialize the fields of an Arena static void ArenaInit(LowLevelAlloc::Arena *arena) { if (arena->pagesize == 0) { arena->pagesize = getpagesize(); // Round up block sizes to a power of two close to the header size. arena->roundup = 16; while (arena->roundup < sizeof (arena->freelist.header)) { arena->roundup += arena->roundup; } // Don't allocate blocks less than twice the roundup size to avoid tiny // free blocks. arena->min_size = 2 * arena->roundup; arena->freelist.header.size = 0; arena->freelist.header.magic = Magic(kMagicUnallocated, &arena->freelist.header); arena->freelist.header.arena = arena; arena->freelist.levels = 0; memset(arena->freelist.next, 0, sizeof (arena->freelist.next)); arena->allocation_count = 0; if (arena == &default_arena) { // Default arena should be hooked, e.g. for heap-checker to trace // pointer chains through objects in the default arena. arena->flags = LowLevelAlloc::kCallMallocHook; } else if (arena == &unhooked_async_sig_safe_arena) { arena->flags = LowLevelAlloc::kAsyncSignalSafe; } else { arena->flags = 0; // other arenas' flags may be overridden by client, // but unhooked_arena will have 0 in 'flags'. } } } // L < meta_data_arena->mu LowLevelAlloc::Arena *LowLevelAlloc::NewArena(int32 flags, Arena *meta_data_arena) { RAW_CHECK(meta_data_arena != 0, "must pass a valid arena"); if (meta_data_arena == &default_arena) { if ((flags & LowLevelAlloc::kAsyncSignalSafe) != 0) { meta_data_arena = &unhooked_async_sig_safe_arena; } else if ((flags & LowLevelAlloc::kCallMallocHook) == 0) { meta_data_arena = &unhooked_arena; } } // Arena(0) uses the constructor for non-static contexts Arena *result = new (AllocWithArena(sizeof (*result), meta_data_arena)) Arena(0); ArenaInit(result); result->flags = flags; return result; } // L < arena->mu, L < arena->arena->mu bool LowLevelAlloc::DeleteArena(Arena *arena) { RAW_CHECK(arena != 0 && arena != &default_arena && arena != &unhooked_arena, "may not delete default arena"); ArenaLock section(arena); bool empty = (arena->allocation_count == 0); section.Leave(); if (empty) { while (arena->freelist.next[0] != 0) { AllocList *region = arena->freelist.next[0]; size_t size = region->header.size; arena->freelist.next[0] = region->next[0]; RAW_CHECK(region->header.magic == Magic(kMagicUnallocated, ®ion->header), "bad magic number in DeleteArena()"); RAW_CHECK(region->header.arena == arena, "bad arena pointer in DeleteArena()"); RAW_CHECK(size % arena->pagesize == 0, "empty arena has non-page-aligned block size"); RAW_CHECK(reinterpret_cast(region) % arena->pagesize == 0, "empty arena has non-page-aligned block"); int munmap_result; if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) == 0) { munmap_result = munmap(region, size); } else { munmap_result = MallocHook::UnhookedMUnmap(region, size); } RAW_CHECK(munmap_result == 0, "LowLevelAlloc::DeleteArena: munmap failed address"); } Free(arena); } return empty; } // --------------------------------------------------------------------------- // Return value rounded up to next multiple of align. // align must be a power of two. static intptr_t RoundUp(intptr_t addr, intptr_t align) { return (addr + align - 1) & ~(align - 1); } // Equivalent to "return prev->next[i]" but with sanity checking // that the freelist is in the correct order, that it // consists of regions marked "unallocated", and that no two regions // are adjacent in memory (they should have been coalesced). // L < arena->mu static AllocList *Next(int i, AllocList *prev, LowLevelAlloc::Arena *arena) { RAW_CHECK(i < prev->levels, "too few levels in Next()"); AllocList *next = prev->next[i]; if (next != 0) { RAW_CHECK(next->header.magic == Magic(kMagicUnallocated, &next->header), "bad magic number in Next()"); RAW_CHECK(next->header.arena == arena, "bad arena pointer in Next()"); if (prev != &arena->freelist) { RAW_CHECK(prev < next, "unordered freelist"); RAW_CHECK(reinterpret_cast(prev) + prev->header.size < reinterpret_cast(next), "malformed freelist"); } } return next; } // Coalesce list item "a" with its successor if they are adjacent. static void Coalesce(AllocList *a) { AllocList *n = a->next[0]; if (n != 0 && reinterpret_cast(a) + a->header.size == reinterpret_cast(n)) { LowLevelAlloc::Arena *arena = a->header.arena; a->header.size += n->header.size; n->header.magic = 0; n->header.arena = 0; AllocList *prev[kMaxLevel]; LLA_SkiplistDelete(&arena->freelist, n, prev); LLA_SkiplistDelete(&arena->freelist, a, prev); a->levels = LLA_SkiplistLevels(a->header.size, arena->min_size, true); LLA_SkiplistInsert(&arena->freelist, a, prev); } } // Adds block at location "v" to the free list // L >= arena->mu static void AddToFreelist(void *v, LowLevelAlloc::Arena *arena) { AllocList *f = reinterpret_cast( reinterpret_cast(v) - sizeof (f->header)); RAW_CHECK(f->header.magic == Magic(kMagicAllocated, &f->header), "bad magic number in AddToFreelist()"); RAW_CHECK(f->header.arena == arena, "bad arena pointer in AddToFreelist()"); f->levels = LLA_SkiplistLevels(f->header.size, arena->min_size, true); AllocList *prev[kMaxLevel]; LLA_SkiplistInsert(&arena->freelist, f, prev); f->header.magic = Magic(kMagicUnallocated, &f->header); Coalesce(f); // maybe coalesce with successor Coalesce(prev[0]); // maybe coalesce with predecessor } // Frees storage allocated by LowLevelAlloc::Alloc(). // L < arena->mu void LowLevelAlloc::Free(void *v) { if (v != 0) { AllocList *f = reinterpret_cast( reinterpret_cast(v) - sizeof (f->header)); RAW_CHECK(f->header.magic == Magic(kMagicAllocated, &f->header), "bad magic number in Free()"); LowLevelAlloc::Arena *arena = f->header.arena; if ((arena->flags & kCallMallocHook) != 0) { MallocHook::InvokeDeleteHook(v); } ArenaLock section(arena); AddToFreelist(v, arena); RAW_CHECK(arena->allocation_count > 0, "nothing in arena to free"); arena->allocation_count--; section.Leave(); } } // allocates and returns a block of size bytes, to be freed with Free() // L < arena->mu static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) { void *result = 0; if (request != 0) { AllocList *s; // will point to region that satisfies request ArenaLock section(arena); ArenaInit(arena); // round up with header size_t req_rnd = RoundUp(request + sizeof (s->header), arena->roundup); for (;;) { // loop until we find a suitable region // find the minimum levels that a block of this size must have int i = LLA_SkiplistLevels(req_rnd, arena->min_size, false) - 1; if (i < arena->freelist.levels) { // potential blocks exist AllocList *before = &arena->freelist; // predecessor of s while ((s = Next(i, before, arena)) != 0 && s->header.size < req_rnd) { before = s; } if (s != 0) { // we found a region break; } } // we unlock before mmap() both because mmap() may call a callback hook, // and because it may be slow. arena->mu.Unlock(); // mmap generous 64K chunks to decrease // the chances/impact of fragmentation: size_t new_pages_size = RoundUp(req_rnd, arena->pagesize * 16); void *new_pages; if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) { new_pages = MallocHook::UnhookedMMap(0, new_pages_size, PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); } else { new_pages = mmap(0, new_pages_size, PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); } RAW_CHECK(new_pages != MAP_FAILED, "mmap error"); arena->mu.Lock(); s = reinterpret_cast(new_pages); s->header.size = new_pages_size; // Pretend the block is allocated; call AddToFreelist() to free it. s->header.magic = Magic(kMagicAllocated, &s->header); s->header.arena = arena; AddToFreelist(&s->levels, arena); // insert new region into free list } AllocList *prev[kMaxLevel]; LLA_SkiplistDelete(&arena->freelist, s, prev); // remove from free list // s points to the first free region that's big enough if (req_rnd + arena->min_size <= s->header.size) { // big enough to split AllocList *n = reinterpret_cast (req_rnd + reinterpret_cast(s)); n->header.size = s->header.size - req_rnd; n->header.magic = Magic(kMagicAllocated, &n->header); n->header.arena = arena; s->header.size = req_rnd; AddToFreelist(&n->levels, arena); } s->header.magic = Magic(kMagicAllocated, &s->header); RAW_CHECK(s->header.arena == arena, ""); arena->allocation_count++; section.Leave(); result = &s->levels; } ANNOTATE_NEW_MEMORY(result, request); return result; } void *LowLevelAlloc::Alloc(size_t request) { void *result = DoAllocWithArena(request, &default_arena); if ((default_arena.flags & kCallMallocHook) != 0) { // this call must be directly in the user-called allocator function // for MallocHook::GetCallerStackTrace to work properly MallocHook::InvokeNewHook(result, request); } return result; } void *LowLevelAlloc::AllocWithArena(size_t request, Arena *arena) { RAW_CHECK(arena != 0, "must pass a valid arena"); void *result = DoAllocWithArena(request, arena); if ((arena->flags & kCallMallocHook) != 0) { // this call must be directly in the user-called allocator function // for MallocHook::GetCallerStackTrace to work properly MallocHook::InvokeNewHook(result, request); } return result; } LowLevelAlloc::Arena *LowLevelAlloc::DefaultArena() { return &default_arena; } ================================================ FILE: distro/google-perftools-1.7/src/base/low_level_alloc.h ================================================ /* Copyright (c) 2006, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #if !defined(_BASE_LOW_LEVEL_ALLOC_H_) #define _BASE_LOW_LEVEL_ALLOC_H_ // A simple thread-safe memory allocator that does not depend on // mutexes or thread-specific data. It is intended to be used // sparingly, and only when malloc() would introduce an unwanted // dependency, such as inside the heap-checker. #include #include // for size_t #include "base/basictypes.h" class LowLevelAlloc { public: struct Arena; // an arena from which memory may be allocated // Returns a pointer to a block of at least "request" bytes // that have been newly allocated from the specific arena. // for Alloc() call the DefaultArena() is used. // Returns 0 if passed request==0. // Does not return 0 under other circumstances; it crashes if memory // is not available. static void *Alloc(size_t request) ATTRIBUTE_SECTION(malloc_hook); static void *AllocWithArena(size_t request, Arena *arena) ATTRIBUTE_SECTION(malloc_hook); // Deallocates a region of memory that was previously allocated with // Alloc(). Does nothing if passed 0. "s" must be either 0, // or must have been returned from a call to Alloc() and not yet passed to // Free() since that call to Alloc(). The space is returned to the arena // from which it was allocated. static void Free(void *s) ATTRIBUTE_SECTION(malloc_hook); // ATTRIBUTE_SECTION(malloc_hook) for Alloc* and Free // are to put all callers of MallocHook::Invoke* in this module // into special section, // so that MallocHook::GetCallerStackTrace can function accurately. // Create a new arena. // The root metadata for the new arena is allocated in the // meta_data_arena; the DefaultArena() can be passed for meta_data_arena. // These values may be ored into flags: enum { // Report calls to Alloc() and Free() via the MallocHook interface. // Set in the DefaultArena. kCallMallocHook = 0x0001, // Make calls to Alloc(), Free() be async-signal-safe. Not set in // DefaultArena(). kAsyncSignalSafe = 0x0002, // When used with DefaultArena(), the NewArena() and DeleteArena() calls // obey the flags given explicitly in the NewArena() call, even if those // flags differ from the settings in DefaultArena(). So the call // NewArena(kAsyncSignalSafe, DefaultArena()) is itself async-signal-safe, // as well as generatating an arena that provides async-signal-safe // Alloc/Free. }; static Arena *NewArena(int32 flags, Arena *meta_data_arena); // Destroys an arena allocated by NewArena and returns true, // provided no allocated blocks remain in the arena. // If allocated blocks remain in the arena, does nothing and // returns false. // It is illegal to attempt to destroy the DefaultArena(). static bool DeleteArena(Arena *arena); // The default arena that always exists. static Arena *DefaultArena(); private: LowLevelAlloc(); // no instances }; #endif ================================================ FILE: distro/google-perftools-1.7/src/base/simple_mutex.h ================================================ // Copyright (c) 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // --- // Author: Craig Silverstein. // // A simple mutex wrapper, supporting locks and read-write locks. // You should assume the locks are *not* re-entrant. // // To use: you should define the following macros in your configure.ac: // ACX_PTHREAD // AC_RWLOCK // The latter is defined in ../autoconf. // // This class is meant to be internal-only and should be wrapped by an // internal namespace. Before you use this module, please give the // name of your internal namespace for this module. Or, if you want // to expose it, you'll want to move it to the Google namespace. We // cannot put this class in global namespace because there can be some // problems when we have multiple versions of Mutex in each shared object. // // NOTE: TryLock() is broken for NO_THREADS mode, at least in NDEBUG // mode. // // CYGWIN NOTE: Cygwin support for rwlock seems to be buggy: // http://www.cygwin.com/ml/cygwin/2008-12/msg00017.html // Because of that, we might as well use windows locks for // cygwin. They seem to be more reliable than the cygwin pthreads layer. // // TRICKY IMPLEMENTATION NOTE: // This class is designed to be safe to use during // dynamic-initialization -- that is, by global constructors that are // run before main() starts. The issue in this case is that // dynamic-initialization happens in an unpredictable order, and it // could be that someone else's dynamic initializer could call a // function that tries to acquire this mutex -- but that all happens // before this mutex's constructor has run. (This can happen even if // the mutex and the function that uses the mutex are in the same .cc // file.) Basically, because Mutex does non-trivial work in its // constructor, it's not, in the naive implementation, safe to use // before dynamic initialization has run on it. // // The solution used here is to pair the actual mutex primitive with a // bool that is set to true when the mutex is dynamically initialized. // (Before that it's false.) Then we modify all mutex routines to // look at the bool, and not try to lock/unlock until the bool makes // it to true (which happens after the Mutex constructor has run.) // // This works because before main() starts -- particularly, during // dynamic initialization -- there are no threads, so a) it's ok that // the mutex operations are a no-op, since we don't need locking then // anyway; and b) we can be quite confident our bool won't change // state between a call to Lock() and a call to Unlock() (that would // require a global constructor in one translation unit to call Lock() // and another global constructor in another translation unit to call // Unlock() later, which is pretty perverse). // // That said, it's tricky, and can conceivably fail; it's safest to // avoid trying to acquire a mutex in a global constructor, if you // can. One way it can fail is that a really smart compiler might // initialize the bool to true at static-initialization time (too // early) rather than at dynamic-initialization time. To discourage // that, we set is_safe_ to true in code (not the constructor // colon-initializer) and set it to true via a function that always // evaluates to true, but that the compiler can't know always // evaluates to true. This should be good enough. // // A related issue is code that could try to access the mutex // after it's been destroyed in the global destructors (because // the Mutex global destructor runs before some other global // destructor, that tries to acquire the mutex). The way we // deal with this is by taking a constructor arg that global // mutexes should pass in, that causes the destructor to do no // work. We still depend on the compiler not doing anything // weird to a Mutex's memory after it is destroyed, but for a // static global variable, that's pretty safe. #ifndef GOOGLE_MUTEX_H_ #define GOOGLE_MUTEX_H_ #include #if defined(NO_THREADS) typedef int MutexType; // to keep a lock-count #elif defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN // We only need minimal includes # endif // We need Windows NT or later for TryEnterCriticalSection(). If you // don't need that functionality, you can remove these _WIN32_WINNT // lines, and change TryLock() to assert(0) or something. # ifndef _WIN32_WINNT # define _WIN32_WINNT 0x0400 # endif # include typedef CRITICAL_SECTION MutexType; #elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK) // Needed for pthread_rwlock_*. If it causes problems, you could take it // out, but then you'd have to unset HAVE_RWLOCK (at least on linux -- it // *does* cause problems for FreeBSD, or MacOSX, but isn't needed // for locking there.) # ifdef __linux__ # define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls # endif # include typedef pthread_rwlock_t MutexType; #elif defined(HAVE_PTHREAD) # include typedef pthread_mutex_t MutexType; #else # error Need to implement mutex.h for your architecture, or #define NO_THREADS #endif #include #include // for abort() #define MUTEX_NAMESPACE perftools_mutex_namespace namespace MUTEX_NAMESPACE { class Mutex { public: // This is used for the single-arg constructor enum LinkerInitialized { LINKER_INITIALIZED }; // Create a Mutex that is not held by anybody. This constructor is // typically used for Mutexes allocated on the heap or the stack. inline Mutex(); // This constructor should be used for global, static Mutex objects. // It inhibits work being done by the destructor, which makes it // safer for code that tries to acqiure this mutex in their global // destructor. inline Mutex(LinkerInitialized); // Destructor inline ~Mutex(); inline void Lock(); // Block if needed until free then acquire exclusively inline void Unlock(); // Release a lock acquired via Lock() inline bool TryLock(); // If free, Lock() and return true, else return false // Note that on systems that don't support read-write locks, these may // be implemented as synonyms to Lock() and Unlock(). So you can use // these for efficiency, but don't use them anyplace where being able // to do shared reads is necessary to avoid deadlock. inline void ReaderLock(); // Block until free or shared then acquire a share inline void ReaderUnlock(); // Release a read share of this Mutex inline void WriterLock() { Lock(); } // Acquire an exclusive lock inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock() private: MutexType mutex_; // We want to make sure that the compiler sets is_safe_ to true only // when we tell it to, and never makes assumptions is_safe_ is // always true. volatile is the most reliable way to do that. volatile bool is_safe_; // This indicates which constructor was called. bool destroy_; inline void SetIsSafe() { is_safe_ = true; } // Catch the error of writing Mutex when intending MutexLock. Mutex(Mutex* /*ignored*/) {} // Disallow "evil" constructors Mutex(const Mutex&); void operator=(const Mutex&); }; // Now the implementation of Mutex for various systems #if defined(NO_THREADS) // When we don't have threads, we can be either reading or writing, // but not both. We can have lots of readers at once (in no-threads // mode, that's most likely to happen in recursive function calls), // but only one writer. We represent this by having mutex_ be -1 when // writing and a number > 0 when reading (and 0 when no lock is held). // // In debug mode, we assert these invariants, while in non-debug mode // we do nothing, for efficiency. That's why everything is in an // assert. Mutex::Mutex() : mutex_(0) { } Mutex::Mutex(Mutex::LinkerInitialized) : mutex_(0) { } Mutex::~Mutex() { assert(mutex_ == 0); } void Mutex::Lock() { assert(--mutex_ == -1); } void Mutex::Unlock() { assert(mutex_++ == -1); } bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; } void Mutex::ReaderLock() { assert(++mutex_ > 0); } void Mutex::ReaderUnlock() { assert(mutex_-- > 0); } #elif defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) Mutex::Mutex() : destroy_(true) { InitializeCriticalSection(&mutex_); SetIsSafe(); } Mutex::Mutex(LinkerInitialized) : destroy_(false) { InitializeCriticalSection(&mutex_); SetIsSafe(); } Mutex::~Mutex() { if (destroy_) DeleteCriticalSection(&mutex_); } void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); } void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); } bool Mutex::TryLock() { return is_safe_ ? TryEnterCriticalSection(&mutex_) != 0 : true; } void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks void Mutex::ReaderUnlock() { Unlock(); } #elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK) #define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \ if (is_safe_ && fncall(&mutex_) != 0) abort(); \ } while (0) Mutex::Mutex() : destroy_(true) { SetIsSafe(); if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort(); } Mutex::Mutex(Mutex::LinkerInitialized) : destroy_(false) { SetIsSafe(); if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort(); } Mutex::~Mutex() { if (destroy_) SAFE_PTHREAD(pthread_rwlock_destroy); } void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); } void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); } bool Mutex::TryLock() { return is_safe_ ? pthread_rwlock_trywrlock(&mutex_) == 0 : true; } void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); } void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); } #undef SAFE_PTHREAD #elif defined(HAVE_PTHREAD) #define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \ if (is_safe_ && fncall(&mutex_) != 0) abort(); \ } while (0) Mutex::Mutex() : destroy_(true) { SetIsSafe(); if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort(); } Mutex::Mutex(Mutex::LinkerInitialized) : destroy_(false) { SetIsSafe(); if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort(); } Mutex::~Mutex() { if (destroy_) SAFE_PTHREAD(pthread_mutex_destroy); } void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); } void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); } bool Mutex::TryLock() { return is_safe_ ? pthread_mutex_trylock(&mutex_) == 0 : true; } void Mutex::ReaderLock() { Lock(); } void Mutex::ReaderUnlock() { Unlock(); } #undef SAFE_PTHREAD #endif // -------------------------------------------------------------------------- // Some helper classes // MutexLock(mu) acquires mu when constructed and releases it when destroyed. class MutexLock { public: explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); } ~MutexLock() { mu_->Unlock(); } private: Mutex * const mu_; // Disallow "evil" constructors MutexLock(const MutexLock&); void operator=(const MutexLock&); }; // ReaderMutexLock and WriterMutexLock do the same, for rwlocks class ReaderMutexLock { public: explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); } ~ReaderMutexLock() { mu_->ReaderUnlock(); } private: Mutex * const mu_; // Disallow "evil" constructors ReaderMutexLock(const ReaderMutexLock&); void operator=(const ReaderMutexLock&); }; class WriterMutexLock { public: explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); } ~WriterMutexLock() { mu_->WriterUnlock(); } private: Mutex * const mu_; // Disallow "evil" constructors WriterMutexLock(const WriterMutexLock&); void operator=(const WriterMutexLock&); }; // Catch bug where variable name is omitted, e.g. MutexLock (&mu); #define MutexLock(x) COMPILE_ASSERT(0, mutex_lock_decl_missing_var_name) #define ReaderMutexLock(x) COMPILE_ASSERT(0, rmutex_lock_decl_missing_var_name) #define WriterMutexLock(x) COMPILE_ASSERT(0, wmutex_lock_decl_missing_var_name) } // namespace MUTEX_NAMESPACE using namespace MUTEX_NAMESPACE; #undef MUTEX_NAMESPACE #endif /* #define GOOGLE_SIMPLE_MUTEX_H_ */ ================================================ FILE: distro/google-perftools-1.7/src/base/spinlock.cc ================================================ /* Copyright (c) 2006, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Sanjay Ghemawat */ #include #include "base/spinlock.h" #include "base/synchronization_profiling.h" #include "base/spinlock_internal.h" #include "base/cycleclock.h" #include "base/sysinfo.h" /* for NumCPUs() */ // NOTE on the Lock-state values: // // kSpinLockFree represents the unlocked state // kSpinLockHeld represents the locked state with no waiters // // Values greater than kSpinLockHeld represent the locked state with waiters, // where the value is the time the current lock holder had to // wait before obtaining the lock. The kSpinLockSleeper state is a special // "locked with waiters" state that indicates that a sleeper needs to // be woken, but the thread that just released the lock didn't wait. static int adaptive_spin_count = 0; const base::LinkerInitialized SpinLock::LINKER_INITIALIZED = base::LINKER_INITIALIZED; namespace { struct SpinLock_InitHelper { SpinLock_InitHelper() { // On multi-cpu machines, spin for longer before yielding // the processor or sleeping. Reduces idle time significantly. if (NumCPUs() > 1) { adaptive_spin_count = 1000; } } }; // Hook into global constructor execution: // We do not do adaptive spinning before that, // but nothing lock-intensive should be going on at that time. static SpinLock_InitHelper init_helper; } // unnamed namespace // Monitor the lock to see if its value changes within some time period // (adaptive_spin_count loop iterations). A timestamp indicating // when the thread initially started waiting for the lock is passed in via // the initial_wait_timestamp value. The total wait time in cycles for the // lock is returned in the wait_cycles parameter. The last value read // from the lock is returned from the method. Atomic32 SpinLock::SpinLoop(int64 initial_wait_timestamp, Atomic32* wait_cycles) { int c = adaptive_spin_count; while (base::subtle::NoBarrier_Load(&lockword_) != kSpinLockFree && --c > 0) { } Atomic32 spin_loop_wait_cycles = CalculateWaitCycles(initial_wait_timestamp); Atomic32 lock_value = base::subtle::Acquire_CompareAndSwap(&lockword_, kSpinLockFree, spin_loop_wait_cycles); *wait_cycles = spin_loop_wait_cycles; return lock_value; } void SpinLock::SlowLock() { // The lock was not obtained initially, so this thread needs to wait for // it. Record the current timestamp in the local variable wait_start_time // so the total wait time can be stored in the lockword once this thread // obtains the lock. int64 wait_start_time = CycleClock::Now(); Atomic32 wait_cycles; Atomic32 lock_value = SpinLoop(wait_start_time, &wait_cycles); int lock_wait_call_count = 0; while (lock_value != kSpinLockFree) { // If the lock is currently held, but not marked as having a sleeper, mark // it as having a sleeper. if (lock_value == kSpinLockHeld) { // Here, just "mark" that the thread is going to sleep. Don't store the // lock wait time in the lock as that will cause the current lock // owner to think it experienced contention. lock_value = base::subtle::Acquire_CompareAndSwap(&lockword_, kSpinLockHeld, kSpinLockSleeper); if (lock_value == kSpinLockHeld) { // Successfully transitioned to kSpinLockSleeper. Pass // kSpinLockSleeper to the SpinLockWait routine to properly indicate // the last lock_value observed. lock_value = kSpinLockSleeper; } else if (lock_value == kSpinLockFree) { // Lock is free again, so try and aquire it before sleeping. The // new lock state will be the number of cycles this thread waited if // this thread obtains the lock. lock_value = base::subtle::Acquire_CompareAndSwap(&lockword_, kSpinLockFree, wait_cycles); continue; // skip the delay at the end of the loop } } // Wait for an OS specific delay. base::internal::SpinLockDelay(&lockword_, lock_value, ++lock_wait_call_count); // Spin again after returning from the wait routine to give this thread // some chance of obtaining the lock. lock_value = SpinLoop(wait_start_time, &wait_cycles); } } // The wait time for contentionz lock profiling must fit into 32 bits. // However, the lower 32-bits of the cycle counter wrap around too quickly // with high frequency processors, so a right-shift by 7 is performed to // quickly divide the cycles by 128. Using these 32 bits, reduces the // granularity of time measurement to 128 cycles, and loses track // of wait time for waits greater than 109 seconds on a 5 GHz machine // [(2^32 cycles/5 Ghz)*128 = 109.95 seconds]. Waits this long should be // very rare and the reduced granularity should not be an issue given // processors in the Google fleet operate at a minimum of one billion // cycles/sec. enum { PROFILE_TIMESTAMP_SHIFT = 7 }; void SpinLock::SlowUnlock(uint64 wait_cycles) { base::internal::SpinLockWake(&lockword_, false); // wake waiter if necessary // Collect contentionz profile info, expanding the wait_cycles back out to // the full value. If wait_cycles is <= kSpinLockSleeper, then no wait // was actually performed, so don't record the wait time. Note, that the // CalculateWaitCycles method adds in kSpinLockSleeper cycles // unconditionally to guarantee the wait time is not kSpinLockFree or // kSpinLockHeld. The adding in of these small number of cycles may // overestimate the contention by a slight amount 50% of the time. However, // if this code tried to correct for that addition by subtracting out the // kSpinLockSleeper amount that would underestimate the contention slightly // 50% of the time. Both ways get the wrong answer, so the code // overestimates to be more conservative. Overestimating also makes the code // a little simpler. // if (wait_cycles > kSpinLockSleeper) { base::SubmitSpinLockProfileData(this, wait_cycles << PROFILE_TIMESTAMP_SHIFT); } } inline int32 SpinLock::CalculateWaitCycles(int64 wait_start_time) { int32 wait_cycles = ((CycleClock::Now() - wait_start_time) >> PROFILE_TIMESTAMP_SHIFT); // The number of cycles waiting for the lock is used as both the // wait_cycles and lock value, so it can't be kSpinLockFree or // kSpinLockHeld. Make sure the value returned is at least // kSpinLockSleeper. wait_cycles |= kSpinLockSleeper; return wait_cycles; } ================================================ FILE: distro/google-perftools-1.7/src/base/spinlock.h ================================================ /* Copyright (c) 2006, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Sanjay Ghemawat */ // // Fast spinlocks (at least on x86, a lock/unlock pair is approximately // half the cost of a Mutex because the unlock just does a store instead // of a compare-and-swap which is expensive). // SpinLock is async signal safe. // If used within a signal handler, all lock holders // should block the signal even outside the signal handler. #ifndef BASE_SPINLOCK_H_ #define BASE_SPINLOCK_H_ #include #include "base/atomicops.h" #include "base/basictypes.h" #include "base/dynamic_annotations.h" #include "base/thread_annotations.h" class LOCKABLE SpinLock { public: SpinLock() : lockword_(kSpinLockFree) { } // Special constructor for use with static SpinLock objects. E.g., // // static SpinLock lock(base::LINKER_INITIALIZED); // // When intialized using this constructor, we depend on the fact // that the linker has already initialized the memory appropriately. // A SpinLock constructed like this can be freely used from global // initializers without worrying about the order in which global // initializers run. explicit SpinLock(base::LinkerInitialized /*x*/) { // Does nothing; lockword_ is already initialized } // Acquire this SpinLock. // TODO(csilvers): uncomment the annotation when we figure out how to // support this macro with 0 args (see thread_annotations.h) inline void Lock() /*EXCLUSIVE_LOCK_FUNCTION()*/ { if (base::subtle::Acquire_CompareAndSwap(&lockword_, kSpinLockFree, kSpinLockHeld) != kSpinLockFree) { SlowLock(); } ANNOTATE_RWLOCK_ACQUIRED(this, 1); } // Try to acquire this SpinLock without blocking and return true if the // acquisition was successful. If the lock was not acquired, false is // returned. If this SpinLock is free at the time of the call, TryLock // will return true with high probability. inline bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true) { bool res = (base::subtle::Acquire_CompareAndSwap(&lockword_, kSpinLockFree, kSpinLockHeld) == kSpinLockFree); if (res) { ANNOTATE_RWLOCK_ACQUIRED(this, 1); } return res; } // Release this SpinLock, which must be held by the calling thread. // TODO(csilvers): uncomment the annotation when we figure out how to // support this macro with 0 args (see thread_annotations.h) inline void Unlock() /*UNLOCK_FUNCTION()*/ { uint64 wait_cycles = static_cast(base::subtle::NoBarrier_Load(&lockword_)); ANNOTATE_RWLOCK_RELEASED(this, 1); base::subtle::Release_Store(&lockword_, kSpinLockFree); if (wait_cycles != kSpinLockHeld) { // Collect contentionz profile info, and speed the wakeup of any waiter. // The wait_cycles value indicates how long this thread spent waiting // for the lock. SlowUnlock(wait_cycles); } } // Determine if the lock is held. When the lock is held by the invoking // thread, true will always be returned. Intended to be used as // CHECK(lock.IsHeld()). inline bool IsHeld() const { return base::subtle::NoBarrier_Load(&lockword_) != kSpinLockFree; } static const base::LinkerInitialized LINKER_INITIALIZED; // backwards compat private: enum { kSpinLockFree = 0 }; enum { kSpinLockHeld = 1 }; enum { kSpinLockSleeper = 2 }; volatile Atomic32 lockword_; void SlowLock(); void SlowUnlock(uint64 wait_cycles); Atomic32 SpinLoop(int64 initial_wait_timestamp, Atomic32* wait_cycles); inline int32 CalculateWaitCycles(int64 wait_start_time); DISALLOW_COPY_AND_ASSIGN(SpinLock); }; // Corresponding locker object that arranges to acquire a spinlock for // the duration of a C++ scope. class SCOPED_LOCKABLE SpinLockHolder { private: SpinLock* lock_; public: inline explicit SpinLockHolder(SpinLock* l) EXCLUSIVE_LOCK_FUNCTION(l) : lock_(l) { l->Lock(); } // TODO(csilvers): uncomment the annotation when we figure out how to // support this macro with 0 args (see thread_annotations.h) inline ~SpinLockHolder() /*UNLOCK_FUNCTION()*/ { lock_->Unlock(); } }; // Catch bug where variable name is omitted, e.g. SpinLockHolder (&lock); #define SpinLockHolder(x) COMPILE_ASSERT(0, spin_lock_decl_missing_var_name) #endif // BASE_SPINLOCK_H_ ================================================ FILE: distro/google-perftools-1.7/src/base/spinlock_internal.cc ================================================ /* Copyright (c) 2010, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // The OS-specific header included below must provide two calls: // base::internal::SpinLockDelay() and base::internal::SpinLockWake(). // See spinlock_internal.h for the spec of SpinLockWake(). // void SpinLockDelay(volatile Atomic32 *w, int32 value, int loop) // SpinLockDelay() generates an apprproate spin delay on iteration "loop" of a // spin loop on location *w, whose previously observed value was "value". // SpinLockDelay() may do nothing, may yield the CPU, may sleep a clock tick, // or may wait for a delay that can be truncated by a call to SpinlockWake(w). // In all cases, it must return in bounded time even if SpinlockWake() is not // called. #include "base/spinlock_internal.h" #if defined(_WIN32) #include "base/spinlock_win32-inl.h" #elif defined(__linux__) #include "base/spinlock_linux-inl.h" #else #include "base/spinlock_posix-inl.h" #endif namespace base { namespace internal { // See spinlock_internal.h for spec. int32 SpinLockWait(volatile Atomic32 *w, int n, const SpinLockWaitTransition trans[]) { int32 v; bool done = false; for (int loop = 0; !done; loop++) { v = base::subtle::Acquire_Load(w); int i; for (i = 0; i != n && v != trans[i].from; i++) { } if (i == n) { SpinLockDelay(w, v, loop); // no matching transition } else if (trans[i].to == v || // null transition base::subtle::Acquire_CompareAndSwap(w, v, trans[i].to) == v) { done = trans[i].done; } } return v; } } // namespace internal } // namespace base ================================================ FILE: distro/google-perftools-1.7/src/base/spinlock_internal.h ================================================ /* Copyright (c) 2010, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * This file is an internal part spinlock.cc and once.cc * It may not be used directly by code outside of //base. */ #ifndef BASE_SPINLOCK_INTERNAL_H_ #define BASE_SPINLOCK_INTERNAL_H_ #include #include "base/basictypes.h" #include "base/atomicops.h" namespace base { namespace internal { // SpinLockWait() waits until it can perform one of several transitions from // "from" to "to". It returns when it performs a transition where done==true. struct SpinLockWaitTransition { int32 from; int32 to; bool done; }; // Wait until *w can transition from trans[i].from to trans[i].to for some i // satisfying 0<=i #include #include #include "base/linux_syscall_support.h" #define FUTEX_WAIT 0 #define FUTEX_WAKE 1 #define FUTEX_PRIVATE_FLAG 128 static bool have_futex; static int futex_private_flag = FUTEX_PRIVATE_FLAG; namespace { static struct InitModule { InitModule() { int x = 0; // futexes are ints, so we can use them only when // that's the same size as the lockword_ in SpinLock. have_futex = (sizeof (Atomic32) == sizeof (int) && sys_futex(&x, FUTEX_WAKE, 1, 0) >= 0); if (have_futex && sys_futex(&x, FUTEX_WAKE | futex_private_flag, 1, 0) < 0) { futex_private_flag = 0; } } } init_module; } // anonymous namespace namespace base { namespace internal { void SpinLockDelay(volatile Atomic32 *w, int32 value, int loop) { if (loop != 0) { int save_errno = errno; struct timespec tm; tm.tv_sec = 0; if (have_futex) { tm.tv_nsec = 1000000; // 1ms; really we're trying to sleep for one // kernel clock tick } else { tm.tv_nsec = 2000001; // above 2ms so linux 2.4 doesn't spin } if (have_futex) { sys_futex(reinterpret_cast(const_cast(w)), FUTEX_WAIT | futex_private_flag, value, reinterpret_cast(&tm)); } else { nanosleep(&tm, NULL); } errno = save_errno; } } void SpinLockWake(volatile Atomic32 *w, bool all) { if (have_futex) { sys_futex(reinterpret_cast(const_cast(w)), FUTEX_WAKE | futex_private_flag, all? INT_MAX : 1, 0); } } } // namespace internal } // namespace base ================================================ FILE: distro/google-perftools-1.7/src/base/spinlock_posix-inl.h ================================================ /* Copyright (c) 2009, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * This file is a Posix-specific part of spinlock_internal.cc */ #include #include #ifdef HAVE_SCHED_H #include /* For sched_yield() */ #endif #include /* For nanosleep() */ namespace base { namespace internal { void SpinLockDelay(volatile Atomic32 *w, int32 value, int loop) { int save_errno = errno; if (loop == 0) { } else if (loop == 1) { sched_yield(); } else { struct timespec tm; tm.tv_sec = 0; tm.tv_nsec = 1000000; nanosleep(&tm, NULL); } errno = save_errno; } void SpinLockWake(volatile Atomic32 *w, bool all) { } } // namespace internal } // namespace base ================================================ FILE: distro/google-perftools-1.7/src/base/spinlock_win32-inl.h ================================================ /* Copyright (c) 2009, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * This file is a Win32-specific part of spinlock_internal.cc */ #include namespace base { namespace internal { void SpinLockDelay(volatile Atomic32 *w, int32 value, int loop) { if (loop == 0) { } else if (loop == 1) { Sleep(0); } else { Sleep(1); } } void SpinLockWake(volatile Atomic32 *w, bool all) { } } // namespace internal } // namespace base ================================================ FILE: distro/google-perftools-1.7/src/base/stl_allocator.h ================================================ /* Copyright (c) 2006, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Maxim Lifantsev */ #ifndef BASE_STL_ALLOCATOR_H_ #define BASE_STL_ALLOCATOR_H_ #include #include // for ptrdiff_t #include #include "base/basictypes.h" #include "base/logging.h" // Generic allocator class for STL objects // that uses a given type-less allocator Alloc, which must provide: // static void* Alloc::Allocate(size_t size); // static void Alloc::Free(void* ptr, size_t size); // // STL_Allocator provides the same thread-safety // guarantees as MyAlloc. // // Usage example: // set, STL_Allocator > my_set; // CAVEAT: Parts of the code below are probably specific // to the STL version(s) we are using. // The code is simply lifted from what std::allocator<> provides. template class STL_Allocator { public: typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; template struct rebind { typedef STL_Allocator other; }; STL_Allocator() { } STL_Allocator(const STL_Allocator&) { } template STL_Allocator(const STL_Allocator&) { } ~STL_Allocator() { } pointer address(reference x) const { return &x; } const_pointer address(const_reference x) const { return &x; } pointer allocate(size_type n, const void* = 0) { RAW_DCHECK((n * sizeof(T)) / sizeof(T) == n, "n is too big to allocate"); return static_cast(Alloc::Allocate(n * sizeof(T))); } void deallocate(pointer p, size_type n) { Alloc::Free(p, n * sizeof(T)); } size_type max_size() const { return size_t(-1) / sizeof(T); } void construct(pointer p, const T& val) { ::new(p) T(val); } void destroy(pointer p) { p->~T(); } // There's no state, so these allocators are always equal bool operator==(const STL_Allocator&) const { return true; } }; #endif // BASE_STL_ALLOCATOR_H_ ================================================ FILE: distro/google-perftools-1.7/src/base/synchronization_profiling.h ================================================ /* Copyright (c) 2010, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Chris Ruemmler */ #ifndef BASE_AUXILIARY_SYNCHRONIZATION_PROFILING_H_ #define BASE_AUXILIARY_SYNCHRONIZATION_PROFILING_H_ #include "base/basictypes.h" namespace base { // We can do contention-profiling of SpinLocks, but the code is in // mutex.cc, which is not always linked in with spinlock. Hence we // provide a weak definition, which are used if mutex.cc isn't linked in. // Submit the number of cycles the spinlock spent contending. ATTRIBUTE_WEAK extern void SubmitSpinLockProfileData(const void *, int64); extern void SubmitSpinLockProfileData(const void *contendedlock, int64 wait_cycles) {} } #endif // BASE_AUXILIARY_SYNCHRONIZATION_PROFILING_H_ ================================================ FILE: distro/google-perftools-1.7/src/base/sysinfo.cc ================================================ // Copyright (c) 2006, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #if (defined(_WIN32) || defined(__MINGW32__)) && !defined(__CYGWIN__) && !defined(__CYGWIN32) # define PLATFORM_WINDOWS 1 #endif #include // for getenv() #include // for snprintf(), sscanf() #include // for memmove(), memchr(), etc. #include // for open() #include // for errno #ifdef HAVE_UNISTD_H #include // for read() #endif #if defined __MACH__ // Mac OS X, almost certainly #include // for iterating over dll's in ProcMapsIter #include // for iterating over dll's in ProcMapsIter #include #include // how we figure out numcpu's on OS X #elif defined __FreeBSD__ #include #elif defined __sun__ // Solaris #include // for, e.g., prmap_t #elif defined(PLATFORM_WINDOWS) #include // for getpid() (actually, _getpid()) #include // for SHGetValueA() #include // for Module32First() #endif #include "base/sysinfo.h" #include "base/commandlineflags.h" #include "base/dynamic_annotations.h" // for RunningOnValgrind #include "base/logging.h" #include "base/cycleclock.h" #ifdef PLATFORM_WINDOWS #ifdef MODULEENTRY32 // In a change from the usual W-A pattern, there is no A variant of // MODULEENTRY32. Tlhelp32.h #defines the W variant, but not the A. // In unicode mode, tlhelp32.h #defines MODULEENTRY32 to be // MODULEENTRY32W. These #undefs are the only way I see to get back // access to the original, ascii struct (and related functions). #undef MODULEENTRY32 #undef Module32First #undef Module32Next #undef PMODULEENTRY32 #undef LPMODULEENTRY32 #endif /* MODULEENTRY32 */ // MinGW doesn't seem to define this, perhaps some windowsen don't either. #ifndef TH32CS_SNAPMODULE32 #define TH32CS_SNAPMODULE32 0 #endif /* TH32CS_SNAPMODULE32 */ #endif /* PLATFORM_WINDOWS */ // Re-run fn until it doesn't cause EINTR. #define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR) // open/read/close can set errno, which may be illegal at this // time, so prefer making the syscalls directly if we can. #ifdef HAVE_SYS_SYSCALL_H # include # define safeopen(filename, mode) syscall(SYS_open, filename, mode) # define saferead(fd, buffer, size) syscall(SYS_read, fd, buffer, size) # define safeclose(fd) syscall(SYS_close, fd) #else # define safeopen(filename, mode) open(filename, mode) # define saferead(fd, buffer, size) read(fd, buffer, size) # define safeclose(fd) close(fd) #endif // ---------------------------------------------------------------------- // GetenvBeforeMain() // GetUniquePathFromEnv() // Some non-trivial getenv-related functions. // ---------------------------------------------------------------------- // It's not safe to call getenv() in the malloc hooks, because they // might be called extremely early, before libc is done setting up // correctly. In particular, the thread library may not be done // setting up errno. So instead, we use the built-in __environ array // if it exists, and otherwise read /proc/self/environ directly, using // system calls to read the file, and thus avoid setting errno. // /proc/self/environ has a limit of how much data it exports (around // 8K), so it's not an ideal solution. const char* GetenvBeforeMain(const char* name) { #if defined(HAVE___ENVIRON) // if we have it, it's declared in unistd.h if (__environ) { // can exist but be NULL, if statically linked const int namelen = strlen(name); for (char** p = __environ; *p; p++) { if (!memcmp(*p, name, namelen) && (*p)[namelen] == '=') // it's a match return *p + namelen+1; // point after = } return NULL; } #endif #if defined(PLATFORM_WINDOWS) // TODO(mbelshe) - repeated calls to this function will overwrite the // contents of the static buffer. static char envvar_buf[1024]; // enough to hold any envvar we care about if (!GetEnvironmentVariableA(name, envvar_buf, sizeof(envvar_buf)-1)) return NULL; return envvar_buf; #endif // static is ok because this function should only be called before // main(), when we're single-threaded. static char envbuf[16<<10]; if (*envbuf == '\0') { // haven't read the environ yet int fd = safeopen("/proc/self/environ", O_RDONLY); // The -2 below guarantees the last two bytes of the buffer will be \0\0 if (fd == -1 || // unable to open the file, fall back onto libc saferead(fd, envbuf, sizeof(envbuf) - 2) < 0) { // error reading file RAW_VLOG(1, "Unable to open /proc/self/environ, falling back " "on getenv(\"%s\"), which may not work", name); if (fd != -1) safeclose(fd); return getenv(name); } safeclose(fd); } const int namelen = strlen(name); const char* p = envbuf; while (*p != '\0') { // will happen at the \0\0 that terminates the buffer // proc file has the format NAME=value\0NAME=value\0NAME=value\0... const char* endp = (char*)memchr(p, '\0', sizeof(envbuf) - (p - envbuf)); if (endp == NULL) // this entry isn't NUL terminated return NULL; else if (!memcmp(p, name, namelen) && p[namelen] == '=') // it's a match return p + namelen+1; // point after = p = endp + 1; } return NULL; // env var never found } // This takes as an argument an environment-variable name (like // CPUPROFILE) whose value is supposed to be a file-path, and sets // path to that path, and returns true. If the env var doesn't exist, // or is the empty string, leave path unchanged and returns false. // The reason this is non-trivial is that this function handles munged // pathnames. Here's why: // // If we're a child process of the 'main' process, we can't just use // getenv("CPUPROFILE") -- the parent process will be using that path. // Instead we append our pid to the pathname. How do we tell if we're a // child process? Ideally we'd set an environment variable that all // our children would inherit. But -- and this is seemingly a bug in // gcc -- if you do a setenv() in a shared libarary in a global // constructor, the environment setting is lost by the time main() is // called. The only safe thing we can do in such a situation is to // modify the existing envvar. So we do a hack: in the parent, we set // the high bit of the 1st char of CPUPROFILE. In the child, we // notice the high bit is set and append the pid(). This works // assuming cpuprofile filenames don't normally have the high bit set // in their first character! If that assumption is violated, we'll // still get a profile, but one with an unexpected name. // TODO(csilvers): set an envvar instead when we can do it reliably. bool GetUniquePathFromEnv(const char* env_name, char* path) { char* envval = getenv(env_name); if (envval == NULL || *envval == '\0') return false; if (envval[0] & 128) { // high bit is set snprintf(path, PATH_MAX, "%c%s_%u", // add pid and clear high bit envval[0] & 127, envval+1, (unsigned int)(getpid())); } else { snprintf(path, PATH_MAX, "%s", envval); envval[0] |= 128; // set high bit for kids to see } return true; } // ---------------------------------------------------------------------- // CyclesPerSecond() // NumCPUs() // It's important this not call malloc! -- they may be called at // global-construct time, before we've set up all our proper malloc // hooks and such. // ---------------------------------------------------------------------- static double cpuinfo_cycles_per_second = 1.0; // 0.0 might be dangerous static int cpuinfo_num_cpus = 1; // Conservative guess static void SleepForMilliseconds(int milliseconds) { #ifdef PLATFORM_WINDOWS _sleep(milliseconds); // Windows's _sleep takes milliseconds argument #else // Sleep for a few milliseconds struct timespec sleep_time; sleep_time.tv_sec = milliseconds / 1000; sleep_time.tv_nsec = (milliseconds % 1000) * 1000000; while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) ; // Ignore signals and wait for the full interval to elapse. #endif } // Helper function estimates cycles/sec by observing cycles elapsed during // sleep(). Using small sleep time decreases accuracy significantly. static int64 EstimateCyclesPerSecond(const int estimate_time_ms) { assert(estimate_time_ms > 0); if (estimate_time_ms <= 0) return 1; double multiplier = 1000.0 / (double)estimate_time_ms; // scale by this much const int64 start_ticks = CycleClock::Now(); SleepForMilliseconds(estimate_time_ms); const int64 guess = int64(multiplier * (CycleClock::Now() - start_ticks)); return guess; } // Helper function for reading an int from a file. Returns true if successful // and the memory location pointed to by value is set to the value read. static bool ReadIntFromFile(const char *file, int *value) { bool ret = false; int fd = open(file, O_RDONLY); if (fd != -1) { char line[1024]; char* err; memset(line, '\0', sizeof(line)); read(fd, line, sizeof(line) - 1); const int temp_value = strtol(line, &err, 10); if (line[0] != '\0' && (*err == '\n' || *err == '\0')) { *value = temp_value; ret = true; } close(fd); } return ret; } // WARNING: logging calls back to InitializeSystemInfo() so it must // not invoke any logging code. Also, InitializeSystemInfo() can be // called before main() -- in fact it *must* be since already_called // isn't protected -- before malloc hooks are properly set up, so // we make an effort not to call any routines which might allocate // memory. static void InitializeSystemInfo() { static bool already_called = false; // safe if we run before threads if (already_called) return; already_called = true; bool saw_mhz = false; if (RunningOnValgrind()) { // Valgrind may slow the progress of time artificially (--scale-time=N // option). We thus can't rely on CPU Mhz info stored in /sys or /proc // files. Thus, actually measure the cps. cpuinfo_cycles_per_second = EstimateCyclesPerSecond(100); saw_mhz = true; } #if defined(__linux__) || defined(__CYGWIN__) || defined(__CYGWIN32__) char line[1024]; char* err; int freq; // If the kernel is exporting the tsc frequency use that. There are issues // where cpuinfo_max_freq cannot be relied on because the BIOS may be // exporintg an invalid p-state (on x86) or p-states may be used to put the // processor in a new mode (turbo mode). Essentially, those frequencies // cannot always be relied upon. The same reasons apply to /proc/cpuinfo as // well. if (!saw_mhz && ReadIntFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq)) { // The value is in kHz (as the file name suggests). For example, on a // 2GHz warpstation, the file contains the value "2000000". cpuinfo_cycles_per_second = freq * 1000.0; saw_mhz = true; } // If CPU scaling is in effect, we want to use the *maximum* frequency, // not whatever CPU speed some random processor happens to be using now. if (!saw_mhz && ReadIntFromFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", &freq)) { // The value is in kHz. For example, on a 2GHz machine, the file // contains the value "2000000". cpuinfo_cycles_per_second = freq * 1000.0; saw_mhz = true; } // Read /proc/cpuinfo for other values, and if there is no cpuinfo_max_freq. const char* pname = "/proc/cpuinfo"; int fd = open(pname, O_RDONLY); if (fd == -1) { perror(pname); if (!saw_mhz) { cpuinfo_cycles_per_second = EstimateCyclesPerSecond(1000); } return; // TODO: use generic tester instead? } double bogo_clock = 1.0; int num_cpus = 0; line[0] = line[1] = '\0'; int chars_read = 0; do { // we'll exit when the last read didn't read anything // Move the next line to the beginning of the buffer const int oldlinelen = strlen(line); if (sizeof(line) == oldlinelen + 1) // oldlinelen took up entire line line[0] = '\0'; else // still other lines left to save memmove(line, line + oldlinelen+1, sizeof(line) - (oldlinelen+1)); // Terminate the new line, reading more if we can't find the newline char* newline = strchr(line, '\n'); if (newline == NULL) { const int linelen = strlen(line); const int bytes_to_read = sizeof(line)-1 - linelen; assert(bytes_to_read > 0); // because the memmove recovered >=1 bytes chars_read = read(fd, line + linelen, bytes_to_read); line[linelen + chars_read] = '\0'; newline = strchr(line, '\n'); } if (newline != NULL) *newline = '\0'; if (!saw_mhz && strncasecmp(line, "cpu MHz", sizeof("cpu MHz")-1) == 0) { const char* freqstr = strchr(line, ':'); if (freqstr) { cpuinfo_cycles_per_second = strtod(freqstr+1, &err) * 1000000.0; if (freqstr[1] != '\0' && *err == '\0') saw_mhz = true; } } else if (strncasecmp(line, "bogomips", sizeof("bogomips")-1) == 0) { const char* freqstr = strchr(line, ':'); if (freqstr) bogo_clock = strtod(freqstr+1, &err) * 1000000.0; if (freqstr == NULL || freqstr[1] == '\0' || *err != '\0') bogo_clock = 1.0; } else if (strncasecmp(line, "processor", sizeof("processor")-1) == 0) { num_cpus++; // count up every time we see an "processor :" entry } } while (chars_read > 0); close(fd); if (!saw_mhz) { // If we didn't find anything better, we'll use bogomips, but // we're not happy about it. cpuinfo_cycles_per_second = bogo_clock; } if (cpuinfo_cycles_per_second == 0.0) { cpuinfo_cycles_per_second = 1.0; // maybe unnecessary, but safe } if (num_cpus > 0) { cpuinfo_num_cpus = num_cpus; } #elif defined __FreeBSD__ // For this sysctl to work, the machine must be configured without // SMP, APIC, or APM support. hz should be 64-bit in freebsd 7.0 // and later. Before that, it's a 32-bit quantity (and gives the // wrong answer on machines faster than 2^32 Hz). See // http://lists.freebsd.org/pipermail/freebsd-i386/2004-November/001846.html // But also compare FreeBSD 7.0: // http://fxr.watson.org/fxr/source/i386/i386/tsc.c?v=RELENG70#L223 // 231 error = sysctl_handle_quad(oidp, &freq, 0, req); // To FreeBSD 6.3 (it's the same in 6-STABLE): // http://fxr.watson.org/fxr/source/i386/i386/tsc.c?v=RELENG6#L131 // 139 error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); #if __FreeBSD__ >= 7 uint64_t hz = 0; #else unsigned int hz = 0; #endif size_t sz = sizeof(hz); const char *sysctl_path = "machdep.tsc_freq"; if ( sysctlbyname(sysctl_path, &hz, &sz, NULL, 0) != 0 ) { fprintf(stderr, "Unable to determine clock rate from sysctl: %s: %s\n", sysctl_path, strerror(errno)); cpuinfo_cycles_per_second = EstimateCyclesPerSecond(1000); } else { cpuinfo_cycles_per_second = hz; } // TODO(csilvers): also figure out cpuinfo_num_cpus #elif defined(PLATFORM_WINDOWS) # pragma comment(lib, "shlwapi.lib") // for SHGetValue() // In NT, read MHz from the registry. If we fail to do so or we're in win9x // then make a crude estimate. OSVERSIONINFO os; os.dwOSVersionInfoSize = sizeof(os); DWORD data, data_size = sizeof(data); if (GetVersionEx(&os) && os.dwPlatformId == VER_PLATFORM_WIN32_NT && SUCCEEDED(SHGetValueA(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", "~MHz", NULL, &data, &data_size))) cpuinfo_cycles_per_second = (int64)data * (int64)(1000 * 1000); // was mhz else cpuinfo_cycles_per_second = EstimateCyclesPerSecond(500); // TODO <500? // Get the number of processors. SYSTEM_INFO info; GetSystemInfo(&info); cpuinfo_num_cpus = info.dwNumberOfProcessors; #elif defined(__MACH__) && defined(__APPLE__) // returning "mach time units" per second. the current number of elapsed // mach time units can be found by calling uint64 mach_absolute_time(); // while not as precise as actual CPU cycles, it is accurate in the face // of CPU frequency scaling and multi-cpu/core machines. // Our mac users have these types of machines, and accuracy // (i.e. correctness) trumps precision. // See cycleclock.h: CycleClock::Now(), which returns number of mach time // units on Mac OS X. mach_timebase_info_data_t timebase_info; mach_timebase_info(&timebase_info); double mach_time_units_per_nanosecond = static_cast(timebase_info.denom) / static_cast(timebase_info.numer); cpuinfo_cycles_per_second = mach_time_units_per_nanosecond * 1e9; int num_cpus = 0; size_t size = sizeof(num_cpus); int numcpus_name[] = { CTL_HW, HW_NCPU }; if (::sysctl(numcpus_name, arraysize(numcpus_name), &num_cpus, &size, 0, 0) == 0 && (size == sizeof(num_cpus))) cpuinfo_num_cpus = num_cpus; #else // Generic cycles per second counter cpuinfo_cycles_per_second = EstimateCyclesPerSecond(1000); #endif } double CyclesPerSecond(void) { InitializeSystemInfo(); return cpuinfo_cycles_per_second; } int NumCPUs(void) { InitializeSystemInfo(); return cpuinfo_num_cpus; } // ---------------------------------------------------------------------- // HasPosixThreads() // Return true if we're running POSIX (e.g., NPTL on Linux) // threads, as opposed to a non-POSIX thread libary. The thing // that we care about is whether a thread's pid is the same as // the thread that spawned it. If so, this function returns // true. // ---------------------------------------------------------------------- bool HasPosixThreads() { #if defined(__linux__) #ifndef _CS_GNU_LIBPTHREAD_VERSION #define _CS_GNU_LIBPTHREAD_VERSION 3 #endif char buf[32]; // We assume that, if confstr() doesn't know about this name, then // the same glibc is providing LinuxThreads. if (confstr(_CS_GNU_LIBPTHREAD_VERSION, buf, sizeof(buf)) == 0) return false; return strncmp(buf, "NPTL", 4) == 0; #elif defined(PLATFORM_WINDOWS) || defined(__CYGWIN__) || defined(__CYGWIN32__) return false; #else // other OS return true; // Assume that everything else has Posix #endif // else OS_LINUX } // ---------------------------------------------------------------------- #if defined __linux__ || defined __FreeBSD__ || defined __sun__ || defined __CYGWIN__ || defined __CYGWIN32__ static void ConstructFilename(const char* spec, pid_t pid, char* buf, int buf_size) { CHECK_LT(snprintf(buf, buf_size, spec, pid ? pid : getpid()), buf_size); } #endif // A templatized helper function instantiated for Mach (OS X) only. // It can handle finding info for both 32 bits and 64 bits. // Returns true if it successfully handled the hdr, false else. #ifdef __MACH__ // Mac OS X, almost certainly template static bool NextExtMachHelper(const mach_header* hdr, int current_image, int current_load_cmd, uint64 *start, uint64 *end, char **flags, uint64 *offset, int64 *inode, char **filename, uint64 *file_mapping, uint64 *file_pages, uint64 *anon_mapping, uint64 *anon_pages, dev_t *dev) { static char kDefaultPerms[5] = "r-xp"; if (hdr->magic != kMagic) return false; const char* lc = (const char *)hdr + sizeof(MachHeader); // TODO(csilvers): make this not-quadradic (increment and hold state) for (int j = 0; j < current_load_cmd; j++) // advance to *our* load_cmd lc += ((const load_command *)lc)->cmdsize; if (((const load_command *)lc)->cmd == kLCSegment) { const intptr_t dlloff = _dyld_get_image_vmaddr_slide(current_image); const SegmentCommand* sc = (const SegmentCommand *)lc; if (start) *start = sc->vmaddr + dlloff; if (end) *end = sc->vmaddr + sc->vmsize + dlloff; if (flags) *flags = kDefaultPerms; // can we do better? if (offset) *offset = sc->fileoff; if (inode) *inode = 0; if (filename) *filename = const_cast(_dyld_get_image_name(current_image)); if (file_mapping) *file_mapping = 0; if (file_pages) *file_pages = 0; // could we use sc->filesize? if (anon_mapping) *anon_mapping = 0; if (anon_pages) *anon_pages = 0; if (dev) *dev = 0; return true; } return false; } #endif ProcMapsIterator::ProcMapsIterator(pid_t pid) { Init(pid, NULL, false); } ProcMapsIterator::ProcMapsIterator(pid_t pid, Buffer *buffer) { Init(pid, buffer, false); } ProcMapsIterator::ProcMapsIterator(pid_t pid, Buffer *buffer, bool use_maps_backing) { Init(pid, buffer, use_maps_backing); } void ProcMapsIterator::Init(pid_t pid, Buffer *buffer, bool use_maps_backing) { pid_ = pid; using_maps_backing_ = use_maps_backing; dynamic_buffer_ = NULL; if (!buffer) { // If the user didn't pass in any buffer storage, allocate it // now. This is the normal case; the signal handler passes in a // static buffer. buffer = dynamic_buffer_ = new Buffer; } else { dynamic_buffer_ = NULL; } ibuf_ = buffer->buf_; stext_ = etext_ = nextline_ = ibuf_; ebuf_ = ibuf_ + Buffer::kBufSize - 1; nextline_ = ibuf_; #if defined(__linux__) || defined(__CYGWIN__) || defined(__CYGWIN32__) if (use_maps_backing) { // don't bother with clever "self" stuff in this case ConstructFilename("/proc/%d/maps_backing", pid, ibuf_, Buffer::kBufSize); } else if (pid == 0) { // We have to kludge a bit to deal with the args ConstructFilename // expects. The 1 is never used -- it's only impt. that it's not 0. ConstructFilename("/proc/self/maps", 1, ibuf_, Buffer::kBufSize); } else { ConstructFilename("/proc/%d/maps", pid, ibuf_, Buffer::kBufSize); } // No error logging since this can be called from the crash dump // handler at awkward moments. Users should call Valid() before // using. NO_INTR(fd_ = open(ibuf_, O_RDONLY)); #elif defined(__FreeBSD__) // We don't support maps_backing on freebsd if (pid == 0) { ConstructFilename("/proc/curproc/map", 1, ibuf_, Buffer::kBufSize); } else { ConstructFilename("/proc/%d/map", pid, ibuf_, Buffer::kBufSize); } NO_INTR(fd_ = open(ibuf_, O_RDONLY)); #elif defined(__sun__) if (pid == 0) { ConstructFilename("/proc/self/map", 1, ibuf_, Buffer::kBufSize); } else { ConstructFilename("/proc/%d/map", pid, ibuf_, Buffer::kBufSize); } NO_INTR(fd_ = open(ibuf_, O_RDONLY)); #elif defined(__MACH__) current_image_ = _dyld_image_count(); // count down from the top current_load_cmd_ = -1; #elif defined(PLATFORM_WINDOWS) snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, GetCurrentProcessId()); memset(&module_, 0, sizeof(module_)); #else fd_ = -1; // so Valid() is always false #endif } ProcMapsIterator::~ProcMapsIterator() { #if defined(PLATFORM_WINDOWS) if (snapshot_ != INVALID_HANDLE_VALUE) CloseHandle(snapshot_); #elif defined(__MACH__) // no cleanup necessary! #else if (fd_ >= 0) NO_INTR(close(fd_)); #endif delete dynamic_buffer_; } bool ProcMapsIterator::Valid() const { #if defined(PLATFORM_WINDOWS) return snapshot_ != INVALID_HANDLE_VALUE; #elif defined(__MACH__) return 1; #else return fd_ != -1; #endif } bool ProcMapsIterator::Next(uint64 *start, uint64 *end, char **flags, uint64 *offset, int64 *inode, char **filename) { return NextExt(start, end, flags, offset, inode, filename, NULL, NULL, NULL, NULL, NULL); } // This has too many arguments. It should really be building // a map object and returning it. The problem is that this is called // when the memory allocator state is undefined, hence the arguments. bool ProcMapsIterator::NextExt(uint64 *start, uint64 *end, char **flags, uint64 *offset, int64 *inode, char **filename, uint64 *file_mapping, uint64 *file_pages, uint64 *anon_mapping, uint64 *anon_pages, dev_t *dev) { #if defined(__linux__) || defined(__FreeBSD__) || defined(__CYGWIN__) || defined(__CYGWIN32__) do { // Advance to the start of the next line stext_ = nextline_; // See if we have a complete line in the buffer already nextline_ = static_cast(memchr (stext_, '\n', etext_ - stext_)); if (!nextline_) { // Shift/fill the buffer so we do have a line int count = etext_ - stext_; // Move the current text to the start of the buffer memmove(ibuf_, stext_, count); stext_ = ibuf_; etext_ = ibuf_ + count; int nread = 0; // fill up buffer with text while (etext_ < ebuf_) { NO_INTR(nread = read(fd_, etext_, ebuf_ - etext_)); if (nread > 0) etext_ += nread; else break; } // Zero out remaining characters in buffer at EOF to avoid returning // garbage from subsequent calls. if (etext_ != ebuf_ && nread == 0) { memset(etext_, 0, ebuf_ - etext_); } *etext_ = '\n'; // sentinel; safe because ibuf extends 1 char beyond ebuf nextline_ = static_cast(memchr (stext_, '\n', etext_ + 1 - stext_)); } *nextline_ = 0; // turn newline into nul nextline_ += ((nextline_ < etext_)? 1 : 0); // skip nul if not end of text // stext_ now points at a nul-terminated line uint64 tmpstart, tmpend, tmpoffset; int64 tmpinode; int major, minor; unsigned filename_offset = 0; #if defined(__linux__) // for now, assume all linuxes have the same format if (sscanf(stext_, "%"SCNx64"-%"SCNx64" %4s %"SCNx64" %x:%x %"SCNd64" %n", start ? start : &tmpstart, end ? end : &tmpend, flags_, offset ? offset : &tmpoffset, &major, &minor, inode ? inode : &tmpinode, &filename_offset) != 7) continue; #elif defined(__CYGWIN__) || defined(__CYGWIN32__) // cygwin is like linux, except the third field is the "entry point" // rather than the offset (see format_process_maps at // http://cygwin.com/cgi-bin/cvsweb.cgi/src/winsup/cygwin/fhandler_process.cc?rev=1.89&content-type=text/x-cvsweb-markup&cvsroot=src // Offset is always be 0 on cygwin: cygwin implements an mmap // by loading the whole file and then calling NtMapViewOfSection. // Cygwin also seems to set its flags kinda randomly; use windows default. char tmpflags[5]; if (offset) *offset = 0; strcpy(flags_, "r-xp"); if (sscanf(stext_, "%llx-%llx %4s %llx %x:%x %lld %n", start ? start : &tmpstart, end ? end : &tmpend, tmpflags, &tmpoffset, &major, &minor, inode ? inode : &tmpinode, &filename_offset) != 7) continue; #elif defined(__FreeBSD__) // For the format, see http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/fs/procfs/procfs_map.c?rev=1.31&content-type=text/x-cvsweb-markup tmpstart = tmpend = tmpoffset = 0; tmpinode = 0; major = minor = 0; // can't get this info in freebsd if (inode) *inode = 0; // nor this if (offset) *offset = 0; // seems like this should be in there, but maybe not // start end resident privateresident obj(?) prot refcnt shadowcnt // flags copy_on_write needs_copy type filename: // 0x8048000 0x804a000 2 0 0xc104ce70 r-x 1 0 0x0 COW NC vnode /bin/cat if (sscanf(stext_, "0x%"SCNx64" 0x%"SCNx64" %*d %*d %*p %3s %*d %*d 0x%*x %*s %*s %*s %n", start ? start : &tmpstart, end ? end : &tmpend, flags_, &filename_offset) != 3) continue; #endif // Depending on the Linux kernel being used, there may or may not be a space // after the inode if there is no filename. sscanf will in such situations // nondeterministically either fill in filename_offset or not (the results // differ on multiple calls in the same run even with identical arguments). // We don't want to wander off somewhere beyond the end of the string. size_t stext_length = strlen(stext_); if (filename_offset == 0 || filename_offset > stext_length) filename_offset = stext_length; // We found an entry if (flags) *flags = flags_; if (filename) *filename = stext_ + filename_offset; if (dev) *dev = minor | (major << 8); if (using_maps_backing_) { // Extract and parse physical page backing info. char *backing_ptr = stext_ + filename_offset + strlen(stext_+filename_offset); // find the second '(' int paren_count = 0; while (--backing_ptr > stext_) { if (*backing_ptr == '(') { ++paren_count; if (paren_count >= 2) { uint64 tmp_file_mapping; uint64 tmp_file_pages; uint64 tmp_anon_mapping; uint64 tmp_anon_pages; sscanf(backing_ptr+1, "F %"SCNx64" %"SCNd64") (A %"SCNx64" %"SCNd64")", file_mapping ? file_mapping : &tmp_file_mapping, file_pages ? file_pages : &tmp_file_pages, anon_mapping ? anon_mapping : &tmp_anon_mapping, anon_pages ? anon_pages : &tmp_anon_pages); // null terminate the file name (there is a space // before the first (. backing_ptr[-1] = 0; break; } } } } return true; } while (etext_ > ibuf_); #elif defined(__sun__) // This is based on MA_READ == 4, MA_WRITE == 2, MA_EXEC == 1 static char kPerms[8][4] = { "---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx" }; COMPILE_ASSERT(MA_READ == 4, solaris_ma_read_must_equal_4); COMPILE_ASSERT(MA_WRITE == 2, solaris_ma_write_must_equal_2); COMPILE_ASSERT(MA_EXEC == 1, solaris_ma_exec_must_equal_1); Buffer object_path; int nread = 0; // fill up buffer with text NO_INTR(nread = read(fd_, ibuf_, sizeof(prmap_t))); if (nread == sizeof(prmap_t)) { long inode_from_mapname = 0; prmap_t* mapinfo = reinterpret_cast(ibuf_); // Best-effort attempt to get the inode from the filename. I think the // two middle ints are major and minor device numbers, but I'm not sure. sscanf(mapinfo->pr_mapname, "ufs.%*d.%*d.%ld", &inode_from_mapname); if (pid_ == 0) { CHECK_LT(snprintf(object_path.buf_, Buffer::kBufSize, "/proc/self/path/%s", mapinfo->pr_mapname), Buffer::kBufSize); } else { CHECK_LT(snprintf(object_path.buf_, Buffer::kBufSize, "/proc/%d/path/%s", pid_, mapinfo->pr_mapname), Buffer::kBufSize); } ssize_t len = readlink(object_path.buf_, current_filename_, PATH_MAX); CHECK_LT(len, PATH_MAX); if (len < 0) len = 0; current_filename_[len] = '\0'; if (start) *start = mapinfo->pr_vaddr; if (end) *end = mapinfo->pr_vaddr + mapinfo->pr_size; if (flags) *flags = kPerms[mapinfo->pr_mflags & 7]; if (offset) *offset = mapinfo->pr_offset; if (inode) *inode = inode_from_mapname; if (filename) *filename = current_filename_; if (file_mapping) *file_mapping = 0; if (file_pages) *file_pages = 0; if (anon_mapping) *anon_mapping = 0; if (anon_pages) *anon_pages = 0; if (dev) *dev = 0; return true; } #elif defined(__MACH__) // We return a separate entry for each segment in the DLL. (TODO(csilvers): // can we do better?) A DLL ("image") has load-commands, some of which // talk about segment boundaries. // cf image_for_address from http://svn.digium.com/view/asterisk/team/oej/minivoicemail/dlfcn.c?revision=53912 for (; current_image_ >= 0; current_image_--) { const mach_header* hdr = _dyld_get_image_header(current_image_); if (!hdr) continue; if (current_load_cmd_ < 0) // set up for this image current_load_cmd_ = hdr->ncmds; // again, go from the top down // We start with the next load command (we've already looked at this one). for (current_load_cmd_--; current_load_cmd_ >= 0; current_load_cmd_--) { #ifdef MH_MAGIC_64 if (NextExtMachHelper( hdr, current_image_, current_load_cmd_, start, end, flags, offset, inode, filename, file_mapping, file_pages, anon_mapping, anon_pages, dev)) { return true; } #endif if (NextExtMachHelper( hdr, current_image_, current_load_cmd_, start, end, flags, offset, inode, filename, file_mapping, file_pages, anon_mapping, anon_pages, dev)) { return true; } } // If we get here, no more load_cmd's in this image talk about // segments. Go on to the next image. } #elif defined(PLATFORM_WINDOWS) static char kDefaultPerms[5] = "r-xp"; BOOL ok; if (module_.dwSize == 0) { // only possible before first call module_.dwSize = sizeof(module_); ok = Module32First(snapshot_, &module_); } else { ok = Module32Next(snapshot_, &module_); } if (ok) { uint64 base_addr = reinterpret_cast(module_.modBaseAddr); if (start) *start = base_addr; if (end) *end = base_addr + module_.modBaseSize; if (flags) *flags = kDefaultPerms; if (offset) *offset = 0; if (inode) *inode = 0; if (filename) *filename = module_.szExePath; if (file_mapping) *file_mapping = 0; if (file_pages) *file_pages = 0; if (anon_mapping) *anon_mapping = 0; if (anon_pages) *anon_pages = 0; if (dev) *dev = 0; return true; } #endif // We didn't find anything return false; } int ProcMapsIterator::FormatLine(char* buffer, int bufsize, uint64 start, uint64 end, const char *flags, uint64 offset, int64 inode, const char *filename, dev_t dev) { // We assume 'flags' looks like 'rwxp' or 'rwx'. char r = (flags && flags[0] == 'r') ? 'r' : '-'; char w = (flags && flags[0] && flags[1] == 'w') ? 'w' : '-'; char x = (flags && flags[0] && flags[1] && flags[2] == 'x') ? 'x' : '-'; // p always seems set on linux, so we set the default to 'p', not '-' char p = (flags && flags[0] && flags[1] && flags[2] && flags[3] != 'p') ? '-' : 'p'; const int rc = snprintf(buffer, bufsize, "%08"PRIx64"-%08"PRIx64" %c%c%c%c %08"PRIx64" %02x:%02x %-11"PRId64" %s\n", start, end, r,w,x,p, offset, static_cast(dev/256), static_cast(dev%256), inode, filename); return (rc < 0 || rc >= bufsize) ? 0 : rc; } namespace tcmalloc { // Helper to add the list of mapped shared libraries to a profile. // Fill formatted "/proc/self/maps" contents into buffer 'buf' of size 'size' // and return the actual size occupied in 'buf'. We fill wrote_all to true // if we successfully wrote all proc lines to buf, false else. // We do not provision for 0-terminating 'buf'. int FillProcSelfMaps(char buf[], int size, bool* wrote_all) { ProcMapsIterator::Buffer iterbuf; ProcMapsIterator it(0, &iterbuf); // 0 means "current pid" uint64 start, end, offset; int64 inode; char *flags, *filename; int bytes_written = 0; *wrote_all = true; while (it.Next(&start, &end, &flags, &offset, &inode, &filename)) { const int line_length = it.FormatLine(buf + bytes_written, size - bytes_written, start, end, flags, offset, inode, filename, 0); if (line_length == 0) *wrote_all = false; // failed to write this line out else bytes_written += line_length; } return bytes_written; } // Dump the same data as FillProcSelfMaps reads to fd. // It seems easier to repeat parts of FillProcSelfMaps here than to // reuse it via a call. void DumpProcSelfMaps(RawFD fd) { ProcMapsIterator::Buffer iterbuf; ProcMapsIterator it(0, &iterbuf); // 0 means "current pid" uint64 start, end, offset; int64 inode; char *flags, *filename; ProcMapsIterator::Buffer linebuf; while (it.Next(&start, &end, &flags, &offset, &inode, &filename)) { int written = it.FormatLine(linebuf.buf_, sizeof(linebuf.buf_), start, end, flags, offset, inode, filename, 0); RawWrite(fd, linebuf.buf_, written); } } } // namespace tcmalloc ================================================ FILE: distro/google-perftools-1.7/src/base/sysinfo.h ================================================ // Copyright (c) 2006, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // All functions here are thread-hostile due to file caching unless // commented otherwise. #ifndef _SYSINFO_H_ #define _SYSINFO_H_ #include #include #if (defined(_WIN32) || defined(__MINGW32__)) && (!defined(__CYGWIN__) && !defined(__CYGWIN32__)) #include // for DWORD #include // for CreateToolhelp32Snapshot #endif #ifdef HAVE_UNISTD_H #include // for pid_t #endif #include // for size_t #include // for PATH_MAX #include "base/basictypes.h" #include "base/logging.h" // for RawFD // This getenv function is safe to call before the C runtime is initialized. // On Windows, it utilizes GetEnvironmentVariable() and on unix it uses // /proc/self/environ instead calling getenv(). It's intended to be used in // routines that run before main(), when the state required for getenv() may // not be set up yet. In particular, errno isn't set up until relatively late // (after the pthreads library has a chance to make it threadsafe), and // getenv() doesn't work until then. // On some platforms, this call will utilize the same, static buffer for // repeated GetenvBeforeMain() calls. Callers should not expect pointers from // this routine to be long lived. // Note that on unix, /proc only has the environment at the time the // application was started, so this routine ignores setenv() calls/etc. Also // note it only reads the first 16K of the environment. extern const char* GetenvBeforeMain(const char* name); // This takes as an argument an environment-variable name (like // CPUPROFILE) whose value is supposed to be a file-path, and sets // path to that path, and returns true. Non-trivial for surprising // reasons, as documented in sysinfo.cc. path must have space PATH_MAX. extern bool GetUniquePathFromEnv(const char* env_name, char* path); extern int NumCPUs(); // processor cycles per second of each processor. Thread-safe. extern double CyclesPerSecond(void); // Return true if we're running POSIX (e.g., NPTL on Linux) threads, // as opposed to a non-POSIX thread libary. The thing that we care // about is whether a thread's pid is the same as the thread that // spawned it. If so, this function returns true. // Thread-safe. // Note: We consider false negatives to be OK. bool HasPosixThreads(); #ifndef SWIG // SWIG doesn't like struct Buffer and variable arguments. // A ProcMapsIterator abstracts access to /proc/maps for a given // process. Needs to be stack-allocatable and avoid using stdio/malloc // so it can be used in the google stack dumper, heap-profiler, etc. // // On Windows and Mac OS X, this iterator iterates *only* over DLLs // mapped into this process space. For Linux, FreeBSD, and Solaris, // it iterates over *all* mapped memory regions, including anonymous // mmaps. For other O/Ss, it is unlikely to work at all, and Valid() // will always return false. Also note: this routine only works on // FreeBSD if procfs is mounted: make sure this is in your /etc/fstab: // proc /proc procfs rw 0 0 class ProcMapsIterator { public: struct Buffer { #ifdef __FreeBSD__ // FreeBSD requires us to read all of the maps file at once, so // we have to make a buffer that's "always" big enough static const size_t kBufSize = 102400; #else // a one-line buffer is good enough static const size_t kBufSize = PATH_MAX + 1024; #endif char buf_[kBufSize]; }; // Create a new iterator for the specified pid. pid can be 0 for "self". explicit ProcMapsIterator(pid_t pid); // Create an iterator with specified storage (for use in signal // handler). "buffer" should point to a ProcMapsIterator::Buffer // buffer can be NULL in which case a bufer will be allocated. ProcMapsIterator(pid_t pid, Buffer *buffer); // Iterate through maps_backing instead of maps if use_maps_backing // is true. Otherwise the same as above. buffer can be NULL and // it will allocate a buffer itself. ProcMapsIterator(pid_t pid, Buffer *buffer, bool use_maps_backing); // Returns true if the iterator successfully initialized; bool Valid() const; // Returns a pointer to the most recently parsed line. Only valid // after Next() returns true, and until the iterator is destroyed or // Next() is called again. This may give strange results on non-Linux // systems. Prefer FormatLine() if that may be a concern. const char *CurrentLine() const { return stext_; } // Writes the "canonical" form of the /proc/xxx/maps info for a single // line to the passed-in buffer. Returns the number of bytes written, // or 0 if it was not able to write the complete line. (To guarantee // success, buffer should have size at least Buffer::kBufSize.) // Takes as arguments values set via a call to Next(). The // "canonical" form of the line (taken from linux's /proc/xxx/maps): // - + // : Note: the // eg // 08048000-0804c000 r-xp 00000000 03:01 3793678 /bin/cat // If you don't have the dev_t (dev), feel free to pass in 0. // (Next() doesn't return a dev_t, though NextExt does.) // // Note: if filename and flags were obtained via a call to Next(), // then the output of this function is only valid if Next() returned // true, and only until the iterator is destroyed or Next() is // called again. (Since filename, at least, points into CurrentLine.) static int FormatLine(char* buffer, int bufsize, uint64 start, uint64 end, const char *flags, uint64 offset, int64 inode, const char *filename, dev_t dev); // Find the next entry in /proc/maps; return true if found or false // if at the end of the file. // // Any of the result pointers can be NULL if you're not interested // in those values. // // If "flags" and "filename" are passed, they end up pointing to // storage within the ProcMapsIterator that is valid only until the // iterator is destroyed or Next() is called again. The caller may // modify the contents of these strings (up as far as the first NUL, // and only until the subsequent call to Next()) if desired. // The offsets are all uint64 in order to handle the case of a // 32-bit process running on a 64-bit kernel // // IMPORTANT NOTE: see top-of-class notes for details about what // mapped regions Next() iterates over, depending on O/S. // TODO(csilvers): make flags and filename const. bool Next(uint64 *start, uint64 *end, char **flags, uint64 *offset, int64 *inode, char **filename); bool NextExt(uint64 *start, uint64 *end, char **flags, uint64 *offset, int64 *inode, char **filename, uint64 *file_mapping, uint64 *file_pages, uint64 *anon_mapping, uint64 *anon_pages, dev_t *dev); ~ProcMapsIterator(); private: void Init(pid_t pid, Buffer *buffer, bool use_maps_backing); char *ibuf_; // input buffer char *stext_; // start of text char *etext_; // end of text char *nextline_; // start of next line char *ebuf_; // end of buffer (1 char for a nul) #if (defined(_WIN32) || defined(__MINGW32__)) && (!defined(__CYGWIN__) && !defined(__CYGWIN32__)) HANDLE snapshot_; // filehandle on dll info // In a change from the usual W-A pattern, there is no A variant of // MODULEENTRY32. Tlhelp32.h #defines the W variant, but not the A. // We want the original A variants, and this #undef is the only // way I see to get them. Redefining it when we're done prevents us // from affecting other .cc files. # ifdef MODULEENTRY32 // Alias of W # undef MODULEENTRY32 MODULEENTRY32 module_; // info about current dll (and dll iterator) # define MODULEENTRY32 MODULEENTRY32W # else // It's the ascii, the one we want. MODULEENTRY32 module_; // info about current dll (and dll iterator) # endif #elif defined(__MACH__) int current_image_; // dll's are called "images" in macos parlance int current_load_cmd_; // the segment of this dll we're examining #elif defined(__sun__) // Solaris int fd_; char current_filename_[PATH_MAX]; #else int fd_; // filehandle on /proc/*/maps #endif pid_t pid_; char flags_[10]; Buffer* dynamic_buffer_; // dynamically-allocated Buffer bool using_maps_backing_; // true if we are looking at maps_backing instead of maps. }; #endif /* #ifndef SWIG */ // Helper routines namespace tcmalloc { int FillProcSelfMaps(char buf[], int size, bool* wrote_all); void DumpProcSelfMaps(RawFD fd); } #endif /* #ifndef _SYSINFO_H_ */ ================================================ FILE: distro/google-perftools-1.7/src/base/thread_annotations.h ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Le-Chun Wu // // This header file contains the macro definitions for thread safety // annotations that allow the developers to document the locking policies // of their multi-threaded code. The annotations can also help program // analysis tools to identify potential thread safety issues. // // The annotations are implemented using GCC's "attributes" extension. // Using the macros defined here instead of the raw GCC attributes allows // for portability and future compatibility. // // This functionality is not yet fully implemented in perftools, // but may be one day. #ifndef BASE_THREAD_ANNOTATIONS_H_ #define BASE_THREAD_ANNOTATIONS_H_ #if defined(__GNUC__) \ && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) \ && defined(__SUPPORT_TS_ANNOTATION__) && (!defined(SWIG)) #define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) #else #define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op #endif // Document if a shared variable/field needs to be protected by a lock. // GUARDED_BY allows the user to specify a particular lock that should be // held when accessing the annotated variable, while GUARDED_VAR only // indicates a shared variable should be guarded (by any lock). GUARDED_VAR // is primarily used when the client cannot express the name of the lock. #define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) #define GUARDED_VAR THREAD_ANNOTATION_ATTRIBUTE__(guarded) // Document if the memory location pointed to by a pointer should be guarded // by a lock when dereferencing the pointer. Similar to GUARDED_VAR, // PT_GUARDED_VAR is primarily used when the client cannot express the name // of the lock. Note that a pointer variable to a shared memory location // could itself be a shared variable. For example, if a shared global pointer // q, which is guarded by mu1, points to a shared memory location that is // guarded by mu2, q should be annotated as follows: // int *q GUARDED_BY(mu1) PT_GUARDED_BY(mu2); #define PT_GUARDED_BY(x) \ THREAD_ANNOTATION_ATTRIBUTE__(point_to_guarded_by(x)) #define PT_GUARDED_VAR \ THREAD_ANNOTATION_ATTRIBUTE__(point_to_guarded) // Document the acquisition order between locks that can be held // simultaneously by a thread. For any two locks that need to be annotated // to establish an acquisition order, only one of them needs the annotation. // (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER // and ACQUIRED_BEFORE.) #define ACQUIRED_AFTER(x) \ THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(x)) #define ACQUIRED_BEFORE(x) \ THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(x)) // The following three annotations document the lock requirements for // functions/methods. // Document if a function expects certain locks to be held before it is called #define EXCLUSIVE_LOCKS_REQUIRED(x) \ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(x)) #define SHARED_LOCKS_REQUIRED(x) \ THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(x)) // Document the locks acquired in the body of the function. These locks // cannot be held when calling this function (as google3's Mutex locks are // non-reentrant). #define LOCKS_EXCLUDED(x) \ THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(x)) // Document the lock the annotated function returns without acquiring it. #define LOCK_RETURNED(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) // Document if a class/type is a lockable type (such as the Mutex class). #define LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(lockable) // Document if a class is a scoped lockable type (such as the MutexLock class). #define SCOPED_LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) // The following annotations specify lock and unlock primitives. #define EXCLUSIVE_LOCK_FUNCTION(x) \ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock(x)) #define SHARED_LOCK_FUNCTION(x) \ THREAD_ANNOTATION_ATTRIBUTE__(shared_lock(x)) #define EXCLUSIVE_TRYLOCK_FUNCTION(x) \ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock(x)) #define SHARED_TRYLOCK_FUNCTION(x) \ THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock(x)) #define UNLOCK_FUNCTION(x) \ THREAD_ANNOTATION_ATTRIBUTE__(unlock(x)) // An escape hatch for thread safety analysis to ignore the annotated function. #define NO_THREAD_SAFETY_ANALYSIS \ THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) #endif // BASE_THREAD_ANNOTATIONS_H_ ================================================ FILE: distro/google-perftools-1.7/src/base/thread_lister.c ================================================ /* Copyright (c) 2005-2007, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Markus Gutschke */ #include "config.h" #include /* needed for NULL on some powerpc platforms (?!) */ #ifdef HAVE_SYS_PRCTL # include #endif #include "base/thread_lister.h" #include "base/linuxthreads.h" /* Include other thread listers here that define THREADS macro * only when they can provide a good implementation. */ #ifndef THREADS /* Default trivial thread lister for single-threaded applications, * or if the multi-threading code has not been ported, yet. */ int ListAllProcessThreads(void *parameter, ListAllProcessThreadsCallBack callback, ...) { int rc; va_list ap; pid_t pid; #ifdef HAVE_SYS_PRCTL int dumpable = prctl(PR_GET_DUMPABLE, 0); if (!dumpable) prctl(PR_SET_DUMPABLE, 1); #endif va_start(ap, callback); pid = getpid(); rc = callback(parameter, 1, &pid, ap); va_end(ap); #ifdef HAVE_SYS_PRCTL if (!dumpable) prctl(PR_SET_DUMPABLE, 0); #endif return rc; } int ResumeAllProcessThreads(int num_threads, pid_t *thread_pids) { return 1; } #endif /* ifndef THREADS */ ================================================ FILE: distro/google-perftools-1.7/src/base/thread_lister.h ================================================ /* Copyright (c) 2005-2007, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Markus Gutschke */ #ifndef _THREAD_LISTER_H #define _THREAD_LISTER_H #include #include #ifdef __cplusplus extern "C" { #endif typedef int (*ListAllProcessThreadsCallBack)(void *parameter, int num_threads, pid_t *thread_pids, va_list ap); /* This function gets the list of all linux threads of the current process * passes them to the 'callback' along with the 'parameter' pointer; at the * call back call time all the threads are paused via * PTRACE_ATTACH. * The callback is executed from a separate thread which shares only the * address space, the filesystem, and the filehandles with the caller. Most * notably, it does not share the same pid and ppid; and if it terminates, * the rest of the application is still there. 'callback' is supposed to do * or arrange for ResumeAllProcessThreads. This happens automatically, if * the thread raises a synchronous signal (e.g. SIGSEGV); asynchronous * signals are blocked. If the 'callback' decides to unblock them, it must * ensure that they cannot terminate the application, or that * ResumeAllProcessThreads will get called. * It is an error for the 'callback' to make any library calls that could * acquire locks. Most notably, this means that most system calls have to * avoid going through libc. Also, this means that it is not legal to call * exit() or abort(). * We return -1 on error and the return value of 'callback' on success. */ int ListAllProcessThreads(void *parameter, ListAllProcessThreadsCallBack callback, ...); /* This function resumes the list of all linux threads that * ListAllProcessThreads pauses before giving to its callback. * The function returns non-zero if at least one thread was * suspended and has now been resumed. */ int ResumeAllProcessThreads(int num_threads, pid_t *thread_pids); #ifdef __cplusplus } #endif #endif /* _THREAD_LISTER_H */ ================================================ FILE: distro/google-perftools-1.7/src/base/vdso_support.cc ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Paul Pluzhnikov // // Allow dynamic symbol lookup in the kernel VDSO page. // // VDSOSupport -- a class representing kernel VDSO (if present). // #include "base/vdso_support.h" #ifdef HAVE_VDSO_SUPPORT // defined in vdso_support.h #include #include // for ptrdiff_t #include "base/atomicops.h" // for MemoryBarrier #include "base/linux_syscall_support.h" #include "base/logging.h" #include "base/dynamic_annotations.h" #include "base/basictypes.h" // for COMPILE_ASSERT using base::subtle::MemoryBarrier; #ifndef AT_SYSINFO_EHDR #define AT_SYSINFO_EHDR 33 #endif // From binutils/include/elf/common.h (this doesn't appear to be documented // anywhere else). // // /* This flag appears in a Versym structure. It means that the symbol // is hidden, and is only visible with an explicit version number. // This is a GNU extension. */ // #define VERSYM_HIDDEN 0x8000 // // /* This is the mask for the rest of the Versym information. */ // #define VERSYM_VERSION 0x7fff #define VERSYM_VERSION 0x7fff namespace base { namespace { template class ElfClass { public: static const int kElfClass = -1; static int ElfBind(const ElfW(Sym) *) { CHECK(false); // << "Unexpected word size"; return 0; } static int ElfType(const ElfW(Sym) *) { CHECK(false); // << "Unexpected word size"; return 0; } }; template <> class ElfClass<32> { public: static const int kElfClass = ELFCLASS32; static int ElfBind(const ElfW(Sym) *symbol) { return ELF32_ST_BIND(symbol->st_info); } static int ElfType(const ElfW(Sym) *symbol) { return ELF32_ST_TYPE(symbol->st_info); } }; template <> class ElfClass<64> { public: static const int kElfClass = ELFCLASS64; static int ElfBind(const ElfW(Sym) *symbol) { return ELF64_ST_BIND(symbol->st_info); } static int ElfType(const ElfW(Sym) *symbol) { return ELF64_ST_TYPE(symbol->st_info); } }; typedef ElfClass<__WORDSIZE> CurrentElfClass; // Extract an element from one of the ELF tables, cast it to desired type. // This is just a simple arithmetic and a glorified cast. // Callers are responsible for bounds checking. template const T* GetTableElement(const ElfW(Ehdr) *ehdr, ElfW(Off) table_offset, ElfW(Word) element_size, size_t index) { return reinterpret_cast(reinterpret_cast(ehdr) + table_offset + index * element_size); } } // namespace const void *const VDSOSupport::kInvalidBase = reinterpret_cast(~0L); const void *VDSOSupport::vdso_base_ = kInvalidBase; VDSOSupport::GetCpuFn VDSOSupport::getcpu_fn_ = &InitAndGetCPU; VDSOSupport::ElfMemImage::ElfMemImage(const void *base) { CHECK(base != kInvalidBase); Init(base); } int VDSOSupport::ElfMemImage::GetNumSymbols() const { if (!hash_) { return 0; } // See http://www.caldera.com/developers/gabi/latest/ch5.dynamic.html#hash return hash_[1]; } const ElfW(Sym) *VDSOSupport::ElfMemImage::GetDynsym(int index) const { CHECK_LT(index, GetNumSymbols()); return dynsym_ + index; } const ElfW(Versym) *VDSOSupport::ElfMemImage::GetVersym(int index) const { CHECK_LT(index, GetNumSymbols()); return versym_ + index; } const ElfW(Phdr) *VDSOSupport::ElfMemImage::GetPhdr(int index) const { CHECK_LT(index, ehdr_->e_phnum); return GetTableElement(ehdr_, ehdr_->e_phoff, ehdr_->e_phentsize, index); } const char *VDSOSupport::ElfMemImage::GetDynstr(ElfW(Word) offset) const { CHECK_LT(offset, strsize_); return dynstr_ + offset; } const void *VDSOSupport::ElfMemImage::GetSymAddr(const ElfW(Sym) *sym) const { if (sym->st_shndx == SHN_UNDEF || sym->st_shndx >= SHN_LORESERVE) { // Symbol corresponds to "special" (e.g. SHN_ABS) section. return reinterpret_cast(sym->st_value); } CHECK_LT(link_base_, sym->st_value); return GetTableElement(ehdr_, 0, 1, sym->st_value) - link_base_; } const ElfW(Verdef) *VDSOSupport::ElfMemImage::GetVerdef(int index) const { CHECK_LE(index, verdefnum_); const ElfW(Verdef) *version_definition = verdef_; while (version_definition->vd_ndx < index && version_definition->vd_next) { const char *const version_definition_as_char = reinterpret_cast(version_definition); version_definition = reinterpret_cast(version_definition_as_char + version_definition->vd_next); } return version_definition->vd_ndx == index ? version_definition : NULL; } const ElfW(Verdaux) *VDSOSupport::ElfMemImage::GetVerdefAux( const ElfW(Verdef) *verdef) const { return reinterpret_cast(verdef+1); } const char *VDSOSupport::ElfMemImage::GetVerstr(ElfW(Word) offset) const { CHECK_LT(offset, strsize_); return dynstr_ + offset; } void VDSOSupport::ElfMemImage::Init(const void *base) { ehdr_ = NULL; dynsym_ = NULL; dynstr_ = NULL; versym_ = NULL; verdef_ = NULL; hash_ = NULL; strsize_ = 0; verdefnum_ = 0; link_base_ = ~0L; // Sentinel: PT_LOAD .p_vaddr can't possibly be this. if (!base) { return; } const intptr_t base_as_uintptr_t = reinterpret_cast(base); // Fake VDSO has low bit set. const bool fake_vdso = ((base_as_uintptr_t & 1) != 0); base = reinterpret_cast(base_as_uintptr_t & ~1); const char *const base_as_char = reinterpret_cast(base); if (base_as_char[EI_MAG0] != ELFMAG0 || base_as_char[EI_MAG1] != ELFMAG1 || base_as_char[EI_MAG2] != ELFMAG2 || base_as_char[EI_MAG3] != ELFMAG3) { RAW_DCHECK(false, "no ELF magic"); // at %p", base); return; } int elf_class = base_as_char[EI_CLASS]; if (elf_class != CurrentElfClass::kElfClass) { DCHECK_EQ(elf_class, CurrentElfClass::kElfClass); return; } switch (base_as_char[EI_DATA]) { case ELFDATA2LSB: { if (__LITTLE_ENDIAN != __BYTE_ORDER) { DCHECK_EQ(__LITTLE_ENDIAN, __BYTE_ORDER); // << ": wrong byte order"; return; } break; } case ELFDATA2MSB: { if (__BIG_ENDIAN != __BYTE_ORDER) { DCHECK_EQ(__BIG_ENDIAN, __BYTE_ORDER); // << ": wrong byte order"; return; } break; } default: { RAW_DCHECK(false, "unexpected data encoding"); // << base_as_char[EI_DATA]; return; } } ehdr_ = reinterpret_cast(base); const ElfW(Phdr) *dynamic_program_header = NULL; for (int i = 0; i < ehdr_->e_phnum; ++i) { const ElfW(Phdr) *const program_header = GetPhdr(i); switch (program_header->p_type) { case PT_LOAD: if (link_base_ == ~0L) { link_base_ = program_header->p_vaddr; } break; case PT_DYNAMIC: dynamic_program_header = program_header; break; } } if (link_base_ == ~0L || !dynamic_program_header) { RAW_DCHECK(~0L != link_base_, "no PT_LOADs in VDSO"); RAW_DCHECK(dynamic_program_header, "no PT_DYNAMIC in VDSO"); // Mark this image as not present. Can not recur infinitely. Init(0); return; } ptrdiff_t relocation = base_as_char - reinterpret_cast(link_base_); ElfW(Dyn) *dynamic_entry = reinterpret_cast(dynamic_program_header->p_vaddr + relocation); for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) { ElfW(Xword) value = dynamic_entry->d_un.d_val; if (fake_vdso) { // A complication: in the real VDSO, dynamic entries are not relocated // (it wasn't loaded by a dynamic loader). But when testing with a // "fake" dlopen()ed vdso library, the loader relocates some (but // not all!) of them before we get here. if (dynamic_entry->d_tag == DT_VERDEF) { // The only dynamic entry (of the ones we care about) libc-2.3.6 // loader doesn't relocate. value += relocation; } } else { // Real VDSO. Everything needs to be relocated. value += relocation; } switch (dynamic_entry->d_tag) { case DT_HASH: hash_ = reinterpret_cast(value); break; case DT_SYMTAB: dynsym_ = reinterpret_cast(value); break; case DT_STRTAB: dynstr_ = reinterpret_cast(value); break; case DT_VERSYM: versym_ = reinterpret_cast(value); break; case DT_VERDEF: verdef_ = reinterpret_cast(value); break; case DT_VERDEFNUM: verdefnum_ = dynamic_entry->d_un.d_val; break; case DT_STRSZ: strsize_ = dynamic_entry->d_un.d_val; break; default: // Unrecognized entries explicitly ignored. break; } } if (!hash_ || !dynsym_ || !dynstr_ || !versym_ || !verdef_ || !verdefnum_ || !strsize_) { RAW_DCHECK(hash_, "invalid VDSO (no DT_HASH)"); RAW_DCHECK(dynsym_, "invalid VDSO (no DT_SYMTAB)"); RAW_DCHECK(dynstr_, "invalid VDSO (no DT_STRTAB)"); RAW_DCHECK(versym_, "invalid VDSO (no DT_VERSYM)"); RAW_DCHECK(verdef_, "invalid VDSO (no DT_VERDEF)"); RAW_DCHECK(verdefnum_, "invalid VDSO (no DT_VERDEFNUM)"); RAW_DCHECK(strsize_, "invalid VDSO (no DT_STRSZ)"); // Mark this image as not present. Can not recur infinitely. Init(0); return; } } VDSOSupport::VDSOSupport() // If vdso_base_ is still set to kInvalidBase, we got here // before VDSOSupport::Init has been called. Call it now. : image_(vdso_base_ == kInvalidBase ? Init() : vdso_base_) { } // NOTE: we can't use GoogleOnceInit() below, because we can be // called by tcmalloc, and none of the *once* stuff may be functional yet. // // In addition, we hope that the VDSOSupportHelper constructor // causes this code to run before there are any threads, and before // InitGoogle() has executed any chroot or setuid calls. // // Finally, even if there is a race here, it is harmless, because // the operation should be idempotent. const void *VDSOSupport::Init() { if (vdso_base_ == kInvalidBase) { // Valgrind zaps AT_SYSINFO_EHDR and friends from the auxv[] // on stack, and so glibc works as if VDSO was not present. // But going directly to kernel via /proc/self/auxv below bypasses // Valgrind zapping. So we check for Valgrind separately. if (RunningOnValgrind()) { vdso_base_ = NULL; getcpu_fn_ = &GetCPUViaSyscall; return NULL; } int fd = open("/proc/self/auxv", O_RDONLY); if (fd == -1) { // Kernel too old to have a VDSO. vdso_base_ = NULL; getcpu_fn_ = &GetCPUViaSyscall; return NULL; } ElfW(auxv_t) aux; while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) { if (aux.a_type == AT_SYSINFO_EHDR) { COMPILE_ASSERT(sizeof(vdso_base_) == sizeof(aux.a_un.a_val), unexpected_sizeof_pointer_NE_sizeof_a_val); vdso_base_ = reinterpret_cast(aux.a_un.a_val); break; } } close(fd); if (vdso_base_ == kInvalidBase) { // Didn't find AT_SYSINFO_EHDR in auxv[]. vdso_base_ = NULL; } } GetCpuFn fn = &GetCPUViaSyscall; // default if VDSO not present. if (vdso_base_) { VDSOSupport vdso; SymbolInfo info; if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) { // Casting from an int to a pointer is not legal C++. To emphasize // this, we use a C-style cast rather than a C++-style cast. fn = (GetCpuFn)(info.address); } } // Subtle: this code runs outside of any locks; prevent compiler // from assigning to getcpu_fn_ more than once. base::subtle::MemoryBarrier(); getcpu_fn_ = fn; return vdso_base_; } const void *VDSOSupport::SetBase(const void *base) { const void *old_base = vdso_base_; vdso_base_ = base; image_.Init(base); // Also reset getcpu_fn_, so GetCPU could be tested with simulated VDSO. getcpu_fn_ = &InitAndGetCPU; return old_base; } bool VDSOSupport::LookupSymbol(const char *name, const char *version, int type, SymbolInfo *info) const { for (SymbolIterator it = begin(); it != end(); ++it) { if (strcmp(it->name, name) == 0 && strcmp(it->version, version) == 0 && CurrentElfClass::ElfType(it->symbol) == type) { if (info) { *info = *it; } return true; } } return false; } bool VDSOSupport::LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const { for (SymbolIterator it = begin(); it != end(); ++it) { const char *const symbol_start = reinterpret_cast(it->address); const char *const symbol_end = symbol_start + it->symbol->st_size; if (symbol_start <= address && address < symbol_end) { if (info_out) { // Client wants to know details for that symbol (the usual case). if (CurrentElfClass::ElfBind(it->symbol) == STB_GLOBAL) { // Strong symbol; just return it. *info_out = *it; return true; } else { // Weak or local. Record it, but keep looking for a strong one. *info_out = *it; } } else { // Client only cares if there is an overlapping symbol. return true; } } } return false; } VDSOSupport::SymbolIterator::SymbolIterator(const void *const image, int index) : index_(index), image_(image) { } const VDSOSupport::SymbolInfo *VDSOSupport::SymbolIterator::operator->() const { return &info_; } const VDSOSupport::SymbolInfo& VDSOSupport::SymbolIterator::operator*() const { return info_; } bool VDSOSupport::SymbolIterator::operator==(const SymbolIterator &rhs) const { return this->image_ == rhs.image_ && this->index_ == rhs.index_; } bool VDSOSupport::SymbolIterator::operator!=(const SymbolIterator &rhs) const { return !(*this == rhs); } VDSOSupport::SymbolIterator &VDSOSupport::SymbolIterator::operator++() { this->Update(1); return *this; } VDSOSupport::SymbolIterator VDSOSupport::begin() const { SymbolIterator it(&image_, 0); it.Update(0); return it; } VDSOSupport::SymbolIterator VDSOSupport::end() const { return SymbolIterator(&image_, image_.GetNumSymbols()); } void VDSOSupport::SymbolIterator::Update(int increment) { const ElfMemImage *image = reinterpret_cast(image_); CHECK(image->IsPresent() || increment == 0); if (!image->IsPresent()) { return; } index_ += increment; if (index_ >= image->GetNumSymbols()) { index_ = image->GetNumSymbols(); return; } const ElfW(Sym) *symbol = image->GetDynsym(index_); const ElfW(Versym) *version_symbol = image->GetVersym(index_); CHECK(symbol && version_symbol); const char *const symbol_name = image->GetDynstr(symbol->st_name); const ElfW(Versym) version_index = version_symbol[0] & VERSYM_VERSION; const ElfW(Verdef) *version_definition = NULL; const char *version_name = ""; if (symbol->st_shndx == SHN_UNDEF) { // Undefined symbols reference DT_VERNEED, not DT_VERDEF, and // version_index could well be greater than verdefnum_, so calling // GetVerdef(version_index) may trigger assertion. } else { version_definition = image->GetVerdef(version_index); } if (version_definition) { // I am expecting 1 or 2 auxiliary entries: 1 for the version itself, // optional 2nd if the version has a parent. CHECK_LE(1, version_definition->vd_cnt); CHECK_LE(version_definition->vd_cnt, 2); const ElfW(Verdaux) *version_aux = image->GetVerdefAux(version_definition); version_name = image->GetVerstr(version_aux->vda_name); } info_.name = symbol_name; info_.version = version_name; info_.address = image->GetSymAddr(symbol); info_.symbol = symbol; } // NOLINT on 'long' because this routine mimics kernel api. long VDSOSupport::GetCPUViaSyscall(unsigned *cpu, void *, void *) { // NOLINT #if defined(__NR_getcpu) return sys_getcpu(cpu, NULL, NULL); #else // x86_64 never implemented sys_getcpu(), except as a VDSO call. errno = ENOSYS; return -1; #endif } // Use fast __vdso_getcpu if available. long VDSOSupport::InitAndGetCPU(unsigned *cpu, void *x, void *y) { // NOLINT Init(); CHECK_NE(getcpu_fn_, &InitAndGetCPU); // << "Init() did not set getcpu_fn_"; return (*getcpu_fn_)(cpu, x, y); } // This function must be very fast, and may be called from very // low level (e.g. tcmalloc). Hence I avoid things like // GoogleOnceInit() and ::operator new. int GetCPU(void) { unsigned cpu; int ret_code = (*VDSOSupport::getcpu_fn_)(&cpu, NULL, NULL); return ret_code == 0 ? cpu : ret_code; } // We need to make sure VDSOSupport::Init() is called before // the main() runs, since it might do something like setuid or // chroot. If VDSOSupport // is used in any global constructor, this will happen, since // VDSOSupport's constructor calls Init. But if not, we need to // ensure it here, with a global constructor of our own. This // is an allowed exception to the normal rule against non-trivial // global constructors. static class VDSOInitHelper { public: VDSOInitHelper() { VDSOSupport::Init(); } } vdso_init_helper; } #endif // HAVE_VDSO_SUPPORT ================================================ FILE: distro/google-perftools-1.7/src/base/vdso_support.h ================================================ // Copyright 2008 Google Inc. All Rights Reserved. // Author: ppluzhnikov@google.com (Paul Pluzhnikov) // // Allow dynamic symbol lookup in the kernel VDSO page. // // VDSO stands for "Virtual Dynamic Shared Object" -- a page of // executable code, which looks like a shared library, but doesn't // necessarily exist anywhere on disk, and which gets mmap()ed into // every process by kernels which support VDSO, such as 2.6.x for 32-bit // executables, and 2.6.24 and above for 64-bit executables. // // More details could be found here: // http://www.trilithium.com/johan/2005/08/linux-gate/ // // VDSOSupport -- a class representing kernel VDSO (if present). // // Example usage: // VDSOSupport vdso; // VDSOSupport::SymbolInfo info; // typedef (*FN)(unsigned *, void *, void *); // FN fn = NULL; // if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) { // fn = reinterpret_cast(info.address); // } #ifndef BASE_VDSO_SUPPORT_H_ #define BASE_VDSO_SUPPORT_H_ #include #ifdef HAVE_FEATURES_H #include // for __GLIBC__ #endif // Maybe one day we can rewrite this file not to require the elf // symbol extensions in glibc, but for right now we need them. #if defined(__ELF__) && defined(__GLIBC__) #define HAVE_VDSO_SUPPORT 1 #include // for NULL #include // for ElfW #include "base/basictypes.h" namespace base { // NOTE: this class may be used from within tcmalloc, and can not // use any memory allocation routines. class VDSOSupport { public: // Sentinel: there could never be a VDSO at this address. static const void *const kInvalidBase; // Information about a single vdso symbol. // All pointers are into .dynsym, .dynstr, or .text of the VDSO. // Do not free() them or modify through them. struct SymbolInfo { const char *name; // E.g. "__vdso_getcpu" const char *version; // E.g. "LINUX_2.6", could be "" // for unversioned symbol. const void *address; // Relocated symbol address. const ElfW(Sym) *symbol; // Symbol in the dynamic symbol table. }; // Supports iteration over all dynamic symbols. class SymbolIterator { public: friend class VDSOSupport; const SymbolInfo *operator->() const; const SymbolInfo &operator*() const; SymbolIterator& operator++(); bool operator!=(const SymbolIterator &rhs) const; bool operator==(const SymbolIterator &rhs) const; private: SymbolIterator(const void *const image, int index); void Update(int incr); SymbolInfo info_; int index_; const void *const image_; }; VDSOSupport(); // Answers whether we have a vdso at all. bool IsPresent() const { return image_.IsPresent(); } // Allow to iterate over all VDSO symbols. SymbolIterator begin() const; SymbolIterator end() const; // Look up versioned dynamic symbol in the kernel VDSO. // Returns false if VDSO is not present, or doesn't contain given // symbol/version/type combination. // If info_out != NULL, additional details are filled in. bool LookupSymbol(const char *name, const char *version, int symbol_type, SymbolInfo *info_out) const; // Find info about symbol (if any) which overlaps given address. // Returns true if symbol was found; false if VDSO isn't present // or doesn't have a symbol overlapping given address. // If info_out != NULL, additional details are filled in. bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const; // Used only for testing. Replace real VDSO base with a mock. // Returns previous value of vdso_base_. After you are done testing, // you are expected to call SetBase() with previous value, in order to // reset state to the way it was. const void *SetBase(const void *s); // Computes vdso_base_ and returns it. Should be called as early as // possible; before any thread creation, chroot or setuid. static const void *Init(); private: // An in-memory ELF image (may not exist on disk). class ElfMemImage { public: explicit ElfMemImage(const void *base); void Init(const void *base); bool IsPresent() const { return ehdr_ != NULL; } const ElfW(Phdr)* GetPhdr(int index) const; const ElfW(Sym)* GetDynsym(int index) const; const ElfW(Versym)* GetVersym(int index) const; const ElfW(Verdef)* GetVerdef(int index) const; const ElfW(Verdaux)* GetVerdefAux(const ElfW(Verdef) *verdef) const; const char* GetDynstr(ElfW(Word) offset) const; const void* GetSymAddr(const ElfW(Sym) *sym) const; const char* GetVerstr(ElfW(Word) offset) const; int GetNumSymbols() const; private: const ElfW(Ehdr) *ehdr_; const ElfW(Sym) *dynsym_; const ElfW(Versym) *versym_; const ElfW(Verdef) *verdef_; const ElfW(Word) *hash_; const char *dynstr_; size_t strsize_; size_t verdefnum_; ElfW(Addr) link_base_; // Link-time base (p_vaddr of first PT_LOAD). }; // image_ represents VDSO ELF image in memory. // image_.ehdr_ == NULL implies there is no VDSO. ElfMemImage image_; // Cached value of auxv AT_SYSINFO_EHDR, computed once. // This is a tri-state: // kInvalidBase => value hasn't been determined yet. // 0 => there is no VDSO. // else => vma of VDSO Elf{32,64}_Ehdr. // // When testing with mock VDSO, low bit is set. // The low bit is always available because vdso_base_ is // page-aligned. static const void *vdso_base_; // NOLINT on 'long' because these routines mimic kernel api. // The 'cache' parameter may be used by some versions of the kernel, // and should be NULL or point to a static buffer containing at // least two 'long's. static long InitAndGetCPU(unsigned *cpu, void *cache, // NOLINT 'long'. void *unused); static long GetCPUViaSyscall(unsigned *cpu, void *cache, // NOLINT 'long'. void *unused); typedef long (*GetCpuFn)(unsigned *cpu, void *cache, // NOLINT 'long'. void *unused); // This function pointer may point to InitAndGetCPU, // GetCPUViaSyscall, or __vdso_getcpu at different stages of initialization. static GetCpuFn getcpu_fn_; friend int GetCPU(void); // Needs access to getcpu_fn_. DISALLOW_COPY_AND_ASSIGN(VDSOSupport); }; // Same as sched_getcpu() on later glibc versions. // Return current CPU, using (fast) __vdso_getcpu@LINUX_2.6 if present, // otherwise use syscall(SYS_getcpu,...). // May return -1 with errno == ENOSYS if the kernel doesn't // support SYS_getcpu. int GetCPU(); } // namespace base #endif // __ELF__ and __GLIBC__ #endif // BASE_VDSO_SUPPORT_H_ ================================================ FILE: distro/google-perftools-1.7/src/central_freelist.cc ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat #include "config.h" #include "central_freelist.h" #include "linked_list.h" #include "static_vars.h" namespace tcmalloc { void CentralFreeList::Init(size_t cl) { size_class_ = cl; tcmalloc::DLL_Init(&empty_); tcmalloc::DLL_Init(&nonempty_); counter_ = 0; cache_size_ = 1; used_slots_ = 0; ASSERT(cache_size_ <= kNumTransferEntries); } void CentralFreeList::ReleaseListToSpans(void* start) { while (start) { void *next = SLL_Next(start); ReleaseToSpans(start); start = next; } } // MapObjectToSpan should logically be part of ReleaseToSpans. But // this triggers an optimization bug in gcc 4.5.0. Moving to a // separate function, and making sure that function isn't inlined, // seems to fix the problem. It also should be fixed for gcc 4.5.1. static #if __GNUC__ == 4 && __GNUC_MINOR__ == 5 && __GNUC_PATCHLEVEL__ == 0 __attribute__ ((noinline)) #endif Span* MapObjectToSpan(void* object) { const PageID p = reinterpret_cast(object) >> kPageShift; Span* span = Static::pageheap()->GetDescriptor(p); return span; } void CentralFreeList::ReleaseToSpans(void* object) { Span* span = MapObjectToSpan(object); ASSERT(span != NULL); ASSERT(span->refcount > 0); // If span is empty, move it to non-empty list if (span->objects == NULL) { tcmalloc::DLL_Remove(span); tcmalloc::DLL_Prepend(&nonempty_, span); Event(span, 'N', 0); } // The following check is expensive, so it is disabled by default if (false) { // Check that object does not occur in list int got = 0; for (void* p = span->objects; p != NULL; p = *((void**) p)) { ASSERT(p != object); got++; } ASSERT(got + span->refcount == (span->length<ByteSizeForClass(span->sizeclass)); } counter_++; span->refcount--; if (span->refcount == 0) { Event(span, '#', 0); counter_ -= ((span->length<ByteSizeForClass(span->sizeclass)); tcmalloc::DLL_Remove(span); // Release central list lock while operating on pageheap lock_.Unlock(); { SpinLockHolder h(Static::pageheap_lock()); Static::pageheap()->Delete(span); } lock_.Lock(); } else { *(reinterpret_cast(object)) = span->objects; span->objects = object; } } bool CentralFreeList::EvictRandomSizeClass( int locked_size_class, bool force) { static int race_counter = 0; int t = race_counter++; // Updated without a lock, but who cares. if (t >= kNumClasses) { while (t >= kNumClasses) { t -= kNumClasses; } race_counter = t; } ASSERT(t >= 0); ASSERT(t < kNumClasses); if (t == locked_size_class) return false; return Static::central_cache()[t].ShrinkCache(locked_size_class, force); } bool CentralFreeList::MakeCacheSpace() { // Is there room in the cache? if (used_slots_ < cache_size_) return true; // Check if we can expand this cache? if (cache_size_ == kNumTransferEntries) return false; // Ok, we'll try to grab an entry from some other size class. if (EvictRandomSizeClass(size_class_, false) || EvictRandomSizeClass(size_class_, true)) { // Succeeded in evicting, we're going to make our cache larger. cache_size_++; return true; } return false; } namespace { class LockInverter { private: SpinLock *held_, *temp_; public: inline explicit LockInverter(SpinLock* held, SpinLock *temp) : held_(held), temp_(temp) { held_->Unlock(); temp_->Lock(); } inline ~LockInverter() { temp_->Unlock(); held_->Lock(); } }; } // This function is marked as NO_THREAD_SAFETY_ANALYSIS because it uses // LockInverter to release one lock and acquire another in scoped-lock // style, which our current annotation/analysis does not support. bool CentralFreeList::ShrinkCache(int locked_size_class, bool force) NO_THREAD_SAFETY_ANALYSIS { // Start with a quick check without taking a lock. if (cache_size_ == 0) return false; // We don't evict from a full cache unless we are 'forcing'. if (force == false && used_slots_ == cache_size_) return false; // Grab lock, but first release the other lock held by this thread. We use // the lock inverter to ensure that we never hold two size class locks // concurrently. That can create a deadlock because there is no well // defined nesting order. LockInverter li(&Static::central_cache()[locked_size_class].lock_, &lock_); ASSERT(used_slots_ <= cache_size_); ASSERT(0 <= cache_size_); if (cache_size_ == 0) return false; if (used_slots_ == cache_size_) { if (force == false) return false; // ReleaseListToSpans releases the lock, so we have to make all the // updates to the central list before calling it. cache_size_--; used_slots_--; ReleaseListToSpans(tc_slots_[used_slots_].head); return true; } cache_size_--; return true; } void CentralFreeList::InsertRange(void *start, void *end, int N) { SpinLockHolder h(&lock_); if (N == Static::sizemap()->num_objects_to_move(size_class_) && MakeCacheSpace()) { int slot = used_slots_++; ASSERT(slot >=0); ASSERT(slot < kNumTransferEntries); TCEntry *entry = &tc_slots_[slot]; entry->head = start; entry->tail = end; return; } ReleaseListToSpans(start); } int CentralFreeList::RemoveRange(void **start, void **end, int N) { ASSERT(N > 0); lock_.Lock(); if (N == Static::sizemap()->num_objects_to_move(size_class_) && used_slots_ > 0) { int slot = --used_slots_; ASSERT(slot >= 0); TCEntry *entry = &tc_slots_[slot]; *start = entry->head; *end = entry->tail; lock_.Unlock(); return N; } int result = 0; void* head = NULL; void* tail = NULL; // TODO: Prefetch multiple TCEntries? tail = FetchFromSpansSafe(); if (tail != NULL) { SLL_SetNext(tail, NULL); head = tail; result = 1; while (result < N) { void *t = FetchFromSpans(); if (!t) break; SLL_Push(&head, t); result++; } } lock_.Unlock(); *start = head; *end = tail; return result; } void* CentralFreeList::FetchFromSpansSafe() { void *t = FetchFromSpans(); if (!t) { Populate(); t = FetchFromSpans(); } return t; } void* CentralFreeList::FetchFromSpans() { if (tcmalloc::DLL_IsEmpty(&nonempty_)) return NULL; Span* span = nonempty_.next; ASSERT(span->objects != NULL); span->refcount++; void* result = span->objects; span->objects = *(reinterpret_cast(result)); if (span->objects == NULL) { // Move to empty list tcmalloc::DLL_Remove(span); tcmalloc::DLL_Prepend(&empty_, span); Event(span, 'E', 0); } counter_--; return result; } // Fetch memory from the system and add to the central cache freelist. void CentralFreeList::Populate() { // Release central list lock while operating on pageheap lock_.Unlock(); const size_t npages = Static::sizemap()->class_to_pages(size_class_); Span* span; { SpinLockHolder h(Static::pageheap_lock()); span = Static::pageheap()->New(npages); if (span) Static::pageheap()->RegisterSizeClass(span, size_class_); } if (span == NULL) { MESSAGE("tcmalloc: allocation failed", npages << kPageShift); lock_.Lock(); return; } ASSERT(span->length == npages); // Cache sizeclass info eagerly. Locking is not necessary. // (Instead of being eager, we could just replace any stale info // about this span, but that seems to be no better in practice.) for (int i = 0; i < npages; i++) { Static::pageheap()->CacheSizeClass(span->start + i, size_class_); } // Split the block into pieces and add to the free-list // TODO: coloring of objects to avoid cache conflicts? void** tail = &span->objects; char* ptr = reinterpret_cast(span->start << kPageShift); char* limit = ptr + (npages << kPageShift); const size_t size = Static::sizemap()->ByteSizeForClass(size_class_); int num = 0; while (ptr + size <= limit) { *tail = ptr; tail = reinterpret_cast(ptr); ptr += size; num++; } ASSERT(ptr <= limit); *tail = NULL; span->refcount = 0; // No sub-object in use yet // Add span to list of non-empty spans lock_.Lock(); tcmalloc::DLL_Prepend(&nonempty_, span); counter_ += num; } int CentralFreeList::tc_length() { SpinLockHolder h(&lock_); return used_slots_ * Static::sizemap()->num_objects_to_move(size_class_); } } // namespace tcmalloc ================================================ FILE: distro/google-perftools-1.7/src/central_freelist.h ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat #ifndef TCMALLOC_CENTRAL_FREELIST_H_ #define TCMALLOC_CENTRAL_FREELIST_H_ #include "config.h" #include "base/thread_annotations.h" #include "base/spinlock.h" #include "common.h" #include "span.h" namespace tcmalloc { // Data kept per size-class in central cache. class CentralFreeList { public: void Init(size_t cl); // These methods all do internal locking. // Insert the specified range into the central freelist. N is the number of // elements in the range. RemoveRange() is the opposite operation. void InsertRange(void *start, void *end, int N); // Returns the actual number of fetched elements and sets *start and *end. int RemoveRange(void **start, void **end, int N); // Returns the number of free objects in cache. int length() { SpinLockHolder h(&lock_); return counter_; } // Returns the number of free objects in the transfer cache. int tc_length(); private: // TransferCache is used to cache transfers of // sizemap.num_objects_to_move(size_class) back and forth between // thread caches and the central cache for a given size class. struct TCEntry { void *head; // Head of chain of objects. void *tail; // Tail of chain of objects. }; // A central cache freelist can have anywhere from 0 to kNumTransferEntries // slots to put link list chains into. To keep memory usage bounded the total // number of TCEntries across size classes is fixed. Currently each size // class is initially given one TCEntry which also means that the maximum any // one class can have is kNumClasses. static const int kNumTransferEntries = kNumClasses; // REQUIRES: lock_ is held // Remove object from cache and return. // Return NULL if no free entries in cache. void* FetchFromSpans() EXCLUSIVE_LOCKS_REQUIRED(lock_); // REQUIRES: lock_ is held // Remove object from cache and return. Fetches // from pageheap if cache is empty. Only returns // NULL on allocation failure. void* FetchFromSpansSafe() EXCLUSIVE_LOCKS_REQUIRED(lock_); // REQUIRES: lock_ is held // Release a linked list of objects to spans. // May temporarily release lock_. void ReleaseListToSpans(void *start) EXCLUSIVE_LOCKS_REQUIRED(lock_); // REQUIRES: lock_ is held // Release an object to spans. // May temporarily release lock_. void ReleaseToSpans(void* object) EXCLUSIVE_LOCKS_REQUIRED(lock_); // REQUIRES: lock_ is held // Populate cache by fetching from the page heap. // May temporarily release lock_. void Populate() EXCLUSIVE_LOCKS_REQUIRED(lock_); // REQUIRES: lock is held. // Tries to make room for a TCEntry. If the cache is full it will try to // expand it at the cost of some other cache size. Return false if there is // no space. bool MakeCacheSpace() EXCLUSIVE_LOCKS_REQUIRED(lock_); // REQUIRES: lock_ for locked_size_class is held. // Picks a "random" size class to steal TCEntry slot from. In reality it // just iterates over the sizeclasses but does so without taking a lock. // Returns true on success. // May temporarily lock a "random" size class. static bool EvictRandomSizeClass(int locked_size_class, bool force); // REQUIRES: lock_ is *not* held. // Tries to shrink the Cache. If force is true it will relase objects to // spans if it allows it to shrink the cache. Return false if it failed to // shrink the cache. Decrements cache_size_ on succeess. // May temporarily take lock_. If it takes lock_, the locked_size_class // lock is released to keep the thread from holding two size class locks // concurrently which could lead to a deadlock. bool ShrinkCache(int locked_size_class, bool force) LOCKS_EXCLUDED(lock_); // This lock protects all the data members. cached_entries and cache_size_ // may be looked at without holding the lock. SpinLock lock_; // We keep linked lists of empty and non-empty spans. size_t size_class_; // My size class Span empty_; // Dummy header for list of empty spans Span nonempty_; // Dummy header for list of non-empty spans size_t counter_; // Number of free objects in cache entry // Here we reserve space for TCEntry cache slots. Since one size class can // end up getting all the TCEntries quota in the system we just preallocate // sufficient number of entries here. TCEntry tc_slots_[kNumTransferEntries]; // Number of currently used cached entries in tc_slots_. This variable is // updated under a lock but can be read without one. int32_t used_slots_; // The current number of slots for this size class. This is an // adaptive value that is increased if there is lots of traffic // on a given size class. int32_t cache_size_; }; // Pads each CentralCache object to multiple of 64 bytes. Since some // compilers (such as MSVC) don't like it when the padding is 0, I use // template specialization to remove the padding entirely when // sizeof(CentralFreeList) is a multiple of 64. template class CentralFreeListPaddedTo : public CentralFreeList { private: char pad_[64 - kFreeListSizeMod64]; }; template<> class CentralFreeListPaddedTo<0> : public CentralFreeList { }; class CentralFreeListPadded : public CentralFreeListPaddedTo< sizeof(CentralFreeList) % 64> { }; } // namespace tcmalloc #endif // TCMALLOC_CENTRAL_FREELIST_H_ ================================================ FILE: distro/google-perftools-1.7/src/common.cc ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat #include "config.h" #include "system-alloc.h" #include "config.h" #include "common.h" namespace tcmalloc { // Note: the following only works for "n"s that fit in 32-bits, but // that is fine since we only use it for small sizes. static inline int LgFloor(size_t n) { int log = 0; for (int i = 4; i >= 0; --i) { int shift = (1 << i); size_t x = n >> shift; if (x != 0) { n = x; log += shift; } } ASSERT(n == 1); return log; } int AlignmentForSize(size_t size) { int alignment = kAlignment; if (size >= 2048) { // Cap alignment at 256 for large sizes. alignment = 256; } else if (size >= 128) { // Space wasted due to alignment is at most 1/8, i.e., 12.5%. alignment = (1 << LgFloor(size)) / 8; } else if (size >= 16) { // We need an alignment of at least 16 bytes to satisfy // requirements for some SSE types. alignment = 16; } CHECK_CONDITION(size < 16 || alignment >= 16); CHECK_CONDITION((alignment & (alignment - 1)) == 0); return alignment; } int SizeMap::NumMoveSize(size_t size) { if (size == 0) return 0; // Use approx 64k transfers between thread and central caches. int num = static_cast(64.0 * 1024.0 / size); if (num < 2) num = 2; // Avoid bringing too many objects into small object free lists. // If this value is too large: // - We waste memory with extra objects sitting in the thread caches. // - The central freelist holds its lock for too long while // building a linked list of objects, slowing down the allocations // of other threads. // If this value is too small: // - We go to the central freelist too often and we have to acquire // its lock each time. // This value strikes a balance between the constraints above. if (num > 32) num = 32; return num; } // Initialize the mapping arrays void SizeMap::Init() { // Do some sanity checking on add_amount[]/shift_amount[]/class_array[] if (ClassIndex(0) < 0) { CRASH("Invalid class index %d for size 0\n", ClassIndex(0)); } if (ClassIndex(kMaxSize) >= sizeof(class_array_)) { CRASH("Invalid class index %d for kMaxSize\n", ClassIndex(kMaxSize)); } // Compute the size classes we want to use int sc = 1; // Next size class to assign int alignment = kAlignment; CHECK_CONDITION(kAlignment <= 16); int last_lg = -1; for (size_t size = kAlignment; size <= kMaxSize; size += alignment) { int lg = LgFloor(size); if (lg > last_lg) { // Increase alignment every so often to reduce number of size classes. alignment = AlignmentForSize(size); last_lg = lg; } CHECK_CONDITION((size % alignment) == 0); // Allocate enough pages so leftover is less than 1/8 of total. // This bounds wasted space to at most 12.5%. size_t psize = kPageSize; while ((psize % size) > (psize >> 3)) { psize += kPageSize; } const size_t my_pages = psize >> kPageShift; if (sc > 1 && my_pages == class_to_pages_[sc-1]) { // See if we can merge this into the previous class without // increasing the fragmentation of the previous class. const size_t my_objects = (my_pages << kPageShift) / size; const size_t prev_objects = (class_to_pages_[sc-1] << kPageShift) / class_to_size_[sc-1]; if (my_objects == prev_objects) { // Adjust last class to include this size class_to_size_[sc-1] = size; continue; } } // Add new class class_to_pages_[sc] = my_pages; class_to_size_[sc] = size; sc++; } if (sc != kNumClasses) { CRASH("wrong number of size classes: found %d instead of %d\n", sc, int(kNumClasses)); } // Initialize the mapping arrays int next_size = 0; for (int c = 1; c < kNumClasses; c++) { const int max_size_in_class = class_to_size_[c]; for (int s = next_size; s <= max_size_in_class; s += kAlignment) { class_array_[ClassIndex(s)] = c; } next_size = max_size_in_class + kAlignment; } // Double-check sizes just to be safe for (size_t size = 0; size <= kMaxSize; size++) { const int sc = SizeClass(size); if (sc <= 0 || sc >= kNumClasses) { CRASH("Bad size class %d for %" PRIuS "\n", sc, size); } if (sc > 1 && size <= class_to_size_[sc-1]) { CRASH("Allocating unnecessarily large class %d for %" PRIuS "\n", sc, size); } const size_t s = class_to_size_[sc]; if (size > s) { CRASH("Bad size %" PRIuS " for %" PRIuS " (sc = %d)\n", s, size, sc); } if (s == 0) { CRASH("Bad size %" PRIuS " for %" PRIuS " (sc = %d)\n", s, size, sc); } } // Initialize the num_objects_to_move array. for (size_t cl = 1; cl < kNumClasses; ++cl) { num_objects_to_move_[cl] = NumMoveSize(ByteSizeForClass(cl)); } } void SizeMap::Dump(TCMalloc_Printer* out) { // Dump class sizes and maximum external wastage per size class for (size_t cl = 1; cl < kNumClasses; ++cl) { const int alloc_size = class_to_pages_[cl] << kPageShift; const int alloc_objs = alloc_size / class_to_size_[cl]; const int min_used = (class_to_size_[cl-1] + 1) * alloc_objs; const int max_waste = alloc_size - min_used; out->printf("SC %3d [ %8d .. %8d ] from %8d ; %2.0f%% maxwaste\n", int(cl), int(class_to_size_[cl-1] + 1), int(class_to_size_[cl]), int(class_to_pages_[cl] << kPageShift), max_waste * 100.0 / alloc_size ); } } // Metadata allocator -- keeps stats about how many bytes allocated. static uint64_t metadata_system_bytes_ = 0; void* MetaDataAlloc(size_t bytes) { void* result = TCMalloc_SystemAlloc(bytes, NULL); if (result != NULL) { metadata_system_bytes_ += bytes; } return result; } uint64_t metadata_system_bytes() { return metadata_system_bytes_; } } // namespace tcmalloc ================================================ FILE: distro/google-perftools-1.7/src/common.h ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // Common definitions for tcmalloc code. #ifndef TCMALLOC_COMMON_H_ #define TCMALLOC_COMMON_H_ #include "config.h" #include #ifdef HAVE_STDINT_H #include #endif #include #include "base/commandlineflags.h" #include "internal_logging.h" // Type that can hold a page number typedef uintptr_t PageID; // Type that can hold the length of a run of pages typedef uintptr_t Length; //------------------------------------------------------------------- // Configuration //------------------------------------------------------------------- // Using large pages speeds up the execution at a cost of larger memory use. // Deallocation may speed up by a factor as the page map gets 8x smaller, so // lookups in the page map result in fewer L2 cache misses, which translates to // speedup for application/platform combinations with high L2 cache pressure. // As the number of size classes increases with large pages, we increase // the thread cache allowance to avoid passing more free ranges to and from // central lists. Also, larger pages are less likely to get freed. // These two factors cause a bounded increase in memory use. #if defined(TCMALLOC_LARGE_PAGES) static const size_t kPageShift = 15; static const size_t kNumClasses = 95; static const size_t kMaxThreadCacheSize = 4 << 20; #else static const size_t kPageShift = 12; static const size_t kNumClasses = 61; static const size_t kMaxThreadCacheSize = 2 << 20; #endif static const size_t kPageSize = 1 << kPageShift; static const size_t kMaxSize = 8u * kPageSize; static const size_t kAlignment = 8; static const size_t kLargeSizeClass = 0; // For all span-lengths < kMaxPages we keep an exact-size list. static const size_t kMaxPages = 1 << (20 - kPageShift); // Default bound on the total amount of thread caches. static const size_t kDefaultOverallThreadCacheSize = 8u * kMaxThreadCacheSize; // Lower bound on the per-thread cache sizes static const size_t kMinThreadCacheSize = kMaxSize * 2; // The number of bytes one ThreadCache will steal from another when // the first ThreadCache is forced to Scavenge(), delaying the // next call to Scavenge for this thread. static const size_t kStealAmount = 1 << 16; // The number of times that a deallocation can cause a freelist to // go over its max_length() before shrinking max_length(). static const int kMaxOverages = 3; // Maximum length we allow a per-thread free-list to have before we // move objects from it into the corresponding central free-list. We // want this big to avoid locking the central free-list too often. It // should not hurt to make this list somewhat big because the // scavenging code will shrink it down when its contents are not in use. static const int kMaxDynamicFreeListLength = 8192; static const Length kMaxValidPages = (~static_cast(0)) >> kPageShift; #ifdef __x86_64__ // All current and planned x86_64 processors only look at the lower 48 bits // in virtual to physical address translation. The top 16 are thus unused. // TODO(rus): Under what operating systems can we increase it safely to 17? // This lets us use smaller page maps. On first allocation, a 36-bit page map // uses only 96 KB instead of the 4.5 MB used by a 52-bit page map. static const int kAddressBits = 48; #else static const int kAddressBits = 8 * sizeof(void*); #endif namespace tcmalloc { // Convert byte size into pages. This won't overflow, but may return // an unreasonably large value if bytes is huge enough. inline Length pages(size_t bytes) { return (bytes >> kPageShift) + ((bytes & (kPageSize - 1)) > 0 ? 1 : 0); } // For larger allocation sizes, we use larger memory alignments to // reduce the number of size classes. int AlignmentForSize(size_t size); // Size-class information + mapping class SizeMap { private: // Number of objects to move between a per-thread list and a central // list in one shot. We want this to be not too small so we can // amortize the lock overhead for accessing the central list. Making // it too big may temporarily cause unnecessary memory wastage in the // per-thread free list until the scavenger cleans up the list. int num_objects_to_move_[kNumClasses]; //------------------------------------------------------------------- // Mapping from size to size_class and vice versa //------------------------------------------------------------------- // Sizes <= 1024 have an alignment >= 8. So for such sizes we have an // array indexed by ceil(size/8). Sizes > 1024 have an alignment >= 128. // So for these larger sizes we have an array indexed by ceil(size/128). // // We flatten both logical arrays into one physical array and use // arithmetic to compute an appropriate index. The constants used by // ClassIndex() were selected to make the flattening work. // // Examples: // Size Expression Index // ------------------------------------------------------- // 0 (0 + 7) / 8 0 // 1 (1 + 7) / 8 1 // ... // 1024 (1024 + 7) / 8 128 // 1025 (1025 + 127 + (120<<7)) / 128 129 // ... // 32768 (32768 + 127 + (120<<7)) / 128 376 static const int kMaxSmallSize = 1024; static const size_t kClassArraySize = (((1 << kPageShift) * 8u + 127 + (120 << 7)) >> 7) + 1; unsigned char class_array_[kClassArraySize]; // Compute index of the class_array[] entry for a given size static inline int ClassIndex(int s) { ASSERT(0 <= s); ASSERT(s <= kMaxSize); const bool big = (s > kMaxSmallSize); const int add_amount = big ? (127 + (120<<7)) : 7; const int shift_amount = big ? 7 : 3; return (s + add_amount) >> shift_amount; } int NumMoveSize(size_t size); // Mapping from size class to max size storable in that class size_t class_to_size_[kNumClasses]; // Mapping from size class to number of pages to allocate at a time size_t class_to_pages_[kNumClasses]; public: // Constructor should do nothing since we rely on explicit Init() // call, which may or may not be called before the constructor runs. SizeMap() { } // Initialize the mapping arrays void Init(); inline int SizeClass(int size) { return class_array_[ClassIndex(size)]; } // Get the byte-size for a specified class inline size_t ByteSizeForClass(size_t cl) { return class_to_size_[cl]; } // Mapping from size class to max size storable in that class inline size_t class_to_size(size_t cl) { return class_to_size_[cl]; } // Mapping from size class to number of pages to allocate at a time inline size_t class_to_pages(size_t cl) { return class_to_pages_[cl]; } // Number of objects to move between a per-thread list and a central // list in one shot. We want this to be not too small so we can // amortize the lock overhead for accessing the central list. Making // it too big may temporarily cause unnecessary memory wastage in the // per-thread free list until the scavenger cleans up the list. inline int num_objects_to_move(size_t cl) { return num_objects_to_move_[cl]; } // Dump contents of the computed size map void Dump(TCMalloc_Printer* out); }; // Allocates "bytes" worth of memory and returns it. Increments // metadata_system_bytes appropriately. May return NULL if allocation // fails. Requires pageheap_lock is held. void* MetaDataAlloc(size_t bytes); // Returns the total number of bytes allocated from the system. // Requires pageheap_lock is held. uint64_t metadata_system_bytes(); // size/depth are made the same size as a pointer so that some generic // code below can conveniently cast them back and forth to void*. static const int kMaxStackDepth = 31; struct StackTrace { uintptr_t size; // Size of object uintptr_t depth; // Number of PC values stored in array below void* stack[kMaxStackDepth]; }; } // namespace tcmalloc #endif // TCMALLOC_COMMON_H_ ================================================ FILE: distro/google-perftools-1.7/src/config.h.in ================================================ /* src/config.h.in. Generated from configure.ac by autoheader. */ #ifndef GOOGLE_PERFTOOLS_CONFIG_H_ #define GOOGLE_PERFTOOLS_CONFIG_H_ /* Define to 1 if compiler supports __builtin_stack_pointer */ #undef HAVE_BUILTIN_STACK_POINTER /* Define to 1 if you have the header file. */ #undef HAVE_CONFLICT_SIGNAL_H /* Define to 1 if you have the header file. */ #undef HAVE_CYGWIN_SIGNAL_H /* Define to 1 if you have the declaration of `cfree', and to 0 if you don't. */ #undef HAVE_DECL_CFREE /* Define to 1 if you have the declaration of `memalign', and to 0 if you don't. */ #undef HAVE_DECL_MEMALIGN /* Define to 1 if you have the declaration of `posix_memalign', and to 0 if you don't. */ #undef HAVE_DECL_POSIX_MEMALIGN /* Define to 1 if you have the declaration of `pvalloc', and to 0 if you don't. */ #undef HAVE_DECL_PVALLOC /* Define to 1 if you have the declaration of `uname', and to 0 if you don't. */ #undef HAVE_DECL_UNAME /* Define to 1 if you have the declaration of `valloc', and to 0 if you don't. */ #undef HAVE_DECL_VALLOC /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if the system has the type `Elf32_Versym'. */ #undef HAVE_ELF32_VERSYM /* Define to 1 if you have the header file. */ #undef HAVE_EXECINFO_H /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the header file. */ #undef HAVE_FEATURES_H /* Define to 1 if you have the `geteuid' function. */ #undef HAVE_GETEUID /* Define to 1 if you have the `getpagesize' function. */ #undef HAVE_GETPAGESIZE /* Define to 1 if you have the header file. */ #undef HAVE_GLOB_H /* Define to 1 if you have the header file. */ #undef HAVE_GRP_H /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_LIBUNWIND_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_PTRACE_H /* Define to 1 if you have the header file. */ #undef HAVE_MALLOC_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have a working `mmap' system call. */ #undef HAVE_MMAP /* define if the compiler implements namespaces */ #undef HAVE_NAMESPACES /* Define to 1 if you have the header file. */ #undef HAVE_POLL_H /* define if libc has program_invocation_name */ #undef HAVE_PROGRAM_INVOCATION_NAME /* Define if you have POSIX threads libraries and header files. */ #undef HAVE_PTHREAD /* Define to 1 if you have the header file. */ #undef HAVE_PWD_H /* Define to 1 if you have the `sbrk' function. */ #undef HAVE_SBRK /* Define to 1 if you have the header file. */ #undef HAVE_SCHED_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if the system has the type `struct mallinfo'. */ #undef HAVE_STRUCT_MALLINFO /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PRCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_RESOURCE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SYSCALL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* is broken on redhat 7 */ #undef HAVE_SYS_UCONTEXT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_WAIT_H /* Define to 1 if compiler supports __thread */ #undef HAVE_TLS /* Define to 1 if you have the header file. */ #undef HAVE_UCONTEXT_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the header file. */ #undef HAVE_UNWIND_H /* Define to 1 if you have the header file. */ #undef HAVE_VALGRIND_H /* define if your compiler has __attribute__ */ #undef HAVE___ATTRIBUTE__ /* Define to 1 if compiler supports __environ */ #undef HAVE___ENVIRON /* Define to 1 if the system has the type `__int64'. */ #undef HAVE___INT64 /* prefix where we look for installed files */ #undef INSTALL_PREFIX /* Define to 1 if int32_t is equivalent to intptr_t */ #undef INT32_EQUALS_INTPTR /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Define to 1 if your C compiler doesn't accept -c and -o together. */ #undef NO_MINUS_C_MINUS_O /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* How to access the PC from a struct ucontext */ #undef PC_FROM_UCONTEXT /* Always the empty-string on non-windows systems. On windows, should be "__declspec(dllexport)". This way, when we compile the dll, we export our functions/classes. It's safe to define this here because config.h is only used internally, to compile the DLL, and every DLL source file #includes "config.h" before anything else. */ #undef PERFTOOLS_DLL_DECL /* printf format code for printing a size_t and ssize_t */ #undef PRIdS /* printf format code for printing a size_t and ssize_t */ #undef PRIuS /* printf format code for printing a size_t and ssize_t */ #undef PRIxS /* Define to necessary symbol if this constant uses a non-standard name on your system. */ #undef PTHREAD_CREATE_JOINABLE /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* the namespace where STL code like vector<> is defined */ #undef STL_NAMESPACE /* Version number of package */ #undef VERSION /* C99 says: define this to get the PRI... macros from stdint.h */ #ifndef __STDC_FORMAT_MACROS # define __STDC_FORMAT_MACROS 1 #endif /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif #ifdef __MINGW32__ #include "windows/mingw.h" #endif #endif /* #ifndef GOOGLE_PERFTOOLS_CONFIG_H_ */ ================================================ FILE: distro/google-perftools-1.7/src/config_for_unittests.h ================================================ // Copyright (c) 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // All Rights Reserved. // // Author: Craig Silverstein // // This file is needed for windows -- unittests are not part of the // perftools dll, but still want to include config.h just like the // dll does, so they can use internal tools and APIs for testing. // // The problem is that config.h declares PERFTOOLS_DLL_DECL to be // for exporting symbols, but the unittest needs to *import* symbols // (since it's not the dll). // // The solution is to have this file, which is just like config.h but // sets PERFTOOLS_DLL_DECL to do a dllimport instead of a dllexport. // // The reason we need this extra PERFTOOLS_DLL_DECL_FOR_UNITTESTS // variable is in case people want to set PERFTOOLS_DLL_DECL explicitly // to something other than __declspec(dllexport). In that case, they // may want to use something other than __declspec(dllimport) for the // unittest case. For that, we allow folks to define both // PERFTOOLS_DLL_DECL and PERFTOOLS_DLL_DECL_FOR_UNITTESTS explicitly. // // NOTE: This file is equivalent to config.h on non-windows systems, // which never defined PERFTOOLS_DLL_DECL_FOR_UNITTESTS and always // define PERFTOOLS_DLL_DECL to the empty string. #include "config.h" #undef PERFTOOLS_DLL_DECL #ifdef PERFTOOLS_DLL_DECL_FOR_UNITTESTS # define PERFTOOLS_DLL_DECL PERFTOOLS_DLL_DECL_FOR_UNITTESTS #else # define PERFTOOLS_DLL_DECL // if DLL_DECL_FOR_UNITTESTS isn't defined, use "" #endif ================================================ FILE: distro/google-perftools-1.7/src/debugallocation.cc ================================================ // Copyright (c) 2000, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Urs Holzle #include "config.h" #ifdef HAVE_MALLOC_H #include #endif #include #include #ifdef HAVE_INTTYPES_H #include #endif #include #ifdef HAVE_MMAP #include #endif #include #include #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #include #include #include "base/commandlineflags.h" #include "base/googleinit.h" #include "base/logging.h" #include "google/malloc_extension.h" #include "google/malloc_hook.h" #include "google/stacktrace.h" #include "addressmap-inl.h" #include "malloc_hook-inl.h" #include "symbolize.h" #ifdef TCMALLOC_FOR_DEBUGALLOCATION #include "tcmalloc.cc" #else #include "base/spinlock.h" // Else we already have a SpinLock defined in tcmalloc/internal_spinlock.h #endif // __THROW is defined in glibc systems. It means, counter-intuitively, // "This function will never throw an exception." It's an optional // optimization tool, but we may need to use it to match glibc prototypes. #ifndef __THROW // I guess we're not on a glibc system # define __THROW // __THROW is just an optimization, so ok to make it "" #endif // On systems (like freebsd) that don't define MAP_ANONYMOUS, use the old // form of the name instead. #ifndef MAP_ANONYMOUS # define MAP_ANONYMOUS MAP_ANON #endif // ========================================================================= // DEFINE_bool(malloctrace, EnvToBool("TCMALLOC_TRACE", false), "Enables memory (de)allocation tracing to /tmp/google.alloc."); #ifdef HAVE_MMAP DEFINE_bool(malloc_page_fence, EnvToBool("TCMALLOC_PAGE_FENCE", false), "Enables putting of memory allocations at page boundaries " "with a guard page following the allocation (to catch buffer " "overruns right when they happen)."); DEFINE_bool(malloc_page_fence_never_reclaim, EnvToBool("TCMALLOC_PAGE_FRANCE_NEVER_RECLAIM", false), "Enables making the virtual address space inaccessible " "upon a deallocation instead of returning it and reusing later."); #else DEFINE_bool(malloc_page_fence, false, "Not usable (requires mmap)"); DEFINE_bool(malloc_page_fence_never_reclaim, false, "Not usable (required mmap)"); #endif DEFINE_bool(malloc_reclaim_memory, EnvToBool("TCMALLOC_RECLAIM_MEMORY", true), "If set to false, we never return memory to malloc " "when an object is deallocated. This ensures that all " "heap object addresses are unique."); DEFINE_int32(max_free_queue_size, EnvToInt("TCMALLOC_MAX_FREE_QUEUE_SIZE", 10*1024*1024), "If greater than 0, keep freed blocks in a queue instead of " "releasing them to the allocator immediately. Release them when " "the total size of all blocks in the queue would otherwise exceed " "this limit."); DEFINE_bool(symbolize_stacktrace, EnvToBool("TCMALLOC_SYMBOLIZE_STACKTRACE", true), "Symbolize the stack trace when provided (on some error exits)"); // ========================================================================= // // A safe version of printf() that does not do any allocation and // uses very little stack space. static void TracePrintf(int fd, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); // // GNU has some weird "weak aliasing" thing that permits us to define our // own malloc(), free(), and realloc() which can use the normal versions of // of themselves by calling __libc_malloc(), __libc_free(), and // __libc_realloc(). // extern "C" { extern void* __libc_malloc(size_t size); extern void __libc_free(void* ptr); extern void* __libc_realloc(void* ptr, size_t size); extern void* __libc_calloc(size_t nmemb, size_t size); extern int __libc_mallopt(int cmd, int value); #ifdef HAVE_STRUCT_MALLINFO extern struct mallinfo __libc_mallinfo(void); #endif } // Define the malloc/free/mallopt/mallinfo implementations // we will be working on top of. // TODO(csilvers): provide debugallocation on top of libc alloc, // so this #ifdef might sometimes be false. #ifdef TCMALLOC_FOR_DEBUGALLOCATION // The do_* functions are defined in tcmalloc.cc, // which is included before this file // when TCMALLOC_FOR_DEBUGALLOCATION is defined. #define BASE_MALLOC_NEW(size) cpp_alloc(size, false) #define BASE_MALLOC do_malloc_or_cpp_alloc #define BASE_FREE do_free #define BASE_MALLOPT do_mallopt #define BASE_MALLINFO do_mallinfo #else // We are working on top of standard libc's malloc library #define BASE_MALLOC_NEW __libc_malloc #define BASE_MALLOC __libc_malloc #define BASE_FREE __libc_free #define BASE_MALLOPT __libc_mallopt #define BASE_MALLINFO __libc_mallinfo #endif // ========================================================================= // class MallocBlock; // A circular buffer to hold freed blocks of memory. MallocBlock::Deallocate // (below) pushes blocks into this queue instead of returning them to the // underlying allocator immediately. See MallocBlock::Deallocate for more // information. // // We can't use an STL class for this because we need to be careful not to // perform any heap de-allocations in any of the code in this class, since the // code in MallocBlock::Deallocate is not re-entrant. template class FreeQueue { public: FreeQueue() : q_front_(0), q_back_(0) {} bool Full() { return (q_front_ + 1) % kFreeQueueSize == q_back_; } void Push(QueueEntry block) { q_[q_front_] = block; q_front_ = (q_front_ + 1) % kFreeQueueSize; } QueueEntry Pop() { const QueueEntry& ret = q_[q_back_]; q_back_ = (q_back_ + 1) % kFreeQueueSize; return ret; } size_t size() const { return (q_front_ - q_back_ + kFreeQueueSize) % kFreeQueueSize; } private: // Maximum number of blocks kept in the free queue before being freed. static const int kFreeQueueSize = 1024; QueueEntry q_[kFreeQueueSize]; int q_front_; int q_back_; }; struct MallocBlockQueueEntry { MallocBlockQueueEntry() : block(NULL), size(0), num_deleter_pcs(0), deleter_threadid(0) {} MallocBlockQueueEntry(MallocBlock* b, size_t s) : block(b), size(s) { if (FLAGS_max_free_queue_size != 0) { // Adjust the number of frames to skip (4) if you change the // location of this call. num_deleter_pcs = GetStackTrace(deleter_pcs, sizeof(deleter_pcs) / sizeof(deleter_pcs[0]), 4); deleter_threadid = pthread_self(); } else { num_deleter_pcs = 0; // Zero is an illegal pthread id by my reading of the pthread // implementation: deleter_threadid = 0; } } MallocBlock* block; size_t size; // When deleted and put in the free queue, we (flag-controlled) // record the stack so that if corruption is later found, we can // print the deleter's stack. (These three vars add 144 bytes of // overhead under the LP64 data model.) void* deleter_pcs[16]; int num_deleter_pcs; pthread_t deleter_threadid; }; class MallocBlock { public: // allocation type constants // Different allocation types we distinguish. // Note: The lower 4 bits are not random: we index kAllocName array // by these values masked with kAllocTypeMask; // the rest are "random" magic bits to help catch memory corruption. static const int kMallocType = 0xEFCDAB90; static const int kNewType = 0xFEBADC81; static const int kArrayNewType = 0xBCEADF72; private: // constants // A mask used on alloc types above to get to 0, 1, 2 static const int kAllocTypeMask = 0x3; // An additional bit to set in AllocType constants // to mark now deallocated regions. static const int kDeallocatedTypeBit = 0x4; // For better memory debugging, we initialize all storage to known // values, and overwrite the storage when it's deallocated: // Byte that fills uninitialized storage. static const int kMagicUninitializedByte = 0xAB; // Byte that fills deallocated storage. // NOTE: tcmalloc.cc depends on the value of kMagicDeletedByte // to work around a bug in the pthread library. static const int kMagicDeletedByte = 0xCD; // A size_t (type of alloc_type_ below) in a deallocated storage // filled with kMagicDeletedByte. static const size_t kMagicDeletedSizeT = 0xCDCDCDCD | (((size_t)0xCDCDCDCD << 16) << 16); // Initializer works for 32 and 64 bit size_ts; // "<< 16 << 16" is to fool gcc from issuing a warning // when size_ts are 32 bits. // NOTE: on Linux, you can enable malloc debugging support in libc by // setting the environment variable MALLOC_CHECK_ to 1 before you // start the program (see man malloc). // We use either BASE_MALLOC or mmap to make the actual allocation. In // order to remember which one of the two was used for any block, we store an // appropriate magic word next to the block. static const int kMagicMalloc = 0xDEADBEEF; static const int kMagicMMap = 0xABCDEFAB; // This array will be filled with 0xCD, for use with memcmp. static unsigned char kMagicDeletedBuffer[1024]; static bool deleted_buffer_initialized_; private: // data layout // The four fields size1_,offset_,magic1_,alloc_type_ // should together occupy a multiple of 16 bytes. (At the // moment, sizeof(size_t) == 4 or 8 depending on piii vs // k8, and 4 of those sum to 16 or 32 bytes). // This, combined with BASE_MALLOC's alignment guarantees, // ensures that SSE types can be stored into the returned // block, at &size2_. size_t size1_; size_t offset_; // normally 0 unless memaligned memory // see comments in memalign() and FromRawPointer(). size_t magic1_; size_t alloc_type_; // here comes the actual data (variable length) // ... // then come the size2_ and magic2_, or a full page of mprotect-ed memory // if the malloc_page_fence feature is enabled. size_t size2_; int magic2_; private: // static data and helpers // Allocation map: stores the allocation type for each allocated object, // or the type or'ed with kDeallocatedTypeBit // for each formerly allocated object. typedef AddressMap AllocMap; static AllocMap* alloc_map_; // This protects alloc_map_ and consistent state of metadata // for each still-allocated object in it. // We use spin locks instead of pthread_mutex_t locks // to prevent crashes via calls to pthread_mutex_(un)lock // for the (de)allocations coming from pthreads initialization itself. static SpinLock alloc_map_lock_; // A queue of freed blocks. Instead of releasing blocks to the allocator // immediately, we put them in a queue, freeing them only when necessary // to keep the total size of all the freed blocks below the limit set by // FLAGS_max_free_queue_size. static FreeQueue* free_queue_; static size_t free_queue_size_; // total size of blocks in free_queue_ // protects free_queue_ and free_queue_size_ static SpinLock free_queue_lock_; // Names of allocation types (kMallocType, kNewType, kArrayNewType) static const char* const kAllocName[]; // Names of corresponding deallocation types static const char* const kDeallocName[]; static const char* AllocName(int type) { return kAllocName[type & kAllocTypeMask]; } static const char* DeallocName(int type) { return kDeallocName[type & kAllocTypeMask]; } private: // helper accessors bool IsMMapped() const { return kMagicMMap == magic1_; } bool IsValidMagicValue(int value) const { return kMagicMMap == value || kMagicMalloc == value; } static size_t real_malloced_size(size_t size) { return size + sizeof(MallocBlock); } static size_t real_mmapped_size(size_t size) { return size + MallocBlock::data_offset(); } size_t real_size() { return IsMMapped() ? real_mmapped_size(size1_) : real_malloced_size(size1_); } // NOTE: if the block is mmapped (that is, we're using the // malloc_page_fence option) then there's no size2 or magic2 // (instead, the guard page begins where size2 would be). size_t* size2_addr() { return (size_t*)((char*)&size2_ + size1_); } const size_t* size2_addr() const { return (const size_t*)((char*)&size2_ + size1_); } int* magic2_addr() { return (int*)(size2_addr() + 1); } const int* magic2_addr() const { return (const int*)(size2_addr() + 1); } private: // other helpers void Initialize(size_t size, int type) { RAW_CHECK(IsValidMagicValue(magic1_), ""); // record us as allocated in the map alloc_map_lock_.Lock(); if (!alloc_map_) { void* p = BASE_MALLOC(sizeof(AllocMap)); alloc_map_ = new(p) AllocMap(BASE_MALLOC, BASE_FREE); } alloc_map_->Insert(data_addr(), type); // initialize us size1_ = size; offset_ = 0; alloc_type_ = type; if (!IsMMapped()) { *magic2_addr() = magic1_; *size2_addr() = size; } alloc_map_lock_.Unlock(); memset(data_addr(), kMagicUninitializedByte, size); if (!IsMMapped()) { RAW_CHECK(size1_ == *size2_addr(), "should hold"); RAW_CHECK(magic1_ == *magic2_addr(), "should hold"); } } size_t CheckAndClear(int type) { alloc_map_lock_.Lock(); CheckLocked(type); if (!IsMMapped()) { RAW_CHECK(size1_ == *size2_addr(), "should hold"); } // record us as deallocated in the map alloc_map_->Insert(data_addr(), type | kDeallocatedTypeBit); alloc_map_lock_.Unlock(); // clear us const size_t size = real_size(); memset(this, kMagicDeletedByte, size); return size; } void CheckLocked(int type) const { int map_type = 0; const int* found_type = alloc_map_ != NULL ? alloc_map_->Find(data_addr()) : NULL; if (found_type == NULL) { RAW_LOG(FATAL, "memory allocation bug: object at %p " "has never been allocated", data_addr()); } else { map_type = *found_type; } if ((map_type & kDeallocatedTypeBit) != 0) { RAW_LOG(FATAL, "memory allocation bug: object at %p " "has been already deallocated (it was allocated with %s)", data_addr(), AllocName(map_type & ~kDeallocatedTypeBit)); } if (alloc_type_ == kMagicDeletedSizeT) { RAW_LOG(FATAL, "memory stomping bug: a word before object at %p " "has been corrupted; or else the object has been already " "deallocated and our memory map has been corrupted", data_addr()); } if (!IsValidMagicValue(magic1_)) { RAW_LOG(FATAL, "memory stomping bug: a word before object at %p " "has been corrupted; " "or else our memory map has been corrupted and this is a " "deallocation for not (currently) heap-allocated object", data_addr()); } if (!IsMMapped()) { if (size1_ != *size2_addr()) { RAW_LOG(FATAL, "memory stomping bug: a word after object at %p " "has been corrupted", data_addr()); } if (!IsValidMagicValue(*magic2_addr())) { RAW_LOG(FATAL, "memory stomping bug: a word after object at %p " "has been corrupted", data_addr()); } } if (alloc_type_ != type) { if ((alloc_type_ != MallocBlock::kMallocType) && (alloc_type_ != MallocBlock::kNewType) && (alloc_type_ != MallocBlock::kArrayNewType)) { RAW_LOG(FATAL, "memory stomping bug: a word before object at %p " "has been corrupted", data_addr()); } RAW_LOG(FATAL, "memory allocation/deallocation mismatch at %p: " "allocated with %s being deallocated with %s", data_addr(), AllocName(alloc_type_), DeallocName(type)); } if (alloc_type_ != map_type) { RAW_LOG(FATAL, "memory stomping bug: our memory map has been corrupted : " "allocation at %p made with %s " "is recorded in the map to be made with %s", data_addr(), AllocName(alloc_type_), AllocName(map_type)); } } public: // public accessors void* data_addr() { return (void*)&size2_; } const void* data_addr() const { return (const void*)&size2_; } static size_t data_offset() { return OFFSETOF_MEMBER(MallocBlock, size2_); } size_t data_size() const { return size1_; } void set_offset(int offset) { this->offset_ = offset; } public: // our main interface static MallocBlock* Allocate(size_t size, int type) { // Prevent an integer overflow / crash with large allocation sizes. // TODO - Note that for a e.g. 64-bit size_t, max_size_t may not actually // be the maximum value, depending on how the compiler treats ~0. The worst // practical effect is that allocations are limited to 4Gb or so, even if // the address space could take more. static size_t max_size_t = ~0; if (size > max_size_t - sizeof(MallocBlock)) { RAW_LOG(ERROR, "Massive size passed to malloc: %"PRIuS"", size); return NULL; } MallocBlock* b = NULL; const bool use_malloc_page_fence = FLAGS_malloc_page_fence; #ifdef HAVE_MMAP if (use_malloc_page_fence) { // Put the block towards the end of the page and make the next page // inaccessible. This will catch buffer overrun right when it happens. size_t sz = real_mmapped_size(size); int pagesize = getpagesize(); int num_pages = (sz + pagesize - 1) / pagesize + 1; char* p = (char*) mmap(NULL, num_pages * pagesize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if (p == MAP_FAILED) { // If the allocation fails, abort rather than returning NULL to // malloc. This is because in most cases, the program will run out // of memory in this mode due to tremendous amount of wastage. There // is no point in propagating the error elsewhere. RAW_LOG(FATAL, "Out of memory: possibly due to page fence overhead: %s", strerror(errno)); } // Mark the page after the block inaccessible if (mprotect(p + (num_pages - 1) * pagesize, pagesize, PROT_NONE)) { RAW_LOG(FATAL, "Guard page setup failed: %s", strerror(errno)); } b = (MallocBlock*) (p + (num_pages - 1) * pagesize - sz); } else { b = (MallocBlock*) (type == kMallocType ? BASE_MALLOC(real_malloced_size(size)) : BASE_MALLOC_NEW(real_malloced_size(size))); } #else b = (MallocBlock*) (type == kMallocType ? BASE_MALLOC(real_malloced_size(size)) : BASE_MALLOC_NEW(real_malloced_size(size))); #endif // It would be nice to output a diagnostic on allocation failure // here, but logging (other than FATAL) requires allocating // memory, which could trigger a nasty recursion. Instead, preserve // malloc semantics and return NULL on failure. if (b != NULL) { b->magic1_ = use_malloc_page_fence ? kMagicMMap : kMagicMalloc; b->Initialize(size, type); } return b; } void Deallocate(int type) { if (IsMMapped()) { // have to do this before CheckAndClear #ifdef HAVE_MMAP int size = CheckAndClear(type); int pagesize = getpagesize(); int num_pages = (size + pagesize - 1) / pagesize + 1; char* p = (char*) this; if (FLAGS_malloc_page_fence_never_reclaim || !FLAGS_malloc_reclaim_memory) { mprotect(p - (num_pages - 1) * pagesize + size, num_pages * pagesize, PROT_NONE); } else { munmap(p - (num_pages - 1) * pagesize + size, num_pages * pagesize); } #endif } else { const size_t size = CheckAndClear(type); if (FLAGS_malloc_reclaim_memory) { // Instead of freeing the block immediately, push it onto a queue of // recently freed blocks. Free only enough blocks to keep from // exceeding the capacity of the queue or causing the total amount of // un-released memory in the queue from exceeding // FLAGS_max_free_queue_size. ProcessFreeQueue(this, size, FLAGS_max_free_queue_size); } } } static size_t FreeQueueSize() { SpinLockHolder l(&free_queue_lock_); return free_queue_size_; } static void ProcessFreeQueue(MallocBlock* b, size_t size, int max_free_queue_size) { SpinLockHolder l(&free_queue_lock_); if (free_queue_ == NULL) free_queue_ = new FreeQueue; RAW_CHECK(!free_queue_->Full(), "Free queue mustn't be full!"); if (b != NULL) { free_queue_size_ += size + sizeof(MallocBlockQueueEntry); MallocBlockQueueEntry new_entry(b, size); free_queue_->Push(new_entry); } // Free blocks until the total size of unfreed blocks no longer exceeds // max_free_queue_size, and the free queue has at least one free // space in it. while (free_queue_size_ > max_free_queue_size || free_queue_->Full()) { MallocBlockQueueEntry cur = free_queue_->Pop(); CheckForDanglingWrites(cur); free_queue_size_ -= cur.size + sizeof(MallocBlockQueueEntry); BASE_FREE(cur.block); } RAW_CHECK(free_queue_size_ >= 0, "Free queue size went negative!"); } static void CheckForDanglingWrites(const MallocBlockQueueEntry& queue_entry) { // Initialize the buffer if necessary. if (!deleted_buffer_initialized_) { // This is threadsafe. We hold free_queue_lock_. memset(kMagicDeletedBuffer, 0xcd, sizeof(kMagicDeletedBuffer)); deleted_buffer_initialized_ = true; } const unsigned char* p = reinterpret_cast(queue_entry.block); static const size_t size_of_buffer = sizeof(kMagicDeletedBuffer); const size_t size = queue_entry.size; const size_t buffers = size / size_of_buffer; const size_t remainder = size % size_of_buffer; size_t buffer_idx; for (buffer_idx = 0; buffer_idx < buffers; ++buffer_idx) { CheckForCorruptedBuffer(queue_entry, buffer_idx, p, size_of_buffer); p += size_of_buffer; } CheckForCorruptedBuffer(queue_entry, buffer_idx, p, remainder); } static void CheckForCorruptedBuffer(const MallocBlockQueueEntry& queue_entry, size_t buffer_idx, const unsigned char* buffer, size_t size_of_buffer) { if (memcmp(buffer, kMagicDeletedBuffer, size_of_buffer) == 0) { return; } RAW_LOG(ERROR, "Found a corrupted memory buffer in MallocBlock (may be offset " "from user ptr): buffer index: %zd, buffer ptr: %p, size of " "buffer: %zd", buffer_idx, buffer, size_of_buffer); // The magic deleted buffer should only be 1024 bytes, but in case // this changes, let's put an upper limit on the number of debug // lines we'll output: if (size_of_buffer <= 1024) { for (int i = 0; i < size_of_buffer; ++i) { if (buffer[i] != 0xcd) { RAW_LOG(ERROR, "Buffer byte %d is 0x%02x (should be 0xcd).", i, buffer[i]); } } } else { RAW_LOG(ERROR, "Buffer too large to print corruption."); } const MallocBlock* b = queue_entry.block; const size_t size = queue_entry.size; if (queue_entry.num_deleter_pcs > 0) { TracePrintf(STDERR_FILENO, "Deleted by thread %p\n", reinterpret_cast( PRINTABLE_PTHREAD(queue_entry.deleter_threadid))); // We don't want to allocate or deallocate memory here, so we use // placement-new. It's ok that we don't destroy this, since we're // just going to error-exit below anyway. Union is for alignment. union { void* alignment; char buf[sizeof(SymbolTable)]; } tablebuf; SymbolTable* symbolization_table = new (tablebuf.buf) SymbolTable; for (int i = 0; i < queue_entry.num_deleter_pcs; i++) { // Symbolizes the previous address of pc because pc may be in the // next function. This may happen when the function ends with // a call to a function annotated noreturn (e.g. CHECK). char *pc = reinterpret_cast(queue_entry.deleter_pcs[i]); symbolization_table->Add(pc - 1); } if (FLAGS_symbolize_stacktrace) symbolization_table->Symbolize(); for (int i = 0; i < queue_entry.num_deleter_pcs; i++) { char *pc = reinterpret_cast(queue_entry.deleter_pcs[i]); TracePrintf(STDERR_FILENO, " @ %p %s\n", pc, symbolization_table->GetSymbol(pc - 1)); } } else { RAW_LOG(ERROR, "Skipping the printing of the deleter's stack! Its stack was " "not found; either the corruption occurred too early in " "execution to obtain a stack trace or --max_free_queue_size was " "set to 0."); } RAW_LOG(FATAL, "Memory was written to after being freed. MallocBlock: %p, user " "ptr: %p, size: %zd. If you can't find the source of the error, " "try using valgrind or purify, or study the output of the " "deleter's stack printed above.", b, b->data_addr(), size); } static MallocBlock* FromRawPointer(void* p) { const size_t data_offset = MallocBlock::data_offset(); // Find the header just before client's memory. MallocBlock *mb = reinterpret_cast( reinterpret_cast(p) - data_offset); // If mb->alloc_type_ is kMagicDeletedSizeT, we're not an ok pointer. if (mb->alloc_type_ == kMagicDeletedSizeT) { RAW_LOG(FATAL, "memory allocation bug: object at %p has been already" " deallocated; or else a word before the object has been" " corrupted (memory stomping bug)", p); } // If mb->offset_ is zero (common case), mb is the real header. If // mb->offset_ is non-zero, this block was allocated by memalign, and // mb->offset_ is the distance backwards to the real header from mb, // which is a fake header. The following subtraction works for both zero // and non-zero values. return reinterpret_cast( reinterpret_cast(mb) - mb->offset_); } static const MallocBlock* FromRawPointer(const void* p) { // const-safe version: we just cast about return FromRawPointer(const_cast(p)); } void Check(int type) { alloc_map_lock_.Lock(); CheckLocked(type); alloc_map_lock_.Unlock(); } static bool CheckEverything() { alloc_map_lock_.Lock(); if (alloc_map_ != NULL) alloc_map_->Iterate(CheckCallback, 0); alloc_map_lock_.Unlock(); return true; // if we get here, we're okay } static bool MemoryStats(int* blocks, size_t* total, int histogram[kMallocHistogramSize]) { memset(histogram, 0, kMallocHistogramSize * sizeof(int)); alloc_map_lock_.Lock(); stats_blocks_ = 0; stats_total_ = 0; stats_histogram_ = histogram; if (alloc_map_ != NULL) alloc_map_->Iterate(StatsCallback, 0); *blocks = stats_blocks_; *total = stats_total_; alloc_map_lock_.Unlock(); return true; } private: // helpers for CheckEverything and MemoryStats static void CheckCallback(const void* ptr, int* type, int dummy) { if ((*type & kDeallocatedTypeBit) == 0) { FromRawPointer(ptr)->CheckLocked(*type); } } // Accumulation variables for StatsCallback protected by alloc_map_lock_ static int stats_blocks_; static size_t stats_total_; static int* stats_histogram_; static void StatsCallback(const void* ptr, int* type, int dummy) { if ((*type & kDeallocatedTypeBit) == 0) { const MallocBlock* b = FromRawPointer(ptr); b->CheckLocked(*type); ++stats_blocks_; size_t mysize = b->size1_; int entry = 0; stats_total_ += mysize; while (mysize) { ++entry; mysize >>= 1; } RAW_CHECK(entry < kMallocHistogramSize, "kMallocHistogramSize should be at least as large as log2 " "of the maximum process memory size"); stats_histogram_[entry] += 1; } } }; void DanglingWriteChecker() { // Clear out the remaining free queue to check for dangling writes. MallocBlock::ProcessFreeQueue(NULL, 0, 0); } // ========================================================================= // const int MallocBlock::kMagicMalloc; const int MallocBlock::kMagicMMap; MallocBlock::AllocMap* MallocBlock::alloc_map_ = NULL; SpinLock MallocBlock::alloc_map_lock_(SpinLock::LINKER_INITIALIZED); FreeQueue* MallocBlock::free_queue_ = NULL; size_t MallocBlock::free_queue_size_ = 0; SpinLock MallocBlock::free_queue_lock_(SpinLock::LINKER_INITIALIZED); unsigned char MallocBlock::kMagicDeletedBuffer[1024]; bool MallocBlock::deleted_buffer_initialized_ = false; const char* const MallocBlock::kAllocName[] = { "malloc", "new", "new []", NULL, }; const char* const MallocBlock::kDeallocName[] = { "free", "delete", "delete []", NULL, }; int MallocBlock::stats_blocks_; size_t MallocBlock::stats_total_; int* MallocBlock::stats_histogram_; // ========================================================================= // // The following cut-down version of printf() avoids // using stdio or ostreams. // This is to guarantee no recursive calls into // the allocator and to bound the stack space consumed. (The pthread // manager thread in linuxthreads has a very small stack, // so fprintf can't be called.) static void TracePrintf(int fd, const char *fmt, ...) { char buf[64]; int i = 0; va_list ap; va_start(ap, fmt); const char *p = fmt; char numbuf[25]; numbuf[sizeof(numbuf)-1] = 0; while (*p != '\0') { // until end of format string char *s = &numbuf[sizeof(numbuf)-1]; if (p[0] == '%' && p[1] != 0) { // handle % formats int64 l = 0; unsigned long base = 0; if (*++p == 's') { // %s s = va_arg(ap, char *); } else if (*p == 'l' && p[1] == 'd') { // %ld l = va_arg(ap, long); base = 10; p++; } else if (*p == 'l' && p[1] == 'u') { // %lu l = va_arg(ap, unsigned long); base = 10; p++; } else if (*p == 'z' && p[1] == 'u') { // %zu l = va_arg(ap, size_t); base = 10; p++; } else if (*p == 'u') { // %u l = va_arg(ap, unsigned int); base = 10; } else if (*p == 'd') { // %d l = va_arg(ap, int); base = 10; } else if (*p == 'p') { // %p l = va_arg(ap, intptr_t); base = 16; } else { write(STDERR_FILENO, "Unimplemented TracePrintf format\n", 33); write(STDERR_FILENO, p, 2); write(STDERR_FILENO, "\n", 1); abort(); } p++; if (base != 0) { bool minus = (l < 0 && base == 10); uint64 ul = minus? -l : l; do { *--s = "0123456789abcdef"[ul % base]; ul /= base; } while (ul != 0); if (base == 16) { *--s = 'x'; *--s = '0'; } else if (minus) { *--s = '-'; } } } else { // handle normal characters *--s = *p++; } while (*s != 0) { if (i == sizeof(buf)) { write(fd, buf, i); i = 0; } buf[i++] = *s++; } } if (i != 0) { write(fd, buf, i); } va_end(ap); } // Return the file descriptor we're writing a log to static int TraceFd() { static int trace_fd = -1; if (trace_fd == -1) { // Open the trace file on the first call trace_fd = open("/tmp/google.alloc", O_CREAT|O_TRUNC|O_WRONLY, 0666); if (trace_fd == -1) { trace_fd = 2; TracePrintf(trace_fd, "Can't open /tmp/google.alloc. Logging to stderr.\n"); } // Add a header to the log. TracePrintf(trace_fd, "Trace started: %lu\n", static_cast(time(NULL))); TracePrintf(trace_fd, "func\tsize\tptr\tthread_id\tstack pcs for tools/symbolize\n"); } return trace_fd; } // Print the hex stack dump on a single line. PCs are separated by tabs. static void TraceStack(void) { void *pcs[16]; int n = GetStackTrace(pcs, sizeof(pcs)/sizeof(pcs[0]), 0); for (int i = 0; i != n; i++) { TracePrintf(TraceFd(), "\t%p", pcs[i]); } } // This protects MALLOC_TRACE, to make sure its info is atomically written. static SpinLock malloc_trace_lock(SpinLock::LINKER_INITIALIZED); #define MALLOC_TRACE(name, size, addr) \ do { \ if (FLAGS_malloctrace) { \ SpinLockHolder l(&malloc_trace_lock); \ TracePrintf(TraceFd(), "%s\t%"PRIuS"\t%p\t%"GPRIuPTHREAD, \ name, size, addr, PRINTABLE_PTHREAD(pthread_self())); \ TraceStack(); \ TracePrintf(TraceFd(), "\n"); \ } \ } while (0) // ========================================================================= // // Write the characters buf[0, ..., size-1] to // the malloc trace buffer. // This function is intended for debugging, // and is not declared in any header file. // You must insert a declaration of it by hand when you need // to use it. void __malloctrace_write(const char *buf, size_t size) { if (FLAGS_malloctrace) { write(TraceFd(), buf, size); } } // ========================================================================= // // General debug allocation/deallocation static inline void* DebugAllocate(size_t size, int type) { MallocBlock* ptr = MallocBlock::Allocate(size, type); if (ptr == NULL) return NULL; MALLOC_TRACE("malloc", size, ptr->data_addr()); return ptr->data_addr(); } static inline void DebugDeallocate(void* ptr, int type) { MALLOC_TRACE("free", (ptr != 0 ? MallocBlock::FromRawPointer(ptr)->data_size() : 0), ptr); if (ptr) MallocBlock::FromRawPointer(ptr)->Deallocate(type); } // ========================================================================= // // Alloc/free stuff for debug hooks for malloc & friends // CAVEAT: The code structure below ensures that MallocHook methods are always // called from the stack frame of the invoked allocation function. // heap-checker.cc depends on this to start a stack trace from // the call to the (de)allocation function. // Put all callers of MallocHook::Invoke* in this module into // ATTRIBUTE_SECTION(google_malloc) section, // so that MallocHook::GetCallerStackTrace can function accurately: extern "C" { void* malloc(size_t size) __THROW ATTRIBUTE_SECTION(google_malloc); void free(void* ptr) __THROW ATTRIBUTE_SECTION(google_malloc); void* realloc(void* ptr, size_t size) __THROW ATTRIBUTE_SECTION(google_malloc); void* calloc(size_t nmemb, size_t size) __THROW ATTRIBUTE_SECTION(google_malloc); void cfree(void* ptr) __THROW ATTRIBUTE_SECTION(google_malloc); void* memalign(size_t __alignment, size_t __size) __THROW ATTRIBUTE_SECTION(google_malloc); int posix_memalign(void** ptr, size_t align, size_t size) __THROW ATTRIBUTE_SECTION(google_malloc); void* valloc(size_t __size) __THROW ATTRIBUTE_SECTION(google_malloc); void* pvalloc(size_t __size) __THROW ATTRIBUTE_SECTION(google_malloc); } static void *MemalignOverride(size_t align, size_t size, const void *caller) __THROW ATTRIBUTE_SECTION(google_malloc); void* operator new(size_t size) throw (std::bad_alloc) ATTRIBUTE_SECTION(google_malloc); void* operator new(size_t size, const std::nothrow_t&) __THROW ATTRIBUTE_SECTION(google_malloc); void operator delete(void* p) __THROW ATTRIBUTE_SECTION(google_malloc); void operator delete(void* p, const std::nothrow_t&) __THROW ATTRIBUTE_SECTION(google_malloc); void* operator new[](size_t size) throw (std::bad_alloc) ATTRIBUTE_SECTION(google_malloc); void* operator new[](size_t size, const std::nothrow_t&) __THROW ATTRIBUTE_SECTION(google_malloc); void operator delete[](void* p) __THROW ATTRIBUTE_SECTION(google_malloc); void operator delete[](void* p, const std::nothrow_t&) __THROW ATTRIBUTE_SECTION(google_malloc); extern "C" void* malloc(size_t size) __THROW { void* ptr = DebugAllocate(size, MallocBlock::kMallocType); MallocHook::InvokeNewHook(ptr, size); return ptr; } extern "C" void free(void* ptr) __THROW { MallocHook::InvokeDeleteHook(ptr); DebugDeallocate(ptr, MallocBlock::kMallocType); } extern "C" void* realloc(void* ptr, size_t size) __THROW { if (ptr == NULL) { ptr = DebugAllocate(size, MallocBlock::kMallocType); MallocHook::InvokeNewHook(ptr, size); return ptr; } if (size == 0) { MallocHook::InvokeDeleteHook(ptr); DebugDeallocate(ptr, MallocBlock::kMallocType); return NULL; } MallocBlock* old = MallocBlock::FromRawPointer(ptr); old->Check(MallocBlock::kMallocType); MallocBlock* p = MallocBlock::Allocate(size, MallocBlock::kMallocType); // If realloc fails we are to leave the old block untouched and // return null if (p == NULL) return NULL; memcpy(p->data_addr(), old->data_addr(), (old->data_size() < size) ? old->data_size() : size); MallocHook::InvokeDeleteHook(ptr); MallocHook::InvokeNewHook(p->data_addr(), size); DebugDeallocate(ptr, MallocBlock::kMallocType); MALLOC_TRACE("realloc", p->data_size(), p->data_addr()); return p->data_addr(); } extern "C" void* calloc(size_t count, size_t size) __THROW { // Overflow check const size_t total_size = count * size; if (size != 0 && total_size / size != count) return NULL; void* block = DebugAllocate(total_size, MallocBlock::kMallocType); MallocHook::InvokeNewHook(block, total_size); if (block) memset(block, 0, total_size); return block; } extern "C" void cfree(void* ptr) __THROW { MallocHook::InvokeDeleteHook(ptr); DebugDeallocate(ptr, MallocBlock::kMallocType); } // Round "value" up to next "alignment" boundary. // Requires that "alignment" be a power of two. static intptr_t RoundUp(intptr_t value, intptr_t alignment) { return (value + alignment - 1) & ~(alignment - 1); } static void *do_debug_memalign(size_t alignment, size_t size) { // Allocate >= size bytes aligned on "alignment" boundary // "alignment" is a power of two. void *p = 0; RAW_CHECK((alignment & (alignment-1)) == 0, "must be power of two"); const size_t data_offset = MallocBlock::data_offset(); // Allocate "alignment-1" extra bytes to ensure alignment is possible, and // a further data_offset bytes for an additional fake header. size_t extra_bytes = data_offset + alignment - 1; if (size + extra_bytes < size) return NULL; // Overflow p = DebugAllocate(size + extra_bytes, MallocBlock::kMallocType); if (p != 0) { intptr_t orig_p = reinterpret_cast(p); // Leave data_offset bytes for fake header, and round up to meet // alignment. p = reinterpret_cast(RoundUp(orig_p + data_offset, alignment)); // Create a fake header block with an offset_ that points back to the // real header. FromRawPointer uses this value. MallocBlock *fake_hdr = reinterpret_cast( reinterpret_cast(p) - data_offset); // offset_ is distance between real and fake headers. // p is now end of fake header (beginning of client area), // and orig_p is the end of the real header, so offset_ // is their difference. fake_hdr->set_offset(reinterpret_cast(p) - orig_p); } return p; } // Override __libc_memalign in libc on linux boxes. // They have a bug in libc that causes them (very rarely) to allocate // with __libc_memalign() yet deallocate with free(). // This function is an exception to the rule of calling MallocHook method // from the stack frame of the allocation function; // heap-checker handles this special case explicitly. static void *MemalignOverride(size_t align, size_t size, const void *caller) __THROW { void *p = do_debug_memalign(align, size); MallocHook::InvokeNewHook(p, size); return p; } void *(*__memalign_hook)(size_t, size_t, const void *) = MemalignOverride; extern "C" void* memalign(size_t align, size_t size) __THROW { void *p = do_debug_memalign(align, size); MallocHook::InvokeNewHook(p, size); return p; } // Implementation taken from tcmalloc/tcmalloc.cc extern "C" int posix_memalign(void** result_ptr, size_t align, size_t size) __THROW { if (((align % sizeof(void*)) != 0) || ((align & (align - 1)) != 0) || (align == 0)) { return EINVAL; } void* result = do_debug_memalign(align, size); MallocHook::InvokeNewHook(result, size); if (result == NULL) { return ENOMEM; } else { *result_ptr = result; return 0; } } extern "C" void* valloc(size_t size) __THROW { // Allocate >= size bytes starting on a page boundary void *p = do_debug_memalign(getpagesize(), size); MallocHook::InvokeNewHook(p, size); return p; } extern "C" void* pvalloc(size_t size) __THROW { // Round size up to a multiple of pages // then allocate memory on a page boundary int pagesize = getpagesize(); size = RoundUp(size, pagesize); if (size == 0) { // pvalloc(0) should allocate one page, according to size = pagesize; // http://man.free4web.biz/man3/libmpatrol.3.html } void *p = do_debug_memalign(pagesize, size); MallocHook::InvokeNewHook(p, size); return p; } extern "C" int mallopt(int cmd, int value) __THROW { return BASE_MALLOPT(cmd, value); } #ifdef HAVE_STRUCT_MALLINFO extern "C" struct mallinfo mallinfo(void) __THROW { return BASE_MALLINFO(); } #endif // ========================================================================= // // Alloc/free stuff for debug operator new & friends // This is mostly the same a cpp_alloc in tcmalloc.cc. inline void* cpp_debug_alloc(size_t size, int new_type, bool nothrow) { for (;;) { void* p = DebugAllocate(size, new_type); #ifdef PREANSINEW return p; #else if (p == NULL) { // allocation failed // Get the current new handler. NB: this function is not // thread-safe. We make a feeble stab at making it so here, but // this lock only protects against tcmalloc interfering with // itself, not with other libraries calling set_new_handler. std::new_handler nh; { SpinLockHolder h(&set_new_handler_lock); nh = std::set_new_handler(0); (void) std::set_new_handler(nh); } #if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) if (nh) { // Since exceptions are disabled, we don't really know if new_handler // failed. Assume it will abort if it fails. (*nh)(); continue; } return 0; #else // If no new_handler is established, the allocation failed. if (!nh) { if (nothrow) return 0; throw std::bad_alloc(); } // Otherwise, try the new_handler. If it returns, retry the // allocation. If it throws std::bad_alloc, fail the allocation. // if it throws something else, don't interfere. try { (*nh)(); } catch (const std::bad_alloc&) { if (!nothrow) throw; return p; } #endif // (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) } else { // allocation success return p; } #endif // PREANSINEW } } void* operator new(size_t size) throw (std::bad_alloc) { void* ptr = cpp_debug_alloc(size, MallocBlock::kNewType, false); MallocHook::InvokeNewHook(ptr, size); if (ptr == NULL) { RAW_LOG(FATAL, "Unable to allocate %"PRIuS" bytes: new failed.", size); } return ptr; } void* operator new(size_t size, const std::nothrow_t&) __THROW { void* ptr = cpp_debug_alloc(size, MallocBlock::kNewType, true); MallocHook::InvokeNewHook(ptr, size); return ptr; } void operator delete(void* ptr) __THROW { MallocHook::InvokeDeleteHook(ptr); DebugDeallocate(ptr, MallocBlock::kNewType); } // Some STL implementations explicitly invoke this. // It is completely equivalent to a normal delete (delete never throws). void operator delete(void* ptr, const std::nothrow_t&) __THROW { MallocHook::InvokeDeleteHook(ptr); DebugDeallocate(ptr, MallocBlock::kNewType); } // ========================================================================= // // Alloc/free stuff for debug operator new[] & friends void* operator new[](size_t size) throw (std::bad_alloc) { void* ptr = cpp_debug_alloc(size, MallocBlock::kArrayNewType, false); MallocHook::InvokeNewHook(ptr, size); if (ptr == NULL) { RAW_LOG(FATAL, "Unable to allocate %"PRIuS" bytes: new[] failed.", size); } return ptr; } void* operator new[](size_t size, const std::nothrow_t&) __THROW { void* ptr = cpp_debug_alloc(size, MallocBlock::kArrayNewType, true); MallocHook::InvokeNewHook(ptr, size); return ptr; } void operator delete[](void* ptr) __THROW { MallocHook::InvokeDeleteHook(ptr); DebugDeallocate(ptr, MallocBlock::kArrayNewType); } // Some STL implementations explicitly invoke this. // It is completely equivalent to a normal delete (delete never throws). void operator delete[](void* ptr, const std::nothrow_t&) __THROW { MallocHook::InvokeDeleteHook(ptr); DebugDeallocate(ptr, MallocBlock::kArrayNewType); } // ========================================================================= // // The following functions may be called via MallocExtension::instance() // for memory verification and statistics. #ifdef TCMALLOC_FOR_DEBUGALLOCATION // Inherit from tcmalloc's version typedef TCMallocImplementation ParentImplementation; #else // Inherit from default version typedef MallocExtension ParentImplementation; #endif class DebugMallocImplementation : public ParentImplementation { public: virtual bool GetNumericProperty(const char* name, size_t* value) { bool result = ParentImplementation::GetNumericProperty(name, value); if (result && (strcmp(name, "generic.current_allocated_bytes") == 0)) { // Subtract bytes kept in the free queue size_t qsize = MallocBlock::FreeQueueSize(); if (*value >= qsize) { *value -= qsize; } } return result; } virtual bool VerifyNewMemory(void* p) { if (p) MallocBlock::FromRawPointer(p)->Check(MallocBlock::kNewType); return true; } virtual bool VerifyArrayNewMemory(void* p) { if (p) MallocBlock::FromRawPointer(p)->Check(MallocBlock::kArrayNewType); return true; } virtual bool VerifyMallocMemory(void* p) { if (p) MallocBlock::FromRawPointer(p)->Check(MallocBlock::kMallocType); return true; } virtual bool VerifyAllMemory() { return MallocBlock::CheckEverything(); } virtual bool MallocMemoryStats(int* blocks, size_t* total, int histogram[kMallocHistogramSize]) { return MallocBlock::MemoryStats(blocks, total, histogram); } virtual size_t GetAllocatedSize(void* p) { if (p) { return MallocBlock::FromRawPointer(p)->data_size(); } return 0; } virtual size_t GetEstimatedAllocatedSize(size_t size) { return size; } virtual void GetFreeListSizes(vector* v) { static const char* kDebugFreeQueue = "debug.free_queue"; ParentImplementation::GetFreeListSizes(v); MallocExtension::FreeListInfo i; i.type = kDebugFreeQueue; i.min_object_size = 0; i.max_object_size = numeric_limits::max(); i.total_bytes_free = MallocBlock::FreeQueueSize(); v->push_back(i); } }; static DebugMallocImplementation debug_malloc_implementation; REGISTER_MODULE_INITIALIZER(debugallocation, { // Either we or valgrind will control memory management. We // register our extension if we're the winner. if (RunningOnValgrind()) { // Let Valgrind uses its own malloc (so don't register our extension). } else { MallocExtension::Register(&debug_malloc_implementation); // When the program exits, check all blocks still in the free // queue for corruption. atexit(DanglingWriteChecker); } }); #ifdef TCMALLOC_FOR_DEBUGALLOCATION // Redefine malloc_stats to use tcmalloc's implementation: extern "C" void malloc_stats(void) __THROW { do_malloc_stats(); } // Some library routines on RedHat 9 allocate memory using malloc() // and free it using __libc_free() (or vice-versa). Since we provide // our own implementations of malloc/free using tcmalloc.cc, // we need to make sure that the __libc_XXX variants // also point to the same implementations. // // Note: this might not override __libc_XXX calls withing libc itself, // but it can be important for other libraries that mention these functions // or when this code is LD_PRELOAD-ed. // TODO: In case these __libc_* definitions do not actually matter, // they should go away from here and from tcmalloc/tcmalloc.cc. // extern "C" { void* __libc_malloc(size_t size) { return malloc(size); } void __libc_free(void* ptr) { free(ptr); } void* __libc_realloc(void* ptr, size_t size) { return realloc(ptr, size); } void* __libc_calloc(size_t n, size_t size) { return calloc(n, size); } void __libc_cfree(void* ptr) { cfree(ptr); } void* __libc_memalign(size_t align, size_t s) { return memalign(align, s); } void* __libc_valloc(size_t size) { return valloc(size); } void* __libc_pvalloc(size_t size) { return pvalloc(size); } int __posix_memalign(void** r, size_t a, size_t s) { return posix_memalign(r, a, s); } } #endif // #ifdef TCMALLOC_FOR_DEBUGALLOCATION ================================================ FILE: distro/google-perftools-1.7/src/getpc.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Craig Silverstein // // This is an internal header file used by profiler.cc. It defines // the single (inline) function GetPC. GetPC is used in a signal // handler to figure out the instruction that was being executed when // the signal-handler was triggered. // // To get this, we use the ucontext_t argument to the signal-handler // callback, which holds the full context of what was going on when // the signal triggered. How to get from a ucontext_t to a Program // Counter is OS-dependent. #ifndef BASE_GETPC_H_ #define BASE_GETPC_H_ #include "config.h" // On many linux systems, we may need _GNU_SOURCE to get access to // the defined constants that define the register we want to see (eg // REG_EIP). Note this #define must come first! #define _GNU_SOURCE 1 // If #define _GNU_SOURCE causes problems, this might work instead. // It will cause problems for FreeBSD though!, because it turns off // the needed __BSD_VISIBLE. //#define _XOPEN_SOURCE 500 #include // for memcmp #if defined(HAVE_SYS_UCONTEXT_H) #include #elif defined(HAVE_UCONTEXT_H) #include // for ucontext_t (and also mcontext_t) #elif defined(HAVE_CYGWIN_SIGNAL_H) #include typedef ucontext ucontext_t; #endif // Take the example where function Foo() calls function Bar(). For // many architectures, Bar() is responsible for setting up and tearing // down its own stack frame. In that case, it's possible for the // interrupt to happen when execution is in Bar(), but the stack frame // is not properly set up (either before it's done being set up, or // after it's been torn down but before Bar() returns). In those // cases, the stack trace cannot see the caller function anymore. // // GetPC can try to identify this situation, on architectures where it // might occur, and unwind the current function call in that case to // avoid false edges in the profile graph (that is, edges that appear // to show a call skipping over a function). To do this, we hard-code // in the asm instructions we might see when setting up or tearing // down a stack frame. // // This is difficult to get right: the instructions depend on the // processor, the compiler ABI, and even the optimization level. This // is a best effort patch -- if we fail to detect such a situation, or // mess up the PC, nothing happens; the returned PC is not used for // any further processing. struct CallUnrollInfo { // Offset from (e)ip register where this instruction sequence // should be matched. Interpreted as bytes. Offset 0 is the next // instruction to execute. Be extra careful with negative offsets in // architectures of variable instruction length (like x86) - it is // not that easy as taking an offset to step one instruction back! int pc_offset; // The actual instruction bytes. Feel free to make it larger if you // need a longer sequence. char ins[16]; // How many bytes to match from ins array? int ins_size; // The offset from the stack pointer (e)sp where to look for the // call return address. Interpreted as bytes. int return_sp_offset; }; // The dereferences needed to get the PC from a struct ucontext were // determined at configure time, and stored in the macro // PC_FROM_UCONTEXT in config.h. The only thing we need to do here, // then, is to do the magic call-unrolling for systems that support it. // -- Special case 1: linux x86, for which we have CallUnrollInfo #if defined(__linux) && defined(__i386) && defined(__GNUC__) static const CallUnrollInfo callunrollinfo[] = { // Entry to a function: push %ebp; mov %esp,%ebp // Top-of-stack contains the caller IP. { 0, {0x55, 0x89, 0xe5}, 3, 0 }, // Entry to a function, second instruction: push %ebp; mov %esp,%ebp // Top-of-stack contains the old frame, caller IP is +4. { -1, {0x55, 0x89, 0xe5}, 3, 4 }, // Return from a function: RET. // Top-of-stack contains the caller IP. { 0, {0xc3}, 1, 0 } }; inline void* GetPC(const ucontext_t& signal_ucontext) { // See comment above struct CallUnrollInfo. Only try instruction // flow matching if both eip and esp looks reasonable. const int eip = signal_ucontext.uc_mcontext.gregs[REG_EIP]; const int esp = signal_ucontext.uc_mcontext.gregs[REG_ESP]; if ((eip & 0xffff0000) != 0 && (~eip & 0xffff0000) != 0 && (esp & 0xffff0000) != 0) { char* eip_char = reinterpret_cast(eip); for (int i = 0; i < sizeof(callunrollinfo)/sizeof(*callunrollinfo); ++i) { if (!memcmp(eip_char + callunrollinfo[i].pc_offset, callunrollinfo[i].ins, callunrollinfo[i].ins_size)) { // We have a match. void **retaddr = (void**)(esp + callunrollinfo[i].return_sp_offset); return *retaddr; } } } return (void*)eip; } // Special case #2: Windows, which has to do something totally different. #elif defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__MINGW32__) // If this is ever implemented, probably the way to do it is to have // profiler.cc use a high-precision timer via timeSetEvent: // http://msdn2.microsoft.com/en-us/library/ms712713.aspx // We'd use it in mode TIME_CALLBACK_FUNCTION/TIME_PERIODIC. // The callback function would be something like prof_handler, but // alas the arguments are different: no ucontext_t! I don't know // how we'd get the PC (using StackWalk64?) // http://msdn2.microsoft.com/en-us/library/ms680650.aspx #include "base/logging.h" // for RAW_LOG #ifndef HAVE_CYGWIN_SIGNAL_H typedef int ucontext_t; #endif inline void* GetPC(const struct ucontext_t& signal_ucontext) { RAW_LOG(ERROR, "GetPC is not yet implemented on Windows\n"); return NULL; } // Normal cases. If this doesn't compile, it's probably because // PC_FROM_UCONTEXT is the empty string. You need to figure out // the right value for your system, and add it to the list in // configure.ac (or set it manually in your config.h). #else inline void* GetPC(const ucontext_t& signal_ucontext) { return (void*)signal_ucontext.PC_FROM_UCONTEXT; // defined in config.h } #endif #endif // BASE_GETPC_H_ ================================================ FILE: distro/google-perftools-1.7/src/google/heap-checker.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Maxim Lifantsev (with design ideas by Sanjay Ghemawat) // // // Module for detecing heap (memory) leaks. // // For full(er) information, see doc/heap_checker.html // // This module can be linked into programs with // no slowdown caused by this unless you activate the leak-checker: // // 1. Set the environment variable HEAPCHEK to _type_ before // running the program. // // _type_ is usually "normal" but can also be "minimal", "strict", or // "draconian". (See the html file for other options, like 'local'.) // // After that, just run your binary. If the heap-checker detects // a memory leak at program-exit, it will print instructions on how // to track down the leak. #ifndef BASE_HEAP_CHECKER_H_ #define BASE_HEAP_CHECKER_H_ #include // for size_t // I can't #include config.h in this public API file, but I should // really use configure (and make malloc_extension.h a .in file) to // figure out if the system has stdint.h or not. But I'm lazy, so // for now I'm assuming it's a problem only with MSVC. #ifndef _MSC_VER #include // for uintptr_t #endif #include // for va_list #include // Annoying stuff for windows -- makes sure clients can import these functions #ifndef PERFTOOLS_DLL_DECL # ifdef _WIN32 # define PERFTOOLS_DLL_DECL __declspec(dllimport) # else # define PERFTOOLS_DLL_DECL # endif #endif // The class is thread-safe with respect to all the provided static methods, // as well as HeapLeakChecker objects: they can be accessed by multiple threads. class PERFTOOLS_DLL_DECL HeapLeakChecker { public: // ----------------------------------------------------------------------- // // Static functions for working with (whole-program) leak checking. // If heap leak checking is currently active in some mode // e.g. if leak checking was started (and is still active now) // due to HEAPCHECK=... defined in the environment. // The return value reflects iff HeapLeakChecker objects manually // constructed right now will be doing leak checking or nothing. // Note that we can go from active to inactive state during InitGoogle() // if FLAGS_heap_check gets set to "" by some code before/during InitGoogle(). static bool IsActive(); // Return pointer to the whole-program checker if it has been created // and NULL otherwise. // Once GlobalChecker() returns non-NULL that object will not disappear and // will be returned by all later GlobalChecker calls. // This is mainly to access BytesLeaked() and ObjectsLeaked() (see below) // for the whole-program checker after one calls NoGlobalLeaks() // or similar and gets false. static HeapLeakChecker* GlobalChecker(); // Do whole-program leak check now (if it was activated for this binary); // return false only if it was activated and has failed. // The mode of the check is controlled by the command-line flags. // This method can be called repeatedly. // Things like GlobalChecker()->SameHeap() can also be called explicitly // to do the desired flavor of the check. static bool NoGlobalLeaks(); // If whole-program checker if active, // cancel its automatic execution after main() exits. // This requires that some leak check (e.g. NoGlobalLeaks()) // has been called at least once on the whole-program checker. static void CancelGlobalCheck(); // ----------------------------------------------------------------------- // // Non-static functions for starting and doing leak checking. // Start checking and name the leak check performed. // The name is used in naming dumped profiles // and needs to be unique only within your binary. // It must also be a string that can be a part of a file name, // in particular not contain path expressions. explicit HeapLeakChecker(const char *name); // Destructor (verifies that some *NoLeaks or *SameHeap method // has been called at least once). ~HeapLeakChecker(); // These used to be different but are all the same now: they return // true iff all memory allocated since this HeapLeakChecker object // was constructor is still reachable from global state. // // Because we fork to convert addresses to symbol-names, and forking // is not thread-safe, and we may be called in a threaded context, // we do not try to symbolize addresses when called manually. bool NoLeaks() { return DoNoLeaks(DO_NOT_SYMBOLIZE); } // These forms are obsolete; use NoLeaks() instead. // TODO(csilvers): mark as DEPRECATED. bool QuickNoLeaks() { return NoLeaks(); } bool BriefNoLeaks() { return NoLeaks(); } bool SameHeap() { return NoLeaks(); } bool QuickSameHeap() { return NoLeaks(); } bool BriefSameHeap() { return NoLeaks(); } // Detailed information about the number of leaked bytes and objects // (both of these can be negative as well). // These are available only after a *SameHeap or *NoLeaks // method has been called. // Note that it's possible for both of these to be zero // while SameHeap() or NoLeaks() returned false in case // of a heap state change that is significant // but preserves the byte and object counts. ssize_t BytesLeaked() const; ssize_t ObjectsLeaked() const; // ----------------------------------------------------------------------- // // Static helpers to make us ignore certain leaks. // Scoped helper class. Should be allocated on the stack inside a // block of code. Any heap allocations done in the code block // covered by the scoped object (including in nested function calls // done by the code block) will not be reported as leaks. This is // the recommended replacement for the GetDisableChecksStart() and // DisableChecksToHereFrom() routines below. // // Example: // void Foo() { // HeapLeakChecker::Disabler disabler; // ... code that allocates objects whose leaks should be ignored ... // } // // REQUIRES: Destructor runs in same thread as constructor class Disabler { public: Disabler(); ~Disabler(); private: Disabler(const Disabler&); // disallow copy void operator=(const Disabler&); // and assign }; // Ignore an object located at 'ptr' (can go at the start or into the object) // as well as all heap objects (transitively) referenced from it // for the purposes of heap leak checking. // If 'ptr' does not point to an active allocated object // at the time of this call, it is ignored; // but if it does, the object must not get deleted from the heap later on; // it must also be not already ignored at the time of this call. // // See also HiddenPointer, below, if you need to prevent a pointer from // being traversed by the heap checker but do not wish to transitively // whitelist objects referenced through it. static void IgnoreObject(const void* ptr); // Undo what an earlier IgnoreObject() call promised and asked to do. // At the time of this call 'ptr' must point at or inside of an active // allocated object which was previously registered with IgnoreObject(). static void UnIgnoreObject(const void* ptr); // ----------------------------------------------------------------------- // // Initialization; to be called from main() only. // Full starting of recommended whole-program checking. static void InternalInitStart(); // ----------------------------------------------------------------------- // // Internal types defined in .cc class Allocator; struct RangeValue; private: // ----------------------------------------------------------------------- // // Various helpers // Create the name of the heap profile file. // Should be deleted via Allocator::Free(). char* MakeProfileNameLocked(); // Helper for constructors void Create(const char *name, bool make_start_snapshot); enum ShouldSymbolize { SYMBOLIZE, DO_NOT_SYMBOLIZE }; // Helper for *NoLeaks and *SameHeap bool DoNoLeaks(ShouldSymbolize should_symbolize); // These used to be public, but they are now deprecated. // Will remove entirely when all internal uses are fixed. // In the meantime, use friendship so the unittest can still test them. static void* GetDisableChecksStart(); static void DisableChecksToHereFrom(const void* start_address); static void DisableChecksIn(const char* pattern); friend void RangeDisabledLeaks(); friend void NamedTwoDisabledLeaks(); friend void* RunNamedDisabledLeaks(void*); friend void TestHeapLeakCheckerNamedDisabling(); friend int main(int, char**); // Helper for DisableChecksIn static void DisableChecksInLocked(const char* pattern); // Disable checks based on stack trace entry at a depth <= // max_depth. Used to hide allocations done inside some special // libraries. static void DisableChecksFromToLocked(const void* start_address, const void* end_address, int max_depth); // Helper for DoNoLeaks to ignore all objects reachable from all live data static void IgnoreAllLiveObjectsLocked(const void* self_stack_top); // Callback we pass to ListAllProcessThreads (see thread_lister.h) // that is invoked when all threads of our process are found and stopped. // The call back does the things needed to ignore live data reachable from // thread stacks and registers for all our threads // as well as do other global-live-data ignoring // (via IgnoreNonThreadLiveObjectsLocked) // during the quiet state of all threads being stopped. // For the argument meaning see the comment by ListAllProcessThreads. // Here we only use num_threads and thread_pids, that ListAllProcessThreads // fills for us with the number and pids of all the threads of our process // it found and attached to. static int IgnoreLiveThreadsLocked(void* parameter, int num_threads, pid_t* thread_pids, va_list ap); // Helper for IgnoreAllLiveObjectsLocked and IgnoreLiveThreadsLocked // that we prefer to execute from IgnoreLiveThreadsLocked // while all threads are stopped. // This helper does live object discovery and ignoring // for all objects that are reachable from everything // not related to thread stacks and registers. static void IgnoreNonThreadLiveObjectsLocked(); // Helper for IgnoreNonThreadLiveObjectsLocked and IgnoreLiveThreadsLocked // to discover and ignore all heap objects // reachable from currently considered live objects // (live_objects static global variable in out .cc file). // "name", "name2" are two strings that we print one after another // in a debug message to describe what kind of live object sources // are being used. static void IgnoreLiveObjectsLocked(const char* name, const char* name2); // Runs REGISTER_HEAPCHECK_CLEANUP cleanups and potentially // calls DoMainHeapCheck static void RunHeapCleanups(); // Do the overall whole-program heap leak check if needed; // returns true when did the leak check. static bool DoMainHeapCheck(); // Type of task for UseProcMapsLocked enum ProcMapsTask { RECORD_GLOBAL_DATA, DISABLE_LIBRARY_ALLOCS }; // Success/Error Return codes for UseProcMapsLocked. enum ProcMapsResult { PROC_MAPS_USED, CANT_OPEN_PROC_MAPS, NO_SHARED_LIBS_IN_PROC_MAPS }; // Read /proc/self/maps, parse it, and do the 'proc_maps_task' for each line. static ProcMapsResult UseProcMapsLocked(ProcMapsTask proc_maps_task); // A ProcMapsTask to disable allocations from 'library' // that is mapped to [start_address..end_address) // (only if library is a certain system library). static void DisableLibraryAllocsLocked(const char* library, uintptr_t start_address, uintptr_t end_address); // Return true iff "*ptr" points to a heap object // ("*ptr" can point at the start or inside of a heap object // so that this works e.g. for pointers to C++ arrays, C++ strings, // multiple-inherited objects, or pointers to members). // We also fill *object_size for this object then // and we move "*ptr" to point to the very start of the heap object. static inline bool HaveOnHeapLocked(const void** ptr, size_t* object_size); // Helper to shutdown heap leak checker when it's not needed // or can't function properly. static void TurnItselfOffLocked(); // Internally-used c-tor to start whole-executable checking. HeapLeakChecker(); // ----------------------------------------------------------------------- // // Friends and externally accessed helpers. // Helper for VerifyHeapProfileTableStackGet in the unittest // to get the recorded allocation caller for ptr, // which must be a heap object. static const void* GetAllocCaller(void* ptr); friend void VerifyHeapProfileTableStackGet(); // This gets to execute before constructors for all global objects static void BeforeConstructorsLocked(); friend void HeapLeakChecker_BeforeConstructors(); // This gets to execute after destructors for all global objects friend void HeapLeakChecker_AfterDestructors(); // ----------------------------------------------------------------------- // // Member data. class SpinLock* lock_; // to make HeapLeakChecker objects thread-safe const char* name_; // our remembered name (we own it) // NULL means this leak checker is a noop // Snapshot taken when the checker was created. May be NULL // for the global heap checker object. We use void* instead of // HeapProfileTable::Snapshot* to avoid including heap-profile-table.h. void* start_snapshot_; bool has_checked_; // if we have done the leak check, so these are ready: ssize_t inuse_bytes_increase_; // bytes-in-use increase for this checker ssize_t inuse_allocs_increase_; // allocations-in-use increase // for this checker bool keep_profiles_; // iff we should keep the heap profiles we've made // ----------------------------------------------------------------------- // // Disallow "evil" constructors. HeapLeakChecker(const HeapLeakChecker&); void operator=(const HeapLeakChecker&); }; // Holds a pointer that will not be traversed by the heap checker. // Contrast with HeapLeakChecker::IgnoreObject(o), in which o and // all objects reachable from o are ignored by the heap checker. template class HiddenPointer { public: explicit HiddenPointer(T* t) : masked_t_(reinterpret_cast(t) ^ kHideMask) { } // Returns unhidden pointer. Be careful where you save the result. T* get() const { return reinterpret_cast(masked_t_ ^ kHideMask); } private: // Arbitrary value, but not such that xor'ing with it is likely // to map one valid pointer to another valid pointer: static const uintptr_t kHideMask = static_cast(0xF03A5F7BF03A5F7Bll); uintptr_t masked_t_; }; // A class that exists solely to run its destructor. This class should not be // used directly, but instead by the REGISTER_HEAPCHECK_CLEANUP macro below. class PERFTOOLS_DLL_DECL HeapCleaner { public: typedef void (*void_function)(void); HeapCleaner(void_function f); static void RunHeapCleanups(); private: static std::vector* heap_cleanups_; }; // A macro to declare module heap check cleanup tasks // (they run only if we are doing heap leak checking.) // 'body' should be the cleanup code to run. 'name' doesn't matter, // but must be unique amongst all REGISTER_HEAPCHECK_CLEANUP calls. #define REGISTER_HEAPCHECK_CLEANUP(name, body) \ namespace { \ void heapcheck_cleanup_##name() { body; } \ static HeapCleaner heapcheck_cleaner_##name(&heapcheck_cleanup_##name); \ } #endif // BASE_HEAP_CHECKER_H_ ================================================ FILE: distro/google-perftools-1.7/src/google/heap-profiler.h ================================================ /* Copyright (c) 2005, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Sanjay Ghemawat * * Module for heap-profiling. * * For full(er) information, see doc/heapprofile.html * * This module can be linked into your program with * no slowdown caused by this unless you activate the profiler * using one of the following methods: * * 1. Before starting the program, set the environment variable * "HEAPPROFILE" to be the name of the file to which the profile * data should be written. * * 2. Programmatically, start and stop the profiler using the * routines "HeapProfilerStart(filename)" and "HeapProfilerStop()". * */ #ifndef BASE_HEAP_PROFILER_H_ #define BASE_HEAP_PROFILER_H_ #include /* Annoying stuff for windows; makes sure clients can import these functions */ #ifndef PERFTOOLS_DLL_DECL # ifdef _WIN32 # define PERFTOOLS_DLL_DECL __declspec(dllimport) # else # define PERFTOOLS_DLL_DECL # endif #endif /* All this code should be usable from within C apps. */ #ifdef __cplusplus extern "C" { #endif /* Start profiling and arrange to write profile data to file names * of the form: "prefix.0000", "prefix.0001", ... */ PERFTOOLS_DLL_DECL void HeapProfilerStart(const char* prefix); /* Returns non-zero if we are currently profiling the heap. (Returns * an int rather than a bool so it's usable from C.) This is true * between calls to HeapProfilerStart() and HeapProfilerStop(), and * also if the program has been run with HEAPPROFILER, or some other * way to turn on whole-program profiling. */ int IsHeapProfilerRunning(); /* Stop heap profiling. Can be restarted again with HeapProfilerStart(), * but the currently accumulated profiling information will be cleared. */ PERFTOOLS_DLL_DECL void HeapProfilerStop(); /* Dump a profile now - can be used for dumping at a hopefully * quiescent state in your program, in order to more easily track down * memory leaks. Will include the reason in the logged message */ PERFTOOLS_DLL_DECL void HeapProfilerDump(const char *reason); /* Generate current heap profiling information. * Returns an empty string when heap profiling is not active. * The returned pointer is a '\0'-terminated string allocated using malloc() * and should be free()-ed as soon as the caller does not need it anymore. */ PERFTOOLS_DLL_DECL char* GetHeapProfile(); #ifdef __cplusplus } // extern "C" #endif #endif /* BASE_HEAP_PROFILER_H_ */ ================================================ FILE: distro/google-perftools-1.7/src/google/malloc_extension.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // Extra extensions exported by some malloc implementations. These // extensions are accessed through a virtual base class so an // application can link against a malloc that does not implement these // extensions, and it will get default versions that do nothing. // // NOTE FOR C USERS: If you wish to use this functionality from within // a C program, see malloc_extension_c.h. #ifndef BASE_MALLOC_EXTENSION_H_ #define BASE_MALLOC_EXTENSION_H_ #include // I can't #include config.h in this public API file, but I should // really use configure (and make malloc_extension.h a .in file) to // figure out if the system has stdint.h or not. But I'm lazy, so // for now I'm assuming it's a problem only with MSVC. #ifndef _MSC_VER #include #endif #include #include // Annoying stuff for windows -- makes sure clients can import these functions #ifndef PERFTOOLS_DLL_DECL # ifdef _WIN32 # define PERFTOOLS_DLL_DECL __declspec(dllimport) # else # define PERFTOOLS_DLL_DECL # endif #endif static const int kMallocHistogramSize = 64; // One day, we could support other types of writers (perhaps for C?) typedef std::string MallocExtensionWriter; namespace base { struct MallocRange; } // The default implementations of the following routines do nothing. // All implementations should be thread-safe; the current one // (TCMallocImplementation) is. class PERFTOOLS_DLL_DECL MallocExtension { public: virtual ~MallocExtension(); // Call this very early in the program execution -- say, in a global // constructor -- to set up parameters and state needed by all // instrumented malloc implemenatations. One example: this routine // sets environemnt variables to tell STL to use libc's malloc() // instead of doing its own memory management. This is safe to call // multiple times, as long as each time is before threads start up. static void Initialize(); // See "verify_memory.h" to see what these routines do virtual bool VerifyAllMemory(); virtual bool VerifyNewMemory(void* p); virtual bool VerifyArrayNewMemory(void* p); virtual bool VerifyMallocMemory(void* p); virtual bool MallocMemoryStats(int* blocks, size_t* total, int histogram[kMallocHistogramSize]); // Get a human readable description of the current state of the malloc // data structures. The state is stored as a null-terminated string // in a prefix of "buffer[0,buffer_length-1]". // REQUIRES: buffer_length > 0. virtual void GetStats(char* buffer, int buffer_length); // Outputs to "writer" a sample of live objects and the stack traces // that allocated these objects. The format of the returned output // is equivalent to the output of the heap profiler and can // therefore be passed to "pprof". // NOTE: by default, tcmalloc does not do any heap sampling, and this // function will always return an empty sample. To get useful // data from GetHeapSample, you must also set the environment // variable TCMALLOC_SAMPLE_PARAMETER to a value such as 524288. virtual void GetHeapSample(MallocExtensionWriter* writer); // Outputs to "writer" the stack traces that caused growth in the // address space size. The format of the returned output is // equivalent to the output of the heap profiler and can therefore // be passed to "pprof". (This does not depend on, or require, // TCMALLOC_SAMPLE_PARAMETER.) virtual void GetHeapGrowthStacks(MallocExtensionWriter* writer); // Invokes func(arg, range) for every controlled memory // range. *range is filled in with information about the range. // // This is a best-effort interface useful only for performance // analysis. The implementation may not call func at all. typedef void (RangeFunction)(void*, const base::MallocRange*); virtual void Ranges(void* arg, RangeFunction func); // ------------------------------------------------------------------- // Control operations for getting and setting malloc implementation // specific parameters. Some currently useful properties: // // generic // ------- // "generic.current_allocated_bytes" // Number of bytes currently allocated by application // This property is not writable. // // "generic.heap_size" // Number of bytes in the heap == // current_allocated_bytes + // fragmentation + // freed memory regions // This property is not writable. // // tcmalloc // -------- // "tcmalloc.max_total_thread_cache_bytes" // Upper limit on total number of bytes stored across all // per-thread caches. Default: 16MB. // // "tcmalloc.current_total_thread_cache_bytes" // Number of bytes used across all thread caches. // This property is not writable. // // "tcmalloc.pageheap_free_bytes" // Number of bytes in free, mapped pages in page heap. These // bytes can be used to fulfill allocation requests. They // always count towards virtual memory usage, and unless the // underlying memory is swapped out by the OS, they also count // towards physical memory usage. This property is not writable. // // "tcmalloc.pageheap_unmapped_bytes" // Number of bytes in free, unmapped pages in page heap. // These are bytes that have been released back to the OS, // possibly by one of the MallocExtension "Release" calls. // They can be used to fulfill allocation requests, but // typically incur a page fault. They always count towards // virtual memory usage, and depending on the OS, typically // do not count towards physical memory usage. This property // is not writable. // ------------------------------------------------------------------- // Get the named "property"'s value. Returns true if the property // is known. Returns false if the property is not a valid property // name for the current malloc implementation. // REQUIRES: property != NULL; value != NULL virtual bool GetNumericProperty(const char* property, size_t* value); // Set the named "property"'s value. Returns true if the property // is known and writable. Returns false if the property is not a // valid property name for the current malloc implementation, or // is not writable. // REQUIRES: property != NULL virtual bool SetNumericProperty(const char* property, size_t value); // Mark the current thread as "idle". This routine may optionally // be called by threads as a hint to the malloc implementation that // any thread-specific resources should be released. Note: this may // be an expensive routine, so it should not be called too often. // // Also, if the code that calls this routine will go to sleep for // a while, it should take care to not allocate anything between // the call to this routine and the beginning of the sleep. // // Most malloc implementations ignore this routine. virtual void MarkThreadIdle(); // Mark the current thread as "busy". This routine should be // called after MarkThreadIdle() if the thread will now do more // work. If this method is not called, performance may suffer. // // Most malloc implementations ignore this routine. virtual void MarkThreadBusy(); // Try to release num_bytes of free memory back to the operating // system for reuse. Use this extension with caution -- to get this // memory back may require faulting pages back in by the OS, and // that may be slow. (Currently only implemented in tcmalloc.) virtual void ReleaseToSystem(size_t num_bytes); // Same as ReleaseToSystem() but release as much memory as possible. virtual void ReleaseFreeMemory(); // Sets the rate at which we release unused memory to the system. // Zero means we never release memory back to the system. Increase // this flag to return memory faster; decrease it to return memory // slower. Reasonable rates are in the range [0,10]. (Currently // only implemented in tcmalloc). virtual void SetMemoryReleaseRate(double rate); // Gets the release rate. Returns a value < 0 if unknown. virtual double GetMemoryReleaseRate(); // Returns the estimated number of bytes that will be allocated for // a request of "size" bytes. This is an estimate: an allocation of // SIZE bytes may reserve more bytes, but will never reserve less. // (Currently only implemented in tcmalloc, other implementations // always return SIZE.) // This is equivalent to malloc_good_size() in OS X. virtual size_t GetEstimatedAllocatedSize(size_t size); // Returns the actual number N of bytes reserved by tcmalloc for the // pointer p. The client is allowed to use the range of bytes // [p, p+N) in any way it wishes (i.e. N is the "usable size" of this // allocation). This number may be equal to or greater than the number // of bytes requested when p was allocated. // p must have been allocated by this malloc implementation, // must not be an interior pointer -- that is, must be exactly // the pointer returned to by malloc() et al., not some offset // from that -- and should not have been freed yet. p may be NULL. // (Currently only implemented in tcmalloc; other implementations // will return 0.) // This is equivalent to malloc_size() in OS X, malloc_usable_size() // in glibc, and _msize() for windows. virtual size_t GetAllocatedSize(void* p); // The current malloc implementation. Always non-NULL. static MallocExtension* instance(); // Change the malloc implementation. Typically called by the // malloc implementation during initialization. static void Register(MallocExtension* implementation); // Returns detailed information about malloc's freelists. For each list, // return a FreeListInfo: struct FreeListInfo { size_t min_object_size; size_t max_object_size; size_t total_bytes_free; const char* type; }; // Each item in the vector refers to a different freelist. The lists // are identified by the range of allocations that objects in the // list can satisfy ([min_object_size, max_object_size]) and the // type of freelist (see below). The current size of the list is // returned in total_bytes_free (which count against a processes // resident and virtual size). // // Currently supported types are: // // "tcmalloc.page{_unmapped}" - tcmalloc's page heap. An entry for each size // class in the page heap is returned. Bytes in "page_unmapped" // are no longer backed by physical memory and do not count against // the resident size of a process. // // "tcmalloc.large{_unmapped}" - tcmalloc's list of objects larger // than the largest page heap size class. Only one "large" // entry is returned. There is no upper-bound on the size // of objects in the large free list; this call returns // kint64max for max_object_size. Bytes in // "large_unmapped" are no longer backed by physical memory // and do not count against the resident size of a process. // // "tcmalloc.central" - tcmalloc's central free-list. One entry per // size-class is returned. Never unmapped. // // "debug.free_queue" - free objects queued by the debug allocator // and not returned to tcmalloc. // // "tcmalloc.thread" - tcmalloc's per-thread caches. Never unmapped. virtual void GetFreeListSizes(std::vector* v); protected: // Get a list of stack traces of sampled allocation points. Returns // a pointer to a "new[]-ed" result array, and stores the sample // period in "sample_period". // // The state is stored as a sequence of adjacent entries // in the returned array. Each entry has the following form: // uintptr_t count; // Number of objects with following trace // uintptr_t size; // Total size of objects with following trace // uintptr_t depth; // Number of PC values in stack trace // void* stack[depth]; // PC values that form the stack trace // // The list of entries is terminated by a "count" of 0. // // It is the responsibility of the caller to "delete[]" the returned array. // // May return NULL to indicate no results. // // This is an internal extension. Callers should use the more // convenient "GetHeapSample(string*)" method defined above. virtual void** ReadStackTraces(int* sample_period); // Like ReadStackTraces(), but returns stack traces that caused growth // in the address space size. virtual void** ReadHeapGrowthStackTraces(); }; namespace base { // Information passed per range. More fields may be added later. struct MallocRange { enum Type { INUSE, // Application is using this range FREE, // Range is currently free UNMAPPED, // Backing physical memory has been returned to the OS UNKNOWN, // More enum values may be added in the future }; uintptr_t address; // Address of range size_t length; // Byte length of range Type type; // Type of this range double fraction; // Fraction of range that is being used (0 if !INUSE) // Perhaps add the following: // - stack trace if this range was sampled // - heap growth stack trace if applicable to this range // - age when allocated (for inuse) or freed (if not in use) }; } // namespace base #endif // BASE_MALLOC_EXTENSION_H_ ================================================ FILE: distro/google-perftools-1.7/src/google/malloc_extension_c.h ================================================ /* Copyright (c) 2008, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * -- * Author: Craig Silverstein * * C shims for the C++ malloc_extension.h. See malloc_extension.h for * details. Note these C shims always work on * MallocExtension::instance(); it is not possible to have more than * one MallocExtension object in C applications. */ #ifndef _MALLOC_EXTENSION_C_H_ #define _MALLOC_EXTENSION_C_H_ #include #include /* Annoying stuff for windows -- makes sure clients can import these fns */ #ifndef PERFTOOLS_DLL_DECL # ifdef _WIN32 # define PERFTOOLS_DLL_DECL __declspec(dllimport) # else # define PERFTOOLS_DLL_DECL # endif #endif #ifdef __cplusplus extern "C" { #endif #define kMallocExtensionHistogramSize 64 PERFTOOLS_DLL_DECL int MallocExtension_VerifyAllMemory(void); PERFTOOLS_DLL_DECL int MallocExtension_VerifyNewMemory(void* p); PERFTOOLS_DLL_DECL int MallocExtension_VerifyArrayNewMemory(void* p); PERFTOOLS_DLL_DECL int MallocExtension_VerifyMallocMemory(void* p); PERFTOOLS_DLL_DECL int MallocExtension_MallocMemoryStats(int* blocks, size_t* total, int histogram[kMallocExtensionHistogramSize]); PERFTOOLS_DLL_DECL void MallocExtension_GetStats(char* buffer, int buffer_length); /* TODO(csilvers): write a C version of these routines, that perhaps * takes a function ptr and a void *. */ /* void MallocExtension_GetHeapSample(string* result); */ /* void MallocExtension_GetHeapGrowthStacks(string* result); */ PERFTOOLS_DLL_DECL int MallocExtension_GetNumericProperty(const char* property, size_t* value); PERFTOOLS_DLL_DECL int MallocExtension_SetNumericProperty(const char* property, size_t value); PERFTOOLS_DLL_DECL void MallocExtension_MarkThreadIdle(void); PERFTOOLS_DLL_DECL void MallocExtension_MarkThreadBusy(void); PERFTOOLS_DLL_DECL void MallocExtension_ReleaseToSystem(size_t num_bytes); PERFTOOLS_DLL_DECL void MallocExtension_ReleaseFreeMemory(void); PERFTOOLS_DLL_DECL size_t MallocExtension_GetEstimatedAllocatedSize(size_t size); PERFTOOLS_DLL_DECL size_t MallocExtension_GetAllocatedSize(void* p); #ifdef __cplusplus } // extern "C" #endif #endif /* _MALLOC_EXTENSION_C_H_ */ ================================================ FILE: distro/google-perftools-1.7/src/google/malloc_hook.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // Some of our malloc implementations can invoke the following hooks // whenever memory is allocated or deallocated. If the hooks are // NULL, they are not invoked. MallocHook is thread-safe, and things // you do before calling SetFooHook(MyHook) are visible to any // resulting calls to MyHook. Hooks must be thread-safe, and if you // write: // // MallocHook::NewHook old_new_hook_ = NULL; // ... // old_new_hook_ = MallocHook::SetNewHook(&MyNewHook); // // old_new_hook_ could still be NULL the first couple times MyNewHook // is called. // // One important user of these hooks is the heap profiler. // // CAVEAT: If you add new MallocHook::Invoke* calls (not for chaining hooks), // then those calls must be directly in the code of the (de)allocation // function that is provided to the user and that function must have // an ATTRIBUTE_SECTION(malloc_hook) attribute. // // Note: Get*Hook() and Invoke*Hook() functions are defined in // malloc_hook-inl.h. If you need to get or invoke a hook (which you // shouldn't unless you're part of tcmalloc), be sure to #include // malloc_hook-inl.h in addition to malloc_hook.h. // // NOTE FOR C USERS: If you want to use malloc_hook functionality from // a C program, #include malloc_hook_c.h instead of this file. // // TODO(csilvers): support a non-inlined function called // Assert*HookIs()? This is the context in which I normally see // Get*Hook() called in non-tcmalloc code. #ifndef _MALLOC_HOOK_H_ #define _MALLOC_HOOK_H_ #include #include extern "C" { #include // a C version of the malloc_hook interface } // Annoying stuff for windows -- makes sure clients can import these functions #ifndef PERFTOOLS_DLL_DECL # ifdef _WIN32 # define PERFTOOLS_DLL_DECL __declspec(dllimport) # else # define PERFTOOLS_DLL_DECL # endif #endif // Note: malloc_hook_c.h defines MallocHook_*Hook and // MallocHook_Set*Hook. The version of these inside the MallocHook // class are defined in terms of the malloc_hook_c version. See // malloc_hook_c.h for details of these types/functions. class PERFTOOLS_DLL_DECL MallocHook { public: // The NewHook is invoked whenever an object is allocated. // It may be passed NULL if the allocator returned NULL. typedef MallocHook_NewHook NewHook; inline static NewHook GetNewHook(); inline static NewHook SetNewHook(NewHook hook) { return MallocHook_SetNewHook(hook); } inline static void InvokeNewHook(const void* p, size_t s); // The DeleteHook is invoked whenever an object is deallocated. // It may be passed NULL if the caller is trying to delete NULL. typedef MallocHook_DeleteHook DeleteHook; inline static DeleteHook GetDeleteHook(); inline static DeleteHook SetDeleteHook(DeleteHook hook) { return MallocHook_SetDeleteHook(hook); } inline static void InvokeDeleteHook(const void* p); // The PreMmapHook is invoked with mmap or mmap64 arguments just // before the call is actually made. Such a hook may be useful // in memory limited contexts, to catch allocations that will exceed // a memory limit, and take outside actions to increase that limit. typedef MallocHook_PreMmapHook PreMmapHook; inline static PreMmapHook GetPreMmapHook(); inline static PreMmapHook SetPreMmapHook(PreMmapHook hook) { return MallocHook_SetPreMmapHook(hook); } inline static void InvokePreMmapHook(const void* start, size_t size, int protection, int flags, int fd, off_t offset); // The MmapHook is invoked whenever a region of memory is mapped. // It may be passed MAP_FAILED if the mmap failed. typedef MallocHook_MmapHook MmapHook; inline static MmapHook GetMmapHook(); inline static MmapHook SetMmapHook(MmapHook hook) { return MallocHook_SetMmapHook(hook); } inline static void InvokeMmapHook(const void* result, const void* start, size_t size, int protection, int flags, int fd, off_t offset); // The MunmapHook is invoked whenever a region of memory is unmapped. typedef MallocHook_MunmapHook MunmapHook; inline static MunmapHook GetMunmapHook(); inline static MunmapHook SetMunmapHook(MunmapHook hook) { return MallocHook_SetMunmapHook(hook); } inline static void InvokeMunmapHook(const void* p, size_t size); // The MremapHook is invoked whenever a region of memory is remapped. typedef MallocHook_MremapHook MremapHook; inline static MremapHook GetMremapHook(); inline static MremapHook SetMremapHook(MremapHook hook) { return MallocHook_SetMremapHook(hook); } inline static void InvokeMremapHook(const void* result, const void* old_addr, size_t old_size, size_t new_size, int flags, const void* new_addr); // The PreSbrkHook is invoked just before sbrk is called -- except when // the increment is 0. This is because sbrk(0) is often called // to get the top of the memory stack, and is not actually a // memory-allocation call. It may be useful in memory-limited contexts, // to catch allocations that will exceed the limit and take outside // actions to increase such a limit. typedef MallocHook_PreSbrkHook PreSbrkHook; inline static PreSbrkHook GetPreSbrkHook(); inline static PreSbrkHook SetPreSbrkHook(PreSbrkHook hook) { return MallocHook_SetPreSbrkHook(hook); } inline static void InvokePreSbrkHook(ptrdiff_t increment); // The SbrkHook is invoked whenever sbrk is called -- except when // the increment is 0. This is because sbrk(0) is often called // to get the top of the memory stack, and is not actually a // memory-allocation call. typedef MallocHook_SbrkHook SbrkHook; inline static SbrkHook GetSbrkHook(); inline static SbrkHook SetSbrkHook(SbrkHook hook) { return MallocHook_SetSbrkHook(hook); } inline static void InvokeSbrkHook(const void* result, ptrdiff_t increment); // Get the current stack trace. Try to skip all routines up to and // and including the caller of MallocHook::Invoke*. // Use "skip_count" (similarly to GetStackTrace from stacktrace.h) // as a hint about how many routines to skip if better information // is not available. inline static int GetCallerStackTrace(void** result, int max_depth, int skip_count) { return MallocHook_GetCallerStackTrace(result, max_depth, skip_count); } // Unhooked versions of mmap() and munmap(). These should be used // only by experts, since they bypass heapchecking, etc. static void* UnhookedMMap(void *start, size_t length, int prot, int flags, int fd, off_t offset); static int UnhookedMUnmap(void *start, size_t length); }; #endif /* _MALLOC_HOOK_H_ */ ================================================ FILE: distro/google-perftools-1.7/src/google/malloc_hook_c.h ================================================ /* Copyright (c) 2008, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * -- * Author: Craig Silverstein * * C shims for the C++ malloc_hook.h. See malloc_hook.h for details * on how to use these. */ #ifndef _MALLOC_HOOK_C_H_ #define _MALLOC_HOOK_C_H_ #include #include // Annoying stuff for windows -- makes sure clients can import these functions #ifndef PERFTOOLS_DLL_DECL # ifdef _WIN32 # define PERFTOOLS_DLL_DECL __declspec(dllimport) # else # define PERFTOOLS_DLL_DECL # endif #endif /* Get the current stack trace. Try to skip all routines up to and * and including the caller of MallocHook::Invoke*. * Use "skip_count" (similarly to GetStackTrace from stacktrace.h) * as a hint about how many routines to skip if better information * is not available. */ PERFTOOLS_DLL_DECL int MallocHook_GetCallerStackTrace(void** result, int max_depth, int skip_count); typedef void (*MallocHook_NewHook)(const void* ptr, size_t size); PERFTOOLS_DLL_DECL MallocHook_NewHook MallocHook_SetNewHook(MallocHook_NewHook hook); typedef void (*MallocHook_DeleteHook)(const void* ptr); PERFTOOLS_DLL_DECL MallocHook_DeleteHook MallocHook_SetDeleteHook(MallocHook_DeleteHook hook); typedef void (*MallocHook_PreMmapHook)(const void *start, size_t size, int protection, int flags, int fd, off_t offset); PERFTOOLS_DLL_DECL MallocHook_PreMmapHook MallocHook_SetPreMmapHook(MallocHook_PreMmapHook hook); typedef void (*MallocHook_MmapHook)(const void* result, const void* start, size_t size, int protection, int flags, int fd, off_t offset); PERFTOOLS_DLL_DECL MallocHook_MmapHook MallocHook_SetMmapHook(MallocHook_MmapHook hook); typedef void (*MallocHook_MunmapHook)(const void* ptr, size_t size); PERFTOOLS_DLL_DECL MallocHook_MunmapHook MallocHook_SetMunmapHook(MallocHook_MunmapHook hook); typedef void (*MallocHook_MremapHook)(const void* result, const void* old_addr, size_t old_size, size_t new_size, int flags, const void* new_addr); PERFTOOLS_DLL_DECL MallocHook_MremapHook MallocHook_SetMremapHook(MallocHook_MremapHook hook); typedef void (*MallocHook_PreSbrkHook)(ptrdiff_t increment); PERFTOOLS_DLL_DECL MallocHook_PreSbrkHook MallocHook_SetPreSbrkHook(MallocHook_PreSbrkHook hook); typedef void (*MallocHook_SbrkHook)(const void* result, ptrdiff_t increment); PERFTOOLS_DLL_DECL MallocHook_SbrkHook MallocHook_SetSbrkHook(MallocHook_SbrkHook hook); #endif /* _MALLOC_HOOK_C_H_ */ ================================================ FILE: distro/google-perftools-1.7/src/google/profiler.h ================================================ /* Copyright (c) 2005, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Sanjay Ghemawat * * Module for CPU profiling based on periodic pc-sampling. * * For full(er) information, see doc/cpuprofile.html * * This module is linked into your program with * no slowdown caused by this unless you activate the profiler * using one of the following methods: * * 1. Before starting the program, set the environment variable * "PROFILE" to be the name of the file to which the profile * data should be written. * * 2. Programmatically, start and stop the profiler using the * routines "ProfilerStart(filename)" and "ProfilerStop()". * * * (Note: if using linux 2.4 or earlier, only the main thread may be * profiled.) * * Use pprof to view the resulting profile output. * % pprof * % pprof --gv * * These functions are thread-safe. */ #ifndef BASE_PROFILER_H_ #define BASE_PROFILER_H_ #include /* For time_t */ /* Annoying stuff for windows; makes sure clients can import these functions */ #ifndef PERFTOOLS_DLL_DECL # ifdef _WIN32 # define PERFTOOLS_DLL_DECL __declspec(dllimport) # else # define PERFTOOLS_DLL_DECL # endif #endif /* All this code should be usable from within C apps. */ #ifdef __cplusplus extern "C" { #endif /* Profiler options, for use with ProfilerStartWithOptions. To use: * * struct ProfilerOptions options; * memset(&options, 0, sizeof options); * * then fill in fields as needed. * * This structure is intended to be usable from C code, so no constructor * is provided to initialize it. (Use memset as described above). */ struct ProfilerOptions { /* Filter function and argument. * * If filter_in_thread is not NULL, when a profiling tick is delivered * the profiler will call: * * (*filter_in_thread)(filter_in_thread_arg) * * If it returns nonzero, the sample will be included in the profile. * Note that filter_in_thread runs in a signal handler, so must be * async-signal-safe. * * A typical use would be to set up filter results for each thread * in the system before starting the profiler, then to make * filter_in_thread be a very simple function which retrieves those * results in an async-signal-safe way. Retrieval could be done * using thread-specific data, or using a shared data structure that * supports async-signal-safe lookups. */ int (*filter_in_thread)(void *arg); void *filter_in_thread_arg; }; /* Start profiling and write profile info into fname, discarding any * existing profiling data in that file. * * This is equivalent to calling ProfilerStartWithOptions(fname, NULL). */ PERFTOOLS_DLL_DECL int ProfilerStart(const char* fname); /* Start profiling and write profile into fname, discarding any * existing profiling data in that file. * * The profiler is configured using the options given by 'options'. * Options which are not specified are given default values. * * 'options' may be NULL, in which case all are given default values. * * Returns nonzero if profiling was started sucessfully, or zero else. */ PERFTOOLS_DLL_DECL int ProfilerStartWithOptions( const char *fname, const struct ProfilerOptions *options); /* Stop profiling. Can be started again with ProfilerStart(), but * the currently accumulated profiling data will be cleared. */ PERFTOOLS_DLL_DECL void ProfilerStop(); /* Flush any currently buffered profiling state to the profile file. * Has no effect if the profiler has not been started. */ PERFTOOLS_DLL_DECL void ProfilerFlush(); /* DEPRECATED: these functions were used to enable/disable profiling * in the current thread, but no longer do anything. */ PERFTOOLS_DLL_DECL void ProfilerEnable(); PERFTOOLS_DLL_DECL void ProfilerDisable(); /* Returns nonzero if profile is currently enabled, zero if it's not. */ PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads(); /* Routine for registering new threads with the profiler. */ PERFTOOLS_DLL_DECL void ProfilerRegisterThread(); /* Stores state about profiler's current status into "*state". */ struct ProfilerState { int enabled; /* Is profiling currently enabled? */ time_t start_time; /* If enabled, when was profiling started? */ char profile_name[1024]; /* Name of profile file being written, or '\0' */ int samples_gathered; /* Number of samples gatheered to far (or 0) */ }; PERFTOOLS_DLL_DECL void ProfilerGetCurrentState(struct ProfilerState* state); #ifdef __cplusplus } // extern "C" #endif #endif /* BASE_PROFILER_H_ */ ================================================ FILE: distro/google-perftools-1.7/src/google/stacktrace.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // Routines to extract the current stack trace. These functions are // thread-safe. #ifndef GOOGLE_STACKTRACE_H_ #define GOOGLE_STACKTRACE_H_ // Annoying stuff for windows -- makes sure clients can import these functions #ifndef PERFTOOLS_DLL_DECL # ifdef _WIN32 # define PERFTOOLS_DLL_DECL __declspec(dllimport) # else # define PERFTOOLS_DLL_DECL # endif #endif // Skips the most recent "skip_count" stack frames (also skips the // frame generated for the "GetStackFrames" routine itself), and then // records the pc values for up to the next "max_depth" frames in // "result", and the corresponding stack frame sizes in "sizes". // Returns the number of values recorded in "result"/"sizes". // // Example: // main() { foo(); } // foo() { bar(); } // bar() { // void* result[10]; // int sizes[10]; // int depth = GetStackFrames(result, sizes, 10, 1); // } // // The GetStackFrames call will skip the frame for "bar". It will // return 2 and will produce pc values that map to the following // procedures: // result[0] foo // result[1] main // (Actually, there may be a few more entries after "main" to account for // startup procedures.) // And corresponding stack frame sizes will also be recorded: // sizes[0] 16 // sizes[1] 16 // (Stack frame sizes of 16 above are just for illustration purposes.) // Stack frame sizes of 0 or less indicate that those frame sizes couldn't // be identified. // // This routine may return fewer stack frame entries than are // available. Also note that "result" and "sizes" must both be non-NULL. extern PERFTOOLS_DLL_DECL int GetStackFrames(void** result, int* sizes, int max_depth, int skip_count); // Same as above, but to be used from a signal handler. The "uc" parameter // should be the pointer to ucontext_t which was passed as the 3rd parameter // to sa_sigaction signal handler. It may help the unwinder to get a // better stack trace under certain conditions. The "uc" may safely be NULL. extern PERFTOOLS_DLL_DECL int GetStackFramesWithContext(void** result, int* sizes, int max_depth, int skip_count, const void *uc); // This is similar to the GetStackFrames routine, except that it returns // the stack trace only, and not the stack frame sizes as well. // Example: // main() { foo(); } // foo() { bar(); } // bar() { // void* result[10]; // int depth = GetStackTrace(result, 10, 1); // } // // This produces: // result[0] foo // result[1] main // .... ... // // "result" must not be NULL. extern PERFTOOLS_DLL_DECL int GetStackTrace(void** result, int max_depth, int skip_count); // Same as above, but to be used from a signal handler. The "uc" parameter // should be the pointer to ucontext_t which was passed as the 3rd parameter // to sa_sigaction signal handler. It may help the unwinder to get a // better stack trace under certain conditions. The "uc" may safely be NULL. extern PERFTOOLS_DLL_DECL int GetStackTraceWithContext(void** result, int max_depth, int skip_count, const void *uc); #endif /* GOOGLE_STACKTRACE_H_ */ ================================================ FILE: distro/google-perftools-1.7/src/google/tcmalloc.h.in ================================================ /* Copyright (c) 2003, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Sanjay Ghemawat * .h file by Craig Silverstein */ #ifndef TCMALLOC_TCMALLOC_H_ #define TCMALLOC_TCMALLOC_H_ // __THROW is defined in glibc systems. It means, counter-intuitively, // "This function will never throw an exception." It's an optional // optimization tool, but we may need to use it to match glibc prototypes. #ifndef __THROW /* I guess we're not on a glibc system */ # define __THROW /* __THROW is just an optimization, so ok to make it "" */ #endif // Define the version number so folks can check against it #define TC_VERSION_MAJOR @TC_VERSION_MAJOR@ #define TC_VERSION_MINOR @TC_VERSION_MINOR@ #define TC_VERSION_PATCH "@TC_VERSION_PATCH@" #define TC_VERSION_STRING "google-perftools @TC_VERSION_MAJOR@.@TC_VERSION_MINOR@@TC_VERSION_PATCH@" #include // for struct mallinfo, if it's defined // Annoying stuff for windows -- makes sure clients can import these functions #ifndef PERFTOOLS_DLL_DECL # ifdef _WIN32 # define PERFTOOLS_DLL_DECL __declspec(dllimport) # else # define PERFTOOLS_DLL_DECL # endif #endif #ifdef __cplusplus #include // for std::nothrow_t extern "C" { #endif // Returns a human-readable version string. If major, minor, // and/or patch are not NULL, they are set to the major version, // minor version, and patch-code (a string, usually ""). PERFTOOLS_DLL_DECL const char* tc_version(int* major, int* minor, const char** patch) __THROW; PERFTOOLS_DLL_DECL void* tc_malloc(size_t size) __THROW; PERFTOOLS_DLL_DECL void tc_free(void* ptr) __THROW; PERFTOOLS_DLL_DECL void* tc_realloc(void* ptr, size_t size) __THROW; PERFTOOLS_DLL_DECL void* tc_calloc(size_t nmemb, size_t size) __THROW; PERFTOOLS_DLL_DECL void tc_cfree(void* ptr) __THROW; PERFTOOLS_DLL_DECL void* tc_memalign(size_t __alignment, size_t __size) __THROW; PERFTOOLS_DLL_DECL int tc_posix_memalign(void** ptr, size_t align, size_t size) __THROW; PERFTOOLS_DLL_DECL void* tc_valloc(size_t __size) __THROW; PERFTOOLS_DLL_DECL void* tc_pvalloc(size_t __size) __THROW; PERFTOOLS_DLL_DECL void tc_malloc_stats(void) __THROW; PERFTOOLS_DLL_DECL int tc_mallopt(int cmd, int value) __THROW; #if @ac_cv_have_struct_mallinfo@ PERFTOOLS_DLL_DECL struct mallinfo tc_mallinfo(void) __THROW; #endif // This is an alias for MallocExtension::instance()->GetAllocatedSize(). // It is equivalent to // OS X: malloc_size() // glibc: malloc_usable_size() // Windows: _msize() size_t tc_malloc_size(void* ptr) __THROW; #ifdef __cplusplus PERFTOOLS_DLL_DECL int tc_set_new_mode(int flag) __THROW; PERFTOOLS_DLL_DECL void* tc_new(size_t size); PERFTOOLS_DLL_DECL void* tc_new_nothrow(size_t size, const std::nothrow_t&) __THROW; PERFTOOLS_DLL_DECL void tc_delete(void* p) __THROW; PERFTOOLS_DLL_DECL void tc_delete_nothrow(void* p, const std::nothrow_t&) __THROW; PERFTOOLS_DLL_DECL void* tc_newarray(size_t size); PERFTOOLS_DLL_DECL void* tc_newarray_nothrow(size_t size, const std::nothrow_t&) __THROW; PERFTOOLS_DLL_DECL void tc_deletearray(void* p) __THROW; PERFTOOLS_DLL_DECL void tc_deletearray_nothrow(void* p, const std::nothrow_t&) __THROW; } #endif #endif // #ifndef TCMALLOC_TCMALLOC_H_ ================================================ FILE: distro/google-perftools-1.7/src/heap-checker-bcad.cc ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // All Rights Reserved. // // Author: Maxim Lifantsev // // A file to ensure that components of heap leak checker run before // all global object constructors and after all global object // destructors. // // This file must be the last library any binary links against. // Otherwise, the heap checker may not be able to run early enough to // catalog all the global objects in your program. If this happens, // and later in the program you allocate memory and have one of these // "uncataloged" global objects point to it, the heap checker will // consider that allocation to be a leak, even though it's not (since // the allocated object is reachable from global data and hence "live"). #include // for abort() #include // A dummy variable to refer from heap-checker.cc. This is to make // sure this file is not optimized out by the linker. bool heap_leak_checker_bcad_variable; extern void HeapLeakChecker_BeforeConstructors(); // in heap-checker.cc extern void HeapLeakChecker_AfterDestructors(); // in heap-checker.cc // A helper class to ensure that some components of heap leak checking // can happen before construction and after destruction // of all global/static objects. class HeapLeakCheckerGlobalPrePost { public: HeapLeakCheckerGlobalPrePost() { if (count_ == 0) { HeapLeakChecker_BeforeConstructors(); // This needs to be called before the first allocation of an STL // object, but after libc is done setting up threads (because it // calls setenv, which requires a thread-aware errno). By // putting it here, we hope it's the first bit of code executed // after the libc global-constructor code. MallocExtension::Initialize(); } ++count_; } ~HeapLeakCheckerGlobalPrePost() { if (count_ <= 0) abort(); --count_; if (count_ == 0) HeapLeakChecker_AfterDestructors(); } private: // Counter of constructions/destructions of objects of this class // (just in case there are more than one of them). static int count_; }; int HeapLeakCheckerGlobalPrePost::count_ = 0; // The early-construction/late-destruction global object. static const HeapLeakCheckerGlobalPrePost heap_leak_checker_global_pre_post; ================================================ FILE: distro/google-perftools-1.7/src/heap-checker.cc ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // All Rights Reserved. // // Author: Maxim Lifantsev // #include "config.h" #include // for O_RDONLY (we use syscall to do actual reads) #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_MMAP #include #endif #ifdef HAVE_PTHREAD #include #endif #include #include #include #include #ifdef HAVE_LINUX_PTRACE_H #include #endif #ifdef HAVE_SYS_SYSCALL_H #include #endif #if defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__MINGW32__) #include #include #undef ERROR // windows defines these as macros, which can cause trouble #undef max #undef min #endif #include #include #include #include #include #include #include #include "base/basictypes.h" #include "base/googleinit.h" #include "base/logging.h" #include #include "base/commandlineflags.h" #include "base/elfcore.h" // for i386_regs #include "base/thread_lister.h" #include "heap-profile-table.h" #include "base/low_level_alloc.h" #include "malloc_hook-inl.h" #include #include #include "maybe_threads.h" #include "memory_region_map.h" #include "base/spinlock.h" #include "base/sysinfo.h" #include "base/stl_allocator.h" using std::string; using std::basic_string; using std::pair; using std::map; using std::set; using std::vector; using std::swap; using std::make_pair; using std::min; using std::max; using std::less; using std::char_traits; // If current process is being ptrace()d, 'TracerPid' in /proc/self/status // will be non-zero. static bool IsDebuggerAttached(void) { // only works under linux, probably char buf[256]; // TracerPid comes relatively earlier in status output int fd = open("/proc/self/status", O_RDONLY); if (fd == -1) { return false; // Can't tell for sure. } const int len = read(fd, buf, sizeof(buf)); bool rc = false; if (len > 0) { const char *const kTracerPid = "TracerPid:\t"; buf[len - 1] = '\0'; const char *p = strstr(buf, kTracerPid); if (p != NULL) { rc = (strncmp(p + strlen(kTracerPid), "0\n", 2) != 0); } } close(fd); return rc; } // This is the default if you don't link in -lprofiler extern "C" { ATTRIBUTE_WEAK PERFTOOLS_DLL_DECL bool ProfilingIsEnabledForAllThreads(); bool ProfilingIsEnabledForAllThreads() { return false; } } //---------------------------------------------------------------------- // Flags that control heap-checking //---------------------------------------------------------------------- DEFINE_string(heap_check, EnvToString("HEAPCHECK", ""), "The heap leak checking to be done over the whole executable: " "\"minimal\", \"normal\", \"strict\", " "\"draconian\", \"as-is\", and \"local\" " " or the empty string are the supported choices. " "(See HeapLeakChecker::InternalInitStart for details.)"); DEFINE_bool(heap_check_report, true, "Obsolete"); DEFINE_bool(heap_check_before_constructors, true, "deprecated; pretty much always true now"); DEFINE_bool(heap_check_after_destructors, EnvToBool("HEAP_CHECK_AFTER_DESTRUCTORS", false), "If overall heap check is to end after global destructors " "or right after all REGISTER_HEAPCHECK_CLEANUP's"); DEFINE_bool(heap_check_strict_check, true, "Obsolete"); DEFINE_bool(heap_check_ignore_global_live, EnvToBool("HEAP_CHECK_IGNORE_GLOBAL_LIVE", true), "If overall heap check is to ignore heap objects reachable " "from the global data"); DEFINE_bool(heap_check_identify_leaks, EnvToBool("HEAP_CHECK_IDENTIFY_LEAKS", false), "If heap check should generate the addresses of the leaked " "objects in the memory leak profiles. This may be useful " "in tracking down leaks where only a small fraction of " "objects allocated at the same stack trace are leaked."); DEFINE_bool(heap_check_ignore_thread_live, EnvToBool("HEAP_CHECK_IGNORE_THREAD_LIVE", true), "If set to true, objects reachable from thread stacks " "and registers are not reported as leaks"); DEFINE_bool(heap_check_test_pointer_alignment, EnvToBool("HEAP_CHECK_TEST_POINTER_ALIGNMENT", false), "Set to true to check if the found leak can be due to " "use of unaligned pointers"); // Alignment at which all pointers in memory are supposed to be located; // use 1 if any alignment is ok. // heap_check_test_pointer_alignment flag guides if we try the value of 1. // The larger it can be, the lesser is the chance of missing real leaks. static const size_t kPointerSourceAlignment = sizeof(void*); DEFINE_int32(heap_check_pointer_source_alignment, EnvToInt("HEAP_CHECK_POINTER_SOURCE_ALIGNMENT", kPointerSourceAlignment), "Alignment at which all pointers in memory are supposed to be " "located. Use 1 if any alignment is ok."); // A reasonable default to handle pointers inside of typical class objects: // Too low and we won't be able to traverse pointers to normally-used // nested objects and base parts of multiple-inherited objects. // Too high and it will both slow down leak checking (FindInsideAlloc // in HaveOnHeapLocked will get slower when there are large on-heap objects) // and make it probabilistically more likely to miss leaks // of large-sized objects. static const int64 kHeapCheckMaxPointerOffset = 1024; DEFINE_int64(heap_check_max_pointer_offset, EnvToInt("HEAP_CHECK_MAX_POINTER_OFFSET", kHeapCheckMaxPointerOffset), "Largest pointer offset for which we traverse " "pointers going inside of heap allocated objects. " "Set to -1 to use the actual largest heap object size."); DEFINE_bool(heap_check_run_under_gdb, EnvToBool("HEAP_CHECK_RUN_UNDER_GDB", false), "If false, turns off heap-checking library when running under gdb " "(normally, set to 'true' only when debugging the heap-checker)"); DEFINE_int32(heap_check_delay_seconds, 0, "Number of seconds to delay on-exit heap checking." " If you set this flag," " you may also want to set exit_timeout_seconds in order to" " avoid exit timeouts.\n" "NOTE: This flag is to be used only to help diagnose issues" " where it is suspected that the heap checker is reporting" " false leaks that will disappear if the heap checker delays" " its checks. Report any such issues to the heap-checker" " maintainer(s)."); //---------------------------------------------------------------------- DEFINE_string(heap_profile_pprof, EnvToString("PPROF_PATH", "pprof"), "OBSOLETE; not used"); DEFINE_string(heap_check_dump_directory, EnvToString("HEAP_CHECK_DUMP_DIRECTORY", "/tmp"), "Directory to put heap-checker leak dump information"); //---------------------------------------------------------------------- // HeapLeakChecker global data //---------------------------------------------------------------------- // Global lock for all the global data of this module. static SpinLock heap_checker_lock(SpinLock::LINKER_INITIALIZED); //---------------------------------------------------------------------- // Heap profile prefix for leak checking profiles. // Gets assigned once when leak checking is turned on, then never modified. static const string* profile_name_prefix = NULL; // Whole-program heap leak checker. // Gets assigned once when leak checking is turned on, // then main_heap_checker is never deleted. static HeapLeakChecker* main_heap_checker = NULL; // Whether we will use main_heap_checker to do a check at program exit // automatically. In any case user can ask for more checks on main_heap_checker // via GlobalChecker(). static bool do_main_heap_check = false; // The heap profile we use to collect info about the heap. // This is created in HeapLeakChecker::BeforeConstructorsLocked // together with setting heap_checker_on (below) to true // and registering our new/delete malloc hooks; // similarly all are unset in HeapLeakChecker::TurnItselfOffLocked. static HeapProfileTable* heap_profile = NULL; // If we are doing (or going to do) any kind of heap-checking. static bool heap_checker_on = false; // pid of the process that does whole-program heap leak checking static pid_t heap_checker_pid = 0; // If we did heap profiling during global constructors execution static bool constructor_heap_profiling = false; // RAW_VLOG level we dump key INFO messages at. If you want to turn // off these messages, set the environment variable PERFTOOLS_VERBOSE=-1. static const int heap_checker_info_level = 0; //---------------------------------------------------------------------- // Cancel our InitialMallocHook_* if present. static void CancelInitialMallocHooks(); // defined below //---------------------------------------------------------------------- // HeapLeakChecker's own memory allocator that is // independent of the normal program allocator. //---------------------------------------------------------------------- // Wrapper of LowLevelAlloc for STL_Allocator and direct use. // We always access this class under held heap_checker_lock, // this allows us to in particular protect the period when threads are stopped // at random spots with ListAllProcessThreads by heap_checker_lock, // w/o worrying about the lock in LowLevelAlloc::Arena. // We rely on the fact that we use an own arena with an own lock here. class HeapLeakChecker::Allocator { public: static void Init() { RAW_DCHECK(heap_checker_lock.IsHeld(), ""); RAW_DCHECK(arena_ == NULL, ""); arena_ = LowLevelAlloc::NewArena(0, LowLevelAlloc::DefaultArena()); } static void Shutdown() { RAW_DCHECK(heap_checker_lock.IsHeld(), ""); if (!LowLevelAlloc::DeleteArena(arena_) || alloc_count_ != 0) { RAW_LOG(FATAL, "Internal heap checker leak of %d objects", alloc_count_); } } static int alloc_count() { RAW_DCHECK(heap_checker_lock.IsHeld(), ""); return alloc_count_; } static void* Allocate(size_t n) { RAW_DCHECK(arena_ && heap_checker_lock.IsHeld(), ""); void* p = LowLevelAlloc::AllocWithArena(n, arena_); if (p) alloc_count_ += 1; return p; } static void Free(void* p) { RAW_DCHECK(heap_checker_lock.IsHeld(), ""); if (p) alloc_count_ -= 1; LowLevelAlloc::Free(p); } static void Free(void* p, size_t /* n */) { Free(p); } // destruct, free, and make *p to be NULL template static void DeleteAndNull(T** p) { (*p)->~T(); Free(*p); *p = NULL; } template static void DeleteAndNullIfNot(T** p) { if (*p != NULL) DeleteAndNull(p); } private: static LowLevelAlloc::Arena* arena_; static int alloc_count_; }; LowLevelAlloc::Arena* HeapLeakChecker::Allocator::arena_ = NULL; int HeapLeakChecker::Allocator::alloc_count_ = 0; //---------------------------------------------------------------------- // HeapLeakChecker live object tracking components //---------------------------------------------------------------------- // Cases of live object placement we distinguish enum ObjectPlacement { MUST_BE_ON_HEAP, // Must point to a live object of the matching size in the // heap_profile map of the heap when we get to it IGNORED_ON_HEAP, // Is a live (ignored) object on heap MAYBE_LIVE, // Is a piece of writable memory from /proc/self/maps IN_GLOBAL_DATA, // Is part of global data region of the executable THREAD_DATA, // Part of a thread stack and a thread descriptor with TLS THREAD_REGISTERS, // Values in registers of some thread }; // Information about an allocated object struct AllocObject { const void* ptr; // the object uintptr_t size; // its size ObjectPlacement place; // where ptr points to AllocObject(const void* p, size_t s, ObjectPlacement l) : ptr(p), size(s), place(l) { } }; // All objects (memory ranges) ignored via HeapLeakChecker::IgnoreObject // Key is the object's address; value is its size. typedef map, STL_Allocator, HeapLeakChecker::Allocator> > IgnoredObjectsMap; static IgnoredObjectsMap* ignored_objects = NULL; // All objects (memory ranges) that we consider to be the sources of pointers // to live (not leaked) objects. // At different times this holds (what can be reached from) global data regions // and the objects we've been told to ignore. // For any AllocObject::ptr "live_objects" is supposed to contain at most one // record at any time. We maintain this by checking with the heap_profile map // of the heap and removing the live heap objects we've handled from it. // This vector is maintained as a stack and the frontier of reachable // live heap objects in our flood traversal of them. typedef vector > LiveObjectsStack; static LiveObjectsStack* live_objects = NULL; // A special string type that uses my allocator typedef basic_string, STL_Allocator > HCL_string; // A placeholder to fill-in the starting values for live_objects // for each library so we can keep the library-name association for logging. typedef map, STL_Allocator, HeapLeakChecker::Allocator> > LibraryLiveObjectsStacks; static LibraryLiveObjectsStacks* library_live_objects = NULL; // Value stored in the map of disabled address ranges; // its key is the end of the address range. // We'll ignore allocations with a return address in a disabled range // if the address occurs at 'max_depth' or less in the stack trace. struct HeapLeakChecker::RangeValue { uintptr_t start_address; // the start of the range int max_depth; // the maximal stack depth to disable at }; typedef map, STL_Allocator, HeapLeakChecker::Allocator> > DisabledRangeMap; // The disabled program counter address ranges for profile dumping // that are registered with HeapLeakChecker::DisableChecksFromToLocked. static DisabledRangeMap* disabled_ranges = NULL; // Set of stack tops. // These are used to consider live only appropriate chunks of the memory areas // that are used for stacks (and maybe thread-specific data as well) // so that we do not treat pointers from outdated stack frames as live. typedef set, STL_Allocator > StackTopSet; static StackTopSet* stack_tops = NULL; // A map of ranges of code addresses for the system libraries // that can mmap/mremap/sbrk-allocate memory regions for stacks // and thread-local storage that we want to consider as live global data. // Maps from the end address to the start address. typedef map, STL_Allocator, HeapLeakChecker::Allocator> > GlobalRegionCallerRangeMap; static GlobalRegionCallerRangeMap* global_region_caller_ranges = NULL; // TODO(maxim): make our big data structs into own modules // Disabler is implemented by keeping track of a per-thread count // of active Disabler objects. Any objects allocated while the // count > 0 are not reported. #ifdef HAVE_TLS static __thread int thread_disable_counter // The "inital exec" model is faster than the default TLS model, at // the cost you can't dlopen this library. But dlopen on heap-checker // doesn't work anyway -- it must run before main -- so this is a good // trade-off. # ifdef HAVE___ATTRIBUTE__ __attribute__ ((tls_model ("initial-exec"))) # endif ; inline int get_thread_disable_counter() { return thread_disable_counter; } inline void set_thread_disable_counter(int value) { thread_disable_counter = value; } #else // #ifdef HAVE_TLS static pthread_key_t thread_disable_counter_key; static int main_thread_counter; // storage for use before main() static bool use_main_thread_counter = true; // TODO(csilvers): this is called from NewHook, in the middle of malloc(). // If perftools_pthread_getspecific calls malloc, that will lead to an // infinite loop. I don't know how to fix that, so I hope it never happens! inline int get_thread_disable_counter() { if (use_main_thread_counter) // means we're running really early return main_thread_counter; void* p = perftools_pthread_getspecific(thread_disable_counter_key); return (intptr_t)p; // kinda evil: store the counter directly in the void* } inline void set_thread_disable_counter(int value) { if (use_main_thread_counter) { // means we're running really early main_thread_counter = value; return; } intptr_t pointer_sized_value = value; // kinda evil: store the counter directly in the void* void* p = (void*)pointer_sized_value; // NOTE: this may call malloc, which will call NewHook which will call // get_thread_disable_counter() which will call pthread_getspecific(). I // don't know if anything bad can happen if we call getspecific() in the // middle of a setspecific() call. It seems to work ok in practice... perftools_pthread_setspecific(thread_disable_counter_key, p); } // The idea here is that this initializer will run pretty late: after // pthreads have been totally set up. At this point we can call // pthreads routines, so we set those up. class InitThreadDisableCounter { public: InitThreadDisableCounter() { perftools_pthread_key_create(&thread_disable_counter_key, NULL); // Set up the main thread's value, which we have a special variable for. void* p = (void*)main_thread_counter; // store the counter directly perftools_pthread_setspecific(thread_disable_counter_key, p); use_main_thread_counter = false; } }; InitThreadDisableCounter init_thread_disable_counter; #endif // #ifdef HAVE_TLS HeapLeakChecker::Disabler::Disabler() { // It is faster to unconditionally increment the thread-local // counter than to check whether or not heap-checking is on // in a thread-safe manner. int counter = get_thread_disable_counter(); set_thread_disable_counter(counter + 1); RAW_VLOG(10, "Increasing thread disable counter to %d", counter + 1); } HeapLeakChecker::Disabler::~Disabler() { int counter = get_thread_disable_counter(); RAW_DCHECK(counter > 0, ""); if (counter > 0) { set_thread_disable_counter(counter - 1); RAW_VLOG(10, "Decreasing thread disable counter to %d", counter); } else { RAW_VLOG(0, "Thread disable counter underflow : %d", counter); } } //---------------------------------------------------------------------- // The size of the largest heap object allocated so far. static size_t max_heap_object_size = 0; // The possible range of addresses that can point // into one of the elements of heap_objects. static uintptr_t min_heap_address = uintptr_t(-1LL); static uintptr_t max_heap_address = 0; //---------------------------------------------------------------------- // Simple casting helpers for uintptr_t and void*: template inline static const void* AsPtr(T addr) { return reinterpret_cast(addr); } inline static uintptr_t AsInt(const void* ptr) { return reinterpret_cast(ptr); } //---------------------------------------------------------------------- // Our hooks for MallocHook static void NewHook(const void* ptr, size_t size) { if (ptr != NULL) { const int counter = get_thread_disable_counter(); const bool ignore = (counter > 0); RAW_VLOG(16, "Recording Alloc: %p of %"PRIuS "; %d", ptr, size, int(counter)); { SpinLockHolder l(&heap_checker_lock); if (size > max_heap_object_size) max_heap_object_size = size; uintptr_t addr = AsInt(ptr); if (addr < min_heap_address) min_heap_address = addr; addr += size; if (addr > max_heap_address) max_heap_address = addr; if (heap_checker_on) { heap_profile->RecordAlloc(ptr, size, 0); if (ignore) { heap_profile->MarkAsIgnored(ptr); } } } RAW_VLOG(17, "Alloc Recorded: %p of %"PRIuS"", ptr, size); } } static void DeleteHook(const void* ptr) { if (ptr != NULL) { RAW_VLOG(16, "Recording Free %p", ptr); { SpinLockHolder l(&heap_checker_lock); if (heap_checker_on) heap_profile->RecordFree(ptr); } RAW_VLOG(17, "Free Recorded: %p", ptr); } } //---------------------------------------------------------------------- enum StackDirection { GROWS_TOWARDS_HIGH_ADDRESSES, GROWS_TOWARDS_LOW_ADDRESSES, UNKNOWN_DIRECTION }; // Determine which way the stack grows: static StackDirection ATTRIBUTE_NOINLINE GetStackDirection( const uintptr_t *const ptr) { uintptr_t x; if (&x < ptr) return GROWS_TOWARDS_LOW_ADDRESSES; if (ptr < &x) return GROWS_TOWARDS_HIGH_ADDRESSES; RAW_CHECK(0, ""); // Couldn't determine the stack direction. return UNKNOWN_DIRECTION; } // Direction of stack growth (will initialize via GetStackDirection()) static StackDirection stack_direction = UNKNOWN_DIRECTION; // This routine is called for every thread stack we know about to register it. static void RegisterStackLocked(const void* top_ptr) { RAW_DCHECK(heap_checker_lock.IsHeld(), ""); RAW_DCHECK(MemoryRegionMap::LockIsHeld(), ""); RAW_VLOG(10, "Thread stack at %p", top_ptr); uintptr_t top = AsInt(top_ptr); stack_tops->insert(top); // add for later use // make sure stack_direction is initialized if (stack_direction == UNKNOWN_DIRECTION) { stack_direction = GetStackDirection(&top); } // Find memory region with this stack MemoryRegionMap::Region region; if (MemoryRegionMap::FindAndMarkStackRegion(top, ®ion)) { // Make the proper portion of the stack live: if (stack_direction == GROWS_TOWARDS_LOW_ADDRESSES) { RAW_VLOG(11, "Live stack at %p of %"PRIuPTR" bytes", top_ptr, region.end_addr - top); live_objects->push_back(AllocObject(top_ptr, region.end_addr - top, THREAD_DATA)); } else { // GROWS_TOWARDS_HIGH_ADDRESSES RAW_VLOG(11, "Live stack at %p of %"PRIuPTR" bytes", AsPtr(region.start_addr), top - region.start_addr); live_objects->push_back(AllocObject(AsPtr(region.start_addr), top - region.start_addr, THREAD_DATA)); } // not in MemoryRegionMap, look in library_live_objects: } else if (FLAGS_heap_check_ignore_global_live) { for (LibraryLiveObjectsStacks::iterator lib = library_live_objects->begin(); lib != library_live_objects->end(); ++lib) { for (LiveObjectsStack::iterator span = lib->second.begin(); span != lib->second.end(); ++span) { uintptr_t start = AsInt(span->ptr); uintptr_t end = start + span->size; if (start <= top && top < end) { RAW_VLOG(11, "Stack at %p is inside /proc/self/maps chunk %p..%p", top_ptr, AsPtr(start), AsPtr(end)); // Shrink start..end region by chopping away the memory regions in // MemoryRegionMap that land in it to undo merging of regions // in /proc/self/maps, so that we correctly identify what portion // of start..end is actually the stack region. uintptr_t stack_start = start; uintptr_t stack_end = end; // can optimize-away this loop, but it does not run often RAW_DCHECK(MemoryRegionMap::LockIsHeld(), ""); for (MemoryRegionMap::RegionIterator r = MemoryRegionMap::BeginRegionLocked(); r != MemoryRegionMap::EndRegionLocked(); ++r) { if (top < r->start_addr && r->start_addr < stack_end) { stack_end = r->start_addr; } if (stack_start < r->end_addr && r->end_addr <= top) { stack_start = r->end_addr; } } if (stack_start != start || stack_end != end) { RAW_VLOG(11, "Stack at %p is actually inside memory chunk %p..%p", top_ptr, AsPtr(stack_start), AsPtr(stack_end)); } // Make the proper portion of the stack live: if (stack_direction == GROWS_TOWARDS_LOW_ADDRESSES) { RAW_VLOG(11, "Live stack at %p of %"PRIuPTR" bytes", top_ptr, stack_end - top); live_objects->push_back( AllocObject(top_ptr, stack_end - top, THREAD_DATA)); } else { // GROWS_TOWARDS_HIGH_ADDRESSES RAW_VLOG(11, "Live stack at %p of %"PRIuPTR" bytes", AsPtr(stack_start), top - stack_start); live_objects->push_back( AllocObject(AsPtr(stack_start), top - stack_start, THREAD_DATA)); } lib->second.erase(span); // kill the rest of the region // Put the non-stack part(s) of the region back: if (stack_start != start) { lib->second.push_back(AllocObject(AsPtr(start), stack_start - start, MAYBE_LIVE)); } if (stack_end != end) { lib->second.push_back(AllocObject(AsPtr(stack_end), end - stack_end, MAYBE_LIVE)); } return; } } } RAW_LOG(ERROR, "Memory region for stack at %p not found. " "Will likely report false leak positives.", top_ptr); } } // Iterator for heap allocation map data to make ignored objects "live" // (i.e., treated as roots for the mark-and-sweep phase) static void MakeIgnoredObjectsLiveCallbackLocked( const void* ptr, const HeapProfileTable::AllocInfo& info) { RAW_DCHECK(heap_checker_lock.IsHeld(), ""); if (info.ignored) { live_objects->push_back(AllocObject(ptr, info.object_size, MUST_BE_ON_HEAP)); } } // Iterator for heap allocation map data to make objects allocated from // disabled regions of code to be live. static void MakeDisabledLiveCallbackLocked( const void* ptr, const HeapProfileTable::AllocInfo& info) { RAW_DCHECK(heap_checker_lock.IsHeld(), ""); bool stack_disable = false; bool range_disable = false; for (int depth = 0; depth < info.stack_depth; depth++) { uintptr_t addr = AsInt(info.call_stack[depth]); if (disabled_ranges) { DisabledRangeMap::const_iterator iter = disabled_ranges->upper_bound(addr); if (iter != disabled_ranges->end()) { RAW_DCHECK(iter->first > addr, ""); if (iter->second.start_address < addr && iter->second.max_depth > depth) { range_disable = true; // in range; dropping break; } } } } if (stack_disable || range_disable) { uintptr_t start_address = AsInt(ptr); uintptr_t end_address = start_address + info.object_size; StackTopSet::const_iterator iter = stack_tops->lower_bound(start_address); if (iter != stack_tops->end()) { RAW_DCHECK(*iter >= start_address, ""); if (*iter < end_address) { // We do not disable (treat as live) whole allocated regions // if they are used to hold thread call stacks // (i.e. when we find a stack inside). // The reason is that we'll treat as live the currently used // stack portions anyway (see RegisterStackLocked), // and the rest of the region where the stack lives can well // contain outdated stack variables which are not live anymore, // hence should not be treated as such. RAW_VLOG(11, "Not %s-disabling %"PRIuS" bytes at %p" ": have stack inside: %p", (stack_disable ? "stack" : "range"), info.object_size, ptr, AsPtr(*iter)); return; } } RAW_VLOG(11, "%s-disabling %"PRIuS" bytes at %p", (stack_disable ? "Stack" : "Range"), info.object_size, ptr); live_objects->push_back(AllocObject(ptr, info.object_size, MUST_BE_ON_HEAP)); } } // This function takes some fields from a /proc/self/maps line: // // start_address start address of a memory region. // end_address end address of a memory region // permissions rwx + private/shared bit // filename filename of the mapped file // // If the region is not writeable, then it cannot have any heap // pointers in it, otherwise we record it as a candidate live region // to get filtered later. static void RecordGlobalDataLocked(uintptr_t start_address, uintptr_t end_address, const char* permissions, const char* filename) { RAW_DCHECK(heap_checker_lock.IsHeld(), ""); // Ignore non-writeable regions. if (strchr(permissions, 'w') == NULL) return; if (filename == NULL || *filename == '\0') filename = "UNNAMED"; RAW_VLOG(11, "Looking into %s: 0x%" PRIxPTR "..0x%" PRIxPTR, filename, start_address, end_address); (*library_live_objects)[filename]. push_back(AllocObject(AsPtr(start_address), end_address - start_address, MAYBE_LIVE)); } // See if 'library' from /proc/self/maps has base name 'library_base' // i.e. contains it and has '.' or '-' after it. static bool IsLibraryNamed(const char* library, const char* library_base) { const char* p = strstr(library, library_base); size_t sz = strlen(library_base); return p != NULL && (p[sz] == '.' || p[sz] == '-'); } // static void HeapLeakChecker::DisableLibraryAllocsLocked(const char* library, uintptr_t start_address, uintptr_t end_address) { RAW_DCHECK(heap_checker_lock.IsHeld(), ""); int depth = 0; // TODO(maxim): maybe this should be extended to also use objdump // and pick the text portion of the library more precisely. if (IsLibraryNamed(library, "/libpthread") || // libpthread has a lot of small "system" leaks we don't care about. // In particular it allocates memory to store data supplied via // pthread_setspecific (which can be the only pointer to a heap object). IsLibraryNamed(library, "/libdl") || // library loaders leak some "system" heap that we don't care about IsLibraryNamed(library, "/libcrypto") || // Sometimes libcrypto of OpenSSH is compiled with -fomit-frame-pointer // (any library can be, of course, but this one often is because speed // is so important for making crypto usable). We ignore all its // allocations because we can't see the call stacks. We'd prefer // to ignore allocations done in files/symbols that match // "default_malloc_ex|default_realloc_ex" // but that doesn't work when the end-result binary is stripped. IsLibraryNamed(library, "/libjvm") || // JVM has a lot of leaks we don't care about. IsLibraryNamed(library, "/libzip") // The JVM leaks java.util.zip.Inflater after loading classes. ) { depth = 1; // only disable allocation calls directly from the library code } else if (IsLibraryNamed(library, "/ld") // library loader leaks some "system" heap // (e.g. thread-local storage) that we don't care about ) { depth = 2; // disable allocation calls directly from the library code // and at depth 2 from it. // We need depth 2 here solely because of a libc bug that // forces us to jump through __memalign_hook and MemalignOverride hoops // in tcmalloc.cc. // Those buggy __libc_memalign() calls are in ld-linux.so and happen for // thread-local storage allocations that we want to ignore here. // We go with the depth-2 hack as a workaround for this libc bug: // otherwise we'd need to extend MallocHook interface // so that correct stack depth adjustment can be propagated from // the exceptional case of MemalignOverride. // Using depth 2 here should not mask real leaks because ld-linux.so // does not call user code. } if (depth) { RAW_VLOG(10, "Disabling allocations from %s at depth %d:", library, depth); DisableChecksFromToLocked(AsPtr(start_address), AsPtr(end_address), depth); if (IsLibraryNamed(library, "/libpthread") || IsLibraryNamed(library, "/libdl") || IsLibraryNamed(library, "/ld")) { RAW_VLOG(10, "Global memory regions made by %s will be live data", library); if (global_region_caller_ranges == NULL) { global_region_caller_ranges = new(Allocator::Allocate(sizeof(GlobalRegionCallerRangeMap))) GlobalRegionCallerRangeMap; } global_region_caller_ranges ->insert(make_pair(end_address, start_address)); } } } // static HeapLeakChecker::ProcMapsResult HeapLeakChecker::UseProcMapsLocked( ProcMapsTask proc_maps_task) { RAW_DCHECK(heap_checker_lock.IsHeld(), ""); // Need to provide own scratch memory to ProcMapsIterator: ProcMapsIterator::Buffer buffer; ProcMapsIterator it(0, &buffer); if (!it.Valid()) { int errsv = errno; RAW_LOG(ERROR, "Could not open /proc/self/maps: errno=%d. " "Libraries will not be handled correctly.", errsv); return CANT_OPEN_PROC_MAPS; } uint64 start_address, end_address, file_offset; int64 inode; char *permissions, *filename; bool saw_shared_lib = false; while (it.Next(&start_address, &end_address, &permissions, &file_offset, &inode, &filename)) { if (start_address >= end_address) { // Warn if a line we can be interested in is ill-formed: if (inode != 0) { RAW_LOG(ERROR, "Errors reading /proc/self/maps. " "Some global memory regions will not " "be handled correctly."); } // Silently skip other ill-formed lines: some are possible // probably due to the interplay of how /proc/self/maps is updated // while we read it in chunks in ProcMapsIterator and // do things in this loop. continue; } // Determine if any shared libraries are present. if (inode != 0 && strstr(filename, "lib") && strstr(filename, ".so")) { saw_shared_lib = true; } switch (proc_maps_task) { case DISABLE_LIBRARY_ALLOCS: // All lines starting like // "401dc000-4030f000 r??p 00132000 03:01 13991972 lib/bin" // identify a data and code sections of a shared library or our binary if (inode != 0 && strncmp(permissions, "r-xp", 4) == 0) { DisableLibraryAllocsLocked(filename, start_address, end_address); } break; case RECORD_GLOBAL_DATA: RecordGlobalDataLocked(start_address, end_address, permissions, filename); break; default: RAW_CHECK(0, ""); } } if (!saw_shared_lib) { RAW_LOG(ERROR, "No shared libs detected. Will likely report false leak " "positives for statically linked executables."); return NO_SHARED_LIBS_IN_PROC_MAPS; } return PROC_MAPS_USED; } // Total number and size of live objects dropped from the profile; // (re)initialized in IgnoreAllLiveObjectsLocked. static int64 live_objects_total; static int64 live_bytes_total; // pid of the thread that is doing the current leak check // (protected by our lock; IgnoreAllLiveObjectsLocked sets it) static pid_t self_thread_pid = 0; // Status of our thread listing callback execution // (protected by our lock; used from within IgnoreAllLiveObjectsLocked) static enum { CALLBACK_NOT_STARTED, CALLBACK_STARTED, CALLBACK_COMPLETED, } thread_listing_status = CALLBACK_NOT_STARTED; // Ideally to avoid deadlocks this function should not result in any libc // or other function calls that might need to lock a mutex: // It is called when all threads of a process are stopped // at arbitrary points thus potentially holding those locks. // // In practice we are calling some simple i/o and sprintf-type library functions // for logging messages, but use only our own LowLevelAlloc::Arena allocator. // // This is known to be buggy: the library i/o function calls are able to cause // deadlocks when they request a lock that a stopped thread happens to hold. // This issue as far as we know have so far not resulted in any deadlocks // in practice, so for now we are taking our chance that the deadlocks // have insignificant frequency. // // If such deadlocks become a problem we should make the i/o calls // into appropriately direct system calls (or eliminate them), // in particular write() is not safe and vsnprintf() is potentially dangerous // due to reliance on locale functions (these are called through RAW_LOG // and in other ways). // /*static*/ int HeapLeakChecker::IgnoreLiveThreadsLocked(void* parameter, int num_threads, pid_t* thread_pids, va_list /*ap*/) { RAW_DCHECK(heap_checker_lock.IsHeld(), ""); thread_listing_status = CALLBACK_STARTED; RAW_VLOG(11, "Found %d threads (from pid %d)", num_threads, getpid()); if (FLAGS_heap_check_ignore_global_live) { UseProcMapsLocked(RECORD_GLOBAL_DATA); } // We put the registers from other threads here // to make pointers stored in them live. vector > thread_registers; int failures = 0; for (int i = 0; i < num_threads; ++i) { // the leak checking thread itself is handled // specially via self_thread_stack, not here: if (thread_pids[i] == self_thread_pid) continue; RAW_VLOG(11, "Handling thread with pid %d", thread_pids[i]); #if (defined(__i386__) || defined(__x86_64)) && \ defined(HAVE_LINUX_PTRACE_H) && defined(HAVE_SYS_SYSCALL_H) && defined(DUMPER) i386_regs thread_regs; #define sys_ptrace(r, p, a, d) syscall(SYS_ptrace, (r), (p), (a), (d)) // We use sys_ptrace to avoid thread locking // because this is called from ListAllProcessThreads // when all but this thread are suspended. if (sys_ptrace(PTRACE_GETREGS, thread_pids[i], NULL, &thread_regs) == 0) { // Need to use SP to get all the data from the very last stack frame: COMPILE_ASSERT(sizeof(thread_regs.SP) == sizeof(void*), SP_register_does_not_look_like_a_pointer); RegisterStackLocked(reinterpret_cast(thread_regs.SP)); // Make registers live (just in case PTRACE_ATTACH resulted in some // register pointers still being in the registers and not on the stack): for (void** p = reinterpret_cast(&thread_regs); p < reinterpret_cast(&thread_regs + 1); ++p) { RAW_VLOG(12, "Thread register %p", *p); thread_registers.push_back(*p); } } else { failures += 1; } #else failures += 1; #endif } // Use all the collected thread (stack) liveness sources: IgnoreLiveObjectsLocked("threads stack data", ""); if (thread_registers.size()) { // Make thread registers be live heap data sources. // we rely here on the fact that vector is in one memory chunk: RAW_VLOG(11, "Live registers at %p of %"PRIuS" bytes", &thread_registers[0], thread_registers.size() * sizeof(void*)); live_objects->push_back(AllocObject(&thread_registers[0], thread_registers.size() * sizeof(void*), THREAD_REGISTERS)); IgnoreLiveObjectsLocked("threads register data", ""); } // Do all other liveness walking while all threads are stopped: IgnoreNonThreadLiveObjectsLocked(); // Can now resume the threads: ResumeAllProcessThreads(num_threads, thread_pids); thread_listing_status = CALLBACK_COMPLETED; return failures; } // Stack top of the thread that is doing the current leak check // (protected by our lock; IgnoreAllLiveObjectsLocked sets it) static const void* self_thread_stack_top; // static void HeapLeakChecker::IgnoreNonThreadLiveObjectsLocked() { RAW_DCHECK(heap_checker_lock.IsHeld(), ""); RAW_DCHECK(MemoryRegionMap::LockIsHeld(), ""); RAW_VLOG(11, "Handling self thread with pid %d", self_thread_pid); // Register our own stack: // Important that all stack ranges (including the one here) // are known before we start looking at them // in MakeDisabledLiveCallbackLocked: RegisterStackLocked(self_thread_stack_top); IgnoreLiveObjectsLocked("stack data", ""); // Make objects we were told to ignore live: if (ignored_objects) { for (IgnoredObjectsMap::const_iterator object = ignored_objects->begin(); object != ignored_objects->end(); ++object) { const void* ptr = AsPtr(object->first); RAW_VLOG(11, "Ignored live object at %p of %"PRIuS" bytes", ptr, object->second); live_objects-> push_back(AllocObject(ptr, object->second, MUST_BE_ON_HEAP)); // we do this liveness check for ignored_objects before doing any // live heap walking to make sure it does not fail needlessly: size_t object_size; if (!(heap_profile->FindAlloc(ptr, &object_size) && object->second == object_size)) { RAW_LOG(FATAL, "Object at %p of %"PRIuS" bytes from an" " IgnoreObject() has disappeared", ptr, object->second); } } IgnoreLiveObjectsLocked("ignored objects", ""); } // Treat objects that were allocated when a Disabler was live as // roots. I.e., if X was allocated while a Disabler was active, // and Y is reachable from X, arrange that neither X nor Y are // treated as leaks. heap_profile->IterateAllocs(MakeIgnoredObjectsLiveCallbackLocked); IgnoreLiveObjectsLocked("disabled objects", ""); // Make code-address-disabled objects live and ignored: // This in particular makes all thread-specific data live // because the basic data structure to hold pointers to thread-specific data // is allocated from libpthreads and we have range-disabled that // library code with UseProcMapsLocked(DISABLE_LIBRARY_ALLOCS); // so now we declare all thread-specific data reachable from there as live. heap_profile->IterateAllocs(MakeDisabledLiveCallbackLocked); IgnoreLiveObjectsLocked("disabled code", ""); // Actually make global data live: if (FLAGS_heap_check_ignore_global_live) { bool have_null_region_callers = false; for (LibraryLiveObjectsStacks::iterator l = library_live_objects->begin(); l != library_live_objects->end(); ++l) { RAW_CHECK(live_objects->empty(), ""); // Process library_live_objects in l->second // filtering them by MemoryRegionMap: // It's safe to iterate over MemoryRegionMap // w/o locks here as we are inside MemoryRegionMap::Lock(): RAW_DCHECK(MemoryRegionMap::LockIsHeld(), ""); // The only change to MemoryRegionMap possible in this loop // is region addition as a result of allocating more memory // for live_objects. This won't invalidate the RegionIterator // or the intent of the loop. // --see the comment by MemoryRegionMap::BeginRegionLocked(). for (MemoryRegionMap::RegionIterator region = MemoryRegionMap::BeginRegionLocked(); region != MemoryRegionMap::EndRegionLocked(); ++region) { // "region" from MemoryRegionMap is to be subtracted from // (tentatively live) regions in l->second // if it has a stack inside or it was allocated by // a non-special caller (not one covered by a range // in global_region_caller_ranges). // This will in particular exclude all memory chunks used // by the heap itself as well as what's been allocated with // any allocator on top of mmap. bool subtract = true; if (!region->is_stack && global_region_caller_ranges) { if (region->caller() == static_cast(NULL)) { have_null_region_callers = true; } else { GlobalRegionCallerRangeMap::const_iterator iter = global_region_caller_ranges->upper_bound(region->caller()); if (iter != global_region_caller_ranges->end()) { RAW_DCHECK(iter->first > region->caller(), ""); if (iter->second < region->caller()) { // in special region subtract = false; } } } } if (subtract) { // The loop puts the result of filtering l->second into live_objects: for (LiveObjectsStack::const_iterator i = l->second.begin(); i != l->second.end(); ++i) { // subtract *region from *i uintptr_t start = AsInt(i->ptr); uintptr_t end = start + i->size; if (region->start_addr <= start && end <= region->end_addr) { // full deletion due to subsumption } else if (start < region->start_addr && region->end_addr < end) { // cutting-out split live_objects->push_back(AllocObject(i->ptr, region->start_addr - start, IN_GLOBAL_DATA)); live_objects->push_back(AllocObject(AsPtr(region->end_addr), end - region->end_addr, IN_GLOBAL_DATA)); } else if (region->end_addr > start && region->start_addr <= start) { // cut from start live_objects->push_back(AllocObject(AsPtr(region->end_addr), end - region->end_addr, IN_GLOBAL_DATA)); } else if (region->start_addr > start && region->start_addr < end) { // cut from end live_objects->push_back(AllocObject(i->ptr, region->start_addr - start, IN_GLOBAL_DATA)); } else { // pass: no intersection live_objects->push_back(AllocObject(i->ptr, i->size, IN_GLOBAL_DATA)); } } // Move live_objects back into l->second // for filtering by the next region. live_objects->swap(l->second); live_objects->clear(); } } // Now get and use live_objects from the final version of l->second: if (VLOG_IS_ON(11)) { for (LiveObjectsStack::const_iterator i = l->second.begin(); i != l->second.end(); ++i) { RAW_VLOG(11, "Library live region at %p of %"PRIuPTR" bytes", i->ptr, i->size); } } live_objects->swap(l->second); IgnoreLiveObjectsLocked("in globals of\n ", l->first.c_str()); } if (have_null_region_callers) { RAW_LOG(ERROR, "Have memory regions w/o callers: " "might report false leaks"); } Allocator::DeleteAndNull(&library_live_objects); } } // Callback for ListAllProcessThreads in IgnoreAllLiveObjectsLocked below // to test/verify that we have just the one main thread, in which case // we can do everything in that main thread, // so that CPU profiler can collect all its samples. // Returns the number of threads in the process. static int IsOneThread(void* parameter, int num_threads, pid_t* thread_pids, va_list ap) { if (num_threads != 1) { RAW_LOG(WARNING, "Have threads: Won't CPU-profile the bulk of leak " "checking work happening in IgnoreLiveThreadsLocked!"); } ResumeAllProcessThreads(num_threads, thread_pids); return num_threads; } // Dummy for IgnoreAllLiveObjectsLocked below. // Making it global helps with compiler warnings. static va_list dummy_ap; // static void HeapLeakChecker::IgnoreAllLiveObjectsLocked(const void* self_stack_top) { RAW_DCHECK(heap_checker_lock.IsHeld(), ""); RAW_CHECK(live_objects == NULL, ""); live_objects = new(Allocator::Allocate(sizeof(LiveObjectsStack))) LiveObjectsStack; stack_tops = new(Allocator::Allocate(sizeof(StackTopSet))) StackTopSet; // reset the counts live_objects_total = 0; live_bytes_total = 0; // Reduce max_heap_object_size to FLAGS_heap_check_max_pointer_offset // for the time of leak check. // FLAGS_heap_check_max_pointer_offset caps max_heap_object_size // to manage reasonably low chances of random bytes // appearing to be pointing into large actually leaked heap objects. const size_t old_max_heap_object_size = max_heap_object_size; max_heap_object_size = ( FLAGS_heap_check_max_pointer_offset != -1 ? min(size_t(FLAGS_heap_check_max_pointer_offset), max_heap_object_size) : max_heap_object_size); // Record global data as live: if (FLAGS_heap_check_ignore_global_live) { library_live_objects = new(Allocator::Allocate(sizeof(LibraryLiveObjectsStacks))) LibraryLiveObjectsStacks; } // Ignore all thread stacks: thread_listing_status = CALLBACK_NOT_STARTED; bool need_to_ignore_non_thread_objects = true; self_thread_pid = getpid(); self_thread_stack_top = self_stack_top; if (FLAGS_heap_check_ignore_thread_live) { // In case we are doing CPU profiling we'd like to do all the work // in the main thread, not in the special thread created by // ListAllProcessThreads, so that CPU profiler can collect all its samples. // The machinery of ListAllProcessThreads conflicts with the CPU profiler // by also relying on signals and ::sigaction. // We can do this (run everything in the main thread) safely // only if there's just the main thread itself in our process. // This variable reflects these two conditions: bool want_and_can_run_in_main_thread = ProfilingIsEnabledForAllThreads() && ListAllProcessThreads(NULL, IsOneThread) == 1; // When the normal path of ListAllProcessThreads below is taken, // we fully suspend the threads right here before any liveness checking // and keep them suspended for the whole time of liveness checking // inside of the IgnoreLiveThreadsLocked callback. // (The threads can't (de)allocate due to lock on the delete hook but // if not suspended they could still mess with the pointer // graph while we walk it). int r = want_and_can_run_in_main_thread ? IgnoreLiveThreadsLocked(NULL, 1, &self_thread_pid, dummy_ap) : ListAllProcessThreads(NULL, IgnoreLiveThreadsLocked); need_to_ignore_non_thread_objects = r < 0; if (r < 0) { RAW_LOG(WARNING, "Thread finding failed with %d errno=%d", r, errno); if (thread_listing_status == CALLBACK_COMPLETED) { RAW_LOG(INFO, "Thread finding callback " "finished ok; hopefully everything is fine"); need_to_ignore_non_thread_objects = false; } else if (thread_listing_status == CALLBACK_STARTED) { RAW_LOG(FATAL, "Thread finding callback was " "interrupted or crashed; can't fix this"); } else { // CALLBACK_NOT_STARTED RAW_LOG(ERROR, "Could not find thread stacks. " "Will likely report false leak positives."); } } else if (r != 0) { RAW_LOG(ERROR, "Thread stacks not found for %d threads. " "Will likely report false leak positives.", r); } else { RAW_VLOG(11, "Thread stacks appear to be found for all threads"); } } else { RAW_LOG(WARNING, "Not looking for thread stacks; " "objects reachable only from there " "will be reported as leaks"); } // Do all other live data ignoring here if we did not do it // within thread listing callback with all threads stopped. if (need_to_ignore_non_thread_objects) { if (FLAGS_heap_check_ignore_global_live) { UseProcMapsLocked(RECORD_GLOBAL_DATA); } IgnoreNonThreadLiveObjectsLocked(); } if (live_objects_total) { RAW_VLOG(10, "Ignoring %"PRId64" reachable objects of %"PRId64" bytes", live_objects_total, live_bytes_total); } // Free these: we made them here and heap_profile never saw them Allocator::DeleteAndNull(&live_objects); Allocator::DeleteAndNull(&stack_tops); max_heap_object_size = old_max_heap_object_size; // reset this var } // Alignment at which we should consider pointer positions // in IgnoreLiveObjectsLocked. Will normally use the value of // FLAGS_heap_check_pointer_source_alignment. static size_t pointer_source_alignment = kPointerSourceAlignment; // Global lock for HeapLeakChecker::DoNoLeaks // to protect pointer_source_alignment. static SpinLock alignment_checker_lock(SpinLock::LINKER_INITIALIZED); // This function changes the live bits in the heap_profile-table's state: // we only record the live objects to be skipped. // // When checking if a byte sequence points to a heap object we use // HeapProfileTable::FindInsideAlloc to handle both pointers to // the start and inside of heap-allocated objects. // The "inside" case needs to be checked to support // at least the following relatively common cases: // - C++ arrays allocated with new FooClass[size] for classes // with destructors have their size recorded in a sizeof(int) field // before the place normal pointers point to. // - basic_string<>-s for e.g. the C++ library of gcc 3.4 // have the meta-info in basic_string<...>::_Rep recorded // before the place normal pointers point to. // - Multiple-inherited objects have their pointers when cast to // different base classes pointing inside of the actually // allocated object. // - Sometimes reachability pointers point to member objects of heap objects, // and then those member objects point to the full heap object. // - Third party UnicodeString: it stores a 32-bit refcount // (in both 32-bit and 64-bit binaries) as the first uint32 // in the allocated memory and a normal pointer points at // the second uint32 behind the refcount. // By finding these additional objects here // we slightly increase the chance to mistake random memory bytes // for a pointer and miss a leak in a particular run of a binary. // /*static*/ void HeapLeakChecker::IgnoreLiveObjectsLocked(const char* name, const char* name2) { RAW_DCHECK(heap_checker_lock.IsHeld(), ""); int64 live_object_count = 0; int64 live_byte_count = 0; while (!live_objects->empty()) { const char* object = reinterpret_cast(live_objects->back().ptr); size_t size = live_objects->back().size; const ObjectPlacement place = live_objects->back().place; live_objects->pop_back(); if (place == MUST_BE_ON_HEAP && heap_profile->MarkAsLive(object)) { live_object_count += 1; live_byte_count += size; } RAW_VLOG(13, "Looking for heap pointers in %p of %"PRIuS" bytes", object, size); const char* const whole_object = object; size_t const whole_size = size; // Try interpretting any byte sequence in object,size as a heap pointer: const size_t remainder = AsInt(object) % pointer_source_alignment; if (remainder) { object += pointer_source_alignment - remainder; if (size >= pointer_source_alignment - remainder) { size -= pointer_source_alignment - remainder; } else { size = 0; } } if (size < sizeof(void*)) continue; const char* const max_object = object + size - sizeof(void*); while (object <= max_object) { // potentially unaligned load: const uintptr_t addr = *reinterpret_cast(object); // Do fast check before the more expensive HaveOnHeapLocked lookup: // this code runs for all memory words that are potentially pointers: const bool can_be_on_heap = // Order tests by the likelyhood of the test failing in 64/32 bit modes. // Yes, this matters: we either lose 5..6% speed in 32 bit mode // (which is already slower) or by a factor of 1.5..1.91 in 64 bit mode. // After the alignment test got dropped the above performance figures // must have changed; might need to revisit this. #if defined(__x86_64__) addr <= max_heap_address && // <= is for 0-sized object with max addr min_heap_address <= addr; #else min_heap_address <= addr && addr <= max_heap_address; // <= is for 0-sized object with max addr #endif if (can_be_on_heap) { const void* ptr = reinterpret_cast(addr); // Too expensive (inner loop): manually uncomment when debugging: // RAW_VLOG(17, "Trying pointer to %p at %p", ptr, object); size_t object_size; if (HaveOnHeapLocked(&ptr, &object_size) && heap_profile->MarkAsLive(ptr)) { // We take the (hopefully low) risk here of encountering by accident // a byte sequence in memory that matches an address of // a heap object which is in fact leaked. // I.e. in very rare and probably not repeatable/lasting cases // we might miss some real heap memory leaks. RAW_VLOG(14, "Found pointer to %p of %"PRIuS" bytes at %p " "inside %p of size %"PRIuS"", ptr, object_size, object, whole_object, whole_size); if (VLOG_IS_ON(15)) { // log call stacks to help debug how come something is not a leak HeapProfileTable::AllocInfo alloc; if (!heap_profile->FindAllocDetails(ptr, &alloc)) { RAW_LOG(FATAL, "FindAllocDetails failed on ptr %p", ptr); } RAW_LOG(INFO, "New live %p object's alloc stack:", ptr); for (int i = 0; i < alloc.stack_depth; ++i) { RAW_LOG(INFO, " @ %p", alloc.call_stack[i]); } } live_object_count += 1; live_byte_count += object_size; live_objects->push_back(AllocObject(ptr, object_size, IGNORED_ON_HEAP)); } } object += pointer_source_alignment; } } live_objects_total += live_object_count; live_bytes_total += live_byte_count; if (live_object_count) { RAW_VLOG(10, "Removed %"PRId64" live heap objects of %"PRId64" bytes: %s%s", live_object_count, live_byte_count, name, name2); } } //---------------------------------------------------------------------- // HeapLeakChecker leak check disabling components //---------------------------------------------------------------------- // static void HeapLeakChecker::DisableChecksIn(const char* pattern) { RAW_LOG(WARNING, "DisableChecksIn(%s) is ignored", pattern); } // static void HeapLeakChecker::IgnoreObject(const void* ptr) { SpinLockHolder l(&heap_checker_lock); if (!heap_checker_on) return; size_t object_size; if (!HaveOnHeapLocked(&ptr, &object_size)) { RAW_LOG(ERROR, "No live heap object at %p to ignore", ptr); } else { RAW_VLOG(10, "Going to ignore live object at %p of %"PRIuS" bytes", ptr, object_size); if (ignored_objects == NULL) { ignored_objects = new(Allocator::Allocate(sizeof(IgnoredObjectsMap))) IgnoredObjectsMap; } if (!ignored_objects->insert(make_pair(AsInt(ptr), object_size)).second) { RAW_LOG(FATAL, "Object at %p is already being ignored", ptr); } } } // static void HeapLeakChecker::UnIgnoreObject(const void* ptr) { SpinLockHolder l(&heap_checker_lock); if (!heap_checker_on) return; size_t object_size; if (!HaveOnHeapLocked(&ptr, &object_size)) { RAW_LOG(FATAL, "No live heap object at %p to un-ignore", ptr); } else { bool found = false; if (ignored_objects) { IgnoredObjectsMap::iterator object = ignored_objects->find(AsInt(ptr)); if (object != ignored_objects->end() && object_size == object->second) { ignored_objects->erase(object); found = true; RAW_VLOG(10, "Now not going to ignore live object " "at %p of %"PRIuS" bytes", ptr, object_size); } } if (!found) RAW_LOG(FATAL, "Object at %p has not been ignored", ptr); } } //---------------------------------------------------------------------- // HeapLeakChecker non-static functions //---------------------------------------------------------------------- char* HeapLeakChecker::MakeProfileNameLocked() { RAW_DCHECK(lock_->IsHeld(), ""); RAW_DCHECK(heap_checker_lock.IsHeld(), ""); const int len = profile_name_prefix->size() + strlen(name_) + 5 + strlen(HeapProfileTable::kFileExt) + 1; char* file_name = reinterpret_cast(Allocator::Allocate(len)); snprintf(file_name, len, "%s.%s-end%s", profile_name_prefix->c_str(), name_, HeapProfileTable::kFileExt); return file_name; } void HeapLeakChecker::Create(const char *name, bool make_start_snapshot) { SpinLockHolder l(lock_); name_ = NULL; // checker is inactive start_snapshot_ = NULL; has_checked_ = false; inuse_bytes_increase_ = 0; inuse_allocs_increase_ = 0; keep_profiles_ = false; char* n = new char[strlen(name) + 1]; // do this before we lock IgnoreObject(n); // otherwise it might be treated as live due to our stack { // Heap activity in other threads is paused for this whole scope. SpinLockHolder al(&alignment_checker_lock); SpinLockHolder hl(&heap_checker_lock); MemoryRegionMap::LockHolder ml; if (heap_checker_on && profile_name_prefix != NULL) { RAW_DCHECK(strchr(name, '/') == NULL, "must be a simple name"); memcpy(n, name, strlen(name) + 1); name_ = n; // checker is active if (make_start_snapshot) { start_snapshot_ = heap_profile->TakeSnapshot(); } const HeapProfileTable::Stats& t = heap_profile->total(); const size_t start_inuse_bytes = t.alloc_size - t.free_size; const size_t start_inuse_allocs = t.allocs - t.frees; RAW_VLOG(10, "Start check \"%s\" profile: %"PRIuS" bytes " "in %"PRIuS" objects", name_, start_inuse_bytes, start_inuse_allocs); } else { RAW_LOG(WARNING, "Heap checker is not active, " "hence checker \"%s\" will do nothing!", name); RAW_LOG(WARNING, "To activate set the HEAPCHECK environment variable.\n"); } } if (name_ == NULL) { UnIgnoreObject(n); delete[] n; // must be done after we unlock } } HeapLeakChecker::HeapLeakChecker(const char *name) : lock_(new SpinLock) { RAW_DCHECK(strcmp(name, "_main_") != 0, "_main_ is reserved"); Create(name, true/*create start_snapshot_*/); } HeapLeakChecker::HeapLeakChecker() : lock_(new SpinLock) { if (FLAGS_heap_check_before_constructors) { // We want to check for leaks of objects allocated during global // constructors (i.e., objects allocated already). So we do not // create a baseline snapshot and hence check for leaks of objects // that may have already been created. Create("_main_", false); } else { // We want to ignore leaks of objects allocated during global // constructors (i.e., objects allocated already). So we snapshot // the current heap contents and use them as a baseline that is // not reported by the leak checker. Create("_main_", true); } } ssize_t HeapLeakChecker::BytesLeaked() const { SpinLockHolder l(lock_); if (!has_checked_) { RAW_LOG(FATAL, "*NoLeaks|SameHeap must execute before this call"); } return inuse_bytes_increase_; } ssize_t HeapLeakChecker::ObjectsLeaked() const { SpinLockHolder l(lock_); if (!has_checked_) { RAW_LOG(FATAL, "*NoLeaks|SameHeap must execute before this call"); } return inuse_allocs_increase_; } // Save pid of main thread for using in naming dump files static int32 main_thread_pid = getpid(); #ifdef HAVE_PROGRAM_INVOCATION_NAME extern char* program_invocation_name; extern char* program_invocation_short_name; static const char* invocation_name() { return program_invocation_short_name; } static string invocation_path() { return program_invocation_name; } #else static const char* invocation_name() { return ""; } static string invocation_path() { return ""; } #endif // Prints commands that users can run to get more information // about the reported leaks. static void SuggestPprofCommand(const char* pprof_file_arg) { // Extra help information to print for the user when the test is // being run in a way where the straightforward pprof command will // not suffice. string extra_help; // Common header info to print for remote runs const string remote_header = "This program is being executed remotely and therefore the pprof\n" "command printed above will not work. Either run this program\n" "locally, or adjust the pprof command as follows to allow it to\n" "work on your local machine:\n"; // Extra command for fetching remote data string fetch_cmd; RAW_LOG(WARNING, "\n\n" "If the preceding stack traces are not enough to find " "the leaks, try running THIS shell command:\n\n" "%s%s %s \"%s\" --inuse_objects --lines --heapcheck " " --edgefraction=1e-10 --nodefraction=1e-10 --gv\n" "\n" "%s" "If you are still puzzled about why the leaks are " "there, try rerunning this program with " "HEAP_CHECK_TEST_POINTER_ALIGNMENT=1 and/or with " "HEAP_CHECK_MAX_POINTER_OFFSET=-1\n" "If the leak report occurs in a small fraction of runs, " "try running with TCMALLOC_MAX_FREE_QUEUE_SIZE of few hundred MB " "or with TCMALLOC_RECLAIM_MEMORY=false, " // only works for debugalloc "it might help find leaks more repeatably\n", fetch_cmd.c_str(), "pprof", // works as long as pprof is on your path invocation_path().c_str(), pprof_file_arg, extra_help.c_str() ); } bool HeapLeakChecker::DoNoLeaks(ShouldSymbolize should_symbolize) { SpinLockHolder l(lock_); // The locking also helps us keep the messages // for the two checks close together. SpinLockHolder al(&alignment_checker_lock); // thread-safe: protected by alignment_checker_lock static bool have_disabled_hooks_for_symbolize = false; // Once we've checked for leaks and symbolized the results once, it's // not safe to do it again. This is because in order to symbolize // safely, we had to disable all the malloc hooks here, so we no // longer can be confident we've collected all the data we need. if (have_disabled_hooks_for_symbolize) { RAW_LOG(FATAL, "Must not call heap leak checker manually after " " program-exit's automatic check."); } HeapProfileTable::Snapshot* leaks = NULL; char* pprof_file = NULL; { // Heap activity in other threads is paused during this function // (i.e. until we got all profile difference info). SpinLockHolder hl(&heap_checker_lock); if (heap_checker_on == false) { if (name_ != NULL) { // leak checking enabled when created the checker RAW_LOG(WARNING, "Heap leak checker got turned off after checker " "\"%s\" has been created, no leak check is being done for it!", name_); } return true; } // Update global_region_caller_ranges. They may need to change since // e.g. initialization because shared libraries might have been loaded or // unloaded. Allocator::DeleteAndNullIfNot(&global_region_caller_ranges); ProcMapsResult pm_result = UseProcMapsLocked(DISABLE_LIBRARY_ALLOCS); RAW_CHECK(pm_result == PROC_MAPS_USED, ""); // Keep track of number of internally allocated objects so we // can detect leaks in the heap-leak-checket itself const int initial_allocs = Allocator::alloc_count(); if (name_ == NULL) { RAW_LOG(FATAL, "Heap leak checker must not be turned on " "after construction of a HeapLeakChecker"); } MemoryRegionMap::LockHolder ml; int a_local_var; // Use our stack ptr to make stack data live: // Sanity check that nobody is messing with the hooks we need: // Important to have it here: else we can misteriously SIGSEGV // in IgnoreLiveObjectsLocked inside ListAllProcessThreads's callback // by looking into a region that got unmapped w/o our knowledge. MemoryRegionMap::CheckMallocHooks(); if (MallocHook::GetNewHook() != NewHook || MallocHook::GetDeleteHook() != DeleteHook) { RAW_LOG(FATAL, "Had our new/delete MallocHook-s replaced. " "Are you using another MallocHook client? " "Use --heap_check=\"\" to avoid this conflict."); } // Make the heap profile, other threads are locked out. HeapProfileTable::Snapshot* base = reinterpret_cast(start_snapshot_); RAW_DCHECK(FLAGS_heap_check_pointer_source_alignment > 0, ""); pointer_source_alignment = FLAGS_heap_check_pointer_source_alignment; IgnoreAllLiveObjectsLocked(&a_local_var); leaks = heap_profile->NonLiveSnapshot(base); inuse_bytes_increase_ = static_cast(leaks->total().alloc_size); inuse_allocs_increase_ = static_cast(leaks->total().allocs); if (leaks->Empty()) { heap_profile->ReleaseSnapshot(leaks); leaks = NULL; // We can only check for internal leaks along the no-user-leak // path since in the leak path we temporarily release // heap_checker_lock and another thread can come in and disturb // allocation counts. if (Allocator::alloc_count() != initial_allocs) { RAW_LOG(FATAL, "Internal HeapChecker leak of %d objects ; %d -> %d", Allocator::alloc_count() - initial_allocs, initial_allocs, Allocator::alloc_count()); } } else if (FLAGS_heap_check_test_pointer_alignment) { if (pointer_source_alignment == 1) { RAW_LOG(WARNING, "--heap_check_test_pointer_alignment has no effect: " "--heap_check_pointer_source_alignment was already set to 1"); } else { // Try with reduced pointer aligment pointer_source_alignment = 1; IgnoreAllLiveObjectsLocked(&a_local_var); HeapProfileTable::Snapshot* leaks_wo_align = heap_profile->NonLiveSnapshot(base); pointer_source_alignment = FLAGS_heap_check_pointer_source_alignment; if (leaks_wo_align->Empty()) { RAW_LOG(WARNING, "Found no leaks without pointer alignment: " "something might be placing pointers at " "unaligned addresses! This needs to be fixed."); } else { RAW_LOG(INFO, "Found leaks without pointer alignment as well: " "unaligned pointers must not be the cause of leaks."); RAW_LOG(INFO, "--heap_check_test_pointer_alignment did not help " "to diagnose the leaks."); } heap_profile->ReleaseSnapshot(leaks_wo_align); } } if (leaks != NULL) { pprof_file = MakeProfileNameLocked(); } } has_checked_ = true; if (leaks == NULL) { if (FLAGS_heap_check_max_pointer_offset == -1) { RAW_LOG(WARNING, "Found no leaks without max_pointer_offset restriction: " "it's possible that the default value of " "heap_check_max_pointer_offset flag is too low. " "Do you use pointers with larger than that offsets " "pointing in the middle of heap-allocated objects?"); } const HeapProfileTable::Stats& stats = heap_profile->total(); RAW_VLOG(heap_checker_info_level, "No leaks found for check \"%s\" " "(but no 100%% guarantee that there aren't any): " "found %"PRId64" reachable heap objects of %"PRId64" bytes", name_, int64(stats.allocs - stats.frees), int64(stats.alloc_size - stats.free_size)); } else { if (should_symbolize == SYMBOLIZE) { // To turn addresses into symbols, we need to fork, which is a // problem if both parent and child end up trying to call the // same malloc-hooks we've set up, at the same time. To avoid // trouble, we turn off the hooks before symbolizing. Note that // this makes it unsafe to ever leak-report again! Luckily, we // typically only want to report once in a program's run, at the // very end. if (MallocHook::GetNewHook() == NewHook) MallocHook::SetNewHook(NULL); if (MallocHook::GetDeleteHook() == DeleteHook) MallocHook::SetDeleteHook(NULL); MemoryRegionMap::Shutdown(); // Make sure all the hooks really got unset: RAW_CHECK(MallocHook::GetNewHook() == NULL, ""); RAW_CHECK(MallocHook::GetDeleteHook() == NULL, ""); RAW_CHECK(MallocHook::GetMmapHook() == NULL, ""); RAW_CHECK(MallocHook::GetSbrkHook() == NULL, ""); have_disabled_hooks_for_symbolize = true; leaks->ReportLeaks(name_, pprof_file, true); // true = should_symbolize } else { leaks->ReportLeaks(name_, pprof_file, false); } if (FLAGS_heap_check_identify_leaks) { leaks->ReportIndividualObjects(); } SuggestPprofCommand(pprof_file); { SpinLockHolder hl(&heap_checker_lock); heap_profile->ReleaseSnapshot(leaks); Allocator::Free(pprof_file); } } return (leaks == NULL); } HeapLeakChecker::~HeapLeakChecker() { if (name_ != NULL) { // had leak checking enabled when created the checker if (!has_checked_) { RAW_LOG(FATAL, "Some *NoLeaks|SameHeap method" " must be called on any created HeapLeakChecker"); } // Deallocate any snapshot taken at start if (start_snapshot_ != NULL) { SpinLockHolder l(&heap_checker_lock); heap_profile->ReleaseSnapshot( reinterpret_cast(start_snapshot_)); } UnIgnoreObject(name_); delete[] name_; name_ = NULL; } delete lock_; } //---------------------------------------------------------------------- // HeapLeakChecker overall heap check components //---------------------------------------------------------------------- // static bool HeapLeakChecker::IsActive() { SpinLockHolder l(&heap_checker_lock); return heap_checker_on; } vector* HeapCleaner::heap_cleanups_ = NULL; // When a HeapCleaner object is intialized, add its function to the static list // of cleaners to be run before leaks checking. HeapCleaner::HeapCleaner(void_function f) { if (heap_cleanups_ == NULL) heap_cleanups_ = new vector; heap_cleanups_->push_back(f); } // Run all of the cleanup functions and delete the vector. void HeapCleaner::RunHeapCleanups() { if (!heap_cleanups_) return; for (int i = 0; i < heap_cleanups_->size(); i++) { void (*f)(void) = (*heap_cleanups_)[i]; f(); } delete heap_cleanups_; heap_cleanups_ = NULL; } // Program exit heap cleanup registered with atexit(). // Will not get executed when we crash on a signal. // /*static*/ void HeapLeakChecker::RunHeapCleanups() { { SpinLockHolder l(&heap_checker_lock); // can get here (via forks?) with other pids if (heap_checker_pid != getpid()) return; } HeapCleaner::RunHeapCleanups(); if (!FLAGS_heap_check_after_destructors) DoMainHeapCheck(); } static bool internal_init_start_has_run = false; // Called exactly once, before main() (but hopefully just before). // This picks a good unique name for the dumped leak checking heap profiles. // // Because we crash when InternalInitStart is called more than once, // it's fine that we hold heap_checker_lock only around pieces of // this function: this is still enough for thread-safety w.r.t. other functions // of this module. // We can't hold heap_checker_lock throughout because it would deadlock // on a memory allocation since our new/delete hooks can be on. // /*static*/ void HeapLeakChecker::InternalInitStart() { { SpinLockHolder l(&heap_checker_lock); RAW_CHECK(!internal_init_start_has_run, "Heap-check constructor called twice. Perhaps you both linked" " in the heap checker, and also used LD_PRELOAD to load it?"); internal_init_start_has_run = true; if (FLAGS_heap_check.empty()) { // turns out we do not need checking in the end; can stop profiling TurnItselfOffLocked(); return; } } // Changing this to false can be useful when debugging heap-checker itself: if (!FLAGS_heap_check_run_under_gdb && IsDebuggerAttached()) { RAW_LOG(WARNING, "Someone is ptrace()ing us; will turn itself off"); SpinLockHolder l(&heap_checker_lock); TurnItselfOffLocked(); return; } { SpinLockHolder l(&heap_checker_lock); if (!constructor_heap_profiling) { RAW_LOG(FATAL, "Can not start so late. You have to enable heap checking " "with HEAPCHECK=."); } } // Set all flags RAW_DCHECK(FLAGS_heap_check_pointer_source_alignment > 0, ""); if (FLAGS_heap_check == "minimal") { // The least we can check. FLAGS_heap_check_before_constructors = false; // from after main // (ignore more) FLAGS_heap_check_after_destructors = false; // to after cleanup // (most data is live) FLAGS_heap_check_ignore_thread_live = true; // ignore all live FLAGS_heap_check_ignore_global_live = true; // ignore all live } else if (FLAGS_heap_check == "normal") { // Faster than 'minimal' and not much stricter. FLAGS_heap_check_before_constructors = true; // from no profile (fast) FLAGS_heap_check_after_destructors = false; // to after cleanup // (most data is live) FLAGS_heap_check_ignore_thread_live = true; // ignore all live FLAGS_heap_check_ignore_global_live = true; // ignore all live } else if (FLAGS_heap_check == "strict") { // A bit stricter than 'normal': global destructors must fully clean up // after themselves if they are present. FLAGS_heap_check_before_constructors = true; // from no profile (fast) FLAGS_heap_check_after_destructors = true; // to after destructors // (less data live) FLAGS_heap_check_ignore_thread_live = true; // ignore all live FLAGS_heap_check_ignore_global_live = true; // ignore all live } else if (FLAGS_heap_check == "draconian") { // Drop not very portable and not very exact live heap flooding. FLAGS_heap_check_before_constructors = true; // from no profile (fast) FLAGS_heap_check_after_destructors = true; // to after destructors // (need them) FLAGS_heap_check_ignore_thread_live = false; // no live flood (stricter) FLAGS_heap_check_ignore_global_live = false; // no live flood (stricter) } else if (FLAGS_heap_check == "as-is") { // do nothing: use other flags as is } else if (FLAGS_heap_check == "local") { // do nothing } else { RAW_LOG(FATAL, "Unsupported heap_check flag: %s", FLAGS_heap_check.c_str()); } { SpinLockHolder l(&heap_checker_lock); RAW_DCHECK(heap_checker_pid == getpid(), ""); heap_checker_on = true; RAW_DCHECK(heap_profile, ""); ProcMapsResult pm_result = UseProcMapsLocked(DISABLE_LIBRARY_ALLOCS); // might neeed to do this more than once // if one later dynamically loads libraries that we want disabled if (pm_result != PROC_MAPS_USED) { // can't function TurnItselfOffLocked(); return; } } // make a good place and name for heap profile leak dumps string* profile_prefix = new string(FLAGS_heap_check_dump_directory + "/" + invocation_name()); // Finalize prefix for dumping leak checking profiles. const int32 our_pid = getpid(); // safest to call getpid() outside lock { SpinLockHolder l(&heap_checker_lock); // main_thread_pid might still be 0 if this function is being called before // global constructors. In that case, our pid *is* the main pid. if (main_thread_pid == 0) main_thread_pid = our_pid; } char pid_buf[15]; snprintf(pid_buf, sizeof(pid_buf), ".%d", main_thread_pid); *profile_prefix += pid_buf; { SpinLockHolder l(&heap_checker_lock); RAW_DCHECK(profile_name_prefix == NULL, ""); profile_name_prefix = profile_prefix; } // Make sure new/delete hooks are installed properly // and heap profiler is indeed able to keep track // of the objects being allocated. // We test this to make sure we are indeed checking for leaks. char* test_str = new char[5]; size_t size; { SpinLockHolder l(&heap_checker_lock); RAW_CHECK(heap_profile->FindAlloc(test_str, &size), "our own new/delete not linked?"); } delete[] test_str; { SpinLockHolder l(&heap_checker_lock); // This check can fail when it should not if another thread allocates // into this same spot right this moment, // which is unlikely since this code runs in InitGoogle. RAW_CHECK(!heap_profile->FindAlloc(test_str, &size), "our own new/delete not linked?"); } // If we crash in the above code, it probably means that // "nm | grep new" will show that tcmalloc's new/delete // implementation did not get linked-in into this binary // (i.e. nm will list __builtin_new and __builtin_vec_new as undefined). // If this happens, it is a BUILD bug to be fixed. RAW_VLOG(heap_checker_info_level, "WARNING: Perftools heap leak checker is active " "-- Performance may suffer"); if (FLAGS_heap_check != "local") { // Schedule registered heap cleanup atexit(RunHeapCleanups); HeapLeakChecker* main_hc = new HeapLeakChecker(); SpinLockHolder l(&heap_checker_lock); RAW_DCHECK(main_heap_checker == NULL, "Repeated creation of main_heap_checker"); main_heap_checker = main_hc; do_main_heap_check = true; } { SpinLockHolder l(&heap_checker_lock); RAW_CHECK(heap_checker_on && constructor_heap_profiling, "Leak checking is expected to be fully turned on now"); } // For binaries built in debug mode, this will set release queue of // debugallocation.cc to 100M to make it less likely for real leaks to // be hidden due to reuse of heap memory object addresses. // Running a test with --malloc_reclaim_memory=0 would help find leaks even // better, but the test might run out of memory as a result. // The scenario is that a heap object at address X is allocated and freed, // but some other data-structure still retains a pointer to X. // Then the same heap memory is used for another object, which is leaked, // but the leak is not noticed due to the pointer to the original object at X. // TODO(csilvers): support this in some manner. #if 0 SetCommandLineOptionWithMode("max_free_queue_size", "104857600", // 100M SET_FLAG_IF_DEFAULT); #endif } // We want this to run early as well, but not so early as // ::BeforeConstructors (we want flag assignments to have already // happened, for instance). Initializer-registration does the trick. REGISTER_MODULE_INITIALIZER(init_start, HeapLeakChecker::InternalInitStart()); // static bool HeapLeakChecker::DoMainHeapCheck() { if (FLAGS_heap_check_delay_seconds > 0) { sleep(FLAGS_heap_check_delay_seconds); } { SpinLockHolder l(&heap_checker_lock); if (!do_main_heap_check) return false; RAW_DCHECK(heap_checker_pid == getpid(), ""); do_main_heap_check = false; // will do it now; no need to do it more } if (!NoGlobalLeaks()) { if (FLAGS_heap_check_identify_leaks) { RAW_LOG(FATAL, "Whole-program memory leaks found."); } RAW_LOG(ERROR, "Exiting with error code (instead of crashing) " "because of whole-program memory leaks"); _exit(1); // we don't want to call atexit() routines! } return true; } // static HeapLeakChecker* HeapLeakChecker::GlobalChecker() { SpinLockHolder l(&heap_checker_lock); return main_heap_checker; } // static bool HeapLeakChecker::NoGlobalLeaks() { // we never delete or change main_heap_checker once it's set: HeapLeakChecker* main_hc = GlobalChecker(); if (main_hc) { RAW_VLOG(10, "Checking for whole-program memory leaks"); // The program is over, so it's safe to symbolize addresses (which // requires a fork) because no serious work is expected to be done // after this. Symbolizing is really useful -- knowing what // function has a leak is better than knowing just an address -- // and while we can only safely symbolize once in a program run, // now is the time (after all, there's no "later" that would be better). return main_hc->DoNoLeaks(SYMBOLIZE); } return true; } // static void HeapLeakChecker::CancelGlobalCheck() { SpinLockHolder l(&heap_checker_lock); if (do_main_heap_check) { RAW_VLOG(heap_checker_info_level, "Canceling the automatic at-exit whole-program memory leak check"); do_main_heap_check = false; } } //---------------------------------------------------------------------- // HeapLeakChecker global constructor/destructor ordering components //---------------------------------------------------------------------- #ifdef HAVE___ATTRIBUTE__ // we need __attribute__((weak)) for this to work #define INSTALLED_INITIAL_MALLOC_HOOKS void HeapLeakChecker_BeforeConstructors(); // below static bool in_initial_malloc_hook = false; // Helper for InitialMallocHook_* below static inline void InitHeapLeakCheckerFromMallocHook() { { SpinLockHolder l(&heap_checker_lock); RAW_CHECK(!in_initial_malloc_hook, "Something did not reset initial MallocHook-s"); in_initial_malloc_hook = true; } // Initialize heap checker on the very first allocation/mmap/sbrk call: HeapLeakChecker_BeforeConstructors(); { SpinLockHolder l(&heap_checker_lock); in_initial_malloc_hook = false; } } // These will owerwrite the weak definitions in malloc_hook.cc: // Important to have this to catch the first allocation call from the binary: extern "C" void InitialMallocHook_New(const void* ptr, size_t size) { InitHeapLeakCheckerFromMallocHook(); // record this first allocation as well (if we need to): MallocHook::InvokeNewHook(ptr, size); } // Important to have this to catch the first mmap call (say from tcmalloc): extern "C" void InitialMallocHook_MMap(const void* result, const void* start, size_t size, int protection, int flags, int fd, off_t offset) { InitHeapLeakCheckerFromMallocHook(); // record this first mmap as well (if we need to): MallocHook::InvokeMmapHook( result, start, size, protection, flags, fd, offset); } // Important to have this to catch the first sbrk call (say from tcmalloc): extern "C" void InitialMallocHook_Sbrk(const void* result, ptrdiff_t increment) { InitHeapLeakCheckerFromMallocHook(); // record this first sbrk as well (if we need to): MallocHook::InvokeSbrkHook(result, increment); } // static void CancelInitialMallocHooks() { if (MallocHook::GetNewHook() == InitialMallocHook_New) { MallocHook::SetNewHook(NULL); } RAW_DCHECK(MallocHook::GetNewHook() == NULL, ""); if (MallocHook::GetMmapHook() == InitialMallocHook_MMap) { MallocHook::SetMmapHook(NULL); } RAW_DCHECK(MallocHook::GetMmapHook() == NULL, ""); if (MallocHook::GetSbrkHook() == InitialMallocHook_Sbrk) { MallocHook::SetSbrkHook(NULL); } RAW_DCHECK(MallocHook::GetSbrkHook() == NULL, ""); } #else // static void CancelInitialMallocHooks() {} #endif // static void HeapLeakChecker::BeforeConstructorsLocked() { RAW_DCHECK(heap_checker_lock.IsHeld(), ""); RAW_CHECK(!constructor_heap_profiling, "BeforeConstructorsLocked called multiple times"); CancelInitialMallocHooks(); // Set hooks early to crash if 'new' gets called before we make heap_profile, // and make sure no other hooks existed: if (MallocHook::SetNewHook(NewHook) != NULL || MallocHook::SetDeleteHook(DeleteHook) != NULL) { RAW_LOG(FATAL, "Had other new/delete MallocHook-s set. " "Somehow leak checker got activated " "after something else have set up these hooks."); } constructor_heap_profiling = true; MemoryRegionMap::Init(1); // Set up MemoryRegionMap with (at least) one caller stack frame to record // (important that it's done before HeapProfileTable creation below). Allocator::Init(); RAW_CHECK(heap_profile == NULL, ""); heap_profile = new(Allocator::Allocate(sizeof(HeapProfileTable))) HeapProfileTable(&Allocator::Allocate, &Allocator::Free); RAW_VLOG(10, "Starting tracking the heap"); heap_checker_on = true; } // static void HeapLeakChecker::TurnItselfOffLocked() { RAW_DCHECK(heap_checker_lock.IsHeld(), ""); // Set FLAGS_heap_check to "", for users who test for it if (!FLAGS_heap_check.empty()) // be a noop in the common case FLAGS_heap_check.clear(); // because clear() could allocate memory if (constructor_heap_profiling) { RAW_CHECK(heap_checker_on, ""); RAW_VLOG(heap_checker_info_level, "Turning perftools heap leak checking off"); heap_checker_on = false; // Unset our hooks checking they were the ones set: if (MallocHook::SetNewHook(NULL) != NewHook || MallocHook::SetDeleteHook(NULL) != DeleteHook) { RAW_LOG(FATAL, "Had our new/delete MallocHook-s replaced. " "Are you using another MallocHook client?"); } Allocator::DeleteAndNull(&heap_profile); // free our optional global data: Allocator::DeleteAndNullIfNot(&ignored_objects); Allocator::DeleteAndNullIfNot(&disabled_ranges); Allocator::DeleteAndNullIfNot(&global_region_caller_ranges); Allocator::Shutdown(); MemoryRegionMap::Shutdown(); } RAW_CHECK(!heap_checker_on, ""); } extern bool heap_leak_checker_bcad_variable; // in heap-checker-bcad.cc static bool has_called_before_constructors = false; void HeapLeakChecker_BeforeConstructors() { SpinLockHolder l(&heap_checker_lock); // We can be called from several places: the first mmap/sbrk/alloc call // or the first global c-tor from heap-checker-bcad.cc: // Do not re-execute initialization: if (has_called_before_constructors) return; has_called_before_constructors = true; heap_checker_pid = getpid(); // set it always heap_leak_checker_bcad_variable = true; // just to reference it, so that heap-checker-bcad.o is linked in // This function can be called *very* early, before the normal // global-constructor that sets FLAGS_verbose. Set it manually now, // so the RAW_LOG messages here are controllable. const char* verbose_str = GetenvBeforeMain("PERFTOOLS_VERBOSE"); if (verbose_str && atoi(verbose_str)) { // different than the default of 0? FLAGS_verbose = atoi(verbose_str); } bool need_heap_check = true; // The user indicates a desire for heap-checking via the HEAPCHECK // environment variable. If it's not set, there's no way to do // heap-checking. if (!GetenvBeforeMain("HEAPCHECK")) { need_heap_check = false; } #ifdef HAVE_GETEUID if (need_heap_check && getuid() != geteuid()) { // heap-checker writes out files. Thus, for security reasons, we don't // recognize the env. var. to turn on heap-checking if we're setuid. RAW_LOG(WARNING, ("HeapChecker: ignoring HEAPCHECK because " "program seems to be setuid\n")); need_heap_check = false; } #endif if (need_heap_check) { HeapLeakChecker::BeforeConstructorsLocked(); } else { // cancel our initial hooks CancelInitialMallocHooks(); } } // This function is executed after all global object destructors run. void HeapLeakChecker_AfterDestructors() { { SpinLockHolder l(&heap_checker_lock); // can get here (via forks?) with other pids if (heap_checker_pid != getpid()) return; } if (FLAGS_heap_check_after_destructors) { if (HeapLeakChecker::DoMainHeapCheck()) { const struct timespec sleep_time = { 0, 500000000 }; // 500 ms nanosleep(&sleep_time, NULL); // Need this hack to wait for other pthreads to exit. // Otherwise tcmalloc find errors // on a free() call from pthreads. } } SpinLockHolder l(&heap_checker_lock); RAW_CHECK(!do_main_heap_check, "should have done it"); } //---------------------------------------------------------------------- // HeapLeakChecker disabling helpers //---------------------------------------------------------------------- // These functions are at the end of the file to prevent their inlining: // static void HeapLeakChecker::DisableChecksFromToLocked(const void* start_address, const void* end_address, int max_depth) { RAW_DCHECK(heap_checker_lock.IsHeld(), ""); RAW_DCHECK(start_address < end_address, ""); if (disabled_ranges == NULL) { disabled_ranges = new(Allocator::Allocate(sizeof(DisabledRangeMap))) DisabledRangeMap; } RangeValue value; value.start_address = AsInt(start_address); value.max_depth = max_depth; if (disabled_ranges->insert(make_pair(AsInt(end_address), value)).second) { RAW_VLOG(10, "Disabling leak checking in stack traces " "under frame addresses between %p..%p", start_address, end_address); } else { // check that this is just a verbatim repetition RangeValue const& val = disabled_ranges->find(AsInt(end_address))->second; if (val.max_depth != value.max_depth || val.start_address != value.start_address) { RAW_LOG(FATAL, "Two DisableChecksToHereFrom calls conflict: " "(%p, %p, %d) vs. (%p, %p, %d)", AsPtr(val.start_address), end_address, val.max_depth, start_address, end_address, max_depth); } } } // static inline bool HeapLeakChecker::HaveOnHeapLocked(const void** ptr, size_t* object_size) { // Commented-out because HaveOnHeapLocked is very performance-critical: // RAW_DCHECK(heap_checker_lock.IsHeld(), ""); const uintptr_t addr = AsInt(*ptr); if (heap_profile->FindInsideAlloc( *ptr, max_heap_object_size, ptr, object_size)) { RAW_VLOG(16, "Got pointer into %p at +%"PRIuPTR" offset", *ptr, addr - AsInt(*ptr)); return true; } return false; } // static const void* HeapLeakChecker::GetAllocCaller(void* ptr) { // this is used only in the unittest, so the heavy checks are fine HeapProfileTable::AllocInfo info; { SpinLockHolder l(&heap_checker_lock); RAW_CHECK(heap_profile->FindAllocDetails(ptr, &info), ""); } RAW_CHECK(info.stack_depth >= 1, ""); return info.call_stack[0]; } ================================================ FILE: distro/google-perftools-1.7/src/heap-profile-table.cc ================================================ // Copyright (c) 2006, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // Maxim Lifantsev (refactoring) // #include #ifdef HAVE_UNISTD_H #include // for write() #endif #include // for open() #ifdef HAVE_GLOB_H #include #ifndef GLOB_NOMATCH // true on some old cygwins # define GLOB_NOMATCH 0 #endif #endif #ifdef HAVE_INTTYPES_H #include // for PRIxPTR #endif #ifdef HAVE_POLL_H #include #endif #include #include #include #include #include // for sort(), equal(), and copy() #include "heap-profile-table.h" #include "base/logging.h" #include "raw_printer.h" #include "symbolize.h" #include #include #include "base/commandlineflags.h" #include "base/logging.h" // for the RawFD I/O commands #include "base/sysinfo.h" using std::sort; using std::equal; using std::copy; using std::string; using std::map; using tcmalloc::FillProcSelfMaps; // from sysinfo.h using tcmalloc::DumpProcSelfMaps; // from sysinfo.h //---------------------------------------------------------------------- DEFINE_bool(cleanup_old_heap_profiles, EnvToBool("HEAP_PROFILE_CLEANUP", true), "At initialization time, delete old heap profiles."); DEFINE_int32(heap_check_max_leaks, EnvToInt("HEAP_CHECK_MAX_LEAKS", 20), "The maximum number of leak reports to print."); //---------------------------------------------------------------------- // header of the dumped heap profile static const char kProfileHeader[] = "heap profile: "; static const char kProcSelfMapsHeader[] = "\nMAPPED_LIBRARIES:\n"; //---------------------------------------------------------------------- const char HeapProfileTable::kFileExt[] = ".heap"; //---------------------------------------------------------------------- static const int kHashTableSize = 179999; // Size for table_. /*static*/ const int HeapProfileTable::kMaxStackDepth; //---------------------------------------------------------------------- // We strip out different number of stack frames in debug mode // because less inlining happens in that case #ifdef NDEBUG static const int kStripFrames = 2; #else static const int kStripFrames = 3; #endif // For sorting Stats or Buckets by in-use space static bool ByAllocatedSpace(HeapProfileTable::Stats* a, HeapProfileTable::Stats* b) { // Return true iff "a" has more allocated space than "b" return (a->alloc_size - a->free_size) > (b->alloc_size - b->free_size); } //---------------------------------------------------------------------- HeapProfileTable::HeapProfileTable(Allocator alloc, DeAllocator dealloc) : alloc_(alloc), dealloc_(dealloc) { // Make the table const int table_bytes = kHashTableSize * sizeof(*table_); table_ = reinterpret_cast(alloc_(table_bytes)); memset(table_, 0, table_bytes); // Make allocation map allocation_ = new(alloc_(sizeof(AllocationMap))) AllocationMap(alloc_, dealloc_); // init the rest: memset(&total_, 0, sizeof(total_)); num_buckets_ = 0; } HeapProfileTable::~HeapProfileTable() { // free allocation map allocation_->~AllocationMap(); dealloc_(allocation_); allocation_ = NULL; // free hash table for (int b = 0; b < kHashTableSize; b++) { for (Bucket* x = table_[b]; x != 0; /**/) { Bucket* b = x; x = x->next; dealloc_(b->stack); dealloc_(b); } } dealloc_(table_); table_ = NULL; } HeapProfileTable::Bucket* HeapProfileTable::GetBucket(int depth, const void* const key[]) { // Make hash-value uintptr_t h = 0; for (int i = 0; i < depth; i++) { h += reinterpret_cast(key[i]); h += h << 10; h ^= h >> 6; } h += h << 3; h ^= h >> 11; // Lookup stack trace in table unsigned int buck = ((unsigned int) h) % kHashTableSize; for (Bucket* b = table_[buck]; b != 0; b = b->next) { if ((b->hash == h) && (b->depth == depth) && equal(key, key + depth, b->stack)) { return b; } } // Create new bucket const size_t key_size = sizeof(key[0]) * depth; const void** kcopy = reinterpret_cast(alloc_(key_size)); copy(key, key + depth, kcopy); Bucket* b = reinterpret_cast(alloc_(sizeof(Bucket))); memset(b, 0, sizeof(*b)); b->hash = h; b->depth = depth; b->stack = kcopy; b->next = table_[buck]; table_[buck] = b; num_buckets_++; return b; } void HeapProfileTable::RecordAlloc(const void* ptr, size_t bytes, int skip_count) { void* key[kMaxStackDepth]; int depth = MallocHook::GetCallerStackTrace( key, kMaxStackDepth, kStripFrames + skip_count + 1); RecordAllocWithStack(ptr, bytes, depth, key); } void HeapProfileTable::RecordAllocWithStack( const void* ptr, size_t bytes, int stack_depth, const void* const call_stack[]) { Bucket* b = GetBucket(stack_depth, call_stack); b->allocs++; b->alloc_size += bytes; total_.allocs++; total_.alloc_size += bytes; AllocValue v; v.set_bucket(b); // also did set_live(false); set_ignore(false) v.bytes = bytes; allocation_->Insert(ptr, v); } void HeapProfileTable::RecordFree(const void* ptr) { AllocValue v; if (allocation_->FindAndRemove(ptr, &v)) { Bucket* b = v.bucket(); b->frees++; b->free_size += v.bytes; total_.frees++; total_.free_size += v.bytes; } } bool HeapProfileTable::FindAlloc(const void* ptr, size_t* object_size) const { const AllocValue* alloc_value = allocation_->Find(ptr); if (alloc_value != NULL) *object_size = alloc_value->bytes; return alloc_value != NULL; } bool HeapProfileTable::FindAllocDetails(const void* ptr, AllocInfo* info) const { const AllocValue* alloc_value = allocation_->Find(ptr); if (alloc_value != NULL) { info->object_size = alloc_value->bytes; info->call_stack = alloc_value->bucket()->stack; info->stack_depth = alloc_value->bucket()->depth; } return alloc_value != NULL; } bool HeapProfileTable::FindInsideAlloc(const void* ptr, size_t max_size, const void** object_ptr, size_t* object_size) const { const AllocValue* alloc_value = allocation_->FindInside(&AllocValueSize, max_size, ptr, object_ptr); if (alloc_value != NULL) *object_size = alloc_value->bytes; return alloc_value != NULL; } bool HeapProfileTable::MarkAsLive(const void* ptr) { AllocValue* alloc = allocation_->FindMutable(ptr); if (alloc && !alloc->live()) { alloc->set_live(true); return true; } return false; } void HeapProfileTable::MarkAsIgnored(const void* ptr) { AllocValue* alloc = allocation_->FindMutable(ptr); if (alloc) { alloc->set_ignore(true); } } // We'd be happier using snprintfer, but we don't to reduce dependencies. int HeapProfileTable::UnparseBucket(const Bucket& b, char* buf, int buflen, int bufsize, const char* extra, Stats* profile_stats) { if (profile_stats != NULL) { profile_stats->allocs += b.allocs; profile_stats->alloc_size += b.alloc_size; profile_stats->frees += b.frees; profile_stats->free_size += b.free_size; } int printed = snprintf(buf + buflen, bufsize - buflen, "%6d: %8"PRId64" [%6d: %8"PRId64"] @%s", b.allocs - b.frees, b.alloc_size - b.free_size, b.allocs, b.alloc_size, extra); // If it looks like the snprintf failed, ignore the fact we printed anything if (printed < 0 || printed >= bufsize - buflen) return buflen; buflen += printed; for (int d = 0; d < b.depth; d++) { printed = snprintf(buf + buflen, bufsize - buflen, " 0x%08" PRIxPTR, reinterpret_cast(b.stack[d])); if (printed < 0 || printed >= bufsize - buflen) return buflen; buflen += printed; } printed = snprintf(buf + buflen, bufsize - buflen, "\n"); if (printed < 0 || printed >= bufsize - buflen) return buflen; buflen += printed; return buflen; } HeapProfileTable::Bucket** HeapProfileTable::MakeSortedBucketList() const { Bucket** list = reinterpret_cast(alloc_(sizeof(Bucket) * num_buckets_)); int n = 0; for (int b = 0; b < kHashTableSize; b++) { for (Bucket* x = table_[b]; x != 0; x = x->next) { list[n++] = x; } } RAW_DCHECK(n == num_buckets_, ""); sort(list, list + num_buckets_, ByAllocatedSpace); return list; } void HeapProfileTable::IterateOrderedAllocContexts( AllocContextIterator callback) const { Bucket** list = MakeSortedBucketList(); AllocContextInfo info; for (int i = 0; i < num_buckets_; ++i) { *static_cast(&info) = *static_cast(list[i]); info.stack_depth = list[i]->depth; info.call_stack = list[i]->stack; callback(info); } dealloc_(list); } int HeapProfileTable::FillOrderedProfile(char buf[], int size) const { Bucket** list = MakeSortedBucketList(); // Our file format is "bucket, bucket, ..., bucket, proc_self_maps_info". // In the cases buf is too small, we'd rather leave out the last // buckets than leave out the /proc/self/maps info. To ensure that, // we actually print the /proc/self/maps info first, then move it to // the end of the buffer, then write the bucket info into whatever // is remaining, and then move the maps info one last time to close // any gaps. Whew! int map_length = snprintf(buf, size, "%s", kProcSelfMapsHeader); if (map_length < 0 || map_length >= size) return 0; bool dummy; // "wrote_all" -- did /proc/self/maps fit in its entirety? map_length += FillProcSelfMaps(buf + map_length, size - map_length, &dummy); RAW_DCHECK(map_length <= size, ""); char* const map_start = buf + size - map_length; // move to end memmove(map_start, buf, map_length); size -= map_length; Stats stats; memset(&stats, 0, sizeof(stats)); int bucket_length = snprintf(buf, size, "%s", kProfileHeader); if (bucket_length < 0 || bucket_length >= size) return 0; bucket_length = UnparseBucket(total_, buf, bucket_length, size, " heapprofile", &stats); for (int i = 0; i < num_buckets_; i++) { bucket_length = UnparseBucket(*list[i], buf, bucket_length, size, "", &stats); } RAW_DCHECK(bucket_length < size, ""); dealloc_(list); RAW_DCHECK(buf + bucket_length <= map_start, ""); memmove(buf + bucket_length, map_start, map_length); // close the gap return bucket_length + map_length; } inline void HeapProfileTable::DumpNonLiveIterator(const void* ptr, AllocValue* v, const DumpArgs& args) { if (v->live()) { v->set_live(false); return; } if (v->ignore()) { return; } Bucket b; memset(&b, 0, sizeof(b)); b.allocs = 1; b.alloc_size = v->bytes; b.depth = v->bucket()->depth; b.stack = v->bucket()->stack; char buf[1024]; int len = UnparseBucket(b, buf, 0, sizeof(buf), "", args.profile_stats); RawWrite(args.fd, buf, len); } // Callback from NonLiveSnapshot; adds entry to arg->dest // if not the entry is not live and is not present in arg->base. void HeapProfileTable::AddIfNonLive(const void* ptr, AllocValue* v, AddNonLiveArgs* arg) { if (v->live()) { v->set_live(false); } else { if (arg->base != NULL && arg->base->map_.Find(ptr) != NULL) { // Present in arg->base, so do not save } else { arg->dest->Add(ptr, *v); } } } bool HeapProfileTable::WriteProfile(const char* file_name, const Bucket& total, AllocationMap* allocations) { RAW_VLOG(1, "Dumping non-live heap profile to %s", file_name); RawFD fd = RawOpenForWriting(file_name); if (fd != kIllegalRawFD) { RawWrite(fd, kProfileHeader, strlen(kProfileHeader)); char buf[512]; int len = UnparseBucket(total, buf, 0, sizeof(buf), " heapprofile", NULL); RawWrite(fd, buf, len); const DumpArgs args(fd, NULL); allocations->Iterate(DumpNonLiveIterator, args); RawWrite(fd, kProcSelfMapsHeader, strlen(kProcSelfMapsHeader)); DumpProcSelfMaps(fd); RawClose(fd); return true; } else { RAW_LOG(ERROR, "Failed dumping filtered heap profile to %s", file_name); return false; } } void HeapProfileTable::CleanupOldProfiles(const char* prefix) { if (!FLAGS_cleanup_old_heap_profiles) return; string pattern = string(prefix) + ".*" + kFileExt; #if defined(HAVE_GLOB_H) glob_t g; const int r = glob(pattern.c_str(), GLOB_ERR, NULL, &g); if (r == 0 || r == GLOB_NOMATCH) { const int prefix_length = strlen(prefix); for (int i = 0; i < g.gl_pathc; i++) { const char* fname = g.gl_pathv[i]; if ((strlen(fname) >= prefix_length) && (memcmp(fname, prefix, prefix_length) == 0)) { RAW_VLOG(1, "Removing old heap profile %s", fname); unlink(fname); } } } globfree(&g); #else /* HAVE_GLOB_H */ RAW_LOG(WARNING, "Unable to remove old heap profiles (can't run glob())"); #endif } HeapProfileTable::Snapshot* HeapProfileTable::TakeSnapshot() { Snapshot* s = new (alloc_(sizeof(Snapshot))) Snapshot(alloc_, dealloc_); allocation_->Iterate(AddToSnapshot, s); return s; } void HeapProfileTable::ReleaseSnapshot(Snapshot* s) { s->~Snapshot(); dealloc_(s); } // Callback from TakeSnapshot; adds a single entry to snapshot void HeapProfileTable::AddToSnapshot(const void* ptr, AllocValue* v, Snapshot* snapshot) { snapshot->Add(ptr, *v); } HeapProfileTable::Snapshot* HeapProfileTable::NonLiveSnapshot( Snapshot* base) { RAW_VLOG(2, "NonLiveSnapshot input: %d %d\n", int(total_.allocs - total_.frees), int(total_.alloc_size - total_.free_size)); Snapshot* s = new (alloc_(sizeof(Snapshot))) Snapshot(alloc_, dealloc_); AddNonLiveArgs args; args.dest = s; args.base = base; allocation_->Iterate(AddIfNonLive, &args); RAW_VLOG(2, "NonLiveSnapshot output: %d %d\n", int(s->total_.allocs - s->total_.frees), int(s->total_.alloc_size - s->total_.free_size)); return s; } // Information kept per unique bucket seen struct HeapProfileTable::Snapshot::Entry { int count; int bytes; Bucket* bucket; Entry() : count(0), bytes(0) { } // Order by decreasing bytes bool operator<(const Entry& x) const { return this->bytes > x.bytes; } }; // State used to generate leak report. We keep a mapping from Bucket pointer // the collected stats for that bucket. struct HeapProfileTable::Snapshot::ReportState { map buckets_; }; // Callback from ReportLeaks; updates ReportState. void HeapProfileTable::Snapshot::ReportCallback(const void* ptr, AllocValue* v, ReportState* state) { Entry* e = &state->buckets_[v->bucket()]; // Creates empty Entry first time e->bucket = v->bucket(); e->count++; e->bytes += v->bytes; } void HeapProfileTable::Snapshot::ReportLeaks(const char* checker_name, const char* filename, bool should_symbolize) { // This is only used by the heap leak checker, but is intimately // tied to the allocation map that belongs in this module and is // therefore placed here. RAW_LOG(ERROR, "Leak check %s detected leaks of %"PRIuS" bytes " "in %"PRIuS" objects", checker_name, size_t(total_.alloc_size), size_t(total_.allocs)); // Group objects by Bucket ReportState state; map_.Iterate(&ReportCallback, &state); // Sort buckets by decreasing leaked size const int n = state.buckets_.size(); Entry* entries = new Entry[n]; int dst = 0; for (map::const_iterator iter = state.buckets_.begin(); iter != state.buckets_.end(); ++iter) { entries[dst++] = iter->second; } sort(entries, entries + n); // Report a bounded number of leaks to keep the leak report from // growing too long. const int to_report = (FLAGS_heap_check_max_leaks > 0 && n > FLAGS_heap_check_max_leaks) ? FLAGS_heap_check_max_leaks : n; RAW_LOG(ERROR, "The %d largest leaks:", to_report); // Print SymbolTable symbolization_table; for (int i = 0; i < to_report; i++) { const Entry& e = entries[i]; for (int j = 0; j < e.bucket->depth; j++) { symbolization_table.Add(e.bucket->stack[j]); } } static const int kBufSize = 2<<10; char buffer[kBufSize]; if (should_symbolize) symbolization_table.Symbolize(); for (int i = 0; i < to_report; i++) { const Entry& e = entries[i]; base::RawPrinter printer(buffer, kBufSize); printer.Printf("Leak of %d bytes in %d objects allocated from:\n", e.bytes, e.count); for (int j = 0; j < e.bucket->depth; j++) { const void* pc = e.bucket->stack[j]; printer.Printf("\t@ %"PRIxPTR" %s\n", reinterpret_cast(pc), symbolization_table.GetSymbol(pc)); } RAW_LOG(ERROR, "%s", buffer); } if (to_report < n) { RAW_LOG(ERROR, "Skipping leaks numbered %d..%d", to_report, n-1); } delete[] entries; // TODO: Dump the sorted Entry list instead of dumping raw data? // (should be much shorter) if (!HeapProfileTable::WriteProfile(filename, total_, &map_)) { RAW_LOG(ERROR, "Could not write pprof profile to %s", filename); } } void HeapProfileTable::Snapshot::ReportObject(const void* ptr, AllocValue* v, char* unused) { // Perhaps also log the allocation stack trace (unsymbolized) // on this line in case somebody finds it useful. RAW_LOG(ERROR, "leaked %"PRIuS" byte object %p", v->bytes, ptr); } void HeapProfileTable::Snapshot::ReportIndividualObjects() { char unused; map_.Iterate(ReportObject, &unused); } ================================================ FILE: distro/google-perftools-1.7/src/heap-profile-table.h ================================================ // Copyright (c) 2006, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // Maxim Lifantsev (refactoring) // #ifndef BASE_HEAP_PROFILE_TABLE_H_ #define BASE_HEAP_PROFILE_TABLE_H_ #include "addressmap-inl.h" #include "base/basictypes.h" #include "base/logging.h" // for RawFD // Table to maintain a heap profile data inside, // i.e. the set of currently active heap memory allocations. // thread-unsafe and non-reentrant code: // each instance object must be used by one thread // at a time w/o self-recursion. // // TODO(maxim): add a unittest for this class. class HeapProfileTable { public: // Extension to be used for heap pforile files. static const char kFileExt[]; // Longest stack trace we record. static const int kMaxStackDepth = 32; // data types ---------------------------- // Profile stats. struct Stats { int32 allocs; // Number of allocation calls int32 frees; // Number of free calls int64 alloc_size; // Total size of all allocated objects so far int64 free_size; // Total size of all freed objects so far // semantic equality bool Equivalent(const Stats& x) const { return allocs - frees == x.allocs - x.frees && alloc_size - free_size == x.alloc_size - x.free_size; } }; // Info we can return about an allocation. struct AllocInfo { size_t object_size; // size of the allocation const void* const* call_stack; // call stack that made the allocation call int stack_depth; // depth of call_stack bool live; bool ignored; }; // Info we return about an allocation context. // An allocation context is a unique caller stack trace // of an allocation operation. struct AllocContextInfo : public Stats { int stack_depth; // Depth of stack trace const void* const* call_stack; // Stack trace }; // Memory (de)allocator interface we'll use. typedef void* (*Allocator)(size_t size); typedef void (*DeAllocator)(void* ptr); // interface --------------------------- HeapProfileTable(Allocator alloc, DeAllocator dealloc); ~HeapProfileTable(); // Record an allocation at 'ptr' of 'bytes' bytes. // skip_count gives the number of stack frames between this call // and the memory allocation function that was asked to do the allocation. void RecordAlloc(const void* ptr, size_t bytes, int skip_count); // Direct version of RecordAlloc when the caller stack to use // is already known: call_stack of depth stack_depth. void RecordAllocWithStack(const void* ptr, size_t bytes, int stack_depth, const void* const call_stack[]); // Record the deallocation of memory at 'ptr'. void RecordFree(const void* ptr); // Return true iff we have recorded an allocation at 'ptr'. // If yes, fill *object_size with the allocation byte size. bool FindAlloc(const void* ptr, size_t* object_size) const; // Same as FindAlloc, but fills all of *info. bool FindAllocDetails(const void* ptr, AllocInfo* info) const; // Return true iff "ptr" points into a recorded allocation // If yes, fill *object_ptr with the actual allocation address // and *object_size with the allocation byte size. // max_size specifies largest currently possible allocation size. bool FindInsideAlloc(const void* ptr, size_t max_size, const void** object_ptr, size_t* object_size) const; // If "ptr" points to a recorded allocation and it's not marked as live // mark it as live and return true. Else return false. // All allocations start as non-live. bool MarkAsLive(const void* ptr); // If "ptr" points to a recorded allocation, mark it as "ignored". // Ignored objects are treated like other objects, except that they // are skipped in heap checking reports. void MarkAsIgnored(const void* ptr); // Return current total (de)allocation statistics. const Stats& total() const { return total_; } // Allocation data iteration callback: gets passed object pointer and // fully-filled AllocInfo. typedef void (*AllocIterator)(const void* ptr, const AllocInfo& info); // Iterate over the allocation profile data calling "callback" // for every allocation. void IterateAllocs(AllocIterator callback) const { allocation_->Iterate(MapArgsAllocIterator, callback); } // Allocation context profile data iteration callback typedef void (*AllocContextIterator)(const AllocContextInfo& info); // Iterate over the allocation context profile data calling "callback" // for every allocation context. Allocation contexts are ordered by the // size of allocated space. void IterateOrderedAllocContexts(AllocContextIterator callback) const; // Fill profile data into buffer 'buf' of size 'size' // and return the actual size occupied by the dump in 'buf'. // The profile buckets are dumped in the decreasing order // of currently allocated bytes. // We do not provision for 0-terminating 'buf'. int FillOrderedProfile(char buf[], int size) const; // Cleanup any old profile files matching prefix + ".*" + kFileExt. static void CleanupOldProfiles(const char* prefix); // Return a snapshot of the current contents of *this. // Caller must call ReleaseSnapshot() on result when no longer needed. // The result is only valid while this exists and until // the snapshot is discarded by calling ReleaseSnapshot(). class Snapshot; Snapshot* TakeSnapshot(); // Release a previously taken snapshot. snapshot must not // be used after this call. void ReleaseSnapshot(Snapshot* snapshot); // Return a snapshot of every non-live, non-ignored object in *this. // If "base" is non-NULL, skip any objects present in "base". // As a side-effect, clears the "live" bit on every live object in *this. // Caller must call ReleaseSnapshot() on result when no longer needed. Snapshot* NonLiveSnapshot(Snapshot* base); private: // data types ---------------------------- // Hash table bucket to hold (de)allocation stats // for a given allocation call stack trace. struct Bucket : public Stats { uintptr_t hash; // Hash value of the stack trace int depth; // Depth of stack trace const void** stack; // Stack trace Bucket* next; // Next entry in hash-table }; // Info stored in the address map struct AllocValue { // Access to the stack-trace bucket Bucket* bucket() const { return reinterpret_cast(bucket_rep & ~uintptr_t(kMask)); } // This also does set_live(false). void set_bucket(Bucket* b) { bucket_rep = reinterpret_cast(b); } size_t bytes; // Number of bytes in this allocation // Access to the allocation liveness flag (for leak checking) bool live() const { return bucket_rep & kLive; } void set_live(bool l) { bucket_rep = (bucket_rep & ~uintptr_t(kLive)) | (l ? kLive : 0); } // Should this allocation be ignored if it looks like a leak? bool ignore() const { return bucket_rep & kIgnore; } void set_ignore(bool r) { bucket_rep = (bucket_rep & ~uintptr_t(kIgnore)) | (r ? kIgnore : 0); } private: // We store a few bits in the bottom bits of bucket_rep. // (Alignment is at least four, so we have at least two bits.) static const int kLive = 1; static const int kIgnore = 2; static const int kMask = kLive | kIgnore; uintptr_t bucket_rep; }; // helper for FindInsideAlloc static size_t AllocValueSize(const AllocValue& v) { return v.bytes; } typedef AddressMap AllocationMap; // Arguments that need to be passed DumpNonLiveIterator callback below. struct DumpArgs { RawFD fd; // file to write to Stats* profile_stats; // stats to update (may be NULL) DumpArgs(RawFD a, Stats* d) : fd(a), profile_stats(d) { } }; // helpers ---------------------------- // Unparse bucket b and print its portion of profile dump into buf. // We return the amount of space in buf that we use. We start printing // at buf + buflen, and promise not to go beyond buf + bufsize. // We do not provision for 0-terminating 'buf'. // // If profile_stats is non-NULL, we update *profile_stats by // counting bucket b. // // "extra" is appended to the unparsed bucket. Typically it is empty, // but may be set to something like " heapprofile" for the total // bucket to indicate the type of the profile. static int UnparseBucket(const Bucket& b, char* buf, int buflen, int bufsize, const char* extra, Stats* profile_stats); // Get the bucket for the caller stack trace 'key' of depth 'depth' // creating the bucket if needed. Bucket* GetBucket(int depth, const void* const key[]); // Helper for IterateAllocs to do callback signature conversion // from AllocationMap::Iterate to AllocIterator. static void MapArgsAllocIterator(const void* ptr, AllocValue* v, AllocIterator callback) { AllocInfo info; info.object_size = v->bytes; info.call_stack = v->bucket()->stack; info.stack_depth = v->bucket()->depth; info.live = v->live(); info.ignored = v->ignore(); callback(ptr, info); } // Helper for DumpNonLiveProfile to do object-granularity // heap profile dumping. It gets passed to AllocationMap::Iterate. inline static void DumpNonLiveIterator(const void* ptr, AllocValue* v, const DumpArgs& args); // Helper for IterateOrderedAllocContexts and FillOrderedProfile. // Creates a sorted list of Buckets whose length is num_buckets_. // The caller is responsible for dellocating the returned list. Bucket** MakeSortedBucketList() const; // Helper for TakeSnapshot. Saves object to snapshot. static void AddToSnapshot(const void* ptr, AllocValue* v, Snapshot* s); // Arguments passed to AddIfNonLive struct AddNonLiveArgs { Snapshot* dest; Snapshot* base; }; // Helper for NonLiveSnapshot. Adds the object to the destination // snapshot if it is non-live. static void AddIfNonLive(const void* ptr, AllocValue* v, AddNonLiveArgs* arg); // Write contents of "*allocations" as a heap profile to // "file_name". "total" must contain the total of all entries in // "*allocations". static bool WriteProfile(const char* file_name, const Bucket& total, AllocationMap* allocations); // data ---------------------------- // Memory (de)allocator that we use. Allocator alloc_; DeAllocator dealloc_; // Overall profile stats; we use only the Stats part, // but make it a Bucket to pass to UnparseBucket. Bucket total_; // Bucket hash table. // We hand-craft one instead of using one of the pre-written // ones because we do not want to use malloc when operating on the table. // It is only few lines of code, so no big deal. Bucket** table_; int num_buckets_; // Map of all currently allocated objects we know about. AllocationMap* allocation_; DISALLOW_COPY_AND_ASSIGN(HeapProfileTable); }; class HeapProfileTable::Snapshot { public: const Stats& total() const { return total_; } // Report anything in this snapshot as a leak. // May use new/delete for temporary storage. // If should_symbolize is true, will fork (which is not threadsafe) // to turn addresses into symbol names. Set to false for maximum safety. // Also writes a heap profile to "filename" that contains // all of the objects in this snapshot. void ReportLeaks(const char* checker_name, const char* filename, bool should_symbolize); // Report the addresses of all leaked objects. // May use new/delete for temporary storage. void ReportIndividualObjects(); bool Empty() const { return (total_.allocs == 0) && (total_.alloc_size == 0); } private: friend class HeapProfileTable; // Total count/size are stored in a Bucket so we can reuse UnparseBucket Bucket total_; // We share the Buckets managed by the parent table, but have our // own object->bucket map. AllocationMap map_; Snapshot(Allocator alloc, DeAllocator dealloc) : map_(alloc, dealloc) { memset(&total_, 0, sizeof(total_)); } // Callback used to populate a Snapshot object with entries found // in another allocation map. inline void Add(const void* ptr, const AllocValue& v) { map_.Insert(ptr, v); total_.allocs++; total_.alloc_size += v.bytes; } // Helpers for sorting and generating leak reports struct Entry; struct ReportState; static void ReportCallback(const void* ptr, AllocValue* v, ReportState*); static void ReportObject(const void* ptr, AllocValue* v, char*); DISALLOW_COPY_AND_ASSIGN(Snapshot); }; #endif // BASE_HEAP_PROFILE_TABLE_H_ ================================================ FILE: distro/google-perftools-1.7/src/heap-profiler.cc ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // TODO: Log large allocations #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #ifdef HAVE_FCNTL_H #include // for open() #endif #ifdef HAVE_MMAP #include #endif #include #include #include #include #include #include #include "base/logging.h" #include "base/basictypes.h" // for PRId64, among other things #include "base/googleinit.h" #include "base/commandlineflags.h" #include "malloc_hook-inl.h" #include "tcmalloc_guard.h" #include #include #include "base/spinlock.h" #include "base/low_level_alloc.h" #include "base/sysinfo.h" // for GetUniquePathFromEnv() #include "heap-profile-table.h" #include "memory_region_map.h" #ifndef PATH_MAX #ifdef MAXPATHLEN #define PATH_MAX MAXPATHLEN #else #define PATH_MAX 4096 // seems conservative for max filename len! #endif #endif using STL_NAMESPACE::string; using STL_NAMESPACE::sort; //---------------------------------------------------------------------- // Flags that control heap-profiling // // The thread-safety of the profiler depends on these being immutable // after main starts, so don't change them. //---------------------------------------------------------------------- DEFINE_int64(heap_profile_allocation_interval, EnvToInt64("HEAP_PROFILE_ALLOCATION_INTERVAL", 1 << 30 /*1GB*/), "If non-zero, dump heap profiling information once every " "specified number of bytes allocated by the program since " "the last dump."); DEFINE_int64(heap_profile_deallocation_interval, EnvToInt64("HEAP_PROFILE_DEALLOCATION_INTERVAL", 0), "If non-zero, dump heap profiling information once every " "specified number of bytes deallocated by the program " "since the last dump."); // We could also add flags that report whenever inuse_bytes changes by // X or -X, but there hasn't been a need for that yet, so we haven't. DEFINE_int64(heap_profile_inuse_interval, EnvToInt64("HEAP_PROFILE_INUSE_INTERVAL", 100 << 20 /*100MB*/), "If non-zero, dump heap profiling information whenever " "the high-water memory usage mark increases by the specified " "number of bytes."); DEFINE_bool(mmap_log, EnvToBool("HEAP_PROFILE_MMAP_LOG", false), "Should mmap/munmap calls be logged?"); DEFINE_bool(mmap_profile, EnvToBool("HEAP_PROFILE_MMAP", false), "If heap-profiling is on, also profile mmap, mremap, and sbrk)"); DEFINE_bool(only_mmap_profile, EnvToBool("HEAP_PROFILE_ONLY_MMAP", false), "If heap-profiling is on, only profile mmap, mremap, and sbrk; " "do not profile malloc/new/etc"); //---------------------------------------------------------------------- // Locking //---------------------------------------------------------------------- // A pthread_mutex has way too much lock contention to be used here. // // I would like to use Mutex, but it can call malloc(), // which can cause us to fall into an infinite recursion. // // So we use a simple spinlock. static SpinLock heap_lock(SpinLock::LINKER_INITIALIZED); //---------------------------------------------------------------------- // Simple allocator for heap profiler's internal memory //---------------------------------------------------------------------- static LowLevelAlloc::Arena *heap_profiler_memory; static void* ProfilerMalloc(size_t bytes) { return LowLevelAlloc::AllocWithArena(bytes, heap_profiler_memory); } static void ProfilerFree(void* p) { LowLevelAlloc::Free(p); } // We use buffers of this size in DoGetHeapProfile. static const int kProfileBufferSize = 1 << 20; // This is a last-ditch buffer we use in DumpProfileLocked in case we // can't allocate more memory from ProfilerMalloc. We expect this // will be used by HeapProfileEndWriter when the application has to // exit due to out-of-memory. This buffer is allocated in // HeapProfilerStart. Access to this must be protected by heap_lock. static char* global_profiler_buffer = NULL; //---------------------------------------------------------------------- // Profiling control/state data //---------------------------------------------------------------------- // Access to all of these is protected by heap_lock. static bool is_on = false; // If are on as a subsytem. static bool dumping = false; // Dumping status to prevent recursion static char* filename_prefix = NULL; // Prefix used for profile file names // (NULL if no need for dumping yet) static int dump_count = 0; // How many dumps so far static int64 last_dump_alloc = 0; // alloc_size when did we last dump static int64 last_dump_free = 0; // free_size when did we last dump static int64 high_water_mark = 0; // In-use-bytes at last high-water dump static HeapProfileTable* heap_profile = NULL; // the heap profile table //---------------------------------------------------------------------- // Profile generation //---------------------------------------------------------------------- enum AddOrRemove { ADD, REMOVE }; // Add or remove all MMap-allocated regions to/from *heap_profile. // Assumes heap_lock is held. static void AddRemoveMMapDataLocked(AddOrRemove mode) { RAW_DCHECK(heap_lock.IsHeld(), ""); if (!FLAGS_mmap_profile || !is_on) return; if (!FLAGS_mmap_log) MemoryRegionMap::CheckMallocHooks(); // MemoryRegionMap maintained all the data we need for all // mmap-like allocations, so we just use it here: MemoryRegionMap::LockHolder l; for (MemoryRegionMap::RegionIterator r = MemoryRegionMap::BeginRegionLocked(); r != MemoryRegionMap::EndRegionLocked(); ++r) { if (mode == ADD) { heap_profile->RecordAllocWithStack( reinterpret_cast(r->start_addr), r->end_addr - r->start_addr, r->call_stack_depth, r->call_stack); } else { heap_profile->RecordFree(reinterpret_cast(r->start_addr)); } } } // Input must be a buffer of size at least 1MB. static char* DoGetHeapProfileLocked(char* buf, int buflen) { // We used to be smarter about estimating the required memory and // then capping it to 1MB and generating the profile into that. if (buf == NULL || buflen < 1) return NULL; RAW_DCHECK(heap_lock.IsHeld(), ""); int bytes_written = 0; if (is_on) { HeapProfileTable::Stats const stats = heap_profile->total(); (void)stats; // avoid an unused-variable warning in non-debug mode. AddRemoveMMapDataLocked(ADD); bytes_written = heap_profile->FillOrderedProfile(buf, buflen - 1); // FillOrderedProfile should not reduce the set of active mmap-ed regions, // hence MemoryRegionMap will let us remove everything we've added above: AddRemoveMMapDataLocked(REMOVE); RAW_DCHECK(stats.Equivalent(heap_profile->total()), ""); // if this fails, we somehow removed by AddRemoveMMapDataLocked // more than we have added. } buf[bytes_written] = '\0'; RAW_DCHECK(bytes_written == strlen(buf), ""); return buf; } extern "C" char* GetHeapProfile() { // Use normal malloc: we return the profile to the user to free it: char* buffer = reinterpret_cast(malloc(kProfileBufferSize)); SpinLockHolder l(&heap_lock); return DoGetHeapProfileLocked(buffer, kProfileBufferSize); } // defined below static void NewHook(const void* ptr, size_t size); static void DeleteHook(const void* ptr); // Helper for HeapProfilerDump. static void DumpProfileLocked(const char* reason) { RAW_DCHECK(heap_lock.IsHeld(), ""); RAW_DCHECK(is_on, ""); RAW_DCHECK(!dumping, ""); if (filename_prefix == NULL) return; // we do not yet need dumping if (FLAGS_only_mmap_profile == false) { if (MallocHook::GetNewHook() != NewHook || MallocHook::GetDeleteHook() != DeleteHook) { RAW_LOG(FATAL, "Had our new/delete MallocHook-s replaced. " "Are you using another MallocHook client? " "Do not use --heap_profile=... to avoid this conflict."); } } dumping = true; // Make file name char file_name[1000]; dump_count++; snprintf(file_name, sizeof(file_name), "%s.%04d%s", filename_prefix, dump_count, HeapProfileTable::kFileExt); // Dump the profile RAW_VLOG(0, "Dumping heap profile to %s (%s)", file_name, reason); // We must use file routines that don't access memory, since we hold // a memory lock now. RawFD fd = RawOpenForWriting(file_name); if (fd == kIllegalRawFD) { RAW_LOG(ERROR, "Failed dumping heap profile to %s", file_name); dumping = false; return; } // This case may be impossible, but it's best to be safe. // It's safe to use the global buffer: we're protected by heap_lock. if (global_profiler_buffer == NULL) { global_profiler_buffer = reinterpret_cast(ProfilerMalloc(kProfileBufferSize)); } char* profile = DoGetHeapProfileLocked(global_profiler_buffer, kProfileBufferSize); RawWrite(fd, profile, strlen(profile)); RawClose(fd); dumping = false; } //---------------------------------------------------------------------- // Profile collection //---------------------------------------------------------------------- // Dump a profile after either an allocation or deallocation, if // the memory use has changed enough since the last dump. static void MaybeDumpProfileLocked() { if (!dumping) { const HeapProfileTable::Stats& total = heap_profile->total(); const int64 inuse_bytes = total.alloc_size - total.free_size; bool need_to_dump = false; char buf[128]; if (FLAGS_heap_profile_allocation_interval > 0 && total.alloc_size >= last_dump_alloc + FLAGS_heap_profile_allocation_interval) { snprintf(buf, sizeof(buf), ("%"PRId64" MB allocated cumulatively, " "%"PRId64" MB currently in use"), total.alloc_size >> 20, inuse_bytes >> 20); need_to_dump = true; } else if (FLAGS_heap_profile_deallocation_interval > 0 && total.free_size >= last_dump_free + FLAGS_heap_profile_deallocation_interval) { snprintf(buf, sizeof(buf), ("%"PRId64" MB freed cumulatively, " "%"PRId64" MB currently in use"), total.free_size >> 20, inuse_bytes >> 20); need_to_dump = true; } else if (FLAGS_heap_profile_inuse_interval > 0 && inuse_bytes > high_water_mark + FLAGS_heap_profile_inuse_interval) { snprintf(buf, sizeof(buf), "%"PRId64" MB currently in use", inuse_bytes >> 20); need_to_dump = true; } if (need_to_dump) { DumpProfileLocked(buf); last_dump_alloc = total.alloc_size; last_dump_free = total.free_size; if (inuse_bytes > high_water_mark) high_water_mark = inuse_bytes; } } } // Record an allocation in the profile. static void RecordAlloc(const void* ptr, size_t bytes, int skip_count) { SpinLockHolder l(&heap_lock); if (is_on) { heap_profile->RecordAlloc(ptr, bytes, skip_count + 1); MaybeDumpProfileLocked(); } } // Record a deallocation in the profile. static void RecordFree(const void* ptr) { SpinLockHolder l(&heap_lock); if (is_on) { heap_profile->RecordFree(ptr); MaybeDumpProfileLocked(); } } //---------------------------------------------------------------------- // Allocation/deallocation hooks for MallocHook //---------------------------------------------------------------------- // static void NewHook(const void* ptr, size_t size) { if (ptr != NULL) RecordAlloc(ptr, size, 0); } // static void DeleteHook(const void* ptr) { if (ptr != NULL) RecordFree(ptr); } // TODO(jandrews): Re-enable stack tracing #ifdef TODO_REENABLE_STACK_TRACING static void RawInfoStackDumper(const char* message, void*) { RAW_LOG(INFO, "%.*s", static_cast(strlen(message) - 1), message); // -1 is to chop the \n which will be added by RAW_LOG } #endif // Saved MemoryRegionMap's hooks to daisy-chain calls to. MallocHook::MmapHook saved_mmap_hook = NULL; MallocHook::MremapHook saved_mremap_hook = NULL; MallocHook::MunmapHook saved_munmap_hook = NULL; MallocHook::SbrkHook saved_sbrk_hook = NULL; static void MmapHook(const void* result, const void* start, size_t size, int prot, int flags, int fd, off_t offset) { if (FLAGS_mmap_log) { // log it // We use PRIxS not just '%p' to avoid deadlocks // in pretty-printing of NULL as "nil". // TODO(maxim): instead should use a safe snprintf reimplementation RAW_LOG(INFO, "mmap(start=0x%"PRIxPTR", len=%"PRIuS", prot=0x%x, flags=0x%x, " "fd=%d, offset=0x%x) = 0x%"PRIxPTR"", (uintptr_t) start, size, prot, flags, fd, (unsigned int) offset, (uintptr_t) result); #ifdef TODO_REENABLE_STACK_TRACING DumpStackTrace(1, RawInfoStackDumper, NULL); #endif } if (saved_mmap_hook) { // Call MemoryRegionMap's hook: it will record needed info about the mmap // for us w/o deadlocks: (*saved_mmap_hook)(result, start, size, prot, flags, fd, offset); } } static void MremapHook(const void* result, const void* old_addr, size_t old_size, size_t new_size, int flags, const void* new_addr) { if (FLAGS_mmap_log) { // log it // We use PRIxS not just '%p' to avoid deadlocks // in pretty-printing of NULL as "nil". // TODO(maxim): instead should use a safe snprintf reimplementation RAW_LOG(INFO, "mremap(old_addr=0x%"PRIxPTR", old_size=%"PRIuS", " "new_size=%"PRIuS", flags=0x%x, new_addr=0x%"PRIxPTR") = " "0x%"PRIxPTR"", (uintptr_t) old_addr, old_size, new_size, flags, (uintptr_t) new_addr, (uintptr_t) result); #ifdef TODO_REENABLE_STACK_TRACING DumpStackTrace(1, RawInfoStackDumper, NULL); #endif } if (saved_mremap_hook) { // call MemoryRegionMap's hook (*saved_mremap_hook)(result, old_addr, old_size, new_size, flags, new_addr); } } static void MunmapHook(const void* ptr, size_t size) { if (FLAGS_mmap_log) { // log it // We use PRIxS not just '%p' to avoid deadlocks // in pretty-printing of NULL as "nil". // TODO(maxim): instead should use a safe snprintf reimplementation RAW_LOG(INFO, "munmap(start=0x%"PRIxPTR", len=%"PRIuS")", (uintptr_t) ptr, size); #ifdef TODO_REENABLE_STACK_TRACING DumpStackTrace(1, RawInfoStackDumper, NULL); #endif } if (saved_munmap_hook) { // call MemoryRegionMap's hook (*saved_munmap_hook)(ptr, size); } } static void SbrkHook(const void* result, ptrdiff_t increment) { if (FLAGS_mmap_log) { // log it RAW_LOG(INFO, "sbrk(inc=%"PRIdS") = 0x%"PRIxPTR"", increment, (uintptr_t) result); #ifdef TODO_REENABLE_STACK_TRACING DumpStackTrace(1, RawInfoStackDumper, NULL); #endif } if (saved_sbrk_hook) { // call MemoryRegionMap's hook (*saved_sbrk_hook)(result, increment); } } //---------------------------------------------------------------------- // Starting/stopping/dumping //---------------------------------------------------------------------- extern "C" void HeapProfilerStart(const char* prefix) { SpinLockHolder l(&heap_lock); if (is_on) return; is_on = true; RAW_VLOG(0, "Starting tracking the heap"); // This should be done before the hooks are set up, since it should // call new, and we want that to be accounted for correctly. MallocExtension::Initialize(); if (FLAGS_only_mmap_profile) { FLAGS_mmap_profile = true; } if (FLAGS_mmap_profile) { // Ask MemoryRegionMap to record all mmap, mremap, and sbrk // call stack traces of at least size kMaxStackDepth: MemoryRegionMap::Init(HeapProfileTable::kMaxStackDepth); } if (FLAGS_mmap_log) { // Install our hooks to do the logging // and maybe save MemoryRegionMap's hooks to call: saved_mmap_hook = MallocHook::SetMmapHook(MmapHook); saved_mremap_hook = MallocHook::SetMremapHook(MremapHook); saved_munmap_hook = MallocHook::SetMunmapHook(MunmapHook); saved_sbrk_hook = MallocHook::SetSbrkHook(SbrkHook); } heap_profiler_memory = LowLevelAlloc::NewArena(0, LowLevelAlloc::DefaultArena()); // Reserve space now for the heap profiler, so we can still write a // heap profile even if the application runs out of memory. global_profiler_buffer = reinterpret_cast(ProfilerMalloc(kProfileBufferSize)); heap_profile = new(ProfilerMalloc(sizeof(HeapProfileTable))) HeapProfileTable(ProfilerMalloc, ProfilerFree); last_dump_alloc = 0; last_dump_free = 0; high_water_mark = 0; // We do not reset dump_count so if the user does a sequence of // HeapProfilerStart/HeapProfileStop, we will get a continuous // sequence of profiles. if (FLAGS_only_mmap_profile == false) { // Now set the hooks that capture new/delete and malloc/free // and check that these are the only hooks: if (MallocHook::SetNewHook(NewHook) != NULL || MallocHook::SetDeleteHook(DeleteHook) != NULL) { RAW_LOG(FATAL, "Had other new/delete MallocHook-s set. " "Are you using the heap leak checker? " "Use --heap_check=\"\" to avoid this conflict."); } } // Copy filename prefix RAW_DCHECK(filename_prefix == NULL, ""); const int prefix_length = strlen(prefix); filename_prefix = reinterpret_cast(ProfilerMalloc(prefix_length + 1)); memcpy(filename_prefix, prefix, prefix_length); filename_prefix[prefix_length] = '\0'; } extern "C" int IsHeapProfilerRunning() { SpinLockHolder l(&heap_lock); return is_on ? 1 : 0; // return an int, because C code doesn't have bool } extern "C" void HeapProfilerStop() { SpinLockHolder l(&heap_lock); if (!is_on) return; if (FLAGS_only_mmap_profile == false) { // Unset our new/delete hooks, checking they were the ones set: if (MallocHook::SetNewHook(NULL) != NewHook || MallocHook::SetDeleteHook(NULL) != DeleteHook) { RAW_LOG(FATAL, "Had our new/delete MallocHook-s replaced. " "Are you using another MallocHook client? " "Do not use --heap_profile=... to avoid this conflict."); } } if (FLAGS_mmap_log) { // Restore mmap/sbrk hooks, checking that our hooks were the ones set: if (MallocHook::SetMmapHook(saved_mmap_hook) != MmapHook || MallocHook::SetMremapHook(saved_mremap_hook) != MremapHook || MallocHook::SetMunmapHook(saved_munmap_hook) != MunmapHook || MallocHook::SetSbrkHook(saved_sbrk_hook) != SbrkHook) { RAW_LOG(FATAL, "Had our mmap/mremap/munmap/sbrk MallocHook-s replaced. " "Are you using another MallocHook client? " "Do not use --heap_profile=... to avoid this conflict."); } } // free profile heap_profile->~HeapProfileTable(); ProfilerFree(heap_profile); heap_profile = NULL; // free output-buffer memory ProfilerFree(global_profiler_buffer); // free prefix ProfilerFree(filename_prefix); filename_prefix = NULL; if (!LowLevelAlloc::DeleteArena(heap_profiler_memory)) { RAW_LOG(FATAL, "Memory leak in HeapProfiler:"); } if (FLAGS_mmap_profile) { MemoryRegionMap::Shutdown(); } is_on = false; } extern "C" void HeapProfilerDump(const char *reason) { SpinLockHolder l(&heap_lock); if (is_on && !dumping) { DumpProfileLocked(reason); } } //---------------------------------------------------------------------- // Initialization/finalization code //---------------------------------------------------------------------- // Initialization code static void HeapProfilerInit() { // Everything after this point is for setting up the profiler based on envvar char fname[PATH_MAX]; if (!GetUniquePathFromEnv("HEAPPROFILE", fname)) { return; } // We do a uid check so we don't write out files in a setuid executable. #ifdef HAVE_GETEUID if (getuid() != geteuid()) { RAW_LOG(WARNING, ("HeapProfiler: ignoring HEAPPROFILE because " "program seems to be setuid\n")); return; } #endif HeapProfileTable::CleanupOldProfiles(fname); HeapProfilerStart(fname); } // class used for finalization -- dumps the heap-profile at program exit struct HeapProfileEndWriter { ~HeapProfileEndWriter() { HeapProfilerDump("Exiting"); } }; // We want to make sure tcmalloc is up and running before starting the profiler static const TCMallocGuard tcmalloc_initializer; REGISTER_MODULE_INITIALIZER(heapprofiler, HeapProfilerInit()); static HeapProfileEndWriter heap_profile_end_writer; ================================================ FILE: distro/google-perftools-1.7/src/internal_logging.cc ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Sanjay Ghemawat #include #include #include #ifdef HAVE_UNISTD_H #include // for write() #endif #include #include #include "internal_logging.h" static const int kLogBufSize = 800; void TCMalloc_MESSAGE(const char* filename, int line_number, const char* format, ...) { char buf[kLogBufSize]; const int n = snprintf(buf, sizeof(buf), "%s:%d] ", filename, line_number); if (n < kLogBufSize) { va_list ap; va_start(ap, format); vsnprintf(buf + n, kLogBufSize - n, format, ap); va_end(ap); } write(STDERR_FILENO, buf, strlen(buf)); } static const int kStatsBufferSize = 16 << 10; static char stats_buffer[kStatsBufferSize] = { 0 }; static void TCMalloc_CRASH_internal(bool dump_stats, const char* filename, int line_number, const char* format, va_list ap) { char buf[kLogBufSize]; const int n = snprintf(buf, sizeof(buf), "%s:%d] ", filename, line_number); if (n < kLogBufSize) { vsnprintf(buf + n, kLogBufSize - n, format, ap); } write(STDERR_FILENO, buf, strlen(buf)); if (dump_stats) { MallocExtension::instance()->GetStats(stats_buffer, kStatsBufferSize); write(STDERR_FILENO, stats_buffer, strlen(stats_buffer)); } abort(); } void TCMalloc_CRASH(bool dump_stats, const char* filename, int line_number, const char* format, ...) { va_list ap; va_start(ap, format); TCMalloc_CRASH_internal(dump_stats, filename, line_number, format, ap); va_end(ap); } void TCMalloc_CrashReporter::PrintfAndDie(const char* format, ...) { va_list ap; va_start(ap, format); TCMalloc_CRASH_internal(dump_stats_, file_, line_, format, ap); va_end(ap); } void TCMalloc_Printer::printf(const char* format, ...) { if (left_ > 0) { va_list ap; va_start(ap, format); const int r = vsnprintf(buf_, left_, format, ap); va_end(ap); if (r < 0) { // Perhaps an old glibc that returns -1 on truncation? left_ = 0; } else if (r > left_) { // Truncation left_ = 0; } else { left_ -= r; buf_ += r; } } } ================================================ FILE: distro/google-perftools-1.7/src/internal_logging.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // Internal logging and related utility routines. #ifndef TCMALLOC_INTERNAL_LOGGING_H_ #define TCMALLOC_INTERNAL_LOGGING_H_ #include #include // for abort() #ifdef HAVE_UNISTD_H #include // for write() #endif //------------------------------------------------------------------- // Utility routines //------------------------------------------------------------------- // Safe debugging routine: we write directly to the stderr file // descriptor and avoid FILE buffering because that may invoke // malloc() extern void TCMalloc_MESSAGE(const char* filename, int line_number, const char* format, ...) #ifdef HAVE___ATTRIBUTE__ __attribute__ ((__format__ (__printf__, 3, 4))) #endif ; // Right now, the only non-fatal messages we want to report are when // an allocation fails (we'll return NULL eventually, but sometimes // want more prominent notice to help debug). message should be // a literal string with no % format directives. #ifdef TCMALLOC_WARNINGS #define MESSAGE(message, num_bytes) \ TCMalloc_MESSAGE(__FILE__, __LINE__, message " (%"PRIuS" bytes)\n", \ static_cast(num_bytes)) #else #define MESSAGE(message, num_bytes) #endif // Dumps the specified message and then calls abort(). If // "dump_stats" is specified, the first call will also dump the // tcmalloc stats. extern void TCMalloc_CRASH(bool dump_stats, const char* filename, int line_number, const char* format, ...) #ifdef HAVE___ATTRIBUTE__ __attribute__ ((__format__ (__printf__, 4, 5))) #endif ; // This is a class that makes using the macro easier. With this class, // CRASH("%d", i) expands to TCMalloc_CrashReporter.PrintfAndDie("%d", i). class PERFTOOLS_DLL_DECL TCMalloc_CrashReporter { public: TCMalloc_CrashReporter(bool dump_stats, const char* file, int line) : dump_stats_(dump_stats), file_(file), line_(line) { } void PrintfAndDie(const char* format, ...) #ifdef HAVE___ATTRIBUTE__ __attribute__ ((__format__ (__printf__, 2, 3))) // 2,3 due to "this" #endif ; private: bool dump_stats_; const char* file_; int line_; }; #define CRASH \ TCMalloc_CrashReporter(false, __FILE__, __LINE__).PrintfAndDie #define CRASH_WITH_STATS \ TCMalloc_CrashReporter(true, __FILE__, __LINE__).PrintfAndDie // Like assert(), but executed even in NDEBUG mode #undef CHECK_CONDITION #define CHECK_CONDITION(cond) \ do { \ if (!(cond)) { \ CRASH("assertion failed: %s\n", #cond); \ } \ } while (0) // Our own version of assert() so we can avoid hanging by trying to do // all kinds of goofy printing while holding the malloc lock. #ifndef NDEBUG #define ASSERT(cond) CHECK_CONDITION(cond) #else #define ASSERT(cond) ((void) 0) #endif // Print into buffer class TCMalloc_Printer { private: char* buf_; // Where should we write next int left_; // Space left in buffer (including space for \0) public: // REQUIRES: "length > 0" TCMalloc_Printer(char* buf, int length) : buf_(buf), left_(length) { buf[0] = '\0'; } void printf(const char* format, ...) #ifdef HAVE___ATTRIBUTE__ __attribute__ ((__format__ (__printf__, 2, 3))) #endif ; }; #endif // TCMALLOC_INTERNAL_LOGGING_H_ ================================================ FILE: distro/google-perftools-1.7/src/linked_list.h ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // Some very basic linked list functions for dealing with using void * as // storage. #ifndef TCMALLOC_LINKED_LIST_H_ #define TCMALLOC_LINKED_LIST_H_ #include namespace tcmalloc { inline void *SLL_Next(void *t) { return *(reinterpret_cast(t)); } inline void SLL_SetNext(void *t, void *n) { *(reinterpret_cast(t)) = n; } inline void SLL_Push(void **list, void *element) { SLL_SetNext(element, *list); *list = element; } inline void *SLL_Pop(void **list) { void *result = *list; *list = SLL_Next(*list); return result; } // Remove N elements from a linked list to which head points. head will be // modified to point to the new head. start and end will point to the first // and last nodes of the range. Note that end will point to NULL after this // function is called. inline void SLL_PopRange(void **head, int N, void **start, void **end) { if (N == 0) { *start = NULL; *end = NULL; return; } void *tmp = *head; for (int i = 1; i < N; ++i) { tmp = SLL_Next(tmp); } *start = *head; *end = tmp; *head = SLL_Next(tmp); // Unlink range from list. SLL_SetNext(tmp, NULL); } inline void SLL_PushRange(void **head, void *start, void *end) { if (!start) return; SLL_SetNext(end, *head); *head = start; } inline size_t SLL_Size(void *head) { int count = 0; while (head) { count++; head = SLL_Next(head); } return count; } } // namespace tcmalloc #endif // TCMALLOC_LINKED_LIST_H_ ================================================ FILE: distro/google-perftools-1.7/src/malloc_extension.cc ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat #include #include #include #include #include #if defined HAVE_STDINT_H #include #elif defined HAVE_INTTYPES_H #include #else #include #endif #include #include "base/dynamic_annotations.h" #include "base/sysinfo.h" // for FillProcSelfMaps #ifndef NO_HEAP_CHECK #include "google/heap-checker.h" #endif #include "google/malloc_extension.h" #include "maybe_threads.h" using STL_NAMESPACE::string; using STL_NAMESPACE::vector; static void DumpAddressMap(string* result) { *result += "\nMAPPED_LIBRARIES:\n"; // We keep doubling until we get a fit const size_t old_resultlen = result->size(); for (int amap_size = 10240; amap_size < 10000000; amap_size *= 2) { result->resize(old_resultlen + amap_size); bool wrote_all = false; const int bytes_written = tcmalloc::FillProcSelfMaps(&((*result)[old_resultlen]), amap_size, &wrote_all); if (wrote_all) { // we fit! (*result)[old_resultlen + bytes_written] = '\0'; result->resize(old_resultlen + bytes_written); return; } } result->reserve(old_resultlen); // just don't print anything } // Note: this routine is meant to be called before threads are spawned. void MallocExtension::Initialize() { static bool initialize_called = false; if (initialize_called) return; initialize_called = true; #ifdef __GLIBC__ // GNU libc++ versions 3.3 and 3.4 obey the environment variables // GLIBCPP_FORCE_NEW and GLIBCXX_FORCE_NEW respectively. Setting // one of these variables forces the STL default allocator to call // new() or delete() for each allocation or deletion. Otherwise // the STL allocator tries to avoid the high cost of doing // allocations by pooling memory internally. However, tcmalloc // does allocations really fast, especially for the types of small // items one sees in STL, so it's better off just using us. // TODO: control whether we do this via an environment variable? setenv("GLIBCPP_FORCE_NEW", "1", false /* no overwrite*/); setenv("GLIBCXX_FORCE_NEW", "1", false /* no overwrite*/); // Now we need to make the setenv 'stick', which it may not do since // the env is flakey before main() is called. But luckily stl only // looks at this env var the first time it tries to do an alloc, and // caches what it finds. So we just cause an stl alloc here. string dummy("I need to be allocated"); dummy += "!"; // so the definition of dummy isn't optimized out #endif /* __GLIBC__ */ } // Default implementation -- does nothing MallocExtension::~MallocExtension() { } bool MallocExtension::VerifyAllMemory() { return true; } bool MallocExtension::VerifyNewMemory(void* p) { return true; } bool MallocExtension::VerifyArrayNewMemory(void* p) { return true; } bool MallocExtension::VerifyMallocMemory(void* p) { return true; } bool MallocExtension::GetNumericProperty(const char* property, size_t* value) { return false; } bool MallocExtension::SetNumericProperty(const char* property, size_t value) { return false; } void MallocExtension::GetStats(char* buffer, int length) { assert(length > 0); buffer[0] = '\0'; } bool MallocExtension::MallocMemoryStats(int* blocks, size_t* total, int histogram[kMallocHistogramSize]) { *blocks = 0; *total = 0; memset(histogram, 0, sizeof(*histogram) * kMallocHistogramSize); return true; } void** MallocExtension::ReadStackTraces(int* sample_period) { return NULL; } void** MallocExtension::ReadHeapGrowthStackTraces() { return NULL; } void MallocExtension::MarkThreadIdle() { // Default implementation does nothing } void MallocExtension::MarkThreadBusy() { // Default implementation does nothing } void MallocExtension::ReleaseToSystem(size_t num_bytes) { // Default implementation does nothing } void MallocExtension::ReleaseFreeMemory() { ReleaseToSystem(static_cast(-1)); // SIZE_T_MAX } void MallocExtension::SetMemoryReleaseRate(double rate) { // Default implementation does nothing } double MallocExtension::GetMemoryReleaseRate() { return -1.0; } size_t MallocExtension::GetEstimatedAllocatedSize(size_t size) { return size; } size_t MallocExtension::GetAllocatedSize(void* p) { return 0; } void MallocExtension::GetFreeListSizes( vector* v) { v->clear(); } // The current malloc extension object. static pthread_once_t module_init = PTHREAD_ONCE_INIT; static MallocExtension* current_instance = NULL; static void InitModule() { current_instance = new MallocExtension; #ifndef NO_HEAP_CHECK HeapLeakChecker::IgnoreObject(current_instance); #endif } MallocExtension* MallocExtension::instance() { perftools_pthread_once(&module_init, InitModule); return current_instance; } void MallocExtension::Register(MallocExtension* implementation) { perftools_pthread_once(&module_init, InitModule); // When running under valgrind, our custom malloc is replaced with // valgrind's one and malloc extensions will not work. (Note: // callers should be responsible for checking that they are the // malloc that is really being run, before calling Register. This // is just here as an extra sanity check.) if (!RunningOnValgrind()) { current_instance = implementation; } } // ----------------------------------------------------------------------- // Heap sampling support // ----------------------------------------------------------------------- namespace { // Accessors uintptr_t Count(void** entry) { return reinterpret_cast(entry[0]); } uintptr_t Size(void** entry) { return reinterpret_cast(entry[1]); } uintptr_t Depth(void** entry) { return reinterpret_cast(entry[2]); } void* PC(void** entry, int i) { return entry[3+i]; } void PrintCountAndSize(MallocExtensionWriter* writer, uintptr_t count, uintptr_t size) { char buf[100]; snprintf(buf, sizeof(buf), "%6lld: %8lld [%6lld: %8lld] @", static_cast(count), static_cast(size), static_cast(count), static_cast(size)); writer->append(buf, strlen(buf)); } void PrintHeader(MallocExtensionWriter* writer, const char* label, void** entries) { // Compute the total count and total size uintptr_t total_count = 0; uintptr_t total_size = 0; for (void** entry = entries; Count(entry) != 0; entry += 3 + Depth(entry)) { total_count += Count(entry); total_size += Size(entry); } const char* const kTitle = "heap profile: "; writer->append(kTitle, strlen(kTitle)); PrintCountAndSize(writer, total_count, total_size); writer->append(" ", 1); writer->append(label, strlen(label)); writer->append("\n", 1); } void PrintStackEntry(MallocExtensionWriter* writer, void** entry) { PrintCountAndSize(writer, Count(entry), Size(entry)); for (int i = 0; i < Depth(entry); i++) { char buf[32]; snprintf(buf, sizeof(buf), " %p", PC(entry, i)); writer->append(buf, strlen(buf)); } writer->append("\n", 1); } } void MallocExtension::GetHeapSample(MallocExtensionWriter* writer) { int sample_period = 0; void** entries = ReadStackTraces(&sample_period); if (entries == NULL) { const char* const kErrorMsg = "This malloc implementation does not support sampling.\n" "As of 2005/01/26, only tcmalloc supports sampling, and\n" "you are probably running a binary that does not use\n" "tcmalloc.\n"; writer->append(kErrorMsg, strlen(kErrorMsg)); return; } char label[32]; sprintf(label, "heap_v2/%d", sample_period); PrintHeader(writer, label, entries); for (void** entry = entries; Count(entry) != 0; entry += 3 + Depth(entry)) { PrintStackEntry(writer, entry); } delete[] entries; DumpAddressMap(writer); } void MallocExtension::GetHeapGrowthStacks(MallocExtensionWriter* writer) { void** entries = ReadHeapGrowthStackTraces(); if (entries == NULL) { const char* const kErrorMsg = "This malloc implementation does not support " "ReadHeapGrowthStackTraces().\n" "As of 2005/09/27, only tcmalloc supports this, and you\n" "are probably running a binary that does not use tcmalloc.\n"; writer->append(kErrorMsg, strlen(kErrorMsg)); return; } // Do not canonicalize the stack entries, so that we get a // time-ordered list of stack traces, which may be useful if the // client wants to focus on the latest stack traces. PrintHeader(writer, "growth", entries); for (void** entry = entries; Count(entry) != 0; entry += 3 + Depth(entry)) { PrintStackEntry(writer, entry); } delete[] entries; DumpAddressMap(writer); } void MallocExtension::Ranges(void* arg, RangeFunction func) { // No callbacks by default } // These are C shims that work on the current instance. #define C_SHIM(fn, retval, paramlist, arglist) \ extern "C" PERFTOOLS_DLL_DECL retval MallocExtension_##fn paramlist { \ return MallocExtension::instance()->fn arglist; \ } C_SHIM(VerifyAllMemory, int, (void), ()); C_SHIM(VerifyNewMemory, int, (void* p), (p)); C_SHIM(VerifyArrayNewMemory, int, (void* p), (p)); C_SHIM(VerifyMallocMemory, int, (void* p), (p)); C_SHIM(MallocMemoryStats, int, (int* blocks, size_t* total, int histogram[kMallocHistogramSize]), (blocks, total, histogram)); C_SHIM(GetStats, void, (char* buffer, int buffer_length), (buffer, buffer_length)); C_SHIM(GetNumericProperty, int, (const char* property, size_t* value), (property, value)); C_SHIM(SetNumericProperty, int, (const char* property, size_t value), (property, value)); C_SHIM(MarkThreadIdle, void, (void), ()); C_SHIM(MarkThreadBusy, void, (void), ()); C_SHIM(ReleaseFreeMemory, void, (void), ()); C_SHIM(ReleaseToSystem, void, (size_t num_bytes), (num_bytes)); C_SHIM(GetEstimatedAllocatedSize, size_t, (size_t size), (size)); C_SHIM(GetAllocatedSize, size_t, (void* p), (p)); ================================================ FILE: distro/google-perftools-1.7/src/malloc_hook-inl.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // This has the implementation details of malloc_hook that are needed // to use malloc-hook inside the tcmalloc system. It does not hold // any of the client-facing calls that are used to add new hooks. #ifndef _MALLOC_HOOK_INL_H_ #define _MALLOC_HOOK_INL_H_ #include #include #include "base/atomicops.h" #include "base/basictypes.h" #include namespace base { namespace internal { // A simple atomic pointer class that can be initialized by the linker // when you define a namespace-scope variable as: // // AtomicPtr my_global = { &initial_value }; // // This isn't suitable for a general atomic<> class because of the // public access to data_. template class AtomicPtr { public: COMPILE_ASSERT(sizeof(PtrT) <= sizeof(AtomicWord), PtrT_should_fit_in_AtomicWord); PtrT Get() const { // Depending on the system, Acquire_Load(AtomicWord*) may have // been defined to return an AtomicWord, Atomic32, or Atomic64. // We hide that implementation detail here with an explicit cast. // This prevents MSVC 2005, at least, from complaining (it has to // do with __wp64; AtomicWord is __wp64, but Atomic32/64 aren't). return reinterpret_cast(static_cast( base::subtle::Acquire_Load(&data_))); } // Sets the contained value to new_val and returns the old value, // atomically, with acquire and release semantics. // This is a full-barrier instruction. PtrT Exchange(PtrT new_val); // Atomically executes: // result = data_ // if (data_ == old_val) // data_ = new_val; // return result; // This is a full-barrier instruction. PtrT CompareAndSwap(PtrT old_val, PtrT new_val); // Not private so that the class is an aggregate and can be // initialized by the linker. Don't access this directly. AtomicWord data_; }; // These are initialized in malloc_hook.cc extern AtomicPtr new_hook_; extern AtomicPtr delete_hook_; extern AtomicPtr premmap_hook_; extern AtomicPtr mmap_hook_; extern AtomicPtr munmap_hook_; extern AtomicPtr mremap_hook_; extern AtomicPtr presbrk_hook_; extern AtomicPtr sbrk_hook_; } } // namespace base::internal inline MallocHook::NewHook MallocHook::GetNewHook() { return base::internal::new_hook_.Get(); } inline void MallocHook::InvokeNewHook(const void* p, size_t s) { MallocHook::NewHook hook = MallocHook::GetNewHook(); if (hook != NULL) (*hook)(p, s); } inline MallocHook::DeleteHook MallocHook::GetDeleteHook() { return base::internal::delete_hook_.Get(); } inline void MallocHook::InvokeDeleteHook(const void* p) { MallocHook::DeleteHook hook = MallocHook::GetDeleteHook(); if (hook != NULL) (*hook)(p); } inline MallocHook::PreMmapHook MallocHook::GetPreMmapHook() { return base::internal::premmap_hook_.Get(); } inline void MallocHook::InvokePreMmapHook(const void* start, size_t size, int protection, int flags, int fd, off_t offset) { MallocHook::PreMmapHook hook = MallocHook::GetPreMmapHook(); if (hook != NULL) (*hook)(start, size, protection, flags, fd, offset); } inline MallocHook::MmapHook MallocHook::GetMmapHook() { return base::internal::mmap_hook_.Get(); } inline void MallocHook::InvokeMmapHook(const void* result, const void* start, size_t size, int protection, int flags, int fd, off_t offset) { MallocHook::MmapHook hook = MallocHook::GetMmapHook(); if (hook != NULL) (*hook)(result, start, size, protection, flags, fd, offset); } inline MallocHook::MunmapHook MallocHook::GetMunmapHook() { return base::internal::munmap_hook_.Get(); } inline void MallocHook::InvokeMunmapHook(const void* p, size_t size) { MallocHook::MunmapHook hook = MallocHook::GetMunmapHook(); if (hook != NULL) (*hook)(p, size); } inline MallocHook::MremapHook MallocHook::GetMremapHook() { return base::internal::mremap_hook_.Get(); } inline void MallocHook::InvokeMremapHook(const void* result, const void* old_addr, size_t old_size, size_t new_size, int flags, const void* new_addr) { MallocHook::MremapHook hook = MallocHook::GetMremapHook(); if (hook != NULL) (*hook)(result, old_addr, old_size, new_size, flags, new_addr); } inline MallocHook::PreSbrkHook MallocHook::GetPreSbrkHook() { return base::internal::presbrk_hook_.Get(); } inline void MallocHook::InvokePreSbrkHook(ptrdiff_t increment) { MallocHook::PreSbrkHook hook = MallocHook::GetPreSbrkHook(); if (hook != NULL && increment != 0) (*hook)(increment); } inline MallocHook::SbrkHook MallocHook::GetSbrkHook() { return base::internal::sbrk_hook_.Get(); } inline void MallocHook::InvokeSbrkHook(const void* result, ptrdiff_t increment) { MallocHook::SbrkHook hook = MallocHook::GetSbrkHook(); if (hook != NULL && increment != 0) (*hook)(result, increment); } #endif /* _MALLOC_HOOK_INL_H_ */ ================================================ FILE: distro/google-perftools-1.7/src/malloc_hook.cc ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat #include // Disable the glibc prototype of mremap(), as older versions of the // system headers define this function with only four arguments, // whereas newer versions allow an optional fifth argument: #ifdef HAVE_MMAP # define mremap glibc_mremap # include # undef mremap #endif #include #include "base/basictypes.h" #include "base/logging.h" #include "malloc_hook-inl.h" #include // This #ifdef should almost never be set. Set NO_TCMALLOC_SAMPLES if // you're porting to a system where you really can't get a stacktrace. #ifdef NO_TCMALLOC_SAMPLES // We use #define so code compiles even if you #include stacktrace.h somehow. # define GetStackTrace(stack, depth, skip) (0) #else # include #endif // __THROW is defined in glibc systems. It means, counter-intuitively, // "This function will never throw an exception." It's an optional // optimization tool, but we may need to use it to match glibc prototypes. #ifndef __THROW // I guess we're not on a glibc system # define __THROW // __THROW is just an optimization, so ok to make it "" #endif using std::copy; // Declarations of five default weak hook functions, that can be overridden by // linking-in a strong definition (as heap-checker.cc does). These are extern // "C" so that they don't trigger gold's --detect-odr-violations warning, which // only looks at C++ symbols. // // These default hooks let some other library we link in // to define strong versions of InitialMallocHook_New, InitialMallocHook_MMap, // InitialMallocHook_PreMMap, InitialMallocHook_PreSbrk, and // InitialMallocHook_Sbrk to have a chance to hook into the very first // invocation of an allocation function call, mmap, or sbrk. // // These functions are declared here as weak, and defined later, rather than a // more straightforward simple weak definition, as a workround for an icc // compiler issue ((Intel reference 290819). This issue causes icc to resolve // weak symbols too early, at compile rather than link time. By declaring it // (weak) here, then defining it below after its use, we can avoid the problem. // extern "C" { ATTRIBUTE_WEAK void InitialMallocHook_New(const void* ptr, size_t size); ATTRIBUTE_WEAK void InitialMallocHook_PreMMap(const void* start, size_t size, int protection, int flags, int fd, off_t offset); ATTRIBUTE_WEAK void InitialMallocHook_MMap(const void* result, const void* start, size_t size, int protection, int flags, int fd, off_t offset); ATTRIBUTE_WEAK void InitialMallocHook_PreSbrk(ptrdiff_t increment); ATTRIBUTE_WEAK void InitialMallocHook_Sbrk(const void* result, ptrdiff_t increment); } // extern "C" namespace base { namespace internal { template PtrT AtomicPtr::Exchange(PtrT new_val) { base::subtle::MemoryBarrier(); // Release semantics. // Depending on the system, NoBarrier_AtomicExchange(AtomicWord*) // may have been defined to return an AtomicWord, Atomic32, or // Atomic64. We hide that implementation detail here with an // explicit cast. This prevents MSVC 2005, at least, from complaining. PtrT old_val = reinterpret_cast(static_cast( base::subtle::NoBarrier_AtomicExchange( &data_, reinterpret_cast(new_val)))); base::subtle::MemoryBarrier(); // And acquire semantics. return old_val; } template PtrT AtomicPtr::CompareAndSwap(PtrT old_val, PtrT new_val) { base::subtle::MemoryBarrier(); // Release semantics. PtrT retval = reinterpret_cast(static_cast( base::subtle::NoBarrier_CompareAndSwap( &data_, reinterpret_cast(old_val), reinterpret_cast(new_val)))); base::subtle::MemoryBarrier(); // And acquire semantics. return retval; } AtomicPtr new_hook_ = { reinterpret_cast(InitialMallocHook_New) }; AtomicPtr delete_hook_ = { 0 }; AtomicPtr premmap_hook_ = { reinterpret_cast(InitialMallocHook_PreMMap) }; AtomicPtr mmap_hook_ = { reinterpret_cast(InitialMallocHook_MMap) }; AtomicPtr munmap_hook_ = { 0 }; AtomicPtr mremap_hook_ = { 0 }; AtomicPtr presbrk_hook_ = { reinterpret_cast(InitialMallocHook_PreSbrk) }; AtomicPtr sbrk_hook_ = { reinterpret_cast(InitialMallocHook_Sbrk) }; } } // namespace base::internal using base::internal::new_hook_; using base::internal::delete_hook_; using base::internal::premmap_hook_; using base::internal::mmap_hook_; using base::internal::munmap_hook_; using base::internal::mremap_hook_; using base::internal::presbrk_hook_; using base::internal::sbrk_hook_; // These are available as C bindings as well as C++, hence their // definition outside the MallocHook class. extern "C" MallocHook_NewHook MallocHook_SetNewHook(MallocHook_NewHook hook) { return new_hook_.Exchange(hook); } extern "C" MallocHook_DeleteHook MallocHook_SetDeleteHook(MallocHook_DeleteHook hook) { return delete_hook_.Exchange(hook); } extern "C" MallocHook_PreMmapHook MallocHook_SetPreMmapHook(MallocHook_PreMmapHook hook) { return premmap_hook_.Exchange(hook); } extern "C" MallocHook_MmapHook MallocHook_SetMmapHook(MallocHook_MmapHook hook) { return mmap_hook_.Exchange(hook); } extern "C" MallocHook_MunmapHook MallocHook_SetMunmapHook(MallocHook_MunmapHook hook) { return munmap_hook_.Exchange(hook); } extern "C" MallocHook_MremapHook MallocHook_SetMremapHook(MallocHook_MremapHook hook) { return mremap_hook_.Exchange(hook); } extern "C" MallocHook_PreSbrkHook MallocHook_SetPreSbrkHook(MallocHook_PreSbrkHook hook) { return presbrk_hook_.Exchange(hook); } extern "C" MallocHook_SbrkHook MallocHook_SetSbrkHook(MallocHook_SbrkHook hook) { return sbrk_hook_.Exchange(hook); } // The definitions of weak default malloc hooks (New, MMap, and Sbrk) // that self deinstall on their first call. This is entirely for // efficiency: the default version of these functions will be called a // maximum of one time. If these functions were a no-op instead, they'd // be called every time, costing an extra function call per malloc. // // However, this 'delete self' isn't safe in general -- it's possible // that this function will be called via a daisy chain. That is, // someone else might do // old_hook = MallocHook::SetNewHook(&myhook); // void myhook(void* ptr, size_t size) { // do_my_stuff(); // old_hook(ptr, size); // daisy-chain the hooks // } // If old_hook is InitialMallocHook_New(), then this is broken code! -- // after the first run it'll deregister not only InitialMallocHook_New() // but also myhook. To protect against that, InitialMallocHook_New() // makes sure it's the 'top-level' hook before doing the deregistration. // This means the daisy-chain case will be less efficient because the // hook will be called, and do an if check, for every new. Alas. // TODO(csilvers): add support for removing a hook from the middle of a chain. void InitialMallocHook_New(const void* ptr, size_t size) { // Set new_hook to NULL iff its previous value was InitialMallocHook_New new_hook_.CompareAndSwap(&InitialMallocHook_New, NULL); } void InitialMallocHook_PreMMap(const void* start, size_t size, int protection, int flags, int fd, off_t offset) { premmap_hook_.CompareAndSwap(&InitialMallocHook_PreMMap, NULL); } void InitialMallocHook_MMap(const void* result, const void* start, size_t size, int protection, int flags, int fd, off_t offset) { mmap_hook_.CompareAndSwap(&InitialMallocHook_MMap, NULL); } void InitialMallocHook_PreSbrk(ptrdiff_t increment) { presbrk_hook_.CompareAndSwap(&InitialMallocHook_PreSbrk, NULL); } void InitialMallocHook_Sbrk(const void* result, ptrdiff_t increment) { sbrk_hook_.CompareAndSwap(&InitialMallocHook_Sbrk, NULL); } DEFINE_ATTRIBUTE_SECTION_VARS(google_malloc); DECLARE_ATTRIBUTE_SECTION_VARS(google_malloc); // actual functions are in debugallocation.cc or tcmalloc.cc DEFINE_ATTRIBUTE_SECTION_VARS(malloc_hook); DECLARE_ATTRIBUTE_SECTION_VARS(malloc_hook); // actual functions are in this file, malloc_hook.cc, and low_level_alloc.cc #define ADDR_IN_ATTRIBUTE_SECTION(addr, name) \ (reinterpret_cast(ATTRIBUTE_SECTION_START(name)) <= \ reinterpret_cast(addr) && \ reinterpret_cast(addr) < \ reinterpret_cast(ATTRIBUTE_SECTION_STOP(name))) // Return true iff 'caller' is a return address within a function // that calls one of our hooks via MallocHook:Invoke*. // A helper for GetCallerStackTrace. static inline bool InHookCaller(const void* caller) { return ADDR_IN_ATTRIBUTE_SECTION(caller, google_malloc) || ADDR_IN_ATTRIBUTE_SECTION(caller, malloc_hook); // We can use one section for everything except tcmalloc_or_debug // due to its special linkage mode, which prevents merging of the sections. } #undef ADDR_IN_ATTRIBUTE_SECTION static bool checked_sections = false; static inline void CheckInHookCaller() { if (!checked_sections) { INIT_ATTRIBUTE_SECTION_VARS(google_malloc); if (ATTRIBUTE_SECTION_START(google_malloc) == ATTRIBUTE_SECTION_STOP(google_malloc)) { RAW_LOG(ERROR, "google_malloc section is missing, " "thus InHookCaller is broken!"); } INIT_ATTRIBUTE_SECTION_VARS(malloc_hook); if (ATTRIBUTE_SECTION_START(malloc_hook) == ATTRIBUTE_SECTION_STOP(malloc_hook)) { RAW_LOG(ERROR, "malloc_hook section is missing, " "thus InHookCaller is broken!"); } checked_sections = true; } } // We can improve behavior/compactness of this function // if we pass a generic test function (with a generic arg) // into the implementations for GetStackTrace instead of the skip_count. extern "C" int MallocHook_GetCallerStackTrace(void** result, int max_depth, int skip_count) { #if defined(NO_TCMALLOC_SAMPLES) return 0; #elif !defined(HAVE_ATTRIBUTE_SECTION_START) // Fall back to GetStackTrace and good old but fragile frame skip counts. // Note: this path is inaccurate when a hook is not called directly by an // allocation function but is daisy-chained through another hook, // search for MallocHook::(Get|Set|Invoke)* to find such cases. return GetStackTrace(result, max_depth, skip_count + int(DEBUG_MODE)); // due to -foptimize-sibling-calls in opt mode // there's no need for extra frame skip here then #else CheckInHookCaller(); // MallocHook caller determination via InHookCaller works, use it: static const int kMaxSkip = 32 + 6 + 3; // Constant tuned to do just one GetStackTrace call below in practice // and not get many frames that we don't actually need: // currently max passsed max_depth is 32, // max passed/needed skip_count is 6 // and 3 is to account for some hook daisy chaining. static const int kStackSize = kMaxSkip + 1; void* stack[kStackSize]; int depth = GetStackTrace(stack, kStackSize, 1); // skip this function frame if (depth == 0) // silenty propagate cases when GetStackTrace does not work return 0; for (int i = 0; i < depth; ++i) { // stack[0] is our immediate caller if (InHookCaller(stack[i])) { RAW_VLOG(10, "Found hooked allocator at %d: %p <- %p", i, stack[i], stack[i+1]); i += 1; // skip hook caller frame depth -= i; // correct depth if (depth > max_depth) depth = max_depth; copy(stack + i, stack + i + depth, result); if (depth < max_depth && depth + i == kStackSize) { // get frames for the missing depth depth += GetStackTrace(result + depth, max_depth - depth, 1 + kStackSize); } return depth; } } RAW_LOG(WARNING, "Hooked allocator frame not found, returning empty trace"); // If this happens try increasing kMaxSkip // or else something must be wrong with InHookCaller, // e.g. for every section used in InHookCaller // all functions in that section must be inside the same library. return 0; #endif } // On Linux/x86, we override mmap/munmap/mremap/sbrk // and provide support for calling the related hooks. // // We define mmap() and mmap64(), which somewhat reimplements libc's mmap // syscall stubs. Unfortunately libc only exports the stubs via weak symbols // (which we're overriding with our mmap64() and mmap() wrappers) so we can't // just call through to them. #if defined(__linux) && \ (defined(__i386__) || defined(__x86_64__) || defined(__PPC__)) #include #include #include #include #include "base/linux_syscall_support.h" // The x86-32 case and the x86-64 case differ: // 32b has a mmap2() syscall, 64b does not. // 64b and 32b have different calling conventions for mmap(). #if defined(__x86_64__) || defined(__PPC64__) static inline void* do_mmap64(void *start, size_t length, int prot, int flags, int fd, __off64_t offset) __THROW { return (void *)syscall(SYS_mmap, start, length, prot, flags, fd, offset); } #elif defined(__i386__) || defined(__PPC__) static inline void* do_mmap64(void *start, size_t length, int prot, int flags, int fd, __off64_t offset) __THROW { void *result; // Try mmap2() unless it's not supported static bool have_mmap2 = true; if (have_mmap2) { static int pagesize = 0; if (!pagesize) pagesize = getpagesize(); // Check that the offset is page aligned if (offset & (pagesize - 1)) { result = MAP_FAILED; errno = EINVAL; goto out; } result = (void *)syscall(SYS_mmap2, start, length, prot, flags, fd, (off_t) (offset / pagesize)); if (result != MAP_FAILED || errno != ENOSYS) goto out; // We don't have mmap2() after all - don't bother trying it in future have_mmap2 = false; } if (((off_t)offset) != offset) { // If we're trying to map a 64-bit offset, fail now since we don't // have 64-bit mmap() support. result = MAP_FAILED; errno = EINVAL; goto out; } { // Fall back to old 32-bit offset mmap() call // Old syscall interface cannot handle six args, so pass in an array int32 args[6] = { (int32) start, length, prot, flags, fd, (off_t) offset }; result = (void *)syscall(SYS_mmap, args); } out: return result; } # endif // defined(__x86_64__) // We use do_mmap64 abstraction to put MallocHook::InvokeMmapHook // calls right into mmap and mmap64, so that the stack frames in the caller's // stack are at the same offsets for all the calls of memory allocating // functions. // Put all callers of MallocHook::Invoke* in this module into // malloc_hook section, // so that MallocHook::GetCallerStackTrace can function accurately: // Make sure mmap doesn't get #define'd away by #undef mmap extern "C" { void* mmap64(void *start, size_t length, int prot, int flags, int fd, __off64_t offset ) __THROW ATTRIBUTE_SECTION(malloc_hook); void* mmap(void *start, size_t length,int prot, int flags, int fd, off_t offset) __THROW ATTRIBUTE_SECTION(malloc_hook); int munmap(void* start, size_t length) __THROW ATTRIBUTE_SECTION(malloc_hook); void* mremap(void* old_addr, size_t old_size, size_t new_size, int flags, ...) __THROW ATTRIBUTE_SECTION(malloc_hook); void* sbrk(ptrdiff_t increment) __THROW ATTRIBUTE_SECTION(malloc_hook); } extern "C" void* mmap64(void *start, size_t length, int prot, int flags, int fd, __off64_t offset) __THROW { MallocHook::InvokePreMmapHook(start, length, prot, flags, fd, offset); void *result = do_mmap64(start, length, prot, flags, fd, offset); MallocHook::InvokeMmapHook(result, start, length, prot, flags, fd, offset); return result; } #if !defined(__USE_FILE_OFFSET64) || !defined(__REDIRECT_NTH) extern "C" void* mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) __THROW { MallocHook::InvokePreMmapHook(start, length, prot, flags, fd, offset); void *result = do_mmap64(start, length, prot, flags, fd, static_cast(offset)); // avoid sign extension MallocHook::InvokeMmapHook(result, start, length, prot, flags, fd, offset); return result; } #endif // !defined(__USE_FILE_OFFSET64) || !defined(__REDIRECT_NTH) extern "C" int munmap(void* start, size_t length) __THROW { MallocHook::InvokeMunmapHook(start, length); return syscall(SYS_munmap, start, length); } extern "C" void* mremap(void* old_addr, size_t old_size, size_t new_size, int flags, ...) __THROW { va_list ap; va_start(ap, flags); void *new_address = va_arg(ap, void *); va_end(ap); void* result = sys_mremap(old_addr, old_size, new_size, flags, new_address); MallocHook::InvokeMremapHook(result, old_addr, old_size, new_size, flags, new_address); return result; } // libc's version: extern "C" void* __sbrk(ptrdiff_t increment); extern "C" void* sbrk(ptrdiff_t increment) __THROW { MallocHook::InvokePreSbrkHook(increment); void *result = __sbrk(increment); MallocHook::InvokeSbrkHook(result, increment); return result; } /*static*/void* MallocHook::UnhookedMMap(void *start, size_t length, int prot, int flags, int fd, off_t offset) { return do_mmap64(start, length, prot, flags, fd, offset); } /*static*/int MallocHook::UnhookedMUnmap(void *start, size_t length) { return sys_munmap(start, length); } #else // defined(__linux) && // (defined(__i386__) || defined(__x86_64__) || defined(__PPC__)) /*static*/void* MallocHook::UnhookedMMap(void *start, size_t length, int prot, int flags, int fd, off_t offset) { return mmap(start, length, prot, flags, fd, offset); } /*static*/int MallocHook::UnhookedMUnmap(void *start, size_t length) { return munmap(start, length); } #endif // defined(__linux) && // (defined(__i386__) || defined(__x86_64__) || defined(__PPC__)) ================================================ FILE: distro/google-perftools-1.7/src/maybe_threads.cc ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Paul Menage // // Some wrappers for pthread functions so that we can be LD_PRELOADed // against non-pthreads apps. // // This module will behave very strangely if some pthreads functions // exist and others don't. #include "config.h" #include #include // for memcmp // We don't actually need strings. But including this header seems to // stop the compiler trying to short-circuit our pthreads existence // tests and claiming that the address of a function is always // non-zero. I have no idea why ... #include #include "maybe_threads.h" #include "base/basictypes.h" // __THROW is defined in glibc systems. It means, counter-intuitively, // "This function will never throw an exception." It's an optional // optimization tool, but we may need to use it to match glibc prototypes. #ifndef __THROW // I guess we're not on a glibc system # define __THROW // __THROW is just an optimization, so ok to make it "" #endif // These are the methods we're going to conditionally include. extern "C" { int pthread_key_create (pthread_key_t*, void (*)(void*)) __THROW ATTRIBUTE_WEAK; void *pthread_getspecific(pthread_key_t) __THROW ATTRIBUTE_WEAK; int pthread_setspecific(pthread_key_t, const void*) __THROW ATTRIBUTE_WEAK; int pthread_once(pthread_once_t *, void (*)(void)) ATTRIBUTE_WEAK; } #define MAX_PERTHREAD_VALS 16 static void *perftools_pthread_specific_vals[MAX_PERTHREAD_VALS]; static int next_key; int perftools_pthread_key_create(pthread_key_t *key, void (*destr_function) (void *)) { if (pthread_key_create) { return pthread_key_create(key, destr_function); } else { assert(next_key < MAX_PERTHREAD_VALS); *key = (pthread_key_t)(next_key++); return 0; } } void *perftools_pthread_getspecific(pthread_key_t key) { if (pthread_getspecific) { return pthread_getspecific(key); } else { return perftools_pthread_specific_vals[(int)key]; } } int perftools_pthread_setspecific(pthread_key_t key, void *val) { if (pthread_setspecific) { return pthread_setspecific(key, val); } else { perftools_pthread_specific_vals[(int)key] = val; return 0; } } static pthread_once_t pthread_once_init = PTHREAD_ONCE_INIT; int perftools_pthread_once(pthread_once_t *ctl, void (*init_routine) (void)) { if (pthread_once) { return pthread_once(ctl, init_routine); } else { if (memcmp(ctl, &pthread_once_init, sizeof(*ctl)) == 0) { init_routine(); ++*(char*)(ctl); // make it so it's no longer equal to init } return 0; } } ================================================ FILE: distro/google-perftools-1.7/src/maybe_threads.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Paul Menage //------------------------------------------------------------------- // Some wrappers for pthread functions so that we can be LD_PRELOADed // against non-pthreads apps. //------------------------------------------------------------------- #ifndef GOOGLE_MAYBE_THREADS_H_ #define GOOGLE_MAYBE_THREADS_H_ #ifdef HAVE_PTHREAD #include #endif int perftools_pthread_key_create(pthread_key_t *key, void (*destr_function) (void *)); void *perftools_pthread_getspecific(pthread_key_t key); int perftools_pthread_setspecific(pthread_key_t key, void *val); int perftools_pthread_once(pthread_once_t *ctl, void (*init_routine) (void)); #endif /* GOOGLE_MAYBE_THREADS_H_ */ ================================================ FILE: distro/google-perftools-1.7/src/memfs_malloc.cc ================================================ // Copyright (c) 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Arun Sharma // // A tcmalloc system allocator that uses a memory based filesystem such as // tmpfs or hugetlbfs // // Since these only exist on linux, we only register this allocator there. #ifdef __linux #include #include #include #include #include #include #include #include #include // for statfs #include #include "base/basictypes.h" #include "base/googleinit.h" #include "base/sysinfo.h" #include "system-alloc.h" #include "internal_logging.h" using std::string; DEFINE_string(memfs_malloc_path, EnvToString("TCMALLOC_MEMFS_MALLOC_PATH", ""), "Path where hugetlbfs or tmpfs is mounted. The caller is " "responsible for ensuring that the path is unique and does " "not conflict with another process"); DEFINE_int64(memfs_malloc_limit_mb, EnvToInt("TCMALLOC_MEMFS_LIMIT_MB", 0), "Limit total allocation size to the " "specified number of MiB. 0 == no limit."); DEFINE_bool(memfs_malloc_abort_on_fail, EnvToBool("TCMALLOC_MEMFS_ABORT_ON_FAIL", false), "abort() whenever memfs_malloc fails to satisfy an allocation " "for any reason."); DEFINE_bool(memfs_malloc_ignore_mmap_fail, EnvToBool("TCMALLOC_MEMFS_IGNORE_MMAP_FAIL", false), "Ignore failures from mmap"); // Hugetlbfs based allocator for tcmalloc class HugetlbSysAllocator: public SysAllocator { public: HugetlbSysAllocator(int fd, int page_size) : big_page_size_(page_size), hugetlb_fd_(fd), hugetlb_base_(0) { } void* Alloc(size_t size, size_t *actual_size, size_t alignment); void DumpStats(TCMalloc_Printer* printer); private: int64 big_page_size_; int hugetlb_fd_; // file descriptor for hugetlb off_t hugetlb_base_; }; void HugetlbSysAllocator::DumpStats(TCMalloc_Printer* printer) { printer->printf("HugetlbSysAllocator: failed_=%d allocated=%"PRId64"\n", failed_, static_cast(hugetlb_base_)); } // No locking needed here since we assume that tcmalloc calls // us with an internal lock held (see tcmalloc/system-alloc.cc). void* HugetlbSysAllocator::Alloc(size_t size, size_t *actual_size, size_t alignment) { // don't go any further if we haven't opened the backing file if (hugetlb_fd_ == -1) { return NULL; } // We don't respond to allocation requests smaller than big_page_size_ unless // the caller is willing to take more than they asked for. if (actual_size == NULL && size < big_page_size_) { return NULL; } // Enforce huge page alignment. Be careful to deal with overflow. if (alignment < big_page_size_) alignment = big_page_size_; size_t aligned_size = ((size + alignment - 1) / alignment) * alignment; if (aligned_size < size) { return NULL; } size = aligned_size; // Ask for extra memory if alignment > pagesize size_t extra = 0; if (alignment > big_page_size_) { extra = alignment - big_page_size_; } // Test if this allocation would put us over the limit. off_t limit = FLAGS_memfs_malloc_limit_mb*1024*1024; if (limit > 0 && hugetlb_base_ + size + extra > limit) { // Disable the allocator when there's less than one page left. if (limit - hugetlb_base_ < big_page_size_) { TCMalloc_MESSAGE(__FILE__, __LINE__, "reached memfs_malloc_limit_mb\n"); failed_ = true; } else { TCMalloc_MESSAGE(__FILE__, __LINE__, "alloc size=%"PRIuS " too large while %"PRId64" bytes remain\n", size, static_cast(limit - hugetlb_base_)); } if (FLAGS_memfs_malloc_abort_on_fail) { CRASH("memfs_malloc_abort_on_fail is set\n"); } return NULL; } // This is not needed for hugetlbfs, but needed for tmpfs. Annoyingly // hugetlbfs returns EINVAL for ftruncate. int ret = ftruncate(hugetlb_fd_, hugetlb_base_ + size + extra); if (ret != 0 && errno != EINVAL) { TCMalloc_MESSAGE(__FILE__, __LINE__, "ftruncate failed: %s\n", strerror(errno)); failed_ = true; if (FLAGS_memfs_malloc_abort_on_fail) { CRASH("memfs_malloc_abort_on_fail is set\n"); } return NULL; } // Note: size + extra does not overflow since: // size + alignment < (1<(MAP_FAILED)) { if (!FLAGS_memfs_malloc_ignore_mmap_fail) { TCMalloc_MESSAGE(__FILE__, __LINE__, "mmap of size %"PRIuS" failed: %s\n", size + extra, strerror(errno)); failed_ = true; if (FLAGS_memfs_malloc_abort_on_fail) { CRASH("memfs_malloc_abort_on_fail is set\n"); } } return NULL; } uintptr_t ptr = reinterpret_cast(result); // Adjust the return memory so it is aligned size_t adjust = 0; if ((ptr & (alignment - 1)) != 0) { adjust = alignment - (ptr & (alignment - 1)); } ptr += adjust; hugetlb_base_ += (size + extra); if (actual_size) { *actual_size = size + extra - adjust; } return reinterpret_cast(ptr); } static void InitSystemAllocator() { if (FLAGS_memfs_malloc_path.length()) { char path[PATH_MAX]; int rc = snprintf(path, sizeof(path), "%s.XXXXXX", FLAGS_memfs_malloc_path.c_str()); if (rc < 0 || rc >= sizeof(path)) { CRASH("XX fatal: memfs_malloc_path too long\n"); } int hugetlb_fd = mkstemp(path); if (hugetlb_fd == -1) { TCMalloc_MESSAGE(__FILE__, __LINE__, "warning: unable to create memfs_malloc_path %s: %s\n", path, strerror(errno)); return; } // Cleanup memory on process exit if (unlink(path) == -1) { CRASH("fatal: error unlinking memfs_malloc_path %s: %s\n", path, strerror(errno)); } // Use fstatfs to figure out the default page size for memfs struct statfs sfs; if (fstatfs(hugetlb_fd, &sfs) == -1) { CRASH("fatal: error fstatfs of memfs_malloc_path: %s\n", strerror(errno)); } int64 page_size = sfs.f_bsize; SysAllocator *alloc = new HugetlbSysAllocator(hugetlb_fd, page_size); // Register ourselves with tcmalloc RegisterSystemAllocator(alloc, 0); } } REGISTER_MODULE_INITIALIZER(memfs_malloc, { InitSystemAllocator(); }); #endif /* ifdef __linux */ ================================================ FILE: distro/google-perftools-1.7/src/memory_region_map.cc ================================================ /* Copyright (c) 2006, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Maxim Lifantsev */ // // Background and key design points of MemoryRegionMap. // // MemoryRegionMap is a low-level module with quite atypical requirements that // result in some degree of non-triviality of the implementation and design. // // MemoryRegionMap collects info about *all* memory regions created with // mmap, munmap, mremap, sbrk. // They key word above is 'all': all that are happening in a process // during its lifetime frequently starting even before global object // constructor execution. // // This is needed by the primary client of MemoryRegionMap: // HeapLeakChecker uses the regions and the associated stack traces // to figure out what part of the memory is the heap: // if MemoryRegionMap were to miss some (early) regions, leak checking would // stop working correctly. // // To accomplish the goal of functioning before/during global object // constructor execution MemoryRegionMap is done as a singleton service // that relies on own on-demand initialized static constructor-less data, // and only relies on other low-level modules that can also function properly // even before global object constructors run. // // Accomplishing the goal of collecting data about all mmap, munmap, mremap, // sbrk occurrences is a more involved: conceptually to do this one needs to // record some bits of data in particular about any mmap or sbrk call, // but to do that one needs to allocate memory for that data at some point, // but all memory allocations in the end themselves come from an mmap // or sbrk call (that's how the address space of the process grows). // // Also note that we need to do all the above recording from // within an mmap/sbrk hook which is sometimes/frequently is made by a memory // allocator, including the allocator MemoryRegionMap itself must rely on. // In the case of heap-checker usage this includes even the very first // mmap/sbrk call happening in the program: heap-checker gets activated due to // a link-time installed mmap/sbrk hook and it initializes MemoryRegionMap // and asks it to record info about this very first call right from that // very first hook invocation. // // MemoryRegionMap is doing its memory allocations via LowLevelAlloc: // unlike more complex standard memory allocator, LowLevelAlloc cooperates with // MemoryRegionMap by not holding any of its own locks while it calls mmap // to get memory, thus we are able to call LowLevelAlloc from // our mmap/sbrk hooks without causing a deadlock in it. // For the same reason of deadlock prevention the locking in MemoryRegionMap // itself is write-recursive which is an exception to Google's mutex usage. // // We still need to break the infinite cycle of mmap calling our hook, // which asks LowLevelAlloc for memory to record this mmap, // which (sometimes) causes mmap, which calls our hook, and so on. // We do this as follows: on a recursive call of MemoryRegionMap's // mmap/sbrk/mremap hook we record the data about the allocation in a // static fixed-sized stack (saved_regions), when the recursion unwinds // but before returning from the outer hook call we unwind this stack and // move the data from saved_regions to its permanent place in the RegionSet, // which can cause more allocations and mmap-s and recursion and unwinding, // but the whole process ends eventually due to the fact that for the small // allocations we are doing LowLevelAlloc reuses one mmap call and parcels out // the memory it created to satisfy several of our allocation requests. // // ========================================================================= // #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #ifdef HAVE_MMAP #include #elif !defined(MAP_FAILED) #define MAP_FAILED -1 // the only thing we need from mman.h #endif #ifdef HAVE_PTHREAD #include // for pthread_t, pthread_self() #endif #include #include #include "memory_region_map.h" #include "base/logging.h" #include "base/low_level_alloc.h" #include "malloc_hook-inl.h" #include #include // MREMAP_FIXED is a linux extension. How it's used in this file, // setting it to 0 is equivalent to saying, "This feature isn't // supported", which is right. #ifndef MREMAP_FIXED # define MREMAP_FIXED 0 #endif using std::max; // ========================================================================= // int MemoryRegionMap::client_count_ = 0; int MemoryRegionMap::max_stack_depth_ = 0; MemoryRegionMap::RegionSet* MemoryRegionMap::regions_ = NULL; LowLevelAlloc::Arena* MemoryRegionMap::arena_ = NULL; SpinLock MemoryRegionMap::lock_(SpinLock::LINKER_INITIALIZED); SpinLock MemoryRegionMap::owner_lock_( // ACQUIRED_AFTER(lock_) SpinLock::LINKER_INITIALIZED); int MemoryRegionMap::recursion_count_ = 0; // GUARDED_BY(owner_lock_) pthread_t MemoryRegionMap::lock_owner_tid_; // GUARDED_BY(owner_lock_) // ========================================================================= // // Simple hook into execution of global object constructors, // so that we do not call pthread_self() when it does not yet work. static bool libpthread_initialized = false; static bool initializer = (libpthread_initialized = true, true); static inline bool current_thread_is(pthread_t should_be) { // Before main() runs, there's only one thread, so we're always that thread if (!libpthread_initialized) return true; // this starts working only sometime well into global constructor execution: return pthread_equal(pthread_self(), should_be); } // ========================================================================= // // Constructor-less place-holder to store a RegionSet in. union MemoryRegionMap::RegionSetRep { char rep[sizeof(RegionSet)]; void* align_it; // do not need a better alignment for 'rep' than this RegionSet* region_set() { return reinterpret_cast(rep); } }; // The bytes where MemoryRegionMap::regions_ will point to. // We use RegionSetRep with noop c-tor so that global construction // does not interfere. static MemoryRegionMap::RegionSetRep regions_rep; // ========================================================================= // // Has InsertRegionLocked been called recursively // (or rather should we *not* use regions_ to record a hooked mmap). static bool recursive_insert = false; void MemoryRegionMap::Init(int max_stack_depth) { RAW_VLOG(10, "MemoryRegionMap Init"); RAW_CHECK(max_stack_depth >= 0, ""); // Make sure we don't overflow the memory in region stacks: RAW_CHECK(max_stack_depth <= kMaxStackDepth, "need to increase kMaxStackDepth?"); Lock(); client_count_ += 1; max_stack_depth_ = max(max_stack_depth_, max_stack_depth); if (client_count_ > 1) { // not first client: already did initialization-proper Unlock(); RAW_VLOG(10, "MemoryRegionMap Init increment done"); return; } // Set our hooks and make sure no other hooks existed: if (MallocHook::SetMmapHook(MmapHook) != NULL || MallocHook::SetMremapHook(MremapHook) != NULL || MallocHook::SetSbrkHook(SbrkHook) != NULL || MallocHook::SetMunmapHook(MunmapHook) != NULL) { RAW_LOG(FATAL, "Had other mmap/mremap/munmap/sbrk MallocHook-s set. " "Make sure only one of MemoryRegionMap and the other " "client is active."); } // We need to set recursive_insert since the NewArena call itself // will already do some allocations with mmap which our hooks will catch // recursive_insert allows us to buffer info about these mmap calls. // Note that Init() can be (and is) sometimes called // already from within an mmap/sbrk hook. recursive_insert = true; arena_ = LowLevelAlloc::NewArena(0, LowLevelAlloc::DefaultArena()); recursive_insert = false; HandleSavedRegionsLocked(&InsertRegionLocked); // flush the buffered ones // Can't instead use HandleSavedRegionsLocked(&DoInsertRegionLocked) before // recursive_insert = false; as InsertRegionLocked will also construct // regions_ on demand for us. Unlock(); RAW_VLOG(10, "MemoryRegionMap Init done"); } bool MemoryRegionMap::Shutdown() { RAW_VLOG(10, "MemoryRegionMap Shutdown"); Lock(); RAW_CHECK(client_count_ > 0, ""); client_count_ -= 1; if (client_count_ != 0) { // not last client; need not really shutdown Unlock(); RAW_VLOG(10, "MemoryRegionMap Shutdown decrement done"); return true; } CheckMallocHooks(); // we assume no other hooks MallocHook::SetMmapHook(NULL); MallocHook::SetMremapHook(NULL); MallocHook::SetSbrkHook(NULL); MallocHook::SetMunmapHook(NULL); if (regions_) regions_->~RegionSet(); regions_ = NULL; bool deleted_arena = LowLevelAlloc::DeleteArena(arena_); if (deleted_arena) { arena_ = 0; } else { RAW_LOG(WARNING, "Can't delete LowLevelAlloc arena: it's being used"); } Unlock(); RAW_VLOG(10, "MemoryRegionMap Shutdown done"); return deleted_arena; } void MemoryRegionMap::CheckMallocHooks() { if (MallocHook::GetMmapHook() != MmapHook || MallocHook::GetMunmapHook() != MunmapHook || MallocHook::GetMremapHook() != MremapHook || MallocHook::GetSbrkHook() != SbrkHook) { RAW_LOG(FATAL, "Our mmap/mremap/munmap/sbrk MallocHook-s got changed."); } } // Invariants (once libpthread_initialized is true): // * While lock_ is not held, recursion_count_ is 0 (and // lock_owner_tid_ is the previous owner, but we don't rely on // that). // * recursion_count_ and lock_owner_tid_ are only written while // both lock_ and owner_lock_ are held. They may be read under // just owner_lock_. // * At entry and exit of Lock() and Unlock(), the current thread // owns lock_ iff pthread_equal(lock_owner_tid_, pthread_self()) // && recursion_count_ > 0. void MemoryRegionMap::Lock() { { SpinLockHolder l(&owner_lock_); if (recursion_count_ > 0 && current_thread_is(lock_owner_tid_)) { RAW_CHECK(lock_.IsHeld(), "Invariants violated"); recursion_count_++; RAW_CHECK(recursion_count_ <= 5, "recursive lock nesting unexpectedly deep"); return; } } lock_.Lock(); { SpinLockHolder l(&owner_lock_); RAW_CHECK(recursion_count_ == 0, "Last Unlock didn't reset recursion_count_"); if (libpthread_initialized) lock_owner_tid_ = pthread_self(); recursion_count_ = 1; } } void MemoryRegionMap::Unlock() { SpinLockHolder l(&owner_lock_); RAW_CHECK(recursion_count_ > 0, "unlock when not held"); RAW_CHECK(lock_.IsHeld(), "unlock when not held, and recursion_count_ is wrong"); RAW_CHECK(current_thread_is(lock_owner_tid_), "unlock by non-holder"); recursion_count_--; if (recursion_count_ == 0) { lock_.Unlock(); } } bool MemoryRegionMap::LockIsHeld() { SpinLockHolder l(&owner_lock_); return lock_.IsHeld() && current_thread_is(lock_owner_tid_); } const MemoryRegionMap::Region* MemoryRegionMap::DoFindRegionLocked(uintptr_t addr) { RAW_CHECK(LockIsHeld(), "should be held (by this thread)"); if (regions_ != NULL) { Region sample; sample.SetRegionSetKey(addr); RegionSet::iterator region = regions_->lower_bound(sample); if (region != regions_->end()) { RAW_CHECK(addr <= region->end_addr, ""); if (region->start_addr <= addr && addr < region->end_addr) { return &(*region); } } } return NULL; } bool MemoryRegionMap::FindRegion(uintptr_t addr, Region* result) { Lock(); const Region* region = DoFindRegionLocked(addr); if (region != NULL) *result = *region; // create it as an independent copy Unlock(); return region != NULL; } bool MemoryRegionMap::FindAndMarkStackRegion(uintptr_t stack_top, Region* result) { Lock(); const Region* region = DoFindRegionLocked(stack_top); if (region != NULL) { RAW_VLOG(10, "Stack at %p is inside region %p..%p", reinterpret_cast(stack_top), reinterpret_cast(region->start_addr), reinterpret_cast(region->end_addr)); const_cast(region)->set_is_stack(); // now we know // cast is safe (set_is_stack does not change the set ordering key) *result = *region; // create *result as an independent copy } Unlock(); return region != NULL; } MemoryRegionMap::RegionIterator MemoryRegionMap::BeginRegionLocked() { RAW_CHECK(LockIsHeld(), "should be held (by this thread)"); RAW_CHECK(regions_ != NULL, ""); return regions_->begin(); } MemoryRegionMap::RegionIterator MemoryRegionMap::EndRegionLocked() { RAW_CHECK(LockIsHeld(), "should be held (by this thread)"); RAW_CHECK(regions_ != NULL, ""); return regions_->end(); } inline void MemoryRegionMap::DoInsertRegionLocked(const Region& region) { RAW_VLOG(12, "Inserting region %p..%p from %p", reinterpret_cast(region.start_addr), reinterpret_cast(region.end_addr), reinterpret_cast(region.caller())); RegionSet::const_iterator i = regions_->lower_bound(region); if (i != regions_->end() && i->start_addr <= region.start_addr) { RAW_DCHECK(region.end_addr <= i->end_addr, ""); // lower_bound ensures this return; // 'region' is a subset of an already recorded region; do nothing // We can be stricter and allow this only when *i has been created via // an mmap with MAP_NORESERVE flag set. } if (DEBUG_MODE) { RAW_CHECK(i == regions_->end() || !region.Overlaps(*i), "Wow, overlapping memory regions"); Region sample; sample.SetRegionSetKey(region.start_addr); i = regions_->lower_bound(sample); RAW_CHECK(i == regions_->end() || !region.Overlaps(*i), "Wow, overlapping memory regions"); } region.AssertIsConsistent(); // just making sure // This inserts and allocates permanent storage for region // and its call stack data: it's safe to do it now: regions_->insert(region); RAW_VLOG(12, "Inserted region %p..%p :", reinterpret_cast(region.start_addr), reinterpret_cast(region.end_addr)); if (VLOG_IS_ON(12)) LogAllLocked(); } // These variables are local to MemoryRegionMap::InsertRegionLocked() // and MemoryRegionMap::HandleSavedRegionsLocked() // and are file-level to ensure that they are initialized at load time. // Number of unprocessed region inserts. static int saved_regions_count = 0; // Unprocessed inserts (must be big enough to hold all allocations that can // be caused by a InsertRegionLocked call). // Region has no constructor, so that c-tor execution does not interfere // with the any-time use of the static memory behind saved_regions. static MemoryRegionMap::Region saved_regions[20]; inline void MemoryRegionMap::HandleSavedRegionsLocked( void (*insert_func)(const Region& region)) { while (saved_regions_count > 0) { // Making a local-var copy of the region argument to insert_func // including its stack (w/o doing any memory allocations) is important: // in many cases the memory in saved_regions // will get written-to during the (*insert_func)(r) call below. Region r = saved_regions[--saved_regions_count]; (*insert_func)(r); } } inline void MemoryRegionMap::InsertRegionLocked(const Region& region) { RAW_CHECK(LockIsHeld(), "should be held (by this thread)"); // We can be called recursively, because RegionSet constructor // and DoInsertRegionLocked() (called below) can call the allocator. // recursive_insert tells us if that's the case. When this happens, // region insertion information is recorded in saved_regions[], // and taken into account when the recursion unwinds. // Do the insert: if (recursive_insert) { // recursion: save in saved_regions RAW_VLOG(12, "Saving recursive insert of region %p..%p from %p", reinterpret_cast(region.start_addr), reinterpret_cast(region.end_addr), reinterpret_cast(region.caller())); RAW_CHECK(saved_regions_count < arraysize(saved_regions), ""); // Copy 'region' to saved_regions[saved_regions_count] // together with the contents of its call_stack, // then increment saved_regions_count. saved_regions[saved_regions_count++] = region; } else { // not a recusrive call if (regions_ == NULL) { // init regions_ RAW_VLOG(12, "Initializing region set"); regions_ = regions_rep.region_set(); recursive_insert = true; new(regions_) RegionSet(); HandleSavedRegionsLocked(&DoInsertRegionLocked); recursive_insert = false; } recursive_insert = true; // Do the actual insertion work to put new regions into regions_: DoInsertRegionLocked(region); HandleSavedRegionsLocked(&DoInsertRegionLocked); recursive_insert = false; } } // We strip out different number of stack frames in debug mode // because less inlining happens in that case #ifdef NDEBUG static const int kStripFrames = 1; #else static const int kStripFrames = 3; #endif void MemoryRegionMap::RecordRegionAddition(const void* start, size_t size) { // Record start/end info about this memory acquisition call in a new region: Region region; region.Create(start, size); // First get the call stack info into the local varible 'region': const int depth = max_stack_depth_ > 0 ? MallocHook::GetCallerStackTrace(const_cast(region.call_stack), max_stack_depth_, kStripFrames + 1) : 0; region.set_call_stack_depth(depth); // record stack info fully RAW_VLOG(10, "New global region %p..%p from %p", reinterpret_cast(region.start_addr), reinterpret_cast(region.end_addr), reinterpret_cast(region.caller())); // Note: none of the above allocates memory. Lock(); // recursively lock InsertRegionLocked(region); // This will (eventually) allocate storage for and copy over the stack data // from region.call_stack_data_ that is pointed by region.call_stack(). Unlock(); } void MemoryRegionMap::RecordRegionRemoval(const void* start, size_t size) { Lock(); if (recursive_insert) { // First remove the removed region from saved_regions, if it's // there, to prevent overrunning saved_regions in recursive // map/unmap call sequences, and also from later inserting regions // which have already been unmapped. uintptr_t start_addr = reinterpret_cast(start); uintptr_t end_addr = start_addr + size; int put_pos = 0; int old_count = saved_regions_count; for (int i = 0; i < old_count; ++i, ++put_pos) { Region& r = saved_regions[i]; if (r.start_addr == start_addr && r.end_addr == end_addr) { // An exact match, so it's safe to remove. --saved_regions_count; --put_pos; RAW_VLOG(10, ("Insta-Removing saved region %p..%p; " "now have %d saved regions"), reinterpret_cast(start_addr), reinterpret_cast(end_addr), saved_regions_count); } else { if (put_pos < i) { saved_regions[put_pos] = saved_regions[i]; } } } } if (regions_ == NULL) { // We must have just unset the hooks, // but this thread was already inside the hook. Unlock(); return; } if (!recursive_insert) { HandleSavedRegionsLocked(&InsertRegionLocked); } // first handle adding saved regions if any uintptr_t start_addr = reinterpret_cast(start); uintptr_t end_addr = start_addr + size; // subtract start_addr, end_addr from all the regions RAW_VLOG(10, "Removing global region %p..%p; have %"PRIuS" regions", reinterpret_cast(start_addr), reinterpret_cast(end_addr), regions_->size()); Region sample; sample.SetRegionSetKey(start_addr); // Only iterate over the regions that might overlap start_addr..end_addr: for (RegionSet::iterator region = regions_->lower_bound(sample); region != regions_->end() && region->start_addr < end_addr; /*noop*/) { RAW_VLOG(13, "Looking at region %p..%p", reinterpret_cast(region->start_addr), reinterpret_cast(region->end_addr)); if (start_addr <= region->start_addr && region->end_addr <= end_addr) { // full deletion RAW_VLOG(12, "Deleting region %p..%p", reinterpret_cast(region->start_addr), reinterpret_cast(region->end_addr)); RegionSet::iterator d = region; ++region; regions_->erase(d); continue; } else if (region->start_addr < start_addr && end_addr < region->end_addr) { // cutting-out split RAW_VLOG(12, "Splitting region %p..%p in two", reinterpret_cast(region->start_addr), reinterpret_cast(region->end_addr)); // Make another region for the start portion: // The new region has to be the start portion because we can't // just modify region->end_addr as it's the sorting key. Region r = *region; r.set_end_addr(start_addr); InsertRegionLocked(r); // cut *region from start: const_cast(*region).set_start_addr(end_addr); } else if (end_addr > region->start_addr && start_addr <= region->start_addr) { // cut from start RAW_VLOG(12, "Start-chopping region %p..%p", reinterpret_cast(region->start_addr), reinterpret_cast(region->end_addr)); const_cast(*region).set_start_addr(end_addr); } else if (start_addr > region->start_addr && start_addr < region->end_addr) { // cut from end RAW_VLOG(12, "End-chopping region %p..%p", reinterpret_cast(region->start_addr), reinterpret_cast(region->end_addr)); // Can't just modify region->end_addr (it's the sorting key): Region r = *region; r.set_end_addr(start_addr); RegionSet::iterator d = region; ++region; // It's safe to erase before inserting since r is independent of *d: // r contains an own copy of the call stack: regions_->erase(d); InsertRegionLocked(r); continue; } ++region; } RAW_VLOG(12, "Removed region %p..%p; have %"PRIuS" regions", reinterpret_cast(start_addr), reinterpret_cast(end_addr), regions_->size()); if (VLOG_IS_ON(12)) LogAllLocked(); Unlock(); } void MemoryRegionMap::MmapHook(const void* result, const void* start, size_t size, int prot, int flags, int fd, off_t offset) { // TODO(maxim): replace all 0x%"PRIxS" by %p when RAW_VLOG uses a safe // snprintf reimplementation that does not malloc to pretty-print NULL RAW_VLOG(10, "MMap = 0x%"PRIxPTR" of %"PRIuS" at %llu " "prot %d flags %d fd %d offs %lld", reinterpret_cast(result), size, reinterpret_cast(start), prot, flags, fd, static_cast(offset)); if (result != reinterpret_cast(MAP_FAILED) && size != 0) { RecordRegionAddition(result, size); } } void MemoryRegionMap::MunmapHook(const void* ptr, size_t size) { RAW_VLOG(10, "MUnmap of %p %"PRIuS"", ptr, size); if (size != 0) { RecordRegionRemoval(ptr, size); } } void MemoryRegionMap::MremapHook(const void* result, const void* old_addr, size_t old_size, size_t new_size, int flags, const void* new_addr) { RAW_VLOG(10, "MRemap = 0x%"PRIxPTR" of 0x%"PRIxPTR" %"PRIuS" " "to %"PRIuS" flags %d new_addr=0x%"PRIxPTR, (uintptr_t)result, (uintptr_t)old_addr, old_size, new_size, flags, flags & MREMAP_FIXED ? (uintptr_t)new_addr : 0); if (result != reinterpret_cast(-1)) { RecordRegionRemoval(old_addr, old_size); RecordRegionAddition(result, new_size); } } extern "C" void* __sbrk(ptrdiff_t increment); // defined in libc void MemoryRegionMap::SbrkHook(const void* result, ptrdiff_t increment) { RAW_VLOG(10, "Sbrk = 0x%"PRIxPTR" of %"PRIdS"", (uintptr_t)result, increment); if (result != reinterpret_cast(-1)) { if (increment > 0) { void* new_end = sbrk(0); RecordRegionAddition(result, reinterpret_cast(new_end) - reinterpret_cast(result)); } else if (increment < 0) { void* new_end = sbrk(0); RecordRegionRemoval(new_end, reinterpret_cast(result) - reinterpret_cast(new_end)); } } } void MemoryRegionMap::LogAllLocked() { RAW_CHECK(LockIsHeld(), "should be held (by this thread)"); RAW_LOG(INFO, "List of regions:"); uintptr_t previous = 0; for (RegionSet::const_iterator r = regions_->begin(); r != regions_->end(); ++r) { RAW_LOG(INFO, "Memory region 0x%"PRIxPTR"..0x%"PRIxPTR" " "from 0x%"PRIxPTR" stack=%d", r->start_addr, r->end_addr, r->caller(), r->is_stack); RAW_CHECK(previous < r->end_addr, "wow, we messed up the set order"); // this must be caused by uncontrolled recursive operations on regions_ previous = r->end_addr; } RAW_LOG(INFO, "End of regions list"); } ================================================ FILE: distro/google-perftools-1.7/src/memory_region_map.h ================================================ /* Copyright (c) 2006, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Maxim Lifantsev */ #ifndef BASE_MEMORY_REGION_MAP_H_ #define BASE_MEMORY_REGION_MAP_H_ #include #ifdef HAVE_PTHREAD #include #endif #include #include "base/stl_allocator.h" #include "base/spinlock.h" #include "base/thread_annotations.h" #include "base/low_level_alloc.h" // TODO(maxim): add a unittest: // execute a bunch of mmaps and compare memory map what strace logs // execute a bunch of mmap/munmup and compare memory map with // own accounting of what those mmaps generated // Thread-safe class to collect and query the map of all memory regions // in a process that have been created with mmap, munmap, mremap, sbrk. // For each memory region, we keep track of (and provide to users) // the stack trace that allocated that memory region. // The recorded stack trace depth is bounded by // a user-supplied max_stack_depth parameter of Init(). // After initialization with Init() // (which can happened even before global object constructor execution) // we collect the map by installing and monitoring MallocHook-s // to mmap, munmap, mremap, sbrk. // At any time one can query this map via provided interface. // For more details on the design of MemoryRegionMap // see the comment at the top of our .cc file. class MemoryRegionMap { private: // Max call stack recording depth supported by Init(). Set it to be // high enough for all our clients. Note: we do not define storage // for this (doing that requires special handling in windows), so // don't take the address of it! static const int kMaxStackDepth = 32; public: // interface ================================================================ // Every client of MemoryRegionMap must call Init() before first use, // and Shutdown() after last use. This allows us to reference count // this (singleton) class properly. MemoryRegionMap assumes it's the // only client of MallocHooks, so a client can only register other // MallocHooks after calling Init() and must unregister them before // calling Shutdown(). // Initialize this module to record memory allocation stack traces. // Stack traces that have more than "max_stack_depth" frames // are automatically shrunk to "max_stack_depth" when they are recorded. // Init() can be called more than once w/o harm, largest max_stack_depth // will be the effective one. // It will install mmap, munmap, mremap, sbrk hooks // and initialize arena_ and our hook and locks, hence one can use // MemoryRegionMap::Lock()/Unlock() to manage the locks. // Uses Lock/Unlock inside. static void Init(int max_stack_depth); // Try to shutdown this module undoing what Init() did. // Returns true iff could do full shutdown (or it was not attempted). // Full shutdown is attempted when the number of Shutdown() calls equals // the number of Init() calls. static bool Shutdown(); // Check that our hooks are still in place and crash if not. // No need for locking. static void CheckMallocHooks(); // Locks to protect our internal data structures. // These also protect use of arena_ if our Init() has been done. // The lock is recursive. static void Lock() EXCLUSIVE_LOCK_FUNCTION(lock_); static void Unlock() UNLOCK_FUNCTION(lock_); // Returns true when the lock is held by this thread (for use in RAW_CHECK-s). static bool LockIsHeld(); // Locker object that acquires the MemoryRegionMap::Lock // for the duration of its lifetime (a C++ scope). class LockHolder { public: LockHolder() { Lock(); } ~LockHolder() { Unlock(); } private: DISALLOW_COPY_AND_ASSIGN(LockHolder); }; // A memory region that we know about through malloc_hook-s. // This is essentially an interface through which MemoryRegionMap // exports the collected data to its clients. Thread-compatible. struct Region { uintptr_t start_addr; // region start address uintptr_t end_addr; // region end address int call_stack_depth; // number of caller stack frames that we saved const void* call_stack[kMaxStackDepth]; // caller address stack array // filled to call_stack_depth size bool is_stack; // does this region contain a thread's stack: // a user of MemoryRegionMap supplies this info // Convenience accessor for call_stack[0], // i.e. (the program counter of) the immediate caller // of this region's allocation function, // but it also returns NULL when call_stack_depth is 0, // i.e whe we weren't able to get the call stack. // This usually happens in recursive calls, when the stack-unwinder // calls mmap() which in turn calls the stack-unwinder. uintptr_t caller() const { return reinterpret_cast(call_stack_depth >= 1 ? call_stack[0] : NULL); } // Return true iff this region overlaps region x. bool Overlaps(const Region& x) const { return start_addr < x.end_addr && end_addr > x.start_addr; } private: // helpers for MemoryRegionMap friend class MemoryRegionMap; // The ways we create Region-s: void Create(const void* start, size_t size) { start_addr = reinterpret_cast(start); end_addr = start_addr + size; is_stack = false; // not a stack till marked such call_stack_depth = 0; AssertIsConsistent(); } void set_call_stack_depth(int depth) { RAW_DCHECK(call_stack_depth == 0, ""); // only one such set is allowed call_stack_depth = depth; AssertIsConsistent(); } // The ways we modify Region-s: void set_is_stack() { is_stack = true; } void set_start_addr(uintptr_t addr) { start_addr = addr; AssertIsConsistent(); } void set_end_addr(uintptr_t addr) { end_addr = addr; AssertIsConsistent(); } // Verifies that *this contains consistent data, crashes if not the case. void AssertIsConsistent() const { RAW_DCHECK(start_addr < end_addr, ""); RAW_DCHECK(call_stack_depth >= 0 && call_stack_depth <= kMaxStackDepth, ""); } // Post-default construction helper to make a Region suitable // for searching in RegionSet regions_. void SetRegionSetKey(uintptr_t addr) { // make sure *this has no usable data: if (DEBUG_MODE) memset(this, 0xFF, sizeof(*this)); end_addr = addr; } // Note: call_stack[kMaxStackDepth] as a member lets us make Region // a simple self-contained struct with correctly behaving bit-vise copying. // This simplifies the code of this module but wastes some memory: // in most-often use case of this module (leak checking) // only one call_stack element out of kMaxStackDepth is actually needed. // Making the storage for call_stack variable-sized, // substantially complicates memory management for the Region-s: // as they need to be created and manipulated for some time // w/o any memory allocations, yet are also given out to the users. }; // Find the region that covers addr and write its data into *result if found, // in which case *result gets filled so that it stays fully functional // even when the underlying region gets removed from MemoryRegionMap. // Returns success. Uses Lock/Unlock inside. static bool FindRegion(uintptr_t addr, Region* result); // Find the region that contains stack_top, mark that region as // a stack region, and write its data into *result if found, // in which case *result gets filled so that it stays fully functional // even when the underlying region gets removed from MemoryRegionMap. // Returns success. Uses Lock/Unlock inside. static bool FindAndMarkStackRegion(uintptr_t stack_top, Region* result); private: // our internal types ============================================== // Region comparator for sorting with STL struct RegionCmp { bool operator()(const Region& x, const Region& y) const { return x.end_addr < y.end_addr; } }; // We allocate STL objects in our own arena. struct MyAllocator { static void *Allocate(size_t n) { return LowLevelAlloc::AllocWithArena(n, arena_); } static void Free(const void *p, size_t /* n */) { LowLevelAlloc::Free(const_cast(p)); } }; // Set of the memory regions typedef std::set > RegionSet; public: // more in-depth interface ========================================== // STL iterator with values of Region typedef RegionSet::const_iterator RegionIterator; // Return the begin/end iterators to all the regions. // These need Lock/Unlock protection around their whole usage (loop). // Even when the same thread causes modifications during such a loop // (which are permitted due to recursive locking) // the loop iterator will still be valid as long as its region // has not been deleted, but EndRegionLocked should be // re-evaluated whenever the set of regions has changed. static RegionIterator BeginRegionLocked(); static RegionIterator EndRegionLocked(); // Effectively private type from our .cc ================================= // public to let us declare global objects: union RegionSetRep; private: // representation =========================================================== // Counter of clients of this module that have called Init(). static int client_count_; // Maximal number of caller stack frames to save (>= 0). static int max_stack_depth_; // Arena used for our allocations in regions_. static LowLevelAlloc::Arena* arena_; // Set of the mmap/sbrk/mremap-ed memory regions // To be accessed *only* when Lock() is held. // Hence we protect the non-recursive lock used inside of arena_ // with our recursive Lock(). This lets a user prevent deadlocks // when threads are stopped by ListAllProcessThreads at random spots // simply by acquiring our recursive Lock() before that. static RegionSet* regions_; // Lock to protect regions_ variable and the data behind. static SpinLock lock_; // Lock to protect the recursive lock itself. static SpinLock owner_lock_; // Recursion count for the recursive lock. static int recursion_count_; // The thread id of the thread that's inside the recursive lock. static pthread_t lock_owner_tid_; // helpers ================================================================== // Helper for FindRegion and FindAndMarkStackRegion: // returns the region covering 'addr' or NULL; assumes our lock_ is held. static const Region* DoFindRegionLocked(uintptr_t addr); // Verifying wrapper around regions_->insert(region) // To be called to do InsertRegionLocked's work only! inline static void DoInsertRegionLocked(const Region& region); // Handle regions saved by InsertRegionLocked into a tmp static array // by calling insert_func on them. inline static void HandleSavedRegionsLocked( void (*insert_func)(const Region& region)); // Wrapper around DoInsertRegionLocked // that handles the case of recursive allocator calls. inline static void InsertRegionLocked(const Region& region); // Record addition of a memory region at address "start" of size "size" // (called from our mmap/mremap/sbrk hooks). static void RecordRegionAddition(const void* start, size_t size); // Record deletion of a memory region at address "start" of size "size" // (called from our munmap/mremap/sbrk hooks). static void RecordRegionRemoval(const void* start, size_t size); // Hooks for MallocHook static void MmapHook(const void* result, const void* start, size_t size, int prot, int flags, int fd, off_t offset); static void MunmapHook(const void* ptr, size_t size); static void MremapHook(const void* result, const void* old_addr, size_t old_size, size_t new_size, int flags, const void* new_addr); static void SbrkHook(const void* result, ptrdiff_t increment); // Log all memory regions; Useful for debugging only. // Assumes Lock() is held static void LogAllLocked(); DISALLOW_COPY_AND_ASSIGN(MemoryRegionMap); }; #endif // BASE_MEMORY_REGION_MAP_H_ ================================================ FILE: distro/google-perftools-1.7/src/packed-cache-inl.h ================================================ // Copyright (c) 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Geoff Pike // // This file provides a minimal cache that can hold a pair // with little if any wasted space. The types of the key and value // must be unsigned integral types or at least have unsigned semantics // for >>, casting, and similar operations. // // Synchronization is not provided. However, the cache is implemented // as an array of cache entries whose type is chosen at compile time. // If a[i] is atomic on your hardware for the chosen array type then // raciness will not necessarily lead to bugginess. The cache entries // must be large enough to hold a partial key and a value packed // together. The partial keys are bit strings of length // kKeybits - kHashbits, and the values are bit strings of length kValuebits. // // In an effort to use minimal space, every cache entry represents // some pair; the class provides no way to mark a cache // entry as empty or uninitialized. In practice, you may want to have // reserved keys or values to get around this limitation. For example, in // tcmalloc's PageID-to-sizeclass cache, a value of 0 is used as // "unknown sizeclass." // // Usage Considerations // -------------------- // // kHashbits controls the size of the cache. The best value for // kHashbits will of course depend on the application. Perhaps try // tuning the value of kHashbits by measuring different values on your // favorite benchmark. Also remember not to be a pig; other // programs that need resources may suffer if you are. // // The main uses for this class will be when performance is // critical and there's a convenient type to hold the cache's // entries. As described above, the number of bits required // for a cache entry is (kKeybits - kHashbits) + kValuebits. Suppose // kKeybits + kValuebits is 43. Then it probably makes sense to // chose kHashbits >= 11 so that cache entries fit in a uint32. // // On the other hand, suppose kKeybits = kValuebits = 64. Then // using this class may be less worthwhile. You'll probably // be using 128 bits for each entry anyway, so maybe just pick // a hash function, H, and use an array indexed by H(key): // void Put(K key, V value) { a_[H(key)] = pair(key, value); } // V GetOrDefault(K key, V default) { const pair &p = a_[H(key)]; ... } // etc. // // Further Details // --------------- // // For caches used only by one thread, the following is true: // 1. For a cache c, // (c.Put(key, value), c.GetOrDefault(key, 0)) == value // and // (c.Put(key, value), <...>, c.GetOrDefault(key, 0)) == value // if the elided code contains no c.Put calls. // // 2. Has(key) will return false if no pair with that key // has ever been Put. However, a newly initialized cache will have // some pairs already present. When you create a new // cache, you must specify an "initial value." The initialization // procedure is equivalent to Clear(initial_value), which is // equivalent to Put(k, initial_value) for all keys k from 0 to // 2^kHashbits - 1. // // 3. If key and key' differ then the only way Put(key, value) may // cause Has(key') to change is that Has(key') may change from true to // false. Furthermore, a Put() call that doesn't change Has(key') // doesn't change GetOrDefault(key', ...) either. // // Implementation details: // // This is a direct-mapped cache with 2^kHashbits entries; the hash // function simply takes the low bits of the key. We store whole keys // if a whole key plus a whole value fits in an entry. Otherwise, an // entry is the high bits of a key and a value, packed together. // E.g., a 20 bit key and a 7 bit value only require a uint16 for each // entry if kHashbits >= 11. // // Alternatives to this scheme will be added as needed. #ifndef TCMALLOC_PACKED_CACHE_INL_H_ #define TCMALLOC_PACKED_CACHE_INL_H_ #include "config.h" #ifdef HAVE_STDINT_H #include #endif #include "base/basictypes.h" // for COMPILE_ASSERT #include "internal_logging.h" // A safe way of doing "(1 << n) - 1" -- without worrying about overflow // Note this will all be resolved to a constant expression at compile-time #define N_ONES_(IntType, N) \ ( (N) == 0 ? 0 : ((static_cast(1) << ((N)-1))-1 + \ (static_cast(1) << ((N)-1))) ) // The types K and V provide upper bounds on the number of valid keys // and values, but we explicitly require the keys to be less than // 2^kKeybits and the values to be less than 2^kValuebits. The size of // the table is controlled by kHashbits, and the type of each entry in // the cache is T. See also the big comment at the top of the file. template class PackedCache { public: typedef uintptr_t K; typedef size_t V; static const int kHashbits = 12; static const int kValuebits = 7; static const bool kUseWholeKeys = kKeybits + kValuebits <= 8 * sizeof(T); explicit PackedCache(V initial_value) { COMPILE_ASSERT(kKeybits <= sizeof(K) * 8, key_size); COMPILE_ASSERT(kValuebits <= sizeof(V) * 8, value_size); COMPILE_ASSERT(kHashbits <= kKeybits, hash_function); COMPILE_ASSERT(kKeybits - kHashbits + kValuebits <= kTbits, entry_size_must_be_big_enough); Clear(initial_value); } void Put(K key, V value) { ASSERT(key == (key & kKeyMask)); ASSERT(value == (value & kValueMask)); array_[Hash(key)] = KeyToUpper(key) | value; } bool Has(K key) const { ASSERT(key == (key & kKeyMask)); return KeyMatch(array_[Hash(key)], key); } V GetOrDefault(K key, V default_value) const { // As with other code in this class, we touch array_ as few times // as we can. Assuming entries are read atomically (e.g., their // type is uintptr_t on most hardware) then certain races are // harmless. ASSERT(key == (key & kKeyMask)); T entry = array_[Hash(key)]; return KeyMatch(entry, key) ? EntryToValue(entry) : default_value; } void Clear(V value) { ASSERT(value == (value & kValueMask)); for (int i = 0; i < 1 << kHashbits; i++) { ASSERT(kUseWholeKeys || KeyToUpper(i) == 0); array_[i] = kUseWholeKeys ? (value | KeyToUpper(i)) : value; } } private: // We are going to pack a value and the upper part of a key (or a // whole key) into an entry of type T. The UPPER type is for the // upper part of a key, after the key has been masked and shifted // for inclusion in an entry. typedef T UPPER; static V EntryToValue(T t) { return t & kValueMask; } // If we have space for a whole key, we just shift it left. // Otherwise kHashbits determines where in a K to find the upper // part of the key, and kValuebits determines where in the entry to // put it. static UPPER KeyToUpper(K k) { if (kUseWholeKeys) { return static_cast(k) << kValuebits; } else { const int shift = kHashbits - kValuebits; // Assume kHashbits >= kValuebits. It'd be easy to lift this assumption. return static_cast(k >> shift) & kUpperMask; } } static size_t Hash(K key) { return static_cast(key) & N_ONES_(size_t, kHashbits); } // Does the entry match the relevant part of the given key? static bool KeyMatch(T entry, K key) { return kUseWholeKeys ? (entry >> kValuebits == key) : ((KeyToUpper(key) ^ entry) & kUpperMask) == 0; } static const int kTbits = 8 * sizeof(T); static const int kUpperbits = kUseWholeKeys ? kKeybits : kKeybits - kHashbits; // For masking a K. static const K kKeyMask = N_ONES_(K, kKeybits); // For masking a T. static const T kUpperMask = N_ONES_(T, kUpperbits) << kValuebits; // For masking a V or a T. static const V kValueMask = N_ONES_(V, kValuebits); // array_ is the cache. Its elements are volatile because any // thread can write any array element at any time. volatile T array_[1 << kHashbits]; }; #undef N_ONES_ #endif // TCMALLOC_PACKED_CACHE_INL_H_ ================================================ FILE: distro/google-perftools-1.7/src/page_heap.cc ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat #include #include "page_heap.h" #include "static_vars.h" #include "system-alloc.h" DEFINE_double(tcmalloc_release_rate, EnvToDouble("TCMALLOC_RELEASE_RATE", 1.0), "Rate at which we release unused memory to the system. " "Zero means we never release memory back to the system. " "Increase this flag to return memory faster; decrease it " "to return memory slower. Reasonable rates are in the " "range [0,10]"); namespace tcmalloc { PageHeap::PageHeap() : pagemap_(MetaDataAlloc), pagemap_cache_(0), scavenge_counter_(0), // Start scavenging at kMaxPages list release_index_(kMaxPages) { COMPILE_ASSERT(kNumClasses <= (1 << PageMapCache::kValuebits), valuebits); DLL_Init(&large_.normal); DLL_Init(&large_.returned); for (int i = 0; i < kMaxPages; i++) { DLL_Init(&free_[i].normal); DLL_Init(&free_[i].returned); } } Span* PageHeap::SearchFreeAndLargeLists(Length n) { ASSERT(Check()); ASSERT(n > 0); // Find first size >= n that has a non-empty list for (Length s = n; s < kMaxPages; s++) { Span* ll = &free_[s].normal; // If we're lucky, ll is non-empty, meaning it has a suitable span. if (!DLL_IsEmpty(ll)) { ASSERT(ll->next->location == Span::ON_NORMAL_FREELIST); return Carve(ll->next, n); } // Alternatively, maybe there's a usable returned span. ll = &free_[s].returned; if (!DLL_IsEmpty(ll)) { ASSERT(ll->next->location == Span::ON_RETURNED_FREELIST); return Carve(ll->next, n); } } // No luck in free lists, our last chance is in a larger class. return AllocLarge(n); // May be NULL } Span* PageHeap::New(Length n) { ASSERT(Check()); ASSERT(n > 0); Span* result = SearchFreeAndLargeLists(n); if (result != NULL) return result; // Grow the heap and try again. if (!GrowHeap(n)) { ASSERT(Check()); return NULL; } return SearchFreeAndLargeLists(n); } Span* PageHeap::AllocLarge(Length n) { // find the best span (closest to n in size). // The following loops implements address-ordered best-fit. Span *best = NULL; // Search through normal list for (Span* span = large_.normal.next; span != &large_.normal; span = span->next) { if (span->length >= n) { if ((best == NULL) || (span->length < best->length) || ((span->length == best->length) && (span->start < best->start))) { best = span; ASSERT(best->location == Span::ON_NORMAL_FREELIST); } } } // Search through released list in case it has a better fit for (Span* span = large_.returned.next; span != &large_.returned; span = span->next) { if (span->length >= n) { if ((best == NULL) || (span->length < best->length) || ((span->length == best->length) && (span->start < best->start))) { best = span; ASSERT(best->location == Span::ON_RETURNED_FREELIST); } } } return best == NULL ? NULL : Carve(best, n); } Span* PageHeap::Split(Span* span, Length n) { ASSERT(0 < n); ASSERT(n < span->length); ASSERT(span->location == Span::IN_USE); ASSERT(span->sizeclass == 0); Event(span, 'T', n); const int extra = span->length - n; Span* leftover = NewSpan(span->start + n, extra); ASSERT(leftover->location == Span::IN_USE); Event(leftover, 'U', extra); RecordSpan(leftover); pagemap_.set(span->start + n - 1, span); // Update map from pageid to span span->length = n; return leftover; } Span* PageHeap::Carve(Span* span, Length n) { ASSERT(n > 0); ASSERT(span->location != Span::IN_USE); const int old_location = span->location; RemoveFromFreeList(span); span->location = Span::IN_USE; Event(span, 'A', n); const int extra = span->length - n; ASSERT(extra >= 0); if (extra > 0) { Span* leftover = NewSpan(span->start + n, extra); leftover->location = old_location; Event(leftover, 'S', extra); RecordSpan(leftover); PrependToFreeList(leftover); // Skip coalescing - no candidates possible span->length = n; pagemap_.set(span->start + n - 1, span); } ASSERT(Check()); return span; } void PageHeap::Delete(Span* span) { ASSERT(Check()); ASSERT(span->location == Span::IN_USE); ASSERT(span->length > 0); ASSERT(GetDescriptor(span->start) == span); ASSERT(GetDescriptor(span->start + span->length - 1) == span); const Length n = span->length; span->sizeclass = 0; span->sample = 0; span->location = Span::ON_NORMAL_FREELIST; Event(span, 'D', span->length); MergeIntoFreeList(span); // Coalesces if possible IncrementalScavenge(n); ASSERT(Check()); } void PageHeap::MergeIntoFreeList(Span* span) { ASSERT(span->location != Span::IN_USE); // Coalesce -- we guarantee that "p" != 0, so no bounds checking // necessary. We do not bother resetting the stale pagemap // entries for the pieces we are merging together because we only // care about the pagemap entries for the boundaries. // // Note that only similar spans are merged together. For example, // we do not coalesce "returned" spans with "normal" spans. const PageID p = span->start; const Length n = span->length; Span* prev = GetDescriptor(p-1); if (prev != NULL && prev->location == span->location) { // Merge preceding span into this span ASSERT(prev->start + prev->length == p); const Length len = prev->length; RemoveFromFreeList(prev); DeleteSpan(prev); span->start -= len; span->length += len; pagemap_.set(span->start, span); Event(span, 'L', len); } Span* next = GetDescriptor(p+n); if (next != NULL && next->location == span->location) { // Merge next span into this span ASSERT(next->start == p+n); const Length len = next->length; RemoveFromFreeList(next); DeleteSpan(next); span->length += len; pagemap_.set(span->start + span->length - 1, span); Event(span, 'R', len); } PrependToFreeList(span); } void PageHeap::PrependToFreeList(Span* span) { ASSERT(span->location != Span::IN_USE); SpanList* list = (span->length < kMaxPages) ? &free_[span->length] : &large_; if (span->location == Span::ON_NORMAL_FREELIST) { stats_.free_bytes += (span->length << kPageShift); DLL_Prepend(&list->normal, span); } else { stats_.unmapped_bytes += (span->length << kPageShift); DLL_Prepend(&list->returned, span); } } void PageHeap::RemoveFromFreeList(Span* span) { ASSERT(span->location != Span::IN_USE); if (span->location == Span::ON_NORMAL_FREELIST) { stats_.free_bytes -= (span->length << kPageShift); } else { stats_.unmapped_bytes -= (span->length << kPageShift); } DLL_Remove(span); } void PageHeap::IncrementalScavenge(Length n) { // Fast path; not yet time to release memory scavenge_counter_ -= n; if (scavenge_counter_ >= 0) return; // Not yet time to scavenge const double rate = FLAGS_tcmalloc_release_rate; if (rate <= 1e-6) { // Tiny release rate means that releasing is disabled. scavenge_counter_ = kDefaultReleaseDelay; return; } Length released_pages = ReleaseAtLeastNPages(1); if (released_pages == 0) { // Nothing to scavenge, delay for a while. scavenge_counter_ = kDefaultReleaseDelay; } else { // Compute how long to wait until we return memory. // FLAGS_tcmalloc_release_rate==1 means wait for 1000 pages // after releasing one page. const double mult = 1000.0 / rate; double wait = mult * static_cast(released_pages); if (wait > kMaxReleaseDelay) { // Avoid overflow and bound to reasonable range. wait = kMaxReleaseDelay; } scavenge_counter_ = static_cast(wait); } } Length PageHeap::ReleaseLastNormalSpan(SpanList* slist) { Span* s = slist->normal.prev; ASSERT(s->location == Span::ON_NORMAL_FREELIST); RemoveFromFreeList(s); const Length n = s->length; TCMalloc_SystemRelease(reinterpret_cast(s->start << kPageShift), static_cast(s->length << kPageShift)); s->location = Span::ON_RETURNED_FREELIST; MergeIntoFreeList(s); // Coalesces if possible. return n; } Length PageHeap::ReleaseAtLeastNPages(Length num_pages) { Length released_pages = 0; Length prev_released_pages = -1; // Round robin through the lists of free spans, releasing the last // span in each list. Stop after releasing at least num_pages. while (released_pages < num_pages) { if (released_pages == prev_released_pages) { // Last iteration of while loop made no progress. break; } prev_released_pages = released_pages; for (int i = 0; i < kMaxPages+1 && released_pages < num_pages; i++, release_index_++) { if (release_index_ > kMaxPages) release_index_ = 0; SpanList* slist = (release_index_ == kMaxPages) ? &large_ : &free_[release_index_]; if (!DLL_IsEmpty(&slist->normal)) { Length released_len = ReleaseLastNormalSpan(slist); released_pages += released_len; } } } return released_pages; } void PageHeap::RegisterSizeClass(Span* span, size_t sc) { // Associate span object with all interior pages as well ASSERT(span->location == Span::IN_USE); ASSERT(GetDescriptor(span->start) == span); ASSERT(GetDescriptor(span->start+span->length-1) == span); Event(span, 'C', sc); span->sizeclass = sc; for (Length i = 1; i < span->length-1; i++) { pagemap_.set(span->start+i, span); } } static double MB(uint64_t bytes) { return bytes / 1048576.0; } static double PagesToMB(uint64_t pages) { return (pages << kPageShift) / 1048576.0; } void PageHeap::GetClassSizes(int64 class_sizes_normal[kMaxPages], int64 class_sizes_returned[kMaxPages], int64* normal_pages_in_spans, int64* returned_pages_in_spans) { for (int s = 0; s < kMaxPages; s++) { if (class_sizes_normal != NULL) { class_sizes_normal[s] = DLL_Length(&free_[s].normal); } if (class_sizes_returned != NULL) { class_sizes_returned[s] = DLL_Length(&free_[s].returned); } } if (normal_pages_in_spans != NULL) { *normal_pages_in_spans = 0; for (Span* s = large_.normal.next; s != &large_.normal; s = s->next) { *normal_pages_in_spans += s->length;; } } if (returned_pages_in_spans != NULL) { *returned_pages_in_spans = 0; for (Span* s = large_.returned.next; s != &large_.returned; s = s->next) { *returned_pages_in_spans += s->length; } } } void PageHeap::Dump(TCMalloc_Printer* out) { int nonempty_sizes = 0; for (int s = 0; s < kMaxPages; s++) { if (!DLL_IsEmpty(&free_[s].normal) || !DLL_IsEmpty(&free_[s].returned)) { nonempty_sizes++; } } out->printf("------------------------------------------------\n"); out->printf("PageHeap: %d sizes; %6.1f MB free; %6.1f MB unmapped\n", nonempty_sizes, MB(stats_.free_bytes), MB(stats_.unmapped_bytes)); out->printf("------------------------------------------------\n"); uint64_t total_normal = 0; uint64_t total_returned = 0; for (int s = 0; s < kMaxPages; s++) { const int n_length = DLL_Length(&free_[s].normal); const int r_length = DLL_Length(&free_[s].returned); if (n_length + r_length > 0) { uint64_t n_pages = s * n_length; uint64_t r_pages = s * r_length; total_normal += n_pages; total_returned += r_pages; out->printf("%6u pages * %6u spans ~ %6.1f MB; %6.1f MB cum" "; unmapped: %6.1f MB; %6.1f MB cum\n", s, (n_length + r_length), PagesToMB(n_pages + r_pages), PagesToMB(total_normal + total_returned), PagesToMB(r_pages), PagesToMB(total_returned)); } } uint64_t n_pages = 0; uint64_t r_pages = 0; int n_spans = 0; int r_spans = 0; out->printf("Normal large spans:\n"); for (Span* s = large_.normal.next; s != &large_.normal; s = s->next) { out->printf(" [ %6" PRIuPTR " pages ] %6.1f MB\n", s->length, PagesToMB(s->length)); n_pages += s->length; n_spans++; } out->printf("Unmapped large spans:\n"); for (Span* s = large_.returned.next; s != &large_.returned; s = s->next) { out->printf(" [ %6" PRIuPTR " pages ] %6.1f MB\n", s->length, PagesToMB(s->length)); r_pages += s->length; r_spans++; } total_normal += n_pages; total_returned += r_pages; out->printf(">255 large * %6u spans ~ %6.1f MB; %6.1f MB cum" "; unmapped: %6.1f MB; %6.1f MB cum\n", (n_spans + r_spans), PagesToMB(n_pages + r_pages), PagesToMB(total_normal + total_returned), PagesToMB(r_pages), PagesToMB(total_returned)); } bool PageHeap::GetNextRange(PageID start, base::MallocRange* r) { Span* span = reinterpret_cast(pagemap_.Next(start)); if (span == NULL) { return false; } r->address = span->start << kPageShift; r->length = span->length << kPageShift; r->fraction = 0; switch (span->location) { case Span::IN_USE: r->type = base::MallocRange::INUSE; r->fraction = 1; if (span->sizeclass > 0) { // Only some of the objects in this span may be in use. const size_t osize = Static::sizemap()->class_to_size(span->sizeclass); r->fraction = (1.0 * osize * span->refcount) / r->length; } break; case Span::ON_NORMAL_FREELIST: r->type = base::MallocRange::FREE; break; case Span::ON_RETURNED_FREELIST: r->type = base::MallocRange::UNMAPPED; break; default: r->type = base::MallocRange::UNKNOWN; break; } return true; } static void RecordGrowth(size_t growth) { StackTrace* t = Static::stacktrace_allocator()->New(); t->depth = GetStackTrace(t->stack, kMaxStackDepth-1, 3); t->size = growth; t->stack[kMaxStackDepth-1] = reinterpret_cast(Static::growth_stacks()); Static::set_growth_stacks(t); } bool PageHeap::GrowHeap(Length n) { ASSERT(kMaxPages >= kMinSystemAlloc); if (n > kMaxValidPages) return false; Length ask = (n>kMinSystemAlloc) ? n : static_cast(kMinSystemAlloc); size_t actual_size; void* ptr = TCMalloc_SystemAlloc(ask << kPageShift, &actual_size, kPageSize); if (ptr == NULL) { if (n < ask) { // Try growing just "n" pages ask = n; ptr = TCMalloc_SystemAlloc(ask << kPageShift, &actual_size, kPageSize); } if (ptr == NULL) return false; } ask = actual_size >> kPageShift; RecordGrowth(ask << kPageShift); uint64_t old_system_bytes = stats_.system_bytes; stats_.system_bytes += (ask << kPageShift); const PageID p = reinterpret_cast(ptr) >> kPageShift; ASSERT(p > 0); // If we have already a lot of pages allocated, just pre allocate a bunch of // memory for the page map. This prevents fragmentation by pagemap metadata // when a program keeps allocating and freeing large blocks. if (old_system_bytes < kPageMapBigAllocationThreshold && stats_.system_bytes >= kPageMapBigAllocationThreshold) { pagemap_.PreallocateMoreMemory(); } // Make sure pagemap_ has entries for all of the new pages. // Plus ensure one before and one after so coalescing code // does not need bounds-checking. if (pagemap_.Ensure(p-1, ask+2)) { // Pretend the new area is allocated and then Delete() it to cause // any necessary coalescing to occur. Span* span = NewSpan(p, ask); RecordSpan(span); Delete(span); ASSERT(Check()); return true; } else { // We could not allocate memory within "pagemap_" // TODO: Once we can return memory to the system, return the new span return false; } } bool PageHeap::Check() { ASSERT(free_[0].normal.next == &free_[0].normal); ASSERT(free_[0].returned.next == &free_[0].returned); return true; } bool PageHeap::CheckExpensive() { bool result = Check(); CheckList(&large_.normal, kMaxPages, 1000000000, Span::ON_NORMAL_FREELIST); CheckList(&large_.returned, kMaxPages, 1000000000, Span::ON_RETURNED_FREELIST); for (Length s = 1; s < kMaxPages; s++) { CheckList(&free_[s].normal, s, s, Span::ON_NORMAL_FREELIST); CheckList(&free_[s].returned, s, s, Span::ON_RETURNED_FREELIST); } return result; } bool PageHeap::CheckList(Span* list, Length min_pages, Length max_pages, int freelist) { for (Span* s = list->next; s != list; s = s->next) { CHECK_CONDITION(s->location == freelist); // NORMAL or RETURNED CHECK_CONDITION(s->length >= min_pages); CHECK_CONDITION(s->length <= max_pages); CHECK_CONDITION(GetDescriptor(s->start) == s); CHECK_CONDITION(GetDescriptor(s->start+s->length-1) == s); } return true; } } // namespace tcmalloc ================================================ FILE: distro/google-perftools-1.7/src/page_heap.h ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat #ifndef TCMALLOC_PAGE_HEAP_H_ #define TCMALLOC_PAGE_HEAP_H_ #include #include #include "common.h" #include "packed-cache-inl.h" #include "pagemap.h" #include "span.h" // We need to dllexport PageHeap just for the unittest. MSVC complains // that we don't dllexport the PageHeap members, but we don't need to // test those, so I just suppress this warning. #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4251) #endif // This #ifdef should almost never be set. Set NO_TCMALLOC_SAMPLES if // you're porting to a system where you really can't get a stacktrace. #ifdef NO_TCMALLOC_SAMPLES // We use #define so code compiles even if you #include stacktrace.h somehow. # define GetStackTrace(stack, depth, skip) (0) #else # include #endif namespace tcmalloc { // ------------------------------------------------------------------------- // Map from page-id to per-page data // ------------------------------------------------------------------------- // We use PageMap2<> for 32-bit and PageMap3<> for 64-bit machines. // We also use a simple one-level cache for hot PageID-to-sizeclass mappings, // because sometimes the sizeclass is all the information we need. // Selector class -- general selector uses 3-level map template class MapSelector { public: typedef TCMalloc_PageMap3 Type; typedef PackedCache CacheType; }; // A two-level map for 32-bit machines template <> class MapSelector<32> { public: typedef TCMalloc_PageMap2<32-kPageShift> Type; typedef PackedCache<32-kPageShift, uint16_t> CacheType; }; // ------------------------------------------------------------------------- // Page-level allocator // * Eager coalescing // // Heap for page-level allocation. We allow allocating and freeing a // contiguous runs of pages (called a "span"). // ------------------------------------------------------------------------- class PERFTOOLS_DLL_DECL PageHeap { public: PageHeap(); // Allocate a run of "n" pages. Returns zero if out of memory. // Caller should not pass "n == 0" -- instead, n should have // been rounded up already. Span* New(Length n); // Delete the span "[p, p+n-1]". // REQUIRES: span was returned by earlier call to New() and // has not yet been deleted. void Delete(Span* span); // Mark an allocated span as being used for small objects of the // specified size-class. // REQUIRES: span was returned by an earlier call to New() // and has not yet been deleted. void RegisterSizeClass(Span* span, size_t sc); // Split an allocated span into two spans: one of length "n" pages // followed by another span of length "span->length - n" pages. // Modifies "*span" to point to the first span of length "n" pages. // Returns a pointer to the second span. // // REQUIRES: "0 < n < span->length" // REQUIRES: span->location == IN_USE // REQUIRES: span->sizeclass == 0 Span* Split(Span* span, Length n); // Return the descriptor for the specified page. Returns NULL if // this PageID was not allocated previously. inline Span* GetDescriptor(PageID p) const { return reinterpret_cast(pagemap_.get(p)); } // Dump state to stderr void Dump(TCMalloc_Printer* out); // If this page heap is managing a range with starting page # >= start, // store info about the range in *r and return true. Else return false. bool GetNextRange(PageID start, base::MallocRange* r); // Page heap statistics struct Stats { Stats() : system_bytes(0), free_bytes(0), unmapped_bytes(0) {} uint64_t system_bytes; // Total bytes allocated from system uint64_t free_bytes; // Total bytes on normal freelists uint64_t unmapped_bytes; // Total bytes on returned freelists }; inline Stats stats() const { return stats_; } void GetClassSizes(int64 class_sizes_normal[kMaxPages], int64 class_sizes_returned[kMaxPages], int64* normal_pages_in_spans, int64* returned_pages_in_spans); bool Check(); // Like Check() but does some more comprehensive checking. bool CheckExpensive(); bool CheckList(Span* list, Length min_pages, Length max_pages, int freelist); // ON_NORMAL_FREELIST or ON_RETURNED_FREELIST // Try to release at least num_pages for reuse by the OS. Returns // the actual number of pages released, which may be less than // num_pages if there weren't enough pages to release. The result // may also be larger than num_pages since page_heap might decide to // release one large range instead of fragmenting it into two // smaller released and unreleased ranges. Length ReleaseAtLeastNPages(Length num_pages); // Return 0 if we have no information, or else the correct sizeclass for p. // Reads and writes to pagemap_cache_ do not require locking. // The entries are 64 bits on 64-bit hardware and 16 bits on // 32-bit hardware, and we don't mind raciness as long as each read of // an entry yields a valid entry, not a partially updated entry. size_t GetSizeClassIfCached(PageID p) const { return pagemap_cache_.GetOrDefault(p, 0); } void CacheSizeClass(PageID p, size_t cl) const { pagemap_cache_.Put(p, cl); } private: // Allocates a big block of memory for the pagemap once we reach more than // 128MB static const size_t kPageMapBigAllocationThreshold = 128 << 20; // Minimum number of pages to fetch from system at a time. Must be // significantly bigger than kBlockSize to amortize system-call // overhead, and also to reduce external fragementation. Also, we // should keep this value big because various incarnations of Linux // have small limits on the number of mmap() regions per // address-space. // REQUIRED: kMinSystemAlloc <= kMaxPages; static const int kMinSystemAlloc = kMaxPages; // Never delay scavenging for more than the following number of // deallocated pages. With 4K pages, this comes to 4GB of // deallocation. static const int kMaxReleaseDelay = 1 << 20; // If there is nothing to release, wait for so many pages before // scavenging again. With 4K pages, this comes to 1GB of memory. static const int kDefaultReleaseDelay = 1 << 18; // Pick the appropriate map and cache types based on pointer size typedef MapSelector::Type PageMap; typedef MapSelector::CacheType PageMapCache; PageMap pagemap_; mutable PageMapCache pagemap_cache_; // We segregate spans of a given size into two circular linked // lists: one for normal spans, and one for spans whose memory // has been returned to the system. struct SpanList { Span normal; Span returned; }; // List of free spans of length >= kMaxPages SpanList large_; // Array mapping from span length to a doubly linked list of free spans SpanList free_[kMaxPages]; // Statistics on system, free, and unmapped bytes Stats stats_; Span* SearchFreeAndLargeLists(Length n); bool GrowHeap(Length n); // REQUIRES: span->length >= n // REQUIRES: span->location != IN_USE // Remove span from its free list, and move any leftover part of // span into appropriate free lists. Also update "span" to have // length exactly "n" and mark it as non-free so it can be returned // to the client. After all that, decrease free_pages_ by n and // return span. Span* Carve(Span* span, Length n); void RecordSpan(Span* span) { pagemap_.set(span->start, span); if (span->length > 1) { pagemap_.set(span->start + span->length - 1, span); } } // Allocate a large span of length == n. If successful, returns a // span of exactly the specified length. Else, returns NULL. Span* AllocLarge(Length n); // Coalesce span with neighboring spans if possible, prepend to // appropriate free list, and adjust stats. void MergeIntoFreeList(Span* span); // Prepends span to appropriate free list, and adjusts stats. void PrependToFreeList(Span* span); // Removes span from its free list, and adjust stats. void RemoveFromFreeList(Span* span); // Incrementally release some memory to the system. // IncrementalScavenge(n) is called whenever n pages are freed. void IncrementalScavenge(Length n); // Release the last span on the normal portion of this list. // Return the length of that span. Length ReleaseLastNormalSpan(SpanList* slist); // Number of pages to deallocate before doing more scavenging int64_t scavenge_counter_; // Index of last free list where we released memory to the OS. int release_index_; }; } // namespace tcmalloc #ifdef _MSC_VER #pragma warning(pop) #endif #endif // TCMALLOC_PAGE_HEAP_H_ ================================================ FILE: distro/google-perftools-1.7/src/page_heap_allocator.h ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat #ifndef TCMALLOC_PAGE_HEAP_ALLOCATOR_H_ #define TCMALLOC_PAGE_HEAP_ALLOCATOR_H_ namespace tcmalloc { // Simple allocator for objects of a specified type. External locking // is required before accessing one of these objects. template class PageHeapAllocator { public: // We use an explicit Init function because these variables are statically // allocated and their constructors might not have run by the time some // other static variable tries to allocate memory. void Init() { ASSERT(sizeof(T) <= kAllocIncrement); inuse_ = 0; free_area_ = NULL; free_avail_ = 0; free_list_ = NULL; // Reserve some space at the beginning to avoid fragmentation. Delete(New()); } T* New() { // Consult free list void* result; if (free_list_ != NULL) { result = free_list_; free_list_ = *(reinterpret_cast(result)); } else { if (free_avail_ < sizeof(T)) { // Need more room. We assume that MetaDataAlloc returns // suitably aligned memory. free_area_ = reinterpret_cast(MetaDataAlloc(kAllocIncrement)); if (free_area_ == NULL) { CRASH("FATAL ERROR: Out of memory trying to allocate internal " "tcmalloc data (%d bytes, object-size %d)\n", kAllocIncrement, static_cast(sizeof(T))); } free_avail_ = kAllocIncrement; } result = free_area_; free_area_ += sizeof(T); free_avail_ -= sizeof(T); } inuse_++; return reinterpret_cast(result); } void Delete(T* p) { *(reinterpret_cast(p)) = free_list_; free_list_ = p; inuse_--; } int inuse() const { return inuse_; } private: // How much to allocate from system at a time static const int kAllocIncrement = 128 << 10; // Free area from which to carve new objects char* free_area_; size_t free_avail_; // Free list of already carved objects void* free_list_; // Number of allocated but unfreed objects int inuse_; }; } // namespace tcmalloc #endif // TCMALLOC_PAGE_HEAP_ALLOCATOR_H_ ================================================ FILE: distro/google-perftools-1.7/src/pagemap.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // A data structure used by the caching malloc. It maps from page# to // a pointer that contains info about that page. We use two // representations: one for 32-bit addresses, and another for 64 bit // addresses. Both representations provide the same interface. The // first representation is implemented as a flat array, the seconds as // a three-level radix tree that strips away approximately 1/3rd of // the bits every time. // // The BITS parameter should be the number of bits required to hold // a page number. E.g., with 32 bit pointers and 4K pages (i.e., // page offset fits in lower 12 bits), BITS == 20. #ifndef TCMALLOC_PAGEMAP_H_ #define TCMALLOC_PAGEMAP_H_ #include "config.h" #if defined HAVE_STDINT_H #include #elif defined HAVE_INTTYPES_H #include #else #include #endif #include "internal_logging.h" // Single-level array template class TCMalloc_PageMap1 { private: static const int LENGTH = 1 << BITS; void** array_; public: typedef uintptr_t Number; explicit TCMalloc_PageMap1(void* (*allocator)(size_t)) { array_ = reinterpret_cast((*allocator)(sizeof(void*) << BITS)); memset(array_, 0, sizeof(void*) << BITS); } // Ensure that the map contains initialized entries "x .. x+n-1". // Returns true if successful, false if we could not allocate memory. bool Ensure(Number x, size_t n) { // Nothing to do since flat array was allocated at start. All // that's left is to check for overflow (that is, we don't want to // ensure a number y where array_[y] would be an out-of-bounds // access). return n <= LENGTH - x; // an overflow-free way to do "x + n <= LENGTH" } void PreallocateMoreMemory() {} // Return the current value for KEY. Returns NULL if not yet set, // or if k is out of range. void* get(Number k) const { if ((k >> BITS) > 0) { return NULL; } return array_[k]; } // REQUIRES "k" is in range "[0,2^BITS-1]". // REQUIRES "k" has been ensured before. // // Sets the value 'v' for key 'k'. void set(Number k, void* v) { array_[k] = v; } // Return the first non-NULL pointer found in this map for // a page number >= k. Returns NULL if no such number is found. void* Next(Number k) const { while (k < (1 << BITS)) { if (array_[k] != NULL) return array_[k]; k++; } return NULL; } }; // Two-level radix tree template class TCMalloc_PageMap2 { private: // Put 32 entries in the root and (2^BITS)/32 entries in each leaf. static const int ROOT_BITS = 5; static const int ROOT_LENGTH = 1 << ROOT_BITS; static const int LEAF_BITS = BITS - ROOT_BITS; static const int LEAF_LENGTH = 1 << LEAF_BITS; // Leaf node struct Leaf { void* values[LEAF_LENGTH]; }; Leaf* root_[ROOT_LENGTH]; // Pointers to 32 child nodes void* (*allocator_)(size_t); // Memory allocator public: typedef uintptr_t Number; explicit TCMalloc_PageMap2(void* (*allocator)(size_t)) { allocator_ = allocator; memset(root_, 0, sizeof(root_)); } void* get(Number k) const { const Number i1 = k >> LEAF_BITS; const Number i2 = k & (LEAF_LENGTH-1); if ((k >> BITS) > 0 || root_[i1] == NULL) { return NULL; } return root_[i1]->values[i2]; } void set(Number k, void* v) { ASSERT(k >> BITS == 0); const Number i1 = k >> LEAF_BITS; const Number i2 = k & (LEAF_LENGTH-1); root_[i1]->values[i2] = v; } bool Ensure(Number start, size_t n) { for (Number key = start; key <= start + n - 1; ) { const Number i1 = key >> LEAF_BITS; // Check for overflow if (i1 >= ROOT_LENGTH) return false; // Make 2nd level node if necessary if (root_[i1] == NULL) { Leaf* leaf = reinterpret_cast((*allocator_)(sizeof(Leaf))); if (leaf == NULL) return false; memset(leaf, 0, sizeof(*leaf)); root_[i1] = leaf; } // Advance key past whatever is covered by this leaf node key = ((key >> LEAF_BITS) + 1) << LEAF_BITS; } return true; } void PreallocateMoreMemory() { // Allocate enough to keep track of all possible pages Ensure(0, 1 << BITS); } void* Next(Number k) const { while (k < (1 << BITS)) { const Number i1 = k >> LEAF_BITS; Leaf* leaf = root_[i1]; if (leaf != NULL) { // Scan forward in leaf for (Number i2 = k & (LEAF_LENGTH - 1); i2 < LEAF_LENGTH; i2++) { if (leaf->values[i2] != NULL) { return leaf->values[i2]; } } } // Skip to next top-level entry k = (i1 + 1) << LEAF_BITS; } return NULL; } }; // Three-level radix tree template class TCMalloc_PageMap3 { private: // How many bits should we consume at each interior level static const int INTERIOR_BITS = (BITS + 2) / 3; // Round-up static const int INTERIOR_LENGTH = 1 << INTERIOR_BITS; // How many bits should we consume at leaf level static const int LEAF_BITS = BITS - 2*INTERIOR_BITS; static const int LEAF_LENGTH = 1 << LEAF_BITS; // Interior node struct Node { Node* ptrs[INTERIOR_LENGTH]; }; // Leaf node struct Leaf { void* values[LEAF_LENGTH]; }; Node* root_; // Root of radix tree void* (*allocator_)(size_t); // Memory allocator Node* NewNode() { Node* result = reinterpret_cast((*allocator_)(sizeof(Node))); if (result != NULL) { memset(result, 0, sizeof(*result)); } return result; } public: typedef uintptr_t Number; explicit TCMalloc_PageMap3(void* (*allocator)(size_t)) { allocator_ = allocator; root_ = NewNode(); } void* get(Number k) const { const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS); const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH-1); const Number i3 = k & (LEAF_LENGTH-1); if ((k >> BITS) > 0 || root_->ptrs[i1] == NULL || root_->ptrs[i1]->ptrs[i2] == NULL) { return NULL; } return reinterpret_cast(root_->ptrs[i1]->ptrs[i2])->values[i3]; } void set(Number k, void* v) { ASSERT(k >> BITS == 0); const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS); const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH-1); const Number i3 = k & (LEAF_LENGTH-1); reinterpret_cast(root_->ptrs[i1]->ptrs[i2])->values[i3] = v; } bool Ensure(Number start, size_t n) { for (Number key = start; key <= start + n - 1; ) { const Number i1 = key >> (LEAF_BITS + INTERIOR_BITS); const Number i2 = (key >> LEAF_BITS) & (INTERIOR_LENGTH-1); // Check for overflow if (i1 >= INTERIOR_LENGTH || i2 >= INTERIOR_LENGTH) return false; // Make 2nd level node if necessary if (root_->ptrs[i1] == NULL) { Node* n = NewNode(); if (n == NULL) return false; root_->ptrs[i1] = n; } // Make leaf node if necessary if (root_->ptrs[i1]->ptrs[i2] == NULL) { Leaf* leaf = reinterpret_cast((*allocator_)(sizeof(Leaf))); if (leaf == NULL) return false; memset(leaf, 0, sizeof(*leaf)); root_->ptrs[i1]->ptrs[i2] = reinterpret_cast(leaf); } // Advance key past whatever is covered by this leaf node key = ((key >> LEAF_BITS) + 1) << LEAF_BITS; } return true; } void PreallocateMoreMemory() { } void* Next(Number k) const { while (k < (Number(1) << BITS)) { const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS); const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH-1); if (root_->ptrs[i1] == NULL) { // Advance to next top-level entry k = (i1 + 1) << (LEAF_BITS + INTERIOR_BITS); } else { Leaf* leaf = reinterpret_cast(root_->ptrs[i1]->ptrs[i2]); if (leaf != NULL) { for (Number i3 = (k & (LEAF_LENGTH-1)); i3 < LEAF_LENGTH; i3++) { if (leaf->values[i3] != NULL) { return leaf->values[i3]; } } } // Advance to next interior entry k = ((k >> LEAF_BITS) + 1) << LEAF_BITS; } } return NULL; } }; #endif // TCMALLOC_PAGEMAP_H_ ================================================ FILE: distro/google-perftools-1.7/src/pprof ================================================ #! /usr/bin/env perl # Copyright (c) 1998-2007, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # --- # Program for printing the profile generated by common/profiler.cc, # or by the heap profiler (common/debugallocation.cc) # # The profile contains a sequence of entries of the form: # # This program parses the profile, and generates user-readable # output. # # Examples: # # % tools/pprof "program" "profile" # Enters "interactive" mode # # % tools/pprof --text "program" "profile" # Generates one line per procedure # # % tools/pprof --gv "program" "profile" # Generates annotated call-graph and displays via "gv" # # % tools/pprof --gv --focus=Mutex "program" "profile" # Restrict to code paths that involve an entry that matches "Mutex" # # % tools/pprof --gv --focus=Mutex --ignore=string "program" "profile" # Restrict to code paths that involve an entry that matches "Mutex" # and does not match "string" # # % tools/pprof --list=IBF_CheckDocid "program" "profile" # Generates disassembly listing of all routines with at least one # sample that match the --list= pattern. The listing is # annotated with the flat and cumulative sample counts at each line. # # % tools/pprof --disasm=IBF_CheckDocid "program" "profile" # Generates disassembly listing of all routines with at least one # sample that match the --disasm= pattern. The listing is # annotated with the flat and cumulative sample counts at each PC value. # # TODO: Use color to indicate files? use strict; use warnings; use Getopt::Long; my $PPROF_VERSION = "1.7"; # These are the object tools we use which can come from a # user-specified location using --tools, from the PPROF_TOOLS # environment variable, or from the environment. my %obj_tool_map = ( "objdump" => "objdump", "nm" => "nm", "addr2line" => "addr2line", "c++filt" => "c++filt", ## ConfigureObjTools may add architecture-specific entries: #"nm_pdb" => "nm-pdb", # for reading windows (PDB-format) executables #"addr2line_pdb" => "addr2line-pdb", # ditto #"otool" => "otool", # equivalent of objdump on OS X ); my $DOT = "dot"; # leave non-absolute, since it may be in /usr/local my $GV = "gv"; my $EVINCE = "evince"; # could also be xpdf or perhaps acroread my $KCACHEGRIND = "kcachegrind"; my $PS2PDF = "ps2pdf"; # These are used for dynamic profiles my $URL_FETCHER = "curl -s"; # These are the web pages that servers need to support for dynamic profiles my $HEAP_PAGE = "/pprof/heap"; my $PROFILE_PAGE = "/pprof/profile"; # must support cgi-param "?seconds=#" my $PMUPROFILE_PAGE = "/pprof/pmuprofile(?:\\?.*)?"; # must support cgi-param # ?seconds=#&event=x&period=n my $GROWTH_PAGE = "/pprof/growth"; my $CONTENTION_PAGE = "/pprof/contention"; my $WALL_PAGE = "/pprof/wall(?:\\?.*)?"; # accepts options like namefilter my $FILTEREDPROFILE_PAGE = "/pprof/filteredprofile(?:\\?.*)?"; my $CENSUSPROFILE_PAGE = "/pprof/censusprofile"; # must support "?seconds=#" my $SYMBOL_PAGE = "/pprof/symbol"; # must support symbol lookup via POST my $PROGRAM_NAME_PAGE = "/pprof/cmdline"; # These are the web pages that can be named on the command line. # All the alternatives must begin with /. my $PROFILES = "($HEAP_PAGE|$PROFILE_PAGE|$PMUPROFILE_PAGE|" . "$GROWTH_PAGE|$CONTENTION_PAGE|$WALL_PAGE|" . "$FILTEREDPROFILE_PAGE|$CENSUSPROFILE_PAGE)"; # default binary name my $UNKNOWN_BINARY = "(unknown)"; # There is a pervasive dependency on the length (in hex characters, # i.e., nibbles) of an address, distinguishing between 32-bit and # 64-bit profiles. To err on the safe size, default to 64-bit here: my $address_length = 16; # A list of paths to search for shared object files my @prefix_list = (); # Special routine name that should not have any symbols. # Used as separator to parse "addr2line -i" output. my $sep_symbol = '_fini'; my $sep_address = undef; ##### Argument parsing ##### sub usage_string { return < is a space separated list of profile names. pprof [options] is a list of profile files where each file contains the necessary symbol mappings as well as profile data (likely generated with --raw). pprof [options] is a remote form. Symbols are obtained from host:port$SYMBOL_PAGE Each name can be: /path/to/profile - a path to a profile file host:port[/] - a location of a service to get profile from The / can be $HEAP_PAGE, $PROFILE_PAGE, /pprof/pmuprofile, $GROWTH_PAGE, $CONTENTION_PAGE, /pprof/wall, $CENSUSPROFILE_PAGE, or /pprof/filteredprofile. For instance: "pprof http://myserver.com:80$HEAP_PAGE". If / is omitted, the service defaults to $PROFILE_PAGE (cpu profiling). pprof --symbols Maps addresses to symbol names. In this mode, stdin should be a list of library mappings, in the same format as is found in the heap- and cpu-profile files (this loosely matches that of /proc/self/maps on linux), followed by a list of hex addresses to map, one per line. For more help with querying remote servers, including how to add the necessary server-side support code, see this filename (or one like it): /usr/doc/google-perftools-$PPROF_VERSION/pprof_remote_servers.html Options: --cum Sort by cumulative data --base= Subtract from before display --interactive Run in interactive mode (interactive "help" gives help) [default] --seconds= Length of time for dynamic profiles [default=30 secs] --add_lib= Read additional symbols and line info from the given library --lib_prefix= Comma separated list of library path prefixes Reporting Granularity: --addresses Report at address level --lines Report at source line level --functions Report at function level [default] --files Report at source file level Output type: --text Generate text report --callgrind Generate callgrind format to stdout --gv Generate Postscript and display --evince Generate PDF and display --web Generate SVG and display --list= Generate source listing of matching routines --disasm= Generate disassembly of matching routines --symbols Print demangled symbol names found at given addresses --dot Generate DOT file to stdout --ps Generate Postcript to stdout --pdf Generate PDF to stdout --svg Generate SVG to stdout --gif Generate GIF to stdout --raw Generate symbolized pprof data (useful with remote fetch) Heap-Profile Options: --inuse_space Display in-use (mega)bytes [default] --inuse_objects Display in-use objects --alloc_space Display allocated (mega)bytes --alloc_objects Display allocated objects --show_bytes Display space in bytes --drop_negative Ignore negative differences Contention-profile options: --total_delay Display total delay at each region [default] --contentions Display number of delays at each region --mean_delay Display mean delay at each region Call-graph Options: --nodecount= Show at most so many nodes [default=80] --nodefraction= Hide nodes below *total [default=.005] --edgefraction= Hide edges below *total [default=.001] --maxdegree= Max incoming/outgoing edges per node [default=8] --focus= Focus on nodes matching --ignore= Ignore nodes matching --scale= Set GV scaling [default=0] --heapcheck Make nodes with non-0 object counts (i.e. direct leak generators) more visible Miscellaneous: --tools=[,...] \$PATH for object tool pathnames --test Run unit tests --help This message --version Version information Environment Variables: PPROF_TMPDIR Profiles directory. Defaults to \$HOME/pprof PPROF_TOOLS Prefix for object tools pathnames Examples: pprof /bin/ls ls.prof Enters "interactive" mode pprof --text /bin/ls ls.prof Outputs one line per procedure pprof --web /bin/ls ls.prof Displays annotated call-graph in web browser pprof --gv /bin/ls ls.prof Displays annotated call-graph via 'gv' pprof --gv --focus=Mutex /bin/ls ls.prof Restricts to code paths including a .*Mutex.* entry pprof --gv --focus=Mutex --ignore=string /bin/ls ls.prof Code paths including Mutex but not string pprof --list=getdir /bin/ls ls.prof (Per-line) annotated source listing for getdir() pprof --disasm=getdir /bin/ls ls.prof (Per-PC) annotated disassembly for getdir() pprof http://localhost:1234/ Enters "interactive" mode pprof --text localhost:1234 Outputs one line per procedure for localhost:1234 pprof --raw localhost:1234 > ./local.raw pprof --text ./local.raw Fetches a remote profile for later analysis and then analyzes it in text mode. EOF } sub version_string { return < \$main::opt_help, "version!" => \$main::opt_version, "cum!" => \$main::opt_cum, "base=s" => \$main::opt_base, "seconds=i" => \$main::opt_seconds, "add_lib=s" => \$main::opt_lib, "lib_prefix=s" => \$main::opt_lib_prefix, "functions!" => \$main::opt_functions, "lines!" => \$main::opt_lines, "addresses!" => \$main::opt_addresses, "files!" => \$main::opt_files, "text!" => \$main::opt_text, "callgrind!" => \$main::opt_callgrind, "list=s" => \$main::opt_list, "disasm=s" => \$main::opt_disasm, "symbols!" => \$main::opt_symbols, "gv!" => \$main::opt_gv, "evince!" => \$main::opt_evince, "web!" => \$main::opt_web, "dot!" => \$main::opt_dot, "ps!" => \$main::opt_ps, "pdf!" => \$main::opt_pdf, "svg!" => \$main::opt_svg, "gif!" => \$main::opt_gif, "raw!" => \$main::opt_raw, "interactive!" => \$main::opt_interactive, "nodecount=i" => \$main::opt_nodecount, "nodefraction=f" => \$main::opt_nodefraction, "edgefraction=f" => \$main::opt_edgefraction, "maxdegree=i" => \$main::opt_maxdegree, "focus=s" => \$main::opt_focus, "ignore=s" => \$main::opt_ignore, "scale=i" => \$main::opt_scale, "heapcheck" => \$main::opt_heapcheck, "inuse_space!" => \$main::opt_inuse_space, "inuse_objects!" => \$main::opt_inuse_objects, "alloc_space!" => \$main::opt_alloc_space, "alloc_objects!" => \$main::opt_alloc_objects, "show_bytes!" => \$main::opt_show_bytes, "drop_negative!" => \$main::opt_drop_negative, "total_delay!" => \$main::opt_total_delay, "contentions!" => \$main::opt_contentions, "mean_delay!" => \$main::opt_mean_delay, "tools=s" => \$main::opt_tools, "test!" => \$main::opt_test, "debug!" => \$main::opt_debug, # Undocumented flags used only by unittests: "test_stride=i" => \$main::opt_test_stride, ) || usage("Invalid option(s)"); # Deal with the standard --help and --version if ($main::opt_help) { print usage_string(); exit(0); } if ($main::opt_version) { print version_string(); exit(0); } # Disassembly/listing/symbols mode requires address-level info if ($main::opt_disasm || $main::opt_list || $main::opt_symbols) { $main::opt_functions = 0; $main::opt_lines = 0; $main::opt_addresses = 1; $main::opt_files = 0; } # Check heap-profiling flags if ($main::opt_inuse_space + $main::opt_inuse_objects + $main::opt_alloc_space + $main::opt_alloc_objects > 1) { usage("Specify at most on of --inuse/--alloc options"); } # Check output granularities my $grains = $main::opt_functions + $main::opt_lines + $main::opt_addresses + $main::opt_files + 0; if ($grains > 1) { usage("Only specify one output granularity option"); } if ($grains == 0) { $main::opt_functions = 1; } # Check output modes my $modes = $main::opt_text + $main::opt_callgrind + ($main::opt_list eq '' ? 0 : 1) + ($main::opt_disasm eq '' ? 0 : 1) + ($main::opt_symbols == 0 ? 0 : 1) + $main::opt_gv + $main::opt_evince + $main::opt_web + $main::opt_dot + $main::opt_ps + $main::opt_pdf + $main::opt_svg + $main::opt_gif + $main::opt_raw + $main::opt_interactive + 0; if ($modes > 1) { usage("Only specify one output mode"); } if ($modes == 0) { if (-t STDOUT) { # If STDOUT is a tty, activate interactive mode $main::opt_interactive = 1; } else { $main::opt_text = 1; } } if ($main::opt_test) { RunUnitTests(); # Should not return exit(1); } # Binary name and profile arguments list $main::prog = ""; @main::pfile_args = (); # Remote profiling without a binary (using $SYMBOL_PAGE instead) if (IsProfileURL($ARGV[0])) { $main::use_symbol_page = 1; } elsif (IsSymbolizedProfileFile($ARGV[0])) { $main::use_symbolized_profile = 1; $main::prog = $UNKNOWN_BINARY; # will be set later from the profile file } if ($main::use_symbol_page || $main::use_symbolized_profile) { # We don't need a binary! my %disabled = ('--lines' => $main::opt_lines, '--disasm' => $main::opt_disasm); for my $option (keys %disabled) { usage("$option cannot be used without a binary") if $disabled{$option}; } # Set $main::prog later... scalar(@ARGV) || usage("Did not specify profile file"); } elsif ($main::opt_symbols) { # --symbols needs a binary-name (to run nm on, etc) but not profiles $main::prog = shift(@ARGV) || usage("Did not specify program"); } else { $main::prog = shift(@ARGV) || usage("Did not specify program"); scalar(@ARGV) || usage("Did not specify profile file"); } # Parse profile file/location arguments foreach my $farg (@ARGV) { if ($farg =~ m/(.*)\@([0-9]+)(|\/.*)$/ ) { my $machine = $1; my $num_machines = $2; my $path = $3; for (my $i = 0; $i < $num_machines; $i++) { unshift(@main::pfile_args, "$i.$machine$path"); } } else { unshift(@main::pfile_args, $farg); } } if ($main::use_symbol_page) { unless (IsProfileURL($main::pfile_args[0])) { error("The first profile should be a remote form to use $SYMBOL_PAGE\n"); } CheckSymbolPage(); $main::prog = FetchProgramName(); } elsif (!$main::use_symbolized_profile) { # may not need objtools! ConfigureObjTools($main::prog) } # Break the opt_list_prefix into the prefix_list array @prefix_list = split (',', $main::opt_lib_prefix); # Remove trailing / from the prefixes, in the list to prevent # searching things like /my/path//lib/mylib.so foreach (@prefix_list) { s|/+$||; } } sub Main() { Init(); $main::collected_profile = undef; @main::profile_files = (); $main::op_time = time(); # Printing symbols is special and requires a lot less info that most. if ($main::opt_symbols) { PrintSymbols(*STDIN); # Get /proc/maps and symbols output from stdin return; } # Fetch all profile data FetchDynamicProfiles(); # this will hold symbols that we read from the profile files my $symbol_map = {}; # Read one profile, pick the last item on the list my $data = ReadProfile($main::prog, pop(@main::profile_files)); my $profile = $data->{profile}; my $pcs = $data->{pcs}; my $libs = $data->{libs}; # Info about main program and shared libraries $symbol_map = MergeSymbols($symbol_map, $data->{symbols}); # Add additional profiles, if available. if (scalar(@main::profile_files) > 0) { foreach my $pname (@main::profile_files) { my $data2 = ReadProfile($main::prog, $pname); $profile = AddProfile($profile, $data2->{profile}); $pcs = AddPcs($pcs, $data2->{pcs}); $symbol_map = MergeSymbols($symbol_map, $data2->{symbols}); } } # Subtract base from profile, if specified if ($main::opt_base ne '') { my $base = ReadProfile($main::prog, $main::opt_base); $profile = SubtractProfile($profile, $base->{profile}); $pcs = AddPcs($pcs, $base->{pcs}); $symbol_map = MergeSymbols($symbol_map, $base->{symbols}); } # Get total data in profile my $total = TotalProfile($profile); # Collect symbols my $symbols; if ($main::use_symbolized_profile) { $symbols = FetchSymbols($pcs, $symbol_map); } elsif ($main::use_symbol_page) { $symbols = FetchSymbols($pcs); } else { # TODO(csilvers): $libs uses the /proc/self/maps data from profile1, # which may differ from the data from subsequent profiles, especially # if they were run on different machines. Use appropriate libs for # each pc somehow. $symbols = ExtractSymbols($libs, $pcs); } # Remove uniniteresting stack items $profile = RemoveUninterestingFrames($symbols, $profile); # Focus? if ($main::opt_focus ne '') { $profile = FocusProfile($symbols, $profile, $main::opt_focus); } # Ignore? if ($main::opt_ignore ne '') { $profile = IgnoreProfile($symbols, $profile, $main::opt_ignore); } my $calls = ExtractCalls($symbols, $profile); # Reduce profiles to required output granularity, and also clean # each stack trace so a given entry exists at most once. my $reduced = ReduceProfile($symbols, $profile); # Get derived profiles my $flat = FlatProfile($reduced); my $cumulative = CumulativeProfile($reduced); # Print if (!$main::opt_interactive) { if ($main::opt_disasm) { PrintDisassembly($libs, $flat, $cumulative, $main::opt_disasm, $total); } elsif ($main::opt_list) { PrintListing($libs, $flat, $cumulative, $main::opt_list); } elsif ($main::opt_text) { # Make sure the output is empty when have nothing to report # (only matters when --heapcheck is given but we must be # compatible with old branches that did not pass --heapcheck always): if ($total != 0) { printf("Total: %s %s\n", Unparse($total), Units()); } PrintText($symbols, $flat, $cumulative, $total, -1); } elsif ($main::opt_raw) { PrintSymbolizedProfile($symbols, $profile, $main::prog); } elsif ($main::opt_callgrind) { PrintCallgrind($calls); } else { if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) { if ($main::opt_gv) { RunGV(TempName($main::next_tmpfile, "ps"), ""); } elsif ($main::opt_evince) { RunEvince(TempName($main::next_tmpfile, "pdf"), ""); } elsif ($main::opt_web) { my $tmp = TempName($main::next_tmpfile, "svg"); RunWeb($tmp); # The command we run might hand the file name off # to an already running browser instance and then exit. # Normally, we'd remove $tmp on exit (right now), # but fork a child to remove $tmp a little later, so that the # browser has time to load it first. delete $main::tempnames{$tmp}; if (fork() == 0) { sleep 5; unlink($tmp); exit(0); } } } else { cleanup(); exit(1); } } } else { InteractiveMode($profile, $symbols, $libs, $total); } cleanup(); exit(0); } ##### Entry Point ##### Main(); # Temporary code to detect if we're running on a Goobuntu system. # These systems don't have the right stuff installed for the special # Readline libraries to work, so as a temporary workaround, we default # to using the normal stdio code, rather than the fancier readline-based # code sub ReadlineMightFail { if (-e '/lib/libtermcap.so.2') { return 0; # libtermcap exists, so readline should be okay } else { return 1; } } sub RunGV { my $fname = shift; my $bg = shift; # "" or " &" if we should run in background if (!system("$GV --version >/dev/null 2>&1")) { # Options using double dash are supported by this gv version. # Also, turn on noantialias to better handle bug in gv for # postscript files with large dimensions. # TODO: Maybe we should not pass the --noantialias flag # if the gv version is known to work properly without the flag. system("$GV --scale=$main::opt_scale --noantialias " . $fname . $bg); } else { # Old gv version - only supports options that use single dash. print STDERR "$GV -scale $main::opt_scale\n"; system("$GV -scale $main::opt_scale " . $fname . $bg); } } sub RunEvince { my $fname = shift; my $bg = shift; # "" or " &" if we should run in background system("$EVINCE " . $fname . $bg); } sub RunWeb { my $fname = shift; print STDERR "Loading web page file:///$fname\n"; if (`uname` =~ /Darwin/) { # OS X: open will use standard preference for SVG files. system("/usr/bin/open", $fname); return; } # Some kind of Unix; try generic symlinks, then specific browsers. # (Stop once we find one.) # Works best if the browser is already running. my @alt = ( "/etc/alternatives/gnome-www-browser", "/etc/alternatives/x-www-browser", "google-chrome", "firefox", ); foreach my $b (@alt) { if (system($b, $fname) == 0) { return; } } print STDERR "Could not load web browser.\n"; } sub RunKcachegrind { my $fname = shift; my $bg = shift; # "" or " &" if we should run in background print STDERR "Starting '$KCACHEGRIND " . $fname . $bg . "'\n"; system("$KCACHEGRIND " . $fname . $bg); } ##### Interactive helper routines ##### sub InteractiveMode { $| = 1; # Make output unbuffered for interactive mode my ($orig_profile, $symbols, $libs, $total) = @_; print STDERR "Welcome to pprof! For help, type 'help'.\n"; # Use ReadLine if it's installed and input comes from a console. if ( -t STDIN && !ReadlineMightFail() && defined(eval {require Term::ReadLine}) ) { my $term = new Term::ReadLine 'pprof'; while ( defined ($_ = $term->readline('(pprof) '))) { $term->addhistory($_) if /\S/; if (!InteractiveCommand($orig_profile, $symbols, $libs, $total, $_)) { last; # exit when we get an interactive command to quit } } } else { # don't have readline while (1) { print STDERR "(pprof) "; $_ = ; last if ! defined $_ ; s/\r//g; # turn windows-looking lines into unix-looking lines # Save some flags that might be reset by InteractiveCommand() my $save_opt_lines = $main::opt_lines; if (!InteractiveCommand($orig_profile, $symbols, $libs, $total, $_)) { last; # exit when we get an interactive command to quit } # Restore flags $main::opt_lines = $save_opt_lines; } } } # Takes two args: orig profile, and command to run. # Returns 1 if we should keep going, or 0 if we were asked to quit sub InteractiveCommand { my($orig_profile, $symbols, $libs, $total, $command) = @_; $_ = $command; # just to make future m//'s easier if (!defined($_)) { print STDERR "\n"; return 0; } if (m/^\s*quit/) { return 0; } if (m/^\s*help/) { InteractiveHelpMessage(); return 1; } # Clear all the mode options -- mode is controlled by "$command" $main::opt_text = 0; $main::opt_callgrind = 0; $main::opt_disasm = 0; $main::opt_list = 0; $main::opt_gv = 0; $main::opt_evince = 0; $main::opt_cum = 0; if (m/^\s*(text|top)(\d*)\s*(.*)/) { $main::opt_text = 1; my $line_limit = ($2 ne "") ? int($2) : 10; my $routine; my $ignore; ($routine, $ignore) = ParseInteractiveArgs($3); my $profile = ProcessProfile($orig_profile, $symbols, "", $ignore); my $reduced = ReduceProfile($symbols, $profile); # Get derived profiles my $flat = FlatProfile($reduced); my $cumulative = CumulativeProfile($reduced); PrintText($symbols, $flat, $cumulative, $total, $line_limit); return 1; } if (m/^\s*callgrind\s*([^ \n]*)/) { $main::opt_callgrind = 1; # Get derived profiles my $calls = ExtractCalls($symbols, $orig_profile); my $filename = $1; if ( $1 eq '' ) { $filename = TempName($main::next_tmpfile, "callgrind"); } PrintCallgrind($calls, $filename); if ( $1 eq '' ) { RunKcachegrind($filename, " & "); $main::next_tmpfile++; } return 1; } if (m/^\s*list\s*(.+)/) { $main::opt_list = 1; my $routine; my $ignore; ($routine, $ignore) = ParseInteractiveArgs($1); my $profile = ProcessProfile($orig_profile, $symbols, "", $ignore); my $reduced = ReduceProfile($symbols, $profile); # Get derived profiles my $flat = FlatProfile($reduced); my $cumulative = CumulativeProfile($reduced); PrintListing($libs, $flat, $cumulative, $routine); return 1; } if (m/^\s*disasm\s*(.+)/) { $main::opt_disasm = 1; my $routine; my $ignore; ($routine, $ignore) = ParseInteractiveArgs($1); # Process current profile to account for various settings my $profile = ProcessProfile($orig_profile, $symbols, "", $ignore); my $reduced = ReduceProfile($symbols, $profile); # Get derived profiles my $flat = FlatProfile($reduced); my $cumulative = CumulativeProfile($reduced); PrintDisassembly($libs, $flat, $cumulative, $routine, $total); return 1; } if (m/^\s*(gv|web|evince)\s*(.*)/) { $main::opt_gv = 0; $main::opt_evince = 0; $main::opt_web = 0; if ($1 eq "gv") { $main::opt_gv = 1; } elsif ($1 eq "evince") { $main::opt_evince = 1; } elsif ($1 eq "web") { $main::opt_web = 1; } my $focus; my $ignore; ($focus, $ignore) = ParseInteractiveArgs($2); # Process current profile to account for various settings my $profile = ProcessProfile($orig_profile, $symbols, $focus, $ignore); my $reduced = ReduceProfile($symbols, $profile); # Get derived profiles my $flat = FlatProfile($reduced); my $cumulative = CumulativeProfile($reduced); if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) { if ($main::opt_gv) { RunGV(TempName($main::next_tmpfile, "ps"), " &"); } elsif ($main::opt_evince) { RunEvince(TempName($main::next_tmpfile, "pdf"), " &"); } elsif ($main::opt_web) { RunWeb(TempName($main::next_tmpfile, "svg")); } $main::next_tmpfile++; } return 1; } if (m/^\s*$/) { return 1; } print STDERR "Unknown command: try 'help'.\n"; return 1; } sub ProcessProfile { my $orig_profile = shift; my $symbols = shift; my $focus = shift; my $ignore = shift; # Process current profile to account for various settings my $profile = $orig_profile; my $total_count = TotalProfile($profile); printf("Total: %s %s\n", Unparse($total_count), Units()); if ($focus ne '') { $profile = FocusProfile($symbols, $profile, $focus); my $focus_count = TotalProfile($profile); printf("After focusing on '%s': %s %s of %s (%0.1f%%)\n", $focus, Unparse($focus_count), Units(), Unparse($total_count), ($focus_count*100.0) / $total_count); } if ($ignore ne '') { $profile = IgnoreProfile($symbols, $profile, $ignore); my $ignore_count = TotalProfile($profile); printf("After ignoring '%s': %s %s of %s (%0.1f%%)\n", $ignore, Unparse($ignore_count), Units(), Unparse($total_count), ($ignore_count*100.0) / $total_count); } return $profile; } sub InteractiveHelpMessage { print STDERR <{$k}; my @addrs = split(/\n/, $k); if ($#addrs >= 0) { my $depth = $#addrs + 1; # int(foo / 2**32) is the only reliable way to get rid of bottom # 32 bits on both 32- and 64-bit systems. print pack('L*', $count & 0xFFFFFFFF, int($count / 2**32)); print pack('L*', $depth & 0xFFFFFFFF, int($depth / 2**32)); foreach my $full_addr (@addrs) { my $addr = $full_addr; $addr =~ s/0x0*//; # strip off leading 0x, zeroes if (length($addr) > 16) { print STDERR "Invalid address in profile: $full_addr\n"; next; } my $low_addr = substr($addr, -8); # get last 8 hex chars my $high_addr = substr($addr, -16, 8); # get up to 8 more hex chars print pack('L*', hex('0x' . $low_addr), hex('0x' . $high_addr)); } } } } # Print symbols and profile data sub PrintSymbolizedProfile { my $symbols = shift; my $profile = shift; my $prog = shift; $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash my $symbol_marker = $&; print '--- ', $symbol_marker, "\n"; if (defined($prog)) { print 'binary=', $prog, "\n"; } while (my ($pc, $name) = each(%{$symbols})) { my $sep = ' '; print '0x', $pc; # We have a list of function names, which include the inlined # calls. They are separated (and terminated) by --, which is # illegal in function names. for (my $j = 2; $j <= $#{$name}; $j += 3) { print $sep, $name->[$j]; $sep = '--'; } print "\n"; } print '---', "\n"; $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash my $profile_marker = $&; print '--- ', $profile_marker, "\n"; if (defined($main::collected_profile)) { # if used with remote fetch, simply dump the collected profile to output. open(SRC, "<$main::collected_profile"); while () { print $_; } close(SRC); } else { # dump a cpu-format profile to standard out PrintProfileData($profile); } } # Print text output sub PrintText { my $symbols = shift; my $flat = shift; my $cumulative = shift; my $total = shift; my $line_limit = shift; # Which profile to sort by? my $s = $main::opt_cum ? $cumulative : $flat; my $running_sum = 0; my $lines = 0; foreach my $k (sort { GetEntry($s, $b) <=> GetEntry($s, $a) || $a cmp $b } keys(%{$cumulative})) { my $f = GetEntry($flat, $k); my $c = GetEntry($cumulative, $k); $running_sum += $f; my $sym = $k; if (exists($symbols->{$k})) { $sym = $symbols->{$k}->[0] . " " . $symbols->{$k}->[1]; if ($main::opt_addresses) { $sym = $k . " " . $sym; } } if ($f != 0 || $c != 0) { printf("%8s %6s %6s %8s %6s %s\n", Unparse($f), Percent($f, $total), Percent($running_sum, $total), Unparse($c), Percent($c, $total), $sym); } $lines++; last if ($line_limit >= 0 && $lines > $line_limit); } } # Print the call graph in a way that's suiteable for callgrind. sub PrintCallgrind { my $calls = shift; my $filename; if ($main::opt_interactive) { $filename = shift; print STDERR "Writing callgrind file to '$filename'.\n" } else { $filename = "&STDOUT"; } open(CG, ">".$filename ); printf CG ("events: Hits\n\n"); foreach my $call ( map { $_->[0] } sort { $a->[1] cmp $b ->[1] || $a->[2] <=> $b->[2] } map { /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/; [$_, $1, $2] } keys %$calls ) { my $count = int($calls->{$call}); $call =~ /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/; my ( $caller_file, $caller_line, $caller_function, $callee_file, $callee_line, $callee_function ) = ( $1, $2, $3, $5, $6, $7 ); printf CG ("fl=$caller_file\nfn=$caller_function\n"); if (defined $6) { printf CG ("cfl=$callee_file\n"); printf CG ("cfn=$callee_function\n"); printf CG ("calls=$count $callee_line\n"); } printf CG ("$caller_line $count\n\n"); } } # Print disassembly for all all routines that match $main::opt_disasm sub PrintDisassembly { my $libs = shift; my $flat = shift; my $cumulative = shift; my $disasm_opts = shift; my $total = shift; foreach my $lib (@{$libs}) { my $symbol_table = GetProcedureBoundaries($lib->[0], $disasm_opts); my $offset = AddressSub($lib->[1], $lib->[3]); foreach my $routine (sort ByName keys(%{$symbol_table})) { my $start_addr = $symbol_table->{$routine}->[0]; my $end_addr = $symbol_table->{$routine}->[1]; # See if there are any samples in this routine my $length = hex(AddressSub($end_addr, $start_addr)); my $addr = AddressAdd($start_addr, $offset); for (my $i = 0; $i < $length; $i++) { if (defined($cumulative->{$addr})) { PrintDisassembledFunction($lib->[0], $offset, $routine, $flat, $cumulative, $start_addr, $end_addr, $total); last; } $addr = AddressInc($addr); } } } } # Return reference to array of tuples of the form: # [start_address, filename, linenumber, instruction, limit_address] # E.g., # ["0x806c43d", "/foo/bar.cc", 131, "ret", "0x806c440"] sub Disassemble { my $prog = shift; my $offset = shift; my $start_addr = shift; my $end_addr = shift; my $objdump = $obj_tool_map{"objdump"}; my $cmd = sprintf("$objdump -C -d -l --no-show-raw-insn " . "--start-address=0x$start_addr " . "--stop-address=0x$end_addr $prog"); open(OBJDUMP, "$cmd |") || error("$objdump: $!\n"); my @result = (); my $filename = ""; my $linenumber = -1; my $last = ["", "", "", ""]; while () { s/\r//g; # turn windows-looking lines into unix-looking lines chop; if (m|\s*([^:\s]+):(\d+)\s*$|) { # Location line of the form: # : $filename = $1; $linenumber = $2; } elsif (m/^ +([0-9a-f]+):\s*(.*)/) { # Disassembly line -- zero-extend address to full length my $addr = HexExtend($1); my $k = AddressAdd($addr, $offset); $last->[4] = $k; # Store ending address for previous instruction $last = [$k, $filename, $linenumber, $2, $end_addr]; push(@result, $last); } } close(OBJDUMP); return @result; } # The input file should contain lines of the form /proc/maps-like # output (same format as expected from the profiles) or that looks # like hex addresses (like "0xDEADBEEF"). We will parse all # /proc/maps output, and for all the hex addresses, we will output # "short" symbol names, one per line, in the same order as the input. sub PrintSymbols { my $maps_and_symbols_file = shift; # ParseLibraries expects pcs to be in a set. Fine by us... my @pclist = (); # pcs in sorted order my $pcs = {}; my $map = ""; foreach my $line (<$maps_and_symbols_file>) { $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines if ($line =~ /\b(0x[0-9a-f]+)\b/i) { push(@pclist, HexExtend($1)); $pcs->{$pclist[-1]} = 1; } else { $map .= $line; } } my $libs = ParseLibraries($main::prog, $map, $pcs); my $symbols = ExtractSymbols($libs, $pcs); foreach my $pc (@pclist) { # ->[0] is the shortname, ->[2] is the full name print(($symbols->{$pc}->[0] || "??") . "\n"); } } # For sorting functions by name sub ByName { return ShortFunctionName($a) cmp ShortFunctionName($b); } # Print source-listing for all all routines that match $main::opt_list sub PrintListing { my $libs = shift; my $flat = shift; my $cumulative = shift; my $list_opts = shift; foreach my $lib (@{$libs}) { my $symbol_table = GetProcedureBoundaries($lib->[0], $list_opts); my $offset = AddressSub($lib->[1], $lib->[3]); foreach my $routine (sort ByName keys(%{$symbol_table})) { # Print if there are any samples in this routine my $start_addr = $symbol_table->{$routine}->[0]; my $end_addr = $symbol_table->{$routine}->[1]; my $length = hex(AddressSub($end_addr, $start_addr)); my $addr = AddressAdd($start_addr, $offset); for (my $i = 0; $i < $length; $i++) { if (defined($cumulative->{$addr})) { PrintSource($lib->[0], $offset, $routine, $flat, $cumulative, $start_addr, $end_addr); last; } $addr = AddressInc($addr); } } } } # Returns the indentation of the line, if it has any non-whitespace # characters. Otherwise, returns -1. sub Indentation { my $line = shift; if (m/^(\s*)\S/) { return length($1); } else { return -1; } } # Print source-listing for one routine sub PrintSource { my $prog = shift; my $offset = shift; my $routine = shift; my $flat = shift; my $cumulative = shift; my $start_addr = shift; my $end_addr = shift; # Disassemble all instructions (just to get line numbers) my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr); # Hack 1: assume that the first source file encountered in the # disassembly contains the routine my $filename = undef; for (my $i = 0; $i <= $#instructions; $i++) { if ($instructions[$i]->[2] >= 0) { $filename = $instructions[$i]->[1]; last; } } if (!defined($filename)) { print STDERR "no filename found in $routine\n"; return; } # Hack 2: assume that the largest line number from $filename is the # end of the procedure. This is typically safe since if P1 contains # an inlined call to P2, then P2 usually occurs earlier in the # source file. If this does not work, we might have to compute a # density profile or just print all regions we find. my $lastline = 0; for (my $i = 0; $i <= $#instructions; $i++) { my $f = $instructions[$i]->[1]; my $l = $instructions[$i]->[2]; if (($f eq $filename) && ($l > $lastline)) { $lastline = $l; } } # Hack 3: assume the first source location from "filename" is the start of # the source code. my $firstline = 1; for (my $i = 0; $i <= $#instructions; $i++) { if ($instructions[$i]->[1] eq $filename) { $firstline = $instructions[$i]->[2]; last; } } # Hack 4: Extend last line forward until its indentation is less than # the indentation we saw on $firstline my $oldlastline = $lastline; { if (!open(FILE, "<$filename")) { print STDERR "$filename: $!\n"; return; } my $l = 0; my $first_indentation = -1; while () { s/\r//g; # turn windows-looking lines into unix-looking lines $l++; my $indent = Indentation($_); if ($l >= $firstline) { if ($first_indentation < 0 && $indent >= 0) { $first_indentation = $indent; last if ($first_indentation == 0); } } if ($l >= $lastline && $indent >= 0) { if ($indent >= $first_indentation) { $lastline = $l+1; } else { last; } } } close(FILE); } # Assign all samples to the range $firstline,$lastline, # Hack 4: If an instruction does not occur in the range, its samples # are moved to the next instruction that occurs in the range. my $samples1 = {}; my $samples2 = {}; my $running1 = 0; # Unassigned flat counts my $running2 = 0; # Unassigned cumulative counts my $total1 = 0; # Total flat counts my $total2 = 0; # Total cumulative counts foreach my $e (@instructions) { # Add up counts for all address that fall inside this instruction my $c1 = 0; my $c2 = 0; for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) { $c1 += GetEntry($flat, $a); $c2 += GetEntry($cumulative, $a); } $running1 += $c1; $running2 += $c2; $total1 += $c1; $total2 += $c2; my $file = $e->[1]; my $line = $e->[2]; if (($file eq $filename) && ($line >= $firstline) && ($line <= $lastline)) { # Assign all accumulated samples to this line AddEntry($samples1, $line, $running1); AddEntry($samples2, $line, $running2); $running1 = 0; $running2 = 0; } } # Assign any leftover samples to $lastline AddEntry($samples1, $lastline, $running1); AddEntry($samples2, $lastline, $running2); printf("ROUTINE ====================== %s in %s\n" . "%6s %6s Total %s (flat / cumulative)\n", ShortFunctionName($routine), $filename, Units(), Unparse($total1), Unparse($total2)); if (!open(FILE, "<$filename")) { print STDERR "$filename: $!\n"; return; } my $l = 0; while () { s/\r//g; # turn windows-looking lines into unix-looking lines $l++; if ($l >= $firstline - 5 && (($l <= $oldlastline + 5) || ($l <= $lastline))) { chop; my $text = $_; if ($l == $firstline) { printf("---\n"); } printf("%6s %6s %4d: %s\n", UnparseAlt(GetEntry($samples1, $l)), UnparseAlt(GetEntry($samples2, $l)), $l, $text); if ($l == $lastline) { printf("---\n"); } }; } close(FILE); } # Return the source line for the specified file/linenumber. # Returns undef if not found. sub SourceLine { my $file = shift; my $line = shift; # Look in cache if (!defined($main::source_cache{$file})) { if (100 < scalar keys(%main::source_cache)) { # Clear the cache when it gets too big $main::source_cache = (); } # Read all lines from the file if (!open(FILE, "<$file")) { print STDERR "$file: $!\n"; $main::source_cache{$file} = []; # Cache the negative result return undef; } my $lines = []; push(@{$lines}, ""); # So we can use 1-based line numbers as indices while () { push(@{$lines}, $_); } close(FILE); # Save the lines in the cache $main::source_cache{$file} = $lines; } my $lines = $main::source_cache{$file}; if (($line < 0) || ($line > $#{$lines})) { return undef; } else { return $lines->[$line]; } } # Print disassembly for one routine with interspersed source if available sub PrintDisassembledFunction { my $prog = shift; my $offset = shift; my $routine = shift; my $flat = shift; my $cumulative = shift; my $start_addr = shift; my $end_addr = shift; my $total = shift; # Disassemble all instructions my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr); # Make array of counts per instruction my @flat_count = (); my @cum_count = (); my $flat_total = 0; my $cum_total = 0; foreach my $e (@instructions) { # Add up counts for all address that fall inside this instruction my $c1 = 0; my $c2 = 0; for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) { $c1 += GetEntry($flat, $a); $c2 += GetEntry($cumulative, $a); } push(@flat_count, $c1); push(@cum_count, $c2); $flat_total += $c1; $cum_total += $c2; } # Print header with total counts printf("ROUTINE ====================== %s\n" . "%6s %6s %s (flat, cumulative) %.1f%% of total\n", ShortFunctionName($routine), Unparse($flat_total), Unparse($cum_total), Units(), ($cum_total * 100.0) / $total); # Process instructions in order my $current_file = ""; for (my $i = 0; $i <= $#instructions; ) { my $e = $instructions[$i]; # Print the new file name whenever we switch files if ($e->[1] ne $current_file) { $current_file = $e->[1]; my $fname = $current_file; $fname =~ s|^\./||; # Trim leading "./" # Shorten long file names if (length($fname) >= 58) { $fname = "..." . substr($fname, -55); } printf("-------------------- %s\n", $fname); } # TODO: Compute range of lines to print together to deal with # small reorderings. my $first_line = $e->[2]; my $last_line = $first_line; my %flat_sum = (); my %cum_sum = (); for (my $l = $first_line; $l <= $last_line; $l++) { $flat_sum{$l} = 0; $cum_sum{$l} = 0; } # Find run of instructions for this range of source lines my $first_inst = $i; while (($i <= $#instructions) && ($instructions[$i]->[2] >= $first_line) && ($instructions[$i]->[2] <= $last_line)) { $e = $instructions[$i]; $flat_sum{$e->[2]} += $flat_count[$i]; $cum_sum{$e->[2]} += $cum_count[$i]; $i++; } my $last_inst = $i - 1; # Print source lines for (my $l = $first_line; $l <= $last_line; $l++) { my $line = SourceLine($current_file, $l); if (!defined($line)) { $line = "?\n"; next; } else { $line =~ s/^\s+//; } printf("%6s %6s %5d: %s", UnparseAlt($flat_sum{$l}), UnparseAlt($cum_sum{$l}), $l, $line); } # Print disassembly for (my $x = $first_inst; $x <= $last_inst; $x++) { my $e = $instructions[$x]; my $address = $e->[0]; $address = AddressSub($address, $offset); # Make relative to section $address =~ s/^0x//; $address =~ s/^0*//; # Trim symbols my $d = $e->[3]; while ($d =~ s/\([^()%]*\)(\s*const)?//g) { } # Argument types, not (%rax) while ($d =~ s/(\w+)<[^<>]*>/$1/g) { } # Remove template arguments printf("%6s %6s %8s: %6s\n", UnparseAlt($flat_count[$x]), UnparseAlt($cum_count[$x]), $address, $d); } } } # Print DOT graph sub PrintDot { my $prog = shift; my $symbols = shift; my $raw = shift; my $flat = shift; my $cumulative = shift; my $overall_total = shift; # Get total my $local_total = TotalProfile($flat); my $nodelimit = int($main::opt_nodefraction * $local_total); my $edgelimit = int($main::opt_edgefraction * $local_total); my $nodecount = $main::opt_nodecount; # Find nodes to include my @list = (sort { abs(GetEntry($cumulative, $b)) <=> abs(GetEntry($cumulative, $a)) || $a cmp $b } keys(%{$cumulative})); my $last = $nodecount - 1; if ($last > $#list) { $last = $#list; } while (($last >= 0) && (abs(GetEntry($cumulative, $list[$last])) <= $nodelimit)) { $last--; } if ($last < 0) { print STDERR "No nodes to print\n"; return 0; } if ($nodelimit > 0 || $edgelimit > 0) { printf STDERR ("Dropping nodes with <= %s %s; edges with <= %s abs(%s)\n", Unparse($nodelimit), Units(), Unparse($edgelimit), Units()); } # Open DOT output file my $output; if ($main::opt_gv) { $output = "| $DOT -Tps2 >" . TempName($main::next_tmpfile, "ps"); } elsif ($main::opt_evince) { $output = "| $DOT -Tps2 | $PS2PDF - " . TempName($main::next_tmpfile, "pdf"); } elsif ($main::opt_ps) { $output = "| $DOT -Tps2"; } elsif ($main::opt_pdf) { $output = "| $DOT -Tps2 | $PS2PDF - -"; } elsif ($main::opt_web || $main::opt_svg) { # We need to post-process the SVG, so write to a temporary file always. $output = "| $DOT -Tsvg >" . TempName($main::next_tmpfile, "svg"); } elsif ($main::opt_gif) { $output = "| $DOT -Tgif"; } else { $output = ">&STDOUT"; } open(DOT, $output) || error("$output: $!\n"); # Title printf DOT ("digraph \"%s; %s %s\" {\n", $prog, Unparse($overall_total), Units()); if ($main::opt_pdf) { # The output is more printable if we set the page size for dot. printf DOT ("size=\"8,11\"\n"); } printf DOT ("node [width=0.375,height=0.25];\n"); # Print legend printf DOT ("Legend [shape=box,fontsize=24,shape=plaintext," . "label=\"%s\\l%s\\l%s\\l%s\\l%s\\l\"];\n", $prog, sprintf("Total %s: %s", Units(), Unparse($overall_total)), sprintf("Focusing on: %s", Unparse($local_total)), sprintf("Dropped nodes with <= %s abs(%s)", Unparse($nodelimit), Units()), sprintf("Dropped edges with <= %s %s", Unparse($edgelimit), Units()) ); # Print nodes my %node = (); my $nextnode = 1; foreach my $a (@list[0..$last]) { # Pick font size my $f = GetEntry($flat, $a); my $c = GetEntry($cumulative, $a); my $fs = 8; if ($local_total > 0) { $fs = 8 + (50.0 * sqrt(abs($f * 1.0 / $local_total))); } $node{$a} = $nextnode++; my $sym = $a; $sym =~ s/\s+/\\n/g; $sym =~ s/::/\\n/g; # Extra cumulative info to print for non-leaves my $extra = ""; if ($f != $c) { $extra = sprintf("\\rof %s (%s)", Unparse($c), Percent($c, $overall_total)); } my $style = ""; if ($main::opt_heapcheck) { if ($f > 0) { # make leak-causing nodes more visible (add a background) $style = ",style=filled,fillcolor=gray" } elsif ($f < 0) { # make anti-leak-causing nodes (which almost never occur) # stand out as well (triple border) $style = ",peripheries=3" } } printf DOT ("N%d [label=\"%s\\n%s (%s)%s\\r" . "\",shape=box,fontsize=%.1f%s];\n", $node{$a}, $sym, Unparse($f), Percent($f, $overall_total), $extra, $fs, $style, ); } # Get edges and counts per edge my %edge = (); my $n; foreach my $k (keys(%{$raw})) { # TODO: omit low %age edges $n = $raw->{$k}; my @translated = TranslateStack($symbols, $k); for (my $i = 1; $i <= $#translated; $i++) { my $src = $translated[$i]; my $dst = $translated[$i-1]; #next if ($src eq $dst); # Avoid self-edges? if (exists($node{$src}) && exists($node{$dst})) { my $edge_label = "$src\001$dst"; if (!exists($edge{$edge_label})) { $edge{$edge_label} = 0; } $edge{$edge_label} += $n; } } } # Print edges (process in order of decreasing counts) my %indegree = (); # Number of incoming edges added per node so far my %outdegree = (); # Number of outgoing edges added per node so far foreach my $e (sort { $edge{$b} <=> $edge{$a} } keys(%edge)) { my @x = split(/\001/, $e); $n = $edge{$e}; # Initialize degree of kept incoming and outgoing edges if necessary my $src = $x[0]; my $dst = $x[1]; if (!exists($outdegree{$src})) { $outdegree{$src} = 0; } if (!exists($indegree{$dst})) { $indegree{$dst} = 0; } my $keep; if ($indegree{$dst} == 0) { # Keep edge if needed for reachability $keep = 1; } elsif (abs($n) <= $edgelimit) { # Drop if we are below --edgefraction $keep = 0; } elsif ($outdegree{$src} >= $main::opt_maxdegree || $indegree{$dst} >= $main::opt_maxdegree) { # Keep limited number of in/out edges per node $keep = 0; } else { $keep = 1; } if ($keep) { $outdegree{$src}++; $indegree{$dst}++; # Compute line width based on edge count my $fraction = abs($local_total ? (3 * ($n / $local_total)) : 0); if ($fraction > 1) { $fraction = 1; } my $w = $fraction * 2; if ($w < 1 && ($main::opt_web || $main::opt_svg)) { # SVG output treats line widths < 1 poorly. $w = 1; } # Dot sometimes segfaults if given edge weights that are too large, so # we cap the weights at a large value my $edgeweight = abs($n) ** 0.7; if ($edgeweight > 100000) { $edgeweight = 100000; } $edgeweight = int($edgeweight); my $style = sprintf("setlinewidth(%f)", $w); if ($x[1] =~ m/\(inline\)/) { $style .= ",dashed"; } # Use a slightly squashed function of the edge count as the weight printf DOT ("N%s -> N%s [label=%s, weight=%d, style=\"%s\"];\n", $node{$x[0]}, $node{$x[1]}, Unparse($n), $edgeweight, $style); } } print DOT ("}\n"); close(DOT); if ($main::opt_web || $main::opt_svg) { # Rewrite SVG to be more usable inside web browser. RewriteSvg(TempName($main::next_tmpfile, "svg")); } return 1; } sub RewriteSvg { my $svgfile = shift; open(SVG, $svgfile) || die "open temp svg: $!"; my @svg = ; close(SVG); unlink $svgfile; my $svg = join('', @svg); # Dot's SVG output is # # # # ... # # # # Change it to # # # $svg_javascript # # # ... # # # # Fix width, height; drop viewBox. $svg =~ s/(?s) above first my $svg_javascript = SvgJavascript(); my $viewport = "\n"; $svg =~ s/ above . $svg =~ s/(.*)(<\/svg>)/$1<\/g>$2/; $svg =~ s/$svgfile") || die "open $svgfile: $!"; print SVG $svg; close(SVG); } } sub SvgJavascript { return <<'EOF'; EOF } # Return a small number that identifies the argument. # Multiple calls with the same argument will return the same number. # Calls with different arguments will return different numbers. sub ShortIdFor { my $key = shift; my $id = $main::uniqueid{$key}; if (!defined($id)) { $id = keys(%main::uniqueid) + 1; $main::uniqueid{$key} = $id; } return $id; } # Translate a stack of addresses into a stack of symbols sub TranslateStack { my $symbols = shift; my $k = shift; my @addrs = split(/\n/, $k); my @result = (); for (my $i = 0; $i <= $#addrs; $i++) { my $a = $addrs[$i]; # Skip large addresses since they sometimes show up as fake entries on RH9 if (length($a) > 8 && $a gt "7fffffffffffffff") { next; } if ($main::opt_disasm || $main::opt_list) { # We want just the address for the key push(@result, $a); next; } my $symlist = $symbols->{$a}; if (!defined($symlist)) { $symlist = [$a, "", $a]; } # We can have a sequence of symbols for a particular entry # (more than one symbol in the case of inlining). Callers # come before callees in symlist, so walk backwards since # the translated stack should contain callees before callers. for (my $j = $#{$symlist}; $j >= 2; $j -= 3) { my $func = $symlist->[$j-2]; my $fileline = $symlist->[$j-1]; my $fullfunc = $symlist->[$j]; if ($j > 2) { $func = "$func (inline)"; } # Do not merge nodes corresponding to Callback::Run since that # causes confusing cycles in dot display. Instead, we synthesize # a unique name for this frame per caller. if ($func =~ m/Callback.*::Run$/) { my $caller = ($i > 0) ? $addrs[$i-1] : 0; $func = "Run#" . ShortIdFor($caller); } if ($main::opt_addresses) { push(@result, "$a $func $fileline"); } elsif ($main::opt_lines) { if ($func eq '??' && $fileline eq '??:0') { push(@result, "$a"); } else { push(@result, "$func $fileline"); } } elsif ($main::opt_functions) { if ($func eq '??') { push(@result, "$a"); } else { push(@result, $func); } } elsif ($main::opt_files) { if ($fileline eq '??:0' || $fileline eq '') { push(@result, "$a"); } else { my $f = $fileline; $f =~ s/:\d+$//; push(@result, $f); } } else { push(@result, $a); last; # Do not print inlined info } } } # print join(",", @addrs), " => ", join(",", @result), "\n"; return @result; } # Generate percent string for a number and a total sub Percent { my $num = shift; my $tot = shift; if ($tot != 0) { return sprintf("%.1f%%", $num * 100.0 / $tot); } else { return ($num == 0) ? "nan" : (($num > 0) ? "+inf" : "-inf"); } } # Generate pretty-printed form of number sub Unparse { my $num = shift; if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') { if ($main::opt_inuse_objects || $main::opt_alloc_objects) { return sprintf("%d", $num); } else { if ($main::opt_show_bytes) { return sprintf("%d", $num); } else { return sprintf("%.1f", $num / 1048576.0); } } } elsif ($main::profile_type eq 'contention' && !$main::opt_contentions) { return sprintf("%.3f", $num / 1e9); # Convert nanoseconds to seconds } else { return sprintf("%d", $num); } } # Alternate pretty-printed form: 0 maps to "." sub UnparseAlt { my $num = shift; if ($num == 0) { return "."; } else { return Unparse($num); } } # Return output units sub Units { if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') { if ($main::opt_inuse_objects || $main::opt_alloc_objects) { return "objects"; } else { if ($main::opt_show_bytes) { return "B"; } else { return "MB"; } } } elsif ($main::profile_type eq 'contention' && !$main::opt_contentions) { return "seconds"; } else { return "samples"; } } ##### Profile manipulation code ##### # Generate flattened profile: # If count is charged to stack [a,b,c,d], in generated profile, # it will be charged to [a] sub FlatProfile { my $profile = shift; my $result = {}; foreach my $k (keys(%{$profile})) { my $count = $profile->{$k}; my @addrs = split(/\n/, $k); if ($#addrs >= 0) { AddEntry($result, $addrs[0], $count); } } return $result; } # Generate cumulative profile: # If count is charged to stack [a,b,c,d], in generated profile, # it will be charged to [a], [b], [c], [d] sub CumulativeProfile { my $profile = shift; my $result = {}; foreach my $k (keys(%{$profile})) { my $count = $profile->{$k}; my @addrs = split(/\n/, $k); foreach my $a (@addrs) { AddEntry($result, $a, $count); } } return $result; } # If the second-youngest PC on the stack is always the same, returns # that pc. Otherwise, returns undef. sub IsSecondPcAlwaysTheSame { my $profile = shift; my $second_pc = undef; foreach my $k (keys(%{$profile})) { my @addrs = split(/\n/, $k); if ($#addrs < 1) { return undef; } if (not defined $second_pc) { $second_pc = $addrs[1]; } else { if ($second_pc ne $addrs[1]) { return undef; } } } return $second_pc; } sub ExtractSymbolLocation { my $symbols = shift; my $address = shift; # 'addr2line' outputs "??:0" for unknown locations; we do the # same to be consistent. my $location = "??:0:unknown"; if (exists $symbols->{$address}) { my $file = $symbols->{$address}->[1]; if ($file eq "?") { $file = "??:0" } $location = $file . ":" . $symbols->{$address}->[0]; } return $location; } # Extracts a graph of calls. sub ExtractCalls { my $symbols = shift; my $profile = shift; my $calls = {}; while( my ($stack_trace, $count) = each %$profile ) { my @address = split(/\n/, $stack_trace); my $destination = ExtractSymbolLocation($symbols, $address[0]); AddEntry($calls, $destination, $count); for (my $i = 1; $i <= $#address; $i++) { my $source = ExtractSymbolLocation($symbols, $address[$i]); my $call = "$source -> $destination"; AddEntry($calls, $call, $count); $destination = $source; } } return $calls; } sub RemoveUninterestingFrames { my $symbols = shift; my $profile = shift; # List of function names to skip my %skip = (); my $skip_regexp = 'NOMATCH'; if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') { foreach my $name ('calloc', 'cfree', 'malloc', 'free', 'memalign', 'posix_memalign', 'pvalloc', 'valloc', 'realloc', 'tc_calloc', 'tc_cfree', 'tc_malloc', 'tc_free', 'tc_memalign', 'tc_posix_memalign', 'tc_pvalloc', 'tc_valloc', 'tc_realloc', 'tc_new', 'tc_delete', 'tc_newarray', 'tc_deletearray', 'tc_new_nothrow', 'tc_newarray_nothrow', 'do_malloc', '::do_malloc', # new name -- got moved to an unnamed ns '::do_malloc_or_cpp_alloc', 'DoSampledAllocation', 'simple_alloc::allocate', '__malloc_alloc_template::allocate', '__builtin_delete', '__builtin_new', '__builtin_vec_delete', '__builtin_vec_new', 'operator new', 'operator new[]', # These mark the beginning/end of our custom sections '__start_google_malloc', '__stop_google_malloc', '__start_malloc_hook', '__stop_malloc_hook') { $skip{$name} = 1; $skip{"_" . $name} = 1; # Mach (OS X) adds a _ prefix to everything } # TODO: Remove TCMalloc once everything has been # moved into the tcmalloc:: namespace and we have flushed # old code out of the system. $skip_regexp = "TCMalloc|^tcmalloc::"; } elsif ($main::profile_type eq 'contention') { foreach my $vname ('base::RecordLockProfileData', 'base::SubmitMutexProfileData', 'base::SubmitSpinLockProfileData', 'Mutex::Unlock', 'Mutex::UnlockSlow', 'Mutex::ReaderUnlock', 'MutexLock::~MutexLock', 'SpinLock::Unlock', 'SpinLock::SlowUnlock', 'SpinLockHolder::~SpinLockHolder') { $skip{$vname} = 1; } } elsif ($main::profile_type eq 'cpu') { # Drop signal handlers used for CPU profile collection # TODO(dpeng): this should not be necessary; it's taken # care of by the general 2nd-pc mechanism below. foreach my $name ('ProfileData::Add', # historical 'ProfileData::prof_handler', # historical 'CpuProfiler::prof_handler', '__FRAME_END__', '__pthread_sighandler', '__restore') { $skip{$name} = 1; } } else { # Nothing skipped for unknown types } if ($main::profile_type eq 'cpu') { # If all the second-youngest program counters are the same, # this STRONGLY suggests that it is an artifact of measurement, # i.e., stack frames pushed by the CPU profiler signal handler. # Hence, we delete them. # (The topmost PC is read from the signal structure, not from # the stack, so it does not get involved.) while (my $second_pc = IsSecondPcAlwaysTheSame($profile)) { my $result = {}; my $func = ''; if (exists($symbols->{$second_pc})) { $second_pc = $symbols->{$second_pc}->[0]; } print STDERR "Removing $second_pc from all stack traces.\n"; foreach my $k (keys(%{$profile})) { my $count = $profile->{$k}; my @addrs = split(/\n/, $k); splice @addrs, 1, 1; my $reduced_path = join("\n", @addrs); AddEntry($result, $reduced_path, $count); } $profile = $result; } } my $result = {}; foreach my $k (keys(%{$profile})) { my $count = $profile->{$k}; my @addrs = split(/\n/, $k); my @path = (); foreach my $a (@addrs) { if (exists($symbols->{$a})) { my $func = $symbols->{$a}->[0]; if ($skip{$func} || ($func =~ m/$skip_regexp/)) { next; } } push(@path, $a); } my $reduced_path = join("\n", @path); AddEntry($result, $reduced_path, $count); } return $result; } # Reduce profile to granularity given by user sub ReduceProfile { my $symbols = shift; my $profile = shift; my $result = {}; foreach my $k (keys(%{$profile})) { my $count = $profile->{$k}; my @translated = TranslateStack($symbols, $k); my @path = (); my %seen = (); $seen{''} = 1; # So that empty keys are skipped foreach my $e (@translated) { # To avoid double-counting due to recursion, skip a stack-trace # entry if it has already been seen if (!$seen{$e}) { $seen{$e} = 1; push(@path, $e); } } my $reduced_path = join("\n", @path); AddEntry($result, $reduced_path, $count); } return $result; } # Does the specified symbol array match the regexp? sub SymbolMatches { my $sym = shift; my $re = shift; if (defined($sym)) { for (my $i = 0; $i < $#{$sym}; $i += 3) { if ($sym->[$i] =~ m/$re/ || $sym->[$i+1] =~ m/$re/) { return 1; } } } return 0; } # Focus only on paths involving specified regexps sub FocusProfile { my $symbols = shift; my $profile = shift; my $focus = shift; my $result = {}; foreach my $k (keys(%{$profile})) { my $count = $profile->{$k}; my @addrs = split(/\n/, $k); foreach my $a (@addrs) { # Reply if it matches either the address/shortname/fileline if (($a =~ m/$focus/) || SymbolMatches($symbols->{$a}, $focus)) { AddEntry($result, $k, $count); last; } } } return $result; } # Focus only on paths not involving specified regexps sub IgnoreProfile { my $symbols = shift; my $profile = shift; my $ignore = shift; my $result = {}; foreach my $k (keys(%{$profile})) { my $count = $profile->{$k}; my @addrs = split(/\n/, $k); my $matched = 0; foreach my $a (@addrs) { # Reply if it matches either the address/shortname/fileline if (($a =~ m/$ignore/) || SymbolMatches($symbols->{$a}, $ignore)) { $matched = 1; last; } } if (!$matched) { AddEntry($result, $k, $count); } } return $result; } # Get total count in profile sub TotalProfile { my $profile = shift; my $result = 0; foreach my $k (keys(%{$profile})) { $result += $profile->{$k}; } return $result; } # Add A to B sub AddProfile { my $A = shift; my $B = shift; my $R = {}; # add all keys in A foreach my $k (keys(%{$A})) { my $v = $A->{$k}; AddEntry($R, $k, $v); } # add all keys in B foreach my $k (keys(%{$B})) { my $v = $B->{$k}; AddEntry($R, $k, $v); } return $R; } # Merges symbol maps sub MergeSymbols { my $A = shift; my $B = shift; my $R = {}; foreach my $k (keys(%{$A})) { $R->{$k} = $A->{$k}; } if (defined($B)) { foreach my $k (keys(%{$B})) { $R->{$k} = $B->{$k}; } } return $R; } # Add A to B sub AddPcs { my $A = shift; my $B = shift; my $R = {}; # add all keys in A foreach my $k (keys(%{$A})) { $R->{$k} = 1 } # add all keys in B foreach my $k (keys(%{$B})) { $R->{$k} = 1 } return $R; } # Subtract B from A sub SubtractProfile { my $A = shift; my $B = shift; my $R = {}; foreach my $k (keys(%{$A})) { my $v = $A->{$k} - GetEntry($B, $k); if ($v < 0 && $main::opt_drop_negative) { $v = 0; } AddEntry($R, $k, $v); } if (!$main::opt_drop_negative) { # Take care of when subtracted profile has more entries foreach my $k (keys(%{$B})) { if (!exists($A->{$k})) { AddEntry($R, $k, 0 - $B->{$k}); } } } return $R; } # Get entry from profile; zero if not present sub GetEntry { my $profile = shift; my $k = shift; if (exists($profile->{$k})) { return $profile->{$k}; } else { return 0; } } # Add entry to specified profile sub AddEntry { my $profile = shift; my $k = shift; my $n = shift; if (!exists($profile->{$k})) { $profile->{$k} = 0; } $profile->{$k} += $n; } # Add a stack of entries to specified profile, and add them to the $pcs # list. sub AddEntries { my $profile = shift; my $pcs = shift; my $stack = shift; my $count = shift; my @k = (); foreach my $e (split(/\s+/, $stack)) { my $pc = HexExtend($e); $pcs->{$pc} = 1; push @k, $pc; } AddEntry($profile, (join "\n", @k), $count); } ##### Code to profile a server dynamically ##### sub CheckSymbolPage { my $url = SymbolPageURL(); open(SYMBOL, "$URL_FETCHER '$url' |"); my $line = ; $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines close(SYMBOL); unless (defined($line)) { error("$url doesn't exist\n"); } if ($line =~ /^num_symbols:\s+(\d+)$/) { if ($1 == 0) { error("Stripped binary. No symbols available.\n"); } } else { error("Failed to get the number of symbols from $url\n"); } } sub IsProfileURL { my $profile_name = shift; if (-f $profile_name) { printf STDERR "Using local file $profile_name.\n"; return 0; } return 1; } sub ParseProfileURL { my $profile_name = shift; if (!defined($profile_name) || $profile_name eq "") { return (); } # Split profile URL - matches all non-empty strings, so no test. $profile_name =~ m,^(https?://)?([^/]+)(.*?)(/|$PROFILES)?$,; my $proto = $1 || "http://"; my $hostport = $2; my $prefix = $3; my $profile = $4 || "/"; my $host = $hostport; $host =~ s/:.*//; my $baseurl = "$proto$hostport$prefix"; return ($host, $baseurl, $profile); } # We fetch symbols from the first profile argument. sub SymbolPageURL { my ($host, $baseURL, $path) = ParseProfileURL($main::pfile_args[0]); return "$baseURL$SYMBOL_PAGE"; } sub FetchProgramName() { my ($host, $baseURL, $path) = ParseProfileURL($main::pfile_args[0]); my $url = "$baseURL$PROGRAM_NAME_PAGE"; my $command_line = "$URL_FETCHER '$url'"; open(CMDLINE, "$command_line |") or error($command_line); my $cmdline = ; $cmdline =~ s/\r//g; # turn windows-looking lines into unix-looking lines close(CMDLINE); error("Failed to get program name from $url\n") unless defined($cmdline); $cmdline =~ s/\x00.+//; # Remove argv[1] and latters. $cmdline =~ s!\n!!g; # Remove LFs. return $cmdline; } # Gee, curl's -L (--location) option isn't reliable at least # with its 7.12.3 version. Curl will forget to post data if # there is a redirection. This function is a workaround for # curl. Redirection happens on borg hosts. sub ResolveRedirectionForCurl { my $url = shift; my $command_line = "$URL_FETCHER --head '$url'"; open(CMDLINE, "$command_line |") or error($command_line); while () { s/\r//g; # turn windows-looking lines into unix-looking lines if (/^Location: (.*)/) { $url = $1; } } close(CMDLINE); return $url; } # Add a timeout flat to URL_FETCHER sub AddFetchTimeout { my $fetcher = shift; my $timeout = shift; if (defined($timeout)) { if ($fetcher =~ m/\bcurl -s/) { $fetcher .= sprintf(" --max-time %d", $timeout); } elsif ($fetcher =~ m/\brpcget\b/) { $fetcher .= sprintf(" --deadline=%d", $timeout); } } return $fetcher; } # Reads a symbol map from the file handle name given as $1, returning # the resulting symbol map. Also processes variables relating to symbols. # Currently, the only variable processed is 'binary=' which updates # $main::prog to have the correct program name. sub ReadSymbols { my $in = shift; my $map = {}; while (<$in>) { s/\r//g; # turn windows-looking lines into unix-looking lines # Removes all the leading zeroes from the symbols, see comment below. if (m/^0x0*([0-9a-f]+)\s+(.+)/) { $map->{$1} = $2; } elsif (m/^---/) { last; } elsif (m/^([a-z][^=]*)=(.*)$/ ) { my ($variable, $value) = ($1, $2); for ($variable, $value) { s/^\s+//; s/\s+$//; } if ($variable eq "binary") { if ($main::prog ne $UNKNOWN_BINARY && $main::prog ne $value) { printf STDERR ("Warning: Mismatched binary name '%s', using '%s'.\n", $main::prog, $value); } $main::prog = $value; } else { printf STDERR ("Ignoring unknown variable in symbols list: " . "'%s' = '%s'\n", $variable, $value); } } } return $map; } # Fetches and processes symbols to prepare them for use in the profile output # code. If the optional 'symbol_map' arg is not given, fetches symbols from # $SYMBOL_PAGE for all PC values found in profile. Otherwise, the raw symbols # are assumed to have already been fetched into 'symbol_map' and are simply # extracted and processed. sub FetchSymbols { my $pcset = shift; my $symbol_map = shift; my %seen = (); my @pcs = grep { !$seen{$_}++ } keys(%$pcset); # uniq if (!defined($symbol_map)) { my $post_data = join("+", sort((map {"0x" . "$_"} @pcs))); open(POSTFILE, ">$main::tmpfile_sym"); print POSTFILE $post_data; close(POSTFILE); my $url = SymbolPageURL(); my $command_line; if ($URL_FETCHER =~ m/\bcurl -s/) { $url = ResolveRedirectionForCurl($url); $command_line = "$URL_FETCHER -d '\@$main::tmpfile_sym' '$url'"; } else { $command_line = "$URL_FETCHER --post '$url' < '$main::tmpfile_sym'"; } # We use c++filt in case $SYMBOL_PAGE gives us mangled symbols. my $cppfilt = $obj_tool_map{"c++filt"}; open(SYMBOL, "$command_line | $cppfilt |") or error($command_line); $symbol_map = ReadSymbols(*SYMBOL{IO}); close(SYMBOL); } my $symbols = {}; foreach my $pc (@pcs) { my $fullname; # For 64 bits binaries, symbols are extracted with 8 leading zeroes. # Then /symbol reads the long symbols in as uint64, and outputs # the result with a "0x%08llx" format which get rid of the zeroes. # By removing all the leading zeroes in both $pc and the symbols from # /symbol, the symbols match and are retrievable from the map. my $shortpc = $pc; $shortpc =~ s/^0*//; # Each line may have a list of names, which includes the function # and also other functions it has inlined. They are separated # (in PrintSymbolizedFile), by --, which is illegal in function names. my $fullnames; if (defined($symbol_map->{$shortpc})) { $fullnames = $symbol_map->{$shortpc}; } else { $fullnames = "0x" . $pc; # Just use addresses } my $sym = []; $symbols->{$pc} = $sym; foreach my $fullname (split("--", $fullnames)) { my $name = ShortFunctionName($fullname); push(@{$sym}, $name, "?", $fullname); } } return $symbols; } sub BaseName { my $file_name = shift; $file_name =~ s!^.*/!!; # Remove directory name return $file_name; } sub MakeProfileBaseName { my ($binary_name, $profile_name) = @_; my ($host, $baseURL, $path) = ParseProfileURL($profile_name); my $binary_shortname = BaseName($binary_name); return sprintf("%s.%s.%s", $binary_shortname, $main::op_time, $host); } sub FetchDynamicProfile { my $binary_name = shift; my $profile_name = shift; my $fetch_name_only = shift; my $encourage_patience = shift; if (!IsProfileURL($profile_name)) { return $profile_name; } else { my ($host, $baseURL, $path) = ParseProfileURL($profile_name); if ($path eq "" || $path eq "/") { # Missing type specifier defaults to cpu-profile $path = $PROFILE_PAGE; } my $profile_file = MakeProfileBaseName($binary_name, $profile_name); my $url = "$baseURL$path"; my $fetch_timeout = undef; if ($path =~ m/$PROFILE_PAGE|$PMUPROFILE_PAGE/) { if ($path =~ m/[?]/) { $url .= "&"; } else { $url .= "?"; } $url .= sprintf("seconds=%d", $main::opt_seconds); $fetch_timeout = $main::opt_seconds * 1.01 + 60; } else { # For non-CPU profiles, we add a type-extension to # the target profile file name. my $suffix = $path; $suffix =~ s,/,.,g; $profile_file .= $suffix; } my $profile_dir = $ENV{"PPROF_TMPDIR"} || ($ENV{HOME} . "/pprof"); if (! -d $profile_dir) { mkdir($profile_dir) || die("Unable to create profile directory $profile_dir: $!\n"); } my $tmp_profile = "$profile_dir/.tmp.$profile_file"; my $real_profile = "$profile_dir/$profile_file"; if ($fetch_name_only > 0) { return $real_profile; } my $fetcher = AddFetchTimeout($URL_FETCHER, $fetch_timeout); my $cmd = "$fetcher '$url' > '$tmp_profile'"; if ($path =~ m/$PROFILE_PAGE|$PMUPROFILE_PAGE|$CENSUSPROFILE_PAGE/){ print STDERR "Gathering CPU profile from $url for $main::opt_seconds seconds to\n ${real_profile}\n"; if ($encourage_patience) { print STDERR "Be patient...\n"; } } else { print STDERR "Fetching $path profile from $url to\n ${real_profile}\n"; } (system($cmd) == 0) || error("Failed to get profile: $cmd: $!\n"); (system("mv $tmp_profile $real_profile") == 0) || error("Unable to rename profile\n"); print STDERR "Wrote profile to $real_profile\n"; $main::collected_profile = $real_profile; return $main::collected_profile; } } # Collect profiles in parallel sub FetchDynamicProfiles { my $items = scalar(@main::pfile_args); my $levels = log($items) / log(2); if ($items == 1) { $main::profile_files[0] = FetchDynamicProfile($main::prog, $main::pfile_args[0], 0, 1); } else { # math rounding issues if ((2 ** $levels) < $items) { $levels++; } my $count = scalar(@main::pfile_args); for (my $i = 0; $i < $count; $i++) { $main::profile_files[$i] = FetchDynamicProfile($main::prog, $main::pfile_args[$i], 1, 0); } print STDERR "Fetching $count profiles, Be patient...\n"; FetchDynamicProfilesRecurse($levels, 0, 0); $main::collected_profile = join(" \\\n ", @main::profile_files); } } # Recursively fork a process to get enough processes # collecting profiles sub FetchDynamicProfilesRecurse { my $maxlevel = shift; my $level = shift; my $position = shift; if (my $pid = fork()) { $position = 0 | ($position << 1); TryCollectProfile($maxlevel, $level, $position); wait; } else { $position = 1 | ($position << 1); TryCollectProfile($maxlevel, $level, $position); cleanup(); exit(0); } } # Collect a single profile sub TryCollectProfile { my $maxlevel = shift; my $level = shift; my $position = shift; if ($level >= ($maxlevel - 1)) { if ($position < scalar(@main::pfile_args)) { FetchDynamicProfile($main::prog, $main::pfile_args[$position], 0, 0); } } else { FetchDynamicProfilesRecurse($maxlevel, $level+1, $position); } } ##### Parsing code ##### # Provide a small streaming-read module to handle very large # cpu-profile files. Stream in chunks along a sliding window. # Provides an interface to get one 'slot', correctly handling # endian-ness differences. A slot is one 32-bit or 64-bit word # (depending on the input profile). We tell endianness and bit-size # for the profile by looking at the first 8 bytes: in cpu profiles, # the second slot is always 3 (we'll accept anything that's not 0). BEGIN { package CpuProfileStream; sub new { my ($class, $file, $fname) = @_; my $self = { file => $file, base => 0, stride => 512 * 1024, # must be a multiple of bitsize/8 slots => [], unpack_code => "", # N for big-endian, V for little perl_is_64bit => 1, # matters if profile is 64-bit }; bless $self, $class; # Let unittests adjust the stride if ($main::opt_test_stride > 0) { $self->{stride} = $main::opt_test_stride; } # Read the first two slots to figure out bitsize and endianness. my $slots = $self->{slots}; my $str; read($self->{file}, $str, 8); # Set the global $address_length based on what we see here. # 8 is 32-bit (8 hexadecimal chars); 16 is 64-bit (16 hexadecimal chars). $address_length = ($str eq (chr(0)x8)) ? 16 : 8; if ($address_length == 8) { if (substr($str, 6, 2) eq chr(0)x2) { $self->{unpack_code} = 'V'; # Little-endian. } elsif (substr($str, 4, 2) eq chr(0)x2) { $self->{unpack_code} = 'N'; # Big-endian } else { ::error("$fname: header size >= 2**16\n"); } @$slots = unpack($self->{unpack_code} . "*", $str); } else { # If we're a 64-bit profile, check if we're a 64-bit-capable # perl. Otherwise, each slot will be represented as a float # instead of an int64, losing precision and making all the # 64-bit addresses wrong. We won't complain yet, but will # later if we ever see a value that doesn't fit in 32 bits. my $has_q = 0; eval { $has_q = pack("Q", "1") ? 1 : 1; }; if (!$has_q) { $self->{perl_is_64bit} = 0; } read($self->{file}, $str, 8); if (substr($str, 4, 4) eq chr(0)x4) { # We'd love to use 'Q', but it's a) not universal, b) not endian-proof. $self->{unpack_code} = 'V'; # Little-endian. } elsif (substr($str, 0, 4) eq chr(0)x4) { $self->{unpack_code} = 'N'; # Big-endian } else { ::error("$fname: header size >= 2**32\n"); } my @pair = unpack($self->{unpack_code} . "*", $str); # Since we know one of the pair is 0, it's fine to just add them. @$slots = (0, $pair[0] + $pair[1]); } return $self; } # Load more data when we access slots->get(X) which is not yet in memory. sub overflow { my ($self) = @_; my $slots = $self->{slots}; $self->{base} += $#$slots + 1; # skip over data we're replacing my $str; read($self->{file}, $str, $self->{stride}); if ($address_length == 8) { # the 32-bit case # This is the easy case: unpack provides 32-bit unpacking primitives. @$slots = unpack($self->{unpack_code} . "*", $str); } else { # We need to unpack 32 bits at a time and combine. my @b32_values = unpack($self->{unpack_code} . "*", $str); my @b64_values = (); for (my $i = 0; $i < $#b32_values; $i += 2) { # TODO(csilvers): if this is a 32-bit perl, the math below # could end up in a too-large int, which perl will promote # to a double, losing necessary precision. Deal with that. # Right now, we just die. my ($lo, $hi) = ($b32_values[$i], $b32_values[$i+1]); if ($self->{unpack_code} eq 'N') { # big-endian ($lo, $hi) = ($hi, $lo); } my $value = $lo + $hi * (2**32); if (!$self->{perl_is_64bit} && # check value is exactly represented (($value % (2**32)) != $lo || int($value / (2**32)) != $hi)) { ::error("Need a 64-bit perl to process this 64-bit profile.\n"); } push(@b64_values, $value); } @$slots = @b64_values; } } # Access the i-th long in the file (logically), or -1 at EOF. sub get { my ($self, $idx) = @_; my $slots = $self->{slots}; while ($#$slots >= 0) { if ($idx < $self->{base}) { # The only time we expect a reference to $slots[$i - something] # after referencing $slots[$i] is reading the very first header. # Since $stride > |header|, that shouldn't cause any lookback # errors. And everything after the header is sequential. print STDERR "Unexpected look-back reading CPU profile"; return -1; # shrug, don't know what better to return } elsif ($idx > $self->{base} + $#$slots) { $self->overflow(); } else { return $slots->[$idx - $self->{base}]; } } # If we get here, $slots is [], which means we've reached EOF return -1; # unique since slots is supposed to hold unsigned numbers } } # Reads the top, 'header' section of a profile, and returns the last # line of the header, commonly called a 'header line'. The header # section of a profile consists of zero or more 'command' lines that # are instructions to pprof, which pprof executes when reading the # header. All 'command' lines start with a %. After the command # lines is the 'header line', which is a profile-specific line that # indicates what type of profile it is, and perhaps other global # information about the profile. For instance, here's a header line # for a heap profile: # heap profile: 53: 38236 [ 5525: 1284029] @ heapprofile # For historical reasons, the CPU profile does not contain a text- # readable header line. If the profile looks like a CPU profile, # this function returns "". If no header line could be found, this # function returns undef. # # The following commands are recognized: # %warn -- emit the rest of this line to stderr, prefixed by 'WARNING:' # # The input file should be in binmode. sub ReadProfileHeader { local *PROFILE = shift; my $firstchar = ""; my $line = ""; read(PROFILE, $firstchar, 1); seek(PROFILE, -1, 1); # unread the firstchar if ($firstchar !~ /[[:print:]]/) { # is not a text character return ""; } while (defined($line = )) { $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines if ($line =~ /^%warn\s+(.*)/) { # 'warn' command # Note this matches both '%warn blah\n' and '%warn\n'. print STDERR "WARNING: $1\n"; # print the rest of the line } elsif ($line =~ /^%/) { print STDERR "Ignoring unknown command from profile header: $line"; } else { # End of commands, must be the header line. return $line; } } return undef; # got to EOF without seeing a header line } sub IsSymbolizedProfileFile { my $file_name = shift; if (!(-e $file_name) || !(-r $file_name)) { return 0; } # Check if the file contains a symbol-section marker. open(TFILE, "<$file_name"); binmode TFILE; my $firstline = ReadProfileHeader(*TFILE); close(TFILE); if (!$firstline) { return 0; } $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash my $symbol_marker = $&; return $firstline =~ /^--- *$symbol_marker/; } # Parse profile generated by common/profiler.cc and return a reference # to a map: # $result->{version} Version number of profile file # $result->{period} Sampling period (in microseconds) # $result->{profile} Profile object # $result->{map} Memory map info from profile # $result->{pcs} Hash of all PC values seen, key is hex address sub ReadProfile { my $prog = shift; my $fname = shift; my $result; # return value $CONTENTION_PAGE =~ m,[^/]+$,; # matches everything after the last slash my $contention_marker = $&; $GROWTH_PAGE =~ m,[^/]+$,; # matches everything after the last slash my $growth_marker = $&; $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash my $symbol_marker = $&; $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash my $profile_marker = $&; # Look at first line to see if it is a heap or a CPU profile. # CPU profile may start with no header at all, and just binary data # (starting with \0\0\0\0) -- in that case, don't try to read the # whole firstline, since it may be gigabytes(!) of data. open(PROFILE, "<$fname") || error("$fname: $!\n"); binmode PROFILE; # New perls do UTF-8 processing my $header = ReadProfileHeader(*PROFILE); if (!defined($header)) { # means "at EOF" error("Profile is empty.\n"); } my $symbols; if ($header =~ m/^--- *$symbol_marker/o) { # Verify that the user asked for a symbolized profile if (!$main::use_symbolized_profile) { # we have both a binary and symbolized profiles, abort error("FATAL ERROR: Symbolized profile\n $fname\ncannot be used with " . "a binary arg. Try again without passing\n $prog\n"); } # Read the symbol section of the symbolized profile file. $symbols = ReadSymbols(*PROFILE{IO}); # Read the next line to get the header for the remaining profile. $header = ReadProfileHeader(*PROFILE) || ""; } $main::profile_type = ''; if ($header =~ m/^heap profile:.*$growth_marker/o) { $main::profile_type = 'growth'; $result = ReadHeapProfile($prog, *PROFILE, $header); } elsif ($header =~ m/^heap profile:/) { $main::profile_type = 'heap'; $result = ReadHeapProfile($prog, *PROFILE, $header); } elsif ($header =~ m/^--- *$contention_marker/o) { $main::profile_type = 'contention'; $result = ReadSynchProfile($prog, *PROFILE); } elsif ($header =~ m/^--- *Stacks:/) { print STDERR "Old format contention profile: mistakenly reports " . "condition variable signals as lock contentions.\n"; $main::profile_type = 'contention'; $result = ReadSynchProfile($prog, *PROFILE); } elsif ($header =~ m/^--- *$profile_marker/) { # the binary cpu profile data starts immediately after this line $main::profile_type = 'cpu'; $result = ReadCPUProfile($prog, $fname, *PROFILE); } else { if (defined($symbols)) { # a symbolized profile contains a format we don't recognize, bail out error("$fname: Cannot recognize profile section after symbols.\n"); } # no ascii header present -- must be a CPU profile $main::profile_type = 'cpu'; $result = ReadCPUProfile($prog, $fname, *PROFILE); } close(PROFILE); # if we got symbols along with the profile, return those as well if (defined($symbols)) { $result->{symbols} = $symbols; } return $result; } # Subtract one from caller pc so we map back to call instr. # However, don't do this if we're reading a symbolized profile # file, in which case the subtract-one was done when the file # was written. # # We apply the same logic to all readers, though ReadCPUProfile uses an # independent implementation. sub FixCallerAddresses { my $stack = shift; if ($main::use_symbolized_profile) { return $stack; } else { $stack =~ /(\s)/; my $delimiter = $1; my @addrs = split(' ', $stack); my @fixedaddrs; $#fixedaddrs = $#addrs; if ($#addrs >= 0) { $fixedaddrs[0] = $addrs[0]; } for (my $i = 1; $i <= $#addrs; $i++) { $fixedaddrs[$i] = AddressSub($addrs[$i], "0x1"); } return join $delimiter, @fixedaddrs; } } # CPU profile reader sub ReadCPUProfile { my $prog = shift; my $fname = shift; # just used for logging local *PROFILE = shift; my $version; my $period; my $i; my $profile = {}; my $pcs = {}; # Parse string into array of slots. my $slots = CpuProfileStream->new(*PROFILE, $fname); # Read header. The current header version is a 5-element structure # containing: # 0: header count (always 0) # 1: header "words" (after this one: 3) # 2: format version (0) # 3: sampling period (usec) # 4: unused padding (always 0) if ($slots->get(0) != 0 ) { error("$fname: not a profile file, or old format profile file\n"); } $i = 2 + $slots->get(1); $version = $slots->get(2); $period = $slots->get(3); # Do some sanity checking on these header values. if ($version > (2**32) || $period > (2**32) || $i > (2**32) || $i < 5) { error("$fname: not a profile file, or corrupted profile file\n"); } # Parse profile while ($slots->get($i) != -1) { my $n = $slots->get($i++); my $d = $slots->get($i++); if ($d > (2**16)) { # TODO(csilvers): what's a reasonable max-stack-depth? my $addr = sprintf("0%o", $i * ($address_length == 8 ? 4 : 8)); print STDERR "At index $i (address $addr):\n"; error("$fname: stack trace depth >= 2**32\n"); } if ($slots->get($i) == 0) { # End of profile data marker $i += $d; last; } # Make key out of the stack entries my @k = (); for (my $j = 0; $j < $d; $j++) { my $pc = $slots->get($i+$j); # Subtract one from caller pc so we map back to call instr. # However, don't do this if we're reading a symbolized profile # file, in which case the subtract-one was done when the file # was written. if ($j > 0 && !$main::use_symbolized_profile) { $pc--; } $pc = sprintf("%0*x", $address_length, $pc); $pcs->{$pc} = 1; push @k, $pc; } AddEntry($profile, (join "\n", @k), $n); $i += $d; } # Parse map my $map = ''; seek(PROFILE, $i * 4, 0); read(PROFILE, $map, (stat PROFILE)[7]); my $r = {}; $r->{version} = $version; $r->{period} = $period; $r->{profile} = $profile; $r->{libs} = ParseLibraries($prog, $map, $pcs); $r->{pcs} = $pcs; return $r; } sub ReadHeapProfile { my $prog = shift; local *PROFILE = shift; my $header = shift; my $index = 1; if ($main::opt_inuse_space) { $index = 1; } elsif ($main::opt_inuse_objects) { $index = 0; } elsif ($main::opt_alloc_space) { $index = 3; } elsif ($main::opt_alloc_objects) { $index = 2; } # Find the type of this profile. The header line looks like: # heap profile: 1246: 8800744 [ 1246: 8800744] @ /266053 # There are two pairs , the first inuse objects/space, and the # second allocated objects/space. This is followed optionally by a profile # type, and if that is present, optionally by a sampling frequency. # For remote heap profiles (v1): # The interpretation of the sampling frequency is that the profiler, for # each sample, calculates a uniformly distributed random integer less than # the given value, and records the next sample after that many bytes have # been allocated. Therefore, the expected sample interval is half of the # given frequency. By default, if not specified, the expected sample # interval is 128KB. Only remote-heap-page profiles are adjusted for # sample size. # For remote heap profiles (v2): # The sampling frequency is the rate of a Poisson process. This means that # the probability of sampling an allocation of size X with sampling rate Y # is 1 - exp(-X/Y) # For version 2, a typical header line might look like this: # heap profile: 1922: 127792360 [ 1922: 127792360] @ _v2/524288 # the trailing number (524288) is the sampling rate. (Version 1 showed # double the 'rate' here) my $sampling_algorithm = 0; my $sample_adjustment = 0; chomp($header); my $type = "unknown"; if ($header =~ m"^heap profile:\s*(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\](\s*@\s*([^/]*)(/(\d+))?)?") { if (defined($6) && ($6 ne '')) { $type = $6; my $sample_period = $8; # $type is "heapprofile" for profiles generated by the # heap-profiler, and either "heap" or "heap_v2" for profiles # generated by sampling directly within tcmalloc. It can also # be "growth" for heap-growth profiles. The first is typically # found for profiles generated locally, and the others for # remote profiles. if (($type eq "heapprofile") || ($type !~ /heap/) ) { # No need to adjust for the sampling rate with heap-profiler-derived data $sampling_algorithm = 0; } elsif ($type =~ /_v2/) { $sampling_algorithm = 2; # version 2 sampling if (defined($sample_period) && ($sample_period ne '')) { $sample_adjustment = int($sample_period); } } else { $sampling_algorithm = 1; # version 1 sampling if (defined($sample_period) && ($sample_period ne '')) { $sample_adjustment = int($sample_period)/2; } } } else { # We detect whether or not this is a remote-heap profile by checking # that the total-allocated stats ($n2,$s2) are exactly the # same as the in-use stats ($n1,$s1). It is remotely conceivable # that a non-remote-heap profile may pass this check, but it is hard # to imagine how that could happen. # In this case it's so old it's guaranteed to be remote-heap version 1. my ($n1, $s1, $n2, $s2) = ($1, $2, $3, $4); if (($n1 == $n2) && ($s1 == $s2)) { # This is likely to be a remote-heap based sample profile $sampling_algorithm = 1; } } } if ($sampling_algorithm > 0) { # For remote-heap generated profiles, adjust the counts and sizes to # account for the sample rate (we sample once every 128KB by default). if ($sample_adjustment == 0) { # Turn on profile adjustment. $sample_adjustment = 128*1024; print STDERR "Adjusting heap profiles for 1-in-128KB sampling rate\n"; } else { printf STDERR ("Adjusting heap profiles for 1-in-%d sampling rate\n", $sample_adjustment); } if ($sampling_algorithm > 1) { # We don't bother printing anything for the original version (version 1) printf STDERR "Heap version $sampling_algorithm\n"; } } my $profile = {}; my $pcs = {}; my $map = ""; while () { s/\r//g; # turn windows-looking lines into unix-looking lines if (/^MAPPED_LIBRARIES:/) { # Read the /proc/self/maps data while () { s/\r//g; # turn windows-looking lines into unix-looking lines $map .= $_; } last; } if (/^--- Memory map:/) { # Read /proc/self/maps data as formatted by DumpAddressMap() my $buildvar = ""; while () { s/\r//g; # turn windows-looking lines into unix-looking lines # Parse "build=" specification if supplied if (m/^\s*build=(.*)\n/) { $buildvar = $1; } # Expand "$build" variable if available $_ =~ s/\$build\b/$buildvar/g; $map .= $_; } last; } # Read entry of the form: # : [: ] @ a1 a2 a3 ... an s/^\s*//; s/\s*$//; if (m/^\s*(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\]\s+@\s+(.*)$/) { my $stack = $5; my ($n1, $s1, $n2, $s2) = ($1, $2, $3, $4); if ($sample_adjustment) { if ($sampling_algorithm == 2) { # Remote-heap version 2 # The sampling frequency is the rate of a Poisson process. # This means that the probability of sampling an allocation of # size X with sampling rate Y is 1 - exp(-X/Y) if ($n1 != 0) { my $ratio = (($s1*1.0)/$n1)/($sample_adjustment); my $scale_factor = 1/(1 - exp(-$ratio)); $n1 *= $scale_factor; $s1 *= $scale_factor; } if ($n2 != 0) { my $ratio = (($s2*1.0)/$n2)/($sample_adjustment); my $scale_factor = 1/(1 - exp(-$ratio)); $n2 *= $scale_factor; $s2 *= $scale_factor; } } else { # Remote-heap version 1 my $ratio; $ratio = (($s1*1.0)/$n1)/($sample_adjustment); if ($ratio < 1) { $n1 /= $ratio; $s1 /= $ratio; } $ratio = (($s2*1.0)/$n2)/($sample_adjustment); if ($ratio < 1) { $n2 /= $ratio; $s2 /= $ratio; } } } my @counts = ($n1, $s1, $n2, $s2); AddEntries($profile, $pcs, FixCallerAddresses($stack), $counts[$index]); } } my $r = {}; $r->{version} = "heap"; $r->{period} = 1; $r->{profile} = $profile; $r->{libs} = ParseLibraries($prog, $map, $pcs); $r->{pcs} = $pcs; return $r; } sub ReadSynchProfile { my $prog = shift; local *PROFILE = shift; my $header = shift; my $map = ''; my $profile = {}; my $pcs = {}; my $sampling_period = 1; my $cyclespernanosec = 2.8; # Default assumption for old binaries my $seen_clockrate = 0; my $line; my $index = 0; if ($main::opt_total_delay) { $index = 0; } elsif ($main::opt_contentions) { $index = 1; } elsif ($main::opt_mean_delay) { $index = 2; } while ( $line = ) { $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines if ( $line =~ /^\s*(\d+)\s+(\d+) \@\s*(.*?)\s*$/ ) { my ($cycles, $count, $stack) = ($1, $2, $3); # Convert cycles to nanoseconds $cycles /= $cyclespernanosec; # Adjust for sampling done by application $cycles *= $sampling_period; $count *= $sampling_period; my @values = ($cycles, $count, $cycles / $count); AddEntries($profile, $pcs, FixCallerAddresses($stack), $values[$index]); } elsif ( $line =~ /^(slow release).*thread \d+ \@\s*(.*?)\s*$/ || $line =~ /^\s*(\d+) \@\s*(.*?)\s*$/ ) { my ($cycles, $stack) = ($1, $2); if ($cycles !~ /^\d+$/) { next; } # Convert cycles to nanoseconds $cycles /= $cyclespernanosec; # Adjust for sampling done by application $cycles *= $sampling_period; AddEntries($profile, $pcs, FixCallerAddresses($stack), $cycles); } elsif ( $line =~ m/^([a-z][^=]*)=(.*)$/ ) { my ($variable, $value) = ($1,$2); for ($variable, $value) { s/^\s+//; s/\s+$//; } if ($variable eq "cycles/second") { $cyclespernanosec = $value / 1e9; $seen_clockrate = 1; } elsif ($variable eq "sampling period") { $sampling_period = $value; } elsif ($variable eq "ms since reset") { # Currently nothing is done with this value in pprof # So we just silently ignore it for now } elsif ($variable eq "discarded samples") { # Currently nothing is done with this value in pprof # So we just silently ignore it for now } else { printf STDERR ("Ignoring unnknown variable in /contention output: " . "'%s' = '%s'\n",$variable,$value); } } else { # Memory map entry $map .= $line; } } if (!$seen_clockrate) { printf STDERR ("No cycles/second entry in profile; Guessing %.1f GHz\n", $cyclespernanosec); } my $r = {}; $r->{version} = 0; $r->{period} = $sampling_period; $r->{profile} = $profile; $r->{libs} = ParseLibraries($prog, $map, $pcs); $r->{pcs} = $pcs; return $r; } # Given a hex value in the form "0x1abcd" return "0001abcd" or # "000000000001abcd", depending on the current address length. # There's probably a more idiomatic (or faster) way to do this... sub HexExtend { my $addr = shift; $addr =~ s/^0x//; if (length $addr > $address_length) { printf STDERR "Warning: address $addr is longer than address length $address_length\n"; } return substr("000000000000000".$addr, -$address_length); } ##### Symbol extraction ##### # Aggressively search the lib_prefix values for the given library # If all else fails, just return the name of the library unmodified. # If the lib_prefix is "/my/path,/other/path" and $file is "/lib/dir/mylib.so" # it will search the following locations in this order, until it finds a file: # /my/path/lib/dir/mylib.so # /other/path/lib/dir/mylib.so # /my/path/dir/mylib.so # /other/path/dir/mylib.so # /my/path/mylib.so # /other/path/mylib.so # /lib/dir/mylib.so (returned as last resort) sub FindLibrary { my $file = shift; my $suffix = $file; # Search for the library as described above do { foreach my $prefix (@prefix_list) { my $fullpath = $prefix . $suffix; if (-e $fullpath) { return $fullpath; } } } while ($suffix =~ s|^/[^/]+/|/|); return $file; } # Return path to library with debugging symbols. # For libc libraries, the copy in /usr/lib/debug contains debugging symbols sub DebuggingLibrary { my $file = shift; if ($file =~ m|^/| && -f "/usr/lib/debug$file") { return "/usr/lib/debug$file"; } return undef; } # Parse text section header of a library using objdump sub ParseTextSectionHeaderFromObjdump { my $lib = shift; my $size = undef; my $vma; my $file_offset; # Get objdump output from the library file to figure out how to # map between mapped addresses and addresses in the library. my $objdump = $obj_tool_map{"objdump"}; open(OBJDUMP, "$objdump -h $lib |") || error("$objdump $lib: $!\n"); while () { s/\r//g; # turn windows-looking lines into unix-looking lines # Idx Name Size VMA LMA File off Algn # 10 .text 00104b2c 420156f0 420156f0 000156f0 2**4 # For 64-bit objects, VMA and LMA will be 16 hex digits, size and file # offset may still be 8. But AddressSub below will still handle that. my @x = split; if (($#x >= 6) && ($x[1] eq '.text')) { $size = $x[2]; $vma = $x[3]; $file_offset = $x[5]; last; } } close(OBJDUMP); if (!defined($size)) { return undef; } my $r = {}; $r->{size} = $size; $r->{vma} = $vma; $r->{file_offset} = $file_offset; return $r; } # Parse text section header of a library using otool (on OS X) sub ParseTextSectionHeaderFromOtool { my $lib = shift; my $size = undef; my $vma = undef; my $file_offset = undef; # Get otool output from the library file to figure out how to # map between mapped addresses and addresses in the library. my $otool = $obj_tool_map{"otool"}; open(OTOOL, "$otool -l $lib |") || error("$otool $lib: $!\n"); my $cmd = ""; my $sectname = ""; my $segname = ""; foreach my $line () { $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines # Load command <#> # cmd LC_SEGMENT # [...] # Section # sectname __text # segname __TEXT # addr 0x000009f8 # size 0x00018b9e # offset 2552 # align 2^2 (4) # We will need to strip off the leading 0x from the hex addresses, # and convert the offset into hex. if ($line =~ /Load command/) { $cmd = ""; $sectname = ""; $segname = ""; } elsif ($line =~ /Section/) { $sectname = ""; $segname = ""; } elsif ($line =~ /cmd (\w+)/) { $cmd = $1; } elsif ($line =~ /sectname (\w+)/) { $sectname = $1; } elsif ($line =~ /segname (\w+)/) { $segname = $1; } elsif (!(($cmd eq "LC_SEGMENT" || $cmd eq "LC_SEGMENT_64") && $sectname eq "__text" && $segname eq "__TEXT")) { next; } elsif ($line =~ /\baddr 0x([0-9a-fA-F]+)/) { $vma = $1; } elsif ($line =~ /\bsize 0x([0-9a-fA-F]+)/) { $size = $1; } elsif ($line =~ /\boffset ([0-9]+)/) { $file_offset = sprintf("%016x", $1); } if (defined($vma) && defined($size) && defined($file_offset)) { last; } } close(OTOOL); if (!defined($vma) || !defined($size) || !defined($file_offset)) { return undef; } my $r = {}; $r->{size} = $size; $r->{vma} = $vma; $r->{file_offset} = $file_offset; return $r; } sub ParseTextSectionHeader { # obj_tool_map("otool") is only defined if we're in a Mach-O environment if (defined($obj_tool_map{"otool"})) { my $r = ParseTextSectionHeaderFromOtool(@_); if (defined($r)){ return $r; } } # If otool doesn't work, or we don't have it, fall back to objdump return ParseTextSectionHeaderFromObjdump(@_); } # Split /proc/pid/maps dump into a list of libraries sub ParseLibraries { return if $main::use_symbol_page; # We don't need libraries info. my $prog = shift; my $map = shift; my $pcs = shift; my $result = []; my $h = "[a-f0-9]+"; my $zero_offset = HexExtend("0"); my $buildvar = ""; foreach my $l (split("\n", $map)) { if ($l =~ m/^\s*build=(.*)$/) { $buildvar = $1; } my $start; my $finish; my $offset; my $lib; if ($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+\.(so|dll|dylib|bundle)((\.\d+)+\w*(\.\d+){0,3})?)$/i) { # Full line from /proc/self/maps. Example: # 40000000-40015000 r-xp 00000000 03:01 12845071 /lib/ld-2.3.2.so $start = HexExtend($1); $finish = HexExtend($2); $offset = HexExtend($3); $lib = $4; $lib =~ s|\\|/|g; # turn windows-style paths into unix-style paths } elsif ($l =~ /^\s*($h)-($h):\s*(\S+\.so(\.\d+)*)/) { # Cooked line from DumpAddressMap. Example: # 40000000-40015000: /lib/ld-2.3.2.so $start = HexExtend($1); $finish = HexExtend($2); $offset = $zero_offset; $lib = $3; } else { next; } # Expand "$build" variable if available $lib =~ s/\$build\b/$buildvar/g; $lib = FindLibrary($lib); # Check for pre-relocated libraries, which use pre-relocated symbol tables # and thus require adjusting the offset that we'll use to translate # VM addresses into symbol table addresses. # Only do this if we're not going to fetch the symbol table from a # debugging copy of the library. if (!DebuggingLibrary($lib)) { my $text = ParseTextSectionHeader($lib); if (defined($text)) { my $vma_offset = AddressSub($text->{vma}, $text->{file_offset}); $offset = AddressAdd($offset, $vma_offset); } } push(@{$result}, [$lib, $start, $finish, $offset]); } # Append special entry for additional library (not relocated) if ($main::opt_lib ne "") { my $text = ParseTextSectionHeader($main::opt_lib); if (defined($text)) { my $start = $text->{vma}; my $finish = AddressAdd($start, $text->{size}); push(@{$result}, [$main::opt_lib, $start, $finish, $start]); } } # Append special entry for the main program. This covers # 0..max_pc_value_seen, so that we assume pc values not found in one # of the library ranges will be treated as coming from the main # program binary. my $min_pc = HexExtend("0"); my $max_pc = $min_pc; # find the maximal PC value in any sample foreach my $pc (keys(%{$pcs})) { if (HexExtend($pc) gt $max_pc) { $max_pc = HexExtend($pc); } } push(@{$result}, [$prog, $min_pc, $max_pc, $zero_offset]); return $result; } # Add two hex addresses of length $address_length. # Run pprof --test for unit test if this is changed. sub AddressAdd { my $addr1 = shift; my $addr2 = shift; my $sum; if ($address_length == 8) { # Perl doesn't cope with wraparound arithmetic, so do it explicitly: $sum = (hex($addr1)+hex($addr2)) % (0x10000000 * 16); return sprintf("%08x", $sum); } else { # Do the addition in 7-nibble chunks to trivialize carry handling. if ($main::opt_debug and $main::opt_test) { print STDERR "AddressAdd $addr1 + $addr2 = "; } my $a1 = substr($addr1,-7); $addr1 = substr($addr1,0,-7); my $a2 = substr($addr2,-7); $addr2 = substr($addr2,0,-7); $sum = hex($a1) + hex($a2); my $c = 0; if ($sum > 0xfffffff) { $c = 1; $sum -= 0x10000000; } my $r = sprintf("%07x", $sum); $a1 = substr($addr1,-7); $addr1 = substr($addr1,0,-7); $a2 = substr($addr2,-7); $addr2 = substr($addr2,0,-7); $sum = hex($a1) + hex($a2) + $c; $c = 0; if ($sum > 0xfffffff) { $c = 1; $sum -= 0x10000000; } $r = sprintf("%07x", $sum) . $r; $sum = hex($addr1) + hex($addr2) + $c; if ($sum > 0xff) { $sum -= 0x100; } $r = sprintf("%02x", $sum) . $r; if ($main::opt_debug and $main::opt_test) { print STDERR "$r\n"; } return $r; } } # Subtract two hex addresses of length $address_length. # Run pprof --test for unit test if this is changed. sub AddressSub { my $addr1 = shift; my $addr2 = shift; my $diff; if ($address_length == 8) { # Perl doesn't cope with wraparound arithmetic, so do it explicitly: $diff = (hex($addr1)-hex($addr2)) % (0x10000000 * 16); return sprintf("%08x", $diff); } else { # Do the addition in 7-nibble chunks to trivialize borrow handling. # if ($main::opt_debug) { print STDERR "AddressSub $addr1 - $addr2 = "; } my $a1 = hex(substr($addr1,-7)); $addr1 = substr($addr1,0,-7); my $a2 = hex(substr($addr2,-7)); $addr2 = substr($addr2,0,-7); my $b = 0; if ($a2 > $a1) { $b = 1; $a1 += 0x10000000; } $diff = $a1 - $a2; my $r = sprintf("%07x", $diff); $a1 = hex(substr($addr1,-7)); $addr1 = substr($addr1,0,-7); $a2 = hex(substr($addr2,-7)) + $b; $addr2 = substr($addr2,0,-7); $b = 0; if ($a2 > $a1) { $b = 1; $a1 += 0x10000000; } $diff = $a1 - $a2; $r = sprintf("%07x", $diff) . $r; $a1 = hex($addr1); $a2 = hex($addr2) + $b; if ($a2 > $a1) { $a1 += 0x100; } $diff = $a1 - $a2; $r = sprintf("%02x", $diff) . $r; # if ($main::opt_debug) { print STDERR "$r\n"; } return $r; } } # Increment a hex addresses of length $address_length. # Run pprof --test for unit test if this is changed. sub AddressInc { my $addr = shift; my $sum; if ($address_length == 8) { # Perl doesn't cope with wraparound arithmetic, so do it explicitly: $sum = (hex($addr)+1) % (0x10000000 * 16); return sprintf("%08x", $sum); } else { # Do the addition in 7-nibble chunks to trivialize carry handling. # We are always doing this to step through the addresses in a function, # and will almost never overflow the first chunk, so we check for this # case and exit early. # if ($main::opt_debug) { print STDERR "AddressInc $addr1 = "; } my $a1 = substr($addr,-7); $addr = substr($addr,0,-7); $sum = hex($a1) + 1; my $r = sprintf("%07x", $sum); if ($sum <= 0xfffffff) { $r = $addr . $r; # if ($main::opt_debug) { print STDERR "$r\n"; } return HexExtend($r); } else { $r = "0000000"; } $a1 = substr($addr,-7); $addr = substr($addr,0,-7); $sum = hex($a1) + 1; $r = sprintf("%07x", $sum) . $r; if ($sum <= 0xfffffff) { $r = $addr . $r; # if ($main::opt_debug) { print STDERR "$r\n"; } return HexExtend($r); } else { $r = "00000000000000"; } $sum = hex($addr) + 1; if ($sum > 0xff) { $sum -= 0x100; } $r = sprintf("%02x", $sum) . $r; # if ($main::opt_debug) { print STDERR "$r\n"; } return $r; } } # Extract symbols for all PC values found in profile sub ExtractSymbols { my $libs = shift; my $pcset = shift; my $symbols = {}; # Map each PC value to the containing library. To make this faster, # we sort libraries by their starting pc value (highest first), and # advance through the libraries as we advance the pc. Sometimes the # addresses of libraries may overlap with the addresses of the main # binary, so to make sure the libraries 'win', we iterate over the # libraries in reverse order (which assumes the binary doesn't start # in the middle of a library, which seems a fair assumption). my @pcs = (sort { $a cmp $b } keys(%{$pcset})); # pcset is 0-extended strings foreach my $lib (sort {$b->[1] cmp $a->[1]} @{$libs}) { my $libname = $lib->[0]; my $start = $lib->[1]; my $finish = $lib->[2]; my $offset = $lib->[3]; # Get list of pcs that belong in this library. my $contained = []; my ($start_pc_index, $finish_pc_index); # Find smallest finish_pc_index such that $finish < $pc[$finish_pc_index]. for ($finish_pc_index = $#pcs + 1; $finish_pc_index > 0; $finish_pc_index--) { last if $pcs[$finish_pc_index - 1] le $finish; } # Find smallest start_pc_index such that $start <= $pc[$start_pc_index]. for ($start_pc_index = $finish_pc_index; $start_pc_index > 0; $start_pc_index--) { last if $pcs[$start_pc_index - 1] lt $start; } # This keeps PC values higher than $pc[$finish_pc_index] in @pcs, # in case there are overlaps in libraries and the main binary. @{$contained} = splice(@pcs, $start_pc_index, $finish_pc_index - $start_pc_index); # Map to symbols MapToSymbols($libname, AddressSub($start, $offset), $contained, $symbols); } return $symbols; } # Map list of PC values to symbols for a given image sub MapToSymbols { my $image = shift; my $offset = shift; my $pclist = shift; my $symbols = shift; my $debug = 0; # Ignore empty binaries if ($#{$pclist} < 0) { return; } # Figure out the addr2line command to use my $addr2line = $obj_tool_map{"addr2line"}; my $cmd = "$addr2line -f -C -e $image"; if (exists $obj_tool_map{"addr2line_pdb"}) { $addr2line = $obj_tool_map{"addr2line_pdb"}; $cmd = "$addr2line --demangle -f -C -e $image"; } # If "addr2line" isn't installed on the system at all, just use # nm to get what info we can (function names, but not line numbers). if (system("$addr2line --help >/dev/null 2>&1") != 0) { MapSymbolsWithNM($image, $offset, $pclist, $symbols); return; } # "addr2line -i" can produce a variable number of lines per input # address, with no separator that allows us to tell when data for # the next address starts. So we find the address for a special # symbol (_fini) and interleave this address between all real # addresses passed to addr2line. The name of this special symbol # can then be used as a separator. $sep_address = undef; # May be filled in by MapSymbolsWithNM() my $nm_symbols = {}; MapSymbolsWithNM($image, $offset, $pclist, $nm_symbols); # TODO(csilvers): only add '-i' if addr2line supports it. if (defined($sep_address)) { # Only add " -i" to addr2line if the binary supports it. # addr2line --help returns 0, but not if it sees an unknown flag first. if (system("$cmd -i --help >/dev/null 2>&1") == 0) { $cmd .= " -i"; } else { $sep_address = undef; # no need for sep_address if we don't support -i } } # Make file with all PC values with intervening 'sep_address' so # that we can reliably detect the end of inlined function list open(ADDRESSES, ">$main::tmpfile_sym") || error("$main::tmpfile_sym: $!\n"); if ($debug) { print("---- $image ---\n"); } for (my $i = 0; $i <= $#{$pclist}; $i++) { # addr2line always reads hex addresses, and does not need '0x' prefix. if ($debug) { printf STDERR ("%s\n", $pclist->[$i]); } printf ADDRESSES ("%s\n", AddressSub($pclist->[$i], $offset)); if (defined($sep_address)) { printf ADDRESSES ("%s\n", $sep_address); } } close(ADDRESSES); if ($debug) { print("----\n"); system("cat $main::tmpfile_sym"); print("----\n"); system("$cmd <$main::tmpfile_sym"); print("----\n"); } open(SYMBOLS, "$cmd <$main::tmpfile_sym |") || error("$cmd: $!\n"); my $count = 0; # Index in pclist while () { # Read fullfunction and filelineinfo from next pair of lines s/\r?\n$//g; my $fullfunction = $_; $_ = ; s/\r?\n$//g; my $filelinenum = $_; if (defined($sep_address) && $fullfunction eq $sep_symbol) { # Terminating marker for data for this address $count++; next; } $filelinenum =~ s|\\|/|g; # turn windows-style paths into unix-style paths my $pcstr = $pclist->[$count]; my $function = ShortFunctionName($fullfunction); if ($fullfunction eq '??') { # See if nm found a symbol my $nms = $nm_symbols->{$pcstr}; if (defined($nms)) { $function = $nms->[0]; $fullfunction = $nms->[2]; } } # Prepend to accumulated symbols for pcstr # (so that caller comes before callee) my $sym = $symbols->{$pcstr}; if (!defined($sym)) { $sym = []; $symbols->{$pcstr} = $sym; } unshift(@{$sym}, $function, $filelinenum, $fullfunction); if ($debug) { printf STDERR ("%s => [%s]\n", $pcstr, join(" ", @{$sym})); } if (!defined($sep_address)) { # Inlining is off, se this entry ends immediately $count++; } } close(SYMBOLS); } # Use nm to map the list of referenced PCs to symbols. Return true iff we # are able to read procedure information via nm. sub MapSymbolsWithNM { my $image = shift; my $offset = shift; my $pclist = shift; my $symbols = shift; # Get nm output sorted by increasing address my $symbol_table = GetProcedureBoundaries($image, "."); if (!%{$symbol_table}) { return 0; } # Start addresses are already the right length (8 or 16 hex digits). my @names = sort { $symbol_table->{$a}->[0] cmp $symbol_table->{$b}->[0] } keys(%{$symbol_table}); if ($#names < 0) { # No symbols: just use addresses foreach my $pc (@{$pclist}) { my $pcstr = "0x" . $pc; $symbols->{$pc} = [$pcstr, "?", $pcstr]; } return 0; } # Sort addresses so we can do a join against nm output my $index = 0; my $fullname = $names[0]; my $name = ShortFunctionName($fullname); foreach my $pc (sort { $a cmp $b } @{$pclist}) { # Adjust for mapped offset my $mpc = AddressSub($pc, $offset); while (($index < $#names) && ($mpc ge $symbol_table->{$fullname}->[1])){ $index++; $fullname = $names[$index]; $name = ShortFunctionName($fullname); } if ($mpc lt $symbol_table->{$fullname}->[1]) { $symbols->{$pc} = [$name, "?", $fullname]; } else { my $pcstr = "0x" . $pc; $symbols->{$pc} = [$pcstr, "?", $pcstr]; } } return 1; } sub ShortFunctionName { my $function = shift; while ($function =~ s/\([^()]*\)(\s*const)?//g) { } # Argument types while ($function =~ s/<[^<>]*>//g) { } # Remove template arguments $function =~ s/^.*\s+(\w+::)/$1/; # Remove leading type return $function; } ##### Miscellaneous ##### # Find the right versions of the above object tools to use. The # argument is the program file being analyzed, and should be an ELF # 32-bit or ELF 64-bit executable file. The location of the tools # is determined by considering the following options in this order: # 1) --tools option, if set # 2) PPROF_TOOLS environment variable, if set # 3) the environment sub ConfigureObjTools { my $prog_file = shift; # Check for the existence of $prog_file because /usr/bin/file does not # predictably return error status in prod. (-e $prog_file) || error("$prog_file does not exist.\n"); # Follow symlinks (at least for systems where "file" supports that) my $file_type = `/usr/bin/file -L $prog_file 2>/dev/null || /usr/bin/file $prog_file`; if ($file_type =~ /64-bit/) { # Change $address_length to 16 if the program file is ELF 64-bit. # We can't detect this from many (most?) heap or lock contention # profiles, since the actual addresses referenced are generally in low # memory even for 64-bit programs. $address_length = 16; } if ($file_type =~ /MS Windows/) { # For windows, we provide a version of nm and addr2line as part of # the opensource release, which is capable of parsing # Windows-style PDB executables. It should live in the path, or # in the same directory as pprof. $obj_tool_map{"nm_pdb"} = "nm-pdb"; $obj_tool_map{"addr2line_pdb"} = "addr2line-pdb"; } if ($file_type =~ /Mach-O/) { # OS X uses otool to examine Mach-O files, rather than objdump. $obj_tool_map{"otool"} = "otool"; $obj_tool_map{"addr2line"} = "false"; # no addr2line $obj_tool_map{"objdump"} = "false"; # no objdump } # Go fill in %obj_tool_map with the pathnames to use: foreach my $tool (keys %obj_tool_map) { $obj_tool_map{$tool} = ConfigureTool($obj_tool_map{$tool}); } } # Returns the path of a caller-specified object tool. If --tools or # PPROF_TOOLS are specified, then returns the full path to the tool # with that prefix. Otherwise, returns the path unmodified (which # means we will look for it on PATH). sub ConfigureTool { my $tool = shift; my $path; # --tools (or $PPROF_TOOLS) is a comma separated list, where each # item is either a) a pathname prefix, or b) a map of the form # :. First we look for an entry of type (b) for our # tool. If one is found, we use it. Otherwise, we consider all the # pathname prefixes in turn, until one yields an existing file. If # none does, we use a default path. my $tools = $main::opt_tools || $ENV{"PPROF_TOOLS"} || ""; if ($tools =~ m/(,|^)\Q$tool\E:([^,]*)/) { $path = $2; # TODO(csilvers): sanity-check that $path exists? Hard if it's relative. } elsif ($tools ne '') { foreach my $prefix (split(',', $tools)) { next if ($prefix =~ /:/); # ignore "tool:fullpath" entries in the list if (-x $prefix . $tool) { $path = $prefix . $tool; last; } } if (!$path) { error("No '$tool' found with prefix specified by " . "--tools (or \$PPROF_TOOLS) '$tools'\n"); } } else { # ... otherwise use the version that exists in the same directory as # pprof. If there's nothing there, use $PATH. $0 =~ m,[^/]*$,; # this is everything after the last slash my $dirname = $`; # this is everything up to and including the last slash if (-x "$dirname$tool") { $path = "$dirname$tool"; } else { $path = $tool; } } if ($main::opt_debug) { print STDERR "Using '$path' for '$tool'.\n"; } return $path; } sub cleanup { unlink($main::tmpfile_sym); unlink(keys %main::tempnames); # We leave any collected profiles in $HOME/pprof in case the user wants # to look at them later. We print a message informing them of this. if ((scalar(@main::profile_files) > 0) && defined($main::collected_profile)) { if (scalar(@main::profile_files) == 1) { print STDERR "Dynamically gathered profile is in $main::collected_profile\n"; } print STDERR "If you want to investigate this profile further, you can do:\n"; print STDERR "\n"; print STDERR " pprof \\\n"; print STDERR " $main::prog \\\n"; print STDERR " $main::collected_profile\n"; print STDERR "\n"; } } sub sighandler { cleanup(); exit(1); } sub error { my $msg = shift; print STDERR $msg; cleanup(); exit(1); } # Run $nm_command and get all the resulting procedure boundaries whose # names match "$regexp" and returns them in a hashtable mapping from # procedure name to a two-element vector of [start address, end address] sub GetProcedureBoundariesViaNm { my $nm_command = shift; my $regexp = shift; my $symbol_table = {}; open(NM, "$nm_command |") || error("$nm_command: $!\n"); my $last_start = "0"; my $routine = ""; while () { s/\r//g; # turn windows-looking lines into unix-looking lines if (m/^\s*([0-9a-f]+) (.) (..*)/) { my $start_val = $1; my $type = $2; my $this_routine = $3; # It's possible for two symbols to share the same address, if # one is a zero-length variable (like __start_google_malloc) or # one symbol is a weak alias to another (like __libc_malloc). # In such cases, we want to ignore all values except for the # actual symbol, which in nm-speak has type "T". The logic # below does this, though it's a bit tricky: what happens when # we have a series of lines with the same address, is the first # one gets queued up to be processed. However, it won't # *actually* be processed until later, when we read a line with # a different address. That means that as long as we're reading # lines with the same address, we have a chance to replace that # item in the queue, which we do whenever we see a 'T' entry -- # that is, a line with type 'T'. If we never see a 'T' entry, # we'll just go ahead and process the first entry (which never # got touched in the queue), and ignore the others. if ($start_val eq $last_start && $type =~ /t/i) { # We are the 'T' symbol at this address, replace previous symbol. $routine = $this_routine; next; } elsif ($start_val eq $last_start) { # We're not the 'T' symbol at this address, so ignore us. next; } if ($this_routine eq $sep_symbol) { $sep_address = HexExtend($start_val); } # Tag this routine with the starting address in case the image # has multiple occurrences of this routine. We use a syntax # that resembles template paramters that are automatically # stripped out by ShortFunctionName() $this_routine .= "<$start_val>"; if (defined($routine) && $routine =~ m/$regexp/) { $symbol_table->{$routine} = [HexExtend($last_start), HexExtend($start_val)]; } $last_start = $start_val; $routine = $this_routine; } elsif (m/^Loaded image name: (.+)/) { # The win32 nm workalike emits information about the binary it is using. if ($main::opt_debug) { print STDERR "Using Image $1\n"; } } elsif (m/^PDB file name: (.+)/) { # The win32 nm workalike emits information about the pdb it is using. if ($main::opt_debug) { print STDERR "Using PDB $1\n"; } } } close(NM); # Handle the last line in the nm output. Unfortunately, we don't know # how big this last symbol is, because we don't know how big the file # is. For now, we just give it a size of 0. # TODO(csilvers): do better here. if (defined($routine) && $routine =~ m/$regexp/) { $symbol_table->{$routine} = [HexExtend($last_start), HexExtend($last_start)]; } return $symbol_table; } # Gets the procedure boundaries for all routines in "$image" whose names # match "$regexp" and returns them in a hashtable mapping from procedure # name to a two-element vector of [start address, end address]. # Will return an empty map if nm is not installed or not working properly. sub GetProcedureBoundaries { my $image = shift; my $regexp = shift; # For libc libraries, the copy in /usr/lib/debug contains debugging symbols my $debugging = DebuggingLibrary($image); if ($debugging) { $image = $debugging; } my $nm = $obj_tool_map{"nm"}; my $cppfilt = $obj_tool_map{"c++filt"}; # nm can fail for two reasons: 1) $image isn't a debug library; 2) nm # binary doesn't support --demangle. In addition, for OS X we need # to use the -f flag to get 'flat' nm output (otherwise we don't sort # properly and get incorrect results). Unfortunately, GNU nm uses -f # in an incompatible way. So first we test whether our nm supports # --demangle and -f. my $demangle_flag = ""; my $cppfilt_flag = ""; if (system("$nm --demangle $image >/dev/null 2>&1") == 0) { # In this mode, we do "nm --demangle " $demangle_flag = "--demangle"; $cppfilt_flag = ""; } elsif (system("$cppfilt $image >/dev/null 2>&1") == 0) { # In this mode, we do "nm | c++filt" $cppfilt_flag = " | $cppfilt"; }; my $flatten_flag = ""; if (system("$nm -f $image >/dev/null 2>&1") == 0) { $flatten_flag = "-f"; } # Finally, in the case $imagie isn't a debug library, we try again with # -D to at least get *exported* symbols. If we can't use --demangle, # we use c++filt instead, if it exists on this system. my @nm_commands = ("$nm -n $flatten_flag $demangle_flag" . " $image 2>/dev/null $cppfilt_flag", "$nm -D -n $flatten_flag $demangle_flag" . " $image 2>/dev/null $cppfilt_flag", # 6nm is for Go binaries "6nm $image 2>/dev/null | sort", ); # If the executable is an MS Windows PDB-format executable, we'll # have set up obj_tool_map("nm_pdb"). In this case, we actually # want to use both unix nm and windows-specific nm_pdb, since # PDB-format executables can apparently include dwarf .o files. if (exists $obj_tool_map{"nm_pdb"}) { my $nm_pdb = $obj_tool_map{"nm_pdb"}; push(@nm_commands, "$nm_pdb --demangle $image 2>/dev/null"); } foreach my $nm_command (@nm_commands) { my $symbol_table = GetProcedureBoundariesViaNm($nm_command, $regexp); return $symbol_table if (%{$symbol_table}); } my $symbol_table = {}; return $symbol_table; } # The test vectors for AddressAdd/Sub/Inc are 8-16-nibble hex strings. # To make them more readable, we add underscores at interesting places. # This routine removes the underscores, producing the canonical representation # used by pprof to represent addresses, particularly in the tested routines. sub CanonicalHex { my $arg = shift; return join '', (split '_',$arg); } # Unit test for AddressAdd: sub AddressAddUnitTest { my $test_data_8 = shift; my $test_data_16 = shift; my $error_count = 0; my $fail_count = 0; my $pass_count = 0; # print STDERR "AddressAddUnitTest: ", 1+$#{$test_data_8}, " tests\n"; # First a few 8-nibble addresses. Note that this implementation uses # plain old arithmetic, so a quick sanity check along with verifying what # happens to overflow (we want it to wrap): $address_length = 8; foreach my $row (@{$test_data_8}) { if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; } my $sum = AddressAdd ($row->[0], $row->[1]); if ($sum ne $row->[2]) { printf STDERR "ERROR: %s != %s + %s = %s\n", $sum, $row->[0], $row->[1], $row->[2]; ++$fail_count; } else { ++$pass_count; } } printf STDERR "AddressAdd 32-bit tests: %d passes, %d failures\n", $pass_count, $fail_count; $error_count = $fail_count; $fail_count = 0; $pass_count = 0; # Now 16-nibble addresses. $address_length = 16; foreach my $row (@{$test_data_16}) { if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; } my $sum = AddressAdd (CanonicalHex($row->[0]), CanonicalHex($row->[1])); my $expected = join '', (split '_',$row->[2]); if ($sum ne CanonicalHex($row->[2])) { printf STDERR "ERROR: %s != %s + %s = %s\n", $sum, $row->[0], $row->[1], $row->[2]; ++$fail_count; } else { ++$pass_count; } } printf STDERR "AddressAdd 64-bit tests: %d passes, %d failures\n", $pass_count, $fail_count; $error_count += $fail_count; return $error_count; } # Unit test for AddressSub: sub AddressSubUnitTest { my $test_data_8 = shift; my $test_data_16 = shift; my $error_count = 0; my $fail_count = 0; my $pass_count = 0; # print STDERR "AddressSubUnitTest: ", 1+$#{$test_data_8}, " tests\n"; # First a few 8-nibble addresses. Note that this implementation uses # plain old arithmetic, so a quick sanity check along with verifying what # happens to overflow (we want it to wrap): $address_length = 8; foreach my $row (@{$test_data_8}) { if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; } my $sum = AddressSub ($row->[0], $row->[1]); if ($sum ne $row->[3]) { printf STDERR "ERROR: %s != %s - %s = %s\n", $sum, $row->[0], $row->[1], $row->[3]; ++$fail_count; } else { ++$pass_count; } } printf STDERR "AddressSub 32-bit tests: %d passes, %d failures\n", $pass_count, $fail_count; $error_count = $fail_count; $fail_count = 0; $pass_count = 0; # Now 16-nibble addresses. $address_length = 16; foreach my $row (@{$test_data_16}) { if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; } my $sum = AddressSub (CanonicalHex($row->[0]), CanonicalHex($row->[1])); if ($sum ne CanonicalHex($row->[3])) { printf STDERR "ERROR: %s != %s - %s = %s\n", $sum, $row->[0], $row->[1], $row->[3]; ++$fail_count; } else { ++$pass_count; } } printf STDERR "AddressSub 64-bit tests: %d passes, %d failures\n", $pass_count, $fail_count; $error_count += $fail_count; return $error_count; } # Unit test for AddressInc: sub AddressIncUnitTest { my $test_data_8 = shift; my $test_data_16 = shift; my $error_count = 0; my $fail_count = 0; my $pass_count = 0; # print STDERR "AddressIncUnitTest: ", 1+$#{$test_data_8}, " tests\n"; # First a few 8-nibble addresses. Note that this implementation uses # plain old arithmetic, so a quick sanity check along with verifying what # happens to overflow (we want it to wrap): $address_length = 8; foreach my $row (@{$test_data_8}) { if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; } my $sum = AddressInc ($row->[0]); if ($sum ne $row->[4]) { printf STDERR "ERROR: %s != %s + 1 = %s\n", $sum, $row->[0], $row->[4]; ++$fail_count; } else { ++$pass_count; } } printf STDERR "AddressInc 32-bit tests: %d passes, %d failures\n", $pass_count, $fail_count; $error_count = $fail_count; $fail_count = 0; $pass_count = 0; # Now 16-nibble addresses. $address_length = 16; foreach my $row (@{$test_data_16}) { if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; } my $sum = AddressInc (CanonicalHex($row->[0])); if ($sum ne CanonicalHex($row->[4])) { printf STDERR "ERROR: %s != %s + 1 = %s\n", $sum, $row->[0], $row->[4]; ++$fail_count; } else { ++$pass_count; } } printf STDERR "AddressInc 64-bit tests: %d passes, %d failures\n", $pass_count, $fail_count; $error_count += $fail_count; return $error_count; } # Driver for unit tests. # Currently just the address add/subtract/increment routines for 64-bit. sub RunUnitTests { my $error_count = 0; # This is a list of tuples [a, b, a+b, a-b, a+1] my $unit_test_data_8 = [ [qw(aaaaaaaa 50505050 fafafafa 5a5a5a5a aaaaaaab)], [qw(50505050 aaaaaaaa fafafafa a5a5a5a6 50505051)], [qw(ffffffff aaaaaaaa aaaaaaa9 55555555 00000000)], [qw(00000001 ffffffff 00000000 00000002 00000002)], [qw(00000001 fffffff0 fffffff1 00000011 00000002)], ]; my $unit_test_data_16 = [ # The implementation handles data in 7-nibble chunks, so those are the # interesting boundaries. [qw(aaaaaaaa 50505050 00_000000f_afafafa 00_0000005_a5a5a5a 00_000000a_aaaaaab)], [qw(50505050 aaaaaaaa 00_000000f_afafafa ff_ffffffa_5a5a5a6 00_0000005_0505051)], [qw(ffffffff aaaaaaaa 00_000001a_aaaaaa9 00_0000005_5555555 00_0000010_0000000)], [qw(00000001 ffffffff 00_0000010_0000000 ff_ffffff0_0000002 00_0000000_0000002)], [qw(00000001 fffffff0 00_000000f_ffffff1 ff_ffffff0_0000011 00_0000000_0000002)], [qw(00_a00000a_aaaaaaa 50505050 00_a00000f_afafafa 00_a000005_a5a5a5a 00_a00000a_aaaaaab)], [qw(0f_fff0005_0505050 aaaaaaaa 0f_fff000f_afafafa 0f_ffefffa_5a5a5a6 0f_fff0005_0505051)], [qw(00_000000f_fffffff 01_800000a_aaaaaaa 01_800001a_aaaaaa9 fe_8000005_5555555 00_0000010_0000000)], [qw(00_0000000_0000001 ff_fffffff_fffffff 00_0000000_0000000 00_0000000_0000002 00_0000000_0000002)], [qw(00_0000000_0000001 ff_fffffff_ffffff0 ff_fffffff_ffffff1 00_0000000_0000011 00_0000000_0000002)], ]; $error_count += AddressAddUnitTest($unit_test_data_8, $unit_test_data_16); $error_count += AddressSubUnitTest($unit_test_data_8, $unit_test_data_16); $error_count += AddressIncUnitTest($unit_test_data_8, $unit_test_data_16); if ($error_count > 0) { print STDERR $error_count, " errors: FAILED\n"; } else { print STDERR "PASS\n"; } exit ($error_count); } ================================================ FILE: distro/google-perftools-1.7/src/profile-handler.cc ================================================ // Copyright (c) 2009, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // Nabeel Mian // // Implements management of profile timers and the corresponding signal handler. #include "config.h" #include "profile-handler.h" #if !(defined(__CYGWIN__) || defined(__CYGWIN32__)) #include #include #include #include #include #include "base/dynamic_annotations.h" #include "base/logging.h" #include "base/spinlock.h" #include "maybe_threads.h" using std::list; using std::string; // This structure is used by ProfileHandlerRegisterCallback and // ProfileHandlerUnregisterCallback as a handle to a registered callback. struct ProfileHandlerToken { // Sets the callback and associated arg. ProfileHandlerToken(ProfileHandlerCallback cb, void* cb_arg) : callback(cb), callback_arg(cb_arg) { } // Callback function to be invoked on receiving a profile timer interrupt. ProfileHandlerCallback callback; // Argument for the callback function. void* callback_arg; }; // This class manages profile timers and associated signal handler. This is a // a singleton. class ProfileHandler { public: // Registers the current thread with the profile handler. On systems which // have a separate interval timer for each thread, this function starts the // timer for the current thread. // // The function also attempts to determine whether or not timers are shared by // all threads in the process. (With LinuxThreads, and with NPTL on some // Linux kernel versions, each thread has separate timers.) // // Prior to determining whether timers are shared, this function will // unconditionally start the timer. However, if this function determines // that timers are shared, then it will stop the timer if no callbacks are // currently registered. void RegisterThread(); // Registers a callback routine to receive profile timer ticks. The returned // token is to be used when unregistering this callback and must not be // deleted by the caller. Registration of the first callback enables the // SIGPROF handler (or SIGALRM if using ITIMER_REAL). ProfileHandlerToken* RegisterCallback(ProfileHandlerCallback callback, void* callback_arg); // Unregisters a previously registered callback. Expects the token returned // by the corresponding RegisterCallback routine. Unregistering the last // callback disables the SIGPROF handler (or SIGALRM if using ITIMER_REAL). void UnregisterCallback(ProfileHandlerToken* token) NO_THREAD_SAFETY_ANALYSIS; // Unregisters all the callbacks, stops the timer if shared, disables the // SIGPROF (or SIGALRM) handler and clears the timer_sharing_ state. void Reset(); // Gets the current state of profile handler. void GetState(ProfileHandlerState* state); // Initializes and returns the ProfileHandler singleton. static ProfileHandler* Instance(); private: ProfileHandler(); ~ProfileHandler(); // Largest allowed frequency. static const int32 kMaxFrequency = 4000; // Default frequency. static const int32 kDefaultFrequency = 100; // ProfileHandler singleton. static ProfileHandler* instance_; // pthread_once_t for one time initialization of ProfileHandler singleton. static pthread_once_t once_; // Initializes the ProfileHandler singleton via GoogleOnceInit. static void Init(); // The number of SIGPROF (or SIGALRM for ITIMER_REAL) interrupts received. int64 interrupts_ GUARDED_BY(signal_lock_); // SIGPROF/SIGALRM interrupt frequency, read-only after construction. int32 frequency_; // ITIMER_PROF (which uses SIGPROF), or ITIMER_REAL (which uses SIGALRM) int timer_type_; // Counts the number of callbacks registered. int32 callback_count_ GUARDED_BY(control_lock_); // Whether or not the threading system provides interval timers that are // shared by all threads in a process. enum { // No timer initialization attempted yet. TIMERS_UNTOUCHED, // First thread has registered and set timer. TIMERS_ONE_SET, // Timers are shared by all threads. TIMERS_SHARED, // Timers are separate in each thread. TIMERS_SEPARATE } timer_sharing_ GUARDED_BY(control_lock_); // This lock serializes the registration of threads and protects the // callbacks_ list below. // Locking order: // In the context of a signal handler, acquire signal_lock_ to walk the // callback list. Otherwise, acquire control_lock_, disable the signal // handler and then acquire signal_lock_. SpinLock control_lock_ ACQUIRED_BEFORE(signal_lock_); SpinLock signal_lock_; // Holds the list of registered callbacks. We expect the list to be pretty // small. Currently, the cpu profiler (base/profiler) and thread module // (base/thread.h) are the only two components registering callbacks. // Following are the locking requirements for callbacks_: // For read-write access outside the SIGPROF handler: // - Acquire control_lock_ // - Disable SIGPROF handler. // - Acquire signal_lock_ // For read-only access in the context of SIGPROF handler // (Read-write access is *not allowed* in the SIGPROF handler) // - Acquire signal_lock_ // For read-only access outside SIGPROF handler: // - Acquire control_lock_ typedef list CallbackList; typedef CallbackList::iterator CallbackIterator; CallbackList callbacks_ GUARDED_BY(signal_lock_); // Starts the interval timer. If the thread library shares timers between // threads, this function starts the shared timer. Otherwise, this will start // the timer in the current thread. void StartTimer() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); // Stops the interval timer. If the thread library shares timers between // threads, this fucntion stops the shared timer. Otherwise, this will stop // the timer in the current thread. void StopTimer() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); // Returns true if the profile interval timer is enabled in the current // thread. This actually checks the kernel's interval timer setting. (It is // used to detect whether timers are shared or separate.) bool IsTimerRunning() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); // Sets the timer interrupt signal handler. void EnableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); // Disables (ignores) the timer interrupt signal. void DisableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); // SIGPROF/SIGALRM handler. Iterate over and call all the registered callbacks. static void SignalHandler(int sig, siginfo_t* sinfo, void* ucontext); DISALLOW_COPY_AND_ASSIGN(ProfileHandler); }; ProfileHandler* ProfileHandler::instance_ = NULL; pthread_once_t ProfileHandler::once_ = PTHREAD_ONCE_INIT; const int32 ProfileHandler::kMaxFrequency; const int32 ProfileHandler::kDefaultFrequency; // If we are LD_PRELOAD-ed against a non-pthreads app, then // pthread_once won't be defined. We declare it here, for that // case (with weak linkage) which will cause the non-definition to // resolve to NULL. We can then check for NULL or not in Instance. extern "C" int pthread_once(pthread_once_t *, void (*)(void)) ATTRIBUTE_WEAK; void ProfileHandler::Init() { instance_ = new ProfileHandler(); } ProfileHandler* ProfileHandler::Instance() { if (pthread_once) { pthread_once(&once_, Init); } if (instance_ == NULL) { // This will be true on systems that don't link in pthreads, // including on FreeBSD where pthread_once has a non-zero address // (but doesn't do anything) even when pthreads isn't linked in. Init(); assert(instance_ != NULL); } return instance_; } ProfileHandler::ProfileHandler() : interrupts_(0), callback_count_(0), timer_sharing_(TIMERS_UNTOUCHED) { SpinLockHolder cl(&control_lock_); timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF); // Get frequency of interrupts (if specified) char junk; const char* fr = getenv("CPUPROFILE_FREQUENCY"); if (fr != NULL && (sscanf(fr, "%u%c", &frequency_, &junk) == 1) && (frequency_ > 0)) { // Limit to kMaxFrequency frequency_ = (frequency_ > kMaxFrequency) ? kMaxFrequency : frequency_; } else { frequency_ = kDefaultFrequency; } // Ignore signals until we decide to turn profiling on. (Paranoia; // should already be ignored.) DisableHandler(); } ProfileHandler::~ProfileHandler() { Reset(); } void ProfileHandler::RegisterThread() { SpinLockHolder cl(&control_lock_); // We try to detect whether timers are being shared by setting a // timer in the first call to this function, then checking whether // it's set in the second call. // // Note that this detection method requires that the first two calls // to RegisterThread must be made from different threads. (Subsequent // calls will see timer_sharing_ set to either TIMERS_SEPARATE or // TIMERS_SHARED, and won't try to detect the timer sharing type.) // // Also note that if timer settings were inherited across new thread // creation but *not* shared, this approach wouldn't work. That's // not an issue for any Linux threading implementation, and should // not be a problem for a POSIX-compliant threads implementation. switch (timer_sharing_) { case TIMERS_UNTOUCHED: StartTimer(); timer_sharing_ = TIMERS_ONE_SET; break; case TIMERS_ONE_SET: // If the timer is running, that means that the main thread's // timer setup is seen in this (second) thread -- and therefore // that timers are shared. if (IsTimerRunning()) { timer_sharing_ = TIMERS_SHARED; // If callback is already registered, we have to keep the timer // running. If not, we disable the timer here. if (callback_count_ == 0) { StopTimer(); } } else { timer_sharing_ = TIMERS_SEPARATE; StartTimer(); } break; case TIMERS_SHARED: // Nothing needed. break; case TIMERS_SEPARATE: StartTimer(); break; } } ProfileHandlerToken* ProfileHandler::RegisterCallback( ProfileHandlerCallback callback, void* callback_arg) { ProfileHandlerToken* token = new ProfileHandlerToken(callback, callback_arg); SpinLockHolder cl(&control_lock_); DisableHandler(); { SpinLockHolder sl(&signal_lock_); callbacks_.push_back(token); } // Start the timer if timer is shared and this is a first callback. if ((callback_count_ == 0) && (timer_sharing_ == TIMERS_SHARED)) { StartTimer(); } ++callback_count_; EnableHandler(); return token; } void ProfileHandler::UnregisterCallback(ProfileHandlerToken* token) { SpinLockHolder cl(&control_lock_); for (CallbackIterator it = callbacks_.begin(); it != callbacks_.end(); ++it) { if ((*it) == token) { RAW_CHECK(callback_count_ > 0, "Invalid callback count"); DisableHandler(); { SpinLockHolder sl(&signal_lock_); delete *it; callbacks_.erase(it); } --callback_count_; if (callback_count_ > 0) { EnableHandler(); } else if (timer_sharing_ == TIMERS_SHARED) { StopTimer(); } return; } } // Unknown token. RAW_LOG(FATAL, "Invalid token"); } void ProfileHandler::Reset() { SpinLockHolder cl(&control_lock_); DisableHandler(); { SpinLockHolder sl(&signal_lock_); CallbackIterator it = callbacks_.begin(); while (it != callbacks_.end()) { CallbackIterator tmp = it; ++it; delete *tmp; callbacks_.erase(tmp); } } callback_count_ = 0; if (timer_sharing_ == TIMERS_SHARED) { StopTimer(); } timer_sharing_ = TIMERS_UNTOUCHED; } void ProfileHandler::GetState(ProfileHandlerState* state) { SpinLockHolder cl(&control_lock_); DisableHandler(); { SpinLockHolder sl(&signal_lock_); // Protects interrupts_. state->interrupts = interrupts_; } if (callback_count_ > 0) { EnableHandler(); } state->frequency = frequency_; state->callback_count = callback_count_; } void ProfileHandler::StartTimer() { struct itimerval timer; timer.it_interval.tv_sec = 0; timer.it_interval.tv_usec = 1000000 / frequency_; timer.it_value = timer.it_interval; setitimer(timer_type_, &timer, 0); } void ProfileHandler::StopTimer() { struct itimerval timer; memset(&timer, 0, sizeof timer); setitimer(timer_type_, &timer, 0); } bool ProfileHandler::IsTimerRunning() { struct itimerval current_timer; RAW_CHECK(0 == getitimer(timer_type_, ¤t_timer), "getitimer"); return (current_timer.it_value.tv_sec != 0 || current_timer.it_value.tv_usec != 0); } void ProfileHandler::EnableHandler() { struct sigaction sa; sa.sa_sigaction = SignalHandler; sa.sa_flags = SA_RESTART | SA_SIGINFO; sigemptyset(&sa.sa_mask); const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (enable)"); } void ProfileHandler::DisableHandler() { struct sigaction sa; sa.sa_handler = SIG_IGN; sa.sa_flags = SA_RESTART; sigemptyset(&sa.sa_mask); const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (disable)"); } void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) { int saved_errno = errno; RAW_CHECK(instance_ != NULL, "ProfileHandler is not initialized"); { SpinLockHolder sl(&instance_->signal_lock_); ++instance_->interrupts_; for (CallbackIterator it = instance_->callbacks_.begin(); it != instance_->callbacks_.end(); ++it) { (*it)->callback(sig, sinfo, ucontext, (*it)->callback_arg); } } errno = saved_errno; } // The sole purpose of this class is to initialize the ProfileHandler singleton // when the global static objects are created. Note that the main thread will // be registered at this time. class ProfileHandlerInitializer { public: ProfileHandlerInitializer() { ProfileHandler::Instance()->RegisterThread(); } private: DISALLOW_COPY_AND_ASSIGN(ProfileHandlerInitializer); }; // ProfileHandlerInitializer singleton static ProfileHandlerInitializer profile_handler_initializer; extern "C" void ProfileHandlerRegisterThread() { ProfileHandler::Instance()->RegisterThread(); } extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback( ProfileHandlerCallback callback, void* callback_arg) { return ProfileHandler::Instance()->RegisterCallback(callback, callback_arg); } extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) { ProfileHandler::Instance()->UnregisterCallback(token); } extern "C" void ProfileHandlerReset() { return ProfileHandler::Instance()->Reset(); } extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) { ProfileHandler::Instance()->GetState(state); } #else // OS_CYGWIN // ITIMER_PROF doesn't work under cygwin. ITIMER_REAL is available, but doesn't // work as well for profiling, and also interferes with alarm(). Because of // these issues, unless a specific need is identified, profiler support is // disabled under Cygwin. extern "C" void ProfileHandlerRegisterThread() { } extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback( ProfileHandlerCallback callback, void* callback_arg) { return NULL; } extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) { } extern "C" void ProfileHandlerReset() { } extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) { } #endif // OS_CYGWIN ================================================ FILE: distro/google-perftools-1.7/src/profile-handler.h ================================================ /* Copyright (c) 2009, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Nabeel Mian * * This module manages the cpu profile timers and the associated interrupt * handler. When enabled, all registered threads in the program are profiled. * (Note: if using linux 2.4 or earlier, you must use the Thread class, in * google3/thread, to ensure all threads are profiled.) * * Any component interested in receiving a profile timer interrupt can do so by * registering a callback. All registered callbacks must be async-signal-safe. * * Note: This module requires the sole ownership of ITIMER_PROF timer and the * SIGPROF signal. */ #ifndef BASE_PROFILE_HANDLER_H_ #define BASE_PROFILE_HANDLER_H_ #include "config.h" #include #ifdef COMPILER_MSVC #include "conflict-signal.h" #endif #include "base/basictypes.h" /* All this code should be usable from within C apps. */ #ifdef __cplusplus extern "C" { #endif /* Forward declaration. */ struct ProfileHandlerToken; /* * Callback function to be used with ProfilefHandlerRegisterCallback. This * function will be called in the context of SIGPROF signal handler and must * be async-signal-safe. The first three arguments are the values provided by * the SIGPROF signal handler. We use void* to avoid using ucontext_t on * non-POSIX systems. * * Requirements: * - Callback must be async-signal-safe. * - None of the functions in ProfileHandler are async-signal-safe. Therefore, * callback function *must* not call any of the ProfileHandler functions. * - Callback is not required to be re-entrant. At most one instance of * callback can run at a time. * * Notes: * - The SIGPROF signal handler saves and restores errno, so the callback * doesn't need to. * - Callback code *must* not acquire lock(s) to serialize access to data shared * with the code outside the signal handler (callback must be * async-signal-safe). If such a serialization is needed, follow the model * used by profiler.cc: * * When code other than the signal handler modifies the shared data it must: * - Acquire lock. * - Unregister the callback with the ProfileHandler. * - Modify shared data. * - Re-register the callback. * - Release lock. * and the callback code gets a lockless, read-write access to the data. */ typedef void (*ProfileHandlerCallback)(int sig, siginfo_t* sig_info, void* ucontext, void* callback_arg); /* * Registers a new thread with profile handler and should be called only once * per thread. The main thread is registered at program startup. This routine * is called by the Thread module in google3/thread whenever a new thread is * created. This function is not async-signal-safe. */ void ProfileHandlerRegisterThread(); /* * Registers a callback routine. This callback function will be called in the * context of SIGPROF handler, so must be async-signal-safe. The returned token * is to be used when unregistering this callback via * ProfileHandlerUnregisterCallback. Registering the first callback enables * the SIGPROF signal handler. Caller must not free the returned token. This * function is not async-signal-safe. */ ProfileHandlerToken* ProfileHandlerRegisterCallback( ProfileHandlerCallback callback, void* callback_arg); /* * Unregisters a previously registered callback. Expects the token returned * by the corresponding ProfileHandlerRegisterCallback and asserts that the * passed token is valid. Unregistering the last callback disables the SIGPROF * signal handler. It waits for the currently running callback to * complete before returning. This function is not async-signal-safe. */ void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token); /* * FOR TESTING ONLY * Unregisters all the callbacks, stops the timers (if shared) and disables the * SIGPROF handler. All the threads, including the main thread, need to be * re-registered after this call. This function is not async-signal-safe. */ void ProfileHandlerReset(); /* * Stores profile handler's current state. This function is not * async-signal-safe. */ struct ProfileHandlerState { int32 frequency; /* Profiling frequency */ int32 callback_count; /* Number of callbacks registered */ int64 interrupts; /* Number of interrupts received */ }; void ProfileHandlerGetState(struct ProfileHandlerState* state); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* BASE_PROFILE_HANDLER_H_ */ ================================================ FILE: distro/google-perftools-1.7/src/profiledata.cc ================================================ // Copyright (c) 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // --- // Author: Sanjay Ghemawat // Chris Demetriou (refactoring) // // Collect profiling data. #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include "profiledata.h" #include "base/logging.h" #include "base/sysinfo.h" // All of these are initialized in profiledata.h. const int ProfileData::kMaxStackDepth; const int ProfileData::kAssociativity; const int ProfileData::kBuckets; const int ProfileData::kBufferLength; ProfileData::Options::Options() : frequency_(1) { } // This function is safe to call from asynchronous signals (but is not // re-entrant). However, that's not part of its public interface. void ProfileData::Evict(const Entry& entry) { const int d = entry.depth; const int nslots = d + 2; // Number of slots needed in eviction buffer if (num_evicted_ + nslots > kBufferLength) { FlushEvicted(); assert(num_evicted_ == 0); assert(nslots <= kBufferLength); } evict_[num_evicted_++] = entry.count; evict_[num_evicted_++] = d; memcpy(&evict_[num_evicted_], entry.stack, d * sizeof(Slot)); num_evicted_ += d; } ProfileData::ProfileData() : hash_(0), evict_(0), num_evicted_(0), out_(-1), count_(0), evictions_(0), total_bytes_(0), fname_(0), start_time_(0) { } bool ProfileData::Start(const char* fname, const ProfileData::Options& options) { if (enabled()) { return false; } // Open output file and initialize various data structures int fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0666); if (fd < 0) { // Can't open outfile for write return false; } start_time_ = time(NULL); fname_ = strdup(fname); // Reset counters num_evicted_ = 0; count_ = 0; evictions_ = 0; total_bytes_ = 0; hash_ = new Bucket[kBuckets]; evict_ = new Slot[kBufferLength]; memset(hash_, 0, sizeof(hash_[0]) * kBuckets); // Record special entries evict_[num_evicted_++] = 0; // count for header evict_[num_evicted_++] = 3; // depth for header evict_[num_evicted_++] = 0; // Version number CHECK_NE(0, options.frequency()); int period = 1000000 / options.frequency(); evict_[num_evicted_++] = period; // Period (microseconds) evict_[num_evicted_++] = 0; // Padding out_ = fd; return true; } ProfileData::~ProfileData() { Stop(); } // Dump /proc/maps data to fd. Copied from heap-profile-table.cc. #define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR) static void FDWrite(int fd, const char* buf, size_t len) { while (len > 0) { ssize_t r; NO_INTR(r = write(fd, buf, len)); RAW_CHECK(r >= 0, "write failed"); buf += r; len -= r; } } static void DumpProcSelfMaps(int fd) { ProcMapsIterator::Buffer iterbuf; ProcMapsIterator it(0, &iterbuf); // 0 means "current pid" uint64 start, end, offset; int64 inode; char *flags, *filename; ProcMapsIterator::Buffer linebuf; while (it.Next(&start, &end, &flags, &offset, &inode, &filename)) { int written = it.FormatLine(linebuf.buf_, sizeof(linebuf.buf_), start, end, flags, offset, inode, filename, 0); FDWrite(fd, linebuf.buf_, written); } } void ProfileData::Stop() { if (!enabled()) { return; } // Move data from hash table to eviction buffer for (int b = 0; b < kBuckets; b++) { Bucket* bucket = &hash_[b]; for (int a = 0; a < kAssociativity; a++) { if (bucket->entry[a].count > 0) { Evict(bucket->entry[a]); } } } if (num_evicted_ + 3 > kBufferLength) { // Ensure there is enough room for end of data marker FlushEvicted(); } // Write end of data marker evict_[num_evicted_++] = 0; // count evict_[num_evicted_++] = 1; // depth evict_[num_evicted_++] = 0; // end of data marker FlushEvicted(); // Dump "/proc/self/maps" so we get list of mapped shared libraries DumpProcSelfMaps(out_); Reset(); fprintf(stderr, "PROFILE: interrupts/evictions/bytes = %d/%d/%" PRIuS "\n", count_, evictions_, total_bytes_); } void ProfileData::Reset() { if (!enabled()) { return; } // Don't reset count_, evictions_, or total_bytes_ here. They're used // by Stop to print information about the profile after reset, and are // cleared by Start when starting a new profile. close(out_); delete[] hash_; hash_ = 0; delete[] evict_; evict_ = 0; num_evicted_ = 0; free(fname_); fname_ = 0; start_time_ = 0; out_ = -1; } // This function is safe to call from asynchronous signals (but is not // re-entrant). However, that's not part of its public interface. void ProfileData::GetCurrentState(State* state) const { if (enabled()) { state->enabled = true; state->start_time = start_time_; state->samples_gathered = count_; int buf_size = sizeof(state->profile_name); strncpy(state->profile_name, fname_, buf_size); state->profile_name[buf_size-1] = '\0'; } else { state->enabled = false; state->start_time = 0; state->samples_gathered = 0; state->profile_name[0] = '\0'; } } // This function is safe to call from asynchronous signals (but is not // re-entrant). However, that's not part of its public interface. void ProfileData::FlushTable() { if (!enabled()) { return; } // Move data from hash table to eviction buffer for (int b = 0; b < kBuckets; b++) { Bucket* bucket = &hash_[b]; for (int a = 0; a < kAssociativity; a++) { if (bucket->entry[a].count > 0) { Evict(bucket->entry[a]); bucket->entry[a].depth = 0; bucket->entry[a].count = 0; } } } // Write out all pending data FlushEvicted(); } void ProfileData::Add(int depth, const void* const* stack) { if (!enabled()) { return; } if (depth > kMaxStackDepth) depth = kMaxStackDepth; RAW_CHECK(depth > 0, "ProfileData::Add depth <= 0"); // Make hash-value Slot h = 0; for (int i = 0; i < depth; i++) { Slot slot = reinterpret_cast(stack[i]); h = (h << 8) | (h >> (8*(sizeof(h)-1))); h += (slot * 31) + (slot * 7) + (slot * 3); } count_++; // See if table already has an entry for this trace bool done = false; Bucket* bucket = &hash_[h % kBuckets]; for (int a = 0; a < kAssociativity; a++) { Entry* e = &bucket->entry[a]; if (e->depth == depth) { bool match = true; for (int i = 0; i < depth; i++) { if (e->stack[i] != reinterpret_cast(stack[i])) { match = false; break; } } if (match) { e->count++; done = true; break; } } } if (!done) { // Evict entry with smallest count Entry* e = &bucket->entry[0]; for (int a = 1; a < kAssociativity; a++) { if (bucket->entry[a].count < e->count) { e = &bucket->entry[a]; } } if (e->count > 0) { evictions_++; Evict(*e); } // Use the newly evicted entry e->depth = depth; e->count = 1; for (int i = 0; i < depth; i++) { e->stack[i] = reinterpret_cast(stack[i]); } } } // This function is safe to call from asynchronous signals (but is not // re-entrant). However, that's not part of its public interface. void ProfileData::FlushEvicted() { if (num_evicted_ > 0) { const char* buf = reinterpret_cast(evict_); size_t bytes = sizeof(evict_[0]) * num_evicted_; total_bytes_ += bytes; FDWrite(out_, buf, bytes); } num_evicted_ = 0; } ================================================ FILE: distro/google-perftools-1.7/src/profiledata.h ================================================ // Copyright (c) 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // --- // Author: Sanjay Ghemawat // Chris Demetriou (refactoring) // // Collect profiling data. // // The profile data file format is documented in // doc/cpuprofile-fileformat.html #ifndef BASE_PROFILEDATA_H_ #define BASE_PROFILEDATA_H_ #include #include // for time_t #include #include "base/basictypes.h" // A class that accumulates profile samples and writes them to a file. // // Each sample contains a stack trace and a count. Memory usage is // reduced by combining profile samples that have the same stack trace // by adding up the associated counts. // // Profile data is accumulated in a bounded amount of memory, and will // flushed to a file as necessary to stay within the memory limit. // // Use of this class assumes external synchronization. The exact // requirements of that synchronization are that: // // - 'Add' may be called from asynchronous signals, but is not // re-entrant. // // - None of 'Start', 'Stop', 'Reset', 'Flush', and 'Add' may be // called at the same time. // // - 'Start', 'Stop', or 'Reset' should not be called while 'Enabled' // or 'GetCurrent' are running, and vice versa. // // A profiler which uses asyncronous signals to add samples will // typically use two locks to protect this data structure: // // - A SpinLock which is held over all calls except for the 'Add' // call made from the signal handler. // // - A SpinLock which is held over calls to 'Start', 'Stop', 'Reset', // 'Flush', and 'Add'. (This SpinLock should be acquired after // the first SpinLock in all cases where both are needed.) class ProfileData { public: struct State { bool enabled; // Is profiling currently enabled? time_t start_time; // If enabled, when was profiling started? char profile_name[1024]; // Name of file being written, or '\0' int samples_gathered; // Number of samples gathered to far (or 0) }; class Options { public: Options(); // Get and set the sample frequency. int frequency() const { return frequency_; } void set_frequency(int frequency) { frequency_ = frequency; } private: int frequency_; // Sample frequency. }; static const int kMaxStackDepth = 64; // Max stack depth stored in profile ProfileData(); ~ProfileData(); // If data collection is not already enabled start to collect data // into fname. Parameters related to this profiling run are specified // by 'options'. // // Returns true if data collection could be started, otherwise (if an // error occurred or if data collection was already enabled) returns // false. bool Start(const char *fname, const Options& options); // If data collection is enabled, stop data collection and write the // data to disk. void Stop(); // Stop data collection without writing anything else to disk, and // discard any collected data. void Reset(); // If data collection is enabled, record a sample with 'depth' // entries from 'stack'. (depth must be > 0.) At most // kMaxStackDepth stack entries will be recorded, starting with // stack[0]. // // This function is safe to call from asynchronous signals (but is // not re-entrant). void Add(int depth, const void* const* stack); // If data collection is enabled, write the data to disk (and leave // the collector enabled). void FlushTable(); // Is data collection currently enabled? bool enabled() const { return out_ >= 0; } // Get the current state of the data collector. void GetCurrentState(State* state) const; private: static const int kAssociativity = 4; // For hashtable static const int kBuckets = 1 << 10; // For hashtable static const int kBufferLength = 1 << 18; // For eviction buffer // Type of slots: each slot can be either a count, or a PC value typedef uintptr_t Slot; // Hash-table/eviction-buffer entry (a.k.a. a sample) struct Entry { Slot count; // Number of hits Slot depth; // Stack depth Slot stack[kMaxStackDepth]; // Stack contents }; // Hash table bucket struct Bucket { Entry entry[kAssociativity]; }; Bucket* hash_; // hash table Slot* evict_; // evicted entries int num_evicted_; // how many evicted entries? int out_; // fd for output file. int count_; // How many samples recorded int evictions_; // How many evictions size_t total_bytes_; // How much output char* fname_; // Profile file name time_t start_time_; // Start time, or 0 // Move 'entry' to the eviction buffer. void Evict(const Entry& entry); // Write contents of eviction buffer to disk. void FlushEvicted(); DISALLOW_COPY_AND_ASSIGN(ProfileData); }; #endif // BASE_PROFILEDATA_H_ ================================================ FILE: distro/google-perftools-1.7/src/profiler.cc ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // Chris Demetriou (refactoring) // // Profile current program by sampling stack-trace every so often #include "config.h" #include "getpc.h" // should be first to get the _GNU_SOURCE dfn #include #include #include #include #include #ifdef HAVE_UNISTD_H #include // for getpid() #endif #if defined(HAVE_SYS_UCONTEXT_H) #include #elif defined(HAVE_UCONTEXT_H) #include #elif defined(HAVE_CYGWIN_SIGNAL_H) #include typedef ucontext ucontext_t; #else typedef int ucontext_t; // just to quiet the compiler, mostly #endif #include #include #include #include #include "base/commandlineflags.h" #include "base/logging.h" #include "base/googleinit.h" #include "base/spinlock.h" #include "base/sysinfo.h" /* for GetUniquePathFromEnv, etc */ #include "profiledata.h" #include "profile-handler.h" #ifdef HAVE_CONFLICT_SIGNAL_H #include "conflict-signal.h" /* used on msvc machines */ #endif using std::string; // Collects up all profile data. This is a singleton, which is // initialized by a constructor at startup. class CpuProfiler { public: CpuProfiler(); ~CpuProfiler(); // Start profiler to write profile info into fname bool Start(const char* fname, const ProfilerOptions* options); // Stop profiling and write the data to disk. void Stop(); // Write the data to disk (and continue profiling). void FlushTable(); bool Enabled(); void GetCurrentState(ProfilerState* state); static CpuProfiler instance_; private: // This lock implements the locking requirements described in the ProfileData // documentation, specifically: // // lock_ is held all over all collector_ method calls except for the 'Add' // call made from the signal handler, to protect against concurrent use of // collector_'s control routines. Code other than signal handler must // unregister the signal handler before calling any collector_ method. // 'Add' method in the collector is protected by a guarantee from // ProfileHandle that only one instance of prof_handler can run at a time. SpinLock lock_; ProfileData collector_; // Filter function and its argument, if any. (NULL means include all // samples). Set at start, read-only while running. Written while holding // lock_, read and executed in the context of SIGPROF interrupt. int (*filter_)(void*); void* filter_arg_; // Opaque token returned by the profile handler. To be used when calling // ProfileHandlerUnregisterCallback. ProfileHandlerToken* prof_handler_token_; // Sets up a callback to receive SIGPROF interrupt. void EnableHandler(); // Disables receiving SIGPROF interrupt. void DisableHandler(); // Signal handler that records the interrupted pc in the profile data. static void prof_handler(int sig, siginfo_t*, void* signal_ucontext, void* cpu_profiler); }; // Profile data structure singleton: Constructor will check to see if // profiling should be enabled. Destructor will write profile data // out to disk. CpuProfiler CpuProfiler::instance_; // Initialize profiling: activated if getenv("CPUPROFILE") exists. CpuProfiler::CpuProfiler() : prof_handler_token_(NULL) { // TODO(cgd) Move this code *out* of the CpuProfile constructor into a // separate object responsible for initialization. With ProfileHandler there // is no need to limit the number of profilers. char fname[PATH_MAX]; if (!GetUniquePathFromEnv("CPUPROFILE", fname)) { return; } // We don't enable profiling if setuid -- it's a security risk #ifdef HAVE_GETEUID if (getuid() != geteuid()) return; #endif if (!Start(fname, NULL)) { RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n", fname, strerror(errno)); } } bool CpuProfiler::Start(const char* fname, const ProfilerOptions* options) { SpinLockHolder cl(&lock_); if (collector_.enabled()) { return false; } ProfileHandlerState prof_handler_state; ProfileHandlerGetState(&prof_handler_state); ProfileData::Options collector_options; collector_options.set_frequency(prof_handler_state.frequency); if (!collector_.Start(fname, collector_options)) { return false; } filter_ = NULL; if (options != NULL && options->filter_in_thread != NULL) { filter_ = options->filter_in_thread; filter_arg_ = options->filter_in_thread_arg; } // Setup handler for SIGPROF interrupts EnableHandler(); return true; } CpuProfiler::~CpuProfiler() { Stop(); } // Stop profiling and write out any collected profile data void CpuProfiler::Stop() { SpinLockHolder cl(&lock_); if (!collector_.enabled()) { return; } // Unregister prof_handler to stop receiving SIGPROF interrupts before // stopping the collector. DisableHandler(); // DisableHandler waits for the currently running callback to complete and // guarantees no future invocations. It is safe to stop the collector. collector_.Stop(); } void CpuProfiler::FlushTable() { SpinLockHolder cl(&lock_); if (!collector_.enabled()) { return; } // Unregister prof_handler to stop receiving SIGPROF interrupts before // flushing the profile data. DisableHandler(); // DisableHandler waits for the currently running callback to complete and // guarantees no future invocations. It is safe to flush the profile data. collector_.FlushTable(); EnableHandler(); } bool CpuProfiler::Enabled() { SpinLockHolder cl(&lock_); return collector_.enabled(); } void CpuProfiler::GetCurrentState(ProfilerState* state) { ProfileData::State collector_state; { SpinLockHolder cl(&lock_); collector_.GetCurrentState(&collector_state); } state->enabled = collector_state.enabled; state->start_time = static_cast(collector_state.start_time); state->samples_gathered = collector_state.samples_gathered; int buf_size = sizeof(state->profile_name); strncpy(state->profile_name, collector_state.profile_name, buf_size); state->profile_name[buf_size-1] = '\0'; } void CpuProfiler::EnableHandler() { RAW_CHECK(prof_handler_token_ == NULL, "SIGPROF handler already registered"); prof_handler_token_ = ProfileHandlerRegisterCallback(prof_handler, this); RAW_CHECK(prof_handler_token_ != NULL, "Failed to set up SIGPROF handler"); } void CpuProfiler::DisableHandler() { RAW_CHECK(prof_handler_token_ != NULL, "SIGPROF handler is not registered"); ProfileHandlerUnregisterCallback(prof_handler_token_); prof_handler_token_ = NULL; } // Signal handler that records the pc in the profile-data structure. We do no // synchronization here. profile-handler.cc guarantees that at most one // instance of prof_handler() will run at a time. All other routines that // access the data touched by prof_handler() disable this signal handler before // accessing the data and therefore cannot execute concurrently with // prof_handler(). void CpuProfiler::prof_handler(int sig, siginfo_t*, void* signal_ucontext, void* cpu_profiler) { CpuProfiler* instance = static_cast(cpu_profiler); if (instance->filter_ == NULL || (*instance->filter_)(instance->filter_arg_)) { void* stack[ProfileData::kMaxStackDepth]; // The top-most active routine doesn't show up as a normal // frame, but as the "pc" value in the signal handler context. stack[0] = GetPC(*reinterpret_cast(signal_ucontext)); // We skip the top two stack trace entries (this function and one // signal handler frame) since they are artifacts of profiling and // should not be measured. Other profiling related frames may be // removed by "pprof" at analysis time. Instead of skipping the top // frames, we could skip nothing, but that would increase the // profile size unnecessarily. int depth = GetStackTraceWithContext(stack + 1, arraysize(stack) - 1, 2, signal_ucontext); depth++; // To account for pc value in stack[0]; instance->collector_.Add(depth, stack); } } #if !(defined(__CYGWIN__) || defined(__CYGWIN32__)) extern "C" PERFTOOLS_DLL_DECL void ProfilerRegisterThread() { ProfileHandlerRegisterThread(); } extern "C" PERFTOOLS_DLL_DECL void ProfilerFlush() { CpuProfiler::instance_.FlushTable(); } extern "C" PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads() { return CpuProfiler::instance_.Enabled(); } extern "C" PERFTOOLS_DLL_DECL int ProfilerStart(const char* fname) { return CpuProfiler::instance_.Start(fname, NULL); } extern "C" PERFTOOLS_DLL_DECL int ProfilerStartWithOptions( const char *fname, const ProfilerOptions *options) { return CpuProfiler::instance_.Start(fname, options); } extern "C" PERFTOOLS_DLL_DECL void ProfilerStop() { CpuProfiler::instance_.Stop(); } extern "C" PERFTOOLS_DLL_DECL void ProfilerGetCurrentState( ProfilerState* state) { CpuProfiler::instance_.GetCurrentState(state); } #else // OS_CYGWIN // ITIMER_PROF doesn't work under cygwin. ITIMER_REAL is available, but doesn't // work as well for profiling, and also interferes with alarm(). Because of // these issues, unless a specific need is identified, profiler support is // disabled under Cygwin. extern "C" void ProfilerRegisterThread() { } extern "C" void ProfilerFlush() { } extern "C" int ProfilingIsEnabledForAllThreads() { return 0; } extern "C" int ProfilerStart(const char* fname) { return 0; } extern "C" int ProfilerStartWithOptions(const char *fname, const ProfilerOptions *options) { return 0; } extern "C" void ProfilerStop() { } extern "C" void ProfilerGetCurrentState(ProfilerState* state) { memset(state, 0, sizeof(*state)); } #endif // OS_CYGWIN // DEPRECATED routines extern "C" PERFTOOLS_DLL_DECL void ProfilerEnable() { } extern "C" PERFTOOLS_DLL_DECL void ProfilerDisable() { } ================================================ FILE: distro/google-perftools-1.7/src/raw_printer.cc ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: sanjay@google.com (Sanjay Ghemawat) #include #include #include #include "raw_printer.h" #include "base/logging.h" namespace base { RawPrinter::RawPrinter(char* buf, int length) : base_(buf), ptr_(buf), limit_(buf + length - 1) { RAW_DCHECK(length > 0, ""); *ptr_ = '\0'; *limit_ = '\0'; } void RawPrinter::Printf(const char* format, ...) { if (limit_ > ptr_) { va_list ap; va_start(ap, format); int avail = limit_ - ptr_; // We pass avail+1 to vsnprintf() since that routine needs room // to store the trailing \0. const int r = vsnprintf(ptr_, avail+1, format, ap); va_end(ap); if (r < 0) { // Perhaps an old glibc that returns -1 on truncation? ptr_ = limit_; } else if (r > avail) { // Truncation ptr_ = limit_; } else { ptr_ += r; } } } } ================================================ FILE: distro/google-perftools-1.7/src/raw_printer.h ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // A printf() wrapper that writes into a fixed length buffer. // Useful in low-level code that does not want to use allocating // routines like StringPrintf(). // // The implementation currently uses vsnprintf(). This seems to // be fine for use in many low-level contexts, but we may need to // rethink this decision if we hit a problem with it calling // down into malloc() etc. #ifndef BASE_RAW_PRINTER_H_ #define BASE_RAW_PRINTER_H_ #include #include "base/basictypes.h" namespace base { class RawPrinter { public: // REQUIRES: "length > 0" // Will printf any data added to this into "buf[0,length-1]" and // will arrange to always keep buf[] null-terminated. RawPrinter(char* buf, int length); // Return the number of bytes that have been appended to the string // so far. Does not count any bytes that were dropped due to overflow. int length() const { return (ptr_ - base_); } // Return the number of bytes that can be added to this. int space_left() const { return (limit_ - ptr_); } // Format the supplied arguments according to the "format" string // and append to this. Will silently truncate the output if it does // not fit. void Printf(const char* format, ...) #ifdef HAVE___ATTRIBUTE__ __attribute__ ((__format__ (__printf__, 2, 3))) #endif ; private: // We can write into [ptr_ .. limit_-1]. // *limit_ is also writable, but reserved for a terminating \0 // in case we overflow. // // Invariants: *ptr_ == \0 // Invariants: *limit_ == \0 char* base_; // Initial pointer char* ptr_; // Where should we write next char* limit_; // One past last non-\0 char we can write DISALLOW_COPY_AND_ASSIGN(RawPrinter); }; } #endif // BASE_RAW_PRINTER_H_ ================================================ FILE: distro/google-perftools-1.7/src/sampler.cc ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // All Rights Reserved. // // Author: Daniel Ford #include "sampler.h" #include // For min() #include using std::min; // The approximate gap in bytes between sampling actions. // I.e., we take one sample approximately once every // tcmalloc_sample_parameter bytes of allocation // i.e. about once every 512KB if value is 1<<19. #ifdef NO_TCMALLOC_SAMPLES DEFINE_int64(tcmalloc_sample_parameter, 0, "Unused: code is compiled with NO_TCMALLOC_SAMPLES"); #else DEFINE_int64(tcmalloc_sample_parameter, EnvToInt64("TCMALLOC_SAMPLE_PARAMETER", 0), "The approximate gap in bytes between sampling actions. " "This must be between 1 and 2^58."); #endif namespace tcmalloc { // Statics for Sampler double Sampler::log_table_[1<(i+0.5)/(1<(reinterpret_cast(this)); if (rnd_ == 0) { rnd_ = 1; } } // Step it forward 20 times for good measure for (int i = 0; i < 20; i++) { rnd_ = NextRandom(rnd_); } // Initialize counter bytes_until_sample_ = PickNextSamplingPoint(); } // Initialize the Statics for the Sampler class void Sampler::InitStatics() { PopulateFastLog2Table(); } // Generates a geometric variable with the specified mean (512K by default). // This is done by generating a random number between 0 and 1 and applying // the inverse cumulative distribution function for an exponential. // Specifically: Let m be the inverse of the sample period, then // the probability distribution function is m*exp(-mx) so the CDF is // p = 1 - exp(-mx), so // q = 1 - p = exp(-mx) // log_e(q) = -mx // -log_e(q)/m = x // log_2(q) * (-log_e(2) * 1/m) = x // In the code, q is actually in the range 1 to 2**26, hence the -26 below size_t Sampler::PickNextSamplingPoint() { rnd_ = NextRandom(rnd_); // Take the top 26 bits as the random number // (This plus the 1<<58 sampling bound give a max possible step of // 5194297183973780480 bytes.) const uint64_t prng_mod_power = 48; // Number of bits in prng // The uint32_t cast is to prevent a (hard-to-reproduce) NAN // under piii debug for some binaries. double q = static_cast(rnd_ >> (prng_mod_power - 26)) + 1.0; // Put the computed p-value through the CDF of a geometric. // For faster performance (save ~1/20th exec time), replace // min(0.0, FastLog2(q) - 26) by (Fastlog2(q) - 26.000705) // The value 26.000705 is used rather than 26 to compensate // for inaccuracies in FastLog2 which otherwise result in a // negative answer. return static_cast(min(0.0, (FastLog2(q) - 26)) * (-log(2.0) * FLAGS_tcmalloc_sample_parameter) + 1); } } // namespace tcmalloc ================================================ FILE: distro/google-perftools-1.7/src/sampler.h ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // All Rights Reserved. // // Author: Daniel Ford #ifndef TCMALLOC_SAMPLER_H_ #define TCMALLOC_SAMPLER_H_ #include "config.h" #include "common.h" #include "static_vars.h" namespace tcmalloc { //------------------------------------------------------------------- // Sampler to decide when to create a sample trace for an allocation // Not thread safe: Each thread should have it's own sampler object. // Caller must use external synchronization if used // from multiple threads. // // With 512K average sample step (the default): // the probability of sampling a 4K allocation is about 0.00778 // the probability of sampling a 1MB allocation is about 0.865 // the probability of sampling a 1GB allocation is about 1.00000 // In general, the probablity of sampling is an allocation of size X // given a flag value of Y (default 1M) is: // 1 - e^(-X/Y) // // With 128K average sample step: // the probability of sampling a 1MB allocation is about 0.99966 // the probability of sampling a 1GB allocation is about 1.0 // (about 1 - 2**(-26)) // With 1M average sample step: // the probability of sampling a 4K allocation is about 0.00390 // the probability of sampling a 1MB allocation is about 0.632 // the probability of sampling a 1GB allocation is about 1.0 // // The sampler works by representing memory as a long stream from // which allocations are taken. Some of the bytes in this stream are // marked and if an allocation includes a marked byte then it is // sampled. Bytes are marked according to a Poisson point process // with each byte being marked independently with probability // p = 1/tcmalloc_sample_parameter. This makes the probability // of sampling an allocation of X bytes equal to the CDF of // a geometric with mean tcmalloc_sample_parameter. (ie. the // probability that at least one byte in the range is marked). This // is accurately given by the CDF of the corresponding exponential // distribution : 1 - e^(X/tcmalloc_sample_parameter_) // Independence of the byte marking ensures independence of // the sampling of each allocation. // // This scheme is implemented by noting that, starting from any // fixed place, the number of bytes until the next marked byte // is geometrically distributed. This number is recorded as // bytes_until_sample_. Every allocation subtracts from this // number until it is less than 0. When this happens the current // allocation is sampled. // // When an allocation occurs, bytes_until_sample_ is reset to // a new independtly sampled geometric number of bytes. The // memoryless property of the point process means that this may // be taken as the number of bytes after the end of the current // allocation until the next marked byte. This ensures that // very large allocations which would intersect many marked bytes // only result in a single call to PickNextSamplingPoint. //------------------------------------------------------------------- class PERFTOOLS_DLL_DECL Sampler { public: // Initialize this sampler. // Passing a seed of 0 gives a non-deterministic // seed value given by casting the object ("this") void Init(uint32_t seed); void Cleanup(); // Record allocation of "k" bytes. Return true iff allocation // should be sampled bool SampleAllocation(size_t k); // Generate a geometric with mean 512K (or FLAG_tcmalloc_sample_parameter) size_t PickNextSamplingPoint(); // Initialize the statics for the Sampler class static void InitStatics(); // Returns the current sample period int GetSamplePeriod(); // The following are public for the purposes of testing static uint64_t NextRandom(uint64_t rnd_); // Returns the next prng value static double FastLog2(const double & d); // Computes Log2(x) quickly static void PopulateFastLog2Table(); // Populate the lookup table private: size_t bytes_until_sample_; // Bytes until we sample next uint64_t rnd_; // Cheap random number generator // Statics for the fast log // Note that this code may not depend on anything in //util // hence the duplication of functionality here static const int kFastlogNumBits = 10; static const int kFastlogMask = (1 << kFastlogNumBits) - 1; static double log_table_[1<(0)) << prng_mod_power); return (prng_mult * rnd + prng_add) & prng_mod_mask; } // Adapted from //util/math/fastmath.[h|cc] by Noam Shazeer // This mimics the VeryFastLog2 code in those files inline double Sampler::FastLog2(const double & d) { ASSERT(d>0); COMPILE_ASSERT(sizeof(d) == sizeof(uint64_t), DoubleMustBe64Bits); uint64_t x; memcpy(&x, &d, sizeof(x)); // we depend on the compiler inlining this const uint32_t x_high = x >> 32; const uint32_t y = x_high >> (20 - kFastlogNumBits) & kFastlogMask; const int32_t exponent = ((x_high >> 20) & 0x7FF) - 1023; return exponent + log_table_[y]; } } // namespace tcmalloc #endif // TCMALLOC_SAMPLER_H_ ================================================ FILE: distro/google-perftools-1.7/src/solaris/libstdc++.la ================================================ # libstdc++.la - a libtool library file # Generated by ltmain.sh - GNU libtool 1.4a-GCC3.0 (1.641.2.256 2001/05/28 20:09:07 with GCC-local changes) # # Please DO NOT delete this file! # It is necessary for linking the library. # --- # NOTE: This file lives in /usr/sfw/lib on Solaris 10. Unfortunately, # due to an apparent bug in the Solaris 10 6/06 release, # /usr/sfw/lib/libstdc++.la is empty. Below is the correct content, # according to # http://forum.java.sun.com/thread.jspa?threadID=5073150 # By passing LDFLAGS='-Lsrc/solaris' to configure, make will pick up # this copy of the file rather than the empty copy in /usr/sfw/lib. # # Also see # http://www.technicalarticles.org/index.php/Compiling_MySQL_5.0_on_Solaris_10 # # Note: this is for 32-bit systems. If you have a 64-bit system, # uncomment the appropriate dependency_libs line below. # ---- # The name that we can dlopen(3). dlname='libstdc++.so.6' # Names of this library. library_names='libstdc++.so.6.0.3 libstdc++.so.6 libstdc++.so' # The name of the static archive. old_library='libstdc++.a' # Libraries that this one depends upon. # 32-bit version: dependency_libs='-lc -lm -L/usr/sfw/lib -lgcc_s' # 64-bit version: #dependency_libs='-L/lib/64 -lc -lm -L/usr/sfw/lib/64 -lgcc_s' # Version information for libstdc++. current=6 age=0 revision=3 # Is this an already installed library? installed=yes # Files to dlopen/dlpreopen dlopen='' dlpreopen='' # Directory that this library needs to be installed in: libdir='/usr/sfw/lib' ================================================ FILE: distro/google-perftools-1.7/src/span.cc ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat #include #include "span.h" #ifdef HAVE_INTTYPES_H #include #endif #include "static_vars.h" namespace tcmalloc { #ifdef SPAN_HISTORY void Event(Span* span, char op, int v = 0) { span->history[span->nexthistory] = op; span->value[span->nexthistory] = v; span->nexthistory++; if (span->nexthistory == sizeof(span->history)) span->nexthistory = 0; } #endif Span* NewSpan(PageID p, Length len) { Span* result = Static::span_allocator()->New(); memset(result, 0, sizeof(*result)); result->start = p; result->length = len; #ifdef SPAN_HISTORY result->nexthistory = 0; #endif return result; } void DeleteSpan(Span* span) { #ifndef NDEBUG // In debug mode, trash the contents of deleted Spans memset(span, 0x3f, sizeof(*span)); #endif Static::span_allocator()->Delete(span); } void DLL_Init(Span* list) { list->next = list; list->prev = list; } void DLL_Remove(Span* span) { span->prev->next = span->next; span->next->prev = span->prev; span->prev = NULL; span->next = NULL; } int DLL_Length(const Span* list) { int result = 0; for (Span* s = list->next; s != list; s = s->next) { result++; } return result; } #if 0 // This isn't used. If that changes, rewrite to use TCMalloc_Printer. void DLL_Print(const char* label, const Span* list) { MESSAGE("%-10s %p:", label, list); for (const Span* s = list->next; s != list; s = s->next) { MESSAGE(" <%p,%"PRIuPTR",%"PRIuPTR">", s, s->start, s->length); } MESSAGE("%s\n", ""); // %s is to get around a compiler error. } #endif void DLL_Prepend(Span* list, Span* span) { ASSERT(span->next == NULL); ASSERT(span->prev == NULL); span->next = list->next; span->prev = list; list->next->prev = span; list->next = span; } } // namespace tcmalloc ================================================ FILE: distro/google-perftools-1.7/src/span.h ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // A Span is a contiguous run of pages. #ifndef TCMALLOC_SPAN_H_ #define TCMALLOC_SPAN_H_ #include #include "common.h" namespace tcmalloc { // Information kept for a span (a contiguous run of pages). struct Span { PageID start; // Starting page number Length length; // Number of pages in span Span* next; // Used when in link list Span* prev; // Used when in link list void* objects; // Linked list of free objects unsigned int refcount : 16; // Number of non-free objects unsigned int sizeclass : 8; // Size-class for small objects (or 0) unsigned int location : 2; // Is the span on a freelist, and if so, which? unsigned int sample : 1; // Sampled object? #undef SPAN_HISTORY #ifdef SPAN_HISTORY // For debugging, we can keep a log events per span int nexthistory; char history[64]; int value[64]; #endif // What freelist the span is on: IN_USE if on none, or normal or returned enum { IN_USE, ON_NORMAL_FREELIST, ON_RETURNED_FREELIST }; }; #ifdef SPAN_HISTORY void Event(Span* span, char op, int v = 0); #else #define Event(s,o,v) ((void) 0) #endif // Allocator/deallocator for spans Span* NewSpan(PageID p, Length len); void DeleteSpan(Span* span); // ------------------------------------------------------------------------- // Doubly linked list of spans. // ------------------------------------------------------------------------- // Initialize *list to an empty list. void DLL_Init(Span* list); // Remove 'span' from the linked list in which it resides, updating the // pointers of adjacent Spans and setting span's next and prev to NULL. void DLL_Remove(Span* span); // Return true iff "list" is empty. inline bool DLL_IsEmpty(const Span* list) { return list->next == list; } // Add span to the front of list. void DLL_Prepend(Span* list, Span* span); // Return the length of the linked list. O(n) int DLL_Length(const Span* list); // Print the contents of the list to stderr. #if 0 // This isn't used. void DLL_Print(const char* label, const Span* list); #endif } // namespace tcmalloc #endif // TCMALLOC_SPAN_H_ ================================================ FILE: distro/google-perftools-1.7/src/stack_trace_table.cc ================================================ // Copyright (c) 2009, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Andrew Fikes #include #include "base/spinlock.h" #include "common.h" #include "static_vars.h" #include "stack_trace_table.h" namespace tcmalloc { bool StackTraceTable::Bucket::KeyEqual(uintptr_t h, const StackTrace& t) const { const bool eq = (this->hash == h && this->trace.depth == t.depth); for (int i = 0; eq && i < t.depth; ++i) { if (this->trace.stack[i] != t.stack[i]) { return false; } } return eq; } StackTraceTable::StackTraceTable() : error_(false), depth_total_(0), bucket_total_(0), table_(new Bucket*[kHashTableSize]()) { memset(table_, 0, kHashTableSize * sizeof(Bucket*)); } StackTraceTable::~StackTraceTable() { delete[] table_; } void StackTraceTable::AddTrace(const StackTrace& t) { if (error_) { return; } // Hash function borrowed from base/heap-profile-table.cc uintptr_t h = 0; for (int i = 0; i < t.depth; ++i) { h += reinterpret_cast(t.stack[i]); h += h << 10; h ^= h >> 6; } h += h << 3; h ^= h >> 11; const int idx = h % kHashTableSize; Bucket* b = table_[idx]; while (b != NULL && !b->KeyEqual(h, t)) { b = b->next; } if (b != NULL) { b->count++; b->trace.size += t.size; // keep cumulative size } else { depth_total_ += t.depth; bucket_total_++; b = Static::bucket_allocator()->New(); if (b == NULL) { MESSAGE("tcmalloc: could not allocate bucket", sizeof(*b)); error_ = true; } else { b->hash = h; b->trace = t; b->count = 1; b->next = table_[idx]; table_[idx] = b; } } } void** StackTraceTable::ReadStackTracesAndClear() { if (error_) { return NULL; } // Allocate output array const int out_len = bucket_total_ * 3 + depth_total_ + 1; void** out = new void*[out_len]; if (out == NULL) { MESSAGE("tcmalloc: allocation failed for stack traces\n", out_len * sizeof(*out)); return NULL; } // Fill output array int idx = 0; for (int i = 0; i < kHashTableSize; ++i) { Bucket* b = table_[i]; while (b != NULL) { out[idx++] = reinterpret_cast(static_cast(b->count)); out[idx++] = reinterpret_cast(b->trace.size); // cumulative size out[idx++] = reinterpret_cast(b->trace.depth); for (int d = 0; d < b->trace.depth; ++d) { out[idx++] = b->trace.stack[d]; } b = b->next; } } out[idx++] = static_cast(0); ASSERT(idx == out_len); // Clear state error_ = false; depth_total_ = 0; bucket_total_ = 0; SpinLockHolder h(Static::pageheap_lock()); for (int i = 0; i < kHashTableSize; ++i) { Bucket* b = table_[i]; while (b != NULL) { Bucket* next = b->next; Static::bucket_allocator()->Delete(b); b = next; } table_[i] = NULL; } return out; } } // namespace tcmalloc ================================================ FILE: distro/google-perftools-1.7/src/stack_trace_table.h ================================================ // Copyright (c) 2009, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Andrew Fikes // // Utility class for coalescing sampled stack traces. Not thread-safe. #ifndef TCMALLOC_STACK_TRACE_TABLE_H_ #define TCMALLOC_STACK_TRACE_TABLE_H_ #include #include "common.h" namespace tcmalloc { class PERFTOOLS_DLL_DECL StackTraceTable { public: // REQUIRES: L < pageheap_lock StackTraceTable(); ~StackTraceTable(); // Adds stack trace "t" to table. // // REQUIRES: L >= pageheap_lock void AddTrace(const StackTrace& t); // Returns stack traces formatted per MallocExtension guidelines. // May return NULL on error. Clears state before returning. // // REQUIRES: L < pageheap_lock void** ReadStackTracesAndClear(); // Exposed for PageHeapAllocator struct Bucket { // Key uintptr_t hash; StackTrace trace; // Payload int count; Bucket* next; bool KeyEqual(uintptr_t h, const StackTrace& t) const; }; // For testing int depth_total() const { return depth_total_; } int bucket_total() const { return bucket_total_; } private: static const int kHashTableSize = 1 << 14; // => table_ is 128k bool error_; int depth_total_; int bucket_total_; Bucket** table_; }; } // namespace tcmalloc #endif // TCMALLOC_STACK_TRACE_TABLE_H_ ================================================ FILE: distro/google-perftools-1.7/src/stacktrace.cc ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // Produce stack trace. // // There are three different ways we can try to get the stack trace: // // 1) Our hand-coded stack-unwinder. This depends on a certain stack // layout, which is used by gcc (and those systems using a // gcc-compatible ABI) on x86 systems, at least since gcc 2.95. // It uses the frame pointer to do its work. // // 2) The libunwind library. This is still in development, and as a // separate library adds a new dependency, abut doesn't need a frame // pointer. It also doesn't call malloc. // // 3) The gdb unwinder -- also the one used by the c++ exception code. // It's obviously well-tested, but has a fatal flaw: it can call // malloc() from the unwinder. This is a problem because we're // trying to use the unwinder to instrument malloc(). // // Note: if you add a new implementation here, make sure it works // correctly when GetStackTrace() is called with max_depth == 0. // Some code may do that. #include #include #include "stacktrace_config.h" #if defined(STACKTRACE_INL_HEADER) #define IS_STACK_FRAMES 0 #define IS_WITH_CONTEXT 0 #define GET_STACK_TRACE_OR_FRAMES \ GetStackTrace(void **result, int max_depth, int skip_count) #include STACKTRACE_INL_HEADER #undef IS_STACK_FRAMES #undef IS_WITH_CONTEXT #undef GET_STACK_TRACE_OR_FRAMES #define IS_STACK_FRAMES 1 #define IS_WITH_CONTEXT 0 #define GET_STACK_TRACE_OR_FRAMES \ GetStackFrames(void **result, int *sizes, int max_depth, int skip_count) #include STACKTRACE_INL_HEADER #undef IS_STACK_FRAMES #undef IS_WITH_CONTEXT #undef GET_STACK_TRACE_OR_FRAMES #define IS_STACK_FRAMES 0 #define IS_WITH_CONTEXT 1 #define GET_STACK_TRACE_OR_FRAMES \ GetStackTraceWithContext(void **result, int max_depth, \ int skip_count, const void *ucp) #include STACKTRACE_INL_HEADER #undef IS_STACK_FRAMES #undef IS_WITH_CONTEXT #undef GET_STACK_TRACE_OR_FRAMES #define IS_STACK_FRAMES 1 #define IS_WITH_CONTEXT 1 #define GET_STACK_TRACE_OR_FRAMES \ GetStackFramesWithContext(void **result, int *sizes, int max_depth, \ int skip_count, const void *ucp) #include STACKTRACE_INL_HEADER #undef IS_STACK_FRAMES #undef IS_WITH_CONTEXT #undef GET_STACK_TRACE_OR_FRAMES #elif 0 // This is for the benefit of code analysis tools that may have // trouble with the computed #include above. # include "base/stacktrace_x86-inl.h" # include "base/stacktrace_libunwind-inl.h" # include "base/stacktrace_generic-inl.h" # include "base/stacktrace_powerpc-inl.h" # include "base/stacktrace_win32-inl.h" #else # error Cannot calculate stack trace: will need to write for your environment #endif ================================================ FILE: distro/google-perftools-1.7/src/stacktrace_config.h ================================================ // Copyright (c) 2009, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Paul Pluzhnikov // // Figure out which unwinder to use on a given platform. // // Defines STACKTRACE_INL_HEADER to the *-inl.h containing // actual unwinder implementation. // // Defines STACKTRACE_SKIP_CONTEXT_ROUTINES if a separate // GetStack{Trace,Frames}WithContext should not be provided. // // This header is "private" to stacktrace.cc and // stacktrace_with_context.cc. // // DO NOT include it into any other files. #ifndef BASE_STACKTRACE_CONFIG_H_ #define BASE_STACKTRACE_CONFIG_H_ // First, the i386 and x86_64 case. #if (defined(__i386__) || defined(__x86_64__)) && __GNUC__ >= 2 # if !defined(NO_FRAME_POINTER) # define STACKTRACE_INL_HEADER "stacktrace_x86-inl.h" # define STACKTRACE_SKIP_CONTEXT_ROUTINES 1 # elif defined(HAVE_LIBUNWIND_H) // a proxy for having libunwind installed # define STACKTRACE_INL_HEADER "stacktrace_libunwind-inl.h" # define STACKTRACE_USES_LIBUNWIND 1 # elif defined(__linux) # error Cannnot calculate stack trace: need either libunwind or frame-pointers (see INSTALL file) # else # error Cannnot calculate stack trace: need libunwind (see INSTALL file) # endif // The PowerPC case #elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2 # if !defined(NO_FRAME_POINTER) # define STACKTRACE_INL_HEADER "stacktrace_powerpc-inl.h" # else # define STACKTRACE_INL_HEADER "stacktrace_generic-inl.h" # endif // The Windows case -- probably cygwin and mingw will use one of the // x86-includes above, but if not, we can fall back to windows intrinsics. #elif defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__MINGW32__) # define STACKTRACE_INL_HEADER "stacktrace_win32-inl.h" #endif // all the cases #endif // BASE_STACKTRACE_CONFIG_H_ ================================================ FILE: distro/google-perftools-1.7/src/stacktrace_generic-inl.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // Portable implementation - just use glibc // // Note: The glibc implementation may cause a call to malloc. // This can cause a deadlock in HeapProfiler. #ifndef BASE_STACKTRACE_GENERIC_INL_H_ #define BASE_STACKTRACE_GENERIC_INL_H_ // Note: this file is included into stacktrace.cc more than once. // Anything that should only be defined once should be here: #include #include #include "google/stacktrace.h" #endif // BASE_STACKTRACE_GENERIC_INL_H_ // Note: this part of the file is included several times. // Do not put globals below. // The following 4 functions are generated from the code below: // GetStack{Trace,Frames}() // GetStack{Trace,Frames}WithContext() // // These functions take the following args: // void** result: the stack-trace, as an array // int* sizes: the size of each stack frame, as an array // (GetStackFrames* only) // int max_depth: the size of the result (and sizes) array(s) // int skip_count: how many stack pointers to skip before storing in result // void* ucp: a ucontext_t* (GetStack{Trace,Frames}WithContext only) int GET_STACK_TRACE_OR_FRAMES { static const int kStackLength = 64; void * stack[kStackLength]; int size; size = backtrace(stack, kStackLength); skip_count++; // we want to skip the current frame as well int result_count = size - skip_count; if (result_count < 0) result_count = 0; if (result_count > max_depth) result_count = max_depth; for (int i = 0; i < result_count; i++) result[i] = stack[i + skip_count]; #if IS_STACK_FRAMES // No implementation for finding out the stack frame sizes yet. memset(sizes, 0, sizeof(*sizes) * result_count); #endif return result_count; } ================================================ FILE: distro/google-perftools-1.7/src/stacktrace_libunwind-inl.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Arun Sharma // // Produce stack trace using libunwind #ifndef BASE_STACKTRACE_LIBINWIND_INL_H_ #define BASE_STACKTRACE_LIBINWIND_INL_H_ // Note: this file is included into stacktrace.cc more than once. // Anything that should only be defined once should be here: // We only need local unwinder. #define UNW_LOCAL_ONLY extern "C" { #include #include // for memset() #include } #include "google/stacktrace.h" #include "base/logging.h" // Sometimes, we can try to get a stack trace from within a stack // trace, because libunwind can call mmap (maybe indirectly via an // internal mmap based memory allocator), and that mmap gets trapped // and causes a stack-trace request. If were to try to honor that // recursive request, we'd end up with infinite recursion or deadlock. // Luckily, it's safe to ignore those subsequent traces. In such // cases, we return 0 to indicate the situation. static __thread int recursive; #endif // BASE_STACKTRACE_LIBINWIND_INL_H_ // Note: this part of the file is included several times. // Do not put globals below. // The following 4 functions are generated from the code below: // GetStack{Trace,Frames}() // GetStack{Trace,Frames}WithContext() // // These functions take the following args: // void** result: the stack-trace, as an array // int* sizes: the size of each stack frame, as an array // (GetStackFrames* only) // int max_depth: the size of the result (and sizes) array(s) // int skip_count: how many stack pointers to skip before storing in result // void* ucp: a ucontext_t* (GetStack{Trace,Frames}WithContext only) int GET_STACK_TRACE_OR_FRAMES { void *ip; int n = 0; unw_cursor_t cursor; unw_context_t uc; #if IS_STACK_FRAMES unw_word_t sp = 0, next_sp = 0; #endif if (recursive) { return 0; } ++recursive; unw_getcontext(&uc); int ret = unw_init_local(&cursor, &uc); assert(ret >= 0); skip_count++; // Do not include current frame while (skip_count--) { if (unw_step(&cursor) <= 0) { goto out; } #if IS_STACK_FRAMES if (unw_get_reg(&cursor, UNW_REG_SP, &next_sp)) { goto out; } #endif } while (n < max_depth) { if (unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *) &ip) < 0) { break; } #if IS_STACK_FRAMES sizes[n] = 0; #endif result[n++] = ip; if (unw_step(&cursor) <= 0) { break; } #if IS_STACK_FRAMES sp = next_sp; if (unw_get_reg(&cursor, UNW_REG_SP, &next_sp) , 0) { break; } sizes[n - 1] = next_sp - sp; #endif } out: --recursive; return n; } ================================================ FILE: distro/google-perftools-1.7/src/stacktrace_powerpc-inl.h ================================================ // Copyright (c) 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Craig Silverstein // // Produce stack trace. I'm guessing (hoping!) the code is much like // for x86. For apple machines, at least, it seems to be; see // http://developer.apple.com/documentation/mac/runtimehtml/RTArch-59.html // http://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK // Linux has similar code: http://patchwork.ozlabs.org/linuxppc/patch?id=8882 #ifndef BASE_STACKTRACE_POWERPC_INL_H_ #define BASE_STACKTRACE_POWERPC_INL_H_ // Note: this file is included into stacktrace.cc more than once. // Anything that should only be defined once should be here: #include // for uintptr_t #include // for NULL #include // Given a pointer to a stack frame, locate and return the calling // stackframe, or return NULL if no stackframe can be found. Perform sanity // checks (the strictness of which is controlled by the boolean parameter // "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned. template static void **NextStackFrame(void **old_sp) { void **new_sp = (void **) *old_sp; // Check that the transition from frame pointer old_sp to frame // pointer new_sp isn't clearly bogus if (STRICT_UNWINDING) { // With the stack growing downwards, older stack frame must be // at a greater address that the current one. if (new_sp <= old_sp) return NULL; // Assume stack frames larger than 100,000 bytes are bogus. if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return NULL; } else { // In the non-strict mode, allow discontiguous stack frames. // (alternate-signal-stacks for example). if (new_sp == old_sp) return NULL; // And allow frames upto about 1MB. if ((new_sp > old_sp) && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return NULL; } if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return NULL; return new_sp; } // This ensures that GetStackTrace stes up the Link Register properly. void StacktracePowerPCDummyFunction() __attribute__((noinline)); void StacktracePowerPCDummyFunction() { __asm__ volatile(""); } #endif // BASE_STACKTRACE_POWERPC_INL_H_ // Note: this part of the file is included several times. // Do not put globals below. // The following 4 functions are generated from the code below: // GetStack{Trace,Frames}() // GetStack{Trace,Frames}WithContext() // // These functions take the following args: // void** result: the stack-trace, as an array // int* sizes: the size of each stack frame, as an array // (GetStackFrames* only) // int max_depth: the size of the result (and sizes) array(s) // int skip_count: how many stack pointers to skip before storing in result // void* ucp: a ucontext_t* (GetStack{Trace,Frames}WithContext only) int GET_STACK_TRACE_OR_FRAMES { void **sp; // Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther) // and Darwin 8.8.1 (Tiger) use as 1.38. This means we have to use a // different asm syntax. I don't know quite the best way to discriminate // systems using the old as from the new one; I've gone with __APPLE__. // TODO(csilvers): use autoconf instead, to look for 'as --version' == 1 or 2 #ifdef __APPLE__ __asm__ volatile ("mr %0,r1" : "=r" (sp)); #else __asm__ volatile ("mr %0,1" : "=r" (sp)); #endif // On PowerPC, the "Link Register" or "Link Record" (LR), is a stack // entry that holds the return address of the subroutine call (what // instruction we run after our function finishes). This is the // same as the stack-pointer of our parent routine, which is what we // want here. While the compiler will always(?) set up LR for // subroutine calls, it may not for leaf functions (such as this one). // This routine forces the compiler (at least gcc) to push it anyway. StacktracePowerPCDummyFunction(); #if IS_STACK_FRAMES // Note we do *not* increment skip_count here for the SYSV ABI. If // we did, the list of stack frames wouldn't properly match up with // the list of return addresses. Note this means the top pc entry // is probably bogus for linux/ppc (and other SYSV-ABI systems). #else // The LR save area is used by the callee, so the top entry is bogus. skip_count++; #endif int n = 0; while (sp && n < max_depth) { #if IS_STACK_FRAMES // The GetStackFrames routine is called when we are in some // informational context (the failure signal handler for example). // Use the non-strict unwinding rules to produce a stack trace // that is as complete as possible (even if it contains a few bogus // entries in some rare cases). void **next_sp = NextStackFrame(sp); #else void **next_sp = NextStackFrame(sp); #endif if (skip_count > 0) { skip_count--; } else { // PowerPC has 3 main ABIs, which say where in the stack the // Link Register is. For DARWIN and AIX (used by apple and // linux ppc64), it's in sp[2]. For SYSV (used by linux ppc), // it's in sp[1]. #if defined(_CALL_AIX) || defined(_CALL_DARWIN) result[n++] = *(sp+2); #elif defined(_CALL_SYSV) result[n++] = *(sp+1); #elif defined(__APPLE__) || (defined(__linux) && defined(__PPC64__)) // This check is in case the compiler doesn't define _CALL_AIX/etc. result[n++] = *(sp+2); #elif defined(__linux) // This check is in case the compiler doesn't define _CALL_SYSV. result[n++] = *(sp+1); #else #error Need to specify the PPC ABI for your archiecture. #endif #if IS_STACK_FRAME if (next_sp > sp) { sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp; } else { // A frame-size of 0 is used to indicate unknown frame size. sizes[n] = 0; } #endif } sp = next_sp; } return n; } ================================================ FILE: distro/google-perftools-1.7/src/stacktrace_win32-inl.h ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // --- // Produces a stack trace for Windows. Normally, one could use // stacktrace_x86-inl.h or stacktrace_x86_64-inl.h -- and indeed, that // should work for binaries compiled using MSVC in "debug" mode. // However, in "release" mode, Windows uses frame-pointer // optimization, which makes getting a stack trace very difficult. // // There are several approaches one can take. One is to use Windows // intrinsics like StackWalk64. These can work, but have restrictions // on how successful they can be. Another attempt is to write a // version of stacktrace_x86-inl.h that has heuristic support for // dealing with FPO, similar to what WinDbg does (see // http://www.nynaeve.net/?p=97). // // The solution we've ended up doing is to call the undocumented // windows function RtlCaptureStackBackTrace, which probably doesn't // work with FPO but at least is fast, and doesn't require a symbol // server. // // This code is inspired by a patch from David Vitek: // http://code.google.com/p/google-perftools/issues/detail?id=83 #ifndef BASE_STACKTRACE_WIN32_INL_H_ #define BASE_STACKTRACE_WIN32_INL_H_ // Note: this file is included into stacktrace.cc more than once. // Anything that should only be defined once should be here: #include "config.h" #include // for GetProcAddress and GetModuleHandle #include typedef USHORT NTAPI RtlCaptureStackBackTrace_Function( IN ULONG frames_to_skip, IN ULONG frames_to_capture, OUT PVOID *backtrace, OUT PULONG backtrace_hash); // Load the function we need at static init time, where we don't have // to worry about someone else holding the loader's lock. static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn = (RtlCaptureStackBackTrace_Function*) GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace"); PERFTOOLS_DLL_DECL int GetStackTrace(void** result, int max_depth, int skip_count) { if (!RtlCaptureStackBackTrace_fn) { // TODO(csilvers): should we log an error here? return 0; // can't find a stacktrace with no function to call } return (int)RtlCaptureStackBackTrace_fn(skip_count + 2, max_depth, result, 0); } PERFTOOLS_DLL_DECL int GetStackFrames(void** /* pcs */, int* /* sizes */, int /* max_depth */, int /* skip_count */) { assert(0 == "Not yet implemented"); return 0; } #endif // BASE_STACKTRACE_WIN32_INL_H_ ================================================ FILE: distro/google-perftools-1.7/src/stacktrace_x86-inl.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // Produce stack trace #ifndef BASE_STACKTRACE_X86_INL_H_ #define BASE_STACKTRACE_X86_INL_H_ // Note: this file is included into stacktrace.cc more than once. // Anything that should only be defined once should be here: #include "config.h" #include // for NULL #include #if defined(HAVE_SYS_UCONTEXT_H) #include #elif defined(HAVE_UCONTEXT_H) #include // for ucontext_t #elif defined(HAVE_CYGWIN_SIGNAL_H) // cygwin/signal.h has a buglet where it uses pthread_attr_t without // #including itself. So we have to do it. # ifdef HAVE_PTHREAD # include # endif #include typedef ucontext ucontext_t; #endif #ifdef HAVE_STDINT_H #include // for uintptr_t #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_MMAP #include // for msync #include "base/vdso_support.h" #endif #include "google/stacktrace.h" #if defined(__linux__) && defined(__i386__) && defined(__ELF__) && defined(HAVE_MMAP) // Count "push %reg" instructions in VDSO __kernel_vsyscall(), // preceeding "syscall" or "sysenter". // If __kernel_vsyscall uses frame pointer, answer 0. // // kMaxBytes tells how many instruction bytes of __kernel_vsyscall // to analyze before giving up. Up to kMaxBytes+1 bytes of // instructions could be accessed. // // Here are known __kernel_vsyscall instruction sequences: // // SYSENTER (linux-2.6.26/arch/x86/vdso/vdso32/sysenter.S). // Used on Intel. // 0xffffe400 <__kernel_vsyscall+0>: push %ecx // 0xffffe401 <__kernel_vsyscall+1>: push %edx // 0xffffe402 <__kernel_vsyscall+2>: push %ebp // 0xffffe403 <__kernel_vsyscall+3>: mov %esp,%ebp // 0xffffe405 <__kernel_vsyscall+5>: sysenter // // SYSCALL (see linux-2.6.26/arch/x86/vdso/vdso32/syscall.S). // Used on AMD. // 0xffffe400 <__kernel_vsyscall+0>: push %ebp // 0xffffe401 <__kernel_vsyscall+1>: mov %ecx,%ebp // 0xffffe403 <__kernel_vsyscall+3>: syscall // // i386 (see linux-2.6.26/arch/x86/vdso/vdso32/int80.S) // 0xffffe400 <__kernel_vsyscall+0>: int $0x80 // 0xffffe401 <__kernel_vsyscall+1>: ret // static const int kMaxBytes = 10; // We use assert()s instead of DCHECK()s -- this is too low level // for DCHECK(). static int CountPushInstructions(const unsigned char *const addr) { int result = 0; for (int i = 0; i < kMaxBytes; ++i) { if (addr[i] == 0x89) { // "mov reg,reg" if (addr[i + 1] == 0xE5) { // Found "mov %esp,%ebp". return 0; } ++i; // Skip register encoding byte. } else if (addr[i] == 0x0F && (addr[i + 1] == 0x34 || addr[i + 1] == 0x05)) { // Found "sysenter" or "syscall". return result; } else if ((addr[i] & 0xF0) == 0x50) { // Found "push %reg". ++result; } else if (addr[i] == 0xCD && addr[i + 1] == 0x80) { // Found "int $0x80" assert(result == 0); return 0; } else { // Unexpected instruction. assert(0 == "unexpected instruction in __kernel_vsyscall"); return 0; } } // Unexpected: didn't find SYSENTER or SYSCALL in // [__kernel_vsyscall, __kernel_vsyscall + kMaxBytes) interval. assert(0 == "did not find SYSENTER or SYSCALL in __kernel_vsyscall"); return 0; } #endif // Given a pointer to a stack frame, locate and return the calling // stackframe, or return NULL if no stackframe can be found. Perform sanity // checks (the strictness of which is controlled by the boolean parameter // "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned. template static void **NextStackFrame(void **old_sp, const void *uc) { void **new_sp = (void **) *old_sp; #if defined(__linux__) && defined(__i386__) && defined(HAVE_VDSO_SUPPORT) if (WITH_CONTEXT && uc != NULL) { // How many "push %reg" instructions are there at __kernel_vsyscall? // This is constant for a given kernel and processor, so compute // it only once. static int num_push_instructions = -1; // Sentinel: not computed yet. // Initialize with sentinel value: __kernel_rt_sigreturn can not possibly // be there. static const unsigned char *kernel_rt_sigreturn_address = NULL; static const unsigned char *kernel_vsyscall_address = NULL; if (num_push_instructions == -1) { base::VDSOSupport vdso; if (vdso.IsPresent()) { base::VDSOSupport::SymbolInfo rt_sigreturn_symbol_info; base::VDSOSupport::SymbolInfo vsyscall_symbol_info; if (!vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.5", STT_FUNC, &rt_sigreturn_symbol_info) || !vdso.LookupSymbol("__kernel_vsyscall", "LINUX_2.5", STT_FUNC, &vsyscall_symbol_info) || rt_sigreturn_symbol_info.address == NULL || vsyscall_symbol_info.address == NULL) { // Unexpected: 32-bit VDSO is present, yet one of the expected // symbols is missing or NULL. assert(0 == "VDSO is present, but doesn't have expected symbols"); num_push_instructions = 0; } else { kernel_rt_sigreturn_address = reinterpret_cast( rt_sigreturn_symbol_info.address); kernel_vsyscall_address = reinterpret_cast( vsyscall_symbol_info.address); num_push_instructions = CountPushInstructions(kernel_vsyscall_address); } } else { num_push_instructions = 0; } } if (num_push_instructions != 0 && kernel_rt_sigreturn_address != NULL && old_sp[1] == kernel_rt_sigreturn_address) { const ucontext_t *ucv = static_cast(uc); // This kernel does not use frame pointer in its VDSO code, // and so %ebp is not suitable for unwinding. void **const reg_ebp = reinterpret_cast(ucv->uc_mcontext.gregs[REG_EBP]); const unsigned char *const reg_eip = reinterpret_cast(ucv->uc_mcontext.gregs[REG_EIP]); if (new_sp == reg_ebp && kernel_vsyscall_address <= reg_eip && reg_eip - kernel_vsyscall_address < kMaxBytes) { // We "stepped up" to __kernel_vsyscall, but %ebp is not usable. // Restore from 'ucv' instead. void **const reg_esp = reinterpret_cast(ucv->uc_mcontext.gregs[REG_ESP]); // Check that alleged %esp is not NULL and is reasonably aligned. if (reg_esp && ((uintptr_t)reg_esp & (sizeof(reg_esp) - 1)) == 0) { // Check that alleged %esp is actually readable. This is to prevent // "double fault" in case we hit the first fault due to e.g. stack // corruption. // // page_size is linker-initalized to avoid async-unsafe locking // that GCC would otherwise insert (__cxa_guard_acquire etc). static int page_size; if (page_size == 0) { // First time through. page_size = getpagesize(); } void *const reg_esp_aligned = reinterpret_cast( (uintptr_t)(reg_esp + num_push_instructions - 1) & ~(page_size - 1)); if (msync(reg_esp_aligned, page_size, MS_ASYNC) == 0) { // Alleged %esp is readable, use it for further unwinding. new_sp = reinterpret_cast( reg_esp[num_push_instructions - 1]); } } } } } #endif // Check that the transition from frame pointer old_sp to frame // pointer new_sp isn't clearly bogus if (STRICT_UNWINDING) { // With the stack growing downwards, older stack frame must be // at a greater address that the current one. if (new_sp <= old_sp) return NULL; // Assume stack frames larger than 100,000 bytes are bogus. if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return NULL; } else { // In the non-strict mode, allow discontiguous stack frames. // (alternate-signal-stacks for example). if (new_sp == old_sp) return NULL; // And allow frames upto about 1MB. if ((new_sp > old_sp) && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return NULL; } if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return NULL; #ifdef __i386__ // On 64-bit machines, the stack pointer can be very close to // 0xffffffff, so we explicitly check for a pointer into the // last two pages in the address space if ((uintptr_t)new_sp >= 0xffffe000) return NULL; #endif #ifdef HAVE_MMAP if (!STRICT_UNWINDING) { // Lax sanity checks cause a crash on AMD-based machines with // VDSO-enabled kernels. // Make an extra sanity check to insure new_sp is readable. // Note: NextStackFrame() is only called while the program // is already on its last leg, so it's ok to be slow here. static int page_size = getpagesize(); void *new_sp_aligned = (void *)((uintptr_t)new_sp & ~(page_size - 1)); if (msync(new_sp_aligned, page_size, MS_ASYNC) == -1) return NULL; } #endif return new_sp; } #endif // BASE_STACKTRACE_X86_INL_H_ // Note: this part of the file is included several times. // Do not put globals below. // The following 4 functions are generated from the code below: // GetStack{Trace,Frames}() // GetStack{Trace,Frames}WithContext() // // These functions take the following args: // void** result: the stack-trace, as an array // int* sizes: the size of each stack frame, as an array // (GetStackFrames* only) // int max_depth: the size of the result (and sizes) array(s) // int skip_count: how many stack pointers to skip before storing in result // void* ucp: a ucontext_t* (GetStack{Trace,Frames}WithContext only) int GET_STACK_TRACE_OR_FRAMES { void **sp; #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2) || __llvm__ // __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8. // It's always correct on llvm, and the techniques below aren't (in // particular, llvm-gcc will make a copy of pcs, so it's not in sp[2]), // so we also prefer __builtin_frame_address when running under llvm. sp = reinterpret_cast(__builtin_frame_address(0)); #elif defined(__i386__) // Stack frame format: // sp[0] pointer to previous frame // sp[1] caller address // sp[2] first argument // ... // NOTE: This will break under llvm, since result is a copy and not in sp[2] sp = (void **)&result - 2; #elif defined(__x86_64__) unsigned long rbp; // Move the value of the register %rbp into the local variable rbp. // We need 'volatile' to prevent this instruction from getting moved // around during optimization to before function prologue is done. // An alternative way to achieve this // would be (before this __asm__ instruction) to call Noop() defined as // static void Noop() __attribute__ ((noinline)); // prevent inlining // static void Noop() { asm(""); } // prevent optimizing-away __asm__ volatile ("mov %%rbp, %0" : "=r" (rbp)); // Arguments are passed in registers on x86-64, so we can't just // offset from &result sp = (void **) rbp; #else # error Using stacktrace_x86-inl.h on a non x86 architecture! #endif int n = 0; while (sp && n < max_depth) { if (*(sp+1) == reinterpret_cast(0)) { // In 64-bit code, we often see a frame that // points to itself and has a return address of 0. break; } #if !IS_WITH_CONTEXT const void *const ucp = NULL; #endif void **next_sp = NextStackFrame(sp, ucp); if (skip_count > 0) { skip_count--; } else { result[n] = *(sp+1); #if IS_STACK_FRAMES if (next_sp > sp) { sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp; } else { // A frame-size of 0 is used to indicate unknown frame size. sizes[n] = 0; } #endif n++; } sp = next_sp; } return n; } ================================================ FILE: distro/google-perftools-1.7/src/stacktrace_x86_64-inl.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Arun Sharma // // Produce stack trace using libgcc extern "C" { #include // for NULL #include // ABI defined unwinder #include // for memset } #include "google/stacktrace.h" typedef struct { void **result; int max_depth; int skip_count; int count; } trace_arg_t; // Workaround for the malloc() in _Unwind_Backtrace() issue. static _Unwind_Reason_Code nop_backtrace(struct _Unwind_Context *uc, void *opq) { return _URC_NO_REASON; } // This code is not considered ready to run until // static initializers run so that we are guaranteed // that any malloc-related initialization is done. static bool ready_to_run = false; class StackTraceInit { public: StackTraceInit() { // Extra call to force initialization _Unwind_Backtrace(nop_backtrace, NULL); ready_to_run = true; } }; static StackTraceInit module_initializer; // Force initialization static _Unwind_Reason_Code GetOneFrame(struct _Unwind_Context *uc, void *opq) { trace_arg_t *targ = (trace_arg_t *) opq; if (targ->skip_count > 0) { targ->skip_count--; } else { targ->result[targ->count++] = (void *) _Unwind_GetIP(uc); } if (targ->count == targ->max_depth) return _URC_END_OF_STACK; return _URC_NO_REASON; } // If you change this function, also change GetStackFrames below. int GetStackTrace(void** result, int max_depth, int skip_count) { if (!ready_to_run) return 0; trace_arg_t targ; skip_count += 1; // Do not include the "GetStackTrace" frame targ.result = result; targ.max_depth = max_depth; targ.skip_count = skip_count; targ.count = 0; _Unwind_Backtrace(GetOneFrame, &targ); return targ.count; } // If you change this function, also change GetStackTrace above: // // This GetStackFrames routine shares a lot of code with GetStackTrace // above. This code could have been refactored into a common routine, // and then both GetStackTrace/GetStackFrames could call that routine. // There are two problems with that: // // (1) The performance of the refactored-code suffers substantially - the // refactored needs to be able to record the stack trace when called // from GetStackTrace, and both the stack trace and stack frame sizes, // when called from GetStackFrames - this introduces enough new // conditionals that GetStackTrace performance can degrade by as much // as 50%. // // (2) Whether the refactored routine gets inlined into GetStackTrace and // GetStackFrames depends on the compiler, and we can't guarantee the // behavior either-way, even with "__attribute__ ((always_inline))" // or "__attribute__ ((noinline))". But we need this guarantee or the // frame counts may be off by one. // // Both (1) and (2) can be addressed without this code duplication, by // clever use of template functions, and by defining GetStackTrace and // GetStackFrames as macros that expand to these template functions. // However, this approach comes with its own set of problems - namely, // macros and preprocessor trouble - for example, if GetStackTrace // and/or GetStackFrames is ever defined as a member functions in some // class, we are in trouble. int GetStackFrames(void** pcs, int* sizes, int max_depth, int skip_count) { if (!ready_to_run) return 0; trace_arg_t targ; skip_count += 1; // Do not include the "GetStackFrames" frame targ.result = pcs; targ.max_depth = max_depth; targ.skip_count = skip_count; targ.count = 0; _Unwind_Backtrace(GetOneFrame, &targ); // No implementation for finding out the stack frame sizes yet. memset(sizes, 0, sizeof(*sizes) * targ.count); return targ.count; } ================================================ FILE: distro/google-perftools-1.7/src/static_vars.cc ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Ken Ashcraft #include "static_vars.h" #include "sampler.h" // for the init function namespace tcmalloc { SpinLock Static::pageheap_lock_(SpinLock::LINKER_INITIALIZED); SizeMap Static::sizemap_; CentralFreeListPadded Static::central_cache_[kNumClasses]; PageHeapAllocator Static::span_allocator_; PageHeapAllocator Static::stacktrace_allocator_; Span Static::sampled_objects_; PageHeapAllocator Static::bucket_allocator_; StackTrace* Static::growth_stacks_ = NULL; char Static::pageheap_memory_[sizeof(PageHeap)]; void Static::InitStaticVars() { sizemap_.Init(); span_allocator_.Init(); span_allocator_.New(); // Reduce cache conflicts span_allocator_.New(); // Reduce cache conflicts stacktrace_allocator_.Init(); bucket_allocator_.Init(); // Do a bit of sanitizing: make sure central_cache is aligned properly CHECK_CONDITION((sizeof(central_cache_[0]) % 64) == 0); for (int i = 0; i < kNumClasses; ++i) { central_cache_[i].Init(i); } new ((void*)pageheap_memory_) PageHeap; DLL_Init(&sampled_objects_); Sampler::InitStatics(); } } // namespace tcmalloc ================================================ FILE: distro/google-perftools-1.7/src/static_vars.h ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Ken Ashcraft // // Static variables shared by multiple classes. #ifndef TCMALLOC_STATIC_VARS_H_ #define TCMALLOC_STATIC_VARS_H_ #include #include "base/spinlock.h" #include "central_freelist.h" #include "common.h" #include "page_heap.h" #include "page_heap_allocator.h" #include "span.h" #include "stack_trace_table.h" namespace tcmalloc { class Static { public: // Linker initialized, so this lock can be accessed at any time. static SpinLock* pageheap_lock() { return &pageheap_lock_; } // Must be called before calling any of the accessors below. static void InitStaticVars(); // Central cache -- an array of free-lists, one per size-class. // We have a separate lock per free-list to reduce contention. static CentralFreeListPadded* central_cache() { return central_cache_; } static SizeMap* sizemap() { return &sizemap_; } ////////////////////////////////////////////////////////////////////// // In addition to the explicit initialization comment, the variables below // must be protected by pageheap_lock. // Page-level allocator. static PageHeap* pageheap() { return reinterpret_cast(pageheap_memory_); } static PageHeapAllocator* span_allocator() { return &span_allocator_; } static PageHeapAllocator* stacktrace_allocator() { return &stacktrace_allocator_; } static StackTrace* growth_stacks() { return growth_stacks_; } static void set_growth_stacks(StackTrace* s) { growth_stacks_ = s; } // State kept for sampled allocations (/pprof/heap support) static Span* sampled_objects() { return &sampled_objects_; } static PageHeapAllocator* bucket_allocator() { return &bucket_allocator_; } private: static SpinLock pageheap_lock_; // These static variables require explicit initialization. We cannot // count on their constructors to do any initialization because other // static variables may try to allocate memory before these variables // can run their constructors. static SizeMap sizemap_; static CentralFreeListPadded central_cache_[kNumClasses]; static PageHeapAllocator span_allocator_; static PageHeapAllocator stacktrace_allocator_; static Span sampled_objects_; static PageHeapAllocator bucket_allocator_; // Linked list of stack traces recorded every time we allocated memory // from the system. Useful for finding allocation sites that cause // increase in the footprint of the system. The linked list pointer // is stored in trace->stack[kMaxStackDepth-1]. static StackTrace* growth_stacks_; // PageHeap uses a constructor for initialization. Like the members above, // we can't depend on initialization order, so pageheap is new'd // into this buffer. static char pageheap_memory_[sizeof(PageHeap)]; }; } // namespace tcmalloc #endif // TCMALLOC_STATIC_VARS_H_ ================================================ FILE: distro/google-perftools-1.7/src/symbolize.cc ================================================ // Copyright (c) 2009, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Craig Silverstein // // This forks out to pprof to do the actual symbolizing. We might // be better off writing our own in C++. #include "config.h" #include "symbolize.h" #include #ifdef HAVE_UNISTD_H #include // for write() #endif #ifdef HAVE_SYS_SOCKET_H #include // for socketpair() -- needed by Symbolize #endif #ifdef HAVE_SYS_WAIT_H #include // for wait() -- needed by Symbolize #endif #ifdef HAVE_POLL_H #include #endif #include #include "base/commandlineflags.h" #include "base/sysinfo.h" using std::string; using tcmalloc::DumpProcSelfMaps; // from sysinfo.h DEFINE_string(symbolize_pprof, EnvToString("PPROF_PATH", "pprof"), "Path to pprof to call for reporting function names."); // heap_profile_table_pprof may be referenced after destructors are // called (since that's when leak-checking is done), so we make // a more-permanent copy that won't ever get destroyed. static string* g_pprof_path = new string(FLAGS_symbolize_pprof); void SymbolTable::Add(const void* addr) { symbolization_table_[addr] = ""; } const char* SymbolTable::GetSymbol(const void* addr) { return symbolization_table_[addr]; } // Updates symbolization_table with the pointers to symbol names corresponding // to its keys. The symbol names are stored in out, which is allocated and // freed by the caller of this routine. // Note that the forking/etc is not thread-safe or re-entrant. That's // ok for the purpose we need -- reporting leaks detected by heap-checker // -- but be careful if you decide to use this routine for other purposes. int SymbolTable::Symbolize() { #if !defined(HAVE_UNISTD_H) || !defined(HAVE_SYS_SOCKET_H) || !defined(HAVE_SYS_WAIT_H) return 0; #elif !defined(HAVE_PROGRAM_INVOCATION_NAME) return 0; // TODO(csilvers): get argv[0] somehow #else // All this work is to do two-way communication. ugh. extern char* program_invocation_name; // gcc provides this int *child_in = NULL; // file descriptors int *child_out = NULL; // for now, we don't worry about child_err int child_fds[5][2]; // socketpair may be called up to five times below // The client program may close its stdin and/or stdout and/or stderr // thus allowing socketpair to reuse file descriptors 0, 1 or 2. // In this case the communication between the forked processes may be broken // if either the parent or the child tries to close or duplicate these // descriptors. The loop below produces two pairs of file descriptors, each // greater than 2 (stderr). for (int i = 0; i < 5; i++) { if (socketpair(AF_UNIX, SOCK_STREAM, 0, child_fds[i]) == -1) { for (int j = 0; j < i; j++) { close(child_fds[j][0]); close(child_fds[j][1]); return 0; } } else { if ((child_fds[i][0] > 2) && (child_fds[i][1] > 2)) { if (child_in == NULL) { child_in = child_fds[i]; } else { child_out = child_fds[i]; for (int j = 0; j < i; j++) { if (child_fds[j] == child_in) continue; close(child_fds[j][0]); close(child_fds[j][1]); } break; } } } } switch (fork()) { case -1: { // error close(child_in[0]); close(child_in[1]); close(child_out[0]); close(child_out[1]); return 0; } case 0: { // child close(child_in[1]); // child uses the 0's, parent uses the 1's close(child_out[1]); // child uses the 0's, parent uses the 1's close(0); close(1); if (dup2(child_in[0], 0) == -1) _exit(1); if (dup2(child_out[0], 1) == -1) _exit(2); // Unset vars that might cause trouble when we fork unsetenv("CPUPROFILE"); unsetenv("HEAPPROFILE"); unsetenv("HEAPCHECK"); unsetenv("PERFTOOLS_VERBOSE"); execlp(g_pprof_path->c_str(), g_pprof_path->c_str(), "--symbols", program_invocation_name, NULL); _exit(3); // if execvp fails, it's bad news for us } default: { // parent close(child_in[0]); // child uses the 0's, parent uses the 1's close(child_out[0]); // child uses the 0's, parent uses the 1's #ifdef HAVE_POLL_H // For maximum safety, we check to make sure the execlp // succeeded before trying to write. (Otherwise we'll get a // SIGPIPE.) For systems without poll.h, we'll just skip this // check, and trust that the user set PPROF_PATH correctly! struct pollfd pfd = { child_in[1], POLLOUT, 0 }; if (!poll(&pfd, 1, 0) || !(pfd.revents & POLLOUT) || (pfd.revents & (POLLHUP|POLLERR))) { return 0; } #endif DumpProcSelfMaps(child_in[1]); // what pprof expects on stdin // Allocate 24 bytes = ("0x" + 8 bytes + "\n" + overhead) for each // address to feed to pprof. const int kOutBufSize = 24 * symbolization_table_.size(); char *pprof_buffer = new char[kOutBufSize]; int written = 0; for (SymbolMap::const_iterator iter = symbolization_table_.begin(); iter != symbolization_table_.end(); ++iter) { written += snprintf(pprof_buffer + written, kOutBufSize - written, // pprof expects format to be 0xXXXXXX "0x%"PRIxPTR"\n", reinterpret_cast(iter->first)); } write(child_in[1], pprof_buffer, strlen(pprof_buffer)); close(child_in[1]); // that's all we need to write const int kSymbolBufferSize = kSymbolSize * symbolization_table_.size(); int total_bytes_read = 0; delete[] symbol_buffer_; symbol_buffer_ = new char[kSymbolBufferSize]; memset(symbol_buffer_, '\0', kSymbolBufferSize); while (1) { int bytes_read = read(child_out[1], symbol_buffer_ + total_bytes_read, kSymbolBufferSize - total_bytes_read); if (bytes_read < 0) { close(child_out[1]); return 0; } else if (bytes_read == 0) { close(child_out[1]); wait(NULL); break; } else { total_bytes_read += bytes_read; } } // We have successfully read the output of pprof into out. Make sure // the last symbol is full (we can tell because it ends with a \n). if (total_bytes_read == 0 || symbol_buffer_[total_bytes_read - 1] != '\n') return 0; // make the symbolization_table_ values point to the output vector SymbolMap::iterator fill = symbolization_table_.begin(); int num_symbols = 0; const char *current_name = symbol_buffer_; for (int i = 0; i < total_bytes_read; i++) { if (symbol_buffer_[i] == '\n') { fill->second = current_name; symbol_buffer_[i] = '\0'; current_name = symbol_buffer_ + i + 1; fill++; num_symbols++; } } return num_symbols; } } return 0; // shouldn't be reachable #endif } ================================================ FILE: distro/google-perftools-1.7/src/symbolize.h ================================================ // Copyright (c) 2009, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Craig Silverstein #ifndef TCMALLOC_SYMBOLIZE_H_ #define TCMALLOC_SYMBOLIZE_H_ #include "config.h" #ifdef HAVE_STDINT_H #include // for uintptr_t #endif #include // for NULL #include using std::map; // SymbolTable encapsulates the address operations necessary for stack trace // symbolization. A common use-case is to Add() the addresses from one or // several stack traces to a table, call Symbolize() once and use GetSymbol() // to get the symbol names for pretty-printing the stack traces. class SymbolTable { public: SymbolTable() : symbol_buffer_(NULL) {} ~SymbolTable() { delete[] symbol_buffer_; } // Adds an address to the table. This may overwrite a currently known symbol // name, so Add() should not generally be called after Symbolize(). void Add(const void* addr); // Returns the symbol name for addr, if the given address was added before // the last successful call to Symbolize(). Otherwise may return an empty // c-string. const char* GetSymbol(const void* addr); // Obtains the symbol names for the addresses stored in the table and returns // the number of addresses actually symbolized. int Symbolize(); private: typedef map SymbolMap; // An average size of memory allocated for a stack trace symbol. static const int kSymbolSize = 1024; // Map from addresses to symbol names. SymbolMap symbolization_table_; // Pointer to the buffer that stores the symbol names. char *symbol_buffer_; }; #endif // TCMALLOC_SYMBOLIZE_H_ ================================================ FILE: distro/google-perftools-1.7/src/system-alloc.cc ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat #include #include // for NULL #if defined HAVE_STDINT_H #include #elif defined HAVE_INTTYPES_H #include #else #include #endif #ifdef HAVE_UNISTD_H #include #endif #include // for open() #ifdef HAVE_MMAP #include #endif #include #include "common.h" #include "system-alloc.h" #include "internal_logging.h" #include "base/logging.h" #include "base/commandlineflags.h" #include "base/spinlock.h" // On systems (like freebsd) that don't define MAP_ANONYMOUS, use the old // form of the name instead. #ifndef MAP_ANONYMOUS # define MAP_ANONYMOUS MAP_ANON #endif // Solaris has a bug where it doesn't declare madvise() for C++. // http://www.opensolaris.org/jive/thread.jspa?threadID=21035&tstart=0 #if defined(__sun) && defined(__SVR4) # include // for caddr_t extern "C" { extern int madvise(caddr_t, size_t, int); } #endif // Set kDebugMode mode so that we can have use C++ conditionals // instead of preprocessor conditionals. #ifdef NDEBUG static const bool kDebugMode = false; #else static const bool kDebugMode = true; #endif // Anonymous namespace to avoid name conflicts on "CheckAddressBits". namespace { // Check that no bit is set at position ADDRESS_BITS or higher. template bool CheckAddressBits(uintptr_t ptr) { return (ptr >> ADDRESS_BITS) == 0; } // Specialize for the bit width of a pointer to avoid undefined shift. template <> bool CheckAddressBits<8 * sizeof(void*)>(uintptr_t ptr) { return true; } } // Anonymous namespace to avoid name conflicts on "CheckAddressBits". COMPILE_ASSERT(kAddressBits <= 8 * sizeof(void*), address_bits_larger_than_pointer_size); // Structure for discovering alignment union MemoryAligner { void* p; double d; size_t s; } CACHELINE_ALIGNED; static SpinLock spinlock(SpinLock::LINKER_INITIALIZED); #if defined(HAVE_MMAP) || defined(MADV_DONTNEED) // Page size is initialized on demand (only needed for mmap-based allocators) static size_t pagesize = 0; #endif // Configuration parameters. DEFINE_int32(malloc_devmem_start, EnvToInt("TCMALLOC_DEVMEM_START", 0), "Physical memory starting location in MB for /dev/mem allocation." " Setting this to 0 disables /dev/mem allocation"); DEFINE_int32(malloc_devmem_limit, EnvToInt("TCMALLOC_DEVMEM_LIMIT", 0), "Physical memory limit location in MB for /dev/mem allocation." " Setting this to 0 means no limit."); DEFINE_bool(malloc_skip_sbrk, EnvToBool("TCMALLOC_SKIP_SBRK", false), "Whether sbrk can be used to obtain memory."); DEFINE_bool(malloc_skip_mmap, EnvToBool("TCMALLOC_SKIP_MMAP", false), "Whether mmap can be used to obtain memory."); // static allocators class SbrkSysAllocator : public SysAllocator { public: SbrkSysAllocator() : SysAllocator() { } void* Alloc(size_t size, size_t *actual_size, size_t alignment); void DumpStats(TCMalloc_Printer* printer); }; static char sbrk_space[sizeof(SbrkSysAllocator)]; class MmapSysAllocator : public SysAllocator { public: MmapSysAllocator() : SysAllocator() { } void* Alloc(size_t size, size_t *actual_size, size_t alignment); void DumpStats(TCMalloc_Printer* printer); }; static char mmap_space[sizeof(MmapSysAllocator)]; class DevMemSysAllocator : public SysAllocator { public: DevMemSysAllocator() : SysAllocator() { } void* Alloc(size_t size, size_t *actual_size, size_t alignment); void DumpStats(TCMalloc_Printer* printer); }; static char devmem_space[sizeof(DevMemSysAllocator)]; static const int kStaticAllocators = 3; // kMaxDynamicAllocators + kStaticAllocators; static const int kMaxAllocators = 5; static SysAllocator *allocators[kMaxAllocators]; bool RegisterSystemAllocator(SysAllocator *a, int priority) { SpinLockHolder lock_holder(&spinlock); // No two allocators should have a priority conflict, since the order // is determined at compile time. CHECK_CONDITION(allocators[priority] == NULL); allocators[priority] = a; return true; } void* SbrkSysAllocator::Alloc(size_t size, size_t *actual_size, size_t alignment) { #ifndef HAVE_SBRK failed_ = true; return NULL; #else // Check if we should use sbrk allocation. // FLAGS_malloc_skip_sbrk starts out as false (its uninitialized // state) and eventually gets initialized to the specified value. Note // that this code runs for a while before the flags are initialized. // That means that even if this flag is set to true, some (initial) // memory will be allocated with sbrk before the flag takes effect. if (FLAGS_malloc_skip_sbrk) { return NULL; } // sbrk will release memory if passed a negative number, so we do // a strict check here if (static_cast(size + alignment) < 0) return NULL; // This doesn't overflow because TCMalloc_SystemAlloc has already // tested for overflow at the alignment boundary. size = ((size + alignment - 1) / alignment) * alignment; // "actual_size" indicates that the bytes from the returned pointer // p up to and including (p + actual_size - 1) have been allocated. if (actual_size) { *actual_size = size; } // Check that we we're not asking for so much more memory that we'd // wrap around the end of the virtual address space. (This seems // like something sbrk() should check for us, and indeed opensolaris // does, but glibc does not: // http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/lib/libc/port/sys/sbrk.c?a=true // http://sourceware.org/cgi-bin/cvsweb.cgi/~checkout~/libc/misc/sbrk.c?rev=1.1.2.1&content-type=text/plain&cvsroot=glibc // Without this check, sbrk may succeed when it ought to fail.) if (reinterpret_cast(sbrk(0)) + size < size) { failed_ = true; return NULL; } void* result = sbrk(size); if (result == reinterpret_cast(-1)) { failed_ = true; return NULL; } // Is it aligned? uintptr_t ptr = reinterpret_cast(result); if ((ptr & (alignment-1)) == 0) return result; // Try to get more memory for alignment size_t extra = alignment - (ptr & (alignment-1)); void* r2 = sbrk(extra); if (reinterpret_cast(r2) == (ptr + size)) { // Contiguous with previous result return reinterpret_cast(ptr + extra); } // Give up and ask for "size + alignment - 1" bytes so // that we can find an aligned region within it. result = sbrk(size + alignment - 1); if (result == reinterpret_cast(-1)) { failed_ = true; return NULL; } ptr = reinterpret_cast(result); if ((ptr & (alignment-1)) != 0) { ptr += alignment - (ptr & (alignment-1)); } return reinterpret_cast(ptr); #endif // HAVE_SBRK } void SbrkSysAllocator::DumpStats(TCMalloc_Printer* printer) { printer->printf("SbrkSysAllocator: failed_=%d\n", failed_); } void* MmapSysAllocator::Alloc(size_t size, size_t *actual_size, size_t alignment) { #ifndef HAVE_MMAP failed_ = true; return NULL; #else // Check if we should use mmap allocation. // FLAGS_malloc_skip_mmap starts out as false (its uninitialized // state) and eventually gets initialized to the specified value. Note // that this code runs for a while before the flags are initialized. // Chances are we never get here before the flags are initialized since // sbrk is used until the heap is exhausted (before mmap is used). if (FLAGS_malloc_skip_mmap) { return NULL; } // Enforce page alignment if (pagesize == 0) pagesize = getpagesize(); if (alignment < pagesize) alignment = pagesize; size_t aligned_size = ((size + alignment - 1) / alignment) * alignment; if (aligned_size < size) { return NULL; } size = aligned_size; // "actual_size" indicates that the bytes from the returned pointer // p up to and including (p + actual_size - 1) have been allocated. if (actual_size) { *actual_size = size; } // Ask for extra memory if alignment > pagesize size_t extra = 0; if (alignment > pagesize) { extra = alignment - pagesize; } // Note: size + extra does not overflow since: // size + alignment < (1<(MAP_FAILED)) { failed_ = true; return NULL; } // Adjust the return memory so it is aligned uintptr_t ptr = reinterpret_cast(result); size_t adjust = 0; if ((ptr & (alignment - 1)) != 0) { adjust = alignment - (ptr & (alignment - 1)); } // Return the unused memory to the system if (adjust > 0) { munmap(reinterpret_cast(ptr), adjust); } if (adjust < extra) { munmap(reinterpret_cast(ptr + adjust + size), extra - adjust); } ptr += adjust; return reinterpret_cast(ptr); #endif // HAVE_MMAP } void MmapSysAllocator::DumpStats(TCMalloc_Printer* printer) { printer->printf("MmapSysAllocator: failed_=%d\n", failed_); } void* DevMemSysAllocator::Alloc(size_t size, size_t *actual_size, size_t alignment) { #ifndef HAVE_MMAP failed_ = true; return NULL; #else static bool initialized = false; static off_t physmem_base; // next physical memory address to allocate static off_t physmem_limit; // maximum physical address allowed static int physmem_fd; // file descriptor for /dev/mem // Check if we should use /dev/mem allocation. Note that it may take // a while to get this flag initialized, so meanwhile we fall back to // the next allocator. (It looks like 7MB gets allocated before // this flag gets initialized -khr.) if (FLAGS_malloc_devmem_start == 0) { // NOTE: not a devmem_failure - we'd like TCMalloc_SystemAlloc to // try us again next time. return NULL; } if (!initialized) { physmem_fd = open("/dev/mem", O_RDWR); if (physmem_fd < 0) { failed_ = true; return NULL; } physmem_base = FLAGS_malloc_devmem_start*1024LL*1024LL; physmem_limit = FLAGS_malloc_devmem_limit*1024LL*1024LL; initialized = true; } // Enforce page alignment if (pagesize == 0) pagesize = getpagesize(); if (alignment < pagesize) alignment = pagesize; size_t aligned_size = ((size + alignment - 1) / alignment) * alignment; if (aligned_size < size) { return NULL; } size = aligned_size; // "actual_size" indicates that the bytes from the returned pointer // p up to and including (p + actual_size - 1) have been allocated. if (actual_size) { *actual_size = size; } // Ask for extra memory if alignment > pagesize size_t extra = 0; if (alignment > pagesize) { extra = alignment - pagesize; } // check to see if we have any memory left if (physmem_limit != 0 && ((size + extra) > (physmem_limit - physmem_base))) { failed_ = true; return NULL; } // Note: size + extra does not overflow since: // size + alignment < (1<(MAP_FAILED)) { failed_ = true; return NULL; } uintptr_t ptr = reinterpret_cast(result); // Adjust the return memory so it is aligned size_t adjust = 0; if ((ptr & (alignment - 1)) != 0) { adjust = alignment - (ptr & (alignment - 1)); } // Return the unused virtual memory to the system if (adjust > 0) { munmap(reinterpret_cast(ptr), adjust); } if (adjust < extra) { munmap(reinterpret_cast(ptr + adjust + size), extra - adjust); } ptr += adjust; physmem_base += adjust + size; return reinterpret_cast(ptr); #endif // HAVE_MMAP } void DevMemSysAllocator::DumpStats(TCMalloc_Printer* printer) { printer->printf("DevMemSysAllocator: failed_=%d\n", failed_); } static bool system_alloc_inited = false; void InitSystemAllocators(void) { // This determines the order in which system allocators are called int i = kMaxDynamicAllocators; allocators[i++] = new (devmem_space) DevMemSysAllocator(); // In 64-bit debug mode, place the mmap allocator first since it // allocates pointers that do not fit in 32 bits and therefore gives // us better testing of code's 64-bit correctness. It also leads to // less false negatives in heap-checking code. (Numbers are less // likely to look like pointers and therefore the conservative gc in // the heap-checker is less likely to misinterpret a number as a // pointer). if (kDebugMode && sizeof(void*) > 4) { allocators[i++] = new (mmap_space) MmapSysAllocator(); allocators[i++] = new (sbrk_space) SbrkSysAllocator(); } else { allocators[i++] = new (sbrk_space) SbrkSysAllocator(); allocators[i++] = new (mmap_space) MmapSysAllocator(); } } void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size, size_t alignment) { // Discard requests that overflow if (size + alignment < size) return NULL; SpinLockHolder lock_holder(&spinlock); if (!system_alloc_inited) { InitSystemAllocators(); system_alloc_inited = true; } // Enforce minimum alignment if (alignment < sizeof(MemoryAligner)) alignment = sizeof(MemoryAligner); // Try twice, once avoiding allocators that failed before, and once // more trying all allocators even if they failed before. for (int i = 0; i < 2; i++) { for (int j = 0; j < kMaxAllocators; j++) { SysAllocator *a = allocators[j]; if (a == NULL) continue; if (a->usable_ && !a->failed_) { void* result = a->Alloc(size, actual_size, alignment); if (result != NULL) { if (actual_size) { CheckAddressBits( reinterpret_cast(result) + *actual_size - 1); } else { CheckAddressBits( reinterpret_cast(result) + size - 1); } return result; } } } // nothing worked - reset failed_ flags and try again for (int j = 0; j < kMaxAllocators; j++) { SysAllocator *a = allocators[j]; if (a == NULL) continue; a->failed_ = false; } } return NULL; } void TCMalloc_SystemRelease(void* start, size_t length) { #ifdef MADV_DONTNEED if (FLAGS_malloc_devmem_start) { // It's not safe to use MADV_DONTNEED if we've been mapping // /dev/mem for heap memory return; } if (pagesize == 0) pagesize = getpagesize(); const size_t pagemask = pagesize - 1; size_t new_start = reinterpret_cast(start); size_t end = new_start + length; size_t new_end = end; // Round up the starting address and round down the ending address // to be page aligned: new_start = (new_start + pagesize - 1) & ~pagemask; new_end = new_end & ~pagemask; ASSERT((new_start & pagemask) == 0); ASSERT((new_end & pagemask) == 0); ASSERT(new_start >= reinterpret_cast(start)); ASSERT(new_end <= end); if (new_end > new_start) { // Note -- ignoring most return codes, because if this fails it // doesn't matter... while (madvise(reinterpret_cast(new_start), new_end - new_start, MADV_DONTNEED) == -1 && errno == EAGAIN) { // NOP } } #endif } void DumpSystemAllocatorStats(TCMalloc_Printer* printer) { for (int j = 0; j < kMaxAllocators; j++) { SysAllocator *a = allocators[j]; if (a == NULL) continue; if (a->usable_) { a->DumpStats(printer); } } } ================================================ FILE: distro/google-perftools-1.7/src/system-alloc.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // Routine that uses sbrk/mmap to allocate memory from the system. // Useful for implementing malloc. #ifndef TCMALLOC_SYSTEM_ALLOC_H_ #define TCMALLOC_SYSTEM_ALLOC_H_ #include #include "internal_logging.h" // REQUIRES: "alignment" is a power of two or "0" to indicate default alignment // // Allocate and return "N" bytes of zeroed memory. // // If actual_bytes is NULL then the returned memory is exactly the // requested size. If actual bytes is non-NULL then the allocator // may optionally return more bytes than asked for (i.e. return an // entire "huge" page if a huge page allocator is in use). // // The returned pointer is a multiple of "alignment" if non-zero. The // returned pointer will always be aligned suitably for holding a // void*, double, or size_t. In addition, if this platform defines // CACHELINE_ALIGNED, the return pointer will always be cacheline // aligned. // // Returns NULL when out of memory. extern void* TCMalloc_SystemAlloc(size_t bytes, size_t *actual_bytes, size_t alignment = 0); // This call is a hint to the operating system that the pages // contained in the specified range of memory will not be used for a // while, and can be released for use by other processes or the OS. // Pages which are released in this way may be destroyed (zeroed) by // the OS. The benefit of this function is that it frees memory for // use by the system, the cost is that the pages are faulted back into // the address space next time they are touched, which can impact // performance. (Only pages fully covered by the memory region will // be released, partial pages will not.) extern void TCMalloc_SystemRelease(void* start, size_t length); // Interface to a pluggable system allocator. class SysAllocator { public: SysAllocator() : usable_(true), failed_(false) { }; virtual ~SysAllocator() {}; virtual void* Alloc(size_t size, size_t *actual_size, size_t alignment) = 0; // Populate the map with whatever properties the specified allocator finds // useful for debugging (such as number of bytes allocated and whether the // allocator has failed). The callee is responsible for any necessary // locking (and avoiding deadlock). virtual void DumpStats(TCMalloc_Printer* printer) = 0; // So the allocator can be turned off at compile time bool usable_; // Did this allocator fail? If so, we don't need to retry more than twice. bool failed_; }; // Register a new system allocator. The priority determines the order in // which the allocators will be invoked. Allocators with numerically lower // priority are tried first. To keep things simple, the priority of various // allocators is known at compile time. // // Valid range of priorities: [0, kMaxDynamicAllocators) // // Please note that we can't use complex data structures and cause // recursive calls to malloc within this function. So all data structures // are statically allocated. // // Returns true on success. Does nothing on failure. extern PERFTOOLS_DLL_DECL bool RegisterSystemAllocator(SysAllocator *allocator, int priority); // Number of SysAllocators known to call RegisterSystemAllocator static const int kMaxDynamicAllocators = 2; // Retrieve the current state of various system allocators. extern PERFTOOLS_DLL_DECL void DumpSystemAllocatorStats(TCMalloc_Printer* printer); #endif /* TCMALLOC_SYSTEM_ALLOC_H_ */ ================================================ FILE: distro/google-perftools-1.7/src/tcmalloc.cc ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // A malloc that uses a per-thread cache to satisfy small malloc requests. // (The time for malloc/free of a small object drops from 300 ns to 50 ns.) // // See doc/tcmalloc.html for a high-level // description of how this malloc works. // // SYNCHRONIZATION // 1. The thread-specific lists are accessed without acquiring any locks. // This is safe because each such list is only accessed by one thread. // 2. We have a lock per central free-list, and hold it while manipulating // the central free list for a particular size. // 3. The central page allocator is protected by "pageheap_lock". // 4. The pagemap (which maps from page-number to descriptor), // can be read without holding any locks, and written while holding // the "pageheap_lock". // 5. To improve performance, a subset of the information one can get // from the pagemap is cached in a data structure, pagemap_cache_, // that atomically reads and writes its entries. This cache can be // read and written without locking. // // This multi-threaded access to the pagemap is safe for fairly // subtle reasons. We basically assume that when an object X is // allocated by thread A and deallocated by thread B, there must // have been appropriate synchronization in the handoff of object // X from thread A to thread B. The same logic applies to pagemap_cache_. // // THE PAGEID-TO-SIZECLASS CACHE // Hot PageID-to-sizeclass mappings are held by pagemap_cache_. If this cache // returns 0 for a particular PageID then that means "no information," not that // the sizeclass is 0. The cache may have stale information for pages that do // not hold the beginning of any free()'able object. Staleness is eliminated // in Populate() for pages with sizeclass > 0 objects, and in do_malloc() and // do_memalign() for all other relevant pages. // // PAGEMAP // ------- // Page map contains a mapping from page id to Span. // // If Span s occupies pages [p..q], // pagemap[p] == s // pagemap[q] == s // pagemap[p+1..q-1] are undefined // pagemap[p-1] and pagemap[q+1] are defined: // NULL if the corresponding page is not yet in the address space. // Otherwise it points to a Span. This span may be free // or allocated. If free, it is in one of pageheap's freelist. // // TODO: Bias reclamation to larger addresses // TODO: implement mallinfo/mallopt // TODO: Better testing // // 9/28/2003 (new page-level allocator replaces ptmalloc2): // * malloc/free of small objects goes from ~300 ns to ~50 ns. // * allocation of a reasonably complicated struct // goes from about 1100 ns to about 300 ns. #include #include #include #include #if defined HAVE_STDINT_H #include #elif defined HAVE_INTTYPES_H #include #else #include #endif #if defined(HAVE_MALLOC_H) && defined(HAVE_STRUCT_MALLINFO) #include // for struct mallinfo #endif #include #ifdef HAVE_PTHREAD #include #endif #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #include #include "base/commandlineflags.h" #include "base/basictypes.h" // gets us PRIu64 #include "base/sysinfo.h" #include "base/spinlock.h" #include "common.h" #include "malloc_hook-inl.h" #include #include #include "central_freelist.h" #include "internal_logging.h" #include "linked_list.h" #include "maybe_threads.h" #include "page_heap.h" #include "page_heap_allocator.h" #include "pagemap.h" #include "span.h" #include "static_vars.h" #include "system-alloc.h" #include "tcmalloc_guard.h" #include "thread_cache.h" #if (defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)) && !defined(WIN32_OVERRIDE_ALLOCATORS) # define WIN32_DO_PATCHING 1 #endif using STL_NAMESPACE::max; using STL_NAMESPACE::numeric_limits; using STL_NAMESPACE::vector; using tcmalloc::AlignmentForSize; using tcmalloc::PageHeap; using tcmalloc::PageHeapAllocator; using tcmalloc::SizeMap; using tcmalloc::Span; using tcmalloc::StackTrace; using tcmalloc::Static; using tcmalloc::ThreadCache; // __THROW is defined in glibc systems. It means, counter-intuitively, // "This function will never throw an exception." It's an optional // optimization tool, but we may need to use it to match glibc prototypes. #ifndef __THROW // I guess we're not on a glibc system # define __THROW // __THROW is just an optimization, so ok to make it "" #endif DECLARE_int64(tcmalloc_sample_parameter); DECLARE_double(tcmalloc_release_rate); // For windows, the printf we use to report large allocs is // potentially dangerous: it could cause a malloc that would cause an // infinite loop. So by default we set the threshold to a huge number // on windows, so this bad situation will never trigger. You can // always set TCMALLOC_LARGE_ALLOC_REPORT_THRESHOLD manually if you // want this functionality. #ifdef _WIN32 const int64 kDefaultLargeAllocReportThreshold = static_cast(1) << 62; #else const int64 kDefaultLargeAllocReportThreshold = static_cast(1) << 30; #endif DEFINE_int64(tcmalloc_large_alloc_report_threshold, EnvToInt64("TCMALLOC_LARGE_ALLOC_REPORT_THRESHOLD", kDefaultLargeAllocReportThreshold), "Allocations larger than this value cause a stack " "trace to be dumped to stderr. The threshold for " "dumping stack traces is increased by a factor of 1.125 " "every time we print a message so that the threshold " "automatically goes up by a factor of ~1000 every 60 " "messages. This bounds the amount of extra logging " "generated by this flag. Default value of this flag " "is very large and therefore you should see no extra " "logging unless the flag is overridden. Set to 0 to " "disable reporting entirely."); // We already declared these functions in tcmalloc.h, but we have to // declare them again to give them an ATTRIBUTE_SECTION: we want to // put all callers of MallocHook::Invoke* in this module into // ATTRIBUTE_SECTION(google_malloc) section, so that // MallocHook::GetCallerStackTrace can function accurately. #ifndef _WIN32 // windows doesn't have attribute_section, so don't bother extern "C" { void* tc_malloc(size_t size) __THROW ATTRIBUTE_SECTION(google_malloc); void tc_free(void* ptr) __THROW ATTRIBUTE_SECTION(google_malloc); void* tc_realloc(void* ptr, size_t size) __THROW ATTRIBUTE_SECTION(google_malloc); void* tc_calloc(size_t nmemb, size_t size) __THROW ATTRIBUTE_SECTION(google_malloc); void tc_cfree(void* ptr) __THROW ATTRIBUTE_SECTION(google_malloc); void* tc_memalign(size_t __alignment, size_t __size) __THROW ATTRIBUTE_SECTION(google_malloc); int tc_posix_memalign(void** ptr, size_t align, size_t size) __THROW ATTRIBUTE_SECTION(google_malloc); void* tc_valloc(size_t __size) __THROW ATTRIBUTE_SECTION(google_malloc); void* tc_pvalloc(size_t __size) __THROW ATTRIBUTE_SECTION(google_malloc); void tc_malloc_stats(void) __THROW ATTRIBUTE_SECTION(google_malloc); int tc_mallopt(int cmd, int value) __THROW ATTRIBUTE_SECTION(google_malloc); #ifdef HAVE_STRUCT_MALLINFO struct mallinfo tc_mallinfo(void) __THROW ATTRIBUTE_SECTION(google_malloc); #endif void* tc_new(size_t size) ATTRIBUTE_SECTION(google_malloc); void tc_delete(void* p) __THROW ATTRIBUTE_SECTION(google_malloc); void* tc_newarray(size_t size) ATTRIBUTE_SECTION(google_malloc); void tc_deletearray(void* p) __THROW ATTRIBUTE_SECTION(google_malloc); // And the nothrow variants of these: void* tc_new_nothrow(size_t size, const std::nothrow_t&) __THROW ATTRIBUTE_SECTION(google_malloc); void* tc_newarray_nothrow(size_t size, const std::nothrow_t&) __THROW ATTRIBUTE_SECTION(google_malloc); // Surprisingly, standard C++ library implementations use a // nothrow-delete internally. See, eg: // http://www.dinkumware.com/manuals/?manual=compleat&page=new.html void tc_delete_nothrow(void* ptr, const std::nothrow_t&) __THROW ATTRIBUTE_SECTION(google_malloc); void tc_deletearray_nothrow(void* ptr, const std::nothrow_t&) __THROW ATTRIBUTE_SECTION(google_malloc); // Some non-standard extensions that we support. // This is equivalent to // OS X: malloc_size() // glibc: malloc_usable_size() // Windows: _msize() size_t tc_malloc_size(void* p) __THROW ATTRIBUTE_SECTION(google_malloc); } // extern "C" #endif // #ifndef _WIN32 // Override the libc functions to prefer our own instead. This comes // first so code in tcmalloc.cc can use the overridden versions. One // exception: in windows, by default, we patch our code into these // functions (via src/windows/patch_function.cc) rather than override // them. In that case, we don't want to do this overriding here. #if !defined(WIN32_DO_PATCHING) && !defined(TCMALLOC_FOR_DEBUGALLOCATION) #if defined(__GNUC__) && !defined(__MACH__) // Potentially faster variants that use the gcc alias extension. // FreeBSD does support aliases, but apparently not correctly. :-( // NOTE: we make many of these symbols weak, but do so in the makefile // (via objcopy -W) and not here. That ends up being more portable. # define ALIAS(x) __attribute__ ((alias (x))) void* operator new(size_t size) throw (std::bad_alloc) ALIAS("tc_new"); void operator delete(void* p) __THROW ALIAS("tc_delete"); void* operator new[](size_t size) throw (std::bad_alloc) ALIAS("tc_newarray"); void operator delete[](void* p) __THROW ALIAS("tc_deletearray"); void* operator new(size_t size, const std::nothrow_t&) __THROW ALIAS("tc_new_nothrow"); void* operator new[](size_t size, const std::nothrow_t&) __THROW ALIAS("tc_newarray_nothrow"); void operator delete(void* size, const std::nothrow_t&) __THROW ALIAS("tc_delete_nothrow"); void operator delete[](void* size, const std::nothrow_t&) __THROW ALIAS("tc_deletearray_nothrow"); extern "C" { void* malloc(size_t size) __THROW ALIAS("tc_malloc"); void free(void* ptr) __THROW ALIAS("tc_free"); void* realloc(void* ptr, size_t size) __THROW ALIAS("tc_realloc"); void* calloc(size_t n, size_t size) __THROW ALIAS("tc_calloc"); void cfree(void* ptr) __THROW ALIAS("tc_cfree"); void* memalign(size_t align, size_t s) __THROW ALIAS("tc_memalign"); void* valloc(size_t size) __THROW ALIAS("tc_valloc"); void* pvalloc(size_t size) __THROW ALIAS("tc_pvalloc"); int posix_memalign(void** r, size_t a, size_t s) __THROW ALIAS("tc_posix_memalign"); void malloc_stats(void) __THROW ALIAS("tc_malloc_stats"); int mallopt(int cmd, int value) __THROW ALIAS("tc_mallopt"); #ifdef HAVE_STRUCT_MALLINFO struct mallinfo mallinfo(void) __THROW ALIAS("tc_mallinfo"); #endif size_t malloc_size(void* p) __THROW ALIAS("tc_malloc_size"); size_t malloc_usable_size(void* p) __THROW ALIAS("tc_malloc_size"); } // extern "C" #else // #if defined(__GNUC__) && !defined(__MACH__) // Portable wrappers void* operator new(size_t size) { return tc_new(size); } void operator delete(void* p) __THROW { tc_delete(p); } void* operator new[](size_t size) { return tc_newarray(size); } void operator delete[](void* p) __THROW { tc_deletearray(p); } void* operator new(size_t size, const std::nothrow_t& nt) __THROW { return tc_new_nothrow(size, nt); } void* operator new[](size_t size, const std::nothrow_t& nt) __THROW { return tc_newarray_nothrow(size, nt); } void operator delete(void* ptr, const std::nothrow_t& nt) __THROW { return tc_delete_nothrow(ptr, nt); } void operator delete[](void* ptr, const std::nothrow_t& nt) __THROW { return tc_deletearray_nothrow(ptr, nt); } extern "C" { void* malloc(size_t s) __THROW { return tc_malloc(s); } void free(void* p) __THROW { tc_free(p); } void* realloc(void* p, size_t s) __THROW { return tc_realloc(p, s); } void* calloc(size_t n, size_t s) __THROW { return tc_calloc(n, s); } void cfree(void* p) __THROW { tc_cfree(p); } void* memalign(size_t a, size_t s) __THROW { return tc_memalign(a, s); } void* valloc(size_t s) __THROW { return tc_valloc(s); } void* pvalloc(size_t s) __THROW { return tc_pvalloc(s); } int posix_memalign(void** r, size_t a, size_t s) __THROW { return tc_posix_memalign(r, a, s); } void malloc_stats(void) __THROW { tc_malloc_stats(); } int mallopt(int cmd, int v) __THROW { return tc_mallopt(cmd, v); } #ifdef HAVE_STRUCT_MALLINFO struct mallinfo mallinfo(void) __THROW { return tc_mallinfo(); } #endif size_t malloc_size(void* p) __THROW { return tc_malloc_size(p); } size_t malloc_usable_size(void* p) __THROW { return tc_malloc_size(p); } } // extern "C" #endif // #if defined(__GNUC__) // Some library routines on RedHat 9 allocate memory using malloc() // and free it using __libc_free() (or vice-versa). Since we provide // our own implementations of malloc/free, we need to make sure that // the __libc_XXX variants (defined as part of glibc) also point to // the same implementations. #ifdef __GLIBC__ // only glibc defines __libc_* extern "C" { #ifdef ALIAS void* __libc_malloc(size_t size) ALIAS("tc_malloc"); void __libc_free(void* ptr) ALIAS("tc_free"); void* __libc_realloc(void* ptr, size_t size) ALIAS("tc_realloc"); void* __libc_calloc(size_t n, size_t size) ALIAS("tc_calloc"); void __libc_cfree(void* ptr) ALIAS("tc_cfree"); void* __libc_memalign(size_t align, size_t s) ALIAS("tc_memalign"); void* __libc_valloc(size_t size) ALIAS("tc_valloc"); void* __libc_pvalloc(size_t size) ALIAS("tc_pvalloc"); int __posix_memalign(void** r, size_t a, size_t s) ALIAS("tc_posix_memalign"); #else // #ifdef ALIAS void* __libc_malloc(size_t size) { return malloc(size); } void __libc_free(void* ptr) { free(ptr); } void* __libc_realloc(void* ptr, size_t size) { return realloc(ptr, size); } void* __libc_calloc(size_t n, size_t size) { return calloc(n, size); } void __libc_cfree(void* ptr) { cfree(ptr); } void* __libc_memalign(size_t align, size_t s) { return memalign(align, s); } void* __libc_valloc(size_t size) { return valloc(size); } void* __libc_pvalloc(size_t size) { return pvalloc(size); } int __posix_memalign(void** r, size_t a, size_t s) { return posix_memalign(r, a, s); } #endif // #ifdef ALIAS } // extern "C" #endif // ifdef __GLIBC__ #undef ALIAS #endif // #ifndef(WIN32_DO_PATCHING) && ndef(TCMALLOC_FOR_DEBUGALLOCATION) // ----------------------- IMPLEMENTATION ------------------------------- static int tc_new_mode = 0; // See tc_set_new_mode(). // Routines such as free() and realloc() catch some erroneous pointers // passed to them, and invoke the below when they do. (An erroneous pointer // won't be caught if it's within a valid span or a stale span for which // the pagemap cache has a non-zero sizeclass.) This is a cheap (source-editing // required) kind of exception handling for these routines. namespace { void InvalidFree(void* ptr) { CRASH("Attempt to free invalid pointer: %p\n", ptr); } size_t InvalidGetSizeForRealloc(void* old_ptr) { CRASH("Attempt to realloc invalid pointer: %p\n", old_ptr); return 0; } size_t InvalidGetAllocatedSize(void* ptr) { CRASH("Attempt to get the size of an invalid pointer: %p\n", ptr); return 0; } } // unnamed namespace // Extract interesting stats struct TCMallocStats { uint64_t thread_bytes; // Bytes in thread caches uint64_t central_bytes; // Bytes in central cache uint64_t transfer_bytes; // Bytes in central transfer cache uint64_t metadata_bytes; // Bytes alloced for metadata PageHeap::Stats pageheap; // Stats from page heap }; // Get stats into "r". Also get per-size-class counts if class_count != NULL static void ExtractStats(TCMallocStats* r, uint64_t* class_count) { r->central_bytes = 0; r->transfer_bytes = 0; for (int cl = 0; cl < kNumClasses; ++cl) { const int length = Static::central_cache()[cl].length(); const int tc_length = Static::central_cache()[cl].tc_length(); const size_t size = static_cast( Static::sizemap()->ByteSizeForClass(cl)); r->central_bytes += (size * length); r->transfer_bytes += (size * tc_length); if (class_count) class_count[cl] = length + tc_length; } // Add stats from per-thread heaps r->thread_bytes = 0; { // scope SpinLockHolder h(Static::pageheap_lock()); ThreadCache::GetThreadStats(&r->thread_bytes, class_count); r->metadata_bytes = tcmalloc::metadata_system_bytes(); r->pageheap = Static::pageheap()->stats(); } } // WRITE stats to "out" static void DumpStats(TCMalloc_Printer* out, int level) { TCMallocStats stats; uint64_t class_count[kNumClasses]; ExtractStats(&stats, (level >= 2 ? class_count : NULL)); static const double MB = 1048576.0; const uint64_t virtual_memory_used = (stats.pageheap.system_bytes + stats.metadata_bytes); const uint64_t physical_memory_used = (virtual_memory_used - stats.pageheap.unmapped_bytes); const uint64_t bytes_in_use_by_app = (physical_memory_used - stats.metadata_bytes - stats.pageheap.free_bytes - stats.central_bytes - stats.transfer_bytes - stats.thread_bytes); out->printf( "------------------------------------------------\n" "MALLOC: %12" PRIu64 " (%7.1f MB) Bytes in use by application\n" "MALLOC: + %12" PRIu64 " (%7.1f MB) Bytes in page heap freelist\n" "MALLOC: + %12" PRIu64 " (%7.1f MB) Bytes in central cache freelist\n" "MALLOC: + %12" PRIu64 " (%7.1f MB) Bytes in transfer cache freelist\n" "MALLOC: + %12" PRIu64 " (%7.1f MB) Bytes in thread cache freelists\n" "MALLOC: + %12" PRIu64 " (%7.1f MB) Bytes in malloc metadata\n" "MALLOC: ------------\n" "MALLOC: = %12" PRIu64 " (%7.1f MB) Actual memory used (physical + swap)\n" "MALLOC: + %12" PRIu64 " (%7.1f MB) Bytes released to OS (aka unmapped)\n" "MALLOC: ------------\n" "MALLOC: = %12" PRIu64 " (%7.1f MB) Virtual address space used\n" "MALLOC:\n" "MALLOC: %12" PRIu64 " Spans in use\n" "MALLOC: %12" PRIu64 " Thread heaps in use\n" "MALLOC: %12" PRIu64 " Tcmalloc page size\n" "------------------------------------------------\n" "Call ReleaseFreeMemory() to release freelist memory to the OS" " (via madvise()).\n" "Bytes released to the OS take up virtual address space" " but no physical memory.\n", bytes_in_use_by_app, bytes_in_use_by_app / MB, stats.pageheap.free_bytes, stats.pageheap.free_bytes / MB, stats.central_bytes, stats.central_bytes / MB, stats.transfer_bytes, stats.transfer_bytes / MB, stats.thread_bytes, stats.thread_bytes / MB, stats.metadata_bytes, stats.metadata_bytes / MB, physical_memory_used, physical_memory_used / MB, stats.pageheap.unmapped_bytes, stats.pageheap.unmapped_bytes / MB, virtual_memory_used, virtual_memory_used / MB, uint64_t(Static::span_allocator()->inuse()), uint64_t(ThreadCache::HeapsInUse()), uint64_t(kPageSize)); if (level >= 2) { out->printf("------------------------------------------------\n"); out->printf("Size class breakdown\n"); out->printf("------------------------------------------------\n"); uint64_t cumulative = 0; for (int cl = 0; cl < kNumClasses; ++cl) { if (class_count[cl] > 0) { uint64_t class_bytes = class_count[cl] * Static::sizemap()->ByteSizeForClass(cl); cumulative += class_bytes; out->printf("class %3d [ %8" PRIuS " bytes ] : " "%8" PRIu64 " objs; %5.1f MB; %5.1f cum MB\n", cl, Static::sizemap()->ByteSizeForClass(cl), class_count[cl], class_bytes / MB, cumulative / MB); } } SpinLockHolder h(Static::pageheap_lock()); Static::pageheap()->Dump(out); out->printf("------------------------------------------------\n"); DumpSystemAllocatorStats(out); } } static void PrintStats(int level) { const int kBufferSize = 16 << 10; char* buffer = new char[kBufferSize]; TCMalloc_Printer printer(buffer, kBufferSize); DumpStats(&printer, level); write(STDERR_FILENO, buffer, strlen(buffer)); delete[] buffer; } static void** DumpHeapGrowthStackTraces() { // Count how much space we need int needed_slots = 0; { SpinLockHolder h(Static::pageheap_lock()); for (StackTrace* t = Static::growth_stacks(); t != NULL; t = reinterpret_cast( t->stack[tcmalloc::kMaxStackDepth-1])) { needed_slots += 3 + t->depth; } needed_slots += 100; // Slop in case list grows needed_slots += needed_slots/8; // An extra 12.5% slop } void** result = new void*[needed_slots]; if (result == NULL) { MESSAGE("tcmalloc: allocation failed for stack trace slots", needed_slots * sizeof(*result)); return NULL; } SpinLockHolder h(Static::pageheap_lock()); int used_slots = 0; for (StackTrace* t = Static::growth_stacks(); t != NULL; t = reinterpret_cast( t->stack[tcmalloc::kMaxStackDepth-1])) { ASSERT(used_slots < needed_slots); // Need to leave room for terminator if (used_slots + 3 + t->depth >= needed_slots) { // No more room break; } result[used_slots+0] = reinterpret_cast(static_cast(1)); result[used_slots+1] = reinterpret_cast(t->size); result[used_slots+2] = reinterpret_cast(t->depth); for (int d = 0; d < t->depth; d++) { result[used_slots+3+d] = t->stack[d]; } used_slots += 3 + t->depth; } result[used_slots] = reinterpret_cast(static_cast(0)); return result; } static void IterateOverRanges(void* arg, MallocExtension::RangeFunction func) { PageID page = 1; // Some code may assume that page==0 is never used bool done = false; while (!done) { // Accumulate a small number of ranges in a local buffer static const int kNumRanges = 16; static base::MallocRange ranges[kNumRanges]; int n = 0; { SpinLockHolder h(Static::pageheap_lock()); while (n < kNumRanges) { if (!Static::pageheap()->GetNextRange(page, &ranges[n])) { done = true; break; } else { uintptr_t limit = ranges[n].address + ranges[n].length; page = (limit + kPageSize - 1) >> kPageShift; n++; } } } for (int i = 0; i < n; i++) { (*func)(arg, &ranges[i]); } } } // TCMalloc's support for extra malloc interfaces class TCMallocImplementation : public MallocExtension { private: // ReleaseToSystem() might release more than the requested bytes because // the page heap releases at the span granularity, and spans are of wildly // different sizes. This member keeps track of the extra bytes bytes // released so that the app can periodically call ReleaseToSystem() to // release memory at a constant rate. // NOTE: Protected by Static::pageheap_lock(). size_t extra_bytes_released_; public: TCMallocImplementation() : extra_bytes_released_(0) { } virtual void GetStats(char* buffer, int buffer_length) { ASSERT(buffer_length > 0); TCMalloc_Printer printer(buffer, buffer_length); // Print level one stats unless lots of space is available if (buffer_length < 10000) { DumpStats(&printer, 1); } else { DumpStats(&printer, 2); } } // We may print an extra, tcmalloc-specific warning message here. virtual void GetHeapSample(MallocExtensionWriter* writer) { if (FLAGS_tcmalloc_sample_parameter == 0) { const char* const kWarningMsg = "%warn\n" "%warn This heap profile does not have any data in it, because\n" "%warn the application was run with heap sampling turned off.\n" "%warn To get useful data from GetHeapSample(), you must\n" "%warn set the environment variable TCMALLOC_SAMPLE_PARAMETER to\n" "%warn a positive sampling period, such as 524288.\n" "%warn\n"; writer->append(kWarningMsg, strlen(kWarningMsg)); } MallocExtension::GetHeapSample(writer); } virtual void** ReadStackTraces(int* sample_period) { tcmalloc::StackTraceTable table; { SpinLockHolder h(Static::pageheap_lock()); Span* sampled = Static::sampled_objects(); for (Span* s = sampled->next; s != sampled; s = s->next) { table.AddTrace(*reinterpret_cast(s->objects)); } } *sample_period = ThreadCache::GetCache()->GetSamplePeriod(); return table.ReadStackTracesAndClear(); // grabs and releases pageheap_lock } virtual void** ReadHeapGrowthStackTraces() { return DumpHeapGrowthStackTraces(); } virtual void Ranges(void* arg, RangeFunction func) { IterateOverRanges(arg, func); } virtual bool GetNumericProperty(const char* name, size_t* value) { ASSERT(name != NULL); if (strcmp(name, "generic.current_allocated_bytes") == 0) { TCMallocStats stats; ExtractStats(&stats, NULL); *value = stats.pageheap.system_bytes - stats.thread_bytes - stats.central_bytes - stats.transfer_bytes - stats.pageheap.free_bytes - stats.pageheap.unmapped_bytes; return true; } if (strcmp(name, "generic.heap_size") == 0) { TCMallocStats stats; ExtractStats(&stats, NULL); *value = stats.pageheap.system_bytes; return true; } if (strcmp(name, "tcmalloc.slack_bytes") == 0) { // Kept for backwards compatibility. Now defined externally as: // pageheap_free_bytes + pageheap_unmapped_bytes. SpinLockHolder l(Static::pageheap_lock()); PageHeap::Stats stats = Static::pageheap()->stats(); *value = stats.free_bytes + stats.unmapped_bytes; return true; } if (strcmp(name, "tcmalloc.pageheap_free_bytes") == 0) { SpinLockHolder l(Static::pageheap_lock()); *value = Static::pageheap()->stats().free_bytes; return true; } if (strcmp(name, "tcmalloc.pageheap_unmapped_bytes") == 0) { SpinLockHolder l(Static::pageheap_lock()); *value = Static::pageheap()->stats().unmapped_bytes; return true; } if (strcmp(name, "tcmalloc.max_total_thread_cache_bytes") == 0) { SpinLockHolder l(Static::pageheap_lock()); *value = ThreadCache::overall_thread_cache_size(); return true; } if (strcmp(name, "tcmalloc.current_total_thread_cache_bytes") == 0) { TCMallocStats stats; ExtractStats(&stats, NULL); *value = stats.thread_bytes; return true; } return false; } virtual bool SetNumericProperty(const char* name, size_t value) { ASSERT(name != NULL); if (strcmp(name, "tcmalloc.max_total_thread_cache_bytes") == 0) { SpinLockHolder l(Static::pageheap_lock()); ThreadCache::set_overall_thread_cache_size(value); return true; } return false; } virtual void MarkThreadIdle() { ThreadCache::BecomeIdle(); } virtual void MarkThreadBusy(); // Implemented below virtual void ReleaseToSystem(size_t num_bytes) { SpinLockHolder h(Static::pageheap_lock()); if (num_bytes <= extra_bytes_released_) { // We released too much on a prior call, so don't release any // more this time. extra_bytes_released_ = extra_bytes_released_ - num_bytes; return; } num_bytes = num_bytes - extra_bytes_released_; // num_bytes might be less than one page. If we pass zero to // ReleaseAtLeastNPages, it won't do anything, so we release a whole // page now and let extra_bytes_released_ smooth it out over time. Length num_pages = max(num_bytes >> kPageShift, 1); size_t bytes_released = Static::pageheap()->ReleaseAtLeastNPages( num_pages) << kPageShift; if (bytes_released > num_bytes) { extra_bytes_released_ = bytes_released - num_bytes; } else { // The PageHeap wasn't able to release num_bytes. Don't try to // compensate with a big release next time. Specifically, // ReleaseFreeMemory() calls ReleaseToSystem(LONG_MAX). extra_bytes_released_ = 0; } } virtual void SetMemoryReleaseRate(double rate) { FLAGS_tcmalloc_release_rate = rate; } virtual double GetMemoryReleaseRate() { return FLAGS_tcmalloc_release_rate; } virtual size_t GetEstimatedAllocatedSize(size_t size) { if (size <= kMaxSize) { const size_t cl = Static::sizemap()->SizeClass(size); const size_t alloc_size = Static::sizemap()->ByteSizeForClass(cl); return alloc_size; } else { return tcmalloc::pages(size) << kPageShift; } } // This just calls GetSizeWithCallback, but because that's in an // unnamed namespace, we need to move the definition below it in the // file. virtual size_t GetAllocatedSize(void* ptr); virtual void GetFreeListSizes(vector* v) { static const char* kCentralCacheType = "tcmalloc.central"; static const char* kTransferCacheType = "tcmalloc.transfer"; static const char* kThreadCacheType = "tcmalloc.thread"; static const char* kPageHeapType = "tcmalloc.page"; static const char* kPageHeapUnmappedType = "tcmalloc.page_unmapped"; static const char* kLargeSpanType = "tcmalloc.large"; static const char* kLargeUnmappedSpanType = "tcmalloc.large_unmapped"; v->clear(); // central class information int64 prev_class_size = 0; for (int cl = 1; cl < kNumClasses; ++cl) { size_t class_size = Static::sizemap()->ByteSizeForClass(cl); MallocExtension::FreeListInfo i; i.min_object_size = prev_class_size + 1; i.max_object_size = class_size; i.total_bytes_free = Static::central_cache()[cl].length() * class_size; i.type = kCentralCacheType; v->push_back(i); // transfer cache i.total_bytes_free = Static::central_cache()[cl].tc_length() * class_size; i.type = kTransferCacheType; v->push_back(i); prev_class_size = Static::sizemap()->ByteSizeForClass(cl); } // Add stats from per-thread heaps uint64_t class_count[kNumClasses]; memset(class_count, 0, sizeof(class_count)); { SpinLockHolder h(Static::pageheap_lock()); uint64_t thread_bytes = 0; ThreadCache::GetThreadStats(&thread_bytes, class_count); } prev_class_size = 0; for (int cl = 1; cl < kNumClasses; ++cl) { MallocExtension::FreeListInfo i; i.min_object_size = prev_class_size + 1; i.max_object_size = Static::sizemap()->ByteSizeForClass(cl); i.total_bytes_free = class_count[cl] * Static::sizemap()->ByteSizeForClass(cl); i.type = kThreadCacheType; v->push_back(i); } // append page heap info int64 page_count_normal[kMaxPages]; int64 page_count_returned[kMaxPages]; int64 span_count_normal; int64 span_count_returned; { SpinLockHolder h(Static::pageheap_lock()); Static::pageheap()->GetClassSizes(page_count_normal, page_count_returned, &span_count_normal, &span_count_returned); } // spans: mapped MallocExtension::FreeListInfo span_info; span_info.type = kLargeSpanType; span_info.max_object_size = (numeric_limits::max)(); span_info.min_object_size = kMaxPages << kPageShift; span_info.total_bytes_free = span_count_normal << kPageShift; v->push_back(span_info); // spans: unmapped span_info.type = kLargeUnmappedSpanType; span_info.total_bytes_free = span_count_returned << kPageShift; v->push_back(span_info); for (int s = 1; s < kMaxPages; s++) { MallocExtension::FreeListInfo i; i.max_object_size = (s << kPageShift); i.min_object_size = ((s - 1) << kPageShift); i.type = kPageHeapType; i.total_bytes_free = (s << kPageShift) * page_count_normal[s]; v->push_back(i); i.type = kPageHeapUnmappedType; i.total_bytes_free = (s << kPageShift) * page_count_returned[s]; v->push_back(i); } } }; // The constructor allocates an object to ensure that initialization // runs before main(), and therefore we do not have a chance to become // multi-threaded before initialization. We also create the TSD key // here. Presumably by the time this constructor runs, glibc is in // good enough shape to handle pthread_key_create(). // // The constructor also takes the opportunity to tell STL to use // tcmalloc. We want to do this early, before construct time, so // all user STL allocations go through tcmalloc (which works really // well for STL). // // The destructor prints stats when the program exits. static int tcmallocguard_refcount = 0; // no lock needed: runs before main() TCMallocGuard::TCMallocGuard() { if (tcmallocguard_refcount++ == 0) { #ifdef HAVE_TLS // this is true if the cc/ld/libc combo support TLS // Check whether the kernel also supports TLS (needs to happen at runtime) tcmalloc::CheckIfKernelSupportsTLS(); #endif #ifdef WIN32_DO_PATCHING // patch the windows VirtualAlloc, etc. PatchWindowsFunctions(); // defined in windows/patch_functions.cc #endif tc_free(tc_malloc(1)); ThreadCache::InitTSD(); tc_free(tc_malloc(1)); // Either we, or debugallocation.cc, or valgrind will control memory // management. We register our extension if we're the winner. #ifdef TCMALLOC_FOR_DEBUGALLOCATION // Let debugallocation register its extension. #else if (RunningOnValgrind()) { // Let Valgrind uses its own malloc (so don't register our extension). } else { MallocExtension::Register(new TCMallocImplementation); } #endif } } TCMallocGuard::~TCMallocGuard() { if (--tcmallocguard_refcount == 0) { const char* env = getenv("MALLOCSTATS"); if (env != NULL) { int level = atoi(env); if (level < 1) level = 1; PrintStats(level); } } } #ifndef WIN32_OVERRIDE_ALLOCATORS static TCMallocGuard module_enter_exit_hook; #endif //------------------------------------------------------------------- // Helpers for the exported routines below //------------------------------------------------------------------- static inline bool CheckCachedSizeClass(void *ptr) { PageID p = reinterpret_cast(ptr) >> kPageShift; size_t cached_value = Static::pageheap()->GetSizeClassIfCached(p); return cached_value == 0 || cached_value == Static::pageheap()->GetDescriptor(p)->sizeclass; } static inline void* CheckedMallocResult(void *result) { ASSERT(result == NULL || CheckCachedSizeClass(result)); return result; } static inline void* SpanToMallocResult(Span *span) { Static::pageheap()->CacheSizeClass(span->start, 0); return CheckedMallocResult(reinterpret_cast(span->start << kPageShift)); } static void* DoSampledAllocation(size_t size) { // Grab the stack trace outside the heap lock StackTrace tmp; tmp.depth = GetStackTrace(tmp.stack, tcmalloc::kMaxStackDepth, 1); tmp.size = size; SpinLockHolder h(Static::pageheap_lock()); // Allocate span Span *span = Static::pageheap()->New(tcmalloc::pages(size == 0 ? 1 : size)); if (span == NULL) { return NULL; } // Allocate stack trace StackTrace *stack = Static::stacktrace_allocator()->New(); if (stack == NULL) { // Sampling failed because of lack of memory return span; } *stack = tmp; span->sample = 1; span->objects = stack; tcmalloc::DLL_Prepend(Static::sampled_objects(), span); return SpanToMallocResult(span); } namespace { // Copy of FLAGS_tcmalloc_large_alloc_report_threshold with // automatic increases factored in. static int64_t large_alloc_threshold = (kPageSize > FLAGS_tcmalloc_large_alloc_report_threshold ? kPageSize : FLAGS_tcmalloc_large_alloc_report_threshold); static void ReportLargeAlloc(Length num_pages, void* result) { StackTrace stack; stack.depth = GetStackTrace(stack.stack, tcmalloc::kMaxStackDepth, 1); static const int N = 1000; char buffer[N]; TCMalloc_Printer printer(buffer, N); printer.printf("tcmalloc: large alloc %llu bytes == %p @ ", static_cast(num_pages) << kPageShift, result); for (int i = 0; i < stack.depth; i++) { printer.printf(" %p", stack.stack[i]); } printer.printf("\n"); write(STDERR_FILENO, buffer, strlen(buffer)); } inline void* cpp_alloc(size_t size, bool nothrow); inline void* do_malloc(size_t size); // TODO(willchan): Investigate whether or not lining this much is harmful to // performance. // This is equivalent to do_malloc() except when tc_new_mode is set to true. // Otherwise, it will run the std::new_handler if set. inline void* do_malloc_or_cpp_alloc(size_t size) { return tc_new_mode ? cpp_alloc(size, true) : do_malloc(size); } void* cpp_memalign(size_t align, size_t size); void* do_memalign(size_t align, size_t size); inline void* do_memalign_or_cpp_memalign(size_t align, size_t size) { return tc_new_mode ? cpp_memalign(align, size) : do_memalign(align, size); } // Must be called with the page lock held. inline bool should_report_large(Length num_pages) { const int64 threshold = large_alloc_threshold; if (threshold > 0 && num_pages >= (threshold >> kPageShift)) { // Increase the threshold by 1/8 every time we generate a report. // We cap the threshold at 8GB to avoid overflow problems. large_alloc_threshold = (threshold + threshold/8 < 8ll<<30 ? threshold + threshold/8 : 8ll<<30); return true; } return false; } // Helper for do_malloc(). inline void* do_malloc_pages(ThreadCache* heap, size_t size) { void* result; bool report_large; Length num_pages = tcmalloc::pages(size); size = num_pages << kPageShift; if ((FLAGS_tcmalloc_sample_parameter > 0) && heap->SampleAllocation(size)) { result = DoSampledAllocation(size); SpinLockHolder h(Static::pageheap_lock()); report_large = should_report_large(num_pages); } else { SpinLockHolder h(Static::pageheap_lock()); Span* span = Static::pageheap()->New(num_pages); result = (span == NULL ? NULL : SpanToMallocResult(span)); report_large = should_report_large(num_pages); } if (report_large) { ReportLargeAlloc(num_pages, result); } return result; } inline void* do_malloc(size_t size) { void* ret = NULL; // The following call forces module initialization ThreadCache* heap = ThreadCache::GetCache(); if (size <= kMaxSize) { size_t cl = Static::sizemap()->SizeClass(size); size = Static::sizemap()->class_to_size(cl); if ((FLAGS_tcmalloc_sample_parameter > 0) && heap->SampleAllocation(size)) { ret = DoSampledAllocation(size); } else { // The common case, and also the simplest. This just pops the // size-appropriate freelist, after replenishing it if it's empty. ret = CheckedMallocResult(heap->Allocate(size, cl)); } } else { ret = do_malloc_pages(heap, size); } if (ret == NULL) errno = ENOMEM; return ret; } inline void* do_calloc(size_t n, size_t elem_size) { // Overflow check const size_t size = n * elem_size; if (elem_size != 0 && size / elem_size != n) return NULL; void* result = do_malloc_or_cpp_alloc(size); if (result != NULL) { memset(result, 0, size); } return result; } static inline ThreadCache* GetCacheIfPresent() { void* const p = ThreadCache::GetCacheIfPresent(); return reinterpret_cast(p); } // This lets you call back to a given function pointer if ptr is invalid. // It is used primarily by windows code which wants a specialized callback. inline void do_free_with_callback(void* ptr, void (*invalid_free_fn)(void*)) { if (ptr == NULL) return; ASSERT(Static::pageheap() != NULL); // Should not call free() before malloc() const PageID p = reinterpret_cast(ptr) >> kPageShift; Span* span = NULL; size_t cl = Static::pageheap()->GetSizeClassIfCached(p); if (cl == 0) { span = Static::pageheap()->GetDescriptor(p); if (!span) { // span can be NULL because the pointer passed in is invalid // (not something returned by malloc or friends), or because the // pointer was allocated with some other allocator besides // tcmalloc. The latter can happen if tcmalloc is linked in via // a dynamic library, but is not listed last on the link line. // In that case, libraries after it on the link line will // allocate with libc malloc, but free with tcmalloc's free. (*invalid_free_fn)(ptr); // Decide how to handle the bad free request return; } cl = span->sizeclass; Static::pageheap()->CacheSizeClass(p, cl); } if (cl != 0) { ASSERT(!Static::pageheap()->GetDescriptor(p)->sample); ThreadCache* heap = GetCacheIfPresent(); if (heap != NULL) { heap->Deallocate(ptr, cl); } else { // Delete directly into central cache tcmalloc::SLL_SetNext(ptr, NULL); Static::central_cache()[cl].InsertRange(ptr, ptr, 1); } } else { SpinLockHolder h(Static::pageheap_lock()); ASSERT(reinterpret_cast(ptr) % kPageSize == 0); ASSERT(span != NULL && span->start == p); if (span->sample) { tcmalloc::DLL_Remove(span); Static::stacktrace_allocator()->Delete( reinterpret_cast(span->objects)); span->objects = NULL; } Static::pageheap()->Delete(span); } } // The default "do_free" that uses the default callback. inline void do_free(void* ptr) { return do_free_with_callback(ptr, &InvalidFree); } inline size_t GetSizeWithCallback(void* ptr, size_t (*invalid_getsize_fn)(void*)) { if (ptr == NULL) return 0; const PageID p = reinterpret_cast(ptr) >> kPageShift; size_t cl = Static::pageheap()->GetSizeClassIfCached(p); if (cl != 0) { return Static::sizemap()->ByteSizeForClass(cl); } else { Span *span = Static::pageheap()->GetDescriptor(p); if (span == NULL) { // means we do not own this memory return (*invalid_getsize_fn)(ptr); } else if (span->sizeclass != 0) { Static::pageheap()->CacheSizeClass(p, span->sizeclass); return Static::sizemap()->ByteSizeForClass(span->sizeclass); } else { return span->length << kPageShift; } } } // This lets you call back to a given function pointer if ptr is invalid. // It is used primarily by windows code which wants a specialized callback. inline void* do_realloc_with_callback( void* old_ptr, size_t new_size, void (*invalid_free_fn)(void*), size_t (*invalid_get_size_fn)(void*)) { // Get the size of the old entry const size_t old_size = GetSizeWithCallback(old_ptr, invalid_get_size_fn); // Reallocate if the new size is larger than the old size, // or if the new size is significantly smaller than the old size. // We do hysteresis to avoid resizing ping-pongs: // . If we need to grow, grow to max(new_size, old_size * 1.X) // . Don't shrink unless new_size < old_size * 0.Y // X and Y trade-off time for wasted space. For now we do 1.25 and 0.5. const int lower_bound_to_grow = old_size + old_size / 4; const int upper_bound_to_shrink = old_size / 2; if ((new_size > old_size) || (new_size < upper_bound_to_shrink)) { // Need to reallocate. void* new_ptr = NULL; if (new_size > old_size && new_size < lower_bound_to_grow) { new_ptr = do_malloc_or_cpp_alloc(lower_bound_to_grow); } if (new_ptr == NULL) { // Either new_size is not a tiny increment, or last do_malloc failed. new_ptr = do_malloc_or_cpp_alloc(new_size); } if (new_ptr == NULL) { return NULL; } MallocHook::InvokeNewHook(new_ptr, new_size); memcpy(new_ptr, old_ptr, ((old_size < new_size) ? old_size : new_size)); MallocHook::InvokeDeleteHook(old_ptr); // We could use a variant of do_free() that leverages the fact // that we already know the sizeclass of old_ptr. The benefit // would be small, so don't bother. do_free_with_callback(old_ptr, invalid_free_fn); return new_ptr; } else { // We still need to call hooks to report the updated size: MallocHook::InvokeDeleteHook(old_ptr); MallocHook::InvokeNewHook(old_ptr, new_size); return old_ptr; } } inline void* do_realloc(void* old_ptr, size_t new_size) { return do_realloc_with_callback(old_ptr, new_size, &InvalidFree, &InvalidGetSizeForRealloc); } // For use by exported routines below that want specific alignments // // Note: this code can be slow for alignments > 16, and can // significantly fragment memory. The expectation is that // memalign/posix_memalign/valloc/pvalloc will not be invoked very // often. This requirement simplifies our implementation and allows // us to tune for expected allocation patterns. void* do_memalign(size_t align, size_t size) { ASSERT((align & (align - 1)) == 0); ASSERT(align > 0); if (size + align < size) return NULL; // Overflow // Fall back to malloc if we would already align this memory access properly. if (align <= AlignmentForSize(size)) { void* p = do_malloc(size); ASSERT((reinterpret_cast(p) % align) == 0); return p; } if (Static::pageheap() == NULL) ThreadCache::InitModule(); // Allocate at least one byte to avoid boundary conditions below if (size == 0) size = 1; if (size <= kMaxSize && align < kPageSize) { // Search through acceptable size classes looking for one with // enough alignment. This depends on the fact that // InitSizeClasses() currently produces several size classes that // are aligned at powers of two. We will waste time and space if // we miss in the size class array, but that is deemed acceptable // since memalign() should be used rarely. int cl = Static::sizemap()->SizeClass(size); while (cl < kNumClasses && ((Static::sizemap()->class_to_size(cl) & (align - 1)) != 0)) { cl++; } if (cl < kNumClasses) { ThreadCache* heap = ThreadCache::GetCache(); size = Static::sizemap()->class_to_size(cl); return CheckedMallocResult(heap->Allocate(size, cl)); } } // We will allocate directly from the page heap SpinLockHolder h(Static::pageheap_lock()); if (align <= kPageSize) { // Any page-level allocation will be fine // TODO: We could put the rest of this page in the appropriate // TODO: cache but it does not seem worth it. Span* span = Static::pageheap()->New(tcmalloc::pages(size)); return span == NULL ? NULL : SpanToMallocResult(span); } // Allocate extra pages and carve off an aligned portion const Length alloc = tcmalloc::pages(size + align); Span* span = Static::pageheap()->New(alloc); if (span == NULL) return NULL; // Skip starting portion so that we end up aligned Length skip = 0; while ((((span->start+skip) << kPageShift) & (align - 1)) != 0) { skip++; } ASSERT(skip < alloc); if (skip > 0) { Span* rest = Static::pageheap()->Split(span, skip); Static::pageheap()->Delete(span); span = rest; } // Skip trailing portion that we do not need to return const Length needed = tcmalloc::pages(size); ASSERT(span->length >= needed); if (span->length > needed) { Span* trailer = Static::pageheap()->Split(span, needed); Static::pageheap()->Delete(trailer); } return SpanToMallocResult(span); } // Helpers for use by exported routines below: inline void do_malloc_stats() { PrintStats(1); } inline int do_mallopt(int cmd, int value) { return 1; // Indicates error } #ifdef HAVE_STRUCT_MALLINFO inline struct mallinfo do_mallinfo() { TCMallocStats stats; ExtractStats(&stats, NULL); // Just some of the fields are filled in. struct mallinfo info; memset(&info, 0, sizeof(info)); // Unfortunately, the struct contains "int" field, so some of the // size values will be truncated. info.arena = static_cast(stats.pageheap.system_bytes); info.fsmblks = static_cast(stats.thread_bytes + stats.central_bytes + stats.transfer_bytes); info.fordblks = static_cast(stats.pageheap.free_bytes + stats.pageheap.unmapped_bytes); info.uordblks = static_cast(stats.pageheap.system_bytes - stats.thread_bytes - stats.central_bytes - stats.transfer_bytes - stats.pageheap.free_bytes - stats.pageheap.unmapped_bytes); return info; } #endif // HAVE_STRUCT_MALLINFO static SpinLock set_new_handler_lock(SpinLock::LINKER_INITIALIZED); inline void* cpp_alloc(size_t size, bool nothrow) { for (;;) { void* p = do_malloc(size); #ifdef PREANSINEW return p; #else if (p == NULL) { // allocation failed // Get the current new handler. NB: this function is not // thread-safe. We make a feeble stab at making it so here, but // this lock only protects against tcmalloc interfering with // itself, not with other libraries calling set_new_handler. std::new_handler nh; { SpinLockHolder h(&set_new_handler_lock); nh = std::set_new_handler(0); (void) std::set_new_handler(nh); } #if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) if (nh) { // Since exceptions are disabled, we don't really know if new_handler // failed. Assume it will abort if it fails. (*nh)(); continue; } return 0; #else // If no new_handler is established, the allocation failed. if (!nh) { if (nothrow) return 0; throw std::bad_alloc(); } // Otherwise, try the new_handler. If it returns, retry the // allocation. If it throws std::bad_alloc, fail the allocation. // if it throws something else, don't interfere. try { (*nh)(); } catch (const std::bad_alloc&) { if (!nothrow) throw; return p; } #endif // (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) } else { // allocation success return p; } #endif // PREANSINEW } } void* cpp_memalign(size_t align, size_t size) { for (;;) { void* p = do_memalign(align, size); #ifdef PREANSINEW return p; #else if (p == NULL) { // allocation failed // Get the current new handler. NB: this function is not // thread-safe. We make a feeble stab at making it so here, but // this lock only protects against tcmalloc interfering with // itself, not with other libraries calling set_new_handler. std::new_handler nh; { SpinLockHolder h(&set_new_handler_lock); nh = std::set_new_handler(0); (void) std::set_new_handler(nh); } #if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) if (nh) { // Since exceptions are disabled, we don't really know if new_handler // failed. Assume it will abort if it fails. (*nh)(); continue; } return 0; #else // If no new_handler is established, the allocation failed. if (!nh) return 0; // Otherwise, try the new_handler. If it returns, retry the // allocation. If it throws std::bad_alloc, fail the allocation. // if it throws something else, don't interfere. try { (*nh)(); } catch (const std::bad_alloc&) { return p; } #endif // (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) } else { // allocation success return p; } #endif // PREANSINEW } } } // end unnamed namespace // As promised, the definition of this function, declared above. size_t TCMallocImplementation::GetAllocatedSize(void* ptr) { return GetSizeWithCallback(ptr, &InvalidGetAllocatedSize); } void TCMallocImplementation::MarkThreadBusy() { // Allocate to force the creation of a thread cache, but avoid // invoking any hooks. do_free(do_malloc(0)); } //------------------------------------------------------------------- // Exported routines //------------------------------------------------------------------- extern "C" PERFTOOLS_DLL_DECL const char* tc_version( int* major, int* minor, const char** patch) __THROW { if (major) *major = TC_VERSION_MAJOR; if (minor) *minor = TC_VERSION_MINOR; if (patch) *patch = TC_VERSION_PATCH; return TC_VERSION_STRING; } // CAVEAT: The code structure below ensures that MallocHook methods are always // called from the stack frame of the invoked allocation function. // heap-checker.cc depends on this to start a stack trace from // the call to the (de)allocation function. extern "C" PERFTOOLS_DLL_DECL void* tc_malloc(size_t size) __THROW { void* result = do_malloc_or_cpp_alloc(size); MallocHook::InvokeNewHook(result, size); return result; } extern "C" PERFTOOLS_DLL_DECL void tc_free(void* ptr) __THROW { MallocHook::InvokeDeleteHook(ptr); do_free(ptr); } extern "C" PERFTOOLS_DLL_DECL void* tc_calloc(size_t n, size_t elem_size) __THROW { void* result = do_calloc(n, elem_size); MallocHook::InvokeNewHook(result, n * elem_size); return result; } extern "C" PERFTOOLS_DLL_DECL void tc_cfree(void* ptr) __THROW { MallocHook::InvokeDeleteHook(ptr); do_free(ptr); } extern "C" PERFTOOLS_DLL_DECL void* tc_realloc(void* old_ptr, size_t new_size) __THROW { if (old_ptr == NULL) { void* result = do_malloc_or_cpp_alloc(new_size); MallocHook::InvokeNewHook(result, new_size); return result; } if (new_size == 0) { MallocHook::InvokeDeleteHook(old_ptr); do_free(old_ptr); return NULL; } return do_realloc(old_ptr, new_size); } extern "C" PERFTOOLS_DLL_DECL void* tc_new(size_t size) { void* p = cpp_alloc(size, false); // We keep this next instruction out of cpp_alloc for a reason: when // it's in, and new just calls cpp_alloc, the optimizer may fold the // new call into cpp_alloc, which messes up our whole section-based // stacktracing (see ATTRIBUTE_SECTION, above). This ensures cpp_alloc // isn't the last thing this fn calls, and prevents the folding. MallocHook::InvokeNewHook(p, size); return p; } extern "C" PERFTOOLS_DLL_DECL void* tc_new_nothrow(size_t size, const std::nothrow_t&) __THROW { void* p = cpp_alloc(size, true); MallocHook::InvokeNewHook(p, size); return p; } extern "C" PERFTOOLS_DLL_DECL void tc_delete(void* p) __THROW { MallocHook::InvokeDeleteHook(p); do_free(p); } // Standard C++ library implementations define and use this // (via ::operator delete(ptr, nothrow)). // But it's really the same as normal delete, so we just do the same thing. extern "C" PERFTOOLS_DLL_DECL void tc_delete_nothrow(void* p, const std::nothrow_t&) __THROW { MallocHook::InvokeDeleteHook(p); do_free(p); } extern "C" PERFTOOLS_DLL_DECL void* tc_newarray(size_t size) { void* p = cpp_alloc(size, false); // We keep this next instruction out of cpp_alloc for a reason: when // it's in, and new just calls cpp_alloc, the optimizer may fold the // new call into cpp_alloc, which messes up our whole section-based // stacktracing (see ATTRIBUTE_SECTION, above). This ensures cpp_alloc // isn't the last thing this fn calls, and prevents the folding. MallocHook::InvokeNewHook(p, size); return p; } extern "C" PERFTOOLS_DLL_DECL void* tc_newarray_nothrow(size_t size, const std::nothrow_t&) __THROW { void* p = cpp_alloc(size, true); MallocHook::InvokeNewHook(p, size); return p; } extern "C" PERFTOOLS_DLL_DECL void tc_deletearray(void* p) __THROW { MallocHook::InvokeDeleteHook(p); do_free(p); } extern "C" PERFTOOLS_DLL_DECL void tc_deletearray_nothrow(void* p, const std::nothrow_t&) __THROW { MallocHook::InvokeDeleteHook(p); do_free(p); } extern "C" PERFTOOLS_DLL_DECL void* tc_memalign(size_t align, size_t size) __THROW { void* result = do_memalign_or_cpp_memalign(align, size); MallocHook::InvokeNewHook(result, size); return result; } extern "C" PERFTOOLS_DLL_DECL int tc_posix_memalign( void** result_ptr, size_t align, size_t size) __THROW { if (((align % sizeof(void*)) != 0) || ((align & (align - 1)) != 0) || (align == 0)) { return EINVAL; } void* result = do_memalign_or_cpp_memalign(align, size); MallocHook::InvokeNewHook(result, size); if (result == NULL) { return ENOMEM; } else { *result_ptr = result; return 0; } } static size_t pagesize = 0; extern "C" PERFTOOLS_DLL_DECL void* tc_valloc(size_t size) __THROW { // Allocate page-aligned object of length >= size bytes if (pagesize == 0) pagesize = getpagesize(); void* result = do_memalign_or_cpp_memalign(pagesize, size); MallocHook::InvokeNewHook(result, size); return result; } extern "C" PERFTOOLS_DLL_DECL void* tc_pvalloc(size_t size) __THROW { // Round up size to a multiple of pagesize if (pagesize == 0) pagesize = getpagesize(); if (size == 0) { // pvalloc(0) should allocate one page, according to size = pagesize; // http://man.free4web.biz/man3/libmpatrol.3.html } size = (size + pagesize - 1) & ~(pagesize - 1); void* result = do_memalign_or_cpp_memalign(pagesize, size); MallocHook::InvokeNewHook(result, size); return result; } extern "C" PERFTOOLS_DLL_DECL void tc_malloc_stats(void) __THROW { do_malloc_stats(); } extern "C" PERFTOOLS_DLL_DECL int tc_mallopt(int cmd, int value) __THROW { return do_mallopt(cmd, value); } #ifdef HAVE_STRUCT_MALLINFO extern "C" PERFTOOLS_DLL_DECL struct mallinfo tc_mallinfo(void) __THROW { return do_mallinfo(); } #endif extern "C" PERFTOOLS_DLL_DECL size_t tc_malloc_size(void* ptr) __THROW { return GetSizeWithCallback(ptr, &InvalidGetAllocatedSize); } // This function behaves similarly to MSVC's _set_new_mode. // If flag is 0 (default), calls to malloc will behave normally. // If flag is 1, calls to malloc will behave like calls to new, // and the std_new_handler will be invoked on failure. // Returns the previous mode. extern "C" PERFTOOLS_DLL_DECL int tc_set_new_mode(int flag) __THROW { int old_mode = tc_new_mode; tc_new_mode = flag; return old_mode; } // Override __libc_memalign in libc on linux boxes specially. // They have a bug in libc that causes them to (very rarely) allocate // with __libc_memalign() yet deallocate with free() and the // definitions above don't catch it. // This function is an exception to the rule of calling MallocHook method // from the stack frame of the allocation function; // heap-checker handles this special case explicitly. #ifndef TCMALLOC_FOR_DEBUGALLOCATION static void *MemalignOverride(size_t align, size_t size, const void *caller) __THROW ATTRIBUTE_SECTION(google_malloc); static void *MemalignOverride(size_t align, size_t size, const void *caller) __THROW { void* result = do_memalign_or_cpp_memalign(align, size); MallocHook::InvokeNewHook(result, size); return result; } void *(*__memalign_hook)(size_t, size_t, const void *) = MemalignOverride; #endif // #ifndef TCMALLOC_FOR_DEBUGALLOCATION ================================================ FILE: distro/google-perftools-1.7/src/tcmalloc.h ================================================ // Copyright (c) 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Craig Silverstein // // Some obscure memory-allocation routines may not be declared on all // systems. In those cases, we'll just declare them ourselves. // This file is meant to be used only internally, for unittests. #include #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 600 // for posix_memalign #endif #include // for posix_memalign // FreeBSD has malloc.h, but complains if you use it #if defined(HAVE_MALLOC_H) && !defined(__FreeBSD__) #include // for memalign, valloc, pvalloc #endif // __THROW is defined in glibc systems. It means, counter-intuitively, // "This function will never throw an exception." It's an optional // optimization tool, but we may need to use it to match glibc prototypes. #ifndef __THROW // I guess we're not on a glibc system # define __THROW // __THROW is just an optimization, so ok to make it "" #endif #if !HAVE_CFREE_SYMBOL extern "C" void cfree(void* ptr) __THROW; #endif #if !HAVE_POSIX_MEMALIGN_SYMBOL extern "C" int posix_memalign(void** ptr, size_t align, size_t size) __THROW; #endif #if !HAVE_MEMALIGN_SYMBOL extern "C" void* memalign(size_t __alignment, size_t __size) __THROW; #endif #if !HAVE_VALLOC_SYMBOL extern "C" void* valloc(size_t __size) __THROW; #endif #if !HAVE_PVALLOC_SYMBOL extern "C" void* pvalloc(size_t __size) __THROW; #endif ================================================ FILE: distro/google-perftools-1.7/src/tcmalloc_guard.h ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Craig Silverstein // // We expose the TCMallocGuard class -- which initializes the tcmalloc // allocator -- so classes that need to be sure tcmalloc is loaded // before they do stuff -- notably heap-profiler -- can. To use this // create a static TCMallocGuard instance at the top of a file where // you need tcmalloc to be initialized before global constructors run. #ifndef TCMALLOC_TCMALLOC_GUARD_H_ #define TCMALLOC_TCMALLOC_GUARD_H_ class TCMallocGuard { public: TCMallocGuard(); ~TCMallocGuard(); }; #endif // TCMALLOC_TCMALLOC_GUARD_H_ ================================================ FILE: distro/google-perftools-1.7/src/tests/addressmap_unittest.cc ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat #include // for rand() #include #include #include #include #include "addressmap-inl.h" #include "base/logging.h" #include "base/commandlineflags.h" DEFINE_int32(iters, 20, "Number of test iterations"); DEFINE_int32(N, 100000, "Number of elements to test per iteration"); using std::pair; using std::make_pair; using std::vector; using std::set; using std::random_shuffle; struct UniformRandomNumberGenerator { size_t Uniform(size_t max_size) { if (max_size == 0) return 0; return rand() % max_size; // not a great random-number fn, but portable } }; static UniformRandomNumberGenerator rnd; // pair of associated value and object size typedef pair ValueT; struct PtrAndSize { char* ptr; size_t size; PtrAndSize(char* p, size_t s) : ptr(p), size(s) {} }; size_t SizeFunc(const ValueT& v) { return v.second; } static void SetCheckCallback(const void* ptr, ValueT* val, set >* check_set) { check_set->insert(make_pair(ptr, val->first)); } int main(int argc, char** argv) { // Get a bunch of pointers const int N = FLAGS_N; static const int kMaxRealSize = 49; // 100Mb to stress not finding previous object (AddressMap's cluster is 1Mb): static const size_t kMaxSize = 100*1000*1000; vector ptrs_and_sizes; for (int i = 0; i < N; ++i) { size_t s = rnd.Uniform(kMaxRealSize); ptrs_and_sizes.push_back(PtrAndSize(new char[s], s)); } for (int x = 0; x < FLAGS_iters; ++x) { RAW_LOG(INFO, "Iteration %d/%d...\n", x, FLAGS_iters); // Permute pointers to get rid of allocation order issues random_shuffle(ptrs_and_sizes.begin(), ptrs_and_sizes.end()); AddressMap map(malloc, free); const ValueT* result; const void* res_p; // Insert a bunch of entries for (int i = 0; i < N; ++i) { char* p = ptrs_and_sizes[i].ptr; CHECK(!map.Find(p)); int offs = rnd.Uniform(ptrs_and_sizes[i].size); CHECK(!map.FindInside(&SizeFunc, kMaxSize, p + offs, &res_p)); map.Insert(p, make_pair(i, ptrs_and_sizes[i].size)); CHECK(result = map.Find(p)); CHECK_EQ(result->first, i); CHECK(result = map.FindInside(&SizeFunc, kMaxRealSize, p + offs, &res_p)); CHECK_EQ(res_p, p); CHECK_EQ(result->first, i); map.Insert(p, make_pair(i + N, ptrs_and_sizes[i].size)); CHECK(result = map.Find(p)); CHECK_EQ(result->first, i + N); } // Delete the even entries for (int i = 0; i < N; i += 2) { void* p = ptrs_and_sizes[i].ptr; ValueT removed; CHECK(map.FindAndRemove(p, &removed)); CHECK_EQ(removed.first, i + N); } // Lookup the odd entries and adjust them for (int i = 1; i < N; i += 2) { char* p = ptrs_and_sizes[i].ptr; CHECK(result = map.Find(p)); CHECK_EQ(result->first, i + N); int offs = rnd.Uniform(ptrs_and_sizes[i].size); CHECK(result = map.FindInside(&SizeFunc, kMaxRealSize, p + offs, &res_p)); CHECK_EQ(res_p, p); CHECK_EQ(result->first, i + N); map.Insert(p, make_pair(i + 2*N, ptrs_and_sizes[i].size)); CHECK(result = map.Find(p)); CHECK_EQ(result->first, i + 2*N); } // Insert even entries back for (int i = 0; i < N; i += 2) { char* p = ptrs_and_sizes[i].ptr; int offs = rnd.Uniform(ptrs_and_sizes[i].size); CHECK(!map.FindInside(&SizeFunc, kMaxSize, p + offs, &res_p)); map.Insert(p, make_pair(i + 2*N, ptrs_and_sizes[i].size)); CHECK(result = map.Find(p)); CHECK_EQ(result->first, i + 2*N); CHECK(result = map.FindInside(&SizeFunc, kMaxRealSize, p + offs, &res_p)); CHECK_EQ(res_p, p); CHECK_EQ(result->first, i + 2*N); } // Check all entries set > check_set; map.Iterate(SetCheckCallback, &check_set); CHECK_EQ(check_set.size(), N); for (int i = 0; i < N; ++i) { void* p = ptrs_and_sizes[i].ptr; check_set.erase(make_pair(p, i + 2*N)); CHECK(result = map.Find(p)); CHECK_EQ(result->first, i + 2*N); } CHECK_EQ(check_set.size(), 0); } for (int i = 0; i < N; ++i) { delete[] ptrs_and_sizes[i].ptr; } printf("PASS\n"); return 0; } ================================================ FILE: distro/google-perftools-1.7/src/tests/atomicops_unittest.cc ================================================ /* Copyright (c) 2006, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Sanjay Ghemawat */ #include #include "base/logging.h" #include "base/atomicops.h" #define GG_ULONGLONG(x) static_cast(x) template static void TestAtomicIncrement() { // For now, we just test single threaded execution // use a guard value to make sure the NoBarrier_AtomicIncrement doesn't go // outside the expected address bounds. This is in particular to // test that some future change to the asm code doesn't cause the // 32-bit NoBarrier_AtomicIncrement doesn't do the wrong thing on 64-bit // machines. struct { AtomicType prev_word; AtomicType count; AtomicType next_word; } s; AtomicType prev_word_value, next_word_value; memset(&prev_word_value, 0xFF, sizeof(AtomicType)); memset(&next_word_value, 0xEE, sizeof(AtomicType)); s.prev_word = prev_word_value; s.count = 0; s.next_word = next_word_value; ASSERT_EQ(1, base::subtle::NoBarrier_AtomicIncrement(&s.count, 1)); ASSERT_EQ(1, s.count); ASSERT_EQ(prev_word_value, s.prev_word); ASSERT_EQ(next_word_value, s.next_word); ASSERT_EQ(3, base::subtle::NoBarrier_AtomicIncrement(&s.count, 2)); ASSERT_EQ(3, s.count); ASSERT_EQ(prev_word_value, s.prev_word); ASSERT_EQ(next_word_value, s.next_word); ASSERT_EQ(6, base::subtle::NoBarrier_AtomicIncrement(&s.count, 3)); ASSERT_EQ(6, s.count); ASSERT_EQ(prev_word_value, s.prev_word); ASSERT_EQ(next_word_value, s.next_word); ASSERT_EQ(3, base::subtle::NoBarrier_AtomicIncrement(&s.count, -3)); ASSERT_EQ(3, s.count); ASSERT_EQ(prev_word_value, s.prev_word); ASSERT_EQ(next_word_value, s.next_word); ASSERT_EQ(1, base::subtle::NoBarrier_AtomicIncrement(&s.count, -2)); ASSERT_EQ(1, s.count); ASSERT_EQ(prev_word_value, s.prev_word); ASSERT_EQ(next_word_value, s.next_word); ASSERT_EQ(0, base::subtle::NoBarrier_AtomicIncrement(&s.count, -1)); ASSERT_EQ(0, s.count); ASSERT_EQ(prev_word_value, s.prev_word); ASSERT_EQ(next_word_value, s.next_word); ASSERT_EQ(-1, base::subtle::NoBarrier_AtomicIncrement(&s.count, -1)); ASSERT_EQ(-1, s.count); ASSERT_EQ(prev_word_value, s.prev_word); ASSERT_EQ(next_word_value, s.next_word); ASSERT_EQ(-5, base::subtle::NoBarrier_AtomicIncrement(&s.count, -4)); ASSERT_EQ(-5, s.count); ASSERT_EQ(prev_word_value, s.prev_word); ASSERT_EQ(next_word_value, s.next_word); ASSERT_EQ(0, base::subtle::NoBarrier_AtomicIncrement(&s.count, 5)); ASSERT_EQ(0, s.count); ASSERT_EQ(prev_word_value, s.prev_word); ASSERT_EQ(next_word_value, s.next_word); } #define NUM_BITS(T) (sizeof(T) * 8) template static void TestCompareAndSwap() { AtomicType value = 0; AtomicType prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 1); ASSERT_EQ(1, value); ASSERT_EQ(0, prev); // Use test value that has non-zero bits in both halves, more for testing // 64-bit implementation on 32-bit platforms. const AtomicType k_test_val = (GG_ULONGLONG(1) << (NUM_BITS(AtomicType) - 2)) + 11; value = k_test_val; prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 5); ASSERT_EQ(k_test_val, value); ASSERT_EQ(k_test_val, prev); value = k_test_val; prev = base::subtle::NoBarrier_CompareAndSwap(&value, k_test_val, 5); ASSERT_EQ(5, value); ASSERT_EQ(k_test_val, prev); } template static void TestAtomicExchange() { AtomicType value = 0; AtomicType new_value = base::subtle::NoBarrier_AtomicExchange(&value, 1); ASSERT_EQ(1, value); ASSERT_EQ(0, new_value); // Use test value that has non-zero bits in both halves, more for testing // 64-bit implementation on 32-bit platforms. const AtomicType k_test_val = (GG_ULONGLONG(1) << (NUM_BITS(AtomicType) - 2)) + 11; value = k_test_val; new_value = base::subtle::NoBarrier_AtomicExchange(&value, k_test_val); ASSERT_EQ(k_test_val, value); ASSERT_EQ(k_test_val, new_value); value = k_test_val; new_value = base::subtle::NoBarrier_AtomicExchange(&value, 5); ASSERT_EQ(5, value); ASSERT_EQ(k_test_val, new_value); } template static void TestAtomicIncrementBounds() { // Test increment at the half-width boundary of the atomic type. // It is primarily for testing at the 32-bit boundary for 64-bit atomic type. AtomicType test_val = GG_ULONGLONG(1) << (NUM_BITS(AtomicType) / 2); AtomicType value = test_val - 1; AtomicType new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1); ASSERT_EQ(test_val, value); ASSERT_EQ(value, new_value); base::subtle::NoBarrier_AtomicIncrement(&value, -1); ASSERT_EQ(test_val - 1, value); } // This is a simple sanity check that values are correct. Not testing // atomicity template static void TestStore() { const AtomicType kVal1 = static_cast(0xa5a5a5a5a5a5a5a5LL); const AtomicType kVal2 = static_cast(-1); AtomicType value; base::subtle::NoBarrier_Store(&value, kVal1); ASSERT_EQ(kVal1, value); base::subtle::NoBarrier_Store(&value, kVal2); ASSERT_EQ(kVal2, value); base::subtle::Acquire_Store(&value, kVal1); ASSERT_EQ(kVal1, value); base::subtle::Acquire_Store(&value, kVal2); ASSERT_EQ(kVal2, value); base::subtle::Release_Store(&value, kVal1); ASSERT_EQ(kVal1, value); base::subtle::Release_Store(&value, kVal2); ASSERT_EQ(kVal2, value); } // This is a simple sanity check that values are correct. Not testing // atomicity template static void TestLoad() { const AtomicType kVal1 = static_cast(0xa5a5a5a5a5a5a5a5LL); const AtomicType kVal2 = static_cast(-1); AtomicType value; value = kVal1; ASSERT_EQ(kVal1, base::subtle::NoBarrier_Load(&value)); value = kVal2; ASSERT_EQ(kVal2, base::subtle::NoBarrier_Load(&value)); value = kVal1; ASSERT_EQ(kVal1, base::subtle::Acquire_Load(&value)); value = kVal2; ASSERT_EQ(kVal2, base::subtle::Acquire_Load(&value)); value = kVal1; ASSERT_EQ(kVal1, base::subtle::Release_Load(&value)); value = kVal2; ASSERT_EQ(kVal2, base::subtle::Release_Load(&value)); } template static void TestAtomicOps() { TestCompareAndSwap(); TestAtomicExchange(); TestAtomicIncrementBounds(); TestStore(); TestLoad(); } int main(int argc, char** argv) { TestAtomicIncrement(); TestAtomicIncrement(); TestAtomicOps(); TestAtomicOps(); // I've commented the Atomic64 tests out for now, because Atomic64 // doesn't work on x86 systems that are not compiled to support mmx // registers. Since I want this project to be as portable as // possible -- that is, not to assume we've compiled for mmx or even // that the processor supports it -- and we don't actually use // Atomic64 anywhere, I've commented it out of the test for now. // (Luckily, if we ever do use Atomic64 by accident, we'll get told // via a compiler error rather than some obscure runtime failure, so // this course of action is safe.) // If we ever *do* want to enable this, try adding -msse (or -mmmx?) // to the CXXFLAGS in Makefile.am. #if 0 and defined(BASE_HAS_ATOMIC64) TestAtomicIncrement(); TestAtomicOps(); #endif printf("PASS\n"); return 0; } ================================================ FILE: distro/google-perftools-1.7/src/tests/debugallocation_test.cc ================================================ // Copyright (c) 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Fred Akalin #include #include #include #include "google/malloc_extension.h" #include "base/logging.h" using std::vector; vector g_testlist; // the tests to run #define TEST(a, b) \ struct Test_##a##_##b { \ Test_##a##_##b() { g_testlist.push_back(&Run); } \ static void Run(); \ }; \ static Test_##a##_##b g_test_##a##_##b; \ void Test_##a##_##b::Run() static int RUN_ALL_TESTS() { vector::const_iterator it; for (it = g_testlist.begin(); it != g_testlist.end(); ++it) { (*it)(); // The test will error-exit if there's a problem. } fprintf(stderr, "\nPassed %d tests\n\nPASS\n", static_cast(g_testlist.size())); return 0; } // The death tests are meant to be run from a shell-script driver, which // passes in an integer saying which death test to run. We store that // test-to-run here, and in the macro use a counter to see when we get // to that test, so we can run it. static int test_to_run = 0; // set in main() based on argv static int test_counter = 0; // incremented every time the macro is called #define IF_DEBUG_EXPECT_DEATH(statement, regex) do { \ if (test_counter++ == test_to_run) { \ fprintf(stderr, "Expected regex:%s\n", regex); \ statement; \ } \ } while (false) // This flag won't be compiled in in opt mode. DECLARE_int32(max_free_queue_size); // Test match as well as mismatch rules: TEST(DebugAllocationTest, DeallocMismatch) { // malloc can be matched only by free // new can be matched only by delete and delete(nothrow) // new[] can be matched only by delete[] and delete[](nothrow) // new(nothrow) can be matched only by delete and delete(nothrow) // new(nothrow)[] can be matched only by delete[] and delete[](nothrow) // Allocate with malloc. { int* x = static_cast(malloc(sizeof(*x))); IF_DEBUG_EXPECT_DEATH(delete x, "mismatch.*being dealloc.*delete"); IF_DEBUG_EXPECT_DEATH(delete [] x, "mismatch.*being dealloc.*delete *[[]"); // Should work fine. free(x); } // Allocate with new. { int* x = new int; int* y = new int; IF_DEBUG_EXPECT_DEATH(free(x), "mismatch.*being dealloc.*free"); IF_DEBUG_EXPECT_DEATH(delete [] x, "mismatch.*being dealloc.*delete *[[]"); delete x; ::operator delete(y, std::nothrow); } // Allocate with new[]. { int* x = new int[1]; int* y = new int[1]; IF_DEBUG_EXPECT_DEATH(free(x), "mismatch.*being dealloc.*free"); IF_DEBUG_EXPECT_DEATH(delete x, "mismatch.*being dealloc.*delete"); delete [] x; ::operator delete[](y, std::nothrow); } // Allocate with new(nothrow). { int* x = new(std::nothrow) int; int* y = new(std::nothrow) int; IF_DEBUG_EXPECT_DEATH(free(x), "mismatch.*being dealloc.*free"); IF_DEBUG_EXPECT_DEATH(delete [] x, "mismatch.*being dealloc.*delete *[[]"); delete x; ::operator delete(y, std::nothrow); } // Allocate with new(nothrow)[]. { int* x = new(std::nothrow) int[1]; int* y = new(std::nothrow) int[1]; IF_DEBUG_EXPECT_DEATH(free(x), "mismatch.*being dealloc.*free"); IF_DEBUG_EXPECT_DEATH(delete x, "mismatch.*being dealloc.*delete"); delete [] x; ::operator delete[](y, std::nothrow); } } TEST(DebugAllocationTest, DoubleFree) { int* pint = new int; delete pint; IF_DEBUG_EXPECT_DEATH(delete pint, "has been already deallocated"); } TEST(DebugAllocationTest, StompBefore) { int* pint = new int; #ifndef NDEBUG // don't stomp memory if we're not in a position to detect it pint[-1] = 5; IF_DEBUG_EXPECT_DEATH(delete pint, "a word before object"); #endif } TEST(DebugAllocationTest, StompAfter) { int* pint = new int; #ifndef NDEBUG // don't stomp memory if we're not in a position to detect it pint[1] = 5; IF_DEBUG_EXPECT_DEATH(delete pint, "a word after object"); #endif } TEST(DebugAllocationTest, FreeQueueTest) { // Verify that the allocator doesn't return blocks that were recently freed. int* x = new int; int* old_x = x; delete x; x = new int; #if 1 // This check should not be read as a universal guarantee of behavior. If // other threads are executing, it would be theoretically possible for this // check to fail despite the efforts of debugallocation.cc to the contrary. // It should always hold under the controlled conditions of this unittest, // however. EXPECT_NE(x, old_x); // Allocator shouldn't return recently freed blocks #else // The below check passes, but since it isn't *required* to pass, I've left // it commented out. // EXPECT_EQ(x, old_x); #endif old_x = NULL; // avoid breaking opt build with an unused variable warning. delete x; } TEST(DebugAllocationTest, DanglingPointerWriteTest) { // This test can only be run if debugging. // // If not debugging, the 'new' following the dangling write might not be // safe. When debugging, we expect the (trashed) deleted block to be on the // list of recently-freed blocks, so the following 'new' will be safe. #if 1 int* x = new int; delete x; int poisoned_x_value = *x; *x = 1; // a dangling write. char* s = new char[FLAGS_max_free_queue_size]; // When we delete s, we push the storage that was previously allocated to x // off the end of the free queue. At that point, the write to that memory // will be detected. IF_DEBUG_EXPECT_DEATH(delete [] s, "Memory was written to after being freed."); // restore the poisoned value of x so that we can delete s without causing a // crash. *x = poisoned_x_value; delete [] s; #endif } TEST(DebugAllocationTest, DanglingWriteAtExitTest) { int *x = new int; delete x; int old_x_value = *x; *x = 1; // verify that dangling writes are caught at program termination if the // corrupted block never got pushed off of the end of the free queue. IF_DEBUG_EXPECT_DEATH(exit(0), "Memory was written to after being freed."); *x = old_x_value; // restore x so that the test can exit successfully. } TEST(DebugAllocationTest, StackTraceWithDanglingWriteAtExitTest) { int *x = new int; delete x; int old_x_value = *x; *x = 1; // verify that we also get a stack trace when we have a dangling write. // The " @ " is part of the stack trace output. IF_DEBUG_EXPECT_DEATH(exit(0), " @ .* main"); *x = old_x_value; // restore x so that the test can exit successfully. } static size_t CurrentlyAllocatedBytes() { size_t value; CHECK(MallocExtension::instance()->GetNumericProperty( "generic.current_allocated_bytes", &value)); return value; } TEST(DebugAllocationTest, CurrentlyAllocated) { // Clear the free queue #if 1 FLAGS_max_free_queue_size = 0; // Force a round-trip through the queue management code so that the // new size is seen and the queue of recently-freed blocks is flushed. free(malloc(1)); FLAGS_max_free_queue_size = 1048576; #endif // Free something and check that it disappears from allocated bytes // immediately. char* p = new char[1000]; size_t after_malloc = CurrentlyAllocatedBytes(); delete[] p; size_t after_free = CurrentlyAllocatedBytes(); EXPECT_LE(after_free, after_malloc - 1000); } TEST(DebugAllocationTest, GetAllocatedSizeTest) { #if 1 // When debug_allocation is in effect, GetAllocatedSize should return // exactly requested size, since debug_allocation doesn't allow users // to write more than that. for (int i = 0; i < 10; ++i) { void *p = malloc(i); EXPECT_EQ(i, MallocExtension::instance()->GetAllocatedSize(p)); free(p); } #endif void* a = malloc(1000); EXPECT_GE(MallocExtension::instance()->GetAllocatedSize(a), 1000); // This is just a sanity check. If we allocated too much, alloc is broken EXPECT_LE(MallocExtension::instance()->GetAllocatedSize(a), 5000); EXPECT_GE(MallocExtension::instance()->GetEstimatedAllocatedSize(1000), 1000); free(a); } TEST(DebugAllocationTest, HugeAlloc) { // This must not be a const variable so it doesn't form an // integral-constant-expression which can be *statically* rejected by the // compiler as too large for the allocation. size_t kTooBig = ~static_cast(0); void* a = NULL; #ifndef NDEBUG a = malloc(kTooBig); EXPECT_EQ(NULL, a); // kAlsoTooBig is small enough not to get caught by debugallocation's check, // but will still fall through to tcmalloc's check. This must also be // a non-const variable. See kTooBig for more details. size_t kAlsoTooBig = kTooBig - 1024; a = malloc(kAlsoTooBig); EXPECT_EQ(NULL, a); #endif } int main(int argc, char** argv) { // If you run without args, we run the non-death parts of the test. // Otherwise, argv[1] should be a number saying which death-test // to run. We will output a regexp we expect the death-message // to include, and then run the given death test (which hopefully // will produce that error message). If argv[1] > the number of // death tests, we will run only the non-death parts. One way to // tell when you are done with all tests is when no 'expected // regexp' message is printed for a given argv[1]. if (argc < 2) { test_to_run = -1; // will never match } else { test_to_run = atoi(argv[1]); } return RUN_ALL_TESTS(); } ================================================ FILE: distro/google-perftools-1.7/src/tests/debugallocation_test.sh ================================================ #!/bin/sh # Copyright (c) 2009, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # --- # Author: Craig Silverstein BINDIR="${BINDIR:-.}" if [ "x$1" = "x-h" -o "x$1" = "x--help" ]; then echo "USAGE: $0 [unittest dir]" echo " By default, unittest_dir=$BINDIR" exit 1 fi DEBUGALLOCATION_TEST="${1:-$BINDIR/debugallocation_test}" num_failures=0 # Run the i-th death test and make sure the test has the expected # regexp. We can depend on the first line of the output being # Expected regex: # Evaluates to "done" if we are not actually a death-test (so $1 is # too big a number, and we can stop). Evaluates to "" otherwise. # Increments num_failures if the death test does not succeed. OneDeathTest() { "$DEBUGALLOCATION_TEST" "$1" 2>&1 | { regex_line='dummy' # Normally the regex_line is the first line of output, but not # always (if tcmalloc itself does any logging to stderr). while test -n "$regex_line"; do read regex_line regex=`expr "$regex_line" : "Expected regex:\(.*\)"` test -n "$regex" && break # found the regex line done test -z "$regex" && echo "done" || grep "$regex" 2>&1 } } death_test_num=0 # which death test to run while /bin/true; do echo -n "Running death test $death_test_num..." output="`OneDeathTest $death_test_num`" case $output in # Empty string means grep didn't find anything. "") echo "FAILED"; num_failures=`expr $num_failures + 1`;; "done"*) echo "done with death tests"; break;; # Any other string means grep found something, like it ought to. *) echo "OK";; esac death_test_num=`expr $death_test_num + 1` done # Test the non-death parts of the test too echo -n "Running non-death tests..." if "$DEBUGALLOCATION_TEST"; then echo "OK" else echo "FAILED" num_failures=`expr $num_failures + 1` fi if [ "$num_failures" = 0 ]; then echo "PASS" else echo "Failed with $num_failures failures" fi exit $num_failures ================================================ FILE: distro/google-perftools-1.7/src/tests/frag_unittest.cc ================================================ // Copyright (c) 2003, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // Test speed of handling fragmented heap #include "config_for_unittests.h" #include #include #ifdef HAVE_SYS_RESOURCE_H #include // for struct timeval #include // for getrusage #endif #ifdef _WIN32 #include // for GetTickCount() #endif #include #include "base/logging.h" #include "common.h" #include using std::vector; int main(int argc, char** argv) { // Make kAllocSize larger than tcmalloc page size. static const int kAllocSize = 9 << kPageShift; // Allocate 400MB in total. static const int kTotalAlloc = 400 << 20; static const int kAllocIterations = kTotalAlloc / kAllocSize; // Allocate lots of objects vector saved(kAllocIterations); for (int i = 0; i < kAllocIterations; i++) { saved[i] = new char[kAllocSize]; } // Free alternating ones to fragment heap size_t free_bytes = 0; for (int i = 0; i < saved.size(); i += 2) { delete[] saved[i]; free_bytes += kAllocSize; } // Check that slack is within 10% of expected size_t slack; MallocExtension::instance()->GetNumericProperty("tcmalloc.slack_bytes", &slack); CHECK_GT(double(slack), 0.9*free_bytes); CHECK_LT(double(slack), 1.1*free_bytes); // Dump malloc stats static const int kBufSize = 1<<20; char* buffer = new char[kBufSize]; MallocExtension::instance()->GetStats(buffer, kBufSize); VLOG(1, "%s", buffer); delete[] buffer; // Now do timing tests for (int i = 0; i < 5; i++) { static const int kIterations = 100000; #ifdef HAVE_SYS_RESOURCE_H struct rusage r; getrusage(RUSAGE_SELF, &r); // figure out user-time spent on this struct timeval tv_start = r.ru_utime; #elif defined(_WIN32) long long int tv_start = GetTickCount(); #else # error No way to calculate time on your system #endif for (int i = 0; i < kIterations; i++) { size_t s; MallocExtension::instance()->GetNumericProperty("tcmalloc.slack_bytes", &s); } #ifdef HAVE_SYS_RESOURCE_H getrusage(RUSAGE_SELF, &r); struct timeval tv_end = r.ru_utime; int64 sumsec = static_cast(tv_end.tv_sec) - tv_start.tv_sec; int64 sumusec = static_cast(tv_end.tv_usec) - tv_start.tv_usec; #elif defined(_WIN32) long long int tv_end = GetTickCount(); int64 sumsec = (tv_end - tv_start) / 1000; // Resolution in windows is only to the millisecond, alas int64 sumusec = ((tv_end - tv_start) % 1000) * 1000; #else # error No way to calculate time on your system #endif fprintf(stderr, "getproperty: %6.1f ns/call\n", (sumsec * 1e9 + sumusec * 1e3) / kIterations); } printf("PASS\n"); return 0; } ================================================ FILE: distro/google-perftools-1.7/src/tests/getpc_test.cc ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Craig Silverstein // // This verifies that GetPC works correctly. This test uses a minimum // of Google infrastructure, to make it very easy to port to various // O/Ses and CPUs and test that GetPC is working. #include "config.h" #include "getpc.h" // should be first to get the _GNU_SOURCE dfn #include #include #include #include // for setitimer // Needs to be volatile so compiler doesn't try to optimize it away static volatile void* getpc_retval = NULL; // what GetPC returns static volatile bool prof_handler_called = false; static void prof_handler(int sig, siginfo_t*, void* signal_ucontext) { if (!prof_handler_called) getpc_retval = GetPC(*reinterpret_cast(signal_ucontext)); prof_handler_called = true; // only store the retval once } static void RoutineCallingTheSignal() { struct sigaction sa; sa.sa_sigaction = prof_handler; sa.sa_flags = SA_RESTART | SA_SIGINFO; sigemptyset(&sa.sa_mask); if (sigaction(SIGPROF, &sa, NULL) != 0) { perror("sigaction"); exit(1); } struct itimerval timer; timer.it_interval.tv_sec = 0; timer.it_interval.tv_usec = 1000; timer.it_value = timer.it_interval; setitimer(ITIMER_PROF, &timer, 0); // Now we need to do some work for a while, that doesn't call any // other functions, so we can be guaranteed that when the SIGPROF // fires, we're the routine executing. int r = 0; for (int i = 0; !prof_handler_called; ++i) { for (int j = 0; j < i; j++) { r ^= i; r <<= 1; r ^= j; r >>= 1; } } // Now make sure the above loop doesn't get optimized out srand(r); } // This is an upper bound of how many bytes the instructions for // RoutineCallingTheSignal might be. There's probably a more // principled way to do this, but I don't know how portable it would be. // (The function is 372 bytes when compiled with -g on Mac OS X 10.4. // I can imagine it would be even bigger in 64-bit architectures.) const int kRoutineSize = 512 * sizeof(void*)/4; // allow 1024 for 64-bit int main(int argc, char** argv) { RoutineCallingTheSignal(); // Annoyingly, C++ disallows casting pointer-to-function to // pointer-to-object, so we use a C-style cast instead. char* expected = (char*)&RoutineCallingTheSignal; char* actual = (char*)getpc_retval; // For ia64, ppc64, and parisc64, the function pointer is actually // a struct. For instance, ia64's dl-fptr.h: // struct fdesc { /* An FDESC is a function descriptor. */ // ElfW(Addr) ip; /* code entry point */ // ElfW(Addr) gp; /* global pointer */ // }; // We want the code entry point. #if defined(__ia64) || defined(__ppc64) // NOTE: ppc64 is UNTESTED expected = ((char**)expected)[0]; // this is "ip" #endif if (actual < expected || actual > expected + kRoutineSize) { printf("Test FAILED: actual PC: %p, expected PC: %p\n", actual, expected); return 1; } else { printf("PASS\n"); return 0; } } ================================================ FILE: distro/google-perftools-1.7/src/tests/heap-checker-death_unittest.sh ================================================ #!/bin/sh # Copyright (c) 2005, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # --- # Author: Maxim Lifantsev # # Run the heap checker unittest in a mode where it is supposed to crash and # return an error if it doesn't. # We expect BINDIR to be set in the environment. # If not, we set it to some reasonable value. BINDIR="${BINDIR:-.}" if [ "x$1" = "x-h" -o "x$1" = "x--help" ]; then echo "USAGE: $0 [unittest dir]" echo " By default, unittest_dir=$BINDIR" exit 1 fi EXE="${1:-$BINDIR}/heap-checker_unittest" TMPDIR="/tmp/heap_check_death_info" ALARM() { # You need perl to run pprof, so I assume it's installed perl -e ' $timeout=$ARGV[0]; shift; $retval = 255; # the default retval, for the case where we timed out eval { # need to run in an eval-block to trigger during system() local $SIG{ALRM} = sub { die "alarm\n" }; # \n is required! alarm $timeout; $retval = system(@ARGV); # Make retval bash-style: exit status, or 128+n if terminated by signal n $retval = ($retval & 127) ? (128 + $retval) : ($retval >> 8); alarm 0; }; exit $retval; # return system()-retval, or 255 if system() never returned ' "$@" } # $1: timeout for alarm; # $2: regexp of expected exit code(s); # $3: regexp to match a line in the output; # $4: regexp to not match a line in the output; # $5+ args to pass to $EXE Test() { # Note: make sure these varnames don't conflict with any vars outside Test()! timeout="$1" shift expected_ec="$1" shift expected_regexp="$1" shift unexpected_regexp="$1" shift echo -n "Testing $EXE with $@ ... " output="$TMPDIR/output" ALARM $timeout env "$@" $EXE > "$output" 2>&1 actual_ec=$? ec_ok=$(expr "$actual_ec" : "$expected_ec$" >/dev/null || echo false) matches_ok=$(test -z "$expected_regexp" || \ grep -q "$expected_regexp" "$output" || echo false) negmatches_ok=$(test -z "$unexpected_regexp" || \ ! grep -q "$unexpected_regexp" "$output" || echo false) if $ec_ok && $matches_ok && $negmatches_ok; then echo "PASS" return 0 # 0: success fi # If we get here, we failed. Now we just need to report why echo "FAIL" if [ $actual_ec -eq 255 ]; then # 255 == SIGTERM due to $ALARM echo "Test was taking unexpectedly long time to run and so we aborted it." echo "Try the test case manually or raise the timeout from $timeout" echo "to distinguish test slowness from a real problem." else $ec_ok || \ echo "Wrong exit code: expected: '$expected_ec'; actual: $actual_ec" $matches_ok || \ echo "Output did not match '$expected_regexp'" $negmatches_ok || \ echo "Output unexpectedly matched '$unexpected_regexp'" fi echo "Output from failed run:" echo "---" cat "$output" echo "---" return 1 # 1: failure } TMPDIR=/tmp/heap_check_death_info rm -rf $TMPDIR || exit 1 mkdir $TMPDIR || exit 2 export HEAPCHECK=strict # default mode # These invocations should pass (0 == PASS): # This tests that turning leak-checker off dynamically works fine Test 120 0 "^PASS$" "" HEAPCHECK="" || exit 1 # This disables threads so we can cause leaks reliably and test finding them Test 120 0 "^PASS$" "" HEAP_CHECKER_TEST_NO_THREADS=1 || exit 2 # Test that --test_cancel_global_check works Test 20 0 "Canceling .* whole-program .* leak check$" "" \ HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_TEST_CANCEL_GLOBAL_CHECK=1 || exit 3 Test 20 0 "Canceling .* whole-program .* leak check$" "" \ HEAP_CHECKER_TEST_TEST_LOOP_LEAK=1 HEAP_CHECKER_TEST_TEST_CANCEL_GLOBAL_CHECK=1 || exit 4 # Test that very early log messages are present and controllable: EARLY_MSG="Starting tracking the heap$" Test 60 0 "$EARLY_MSG" "" \ HEAPCHECK="" HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 \ PERFTOOLS_VERBOSE=10 || exit 5 Test 60 0 "MemoryRegionMap Init$" "" \ HEAPCHECK="" HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 \ PERFTOOLS_VERBOSE=11 || exit 6 Test 60 0 "" "$EARLY_MSG" \ HEAPCHECK="" HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 \ PERFTOOLS_VERBOSE=-11 || exit 7 # These invocations should fail with very high probability, # rather than return 0 or hang (1 == exit(1), 134 == abort(), 139 = SIGSEGV): Test 60 1 "Exiting .* because of .* leaks$" "" \ HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 || exit 8 Test 60 1 "Exiting .* because of .* leaks$" "" \ HEAP_CHECKER_TEST_TEST_LOOP_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 || exit 9 # Test that we produce a reasonable textual leak report. Test 60 1 "MakeALeak" "" \ HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECK_TEST_NO_THREADS=1 \ || exit 10 # Test that very early log messages are present and controllable: Test 60 1 "Starting tracking the heap$" "" \ HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 PERFTOOLS_VERBOSE=10 \ || exit 11 Test 60 1 "" "Starting tracking the heap" \ HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 PERFTOOLS_VERBOSE=-10 \ || exit 12 cd / # so we're not in TMPDIR when we delete it rm -rf $TMPDIR echo "PASS" exit 0 ================================================ FILE: distro/google-perftools-1.7/src/tests/heap-checker_unittest.cc ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Maxim Lifantsev // // Running: // ./heap-checker_unittest // // If the unittest crashes because it can't find pprof, try: // PPROF_PATH=/usr/local/someplace/bin/pprof ./heap-checker_unittest // // To test that the whole-program heap checker will actually cause a leak, try: // HEAPCHECK_TEST_LEAK= ./heap-checker_unittest // HEAPCHECK_TEST_LOOP_LEAK= ./heap-checker_unittest // // Note: Both of the above commands *should* abort with an error message. // CAVEAT: Do not use vector<> and string on-heap objects in this test, // otherwise the test can sometimes fail for tricky leak checks // when we want some allocated object not to be found live by the heap checker. // This can happen with memory allocators like tcmalloc that can allocate // heap objects back to back without any book-keeping data in between. // What happens is that end-of-storage pointers of a live vector // (or a string depending on the STL implementation used) // can happen to point to that other heap-allocated // object that is not reachable otherwise and that // we don't want to be reachable. // // The implication of this for real leak checking // is just one more chance for the liveness flood to be inexact // (see the comment in our .h file). #include "config_for_unittests.h" #ifdef HAVE_POLL_H #include #endif #if defined HAVE_STDINT_H #include // to get uint16_t (ISO naming madness) #elif defined HAVE_INTTYPES_H #include // another place uint16_t might be defined #endif #include #include #include // errno #ifdef HAVE_UNISTD_H #include // for sleep(), geteuid() #endif #ifdef HAVE_MMAP #include #endif #include // for open(), close() // FreeBSD has malloc.h, but complains if you use it #if defined(HAVE_MALLOC_H) && !defined(__FreeBSD__) #include #endif #ifdef HAVE_EXECINFO_H #include // backtrace #endif #ifdef HAVE_GRP_H #include // getgrent, getgrnam #endif #ifdef HAVE_PWD_H #include #endif #include // for cout #include // for hex #include #include #include #include #include #include #include "base/googleinit.h" #include "base/logging.h" #include "base/commandlineflags.h" #include "base/thread_lister.h" #include #include "memory_region_map.h" #include #include // On systems (like freebsd) that don't define MAP_ANONYMOUS, use the old // form of the name instead. #ifndef MAP_ANONYMOUS # define MAP_ANONYMOUS MAP_ANON #endif using namespace std; // ========================================================================= // // TODO(maxim): write a shell script to test that these indeed crash us // (i.e. we do detect leaks) // Maybe add more such crash tests. DEFINE_bool(test_leak, EnvToBool("HEAP_CHECKER_TEST_TEST_LEAK", false), "If should cause a leak crash"); DEFINE_bool(test_loop_leak, EnvToBool("HEAP_CHECKER_TEST_TEST_LOOP_LEAK", false), "If should cause a looped leak crash"); DEFINE_bool(test_register_leak, EnvToBool("HEAP_CHECKER_TEST_TEST_REGISTER_LEAK", false), "If should cause a leak crash by hiding a pointer " "that is only in a register"); DEFINE_bool(test_cancel_global_check, EnvToBool("HEAP_CHECKER_TEST_TEST_CANCEL_GLOBAL_CHECK", false), "If should test HeapLeakChecker::CancelGlobalCheck " "when --test_leak or --test_loop_leak are given; " "the test should not fail then"); DEFINE_bool(maybe_stripped, EnvToBool("HEAP_CHECKER_TEST_MAYBE_STRIPPED", true), "If we think we can be a stripped binary"); DEFINE_bool(interfering_threads, EnvToBool("HEAP_CHECKER_TEST_INTERFERING_THREADS", true), "If we should use threads trying " "to interfere with leak checking"); DEFINE_bool(hoarding_threads, EnvToBool("HEAP_CHECKER_TEST_HOARDING_THREADS", true), "If threads (usually the manager thread) are known " "to retain some old state in their global buffers, " "so that it's hard to force leaks when threads are around"); // TODO(maxim): Chage the default to false // when the standard environment used NTPL threads: // they do not seem to have this problem. DEFINE_bool(no_threads, EnvToBool("HEAP_CHECKER_TEST_NO_THREADS", false), "If we should not use any threads"); // This is used so we can make can_create_leaks_reliably true // for any pthread implementation and test with that. DECLARE_int64(heap_check_max_pointer_offset); // heap-checker.cc DECLARE_string(heap_check); // in heap-checker.cc #define WARN_IF(cond, msg) LOG_IF(WARNING, cond, msg) // This is an evil macro! Be very careful using it... #undef VLOG // and we start by evilling overriding logging.h VLOG #define VLOG(lvl) if (FLAGS_verbose >= (lvl)) cout << "\n" // This is, likewise, evil #define LOGF VLOG(INFO) static void RunHeapBusyThreads(); // below class Closure { public: virtual ~Closure() { } virtual void Run() = 0; }; class Callback0 : public Closure { public: typedef void (*FunctionSignature)(); inline Callback0(FunctionSignature f) : f_(f) {} virtual void Run() { (*f_)(); delete this; } private: FunctionSignature f_; }; template class Callback1 : public Closure { public: typedef void (*FunctionSignature)(P1); inline Callback1(FunctionSignature f, P1 p1) : f_(f), p1_(p1) {} virtual void Run() { (*f_)(p1_); delete this; } private: FunctionSignature f_; P1 p1_; }; template class Callback2 : public Closure { public: typedef void (*FunctionSignature)(P1,P2); inline Callback2(FunctionSignature f, P1 p1, P2 p2) : f_(f), p1_(p1), p2_(p2) {} virtual void Run() { (*f_)(p1_, p2_); delete this; } private: FunctionSignature f_; P1 p1_; P2 p2_; }; inline Callback0* NewCallback(void (*function)()) { return new Callback0(function); } template inline Callback1* NewCallback(void (*function)(P1), P1 p1) { return new Callback1(function, p1); } template inline Callback2* NewCallback(void (*function)(P1,P2), P1 p1, P2 p2) { return new Callback2(function, p1, p2); } // Set to true at end of main, so threads know. Not entirely thread-safe!, // but probably good enough. static bool g_have_exited_main = false; // If we can reliably create leaks (i.e. make leaked object // really unreachable from any global data). static bool can_create_leaks_reliably = false; // We use a simple allocation wrapper // to make sure we wipe out the newly allocated objects // in case they still happened to contain some pointer data // accidentally left by the memory allocator. struct Initialized { }; static Initialized initialized; void* operator new(size_t size, const Initialized&) { // Below we use "p = new(initialized) Foo[1];" and "delete[] p;" // instead of "p = new(initialized) Foo;" // when we need to delete an allocated object. void* p = malloc(size); memset(p, 0, size); return p; } void* operator new[](size_t size, const Initialized&) { char* p = new char[size]; memset(p, 0, size); return p; } static void DoWipeStack(int n); // defined below static void WipeStack() { DoWipeStack(20); } static void Pause() { poll(NULL, 0, 77); // time for thread activity in HeapBusyThreadBody // Indirectly test malloc_extension.*: CHECK(MallocExtension::instance()->VerifyAllMemory()); int blocks; size_t total; int histogram[kMallocHistogramSize]; if (MallocExtension::instance() ->MallocMemoryStats(&blocks, &total, histogram) && total != 0) { VLOG(3) << "Malloc stats: " << blocks << " blocks of " << total << " bytes"; for (int i = 0; i < kMallocHistogramSize; ++i) { if (histogram[i]) { VLOG(3) << " Malloc histogram at " << i << " : " << histogram[i]; } } } WipeStack(); // e.g. MallocExtension::VerifyAllMemory // can leave pointers to heap objects on stack } // Make gcc think a pointer is "used" template static void Use(T** foo) { VLOG(2) << "Dummy-using " << static_cast(*foo) << " at " << foo; } // Arbitrary value, but not such that xor'ing with it is likely // to map one valid pointer to another valid pointer: static const uintptr_t kHideMask = static_cast(0xF03A5F7BF03A5F7BLL); // Helpers to hide a pointer from live data traversal. // We just xor the pointer so that (with high probability) // it's not a valid address of a heap object anymore. // Both Hide and UnHide must be executed within RunHidden() below // to prevent leaving stale data on active stack that can be a pointer // to a heap object that is not actually reachable via live variables. // (UnHide might leave heap pointer value for an object // that will be deallocated but later another object // can be allocated at the same heap address.) template static void Hide(T** ptr) { // we cast values, not dereferenced pointers, so no aliasing issues: *ptr = reinterpret_cast(reinterpret_cast(*ptr) ^ kHideMask); VLOG(2) << "hid: " << static_cast(*ptr); } template static void UnHide(T** ptr) { VLOG(2) << "unhiding: " << static_cast(*ptr); // we cast values, not dereferenced pointers, so no aliasing issues: *ptr = reinterpret_cast(reinterpret_cast(*ptr) ^ kHideMask); } static void LogHidden(const char* message, const void* ptr) { LOGF << message << " : " << ptr << " ^ " << reinterpret_cast(kHideMask) << endl; } // volatile to fool the compiler against inlining the calls to these void (*volatile run_hidden_ptr)(Closure* c, int n); void (*volatile wipe_stack_ptr)(int n); static void DoRunHidden(Closure* c, int n) { if (n) { VLOG(10) << "Level " << n << " at " << &n; (*run_hidden_ptr)(c, n-1); (*wipe_stack_ptr)(n); sleep(0); // undo -foptimize-sibling-calls } else { c->Run(); } } /*static*/ void DoWipeStack(int n) { VLOG(10) << "Wipe level " << n << " at " << &n; if (n) { const int sz = 30; volatile int arr[sz]; for (int i = 0; i < sz; ++i) arr[i] = 0; (*wipe_stack_ptr)(n-1); sleep(0); // undo -foptimize-sibling-calls } } // This executes closure c several stack frames down from the current one // and then makes an effort to also wipe out the stack data that was used by // the closure. // This way we prevent leak checker from finding any temporary pointers // of the closure execution on the stack and deciding that // these pointers (and the pointed objects) are still live. static void RunHidden(Closure* c) { DoRunHidden(c, 15); DoWipeStack(20); } static void DoAllocHidden(size_t size, void** ptr) { void* p = new(initialized) char[size]; Hide(&p); Use(&p); // use only hidden versions VLOG(2) << "Allocated hidden " << p << " at " << &p; *ptr = p; // assign the hidden versions } static void* AllocHidden(size_t size) { void* r; RunHidden(NewCallback(DoAllocHidden, size, &r)); return r; } static void DoDeAllocHidden(void** ptr) { Use(ptr); // use only hidden versions void* p = *ptr; VLOG(2) << "Deallocating hidden " << p; UnHide(&p); delete [] reinterpret_cast(p); } static void DeAllocHidden(void** ptr) { RunHidden(NewCallback(DoDeAllocHidden, ptr)); *ptr = NULL; Use(ptr); } void PreventHeapReclaiming(size_t size) { #ifdef NDEBUG if (true) { static void** no_reclaim_list = NULL; CHECK(size >= sizeof(void*)); // We can't use malloc_reclaim_memory flag in opt mode as debugallocation.cc // is not used. Instead we allocate a bunch of heap objects that are // of the same size as what we are going to leak to ensure that the object // we are about to leak is not at the same address as some old allocated // and freed object that might still have pointers leading to it. for (int i = 0; i < 100; ++i) { void** p = reinterpret_cast(new(initialized) char[size]); p[0] = no_reclaim_list; no_reclaim_list = p; } } #endif } static bool RunSilent(HeapLeakChecker* check, bool (HeapLeakChecker::* func)()) { // By default, don't print the 'we detected a leak' message in the // cases we're expecting a leak (we still print when --v is >= 1). // This way, the logging output is less confusing: we only print // "we detected a leak", and how to diagnose it, for *unexpected* leaks. int32 old_FLAGS_verbose = FLAGS_verbose; if (!VLOG_IS_ON(1)) // not on a verbose setting FLAGS_verbose = FATAL; // only log fatal errors const bool retval = (check->*func)(); FLAGS_verbose = old_FLAGS_verbose; return retval; } #define RUN_SILENT(check, func) RunSilent(&(check), &HeapLeakChecker::func) enum CheckType { SAME_HEAP, NO_LEAKS }; static void VerifyLeaks(HeapLeakChecker* check, CheckType type, int leaked_bytes, int leaked_objects) { WipeStack(); // to help with can_create_leaks_reliably const bool no_leaks = type == NO_LEAKS ? RUN_SILENT(*check, BriefNoLeaks) : RUN_SILENT(*check, BriefSameHeap); if (can_create_leaks_reliably) { // these might still fail occasionally, but it should be very rare CHECK_EQ(no_leaks, false); CHECK_EQ(check->BytesLeaked(), leaked_bytes); CHECK_EQ(check->ObjectsLeaked(), leaked_objects); } else { WARN_IF(no_leaks != false, "Expected leaks not found: " "Some liveness flood must be too optimistic"); } } // not deallocates static void TestHeapLeakCheckerDeathSimple() { HeapLeakChecker check("death_simple"); void* foo = AllocHidden(100 * sizeof(int)); Use(&foo); void* bar = AllocHidden(300); Use(&bar); LogHidden("Leaking", foo); LogHidden("Leaking", bar); Pause(); VerifyLeaks(&check, NO_LEAKS, 300 + 100 * sizeof(int), 2); DeAllocHidden(&foo); DeAllocHidden(&bar); } static void MakeDeathLoop(void** arr1, void** arr2) { PreventHeapReclaiming(2 * sizeof(void*)); void** a1 = new(initialized) void*[2]; void** a2 = new(initialized) void*[2]; a1[1] = reinterpret_cast(a2); a2[1] = reinterpret_cast(a1); Hide(&a1); Hide(&a2); Use(&a1); Use(&a2); VLOG(2) << "Made hidden loop at " << &a1 << " to " << arr1; *arr1 = a1; *arr2 = a2; } // not deallocates two objects linked together static void TestHeapLeakCheckerDeathLoop() { HeapLeakChecker check("death_loop"); void* arr1; void* arr2; RunHidden(NewCallback(MakeDeathLoop, &arr1, &arr2)); Use(&arr1); Use(&arr2); LogHidden("Leaking", arr1); LogHidden("Leaking", arr2); Pause(); VerifyLeaks(&check, NO_LEAKS, 4 * sizeof(void*), 2); DeAllocHidden(&arr1); DeAllocHidden(&arr2); } // deallocates more than allocates static void TestHeapLeakCheckerDeathInverse() { void* bar = AllocHidden(250 * sizeof(int)); Use(&bar); LogHidden("Pre leaking", bar); Pause(); HeapLeakChecker check("death_inverse"); void* foo = AllocHidden(100 * sizeof(int)); Use(&foo); LogHidden("Leaking", foo); DeAllocHidden(&bar); Pause(); VerifyLeaks(&check, SAME_HEAP, 100 * static_cast(sizeof(int)), 1); DeAllocHidden(&foo); } // deallocates more than allocates static void TestHeapLeakCheckerDeathNoLeaks() { void* foo = AllocHidden(100 * sizeof(int)); Use(&foo); void* bar = AllocHidden(250 * sizeof(int)); Use(&bar); HeapLeakChecker check("death_noleaks"); DeAllocHidden(&bar); CHECK_EQ(check.BriefNoLeaks(), true); DeAllocHidden(&foo); } // have less objecs static void TestHeapLeakCheckerDeathCountLess() { void* bar1 = AllocHidden(50 * sizeof(int)); Use(&bar1); void* bar2 = AllocHidden(50 * sizeof(int)); Use(&bar2); LogHidden("Pre leaking", bar1); LogHidden("Pre leaking", bar2); Pause(); HeapLeakChecker check("death_count_less"); void* foo = AllocHidden(100 * sizeof(int)); Use(&foo); LogHidden("Leaking", foo); DeAllocHidden(&bar1); DeAllocHidden(&bar2); Pause(); VerifyLeaks(&check, SAME_HEAP, 100 * sizeof(int), 1); DeAllocHidden(&foo); } // have more objecs static void TestHeapLeakCheckerDeathCountMore() { void* foo = AllocHidden(100 * sizeof(int)); Use(&foo); LogHidden("Pre leaking", foo); Pause(); HeapLeakChecker check("death_count_more"); void* bar1 = AllocHidden(50 * sizeof(int)); Use(&bar1); void* bar2 = AllocHidden(50 * sizeof(int)); Use(&bar2); LogHidden("Leaking", bar1); LogHidden("Leaking", bar2); DeAllocHidden(&foo); Pause(); VerifyLeaks(&check, SAME_HEAP, 100 * sizeof(int), 2); DeAllocHidden(&bar1); DeAllocHidden(&bar2); } static void TestHiddenPointer() { int i; void* foo = &i; HiddenPointer p(foo); CHECK_EQ(foo, p.get()); // Confirm pointer doesn't appear to contain a byte sequence // that == the pointer. We don't really need to test that // the xor trick itself works, as without it nothing in this // test suite would work. See the Hide/Unhide/*Hidden* set // of helper methods. CHECK_NE(foo, *reinterpret_cast(&p)); } // simple tests that deallocate what they allocated static void TestHeapLeakChecker() { { HeapLeakChecker check("trivial"); int foo = 5; int* p = &foo; Use(&p); Pause(); CHECK(check.BriefSameHeap()); } Pause(); { HeapLeakChecker check("simple"); void* foo = AllocHidden(100 * sizeof(int)); Use(&foo); void* bar = AllocHidden(200 * sizeof(int)); Use(&bar); DeAllocHidden(&foo); DeAllocHidden(&bar); Pause(); CHECK(check.BriefSameHeap()); } } // no false positives static void TestHeapLeakCheckerNoFalsePositives() { { HeapLeakChecker check("trivial_p"); int foo = 5; int* p = &foo; Use(&p); Pause(); CHECK(check.BriefSameHeap()); } Pause(); { HeapLeakChecker check("simple_p"); void* foo = AllocHidden(100 * sizeof(int)); Use(&foo); void* bar = AllocHidden(200 * sizeof(int)); Use(&bar); DeAllocHidden(&foo); DeAllocHidden(&bar); Pause(); CHECK(check.SameHeap()); } } // test that we detect leaks when we have same total # of bytes and // objects, but different individual object sizes static void TestLeakButTotalsMatch() { void* bar1 = AllocHidden(240 * sizeof(int)); Use(&bar1); void* bar2 = AllocHidden(160 * sizeof(int)); Use(&bar2); LogHidden("Pre leaking", bar1); LogHidden("Pre leaking", bar2); Pause(); HeapLeakChecker check("trick"); void* foo1 = AllocHidden(280 * sizeof(int)); Use(&foo1); void* foo2 = AllocHidden(120 * sizeof(int)); Use(&foo2); LogHidden("Leaking", foo1); LogHidden("Leaking", foo2); DeAllocHidden(&bar1); DeAllocHidden(&bar2); Pause(); // foo1 and foo2 leaked VerifyLeaks(&check, NO_LEAKS, (280+120)*sizeof(int), 2); DeAllocHidden(&foo1); DeAllocHidden(&foo2); } // no false negatives from pprof static void TestHeapLeakCheckerDeathTrick() { void* bar1 = AllocHidden(240 * sizeof(int)); Use(&bar1); void* bar2 = AllocHidden(160 * sizeof(int)); Use(&bar2); HeapLeakChecker check("death_trick"); DeAllocHidden(&bar1); DeAllocHidden(&bar2); void* foo1 = AllocHidden(280 * sizeof(int)); Use(&foo1); void* foo2 = AllocHidden(120 * sizeof(int)); Use(&foo2); // TODO(maxim): use the above if we make pprof work in automated test runs if (!FLAGS_maybe_stripped) { CHECK_EQ(RUN_SILENT(check, SameHeap), false); // pprof checking should catch the leak } else { WARN_IF(RUN_SILENT(check, SameHeap) != false, "death_trick leak is not caught; " "we must be using a stripped binary"); } DeAllocHidden(&foo1); DeAllocHidden(&foo2); } // simple leak static void TransLeaks() { AllocHidden(1 * sizeof(char)); } // range-based disabling using Disabler static void ScopedDisabledLeaks() { HeapLeakChecker::Disabler disabler; AllocHidden(3 * sizeof(int)); TransLeaks(); malloc(10); // Direct leak } // have different disabled leaks static void* RunDisabledLeaks(void* a) { ScopedDisabledLeaks(); return a; } // have different disabled leaks inside of a thread static void ThreadDisabledLeaks() { if (FLAGS_no_threads) return; pthread_t tid; pthread_attr_t attr; CHECK_EQ(pthread_attr_init(&attr), 0); CHECK_EQ(pthread_create(&tid, &attr, RunDisabledLeaks, NULL), 0); void* res; CHECK_EQ(pthread_join(tid, &res), 0); } // different disabled leaks (some in threads) static void TestHeapLeakCheckerDisabling() { HeapLeakChecker check("disabling"); RunDisabledLeaks(NULL); RunDisabledLeaks(NULL); ThreadDisabledLeaks(); RunDisabledLeaks(NULL); ThreadDisabledLeaks(); ThreadDisabledLeaks(); Pause(); CHECK(check.SameHeap()); } typedef set IntSet; static int some_ints[] = { 1, 2, 3, 21, 22, 23, 24, 25 }; static void DoTestSTLAlloc() { IntSet* x = new(initialized) IntSet[1]; *x = IntSet(some_ints, some_ints + 6); for (int i = 0; i < 1000; i++) { x->insert(i*3); } delete [] x; } // Check that normal STL usage does not result in a leak report. // (In particular we test that there's no complex STL's own allocator // running on top of our allocator with hooks to heap profiler // that can result in false leak report in this case.) static void TestSTLAlloc() { HeapLeakChecker check("stl"); RunHidden(NewCallback(DoTestSTLAlloc)); CHECK_EQ(check.BriefSameHeap(), true); } static void DoTestSTLAllocInverse(IntSet** setx) { IntSet* x = new(initialized) IntSet[1]; *x = IntSet(some_ints, some_ints + 3); for (int i = 0; i < 100; i++) { x->insert(i*2); } Hide(&x); *setx = x; } static void FreeTestSTLAllocInverse(IntSet** setx) { IntSet* x = *setx; UnHide(&x); delete [] x; } // Check that normal leaked STL usage *does* result in a leak report. // (In particular we test that there's no complex STL's own allocator // running on top of our allocator with hooks to heap profiler // that can result in false absence of leak report in this case.) static void TestSTLAllocInverse() { HeapLeakChecker check("death_inverse_stl"); IntSet* x; RunHidden(NewCallback(DoTestSTLAllocInverse, &x)); LogHidden("Leaking", x); if (can_create_leaks_reliably) { WipeStack(); // to help with can_create_leaks_reliably // these might still fail occasionally, but it should be very rare CHECK_EQ(RUN_SILENT(check, BriefNoLeaks), false); CHECK_GE(check.BytesLeaked(), 100 * sizeof(int)); CHECK_GE(check.ObjectsLeaked(), 100); // assumes set<>s are represented by some kind of binary tree // or something else allocating >=1 heap object per set object } else { WARN_IF(RUN_SILENT(check, BriefNoLeaks) != false, "Expected leaks not found: " "Some liveness flood must be too optimistic"); } RunHidden(NewCallback(FreeTestSTLAllocInverse, &x)); } template static void DirectTestSTLAlloc(Alloc allocator, const char* name) { HeapLeakChecker check((string("direct_stl-") + name).c_str()); static const int kSize = 1000; typename Alloc::pointer ptrs[kSize]; for (int i = 0; i < kSize; ++i) { typename Alloc::pointer p = allocator.allocate(i*3+1); HeapLeakChecker::IgnoreObject(p); // This will crash if p is not known to heap profiler: // (i.e. STL's "allocator" does not have a direct hook to heap profiler) HeapLeakChecker::UnIgnoreObject(p); ptrs[i] = p; } for (int i = 0; i < kSize; ++i) { allocator.deallocate(ptrs[i], i*3+1); ptrs[i] = NULL; } CHECK(check.BriefSameHeap()); // just in case } static struct group* grp = NULL; static const int kKeys = 50; static pthread_key_t key[kKeys]; static void KeyFree(void* ptr) { delete [] reinterpret_cast(ptr); } static bool key_init_has_run = false; static void KeyInit() { for (int i = 0; i < kKeys; ++i) { CHECK_EQ(pthread_key_create(&key[i], KeyFree), 0); VLOG(2) << "pthread key " << i << " : " << key[i]; } key_init_has_run = true; // needed for a sanity-check } // force various C library static and thread-specific allocations static void TestLibCAllocate() { CHECK(key_init_has_run); for (int i = 0; i < kKeys; ++i) { void* p = pthread_getspecific(key[i]); if (NULL == p) { if (i == 0) { // Test-logging inside threads which (potentially) creates and uses // thread-local data inside standard C++ library: VLOG(0) << "Adding pthread-specifics for thread " << pthread_self() << " pid " << getpid(); } p = new(initialized) char[77 + i]; VLOG(2) << "pthread specific " << i << " : " << p; pthread_setspecific(key[i], p); } } strerror(errno); const time_t now = time(NULL); ctime(&now); #ifdef HAVE_EXECINFO_H void *stack[1]; backtrace(stack, 1); #endif #ifdef HAVE_GRP_H gid_t gid = getgid(); getgrgid(gid); if (grp == NULL) grp = getgrent(); // a race condition here is okay getgrnam(grp->gr_name); #endif #ifdef HAVE_PWD_H getpwuid(geteuid()); #endif } // Continuous random heap memory activity to try to disrupt heap checking. static void* HeapBusyThreadBody(void* a) { const int thread_num = reinterpret_cast(a); VLOG(0) << "A new HeapBusyThread " << thread_num; TestLibCAllocate(); int user = 0; // Try to hide ptr from heap checker in a CPU register: // Here we are just making a best effort to put the only pointer // to a heap object into a thread register to test // the thread-register finding machinery in the heap checker. #if defined(__i386__) && defined(__GNUC__) register int** ptr asm("esi"); #elif defined(__x86_64__) && defined(__GNUC__) register int** ptr asm("r15"); #else register int** ptr; #endif ptr = NULL; typedef set Set; Set s1; while (1) { // TestLibCAllocate() calls libc functions that don't work so well // after main() has exited. So we just don't do the test then. if (!g_have_exited_main) TestLibCAllocate(); if (ptr == NULL) { ptr = new(initialized) int*[1]; *ptr = new(initialized) int[1]; } set* s2 = new(initialized) set[1]; s1.insert(random()); s2->insert(*s1.begin()); user += *s2->begin(); **ptr += user; if (random() % 51 == 0) { s1.clear(); if (random() % 2 == 0) { s1.~Set(); new(&s1) Set; } } VLOG(3) << pthread_self() << " (" << getpid() << "): in wait: " << ptr << ", " << *ptr << "; " << s1.size(); VLOG(2) << pthread_self() << " (" << getpid() << "): in wait, ptr = " << reinterpret_cast( reinterpret_cast(ptr) ^ kHideMask) << "^" << reinterpret_cast(kHideMask); if (FLAGS_test_register_leak && thread_num % 5 == 0) { // Hide the register "ptr" value with an xor mask. // If one provides --test_register_leak flag, the test should // (with very high probability) crash on some leak check // with a leak report (of some x * sizeof(int) + y * sizeof(int*) bytes) // pointing at the two lines above in this function // with "new(initialized) int" in them as the allocators // of the leaked objects. // CAVEAT: We can't really prevent a compiler to save some // temporary values of "ptr" on the stack and thus let us find // the heap objects not via the register. // Hence it's normal if for certain compilers or optimization modes // --test_register_leak does not cause a leak crash of the above form // (this happens e.g. for gcc 4.0.1 in opt mode). ptr = reinterpret_cast( reinterpret_cast(ptr) ^ kHideMask); // busy loop to get the thread interrupted at: for (int i = 1; i < 10000000; ++i) user += (1 + user * user * 5) / i; ptr = reinterpret_cast( reinterpret_cast(ptr) ^ kHideMask); } else { poll(NULL, 0, random() % 100); } VLOG(2) << pthread_self() << ": continuing"; if (random() % 3 == 0) { delete [] *ptr; delete [] ptr; ptr = NULL; } delete [] s2; } return a; } static void RunHeapBusyThreads() { KeyInit(); if (!FLAGS_interfering_threads || FLAGS_no_threads) return; const int n = 17; // make many threads pthread_t tid; pthread_attr_t attr; CHECK_EQ(pthread_attr_init(&attr), 0); // make them and let them run for (int i = 0; i < n; ++i) { VLOG(0) << "Creating extra thread " << i + 1; CHECK(pthread_create(&tid, &attr, HeapBusyThreadBody, reinterpret_cast(i)) == 0); } Pause(); Pause(); } // ========================================================================= // // This code section is to test that objects that are reachable from global // variables are not reported as leaks // as well as that (Un)IgnoreObject work for such objects fine. // An object making functions: // returns a "weird" pointer to a new object for which // it's worth checking that the object is reachable via that pointer. typedef void* (*ObjMakerFunc)(); static list obj_makers; // list of registered object makers // Helper macro to register an object making function // 'name' is an identifier of this object maker, // 'body' is its function body that must declare // pointer 'p' to the nex object to return. // Usage example: // REGISTER_OBJ_MAKER(trivial, int* p = new(initialized) int;) #define REGISTER_OBJ_MAKER(name, body) \ void* ObjMaker_##name##_() { \ VLOG(1) << "Obj making " << #name; \ body; \ return p; \ } \ static ObjMakerRegistrar maker_reg_##name##__(&ObjMaker_##name##_); // helper class for REGISTER_OBJ_MAKER struct ObjMakerRegistrar { ObjMakerRegistrar(ObjMakerFunc obj_maker) { obj_makers.push_back(obj_maker); } }; // List of the objects/pointers made with all the obj_makers // to test reachability via global data pointers during leak checks. static list* live_objects = new list; // pointer so that it does not get destructed on exit // Exerciser for one ObjMakerFunc. static void TestPointerReach(ObjMakerFunc obj_maker) { HeapLeakChecker::IgnoreObject(obj_maker()); // test IgnoreObject void* obj = obj_maker(); HeapLeakChecker::IgnoreObject(obj); HeapLeakChecker::UnIgnoreObject(obj); // test UnIgnoreObject HeapLeakChecker::IgnoreObject(obj); // not to need deletion for obj live_objects->push_back(obj_maker()); // test reachability at leak check } // Test all ObjMakerFunc registred via REGISTER_OBJ_MAKER. static void TestObjMakers() { for (list::const_iterator i = obj_makers.begin(); i != obj_makers.end(); ++i) { TestPointerReach(*i); TestPointerReach(*i); // a couple more times would not hurt TestPointerReach(*i); } } // A dummy class to mimic allocation behavior of string-s. template struct Array { Array() { size = 3 + random() % 30; ptr = new(initialized) T[size]; } ~Array() { delete [] ptr; } Array(const Array& x) { size = x.size; ptr = new(initialized) T[size]; for (size_t i = 0; i < size; ++i) { ptr[i] = x.ptr[i]; } } void operator=(const Array& x) { delete [] ptr; size = x.size; ptr = new(initialized) T[size]; for (size_t i = 0; i < size; ++i) { ptr[i] = x.ptr[i]; } } void append(const Array& x) { T* p = new(initialized) T[size + x.size]; for (size_t i = 0; i < size; ++i) { p[i] = ptr[i]; } for (size_t i = 0; i < x.size; ++i) { p[size+i] = x.ptr[i]; } size += x.size; delete [] ptr; ptr = p; } private: size_t size; T* ptr; }; // to test pointers to objects, built-in arrays, string, etc: REGISTER_OBJ_MAKER(plain, int* p = new(initialized) int;) REGISTER_OBJ_MAKER(int_array_1, int* p = new(initialized) int[1];) REGISTER_OBJ_MAKER(int_array, int* p = new(initialized) int[10];) REGISTER_OBJ_MAKER(string, Array* p = new(initialized) Array();) REGISTER_OBJ_MAKER(string_array, Array* p = new(initialized) Array[5];) REGISTER_OBJ_MAKER(char_array, char* p = new(initialized) char[5];) REGISTER_OBJ_MAKER(appended_string, Array* p = new Array(); p->append(Array()); ) REGISTER_OBJ_MAKER(plain_ptr, int** p = new(initialized) int*;) REGISTER_OBJ_MAKER(linking_ptr, int** p = new(initialized) int*; *p = new(initialized) int; ) // small objects: REGISTER_OBJ_MAKER(0_sized, void* p = malloc(0);) // 0-sized object (important) REGISTER_OBJ_MAKER(1_sized, void* p = malloc(1);) REGISTER_OBJ_MAKER(2_sized, void* p = malloc(2);) REGISTER_OBJ_MAKER(3_sized, void* p = malloc(3);) REGISTER_OBJ_MAKER(4_sized, void* p = malloc(4);) static int set_data[] = { 1, 2, 3, 4, 5, 6, 7, 21, 22, 23, 24, 25, 26, 27 }; static set live_leak_set(set_data, set_data+7); static const set live_leak_const_set(set_data, set_data+14); REGISTER_OBJ_MAKER(set, set* p = new(initialized) set(set_data, set_data + 13); ) class ClassA { public: explicit ClassA(int a) : ptr(NULL) { } mutable char* ptr; }; static const ClassA live_leak_mutable(1); template class TClass { public: explicit TClass(int a) : ptr(NULL) { } mutable C val; mutable C* ptr; }; static const TClass > live_leak_templ_mutable(1); class ClassB { public: ClassB() { } char b[7]; virtual void f() { } virtual ~ClassB() { } }; class ClassB2 { public: ClassB2() { } char b2[11]; virtual void f2() { } virtual ~ClassB2() { } }; class ClassD1 : public ClassB { char d1[15]; virtual void f() { } }; class ClassD2 : public ClassB2 { char d2[19]; virtual void f2() { } }; class ClassD : public ClassD1, public ClassD2 { char d[3]; virtual void f() { } virtual void f2() { } }; // to test pointers to objects of base subclasses: REGISTER_OBJ_MAKER(B, ClassB* p = new(initialized) ClassB;) REGISTER_OBJ_MAKER(D1, ClassD1* p = new(initialized) ClassD1;) REGISTER_OBJ_MAKER(D2, ClassD2* p = new(initialized) ClassD2;) REGISTER_OBJ_MAKER(D, ClassD* p = new(initialized) ClassD;) REGISTER_OBJ_MAKER(D1_as_B, ClassB* p = new(initialized) ClassD1;) REGISTER_OBJ_MAKER(D2_as_B2, ClassB2* p = new(initialized) ClassD2;) REGISTER_OBJ_MAKER(D_as_B, ClassB* p = new(initialized) ClassD;) REGISTER_OBJ_MAKER(D_as_D1, ClassD1* p = new(initialized) ClassD;) // inside-object pointers: REGISTER_OBJ_MAKER(D_as_B2, ClassB2* p = new(initialized) ClassD;) REGISTER_OBJ_MAKER(D_as_D2, ClassD2* p = new(initialized) ClassD;) class InterfaceA { public: virtual void A() = 0; virtual ~InterfaceA() { } protected: InterfaceA() { } }; class InterfaceB { public: virtual void B() = 0; virtual ~InterfaceB() { } protected: InterfaceB() { } }; class InterfaceC : public InterfaceA { public: virtual void C() = 0; virtual ~InterfaceC() { } protected: InterfaceC() { } }; class ClassMltD1 : public ClassB, public InterfaceB, public InterfaceC { public: char d1[11]; virtual void f() { } virtual void A() { } virtual void B() { } virtual void C() { } }; class ClassMltD2 : public InterfaceA, public InterfaceB, public ClassB { public: char d2[15]; virtual void f() { } virtual void A() { } virtual void B() { } }; // to specifically test heap reachability under // inerface-only multiple inheritance (some use inside-object pointers): REGISTER_OBJ_MAKER(MltD1, ClassMltD1* p = new(initialized) ClassMltD1;) REGISTER_OBJ_MAKER(MltD1_as_B, ClassB* p = new(initialized) ClassMltD1;) REGISTER_OBJ_MAKER(MltD1_as_IA, InterfaceA* p = new(initialized) ClassMltD1;) REGISTER_OBJ_MAKER(MltD1_as_IB, InterfaceB* p = new(initialized) ClassMltD1;) REGISTER_OBJ_MAKER(MltD1_as_IC, InterfaceC* p = new(initialized) ClassMltD1;) REGISTER_OBJ_MAKER(MltD2, ClassMltD2* p = new(initialized) ClassMltD2;) REGISTER_OBJ_MAKER(MltD2_as_B, ClassB* p = new(initialized) ClassMltD2;) REGISTER_OBJ_MAKER(MltD2_as_IA, InterfaceA* p = new(initialized) ClassMltD2;) REGISTER_OBJ_MAKER(MltD2_as_IB, InterfaceB* p = new(initialized) ClassMltD2;) // to mimic UnicodeString defined in third_party/icu, // which store a platform-independent-sized refcount in the first // few bytes and keeps a pointer pointing behind the refcount. REGISTER_OBJ_MAKER(unicode_string, char* p = new char[sizeof(uint32) * 10]; p += sizeof(uint32); ) // similar, but for platform-dependent-sized refcount REGISTER_OBJ_MAKER(ref_counted, char* p = new char[sizeof(int) * 20]; p += sizeof(int); ) struct Nesting { struct Inner { Nesting* parent; Inner(Nesting* p) : parent(p) {} }; Inner i0; char n1[5]; Inner i1; char n2[11]; Inner i2; char n3[27]; Inner i3; Nesting() : i0(this), i1(this), i2(this), i3(this) {} }; // to test inside-object pointers pointing at objects nested into heap objects: REGISTER_OBJ_MAKER(nesting_i0, Nesting::Inner* p = &((new Nesting())->i0);) REGISTER_OBJ_MAKER(nesting_i1, Nesting::Inner* p = &((new Nesting())->i1);) REGISTER_OBJ_MAKER(nesting_i2, Nesting::Inner* p = &((new Nesting())->i2);) REGISTER_OBJ_MAKER(nesting_i3, Nesting::Inner* p = &((new Nesting())->i3);) // allocate many objects reachable from global data static void TestHeapLeakCheckerLiveness() { live_leak_mutable.ptr = new(initialized) char[77]; live_leak_templ_mutable.ptr = new(initialized) Array(); live_leak_templ_mutable.val = Array(); TestObjMakers(); } // ========================================================================= // // Get address (PC value) following the mmap call into addr_after_mmap_call static void* Mmapper(uintptr_t* addr_after_mmap_call) { void* r = mmap(NULL, 100, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); // Get current PC value into addr_after_mmap_call void* stack[1]; CHECK_EQ(GetStackTrace(stack, 1, 0), 1); *addr_after_mmap_call = reinterpret_cast(stack[0]); sleep(0); // undo -foptimize-sibling-calls return r; } // to trick complier into preventing inlining static void* (*mmapper_addr)(uintptr_t* addr) = &Mmapper; // TODO(maxim): copy/move this to memory_region_map_unittest // TODO(maxim): expand this test to include mmap64, mremap and sbrk calls. static void VerifyMemoryRegionMapStackGet() { uintptr_t caller_addr_limit; void* addr = (*mmapper_addr)(&caller_addr_limit); uintptr_t caller = 0; { MemoryRegionMap::LockHolder l; for (MemoryRegionMap::RegionIterator i = MemoryRegionMap::BeginRegionLocked(); i != MemoryRegionMap::EndRegionLocked(); ++i) { if (i->start_addr == reinterpret_cast(addr)) { CHECK_EQ(caller, 0); caller = i->caller(); } } } // caller must point into Mmapper function: if (!(reinterpret_cast(mmapper_addr) <= caller && caller < caller_addr_limit)) { LOGF << std::hex << "0x" << caller << " does not seem to point into code of function Mmapper at " << "0x" << reinterpret_cast(mmapper_addr) << "! Stack frame collection must be off in MemoryRegionMap!"; LOG(FATAL, "\n"); } munmap(addr, 100); } static void* Mallocer(uintptr_t* addr_after_malloc_call) { void* r = malloc(100); sleep(0); // undo -foptimize-sibling-calls // Get current PC value into addr_after_malloc_call void* stack[1]; CHECK_EQ(GetStackTrace(stack, 1, 0), 1); *addr_after_malloc_call = reinterpret_cast(stack[0]); return r; } // to trick complier into preventing inlining static void* (*mallocer_addr)(uintptr_t* addr) = &Mallocer; // non-static for friendship with HeapProfiler // TODO(maxim): expand this test to include // realloc, calloc, memalign, valloc, pvalloc, new, and new[]. extern void VerifyHeapProfileTableStackGet() { uintptr_t caller_addr_limit; void* addr = (*mallocer_addr)(&caller_addr_limit); uintptr_t caller = reinterpret_cast(HeapLeakChecker::GetAllocCaller(addr)); // caller must point into Mallocer function: if (!(reinterpret_cast(mallocer_addr) <= caller && caller < caller_addr_limit)) { LOGF << std::hex << "0x" << caller << " does not seem to point into code of function Mallocer at " << "0x" << reinterpret_cast(mallocer_addr) << "! Stack frame collection must be off in heap profiler!"; LOG(FATAL, "\n"); } free(addr); } // ========================================================================= // static void MakeALeak(void** arr) { PreventHeapReclaiming(10 * sizeof(int)); void* a = new(initialized) int[10]; Hide(&a); *arr = a; } // Helper to do 'return 0;' inside main(): insted we do 'return Pass();' static int Pass() { fprintf(stdout, "PASS\n"); g_have_exited_main = true; return 0; } int main(int argc, char** argv) { run_hidden_ptr = DoRunHidden; wipe_stack_ptr = DoWipeStack; if (!HeapLeakChecker::IsActive()) { CHECK_EQ(FLAGS_heap_check, ""); LOG(WARNING, "HeapLeakChecker got turned off; we won't test much..."); } else { VerifyMemoryRegionMapStackGet(); VerifyHeapProfileTableStackGet(); } KeyInit(); // glibc 2.4, on x86_64 at least, has a lock-ordering bug, which // means deadlock is possible when one thread calls dl_open at the // same time another thread is calling dl_iterate_phdr. libunwind // calls dl_iterate_phdr, and TestLibCAllocate calls dl_open (or the // various syscalls in it do), at least the first time it's run. // To avoid the deadlock, we run TestLibCAllocate once before getting // multi-threaded. // TODO(csilvers): once libc is fixed, or libunwind can work around it, // get rid of this early call. We *want* our test to // find potential problems like this one! TestLibCAllocate(); if (FLAGS_interfering_threads) { RunHeapBusyThreads(); // add interference early } TestLibCAllocate(); LOGF << "In main(): heap_check=" << FLAGS_heap_check << endl; CHECK(HeapLeakChecker::NoGlobalLeaks()); // so far, so good if (FLAGS_test_leak) { void* arr; RunHidden(NewCallback(MakeALeak, &arr)); Use(&arr); LogHidden("Leaking", arr); if (FLAGS_test_cancel_global_check) HeapLeakChecker::CancelGlobalCheck(); return Pass(); // whole-program leak-check should (with very high probability) // catch the leak of arr (10 * sizeof(int) bytes) // (when !FLAGS_test_cancel_global_check) } if (FLAGS_test_loop_leak) { void* arr1; void* arr2; RunHidden(NewCallback(MakeDeathLoop, &arr1, &arr2)); Use(&arr1); Use(&arr2); LogHidden("Loop leaking", arr1); LogHidden("Loop leaking", arr2); if (FLAGS_test_cancel_global_check) HeapLeakChecker::CancelGlobalCheck(); return Pass(); // whole-program leak-check should (with very high probability) // catch the leak of arr1 and arr2 (4 * sizeof(void*) bytes) // (when !FLAGS_test_cancel_global_check) } if (FLAGS_test_register_leak) { // make us fail only where the .sh test expects: Pause(); for (int i = 0; i < 100; ++i) { // give it some time to crash CHECK(HeapLeakChecker::NoGlobalLeaks()); Pause(); } return Pass(); } TestHeapLeakCheckerLiveness(); HeapLeakChecker heap_check("all"); TestHiddenPointer(); TestHeapLeakChecker(); Pause(); TestLeakButTotalsMatch(); Pause(); TestHeapLeakCheckerDeathSimple(); Pause(); TestHeapLeakCheckerDeathLoop(); Pause(); TestHeapLeakCheckerDeathInverse(); Pause(); TestHeapLeakCheckerDeathNoLeaks(); Pause(); TestHeapLeakCheckerDeathCountLess(); Pause(); TestHeapLeakCheckerDeathCountMore(); Pause(); TestHeapLeakCheckerDeathTrick(); Pause(); CHECK(HeapLeakChecker::NoGlobalLeaks()); // so far, so good TestHeapLeakCheckerNoFalsePositives(); Pause(); TestHeapLeakCheckerDisabling(); Pause(); TestSTLAlloc(); Pause(); TestSTLAllocInverse(); Pause(); // Test that various STL allocators work. Some of these are redundant, but // we don't know how STL might change in the future. For example, // http://wiki/Main/StringNeStdString. #define DTSL(a) { DirectTestSTLAlloc(a, #a); \ Pause(); } DTSL(std::allocator()); DTSL(std::allocator()); DTSL(std::string().get_allocator()); DTSL(string().get_allocator()); DTSL(vector().get_allocator()); DTSL(vector().get_allocator()); DTSL(vector >().get_allocator()); DTSL(vector().get_allocator()); DTSL((map().get_allocator())); DTSL((map().get_allocator())); DTSL(set().get_allocator()); #undef DTSL TestLibCAllocate(); Pause(); CHECK(HeapLeakChecker::NoGlobalLeaks()); // so far, so good Pause(); if (!FLAGS_maybe_stripped) { CHECK(heap_check.SameHeap()); } else { WARN_IF(heap_check.SameHeap() != true, "overall leaks are caught; we must be using a stripped binary"); } CHECK(HeapLeakChecker::NoGlobalLeaks()); // so far, so good return Pass(); } ================================================ FILE: distro/google-perftools-1.7/src/tests/heap-checker_unittest.sh ================================================ #!/bin/sh # Copyright (c) 2005, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # --- # Author: Craig Silverstein # # Runs the heap-checker unittest with various environment variables. # This is necessary because we turn on features like the heap profiler # and heap checker via environment variables. This test makes sure # they all play well together. # We expect BINDIR and PPROF_PATH to be set in the environment. # If not, we set them to some reasonable values BINDIR="${BINDIR:-.}" PPROF_PATH="${PPROF_PATH:-$BINDIR/src/pprof}" if [ "x$1" = "x-h" -o "$1" = "x--help" ]; then echo "USAGE: $0 [unittest dir] [path to pprof]" echo " By default, unittest_dir=$BINDIR, pprof_path=$PPROF_PATH" exit 1 fi HEAP_CHECKER="${1:-$BINDIR}/heap-checker_unittest" PPROF_PATH="${2:-$PPROF_PATH}" TMPDIR=/tmp/heap_check_info rm -rf $TMPDIR || exit 2 mkdir $TMPDIR || exit 3 # $1: value of heap-check env. var. run_check() { export PPROF_PATH="$PPROF_PATH" [ -n "$1" ] && export HEAPCHECK="$1" || unset HEAPPROFILE echo -n "Testing $HEAP_CHECKER with HEAPCHECK=$1 ... " if $HEAP_CHECKER > $TMPDIR/output 2>&1; then echo "OK" else echo "FAILED" echo "Output from the failed run:" echo "----" cat $TMPDIR/output echo "----" exit 4 fi # If we set HEAPPROFILE, then we expect it to actually have emitted # a profile. Check that it did. if [ -n "$HEAPPROFILE" ]; then [ -e "$HEAPPROFILE.0001.heap" ] || exit 5 fi } run_check "" run_check "local" run_check "normal" run_check "strict" rm -rf $TMPDIR # clean up echo "PASS" ================================================ FILE: distro/google-perftools-1.7/src/tests/heap-profiler_unittest.cc ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Craig Silverstein // // A small program that just exercises our heap profiler by allocating // memory and letting the heap-profiler emit a profile. We don't test // threads (TODO). By itself, this unittest tests that the heap-profiler // doesn't crash on simple programs, but its output can be analyzed by // another testing script to actually verify correctness. See, eg, // heap-profiler_unittest.sh. #include "config_for_unittests.h" #include #include #include // for mkdir() #include // for mkdir() on freebsd and os x #ifdef HAVE_UNISTD_H #include // for fork() #endif #include // for wait() #include #include "base/basictypes.h" #include "base/logging.h" #include using std::string; static const int kMaxCount = 100000; int* g_array[kMaxCount]; // an array of int-vectors static ATTRIBUTE_NOINLINE void Allocate(int start, int end, int size) { for (int i = start; i < end; ++i) { if (i < kMaxCount) g_array[i] = new int[size]; } } static ATTRIBUTE_NOINLINE void Allocate2(int start, int end, int size) { for (int i = start; i < end; ++i) { if (i < kMaxCount) g_array[i] = new int[size]; } } static void Deallocate(int start, int end) { for (int i = start; i < end; ++i) { delete[] g_array[i]; g_array[i] = 0; } } static void TestHeapProfilerStartStopIsRunning() { // If you run this with whole-program heap-profiling on, than // IsHeapProfilerRunning should return true. if (!IsHeapProfilerRunning()) { const char* tmpdir = getenv("TMPDIR"); if (tmpdir == NULL) tmpdir = "/tmp"; mkdir(tmpdir, 0755); // if necessary HeapProfilerStart((string(tmpdir) + "/start_stop").c_str()); CHECK(IsHeapProfilerRunning()); Allocate(0, 40, 100); Deallocate(0, 40); HeapProfilerStop(); CHECK(!IsHeapProfilerRunning()); } } static void TestDumpHeapProfiler() { // If you run this with whole-program heap-profiling on, than // IsHeapProfilerRunning should return true. if (!IsHeapProfilerRunning()) { const char* tmpdir = getenv("TMPDIR"); if (tmpdir == NULL) tmpdir = "/tmp"; mkdir(tmpdir, 0755); // if necessary HeapProfilerStart((string(tmpdir) + "/dump").c_str()); CHECK(IsHeapProfilerRunning()); Allocate(0, 40, 100); Deallocate(0, 40); char* output = GetHeapProfile(); free(output); HeapProfilerStop(); } } int main(int argc, char** argv) { if (argc > 2 || (argc == 2 && argv[1][0] == '-')) { printf("USAGE: %s [number of children to fork]\n", argv[0]); exit(0); } int num_forks = 0; if (argc == 2) { num_forks = atoi(argv[1]); } TestHeapProfilerStartStopIsRunning(); TestDumpHeapProfiler(); Allocate(0, 40, 100); Deallocate(0, 40); Allocate(0, 40, 100); Allocate(0, 40, 100); Allocate2(40, 400, 1000); Allocate2(400, 1000, 10000); Deallocate(0, 1000); Allocate(0, 100, 100000); Deallocate(0, 10); Deallocate(10, 20); Deallocate(90, 100); Deallocate(20, 90); while (num_forks-- > 0) { switch (fork()) { case -1: printf("FORK failed!\n"); return 1; case 0: // child return execl(argv[0], argv[0], NULL); // run child with no args default: wait(NULL); // we'll let the kids run one at a time } } printf("DONE.\n"); return 0; } ================================================ FILE: distro/google-perftools-1.7/src/tests/heap-profiler_unittest.sh ================================================ #!/bin/sh # Copyright (c) 2005, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # --- # Author: Craig Silverstein # # Runs the heap-profiler unittest and makes sure the profile looks appropriate. # # We run under the assumption that if $HEAP_PROFILER is run with --help, # it prints a usage line of the form # USAGE: [...] # # This is because libtool sometimes turns the 'executable' into a # shell script which runs an actual binary somewhere else. # We expect BINDIR and PPROF_PATH to be set in the environment. # If not, we set them to some reasonable values BINDIR="${BINDIR:-.}" PPROF_PATH="${PPROF_PATH:-$BINDIR/src/pprof}" if [ "x$1" = "x-h" -o "x$1" = "x--help" ]; then echo "USAGE: $0 [unittest dir] [path to pprof]" echo " By default, unittest_dir=$BINDIR, pprof_path=$PPROF_PATH" exit 1 fi HEAP_PROFILER="${1:-$BINDIR}/heap-profiler_unittest" PPROF="${2:-$PPROF_PATH}" TEST_TMPDIR=/tmp/heap_profile_info # It's meaningful to the profiler, so make sure we know its state unset HEAPPROFILE rm -rf "$TEST_TMPDIR" mkdir "$TEST_TMPDIR" || exit 2 num_failures=0 # Given one profile (to check the contents of that profile) or two # profiles (to check the diff between the profiles), and a function # name, verify that the function name takes up at least 90% of the # allocated memory. The function name is actually specified first. VerifyMemFunction() { function="$1" shift # get program name. Note we have to unset HEAPPROFILE so running # help doesn't overwrite existing profiles. exec=`unset HEAPPROFILE; $HEAP_PROFILER --help | awk '{print $2; exit;}'` if [ $# = 2 ]; then [ -f "$1" ] || { echo "Profile not found: $1"; exit 1; } [ -f "$2" ] || { echo "Profile not found: $2"; exit 1; } $PPROF --base="$1" $exec "$2" >"$TEST_TMPDIR/output.pprof" 2>&1 else [ -f "$1" ] || { echo "Profile not found: $1"; exit 1; } $PPROF $exec "$1" >"$TEST_TMPDIR/output.pprof" 2>&1 fi cat "$TEST_TMPDIR/output.pprof" \ | tr -d % | awk '$6 ~ /^'$function'$/ && $2 > 90 {exit 1;}' if [ $? != 1 ]; then echo echo "--- Test failed for $function: didn't account for 90% of executable memory" echo "--- Program output:" cat "$TEST_TMPDIR/output" echo "--- pprof output:" cat "$TEST_TMPDIR/output.pprof" echo "---" num_failures=`expr $num_failures + 1` fi } VerifyOutputContains() { text="$1" if ! grep "$text" "$TEST_TMPDIR/output" >/dev/null 2>&1; then echo "--- Test failed: output does not contain '$text'" echo "--- Program output:" cat "$TEST_TMPDIR/output" echo "---" num_failures=`expr $num_failures + 1` fi } HEAPPROFILE="$TEST_TMPDIR/test" HEAP_PROFILE_INUSE_INTERVAL="10240" # need this to be 10Kb HEAP_PROFILE_ALLOCATION_INTERVAL="$HEAP_PROFILE_INUSE_INTERVAL" HEAP_PROFILE_DEALLOCATION_INTERVAL="$HEAP_PROFILE_INUSE_INTERVAL" export HEAPPROFILE export HEAP_PROFILE_INUSE_INTERVAL export HEAP_PROFILE_ALLOCATION_INTERVAL export HEAP_PROFILE_DEALLOCATION_INTERVAL # We make the unittest run a child process, to test that the child # process doesn't try to write a heap profile as well and step on the # parent's toes. If it does, we expect the parent-test to fail. $HEAP_PROFILER 1 >$TEST_TMPDIR/output 2>&1 # run program, with 1 child proc VerifyMemFunction Allocate2 "$HEAPPROFILE.1329.heap" VerifyMemFunction Allocate "$HEAPPROFILE.1448.heap" "$HEAPPROFILE.1548.heap" # Check the child process got to emit its own profile as well. VerifyMemFunction Allocate2 "$HEAPPROFILE"_*.1329.heap VerifyMemFunction Allocate "$HEAPPROFILE"_*.1448.heap "$HEAPPROFILE"_*.1548.heap # Make sure we logged both about allocating and deallocating memory VerifyOutputContains "62 MB allocated" VerifyOutputContains "62 MB freed" # Now try running without --heap_profile specified, to allow # testing of the HeapProfileStart/Stop functionality. $HEAP_PROFILER >"$TEST_TMPDIR/output2" 2>&1 rm -rf $TMPDIR # clean up if [ $num_failures = 0 ]; then echo "PASS" else echo "Tests finished with $num_failures failures" fi exit $num_failures ================================================ FILE: distro/google-perftools-1.7/src/tests/low_level_alloc_unittest.cc ================================================ /* Copyright (c) 2006, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // A test for low_level_alloc.cc #include #include #include "base/low_level_alloc.h" #include "base/logging.h" #include using std::map; // a block of memory obtained from the allocator struct BlockDesc { char *ptr; // pointer to memory int len; // number of bytes int fill; // filled with data starting with this }; // Check that the pattern placed in the block d // by RandomizeBlockDesc is still there. static void CheckBlockDesc(const BlockDesc &d) { for (int i = 0; i != d.len; i++) { CHECK((d.ptr[i] & 0xff) == ((d.fill + i) & 0xff)); } } // Fill the block "*d" with a pattern // starting with a random byte. static void RandomizeBlockDesc(BlockDesc *d) { d->fill = rand() & 0xff; for (int i = 0; i != d->len; i++) { d->ptr[i] = (d->fill + i) & 0xff; } } // Use to indicate to the malloc hooks that // this calls is from LowLevelAlloc. static bool using_low_level_alloc = false; // n times, toss a coin, and based on the outcome // either allocate a new block or deallocate an old block. // New blocks are placed in a map with a random key // and initialized with RandomizeBlockDesc(). // If keys conflict, the older block is freed. // Old blocks are always checked with CheckBlockDesc() // before being freed. At the end of the run, // all remaining allocated blocks are freed. // If use_new_arena is true, use a fresh arena, and then delete it. // If call_malloc_hook is true and user_arena is true, // allocations and deallocations are reported via the MallocHook // interface. static void Test(bool use_new_arena, bool call_malloc_hook, int n) { typedef map AllocMap; AllocMap allocated; AllocMap::iterator it; BlockDesc block_desc; int rnd; LowLevelAlloc::Arena *arena = 0; if (use_new_arena) { int32 flags = call_malloc_hook? LowLevelAlloc::kCallMallocHook : 0; arena = LowLevelAlloc::NewArena(flags, LowLevelAlloc::DefaultArena()); } for (int i = 0; i != n; i++) { if (i != 0 && i % 10000 == 0) { printf("."); fflush(stdout); } switch(rand() & 1) { // toss a coin case 0: // coin came up heads: add a block using_low_level_alloc = true; block_desc.len = rand() & 0x3fff; block_desc.ptr = reinterpret_cast( arena == 0 ? LowLevelAlloc::Alloc(block_desc.len) : LowLevelAlloc::AllocWithArena(block_desc.len, arena)); using_low_level_alloc = false; RandomizeBlockDesc(&block_desc); rnd = rand(); it = allocated.find(rnd); if (it != allocated.end()) { CheckBlockDesc(it->second); using_low_level_alloc = true; LowLevelAlloc::Free(it->second.ptr); using_low_level_alloc = false; it->second = block_desc; } else { allocated[rnd] = block_desc; } break; case 1: // coin came up tails: remove a block it = allocated.begin(); if (it != allocated.end()) { CheckBlockDesc(it->second); using_low_level_alloc = true; LowLevelAlloc::Free(it->second.ptr); using_low_level_alloc = false; allocated.erase(it); } break; } } // remove all remaniing blocks while ((it = allocated.begin()) != allocated.end()) { CheckBlockDesc(it->second); using_low_level_alloc = true; LowLevelAlloc::Free(it->second.ptr); using_low_level_alloc = false; allocated.erase(it); } if (use_new_arena) { CHECK(LowLevelAlloc::DeleteArena(arena)); } } // used for counting allocates and frees static int32 allocates; static int32 frees; static MallocHook::NewHook old_alloc_hook; static MallocHook::DeleteHook old_free_hook; // called on each alloc if kCallMallocHook specified static void AllocHook(const void *p, size_t size) { if (using_low_level_alloc) { allocates++; } if (old_alloc_hook != 0) { (*old_alloc_hook)(p, size); } } // called on each free if kCallMallocHook specified static void FreeHook(const void *p) { if (using_low_level_alloc) { frees++; } if (old_free_hook != 0) { (*old_free_hook)(p); } } int main(int argc, char *argv[]) { // This is needed by maybe_threads_unittest.sh, which parses argv[0] // to figure out what directory low_level_alloc_unittest is in. if (argc != 1) { fprintf(stderr, "USAGE: %s\n", argv[0]); return 1; } old_alloc_hook = MallocHook::SetNewHook(AllocHook); old_free_hook = MallocHook::SetDeleteHook(FreeHook); CHECK_EQ(allocates, 0); CHECK_EQ(frees, 0); Test(false, false, 50000); CHECK_NE(allocates, 0); // default arena calls hooks CHECK_NE(frees, 0); for (int i = 0; i != 16; i++) { bool call_hooks = ((i & 1) == 1); allocates = 0; frees = 0; Test(true, call_hooks, 15000); if (call_hooks) { CHECK_GT(allocates, 5000); // arena calls hooks CHECK_GT(frees, 5000); } else { CHECK_EQ(allocates, 0); // arena doesn't call hooks CHECK_EQ(frees, 0); } } printf("\nPASS\n"); CHECK_EQ(MallocHook::SetNewHook(old_alloc_hook), AllocHook); CHECK_EQ(MallocHook::SetDeleteHook(old_free_hook), FreeHook); return 0; } ================================================ FILE: distro/google-perftools-1.7/src/tests/malloc_extension_c_test.c ================================================ /* Copyright (c) 2009, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Craig Silverstein * * This tests the c shims: malloc_extension_c.h and malloc_hook_c.h. * Mostly, we'll just care that these shims compile under gcc * (*not* g++!) * * NOTE: this is C code, not C++ code! */ #include #include #include /* for size_t */ #include #include #define FAIL(msg) do { \ fprintf(stderr, "FATAL ERROR: %s\n", msg); \ exit(1); \ } while (0) static int g_new_hook_calls = 0; static int g_delete_hook_calls = 0; void TestNewHook(const void* ptr, size_t size) { g_new_hook_calls++; } void TestDeleteHook(const void* ptr) { g_delete_hook_calls++; } void TestMallocHook(void) { /* TODO(csilvers): figure out why we get: * E0100 00:00:00.000000 7383 malloc_hook.cc:244] RAW: google_malloc section is missing, thus InHookCaller is broken! */ #if 0 void* result[5]; if (MallocHook_GetCallerStackTrace(result, sizeof(result)/sizeof(*result), 0) < 2) { /* should have this and main */ FAIL("GetCallerStackTrace failed"); } #endif MallocHook_SetNewHook(&TestNewHook); MallocHook_SetDeleteHook(&TestDeleteHook); free(malloc(10)); free(malloc(20)); if (g_new_hook_calls != 2) { FAIL("Wrong number of calls to the new hook"); } if (g_delete_hook_calls != 2) { FAIL("Wrong number of calls to the delete hook"); } } void TestMallocExtension(void) { int blocks; size_t total; int hist[64]; char buffer[200]; char* x = (char*)malloc(10); MallocExtension_VerifyAllMemory(); MallocExtension_VerifyMallocMemory(x); MallocExtension_MallocMemoryStats(&blocks, &total, hist); MallocExtension_GetStats(buffer, sizeof(buffer)); if (!MallocExtension_GetNumericProperty("generic.current_allocated_bytes", &total)) { FAIL("GetNumericProperty failed for generic.current_allocated_bytes"); } if (total < 10) { FAIL("GetNumericProperty had bad return for generic.current_allocated_bytes"); } if (!MallocExtension_GetNumericProperty("generic.current_allocated_bytes", &total)) { FAIL("GetNumericProperty failed for generic.current_allocated_bytes"); } MallocExtension_MarkThreadIdle(); MallocExtension_MarkThreadBusy(); MallocExtension_ReleaseToSystem(1); MallocExtension_ReleaseFreeMemory(); if (MallocExtension_GetEstimatedAllocatedSize(10) < 10) { FAIL("GetEstimatedAllocatedSize returned a bad value (too small)"); } if (MallocExtension_GetAllocatedSize(x) < 10) { FAIL("GetEstimatedAllocatedSize returned a bad value (too small)"); } free(x); } int main(int argc, char** argv) { TestMallocHook(); TestMallocExtension(); printf("PASS\n"); return 0; } ================================================ FILE: distro/google-perftools-1.7/src/tests/malloc_extension_test.cc ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Craig Silverstein // // Simple test of malloc_extension. Includes test of C shims. #include "config_for_unittests.h" #include #include #include "base/logging.h" #include #include using STL_NAMESPACE::vector; int main(int argc, char** argv) { void* a = malloc(1000); size_t cxx_bytes_used, c_bytes_used; ASSERT_TRUE(MallocExtension::instance()->GetNumericProperty( "generic.current_allocated_bytes", &cxx_bytes_used)); ASSERT_TRUE(MallocExtension_GetNumericProperty( "generic.current_allocated_bytes", &c_bytes_used)); ASSERT_GT(cxx_bytes_used, 1000); ASSERT_EQ(cxx_bytes_used, c_bytes_used); ASSERT_TRUE(MallocExtension::instance()->VerifyAllMemory()); ASSERT_TRUE(MallocExtension_VerifyAllMemory()); ASSERT_GE(MallocExtension::instance()->GetAllocatedSize(a), 1000); // This is just a sanity check. If we allocated too much, tcmalloc is broken ASSERT_LE(MallocExtension::instance()->GetAllocatedSize(a), 5000); ASSERT_GE(MallocExtension::instance()->GetEstimatedAllocatedSize(1000), 1000); for (int i = 0; i < 10; ++i) { void *p = malloc(i); ASSERT_GE(MallocExtension::instance()->GetAllocatedSize(p), MallocExtension::instance()->GetEstimatedAllocatedSize(i)); free(p); } // Check the c-shim version too. ASSERT_GE(MallocExtension_GetAllocatedSize(a), 1000); ASSERT_LE(MallocExtension_GetAllocatedSize(a), 5000); ASSERT_GE(MallocExtension_GetEstimatedAllocatedSize(1000), 1000); free(a); printf("DONE\n"); return 0; } ================================================ FILE: distro/google-perftools-1.7/src/tests/markidle_unittest.cc ================================================ // Copyright (c) 2003, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // MallocExtension::MarkThreadIdle() testing #include #include "config_for_unittests.h" #include "base/logging.h" #include #include "tests/testutil.h" // for RunThread() // Helper routine to do lots of allocations static void TestAllocation() { static const int kNum = 100; void* ptr[kNum]; for (int size = 8; size <= 65536; size*=2) { for (int i = 0; i < kNum; i++) { ptr[i] = malloc(size); } for (int i = 0; i < kNum; i++) { free(ptr[i]); } } } // Routine that does a bunch of MarkThreadIdle() calls in sequence // without any intervening allocations static void MultipleIdleCalls() { for (int i = 0; i < 4; i++) { MallocExtension::instance()->MarkThreadIdle(); } } // Routine that does a bunch of MarkThreadIdle() calls in sequence // with intervening allocations static void MultipleIdleNonIdlePhases() { for (int i = 0; i < 4; i++) { TestAllocation(); MallocExtension::instance()->MarkThreadIdle(); } } // Get current thread cache usage static size_t GetTotalThreadCacheSize() { size_t result; CHECK(MallocExtension::instance()->GetNumericProperty( "tcmalloc.current_total_thread_cache_bytes", &result)); return result; } // Check that MarkThreadIdle() actually reduces the amount // of per-thread memory. static void TestIdleUsage() { const size_t original = GetTotalThreadCacheSize(); TestAllocation(); const size_t post_allocation = GetTotalThreadCacheSize(); CHECK_GT(post_allocation, original); MallocExtension::instance()->MarkThreadIdle(); const size_t post_idle = GetTotalThreadCacheSize(); CHECK_LE(post_idle, original); // Log after testing because logging can allocate heap memory. VLOG(0, "Original usage: %"PRIuS"\n", original); VLOG(0, "Post allocation: %"PRIuS"\n", post_allocation); VLOG(0, "Post idle: %"PRIuS"\n", post_idle); } int main(int argc, char** argv) { RunThread(&TestIdleUsage); RunThread(&TestAllocation); RunThread(&MultipleIdleCalls); RunThread(&MultipleIdleNonIdlePhases); printf("PASS\n"); return 0; } ================================================ FILE: distro/google-perftools-1.7/src/tests/maybe_threads_unittest.sh ================================================ #!/bin/sh # Copyright (c) 2007, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # --- # Author: Craig Silverstein # # maybe_threads.cc was written to allow LD_PRELOAD=libtcmalloc.so to # work even on binaries that were not linked with pthreads. This # unittest tests that, by running low_level_alloc_unittest with an # LD_PRELOAD. (low_level_alloc_unittest was chosen because it doesn't # link in tcmalloc.) # # We assume all the .so files are in the same directory as both # addressmap_unittest and profiler1_unittest. The reason we need # profiler1_unittest is because it's instrumented to show the directory # it's "really" in when run without any args. In practice this will either # be BINDIR, or, when using libtool, BINDIR/.lib. # We expect BINDIR to be set in the environment. # If not, we set them to some reasonable values. BINDIR="${BINDIR:-.}" if [ "x$1" = "x-h" -o "x$1" = "x--help" ]; then echo "USAGE: $0 [unittest dir]" echo " By default, unittest_dir=$BINDIR" exit 1 fi UNITTEST_DIR=${1:-$BINDIR} # Figure out the "real" unittest directory. Also holds the .so files. UNITTEST_DIR=`$UNITTEST_DIR/low_level_alloc_unittest --help 2>&1 \ | awk '{print $2; exit;}' \ | xargs dirname` # Figure out where libtcmalloc lives. It should be in UNITTEST_DIR, # but with libtool it might be in a subdir. if [ -r "$UNITTEST_DIR/libtcmalloc_minimal.so" ]; then LIB_PATH="$UNITTEST_DIR/libtcmalloc_minimal.so" elif [ -r "$UNITTEST_DIR/.libs/libtcmalloc_minimal.so" ]; then LIB_PATH="$UNITTEST_DIR/.libs/libtcmalloc_minimal.so" elif [ -r "$UNITTEST_DIR/libtcmalloc_minimal.dylib" ]; then # for os x LIB_PATH="$UNITTEST_DIR/libtcmalloc_minimal.dylib" elif [ -r "$UNITTEST_DIR/.libs/libtcmalloc_minimal.dylib" ]; then LIB_PATH="$UNITTEST_DIR/.libs/libtcmalloc_minimal.dylib" else echo "Cannot run $0: cannot find libtcmalloc_minimal.so" exit 2 fi LD_PRELOAD="$LIB_PATH" $UNITTEST_DIR/low_level_alloc_unittest ================================================ FILE: distro/google-perftools-1.7/src/tests/memalign_unittest.cc ================================================ // Copyright (c) 2004, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // Check memalign related routines. // // We can't really do a huge amount of checking, but at the very // least, the following code checks that return values are properly // aligned, and that writing into the objects works. #include "config_for_unittests.h" // Complicated ordering requirements. tcmalloc.h defines (indirectly) // _POSIX_C_SOURCE, which it needs so stdlib.h defines posix_memalign. // unistd.h, on the other hand, requires _POSIX_C_SOURCE to be unset, // at least on Mac OS X, in order to define getpagesize. The solution // is to #include unistd.h first. This is safe because unistd.h // doesn't sub-include stdlib.h, so we'll still get posix_memalign // when we #include stdlib.h. Blah. #ifdef HAVE_UNISTD_H #include // for getpagesize() #endif #include "tcmalloc.h" // must come early, to pick up posix_memalign #include // defines posix_memalign #include // for the printf at the end #ifdef HAVE_STDINT_H #include // for uintptr_t #endif #ifdef HAVE_UNISTD_H #include // for getpagesize() #endif #ifdef HAVE_MALLOC_H #include #endif #include "base/basictypes.h" #include "base/logging.h" #include "tests/testutil.h" // Return the next interesting size/delta to check. Returns -1 if no more. static int NextSize(int size) { if (size < 100) { return size+1; } else if (size < 1048576) { // Find next power of two int power = 1; while (power < size) { power <<= 1; } // Yield (power-1, power, power+1) if (size < power-1) { return power-1; } else if (size == power-1) { return power; } else { assert(size == power); return power+1; } } else { return -1; } } // Shortform for cast static uintptr_t Number(void* p) { return reinterpret_cast(p); } // Check alignment static void CheckAlignment(void* p, int align) { if ((Number(p) & (align-1)) != 0) LOG(FATAL, "wrong alignment; wanted 0x%x; got %p\n", align, p); } // Fill a buffer of the specified size with a predetermined pattern static void Fill(void* p, int n, char seed) { unsigned char* buffer = reinterpret_cast(p); for (int i = 0; i < n; i++) { buffer[i] = ((seed + i) & 0xff); } } // Check that the specified buffer has the predetermined pattern // generated by Fill() static bool Valid(const void* p, int n, char seed) { const unsigned char* buffer = reinterpret_cast(p); for (int i = 0; i < n; i++) { if (buffer[i] != ((seed + i) & 0xff)) { return false; } } return true; } int main(int argc, char** argv) { SetTestResourceLimit(); // Try allocating data with a bunch of alignments and sizes for (int a = 1; a < 1048576; a *= 2) { for (int s = 0; s != -1; s = NextSize(s)) { void* ptr = memalign(a, s); CheckAlignment(ptr, a); Fill(ptr, s, 'x'); CHECK(Valid(ptr, s, 'x')); free(ptr); if ((a >= sizeof(void*)) && ((a & (a-1)) == 0)) { CHECK(posix_memalign(&ptr, a, s) == 0); CheckAlignment(ptr, a); Fill(ptr, s, 'y'); CHECK(Valid(ptr, s, 'y')); free(ptr); } } } { // Check various corner cases void* p1 = memalign(1<<20, 1<<19); void* p2 = memalign(1<<19, 1<<19); void* p3 = memalign(1<<21, 1<<19); CheckAlignment(p1, 1<<20); CheckAlignment(p2, 1<<19); CheckAlignment(p3, 1<<21); Fill(p1, 1<<19, 'a'); Fill(p2, 1<<19, 'b'); Fill(p3, 1<<19, 'c'); CHECK(Valid(p1, 1<<19, 'a')); CHECK(Valid(p2, 1<<19, 'b')); CHECK(Valid(p3, 1<<19, 'c')); free(p1); free(p2); free(p3); } { // posix_memalign void* ptr; CHECK(posix_memalign(&ptr, 0, 1) == EINVAL); CHECK(posix_memalign(&ptr, sizeof(void*)/2, 1) == EINVAL); CHECK(posix_memalign(&ptr, sizeof(void*)+1, 1) == EINVAL); CHECK(posix_memalign(&ptr, 4097, 1) == EINVAL); // Grab some memory so that the big allocation below will definitely fail. void* p_small = malloc(4*1048576); CHECK(p_small != NULL); // Make sure overflow is returned as ENOMEM const size_t zero = 0; static const size_t kMinusNTimes = 10; for ( size_t i = 1; i < kMinusNTimes; ++i ) { int r = posix_memalign(&ptr, 1024, zero - i); CHECK(r == ENOMEM); } free(p_small); } const int pagesize = getpagesize(); { // valloc for (int s = 0; s != -1; s = NextSize(s)) { void* p = valloc(s); CheckAlignment(p, pagesize); Fill(p, s, 'v'); CHECK(Valid(p, s, 'v')); free(p); } } { // pvalloc for (int s = 0; s != -1; s = NextSize(s)) { void* p = pvalloc(s); CheckAlignment(p, pagesize); int alloc_needed = ((s + pagesize - 1) / pagesize) * pagesize; Fill(p, alloc_needed, 'x'); CHECK(Valid(p, alloc_needed, 'x')); free(p); } } printf("PASS\n"); return 0; } ================================================ FILE: distro/google-perftools-1.7/src/tests/packed-cache_test.cc ================================================ // Copyright (c) 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Geoff Pike #include #include "base/logging.h" #include "packed-cache-inl.h" static const int kHashbits = PackedCache<64, uint64>::kHashbits; // A basic sanity test. void PackedCacheTest_basic() { PackedCache<32, uint32> cache(0); CHECK_EQ(cache.GetOrDefault(0, 1), 0); cache.Put(0, 17); CHECK(cache.Has(0)); CHECK_EQ(cache.GetOrDefault(0, 1), 17); cache.Put(19, 99); CHECK(cache.Has(0) && cache.Has(19)); CHECK_EQ(cache.GetOrDefault(0, 1), 17); CHECK_EQ(cache.GetOrDefault(19, 1), 99); // Knock <0, 17> out by using a conflicting key. cache.Put(1 << kHashbits, 22); CHECK(!cache.Has(0)); CHECK_EQ(cache.GetOrDefault(0, 1), 1); CHECK_EQ(cache.GetOrDefault(1 << kHashbits, 1), 22); } int main(int argc, char **argv) { PackedCacheTest_basic(); printf("PASS\n"); return 0; } ================================================ FILE: distro/google-perftools-1.7/src/tests/page_heap_test.cc ================================================ // Copyright 2009 Google Inc. All Rights Reserved. // Author: fikes@google.com (Andrew Fikes) #include #include "config_for_unittests.h" #include "base/logging.h" #include "common.h" #include "page_heap.h" namespace { static void CheckStats(const tcmalloc::PageHeap* ph, uint64_t system_pages, uint64_t free_pages, uint64_t unmapped_pages) { tcmalloc::PageHeap::Stats stats = ph->stats(); EXPECT_EQ(system_pages, stats.system_bytes >> kPageShift); EXPECT_EQ(free_pages, stats.free_bytes >> kPageShift); EXPECT_EQ(unmapped_pages, stats.unmapped_bytes >> kPageShift); } static void TestPageHeap_Stats() { tcmalloc::PageHeap* ph = new tcmalloc::PageHeap(); // Empty page heap CheckStats(ph, 0, 0, 0); // Allocate a span 's1' tcmalloc::Span* s1 = ph->New(256); CheckStats(ph, 256, 0, 0); // Split span 's1' into 's1', 's2'. Delete 's2' tcmalloc::Span* s2 = ph->Split(s1, 128); Length s2_len = s2->length; ph->Delete(s2); CheckStats(ph, 256, 128, 0); // Unmap deleted span 's2' EXPECT_EQ(s2_len, ph->ReleaseAtLeastNPages(1)); CheckStats(ph, 256, 0, 128); // Delete span 's1' ph->Delete(s1); CheckStats(ph, 256, 128, 128); delete ph; } } // namespace int main(int argc, char **argv) { TestPageHeap_Stats(); printf("PASS\n"); return 0; } ================================================ FILE: distro/google-perftools-1.7/src/tests/pagemap_unittest.cc ================================================ // Copyright (c) 2003, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat #include "config_for_unittests.h" #include #include #if defined HAVE_STDINT_H #include // to get intptr_t #elif defined HAVE_INTTYPES_H #include // another place intptr_t might be defined #endif #include #include #include "base/logging.h" #include "pagemap.h" using std::vector; static void Permute(vector* elements) { if (elements->empty()) return; const size_t num_elements = elements->size(); for (size_t i = num_elements - 1; i > 0; --i) { const size_t newpos = rand() % (i + 1); const intptr_t tmp = (*elements)[i]; // swap (*elements)[i] = (*elements)[newpos]; (*elements)[newpos] = tmp; } } // Note: we leak memory every time a map is constructed, so do not // create too many maps. // Test specified map type template void TestMap(int limit, bool limit_is_below_the_overflow_boundary) { RAW_LOG(INFO, "Running test with %d iterations...\n", limit); { // Test sequential ensure/assignment Type map(malloc); for (intptr_t i = 0; i < static_cast(limit); i++) { map.Ensure(i, 1); map.set(i, (void*)(i+1)); CHECK_EQ(map.get(i), (void*)(i+1)); } for (intptr_t i = 0; i < static_cast(limit); i++) { CHECK_EQ(map.get(i), (void*)(i+1)); } } { // Test bulk Ensure Type map(malloc); map.Ensure(0, limit); for (intptr_t i = 0; i < static_cast(limit); i++) { map.set(i, (void*)(i+1)); CHECK_EQ(map.get(i), (void*)(i+1)); } for (intptr_t i = 0; i < static_cast(limit); i++) { CHECK_EQ(map.get(i), (void*)(i+1)); } } // Test that we correctly notice overflow { Type map(malloc); CHECK_EQ(map.Ensure(limit, limit+1), limit_is_below_the_overflow_boundary); } { // Test randomized accesses srand(301); // srand isn't great, but it's portable vector elements; for (intptr_t i = 0; i < static_cast(limit); i++) elements.push_back(i); Permute(&elements); Type map(malloc); for (intptr_t i = 0; i < static_cast(limit); i++) { map.Ensure(elements[i], 1); map.set(elements[i], (void*)(elements[i]+1)); CHECK_EQ(map.get(elements[i]), (void*)(elements[i]+1)); } for (intptr_t i = 0; i < static_cast(limit); i++) { CHECK_EQ(map.get(i), (void*)(i+1)); } } } // REQUIRES: BITS==10, i.e., valid range is [0,1023]. // Representations for different types will end up being: // PageMap1: array[1024] // PageMap2: array[32][32] // PageMap3: array[16][16][4] template void TestNext(const char* name) { RAW_LOG(ERROR, "Running NextTest %s\n", name); Type map(malloc); char a, b, c, d, e; // When map is empty CHECK(map.Next(0) == NULL); CHECK(map.Next(5) == NULL); CHECK(map.Next(1<<30) == NULL); // Add a single value map.Ensure(40, 1); map.set(40, &a); CHECK(map.Next(0) == &a); CHECK(map.Next(39) == &a); CHECK(map.Next(40) == &a); CHECK(map.Next(41) == NULL); CHECK(map.Next(1<<30) == NULL); // Add a few values map.Ensure(41, 1); map.Ensure(100, 3); map.set(41, &b); map.set(100, &c); map.set(101, &d); map.set(102, &e); CHECK(map.Next(0) == &a); CHECK(map.Next(39) == &a); CHECK(map.Next(40) == &a); CHECK(map.Next(41) == &b); CHECK(map.Next(42) == &c); CHECK(map.Next(63) == &c); CHECK(map.Next(64) == &c); CHECK(map.Next(65) == &c); CHECK(map.Next(99) == &c); CHECK(map.Next(100) == &c); CHECK(map.Next(101) == &d); CHECK(map.Next(102) == &e); CHECK(map.Next(103) == NULL); } int main(int argc, char** argv) { TestMap< TCMalloc_PageMap1<10> > (100, true); TestMap< TCMalloc_PageMap1<10> > (1 << 10, false); TestMap< TCMalloc_PageMap2<20> > (100, true); TestMap< TCMalloc_PageMap2<20> > (1 << 20, false); TestMap< TCMalloc_PageMap3<20> > (100, true); TestMap< TCMalloc_PageMap3<20> > (1 << 20, false); TestNext< TCMalloc_PageMap1<10> >("PageMap1"); TestNext< TCMalloc_PageMap2<10> >("PageMap2"); TestNext< TCMalloc_PageMap3<10> >("PageMap3"); printf("PASS\n"); return 0; } ================================================ FILE: distro/google-perftools-1.7/src/tests/profile-handler_unittest.cc ================================================ // Copyright 2009 Google Inc. All Rights Reserved. // Author: Nabeel Mian (nabeelmian@google.com) // Chris Demetriou (cgd@google.com) // // This file contains the unit tests for profile-handler.h interface. #include "config.h" #include "profile-handler.h" #include #include #include #include #include "base/logging.h" #include "base/simple_mutex.h" // Some helpful macros for the test class #define TEST_F(cls, fn) void cls :: fn() namespace { // TODO(csilvers): error-checking on the pthreads routines class Thread { public: Thread() : joinable_(false) { } void SetJoinable(bool value) { joinable_ = value; } void Start() { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, joinable_ ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED); pthread_create(&thread_, &attr, &DoRun, this); pthread_attr_destroy(&attr); } void Join() { assert(joinable_); pthread_join(thread_, NULL); } virtual void Run() = 0; private: static void* DoRun(void* cls) { ProfileHandlerRegisterThread(); reinterpret_cast(cls)->Run(); return NULL; } pthread_t thread_; bool joinable_; }; // Sleep interval in nano secs. ITIMER_PROF goes off only afer the specified CPU // time is consumed. Under heavy load this process may no get scheduled in a // timely fashion. Therefore, give enough time (20x of ProfileHandle timer // interval 10ms (100Hz)) for this process to accumulate enought CPU time to get // a profile tick. int kSleepInterval = 200000000; // Sleep interval in nano secs. To ensure that if the timer has expired it is // reset. int kTimerResetInterval = 5000000; // Whether each thread has separate timers. static bool timer_separate_ = false; static int timer_type_ = ITIMER_PROF; static int signal_number_ = SIGPROF; // Delays processing by the specified number of nano seconds. 'delay_ns' // must be less than the number of nano seconds in a second (1000000000). void Delay(int delay_ns) { static const int kNumNSecInSecond = 1000000000; EXPECT_LT(delay_ns, kNumNSecInSecond); struct timespec delay = { 0, delay_ns }; nanosleep(&delay, 0); } // Checks whether the profile timer is enabled for the current thread. bool IsTimerEnabled() { itimerval current_timer; EXPECT_EQ(0, getitimer(timer_type_, ¤t_timer)); if ((current_timer.it_value.tv_sec == 0) && (current_timer.it_value.tv_usec != 0)) { // May be the timer has expired. Sleep for a bit and check again. Delay(kTimerResetInterval); EXPECT_EQ(0, getitimer(timer_type_, ¤t_timer)); } return (current_timer.it_value.tv_sec != 0 || current_timer.it_value.tv_usec != 0); } class VirtualTimerGetterThread : public Thread { public: VirtualTimerGetterThread() { memset(&virtual_timer_, 0, sizeof virtual_timer_); } struct itimerval virtual_timer_; private: void Run() { CHECK_EQ(0, getitimer(ITIMER_VIRTUAL, &virtual_timer_)); } }; // This function checks whether the timers are shared between thread. This // function spawns a thread, so use it carefully when testing thread-dependent // behaviour. static bool threads_have_separate_timers() { struct itimerval new_timer_val; // Enable the virtual timer in the current thread. memset(&new_timer_val, 0, sizeof new_timer_val); new_timer_val.it_value.tv_sec = 1000000; // seconds CHECK_EQ(0, setitimer(ITIMER_VIRTUAL, &new_timer_val, NULL)); // Spawn a thread, get the virtual timer's value there. VirtualTimerGetterThread thread; thread.SetJoinable(true); thread.Start(); thread.Join(); // Disable timer here. memset(&new_timer_val, 0, sizeof new_timer_val); CHECK_EQ(0, setitimer(ITIMER_VIRTUAL, &new_timer_val, NULL)); bool target_timer_enabled = (thread.virtual_timer_.it_value.tv_sec != 0 || thread.virtual_timer_.it_value.tv_usec != 0); if (!target_timer_enabled) { LOG(INFO, "threads have separate timers"); return true; } else { LOG(INFO, "threads have shared timers"); return false; } } // Dummy worker thread to accumulate cpu time. class BusyThread : public Thread { public: BusyThread() : stop_work_(false) { } // Setter/Getters bool stop_work() { MutexLock lock(&mu_); return stop_work_; } void set_stop_work(bool stop_work) { MutexLock lock(&mu_); stop_work_ = stop_work; } private: // Protects stop_work_ below. Mutex mu_; // Whether to stop work? bool stop_work_; // Do work until asked to stop. void Run() { while (!stop_work()) { } // If timers are separate, check that timer is enabled for this thread. EXPECT_TRUE(!timer_separate_ || IsTimerEnabled()); } }; class NullThread : public Thread { private: void Run() { // If timers are separate, check that timer is enabled for this thread. EXPECT_TRUE(!timer_separate_ || IsTimerEnabled()); } }; // Signal handler which tracks the profile timer ticks. static void TickCounter(int sig, siginfo_t* sig_info, void *vuc, void* tick_counter) { int* counter = static_cast(tick_counter); ++(*counter); } // This class tests the profile-handler.h interface. class ProfileHandlerTest { protected: // Determines whether threads have separate timers. static void SetUpTestCase() { timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF); signal_number_ = (getenv("CPUPROFILE_REALTIME") ? SIGALRM : SIGPROF); timer_separate_ = threads_have_separate_timers(); Delay(kTimerResetInterval); } // Sets up the profile timers and SIGPROF/SIGALRM handler in a known state. // It does the following: // 1. Unregisters all the callbacks, stops the timer (if shared) and // clears out timer_sharing state in the ProfileHandler. This clears // out any state left behind by the previous test or during module // initialization when the test program was started. // 2. Spawns two threads which will be registered with the ProfileHandler. // At this time ProfileHandler knows if the timers are shared. // 3. Starts a busy worker thread to accumulate CPU usage. virtual void SetUp() { // Reset the state of ProfileHandler between each test. This unregisters // all callbacks, stops timer (if shared) and clears timer sharing state. ProfileHandlerReset(); EXPECT_EQ(0, GetCallbackCount()); VerifyDisabled(); // ProfileHandler requires at least two threads to be registerd to determine // whether timers are shared. RegisterThread(); RegisterThread(); // Now that two threads are started, verify that the signal handler is // disabled and the timers are correctly enabled/disabled. VerifyDisabled(); // Start worker to accumulate cpu usage. StartWorker(); } virtual void TearDown() { ProfileHandlerReset(); // Stops the worker thread. StopWorker(); } // Starts a no-op thread that gets registered with the ProfileHandler. Waits // for the thread to stop. void RegisterThread() { NullThread t; t.SetJoinable(true); t.Start(); t.Join(); } // Starts a busy worker thread to accumulate cpu time. There should be only // one busy worker running. This is required for the case where there are // separate timers for each thread. void StartWorker() { busy_worker_ = new BusyThread(); busy_worker_->SetJoinable(true); busy_worker_->Start(); // Wait for worker to start up and register with the ProfileHandler. // TODO(nabeelmian) This may not work under very heavy load. Delay(kSleepInterval); } // Stops the worker thread. void StopWorker() { busy_worker_->set_stop_work(true); busy_worker_->Join(); delete busy_worker_; } // Checks whether SIGPROF/SIGALRM signal handler is enabled. bool IsSignalEnabled() { struct sigaction sa; CHECK_EQ(sigaction(signal_number_, NULL, &sa), 0); return ((sa.sa_handler == SIG_IGN) || (sa.sa_handler == SIG_DFL)) ? false : true; } // Gets the number of callbacks registered with the ProfileHandler. uint32 GetCallbackCount() { ProfileHandlerState state; ProfileHandlerGetState(&state); return state.callback_count; } // Gets the current ProfileHandler interrupt count. uint64 GetInterruptCount() { ProfileHandlerState state; ProfileHandlerGetState(&state); return state.interrupts; } // Verifies that a callback is correctly registered and receiving // profile ticks. void VerifyRegistration(const int& tick_counter) { // Check the callback count. EXPECT_GT(GetCallbackCount(), 0); // Check that the profile timer is enabled. EXPECT_TRUE(IsTimerEnabled()); // Check that the signal handler is enabled. EXPECT_TRUE(IsSignalEnabled()); uint64 interrupts_before = GetInterruptCount(); // Sleep for a bit and check that tick counter is making progress. int old_tick_count = tick_counter; Delay(kSleepInterval); int new_tick_count = tick_counter; EXPECT_GT(new_tick_count, old_tick_count); uint64 interrupts_after = GetInterruptCount(); EXPECT_GT(interrupts_after, interrupts_before); } // Verifies that a callback is not receiving profile ticks. void VerifyUnregistration(const int& tick_counter) { // Sleep for a bit and check that tick counter is not making progress. int old_tick_count = tick_counter; Delay(kSleepInterval); int new_tick_count = tick_counter; EXPECT_EQ(old_tick_count, new_tick_count); // If no callbacks, signal handler and shared timer should be disabled. if (GetCallbackCount() == 0) { EXPECT_FALSE(IsSignalEnabled()); if (timer_separate_) { EXPECT_TRUE(IsTimerEnabled()); } else { EXPECT_FALSE(IsTimerEnabled()); } } } // Verifies that the SIGPROF/SIGALRM interrupt handler is disabled and the // timer, if shared, is disabled. Expects the worker to be running. void VerifyDisabled() { // Check that the signal handler is disabled. EXPECT_FALSE(IsSignalEnabled()); // Check that the callback count is 0. EXPECT_EQ(0, GetCallbackCount()); // Check that the timer is disabled if shared, enabled otherwise. if (timer_separate_) { EXPECT_TRUE(IsTimerEnabled()); } else { EXPECT_FALSE(IsTimerEnabled()); } // Verify that the ProfileHandler is not accumulating profile ticks. uint64 interrupts_before = GetInterruptCount(); Delay(kSleepInterval); uint64 interrupts_after = GetInterruptCount(); EXPECT_EQ(interrupts_before, interrupts_after); } // Registers a callback and waits for kTimerResetInterval for timers to get // reset. ProfileHandlerToken* RegisterCallback(void* callback_arg) { ProfileHandlerToken* token = ProfileHandlerRegisterCallback( TickCounter, callback_arg); Delay(kTimerResetInterval); return token; } // Unregisters a callback and waits for kTimerResetInterval for timers to get // reset. void UnregisterCallback(ProfileHandlerToken* token) { ProfileHandlerUnregisterCallback(token); Delay(kTimerResetInterval); } // Busy worker thread to accumulate cpu usage. BusyThread* busy_worker_; private: // The tests to run void RegisterUnregisterCallback(); void MultipleCallbacks(); void Reset(); void RegisterCallbackBeforeThread(); public: #define RUN(test) do { \ printf("Running %s\n", #test); \ ProfileHandlerTest pht; \ pht.SetUp(); \ pht.test(); \ pht.TearDown(); \ } while (0) static int RUN_ALL_TESTS() { SetUpTestCase(); RUN(RegisterUnregisterCallback); RUN(MultipleCallbacks); RUN(Reset); RUN(RegisterCallbackBeforeThread); printf("Done\n"); return 0; } }; // Verifies ProfileHandlerRegisterCallback and // ProfileHandlerUnregisterCallback. TEST_F(ProfileHandlerTest, RegisterUnregisterCallback) { int tick_count = 0; ProfileHandlerToken* token = RegisterCallback(&tick_count); VerifyRegistration(tick_count); UnregisterCallback(token); VerifyUnregistration(tick_count); } // Verifies that multiple callbacks can be registered. TEST_F(ProfileHandlerTest, MultipleCallbacks) { // Register first callback. int first_tick_count; ProfileHandlerToken* token1 = RegisterCallback(&first_tick_count); // Check that callback was registered correctly. VerifyRegistration(first_tick_count); EXPECT_EQ(1, GetCallbackCount()); // Register second callback. int second_tick_count; ProfileHandlerToken* token2 = RegisterCallback(&second_tick_count); // Check that callback was registered correctly. VerifyRegistration(second_tick_count); EXPECT_EQ(2, GetCallbackCount()); // Unregister first callback. UnregisterCallback(token1); VerifyUnregistration(first_tick_count); EXPECT_EQ(1, GetCallbackCount()); // Verify that second callback is still registered. VerifyRegistration(second_tick_count); // Unregister second callback. UnregisterCallback(token2); VerifyUnregistration(second_tick_count); EXPECT_EQ(0, GetCallbackCount()); // Verify that the signal handler and timers are correctly disabled. VerifyDisabled(); } // Verifies ProfileHandlerReset TEST_F(ProfileHandlerTest, Reset) { // Verify that the profile timer interrupt is disabled. VerifyDisabled(); int first_tick_count; RegisterCallback(&first_tick_count); VerifyRegistration(first_tick_count); EXPECT_EQ(1, GetCallbackCount()); // Register second callback. int second_tick_count; RegisterCallback(&second_tick_count); VerifyRegistration(second_tick_count); EXPECT_EQ(2, GetCallbackCount()); // Reset the profile handler and verify that callback were correctly // unregistered and timer/signal are disabled. ProfileHandlerReset(); VerifyUnregistration(first_tick_count); VerifyUnregistration(second_tick_count); VerifyDisabled(); } // Verifies that ProfileHandler correctly handles a case where a callback was // registered before the second thread started. TEST_F(ProfileHandlerTest, RegisterCallbackBeforeThread) { // Stop the worker. StopWorker(); // Unregister all existing callbacks, stop the timer (if shared), disable // the signal handler and reset the timer sharing state in the Profile // Handler. ProfileHandlerReset(); EXPECT_EQ(0, GetCallbackCount()); VerifyDisabled(); // Start the worker. At this time ProfileHandler doesn't know if timers are // shared as only one thread has registered so far. StartWorker(); // Register a callback and check that profile ticks are being delivered. int tick_count; RegisterCallback(&tick_count); EXPECT_EQ(1, GetCallbackCount()); VerifyRegistration(tick_count); // Register a second thread and verify that timer and signal handler are // correctly enabled. RegisterThread(); EXPECT_EQ(1, GetCallbackCount()); EXPECT_TRUE(IsTimerEnabled()); EXPECT_TRUE(IsSignalEnabled()); } } // namespace int main(int argc, char** argv) { return ProfileHandlerTest::RUN_ALL_TESTS(); } ================================================ FILE: distro/google-perftools-1.7/src/tests/profiledata_unittest.cc ================================================ // Copyright (c) 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // --- // Author: Chris Demetriou // // This file contains the unit tests for the ProfileData class. #if defined HAVE_STDINT_H #include // to get uintptr_t #elif defined HAVE_INTTYPES_H #include // another place uintptr_t might be defined #endif #include #include #include #include #include #include "profiledata.h" #include "base/commandlineflags.h" #include "base/logging.h" using std::string; // Some helpful macros for the test class #define TEST_F(cls, fn) void cls :: fn() namespace { template class scoped_array { public: scoped_array(T* data) : data_(data) { } ~scoped_array() { delete[] data_; } T* get() { return data_; } T& operator[](int i) { return data_[i]; } private: T* const data_; }; // Re-runs fn until it doesn't cause EINTR. #define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR) // Read up to "count" bytes from file descriptor "fd" into the buffer // starting at "buf" while handling short reads and EINTR. On // success, return the number of bytes read. Otherwise, return -1. static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) { CHECK_GE(fd, 0); char *buf0 = reinterpret_cast(buf); ssize_t num_bytes = 0; while (num_bytes < count) { ssize_t len; NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes)); if (len < 0) { // There was an error other than EINTR. return -1; } if (len == 0) { // Reached EOF. break; } num_bytes += len; } CHECK(num_bytes <= count); return num_bytes; } // Thin wrapper around a file descriptor so that the file descriptor // gets closed for sure. struct FileDescriptor { const int fd_; explicit FileDescriptor(int fd) : fd_(fd) {} ~FileDescriptor() { if (fd_ >= 0) { NO_INTR(close(fd_)); } } int get() { return fd_; } }; // must be the same as with ProfileData::Slot. typedef uintptr_t ProfileDataSlot; // Quick and dirty function to make a number into a void* for use in a // sample. inline void* V(intptr_t x) { return reinterpret_cast(x); } // String returned by ProfileDataChecker helper functions to indicate success. const char kNoError[] = ""; class ProfileDataChecker { public: ProfileDataChecker() { const char* tmpdir = getenv("TMPDIR"); if (tmpdir == NULL) tmpdir = "/tmp"; mkdir(tmpdir, 0755); // if necessary filename_ = string(tmpdir) + "/profiledata_unittest.tmp"; } string filename() const { return filename_; } // Checks the first 'num_slots' profile data slots in the file // against the data pointed to by 'slots'. Returns kNoError if the // data matched, otherwise returns an indication of the cause of the // mismatch. string Check(const ProfileDataSlot* slots, int num_slots) { return CheckWithSkips(slots, num_slots, NULL, 0); } // Checks the first 'num_slots' profile data slots in the file // against the data pointed to by 'slots', skipping over entries // described by 'skips' and 'num_skips'. // // 'skips' must be a sorted list of (0-based) slot numbers to be // skipped, of length 'num_skips'. Note that 'num_slots' includes // any skipped slots, i.e., the first 'num_slots' profile data slots // will be considered, but some may be skipped. // // Returns kNoError if the data matched, otherwise returns an // indication of the cause of the mismatch. string CheckWithSkips(const ProfileDataSlot* slots, int num_slots, const int* skips, int num_skips); // Validate that a profile is correctly formed. The profile is // assumed to have been created by the same kind of binary (e.g., // same slot size, same endian, etc.) as is validating the profile. // // Returns kNoError if the profile appears valid, otherwise returns // an indication of the problem with the profile. string ValidateProfile(); private: string filename_; }; string ProfileDataChecker::CheckWithSkips(const ProfileDataSlot* slots, int num_slots, const int* skips, int num_skips) { FileDescriptor fd(open(filename_.c_str(), O_RDONLY)); if (fd.get() < 0) return "file open error"; scoped_array filedata(new ProfileDataSlot[num_slots]); size_t expected_bytes = num_slots * sizeof filedata[0]; ssize_t bytes_read = ReadPersistent(fd.get(), filedata.get(), expected_bytes); if (expected_bytes != bytes_read) return "file too small"; for (int i = 0; i < num_slots; i++) { if (num_skips > 0 && *skips == i) { num_skips--; skips++; continue; } if (slots[i] != filedata[i]) return "data mismatch"; } return kNoError; } string ProfileDataChecker::ValidateProfile() { FileDescriptor fd(open(filename_.c_str(), O_RDONLY)); if (fd.get() < 0) return "file open error"; struct stat statbuf; if (fstat(fd.get(), &statbuf) != 0) return "fstat error"; if (statbuf.st_size != static_cast(statbuf.st_size)) return "file impossibly large"; ssize_t filesize = statbuf.st_size; scoped_array filedata(new char[filesize]); if (ReadPersistent(fd.get(), filedata.get(), filesize) != filesize) return "read of whole file failed"; // Must have enough data for the header and the trailer. if (filesize < (5 + 3) * sizeof(ProfileDataSlot)) return "not enough data in profile for header + trailer"; // Check the header if (reinterpret_cast(filedata.get())[0] != 0) return "error in header: non-zero count"; if (reinterpret_cast(filedata.get())[1] != 3) return "error in header: num_slots != 3"; if (reinterpret_cast(filedata.get())[2] != 0) return "error in header: non-zero format version"; // Period (slot 3) can have any value. if (reinterpret_cast(filedata.get())[4] != 0) return "error in header: non-zero padding value"; ssize_t cur_offset = 5 * sizeof(ProfileDataSlot); // While there are samples, skip them. Each sample consists of // at least three slots. bool seen_trailer = false; while (!seen_trailer) { if (cur_offset > filesize - 3 * sizeof(ProfileDataSlot)) return "truncated sample header"; ProfileDataSlot* sample = reinterpret_cast(filedata.get() + cur_offset); ProfileDataSlot slots_this_sample = 2 + sample[1]; ssize_t size_this_sample = slots_this_sample * sizeof(ProfileDataSlot); if (cur_offset > filesize - size_this_sample) return "truncated sample"; if (sample[0] == 0 && sample[1] == 1 && sample[2] == 0) { seen_trailer = true; } else { if (sample[0] < 1) return "error in sample: sample count < 1"; if (sample[1] < 1) return "error in sample: num_pcs < 1"; for (int i = 2; i < slots_this_sample; i++) { if (sample[i] == 0) return "error in sample: NULL PC"; } } cur_offset += size_this_sample; } // There must be at least one line in the (text) list of mapped objects, // and it must be terminated by a newline. Note, the use of newline // here and below Might not be reasonable on non-UNIX systems. if (cur_offset >= filesize) return "no list of mapped objects"; if (filedata[filesize - 1] != '\n') return "profile did not end with a complete line"; while (cur_offset < filesize) { char* line_start = filedata.get() + cur_offset; // Find the end of the line, and replace it with a NUL for easier // scanning. char* line_end = strchr(line_start, '\n'); *line_end = '\0'; // Advance past any leading space. It's allowed in some lines, // but not in others. bool has_leading_space = false; char* line_cur = line_start; while (*line_cur == ' ') { has_leading_space = true; line_cur++; } bool found_match = false; // Check for build lines. if (!found_match) { found_match = (strncmp(line_cur, "build=", 6) == 0); // Anything may follow "build=", and leading space is allowed. } // A line from ProcMapsIterator::FormatLine, of the form: // // 40000000-40015000 r-xp 00000000 03:01 12845071 /lib/ld-2.3.2.so // // Leading space is not allowed. The filename may be omitted or // may consist of multiple words, so we scan only up to the // space before the filename. if (!found_match) { int chars_scanned = -1; sscanf(line_cur, "%*x-%*x %*c%*c%*c%*c %*x %*x:%*x %*d %n", &chars_scanned); found_match = (chars_scanned > 0 && !has_leading_space); } // A line from DumpAddressMap, of the form: // // 40000000-40015000: /lib/ld-2.3.2.so // // Leading space is allowed. The filename may be omitted or may // consist of multiple words, so we scan only up to the space // before the filename. if (!found_match) { int chars_scanned = -1; sscanf(line_cur, "%*x-%*x: %n", &chars_scanned); found_match = (chars_scanned > 0); } if (!found_match) return "unrecognized line in text section"; cur_offset += (line_end - line_start) + 1; } return kNoError; } class ProfileDataTest { protected: void ExpectStopped() { EXPECT_FALSE(collector_.enabled()); } void ExpectRunningSamples(int samples) { ProfileData::State state; collector_.GetCurrentState(&state); EXPECT_TRUE(state.enabled); EXPECT_EQ(samples, state.samples_gathered); } void ExpectSameState(const ProfileData::State& before, const ProfileData::State& after) { EXPECT_EQ(before.enabled, after.enabled); EXPECT_EQ(before.samples_gathered, after.samples_gathered); EXPECT_EQ(before.start_time, after.start_time); EXPECT_STREQ(before.profile_name, after.profile_name); } ProfileData collector_; ProfileDataChecker checker_; private: // The tests to run void OpsWhenStopped(); void StartStopEmpty(); void StartStopNoOptionsEmpty(); void StartWhenStarted(); void StartStopEmpty2(); void CollectOne(); void CollectTwoMatching(); void CollectTwoFlush(); void StartResetRestart(); public: #define RUN(test) do { \ printf("Running %s\n", #test); \ ProfileDataTest pdt; \ pdt.test(); \ } while (0) static int RUN_ALL_TESTS() { RUN(OpsWhenStopped); RUN(StartStopEmpty); RUN(StartWhenStarted); RUN(StartStopEmpty2); RUN(CollectOne); RUN(CollectTwoMatching); RUN(CollectTwoFlush); RUN(StartResetRestart); return 0; } }; // Check that various operations are safe when stopped. TEST_F(ProfileDataTest, OpsWhenStopped) { ExpectStopped(); EXPECT_FALSE(collector_.enabled()); // Verify that state is disabled, all-empty/all-0 ProfileData::State state_before; collector_.GetCurrentState(&state_before); EXPECT_FALSE(state_before.enabled); EXPECT_EQ(0, state_before.samples_gathered); EXPECT_EQ(0, state_before.start_time); EXPECT_STREQ("", state_before.profile_name); // Safe to call stop again. collector_.Stop(); // Safe to call FlushTable. collector_.FlushTable(); // Safe to call Add. const void *trace[] = { V(100), V(101), V(102), V(103), V(104) }; collector_.Add(arraysize(trace), trace); ProfileData::State state_after; collector_.GetCurrentState(&state_after); ExpectSameState(state_before, state_after); } // Start and Stop, collecting no samples. Verify output contents. TEST_F(ProfileDataTest, StartStopEmpty) { const int frequency = 1; ProfileDataSlot slots[] = { 0, 3, 0, 1000000 / frequency, 0, // binary header 0, 1, 0 // binary trailer }; ExpectStopped(); ProfileData::Options options; options.set_frequency(frequency); EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options)); ExpectRunningSamples(0); collector_.Stop(); ExpectStopped(); EXPECT_EQ(kNoError, checker_.ValidateProfile()); EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots))); } // Start and Stop with no options, collecting no samples. Verify // output contents. TEST_F(ProfileDataTest, StartStopNoOptionsEmpty) { // We're not requesting a specific period, implementation can do // whatever it likes. ProfileDataSlot slots[] = { 0, 3, 0, 0 /* skipped */, 0, // binary header 0, 1, 0 // binary trailer }; int slots_to_skip[] = { 3 }; ExpectStopped(); EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), ProfileData::Options())); ExpectRunningSamples(0); collector_.Stop(); ExpectStopped(); EXPECT_EQ(kNoError, checker_.ValidateProfile()); EXPECT_EQ(kNoError, checker_.CheckWithSkips(slots, arraysize(slots), slots_to_skip, arraysize(slots_to_skip))); } // Start after already started. Should return false and not impact // collected data or state. TEST_F(ProfileDataTest, StartWhenStarted) { const int frequency = 1; ProfileDataSlot slots[] = { 0, 3, 0, 1000000 / frequency, 0, // binary header 0, 1, 0 // binary trailer }; ProfileData::Options options; options.set_frequency(frequency); EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options)); ProfileData::State state_before; collector_.GetCurrentState(&state_before); options.set_frequency(frequency * 2); CHECK(!collector_.Start("foobar", options)); ProfileData::State state_after; collector_.GetCurrentState(&state_after); ExpectSameState(state_before, state_after); collector_.Stop(); ExpectStopped(); EXPECT_EQ(kNoError, checker_.ValidateProfile()); EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots))); } // Like StartStopEmpty, but uses a different file name and frequency. TEST_F(ProfileDataTest, StartStopEmpty2) { const int frequency = 2; ProfileDataSlot slots[] = { 0, 3, 0, 1000000 / frequency, 0, // binary header 0, 1, 0 // binary trailer }; ExpectStopped(); ProfileData::Options options; options.set_frequency(frequency); EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options)); ExpectRunningSamples(0); collector_.Stop(); ExpectStopped(); EXPECT_EQ(kNoError, checker_.ValidateProfile()); EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots))); } TEST_F(ProfileDataTest, CollectOne) { const int frequency = 2; ProfileDataSlot slots[] = { 0, 3, 0, 1000000 / frequency, 0, // binary header 1, 5, 100, 101, 102, 103, 104, // our sample 0, 1, 0 // binary trailer }; ExpectStopped(); ProfileData::Options options; options.set_frequency(frequency); EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options)); ExpectRunningSamples(0); const void *trace[] = { V(100), V(101), V(102), V(103), V(104) }; collector_.Add(arraysize(trace), trace); ExpectRunningSamples(1); collector_.Stop(); ExpectStopped(); EXPECT_EQ(kNoError, checker_.ValidateProfile()); EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots))); } TEST_F(ProfileDataTest, CollectTwoMatching) { const int frequency = 2; ProfileDataSlot slots[] = { 0, 3, 0, 1000000 / frequency, 0, // binary header 2, 5, 100, 201, 302, 403, 504, // our two samples 0, 1, 0 // binary trailer }; ExpectStopped(); ProfileData::Options options; options.set_frequency(frequency); EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options)); ExpectRunningSamples(0); for (int i = 0; i < 2; ++i) { const void *trace[] = { V(100), V(201), V(302), V(403), V(504) }; collector_.Add(arraysize(trace), trace); ExpectRunningSamples(i + 1); } collector_.Stop(); ExpectStopped(); EXPECT_EQ(kNoError, checker_.ValidateProfile()); EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots))); } TEST_F(ProfileDataTest, CollectTwoFlush) { const int frequency = 2; ProfileDataSlot slots[] = { 0, 3, 0, 1000000 / frequency, 0, // binary header 1, 5, 100, 201, 302, 403, 504, // first sample (flushed) 1, 5, 100, 201, 302, 403, 504, // second identical sample 0, 1, 0 // binary trailer }; ExpectStopped(); ProfileData::Options options; options.set_frequency(frequency); EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options)); ExpectRunningSamples(0); const void *trace[] = { V(100), V(201), V(302), V(403), V(504) }; collector_.Add(arraysize(trace), trace); ExpectRunningSamples(1); collector_.FlushTable(); collector_.Add(arraysize(trace), trace); ExpectRunningSamples(2); collector_.Stop(); ExpectStopped(); EXPECT_EQ(kNoError, checker_.ValidateProfile()); EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots))); } // Start then reset, verify that the result is *not* a valid profile. // Then start again and make sure the result is OK. TEST_F(ProfileDataTest, StartResetRestart) { ExpectStopped(); ProfileData::Options options; options.set_frequency(1); EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options)); ExpectRunningSamples(0); collector_.Reset(); ExpectStopped(); // We expect the resulting file to be empty. This is a minimal test // of ValidateProfile. EXPECT_NE(kNoError, checker_.ValidateProfile()); struct stat statbuf; EXPECT_EQ(0, stat(checker_.filename().c_str(), &statbuf)); EXPECT_EQ(0, statbuf.st_size); const int frequency = 2; // Different frequency than used above. ProfileDataSlot slots[] = { 0, 3, 0, 1000000 / frequency, 0, // binary header 0, 1, 0 // binary trailer }; options.set_frequency(frequency); EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options)); ExpectRunningSamples(0); collector_.Stop(); ExpectStopped(); EXPECT_EQ(kNoError, checker_.ValidateProfile()); EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots))); } } // namespace int main(int argc, char** argv) { int rc = ProfileDataTest::RUN_ALL_TESTS(); printf("%s\n", rc == 0 ? "PASS" : "FAIL"); return rc; } ================================================ FILE: distro/google-perftools-1.7/src/tests/profiler_unittest.cc ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Craig Silverstein // // Does some simple arithmetic and a few libc routines, so we can profile it. // Define WITH_THREADS to add pthread functionality as well (otherwise, btw, // the num_threads argument to this program is ingored). #include "config_for_unittests.h" #include #include #ifdef HAVE_UNISTD_H #include // for fork() #endif #include // for wait() #include "google/profiler.h" #include "base/simple_mutex.h" #include "tests/testutil.h" static int result = 0; static int g_iters = 0; // argv[1] Mutex mutex(Mutex::LINKER_INITIALIZED); static void test_other_thread() { #ifndef NO_THREADS ProfilerRegisterThread(); int i, m; char b[128]; MutexLock ml(&mutex); for (m = 0; m < 1000000; ++m) { // run millions of times for (i = 0; i < g_iters; ++i ) { result ^= i; } snprintf(b, sizeof(b), "%d", result); // get some libc action } #endif } static void test_main_thread() { int i, m; char b[128]; MutexLock ml(&mutex); for (m = 0; m < 1000000; ++m) { // run millions of times for (i = 0; i < g_iters; ++i ) { result ^= i; } snprintf(b, sizeof(b), "%d", result); // get some libc action } } int main(int argc, char** argv) { if ( argc <= 1 ) { fprintf(stderr, "USAGE: %s [num_threads] [filename]\n", argv[0]); fprintf(stderr, " iters: How many million times to run the XOR test.\n"); fprintf(stderr, " num_threads: how many concurrent threads.\n"); fprintf(stderr, " 0 or 1 for single-threaded mode,\n"); fprintf(stderr, " -# to fork instead of thread.\n"); fprintf(stderr, " filename: The name of the output profile.\n"); fprintf(stderr, (" If you don't specify, set CPUPROFILE " "in the environment instead!\n")); return 1; } g_iters = atoi(argv[1]); int num_threads = 1; const char* filename = NULL; if (argc > 2) { num_threads = atoi(argv[2]); } if (argc > 3) { filename = argv[3]; } if (filename) { ProfilerStart(filename); } test_main_thread(); ProfilerFlush(); // just because we can // The other threads, if any, will run only half as long as the main thread RunManyThreads(test_other_thread, num_threads); // Or maybe they asked to fork. The fork test is only interesting // when we use CPUPROFILE to name, so check for that #ifdef HAVE_UNISTD_H for (; num_threads < 0; ++num_threads) { // - to fork if (filename) { printf("FORK test only makes sense when no filename is specified.\n"); return 2; } switch (fork()) { case -1: printf("FORK failed!\n"); return 1; case 0: // child return execl(argv[0], argv[0], argv[1], NULL); default: wait(NULL); // we'll let the kids run one at a time } } #endif test_main_thread(); if (filename) { ProfilerStop(); } return 0; } ================================================ FILE: distro/google-perftools-1.7/src/tests/profiler_unittest.sh ================================================ #!/bin/sh # Copyright (c) 2005, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # --- # Author: Craig Silverstein # # Runs the 4 profiler unittests and makes sure their profiles look # appropriate. We expect two commandline args, as described below. # # We run under the assumption that if $PROFILER1 is run with no # arguments, it prints a usage line of the form # USAGE: [...] # # This is because libtool sometimes turns the 'executable' into a # shell script which runs an actual binary somewhere else. # We expect BINDIR and PPROF_PATH to be set in the environment. # If not, we set them to some reasonable values BINDIR="${BINDIR:-.}" PPROF_PATH="${PPROF_PATH:-$BINDIR/src/pprof}" if [ "x$1" = "x-h" -o "x$1" = "x--help" ]; then echo "USAGE: $0 [unittest dir] [path to pprof]" echo " By default, unittest_dir=$BINDIR, pprof_path=$PPROF_PATH" exit 1 fi TMPDIR=/tmp/profile_info UNITTEST_DIR=${1:-$BINDIR} PPROF=${2:-$PPROF_PATH} # We test the sliding-window functionality of the cpu-profile reader # by using a small stride, forcing lots of reads. PPROF_FLAGS="--test_stride=128" PROFILER1="$UNITTEST_DIR/profiler1_unittest" PROFILER2="$UNITTEST_DIR/profiler2_unittest" PROFILER3="$UNITTEST_DIR/profiler3_unittest" PROFILER4="$UNITTEST_DIR/profiler4_unittest" # Unfortunately, for us, libtool can replace executables with a shell # script that does some work before calling the 'real' executable # under a different name. We need the 'real' executable name to run # pprof on it. We've constructed all the binaries used in this # unittest so when they are called with no arguments, they report # their argv[0], which is the real binary name. Realname() { "$1" 2>&1 | awk '{print $2; exit;}' } PROFILER1_REALNAME=`Realname "$PROFILER1"` PROFILER2_REALNAME=`Realname "$PROFILER2"` PROFILER3_REALNAME=`Realname "$PROFILER3"` PROFILER4_REALNAME=`Realname "$PROFILER4"` # It's meaningful to the profiler, so make sure we know its state unset CPUPROFILE rm -rf "$TMPDIR" mkdir "$TMPDIR" || exit 2 num_failures=0 RegisterFailure() { num_failures=`expr $num_failures + 1` } # Takes two filenames representing profiles, with their executable scripts, # and a multiplier, and verifies that the 'contentful' functions in # each profile take the same time (possibly scaled by the given # multiplier). It used to be "same" meant within 50%, after adding an # noise-reducing X units to each value. But even that would often # spuriously fail, so now it's "both non-zero". We're pretty forgiving. VerifySimilar() { prof1="$TMPDIR/$1" exec1="$2" prof2="$TMPDIR/$3" exec2="$4" mult="$5" # We are careful not to put exec1 and exec2 in quotes, because if # they are the empty string, it means we want to use the 1-arg # version of pprof. mthread1=`"$PPROF" $PPROF_FLAGS $exec1 "$prof1" | grep test_main_thread | awk '{print $1}'` mthread2=`"$PPROF" $PPROF_FLAGS $exec2 "$prof2" | grep test_main_thread | awk '{print $1}'` mthread1_plus=`expr $mthread1 + 5` mthread2_plus=`expr $mthread2 + 5` if [ -z "$mthread1" ] || [ -z "$mthread2" ] || \ [ "$mthread1" -le 0 -o "$mthread2" -le 0 ] # || [ `expr $mthread1_plus \* $mult` -gt `expr $mthread2_plus \* 2` -o \ # `expr $mthread1_plus \* $mult \* 2` -lt `expr $mthread2_plus` ] then echo echo ">>> profile on $exec1 vs $exec2 with multiplier $mult failed:" echo "Actual times (in profiling units) were '$mthread1' vs. '$mthread2'" echo RegisterFailure fi } # Takes two filenames representing profiles, and optionally their # executable scripts (these may be empty if the profiles include # symbols), and verifies that the two profiles are identical. VerifyIdentical() { prof1="$TMPDIR/$1" exec1="$2" prof2="$TMPDIR/$3" exec2="$4" # We are careful not to put exec1 and exec2 in quotes, because if # they are the empty string, it means we want to use the 1-arg # version of pprof. "$PPROF" $PPROF_FLAGS $exec1 "$prof1" > "$TMPDIR/out1" "$PPROF" $PPROF_FLAGS $exec2 "$prof2" > "$TMPDIR/out2" diff=`diff "$TMPDIR/out1" "$TMPDIR/out2"` if [ ! -z "$diff" ]; then echo echo ">>> profile doesn't match, args: $exec1 $prof1 vs. $exec2 $prof2" echo ">>> Diff:" echo "$diff" echo RegisterFailure fi } # Takes a filename representing a profile, with its executable, # and a multiplier, and verifies that the main-thread function takes # the same amount of time as the other-threads function (possibly scaled # by the given multiplier). Figuring out the multiplier can be tricky, # since by design the main thread runs twice as long as each of the # 'other' threads! It used to be "same" meant within 50%, after adding an # noise-reducing X units to each value. But even that would often # spuriously fail, so now it's "both non-zero". We're pretty forgiving. VerifyAcrossThreads() { prof1="$TMPDIR/$1" # We need to run the script with no args to get the actual exe name exec1="$2" mult="$3" # We are careful not to put exec1 in quotes, because if it is the # empty string, it means we want to use the 1-arg version of pprof. mthread=`$PPROF $PPROF_FLAGS $exec1 "$prof1" | grep test_main_thread | awk '{print $1}'` othread=`$PPROF $PPROF_FLAGS $exec1 "$prof1" | grep test_other_thread | awk '{print $1}'` if [ -z "$mthread" ] || [ -z "$othread" ] || \ [ "$mthread" -le 0 -o "$othread" -le 0 ] # || [ `expr $mthread \* $mult \* 3` -gt `expr $othread \* 10` -o \ # `expr $mthread \* $mult \* 10` -lt `expr $othread \* 3` ] then echo echo ">>> profile on $exec1 (main vs thread) with multiplier $mult failed:" echo "Actual times (in profiling units) were '$mthread' vs. '$othread'" echo RegisterFailure fi } echo echo ">>> WARNING <<<" echo "This test looks at timing information to determine correctness." echo "If your system is loaded, the test may spuriously fail." echo "If the test does fail with an 'Actual times' error, try running again." echo # profiler1 is a non-threaded version "$PROFILER1" 50 1 "$TMPDIR/p1" || RegisterFailure "$PROFILER1" 100 1 "$TMPDIR/p2" || RegisterFailure VerifySimilar p1 "$PROFILER1_REALNAME" p2 "$PROFILER1_REALNAME" 2 # Verify the same thing works if we statically link "$PROFILER2" 50 1 "$TMPDIR/p3" || RegisterFailure "$PROFILER2" 100 1 "$TMPDIR/p4" || RegisterFailure VerifySimilar p3 "$PROFILER2_REALNAME" p4 "$PROFILER2_REALNAME" 2 # Verify the same thing works if we specify via CPUPROFILE CPUPROFILE="$TMPDIR/p5" "$PROFILER2" 50 || RegisterFailure CPUPROFILE="$TMPDIR/p6" "$PROFILER2" 100 || RegisterFailure VerifySimilar p5 "$PROFILER2_REALNAME" p6 "$PROFILER2_REALNAME" 2 CPUPROFILE="$TMPDIR/p5b" "$PROFILER3" 30 || RegisterFailure CPUPROFILE="$TMPDIR/p5c" "$PROFILER3" 60 || RegisterFailure VerifySimilar p5b "$PROFILER3_REALNAME" p5c "$PROFILER3_REALNAME" 2 # Now try what happens when we use threads "$PROFILER3" 30 2 "$TMPDIR/p7" || RegisterFailure "$PROFILER3" 60 2 "$TMPDIR/p8" || RegisterFailure VerifySimilar p7 "$PROFILER3_REALNAME" p8 "$PROFILER3_REALNAME" 2 "$PROFILER4" 30 2 "$TMPDIR/p9" || RegisterFailure "$PROFILER4" 60 2 "$TMPDIR/p10" || RegisterFailure VerifySimilar p9 "$PROFILER4_REALNAME" p10 "$PROFILER4_REALNAME" 2 # More threads! "$PROFILER4" 25 3 "$TMPDIR/p9" || RegisterFailure "$PROFILER4" 50 3 "$TMPDIR/p10" || RegisterFailure VerifySimilar p9 "$PROFILER4_REALNAME" p10 "$PROFILER4_REALNAME" 2 # Compare how much time the main thread takes compared to the other threads # Recall the main thread runs twice as long as the other threads, by design. "$PROFILER4" 20 4 "$TMPDIR/p11" || RegisterFailure VerifyAcrossThreads p11 "$PROFILER4_REALNAME" 2 # Test symbol save and restore "$PROFILER1" 50 1 "$TMPDIR/p12" || RegisterFailure "$PPROF" $PPROF_FLAGS "$PROFILER1_REALNAME" "$TMPDIR/p12" --raw \ >"$TMPDIR/p13" 2>/dev/null || RegisterFailure VerifyIdentical p12 "$PROFILER1_REALNAME" p13 "" || RegisterFailure "$PROFILER3" 30 2 "$TMPDIR/p14" || RegisterFailure "$PPROF" $PPROF_FLAGS "$PROFILER3_REALNAME" "$TMPDIR/p14" --raw \ >"$TMPDIR/p15" 2>/dev/null || RegisterFailure VerifyIdentical p14 "$PROFILER3_REALNAME" p15 "" || RegisterFailure # Test using ITIMER_REAL instead of ITIMER_PROF. env CPUPROFILE_REALTIME=1 "$PROFILER3" 30 2 "$TMPDIR/p16" || RegisterFailure env CPUPROFILE_REALTIME=1 "$PROFILER3" 60 2 "$TMPDIR/p17" || RegisterFailure VerifySimilar p16 "$PROFILER3_REALNAME" p17 "$PROFILER3_REALNAME" 2 # Make sure that when we have a process with a fork, the profiles don't # clobber each other CPUPROFILE="$TMPDIR/pfork" "$PROFILER1" 1 -2 || RegisterFailure n=`ls $TMPDIR/pfork* | wc -l` if [ $n != 3 ]; then echo "FORK test FAILED: expected 3 profiles (for main + 2 children), found $n" num_failures=`expr $num_failures + 1` fi rm -rf "$TMPDIR" # clean up echo "Tests finished with $num_failures failures" exit $num_failures ================================================ FILE: distro/google-perftools-1.7/src/tests/raw_printer_test.cc ================================================ // Copyright 2009 Google Inc. All Rights Reserved. // Author: sanjay@google.com (Sanjay Ghemawat) #include "raw_printer.h" #include #include #include "base/logging.h" using std::string; #define TEST(a, b) void TEST_##a##_##b() #define RUN_TEST(a, b) TEST_##a##_##b() TEST(RawPrinter, Empty) { char buffer[1]; base::RawPrinter printer(buffer, arraysize(buffer)); CHECK_EQ(0, printer.length()); CHECK_EQ(string(""), buffer); CHECK_EQ(0, printer.space_left()); printer.Printf("foo"); CHECK_EQ(string(""), string(buffer)); CHECK_EQ(0, printer.length()); CHECK_EQ(0, printer.space_left()); } TEST(RawPrinter, PartiallyFilled) { char buffer[100]; base::RawPrinter printer(buffer, arraysize(buffer)); printer.Printf("%s %s", "hello", "world"); CHECK_EQ(string("hello world"), string(buffer)); CHECK_EQ(11, printer.length()); CHECK_LT(0, printer.space_left()); } TEST(RawPrinter, Truncated) { char buffer[3]; base::RawPrinter printer(buffer, arraysize(buffer)); printer.Printf("%d", 12345678); CHECK_EQ(string("12"), string(buffer)); CHECK_EQ(2, printer.length()); CHECK_EQ(0, printer.space_left()); } TEST(RawPrinter, ExactlyFilled) { char buffer[12]; base::RawPrinter printer(buffer, arraysize(buffer)); printer.Printf("%s %s", "hello", "world"); CHECK_EQ(string("hello world"), string(buffer)); CHECK_EQ(11, printer.length()); CHECK_EQ(0, printer.space_left()); } int main(int argc, char **argv) { RUN_TEST(RawPrinter, Empty); RUN_TEST(RawPrinter, PartiallyFilled); RUN_TEST(RawPrinter, Truncated); RUN_TEST(RawPrinter, ExactlyFilled); printf("PASS\n"); return 0; // 0 means success } ================================================ FILE: distro/google-perftools-1.7/src/tests/realloc_unittest.cc ================================================ // Copyright (c) 2004, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // Test realloc() functionality #include "config_for_unittests.h" #include #include #include // for min() #include "base/logging.h" using std::min; // Fill a buffer of the specified size with a predetermined pattern static void Fill(unsigned char* buffer, int n) { for (int i = 0; i < n; i++) { buffer[i] = (i & 0xff); } } // Check that the specified buffer has the predetermined pattern // generated by Fill() static bool Valid(unsigned char* buffer, int n) { for (int i = 0; i < n; i++) { if (buffer[i] != (i & 0xff)) { return false; } } return true; } // Return the next interesting size/delta to check. Returns -1 if no more. static int NextSize(int size) { if (size < 100) { return size+1; } else if (size < 100000) { // Find next power of two int power = 1; while (power < size) { power <<= 1; } // Yield (power-1, power, power+1) if (size < power-1) { return power-1; } else if (size == power-1) { return power; } else { assert(size == power); return power+1; } } else { return -1; } } int main(int argc, char** argv) { for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) { for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) { unsigned char* src = (unsigned char*) malloc(src_size); Fill(src, src_size); unsigned char* dst = (unsigned char*) realloc(src, dst_size); CHECK(Valid(dst, min(src_size, dst_size))); Fill(dst, dst_size); CHECK(Valid(dst, dst_size)); if (dst != NULL) free(dst); } } // Now make sure realloc works correctly even when we overflow the // packed cache, so some entries are evicted from the cache. // The cache has 2^12 entries, keyed by page number. const int kNumEntries = 1 << 14; int** p = (int**)malloc(sizeof(*p) * kNumEntries); int sum = 0; for (int i = 0; i < kNumEntries; i++) { p[i] = (int*)malloc(8192); // no page size is likely to be bigger p[i][1000] = i; // use memory deep in the heart of p } for (int i = 0; i < kNumEntries; i++) { p[i] = (int*)realloc(p[i], 9000); } for (int i = 0; i < kNumEntries; i++) { sum += p[i][1000]; free(p[i]); } CHECK_EQ(kNumEntries/2 * (kNumEntries - 1), sum); // assume kNE is even free(p); printf("PASS\n"); return 0; } ================================================ FILE: distro/google-perftools-1.7/src/tests/sampler_test.cc ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // All Rights Reserved. // // Author: Daniel Ford // // Checks basic properties of the sampler #include "config_for_unittests.h" #include // defines posix_memalign #include // for the printf at the end #if defined HAVE_STDINT_H #include // to get uintptr_t #elif defined HAVE_INTTYPES_H #include // another place uintptr_t might be defined #endif #include #include #include #include #include #include #include "base/logging.h" #include "base/commandlineflags.h" #include "sampler.h" // The Sampler class being tested using std::sort; using std::min; using std::max; using std::vector; using std::abs; vector g_testlist; // the tests to run #define TEST(a, b) \ struct Test_##a##_##b { \ Test_##a##_##b() { g_testlist.push_back(&Run); } \ static void Run(); \ }; \ static Test_##a##_##b g_test_##a##_##b; \ void Test_##a##_##b::Run() static int RUN_ALL_TESTS() { vector::const_iterator it; for (it = g_testlist.begin(); it != g_testlist.end(); ++it) { (*it)(); // The test will error-exit if there's a problem. } fprintf(stderr, "\nPassed %d tests\n\nPASS\n", (int)g_testlist.size()); return 0; } #undef LOG // defined in base/logging.h // Ideally, we'd put the newline at the end, but this hack puts the // newline at the end of the previous log message, which is good enough :-) #define LOG(level) std::cerr << "\n" static std::string StringPrintf(const char* format, ...) { char buf[256]; // should be big enough for all logging va_list ap; va_start(ap, format); vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); return buf; } namespace { template class scoped_array { public: scoped_array(T* p) : p_(p) { } ~scoped_array() { delete[] p_; } const T* get() const { return p_; } T* get() { return p_; } T& operator[](int i) { return p_[i]; } private: T* p_; }; } // Note that these tests are stochastic. // This mean that the chance of correct code passing the test is, // in the case of 5 standard deviations: // kSigmas=5: ~99.99994267% // in the case of 4 standard deviations: // kSigmas=4: ~99.993666% static const double kSigmas = 4; static const size_t kSamplingInterval = 512*1024; // Tests that GetSamplePeriod returns the expected value // which is 1<<19 TEST(Sampler, TestGetSamplePeriod) { tcmalloc::Sampler sampler; sampler.Init(1); uint64_t sample_period; sample_period = sampler.GetSamplePeriod(); CHECK_GT(sample_period, 0); } // Tests of the quality of the random numbers generated // This uses the Anderson Darling test for uniformity. // See "Evaluating the Anderson-Darling Distribution" by Marsaglia // for details. // Short cut version of ADinf(z), z>0 (from Marsaglia) // This returns the p-value for Anderson Darling statistic in // the limit as n-> infinity. For finite n, apply the error fix below. double AndersonDarlingInf(double z) { if (z < 2) { return exp(-1.2337141 / z) / sqrt(z) * (2.00012 + (0.247105 - (0.0649821 - (0.0347962 - (0.011672 - 0.00168691 * z) * z) * z) * z) * z); } return exp( - exp(1.0776 - (2.30695 - (0.43424 - (0.082433 - (0.008056 - 0.0003146 * z) * z) * z) * z) * z)); } // Corrects the approximation error in AndersonDarlingInf for small values of n // Add this to AndersonDarlingInf to get a better approximation // (from Marsaglia) double AndersonDarlingErrFix(int n, double x) { if (x > 0.8) { return (-130.2137 + (745.2337 - (1705.091 - (1950.646 - (1116.360 - 255.7844 * x) * x) * x) * x) * x) / n; } double cutoff = 0.01265 + 0.1757 / n; double t; if (x < cutoff) { t = x / cutoff; t = sqrt(t) * (1 - t) * (49 * t - 102); return t * (0.0037 / (n * n) + 0.00078 / n + 0.00006) / n; } else { t = (x - cutoff) / (0.8 - cutoff); t = -0.00022633 + (6.54034 - (14.6538 - (14.458 - (8.259 - 1.91864 * t) * t) * t) * t) * t; return t * (0.04213 + 0.01365 / n) / n; } } // Returns the AndersonDarling p-value given n and the value of the statistic double AndersonDarlingPValue(int n, double z) { double ad = AndersonDarlingInf(z); double errfix = AndersonDarlingErrFix(n, ad); return ad + errfix; } double AndersonDarlingStatistic(int n, double* random_sample) { double ad_sum = 0; for (int i = 0; i < n; i++) { ad_sum += (2*i + 1) * log(random_sample[i] * (1 - random_sample[n-1-i])); } double ad_statistic = - n - 1/static_cast(n) * ad_sum; return ad_statistic; } // Tests if the array of doubles is uniformly distributed. // Returns the p-value of the Anderson Darling Statistic // for the given set of sorted random doubles // See "Evaluating the Anderson-Darling Distribution" by // Marsaglia and Marsaglia for details. double AndersonDarlingTest(int n, double* random_sample) { double ad_statistic = AndersonDarlingStatistic(n, random_sample); LOG(INFO) << StringPrintf("AD stat = %f, n=%d\n", ad_statistic, n); double p = AndersonDarlingPValue(n, ad_statistic); return p; } // Test the AD Test. The value of the statistic should go to zero as n->infty // Not run as part of regular tests void ADTestTest(int n) { scoped_array random_sample(new double[n]); for (int i = 0; i < n; i++) { random_sample[i] = (i+0.01)/n; } sort(random_sample.get(), random_sample.get() + n); double ad_stat = AndersonDarlingStatistic(n, random_sample.get()); LOG(INFO) << StringPrintf("Testing the AD test. n=%d, ad_stat = %f", n, ad_stat); } // Print the CDF of the distribution of the Anderson-Darling Statistic // Used for checking the Anderson-Darling Test // Not run as part of regular tests void ADCDF() { for (int i = 1; i < 40; i++) { double x = i/10.0; LOG(INFO) << "x= " << x << " adpv= " << AndersonDarlingPValue(100, x) << ", " << AndersonDarlingPValue(1000, x); } } // Testing that NextRandom generates uniform // random numbers. // Applies the Anderson-Darling test for uniformity void TestNextRandom(int n) { tcmalloc::Sampler sampler; sampler.Init(1); uint64_t x = 1; // This assumes that the prng returns 48 bit numbers uint64_t max_prng_value = static_cast(1)<<48; // Initialize for (int i = 1; i <= 20; i++) { // 20 mimics sampler.Init() x = sampler.NextRandom(x); } scoped_array int_random_sample(new uint64_t[n]); // Collect samples for (int i = 0; i < n; i++) { int_random_sample[i] = x; x = sampler.NextRandom(x); } // First sort them... sort(int_random_sample.get(), int_random_sample.get() + n); scoped_array random_sample(new double[n]); // Convert them to uniform randoms (in the range [0,1]) for (int i = 0; i < n; i++) { random_sample[i] = static_cast(int_random_sample[i])/max_prng_value; } // Now compute the Anderson-Darling statistic double ad_pvalue = AndersonDarlingTest(n, random_sample.get()); LOG(INFO) << StringPrintf("pvalue for AndersonDarlingTest " "with n= %d is p= %f\n", n, ad_pvalue); CHECK_GT(min(ad_pvalue, 1 - ad_pvalue), 0.0001); // << StringPrintf("prng is not uniform, %d\n", n); } TEST(Sampler, TestNextRandom_MultipleValues) { TestNextRandom(10); // Check short-range correlation TestNextRandom(100); TestNextRandom(1000); TestNextRandom(10000); // Make sure there's no systematic error } // Tests that PickNextSamplePeriod generates // geometrically distributed random numbers. // First converts to uniforms then applied the // Anderson-Darling test for uniformity. void TestPickNextSample(int n) { tcmalloc::Sampler sampler; sampler.Init(1); scoped_array int_random_sample(new uint64_t[n]); int sample_period = sampler.GetSamplePeriod(); int ones_count = 0; for (int i = 0; i < n; i++) { int_random_sample[i] = sampler.PickNextSamplingPoint(); CHECK_GE(int_random_sample[i], 1); if (int_random_sample[i] == 1) { ones_count += 1; } CHECK_LT(ones_count, 4); // << " out of " << i << " samples."; } // First sort them... sort(int_random_sample.get(), int_random_sample.get() + n); scoped_array random_sample(new double[n]); // Convert them to uniform random numbers // by applying the geometric CDF for (int i = 0; i < n; i++) { random_sample[i] = 1 - exp(-static_cast(int_random_sample[i]) / sample_period); } // Now compute the Anderson-Darling statistic double geom_ad_pvalue = AndersonDarlingTest(n, random_sample.get()); LOG(INFO) << StringPrintf("pvalue for geometric AndersonDarlingTest " "with n= %d is p= %f\n", n, geom_ad_pvalue); CHECK_GT(min(geom_ad_pvalue, 1 - geom_ad_pvalue), 0.0001); // << "PickNextSamplingPoint does not produce good " // "geometric/exponential random numbers\n"; } TEST(Sampler, TestPickNextSample_MultipleValues) { TestPickNextSample(10); // Make sure the first few are good (enough) TestPickNextSample(100); TestPickNextSample(1000); TestPickNextSample(10000); // Make sure there's no systematic error } // This is superceeded by the Anderson-Darling Test // and it not run now. // Tests how fast nearby values are spread out with LRand64 // The purpose of this code is to determine how many // steps to apply to the seed during initialization void TestLRand64Spread() { tcmalloc::Sampler sampler; sampler.Init(1); uint64_t current_value; printf("Testing LRand64 Spread\n"); for (int i = 1; i < 10; i++) { printf("%d ", i); current_value = i; for (int j = 1; j < 100; j++) { current_value = sampler.NextRandom(current_value); } LOG(INFO) << current_value; } } // Test for Fastlog2 code // We care about the percentage error because we're using this // for choosing step sizes, so "close" is relative to the size of // the step we would get if we used the built-in log function TEST(Sampler, FastLog2) { tcmalloc::Sampler sampler; sampler.Init(1); double max_ratio_error = 0; for (double d = -1021.9; d < 1; d+= 0.13124235) { double e = pow(2.0, d); double truelog = log(e) / log(2.0); // log_2(e) double fastlog = sampler.FastLog2(e); max_ratio_error = max(max_ratio_error, max(truelog/fastlog-1, fastlog/truelog-1)); CHECK_LE(max_ratio_error, 0.01); // << StringPrintf("d = %f, e=%f, truelog = %f, fastlog= %f\n", // d, e, truelog, fastlog); } LOG(INFO) << StringPrintf("Fastlog2: max_ratio_error = %f\n", max_ratio_error); } // Futher tests bool CheckMean(size_t mean, int num_samples) { tcmalloc::Sampler sampler; sampler.Init(1); size_t total = 0; for (int i = 0; i < num_samples; i++) { total += sampler.PickNextSamplingPoint(); } double empirical_mean = total / static_cast(num_samples); double expected_sd = mean / pow(num_samples * 1.0, 0.5); return(abs(mean-empirical_mean) < expected_sd * kSigmas); } // Prints a sequence so you can look at the distribution void OutputSequence(int sequence_length) { tcmalloc::Sampler sampler; sampler.Init(1); size_t next_step; for (int i = 0; i< sequence_length; i++) { next_step = sampler.PickNextSamplingPoint(); LOG(INFO) << next_step; } } double StandardDeviationsErrorInSample( int total_samples, int picked_samples, int alloc_size, int sampling_interval) { double p = 1 - exp(-(static_cast(alloc_size) / sampling_interval)); double expected_samples = total_samples * p; double sd = pow(p*(1-p)*total_samples, 0.5); return((picked_samples - expected_samples) / sd); } TEST(Sampler, LargeAndSmallAllocs_CombinedTest) { tcmalloc::Sampler sampler; sampler.Init(1); int counter_big = 0; int counter_small = 0; int size_big = 129*8*1024+1; int size_small = 1024*8; int num_iters = 128*4*8; // Allocate in mixed chunks for (int i = 0; i < num_iters; i++) { if (sampler.SampleAllocation(size_big)) { counter_big += 1; } for (int i = 0; i < 129; i++) { if (sampler.SampleAllocation(size_small)) { counter_small += 1; } } } // Now test that there are the right number of each double large_allocs_sds = StandardDeviationsErrorInSample(num_iters, counter_big, size_big, kSamplingInterval); double small_allocs_sds = StandardDeviationsErrorInSample(num_iters*129, counter_small, size_small, kSamplingInterval); LOG(INFO) << StringPrintf("large_allocs_sds = %f\n", large_allocs_sds); LOG(INFO) << StringPrintf("small_allocs_sds = %f\n", small_allocs_sds); CHECK_LE(abs(large_allocs_sds), kSigmas); CHECK_LE(abs(small_allocs_sds), kSigmas); } // Tests whether the mean is about right over 1000 samples TEST(Sampler, IsMeanRight) { CHECK(CheckMean(kSamplingInterval, 1000)); } // This flag is for the OldSampler class to use const int64 FLAGS_mock_tcmalloc_sample_parameter = 1<<19; // A cut down and slightly refactored version of the old Sampler class OldSampler { public: void Init(uint32_t seed); void Cleanup() {} // Record allocation of "k" bytes. Return true iff allocation // should be sampled bool SampleAllocation(size_t k); // Generate a geometric with mean 1M (or FLAG value) void PickNextSample(size_t k); // Initialize the statics for the Sample class static void InitStatics() { sample_period = 1048583; } size_t bytes_until_sample_; private: uint32_t rnd_; // Cheap random number generator static uint64_t sample_period; // Should be a prime just above a power of 2: // 2, 5, 11, 17, 37, 67, 131, 257, // 521, 1031, 2053, 4099, 8209, 16411, // 32771, 65537, 131101, 262147, 524309, 1048583, // 2097169, 4194319, 8388617, 16777259, 33554467 }; // Statics for OldSampler uint64_t OldSampler::sample_period; void OldSampler::Init(uint32_t seed) { // Initialize PRNG -- run it for a bit to get to good values if (seed != 0) { rnd_ = seed; } else { rnd_ = 12345; } bytes_until_sample_ = 0; for (int i = 0; i < 100; i++) { PickNextSample(sample_period * 2); } }; // A cut-down version of the old PickNextSampleRoutine void OldSampler::PickNextSample(size_t k) { // Make next "random" number // x^32+x^22+x^2+x^1+1 is a primitive polynomial for random numbers static const uint32_t kPoly = (1 << 22) | (1 << 2) | (1 << 1) | (1 << 0); uint32_t r = rnd_; rnd_ = (r << 1) ^ ((static_cast(r) >> 31) & kPoly); // Next point is "rnd_ % (sample_period)". I.e., average // increment is "sample_period/2". const int flag_value = FLAGS_mock_tcmalloc_sample_parameter; static int last_flag_value = -1; if (flag_value != last_flag_value) { // There should be a spinlock here, but this code is // for benchmarking only. sample_period = 1048583; last_flag_value = flag_value; } bytes_until_sample_ += rnd_ % sample_period; if (k > (static_cast(-1) >> 2)) { // If the user has asked for a huge allocation then it is possible // for the code below to loop infinitely. Just return (note that // this throws off the sampling accuracy somewhat, but a user who // is allocating more than 1G of memory at a time can live with a // minor inaccuracy in profiling of small allocations, and also // would rather not wait for the loop below to terminate). return; } while (bytes_until_sample_ < k) { // Increase bytes_until_sample_ by enough average sampling periods // (sample_period >> 1) to allow us to sample past the current // allocation. bytes_until_sample_ += (sample_period >> 1); } bytes_until_sample_ -= k; } inline bool OldSampler::SampleAllocation(size_t k) { if (bytes_until_sample_ < k) { PickNextSample(k); return true; } else { bytes_until_sample_ -= k; return false; } } // This checks that the stated maximum value for the // tcmalloc_sample_parameter flag never overflows bytes_until_sample_ TEST(Sampler, bytes_until_sample_Overflow_Underflow) { tcmalloc::Sampler sampler; sampler.Init(1); uint64_t one = 1; // sample_parameter = 0; // To test the edge case uint64_t sample_parameter_array[4] = {0, 1, one<<19, one<<58}; for (int i = 0; i < 4; i++) { uint64_t sample_parameter = sample_parameter_array[i]; LOG(INFO) << "sample_parameter = " << sample_parameter; double sample_scaling = - log(2.0) * sample_parameter; // Take the top 26 bits as the random number // (This plus the 1<<26 sampling bound give a max step possible of // 1209424308 bytes.) const uint64_t prng_mod_power = 48; // Number of bits in prng // First, check the largest_prng value uint64_t largest_prng_value = (static_cast(1)<<48) - 1; double q = (largest_prng_value >> (prng_mod_power - 26)) + 1.0; LOG(INFO) << StringPrintf("q = %f\n", q); LOG(INFO) << StringPrintf("FastLog2(q) = %f\n", sampler.FastLog2(q)); LOG(INFO) << StringPrintf("log2(q) = %f\n", log(q)/log(2.0)); // Replace min(sampler.FastLog2(q) - 26, 0.0) with // (sampler.FastLog2(q) - 26.000705) when using that optimization uint64_t smallest_sample_step = static_cast(min(sampler.FastLog2(q) - 26, 0.0) * sample_scaling + 1); LOG(INFO) << "Smallest sample step is " << smallest_sample_step; uint64_t cutoff = static_cast(10) * (sample_parameter/(one<<24) + 1); LOG(INFO) << "Acceptable value is < " << cutoff; // This checks that the answer is "small" and positive CHECK_LE(smallest_sample_step, cutoff); // Next, check with the smallest prng value uint64_t smallest_prng_value = 0; q = (smallest_prng_value >> (prng_mod_power - 26)) + 1.0; LOG(INFO) << StringPrintf("q = %f\n", q); // Replace min(sampler.FastLog2(q) - 26, 0.0) with // (sampler.FastLog2(q) - 26.000705) when using that optimization uint64_t largest_sample_step = static_cast(min(sampler.FastLog2(q) - 26, 0.0) * sample_scaling + 1); LOG(INFO) << "Largest sample step is " << largest_sample_step; CHECK_LE(largest_sample_step, one<<63); CHECK_GE(largest_sample_step, smallest_sample_step); } } // Test that NextRand is in the right range. Unfortunately, this is a // stochastic test which could miss problems. TEST(Sampler, NextRand_range) { tcmalloc::Sampler sampler; sampler.Init(1); uint64_t one = 1; // The next number should be (one << 48) - 1 uint64_t max_value = (one << 48) - 1; uint64_t x = (one << 55); int n = 22; // 27; LOG(INFO) << "Running sampler.NextRandom 1<<" << n << " times"; for (int i = 1; i <= (1<>27); i++) { // 20 mimics sampler.Init() rnd = sampler.NextRandom(rnd); CHECK_LE(rnd, max_value); double q = (rnd >> (prng_mod_power - 26)) + 1.0; CHECK_GE(q, 0); // << rnd << " " << prng_mod_power; } // Test some potentially out of bounds value for rnd for (int i = 1; i <= 66; i++) { rnd = one << i; double q = (rnd >> (prng_mod_power - 26)) + 1.0; LOG(INFO) << "rnd = " << rnd << " i=" << i << " q=" << q; CHECK_GE(q, 0); // << " rnd=" << rnd << " i=" << i << " prng_mod_power" << prng_mod_power; } } void test_arithmetic(uint64_t rnd) { const uint64_t prng_mod_power = 48; // Number of bits in prng uint64_t shifted_rnd = rnd >> (prng_mod_power - 26); CHECK_GE(shifted_rnd, 0); CHECK_LT(shifted_rnd, (1<<26)); LOG(INFO) << shifted_rnd; LOG(INFO) << static_cast(shifted_rnd); CHECK_GE(static_cast(static_cast(shifted_rnd)), 0); // << " rnd=" << rnd << " srnd=" << shifted_rnd; CHECK_GE(static_cast(shifted_rnd), 0); // << " rnd=" << rnd << " srnd=" << shifted_rnd; double q = static_cast(shifted_rnd) + 1.0; CHECK_GT(q, 0); } // Tests certain arithmetic operations to make sure they compute what we // expect them too (for testing across different platforms) // know bad values under with -c dbg --cpu piii for _some_ binaries: // rnd=227453640600554 // shifted_rnd=54229173 // (hard to reproduce) TEST(Sampler, arithmetic_2) { uint64_t rnd = 227453640600554LL; test_arithmetic(rnd); } // It's not really a test, but it's good to know TEST(Sample, size_of_class) { tcmalloc::Sampler sampler; sampler.Init(1); LOG(INFO) << "Size of Sampler class is: " << sizeof(tcmalloc::Sampler); LOG(INFO) << "Size of Sampler object is: " << sizeof(sampler); } // Make sure sampling is enabled, or the tests won't work right. DECLARE_int64(tcmalloc_sample_parameter); int main(int argc, char **argv) { if (FLAGS_tcmalloc_sample_parameter == 0) FLAGS_tcmalloc_sample_parameter = 524288; return RUN_ALL_TESTS(); } ================================================ FILE: distro/google-perftools-1.7/src/tests/sampling_test.cc ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Craig Silverstein // // This tests ReadStackTraces and ReadGrowthStackTraces. It does this // by doing a bunch of allocations and then calling those functions. // A driver shell-script can call this, and then call pprof, and // verify the expected output. The output is written to // argv[1].heap and argv[1].growth #include "config_for_unittests.h" #include #include #include #include "base/logging.h" #include using std::string; extern "C" void* AllocateAllocate() ATTRIBUTE_NOINLINE; extern "C" void* AllocateAllocate() { // The VLOG's are mostly to discourage inlining VLOG(1, "Allocating some more"); void* p = malloc(10000); VLOG(1, "Done allocating"); return p; } static void WriteStringToFile(const string& s, const string& filename) { FILE* fp = fopen(filename.c_str(), "w"); fwrite(s.data(), 1, s.length(), fp); fclose(fp); } int main(int argc, char** argv) { if (argc < 2) { fprintf(stderr, "USAGE: %s \n", argv[0]); exit(1); } for (int i = 0; i < 8000; i++) { AllocateAllocate(); } string s; MallocExtension::instance()->GetHeapSample(&s); WriteStringToFile(s, string(argv[1]) + ".heap"); s.clear(); MallocExtension::instance()->GetHeapGrowthStacks(&s); WriteStringToFile(s, string(argv[1]) + ".growth"); return 0; } ================================================ FILE: distro/google-perftools-1.7/src/tests/sampling_test.sh ================================================ #!/bin/sh # Copyright (c) 2008, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # --- # Author: Craig Silverstein # # This is a test that tcmalloc creates, and pprof reads, sampling data # correctly: both for the heap profile (ReadStackTraces) and for # growth in the heap sized (ReadGrowthStackTraces). BINDIR="${BINDIR:-.}" PPROF_PATH="${PPROF_PATH:-$BINDIR/src/pprof}" if [ "x$1" = "x-h" -o "x$1" = "x--help" ]; then echo "USAGE: $0 [unittest dir] [path to pprof]" echo " By default, unittest_dir=$BINDIR, pprof_path=$PPROF_PATH" exit 1 fi SAMPLING_TEST="${1:-$BINDIR/sampling_test}" PPROF="${2:-$PPROF_PATH}" OUTDIR="/tmp/sampling_test_dir" # libtool is annoying, and puts the actual executable in a different # directory, replacing the seeming-executable with a shell script. # We use the error output of sampling_test to indicate its real location SAMPLING_TEST_BINARY=`"$SAMPLING_TEST" 2>&1 | awk '/USAGE/ {print $2; exit;}'` # A kludge for cygwin. Unfortunately, 'test -f' says that 'foo' exists # even when it doesn't, and only foo.exe exists. Other unix utilities # (like nm) need you to say 'foo.exe'. We use one such utility, cat, to # see what the *real* binary name is. if ! cat "$SAMPLING_TEST_BINARY" >/dev/null 2>&1; then SAMPLING_TEST_BINARY="$SAMPLING_TEST_BINARY".exe fi die() { # runs the command given as arguments, and then dies. echo "FAILED. Output from $@" echo "----" "$@" echo "----" exit 1 } rm -rf "$OUTDIR" || die "Unable to delete $OUTDIR" mkdir "$OUTDIR" || die "Unable to create $OUTDIR" # This puts the output into out.heap and out.growth. It allocates # 8*10^7 bytes of memory, which is 76M. Because we sample, the # estimate may be a bit high or a bit low: we accept anything from # 50M to 99M. "$SAMPLING_TEST" "$OUTDIR/out" echo "Testing heap output..." "$PPROF" --text "$SAMPLING_TEST_BINARY" "$OUTDIR/out.heap" \ | grep '[5-9][0-9]\.[0-9][ 0-9.%]*_*AllocateAllocate' >/dev/null \ || die "$PPROF" --text "$SAMPLING_TEST_BINARY" "$OUTDIR/out.heap" echo "OK" echo "Testing growth output..." "$PPROF" --text "$SAMPLING_TEST_BINARY" "$OUTDIR/out.growth" \ | grep '[5-9][0-9]\.[0-9][ 0-9.%]*_*AllocateAllocate' >/dev/null \ || die "$PPROF" --text "$SAMPLING_TEST_BINARY" "$OUTDIR/out.growth" echo "OK" echo "PASS" ================================================ FILE: distro/google-perftools-1.7/src/tests/stack_trace_table_test.cc ================================================ // Copyright 2009 Google Inc. All Rights Reserved. // Author: fikes@google.com (Andrew Fikes) #include "config_for_unittests.h" #include // for puts() #include "stack_trace_table.h" #include "base/logging.h" #include "base/spinlock.h" #include "static_vars.h" #undef ARRAYSIZE // may be defined on, eg, windows #define ARRAYSIZE(a) ( sizeof(a) / sizeof(*(a)) ) static void CheckTracesAndReset(tcmalloc::StackTraceTable* table, const uintptr_t* expected, int len) { void** entries = table->ReadStackTracesAndClear(); for (int i = 0; i < len; ++i) { CHECK_EQ(reinterpret_cast(entries[i]), expected[i]); } delete[] entries; } static void AddTrace(tcmalloc::StackTraceTable* table, const tcmalloc::StackTrace& t) { // Normally we'd need this lock, but since the test is single-threaded // we don't. I comment it out on windows because the DLL-decl thing // is really annoying in this case. #ifndef _MSC_VER SpinLockHolder h(tcmalloc::Static::pageheap_lock()); #endif table->AddTrace(t); } int main(int argc, char **argv) { tcmalloc::StackTraceTable table; // Empty table CHECK_EQ(table.depth_total(), 0); CHECK_EQ(table.bucket_total(), 0); static const uintptr_t k1[] = {0}; CheckTracesAndReset(&table, k1, ARRAYSIZE(k1)); tcmalloc::StackTrace t1; t1.size = static_cast(1024); t1.depth = static_cast(2); t1.stack[0] = reinterpret_cast(1); t1.stack[1] = reinterpret_cast(2); tcmalloc::StackTrace t2; t2.size = static_cast(512); t2.depth = static_cast(2); t2.stack[0] = reinterpret_cast(2); t2.stack[1] = reinterpret_cast(1); // Table w/ just t1 AddTrace(&table, t1); CHECK_EQ(table.depth_total(), 2); CHECK_EQ(table.bucket_total(), 1); static const uintptr_t k2[] = {1, 1024, 2, 1, 2, 0}; CheckTracesAndReset(&table, k2, ARRAYSIZE(k2)); // Table w/ t1, t2 AddTrace(&table, t1); AddTrace(&table, t2); CHECK_EQ(table.depth_total(), 4); CHECK_EQ(table.bucket_total(), 2); static const uintptr_t k3[] = {1, 1024, 2, 1, 2, 1, 512, 2, 2, 1, 0}; CheckTracesAndReset(&table, k3, ARRAYSIZE(k3)); // Table w/ 2 x t1, 1 x t2 AddTrace(&table, t1); AddTrace(&table, t2); AddTrace(&table, t1); CHECK_EQ(table.depth_total(), 4); CHECK_EQ(table.bucket_total(), 2); static const uintptr_t k4[] = {2, 2048, 2, 1, 2, 1, 512, 2, 2, 1, 0}; CheckTracesAndReset(&table, k4, ARRAYSIZE(k4)); // Same stack as t1, but w/ different size tcmalloc::StackTrace t3; t3.size = static_cast(2); t3.depth = static_cast(2); t3.stack[0] = reinterpret_cast(1); t3.stack[1] = reinterpret_cast(2); // Table w/ t1, t3 AddTrace(&table, t1); AddTrace(&table, t3); CHECK_EQ(table.depth_total(), 2); CHECK_EQ(table.bucket_total(), 1); static const uintptr_t k5[] = {2, 1026, 2, 1, 2, 0}; CheckTracesAndReset(&table, k5, ARRAYSIZE(k5)); puts("PASS"); return 0; } ================================================ FILE: distro/google-perftools-1.7/src/tests/stacktrace_unittest.cc ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "config_for_unittests.h" #ifdef HAVE_EXECINFO_H #include #endif #include #include #include "base/commandlineflags.h" #include "base/logging.h" #include namespace { // Obtain a backtrace, verify that the expected callers are present in the // backtrace, and maybe print the backtrace to stdout. // The sequence of functions whose return addresses we expect to see in the // backtrace. const int BACKTRACE_STEPS = 6; struct AddressRange { const void *start, *end; }; // Expected function [start,end] range. AddressRange expected_range[BACKTRACE_STEPS]; #if __GNUC__ // Using GCC extension: address of a label can be taken with '&&label'. // Start should be a label somewhere before recursive call, end somewhere // after it. #define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \ do { \ (prange)->start = &&start_label; \ (prange)->end = &&end_label; \ CHECK_LT((prange)->start, (prange)->end); \ } while (0) // This macro expands into "unmovable" code (opaque to GCC), and that // prevents GCC from moving a_label up or down in the code. // Without it, there is no code following the 'end' label, and GCC // (4.3.1, 4.4.0) thinks it safe to assign &&end an address that is before // the recursive call. #define DECLARE_ADDRESS_LABEL(a_label) \ a_label: do { __asm__ __volatile__(""); } while (0) // Gcc 4.4.0 may split function into multiple chunks, and the chunk // performing recursive call may end up later in the code then the return // instruction (this actually happens with FDO). // Adjust function range from __builtin_return_address. #define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \ do { \ void *ra = __builtin_return_address(0); \ CHECK_LT((prange)->start, ra); \ if (ra > (prange)->end) { \ printf("Adjusting range from %p..%p to %p..%p\n", \ (prange)->start, (prange)->end, \ (prange)->start, ra); \ (prange)->end = ra; \ } \ } while (0) #else // Assume the Check* functions below are not longer than 256 bytes. #define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \ do { \ (prange)->start = reinterpret_cast(&fn); \ (prange)->end = reinterpret_cast(&fn) + 256; \ } while (0) #define DECLARE_ADDRESS_LABEL(a_label) do { } while (0) #define ADJUST_ADDRESS_RANGE_FROM_RA(prange) do { } while (0) #endif // __GNUC__ //-----------------------------------------------------------------------// void CheckRetAddrIsInFunction(void *ret_addr, const AddressRange &range) { CHECK_GE(ret_addr, range.start); CHECK_LE(ret_addr, range.end); } //-----------------------------------------------------------------------// void ATTRIBUTE_NOINLINE CheckStackTrace(int); void ATTRIBUTE_NOINLINE CheckStackTraceLeaf(void) { const int STACK_LEN = 10; void *stack[STACK_LEN]; int size; ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]); INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]); DECLARE_ADDRESS_LABEL(start); size = GetStackTrace(stack, STACK_LEN, 0); printf("Obtained %d stack frames.\n", size); CHECK_GE(size, 1); CHECK_LE(size, STACK_LEN); #ifdef HAVE_EXECINFO_H { char **strings = backtrace_symbols(stack, size); printf("Obtained %d stack frames.\n", size); for (int i = 0; i < size; i++) printf("%s %p\n", strings[i], stack[i]); printf("CheckStackTrace() addr: %p\n", &CheckStackTrace); free(strings); } #endif for (int i = 0; i < BACKTRACE_STEPS; i++) { printf("Backtrace %d: expected: %p..%p actual: %p ... ", i, expected_range[i].start, expected_range[i].end, stack[i]); fflush(stdout); CheckRetAddrIsInFunction(stack[i], expected_range[i]); printf("OK\n"); } DECLARE_ADDRESS_LABEL(end); } //-----------------------------------------------------------------------// /* Dummy functions to make the backtrace more interesting. */ void ATTRIBUTE_NOINLINE CheckStackTrace4(int i) { ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[2]); INIT_ADDRESS_RANGE(CheckStackTrace4, start, end, &expected_range[1]); DECLARE_ADDRESS_LABEL(start); for (int j = i; j >= 0; j--) CheckStackTraceLeaf(); DECLARE_ADDRESS_LABEL(end); } void ATTRIBUTE_NOINLINE CheckStackTrace3(int i) { ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[3]); INIT_ADDRESS_RANGE(CheckStackTrace3, start, end, &expected_range[2]); DECLARE_ADDRESS_LABEL(start); for (int j = i; j >= 0; j--) CheckStackTrace4(j); DECLARE_ADDRESS_LABEL(end); } void ATTRIBUTE_NOINLINE CheckStackTrace2(int i) { ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[4]); INIT_ADDRESS_RANGE(CheckStackTrace2, start, end, &expected_range[3]); DECLARE_ADDRESS_LABEL(start); for (int j = i; j >= 0; j--) CheckStackTrace3(j); DECLARE_ADDRESS_LABEL(end); } void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) { ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[5]); INIT_ADDRESS_RANGE(CheckStackTrace1, start, end, &expected_range[4]); DECLARE_ADDRESS_LABEL(start); for (int j = i; j >= 0; j--) CheckStackTrace2(j); DECLARE_ADDRESS_LABEL(end); } void ATTRIBUTE_NOINLINE CheckStackTrace(int i) { INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]); DECLARE_ADDRESS_LABEL(start); for (int j = i; j >= 0; j--) CheckStackTrace1(j); DECLARE_ADDRESS_LABEL(end); } } // namespace //-----------------------------------------------------------------------// int main(int argc, char ** argv) { CheckStackTrace(0); printf("PASS\n"); return 0; } ================================================ FILE: distro/google-perftools-1.7/src/tests/system-alloc_unittest.cc ================================================ // Copyright (c) 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Arun Sharma #include "config_for_unittests.h" #include #if defined HAVE_STDINT_H #include // to get uintptr_t #elif defined HAVE_INTTYPES_H #include // another place uintptr_t might be defined #endif #include #include #include "base/logging.h" #include "common.h" #include "system-alloc.h" class ArraySysAllocator : public SysAllocator { public: // Was this allocator invoked at least once? bool invoked_; ArraySysAllocator() : SysAllocator() { ptr_ = 0; invoked_ = false; } void* Alloc(size_t size, size_t *actual_size, size_t alignment) { invoked_ = true; void *result = &array_[ptr_]; uintptr_t ptr = reinterpret_cast(result); if (actual_size) { *actual_size = size; } // Try to get more memory for alignment size_t extra = alignment - (ptr & (alignment-1)); size += extra; CHECK_LT(ptr_ + size, kArraySize); if ((ptr & (alignment-1)) != 0) { ptr += alignment - (ptr & (alignment-1)); } ptr_ += size; return reinterpret_cast(ptr); } void DumpStats(TCMalloc_Printer* printer) { } private: static const int kArraySize = 8 * 1024 * 1024; char array_[kArraySize]; // We allocate the next chunk from here int ptr_; }; const int ArraySysAllocator::kArraySize; ArraySysAllocator a; static void TestBasicInvoked() { RegisterSystemAllocator(&a, 0); // An allocation size that is likely to trigger the system allocator. // XXX: this is implementation specific. char *p = new char[1024 * 1024]; delete [] p; // Make sure that our allocator was invoked. CHECK(a.invoked_); } #if 0 // could port this to various OSs, but won't bother for now TEST(AddressBits, CpuVirtualBits) { // Check that kAddressBits is as least as large as either the number of bits // in a pointer or as the number of virtual bits handled by the processor. // To be effective this test must be run on each processor model. const int kPointerBits = 8 * sizeof(void*); const int kImplementedVirtualBits = NumImplementedVirtualBits(); CHECK_GE(kAddressBits, min(kImplementedVirtualBits, kPointerBits)); } #endif int main(int argc, char** argv) { TestBasicInvoked(); printf("PASS\n"); return 0; } ================================================ FILE: distro/google-perftools-1.7/src/tests/tcmalloc_large_unittest.cc ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Michael Chastain // // This is a unit test for large allocations in malloc and friends. // "Large" means "so large that they overflow the address space". // For 32 bits, this means allocations near 2^32 bytes and 2^31 bytes. // For 64 bits, this means allocations near 2^64 bytes and 2^63 bytes. #include #include #include #include #include "base/logging.h" using std::set; // Alloc a size that should always fail. void TryAllocExpectFail(size_t size) { void* p1 = malloc(size); CHECK(p1 == NULL); void* p2 = malloc(1); CHECK(p2 != NULL); void* p3 = realloc(p2, size); CHECK(p3 == NULL); free(p2); } // Alloc a size that might work and might fail. // If it does work, touch some pages. void TryAllocMightFail(size_t size) { unsigned char* p = static_cast(malloc(size)); if ( p != NULL ) { unsigned char volatile* vp = p; // prevent optimizations static const size_t kPoints = 1024; for ( size_t i = 0; i < kPoints; ++i ) { vp[i * (size / kPoints)] = static_cast(i); } for ( size_t i = 0; i < kPoints; ++i ) { CHECK(vp[i * (size / kPoints)] == static_cast(i)); } vp[size-1] = 'M'; CHECK(vp[size-1] == 'M'); } free(p); } int main (int argc, char** argv) { // Allocate some 0-byte objects. They better be unique. // 0 bytes is not large but it exercises some paths related to // large-allocation code. { static const int kZeroTimes = 1024; printf("Test malloc(0) x %d\n", kZeroTimes); set p_set; for ( int i = 0; i < kZeroTimes; ++i ) { char* p = new char; CHECK(p != NULL); CHECK(p_set.find(p) == p_set.end()); p_set.insert(p_set.end(), p); } // Just leak the memory. } // Grab some memory so that some later allocations are guaranteed to fail. printf("Test small malloc\n"); void* p_small = malloc(4*1048576); CHECK(p_small != NULL); // Test sizes up near the maximum size_t. // These allocations test the wrap-around code. printf("Test malloc(0 - N)\n"); const size_t zero = 0; static const size_t kMinusNTimes = 16384; for ( size_t i = 1; i < kMinusNTimes; ++i ) { TryAllocExpectFail(zero - i); } // Test sizes a bit smaller. // The small malloc above guarantees that all these return NULL. printf("Test malloc(0 - 1048576 - N)\n"); static const size_t kMinusMBMinusNTimes = 16384; for ( size_t i = 0; i < kMinusMBMinusNTimes; ++i) { TryAllocExpectFail(zero - 1048576 - i); } // Test sizes at half of size_t. // These might or might not fail to allocate. printf("Test malloc(max/2 +- N)\n"); static const size_t kHalfPlusMinusTimes = 64; const size_t half = (zero - 2) / 2 + 1; for ( size_t i = 0; i < kHalfPlusMinusTimes; ++i) { TryAllocMightFail(half - i); TryAllocMightFail(half + i); } printf("PASS\n"); return 0; } ================================================ FILE: distro/google-perftools-1.7/src/tests/tcmalloc_unittest.cc ================================================ // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Unittest for the TCMalloc implementation. // // * The test consists of a set of threads. // * Each thread maintains a set of allocated objects, with // a bound on the total amount of data in the set. // * Each allocated object's contents are generated by // hashing the object pointer, and a generation count // in the object. This allows us to easily check for // data corruption. // * At any given step, the thread can do any of the following: // a. Allocate an object // b. Increment an object's generation count and update // its contents. // c. Pass the object to another thread // d. Free an object // Also, at the end of every step, object(s) are freed to maintain // the memory upper-bound. // // If this test is compiled with -DDEBUGALLOCATION, then we don't // run some tests that test the inner workings of tcmalloc and // break on debugallocation: that certain allocations are aligned // in a certain way (even though no standard requires it), and that // realloc() tries to minimize copying (which debug allocators don't // care about). #include "config_for_unittests.h" // Complicated ordering requirements. tcmalloc.h defines (indirectly) // _POSIX_C_SOURCE, which it needs so stdlib.h defines posix_memalign. // unistd.h, on the other hand, requires _POSIX_C_SOURCE to be unset, // at least on FreeBSD, in order to define sbrk. The solution // is to #include unistd.h first. This is safe because unistd.h // doesn't sub-include stdlib.h, so we'll still get posix_memalign // when we #include stdlib.h. Blah. #ifdef HAVE_UNISTD_H #include // for testing sbrk hooks #endif #include "tcmalloc.h" // must come early, to pick up posix_memalign #include #include #include #if defined HAVE_STDINT_H #include // for intptr_t #endif #include // for size_t #ifdef HAVE_FCNTL_H #include // for open; used with mmap-hook test #endif #ifdef HAVE_MMAP #include // for testing mmap hooks #endif #ifdef HAVE_MALLOC_H #include // defines pvalloc/etc on cygwin #endif #include #include #include #include #include #include "base/logging.h" #include "base/simple_mutex.h" #include "google/malloc_hook.h" #include "google/malloc_extension.h" #include "google/tcmalloc.h" #include "thread_cache.h" #include "tests/testutil.h" // Windows doesn't define pvalloc and a few other obsolete unix // functions; nor does it define posix_memalign (which is not obsolete). #if defined(_MSC_VER) || defined(__MINGW32__) # define cfree free // don't bother to try to test these obsolete fns # define valloc malloc # define pvalloc malloc // I'd like to map posix_memalign to _aligned_malloc, but _aligned_malloc // must be paired with _aligned_free (not normal free), which is too // invasive a change to how we allocate memory here. So just bail # include # define memalign(alignment, size) malloc(size) # define posix_memalign(pptr, align, size) ((*(pptr)=malloc(size)) ? 0 : ENOMEM) #endif // On systems (like freebsd) that don't define MAP_ANONYMOUS, use the old // form of the name instead. #ifndef MAP_ANONYMOUS # define MAP_ANONYMOUS MAP_ANON #endif #define LOGSTREAM stdout using std::vector; using std::string; DECLARE_double(tcmalloc_release_rate); DECLARE_int32(max_free_queue_size); // in debugallocation.cc DECLARE_int64(tcmalloc_sample_parameter); namespace testing { static const int FLAGS_numtests = 50000; static const int FLAGS_log_every_n_tests = 50000; // log exactly once // Testing parameters static const int FLAGS_lgmaxsize = 16; // lg() of the max size object to alloc static const int FLAGS_numthreads = 10; // Number of threads static const int FLAGS_threadmb = 4; // Max memory size allocated by thread static const int FLAGS_lg_max_memalign = 18; // lg of max alignment for memalign static const double FLAGS_memalign_min_fraction = 0; // min expected% static const double FLAGS_memalign_max_fraction = 0.4; // max expected% static const double FLAGS_memalign_max_alignment_ratio = 6; // alignment/size // Weights of different operations static const int FLAGS_allocweight = 50; // Weight for picking allocation static const int FLAGS_freeweight = 50; // Weight for picking free static const int FLAGS_updateweight = 10; // Weight for picking update static const int FLAGS_passweight = 1; // Weight for passing object static const int kSizeBits = 8 * sizeof(size_t); static const size_t kMaxSize = ~static_cast(0); static const size_t kMaxSignedSize = ((size_t(1) << (kSizeBits-1)) - 1); static const size_t kNotTooBig = 100000; static const size_t kTooBig = kMaxSize; static int news_handled = 0; // Global array of threads class TesterThread; static TesterThread** threads; // To help with generating random numbers class TestHarness { private: // Information kept per type struct Type { string name; int type; int weight; }; public: TestHarness(int seed) : types_(new vector), total_weight_(0), num_tests_(0) { srandom(seed); } ~TestHarness() { delete types_; } // Add operation type with specified weight. When starting a new // iteration, an operation type is picked with probability // proportional to its weight. // // "type" must be non-negative. // "weight" must be non-negative. void AddType(int type, int weight, const char* name); // Call this to get the type of operation for the next iteration. // It returns a random operation type from the set of registered // operations. Returns -1 if tests should finish. int PickType(); // If n == 0, returns the next pseudo-random number in the range [0 .. 0] // If n != 0, returns the next pseudo-random number in the range [0 .. n) int Uniform(int n) { if (n == 0) { return random() * 0; } else { return random() % n; } } // Pick "base" uniformly from range [0,max_log] and then return // "base" random bits. The effect is to pick a number in the range // [0,2^max_log-1] with bias towards smaller numbers. int Skewed(int max_log) { const int base = random() % (max_log+1); return random() % (1 << base); } private: vector* types_; // Registered types int total_weight_; // Total weight of all types int num_tests_; // Num tests run so far }; void TestHarness::AddType(int type, int weight, const char* name) { Type t; t.name = name; t.type = type; t.weight = weight; types_->push_back(t); total_weight_ += weight; } int TestHarness::PickType() { if (num_tests_ >= FLAGS_numtests) return -1; num_tests_++; assert(total_weight_ > 0); // This is a little skewed if total_weight_ doesn't divide 2^31, but it's close int v = Uniform(total_weight_); int i; for (i = 0; i < types_->size(); i++) { v -= (*types_)[i].weight; if (v < 0) { break; } } assert(i < types_->size()); if ((num_tests_ % FLAGS_log_every_n_tests) == 0) { fprintf(LOGSTREAM, " Test %d out of %d: %s\n", num_tests_, FLAGS_numtests, (*types_)[i].name.c_str()); } return (*types_)[i].type; } class AllocatorState : public TestHarness { public: explicit AllocatorState(int seed) : TestHarness(seed) { CHECK_GE(FLAGS_memalign_max_fraction, 0); CHECK_LE(FLAGS_memalign_max_fraction, 1); CHECK_GE(FLAGS_memalign_min_fraction, 0); CHECK_LE(FLAGS_memalign_min_fraction, 1); double delta = FLAGS_memalign_max_fraction - FLAGS_memalign_min_fraction; CHECK_GE(delta, 0); memalign_fraction_ = (Uniform(10000)/10000.0 * delta + FLAGS_memalign_min_fraction); //fprintf(LOGSTREAM, "memalign fraction: %f\n", memalign_fraction_); } virtual ~AllocatorState() {} // Allocate memory. Randomly choose between malloc() or posix_memalign(). void* alloc(size_t size) { if (Uniform(100) < memalign_fraction_ * 100) { // Try a few times to find a reasonable alignment, or fall back on malloc. for (int i = 0; i < 5; i++) { size_t alignment = 1 << Uniform(FLAGS_lg_max_memalign); if (alignment >= sizeof(intptr_t) && (size < sizeof(intptr_t) || alignment < FLAGS_memalign_max_alignment_ratio * size)) { void *result = reinterpret_cast(static_cast(0x1234)); int err = posix_memalign(&result, alignment, size); if (err != 0) { CHECK_EQ(err, ENOMEM); } return err == 0 ? result : NULL; } } } return malloc(size); } private: double memalign_fraction_; }; // Info kept per thread class TesterThread { private: // Info kept per allocated object struct Object { char* ptr; // Allocated pointer int size; // Allocated size int generation; // Generation counter of object contents }; Mutex lock_; // For passing in another thread's obj int id_; // My thread id AllocatorState rnd_; // For generating random numbers vector heap_; // This thread's heap vector passed_; // Pending objects passed from others size_t heap_size_; // Current heap size int locks_ok_; // Number of OK TryLock() ops int locks_failed_; // Number of failed TryLock() ops // Type of operations enum Type { ALLOC, FREE, UPDATE, PASS }; // ACM minimal standard random number generator. (re-entrant.) class ACMRandom { int32 seed_; public: explicit ACMRandom(int32 seed) { seed_ = seed; } int32 Next() { const int32 M = 2147483647L; // 2^31-1 const int32 A = 16807; // In effect, we are computing seed_ = (seed_ * A) % M, where M = 2^31-1 uint32 lo = A * (int32)(seed_ & 0xFFFF); uint32 hi = A * (int32)((uint32)seed_ >> 16); lo += (hi & 0x7FFF) << 16; if (lo > M) { lo &= M; ++lo; } lo += hi >> 15; if (lo > M) { lo &= M; ++lo; } return (seed_ = (int32) lo); } }; public: TesterThread(int id) : id_(id), rnd_(id+1), heap_size_(0), locks_ok_(0), locks_failed_(0) { } virtual ~TesterThread() { if (FLAGS_verbose) fprintf(LOGSTREAM, "Thread %2d: locks %6d ok; %6d trylocks failed\n", id_, locks_ok_, locks_failed_); if (locks_ok_ + locks_failed_ >= 1000) { CHECK_LE(locks_failed_, locks_ok_ / 2); } } virtual void Run() { rnd_.AddType(ALLOC, FLAGS_allocweight, "allocate"); rnd_.AddType(FREE, FLAGS_freeweight, "free"); rnd_.AddType(UPDATE, FLAGS_updateweight, "update"); rnd_.AddType(PASS, FLAGS_passweight, "pass"); while (true) { AcquirePassedObjects(); switch (rnd_.PickType()) { case ALLOC: AllocateObject(); break; case FREE: FreeObject(); break; case UPDATE: UpdateObject(); break; case PASS: PassObject(); break; case -1: goto done; default: assert(NULL == "Unknown type"); } ShrinkHeap(); } done: DeleteHeap(); } // Allocate a new object void AllocateObject() { Object object; object.size = rnd_.Skewed(FLAGS_lgmaxsize); object.ptr = static_cast(rnd_.alloc(object.size)); CHECK(object.ptr); object.generation = 0; FillContents(&object); heap_.push_back(object); heap_size_ += object.size; } // Mutate a random object void UpdateObject() { if (heap_.empty()) return; const int index = rnd_.Uniform(heap_.size()); CheckContents(heap_[index]); heap_[index].generation++; FillContents(&heap_[index]); } // Free a random object void FreeObject() { if (heap_.empty()) return; const int index = rnd_.Uniform(heap_.size()); Object object = heap_[index]; CheckContents(object); free(object.ptr); heap_size_ -= object.size; heap_[index] = heap_[heap_.size()-1]; heap_.pop_back(); } // Delete all objects in the heap void DeleteHeap() { while (!heap_.empty()) { FreeObject(); } } // Free objects until our heap is small enough void ShrinkHeap() { while (heap_size_ > FLAGS_threadmb << 20) { assert(!heap_.empty()); FreeObject(); } } // Pass a random object to another thread void PassObject() { // Pick object to pass if (heap_.empty()) return; const int index = rnd_.Uniform(heap_.size()); Object object = heap_[index]; CheckContents(object); // Pick thread to pass const int tid = rnd_.Uniform(FLAGS_numthreads); TesterThread* thread = threads[tid]; if (thread->lock_.TryLock()) { // Pass the object locks_ok_++; thread->passed_.push_back(object); thread->lock_.Unlock(); heap_size_ -= object.size; heap_[index] = heap_[heap_.size()-1]; heap_.pop_back(); } else { locks_failed_++; } } // Grab any objects passed to this thread by another thread void AcquirePassedObjects() { // We do not create unnecessary contention by always using // TryLock(). Plus we unlock immediately after swapping passed // objects into a local vector. vector copy; { // Locking scope if (!lock_.TryLock()) { locks_failed_++; return; } locks_ok_++; swap(copy, passed_); lock_.Unlock(); } for (int i = 0; i < copy.size(); ++i) { const Object& object = copy[i]; CheckContents(object); heap_.push_back(object); heap_size_ += object.size; } } // Fill object contents according to ptr/generation void FillContents(Object* object) { ACMRandom r(reinterpret_cast(object->ptr) & 0x7fffffff); for (int i = 0; i < object->generation; ++i) { r.Next(); } const char c = static_cast(r.Next()); memset(object->ptr, c, object->size); } // Check object contents void CheckContents(const Object& object) { ACMRandom r(reinterpret_cast(object.ptr) & 0x7fffffff); for (int i = 0; i < object.generation; ++i) { r.Next(); } // For large objects, we just check a prefix/suffix const char expected = static_cast(r.Next()); const int limit1 = object.size < 32 ? object.size : 32; const int start2 = limit1 > object.size - 32 ? limit1 : object.size - 32; for (int i = 0; i < limit1; ++i) { CHECK_EQ(object.ptr[i], expected); } for (int i = start2; i < object.size; ++i) { CHECK_EQ(object.ptr[i], expected); } } }; static void RunThread(int thread_id) { threads[thread_id]->Run(); } static void TryHugeAllocation(size_t s, AllocatorState* rnd) { void* p = rnd->alloc(s); CHECK(p == NULL); // huge allocation s should fail! } static void TestHugeAllocations(AllocatorState* rnd) { // Check that asking for stuff tiny bit smaller than largest possible // size returns NULL. for (size_t i = 0; i < 70000; i += rnd->Uniform(20)) { TryHugeAllocation(kMaxSize - i, rnd); } // Asking for memory sizes near signed/unsigned boundary (kMaxSignedSize) // might work or not, depending on the amount of virtual memory. #ifndef DEBUGALLOCATION // debug allocation takes forever for huge allocs for (size_t i = 0; i < 100; i++) { void* p = NULL; p = rnd->alloc(kMaxSignedSize + i); if (p) free(p); // if: free(NULL) is not necessarily defined p = rnd->alloc(kMaxSignedSize - i); if (p) free(p); } #endif // Check that ReleaseFreeMemory has no visible effect (aka, does not // crash the test): MallocExtension* inst = MallocExtension::instance(); CHECK(inst); inst->ReleaseFreeMemory(); } static void TestCalloc(size_t n, size_t s, bool ok) { char* p = reinterpret_cast(calloc(n, s)); if (FLAGS_verbose) fprintf(LOGSTREAM, "calloc(%"PRIxS", %"PRIxS"): %p\n", n, s, p); if (!ok) { CHECK(p == NULL); // calloc(n, s) should not succeed } else { CHECK(p != NULL); // calloc(n, s) should succeed for (int i = 0; i < n*s; i++) { CHECK(p[i] == '\0'); } free(p); } } // This makes sure that reallocing a small number of bytes in either // direction doesn't cause us to allocate new memory. static void TestRealloc() { #ifndef DEBUGALLOCATION // debug alloc doesn't try to minimize reallocs // When sampling, we always allocate in units of page-size, which // makes reallocs of small sizes do extra work (thus, failing these // checks). Since sampling is random, we turn off sampling to make // sure that doesn't happen to us here. const int64 old_sample_parameter = FLAGS_tcmalloc_sample_parameter; FLAGS_tcmalloc_sample_parameter = 0; // turn off sampling int start_sizes[] = { 100, 1000, 10000, 100000 }; int deltas[] = { 1, -2, 4, -8, 16, -32, 64, -128 }; for (int s = 0; s < sizeof(start_sizes)/sizeof(*start_sizes); ++s) { void* p = malloc(start_sizes[s]); CHECK(p); // The larger the start-size, the larger the non-reallocing delta. for (int d = 0; d < (s+1) * 2; ++d) { void* new_p = realloc(p, start_sizes[s] + deltas[d]); CHECK(p == new_p); // realloc should not allocate new memory } // Test again, but this time reallocing smaller first. for (int d = 0; d < s*2; ++d) { void* new_p = realloc(p, start_sizes[s] - deltas[d]); CHECK(p == new_p); // realloc should not allocate new memory } free(p); } FLAGS_tcmalloc_sample_parameter = old_sample_parameter; #endif } static void TestNewHandler() throw (std::bad_alloc) { ++news_handled; throw std::bad_alloc(); } static void TestOneNew(void* (*func)(size_t)) { // success test try { void* ptr = (*func)(kNotTooBig); if (0 == ptr) { fprintf(LOGSTREAM, "allocation should not have failed.\n"); abort(); } } catch (...) { fprintf(LOGSTREAM, "allocation threw unexpected exception.\n"); abort(); } // failure test // we should always receive a bad_alloc exception try { (*func)(kTooBig); fprintf(LOGSTREAM, "allocation should have failed.\n"); abort(); } catch (const std::bad_alloc&) { // correct } catch (...) { fprintf(LOGSTREAM, "allocation threw unexpected exception.\n"); abort(); } } static void TestNew(void* (*func)(size_t)) { news_handled = 0; // test without new_handler: std::new_handler saved_handler = std::set_new_handler(0); TestOneNew(func); // test with new_handler: std::set_new_handler(TestNewHandler); TestOneNew(func); if (news_handled != 1) { fprintf(LOGSTREAM, "new_handler was not called.\n"); abort(); } std::set_new_handler(saved_handler); } static void TestOneNothrowNew(void* (*func)(size_t, const std::nothrow_t&)) { // success test try { void* ptr = (*func)(kNotTooBig, std::nothrow); if (0 == ptr) { fprintf(LOGSTREAM, "allocation should not have failed.\n"); abort(); } } catch (...) { fprintf(LOGSTREAM, "allocation threw unexpected exception.\n"); abort(); } // failure test // we should always receive a bad_alloc exception try { if ((*func)(kTooBig, std::nothrow) != 0) { fprintf(LOGSTREAM, "allocation should have failed.\n"); abort(); } } catch (...) { fprintf(LOGSTREAM, "nothrow allocation threw unexpected exception.\n"); abort(); } } static void TestNothrowNew(void* (*func)(size_t, const std::nothrow_t&)) { news_handled = 0; // test without new_handler: std::new_handler saved_handler = std::set_new_handler(0); TestOneNothrowNew(func); // test with new_handler: std::set_new_handler(TestNewHandler); TestOneNothrowNew(func); if (news_handled != 1) { fprintf(LOGSTREAM, "nothrow new_handler was not called.\n"); abort(); } std::set_new_handler(saved_handler); } // These are used as callbacks by the sanity-check. Set* and Reset* // register the hook that counts how many times the associated memory // function is called. After each such call, call Verify* to verify // that we used the tcmalloc version of the call, and not the libc. // Note the ... in the hook signature: we don't care what arguments // the hook takes. #define MAKE_HOOK_CALLBACK(hook_type) \ static int g_##hook_type##_calls = 0; \ static void IncrementCallsTo##hook_type(...) { \ g_##hook_type##_calls++; \ } \ static void Verify##hook_type##WasCalled() { \ CHECK_GT(g_##hook_type##_calls, 0); \ g_##hook_type##_calls = 0; /* reset for next call */ \ } \ static MallocHook::hook_type g_old_##hook_type; \ static void Set##hook_type() { \ g_old_##hook_type = MallocHook::Set##hook_type( \ (MallocHook::hook_type)&IncrementCallsTo##hook_type); \ } \ static void Reset##hook_type() { \ CHECK_EQ(MallocHook::Set##hook_type(g_old_##hook_type), \ (MallocHook::hook_type)&IncrementCallsTo##hook_type); \ } // We do one for each hook typedef in malloc_hook.h MAKE_HOOK_CALLBACK(NewHook); MAKE_HOOK_CALLBACK(DeleteHook); MAKE_HOOK_CALLBACK(MmapHook); MAKE_HOOK_CALLBACK(MremapHook); MAKE_HOOK_CALLBACK(MunmapHook); MAKE_HOOK_CALLBACK(SbrkHook); static void TestAlignmentForSize(int size) { fprintf(LOGSTREAM, "Testing alignment of malloc(%d)\n", size); static const int kNum = 100; void* ptrs[kNum]; for (int i = 0; i < kNum; i++) { ptrs[i] = malloc(size); uintptr_t p = reinterpret_cast(ptrs[i]); CHECK((p % sizeof(void*)) == 0); CHECK((p % sizeof(double)) == 0); // Must have 16-byte alignment for large enough objects if (size >= 16) { CHECK((p % 16) == 0); } } for (int i = 0; i < kNum; i++) { free(ptrs[i]); } } static void TestMallocAlignment() { for (int lg = 0; lg < 16; lg++) { TestAlignmentForSize((1<(arg); if (state->ptr >= r->address && state->ptr < r->address + r->length) { CHECK_EQ(r->type, state->expected_type); CHECK_GE(r->length, state->min_size); state->matched = true; } } // Check that at least one of the callbacks from Ranges() contains // the specified address with the specified type, and has size // >= min_size. static void CheckRangeCallback(void* ptr, base::MallocRange::Type type, size_t min_size) { RangeCallbackState state; state.ptr = reinterpret_cast(ptr); state.expected_type = type; state.min_size = min_size; state.matched = false; MallocExtension::instance()->Ranges(&state, RangeCallback); CHECK(state.matched); } } static void TestRanges() { static const int MB = 1048576; void* a = malloc(MB); void* b = malloc(MB); CheckRangeCallback(a, base::MallocRange::INUSE, MB); CheckRangeCallback(b, base::MallocRange::INUSE, MB); free(a); CheckRangeCallback(a, base::MallocRange::FREE, MB); CheckRangeCallback(b, base::MallocRange::INUSE, MB); MallocExtension::instance()->ReleaseFreeMemory(); CheckRangeCallback(a, base::MallocRange::UNMAPPED, MB); CheckRangeCallback(b, base::MallocRange::INUSE, MB); free(b); CheckRangeCallback(a, base::MallocRange::UNMAPPED, MB); CheckRangeCallback(b, base::MallocRange::FREE, MB); } #ifndef DEBUGALLOCATION static size_t GetUnmappedBytes() { size_t bytes; CHECK(MallocExtension::instance()->GetNumericProperty( "tcmalloc.pageheap_unmapped_bytes", &bytes)); return bytes; } #endif static void TestReleaseToSystem() { // Debug allocation mode adds overhead to each allocation which // messes up all the equality tests here. I just disable the // teset in this mode. TODO(csilvers): get it to work for debugalloc? #ifndef DEBUGALLOCATION const double old_tcmalloc_release_rate = FLAGS_tcmalloc_release_rate; FLAGS_tcmalloc_release_rate = 0; static const int MB = 1048576; void* a = malloc(MB); void* b = malloc(MB); MallocExtension::instance()->ReleaseFreeMemory(); size_t starting_bytes = GetUnmappedBytes(); // Calling ReleaseFreeMemory() a second time shouldn't do anything. MallocExtension::instance()->ReleaseFreeMemory(); EXPECT_EQ(starting_bytes, GetUnmappedBytes()); // ReleaseToSystem shouldn't do anything either. MallocExtension::instance()->ReleaseToSystem(MB); EXPECT_EQ(starting_bytes, GetUnmappedBytes()); free(a); // The span to release should be 1MB. MallocExtension::instance()->ReleaseToSystem(MB/2); EXPECT_EQ(starting_bytes + MB, GetUnmappedBytes()); // Should do nothing since the previous call released too much. MallocExtension::instance()->ReleaseToSystem(MB/4); EXPECT_EQ(starting_bytes + MB, GetUnmappedBytes()); free(b); // Use up the extra MB/4 bytes from 'a' and also release 'b'. MallocExtension::instance()->ReleaseToSystem(MB/2); EXPECT_EQ(starting_bytes + 2*MB, GetUnmappedBytes()); // Should do nothing since the previous call released too much. MallocExtension::instance()->ReleaseToSystem(MB/2); EXPECT_EQ(starting_bytes + 2*MB, GetUnmappedBytes()); // Nothing else to release. MallocExtension::instance()->ReleaseFreeMemory(); EXPECT_EQ(starting_bytes + 2*MB, GetUnmappedBytes()); a = malloc(MB); free(a); EXPECT_EQ(starting_bytes + MB, GetUnmappedBytes()); // Releasing less than a page should still trigger a release. MallocExtension::instance()->ReleaseToSystem(1); EXPECT_EQ(starting_bytes + 2*MB, GetUnmappedBytes()); FLAGS_tcmalloc_release_rate = old_tcmalloc_release_rate; #endif // #ifndef DEBUGALLOCATION } bool g_no_memory = false; std::new_handler g_old_handler = NULL; static void OnNoMemory() { g_no_memory = true; std::set_new_handler(g_old_handler); } static void TestSetNewMode() { int old_mode = tc_set_new_mode(1); // DebugAllocation will try to catch huge allocations. We need to avoid this // by requesting a smaller malloc block, that still can't be satisfied. const size_t kHugeRequest = kTooBig - 1024; g_old_handler = std::set_new_handler(&OnNoMemory); g_no_memory = false; void* ret = malloc(kHugeRequest); EXPECT_EQ(NULL, ret); EXPECT_TRUE(g_no_memory); g_old_handler = std::set_new_handler(&OnNoMemory); g_no_memory = false; ret = calloc(1, kHugeRequest); EXPECT_EQ(NULL, ret); EXPECT_TRUE(g_no_memory); g_old_handler = std::set_new_handler(&OnNoMemory); g_no_memory = false; ret = realloc(NULL, kHugeRequest); EXPECT_EQ(NULL, ret); EXPECT_TRUE(g_no_memory); // Not really important, but must be small enough such that kAlignment + // kHugeRequest does not overflow. const int kAlignment = 1 << 5; g_old_handler = std::set_new_handler(&OnNoMemory); g_no_memory = false; ret = memalign(kAlignment, kHugeRequest); EXPECT_EQ(NULL, ret); EXPECT_TRUE(g_no_memory); g_old_handler = std::set_new_handler(&OnNoMemory); g_no_memory = false; EXPECT_EQ(ENOMEM, posix_memalign(&ret, kAlignment, kHugeRequest)); EXPECT_EQ(NULL, ret); EXPECT_TRUE(g_no_memory); tc_set_new_mode(old_mode); } static int RunAllTests(int argc, char** argv) { // Optional argv[1] is the seed AllocatorState rnd(argc > 1 ? atoi(argv[1]) : 100); SetTestResourceLimit(); // TODO(odo): This test has been disabled because it is only by luck that it // does not result in fragmentation. When tcmalloc makes an allocation which // spans previously unused leaves of the pagemap it will allocate and fill in // the leaves to cover the new allocation. The leaves happen to be 256MiB in // the 64-bit build, and with the sbrk allocator these allocations just // happen to fit in one leaf by luck. With other allocators (mmap, // memfs_malloc when used with small pages) the allocations generally span // two leaves and this results in a very bad fragmentation pattern with this // code. The same failure can be forced with the sbrk allocator just by // allocating something on the order of 128MiB prior to starting this test so // that the test allocations straddle a 256MiB boundary. // TODO(csilvers): port MemoryUsage() over so the test can use that #if 0 # include // for getpid() // Allocate and deallocate blocks of increasing sizes to check if the alloc // metadata fragments the memory. (Do not put other allocations/deallocations // before this test, it may break). { size_t memory_usage = MemoryUsage(getpid()); fprintf(LOGSTREAM, "Testing fragmentation\n"); for ( int i = 200; i < 240; ++i ) { int size = i << 20; void *test1 = rnd.alloc(size); CHECK(test1); for ( int j = 0; j < size; j += (1 << 12) ) { static_cast(test1)[j] = 1; } free(test1); } // There may still be a bit of fragmentation at the beginning, until we // reach kPageMapBigAllocationThreshold bytes so we check for // 200 + 240 + margin. CHECK_LT(MemoryUsage(getpid()), memory_usage + (450 << 20) ); } #endif // Check that empty allocation works fprintf(LOGSTREAM, "Testing empty allocation\n"); { void* p1 = rnd.alloc(0); CHECK(p1 != NULL); void* p2 = rnd.alloc(0); CHECK(p2 != NULL); CHECK(p1 != p2); free(p1); free(p2); } // This code stresses some of the memory allocation via STL. // It may call operator delete(void*, nothrow_t). fprintf(LOGSTREAM, "Testing STL use\n"); { std::vector v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(0); std::stable_sort(v.begin(), v.end()); } // Test each of the memory-allocation functions once, just as a sanity-check fprintf(LOGSTREAM, "Sanity-testing all the memory allocation functions\n"); { // We use new-hook and delete-hook to verify we actually called the // tcmalloc version of these routines, and not the libc version. SetNewHook(); // defined as part of MAKE_HOOK_CALLBACK, above SetDeleteHook(); // ditto void* p1 = malloc(10); VerifyNewHookWasCalled(); // Also test the non-standard tc_malloc_size size_t actual_p1_size = tc_malloc_size(p1); CHECK_GE(actual_p1_size, 10); CHECK_LT(actual_p1_size, 100000); // a reasonable upper-bound, I think free(p1); VerifyDeleteHookWasCalled(); p1 = calloc(10, 2); VerifyNewHookWasCalled(); p1 = realloc(p1, 30); VerifyNewHookWasCalled(); VerifyDeleteHookWasCalled(); cfree(p1); // synonym for free VerifyDeleteHookWasCalled(); CHECK_EQ(posix_memalign(&p1, sizeof(p1), 40), 0); VerifyNewHookWasCalled(); free(p1); VerifyDeleteHookWasCalled(); p1 = memalign(sizeof(p1) * 2, 50); VerifyNewHookWasCalled(); free(p1); VerifyDeleteHookWasCalled(); // Windows has _aligned_malloc. Let's test that that's captured too. #if (defined(_MSC_VER) || defined(__MINGW32__)) && !defined(PERFTOOLS_NO_ALIGNED_MALLOC) p1 = _aligned_malloc(sizeof(p1) * 2, 64); VerifyNewHookWasCalled(); _aligned_free(p1); VerifyDeleteHookWasCalled(); #endif p1 = valloc(60); VerifyNewHookWasCalled(); free(p1); VerifyDeleteHookWasCalled(); p1 = pvalloc(70); VerifyNewHookWasCalled(); free(p1); VerifyDeleteHookWasCalled(); char* p2 = new char; VerifyNewHookWasCalled(); delete p2; VerifyDeleteHookWasCalled(); p2 = new char[100]; VerifyNewHookWasCalled(); delete[] p2; VerifyDeleteHookWasCalled(); p2 = new(std::nothrow) char; VerifyNewHookWasCalled(); delete p2; VerifyDeleteHookWasCalled(); p2 = new(std::nothrow) char[100]; VerifyNewHookWasCalled(); delete[] p2; VerifyDeleteHookWasCalled(); // Another way of calling operator new p2 = static_cast(::operator new(100)); VerifyNewHookWasCalled(); ::operator delete(p2); VerifyDeleteHookWasCalled(); // Try to call nothrow's delete too. Compilers use this. p2 = static_cast(::operator new(100, std::nothrow)); VerifyNewHookWasCalled(); ::operator delete(p2, std::nothrow); VerifyDeleteHookWasCalled(); // Test mmap too: both anonymous mmap and mmap of a file // Note that for right now we only override mmap on linux // systems, so those are the only ones for which we check. SetMmapHook(); SetMremapHook(); SetMunmapHook(); #if defined(HAVE_MMAP) && defined(__linux) && \ (defined(__i386__) || defined(__x86_64__)) int size = 8192*2; p1 = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); VerifyMmapHookWasCalled(); p1 = mremap(p1, size, size/2, 0); VerifyMremapHookWasCalled(); size /= 2; munmap(p1, size); VerifyMunmapHookWasCalled(); int fd = open("/dev/zero", O_RDONLY); CHECK_GE(fd, 0); // make sure the open succeeded p1 = mmap(NULL, 8192, PROT_READ, MAP_SHARED, fd, 0); VerifyMmapHookWasCalled(); munmap(p1, 8192); VerifyMunmapHookWasCalled(); close(fd); #else // this is just to quiet the compiler: make sure all fns are called IncrementCallsToMmapHook(); IncrementCallsToMunmapHook(); IncrementCallsToMremapHook(); VerifyMmapHookWasCalled(); VerifyMremapHookWasCalled(); VerifyMunmapHookWasCalled(); #endif // Test sbrk SetSbrkHook(); #if defined(HAVE_SBRK) && defined(__linux) && \ (defined(__i386__) || defined(__x86_64__)) p1 = sbrk(8192); VerifySbrkHookWasCalled(); p1 = sbrk(-8192); VerifySbrkHookWasCalled(); // However, sbrk hook should *not* be called with sbrk(0) p1 = sbrk(0); CHECK_EQ(g_SbrkHook_calls, 0); #else // this is just to quiet the compiler: make sure all fns are called IncrementCallsToSbrkHook(); VerifySbrkHookWasCalled(); #endif // Reset the hooks to what they used to be. These are all // defined as part of MAKE_HOOK_CALLBACK, above. ResetNewHook(); ResetDeleteHook(); ResetMmapHook(); ResetMremapHook(); ResetMunmapHook(); ResetSbrkHook(); } // Check that "lots" of memory can be allocated fprintf(LOGSTREAM, "Testing large allocation\n"); { const int mb_to_allocate = 100; void* p = rnd.alloc(mb_to_allocate << 20); CHECK(p != NULL); // could not allocate free(p); } TestMallocAlignment(); // Check calloc() with various arguments fprintf(LOGSTREAM, "Testing calloc\n"); TestCalloc(0, 0, true); TestCalloc(0, 1, true); TestCalloc(1, 1, true); TestCalloc(1<<10, 0, true); TestCalloc(1<<20, 0, true); TestCalloc(0, 1<<10, true); TestCalloc(0, 1<<20, true); TestCalloc(1<<20, 2, true); TestCalloc(2, 1<<20, true); TestCalloc(1000, 1000, true); TestCalloc(kMaxSize, 2, false); TestCalloc(2, kMaxSize, false); TestCalloc(kMaxSize, kMaxSize, false); TestCalloc(kMaxSignedSize, 3, false); TestCalloc(3, kMaxSignedSize, false); TestCalloc(kMaxSignedSize, kMaxSignedSize, false); // Test that realloc doesn't always reallocate and copy memory. fprintf(LOGSTREAM, "Testing realloc\n"); TestRealloc(); fprintf(LOGSTREAM, "Testing operator new(nothrow).\n"); TestNothrowNew(&::operator new); fprintf(LOGSTREAM, "Testing operator new[](nothrow).\n"); TestNothrowNew(&::operator new[]); fprintf(LOGSTREAM, "Testing operator new.\n"); TestNew(&::operator new); fprintf(LOGSTREAM, "Testing operator new[].\n"); TestNew(&::operator new[]); // Create threads fprintf(LOGSTREAM, "Testing threaded allocation/deallocation (%d threads)\n", FLAGS_numthreads); threads = new TesterThread*[FLAGS_numthreads]; for (int i = 0; i < FLAGS_numthreads; ++i) { threads[i] = new TesterThread(i); } // This runs all the tests at the same time, with a 1M stack size each RunManyThreadsWithId(RunThread, FLAGS_numthreads, 1<<20); for (int i = 0; i < FLAGS_numthreads; ++i) delete threads[i]; // Cleanup // Do the memory intensive tests after threads are done, since exhausting // the available address space can make pthread_create to fail. // Check that huge allocations fail with NULL instead of crashing fprintf(LOGSTREAM, "Testing huge allocations\n"); TestHugeAllocations(&rnd); // Check that large allocations fail with NULL instead of crashing #ifndef DEBUGALLOCATION // debug allocation takes forever for huge allocs fprintf(LOGSTREAM, "Testing out of memory\n"); for (int s = 0; ; s += (10<<20)) { void* large_object = rnd.alloc(s); if (large_object == NULL) break; free(large_object); } #endif TestHugeThreadCache(); TestRanges(); TestReleaseToSystem(); TestSetNewMode(); return 0; } } using testing::RunAllTests; int main(int argc, char** argv) { #ifdef DEBUGALLOCATION // debug allocation takes forever for huge allocs FLAGS_max_free_queue_size = 0; // return freed blocks to tcmalloc immediately #endif RunAllTests(argc, argv); // Test tc_version() fprintf(LOGSTREAM, "Testing tc_version()\n"); int major; int minor; const char* patch; char mmp[64]; const char* human_version = tc_version(&major, &minor, &patch); snprintf(mmp, sizeof(mmp), "%d.%d%s", major, minor, patch); CHECK(!strcmp(PACKAGE_STRING, human_version)); CHECK(!strcmp(PACKAGE_VERSION, mmp)); fprintf(LOGSTREAM, "PASS\n"); } ================================================ FILE: distro/google-perftools-1.7/src/tests/testutil.cc ================================================ // Copyright (c) 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Craig Silverstein // // A few routines that are useful for multiple tests in this directory. #include "config_for_unittests.h" #include // for NULL, abort() // On FreeBSD, if you #include , you have to get stdint first. #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_RESOURCE_H #include #endif #include "tests/testutil.h" // When compiled 64-bit and run on systems with swap several unittests will end // up trying to consume all of RAM+swap, and that can take quite some time. By // limiting the address-space size we get sufficient coverage without blowing // out job limits. void SetTestResourceLimit() { #ifdef HAVE_SYS_RESOURCE_H // The actual resource we need to set varies depending on which flavour of // unix. On Linux we need RLIMIT_AS because that covers the use of mmap. // Otherwise hopefully RLIMIT_RSS is good enough. (Unfortunately 64-bit // and 32-bit headers disagree on the type of these constants!) #ifdef RLIMIT_AS #define USE_RESOURCE RLIMIT_AS #else #define USE_RESOURCE RLIMIT_RSS #endif // Restrict the test to 1GiB, which should fit comfortably well on both // 32-bit and 64-bit hosts, and executes in ~1s. const rlim_t kMaxMem = 1<<30; struct rlimit rlim; if (getrlimit(USE_RESOURCE, &rlim) == 0) { if (rlim.rlim_cur == RLIM_INFINITY || rlim.rlim_cur > kMaxMem) { rlim.rlim_cur = kMaxMem; setrlimit(USE_RESOURCE, &rlim); // ignore result } } #endif /* HAVE_SYS_RESOURCE_H */ } struct FunctionAndId { void (*ptr_to_function)(int); int id; }; #if defined(NO_THREADS) || !(defined(HAVE_PTHREAD) || defined(_WIN32)) extern "C" void RunThread(void (*fn)()) { (*fn)(); } extern "C" void RunManyThreads(void (*fn)(), int count) { // I guess the best we can do is run fn sequentially, 'count' times for (int i = 0; i < count; i++) (*fn)(); } extern "C" void RunManyThreadsWithId(void (*fn)(int), int count, int) { for (int i = 0; i < count; i++) (*fn)(i); // stacksize doesn't make sense in a non-threaded context } #elif defined(_WIN32) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN /* We always want minimal includes */ #endif #include extern "C" { // This helper function has the signature that pthread_create wants. DWORD WINAPI RunFunctionInThread(LPVOID ptr_to_ptr_to_fn) { (**static_cast(ptr_to_ptr_to_fn))(); // runs fn return 0; } DWORD WINAPI RunFunctionInThreadWithId(LPVOID ptr_to_fnid) { FunctionAndId* fn_and_id = static_cast(ptr_to_fnid); (*fn_and_id->ptr_to_function)(fn_and_id->id); // runs fn return 0; } void RunManyThreads(void (*fn)(), int count) { DWORD dummy; HANDLE* hThread = new HANDLE[count]; for (int i = 0; i < count; i++) { hThread[i] = CreateThread(NULL, 0, RunFunctionInThread, &fn, 0, &dummy); if (hThread[i] == NULL) ExitProcess(i); } WaitForMultipleObjects(count, hThread, TRUE, INFINITE); for (int i = 0; i < count; i++) { CloseHandle(hThread[i]); } delete[] hThread; } void RunThread(void (*fn)()) { RunManyThreads(fn, 1); } void RunManyThreadsWithId(void (*fn)(int), int count, int stacksize) { DWORD dummy; HANDLE* hThread = new HANDLE[count]; FunctionAndId* fn_and_ids = new FunctionAndId[count]; for (int i = 0; i < count; i++) { fn_and_ids[i].ptr_to_function = fn; fn_and_ids[i].id = i; hThread[i] = CreateThread(NULL, stacksize, RunFunctionInThreadWithId, &fn_and_ids[i], 0, &dummy); if (hThread[i] == NULL) ExitProcess(i); } WaitForMultipleObjects(count, hThread, TRUE, INFINITE); for (int i = 0; i < count; i++) { CloseHandle(hThread[i]); } delete[] fn_and_ids; delete[] hThread; } } #else // not NO_THREADS, not !HAVE_PTHREAD, not _WIN32 #include #define SAFE_PTHREAD(fncall) do { if ((fncall) != 0) abort(); } while (0) extern "C" { // This helper function has the signature that pthread_create wants. static void* RunFunctionInThread(void *ptr_to_ptr_to_fn) { (**static_cast(ptr_to_ptr_to_fn))(); // runs fn return NULL; } static void* RunFunctionInThreadWithId(void *ptr_to_fnid) { FunctionAndId* fn_and_id = static_cast(ptr_to_fnid); (*fn_and_id->ptr_to_function)(fn_and_id->id); // runs fn return NULL; } // Run a function in a thread of its own and wait for it to finish. // This is useful for tcmalloc testing, because each thread is // handled separately in tcmalloc, so there's interesting stuff to // test even if the threads are not running concurrently. void RunThread(void (*fn)()) { pthread_t thr; // Even though fn is on the stack, it's safe to pass a pointer to it, // because we pthread_join immediately (ie, before RunInThread exits). SAFE_PTHREAD(pthread_create(&thr, NULL, RunFunctionInThread, &fn)); SAFE_PTHREAD(pthread_join(thr, NULL)); } void RunManyThreads(void (*fn)(), int count) { pthread_t* thr = new pthread_t[count]; for (int i = 0; i < count; i++) { SAFE_PTHREAD(pthread_create(&thr[i], NULL, RunFunctionInThread, &fn)); } for (int i = 0; i < count; i++) { SAFE_PTHREAD(pthread_join(thr[i], NULL)); } delete[] thr; } void RunManyThreadsWithId(void (*fn)(int), int count, int stacksize) { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, stacksize); pthread_t* thr = new pthread_t[count]; FunctionAndId* fn_and_ids = new FunctionAndId[count]; for (int i = 0; i < count; i++) { fn_and_ids[i].ptr_to_function = fn; fn_and_ids[i].id = i; SAFE_PTHREAD(pthread_create(&thr[i], &attr, RunFunctionInThreadWithId, &fn_and_ids[i])); } for (int i = 0; i < count; i++) { SAFE_PTHREAD(pthread_join(thr[i], NULL)); } delete[] fn_and_ids; delete[] thr; pthread_attr_destroy(&attr); } } #endif ================================================ FILE: distro/google-perftools-1.7/src/tests/testutil.h ================================================ // Copyright (c) 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Craig Silverstein #ifndef TCMALLOC_TOOLS_TESTUTIL_H_ #define TCMALLOC_TOOLS_TESTUTIL_H_ // Run a function in a thread of its own and wait for it to finish. // The function you pass in must have the signature // void MyFunction(); extern "C" void RunThread(void (*fn)()); // Run a function X times, in X threads, and wait for them all to finish. // The function you pass in must have the signature // void MyFunction(); extern "C" void RunManyThreads(void (*fn)(), int count); // The 'advanced' version: run a function X times, in X threads, and // wait for them all to finish. Give them all the specified stack-size. // (If you're curious why this takes a stacksize and the others don't, // it's because the one client of this fn wanted to specify stacksize. :-) ) // The function you pass in must have the signature // void MyFunction(int idx); // where idx is the index of the thread (which of the X threads this is). extern "C" void RunManyThreadsWithId(void (*fn)(int), int count, int stacksize); // When compiled 64-bit and run on systems with swap several unittests will end // up trying to consume all of RAM+swap, and that can take quite some time. By // limiting the address-space size we get sufficient coverage without blowing // out job limits. void SetTestResourceLimit(); #endif // TCMALLOC_TOOLS_TESTUTIL_H_ ================================================ FILE: distro/google-perftools-1.7/src/tests/thread_dealloc_unittest.cc ================================================ // Copyright (c) 2004, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat // // Check that we do not leak memory when cycling through lots of threads. #include "config_for_unittests.h" #include #ifdef HAVE_UNISTD_H #include // for sleep() #endif #include "base/logging.h" #include #include "tests/testutil.h" // for RunThread() // Size/number of objects to allocate per thread (1 MB per thread) static const int kObjectSize = 1024; static const int kNumObjects = 1024; // Number of threads to create and destroy static const int kNumThreads = 1000; // Allocate lots of stuff static void AllocStuff() { void** objects = new void*[kNumObjects]; for (int i = 0; i < kNumObjects; i++) { objects[i] = malloc(kObjectSize); } for (int i = 0; i < kNumObjects; i++) { free(objects[i]); } delete[] objects; } int main(int argc, char** argv) { static const int kDisplaySize = 1048576; char* display = new char[kDisplaySize]; for (int i = 0; i < kNumThreads; i++) { RunThread(&AllocStuff); if (((i+1) % 200) == 0) { fprintf(stderr, "Iteration: %d of %d\n", (i+1), kNumThreads); MallocExtension::instance()->GetStats(display, kDisplaySize); fprintf(stderr, "%s\n", display); } } delete[] display; printf("PASS\n"); #ifdef HAVE_UNISTD_H sleep(1); // Prevent exit race problem with glibc #endif return 0; } ================================================ FILE: distro/google-perftools-1.7/src/third_party/valgrind.h ================================================ /* -*- c -*- ---------------------------------------------------------------- Notice that the following BSD-style license applies to this one file (valgrind.h) only. The rest of Valgrind is licensed under the terms of the GNU General Public License, version 2, unless otherwise indicated. See the COPYING file in the source distribution for details. ---------------------------------------------------------------- This file is part of Valgrind, a dynamic binary instrumentation framework. Copyright (C) 2000-2008 Julian Seward. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------- Notice that the above BSD-style license applies to this one file (valgrind.h) only. The entire rest of Valgrind is licensed under the terms of the GNU General Public License, version 2. See the COPYING file in the source distribution for details. ---------------------------------------------------------------- */ /* This file is for inclusion into client (your!) code. You can use these macros to manipulate and query Valgrind's execution inside your own programs. The resulting executables will still run without Valgrind, just a little bit more slowly than they otherwise would, but otherwise unchanged. When not running on valgrind, each client request consumes very few (eg. 7) instructions, so the resulting performance loss is negligible unless you plan to execute client requests millions of times per second. Nevertheless, if that is still a problem, you can compile with the NVALGRIND symbol defined (gcc -DNVALGRIND) so that client requests are not even compiled in. */ #ifndef __VALGRIND_H #define __VALGRIND_H #include /* Nb: this file might be included in a file compiled with -ansi. So we can't use C++ style "//" comments nor the "asm" keyword (instead use "__asm__"). */ /* Derive some tags indicating what the target platform is. Note that in this file we're using the compiler's CPP symbols for identifying architectures, which are different to the ones we use within the rest of Valgrind. Note, __powerpc__ is active for both 32 and 64-bit PPC, whereas __powerpc64__ is only active for the latter (on Linux, that is). */ #undef PLAT_x86_linux #undef PLAT_amd64_linux #undef PLAT_ppc32_linux #undef PLAT_ppc64_linux #undef PLAT_ppc32_aix5 #undef PLAT_ppc64_aix5 #if !defined(_AIX) && defined(__i386__) # define PLAT_x86_linux 1 #elif !defined(_AIX) && defined(__x86_64__) # define PLAT_amd64_linux 1 #elif !defined(_AIX) && defined(__powerpc__) && !defined(__powerpc64__) # define PLAT_ppc32_linux 1 #elif !defined(_AIX) && defined(__powerpc__) && defined(__powerpc64__) # define PLAT_ppc64_linux 1 #elif defined(_AIX) && defined(__64BIT__) # define PLAT_ppc64_aix5 1 #elif defined(_AIX) && !defined(__64BIT__) # define PLAT_ppc32_aix5 1 #endif /* If we're not compiling for our target platform, don't generate any inline asms. */ #if !defined(PLAT_x86_linux) && !defined(PLAT_amd64_linux) \ && !defined(PLAT_ppc32_linux) && !defined(PLAT_ppc64_linux) \ && !defined(PLAT_ppc32_aix5) && !defined(PLAT_ppc64_aix5) # if !defined(NVALGRIND) # define NVALGRIND 1 # endif #endif /* ------------------------------------------------------------------ */ /* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS. There is nothing */ /* in here of use to end-users -- skip to the next section. */ /* ------------------------------------------------------------------ */ #if defined(NVALGRIND) /* Define NVALGRIND to completely remove the Valgrind magic sequence from the compiled code (analogous to NDEBUG's effects on assert()) */ #define VALGRIND_DO_CLIENT_REQUEST( \ _zzq_rlval, _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ { \ (_zzq_rlval) = (_zzq_default); \ } #else /* ! NVALGRIND */ /* The following defines the magic code sequences which the JITter spots and handles magically. Don't look too closely at them as they will rot your brain. The assembly code sequences for all architectures is in this one file. This is because this file must be stand-alone, and we don't want to have multiple files. For VALGRIND_DO_CLIENT_REQUEST, we must ensure that the default value gets put in the return slot, so that everything works when this is executed not under Valgrind. Args are passed in a memory block, and so there's no intrinsic limit to the number that could be passed, but it's currently five. The macro args are: _zzq_rlval result lvalue _zzq_default default value (result returned when running on real CPU) _zzq_request request code _zzq_arg1..5 request params The other two macros are used to support function wrapping, and are a lot simpler. VALGRIND_GET_NR_CONTEXT returns the value of the guest's NRADDR pseudo-register and whatever other information is needed to safely run the call original from the wrapper: on ppc64-linux, the R2 value at the divert point is also needed. This information is abstracted into a user-visible type, OrigFn. VALGRIND_CALL_NOREDIR_* behaves the same as the following on the guest, but guarantees that the branch instruction will not be redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64: branch-and-link-to-r11. VALGRIND_CALL_NOREDIR is just text, not a complete inline asm, since it needs to be combined with more magic inline asm stuff to be useful. */ /* ------------------------- x86-linux ------------------------- */ #if defined(PLAT_x86_linux) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "roll $3, %%edi ; roll $13, %%edi\n\t" \ "roll $29, %%edi ; roll $19, %%edi\n\t" #define VALGRIND_DO_CLIENT_REQUEST( \ _zzq_rlval, _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ { volatile unsigned int _zzq_args[6]; \ volatile unsigned int _zzq_result; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %EDX = client_request ( %EAX ) */ \ "xchgl %%ebx,%%ebx" \ : "=d" (_zzq_result) \ : "a" (&_zzq_args[0]), "0" (_zzq_default) \ : "cc", "memory" \ ); \ _zzq_rlval = _zzq_result; \ } #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %EAX = guest_NRADDR */ \ "xchgl %%ecx,%%ecx" \ : "=a" (__addr) \ : \ : "cc", "memory" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_EAX \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir *%EAX */ \ "xchgl %%edx,%%edx\n\t" #endif /* PLAT_x86_linux */ /* ------------------------ amd64-linux ------------------------ */ #if defined(PLAT_amd64_linux) typedef struct { unsigned long long int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rolq $3, %%rdi ; rolq $13, %%rdi\n\t" \ "rolq $61, %%rdi ; rolq $51, %%rdi\n\t" #define VALGRIND_DO_CLIENT_REQUEST( \ _zzq_rlval, _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ { volatile unsigned long long int _zzq_args[6]; \ volatile unsigned long long int _zzq_result; \ _zzq_args[0] = (unsigned long long int)(_zzq_request); \ _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %RDX = client_request ( %RAX ) */ \ "xchgq %%rbx,%%rbx" \ : "=d" (_zzq_result) \ : "a" (&_zzq_args[0]), "0" (_zzq_default) \ : "cc", "memory" \ ); \ _zzq_rlval = _zzq_result; \ } #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned long long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %RAX = guest_NRADDR */ \ "xchgq %%rcx,%%rcx" \ : "=a" (__addr) \ : \ : "cc", "memory" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_RAX \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir *%RAX */ \ "xchgq %%rdx,%%rdx\n\t" #endif /* PLAT_amd64_linux */ /* ------------------------ ppc32-linux ------------------------ */ #if defined(PLAT_ppc32_linux) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rlwinm 0,0,3,0,0 ; rlwinm 0,0,13,0,0\n\t" \ "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t" #define VALGRIND_DO_CLIENT_REQUEST( \ _zzq_rlval, _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ { unsigned int _zzq_args[6]; \ unsigned int _zzq_result; \ unsigned int* _zzq_ptr; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ _zzq_ptr = _zzq_args; \ __asm__ volatile("mr 3,%1\n\t" /*default*/ \ "mr 4,%2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = client_request ( %R4 ) */ \ "or 1,1,1\n\t" \ "mr %0,3" /*result*/ \ : "=b" (_zzq_result) \ : "b" (_zzq_default), "b" (_zzq_ptr) \ : "cc", "memory", "r3", "r4"); \ _zzq_rlval = _zzq_result; \ } #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR */ \ "or 2,2,2\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R11 */ \ "or 3,3,3\n\t" #endif /* PLAT_ppc32_linux */ /* ------------------------ ppc64-linux ------------------------ */ #if defined(PLAT_ppc64_linux) typedef struct { unsigned long long int nraddr; /* where's the code? */ unsigned long long int r2; /* what tocptr do we need? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ "rotldi 0,0,61 ; rotldi 0,0,51\n\t" #define VALGRIND_DO_CLIENT_REQUEST( \ _zzq_rlval, _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ { unsigned long long int _zzq_args[6]; \ register unsigned long long int _zzq_result __asm__("r3"); \ register unsigned long long int* _zzq_ptr __asm__("r4"); \ _zzq_args[0] = (unsigned long long int)(_zzq_request); \ _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \ _zzq_ptr = _zzq_args; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = client_request ( %R4 ) */ \ "or 1,1,1" \ : "=r" (_zzq_result) \ : "0" (_zzq_default), "r" (_zzq_ptr) \ : "cc", "memory"); \ _zzq_rlval = _zzq_result; \ } #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ register unsigned long long int __addr __asm__("r3"); \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR */ \ "or 2,2,2" \ : "=r" (__addr) \ : \ : "cc", "memory" \ ); \ _zzq_orig->nraddr = __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR_GPR2 */ \ "or 4,4,4" \ : "=r" (__addr) \ : \ : "cc", "memory" \ ); \ _zzq_orig->r2 = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R11 */ \ "or 3,3,3\n\t" #endif /* PLAT_ppc64_linux */ /* ------------------------ ppc32-aix5 ------------------------- */ #if defined(PLAT_ppc32_aix5) typedef struct { unsigned int nraddr; /* where's the code? */ unsigned int r2; /* what tocptr do we need? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rlwinm 0,0,3,0,0 ; rlwinm 0,0,13,0,0\n\t" \ "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t" #define VALGRIND_DO_CLIENT_REQUEST( \ _zzq_rlval, _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ { unsigned int _zzq_args[7]; \ register unsigned int _zzq_result; \ register unsigned int* _zzq_ptr; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ _zzq_args[6] = (unsigned int)(_zzq_default); \ _zzq_ptr = _zzq_args; \ __asm__ volatile("mr 4,%1\n\t" \ "lwz 3, 24(4)\n\t" \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = client_request ( %R4 ) */ \ "or 1,1,1\n\t" \ "mr %0,3" \ : "=b" (_zzq_result) \ : "b" (_zzq_ptr) \ : "r3", "r4", "cc", "memory"); \ _zzq_rlval = _zzq_result; \ } #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ register unsigned int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR */ \ "or 2,2,2\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "r3", "cc", "memory" \ ); \ _zzq_orig->nraddr = __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR_GPR2 */ \ "or 4,4,4\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "r3", "cc", "memory" \ ); \ _zzq_orig->r2 = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R11 */ \ "or 3,3,3\n\t" #endif /* PLAT_ppc32_aix5 */ /* ------------------------ ppc64-aix5 ------------------------- */ #if defined(PLAT_ppc64_aix5) typedef struct { unsigned long long int nraddr; /* where's the code? */ unsigned long long int r2; /* what tocptr do we need? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ "rotldi 0,0,61 ; rotldi 0,0,51\n\t" #define VALGRIND_DO_CLIENT_REQUEST( \ _zzq_rlval, _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ { unsigned long long int _zzq_args[7]; \ register unsigned long long int _zzq_result; \ register unsigned long long int* _zzq_ptr; \ _zzq_args[0] = (unsigned int long long)(_zzq_request); \ _zzq_args[1] = (unsigned int long long)(_zzq_arg1); \ _zzq_args[2] = (unsigned int long long)(_zzq_arg2); \ _zzq_args[3] = (unsigned int long long)(_zzq_arg3); \ _zzq_args[4] = (unsigned int long long)(_zzq_arg4); \ _zzq_args[5] = (unsigned int long long)(_zzq_arg5); \ _zzq_args[6] = (unsigned int long long)(_zzq_default); \ _zzq_ptr = _zzq_args; \ __asm__ volatile("mr 4,%1\n\t" \ "ld 3, 48(4)\n\t" \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = client_request ( %R4 ) */ \ "or 1,1,1\n\t" \ "mr %0,3" \ : "=b" (_zzq_result) \ : "b" (_zzq_ptr) \ : "r3", "r4", "cc", "memory"); \ _zzq_rlval = _zzq_result; \ } #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ register unsigned long long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR */ \ "or 2,2,2\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "r3", "cc", "memory" \ ); \ _zzq_orig->nraddr = __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR_GPR2 */ \ "or 4,4,4\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "r3", "cc", "memory" \ ); \ _zzq_orig->r2 = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R11 */ \ "or 3,3,3\n\t" #endif /* PLAT_ppc64_aix5 */ /* Insert assembly code for other platforms here... */ #endif /* NVALGRIND */ /* ------------------------------------------------------------------ */ /* PLATFORM SPECIFICS for FUNCTION WRAPPING. This is all very */ /* ugly. It's the least-worst tradeoff I can think of. */ /* ------------------------------------------------------------------ */ /* This section defines magic (a.k.a appalling-hack) macros for doing guaranteed-no-redirection macros, so as to get from function wrappers to the functions they are wrapping. The whole point is to construct standard call sequences, but to do the call itself with a special no-redirect call pseudo-instruction that the JIT understands and handles specially. This section is long and repetitious, and I can't see a way to make it shorter. The naming scheme is as follows: CALL_FN_{W,v}_{v,W,WW,WWW,WWWW,5W,6W,7W,etc} 'W' stands for "word" and 'v' for "void". Hence there are different macros for calling arity 0, 1, 2, 3, 4, etc, functions, and for each, the possibility of returning a word-typed result, or no result. */ /* Use these to write the name of your wrapper. NOTE: duplicates VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. */ #define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \ _vgwZU_##soname##_##fnname #define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \ _vgwZZ_##soname##_##fnname /* Use this macro from within a wrapper function to collect the context (address and possibly other info) of the original function. Once you have that you can then use it in one of the CALL_FN_ macros. The type of the argument _lval is OrigFn. */ #define VALGRIND_GET_ORIG_FN(_lval) VALGRIND_GET_NR_CONTEXT(_lval) /* Derivatives of the main macros below, for calling functions returning void. */ #define CALL_FN_v_v(fnptr) \ do { volatile unsigned long _junk; \ CALL_FN_W_v(_junk,fnptr); } while (0) #define CALL_FN_v_W(fnptr, arg1) \ do { volatile unsigned long _junk; \ CALL_FN_W_W(_junk,fnptr,arg1); } while (0) #define CALL_FN_v_WW(fnptr, arg1,arg2) \ do { volatile unsigned long _junk; \ CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0) #define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3) \ do { volatile unsigned long _junk; \ CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0) /* ------------------------- x86-linux ------------------------- */ #if defined(PLAT_x86_linux) /* These regs are trashed by the hidden call. No need to mention eax as gcc can already see that, plus causes gcc to bomb. */ #define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx" /* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ "addl $4, %%esp\n" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ "addl $8, %%esp\n" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ "addl $12, %%esp\n" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ "addl $16, %%esp\n" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ "addl $20, %%esp\n" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ "addl $24, %%esp\n" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ "addl $28, %%esp\n" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ "addl $32, %%esp\n" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ "addl $36, %%esp\n" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ "pushl 40(%%eax)\n\t" \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ "addl $40, %%esp\n" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ "pushl 44(%%eax)\n\t" \ "pushl 40(%%eax)\n\t" \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ "addl $44, %%esp\n" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ "pushl 48(%%eax)\n\t" \ "pushl 44(%%eax)\n\t" \ "pushl 40(%%eax)\n\t" \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ "addl $48, %%esp\n" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_x86_linux */ /* ------------------------ amd64-linux ------------------------ */ #if defined(PLAT_amd64_linux) /* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi", \ "rdi", "r8", "r9", "r10", "r11" /* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned long) == 8. */ /* NB 9 Sept 07. There is a nasty kludge here in all these CALL_FN_ macros. In order not to trash the stack redzone, we need to drop %rsp by 128 before the hidden call, and restore afterwards. The nastyness is that it is only by luck that the stack still appears to be unwindable during the hidden call - since then the behaviour of any routine using this macro does not match what the CFI data says. Sigh. Why is this important? Imagine that a wrapper has a stack allocated local, and passes to the hidden call, a pointer to it. Because gcc does not know about the hidden call, it may allocate that local in the redzone. Unfortunately the hidden call may then trash it before it comes to use it. So we must step clear of the redzone, for the duration of the hidden call, to make it safe. Probably the same problem afflicts the other redzone-style ABIs too (ppc64-linux, ppc32-aix5, ppc64-aix5); but for those, the stack is self describing (none of this CFI nonsense) so at least messing with the stack pointer doesn't give a danger of non-unwindable stack. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ "subq $128,%%rsp\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ "addq $128,%%rsp\n\t" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ "subq $128,%%rsp\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ "addq $128,%%rsp\n\t" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ "subq $128,%%rsp\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ "addq $128,%%rsp\n\t" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ "subq $128,%%rsp\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ "addq $128,%%rsp\n\t" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ "subq $128,%%rsp\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ "addq $128,%%rsp\n\t" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ "subq $128,%%rsp\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ "addq $128,%%rsp\n\t" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ "subq $128,%%rsp\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ "addq $128,%%rsp\n\t" \ VALGRIND_CALL_NOREDIR_RAX \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ "subq $128,%%rsp\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ "addq $8, %%rsp\n" \ "addq $128,%%rsp\n\t" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ "subq $128,%%rsp\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ "addq $16, %%rsp\n" \ "addq $128,%%rsp\n\t" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ "subq $128,%%rsp\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ "addq $24, %%rsp\n" \ "addq $128,%%rsp\n\t" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ "subq $128,%%rsp\n\t" \ "pushq 80(%%rax)\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ "addq $32, %%rsp\n" \ "addq $128,%%rsp\n\t" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ "subq $128,%%rsp\n\t" \ "pushq 88(%%rax)\n\t" \ "pushq 80(%%rax)\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ "addq $40, %%rsp\n" \ "addq $128,%%rsp\n\t" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ "subq $128,%%rsp\n\t" \ "pushq 96(%%rax)\n\t" \ "pushq 88(%%rax)\n\t" \ "pushq 80(%%rax)\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ "addq $48, %%rsp\n" \ "addq $128,%%rsp\n\t" \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_amd64_linux */ /* ------------------------ ppc32-linux ------------------------ */ #if defined(PLAT_ppc32_linux) /* This is useful for finding out about the on-stack stuff: extern int f9 ( int,int,int,int,int,int,int,int,int ); extern int f10 ( int,int,int,int,int,int,int,int,int,int ); extern int f11 ( int,int,int,int,int,int,int,int,int,int,int ); extern int f12 ( int,int,int,int,int,int,int,int,int,int,int,int ); int g9 ( void ) { return f9(11,22,33,44,55,66,77,88,99); } int g10 ( void ) { return f10(11,22,33,44,55,66,77,88,99,110); } int g11 ( void ) { return f11(11,22,33,44,55,66,77,88,99,110,121); } int g12 ( void ) { return f12(11,22,33,44,55,66,77,88,99,110,121,132); } */ /* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "lr", "ctr", "xer", \ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ "r11", "r12", "r13" /* These CALL_FN_ macros assume that on ppc32-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "addi 1,1,-16\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "addi 1,1,16\n\t" \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "addi 1,1,-16\n\t" \ /* arg10 */ \ "lwz 3,40(11)\n\t" \ "stw 3,12(1)\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "addi 1,1,16\n\t" \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ _argvec[11] = (unsigned long)arg11; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "addi 1,1,-32\n\t" \ /* arg11 */ \ "lwz 3,44(11)\n\t" \ "stw 3,16(1)\n\t" \ /* arg10 */ \ "lwz 3,40(11)\n\t" \ "stw 3,12(1)\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "addi 1,1,32\n\t" \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ _argvec[11] = (unsigned long)arg11; \ _argvec[12] = (unsigned long)arg12; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "addi 1,1,-32\n\t" \ /* arg12 */ \ "lwz 3,48(11)\n\t" \ "stw 3,20(1)\n\t" \ /* arg11 */ \ "lwz 3,44(11)\n\t" \ "stw 3,16(1)\n\t" \ /* arg10 */ \ "lwz 3,40(11)\n\t" \ "stw 3,12(1)\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "addi 1,1,32\n\t" \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_ppc32_linux */ /* ------------------------ ppc64-linux ------------------------ */ #if defined(PLAT_ppc64_linux) /* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "lr", "ctr", "xer", \ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ "r11", "r12", "r13" /* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned long) == 8. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+0]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)" /* restore tocptr */ \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+1]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)" /* restore tocptr */ \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+2]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)" /* restore tocptr */ \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+3]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)" /* restore tocptr */ \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+4]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)" /* restore tocptr */ \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+5]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)" /* restore tocptr */ \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+6]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)" /* restore tocptr */ \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+7]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)" /* restore tocptr */ \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+8]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)" /* restore tocptr */ \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+9]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-128\n\t" /* expand stack frame */ \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ "addi 1,1,128" /* restore frame */ \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+10]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-128\n\t" /* expand stack frame */ \ /* arg10 */ \ "ld 3,80(11)\n\t" \ "std 3,120(1)\n\t" \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ "addi 1,1,128" /* restore frame */ \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+11]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-144\n\t" /* expand stack frame */ \ /* arg11 */ \ "ld 3,88(11)\n\t" \ "std 3,128(1)\n\t" \ /* arg10 */ \ "ld 3,80(11)\n\t" \ "std 3,120(1)\n\t" \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ "addi 1,1,144" /* restore frame */ \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+12]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ _argvec[2+12] = (unsigned long)arg12; \ __asm__ volatile( \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-144\n\t" /* expand stack frame */ \ /* arg12 */ \ "ld 3,96(11)\n\t" \ "std 3,136(1)\n\t" \ /* arg11 */ \ "ld 3,88(11)\n\t" \ "std 3,128(1)\n\t" \ /* arg10 */ \ "ld 3,80(11)\n\t" \ "std 3,120(1)\n\t" \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ "addi 1,1,144" /* restore frame */ \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_ppc64_linux */ /* ------------------------ ppc32-aix5 ------------------------- */ #if defined(PLAT_ppc32_aix5) /* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "lr", "ctr", "xer", \ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ "r11", "r12", "r13" /* Expand the stack frame, copying enough info that unwinding still works. Trashes r3. */ #define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr) \ "addi 1,1,-" #_n_fr "\n\t" \ "lwz 3," #_n_fr "(1)\n\t" \ "stw 3,0(1)\n\t" #define VG_CONTRACT_FRAME_BY(_n_fr) \ "addi 1,1," #_n_fr "\n\t" /* These CALL_FN_ macros assume that on ppc32-aix5, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+0]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "stw 2,-8(11)\n\t" /* save tocptr */ \ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ "lwz 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "lwz 2,-8(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+1]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "stw 2,-8(11)\n\t" /* save tocptr */ \ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ "lwz 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "lwz 2,-8(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+2]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "stw 2,-8(11)\n\t" /* save tocptr */ \ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ "lwz 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "lwz 2,-8(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+3]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "stw 2,-8(11)\n\t" /* save tocptr */ \ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ "lwz 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "lwz 2,-8(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+4]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "stw 2,-8(11)\n\t" /* save tocptr */ \ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ "lwz 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "lwz 2,-8(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+5]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "stw 2,-8(11)\n\t" /* save tocptr */ \ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ "lwz 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "lwz 2,-8(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+6]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "stw 2,-8(11)\n\t" /* save tocptr */ \ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ "lwz 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "lwz 2,-8(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+7]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "stw 2,-8(11)\n\t" /* save tocptr */ \ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ "lwz 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "lwz 2,-8(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+8]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "stw 2,-8(11)\n\t" /* save tocptr */ \ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ "lwz 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "lwz 2,-8(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+9]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "stw 2,-8(11)\n\t" /* save tocptr */ \ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ VG_EXPAND_FRAME_BY_trashes_r3(64) \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,56(1)\n\t" \ /* args1-8 */ \ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ "lwz 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "lwz 2,-8(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(64) \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+10]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "stw 2,-8(11)\n\t" /* save tocptr */ \ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ VG_EXPAND_FRAME_BY_trashes_r3(64) \ /* arg10 */ \ "lwz 3,40(11)\n\t" \ "stw 3,60(1)\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,56(1)\n\t" \ /* args1-8 */ \ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ "lwz 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "lwz 2,-8(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(64) \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+11]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "stw 2,-8(11)\n\t" /* save tocptr */ \ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ VG_EXPAND_FRAME_BY_trashes_r3(72) \ /* arg11 */ \ "lwz 3,44(11)\n\t" \ "stw 3,64(1)\n\t" \ /* arg10 */ \ "lwz 3,40(11)\n\t" \ "stw 3,60(1)\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,56(1)\n\t" \ /* args1-8 */ \ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ "lwz 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "lwz 2,-8(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(72) \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+12]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ _argvec[2+12] = (unsigned long)arg12; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "stw 2,-8(11)\n\t" /* save tocptr */ \ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ VG_EXPAND_FRAME_BY_trashes_r3(72) \ /* arg12 */ \ "lwz 3,48(11)\n\t" \ "stw 3,68(1)\n\t" \ /* arg11 */ \ "lwz 3,44(11)\n\t" \ "stw 3,64(1)\n\t" \ /* arg10 */ \ "lwz 3,40(11)\n\t" \ "stw 3,60(1)\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,56(1)\n\t" \ /* args1-8 */ \ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ "lwz 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "lwz 2,-8(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(72) \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_ppc32_aix5 */ /* ------------------------ ppc64-aix5 ------------------------- */ #if defined(PLAT_ppc64_aix5) /* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "lr", "ctr", "xer", \ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ "r11", "r12", "r13" /* Expand the stack frame, copying enough info that unwinding still works. Trashes r3. */ #define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr) \ "addi 1,1,-" #_n_fr "\n\t" \ "ld 3," #_n_fr "(1)\n\t" \ "std 3,0(1)\n\t" #define VG_CONTRACT_FRAME_BY(_n_fr) \ "addi 1,1," #_n_fr "\n\t" /* These CALL_FN_ macros assume that on ppc64-aix5, sizeof(unsigned long) == 8. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+0]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+1]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+2]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+3]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+4]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+5]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+6]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+7]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+8]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+9]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ VG_EXPAND_FRAME_BY_trashes_r3(128) \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(128) \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+10]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ VG_EXPAND_FRAME_BY_trashes_r3(128) \ /* arg10 */ \ "ld 3,80(11)\n\t" \ "std 3,120(1)\n\t" \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(128) \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+11]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ VG_EXPAND_FRAME_BY_trashes_r3(144) \ /* arg11 */ \ "ld 3,88(11)\n\t" \ "std 3,128(1)\n\t" \ /* arg10 */ \ "ld 3,80(11)\n\t" \ "std 3,120(1)\n\t" \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(144) \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+12]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ _argvec[2+12] = (unsigned long)arg12; \ __asm__ volatile( \ "mr 11,%1\n\t" \ VG_EXPAND_FRAME_BY_trashes_r3(512) \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ VG_EXPAND_FRAME_BY_trashes_r3(144) \ /* arg12 */ \ "ld 3,96(11)\n\t" \ "std 3,136(1)\n\t" \ /* arg11 */ \ "ld 3,88(11)\n\t" \ "std 3,128(1)\n\t" \ /* arg10 */ \ "ld 3,80(11)\n\t" \ "std 3,120(1)\n\t" \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VG_CONTRACT_FRAME_BY(144) \ VG_CONTRACT_FRAME_BY(512) \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_ppc64_aix5 */ /* ------------------------------------------------------------------ */ /* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS. */ /* */ /* ------------------------------------------------------------------ */ /* Some request codes. There are many more of these, but most are not exposed to end-user view. These are the public ones, all of the form 0x1000 + small_number. Core ones are in the range 0x00000000--0x0000ffff. The non-public ones start at 0x2000. */ /* These macros are used by tools -- they must be public, but don't embed them into other programs. */ #define VG_USERREQ_TOOL_BASE(a,b) \ ((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16)) #define VG_IS_TOOL_USERREQ(a, b, v) \ (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000)) /* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! This enum comprises an ABI exported by Valgrind to programs which use client requests. DO NOT CHANGE THE ORDER OF THESE ENTRIES, NOR DELETE ANY -- add new ones at the end. */ typedef enum { VG_USERREQ__RUNNING_ON_VALGRIND = 0x1001, VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002, /* These allow any function to be called from the simulated CPU but run on the real CPU. Nb: the first arg passed to the function is always the ThreadId of the running thread! So CLIENT_CALL0 actually requires a 1 arg function, etc. */ VG_USERREQ__CLIENT_CALL0 = 0x1101, VG_USERREQ__CLIENT_CALL1 = 0x1102, VG_USERREQ__CLIENT_CALL2 = 0x1103, VG_USERREQ__CLIENT_CALL3 = 0x1104, /* Can be useful in regression testing suites -- eg. can send Valgrind's output to /dev/null and still count errors. */ VG_USERREQ__COUNT_ERRORS = 0x1201, /* These are useful and can be interpreted by any tool that tracks malloc() et al, by using vg_replace_malloc.c. */ VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301, VG_USERREQ__FREELIKE_BLOCK = 0x1302, /* Memory pool support. */ VG_USERREQ__CREATE_MEMPOOL = 0x1303, VG_USERREQ__DESTROY_MEMPOOL = 0x1304, VG_USERREQ__MEMPOOL_ALLOC = 0x1305, VG_USERREQ__MEMPOOL_FREE = 0x1306, VG_USERREQ__MEMPOOL_TRIM = 0x1307, VG_USERREQ__MOVE_MEMPOOL = 0x1308, VG_USERREQ__MEMPOOL_CHANGE = 0x1309, VG_USERREQ__MEMPOOL_EXISTS = 0x130a, /* Allow printfs to valgrind log. */ VG_USERREQ__PRINTF = 0x1401, VG_USERREQ__PRINTF_BACKTRACE = 0x1402, /* Stack support. */ VG_USERREQ__STACK_REGISTER = 0x1501, VG_USERREQ__STACK_DEREGISTER = 0x1502, VG_USERREQ__STACK_CHANGE = 0x1503 } Vg_ClientRequest; #if !defined(__GNUC__) # define __extension__ /* */ #endif /* Returns the number of Valgrinds this code is running under. That is, 0 if running natively, 1 if running under Valgrind, 2 if running under Valgrind which is running under another Valgrind, etc. */ #define RUNNING_ON_VALGRIND __extension__ \ ({unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* if not */, \ VG_USERREQ__RUNNING_ON_VALGRIND, \ 0, 0, 0, 0, 0); \ _qzz_res; \ }) /* Discard translation of code in the range [_qzz_addr .. _qzz_addr + _qzz_len - 1]. Useful if you are debugging a JITter or some such, since it provides a way to make sure valgrind will retranslate the invalidated area. Returns no value. */ #define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \ {unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ VG_USERREQ__DISCARD_TRANSLATIONS, \ _qzz_addr, _qzz_len, 0, 0, 0); \ } /* These requests are for getting Valgrind itself to print something. Possibly with a backtrace. This is a really ugly hack. */ #if defined(NVALGRIND) # define VALGRIND_PRINTF(...) # define VALGRIND_PRINTF_BACKTRACE(...) #else /* NVALGRIND */ /* Modern GCC will optimize the static routine out if unused, and unused attribute will shut down warnings about it. */ static int VALGRIND_PRINTF(const char *format, ...) __attribute__((format(__printf__, 1, 2), __unused__)); static int VALGRIND_PRINTF(const char *format, ...) { unsigned long _qzz_res; va_list vargs; va_start(vargs, format); VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, VG_USERREQ__PRINTF, (unsigned long)format, (unsigned long)vargs, 0, 0, 0); va_end(vargs); return (int)_qzz_res; } static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...) __attribute__((format(__printf__, 1, 2), __unused__)); static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...) { unsigned long _qzz_res; va_list vargs; va_start(vargs, format); VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, VG_USERREQ__PRINTF_BACKTRACE, (unsigned long)format, (unsigned long)vargs, 0, 0, 0); va_end(vargs); return (int)_qzz_res; } #endif /* NVALGRIND */ /* These requests allow control to move from the simulated CPU to the real CPU, calling an arbitary function. Note that the current ThreadId is inserted as the first argument. So this call: VALGRIND_NON_SIMD_CALL2(f, arg1, arg2) requires f to have this signature: Word f(Word tid, Word arg1, Word arg2) where "Word" is a word-sized type. Note that these client requests are not entirely reliable. For example, if you call a function with them that subsequently calls printf(), there's a high chance Valgrind will crash. Generally, your prospects of these working are made higher if the called function does not refer to any global variables, and does not refer to any libc or other functions (printf et al). Any kind of entanglement with libc or dynamic linking is likely to have a bad outcome, for tricky reasons which we've grappled with a lot in the past. */ #define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \ __extension__ \ ({unsigned long _qyy_res; \ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ VG_USERREQ__CLIENT_CALL0, \ _qyy_fn, \ 0, 0, 0, 0); \ _qyy_res; \ }) #define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \ __extension__ \ ({unsigned long _qyy_res; \ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ VG_USERREQ__CLIENT_CALL1, \ _qyy_fn, \ _qyy_arg1, 0, 0, 0); \ _qyy_res; \ }) #define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \ __extension__ \ ({unsigned long _qyy_res; \ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ VG_USERREQ__CLIENT_CALL2, \ _qyy_fn, \ _qyy_arg1, _qyy_arg2, 0, 0); \ _qyy_res; \ }) #define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \ __extension__ \ ({unsigned long _qyy_res; \ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ VG_USERREQ__CLIENT_CALL3, \ _qyy_fn, \ _qyy_arg1, _qyy_arg2, \ _qyy_arg3, 0); \ _qyy_res; \ }) /* Counts the number of errors that have been recorded by a tool. Nb: the tool must record the errors with VG_(maybe_record_error)() or VG_(unique_error)() for them to be counted. */ #define VALGRIND_COUNT_ERRORS \ __extension__ \ ({unsigned int _qyy_res; \ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ VG_USERREQ__COUNT_ERRORS, \ 0, 0, 0, 0, 0); \ _qyy_res; \ }) /* Mark a block of memory as having been allocated by a malloc()-like function. `addr' is the start of the usable block (ie. after any redzone) `rzB' is redzone size if the allocator can apply redzones; use '0' if not. Adding redzones makes it more likely Valgrind will spot block overruns. `is_zeroed' indicates if the memory is zeroed, as it is for calloc(). Put it immediately after the point where a block is allocated. If you're using Memcheck: If you're allocating memory via superblocks, and then handing out small chunks of each superblock, if you don't have redzones on your small blocks, it's worth marking the superblock with VALGRIND_MAKE_MEM_NOACCESS when it's created, so that block overruns are detected. But if you can put redzones on, it's probably better to not do this, so that messages for small overruns are described in terms of the small block rather than the superblock (but if you have a big overrun that skips over a redzone, you could miss an error this way). See memcheck/tests/custom_alloc.c for an example. WARNING: if your allocator uses malloc() or 'new' to allocate superblocks, rather than mmap() or brk(), this will not work properly -- you'll likely get assertion failures during leak detection. This is because Valgrind doesn't like seeing overlapping heap blocks. Sorry. Nb: block must be freed via a free()-like function specified with VALGRIND_FREELIKE_BLOCK or mismatch errors will occur. */ #define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \ {unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ VG_USERREQ__MALLOCLIKE_BLOCK, \ addr, sizeB, rzB, is_zeroed, 0); \ } /* Mark a block of memory as having been freed by a free()-like function. `rzB' is redzone size; it must match that given to VALGRIND_MALLOCLIKE_BLOCK. Memory not freed will be detected by the leak checker. Put it immediately after the point where the block is freed. */ #define VALGRIND_FREELIKE_BLOCK(addr, rzB) \ {unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ VG_USERREQ__FREELIKE_BLOCK, \ addr, rzB, 0, 0, 0); \ } /* Create a memory pool. */ #define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \ {unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ VG_USERREQ__CREATE_MEMPOOL, \ pool, rzB, is_zeroed, 0, 0); \ } /* Destroy a memory pool. */ #define VALGRIND_DESTROY_MEMPOOL(pool) \ {unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ VG_USERREQ__DESTROY_MEMPOOL, \ pool, 0, 0, 0, 0); \ } /* Associate a piece of memory with a memory pool. */ #define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \ {unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ VG_USERREQ__MEMPOOL_ALLOC, \ pool, addr, size, 0, 0); \ } /* Disassociate a piece of memory from a memory pool. */ #define VALGRIND_MEMPOOL_FREE(pool, addr) \ {unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ VG_USERREQ__MEMPOOL_FREE, \ pool, addr, 0, 0, 0); \ } /* Disassociate any pieces outside a particular range. */ #define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \ {unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ VG_USERREQ__MEMPOOL_TRIM, \ pool, addr, size, 0, 0); \ } /* Resize and/or move a piece associated with a memory pool. */ #define VALGRIND_MOVE_MEMPOOL(poolA, poolB) \ {unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ VG_USERREQ__MOVE_MEMPOOL, \ poolA, poolB, 0, 0, 0); \ } /* Resize and/or move a piece associated with a memory pool. */ #define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size) \ {unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ VG_USERREQ__MEMPOOL_CHANGE, \ pool, addrA, addrB, size, 0); \ } /* Return 1 if a mempool exists, else 0. */ #define VALGRIND_MEMPOOL_EXISTS(pool) \ ({unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ VG_USERREQ__MEMPOOL_EXISTS, \ pool, 0, 0, 0, 0); \ _qzz_res; \ }) /* Mark a piece of memory as being a stack. Returns a stack id. */ #define VALGRIND_STACK_REGISTER(start, end) \ ({unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ VG_USERREQ__STACK_REGISTER, \ start, end, 0, 0, 0); \ _qzz_res; \ }) /* Unmark the piece of memory associated with a stack id as being a stack. */ #define VALGRIND_STACK_DEREGISTER(id) \ {unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ VG_USERREQ__STACK_DEREGISTER, \ id, 0, 0, 0, 0); \ } /* Change the start and end address of the stack id. */ #define VALGRIND_STACK_CHANGE(id, start, end) \ {unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ VG_USERREQ__STACK_CHANGE, \ id, start, end, 0, 0); \ } #undef PLAT_x86_linux #undef PLAT_amd64_linux #undef PLAT_ppc32_linux #undef PLAT_ppc64_linux #undef PLAT_ppc32_aix5 #undef PLAT_ppc64_aix5 #endif /* __VALGRIND_H */ ================================================ FILE: distro/google-perftools-1.7/src/thread_cache.cc ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Ken Ashcraft #include #ifdef HAVE_INTTYPES_H #include #endif #include // for min and max #include "thread_cache.h" #include "maybe_threads.h" using std::min; using std::max; DEFINE_int64(tcmalloc_max_total_thread_cache_bytes, EnvToInt64("TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES", kDefaultOverallThreadCacheSize), "Bound on the total amount of bytes allocated to " "thread caches. This bound is not strict, so it is possible " "for the cache to go over this bound in certain circumstances. "); namespace tcmalloc { static bool phinited = false; volatile size_t ThreadCache::per_thread_cache_size_ = kMaxThreadCacheSize; size_t ThreadCache::overall_thread_cache_size_ = kDefaultOverallThreadCacheSize; ssize_t ThreadCache::unclaimed_cache_space_ = kDefaultOverallThreadCacheSize; PageHeapAllocator threadcache_allocator; ThreadCache* ThreadCache::thread_heaps_ = NULL; int ThreadCache::thread_heap_count_ = 0; ThreadCache* ThreadCache::next_memory_steal_ = NULL; #ifdef HAVE_TLS __thread ThreadCache* ThreadCache::threadlocal_heap_ # ifdef HAVE___ATTRIBUTE__ __attribute__ ((tls_model ("initial-exec"))) # endif ; #endif bool ThreadCache::tsd_inited_ = false; pthread_key_t ThreadCache::heap_key_; #if defined(HAVE_TLS) bool kernel_supports_tls = false; // be conservative # if !HAVE_DECL_UNAME // if too old for uname, probably too old for TLS void CheckIfKernelSupportsTLS() { kernel_supports_tls = false; } # else # include // DECL_UNAME checked for too void CheckIfKernelSupportsTLS() { struct utsname buf; if (uname(&buf) != 0) { // should be impossible MESSAGE("uname failed assuming no TLS support (errno=%d)\n", errno); kernel_supports_tls = false; } else if (strcasecmp(buf.sysname, "linux") == 0) { // The linux case: the first kernel to support TLS was 2.6.0 if (buf.release[0] < '2' && buf.release[1] == '.') // 0.x or 1.x kernel_supports_tls = false; else if (buf.release[0] == '2' && buf.release[1] == '.' && buf.release[2] >= '0' && buf.release[2] < '6' && buf.release[3] == '.') // 2.0 - 2.5 kernel_supports_tls = false; else kernel_supports_tls = true; } else { // some other kernel, we'll be optimisitic kernel_supports_tls = true; } // TODO(csilvers): VLOG(1) the tls status once we support RAW_VLOG } # endif // HAVE_DECL_UNAME #endif // HAVE_TLS void ThreadCache::Init(pthread_t tid) { size_ = 0; max_size_ = 0; IncreaseCacheLimitLocked(); if (max_size_ == 0) { // There isn't enough memory to go around. Just give the minimum to // this thread. max_size_ = kMinThreadCacheSize; // Take unclaimed_cache_space_ negative. unclaimed_cache_space_ -= kMinThreadCacheSize; ASSERT(unclaimed_cache_space_ < 0); } next_ = NULL; prev_ = NULL; tid_ = tid; in_setspecific_ = false; for (size_t cl = 0; cl < kNumClasses; ++cl) { list_[cl].Init(); } uint32_t sampler_seed; memcpy(&sampler_seed, &tid, sizeof(sampler_seed)); sampler_.Init(sampler_seed); } void ThreadCache::Cleanup() { // Put unused memory back into central cache for (int cl = 0; cl < kNumClasses; ++cl) { if (list_[cl].length() > 0) { ReleaseToCentralCache(&list_[cl], cl, list_[cl].length()); } } } // Remove some objects of class "cl" from central cache and add to thread heap. // On success, return the first object for immediate use; otherwise return NULL. void* ThreadCache::FetchFromCentralCache(size_t cl, size_t byte_size) { FreeList* list = &list_[cl]; ASSERT(list->empty()); const int batch_size = Static::sizemap()->num_objects_to_move(cl); const int num_to_move = min(list->max_length(), batch_size); void *start, *end; int fetch_count = Static::central_cache()[cl].RemoveRange( &start, &end, num_to_move); ASSERT((start == NULL) == (fetch_count == 0)); if (--fetch_count >= 0) { size_ += byte_size * fetch_count; list->PushRange(fetch_count, SLL_Next(start), end); } // Increase max length slowly up to batch_size. After that, // increase by batch_size in one shot so that the length is a // multiple of batch_size. if (list->max_length() < batch_size) { list->set_max_length(list->max_length() + 1); } else { // Don't let the list get too long. In 32 bit builds, the length // is represented by a 16 bit int, so we need to watch out for // integer overflow. int new_length = min(list->max_length() + batch_size, kMaxDynamicFreeListLength); // The list's max_length must always be a multiple of batch_size, // and kMaxDynamicFreeListLength is not necessarily a multiple // of batch_size. new_length -= new_length % batch_size; ASSERT(new_length % batch_size == 0); list->set_max_length(new_length); } return start; } void ThreadCache::ListTooLong(FreeList* list, size_t cl) { const int batch_size = Static::sizemap()->num_objects_to_move(cl); ReleaseToCentralCache(list, cl, batch_size); // If the list is too long, we need to transfer some number of // objects to the central cache. Ideally, we would transfer // num_objects_to_move, so the code below tries to make max_length // converge on num_objects_to_move. if (list->max_length() < batch_size) { // Slow start the max_length so we don't overreserve. list->set_max_length(list->max_length() + 1); } else if (list->max_length() > batch_size) { // If we consistently go over max_length, shrink max_length. If we don't // shrink it, some amount of memory will always stay in this freelist. list->set_length_overages(list->length_overages() + 1); if (list->length_overages() > kMaxOverages) { ASSERT(list->max_length() > batch_size); list->set_max_length(list->max_length() - batch_size); list->set_length_overages(0); } } } // Remove some objects of class "cl" from thread heap and add to central cache void ThreadCache::ReleaseToCentralCache(FreeList* src, size_t cl, int N) { ASSERT(src == &list_[cl]); if (N > src->length()) N = src->length(); size_t delta_bytes = N * Static::sizemap()->ByteSizeForClass(cl); // We return prepackaged chains of the correct size to the central cache. // TODO: Use the same format internally in the thread caches? int batch_size = Static::sizemap()->num_objects_to_move(cl); while (N > batch_size) { void *tail, *head; src->PopRange(batch_size, &head, &tail); Static::central_cache()[cl].InsertRange(head, tail, batch_size); N -= batch_size; } void *tail, *head; src->PopRange(N, &head, &tail); Static::central_cache()[cl].InsertRange(head, tail, N); size_ -= delta_bytes; } // Release idle memory to the central cache void ThreadCache::Scavenge() { // If the low-water mark for the free list is L, it means we would // not have had to allocate anything from the central cache even if // we had reduced the free list size by L. We aim to get closer to // that situation by dropping L/2 nodes from the free list. This // may not release much memory, but if so we will call scavenge again // pretty soon and the low-water marks will be high on that call. //int64 start = CycleClock::Now(); for (int cl = 0; cl < kNumClasses; cl++) { FreeList* list = &list_[cl]; const int lowmark = list->lowwatermark(); if (lowmark > 0) { const int drop = (lowmark > 1) ? lowmark/2 : 1; ReleaseToCentralCache(list, cl, drop); // Shrink the max length if it isn't used. Only shrink down to // batch_size -- if the thread was active enough to get the max_length // above batch_size, it will likely be that active again. If // max_length shinks below batch_size, the thread will have to // go through the slow-start behavior again. The slow-start is useful // mainly for threads that stay relatively idle for their entire // lifetime. const int batch_size = Static::sizemap()->num_objects_to_move(cl); if (list->max_length() > batch_size) { list->set_max_length( max(list->max_length() - batch_size, batch_size)); } } list->clear_lowwatermark(); } IncreaseCacheLimit(); // int64 finish = CycleClock::Now(); // CycleTimer ct; // MESSAGE("GC: %.0f ns\n", ct.CyclesToUsec(finish-start)*1000.0); } void ThreadCache::IncreaseCacheLimit() { SpinLockHolder h(Static::pageheap_lock()); IncreaseCacheLimitLocked(); } void ThreadCache::IncreaseCacheLimitLocked() { if (unclaimed_cache_space_ > 0) { // Possibly make unclaimed_cache_space_ negative. unclaimed_cache_space_ -= kStealAmount; max_size_ += kStealAmount; return; } // Don't hold pageheap_lock too long. Try to steal from 10 other // threads before giving up. The i < 10 condition also prevents an // infinite loop in case none of the existing thread heaps are // suitable places to steal from. for (int i = 0; i < 10; ++i, next_memory_steal_ = next_memory_steal_->next_) { // Reached the end of the linked list. Start at the beginning. if (next_memory_steal_ == NULL) { ASSERT(thread_heaps_ != NULL); next_memory_steal_ = thread_heaps_; } if (next_memory_steal_ == this || next_memory_steal_->max_size_ <= kMinThreadCacheSize) { continue; } next_memory_steal_->max_size_ -= kStealAmount; max_size_ += kStealAmount; next_memory_steal_ = next_memory_steal_->next_; return; } } int ThreadCache::GetSamplePeriod() { return sampler_.GetSamplePeriod(); } void ThreadCache::InitModule() { SpinLockHolder h(Static::pageheap_lock()); if (!phinited) { Static::InitStaticVars(); threadcache_allocator.Init(); phinited = 1; } } void ThreadCache::InitTSD() { ASSERT(!tsd_inited_); perftools_pthread_key_create(&heap_key_, DestroyThreadCache); tsd_inited_ = true; // We may have used a fake pthread_t for the main thread. Fix it. pthread_t zero; memset(&zero, 0, sizeof(zero)); SpinLockHolder h(Static::pageheap_lock()); for (ThreadCache* h = thread_heaps_; h != NULL; h = h->next_) { if (h->tid_ == zero) { h->tid_ = pthread_self(); } } } ThreadCache* ThreadCache::CreateCacheIfNecessary() { // Initialize per-thread data if necessary ThreadCache* heap = NULL; { SpinLockHolder h(Static::pageheap_lock()); // Early on in glibc's life, we cannot even call pthread_self() pthread_t me; if (!tsd_inited_) { memset(&me, 0, sizeof(me)); } else { me = pthread_self(); } // This may be a recursive malloc call from pthread_setspecific() // In that case, the heap for this thread has already been created // and added to the linked list. So we search for that first. for (ThreadCache* h = thread_heaps_; h != NULL; h = h->next_) { if (h->tid_ == me) { heap = h; break; } } if (heap == NULL) heap = NewHeap(me); } // We call pthread_setspecific() outside the lock because it may // call malloc() recursively. We check for the recursive call using // the "in_setspecific_" flag so that we can avoid calling // pthread_setspecific() if we are already inside pthread_setspecific(). if (!heap->in_setspecific_ && tsd_inited_) { heap->in_setspecific_ = true; perftools_pthread_setspecific(heap_key_, heap); #ifdef HAVE_TLS // Also keep a copy in __thread for faster retrieval threadlocal_heap_ = heap; #endif heap->in_setspecific_ = false; } return heap; } ThreadCache* ThreadCache::NewHeap(pthread_t tid) { // Create the heap and add it to the linked list ThreadCache *heap = threadcache_allocator.New(); heap->Init(tid); heap->next_ = thread_heaps_; heap->prev_ = NULL; if (thread_heaps_ != NULL) { thread_heaps_->prev_ = heap; } else { // This is the only thread heap at the momment. ASSERT(next_memory_steal_ == NULL); next_memory_steal_ = heap; } thread_heaps_ = heap; thread_heap_count_++; return heap; } void ThreadCache::BecomeIdle() { if (!tsd_inited_) return; // No caches yet ThreadCache* heap = GetThreadHeap(); if (heap == NULL) return; // No thread cache to remove if (heap->in_setspecific_) return; // Do not disturb the active caller heap->in_setspecific_ = true; perftools_pthread_setspecific(heap_key_, NULL); #ifdef HAVE_TLS // Also update the copy in __thread threadlocal_heap_ = NULL; #endif heap->in_setspecific_ = false; if (GetThreadHeap() == heap) { // Somehow heap got reinstated by a recursive call to malloc // from pthread_setspecific. We give up in this case. return; } // We can now get rid of the heap DeleteCache(heap); } void ThreadCache::DestroyThreadCache(void* ptr) { // Note that "ptr" cannot be NULL since pthread promises not // to invoke the destructor on NULL values, but for safety, // we check anyway. if (ptr == NULL) return; #ifdef HAVE_TLS // Prevent fast path of GetThreadHeap() from returning heap. threadlocal_heap_ = NULL; #endif DeleteCache(reinterpret_cast(ptr)); } void ThreadCache::DeleteCache(ThreadCache* heap) { // Remove all memory from heap heap->Cleanup(); // Remove from linked list SpinLockHolder h(Static::pageheap_lock()); if (heap->next_ != NULL) heap->next_->prev_ = heap->prev_; if (heap->prev_ != NULL) heap->prev_->next_ = heap->next_; if (thread_heaps_ == heap) thread_heaps_ = heap->next_; thread_heap_count_--; if (next_memory_steal_ == heap) next_memory_steal_ = heap->next_; if (next_memory_steal_ == NULL) next_memory_steal_ = thread_heaps_; unclaimed_cache_space_ += heap->max_size_; threadcache_allocator.Delete(heap); } void ThreadCache::RecomputePerThreadCacheSize() { // Divide available space across threads int n = thread_heap_count_ > 0 ? thread_heap_count_ : 1; size_t space = overall_thread_cache_size_ / n; // Limit to allowed range if (space < kMinThreadCacheSize) space = kMinThreadCacheSize; if (space > kMaxThreadCacheSize) space = kMaxThreadCacheSize; double ratio = space / max(1, per_thread_cache_size_); size_t claimed = 0; for (ThreadCache* h = thread_heaps_; h != NULL; h = h->next_) { // Increasing the total cache size should not circumvent the // slow-start growth of max_size_. if (ratio < 1.0) { h->max_size_ = static_cast(h->max_size_ * ratio); } claimed += h->max_size_; } unclaimed_cache_space_ = overall_thread_cache_size_ - claimed; per_thread_cache_size_ = space; // TCMalloc_MESSAGE(__FILE__, __LINE__, "Threads %d => cache size %8d\n", n, int(space)); } void ThreadCache::Print(TCMalloc_Printer* out) const { for (int cl = 0; cl < kNumClasses; ++cl) { out->printf(" %5" PRIuS " : %4" PRIuS " len; %4d lo; %4"PRIuS " max; %4"PRIuS" overages;\n", Static::sizemap()->ByteSizeForClass(cl), list_[cl].length(), list_[cl].lowwatermark(), list_[cl].max_length(), list_[cl].length_overages()); } } void ThreadCache::PrintThreads(TCMalloc_Printer* out) { size_t actual_limit = 0; for (ThreadCache* h = thread_heaps_; h != NULL; h = h->next_) { h->Print(out); actual_limit += h->max_size_; } out->printf("ThreadCache overall: %"PRIuS ", unclaimed: %"PRIuS ", actual: %"PRIuS"\n", overall_thread_cache_size_, unclaimed_cache_space_, actual_limit); } void ThreadCache::GetThreadStats(uint64_t* total_bytes, uint64_t* class_count) { for (ThreadCache* h = thread_heaps_; h != NULL; h = h->next_) { *total_bytes += h->Size(); if (class_count) { for (int cl = 0; cl < kNumClasses; ++cl) { class_count[cl] += h->freelist_length(cl); } } } } void ThreadCache::set_overall_thread_cache_size(size_t new_size) { // Clip the value to a reasonable range if (new_size < kMinThreadCacheSize) new_size = kMinThreadCacheSize; if (new_size > (1<<30)) new_size = (1<<30); // Limit to 1GB overall_thread_cache_size_ = new_size; RecomputePerThreadCacheSize(); } } // namespace tcmalloc ================================================ FILE: distro/google-perftools-1.7/src/thread_cache.h ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Sanjay Ghemawat #ifndef TCMALLOC_THREAD_CACHE_H_ #define TCMALLOC_THREAD_CACHE_H_ #include #ifdef HAVE_PTHREAD #include #endif #include "common.h" #include "linked_list.h" #include "maybe_threads.h" #include "page_heap_allocator.h" #include "sampler.h" #include "static_vars.h" namespace tcmalloc { // Even if we have support for thread-local storage in the compiler // and linker, the OS may not support it. We need to check that at // runtime. Right now, we have to keep a manual set of "bad" OSes. #if defined(HAVE_TLS) extern bool kernel_supports_tls; // defined in thread_cache.cc void CheckIfKernelSupportsTLS(); inline bool KernelSupportsTLS() { return kernel_supports_tls; } #endif // HAVE_TLS //------------------------------------------------------------------- // Data kept per thread //------------------------------------------------------------------- class ThreadCache { public: // All ThreadCache objects are kept in a linked list (for stats collection) ThreadCache* next_; ThreadCache* prev_; void Init(pthread_t tid); void Cleanup(); // Accessors (mostly just for printing stats) int freelist_length(size_t cl) const { return list_[cl].length(); } // Total byte size in cache size_t Size() const { return size_; } // Allocate an object of the given size and class. The size given // must be the same as the size of the class in the size map. void* Allocate(size_t size, size_t cl); void Deallocate(void* ptr, size_t size_class); void Scavenge(); void Print(TCMalloc_Printer* out) const; int GetSamplePeriod(); // Record allocation of "k" bytes. Return true iff allocation // should be sampled bool SampleAllocation(size_t k); static void InitModule(); static void InitTSD(); static ThreadCache* GetThreadHeap(); static ThreadCache* GetCache(); static ThreadCache* GetCacheIfPresent(); static ThreadCache* CreateCacheIfNecessary(); static void BecomeIdle(); // Return the number of thread heaps in use. static inline int HeapsInUse(); // Writes to total_bytes the total number of bytes used by all thread heaps. // class_count must be an array of size kNumClasses. Writes the number of // items on the corresponding freelist. class_count may be NULL. // The storage of both parameters must be zero intialized. // REQUIRES: Static::pageheap_lock is held. static void GetThreadStats(uint64_t* total_bytes, uint64_t* class_count); // Write debugging statistics to 'out'. // REQUIRES: Static::pageheap_lock is held. static void PrintThreads(TCMalloc_Printer* out); // Sets the total thread cache size to new_size, recomputing the // individual thread cache sizes as necessary. // REQUIRES: Static::pageheap lock is held. static void set_overall_thread_cache_size(size_t new_size); static size_t overall_thread_cache_size() { return overall_thread_cache_size_; } private: class FreeList { private: void* list_; // Linked list of nodes #ifdef _LP64 // On 64-bit hardware, manipulating 16-bit values may be slightly slow. uint32_t length_; // Current length. uint32_t lowater_; // Low water mark for list length. uint32_t max_length_; // Dynamic max list length based on usage. // Tracks the number of times a deallocation has caused // length_ > max_length_. After the kMaxOverages'th time, max_length_ // shrinks and length_overages_ is reset to zero. uint32_t length_overages_; #else // If we aren't using 64-bit pointers then pack these into less space. uint16_t length_; uint16_t lowater_; uint16_t max_length_; uint16_t length_overages_; #endif public: void Init() { list_ = NULL; length_ = 0; lowater_ = 0; max_length_ = 1; length_overages_ = 0; } // Return current length of list size_t length() const { return length_; } // Return the maximum length of the list. size_t max_length() const { return max_length_; } // Set the maximum length of the list. If 'new_max' > length(), the // client is responsible for removing objects from the list. void set_max_length(size_t new_max) { max_length_ = new_max; } // Return the number of times that length() has gone over max_length(). size_t length_overages() const { return length_overages_; } void set_length_overages(size_t new_count) { length_overages_ = new_count; } // Is list empty? bool empty() const { return list_ == NULL; } // Low-water mark management int lowwatermark() const { return lowater_; } void clear_lowwatermark() { lowater_ = length_; } void Push(void* ptr) { SLL_Push(&list_, ptr); length_++; } void* Pop() { ASSERT(list_ != NULL); length_--; if (length_ < lowater_) lowater_ = length_; return SLL_Pop(&list_); } void PushRange(int N, void *start, void *end) { SLL_PushRange(&list_, start, end); length_ += N; } void PopRange(int N, void **start, void **end) { SLL_PopRange(&list_, N, start, end); ASSERT(length_ >= N); length_ -= N; if (length_ < lowater_) lowater_ = length_; } }; // Gets and returns an object from the central cache, and, if possible, // also adds some objects of that size class to this thread cache. void* FetchFromCentralCache(size_t cl, size_t byte_size); // Releases some number of items from src. Adjusts the list's max_length // to eventually converge on num_objects_to_move(cl). void ListTooLong(FreeList* src, size_t cl); // Releases N items from this thread cache. void ReleaseToCentralCache(FreeList* src, size_t cl, int N); // Increase max_size_ by reducing unclaimed_cache_space_ or by // reducing the max_size_ of some other thread. In both cases, // the delta is kStealAmount. void IncreaseCacheLimit(); // Same as above but requires Static::pageheap_lock() is held. void IncreaseCacheLimitLocked(); // If TLS is available, we also store a copy of the per-thread object // in a __thread variable since __thread variables are faster to read // than pthread_getspecific(). We still need pthread_setspecific() // because __thread variables provide no way to run cleanup code when // a thread is destroyed. // We also give a hint to the compiler to use the "initial exec" TLS // model. This is faster than the default TLS model, at the cost that // you cannot dlopen this library. (To see the difference, look at // the CPU use of __tls_get_addr with and without this attribute.) // Since we don't really use dlopen in google code -- and using dlopen // on a malloc replacement is asking for trouble in any case -- that's // a good tradeoff for us. #ifdef HAVE_TLS static __thread ThreadCache* threadlocal_heap_ # ifdef HAVE___ATTRIBUTE__ __attribute__ ((tls_model ("initial-exec"))) # endif ; #endif // Thread-specific key. Initialization here is somewhat tricky // because some Linux startup code invokes malloc() before it // is in a good enough state to handle pthread_keycreate(). // Therefore, we use TSD keys only after tsd_inited is set to true. // Until then, we use a slow path to get the heap object. static bool tsd_inited_; static pthread_key_t heap_key_; // Linked list of heap objects. Protected by Static::pageheap_lock. static ThreadCache* thread_heaps_; static int thread_heap_count_; // A pointer to one of the objects in thread_heaps_. Represents // the next ThreadCache from which a thread over its max_size_ should // steal memory limit. Round-robin through all of the objects in // thread_heaps_. Protected by Static::pageheap_lock. static ThreadCache* next_memory_steal_; // Overall thread cache size. Protected by Static::pageheap_lock. static size_t overall_thread_cache_size_; // Global per-thread cache size. Writes are protected by // Static::pageheap_lock. Reads are done without any locking, which should be // fine as long as size_t can be written atomically and we don't place // invariants between this variable and other pieces of state. static volatile size_t per_thread_cache_size_; // Represents overall_thread_cache_size_ minus the sum of max_size_ // across all ThreadCaches. Protected by Static::pageheap_lock. static ssize_t unclaimed_cache_space_; // This class is laid out with the most frequently used fields // first so that hot elements are placed on the same cache line. size_t size_; // Combined size of data size_t max_size_; // size_ > max_size_ --> Scavenge() // We sample allocations, biased by the size of the allocation Sampler sampler_; // A sampler FreeList list_[kNumClasses]; // Array indexed by size-class pthread_t tid_; // Which thread owns it bool in_setspecific_; // In call to pthread_setspecific? // Allocate a new heap. REQUIRES: Static::pageheap_lock is held. static ThreadCache* NewHeap(pthread_t tid); // Use only as pthread thread-specific destructor function. static void DestroyThreadCache(void* ptr); static void DeleteCache(ThreadCache* heap); static void RecomputePerThreadCacheSize(); // Ensure that this class is cacheline-aligned. This is critical for // performance, as false sharing would negate many of the benefits // of a per-thread cache. } CACHELINE_ALIGNED; // Allocator for thread heaps // This is logically part of the ThreadCache class, but MSVC, at // least, does not like using ThreadCache as a template argument // before the class is fully defined. So we put it outside the class. extern PageHeapAllocator threadcache_allocator; inline int ThreadCache::HeapsInUse() { return threadcache_allocator.inuse(); } inline bool ThreadCache::SampleAllocation(size_t k) { return sampler_.SampleAllocation(k); } inline void* ThreadCache::Allocate(size_t size, size_t cl) { ASSERT(size <= kMaxSize); ASSERT(size == Static::sizemap()->ByteSizeForClass(cl)); FreeList* list = &list_[cl]; if (list->empty()) { return FetchFromCentralCache(cl, size); } size_ -= size; return list->Pop(); } inline void ThreadCache::Deallocate(void* ptr, size_t cl) { FreeList* list = &list_[cl]; size_ += Static::sizemap()->ByteSizeForClass(cl); ssize_t size_headroom = max_size_ - size_ - 1; list->Push(ptr); ssize_t list_headroom = static_cast(list->max_length()) - list->length(); // There are two relatively uncommon things that require further work. // In the common case we're done, and in that case we need a single branch // because of the bitwise-or trick that follows. if ((list_headroom | size_headroom) < 0) { if (list_headroom < 0) { ListTooLong(list, cl); } if (size_ >= max_size_) Scavenge(); } } inline ThreadCache* ThreadCache::GetThreadHeap() { #ifdef HAVE_TLS // __thread is faster, but only when the kernel supports it if (KernelSupportsTLS()) return threadlocal_heap_; #endif return reinterpret_cast( perftools_pthread_getspecific(heap_key_)); } inline ThreadCache* ThreadCache::GetCache() { ThreadCache* ptr = NULL; if (!tsd_inited_) { InitModule(); } else { ptr = GetThreadHeap(); } if (ptr == NULL) ptr = CreateCacheIfNecessary(); return ptr; } // In deletion paths, we do not try to create a thread-cache. This is // because we may be in the thread destruction code and may have // already cleaned up the cache for this thread. inline ThreadCache* ThreadCache::GetCacheIfPresent() { if (!tsd_inited_) return NULL; return GetThreadHeap(); } } // namespace tcmalloc #endif // TCMALLOC_THREAD_CACHE_H_ ================================================ FILE: distro/google-perftools-1.7/src/windows/addr2line-pdb.c ================================================ /* Copyright (c) 2008, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: David Vitek * * Dump function addresses using Microsoft debug symbols. This works * on PDB files. Note that this program will download symbols to * c:\websymbols without asking. */ #define WIN32_LEAN_AND_MEAN #define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_DEPRECATE #include #include #include #include #define SEARCH_CAP (1024*1024) #define WEBSYM "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols" void usage() { fprintf(stderr, "usage: " "addr2line-pdb [-f|--functions] [-C|--demangle] [-e filename]\n"); fprintf(stderr, "(Then list the hex addresses on stdin, one per line)\n"); } int main(int argc, char *argv[]) { DWORD error; HANDLE process; ULONG64 module_base; int i; char* search; char buf[256]; /* Enough to hold one hex address, I trust! */ int rv = 0; /* We may add SYMOPT_UNDNAME if --demangle is specified: */ DWORD symopts = SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES; char* filename = "a.out"; /* The default if -e isn't specified */ int print_function_name = 0; /* Set to 1 if -f is specified */ for (i = 1; i < argc; i++) { if (strcmp(argv[i], "--functions") == 0 || strcmp(argv[i], "-f") == 0) { print_function_name = 1; } else if (strcmp(argv[i], "--demangle") == 0 || strcmp(argv[i], "-C") == 0) { symopts |= SYMOPT_UNDNAME; } else if (strcmp(argv[i], "-e") == 0) { if (i + 1 >= argc) { fprintf(stderr, "FATAL ERROR: -e must be followed by a filename\n"); return 1; } filename = argv[i+1]; i++; /* to skip over filename too */ } else if (strcmp(argv[i], "--help") == 0) { usage(); exit(0); } else { usage(); exit(1); } } process = GetCurrentProcess(); if (!SymInitialize(process, NULL, FALSE)) { error = GetLastError(); fprintf(stderr, "SymInitialize returned error : %d\n", error); return 1; } search = malloc(SEARCH_CAP); if (SymGetSearchPath(process, search, SEARCH_CAP)) { if (strlen(search) + sizeof(";" WEBSYM) > SEARCH_CAP) { fprintf(stderr, "Search path too long\n"); SymCleanup(process); return 1; } strcat(search, ";" WEBSYM); } else { error = GetLastError(); fprintf(stderr, "SymGetSearchPath returned error : %d\n", error); rv = 1; /* An error, but not a fatal one */ strcpy(search, WEBSYM); /* Use a default value */ } if (!SymSetSearchPath(process, search)) { error = GetLastError(); fprintf(stderr, "SymSetSearchPath returned error : %d\n", error); rv = 1; /* An error, but not a fatal one */ } SymSetOptions(symopts); module_base = SymLoadModuleEx(process, NULL, filename, NULL, 0, 0, NULL, 0); if (!module_base) { /* SymLoadModuleEx failed */ error = GetLastError(); fprintf(stderr, "SymLoadModuleEx returned error : %d for %s\n", error, filename); SymCleanup(process); return 1; } buf[sizeof(buf)-1] = '\0'; /* Just to be safe */ while (fgets(buf, sizeof(buf)-1, stdin)) { /* GNU addr2line seems to just do a strtol and ignore any * weird characters it gets, so we will too. */ unsigned __int64 addr = _strtoui64(buf, NULL, 16); ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME*sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; IMAGEHLP_LINE64 line; DWORD dummy; pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); pSymbol->MaxNameLen = MAX_SYM_NAME; if (print_function_name) { if (SymFromAddr(process, (DWORD64)addr, NULL, pSymbol)) { printf("%s\n", pSymbol->Name); } else { printf("??\n"); } } line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); if (SymGetLineFromAddr64(process, (DWORD64)addr, &dummy, &line)) { printf("%s:%d\n", line.FileName, (int)line.LineNumber); } else { printf("??:0\n"); } } SymUnloadModule64(process, module_base); SymCleanup(process); return rv; } ================================================ FILE: distro/google-perftools-1.7/src/windows/get_mangled_names.cc ================================================ // Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // --- // Author: Craig Silverstein (opensource@google.com) // When you are porting perftools to a new compiler or architecture // (win64 vs win32) for instance, you'll need to change the mangled // symbol names for operator new and friends at the top of // patch_functions.cc. This file helps you do that. // // It does this by defining these functions with the proper signature. // All you need to do is compile this file and the run dumpbin on it. // (See http://msdn.microsoft.com/en-us/library/5x49w699.aspx for more // on dumpbin). To do this in MSVC, use the MSVC commandline shell: // http://msdn.microsoft.com/en-us/library/ms235639(VS.80).aspx) // // The run: // cl /c get_mangled_names.cc // dumpbin /symbols get_mangled_names.obj // // It will print out the mangled (and associated unmangled) names of // the 8 symbols you need to put at the top of patch_functions.cc #include // for size_t #include // for nothrow_t static char m; // some dummy memory so new doesn't return NULL. void* operator new(size_t size) { return &m; } void operator delete(void* p) throw() { } void* operator new[](size_t size) { return &m; } void operator delete[](void* p) throw() { } void* operator new(size_t size, const std::nothrow_t&) throw() { return &m; } void operator delete(void* p, const std::nothrow_t&) throw() { } void* operator new[](size_t size, const std::nothrow_t&) throw() { return &m; } void operator delete[](void* p, const std::nothrow_t&) throw() { } ================================================ FILE: distro/google-perftools-1.7/src/windows/google/tcmalloc.h ================================================ /* Copyright (c) 2003, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Sanjay Ghemawat * .h file by Craig Silverstein */ #ifndef TCMALLOC_TCMALLOC_H_ #define TCMALLOC_TCMALLOC_H_ // Define the version number so folks can check against it #define TC_VERSION_MAJOR 1 #define TC_VERSION_MINOR 4 #define TC_VERSION_PATCH "" #define TC_VERSION_STRING "google-perftools 1.4" // __THROW is defined in glibc systems. It means, counter-intuitively, // "This function will never throw an exception." It's an optional // optimization tool, but we may need to use it to match glibc prototypes. #ifndef __THROW /* I guess we're not on a glibc system */ # define __THROW /* __THROW is just an optimization, so ok to make it "" */ #endif #include // for struct mallinfo, if it's defined // Annoying stuff for windows -- makes sure clients can import these functions #ifndef PERFTOOLS_DLL_DECL # ifdef _WIN32 # define PERFTOOLS_DLL_DECL __declspec(dllimport) # else # define PERFTOOLS_DLL_DECL # endif #endif #ifdef __cplusplus #include // for std::nothrow_t extern "C" { #endif // Returns a human-readable version string. If major, minor, // and/or patch are not NULL, they are set to the major version, // minor version, and patch-code (a string, usually ""). PERFTOOLS_DLL_DECL const char* tc_version(int* major, int* minor, const char** patch) __THROW; PERFTOOLS_DLL_DECL void* tc_malloc(size_t size) __THROW; PERFTOOLS_DLL_DECL void tc_free(void* ptr) __THROW; PERFTOOLS_DLL_DECL void* tc_realloc(void* ptr, size_t size) __THROW; PERFTOOLS_DLL_DECL void* tc_calloc(size_t nmemb, size_t size) __THROW; PERFTOOLS_DLL_DECL void tc_cfree(void* ptr) __THROW; PERFTOOLS_DLL_DECL void* tc_memalign(size_t __alignment, size_t __size) __THROW; PERFTOOLS_DLL_DECL int tc_posix_memalign(void** ptr, size_t align, size_t size) __THROW; PERFTOOLS_DLL_DECL void* tc_valloc(size_t __size) __THROW; PERFTOOLS_DLL_DECL void* tc_pvalloc(size_t __size) __THROW; PERFTOOLS_DLL_DECL void tc_malloc_stats(void) __THROW; PERFTOOLS_DLL_DECL int tc_mallopt(int cmd, int value) __THROW; #if 0 PERFTOOLS_DLL_DECL struct mallinfo tc_mallinfo(void) __THROW; #endif // This is an alias for MallocExtension::instance()->GetAllocatedSize(). // It is equivalent to // OS X: malloc_size() // glibc: malloc_usable_size() // Windows: _msize() PERFTOOLS_DLL_DECL size_t tc_malloc_size(void* ptr) __THROW; #ifdef __cplusplus PERFTOOLS_DLL_DECL int tc_set_new_mode(int flag) __THROW; PERFTOOLS_DLL_DECL void* tc_new(size_t size); PERFTOOLS_DLL_DECL void* tc_new_nothrow(size_t size, const std::nothrow_t&) __THROW; PERFTOOLS_DLL_DECL void tc_delete(void* p) __THROW; PERFTOOLS_DLL_DECL void tc_delete_nothrow(void* p, const std::nothrow_t&) __THROW; PERFTOOLS_DLL_DECL void* tc_newarray(size_t size); PERFTOOLS_DLL_DECL void* tc_newarray_nothrow(size_t size, const std::nothrow_t&) __THROW; PERFTOOLS_DLL_DECL void tc_deletearray(void* p) __THROW; PERFTOOLS_DLL_DECL void tc_deletearray_nothrow(void* p, const std::nothrow_t&) __THROW; } #endif #endif // #ifndef TCMALLOC_TCMALLOC_H_ ================================================ FILE: distro/google-perftools-1.7/src/windows/ia32_modrm_map.cc ================================================ /* Copyright (c) 2007, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Joi Sigurdsson * * Table of relevant information about how to decode the ModR/M byte. * Based on information in the IA-32 Intel Architecture * Software Developers Manual Volume 2: Instruction Set Reference. */ #include "mini_disassembler.h" #include "mini_disassembler_types.h" namespace sidestep { const ModrmEntry MiniDisassembler::s_ia16_modrm_map_[] = { // mod == 00 /* r/m == 000 */ { false, false, OS_ZERO }, /* r/m == 001 */ { false, false, OS_ZERO }, /* r/m == 010 */ { false, false, OS_ZERO }, /* r/m == 011 */ { false, false, OS_ZERO }, /* r/m == 100 */ { false, false, OS_ZERO }, /* r/m == 101 */ { false, false, OS_ZERO }, /* r/m == 110 */ { true, false, OS_WORD }, /* r/m == 111 */ { false, false, OS_ZERO }, // mod == 01 /* r/m == 000 */ { true, false, OS_BYTE }, /* r/m == 001 */ { true, false, OS_BYTE }, /* r/m == 010 */ { true, false, OS_BYTE }, /* r/m == 011 */ { true, false, OS_BYTE }, /* r/m == 100 */ { true, false, OS_BYTE }, /* r/m == 101 */ { true, false, OS_BYTE }, /* r/m == 110 */ { true, false, OS_BYTE }, /* r/m == 111 */ { true, false, OS_BYTE }, // mod == 10 /* r/m == 000 */ { true, false, OS_WORD }, /* r/m == 001 */ { true, false, OS_WORD }, /* r/m == 010 */ { true, false, OS_WORD }, /* r/m == 011 */ { true, false, OS_WORD }, /* r/m == 100 */ { true, false, OS_WORD }, /* r/m == 101 */ { true, false, OS_WORD }, /* r/m == 110 */ { true, false, OS_WORD }, /* r/m == 111 */ { true, false, OS_WORD }, // mod == 11 /* r/m == 000 */ { false, false, OS_ZERO }, /* r/m == 001 */ { false, false, OS_ZERO }, /* r/m == 010 */ { false, false, OS_ZERO }, /* r/m == 011 */ { false, false, OS_ZERO }, /* r/m == 100 */ { false, false, OS_ZERO }, /* r/m == 101 */ { false, false, OS_ZERO }, /* r/m == 110 */ { false, false, OS_ZERO }, /* r/m == 111 */ { false, false, OS_ZERO } }; const ModrmEntry MiniDisassembler::s_ia32_modrm_map_[] = { // mod == 00 /* r/m == 000 */ { false, false, OS_ZERO }, /* r/m == 001 */ { false, false, OS_ZERO }, /* r/m == 010 */ { false, false, OS_ZERO }, /* r/m == 011 */ { false, false, OS_ZERO }, /* r/m == 100 */ { false, true, OS_ZERO }, /* r/m == 101 */ { true, false, OS_DOUBLE_WORD }, /* r/m == 110 */ { false, false, OS_ZERO }, /* r/m == 111 */ { false, false, OS_ZERO }, // mod == 01 /* r/m == 000 */ { true, false, OS_BYTE }, /* r/m == 001 */ { true, false, OS_BYTE }, /* r/m == 010 */ { true, false, OS_BYTE }, /* r/m == 011 */ { true, false, OS_BYTE }, /* r/m == 100 */ { true, true, OS_BYTE }, /* r/m == 101 */ { true, false, OS_BYTE }, /* r/m == 110 */ { true, false, OS_BYTE }, /* r/m == 111 */ { true, false, OS_BYTE }, // mod == 10 /* r/m == 000 */ { true, false, OS_DOUBLE_WORD }, /* r/m == 001 */ { true, false, OS_DOUBLE_WORD }, /* r/m == 010 */ { true, false, OS_DOUBLE_WORD }, /* r/m == 011 */ { true, false, OS_DOUBLE_WORD }, /* r/m == 100 */ { true, true, OS_DOUBLE_WORD }, /* r/m == 101 */ { true, false, OS_DOUBLE_WORD }, /* r/m == 110 */ { true, false, OS_DOUBLE_WORD }, /* r/m == 111 */ { true, false, OS_DOUBLE_WORD }, // mod == 11 /* r/m == 000 */ { false, false, OS_ZERO }, /* r/m == 001 */ { false, false, OS_ZERO }, /* r/m == 010 */ { false, false, OS_ZERO }, /* r/m == 011 */ { false, false, OS_ZERO }, /* r/m == 100 */ { false, false, OS_ZERO }, /* r/m == 101 */ { false, false, OS_ZERO }, /* r/m == 110 */ { false, false, OS_ZERO }, /* r/m == 111 */ { false, false, OS_ZERO }, }; }; // namespace sidestep ================================================ FILE: distro/google-perftools-1.7/src/windows/ia32_opcode_map.cc ================================================ /* Copyright (c) 2007, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Joi Sigurdsson * * Opcode decoding maps. Based on the IA-32 Intel Architecture * Software Developers Manual Volume 2: Instruction Set Reference. Idea * for how to lay out the tables in memory taken from the implementation * in the Bastard disassembly environment. */ #include "mini_disassembler.h" namespace sidestep { /* * This is the first table to be searched; the first field of each * Opcode in the table is either 0 to indicate you're in the * right table, or an index to the correct table, in the global * map g_pentiumOpcodeMap */ const Opcode s_first_opcode_byte[] = { /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x8 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x9 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xC */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xD */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xE */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xF */ { 1, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x10 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x11 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x12 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x13 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x14 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x15 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x16 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x17 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x18 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x19 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1C */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1E */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1F */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x20 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x21 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x22 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x23 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x24 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x25 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x26 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x27 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "daa", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x28 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x29 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2C */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2E */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2F */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "das", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x30 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x31 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x32 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x33 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x34 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x35 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x36 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x37 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "aaa", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x38 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x39 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3C */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3E */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3F */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "aas", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x40 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x41 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x42 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x43 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x44 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x45 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x46 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x47 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x48 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x49 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4A */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4B */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4C */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4E */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4F */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x50 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x51 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x52 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x53 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x54 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x55 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x56 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x57 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x58 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x59 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5A */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5B */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5C */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5E */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5F */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x60 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "pushad", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x61 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "popad", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x62 */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_A, AM_NOT_USED, "bound", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x63 */ { 0, IT_GENERIC, AM_E | OT_W, AM_G | OT_W, AM_NOT_USED, "arpl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x64 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x65 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x66 */ { 0, IT_PREFIX_OPERAND, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x67 */ { 0, IT_PREFIX_ADDRESS, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x68 */ { 0, IT_GENERIC, AM_I | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x69 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_I | OT_V, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6A */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_I | OT_B, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6C */ { 0, IT_GENERIC, AM_Y | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "insb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6D */ { 0, IT_GENERIC, AM_Y | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "insd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6E */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_X | OT_B, AM_NOT_USED, "outsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6F */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_X | OT_V, AM_NOT_USED, "outsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x70 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x71 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x72 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x73 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x74 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x75 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x76 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x77 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "ja", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x78 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "js", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x79 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7A */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7B */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7C */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7D */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7E */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7F */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x80 */ { 2, IT_REFERENCE, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x81 */ { 3, IT_REFERENCE, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x82 */ { 4, IT_REFERENCE, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x83 */ { 5, IT_REFERENCE, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x84 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x85 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x86 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x87 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x88 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x89 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x8A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x8B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x8C */ { 0, IT_GENERIC, AM_E | OT_W, AM_S | OT_W, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x8D */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_ADDRESS_MODE_M, AM_NOT_USED, "lea", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x8E */ { 0, IT_GENERIC, AM_S | OT_W, AM_E | OT_W, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x8F */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x90 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "nop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x91 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x92 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x93 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x94 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x95 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x96 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x97 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x98 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cwde", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x99 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cdq", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x9A */ { 0, IT_JUMP, AM_A | OT_P, AM_NOT_USED, AM_NOT_USED, "callf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x9B */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "wait", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x9C */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "pushfd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x9D */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "popfd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x9E */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sahf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x9F */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "lahf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA0 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_O | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA1 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_O | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA2 */ { 0, IT_GENERIC, AM_O | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA3 */ { 0, IT_GENERIC, AM_O | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA4 */ { 0, IT_GENERIC, AM_X | OT_B, AM_Y | OT_B, AM_NOT_USED, "movsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA5 */ { 0, IT_GENERIC, AM_X | OT_V, AM_Y | OT_V, AM_NOT_USED, "movsd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA6 */ { 0, IT_GENERIC, AM_X | OT_B, AM_Y | OT_B, AM_NOT_USED, "cmpsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA7 */ { 0, IT_GENERIC, AM_X | OT_V, AM_Y | OT_V, AM_NOT_USED, "cmpsd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA8 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA9 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xAA */ { 0, IT_GENERIC, AM_Y | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "stosb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xAB */ { 0, IT_GENERIC, AM_Y | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "stosd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xAC */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_X| OT_B, AM_NOT_USED, "lodsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xAD */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_X| OT_V, AM_NOT_USED, "lodsd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xAE */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_Y | OT_B, AM_NOT_USED, "scasb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xAF */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_Y | OT_V, AM_NOT_USED, "scasd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB0 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB1 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB2 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB3 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB4 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB5 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB6 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB7 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB8 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB9 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xBA */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xBB */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xBC */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xBD */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xBE */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xBF */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xC0 */ { 6, IT_REFERENCE, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xC1 */ { 7, IT_REFERENCE, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xC2 */ { 0, IT_RETURN, AM_I | OT_W, AM_NOT_USED, AM_NOT_USED, "ret", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xC3 */ { 0, IT_RETURN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ret", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xC4 */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_P, AM_NOT_USED, "les", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xC5 */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_P, AM_NOT_USED, "lds", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xC6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xC7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xC8 */ { 0, IT_GENERIC, AM_I | OT_W, AM_I | OT_B, AM_NOT_USED, "enter", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xC9 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "leave", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xCA */ { 0, IT_RETURN, AM_I | OT_W, AM_NOT_USED, AM_NOT_USED, "retf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xCB */ { 0, IT_RETURN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "retf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xCC */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "int3", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xCD */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "int", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xCE */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "into", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xCF */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "iret", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xD0 */ { 8, IT_REFERENCE, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xD1 */ { 9, IT_REFERENCE, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xD2 */ { 10, IT_REFERENCE, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xD3 */ { 11, IT_REFERENCE, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xD4 */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "aam", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xD5 */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "aad", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xD6 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xD7 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "xlat", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, // The following 8 lines would be references to the FPU tables, but we currently // do not support the FPU instructions in this disassembler. /* 0xD8 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xD9 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xDA */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xDB */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xDC */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xDD */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xDE */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xDF */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xE0 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "loopnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xE1 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "loopz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xE2 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "loop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xE3 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jcxz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xE4 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xE5 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xE6 */ { 0, IT_GENERIC, AM_I | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xE7 */ { 0, IT_GENERIC, AM_I | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xE8 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "call", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xE9 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xEA */ { 0, IT_JUMP, AM_A | OT_P, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xEB */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xEC */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_REGISTER | OT_W, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xED */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_W, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xEE */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_REGISTER | OT_B, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xEF */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_REGISTER | OT_V, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xF0 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "lock:", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xF1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xF2 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "repne:", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xF3 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rep:", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xF4 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "hlt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xF5 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cmc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xF6 */ { 12, IT_REFERENCE, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xF7 */ { 13, IT_REFERENCE, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xF8 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "clc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xF9 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "stc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xFA */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cli", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xFB */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sti", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xFC */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cld", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xFD */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "std", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xFE */ { 14, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xFF */ { 15, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_0f[] = { /* 0x0 */ { 16, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 17, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "lar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "lsl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "clts", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x8 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "invd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x9 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "wbinvd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ud2", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xC */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xD */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xE */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xF */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x10 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "movups", true, /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "movsd" }, /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "movss" }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "movupd" } }, /* 0x11 */ { 0, IT_GENERIC, AM_W | OT_PS, AM_V | OT_PS, AM_NOT_USED, "movups", true, /* F2h */ { 0, IT_GENERIC, AM_W | OT_SD, AM_V | OT_SD, AM_NOT_USED, "movsd" }, /* F3h */ { 0, IT_GENERIC, AM_W | OT_SS, AM_V | OT_SS, AM_NOT_USED, "movss" }, /* 66h */ { 0, IT_GENERIC, AM_W | OT_PD, AM_V | OT_PD, AM_NOT_USED, "movupd" } }, /* 0x12 */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movlps", true, /* F2h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhlps" }, // only one of ... /* F3h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhlps" }, // ...these two is correct, Intel doesn't specify which /* 66h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_S, AM_NOT_USED, "movlpd" } }, /* 0x13 */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movlps", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movlpd" } }, /* 0x14 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_Q, AM_NOT_USED, "unpcklps", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_Q, AM_NOT_USED, "unpcklpd" } }, /* 0x15 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_Q, AM_NOT_USED, "unpckhps", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_Q, AM_NOT_USED, "unpckhpd" } }, /* 0x16 */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movhps", true, /* F2h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movlhps" }, // only one of... /* F3h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movlhps" }, // ...these two is correct, Intel doesn't specify which /* 66h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movhpd" } }, /* 0x17 */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhps", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhpd" } }, /* 0x18 */ { 18, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x19 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1A */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1B */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1C */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1D */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1E */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1F */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x20 */ { 0, IT_GENERIC, AM_R | OT_D, AM_C | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x21 */ { 0, IT_GENERIC, AM_R | OT_D, AM_D | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x22 */ { 0, IT_GENERIC, AM_C | OT_D, AM_R | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x23 */ { 0, IT_GENERIC, AM_D | OT_D, AM_R | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x24 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x25 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x26 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x27 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x28 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "movaps", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "movapd" } }, /* 0x29 */ { 0, IT_GENERIC, AM_W | OT_PS, AM_V | OT_PS, AM_NOT_USED, "movaps", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_W | OT_PD, AM_V | OT_PD, AM_NOT_USED, "movapd" } }, /* 0x2A */ { 0, IT_GENERIC, AM_V | OT_PS, AM_Q | OT_Q, AM_NOT_USED, "cvtpi2ps", true, /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_E | OT_D, AM_NOT_USED, "cvtsi2sd" }, /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_E | OT_D, AM_NOT_USED, "cvtsi2ss" }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_Q | OT_DQ, AM_NOT_USED, "cvtpi2pd" } }, /* 0x2B */ { 0, IT_GENERIC, AM_W | OT_PS, AM_V | OT_PS, AM_NOT_USED, "movntps", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_W | OT_PD, AM_V | OT_PD, AM_NOT_USED, "movntpd" } }, /* 0x2C */ { 0, IT_GENERIC, AM_Q | OT_Q, AM_W | OT_PS, AM_NOT_USED, "cvttps2pi", true, /* F2h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SD, AM_NOT_USED, "cvttsd2si" }, /* F3h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SS, AM_NOT_USED, "cvttss2si" }, /* 66h */ { 0, IT_GENERIC, AM_Q | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvttpd2pi" } }, /* 0x2D */ { 0, IT_GENERIC, AM_Q | OT_Q, AM_W | OT_PS, AM_NOT_USED, "cvtps2pi", true, /* F2h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SD, AM_NOT_USED, "cvtsd2si" }, /* F3h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SS, AM_NOT_USED, "cvtss2si" }, /* 66h */ { 0, IT_GENERIC, AM_Q | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvtpd2pi" } }, /* 0x2E */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "ucomiss", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "ucomisd" } }, /* 0x2F */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_SS, AM_NOT_USED, "comiss", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "comisd" } }, /* 0x30 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "wrmsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x31 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rdtsc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x32 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rdmsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x33 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rdpmc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x34 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sysenter", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x35 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sysexit", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x36 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x37 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x38 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x39 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3A */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3B */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3C */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "movnti", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3D */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3E */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3F */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x40 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x41 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x42 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x43 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x44 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x45 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x46 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x47 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmova", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x48 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovs", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x49 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4A */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4C */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4D */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4E */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4F */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x50 */ { 0, IT_GENERIC, AM_E | OT_D, AM_V | OT_PS, AM_NOT_USED, "movmskps", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_E | OT_D, AM_V | OT_PD, AM_NOT_USED, "movmskpd" } }, /* 0x51 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "sqrtps", true, /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "sqrtsd" }, /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "sqrtss" }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "sqrtpd" } }, /* 0x52 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "rsqrtps", true, /* F2h */ { 0 }, /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "rsqrtss" }, /* 66h */ { 0 } }, /* 0x53 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "rcpps", true, /* F2h */ { 0 }, /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "rcpss" }, /* 66h */ { 0 } }, /* 0x54 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "andps", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "andpd" } }, /* 0x55 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "andnps", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "andnpd" } }, /* 0x56 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "orps", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "orpd" } }, /* 0x57 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "xorps", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "xorpd" } }, /* 0x58 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "addps", true, /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "addsd" }, /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "addss" }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "addpd" } }, /* 0x59 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "mulps", true, /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "mulsd" }, /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "mulss" }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "mulpd" } }, /* 0x5A */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PS, AM_NOT_USED, "cvtps2pd", true, /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "cvtsd2ss" }, /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "cvtss2sd" }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PD, AM_NOT_USED, "cvtpd2ps" } }, /* 0x5B */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_DQ, AM_NOT_USED, "cvtdq2ps", true, /* F2h */ { 0 }, /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PS, AM_NOT_USED, "cvttps2dq" }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PS, AM_NOT_USED, "cvtps2dq" } }, /* 0x5C */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "subps", true, /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "subsd" }, /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "subss" }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "subpd" } }, /* 0x5D */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "minps", true, /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "minsd" }, /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "minss" }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "minpd" } }, /* 0x5E */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "divps", true, /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "divsd" }, /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "divss" }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "divpd" } }, /* 0x5F */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "maxps", true, /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "maxsd" }, /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "maxss" }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "maxpd" } }, /* 0x60 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpcklbw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklbw" } }, /* 0x61 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpcklwd", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklwd" } }, /* 0x62 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckldq", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpckldq" } }, /* 0x63 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "packsswb", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "packsswb" } }, /* 0x64 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "pcmpgtb", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpgtb" } }, /* 0x65 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "pcmpgtw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpgtw" } }, /* 0x66 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "pcmpgtd", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpgtd" } }, /* 0x67 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "packuswb", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "packuswb" } }, /* 0x68 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckhbw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "punpckhbw" } }, /* 0x69 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckhwd", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "punpckhwd" } }, /* 0x6A */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckhdq", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "punpckhdq" } }, /* 0x6B */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "packssdw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "packssdw" } }, /* 0x6C */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "not used without prefix", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklqdq" } }, /* 0x6D */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "not used without prefix", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklqdq" } }, /* 0x6E */ { 0, IT_GENERIC, AM_P | OT_D, AM_E | OT_D, AM_NOT_USED, "movd", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_E | OT_D, AM_NOT_USED, "movd" } }, /* 0x6F */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "movq", true, /* F2h */ { 0 }, /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "movdqu" }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "movdqa" } }, /* 0x70 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_I | OT_B, "pshuf", true, /* F2h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_I | OT_B, "pshuflw" }, /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_I | OT_B, "pshufhw" }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_I | OT_B, "pshufd" } }, /* 0x71 */ { 19, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x72 */ { 20, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x73 */ { 21, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x74 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pcmpeqb", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpeqb" } }, /* 0x75 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pcmpeqw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpeqw" } }, /* 0x76 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pcmpeqd", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpeqd" } }, /* 0x77 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "emms", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, // The following six opcodes are escapes into the MMX stuff, which this disassembler does not support. /* 0x78 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x79 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7A */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7B */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7C */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7D */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7E */ { 0, IT_GENERIC, AM_E | OT_D, AM_P | OT_D, AM_NOT_USED, "movd", true, /* F2h */ { 0 }, /* F3h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movq" }, /* 66h */ { 0, IT_GENERIC, AM_E | OT_D, AM_V | OT_DQ, AM_NOT_USED, "movd" } }, /* 0x7F */ { 0, IT_GENERIC, AM_Q | OT_Q, AM_P | OT_Q, AM_NOT_USED, "movq", true, /* F2h */ { 0 }, /* F3h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_V | OT_DQ, AM_NOT_USED, "movdqu" }, /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_V | OT_DQ, AM_NOT_USED, "movdqa" } }, /* 0x80 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x81 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x82 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x83 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x84 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x85 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x86 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x87 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "ja", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x88 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "js", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x89 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x8A */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x8B */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x8C */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x8D */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x8E */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x8F */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x90 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "seto", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x91 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x92 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x93 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x94 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x95 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x96 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x97 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "seta", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x98 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "sets", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x99 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x9A */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x9B */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x9C */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x9D */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x9E */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x9F */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA0 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA1 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA2 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cpuid", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "bt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B, "shld", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B | AM_REGISTER, "shld", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA6 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA7 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA8 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xA9 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xAA */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rsm", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xAB */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "bts", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xAC */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B, "shrd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xAD */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B | AM_REGISTER, "shrd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xAE */ { 22, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xAF */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "cmpxchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "cmpxchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB2 */ { 0, IT_GENERIC, AM_M | OT_P, AM_NOT_USED, AM_NOT_USED, "lss", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "btr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB4 */ { 0, IT_GENERIC, AM_M | OT_P, AM_NOT_USED, AM_NOT_USED, "lfs", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB5 */ { 0, IT_GENERIC, AM_M | OT_P, AM_NOT_USED, AM_NOT_USED, "lgs", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB6 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_B, AM_NOT_USED, "movzx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB7 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "movzx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB8 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xB9 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ud1", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xBA */ { 23, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xBB */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "btc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xBC */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "bsf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xBD */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "bsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xBE */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_B, AM_NOT_USED, "movsx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xBF */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "movsx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xC0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "xadd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xC1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "xadd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xC2 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_I | OT_B, "cmpps", true, /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_I | OT_B, "cmpsd" }, /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_I | OT_B, "cmpss" }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_I | OT_B, "cmppd" } }, /* 0xC3 */ { 0, IT_GENERIC, AM_E | OT_D, AM_G | OT_D, AM_NOT_USED, "movnti", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xC4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_E | OT_D, AM_I | OT_B, "pinsrw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_E | OT_D, AM_I | OT_B, "pinsrw" } }, /* 0xC5 */ { 0, IT_GENERIC, AM_G | OT_D, AM_P | OT_Q, AM_I | OT_B, "pextrw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_G | OT_D, AM_V | OT_DQ, AM_I | OT_B, "pextrw" } }, /* 0xC6 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_I | OT_B, "shufps", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_I | OT_B, "shufpd" } }, /* 0xC7 */ { 24, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xC8 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xC9 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xCA */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xCB */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xCC */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xCD */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xCE */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xCF */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xD0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xD1 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrlw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrlw" } }, /* 0xD2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrld", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrld" } }, /* 0xD3 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrlq", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrlq" } }, /* 0xD4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddq", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddq" } }, /* 0xD5 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmullw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmullw" } }, /* 0xD6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "unused without prefix", true, /* F2h */ { 0, IT_GENERIC, AM_P | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movdq2q" }, /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_Q | OT_Q, AM_NOT_USED, "movq2dq" }, /* 66h */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movq" } }, /* 0xD7 */ { 0, IT_GENERIC, AM_G | OT_D, AM_P | OT_Q, AM_NOT_USED, "pmovmskb", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_G | OT_D, AM_V | OT_DQ, AM_NOT_USED, "pmovmskb" } }, /* 0xD8 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubusb", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubusb" } }, /* 0xD9 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubusw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubusw" } }, /* 0xDA */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pminub", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pminub" } }, /* 0xDB */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pand", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pand" } }, /* 0xDC */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddusb", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddusb" } }, /* 0xDD */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddusw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddusw" } }, /* 0xDE */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmaxub", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmaxub" } }, /* 0xDF */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pandn", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pandn" } }, /* 0xE0 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pavgb", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pavgb" } }, /* 0xE1 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psraw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrqw" } }, /* 0xE2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrad", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrad" } }, /* 0xE3 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pavgw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pavgw" } }, /* 0xE4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmulhuw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmulhuw" } }, /* 0xE5 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmulhuw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmulhw" } }, /* 0xE6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "not used without prefix", true, /* F2h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvtpd2dq" }, /* F3h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_DQ, AM_NOT_USED, "cvtdq2pd" }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvttpd2dq" } }, /* 0xE7 */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movntq", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_V | OT_DQ, AM_NOT_USED, "movntdq" } }, /* 0xE8 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubsb", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubsb" } }, /* 0xE9 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubsw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubsw" } }, /* 0xEA */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pminsw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pminsw" } }, /* 0xEB */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "por", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "por" } }, /* 0xEC */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddsb", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddsb" } }, /* 0xED */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddsw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddsw" } }, /* 0xEE */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmaxsw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmaxsw" } }, /* 0xEF */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pxor", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pxor" } }, /* 0xF0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0xF1 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psllw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psllw" } }, /* 0xF2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pslld", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pslld" } }, /* 0xF3 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psllq", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psllq" } }, /* 0xF4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmuludq", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmuludq" } }, /* 0xF5 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmaddwd", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmaddwd" } }, /* 0xF6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psadbw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psadbw" } }, /* 0xF7 */ { 0, IT_GENERIC, AM_P | OT_PI, AM_Q | OT_PI, AM_NOT_USED, "maskmovq", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "maskmovdqu" } }, /* 0xF8 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubb", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubb" } }, /* 0xF9 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubw" } }, /* 0xFA */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubd", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubd" } }, /* 0xFB */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubq", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubq" } }, /* 0xFC */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddb", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddb" } }, /* 0xFD */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddw" } }, /* 0xFE */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddd", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddd" } }, /* 0xFF */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_0f00[] = { /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "sldt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "str", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "lldt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "ltr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "verr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "verw", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_0f01[] = { /* 0x0 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "sgdt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "sidt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "lgdt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "lidt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "smsw", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "lmsw", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_GENERIC, AM_M | OT_B, AM_NOT_USED, AM_NOT_USED, "invlpg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_0f18[] = { /* 0x0 */ { 0, IT_GENERIC, AM_M | OT_ADDRESS_MODE_M, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_0f71[] = { /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrlw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrlw" } }, /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psraw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psraw" } }, /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psllw", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psllw" } }, /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_0f72[] = { /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrld", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrld" } }, /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrad", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrad" } }, /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "pslld", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "pslld" } }, /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_0f73[] = { /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrlq", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrlq" } }, /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psllq", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psllq" } }, /* 0x7 */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "pslldq", true, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "pslldq" } }, }; const Opcode s_opcode_byte_after_0fae[] = { /* 0x0 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "fxsave", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "fxrstor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ldmxcsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "stmxcsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "lfence", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "mfence", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "clflush/sfence", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, }; const Opcode s_opcode_byte_after_0fba[] = { /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "bt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "bts", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "btr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "btc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_0fc7[] = { /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_M | OT_Q, AM_NOT_USED, AM_NOT_USED, "cmpxch8b", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_80[] = { /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_81[] = { /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_82[] = { /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_83[] = { /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_c0[] = { /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_c1[] = { /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_d0[] = { /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_d1[] = { /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_d2[] = { /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_d3[] = { /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_f6[] = { /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "not", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "neg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_GENERIC, OT_B | AM_REGISTER, AM_E | OT_B, AM_NOT_USED, "mul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_GENERIC, OT_B | AM_REGISTER, AM_E | OT_B, AM_NOT_USED, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_E | OT_B, AM_NOT_USED, "div", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_E | OT_B, AM_NOT_USED, "idiv", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_f7[] = { /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "not", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "neg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "mul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "div", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "idiv", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_fe[] = { /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; const Opcode s_opcode_byte_after_ff[] = { /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x2 */ { 0, IT_JUMP, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "call", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x3 */ { 0, IT_JUMP, AM_E | OT_P, AM_NOT_USED, AM_NOT_USED, "call", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x4 */ { 0, IT_JUMP, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x5 */ { 0, IT_JUMP, AM_E | OT_P, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }, /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } } }; /* * A table of all the other tables, containing some extra information, e.g. * how to mask out the byte we're looking at. */ const OpcodeTable MiniDisassembler::s_ia32_opcode_map_[]={ // One-byte opcodes and jumps to larger /* 0 */ {s_first_opcode_byte, 0, 0xff, 0, 0xff}, // Two-byte opcodes (second byte) /* 1 */ {s_opcode_byte_after_0f, 0, 0xff, 0, 0xff}, // Start of tables for opcodes using ModR/M bits as extension /* 2 */ {s_opcode_byte_after_80, 3, 0x07, 0, 0x07}, /* 3 */ {s_opcode_byte_after_81, 3, 0x07, 0, 0x07}, /* 4 */ {s_opcode_byte_after_82, 3, 0x07, 0, 0x07}, /* 5 */ {s_opcode_byte_after_83, 3, 0x07, 0, 0x07}, /* 6 */ {s_opcode_byte_after_c0, 3, 0x07, 0, 0x07}, /* 7 */ {s_opcode_byte_after_c1, 3, 0x07, 0, 0x07}, /* 8 */ {s_opcode_byte_after_d0, 3, 0x07, 0, 0x07}, /* 9 */ {s_opcode_byte_after_d1, 3, 0x07, 0, 0x07}, /* 10 */ {s_opcode_byte_after_d2, 3, 0x07, 0, 0x07}, /* 11 */ {s_opcode_byte_after_d3, 3, 0x07, 0, 0x07}, /* 12 */ {s_opcode_byte_after_f6, 3, 0x07, 0, 0x07}, /* 13 */ {s_opcode_byte_after_f7, 3, 0x07, 0, 0x07}, /* 14 */ {s_opcode_byte_after_fe, 3, 0x07, 0, 0x01}, /* 15 */ {s_opcode_byte_after_ff, 3, 0x07, 0, 0x07}, /* 16 */ {s_opcode_byte_after_0f00, 3, 0x07, 0, 0x07}, /* 17 */ {s_opcode_byte_after_0f01, 3, 0x07, 0, 0x07}, /* 18 */ {s_opcode_byte_after_0f18, 3, 0x07, 0, 0x07}, /* 19 */ {s_opcode_byte_after_0f71, 3, 0x07, 0, 0x07}, /* 20 */ {s_opcode_byte_after_0f72, 3, 0x07, 0, 0x07}, /* 21 */ {s_opcode_byte_after_0f73, 3, 0x07, 0, 0x07}, /* 22 */ {s_opcode_byte_after_0fae, 3, 0x07, 0, 0x07}, /* 23 */ {s_opcode_byte_after_0fba, 3, 0x07, 0, 0x07}, /* 24 */ {s_opcode_byte_after_0fc7, 3, 0x07, 0, 0x01} }; }; // namespace sidestep ================================================ FILE: distro/google-perftools-1.7/src/windows/mingw.h ================================================ /* Copyright (c) 2007, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Craig Silverstein * * MinGW is an interesting mix of unix and windows. We use a normal * configure script, but still need the windows port.h to define some * stuff that MinGW doesn't support, like pthreads. */ #ifndef GOOGLE_PERFTOOLS_WINDOWS_MINGW_H_ #define GOOGLE_PERFTOOLS_WINDOWS_MINGW_H_ #ifdef __MINGW32__ // Older version of the mingw msvcrt don't define _aligned_malloc #if __MSVCRT_VERSION__ < 0x0700 # define PERFTOOLS_NO_ALIGNED_MALLOC 1 #endif // This must be defined before the windows.h is included. We need at // least 0x0400 for mutex.h to have access to TryLock, and at least // 0x0501 for patch_functions.cc to have access to GetModuleHandleEx. // (This latter is an optimization we could take out if need be.) #ifndef _WIN32_WINNT # define _WIN32_WINNT 0x0501 #endif #include "windows/port.h" #define HAVE_SNPRINTF 1 // Some mingw distributions have a pthreads wrapper, but it doesn't // work as well as native windows spinlocks (at least for us). So // pretend the pthreads wrapper doesn't exist, even when it does. #undef HAVE_PTHREAD #endif /* __MINGW32__ */ #endif /* GOOGLE_PERFTOOLS_WINDOWS_MINGW_H_ */ ================================================ FILE: distro/google-perftools-1.7/src/windows/mini_disassembler.cc ================================================ /* Copyright (c) 2007, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Joi Sigurdsson * * Implementation of MiniDisassembler. */ #include "mini_disassembler.h" namespace sidestep { MiniDisassembler::MiniDisassembler(bool operand_default_is_32_bits, bool address_default_is_32_bits) : operand_default_is_32_bits_(operand_default_is_32_bits), address_default_is_32_bits_(address_default_is_32_bits) { Initialize(); } MiniDisassembler::MiniDisassembler() : operand_default_is_32_bits_(true), address_default_is_32_bits_(true) { Initialize(); } InstructionType MiniDisassembler::Disassemble( unsigned char* start_byte, unsigned int& instruction_bytes) { // Clean up any state from previous invocations. Initialize(); // Start by processing any prefixes. unsigned char* current_byte = start_byte; unsigned int size = 0; InstructionType instruction_type = ProcessPrefixes(current_byte, size); if (IT_UNKNOWN == instruction_type) return instruction_type; current_byte += size; size = 0; // Invariant: We have stripped all prefixes, and the operand_is_32_bits_ // and address_is_32_bits_ flags are correctly set. instruction_type = ProcessOpcode(current_byte, 0, size); // Check for error processing instruction if ((IT_UNKNOWN == instruction_type_) || (IT_UNUSED == instruction_type_)) { return IT_UNKNOWN; } current_byte += size; // Invariant: operand_bytes_ indicates the total size of operands // specified by the opcode and/or ModR/M byte and/or SIB byte. // pCurrentByte points to the first byte after the ModR/M byte, or after // the SIB byte if it is present (i.e. the first byte of any operands // encoded in the instruction). // We get the total length of any prefixes, the opcode, and the ModR/M and // SIB bytes if present, by taking the difference of the original starting // address and the current byte (which points to the first byte of the // operands if present, or to the first byte of the next instruction if // they are not). Adding the count of bytes in the operands encoded in // the instruction gives us the full length of the instruction in bytes. instruction_bytes += operand_bytes_ + (current_byte - start_byte); // Return the instruction type, which was set by ProcessOpcode(). return instruction_type_; } void MiniDisassembler::Initialize() { operand_is_32_bits_ = operand_default_is_32_bits_; address_is_32_bits_ = address_default_is_32_bits_; operand_bytes_ = 0; have_modrm_ = false; should_decode_modrm_ = false; instruction_type_ = IT_UNKNOWN; got_f2_prefix_ = false; got_f3_prefix_ = false; got_66_prefix_ = false; } InstructionType MiniDisassembler::ProcessPrefixes(unsigned char* start_byte, unsigned int& size) { InstructionType instruction_type = IT_GENERIC; const Opcode& opcode = s_ia32_opcode_map_[0].table_[*start_byte]; switch (opcode.type_) { case IT_PREFIX_ADDRESS: address_is_32_bits_ = !address_default_is_32_bits_; goto nochangeoperand; case IT_PREFIX_OPERAND: operand_is_32_bits_ = !operand_default_is_32_bits_; nochangeoperand: case IT_PREFIX: if (0xF2 == (*start_byte)) got_f2_prefix_ = true; else if (0xF3 == (*start_byte)) got_f3_prefix_ = true; else if (0x66 == (*start_byte)) got_66_prefix_ = true; instruction_type = opcode.type_; size ++; // we got a prefix, so add one and check next byte ProcessPrefixes(start_byte + 1, size); default: break; // not a prefix byte } return instruction_type; } InstructionType MiniDisassembler::ProcessOpcode(unsigned char* start_byte, unsigned int table_index, unsigned int& size) { const OpcodeTable& table = s_ia32_opcode_map_[table_index]; // Get our table unsigned char current_byte = (*start_byte) >> table.shift_; current_byte = current_byte & table.mask_; // Mask out the bits we will use // Check whether the byte we have is inside the table we have. if (current_byte < table.min_lim_ || current_byte > table.max_lim_) { instruction_type_ = IT_UNKNOWN; return instruction_type_; } const Opcode& opcode = table.table_[current_byte]; if (IT_UNUSED == opcode.type_) { // This instruction is not used by the IA-32 ISA, so we indicate // this to the user. Probably means that we were pointed to // a byte in memory that was not the start of an instruction. instruction_type_ = IT_UNUSED; return instruction_type_; } else if (IT_REFERENCE == opcode.type_) { // We are looking at an opcode that has more bytes (or is continued // in the ModR/M byte). Recursively find the opcode definition in // the table for the opcode's next byte. size++; ProcessOpcode(start_byte + 1, opcode.table_index_, size); return instruction_type_; } const SpecificOpcode* specific_opcode = (SpecificOpcode*)&opcode; if (opcode.is_prefix_dependent_) { if (got_f2_prefix_ && opcode.opcode_if_f2_prefix_.mnemonic_ != 0) { specific_opcode = &opcode.opcode_if_f2_prefix_; } else if (got_f3_prefix_ && opcode.opcode_if_f3_prefix_.mnemonic_ != 0) { specific_opcode = &opcode.opcode_if_f3_prefix_; } else if (got_66_prefix_ && opcode.opcode_if_66_prefix_.mnemonic_ != 0) { specific_opcode = &opcode.opcode_if_66_prefix_; } } // Inv: The opcode type is known. instruction_type_ = specific_opcode->type_; // Let's process the operand types to see if we have any immediate // operands, and/or a ModR/M byte. ProcessOperand(specific_opcode->flag_dest_); ProcessOperand(specific_opcode->flag_source_); ProcessOperand(specific_opcode->flag_aux_); // Inv: We have processed the opcode and incremented operand_bytes_ // by the number of bytes of any operands specified by the opcode // that are stored in the instruction (not registers etc.). Now // we need to return the total number of bytes for the opcode and // for the ModR/M or SIB bytes if they are present. if (table.mask_ != 0xff) { if (have_modrm_) { // we're looking at a ModR/M byte so we're not going to // count that into the opcode size ProcessModrm(start_byte, size); return IT_GENERIC; } else { // need to count the ModR/M byte even if it's just being // used for opcode extension size++; return IT_GENERIC; } } else { if (have_modrm_) { // The ModR/M byte is the next byte. size++; ProcessModrm(start_byte + 1, size); return IT_GENERIC; } else { size++; return IT_GENERIC; } } } bool MiniDisassembler::ProcessOperand(int flag_operand) { bool succeeded = true; if (AM_NOT_USED == flag_operand) return succeeded; // Decide what to do based on the addressing mode. switch (flag_operand & AM_MASK) { // No ModR/M byte indicated by these addressing modes, and no // additional (e.g. immediate) parameters. case AM_A: // Direct address case AM_F: // EFLAGS register case AM_X: // Memory addressed by the DS:SI register pair case AM_Y: // Memory addressed by the ES:DI register pair case AM_IMPLICIT: // Parameter is implicit, occupies no space in // instruction break; // There is a ModR/M byte but it does not necessarily need // to be decoded. case AM_C: // reg field of ModR/M selects a control register case AM_D: // reg field of ModR/M selects a debug register case AM_G: // reg field of ModR/M selects a general register case AM_P: // reg field of ModR/M selects an MMX register case AM_R: // mod field of ModR/M may refer only to a general register case AM_S: // reg field of ModR/M selects a segment register case AM_T: // reg field of ModR/M selects a test register case AM_V: // reg field of ModR/M selects a 128-bit XMM register have_modrm_ = true; break; // In these addressing modes, there is a ModR/M byte and it needs to be // decoded. No other (e.g. immediate) params than indicated in ModR/M. case AM_E: // Operand is either a general-purpose register or memory, // specified by ModR/M byte case AM_M: // ModR/M byte will refer only to memory case AM_Q: // Operand is either an MMX register or memory (complex // evaluation), specified by ModR/M byte case AM_W: // Operand is either a 128-bit XMM register or memory (complex // eval), specified by ModR/M byte have_modrm_ = true; should_decode_modrm_ = true; break; // These addressing modes specify an immediate or an offset value // directly, so we need to look at the operand type to see how many // bytes. case AM_I: // Immediate data. case AM_J: // Jump to offset. case AM_O: // Operand is at offset. switch (flag_operand & OT_MASK) { case OT_B: // Byte regardless of operand-size attribute. operand_bytes_ += OS_BYTE; break; case OT_C: // Byte or word, depending on operand-size attribute. if (operand_is_32_bits_) operand_bytes_ += OS_WORD; else operand_bytes_ += OS_BYTE; break; case OT_D: // Doubleword, regardless of operand-size attribute. operand_bytes_ += OS_DOUBLE_WORD; break; case OT_DQ: // Double-quadword, regardless of operand-size attribute. operand_bytes_ += OS_DOUBLE_QUAD_WORD; break; case OT_P: // 32-bit or 48-bit pointer, depending on operand-size // attribute. if (operand_is_32_bits_) operand_bytes_ += OS_48_BIT_POINTER; else operand_bytes_ += OS_32_BIT_POINTER; break; case OT_PS: // 128-bit packed single-precision floating-point data. operand_bytes_ += OS_128_BIT_PACKED_SINGLE_PRECISION_FLOATING; break; case OT_Q: // Quadword, regardless of operand-size attribute. operand_bytes_ += OS_QUAD_WORD; break; case OT_S: // 6-byte pseudo-descriptor. operand_bytes_ += OS_PSEUDO_DESCRIPTOR; break; case OT_SD: // Scalar Double-Precision Floating-Point Value case OT_PD: // Unaligned packed double-precision floating point value operand_bytes_ += OS_DOUBLE_PRECISION_FLOATING; break; case OT_SS: // Scalar element of a 128-bit packed single-precision // floating data. // We simply return enItUnknown since we don't have to support // floating point succeeded = false; break; case OT_V: // Word or doubleword, depending on operand-size attribute. if (operand_is_32_bits_) operand_bytes_ += OS_DOUBLE_WORD; else operand_bytes_ += OS_WORD; break; case OT_W: // Word, regardless of operand-size attribute. operand_bytes_ += OS_WORD; break; // Can safely ignore these. case OT_A: // Two one-word operands in memory or two double-word // operands in memory case OT_PI: // Quadword MMX technology register (e.g. mm0) case OT_SI: // Doubleword integer register (e.g., eax) break; default: break; } break; default: break; } return succeeded; } bool MiniDisassembler::ProcessModrm(unsigned char* start_byte, unsigned int& size) { // If we don't need to decode, we just return the size of the ModR/M // byte (there is never a SIB byte in this case). if (!should_decode_modrm_) { size++; return true; } // We never care about the reg field, only the combination of the mod // and r/m fields, so let's start by packing those fields together into // 5 bits. unsigned char modrm = (*start_byte); unsigned char mod = modrm & 0xC0; // mask out top two bits to get mod field modrm = modrm & 0x07; // mask out bottom 3 bits to get r/m field mod = mod >> 3; // shift the mod field to the right place modrm = mod | modrm; // combine the r/m and mod fields as discussed mod = mod >> 3; // shift the mod field to bits 2..0 // Invariant: modrm contains the mod field in bits 4..3 and the r/m field // in bits 2..0, and mod contains the mod field in bits 2..0 const ModrmEntry* modrm_entry = 0; if (address_is_32_bits_) modrm_entry = &s_ia32_modrm_map_[modrm]; else modrm_entry = &s_ia16_modrm_map_[modrm]; // Invariant: modrm_entry points to information that we need to decode // the ModR/M byte. // Add to the count of operand bytes, if the ModR/M byte indicates // that some operands are encoded in the instruction. if (modrm_entry->is_encoded_in_instruction_) operand_bytes_ += modrm_entry->operand_size_; // Process the SIB byte if necessary, and return the count // of ModR/M and SIB bytes. if (modrm_entry->use_sib_byte_) { size++; return ProcessSib(start_byte + 1, mod, size); } else { size++; return true; } } bool MiniDisassembler::ProcessSib(unsigned char* start_byte, unsigned char mod, unsigned int& size) { // get the mod field from the 2..0 bits of the SIB byte unsigned char sib_base = (*start_byte) & 0x07; if (0x05 == sib_base) { switch (mod) { case 0x00: // mod == 00 case 0x02: // mod == 10 operand_bytes_ += OS_DOUBLE_WORD; break; case 0x01: // mod == 01 operand_bytes_ += OS_BYTE; break; case 0x03: // mod == 11 // According to the IA-32 docs, there does not seem to be a disp // value for this value of mod default: break; } } size++; return true; } }; // namespace sidestep ================================================ FILE: distro/google-perftools-1.7/src/windows/mini_disassembler.h ================================================ /* Copyright (c) 2007, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Joi Sigurdsson * * Definition of MiniDisassembler. */ #ifndef GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_H_ #define GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_H_ #include #include "mini_disassembler_types.h" // compatibility shim #include "base/logging.h" #define SIDESTEP_ASSERT(cond) RAW_DCHECK(cond, #cond) #define SIDESTEP_LOG(msg) RAW_VLOG(1, msg) namespace sidestep { // This small disassembler is very limited // in its functionality, and in fact does only the bare minimum required by the // preamble patching utility. It may be useful for other purposes, however. // // The limitations include at least the following: // -# No support for coprocessor opcodes, MMX, etc. // -# No machine-readable identification of opcodes or decoding of // assembly parameters. The name of the opcode (as a string) is given, // however, to aid debugging. // // You may ask what this little disassembler actually does, then? The answer is // that it does the following, which is exactly what the patching utility needs: // -# Indicates if opcode is a jump (any kind) or a return (any kind) // because this is important for the patching utility to determine if // a function is too short or there are jumps too early in it for it // to be preamble patched. // -# The opcode length is always calculated, so that the patching utility // can figure out where the next instruction starts, and whether it // already has enough instructions to replace with the absolute jump // to the patching code. // // The usage is quite simple; just create a MiniDisassembler and use its // Disassemble() method. // // If you would like to extend this disassembler, please refer to the // IA-32 Intel Architecture Software Developers Manual Volume 2: // Instruction Set Reference for information about operand decoding // etc. class MiniDisassembler { public: // Creates a new instance and sets defaults. // // @param operand_default_32_bits If true, the default operand size is // set to 32 bits, which is the default under Win32. Otherwise it is 16 bits. // @param address_default_32_bits If true, the default address size is // set to 32 bits, which is the default under Win32. Otherwise it is 16 bits. MiniDisassembler(bool operand_default_32_bits, bool address_default_32_bits); // Equivalent to MiniDisassembler(true, true); MiniDisassembler(); // Attempts to disassemble a single instruction starting from the // address in memory it is pointed to. // // @param start Address where disassembly should start. // @param instruction_bytes Variable that will be incremented by // the length in bytes of the instruction. // @return enItJump, enItReturn or enItGeneric on success. enItUnknown // if unable to disassemble, enItUnused if this seems to be an unused // opcode. In the last two (error) cases, cbInstruction will be set // to 0xffffffff. // // @post This instance of the disassembler is ready to be used again, // with unchanged defaults from creation time. InstructionType Disassemble(unsigned char* start, unsigned int& instruction_bytes); private: // Makes the disassembler ready for reuse. void Initialize(); // Sets the flags for address and operand sizes. // @return Number of prefix bytes. InstructionType ProcessPrefixes(unsigned char* start, unsigned int& size); // Sets the flag for whether we have ModR/M, and increments // operand_bytes_ if any are specifies by the opcode directly. // @return Number of opcode bytes. InstructionType ProcessOpcode(unsigned char* start, unsigned int table, unsigned int& size); // Checks the type of the supplied operand. Increments // operand_bytes_ if it directly indicates an immediate etc. // operand. Asserts have_modrm_ if the operand specifies // a ModR/M byte. bool ProcessOperand(int flag_operand); // Increments operand_bytes_ by size specified by ModR/M and // by SIB if present. // @return 0 in case of error, 1 if there is just a ModR/M byte, // 2 if there is a ModR/M byte and a SIB byte. bool ProcessModrm(unsigned char* start, unsigned int& size); // Processes the SIB byte that it is pointed to. // @param start Pointer to the SIB byte. // @param mod The mod field from the ModR/M byte. // @return 1 to indicate success (indicates 1 SIB byte) bool ProcessSib(unsigned char* start, unsigned char mod, unsigned int& size); // The instruction type we have decoded from the opcode. InstructionType instruction_type_; // Counts the number of bytes that is occupied by operands in // the current instruction (note: we don't care about how large // operands stored in registers etc. are). unsigned int operand_bytes_; // True iff there is a ModR/M byte in this instruction. bool have_modrm_; // True iff we need to decode the ModR/M byte (sometimes it just // points to a register, we can tell by the addressing mode). bool should_decode_modrm_; // Current operand size is 32 bits if true, 16 bits if false. bool operand_is_32_bits_; // Default operand size is 32 bits if true, 16 bits if false. bool operand_default_is_32_bits_; // Current address size is 32 bits if true, 16 bits if false. bool address_is_32_bits_; // Default address size is 32 bits if true, 16 bits if false. bool address_default_is_32_bits_; // Huge big opcode table based on the IA-32 manual, defined // in Ia32OpcodeMap.cc static const OpcodeTable s_ia32_opcode_map_[]; // Somewhat smaller table to help with decoding ModR/M bytes // when 16-bit addressing mode is being used. Defined in // Ia32ModrmMap.cc static const ModrmEntry s_ia16_modrm_map_[]; // Somewhat smaller table to help with decoding ModR/M bytes // when 32-bit addressing mode is being used. Defined in // Ia32ModrmMap.cc static const ModrmEntry s_ia32_modrm_map_[]; // Indicators of whether we got certain prefixes that certain // silly Intel instructions depend on in nonstandard ways for // their behaviors. bool got_f2_prefix_, got_f3_prefix_, got_66_prefix_; }; }; // namespace sidestep #endif // GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_H_ ================================================ FILE: distro/google-perftools-1.7/src/windows/mini_disassembler_types.h ================================================ /* Copyright (c) 2007, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Joi Sigurdsson * * Several simple types used by the disassembler and some of the patching * mechanisms. */ #ifndef GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_TYPES_H_ #define GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_TYPES_H_ namespace sidestep { // Categories of instructions that we care about enum InstructionType { // This opcode is not used IT_UNUSED, // This disassembler does not recognize this opcode (error) IT_UNKNOWN, // This is not an instruction but a reference to another table IT_REFERENCE, // This byte is a prefix byte that we can ignore IT_PREFIX, // This is a prefix byte that switches to the nondefault address size IT_PREFIX_ADDRESS, // This is a prefix byte that switches to the nondefault operand size IT_PREFIX_OPERAND, // A jump or call instruction IT_JUMP, // A return instruction IT_RETURN, // Any other type of instruction (in this case we don't care what it is) IT_GENERIC, }; // Lists IA-32 operand sizes in multiples of 8 bits enum OperandSize { OS_ZERO = 0, OS_BYTE = 1, OS_WORD = 2, OS_DOUBLE_WORD = 4, OS_QUAD_WORD = 8, OS_DOUBLE_QUAD_WORD = 16, OS_32_BIT_POINTER = 32/8, OS_48_BIT_POINTER = 48/8, OS_SINGLE_PRECISION_FLOATING = 32/8, OS_DOUBLE_PRECISION_FLOATING = 64/8, OS_DOUBLE_EXTENDED_PRECISION_FLOATING = 80/8, OS_128_BIT_PACKED_SINGLE_PRECISION_FLOATING = 128/8, OS_PSEUDO_DESCRIPTOR = 6 }; // Operand addressing methods from the IA-32 manual. The enAmMask value // is a mask for the rest. The other enumeration values are named for the // names given to the addressing methods in the manual, e.g. enAm_D is for // the D addressing method. // // The reason we use a full 4 bytes and a mask, is that we need to combine // these flags with the enOperandType to store the details // on the operand in a single integer. enum AddressingMethod { AM_NOT_USED = 0, // This operand is not used for this instruction AM_MASK = 0x00FF0000, // Mask for the rest of the values in this enumeration AM_A = 0x00010000, // A addressing type AM_C = 0x00020000, // C addressing type AM_D = 0x00030000, // D addressing type AM_E = 0x00040000, // E addressing type AM_F = 0x00050000, // F addressing type AM_G = 0x00060000, // G addressing type AM_I = 0x00070000, // I addressing type AM_J = 0x00080000, // J addressing type AM_M = 0x00090000, // M addressing type AM_O = 0x000A0000, // O addressing type AM_P = 0x000B0000, // P addressing type AM_Q = 0x000C0000, // Q addressing type AM_R = 0x000D0000, // R addressing type AM_S = 0x000E0000, // S addressing type AM_T = 0x000F0000, // T addressing type AM_V = 0x00100000, // V addressing type AM_W = 0x00110000, // W addressing type AM_X = 0x00120000, // X addressing type AM_Y = 0x00130000, // Y addressing type AM_REGISTER = 0x00140000, // Specific register is always used as this op AM_IMPLICIT = 0x00150000, // An implicit, fixed value is used }; // Operand types from the IA-32 manual. The enOtMask value is // a mask for the rest. The rest of the values are named for the // names given to these operand types in the manual, e.g. enOt_ps // is for the ps operand type in the manual. // // The reason we use a full 4 bytes and a mask, is that we need // to combine these flags with the enAddressingMethod to store the details // on the operand in a single integer. enum OperandType { OT_MASK = 0xFF000000, OT_A = 0x01000000, OT_B = 0x02000000, OT_C = 0x03000000, OT_D = 0x04000000, OT_DQ = 0x05000000, OT_P = 0x06000000, OT_PI = 0x07000000, OT_PS = 0x08000000, // actually unsupported for (we don't know its size) OT_Q = 0x09000000, OT_S = 0x0A000000, OT_SS = 0x0B000000, OT_SI = 0x0C000000, OT_V = 0x0D000000, OT_W = 0x0E000000, OT_SD = 0x0F000000, // scalar double-precision floating-point value OT_PD = 0x10000000, // double-precision floating point // dummy "operand type" for address mode M - which doesn't specify // operand type OT_ADDRESS_MODE_M = 0x80000000 }; // Everything that's in an Opcode (see below) except the three // alternative opcode structs for different prefixes. struct SpecificOpcode { // Index to continuation table, or 0 if this is the last // byte in the opcode. int table_index_; // The opcode type InstructionType type_; // Description of the type of the dest, src and aux operands, // put together from an enOperandType flag and an enAddressingMethod // flag. int flag_dest_; int flag_source_; int flag_aux_; // We indicate the mnemonic for debugging purposes const char* mnemonic_; }; // The information we keep in our tables about each of the different // valid instructions recognized by the IA-32 architecture. struct Opcode { // Index to continuation table, or 0 if this is the last // byte in the opcode. int table_index_; // The opcode type InstructionType type_; // Description of the type of the dest, src and aux operands, // put together from an enOperandType flag and an enAddressingMethod // flag. int flag_dest_; int flag_source_; int flag_aux_; // We indicate the mnemonic for debugging purposes const char* mnemonic_; // Alternative opcode info if certain prefixes are specified. // In most cases, all of these are zeroed-out. Only used if // bPrefixDependent is true. bool is_prefix_dependent_; SpecificOpcode opcode_if_f2_prefix_; SpecificOpcode opcode_if_f3_prefix_; SpecificOpcode opcode_if_66_prefix_; }; // Information about each table entry. struct OpcodeTable { // Table of instruction entries const Opcode* table_; // How many bytes left to shift ModR/M byte before applying mask unsigned char shift_; // Mask to apply to byte being looked at before comparing to table unsigned char mask_; // Minimum/maximum indexes in table. unsigned char min_lim_; unsigned char max_lim_; }; // Information about each entry in table used to decode ModR/M byte. struct ModrmEntry { // Is the operand encoded as bytes in the instruction (rather than // if it's e.g. a register in which case it's just encoded in the // ModR/M byte) bool is_encoded_in_instruction_; // Is there a SIB byte? In this case we always need to decode it. bool use_sib_byte_; // What is the size of the operand (only important if it's encoded // in the instruction)? OperandSize operand_size_; }; }; // namespace sidestep #endif // GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_TYPES_H_ ================================================ FILE: distro/google-perftools-1.7/src/windows/nm-pdb.c ================================================ /* Copyright (c) 2008, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: David Vitek * * Dump function addresses using Microsoft debug symbols. This works * on PDB files. Note that this program will download symbols to * c:\websymbols without asking. */ #define WIN32_LEAN_AND_MEAN #define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_DEPRECATE #include #include #include // for _strdup #include #include // Unfortunately, there is no versioning info in dbghelp.h so I can // tell whether it has an old-style (circa VC7.1) IMAGEHLP_MODULE64 // struct, with only a few fields, or a new-style (circa VC8) // IMAGEHLP_MODULE64, with lots of fields. These fields are just used // for debugging, so it's fine to just assume the smaller struct, but // for most people, using a modern MSVC, the full struct is available. // If you are one of those people and would like this extra debugging // info, you can uncomment the line below. //#define VC8_OR_ABOVE #define SEARCH_CAP (1024*1024) #define WEBSYM "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols" typedef struct { char *name; ULONG64 addr; ULONG flags; } SYM; typedef struct { ULONG64 module_base; SYM *syms; DWORD syms_len; DWORD syms_cap; } SYM_CONTEXT; static int sym_cmp(const void *_s1, const void *_s2) { const SYM *s1 = (const SYM *)_s1; const SYM *s2 = (const SYM *)_s2; if (s1->addr < s2->addr) return -1; if (s1->addr > s2->addr) return 1; return 0; } static BOOL CALLBACK EnumSymProc(PSYMBOL_INFO symbol_info, ULONG symbol_size, PVOID user_context) { SYM_CONTEXT *ctx = (SYM_CONTEXT*)user_context; if (symbol_info->Address < ctx->module_base || (symbol_info->Flags & SYMFLAG_TLSREL)) { return TRUE; } if (ctx->syms_len == ctx->syms_cap) { if (!ctx->syms_cap) ctx->syms_cap++; ctx->syms_cap *= 2; ctx->syms = realloc(ctx->syms, sizeof(ctx->syms[0]) * ctx->syms_cap); } ctx->syms[ctx->syms_len].name = _strdup(symbol_info->Name); ctx->syms[ctx->syms_len].addr = symbol_info->Address; ctx->syms[ctx->syms_len].flags = symbol_info->Flags; ctx->syms_len++; return TRUE; } static void MaybePrint(const char* var, const char* description) { if (var[0]) printf("%s: %s\n", description, var); } static void PrintAvailability(BOOL var, const char *description) { printf("s: %s\n", description, (var ? "Available" : "Not available")); } static void ShowSymbolInfo(HANDLE process, ULONG64 module_base) { /* Get module information. */ IMAGEHLP_MODULE64 module_info; BOOL getmoduleinfo_rv; printf("Load Address: %I64x\n", module_base); memset(&module_info, 0, sizeof(module_info)); module_info.SizeOfStruct = sizeof(module_info); getmoduleinfo_rv = SymGetModuleInfo64(process, module_base, &module_info); if (!getmoduleinfo_rv) { printf("Error: SymGetModuleInfo64() failed. Error code: %u\n", GetLastError()); return; } /* Display information about symbols, based on kind of symbol. */ switch (module_info.SymType) { case SymNone: printf(("No symbols available for the module.\n")); break; case SymExport: printf(("Loaded symbols: Exports\n")); break; case SymCoff: printf(("Loaded symbols: COFF\n")); break; case SymCv: printf(("Loaded symbols: CodeView\n")); break; case SymSym: printf(("Loaded symbols: SYM\n")); break; case SymVirtual: printf(("Loaded symbols: Virtual\n")); break; case SymPdb: printf(("Loaded symbols: PDB\n")); break; case SymDia: printf(("Loaded symbols: DIA\n")); break; case SymDeferred: printf(("Loaded symbols: Deferred\n")); /* not actually loaded */ break; default: printf(("Loaded symbols: Unknown format.\n")); break; } MaybePrint("Image name", module_info.ImageName); MaybePrint("Loaded image name", module_info.LoadedImageName); #ifdef VC8_OR_ABOVE /* TODO(csilvers): figure out how to tell */ MaybePrint("PDB file name", module_info.LoadedPdbName); if (module_info.PdbUnmatched || module_info.DbgUnmatched) { /* This can only happen if the debug information is contained in a * separate file (.DBG or .PDB) */ printf(("Warning: Unmatched symbols.\n")); } #endif /* Contents */ #ifdef VC8_OR_ABOVE /* TODO(csilvers): figure out how to tell */ PrintAvailability("Line numbers", module_info.LineNumbers); PrintAvailability("Global symbols", module_info.GlobalSymbols); PrintAvailability("Type information", module_info.TypeInfo); #endif } void usage() { fprintf(stderr, "usage: nm-pdb [-C|--demangle] \n"); } int main(int argc, char *argv[]) { DWORD error; HANDLE process; ULONG64 module_base; SYM_CONTEXT ctx; int i; char* search; char* filename = NULL; int rv = 0; /* We may add SYMOPT_UNDNAME if --demangle is specified: */ DWORD symopts = SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "--demangle") == 0 || strcmp(argv[i], "-C") == 0) { symopts |= SYMOPT_UNDNAME; } else if (strcmp(argv[i], "--help") == 0) { usage(); exit(0); } else { break; } } if (i != argc - 1) { usage(); exit(1); } filename = argv[i]; process = GetCurrentProcess(); if (!SymInitialize(process, NULL, FALSE)) { error = GetLastError(); fprintf(stderr, "SymInitialize returned error : %d\n", error); return 1; } search = malloc(SEARCH_CAP); if (SymGetSearchPath(process, search, SEARCH_CAP)) { if (strlen(search) + sizeof(";" WEBSYM) > SEARCH_CAP) { fprintf(stderr, "Search path too long\n"); SymCleanup(process); return 1; } strcat(search, ";" WEBSYM); } else { error = GetLastError(); fprintf(stderr, "SymGetSearchPath returned error : %d\n", error); rv = 1; /* An error, but not a fatal one */ strcpy(search, WEBSYM); /* Use a default value */ } if (!SymSetSearchPath(process, search)) { error = GetLastError(); fprintf(stderr, "SymSetSearchPath returned error : %d\n", error); rv = 1; /* An error, but not a fatal one */ } SymSetOptions(symopts); module_base = SymLoadModuleEx(process, NULL, filename, NULL, 0, 0, NULL, 0); if (!module_base) { /* SymLoadModuleEx failed */ error = GetLastError(); fprintf(stderr, "SymLoadModuleEx returned error : %d for %s\n", error, filename); SymCleanup(process); return 1; } ShowSymbolInfo(process, module_base); memset(&ctx, 0, sizeof(ctx)); ctx.module_base = module_base; if (!SymEnumSymbols(process, module_base, NULL, EnumSymProc, &ctx)) { error = GetLastError(); fprintf(stderr, "SymEnumSymbols returned error: %d\n", error); rv = 1; } else { DWORD j; qsort(ctx.syms, ctx.syms_len, sizeof(ctx.syms[0]), sym_cmp); for (j = 0; j < ctx.syms_len; j++) { printf("%016I64x X %s\n", ctx.syms[j].addr, ctx.syms[j].name); } /* In a perfect world, maybe we'd clean up ctx's memory? */ } SymUnloadModule64(process, module_base); SymCleanup(process); return rv; } ================================================ FILE: distro/google-perftools-1.7/src/windows/override_functions.cc ================================================ // Copyright (c) 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // --- // Author: Mike Belshe // // To link tcmalloc into a EXE or DLL statically without using the patching // facility, we can take a stock libcmt and remove all the allocator functions. // When we relink the EXE/DLL with the modified libcmt and tcmalloc, a few // functions are missing. This file contains the additional overrides which // are required in the VS2005 libcmt in order to link the modified libcmt. // // See also // http://groups.google.com/group/google-perftools/browse_thread/thread/41cd3710af85e57b #include #ifndef _WIN32 # error You should only be including this file in a windows environment! #endif #ifndef WIN32_OVERRIDE_ALLOCATORS # error This file is intended for use when overriding allocators #endif #include "tcmalloc.cc" extern "C" void* _recalloc(void* p, size_t n, size_t size) { void* result = realloc(p, n * size); memset(result, 0, n * size); return result; } extern "C" void* _calloc_impl(size_t n, size_t size) { return calloc(n, size); } extern "C" size_t _msize(void* p) { return MallocExtension::instance()->GetAllocatedSize(p); } extern "C" intptr_t _get_heap_handle() { return 0; } // The CRT heap initialization stub. extern "C" int _heap_init() { // We intentionally leak this object. It lasts for the process // lifetime. Trying to teardown at _heap_term() is so late that // you can't do anything useful anyway. new TCMallocGuard(); return 1; } // The CRT heap cleanup stub. extern "C" void _heap_term() { } extern "C" int _set_new_mode(int flag) { return tc_set_new_mode(flag); } #ifndef NDEBUG #undef malloc #undef free #undef calloc int _CrtDbgReport(int, const char*, int, const char*, const char*, ...) { return 0; } int _CrtDbgReportW(int, const wchar_t*, int, const wchar_t*, const wchar_t*, ...) { return 0; } int _CrtSetReportMode(int, int) { return 0; } extern "C" void* _malloc_dbg(size_t size, int , const char*, int) { return malloc(size); } extern "C" void _free_dbg(void* ptr, int) { free(ptr); } extern "C" void* _calloc_dbg(size_t n, size_t size, int, const char*, int) { return calloc(n, size); } #endif // NDEBUG // We set this to 1 because part of the CRT uses a check of _crtheap != 0 // to test whether the CRT has been initialized. Once we've ripped out // the allocators from libcmt, we need to provide this definition so that // the rest of the CRT is still usable. extern "C" void* _crtheap = reinterpret_cast(1); ================================================ FILE: distro/google-perftools-1.7/src/windows/patch_functions.cc ================================================ // Copyright (c) 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // --- // Author: Craig Silverstein // // The main purpose of this file is to patch the libc allocation // routines (malloc and friends, but also _msize and other // windows-specific libc-style routines). However, we also patch // windows routines to do accounting. We do better at the former than // the latter. Here are some comments from Paul Pluzhnikov about what // it might take to do a really good job patching windows routines to // keep track of memory usage: // // "You should intercept at least the following: // HeapCreate HeapDestroy HeapAlloc HeapReAlloc HeapFree // RtlCreateHeap RtlDestroyHeap RtlAllocateHeap RtlFreeHeap // malloc calloc realloc free // malloc_dbg calloc_dbg realloc_dbg free_dbg // Some of these call the other ones (but not always), sometimes // recursively (i.e. HeapCreate may call HeapAlloc on a different // heap, IIRC)." // // Since Paul didn't mention VirtualAllocEx, he may not have even been // considering all the mmap-like functions that windows has (or he may // just be ignoring it because he's seen we already patch it). Of the // above, we do not patch the *_dbg functions, and of the windows // functions, we only patch HeapAlloc and HeapFree. // // The *_dbg functions come into play with /MDd, /MTd, and /MLd, // probably. It may be ok to just turn off tcmalloc in those cases -- // if the user wants the windows debug malloc, they probably don't // want tcmalloc! We should also test with all of /MD, /MT, and /ML, // which we're not currently doing. // TODO(csilvers): try to do better here? Paul does conclude: // "Keeping track of all of this was a nightmare." #ifndef _WIN32 # error You should only be including windows/patch_functions.cc in a windows environment! #endif #include #ifdef WIN32_OVERRIDE_ALLOCATORS #error This file is intended for patching allocators - use override_functions.cc instead. #endif // We use psapi. Non-MSVC systems will have to link this in themselves. #ifdef _MSC_VER #pragma comment(lib, "Psapi.lib") #endif // Make sure we always use the 'old' names of the psapi functions. #ifndef PSAPI_VERSION #define PSAPI_VERSION 1 #endif #include #include #include // for _msize and _expand #include // for EnumProcessModules, GetModuleInformation, etc. #include #include #include #include #include "base/spinlock.h" #include "google/malloc_hook.h" #include "malloc_hook-inl.h" #include "preamble_patcher.h" // The maximum number of modules we allow to be in one executable const int kMaxModules = 8182; // These are hard-coded, unfortunately. :-( They are also probably // compiler specific. See get_mangled_names.cc, in this directory, // for instructions on how to update these names for your compiler. const char kMangledNew[] = "??2@YAPAXI@Z"; const char kMangledNewArray[] = "??_U@YAPAXI@Z"; const char kMangledDelete[] = "??3@YAXPAX@Z"; const char kMangledDeleteArray[] = "??_V@YAXPAX@Z"; const char kMangledNewNothrow[] = "??2@YAPAXIABUnothrow_t@std@@@Z"; const char kMangledNewArrayNothrow[] = "??_U@YAPAXIABUnothrow_t@std@@@Z"; const char kMangledDeleteNothrow[] = "??3@YAXPAXABUnothrow_t@std@@@Z"; const char kMangledDeleteArrayNothrow[] = "??_V@YAXPAXABUnothrow_t@std@@@Z"; // This is an unused but exported symbol that we can use to tell the // MSVC linker to bring in libtcmalloc, via the /INCLUDE linker flag. // Without this, the linker will likely decide that libtcmalloc.dll // doesn't add anything to the executable (since it does all its work // through patching, which the linker can't see), and ignore it // entirely. (The name 'tcmalloc' is already reserved for a // namespace. I'd rather export a variable named "_tcmalloc", but I // couldn't figure out how to get that to work. This function exports // the symbol "__tcmalloc".) extern "C" PERFTOOLS_DLL_DECL void _tcmalloc(); void _tcmalloc() { } namespace { // most everything here is in an unnamed namespace typedef void (*GenericFnPtr)(); using sidestep::PreamblePatcher; struct ModuleEntryCopy; // defined below // These functions are how we override the memory allocation // functions, just like tcmalloc.cc and malloc_hook.cc do. // This is information about the routines we're patching, for a given // module that implements libc memory routines. A single executable // can have several libc implementations running about (in different // .dll's), and we need to patch/unpatch them all. This defines // everything except the new functions we're patching in, which // are defined in LibcFunctions, below. class LibcInfo { public: LibcInfo() { memset(this, 0, sizeof(*this)); // easiest way to initialize the array } bool patched() const { return is_valid(); } void set_is_valid(bool b) { is_valid_ = b; } // According to http://msdn.microsoft.com/en-us/library/ms684229(VS.85).aspx: // "The load address of a module (lpBaseOfDll) is the same as the HMODULE // value." HMODULE hmodule() const { return reinterpret_cast(const_cast(module_base_address_)); } // Populates all the windows_fn_[] vars based on our module info. // Returns false if windows_fn_ is all NULL's, because there's // nothing to patch. Also populates the rest of the module_entry // info, such as the module's name. bool PopulateWindowsFn(const ModuleEntryCopy& module_entry); protected: void CopyFrom(const LibcInfo& that) { if (this == &that) return; this->is_valid_ = that.is_valid_; memcpy(this->windows_fn_, that.windows_fn_, sizeof(windows_fn_)); this->module_base_address_ = that.module_base_address_; this->module_base_size_ = that.module_base_size_; } enum { kMalloc, kFree, kRealloc, kCalloc, kNew, kNewArray, kDelete, kDeleteArray, kNewNothrow, kNewArrayNothrow, kDeleteNothrow, kDeleteArrayNothrow, // These are windows-only functions from malloc.h k_Msize, k_Expand, kNumFunctions }; // I'd like to put these together in a struct (perhaps in the // subclass, so we can put in perftools_fn_ as well), but vc8 seems // to have a bug where it doesn't initialize the struct properly if // we try to take the address of a function that's not yet loaded // from a dll, as is the common case for static_fn_. So we need // each to be in its own array. :-( static const char* const function_name_[kNumFunctions]; // This function is only used when statically linking the binary. // In that case, loading malloc/etc from the dll (via // PatchOneModule) won't work, since there are no dlls. Instead, // you just want to be taking the address of malloc/etc directly. // In the common, non-static-link case, these pointers will all be // NULL, since this initializer runs before msvcrt.dll is loaded. static const GenericFnPtr static_fn_[kNumFunctions]; // This is the address of the function we are going to patch // (malloc, etc). Other info about the function is in the // patch-specific subclasses, below. GenericFnPtr windows_fn_[kNumFunctions]; // This is set to true when this structure is initialized (because // we're patching a new library) and set to false when it's // uninitialized (because we've freed that library). bool is_valid_; const void *module_base_address_; size_t module_base_size_; public: // These shouldn't have to be public, since only subclasses of // LibcInfo need it, but they do. Maybe something to do with // templates. Shrug. I hide them down here so users won't see // them. :-) (OK, I also need to define ctrgProcAddress late.) bool is_valid() const { return is_valid_; } GenericFnPtr windows_fn(int ifunction) const { return windows_fn_[ifunction]; } // These three are needed by ModuleEntryCopy. static const int ctrgProcAddress = kNumFunctions; static GenericFnPtr static_fn(int ifunction) { return static_fn_[ifunction]; } static const char* const function_name(int ifunction) { return function_name_[ifunction]; } }; // Template trickiness: logically, a LibcInfo would include // Windows_malloc_, origstub_malloc_, and Perftools_malloc_: for a // given module, these three go together. And in fact, // Perftools_malloc_ may need to call origstub_malloc_, which means we // either need to change Perftools_malloc_ to take origstub_malloc_ as // an arugment -- unfortunately impossible since it needs to keep the // same API as normal malloc -- or we need to write a different // version of Perftools_malloc_ for each LibcInfo instance we create. // We choose the second route, and use templates to implement it (we // could have also used macros). So to get multiple versions // of the struct, we say "struct<1> var1; struct<2> var2;". The price // we pay is some code duplication, and more annoying, each instance // of this var is a separate type. template class LibcInfoWithPatchFunctions : public LibcInfo { public: // me_info should have had PopulateWindowsFn() called on it, so the // module_* vars and windows_fn_ are set up. bool Patch(const LibcInfo& me_info); void Unpatch(); private: // This holds the original function contents after we patch the function. // This has to be defined static in the subclass, because the perftools_fns // reference origstub_fn_. static GenericFnPtr origstub_fn_[kNumFunctions]; // This is the function we want to patch in static const GenericFnPtr perftools_fn_[kNumFunctions]; static void* Perftools_malloc(size_t size) __THROW; static void Perftools_free(void* ptr) __THROW; static void* Perftools_realloc(void* ptr, size_t size) __THROW; static void* Perftools_calloc(size_t nmemb, size_t size) __THROW; static void* Perftools_new(size_t size); static void* Perftools_newarray(size_t size); static void Perftools_delete(void *ptr); static void Perftools_deletearray(void *ptr); static void* Perftools_new_nothrow(size_t size, const std::nothrow_t&) __THROW; static void* Perftools_newarray_nothrow(size_t size, const std::nothrow_t&) __THROW; static void Perftools_delete_nothrow(void *ptr, const std::nothrow_t&) __THROW; static void Perftools_deletearray_nothrow(void *ptr, const std::nothrow_t&) __THROW; static size_t Perftools__msize(void *ptr) __THROW; static void* Perftools__expand(void *ptr, size_t size) __THROW; // malloc.h also defines these functions: // _aligned_malloc, _aligned_free, // _recalloc, _aligned_offset_malloc, _aligned_realloc, _aligned_recalloc // _aligned_offset_realloc, _aligned_offset_recalloc, _malloca, _freea // But they seem pretty obscure, and I'm fine not overriding them for now. // It may be they all call into malloc/free anyway. }; // This is a subset of MODDULEENTRY32, that we need for patching. struct ModuleEntryCopy { LPVOID modBaseAddr; // the same as hmodule DWORD modBaseSize; // This is not part of MODDULEENTRY32, but is needed to avoid making // windows syscalls while we're holding patch_all_modules_lock (see // lock-inversion comments at patch_all_modules_lock definition, below). GenericFnPtr rgProcAddresses[LibcInfo::ctrgProcAddress]; ModuleEntryCopy() { modBaseAddr = NULL; modBaseSize = 0; for (int i = 0; i < sizeof(rgProcAddresses)/sizeof(*rgProcAddresses); i++) rgProcAddresses[i] = LibcInfo::static_fn(i); } ModuleEntryCopy(const MODULEINFO& mi) { this->modBaseAddr = mi.lpBaseOfDll; this->modBaseSize = mi.SizeOfImage; LPVOID modEndAddr = (char*)mi.lpBaseOfDll + mi.SizeOfImage; for (int i = 0; i < sizeof(rgProcAddresses)/sizeof(*rgProcAddresses); i++) { FARPROC target = ::GetProcAddress( reinterpret_cast(mi.lpBaseOfDll), LibcInfo::function_name(i)); // Sometimes a DLL forwards a function to a function in another // DLL. We don't want to patch those forwarded functions -- // they'll get patched when the other DLL is processed. if (target >= modBaseAddr && target < modEndAddr) rgProcAddresses[i] = (GenericFnPtr)target; else rgProcAddresses[i] = (GenericFnPtr)NULL; } } }; // This class is easier because there's only one of them. class WindowsInfo { public: void Patch(); void Unpatch(); private: // TODO(csilvers): should we be patching GlobalAlloc/LocalAlloc instead, // for pre-XP systems? enum { kHeapAlloc, kHeapFree, kVirtualAllocEx, kVirtualFreeEx, kMapViewOfFileEx, kUnmapViewOfFile, kLoadLibraryExW, kFreeLibrary, kNumFunctions }; struct FunctionInfo { const char* const name; // name of fn in a module (eg "malloc") GenericFnPtr windows_fn; // the fn whose name we call (&malloc) GenericFnPtr origstub_fn; // original fn contents after we patch const GenericFnPtr perftools_fn; // fn we want to patch in }; static FunctionInfo function_info_[kNumFunctions]; // A Windows-API equivalent of malloc and free static LPVOID WINAPI Perftools_HeapAlloc(HANDLE hHeap, DWORD dwFlags, DWORD_PTR dwBytes); static BOOL WINAPI Perftools_HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem); // A Windows-API equivalent of mmap and munmap, for "anonymous regions" static LPVOID WINAPI Perftools_VirtualAllocEx(HANDLE process, LPVOID address, SIZE_T size, DWORD type, DWORD protect); static BOOL WINAPI Perftools_VirtualFreeEx(HANDLE process, LPVOID address, SIZE_T size, DWORD type); // A Windows-API equivalent of mmap and munmap, for actual files static LPVOID WINAPI Perftools_MapViewOfFileEx(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap, LPVOID lpBaseAddress); static BOOL WINAPI Perftools_UnmapViewOfFile(LPCVOID lpBaseAddress); // We don't need the other 3 variants because they all call this one. */ static HMODULE WINAPI Perftools_LoadLibraryExW(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags); static BOOL WINAPI Perftools_FreeLibrary(HMODULE hLibModule); }; // If you run out, just add a few more to the array. You'll also need // to update the switch statement in PatchOneModule(), and the list in // UnpatchWindowsFunctions(). // main_executable and main_executable_windows are two windows into // the same executable. One is responsible for patching the libc // routines that live in the main executable (if any) to use tcmalloc; // the other is responsible for patching the windows routines like // HeapAlloc/etc to use tcmalloc. static LibcInfoWithPatchFunctions<0> main_executable; static LibcInfoWithPatchFunctions<1> libc1; static LibcInfoWithPatchFunctions<2> libc2; static LibcInfoWithPatchFunctions<3> libc3; static LibcInfoWithPatchFunctions<4> libc4; static LibcInfoWithPatchFunctions<5> libc5; static LibcInfoWithPatchFunctions<6> libc6; static LibcInfoWithPatchFunctions<7> libc7; static LibcInfoWithPatchFunctions<8> libc8; static LibcInfo* g_module_libcs[] = { &libc1, &libc2, &libc3, &libc4, &libc5, &libc6, &libc7, &libc8 }; static WindowsInfo main_executable_windows; const char* const LibcInfo::function_name_[] = { "malloc", "free", "realloc", "calloc", kMangledNew, kMangledNewArray, kMangledDelete, kMangledDeleteArray, // Ideally we should patch the nothrow versions of new/delete, but // at least in msvcrt, nothrow-new machine-code is of a type we // can't patch. Since these are relatively rare, I'm hoping it's ok // not to patch them. (NULL name turns off patching.) NULL, // kMangledNewNothrow, NULL, // kMangledNewArrayNothrow, NULL, // kMangledDeleteNothrow, NULL, // kMangledDeleteArrayNothrow, "_msize", "_expand", }; // For mingw, I can't patch the new/delete here, because the // instructions are too small to patch. Luckily, they're so small // because all they do is call into malloc/free, so they still end up // calling tcmalloc routines, and we don't actually lose anything // (except maybe some stacktrace goodness) by not patching. const GenericFnPtr LibcInfo::static_fn_[] = { (GenericFnPtr)&::malloc, (GenericFnPtr)&::free, (GenericFnPtr)&::realloc, (GenericFnPtr)&::calloc, #ifdef __MINGW32__ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, #else (GenericFnPtr)(void*(*)(size_t))&::operator new, (GenericFnPtr)(void*(*)(size_t))&::operator new[], (GenericFnPtr)(void(*)(void*))&::operator delete, (GenericFnPtr)(void(*)(void*))&::operator delete[], (GenericFnPtr) (void*(*)(size_t, struct std::nothrow_t const &))&::operator new, (GenericFnPtr) (void*(*)(size_t, struct std::nothrow_t const &))&::operator new[], (GenericFnPtr) (void(*)(void*, struct std::nothrow_t const &))&::operator delete, (GenericFnPtr) (void(*)(void*, struct std::nothrow_t const &))&::operator delete[], #endif (GenericFnPtr)&::_msize, (GenericFnPtr)&::_expand, }; template GenericFnPtr LibcInfoWithPatchFunctions::origstub_fn_[] = { // This will get filled in at run-time, as patching is done. }; template const GenericFnPtr LibcInfoWithPatchFunctions::perftools_fn_[] = { (GenericFnPtr)&Perftools_malloc, (GenericFnPtr)&Perftools_free, (GenericFnPtr)&Perftools_realloc, (GenericFnPtr)&Perftools_calloc, (GenericFnPtr)&Perftools_new, (GenericFnPtr)&Perftools_newarray, (GenericFnPtr)&Perftools_delete, (GenericFnPtr)&Perftools_deletearray, (GenericFnPtr)&Perftools_new_nothrow, (GenericFnPtr)&Perftools_newarray_nothrow, (GenericFnPtr)&Perftools_delete_nothrow, (GenericFnPtr)&Perftools_deletearray_nothrow, (GenericFnPtr)&Perftools__msize, (GenericFnPtr)&Perftools__expand, }; /*static*/ WindowsInfo::FunctionInfo WindowsInfo::function_info_[] = { { "HeapAlloc", NULL, NULL, (GenericFnPtr)&Perftools_HeapAlloc }, { "HeapFree", NULL, NULL, (GenericFnPtr)&Perftools_HeapFree }, { "VirtualAllocEx", NULL, NULL, (GenericFnPtr)&Perftools_VirtualAllocEx }, { "VirtualFreeEx", NULL, NULL, (GenericFnPtr)&Perftools_VirtualFreeEx }, { "MapViewOfFileEx", NULL, NULL, (GenericFnPtr)&Perftools_MapViewOfFileEx }, { "UnmapViewOfFile", NULL, NULL, (GenericFnPtr)&Perftools_UnmapViewOfFile }, { "LoadLibraryExW", NULL, NULL, (GenericFnPtr)&Perftools_LoadLibraryExW }, { "FreeLibrary", NULL, NULL, (GenericFnPtr)&Perftools_FreeLibrary }, }; bool LibcInfo::PopulateWindowsFn(const ModuleEntryCopy& module_entry) { // First, store the location of the function to patch before // patching it. If none of these functions are found in the module, // then this module has no libc in it, and we just return false. for (int i = 0; i < kNumFunctions; i++) { if (!function_name_[i]) // we can turn off patching by unsetting name continue; // The ::GetProcAddress calls were done in the ModuleEntryCopy // constructor, so we don't have to make any windows calls here. const GenericFnPtr fn = module_entry.rgProcAddresses[i]; if (fn) { windows_fn_[i] = PreamblePatcher::ResolveTarget(fn); } } // Some modules use the same function pointer for new and new[]. If // we find that, set one of the pointers to NULL so we don't double- // patch. Same may happen with new and nothrow-new, or even new[] // and nothrow-new. It's easiest just to check each fn-ptr against // every other. for (int i = 0; i < kNumFunctions; i++) { for (int j = i+1; j < kNumFunctions; j++) { if (windows_fn_[i] == windows_fn_[j]) { // We NULL the later one (j), so as to minimize the chances we // NULL kFree and kRealloc. See comments below. This is fragile! windows_fn_[j] = NULL; } } } // There's always a chance that our module uses the same function // as another module that we've already loaded. In that case, we // need to set our windows_fn to NULL, to avoid double-patching. for (int ifn = 0; ifn < kNumFunctions; ifn++) { for (int imod = 0; imod < sizeof(g_module_libcs)/sizeof(*g_module_libcs); imod++) { if (g_module_libcs[imod]->is_valid() && this->windows_fn(ifn) == g_module_libcs[imod]->windows_fn(ifn)) { windows_fn_[ifn] = NULL; } } } bool found_non_null = false; for (int i = 0; i < kNumFunctions; i++) { if (windows_fn_[i]) found_non_null = true; } if (!found_non_null) return false; // It's important we didn't NULL out windows_fn_[kFree] or [kRealloc]. // The reason is, if those are NULL-ed out, we'll never patch them // and thus never get an origstub_fn_ value for them, and when we // try to call origstub_fn_[kFree/kRealloc] in Perftools_free and // Perftools_realloc, below, it will fail. We could work around // that by adding a pointer from one patch-unit to the other, but we // haven't needed to yet. CHECK(windows_fn_[kFree]); CHECK(windows_fn_[kRealloc]); // OK, we successfully populated. Let's store our member information. module_base_address_ = module_entry.modBaseAddr; module_base_size_ = module_entry.modBaseSize; return true; } template bool LibcInfoWithPatchFunctions::Patch(const LibcInfo& me_info) { CopyFrom(me_info); // copies the module_entry and the windows_fn_ array for (int i = 0; i < kNumFunctions; i++) { if (windows_fn_[i] && windows_fn_[i] != perftools_fn_[i]) { // if origstub_fn_ is not NULL, it's left around from a previous // patch. We need to set it to NULL for the new Patch call. // Since we've patched Unpatch() not to delete origstub_fn_ (it // causes problems in some contexts, though obviously not this // one), we should delete it now, before setting it to NULL. // NOTE: casting from a function to a pointer is contra the C++ // spec. It's not safe on IA64, but is on i386. We use // a C-style cast here to emphasize this is not legal C++. delete[] (char*)(origstub_fn_[i]); origstub_fn_[i] = NULL; // Patch() will fill this in CHECK_EQ(sidestep::SIDESTEP_SUCCESS, PreamblePatcher::Patch(windows_fn_[i], perftools_fn_[i], &origstub_fn_[i])); } } set_is_valid(true); return true; } template void LibcInfoWithPatchFunctions::Unpatch() { // We have to cast our GenericFnPtrs to void* for unpatch. This is // contra the C++ spec; we use C-style casts to empahsize that. for (int i = 0; i < kNumFunctions; i++) { if (windows_fn_[i]) CHECK_EQ(sidestep::SIDESTEP_SUCCESS, PreamblePatcher::Unpatch((void*)windows_fn_[i], (void*)perftools_fn_[i], (void*)origstub_fn_[i])); } set_is_valid(false); } void WindowsInfo::Patch() { HMODULE hkernel32 = ::GetModuleHandleA("kernel32"); CHECK_NE(hkernel32, NULL); // Unlike for libc, we know these exist in our module, so we can get // and patch at the same time. for (int i = 0; i < kNumFunctions; i++) { function_info_[i].windows_fn = (GenericFnPtr) ::GetProcAddress(hkernel32, function_info_[i].name); // If origstub_fn is not NULL, it's left around from a previous // patch. We need to set it to NULL for the new Patch call. // Since we've patched Unpatch() not to delete origstub_fn_ (it // causes problems in some contexts, though obviously not this // one), we should delete it now, before setting it to NULL. // NOTE: casting from a function to a pointer is contra the C++ // spec. It's not safe on IA64, but is on i386. We use // a C-style cast here to emphasize this is not legal C++. delete[] (char*)(function_info_[i].origstub_fn); function_info_[i].origstub_fn = NULL; // Patch() will fill this in CHECK_EQ(sidestep::SIDESTEP_SUCCESS, PreamblePatcher::Patch(function_info_[i].windows_fn, function_info_[i].perftools_fn, &function_info_[i].origstub_fn)); } } void WindowsInfo::Unpatch() { // We have to cast our GenericFnPtrs to void* for unpatch. This is // contra the C++ spec; we use C-style casts to empahsize that. for (int i = 0; i < kNumFunctions; i++) { CHECK_EQ(sidestep::SIDESTEP_SUCCESS, PreamblePatcher::Unpatch((void*)function_info_[i].windows_fn, (void*)function_info_[i].perftools_fn, (void*)function_info_[i].origstub_fn)); } } // You should hold the patch_all_modules_lock when calling this. void PatchOneModuleLocked(const LibcInfo& me_info) { // If we don't already have info on this module, let's add it. This // is where we're sad that each libcX has a different type, so we // can't use an array; instead, we have to use a switch statement. // Patch() returns false if there were no libc functions in the module. for (int i = 0; i < sizeof(g_module_libcs)/sizeof(*g_module_libcs); i++) { if (!g_module_libcs[i]->is_valid()) { // found an empty spot to add! switch (i) { case 0: libc1.Patch(me_info); return; case 1: libc2.Patch(me_info); return; case 2: libc3.Patch(me_info); return; case 3: libc4.Patch(me_info); return; case 4: libc5.Patch(me_info); return; case 5: libc6.Patch(me_info); return; case 6: libc7.Patch(me_info); return; case 7: libc8.Patch(me_info); return; } } } printf("PERFTOOLS ERROR: Too many modules containing libc in this executable\n"); } void PatchMainExecutableLocked() { if (main_executable.patched()) return; // main executable has already been patched ModuleEntryCopy fake_module_entry; // make a fake one to pass into Patch() // No need to call PopulateModuleEntryProcAddresses on the main executable. main_executable.PopulateWindowsFn(fake_module_entry); main_executable.Patch(main_executable); } // This lock is subject to a subtle and annoying lock inversion // problem: it may interact badly with unknown internal windows locks. // In particular, windows may be holding a lock when it calls // LoadLibraryExW and FreeLibrary, which we've patched. We have those // routines call PatchAllModules, which acquires this lock. If we // make windows system calls while holding this lock, those system // calls may need the internal windows locks that are being held in // the call to LoadLibraryExW, resulting in deadlock. The solution is // to be very careful not to call *any* windows routines while holding // patch_all_modules_lock, inside PatchAllModules(). static SpinLock patch_all_modules_lock(SpinLock::LINKER_INITIALIZED); // last_loaded: The set of modules that were loaded the last time // PatchAllModules was called. This is an optimization for only // looking at modules that were added or removed from the last call. static std::set *g_last_loaded; // Iterates over all the modules currently loaded by the executable, // according to windows, and makes sure they're all patched. Most // modules will already be in loaded_modules, meaning we have already // loaded and either patched them or determined they did not need to // be patched. Others will not, which means we need to patch them // (if necessary). Finally, we have to go through the existing // g_module_libcs and see if any of those are *not* in the modules // currently loaded by the executable. If so, we need to invalidate // them. Returns true if we did any work (patching or invalidating), // false if we were a noop. May update loaded_modules as well. // NOTE: you must hold the patch_all_modules_lock to access loaded_modules. bool PatchAllModules() { std::vector modules; bool made_changes = false; const HANDLE hCurrentProcess = GetCurrentProcess(); DWORD num_modules = 0; HMODULE hModules[kMaxModules]; // max # of modules we support in one process if (!::EnumProcessModules(hCurrentProcess, hModules, sizeof(hModules), &num_modules)) { num_modules = 0; } // EnumProcessModules actually set the bytes written into hModules, // so we need to divide to make num_modules actually be a module-count. num_modules /= sizeof(*hModules); if (num_modules >= kMaxModules) { printf("PERFTOOLS ERROR: Too many modules in this executable to try" " to patch them all (if you need to, raise kMaxModules in" " patch_functions.cc).\n"); num_modules = kMaxModules; } // Now we handle the unpatching of modules we have in g_module_libcs // but that were not found in EnumProcessModules. We need to // invalidate them. To speed that up, we store the EnumProcessModules // output in a set. // At the same time, we prepare for the adding of new modules, by // removing from hModules all the modules we know we've already // patched (or decided don't need to be patched). At the end, // hModules will hold only the modules that we need to consider patching. std::set currently_loaded_modules; { SpinLockHolder h(&patch_all_modules_lock); if (!g_last_loaded) g_last_loaded = new std::set; // At the end of this loop, currently_loaded_modules contains the // full list of EnumProcessModules, and hModules just the ones we // haven't handled yet. for (int i = 0; i < num_modules; ) { currently_loaded_modules.insert(hModules[i]); if (g_last_loaded->count(hModules[i]) > 0) { hModules[i] = hModules[--num_modules]; // replace element i with tail } else { i++; // keep element i } } // Now we do the unpatching/invalidation. for (int i = 0; i < sizeof(g_module_libcs)/sizeof(*g_module_libcs); i++) { if (g_module_libcs[i]->patched() && currently_loaded_modules.count(g_module_libcs[i]->hmodule()) == 0) { // Means g_module_libcs[i] is no longer loaded (no me32 matched). // We could call Unpatch() here, but why bother? The module // has gone away, so nobody is going to call into it anyway. g_module_libcs[i]->set_is_valid(false); made_changes = true; } } // Update the loaded module cache. g_last_loaded->swap(currently_loaded_modules); } // Now that we know what modules are new, let's get the info we'll // need to patch them. Note this *cannot* be done while holding the // lock, since it needs to make windows calls (see the lock-inversion // comments before the definition of patch_all_modules_lock). MODULEINFO mi; for (int i = 0; i < num_modules; i++) { if (::GetModuleInformation(hCurrentProcess, hModules[i], &mi, sizeof(mi))) modules.push_back(ModuleEntryCopy(mi)); } // Now we can do the patching of new modules. { SpinLockHolder h(&patch_all_modules_lock); for (std::vector::iterator it = modules.begin(); it != modules.end(); ++it) { LibcInfo libc_info; if (libc_info.PopulateWindowsFn(*it)) { // true==module has libc routines PatchOneModuleLocked(libc_info); made_changes = true; } } // Now that we've dealt with the modules (dlls), update the main // executable. We do this last because PatchMainExecutableLocked // wants to look at how other modules were patched. if (!main_executable.patched()) { PatchMainExecutableLocked(); made_changes = true; } } // TODO(csilvers): for this to be reliable, we need to also take // into account if we *would* have patched any modules had they not // already been loaded. (That is, made_changes should ignore // g_last_loaded.) return made_changes; } } // end unnamed namespace // --------------------------------------------------------------------- // Now that we've done all the patching machinery, let's actually // define the functions we're patching in. Mostly these are // simple wrappers around the do_* routines in tcmalloc.cc. // // In fact, we #include tcmalloc.cc to get at the tcmalloc internal // do_* functions, the better to write our own hook functions. // U-G-L-Y, I know. But the alternatives are, perhaps, worse. This // also lets us define _msize(), _expand(), and other windows-specific // functions here, using tcmalloc internals, without polluting // tcmalloc.cc. // ------------------------------------------------------------------- // TODO(csilvers): refactor tcmalloc.cc into two files, so I can link // against the file with do_malloc, and ignore the one with malloc. #include "tcmalloc.cc" template void* LibcInfoWithPatchFunctions::Perftools_malloc(size_t size) __THROW { void* result = do_malloc_or_cpp_alloc(size); MallocHook::InvokeNewHook(result, size); return result; } template void LibcInfoWithPatchFunctions::Perftools_free(void* ptr) __THROW { MallocHook::InvokeDeleteHook(ptr); // This calls the windows free if do_free decides ptr was not // allocated by tcmalloc. Note it calls the origstub_free from // *this* templatized instance of LibcInfo. See "template // trickiness" above. do_free_with_callback(ptr, (void (*)(void*))origstub_fn_[kFree]); } template void* LibcInfoWithPatchFunctions::Perftools_realloc( void* old_ptr, size_t new_size) __THROW { if (old_ptr == NULL) { void* result = do_malloc_or_cpp_alloc(new_size); MallocHook::InvokeNewHook(result, new_size); return result; } if (new_size == 0) { MallocHook::InvokeDeleteHook(old_ptr); do_free_with_callback(old_ptr, (void (*)(void*))origstub_fn_[kFree]); return NULL; } return do_realloc_with_callback( old_ptr, new_size, (void (*)(void*))origstub_fn_[kFree], (size_t (*)(void*))origstub_fn_[k_Msize]); } template void* LibcInfoWithPatchFunctions::Perftools_calloc( size_t n, size_t elem_size) __THROW { void* result = do_calloc(n, elem_size); MallocHook::InvokeNewHook(result, n * elem_size); return result; } template void* LibcInfoWithPatchFunctions::Perftools_new(size_t size) { void* p = cpp_alloc(size, false); MallocHook::InvokeNewHook(p, size); return p; } template void* LibcInfoWithPatchFunctions::Perftools_newarray(size_t size) { void* p = cpp_alloc(size, false); MallocHook::InvokeNewHook(p, size); return p; } template void LibcInfoWithPatchFunctions::Perftools_delete(void *p) { MallocHook::InvokeDeleteHook(p); do_free_with_callback(p, (void (*)(void*))origstub_fn_[kFree]); } template void LibcInfoWithPatchFunctions::Perftools_deletearray(void *p) { MallocHook::InvokeDeleteHook(p); do_free_with_callback(p, (void (*)(void*))origstub_fn_[kFree]); } template void* LibcInfoWithPatchFunctions::Perftools_new_nothrow( size_t size, const std::nothrow_t&) __THROW { void* p = cpp_alloc(size, true); MallocHook::InvokeNewHook(p, size); return p; } template void* LibcInfoWithPatchFunctions::Perftools_newarray_nothrow( size_t size, const std::nothrow_t&) __THROW { void* p = cpp_alloc(size, true); MallocHook::InvokeNewHook(p, size); return p; } template void LibcInfoWithPatchFunctions::Perftools_delete_nothrow( void *p, const std::nothrow_t&) __THROW { MallocHook::InvokeDeleteHook(p); do_free_with_callback(p, (void (*)(void*))origstub_fn_[kFree]); } template void LibcInfoWithPatchFunctions::Perftools_deletearray_nothrow( void *p, const std::nothrow_t&) __THROW { MallocHook::InvokeDeleteHook(p); do_free_with_callback(p, (void (*)(void*))origstub_fn_[kFree]); } // _msize() lets you figure out how much space is reserved for a // pointer, in Windows. Even if applications don't call it, any DLL // with global constructors will call (transitively) something called // __dllonexit_lk in order to make sure the destructors get called // when the dll unloads. And that will call msize -- horrible things // can ensue if this is not hooked. Other parts of libc may also call // this internally. template size_t LibcInfoWithPatchFunctions::Perftools__msize(void* ptr) __THROW { return GetSizeWithCallback(ptr, (size_t (*)(void*))origstub_fn_[k_Msize]); } // We need to define this because internal windows functions like to // call into it(?). _expand() is like realloc but doesn't move the // pointer. We punt, which will cause callers to fall back on realloc. template void* LibcInfoWithPatchFunctions::Perftools__expand(void *ptr, size_t size) __THROW { return NULL; } LPVOID WINAPI WindowsInfo::Perftools_HeapAlloc(HANDLE hHeap, DWORD dwFlags, DWORD_PTR dwBytes) { LPVOID result = ((LPVOID (WINAPI *)(HANDLE, DWORD, DWORD_PTR)) function_info_[kHeapAlloc].origstub_fn)( hHeap, dwFlags, dwBytes); MallocHook::InvokeNewHook(result, dwBytes); return result; } BOOL WINAPI WindowsInfo::Perftools_HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) { MallocHook::InvokeDeleteHook(lpMem); return ((BOOL (WINAPI *)(HANDLE, DWORD, LPVOID)) function_info_[kHeapFree].origstub_fn)( hHeap, dwFlags, lpMem); } LPVOID WINAPI WindowsInfo::Perftools_VirtualAllocEx(HANDLE process, LPVOID address, SIZE_T size, DWORD type, DWORD protect) { LPVOID result = ((LPVOID (WINAPI *)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD)) function_info_[kVirtualAllocEx].origstub_fn)( process, address, size, type, protect); // VirtualAllocEx() seems to be the Windows equivalent of mmap() MallocHook::InvokeMmapHook(result, address, size, protect, type, -1, 0); return result; } BOOL WINAPI WindowsInfo::Perftools_VirtualFreeEx(HANDLE process, LPVOID address, SIZE_T size, DWORD type) { MallocHook::InvokeMunmapHook(address, size); return ((BOOL (WINAPI *)(HANDLE, LPVOID, SIZE_T, DWORD)) function_info_[kVirtualFreeEx].origstub_fn)( process, address, size, type); } LPVOID WINAPI WindowsInfo::Perftools_MapViewOfFileEx( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap, LPVOID lpBaseAddress) { // For this function pair, you always deallocate the full block of // data that you allocate, so NewHook/DeleteHook is the right API. LPVOID result = ((LPVOID (WINAPI *)(HANDLE, DWORD, DWORD, DWORD, SIZE_T, LPVOID)) function_info_[kMapViewOfFileEx].origstub_fn)( hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap, lpBaseAddress); MallocHook::InvokeNewHook(result, dwNumberOfBytesToMap); return result; } BOOL WINAPI WindowsInfo::Perftools_UnmapViewOfFile(LPCVOID lpBaseAddress) { MallocHook::InvokeDeleteHook(lpBaseAddress); return ((BOOL (WINAPI *)(LPCVOID)) function_info_[kUnmapViewOfFile].origstub_fn)( lpBaseAddress); } // g_load_map holds a copy of windows' refcount for how many times // each currently loaded module has been loaded and unloaded. We use // it as an optimization when the same module is loaded more than // once: as long as the refcount stays above 1, we don't need to worry // about patching because it's already patched. Likewise, we don't // need to unpatch until the refcount drops to 0. load_map is // maintained in LoadLibraryExW and FreeLibrary, and only covers // modules explicitly loaded/freed via those interfaces. static std::map* g_load_map = NULL; HMODULE WINAPI WindowsInfo::Perftools_LoadLibraryExW(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags) { HMODULE rv; // Check to see if the modules is already loaded, flag 0 gets a // reference if it was loaded. If it was loaded no need to call // PatchAllModules, just increase the reference count to match // what GetModuleHandleExW does internally inside windows. if (::GetModuleHandleExW(0, lpFileName, &rv)) { return rv; } else { // Not already loaded, so load it. rv = ((HMODULE (WINAPI *)(LPCWSTR, HANDLE, DWORD)) function_info_[kLoadLibraryExW].origstub_fn)( lpFileName, hFile, dwFlags); // This will patch any newly loaded libraries, if patching needs // to be done. PatchAllModules(); return rv; } } BOOL WINAPI WindowsInfo::Perftools_FreeLibrary(HMODULE hLibModule) { BOOL rv = ((BOOL (WINAPI *)(HMODULE)) function_info_[kFreeLibrary].origstub_fn)(hLibModule); // Check to see if the module is still loaded by passing the base // address and seeing if it comes back with the same address. If it // is the same address it's still loaded, so the FreeLibrary() call // was a noop, and there's no need to redo the patching. HMODULE owner = NULL; BOOL result = ::GetModuleHandleExW( (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT), (LPCWSTR)hLibModule, &owner); if (result && owner == hLibModule) return rv; PatchAllModules(); // this will fix up the list of patched libraries return rv; } // --------------------------------------------------------------------- // PatchWindowsFunctions() // This is the function that is exposed to the outside world. // It should be called before the program becomes multi-threaded, // since main_executable_windows.Patch() is not thread-safe. // --------------------------------------------------------------------- void PatchWindowsFunctions() { // This does the libc patching in every module, and the main executable. PatchAllModules(); main_executable_windows.Patch(); } #if 0 // It's possible to unpatch all the functions when we are exiting. // The idea is to handle properly windows-internal data that is // allocated before PatchWindowsFunctions is called. If all // destruction happened in reverse order from construction, then we // could call UnpatchWindowsFunctions at just the right time, so that // that early-allocated data would be freed using the windows // allocation functions rather than tcmalloc. The problem is that // windows allocates some structures lazily, so it would allocate them // late (using tcmalloc) and then try to deallocate them late as well. // So instead of unpatching, we just modify all the tcmalloc routines // so they call through to the libc rountines if the memory in // question doesn't seem to have been allocated with tcmalloc. I keep // this unpatch code around for reference. void UnpatchWindowsFunctions() { // We need to go back to the system malloc/etc at global destruct time, // so objects that were constructed before tcmalloc, using the system // malloc, can destroy themselves using the system free. This depends // on DLLs unloading in the reverse order in which they load! // // We also go back to the default HeapAlloc/etc, just for consistency. // Who knows, it may help avoid weird bugs in some situations. main_executable_windows.Unpatch(); main_executable.Unpatch(); if (libc1.is_valid()) libc1.Unpatch(); if (libc2.is_valid()) libc2.Unpatch(); if (libc3.is_valid()) libc3.Unpatch(); if (libc4.is_valid()) libc4.Unpatch(); if (libc5.is_valid()) libc5.Unpatch(); if (libc6.is_valid()) libc6.Unpatch(); if (libc7.is_valid()) libc7.Unpatch(); if (libc8.is_valid()) libc8.Unpatch(); } #endif ================================================ FILE: distro/google-perftools-1.7/src/windows/port.cc ================================================ /* Copyright (c) 2007, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Craig Silverstein */ #ifndef _WIN32 # error You should only be including windows/port.cc in a windows environment! #endif #define NOMINMAX // so std::max, below, compiles correctly #include #include // for strlen(), memset(), memcmp() #include #include // for va_list, va_start, va_end #include #include "port.h" #include "base/logging.h" #include "base/spinlock.h" #include "system-alloc.h" // ----------------------------------------------------------------------- // Basic libraries // These call the windows _vsnprintf, but always NUL-terminate. int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) { if (size == 0) // not even room for a \0? return -1; // not what C99 says to do, but what windows does str[size-1] = '\0'; return _vsnprintf(str, size-1, format, ap); } #ifndef HAVE_SNPRINTF int snprintf(char *str, size_t size, const char *format, ...) { va_list ap; va_start(ap, format); const int r = vsnprintf(str, size, format, ap); va_end(ap); return r; } #endif int getpagesize() { static int pagesize = 0; if (pagesize == 0) { SYSTEM_INFO system_info; GetSystemInfo(&system_info); pagesize = std::max(system_info.dwPageSize, system_info.dwAllocationGranularity); } return pagesize; } extern "C" PERFTOOLS_DLL_DECL void* __sbrk(ptrdiff_t increment) { LOG(FATAL, "Windows doesn't implement sbrk!\n"); return NULL; } // We need to write to 'stderr' without having windows allocate memory. // The safest way is via a low-level call like WriteConsoleA(). But // even then we need to be sure to print in small bursts so as to not // require memory allocation. extern "C" PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len) { // Looks like windows allocates for writes of >80 bytes for (int i = 0; i < len; i += 80) { write(STDERR_FILENO, buf + i, std::min(80, len - i)); } } // ----------------------------------------------------------------------- // Threads code bool CheckIfKernelSupportsTLS() { // TODO(csilvers): return true (all win's since win95, at least, support this) return false; } // Windows doesn't support pthread_key_create's destr_function, and in // fact it's a bit tricky to get code to run when a thread exits. This // is cargo-cult magic from http://www.codeproject.com/threads/tls.asp. // This code is for VC++ 7.1 and later; VC++ 6.0 support is possible // but more busy-work -- see the webpage for how to do it. If all // this fails, we could use DllMain instead. The big problem with // DllMain is it doesn't run if this code is statically linked into a // binary (it also doesn't run if the thread is terminated via // TerminateThread, which if we're lucky this routine does). // Force a reference to _tls_used to make the linker create the TLS directory // if it's not already there (that is, even if __declspec(thread) is not used). // Force a reference to p_thread_callback_tcmalloc and p_process_term_tcmalloc // to prevent whole program optimization from discarding the variables. #ifdef _MSC_VER #pragma comment(linker, "/INCLUDE:__tls_used") #pragma comment(linker, "/INCLUDE:_p_thread_callback_tcmalloc") #pragma comment(linker, "/INCLUDE:_p_process_term_tcmalloc") #endif // When destr_fn eventually runs, it's supposed to take as its // argument the tls-value associated with key that pthread_key_create // creates. (Yeah, it sounds confusing but it's really not.) We // store the destr_fn/key pair in this data structure. Because we // store this in a single var, this implies we can only have one // destr_fn in a program! That's enough in practice. If asserts // trigger because we end up needing more, we'll have to turn this // into an array. struct DestrFnClosure { void (*destr_fn)(void*); pthread_key_t key_for_destr_fn_arg; }; static DestrFnClosure destr_fn_info; // initted to all NULL/0. static int on_process_term(void) { if (destr_fn_info.destr_fn) { void *ptr = TlsGetValue(destr_fn_info.key_for_destr_fn_arg); // This shouldn't be necessary, but in Release mode, Windows // sometimes trashes the pointer in the TLS slot, so we need to // remove the pointer from the TLS slot before the thread dies. TlsSetValue(destr_fn_info.key_for_destr_fn_arg, NULL); if (ptr) // pthread semantics say not to call if ptr is NULL (*destr_fn_info.destr_fn)(ptr); } return 0; } static void NTAPI on_tls_callback(HINSTANCE h, DWORD dwReason, PVOID pv) { if (dwReason == DLL_THREAD_DETACH) { // thread is being destroyed! on_process_term(); } } #ifdef _MSC_VER // extern "C" suppresses C++ name mangling so we know the symbol names // for the linker /INCLUDE:symbol pragmas above. extern "C" { // This tells the linker to run these functions. #pragma data_seg(push, old_seg) #pragma data_seg(".CRT$XLB") void (NTAPI *p_thread_callback_tcmalloc)( HINSTANCE h, DWORD dwReason, PVOID pv) = on_tls_callback; #pragma data_seg(".CRT$XTU") int (*p_process_term_tcmalloc)(void) = on_process_term; #pragma data_seg(pop, old_seg) } // extern "C" #else // #ifdef _MSC_VER [probably msys/mingw] // We have to try the DllMain solution here, because we can't use the // msvc-specific pragmas. BOOL WINAPI DllMain(HINSTANCE h, DWORD dwReason, PVOID pv) { if (dwReason == DLL_THREAD_DETACH) on_tls_callback(h, dwReason, pv); else if (dwReason == DLL_PROCESS_DETACH) on_process_term(); return TRUE; } #endif // #ifdef _MSC_VER pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)) { // Semantics are: we create a new key, and then promise to call // destr_fn with TlsGetValue(key) when the thread is destroyed // (as long as TlsGetValue(key) is not NULL). pthread_key_t key = TlsAlloc(); if (destr_fn) { // register it // If this assert fails, we'll need to support an array of destr_fn_infos assert(destr_fn_info.destr_fn == NULL); destr_fn_info.destr_fn = destr_fn; destr_fn_info.key_for_destr_fn_arg = key; } return key; } // ----------------------------------------------------------------------- // These functions replace system-alloc.cc // This is mostly like MmapSysAllocator::Alloc, except it does these weird // munmap's in the middle of the page, which is forbidden in windows. extern void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size, size_t alignment) { // Align on the pagesize boundary const int pagesize = getpagesize(); if (alignment < pagesize) alignment = pagesize; size = ((size + alignment - 1) / alignment) * alignment; // Safest is to make actual_size same as input-size. if (actual_size) { *actual_size = size; } // Ask for extra memory if alignment > pagesize size_t extra = 0; if (alignment > pagesize) { extra = alignment - pagesize; } void* result = VirtualAlloc(0, size + extra, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); if (result == NULL) return NULL; // Adjust the return memory so it is aligned uintptr_t ptr = reinterpret_cast(result); size_t adjust = 0; if ((ptr & (alignment - 1)) != 0) { adjust = alignment - (ptr & (alignment - 1)); } ptr += adjust; return reinterpret_cast(ptr); } void TCMalloc_SystemRelease(void* start, size_t length) { // TODO(csilvers): should I be calling VirtualFree here? } bool RegisterSystemAllocator(SysAllocator *allocator, int priority) { return false; // we don't allow registration on windows, right now } void DumpSystemAllocatorStats(TCMalloc_Printer* printer) { // We don't dump stats on windows, right now } // ----------------------------------------------------------------------- // These functions rework existing functions of the same name in the // Google codebase. // A replacement for HeapProfiler::CleanupOldProfiles. void DeleteMatchingFiles(const char* prefix, const char* full_glob) { WIN32_FIND_DATAA found; // that final A is for Ansi (as opposed to Unicode) HANDLE hFind = FindFirstFileA(full_glob, &found); // A is for Ansi if (hFind != INVALID_HANDLE_VALUE) { const int prefix_length = strlen(prefix); do { const char *fname = found.cFileName; if ((strlen(fname) >= prefix_length) && (memcmp(fname, prefix, prefix_length) == 0)) { RAW_VLOG(0, "Removing old heap profile %s\n", fname); // TODO(csilvers): we really need to unlink dirname + fname _unlink(fname); } } while (FindNextFileA(hFind, &found) != FALSE); // A is for Ansi FindClose(hFind); } } ================================================ FILE: distro/google-perftools-1.7/src/windows/port.h ================================================ /* Copyright (c) 2007, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Craig Silverstein * * These are some portability typedefs and defines to make it a bit * easier to compile this code under VC++. * * Several of these are taken from glib: * http://developer.gnome.org/doc/API/glib/glib-windows-compatability-functions.html */ #ifndef GOOGLE_BASE_WINDOWS_H_ #define GOOGLE_BASE_WINDOWS_H_ // You should never include this file directly, but always include it // from either config.h (MSVC) or mingw.h (MinGW/msys). #if !defined(GOOGLE_PERFTOOLS_WINDOWS_CONFIG_H_) && \ !defined(GOOGLE_PERFTOOLS_WINDOWS_MINGW_H_) # error "port.h should only be included from config.h or mingw.h" #endif #ifdef _WIN32 #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN /* We always want minimal includes */ #endif #include #include /* because we so often use open/close/etc */ #include /* for _getpid */ #include /* for va_list */ #include /* need this to override stdio's (v)snprintf */ // 4018: signed/unsigned mismatch is common (and ok for signed_i < unsigned_i) // 4244: otherwise we get problems when substracting two size_t's to an int // 4288: VC++7 gets confused when a var is defined in a loop and then after it // 4267: too many false positives for "conversion gives possible data loss" // 4290: it's ok windows ignores the "throw" directive // 4996: Yes, we're ok using "unsafe" functions like vsnprintf and getenv() #ifdef _MSC_VER #pragma warning(disable:4018 4244 4288 4267 4290 4996) #endif // ----------------------------------- BASIC TYPES #ifndef HAVE_STDINT_H #ifndef HAVE___INT64 /* we need to have all the __intX names */ # error Do not know how to set up type aliases. Edit port.h for your system. #endif typedef __int8 int8_t; typedef __int16 int16_t; typedef __int32 int32_t; typedef __int64 int64_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; #endif // #ifndef HAVE_STDINT_H // I guess MSVC's doesn't include ssize_t by default? #ifdef _MSC_VER typedef intptr_t ssize_t; #endif // ----------------------------------- THREADS #ifndef HAVE_PTHREAD // not true for MSVC, but may be true for MSYS typedef DWORD pthread_t; typedef DWORD pthread_key_t; typedef LONG pthread_once_t; enum { PTHREAD_ONCE_INIT = 0 }; // important that this be 0! for SpinLock #define pthread_self GetCurrentThreadId #define pthread_equal(pthread_t_1, pthread_t_2) ((pthread_t_1)==(pthread_t_2)) #ifdef __cplusplus // This replaces maybe_threads.{h,cc} extern pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)); // in port.cc #define perftools_pthread_key_create(pkey, destr_fn) \ *(pkey) = PthreadKeyCreate(destr_fn) inline void* perftools_pthread_getspecific(DWORD key) { DWORD err = GetLastError(); void* rv = TlsGetValue(key); if (err) SetLastError(err); return rv; } #define perftools_pthread_setspecific(key, val) \ TlsSetValue((key), (val)) // NOTE: this is Win2K and later. For Win98 we could use a CRITICAL_SECTION... #define perftools_pthread_once(once, init) do { \ if (InterlockedCompareExchange(once, 1, 0) == 0) (init)(); \ } while (0) #endif // __cplusplus #endif // HAVE_PTHREAD // __declspec(thread) isn't usable in a dll opened via LoadLibrary(). // But it doesn't work to LoadLibrary() us anyway, because of all the // things we need to do before main()! So this kind of TLS is safe for us. #define __thread __declspec(thread) // This code is obsolete, but I keep it around in case we are ever in // an environment where we can't or don't want to use google spinlocks // (from base/spinlock.{h,cc}). In that case, uncommenting this out, // and removing spinlock.cc from the build, should be enough to revert // back to using native spinlocks. #if 0 // Windows uses a spinlock internally for its mutexes, making our life easy! // However, the Windows spinlock must always be initialized, making life hard, // since we want LINKER_INITIALIZED. We work around this by having the // linker initialize a bool to 0, and check that before accessing the mutex. // This replaces spinlock.{h,cc}, and all the stuff it depends on (atomicops) #ifdef __cplusplus class SpinLock { public: SpinLock() : initialize_token_(PTHREAD_ONCE_INIT) {} // Used for global SpinLock vars (see base/spinlock.h for more details). enum StaticInitializer { LINKER_INITIALIZED }; explicit SpinLock(StaticInitializer) : initialize_token_(PTHREAD_ONCE_INIT) { perftools_pthread_once(&initialize_token_, InitializeMutex); } // It's important SpinLock not have a destructor: otherwise we run // into problems when the main thread has exited, but other threads // are still running and try to access a main-thread spinlock. This // means we leak mutex_ (we should call DeleteCriticalSection() // here). However, I've verified that all SpinLocks used in // perftools have program-long scope anyway, so the leak is // perfectly fine. But be aware of this for the future! void Lock() { // You'd thionk this would be unnecessary, since we call // InitializeMutex() in our constructor. But sometimes Lock() can // be called before our constructor is! This can only happen in // global constructors, when this is a global. If we live in // bar.cc, and some global constructor in foo.cc calls a routine // in bar.cc that calls this->Lock(), then Lock() may well run // before our global constructor does. To protect against that, // we do this check. For SpinLock objects created after main() // has started, this pthread_once call will always be a noop. perftools_pthread_once(&initialize_token_, InitializeMutex); EnterCriticalSection(&mutex_); } void Unlock() { LeaveCriticalSection(&mutex_); } // Used in assertion checks: assert(lock.IsHeld()) (see base/spinlock.h). inline bool IsHeld() const { // This works, but probes undocumented internals, so I've commented it out. // c.f. http://msdn.microsoft.com/msdnmag/issues/03/12/CriticalSections/ //return mutex_.LockCount>=0 && mutex_.OwningThread==GetCurrentThreadId(); return true; } private: void InitializeMutex() { InitializeCriticalSection(&mutex_); } pthread_once_t initialize_token_; CRITICAL_SECTION mutex_; }; class SpinLockHolder { // Acquires a spinlock for as long as the scope lasts private: SpinLock* lock_; public: inline explicit SpinLockHolder(SpinLock* l) : lock_(l) { l->Lock(); } inline ~SpinLockHolder() { lock_->Unlock(); } }; #endif // #ifdef __cplusplus // This keeps us from using base/spinlock.h's implementation of SpinLock. #define BASE_SPINLOCK_H_ 1 #endif // #if 0 // This replaces testutil.{h,cc} extern PERFTOOLS_DLL_DECL void RunInThread(void (*fn)()); extern PERFTOOLS_DLL_DECL void RunManyInThread(void (*fn)(), int count); extern PERFTOOLS_DLL_DECL void RunManyInThreadWithId(void (*fn)(int), int count, int stacksize); // ----------------------------------- MMAP and other memory allocation #ifndef HAVE_MMAP // not true for MSVC, but may be true for msys #define MAP_FAILED 0 #define MREMAP_FIXED 2 // the value in linux, though it doesn't really matter // These, when combined with the mmap invariants below, yield the proper action #define PROT_READ PAGE_READWRITE #define PROT_WRITE PAGE_READWRITE #define MAP_ANONYMOUS MEM_RESERVE #define MAP_PRIVATE MEM_COMMIT #define MAP_SHARED MEM_RESERVE // value of this #define is 100% arbitrary // VirtualAlloc is only a replacement for mmap when certain invariants are kept #define mmap(start, length, prot, flags, fd, offset) \ ( (start) == NULL && (fd) == -1 && (offset) == 0 && \ (prot) == (PROT_READ|PROT_WRITE) && (flags) == (MAP_PRIVATE|MAP_ANONYMOUS)\ ? VirtualAlloc(0, length, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE) \ : NULL ) #define munmap(start, length) (VirtualFree(start, 0, MEM_RELEASE) ? 0 : -1) #endif // HAVE_MMAP // We could maybe use VirtualAlloc for sbrk as well, but no need #define sbrk(increment) ( (void*)-1 ) // sbrk returns -1 on failure // ----------------------------------- STRING ROUTINES // We can't just use _vsnprintf and _snprintf as drop-in-replacements, // because they don't always NUL-terminate. :-( We also can't use the // name vsnprintf, since windows defines that (but not snprintf (!)). extern PERFTOOLS_DLL_DECL int snprintf(char *str, size_t size, const char *format, ...); extern PERFTOOLS_DLL_DECL int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap); #define vsnprintf(str, size, format, ap) safe_vsnprintf(str, size, format, ap) #define PRIx64 "I64x" #define SCNx64 "I64x" #define PRId64 "I64d" #define SCNd64 "I64d" #define PRIu64 "I64u" #ifdef _WIN64 # define PRIuPTR "llu" # define PRIxPTR "llx" #else # define PRIuPTR "lu" # define PRIxPTR "lx" #endif // ----------------------------------- FILE IO #ifndef PATH_MAX #define PATH_MAX 1024 #endif #ifndef __MINGW32__ enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 }; #endif #define getcwd _getcwd #define access _access #define open _open #define read _read #define write _write #define lseek _lseek #define close _close #define popen _popen #define pclose _pclose #define mkdir(dirname, mode) _mkdir(dirname) #ifndef O_RDONLY #define O_RDONLY _O_RDONLY #endif #ifdef __cplusplus extern "C" #endif PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len); // ----------------------------------- SYSTEM/PROCESS typedef int pid_t; #define getpid _getpid #define getppid() (0) // Handle case when poll is used to simulate sleep. #define poll(r, w, t) \ do { \ assert(r == 0); \ assert(w == 0); \ Sleep(t); \ } while(0) extern PERFTOOLS_DLL_DECL int getpagesize(); // in port.cc // ----------------------------------- OTHER #define srandom srand #define random rand #define sleep(t) Sleep(t * 1000) struct timespec { int tv_sec; int tv_nsec; }; #define nanosleep(tm_ptr, ignored) \ Sleep((tm_ptr)->tv_sec * 1000 + (tm_ptr)->tv_nsec / 1000000) #ifndef __MINGW32__ #define strtoq _strtoi64 #define strtouq _strtoui64 #define strtoll _strtoi64 #define strtoull _strtoui64 #define atoll _atoi64 #endif #define __THROW throw() // ----------------------------------- TCMALLOC-SPECIFIC // tcmalloc.cc calls this so we can patch VirtualAlloc() et al. extern PERFTOOLS_DLL_DECL void PatchWindowsFunctions(); // ----------------------------------- BUILD-SPECIFIC // windows/port.h defines compatibility APIs for several .h files, which // we therefore shouldn't be #including directly. This hack keeps us from // doing so. TODO(csilvers): do something more principled. #define GOOGLE_MAYBE_THREADS_H_ 1 #endif /* _WIN32 */ #endif /* GOOGLE_BASE_WINDOWS_H_ */ ================================================ FILE: distro/google-perftools-1.7/src/windows/preamble_patcher.cc ================================================ /* Copyright (c) 2007, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Joi Sigurdsson * * Implementation of PreamblePatcher */ #include "preamble_patcher.h" #include "mini_disassembler.h" // compatibility shims #include "base/logging.h" // Definitions of assembly statements we need #define ASM_JMP32REL 0xE9 #define ASM_INT3 0xCC #define ASM_JMP32ABS_0 0xFF #define ASM_JMP32ABS_1 0x25 #define ASM_JMP8REL 0xEB namespace sidestep { // Handle a special case that we see with functions that point into an // IAT table (including functions linked statically into the // application): these function already starts with ASM_JMP32*. For // instance, malloc() might be implemented as a JMP to __malloc(). // This function follows the initial JMPs for us, until we get to the // place where the actual code is defined. If we get to STOP_BEFORE, // we return the address before stop_before. void* PreamblePatcher::ResolveTargetImpl(unsigned char* target, unsigned char* stop_before) { if (target == NULL) return NULL; while (1) { unsigned char* new_target; if (target[0] == ASM_JMP32REL) { // target[1-4] holds the place the jmp goes to, but it's // relative to the next instruction. int relative_offset; // Windows guarantees int is 4 bytes SIDESTEP_ASSERT(sizeof(relative_offset) == 4); memcpy(reinterpret_cast(&relative_offset), reinterpret_cast(target + 1), 4); new_target = target + 5 + relative_offset; } else if (target[0] == ASM_JMP8REL) { // Visual Studio 7.1 implements new[] as an 8 bit jump to new signed char relative_offset; memcpy(reinterpret_cast(&relative_offset), reinterpret_cast(target + 1), 1); new_target = target + 2 + relative_offset; } else if (target[0] == ASM_JMP32ABS_0 && target[1] == ASM_JMP32ABS_1) { // Visual studio seems to sometimes do it this way instead of the // previous way. Not sure what the rules are, but it was happening // with operator new in some binaries. void **new_target_v; SIDESTEP_ASSERT(sizeof(new_target) == 4); memcpy(&new_target_v, reinterpret_cast(target + 2), 4); new_target = reinterpret_cast(*new_target_v); } else { break; } if (new_target == stop_before) break; target = new_target; } return target; } // Special case scoped_ptr to avoid dependency on scoped_ptr below. class DeleteUnsignedCharArray { public: DeleteUnsignedCharArray(unsigned char* array) : array_(array) { } ~DeleteUnsignedCharArray() { if (array_) { delete [] array_; } } unsigned char* Release() { unsigned char* temp = array_; array_ = NULL; return temp; } private: unsigned char* array_; }; SideStepError PreamblePatcher::RawPatchWithStubAndProtections( void* target_function, void *replacement_function, unsigned char* preamble_stub, unsigned long stub_size, unsigned long* bytes_needed) { // We need to be able to write to a process-local copy of the first // MAX_PREAMBLE_STUB_SIZE bytes of target_function DWORD old_target_function_protect = 0; BOOL succeeded = ::VirtualProtect(reinterpret_cast(target_function), MAX_PREAMBLE_STUB_SIZE, PAGE_EXECUTE_READWRITE, &old_target_function_protect); if (!succeeded) { SIDESTEP_ASSERT(false && "Failed to make page containing target function " "copy-on-write."); return SIDESTEP_ACCESS_DENIED; } SideStepError error_code = RawPatchWithStub(target_function, replacement_function, preamble_stub, stub_size, bytes_needed); // Restore the protection of the first MAX_PREAMBLE_STUB_SIZE bytes of // pTargetFunction to what they were before we started goofing around. // We do this regardless of whether the patch succeeded or not. succeeded = ::VirtualProtect(reinterpret_cast(target_function), MAX_PREAMBLE_STUB_SIZE, old_target_function_protect, &old_target_function_protect); if (!succeeded) { SIDESTEP_ASSERT(false && "Failed to restore protection to target function."); // We must not return an error here because the function has // likely actually been patched, and returning an error might // cause our client code not to unpatch it. So we just keep // going. } if (SIDESTEP_SUCCESS != error_code) { // Testing RawPatchWithStub, above SIDESTEP_ASSERT(false); return error_code; } // Flush the instruction cache to make sure the processor doesn't execute the // old version of the instructions (before our patch). // // FlushInstructionCache is actually a no-op at least on // single-processor XP machines. I'm not sure why this is so, but // it is, yet I want to keep the call to the API here for // correctness in case there is a difference in some variants of // Windows/hardware. succeeded = ::FlushInstructionCache(::GetCurrentProcess(), target_function, MAX_PREAMBLE_STUB_SIZE); if (!succeeded) { SIDESTEP_ASSERT(false && "Failed to flush instruction cache."); // We must not return an error here because the function has actually // been patched, and returning an error would likely cause our client // code not to unpatch it. So we just keep going. } return SIDESTEP_SUCCESS; } SideStepError PreamblePatcher::RawPatch(void* target_function, void* replacement_function, void** original_function_stub) { if (!target_function || !replacement_function || !original_function_stub || (*original_function_stub) || target_function == replacement_function) { SIDESTEP_ASSERT(false && "Preconditions not met"); return SIDESTEP_INVALID_PARAMETER; } // @see MAX_PREAMBLE_STUB_SIZE for an explanation of how we arrives at // this size unsigned char* preamble_stub = new unsigned char[MAX_PREAMBLE_STUB_SIZE]; if (!preamble_stub) { SIDESTEP_ASSERT(false && "Unable to allocate preamble-stub."); return SIDESTEP_INSUFFICIENT_BUFFER; } // Frees the array at end of scope. DeleteUnsignedCharArray guard_preamble_stub(preamble_stub); // Change the protection of the newly allocated preamble stub to // PAGE_EXECUTE_READWRITE. This is required to work with DEP (Data // Execution Prevention) which will cause an exception if code is executed // from a page on which you do not have read access. DWORD old_stub_protect = 0; BOOL succeeded = ::VirtualProtect(preamble_stub, MAX_PREAMBLE_STUB_SIZE, PAGE_EXECUTE_READWRITE, &old_stub_protect); if (!succeeded) { SIDESTEP_ASSERT(false && "Failed to make page preamble stub read-write-execute."); return SIDESTEP_ACCESS_DENIED; } SideStepError error_code = RawPatchWithStubAndProtections( target_function, replacement_function, preamble_stub, MAX_PREAMBLE_STUB_SIZE, NULL); if (SIDESTEP_SUCCESS != error_code) { SIDESTEP_ASSERT(false); return error_code; } // Flush the instruction cache to make sure the processor doesn't execute the // old version of the instructions (before our patch). // // FlushInstructionCache is actually a no-op at least on // single-processor XP machines. I'm not sure why this is so, but // it is, yet I want to keep the call to the API here for // correctness in case there is a difference in some variants of // Windows/hardware. succeeded = ::FlushInstructionCache(::GetCurrentProcess(), target_function, MAX_PREAMBLE_STUB_SIZE); if (!succeeded) { SIDESTEP_ASSERT(false && "Failed to flush instruction cache."); // We must not return an error here because the function has actually // been patched, and returning an error would likely cause our client // code not to unpatch it. So we just keep going. } SIDESTEP_LOG("PreamblePatcher::RawPatch successfully patched."); // detach the scoped pointer so the memory is not freed *original_function_stub = reinterpret_cast(guard_preamble_stub.Release()); return SIDESTEP_SUCCESS; } SideStepError PreamblePatcher::Unpatch(void* target_function, void* replacement_function, void* original_function_stub) { SIDESTEP_ASSERT(target_function && replacement_function && original_function_stub); if (!target_function || !replacement_function || !original_function_stub) { return SIDESTEP_INVALID_PARAMETER; } // We disassemble the preamble of the _stub_ to see how many bytes we // originally copied to the stub. MiniDisassembler disassembler; unsigned int preamble_bytes = 0; while (preamble_bytes < 5) { InstructionType instruction_type = disassembler.Disassemble( reinterpret_cast(original_function_stub) + preamble_bytes, preamble_bytes); if (IT_GENERIC != instruction_type) { SIDESTEP_ASSERT(false && "Should only have generic instructions in stub!!"); return SIDESTEP_UNSUPPORTED_INSTRUCTION; } } // Before unpatching, target_function should be a JMP to // replacement_function. If it's not, then either it's an error, or // we're falling into the case where the original instruction was a // JMP, and we patched the jumped_to address rather than the JMP // itself. (For instance, if malloc() is just a JMP to __malloc(), // we patched __malloc() and not malloc().) unsigned char* target = reinterpret_cast(target_function); target = reinterpret_cast( ResolveTargetImpl( target, reinterpret_cast(replacement_function))); // We should end at the function we patched. When we patch, we insert // a ASM_JMP32REL instruction, so look for that as a sanity check. if (target[0] != ASM_JMP32REL) { SIDESTEP_ASSERT(false && "target_function does not look like it was patched."); return SIDESTEP_INVALID_PARAMETER; } // We need to be able to write to a process-local copy of the first // MAX_PREAMBLE_STUB_SIZE bytes of target_function DWORD old_target_function_protect = 0; BOOL succeeded = ::VirtualProtect(reinterpret_cast(target_function), MAX_PREAMBLE_STUB_SIZE, PAGE_EXECUTE_READWRITE, &old_target_function_protect); if (!succeeded) { SIDESTEP_ASSERT(false && "Failed to make page containing target function " "copy-on-write."); return SIDESTEP_ACCESS_DENIED; } // Replace the first few bytes of the original function with the bytes we // previously moved to the preamble stub. memcpy(reinterpret_cast(target), original_function_stub, preamble_bytes); // Stub is now useless so delete it. // [csilvers: Commented out for perftools because it causes big problems // when we're unpatching malloc. We just let this live on as a leak.] //delete [] reinterpret_cast(original_function_stub); // Restore the protection of the first MAX_PREAMBLE_STUB_SIZE bytes of // target to what they were before we started goofing around. succeeded = ::VirtualProtect(reinterpret_cast(target), MAX_PREAMBLE_STUB_SIZE, old_target_function_protect, &old_target_function_protect); // Flush the instruction cache to make sure the processor doesn't execute the // old version of the instructions (before our patch). // // See comment on FlushInstructionCache elsewhere in this file. succeeded = ::FlushInstructionCache(::GetCurrentProcess(), target, MAX_PREAMBLE_STUB_SIZE); if (!succeeded) { SIDESTEP_ASSERT(false && "Failed to flush instruction cache."); return SIDESTEP_UNEXPECTED; } SIDESTEP_LOG("PreamblePatcher::Unpatch successfully unpatched."); return SIDESTEP_SUCCESS; } }; // namespace sidestep ================================================ FILE: distro/google-perftools-1.7/src/windows/preamble_patcher.h ================================================ /* Copyright (c) 2007, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Joi Sigurdsson * * Definition of PreamblePatcher */ #ifndef GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_ #define GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_ #include // compatibility shim #include "base/logging.h" #define SIDESTEP_ASSERT(cond) RAW_DCHECK(cond, #cond) #define SIDESTEP_LOG(msg) RAW_VLOG(1, msg) // Maximum size of the preamble stub. We overwrite at least the first 5 // bytes of the function. Considering the worst case scenario, we need 4 // bytes + the max instruction size + 5 more bytes for our jump back to // the original code. With that in mind, 32 is a good number :) #define MAX_PREAMBLE_STUB_SIZE (32) namespace sidestep { // Possible results of patching/unpatching enum SideStepError { SIDESTEP_SUCCESS = 0, SIDESTEP_INVALID_PARAMETER, SIDESTEP_INSUFFICIENT_BUFFER, SIDESTEP_JUMP_INSTRUCTION, SIDESTEP_FUNCTION_TOO_SMALL, SIDESTEP_UNSUPPORTED_INSTRUCTION, SIDESTEP_NO_SUCH_MODULE, SIDESTEP_NO_SUCH_FUNCTION, SIDESTEP_ACCESS_DENIED, SIDESTEP_UNEXPECTED, }; #define SIDESTEP_TO_HRESULT(error) \ MAKE_HRESULT(SEVERITY_ERROR, FACILITY_NULL, error) // Implements a patching mechanism that overwrites the first few bytes of // a function preamble with a jump to our hook function, which is then // able to call the original function via a specially-made preamble-stub // that imitates the action of the original preamble. // // NOTE: This patching mechanism should currently only be used for // non-production code, e.g. unit tests, because it is not threadsafe. // See the TODO in preamble_patcher_with_stub.cc for instructions on what // we need to do before using it in production code; it's fairly simple // but unnecessary for now since we only intend to use it in unit tests. // // To patch a function, use either of the typesafe Patch() methods. You // can unpatch a function using Unpatch(). // // Typical usage goes something like this: // @code // typedef int (*MyTypesafeFuncPtr)(int x); // MyTypesafeFuncPtr original_func_stub; // int MyTypesafeFunc(int x) { return x + 1; } // int HookMyTypesafeFunc(int x) { return 1 + original_func_stub(x); } // // void MyPatchInitializingFunction() { // original_func_stub = PreamblePatcher::Patch( // MyTypesafeFunc, HookMyTypesafeFunc); // if (!original_func_stub) { // // ... error handling ... // } // // // ... continue - you have patched the function successfully ... // } // @endcode // // Note that there are a number of ways that this method of patching can // fail. The most common are: // - If there is a jump (jxx) instruction in the first 5 bytes of // the function being patched, we cannot patch it because in the // current implementation we do not know how to rewrite relative // jumps after relocating them to the preamble-stub. Note that // if you really really need to patch a function like this, it // would be possible to add this functionality (but at some cost). // - If there is a return (ret) instruction in the first 5 bytes // we cannot patch the function because it may not be long enough // for the jmp instruction we use to inject our patch. // - If there is another thread currently executing within the bytes // that are copied to the preamble stub, it will crash in an undefined // way. // // If you get any other error than the above, you're either pointing the // patcher at an invalid instruction (e.g. into the middle of a multi- // byte instruction, or not at memory containing executable instructions) // or, there may be a bug in the disassembler we use to find // instruction boundaries. // // NOTE: In optimized builds, when you have very trivial functions that // the compiler can reason do not have side effects, the compiler may // reuse the result of calling the function with a given parameter, which // may mean if you patch the function in between your patch will never get // invoked. See preamble_patcher_test.cc for an example. class PreamblePatcher { public: // This is a typesafe version of RawPatch(), identical in all other // ways than it takes a template parameter indicating the type of the // function being patched. // // @param T The type of the function you are patching. Usually // you will establish this type using a typedef, as in the following // example: // @code // typedef BOOL (WINAPI *MessageBoxPtr)(HWND, LPCTSTR, LPCTSTR, UINT); // MessageBoxPtr original = NULL; // PreamblePatcher::Patch(MessageBox, Hook_MessageBox, &original); // @endcode template static SideStepError Patch(T target_function, T replacement_function, T* original_function_stub) { // NOTE: casting from a function to a pointer is contra the C++ // spec. It's not safe on IA64, but is on i386. We use // a C-style cast here to emphasize this is not legal C++. return RawPatch((void*)(target_function), (void*)(replacement_function), (void**)(original_function_stub)); } // Patches a named function imported from the named module using // preamble patching. Uses RawPatch() to do the actual patching // work. // // @param T The type of the function you are patching. Must // exactly match the function you specify using module_name and // function_name. // // @param module_name The name of the module from which the function // is being imported. Note that the patch will fail if this module // has not already been loaded into the current process. // // @param function_name The name of the function you wish to patch. // // @param replacement_function Your replacement function which // will be called whenever code tries to call the original function. // // @param original_function_stub Pointer to memory that should receive a // pointer that can be used (e.g. in the replacement function) to call the // original function, or NULL to indicate failure. // // @return One of the EnSideStepError error codes; only SIDESTEP_SUCCESS // indicates success. template static SideStepError Patch(LPCTSTR module_name, LPCSTR function_name, T replacement_function, T* original_function_stub) { SIDESTEP_ASSERT(module_name && function_name); if (!module_name || !function_name) { SIDESTEP_ASSERT(false && "You must specify a module name and function name."); return SIDESTEP_INVALID_PARAMETER; } HMODULE module = ::GetModuleHandle(module_name); SIDESTEP_ASSERT(module != NULL); if (!module) { SIDESTEP_ASSERT(false && "Invalid module name."); return SIDESTEP_NO_SUCH_MODULE; } FARPROC existing_function = ::GetProcAddress(module, function_name); if (!existing_function) { SIDESTEP_ASSERT( false && "Did not find any function with that name in the module."); return SIDESTEP_NO_SUCH_FUNCTION; } // NOTE: casting from a function to a pointer is contra the C++ // spec. It's not safe on IA64, but is on i386. We use // a C-style cast here to emphasize this is not legal C++. return RawPatch((void*)existing_function, (void*)replacement_function, (void**)(original_function_stub)); } // Patches a function by overwriting its first few bytes with // a jump to a different function. This is the "worker" function // for each of the typesafe Patch() functions. In most cases, // it is preferable to use the Patch() functions rather than // this one as they do more checking at compile time. // // @param target_function A pointer to the function that should be // patched. // // @param replacement_function A pointer to the function that should // replace the target function. The replacement function must have // exactly the same calling convention and parameters as the original // function. // // @param original_function_stub Pointer to memory that should receive a // pointer that can be used (e.g. in the replacement function) to call the // original function, or NULL to indicate failure. // // @param original_function_stub Pointer to memory that should receive a // pointer that can be used (e.g. in the replacement function) to call the // original function, or NULL to indicate failure. // // @return One of the EnSideStepError error codes; only SIDESTEP_SUCCESS // indicates success. // // @note The preamble-stub (the memory pointed to by // *original_function_stub) is allocated on the heap, and (in // production binaries) never destroyed, resulting in a memory leak. This // will be the case until we implement safe unpatching of a method. // However, it is quite difficult to unpatch a method (because other // threads in the process may be using it) so we are leaving it for now. // See however UnsafeUnpatch, which can be used for binaries where you // know only one thread is running, e.g. unit tests. static SideStepError RawPatch(void* target_function, void* replacement_function, void** original_function_stub); // Unpatches target_function and deletes the stub that previously could be // used to call the original version of the function. // // DELETES the stub that is passed to the function. // // @param target_function Pointer to the target function which was // previously patched, i.e. a pointer which value should match the value // of the symbol prior to patching it. // // @param replacement_function Pointer to the function target_function // was patched to. // // @param original_function_stub Pointer to the stub returned when // patching, that could be used to call the original version of the // patched function. This function will also delete the stub, which after // unpatching is useless. // // If your original call was // Patch(VirtualAlloc, MyVirtualAlloc, &origptr) // then to undo it you would call // Unpatch(VirtualAlloc, MyVirtualAlloc, origptr); // // @return One of the EnSideStepError error codes; only SIDESTEP_SUCCESS // indicates success. static SideStepError Unpatch(void* target_function, void* replacement_function, void* original_function_stub); // A helper routine when patching, which follows jmp instructions at // function addresses, to get to the "actual" function contents. // This allows us to identify two functions that are at different // addresses but actually resolve to the same code. // // @param target_function Pointer to a function. // // @return Either target_function (the input parameter), or if // target_function's body consists entirely of a JMP instruction, // the address it JMPs to (or more precisely, the address at the end // of a chain of JMPs). template static T ResolveTarget(T target_function) { return (T)ResolveTargetImpl((unsigned char*)target_function, NULL); } private: // Patches a function by overwriting its first few bytes with // a jump to a different function. This is similar to the RawPatch // function except that it uses the stub allocated by the caller // instead of allocating it. // // We call VirtualProtect to make the // target function writable at least for the duration of the call. // // @param target_function A pointer to the function that should be // patched. // // @param replacement_function A pointer to the function that should // replace the target function. The replacement function must have // exactly the same calling convention and parameters as the original // function. // // @param preamble_stub A pointer to a buffer where the preamble stub // should be copied. The size of the buffer should be sufficient to // hold the preamble bytes. // // @param stub_size Size in bytes of the buffer allocated for the // preamble_stub // // @param bytes_needed Pointer to a variable that receives the minimum // number of bytes required for the stub. Can be set to NULL if you're // not interested. // // @return An error code indicating the result of patching. static SideStepError RawPatchWithStubAndProtections( void* target_function, void *replacement_function, unsigned char* preamble_stub, unsigned long stub_size, unsigned long* bytes_needed); // A helper function used by RawPatchWithStubAndProtections -- it // does everything but the VirtualProtect work. Defined in // preamble_patcher_with_stub.cc. // // @param target_function A pointer to the function that should be // patched. // // @param replacement_function A pointer to the function that should // replace the target function. The replacement function must have // exactly the same calling convention and parameters as the original // function. // // @param preamble_stub A pointer to a buffer where the preamble stub // should be copied. The size of the buffer should be sufficient to // hold the preamble bytes. // // @param stub_size Size in bytes of the buffer allocated for the // preamble_stub // // @param bytes_needed Pointer to a variable that receives the minimum // number of bytes required for the stub. Can be set to NULL if you're // not interested. // // @return An error code indicating the result of patching. static SideStepError RawPatchWithStub(void* target_function, void *replacement_function, unsigned char* preamble_stub, unsigned long stub_size, unsigned long* bytes_needed); // A helper routine when patching, which follows jmp instructions at // function addresses, to get to the "actual" function contents. // This allows us to identify two functions that are at different // addresses but actually resolve to the same code. // // @param target_function Pointer to a function. // // @param stop_before If, when following JMP instructions from // target_function, we get to the address stop, we return // immediately, the address that jumps to stop_before. // // @return Either target_function (the input parameter), or if // target_function's body consists entirely of a JMP instruction, // the address it JMPs to (or more precisely, the address at the end // of a chain of JMPs). static void* ResolveTargetImpl(unsigned char* target_function, unsigned char* stop_before); }; }; // namespace sidestep #endif // GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_ ================================================ FILE: distro/google-perftools-1.7/src/windows/preamble_patcher_with_stub.cc ================================================ /* Copyright (c) 2007, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Joi Sigurdsson * * Implementation of PreamblePatcher */ #include "preamble_patcher.h" #include "mini_disassembler.h" // Definitions of assembly statements we need #define ASM_JMP32REL 0xE9 #define ASM_INT3 0xCC namespace sidestep { SideStepError PreamblePatcher::RawPatchWithStub( void* target_function, void *replacement_function, unsigned char* preamble_stub, unsigned long stub_size, unsigned long* bytes_needed) { if ((NULL == target_function) || (NULL == replacement_function) || (NULL == preamble_stub)) { SIDESTEP_ASSERT(false && "Invalid parameters - either pTargetFunction or " "pReplacementFunction or pPreambleStub were NULL."); return SIDESTEP_INVALID_PARAMETER; } // TODO(V7:joi) Siggi and I just had a discussion and decided that both // patching and unpatching are actually unsafe. We also discussed a // method of making it safe, which is to freeze all other threads in the // process, check their thread context to see if their eip is currently // inside the block of instructions we need to copy to the stub, and if so // wait a bit and try again, then unfreeze all threads once we've patched. // Not implementing this for now since we're only using SideStep for unit // testing, but if we ever use it for production code this is what we // should do. // // NOTE: Stoyan suggests we can write 8 or even 10 bytes atomically using // FPU instructions, and on newer processors we could use cmpxchg8b or // cmpxchg16b. So it might be possible to do the patching/unpatching // atomically and avoid having to freeze other threads. Note though, that // doing it atomically does not help if one of the other threads happens // to have its eip in the middle of the bytes you change while you change // them. // First, deal with a special case that we see with functions that // point into an IAT table (including functions linked statically // into the application): these function already starts with // ASM_JMP32REL. For instance, malloc() might be implemented as a // JMP to __malloc(). In that case, we replace the destination of // the JMP (__malloc), rather than the JMP itself (malloc). This // way we get the correct behavior no matter how malloc gets called. void *new_target = ResolveTarget(target_function); if (new_target != target_function) { // we're in the IAT case // I'd like to just say "target = new_target", but I can't, // because the new target will need to have its protections set. return RawPatchWithStubAndProtections(new_target, replacement_function, preamble_stub, stub_size, bytes_needed); } unsigned char* target = reinterpret_cast(new_target); // Let's disassemble the preamble of the target function to see if we can // patch, and to see how much of the preamble we need to take. We need 5 // bytes for our jmp instruction, so let's find the minimum number of // instructions to get 5 bytes. MiniDisassembler disassembler; unsigned int preamble_bytes = 0; while (preamble_bytes < 5) { InstructionType instruction_type = disassembler.Disassemble(target + preamble_bytes, preamble_bytes); if (IT_JUMP == instruction_type) { SIDESTEP_ASSERT(false && "Unable to patch because there is a jump instruction " "in the first 5 bytes."); return SIDESTEP_JUMP_INSTRUCTION; } else if (IT_RETURN == instruction_type) { SIDESTEP_ASSERT(false && "Unable to patch because function is too short"); return SIDESTEP_FUNCTION_TOO_SMALL; } else if (IT_GENERIC != instruction_type) { SIDESTEP_ASSERT(false && "Disassembler encountered unsupported instruction " "(either unused or unknown"); return SIDESTEP_UNSUPPORTED_INSTRUCTION; } } if (NULL != bytes_needed) *bytes_needed = preamble_bytes + 5; // Inv: cbPreamble is the number of bytes (at least 5) that we need to take // from the preamble to have whole instructions that are 5 bytes or more // in size total. The size of the stub required is cbPreamble + size of // jmp (5) if (preamble_bytes + 5 > stub_size) { SIDESTEP_ASSERT(false); return SIDESTEP_INSUFFICIENT_BUFFER; } // First, copy the preamble that we will overwrite. memcpy(reinterpret_cast(preamble_stub), reinterpret_cast(target), preamble_bytes); // Now, make a jmp instruction to the rest of the target function (minus the // preamble bytes we moved into the stub) and copy it into our preamble-stub. // find address to jump to, relative to next address after jmp instruction #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4244) #endif int relative_offset_to_target_rest = ((reinterpret_cast(target) + preamble_bytes) - (preamble_stub + preamble_bytes + 5)); #ifdef _MSC_VER #pragma warning(pop) #endif // jmp (Jump near, relative, displacement relative to next instruction) preamble_stub[preamble_bytes] = ASM_JMP32REL; // copy the address memcpy(reinterpret_cast(preamble_stub + preamble_bytes + 1), reinterpret_cast(&relative_offset_to_target_rest), 4); // Inv: preamble_stub points to assembly code that will execute the // original function by first executing the first cbPreamble bytes of the // preamble, then jumping to the rest of the function. // Overwrite the first 5 bytes of the target function with a jump to our // replacement function. // (Jump near, relative, displacement relative to next instruction) target[0] = ASM_JMP32REL; // Find offset from instruction after jmp, to the replacement function. #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4244) #endif int offset_to_replacement_function = reinterpret_cast(replacement_function) - reinterpret_cast(target) - 5; #ifdef _MSC_VER #pragma warning(pop) #endif // complete the jmp instruction memcpy(reinterpret_cast(target + 1), reinterpret_cast(&offset_to_replacement_function), 4); // Set any remaining bytes that were moved to the preamble-stub to INT3 so // as not to cause confusion (otherwise you might see some strange // instructions if you look at the disassembly, or even invalid // instructions). Also, by doing this, we will break into the debugger if // some code calls into this portion of the code. If this happens, it // means that this function cannot be patched using this patcher without // further thought. if (preamble_bytes > 5) { memset(reinterpret_cast(target + 5), ASM_INT3, preamble_bytes - 5); } // Inv: The memory pointed to by target_function now points to a relative // jump instruction that jumps over to the preamble_stub. The preamble // stub contains the first stub_size bytes of the original target // function's preamble code, followed by a relative jump back to the next // instruction after the first cbPreamble bytes. return SIDESTEP_SUCCESS; } }; // namespace sidestep ================================================ FILE: distro/google-perftools-1.7/vsprojects/addr2line-pdb/addr2line-pdb.vcproj ================================================ ================================================ FILE: distro/google-perftools-1.7/vsprojects/addressmap_unittest/addressmap_unittest.vcproj ================================================ ================================================ FILE: distro/google-perftools-1.7/vsprojects/frag_unittest/frag_unittest.vcproj ================================================ ================================================ FILE: distro/google-perftools-1.7/vsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcproj ================================================ ================================================ FILE: distro/google-perftools-1.7/vsprojects/low_level_alloc_unittest/low_level_alloc_unittest.vcproj ================================================ ================================================ FILE: distro/google-perftools-1.7/vsprojects/malloc_extension_test/malloc_extension_test.vcproj ================================================ ================================================ FILE: distro/google-perftools-1.7/vsprojects/markidle_unittest/markidle_unittest.vcproj ================================================ ================================================ FILE: distro/google-perftools-1.7/vsprojects/nm-pdb/nm-pdb.vcproj ================================================ ================================================ FILE: distro/google-perftools-1.7/vsprojects/packed-cache_test/packed-cache_test.vcproj ================================================ ================================================ FILE: distro/google-perftools-1.7/vsprojects/page_heap_test/page_heap_test.vcproj ================================================ ================================================ FILE: distro/google-perftools-1.7/vsprojects/pagemap_unittest/pagemap_unittest.vcproj ================================================ ================================================ FILE: distro/google-perftools-1.7/vsprojects/realloc_unittest/realloc_unittest.vcproj ================================================ ================================================ FILE: distro/google-perftools-1.7/vsprojects/sampler_test/sampler_test.vcproj ================================================ ================================================ FILE: distro/google-perftools-1.7/vsprojects/stack_trace_table_test/stack_trace_table_test.vcproj ================================================ ================================================ FILE: distro/google-perftools-1.7/vsprojects/tcmalloc_minimal_large/tcmalloc_minimal_large_unittest.vcproj ================================================ ================================================ FILE: distro/google-perftools-1.7/vsprojects/tcmalloc_minimal_unittest/tcmalloc_minimal_unittest.vcproj ================================================ ================================================ FILE: distro/google-perftools-1.7/vsprojects/thread_dealloc_unittest/thread_dealloc_unittest.vcproj ================================================ ================================================ FILE: distro/google-perftools-1.7/vsprojects/tmu-static/tmu-static.vcproj ================================================ ================================================ FILE: distro/installer ================================================ #!/bin/sh # Simple bootstrap script for the installer. This script uses the bundled # Ruby interpreter binary whenever possible, and falls back to the system's # Ruby interpreter if no suitable bundled Ruby interpreter exists. dir=`dirname "$0"` cd "$dir" unset GEM_HOME unset GEM_PATH unset RUBYOPT platform="`uname`-`uname -m`" if (ruby -e '') 2>/dev/null; then exec ruby installer.rb "$@" else #echo "Using 'runtime/$platform/ruby'" if ("runtime/$platform/ruby" -e '') 2>/dev/null; then exec "runtime/$platform/ruby" installer.rb "$@" else echo "*** ERROR: Ruby is not installed ***" >&2 echo "The Ruby Enterprise Edition installer is written in Ruby. This source tarball bundles precompiled versions of Ruby for many platforms for the purpose of running this installer, but unfortunately we did not include a precompiled Ruby binary for the current platform. So please install Ruby manually, then run this installer again." >&2 exit 10 fi fi ================================================ FILE: distro/installer.rb ================================================ #!/usr/bin/env ruby require "#{File.dirname(__FILE__)}/optparse" require "#{File.dirname(__FILE__)}/dependencies" class Installer include RubyEnterpriseEdition ROOT = File.expand_path(File.dirname(__FILE__)) PASSENGER_WEBSITE = "http://www.modrails.com" EMM_RUBY_WEBSITE = "http://www.rubyenterpriseedition.com" REQUIRED_DEPENDENCIES = [ # Don't forget to update the dependency list in the manual too. Dependencies::CC, Dependencies::CXX, Dependencies::Make, Dependencies::Patch, Dependencies::Zlib_Dev, Dependencies::OpenSSL_Dev, Dependencies::Readline_Dev ] def start(options = {}) Dir.chdir(ROOT) @version = File.read("version.txt") @auto_install_prefix = options[:prefix] @destdir = strip_trailing_slashes(options[:destdir]) @install_useful_gems = options[:install_useful_gems] @use_tcmalloc = options[:tcmalloc] @fast_threading = options[:fast_threading] if !options[:extra_configure_args].empty? @extra_configure_args = options[:extra_configure_args].join(" ") end if RUBY_PLATFORM =~ /darwin/ ENV['PATH'] = "#{ENV['PATH']}:/usr/local/mysql/bin" end show_welcome_screen check_dependencies || exit(1) ask_installation_prefix steps = [] if tcmalloc_supported? steps += [ :configure_tcmalloc, :compile_tcmalloc, :install_tcmalloc ] end steps += [ :configure_ruby, :compile_system_allocator, :compile_ruby, :install_ruby] steps += [:install_dev_docs] if options[:install_dev_docs] steps += [ :install_ree_specific_binaries, :install_rubygems, :install_iconv ] steps.each do |step| if !self.send(step) exit 1 end end install_useful_libraries show_finalization_screen ensure reset_terminal_colors end private def show_welcome_screen color_puts "Welcome to the Ruby Enterprise Edition installer" color_puts "This installer will help you install Ruby Enterprise Edition #{@version}." color_puts "Don't worry, none of your system files will be touched if you don't want them" color_puts "to, so there is no risk that things will screw up." puts color_puts "You can expect this from the installation process:" puts color_puts " 1. Ruby Enterprise Edition will be compiled and optimized for speed for this" color_puts " system." color_puts " 2. Ruby on Rails will be installed for Ruby Enterprise Edition." color_puts " 3. You will learn how to tell Phusion Passenger to use Ruby Enterprise" color_puts " Edition instead of regular Ruby." puts color_puts "Press Enter to continue, or Ctrl-C to abort." wait end def check_dependencies missing_dependencies = [] color_puts "Checking for required software..." puts REQUIRED_DEPENDENCIES.each do |dep| color_print " * #{dep.name}... " result = dep.check if result.found? if result.found_at color_puts "found at #{result.found_at}" else color_puts "found" end else color_puts "not found" missing_dependencies << dep end end if missing_dependencies.empty? return true else puts color_puts "Some required software is not installed." color_puts "But don't worry, this installer will tell you how to install them.\n" color_puts "Press Enter to continue, or Ctrl-C to abort." wait line color_puts "Installation instructions for required software" puts missing_dependencies.each do |dep| print_dependency_installation_instructions(dep) puts end return false end end def print_dependency_installation_instructions(dep) color_puts " * To install #{dep.name}:" if !dep.install_command.nil? color_puts " Please run #{dep.install_command} as root." elsif !dep.install_instructions.nil? color_puts " " << dep.install_instructions elsif !dep.website.nil? color_puts " Please download it from #{dep.website}" if !dep.website_comments.nil? color_puts " (#{dep.website_comments})" end else color_puts " Search Google." end end def strip_trailing_slashes(data) if data.nil? return nil else result = data.sub(/\/+$/, '') if result.empty? && !data.empty? return '/' else return result end end end def ask_installation_prefix line color_puts "Target directory" puts @old_prefix = File.read("source/.prefix.txt") rescue nil if @auto_install_prefix @prefix = @auto_install_prefix puts "Auto-installing to: #{@prefix}" else puts "Where would you like to install Ruby Enterprise Edition to?" puts "(All Ruby Enterprise Edition files will be put inside that directory.)" puts @prefix = query_directory(@old_prefix || "/opt/ruby-enterprise-#{@version}") end @prefix = strip_trailing_slashes(@prefix) @prefix_changed = @prefix != @old_prefix File.open("source/.prefix.txt", "w") do |f| f.write(@prefix) end if @destdir && !@destdir =~ /\/$/ @destdir += "/" end ENV['CPATH'] = "#{@destdir}#{@prefix}/include:/usr/include:/usr/local/include:#{ENV['CPATH']}" ENV['LD_LIBRARY_PATH'] = "#{@destdir}#{@prefix}/lib:#{ENV['LD_LIBRARY_PATH']}" ENV['DYLD_LIBRARY_PATH'] = "#{@destdir}#{@prefix}/lib:#{ENV['DYLD_LIBRARY_PATH']}" end def configure_tcmalloc return configure_autoconf_package('source/distro/google-perftools-1.7', 'the memory allocator for Ruby Enterprise Edition', '--disable-dependency-tracking') end def compile_tcmalloc Dir.chdir('source/distro/google-perftools-1.7') do return sh("make libtcmalloc_minimal.la") end end def install_tcmalloc return install_autoconf_package('source/distro/google-perftools-1.7', 'the memory allocator for Ruby Enterprise Edition') do sh("mkdir", "-p", "#{@destdir}#{@prefix}/lib") && # Remove existing .so files so that the copy operation doesn't # overwrite the existing files in-place. Overwriting shared # libraries in-place can cause existing processes that use # those libraries to crash. sh("rm -rf '#{@destdir}#{@prefix}/lib'/libtcmalloc_minimal*.#{PlatformInfo::LIBEXT}*") && sh("cp -Rpf .libs/libtcmalloc_minimal*.#{PlatformInfo::LIBEXT}* '#{@destdir}#{@prefix}/lib/'") end end def configure_ruby return configure_autoconf_package('source', 'Ruby Enterprise Edition', "#{@extra_configure_args} " << "CFLAGS='-g -O2 #{ENV['CFLAGS']}'") end def compile_system_allocator if platform_uses_two_level_namespace_for_dynamic_libraries? Dir.chdir("source") do @using_system_allocator_library = true # On platforms that use a two-level symbol namespace for # dynamic libraries (most notably MacOS X), integrating # tcmalloc requires a special library. See system_allocator.c # for more information. ENV['DYLD_LIBRARY_PATH'] = "#{ROOT}/source:#{ENV['DYLD_LIBRARY_PATH']}" return sh("#{PlatformInfo::CC} #{ENV['CFLAGS']} #{ENV['LDFLAGS']} -dynamiclib system_allocator.c -install_name @rpath/libsystem_allocator.dylib -o libsystem_allocator.dylib") end else return true end end def compile_ruby Dir.chdir("source") do if fast_threading_patch_applied? if !@fast_threading sh "patch -p1 -R < ../fast-threading.patch" end else if @fast_threading sh "patch -p1 < ../fast-threading.patch" end end # No idea why, but sometimes 'make' fails unless we do this. sh("mkdir -p .ext/common") makefile = File.read('Makefile') if makefile !~ /\$\(PRELIBS\)/ makefile.sub!(/^LIBS = (.*)$/, 'LIBS = $(PRELIBS) \1') File.open('Makefile', 'w') do |f| f.write(makefile) end end prelibs = "-Wl," if PlatformInfo.solaris_ld? prelibs << "-R#{@prefix}/lib" else prelibs << "-rpath,#{@prefix}/lib" end prelibs << " -L#{@destdir}#{@prefix}/lib" if tcmalloc_supported? prelibs << " -ltcmalloc_minimal " end if platform_uses_two_level_namespace_for_dynamic_libraries? prelibs << " -lsystem_allocator" end if RUBY_PLATFORM =~ /freebsd/ # On FreeBSD the Ruby interpreter must be linked to # pthread, otherwise native extensions that are linked # to pthread won't load properly. prelibs << " -lpthread" end File.open("make.sh", "w") do |f| f.write("#!/bin/bash\n") f.write("exec make PRELIBS='#{prelibs}' \"$@\"") f.chmod(0755) end return sh("make PRELIBS='#{prelibs}'") end end def install_ruby if install_autoconf_package('source', 'Ruby Enterprise Edition') # Some installed files may have wrong permissions # (not world-readable). So we fix this. if sh("chmod -R g+r,o+r,o-w #{@destdir}#{@prefix}/lib/ruby") if @using_system_allocator_library && !sh("install source/libsystem_allocator.dylib #{@destdir}#{@prefix}/lib/") return false else return true end else return false end else return false end end def install_ree_specific_binaries File.open("#{@destdir}#{@prefix}/bin/ree-version", 'w') do |f| f.puts("#!/bin/sh") f.puts("echo 'Ruby Enterprise Edition version #{@version}'") end system("chmod +x '#{@destdir}#{@prefix}/bin/ree-version'") end def install_rubygems # We might be installing into a fakeroot, so add the fakeroot's library # search paths to RUBYLIB so that gem installation will work. basedir = "#{@destdir}#{@prefix}/lib/ruby" libdir = "#{basedir}/1.8" archname = File.basename(File.dirname(Dir["#{libdir}/*/thread.#{PlatformInfo::RUBYLIBEXT}"].first)) extlibdir = "#{libdir}/#{archname}" site_libdir = "#{basedir}/site_ruby/1.8" site_extlibdir = "#{site_libdir}/#{archname}" ENV['RUBYLIB'] = "#{libdir}:#{extlibdir}:#{site_libdir}:#{site_extlibdir}" Dir.chdir("rubygems") do line color_puts "Installing RubyGems..." if !sh("#{@destdir}#{@prefix}/bin/ruby", "setup.rb", "--no-ri", "--no-rdoc") puts "*** Cannot install RubyGems" return false end end return true end def install_iconv # On some systems, most notably FreeBSD, the iconv extension isn't # correctly installed. So here we do it manually. Dir.chdir('source/ext/iconv') do # On FreeBSD, iconv.h is in /usr/local/include when installed # via ports. For some reason they thought it's a good idea # to not have GCC look in /usr/local/include by default. # *Sigh*, let's fix this. if !File.exist?("/usr/include/iconv.h") && File.exist?("/usr/local/include/iconv.h") args = ["--with-iconv-dir=/usr/local"] else args = [] end if !sh("#{@destdir}#{@prefix}/bin/ruby", "extconf.rb", *args) || # 'make clean' must be run, because sometimes 'make' # thinks iconv.so is already compiled even though it # isn't. !sh("make clean") || !sh("make") || # For some reason DESTDIR is not necessary here; # not sure why. !sh("make install") puts "*** Cannot install the iconv extension" return false end end return true end def install_dev_docs Dir.chdir("source") do color_puts "Installing developer documentation..." if !system("make install-doc DESTDIR='#{@destdir}'") return false end end return true end def install_useful_libraries line color_puts "Installing useful libraries..." gem = "#{@destdir}#{@prefix}/bin/ruby #{@destdir}#{@prefix}/bin/gem" mysql_config = PlatformInfo.find_command('mysql_config') if mysql_config mysql_gem = "mysql -- --with-mysql-config='#{mysql_config}'" else mysql_gem = "mysql" end gem_names = [] if @install_useful_gems gem_names += ["passenger", "rake", "rails", "fastthread", "rack", mysql_gem, "sqlite3-ruby", "pg"] end failed_gems = [] if sh("#{gem} sources --update") gem_names.each do |gem_name| color_puts "\nInstalling #{gem_name}..." if !sh("#{gem} install -r --no-rdoc --no-ri --no-update-sources --backtrace #{gem_name}") failed_gems << gem_name end end else failed_gems = gem_names end if !failed_gems.empty? line color_puts "Warning: some libraries could not be installed" color_puts "The following gems could not be installed, probably because of an Internet" color_puts "connection error:" puts failed_gems.each do |gem_name| color_puts " * #{gem_name}" end puts color_puts "These gems are not required, i.e. Ruby Enterprise Edition will work fine without them. But most people use Ruby Enterprise Edition in combination with Phusion Passenger and Ruby on Rails, which do require one or more of the aforementioned gems, so you may want to install them later." puts color_puts "To install the aforementioned gems, please use the following commands:" failed_gems.each do |gem_name| color_puts " * #{gem} install #{gem_name}" end puts color_puts "Press ENTER to show the next screen." wait end # Fix the shebang lines of scripts in 'bin' folder. fix_shebang_lines("#{@destdir}#{@prefix}/bin", "#{@prefix}/bin/ruby") Dir.chdir("#{@destdir}#{@prefix}/lib/ruby/gems/1.8/gems") do if !Dir["sqlite3-ruby*"].empty? # The sqlite3-ruby gem installs files with wrong # permissions. We fix this. sh "chmod -R g+r,o+r,o-w sqlite3-ruby*" end end end def show_finalization_screen line color_puts "Ruby Enterprise Edition is successfully installed!" color_puts "If want to use Phusion Passenger (#{PASSENGER_WEBSITE}) in combination" color_puts "with Ruby Enterprise Edition, then you must reinstall Phusion Passenger against" color_puts "Ruby Enterprise Edition, as follows:" puts color_puts " #{@prefix}/bin/passenger-install-apache2-module" puts color_puts "Make sure you don't forget to paste the Apache configuration directives that" color_puts "the installer gives you." puts puts color_puts "If you ever want to uninstall Ruby Enterprise Edition, simply remove this" color_puts "directory:" puts color_puts " #{@prefix}" puts color_puts "If you have any questions, feel free to visit our website:" puts color_puts " #{EMM_RUBY_WEBSITE}" puts color_puts "Enjoy Ruby Enterprise Edition, a product of Phusion (www.phusion.nl) :-)" end private DEFAULT_TERMINAL_COLORS = "\e[0m\e[37m\e[40m" def color_puts(message) puts substitute_color_tags(message) end def color_print(message) print substitute_color_tags(message) end def substitute_color_tags(data) data = data.gsub(%r{(.*?)}m, "\e[1m\\1#{DEFAULT_TERMINAL_COLORS}") data.gsub!(%r{(.*?)}m, "\e[1m\e[31m\\1#{DEFAULT_TERMINAL_COLORS}") data.gsub!(%r{(.*?)}m, "\e[1m\e[32m\\1#{DEFAULT_TERMINAL_COLORS}") data.gsub!(%r{(.*?)}m, "\e[1m\e[33m\\1#{DEFAULT_TERMINAL_COLORS}") data.gsub!(%r{(.*?)}m, "\e[33m\e[44m\e[1m\\1#{DEFAULT_TERMINAL_COLORS}") return data end def reset_terminal_colors STDOUT.write("\e[0m") STDOUT.flush end def line puts "--------------------------------------------" end def wait if !@auto_install_prefix STDIN.readline end rescue Interrupt exit 2 end def query_directory(default = "") while true STDOUT.write("[#{default}] : ") STDOUT.flush input = STDIN.readline.strip if input.empty? return default elsif input !~ /^\// color_puts "Please specify an absolute directory." elsif input =~ /\s/ color_puts "The directory name may not contain spaces." else return input end end rescue Interrupt, EOFError exit 2 end def tcmalloc_supported? return @use_tcmalloc && RUBY_PLATFORM !~ /solaris/ && RUBY_PLATFORM !~ /openbsd/ && RUBY_PLATFORM !~ /arm/ && # tcmalloc has issues on Snow Leopard, but works fine on Leopard. (RUBY_PLATFORM !~ /darwin/ || osx_kernel_major_release_version <= 9) end def osx_kernel_major_release_version release = `uname -r`.strip release.gsub!(/\..*/, '') return release.to_i end def platform_uses_two_level_namespace_for_dynamic_libraries? return RUBY_PLATFORM =~ /darwin/ end def sh(*command) puts command.join(' ') return system(*command) end def configure_autoconf_package(dir, name, configure_options = nil) line color_puts "Compiling and optimizing #{name}" color_puts "In the mean time, feel free to grab a cup of coffee.\n\n" Dir.chdir(dir) do # If nothing has been compiled yet, then set the timestamps of the files # to some time in the past. I think the "/" directory's timestamp is # guaranteed to be in the past. # This prevents 'configure' and 'make' from thinking that the 'configure' # script must be regenerated, for computers that have the clock wrongly # configured or computers that are in a different time zone than the # computer the REE tarball was created on. if Dir["*.o"].empty? system("touch -r / *") if File.directory?("m4") system("touch -r / m4/*") end end if @prefix_changed || !File.exist?("Makefile") if !sh("./configure --prefix=#{@prefix} #{configure_options}") return false end else color_puts "It looks like the source is already configured." color_puts "Skipping configure script..." end return true end end def install_autoconf_package(dir, name) Dir.chdir(dir) do if block_given? result = yield else result = sh("make install DESTDIR='#{@destdir}'") end if result return true else puts line color_puts "Cannot install #{name}" puts color_puts "This installer was able to compile #{name}, but could not " << "install the files to #{@destdir}#{@prefix}." puts if Process.uid == 0 color_puts "This installer probably doesn't have permission " << "to write to that folder, even though it's running as " << "root. Please fix the permissions, and re-run this installer." else color_puts "This installer probably doesn't have permission to " << "write to that folder, because it's running as " << "#{`whoami`.strip}. Please re-run this installer " << "as root." end return false end end end # Fix the shebang lines of Ruby scripts. def fix_shebang_lines(dir, new_shebang_line) Dir.foreach(dir) do |basename| next if basename =~ /^\./ filename = File.join(dir, basename) begin next if !File.executable?(filename) rest = nil File.open(filename, 'rb') do |f| shebang = f.readline if shebang =~ /ruby/ puts "Updating #{filename}..." rest = f.read end end if rest tempfile = "#{filename}.tmp.#{Process.pid}" File.open(tempfile, 'w') do |f| f.write("#!#{new_shebang_line}\n") f.write(rest) end File.chmod(File.stat(filename).mode, tempfile) File.rename(tempfile, filename) rest.replace("") end rescue SystemCallError, IOError => e STDERR.puts "*** ERROR: #{e}" end end end def fast_threading_patch_applied? File.read("eval.c") =~ /PROT_EMPTY/ end end options = { :tcmalloc => true, :install_dev_docs => true, :install_useful_gems => true, :extra_configure_args => [] } parser = OptionParser.new do |opts| newline = "\n#{' ' * 37}" opts.banner = "Usage: installer [options]" opts.separator("") opts.on("-a", "--auto PREFIX", String, "Configure Ruby with prefix PREFIX and#{newline}" << "install it without any user interaction.") do |dir| options[:prefix] = dir end opts.on("--destdir DIR", String, "Install everthing under the given#{newline}" << "destination directory. Used when building#{newline}" << "packages for Ruby Enterprise Edition.") do |dir| options[:destdir] = dir end opts.on("-c", "--configure-arg ARG", String, "Pass an extra argument to the Ruby#{newline}" << "configure script. You can specify this#{newline}" << "option multiple times to pass multiple#{newline}" << "arguments.") do |arg| options[:extra_configure_args] << arg end opts.on("--dont-install-useful-gems", "Do not install a few useful gems that are#{newline}" << "normally installed as well: passenger,#{newline}" << "rails, mysql, etc.") do options[:install_useful_gems] = false end opts.on("--no-tcmalloc", "Do not install tcmalloc support.") do options[:tcmalloc] = false end opts.on("--no-dev-docs", "Do not install Ruby developer#{newline}documentation.") do options[:install_dev_docs] = false end opts.on("--fast-threading", "Enable zero-copy context switching#{newline}" << "(experimental)") do options[:fast_threading] = true end opts.on("-h", "--help", "Show this message.") do puts opts exit end end begin parser.parse! rescue OptionParser::ParseError => e puts e puts puts "Please see '--help' for valid options." exit 1 end Installer.new.start(options) ================================================ FILE: distro/optparse.rb ================================================ # # optparse.rb - command-line option analysis with the OptionParser class. # # Author:: Nobu Nakada # Documentation:: Nobu Nakada and Gavin Sinclair. # # See OptionParser for documentation. # # == Developer Documentation (not for RDoc output) # # === Class tree # # - OptionParser:: front end # - OptionParser::Switch:: each switches # - OptionParser::List:: options list # - OptionParser::ParseError:: errors on parsing # - OptionParser::AmbiguousOption # - OptionParser::NeedlessArgument # - OptionParser::MissingArgument # - OptionParser::InvalidOption # - OptionParser::InvalidArgument # - OptionParser::AmbiguousArgument # # === Object relationship diagram # # +--------------+ # | OptionParser |<>-----+ # +--------------+ | +--------+ # | ,-| Switch | # on_head -------->+---------------+ / +--------+ # accept/reject -->| List |<|>- # | |<|>- +----------+ # on ------------->+---------------+ `-| argument | # : : | class | # +---------------+ |==========| # on_tail -------->| | |pattern | # +---------------+ |----------| # OptionParser.accept ->| DefaultList | |converter | # reject |(shared between| +----------+ # | all instances)| # +---------------+ # # == OptionParser # # === Introduction # # OptionParser is a class for command-line option analysis. It is much more # advanced, yet also easier to use, than GetoptLong, and is a more Ruby-oriented # solution. # # === Features # # 1. The argument specification and the code to handle it are written in the # same place. # 2. It can output an option summary; you don't need to maintain this string # separately. # 3. Optional and mandatory arguments are specified very gracefully. # 4. Arguments can be automatically converted to a specified class. # 5. Arguments can be restricted to a certain set. # # All of these features are demonstrated in the examples below. # # === Minimal example # # require 'optparse' # # options = {} # OptionParser.new do |opts| # opts.banner = "Usage: example.rb [options]" # # opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| # options[:verbose] = v # end # end.parse! # # p options # p ARGV # # === Complete example # # The following example is a complete Ruby program. You can run it and see the # effect of specifying various options. This is probably the best way to learn # the features of +optparse+. # # require 'optparse' # require 'optparse/time' # require 'ostruct' # require 'pp' # # class OptparseExample # # CODES = %w[iso-2022-jp shift_jis euc-jp utf8 binary] # CODE_ALIASES = { "jis" => "iso-2022-jp", "sjis" => "shift_jis" } # # # # # Return a structure describing the options. # # # def self.parse(args) # # The options specified on the command line will be collected in *options*. # # We set default values here. # options = OpenStruct.new # options.library = [] # options.inplace = false # options.encoding = "utf8" # options.transfer_type = :auto # options.verbose = false # # opts = OptionParser.new do |opts| # opts.banner = "Usage: example.rb [options]" # # opts.separator "" # opts.separator "Specific options:" # # # Mandatory argument. # opts.on("-r", "--require LIBRARY", # "Require the LIBRARY before executing your script") do |lib| # options.library << lib # end # # # Optional argument; multi-line description. # opts.on("-i", "--inplace [EXTENSION]", # "Edit ARGV files in place", # " (make backup if EXTENSION supplied)") do |ext| # options.inplace = true # options.extension = ext || '' # options.extension.sub!(/\A\.?(?=.)/, ".") # Ensure extension begins with dot. # end # # # Cast 'delay' argument to a Float. # opts.on("--delay N", Float, "Delay N seconds before executing") do |n| # options.delay = n # end # # # Cast 'time' argument to a Time object. # opts.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time| # options.time = time # end # # # Cast to octal integer. # opts.on("-F", "--irs [OCTAL]", OptionParser::OctalInteger, # "Specify record separator (default \\0)") do |rs| # options.record_separator = rs # end # # # List of arguments. # opts.on("--list x,y,z", Array, "Example 'list' of arguments") do |list| # options.list = list # end # # # Keyword completion. We are specifying a specific set of arguments (CODES # # and CODE_ALIASES - notice the latter is a Hash), and the user may provide # # the shortest unambiguous text. # code_list = (CODE_ALIASES.keys + CODES).join(',') # opts.on("--code CODE", CODES, CODE_ALIASES, "Select encoding", # " (#{code_list})") do |encoding| # options.encoding = encoding # end # # # Optional argument with keyword completion. # opts.on("--type [TYPE]", [:text, :binary, :auto], # "Select transfer type (text, binary, auto)") do |t| # options.transfer_type = t # end # # # Boolean switch. # opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| # options.verbose = v # end # # opts.separator "" # opts.separator "Common options:" # # # No argument, shows at tail. This will print an options summary. # # Try it and see! # opts.on_tail("-h", "--help", "Show this message") do # puts opts # exit # end # # # Another typical switch to print the version. # opts.on_tail("--version", "Show version") do # puts OptionParser::Version.join('.') # exit # end # end # # opts.parse!(args) # options # end # parse() # # end # class OptparseExample # # options = OptparseExample.parse(ARGV) # pp options # # === Further documentation # # The above examples should be enough to learn how to use this class. If you # have any questions, email me (gsinclair@soyabean.com.au) and I will update # this document. # class OptionParser # :stopdoc: RCSID = %w$Id: optparse.rb 11798 2007-02-20 06:53:16Z knu $[1..-1].each {|s| s.freeze}.freeze Version = (RCSID[1].split('.').collect {|s| s.to_i}.extend(Comparable).freeze if RCSID[1]) LastModified = (Time.gm(*RCSID[2, 2].join('-').scan(/\d+/).collect {|s| s.to_i}) if RCSID[2]) Release = RCSID[2] NoArgument = [NO_ARGUMENT = :NONE, nil].freeze RequiredArgument = [REQUIRED_ARGUMENT = :REQUIRED, true].freeze OptionalArgument = [OPTIONAL_ARGUMENT = :OPTIONAL, false].freeze # :startdoc: # # Keyword completion module. This allows partial arguments to be specified # and resolved against a list of acceptable values. # module Completion def complete(key, icase = false, pat = nil) pat ||= Regexp.new('\A' + Regexp.quote(key).gsub(/\w+\b/, '\&\w*'), icase) canon, sw, k, v, cn = nil candidates = [] each do |k, *v| (if Regexp === k kn = nil k === key else kn = defined?(k.id2name) ? k.id2name : k pat === kn end) or next v << k if v.empty? candidates << [k, v, kn] end candidates = candidates.sort_by {|k, v, kn| kn.size} if candidates.size == 1 canon, sw, * = candidates[0] elsif candidates.size > 1 canon, sw, cn = candidates.shift candidates.each do |k, v, kn| next if sw == v if String === cn and String === kn if cn.rindex(kn, 0) canon, sw, cn = k, v, kn next elsif kn.rindex(cn, 0) next end end throw :ambiguous, key end end if canon block_given? or return key, *sw yield(key, *sw) end end def convert(opt = nil, val = nil, *) val end end # # Map from option/keyword string to object with completion. # class OptionMap < Hash include Completion end # # Individual switch class. Not important to the user. # # Defined within Switch are several Switch-derived classes: NoArgument, # RequiredArgument, etc. # class Switch attr_reader :pattern, :conv, :short, :long, :arg, :desc, :block # # Guesses argument style from +arg+. Returns corresponding # OptionParser::Switch class (OptionalArgument, etc.). # def self.guess(arg) case arg when "" t = self when /\A=?\[/ t = Switch::OptionalArgument when /\A\s+\[/ t = Switch::PlacedArgument else t = Switch::RequiredArgument end self >= t or incompatible_argument_styles(arg, t) t end def self.incompatible_argument_styles(arg, t) raise ArgumentError, "#{arg}: incompatible argument styles\n #{self}, #{t}" end def self.pattern NilClass end def initialize(pattern = nil, conv = nil, short = nil, long = nil, arg = nil, desc = ([] if short or long), block = Proc.new) raise if Array === pattern @pattern, @conv, @short, @long, @arg, @desc, @block = pattern, conv, short, long, arg, desc, block end # # Parses +arg+ and returns rest of +arg+ and matched portion to the # argument pattern. Yields when the pattern doesn't match substring. # def parse_arg(arg) pattern or return nil, arg unless m = pattern.match(arg) yield(InvalidArgument, arg) return arg, nil end if String === m m = [s = m] else m = m.to_a s = m[0] return nil, m unless String === s end raise InvalidArgument, arg unless arg.rindex(s, 0) return nil, m if s.length == arg.length yield(InvalidArgument, arg) # didn't match whole arg return arg[s.length..-1], m end private :parse_arg # # Parses argument, converts and returns +arg+, +block+ and result of # conversion. Yields at semi-error condition instead of raising an # exception. # def conv_arg(arg, val = nil) if conv val = conv.call(*val) else val = proc {|val| val}.call(*val) end return arg, block, val end private :conv_arg # # Produces the summary text. Each line of the summary is yielded to the # block (without newline). # # +sdone+:: Already summarized short style options keyed hash. # +ldone+:: Already summarized long style options keyed hash. # +width+:: Width of left side (option part). In other words, the right # side (description part) starts after +width+ columns. # +max+:: Maximum width of left side -> the options are filled within # +max+ columns. # +indent+:: Prefix string indents all summarized lines. # def summarize(sdone = [], ldone = [], width = 1, max = width - 1, indent = "") sopts, lopts, s = [], [], nil @short.each {|s| sdone.fetch(s) {sopts << s}; sdone[s] = true} if @short @long.each {|s| ldone.fetch(s) {lopts << s}; ldone[s] = true} if @long return if sopts.empty? and lopts.empty? # completely hidden left = [sopts.join(', ')] right = desc.dup while s = lopts.shift l = left[-1].length + s.length l += arg.length if left.size == 1 && arg l < max or left << '' left[-1] << if left[-1].empty? then ' ' * 4 else ', ' end << s end left[0] << arg if arg mlen = left.collect {|s| s.length}.max.to_i while mlen > width and l = left.shift mlen = left.collect {|s| s.length}.max.to_i if l.length == mlen yield(indent + l) end while begin l = left.shift; r = right.shift; l or r end l = l.to_s.ljust(width) + ' ' + r if r and !r.empty? yield(indent + l) end self end def add_banner(to) # :nodoc: unless @short or @long s = desc.join to << " [" + s + "]..." unless s.empty? end to end def match_nonswitch?(str) # :nodoc: @pattern =~ str unless @short or @long end # # Main name of the switch. # def switch_name (long.first || short.first).sub(/\A-+(?:\[no-\])?/, '') end # # Switch that takes no arguments. # class NoArgument < self # # Raises an exception if any arguments given. # def parse(arg, argv) yield(NeedlessArgument, arg) if arg conv_arg(arg) end def self.incompatible_argument_styles(*) end def self.pattern Object end end # # Switch that takes an argument. # class RequiredArgument < self # # Raises an exception if argument is not present. # def parse(arg, argv) unless arg raise MissingArgument if argv.empty? arg = argv.shift end conv_arg(*parse_arg(arg) {|*exc| raise(*exc)}) end end # # Switch that can omit argument. # class OptionalArgument < self # # Parses argument if given, or uses default value. # def parse(arg, argv, &error) if arg conv_arg(*parse_arg(arg, &error)) else conv_arg(arg) end end end # # Switch that takes an argument, which does not begin with '-'. # class PlacedArgument < self # # Returns nil if argument is not present or begins with '-'. # def parse(arg, argv, &error) if !(val = arg) and (argv.empty? or /\A-/ =~ (val = argv[0])) return nil, block, nil end opt = (val = parse_arg(val, &error))[1] val = conv_arg(*val) if opt and !arg argv.shift else val[0] = nil end val end end end # # Simple option list providing mapping from short and/or long option # string to OptionParser::Switch and mapping from acceptable argument to # matching pattern and converter pair. Also provides summary feature. # class List # Map from acceptable argument types to pattern and converter pairs. attr_reader :atype # Map from short style option switches to actual switch objects. attr_reader :short # Map from long style option switches to actual switch objects. attr_reader :long # List of all switches and summary string. attr_reader :list # # Just initializes all instance variables. # def initialize @atype = {} @short = OptionMap.new @long = OptionMap.new @list = [] end # # See OptionParser.accept. # def accept(t, pat = /.*/nm, &block) if pat pat.respond_to?(:match) or raise TypeError, "has no `match'" else pat = t if t.respond_to?(:match) end unless block block = pat.method(:convert).to_proc if pat.respond_to?(:convert) end @atype[t] = [pat, block] end # # See OptionParser.reject. # def reject(t) @atype.delete(t) end # # Adds +sw+ according to +sopts+, +lopts+ and +nlopts+. # # +sw+:: OptionParser::Switch instance to be added. # +sopts+:: Short style option list. # +lopts+:: Long style option list. # +nlopts+:: Negated long style options list. # def update(sw, sopts, lopts, nsw = nil, nlopts = nil) o = nil sopts.each {|o| @short[o] = sw} if sopts lopts.each {|o| @long[o] = sw} if lopts nlopts.each {|o| @long[o] = nsw} if nsw and nlopts used = @short.invert.update(@long.invert) @list.delete_if {|o| Switch === o and !used[o]} end private :update # # Inserts +switch+ at the head of the list, and associates short, long # and negated long options. Arguments are: # # +switch+:: OptionParser::Switch instance to be inserted. # +short_opts+:: List of short style options. # +long_opts+:: List of long style options. # +nolong_opts+:: List of long style options with "no-" prefix. # # prepend(switch, short_opts, long_opts, nolong_opts) # def prepend(*args) update(*args) @list.unshift(args[0]) end # # Appends +switch+ at the tail of the list, and associates short, long # and negated long options. Arguments are: # # +switch+:: OptionParser::Switch instance to be inserted. # +short_opts+:: List of short style options. # +long_opts+:: List of long style options. # +nolong_opts+:: List of long style options with "no-" prefix. # # append(switch, short_opts, long_opts, nolong_opts) # def append(*args) update(*args) @list.push(args[0]) end # # Searches +key+ in +id+ list. The result is returned or yielded if a # block is given. If it isn't found, nil is returned. # def search(id, key) if list = __send__(id) val = list.fetch(key) {return nil} block_given? ? yield(val) : val end end # # Searches list +id+ for +opt+ and the optional patterns for completion # +pat+. If +icase+ is true, the search is case insensitive. The result # is returned or yielded if a block is given. If it isn't found, nil is # returned. # def complete(id, opt, icase = false, *pat, &block) __send__(id).complete(opt, icase, *pat, &block) end # # Iterates over each option, passing the option to the +block+. # def each_option(&block) list.each(&block) end # # Creates the summary table, passing each line to the +block+ (without # newline). The arguments +args+ are passed along to the summarize # method which is called on every option. # def summarize(*args, &block) list.each do |opt| if opt.respond_to?(:summarize) # perhaps OptionParser::Switch opt.summarize(*args, &block) elsif !opt or opt.empty? yield("") else opt.each(&block) end end end def add_banner(to) # :nodoc: list.each do |opt| if opt.respond_to?(:add_banner) opt.add_banner(to) end end to end end # # Hash with completion search feature. See OptionParser::Completion. # class CompletingHash < Hash include Completion # # Completion for hash key. # def match(key) return key, *fetch(key) { raise AmbiguousArgument, catch(:ambiguous) {return complete(key)} } end end # :stopdoc: # # Enumeration of acceptable argument styles. Possible values are: # # NO_ARGUMENT:: The switch takes no arguments. (:NONE) # REQUIRED_ARGUMENT:: The switch requires an argument. (:REQUIRED) # OPTIONAL_ARGUMENT:: The switch requires an optional argument. (:OPTIONAL) # # Use like --switch=argument (long style) or -Xargument (short style). For # short style, only portion matched to argument pattern is dealed as # argument. # ArgumentStyle = {} NoArgument.each {|el| ArgumentStyle[el] = Switch::NoArgument} RequiredArgument.each {|el| ArgumentStyle[el] = Switch::RequiredArgument} OptionalArgument.each {|el| ArgumentStyle[el] = Switch::OptionalArgument} ArgumentStyle.freeze # # Switches common used such as '--', and also provides default # argument classes # DefaultList = List.new DefaultList.short['-'] = Switch::NoArgument.new {} DefaultList.long[''] = Switch::NoArgument.new {throw :terminate} # # Default options for ARGV, which never appear in option summary. # Officious = {} # # --help # Shows option summary. # Officious['help'] = proc do |parser| Switch::NoArgument.new do puts parser.help exit end end # # --version # Shows version string if Version is defined. # Officious['version'] = proc do |parser| Switch::OptionalArgument.new do |pkg| if pkg begin require 'optparse/version' rescue LoadError else show_version(*pkg.split(/,/)) or abort("#{parser.program_name}: no version found in package #{pkg}") exit end end v = parser.ver or abort("#{parser.program_name}: version unknown") puts v exit end end # :startdoc: # # Class methods # # # Initializes a new instance and evaluates the optional block in context # of the instance. Arguments +args+ are passed to #new, see there for # description of parameters. # # This method is *deprecated*, its behavior corresponds to the older #new # method. # def self.with(*args, &block) opts = new(*args) opts.instance_eval(&block) opts end # # Returns an incremented value of +default+ according to +arg+. # def self.inc(arg, default = nil) case arg when Integer arg.nonzero? when nil default.to_i + 1 end end def inc(*args) self.class.inc(*args) end # # Initializes the instance and yields itself if called with a block. # # +banner+:: Banner message. # +width+:: Summary width. # +indent+:: Summary indent. # def initialize(banner = nil, width = 32, indent = ' ' * 4) @stack = [DefaultList, List.new, List.new] @program_name = nil @banner = banner @summary_width = width @summary_indent = indent @default_argv = ARGV add_officious yield self if block_given? end def add_officious # :nodoc: list = base() Officious.each do |opt, block| list.long[opt] ||= block.call(self) end end # # Terminates option parsing. Optional parameter +arg+ is a string pushed # back to be the first non-option argument. # def terminate(arg = nil) self.class.terminate(arg) end def self.terminate(arg = nil) throw :terminate, arg end @stack = [DefaultList] def self.top() DefaultList end # # Directs to accept specified class +t+. The argument string is passed to # the block in which it should be converted to the desired class. # # +t+:: Argument class specifier, any object including Class. # +pat+:: Pattern for argument, defaults to +t+ if it responds to match. # # accept(t, pat, &block) # def accept(*args, &blk) top.accept(*args, &blk) end # # See #accept. # def self.accept(*args, &blk) top.accept(*args, &blk) end # # Directs to reject specified class argument. # # +t+:: Argument class speficier, any object including Class. # # reject(t) # def reject(*args, &blk) top.reject(*args, &blk) end # # See #reject. # def self.reject(*args, &blk) top.reject(*args, &blk) end # # Instance methods # # Heading banner preceding summary. attr_writer :banner # Program name to be emitted in error message and default banner, # defaults to $0. attr_writer :program_name # Width for option list portion of summary. Must be Numeric. attr_accessor :summary_width # Indentation for summary. Must be String (or have + String method). attr_accessor :summary_indent # Strings to be parsed in default. attr_accessor :default_argv # # Heading banner preceding summary. # def banner unless @banner @banner = "Usage: #{program_name} [options]" visit(:add_banner, @banner) end @banner end # # Program name to be emitted in error message and default banner, defaults # to $0. # def program_name @program_name || File.basename($0, '.*') end # for experimental cascading :-) alias set_banner banner= alias set_program_name program_name= alias set_summary_width summary_width= alias set_summary_indent summary_indent= # Version attr_writer :version # Release code attr_writer :release # # Version # def version @version || (defined?(::Version) && ::Version) end # # Release code # def release @release || (defined?(::Release) && ::Release) || (defined?(::RELEASE) && ::RELEASE) end # # Returns version string from program_name, version and release. # def ver if v = version str = "#{program_name} #{[v].join('.')}" str << " (#{v})" if v = release str end end def warn(mesg = $!) super("#{program_name}: #{mesg}") end def abort(mesg = $!) super("#{program_name}: #{mesg}") end # # Subject of #on / #on_head, #accept / #reject # def top @stack[-1] end # # Subject of #on_tail. # def base @stack[1] end # # Pushes a new List. # def new @stack.push(List.new) if block_given? yield self else self end end # # Removes the last List. # def remove @stack.pop end # # Puts option summary into +to+ and returns +to+. Yields each line if # a block is given. # # +to+:: Output destination, which must have method <<. Defaults to []. # +width+:: Width of left side, defaults to @summary_width. # +max+:: Maximum length allowed for left side, defaults to +width+ - 1. # +indent+:: Indentation, defaults to @summary_indent. # def summarize(to = [], width = @summary_width, max = width - 1, indent = @summary_indent, &blk) visit(:summarize, {}, {}, width, max, indent, &(blk || proc {|l| to << l + $/})) to end # # Returns option summary string. # def help; summarize(banner.to_s.sub(/\n?\z/, "\n")) end alias to_s help # # Returns option summary list. # def to_a; summarize(banner.to_a.dup) end # # Checks if an argument is given twice, in which case an ArgumentError is # raised. Called from OptionParser#switch only. # # +obj+:: New argument. # +prv+:: Previously specified argument. # +msg+:: Exception message. # def notwice(obj, prv, msg) unless !prv or prv == obj begin raise ArgumentError, "argument #{msg} given twice: #{obj}" rescue $@[0, 2] = nil raise end end obj end private :notwice # # Creates an OptionParser::Switch from the parameters. The parsed argument # value is passed to the given block, where it can be processed. # # See at the beginning of OptionParser for some full examples. # # +opts+ can include the following elements: # # [Argument style:] # One of the following: # :NONE, :REQUIRED, :OPTIONAL # # [Argument pattern:] # Acceptable option argument format, must be pre-defined with # OptionParser.accept or OptionParser#accept, or Regexp. This can appear # once or assigned as String if not present, otherwise causes an # ArgumentError. Examples: # Float, Time, Array # # [Possible argument values:] # Hash or Array. # [:text, :binary, :auto] # %w[iso-2022-jp shift_jis euc-jp utf8 binary] # { "jis" => "iso-2022-jp", "sjis" => "shift_jis" } # # [Long style switch:] # Specifies a long style switch which takes a mandatory, optional or no # argument. It's a string of the following form: # "--switch=MANDATORY" or "--switch MANDATORY" # "--switch[=OPTIONAL]" # "--switch" # # [Short style switch:] # Specifies short style switch which takes a mandatory, optional or no # argument. It's a string of the following form: # "-xMANDATORY" # "-x[OPTIONAL]" # "-x" # There is also a special form which matches character range (not full # set of regural expression): # "-[a-z]MANDATORY" # "-[a-z][OPTIONAL]" # "-[a-z]" # # [Argument style and description:] # Instead of specifying mandatory or optional orguments directly in the # switch parameter, this separate parameter can be used. # "=MANDATORY" # "=[OPTIONAL]" # # [Description:] # Description string for the option. # "Run verbosely" # # [Handler:] # Handler for the parsed argument value. Either give a block or pass a # Proc or Method as an argument. # def make_switch(opts, block = nil) short, long, nolong, style, pattern, conv, not_pattern, not_conv, not_style = [], [], [] ldesc, sdesc, desc, arg = [], [], [] default_style = Switch::NoArgument default_pattern = nil klass = nil o = nil n, q, a = nil opts.each do |o| # argument class next if search(:atype, o) do |pat, c| klass = notwice(o, klass, 'type') if not_style and not_style != Switch::NoArgument not_pattern, not_conv = pat, c else default_pattern, conv = pat, c end end # directly specified pattern(any object possible to match) if !(String === o) and o.respond_to?(:match) pattern = notwice(o, pattern, 'pattern') conv = (pattern.method(:convert).to_proc if pattern.respond_to?(:convert)) next end # anything others case o when Proc, Method block = notwice(o, block, 'block') when Array, Hash case pattern when CompletingHash when nil pattern = CompletingHash.new conv = (pattern.method(:convert).to_proc if pattern.respond_to?(:convert)) else raise ArgumentError, "argument pattern given twice" end o.each {|(o, *v)| pattern[o] = v.fetch(0) {o}} when Module raise ArgumentError, "unsupported argument type: #{o}" when *ArgumentStyle.keys style = notwice(ArgumentStyle[o], style, 'style') when /^--no-([^\[\]=\s]*)(.+)?/ q, a = $1, $2 o = notwice(a ? Object : TrueClass, klass, 'type') not_pattern, not_conv = search(:atype, o) unless not_style not_style = (not_style || default_style).guess(arg = a) if a default_style = Switch::NoArgument default_pattern, conv = search(:atype, FalseClass) unless default_pattern ldesc << "--no-#{q}" long << 'no-' + (q = q.downcase) nolong << q when /^--\[no-\]([^\[\]=\s]*)(.+)?/ q, a = $1, $2 o = notwice(a ? Object : TrueClass, klass, 'type') if a default_style = default_style.guess(arg = a) default_pattern, conv = search(:atype, o) unless default_pattern end ldesc << "--[no-]#{q}" long << (o = q.downcase) not_pattern, not_conv = search(:atype, FalseClass) unless not_style not_style = Switch::NoArgument nolong << 'no-' + o when /^--([^\[\]=\s]*)(.+)?/ q, a = $1, $2 if a o = notwice(NilClass, klass, 'type') default_style = default_style.guess(arg = a) default_pattern, conv = search(:atype, o) unless default_pattern end ldesc << "--#{q}" long << (o = q.downcase) when /^-(\[\^?\]?(?:[^\\\]]|\\.)*\])(.+)?/ q, a = $1, $2 o = notwice(Object, klass, 'type') if a default_style = default_style.guess(arg = a) default_pattern, conv = search(:atype, o) unless default_pattern end sdesc << "-#{q}" short << Regexp.new(q) when /^-(.)(.+)?/ q, a = $1, $2 if a o = notwice(NilClass, klass, 'type') default_style = default_style.guess(arg = a) default_pattern, conv = search(:atype, o) unless default_pattern end sdesc << "-#{q}" short << q when /^=/ style = notwice(default_style.guess(arg = o), style, 'style') default_pattern, conv = search(:atype, Object) unless default_pattern else desc.push(o) end end default_pattern, conv = search(:atype, default_style.pattern) unless default_pattern if !(short.empty? and long.empty?) s = (style || default_style).new(pattern || default_pattern, conv, sdesc, ldesc, arg, desc, block) elsif !block raise ArgumentError, "no switch given" if style or pattern s = desc else short << pattern s = (style || default_style).new(pattern, conv, nil, nil, arg, desc, block) end return s, short, long, (not_style.new(not_pattern, not_conv, sdesc, ldesc, nil, desc, block) if not_style), nolong end def define(*opts, &block) top.append(*(sw = make_switch(opts, block))) sw[0] end # # Add option switch and handler. See #make_switch for an explanation of # parameters. # def on(*opts, &block) define(*opts, &block) self end alias def_option define def define_head(*opts, &block) top.prepend(*(sw = make_switch(opts, block))) sw[0] end # # Add option switch like with #on, but at head of summary. # def on_head(*opts, &block) define_head(*opts, &block) self end alias def_head_option define_head def define_tail(*opts, &block) base.append(*(sw = make_switch(opts, block))) sw[0] end # # Add option switch like with #on, but at tail of summary. # def on_tail(*opts, &block) define_tail(*opts, &block) self end alias def_tail_option define_tail # # Add separator in summary. # def separator(string) top.append(string, nil, nil) end # # Parses command line arguments +argv+ in order. When a block is given, # each non-option argument is yielded. # # Returns the rest of +argv+ left unparsed. # def order(*argv, &block) argv = argv[0].dup if argv.size == 1 and Array === argv[0] order!(argv, &block) end # # Same as #order, but removes switches destructively. # def order!(argv = default_argv, &nonopt) parse_in_order(argv, &nonopt) end def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc: opt, arg, sw, val, rest = nil nonopt ||= proc {|arg| throw :terminate, arg} argv.unshift(arg) if arg = catch(:terminate) { while arg = argv.shift case arg # long option when /\A--([^=]*)(?:=(.*))?/nm opt, rest = $1, $2 begin sw, = complete(:long, opt, true) rescue ParseError raise $!.set_option(arg, true) end begin opt, cb, val = sw.parse(rest, argv) {|*exc| raise(*exc)} val = cb.call(val) if cb setter.call(sw.switch_name, val) if setter rescue ParseError raise $!.set_option(arg, rest) end # short option when /\A-(.)((=).*|.+)?/nm opt, has_arg, eq, val, rest = $1, $3, $3, $2, $2 begin sw, = search(:short, opt) unless sw begin sw, = complete(:short, opt) # short option matched. val = arg.sub(/\A-/, '') has_arg = true rescue InvalidOption # if no short options match, try completion with long # options. sw, = complete(:long, opt) eq ||= !rest end end rescue ParseError raise $!.set_option(arg, true) end begin opt, cb, val = sw.parse(val, argv) {|*exc| raise(*exc) if eq} raise InvalidOption, arg if has_arg and !eq and arg == "-#{opt}" argv.unshift(opt) if opt and (opt = opt.sub(/\A-*/, '-')) != '-' val = cb.call(val) if cb setter.call(sw.switch_name, val) if setter rescue ParseError raise $!.set_option(arg, arg.length > 2) end # non-option argument else catch(:prune) do visit(:each_option) do |sw| sw.block.call(arg) if Switch === sw and sw.match_nonswitch?(arg) end nonopt.call(arg) end end end nil } visit(:search, :short, nil) {|sw| sw.block.call(*argv) if !sw.pattern} argv end private :parse_in_order # # Parses command line arguments +argv+ in permutation mode and returns # list of non-option arguments. # def permute(*argv) argv = argv[0].dup if argv.size == 1 and Array === argv[0] permute!(argv) end # # Same as #permute, but removes switches destructively. # def permute!(argv = default_argv) nonopts = [] arg = nil order!(argv) {|arg| nonopts << arg} argv[0, 0] = nonopts argv end # # Parses command line arguments +argv+ in order when environment variable # POSIXLY_CORRECT is set, and in permutation mode otherwise. # def parse(*argv) argv = argv[0].dup if argv.size == 1 and Array === argv[0] parse!(argv) end # # Same as #parse, but removes switches destructively. # def parse!(argv = default_argv) if ENV.include?('POSIXLY_CORRECT') order!(argv) else permute!(argv) end end # # Wrapper method for getopts.rb. # # params = ARGV.getopts("ab:", "foo", "bar:") # # params[:a] = true # -a # # params[:b] = "1" # -b1 # # params[:foo] = "1" # --foo # # params[:bar] = "x" # --bar x # def getopts(*args) argv = Array === args.first ? args.shift : default_argv single_options, *long_options = *args result = {} single_options.scan(/(.)(:)?/) do |opt, val| if val result[opt] = nil define("-#{opt} VAL") else result[opt] = false define("-#{opt}") end end if single_options long_options.each do |arg| opt, val = arg.split(':', 2) if val result[opt] = val.empty? ? nil : val define("--#{opt} VAL") else result[opt] = false define("--#{opt}") end end parse_in_order(argv, result.method(:[]=)) result end # # See #getopts. # def self.getopts(*args) new.getopts(*args) end # # Traverses @stack, sending each element method +id+ with +args+ and # +block+. # def visit(id, *args, &block) el = nil @stack.reverse_each do |el| el.send(id, *args, &block) end nil end private :visit # # Searches +key+ in @stack for +id+ hash and returns or yields the result. # def search(id, key) block_given = block_given? visit(:search, id, key) do |k| return block_given ? yield(k) : k end end private :search # # Completes shortened long style option switch and returns pair of # canonical switch and switch descriptor OptionParser::Switch. # # +id+:: Searching table. # +opt+:: Searching key. # +icase+:: Search case insensitive if true. # +pat+:: Optional pattern for completion. # def complete(typ, opt, icase = false, *pat) if pat.empty? search(typ, opt) {|sw| return [sw, opt]} # exact match or... end raise AmbiguousOption, catch(:ambiguous) { visit(:complete, typ, opt, icase, *pat) {|opt, *sw| return sw} raise InvalidOption, opt } end private :complete # # Loads options from file names as +filename+. Does nothing when the file # is not present. Returns whether successfully loaded. # # +filename+ defaults to basename of the program without suffix in a # directory ~/.options. # def load(filename = nil) begin filename ||= File.expand_path(File.basename($0, '.*'), '~/.options') rescue return false end begin parse(*IO.readlines(filename).each {|s| s.chomp!}) true rescue Errno::ENOENT, Errno::ENOTDIR false end end # # Parses environment variable +env+ or its uppercase with splitting like a # shell. # # +env+ defaults to the basename of the program. # def environment(env = File.basename($0, '.*')) env = ENV[env] || ENV[env.upcase] or return parse(*Shellwords.shellwords(env)) end # # Acceptable argument classes # # # Any string and no conversion. This is fall-back. # accept(Object) {|s,|s or s.nil?} accept(NilClass) {|s,|s} # # Any non-empty string, and no conversion. # accept(String, /.+/nm) {|s,*|s} # # Ruby/C-like integer, octal for 0-7 sequence, binary for 0b, hexadecimal # for 0x, and decimal for others; with optional sign prefix. Converts to # Integer. # decimal = '\d+(?:_\d+)*' binary = 'b[01]+(?:_[01]+)*' hex = 'x[\da-f]+(?:_[\da-f]+)*' octal = "0(?:[0-7]*(?:_[0-7]+)*|#{binary}|#{hex})" integer = "#{octal}|#{decimal}" accept(Integer, %r"\A[-+]?(?:#{integer})"io) {|s,| Integer(s) if s} # # Float number format, and converts to Float. # float = "(?:#{decimal}(?:\\.(?:#{decimal})?)?|\\.#{decimal})(?:E[-+]?#{decimal})?" floatpat = %r"\A[-+]?#{float}"io accept(Float, floatpat) {|s,| s.to_f if s} # # Generic numeric format, converts to Integer for integer format, Float # for float format. # accept(Numeric, %r"\A[-+]?(?:#{octal}|#{float})"io) {|s,| eval(s) if s} # # Decimal integer format, to be converted to Integer. # DecimalInteger = /\A[-+]?#{decimal}/io accept(DecimalInteger) {|s,| s.to_i if s} # # Ruby/C like octal/hexadecimal/binary integer format, to be converted to # Integer. # OctalInteger = /\A[-+]?(?:[0-7]+(?:_[0-7]+)*|0(?:#{binary}|#{hex}))/io accept(OctalInteger) {|s,| s.oct if s} # # Decimal integer/float number format, to be converted to Integer for # integer format, Float for float format. # DecimalNumeric = floatpat # decimal integer is allowed as float also. accept(DecimalNumeric) {|s,| eval(s) if s} # # Boolean switch, which means whether it is present or not, whether it is # absent or not with prefix no-, or it takes an argument # yes/no/true/false/+/-. # yesno = CompletingHash.new %w[- no false].each {|el| yesno[el] = false} %w[+ yes true].each {|el| yesno[el] = true} yesno['nil'] = false # shoud be nil? accept(TrueClass, yesno) {|arg, val| val == nil or val} # # Similar to TrueClass, but defaults to false. # accept(FalseClass, yesno) {|arg, val| val != nil and val} # # List of strings separated by ",". # accept(Array) do |s,| if s s = s.split(',').collect {|s| s unless s.empty?} end s end # # Regular expression with options. # accept(Regexp, %r"\A/((?:\\.|[^\\])*)/([[:alpha:]]+)?\z|.*") do |all, s, o| f = 0 if o f |= Regexp::IGNORECASE if /i/ =~ o f |= Regexp::MULTILINE if /m/ =~ o f |= Regexp::EXTENDED if /x/ =~ o k = o.delete("^imx") end Regexp.new(s || all, f, k) end # # Exceptions # # # Base class of exceptions from OptionParser. # class ParseError < RuntimeError # Reason which caused the error. Reason = 'parse error'.freeze def initialize(*args) @args = args @reason = nil end attr_reader :args attr_writer :reason # # Pushes back erred argument(s) to +argv+. # def recover(argv) argv[0, 0] = @args argv end def set_option(opt, eq) if eq @args[0] = opt else @args.unshift(opt) end self end # # Returns error reason. Override this for I18N. # def reason @reason || self.class::Reason end def inspect "#<#{self.class.to_s}: #{args.join(' ')}>" end # # Default stringizing method to emit standard error message. # def message reason + ': ' + args.join(' ') end alias to_s message end # # Raises when ambiguously completable string is encountered. # class AmbiguousOption < ParseError const_set(:Reason, 'ambiguous option'.freeze) end # # Raises when there is an argument for a switch which takes no argument. # class NeedlessArgument < ParseError const_set(:Reason, 'needless argument'.freeze) end # # Raises when a switch with mandatory argument has no argument. # class MissingArgument < ParseError const_set(:Reason, 'missing argument'.freeze) end # # Raises when switch is undefined. # class InvalidOption < ParseError const_set(:Reason, 'invalid option'.freeze) end # # Raises when the given argument does not match required format. # class InvalidArgument < ParseError const_set(:Reason, 'invalid argument'.freeze) end # # Raises when the given argument word can't be completed uniquely. # class AmbiguousArgument < InvalidArgument const_set(:Reason, 'ambiguous argument'.freeze) end # # Miscellaneous # # # Extends command line arguments array (ARGV) to parse itself. # module Arguable # # Sets OptionParser object, when +opt+ is +false+ or +nil+, methods # OptionParser::Arguable#options and OptionParser::Arguable#options= are # undefined. Thus, there is no ways to access the OptionParser object # via the receiver object. # def options=(opt) unless @optparse = opt class << self undef_method(:options) undef_method(:options=) end end end # # Actual OptionParser object, automatically created if nonexistent. # # If called with a block, yields the OptionParser object and returns the # result of the block. If an OptionParser::ParseError exception occurs # in the block, it is rescued, a error message printed to STDERR and # +nil+ returned. # def options @optparse ||= OptionParser.new @optparse.default_argv = self block_given? or return @optparse begin yield @optparse rescue ParseError @optparse.warn $! nil end end # # Parses +self+ destructively in order and returns +self+ containing the # rest arguments left unparsed. # def order!(&blk) options.order!(self, &blk) end # # Parses +self+ destructively in permutation mode and returns +self+ # containing the rest arguments left unparsed. # def permute!() options.permute!(self) end # # Parses +self+ destructively and returns +self+ containing the # rest arguments left unparsed. # def parse!() options.parse!(self) end # # Substitution of getopts is possible as follows. Also see # OptionParser#getopts. # # def getopts(*args) # ($OPT = ARGV.getopts(*args)).each do |opt, val| # eval "$OPT_#{opt.gsub(/[^A-Za-z0-9_]/, '_')} = val" # end # rescue OptionParser::ParseError # end # def getopts(*args) options.getopts(self, *args) end # # Initializes instance variable. # def self.extend_object(obj) super obj.instance_eval {@optparse = nil} end def initialize(*args) super @optparse = nil end end # # Acceptable argument classes. Now contains DecimalInteger, OctalInteger # and DecimalNumeric. See Acceptable argument classes (in source code). # module Acceptables const_set(:DecimalInteger, OptionParser::DecimalInteger) const_set(:OctalInteger, OptionParser::OctalInteger) const_set(:DecimalNumeric, OptionParser::DecimalNumeric) end end # ARGV is arguable by OptionParser ARGV.extend(OptionParser::Arguable) if $0 == __FILE__ Version = OptionParser::Version ARGV.options {|q| q.parse!.empty? or puts "what's #{ARGV.join(' ')}?" } or abort(ARGV.options.to_s) end ================================================ FILE: distro/platform_info.rb ================================================ # This module autodetects various platform-specific information, and # provides that information through constants. module PlatformInfo private def self.env_defined?(name) return !ENV[name].nil? && !ENV[name].empty? end def self.determine_gem_command gem_exe_in_path = find_command("gem") correct_gem_exe = File.dirname(RUBY) + "/gem" if gem_exe_in_path.nil? || gem_exe_in_path == correct_gem_exe return "gem" else return correct_gem_exe end end def self.find_apxs2 if env_defined?("APXS2") return ENV["APXS2"] end ['apxs2', 'apxs'].each do |name| command = find_command(name) if !command.nil? return command end end return nil end def self.determine_apache2_bindir if APXS2.nil? return nil else return `#{APXS2} -q BINDIR 2>/dev/null`.strip end end def self.determine_apache2_sbindir if APXS2.nil? return nil else return `#{APXS2} -q SBINDIR`.strip end end def self.find_apache2_executable(*possible_names) [APACHE2_BINDIR, APACHE2_SBINDIR].each do |bindir| if bindir.nil? next end possible_names.each do |name| filename = "#{bindir}/#{name}" if File.file?(filename) && File.executable?(filename) return filename end end end return nil end def self.find_apache2ctl return find_apache2_executable('apache2ctl', 'apachectl') end def self.find_httpd if env_defined?('HTTPD') return ENV['HTTPD'] elsif APXS2.nil? ["apache2", "httpd2", "apache", "httpd"].each do |name| command = find_command(name) if !command.nil? return command end end return nil else return find_apache2_executable(`#{APXS2} -q TARGET`.strip) end end def self.determine_apxs2_flags if APXS2.nil? return nil else flags = `#{APXS2} -q CFLAGS`.strip << " -I" << `#{APXS2} -q INCLUDEDIR` flags.strip! flags.gsub!(/-O\d? /, '') return flags end end def self.find_apr_config if env_defined?('APR_CONFIG') apr_config = ENV['APR_CONFIG'] elsif RUBY_PLATFORM =~ /darwin/ && HTTPD == "/usr/sbin/httpd" # If we're on MacOS X, and we're compiling against the # default provided Apache, then we'll want to query the # correct 'apr-1-config' command. However, that command # is not in $PATH by default. Instead, it lives in # /Developer/SDKs/MacOSX*sdk/usr/bin. sdk_dir = Dir["/Developer/SDKs/MacOSX*sdk"].sort.last if sdk_dir apr_config = "#{sdk_dir}/usr/bin/apr-1-config" if !File.executable?(apr_config) apr_config = nil end end else apr_config = find_command('apr-1-config') if apr_config.nil? apr_config = find_command('apr-config') end end return apr_config end def self.determine_apr_info if APR_CONFIG.nil? return nil else flags = `#{APR_CONFIG} --cppflags --includes`.strip libs = `#{APR_CONFIG} --link-ld`.strip flags.gsub!(/-O\d? /, '') return [flags, libs] end end def self.determine_multi_arch_flags if RUBY_PLATFORM =~ /darwin/ && !HTTPD.nil? architectures = [] `file "#{HTTPD}"`.split("\n").grep(/for architecture/).each do |line| line =~ /for architecture (.*?)\)/ architectures << "-arch #{$1}" end return architectures.join(' ') else return "" end end def self.determine_library_extension if RUBY_PLATFORM =~ /darwin/ return "bundle" else return "so" end end def self.read_file(filename) return File.read(filename) rescue return "" end def self.determine_libext if RUBY_PLATFORM =~ /darwin/ return "dylib" else return "so" end end def self.determine_ruby_libext if RUBY_PLATFORM =~ /darwin/ return "bundle" else return "so" end end def self.determine_linux_distro if RUBY_PLATFORM !~ /linux/ return nil end lsb_release = read_file("/etc/lsb-release") if lsb_release =~ /Ubuntu/ return :ubuntu elsif File.exist?("/etc/debian_version") return :debian elsif File.exist?("/etc/redhat-release") redhat_release = read_file("/etc/redhat-release") if redhat_release =~ /CentOS/ return :centos elsif redhat_release =~ /Fedora/ # is this correct? return :fedora else # On official RHEL distros, the content is in the form of # "Red Hat Enterprise Linux Server release 5.1 (Tikanga)" return :rhel end elsif File.exist?("/etc/suse-release") return :suse elsif File.exist?("/etc/gentoo-release") return :gentoo else return :unknown end # TODO: Slackware, Mandrake/Mandriva end def self.determine_c_compiler return ENV['CC'] || find_command('gcc') || find_command('cc') end def self.determine_cxx_compiler return ENV['CXX'] || find_command('g++') || find_command('c++') end # Returns true if the Solaris version of ld is in use. def self.solaris_ld? ld_version = `ld -V 2>&1` return !!ld_version.index("Solaris") end public # Check whether the specified command is in $PATH, and return its # absolute filename. Returns nil if the command is not found. # # This function exists because system('which') doesn't always behave # correctly, for some weird reason. def self.find_command(name) ENV['PATH'].split(File::PATH_SEPARATOR).detect do |directory| path = File.join(directory, name.to_s) if File.executable?(path) return path end end return nil end CC = determine_c_compiler CXX = determine_cxx_compiler LIBEXT = determine_libext RUBYLIBEXT = determine_ruby_libext # An identifier for the current Linux distribution. nil if the operating system is not Linux. LINUX_DISTRO = determine_linux_distro end ================================================ FILE: distro/tasks.rb ================================================ verbose true VENDOR_RUBY_VERSION = begin data = File.read("version.h") data =~ /RUBY_VERSION "(.*)"/ $1 end REE_VERSION = begin data = File.read("version.c") data =~ /REE_VERSION "(.*)"/ $1 end DISTDIR = "ruby-enterprise-#{VENDOR_RUBY_VERSION}-#{REE_VERSION}" RUBYGEMS_URL = "http://rubyforge.org/frs/download.php/70696/rubygems-1.3.7.tgz" RUBYGEMS_PACKAGE = RUBYGEMS_URL.sub(/.*\//, '') def create_fakeroot distdir = "/tmp/r8ee-test" create_distdir(distdir) sh "rm -rf fakeroot" sh "mkdir fakeroot" fakeroot = File.expand_path("fakeroot") sh "#{distdir}/installer --auto='/usr/local' --destdir='#{fakeroot}' #{ENV['ARGS']}" puts "*** Ruby Enterprise Edition has been installed to #{fakeroot}" end # Check whether the specified command is in $PATH, and return its # absolute filename. Returns nil if the command is not found. # # This function exists because system('which') doesn't always behave # correctly, for some weird reason. def find_command(name) ENV['PATH'].split(File::PATH_SEPARATOR).detect do |directory| path = File.join(directory, name.to_s) if File.executable?(path) return path end end return nil end def download(url) if find_command('wget') sh "wget", RUBYGEMS_URL else sh "curl", "-O", "-L", RUBYGEMS_URL end end def create_distdir(distdir = DISTDIR, sudo = false) if sudo sh "sudo rm -rf #{distdir}" else sh "rm -rf #{distdir}" end sh "mkdir #{distdir}" sh "mkdir #{distdir}/source" sh "git archive HEAD | tar -C #{distdir}/source -xf -" sh "cp distro/*.rb #{distdir}/" Dir.chdir("#{distdir}/source") do sh "autoconf" sh 'rm', '-rf', 'autom4te.cache' sh 'bison', '-y', '-o', 'parse.c', 'parse.y' end sh "git diff copy_on_write..zero_copy_context_switch > #{distdir}/fast-threading.patch" sh "cp distro/installer distro/installer.rb distro/platform_info.rb " << "distro/dependencies.rb distro/optparse.rb #{distdir}/" sh "cd #{distdir} && ln -s source/distro/runtime ." File.open("#{distdir}/version.txt", "w") do |f| f.write("#{VENDOR_RUBY_VERSION}-#{REE_VERSION}") end if !File.exist?("distro/#{RUBYGEMS_PACKAGE}") Dir.chdir("distro") do download(RUBYGEMS_URL) end end rubygems_package = File.expand_path("distro/#{RUBYGEMS_PACKAGE}") Dir.chdir(distdir) do sh "tar", "xzf", rubygems_package sh "mv rubygems* rubygems" end end # Returns the disk usage of the given directory, in KB. def disk_usage(dir) if RUBY_PLATFORM =~ /linux/ options = "-a -k --apparent-size --max-depth=0" else options = "-k -d 0" end return `du #{options} \"#{dir}\"`.strip.to_i end desc "Create a distribution directory" task :distdir do create_distdir end desc "Create a distribution package" task :package do create_distdir ENV['GZIP'] = '--best' sh "tar -czf #{DISTDIR}.tar.gz #{DISTDIR}" sh "rm -rf #{DISTDIR}" end desc "Test the installer script. Pass extra arguments to the installer with ARGS." task :test_installer do distdir = "/tmp/r8ee-test" create_distdir(distdir, ENV['SUDO']) sh "ln -sf `pwd`/distro/installer.rb #{distdir}/installer.rb" command = "#{distdir}/installer --no-dev-docs #{ENV['ARGS']}" if ENV['SUDO'] command = "sudo #{command}" end sh command end desc "Auto-install into a fake root directory" task :fakeroot do create_fakeroot end desc "Create a Debian package. Set SKIP_FAKEROOT=1 if you want to bypass fakeroot recreation." task 'package:debian' do create_fakeroot if ENV['SKIP_FAKEROOT'].nil? || ENV['SKIP_FAKEROOT'].empty? sh "rm -rf fakeroot/DEBIAN" sh "cp -R distro/debian fakeroot/DEBIAN" installed_size = disk_usage("fakeroot") raw_arch = `uname -m`.strip arch = case raw_arch when /^i.86$/ "i386" when /^x86_64/ "amd64" else raw_arch end require 'erb' template = ERB.new(File.read("fakeroot/DEBIAN/control")) File.open("fakeroot/DEBIAN/control", "w") do |f| f.write(template.result(binding)) end sh "fakeroot dpkg -b fakeroot ruby-enterprise_#{VENDOR_RUBY_VERSION}-#{REE_VERSION}_#{arch}.deb" end desc "Generate the documentation HTML" file 'distro/documentation.html' => 'distro/documentation.txt' do sh "asciidoc -a toc -a numbered -a toclevels=3 -a icons distro/documentation.txt" end desc "Change shebang lines for Ruby scripts to '#!/usr/bin/env ruby'" task :fix_shebang do if ENV['dir'].nil? STDERR.write("Usage: rake fix_shebang dir=\n") exit 1 end Dir.chdir(ENV['dir']) do sh "sed -i 's|^#!.*$|#!/usr/bin/env ruby|' *" end end ================================================ FILE: distruby.rb ================================================ #!./miniruby if RUBY_PATCHLEVEL.zero? dirname = sprintf 'ruby-%s', RUBY_VERSION tagname = dirname.gsub /ruby-(\d)\.(\d)\.(\d)/, 'v\1_\2_\3' else dirname = sprintf 'ruby-%s-p%u', RUBY_VERSION, RUBY_PATCHLEVEL tagname = dirname.gsub /ruby-(\d)\.(\d)\.(\d)-p/, 'v\1_\2_\3_' end tgzname = dirname + '.tar.gz' tbzname = dirname + '.tar.bz2' zipname = dirname + '.zip' repos = 'http://svn.ruby-lang.org/repos/ruby/tags/' + tagname STDERR.puts 'exporting sources...' system 'svn', 'export', '-q', repos, dirname Dir.chdir dirname do STDERR.puts 'generating configure...' system 'autoconf' system 'rm', '-rf', 'autom4te.cache' STDERR.puts 'generating parse.c...' system 'bison', '-y', '-o', 'parse.c', 'parse.y' end STDERR.puts 'generating tarballs...' ENV['GZIP'] = '-9' system 'tar', 'chofzp', tgzname, dirname system 'tar', 'chojfp', tbzname, dirname system 'zip', '-q9r', zipname, dirname require 'digest/md5' require 'digest/sha2' for name in [tgzname, tbzname, zipname] do open name, 'rb' do |fp| str = fp.read md5 = Digest::MD5.hexdigest str sha = Digest::SHA256.hexdigest str printf "MD5(%s)= %s\nSHA256(%s)= %s\nSIZE(%s)= %s\n\n", name, md5, name, sha, name, str.size end end # # Local Variables: # mode: ruby # code: utf-8 # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # fill-column: 79 # default-justification: full # End: # vi: ts=3 sw=3 ================================================ FILE: djgpp/GNUmakefile.in ================================================ include Makefile VPATH = $(srcdir) $(srcdir)/missing ================================================ FILE: djgpp/README.djgpp ================================================ * How to compile and install on djgpp This is what you need to do to compile and install Ruby: 1. Run configure.bat, which will generate config.h and Makefile (GNU sed required). Message like this is normal: sed.exe: can't read 123456789: No such file or directory (ENOENT) 2. Edit defines.h if you need. Probably this step will not need. 3. Remove comment mark(#) before the module names from ext/Setup.dj (or add module names if not present). 4. Run make. 5. Optionally, run 'make test' to check whether the compiled Ruby interpreter works well. If you see the message "test succeeded", your ruby works as it should (hopefully). 6. Run 'make install' ================================================ FILE: djgpp/config.hin ================================================ #define PACKAGE_NAME "" #define PACKAGE_TARNAME "" #define PACKAGE_VERSION "" #define PACKAGE_STRING "" #define PACKAGE_BUGREPORT "" #define USE_BUILTIN_FRAME_ADDRESS 1 #define STDC_HEADERS 1 #define HAVE_SYS_TYPES_H 1 #define HAVE_SYS_STAT_H 1 #define HAVE_STDLIB_H 1 #define HAVE_STRING_H 1 #define HAVE_MEMORY_H 1 #define HAVE_STRINGS_H 1 #define HAVE_UNISTD_H 1 #define HAVE_LONG_LONG 1 #define HAVE_OFF_T 1 #define SIZEOF_INT 4 #define SIZEOF_SHORT 2 #define SIZEOF_LONG 4 #define SIZEOF_LONG_LONG 8 #define SIZEOF___INT64 0 #define SIZEOF_OFF_T 4 #define SIZEOF_VOIDP 4 #define SIZEOF_FLOAT 4 #define SIZEOF_DOUBLE 8 #define HAVE_PROTOTYPES 1 #define TOKEN_PASTE(x,y) x##y #define HAVE_STDARG_PROTOTYPES 1 #define NORETURN(x) x __attribute__ ((noreturn)) #define HAVE_DECL_SYS_NERR 1 #define HAVE_DIRENT_H 1 #define STDC_HEADERS 1 #define HAVE_SYS_WAIT_H 1 #define HAVE_STDLIB_H 1 #define HAVE_STRING_H 1 #define HAVE_UNISTD_H 1 #define HAVE_LIMITS_H 1 #define HAVE_SYS_FILE_H 1 #define HAVE_SYS_IOCTL_H 1 #define HAVE_FCNTL_H 1 #define HAVE_SYS_FCNTL_H 1 #define HAVE_SYS_TIME_H 1 #define HAVE_SYS_TIMES_H 1 #define HAVE_SYS_PARAM_H 1 #define HAVE_PWD_H 1 #define HAVE_UTIME_H 1 #define HAVE_MEMORY_H 1 #define HAVE_DIRECT_H 1 #define HAVE_SYS_RESOURCE_H 1 #define HAVE_STRUCT_STAT_ST_BLKSIZE 1 #define HAVE_ST_BLKSIZE 1 #define HAVE_STRUCT_STAT_ST_RDEV 1 #define HAVE_ST_RDEV 1 #define GETGROUPS_T gid_t #define RETSIGTYPE void #define HAVE_ALLOCA 1 #define HAVE_DUP2 1 #define HAVE_MEMMOVE 1 #define HAVE_MKDIR 1 #define HAVE_STRCASECMP 1 #define HAVE_STRNCASECMP 1 #define HAVE_STRERROR 1 #define HAVE_STRFTIME 1 #define HAVE_STRCHR 1 #define HAVE_STRSTR 1 #define HAVE_STRTOUL 1 #define HAVE_ISINF 1 #define HAVE_ISNAN 1 #define HAVE_FINITE 1 #define HAVE_HYPOT 1 #define HAVE_ACOSH 1 #define HAVE_FMOD 1 #define HAVE_WAITPID 1 #define HAVE_FSYNC 1 #define HAVE_TRUNCATE 1 #define HAVE_CHSIZE 1 #define HAVE_TIMES 1 #define HAVE_UTIMES 1 #define HAVE_FCNTL 1 #define HAVE_SYMLINK 1 #define HAVE_SETITIMER 1 #define HAVE_PAUSE 1 #define HAVE_GETPGRP 1 #define HAVE_SETPGID 1 #define HAVE_GETGROUPS 1 #define HAVE_GETRLIMIT 1 #define HAVE_SIGPROCMASK 1 #define HAVE_SIGACTION 1 #define HAVE_SETSID 1 #define HAVE_TELLDIR 1 #define HAVE_SEEKDIR 1 #define HAVE_MKTIME 1 #define HAVE_COSH 1 #define HAVE_SINH 1 #define HAVE_TANH 1 #define HAVE_STRUCT_TM_TM_ZONE 1 #define HAVE_TM_ZONE 1 #define HAVE_STRUCT_TM_TM_GMTOFF 1 #define POSIX_SIGNAL 1 #define GETPGRP_VOID 1 #define SETPGRP_VOID 1 #define RSHIFT(x,y) ((x)>>(int)y) #define FILE_COUNT _cnt #define FILE_READPTR _ptr #define NEED_IO_FLUSH_BETWEEN_RW 1 #define DEFAULT_KCODE KCODE_NONE #define DLEXT ".so" #define RUBY_LIB "/lib/ruby/@MAJOR@.@MINOR@" #define RUBY_SITE_LIB "/lib/ruby/site_ruby" #define RUBY_SITE_LIB2 "/lib/ruby/site_ruby/@MAJOR@.@MINOR@" #define RUBY_PLATFORM "i386-msdosdjgpp" #define RUBY_ARCHLIB "/lib/ruby/@MAJOR@.@MINOR@/i386-msdosdjgpp" #define RUBY_SITE_ARCHLIB "/lib/ruby/site_ruby/@MAJOR@.@MINOR@/i386-msdosdjgpp" ================================================ FILE: djgpp/config.sed ================================================ /^SHELL/s,/bin/sh,$(COMSPEC), ;s%/bin/rm%rm% ;s%|| true%% ;/\/dev\/null/ { ;s,/dev/null 2>&1, nul, ;s,2> /dev/null,, ;} ;/^config.status/ { ; N;N;N;N;N;d ;} :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s,@srcdir@,.,g;t t s,@top_srcdir@,..,;t t s,@PATH_SEPARATOR@,:,;t t s,@PACKAGE_NAME@,,;t t s,@PACKAGE_TARNAME@,,;t t s,@PACKAGE_VERSION@,,;t t s,@PACKAGE_STRING@,,;t t s,@PACKAGE_BUGREPORT@,,;t t s,@exec_prefix@,${prefix},;t t s,@prefix@,/dev/env/DJDIR,;t t s%@program_transform_name@%s,^,,%;t t s,@bindir@,${exec_prefix}/bin,;t t s,@sbindir@,${exec_prefix}/sbin,;t t s,@libexecdir@,${exec_prefix}/libexec,;t t s,@datadir@,${prefix}/share,;t t s,@sysconfdir@,${prefix}/etc,;t t s,@sharedstatedir@,${prefix}/com,;t t s,@localstatedir@,${prefix}/var,;t t s,@libdir@,${exec_prefix}/lib,;t t s,@includedir@,${prefix}/include,;t t s,@oldincludedir@,/usr/include,;t t s,@infodir@,${prefix}/info,;t t s,@mandir@,${prefix}/man,;t t s,@build_alias@,i586-pc-msdosdjgpp,;t t s,@host_alias@,i586-pc-msdosdjgpp,;t t s,@target_alias@,i386-msdosdjgpp,;t t s,@DEFS@,,;t t s,@ECHO_C@,,;t t s,@ECHO_N@,-n,;t t s,@ECHO_T@,,;t t s,@LIBS@,-lm ,;t t s,@MAJOR@,1,;t t s,@MINOR@,7,;t t s,@TEENY@,3,;t t s,@build@,i586-pc-msdosdjgpp,;t t s,@build_cpu@,i586,;t t s,@build_vendor@,pc,;t t s,@build_os@,msdosdjgpp,;t t s,@host@,i586-pc-msdosdjgpp,;t t s,@host_cpu@,i586,;t t s,@host_vendor@,pc,;t t s,@host_os@,msdosdjgpp,;t t s,@target@,i386-pc-msdosdjgpp,;t t s,@target_cpu@,i386,;t t s,@target_vendor@,pc,;t t s,@target_os@,msdosdjgpp,;t t s,@CC@,gcc,;t t s,@ac_ct_CC@,,;t t s,@CFLAGS@,-Os,;t t s,@LDFLAGS@,,;t t s,@CPPFLAGS@,,;t t s,@EXEEXT@,.exe,;t t s,@OBJEXT@,o,;t t s,@CPP@,gcc -E,;t t s,@EGREP@,grep -E,;t t s,@GNU_LD@,yes,;t t s,@CPPOUTFILE@,-o conftest.i,;t t s,@OUTFLAG@,-o ,;t t s,@YACC@,bison -y,;t t s,@RANLIB@,ranlib,;t t s,@ac_ct_RANLIB@,,;t t s,@AR@,ar,;t t s,@ac_ct_AR@,,;t t s,@NM@,,;t t s,@ac_ct_NM@,,;t t s,@WINDRES@,,;t t s,@ac_ct_WINDRES@,,;t t s,@DLLWRAP@,,;t t s,@ac_ct_DLLWRAP@,,;t t s,@LN_S@,ln -s,;t t s,@SET_MAKE@,,;t t s,@LIBOBJS@,crypt.o flock.o vsnprintf.o,;t t s,@ALLOCA@,,;t t s,@XCFLAGS@,,;t t s,@XLDFLAGS@, -L.,;t t s,@DLDFLAGS@,,;t t s,@STATIC@,,;t t s,@CCDLFLAGS@,,;t t s,@LDSHARED@,ld,;t t s,@DLEXT@,so,;t t s,@DLEXT2@,,;t t s,@LIBEXT@,a,;t t s,@LINK_SO@,,;t t s,@LIBPATHFLAG@, -L%s,;t t s,@STRIP@,strip,;t t s,@EXTSTATIC@,,;t t s,@setup@,Setup.dj,;t t s,@MINIRUBY@,./miniruby,;t t s,@PREP@,,;t t s,@ARCHFILE@,,;t t s,@LIBRUBY_LDSHARED@,ld,;t t s,@LIBRUBY_DLDFLAGS@,,;t t s,@RUBY_INSTALL_NAME@,ruby,;t t s,@rubyw_install_name@,,;t t s,@RUBYW_INSTALL_NAME@,,;t t s,@RUBY_SO_NAME@,$(RUBY_INSTALL_NAME),;t t s,@LIBRUBY_A@,lib$(RUBY_INSTALL_NAME).a,;t t s,@LIBRUBY_SO@,lib$(RUBY_SO_NAME).so.$(MAJOR).$(MINOR).$(TEENY),;t t s,@LIBRUBY_ALIASES@,lib$(RUBY_SO_NAME).so,;t t s,@LIBRUBY@,$(LIBRUBY_A),;t t s,@LIBRUBYARG@,-l$(RUBY_INSTALL_NAME),;t t s,@SOLIBS@,,;t t s,@DLDLIBS@,-lc,;t t s,@ENABLE_SHARED@,no,;t t s,@MAINLIBS@,,;t t s,@COMMON_LIBS@,,;t t s,@COMMON_MACROS@,,;t t s,@COMMON_HEADERS@,,;t t s,@EXPORT_PREFIX@,,;t t s,@MAKEFILES@,Makefile,;t t s,@arch@,i386-msdosdjgpp,;t t s,@sitearch@,i386-msdosdjgpp,;t t s,@sitedir@,${prefix}/lib/ruby/site_ruby,;t t s,@configure_args@,,;t t /^,THIS_IS_DUMMY_PATTERN_/i\ ac_given_srcdir=. ================================================ FILE: djgpp/configure.bat ================================================ @echo off if exist configure.bat cd .. if exist djgpp\version.sed goto exist sed -n -f djgpp\mkver.sed < version.h > djgpp\version.sed :exist set _conv_=-f djgpp\config.sed -f djgpp\version.sed sed %_conv_% < Makefile.in > Makefile sed %_conv_% < djgpp\config.hin > config.h echo LFN check > 12345678 sed -n /LFN/d 123456789 > nul if errorlevel 2 goto LFN copy missing\vsnprintf.c missing\vsnprint.c > nul copy djgpp\config.sed config.sta > nul goto end :LFN copy djgpp\config.sed config.status > nul :end set _conv_= del 12345678 echo Now you must run a make. ================================================ FILE: djgpp/mkver.sed ================================================ /RUBY_VERSION /s/^.*\([0-9][0-9]*\)\.\([0-9][0-9]*\)\.\([0-9][0-9]*\).*$/s,@MAJOR@,\1,;s,@MINOR@,\2,;s,@TEENY@,\3,/p ================================================ FILE: dln.c ================================================ /********************************************************************** dln.c - $Author$ $Date$ created at: Tue Jan 18 17:05:06 JST 1994 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #include "ruby.h" #include "dln.h" #ifdef HAVE_STDLIB_H # include #endif #ifdef __CHECKER__ #undef HAVE_DLOPEN #undef USE_DLN_A_OUT #undef USE_DLN_DLOPEN #endif #ifdef USE_DLN_A_OUT char *dln_argv0; #endif #if defined(HAVE_ALLOCA_H) #include #endif #ifdef HAVE_STRING_H # include #else # include #endif #ifndef xmalloc void *xmalloc(); void *xcalloc(); void *xrealloc(); #endif #include #if defined(_WIN32) || defined(__VMS) #include "missing/file.h" #endif #include #include #ifndef S_ISDIR # define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) #endif #ifdef HAVE_SYS_PARAM_H # include #endif #ifndef MAXPATHLEN # define MAXPATHLEN 1024 #endif #ifdef HAVE_UNISTD_H # include #endif #ifndef _WIN32 char *getenv(); #endif #if defined(__VMS) #pragma builtins #include #endif #ifdef __MACOS__ # include # include # include # include "macruby_private.h" #endif #if defined(__APPLE__) && defined(__MACH__) /* Mac OS X */ # if defined(HAVE_DLOPEN) /* Mac OS X with dlopen (10.3 or later) */ # define MACOSX_DLOPEN # else # define MACOSX_DYLD # endif #endif #ifdef __BEOS__ # include #endif #ifndef NO_DLN_LOAD #if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX) && !defined(MACOSX_DYLD) && !defined(_UNICOSMP) /* dynamic load with dlopen() */ # define USE_DLN_DLOPEN #endif #ifndef FUNCNAME_PATTERN # if defined(__hp9000s300) || (defined(__NetBSD__) && !defined(__ELF__)) || defined(__BORLANDC__) || (defined(__FreeBSD__) && !defined(__ELF__)) || (defined(__OpenBSD__) && !defined(__ELF__)) || defined(NeXT) || defined(__WATCOMC__) || defined(MACOSX_DYLD) # define FUNCNAME_PATTERN "_Init_%s" # else # define FUNCNAME_PATTERN "Init_%s" # endif #endif static int init_funcname_len(buf, file) char **buf; const char *file; { char *p; const char *slash; int len; /* Load the file as an object one */ for (slash = file-1; *file; file++) /* Find position of last '/' */ #ifdef __MACOS__ if (*file == ':') slash = file; #else if (*file == '/') slash = file; #endif len = strlen(FUNCNAME_PATTERN) + strlen(slash + 1); *buf = xmalloc(len); snprintf(*buf, len, FUNCNAME_PATTERN, slash + 1); for (p = *buf; *p; p++) { /* Delete suffix if it exists */ if (*p == '.') { *p = '\0'; break; } } return p - *buf; } #define init_funcname(buf, file) do {\ int len = init_funcname_len(buf, file);\ char *tmp = ALLOCA_N(char, len+1);\ if (!tmp) {\ free(*buf);\ rb_memerror();\ }\ strcpy(tmp, *buf);\ free(*buf);\ *buf = tmp;\ } while (0) #ifdef USE_DLN_A_OUT #ifndef LIBC_NAME # define LIBC_NAME "libc.a" #endif #ifndef DLN_DEFAULT_LIB_PATH # define DLN_DEFAULT_LIB_PATH "/lib:/usr/lib:/usr/local/lib:." #endif #include static int dln_errno; #define DLN_ENOEXEC ENOEXEC /* Exec format error */ #define DLN_ECONFL 1201 /* Symbol name conflict */ #define DLN_ENOINIT 1202 /* No initializer given */ #define DLN_EUNDEF 1203 /* Undefine symbol remains */ #define DLN_ENOTLIB 1204 /* Not a library file */ #define DLN_EBADLIB 1205 /* Malformed library file */ #define DLN_EINIT 1206 /* Not initialized */ static int dln_init_p = 0; #include #include #ifndef N_COMM # define N_COMM 0x12 #endif #ifndef N_MAGIC # define N_MAGIC(x) (x).a_magic #endif #define INVALID_OBJECT(h) (N_MAGIC(h) != OMAGIC) #include "util.h" #include "st.h" static st_table *sym_tbl; static st_table *undef_tbl; static int load_lib(); static int load_header(fd, hdrp, disp) int fd; struct exec *hdrp; long disp; { int size; lseek(fd, disp, 0); size = read(fd, hdrp, sizeof(struct exec)); if (size == -1) { dln_errno = errno; return -1; } if (size != sizeof(struct exec) || N_BADMAG(*hdrp)) { dln_errno = DLN_ENOEXEC; return -1; } return 0; } #if defined(sequent) #define RELOC_SYMBOL(r) ((r)->r_symbolnum) #define RELOC_MEMORY_SUB_P(r) ((r)->r_bsr) #define RELOC_PCREL_P(r) ((r)->r_pcrel || (r)->r_bsr) #define RELOC_TARGET_SIZE(r) ((r)->r_length) #endif /* Default macros */ #ifndef RELOC_ADDRESS #define RELOC_ADDRESS(r) ((r)->r_address) #define RELOC_EXTERN_P(r) ((r)->r_extern) #define RELOC_SYMBOL(r) ((r)->r_symbolnum) #define RELOC_MEMORY_SUB_P(r) 0 #define RELOC_PCREL_P(r) ((r)->r_pcrel) #define RELOC_TARGET_SIZE(r) ((r)->r_length) #endif #if defined(sun) && defined(sparc) /* Sparc (Sun 4) macros */ # undef relocation_info # define relocation_info reloc_info_sparc # define R_RIGHTSHIFT(r) (reloc_r_rightshift[(r)->r_type]) # define R_BITSIZE(r) (reloc_r_bitsize[(r)->r_type]) # define R_LENGTH(r) (reloc_r_length[(r)->r_type]) static int reloc_r_rightshift[] = { 0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0, }; static int reloc_r_bitsize[] = { 8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16, }; static int reloc_r_length[] = { 0, 1, 2, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, }; # define R_PCREL(r) \ ((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22) # define R_SYMBOL(r) ((r)->r_index) #endif #if defined(sequent) #define R_SYMBOL(r) ((r)->r_symbolnum) #define R_MEMORY_SUB(r) ((r)->r_bsr) #define R_PCREL(r) ((r)->r_pcrel || (r)->r_bsr) #define R_LENGTH(r) ((r)->r_length) #endif #ifndef R_SYMBOL # define R_SYMBOL(r) ((r)->r_symbolnum) # define R_MEMORY_SUB(r) 0 # define R_PCREL(r) ((r)->r_pcrel) # define R_LENGTH(r) ((r)->r_length) #endif static struct relocation_info * load_reloc(fd, hdrp, disp) int fd; struct exec *hdrp; long disp; { struct relocation_info *reloc; int size; lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0); size = hdrp->a_trsize + hdrp->a_drsize; reloc = (struct relocation_info*)xmalloc(size); if (reloc == NULL) { dln_errno = errno; return NULL; } if (read(fd, reloc, size) != size) { dln_errno = errno; free(reloc); return NULL; } return reloc; } static struct nlist * load_sym(fd, hdrp, disp) int fd; struct exec *hdrp; long disp; { struct nlist * buffer; struct nlist * sym; struct nlist * end; long displ; int size; lseek(fd, N_SYMOFF(*hdrp) + hdrp->a_syms + disp, 0); if (read(fd, &size, sizeof(int)) != sizeof(int)) { goto err_noexec; } buffer = (struct nlist*)xmalloc(hdrp->a_syms + size); if (buffer == NULL) { dln_errno = errno; return NULL; } lseek(fd, disp + N_SYMOFF(*hdrp), 0); if (read(fd, buffer, hdrp->a_syms + size) != hdrp->a_syms + size) { free(buffer); goto err_noexec; } sym = buffer; end = sym + hdrp->a_syms / sizeof(struct nlist); displ = (long)buffer + (long)(hdrp->a_syms); while (sym < end) { sym->n_un.n_name = (char*)sym->n_un.n_strx + displ; sym++; } return buffer; err_noexec: dln_errno = DLN_ENOEXEC; return NULL; } static st_table * sym_hash(hdrp, syms) struct exec *hdrp; struct nlist *syms; { st_table *tbl; struct nlist *sym = syms; struct nlist *end = syms + (hdrp->a_syms / sizeof(struct nlist)); tbl = st_init_strtable(); if (tbl == NULL) { dln_errno = errno; return NULL; } while (sym < end) { st_insert(tbl, sym->n_un.n_name, sym); sym++; } return tbl; } static int dln_init(prog) const char *prog; { char *file; int fd; struct exec hdr; struct nlist *syms; if (dln_init_p == 1) return 0; file = dln_find_exe(prog, NULL); if (file == NULL || (fd = open(file, O_RDONLY)) < 0) { dln_errno = errno; return -1; } if (load_header(fd, &hdr, 0) == -1) return -1; syms = load_sym(fd, &hdr, 0); if (syms == NULL) { close(fd); return -1; } sym_tbl = sym_hash(&hdr, syms); if (sym_tbl == NULL) { /* file may be start with #! */ char c = '\0'; char buf[MAXPATHLEN]; char *p; free(syms); lseek(fd, 0L, 0); if (read(fd, &c, 1) == -1) { dln_errno = errno; return -1; } if (c != '#') goto err_noexec; if (read(fd, &c, 1) == -1) { dln_errno = errno; return -1; } if (c != '!') goto err_noexec; p = buf; /* skip forwarding spaces */ while (read(fd, &c, 1) == 1) { if (c == '\n') goto err_noexec; if (c != '\t' && c != ' ') { *p++ = c; break; } } /* read in command name */ while (read(fd, p, 1) == 1) { if (*p == '\n' || *p == '\t' || *p == ' ') break; p++; if (p-buf >= MAXPATHLEN) { dln_errno = ENAMETOOLONG; return -1; } } *p = '\0'; return dln_init(buf); } dln_init_p = 1; undef_tbl = st_init_strtable(); close(fd); return 0; err_noexec: close(fd); dln_errno = DLN_ENOEXEC; return -1; } static long load_text_data(fd, hdrp, bss, disp) int fd; struct exec *hdrp; int bss; long disp; { int size; unsigned char* addr; lseek(fd, disp + N_TXTOFF(*hdrp), 0); size = hdrp->a_text + hdrp->a_data; if (bss == -1) size += hdrp->a_bss; else if (bss > 1) size += bss; addr = (unsigned char*)xmalloc(size); if (addr == NULL) { dln_errno = errno; return 0; } if (read(fd, addr, size) != size) { dln_errno = errno; free(addr); return 0; } if (bss == -1) { memset(addr + hdrp->a_text + hdrp->a_data, 0, hdrp->a_bss); } else if (bss > 0) { memset(addr + hdrp->a_text + hdrp->a_data, 0, bss); } return (long)addr; } static int undef_print(key, value) char *key, *value; { fprintf(stderr, " %s\n", key); return ST_CONTINUE; } static void dln_print_undef() { fprintf(stderr, " Undefined symbols:\n"); st_foreach(undef_tbl, undef_print, NULL); } static void dln_undefined() { if (undef_tbl->num_entries > 0) { fprintf(stderr, "dln: Calling undefined function\n"); dln_print_undef(); rb_exit(1); } } struct undef { char *name; struct relocation_info reloc; long base; char *addr; union { char c; short s; long l; } u; }; static st_table *reloc_tbl = NULL; static void link_undef(name, base, reloc) const char *name; long base; struct relocation_info *reloc; { static int u_no = 0; struct undef *obj; char *addr = (char*)(reloc->r_address + base); obj = (struct undef*)xmalloc(sizeof(struct undef)); obj->name = strdup(name); obj->reloc = *reloc; obj->base = base; switch (R_LENGTH(reloc)) { case 0: /* byte */ obj->u.c = *addr; break; case 1: /* word */ obj->u.s = *(short*)addr; break; case 2: /* long */ obj->u.l = *(long*)addr; break; } if (reloc_tbl == NULL) { reloc_tbl = st_init_numtable(); } st_insert(reloc_tbl, u_no++, obj); } struct reloc_arg { const char *name; long value; }; static int reloc_undef(no, undef, arg) int no; struct undef *undef; struct reloc_arg *arg; { int datum; char *address; #if defined(sun) && defined(sparc) unsigned int mask = 0; #endif if (strcmp(arg->name, undef->name) != 0) return ST_CONTINUE; address = (char*)(undef->base + undef->reloc.r_address); datum = arg->value; if (R_PCREL(&(undef->reloc))) datum -= undef->base; #if defined(sun) && defined(sparc) datum += undef->reloc.r_addend; datum >>= R_RIGHTSHIFT(&(undef->reloc)); mask = (1 << R_BITSIZE(&(undef->reloc))) - 1; mask |= mask -1; datum &= mask; switch (R_LENGTH(&(undef->reloc))) { case 0: *address = undef->u.c; *address &= ~mask; *address |= datum; break; case 1: *(short *)address = undef->u.s; *(short *)address &= ~mask; *(short *)address |= datum; break; case 2: *(long *)address = undef->u.l; *(long *)address &= ~mask; *(long *)address |= datum; break; } #else switch (R_LENGTH(&(undef->reloc))) { case 0: /* byte */ if (R_MEMORY_SUB(&(undef->reloc))) *address = datum - *address; else *address = undef->u.c + datum; break; case 1: /* word */ if (R_MEMORY_SUB(&(undef->reloc))) *(short*)address = datum - *(short*)address; else *(short*)address = undef->u.s + datum; break; case 2: /* long */ if (R_MEMORY_SUB(&(undef->reloc))) *(long*)address = datum - *(long*)address; else *(long*)address = undef->u.l + datum; break; } #endif free(undef->name); free(undef); return ST_DELETE; } static void unlink_undef(name, value) const char *name; long value; { struct reloc_arg arg; arg.name = name; arg.value = value; st_foreach(reloc_tbl, reloc_undef, &arg); } #ifdef N_INDR struct indr_data { char *name0, *name1; }; static int reloc_repl(no, undef, data) int no; struct undef *undef; struct indr_data *data; { if (strcmp(data->name0, undef->name) == 0) { free(undef->name); undef->name = strdup(data->name1); } return ST_CONTINUE; } #endif static int load_1(fd, disp, need_init) int fd; long disp; const char *need_init; { static const char *libc = LIBC_NAME; struct exec hdr; struct relocation_info *reloc = NULL; long block = 0; long new_common = 0; /* Length of new common */ struct nlist *syms = NULL; struct nlist *sym; struct nlist *end; int init_p = 0; if (load_header(fd, &hdr, disp) == -1) return -1; if (INVALID_OBJECT(hdr)) { dln_errno = DLN_ENOEXEC; return -1; } reloc = load_reloc(fd, &hdr, disp); if (reloc == NULL) return -1; syms = load_sym(fd, &hdr, disp); if (syms == NULL) { free(reloc); return -1; } sym = syms; end = syms + (hdr.a_syms / sizeof(struct nlist)); while (sym < end) { struct nlist *old_sym; int value = sym->n_value; #ifdef N_INDR if (sym->n_type == (N_INDR | N_EXT)) { char *key = sym->n_un.n_name; if (st_lookup(sym_tbl, sym[1].n_un.n_name, &old_sym)) { if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) { unlink_undef(key, old_sym->n_value); free(key); } } else { struct indr_data data; data.name0 = sym->n_un.n_name; data.name1 = sym[1].n_un.n_name; st_foreach(reloc_tbl, reloc_repl, &data); st_insert(undef_tbl, strdup(sym[1].n_un.n_name), NULL); if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) { free(key); } } sym += 2; continue; } #endif if (sym->n_type == (N_UNDF | N_EXT)) { if (st_lookup(sym_tbl, sym->n_un.n_name, &old_sym) == 0) { old_sym = NULL; } if (value) { if (old_sym) { sym->n_type = N_EXT | N_COMM; sym->n_value = old_sym->n_value; } else { int rnd = value >= sizeof(double) ? sizeof(double) - 1 : value >= sizeof(long) ? sizeof(long) - 1 : sizeof(short) - 1; sym->n_type = N_COMM; new_common += rnd; new_common &= ~(long)rnd; sym->n_value = new_common; new_common += value; } } else { if (old_sym) { sym->n_type = N_EXT | N_COMM; sym->n_value = old_sym->n_value; } else { sym->n_value = (long)dln_undefined; st_insert(undef_tbl, strdup(sym->n_un.n_name), NULL); } } } sym++; } block = load_text_data(fd, &hdr, hdr.a_bss + new_common, disp); if (block == 0) goto err_exit; sym = syms; while (sym < end) { struct nlist *new_sym; char *key; switch (sym->n_type) { case N_COMM: sym->n_value += hdr.a_text + hdr.a_data; case N_TEXT|N_EXT: case N_DATA|N_EXT: sym->n_value += block; if (st_lookup(sym_tbl, sym->n_un.n_name, &new_sym) != 0 && new_sym->n_value != (long)dln_undefined) { dln_errno = DLN_ECONFL; goto err_exit; } key = sym->n_un.n_name; if (st_delete(undef_tbl, (st_data_t*)&key, NULL) != 0) { unlink_undef(key, sym->n_value); free(key); } new_sym = (struct nlist*)xmalloc(sizeof(struct nlist)); *new_sym = *sym; new_sym->n_un.n_name = strdup(sym->n_un.n_name); st_insert(sym_tbl, new_sym->n_un.n_name, new_sym); break; case N_TEXT: case N_DATA: sym->n_value += block; break; } sym++; } /* * First comes the text-relocation */ { struct relocation_info * rel = reloc; struct relocation_info * rel_beg = reloc + (hdr.a_trsize/sizeof(struct relocation_info)); struct relocation_info * rel_end = reloc + (hdr.a_trsize+hdr.a_drsize)/sizeof(struct relocation_info); while (rel < rel_end) { char *address = (char*)(rel->r_address + block); long datum = 0; #if defined(sun) && defined(sparc) unsigned int mask = 0; #endif if(rel >= rel_beg) address += hdr.a_text; if (rel->r_extern) { /* Look it up in symbol-table */ sym = &(syms[R_SYMBOL(rel)]); switch (sym->n_type) { case N_EXT|N_UNDF: link_undef(sym->n_un.n_name, block, rel); case N_EXT|N_COMM: case N_COMM: datum = sym->n_value; break; default: goto err_exit; } } /* end.. look it up */ else { /* is static */ switch (R_SYMBOL(rel)) { case N_TEXT: case N_DATA: datum = block; break; case N_BSS: datum = block + new_common; break; case N_ABS: break; } } /* end .. is static */ if (R_PCREL(rel)) datum -= block; #if defined(sun) && defined(sparc) datum += rel->r_addend; datum >>= R_RIGHTSHIFT(rel); mask = (1 << R_BITSIZE(rel)) - 1; mask |= mask -1; datum &= mask; switch (R_LENGTH(rel)) { case 0: *address &= ~mask; *address |= datum; break; case 1: *(short *)address &= ~mask; *(short *)address |= datum; break; case 2: *(long *)address &= ~mask; *(long *)address |= datum; break; } #else switch (R_LENGTH(rel)) { case 0: /* byte */ if (datum < -128 || datum > 127) goto err_exit; *address += datum; break; case 1: /* word */ *(short *)address += datum; break; case 2: /* long */ *(long *)address += datum; break; } #endif rel++; } } if (need_init) { int len; char **libs_to_be_linked = 0; char *buf; if (undef_tbl->num_entries > 0) { if (load_lib(libc) == -1) goto err_exit; } init_funcname(&buf, need_init); len = strlen(buf); for (sym = syms; symn_un.n_name; if (name[0] == '_' && sym->n_value >= block) { if (strcmp(name+1, "dln_libs_to_be_linked") == 0) { libs_to_be_linked = (char**)sym->n_value; } else if (strcmp(name+1, buf) == 0) { init_p = 1; ((int (*)())sym->n_value)(); } } } if (libs_to_be_linked && undef_tbl->num_entries > 0) { while (*libs_to_be_linked) { load_lib(*libs_to_be_linked); libs_to_be_linked++; } } } free(reloc); free(syms); if (need_init) { if (init_p == 0) { dln_errno = DLN_ENOINIT; return -1; } if (undef_tbl->num_entries > 0) { if (load_lib(libc) == -1) goto err_exit; if (undef_tbl->num_entries > 0) { dln_errno = DLN_EUNDEF; return -1; } } } return 0; err_exit: if (syms) free(syms); if (reloc) free(reloc); if (block) free((char*)block); return -1; } static int target_offset; static int search_undef(key, value, lib_tbl) const char *key; int value; st_table *lib_tbl; { long offset; if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE; target_offset = offset; return ST_STOP; } struct symdef { int rb_str_index; int lib_offset; }; char *dln_librrb_ary_path = DLN_DEFAULT_LIB_PATH; static int load_lib(lib) const char *lib; { char *path, *file; char armagic[SARMAG]; int fd, size; struct ar_hdr ahdr; st_table *lib_tbl = NULL; int *data, nsym; struct symdef *base; char *name_base; if (dln_init_p == 0) { dln_errno = DLN_ENOINIT; return -1; } if (undef_tbl->num_entries == 0) return 0; dln_errno = DLN_EBADLIB; if (lib[0] == '-' && lib[1] == 'l') { long len = strlen(lib) + 4; char *p = alloca(len); snprintf(p, len, "lib%s.a", lib+2); lib = p; } /* library search path: */ /* look for environment variable DLN_LIBRARY_PATH first. */ /* then variable dln_librrb_ary_path. */ /* if path is still NULL, use "." for path. */ path = getenv("DLN_LIBRARY_PATH"); if (path == NULL) path = dln_librrb_ary_path; file = dln_find_file(lib, path); fd = open(file, O_RDONLY); if (fd == -1) goto syserr; size = read(fd, armagic, SARMAG); if (size == -1) goto syserr; if (size != SARMAG) { dln_errno = DLN_ENOTLIB; goto badlib; } size = read(fd, &ahdr, sizeof(ahdr)); if (size == -1) goto syserr; if (size != sizeof(ahdr) || sscanf(ahdr.ar_size, "%d", &size) != 1) { goto badlib; } if (strncmp(ahdr.ar_name, "__.SYMDEF", 9) == 0) { /* make hash table from __.SYMDEF */ lib_tbl = st_init_strtable(); data = (int*)xmalloc(size); if (data == NULL) goto syserr; size = read(fd, data, size); nsym = *data / sizeof(struct symdef); base = (struct symdef*)(data + 1); name_base = (char*)(base + nsym) + sizeof(int); while (nsym > 0) { char *name = name_base + base->rb_str_index; st_insert(lib_tbl, name, base->lib_offset + sizeof(ahdr)); nsym--; base++; } for (;;) { target_offset = -1; st_foreach(undef_tbl, search_undef, lib_tbl); if (target_offset == -1) break; if (load_1(fd, target_offset, 0) == -1) { st_free_table(lib_tbl); free(data); goto badlib; } if (undef_tbl->num_entries == 0) break; } free(data); st_free_table(lib_tbl); } else { /* linear library, need to scan (FUTURE) */ for (;;) { int offset = SARMAG; int found = 0; struct exec hdr; struct nlist *syms, *sym, *end; while (undef_tbl->num_entries > 0) { found = 0; lseek(fd, offset, 0); size = read(fd, &ahdr, sizeof(ahdr)); if (size == -1) goto syserr; if (size == 0) break; if (size != sizeof(ahdr) || sscanf(ahdr.ar_size, "%d", &size) != 1) { goto badlib; } offset += sizeof(ahdr); if (load_header(fd, &hdr, offset) == -1) goto badlib; syms = load_sym(fd, &hdr, offset); if (syms == NULL) goto badlib; sym = syms; end = syms + (hdr.a_syms / sizeof(struct nlist)); while (sym < end) { if (sym->n_type == N_EXT|N_TEXT && st_lookup(undef_tbl, sym->n_un.n_name, NULL)) { break; } sym++; } if (sym < end) { found++; free(syms); if (load_1(fd, offset, 0) == -1) { goto badlib; } } offset += size; if (offset & 1) offset++; } if (found) break; } } close(fd); return 0; syserr: dln_errno = errno; badlib: if (fd >= 0) close(fd); return -1; } static int load(file) const char *file; { int fd; int result; if (dln_init_p == 0) { if (dln_init(dln_argv0) == -1) return -1; } result = strlen(file); if (file[result-1] == 'a') { return load_lib(file); } fd = open(file, O_RDONLY); if (fd == -1) { dln_errno = errno; return -1; } result = load_1(fd, 0, file); close(fd); return result; } void* dln_sym(name) const char *name; { struct nlist *sym; if (st_lookup(sym_tbl, name, &sym)) return (void*)sym->n_value; return NULL; } #endif /* USE_DLN_A_OUT */ #ifdef USE_DLN_DLOPEN # if defined(__NetBSD__) && defined(__NetBSD_Version__) && __NetBSD_Version__ < 105000000 # include # include # else # include # endif #endif #ifdef __hpux #include #include "dl.h" #endif #if defined(_AIX) #include /* for isdigit() */ #include /* for global errno */ #include #endif #ifdef NeXT #if NS_TARGET_MAJOR < 4 #include #else #include #ifndef NSLINKMODULE_OPTION_BINDNOW #define NSLINKMODULE_OPTION_BINDNOW 1 #endif #endif #else #ifdef MACOSX_DYLD #include #endif #endif #if defined _WIN32 && !defined __CYGWIN__ #include #endif #ifdef _WIN32_WCE #undef FormatMessage #define FormatMessage FormatMessageA #undef LoadLibrary #define LoadLibrary LoadLibraryA #undef GetProcAddress #define GetProcAddress GetProcAddressA #endif static const char * dln_strerror() { #ifdef USE_DLN_A_OUT char *strerror(); switch (dln_errno) { case DLN_ECONFL: return "Symbol name conflict"; case DLN_ENOINIT: return "No initializer given"; case DLN_EUNDEF: return "Unresolved symbols"; case DLN_ENOTLIB: return "Not a library file"; case DLN_EBADLIB: return "Malformed library file"; case DLN_EINIT: return "Not initialized"; default: return strerror(dln_errno); } #endif #ifdef USE_DLN_DLOPEN return (char*)dlerror(); #endif #if defined _WIN32 && !defined __CYGWIN__ static char message[1024]; int error = GetLastError(); char *p = message; p += sprintf(message, "%d: ", error); FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), p, sizeof message - strlen(message), NULL); for (p = message; *p; p++) { if (*p == '\n' || *p == '\r') *p = ' '; } return message; #endif } #if defined(_AIX) && ! defined(_IA64) static void aix_loaderror(const char *pathname) { char *message[8], errbuf[1024]; int i,j; struct errtab { int errnum; char *errstr; } load_errtab[] = { {L_ERROR_TOOMANY, "too many errors, rest skipped."}, {L_ERROR_NOLIB, "can't load library:"}, {L_ERROR_UNDEF, "can't find symbol in library:"}, {L_ERROR_RLDBAD, "RLD index out of range or bad relocation type:"}, {L_ERROR_FORMAT, "not a valid, executable xcoff file:"}, {L_ERROR_MEMBER, "file not an archive or does not contain requested member:"}, {L_ERROR_TYPE, "symbol table mismatch:"}, {L_ERROR_ALIGN, "text alignment in file is wrong."}, {L_ERROR_SYSTEM, "System error:"}, {L_ERROR_ERRNO, NULL} }; #define LOAD_ERRTAB_LEN (sizeof(load_errtab)/sizeof(load_errtab[0])) #define ERRBUF_APPEND(s) strncat(errbuf, s, sizeof(errbuf)-strlen(errbuf)-1) snprintf(errbuf, 1024, "load failed - %s ", pathname); if (!loadquery(1, &message[0], sizeof(message))) ERRBUF_APPEND(strerror(errno)); for(i = 0; message[i] && *message[i]; i++) { int nerr = atoi(message[i]); for (j=0; j #include #include #include #include #include static char *vms_filespec; static int vms_fileact(char *filespec, int type); static long vms_fisexh(long *sigarr, long *mecarr); #endif #endif /* NO_DLN_LOAD */ void* dln_load(file) const char *file; { #ifdef NO_DLN_LOAD rb_raise(rb_eLoadError, "this executable file can't load extension libraries"); #else #if !defined(_AIX) && !defined(NeXT) const char *error = 0; #define DLN_ERROR() (error = dln_strerror(), strcpy(ALLOCA_N(char, strlen(error) + 1), error)) #endif #if defined _WIN32 && !defined __CYGWIN__ HINSTANCE handle; char winfile[MAXPATHLEN]; void (*init_fct)(); char *buf; if (strlen(file) >= MAXPATHLEN) rb_loaderror("filename too long"); /* Load the file as an object one */ init_funcname(&buf, file); strcpy(winfile, file); /* Load file */ if ((handle = LoadLibrary(winfile)) == NULL) { error = dln_strerror(); goto failed; } if ((init_fct = (void(*)())GetProcAddress(handle, buf)) == NULL) { rb_loaderror("%s - %s\n%s", dln_strerror(), buf, file); } /* Call the init code */ (*init_fct)(); return handle; #else #ifdef USE_DLN_A_OUT if (load(file) == -1) { error = dln_strerror(); goto failed; } return 0; #else char *buf; /* Load the file as an object one */ init_funcname(&buf, file); #ifdef USE_DLN_DLOPEN #define DLN_DEFINED { void *handle; void (*init_fct)(); #ifndef RTLD_LAZY # define RTLD_LAZY 1 #endif #ifdef __INTERIX # undef RTLD_GLOBAL #endif #ifndef RTLD_GLOBAL # define RTLD_GLOBAL 0 #endif /* Load file */ if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) { error = dln_strerror(); goto failed; } init_fct = (void(*)())dlsym(handle, buf); if (init_fct == NULL) { error = DLN_ERROR(); dlclose(handle); goto failed; } /* Call the init code */ (*init_fct)(); return handle; } #endif /* USE_DLN_DLOPEN */ #ifdef __hpux #define DLN_DEFINED { shl_t lib = NULL; int flags; void (*init_fct)(); flags = BIND_DEFERRED; lib = shl_load(file, flags, 0); if (lib == NULL) { extern int errno; rb_loaderror("%s - %s", strerror(errno), file); } shl_findsym(&lib, buf, TYPE_PROCEDURE, (void*)&init_fct); if (init_fct == NULL) { shl_findsym(&lib, buf, TYPE_UNDEFINED, (void*)&init_fct); if (init_fct == NULL) { errno = ENOSYM; rb_loaderror("%s - %s", strerror(ENOSYM), file); } } (*init_fct)(); return (void*)lib; } #endif /* hpux */ #if defined(_AIX) && ! defined(_IA64) #define DLN_DEFINED { void (*init_fct)(); init_fct = (void(*)())load((char*)file, 1, 0); if (init_fct == NULL) { aix_loaderror(file); } if (loadbind(0, (void*)dln_load, (void*)init_fct) == -1) { aix_loaderror(file); } (*init_fct)(); return (void*)init_fct; } #endif /* _AIX */ #if defined(NeXT) || defined(MACOSX_DYLD) #define DLN_DEFINED /*---------------------------------------------------- By SHIROYAMA Takayuki Psi@fortune.nest.or.jp Special Thanks... Yu tomoak-i@is.aist-nara.ac.jp, Mi hisho@tasihara.nest.or.jp, sunshine@sunshineco.com, and... Miss ARAI Akino(^^;) ----------------------------------------------------*/ #if defined(NeXT) && (NS_TARGET_MAJOR < 4)/* NeXTSTEP rld functions */ { NXStream* s; unsigned long init_address; char *object_files[2] = {NULL, NULL}; void (*init_fct)(); object_files[0] = (char*)file; s = NXOpenFile(2,NX_WRITEONLY); /* Load object file, if return value ==0 , load failed*/ if(rld_load(s, NULL, object_files, NULL) == 0) { NXFlush(s); NXClose(s); rb_loaderror("Failed to load %.200s", file); } /* lookup the initial function */ if(rld_lookup(s, buf, &init_address) == 0) { NXFlush(s); NXClose(s); rb_loaderror("Failed to lookup Init function %.200s", file); } NXFlush(s); NXClose(s); /* Cannot call *init_address directory, so copy this value to funtion pointer */ init_fct = (void(*)())init_address; (*init_fct)(); return (void*)init_address; } #else/* OPENSTEP dyld functions */ { int dyld_result; NSObjectFileImage obj_file; /* handle, but not use it */ /* "file" is module file name . "buf" is pointer to initial function name with "_" . */ void (*init_fct)(); dyld_result = NSCreateObjectFileImageFromFile(file, &obj_file); if (dyld_result != NSObjectFileImageSuccess) { rb_loaderror("Failed to load %.200s", file); } NSLinkModule(obj_file, file, NSLINKMODULE_OPTION_BINDNOW); /* lookup the initial function */ if(!NSIsSymbolNameDefined(buf)) { rb_loaderror("Failed to lookup Init function %.200s",file); } init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf)); (*init_fct)(); return (void*)init_fct; } #endif /* rld or dyld */ #endif #ifdef __BEOS__ # define DLN_DEFINED { status_t err_stat; /* BeOS error status code */ image_id img_id; /* extention module unique id */ void (*init_fct)(); /* initialize function for extention module */ /* load extention module */ img_id = load_add_on(file); if (img_id <= 0) { rb_loaderror("Failed to load %.200s", file); } /* find symbol for module initialize function. */ /* The Be Book KernelKit Images section described to use B_SYMBOL_TYPE_TEXT for symbol of function, not B_SYMBOL_TYPE_CODE. Why ? */ /* strcat(init_fct_symname, "__Fv"); */ /* parameter nothing. */ /* "__Fv" dont need! The Be Book Bug ? */ err_stat = get_image_symbol(img_id, buf, B_SYMBOL_TYPE_TEXT, (void **)&init_fct); if (err_stat != B_NO_ERROR) { char real_name[MAXPATHLEN]; strcpy(real_name, buf); strcat(real_name, "__Fv"); err_stat = get_image_symbol(img_id, real_name, B_SYMBOL_TYPE_TEXT, (void **)&init_fct); } if ((B_BAD_IMAGE_ID == err_stat) || (B_BAD_INDEX == err_stat)) { unload_add_on(img_id); rb_loaderror("Failed to lookup Init function %.200s", file); } else if (B_NO_ERROR != err_stat) { char errmsg[] = "Internal of BeOS version. %.200s (symbol_name = %s)"; unload_add_on(img_id); rb_loaderror(errmsg, strerror(err_stat), buf); } /* call module initialize function. */ (*init_fct)(); return (void*)img_id; } #endif /* __BEOS__*/ #ifdef __MACOS__ /* Mac OS 9 or before */ # define DLN_DEFINED { OSErr err; FSSpec libspec; CFragConnectionID connID; Ptr mainAddr; char errMessage[1024]; Boolean isfolder, didsomething; Str63 fragname; Ptr symAddr; CFragSymbolClass class; void (*init_fct)(); char fullpath[MAXPATHLEN]; strcpy(fullpath, file); /* resolve any aliases to find the real file */ c2pstr(fullpath); (void)FSMakeFSSpec(0, 0, fullpath, &libspec); err = ResolveAliasFile(&libspec, 1, &isfolder, &didsomething); if (err) { rb_loaderror("Unresolved Alias - %s", file); } /* Load the fragment (or return the connID if it is already loaded */ fragname[0] = 0; err = GetDiskFragment(&libspec, 0, 0, fragname, kLoadCFrag, &connID, &mainAddr, errMessage); if (err) { p2cstr(errMessage); rb_loaderror("%s - %s",errMessage , file); } /* Locate the address of the correct init function */ c2pstr(buf); err = FindSymbol(connID, buf, &symAddr, &class); if (err) { rb_loaderror("Unresolved symbols - %s" , file); } init_fct = (void (*)())symAddr; (*init_fct)(); return (void*)init_fct; } #endif /* __MACOS__ */ #if defined(__VMS) #define DLN_DEFINED { long status; void (*init_fct)(); char *fname, *p1, *p2; $DESCRIPTOR(fname_d, ""); $DESCRIPTOR(image_d, ""); $DESCRIPTOR(buf_d, ""); decc$to_vms(file, vms_fileact, 0, 0); fname = (char *)__alloca(strlen(file)+1); strcpy(fname,file); if (p1 = strrchr(fname,'/')) fname = p1 + 1; if (p2 = strrchr(fname,'.')) *p2 = '\0'; fname_d.dsc$w_length = strlen(fname); fname_d.dsc$a_pointer = fname; image_d.dsc$w_length = strlen(vms_filespec); image_d.dsc$a_pointer = vms_filespec; buf_d.dsc$w_length = strlen(buf); buf_d.dsc$a_pointer = buf; lib$establish(vms_fisexh); status = lib$find_image_symbol ( &fname_d, &buf_d, &init_fct, &image_d); lib$establish(0); if (status == RMS$_FNF) { error = dln_strerror(); goto failed; } else if (!$VMS_STATUS_SUCCESS(status)) { error = DLN_ERROR(); goto failed; } /* Call the init code */ (*init_fct)(); return 1; } #endif /* __VMS */ #ifndef DLN_DEFINED rb_notimplement(); #endif #endif /* USE_DLN_A_OUT */ #endif #if !defined(_AIX) && !defined(NeXT) failed: rb_loaderror("%s - %s", error, file); #endif #endif /* NO_DLN_LOAD */ return 0; /* dummy return */ } static char *dln_find_1(); char * dln_find_exe(fname, path) const char *fname; const char *path; { if (!path) { path = getenv(PATH_ENV); } if (!path) { #if defined(MSDOS) || defined(_WIN32) || defined(__human68k__) || defined(__MACOS__) path = "/usr/local/bin;/usr/ucb;/usr/bin;/bin;."; #else path = "/usr/local/bin:/usr/ucb:/usr/bin:/bin:."; #endif } return dln_find_1(fname, path, 1); } char * dln_find_file(fname, path) const char *fname; const char *path; { #ifndef __MACOS__ if (!path) path = "."; return dln_find_1(fname, path, 0); #else if (!path) path = "."; return _macruby_path_conv_posix_to_macos(dln_find_1(fname, path, 0)); #endif } static char fbuf[MAXPATHLEN]; static char * dln_find_1(fname, path, exe_flag) const char *fname; const char *path; int exe_flag; /* non 0 if looking for executable. */ { register const char *dp; register const char *ep; register char *bp; struct stat st; #ifdef __MACOS__ const char* mac_fullpath; #endif if (!fname) return (char *)fname; if (fname[0] == '/') return (char *)fname; if (strncmp("./", fname, 2) == 0 || strncmp("../", fname, 3) == 0) return (char *)fname; if (exe_flag && strchr(fname, '/')) return (char *)fname; #ifdef DOSISH if (fname[0] == '\\') return (char *)fname; # ifdef DOSISH_DRIVE_LETTER if (strlen(fname) > 2 && fname[1] == ':') return (char *)fname; # endif if (strncmp(".\\", fname, 2) == 0 || strncmp("..\\", fname, 3) == 0) return (char *)fname; if (exe_flag && strchr(fname, '\\')) return (char *)fname; #endif for (dp = path;; dp = ++ep) { register int l; int i; int fspace; /* extract a component */ ep = strchr(dp, PATH_SEP[0]); if (ep == NULL) ep = dp+strlen(dp); /* find the length of that component */ l = ep - dp; bp = fbuf; fspace = sizeof fbuf - 2; if (l > 0) { /* ** If the length of the component is zero length, ** start from the current directory. If the ** component begins with "~", start from the ** user's $HOME environment variable. Otherwise ** take the path literally. */ if (*dp == '~' && (l == 1 || #if defined(DOSISH) dp[1] == '\\' || #endif dp[1] == '/')) { char *home; home = getenv("HOME"); if (home != NULL) { i = strlen(home); if ((fspace -= i) < 0) goto toolong; memcpy(bp, home, i); bp += i; } dp++; l--; } if (l > 0) { if ((fspace -= l) < 0) goto toolong; memcpy(bp, dp, l); bp += l; } /* add a "/" between directory and filename */ if (ep[-1] != '/') *bp++ = '/'; } /* now append the file name */ i = strlen(fname); if ((fspace -= i) < 0) { toolong: fprintf(stderr, "openpath: pathname too long (ignored)\n"); *bp = '\0'; fprintf(stderr, "\tDirectory \"%s\"\n", fbuf); fprintf(stderr, "\tFile \"%s\"\n", fname); goto next; } memcpy(bp, fname, i + 1); #if defined(DOSISH) if (exe_flag) { static const char extension[][5] = { #if defined(MSDOS) ".com", ".exe", ".bat", #if defined(DJGPP) ".btm", ".sh", ".ksh", ".pl", ".sed", #endif #elif defined(__EMX__) || defined(_WIN32) ".exe", ".com", ".cmd", ".bat", /* end of __EMX__ or _WIN32 */ #else ".r", ".R", ".x", ".X", ".bat", ".BAT", /* __human68k__ */ #endif }; int j; for (j = 0; j < sizeof(extension) / sizeof(extension[0]); j++) { if (fspace < strlen(extension[j])) { fprintf(stderr, "openpath: pathname too long (ignored)\n"); fprintf(stderr, "\tDirectory \"%.*s\"\n", (int) (bp - fbuf), fbuf); fprintf(stderr, "\tFile \"%s%s\"\n", fname, extension[j]); continue; } strcpy(bp + i, extension[j]); #ifndef __MACOS__ if (stat(fbuf, &st) == 0) return fbuf; #else if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf)) return mac_fullpath; #endif } goto next; } #endif /* MSDOS or _WIN32 or __human68k__ or __EMX__ */ #ifndef __MACOS__ if (stat(fbuf, &st) == 0) { if (exe_flag == 0) return fbuf; /* looking for executable */ if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0) return fbuf; } #else if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf)) { if (exe_flag == 0) return mac_fullpath; /* looking for executable */ if (stat(mac_fullpath, &st) == 0) { if (!S_ISDIR(st.st_mode) && eaccess(mac_fullpath, X_OK) == 0) return mac_fullpath; } } #endif next: /* if not, and no other alternatives, life is bleak */ if (*ep == '\0') { return NULL; } /* otherwise try the next component in the search path */ } } #if defined(__VMS) /* action routine for decc$to_vms */ static int vms_fileact(char *filespec, int type) { if (vms_filespec) free(vms_filespec); vms_filespec = malloc(strlen(filespec)+1); strcpy(vms_filespec, filespec); return 1; } /* exception handler for LIB$FIND_IMAGE_SYMBOL */ static long vms_fisexh(long *sigarr, long *mecarr) { sys$unwind(1, 0); return 1; } #endif /* __VMS */ ================================================ FILE: dln.h ================================================ /********************************************************************** dln.h - $Author$ $Date$ created at: Wed Jan 19 16:53:09 JST 1994 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #ifndef DLN_H #define DLN_H #ifdef __cplusplus # ifndef HAVE_PROTOTYPES # define HAVE_PROTOTYPES 1 # endif # ifndef HAVE_STDARG_PROTOTYPES # define HAVE_STDARG_PROTOTYPES 1 # endif #endif #undef _ #ifdef HAVE_PROTOTYPES # define _(args) args #else # define _(args) () #endif char *dln_find_exe _((const char*,const char*)); char *dln_find_file _((const char*,const char*)); #ifdef USE_DLN_A_OUT extern char *dln_argv0; #endif void *dln_load _((const char*)); #endif ================================================ FILE: dmydln.c ================================================ #define NO_DLN_LOAD 1 #include "dln.c" ================================================ FILE: dmyext.c ================================================ void Init_ext() { } ================================================ FILE: doc/ChangeLog-1.8.0 ================================================ Mon Aug 4 17:21:19 2003 Yukihiro Matsumoto * class.c (class_instance_method_list): methods defined in singleton class and extended modules should be included. [ruby-dev:21119] Mon Aug 4 13:05:57 2003 Yukihiro Matsumoto * eval.c (method_proc): should specify YIELD_FUNC_SVALUE. [ruby-dev:21107] * marshal.c (w_object): should not call w_extended for USRMARSHAL dump. [ruby-dev:21106] Mon Aug 4 10:42:00 2003 Nathaniel Talbott * lib/test/unit/ui/console/testrunner.rb: Flushed io in the Console::TestRunner so that it will output immediately. Mon Aug 4 10:27:22 2003 Nobuyoshi Nakada * util.h: remove unnecessary parentheses. [ruby-dev:20879] Mon Aug 4 10:00:47 2003 Shugo Maeda * lib/net/imap.rb (receive_responses): raise exception to client_thread. Thanks to William Webber. Mon Aug 4 09:22:53 2003 William Webber * lib/net/imap.rb: convert RD to RDoc. Mon Aug 4 02:34:05 2003 NAKAMURA Usaku * win32/win32.c (rb_w32_utime): never use utime() of C runtime. [ruby-talk:77782] Sun Aug 3 23:56:50 2003 Nobuyoshi Nakada * eval.c (rb_call_super): should propagate previous block for super call. [ruby-talk:77884] Sun Aug 3 22:07:47 2003 Hidetoshi NAGAI * ext/tk/lib/tkentry.rb: support 'validatecommand' option of TkEntry/TkSpinbox widget * ext/tk/sample/{demos-en,demos-jp}/spin.rb: add Sun Aug 3 19:25:28 2003 Nobuyoshi Nakada * eval.c (call_trace_func): clear exception flag temporarily. [ruby-dev:21090] Sun Aug 3 18:03:44 2003 WATANABE Hirofumi * regex.h (re_mbctab): should refer to RUBY_EXPORT. [ruby-ext:02199] * lib/un.h (help): new. % ruby -run -e help cp Sun Aug 3 08:53:06 2003 Hidetoshi NAGAI * ext/tk/sample/{demos-en,demos-jp}/image3.rb: add * ext/tk/lib/tkcanvas.rb: bug fix on Tk object ID management * ext/tk/lib/tktext.rb: ditto Sun Aug 3 02:55:52 2003 Hidetoshi NAGAI * process.c: modify macro to detect 'MacOS X' [ruby-talk:77849] * ext/tcltklib/lib/tcltk.rb: bug fix ( NOT MAINTAINED : only for running 'line2.rb' demo. ) Sun Aug 3 02:45:06 2003 Koji Arai * numeric.c (flo_to_s): get rid of buffer overflow. Sat Aug 2 23:51:52 2003 Yukihiro Matsumoto * io.c (appendline): clearerr(3) before raising exception, since exception may be captured by rescue. [ruby-talk:77794] Sat Aug 2 09:58:13 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: bug fix --- TkGrid failed to treat RELATIVE PLACEMENT * ext/tk/sample/demos-en/, demos-jp/: add or modify some widget demo scripts Sat Aug 2 20:59:38 2003 GOTOU Yuuzou * lib/webrick/https.rb: change an option name. :SSLCertStore -> :SSLCertificateStore. Sat Aug 2 19:18:40 2003 Minero Aoki * lib/net/smtp.rb: respond_to? needs 2nd argument. Thanks Jim Bob. [ruby-talk:77796] Sat Aug 2 15:11:54 2003 WATANABE Hirofumi * ext/extmk.rb (--no-undefined): annoying option removed. Sat Aug 2 14:53:55 2003 Nobuyoshi Nakada * lib/mkmf.rb (pkg_config): get configuration by pkg-config. [new] * ext/openssl/extconf.rb: use pkg_config. Sat Aug 2 13:45:17 2003 Yukihiro Matsumoto * gc.c: add "#pragma weak" for __libc_ia64_register_backing_store_base. [ruby-dev:21072] Sat Aug 2 14:02:39 2003 Nobuyoshi Nakada * variable.c (classname): find regular class name if not set. [ruby-dev:20496] Sat Aug 2 09:58:13 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: bug fix --- forgot to entry a widget class name of 'labelframe' widget * ext/tk/sample/{demos-en,demos-jp}/{labelframe.rb,paned1.rb, paned2.rb,spin.rb}: add demo-scripts to the JP/EN widget demos Sat Aug 2 05:04:30 2003 Hidetoshi NAGAI * ext/tk/lib/tkentry.rb: bug fix of TkEntry#delete * ext/tk/samples/: bug fix of some widget demos * ext/tk/lib/tk.rb: support == * ext/tk/lib/*.rb: freeze some object for security reason Sat Aug 2 03:30:25 2003 Yukihiro Matsumoto * class.c (rb_obj_singleton_methods): should not go up to ancestors unless the recursive flag is set. [ruby-list:38007] * eval.c (rb_yield_0): expand [] to nil if avalue is set. [ruby-dev:21058] * hash.c (env_each_key): use env_keys to avoid environment modify on the fly. * hash.c (env_each_value): use env_values for safety. * hash.c (env_each): allocate environment array first. Fri Aug 2 03:20:00 2003 why the lucky stiff * lib/yaml/store.rb (YAML::Store#initialize): filename is first argument. Thanks Kent Dahl. Sat Aug 2 00:49:31 2003 Minero Aoki * lib/net/http.rb: refine document. Fri Aug 1 23:57:45 2003 Nobuyoshi Nakada * gc.c (rb_gc_mark_locations): no need to swap arguments. * gc.c (STACK_LENGTH): insufficient for growing up stack architectures. * gc.c (rb_gc, Init_stack) ditto. Fri Aug 1 23:33:36 2003 Masatoshi Seki * rubytest.rb: set dldpath on darwin. Fri Aug 1 23:07:38 2003 Minero Aoki * lib/net/http.rb: convert RD to RDoc. Thanks William Webber. [ruby-doc:456] Fri Aug 1 19:48:56 2003 Yukihiro Matsumoto * ext/syck/rubyext.c (syck_emitter_write_m): forgot to declare "self", making it default to "int". * ext/syck/rubyext.c (syck_emitter_simple_write): ditto. * gc.c (rb_gc): should mark backing store region on IA64. Fri Aug 1 18:51:10 2003 Hidetoshi NAGAI * process.c: bug fix --- preprocessor errors occur on OpenBSD-current Fri Aug 1 17:13:23 2003 Nobuyoshi Nakada * ext/openssl/extconf.rb: should replace literally. Fri Aug 1 16:22:57 2003 Nobuyoshi Nakada * io.c (rb_io_check_readable, rb_io_check_writable): ensure not closed at first. * io.c (rb_io_getline): check readable always. (ruby-bugs:PR#1069) * io.c (rb_io_each_byte): ditto. Fri Aug 1 16:02:46 2003 Nobuyoshi Nakada * io.c (READ_DATA_PENDING_PTR): cast to get rid of warnings. * ext/socket/socket.c (unix_send_io, unix_recv_io): ditto. Fri Aug 1 15:53:24 2003 NAKAMURA Usaku * win32/win32.c (isInternalCmd): shouldn't return if find end of str. [ruby-talk:77678] Fri Aug 1 13:45:14 2003 Nobuyoshi Nakada * eval.c (rb_call_super): propagate previous block if a block is given. [ruby-talk:77577] Fri Aug 1 09:54:38 2003 Yukihiro Matsumoto * array.c (rb_ary_fill): array length may be changed during the block execution. [ruby-talk:77579] * array.c (rb_ary_zip): ditto. * array.c (rb_ary_fill): ditto. * hash.c (env_reject_bang): length may be changed during the block execution. * hash.c (env_clear): ditto. Fri Aug 1 04:58:55 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: bug fix --- forget to eval given block to TkRoot.new method * ext/tk/sample/tkoptdb-safeTk.rb: new sample script Fri Aug 1 00:52:58 2003 Yukihiro Matsumoto * gc.c (Init_stack): IA64 requires STACK_LEVEL_MAX to be less than magic number when optimizer turned on, regardless of rlimit values. Thu Jul 31 23:44:00 2003 Masatoshi SEKI * lib/erb.rb: import erb-2.0.4b4. Thu Jul 31 23:04:45 2003 Hidetoshi NAGAI * ext/tk/sample/resource.en, ext/tk/sample/resource.jp: wrong resource file format * ext/tk/lib/tk.rb: add Tk::Encoding.{encoding_convertfrom, encoding_convertto} * ext/tk/lib/tk.rb: add TkOptionDB.read_with_encoding to read non-utf8 resource file Thu Jul 31 23:02:47 2003 NAKAMURA Usaku * ext/etc/etc.c: revert getenv()'s prototype. use it only when _WIN32 is not defined. Thu Jul 31 20:52:40 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: (IMPORTANT BUG FIX) scan of event keywords doesn't work on recent versions of Tck/Tk * ext/tk/lib/tk.rb: initialize error of instance variable on TkComposite * ext/tk/lib/multi-tk.rb: initialize error on encoding-system on MultiTkIp * ext/tk/lib/tk.rb: trouble on destroying widgets * ext/tk/sample/demos-en/, demos-jp/: add JP and EN version of Ruby/Tk widget demos Thu Jul 31 15:25:12 2003 NAKAMURA Usaku * array.c (rb_ary_collect): must get length of array for each iteration. reported on [ruby-talk:77500], and fixed by K.Sasada on [ruby-talk:77504] Thu Jul 31 14:11:54 2003 GOTOU Yuuzou * ext/openssl/extconf.rb: move gmake specific features into GNUmakefile. Thu Jul 31 12:36:11 2003 Masatoshi SEKI * bin/erb, lib/erb.rb: add explicit trim mode. Thu Jul 31 04:59:10 2003 Yukihiro Matsumoto * numeric.c (rb_num_coerce_relop): export function. Thu Jul 31 08:18:00 2003 Nathaniel Talbott * lib/test/unit.rb: A useful return code is now set if tests fail when running automatically using the Console::TestRunner. Thu Jul 31 07:59:18 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: wrap the command-proc of TkScale --- pass the numeric object to the proc * ext/tk/lib/tk.rb: better support for widgets created on Tk interpreter (without Ruby) * ext/tk/lib/multi-tk.rb: a little more stable on Multiple Tk interpreters running Thu Jul 31 00:17:19 2003 Shugo Maeda * lib/net/ftp.rb (return_code): obsolete. * lib/net/ftp.rb (last_response_code): new method. lastresp is now alias to last_response_code. * lib/net/ftp.rb (last_response): new method. Wed Jul 30 23:55:44 2003 Yukihiro Matsumoto * marshal.c (w_object): check has been dropped. "_dump must return string." [ruby-dev:21024] Wed Jul 30 22:35:19 2003 Nobuyoshi Nakada * lib/mkmf.rb (dir_config): allow multiple directories separated by File::PATH_SEPARATOR. * lib/mkmf.rb (create_makefile): DLDFLAGS include $LDFLAGS again. [ruby-talk:76894] * lib/mkmf.rb (init_mkmf): not default $LDFLAGS to LDFLAGS for ruby itself, but default $DLDFLAGS to DLDFLAGS. Wed Jul 30 16:17:06 2003 Yukihiro Matsumoto * marshal.c (w_object): marshal_dump should not take any argument. Wed Jul 30 15:54:04 2003 GOTOU Yuuzou * ext/openssl/ossl_ssl.c (ossl_sslctx_initialize): should initialize instance variables. [ruby-talk:77362] Wed Jul 30 15:39:54 2003 Yukihiro Matsumoto * ruby.c (proc_options): -F set compiled regular expression to $;. [ruby-talk:77381] * string.c (Init_String): no setter type check for $; Wed Jul 30 15:10:02 2003 Nobuyoshi Nakada * error.c (rb_raise): snprintf() termination moved to win32/win32.c. * win32/win32.c (valid_filename, str_grow): unused. * win32/win32.c (NTLoginName, ChildRecord): make static. * win32/win32.c (CreateChild): argument check. * win32/win32.c (kill): should not call CloseHandle() when OpenProcess() failed. * win32/win32.c (rb_w32_vsnprintf, rb_w32_snprintf): ensure buffer terminated. [ruby-talk:69672] Wed Jul 30 10:54:10 2003 Shugo Maeda * lib/net/ftp.rb (get): fix wrong argument name. Thanks to William Webber. Wed Jul 30 10:31:37 2003 Nobuyoshi Nakada * ext/iconv/iconv.c (iconv_convert): append unchanged portion after overflow. [ruby-dev:21006] * ext/iconv/extconf.rb: check if iconv() 2nd argument is const. Wed Jul 30 09:31:55 2003 Nobuyoshi Nakada * configure.in (os2-emx): renamed from os2_emx, add flags to CFLAGS and LDFLAGS, and remove lib prefix. [ruby-dev:20993] * file.c (rb_file_s_rename): retry with removing new file on DOSISH. [ruby-dev:21007] * ext/socket/extconf.rb (sendmsg, recvmsg): check functions. * ext/socket/socket.c (unix_send_io, unix_recv_io): raise NotImplementedError unless system calls are available. * ext/socket/socket.c (sock_initialize): rename from sock_init() to get rid of conflict with OS/2 socket library. Wed Jul 30 07:23:14 2003 Hidetoshi NAGAI * ext/tk/lib/tkentry.rb: fix lack of methods for TkEntry * ext/tk/lib/multi-tk.rb, ext/tk/lib/tk.rb, ext/tk/lib/tkdialog.rb, ext/tk/lib/tkentry.rb, ext/tk/sample/safe-tk.rb, ext/tk/sample/tktimer2.rb: bug fix * ext/tk/lib/multi-tk.rb: MultiTkIp.new_* accept a block to eval under the new interpreter Wed Jul 30 04:36:30 2003 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c, ext/tk/lib/tk.rb, ext/tk/lib/tkafter.rb: additional check of Tk interpreters' status for a little more safety Wed Jul 30 02:37:12 2003 Yukihiro Matsumoto * marshal.c (w_object): if object responds to 'marshal_dump', Marshal.dump uses it to dump object. unlike '_dump', marshal_dump returns any kind of object. * marshal.c (r_object0): restore instance by calling 'marshal_load' method. unlike '_load', it's an instance method, to handle cyclic reference. * marshal.c (marshal_load): all objects read from file should be tainted. [ruby-core:01325] Wed Jul 30 01:47:51 2003 Hugh Sasse * lib/timeout.rb (Timeout::timeout): execute immediately if sec is zero. Wed Jul 30 01:36:18 2003 Aron Griffis * ext/socket/socket.c (socks_init): typo fixed. [ruby-talk:77232] Wed Jul 30 00:48:43 2003 Yukihiro Matsumoto * ext/socket/extconf.rb: the default value for --enable-socks is taken from ENV["SOCKS_SERVER"]. [ruby-talk:77232] * ruby.c (proc_options): add -W option. -W0 to shut up all warning messages. [ruby-talk:77227] * error.c (rb_warn): no message will be printed if the value of $VERBOSE is "nil", i.e. perfect silence. * ruby.c (verbose_setter): $VERBOSE value is either true, false, or nil. * io.c (Init_IO): no "read" check for $stdin. in addition some function names has been changed. Tue Jul 29 23:10:19 2003 Yoshida Masato * regex.c (re_match_exec): incorrect multibyte match. Tue Jul 29 22:36:50 2003 Minero Aoki * lib/net/smtp.rb (send0): do taint check only when $SAFE > 0 Tue Jul 29 19:20:34 2003 WATANABE Hirofumi * lib/fileutils.rb (install): support preserve timestamp. * instruby.rb (install): use FileUtils::install preserve mode. * lib/un.rb: new. % ruby -run -e cp -- -p foo bar * lib/mkmf.rb: use un.rb instead of ftools.rb. * MANIFEST: add lib/un.rb. * ext/extmk.rb (INSTALL_PROG, INSTALL_DATA): modify verbose messages. Tue Jul 29 18:55:22 2003 Minero Aoki * lib/net/smtp.rb: unify coding style. * lib/net/http.rb: ditto. Tue Jul 29 17:27:59 2003 NAKAMURA Usaku * ruby.h (LLONG_MIN): fix typo. Tue Jul 29 16:38:44 2003 Yukihiro Matsumoto * lib/net/smtp.rb (Net::SMTP::send0): add taint check. Tue Jul 29 15:41:02 2003 WATANABE Hirofumi * instruby.rb (install): preserve the timestamp for Mac OS X ranlib problem. Tue Jul 29 01:14:51 2003 Rick Ohnemus * ruby.h (LLONG_MIN): wrong value. Mon Jul 28 22:57:52 2003 Yukihiro Matsumoto * io.c (rb_f_getc): $stdin may not be IO. [ruby-dev:20973] Tue Jul 29 16:20:36 2003 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: bug fix and change mainloop_abort_on_no_widget_cmd => mainloop_abort_on_exception ( to avoid thread timing trouble on accessing destroyed widgets ) * ext/tk/lib/multi-tk.rb: change default mode of mainloop_abort_on_exception on multi-tk.rb * ext/tk/lib/multi-tk.rb: fix a bug of the procedure for 'Delete' button on the safe-Tk frmae Tue Jul 29 12:22:28 2003 why the lucky stiff * ext/syck/token.c: prefixed many constants and definitions with YAML_ to avoid name clash. * ext/syck/gram.c: ditto. * ext/syck/gram.h: ditto. Tue Jul 29 12:15:37 2003 NAKAMURA Usaku * ext/etc/etc.c: add real prototype to getenv(). * win32/win32.h: add arguments to definitions of functions if possible. Tue Jul 29 08:05:30 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb, ext/tk/lib/tkdialog.rb, ext/tk/lib/tktext.rb, ext/tk/sample/tkbiff.rb, ext/tk/sample/tkdialog.rb, ext/tk/sample/tkform.rb: bug fix ( tested with Ruby/Tk widget demo ) Tue Jul 29 04:22:08 2003 why the lucky stiff * ext/syck/syck.h: Added 'syck' yacc prefixes. * ext/syck/gram.c: ditto. * ext/syck/token.c: ditto. * ext/syck: Added ruby.h reference to source files. Tue Jul 29 03:53:28 2003 GOTOU Yuuzou * ext/openssl/lib/net/https.rb (use_ssl=): raise ProtocolError if connection is set up already. Tue Jul 29 01:45:32 2003 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: use RTEST() Tue Jul 29 01:24:32 2003 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: bug fix * ext/tk/lib/multi-tk.rb: bug fix and pack options are pssed to the safeTk container * ext/tk/sample/safe-tk.rb: add example for pack options of safeTk container Mon Jul 28 23:23:08 2003 Nobuyoshi Nakada * file.c (Init_File): IO should include File::Const. [ruby-dev:20964] Mon Jul 28 18:53:03 2003 WATANABE Hirofumi * ext/openssl/extconf.rb: check again after pkg-config for MinGW on Cygwin. Mon Jul 28 15:32:04 2003 Yukihiro Matsumoto * ext/stringio/stringio.c (strio_gets): only "gets" should set $_. * ext/stringio/stringio.c (strio_getline): should not set $_ here. * io.c (argf_to_s): argf.to_s returns "ARGF". * io.c (set_defout_var, set_deferr_var): make $defout and $deferr obsolete. * io.c (set_input_var, set_output_var): allow $stdin, $stdout, $stderr not to be instance of IO. * io.c (rb_f_readline): forward method to current_file. gets, readline, readlines, getc, readchar, tell, seek, pos=, rewind, fileno, to_io, eof, each_line, each_byte, binmode, and closed? as well. * io.c (argf_forward): utility function to forward method to current_file. Mon Jul 28 06:10:13 2003 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: bug fix * ext/lib/tk/multi-tk.rb: bug fix * ext/lib/tk/multi-tk.rb: add methods depend on Tcl's 'interp' command * ext/lib/tk/multi-tk.rb: suppot safe-level control of each interpreter Mon Jul 28 03:08:47 2003 Akinori MUSHA * lib/set.rb: each() should return self. Mon Jul 28 01:35:32 2003 Yukihiro Matsumoto * string.c (rb_str_chomp_bang): defer rb_str_modify() to actual modify point. other methods, replace, tr, delete, squeeze, lstrip, and rstrip as well. * string.c (rb_str_rstrip_bang): remove trailing '\0' at the end of string. * string.c (rb_str_lstrip_bang): do not strip '\0' from the left. Sun Jul 27 21:16:30 2003 WATANABE Hirofumi * ext/openssl/extconf.rb: better support MinGW. add dir_config("kerberos") and with_config("pkg-config"). * mkconfig.rb: initialize global variables to avoid warnings. Sun Jul 27 19:35:06 2003 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: add some methods to support multiple interpreters (low level) * ext/tk/lib/multi-tk.rb: new library to support multiple Tk interpreters (high level) * ext/tcltklib/demo/safeTk.rb: new sample of safeTk interpreter * ext/tk/sample/safe-tk.rb: new sample of multi-tk.rb * ext/tk/lib/tk.rb: bug fix and add feature to supprt multi-tk * ext/tk/lib/tkafter.rb: ditto Sun Jul 27 14:43:37 2003 NAKAMURA, Hiroshi * lib/debug.rb: fix breakpoint parameter parsing/checking. (?:(file|class):)(line_number|method) Sun Jul 27 10:21:28 2003 Masatoshi SEKI * lib/drb/unix.rb: add UNIXFileOwner, UNIXFileGroup. Sun Jul 27 03:10:43 2003 Nobuyoshi Nakada * io.c (io_reopen): avoid dup2() equal handles not to close itself and to get rid of a msvcrt bug. [ruby-dev:20919] Sun Jul 27 00:37:16 2003 WATANABE Hirofumi * lib/tmpdir.rb: use GetWindowsDirectory, not GetSystemDirectory. [ruby-talk:77073] Sat Jul 26 21:25:21 2003 NAKAMURA Usaku * io.c (rb_fdopen): set errno if it's zero on win32 platforms. * ext/openssl/ossl_ssl.c (TO_SOCKET): define special version when _WIN32 is defined. this is ruby's problem, not OpenSSL. * win32/win32.c: remove some old comments. Sat Jul 26 14:26:57 2003 Yukihiro Matsumoto * ext/tk/lib/tk.rb (TkCore::chooseDirectory): back up wrongly removed method. Sat Jul 26 14:14:12 2003 Nobuyoshi Nakada * ext/stringio/stringio.c: includes Enumerable as well as IO. [ruby-talk:77058] Sat Jul 26 07:00:53 2003 Masatoshi SEKI * lib/erb.rb: fix % line. Sat Jul 26 05:31:09 2003 GOTOU Yuuzou * ext/openssl/ossl.h: fix comment. * ext/openssl/ossl.c (ossl_debug): should enable if no va-args macro supplied. Sat Jul 26 04:04:36 2003 GOTOU Yuuzou * ext/openssl/extconf.rb: refine va-args macro detection. [ruby-talk:76983] Sat Jul 26 01:33:51 2003 NAKAMURA Usaku * ext/openssl/ossl_ssl.c (ossl_ssl_setup): need to pass the real socket to SSL_get_fd on native win32 platforms. Sat Jul 26 01:20:29 2003 Yukihiro Matsumoto * variable.c (rb_mod_const_missing): "const_missing" should not appear in the caller(); add call frame adjustment. * eval.c (rb_method_missing): simplify call frame adjustment. Fri Jul 26 00:04:25 2003 NAKAMURA, Hiroshi * ext/openssl/sample: add samples. - cert2text.rb: dump certificate file as text. - crlstore.rb: CRL store implementation. Fetch CRL via HTTP when http-access2 is installed. - certstore.rb: certificate store implementation. - cert_store_view.rb: certificate store viewer with FXRuby. Uses c_rehash.rb, crlstore.rb and certstore.rb. Fri Jul 25 16:43:03 2003 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: add TclTkIp#create_slave, TclTkIp#_make_safe and TclTkIp#safe? * ext/tcltklib/MANUAL.euc: modify descriptions * ext/tk/lib/tk.rb: bug fix [ruby-talk:76980] and modify to support multi Tk IPs * ext/tk/lib/tkafter.rb: modify to support multi Tk IPs Fri Jul 25 15:47:39 2003 GOTOU Yuuzou * ext/openssl/extconf.rb: add check for BN_rand_range() and BN_pseudo_rand_range(). * ext/openssl/ossl_bn.c (ossl_bn_s_rand_range): should raise NotImplementedError if BN_rand_range() wan not defined. * ext/openssl/ossl_bn.c (ossl_bn_s_pseudo_rand_range): should raise NotImplementedError if BN_pseudo_rand_range() wan not defined. * ext/openssl/ossl_pkcs7.c (ossl_pkcs7_s_encrypt): avoid compiler warning for OpenSSL-0.9.6. * ext/openssl/ossl_pkcs7.c (ossl_pkcs7si_initialize): ditto. Fri Jul 25 14:34:55 2003 Yukihiro Matsumoto * ext/socket/socket.c (tcp_s_gethostbyname): was using uninitialized size_t value. [ruby-talk:76946] Fri Jul 25 13:38:38 2003 Nobuyoshi Nakada * re.c (rb_reg_options_m): use rb_reg_options() to mask internal flags. * re.c (rb_reg_initialize_m): allow nil as third argument and ignore, and mask code flags if the argument is given. [ruby-dev:20885] * re.c (rb_reg_options): get common flags directly. Fri Jul 25 03:52:21 2003 why the lucky stiff * lib/yaml/dbm.rb: replace indexes with values_at. Fri Jul 25 02:55:59 2003 GOTOU Yuuzou * ext/openssl/extconf.rb: add check for libsocket and libnsl. * ext/openssl/extconf.rb: use pkg-config to build CFLAGS and LDFLAGS. Fri Jul 25 01:27:59 2003 why the lucky stiff * ext/syck/emitter.c (syck_emitter_flush): accepts count of bytes to flush. anchor offsets now functional. * ext/syck/syck.h (syck_emitter_flush): ditto. * ext/syck/rubyext.c: ditto. * ext/syck/token.c: URI escaping now supported. Thu Jul 24 16:41:31 2003 Nobuyoshi Nakada * lib/mkmf.rb (have_type): check if a type is defined. * lib/mkmf.rb (check_sizeof): check size of a type. * ext/dbm/extconf.rb: check if type DBM is defined. [ruby-talk:76693] Thu Jul 24 16:18:40 2003 Nobuyoshi Nakada * ChangeLog (add-log-time-format): "%c" contains timezone on XEmacs. Thu Jul 24 16:05:22 2003 Nobuyoshi Nakada * configure.in (AC_C_VOLATILE): check if volatile works. * defines.h (volatile): removed. * eval.c (rb_thread_group): Thread#group. [new] Thu Jul 24 15:50:42 2003 GOTOU Yuuzou * ext/openssl/extconf.rb: add check for win32 OpenSSL libraries. * ext/openssl/extconf.rb: add check for __VA_ARGS__. * ext/openssl/ossl.h: avoid non C99 compiler errors. Thu Jul 24 13:32:56 2003 Yukihiro Matsumoto * eval.c (thgroup_add): no warning for terminated threads. Thu Jul 24 13:09:26 2003 Tanaka Akira * lib/pathname.rb: added. Thu Jul 24 11:21:10 2003 Nobuyoshi Nakada * ext/io/wait/extconf.rb: removed unnecessary backward compatibility stuff. Thu Jul 24 11:09:10 2003 WATANABE Hirofumi * ext/openssl/extconf.rb: revert use of dir_config. Thu Jul 24 09:58:32 2003 NAKAMURA Usaku * ext/Win32API/lib/win32/resolv.rb: added. * lib/resolv.rb: support Win32 platforms. based on Tietew's work [ruby-dev:15573]. Thu Jul 24 04:05:46 2003 GOTOU Yuuzou * ext/openssl/ssl.h: undef X509_NAME and PKCS7_SIGNER_INFO to avoid name confliction on mswin32. * ext/openssl/ssl.c (ossl_protect_obj2bio): avoid VC++ warnings in function prototype. * ext/openssl/ssl.c (ossl_protect_membio2str): ditto. * ext/openssl/ssl.c (ossl_protect_x509_ary2sk): ditto. Thu Jul 24 03:44:04 2003 Michal Rokos * ext/openssl/extconf.rb: cut check for OpenSSL version Thu Jul 24 03:41:30 2003 NAKAMURA Usaku * ext/tcltklib/tcltklib.c (ip_init): need at least one statement after label. Thu Jul 24 01:48:03 2003 Yukihiro Matsumoto * lib/cgi.rb (CGI::QueryExtension::[]): should return StringIO (or Tempfile) for multipart/form. * variable.c (rb_define_const): give warning for non constant name. [ruby-core:01287] Thu Jul 24 01:51:08 2003 GOTOU Yuuzou * lib/webrick: imported. * MANIFEST: added webrick files. Thu Jul 24 01:32:04 2003 WATANABE Hirofumi * lib/tmpdir.rb (tmpdir): new method. remove TMPDIR. use GetSystemWindowsDirectory(GetSystemDirectory), not GetTempPath. Thu Jul 24 01:08:43 2003 GOTOU Yuuzou * ext/openssl: imported. Wed Jul 23 23:06:59 2003 WATANABE Hirofumi * file.c (DOSISH): better Cygwin support. Wed Jul 23 19:13:21 2003 Yukihiro Matsumoto * string.c (rb_str_split_m): the receiver may be empty string. Wed Jul 23 18:43:00 2003 Masatoshi SEKI * lib/erb.rb: import erb-2.0.4b1. Wed Jul 23 18:21:52 2003 Nobuyoshi Nakada * ext/io/wait: imported. Wed Jul 23 16:07:35 2003 Hidetoshi NAGAI * process.c: unify indentation * configure.in: add --enable-setreuid option * ext/tcltklib/tcltklib.c: TclTkIp.new accepts 'ip-name' and 'options' * ext/tk/lib/tk.rb: support arguments of TclTkIp.new * ext/tk/lib/tk*.rb: preparations for multi-Tk interpreter support Wed Jul 23 15:49:01 2003 Yukihiro Matsumoto * string.c (rb_str_lstrip_bang): strip NUL along with white spaces. [ruby-talk:76659] * string.c (rb_str_rstrip_bang): ditto. Wed Jul 23 14:19:17 2003 Nobuyoshi Nakada * lib/mkmf.rb (log_src, checking_for, create_header): Logging.message is printf like format. Wed Jul 23 10:11:15 2003 Nobuyoshi Nakada * ext/iconv/iconv.c (check_iconv): check if Iconv instance. * ext/iconv/iconv.c (iconv_convert): stringify argument. Wed Jul 23 02:39:46 2003 Hidetoshi NAGAI * process.c: add a module for raw syscalls to control UID/GID * process.c: add modules for portable UID/GID control Tue Jul 22 19:16:40 2003 Tanaka Akira * ext/iconv/iconv.c (iconv_failure_initialize): limit inspect message. [ruby-dev:20785] * ext/iconv/iconv.c (rb_str_derive): share with original string if possible. [ruby-dev:20785] Tue Jul 22 17:22:34 2003 Yukihiro Matsumoto * variable.c (rb_mod_const_missing): new method. [ruby-core:00441] * variable.c (rb_const_get_at): allow "const_missing" hook. * variable.c (rb_const_get_0): ditto. * eval.c (method_missing): rename from rb_undefined to clarify. * eval.c (ruby_finalize_0): update exit status if any of END proc raises SystemExit. [ruby-core:01256] * signal.c (rb_trap_exit): wrap rb_eval_cmd * eval.c (rb_exec_end_proc): reduce rb_protect(). Tue Jul 22 17:15:57 2003 WATANABE Hirofumi * MANIFEST (lib/cgi/session/pstore.rb, lib/yaml/baseemitter.rb): added. Tue Jul 22 10:52:19 2003 NAKAMURA Usaku * lib/tmpdir.rb: remove charcters after "\000" and regularize path. Tue Jul 22 02:22:45 2003 Yukihiro Matsumoto * numeric.c (num_equal): should not use rb_equal(). * string.c (rb_str_equal): should return nil for non string operand to conform comparable convention. [ruby-dev:20759] Tue Jul 22 00:19:19 2003 Yukihiro Matsumoto * lib/tmpdir.rb: new library to get temporary directory path, using GetTempPath on Win32 environment. * lib/tempfile.rb: now uses tmpdir.rb. * lib/cgi/session.rb, ib/drb/unix.rb: ditto. Mon Jul 21 01:53:43 2003 Yukihiro Matsumoto * string.c (rb_string_value_cstr): check null byte in the string before retrieving C ptr. accessed via macro StringValueCStr. * file.c: use StringValueCStr to retrieve paths to system calls. * file.c (sys_fail2): raise error for two operand system calls such as rename, link, symlink. (ruby-bugs PR#1047) Sun Jul 20 11:03:25 2003 UENO Katsuhiro * ext/zlib/zlib.c (gzfile_read_header): gz->z.input may be nil after finishing reading a gzip header. Sat Jul 19 22:25:47 2003 Yukihiro Matsumoto * string.c (rb_str_match2): add warning to "~string". [ruby-list:37751] * lib/net/ftp.rb (Net::FTP::open): takes block. suggested by Gavin Sinclair in [ruby-core:01237]. Sat Jul 19 19:03:24 2003 Takaaki Uematsu * wince/stdlib.c: add bsearch(). Sat Jul 19 12:34:45 2003 David Black * lib/scanf.rb: import. Sat Jul 19 11:27:25 2003 Yukihiro Matsumoto * lib/xmlrpc: import. * eval.c (thgroup_add): should return group for terminated thread case. * eval.c (thgroup_add): do not raise ThreadError on terminated thread addition for compatibility. just warning. Sat Jul 19 04:50:56 2003 Nobuyoshi Nakada * ext/iconv/charset_alias.rb, ext/iconv/extconf.rb: make wrapper script which maps charset names. [ruby-dev:20625] * ext/iconv/iconv.c (charset_map): charset name map. * ext/iconv/iconv.c (iconv_dfree): no exception while finalization. * ext/iconv/iconv.c (iconv_s_conv): new method Iconv.conv. [ruby-dev:20588] Sat Jul 19 03:09:18 2003 NAKAMURA Usaku * ext/Win32API/lib/win32/registry.rb (Win32::Registry::Error): inherit StandardError instead of SystemCallError. Sat Jul 19 02:00:39 2003 Nobuyoshi Nakada * eval.c (rb_attr): extra calls of method_added. [ruby-talk:76361] Fri Jul 18 18:44:22 2003 Nobuyoshi Nakada * lib/mkmf.rb (init_mkmf): clear $INSTALLFILES. [ruby-dev:20727] Fri Jul 18 17:34:39 2003 Nobuyoshi Nakada * lib/mkmf.rb (rm_f): use FileUtils. * lib/mkmf.rb (modified?): return mtime of the target if it exists and newer than times. * lib/mkmf.rb (install_files): add a current directory file even if it does not exist yet. * lib/mkmf.rb (configuration): do not add $LDFLAGS to DLDFLAGS. * ext/extmk.rb (extmake): check whether Makefile is newer than depend and MANIFEST. Fri Jul 18 14:57:19 2003 NAKAMURA Usaku * win32/win32.c (make_cmdvector): recognize quote within string. based on Nobu's patch ([ruby-win32:450]). [ruby-talk:75853] Fri Jul 18 13:04:36 2003 Yukihiro Matsumoto * eval.c (rb_f_missing): VCALL is called only for LOCAL_ID. no check required. * parse.y (primary): primary:tFID generates NODE_FCALL. [ruby-dev:20641] Thu Jul 17 18:50:26 2003 Yukihiro Matsumoto * re.c (match_captures): rename from "groups". Thu Jul 17 17:57:32 2003 Yukihiro Matsumoto * eval.c (rb_clear_cache_by_class): check both klass and origin. Thu Jul 17 13:46:25 2003 Yukihiro Matsumoto * eval.c (ruby_init): set ruby_running to true after initialization. Thu Jul 17 13:42:53 2003 WATANABE Hirofumi * lib/ftools.rb (File::makedirs): do not handle "//" as a directory. Thu Jul 17 06:40:28 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: recover and fix typo : Tk.chooseDirectory (Tk8.4 feature) Wed Jul 16 16:23:58 2003 Yukihiro Matsumoto * eval.c (rb_proc_new): call svalue_to_avalue for yield argument. Wed Jul 16 00:31:00 2003 Yukihiro Matsumoto * eval.c (rb_disable_super, rb_enable_super): deprecate. * eval.c (thgroup_s_alloc): re-implement group struct. * eval.c (thgroup_add): add check for enclose and frozen status. Tue Jul 15 19:50:49 2003 Nobuyoshi Nakada * eval.c (rb_add_method, rb_alias): need to clear cache by ID when method defined in parent class is cached for grand child classes. [ruby-dev:20672] Tue Jul 15 14:38:21 2003 Yukihiro Matsumoto * lib/matrix.rb: remove elements conversion to_f, to_i, to_r. * lib/cgi/session/pstore.rb: add new file. Tue Jul 15 03:30:41 2003 why the lucky stiff * ext/syck/rubyext.c (syck_mark_emitter): forgot to rb_gc_mark the outgoing IO object. Sun Jul 13 14:55:36 2003 Koji Arai * process.c (proc_getgroups, proc_setmaxgroups): fix typo. Sat Jul 12 17:01:28 2003 NAKAMURA Usaku * struct.c (struct_entry): add prototype to avoid VC++ warnings. Sat Jul 12 04:43:57 2003 why the lucky stiff * ext/syck/emitter.c: new emitter code. * ext/syck/rubyext.c: Emitter class. * lib/yaml.rb: Load Syck emitter, if available. * lib/yaml/stream.rb: ditto. * lib/yaml/baseemitter.rb: underlying class for all emitters. * lib/yaml/rubytypes.rb: use BaseEmitter abstraction. * lib/yaml/emitter.rb: ditto. Sat Jul 12 04:23:13 2003 Nobuyoshi Nakada * eval.c (rb_undef): need to clear cache for inherited class. (rubicon/builtin/TestModulePrivate.rb:test_undef_method) Sat Jul 12 01:21:54 2003 Nobuyoshi Nakada * eval.c (avalue_to_svalue): typo. * eval.c (rb_load): rb_prohibit_interrupt must not underflow. * parse.y (NODE_STRTERM, tokadd_string, parse_string): moved string nest level from a static variable to NODE_STRTERM, to preserve it from word to word in %W/%w. Fri Jul 11 22:37:18 2003 Nobuyoshi Nakada * configure.in (aix): needs ruby.imp even with gcc. (ruby-bugs:PR#1007) Fri Jul 11 18:37:37 2003 WATANABE Hirofumi * instruby.rb: do not handle directories. [ruby-dev:20613] Fri Jul 11 16:09:09 2003 Yukihiro Matsumoto * util.c (ruby_strtod): exp should be less than MDMAXEXPT. Fri Jul 11 07:17:47 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: not create a Tcl/Tk interpreter if already defined TkCore::INTERP * ext/tk/lib/tk.rb: bugfix on TkWindow#configure Thu Jul 10 14:42:02 2003 WATANABE Hirofumi * math.c (math_log): nan takes a dummy argument on Cygwin 1.5.0. Wed Jul 9 23:50:46 2003 Nobuyoshi Nakada * regex.c (mbctab_sjis): 0x80 is not shift jis first byte. [ruby-dev:20516] Wed Jul 9 15:38:28 2003 WATANABE Hirofumi * instruby.rb: do not install shared libraries as man pages. * mkconfig.rb: support text-mount on Cygwin. Wed Jul 9 11:09:57 2003 NAKAMURA Usaku * re.c (match_entry): add prototype to avoid VC++ warnings. Wed Jul 9 03:48:27 2003 Yukihiro Matsumoto * eval.c (rb_load): put rb_load_file() in a thread critical section. [ruby-dev:20490] * eval.c (compile): put rb_compile_string() in a thread critical section. Tue Jul 8 02:35:41 2003 Yukihiro Matsumoto * variable.c (rb_const_get_0): should not warn if constant is not defined. (ruby-bugs-ja PR#509) * bignum.c (rb_big2dbl): give a warning on overflow. (ruby-bugs-ja PR#510) * util.c (ruby_strtod): change MDMAXEXPT from 511 to 308. * pack.c (utf8_to_uv): long is sufficient. LONG_LONG is not required. Tue Jul 8 01:43:16 2003 Koji Arai * bignum.c (rb_big2str): support 32 bit (without `long long' type) machines. (ruby-bugs-ja PR#512) Mon Jul 7 10:22:46 2003 WATANABE Hirofumi * ext/dbm/extconf.rb (gdbm_compat, qdbm): add check for gdbm_compat and qdbm. Mon Jul 7 01:34:49 2003 Yukihiro Matsumoto * eval.c (rb_call_super): k->super maybe NULL if klass is Kernel. [ruby-dev:20519] * gc.c (obj_free): clear method cache when freeing class/module. Sat Jul 5 23:32:06 2003 Yukihiro Matsumoto * eval.c (rb_mod_remove_method): allow "remove_method" to accept multiple arguments. Sat Jul 5 00:22:59 2003 Yukihiro Matsumoto * node.h (NEW_NODE): cast arguments to rb_node_newnode(). Fri Jul 4 21:48:44 2003 Nobuyoshi Nakada * ext/syck/rubyext.c, ext/syck/syck.c, ext/syck/syck.h, ext/syck/token.c: C++ style comments are not allowed. (ruby-bugs:PR#1008) Thu Jul 3 23:41:30 2003 Tanaka Akira * lib/timeout.rb: add optional exception argument for compatibility function. Thu Jul 3 14:22:46 2003 Yukihiro Matsumoto * array.c (rb_values_at): extract common procedure from rb_ary_values_at. follow DRY principle. * re.c (match_values_at): values_at should understand ranges. * struct.c (rb_struct_values_at): ditto. * struct.c (inspect_struct): inspect format changed; add "struct " at the top. * sprintf.c (rb_f_sprintf): "%p" specifier for inspect output. (RCR#69) * eval.c (rb_mod_undef_method): allow "undef_method" to accept multiple arguments. (RCR#146) * lib/timeout.rb: put timeout in Timeout module. (RCR#121) [ruby-talk:61028] * re.c (match_groups): new method added. (RCR#139) * variable.c (rb_mod_const_of): should exclude constant defined in Object, unless retrieving constants of Object. Thu Jul 3 12:13:05 2003 WATANABE Hirofumi * lib/mkmf.rb (VPATH): convert from Windows form to Unix form on MinGW. This fixes the build with GNU make 3.80-1 for Cygwin. Wed Jul 2 23:27:34 2003 Yukihiro Matsumoto * string.c (rb_str_new4): do not allocate new string if original is frozen or already have copy-on-write entry. [ruby-talk:74940] Wed Jul 2 13:22:39 2003 Yukihiro Matsumoto * string.c (rb_str_shared_replace): clear flags before copy. * string.c (rb_str_replace): ditto. * eval.c (rb_yield_0): override visibility mode for module_eval etc. (ruby-bugs-ja PR#505) Wed Jul 2 11:45:34 2003 Minero Aoki * lib/net/smtp.rb: synchronize document with source code. * lib/net/pop.rb: ditto. Wed Jul 2 11:39:50 2003 Minero Aoki * lib/net/smtp.rb: unify SMTP and SMTPCommand. * lib/net/smtp.rb: new exception class SMTPError. * lib/net/smtp.rb: new exception class SMTPAuthenticationError. * lib/net/smtp.rb: new exception class SMTPServerBusy. * lib/net/smtp.rb: new exception class SMTPSyntaxError. * lib/net/smtp.rb: new exception class SMTPFatalError. * lib/net/smtp.rb: new exception class SMTPUnknownError. * lib/net/smtp.rb: change critical section protect algorithm. * lib/net/smtp.rb (SMTP#do_start): check authentication args before all. * lib/net/smtp.rb: new method send_message (alias send_mail). * lib/net/smtp.rb: new method open_message_stream (alias ready). * lib/net/pop.rb: POPBadResponse is a POPError. * lib/net/pop.rb (POPMail#pop): ban ReadAdapter. * lib/net/pop.rb (POPMail#top): ditto. * lib/net/pop.rb (POP3Command): change critical section protect algorithm. * lib/net/pop.rb (POP3Command#auth): USER and PASS should be one critical block. * lib/net/pop.rb (POP3Command#retr): ban `dest' argument using iterator. * lib/net/pop.rb (POP3Command#top): ditto. * lib/net/protocol.rb: #read_message_to -> #each_message_chunk * lib/net/protocol.rb: #D -> #LOG * lib/net/protocol.rb: #D_off -> #LOG_off * lib/net/protocol.rb: #D_on -> #LOG_on Wed Jul 2 11:10:47 2003 Minero Aoki * lib/net/http.rb: set old class aliases for backward compatibility. [ruby-talk:74863] * lib/net/protocol.rb: ditto. Wed Jul 2 01:32:40 2003 WATANABE Hirofumi * lib/net/pop.rb (Net::POP3#start): typofix. Tue Jul 1 22:08:19 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: TkWindow include TkWinfo * ext/tk/lib/tk.rb: treat unknown widget classes as subclasses of TkWindow Tue Jul 1 19:02:12 2003 WATANABE Hirofumi * parse.y (rb_intern): should use mbclen instead of mblen. Tue Jul 1 10:36:19 2003 Nobuyoshi Nakada * class.c (rb_define_class, rb_define_module): also set constant under Object. [ruby-dev:20445] * object.c (boot_defclass): ditto. * variable.c (rb_const_get_at, rb_const_get_0, rb_mod_const_at, rb_const_defined, mod_av_set, rb_const_assign): toplevel constants are now under Object, rb_class_tbl remains for GC. Mon Jun 30 17:53:06 2003 Nobuyoshi Nakada * eval.c (mnew): ignore metaclasses have no influence, for rklass. [ruby-talk:74706] Sun Jun 29 06:59:07 2003 Masatoshi SEKI * lib/drb/drb.rb, lib/drb/invokemethod.rb: import drb-2.0.4 (use LocalJumpError#reason) Sat Jun 28 12:28:54 2003 Nobuyoshi Nakada * configure.in (rb_cv_stack_grow_dir): check stack growing direction. * eval.c (rb_thread_restore_context): prior configuration macro. * gc.c (ruby_stack_length): always return the address of lower edge. * gc.c (rb_gc_mark_locations): remove margin. [ruby-dev:20462] * gc.c (rb_gc, Init_stack): prior configuration macro. * gc.c (Init_stack): add safety margin. Fri Jun 27 14:41:22 2003 Nobuyoshi Nakada * string.c (rb_str_split_m): remove white spaces on the head of the last element, when limit is specified. [ruby-talk:74506] Fri Jun 27 03:24:54 2003 Nobuyoshi Nakada * io.c (io_fflush): need to check if closed after thread switch. [ruby-dev:20351] * io.c (fptr_finalize): ditto. * string.c (rb_str_rindex_m): fixed wrong fix. should move backward first only when matching from the end. Thu Jun 26 21:34:49 2003 Nobuyoshi Nakada * class.c (class_instance_method_list): get rid of warning about arguement type mismatch, and inline method_list(). [ruby-core:01198] Wed Jun 25 14:40:33 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: add and modify methods --- TkWidget.database_class, TkWidget.database_classname, TkWidget#database_class, TkWidget#database_classname * ext/tk/lib/tk.rb: instances of a subclass of TkToplevel or TkFrame are created with ":class=>subclass" option as default. * ext/tk/sample/tkoptdb.rb: add a new part Wed Jun 25 12:52:58 2003 Matthew Dempsky * class.c (rb_generic_class_instance_methods): merge argument check (and warning) into one function; following DRY principle. [ruby-core:01193] Wed Jun 25 05:49:10 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: add widget destroy hook binding to TkBindTag::ALL * ext/tk/lib/tkcanvas.rb: Although requiring manual control of GC, memory eating problem of TkCanvas Items is fixed. * ext/tk/lib/tktext.rb: add some methods and bug fix Wed Jun 25 00:14:30 2003 Yukihiro Matsumoto * variable.c (autoload_delete): should delete Qundef from iv_tbl. (ruby-bugs-ja PR#504) Tue Jun 24 16:46:07 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: bug fix on TkToplevel, TkFrame, TkPanedwindow, TkOptionDB * ext/tk/lib/tk.rb: TkOptionDB --- make it more secure to use procs defined on resourceDB * ext/tk/sample/tkoptdb.rb, resource.ja, resource.en: sample script how to use TkOptionDB. Tue Jun 24 14:22:41 2003 why the lucky stiff * lib/yaml/types.rb: replaced Kernel::Hash reference with Object::Hash from [ruby-talk:74270] Tue Jun 24 17:59:30 2003 Nobuyoshi Nakada * eval.c (rb_yield_0): show yielded block position not only yielding point. [ruby-dev:20441] Tue Jun 24 16:47:07 2003 Minero Aoki * lib/net/http.rb (HTTPHeader#proxy_basic_auth): missing `@'. Thanks Douglas Koszerek. (ruby-bugs:PR975) Tue Jun 24 14:31:17 2003 Minero Aoki * config.guess: have wrongly returned "alphaev56-unknown-linux-" on Linux/Alpha. [ruby-dev:20434] Tue Jun 24 04:54:46 2003 Minero Aoki * configure.in: always add -mieee for gcc/alpha. [ruby-dev:20429] Tue Jun 24 02:40:09 2003 Nobuyoshi Nakada * array.c (rb_ary_unshift_m): need to check number of arguments. [ruby-talk:74189] Mon Jun 23 23:59:56 2003 Minero Aoki * io.c (io_close): missing prototype. [ruby-dev:20422] * ext/socket/socket.c (bsock_do_not_rev_lookup_set): ditto. * ext/win32ole/win32ole.c (foletype_guid, foletype_progid): ditto. * error.c (syserr_initialize): length argument of sprintf() is an int. Mon Jun 23 23:28:14 2003 WATANABE Hirofumi * MANIFEST: add wince files. * ext/tk/MANIFEST: add sample/tkmenubutton.rb. Mon Jun 23 17:40:58 2003 Nobuyoshi Nakada * dir.c (find_dirsep): get rid of warnings. * eval.c (error_print): temporary value might be disposed by GC. * hash.c (env_has_value, env_index): should not increment NULL. * io.c (io_read, rb_io_sysread): not read when length is 0. * io.c (rb_io_reopen): ensure initialized IO. * io.c (rb_io_init_copy): sychronize file pointer. * io.c (rb_io_s_pipe): make exception proof. * string.c (rb_str_rindex_m): Fixnum 0 matched end of string. Mon Jun 23 16:18:12 2003 Tanaka Akira * io.c (rb_open_file): initialize flags. * time.c (time_arg): initialize v[6] even when argc is 10 to avoid valgrind error. Mon Jun 23 14:22:44 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: bug fix on TkRoot and TkToplevel Mon Jun 23 08:24:01 2003 Florian Frank * string.c (rb_str_upto): generate sequence according to "succ" order. formerly check was done by dictionary order. [ruby-talk:74138] Mon Jun 23 00:27:32 2003 Yukihiro Matsumoto * string.c (rb_string_value): fill constant empty string along with setting ELTS_SHARED if str->ptr is NULL. [ruby-core:01179] * string.c (rb_string_value_ptr): ditto. * string.c (rb_check_string_type): ditto. Sun Jun 22 23:42:20 2003 Nobuyoshi Nakada * string.c (str_gsub): move END(0) check before mbclen2(). * string.c (scan_once): reduce END(0) check. * io.c (rb_io_initialize): accept fixnum mode. * eval.c (error_print): replace strchr() by memchr(), einfo may contain "\0". * pack.c (pack_unpack): range check for "@" move; initialize check for "m". * error.c (syserr_initialize): avoid buffer overflow. * file.c (rb_file_s_readlink): expand buffer until readlink succeed. Sun Jun 22 16:17:02 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: TkRoot.new and TkToplevel.new accept Wm commands as elements * ext/tk/lib/tk.rb: TkMenu --- add some methods * ext/tk/lib/tk.rb: TkOptionMenubutton --- bug fix * ext/tk/sample/tkmenubutton.rb: sample of TkMenubutton and TkOptionMenubutton Sat Jun 21 23:15:08 2003 Yukihiro Matsumoto * eval.c (proc_invoke): should not propagate distination tag if tag is already handled in this level. (ruby-bugs-ja PR#501) * object.c (str_to_id): check for empty string before intern. [ruby-talk:74006] Sat Jun 21 13:56:09 2003 Takaaki Uematsu * wince/Makefile.sub: undefine HAVE__SETJMP. * wince/resource.rb: include winver.h in wince3.0. Sat Jun 21 12:55:17 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: TkRoot.new and TkToplevel.new accept Wm commands as elements of a hash argument. * ext/tk/sample/tktimer2.rb: add comments about the usage of a TkTimer object. Sat Jun 21 08:47:22 2003 Hidetoshi NAGAI * ext/tk/lib/tk*.rb: remove direct-accesses to TkComm::INTERP and TkComm::INITIALIZE_TARGETS * ext/tk/lib/tk*.rb: use TkINTERP_SETUP_SCRIPTS constant for setting up the interpreter * ext/tcltklib/tcltklib.c: support to create a safe interpreter with safe-Tk Fri Jun 20 23:28:27 2003 Yukihiro Matsumoto * eval.c (proc_invoke): should not propagate TAG_BREAK and TAG_RETURN from orphan Proc object. [ruby-core:01148] Fri Jun 20 15:04:28 2003 NAKAMURA Usaku * defines.h (PATH_ENV): name of PATH environment. [new]. * defines.h (ENV_IGNORECASE): define for case insensitive platforms to access environment variables. * dln.c (dln_find_exe): use PATH_ENV instead of "PATH". * hash.c (env_delete, rb_f_getenv, env_fetch, rb_env_path_tainted, env_aset): ditto. * ruby.c (proc_options): ditto. Fri Jun 20 14:52:46 2003 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: Tk interpreter returns TAINTED strings. Fri Jun 20 03:09:21 2003 Yukihiro Matsumoto * parse.y (new_yield): distinguish "yield 1,2" and "yield [1,2]". [ruby-dev:20360] * eval.c (rb_eval): support new_yield() change. * variable.c (rb_const_get_0): warn for Foo::BAR when BAR is a toplevel constant (i.e. a constant defined under Object). [ruby-list:36935] * parse.y (no_blockarg): separate no block argument check and ret_args argument processing. Fri Jun 20 00:45:19 2003 NAKAMURA, Hiroshi * lib/csv.rb: import csv module. Thu Jun 19 22:51:41 2003 Masatoshi SEKI * lib/drb.rb, lib/drb/drb.rb, lib/drb/eq.rb, lib/drb/extserv.rb, lib/drb/extservm.rb, lib/drb/gw.rb, lib/drb/invokemethod.rb, lib/drb/observer.rb, lib/drb/timeridconv.rb, lib/drb/unix.rb: import drb-2.0.4b3 Thu Jun 19 16:14:43 2003 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c (lib_do_one_event): change default value of the argument * ext/tcltklib/tcltklib.c (lib_do_one_event): returns true/false * ext/tcltklib/tcltklib.c: add TclTkLib::EventFlag::NONE ( == 0 ) * ext/tcltklib/tcltklib.c: add set_no_event_wait() and get_no_event_wait() * ext/tcltklib/MANUAL.euc: modify * ext/tcltklib/README.euc: ditto * ext/tk/lib/tk.rb: change default value of TkCore.do_one_event argument * ext/tk/lib/tk.rb: add TkCore.set_no_event_wait(wait) and TkCore.get_no_event_wait * ext/tk/lib/tk.rb: add Tk.exit ( == destroy root widget ) * ext/tk/lib/tkafter.rb: rename TkAfter => TkTimer (TkAfter is an alias name) * ext/tk/lib/tkafter.rb: set_callback returns self * ext/tk/lib/tkafter.rb: continue() raises an exception, if already running or no procedure. * ext/tk/lib/tkafter.rb: skip() raises an exception, if not running. * ext/tk/sample/tktimer2.rb: new sample for TkTimer class. Thu Jun 19 16:13:54 2003 WATANABE Hirofumi * rubytest.rb: add library path to include standard libraries. Thu Jun 19 13:13:10 2003 NAKAMURA Usaku * hash.c (env_delete, rb_f_getenv, env_fetch): case insensitive to access environment variables on DOSISH platforms. Thu Jun 19 00:51:47 2003 NAKAMURA, Hiroshi * range.c (rb_range_beg_len): out_of_range check after adjusting end point. [ruby-dev:20370] Wed Jun 18 23:59:11 2003 Guy Decoux * parse.y (call_args): the first argument to arg_cancat() should be NODE_LIST. [ruby-core:01151] Wed Jun 18 23:41:27 2003 Marc Cartright * ext/zlib/zlib.c (zstream_run): In a particular situation, deflate/inflate will return Z_BUF_ERROR, even though another call is required by the zlib library. Wed Jun 18 19:46:21 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb: bug fix * ext/tk/lib/tk.rb: rename 'no_create' option to 'without_creating' * ext/tk/lib/tk.rb: add TkWindow#pack_in, TkWindow#grid_in, TkWindow#place_in * ext/tk/lib/tk.rb: add TkWindow#bind_class and TkWindow#database_class * ext/tk/lib/tk.rb: add TkBindTag.new_by_name and TkDatabaseClass for binding to database class * ext/tk/lib/tk.rb: check varname whether already exsist or not. (TkVarAccess.new) * ext/tk/lib/tk.rb: TkTextWin#bbox returns an array of four numbers * ext/tk/lib/tk.rb: autoload TkDialog2, TkWarning2 * ext/tk/lib/tk.rb: scan event callback arguments and convert to proper type * ext/tk/lib/tk.rb: TkBindTag.new accepts a block * ext/tk/lib/tk.rb: If given taglist, TkWindow#bindtags(taglist) returns taglist * ext/tk/lib/tk.rb: add TkWindow#bindtags=(taglist) * ext/tk/lib/tk.rb: Tk.focue and Tk.focus_lastfor return nil if there is no target widget. * ext/tk/lib/tk.rb: Tk::Wm.client returns the argument string when setting name * ext/tk/lib/tk.rb: TkGrid.columnconfiginfo and rowconfiginfo given a slot return a number. * ext/tk/lib/tk.rb: TkWindow.grid_columnconfiginfo and grid_rowconfiginfo --- ditto * ext/tk/lib/tk.rb: rename and define alias :: TkOption ==> TkOptionDB * ext/tk/lib/tk.rb: define alias :: TkTimer ==> TkAfter * ext/tk/lib/tk.rb: some instance methods change from public to private * ext/tk/lib/tk.rb: some TkComm methods change to module functions * ext/tk/lib/tk.rb: add support for -displayof option to some TkWinfo methods * ext/tk/lib/tk.rb: bind, bind_append and bind_remove --- returns the target of event-binding * ext/tk/lib/tk.rb: add Tk8.4 features * ext/tk/lib/tk.rb: add TkPaneWindow * ext/tk/lib/tkdialog.rb: bug fix * ext/tk/lib/tkdialog.rb: some methods return self * ext/tk/lib/tkdialog.rb: add TkTextMark#+(mod) and TkTextMark#-(mod) * ext/tk/lib/tkdialog.rb: add some methods * ext/tk/lib/tkcanvas.rb: bug fix and some methods return self * ext/tk/lib/tkentry.rb: some methods return self * ext/tk/lib/tkentry.rb: TkEntry#bbox returns an array of four numbers * ext/tk/lib/tkentry.rb: scan validatecommand arguments and convert to proper type * ext/tk/lib/tkbgerror.rb: support to define a error handler by user * ext/tcltklib/tcltklib.c: [ruby-talk:60759] Wed Jun 18 13:50:06 2003 Yukihiro Matsumoto * eval.c (rb_eval): should dispatch based on ID type. Wed Jun 18 12:53:42 2003 Minero Aoki * eval.c (rb_yield_0): should restore scope_vmode during yield. [ruby-dev:20361] Wed Jun 18 01:13:36 2003 why the lucky stiff * ext/syck/rubyext.c (rb_syck_load_handler): merge key implemented. * ext/syck/rubyext.c (transfer_find_i): removed use of String#=~ in favor of Regexp#match. * lib/yaml.rb: YAML::try_implicit returns. * lib/yaml/rubytypes.rb: Regexps added for type matching. * lib/yaml/emitter.rb: fix String + nil error. Tue Jun 17 17:01:08 2003 why the lucky stiff * ext/syck/gram.c: added grammar for certain empty sequence entries. * ext/syck/handler.c, ext/syck/syck.c, ext/syck/syck.h: track bad anchors. * ext/syck/token.c: added pause token, tag possible circular references. * lib/yaml/rubytypes.rb: parsing YMD time as Date instance. * ext/syck/rubyext.c: ditto. DomainType, PrivateType, BadAlias classes. Tue Jun 17 21:28:27 2003 Ariff Abdullah * win32/win32.c (rb_w32_opendir): need to set errno. [ruby-talk:73761] Mon Jun 16 19:01:25 2003 Yukihiro Matsumoto * eval.c: remove rb_cBlock. Mon Jun 16 18:06:33 2003 WATANABE Hirofumi * numeric.c (rb_fix2uint): renamed from rb_fix2int on IA64. Mon Jun 16 17:02:57 2003 Nobuyoshi Nakada * eval.c (proc_invoke): format the message for localjump_error(). Mon Jun 16 16:23:56 2003 NAKAMURA Usaku * ext/dl/dl.c (rb_dl_callback): use rb_block_proc() instead of rb_block_new(). * ext/win32ole/win32ole.c (ev_on_event): ditto. Mon Jun 16 16:06:47 2003 Yukihiro Matsumoto * eval.c (proc_alloc): re-unification of Block and Proc. Block class is no longer available. Mon Jun 16 14:43:14 2003 WATANABE Hirofumi * bcc32/Makefile.sub: undefine HAVE_GETGROUPS. Sat Jun 14 16:58:41 2003 Guy Decoux * regex.c (calculate_must_string): should handle option_set properly. [ruby-talk:73481] * regex.c (re_compile_fastmap): a bug in flag manipulation. [ruby-talk:73549] Sat Jun 14 17:59:59 2003 Guy Decoux * eval.c (method_arity): should handle NODE_BMETHOD and NODE_DMETHOD. [ruby-core:01138] Fri Jun 13 09:24:39 2003 Shugo Maeda * lib/net/ftp.rb (storebinary): seek correctly. Thanks, William Webber. * lib/net/ftp.rb (putbinaryfile): rescue FTPPermError. Thu Jun 12 22:13:13 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb : add 'no_create' option to widget initialize method. * ext/tk/MANIFEST : forgot to commit when added tkmacpkg.rb and tkwinpkg.rb * ext/tk/lib/README : ditto. Thu Jun 12 21:14:11 2003 Hidetoshi NAGAI * ext/tk/lib/tk.rb : widget configure returns self (for method call chain) * ext/tk/lib/tkmacpkg.rb : Mac resource (not new but not included until now) * ext/tk/lib/tkwinpkg.rb : Win DDE and registry (not new but not included until now) Tue Jun 10 14:26:30 2003 why the lucky stiff * ext/syck/token.c: preserve newlines prepended to a block. * ext/syck/implicit.c (syck_match_implicit): added !merge and !default. * lib/yaml/constants.rb: remove '\z' escape. * lib/yaml/emitter.rb: ensure reset of @seq_map shortcut flag. * lib/yaml/encoding.rb: remove Unicode translation methods. * lib/yaml/rubytypes.rb: improved round-tripping of Strings. [ruby-core:1134] Tue Jun 10 01:07:54 2003 Yukihiro Matsumoto * lib/irb.rb (IRB::Irb::eval_input): warn and exit if $SAFE >=3 after input evaluation. * lib/irb.rb (IRB::Irb::eval_input): untaint input string. now irb works for levels 1 and 2. Mon Jun 9 19:02:33 2003 Nobuyoshi Nakada * configure.in: checks presence of grp.h and setgroups(). * process.c (proc_getgroups, proc_setgroups): raise NotImplementedError unless available. [ruby-talk:73014] Mon Jun 9 18:09:11 2003 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: fixed 100% CPU problem of Tk.mainloop Mon Jun 9 15:50:24 2003 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: renewal Tk.mainloop Sun Jun 8 13:37:21 2003 Takaaki Uematsu * wince/setup.mak: set SUBSYSTEM in each platform. * wince/stdlib.c: fix mblen() bug. Sat Jun 7 22:22:03 2003 Yukihiro Matsumoto * ext/syck/rubyext.c (syck_loader_transfer): should not use rb_cProc directly, since type_proc may be Proc, Block, or Method. * parse.y (value_expr0): class and module statements should not be warned for "void value expression". [ruby-talk:72989] Sat Jun 7 01:46:41 2003 Yukihiro Matsumoto * gc.c (add_final): should determine type by respond_to? * gc.c (define_final): ditto. * io.c (rb_io_ctl): should not depend on respond_to? * range.c (range_step): rb_check_string_type(). Fri Jun 6 20:29:14 2003 Nobuyoshi Nakada * eval.c (error_print): needs to be exception proof. * eval.c (error_handle, rb_longjmp): bails out when exception reentered. (ruby-bugs-ja:PR#487), [ruby-core:01119], [ruby-core:01122] * eval.c (Init_Proc): pre-allocates critical error objects. Fri Jun 6 20:29:14 2003 Nobuyoshi Nakada * parse.y (cmd_brace_block, do_block, brace_block): initialize block variables at the beginning of the block. [ruby-talk:72521] Fri Jun 6 18:49:11 2003 Yukihiro Matsumoto * process.c (proc_setgroups): new functions. Fri Jun 6 18:33:27 2003 Yukihiro Matsumoto * gc.c (define_final): eliminate rb_f_lambda() call. * class.c (rb_scan_args): ditto. * signal.c (sig_trap): ditto. * hash.c (rb_hash_initialize): ditto. * variable.c (rb_f_trace_var): ditto. * ext/dl/dl.c (rb_dl_callback): ditto. * ext/win32ole/win32ole.c (ev_on_event): ditto. Fri Jun 6 16:10:01 2003 Minero Aoki * lib/net/http.rb: define Net::HTTPResponse#to_ary for backward compatibility. [ruby-talk:72927] * lib/net/protocol.rb: add warning. Fri Jun 6 13:30:57 2003 Yukihiro Matsumoto * eval.c (ruby_cleanup): $SAFE is turned off in the finalization. Each END proc should preserve its own $SAFE level. [ruby-core:01119] * marshal.c (marshal_load): remove unused variable "hash". [ruby-core:01120] * hash.c (env_str_new): freeze strings from ENV. [ruby-talk:72860] * array.c (rb_ary_first): optional argument to retrieve first n elements. * array.c (rb_ary_last): optional argument to retrieve last n elements. Thu Jun 5 21:31:55 2003 Takaaki Uematsu * wince/stdlib.c: add mblen(). Thu Jun 5 18:33:46 2003 WATANABE Hirofumi * ext/curses/curses.c (window_s_allocate,curses_finalize): avoid VC++ warnings. Thu Jun 5 17:44:11 2003 why the lucky stiff * ext/syck/rubyext.c (syck_parser_mark): was a bit heavy on the GC. * lib/yaml.rb (YAML::transfer): added. Thu Jun 5 16:11:50 2003 NAKAMURA Usaku * bcc32/Makefile.sub, win32/Makefile.sub, wince/Makefile.sub (MISSING): link with missing/erf.c. * missing.h (erf, erfc): fix prototype. * missing/erf.c: new. [ruby-list:37753] Thu Jun 5 15:09:06 2003 Yukihiro Matsumoto * math.c (math_erf,math_erfc): new function. [ruby-list:37753] Thu Jun 5 14:49:43 2003 why the lucky stiff * ext/syck/rubyext.c: using GC nodes caused segfault. [ruby-core:1071] Thu Jun 5 13:48:57 2003 why the lucky stiff * ext/syck/token.c: directives choked on a period. * ext/syck/gram.y: anchors work above a collection. [ruby-core:1071] * ext/syck/handler.c, ext/syck/syck.c: ensure a fresh strtable between parser iterations. Wed Jun 4 12:06:59 2003 Yukihiro Matsumoto * eval.c (ruby_finalize): no longer need to turn off $DEBUG in the finalizer. (ruby-bugs-ja PR#473) Tue Jun 3 22:20:49 2003 Yukihiro Matsumoto * eval.c (rb_call_super): should search superclass method based on orig_func, not last_func. Tue Jun 3 09:59:27 2003 Yukihiro Matsumoto * eval.c (rb_call_super): inheritance line adjustment moved from rb_call(). [ruby-core:01113] * eval.c (rb_eval): use rb_call_super() to follow DRY principle. Mon Jun 2 02:20:52 2003 Yukihiro Matsumoto * array.c (push_values_at): Array#values_at should work with ranges too. * range.c (rb_range_beg_len): length calculation was wrong. * eval.c (rb_call): should set T_ICLASS in the frame->last_class. [ruby-core:01110] Sun Jun 1 21:50:01 2003 WATANABE Hirofumi * configure.in: should not use def file, use ld with --export-all-symbols option on Cygwin/MinGW. * defines.h: ditto. * cygwin/GNUmakefile.in: ditto. * ext/digest/defs.h: avoid warnings on Cygwin. Sun Jun 01 13:33:49 2003 Takaaki Uematsu * wince/string_wce.c: add strpbrk() for hpcpro support. * wince/setup.mak: add hpcpro(CE2.11) & armv4t(CE.NET) support. * wince/resource.rb: ditto. * wince/Makefile.sub: ditto. Sun Jun 1 10:38:28 2003 Nobuyoshi Nakada * variable.c (rb_autoload_load): autoloaded constants under a module belong to the module. [ruby-core:01094], [ruby-dev:20309] Sat May 31 04:36:54 2003 Nobuyoshi Nakada * parse.y (rb_intern): should handle multibyte name. Fri May 30 23:18:01 2003 why the lucky stiff * ext/syck/rubyext.c (rb_syck_mktime): seconds calculated wrong. * ext/syck/gram.c: flexibility to anchors and transfer methods on collections. * ext/syck/token.c: hex escapes. * lib/yaml/basenode.rb: YamlNode references changed to YAML::BaseNode. Fri May 30 22:28:04 2003 Nobuyoshi Nakada * numeric.c (rb_num2uint, rb_fix2int): new function to convert values over INT_MAX. [ruby-core:01099] * ruby.h (NUM2UINT, FIX2INT): ditto. Fri May 30 15:01:05 2003 why the lucky stiff * ext/syck/token.c: preserve any indentation past an explicit indentation. Fri May 30 14:55:44 2003 Nobuyoshi Nakada * eval.c (rb_Array): exclude Kernel#to_a instead of Object#to_a. (ruby-bugs-ja:PR#483) * lib/optparse.rb (OptionParser::Switch#parse_arg): not splat. * lib/optparse.rb (OptionParser::Switch#conv_arg): splat if no conversion supplied. * lib/optparse.rb (OptionParser::Switch::PlacedArgument#parse): override next switch after argument conversion. Fri May 30 14:41:34 2003 why the lucky stiff * ext/syck/handler.c, ext/syck/syck.h: removed syck_fold_format(). * ext/syck/gram.c: flexibility for aliases and anchors. * ext/syck/token.c: folding now handled in the tokenizer. Fri May 30 06:21:18 2003 Nobuyoshi Nakada * variable.c (rb_autoload_load): should delete autoloaded symbol itself before load. [ruby-core:01097] * variable.c (rb_mod_remove_const): must not return Qundef. Thu May 29 14:59:10 2003 WATANABE Hirofumi * win32/win32.c (_CRTIMP): redefine _CRTIMP on MinGW. * configure.in: remove '-D__USE_CRTIMP' from XCFLAGS on MinGW. * win32/win32.c (NtMakeCmdVector): handle quotes only if not instring. Thu May 29 09:11:01 2003 Nobuyoshi Nakada * eval.c (ev_const_defined, ev_const_get), variable.c (rb_const_get_at, rb_const_get, rb_mod_remove_const): use Qundef as autoload marker. [ruby-dev:18103], [ruby-dev:18184] * eval.c (rb_mod_autoload, rb_mod_autoload_p): new method; Module#autoload, Module#autoload?. * variable.c (rb_autoload, rb_autoload_load, rb_autoload_p): manage autoload constants per classes/modules. * variable.c (rb_const_defined_at, rb_const_defined): return false for autoloading constants. * class.c (rb_define_class, rb_define_module), eval.c (rb_eval), variable.c (rb_mod_const_at, rb_const_assign): removed autoload stuff. * intern.h: prototypes; rb_autoload, rb_autoload_load, rb_autoload_p. * lib/optparse.rb (OptionParser::Switch::PlacedArgument::parse): do not treat unmatched argument as an option. Wed May 28 08:44:26 2003 Yukihiro Matsumoto * io.c (rb_f_syscall): type dispatch should be based on rb_check_string_type(), not FIXNUM_P(), because values may be a bignum. [ruby-talk:72257] Tue May 27 20:33:18 2003 Nobuyoshi Nakada * eval.c, util.c: removed duplicated includes/defines. * ext/socket/socket.c (sock_addrinfo): get rid of SEGV at NULL ptr String. increase buffer size for 64bit platforms. Tue May 27 02:34:14 2003 Yukihiro Matsumoto * eval.c (rb_call0): should pass the current klass value to block_invoke, which may be called via "super". [ruby-core:01077] * eval.c (block_invoke): now takes 4th argument "klass". * eval.c (block_alloc): should propagate BLOCK_PROC to ruby_block. Mon May 26 23:51:38 2003 Yukihiro Matsumoto * marshal.c (r_object0): should not use "yield" method, use "call" instead. (ruby-bugs-ja PR#476) Mon May 26 21:39:46 2003 MoonWolf * lib/mkmf.rb, lib/optparse.rb, lib/tracer.rb: use Method#to_block instead of deprecated Method#to_proc. (ruby-bugs-ja:PR#477) Mon May 26 21:21:20 2003 Nobuyoshi Nakada * lib/optparse.rb (OptionParser::Switch::parse, OptionParser::order): use {Block,Proc}#call instead of deprecated #yield. Mon May 26 16:39:10 2003 Yukihiro Matsumoto * eval.c (Init_Proc): Block/Proc separation. [huge change] * eval.c (block_arity): returns exact arity number for Procs out of methods. also gives 1 for {|a|..}. * string.c (rb_str_match): revert use of String#index for invocation like string =~ string. * eval.c (rb_Array): move Object#to_a exclusion hack from splat_value(). need to be in eval.c for a while. Sun May 25 23:48:21 2003 Nobuyoshi Nakada * bignum.c (rb_quad_pack): should negate negative bignum. (ruby-bugs-ja:PR#474) Sun May 25 03:27:25 2003 Minero Aoki * lib/net/smtp.rb: support LOGIN authentication, based on the patch by Kazuhiko Izawa. [ruby-talk:78981] Sat May 24 18:19:51 2003 Takaaki Uematsu * wince/Makefile.sub: add eMbedded Visual C++ 4.0 support. * wince/resource.rb: ditto. * wince/setup.mak: ditto. * wince/configure.bat: ditto. * wince/mkexports.rb: delete japanese comments. Fri May 23 18:34:05 2003 Nobuyoshi Nakada * eval.c (rb_longjmp): get rid of reentering while debug warning. (ruby-bugs-ja:PR473) Fri May 23 15:16:16 2003 Nobuyoshi Nakada * pack.c (pack_unpack): sign-extend if sizeof long is bigger than 32. (ruby-bugs-ja:PR#472) Fri May 23 14:19:29 2003 Yukihiro Matsumoto * eval.c (ruby_finalize): turn off ruby_debug flag before calling at_exit procs and finalizers. (ruby-bugs-ja:PR473) * ext/tcltklib/tcltklib.c (lib_mainloop_core): OK to block if there's no other thread. (ruby-bugs:PR#861) Thu May 22 18:07:46 2003 why the lucky stiff * ext/syck/token.c: single- and double-quoted root-level fix. * lib/yaml.rb (YAML::object_maker): can create object attributes (such as found in Exception class) * lib/yaml/rubytypes.rb: roundtripping of Exception and subclasses. Fri May 23 01:26:26 2003 Yukihiro Matsumoto * object.c (rb_obj_clone): defer copying freezing state after calling initialize_copy(). [ruby-dev:20276] Thu May 22 17:12:10 2003 Yukihiro Matsumoto * gc.c (run_final): use rb_thread_critical instead of DEFER_INTS. [ruby-dev:20272] * marshal.c: try to make ArgumentError and TypeError consistent. [ruby-core:01068] Thu May 22 15:46:37 2003 Yukihiro Matsumoto * eval.c (rb_define_alloc_func): need not to disable rb_call_super() for allocation functions. [ruby-core:1065] Thu May 22 06:21:33 2003 why the lucky stiff * ext/syck/rubyext.c (rb_syck_err_handler): raise ArgumentError on malformed YAML. * lib/yaml/rubytypes.rb: String#to_yaml was missing space indicators at the end of a line. Thu May 22 05:43:24 2003 why the lucky stiff * ext/syck/rubyext.c (syck_parser_load): root-level false was returning nil. * ext/syck/token.c: root-level transfer method bug. * ext/syck/gram.c: root-level empty gave a parse error. * lib/yaml/rubytypes.rb: Symbol#to_yaml generating method call error. Thu May 22 02:46:38 2003 Nobuyoshi Nakada * eval.c (rb_eval): splat NODE_RESTARY. [ruby-dev:20268] * eval.c (rb_thread_fd_close): raise for writing threads. [ruby-dev:20269] * io.c (rb_io_close, io_reopen): ditto. * io.c (io_reopen): keep stdio objects for stdin, stdout, and stderr. [ruby-dev:19442] Thu May 22 01:11:15 2003 Nobuyoshi Nakada * parse.y (strings, word_list): must create new instance always. http://yowaken.dip.jp/tdiary/20030521.html#p02 * parse.y (yylex): slight optimization. Wed May 21 23:07:08 2003 Yukihiro Matsumoto * error.c (rb_sys_fail): should not specify errno explicitly. [ruby-dev:20264] Wed May 21 20:51:47 2003 Nobuyoshi Nakada * Makefile.in, bcc32/Makefile.sub, win32/Makefile.sub, wince/Makefile.sub: update dependencies. Wed May 21 17:44:16 2003 Yukihiro Matsumoto * error.c (syserr_initialize): prohibit specifying errno for subclasses of SystemCallError. in addition, if initialize is called for SystenCallError instance, its class be changed. [ruby-dev:20257] * gc.c (run_final): to protect thread context switch, finalizers are wrapped in DEFER_INTS/ENABLE_INTS. Wed May 21 13:26:08 2003 Nobuyoshi Nakada * lib/optparse.rb: get rid of warnings. Tue May 20 18:59:54 2003 Yukihiro Matsumoto * eval.c (rb_thread_save_context): prohibit rb_gc_force_recycle() on thread saved ruby_dyna_vars. [ruby-dev:20236] Tue May 20 17:39:15 2003 Yukihiro Matsumoto * object.c (init_copy): call initialize_copy at the end of copy process. Tue May 20 17:15:55 2003 Nobuyoshi Nakada * error.c (syserr_initialize): use Errno constants as default errno for subclasses. [ruby-dev:20241] Tue May 20 15:26:25 2003 WATANABE Hirofumi * st.h: define ST_DATA_T_DEFINED for portability. * ext/syck/syck.h: add typedef, st_data_t for Ruby 1.6. * ext/syck/syck.c (syck_st_free_nodes): return int. * ext/syck/syck.c (syck_add_sym): cast the data to st_data_t to avoid error on bcc32. * ext/syck/syck.c (syck_lookup_sym): ditto. * ext/syck/syck.c (syck_free_parser): NULL is not integer. Tue May 20 13:29:04 2003 NAKAMURA Usaku * win32/win32.c (kill): set errno after calling raise(). Tue May 20 10:51:26 2003 Nobuyoshi Nakada * eval.c (rb_f_missing): create exception instance by ordinal method. [ruby-dev:20033] * error.c (rb_name_error, rb_sys_fail): ditto. * error.c (exc_to_s, exit_status, name_err_name, nometh_err_args, syserr_errno, syserr_eqq): access attributes. * error.c (name_err_initialize, nometh_err_initialize, syserr_initialize): initialize attributes. Tue May 20 10:26:56 2003 Yukihiro Matsumoto * eval.c (rb_yield_0): give warning for multiple values for a block parameter. * eval.c (rb_yield_values): a function to yield multiple values. * array.c (sort_1): use rb_yield_values. * enum.c (min_ii, max_ii): ditto. * hash.c (rb_hash_update_block_i, delete_if_i, select_i, each_pair_i, env_each, env_reject_bang, env_select, env_update_i): ditto. * struct.c (rb_struct_each_pair): ditto. * eval.c (top_include): should include module in the current self, not ruby_top_self. [ruby-dev:20198] * eval.c (top_include): stop inclusion to ruby_wrapper; give warning. Mon May 19 18:54:30 2003 why the lucky stiff * ext/syck/token.c, ext/syck/implicit.c: expanded character set to allow UTF-8, other Ruby encodings. Mon May 19 16:47:00 2003 why the lucky stiff * ext/syck/syck.c, ext/syck/syck.h, ext/syck/token.c, ext/syck/gram.c: count line numbers only if line pointer has increased. Tue May 20 00:45:40 2003 Yukihiro Matsumoto * dir.c (push_braces): do not push_braces() unless rbrace is found. (ruby-bugs-ja:PR#469) Tue May 20 00:09:41 2003 Yukihiro Matsumoto * ext/pty/pty.c (pty_finalize_syswait): join (using Thread#value) before detach pid. [ruby-talk:71519] Mon May 19 23:02:10 2003 Yukihiro Matsumoto * eval.c (PUSH_FRAME): save outer ruby_block. [ruby-list:37677], [ruby-dev:20202] * eval.c (BEGIN_CALLARGS): restore outer block by using ruby_block->outer. * eval.c (block_pass): do not alter block->prev, but block->outer. * array.c (get_inspect_tbl): warning on wrong condition. Mon May 19 16:13:57 2003 Minero Aoki * class.c: add #include "version.h". * hash.c: ditto. * string.c: ditto. Mon May 19 15:33:27 2003 Yukihiro Matsumoto * eval.c (localjump_xvalue): renamed exitstatus to exit_value since it's not exit "status" after all. * eval.c (localjump_error): add reason to LocalJumpError. * compar.c (rb_cmpint): raise error via rb_cmperr(), if cmp value is nil. now take new 2 arguments. * time.c (time_cmp): 2003-05-16 fix was incomplete. (ruby-bugs-ja:PR#458) Mon May 19 14:42:50 2003 Yukihiro Matsumoto * object.c (rb_mod_cmp): stupid comparison fixed. * io.c (Init_IO): ARGF.path added (alias to ARGF.filename). [ruby-dev:20197] Mon May 19 13:58:03 2003 Yukihiro Matsumoto * object.c (init_copy): rename copy_object as initialize_copy, since it works as copy constructor. * eval.c (rb_add_method): initialize_copy should always be private, like initialize. Mon May 19 13:51:50 2003 Minero Aoki * re.c (rb_reg_quote): \n \r \f \v quoting was wrong. [ruby-dev:20203] * re.c (rb_reg_quote): rb_reg_quote(" ") should be "\\ ", not "\\s". Mon May 19 08:08:51 2003 Tadayoshi Funaba * lib/date.rb: use warn() instead of $stderr.puts(). * sample/cal.rb: ditto. Sat May 17 12:02:25 2003 Yukihiro Matsumoto * array.c (get_inspect_tbl): check whether inspect_tbl value is a valid array. (ruby-bugs-ja PR#65) * array.c (inspect_ensure,rb_protect_inspect,rb_inspecting_p): use get_inspect_tbl(). Sat May 17 11:50:26 2003 Yukihiro Matsumoto * eval.c (rb_f_abort): call exit(1) if exception is raised. This patch was made by Nobuyoshi Nakada on 2002-05-30. (ruby-bugs-ja PR#236) * signal.c: disable Ruby's interrupt handler at the beginning. (ruby-bugs-ja PR#236) Sat May 17 02:17:42 2003 Nobuyoshi Nakada * lib/rational.rb (Integer::denominator): fixed typo. (ruby-bugs-ja:PR#466) Sat May 17 00:18:11 2003 Nobuyoshi Nakada * ext/socket/socket.c (ruby_connect): connect() after EINPROGRESS returns EINVAL on some platforms, need to check true error status. [ruby-core:01037] Sat May 17 00:21:51 2003 Yukihiro Matsumoto * object.c (rb_class_allocate_instance): singleton class check moved to rb_obj_alloc(). (ruby-bugs-ja PR#345) Fri May 16 23:55:50 2003 Yukihiro Matsumoto * re.c (rb_reg_quote): should escape white space characters, \t, \f, \n, \r. (ruby-bugs-ja PR#231) Fri May 16 12:40:40 2003 Yukihiro Matsumoto * eval.c (block_pass): chain previous block to the pushing block. [ruby-list:37677] * time.c (time_cmp): does not compare with numbers for interchangeability. (ruby-bugs-ja:PR#458) Thu May 15 21:55:54 2003 why the lucky stiff * ext/syck/gram.c: fixes to one-line documents and end of stream documents. * ext/syck/syck.c, ext/syck/syck.h: add root_on_error to parser struct, specifying the symbol to be returned on a parse error. Thu May 15 18:44:31 2003 Tanaka Akira * lib/open-uri.rb (OpenURI::Redirect#initialize): call super to initialize mesg. * lib/open-uri.rb (OpenURI::Meta#charset): call block to guess charset if block is given and charset is not given. Thu May 15 16:55:16 2003 Yukihiro Matsumoto * object.c (rb_mod_le): returns nil if two classes/modules are not in class-superclass relationship. * object.c (rb_mod_cmp): uses new rb_mod_le() behavior. Thu May 15 07:45:30 2003 why the lucky stiff * ext/syck/rubyext.c, ext/syck/implicit.c: timestamp repairs to timezone and milliseconds. * ext/syck/syck.c (syck_parser_reset_levels): duplicate string literal to avoid warning. Thu May 15 13:26:48 2003 Yukihiro Matsumoto * class.c (rb_class_instance_methods): default will be changed in 1.8.1. * io.c (set_stdio): better message. Thu May 15 13:18:11 2003 Yukihiro Matsumoto * io.c (set_stdio): $stdin, $stdout, $stderr now became read-only. * variable.c (readonly_setter): message changed. Thu May 15 09:50:51 2003 NAKAMURA Usaku * ext/syck/syck.c (syck_parser_pop_level): add prototype. * ext/syck/syck.c (syck_strndup): should return value. Thu May 15 09:32:25 2003 NAKAMURA Usaku * win32/win32.c (kill): fix typo and add signal 0 support. Wed May 14 20:09:26 2003 why the lucky stiff * ext/syck/gram.c: sequence-in-map shortcut, transfer methods on sequence-in-sequence, memory leak in mapping merge. * ext/syck/syck.c: memory leak in domain anchoring. * lib/yaml/rubytypes.rb, lib/yaml/types.rb: eliminated 1.6.x code. Wed May 14 19:56:43 2003 NAKAMURA Usaku * ext/syck/rubyext.c: add prototypes to avoid VC++ warnings. Wed May 14 12:23:46 2003 Minero Aoki * lib/net/http.rb (Net::HTTP#start): should check whether HTTP session is opened before finishing. (ruby-bugs-ja:PR#463) Wed May 14 09:12:55 2003 Minero Aoki * lib/net/http.rb: reduce warning. (ruby-bugs-ja:PR#462) Tue May 13 22:31:04 2003 why the lucky stiff * lib/yaml/rubytypes.rb, lib/yaml/types.rb: using Object#object_id rather than deprecated Object#id. * ext/syck/token.c: changed ASCII escapes to octal notation. * ext/Setup*: added entries for static linking of Syck extension. Tue May 13 20:31:58 2003 WATANABE Hirofumi * configure.in: add '--Wl,--enable-auto-import' to DLDFLAGS on Cygwin/MinGW. * configure.in: add '-D__USE_CRTIMP' to XCFLAGS on MinGW. * ext/syck/handler.c: add proper casts. * ext/syck/syck.c: ditto. Tue May 13 17:58:08 2003 NAKAMURA Usaku * configure.in, bcc32/Makefile.sub, win32/Makefile.sub: define HAVE_FSYNC. * win32/win32.h (fsync): define as _commit(). Tue May 13 15:35:35 2003 Yukihiro Matsumoto * regex.c (re_match_exec): \Z changed to be consistent with new $ (endbuf) behavior. Tue May 13 14:48:07 2003 Yukihiro Matsumoto * eval.c (error_pos): use $deferr for output instead of stderr directly. * eval.c (error_print,error_handle,rb_longjmp,rb_thread_schedule): ditto. Tue May 13 06:34:19 2003 why the lucky stiff * lib/yaml/rubytypes.rb: object and struct loading * lib/yaml.rb: YAML::detect_implicit will discover typing for a Ruby string * ext/syck/: Fixed portable comments, misuse of NULL and methods without return VALUEs. Mon May 12 18:08:21 2003 Yukihiro Matsumoto * io.c (Init_IO): new variable $deferr which is default output port of error messages. * io.c (rb_warn_m): new method "warn". [new] * error.c (warn_print): use $deferr. * error.c (rb_bug): ditto. * error.c (err_append): ditto. Sun May 11 13:50:12 2003 Tanaka Akira * lib/pp.rb: refine to_s test. * lib/pp.rb (PP::ObjectMixin#pretty_print): refine to_s handling. Sun May 11 06:32:13 2003 why the lucky stiff * ext/syck/implicit.c, ext/syck/rubyext.c: transfer methods applied to native loading * ext/syck/token.c: fix for transfer methods on same indentation as nested mapping * lib/yaml/rubytypes.rb: all type names in lowercase Sat May 10 19:55:18 2003 why the lucky stiff * ext/syck/gram.c ext/syck/handler.c ext/syck/implicit.c ext/syck/node.c ext/syck/rubyext.c ext/syck/syck.c ext/syck/syck.h ext/syck/token.c: updated to Syck 0.27 * lib/yaml/loader.rb: new YAML::Loader class * lib/yaml.rb: loading of type families leverages YAML::DefaultLoader Sat May 10 19:00:08 2003 Takaaki Uematsu * wince/string.c: file removed. * wince/stdlib.c: file added. Sat May 10 16:17:02 2003 Shugo Maeda * lib/net/imap.rb (decode_utf7): new method. * lib/net/imap.rb (encode_utf7): new method. Fri May 9 21:25:50 2003 why the lucky stiff * ruby/ext/syck, ruby/lib/yaml: Initial checkin of YAML substances. Fri May 9 16:38:30 2003 Yukihiro Matsumoto * io.c (rb_io_reopen): It should be possible to reopen closed IO. [ruby-talk:70941] * io.c (rb_io_reopen): inherit original file mode unless specified. Thu May 8 18:44:09 2003 Yukihiro Matsumoto * gc.c (rb_gc): check odd alignment stack on m68k machines. Thu May 8 12:56:04 2003 Nobuyoshi Nakada * compar.c (rb_cmperr): raise comparison failure. * intern.h: prototype; rb_cmperr * numeric.c (flo_gt, flo_ge, flo_lt, flo_le, fix_gt, fix_ge, fix_lt, fix_le): should fail unless the argument is comparable. (ruby-bugs-ja:PR#456) * numeric.c (int_upto, int_downto): should fail unless the argument is comparable. (ruby-bugs-ja:PR#454) Wed May 7 13:30:11 2003 Masahiro TANAKA * numeric.c (num_step): better error treatment of float values. Tue May 6 17:51:54 2003 Minero Aoki * lib/net/pop.rb: rename method: POP3#mail_size -> n_mails * lib/net/pop.rb: rename method: POP3#bytes -> n_bytes Tue May 6 17:21:01 2003 Minero Aoki * ext/bigdecimal/.cvsignore: new file. * ext/zlib/.cvsignore: new file. Tue May 6 14:39:36 2003 Yukihiro Matsumoto * object.c (rb_obj_methods): list singleton methods if recur argument is false; list all methods otherwise. Mon May 5 21:19:25 2003 Koji Arai * ext/gdbm/gdbm.c (fgdbm_values_at): new method to replace select(index..). * ext/sdbm/init.c (fsdbm_values_at): ditto. * ext/dbm/dbm.c (fdbm_values_at): ditto. * ext/dbm/dbm.c (DBM::VERSION): defined. * ext/gdbm/testgdbm.rb: replace select with values_at. * ext/sdbm/testsdbm.rb: ditto. * ext/dbm/testdbm.rb: ditto. * ext/dbm/testdbm.rb (setup): DBM.open(path, 0400) cause EACCESS on Berkeley DB[234]. Mon May 5 22:57:07 2003 Tadayoshi Funaba * sample/cal.rb: use values_at instead of select. * sample/biorhythm.rb: ditto. Mon May 5 18:59:45 2003 WATANABE Hirofumi * sample/test.rb: substitute 'select' with 'values_at'. * lib/date.rb: ditto. * lib/parsedate.rb: ditto. Mon May 5 00:46:10 2003 Yukihiro Matsumoto * array.c (rb_ary_values_at): new method to replace select(index..). * hash.c (rb_hash_values_at,env_values_at): ditto. * re.c (match_values_at): ditto. * struct.c (rb_struct_values_at): ditto. * re.c (match_select): add iterator behavior. Sun May 4 19:08:53 2003 Tadayoshi Funaba * lib/date/format.rb: synchronized with date2 3.3.2. Sun May 4 15:21:18 2003 Minero Aoki * lib/net/smtp.rb: ESMTP -> SMTP transition wrongly fails. Sun May 4 15:06:37 2003 Minero Aoki * lib/net/pop.rb: APOP did not work. [ruby-dev:20149] Sat May 3 21:14:29 2003 Johan Holmberg * ext/curses/curses.c, ext/digest/sha2/sha2.c, ext/iconv/iconv.c, ext/racc/cparse/cparse.c: include "ruby.h" at the top to shut up "_FILE_OFFSET_BITS redefined" warning on Solaris. Sat May 3 11:00:12 2003 Yukihiro Matsumoto * class.c (rb_class_protected_instance_methods): now gives warnings to show migration path. The default will be reversed on Jan 2004. Sat May 3 00:58:53 2003 Yukihiro Matsumoto * object.c (rb_obj_methods): now accepts recurse parameter. * lib/delegate.rb (Delegator::initialize): instance_methods etc. now recurse by default. need to specify false. Sat May 3 00:22:00 2003 Minero Aoki * lib/net/protocol.rb: reintroduce Protocol.protocol_param. * lib/net/http.rb: ditto. * lib/net/pop.rb: ditto. * lib/net/smtp.rb: ditto. Fri May 2 23:29:53 2003 Minero Aoki * lib/net/protocol.rb: remove Protocol class. * lib/net/smtp.rb (SMTP): ditto. * lib/net/pop.rb (POP3): ditto. * lib/net/http.rb (HTTP): ditto. * lib/net/protocol.rb: remove Command class. * lib/net/smtp.rb (SMTPCommand): ditto. * lib/net/pop.rb (POP3Command): ditto. * lib/net/pop.rb: remove APOPCommand class. * lib/net/protocol.rb: remove Code class and its all subclasses. * lib/net/protocol.rb: remove Response class and its all subclasses. * lib/net/pop.rb (POPMail): new method unique_id (alias uidl). Fri May 2 18:17:37 2003 Yukihiro Matsumoto * compar.c (cmp_gt): raises ArgumentError when "<=>" give nil. inspired by discussion on comp.lang.python. Fri May 2 17:37:01 2003 Yukihiro Matsumoto * lib/cgi/session.rb (CGI::Session::initialize): updated to support 2003-04-23 change in cgi.rb [ruby-core:1002] Fri May 2 17:21:02 2003 Yukihiro Matsumoto * class.c (method_list): classify methods based on nearest visibility. [ruby-dev:20127] * class.c (rb_class_instance_methods): recurse by default. other method listing methods as well. Fri May 2 09:38:06 2003 Warren Brown * string.c (rb_str_ljust): now takes optional argument to specify pad string. [ruby-talk:70482] * string.c (rb_str_rjust): ditto. * string.c (rb_str_center): ditto. * string.c (rb_str_justify): utility function. Fri May 2 04:10:59 2003 Yukihiro Matsumoto * eval.c (rb_add_method): call singleton_method_added or method_added for every method definition (after ruby_running). [ruby-talk:70471] * array.c (rb_ary_reverse_bang): Array#reverse! should not return nil even for arrays sized less than 2. Thu May 1 23:18:01 2003 Yukihiro Matsumoto * io.c (argf_eof): should not block after reading all argument files. (ruby-bugs-ja PR#449) Fri May 2 15:10:41 2003 Minero Aoki * lib/fileutils.rb: use hashes to pass options. * lib/fileutils.rb: new option mkdir(:mode), mkdir_p(:mode). * instruby.rb: follow fileutils.rb feature change. Thu May 1 08:24:00 2003 Yukihiro Matsumoto * regex.c (re_match_exec): $ _always_ matches at the end of string. Wed Apr 30 14:12:00 2003 wanowa.kimura@nifty.ne.jp (kimura wataru) * net/imap.rb: support THREAD extension. Sun Apr 27 23:13:20 2003 Nobuyoshi Nakada * string.c (rb_str_to_i): disallow negative radix. [ruby-dev:20087] Sat Apr 26 23:34:42 2003 Yukihiro Matsumoto * parse.y (open_args): warning message changed to "don't put space before argument parentheses". Sat Apr 26 14:25:00 2003 Takaaki Uematsu * wince/ : files removed. (config, dll.mak, exe.mak, mswince-ruby17.def, io.c, process.c, signal.c, string.c, time.c) * wince/ : files added. (assert.c, Makefile.sub, mkexports.rb, io_wce.c, process_wce.c, signal_wce.c, string_wce.c, time_wce.c) * wince/configure.bat : like mswin32 style. * wince/direct.c : remove "static" at _currentdir. * wince/io.h : change definition. * wince/stdio.c : _fdopen -> fdopen. * wince/process.h : add _P_OVERLAY. * wince/time.h : change definition. * wince/wincemain.c : add wce_SetCurrentDir. * wince/wince.c : add wce_SetCurrentDir and wce_fopen. fix GetModuleFileNameA to return correct "lpFileName". * wince/wince.h : remove #ifdef. * wince/sys/utime.h, utime.c : rename _utime to utime. * wince/sys/stat.c : expand relative directory in stat. Sat Apr 26 06:33:04 2003 Yukihiro Matsumoto * io.c (argf_read): ARGF.read() should read all argument files. Fri Apr 25 18:46:00 2003 Takaaki Uematsu * gc.c: STACK_LEVEL_MAX=65535 on mswince. Fri Apr 25 18:40:07 2003 Yukihiro Matsumoto * io.c (argf_read): read should not span two files. [ruby-dev:20073] Fri Apr 25 18:19:03 2003 Yukihiro Matsumoto * eval.c (splat_value): split splat_value() and avalue_splat(). * io.c: there's no way to set non-IO value to current_file, thus no need for argf_forward(). Fri Apr 25 02:03:25 2003 Yukihiro Matsumoto * eval.c (proc_invoke): Proc#yield should pass through retry and break like keyword yield. [ruby-talk:70034] * eval.c (proc_invoke): orphan Proc now raises LocalJumpError for break and retry again. * eval.c (rb_eval): ARGSCAT should splat the argument. * eval.c (splat_value): splat operation function. Thu Apr 24 23:37:02 2003 Dave Thomas * lib/matrix.rb (Matrix#minor): Used Range#size, which no longer exists. * lib/complex.rb (new!): Complex.new had been made private, but Kernel#Complex called it. Re-exposed as new!. * lib/matrix.rb (Matrix.row_vector): Fix method name typo Thu Apr 24 19:40:02 2003 WATANABE Hirofumi * ext/extmk.rb: add -Wl,--no-undefined to LDSHARED only if GNU ld is 2.11 or later. Wed Apr 23 14:05:40 2003 Dave Thomas * lib/ipaddr.rb (include?): Support non-IPAddr parameters. [ruby-core:00980] Wed Apr 23 13:31:10 2003 Yukihiro Matsumoto * lib/cgi.rb (CGI::QueryExtension::[]): always return Value object. Wed Apr 23 08:39:27 2003 Nobuyoshi Nakada * ext/zlib/extconf.rb: bccwin32 is win32 too. Tue Apr 22 20:58:00 2003 Takaaki Uematsu * ruby.c: don't call VirtualQuery in ruby_init_loadpath() on mswince. Tue Apr 22 19:08:53 2003 Nobuyoshi Nakada * marshal.c (save_mantissa, load_mantissa): for interoperability should count cut-down bit from topmost. Tue Apr 22 09:20:40 2003 Yukihiro Matsumoto * parse.y (arg_ambiguous): hopefully better message. * lib/cgi.rb (CGI::QueryExtension::initialize_query): to_ary removed. Tue Apr 22 06:06:22 2003 Tanaka Akira * lib/resolv.rb (Resolv::DNS::Resource#hash): use XOR to accumulate hash value. * lib/tsort.rb (TSort#each_strongly_connected_component): don't use block argument. (each_strongly_connected_component_from): ditto. Mon Apr 21 21:59:48 2003 Nobuyoshi Nakada * marshal.c: one more digit for decimal point. [ruby-talk:69808] Mon Apr 21 21:25:59 2003 Nobuyoshi Nakada * numeric.c (flo_is_finite_p): use finite() if available. * win32/win32.h (isinf, isnan): define as macro. [ruby-win32:00533] * bcc32/Makefile.sub, win32/Makefile.sub: no longer use missing/isinf.c, missing/isnan.c. Mon Apr 21 18:36:28 2003 Nobuyoshi Nakada * bignum.c (rb_cstr_to_inum): unnecessarily long buffer was used for radix 9. [ruby-dev:20057] Mon Apr 21 17:44:34 2003 Nobuyoshi Nakada * parse.y (block_append, value_expr0, assign_in_cond, warn_unless_e_option, warning_unless_e_option, range_op, cond0): adjust line number in warning. Mon Apr 21 00:47:42 2003 WATANABE Hirofumi * sample/test.rb: avoid the MSVCRT *printf problem(float). [ruby-dev:20037] Mon Apr 21 00:11:15 2003 Nobuyoshi Nakada * marshal.c (w_float): append least mantissa bits to get rid of roundoff problem. [ruby-talk:69518] * marshal.c (r_object0): load least mantissa bits. Sun Apr 20 23:24:25 2003 WATANABE Hirofumi * win32/win32.c (NtInitialize): set the floating-point control word on bcc32. * win32/win32.h, bcc32/Makefile.sub: use missing/isinf.c, should not use _finite() because it returns 0 if NaN. Sun Apr 20 03:09:30 2003 WATANABE Hirofumi * parse.y (void_expr0): node might become NULL after calling remove_begin(). Sat Apr 19 21:55:10 2003 Akinori MUSHA * ext/Setup*: Add zlib and remove bogus and obsolete entries. Sat Apr 19 14:47:07 2003 Yukihiro Matsumoto * gc.c (rb_gc): use rb_gc_mark_maybe() to mark registered C addresses. C variables may not hold valid reference to Ruby objects. [ruby-core:00975] Sat Apr 19 00:56:13 2003 Yukihiro Matsumoto * struct.c (rb_struct_eql): should compare values with "eql?". Fri Apr 18 23:29:08 2003 Yukihiro Matsumoto * range.c (range_check): <=> returns nil for invalid values; should check. Fri Apr 18 15:26:50 2003 NAKAMURA Usaku * error.c (rb_raise): workaround for some implementations of vsnprintf. Fri Apr 18 02:23:42 2003 Yukihiro Matsumoto * regex.c (re_compile_pattern): should not set RE_OPTIMIZE_ANCHOR, if anychar_repeat is enclosed by parentheses. Fri Apr 18 01:49:18 2003 Nobuyoshi Nakada * util.c (ruby_strtod): improved conversion accuracy. Thu Apr 17 14:39:23 2003 NAKAMURA Usaku * ext/dbm/dbm.c (each_pair): add prototype to avoid VC++ warnings. * ext/readline/readline.c (Init_readline): follow readline 4.2 prototype. Thu Apr 17 14:22:36 2003 Nobuyoshi Nakada * parse.y (cond0): warn only range literals whose both side are literals. [ruby-core:00964] Thu Apr 17 11:10:59 2003 WATANABE Hirofumi * ext/readline/readline.c: add the defined operator for bcc32. Wed Apr 16 00:14:06 2003 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-special-char-p): should test at the point if no argument. fixed by Michael Scholz . Tue Apr 15 19:35:08 2003 Minero Aoki * lib/fileutils.rb: rm_r should raise Errno::ENOENT if file does not exist ([ruby-core:958]). Thanks Johan Holmberg. Tue Apr 15 19:12:21 2003 Nobuyoshi Nakada * struct.c (rb_struct_hash): new methods Struct#hash, Struct#eql?. (ruby-bugs:PR#758) Tue Apr 15 16:05:11 2003 Nobuyoshi Nakada * numeric.c (rb_fix2str): buffer was insufficient. (ruby-bugs-ja:PR#431) Mon Apr 14 19:45:56 2003 Nobuyoshi Nakada * file.c (file_expand_path): root must follow buf when reallocated. [ruby-talk:69339], [ruby-dev:20025] Mon Apr 14 03:22:33 2003 Yukihiro Matsumoto * rubyio.h (struct OpenFile): add noraise flag to finalizer. * io.c (Init_IO): define $/, $-0, and $\ as string-only variables. * string.c (rb_str_split_m): does not generate empty string if the receiver is empty. * io.c (fptr_finalize): should raise error on EBADF for readable IOs as well. Mon Apr 14 15:54:18 2003 Nobuyoshi Nakada * bignum.c (rb_cstr_to_inum, rb_big2str): allow 2-36 as radix. * numeric.c (rb_fix2str): ditto. * string.c (rb_str_to_i): ditto. Sun Apr 13 03:20:31 2003 WATANABE Hirofumi * lib/mkmf.rb (try_func): remove COMMON_HEADERS at first for performance. Sat Apr 12 20:59:40 2003 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-beginning-of-arg): substitute ruby-backward-arg. * misc/ruby-mode.el (ruby-calculate-indent): fixed wrong indentation in brace block and parentheses. * misc/ruby-mode.el (ruby-forward-sexp, ruby-backward-sexp): support special char literal, and negative arguments. Sat Apr 12 17:52:47 2003 Yukihiro Matsumoto * file.c (rb_stat): use rb_check_convert_type() to retrieve IO. Fri Apr 11 19:00:14 2003 Nobuyoshi Nakada * win32/win32.c (rb_w32_stat): check arguments. [ruby-dev:20007] [ruby-win32:535] Fri Apr 11 15:56:08 2003 Nobuyoshi Nakada * numeric.c (coerce_rescue): prevent inspected String from GC. * numeric.c (flo_eq, rb_dbl_cmp, flo_gt, flo_ge, flo_lt, flo_le, flo_eql): correct NaN comparison. (ruby-bugs:PR#744) * sample/test.rb: NaN comparison test. Fri Apr 11 14:48:47 2003 Yukihiro Matsumoto * file.c (rb_stat): dereference using StringValuePtr(). * file.c (rb_file_s_stat): use rb_stat(). [ruby-dev:20007] Fri Apr 11 10:51:08 2003 Nobuyoshi Nakada * lib/benchmark.rb (Benchmark::bm): get rid of warning. [ruby-talk:69124] Fri Apr 11 02:41:35 2003 Nobuyoshi Nakada * io.c (set_stdin): assigned value must respond to "read" and "getc". * io.c (set_outfile): assigned value must respond to "write". (ruby-bugs-ja:PR#425) Thu Apr 10 21:12:19 2003 Minero Aoki * lib/net/pop.rb: Exception line was accidentaly removed. [ruby-dev:19989] Thu Apr 10 18:42:13 2003 Tadayoshi Funaba * array.c (rb_ary_times): added some checks for request size. Thu Apr 10 03:22:38 2003 Yukihiro Matsumoto * variable.c (rb_mod_name): always return empty string for anonymous class/module. (ruby-bugs-ja PR#424) * config.sub: stop forcing addition of -gnu to -linux. * variable.c (classname): refactoring. * variable.c (rb_class_path): __tmp__classpath__ handling moved from classname(). Thu Apr 10 01:52:24 2003 Nobuyoshi Nakada * eval.c (rb_obj_is_method): indefinite return value. Thu Apr 10 00:39:32 2003 Tanaka Akira * regex.c (re_compile_pattern): /[\--\-]/ was warned. warn /]/. * mkconfig.rb: escape `]' in regexp. Thu Apr 10 00:27:07 2003 Nobuyoshi Nakada * time.c (time_strftime): RSTRING(format)->ptr might become NULL. Wed Apr 9 23:54:50 2003 Yukihiro Matsumoto * variable.c (rb_obj_remove_instance_variable): better message. [ruby-talk:68987] * variable.c (rb_mod_remove_const): ditto. * object.c (rb_obj_ivar_get): ditto. * object.c (rb_obj_ivar_set): ditto. * parse.y (yylex): ditto. Wed Apr 9 21:51:20 2003 Dave Thomas * eval.c (rb_mod_define_method): Allow UnboundMethod as parameter. Wed Apr 9 18:30:58 2003 Yukihiro Matsumoto * eval.c (top_include): include module to wrapper module if wrapper is present. experimental. [ruby-list:37539] Wed Apr 9 17:24:21 2003 Yukihiro Matsumoto * gc.c (rb_gc_mark_children): introduce this function again; this is required when stack was very tight. [ruby-talk:68916] Wed Apr 9 15:49:30 2003 Yukihiro Matsumoto * bignum.c (bigdivmod): small typo. Wed Apr 9 15:35:04 2003 NAKAMURA Usaku * ext/readline/readline.c: include only when HAVE_UNISTD_H is defined. Wed Apr 9 14:05:00 2003 Nobuyoshi Nakada * marshal.c (w_object): preserve extended module on struct. (ruby-bugs-ja:PR#422) Wed Apr 9 03:43:14 2003 Yukihiro Matsumoto * bignum.c (BIGZEROP): macro to determine if x is a bignum zero. Tue Apr 8 11:49:31 2003 Yukihiro Matsumoto * eval.c (Init_Proc): make Method and UnboundMethod independent. They are like instance and its class. [ruby-core:00941] * parse.y (yylex): disallow global variables like "$1ve". [ruby-core:00945] * marshal.c (marshal_dump): Marshal.dump(0, false) should cause an error. (ruby-bugs-ja PR#421) * regex.c (re_compile_pattern): warn if '-' is the edge of character range. Mon Apr 7 15:49:09 2003 Yukihiro Matsumoto * ext/socket/socket.c (sock_s_unpack_sockaddr_in): remove struct size check. getnameinfo(3) can handle. [ruby-dev:19967] Mon Apr 7 01:33:31 2003 Yukihiro Matsumoto * io.c (io_read): do not call rb_sys_fail() when required data length is zero. (ruby-bugs-ja PR#420) * eval.c (umethod_proc): should raise TypeError, instead of returning error causing Proc. Following the principle of "fail early". [ruby-core:00927] Sun Apr 6 18:29:21 2003 UENO Katsuhiro * ext/zlib/zlib.c: the return value of GzipReader#getc must be unsigned. Sun Apr 6 00:35:37 2003 Tanaka Akira * sample/exyacc.rb: use Regexp in gsub!. Sat Apr 5 23:41:28 2003 Yukihiro Matsumoto * pack.c (pack_pack): small but serious typo. Sat Apr 5 04:23:05 2003 Warren Brown * sprintf.c (rb_f_sprintf): was decrementing width even if there is no sign character. Sat Apr 5 01:41:28 2003 Yukihiro Matsumoto * eval.c (backtrace): skip internal allocator frame. (ruby-bugs-ja PR#416) Fri Apr 4 10:53:22 2003 Yukihiro Matsumoto * eval.c (assign): should prepare mrhs by svalue_to_mrhs(). Wed Apr 2 15:11:23 2003 Nobuyoshi Nakada * README.EXT, README.EXT.ja (3.3): clarified -1 as free for Data_Wrap_Struct(). [ruby-dev:19881] Mon Mar 31 11:11:36 2003 Yukihiro Matsumoto * eval.c (rb_f_missing): use "inspect" for T_OBJECT as well. Mon Mar 31 10:50:48 2003 Yukihiro Matsumoto * hash.c (env_reject_bang): untaint key string. * hash.c (env_delete_m): execute block only if deleting key does not exist. Sat Mar 29 17:54:46 2003 Yukihiro Matsumoto * pack.c (pack_pack): do not call rb_str_buf_cat() with NULL ptr, which causes SEGV; jump to grow instead. [ruby-dev:19944] Sat Mar 29 15:19:48 2003 Tanaka Akira * instruby.rb, ext/extmk.rb, lib/benchmark.rb, lib/cgi.rb, lib/debug.rb, lib/getoptlong.rb, lib/optparse.rb, lib/time.rb, lib/date/format.rb, lib/irb/ruby-lex.rb lib/uri/common.rb: revert escape for `-' in character class. Sat Mar 29 09:48:35 2003 Yukihiro Matsumoto * eval.c (avalue_to_svalue): use rb_check_array_type() again. Clarify how "to_ary" and "to_a" work. [ruby-talk:68155] * eval.c (svalue_to_avalue): ditto. * eval.c (svalue_to_mrhs): ditto. * eval.c (rb_eval): unary splat to use to_a, but we need a hack to exclude Object#to_a until it's removed. * object.c (rb_Array): check obj.respond_to?("to_a"). Currently all object respond_to "to_a", but Object#to_a will be removed. * range.c (Init_Range): undefine to_ary. * re.c (Init_Regexp): ditto. Sat Mar 29 09:47:52 2003 Nobuyoshi Nakada * MANIFEST (ext/aix_mksym.rb): remove obsolete file. Fri Mar 29 06:21:24 2003 UENO Katsuhiro * ext/zlib: merge from rough. Fri Mar 28 19:33:39 2003 Nobuyoshi Nakada * variable.c (rb_class_path): hold temporary class path in a instance variable to get rid of GC. [ruby-dev:19932] * variable.c (classname): remove temporary class path when exact name found. Fri Mar 28 18:29:23 2003 Yukihiro Matsumoto * regex.c (re_compile_pattern): do not warn if "-" is at the top or last of character class. Thu Mar 27 12:10:15 2003 Tanaka Akira * regex.c (re_compile_pattern): fix [:name:] handling. /[\[:digit:]]/ was treated as /[[:digit:]]/. /[[:-@]/ was treated as /[\[:\-@]/. /[%-[:digit:]]/ was treated as /[%-\[:digit:]\]/. Thu Mar 27 03:26:40 2003 Nobuyoshi Nakada * string.c (rb_str_capitalize_bang): check length before upcase first character. (ruby-bugs:PR#697) Wed Mar 26 20:25:10 2003 Nobuyoshi Nakada * dln.c (dln_find_1): break if path list end, even for too long path names. (ruby-bugs-ja:PR#412) Wed Mar 26 13:19:32 2003 Yukihiro Matsumoto * eval.c (avalue_splat): new function to do unary * (splat) operator. * eval.c (avalue_to_svalue,svalue_to_avalue,svalue_to_mrhs): do not use implicit "to_ary" conversion. * ext/curses/curses.c (GetWINDOW,GetMOUSE): add taint check. * ext/curses/curses.c (curses_init_screen): ditto. * ext/curses/curses.c (window_initialize): ditto. * gc.c (os_each_obj): prohibit ObjectSpace#each_object in safe mode ($SAFE >= 4). Tue Mar 25 23:26:02 2003 Yukihiro Matsumoto * signal.c (trap): return "DEFAULT" and "IGNORE" respectively for previous sighandler SIG_DFL and SIG_IGN. [ruby-talk:67860] Tue Mar 25 12:24:15 2003 Yukihiro Matsumoto * eval.c (rb_yield_0): call avalue_to_mrhs() to assign block parameter |a|. [ruby-dev:19897] * ruby.c (ruby_set_argv): freeze argument strings. Tue Mar 25 12:01:54 2003 Yukihiro Matsumoto * io.c (rb_io_initialize): should check rb_secure(4). * dir.c (dir_s_getwd): should check rb_secure(4). * object.c (rb_obj_infect): function version of OBJ_INFECT(). * eval.c (rb_secure_update): new function to check object update. Tue Mar 25 10:18:05 2003 Minero Aoki * ext/strscan/strscan.c: should infect also return values of #inspect. * ext/strscan/strscan.c: use snprintf() instead of sprintf(). Mon Mar 24 16:55:04 2003 Takaaki Tateishi * ext/dl/dl.c: added rb_secure(4). (Thanks to Minero Aoki) * ext/dl/sym.c: ditto. * ext/dl/ptr.c: ditto. Mon Mar 24 00:09:02 2003 Nobuyoshi Nakada * parse.y (block_append): warn unused literal. Sun Mar 23 22:22:04 2003 WATANABE Hirofumi * lib/jcode.rb (tr!, delete!, szueeze!): add empty string checking. Sun Mar 23 19:54:53 2003 Nobuyoshi Nakada * gc.c (rb_gc_call_finalizer_at_exit): use free() if dfree is -1. Sat Mar 22 15:50:29 2003 Tanaka Akira * time.c (make_time_t): try search_time_t if mktime/timegm is failed. Sat Mar 22 13:26:33 2003 Tanaka Akira * lib/optparse.rb, lib/jcode.rb, ext/tk/lib/tk.rb: reorder character class /[\]\[]/ to /[\[\]]/ for readability. Sat Mar 22 12:44:15 2003 Tanaka Akira * lib/date/format.rb, lib/uri/common.rb: escape `[', `]', `-' in character class in regexp to avoid warning. Sat Mar 22 07:39:32 2003 Ulf Betlehem * io.c (rb_io_fread): may lose data on nonblocking read. Fri Mar 21 23:40:41 2003 Tanaka Akira * regex.c (re_compile_pattern): fix previous change. * instruby.rb, ext/extmk.rb, ext/tk/lib/tk.rb, lib/benchmark.rb, lib/cgi.rb, lib/debug.rb, lib/getoptlong.rb, lib/jcode.rb, lib/optparse.rb, lib/time.rb, lib/date/format.rb, lib/irb/ruby-lex.rb: escape `[', `]', `-' in character class in regexp to avoid warning. Fri Mar 21 23:23:45 2003 Yukihiro Matsumoto * regex.c (re_compile_pattern): give warning for unescaped square brackets and minus in character class. [ruby-dev:19868] Fri Mar 21 18:12:20 2003 Nobuyoshi Nakada * eval.c (bmcall): missing type. Fri Mar 21 01:29:35 2003 Yukihiro Matsumoto * sprintf.c (rb_f_sprintf): copy sign bits only if value is negative. * missing.h: include or if HAVE_VSNPRINTF is not defined. Thu Mar 20 18:31:37 2003 Nobuyoshi Nakada * lib/optparse.rb (OptionParser#order!): follow recent change of proc argument. Thu Mar 20 16:12:53 2003 Yukihiro Matsumoto * numeric.c (flo_to_s): change format specifier to "%.15g" to avoid unnecessary 9s (e.g. 99.59999999999999). (ruby-bugs-ja PR#406) Thu Mar 20 16:03:18 2003 Nobuyoshi Nakada * parse.y (stmt, primary): get rid of SEGV at empty or invalid condition. (ruby-bugs-ja:PR#410) * parse.y (cond_negative): negate condition node when NODE_NOT. Thu Mar 20 10:45:29 2003 Tanaka Akira * eval.c (bmcall): add volatile to avoid GC problem. Thu Mar 20 10:10:49 2003 Yukihiro Matsumoto * eval.c (load_dyna): clear ruby_errinfo. (ruby-bugs-ja PR#409) Wed Mar 19 23:05:30 2003 NAKAMURA, Hiroshi * lib/tracer.rb (trace_func): save and recover Thread.critical state. Fixed by Fukumoto Atsushi [ruby-dev:19830] Wed Mar 19 02:55:46 2003 Yukihiro Matsumoto * io.c (read_all): make str empty if given. (ruby-bugs-ja PR#408) * io.c (io_read): ditto. * io.c (rb_io_sysread): ditto. Tue Mar 18 18:24:03 2003 Yukihiro Matsumoto * range.c: do not override min and max. Sun Mar 16 12:29:55 2003 Tanaka Akira * lib/pp.rb (object_address_group): use to_s instead of name to get name of class. Fri Mar 14 08:53:29 2003 Yukihiro Matsumoto * sprintf.c (remove_sign_bits): octal left most digit for negative numbers may be '3'. (ruby-bugs-ja PR#407) * sprintf.c (rb_f_sprintf): should prefix sign bits if bignum is negative, using sign_bits(). Wed Mar 12 16:48:19 2003 WATANABE Hirofumi * io.c (prep_stdio): set binmode only if the file descriptor is not connected to a terminal on Cygwin. Wed Mar 12 11:23:49 2003 Yukihiro Matsumoto * eval.c (avalue_to_mrhs): split argument passing and assignment conversion. * eval.c (svalue_to_mrhs): ditto. * eval.c (avalue_to_svalue): avalue_to_svalue([[1,2]]) should be [[1,2]], not [1,2] to wrap-around. Tue Mar 11 21:00:59 2003 Minero Aoki * lib/net/smtp.rb: Digest string wrongly included '\n' when user name is too long (ruby-bugs-ja:PR#404). Tue Mar 11 20:07:01 2003 Minero Aoki * lib/net/http.rb: speeding up by avoiding extra flush. (suggested by Brian Candler [ruby-talk:66516]) Tue Mar 11 04:30:12 2003 Yukihiro Matsumoto * eval.c (massign): remove unnecessary array unpacking; it should be handled before massign() by svalue_to_mrhs(). * eval.c (svalue_to_mrhs): '*a = v' value conversion to avalue (i.e. [1] => [[1]], [1,2] => [1,2]). * eval.c (rb_eval): use svalue_to_mrhs. * eval.c (rb_yield_0): ditto. * eval.c (proc_invoke): break from "Proc#yield" is legal. Mon Mar 10 23:19:29 2003 Yukihiro Matsumoto * file.c (rb_find_file): need world writable directory check for relative paths too. Mon Mar 10 11:23:00 2003 Yukihiro Matsumoto * file.c (rb_find_file): world writable directory check if $SAFE >= 1 (was $SAFE >= 2). Mon Mar 10 01:59:47 2003 Minero Aoki * lib/net/pop.rb: do not dispatch LIST when a mailbox is empty. * lib/net/pop.rb: merge the 'STAT' patch from Frank S.Fejes , with modifications (listed below). * lib/net/pop.rb: new method Net::POP#mail_size. * lib/net/pop.rb: new method Net::POP#bytes. * lib/net/pop.rb: new method Net::POPCommand#stat. Sun Mar 9 19:30:25 2003 WATANABE Hirofumi * lib/fileutils.rb (mkdir, mkdir_p): revert. * instruby.rb (umask): umask 0022, not 0. Sun Mar 9 17:09:40 2003 WATANABE Hirofumi * lib/fileutils.rb (mkdir, mkdir_p): set mode to 0755. * Makefile.in (fake.rb): set ALT_SEPARATOR to the default value. Sat Mar 8 11:30:59 2003 Nobuyoshi Nakada * eval.c (massign): fix a bug not to expand in assignment to sole lhs. [ruby-dev:19766] Fri Mar 7 21:57:25 2003 Tanaka Akira * lib/pp.rb (Kernel.pp): module function. (MatchData#pretty_print): new method. Fri Mar 7 20:27:19 2003 Nobuyoshi Nakada * ext/tcltklib/extconf.rb (find_tcl, find_tk): return true if non-versioned found. [ruby-dev:19759] Fri Mar 7 15:05:35 2003 WATANABE Hirofumi * ext/dbm/extconf.rb: add QDBM support. Fri Mar 7 12:59:39 2003 Nobuyoshi Nakada * eval.c (massign): deal with sole lhs, assign rest args from converted array. [ruby-dev:19751] Fri Mar 7 03:31:36 2003 Yukihiro Matsumoto * parse.y (dsym): :"symbol string" style should not contain `\0'. * process.c (proc_detach): new method Process.detach(pid) which create background watcher thread to issue waitpid. [new] * process.c (rb_detach_process): utility function to detach process from C code. * ext/pty/pty.c (pty_finalize_syswait): terminate watcher thread, and detach child process (by creating new idle waitpid watcher thread). * ext/pty/pty.c (pty_syswait): may lost signal stopped child. Fri Mar 7 00:30:33 2003 WATANABE Hirofumi * ext/Win32API/Win32API.c: no longer use inline-asms. * ext/Win32API/extconf.rb: no need to add gcc options. Thu Mar 6 13:02:10 2003 Yukihiro Matsumoto * parse.y (reswords): fix reswords list. Wed Mar 5 12:13:21 2003 WATANABE Hirofumi * configure.in: better YACC support on HP-UX. Wed Mar 5 05:55:20 2003 Yukihiro Matsumoto * string.c (rb_str_cat): remove ptr NULL check and MEMZERO(). ptr must be non NULL. Tue Mar 4 23:12:07 2003 Nobuyoshi Nakada * configure.in, bcc32/Makefile.sub, win32/Makefile.sub: define RUBY_EXPORT to export symbols. * defines.h: use RUBY_EXTERN instead of EXTERN. * intern.h, re.h, ruby.h, rubysig.h: ditto. * win32/win32.h: remove EXTERN definition. Tue Mar 4 17:54:30 2003 Yukihiro Matsumoto * array.c (rb_ary_aref): raise TypeError if index is a symbol. [ruby-list:37217] * array.c (rb_ary_aset): ditto. Tue Nov 13 14:39:11 2001 WATANABE Tetsuya * missing/strftime.c: HP-UX support. Tue Mar 4 15:08:08 2003 WATANABE Hirofumi * configure.in: better HP-UX support. * missing/strftime.c: ditto. Tue Mar 4 10:11:32 2003 Yukihiro Matsumoto * io.c (rb_io_popen): do not call rb_io_close() directly, call "close" method instead. [ruby-dev:19717] * io.c (rb_io_s_open): ditto. * hash.c (rb_any_hash): remove DEFER_INTS. all do_hash() calls in st.c are at the top of functions. No reentrant problem. Tue Mar 4 01:19:21 2003 Akinori MUSHA * ext/dl/MANIFEST: Exclude .cvsignore. [found by: eban] Tue Mar 4 01:17:08 2003 Akinori MUSHA * ext/Win32API/MANIFEST: Belatedly add lib/win32/registry.rb. [found by: eban] Tue Mar 4 00:33:04 2003 Akinori MUSHA * MANIFEST: Belatedly add Test::Unit files. D'oh! Sun Mar 2 09:51:47 2003 Nobuyoshi Nakada * marshal.c (w_nbyte): should output always via rb_io_write(). * marshal.c (dump_ensure): ditto. * marshal.c (marshal_dump): should call "binmode" method, if it responds to. * marshal.c (r_byte): should input always via "getc" method. * marshal.c (r_bytes0): should input always via "read" method. * marshal.c (marshal_load): need not to set up FILE* fp; Mon Mar 3 11:29:04 2003 Yukihiro Matsumoto * parse.y (arg): parse 'lhs = a rescue b' as 'lhs=(a rescue b)'. Mon Mar 3 02:53:52 2003 Yukihiro Matsumoto * io.c (rb_io_fread): should not clearerr() if there's no filled buffer (i.e. rb_io_fread() returning zero). Mon Mar 3 01:42:35 2003 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-expr-beg): escaped char syntax. * misc/ruby-mode.el (ruby-parse-partial): ditto. * misc/ruby-mode.el (ruby-parse-partial): no deep indent for block. * misc/ruby-mode.el (ruby-backward-arg): skip arguments backward. * misc/ruby-mode.el (ruby-calculate-indent): too deep indentation. Fri Feb 28 23:50:32 2003 NAKAMURA Usaku * win32/win32.c (map_errno): map OS error to errno. [new] * win32/win32.c (pipe_exec, CreateChild, poll_child_status, waitpid, kill, link, rb_w32_rename, unixtime_to_filetime, rb_w32_utime): use map_errno() instead of using GetLastError() directly. * win32/win32.c (rb_w32_select, rb_w32_accept, rb_w32_bind, rb_w32_connect, rb_w32_getpeername, rb_w32_getsockname, rb_w32_getsockopt, rb_w32_ioctlsocket, rb_w32_listen, rb_w32_recv, rb_w32_recvfrom, rb_w32_send, rb_w32_sendto, rb_w32_setsockopt, rb_w32_shutdown, rb_w32_socket, rb_w32_gethostbyaddr, rb_w32_gethostbyname, rb_w32_gethostname, rb_w32_getprotobyname, rb_w32_getprotobynumber, rb_w32_getservbyname, rb_w32_getservbyport, rb_w32_fclose, rb_w32_close): map winsock error to errno. Fri Feb 28 22:54:10 2003 Nobuyoshi Nakada * win32/win32.c (flock): supports larger files, and maps error code. * win32/win32.c (rb_w32_asynchronize): returns errno from child thread. * win32/win32.c (rb_w32_fclose, rb_w32_close): ensures unlocked. Wed Feb 26 17:38:16 2003 Tanaka Akira * lib/open-uri.rb: replace Kernel.open as well. Tue Feb 25 23:03:08 2003 NAKAMURA, Hiroshi * lib/debug.rb (DEBUGGER__::Context#debug_command): bp filename must be the basename of it. [ruby-talk:65644] Mon Feb 24 17:49:35 2003 Nobuyoshi Nakada * parse.y (yycompile): zero clear ruby_eval_tree_begin if compilation failed. Mon Feb 24 08:06:29 2003 Yukihiro Matsumoto * string.c (str_new): need no MEMZERO(). Sun Feb 23 17:57:06 2003 WATANABE Hirofumi * lib/fileutils (fu_stream_blksize): wrong logical condition. (and -> or). Sat Feb 22 03:12:56 2003 Yukihiro Matsumoto * numeric.c (fix_gt): use rb_num_coerce_cmp() instead of rb_num_coerce_bin. * numeric.c (fix_ge, fix_lt, fix_le): ditto. * numeric.c (flo_gt, flo_ge, flo_lt, flo_le): ditto. Sat Feb 22 02:45:20 2003 Yukihiro Matsumoto * eval.c (rb_thread_create): may called from place higher than rb_gc_stack_start. * gc.c (Init_stack): update rb_gc_stack_start if it is lower (or higher if stack grows down) than the previous value. Fri Feb 21 21:03:41 2003 Minero Aoki * lib/fileutils.rb: new method FileUtils#copy_stream. * lib/fileutils.rb: new method FileUtils#compare_file. * lib/fileutils.rb: new method FileUtils#compare_stream. * lib/fileutils.rb: new method FileUtils#rmtree (alias of rm_rf). Fri Feb 21 17:19:27 2003 WATANABE Hirofumi * eval.c (rb_f_require): do not need to abort if a DLEXT file is not found. Fri Feb 21 13:39:25 2003 Yukihiro Matsumoto * string.c (rb_str_cmp_m): should use LONG2NUM(). Fri Feb 21 12:45:50 2003 Yukihiro Matsumoto * string.c (rb_str_cmp_m): two small bugs fixed. Fri Feb 21 08:03:09 2003 Yukihiro Matsumoto * gc.c (rb_gc_mark): inline rb_gc_mark_children(). * gc.c (gc_sweep): new tactics to increase malloc_limit mildly. Fri Feb 21 05:16:14 2003 Yukihiro Matsumoto * string.c (rb_str_cmp_m): return nil if str2 does not respond to both "to_str" and "<=>". * compar.c (cmp_gt): return nil if "<=>" returns nil (means incomparable). * compar.c (cmp_ge, cmp_lt, cmp_le): ditto. * compar.c (cmp_between): use RTEST(), since cmp_lt and cmp_gt may return nil. Thu Feb 20 19:05:51 2003 Yukihiro Matsumoto * eval.c (rb_thread_start_0): main thread swapped by fork() may terminate rb_thread_start_0() successfully. call ruby_stop(0); this change was suggested by Rudi Cilibrasi . Thu Feb 20 18:44:51 2003 Nobuyoshi Nakada * file.c (file_expand_path): fix wrong behavior for root file. expand_path("..", "//machine/share") => "//machine/share" expand_path("..", "c:/a") => "c:/" expand_path("..", "/a") => "/" Thu Feb 20 18:11:01 2003 Nobuyoshi Nakada * file.c (file_expand_path): should not upward beyond share name. Thu Feb 20 15:45:33 2003 WATANABE Hirofumi * missing.h (strtoul): fix prototype of strtoul. Thu Feb 20 10:11:30 2003 Yukihiro Matsumoto * parse.y (clhs): allow "Foo::Bar = x". Thu Feb 20 04:07:06 2003 Nobuyoshi Nakada * parse.y (primary): "self[n]=x" can be legal even when "[]=" is private. changes submitted in [ruby-talk:63982] * parse.y (aryset): ditto. * parse.y (attrset): "self.foo=x" can be legal even when "foo=" is private. * eval.c (is_defined): private "[]=" and "foo=" support. * eval.c (rb_eval, assign): ditto. Thu Feb 20 03:58:34 2003 Yukihiro Matsumoto * eval.c (rb_eval): "foo=" should not always be public. Thu Feb 20 01:23:59 2003 Nobuyoshi Nakada * eval.c (rb_thread_restore_context): inhibit interrupts in critical section while context switching. [ruby-talk:64785] Wed Feb 19 18:27:42 2003 Nobuyoshi Nakada * node.h (nd_cpath): nested class/module declaration. [EXPERIMENTAL] * eval.c (rb_eval): ditto. * gc.c (rb_gc_mark_children): ditto. * parse.y (cpath): ditto. Tue Feb 18 21:39:27 2003 Yukihiro Matsumoto * eval.c (rb_call0): should not report uninitialized warning by attribute reader method. * variable.c (rb_attr_get): new function to get instance variable without uninitialized warning. * io.c (argf_to_io): should prefetch argv. Tue Feb 18 00:13:50 2003 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-comment-column): customize comment column. [new] * misc/ruby-mode.el (ruby-deep-indent-paren): deep indentation parentheses. [new] * misc/ruby-mode.el (ruby-expr-beg): fix for / after $?. * misc/ruby-mode.el (ruby-parse-partial, ruby-calculate-indent): deep indentation support. * misc/ruby-mode.el (ruby-forward-sexp, ruby-backward-sexp): move forward/backward across one balanced expression. [new] * misc/ruby-mode.el (ruby-indent-exp): indent balanced expression. [new] * misc/ruby-mode.el (ruby-electric-brace): indent before show matching parenthesis. (contributed by NABEYA Kenichi) Mon Feb 17 14:36:56 2003 Nobuyoshi Nakada * win32/win32.c (rb_w32_opendir, rb_w32_utime): need parens. Mon Feb 17 14:13:25 2003 NAKAMURA Usaku * win32/win32.c (link): implement with CreateHardLink(). * win32/win32.c, win32/win32.h (rb_w32_utime): enable utime() to directory if on NT. [new] (ruby-bugs-ja:PR#393) Mon Feb 17 13:28:51 2003 Nobuyoshi Nakada * file.c (file_expand_path): strip last slash when path is root. Sun Feb 16 19:22:31 2003 Nobuyoshi Nakada * file.c (file_expand_path): buffer might be reallocated while expanding default directory. * file.c (file_expand_path): default directory was being ignored if path was full path with no drive letter, under DOSISH. Sun Feb 16 03:14:33 2003 WATANABE Hirofumi * io.c (prep_stdio, Init_io): always set binmode on Cygwin. Sat Feb 15 01:01:45 2003 Nobuyoshi Nakada * file.c (file_expand_path): fix surplus path separators while expanding at root directory. [ruby-dev:19572] Fri Feb 14 14:25:24 2003 akira yamada * lib/uri/generic.rb, lib/uri/ldap.rb, lib/uri/mailto.ldap: all foo=() returns arguments passed by caller. * lib/uri/generic.rb (Generic#to_str, Generic#to_s): removed to_str. Suggested by Tanaka Akira at [ruby-dev:19475]. * lib/uri/generic.rb (Generic#==): should not generate an URI object from argument. Suggested by Tanaka Akira at [ruby-dev:19475]. Thu Feb 13 11:54:50 2003 Nobuyoshi Nakada * ruby.c (ruby_init_loadpath): ensures buffer terminated before use strncpy(). * ruby.c (proc_options): avoid SEGV at -S with no arguments. script argument is in effect only when -e is not given. (ruby-bugs-ja:PR#391) Thu Feb 13 01:30:10 2003 Nobuyoshi Nakada * eval.c (rb_thread_schedule): current thread may be dead when deadlock. (ruby-bugs:PR#588) Thu Feb 13 00:28:52 2003 Yukihiro Matsumoto * range.c (range_step): step might be float 0 < x < 1. * eval.c (rb_thread_schedule): pause if no runnable thread when there's only one thread. Thu Feb 13 00:09:47 2003 Nobuyoshi Nakada * file.c (strrdirsep): ignore trailing directory separators. * file.c (rb_file_s_expand_path): File.expand_path(".","/") should return "/". (ruby-bugs-ja:PR#389) * file.c (rb_file_s_basename): also ignore trailing directory separators, in compliance with SUSv3. (ruby-bugs-ja:PR#390) * file.c (rb_file_s_dirname, rb_file_s_extname): ditto. * file.c (rb_file_s_dirname): append "." if drive only. * file.c (rb_file_s_split): get rid of converting twice. Mon Feb 10 20:55:15 2003 WATANABE Hirofumi * ext/extmk.rb (parse_args): add '-n' to $mflags BEFORE "--". do not add DESTDIR if already included in $mflags. Mon Feb 10 19:54:30 2003 Minero Aoki * lib/fileutils.rb (FileUtils#uptodate?): use mtime for comparison. Mon Feb 10 10:14:26 2003 Yukihiro Matsumoto * array.c (rb_ary_to_a): return value should be an Array if the receiver is an instance of subclass of Array. * string.c (rb_str_to_s): return value should be a String if the receiver is an instance of subclass of String. Mon Feb 10 03:33:42 2003 WATANABE Hirofumi * io.c (rb_file_sysopen): rb_file_sysopen_internal() needs four arguments. Sun Feb 9 15:16:04 2003 Nobuyoshi Nakada * intern.h (HAVE_RB_DEFINE_ALLOC_FUNC, RB_CVAR_SET_4ARGS): define to 1. * ruby.h (NORETURN_STYLE_NEW): ditto. Sun Feb 9 12:28:18 2003 Nobuyoshi Nakada * lib/mkmf.rb (init_mkmf): add libdir to LIBPATH unless cross compiling. Sun Feb 9 08:34:45 2003 Minero Aoki * lib/net/http.rb: 4xx raises Net::ProtoServerError, 5xx raises Net::ProtoFatalError (for backward compatibility). Sun Feb 9 07:07:26 2003 Minero Aoki * lib/fileutils.rb: new method FileUtils.pwd (really). * lib/fileutils.rb: FileUtils.pwd, cmp, identical?, uptodate? does not accept any option. Sat Feb 8 18:35:30 2003 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-forward-string): fixed void variable error. Sat Feb 8 16:23:11 2003 NABEYA Kenichi * misc/ruby-mode.el (ruby-font-lock-keywords): method name can be delimited by tab. Sat Feb 8 03:57:32 2003 Akinori MUSHA * lib/irb/workspace.rb, lib/irb/ext/math-mode.rb, lib/irb/ext/multi-irb.rb, lib/irb/lc/error.rb, lib/irb/lc/help-message, lib/irb/lc/ja/error.rb, lib/shell/command-processor.rb, lib/shell/error.rb, lib/shell/filter.rb: Fix typos and grammos. [approved by: keiju] Sat Feb 8 03:34:28 2003 Akinori MUSHA * intern.h (HAVE_RB_DEFINE_ALLOC_FUNC): New boolean macro to make it easier to write extensions that work with both ~1.6 and 1.8~. * intern.h (RB_CVAR_SET_4ARGS): Ditto. * ruby.h (NORETURN_STYLE_NEW): Ditto. Sat Feb 8 00:47:24 2003 Yukihiro Matsumoto * eval.c (rb_call): calls method_missing when superclass method does not exist. * eval.c (rb_f_missing): now handles "no super" case. * object.c (rb_obj_ivar_get): Object#instance_variable_get: new method to get instance variable value without eval(). [new] * object.c (rb_obj_ivar_set): Object#instance_variable_set: new method to set instance variable value without eval(). [new] Fri Feb 7 15:35:21 2003 Nobuyoshi Nakada * intern.h, re.c (rb_memsearch): returns long. * string.c (rb_str_index): should return offset position. Fri Feb 7 15:30:15 2003 Nobuyoshi Nakada * eval.c (proc_invoke): should propagate self to super methods. [ruby-dev:19510] Thu Feb 6 19:04:32 2003 Yukihiro Matsumoto * re.c (rb_reg_initialize_m): should not preset "kcode" unless encoding is explicitly specified. Thu Feb 6 19:01:32 2003 Minero Aoki * lib/fileutils.rb: new method FileUtils.pwd. * lib/fileutils.rb: default label is ''. * lib/fileutils.rb: using module_eval again, to avoid ruby's bug. * lib/fileutils.rb: fix wrong examples in rdoc. Thu Feb 6 17:43:56 2003 Yukihiro Matsumoto * lib/complex.rb (Complex#==): should not raise error by type mismatch. * lib/rational.rb (Rational#==): ditto. Thu Feb 6 11:44:40 2003 MoonWolf * re.c (rb_reg_initialize_m): 3rd argument was ignored. Thu Feb 6 01:09:05 2003 Yukihiro Matsumoto * string.c (rb_str_count): return 0 for empty string (was returning nil). Wed Feb 5 19:41:37 2003 Tanaka Akira * lib/open-uri.rb: dispatch code restructured to make it openable that has `open' method. * lib/open-uri.rb: Location: field may has a relative URI. pointed out by erik eriksson . Wed Feb 5 17:11:02 2003 Yukihiro Matsumoto * parse.y (yylex): no . float literal anymore. Tue Feb 4 16:11:30 2003 Yukihiro Matsumoto * array.c (rb_ary_equal): a == b is true when b is non T_ARRAY object, if b has "to_ary" and b == a. * hash.c (rb_hash_equal): a == b is true when b is non T_HASH object, if b has "to_hash" and b == a. * string.c (rb_str_equal): a == b is true when b is non T_STRING object, if b has "to_str" and b == a. Mon Feb 3 23:46:48 2003 Yukihiro Matsumoto * io.c (argf_getline): should not increment lineno at EOF. Mon Feb 3 16:49:19 2003 Yukihiro Matsumoto * object.c (Init_Object): default Object#=== now calls "==" internally. * re.c (rb_reg_initialize_m): should honor option status of original regexp. * array.c (rb_ary_equal): ary2 should be T_ARRAY (no to_ary conversion). * array.c (rb_ary_eql): ditto. * string.c (rb_str_equal): str2 should be T_STRING (no to_str conversion). Mon Feb 3 16:32:52 2003 Nobuyoshi Nakada * re.c (rb_memsearch): a little improvement. Mon Feb 3 13:18:05 2003 Yukihiro Matsumoto * re.c (rb_memsearch): algorithm body of String#index. * error.c (Init_Exception): "to_str" removed. * eval.c (eval): should not rely on Exception#to_str * eval.c (compile_error): ditto. * error.c (err_append): ditto. Sat Feb 1 23:56:29 2003 Yukihiro Matsumoto * hash.c (rb_hash_merge): Hash#merge, non destructive "update". now there's also Hash#merge! which is an alias to "update". Fri Jan 31 14:16:59 2003 Yukihiro Matsumoto * string.c (rb_str_index): search using Karp-Rabin algorithm. Fri Jan 31 12:45:11 2003 Yukihiro Matsumoto * variable.c (rb_obj_classname): new function. * string.c (rb_str_dup): should preserve original's class (but not hidden singleton class). * string.c (rb_str_substr): ditto. * parse.y: backout EXPR_CMDARG removal. Fri Jan 31 09:40:07 2003 Nobuyoshi Nakada * lib/optparse.rb (OptionParser::List::accept): default pattern must not be nil. * lib/optparse.rb (OptionParser::make_switch): NoArgument doesn't override other styles. Thu Jan 30 16:46:43 2003 Nobuyoshi Nakada * lib/optparse.rb (OptionParser::Switch::PlacedArgument): added. if the next argument doesn't start with '-', use it as the value. * lib/optparse.rb (OptionParser::make_switch): fixed a bug of pattern. * lib/optparse.rb (Array): no need to guard. Thu Jan 30 08:27:19 2003 Nobuyoshi Nakada * file.c (rb_file_s_expand_path): removed a sludge. Wed Jan 29 03:24:39 2003 Michal Rokos * dir.c (glob_helper): memory leak fixed. Tue Jan 28 04:45:03 2003 Akinori MUSHA * instruby.rb (parse_args), ext/extmk.rb (parse_args): Prepend a hyphen to the first argument of MAKEFLAGS only if appropriate. Remove wrong comments. Mon Jan 27 03:30:06 2003 NAKAMURA Usaku * error.c (get_syserror): use snprintf() instead of sprintf(). pointed out by knu. Mon Jan 27 02:06:38 2003 NAKAMURA Usaku * error.c (get_syserror): some Windows' errno have 5 digits. pointed out by znz. Sun Jan 26 19:23:10 2003 NAKAMURA Usaku * instruby.rb ($mflags.set?): Check $make instead of $nmake, since there is no such a variable. * instruby.rb ($mflags.set?), ext/extmk.rb ($mflags.set?): Return false if unmatched. Sun Jan 26 19:08:30 2003 Akinori MUSHA * lib/shellwords.rb: Embed rdoc style comments. * lib/shellwords.rb (shellwords): Use String#lstrip!. * lib/shellwords.rb (shellwords): Recognize an object that responds to to_str() by using String.new(). Sun Jan 26 17:53:04 2003 Akinori MUSHA * instruby.rb (parse_args), ext/extmk.rb (parse_args): Detect -n and emulate a dry run. Use 'make' in case no --make argument is given. Sun Jan 26 07:18:42 2003 Nobuyoshi Nakada * instruby.rb: re-define individual methods verbosely rather than including FileUtils::Verbose, in order to suppress messages from FileUtils#cmp. * instruby.rb (makedirs): make same directory only once even if dryrun. * lib/fileutils.rb (FileUtils::Verbose, FileUtils::NoWrite): re-define methods with define_method instead of module_eval. Sun Jan 26 03:37:18 2003 Akinori MUSHA * instruby.rb, ext/extmk.rb, Makefile.in, win32/Makefile.sub, bcc32/Makefile.sub: Replace the complicated MFLAGS/MAKEFLAGS parser with something plain and comprehensible. This fixes a bug where make flags were wrongly reordered and the resulted command line often did not make sense especially when BSD make is used with extra arguments given. Tested with FreeBSD and Linux by me and mswin32, bccwin32 and mingw by usa. Fri Jan 24 18:15:33 2003 Yukihiro Matsumoto * parse.y: tMINUS should have lower precedence than tPOW. Fri Jan 24 05:12:55 2003 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-font-lock-syntactic-keywords): deal with escaped $ and ? at the end of strings. [ruby-talk:62297] * misc/ruby-mode.el (ruby-font-lock-keywords): added defined?. Thu Jan 23 17:25:04 2003 Yukihiro Matsumoto * eval.c (rb_eval): do not warn discarding already undefined method. * lib/rational.rb: undef quo before replacing. Thu Jan 23 15:49:57 2003 Nobuyoshi Nakada * parse.y (arg): missing arguments. Thu Jan 23 14:56:52 2003 Yukihiro Matsumoto * lib/rational.rb: modified to support "quo". * numeric.c (num_quo): should return most exact quotient value, i.e. float by default, rational if available. * numeric.c (num_div): "div" should return x.divmod(x)[0]. Thu Jan 23 13:24:18 2003 Yukihiro Matsumoto * time.c (time_arg): was accessing garbage argv value. Thu Jan 23 06:37:01 2003 Nobuyoshi Nakada * instruby.rb: should not contain destdir in shebang line. Wed Jan 22 23:19:57 2003 NAKAMURA Usaku * win32/win32.c (pipe_exec): remove unnecessary SetStdHandle(). Wed Jan 22 20:20:59 2003 Yukihiro Matsumoto * parse.y (arg): syntaxify tPOW negative number hack. * parse.y (negate_lit): new function to negate literal numeric values in compile time. Wed Jan 22 15:36:54 2003 Yukihiro Matsumoto * regex.c (re_match_exec): charset info may be stored in MBC region when $KCODE != NONE. Wed Jan 22 14:22:53 2003 Yukihiro Matsumoto * error.c (set_syserr): should preserve duplicated error names. Tue Jan 21 20:29:31 2003 Michal Rokos * mkmf.rb: make possible to add files to clean and distclean targets Tue Jan 21 18:05:25 2003 Nobuyoshi Nakada * bcc32/Makefile.sub (LIBRUBY_A): link dmyext. Tue Jan 21 16:59:18 2003 NAKAMURA Usaku * instruby.rb: use real interpreter pathname at shebang line. [ruby-dev:19370] Tue Jan 21 16:22:32 2003 Yukihiro Matsumoto * parse.y (arg): put back old ** behavior for negative number right operand. Tue Jan 21 14:46:12 2003 Tanaka Akira * lib/pp.rb: Use Test::Unit. * lib/prettyprint.rb: Ditto * lib/time.rb: Ditto * lib/tsort.rb: Ditto Tue Jan 21 04:15:50 2003 Tanaka Akira * lib/pp.rb: Use redefined `to_s' as well as `inspect'. Useless `pretty_print' methods removed. (PP::ObjectMixin#pretty_print_inspect): new method. Mon Jan 20 21:48:43 2003 Akinori MUSHA * configure.in (MANTYPE): Detect if the system's nroff(1) groks mdoc. Provide a new option --with-mantype={doc|man} in case the check does not work as expected. * Makefile.in (MANTYPE): Define MANTYPE and pass it to instruby.rb. * instruby.rb: Convert mdoc manpages to man for systems which nroff(1) does not grok mdoc. Mon Jan 20 21:25:18 2003 Akinori MUSHA * lib/tempfile.rb (self.open): If a block is given, call it with tempfile as an argument and automatically close the tempfile when the block terminates. Mon Jan 20 21:02:50 2003 Akinori MUSHA * mdoc2man.rb: Properly put nested braces, parentheses and angles. * mdoc2man.rb: Add support for .An and .Aq/.Ao/.Ac. * mdoc2man.rb: Add support for .Dl. * mdoc2man.rb: Make .Pf macro actually work. * mdoc2man.rb: Properly handle .Os. * mdoc2man.rb: Correctly omit spaces around punctuation characters. Mon Jan 20 19:43:41 2003 Akinori MUSHA * mdoc2man.rb: Make this work as a library. Mon Jan 20 18:22:40 2003 Nobuyoshi Nakada * eval.c (rb_f_require): purge too many goto's. Mon Jan 20 17:50:05 2003 Akinori MUSHA * mdoc2man.rb (parse_macro): Understand .Ux. Mon Jan 20 17:32:56 2003 Akinori MUSHA * mdoc2man.rb: New file. A mdoc to man converter ported from Perl. Mon Jan 20 15:40:15 2003 Akinori MUSHA * ruby.1: Properly close .Bl with .El. Mon Jan 20 04:14:17 2003 Nobuyoshi Nakada * lib/mkmf.rb (egrep_cpp): use inspect to show options. * lib/mkmf.rb (dir_config): prior configured directories to defaults. * lib/mkmf.rb (dir_config): extract first word to determine make command type. Mon Jan 20 02:15:53 2003 Nobuyoshi Nakada * ext/aix_mksym.rb: no longer used. Mon Jan 20 00:17:16 2003 Matt Armstrong * file.c (eaccess): under windows, make eaccess() just call access(). [ruby-core:716], [ruby-bugs:PR#556] Sun Jan 19 23:08:18 2003 Akinori MUSHA * lib/shellwords.rb (shellwords): A backslash ('\') in single quotes should not be regarded as meta character. This bug or maybe feature was inherited from Perl's shellwords.pl. Sun Jan 19 14:01:12 2003 UENO Katsuhiro * regex.c (is_in_list): should work well with UTF-8. * regex.c (re_match_exec): ditto. Sat Jan 18 14:53:49 2003 Nobuyoshi Nakada * bignum.c (rb_cstr_to_inum): should not erase all 0s, but squeeze into one. [ruby-dev:19377] Fri Jan 17 03:33:42 2003 Akinori MUSHA * sprintf.c (rb_f_sprintf): Fix a bug caused by an uninitialized variable v, that a bignum unexpectedly gets converted into a string with its higher figures all filled with ./f/7/1, depending on the base. This bug seems to have been introduced in rev.1.27. * sprintf.c (rb_f_sprintf): Use switch instead of a sequence of else-if's. Wed Jan 15 15:18:38 2003 moumar * configure.in (ARCHFILE): set even unless --enable-shared on AIX. [ruby-talk:61466] * marshal.c (math.h): should be included after ruby.h on AIX. [ruby-talk:61366] Tue Jan 14 21:47:56 2003 Nobuyoshi Nakada * eval.c (rb_f_require): do not search adding .rb/.so suffixes if the suffix specified. [ruby-dev:18702] http://moonrock.jp/~don/d/200211.html#d08_t1 Tue Jan 14 18:36:41 2003 Yukihiro Matsumoto * enum.c (enum_all): now works without block. * enum.c (enum_any): ditto. Tue Jan 14 01:21:32 2003 Nobuyoshi Nakada * io.c (next_argv): not always set binmode. Mon Jan 13 20:45:19 2003 Guy Decoux * parse.y (list_append): avoid O(n) search using node->nd_next->nd_end. * parse.y (list_concat): ditto. * eval.c (rb_eval): NODE_ARRY nd_end adoption. Mon Jan 13 02:22:11 2003 WATANABE Hirofumi * ext/dl/lib/dl/win32.rb: eliminate unnecessary "A" adding. Sun Jan 12 16:07:17 2003 WATANABE Hirofumi * io.c (next_argv): inherit binmode from $defout. Sat Jan 11 22:50:47 2003 WATANABE Hirofumi * ext/dl/lib/dl/win32.rb: compatibility improvement. Sat Jan 11 01:44:16 2003 Nobuyoshi Nakada * configure.in (RUBY_CHECK_IO_NEED): added more tests. * io.c (rb_io_check_readable): seek after synchronized write. Fri Jan 10 01:23:45 2003 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-font-lock-syntactic-keywords): syntax classes are not allowed inside character classes. [ruby-talk:60996] Thu Jan 9 23:28:01 2003 Nobuyoshi Nakada * configure.in: AC_MSG_FAILURE is a new macro in 2.54b or later. Thu Jan 9 17:05:24 2003 Nobuyoshi Nakada * configure.in (RUBY_CHECK_IO_NEED): check whether fseek() and fflush() are needed. * io.c (flush_before_seek): flush write stream only. * io.c (rb_io_check_readable): seek instead of flush if the last operation was write. * io.c (rb_io_check_writable): seek instead of flush if the last operation was read. * bcc32/Makefile.sub, win32/Makefile.sub: needs to seek between R/W. Thu Jan 9 16:31:51 2003 Yukihiro Matsumoto * eval.c (rb_eval): should not discard nested NODE_BLOCK. Thu Jan 9 15:12:30 2003 Yukihiro Matsumoto * parse.y (stmt): NODE_NOT elimination for if/unless/while/until node. * parse.y (primary): ditto. Thu Jan 9 13:26:18 2003 Akinori MUSHA * st.h, st.c: Back out the introduction of st_*_func_t. Some compilers complain about function type mismatch. Thu Jan 9 02:10:44 2003 Yukihiro Matsumoto * eval.c (rb_eval): reduce recursive rb_eval() call by using sort of continuation passing style. Wed Jan 8 17:10:32 2003 NAKAMURA Usaku * ext/Win32API/lib/win32/registry.rb: added. [new] Wed Jan 8 15:54:05 2003 Yukihiro Matsumoto * eval.c: remove ruby_last_node and assignments seems to be unnecessary * intern.h: debug does not run if ID_ALLOCATOR is zero. Wed Jan 8 15:04:11 2003 Yukihiro Matsumoto * range.c (range_each): treat fixnums specially to boost. * numeric.c (num_step): remove rb_scan_args() for small speedup. Tue Jan 7 17:56:08 2003 Yukihiro Matsumoto * eval.c (svalue_to_avalue): should return converted array. Tue Jan 7 07:48:01 2003 Nobuyoshi Nakada * eval.c (rb_f_local_variables): skip $_, $~ and flip states in dynamic variables. [ruby-core:00681] Tue Jan 7 02:46:29 2003 Yukihiro Matsumoto * hash.c (env_clear): new Hash compatible method. * hash.c (env_shift, env_invert, env_replace, env_update): ditto. Mon Jan 6 23:36:29 2003 Akinori MUSHA * st.h, st.c: Introduce new conventional typedef's, st_data_t, st_compare_func_t, st_hash_func_t and st_each_func_t. * st.h, st.c: Do explicit function declarations and do not rely on implicit declarations. * class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c: Add proper casts to avoid warnings. Mon Jan 6 20:44:43 2003 Akinori MUSHA * intern.h (rb_check_array_type): Declare rb_check_array_type(). * ext/digest/md5/md5ossl.c: Include stdio.h for sprintf() and string.h for memcmp(). * ext/dl/ptr.c: Include ctype.h for isdigit(). Mon Jan 6 18:43:17 2003 NAKAMURA Usaku * file.c: improve DOSISH drive letter support. Mon Jan 6 18:31:45 2003 WATANABE Hirofumi * lib/fileutils.rb (ln): add ' -f' in the verbose message. * lib/fileutils.rb (cp_r): add 'p' in the verbose message. Mon Jan 6 16:44:52 2003 Yukihiro Matsumoto * array.c (rb_ary_join): dispatch based on "to_str". * array.c (rb_ary_times, rb_ary_equal): ditto. Mon Jan 6 13:26:35 2003 NAKAMURA Usaku * process.c (proc_exec_v): follow to proc_spawn_v(). call do_aspawn() on Win32. * process.c (rb_proc_exec): call do_spawn() on Win32. * win32/win32.c, win32/win32.h (do_spawn, do_aspawn): add mode flag. * process.c (proc_spawn_v, rb_f_system): follow above change. Mon Jan 6 05:11:15 2003 Nobuyoshi Nakada * ext/extmk.rb: make $0 normal variable. Mon Jan 6 02:32:46 2003 Nobuyoshi Nakada * struct.c (make_struct): needs meta class. Sun Jan 5 22:54:05 2003 WATANABE Hirofumi * lib/fileutils.rb (ln): `argv' is not a argument. Sun Jan 5 17:44:37 2003 Nobuyoshi Nakada * ext/extmk.rb (extmake): set $0 temporarily while loading extconf.rb. Sun Jan 5 14:46:46 2003 WATANABE Hirofumi * instruby.rb: need paren in regexp(make -n install). * ext/extmk.rb (sysquote): do not need to quote on mswin/bccwin/mingw. * ext/extmk.rb ($mflags): uniq items and remove '-' and '--'. move options to the lead. * lib/fileutils.rb (install): model on the real install command(message). Sun Jan 5 09:36:46 2003 Nobuyoshi Nakada * ruby.c (ruby_init_loadpath): under Windows, get the module path from an internal address instead of hard coded library name. * cygwin/GNUmakefile.in, bcc32/Makefile.sub, win32/Makefile.sub (CPPFLAGS): removed LIBRUBY_SO macro. * bcc32/Makefile.sub, win32/Makefile.sub (config.h): no longer depends on makefiles. Sun Jan 5 04:17:05 2003 Akinori MUSHA * gc.c (SET_STACK_END): Issue a FLUSH_REGISTER_WINDOWS here too. This fixes make test on FreeBSD/sparc64. Sun Jan 5 03:43:47 2003 Akinori MUSHA * defines.h (FLUSH_REGISTER_WINDOWS): Make the flushw call an inline function so it can be used as an expression. * eval.c (EXEC_TAG, THREAD_SAVE_CONTEXT): Consistently call FLUSH_REGISTER_WINDOWS before calling setjmp(). (I suspect that every setjmp() implementation should take care of register windows, though) Sun Jan 5 03:12:32 2003 NAKAMURA Usaku * file.c (utimbuf): use utimbuf instead of _utimbuf if defined _WIN32. * win32/Makefile.sub (LIBS): use oldnames.lib. * win32/win32.c (rb_w32_getcwd): follow above change. * win32/win32.h: ditto. * wince/direct.c, wince/direct.h (getcwd): ditto. * wince/io.h: ditto. * wince/string.c, wince/wince.h (stricmp, strnicmp): ditto. Sat Jan 4 15:18:50 2003 NAKAMURA Usaku * process.c (rb_proc_exec): use same logic as DJGPP on win32 ports. * process.c (rb_f_system): ditto. * win32/win32.c, win32/win32.h (do_aspawn): [new]. for arrayed arguments. * win32/win32.c (CreateChild): add new argument for real filename of executing process. * win32/win32.c (NtHasRedirection, pipe_exec): follow above change. Sat Jan 4 14:29:52 2003 NAKAMURA Usaku * configure.in: set rb_cv_need_io_flush_between_seek=yes. * win32/Makefile.sub (config.h): define NEED_IO_FLUSH_BETWEE_SEEK. (pointed out by moriq [ruby-dev:19299]) Sat Jan 4 03:12:14 2003 Yukihiro Matsumoto * eval.c (umethod_bind): exact class match is not required. relax the restriction to subclasses. Sat Jan 4 01:33:40 2003 Nobuyoshi Nakada * file.c (rb_file_s_lchmod): get rid of gcc-3 -O3 warning. Fri Jan 3 22:26:07 2003 Nobuyoshi Nakada * process.c (rb_proc_times): need to initialize first. Fri Jan 3 01:10:17 2003 Yukihiro Matsumoto * eval.c (rb_eval): call "inherited" before executing class body. * class.c (rb_define_class): call "inherited" after defining the constant. * class.c (rb_define_class_under): ditto. Thu Jan 2 19:37:30 2003 Yukihiro Matsumoto * eval.c (massign): expand first element if RHS is an array and its size is 1, and LHS has concrete assignment target (i.e. LHS has target(s) other than *var). * eval.c (massign): avoid unnecessary avalue/svalue conversion. * eval.c (rb_yield_0): ditto * array.c (rb_ary_update): do not allocate unused array if rpl is nil (i.e. merely removing elements). Thu Jan 2 13:55:08 2003 Mathieu Bouchard * io.c (io_read): should resize supplied string if it's shorter than expected. Thu Jan 2 11:01:20 2003 Nobuyoshi Nakada * eval.c (bmcall): arguments should be an array. Wed Jan 1 18:18:45 2003 WATANABE Hirofumi * configure.in: better DJGPP support. add GNUmakefile. * djgpp/GNUmakefile: new. Wed Jan 1 04:16:18 2003 Akinori MUSHA * node.h (struct RNode): Change argc from int to long. Otherwise NEW_CFUNC() sets argc to a wrong value on platforms where sizeof(int) != sizeof(long) and the byte order is big-endian. This fixes breakage on FreeBSD/sparc64. Tue Dec 31 23:22:50 2002 Yukihiro Matsumoto * eval.c (massign): removed awkward conversion between yvalue, mvalue, etc. * eval.c (rb_yield_0): new parameter added to tell whether val is an array value or not. * parse.y (yield_args): restructuring: new nodes: NODE_RESTARY2, NODE_SVALUE; removed node: NODE_RESTARGS. Tue Dec 31 21:13:51 2002 WATANABE Hirofumi * Makefile.in, {win32,bcc32}/Makefile.sub: add new target: what-where, no-install. * mkconfig.rb: add const: CROSS_COMPILING. * ext/extmk.rb: no-install support. add MAKEDIRS macro. * lib/mkmf.rb: add !ifdef .. !endif for Borland make. * process.c: improve DJGPP support. system "ls", "-l". Tue Dec 31 20:16:37 2002 Akinori MUSHA * ext/socket/addrinfo.h (NI_MAXHOST): Define NI_MAXHOST and NI_MAXSERV only if they are not defined yet. This fixes build on such platforms as OpenBSD. Tue Dec 31 20:07:49 2002 Akinori MUSHA * ext/tcltklib/extconf.rb (find_tcl, find_tk): Look for both lib{tcl,tk}M.N and lib{tcl,tk}MN on all platforms. *BSD have Tcl/Tk libraries named this way. Tue Dec 31 19:48:21 2002 Akinori MUSHA * configure.in: Improve OpenBSD support. [obtained from: OpenBSD ports] * dln.c (FUNCNAME_PATTERN): Ditto. Tue Dec 31 19:21:02 2002 Akinori MUSHA * array.c (rb_ary_transpose): Properly declare ary as a VALUE. * file.c (rb_file_s_chmod): Do not directly cast an int to void * to avoid a warning. * defines.h (FLUSH_REGISTER_WINDOWS): Add support for FreeBSD/sparc64. miniruby still coredumps in a different place, though. Tue Dec 31 07:47:15 2002 Nobuyoshi Nakada * parse.y (parse_string): readjusted. * parse.y (heredoc_identifier): readjusted. * parse.y (here_document): make EOL codes of single-quoted here-documents consistent. * parse.y (yylex): reduced unnecessary conditionals. Tue Dec 31 04:49:51 2002 Akinori MUSHA * ruby.1: mdoc'ify. Tue Dec 31 01:30:29 2002 WATANABE Hirofumi * parse.y (yylex): do not accept " __END__\n". ([ruby-dev:19245]) Mon Dec 30 21:10:59 2002 WATANABE Hirofumi * parse.y (yylex): use strncmp instead of strcmp. accept "__END__\r\n". ([ruby-dev:19241]) Mon Dec 30 20:32:14 2002 Yukihiro Matsumoto * gc.c (rb_gc_mark_frame): should mark frame->node. Mon Dec 30 19:10:30 2002 Nobuyoshi Nakada * ext/extmk.rb: split --make argument contains options, assume the first word of --make-flags is always options even unless preceded by -, and ignore letter-case of options if nmake. * instruby.rb: extract -n option also from --make and --make-flags. * bcc32/Makefile.sub, win32/Makefile.sub: not prepend - to $(MFLAGS) Mon Dec 30 16:44:14 2002 Nobuyoshi Nakada * string.c (rb_str_substr): should share the shared string if present, instead of the original string. (ruby-bugs:PR#528) Mon Dec 30 05:10:00 2002 Nobuyoshi Nakada * ext/socket/socket.c (tcp_svr_init): local host to init_inetsock() is VALUE but not pointer. * ext/socket/socket.c (sock_s_unpack_sockaddr_in): get rid of gcc-3 -O3 warning. Sun Dec 29 23:45:53 2002 Nobuyoshi Nakada * gc.c (gc_sweep): adjust GC trigger. * dln.c (init_funcname_len): get rid of gcc-3 -O3 warning. * eval.c (copy_node_scope): ditto. * hash.c (rb_hash_foreach, delete_if_i, select_i, each_value_i, each_key_i, each_pair_i, envix): ditto. * range.c (range_each_func): ditto. * file.c (rb_file_s_chmod): ditto. Sun Dec 29 15:30:37 2002 Minero Aoki * lib/fileutils.rb (fu_parseargs): should not inherit ftools.rb's misfeature. Sun Dec 29 05:08:13 2002 NAKAMURA Usaku * lib/fileutils.rb (cmp): return false if file size differs. Sat Dec 28 19:21:24 2002 WATANABE Hirofumi * instruby.rb: remove junk args. * lib/mkmf.rb (create_makefile): remove a trouble library before making a shared library. * win32/Makefile.sub: invoke instruby.rb with the --make-flags option. Sat Dec 28 03:09:58 2002 Wakou Aoyama * lib/cgi.rb (CGI#[]): improvement. thanks to Kazuhiro NISHIYAMA Sat Dec 28 00:34:03 2002 WATANABE Hirofumi * {win32,bcc32}/Makefile.sub: remove `=' from --make-flags options. nmake quotes args if included `=' in args. * instruby.rb: use getopts.rb. * ext/dbm/extconf.rb (-DDBM_HDR): substitute ' with " to avoid a error on Win32. * ext/gdbm/gdbm.c: add prototypes to avoid VC++ warnings. Fri Dec 27 21:41:57 2002 Nobuyoshi Nakada * bcc32/setup.mak, win32/setup.mak(-prologue-): move srcdir from CPP input or UNC path will be removed as a comment. Fri Dec 27 17:55:00 2002 Takaaki Uematsu * wince/config, wince/configure.bat: replace 1.7 with 1.8 in macros. Fri Dec 27 13:28:14 2002 Minero Aoki * instruby.rb: fileutils.rb accepts only one argument. Fri Dec 27 13:23:29 2002 Minero Aoki * lib/fileutils.rb (fu_parseargs): reject illegal options correctly. * lib/fileutils.rb (uptodate?): parameter declaration was wrong. * lib/fileutils.rb: change coding styles. Fri Dec 27 09:25:22 2002 ABE Shigeru * process.c (rb_proc_times): avoid WindowsXP crash using volatile variables. Fri Dec 27 02:56:58 2002 Nobuyoshi Nakada * instruby.rb: check only `-' option, and use fileutils instead of ftools. Fri Dec 27 02:45:17 2002 Wakou Aoyama * lib/net/telnet.rb: Telnet#print not add "\n". * lib/cgi.rb: cgi['key'] is equal cgi['key'][0] Thu Dec 26 22:33:18 2002 WATANABE Hirofumi * ext/extmk.rb (create_makefile): check only `-' option. * configure.in: cleanups for MinGW. remove -D__NO_ISOCEXT in $CFLAGS. * win32/win32.h: prototypes for isinf, isnan are not needed on MinGW. Thu Dec 26 19:22:00 2002 YOSHIDA Kazuhiro * win32/setup.mak (-prologue-): moved srcdir macro definition. [ruby-win32:420]. Wed Dec 25 18:26:44 2002 K.Kosako * regex.c (re_match): fixed wrong \G behavior. (ruby-bugs-ja:PR#377) Wed Dec 25 16:41:16 2002 Yukihiro Matsumoto * regex.c (re_match_exec): fix odd \G behavior based on the patch from Nobu. Wed Dec 25 11:05:11 2002 Nobuyoshi Nakada * bcc32/setup.mak (-generic-): removed garbages. Wed Dec 25 10:36:20 2002 NAKAMURA Usaku * bcc32/Makefile.sub, win32/Makefile.sub (RUBY_SO_NAME, config.h): use $(MAJOR) and $(MINOR). based on Nobu's patch. [ruby-win32:413] * bcc32/setup.mak, win32/setup.mak (-prologue-): define MAJOR, MINOR and TEENY from version.h. based on Nobu's patch. [ruby-win32:413] * win32/Makefile.sub (config.h): add HAVE_FLOAT_H. * win32/Makefile.sub (parse.obj): depend on win32/win32.h. Tue Dec 24 23:49:16 2002 Akinori MUSHA * lib/irb/completion.rb: Use Object#class rather than Object#type. Tue Dec 24 23:37:40 2002 TADA Tadashi * lib/cgi.rb (Cookie::parse), lib/cgi-lib.rb (initialize): Do not pass to split() a bare string longer than 2 characters as separator. Tue Dec 24 19:19:24 2002 Tietew * numeric.c (DBL_MAX_10_EXP): fix typo. [ruby-dev:19175] Tue Dec 24 17:02:46 2002 Yukihiro Matsumoto * eval.c (rb_undefined): use NoMethodError instead of fatal. Tue Dec 24 02:12:45 2002 Akinori MUSHA * lib/README: Synchronize with reality. Tue Dec 24 02:05:51 2002 Akinori MUSHA * MANIFEST, lib/README, lib/ipaddr.rb: Add ipaddr.rb from rough. Sun Dec 22 04:07:47 2002 NAKAMURA Usaku * ext/dbm/dbm.c (fdbm_alloc): allocator takes only one argument. Sun Dec 22 02:49:25 2002 NAKAMURA Usaku * array.c (ary_alloc), dir.c (dir_s_alloc), eval.c (thgroup_s_alloc), file.c (rb_stat_s_alloc), hash.c (hash_alloc), io.c (io_alloc), object.c (rb_module_s_alloc, rb_class_allocate_instance), re.c (match_alloc, rb_reg_s_alloc), string.c (str_alloc), time.c (time_s_alloc), ext/digest/digest.c (rb_digest_base_alloc), ext/tcltklib/tcltklib.c (ip_alloc), ext/win32ole/win32ole.c (fole_s_allocate, fev_s_allocate) : add prototype to get rid of VC++ warnings. * ext/sdbm/init.c (fsdbm_alloc): allocator takes only one argument. Sun Dec 22 00:36:43 2002 WATANABE Hirofumi * lib/mkmf.rb (create_makefile): accept pure ruby libraries. Sat Dec 21 23:59:42 2002 Yukihiro Matsumoto * class.c (ins_methods_i): should not show ID_ALLOCATOR. * class.c (ins_methods_prot_i): ditto. * class.c (ins_methods_priv_i): ditto. * class.c (ins_methods_pub_i): ditto. * eval.c (call_trace_func): ditto. * eval.c (rb_undefined): ditto. Sat Dec 21 07:27:24 2002 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-parse-partial): keywords must not be preceded by @ or $. Fri Dec 20 20:29:04 2002 Nobuyoshi Nakada * ext/curses/curses.c, ext/dbm/dbm.c, ext/digest/digest.c, ext/dl/handle.c, ext/dl/ptr.c, ext/dl/sym.c, ext/gdbm/gdbm.c, ext/iconv/iconv.c, ext/sdbm/init.c, ext/stringio/stringio.c, ext/strscan/strscan.c, ext/tcltklib/tcltklib.c, ext/win32ole/win32ole.c: use rb_define_alloc_func(). Fri Dec 20 18:29:04 2002 Nobuyoshi Nakada * io.c (rb_io_fwrite): separated from io_write(). * marshal.c (w_byten): use rb_io_fwrite() to support non-blocking IO, and added error check. * rubyio.h: prototypes; rb_io_fwrite Fri Dec 20 17:40:59 2002 Yukihiro Matsumoto * object.c (Init_Object): should not remove Class#allocate. * lib/profiler.rb: separate profiling functions, without trace_func and at_exit setting. Fri Dec 20 16:20:04 2002 Yukihiro Matsumoto * parse.y (do_block): split "do" block and tLBRACE_ARG block. * parse.y (cmd_brace_block): new tLBRACE_ARG block rule * parse.y (command): can take optional cmd_brace_block; use %prec to resolve shift/reduce conflict. (ruby-bugs-ja PR#372) * eval.c (ruby_finalize): trace_func should be cleared here (after executing exit procs and finalizers). * eval.c (rb_define_alloc_func): new allocation framework, based on Nobu's work [ruby-dev:19116]. "allocate" method is no longer used for object allocation. Fri Dec 20 05:06:49 2002 Akinori MUSHA * lib/README, lib/cgi/ftplib.rb, lib/telnet.rb: Delete ftplib.rb and telnet.rb. It has been quite some time sinc they were obsoleted and made to emit warnings. Fri Dec 20 04:58:22 2002 Akinori MUSHA * lib/tempfile.rb: Embed Rdoc style comments. * lib/tempfile.rb: Add length as an alias for size. Fri Dec 20 03:57:32 2002 Akinori MUSHA * lib/tempfile.rb: Add Tempfile#close!() as a shorthand for Tempfile#close(true). * lib/tempfile.rb: Add Tempfile#{unlink,delete}(). Fri Dec 20 03:53:01 2002 Akinori MUSHA * lib/README, lib/cgi/final.rb, lib/cgi/session.rb: Delete final.rb, which was obsoleted long ago. Fri Dec 20 00:16:06 2002 Nobuyoshi Nakada * re.c (rb_reg_match_pre, rb_reg_match_post, match_to_a, match_select): return instances of same class as the original string. [ruby-dev:19119] Thu Dec 19 22:55:49 2002 NAKAMURA Usaku * numeric.c (DBL_EPSILON): fix typo. Thu Dec 19 22:35:20 2002 Nobuyoshi Nakada * eval.c (assign): avoid [BUG] at multiple attribute assignment. Thu Dec 19 01:00:09 2002 Yukihiro Matsumoto * numeric.c (num_step): use DBL_EPSILON. * array.c (rb_check_array_type): new function: return an array (convert if possible), or nil. * string.c (rb_check_string_type): new function: return a string (convert if possible), or nil. * numeric.c (rb_dbl_cmp): returns nil if values are not comparable. * numeric.c (fix_cmp,flo_cmp): use rb_num_coerce_cmp() * bignum.c (rb_big_cmp): ditto. * numeric.c (rb_num_coerce_cmp): new coercing function for "<=>", which does not raise TypeError. * numeric.c (do_coerce): can be suppress exception now. * object.c (rb_mod_cmp): should return nil for non class/module objects. Thu Dec 19 04:21:10 2002 Akinori MUSHA * lib/open-uri.rb: add a missing ||. (found by: ruby -wc) Wed Dec 18 17:53:05 2002 Yukihiro Matsumoto * re.c (rb_reg_eqq): return false if the argument is not a string. now returns boolean value. * class.c (rb_include_module): argument should be T_MODULE, not T_class, nor T_ICLASS. Wed Dec 18 03:52:55 2002 Nobuyoshi Nakada * string.c (rb_str_new4): handle tail shared string. (ruby-bugs-ja:PR#370) * string.c (rb_str_dup_frozen): ditto. Tue Dec 17 21:08:29 2002 Nobuyoshi Nakada * node.h (NODE_ATTRASGN): new node, assignment to attribute. [ruby-core:00637]. * eval.c (is_defined, rb_eval): ditto. * parse.y (attrset, node_assign): ditto. * string.c (rb_str_substr): tail sharing. [ruby-core:00650] * re.c (rb_reg_nth_match): ditto. Tue Dec 17 16:52:38 2002 Yukihiro Matsumoto * eval.c (is_defined): "defined?" should return "assignment" for attribute assignment (e.g. a.foo=b) and indexed assignment (e.g. a[2] = 44). * parse.y (aryset): use NODE_ATTRASGN. Tue Dec 17 04:03:45 2002 Tanaka Akira * lib/open-uri.rb: new file. Tue Dec 17 00:28:19 2002 NAKAMURA Usaku * file.c (utimbuf): need to define for VC++. Mon Dec 16 15:53:20 2002 Nobuyoshi Nakada * parse.y (nextc): get rid of overrun. (pointed out by akr [ruby-list:36773]) Sun Dec 15 21:16:44 2002 WATANABE Hirofumi * lib/mkmf.rb (init_mkmf): add $(topdir) to $LIBPATH if $extmk. remove adding $(archdir) to $LIBPATH. Sat Dec 15 12:15:00 2002 Takaaki Uematsu * configure.in, defines.h, dir.c, dir.h, dln.c, error.c, eval.c, file.c, hash.c, io.c, main.c, missing.c, process.c, ruby.c, rubysig.h, signal.c, st.c, util.c, util.h, bcc/Makefile.sub, win32/Makefile.sub, win32/win32.h, ext/Win32API/Win32API.c, ext/socket/getaddrinfo.c, ext/socket/getnameinfo.c, ext/socket/socket.c, ext/tcltklib/stubs.c : replace "NT" with "_WIN32", add DOSISH_DRIVE_LETTER * wince/exe.mak : delete \r at the end of lines. * wince/mswince-ruby17.def : delete rb_obj_become Sun Dec 15 11:43:26 2002 Nobuyoshi Nakada * parse.y (dispose_string): dispose String object. * parse.y (heredoc_restore, here_document): fix memory leak. Sat Dec 14 14:25:00 2002 Takaaki Uematsu * wince/sys : add stat.c, stat.h, timeb.c, timeb.h, types.h, utime.c, utime.h * wince/dll.mak : object file name changed. * wince/io.c : add empty dup2(). * wince/io.h : add dup2 definition. Sat Dec 14 01:51:29 2002 WATANABE Hirofumi * ext/dbm/extconf.rb (rb_check): support for GNU dbm 1.8.3. (-with-dbm-type=gdbm_compat). link against -lgdbm_compat and -lgdbm. Fri Dec 13 23:42:16 2002 WATANABE Hirofumi * ext/dbm/extconf.rb (db_check): check existence of the function in the specified library before checking it in libc. Fri Dec 13 17:15:49 2002 Yukihiro Matsumoto * variable.c (generic_ivar_get): should always warn uninitialized instance variables. Fri Dec 13 12:33:22 2002 Nobuyoshi Nakada * parse.y (expr): rescue clause was ignored. Thu Dec 12 18:19:14 2002 WATANABE Hirofumi * configure.in (RUBY_PROG_GNU_LD): add $CFLAGS, $CPPFLAGS, $LDFLAGS to the option of $CC. * configure.in: set LIBRUBYARG to '-l$(RUBY_SO_NAME)' if the target os is cygwin and --disable-shared option is supplied. * lib/mkmf.rb (init_mkmf): expand config["LIBRUBY"] and config["LIBRUBY_A"]. don't link $LIBRUBYARG_STATIC if --disable-shared option is supplied. * configure.in (RUBY_CPPOUTFILE): should be a better message. * ext/Win32API/extconf.rb: join with a space. Thu Dec 12 17:27:19 2002 Yukihiro Matsumoto * re.c (rb_reg_hash): define Regexp#hash to make regexps to be hash keys. * re.c (Init_Regexp): define Regexp#eql? (alias to Regexp#==). Thu Dec 12 16:26:31 2002 Nobuyoshi Nakada * marshal.c (r_object0): singleton class instance can't be loaded. (ruby-bugs-ja:PR#366) Wed Dec 11 23:35:43 2002 WATANABE Hirofumi * ext/extmk.rb (create_makefile): -no-undefined -> --no-undefined. Wed Dec 11 17:54:59 2002 Yukihiro Matsumoto * io.c (io_read): takes optional second argument to specify a string to be written. the string should not be frozen. * io.c (rb_io_sysread): ditto. Wed Dec 11 11:30:28 2002 Nobuyoshi Nakada * ext/digest/digest.c (rb_digest_base_copy): renamed "become". * ext/stringio/stringio.c (strio_copy): ditto. Wed Dec 11 00:45:00 2002 Yukihiro Matsumoto * lib/getoptlong.rb (GetoptLong::Error): provide a common ancestor for GetoptLong error classes (RCR#129). Tue Dec 10 17:42:39 2002 K.Kosako * re.c (rb_reg_copy_object): fixed memory leak. Tue Dec 10 17:30:35 2002 Tanaka Akira * pack.c (utf8_limits): fix the limit of 4 bytes UTF-8 sequence. Tue Dec 10 12:01:15 2002 Nobuyoshi Nakada * eval.c (mnew): original class of method defined in module should be the module not intermediate class. [ruby-dev:19040] Tue Dec 10 01:16:52 2002 Yukihiro Matsumoto * sprintf.c (rb_f_sprintf): preceding ".." for negative numbers still left; removed. * sprintf.c (rb_f_sprintf): should not prepend '0' if width > prec for example "%5.3d". Sat Dec 7 18:14:23 2002 Yukihiro Matsumoto * process.c (Init_process): add Process.exit and Process.abort * pack.c (utf8_to_uv): raise ArgumentError for malformed/redundant UTF-8 sequences. Fri Dec 6 03:46:00 2002 Yukihiro Matsumoto * process.c (last_status_set): add pid attribute to Process::Status. Wed Dec 4 17:31:42 2002 Yukihiro Matsumoto * pack.c (uv_to_utf8): limit maximum length of the encoded string to 6 bytes, even when the platform supports 8 bytes long integers. * pack.c (utf8_to_uv): do not decode sequences longer than 6 bytes. * object.c (copy_object): use "copy_object" method, not "become". Wed Dec 4 16:37:11 2002 Yukihiro Matsumoto * object.c (copy_object): copy finalizers as well if any. * gc.c (rb_gc_copy_finalizer): new function to copy finalizers. Tue Dec 3 01:13:41 2002 Tanaka Akira * lib/pp.rb (PP.singleline_pp): new method. Sun Dec 1 23:04:03 2002 Nobuyoshi Nakada * lib/optparse.rb (OptionParser::new): same as OptionParser#on but returns new OptionParser::switch. Sun Dec 1 22:43:29 2002 Nobuyoshi Nakada * win32/win32.c (rb_w32_stat): empty path is invalid, and return ENOENT rather than EBADF in such case. [ruby-talk:57177] Fri Nov 29 18:01:48 2002 Yukihiro Matsumoto * pack.c (utf8_to_uv): added checks for malformed or redundant UTF-8 sequences. Thu Nov 28 12:08:30 2002 Akinori MUSHA * lib/mkmf.rb: Avoid the use of "clean::" in favor of "clean:" in order not to let make(1) choke if there is another dependency on the target added in a depend file. Thu Nov 28 02:40:42 2002 Akinori MUSHA * lib/mkmf.rb: Make sure to dig the destination directory before installing a file there. Formerly "make install" could fail depending on make(1)'s mood of the moment, especially when -jN is given. Wed Nov 27 17:39:38 2002 Akinori MUSHA * ext/syslog/syslog.c: Cut redundancy. * ext/syslog/syslog.c: Do not leak ident. Wed Nov 27 17:25:29 2002 Akinori MUSHA * ext/syslog/syslog.c, ext/syslog/test.rb: Syslog.close should raise RuntimeError when not opened. * ext/syslog/syslog.c, ext/syslog/test.rb: Syslog.{ident,options,facility,mask} should all return nil when not opened. * ext/syslog/syslog.c, ext/syslog/test.rb: Change back the output format of inspect(). Wed Nov 27 16:25:43 2002 Akinori MUSHA * ext/digest/test.rb: Switch from RUnit to Test::Unit. Wed Nov 27 16:14:12 2002 Akinori MUSHA * ext/syslog/syslog.c: Fix a problem where Syslog.ident was not marked and could thus be GC'd. Wed Nov 27 16:11:53 2002 Akinori MUSHA * ext/syslog/test.rb: Switch from RUnit to Test::Unit. * ext/syslog/test.rb: The output format of inspect() is slightly altered. Wed Nov 27 06:43:26 2002 Nobuyoshi Nakada * error.c (exit_initialize): add SystemExit#initialize to set instance variable status. (ruby-bugs-ja:PR#362) Now accepts status as optional first argument. * eval.c (error_handle): now SystemExit have status always. * eval.c (system_exit): just instantiate SystemExit without raise. * eval.c (rb_thread_start_0): initialize SystemExit properly. Tue Nov 26 10:17:04 2002 Yukihiro Matsumoto * dln.c (init_funcname_len): remove MAXPATHLEN dependency. Mon Nov 25 19:55:38 2002 WATANABE Hirofumi * ext/extmk.rb (extmake): return true if not dynamic and not static. Mon Nov 25 01:08:40 2002 WATANABE Hirofumi * dln.c: revert and add the MAXPATHLEN definition on mswin32/mingw32. Sun Nov 24 20:36:53 2002 WATANABE Hirofumi * dln.c: move the MAXPATHLEN definition in front. Fri Nov 22 22:55:01 2002 Yukihiro Matsumoto * sprintf.c (rb_f_sprintf): preceding ".." for negative hexadecimal numbers should not appear if prec (e.g. %.4) is specified. * pack.c (NUM2I32): support platforms which does not have 32bit integers (e.g. Cray). Fri Nov 22 19:20:36 2002 Akinori MUSHA * instruby.rb: Install batch files on Windows. [Submitted by usa] Fri Nov 22 18:31:46 2002 Yukihiro Matsumoto * eval.c (rb_add_method): node may be NULL. Thu Nov 21 20:53:06 2002 Minero Aoki * lib/net/smtp.rb: changes coding style. * lib/net/pop.rb: ditto. * lib/net/protocol.rb: ditto. Thu Nov 21 20:17:08 2002 Minero Aoki * lib/net/http.rb: changes coding style. Thu Nov 21 20:04:06 2002 Minero Aoki * lib/net/http.rb: should not overwrite Host: header. (This patch is contributed by sean@ruby-lang.org) Thu Nov 21 20:01:33 2002 Minero Aoki * lib/net/http.rb: support Proxy-Authorization. (This patch is contributed by Alexander Bokovoy) Thu Nov 21 11:03:39 2002 Yukihiro Matsumoto * file.c (rb_find_file_ext): should not terminate searching with empty path, just ignore. * dir.c: remove inclusion. Wed Nov 20 02:07:12 2002 Yukihiro Matsumoto * compar.c (cmp_eq,cmp_gt,cmp_ge,cmp_lt,cmp_le): check using rb_cmpint(). * error.c (init_syserr): remove sys_nerr dependency. Wed Nov 20 01:52:21 2002 Yukihiro Matsumoto * numeric.c (num_cmp): added to satisfy Comparable assumption. * eval.c (rb_add_method): "initialize" should be public if it is a singleton method. Tue Nov 19 22:37:23 2002 Yukihiro Matsumoto * regex.c (re_match): avoid dereferencing if size == 0. (ruby-bugs-ja:PR#360) Tue Nov 19 20:40:39 2002 Yukihiro Matsumoto * time.c (time_cmp): should return nil if an operand is not a number nor time. (ruby-bugs-ja:PR#359) * file.c (rb_stat_cmp): should return nil if an operand is not File::Stat. Tue Nov 19 14:35:09 2002 Yukihiro Matsumoto * array.c (rb_ary_zip): iterates over items in the receiver. zipped with nil if argument arrays are shorter. if arrays are longer, left items are ignored. now works with blocks. * enum.c (zip_i): changed for new behavior. * array.c (rb_ary_transpose): added. [new] Tue Nov 19 05:12:21 2002 Akinori MUSHA * instruby.rb: Do not install various working files under bin/. Tue Nov 19 05:07:39 2002 Nobuyoshi Nakada * instruby.rb: not rewrite installed scripts when dry-run mode. * lib/ostruct.rb (OpenStruct::initialize): should symbolize keys instead of values. Tue Nov 19 02:24:10 2002 Akinori MUSHA * instruby.rb: Rewrite installed scripts' shebang lines. * instruby.rb: Use File.join() where appropriate. Tue Nov 19 01:53:35 2002 Akinori MUSHA * bin/irb: Moved from sample/irb.rb. * instruby.rb: Install script files under bin/ with ruby's program prefix and suffix. Mon Nov 18 02:13:36 2002 Akinori MUSHA * lib/tempfile.rb: Make this library thread safe. * lib/tempfile.rb: Do not pick a name which was once used and is still scheduled for removal. * lib/tempfile.rb: A lock file need not and must not be scheduled for removal. * lib/tempfile.rb: Compare Max_try with the number of mkdir failures instead of the suffix counter. * lib/tempfile.rb: Overall cleanup and add some important notices. Sun Nov 17 22:57:31 2002 Nobuyoshi Nakada * parse.y (dsym): garbage returned. (ruby-bugs-ja:PR#358) Fri Nov 15 07:40:08 2002 NAKAMURA, Hiroshi * observer.rb: raise NoMethodError instead of NameError. [ruby-dev:18788] * ostruct.rb: ditto. fix a bug in inspect which called String#+ with Symbol. [ruby-dev:18788] * profile.rb: illegal use of Array#sort!. replaced it with non-bang method. [ruby-dev:18792] Thu Nov 14 22:40:29 2002 Nobuyoshi Nakada * configure.in (LIBRUBY_A): append -static. [ruby-dev:18689] * configure.in (LIBRUBYARG_STATIC, LIBRUBYARG_SHARED): linker argument to link static/shared library respectively. * Makefile.in (LIBRUBYARG_STATIC, LIBRUBYARG_SHARED): added. * bcc32/Makefile.sub, win32/Makefile.sub: ditto. * instruby.rb (LIBRUBY_A): install to libdir. * lib/mkmf.rb (link_command): link static library of ruby, or try_run fails unless LIBRUBY_SO is installed. [ruby-dev:18646] * eval.c (call_trace_func): toplevel caller was missing. [ruby-dev:18754] * eval.c (proc_to_s): adjust created line number. * parse.y (primary, do_block, brace_block): adjust line number of block to beginning line, instead of the first statement inside the block. Thu Nov 14 08:23:42 2002 Yukihiro Matsumoto * math.c (math_acos): check errno after operation. ditto for asin, acosh, atanh, log, log10 and sqrt. * eval.c (rb_add_method): initialize should always be private. * parse.y (expr): add rescue modifier rule. * parse.y (command_call): return, break and next with argument is now part of this rule. Wed Nov 13 16:22:38 2002 Nobuyoshi Nakada * configure.in (DLDFLAGS): removed -Wl,-no-undefined to ext/extmk.rb, in order to allow references to symbols in other extension libraries for mkmf.rb. [ruby-dev:18724] * ext/extmk.rb (extmake): ditto. * ext/extmk.rb (extmake): exit when make failed. Sun Nov 10 03:46:18 2002 Akinori MUSHA * lib/set.rb: retire contain?() and add superset?(), proper_superset?() subset?(), and proper_subset?(). [obtained from: Jason Voegele's set.rb] * lib/set.rb: define several aliases: union() for |(), difference() for -(), and intersection() for &(). [obtained from: Jason Voegele's set.rb] * lib/set.rb: deal with a s/id/object_id/ leftover. Sat Nov 9 16:06:57 2002 WATANABE Hirofumi * ext/tcltklib/stubs.c: should include "util.h" for ruby_strdup. Sat Nov 9 11:39:45 2002 Nobuyoshi Nakada * eval.c: remove ENABLE_TRACE/DISABLE_TRACE to trace child nodes of c-call. [ruby-dev:18699] Fri Nov 8 04:16:55 2002 Yukihiro Matsumoto * parse.y (yylex): "a" in "a /5" should be considered as a local variable. [experimental] Thu Nov 7 09:51:37 2002 Nobuyoshi Nakada * eval.c (rb_yield_0): should enable trace for non-cfunc nodes. [ruby-dev:18645] * eval.c (blk_orphan): a block created in a different thread is orphan. [ruby-dev:17471] Wed Nov 6 16:57:06 2002 Yukihiro Matsumoto * class.c (rb_define_method): do not set NOEX_CFUNC if klass is really a module, whose methods must be safe for reciever's type. * eval.c (rb_eval): nosuper should not be inherited unless the overwritten method is an undef placeholder. Tue Nov 5 00:46:04 2002 Akinori MUSHA * ext/extmk.rb: Properly pass the given target to make(1). [pointed out by eban] Mon Nov 4 20:03:53 2002 NAKAMURA Usaku * instruby.rb, lib/mkmf.rb: use CONFIG["ENABLE_SHARED"] instead of checking whether CONFIG["configure-args"] includes "--enable-shared". Mon Nov 4 16:49:14 2002 Yukihiro Matsumoto * parse.y (primary): allow 'when'-less case statement; persuaded by Sean Chittenden. Mon Nov 4 06:28:09 2002 Akinori MUSHA * Makefile.in, ext/extmk.rb, bcc32/Makefile.sub, win32/Makefile.sub: Introduce better command line syntax (--make/--make-flags/--extstatic) to extmk.rb and instruby.rb. Previously such command as 'make -j3 install' with pmake doesn't fail. Formerly extmk.rb was receiving "make -j 3 -j 3" via the command line arguments and just ended up recognizing the first "3" as destdir. [with help of usa] Mon Nov 4 03:59:51 2002 Akinori MUSHA * lib/getopts.rb: Do not choke on characters that cannot be used in a variable name. Replace them with `_'. Define a hash named $OPT for convenience. Sat Nov 2 00:38:55 2002 Yukihiro Matsumoto * object.c (Init_Object): added Object#object_id, new name for Object#id. [new] * object.c (rb_obj_id_obsolete): give warning for Object#id. * numeric.c (fix_intern): added Fixnum#to_sym. [new] * object.c (sym_to_sym): rename from Symbol#intern Fri Nov 1 14:21:06 2002 Yukihiro Matsumoto * enum.c (enum_zip): added Enumerable#zip. [new] * array.c (rb_ary_zip): added Array#zip. Thu Oct 31 20:10:18 2002 Yukihiro Matsumoto * error.c (init_syserr): remove sys_nerr dependency. Thu Oct 31 09:31:51 2002 K.Kosako * eval.c (rb_export_method): undef'ed method visibility should not be changed. Wed Oct 30 17:00:47 2002 Yukihiro Matsumoto * eval.c (rb_mod_public_method_defined, etc.): new methods: public_method_defined?, private_method_defined?, protected_method_defined? * object.c (rb_obj_public_methods): new method Object#public_methods. * class.c (ins_methods_i): Object#methods should list both public and protected methods. * class.c (rb_class_public_instance_methods): new method Module#public_instance_methods. Wed Oct 30 06:29:00 2002 Akinori MUSHA * eval.c, file.c, gc.c, io.c, object.c, ruby.c, ruby.h, struct.c, ext/socket/socket.c: differentiate long and int; use proper printf type specifiers and do casts where appropriate. Wed Oct 30 04:07:33 2002 Nobuyoshi Nakada * eval.c (error_print, rb_longjmp, rb_thread_schedule): flush error message. [ruby-dev:18582] * eval.c (ruby_cleanup): added. just clean up without exit. [ruby-dev:18582] * eval.c (ruby_exec): added. execute main evaluation tree without exit. [ruby-dev:18582] * intern.h: prototypes; ruby_cleanup, ruby_exec Tue Oct 29 02:00:08 2002 Nobuyoshi Nakada * ext/extmk.rb (extmake): use dummy_makefile to create dummy Makefile. * lib/mkmf.rb (find_executable0): EXEEXT is optional. * lib/mkmf.rb (dummy_makefile): make dummy Makefile content. * lib/mkmf.rb (create_makefile): define EXTLIB replacing -l. * lib/mkmf.rb ($bccwin): detect Borland make by help message. * lib/mkmf.rb (CLEANINGS): common rules to clean. Mon Oct 28 01:27:17 2002 WATANABE Hirofumi * djgpp/config.sed (@program_transform_name@): use `%', not `,'. Sun Oct 27 22:59:50 2002 KONISHI Hiromasa * ext/extmk.rb(78) : The unnecessary error when installing by bccwin32 is controlled. * lib/mkmf.rb(773) : Also in the case of bccwin32, the path was added. Sun Oct 27 17:07:25 2002 WATANABE Hirofumi * djgpp/*: sync with the latest. * ext/extmk.rb, lib/mkmf.rb: flush $stdout. * io.c (READ_DATA_PENDING_COUNT, READ_DATA_PENDING_PTR): undef these macros on DJGPP. Sat Oct 26 10:11:47 2002 Akinori MUSHA * node.h (nd_type): cast the value to int. Sat Oct 26 04:27:35 2002 Akinori MUSHA * ext/dbm/dbm.c (fdbm_indexes, fdbm_select): add a missing argument and prevent coredump when a nonexistent key is specified. * ext/sdbm/init.c (fsdbm_indexes, fsdbm_select): ditto. Sat Oct 26 03:28:43 2002 Akinori MUSHA * eval.c, gc.c: use a common set of alloca() #ifdef's. This fixes the build with Intel C Compiler for Linux. * eval.c (rb_f_require): declare old_func with a real type, not just type modifiers. Fri Oct 25 02:55:01 2002 Minero Aoki * string.c (rb_str_split_m): RSTRING(str)->ptr might become NULL. [ruby-dev:18581] Thu Oct 24 21:57:02 2002 Nobuyoshi Nakada * configure.in (LIBPATHFLAG): avoid $ substitution. [ruby-dev:18577] * ext/extmk.rb (extmake): expand $srcdir. * ext/win32ole/extconf.rb: should not override $CFLAGS, but append. * lib/mkmf.rb (config_string): use given config hash. * bcc32/Makefile.sub (.rc.res): directory part may be empty in Borland make. Thu Oct 24 03:38:07 2002 Nobuyoshi Nakada * lib/mkmf.rb (create_makefile): site-install target for backward compatibility. * lib/mkmf.rb (init_mkmf): libdir prior to topdir. * configure.in (LIBPATHFLAG): should escape $. [ruby-dev:18572] * mkconfig.rb: never substitute escaped $$. * instruby.rb: not install LIBRUBY_SO unless enable-shared. [ruby-dev:18569] Wed Oct 23 19:16:06 2002 Nobuyoshi Nakada * eval.c (rb_eval): added NODE_DSYM, symbol literal with interpolation. * node.h: ditto. * intern.h: prototypes; rb_is_junk_id, rb_str_dump, rb_str_intern * object.c (sym_inspect): escape and quote for non-alphanumeric symbols. * parse.y (dsym, tokadd_string, yylex): extended symbol literals. * parse.y (rb_is_junk_id): added. * string.c (rb_str_dump, rb_str_intern) : make extern. * lib/mkmf.rb (create_makefile): deffile should be removed by distclean, not clean. Tue Oct 22 23:56:41 2002 WATANABE Hirofumi * lib/mkmf.rb (init_mkmf): add dir_config("opt"). Tue Oct 22 19:44:03 2002 KONISHI Hiromasa * bcc32/configure.bat : The command line when calling setup.mak is corrected. * bcc32/readme.bcc32 : It follows up about the option of configure.bat. Tue Oct 22 15:23:19 2002 Nobuyoshi Nakada * instruby.rb: add dryrun mode. * ext/extmk.rb (extmake): add install: target to dummy Makefile. * ext/extmk.rb (extmake): avoid Borland make's quirk behavior. * lib/mkmf.rb (link_command): opt is not a makefile macro. * bcc32/Makefile.sub ($(LIBRUBY_SO) $(LIBRUBY)): EXTOBJS were not linked. * bcc32/Makefile.sub (ext/extinit.obj): missing. * bcc32/Makefile.sub (TRY_LINK): options have to place before any non-option arguments. * win32/Makefile.sub (TRY_LINK): need -link and -libpath options. * bcc32/Makefile.sub, win32/Makefile.sub (RANLIB): logical operator never work with command.com. Tue Oct 22 00:59:59 2002 WATANABE Hirofumi * configure.in (RUBY_CPPOUTFILE): fix cache file bug. * lib/mkmf.rb (link_command): put 'opt' after conftest.c for static linking. Mon Oct 21 22:53:02 2002 Nobuyoshi Nakada * configure.in (XCFLAGS): CFLAGS to compile ruby itself. * configure.in (LIBEXT): suffix for static libraries. * configure.in (LIBPATHFLAG): switch template to specify library path. * configure.in (LINK_SO): command to link shared objects. * configure.in (DEFFILE, ARCHFILE): miscellaneous system dependent files. * configure.in (EXPORT_PREFIX): prefix to exported symbols on Windows. * configure.in (COMMON_LIBS, COMMON_MACROS, COMMON_HEADERS): libraries, macros and headers used in common. * configure.in (RUBYW_INSTALL_NAME, rubyw_install_name): GUI mode executable name. * Makefile.in (CFLAGS): append XCFLAGS. * Makefile.in (PREP): miscellaneous system dependent files. * Makefile.in (ruby.imp, ext/extinit.o): moved from ext/extmk.rb. * Makefile.in (fake.rb): CROSS_COMPILING keeps building platform. * Makefile.in (MAKEFILES): depend on *.in and config.status. * Makefile.in (parse.c): replace "y.tab.c" with actual name for byacc. * ext/extmk.rb, lib/mkmf.rb: integrated. * ext/extmk.rb: propagate MFLAGS. * ext/extmk.rb (extmake): make dummy Makefile to clean even if no Makefile is made. * lib/mkmf.rb (older): accept multiple file names and Time objects. * lib/mkmf.rb (xsystem): split and quote. * lib/mkmf.rb (cpp_include): make include directives. * lib/mkmf.rb (try_func): try whether specified function is available. * lib/mkmf.rb (install_files): default to site-install. * lib/mkmf.rb (checking_for): added. * lib/mkmf.rb (find_executable0): just find executable file with no message. * lib/mkmf.rb (create_header): output header file is variable. * lib/mkmf.rb (create_makefile): separate sections. * lib/mkmf.rb (init_mkmf): initialize global variables. * win32/Makefile.sub, bcc32/Makefile.sub (CPP, AR): added. * bcc32/Makefile.sub (ARCH): fixed to i386. * win32/Makefile.sub, bcc32/Makefile.sub (miniruby): should not link EXTOBJS. * ext/dl/extconf.rb: use try_cpp to cross compile. * ext/dl/extconf.rb: not modify files in source directory. Fri Oct 18 23:11:21 2002 Nobuyoshi Nakada * parse.y (value_expr0): allow return/break/next/redo/retry in rhs of logical operator. [ruby-dev:18534] * parse.y (remove_begin): eliminate useless NODE_BEGIN. [ruby-dev:18535] Fri Oct 18 01:02:44 2002 Akinori MUSHA * hash.c, eval.c: Use (*_NSGetEnviron()) instead of environ on Darwin for namespace cleanness. [ruby-core:00537] * dln.c (dln_load): Fix Darwin support that has been disabled and switch to using it on Darwin instead of the system dlopen(). [ruby-core:00541] Thu Oct 17 19:17:56 2002 Nobuyoshi Nakada * marshal.c (w_byten): added; write n bytes from s to arg. * marshal.c (dump): flush buffered data. * marshal.c (marshal_dump, r_byte, r_bytes0, marshal_load): unify marshaling I/O. [ruby-talk:53368] Thu Oct 17 12:58:24 2002 Minero Aoki * lib/fileutils.rb: stat.blksize might be 0/nil. * lib/fileutils.rb: change coding style. Wed Oct 16 22:35:53 2002 Nobuyoshi Nakada * sprintf.c (rb_f_sprintf): disallow mixed usage of numbered and unnumbered arguments. [ruby-dev:18531] get rid of memory leak at exception. [ruby-core:00460] Wed Oct 16 13:36:29 2002 Nobuyoshi Nakada * variable.c (rb_global_entry): not add global entry until initialized to avoid accessing it while GC. [ruby-dev:18514] * variable.c (rb_alias_variable): ditto. Wed Oct 16 01:03:54 2002 Yukihiro Matsumoto * object.c (rb_str_to_dbl): RString ptr might be NULL. * object.c (rb_cstr_to_dbl): p pointer might be NULL. * bignum.c (rb_str_to_inum): RString ptr might be NULL. * bignum.c (rb_cstr_to_inum): str pointer might be NULL. Sat Oct 12 23:44:11 2002 Nobuyoshi Nakada * win32/win32.c (rb_w32_putc): wrong condition to fill or flush on bccwin32. [ruby-win32:408] Fri Oct 11 15:58:06 2002 Yukihiro Matsumoto * parse.y (arg): rescue modifier is now an operator with precedence right below assignments. i.e. "a = b rescue c" now parsed as "a = (b rescue c)", not as "(a = b) rescue c". [new] [experimental] Fri Oct 11 06:05:30 2002 Nobuyoshi Nakada * win32/win32.c (rb_w32_fclose, rb_w32_close): use closesocket() for socket. [ruby-win32:382] * win32/win32.c (StartSockets): set NtSocketsInitialized. * win32/win32.h: prototypes; rb_w32_fclose, rb_w32_close Fri Oct 11 00:24:57 2002 Nobuyoshi Nakada * gc.c (ruby_xmalloc, ruby_xrealloc): restrict total allocation size according to memories consumed by live objects. [ruby-dev:18482] * gc.c (gc_sweep): estimate how live objects consume memories. Thu Oct 10 17:26:12 2002 WATANABE Hirofumi * ext/tcltklib/stubs.c (ruby_tcltk_stubs): fix memory leak. [ruby-dev:18478] Thu Oct 10 15:20:18 2002 Nobuyoshi Nakada * lib/weakref.rb (WeakRef::@@final): use Hash#delete. * lib/weakref.rb (WeakRef::__getobj__): examine if alive or not by ID_REV_MAP to deal with recycled object. [ruby-dev:18472] * lib/weakref.rb (WeakRef::weakref_alive?): ditto. Wed Oct 9 07:11:25 2002 Nobuyoshi Nakada * gc.c (gc_sweep): also adjust heaps_limits when free unused heap page. [ruby-core:00526] * io.c (io_fflush): condition to retry can occur. * io.c (io_write): returned 0 wrongly if no error occurred. Tue Oct 8 14:19:07 2002 Nobuyoshi Nakada * io.c (io_write): must check returned value from fwrite() before test with ferror(). (ruby-bugs-ja:PR#350) Tue Oct 8 10:55:23 2002 Tanaka Akira * lib/prettyprint.rb (PrettyPrint.singleline_format): new method. Mon Oct 7 16:43:07 2002 Yukihiro Matsumoto * bignum.c (bigdivrem): bignum zero's len should not be 0. Mon Oct 7 15:36:42 2002 Yukihiro Matsumoto * bignum.c (bigdivmod): wrong condition check for Bignum zero. * bignum.c (Init_Bignum): need to add Bignum#div. Sun Oct 6 00:49:15 2002 Minero Aoki * eval.c (rb_load): should not pass blocks to the loaded file. [ruby-dev:18458] Fri Oct 4 20:25:38 2002 Nobuyoshi Nakada * eval.c (rb_thread_interrupt, rb_thread_signal_raise): no need to save dead thread context. (same as [ruby-dev:18322]) (ruby-bugs-ja:PR#349) Fri Oct 4 13:05:58 2002 WATANABE Hirofumi * configure.in (RUBY_PROG_GNU_LD): check whether the linker is GNU ld. * ext/extmk.rb (create_makefile): add -Wl,-no-undefined to $DLDFLAGS on Linux if GNU ld is used and --enable-shared is specified. Fri Oct 4 02:21:16 2002 Yukihiro Matsumoto * bignum.c (rb_big_rshift): num should be initialized by carry bits if x is negative. * bignum.c (bigdivmod): len for bignum zero is 1, not 0. Thu Oct 3 20:22:11 2002 Nobuyoshi Nakada * bcc32/mkexports.rb: to work on cygwin via telnet. [ruby-win32:358] * ext/tcltklib/tcltklib.c (ip_invoke): requires command name argument. [ruby-dev:18438] * eval.c (ruby_init, ruby_options): Init_stack() with local location. (ruby-bugs-ja:PR#277) * eval.c (rb_call0): disable trace call. [ruby-dev:18074] * eval.c (eval, rb_load): enable trace call. [ruby-dev:18074] * eval.c (rb_f_require): set source file name for extension libraries. [ruby-dev:18445] * gc.c (Init_stack): prefer address of argument rather than local variable to initialize rb_gc_stack_start. * ruby.c (translate_char): translate a character in a string; DOSISH only. [ruby-dev:18274] * ruby.c (ruby_init_loadpath): added argv[0] handling under Human68K. [ruby-dev:18274] * ruby.c (proc_options): translate directory separator in $0 to '/'. [ruby-dev:18274] Thu Oct 3 00:27:26 2002 Nobuyoshi Nakada * lib/delegate.rb (Delegator::initialize): use Object#class instead of deprecated Object#type. Wed Oct 2 23:32:48 2002 Nobuyoshi Nakada * configure.in (RUBY_CHECK_IO_NEED_FLUSH): check whether fflush() is needed. * io.c (flush_before_seek): flush before seek if buffered data may remain. * io.c (rb_io_check_readable): flush if the last operation was write. * io.c (rb_io_check_writable): flush if the last operation was read. * rubyio.h (FMODE_RBUF): added. Wed Oct 2 23:09:20 2002 Nobuyoshi Nakada * io.c (rb_io_wait_readable): handle retryable errors. * io.c (rb_io_wait_writable): ditto. * ext/socket/socket.c (bsock_send): ditto. * ext/socket/socket.c (s_recvfrom): ditto. * ext/socket/socket.c (s_accept): ditto. * ext/socket/socket.c (udp_send): ditto. * ext/socket/getaddrinfo.c (afdl): made private structures constant. * rubyio.h: prototype; rb_io_wait_readable(), rb_io_wait_writable(). Wed Oct 2 13:03:58 2002 WATANABE Hirofumi * configure.in: set ac_cv_func_setitimer to "no" on Cygwin. Wed Oct 2 10:59:29 2002 Yukihiro Matsumoto * gc.c (gc_sweep): free unused heap page to reduce process size if possible. * object.c (rb_obj_type): deprecated Object#type; use Object#class. Tue Oct 1 23:48:32 2002 Nobuyoshi Nakada * ext/socket/socket.c (init_sock): no need for special finalizer, socket descriptor is no longer duplicated in 1.7. [ruby-talk:50732] * win32/win32.c, win32/win32.h (rb_w32_fddup, rb_w32_fdclose): delete. Mon Sep 30 20:29:10 2002 Nobuyoshi Nakada * io.c (rb_io_inspect): not need to raise IOError for closed stream. [ruby-talk:51871] Mon Sep 30 03:48:15 2002 Yukihiro Matsumoto * range.c (range_check): need no Fixnum check. Sun Sep 29 18:30:24 2002 Nobuyoshi Nakada * win32/win32.c (rb_w32_open_osfhandle): adjust rb_w32_open_osfhandle() with _open_osfhandle(). * win32/win32.c (rb_w32_accept, rb_w32_socket): return -1 on error. * win32/win32.h: should use file descriptor instead of SOCKET. Sun Sep 29 06:33:03 2002 NAKAMURA Usaku * win32/win32.c (is_socket, rb_w32_select, rb_w32_accept, rb_w32_bind, rb_w32_connect, rb_w32_getpeername, rb_w32_getsockname, rb_w32_getsockopt, rb_w32_ioctlsocket, rb_w32_listen, rb_w32_recv, rb_w32_recvfrom, rb_w32_send, rb_w32_sendto, rb_w32_setsockopt, rb_w32_shutdown, rb_w32_socket, rb_w32_gethostbyaddr, rb_w32_gethostbyname, rb_w32_gethostname, rb_w32_getprotobyname, rb_w32_getprotobynumber, rb_w32_getservbyname, rb_w32_getservbyport): need to protect WSAGetLastError() by RUBY_CRITICAL. [ruby-talk:51778] Sat Sep 28 20:06:36 2002 Nobuyoshi Nakada * keywords: add braces around initializers. Sat Sep 28 13:19:29 2002 Nobuyoshi Nakada * hash.c (rb_hash_become): should check self-assignment after conversion. Sat Sep 28 10:40:44 2002 Yukihiro Matsumoto * hash.c (rb_hash_become): Hash#become should check added self-assignment. * class.c (rb_make_metaclass): metaclass of a superclass may be NULL at boot time. Sat Sep 28 09:50:03 2002 KONISHI Hiromasa * ext/extmk.rb: The condition judgment without necessity was deleted. Fri Sep 27 18:40:42 2002 Nobuyoshi Nakada * eval.c (rb_thread_deadlock): more verbose message at deadlock. * eval.c (rb_thread_schedule): ditto. * eval.c (rb_thread_join): ditto. Fri Sep 27 13:24:35 2002 Yukihiro Matsumoto * eval.c (rb_eval): Class#inherited should be called after the execution of the class body. Fri Sep 27 02:41:53 2002 Akinori MUSHA * ext/digest/sha1: Use OpenSSL's SHA1 engine if available. It is much faster than what we have now (sha1.[ch]). Add a knob (--with-bundled-sha1) to extconf.rb which makes it use the bundled one anyway. Fri Sep 27 02:25:14 2002 Akinori MUSHA * ext/digest/rmd160: Use OpenSSL's RMD160 engine if available. It is much faster than what we have now (rmd160.[ch]). Add a knob (--with-bundled-rmd160) to extconf.rb which makes it use the bundled one anyway. Fri Sep 27 01:23:39 2002 Akinori MUSHA * ext/digest/md5: Use OpenSSL's MD5 engine if available. It is much faster than what we have now (md5.[ch]). Add a knob (--with-bundled-md5) to extconf.rb which makes it use the bundled one anyway. Thu Sep 26 22:44:21 2002 Akinori MUSHA * ext/digest/digest.c (rb_digest_base_s_digest): Fix a double free() bug mingled with allocation framework deployment. * ext/digest/digest.c (rb_digest_base_s_hexdigest): Get rid of redundant struct allocation. Thu Sep 26 09:52:52 2002 Yukihiro Matsumoto * parse.y (primary): remove "return outside of method" check at compile time. Wed Sep 25 23:51:29 2002 Nobuyoshi Nakada * dir.c (glob_helper): must not closedir() when exception raised while globbing "**". * marshal.c (w_uclass): unused variable. * re.c (match_clone): unused. * regex.c (re_compile_pattern): get rid of implicit promotion from plain char to int. Wed Sep 25 17:46:46 2002 NAKAMURA Usaku * lib/mkmf.rb (libpathflag): restore ENV['LIB'] when some error occurred. Wed Sep 25 16:14:51 2002 Yukihiro Matsumoto * regex.c (re_match): p1 may exceed pend limit. Mon Sep 23 23:22:43 2002 Nobuyoshi Nakada * eval.c (rb_call0): must not clear ruby_current_node, or backtrace cannot be generated. * intern.h (ruby_yyparse): rather than yyparse(). * parse.y (yylex): nextc() returns -1 at end of input, not 0. * parse.y (newline_node): reduce duplicated newline node. * parse.y (literal_concat): get rid of warning. * parse.y (new_evstr): fixed junk code. Mon Sep 23 19:57:52 2002 WATANABE Hirofumi * configure.in (RUBY_MINGW32): new macro. check for the MinGW compiler environment. * lib/mkmf.rb: refactoring. Mon Sep 23 08:27:11 2002 Tanaka Akira * io.c (appendline): forget to terminate with nul. Mon Sep 23 02:46:29 2002 Yukihiro Matsumoto * eval.c (ruby_run): should set toplevel visibility again here. * eval.c (rb_eval): should not rely on ruby_class == rb_cObject check. Besides allow implicit publicity for attribute set methods. * parse.y (primary): need not to check class_nest, just set whether method is an attrset or not. Sun Sep 22 21:49:42 2002 Nobuyoshi Nakada * eval.c (call_trace_func): should not call trace function while compilation. * eval.c (rb_call0): also inside c-func. * parse.y (yycompile): ditto. * ruby.c (require_libraries): preserve source file/line for each require. Sun Sep 22 17:08:11 2002 Tanaka Akira * string.c (rb_str_each_line): p might be at the top of the string. Sat Sep 21 23:28:28 2002 Yukihiro Matsumoto * class.c (rb_make_metaclass): class of metaclass should be metaclass of superclass, unless class itself is a metaclass; class of metaclass of metaclass should point back to self. eh, confusing, isn't it. * class.c (rb_singleton_class): check if its class is singleton AND attached to self. Sat Sep 21 22:23:41 2002 Nobuyoshi Nakada * eval.c (rb_thread_raise): no need to save dead thread context. [ruby-dev:18322] Fri Sep 20 23:02:01 2002 Nobuyoshi Nakada * parse.y (block_append): eliminate unused literal nodes. * parse.y (literal_concat): refined literal concatenation. Fri Sep 20 19:43:40 2002 Akinori MUSHA * lib/set.rb: Merge rough/lib/set.rb rev.1.5-1.15. Wed Sep 18 12:41:16 2002 Yukihiro Matsumoto * eval.c (rb_eval): should define class/module under ruby_cbase. * eval.c (rb_eval): should set class/module path based on ruby_cbase, not ruby_class. * eval.c (module_setup): use ruby_cbase instead of ruby_class. Tue Sep 17 21:06:04 2002 Nobuyoshi Nakada * eval.c (rb_thread_die): put thread dead state. * eval.c (rb_thread_atfork): free stack buffer at fork too. Tue Sep 17 01:13:31 2002 Yukihiro Matsumoto * eval.c (rb_mod_nesting): load wrapping module should appear in Module#nesting list. (ruby-bugs-ja:PR#328) * eval.c (rb_thread_remove): free stack buffer on remove. Tue Sep 17 00:58:35 2002 Minero Aoki * io.c: add parameter prototype. * re.c: ditto. Sun Sep 15 21:14:22 2002 KONISHI Hiromasa * win32/win32.c (rb_w32_opendir, rb_w32_stat): Corresponds to the unjust path containing ". Sun Sep 15 19:48:55 2002 WATANABE Hirofumi * configure.in (OUTFLAG, CPPOUTFILE): moved from lib/mkmf.rb. check whether ${CPP} accepts the -o option. * win32/Makefile.sub (OUTFLAG, CPPOUTFILE): ditto. * bcc32/Makefile.sub (OUTFLAG, CPPOUTFILE): ditto. * djgpp/config.sed (OUTFLAG, CPPOUTFILE): ditto. * lib/mkmf.rb (OUTFLAG, CPPOUTFILE): use CONFIG. make easy to understand log. * mkconfig.rb (val): should not strip. Sat Sep 14 20:13:42 2002 KONISHI Hiromasa * error.c(rb_sys_fail): remove case EPIPE on bcc32 . Fri Sep 13 23:39:49 2002 Nobuyoshi Nakada * dir.c (glob_func_caller): add prototype to get rid of warning. Fri Sep 13 18:35:12 2002 Nobuyoshi Nakada * eval.c (rb_eval): avoid uninitialized global/class variable warnings at `||='. [ruby-dev:18278] * parse.y (stmt, arg): ditto Fri Sep 13 13:28:04 2002 WATANABE Hirofumi * lib/mkmf.rb ($INSTALLFILES): avoid warning when $VERBOSE mode. Thu Sep 12 23:20:10 2002 KONISHI Hiromasa * bcc32/setup.mak : Control of a message. * bcc32/makefile.sub : include resource. Thu Sep 12 18:10:03 2002 Nobuyoshi Nakada * dir.c (glob_helper): fixed freeing buffer. (ruby-bugs-ja:PR#332) * dir.c (glob_helper): should pass matched path. (ruby-bugs-ja:PR#333) Thu Sep 12 00:09:32 2002 Nobuyoshi Nakada * eval.c (rb_trap_eval): preserve thread status and so on. [ruby-talk:40337], [ruby-core:00019] Wed Sep 11 21:25:52 2002 Tanaka Akira * pp.rb (ARGF.pretty_print): implemented. (PP.pp): arguments reordered. Wed Sep 11 18:55:38 2002 Nobuyoshi Nakada * eval.c (proc_to_s): refined format. [ruby-dev:18215] Wed Sep 11 17:47:17 2002 NAKAMURA Usaku * win32/win32.c, win32/win32.h (rb_w32_getpid): negate pid under Win9x. [ruby-dev:18262] Wed Sep 11 12:58:57 2002 Akinori MUSHA * string.c (get_pat): Add an extra argument "quote". * string.c (rb_str_match_m): Do not bother to convert if a regexp is given. Wed Sep 11 11:33:40 2002 NAKAMURA Usaku * bcc32/Makefile.sub: remove unnecessary `.dll' from filename of dll's resource file. * cygwin/GNUmakefile.in: ditto. [ruby-dev:17103] * win32/Makefile.sub: ditto. [ruby-dev:17103] * win32/resource.rb: ditto. [ruby-dev:17103] Wed Sep 11 09:59:46 2002 Nobuyoshi Nakada * io.c (rb_io_wait_readable): added. * io.c (rb_io_wait_writable): added. * io.c (io_read_retryable): added. * io.c (io_write): retry on EINTR, ERESTART and EWOULDBLOCK. [ruby-dev:17855], [ruby-dev:17878], [ruby-core:00444] * io.c (rb_io_fread): ditto. * io.c (read_all): ditto. * io.c (appendline): ditto. * io.c (rb_io_each_byte): ditto. * io.c (rb_io_getc): ditto. Wed Sep 11 09:29:24 2002 NAKAMURA Usaku * win32/Makefile.sub (ext): make directory `ext' on compile dir. [ruby-dev:18255] Wed Sep 11 00:41:10 2002 Nobuyoshi Nakada * eval.c (rb_mod_define_method): initialize orig_func too. (ruby-bugs-ja:PR#330) Wed Sep 11 00:01:32 2002 Yukihiro Matsumoto * dir.c (glob_helper): prevent memory leak using rb_protect(). * string.c (rb_str_associate): no need to check freeze flag. * string.c (rb_str_resize): should honor STR_ASSOC flag on resize. * string.c (rb_str_resize): proper STR_ASSOC handling. pointed out by Michal Rokos. * string.c (rb_str_buf_cat): ditto. * string.c (rb_str_cat): ditto. * string.c (rb_str_buf_append): ditto. * string.c (rb_str_append): ditto. Tue Sep 10 23:35:46 2002 Nobuyoshi Nakada * parse.y (nextc): restore line number after here documents. (ruby-bugs-ja:PR#331) * parse.y (heredoc_restore): ditto. Tue Sep 10 18:26:52 2002 WATANABE Hirofumi * ext/extmk.rb, lib/mkmf.rb ($INCFLAGS): new var for -I$(topdir). * lib/mkmf.rb: add #define WIN32_LEAN_AND_MEAN to improve compile times. Tue Sep 10 17:16:14 2002 NAKAMURA Usaku * win32/Makefile.sub (miniruby): shouldn't link $(EXTOBJS). [ruby-dev:17059] * win32/Makefile.sub ($(LIBRUBY_A), $(LIBRUBY)): avoid lib.exe's warning. [ruby-dev:17059] * win32/Makefile.sub: remove unnecessary rules. [ruby-dev:17059] * win32/configure.bat, win32/setup.mak, win32/README.win32: enable to pass some arguments to configure. [ruby-dev:17059] Mon Sep 9 23:43:33 2002 WATANABE Hirofumi * win32/win32.h (S_I?USR): define only if not mingw32. Mon Sep 9 11:21:04 2002 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_set_string): reinitialize properly. * ext/stringio/stringio.c (strio_become): added self-assign check and experimental auto-conversion to StringIO. * ext/stringio/stringio.c (strio_reopen): added. Sun Sep 8 21:29:25 2002 WATANABE Hirofumi * time.c (time_free): prototype; struct time_object -> void *. avoid GCC warnings. * lib/mkmf.rb, ext/extmk.rb ($LINK, $CPP): move to lib/mkmf.rb. Sun Sep 8 19:02:28 2002 NAKAMURA Usaku * time.c: prototype; time_free() to avoid VC++ warnings. * ext/tcltklib/tcltklib.c: prototype; invoke_queue_handler() to avoid VC++ warning. * win32/win32.c (rb_w32_stat): remove S_IWGRP and S_IWOTH bits from st_mode. * win32/win32.h (S_I*): define if not defined. Sun Sep 8 14:38:31 2002 WATANABE Hirofumi * configure.in: modify program_prefix only if specified --program-prefix. * configure.in: don't generate ext/extmk.rb. * Makefile.in: execute directly $(srcdir)/ext/extmk.rb. remove -Cext option, "Dir::chdir 'ext'" in ext/extmk.rb. * {win32,bccwin32}/Makefile.sub: ditto. * instruby.rb: ditto. * ext/extmk.rb: renamed from ext/extmk.rb.in. * lib/mkmf.rb (module Logging): create log files (mkmf.log) in each extension module directories. * ext/extmk.rb: ditto. * lib/mkmf.rb (macro_defined?): new method. * ext/.cvsignore: remove extmk.rb. * ext/*/.cvsignore: add "*.def". * lib/mkmf.rb (have_struct_member): moved from ext/socket/extconf.rb. * ext/socket/extconf.rb: use macro_defined? instead of egrep_cpp. * ext/etc/extconf.rb: use have_struct_member. * ext/etc/etc.c: add prefix HAVE_ST_ to PW_ macros. Sun Sep 8 14:36:40 2002 KONISHI Hiromasa * bcc32/configure.bat : Control of a message. * bcc32/makefile.sub : @(sitearch) typo. * ext/extmk.rb.in : [bccwin32] libdir is added to a library path. * lib/mkmf.rb : ditto. Sat Sep 7 23:32:56 2002 Nobuyoshi Nakada * misc/inf-ruby.el (inferior-ruby-error-regexp-alist): regexp alist for error message from ruby. * misc/inf-ruby.el (inferior-ruby-mode): fixed for Emacs. * misc/inf-ruby.el (ruby-send-region): compilation-parse-errors doesn't parse first line, so insert separators before each evaluations. Sat Sep 7 19:46:57 2002 Akinori MUSHA * lib/set.rb: Disallow Set.new(false). Add even more tests. [Submitted by: "Christoph" ] Sat Sep 7 19:23:56 2002 Akinori MUSHA * lib/set.rb: Fix a bug in flatten()'s recursive set detection. [Submitted by: "Christoph" ] Some tests against the bug are added. * lib/set.rb: Resurrect the test suite by putting it after __END__ and executing `eval DATA.read'. Sat Sep 7 08:41:39 2002 Minero Aoki * parse.y (rb_gc_mark_parser): ruby_eval_tree is marked in eval.c. Fri Sep 6 20:01:38 2002 Nobuyoshi Nakada * lib/mkmf.rb ($CC): command to compile C source. * lib/mkmf.rb (logging): added. * lib/mkmf.rb (try_compile): added. * lib/mkmf.rb (egrep_cpp): use internal grep when pattern is Regexp, otherwise use external egrep command but get rid of pipe of command.com. * lib/mkmf.rb (have_func): local variable should be volatile not to be eliminated by optimization. * lib/mkmf.rb (create_makefile): link with CONFIG["LIBS"]. * lib/mkmf.rb (create_makefile): emit .SUFFIXES:. Fri Sep 6 12:11:22 2002 Minero Aoki * parse.y (rb_gc_mark_parser): should mark ALL global variables defined in parse.y. Fri Sep 6 01:15:23 2002 Yukihiro Matsumoto * gc.c (ruby_xmalloc): remove MALLOC_LIMIT to avoid frequent garbage collection. Fri Sep 6 11:47:37 2002 Minero Aoki * parse.y (rb_gc_mark_parser): should mark global variables defined in parse.y. Fri Sep 6 10:34:32 2002 Minero Aoki * io.c (rb_io_puts): RSTRING(line)->ptr might be NULL. Fri Sep 6 10:26:37 2002 Minero Aoki * parse.y: should not put non-NODE-VALUEs in the semantic stack. Fri Sep 6 05:48:26 2002 Nobuyoshi Nakada * file.c (rb_path_check): nothing to check under DOSISH. [ruby-list:35772] Fri Sep 6 05:03:50 2002 Minero Aoki * gc.c (rb_gc): should mark parser. * parse.y (rb_gc_mark_parser): new function. * intern.h (rb_gc_mark_parser): added. Thu Sep 5 18:32:32 2002 Yukihiro Matsumoto * variable.c (rb_path2class): should not use rb_eval_string(). Thu Sep 5 17:18:22 2002 Michal Rokos * dln.c: fix memory leak in dln_load (ruby-core:405) and in load_1 (ruby-core:407) Thu Sep 5 15:43:54 2002 Yukihiro Matsumoto * marshal.c (w_extended): should allow marshaling of object which is extended by named module. * class.c (rb_make_metaclass): super may be T_ICLASS, need to skip. Thu Sep 5 13:09:22 2002 Nobuyoshi Nakada * eval.c (rb_eval): overriding false constant with class/module definition should be error. (PR#327) Thu Sep 5 01:24:26 2002 WATANABE Hirofumi * extmk.rb (create_makefile): add macro MAKEDIRS, INSTALL_PROG, INSTALL_DATA. * extmk.rb (create_makefile): support for building to any directory. * extmk.rb (xsystem): move to mkmf.rb. * mkmf.rb (xsystem): support for extmk.rb * mkmf.rb ($CPP): remove '-E' option. add CPPFLAGS. Wed Sep 4 16:15:17 2002 Akinori MUSHA * lib/set.rb: ==(o) should be aware of all the Set variant instances, not just those of its subclasses. [Submitted by: "Christoph" ] * lib/set.rb: - Fix eql?(). [ditto] Wed Sep 4 15:23:23 2002 Yukihiro Matsumoto * class.c (rb_make_metaclass): obj.meta.super.meta should be equal to obj.meta.meta.super (ruby-bugs-ja:PR#324). Wed Sep 4 05:10:16 2002 Koji Arai * parse.y (yylex): the warning message "invalid character syntax" was never issued (ruby-bugs-ja:PR#323). Wed Sep 4 01:08:45 2002 Yukihiro Matsumoto * marshal.c (r_bytes): do not use alloca (ruby-bugs:PR#382). Tue Sep 3 17:12:59 2002 WATANABE Hirofumi * extmk.rb: require mkmf.rb. remove duplicate methods. use Config::CONFIG["FOO"] instead of @FOO@. * mkmf.rb: support for extmk.rb. Mon Sep 2 23:01:50 2002 Nobuyoshi Nakada * re.c (rb_reg_search): MatchData must be rb_cMatch. (ruby-bugs-ja:PR#319) Mon Sep 2 21:21:46 2002 Minero Aoki * gc.c (gc_sweep): does reclaim nodes in also compile time, if we can. * ruby.c (load_file): omit GC if we can. * parse.y (ruby_parser_stack_on_heap): new function. * intern.h (ruby_parser_stack_on_heap): added. Mon Sep 2 18:45:07 2002 Yukihiro Matsumoto * variable.c (rb_copy_generic_ivar): remove old generic instance variable table if it exists. Sun Sep 1 15:54:33 2002 WATANABE Hirofumi * config.guess: fixed for Linux/PPC. Sat Aug 31 09:38:12 2002 Yukihiro Matsumoto * class.c (rb_make_metaclass): metaclass of a metaclass is a metaclass itself. Fri Aug 30 22:45:16 2002 Akinori MUSHA * lib/set.rb: Added. Fri Aug 30 20:58:54 2002 KONISHI Hiromasa * ext/Win32API/Win32API.c (Win32API_Call): typo. Fri Aug 30 19:45:52 2002 Nobuyoshi Nakada * variable.c (rb_const_assign): st_delete() takes pointer to key. Fri Aug 30 19:40:28 2002 Nobuyoshi Nakada * ext/Win32API/Win32API.c (Win32API_Call): RSTRING()->ptr may be NULL. * ext/nkf/nkf.c (rb_nkf_guess): ditto. * ext/readline/readline.c (readline_s_set_completion_append_character): ditto. * ext/socket/socket.c (sock_s_getaddrinfo, sock_s_getnameinfo): ditto. * ext/tcltklib/tcltklib.c (ip_toUTF8, ip_fromUTF8): ditto. Fri Aug 30 01:32:17 2002 Yukihiro Matsumoto * class.c (rb_singleton_class): superclass of a metaclass should be a metaclass of superclass. * range.c (range_eq): two instances must belong to a same class to be equal. * range.c (range_eql): ditto. * io.c (rb_io_taint_check): frozen check added. * file.c (rb_stat_become): frozen check added. * object.c (rb_obj_become): ditto. * re.c (rb_reg_become): ditto. * struct.c (rb_struct_become): ditto. * time.c (time_become): ditto. * array.c (rb_ary_become): should call rb_ary_modify(). * hash.c (rb_hash_become): should call rb_hash_modify(). * compar.c (cmp_equal): should not use NUM2LONG(), since <=> may return bignum. * compar.c (cmp_gt, cmp_ge, cmp_lt, cmp_le, cmp_between): ditto. Thu Aug 29 23:34:42 2002 KONISHI Hiromasa * bcc32/MakeFile.sub (sitearch): add. Thu Aug 29 13:36:42 2002 WATANABE Hirofumi * io.c (read_all): should use off_t instead of long. Thu Aug 29 00:55:55 2002 Nobuyoshi Nakada * marshal.c (r_object): yield loaded objects, not intermediates. (ruby-bugs-ja:PR#296) Thu Aug 29 00:06:54 2002 Yukihiro Matsumoto * array.c (rb_ary_become): should not free ptr if it's shared. * eval.c (rb_alias): prohibit making an alias named "allocate" if klass is a metaclass. Wed Aug 28 23:59:15 2002 Michal Rokos * signal.c: remove #ifdef SIGINT for struct signals. * variable.c: get rid of fix length buffer in rb_class_path. Wed Aug 28 23:34:32 2002 Nobuyoshi Nakada * io.c (appendline): data was lost when raw mode. Wed Aug 28 22:57:34 2002 Yukihiro Matsumoto * string.c (rb_string_value_ptr): StringValuePtr() should never return NULL pointer. Wed Aug 28 19:12:46 2002 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_initialize): RSTRING(mode)->ptr can be NULL. * ext/stringio/stringio.c (strio_ungetc): fix buffer overflow. Wed Aug 28 18:19:55 2002 Michal Rokos * file.c: fix memory leak in rb_stat_init. Wed Aug 28 17:45:03 2002 Nobuyoshi Nakada * win32/win32.c (kill): negate pid under Win9x. Wed Aug 28 16:36:40 2002 WATANABE Hirofumi * configure.in (ar): don't check ar twice. Wed Aug 28 15:00:29 2002 Yukihiro Matsumoto * string.c (rb_str_delete_bang): should check if str->ptr is 0. * string.c (rb_str_squeeze_bang): ditto. * string.c (rb_str_count): ditto. * string.c (rb_str_lstrip_bang): ditto. * string.c (rb_str_rstrip_bang): ditto. * string.c (rb_str_intern): ditto. Wed Aug 28 11:37:35 2002 NAKAMURA Usaku * win32/win32.h: define SIGINT and SIGKILL if not defined. * win32/win32.c: remove definition of SIGINT and SIGKILL. Tue Aug 27 19:50:27 2002 Nobuyoshi Nakada * ruby.c (require_libraries): prevent ruby_sourcefile from GC. Tue Aug 27 15:03:35 2002 Yukihiro Matsumoto * file.c (rb_find_file): $LOAD_PATH must not be empty. * file.c (rb_find_file_ext): ditto. Tue Aug 27 02:35:21 2002 Yukihiro Matsumoto * range.c (range_eq): class check should be based on range.class, instead of Range to work with Range.dup. * range.c (range_eql): ditto. Mon Aug 26 18:17:56 2002 Yukihiro Matsumoto * class.c (rb_mod_dup): need to preserve metaclass and flags. Mon Aug 26 10:44:18 2002 Tanaka Akira * object.c (rb_cstr_to_dbl): had a buffer overrun. Sun Aug 25 20:10:32 2002 Wakou Aoyama * lib/cgi.rb (CGI#form): fix ruby-bugs-ja:PR#280, add default action. Sat Aug 24 15:32:16 2002 Nobuyoshi Nakada * eval.c (call_trace_func): restore source file/line, as trace function installed in required library with -r option can be called while parsing. (ruby-bugs:PR#372) * eval.c (module_setup): unused variable. [ruby-core:00358] Sat Aug 24 14:59:02 2002 Yukihiro Matsumoto * marshal.c (w_class): integrate singleton check into a function to follow DRY principle. * marshal.c (w_uclass): should check singleton method. * object.c (rb_obj_dup): dmark and dfree functions must be match for T_DATA type. * object.c (rb_obj_dup): class of the duped object must be match to the class of the original. Sat Aug 24 13:57:28 2002 Tanaka Akira * lib/time.rb (Time.rfc2822, Time#rfc2822): preserve localtimeness. * lib/pp.rb: pretty_print_cycled is renamed to pretty_print_cycle. Fri Aug 23 23:59:57 2002 Nobuyoshi Nakada * eval.c (method_call): check receiver is defined. * eval.c (umethod_call): removed. Fri Aug 23 23:39:17 2002 Yukihiro Matsumoto * re.c (rb_reg_quote): do not escape \t, \f, \r, \n, for they are not regular expression metacharacters. * time.c (time_s_alloc): use time_free instead of free (null check, also serves for type mark). * time.c (time_s_at): check dfree function too. Fri Aug 23 17:06:48 2002 WATANABE Hirofumi * configure.in: RUBY_SO_NAME is msvcrt-rubyXX on mswin32/mingw32. * configure.in (sitearch): new var. * mkconfig.rb, lib/mkmf.rb (sitearch): ditto. * win32/Makefile.sub, win32/setup.mak (sitearch): ditto. * instruby.rb: ditto. Wed Aug 21 16:53:00 2002 Michal Rokos * *.c: int, long types cleanup. * parse.y: ditto. * re.h, regex.h, ruby.h: ditto. Wed Aug 21 16:43:19 2002 Yukihiro Matsumoto * eval.c (rb_thread_cleanup): should not modify the global variable curr_thread. Wed Aug 21 16:14:26 2002 WATANABE Hirofumi * configure.in: set ac_cv_func__setjmp to "no" on Cygwin. * configure.in: set ac_cv_func_crypt to "no" on MinGW. Tue Aug 20 21:47 2002 KONISHI Hiromasa * io.c (rb_io_fread): remove case EPIPE on bcc32 . * win32/win32.c (rb_w32_getc): clear EPIPE error on bcc32. Tue Aug 20 19:39:03 2002 WATANABE Hirofumi * file.c (rb_file_s_expand_path): accept drive letter on Cygwin. * file.c (is_absolute_path): ditto. Tue Aug 20 12:12:25 2002 Tietew * io.c (rb_io_putc): output via rb_io_write(). Mon Aug 19 19:01:55 2002 Nobuyoshi Nakada * misc/inf-ruby.el (inf-ruby-keys): ruby-send-definition conflicted with ruby-insert-end. * misc/inf-ruby.el (inferior-ruby-mode): compilation-minor-mode. * misc/inf-ruby.el (ruby-send-region): send as here document to adjust source file/line. [ruby-talk:47113], [ruby-dev:17965] * misc/inf-ruby.el (ruby-send-terminator): added to make unique terminator. Mon Aug 19 17:08:19 2002 Yukihiro Matsumoto * re.c (rb_reg_initialize_m): frozen check should be moved here from rb_reg_initialize(). Mon Aug 19 15:38:44 2002 Yukihiro Matsumoto * array.c (sort_2): comparison should be done as signed long. * array.c (sort_2): should return int, not VALUE. Mon Aug 19 12:38:33 2002 Nobuyoshi Nakada * eval.c (rb_thread_save_context, rb_thread_restore_context): save/restore SEH chain on MS-Windows at thread switch. [ruby-win32:273] * eval.c (win32_get_exception_list, win32_set_exception_list): added. Sat Aug 17 23:01:25 2002 Yukihiro Matsumoto * array.c (sort_2): *a - *b may overflow. Sat Aug 17 00:25:08 2002 Yukihiro Matsumoto * array.c (ary_new): len*sizeof(VALUE) may be a positive value. * array.c (rb_ary_initialize): ditto. Fri Aug 16 15:58:16 2002 WATANABE Hirofumi * io.c (NOFILE): define NOFILE as 64 if not defined. * signal.c (sighandler_t): rename to sh_t on dietlibc. Fri Aug 16 15:37:04 2002 Nobuyoshi Nakada * bignum.c (rb_cstr_to_inum): new decimal and octal string. Fri Aug 16 13:17:11 2002 Yukihiro Matsumoto * object.c (rb_class_allocate_instance): move singleton class check from rb_obj_alloc(). Fri Aug 16 11:47:24 2002 Nobuyoshi Nakada * io.c (rb_io_fread): renamed from io_fread and made extern. * marshal.c (r_bytes0): check if successfully read, use rb_io_fread() instead of fread() to be preemptive. (ruby-bugs-ja:PR#294, 295) * rubyio.h (rb_io_fread): added. Fri Aug 16 07:57:26 2002 Nobuyoshi Nakada * eval.c (compile_error): must not clear ruby_sourcefile here. (ruby-bugs:PR#364). * eval.c (rb_longjmp): set ruby_sourcefile before making backtrace. Thu Aug 15 20:38:58 2002 Nobuyoshi Nakada * eval.c (ruby_current_node) : added to set sourceline on demand. * eval.c (error_pos, error_print, rb_longjmp, assign): set source file/line. * eval.c (rb_eval): store current node instead of file/line, and preserve it at return. * eval.c (module_setup): ditto. * eval.c (struct thread): store node instead of file/line. * eval.c (rb_thread_raise): ditto. * intern.h (ruby_current_node): added. * intern.h (ruby_set_current_source): added. * parse.y (stmt, arg): not fix position of assignment. * parse.y (node_assign): ditto. * parse.y (yycompile): clear current node. Thu Aug 15 00:48:46 2002 Yukihiro Matsumoto * re.c (rb_reg_initialize): should not modify frozen Regexp. Tue Aug 13 18:33:18 2002 Yukihiro Matsumoto * ext/tcltklib/tcltklib.c (ip_init): allocation framework. Tue Aug 13 15:32:14 2002 Yukihiro Matsumoto * hash.c (rb_hash_replace): should copy ifnone. * hash.c (rb_hash_dup): should preserve HASH_PROC_DEFAULT and HASH_DELETED flags. * hash.c (rb_hash_shift): shift from empty hash should not return its default proc. * hash.c (rb_hash_default_proc): new method. [new] Tue Aug 13 00:37:11 2002 Yukihiro Matsumoto * array.c (rb_ary_aref): no need for Bignum check. * array.c (rb_ary_aset): explicit Bignum check removed. * numeric.c (fix_aref): normalize bignum before bit-op. * bignum.c (rb_big_rand): max may be Bignum zero. * bignum.c (rb_cstr_to_inum): should normalize bignums, to avoid returning fixable bignum value. * bignum.c (rb_uint2big): there should be no zero sized bignum. Mon Aug 12 23:45:28 2002 Yukihiro Matsumoto * ext/extmk.rb.in: extmake() that works properly for both tkutil (tk/tkutil.so) and digest/sha1. Mon Aug 12 22:29:35 2002 Akinori MUSHA * ruby.c (set_arg0): Correct the position of #endif. Mon Aug 12 17:25:06 2002 Yukihiro Matsumoto * hash.c (rb_hash_equal): should check HASH_PROC_DEFAULT too. Mon Aug 12 16:15:37 2002 Nobuyoshi Nakada * bignum.c (rb_big_cmp): raise for NaN. (ruby-bugs-ja:PR#284). Sun Aug 11 09:34:07 2002 Nobuyoshi Nakada * eval.c (rb_eval): set line number from all nodes. * eval.c (proc_to_s): show source file/line if available. * marshal.c (r_object): register TYPE_BIGNUM regardless real type. Sat Aug 10 23:47:16 2002 Yukihiro Matsumoto * bignum.c (rb_big_cmp): use dbl2big() for Floats, instead of big2dbl(). * bignum.c (Init_Bignum): rb_big_zero_p() removed. There may be Bignum zero. Fri Aug 9 13:31:40 2002 WATANABE Hirofumi * ext/Win32API/extconf.rb: check existence of . Thu Aug 8 09:37:02 2002 Nobuyoshi Nakada * lib/optparse.rb (NilClass): must provide conversion block. * lib/optparse.rb (String): ditto. Thu Aug 8 00:45:15 2002 Yukihiro Matsumoto * eval.c (rb_call0): new argument added for original method name. preserve original method name in frame->orig_func. * eval.c (is_defined): use frame->orig_func, not last_func. * eval.c (rb_eval): ditto. * eval.c (method_call): supply data->oid also to rb_call0(). * object.c (rb_class_allocate_instance): call rb_obj_alloc() when called from alias, thus invoke original "allocate". * eval.c (remove_method): removing allocate from classes should cause NameError. Wed Aug 7 22:12:54 2002 Nobuyoshi Nakada * lib/optparse.rb (OptionParser::Completion::convert): returned all values not first one. * lib/optparse.rb (OptionParser::Switch::parse): return values as is. * lib/optparse.rb (OptionParser::order): ditto. * lib/optparse/time.rb: prior time.rb. * lib/optparse/uri.rb: require standard uri module. thanks to Minero Aoki. Wed Aug 7 09:51:54 2002 Yukihiro Matsumoto * hash.c (rb_hash_equal): should check default values. Wed Aug 7 08:44:32 2002 Minero Aoki * ext/racc/cparse/cparse.c: reduce goto. Tue Aug 6 15:19:39 2002 NAKAMURA Usaku * string.c (rb_str_rindex): must return -1 if unmatched. Mon Aug 5 22:41:18 2002 Minero Aoki * MANIFEST: add lib/racc/parser.rb. * ext/racc/cparse/cparse.c: code refine. * ext/racc/cparse/MANIFEST: add depend. Sun Aug 4 22:30:50 2002 Nobuyoshi Nakada * ext/curses/curses.c: follow allocation framework. Sat Aug 3 21:23:56 2002 Nobuyoshi Nakada * eval.c (rb_eval): set constant in cbase scope. * eval.c (assign): ditto. Fri Aug 2 09:12:32 2002 Minero Aoki * ext/strscan/strscan.c: follow allocation framework. Fri Aug 2 01:21:52 2002 Yukihiro Matsumoto * ext/socket/socket.c (s_recvfrom): update RSTRING len. Thu Aug 1 17:47:15 2002 Tachino Nobuhiro * parse.y (tokadd_string): ignore backslashed spaces in %w. Thu Aug 1 14:14:15 2002 Yukihiro Matsumoto * enum.c (enum_find): do not use rb_eval_cmd(); should not accept a string for if_none. Wed Jul 31 14:11:43 2002 Yukihiro Matsumoto * eval.c (rb_undef): undef should be done for klass, not ruby_class. Tue Jul 30 19:48:51 2002 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-accurate-end-of-block): restrict search region. * misc/ruby-mode.el (ruby-parse-partial): reversed wrong patch. Tue Jul 30 17:21:13 2002 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-accurate-end-of-block): incomplete block caused infinite loop. * misc/ruby-mode.el (ruby-parse-partial): returns nil unless delimiters found. Tue Jul 30 15:24:07 2002 WATANABE Hirofumi * ext/tcltklib/stubs.c (ruby_tcltk_stubs): win32_getenv returns the same address always, so allocate string by ruby_strdup. * win32/win32.c: prototype; rb_w32_open_osfhandle(). Tue Jul 30 09:11:07 2002 Minero Aoki * eval.c (rb_thread_join_m): add parameter type declaration. Tue Jul 30 08:37:11 2002 Minero Aoki * eval.c (localjump_error): add parameter type declaration. Mon Jul 29 16:00:54 2002 WATANABE Hirofumi * ext/extmk.rb.in: always use File.expand_path for $top_srcdir. Sat Jul 27 23:07:52 2002 Yukihiro Matsumoto * numeric.c (num_to_int): default to_int implementation for every numeric class. Sat Jul 27 08:09:03 2002 Booker C. Bense * re.c (rb_reg_quote): initial part of the string was never copied to the quoted string. Fri Jul 26 23:03:53 2002 Nobuyoshi Nakada * eval.c (rb_eval): no need to convert to string twice. Fri Jul 26 18:32:37 2002 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-expr-beg): wrong indent at modifiers after ?. Fri Jul 26 16:01:16 2002 WATANABE Hirofumi * ext/extmk.rb.in (create_makefile): use Regexp in gsub. * sample/mkproto.rb: ditto and fix bug. Fri Jul 26 14:31:06 2002 Yukihiro Matsumoto * random.c: replace with Mersenne Twister RNG. Fri Jul 26 12:14:48 2002 Minero Aoki * parse.y (yylex): modify to accept a code like "m (a){...}". Thu Jul 25 09:05:02 2002 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-delimiter): include here document. * misc/ruby-mode.el (ruby-deep-arglist): skips spaces after parenthesis when 'space. * misc/ruby-mode.el (ruby-imenu-create-index): fix for nested classes. * misc/ruby-mode.el (ruby-accurate-end-of-block): added. scan a block in the order. * misc/ruby-mode.el (ruby-expr-beg): support for here document. * misc/ruby-mode.el (ruby-parse-partial): splitted from ruby-parse-region. * misc/ruby-mode.el (ruby-move-to-block): skips RD style comments. Wed Jul 24 09:47:42 2002 Yukihiro Matsumoto * eval.c (jump_tag_but_local_jump): preserve retval in LocalJumpError exceptions. * parse.y (command): no more check for "super outside of method". * eval.c (rb_mod_define_method): should set last_class and last_func in the block->frame. Mon Jul 22 17:23:00 2002 Yukihiro Matsumoto * eval.c (error_handle): should handle TAG_THROW as well. Fri Jul 19 10:52:32 2002 Yukihiro Matsumoto * parse.y (yylex): new decimal notation '0d4567'. Thu Jul 18 11:52:02 2002 Shugo Maeda * lib/net/ftp.rb (set_socket): new method. Thu Jul 18 06:51:24 2002 Minero Aoki * parse.y (yylex): fix typo. Wed Jul 17 18:41:28 2002 Yukihiro Matsumoto * parse.y (yylex): new octal notation '0o777'. Mon Jul 15 18:36:42 2002 Yukihiro Matsumoto * parse.y (string_content): every string_content node should return string only. use NODE_EVSTR to coercing. * eval.c (rb_eval): NODE_EVSTR support. Mon Jul 15 10:35:35 2002 Minero Aoki * parse.y (heredoc_identifier): fix typo. Sat Jul 13 09:30:04 2002 Nobuyoshi Nakada * parse.y (literal_concat_string): wrong optimization. Sat Jul 13 01:25:38 2002 Nobuyoshi Nakada * lib/resolv.rb (Resolv::DNS::open, close): new. * lib/optparse.rb, lib/optparse: import. Fri Jul 12 06:34:05 2002 Minero Aoki * lib/net/http.rb: rename HTTP.get_uri get_response. * lib/net/http.rb: HTTP.get_print accepts URI objects. * lib/net/http.rb: HTTP.get had not work with URI objects. Fri Jul 12 02:15:58 2002 Nobuyoshi Nakada * string.c (rb_str_match): fix for string match. Fri Jul 12 00:02:50 2002 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_gets_internal): fixed for record separator longer than 1. Thu Jul 11 17:59:20 2002 Yukihiro Matsumoto * re.c (rb_reg_quote): avoid unnecessary string allocation. * string.c (get_pat): quote metacharacters before compiling a string into a regex. * string.c (rb_str_split_m): special treatment of strings of size 1, but AWK emulation. now uses get_pat(). * string.c (rb_str_match_m): quote metacharacters. * string.c (rb_str_match2): ditto. Thu Jul 11 12:59:23 2002 Shugo Maeda * lib/resolv.rb: untaint strings read from /etc/hosts and /etc/resolv.conf to prevent SecurityError when $SAFE==1. Thu Jul 11 09:00:43 2002 Yukihiro Matsumoto * string.c (rb_str_slice_bang): if there's no corresponding substring, slice! should return nil without exception. Tue Jul 9 20:03:55 2002 Keiju Ishitsuka * irb 0.9 Sat Jul 6 07:35:02 2002 Jamie Herre * array.c (rb_ary_insert): type fixed. Fri Jul 5 09:17:00 2002 Yukihiro Matsumoto * string.c (rb_str_split_m): accept separator value nil as well. Fri Jul 5 08:59:15 2002 Michal Rokos * enum.c: Fix bug in enum_sort_by and some code indents Fri Jul 5 05:00:40 2002 Wakou Aoyama * lib/cgi.rb (CGI#initialize): improvement for mod_ruby. thanks to Sean Chittenden , Shugo Maeda Fri Jul 5 00:10:09 2002 Yukihiro Matsumoto * string.c (rb_str_become): was leaking memory. Thu Jul 4 23:43:26 2002 Minero Aoki * parse.y: remove useless function str_extend_p(). Wed Jul 3 14:26:40 2002 Sean Chittenden * lib/net/ftp.rb (get): new method. * lib/net/ftp.rb (putt): ditto. * lib/net/ftp.rb (binary): ditto. * lib/net/ftp.rb (binary=): ditto. Wed Jul 3 13:57:53 2002 Sean Chittenden * lib/net/ftp.rb (getbinaryfile): the second argument (localfile) is now optional. * lib/net/ftp.rb (gettextfile): ditto. Wed Jul 3 13:45:42 2002 Shugo Maeda * lib/net/ftp.rb: use &block and yield for speed. Wed Jul 3 02:32:31 2002 Wakou Aoyama * lib/cgi.rb (CGI#initialize): improvement for mod_ruby. Tue Jul 2 14:53:10 2002 Yukihiro Matsumoto * class.c (rb_include_module): should not alter other classes/modules by inclusion. by this fix, local order may not be preserved for some cases. * class.c (include_class_new): module may be T_ICLASS; retrieve original module information. Tue Jul 2 14:13:11 2002 Wakou Aoyama * lib/cgi.rb (CGI#header): accept any type as value. Sun Jun 30 17:05:29 2002 WATANABE Hirofumi * configure.in (seekdir, telldir): add ac_cv_func_telldir=yes, ac_cv_func_seekdir=yes for MinGW. Sat Jun 29 01:43:32 2002 NAKAMURA Usaku * io.c (pipe_finalize, pipe_popen): two-way pipe support for win32. * win32/win32.c (ChildRecord, FindFreeChildSlot): ditto. * win32/win32.c, win32/win32.h (pipe_exec): new function for two-way pipe support for win32. * win32/win32.c, win32/win32.h (FindPipedChildSlot, rb_w32_popen, rb_w32_pclose): removed functions for two-way pipe support for win32. Fri Jun 28 23:49:34 2002 NAKAMURA Usaku * pack.c (pack_unpack): change names of local variables because their names are overlapped. Fri Jun 28 17:54:07 2002 Tanaka Akira * lib/pp.rb: fix object address. Thu Jun 27 23:55:50 2002 NAKAMURA Usaku * win32/win32.c (rb_w32_stat): fix buffer overflow. (ruby-bugs:PR#329) Thu Jun 27 20:57:45 2002 Tanaka Akira * lib/prettyprint.rb, lib/pp.rb: convenience methods added. Thu Jun 27 15:22:18 2002 Tanaka Akira * lib/prettyprint.rb: re-implemented for incremental output to handle huge data. API is changed a bit. * lib/pp.rb: adapt new pretty printing API. Thu Jun 27 08:28:18 2002 Nobuyoshi Nakada * parse.y (literal_concat_string): non-string last expression in #{} was ignored when followed by literal. Thu Jun 27 03:42:04 2002 Yukihiro Matsumoto * re.c (rb_reg_expr_str): need to process backslashes properly. Wed Jun 26 17:33:38 2002 Yukihiro Matsumoto * object.c (rb_any_to_a): declare Object#to_a to be obsolete. * object.c (rb_Array): do not convert nil into [] automagically. Wed Jun 26 15:40:00 2002 Nobuyoshi Nakada * parse.y (words, qwords): word list literal rules. * parse.y (parse_string): ditto. * parse.y (yylex): %W: word list literal with interpolation. [new] Tue Jun 25 18:53:34 2002 Nobuyoshi Nakada * parse.y (string1, xstring, regexp): moved lex_strnest initialization to string_contents/xstring_contents. Tue Jun 25 19:24:38 2002 KONISHI Hiromasa * dln.c: remove definition rb_loaderror(). Tue Jun 25 00:34:54 2002 Yukihiro Matsumoto * object.c (rb_Integer): use "to_int" instead of "to_i". [experimental] * object.c (nil_to_f): new method. * object.c (rb_Integer): Symbols and nil should cause error. * object.c (rb_Float): nil should cause error. Tue Jun 25 00:21:00 2002 KONISHI Hiromasa * dln.c: remark definition rb_loaderror(). Tue Jun 25 00:14:07 2002 Nobuyoshi Nakada * parse.y (string_dvar): allow back references in interpolation. Mon Jun 24 16:32:31 2002 Nobuyoshi Nakada * eval.c (rb_eval): NODE_EVSTR is no longer used. * eval.c (eval): not enforce to make assigned variables dynamic. * parse.y (string): split rules to strings/xstring/regexp to allow arbitrary statements inside string interpolation. * parse.y (here_document): splitted into three phases. * parse.y (literall_append, literal_concat): added. append/concatenate string literals. * sample/test.rb (valid_syntax): adjust line number for BEGIN. * lib/mkmf.rb (create_makefile): get rid of nested string. * lib/mkmf.rb (install_rb): site-install didn't work properly. Sun Jun 23 00:19:10 2002 Tadayoshi Funaba * lib/date.rb, lib/date/format.rb, sample/cal.rb, sample/goodfriday.rb: updated to the new version (based on date2 3.3). Sat Jun 22 14:41:33 2002 Guy Decoux * ext/socket/socket.c (sock_addrinfo): make all 3 versions of getaddrinfo happy. [ruby-core:00184] Fri Jun 21 18:49:58 2002 Yukihiro Matsumoto * parse.y (yylex): __END__ should not be effective within string literals. Thu Jun 20 21:09:37 2002 Nobuyoshi Nakada * ext/readline/readline.c (readline_readline): get rid of libreadline's bug. (ruby-bugs-ja:PR#268) Thu Jun 20 17:10:27 2002 WATANABE Hirofumi * lib/ftool.rb (BUFSIZE): tuning, set buffer length to 8192. * configure.in (__NO_ISOCEXT): add for mingw-runtime 2.0-2. * configure.in (__MSVCRT__): removed because it is defined in the GCC specs. Wed Jun 19 14:46:18 2002 WATANABE Hirofumi * ext/extmk.rb, lib/mkmf.rb (xsystem): open the log file if xsystem is called. Wed Jun 19 01:01:13 2002 Yukihiro Matsumoto * parse.y (here_document): should be aware of __END__ within here documents. Wed Jun 19 00:50:50 2002 Nobuyoshi Nakada * parse.y (yylex): ? followed by successive word characters is ternary operator not numeric literal. * parse.y (yylex): commands after break/next/rescue can take arguments. (ruby-bugs-ja:PR#265) Tue Jun 18 19:20:16 2002 NAKAMURA Usaku * win32/mkexports.rb: remove unnecessary exports. (ruby-dev:17418) Tue Jun 18 12:50:17 2002 Nobuyoshi Nakada * parse.y (yylex): should pushback proper char after '<<'. * parse.y (range_op, cond0, cond): get rid of doubled warnings. * parse.y (value_expr): reduce recursion level. * parse.y (logop): ditto. Mon Jun 17 11:11:34 2002 Kazuhiro NISHIYAMA * string.c (rb_str_crypt): result need not be tainted always. Mon Jun 17 10:51:37 2002 Nobuyoshi Nakada * dln.c (dln_load): need to preserve dln_strerror() result, calling other dl family can clear it. Sat Jun 15 22:56:37 2002 Yukihiro Matsumoto * parse.y (yylex): obsolete '?'; use '?\s', '?\n', etc, instead. Sat Jun 15 18:51:13 2002 Akinori MUSHA * dir.c (glob_helper): Use lstat() instead of stat() so it catches a dead symlink. Given a dead symlink named "a", Dir.glob("?") did catch it but Dir.glob("a") somehow didn't. Sat Jun 15 01:59:05 2002 Yukihiro Matsumoto * parse.y (yylex): no here document after a dot. * parse.y (yylex): should have set lex_state after '`'. * parse.y (yylex): should have set lex_state properly after tOP_ASGN. Fri Jun 14 21:01:48 2002 KONISHI Hiromasa * bcc32/mkexports.rb: insert sleep(1) for win9x. * bcc32/configure.bat: change return code LF -> CRLF for win9x. * win32/win32.c: fix rb_w32_open_osfhandle() Fri Jun 14 15:22:19 2002 Nobuyoshi Nakada * parse.y (read_escape): deny zero-width hexadecimal character. (ruby-bugs-ja:PR#260) * parse.y (tokadd_escape): ditto. * regex.c (re_compile_pattern): ditto. Fri Jun 14 00:49:54 2002 Yukihiro Matsumoto * bignum.c (rb_big2dbl): return canonical HUGE_VAL for infinity. Thu Jun 13 09:43:37 2002 Yukihiro Matsumoto * eval.c (svalue_to_avalue): v may be Qundef. This fix was suggested by Guy Decoux. Thu Jun 13 00:33:49 2002 takuma ozawa * hash.c (rb_hash_s_create): use rb_hash_aset() instead of calling st_insert() directly, to dup&freeze string keys. Thu Jun 13 00:12:54 2002 Yukihiro Matsumoto * parse.y (yylex): proper error message for "@@0". * parse.y (yylex): paren to parse_string() must be zero for unparenthesized strings. * parse.y (str_extend): broken string when unterminated "#{". * enum.c (enum_sort_by): had a bug in 1 element enumeration. Wed Jun 12 18:04:44 2002 akira yamada * uri/common.rb (REGEXP::PATTERN::X_ABS_URI): 'file:/foo' is valid. * uri/generic.rb (Generic#xxx=): should return substituted value. (ruby-dev:16728.) * test/generic.rb (test_set_component): added tests for the above change. Wed Jun 12 02:38:00 2002 Nobuyoshi Nakada * parse.y (stmt): fix typo. Wed Jun 12 01:10:55 2002 Yukihiro Matsumoto * parse.y (yylex): 'do' should return kDO_BLOCK on EXPR_ENDARG. * parse.y (singleton): "def (()).a end" dumped core. * parse.y (range_op): node may be null. * parse.y (match_gen): ditto. Tue Jun 11 19:20:34 2002 WATANABE Hirofumi * configure.in (LIBRUBY): rename to lib$(LIBRUBY_SO).a on Cygwin/MinGW. * configure.in, cygwin/GNUmakefile: use dllwrap when --disable-shared is specified. Tue Jun 11 17:12:04 2002 Yukihiro Matsumoto * parse.y (arg): void value check for "..", "...", "!", and "not". * parse.y (match_gen): void value check for "=~". * parse.y (value_expr): check NODE_AND and NODE_OR recursively. * parse.y (cond0): void value check added for conditionals. Tue Jun 11 13:18:47 2002 Shugo Maeda * lib/net/ftp.rb (noop): new method. * lib/net/ftp.rb (site): ditto. Tue Jun 11 13:15:41 2002 NAKAMURA Usaku * bcc32/Makefile.sub: set PROCESSOR_LEVEL to 6 if it's too big value. * win32/Makefile.sub: ditto. Tue Jun 11 12:37:46 2002 KONISHI Hiromasa * bcc32/configure.bat fix. Tue Jun 11 10:18:23 2002 KONISHI Hiromasa * new platform [bccwin32] merged. - create new folder bcc32 - modify any files for bccwin32 error.c, file.c, hash.c, io.c, instruby.rb, ext/extmk.rb.in, lib/mkmf.rb, lib/ftools.rb, ext/digest/defs.h, ext/dl/depend, ext/dl/dl.c, ext/dl/sym.c, ext/dl/extconf.rb, ext/socket/extconf.rb, ext/pty/extconf.rb, ext/tcltklib/extconf.rb ext/Win32API/Win32API.c, win32/dir.h, win32/win32.c, win32/win32.h, win32/resource.rb Mon Jun 10 19:02:19 2002 Nobuyoshi Nakada * numeric.c (fix_lshift): negative shift count means right shift. (ruby-bugs-ja:PR#248) * numeric.c (fix_rshift): return -1 when left side operand is negative. (ruby-bugs-ja:PR#247) * parse.y (yylex): `0_' should be an error. (ruby-bugs-ja:PR#249) Mon Jun 10 01:53:54 2002 Yukihiro Matsumoto * eval.c (rb_eval): ruby_frame->last_func may be null, if it's called outside of a method. * parse.y (arg): use INT2NUM, not INT2FIX for tUMINUS. * parse.y (arg): unnecessary negative tPOW treatment. * parse.y (tokadd_escape): wrong backslash escapement. Sun Jun 9 17:40:41 2002 Takaaki Tateishi * ext/dl: change the callback mechanism. Sat Jun 8 00:48:38 2002 Yukihiro Matsumoto * parse.y (stmt,arg): too much void value check. * parse.y (stmt,arg): need to check void value on rules which does not use node_assign(). Thu Jun 6 19:50:39 2002 KONISHI Hiromasa * sample/biorhythm.rb (getPosiiton,etc) fix at changing Date module ( Date is changed Fixnum to Rational ) Thu Jun 6 17:42:39 2002 Yukihiro Matsumoto * ext/socket/socket.c (ipaddr): need not to taint hostnames. Thu Jun 6 12:04:30 2002 NAKAMURA Usaku * win32/Makefile.sub (config.status): use sub! instead of []= because []= causes exception. Thu Jun 6 11:42:15 2002 Nobuyoshi Nakada * lib/thread.rb (Queue::pop): get rid of race condition. Wed Jun 5 01:56:47 2002 Hidetoshi NAGAI * ext/tcltklib/tcltklib.c: Stop the running zombi-eventloop when mainloop_watchdog is killed. Tue Jun 4 23:09:24 2002 Yukihiro Matsumoto * range.c (range_include): should be based on "<=>", whereas member? still is based on "each". * range.c (range_min,range_max): redefine methods based on "<=>". Tue Jun 4 18:28:37 2002 WATANABE Hirofumi * ext/socket/extconf.rb: The IPv6 stack of Cygwin is still incomplete. * ext/Win32API/extconf.rb: refactoring. Tue Jun 4 07:03:33 2002 Hidetoshi NAGAI * ext/tk/lib/tkfont.rb: Fix bugs on TkFont.init_widget_font for Tk8.x. * ext/tk/lib/tkafter.rb: Add self to 1st argument of interval- and loop-proc TkAfter#current_interval returns an interval (sleep) time value TkAfter#current_args returns an array of arguments TkAfter#return_value returns a return value of last loop-proc * ext/tk/lib/tk*.rb: Allow to use Symbols for parameters. * ext/tk/lib/tkcanvas.rb: (TkcItem) Add 'coords' parameter to the canvas item constructor (for new notation of constructor). * ext/tcltklib/tcltklib.c: New 'mainloop' and 'mainloop_watchdog'. * ext/tk/lib/tk.rb: (Tk.restart) Add 'app-name' paramater and 'use' parameter. * ext/tk/lib/tk.rb: Add new parameter 'widgetname' to the widget constructor to support effective use of Resource Database. * ext/tk/lib/tk.rb: TkOption::get always returns a tainted string. Tue Jun 4 00:45:50 2002 Nobuyoshi Nakada * ext/socket/addrinfo.h: typo. * ext/socket/getaddrinfo.c (gai_strerror): make literals const. * ext/socket/socket.c (init_inetsock): ensures resources are freed at exceptions. * ext/socket/socket.c (init_unixsock): ditto. * ext/socket/socket.c (udp_connect): ditto. Mon Jun 3 20:39:51 2002 Masaki Suketa * ext/win32ole/extconf.rb : change PLATFORM with RUBY_PLATFORM. Mon Jun 3 07:07:07 2002 Nobuyoshi Nakada * parse.y (here_document): check if identifier is terminated. (ruby-bugs-ja:PR#239) * parse.y (yylex): should pushback proper char after '**'. (ruby-bugs-ja:PR#240) Mon Jun 3 05:56:17 2002 Yukihiro Matsumoto * string.c (rb_str_aset): should raise error if an indexing string is not found in the receiver. * sprintf.c (rb_f_sprintf): "%d" should convert objects into integers using Integer(). Sat Jun 1 19:20:07 2002 Masaki Suketa * ext/win32ole: merge from rough. Fri May 31 17:11:42 2002 Yukihiro Matsumoto * lib/tempfile.rb (Tempfile::size): added. Thu May 30 12:52:42 2002 Yukihiro Matsumoto * range.c (range_step): iteration done using "+" if elements are Numeric. Otherwise using "succ". * range.c (range_each): iteration done using "succ". If the elements does not respond to "succ", raise TypeError. As a result, all Enumerable methods, e.g. collect, require elements to respond to "succ". * range.c (range_member): comparison done using "each", if elements are non-Numeric or no-"succ" objects. Otherwise compare using "<=>". * range.c (Init_Range): remove "size" and "length". Thu May 30 09:16:36 2002 Wakou Aoyama * lib/cgi.rb: if StringIO is usable then use it. Wed May 29 18:55:47 2002 KONISHI Hiromasa * function renames my* and win32_* to rb_w32_* in win32/win32.c fixed files win32/win32.c, win32/win32.h, win32/dir.h, hash.c, rubysig.h, signal.c, ext/socket/socket.c Wed May 29 17:32:55 2002 WATANABE Hirofumi * time.c (tmcmp, search_time_t): activate unless HAVE_TIMEGM. Wed May 29 13:45:15 2002 Wakou Aoyama * lib/cgi.rb: not use const if GET, HEAD. check multipart form head. Tue May 28 17:56:02 2002 Sean Chittenden * parse.y: yyparse #defines moved from intern.h * ruby.c (proc_options): access prefixed "ruby_yydebug". * applied modifies to pacify some of gcc -Wall warnings. Tue May 28 14:07:00 2002 Yukihiro Matsumoto * parse.y (arg): no more ugly hack for "**", so that "-2**2" to be parsed as "(-2)**2", whereas "- 2**2" or "-(2)**2" to be parsed as "-(2**2)". * parse.y (yylex): '-2' to be literal fixnum. [new] Tue May 28 12:13:37 2002 Nobuyoshi Nakada * eval.c (scope_node): trick to keep the node has a scope. * eval.c (rb_eval): NODE_EVSTR: write back local_tbl to the node. * eval.c (rb_eval): NODE_SCOPE: hold the scope node in ruby_scope. * eval.c (module_setup): ditto. * eval.c (rb_call0): ditto. * node.h (NEW_DASGN, NEW_DASGN_CURR): remove surplus semicolons. Fri May 24 09:06:29 2002 Yukihiro Matsumoto * time.c (time_arg): nil test against v[6] (usec). Thu May 23 16:39:21 2002 Nobuyoshi Nakada * ruby.c (proc_options): option parsing problem. (ruby-bugs-ja:PR#233) Thu May 23 09:13:56 2002 Yukihiro Matsumoto * ruby.c (proc_options): removed "-*-" support for #! line. * io.c (rb_io_s_sysopen): new method to get a raw file descriptor. [new] * ext/socket/socket.c (tcp_sysaccept): new method to return an accepted socket fd (integer). [new] * ext/socket/socket.c (unix_sysaccept,sock_sysaccept): ditto. Wed May 22 21:26:47 2002 Nobuyoshi Nakada * ruby.c (proc_options): -T consumes digits only. Wed May 22 20:18:31 2002 WATANABE Hirofumi * configure.in: need not link vsnprintf.o on MinGW. Wed May 22 18:34:23 2002 Minero Aoki * parse.y (yylex): Here-document label ate '-'. Tue May 21 13:25:18 2002 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-font-lock-keywords): symbols end with '_'. Tue May 21 04:48:37 2002 Sean Chittenden * lib/cgi-lib.rb: Checking for constant MOD_RUBY instead of environment variable. Remove a mod_ruby warning and use Apache::request.headers_out[] instead. Tue May 21 01:16:46 2002 Nobuyoshi Nakada * parse.y (bodystmt): ensure clause was executed on else clause without rescue clause. Tue May 21 00:20:25 2002 Takaaki Tateishi * ext/dl/ptr.c: rename PtrData::alloc to PtrData::malloc. * ext/dl/lib/dl/struct.c: rename Struct#alloc to Struct#malloc. Mon May 20 14:29:14 2002 Yukihiro Matsumoto * object.c (Init_Object): should do exact match for Module#==. * compar.c (cmp_eq): returns 'false' if <=> returns 'nil'. * compar.c (cmp_gt,cmp_ge,cmp_lt,cmp_le,cmp_between): ditto. Mon May 20 13:28:52 2002 Nobuyoshi Nakada * io.c (rb_io_clone): writing stream was not copied properly. Sat May 18 21:38:11 2002 Tadayoshi Funaba * lib/date.rb, lib/date/format.rb, lib/parsedate.rb: updated to the new version (based on date2 3.2.1). Sat May 18 21:18:00 2002 NAKAMURA Usaku * win32/Makefile.sub (config.h): add VC++4/5 support about noreturn directive. Sat May 18 02:16:41 2002 Yukihiro Matsumoto * pack.c (pack_pack): should propagate taintedness. * pack.c (pack_unpack): ditto. Fri May 17 16:16:19 2002 WATANABE Hirofumi * sample/test.rb: use eval instead of './miniruby -c', in order to check a syntax error. Thu May 16 14:46:34 2002 Nobuyoshi Nakada * eval.c (rb_thread_select): cleanup conditional compilation. Wed May 15 06:13:35 2002 Yukihiro Matsumoto * eval.c (rb_thread_schedule): need to preserve errno before calling rb_trap_exec(). * regex.c (calculate_must_string): a bug in charset/charset_not parsing. Tue May 14 18:17:44 2002 Nobuyoshi Nakada * win32/Makefile.sub: config.h inlined. and catch up with the latest change. * win32/config.h.in: no longer used. Tue May 14 14:49:05 2002 WATANABE Hirofumi * gc.c (is_pointer_to_heap): avoid GCC 3.1 warnings. * missing/strftime.c (timezone): it should take no argument on Cygwin. Tue May 14 03:07:35 2002 Yukihiro Matsumoto * eval.c (rb_clear_cache_by_class): new function. * eval.c (set_method_visibility): should have clear cache for updated visibility. Mon May 13 14:38:33 2002 WATANABE Hirofumi * djgpp/config.hin, djgpp/config.sed: catch up with the latest change. Mon May 13 01:59:55 2002 Yukihiro Matsumoto * numeric.c (flo_to_s): default format precision to be "%.16g". * util.c (ruby_strtod): use own strtod(3) implementation to avoid locale hell. Due to this change "0xff".to_f no longer returns 255.0 Sun May 12 03:01:08 2002 WATANABE Hirofumi * missing.h: add for missing/*.c. * ruby.h: add `#include "missing.h"'. * Makefile.in: add the dependency of missing.h by gcc -MM. * MANIFEST: add missing.h Sat May 11 23:24:52 2002 Takaaki Tateishi * ext/dl: enable dl's stack emulation for constructing function call. Sat May 11 10:52:09 2002 Nobuyoshi Nakada * dir.c (glob_helper): remove escaping backslashes. Sat May 11 02:46:43 2002 Yukihiro Matsumoto * eval.c (avalue_to_yvalue): new function to distinguish yvalue (no-arg == Qundef) from svalue (no-arg == Qnil). * eval.c (rb_yield_0): use avalue_to_yvalue(). * eval.c (assign): warn if val == Qundef where it means rhs is void (e.g. yield without value or call without argument). Fri May 10 19:00:47 2002 Nobuyoshi Nakada * parse.y (here_document): preserve line number begins here document. Fri May 10 01:55:44 2002 Nobuyoshi Nakada * eval.c (rb_thread_join): added an argument to limit time to wait the thread. * eval.c (rb_thread_join_m): new. and added optional argument. Wed May 8 23:48:40 2002 Yukihiro Matsumoto * parse.y (value_expr): need not to warn for WHILE and UNTIL, since they can have return value (via valued break). Tue May 7 17:13:40 2002 WATANABE Hirofumi * configure.in: forgot to add '-Wl,' to the gcc option on Cygwin/MinGW. Tue May 7 15:41:33 2002 Nobuyoshi Nakada * ext/iconv/iconv.c (iconv_try): should initialize exceptions properly. (ruby-bugs-ja:PR#232) Tue May 7 15:28:03 2002 Minero Aoki * eval.c (rb_yield_0): The destination of the goto jump was wrong. Tue May 7 09:17:51 2002 Minero Aoki * eval.c (superclass): undesirable "unexpected return" when the superclass is not a Class. Sun May 5 06:53:45 2002 Akinori MUSHA * lib/mkmf.rb: exclude topdir from the system configuration section and prevent it from being overridden. Fri May 3 20:19:00 2002 WATANABE Hirofumi * configure.in: add #include in AC_CHECK_DECLS(). * win32/config.h.in: define HAVE_DECL_SYS_NERR. Thu May 2 23:42:40 2002 Yukihiro Matsumoto * re.c (rb_reg_s_quote): # also should be quoted. Thu May 2 18:27:13 2002 WATANABE Hirofumi * ext/extmk.rb.in, lib/mkmf.rb: use 'do...end' instead of '{}' for Borland make. Thu May 2 08:01:56 2002 Chris Thomas * error.c: use HAVE_DECL_SYS_NERR instead of platform names. Tue Apr 30 09:23:05 2002 Yukihiro Matsumoto * numeric.c (num_step): better iteration condition for float values; suggested by Masahiro TANAKA . Tue Apr 30 05:59:42 2002 Michal Rokos * range.c (range_step): step (for Range#step method) <= 0 makes no sense, thus ArgError will be raised. * range.c (range_each): Range#each method is special case for Range#step(1) Mon Apr 29 18:46:42 2002 Yukihiro Matsumoto * file.c (rb_find_file): load must be done from an absolute path if $SAFE >= 4. Sun Apr 28 17:01:56 2002 WATANABE Hirofumi * win32/win32.c (insert): fix prototype for ANSI C. Fri Apr 26 13:47:15 2002 Yukihiro Matsumoto * enum.c (enum_partition): new method. [new] Fri Apr 26 13:41:00 2002 Yukihiro Matsumoto * re.c (rb_reg_s_quote): quote whitespaces for /x cases. Fri Apr 26 06:48:23 2002 Takaaki Tateishi * ext/dl/ptr.c (cary2ary): missing break in switch statements. Fri Apr 26 09:35:47 2002 Nobuyoshi Nakada * eval.c (rb_proc_new): make Proc from C function. [new] * intern.h (rb_proc_new): prototype. Wed Apr 24 14:56:46 2002 Nobuyoshi Nakada * eval.c (proc_to_proc): return self. [new] * eval.c (block_pass): no need to convert if block is Proc. Wed Apr 24 14:21:41 2002 WATANABE Hirofumi * configure.in: set size of the initial stack from 2MB to 32MB on MinGW/Cygwin. Wed Apr 24 14:06:35 2002 Yukihiro Matsumoto * numeric.c (num_step): try to reduce residual on Float operations. Wed Apr 24 06:48:31 2002 Koji Arai * io.c (rb_io_mode_flags): both 'r+b' and 'rb+' should be allowed. * io.c (rb_io_mode_modenum): ditto. Wed Apr 24 01:16:14 2002 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_mark): must check if ptr is NULL first. [ruby-talk:38873] * lib/mkmf.rb (create_makefile): should print depend file when make is other than nmake. Wed Apr 24 00:37:12 2002 NAKAMURA Usaku * ext/extmk.rb.in (create_makefile): use `{$(srcdir)}' directive instead of `$(srcdir)/' when including depend file. * lib/mkmf.rb (create_makefile): add `{$(srcdir)}' when including depend file. Tue Apr 23 12:58:18 2002 Yukihiro Matsumoto * gc.c (rb_memerror): rename from mem_error, and exported. * gc.c (Init_GC): pre-allocate NoMemoryError instance. * object.c (convert_type): error message changed from "failed to convert" to "cannot convert", since it does not try to convert if an object does not respond to the converting method. Mon Apr 22 09:31:30 2002 Yukihiro Matsumoto * eval.c (block_pass): convert Method to Proc using rb_check_convert_type(). * object.c (rb_check_convert_type): always convert T_DATA * eval.c (rb_thread_cleanup): should not terminate main_thread by Fatal error. * regex.c (is_in_list): need to not exclude NUL and NEWLINE. Sat Apr 20 00:19:13 2002 Yukihiro Matsumoto * re.c (rb_reg_expr_str): wrong backslash escapement. * re.c (rb_reg_expr_str): do not escape embedded space characters. Fri Apr 19 22:03:40 2002 NAKAMURA Usaku * win32/Makefile.sub: add -DNT to $CFLAGS instead of $CPPFLAGS. * win32/setup.mak: ditto. Fri Apr 19 17:24:22 2002 Yukihiro Matsumoto * marshal.c (w_object): T_DATA process patch from Joel VanderWerf . This is temporary hack; it remains undocumented, and it will be removed when marshaling is re-designed. * marshal.c (r_object): ditto. Fri Apr 19 17:10:55 2002 Yukihiro Matsumoto * numeric.c (num_step): Integer#step is moved to Numeric#step; Fixnum#step is merged into this method. * numeric.c (int_dotimes): Fixnum#times is merged. * numeric.c (int_upto): Fixnum#upto is merged. * numeric.c (int_downto): Fixnum#downto is merged. Fri Apr 19 16:22:55 2002 WATANABE Hirofumi * ext/socket/extconf.rb: include , on _WIN32. * win32/win32.c: include on __MINGW32__. * configure.in: cleanup for autoconf 2.5x. * configure.in: use gcc -shared instead of dllwrap on Cygwin/MinGW. * ext/extmk.rb, lib/mkmf.rb: get rid of "--def=". Fri Apr 19 14:57:44 2002 Nobuyoshi Nakada * re.c (rb_reg_to_s): remove redundant shy group. Fri Apr 19 01:08:20 2002 Yukihiro Matsumoto * eval.c (rb_thread_cleanup): current thread may be THREAD_STOPPED, for example when terminated from signal handler. Thu Apr 18 19:03:15 2002 Yukihiro Matsumoto * regex.c (re_compile_pattern): remove /p support. * regex.h: ditto. * parse.y (parse_regx): ditto. Thu Apr 18 17:01:43 2002 Takaaki Tateishi * ext/dl/ptr.c (rb_dlptr_cast): removed. Thu Apr 18 17:01:43 2002 Tanaka Akira * re.c (rb_reg_to_s): new function for Regexp#to_s. Wed Apr 17 23:55:34 2002 Akinori MUSHA * ext/Setup*, ext/bigfloat/*: Back out the import of BigFloat in favor of its forthcoming successor, BigDecimal. Wed Apr 17 16:53:33 2002 Yukihiro Matsumoto * re.c (rb_reg_expr_str): should treat backslash specially in escaping. Wed Apr 17 08:16:41 2002 Michal Rokos * io.c: complete off_t handling; missing argument for fptr_finalize(); polished rb_scan_args call. Wed Apr 17 00:01:59 2002 Michal Rokos * dir.c: wrap multi-statement macro by do { } while (0) * eval.c, numeric,c, sprintf.c, util.c: ditto. Tue Apr 16 08:59:50 2002 Nobuyoshi Nakada * eval.c (assign): convert mrhs to mvalue. Mon Apr 15 18:12:57 2002 Yukihiro Matsumoto * bignum.c (rb_big_eq): check `y == x' if y is neither Fixnum, Bignum, nor Float. Mon Apr 15 09:27:31 2002 Yukihiro Matsumoto * pack.c (pack_unpack): should treat 'U' in character unit, not in byte unit. * error.c (exc_initialize): should clear backtrace information. Sat Apr 13 23:42:43 2002 Yukihiro Matsumoto * io.c (rb_io_fptr_cleanup): should close IO created by IO.new(fd). * rubyio.h: remove FMODE_FDOPEN Fri Apr 12 12:54:04 2002 NAKAMURA Usaku * win32/Makefile.sub: use missing/acosh.c. * win32/config.h.in: define HAVE_COSH, HAVE_SINH, and HAVE_TANH. Fri Apr 12 02:58:55 2002 Koji Arai * struct.c (rb_struct_select): fix typo. Fri Apr 12 00:34:17 2002 Nobuyoshi Nakada * MANIFEST (missing/acosh.c): added. * Makefile.in (missing/acosh.c): ditto. * Makefile.in (missing/fileblocks.c): ditto. * configure.in (AC_REPLACE_FUNCS): check acosh() on behalf of inverse hyperbolic functions, asinh() and atanh(). * missing/acosh.c: added for acosh(), asinh() and atanh(). Thu Apr 11 20:01:44 2002 Masahiro Tomita * io.c (io_write): check error if written data is less than specified size to detect EPIPE. Thu Apr 11 19:10:37 2002 WATANABE Hirofumi * io.c (remain_size): IO#read returns "" if file.size == 0. * random.c (rand_init): add check for initstate(3). * configure.in: ditto. Thu Apr 11 09:31:19 2002 Takaaki Tateishi * ext/dl/ptr.c: raise() -> rb_raise(). (Thanks Tetsuya Watanabe) * ext/dl/sym.c: ditto. Thu Apr 11 07:57:48 2002 Michal Rokos * eval.c (assign): ruby_verbose should be surrounded by RTEST(). * object.c (rb_str2cstr): ditto. * parse.y (void_expr): ditto. * parse.y (void_stmts): ditto. * variable.c (rb_ivar_get): ditto. * variable.c (rb_cvar_set): ditto. * variable.c (rb_cvar_get): ditto. Thu Apr 11 07:02:31 2002 Takaaki Tateishi * ext/dl: Add dl.txt instead of README and README.html. Thu Apr 11 01:55:52 2002 Wakou Aoyama * lib/cgi/session.rb: support for multipart form. Wed Apr 10 18:42:23 2002 Tachino Nobuhiro * dir.c (glob_helper): should have proceed link when link->path was non existing symbolic link. Wed Apr 10 17:30:19 2002 Yukihiro Matsumoto * variable.c (rb_obj_remove_instance_variable): raise NameError if specified instance variable is not defined. * variable.c (generic_ivar_remove): modified to check ivar existence. Wed Apr 10 14:16:45 2002 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-font-lock-keywords): fontify symbols for unary operators and aset. Tue Apr 9 13:40:31 2002 Nobuyoshi Nakada * lib/mkmf.rb (try_link0): need expand macro in command, sync with ext/extmk.rb.in. * lib/mkmf.rb (try_cpp): ditto. * lib/mkmf.rb (egrep_cpp): ditto. Tue Apr 9 12:44:59 2002 Nobuyoshi Nakada * ext/stringio/stringio.c (check_modifiable): performance improvement. avoid calling rb_str_modify() twice. * ext/stringio/stringio.c (strio_ungetc): ditto. * ext/stringio/stringio.c (strio_putc): ditto. * ext/stringio/stringio.c (strio_write): ditto, and use rb_str_cat() as possible. Tue Apr 9 05:17:48 2002 Akinori MUSHA * re.c (match_select): fix index references and make MatchData#select actually work. Tue Apr 9 00:20:52 2002 Yukihiro Matsumoto * file.c (rb_file_s_extname): new method based on the proposal (and patch) from Mike Hall. [new] Mon Apr 8 04:50:51 2002 Nobuyoshi Nakada * eval.c (error_handle): default to 1 unless status is set. * eval.c (ruby_options): guard error_handle() with PROT_NONE. * eval.c (ruby_stop): ditto. Mon Apr 8 01:22:24 2002 Yukihiro Matsumoto * math.c (math_acosh): added. [new] * math.c (math_asinh): ditto. * math.c (math_atanh): ditto. * struct.c (rb_struct_each_pair): method added. [new] Sat Apr 6 02:04:49 2002 Guy Decoux * class.c (rb_singleton_class): wrong condition; was creating unnecessary singleton class. Sat Apr 6 01:09:41 2002 Yukihiro Matsumoto * sprintf.c (remove_sign_bits): simplifies the condition. * bignum.c (get2comp): calculate proper carry over. Fri Apr 5 05:07:28 2002 Takaaki Tateishi * ext/dl: Add dl/struct.rb. Thu Apr 4 14:08:52 2002 Takaaki Tateishi * ext/dl/lib/dl/import.rb: Get rid of ineffective encoding/decoding procedures. Thu Apr 4 01:08:23 2002 Yukihiro Matsumoto * numeric.c (int_step): step may be a float less than 1. Wed Apr 3 20:42:34 2002 Takaaki Tateishi * ext/dl: Merge Nakada's patch. * ext/dl/dl.h: define StringValuePtr for ruby-1.6. Wed Apr 3 15:37:24 2002 Takaaki Tateishi * ext/dl: Add dl/types.rb. Wed Apr 3 01:54:10 2002 Nobuyoshi Nakada * ext/extmk.rb.in (enable_config): follow lib/mkmf.rb. Tue Apr 2 19:59:13 2002 Takaaki Tateishi * ext/dl: Merge from rough. Tue Apr 2 15:17:54 2002 Yukihiro Matsumoto * Makefile.in (CPPFLAGS): remove @includedir@. * lib/mkmf.rb (create_makefile): ditto. * ext/extmk.rb.in (create_makefile): ditto. Tue Apr 2 15:09:05 2002 WATANABE Hirofumi * ext/socket/socket.c (sock_addrinfo): should clear addrinfo hints. Mon Apr 1 23:48:12 2002 Takaaki Tateishi * lib/mkmf.rb: install any files using $INSTALLFILES. (see also [ruby-dev:16683]) Mon Apr 1 17:25:50 2002 Yukihiro Matsumoto * io.c (rb_io_fptr_cleanup): need flush even when io will not be closed. * io.c (rb_io_initialize): was calling wrong function rb_io_mode_flags(). Mon Apr 1 16:52:00 2002 Nobuyoshi Nakada * ext/sdbm/init.c (each_pair): moved prototype before the definition. * ext/racc/cparse/cparse.c (call_scaniter): ditto. Mon Apr 1 15:11:40 2002 NAKAMURA Usaku * ext/racc/cparse/cparse.c: prototype; call_scaniter(). * ext/sdbm/init.c: prototype; each_pair(). * ext/tcltklib/tcltklib.c: prototypes; _timer_for_tcl() and ip_ruby(), Nobu's patch at [ruby-dev:14483]. Mon Apr 1 10:56:40 2002 Yukihiro Matsumoto * re.c (match_setter): it's OK to assign nil to $~. Mon Apr 1 03:55:46 2002 Yukihiro Matsumoto * io.c (rb_io_fptr_cleanup): do not close IO created by for_fd(). * io.c (rb_io_initialize): mark IO created by for_fd * ext/socket/socket.c (bsock_s_for_fd): ditto. Fri Mar 29 20:21:58 2002 Nobuyoshi Nakada * lib/mkmf.rb (create_makefile): default FLAGS to empty strings. Fri Mar 29 16:36:52 2002 Nobuyoshi Nakada * lib/mkmf.rb (arg_config): should use Shellwords::shellwords like ext/extmk.rb.in. * lib/mkmf.rb (enable_config): default had priority over command line options and configure_args. * lib/mkmf.rb: support autoconf 2.53 style variables from environment. * lib/mkmf.rb: add directory options. Fri Mar 29 15:49:29 2002 Usaku Nakamura * win32/README.win32: follow recent changes. Fri Mar 29 14:44:05 2002 Yukihiro Matsumoto * io.c (io_fflush): DRY patch from /Christoph applied. Thu Mar 28 18:58:13 2002 Usaku Nakamura * win32/Makefile.sub (config.status): reflect user defined $CC in config.status. Thu Mar 28 18:03:51 2002 Minero Aoki * ext/strscan/strscan.c: add taint check. * ext/strscan/strscan.c: #getch/#get_byte should set regexp registers. * ext/strscan/strscan.c: remove useless #include directive. * ext/strscan/strscan.c: refactor struct strscanner. Thu Mar 28 14:51:38 2002 Yukihiro Matsumoto * ext/socket/socket.c (sock_addrinfo): should specify socktype from outside. Wed Mar 27 17:04:30 2002 Yukihiro Matsumoto * io.c (argf_binmode): should call next_argv() to initialize ARGF. * io.c (argf_filename): ditto. * io.c (argf_file): ditto. Wed Mar 27 14:47:32 2002 WATANABE Hirofumi * io.c (READ_DATA_PENDING): configure.in has supported for uClibc, so remove uClibc stuff. Wed Mar 27 13:14:43 2002 Yukihiro Matsumoto * io.c (rb_io_sysseek): new method based on a patch from Aristarkh A Zagorodnikov . [new] * io.c (READ_DATA_PENDING): use !feof(fp) for default behavior. Tue Mar 26 20:28:50 2002 Minero Aoki * lib/net/http.rb: HTTP.get accepts URI. * lib/net/http.rb: new method HTTP.get_uri. * lib/net/http.rb: add some HTTP 1.1 response codes. Tue Mar 26 20:25:28 2002 Minero Aoki * doc/net/protocol.rd.ja, smtp.rd.ja, pop.rd.ja: removed. * MANIFEST: remove doc/net/* entries. Tue Mar 26 18:45:15 2002 WATANABE Hirofumi * configure.in (FILE_READPTR): check bufread instead of bufend for uClibc. * ext/extmk.rb.in (arg_config): should use Shellwords::shellwords. Tue Mar 26 01:56:33 2002 Yukihiro Matsumoto * parse.y (primary): while/until statement modifiers to "begin" statement now work as "do .. while" even when begin statement has "rescue" or "ensure" [new]. * parse.y (bodystmt): rescue/ensure is allowed at every bodies, i.e. method bodies, begin bodies, class bodies[new], and module bodies[new]. Mon Mar 25 22:10:04 2002 Yukihiro Matsumoto * ext/socket/socket.c (sock_addrinfo): should specify ai_socktype for getaddrinfo hints. Mon Mar 25 17:18:48 2002 Nobuyoshi Nakada * dir.c (rb_push_glob): local variable 'maxnest' was uninitialized. Mon Mar 25 16:53:30 2002 Yukihiro Matsumoto * eval.c (rb_f_abort): embed aborting message into exception object [new]. * eval.c (terminate_process): utility function for exit and abort. Tue Mar 26 14:04:47 2002 okabe katsuyuki * win32/mkexports.rb: support VC++.NET. Tue Mar 26 14:00:17 2002 Akinori MUSHA * ext/bigfloat/bigfloat.c: Fix the initializer's function name according to the new library name. (pointed out by nobu) Tue Mar 26 11:12:01 2002 Minero Aoki * lib/fileutils.rb: new file. Tue Mar 26 03:23:50 2002 Tanaka Akira * lib/pp.rb (pp): return nil like p. Tue Mar 26 01:48:01 2002 Akinori MUSHA * ext/bigfloat/extconf.rb: Downcase the library name. (BigFloat.so -> bigfloat.so) * ext/bigfloat/bigfloat.c (BigFloat_inspect): Alter the inspect format not to look like an array. (pointed out by akr) * ext/bigfloat/bigfloat.c (BigFloat_hash): Implement BigFloat#hash. * ext/bigfloat/bigfloat.c (BigFloat_dump, BigFloat_load): Support marshaling. Tue Mar 26 00:38:11 2002 Tanaka Akira * configure.in (FILE_READPTR): check _p for 4.4BSD. Mon Mar 25 23:39:25 2002 Nobuyoshi Nakada * configure.in (FILE_READPTR): new. for IO#gets improvement. * io.c (READ_DATA_PENDING_PTR): ditto. * io.c (remain_size): separated from read_all(). * io.c (read_all): argument changed. * io.c (appendline): new. get a line and append to string. * io.c (swallow): new. swallow continuous line delimiters. * io.c (rb_io_getline_fast): add delimiter argument. * io.c (rb_io_getline): performance improvement. Mon Mar 25 19:30:25 2002 WATANABE Hirofumi * ext/extmk.rb.in (arg_config): get rid of single quotes for autoconf 2.53. Mon Mar 25 17:49:41 2002 Nobuyoshi Nakada * regex.c (mbc_startpos_func): VC6 seems to be unable to understand forward declaration for static variables. * dir.c (rb_push_glob): local variable 'maxnest' was uninitialized. Mon Mar 25 13:24:20 2002 Yukihiro Matsumoto * ext/socket/socket.c (bsock_do_not_rev_lookup_set): should not be allowed when $SAFE > 3. * eval.c (rb_thread_ready): THREAD_TO_KILL threads should not turn into THREAD_RUNNABLE on wakeup. * eval.c (rb_thread_list): THREAD_TO_KILL threads should be in the list. * eval.c (thgroup_list): ditto; by moving gid clearance from rb_thread_cleanup(). Mon Mar 25 11:06:19 2002 Nobuyoshi Nakada * dln.c (dln_argv0): unused unless USE_DLN_A_OUT. * regex.c (mbc_startpos_func): should be static. Sun Mar 24 12:19:09 2002 Koji Arai * dir.c (fnmatch): "*/bar" (with FNM_PATHNAME flag) does not match "foo/bar". Sun Mar 24 00:46:05 2002 WATANABE Hirofumi * util.c (push_element): avoid warning for djgpp. Sat Mar 23 01:50:30 2002 Yukihiro Matsumoto * io.c (read_all): files on /proc filesystem with zero stat size, may have contents. Fri Mar 22 18:07:29 2002 Yukihiro Matsumoto * ext/socket/socket.c (tcp_s_gethostbyname): refactored. * ext/socket/socket.c (sock_s_gethostbyname): ditto. Fri Mar 22 16:46:54 2002 Minero Aoki * ext/extmk.rb.in: replace mkdir with mkpath to compile racc/cparse. Fri Mar 22 16:22:55 2002 Yukihiro Matsumoto * the VMS support patch submitted by Akiyoshi, Masamichi is merged. Fri Mar 22 16:27:24 2002 Minero Aoki * lib/racc/parser.rb: new file. * ext/racc/MANIFEST, cparse.c, depend, extconf.rb: new files. * lib/README: add racc/parser.rb. * ext/Setup*: add racc/cparse. Fri Mar 22 15:04:03 2002 Yukihiro Matsumoto * eval.c (exec_under): changing ruby_class is OK, but should not alter cbase. * eval.c (yield_under_i): ditto. Fri Mar 22 15:44:38 2002 Minero Aoki * ext/strscan/MANIFEST, strscan.c, depend, extconf.rb: new files. * ext/Setup*: add strscan entry. Fri Mar 22 14:32:14 2002 Minero Aoki * lib/net/protocol.rb: Protocol#start should return self. Fri Mar 22 14:14:21 2002 Tanaka Akira * lib/resolv.rb: fix arguments to create exceptions. Patch from matt@lickey.com. (ruby-bugs:PR#278) Fri Mar 22 13:51:11 2002 Akinori MUSHA * ext/bigfloat/.cvsignore, ext/bigfloat/MANIFEST: BigFloat 1.1.8 has been imported. Add .cvsignore and MANIFEST. Fri Mar 22 04:07:55 2002 Koji Arai * sprintf.c (rb_f_printf): discard meaningless prefix ".." for '%u'. Thu Mar 21 01:11:37 2002 Usaku Nakamura * win32/Makefile.sub (config.status): fix install path (prefix). Thu Mar 21 01:03:05 2002 Nobuyoshi Nakada * ext/configsub.rb: latest autoconf style support. Wed Mar 20 22:16:25 2002 Usaku Nakamura * mkconfig.rb: close duplicated $stdout before renaming rbconfig.rb. Wed Mar 20 21:54:17 2002 Nobuyoshi Nakada * win32/Makefile.sub: made variables configurable. * win32/Makefile.sub (config.h): updates RUBY_PLATFORM from Makefile. * win32/Makefile.sub (config.status): ditto. and use recent autoconf format. * win32/Makefile.sub (clean): separate ext and local clean up. * win32/Makefile.sub (distclean): ditto. * win32/config.status.in: no longer used. Wed Mar 20 20:12:35 2002 Nobuyoshi Nakada * variable.c (rb_const_list): a temporary table must be freed. Wed Mar 20 19:44:09 2002 Tanaka Akira * mkconfig.rb: don't touch rbconfig.rb if there is a trouble. Wed Mar 20 16:05:37 2002 Yukihiro Matsumoto * eval.c (is_defined): should check receiver only once. * eval.c (is_defined): should handle NODE_NEWLINE. Wed Mar 20 11:29:25 2002 Aristarkh A Zagorodnikov * file.c (rb_file_s_expand_path): memory leak fixed. Wed Mar 20 00:36:43 2002 Akinori MUSHA * util.c (ruby_getcwd): the content of buf is uncertain and must not be printed when getcwd(buf, size) has failed. Mon Mar 18 22:19:52 2002 Nobuyoshi Nakada * ext/stringio/stringio.c (check_modifiable): wrong declaration. Mon Mar 18 18:04:05 2002 Nobuyoshi Nakada * ext/digest: add depend file. * ext/digest/md5: ditto. * ext/digest/rmd160: ditto. * ext/digest/sha1: ditto. * ext/digest/sha2: ditto. * ext/iconv/MANIFEST: ditto. * ext/stringio/MANIFEST: ditto. * ext/syslog: ditto. Mon Mar 18 17:18:06 2002 Nobuyoshi Nakada * eval.c (rb_f_abort): should not bypass cleanup. * ext/stringio/stringio.c (check_modifiable): void function. Mon Mar 18 12:52:01 2002 WATANABE Hirofumi * ext/iconv/extconf.rb: workaround for GNU libiconv. Mon Mar 18 10:55:03 2002 Nobuyoshi Nakada * parse.y (parse_string): part of multi-byte sequence must not match to paren. * parse.y (parse_qstring): ditto. * parse.y (parse_quotedwords): ditto. * parse.y (str_extend): handle multi-byte characters. Mon Mar 18 10:31:20 2002 Nobuyoshi Nakada * enum.c (enum_find): catch a value before recycle. * enum.c (enum_all): ditto. * enum.c (enum_any): ditto. * enum.c (enum_min): ditto. * enum.c (enum_max): ditto. Sun Mar 17 20:08:04 2002 Nobuyoshi Nakada * ext/iconv/depend: added. * ext/stringio/depend: added. Sat Mar 16 22:43:53 2002 WATANABE Hirofumi * missing/fileblocks.c: add for autoconf. Sat Mar 16 15:30:40 2002 Yukihiro Matsumoto * re.c (rb_reg_search): should clear last_match if pos is out of string range. * string.c (rb_str_index_m): ditto. * string.c (rb_str_rindex): ditto. Sat Mar 16 09:04:58 2002 Koji Arai * enum.c (enum_inject): use the first iterated element as the initial value when omitted. * enum.c (inject_i): ditto. * enum.c (Init_Enumerable): Enumerable#inject now takes variable count arguments. Fri Mar 15 19:47:31 2002 Nobuyoshi Nakada * win32/win32.c (StartSockets): remove duplicated lines. Fri Mar 15 17:44:08 2002 Usaku Nakamura * bignum.c, intern.h (rb_ull2big, rb_ll2big, rb_ull2inum, rb_ll2inum, big2ull, rb_big2ull, rb_big2ll): use LONG_LONG macro instead of long long. * numeric.c, intern.h, ruby.h (rb_num2ll, rb_num2ull): ditto. * ruby.h: use _I64_MAX and _I64_MIN if they are defined (for VC++). Fri Mar 15 14:02:43 2002 Nobuyoshi Nakada * ext/iconv/iconv.c: fixed document, Iconv#new is no longer an iterator. thanks to Tanaka Akira . Thu Mar 14 22:17:45 2002 Nobuyoshi Nakada * ext/iconv: imported. Thu Mar 14 16:42:37 2002 Yukihiro Matsumoto * class.c (rb_define_class): should handle autoload. * class.c (rb_define_module): ditto. Thu Mar 14 16:18:12 2002 WATANABE Hirofumi * configure.in: autoconf 2.53 support. use AC_LIBOBJ. Thu Mar 14 00:29:12 2002 Yukihiro Matsumoto * re.c (rb_reg_match): should clear $~ if operand is nil. * re.c (rb_reg_match2): ditto. Thu Mar 14 12:32:59 2002 Nobuyoshi Nakada * ext/stringio/stringio.c: fixed frozen string bug. ungetc no longer raises on readonly stream unless modifies actually. Thu Mar 14 08:57:41 2002 Nobuyoshi Nakada * dir.c (rb_push_glob): avoid SEGV when a block given. Thu Mar 14 00:16:02 2002 Nobuyoshi Nakada * string.c (rb_str_subpat_set): must make str independent after rb_reg_search() matched. Wed Mar 13 19:05:15 2002 Akinori MUSHA * dir.c: FNM_PERIOD is obsoleted and FNM_DOTMATCH is introduced instead, which has the opposite meaning of FNM_PERIOD. * dir.c: Dir::glob now accepts optional FNM_* flags via the second argument, whereas Dir::[] doesn't. Wed Mar 13 18:36:55 2002 Akinori MUSHA * lib/getopts.rb: single_options can be nil[*], and is not not optional. ([*]Pointed out by gotoken) Wed Mar 13 17:23:46 2002 Yukihiro Matsumoto * configure: merge Jonathan Baker's large file support patch [ruby-talk:35316], with read_all patch in [ruby-talk:35470]. Wed Mar 13 04:06:48 2002 Yukihiro Matsumoto * eval.c (rb_f_abort): optional message argument that be printed on termination. Tue Mar 12 17:12:06 2002 Tanaka Akira * lib/resolv.rb: don't complete domains for absolute FQNs. Mon Mar 11 23:08:48 2002 Tanaka Akira * lib/tsort.rb: new file. Mon Mar 11 21:03:37 2002 Nobuyoshi Nakada * ext/stringio: new. Mon Mar 11 18:03:37 2002 Yukihiro Matsumoto * regex.c (re_compile_pattern): '\0111' should be '\011' plus '1', since octal literals are formed by three digits at most. Mon Mar 11 14:44:38 2002 Yukihiro Matsumoto * marshal.c (w_object): module inclusion using extend() should also be detected. * eval.c (rb_eval_cmd): cbase should not be NULL; it should be either ruby_wrapper or Object. Sun Mar 10 02:18:22 2002 Koji Arai * enum.c (enum_each_with_index): should return self. * process.c (proc_setpgrp): should return value for non-void function. * process.c (proc_getpgid): should raise exception if getpgid() return -1. * string.c (rb_str_ljust): should return a duplicated string. * string.c (rb_str_rjust): ditto. * string.c (rb_str_center): ditto. Sat Mar 9 08:45:58 2002 Tanaka Akira * ext/socket/extconf.rb (have_struct_member): don't print checked result. Fri Mar 8 12:19:15 2002 Tanaka Akira * lib/resolv.rb: use its own thread group for background threads. Fri Mar 8 02:21:32 2002 Yukihiro Matsumoto * eval.c (cvar_cbase): utility function to find innermost non singleton cbase. * eval.c (is_defined): adopt new cvar behavior. * eval.c (rb_eval): ditto. * eval.c (assign): ditto. Thu Mar 7 20:08:25 2002 Nobuyoshi Nakada * gc.c (rb_source_filename): added. holds unique strings for file names with GC space. * gc.c (rb_gc_mark): mark source file name. * gc.c (gc_sweep): ditto. * gc.c (Init_GC): initialize source file name table. * intern.h (rb_source_filename): added. * eval.c (rb_eval_string): use rb_source_filename(). * parse.y (yycompile): ditto. * ruby.c (proc_options): ditto. * ruby.c (load_file): ditto. * ruby.c (ruby_script): ditto. * ruby.c (ruby_prog_init): ditto. Wed Mar 6 17:58:08 2002 WATANABE Hirofumi * dln.c (dln_load): use LoadLibrary instead of LoadLibraryEx. Wed Mar 6 16:50:37 2002 Yukihiro Matsumoto * class.c (rb_mod_clone): should not call rb_obj_clone(), since Module does not provide "allocate". * class.c (rb_singleton_class): should create new singleton class if obj is a class or module and attached object is different, which means metaclass of singleton class is sought. * time.c (time_s_alloc): now follows allocation framework. Tue Mar 5 05:56:29 2002 Akinori MUSHA * lib/getopts.rb: Rewrite to fix some bugs and complete features. - Accept options with the colon in the first argument; getopts("a:bcd:") is equivalent to getopts("bc", "a:", "d:"). - Do not discard the argument that caused an error. - Do not discard '-', which commonly stands for stdin or stdout. - Allow specifying a long option with a value using '='. (command --long-option=value) - Stop reading options when it meets a non-option argument. Mon Mar 4 13:19:18 2002 Akinori MUSHA * ext/extmk.rb.in (dir_config): Sync with mkmf.rb: Fix a bug where --with-xx-{include,lib} is ignored when --with-xx-dir is specified. Mon Mar 4 00:09:55 2002 Yukihiro Matsumoto * eval.c (rb_eval): should initialize outer class variables from methods in singleton class definitions. * eval.c (assign): ditto. Fri Mar 1 11:29:10 2002 WATANABE Hirofumi * ext/socket/{addinfo.h,getaddrinfo.c} (gai_strerror): add const qualifier only for uClibc. Fri Mar 1 11:22:51 2002 Amos Gouaux * lib/net/imap.rb: added document. * lib/net/imap.rb (getquotaroot): new method. * lib/net/imap.rb (setacl): remove the rights if the rights parameter is nil. * lib/net/imap.rb (getacl): return an array of MailboxACLItem. Fri Mar 1 06:25:49 2002 Tanaka Akira * ext/socket/extconf.rb (have_struct_member): new method. check msg_control and msg_accrights in struct msghdr. check sys/uio.h. * ext/socket/socket.c: include sys/uio.h if available. (thread_read_select): new function. (unix_send_io): ditto. (unix_recv_io): ditto. (unix_s_socketpair): ditto. (Init_socket): define UNIXSocket#send_io, UNIXSocket#recv_io, UNIXSocket.socketpair and UNIXSocket.pair. * dln.c (dln_load): fix typo. Wed Feb 27 16:30:50 2002 Yukihiro Matsumoto * eval.c (rb_mod_include): load modules in argument order. * st.c (st_init_table_with_size): num_bins should be prime numbers (no decrement). * st.c (rehash): ditto. Wed Feb 27 13:18:49 2002 WATANABE Hirofumi * io.c (READ_DATA_PENDING): uClibc support. * random.c (rand_init): ditto. * ext/socket/{addinfo.h,getaddrinfo.c} (gai_strerror): ditto. Wed Feb 27 07:05:17 2002 Akinori MUSHA * ext/digest/sha2/sha2.c: Merge from rough. Fix a couple of off-by-one errors in Aaron Gifford's code. Obtained from: KAME via FreeBSD KAME PR: 393 FreeBSD PR: kern/34242 Wed Feb 27 03:36:47 2002 Koji Arai * ext/dbm/dbm.c (fdbm_select): 1.7 behavior. * ext/gdbm/gdbm.c (fgdbm_select): ditto. * ext/sdbm/sdbm.c (fsdbm_select): ditto. * ext/dbm/dbm.c (fdbm_delete): adopt Hash#delete behavior. * ext/sdbm/sdbm.c (fsdbm_delete): ditto. * ext/gdbm/gdbm.c: need not to dup key to the block. * ext/sdbm/sdbm.c : replace RuntimeError with SDBMError. Tue Feb 26 21:34:07 2002 Usaku Nakamura * bignum.c (rb_big_2comp): void function cannot return any value. Tue Feb 26 16:52:12 2002 Yukihiro Matsumoto * eval.c (rb_f_missing): NoMethod error messages for true, false, nil must respond visibility like for other objects. Tue Feb 26 15:41:30 2002 Yukihiro Matsumoto * eval.c (rb_eval): call trace_func for if/while conditions. * marshal.c (r_object): separate r_regist from proc calling. Tue Feb 26 11:25:50 2002 akira yamada * lib/uri/generic.rb: merge0 should return [oth, oth] if oth is absolute URI. * lib/uri/generic.rb: registry part must not be allowed for any schemes for the Internet. (RFC2396, section 3.2.2 and 3.2.1.) Mon Feb 25 21:22:41 2002 Akinori MUSHA * ext/syslog/syslog.c: Merge from rough. Use SafeStringValue(). Mon Feb 25 21:12:08 2002 Akinori MUSHA * ext/syslog/syslog.c: Merge from rough. Turn Syslog into a module keeping backward compatibility intact. Mon Feb 25 19:35:48 2002 Nobuyoshi Nakada * sample/test.rb (system): test with scripts under the source directory. Mon Feb 25 15:14:01 2002 Yukihiro Matsumoto * eval.c (method_inspect): should not dump core for unbound singleton methods. * object.c (rb_mod_to_s): better description. Mon Feb 25 13:32:13 2002 Nobuyoshi Nakada * lib/shell.rb (Shell::expand_path): relative to @cwd. Mon Feb 25 06:30:11 2002 Koji Arai * hash.c (env_select): should path the assoc list. Sun Feb 24 17:20:22 2002 Akinori MUSHA * ext/digest/*/*.h: Merge from rough. - Avoid namespace pollution. (MD5_* -> rb_Digest_MD5_*, etc.) Sat Feb 23 21:12:13 2002 Yukihiro Matsumoto * process.c (rb_syswait): thread kludge; should be fixed to support native thread. Fri Feb 22 21:20:53 2002 Minero Aoki * lib/net/protocol.rb: set read_timeout dynamically. * lib/net/http.rb: @@newimpl is always true in the main trunk. * lib/net/http.rb: HTTP.port -> default_port * lib/net/http.rb: HTTPResponse.read_response_status -> read_status_line Fri Feb 22 19:56:15 2002 Usaku Nakamura * win32/config.status.in: set LIBRUBY_SO. Fri Feb 22 03:34:38 2002 Yukihiro Matsumoto * bignum.c (get2comp): need to specify to carry or not. * io.c (rb_io_inspect): embed path info. Fri Feb 22 11:30:01 2002 Tanaka Akira * lib/prettyprint.rb: FillGroup implemented. Thu Feb 21 21:40:18 2002 Usaku Nakamura * ext/extmk.rb.in (create_makefile): remove unnecessary -L option from LIBS macro. Thu Feb 21 02:49:12 2002 Koji Arai * pack.c (pack_pack): wrong # comment treatment. * pack.c (pack_unpack): ditto. Wed Feb 20 15:15:03 2002 Nobuyoshi Nakada * intern.h: prototypes; rb_io_addstr(), rb_io_printf(), rb_io_print(), rb_io_puts() * io.c (rb_io_addstr): make extern. * io.c (rb_io_printf): ditto. * io.c (rb_io_print): ditto. * io.c (rb_io_puts): ditto. Wed Feb 20 13:41:35 2002 Usaku Nakamura * io.c (rb_io_close): return Qnil. Wed Feb 20 12:41:59 2002 Yukihiro Matsumoto * hash.c (rb_any_cmp): should handle Qundef in keys. * eval.c (remove_method): should not remove a empty method to implement "undef". * eval.c (rb_eval): should allow singleton class def for true/false/nil. Tue Feb 19 21:43:32 2002 Minero Aoki * lib/net/protocol.rb: rename Protocol.port to default_port. * lib/net/smtp.rb: ditto. * lib/net/pop.rb: ditto. * lib/net/http.rb: ditto. * lib/net/protocol.rb: rename BufferedSocket class to InternetMessageIO. * lib/net/smtp.rb: ditto. * lib/net/pop.rb: ditto. * lib/net/http.rb: ditto. * lib/net/protocol.rb: rename InternetMessageIO#write_pendstr to write_message. * lib/net/smtp.rb: ditto. * lib/net/protocol.rb: new method InternetMessageIO#through_message. * lib/net/smtp.rb: ditto. * lib/net/protocol.rb: rename InternetMessageIO#read_pendstr to read_message_to. * lib/net/pop.rb: ditto. * lib/net/protocol.rb: rename InternetMessageIO#read_pendlist to each_list_item * lib/net/pop.rb: ditto. * lib/net/protocol.rb: Now block size is 1024. * lib/net/smtp.rb: new methods SMTP#esmtp? and #esmtp=. * lib/net/http.rb: Using singleton method syntax instead of singleton class clause, to avoid behavior change of class variables in ruby 1.7. * lib/net/http.rb: HTTPResponse class does not inherit from Net::Response. * lib/net/http.rb: divide HTTP#connecting into {begin,end}_transport. * lib/net/http.rb: unused class Accumulator removed. * lib/net/http.rb: Net::HTTP reads response. not HTTPRequest. * lib/net/http.rb: proxy related class-instance-variables are not initialized correctly. Tue Feb 19 20:20:12 2002 Ed Sinjiashvili * parse.y (str_extend): backslash escape was done wrong. Tue Feb 19 17:10:25 2002 Nobuyoshi Nakada * file.c (path_check_1): do not fail on world writable *parent* directories too. Tue Feb 19 15:51:41 2002 Yukihiro Matsumoto * file.c (path_check_1): do not warn on world writable *parent* directories. * class.c (rb_include_module): should preserve ancestor order in the included class/module. Tue Feb 19 14:45:32 2002 Yukihiro Matsumoto * file.c (path_check_1): should check directory sticky bits. * process.c (security): need not to warn twice. * marshal.c (r_object): complete restoration before calling r_regist(). Tue Feb 19 14:24:36 2002 Yukihiro Matsumoto * parse.y (yylex): operators in the "op" rule should make lex_state EXPR_ARG on EXPR_FNAME and EXPR_DOT. Tue Feb 19 13:38:10 2002 Yukihiro Matsumoto * eval.c (rb_eval_string_wrap): should hide the toplevel local variable bindings by PUSH_SCOPE(). Tue Feb 19 13:21:51 2002 WATANABE Hirofumi * regex.c: fix prototypes of xmalloc(), xcalloc() and xrealloc(). Tue Feb 19 13:16:08 2002 Nobuyoshi Nakada * io.c (rb_io_ungetc): don't fail pushed EOF back. Mon Feb 18 20:48:40 2002 Nobuyoshi Nakada * pack.c (pack_pack): avoid infinite loop at comment. * pack.c (pack_unpack): ditto. Mon Feb 18 14:06:28 2002 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-block-hanging-re): rescue block was too indented. Mon Feb 18 13:56:44 2002 Yukihiro Matsumoto * parse.y (expr_value, arg_value, primary_value): value_expr() check in place. * eval.c (block_pass): "&nil" should clear block given. Mon Feb 18 02:05:56 2002 Wolfgang Jahrling * dir.c (push_braces): remove MAXPATHLEN dependency. * dir.c (dir_s_globd): ditto. * dln.c (init_funcname): ditto. * dln.c (load_1): ditto. * dln.c (dln_load): ditto. * configure.in: add GNU/Hurd switches. Fri Feb 15 17:44:26 2002 Yukihiro Matsumoto * pack.c (pack_pack): allows comment in template strings. * pack.c (pack_unpack): ditto. Sun Feb 17 23:41:37 2002 Nobuyoshi Nakada * mkconfig.rb (Config::expand): expand ${} too. * ext/extmk.rb.in (try_link0): expand command. * ext/extmk.rb.in (try_cpp): ditto. * ext/extmk.rb.in (extmake): default $LIBPATH to $libdir Sun Feb 17 21:39:24 2002 Tetsuya Watanabe * ext/digest/md5/md5init.c (Init_md5): rb_cvar_declare() is replaced by rb_cvar_set(). * ext/digest/rmd160/rmd160init.c (Init_rmd160): ditto. * ext/digest/sha1/sha1init.c (Init_sha1): ditto. * ext/digest/sha2/sha2init.c (Init_sha2): ditto. Sun Feb 17 18:10:09 2002 Nobuyoshi Nakada * class.c (rb_define_class): warn unless superclass is specified explicitly. * class.c (rb_define_class_under): ditto. Thu Feb 16 02:11:08 2002 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-font-lock-keywords): fontify instance/class/global variables start with '_'. Fri Feb 15 14:40:38 2002 Yukihiro Matsumoto * eval.c (rb_eval): replace rb_cvar_declare() by rb_cvar_set(). * eval.c (assign): ditto. * variable.c (rb_cvar_set): 4th argument (warn) added; define new class variable if it's not defined yet. * variable.c (rb_cvar_declare): removed. Fri Feb 15 13:36:58 2002 Yukihiro Matsumoto * bignum.c (rb_big_rshift): should properly convert the negative value to 2's compliment. Thu Feb 14 17:38:35 2002 Nobuyoshi Nakada * parse.y: avoid SEGV at OP_ASIGN to pseudo variable. Thu Feb 14 14:13:16 2002 Yukihiro Matsumoto * struct.c (Init_Struct): should undefine "allocate" for Struct class (it's redefined in the subclasses). Wed Feb 13 17:58:12 2002 Yukihiro Matsumoto * parse.y (stmt): local variable declaration order was changed since 1.6 * parse.y (arg): ditto. * pack.c (pack_pack): add templates 'q' and 'Q'. * pack.c (pack_unpack): ditto. * bignum.c (rb_quad_pack): new utility function. * bignum.c (rb_quad_unpack): ditto. Tue Feb 12 01:21:34 2002 Yukihiro Matsumoto * parse.y (assignable): should emit CVASGN within the method body. Mon Feb 11 06:13:53 2002 Matt Armstrong * dir.c (dir_s_glob): should not warn even if no match found. Mon Feb 11 04:25:54 2002 Yukihiro Matsumoto * eval.c (rb_eval): clean up class variable behavior. * eval.c (assign): ditto. * eval.c (is_defined): ditto. * variable.c (rb_mod_class_variables): need not to call rb_cvar_singleton(). * variable.c (rb_cvar_singleton): removed. Mon Feb 11 00:10:41 2002 Nobuyoshi Nakada * regex.c (re_compile_fastmap): skip begpos. Sun Feb 10 16:52:53 2002 Nobuyoshi Nakada * ruby.c (load_file): avoid SEGV on '#' only input. Fri Feb 8 23:07:23 2002 Yukihiro Matsumoto * eval.c (rb_eval): singleton check should be moved from yycompile to here. * eval.c (is_defined): check should be added here too. Fri Feb 8 05:31:48 2002 Minero Aoki * lib/net/http.rb: HTTP.Proxy should use self for proxy-class's super class. * lib/net/http.rb: initialize HTTP.proxy_port by HTTP.port. Fri Feb 8 01:27:33 2002 Yukihiro Matsumoto * parse.y (yycompile): should inherit "in_single" if eval happened in a singleton method. * eval.c (rb_eval): class variables from singleton methods defined within singleton class statement should work like ones defined by singleton def statements. Thu Feb 7 13:44:08 2002 akira yamada * uri/common.rb (URI::join): new method. * uri/generic.rb (Generic#merge): URI.parse("http://a/")+"b" should return "http://a/b" but it returned "http://a//b". * uri/generic.rb (Generic#check_path): corrected error message, @path -> v Thu Feb 7 00:18:43 2002 Yukihiro Matsumoto * io.c (io_write): flag when buffered write is done. * io.c (fptr_finalize): do not raise error on EBADF if write buffer is empty. Wed Feb 6 17:18:54 2002 Nobuyoshi Nakada * configure.in: keep old config.h unless changed. Wed Feb 6 13:28:53 2002 Amos Gouaux * lib/net/imap.rb: OpenSSL support. * lib/net/imap.rb (setquota): unset quota if the second argument is nil. Wed Feb 6 13:05:11 2002 Yukihiro Matsumoto * io.c (rb_io_readlines): avoid calling GetOpenFile() repeatedly. * io.c (rb_io_each_line): ditto. * io.c (argf_getline): ditto. * process.c: should include to get proper CLK_TCK. Wed Feb 6 02:10:30 2002 Nobuyoshi Nakada * io.c (fptr_finalize): ignore EBADF when f and f2 use same descriptor. Tue Feb 5 16:17:20 2002 Yukihiro Matsumoto * io.c (fptr_finalize): should raise error when fclose fails. * eval.c (method_inspect): proper output format to distinguish methods and singleton methods. Mon Feb 4 22:44:58 2002 Nobuyoshi Nakada * file.c (rb_file_s_expand_path): should terminate. Mon Feb 4 15:38:29 2002 Yukihiro Matsumoto * object.c (rb_class_real): should not follow ICLASS link * variable.c (classname): should follow ICLASS link explicitly. * eval.c (rb_call): ditto. Fri Feb 1 19:10:04 2002 Nobuyoshi Nakada * intern.h: prototypes for new functions; rb_cstr_to_inum(), rb_str_to_inum(), rb_cstr_to_dbl(), rb_str_to_dbl() * bignum.c (rb_cstr_to_inum): changed from rb_cstr2inum(), and added argument badcheck to be consistent with parser. [new] * bignum.c (rb_str_to_inum): ditto. * bignum.c (rb_cstr2inum): wrapper of rb_cstr_to_inum() now. * bignum.c (rb_str2inum): ditto. * object.c (rb_cstr_to_dbl): float number parser. [new] * object.c (rb_str_to_dbl): ditto. * object.c (rb_Float): use rb_cstr_to_dbl() for strict check. * object.c (rb_Integer): use rb_str_to_inum() for strict check. * string.c (rb_str_to_f): use rb_str_to_dbl() with less check. * string.c (rb_str_to_i): use rb_str_to_inum() with less check. * string.c (rb_str_hex): ditto. * string.c (rb_str_oct): ditto. * sprintf.c (rb_f_sprintf): ditto. * time.c (obj2long): ditto. * parse.y (yylex): use rb_cstr_to_inum() for strict check. Fri Feb 1 17:46:39 2002 Nobuyoshi Nakada * regex.c (mbc_startpos): become macro. * regex.c (euc_startpos): added for improvement. * regex.c (sjis_startpos): ditto. * regex.c (utf8_startpos): ditto. Fri Feb 1 00:03:30 2002 Yukihiro Matsumoto * file.c (rb_stat_inspect): print dev, rdev in hexadecimal. Thu Jan 31 20:45:33 2002 Nobuyoshi Nakada * lib/mkmf.rb (dir_config): prior --with flag. * lib/mkmf.rb (arg_config): avoid special variables for font-lock-mode. Thu Jan 31 13:22:36 2002 Tanaka Akira * lib/pp.rb (File::Stat#pretty_print): print rdev_major and rdev_minor. Wed Jan 30 15:58:04 2002 K.Kosako * regex.c (re_adjust_startpos): fix for SJIS and UTF-8. * regex.c (mbc_startpos): ditto. Wed Jan 30 13:37:05 2002 Yukihiro Matsumoto * re.c (rb_reg_search): should set regs.allocated. Wed Jan 30 02:25:38 2002 Nobuyoshi Nakada * regex.c (re_adjust_startpos): search start of multibyte backward. * regex.c (mbc_startpos): ditto. Tue Jan 29 17:59:20 2002 Tanaka Akira * file.c: `major' and `minor' macro needs sys/mkdev.h on SunOS 5.x. * configure.in: add check for `sys/mkdev.h'. * lib/pp.rb: don't print a mode File::Stat as decimal number. Mon Jan 28 19:16:58 2002 Nobuyoshi Nakada * array.c (rb_ary_fill): shouldn't yield unless block given. Mon Jan 28 18:33:18 2002 Nobuyoshi Nakada * parse.y (yylex): strict check for numbers. Mon Jan 28 18:01:01 2002 Yukihiro Matsumoto * file.c (rb_stat_rdev_major): added. [new] * file.c (rb_stat_rdev_minor): added. [new] * file.c (rb_stat_inspect): print mode in octal. Mon Jan 28 13:29:41 2002 K.Kosako * eval.c (is_defined): defined?(Foo::Baz) should check constants only, no methods. * eval.c (is_defined): should not dump core on defined?(a::b) where a is not a class nor a module. Mon Jan 28 02:50:12 2002 Yukihiro Matsumoto * object.c (Init_Object): remove dup and clone from TrueClass, FalseClass, and NilClass. * array.c (rb_ary_fill): Array#fill takes block to get the value to fill. Sat Jan 26 20:05:18 2002 Yukihiro Matsumoto * string.c (rb_str_to_i): to_i(0) auto-detects base radix. * array.c (rb_ary_initialize): fill by the block evaluation value if block is given. Fri Jan 25 17:48:43 2002 WATANABE Hirofumi * configure.in (solaris): add '-shared' only for GNU ld. Fri Jan 25 17:16:23 2002 Yukihiro Matsumoto * class.c (rb_include_module): detect cyclic module inclusion. Fri Jan 25 02:17:56 2002 Yukihiro Matsumoto * eval.c (rb_thread_cleanup): need not to free thread stacks at process termination. * array.c (rb_ary_fetch): use the block to get the default value if the block is given. * eval.c (rb_thread_schedule): should check time only if BOTH WAIT_SELECT and WAIT_TIME. Thu Jan 24 11:49:05 2002 Yukihiro Matsumoto * eval.c (umethod_bind): should update rklass field. * hash.c (rb_hash_update): if a block is given, yields [key, value1, value2] to the block to resolve conflict. Thu Jan 24 05:42:01 2002 Koji Arai * string.c (rb_str_split_m): no need to consider KANJI characters, if the length of separator is 1 (byte). Wed Jan 23 16:07:31 2002 Yukihiro Matsumoto * array.c (Init_Array): remove Array#filter. Wed Jan 23 13:27:44 2002 Nobuyoshi Nakada * eval.c (rb_yield_0): restore source file/line after yield. Wed Jan 23 02:00:14 2002 Yukihiro Matsumoto * object.c (rb_mod_initialize): should accept zero argument. * object.c (rb_mod_cmp): should raise ArgumentError if inheritance/inclusion relation between two classes/modules is not defined. [new] Tue Jan 22 17:45:23 2002 Yukihiro Matsumoto * io.c (rb_io_fsync): new method. [new] Mon Jan 21 22:57:18 2002 Nobuyoshi Nakada * signal.c (ruby_signal): must define sighandler_t for every occasion. Mon Jan 21 08:25:30 2002 Yukihiro Matsumoto * eval.c (ruby_stop): should not trace error handler. * signal.c (install_sighandler): do not install sighandler unless the old value is SIG_DFL. * io.c (io_write): should not raise exception on O_NONBLOCK io. * dir.c (dir_set_pos): seek should return dir, pos= should not. Sat Jan 19 02:31:45 2002 Yukihiro Matsumoto * eval.c (rb_eval): need not to clear method cache for NODE_CLASS, NODE_SCLASS. * gc.c (obj_free): need not to clear method cache on class/module finalization. Fri Jan 18 23:38:03 2002 Yukihiro Matsumoto * array.c (rb_ary_fetch): index out of range raises exception unless optional second argument is specified. Fri Jan 18 17:32:09 2002 Yukihiro Matsumoto * io.c (rb_io_s_new): block check moved from initialize to this method. * io.c (rb_io_s_open): open should call initialize too. IO#for_fd also calls initialize. [new] Fri Jan 18 10:26:33 2002 Yukihiro Matsumoto * error.c (rb_sys_fail): replace INT2FIX() by INT2NUM() since errno value may not fit in Fixnum size on Hurd. * error.c (set_syserr): ditto. Fri Jan 18 10:12:00 2002 Usaku Nakamura * ext/socket/socket.c (tcp_svr_s_open): fix typo. Fri Jan 18 02:27:48 2002 Yukihiro Matsumoto * dir.c (dir_s_glob): returns nil if block given. * io.c (rb_io_each_byte): should return self. * io.c (rb_io_close_m): close check added. * dir.c (dir_seek): should return pos. Fri Jan 18 01:21:53 2002 Yukihiro Matsumoto * parse.y (fixpos): orig may be (NODE*)1, which should not be dereferenced. Thu Jan 17 16:21:42 2002 Yukihiro Matsumoto * eval.c (block_pass): allow "retry" from within argument passed block. [new] * eval.c (localjump_error): should preserve exit status in the exception object. [new] * eval.c (proc_invoke): should raise exception for "break" if it's yielding, not calling. [new] * eval.c (block_pass): should NOT raise exception for "break". [new] * eval.c (block_pass): should allow block argument relay even in the tainted mode. Thu Jan 17 04:51:48 2002 Yukihiro Matsumoto * ext/socket/socket.c: support subclassing by proper "initialize" calling convention. [new] Wed Jan 16 18:25:08 2002 Yukihiro Matsumoto * st.c: primes should be primes. Wed Jan 16 12:29:14 2002 Tanaka Akira * lib/timeout.rb (timeout): new optional argument to specify an exception class. * lib/resolv.rb: use Resolv::ResolvTimeout for internal timeout to avoid problem with timeout of application. Wed Jan 16 11:12:30 2002 Nobuyoshi Nakada * object.c (rb_Float): remove underscores between digits. * bignum.c (rb_cstr2inum): reject prefix followed by spaces only. * class.c (rb_class_inherited): should use Object when no super class. Tue Jan 15 01:11:44 2002 Yukihiro Matsumoto * eval.c (is_defined): method defined? check should honor protected too. Mon Jan 14 13:06:02 2002 Yukihiro Matsumoto * eval.c (block_pass): should not pass tainted block, if $SAFE > 0. Sun Jan 13 09:31:41 2002 Koji Arai * variable.c (rb_mod_remove_cvar): should pass the char*. Fri Jan 11 05:06:25 2002 Nobuyoshi Nakada * class.c (rb_make_metaclass): [new] * class.c (rb_define_class_id): use rb_make_metaclass(), don't call Class#inherited hook. * class.c (rb_class_inherited): [new] * class.c (rb_define_class): call Class#inherited hook here. * class.c (rb_define_class_under): ditto after class path is set. * class.c (rb_singleton_class): use rb_make_metaclass(). * eval.c (rb_eval): same as rb_define_class_under(). * intern.h: prototypes of rb_make_metaclass() and rb_class_inherited(). * object.c (rb_class_s_new): use rb_make_metaclass() and rb_class_inherited(). * object.c (Init_Object): use rb_make_metaclass(). * struct.c (make_struct): use rb_class_inherited(). Thu Jan 10 19:15:15 2002 Nobuyoshi Nakada * eval.c (rb_add_method): should clear cache by id always. * eval.c (rb_disable_super): no longer need to clear cache before rb_add_method(). * eval.c (rb_export_method): ditto. * eval.c (rb_attr): ditto. * eval.c (rb_undef): ditto. * eval.c (rb_eval): ditto. * eval.c (rb_mod_modfunc): ditto. * eval.c (rb_mod_define_method): ditto. Thu Jan 10 11:42:47 2002 Usaku Nakamura * win32/resource.rb: Modify copyright in resource script. Thu Jan 10 07:15:44 2002 takuma ozawa * re.c (match_select): should propagate taintness. Thu Jan 10 00:54:57 2002 Yukihiro Matsumoto * hash.c (rb_hash_set_default): Hash#default= should return the new value. Wed Jan 9 20:21:09 2002 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-calculate-indent): indentation after comment at beginning of buffer failed. * misc/ruby-mode.el (font-lock-defaults): unless XEmacs, set font-lock variables in ruby-mode-hook. Tue Jan 8 15:56:20 2002 Yukihiro Matsumoto * string.c (rb_str_to_i): accepts optional base argument. [new] * numeric.c (rb_fix2str): should not handle negative fixnum values int32 via calling sprintf() directly. Tue Jan 8 15:54:02 2002 Nobuyoshi Nakada * eval.c (rb_add_method): clear replaced method from the cache. Mon Jan 7 12:38:47 2002 Tanaka Akira * lib/time.rb (Time#xmlschema): new optional argument fractional_seconds to specify a number of digits of fractional part of the time. Sat Jan 5 13:18:11 2002 Nobuyoshi Nakada * range.c (range_member): beginning check was wrong. [ruby-talk:30252] Sat Jan 5 03:07:34 2002 Yukihiro Matsumoto * string.c (rb_str_new2): NULL pointer check added. Sat Jan 5 00:19:12 2002 Nobuyoshi Nakada * parse.y (yycompile): strdup()'ed twice. Fri Jan 4 18:29:10 2002 Michal Rokos * class.c (rb_define_module_under): should locate predefined module using rb_const_defined_at(). Fri Jan 4 17:23:49 2002 Nobuyoshi Nakada * misc/ruby-mode.el (ruby-forward-string): forward a string. [new] * misc/ruby-mode.el (ruby-parse-region): handle nested parentheses in a string and terminators in #{}. * misc/ruby-mode.el (ruby-calculate-indent): ditto. Wed Jan 2 23:34:25 2002 WATANABE Hirofumi * lib/mkmf.rb (create_makefile): add -I. to CPPFLAGS. * lib/mkmf.rb (create_makefile): srcdir support(.def and depend file). Wed Jan 2 11:51:56 2002 Yukihiro Matsumoto * process.c (rb_f_system): abandon vfork. * io.c (pipe_open): ditto. Tue Jan 1 02:16:48 2002 WATANABE Hirofumi * ext/curses/extconf.rb: add dir_config. * Makefile.in (fake.rb): set RUBY_VERSION. Mon Dec 31 14:20:46 2001 Nobuyoshi Nakada * parse.y (yycompile): always store copy of filename. * parse.y (rb_compile_file): no longer need to strdup() here. Mon Dec 31 05:26:40 2001 Ferris McCormick * defines.h: sparc linux needs different FLUSH_REGISTER_WINDOWS Mon Dec 31 04:27:28 2001 Minero Aoki * lib/net/protocol.rb: Protocol#start returns the return value of block. * lib/net/protocol.rb: set timeout limit by default. * lib/net/protocol.rb: new methods WriteAdapter#write, puts, print, printf. * lib/net/http.rb: rename HTTP#get2 to request_get, post2 to request_post ... * lib/net/smtp.rb: should not resolve HELO domain automatically. Sun Dec 30 00:59:16 2001 WATANABE Hirofumi * ext/extmk.rb.in, lib/mkmf.rb (have_library): accept -lm unconditionally on mswin32/mingw32. Sat Dec 29 01:55:42 2001 Yukihiro Matsumoto * regex.c (re_search): abandon stclass optimization. Fri Dec 28 14:39:05 2001 Nobuyoshi Nakada * array.c (rb_cmpint): fixed typo. Thu Dec 27 18:43:04 2001 Nobuyoshi Nakada * bignum.c (rb_cstr2inum): deny "0_". Thu Dec 27 01:54:02 2001 Nobuyoshi Nakada * bignum.c (rb_cstr2inum): allow "0\n" and so on. Wed Dec 26 19:24:21 2001 Yukihiro Matsumoto * error.c (rb_invalid_str): utility function to show inspect()'ed string. * bignum.c (rb_cstr2inum): prints invalid strings in inspect()'ed format. * object.c (rb_Float): ditto. Wed Dec 26 02:41:29 2001 Yukihiro Matsumoto * object.c (rb_convert_type): no longer use rb_rescue(). Tue Dec 25 18:32:16 2001 K.Kosako * re.c (rb_reg_search): initialize taint status of match object. Tue Dec 25 02:37:49 2001 Tanaka Akira * lib/pp.rb, lib/prettyprint.rb: new files. Tue Dec 25 02:11:17 2001 Yukihiro Matsumoto * object.c (rb_convert_type): check method response check before invoking rb_rescue(). * object.c (rb_check_convert_type): ditto. Mon Dec 24 02:37:40 2001 Le Wang * misc/ruby-mode.el (ruby-font-lock-syntactic-keywords): fix font-lock problem [ruby-talk:29296]. Sat Dec 22 22:52:14 2001 Yukihiro Matsumoto * time.c (time_timeval): wrong cast to time_t. * time.c (time_plus): ditto. Fri Dec 21 20:33:34 2001 K.Kosako * parse.y (str_extend): make up "#$;" handling. Fri Dec 21 16:18:17 2001 Nobuyoshi Nakada * dln.h, ruby.h, util.h: enable prototypes in C++. Fri Dec 21 15:12:41 2001 Yukihiro Matsumoto * time.c (time_plus): result should not be negative unless NEGATIVE_TIME_T is defined. * time.c (time_new_internal): should check tv_sec overflow too. * time.c (time_timeval): should check time_t range when time is initialized from float. * time.c (time_plus): uses modf(3). Fri Dec 21 03:15:52 2001 Nobuyoshi Nakada * eval.c (rb_mod_define_method): must not convert Method to Proc. Fri Dec 21 01:17:57 2001 Nobuyoshi Nakada * lib/mkmf.rb (with_destdir): new. * lib/mkmf.rb: prefix target directories with $(DESTDIR) all. * lib/mkmf.rb: no need to mkdir $(libdir) Thu Dec 20 14:08:20 2001 Minero Aoki * lib/net/protocol.rb: rename Net::Socket to Net::BufferedSocket Thu Dec 20 13:51:52 2001 K.Kosako * variable.c (rb_cvar_set): add frozen class/module check. * variable.c (rb_cvar_declare): add frozen class/module check. Thu Dec 20 01:01:50 2001 takuma ozawa * re.c (match_to_a): should propagate taint. * re.c (rb_reg_s_quote): ditto. Wed Dec 19 16:58:29 2001 Shugo Maeda * ext/readline/readline.c: new methods Readline::basic_word_break_characters, Readline::basic_word_break_characters=, Readline::completer_word_break_characters, Readline::completer_word_break_characters=, Readline::basic_quote_characters, Readline::basic_quote_characters=, Readline::completer_quote_characters, Readline::completer_quote_characters=, Readline::filename_quote_characters, Readline::filename_quote_characters=. Wed Dec 19 14:05:00 2001 Yukihiro Matsumoto * eval.c (rb_mod_define_method): define_method should follow default method visibility. * eval.c (rb_attr): should warn if the default method visibility is "module_function" (can be error). * eval.c (rb_mod_define_method): should define class/module method also if the visibility is "module_function". * eval.c (rb_mod_define_method): should call hook method "method_added", and "singleton_method_added". Wed Dec 19 11:42:13 2001 K.Kosako * string.c: use RESIZE_CAPA for capacity change. Wed Dec 19 03:08:40 2001 Tanaka Akira * lib/time.rb: date.rb is not required anymore. * lib/resolv.rb: fix document. refine IPv6 regex. Tue Dec 18 23:24:53 2001 Yukihiro Matsumoto * ext/socket/socket.c (Init_socket): add listen method to TCPServer and UNIXServer. Tue Dec 18 17:54:53 2001 WATANABE Hirofumi * sample/test.rb: Hash#indexes -> Hash#select. Tue Dec 18 01:02:13 2001 Yukihiro Matsumoto * eval.c (rb_thread_schedule): should not select a thread which is not yet initialized. Mon Dec 17 18:53:49 2001 K.Kosako * string.c (rb_str_replace): swap arguments of OBJ_INFECT. Mon Dec 17 16:52:20 2001 Nobuyoshi Nakada * intern.h: add prototypes. rb_gc_enable(), rb_gc_disable(), rb_gc_start(), rb_str_new5() rb_str_buf_append(), rb_str_buf_cat(), rb_str_buf_cat2(), rb_str_dup_frozen() * ruby.h: added declaration. rb_defout, rb_stdin, rb_stdout, rb_stderr, ruby_errinfo * rubyio.h: changed double include guard macro to RUBYIO_H. * array.c (inspect_call): make static. * eval.c (dvar_asgn): ditto. * io.c (rb_io_close_read): ditto. * lex.c (rb_reserved_word): ditto. * ruby.c: (req_list_head, req_list_last): ditto. * ruby.c (require_libraries): ditto. Mon Dec 17 15:41:24 2001 Yukihiro Matsumoto * time.c (time_plus): wrong boundary check. * time.c (time_minus): ditto. Mon Dec 17 15:19:32 2001 Tanaka Akira * time.c: new method `gmtoff', `gmt_offset' and `utc_offset'. (time_utc_offset): new function. (Init_Time): bind above methods to `time_utc_offset'. * time.c: 64bit time_t support. (time_s_at): use NUM2LONG instead of NUM2INT for tv_sec. (time_arg): initialize tm_isdst correctly. use long to initialize tm_year. (search_time_t): renamed from `make_time_t'. (make_time_t): call `timegm' and `mktime' instead of `search_time_t' if available. (time_to_i): use LONG2NUM instead of INT2NUM. (time_localtime): check localtime failure. (time_gmtime): check gmtime failure. (time_year): use LONG2NUM instead of INT2FIX. (time_to_a): use long for tm_year. (time_dump): check tm_year which is not representable with 17bit. (time_load): initialize tm_isdst. * configure.in: check existence of `mktime' and `timegm'. check existence of tm_gmtoff field of struct tm. fix negative time_t for 64bit time_t. * missing/strftime.c: fix overflow by tm_year + 1900. * lib/time.rb: use Time#utc_offset. Mon Dec 17 00:02:04 2001 Guy Decoux * variable.c (find_class_path): should initialize iv_tbl if it's NULL. Fri Dec 14 04:23:36 2001 Minero Aoki * lib/net/pop.rb: new method Net::POP3.APOP * lib/net/http.rb: set default Content-Type to x-www-form-urlencoded (causes warning) * lib/net/protocol.rb: remove Net::NetPrivate module. * lib/net/smtp.rb: ditto. * lib/net/pop.rb: ditto. * lib/net/http.rb: ditto. Fri Dec 14 00:16:06 2001 Yukihiro Matsumoto * class.c (rb_define_class): should return the existing class if the class is already defined and its superclass is identical to the specified superclass. * class.c (rb_define_class_under): ditto. * class.c (rb_define_module): should return the existing module if the module is already defined. Thu Dec 13 09:52:59 2001 Yukihiro Matsumoto * time.c (time_new_internal): avoid loop to calculate negative div, mod. * time.c (time_cmp): should handle Bignums. Tue Dec 11 17:39:16 2001 K.Kosako * array.c (rb_ary_pop): should ELTS_SHARED flag check before REALLOC. Tue Dec 11 12:45:28 2001 Yukihiro Matsumoto * string.c (rb_str_match_m): should convert an argument into regexp if it's a string. Tue Dec 11 03:40:23 2001 Yukihiro Matsumoto * array.c (rb_ary_select): Array#select(n,m,...) now works like Array#indexes(n,m,..). [new, experimental] * hash.c (rb_hash_select): ditto. * hash.c (env_select): ditto. * re.c (match_select): ditto. * struct.c (rb_struct_select): ditto. Tue Dec 11 03:17:19 2001 Nobuyoshi Nakada * object.c (rb_class_real): follow included modules. Mon Dec 10 23:37:51 2001 Usaku Nakamura * util.h: change prototype of ruby_qsort() to accord with its definition. Mon Dec 10 20:30:01 2001 K.Kosako * gc.c (STR_ASSOC): use FL_USER3 instead of FL_USER2. Mon Dec 10 17:40:02 2001 K.Kosako * parse.y (str_extend): make up pushback call. Mon Dec 10 02:09:28 2001 Yukihiro Matsumoto * array.c (rb_ary_modify): should copy the internal buffer if the modifying buffer is shared. * array.c (ary_make_shared): make an internal buffer of an array to be shared. * array.c (rb_ary_shift): avoid sliding an internal buffer by using shared buffer. * array.c (rb_ary_subseq): avoid copying the buffer. Mon Dec 10 01:06:56 2001 Yukihiro Matsumoto * parse.y (gettable): should freeze __FILE__ string. Sun Dec 9 18:06:26 2001 Minero Aoki * lib/net/protocol.rb: calls on_connect before conn_command Sat Dec 8 23:27:44 2001 Yukihiro Matsumoto * io.c (rb_io_puts): old behavior restored. rationale: a) if you want to call to_s for arrays, you can just call print a, "\n". b) to_s wastes memory if array (and sum of its contents) is huge. c) now any object that has to_ary is treated as an array, using rb_check_convert_type(). Sat Dec 8 22:40:38 2001 Yukihiro Matsumoto * hash.c (rb_hash_initialize): now accepts a block to calculate the default value. [new] * hash.c (rb_hash_aref): call "default" method to get the value corresponding to the non existing key. * hash.c (rb_hash_default): get the default value based on the block given to 'new'. Now it takes an optional "key" argument. "default" became the method to get the value for non existing key. Users may override "default" method to change the hash behavior. * hash.c (rb_hash_set_default): clear the flag if a block is given to 'new' Sat Dec 8 02:29:54 2001 Yukihiro Matsumoto * object.c (Init_Object): undef Data.allocate, left Data.new. Fri Dec 7 19:12:14 2001 Minero Aoki * lib/net/smtp.rb: SMTP.new requires at least one arg. * lib/net/pop.rb: POP.new requires at least one arg. * lib/net/pop.rb: uses "raise *Error.new" instead of simple raise. * lib/net/http.rb: HTTP.new requires at least one arg. * lib/net/http.rb: changes implicit start algorithm. Fri Dec 7 15:49:39 2001 Usaku Nakamura * ext/extmk.rb.in: ignore adding -Wl,-R to DLDFLAGS when the directory is $topdir. Fri Dec 7 13:58:58 2001 Yukihiro Matsumoto * ext/curses/curses.c (window_scrollok): use RTEST(). * ext/curses/curses.c (window_idlok): ditto. * ext/curses/curses.c (window_keypad): ditto. * ext/curses/curses.c (window_idlok): idlok() may return void on some platforms; so don't use return value. * ext/curses/curses.c (window_scrollok): ditto for consistency. * ext/curses/curses.c: replace FIX2INT() by typechecking NUM2INT(). Fri Dec 7 09:51:00 2001 Yukihiro Matsumoto * parse.y (str_extend): should not process immature #$x and #@x interpolation, e.g #@#@ etc. Fri Dec 7 03:21:18 2001 Yukihiro Matsumoto * enum.c (enum_sort_by): sort_by does not have to be stable always. * enum.c (enum_sort_by): call qsort directly to gain performance. Thu Dec 6 18:52:28 2001 Usaku Nakamura * ext/extmk.rb.in: add -Wl,-R flags to DLDFLAGS on netbsdelf. * lib/mkmf.rb: ditto. Thu Dec 6 09:15:14 2001 Yukihiro Matsumoto * util.c (ruby_qsort): ruby_qsort(qs6) is now native thread safe. * error.c (rb_sys_fail): it must be a bug if it's called when errno == 0. Wed Dec 5 23:36:56 2001 Yukihiro Matsumoto * regex.c (WC2MBC1ST): should not pass through > 0x80 number in UTF-8. Wed Dec 5 20:05:18 2001 Florian Frank * ext/socket/socket.c (bsock_send): should raise EWOULDBLOCK exception. * ext/socket/socket.c (s_recvfrom): ditto. * ext/socket/socket.c (s_accept): ditto. * ext/socket/socket.c (udp_send): ditto. Tue Dec 4 17:43:10 2001 Yukihiro Matsumoto * ruby.h (DUPSETUP): new SETUP macro for duplication. * time.c (time_dup): implement in Time class using DUPSETUP. * time.c (time_getlocaltime): new method; probably requires better name than getlocaltime. [new,experimental] * time.c (time_getgmtime): ditto. * array.c (rb_ary_dup): uses DUPSETUP. * string.c (rb_str_dup): uses DUPSETUP. now properly copies instance variables too. Tue Dec 4 03:49:06 2001 Yukihiro Matsumoto * io.c (io_fread): EAGAIN/EWOULDBLOCK should not terminate and throw away the input. * time.c (time_new_internal): underflow adjustment must not use negative div/mod. * time.c (time_cmp): should consider tv_usec on non Fixnum number comparison. Sun Dec 9 23:00:54 2001 Keiju Ishitsuka * matrix.rb: Vector#* bug. reported from Massimiliano Mirra . Sun Dec 9 22:15:59 2001 Nobuyoshi Nakada * enum.c (enum_sort_by): should replace with last elements. Mon Dec 3 16:06:57 2001 WATANABE Hirofumi * ext/socket/extconf.rb: remove -L/usr/local/lib. * configure.in: add -Wl,-export-dynamic on NetBSD. Mon Dec 3 16:04:16 2001 Usaku Nakamura * configure.in: not use X11BASE, since it's not always set. Mon Dec 3 13:53:49 2001 Tanaka Akira * time.c (rb_strftime): buffer length condition was wrong. * time.c (time_strftime): should backup buf to the original buffer. Mon Dec 3 09:59:08 2001 Yukihiro Matsumoto * time.c (time_plus): must detect result overflow. * time.c (time_minus): ditto. * time.c (time_new_internal): round usec overflow and underflow here. * time.c (time_plus): move operand overflow/underflow check to time_new_internal(). * time.c (time_minus): ditto. * time.c (time_cmp): should consider tv_usec too. Mon Dec 3 03:32:22 2001 Usaku Nakamura * configure.in: apply patch from NetBSD's pkgsrc (patch-aa). Sun Dec 2 22:01:52 2001 WATANABE Hirofumi * configure.in: use GCC, not without_gcc. remove without_gcc. * ext/curses/extconf.rb: check for curses.h. * ext/dbm/extconf.rb: check if $CFLAGS includes DBM_HDR. Sat Dec 1 12:13:20 2001 Yukihiro Matsumoto * time.c (time_gmtime): time_modify() should be called even if tm struct is not calculated yet. Fri Nov 30 17:02:55 2001 WATANABE Hirofumi * configure.in: set target_cpu to i386 on cygwin and mingw32. * configure.in: default --enable-shared to yes on cygwin and mingw32. Fri Nov 30 00:25:28 2001 Usaku Nakamura * README.EXT: Appendix B is duplicated. * README.EXT.ja: ditto. Thu Nov 29 00:28:07 2001 Yukihiro Matsumoto * string.c (rb_str_equal): object with to_str must be treated as a string. Wed Nov 28 18:46:28 2001 Ville Mattila * eval.c (rb_thread_select): should subtract timeofday() from limit, not reverse. Wed Nov 28 16:03:28 2001 K.Kosako * util.c (scan_hex): x is not a hexadecimal digit. Wed Nov 28 13:38:04 2001 Yukihiro Matsumoto * eval.c (rb_thread_schedule): should treat the case that select(2) returns 0, if a thread is under both WAIT_SELECT and WAIT_TIME. Jakub Travnik actually fixed this bug. Tue Nov 27 02:15:25 2001 Yukihiro Matsumoto * marshal.c (w_float): must distinguish -0.0 from 0.0. Mon Nov 26 20:57:24 2001 Akinori MUSHA * ext/Setup*, ext/syslog/*: import the "syslog" module from the rough ruby project. Mon Nov 26 16:14:42 2001 K.Kosako * gc.c (gc_mark_all): tweak mark order for little bit better scan. * gc.c (rb_gc_mark): ditto. * gc.c (rb_gc): ditto. Mon Nov 26 16:54:59 2001 Usaku Nakamura * win32/win32.c (mypopen): fixed that mypclose() didn't really close pipe. * win32/win32.c (CreateChild): set STARTF_USESTDHANDLES flag only when some handles are passed. Mon Nov 26 16:31:28 2001 Yukihiro Matsumoto * enum.c (sort_by_i): slight performance boost. Sun Nov 25 21:02:18 2001 Usaku Nakamura * parse.y (str_extend): change types of second and third arguments from char to int. Thu Nov 22 20:15:28 2001 TAMURA Takashi * gc.c (gc_mark_rest): should call gc_mark_children(), not gc_mark(). * gc.c (rb_gc_mark): may cause infinite loop. Thu Nov 22 00:28:13 2001 Yukihiro Matsumoto * parse.y (str_extend): should check nesting parentheses in #{}. Wed Nov 21 12:22:52 2001 Shugo Maeda * lib/cgi.rb: CGI#header: do not set Apache.request.status for Location: if Apache.request.status is already set. Wed Nov 21 02:24:18 2001 Yukihiro Matsumoto * process.c (pst_wstopsig): returns nil unless WIFSTOPPED() is non-zero. * process.c (pst_wtermsig): returns nil unless WIFSIGNALED() is non-zero. * process.c (pst_wexitstatus): returns nil unless WIFEXITED() is non-zero. Wed Nov 21 00:17:54 2001 Ville Mattila * eval.c (rb_thread_select): tv_sec and tv_usec should not be negative. * signal.c (posix_signal): do not set SA_RESTART for SIGVTALRM. Tue Nov 20 21:09:22 2001 Guy Decoux * parse.y (call_args2): block_arg may follow the first argument in call_args2. Tue Nov 20 02:01:15 2001 Yukihiro Matsumoto * eval.c (stack_check): should avoid stack length check during raising SystemStackError exception. Tue Nov 20 01:07:13 2001 Yukihiro Matsumoto * parse.y (str_extend): should not terminate string interpolation with newlines in here-docs and newline terminated strings. Mon Nov 19 17:58:49 2001 Yukihiro Matsumoto * eval.c (rb_mod_modfunc): should follow NODE_ZSUPER link; based on Guy Decoux's patch in [ruby-talk:25478]. Mon Nov 19 16:09:33 2001 Tanaka Akira * string.c (rb_str_succ): there was buffer overrun. Mon Nov 19 14:14:58 2001 Yukihiro Matsumoto * parse.y (str_extend): term can be any character. Mon Nov 19 04:58:42 2001 Wakou Aoyama * lib/cgi.rb (header): support for Apache. thanks to Shugo Maeda . Sun Nov 18 19:37:55 2001 Nobuyoshi Nakada * parse.y: needless conditionals. * parse.y (parse_regx): parse error at unterminated regex /#{. (ruby-bugs-ja:PR#142) Sat Nov 17 12:37:39 2001 Yukihiro Matsumoto * pack.c (pack_unpack): should give length to utf8_to_uv(). * pack.c (utf8_to_uv): add length check. Sat Nov 17 01:41:52 2001 Yukihiro Matsumoto * massages: replace "wrong #" by "wrong number". * marshal.c (w_float): output Infinity and NaN explicitly. * marshal.c (r_object): support new explicit float format. * eval.c (rb_thread_wait_for): select may cause ERESTART on Solaris. * eval.c (rb_thread_select): ditto. Thu Nov 15 15:29:39 2001 Nobuyoshi Nakada * array.c (rb_ary_join): non-nil separator must be converted to String. and separators' total length was wrong. Thu Nov 15 03:37:17 2001 Usaku Nakamura * hash.c (ruby_setenv): remove USE_WIN32_RTL_ENV block since it's obsoleted. * win32/win32.c, win32/win32.h: sort out #if 0 - #endif or others. Thu Nov 15 00:07:12 2001 Yukihiro Matsumoto * array.c (rb_ary_to_s): if rb_output_fs is nil, insert newlines between array elements (use rb_default_rs as newline literal) [experimental]. Wed Nov 14 15:16:23 2001 K.Kosako * gc.c (init_mark_stack): no need to clear mark_stack. * gc.c (gc_mark_all): need to handle finalizer mark. * gc.c (gc_mark_rest): use MEMCPY instead of memcpy. * gc.c (rb_gc_mark): earlier const check to avoid pusing special constants into mark stack. Wed Nov 14 01:12:07 2001 Usaku Nakamura * win32/win32.c (waitpid): fix wait count. * win32/win32.c (poll_child_status): rename from wait_child(). Wed Nov 14 01:33:49 2001 Yukihiro Matsumoto * numeric.c (fix_to_s): 'to_s' now takes optional argument to specify radix. [new] * bignum.c (rb_big_to_s): ditto. [new] Tue Nov 13 19:50:30 2001 WATANABE Hirofumi * configure.in: do not override CC if set. Tue Nov 13 16:49:16 2001 Usaku Nakamura * win32/win32.c (mypopen): return error status instead of calling rb_sys_fail(). * win32/win32.c (do_spawn): ditto. Tue Nov 13 14:39:11 2001 WATANABE Tetsuya * signal.c (sighandle): should not re-register sighandler if POSIX_SIGNAL is defined. Tue Nov 13 12:55:59 2001 Usaku Nakamura * win32/win32.c (do_spawn): use CreateChild() instead of calling CreateProcess() directly. Original patches comes from Patrick Cheng. * win32/win32.c (mypopen): ditto. * win32/win32.c (mypclose): use rb_syswait() instead of waiting in this function. * win32/win32.c (waitpid): use wait_child() instead of _cwait(). * win32/win32.c (CreateChild): added. [new] * win32/win32.c (wait_child): added. [new] * win32/win32.c (FindFirstChildSlot): added. [new] * win32/win32.c (FindChildSlot): added. [new] * win32/win32.c (FindPipedChildSlot): added. [new] * win32/win32.c (CloseChildHandle): added. [new] * win32/win32.c (FindFreeChildSlot): added. [new] Tue Nov 13 12:38:12 2001 Usaku Nakamura * hash.c (envix): use GET_ENVIRON and FREE_ENVIRON to get environment variables list. * hash.c (env_keys): ditto. * hash.c (env_each_key): ditto. * hash.c (env_values): ditto. * hash.c (env_keys): ditto. * hash.c (env_each_value): ditto. * hash.c (env_each): ditto. * hash.c (env_inspect): ditto. * hash.c (env_to_a): ditto. * hash.c (env_size): ditto. * hash.c (env_empty_p): ditto. * hash.c (env_has_value): ditto. * hash.c (env_index): ditto. * hash.c (env_to_hash): ditto. * win32/win32.c (win32_getenv): use static buffer. * win32/win32.c, win32/win32.h (win32_get_environ): get environment variables list. [new] * win32/win32.c, win32/win32.h (win32_free_environ): free environment variables list. [new] Mon Nov 12 16:48:48 2001 Yukihiro Matsumoto * eval.c (error_print): errat array may be empty. Mon Nov 12 01:30:37 2001 Yukihiro Matsumoto * eval.c (rb_eval_cmd): should not upgrade safe level unless explicitly specified by argument newly added. * signal.c (sig_trap): should not allow tainted trap closure. * variable.c (rb_f_trace_var): should not allow trace_var on safe level higher than 3. * variable.c (rb_f_trace_var): should not allow tainted trace closure. Sun Nov 11 00:12:23 2001 TAMURA Takashi * gc.c: do not use static stack until system stack overflows. Sat Nov 10 03:57:09 2001 Yukihiro Matsumoto * eval.c (eval): should call Exception#exception instead of calling rb_exc_new3() directly. * error.c (exc_exception): set "mesg" directly to the clone. it might be better to set mesg via some method for flexibility. Sat Nov 10 00:14:24 2001 Yukihiro Matsumoto * variable.c (cvar_override_check): should print original module name, if 'a' is T_ICLASS. * parse.y (yylex): float '1_.0' should not be allowed. * variable.c (var_getter): should care about var as Qfalse (ruby-bugs#PR199). Fri Nov 9 13:50:06 2001 Usaku Nakamura * win32/config.status.in: make CFLAGS same as Makefile's one. Thu Nov 8 20:20:37 2001 Nobuyoshi Nakada * eval.c (rb_trap_eval): avoid annoying warning with signal. [ruby-talk:23225] * eval.c (rb_call0): adjust caller source file/line while evaluating optional arguments. Thu Nov 8 18:41:58 2001 Yukihiro Matsumoto * array.c (cmpint): <=> or block for {min,max} may return bignum. * array.c (sort_1): use rb_compint. * array.c (sort_2): ditto. * enum.c (min_ii): ditto. * enum.c (min_ii): ditto. * enum.c (max_i): ditto. * enum.c (max_ii): ditto. Thu Nov 8 18:21:02 2001 Yukihiro Matsumoto * file.c (path_check_1): forgot to initialize 'p'. Thu Nov 8 14:52:15 2001 Tanaka Akira * mkconfig.rb: use String#dump to generate Ruby string literal. Thu Nov 8 15:46:54 2001 Yukihiro Matsumoto * range.c (range_eql): should override 'eql?' * array.c (rb_ary_hash): should override 'hash' too. Tue Nov 6 14:38:48 2001 Yukihiro Matsumoto * process.c (security): always give warning for insecure PATH. * dir.c (my_getcwd): do not rely on MAXPATHLEN. * file.c (rb_file_s_readlink): ditto. * file.c (path_check_1): ditto. Tue Nov 6 14:17:14 2001 Amos Gouaux * lib/net/imap.rb (getquota_response): use astring for mailbox names. * lib/net/imap.rb (getacl_response): ditto. Mon Nov 5 17:09:55 2001 Yukihiro Matsumoto * eval.c (rb_yield_0): should not call rb_f_block_given_p(). Sat Nov 3 23:33:18 2001 Yukihiro Matsumoto * string.c (rb_str_chomp_bang): should terminate string by NUL. Sat Nov 3 22:28:51 2001 Keiju Ishitsuka * matrix.rb (Matrix#column_vectors, Matrix#row_vectors): ditto bug. this bug report and fix by tsutomu@nucba.ac.jp. * forwardable.rb: change raise to Kernel::raise Sat Nov 3 10:11:57 2001 Yukihiro Matsumoto * eval.c (rb_yield_0): better error message. Thu Nov 1 14:08:42 2001 Yukihiro Matsumoto * bignum.c (rb_big_aref): idx may be a Bignum. * numeric.c (fix_aref): negative index must return zero. Thu Nov 1 13:23:50 2001 Yukihiro Matsumoto * gc.c (gc_mark_children): should NOT treat last element of structs and arrays specially. Wed Oct 31 16:59:25 2001 Yukihiro Matsumoto * eval.c (exec_under): should initialize ruby_frame->self; Wed Oct 31 15:09:28 2001 Yukihiro Matsumoto * eval.c (POP_VARS): should not set DVAR_DONT_RECYCLE if _old ruby_vars is already force_recycled. Wed Oct 31 10:28:49 2001 Yukihiro Matsumoto * gc.c (rb_gc): handles mark stack overflow. * gc.c (PUSH_MARK): use static mark stack, no more recursion. Wed Oct 31 02:44:06 2001 Wakou Aoyama * lib/cgi.rb: CGI::Cookie::parse(): Ignore duplicate keys caused by Netscape bug. Tue Oct 30 18:21:51 2001 Usaku Nakamura * win32/mkexports.rb: follow the change of rb_io_puts(). Tue Oct 30 14:04:04 2001 Yukihiro Matsumoto * string.c (rb_str_chomp_bang): do smart chomp if $/ == '\n'. [new] * io.c (rb_io_puts): don't treat Array specially. * bignum.c (rb_big_cmp): should convert bignum to float. * eval.c (rb_f_eval): can't modify untainted binding. Mon Oct 29 16:08:30 2001 Yukihiro Matsumoto * regex.c (re_compile_pattern): should preserve p0 value. Mon Oct 29 14:56:44 2001 Usaku Nakamura * intern.h (rb_protect_inspect): follow the change of array.c. * eval.c (rb_exec_end_proc): follow the change of rb_protect(). * eval.c (method_proc, umethod_proc, rb_catch): cast the first parameter of rb_iterate() to avoid VC++ warning. * range.c (range_step): ditto. * ext/sdbm/init.c (fsdbm_update, fsdbm_replace): ditto. Mon Oct 29 07:57:31 2001 Yukihiro Matsumoto * parse.y (str_extend): should allow interpolation of $-x. * variable.c (rb_cvar_set): empty iv_tbl may cause infinite loop. * variable.c (rb_cvar_get): ditto. * variable.c (cvar_override_check): ditto. Sat Oct 27 23:01:19 2001 Yukihiro Matsumoto * bignum.c (rb_big_eq): convert Bignum to Float, instead of reverse. Fri Oct 26 06:19:29 2001 Yukihiro Matsumoto * time.c (time_localtime): getting tm should not be prohibited for frozen time objects. * time.c (time_gmtime): ditto. * version.c (Init_version): freeze RUBY_VERSION, RUBY_RELEASE_DATE, and RUBY_PLATFORM. * file.c (Init_File): freeze File::SEPARATOR, ALT_SEPARATOR and PATH_SEPARATOR. * file.c (rb_stat_cmp): should check operand type before calling get_stat(). Thu Oct 25 10:28:15 2001 Yukihiro Matsumoto * eval.c (rb_eval_cmd): should not invoke "call" with a block on any occasion. Wed Oct 24 03:25:31 2001 Yukihiro Matsumoto * numeric.c (fix_aref): idx may be a Bignum. Tue Oct 23 01:21:19 2001 Nobuyoshi Nakada * eval.c (proc_invoke): fix self switching in Proc#call (ruby-bugs-ja#PR108) and GC failure. use Qundef instead of 0 to direct not switching self. * eval.c (call_trace_func): ditto. * eval.c (call_end_proc): ditto. * eval.c (proc_call): ditto. * eval.c (proc_yield): ditto. Tue Oct 23 01:15:43 2001 K.Kosako * variable.c (rb_global_entry): reconstruct global variable aliasing (sharing global_entry->var with other global_entry). * variable.c (undef_getter): ditto. * variable.c (undef_setter): ditto. * variable.c (val_setter): ditto. * variable.c (mark_global_entry): ditto. * variable.c (rb_define_hooked_variable): ditto. * variable.c (rb_f_trace_var): ditto. * variable.c (remove_trace): ditto. * variable.c (rb_f_untrace_var): ditto. * variable.c (rb_gvar_get): ditto. * variable.c (trace_en): ditto. * variable.c (rb_gvar_set): ditto. * variable.c (rb_gvar_defined): ditto. * variable.c (rb_alias_variable): ditto. Mon Oct 22 18:53:55 2001 Masahiro Tanaka * numeric.c (num_remainder): a bug in Numeric#remainder. Mon Oct 22 15:21:55 2001 Yukihiro Matsumoto * eval.c (rb_exec_end_proc): END might be called within END block. * class.c (rb_mod_clone): should not copy class name, since clone should remain anonymous. Fri Oct 19 23:40:37 2001 Nobuyoshi Nakada * variable.c (remove_trace): should not access already freed area. * variable.c (rb_f_untrace_var): fix memory leak. Fri Oct 19 17:55:14 2001 Nobuyoshi Nakada * marshal.c (w_uclass): cloned class is not user class. (ruby-bugs-ja#PR103) * marshal.c (r_object): Struct subclass couldn't load. (ruby-bugs-ja#PR104) Wed Oct 17 14:12:50 2001 Nobuyoshi Nakada * variable.c (alias_fixup): added. ad hoc support for ordinary global variable aliasing. when original entry is set, make the alias to refer directly as possible. * variable.c (alias_getter, alias_setter): ditto. * variable.c (rb_alias_variable): ditto. and no need to mark alias variables. * variable.c (rb_gvar_defined): refer the original entry of an alias. Tue Oct 16 23:29:26 2001 Yukihiro Matsumoto * eval.c (rb_call0): self in a block given to define_method now be switched to the receiver of the method. * eval.c (proc_invoke): added new parameter to allow self switching. Tue Oct 16 21:38:15 2001 Nobuyoshi Nakada * eval.c (rb_f_missing): check stack level with rb_stack_check(). * eval.c (rb_call0): ditto. * eval.c, intern.h (rb_stack_check): added. [new] Tue Oct 16 13:18:47 2001 Nobuyoshi Nakada * object.c (rb_mod_initialize): optional block with Module.new. [new] (from 2001-10-10) Tue Oct 16 00:07:06 2001 Nobuyoshi Nakada * parse.y (yylex): disallow alpha-numeric and mbchar for terminator of %string. Mon Oct 15 18:00:05 2001 Pit Capitain * string.c (rb_str_index): wrong increment for non alphanumeric string. Mon Oct 15 05:23:02 2001 Koji Arai * sprintf.c (rb_f_sprintf): support "%B". Wed Oct 10 03:11:47 2001 Yukihiro Matsumoto * file.c (rb_stat_clone): should copy internal data too. * numeric.c (num_clone): Numeric should not be copied by clone. * object.c (rb_obj_clone): should check immediate values. * parse.y (command): `yield' should take command_args. * parse.y (parse_quotedwords): %w(...) is not a string. Tue Oct 9 18:40:35 2001 WATANABE Hirofumi * process.c (Init_process): activate the case NT. Tue Oct 9 17:08:00 2001 Nobuyoshi Nakada * eval.c (thread_status_name): separated from rb_thread_inspect(). return string expression for thread status. * eval.c (rb_thread_status, rb_thread_inspect): use thread_status_name(). * eval.c (rb_thread_priority_set): return the priority not but self. Sat Oct 6 23:07:08 2001 Yukihiro Matsumoto * eval.c (rb_eval): NODE_MATCH3 was confusing left and right. sigh. Fri Oct 5 15:19:46 2001 Yukihiro Matsumoto * marshal.c (w_unique): should not dump anonymous class. Fri Oct 5 11:59:13 2001 Nobuyoshi Nakada * eval.c (proc_s_new): revived. * eval.c (Init_Proc): define Proc.new instead of Proc.allocate to inhibit from creating uninitialized Proc. Thu Oct 4 14:11:03 2001 WATANABE Hirofumi * ext/socket/socket.c (ruby_connect): EALREADY is the equivalent for EINPROGRESS in ws2_32.lib. Wed Oct 3 20:11:06 2001 Nobuyoshi Nakada * re.c (rb_reg_s_alloc): avoid infinite recursion. Wed Oct 3 16:49:49 2001 Nobuyoshi Nakada * ext/gdbm/gdbm.c (rb_gdbm_fetch): str is a VALUE now. Wed Oct 3 13:32:06 2001 Yukihiro Matsumoto * marshal.c (r_object): better allocation type check for TYPE_UCLASS. usage of allocation framework is disabled for now. * variable.c (rb_class_path): Module may have subclass. * string.c (rb_str_update): should maintain original negative offset. * string.c (rb_str_subpat_set): ditto * string.c (rb_str_aset): ditto. * re.c (rb_reg_nth_match): should check negative nth. * re.c (rb_reg_nth_defined): ditto. Tue Oct 2 19:12:47 2001 WATANABE Hirofumi * lib/ftools.rb (catname): allow trailing '/' for the destination. Tue Oct 2 18:31:20 2001 Yukihiro Matsumoto * eval.c (rb_eval): should override existing class. Tue Oct 2 17:08:49 2001 Yukihiro Matsumoto * object.c (rb_obj_alloc): general instance allocation framework. use of NEWOBJ() is deprecated except within 'allocate' method. Tue Oct 2 08:04:52 2001 Nobuyoshi Nakada * marshal.c (r_object): TYPE_UCLASS check should be inversed. Mon Oct 1 19:18:54 2001 Tanaka Akira * ext/socket/socket.c (unix_addr): getsockname(2) may result len = 0. * ext/socket/socket.c (unix_peeraddr): getpeername(2) may result len = 0. Mon Oct 1 09:59:07 2001 Yukihiro Matsumoto * string.c (rb_str_subpat_set): support function for new argument pattern String#[re,offset] = val. [new] Sat Sep 29 02:30:06 2001 Yukihiro Matsumoto * eval.c (POP_BLOCK): rb_gc_force_recycle() was called too much. Should not be called if SCOPE_DONT_RECYCLE is set. Wed Sep 26 22:21:52 2001 Yukihiro Matsumoto * string.c (rb_str_aref_m): new argument pattern String#[re,offset]. [new] Wed Sep 26 19:02:39 2001 Guy Decoux * parse.y: allow 'primary[] = arg' Tue Sep 25 10:46:42 2001 Usaku Nakamura * win32/win32.c (isInternalCmd): check return value of NtMakeCmdVector (Tietew 's patch). Mon Sep 24 00:55:06 2001 Yukihiro Matsumoto * string.c (rb_str_substr): should return an instance of receiver's class. * string.c (rb_str_succ): ditto. * array.c (rb_ary_subseq): ditto. * array.c (rb_ary_initialize): Array.new([1,2,3]) => [1,2,3]. [new] Sat Sep 22 22:16:08 2001 Yukihiro Matsumoto * string.c (rb_str_reverse): should return an instance of receiver's class. * string.c (rb_str_times): ditto. * array.c (rb_ary_times): ditto * string.c (str_gsub): ditto. * string.c (rb_str_ljust): ditto. * string.c (rb_str_rjust): ditto. * string.c (rb_str_center): ditto. Sat Sep 22 12:13:39 2001 Yukihiro Matsumoto * eval.c (eval): retrieves file, line information from binding. Thu Sep 20 21:25:00 2001 Nobuyoshi Nakada * eval.c (MATCH_DATA): access via rb_svar(). Thu Sep 20 15:20:00 2001 Nobuyoshi Nakada * eval.c, intern.h (rb_svar): return reference to special variable from local variable index. [new] * eval.c (rb_eval): use rb_svar() for NODE_FLIP{2,3}. * parse.y (rb_(backref|lastline)_(get|set)): access via rb_svar(). * eval.c (proc_invoke): push dynamic variables. * eval.c (rb_thread_yield): push special variables as dynamic variables($_, $~ and FLIP states). Thu Sep 20 15:20:00 2001 Nobuyoshi Nakada * intern.h, parse.y (rb_is_local_id): return true if the ID is local symbol. [new] * parse.y (internal_id): make new ID for internal use. [new] * parse.y (cond0): allocate internal ID for NODE_FLIP{2,3}. * eval.c (rb_f_local_variables): use rb_is_local_id() to select visible local variables. Thu Sep 20 15:20:00 2001 Nobuyoshi Nakada * eval.c (rb_thread_start_0): SCOPE_SHARED is removed. * eval.c, intern.h (rb_thread_scope_shared_p): removed. special variables are no longer shared by threads. * re.c (rb_reg_search): MATCHDATA is no longer shared by threads. Tue Sep 18 11:44:26 2001 Yukihiro Matsumoto * string.c (rb_str_init): String.new() => "" [new] Tue Sep 11 20:53:56 2001 Yukihiro Matsumoto * dir.c (dir_path): new method. * dir.c (dir_initialize): wrap DIR into struct, along with path information. Sat Sep 8 07:13:42 2001 Wakou Aoyama * lib/net/telnet.rb: waitfor(): improvement. thanks to nobu.nakada@nifty.ne.jp Sat Sep 8 04:34:17 2001 Yukihiro Matsumoto * eval.c (rb_thread_restore_context): save current value of lastline and lastmatch in the thread struct for later restore. * eval.c (rb_thread_save_context): restore lastline and lastmatch. Fri Sep 7 11:27:56 2001 akira yamada * numeric.c (flo_to_s): should handle negative float value. Fri Sep 7 09:44:44 2001 Wakou Aoyama * lib/net/telnet.rb: waitfor(): bug fix. Fri Sep 7 07:11:34 2001 Wakou Aoyama * lib/cgi.rb: CGI#doctype(): bug fix (html4Fr). * lib/net/telnet.rb, lib/cgi.rb: remove VERSION, RELEASE_DATE, VERSION_CODE, RELEASE_CODE. please use REVISION. * lib/cgi.rb: CGI#header(): bug fix. * lib/net/telnet.rb, lib/cgi.rb: concat --> += Thu Sep 6 17:38:18 2001 Nobuyoshi Nakada * dir.c (dir_s_chdir): raise if environment variable HOME/LOGDIR not set. * dir.c (glob_helper): avoid infinite loop on a file name with wildcard characters. (ruby-bugs#PR177) Thu Sep 6 14:25:15 2001 Akinori MUSHA * ext/digest/digest.c (rb_digest_base_s_hexdigest): remove a debug print. Thu Sep 6 13:56:14 2001 Akinori MUSHA * ext/digest/digest.c (rb_digest_base_s_digest, rb_digest_base_s_hexdigest): ensure that a string is given. Thu Sep 6 13:28:51 2001 WATANABE Hirofumi * lib/jcode.rb (_regexp_quote): fix quote handling, again. Thu Sep 6 07:28:56 2001 Nobuyoshi Nakada * file.c (rb_find_file_ext): add const qualifiers to ext. * intern.h (rb_find_file_ext): ditto. Thu Sep 6 07:16:14 2001 Nobuyoshi Nakada * ext/socket/socket.c (Init_socket): remove duplicating constants. Thu Sep 6 03:15:24 2001 Yukihiro Matsumoto * class.c (rb_include_module): should check whole ancestors to avoid duplicate module inclusion. Wed Sep 5 20:02:27 2001 Shin'ya Adzumi * string.c (trnext): should check backslash before updating "now" position. Wed Sep 5 17:41:11 2001 WATANABE Hirofumi * lib/jcode.rb (_regexp_quote): fix quote handling. Tue Sep 4 01:03:18 2001 Yukihiro Matsumoto * re.c (Init_Regexp): to_s to be alias to inspect. Mon Sep 3 22:46:59 2001 Yukihiro Matsumoto * parse.y (yylex): should support 'keyword='. Mon Sep 3 20:26:08 2001 Nobuyoshi Nakada * intern.h (rb_find_file_ext): changed from rb_find_file_noext(). Mon Sep 3 15:12:49 2001 Yukihiro Matsumoto * ruby.c (proc_options): should not adjust argc/argv if -e option is supplied. Mon Sep 3 14:11:17 2001 Akinori MUSHA * error.c: unbreak the build on *BSD with gcc 3.0.1 by removing the conflicting declaration of sys_nerr for *BSD. Sat Sep 1 18:50:07 2001 Yukihiro Matsumoto * ruby.c (proc_options): should not alter origargv[]. * ruby.c (set_arg0): long strings for $0 dumped core. Sat Sep 1 09:50:54 2001 Nobuyoshi Nakada * ruby.c (set_arg0): prevent SEGV when val is longer than the original arguments. * ruby.c (ruby_process_options): initialize total length of original arguments at first. Sat Sep 1 14:05:28 2001 Brian F. Feldman * ruby.c (set_arg0): use setprogtitle() if it's available. Sat Sep 1 03:49:11 2001 Yukihiro Matsumoto * io.c (rb_io_popen): accept integer flags as mode. Fri Aug 31 19:46:05 2001 Nobuyoshi Nakada * file.c (rb_find_file_ext): extension table can be supplied from outside. renamed. * eval.c (rb_f_require): replace rb_find_file_noext by rb_find_file_ext. Fri Aug 31 19:26:55 2001 Nobuyoshi Nakada * eval.c (rb_provided): should also check feature without extension. Fri Aug 31 13:06:33 2001 Yukihiro Matsumoto * numeric.c (flo_to_s): do not rely on decimal point to be '.' Wed Aug 29 02:18:53 2001 Yukihiro Matsumoto * parse.y (yylex): ternary ? can be followed by newline. Tue Aug 28 00:40:48 2001 Yukihiro Matsumoto * eval.c (rb_f_require): should check static linked libraries before raising exception. Fri Aug 24 15:17:40 2001 Yukihiro Matsumoto * array.c (rb_ary_equal): check identity equality first. * string.c (rb_str_equal): ditto. * struct.c (rb_struct_equal): ditto. Fri Aug 24 14:38:17 2001 Usaku Nakamura * dln.c (dln_strerror): fix a bug that sometimes made null message on win32 (Tietew 's patch). * win32/win32.c (mystrerror): ditto. Fri Aug 24 03:15:07 2001 Yukihiro Matsumoto * numeric.c (Init_Numeric): undef Integer::new. Fri Aug 24 00:46:44 2001 Yukihiro Matsumoto * eval.c (rb_eval): NODE_WHILE should update result for each conditional evaluation. * eval.c (rb_eval): NODE_UNTIL should return last evaluated value (or value given to break). Thu Aug 23 21:59:38 2001 Nobuyoshi Nakada * enum.c (sort_by_i): fix typo. Thu Aug 23 10:10:59 2001 Yukihiro Matsumoto * eval.c (is_defined): should not dump core for "defined?(())". * eval.c (umethod_bind): recv can be an instance of descender of oklass if oklass is a Module. Wed Aug 22 23:20:03 2001 Yukihiro Matsumoto * hash.c (rb_hash_equal): check identity equality first. Wed Aug 22 19:58:59 2001 Nobuyoshi Nakada * eval.c (intersect_fds): counts intersecting fds. * eval.c (rb_thread_schedule): only fds requested by each thread count as select_value. Tue Aug 21 22:28:09 2001 Nobuyoshi Nakada * file.c (group_member): should check real gid only. * file.c (eaccess): do not cache euid, since effective euid may be changed via Process.euid=(). * file.c (eaccess): return -1 unless every specified access mode is permitted. Tue Aug 21 16:09:27 2001 Yukihiro Matsumoto * eval.c (rb_eval): while/until returns the value which is given to break. * parse.y (value_expr): using while/until/class/def as an expression is now gives a warning, not an error. Tue Aug 21 11:56:02 2001 Yukihiro Matsumoto * range.c (range_eqq): should compare strings based on magical increment (using String#upto), not dictionary order. Mon Aug 20 19:53:16 2001 WATANABE Hirofumi * ext/digest/sha2/extconf.rb: fix support for cross-compiling. * mkconfig.rb: fix support for autoconf 2.52. Mon Aug 20 17:24:15 2001 Yukihiro Matsumoto * enum.c (enum_sort_by): new method for Schewartzian transformed stable sort. Mon Aug 20 16:09:05 2001 Yukihiro Matsumoto * variable.c (mod_av_set): detect constant overriding for built-in classes/modules. Mon Aug 20 15:14:27 2001 Yukihiro Matsumoto * parse.y (tokadd_escape): escaped backslashes too much. Mon Aug 20 13:24:08 2001 Yukihiro Matsumoto * range.c (range_step): 'iter' here should be an array. Mon Aug 20 12:43:08 2001 Yukihiro Matsumoto * marshal.c (w_object): should retrieve __member__ data from non-singleton class. Sat Aug 18 23:11:14 2001 Yukihiro Matsumoto * variable.c (rb_cvar_get): class variable override check added. * variable.c (rb_cvar_set): ditto * variable.c (rb_cvar_declare): ditto. Fri Aug 17 12:13:48 2001 Minero Aoki * lib/net/protocol.rb: Protocol.new requires at least one arg. * lib/net/smtp.rb: ditto. * lib/net/pop.rb: ditto. * lib/net/http.rb: ditto. Fri Aug 17 00:49:51 2001 Yukihiro Matsumoto * parse.y (parse_regx): handle backslash escaping of delimiter here. Thu Aug 16 23:03:40 2001 Koji Arai * io.c: prevent recursive malloc calls on NEC UX/4800. * ext/socket/socket.c: ditto. Thu Aug 16 13:54:04 2001 Usaku Nakamura * ext/socket/socket.c (s_recvfrom): fix typo. Thu Aug 16 09:53:28 2001 Usaku Nakamura * ext/socket/socket.c (s_recvfrom): avoid VC++6 warning. Thu Aug 16 03:50:33 2001 Usaku Nakamura * win32/win32.c (NtCmdGlob): avoid VC++ warning. * lib/mkmf.rb: add -I$(srcdir) to CPPFLAGS. Wed Aug 15 04:59:15 2001 Akinori MUSHA * ext/digest/*/extconf.rb: really fix so that they build from any directory. Wed Aug 15 04:04:02 2001 Akinori MUSHA * ext/digest/sha2/extconf.rb: fix so that they build from any directory. Wed Aug 15 01:59:19 2001 Akinori MUSHA * ext/digest/defs.h: Define NO_UINT64_T instead of emitting an error to fail. * ext/digest/sha2/extconf.rb: Do not exit on error, and utilize NO_UINT64_T to detect if the system has a 64bit integer type. Tue Aug 14 21:14:07 2001 Akinori MUSHA * ext/digest/sha2/extconf.rb: do not create Makefile when no 64bit integer type is detected. Tue Aug 14 17:09:12 2001 Yukihiro Matsumoto * range.c (range_step): new method. Tue Aug 14 11:49:00 2001 TOYOFUKU Chikanobu * string.c (rb_str_cmp): remove needless conditional. Tue Aug 14 03:23:25 2001 Koji Arai * string.c (rb_str_lstrip_bang) `return Qnil' was missing. Mon Aug 13 14:16:46 2001 Akinori MUSHA * bignum.c, marshal.c: Detypo: s/SIZEOF_ING/SIZEOF_INT/. Sun Aug 12 15:01:58 2001 Nobuyoshi Nakada * string.c (rb_str_cat): fix buffer overflow. * string.c (rb_str_append): nothing to append actually when `str2' is empty. Sat Aug 11 14:43:47 2001 Tanaka Akira * array.c (rb_inspecting_p): initialize inspect_key if it is not initialized yet. Fri Aug 10 22:14:37 2001 Yukihiro Matsumoto * parse.y (cond0): operands of logical operators are not treated as conditional expression anymore, but propagate conditional status if used in conditionals. Tue Aug 7 09:10:32 2001 Usaku Nakamura * win32/win32.h: fix problems with BC++ (ruby-bugs#PR161). Mon Aug 6 23:47:46 2001 Nobuyoshi Nakada * pack.c (pack_pack): associates p/P strings once at last (reverted to 1.26). * string.c (rb_str_associate): associates an Array at once, not but a String. realloc's when str_buf. Mon Aug 6 17:01:33 2001 Yukihiro Matsumoto * eval.c (rb_gc_mark_threads): should mark ruby_cref. Mon Aug 6 14:31:37 2001 Usaku Nakamura * numeric.c (num_divmod): fix typo. Mon Aug 6 03:29:03 2001 Yukihiro Matsumoto * string.c (rb_str_lstrip_bang): new method. * string.c (rb_str_rstrip_bang): new method. Mon Aug 6 00:35:03 2001 Guy Decoux * struct.c (rb_struct_modify): should check frozen and taint status. Sun Aug 5 19:28:39 2001 Nobuyoshi Nakada * string.c (rb_str_associate): should consider STR_ASSOC too. Sun Aug 5 07:46:18 2001 Nobuyoshi Nakada * eval.c (rb_undefined): do not recurse if method_missing is undefined. Thu Aug 2 21:37:32 2001 Yukihiro Matsumoto * process.c (proc_waitpid): now all arguments are optional. * process.c (Init_process): waitpid is now alias to wait. * process.c (Init_process): waitpid2 is now alias to wait2. * process.c (rb_waitpid): made public. * ext/pty/pty.c (pty_getpty): avoid disturbing SIGCHLD using thread and rb_waitpid. Thu Aug 2 11:23:07 2001 Yukihiro Matsumoto * process.c (proc_getpgrp): now takes no argument on all platforms. * process.c (proc_setpgrp): ditto. Thu Aug 2 01:29:42 2001 Nobuyoshi Nakada * file.c (strrdirsep): removed meaningless code. * file.c (rb_file_s_expand_path): reverted to 1.66. Wed Aug 1 16:17:47 2001 Yukihiro Matsumoto * ext/socket/socket.c (sock_s_pack_sockaddr_in): added Socket::pack_sockaddr_in(). [new] * ext/socket/socket.c (sock_s_pack_sockaddr_un): added Socket::pack_sockaddr_un(). [new] * ext/socket/socket.c (sock_s_pack_sockaddr_in): added Socket::unpack_sockaddr_in(). [new] * ext/socket/socket.c (sock_s_pack_sockaddr_un): added Socket::unpack_sockaddr_un(). [new] Wed Aug 1 15:42:16 2001 Usaku Nakamura * eval.c (ruby_run): avoid VC++ warning. Tue Jul 31 17:30:53 2001 Usaku Nakamura * marshal.c (Init_marshal): fix typos. Tue Jul 31 15:16:39 2001 Nobuyoshi Nakada * process.c (last_status_set): nothing returned, should be void. * ext/socket/socket.c (load_addr_info): ditto. Tue Jul 31 12:11:42 2001 Yukihiro Matsumoto * marshal.c (Init_marshal): new constant Marshal::MAJOR_VERSION and Marshal::MINOR_VERSION. Tue Jul 31 07:18:04 2001 Nobuyoshi Nakada * file.c (rb_file_s_expand_path): scans per path element not per byte/character, including fix of [ruby-talk:18152] and multi-byte pathname support. Tue Jul 31 11:52:10 2001 akira yamada * marshal.c (marshal_load): ruby_verbose test should be wrapped by RTEST(). Mon Jul 30 17:54:23 2001 Yukihiro Matsumoto * hash.c (rb_hash_index): should return nil (not the default value) if value is not in the hash. Mon Jul 30 12:55:47 2001 Yukihiro Matsumoto * numeric.c (num_div): new method added. alias to '/' which should be preserved even if '/' is redefined (e.g. by mathn). [new] Mon Jul 30 11:12:14 2001 Amos Gouaux * lib/net/imap.rb: added new commands for managing folder quotas and folder ACLs. Mon Jul 30 03:19:53 2001 Yukihiro Matsumoto * bignum.c (rb_cstr2inum): "0 ff".hex should return 0, not 255. Fri Jul 27 22:29:41 2001 Nobuyoshi Nakada * file.c (rb_file_s_expand_path): fixed using CharNext(). Fri Jul 27 18:07:27 2001 Yukihiro Matsumoto * eval.c (rb_provided): extension should be guessed using rb_find_file_noext(). * eval.c (rb_f_require): should call rb_feature_p() after extension completion. Fri Jul 27 16:25:52 2001 Yukihiro Matsumoto * eval.c (rb_eval): add CHECK_INTS before next, redo, retry to avoid potential uninterruptable infinite loop. Thu Jul 26 11:27:12 2001 WATANABE Hirofumi * file.c (rb_find_file_noext, rb_find_file): fix tilde expansion problem. Wed Jul 25 17:54:20 2001 Yukihiro Matsumoto * file.c (rb_file_s_expand_path): use CharNext() to expand. Wed Jul 25 17:16:26 2001 Akinori MUSHA * intern.h: add some missing function prototypes. Wed Jul 25 15:50:05 2001 Guy Decoux * file.c (rb_file_s_expand_path): should not expand "." and ".." not following dirsep. Wed Jul 25 12:15:32 2001 WATANABE Hirofumi * file.c (rb_find_file_noext): should update f by expanded path. * file.c (rb_find_file): ditto. Tue Jul 24 23:10:47 2001 Nobuyoshi Nakada * file.c (strrdirsep): multi-byte pathname and DOSish separator support. originally comes from Patrick Cheng. [new] * file.c (rb_file_s_basename, rb_file_s_dirname): use strrdirsep(). comes from Patrick Cheng. * file.c (is_absolute_path): restricted in DOSish absolute path with drive letter, and UNC support. originally comes from Patrick Cheng. * file.c (getcwd): define macro using getwd() unless provided. Tue Jul 24 19:23:15 2001 Akinori MUSHA * ext/extmk.rb.in, lib/mkmf.rb: dig the target subdirectory for lib/* files properly in case of create_makefile("dir/name"). Mon Jul 23 00:26:04 2001 Yukihiro Matsumoto * eval.c (rb_provide_feature): should not tweak extension used for loading. Sun Jul 22 21:16:43 2001 Akinori MUSHA * ext/extmk.rb.in, lib/mkmf.rb: introduce a couple of new make variables: CLEANFILES and DISTCLEANFILES. They'd typically be defined in a file "depend". Sat Jul 21 09:40:10 2001 Nobuyoshi Nakada * io.c (io_fread): use fread(3) if PENDING_COUNT is available. Fri Jul 20 22:55:01 2001 Akinori MUSHA * gc.c (ruby_xrealloc): fix a dangling bug which led memory reallocation to fail even though the second try after a GC succeeds. Fri Jul 20 03:00:46 2001 Akinori MUSHA * class.c (rb_mod_include_p): Module#include? added. [new] Fri Jul 20 01:05:50 2001 Yukihiro Matsumoto * re.c (ignorecase_setter): give warning on modifying $=. * string.c (rb_str_casecmp): new method. [new] * string.c (rb_str_eql): separated from rb_str_equal(), make it always be case sensitive. [new] * string.c (rb_str_hash): made it always be case sensitive. Thu Jul 19 13:03:15 2001 Nobuyoshi Nakada * eval.c (rb_f_require): should not include path in $" value * file.c (rb_find_file): should return 0 explicitly on failure. Tue Jul 17 11:44:40 2001 Usaku Nakamura * ruby.h: enable volatile directive with VC++. * regex.c: ditto. Tue Jul 17 06:01:12 2001 Minero Aoki * doc/net/smtp.rd.ja, pop.rd.ja, http.rd.ja: new files. * MANIFEST: add doc/net/{http,pop,smtp}.rd.ja. Tue Jul 17 11:22:01 2001 Yukihiro Matsumoto * regex.c (NUM_FAILURE_ITEMS): was confusing NUM_REG_ITEMS and NUM_NONREG_ITEMS, which have happened to be same value. Tue Jul 17 11:08:34 2001 Usaku Nakamura * ext/extmk.rb.in: modify RM macro because command.com/cmd.exe don't recognize single quotation as quote character. * lib/mkmf.rb: ditto. Tue Jul 17 01:38:15 2001 Yukihiro Matsumoto * class.c (rb_class_new): subclass check moved to this function. * class.c (rb_class_boot): check less version of rb_class_new(). Man Jul 16 13:21:30 2001 Usaku Nakamura * file.c (file_load_ok): fix typo. Mon Jul 16 12:58:07 2001 Yukihiro Matsumoto * eval.c (proc_invoke): should preserve iter status for embedded frame in the block. Mon Jul 16 00:04:39 2001 Yukihiro Matsumoto * file.c (rb_file_s_expand_path): may overrun buffer on stack. Sun Jul 15 01:38:28 2001 Guy Decoux * string.c (rb_str_insert): forgot to call rb_str_modify(). Sat Jul 14 12:26:30 2001 Nobuyoshi Nakada * ext/digest/*/extconf.rb: fix so that they build from any directory. Sat Jul 14 06:20:17 2001 WATANABE Hirofumi * lib/net/http.rb: HTTP#proxy? did not worked. Sat Jul 14 02:56:19 2001 Akinori MUSHA * ext/extmk.rb.in: support multi-level ext/ directories. (e.g. you can have ext/foo, ext/foo/bar and ext/foo/baz) Sat Jul 14 02:55:02 2001 Akinori MUSHA * ext/.cvsignore: let cvs ignore extinit.c. Fri Jul 13 23:47:35 2001 Yukihiro Matsumoto * regex.c (re_search): should consider reverse search. Fri Jul 13 22:26:09 2001 Akinori MUSHA * lib/mkmf.rb: use File::split to split a target into a prefix and a module name. This also works around a just found bug of String#rindex. * ext/extmk.rb.in: ditto. Fri Jul 13 02:36:10 2001 Minero Aoki * dir.c (dir_s_chdir): warn only when invoked from multiple threads or block is not given. Thu Jul 12 15:11:48 2001 WATANABE Hirofumi * ext/socket/socket.c (ruby_connect): workaround for the setup of Cygwin socket(EALREADY). Mon Jul 9 16:49:30 2001 WATANABE Hirofumi * ext/extmk.rb.in: modify RM macro. * lib/mkmf.rb: ditto. Sun Jul 8 20:52:02 2001 Akinori MUSHA * ruby.h: fix a wrong function name: rb_iglob() -> rb_globi(). Sun Jul 8 16:04:35 2001 Minero Aoki * lib/net/http.rb: rename HTTP#request_by_name to send_request. * lib/net/protocol.rb (ProtoSocket#read): modify typo. Sat Jul 7 17:45:35 2001 Yukihiro Matsumoto * object.c (rb_convert_type): should use rb_rescue(), not rb_rescue2(). * range.c (range_init): ditto. Fri Jul 6 18:01:10 2001 Yukihiro Matsumoto * object.c (rb_obj_dup): copies (actually does not free) generic_ivar on dupif original owns them. Fri Jul 6 02:15:06 2001 Akinori MUSHA * lib/tempfile.rb: a tempfile must be created with mode 0600. Thu Jul 5 20:28:53 2001 Tietew * string.c (rb_str_each_line): should propagate taint mark. * ext/nkf/nkf.c (rb_nkf_kconv): ditto. Fri Jul 6 14:54:27 2001 Yukihiro Matsumoto * eval.c (rb_f_require): revamp for simpler implementation. * file.c (rb_find_file_noext): use String object, instead of passing char* around. * file.c (rb_find_file): ditto. Thu Jul 5 22:01:02 2001 Mitsuhiro Kondo * dln.c (dln_load): should use NSLINKMODULE_OPTION_BINDNOW. Thu Jul 5 13:44:03 2001 Yukihiro Matsumoto * ruby.c (load_file): local variables 'c' remain uninitialized on xflag. Thu Jul 5 10:00:59 2001 Yukihiro Matsumoto * regex.c (re_match): prefetched escaped character too early. Wed Jul 4 08:58:30 2001 Yukihiro Matsumoto * eval.c (rb_call0): add argument check for attr_readers. Wed Jul 4 04:22:44 2001 Minero Aoki * lib/net/http.rb (HTTP#request_by_name): arg order changes. Wed Jul 4 04:07:36 2001 Minero Aoki * lib/net/http.rb (HTTP#request_by_name): bug fix. * lib/net/http.rb: does not write Connection: by default. * lib/net/protocol.rb: "start" for started protocol is an error. * lib/net/protocol.rb: "finish" for finished protocol is an error. Wed Jul 4 03:17:31 2001 Minero Aoki * lib/net/http.rb: new method HTTP#request_by_name (test) * lib/net/http.rb: new class HTTPGenericRequest Tue Jul 3 23:58:29 2001 Akinori MUSHA * lib/mkmf.rb: distclean should remove mkmf.log as well. Tue Jul 3 18:35:49 2001 Yukihiro Matsumoto * eval.c (rb_eval_string_wrap): should push frame (and adjust cbase) before wrapped eval. * eval.c (rb_eval_cmd): ditto. * eval.c (eval): should update ruby_class always after all. Tue Jul 3 14:56:27 2001 Shugo Maeda * eval.c (block_pass): do not change wrapper information. * eval.c (rb_yield_0): preserve wrapper information. Tue Jul 3 08:59:50 2001 Nobuyoshi Nakada * error.c (rb_name_error): raise NameError instead of LoadError. Mon Jul 2 17:22:00 2001 Yukihiro Matsumoto * error.c (exc_exception): clone the receiver exception instead of creating brand new exception object of the receiver. Mon Jul 2 09:53:12 2001 Yukihiro Matsumoto * eval.c (rb_eval_string_wrap): extend new ruby_top_self, not original self. * eval.c (rb_eval_cmd): respect ruby_wrapper if set. * eval.c (eval): do not update ruby_class unless scope is not provided. Sun Jul 1 10:51:15 2001 Shugo Maeda * eval.c (eval): preserve wrapper information. * eval.c (proc_invoke): ditto. * eval.c (block_pass): ditto. Sat Jun 30 02:55:45 2001 Yukihiro Matsumoto * parse.y (void_expr): too much warnings for void context (e.g. foo[1] that can be mere Proc call). Fri Jun 29 17:23:18 2001 Yukihiro Matsumoto * error.c (rb_name_error): new function to raise NameError with name attribute set. * eval.c (rb_f_missing): set name and args in the exception object. [new] * error.c (name_name): NameError#name - new method. * error.c (nometh_args): NoMethodError#args - new method. Fri Jun 29 15:29:31 2001 Yukihiro Matsumoto * lex.c (rb_reserved_word): lex_state after tRESCUE should be EXPR_MID. Thu Jun 28 00:21:28 2001 Keiju Ishitsuka * lib/matrix.rb: resolve 'ruby -w' warnings. * lib/irb/locale.rb: resolve 'ruby -w' warnings. * lib/irb/multi-irb.rb: resolve 'ruby -w' warnings. * lib/irb/ruby-lex.rb: fix problem for "\\M-\\..." and "\\C-\\..." and resolve 'ruby -w' warnings. * lib/irb/ruby-token.rb: fix typo * lib/shell/command-processor.rb: resolve 'ruby -w' warnings. Wed Jun 27 08:53:26 2001 Minero Aoki * lib/net/pop.rb: new methods POP3.auth_only, POP3#auth_only * lib/net/http.rb: HTTP.Proxy returns self if ADDRESS is nil. * lib/net/protocol.rb: new method ProtocolError#response * lib/net/protocol.rb,smtp.rb,pop.rb,http.rb: add document. Tue Jun 26 18:42:42 2001 Yukihiro Matsumoto * gc.c (add_heap): allocation size of the heap unit is doubled for each allocation. Mon Jun 25 09:54:48 2001 Yukihiro Matsumoto * dir.c (isdelim): space, tab, and newline are no longer delimiters for glob patterns. Sat Jun 23 22:28:52 2001 Yukihiro Matsumoto * eval.c (svalue_to_avalue): new conversion scheme between single value and array values. * eval.c (avalue_to_svalue): ditto. * eval.c (rb_eval): REXPAND now uses avalue_to_svalue(), return and yield too. * eval.c (rb_yield_0): use avalue_to_svalue(). * eval.c (proc_invoke): Proc#call gives avaules, whereas Proc#yield gives mvalues. * eval.c (bmcall): convert given value (svalue) to avalue. Sat Jun 23 18:28:52 2001 Akinori MUSHA * ext/readline/readline.c (readline_event): a non-void function should return a value. Fri Jun 22 23:17:28 2001 WATANABE Hirofumi * ext/socket/socket.c (ruby_connect): workaround for the setup of Cygwin socket. Fri Jun 22 23:11:17 2001 Keiju Ishitsuka * lib/irb/locale.rb: fix for require "kconv" problem Fri Jun 22 18:08:45 2001 Yukihiro Matsumoto * eval.c (rb_yield_0): no mvalue_to_svalue conversion here. * eval.c (massign): takes svalue, convert it to mvalue inside. * eval.c (rb_eval): parameters for yield/return are always svalues now. * eval.c (svalue_to_mvalue): more strict conversion. * eval.c (mvalue_to_svalue): ditto. Fri Jun 22 17:12:23 2001 Yukihiro Matsumoto * st.c (new_size): prime hash size enabled. * ext/socket/socket.c (Init_socket): SO_* constants added. Tue Jun 19 22:24:07 2001 WATANABE Hirofumi * gc.c (rb_setjmp): avoid GCC 3.0 warnings. Tue Jun 19 18:19:30 2001 Akinori MUSHA * ext/readline/readline.c: add new methods: Readline::completion_append_character and Readline::completion_append_character=. Tue Jun 19 16:29:50 2001 Yukihiro Matsumoto * eval.c (svalue_to_mvalue): new function to convert from svalue to mvalue. [experimental] * eval.c (mvalue_to_svalue): new function to convert from mvalue to svalue. * eval.c (rb_eval): use mvalue_to_svalue(). * eval.c (rb_yield_0): use mvalue_to_svalue(). * eval.c (proc_invoke): proper mvalue handling. Mon Jun 18 17:38:50 2001 Yukihiro Matsumoto * eval.c (rb_f_require): searches ".rb" and ".so" at the same time. previous behavior (search ".rb", then ".so") has a security risk (ruby-bugs#PR140). * array.c (rb_ary_to_ary): new function to replace internal rb_Array(), which never calls to_a, but to_ary (rb_Array() might call both). [new] Mon Jun 18 00:43:20 2001 Yukihiro Matsumoto * regex.c (PUSH_FAILURE_POINT): push option status again. * regex.c (re_compile_pattern): avoid pushing unnecessary option_set. Sat Jun 16 10:58:48 2001 Yukihiro Matsumoto * eval.c (rb_load): tainted string is OK if wrapped *and* $SAFE >= 4. Thu Jun 14 16:27:07 2001 Yukihiro Matsumoto * eval.c (rb_thread_start_0): should not nail down higher blocks before preserving original context (i.e. should not alter original context). Wed Jun 13 19:34:59 2001 Akinori MUSHA * dir.c (Init_Dir): add a new method File::fnmatch? along with File::Constants::FNM_*. While I am here, FNM_NOCASE is renamed to FNM_CASEFOLD which is commonly used by *BSD and GNU libc. Wed Jun 13 09:33:45 2001 Yukihiro Matsumoto * eval.c (proc_yield): new method equivalent to Proc#call but no check for number of arguments. [new] Tue Jun 12 14:21:28 2001 Nobuyoshi Nakada * lib/mkmf.rb: target_prefix is only for installation, not for build. Tue Jun 12 00:41:18 2001 Yukihiro Matsumoto * eval.c (method_eq): new method Method#==. [new] Mon Jun 11 14:29:41 2001 WATANABE Hirofumi * confgure.in: add RUBY_CANONICAL_BUILD. Sun Jun 10 17:31:47 2001 Guy Decoux * gc.c (STR_NO_ORIG): STR_NO_ORIG value was different between string.c and gc.c Sat Jun 9 22:10:04 2001 Yukihiro Matsumoto * eval.c (rb_eval): should convert *non-array at the end of arguments by using Array(). Sat Jun 9 17:04:30 2001 Nobuyoshi Nakada * hash.c (ruby_setenv): readline library leaves their environment strings uncopied. "free" check revised. Sat Jun 9 16:31:03 2001 Usaku Nakamura * ext/extmk.rb.in: Use -F and -T for mswin32 because cl.exe doesn't support -o officially and cl.exe considers that *.cc and *.cxx are OBJs. * lib/mkmf.rb: ditto. * win32/Makefile.sub: Use del instead of rm. All these changes are derived from Nobuyoshi Nakada's patch. Thanks. Fri Jun 8 22:37:40 2001 Yukihiro Matsumoto * gc.c (Init_stack): avoid __builtin_frame_address(2) to retrieve stack bottom line. Fri Jun 8 18:14:12 2001 Yukihiro Matsumoto * st.c (numhash): should shuffle bits by dividing by prime number. Fri Jun 8 17:05:21 2001 Yukihiro Matsumoto * eval.c (rb_eval): multiple assignment behavior fixed, which results "*a = nil" makes "a == []" now. Fri Jun 8 15:25:09 2001 Yukihiro Matsumoto * eval.c (rb_f_require): should set SCOPE_PUBLIC before calling dln_load(). Thu Jun 7 17:28:00 2001 Yukihiro Matsumoto * parse.y (yylex): exclude kDO_BLOCK too much by false condition. Wed Jun 6 23:02:36 2001 Keiju Ishitsuka * lib/sync.rb: bug fix if obj.initialize has parameters when obj.extend(Sync_m) * lib/mutex_m.rb: modified bit Wed Jun 6 16:11:06 2001 Yukihiro Matsumoto * eval.c (rb_load): should check if tainted even when wrap is specified. Wed Jun 6 14:34:27 2001 Yukihiro Matsumoto * parse.y (mrhs_basic): "*arg" should always be expanded by REXPAND. * regex.c (re_compile_pattern): too much optimization for the cases like /(.|a)b/. Tue Jun 5 23:58:43 2001 Yukihiro Matsumoto * variable.c (fc_i): removed vast string allocation. Tue Jun 5 16:45:48 2001 Yukihiro Matsumoto * error.c (Init_Exception): NameError went under StandardError, and NoMethodError went under NameError. Tue Jun 5 16:40:06 2001 Yukihiro Matsumoto * parse.y (rb_intern): non identifier symbols should be categorized as ID_JUNK. [new] Tue Jun 5 16:15:58 2001 Yukihiro Matsumoto * variable.c (rb_mod_const_at): use hash table as internal data. [new] * variable.c (rb_mod_const_of): ditto. * variable.c (rb_const_list): new function to convert internal data (hash table) to array of strings. * eval.c (rb_mod_s_constants): data handling scheme has changed. Tue Jun 5 15:16:06 2001 Yukihiro Matsumoto * eval.c (rb_add_method): should not call rb_secure(), for last_func may not be set. * io.c (rb_io_ctl): ioctl should accept any integer within C long range. Tue Jun 5 13:41:13 2001 WATANABE Hirofumi * ext/etc/extconf.rb: use egrep_cpp. Tue Jun 5 12:44:59 2001 Yukihiro Matsumoto * marshal.c (r_object): wrong type check for modules. * marshal.c (w_object): should not dump anonymous classes/modules. Tue Jun 5 01:19:34 2001 Yukihiro Matsumoto * io.c (rb_open_file): use rb_file_sysopen_internal() if the 3rd argument (permission flags) is given. [new, should be backported?] * io.c (rb_io_mode_binmode): mode string (e.g. "r+") to flags to open(2). Mon Jun 4 23:55:54 2001 Yukihiro Matsumoto * eval.c (rb_eval): NODE_REXPAND expand an array of 1 element as the element itself. [new, should be backported?] * parse.y (ret_args): should treat "*[a]" in rhs expression as "a", not "[a]". Mon Jun 4 04:14:53 2001 Wakou Aoyama * lib/shellwords.rb: don't destroy argument. Sat Jun 2 23:23:05 2001 Yukihiro Matsumoto * regex.c (re_compile_pattern): should push option modifier at the right place. Sat Jun 2 23:05:20 2001 Shugo Maeda * lib/cgi/session.rb: don't use module_function for Class. Sat Jun 2 00:02:22 2001 Keiju Ishitsuka * irb messages: fix typos. Fri Jun 1 17:26:24 2001 K.Kosako * hash.c (replace_i): ignore when key == Qundef. Fri Jun 1 16:50:59 2001 Yukihiro Matsumoto * parse.y (call_args2): confusion with list_append() and list_concat() was fixed. Fri Jun 1 15:01:40 2001 Yukihiro Matsumoto * parse.y (yylex): fixed 'print CGI::bar() {}, "\n"' syntax breakage, adding new lex_state status. sigh. [new] Fri Jun 1 11:21:04 2001 WATANABE Hirofumi * configure.in: use waitpid on mingw32. * ext/dbm/extconf.rb: include , not . Thu May 31 18:34:57 2001 K.Kosako * file.c (rb_file_s_unlink): should not allow if $SAFE >= 2. Thu May 31 17:23:25 2001 Yukihiro Matsumoto * range.c (Init_Range): define "to_ary". Thu May 31 13:30:25 2001 WATANABE Hirofumi * mkconfig.rb, ext/configsub.rb: VERSION -> RUBY_VERSION. Thu May 31 08:00:58 2001 Usaku Nakamura * win32/dir.h: re-add. Thu May 31 01:25:59 2001 Akinori MUSHA * configure.in: default --with-libc_r to `no' until the problem is fixed. (FreeBSD only) Tue May 29 17:24:23 2001 K.Kosako * ruby.c (proc_options): unexpected SecurityError happens when -T4. Tue May 29 18:46:04 2001 Yukihiro Matsumoto * regex.c (re_compile_pattern): * \1 .. \9 should be backreferences always. * regex.c (re_match): backreferences corresponding to unclosed/unmatched parentheses should fail always. Tue May 29 16:35:49 2001 Yukihiro Matsumoto * string.c (rb_str_cat): use rb_str_buf_cat() if possible. [new] * string.c (rb_str_append): ditto. * string.c (rb_str_buf_cat): remove unnecessary check (type, taint, modify) to gain performance. * string.c (rb_str_buf_append): ditto. * string.c (rb_str_buf_finish): removed. Tue May 29 02:05:55 2001 Yukihiro Matsumoto * string.c (rb_str_buf_new): buffering string function. [new] * string.c (rb_str_buf_append): ditto. * string.c (rb_str_buf_cat): ditto. * string.c (rb_str_buf_finish): ditto. Mon May 28 23:20:43 2001 WATANABE Hirofumi * configure.in: remove unnecessary AC_CANONICAL_BUILD * defines.h: #define HAVE_SETITIMER on Cygwin(bug fixed). * ruby.c: use relative path from LIBRUBY_SO. * ruby.c: don't use -mwin32 option on Cygwin. * cygwin/GNUmakefile.in: ditto. * ext/sdbm/_sdbm: ditto. * ext/tcltklib/extconf.rb: ditto. * ext/tcltklib/stubs.c: ditto. Mon May 28 22:12:01 2001 Nobuyoshi Nakada * ext/extconf.rb.in: make the priority of the make rule of .c higher than .C . Mon May 28 13:22:19 2001 Tanaka Akira * time.c (make_time_t): local time adjustment revised. Mon May 28 02:20:38 2001 Akinori MUSHA * dir.c (glob_helper): teach has_magic() to handle flags and get glob_helper to properly support FNM_NOESCAPE. * dir.c (fnmatch): fix a bug when FNM_PATHNAME and FNM_PERIOD are specified at the same time. Sat May 26 09:55:26 2001 Yukihiro Matsumoto * parse.y: accomplish extended syntax described in [ruby-talk:14525] using tSPC token. [new, experimental] Sat May 26 07:05:45 2001 Usaku Nakamura * MANIFEST: add win32/dir.h . Fri May 25 20:03:51 2001 Pascal Rigaux * dln.c (dln_find_1): should exclude directories in executable file lookup. Fri May 25 18:00:26 2001 Yukihiro Matsumoto * class.c (rb_obj_singleton_methods): list methods in extended modules if optional argument is true. [new] Fri May 25 14:19:25 2001 K.Kosako * string.c (rb_str_replace): add taint status infection (OBJ_INFECT()). * string.c (rb_str_crypt): ditto. * string.c (rb_str_ljust): ditto. * string.c (rb_str_rjust): ditto. * string.c (rb_str_center): ditto. Fri May 25 05:39:03 2001 Akinori MUSHA * ext/sha1/sha1-ruby.c (sha1_hexdigest): fix buffer overflow. The buffer for a SHA-1 hexdigest needs to be 41 bytes in length. Fri May 25 01:47:39 2001 Akinori MUSHA * MANIFEST: update the entries I forgot to add or remove. Fri May 25 00:57:25 2001 Akinori MUSHA * ext/sha1/sha1-ruby.c (sha1_new): separate initialize() from new(). * ext/md5/md5init.c (md5i_new): ditto. Fri May 25 00:53:41 2001 Akinori MUSHA * ext/dbm/extconf.rb: fix support for *BSD and set $CFLAGS properly. Thu May 24 16:10:33 2001 Yukihiro Matsumoto * range.c (range_member): check based on "<=>" comparison. [new] * range.c (range_check): add "succ" check if first end is not a numeric. * range.c (range_eqq): comparison should based on "<=>". * range.c (range_each): ditto. Thu May 24 16:08:21 2001 WATANABE Hirofumi * mkconfig.rb: autoconf 2.50 support. Thu May 24 14:23:35 2001 Yukihiro Matsumoto * eval.c (rb_yield_0): need argument adjustment for C defined blocks too. Thu May 24 01:11:30 2001 Yukihiro Matsumoto * ext/dbm/extconf.rb: header search added. [new] Wed May 23 02:58:21 2001 Tanaka Akira * time.c (make_time_t): fix ad-hoc local time adjustment, using binary tree search. Tue May 22 17:10:35 2001 K.Kosako * variable.c (rb_alias_variable): should not allow variable aliasing if $SAFE >= 4. Tue May 22 02:37:45 2001 Yukihiro Matsumoto * parse.y (expr): "break" and "next" to take optional expression, which is used as a value for termination. [new, experimental] * eval.c (rb_eval): "break" can give value to terminating method. * eval.c (rb_eval): "break" and "next" to take optional expression. * eval.c (rb_yield_0): "next" can give value to terminating "yield". * eval.c (rb_iterate): "break" can give value to terminating method. * eval.c (proc_call): ditto. Mon May 21 13:15:25 2001 Yukihiro Matsumoto * bignum.c (rb_big2str): t should be protected from GC. Sat May 19 09:29:07 2001 Yukihiro Matsumoto * process.c (rb_proc_times): need not to check return value from times(2). Fri May 18 05:36:08 2001 Akinori MUSHA * ext/extmk.rb.in (xsystem): backout the previous fix which was bogus. Fri May 18 05:19:55 2001 Akinori MUSHA * lib/mkmf.rb (xsystem): make a temporary fix to get $(...) macros properly expanded on a command execution. * ext/extmk.rb.in (xsystem): ditto. Fri May 18 03:45:55 2001 Brian F. Feldman * lib/mkmf.rb: unbreak "make install". lib/* must be installed under $rubylibdir, not under $libdir. Fri May 18 01:28:07 2001 Yukihiro Matsumoto * parse.y (expr): break, next, redo, retry are moved from primary. Fri May 18 01:11:02 2001 Usaku Nakamura * ext/sha1/sha1-ruby.c (sha1_new): get rid of an unneeded rb_obj_call_init() call. Fri May 18 01:03:55 2001 Usaku Nakamura * ext/sha1/sha1.txt, ext/sha1/sha1.txt.jp: fix typos. Thu May 17 19:17:11 2001 Akinori MUSHA * lib/shell.rb, lib/shell/process-controller.rb, lib/shell/command-processor.rb: translate Japanese comments into English. Thu May 17 19:07:14 2001 Akinori MUSHA * doc/shell.rd.jp: RD'ify and make some fixes. * doc/shell.rd: RD'ify, delete Japanese leftovers, make overall English fixes, and sync with doc/shell.rd.jp. Thu May 17 17:35:04 2001 Yukihiro Matsumoto * eval.c (rb_call0): address of local_vars might change during eval. Thu May 17 07:27:09 2001 Akinori MUSHA * ext/md5/md5.txt.jp, ext/sha1/sha1.txt.jp: s/SuperClass/Superclass/. Thu May 17 07:21:44 2001 Akinori MUSHA * ext/Setup.dj, ext/Setup.emx, ext/Setup.nt, ext/Setup.x68: compile sha1 in as well as md5. * ext/Setup: put sha1 in a comment. Thu May 17 07:16:38 2001 Akinori MUSHA * ext/sha1/sha1.txt.jp: add the Japanese version derived from ext/md5/md5.txt.jp. * ext/sha1/sha1.txt: revise the copyright info and reduce the difference from ext/md5/md5.txt. * ext/md5/md5.txt: reduce the difference from ext/sha1/sha1.txt. Thu May 17 07:11:35 2001 Akinori MUSHA * ext/sha1/extconf.rb, ext/sha1/sha1.c: use WORDS_BIGENDIAN to detect the platform's endian. Thu May 17 06:31:30 2001 Akinori MUSHA * ext/md5/md5.txt: make wording fixes, and mention the newly added method: "<<". * ext/md5/md5.txt.jp: ditto. Wed May 16 18:05:52 2001 Akinori MUSHA * ext/md5/md5init.c: add an instance method "<<" as an alias for "update". (inspired by Steve Coltrin's ruby-sha1) Tue May 15 17:46:37 2001 Yukihiro Matsumoto * array.c (rb_ary_and): should not push frozen key string. * array.c (rb_ary_or): ditto. Tue May 15 02:18:23 2001 Akinori MUSHA * lib/thread.rb: rescue ThreadError in case the thread is dead just before calling Thread#run. Mon May 14 13:50:22 2001 Yukihiro Matsumoto * eval.c (rb_thread_schedule): should save context before raising deadlock, saved context for current thread might be obsolete. * time.c (make_time_t): non DST timezone shift supported (hopefully). * time.c (make_time_t): strict range detection for negative time_t. Mon May 14 11:54:20 2001 Tanaka Akira * signal.c: SIGINFO added. Mon May 14 08:57:06 2001 Yukihiro Matsumoto * eval.c (rb_ensure): should not SEGV when prot_tag is NULL. Sun May 13 23:51:14 2001 Usaku Nakamura * win32/resource.rb: Modify copyright in resource script. Sun May 13 14:03:33 2001 Okada Jun * lib/thread.rb: fix Queue#pop and SizedQueue#max= to avoid deadlock. Sat May 12 15:43:55 2001 Usaku Nakamura * win32/win32.c (kill): add support of signal 9 on mswin32/mingw32. Fri May 11 15:09:52 2001 WATANABE Hirofumi * ruby.h (rb_string_value): add volatile to avoid compiler warning. * string.c (rb_string_value): ditto. Fri May 11 03:35:33 2001 Akinori MUSHA * README.EXT: Document find_library(), with_config() and dir_config(). Fri May 11 03:34:20 2001 Akinori MUSHA * README.EXT.jp: Remove the description of find_header() because such a function does not actually exist. * README.EXT.jp: Update the description of dir_config(). Fri May 11 02:42:05 2001 Kazuhiro NISHIYAMA * README, README.jp: Fix CVS access and mailing lists info. Fri May 11 02:00:44 2001 Ryo HAYASAKA * bignum.c (bigdivrem): access boundary bug. Thu May 10 02:40:47 2001 Yukihiro Matsumoto * marshal.c (w_object): prohibit dumping out singleton classes. * object.c (rb_mod_to_s): distinguish singleton classes. * variable.c (rb_class2name): it's ok to reveal NilClass, TrueClass, FalseClass. Wed May 9 14:38:33 2001 K.Kosako * eval.c (rb_yield_0): preserve and restore ruby_cref as well. Tue May 8 18:28:19 2001 Keiju Ishitsuka * lib/irb.rb lib/irb/multi-irb.rb lib/irb/ruby-lex.rb lib/irb/version.rb resolve ctrl-c problem Tue May 8 17:12:43 2001 K.Kosako * eval.c (is_defined): core dumped during instance_eval for special constants. * eval.c (rb_eval): ditto. Tue May 8 08:52:57 2001 Akinori MUSHA * doc/forwardable.rd, doc/forwardable.rd.jp: Hit `=begin' and `=end' in proper places so rd2 can format them without a problem. * doc/irb/irb-tools.rd.jp, doc/irb/irb.rd, doc/irb/irb.rd.jp: ditto. Tue May 8 08:38:53 2001 Akinori MUSHA * doc/forwardable.rd, doc/forwardable.rd.jp, lib/forwardable.rb: Import forwardable 1.1. Tue May 8 08:34:33 2001 Akinori MUSHA * doc/irb/irb-tools.rd.jp, doc/irb/irb.rd.jp: Convert from JIS to EUC. Tue May 8 03:46:39 2001 Akinori MUSHA * sample/rbc.rb: Obsoleted by IRB. Mon May 7 15:58:45 2001 Yukihiro Matsumoto * parse.y (arg): "||=" should not warn for uninitialized instance variables. * eval.c (rb_eval): ditto. * eval.c (eval): preserve and restore ruby_cref as well. Mon May 7 15:45:48 2001 WATANABE Hirofumi * lib/ftools.rb (syscopy): chmod destination file only if it does not exist. Mon May 7 14:35:57 2001 Yukihiro Matsumoto * object.c (rb_obj_is_instance_of): takes only class/module as an argument. Sun May 6 16:27:29 2001 Koji Arai * eval.c (is_defined): rb_reg_nth_defined() may return Qnil. Thu May 3 03:15:06 2001 SHIROYAMA Takayuki * configure.in: get --enable-shared to work on MacOS X. * Makefile.in: make $(LIBRUBY_SO) depend on miniruby properly. Now `make -jN' should work without a problem. Thu May 3 02:07:45 2001 Usaku Nakamura * win32/config.h.in: add SIZEOF___INT64 definition. Wed May 2 20:39:35 2001 WATANABE Hirofumi * dir.c (rb_glob, rb_globi): remove unnecessary FNM_PATHNAME. Wed May 2 11:46:13 2001 K.Kosako * eval.c (block_pass): should not downgrade safe level. Wed May 2 03:07:49 2001 Yukihiro Matsumoto * ext/dbm/extconf.rb: allow specifying dbm-type explicitly. * ext/dbm/extconf.rb: avoid gdbm if possible, because it leaks memory, whereas gdbm.so doesn't. potential incompatibility. Wed May 2 02:02:18 2001 Yukihiro Matsumoto * string.c (rb_str_insert): new method. Tue May 1 17:55:58 2001 Yukihiro Matsumoto * parse.y (yylex): lex_state after RESCUE_MOD should be EXPR_BEG. Tue May 1 16:23:03 2001 Yukihiro Matsumoto * array.c (rb_ary_insert): new method. * array.c (rb_ary_update): new utility function. Tue May 1 03:24:05 2001 Akinori MUSHA * lib/irb/completion.rb, lib/irb/frame.rb, lib/irb/xmp.rb, doc/irb/irb-tools.rd.jp: Merge from irb-tools 0.7.1. Tue May 1 03:07:17 2001 Akinori MUSHA * sample/irb.rb, lib/irb.rb, lib/irb/*, doc/irb/*: Merge from irb 0.7.3. * instruby.rb: Install help-message's too. * lib/irb/main.rb: This file is not needed anymore. Fri Apr 27 09:27:10 2001 Yukihiro Matsumoto * io.c (set_outfile): should check if closed before assignment. Thu Apr 26 22:36:11 2001 WATANABE Hirofumi * configure.in: don't use tzname on Cygwin 1.3.1+. * configure.in: add -mieee/-ieee to CFLAGS on OSF1/Alpha to disable "DIVISION BY ZERO" exception. Thu Apr 26 22:30:43 2001 Yukihiro Matsumoto * eval.c (rb_eval): should preserve value of ruby_errinfo. Thu Apr 26 10:36:09 2001 Yukihiro Matsumoto * eval.c (rb_thread_schedule): infinite sleep should not cause dead lock. Wed Apr 25 16:40:44 2001 Yukihiro Matsumoto * array.c (rb_ary_flatten_bang): proper recursive detection. Wed Apr 25 15:36:15 2001 K.Kosako * eval.c (yield_under): need not to prohibit at safe level 4. Wed Apr 25 15:22:20 2001 Yukihiro Matsumoto * pack.c (pack_pack): p/P packs nil into NULL. * pack.c (pack_unpack): p/P unpacks NULL into nil. Tue Apr 24 15:35:32 2001 Yukihiro Matsumoto * pack.c (pack_pack): size check for P template. * ruby.c (set_arg0): wrong predicate when new $0 value is bigger than original space. Tue Apr 24 15:18:49 2001 Akinori MUSHA * ext/extmk.rb.in, lib/mkmf.rb: (dir_config) do not add the specified include directory if already included in $CPPFLAGS. * ext/extmk.rb.in, lib/mkmf.rb: (dir_config) return a more useful value, [include_dir, lib_dir]. Mon Apr 23 14:43:59 2001 Yukihiro Matsumoto * gc.c (id2ref): should use NUM2ULONG() * object.c (rb_mod_const_get): check whether name is a class variable name. * object.c (rb_mod_const_set): ditto. * object.c (rb_mod_const_defined): ditto. Sat Apr 21 22:33:26 2001 Yukihiro Matsumoto * marshal.c (w_float): precision changed to "%.16g" Sat Apr 21 22:07:58 2001 Guy Decoux * eval.c (rb_call0): wrong retry behavior. Fri Apr 20 19:12:20 2001 Yukihiro Matsumoto * numeric.c (fix_aref): a bug on long>int architecture. Fri Apr 20 14:57:15 2001 K.Kosako * eval.c (rb_eval_string_wrap): should restore ruby_wrapper. Sun Apr 22 17:44:37 2001 WATANABE Hirofumi * configure.in: add -mieee to CFLAGS on Linux/Alpha to disable "DIVISION BY ZERO" exception. * configure.in: remove -ansi on OSF/1. Wed Apr 18 04:37:51 2001 Wakou Aoyama * lib/cgi.rb: CGI::Cookie: no use PATH_INFO. Wed Apr 18 00:24:40 2001 Yukihiro Matsumoto * regex.c (re_compile_pattern): char class at either edge of range should be invalid. Tue Apr 17 17:33:55 2001 Yukihiro Matsumoto * eval.c (handle_rescue): use === to compare exception match. * error.c (syserr_eqq): comparison between SytemCallErrors should based on their error numbers. Tue Apr 17 16:54:39 2001 K.Kosako * eval.c (safe_getter): should use INT2NUM(). Tue Apr 17 15:12:56 2001 Yukihiro Matsumoto * bignum.c (rb_big2long): 2**31 cannot fit in 31 bit long. Sat Apr 14 22:46:43 2001 Guy Decoux * regex.c (calculate_must_string): wrong length calculation. Sat Apr 14 13:37:32 2001 Usaku Nakamura * win32/config.status.in: no longer use missing/alloca.c. * win32/Makefile.sub: ditto. Fri Apr 13 12:40:48 2001 K.Kosako * eval.c (rb_thread_start_0): fixed memory leak. Fri Apr 13 16:41:18 2001 Yukihiro Matsumoto * parse.y (none): should clear cmdarg_stack too. Fri Apr 13 06:19:29 2001 GOTOU Yuuzou * io.c (rb_fopen): use setvbuf() to avoid recursive malloc() on some platforms. Wed Apr 11 23:36:26 2001 Yukihiro Matsumoto * file.c (rb_stat_dev): device functions should honor stat field types (except long long such as dev_t). Wed Apr 11 18:07:53 2001 K.Kosako * eval.c (rb_mod_nesting): should not push nil for nesting array. * eval.c (rb_mod_s_constants): should not search array by rb_mod_const_at() for nil (happens for singleton class). Wed Apr 11 13:29:26 2001 Yukihiro Matsumoto * class.c (rb_singleton_class_attached): should modify iv_tbl by itself, no longer use rb_iv_set() to avoid freeze check error. * variable.c (rb_const_get): error message "uninitialized constant Foo at Bar::Baz" instead of "uninitialized constantBar::Baz::Foo". Tue Apr 10 17:52:10 2001 Yukihiro Matsumoto * eval.c (rb_mod_included): new hook called from rb_mod_include(). Tue Apr 10 02:24:40 2001 Nobuyoshi Nakada * io.c (opt_i_set): should strdup() inplace_edit string. Mon Apr 9 23:29:54 2001 Yukihiro Matsumoto * eval.c (exec_under): need to push cref too. Mon Apr 9 15:20:21 2001 Yukihiro Matsumoto * eval.c (rb_f_missing): raise NameError for "undefined local variable or method". * error.c (Init_Exception): new exception NoMethodError. NameError moved under ScriptError again. * eval.c (rb_f_missing): use NoMethodError instead of NameError. Mon Apr 9 12:05:44 2001 Yukihiro Matsumoto * file.c (Init_File): should redefine "new" class method. Mon Apr 9 11:56:52 2001 Shugo Maeda * lib/net/imap.rb: fix typo. Fri Apr 6 01:46:35 2001 Yukihiro Matsumoto * eval.c (PUSH_CREF): sharing cref node was problematic. maintain runtime cref list instead. * eval.c (rb_eval): copy defn node before registering. * eval.c (rb_load): clear ruby_cref before loading. Thu Apr 5 22:40:12 2001 Yukihiro Matsumoto * variable.c (rb_const_get): no recursion to show full class path for modules. * eval.c (rb_set_safe_level): should set safe level in curr_thread as well. * eval.c (safe_setter): ditto. Thu Apr 5 13:46:06 2001 K.Kosako * object.c (rb_obj_is_instance_of): nil belongs to false, not true. Thu Apr 5 02:19:03 2001 Yukihiro Matsumoto * time.c (make_time_t): proper (I hope) daylight saving time handling for both US and Europe. I HATE DST! * eval.c (rb_thread_wait_for): non blocked signal interrupt should stop the interval. Wed Apr 4 03:47:03 2001 Yukihiro Matsumoto * eval.c (proc_eq): class check added. * eval.c (proc_eq): typo fixed ("return" was omitted). * error.c (Init_Exception): move NameError under StandardError. * class.c (rb_mod_clone): should copy method bodies too. * bignum.c (bigdivrem): should trim trailing zero bdigits of remainder, even if dd == 0. * file.c (check3rdbyte): safe string check moved here. Tue Apr 3 09:56:20 2001 WATANABE Hirofumi * ext/extmk.rb.in (create_makefile): create def file only if it does not yet exist. * lib/mkmf.rb: ditto. Tue Apr 3 00:05:07 2001 Yukihiro Matsumoto * time.c (make_time_t): remove HAVE_TM_ZONE code since it sometimes reports wrong time. * time.c (make_time_t): remove unnecessary range check for platforms where negative time_t is available. Mon Apr 2 16:52:48 2001 Yukihiro Matsumoto * process.c (proc_waitall): should push Process::Status instead of Fixnum status. * process.c (waitall_each): should add all entries in pid_tbl. these changes are inspired by Koji Arai. Thanks. * process.c (proc_wait): should not iterate if pid_tbl is 0. * process.c (proc_waitall): ditto. Mon Apr 2 14:25:49 2001 Shugo Maeda * lib/monitor.rb (wait): ensure reentrance. * lib/monitor.rb (wait): fix timeout support. Mon Apr 2 12:40:45 2001 Shugo Maeda * lib/net/imap.rb (media_subtype): return subtype. Mon Apr 2 12:01:15 2001 Shugo Maeda * lib/net/imap.rb (flag_list): capitalize flags. Mon Apr 2 01:32:38 2001 Akinori MUSHA * Makefile.in: Introduce MAINLIBS. * configure.in: Link libc_r against the ruby executable on FreeBSD, which is the first attempt to work around a certain problem regarding pthread on FreeBSD. It should make ruby/libruby happy when it loads an extension to a library compiled and linked with -pthread. Note, however, that libruby is _not_ linked with libc_r so as not to mess up pthread unfriendly stuff including apache+mod_ruby and vim6+ruby_interp. Mon Apr 2 01:16:24 2001 WATANABE Hirofumi * win32/win32.c: use ruby's opendir on mingw32. * win32/dir.h, dir.c, Makefile: ditto. Sun Apr 1 23:26:14 2001 TOYOFUKU Chikanobu * numeric.c (flodivmod): a bug in no fmod case. Sun Apr 1 18:36:14 2001 Koji Arai * process.c (pst_wifsignaled): should apply WIFSIGNALED for status (int), not st (VALUE). Sat Mar 31 04:47:55 2001 Shugo Maeda * lib/net/imap.rb: add document and example code. Sat Mar 31 03:24:10 2001 Yukihiro Matsumoto * io.c (Init_IO): value of $/ and $\ are no longer restricted to strings. type checks are done on demand. * class.c (rb_include_module): module inclusion should be check taints. * ruby.h (STR2CSTR): replace to StringType() and StringTypePtr(). * ruby.h (rb_str2cstr): ditto. Fri Mar 30 23:37:49 2001 Yukihiro Matsumoto * eval.c (rb_load): should not copy toplevel local variables. It cause variable/method ambiguity. Thanks to L. Peter Deutsch. Fri Mar 30 22:56:56 2001 Shugo Maeda * lib/net/imap.rb: rename ContinueRequest to ContinuationRequest. Fri Mar 30 12:51:19 2001 Yukihiro Matsumoto * class.c (rb_include_module): freeze check at first. Thu Mar 29 17:05:09 2001 Yukihiro Matsumoto * eval.c (rb_attr): sprintf() and rb_intern() moved into conditional body. Wed Mar 28 23:43:00 2001 Nobuyoshi Nakada * ext/extmk.rb.in, lib/mkmf.rb: add C++ rules in addition to C rules for the mswin32 platforms. Wed Mar 28 19:29:21 2001 Akinori MUSHA * ext/extmk.rb.in, lib/mkmf.rb: move C++ rules to the right place. Wed Mar 28 17:39:04 2001 Yukihiro Matsumoto * object.c (rb_str2cstr): warn if string contains \0 and length value is ignored. Wed Mar 28 15:00:31 2001 K.Kosako * class.c (rb_singleton_class_clone): should copy class constant table as well. Wed Mar 28 14:23:23 2001 Yukihiro Matsumoto * class.c (rb_include_module): sometimes cache was mistakenly left uncleared - based on the patch by K.Kosako. * ruby.h: all Check_SafeStr()'s are replaced by SafeStr() to ensure 'to_str' be always effective. Wed Mar 28 09:52:33 2001 WATANABE Hirofumi * win32/Makefile.sub: disable global optimization. Tue Mar 27 15:00:54 2001 K.Kosako * eval.c (rb_mod_define_method): should have clear method cache. * eval.c (rb_mod_define_method): should have raised exception for type error. Tue Mar 27 14:48:17 2001 Yukihiro Matsumoto * ruby.h: changed "extern INLINE" to "static inline". Mon Mar 26 23:19:33 2001 WATANABE Hirofumi * time.c (rb_strftime): check whether strftime returns empty string. Mon Mar 26 21:16:56 2001 Shugo Maeda * lib/net/imap.rb: supports response handlers and multiple commands. Mon Mar 26 17:21:07 2001 Yukihiro Matsumoto * eval.c: remove TMP_PROTECT_END to prevent C_ALLOCA crash. Mon Mar 26 14:04:41 2001 WATANABE Hirofumi * ext/Win32API/Win32API.c: remove Init_win32api(). Sun Mar 25 16:52:48 2001 Koji Arai * file.c (rb_file_flock): do not trap EINTR. * missing/flock.c (flock): returns the value from lockf(2) directly. Sat Mar 24 23:44:50 2001 Yukihiro Matsumoto * eval.c (ev_const_defined): should ignore toplevel cbase (Object). * eval.c (ev_const_get): ditto. Fri Mar 23 17:37:52 2001 Yukihiro Matsumoto * ext/md5/md5.h: replace by independent md5 implementation contributed by L. Peter Deutsch (thanks). * ext/md5/md5init.c: adopted to Deutsch's md5 implementation. Fri Mar 23 17:26:19 2001 Yukihiro Matsumoto * pack.c (pack_unpack): string from P/p should be tainted. Fri Mar 23 12:18:44 2001 SHIROYAMA Takayuki * ext/curses/curses.c: curses on Mac OS X public beta does not have _maxx etc. Fri Mar 23 10:50:31 2001 Yukihiro Matsumoto * marshal.c (w_object): should truncate trailing zero short for bignums. Fri Mar 23 09:49:02 2001 Yukihiro Matsumoto * object.c (sym_intern): new method. Thu Mar 22 22:15:45 2001 WATANABE Hirofumi * ext/Win32API/extconf.rb: add -fno-omit-frame-pointer. Thu Mar 22 18:17:36 2001 Yukihiro Matsumoto * eval.c (rb_mod_nesting): should not include Object at the toplevel. Thu Mar 22 17:43:44 2001 Yukihiro Matsumoto * ruby.h: better inline function support. * configure.in (NO_C_INLINE): check if inline is available for the C compiler. Mon Mar 19 11:03:10 2001 Koji Arai * marshal.c (r_object): len calculation patch was wrong for machines SIZEOF_BDIGITS == SIZEOF_SHORT. * gc.c: alloca prototype reorganized for C_ALLOCA machine. Wed Mar 21 23:07:45 2001 WATANABE Hirofumi * win32/win32.c (win32_stat): WinNT/2k "//host/share" support. Wed Mar 21 08:05:35 2001 Nobuyoshi Nakada * win32/dir.h: replace missing/dir.h . * win32/win32.h: ditto. * win32/win32.c: ditto. Wed Mar 21 01:26:14 2001 Yukihiro Matsumoto * gc.c (id2ref): sometimes confused symbol and reference. Tue Mar 20 23:09:33 2001 WATANABE Hirofumi * win32/win32.c (win32_stat): UNC support. * dir.c (extract_path): fix "./*" problem. Tue Mar 20 15:10:00 2001 Yukihiro Matsumoto * dir.c (glob_helper): breaks loop after calling recursive glob_helper; all wild cards should be consumed; no need for further match. * dir.c (dir_s_glob): gives warning if no match found. Tue Mar 20 14:13:45 2001 Koji Arai * object.c (sym_inspect): did allocate extra byte space. Mon Mar 19 19:14:47 2001 Guy Decoux * marshal.c (shortlen): shortlen should return number of bytes written. Mon Mar 19 16:52:23 2001 K.Kosako * eval.c (ev_const_defined): need not to check if cbase->nd_class is rb_cObject. * eval.c (ev_const_get): ditto. Mon Mar 19 17:11:20 2001 Yukihiro Matsumoto * time.c (time_zone): return "UTC" for UTC time objects. Mon Mar 19 16:27:32 2001 Yukihiro Matsumoto * eval.c (THREAD_ALLOC): flags should be initialized. * signal.c (rb_f_kill): should use FIX2INT, not FIX2UINT. Mon Mar 19 10:55:10 2001 Yukihiro Matsumoto * dir.c (glob_helper): replace lstat() by stat() to follow symlink in the case like 'symlink/*'. * dir.c (glob_helper): gave warning too much. Sun Mar 18 08:58:18 2001 Wakou Aoyama * lib/cgi.rb: // === '' --> //.match('') * lib/cgi.rb: cgi#header(): improvement for mod_ruby. * lib/cgi.rb: cgi#rfc1123date(): improvement. thanks to TADA Tadashi . * lib/cgi.rb: cgi#rfc1123date(): document bug fix. thanks to Kazuhiro NISHIYAMA . * lib/cgi.rb: cgi#header(): bug fix. thanks to IWATSUKI Hiroyuki . Sat Mar 17 11:11:24 2001 Yukihiro Matsumoto * dir.c (glob_helper): * should follow symlink, whereas ** should not follow. Thu Mar 15 01:28:02 2001 Yukihiro Matsumoto * dir.c (dir_s_chdir): block form of Dir.chdir. (RCR#U016). Fri Mar 16 17:14:17 2001 Akinori MUSHA * configure.in: Set SOLIBS properly for all ELF and FreeBSD/NetBSD/OpenBSD a.out platforms so that the shlib dependencies are recorded in the libruby shlib. Wed Mar 14 16:41:45 2001 Yukihiro Matsumoto * eval.c (rb_thread_schedule): raise FATAL just once to THREAD_TO_KILL. Wed Mar 14 10:41:34 2001 Yukihiro Matsumoto * eval.c (rb_yield_0): 0 (= Qfalse) is a valid value, so that default self should be checked by klass == 0. * bignum.c (rb_cstr2inum): should disallow '++1', '+-1', etc. Tue Mar 13 17:51:09 2001 Yukihiro Matsumoto * eval.c (ev_const_defined): add new parameter self for special const fallback. * eval.c (ev_const_get): ditto. Tue Mar 13 16:39:45 2001 WATANABE Hirofumi * dir.c (rb_glob_helper): fix drive letter handling on DOSISH. Tue Mar 13 14:54:39 2001 Minero Aoki * lib/net/http.rb: add HTTPRequest#basic_auth. * lib/net/smtp.rb: raise if only account or password is given. * lib/net/protocol.rb: WriteAdapter#<< returns self. Tue Mar 13 14:41:16 2001 Yukihiro Matsumoto * io.c (argf_seek_m): wrong calling sequence of rb_io_seek(). Tue Mar 13 09:14:19 2001 Yukihiro Matsumoto * parse.y (cond0): no special treatment of string literal in condition. Mon Mar 12 18:59:38 2001 WATANABE Hirofumi * lib/mkmf.rb (create_makefile): save/restore $libs and $LIBPATH. Sun Mar 11 18:13:34 2001 Masahiro Tanaka * math.c: add acos, asin, atan, conh, sinh, tanh and hypot to Math. * configure.in: check hypot availability. * missing/hypot.c: public domain rewrite of hypot. Sun Mar 11 13:21:04 2001 Koji Arai * parse.y (warn_unless_e_option): warning condition was wrong. * parse.y (warning_unless_e_option): ditto. Sun Mar 11 00:55:31 2001 WATANABE Hirofumi * lib/mkmf.rb (install_rb): fix handling of destination path. Sat Mar 10 22:56:44 2001 Yukihiro Matsumoto * enum.c (enum_all): new method 'all?', which returns true if block returns true for all elements. * enum.c (enum_any): new method 'any?', which returns true if block returns true for any of elements. Sat Mar 10 02:34:18 2001 WATANABE Hirofumi * math.c (math_log, math_log10): use nan() instead of 0.0/0.0 on Cygwin. Fri Mar 9 09:56:19 2001 Yukihiro Matsumoto * marshal.c (marshal_load): do not give warning unless explicitly set to verbose. Fri Mar 9 02:07:53 2001 Yukihiro Matsumoto * eval.c (rb_exit): give string value "exit" to SystemExit. * ruby.c (proc_options): -v should not print version if proc_options called via moreswitches(). Thu Mar 8 17:45:19 2001 Minero Aoki * lib/net/protocol.rb: one write(2) per one line. Wed Mar 7 14:26:11 2001 WATANABE Hirofumi * math.c (math_log, math_log10): should return NaN if x < 0.0 on Cygwin. Thu Mar 7 10:31:26 2001 Nobuyoshi Nakada * parse.y (stmt): while/until modifier must work for empty body. Tue Mar 6 22:53:58 2001 Kazuhiro Yoshida * ruby.c (ruby_set_argv): clear ARGV contents before adding args. Tue Mar 6 10:50:29 2001 Yukihiro Matsumoto * parse.y (primary): rescue and ensure clauses should be allowed to appear in singleton method body. Mon Mar 5 17:25:13 2001 Yukihiro Matsumoto * eval.c (proc_eq): compare Procs using blocktag equality. * eval.c (proc_to_s): stringify according to block tag address. Mon Mar 5 17:19:56 2001 WATANABE Hirofumi * win32/win32.c (gettimeofday): use GetLocalTime() instead of ftime() for high-resolution timing. Sun Mar 4 17:01:09 2001 WATANABE Hirofumi * string.c (trnext): support backslash escape in String#tr. Sat Mar 3 16:15:16 2001 Yukihiro Matsumoto * eval.c (rb_eval): push cbase if ruby_cbase != ruby_class, for example in the case NODE_DEFN/NODE_DEFS are called within module_eval. Wed Feb 28 11:02:41 2001 Yukihiro Matsumoto * string.c (rb_str_delete_bang): delete! should take at least 1 argument. * ruby.c (load_file): add rb_gc() after loading to avoid extraordinary memory growth. Wed Feb 28 05:01:40 2001 Koji Arai * dir.c (rb_glob_helper): "./foo" should match "foo", not "./foo". Tue Feb 27 16:38:15 2001 Yukihiro Matsumoto * eval.c (ev_const_get): retrieve Object's constant if no current class is available (e.g. defining singleton class for Fixnums). * eval.c (ev_const_defined): check Object's constant if no current class is available (e.g. defining singleton class for Fixnums). * time.c (time_timeval): negative time interval should not be allowed. * eval.c (proc_call): ignore block to `call' always, despite of being orphan or not. Wed Feb 27 10:16:32 2001 Nobuyoshi Nakada * eval.c (rb_yield_0): should check based on rb_block_given_p() and rb_f_block_given_p(). Tue Feb 27 04:13:45 2001 Nobuyoshi Nakada * configure.in (frame-address): --enable-frame-address to allow __builtin_frame_address() to be used. * eval.c (stack_length): use __builtin_frame_address() based on the macro USE_BUILTIN_FRAME_ADDRESS. * gc.c (rb_gc): ditto. * gc.c (Init_stack): ditto. Mon Feb 26 16:20:27 2001 Yukihiro Matsumoto * ruby.c (proc_options): call ruby_show_version() just once. * dir.c (dir_s_open): returns the value from a block (if given). Mon Feb 26 14:29:04 2001 Akinori MUSHA * ext/extmk.rb.in, lib/mkmf.rb: add C++ rules in addition to C rules. Mon Feb 26 00:04:52 2001 Yukihiro Matsumoto * eval.c (proc_call): should not modify ruby_block->frame.iter based on ruby_frame->iter altered by PUSH_ITER(). Mon Feb 26 05:27:52 2001 Wakou Aoyama * lib/net/telnet.rb: #telnetmode(), #binmode(): bug fix. thanks to nobu.nakada@nifty.ne.jp. Mon Feb 26 04:55:50 2001 Wakou Aoyama * lib/cgi.rb: CGI#form(): bug fix. thanks to MoonWolf . * lib/cgi.rb: CGI#rfc1123_date(): improvement. thanks to Tomoyasu Akita . * lib/cgi.rb: CGI#header(): improvement for mod_ruby. thanks to Shugo Maeda . Sun Feb 25 02:45:30 2001 WATANABE Hirofumi * file.c (rb_file_s_rename): avoid Cygwin's bug. Sat Feb 24 23:32:55 2001 Yukihiro Matsumoto * eval.c (rb_thread_fd_close): should save current context before raising exception. Sat Feb 24 22:14:00 2001 WATANABE Hirofumi * win32/win32.c (myrename): fix error handling. Sat Feb 24 13:58:48 2001 Minero Aoki * lib/net/http.rb: always close connection on request without body. * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: change copyright. Sat Feb 24 03:15:49 2001 Yukihiro Matsumoto * io.c (set_stdin): preserve original stdin. * io.c (set_outfile): preserve original stdout/stderr. Fri Feb 23 08:28:58 2001 Minero Aoki * lib/net/protocol.rb: clear read buffer after reopen. * lib/net/protocol.rb: refactoring. * lib/net/http.rb: split module HTTPHeader from HTTPResponse. Tue Feb 20 23:45:35 2001 WATANABE Hirofumi * process.c: add W* macro if not available. Tue Feb 20 16:37:58 2001 Yukihiro Matsumoto * configure.in: add check for negative time_t for gmtime(3). * time.c (time_new_internal): no positive check if gmtime(3) can handle negative time_t. * time.c (time_timeval): ditto. * bignum.c (rb_big2long): should not raise RangeError for Bignum LONG_MIN value. Mon Feb 19 17:46:37 2001 Yukihiro Matsumoto * string.c (rb_str_substr): "a"[1,2] should return ""; need rubicon upgrade. Mon Feb 19 12:10:36 2001 Triet H. Lai * error.c (rb_sys_warning): new function to give warning with strerror() message. * dir.c (rb_glob_helper): better error handling, along with performance tune. Mon Feb 19 01:55:43 2001 Yukihiro Matsumoto * eval.c (secure_visibility): visibility check for untainted modules. Mon Feb 19 00:29:29 2001 Nobuyoshi Nakada * signal.c (sigpipe): sighandler which does nothing. * signal.c (trap): set sigpipe function for SIGPIPE. * signal.c (Init_signal): default SIGPIPE handler should be sigpipe function. Sun Feb 18 15:42:38 2001 WATANABE Hirofumi * ext/curses/extconf.rb: add dir_config. * missing/flock.c: use fcntl(2) instead of lockf(2). Sun Feb 18 05:46:03 2001 Minero Aoki * lib/net/http.rb: Response#range_length was not debugged. Sun Feb 18 04:02:03 2001 Yasushi Shoji * array.c (rb_ary_subseq): wrong boundary check. Sun Feb 18 00:09:50 2001 Nobuyoshi Nakada * win32/win32.c: make file I/O faster on mswin32/mingw32. * win32/win32.h: ditto. * rubysig.h: ditto. Sat Feb 17 23:32:45 2001 Yukihiro Matsumoto * parse.y (cond0): integer literal in condition should not be compared to lineno ($.). Fri Feb 16 01:44:56 2001 Yukihiro Matsumoto * io.c (set_outfile): f should be the FILE* from the assigning value. * ext/socket/socket.c (tcp_s_open): should not give default value to local_host. * time.c (time_s_times): move to Process::times. * file.c (rb_file_s_lchmod): new method File::lchmod. * file.c (rb_file_s_lchown): new method File::lchown. Thu Feb 15 11:33:49 2001 Shugo Maeda * lib/cgi/session.rb (close): fixed reversed condition. Thu Feb 15 08:34:14 2001 Yukihiro Matsumoto * process.c (proc_waitall): new method based on a patch from Brian Fundakowski Feldman . * process.c (last_status_set): objectify $? value (Process::Status). Wed Feb 14 17:28:24 2001 Shugo Maeda * lib/net/imap.rb: supports unknown resp_text_code. Wed Feb 14 00:44:17 2001 Yukihiro Matsumoto * dir.c (dir_s_glob): support backslash escape of metacharacters and delimiters. * dir.c (remove_backslases): remove backslashes from path before calling stat(2). * dir.c (dir_s_glob): call rb_yield directly (via push_pattern) if block is given to the method. * dir.c (push_pattern): do not call rb_ary_push; yield directly. * eval.c (blk_copy_prev): reduced ALLOC_N too much. * eval.c (frame_dup): ditto. Tue Feb 13 23:05:38 2001 WATANABE Hirofumi * dir.c (lstat): should use rb_sys_stat if lstat(2) is not available. Tue Feb 13 08:43:10 2001 Yukihiro Matsumoto * io.c (rb_io_ctl): do not call ioctl/fcntl for f2, if f and f2 have same fileno. Tue Feb 13 01:13:43 2001 Yukihiro Matsumoto * eval.c (rb_load): raise LocalJumpError if unexpected local jumps appear during load. * ext/socket/socket.c (bsock_close_read): don't call rb_thread_fd_close(); it's supposed to be called by io_io_close(). * ext/socket/socket.c (bsock_close_read): do not modify f and f2. * ext/socket/socket.c (bsock_close_write): ditto. * ext/socket/socket.c (sock_new): avoid dup(2) on sockets. * parse.y (primary): preserve and clear in_single and in_def using stack to prevent nested method errors in singleton class bodies. Sun Feb 11 16:00:30 2001 WATANABE Hirofumi * eval.c (stack_length): use __builtin_frame_address() only if GCC and i386 CPU. * gc.c (rb_gc, Init_stack): ditto. * configure.in: add ac_cv_func_getpgrp_void=yes on DJGPP. Sat Feb 10 23:43:49 2001 Nobuyoshi Nakada * hash.c (rb_any_hash): dumped core on machines sizeof(int) != sizeof(long). Sat Feb 10 23:07:15 2001 Yukihiro Matsumoto * io.c (rb_io_s_for_fd): IO::for_fd(fd) - new method. * regex.c (PREV_IS_A_LETTER): should not treat c>0x7f as a word character if -Kn. Sat Feb 10 00:00:30 2001 Nobuyoshi Nakada * win32/win32.c (win32_stat): replace stat to enable when pathname ends with '/' or '\' for mswin32 on Win9X / Win2k. * win32/win32.h: ditto. * ruby.h: ditto. * dir.c (rb_glob_helper): ditto. * file.c (rb_stat, rb_file_s_stat, eaccess, check3rdbyte): ditto. Fri Feb 9 22:54:57 2001 WATANABE Hirofumi * ruby.c (ruby_init_loadpath): convert '\\' to '/' before finding executable file path. Fri Feb 9 17:41:53 2001 Triet H. Lai * dir.c (rb_glob_helper): do not follow symbolic links. Thu Feb 8 21:27:24 2001 WATANABE Hirofumi * lib/mkmf.rb (install_rb): fix handling of relative path. * lib/mkmf.rb (create_makefile): add srcdir. Thu Feb 8 02:22:09 2001 Minero Aoki * lib/net/http.rb: join HTTPReadResponse into HTTPResponse again. * lib/net/http.rb: move http_version() from HTTPRequest to HTTPResponse. * lib/net/protocol.rb: refactoring. Wed Feb 7 16:27:27 2001 Minero Aoki * lib/net/http.rb: split HTTPResponse into HTTPReadResponse module. * lib/net/protocol.rb: add Net::net_private. * lib/net/protocol.rb: Socket#reopen takes arg, open_timeout. Wed Feb 7 16:05:22 2001 Nobuyoshi Nakada * parse.y (parse_quotedwords): %w should allow parenthesis escape. Wed Feb 7 00:57:42 2001 Yukihiro Matsumoto * parse.y (parse_qstring): %q should allow terminator escape. * re.c (rb_reg_options): new method to give an option values. * parse.y (cond0): disable special treating of integer literal in conditional unless option -e is supplied. changes current behavior. experimental. * parse.y (cond0): give warning for string/integer literals and dot operators in conditionals unless option -e is supplied. * re.c (rb_reg_equal): all option flags should be same to be equal. Tue Feb 6 21:30:44 2001 Minero Aoki * lib/net/http.rb: call on_connect() on re-opening socket. * lib/net/pop.rb: also POP3 can use APOP auth. Tue Feb 6 20:19:10 2001 Minero Aoki * lib/net/http.rb: add HTTP#request. * lib/net/http.rb: take HTTP 1.0 server into account (incomplete). * lib/net/protocol.rb: timeout for open/read. * lib/net/protocol.rb: add Protocol#on_connect,on_disconnect. Mon Feb 5 23:15:46 2001 Yukihiro Matsumoto * error.c (Init_Exception): make Interrupt a subclass of SignalException. Mon Feb 5 00:39:06 2001 KANEKO Naoshi * dir.c: use ISXXX() instead of isxxx(). * dln.c (aix_loaderror): ditto. * file.c (rb_file_s_expand_path): ditto. * string.c (rb_str_upcase_bang): ditto. * win32/win32.c (do_spawn): ditto. * win32/win32.c (NtMakeCmdVector): ditto. * win32/win32.c (opendir): ditto. Sat Feb 3 14:44:53 2001 Nobuyoshi Nakada * configure.in (AC_C_INLINE): check inline attribute. * gc.c (is_pointer_to_heap): use inline rather than __inline__. * pack.c (hex2num): ditto. * ruby.h (rb_class_of, rb_type, rb_special_const_p): ditto. * util.c (rb_class_of, rb_type, rb_special_const_p): defined in ruby.h. Fri Feb 2 16:14:51 2001 Yukihiro Matsumoto * array.c (rb_ary_sort_bang): returns self, even if its length is less than 2. * eval.c (POP_VARS): propagate DVAR_DONT_RECYCLE, if SCOPE_DONT_RECYCLE of ruby_scope is set. Wed Jan 31 22:27:29 2001 WATANABE Hirofumi * configure.in: gcc-2.95.2-7(Cygwin) support. add -mwin32 if available. * cygwin/GNUmakefile: ditto. Tue Jan 30 17:56:48 2001 Yukihiro Matsumoto * array.c (rb_ary_fetch): new method. Mon Jan 29 17:36:19 2001 TOYOFUKU Chikanobu * eval.c (rb_eval): nd_iter evaluation should be wrapped by BEGIN_CALLARGS and END_CALLARGS. Mon Jan 29 14:25:39 2001 Yukihiro Matsumoto * eval.c (block_pass): return from block jumps directory to block invoker. Mon Jan 29 01:40:27 2001 Yukihiro Matsumoto * string.c (str_independent): should not clear str->orig here. it's too early. Fri Jan 26 01:42:40 2001 Yukihiro Matsumoto * parse.y: clarify do ambiguity, bit more complex but natural from my point of view. Wed Jan 24 14:58:08 2001 Akinori MUSHA * lib/cgi.rb: fix the problem that when running under mod_ruby header() outputs only one Set-Cookie line. Wed Jan 24 01:45:49 2001 Yukihiro Matsumoto * eval.c (POP_BLOCK_TAG): call rb_gc_force_recycle() if block has not been objectified. * eval.c (rb_callcc): should nail down block->tag history to avoid rb_gc_force_recycle(). Tue Jan 23 18:51:57 2001 Yukihiro Matsumoto * gc.c (rb_gc_call_finalizer_at_exit): should finalize objects in deferred_final_list too. Tue Jan 23 16:10:12 2001 Yukihiro Matsumoto * gc.c (os_live_obj): do not list terminated object. * gc.c (os_obj_of): ditto. * gc.c (rb_gc_mark): support new T_BLKTAG tag. * gc.c (obj_free): ditto. * eval.c (new_blktag): creation of new block tag, which holds destination of global jump and orphan status. * eval.c (block_pass): break from orphan Proc object will raise a LocalJumpError exception. Mon Jan 22 16:33:16 2001 WATANABE Hirofumi * mkconfig.rb: autoconf 2.49 support. Mon Jan 22 00:32:44 2001 Yukihiro Matsumoto * eval.c (block_pass): behavior consistency with proc_call(). do not propagate `break'. Sat Jan 20 03:54:00 2001 Yukihiro Matsumoto * parse.y (yylex): fixed serious syntax misbehavior. do's preceding was too high. a block in `foo bar do .. end' should be passed to `foo', not `bar'. * parse.y (block_call): syntax restructure. Thu Jan 18 04:28:14 2001 Yukihiro Matsumoto * io.c (rb_io_s_read): new method to call IO#read from pathname. In addition, it accepts third optional argument to specify starting point. Wed Jan 17 13:28:26 2001 WATANABE Hirofumi * configure.in: remove DEFS definition. * mkconfig.rb: ditto. * win32/config.status.in: ditto. Tue Jan 16 17:00:50 2001 Minero Aoki * lib/net/protocol.rb: ignore EOFError for read. * lib/net/http.rb: user specified header was not used. Mon Jan 15 16:00:07 2001 Yukihiro Matsumoto * pack.c (pack_unpack): should check associated pointer packed by pack("P"). Thus pointers can be retrieved only from pointer packed strings. restriction added. Sun Jan 14 21:49:28 2001 Koji Arai * sprintf.c (rb_f_sprintf): simple typo. binary base should be 2, not '2'. * re.c (rb_reg_s_last_match): should explicitly return nth match. Sun Jan 14 18:21:30 2001 Usaku Nakamura * win32/config.status.in: add some field. * win32/win32.c (isInternalCmd): ignore case for shell's internal command. * win32/win32.c (do_spawn): recognize quoted command line. Sun Jan 14 04:10:27 2001 Minero Aoki * lib/net/protocol.rb (adding): too few "yield" in case of arg is not String/File. * lib/net/http.rb: add http request object. Sat Jan 13 19:39:30 2001 WATANABE Hirofumi * re.c (rb_reg_desc): separate RE_OPTION_MULTILINE * re.c (rb_reg_options): add RE_OPTION_{POSIXLINE,RE_OPTION_MULTILINE, RE_OPTION_EXTENDED} Thu Jan 11 10:45:04 2001 WATANABE Hirofumi * win32/win32.h, win32/config.h.in: move NORETURN from win32.h to config.h.in. * win32/config.h.in (inline): renamed from INLINE. * djgpp/config.hin (INLINE): removed. Thu Jan 11 06:45:55 2001 Yukihiro Matsumoto * object.c (rb_mod_dup): should propagate FL_SINGLETON. * object.c (inspect_obj): handles the case of no instance variable. Wed Jan 10 16:15:08 2001 WATANABE Hirofumi * ruby.h: NORETURN macro is changed for VC++ 6.0. * eval.c, intern.h: ditto. * djgpp/config.hin, win32/win32.h: ditto. * configure.in: ditto. Wed Jan 10 13:54:53 2001 WATANABE Hirofumi * process.c (proc_setuid): use setresuid() if available. * process.c (proc_setgid): use setresgid() if available. * configure.in: ditto. Wed Jan 10 01:50:45 2001 Yukihiro Matsumoto * configure.in (AC_C_INLINE): check inline attribute. * string.c (rb_str_reverse_bang): forgot to call rb_str_modify(). Tue Jan 9 17:41:40 2001 Yukihiro Matsumoto * object.c (rb_obj_taint): check frozen status before modifying taint status. * object.c (rb_obj_untaint): ditto. Tue Jan 9 16:22:14 2001 Yukihiro Matsumoto * enum.c (enum_inject): new method. Tue Jan 9 02:16:42 2001 Yukihiro Matsumoto * gc.c (rb_gc_call_finalizer_at_exit): clear klass member of terminating object. * eval.c (rb_call): raise exception for terminated object. Mon Jan 8 21:24:37 2001 Yukihiro Matsumoto * bignum.c (bigdivrem): t2 might be too big for signed long; do not use rb_int2big(), but rb_uint2big(). Mon Jan 8 21:35:10 2001 Guy Decoux * file.c (path_check_1): should restore modified path. Mon Jan 8 03:09:58 2001 Yukihiro Matsumoto * error.c (rb_load_fail): new func to report LoadError. * ruby.c (load_file): use rb_load_fail. Sat Jan 6 00:17:18 2001 WATANABE Hirofumi * pack.c (pack_pack): avoid infinite loop(pack 'm2'). Fri Jan 5 01:02:17 2001 Yukihiro Matsumoto * eval.c (ruby_finalize): should enclosed by PUSH_TAG/POP_TAG. * gc.c (rb_gc_mark): link 2 of NODE_IFUNC should not be explicitly marked. it may contain non object pointer. Tue Jan 2 00:20:06 2001 Yukihiro Matsumoto * re.c (reg_s_last_match): Regexp::last_match(nth) returns nth substring of the match (alternative for $& and $). Sun Dec 31 01:39:16 2000 Guy Decoux * eval.c (rb_mod_define_method): wrong comparison for blocks. Sat Dec 30 19:28:50 2000 Yukihiro Matsumoto * gc.c (id2ref): should handle Symbol too. * gc.c (id2ref): should print original ptr value Sat Dec 30 03:14:22 2000 Yukihiro Matsumoto * eval.c (rb_iterate): NODE_CFUNC does not protect its data (nd_tval), so create new node NODE_IFUNC for iteration C function. * eval.c (rb_yield_0): use NODE_IFUNC. * gc.c (rb_gc_mark): support NODE_IFUNC. Fri Dec 29 11:41:55 2000 Yukihiro Matsumoto * gc.c (mem_error): prohibit recursive mem_error(). (ruby-bugs-ja:PR#36) Fri Dec 29 11:05:41 2000 Yukihiro Matsumoto * eval.c (rb_thread_fd_writable): should not switch context if rb_thread_critical is set. * eval.c (rb_thread_wait_fd): ditto. * eval.c (rb_thread_wait_for): ditto. * eval.c (rb_thread_select): ditto. * eval.c (rb_thread_join): join during critical section causes deadlock. Fri Dec 29 00:38:46 2000 Yukihiro Matsumoto * m17n.c: new file - core functions of M17N. Tue Dec 26 18:46:41 2000 NAKAMURA, Hiroshi * lib/debug.rb: Avoid thread deadlock in debugging stopped thread. * lib/debug.rb: Uncleared 'finish' state. Tue Dec 26 16:53:55 2000 Yukihiro Matsumoto * eval.c (rb_yield_0): remove dvar node by rb_gc_force_recycle() more eagerly. * eval.c (rb_f_binding): recycling should be stopped for outer scope too. * eval.c (proc_new): ditto. Tue Dec 26 15:45:35 2000 Yukihiro Matsumoto * string.c (rb_str_inspect): should treat multibyte characters properly. Mon Dec 25 17:49:08 2000 K.Kosako * string.c (rb_str_replace_m): unexpected string share happens if replace is done for associated (STR_NO_ORIG) string. Tue Dec 26 15:01:53 2000 Yukihiro Matsumoto * io.c (rb_f_p): should not call rb_io_flush() if rb_defout is not a IO (T_FILE). Mon Dec 25 15:52:39 2000 Yukihiro Matsumoto * stable version 1.6.2 released. Mon Dec 25 05:11:04 2000 Wakou Aoyama * lib/cgi.rb: version 2.1.2 (some bug fixes). * lib/cgi.rb: Regexp::last_match[1] --> $1 * lib/net/telnet.rb: ditto. Mon Dec 25 04:43:02 2000 Minero Aoki * lib/net/http.rb: does not send HEAD on closing socket. Mon Dec 25 00:44:48 2000 Yukihiro Matsumoto * hash.c (rb_any_cmp): should use rb_str_cmp() if TYPE == T_STRING and CLASS_OF == rb_cString. * string.c (rb_str_new4): should copy class of original too. Mon Dec 25 00:04:54 2000 Nobuyoshi Nakada * eval.c (rb_thread_schedule): initial value of `max' changed to -1. Mon Dec 25 00:16:14 2000 Yukihiro Matsumoto * string.c (rb_str_replace_m): copy-on-write replace. * parse.y (yylex): should handle => after identifier as well as == and =~. Sat Dec 23 23:55:57 2000 Yukihiro Matsumoto * bignum.c (rb_cstr2inum): Integer("") should not return 0. Sat Dec 23 11:55:57 2000 Yukihiro Matsumoto * array.c (rb_ary_and): Array#& should preserve original order. Sat Dec 23 03:44:16 2000 Minero Aoki * lib/net/protocol.rb: set @closed false in Socket#reopen. * lib/net/pop.rb: add POP3.foreach, delete_all. * lib/net/pop.rb: add POP3#delete_all. * lib/net/http.rb: add HTTP.version_1_1, version_1_2 * lib/net/http.rb: refactoring. Fri Dec 22 23:11:12 2000 Ueno Katsuhiro * eval.c (rb_feature_p): ext might be null. Fri Dec 22 17:04:12 2000 Nobuyoshi Nakada * win32/win32.c (myselect): avoid busy loop by adjusting fd_count. Fri Dec 22 15:07:55 2000 Yukihiro Matsumoto * bignum.c (rb_cstr2inum): prefix like '0x' had removed too much. Thu Dec 21 13:01:46 2000 Tanaka Akira * lib/net/ftp.rb (makeport): don't use TCPsocket.getaddress. Wed Dec 20 12:00:15 2000 Yukihiro Matsumoto * bignum.c (rb_big_lshift): should cast up to BDIGIT_DBL. * parse.y (yylex): disallow trailing '_' for numeric literals. * bignum.c (rb_cstr2inum): allow `_' within converting string. * eval.c (specific_eval): should take no argument if block is supplied. Tue Dec 19 13:44:50 2000 K.Kosako * io.c (rb_f_p): should flush rb_defout, not stdout. Tue Dec 19 00:57:10 2000 Yukihiro Matsumoto * time.c (time_minus): usec might overflow. (ruby-bugs-ja:PR#35) * eval.c (rb_obj_extend): Object#extend should take at least one argument. * parse.y (mrhs_basic): should check value_expr($3), not $1. Mon Dec 18 23:18:39 2000 WATANABE Hirofumi * util.c (mblen, __crt0_glob_function): add for multibyte on DJGPP 2.03. Mon Dec 18 18:10:30 2000 Yukihiro Matsumoto * time.c (time_plus): usec might underflow (ruby-bugs-ja:#PR33). Mon Dec 18 08:11:20 2000 Yukihiro Matsumoto * hash.c (rb_hash_set_default): should call rb_hash_modify(). Sat Dec 16 02:58:26 2000 Minero Aoki * eval.c (rb_eval): should clear ruby_errinfo on retry. * eval.c (rb_rescue2): ditto. Thu Dec 14 13:06:18 2000 Nobuyoshi Nakada * class.c (rb_include_module): prohibit frozen class/module. * eval.c (rb_frozen_class_p): make external. * intern.h (rb_frozen_class_p): prototyped. * intern.h (rb_undef): prototyped not but rb_undef_method() which is also in ruby.h. Thu Dec 14 09:20:26 2000 Wakou Aoyama * lib/cgi.rb: support -T1 on ruby 1.6.2 * lib/cgi.rb: $1 --> Regexp::last_match[1] * lib/net/telnet.rb: ditto. Wed Dec 13 23:27:06 2000 Yukihiro Matsumoto * eval.c (rb_eval): handles case statement without expr, which looks for any TRUE (non nil, non false) when expression. * parse.y (primary): case expression should not be compstmt, but mere expr. * parse.y (primary): case without following expression is now separated rule. Wed Dec 13 12:41:27 2000 WATANABE Hirofumi * ruby.c (proc_options): accept "--^M" for DOS line endings. Tue Dec 12 15:45:42 2000 Yukihiro Matsumoto * parse.y (newline_node): cancel newline unification. Mon Dec 11 23:01:57 2000 Yukihiro Matsumoto * parse.y (yylex): supports cases `?' precedes EOF and newline. Mon Dec 11 12:11:25 2000 Yukihiro Matsumoto * eval.c (call_end_proc): some frame members were left uninitialized. Mon Dec 11 01:14:58 2000 Yukihiro Matsumoto * io.c (rb_io_fptr_finalize): do not fclose stdin, stdout and stderr at exit. Sat Dec 9 17:34:48 2000 Tachino Nobuhiro * time.c (time_cmp): should check with kind_of?, not instance_of? * time.c (time_eql): ditto. * time.c (time_minus): ditto. Fri Dec 8 17:23:25 2000 Tachino Nobuhiro * sprintf.c (rb_f_sprintf): proper string precision treat. Fri Dec 8 10:44:05 2000 Yukihiro Matsumoto * variable.c (rb_mod_remove_cvar): Module#remove_class_variable added. Thu Dec 7 17:35:51 2000 Shugo Maeda * eval.c (stack_length): don't use __builtin_frame_address() on alpha. Wed Dec 6 18:07:13 2000 WATANABE Hirofumi * djgpp/config.sed, win32/Makefile.sub: typo. * eval.c (rb_mod_define_method): avoid VC4.0 warnings. Wed Dec 6 13:38:08 2000 Yukihiro Matsumoto * array.c (rb_ary_and): tuning, make hash from shorter operand. Wed Dec 6 01:28:50 2000 SHIROYAMA Takayuki * gc.c (rb_gc): __builtin_frame_address() should not be used on MacOS X. * gc.c (Init_stack): ditto. Mon Dec 4 13:44:01 2000 WATANABE Hirofumi * lib/jcode.rb: consider multibyte. not /n. Mon Dec 4 09:49:36 2000 Yukihiro Matsumoto * string.c (rb_str_inspect): output whole string contents. no more `...' * string.c (rb_str_dump): should propagate taintness. * hash.c (env_inspect): hash like human readable output. * variable.c (rb_ivar_get): prohibiting instance variable access is too much restriction. * class.c (method_list): retrieving information should not be restricted where $SAFE=4. * class.c (rb_obj_singleton_methods): ditto. * eval.c (rb_thread_priority): ditto. * eval.c (rb_thread_local_aref): ditto. * variable.c (rb_obj_instance_variables): ditto. * variable.c (rb_mod_const_at): ditto. * variable.c (rb_mod_class_variables): ditto. * eval.c (rb_exec_end_proc): end_proc should be preserved. Sat Dec 2 22:32:43 2000 Yukihiro Matsumoto * eval.c (rb_yield_0): || should accept exactly zero argument. * parse.y (stmt): multiple right hand side for single assignment (e.g. a = 1,2) is allowed. Wed Nov 29 07:55:29 2000 Yukihiro Matsumoto * marshal.c (w_long): dumping long should be smaller than 32bit max. * marshal.c (w_long): shorter long format for small integers(-123..122). * marshal.c (r_long): ditto. Tue Nov 28 18:10:51 2000 Yukihiro Matsumoto * eval.c (rb_mod_define_method): quick hack to implement on-the-fly method definition. experimental. Mon Nov 27 17:00:35 2000 Yukihiro Matsumoto * eval.c (rb_eval): should not redefine builtin classes/modules from within wrapped load. Mon Nov 27 08:57:33 2000 Yukihiro Matsumoto * eval.c (call_end_proc): should be isolated from outer block. Mon Nov 27 00:10:08 2000 Yukihiro Matsumoto * io.c (rb_io_ctl): call ioctl/fcntl for fptr->f2 too. * process.c (rb_f_fork): call rb_thread_atfork() after creating child process. * eval.c (rb_thread_atfork): kill all other threads immediately, then turn the current thread into the main thread. Sat Nov 25 23:12:22 2000 Yukihiro Matsumoto * eval.c (ruby_run): move calling point of rb_trap_exit after cleaning up threads. * eval.c (ruby_finalize): new function to call EXIT trap, END procs and GC finalizers. * eval.c (rb_exec_end_proc): prevent recursion. * gc.c (rb_gc_call_finalizer_at_exit): ditto. * signal.c (rb_trap_exit): ditto. made static. * process.c (rb_f_fork): should swallow all exceptions from block execution. * process.c (fork_rescue): should call ruby_finalize(). * parse.y (yycompile): rb_gc() removed. I don't remember why I put this here. test code? Fri Nov 24 22:03:48 2000 Yukihiro Matsumoto * range.c (EXCL): exclusive information is now stored in an instance variable. this enables proper marshal dump. * process.c (proc_waitpid): should clear rb_last_status ($?) if no pid was given by waitpid(2). Thu Nov 23 01:35:38 2000 Yukihiro Matsumoto * process.c (proc_waitpid2): returns nil if no pid found. Wed Nov 22 23:45:15 2000 Yukihiro Matsumoto * range.c (range_eq): new method. Compares start and end of range respectively. Wed Nov 22 11:01:32 2000 Yukihiro Matsumoto * variable.c (rb_mod_class_variables): should honor singleton class variable rule defined yesterday. Tue Nov 21 23:24:14 2000 Mitsuteru S Nakao * numeric.c (flodivmod): missing second operand (typo). Tue Nov 21 03:39:41 2000 Yukihiro Matsumoto * marshal.c (marshal_load): marshal format compatibility check revised. greater minor revision is UPWARD compatible; downward compatibility is not assured. * eval.c (is_defined): clarify class variable behavior for singleton classes. class variables within singleton class should be treated like within singleton method. Mon Nov 20 13:45:21 2000 Yukihiro Matsumoto * eval.c (rb_eval): set ruby_sourceline before evaluating exceptions. * gc.c (gc_sweep): defer finalization in GC during compilation or interrupt prohibit section. * gc.c (gc_sweep): mark all nodes before sweeping if GC happened during compilation. * eval.c (rb_eval): should treat class variables specially in a method defined in the singleton class. Mon Nov 20 10:20:21 2000 WATANABE Hirofumi * dir.c, win32/win32.c, ruby.h: add rb_iglob(). Mon Nov 20 00:18:16 2000 Yukihiro Matsumoto * array.c (rb_ary_subseq): should return nil for outbound start index. * marshal.c (marshal_load): show format versions explicitly when format version mismatch happens. Sun Nov 19 06:13:24 2000 Kazuhiro NISHIYAMA * marshal.c: use long for string/array length. * pack.c (swaps): use bit-or(|) instead of plus(+). * pack.c (swapl): ditto. Sat Nov 18 15:18:16 2000 Kazuhiro NISHIYAMA * array.c (rb_ary_replace): array size should be in long. * array.c (rb_ary_concat): ditto. * array.c (rb_ary_hash): ditto. Sat Nov 18 14:07:20 2000 Minero Aoki * lib/net/http.rb: Socket#readline() reads until "\n", not "\r\n" Fri Nov 17 14:55:18 2000 WATANABE Hirofumi * string.c (rb_str_succ): output should be NUL terminated. Fri Nov 17 02:54:15 2000 Yukihiro Matsumoto * io.c (rb_io_close): need not to flush before closing. * eval.c (rb_thread_join): should preserve last thread status when THREAD_TO_KILL. * eval.c (rb_thread_stop): ditto. * io.c (io_fflush): wrap fflush by TRAP_BEG, TRAP_END. * eval.c (rb_eval): method defined within singleton class definition should behave like singleton method about class variables. * eval.c (is_defined): ditto. Thu Nov 16 23:06:07 2000 Minero Aoki * lib/net/http.rb: can call {old,new}_implementation any times. * lib/net/http.rb: HTTP#connecting, receive -> common_oper, connecting. * lib/net/http.rb: output warning if u_header includes duplicated header. * lib/net/http.rb: not check Connection:/Proxy-Connection; always read until eof. * lib/net/protocol.rb: detects and catches "break" from block. Thu Nov 16 16:32:45 2000 Masahiro Tanaka * bignum.c (bigdivrem): should have incremented ny first. Thu Nov 16 14:58:00 2000 Nobuyoshi Nakada * ext/socket/socket.c (sock_new): duplicates file descriptor with myfddup() on mswin32/mingw32. * win32/win32.h: uses system original fdopen(). * win32/win32.c (myfddup): newly added instead of myfdopen(). * win32/win32.c (mybind, myconnect, mygetsockname, mygetsockopt, mylisten, mysetsockopt): now accept file descriptor only, not SOCKET. * win32/win32.c (myaccept, mysocket): return file descriptor, instead of SOCKET. Thu Nov 16 10:23:24 2000 Yukihiro Matsumoto * eval.c (massign): too strict check for nameless rest argument. * eval.c (method_arity): mere * should return -1. * eval.c (intersect_fds): should check all FDs in the fd_set. Wed Nov 15 19:33:20 2000 Nobuyoshi Nakada * eval.c (rb_attr): should clear method cache before calling hook. * eval.c (rb_eval): ditto. * eval.c (rb_mod_modfunc): ditto. Mon Nov 13 22:44:52 2000 Yukihiro Matsumoto * error.c (rb_bug): print version to stderr. Mon Nov 13 19:02:08 2000 WATANABE Hirofumi * win32/win32.c, io.c, process.c: the exit status of program must be multiplied 256 on mswin32 and msdosdjgpp(system(), ``). Sat Nov 11 22:57:38 2000 Yukihiro Matsumoto * parse.y (arg): uniformed treatment of -a**b, where a is a number literal; hacky but behavior appears more consistent. * parse.y (newline_node): reduce newline node (one per line). * random.c (rb_f_srand): should be prohibited in safe level greater than 4. Sat Nov 11 22:37:36 2000 Nobuyoshi Nakada * rubysig.h: do not use rb_trap_immediate on win32. * rubysig.h: new macros, ATOMIC_TEST, ATOMIC_SET, ATOMIC_INC, ATOMIC_DEC, RUBY_CRITICAL and new definition of TRAP_BEG, TRAP_END. * gc.c (ruby_xmalloc): should wrap malloc() by RUBY_CRITICAL. * signal.c (sighandle): better win32 sig handling. * win32/win32.c (flock): better implementation. * win32/win32.c (myselect): ditto. * win32/win32.c (myaccept): ditto. * win32/win32.c (waitpid): ditto. * win32/win32.c (myrename): ditto. * win32/win32.c (wait_events): support function for win32 signal handling. Sat Nov 11 08:34:18 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.31. * lib/net/http.rb: initializes header in HTTP, not HTTPCommand. * lib/net/protocol.rb, http.rb: rewrites proxy code. Fri Nov 10 16:15:53 2000 Yukihiro Matsumoto * numeric.c (rb_num2long): use to_int, not to_i. * error.c: T_SYMBOL was misplaced by T_UNDEF. * parse.y (yylex): eval("^") caused infinite loop. Thu Nov 9 14:22:13 2000 Yukihiro Matsumoto * io.c (rb_io_taint_check): should check IO taintness; no operation for untainted IO should be allowed in the sandbox. * rubyio.h (GetOpenFile): check IO taintness inside using rb_io_taint_check(). Wed Nov 8 03:08:53 2000 Yukihiro Matsumoto * io.c (io_fflush): ensure fflush(3) would not block by calling rb_thread_fd_writable(). Tue Nov 7 20:29:56 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.30. * lib/net/protocol.rb, smtp.rb: Command#critical_ok -> error_ok * lib/net/http.rb: reads header when also "100 Continue". Tue Nov 7 04:32:19 2000 Yukihiro Matsumoto * bignum.c (bigdivrem): use bit shift to make y's MSB set. Mon Nov 6 1:22:49 2000 Yukihiro Matsumoto * error.c (warn_print): do not use err_append(), to ensure output to stderr. * error.c (rb_warn): use warn_print() instead of err_print(). * error.c (rb_warning): ditto. * error.c (rb_bug): ditto. * eval.c (rb_load): re-raise exceptions during load. * time.c (make_time_t): remove useless adjust Thu Nov 2 18:01:16 2000 Yukihiro Matsumoto * random.c (rb_f_rand): half-baked float support fixed. This fix was originally proposed by K.Kosako . Tue Oct 31 17:27:17 2000 Yukihiro Matsumoto * bignum.c: change digit size to `long|int' if long long is available. * marshal.c (w_object): support `long|int' digits. * marshal.c (r_object): ditto. Sat Oct 28 23:54:22 2000 Yukihiro Matsumoto * parse.y (yylex): allow =end at the end of file (without a newline at the end). Fri Oct 27 10:00:27 2000 Yukihiro Matsumoto * bignum.c (rb_cstr2inum): should ignore trailing white spaces. * bignum.c (rb_str2inum): string may not have sentinel NUL. Fri Oct 27 02:37:22 2000 Yukihiro Matsumoto * bignum.c (rb_cstr2inum): wrongly assigned base to c before badcheck check. Thu Oct 26 02:42:50 2000 Minero Aoki * lib/net/protocol.rb: Command#critical_ok * lib/net/smtp.rb: clear critical flag before go to SMTP Wed Oct 25 12:30:19 2000 Yukihiro Matsumoto * array.c (rb_ary_concat): replacing array might be the receiver itself. do not call rb_ary_push_m. * array.c (rb_ary_replace): replacing array might be the receiver itself. use memmove. Fri Oct 20 07:56:23 2000 Yukihiro Matsumoto * eval.c (rb_eval): ARGSPUSH should not modify args array. Thu Oct 19 14:58:17 2000 WATANABE Tetsuya * pack.c (NUM2U32): should use NUM2ULONG(). Tue Oct 17 17:30:34 2000 WATANABE Hirofumi * eval.c (error_print): ruby_sourcefile may be NULL. Tue Oct 17 16:36:28 2000 Wes Nakamura * pack.c (NATINT_U32): wrong use of sizeof. Tue Oct 17 12:48:20 2000 Katsuyuki Komatsu * eval.c (rb_abort): nil check against ruby_errinfo. * eval.c (rb_thread_schedule): use FOREACH_THREAD_FROM instead of FOREACH_THREAD, since curr_thread may be removed from thread ring. * eval.c (THREAD_ALLOC): errinfo should be Qnil. * eval.c (rb_callcc): th->prev,th->next are now already initialized in THREAD_ALLOC. Mon Oct 16 15:37:33 2000 Kazuhiro NISHIYAMA * eval.c (rb_thread_inspect): tag size was shorter than required. * object.c (rb_obj_inspect): ditto. Mon Oct 16 14:25:18 2000 Shugo Maeda * object.c (sym_inspect): used `name' before initialization. Mon Oct 16 14:06:00 2000 Yukihiro Matsumoto * pack.c (pack_pack): use NATINT_U32 for 'l', 'L', and 'N'. * pack.c (I32,U32): 32 bit sized integer. * pack.c (OFF16,OFF32B): big endian offset for network byteorder. Mon Oct 16 06:39:32 2000 Minero Aoki * lib/net/http.rb: hex-alpha is not [a-h] but [a-f]. Mon Oct 16 01:02:02 2000 Yukihiro Matsumoto * eval.c (rb_thread_start_0): should not abort on exception if $SAFE >= 4. * parse.y (sym): symbols for class variable names. Sun Oct 15 01:49:18 2000 Yukihiro Matsumoto * file.c (rb_file_flock): should accept interrupt. * process.c (rb_waitpid): ditto. * process.c (rb_waitpid): ditto. * process.c (proc_wait): ditto. * process.c (proc_waitpid2): wrong recursion. Sat Oct 14 03:32:13 2000 Yukihiro Matsumoto * eval.c (rb_thread_alloc): should not link a new thread in the live thread ring before initialization. Fri Oct 13 17:08:09 2000 Shugo Maeda * lib/net/imap.rb: new file. Thu Oct 12 18:56:28 2000 Minero Aoki * lib/net/pop.rb: POP3#reset * lib/net/http.rb: a code for "Switch Protocol" was wrongly 100. Thu Oct 12 01:23:38 2000 Wakou Aoyama * lib/cgi.rb: bug fix: CGI::html(): PRETTY option didn't work. Thu Oct 12 00:03:02 2000 Yukihiro Matsumoto * object.c (sym_inspect): should adjust string length. * struct.c (rb_struct_to_s): ditto. * struct.c (rb_struct_inspect): ditto. Wed Oct 11 22:15:47 2000 Katsuyuki Komatsu * eval.c (rb_thread_inspect): should adjust string length. * object.c (rb_any_to_s): ditto. * object.c (rb_obj_inspect): ditto. Wed Oct 11 18:13:50 2000 Yukihiro Matsumoto * eval.c (rb_thread_start_0): should check insecure exit. Wed Oct 11 14:29:51 2000 Minero Aoki * lib/net/protocol.rb: 2nd arg for ProtocolError#initialize is optional. * lib/net/http.rb: code refining. Wed Oct 11 11:13:03 2000 Yukihiro Matsumoto * parse.y (primary): setter method (e.g. foo=) should always be public. * eval.c (rb_thread_raise): should not raise SecurityError if exception raised by the interpreter. * eval.c (rb_thread_cleanup): skip all THREAD_KILLED threads before FOREACH_THREAD. Tue Oct 10 16:11:54 2000 WATANABE Hirofumi * dln.c (dln_load): remove unused code for Cygwin. Tue Oct 10 09:49:23 2000 Yukihiro Matsumoto * file.c (Init_File): FileTest.size should return 0 (not nil) for empty files. Sun Oct 8 13:20:26 2000 Guy Decoux * eval.c (POP_SCOPE): not just set SCOPE_DONT_RECYCLE, but do scope_dup(). Sat Oct 7 15:10:50 2000 Yukihiro Matsumoto * string.c (rb_str_reverse_bang): unnecessary ALLOCA_N() was removed. Fri Oct 6 14:50:24 2000 WATANABE Hirofumi * ext/extmk.rb.in, lib/mkmf.rb: remove "DESTDIR =". * Makefile.in, win32/Makefile.sub, ruby.1: renamed -X to -C. Fri Oct 6 12:50:52 2000 Yukihiro Matsumoto * array.c (rb_ary_plus): use to_ary(), not Check_Type(). * array.c (rb_ary_concat): ditto. * gc.c (rb_gc): use __builtin_frame_address() for gcc. * eval.c (stack_length): ditto. * parse.y (assign_in_cond): stop warning till some better warning condition will be found. Thu Oct 5 18:02:39 2000 Yukihiro Matsumoto * object.c (rb_obj_dup): should have propagated taint flag. (ruby-bugs:#PR64,65) Wed Oct 4 00:26:11 2000 Yukihiro Matsumoto * eval.c (proc_arity): proc{|a|}'s arity should be -1. Mon Oct 2 05:28:58 2000 akira yamada * string.c (trnext): minus at the end of pattern. Sun Oct 1 00:43:34 2000 WATANABE Hirofumi * configure.in: exp-name was wrong on cygwin and mingw32. Thu Sep 28 14:57:09 2000 Yukihiro Matsumoto * regex.c (re_compile_pattern): should try must_string calculation every time. Tue Sep 19 23:47:44 2000 SHIROYAMA Takayuki * configure.in, config.guess, config.sub: MacOS X support. Wed Sep 27 18:40:05 2000 Yukihiro Matsumoto * stable version 1.6.1 released. Wed Sep 27 16:13:05 2000 WATANABE Hirofumi * mkconfig.rb: variables should be expanded only if /\$\{?\w+\}?/. Tue Sep 26 18:09:51 2000 WATANABE Hirofumi * string.c: include Tue Sep 26 15:59:50 2000 Yukihiro Matsumoto * object.c (rb_mod_dup): metaclasses of class/module should not be cleared by rb_obj_dup. Tue Sep 26 02:44:54 2000 Yukihiro Matsumoto * gc.c (GC_MALLOC_LIMIT): size extended. * regex.c (DOUBLE_STACK): use machine's stack region for regex stack if its size is small enough. Mon Sep 25 18:13:07 2000 Yukihiro Matsumoto * regex.c: include . * eval.c (rb_add_method): cache mismatch by method definition. need to clear_cache_by_id every time. Mon Sep 25 13:31:45 2000 WATANABE Hirofumi * win32/win32.c (NtCmdGlob): substitute '\\' with '/'. Mon Sep 25 00:35:01 2000 WATANABE Hirofumi * defines.h: #undef HAVE_SETITIMER on cygwin. Sun Sep 24 03:01:53 2000 Minero Aoki * lib/net/protocol.rb, http.rb: typo. Sat Sep 23 07:33:20 2000 Aleksi Niemela * regex.c (re_compile_pattern): nicer regexp error messages for invalid patterns. Sat Sep 23 03:06:25 2000 Yukihiro Matsumoto * variable.c (rb_autoload_load): should not require already provided features. Fri Sep 22 15:46:21 2000 Minero Aoki * lib/net/http.rb: too early parameter expansion in string. Fri Sep 22 13:58:51 2000 WATANABE Hirofumi * ext/extmk.rb.in: don't use default $: Fri Sep 22 13:42:50 2000 Katsuyuki Komatsu * regex.c (PUSH_FAILURE_COUNT): avoid casting warning on alpha. * regex.c (PUSH_FAILURE_POINT): ditto. Fri Sep 22 10:16:21 2000 WATANABE Hirofumi * win32/config.h.in: add HAVE_TELLDIR, HAVE_SEEKDIR Thu Sep 21 19:04:34 2000 WATANABE Hirofumi * ext/extmk.rb, lib/mkmf.rb (install_rb): check whether libdir is directory or not. Thu Sep 21 17:23:05 2000 Yukihiro Matsumoto * file.c (rb_file_s_symlink): use HAVE_SYMLINK. * file.c (rb_file_s_readlink): use HAVE_READLINK. * dir.c (dir_tell): use HAVE_TELLDIR. * dir.c (dir_seek): use HAVE_SEEKDIR. * configure.in (AC_CHECK_FUNCS): lstat, symlink, readlink, telldir, seekdir checks added. * file.c (lstat): should use stat(2) if lstat(2) is not available. Thu Sep 21 15:59:23 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.29. * lib/net/http.rb: HTTPReadAdapter -> HTTPResponseReceiver * lib/net/http.rb (connecting): response is got in receive() Thu Sep 21 15:49:07 2000 Wayne Scott * lib/find.rb (find): should not follow symbolic links; tuned performance too. Wed Sep 20 23:21:38 2000 Yukihiro Matsumoto * ruby.c (load_file): two Ctrl-D was required to stop ruby at the beginning of stdin script read. Wed Sep 20 14:01:45 2000 Yukihiro Matsumoto * eval.c (rb_provided): detect infinite load loop. * eval.c (rb_provided): too weak filename comparison. * eval.c (rb_thread_alloc): avoid recycling still referenced dvar structures. * eval.c (rb_callcc): ditto. * eval.c (THREAD_ALLOC): fill dyna_vars field by ruby_dyna_vars. Tue Sep 19 17:47:03 2000 Yukihiro Matsumoto * stable version 1.6.0 released. Tue Sep 19 16:24:52 2000 Yukihiro Matsumoto * marshal.c (Init_marshal): provide marshal.so no more. Tue Sep 19 14:01:01 2000 WATANABE Hirofumi * configure.in, win32/setup.mak: include version number in RUBY_SO_NAME. Tue Sep 19 13:07:47 2000 Yukihiro Matsumoto * parse.y (yylex): was confusing $~ and $_. Tue Sep 19 13:06:53 2000 GOTOU Yuuzou * signal.c (rb_f_kill): signum may be a negative number, should be treated by signed number. Tue Sep 19 01:14:56 2000 Yukihiro Matsumoto * eval.c (rb_provide): better feature handling. * eval.c (rb_f_require): loading ruby library may be partial state. checks in rb_thread_loading is integrated. * eval.c (rb_provided): better thread awareness. * lib/irb/frame.rb: 6 (not 5) parameters for trace_func proc. * eval.c (error_print): should print error position even if get_backtrace() failed. Sat Sep 16 03:29:59 2000 Yukihiro Matsumoto * eval.c (rb_f_require): rb_provided() was called too early; does not work well with threads. * parse.y (ensure): should distinguish empty ensure and non existing ensure. * file.c (Init_File): extending File by class of FileTest was serious mistake. Thu Sep 14 02:46:54 2000 Yukihiro Matsumoto * eval.c (rb_thread_yield): array strip should be done in this function. Wed Sep 13 17:01:03 2000 Yukihiro Matsumoto * bignum.c (rb_big_eq): incomplete value comparison of bignums. Wed Sep 13 06:39:54 2000 Yukihiro Matsumoto * variable.c (rb_mod_class_variables): Module#class_variables added. Wed Sep 13 06:09:26 2000 Wakou Aoyama * lib/cgi.rb: bug fix: CGI::header(): output status header. Wed Sep 13 01:09:12 2000 Yukihiro Matsumoto * parse.y (yylex): allow global variables like '$__a'. Tue Sep 12 22:28:43 2000 WATANABE Hirofumi * ext/socket/extconf.rb: avoid using terrible on cygwin 1.1.5. Tue Sep 12 16:01:58 2000 WATANABE Hirofumi * array.c (rb_ary_unshift_m): typo. Tue Sep 12 15:37:55 2000 Yukihiro Matsumoto * eval.c (rb_yield_0): stripped array too much, should remove just for proc_call(). Tue Sep 12 07:05:24 2000 Wakou Aoyama * lib/cgi.rb: version 2.0.0: require ruby1.5.4 or later. * lib/net/telnet.rb: version 1.6.0 Tue Sep 12 03:26:07 2000 Yukihiro Matsumoto * eval.c (massign): use to_ary to get an array if available. * object.c (rb_Array): ditto. Mon Sep 11 14:24:47 2000 Yukihiro Matsumoto * hash.c (ruby_setenv): should not free the element of origenvironment. * parse.y (command_call): kYIELD moved to this rule to allow 'a = yield b'. (ruby-bugs-ja:#PR15) Mon Sep 11 01:27:54 2000 Yukihiro Matsumoto * eval.c (rb_yield_0): proc#call([]) should pass single value to the block. * eval.c (callargs): reduce array allocation. * eval.c (massign): precise check for argument number. Fri Sep 8 10:05:17 2000 Yukihiro Matsumoto * gc.c (STR_NO_ORIG): should be FL_USER2. Thu Sep 7 14:17:51 2000 Yukihiro Matsumoto * string.c (rb_str_cat): should work even for concatenating same string. Wed Sep 6 17:06:38 2000 Yukihiro Matsumoto * variable.c (rb_cvar_declare): should check superclass's class variable first. Wed Sep 6 10:42:02 2000 Yukihiro Matsumoto * misc/ruby-mode.el (ruby-calculate-indent): shift continuing line if previous line ends with modifier keyword. * misc/ruby-mode.el (ruby-parse-region): should not give up if modifiers are at the end of line. * misc/ruby-mode.el (ruby-expr-beg): indented wrongly if modified statement was size 1. Wed Sep 6 10:41:19 2000 Kenichi Komiya * misc/ruby-mode.el (ruby-parse-region): modifier was not handled well on emacs19. Tue Sep 5 17:10:12 2000 Yukihiro Matsumoto * time.c (time_to_s): fixed zone string UTC for utc time object. Tue Sep 5 00:26:06 2000 Yukihiro Matsumoto * regex.c (re_search): range worked wrongly on bm_search(). Mon Sep 4 13:40:40 2000 WATANABE Hirofumi * configure.in: renamed libruby.a to libruby.{cygwin,mingw32}.a on cygwin and mingw32. Sun Sep 3 23:44:04 2000 Noriaki Harada * io.c (NO_SAFE_RENAME): for BeOS too. Sun Sep 3 11:31:53 2000 Takaaki Tateishi * parse.y (rescue): no assignment was done if rescue body was empty. Sat Sep 2 10:52:21 2000 Yukihiro Matsumoto * parse.y (call_args,aref_args): block_call can be the last argument. * parse.y (COND_PUSH,COND_POP): maintain condition stack to allow kDO2 in parentheses in while/until/for conditions. * parse.y (yylex): generate kDO2 for EXPR_ARG outside of while/until/for condition. Fri Sep 1 10:36:29 2000 Yukihiro Matsumoto * parse.y (aref_args,opt_call_args): add block_call to allow a method without parentheses and with block as a last argument. * hash.c (rb_hash_sort): should not return nil. * re.c (match_aref): should use rb_reg_nth_match(). * eval.c (POP_SCOPE): recycled scopes too much * eval.c (Init_eval): extend room for stack allowance. * eval.c (POP_SCOPE): frees scope too much. Thu Aug 31 14:28:39 2000 Yukihiro Matsumoto * gc.c (rb_gc_mark): T_SCOPE condition must be more precise. * eval.c (scope_dup): should not make all duped scope orphan. Thu Aug 31 10:11:47 2000 Yukihiro Matsumoto * parse.y (stmt): allow stmt_rhs to be right hand side of multiple assignment. * time.c (rb_time_timeval): type error should not mention the word 'interval'. Wed Aug 30 23:21:20 2000 Yukihiro Matsumoto * numeric.c (rb_num2long): use rb_Integer() instead of independent convert routine. * eval.c (rb_rescue2): now takes arbitrary number of exception types. * object.c (rb_convert_type): use rb_rescue2 now to handle NameError. * object.c (rb_convert_type): better error message. Wed Aug 30 17:09:14 2000 WATANABE Hirofumi * ext/Win32API/Win32API.c (Win32API_initialize): AlphaNT support. Wed Aug 30 14:19:07 2000 Yukihiro Matsumoto * parse.y (node_assign): should support NODE_CVASGN2 too. Wed Aug 30 11:31:47 2000 Nobuyoshi Nakada * ext/Win32API/Win32API.c (Win32API_initialize): add the arguments checking. * ext/Win32API/Win32API.c (Win32API_initialize): add taint checking. allow String object in the third argument. Wed Aug 30 10:29:40 2000 Masahiro Tomita * io.c (rb_f_p): flush output buffer. Tue Aug 29 16:29:15 2000 Yukihiro Matsumoto * parse.y (assignable): remove NODE_CVASGN3. * parse.y (gettable): remove NODE_CVAR3. Tue Aug 29 02:02:14 2000 Yukihiro Matsumoto * lib/mkmf.rb (create_makefile): handles create_makefile("a/b"). * ext/extmk.rb.in (create_makefile): ditto Mon Aug 28 18:43:54 2000 Yukihiro Matsumoto * eval.c (is_defined): now handles class variables. * eval.c (rb_eval): class variable behavior revisited. * parse.y (assignable): ditto. * parse.y (gettable): ditto. * regex.c (PUSH_FAILURE_COUNT): push/pop interval count on failure stack. this fix is inspired by the Emacs21 patch from Stefan Monnier . Fri Aug 25 15:24:39 2000 Yukihiro Matsumoto * variable.c (rb_cvar_get): should not follow __attached__. * variable.c (rb_cvar_set): ditto. * variable.c (rb_cvar_declare): ditto. * variable.c (mod_av_set): second class variable assignment at the toplevel should not give warning. Fri Aug 25 01:18:36 2000 Yukihiro Matsumoto * io.c (next_argv): prepare path for open file. * string.c (rb_str_setter): moved from io.c. * io.c (next_argv): filename should be "-" for refreshed ARGF. Thu Aug 24 15:27:39 2000 WATANABE Hirofumi * ext/socket/socketport.h: use `extern int h_errno' if needed. Sat Aug 19 01:34:02 2000 WATANABE Hirofumi * ext/sdbm/_sdbm.c (sdbm_prep): flags should be or-ed by O_BINARY on Win32 too. * ext/sdbm/_sdbm.c (makroom): fill hole with 0 on Win32 too. Fri Aug 18 13:23:59 2000 Yukihiro Matsumoto * eval.c (rb_eval): should preserve and clear $! value before compilation. * eval.c (eval): ditto. Fri Aug 18 11:06:19 2000 Shugo Maeda * ext/socket/socket.c (s_accept): start GC on EMFILE/ENFILE. Thu Aug 17 16:04:48 2000 Yukihiro Matsumoto * eval.c (is_defined): should clear ruby_errinfo. Thu Aug 17 04:26:31 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.27. * lib/net/protocol.rb: writing methods returns written byte size. * lib/net/smtp.rb: send_mail accepts many destinations. Wed Aug 16 00:43:47 2000 Yukihiro Matsumoto * time.c (time_s_times): use CLK_TCK for HZ if it's defined. Tue Aug 15 17:30:59 2000 Yukihiro Matsumoto * eval.c (frame_dup): should set flag FRAME_MALLOC after argv allocation. * eval.c (blk_free): should not free argv if GC was called before frame_dup. Tue Aug 15 16:08:40 2000 WATANABE Hirofumi * configure.in: add ac_cv_func_times=yes for mingw32. * win32/win32.c (mytimes): typo. Tue Aug 15 01:45:28 2000 Yukihiro Matsumoto * io.c (argf_eof): should return true at the end of ARGF without checking stdout if arguments are given. Mon Aug 14 10:34:32 2000 Yukihiro Matsumoto * eval.c (rb_thread_status): status should return false for normal termination, nil for termination by exception. Fri Aug 11 15:43:46 2000 Yukihiro Matsumoto * eval.c (rb_undef): give warning for undefining __id__, __send__. Thu Aug 10 08:05:03 2000 Yukihiro Matsumoto * eval.c (rb_callcc): returned current thread instead of continuation wrongly. Thu Aug 10 05:40:28 2000 WATANABE Hirofumi * ext/extmk.rb.in: $CPPFLAGS should be initialized. * ext/tcltklib/depend: add stubs.o. * ext/tcltklib/extconf.rb: use $CPPFLAGS instead of $CFLAGS. Wed Aug 9 16:31:48 2000 Yukihiro Matsumoto * eval.c (rb_callcc): thread status for continuations must be THREAD_KILLED, otherwise thread_free() breaks other threads. Wed Aug 9 13:24:25 2000 WATANABE Hirofumi * win32/win32.[ch]: emulate rename(2). Tue Aug 8 14:01:46 2000 WATANABE Hirofumi * ext/tcltklib/tcltklib.c: support --enable-tcltk_stubs * ext/tcltklib/extconf.rb: ditto. * ext/tcltklib/stubs.c: created. examine candidate shared libraries. Mon Aug 7 13:59:12 2000 Yukihiro Matsumoto * ruby.h (CLONESETUP): should copy flags before any potential object allocation. * regex.c (re_match): check for stack depth was needed. Sat Aug 5 16:43:43 2000 WATANABE Hirofumi * djgpp/*: convert DOS line endings to UNIX style. * djgpp/config.status: rename to config.sed for SFN. * lib/ftools.rb (compare, safe_unlink, chmod): avoid warnings. * lib/ftools.rb (move): typo. not `tpath', but `to'. Fri Aug 4 23:26:48 2000 Yukihiro Matsumoto * eval.c (proc_call): gives warning if a block is supplied. * eval.c (rb_eval): no warning for discarding if an alias for the method is already made. Fri Aug 4 16:32:29 2000 Yukihiro Matsumoto * array.c (rb_ary_reject_bang): returns nil if no element removed. * hash.c (rb_hash_reject_bang): returns nil if no element removed. Thu Aug 3 19:44:26 2000 Yukihiro Matsumoto * eval.c (rb_thread_fd_writable): should return integer value. * array.c (rb_ary_assoc): search array element whose length is longer than 0 (not 1). Wed Aug 2 18:27:47 2000 Yukihiro Matsumoto * eval.c (rb_thread_wait_fd): prohibit thread context switch during compilation. * eval.c (rb_cont_call): prohibit Continuation#call across threads. Wed Aug 2 08:22:04 2000 Yukihiro Matsumoto * gc.c (rb_gc): clear malloc_memories to zero, to avoid potential super frequent GC invocation. (ruby-bugs:#PR48) * gc.c (rb_gc): only add_heap() if GC trigger condition is satisfied. Tue Aug 1 16:41:58 2000 Yukihiro Matsumoto * ruby.c (proc_options): global load path setting moved from ruby_prog_init(). * ruby.c (incpush): renamed. push path entry at the END of the load path array. This makes -I directories sorted in order in the arguments. Sat Jul 29 23:42:04 2000 Yukihiro Matsumoto * dir.c (dir_each): should check whether dir is closed during the block execution. (ruby-bugs:#PR47) Sat Jul 29 21:57:30 2000 WATANABE Hirofumi * ruby.c (rubylib_mangle): provide another buffer for the result. Wed Jul 26 10:09:01 2000 WATANABE Hirofumi * configure.in: set SOLIBS to LIBS on Cygwin. * configure.in: LIBRUBY_SO='$(RUBY_INSTALL_NAME)'.$target_os.dll on cygwin and mingw32. ruby-cygwin.dll is bad. why? Wed Jul 26 10:04:03 2000 Yukihiro Matsumoto * gc.c (gc_sweep): avoid full scan during compilation. * gc.c (rb_gc): add heap during no gc period (including compilation). Tue Jul 25 19:03:04 2000 WATANABE Hirofumi * cygwin/GNUmakefile: use puts instead of print, because Cygwin DLL's behavior is changed(or bug?). * configure.in: LIBRUBY_SO='$(RUBY_INSTALL_NAME)'-$target_os.dll on cygwin and mingw32. * cygwin/GNUmakefile: ditto. * Makefile.in: $(SOLIBS) should be put after dmyext.@OBJEXT@. * instruby.rb: install $(LIBRUBY) to libdir if $(LIBRUBY) != $(LIBRUBY_A_). Tue Jul 25 15:16:00 2000 Yukihiro Matsumoto * io.c (rb_p): redirect to $defout. Mon Jul 24 18:52:55 2000 WATANABE Hirofumi * win32/win32.c (win32_getenv): should remove `static'. * ruby.c (rubylib_mangle): support "/hoge;/foo" Mon Jul 24 10:28:55 2000 GOTO Kentaro * string.c (rb_str_count): raise exception if no argument is given. Sun Jul 23 12:55:04 2000 Dave Thomas * string.c (rb_str_rindex): Support negative end position. Fri Jul 21 17:35:01 2000 Yukihiro Matsumoto * parse.y (aref_args): command_call now be permitted as aref_args. * process.c (proc_getpriority): getpriority(2) may return valid negative number. use errno to detect error. * marshal.c (dump_ensure): dumped string should be tainted if any among target objects is tainted. * marshal.c (r_regist): restored object should be tainted if and only if the source is a file or a tainted string. Wed Jul 19 15:14:04 2000 Yukihiro Matsumoto * bignum.c (bigdivrem): should use rb_int2big(), not rb_uint2big(). Tue Jul 18 14:58:30 2000 Yukihiro Matsumoto * eval.c (ruby_options): should treat SystemExit etc. properly. * parse.y (yycompile): should check compile_for_eval, not ruby_in_eval. Mon Jul 17 04:29:50 2000 Minero Aoki * lib/mkmf.rb: converts extension of $objs into $OBJEXT. Sun Jul 16 03:02:34 2000 Dave Thomas * lib/weakref.rb: Change to use new ObjectSpace calls. Sat Jul 15 21:59:58 2000 Yukihiro Matsumoto * eval.c (rb_eval): should not redefine __id__ nor __send__. * gc.c (define_final): integrate final.rb features into the interpreter. define_finalizer and undefine_finalizer was added to ObjectSpace. plus, add_finalizer, remove_finalizer, and call_finalizer are deprecated now. Sat Jul 15 01:32:34 2000 Yukihiro Matsumoto * eval.c (rb_mod_method): implements unbound method. * eval.c (Init_eval): should prohibit `module_function' for class Class. Fri Jul 14 17:19:59 2000 WATANABE Hirofumi * cygwin/GNUmakefile.in: use miniruby instead of sed. Fri Jul 14 12:49:50 2000 Yukihiro Matsumoto * io.c (argf_eof): need to check stdin, when next_p == -1. * io.c (read_all): use io_fread() instead of fread(3). * io.c (io_reopen): should clearerr FILE if fd < 3. * re.c (rb_reg_match_m): the result is exported, so it should be declared as busy. * eval.c (rb_eval): should preserve errinfo even if return, break, etc. is called in rescue clause. * instruby.rb: install irb too. Wed Jul 12 15:32:57 2000 Yukihiro Matsumoto * variable.c (rb_const_get): constants for builtin classes must have higher priority than constants from included modules at Object class. * bignum.c (bigdivrem): small embarrassing typo. Wed Jul 12 15:06:28 2000 Yukihiro Matsumoto * eval.c (rb_eval): use rb_const_get_at(). * variable.c (top_const_get): retrieve toplevel constants only, not ones of Object (and its included modules) in general. Wed Jul 12 15:04:11 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.26. * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: add module Net::NetPrivate and its inner classes {Read,Write}Adapter, Command, Socket, SMTPCommand, POP3Command, APOPCommand, HTTPCommand Wed Jul 12 13:10:30 2000 Yukihiro Matsumoto * bignum.c (bigdivrem): defer bignorm(). * bignum.c (bignorm): accepts accidental fixnums. Tue Jul 11 16:54:17 2000 Yukihiro Matsumoto * parse.y (yylex): `@' is no longer a valid instance variable name. Tue Jul 11 01:51:50 2000 Yukihiro Matsumoto * bignum.c (rb_big_divmod): should not use Integer(float) for the right operand. * bignum.c (rb_big_remainder): ditto. * bignum.c (rb_big_modulo): ditto. Mon Jul 10 15:27:16 2000 WATANABE Hirofumi * io.c (pipe_finalize): should set rb_last_status when pclose(). Mon Jul 10 09:07:54 2000 Yukihiro Matsumoto * error.c (rb_bug): print version number and such too. Sat Jul 8 23:08:40 2000 Yukihiro Matsumoto * eval.c (rb_thread_start_0): should copy previous scopes to prevent rb_gc_force_recycle(). Fri Jul 7 23:36:36 2000 Katsuyuki Komatsu * ext/socket/addrinfo.h: move IN_EXPERIMENTAL and IN_LOOPBACKNET definitions to ext/socket/sockport.h. * ext/socket/extconf.rb: add getservbyport() and arpa/inet.h check. * ext/socket/getaddrinfo.c (getaddrinfo): SOCK_RAW may not be defined (ex. BeOS, Palm OS 2.x or before). * ext/socket/getnameinfo.c (getnameinfo): getservbyport() may not exist (ex. BeOS, Palm OS). * ext/socket/sockport.h: add IN_EXPERIMENTAL, IN_CLASSA_NSHIFT, IN_LOOPBACKNET, AF_UNSPEC, PF_UNSPEC and PF_INET. Fri Jul 7 03:30:00 2000 Yukihiro Matsumoto * parse.y (aref_args): should allow Hash[:a=>2] etc. * numeric.c (fix_aref): convert index by NUM2INT, not FIX2INT. (ruby-bugs:#PR37) * time.c (time_localtime): should prohibit for frozen time. * time.c (time_gmtime): ditto. Thu Jul 6 19:12:12 2000 Yukihiro Matsumoto * io.c (rb_file_s_open): should not terminate fptr; just clear it. * ruby.c (proc_options): should not call require_libraries() twice. * ruby.c (require_libraries): clear req_list_head.next after execution. Thu Jul 6 13:51:57 2000 Nobuyoshi Nakada * object.c (rb_to_id): name may not be symbol nor fixnum. * struct.c (rb_struct_s_def): name may be nil. Thu Jul 6 02:09:06 2000 Yukihiro Matsumoto * bignum.c (bigdivrem): new function to return remainder. * numeric.c (fixdivmod): now returns modulo, not remainder. * numeric.c (flodivmod): ditto. * bignum.c (bigdivmod): ditto. * numeric.c (num_modulo): new method; alias to '%'. Thu Jul 6 00:51:43 2000 WATANABE Hirofumi * win32/win32.c (NtCmdGlob): patterns should be separated and NUL terminated. Wed Jul 5 22:27:56 2000 WATANABE Hirofumi * cygwin/GNUmakefile: use ruby.def to make rubycw.dll. * ext/extmk.rb.in: create target.def. * lib/mkmf.rb: ditto. Wed Jul 5 09:47:14 2000 Yukihiro Matsumoto * time.c (time_arg): Time::local, Time::gm now take 7th optional argument for usec. * numeric.c (num_ceil, etc): default ceil, floor, round, truncate implementation for Numeric, using `to_f'. * io.c (rb_io_reopen): clear fptr->path after free() to prevent potential GC crash. * io.c (rb_file_s_open): terminate fptr unless null. * io.c (rb_file_initialize): ditto. * lib/tempfile.rb: specify FILE::CREAT|File::EXCL to open for better security. * numeric.c (flo_truncate): new method. Wed Jul 5 01:02:53 2000 WATANABE Hirofumi * ext/extmk.rb.in: join ' ' -> join(' '). * lib/mkmf.rb: ditto. Tue Jul 4 13:51:29 2000 Yukihiro Matsumoto * ext/dbm/dbm.c: add methods added to Hash in 1.5.x. * ext/gdbm/gdbm.c: ditto. * ext/sdbm/init.c: ditto. * eval.c (proc_call): args may be Qundef (means no argument), do not call TYPE() for args. Tue Jul 4 13:20:56 2000 WATANABE Hirofumi * ext/extmk.rb.in: make command line must be single-quoted. $(RUBY_INSTALL_NAME) is command substitution in the POSIX sh. Tue Jul 4 13:16:02 2000 Yukihiro Matsumoto * util.c (rb_type): should add T_UNDEF. Tue Jul 4 09:30:35 2000 Yukihiro Matsumoto * parse.y (here_document): supports EOF right after terminator. * random.c (rb_f_rand): argument is now optional (rand(max=0)). Tue Jul 4 01:50:49 2000 WATANABE Hirofumi * win32/ruby.def: remove ruby_mktemp. Tue Jul 4 01:27:13 2000 Yukihiro Matsumoto * eval.c (rb_rescue2): new function to rescue arbitrary exception. * numeric.c (do_coerce): should catch NameError explicitly. Tue Jul 4 00:15:23 2000 Dave Thomas * numeric.c (Init_Numeric): forgot to register Numeric#remainder. Mon Jul 3 23:46:56 2000 Katsuyuki Komatsu * win32/win32.c (myselect, myaccept): disable interrupt while executing accept() or select() to avoid Ctrl-C causes "unknown software exception (0xc0000029)". Mon Jul 3 18:35:41 2000 WATANABE Hirofumi * lib/mkmf.rb: use null device if it exists for cross-compiling. Mon Jul 3 18:19:51 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.26. * lib/net/protocol.rb (finish): do nothing unless active. * lib/net/http.rb: HTTP#{get,post}2 again (for new impl). Mon Jul 3 16:47:22 2000 WATANABE Hirofumi * cygwin/GNUmakefile: librubys.a -> lib$(RUBY_INSTALL_NAME)s.a * configure.in: use AC_CANONICAL_{HOST,TARGET,BUILD}. Mon Jul 3 13:15:02 2000 Yukihiro Matsumoto * numeric.c (fix_divmod): x * d + m = y where d, m = x.divmod(y). * bignum.c (rb_big_divmod): ditto. * numeric.c (fixdivmod): does not depend C's undefined % behavior. adopt to fmod(3m) behavior. * numeric.c (flo_mod): modulo now reserves fmod(3m) behavior. * numeric.c (num_remainder): 'deprecated' warning. Mon Jul 3 10:27:28 2000 WATANABE Hirofumi * configure.in: use AC_CANONICAL_SYSTEM. Sun Jul 2 21:17:37 2000 WATANABE Hirofumi * configure.in: support without --enable-shared for cygwin/mingw32. * cygwin/GNUmakefile: ditto. * ext/extmk.rb.in: use null device if it exists for cross-compiling. * lib/mkmf.rb: ditto. * util.c (ruby_mktemp): remove unused ruby_mktemp(). Sun Jul 2 14:18:04 2000 Koji Arai * eval.c (TMP_PROTECT_END): tmp__protect_tmp may be NULL. Sun Jul 2 03:37:50 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.25. * lib/net/protocol.rb (each_crlf_line): beg = 0 is needed in adding{} * lib/net/smtp.rb: allow String for to_addr of SMTP#sendmail Sat Jul 1 15:22:35 2000 Yukihiro Matsumoto * numeric.c (fix_rshift): should handle shift value more than sizeof(long). Sat Jul 1 15:22:35 2000 Yukihiro Matsumoto * eval.c (rb_eval): the value from RTEST() is not valid Ruby object. result should be either true or false. Sat Jul 1 09:30:06 2000 Katsuyuki Komatsu * re.c (rb_reg_initialize): was freeing invalid pointer. Sat Jul 1 03:25:56 2000 Yukihiro Matsumoto * parse.y (call_args): command_call can be the last argument of call_args. It had to be the only argument. * re.c (rb_reg_s_quote): should not dump core even for unsane mbc string. Fri Jun 30 01:36:20 2000 Aleksi Niemela * parse.y (f_norm_arg): better, nicer error message. Thu Jun 29 07:45:33 2000 Yukihiro Matsumoto * ext/socket/socket.c (udp_send): destination may be packed struct sockaddr. * object.c (rb_Integer): Integer(nil) should be invalid, on the other hand, nil.to_i is OK. Wed Jun 28 17:26:06 2000 Yukihiro Matsumoto * ext/socket/socket.c (ip_recvfrom): udp_recvfrom and tcp_recvfrom is merged and moved to IPSocket#recvfrom. * ext/socket/socket.c (sock_s_getaddrinfo): family can be a strings such as "AF_INET" etc. * ruby.c (require_libraries): . and RUBYLIB added to $load_path just before -r procedure. * ruby.c (proc_options): -e, - did not exec -r. Wed Jun 28 14:52:28 2000 Koga Youichirou * config.sub: NetBSD/hpcmips support. Wed Jun 28 10:11:06 2000 Yukihiro Matsumoto * gc.c: gc trigger threshold changed; GC_NEWOBJ_LIMIT removed, FREE_MIN is increased to 4096. Tue Jun 27 22:39:28 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.24. * lib/net/protocol.rb: modified each_crlf_line again. * lib/net/protocol.rb: do_write_beg,do_write_end -> writing{} do_write_do -> do_write * lib/net/http.rb: can make proxy connection by passing addresses to HTTP.new, start. * lib/net/http.rb: HTTP.new_implementation, old_implementation: can use 1.2 implementation of head, get, post, put. (see document) Tue Jun 27 12:05:10 2000 Katsuyuki Komatsu * win32.c (myfdclr): new function. * win32.h: add FD_CLR. Mon Jun 26 23:41:41 2000 WATANABE Hirofumi * ruby.h: add cast for ANSI style. * gc.c (rb_data_object_alloc): use RUBY_DATA_FUNC. Mon Jun 26 22:20:03 2000 Katsuyuki Komatsu * win32/win32.c (is_socket, extract_file_fd): New function. * win32/win32.c (myfdopen): use is_socket(). * win32/win32.c (myselect): return non socket files immediately if file and socket handles are mixed. Mon Jun 26 16:21:30 2000 Yukihiro Matsumoto * eval.c (rb_thread_schedule): wait_for cleared too early. Mon Jun 26 09:15:31 2000 Yukihiro Matsumoto * pack.c: remove obsolete 'F', 'D' specifiers. Sun Jun 25 00:55:03 2000 Katsuyuki Komatsu * ext/socket/socket.c (sock_s_getnameinfo): `res' would not be assigned if TYPE(sa) == T_STRING. Sat Jun 24 14:36:29 2000 WATANABE Hirofumi * config*.dj, configure.bat, top.sed: move to djgpp/. Sat Jun 24 02:34:17 2000 Yukihiro Matsumoto * ruby.c (load_file): call require_libraries() here to let debug.rb work properly. Fri Jun 23 22:34:51 2000 Katsuyuki Komatsu * bignum.c (rb_big_lshift): reorder xds assignment to avoid reusing `x' as `len' by VC++ 6.0 SP3 compiler with -Ox switch. Fri Jun 23 01:11:27 2000 Yukihiro Matsumoto * string.c (rb_str_substr): should return empty string (""), if beg == str.size and len == zero, mostly for convenience and backward compatibility. * parse.y (new_super): should tweak block_pass node for super too. * string.c (rb_str_split_m): last split element should not be nil, but "" when limit is specified. Thu Jun 22 17:27:46 2000 Yukihiro Matsumoto * string.c (rb_str_substr): str[n,m] now returns nil when n equals to str.size. Thu Jun 22 13:49:02 2000 Uechi Yasumasa * lib/net/ftp.rb: support resuming. Thu Jun 22 13:37:19 2000 WATANABE Hirofumi * eval.c (rb_thread_sleep_forever): merge pause() macro. Wed Jun 21 08:49:04 2000 Yukihiro Matsumoto * eval.c (rb_eval): should not raise exception just by defining singleton class. Wed Jun 21 01:18:03 2000 Yukihiro Matsumoto * ruby.h: two macros RUBY_DATA_FUNC and RUBY_METHOD_FUNC are added to make writing C++ extensions easier. * array.c (rb_ary_dup): internal classes should not be shared by dup. * hash.c (rb_hash_dup): ditto. * object.c (rb_obj_dup): ditto. * string.c (rb_str_dup): ditto. * error.c (Init_Exception): renamed NotImplementError to NotImplementedError. Tue Jun 20 16:22:38 2000 Yukihiro Matsumoto * time.c (make_time_t): bug in DST boundary. Tue Jun 20 10:54:19 2000 WATANABE Hirofumi * configure.in: add eval sitedir. Tue Jun 20 06:14:43 2000 Wakou Aoyama * lib/cgi.rb: change: version syntax. old: x.yz, now: x.y.z * lib/net/telnet.rb: ditto. Tue Jun 20 00:37:45 2000 Yukihiro Matsumoto * re.c (rb_reg_kcode_m): Regexp#kcode returns nil for code unfixed regexp object. * bignum.c (bigdivmod): bignum zero check was wrong. Mon Jun 19 10:48:28 2000 Yukihiro Matsumoto * variable.c (rb_cvar_set): forgot to add security check for class variable assignment. Sun Jun 18 22:49:13 2000 WATANABE Hirofumi * configure.in: single quoted sitedir. * mkconfig.rb: add DESTDIR for cross-compiling. * lib/mkmf.rb: add DESTDIR. * ruby.c (load_file): force binmode if fname includes ".exe" on DOSISH. Sat Jun 17 23:22:17 2000 Yukihiro Matsumoto * sprintf.c (rb_f_sprintf): should ignore negative precision given by <%.*>. * sprintf.c (rb_f_sprintf): should allow zero precision. Sat Jun 17 03:13:29 2000 Yukihiro Matsumoto * time.c (time_localtime): avoid unnecessary call of localtime. * time.c (time_gmtime): avoid unnecessary call of gmtime. * process.c (proc_wait2): new method. * process.c (proc_waitpid): second argument made optional. * process.c (proc_waitpid2): new method. Sat Jun 17 00:05:00 2000 Yukihiro Matsumoto * re.c (rb_reg_clone): should initialize member fields. Fri Jun 16 22:49:34 2000 Yukihiro Matsumoto * io.c (rb_io_rewind): set lineno to zero. Fri Jun 16 22:47:47 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.23. * lib/net/protocol.rb: too many CRLF in last line. Fri Jun 16 21:23:59 2000 WATANABE Hirofumi * configure.in: add pause(2) checking. * eval.c: define pause() if missing. Fri Jun 16 18:41:58 2000 Koji Arai * process.c (proc_setsid): BSD-style setpgrp() don't return process group ID, but 0 or -1. Fri Jun 16 16:23:35 2000 Koji Arai * file.c (rb_stat_inspect): gives detailed information; compatibility with ruby-1.4.x. Fri Jun 16 05:18:45 2000 Yasuhiro Fukuma * configure.in: FreeBSD: do not link dummy libxpg4 which was merged into libc. Fri Jun 16 03:17:36 2000 Satoshi Nojo * ext/dbm/dbm.c (fdbm_length): use GetDBM. empty?, [] too. * ext/gdbm/gdbm.c (fgdbm_length): ditto. * ext/sdbm/init.c (fsdbm_length): ditto. Fri Jun 16 01:57:31 2000 Yukihiro Matsumoto * eval.c (rb_thread_sleep_forever): pause(2) instead of sleep(3). Thu Jun 15 10:46:36 2000 Yukihiro Matsumoto * string.c (rb_str_sub_bang): should propagate taintness from replacement string. Wed Jun 14 17:01:41 2000 Katsuyuki Komatsu * rubytest.rb: add CONFIG['EXEEXT'] to the executable file name. Wed Jun 14 14:50:00 2000 Yukihiro Matsumoto * string.c (rb_f_sub): assign to $_ only if modification happens. * string.c (rb_f_gsub): ditto. * string.c (rb_f_chop): ditto. * string.c (rb_f_chomp): ditto. * io.c (io_reopen): preserve file position by ftell/fseek, if io is a seekable. * eval.c (method_arity): wrong arity number for the methods with optional arguments. * time.c (make_time_t): opposite timezone shift (should be negative). Wed Jun 14 14:07:38 2000 WATANABE Hirofumi * io.c: typo(ig/if). * re.c: typo(re/reg). add rb_reg_check(). * time.c: remove unneeded declare(daylight, timezone). * configure.in: add include when daylight checking. Wed Jun 14 11:36:52 2000 WATANABE Hirofumi * marshal.c (r_object): modified for symbols. * marshal.c (w_object): ditto. Wed Jun 14 10:04:58 2000 Yukihiro Matsumoto * re.c (rb_memcmp): should compare according to ruby_ignorecase. * string.c (rb_str_cmp): use rb_memcmp. * string.c (rb_str_index): ditto. * string.c (rb_str_rindex): ditto. * string.c (rb_str_each_line): ditto. Wed Jun 14 04:58:53 2000 Dave Thomas * io.c (rb_io_set_lineno): should have returned VALUE, not integer. Wed Jun 14 09:29:42 2000 Yukihiro Matsumoto * string.c (rb_str_dup): dup should always propagate taintness. Wed Jun 14 00:50:14 2000 Wakou Aoyama * lib/cgi.rb: read_multipart(): if no content body then raise EOFError. Tue Jun 13 11:46:17 2000 Yukihiro Matsumoto * process.c (proc_setsid): try implement it using setpgrp() and ioctl(fd, TIOCNOTTY, NULL). * re.c (rb_reg_prepare_re): magic variable $= should affect regex pattern match. * time.c (make_time_t): use tm.tm_gmtoff if possible. * time.c (time_zone): use tm.tm_zone if available. Tue Jun 13 01:50:57 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.22. * lib/net/http.rb: HTTPResponse#body returns body. Mon Jun 12 23:41:54 2000 WATANABE Hirofumi * configure.in (daylight): avoid GCC optimization. Mon Jun 12 19:02:27 2000 WATANABE Hirofumi * configure.in: cygwin has strange timezone. * time.c (time_zone): use tzname and daylight. Sat Jun 10 23:10:32 2000 Yukihiro Matsumoto * io.c (rb_io_seek): whence is optional, default is SEEK_SET. Fri Jun 9 17:00:29 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.21. * lib/net/http.rb: exception is raised with response object. Fri Jun 9 15:11:35 2000 Yukihiro Matsumoto * time.c (make_time_t): supports daylight saving time. * eval.c (rb_thread_safe_level): should retrieve current $SAFE value if a thread is the current thread. Thu Jun 8 14:25:45 2000 Hiroshi Igarashi * lib/mkmf.rb: add target `distclean' in Makefile for extlib. target `clean' doesn't remove Makefile. Thu Jun 8 13:34:03 2000 Dave Thomas * numeric.c: add nan?, infinite?, and finite? to Float Thu Jun 8 00:31:04 2000 WATANABE Hirofumi * regex.h: export re_mbctab properly on cygwin. * dln.c: use dlopen instead of LoadLibrary on cygwin. Thu Jun 8 13:41:34 2000 Tadayoshi Funaba * file.c (rb_file_s_basename): might dump core. Tue Jun 6 03:29:12 2000 Yukihiro Matsumoto * dir.c (dir_foreach): now returns nil for consistency. * bignum.c (bigdivmod): modulo by small numbers was wrong. Mon Jun 5 00:18:08 2000 WATANABE Hirofumi * bignum.c: avoid conflict with USHORT on mingw32. Mon Jun 5 00:13:35 2000 WATANABE Hirofumi * eval.c (rb_thread_schedule): =/== typo. Sun Jun 4 03:17:36 2000 Wakou Aoyama * lib/cgi.rb: improve: CGI::pretty() Sun Jun 4 02:01:10 2000 WATANABE Hirofumi * lib/mkmf.rb: do not need to add -L$(topdir) in --enable-shared case. Sat Jun 3 13:50:06 2000 Yukihiro Matsumoto * parse.y (rb_id2name): should support constant attrset identifiers. * bignum.c (rb_big_eq): Bignum#== should not raise exception. Fri Jun 2 11:24:48 2000 Yukihiro Matsumoto * io.c (rb_io_popen): open with a block returns the value from the block. old behavior was back. Fri Jun 2 00:42:31 2000 Yukihiro Matsumoto * eval.c (rb_thread_cleanup): should clear priority for thread termination. Thu Jun 1 22:39:41 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.20. * lib/net/http.rb: wrongly closed the socket twice when no Content-Length: was given. Thu Jun 1 00:59:15 2000 Yukihiro Matsumoto * eval.c (rb_yield_0): convert Qundef to []. Wed May 31 20:45:59 2000 Dave Thomas * string.c (rb_str_slice_bang): wrong argument number. Wed May 31 12:37:04 2000 Yukihiro Matsumoto * eval.c (rb_exec_end_proc): print error message from END procs. Wed May 31 04:06:41 2000 Wakou Aoyama * lib/cgi.rb: change: CGI#out() if "HEAD" == REQUEST_METHOD then output only HTTP header. Wed May 31 01:54:21 2000 Yukihiro Matsumoto * eval.c (rb_thread_schedule): set main_thread->status to THREAD_TO_KILL, before raising deadlock error. * eval.c (rb_thread_deadlock): if curr_thread == main_thread, do not call rb_thread_restore_context() Tue May 30 23:33:41 2000 Katsuyuki Komatsu * lib/mkmf.rb (create_makefile): add $(TARGET).ilk and *.pdb to cleanup files for mswin32. Mon May 29 10:41:10 2000 Nobuyoshi Nakada * file.c (rb_file_s_basename): should propagate taintness. Sun May 28 21:37:13 2000 WATANABE Hirofumi * eval.c: bug fix: DLEXT2. Sun May 28 19:21:43 2000 WATANABE Hirofumi * win32/win32.c: use ruby's glob. * dir.c: "glob" exported and renamed to "rb_glob". * ruby.h: ditto. * main.c: turn off command line mingw32's globbing. Wed May 25 22:25:13 2000 WATANABE Hirofumi * ext/extmk.rb.in: use "ftools" instead of "rm -f". * lib/mkmf.rb: ditto. Thu May 25 22:01:32 2000 Katsuyuki Komatsu * defines.h: mswin32: remove obsolete USHORT definition. * re.h: mswin32: use EXTERN instead of extern. * regex.h: mswin32: export re_mbctab properly. * win32/ruby.def: add ruby_ignorecase and regex.c's exports. Thu May 25 21:28:44 2000 Minero Aoki * re.c (rb_reg_expr_str): escape un-printable character. Thu May 25 01:35:15 2000 Yukihiro Matsumoto * parse.y (tokadd_escape): forgot to add `\x' to hexadecimal escape sequences. * object.c (rb_obj_dup): dup for normal object (T_OBJECT) copies instance variables only. Wed May 24 23:49:47 2000 Yukihiro Matsumoto * object.c (rb_mod_initialize): should provide initialize. Wed May 24 23:17:50 2000 Katsuyuki Komatsu * win32/Makefile: remove unnecessary mv and rm command call. Wed May 24 21:01:04 2000 Katsuyuki Komatsu * ext/pty/pty.c: use "" instead of <> to include ruby.h and rubyio.h for BeOS (PowerPC). * file.c (rb_find_file): should check dln_find_file() result. * win32/ruby.def: add rb_block_given_p. Wed May 24 16:32:45 2000 Yukihiro Matsumoto * io.c (rb_io_popen): popen does not take 3rd argument anymore. * re.c (rb_reg_desc): re may be zero, check before dereferencing. Wed May 24 16:03:06 2000 Wakou Aoyama * lib/cgi.rb: bug fix: CGI::escape(), CGI::Cookie::new() * lib/net/telnet.rb: improve: binmode(), telnetmode() interface Wed May 24 13:12:31 2000 Yukihiro Matsumoto * misc/ruby-mode.el (ruby-parse-region): support `while .. do' etc. But corresponding keywords must be at the beginning of line. Tue May 23 23:50:12 2000 Yukihiro Matsumoto * re.c (rb_reg_initialize_m): wrong kcode value. * re.c (rb_reg_s_new): forgot to initialize re->ptr. Tue May 23 08:36:24 2000 Yukihiro Matsumoto * regex.c (re_compile_pattern): forgot to restore old option status by (?ix-ix). * regex.c (re_compile_fastmap): anychar may match newline if RE_OPTION_MULTILINE or RE_OPTION_POSIXLINE is set. Mon May 22 22:45:06 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.19. * lib/net/http.rb: do not use Regexp "p" option. Mon May 22 21:56:43 2000 Nobuyoshi Nakada * struct.c (rb_struct_getmember): should use ID2SYM, not INT2NUM. Mon May 22 15:07:37 2000 Yukihiro Matsumoto * file.c (rb_find_file): should check if the file really exists. Mon May 22 09:08:12 2000 Yukihiro Matsumoto * io.c (rb_io_popen): _exit(0) after processing block under the child process. * io.c (rb_io_popen): flush stdout/stderr before subprocess termination. * eval.c (rb_check_safe_str): insert rb_secure(4); operation requires untainted string should be prohibited in level 4. Sun May 21 21:17:00 2000 WATANABE Hirofumi * configure.in: add Setup.dj for djgpp cross-compiling. * Setup.dj: add readline. * instruby.rb: copy win32/win32.h to archlibdir on mingw32. Sun May 21 20:58:08 2000 Katsuyuki Komatsu * pack.c: fix OFF16 and OFF32 definitions for Alpha and IRIX64. Sun May 21 17:31:37 2000 WATANABE Hirofumi * instruby.rb: support "make install" for cross-compiling. * ext/extmk.rb.in: ditto. Sun May 21 14:22:49 2000 WATANABE Hirofumi * Makefile.in: rename prep.rb to fake.rb. * configure.in: ditto. Sat May 20 23:29:14 2000 Yukihiro Matsumoto * dir.c (dir_s_new): does not take block; "open" does. * io.c (rb_io_s_new): ditto. Fri May 19 07:44:26 2000 Yukihiro Matsumoto * dir.c (dir_s_open): Dir#open does not returns closed Dir if a block is given to the method. * re.c (rb_reg_initialize_m): Regexp::new calls initialize now. * string.c (Init_String): String#delete_at removed. * string.c (rb_str_aset_m): should have checked argc != 2. * eval.c (rb_thread_schedule): select(2) was called too many. * regex.c (re_compile_pattern): a bug in (?m) support. Pointed out by Dave Thomas . Thu May 18 23:55:26 2000 Katsuyuki Komatsu * dln.c (search_undef): st_lookup()'s 3rd parameter should be a pointer of the variable which has the same size and alignment as `char *'. * marshal.c (w_symbol, w_object): ditto. * parse.y (rb_intern): ditto. Thu May 18 18:00:35 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.18. * lib/net/protocol.rb: Net::Version was removed. * lib/net/smtp.rb: use Socket.gethostname to get local host name. Thu May 18 13:34:57 2000 Yukihiro Matsumoto * ext/socket/socket.c (ruby_connect): should not have replaced thread_write_select() by rb_thread_fd_writable(). Thu May 18 09:01:25 2000 Katsuyuki Komatsu * configure.in, ext/extmk.rb.in, lib/mkmf.rb: remove BeOS R3 support. Make a shared library (libruby.so) only if the --enable-shared option is specified. * instruby.rb: no longer use libruby.so.LIB and import.h. * io.c: fix READ_DATA_PENDING definition for BeOS (PowerPC). Wed May 17 14:14:23 2000 Yukihiro Matsumoto * re.c (rb_reg_new_1): use /m instead of /p. Wed May 17 02:22:03 2000 Yukihiro Matsumoto * eval.c (rb_thread_polling): wait 0.06 second to let other processes run. * process.c (rb_waitpid): avoid busy wait using rb_thread_polling. * file.c (rb_thread_flock): ditto. * parse.y (expr): avoid calling value_expr() twice. Wed May 17 00:45:57 2000 WATANABE Hirofumi * io.c (rb_io_binmode): should check PLATFORMs, not O_BINARY, sigh... Wed May 17 00:40:15 2000 Katsuyuki Komatsu * win32/config.h: add DLEXT2, now DLEXT on mswin32 is "so". * win32/config.status: ditto. * win32/ruby.def: add symbol "rb_big_divmod". Tue May 16 19:45:32 2000 Katsuyuki Komatsu * intern.h: use EXTERN instead of extern. * win32/ruby.def: add rb_defout, rb_stdout, ruby_errinfo, ruby_sourceline, ruby_sourcefile to work with eruby reported by Hiroshi Saito . Export both ruby_xmalloc and xmalloc etc. Tue May 16 17:00:05 2000 Masaki Fukushima * eval.c (rb_thread_select): should check whether fds are null. Tue May 16 11:51:31 2000 Yukihiro Matsumoto * io.c (pipe_open): synchronize subprocess stdout/stderr. Mon May 15 15:38:09 2000 Yukihiro Matsumoto * ruby.h: exported symbols should be for xmalloc etc. are now prefixed by 'ruby_', e.g. ruby_xmalloc(). * eval.c (rb_thread_select): remove busy wait for select. * dir.c (glob): trailing path may be null, e.g. glob("**"). Mon May 15 14:48:41 2000 Nobuyoshi Nakada * io.c (rb_io_pid): new method; returns nil if no process attached to the IO. Mon May 15 01:18:20 2000 Yukihiro Matsumoto * io.c (rb_io_s_popen): _exit after Proc execution. Sun May 14 18:05:59 2000 WATANABE Hirofumi * Makefile.in: missing/nt.c -> win32/win32.c * configure.in: bug fix; static linking on mingw32. * cygwin/GNUmakefile.in: remove VPATH. * ext/extmk.rb.in: Makefile set binmode with mingw32 on cygwin32. * lib/mkmf.rb: ditto. * win32/config.h: undef HAVE_SYS_FILE_H. Sun May 14 02:02:48 2000 WATANABE Hirofumi * lib/irb/ruby-lex.rb: '/' should be escaped in character class. Sun May 14 00:54:43 2000 WATANABE Hirofumi * configure.in, ...: support mingw32. * defines.h: ditto. undef EXTERN for tcl/tk on cygwin. * ext/*/extconf.rb: replace PLATFORM with RUBY_PLATFORM. * ext/socket/sockport.h: define IN_MULTICAST for missing IN_MULTICAST. * ext/tcltklib/tcltklib.c: remove declaration of rb_argv0. * file.c: should check S_IXGRP, S_ISGID, not NT. * io.c (rb_io_binmode): should check _IOBIN, O_BINARY, not PLATFORMs. Sat May 13 14:21:15 2000 Koji Arai * io.c (rb_io_s_popen): should check whether a block is given. Fri May 12 17:33:44 2000 Yukihiro Matsumoto * regex.c (re_compile_pattern): charset_not should not exclude newline from matching set. Thu May 11 22:51:05 2000 Ryunosuke Ohshima * pack.c (pack_pack): Bignum support. * pack.c (pack_unpack): ditto. Thu May 11 21:19:29 2000 Hiroshi Igarashi * intern.h: add missing declarations of ruby API functions. * ruby.h: fix function name in declarations. Thu May 11 22:29:25 2000 Katsuyuki Komatsu * ext/md5/depend: add $(topdir)/config.h dependency to md5c.o. * ext/md5/extconf.rb: new file to add -DHAVE_CONFIG_H flag for Alpha. Thu May 11 10:55:52 2000 Ryunosuke Ohshima * pack.c (pack_pack): packing BER compressed integer by `w'. * pack.c (pack_unpack): unpacking BER. Thu May 11 00:37:55 2000 Yukihiro Matsumoto * parse.y (parse_regx): remove in_brack. Wed May 10 12:51:18 2000 Yukihiro Matsumoto * ruby.c (proc_options): move adding RUBYLIB and "." to the load path after #! line parsing. * parse.y (parse_regx): should parse backslash escape like `\c[' here to avoid causing `unterminated regexp' error. Wed May 10 00:19:53 2000 Katsuyuki Komatsu * MANIFEST, beos/GNUmakefile.in, configure.in: no longer need beos/GNUmakefile.in to support BeOS R4.5.2 (Intel) as a result of eban's Makefile.in change. * io.c: NOFILE is already defined on BeOS R4.5 (Intel) or later. * lib/matrix.rb: remove debug print. * regex.c: don't use nested comment. Tue May 9 17:08:43 2000 Yukihiro Matsumoto * eval.c (massign): no longer convert nil into empty array. * io.c (rb_io_s_popen): optional 3rd argument to give proc, which will be executed in spawned child process. Mon May 8 23:47:39 2000 Katsuyuki Komatsu * eval.c (rb_callcc): prev & next should be initialized to zero. Mon May 8 23:17:36 2000 Yukihiro Matsumoto * dln.c (dln_init): remove possible buffer overrun. This is suggested by Aleksi Niemela . * dln.c (init_funcname): ditto. Sat May 6 23:35:47 2000 Yukihiro Matsumoto * parse.y (lhs): should allow `obj.Attr = 5' type expression. Sat May 6 15:46:08 2000 WATANABE Hirofumi * ext/socket/extconf.rb: add a new configure option to force use of the WIDE Project's getaddrinfo(): --enbale-wide-getaddrinfo. Fri May 5 21:19:22 2000 MOROHOSHI Akihiko * parse.y (yylex): allow '$1foo' and such. Fri May 5 17:57:24 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.17. * lib/net/http.rb: write also port number in Host: field. * lib/net/http.rb: see Proxy-Connection: to decide socket connection. Fri May 5 03:25:15 2000 Yukihiro Matsumoto * regex.c (re_compile_fastmap): charset_not for multibyte characters excluded too many characters. Tue May 2 13:23:43 2000 Yukihiro Matsumoto * eval.c (rb_thread_schedule): little bit more impartial context switching. Tue May 2 09:50:03 2000 Katsuyuki Komatsu * configure.in: add DLDLIBS to set platform specific library for extensions. * ext/extmk.rb.in: use @DLDLIBS@ instead of RUBY_PLATFORM choice. * lib/mkmf.rb: use CONFIG["DLDLIBS"] instead of RUBY_PLATFORM choice. * config_s.dj: add @DLDLIBS@. * win32/config.status: ditto. * win32/ruby.def: regular maintenance. Mon May 1 23:42:44 2000 WATANABE Hirofumi * configure.in, eval.c: add DLEXT2. now DLEXT on Cygwin is "so". * defines.h: use dllimport, dllexport for Cygwin 1.1.x. * ruby.h: ditto. * cygwin/GNUmakefile.in: ditto. * ext/Win32API/Win32API.c: directly "call" in asm statement for gcc 2.95.x or newer. Sat Apr 29 04:58:12 2000 Nobuyoshi Nakada * array.c (rb_ary_unshift_m): performance improvement. Fri Apr 28 00:19:22 2000 Nobuyoshi Nakada * array.c (rb_ary_unshift_m): takes items to push. Wed Apr 26 15:23:02 2000 Yukihiro Matsumoto * string.c (rb_str_succ): insert carrying character just before the leftmost alpha numeric character. * string.c (rb_str_succ): proper behavior for "".succ and "\377".succ. * string.c (rb_str_succ): use realloc and memmove. Tue Apr 25 18:28:45 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.16. * lib/net/smtp.rb: add SMTP AUTH Tue Apr 25 14:30:13 2000 Yukihiro Matsumoto * io.c (rb_io_gets_internal): shortcut when rs == rb_default_rs. Sat Apr 22 23:14:41 2000 SHIROYAMA Takayuki * configure.in: MacOS X support. Sat Apr 22 16:37:10 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.15. * lib/net/http.rb: closing socket by watching both user header and server response Fri Apr 21 21:44:34 2000 WATANABE Hirofumi * io.c (rb_io_s_pipe): should set FMODE_SYNC. Thu Apr 20 16:59:22 2000 Nobuyoshi Nakada * eval.c (massign): `*lvalue = false' should assign `[false]' to lvalue. Wed Apr 19 08:35:08 2000 Yukihiro Matsumoto * class.c (rb_singleton_class): generate singleton class for special constants: nil, true, false. Wed Apr 19 02:09:30 2000 Yukihiro Matsumoto * class.c (rb_singleton_class): singleton method for nil, true, false is possible now. * eval.c (rb_eval): ditto. Tue Apr 18 18:54:25 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.14. * lib/net/http.rb: new method HTTP#head2. * lib/net/http.rb: get2/post2 does not raise exceptions. Mon Apr 17 15:16:31 2000 Yukihiro Matsumoto * io.c (rb_io_close): to detect some exceptional status, writable IO should be flushed before close; Sat Apr 15 18:29:00 2000 Yukihiro Matsumoto * array.c (rb_ary_collect_bang): Array#filter renamed. Fri Apr 14 19:47:11 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.13. * lib/net/pop.rb: accept illegal timestamp * lib/net/http.rb: when body was chunked, does not set Content-Length: Tue Apr 11 21:14:42 2000 Katsuyuki Komatsu * config_s.dj: add @sitedir@. * configure.in: add --with-sitedir=DIR option. * instruby.rb: use CONFIG["sitedir"]. * lib/mkmf.rb: support 'make site-install'. * win32/config.status: add @sitedir@. Tue Apr 11 16:25:15 2000 Yukihiro Matsumoto * bignum.c (rb_big_2comp): unnecessary lvalue cast removed. Tue Apr 11 02:25:53 2000 Yukihiro Matsumoto * hash.c (env_fetch): new method. * marshal.c (marshal_dump): accepts depth = nil for unlimited depth. Sun Apr 9 20:49:19 2000 Dave Thomas * parse.y (str_extend): Allow class variables to be expanded. Fri Apr 7 02:03:54 2000 Yukihiro Matsumoto * error.c (rb_sys_fail): escape non-printable characters. Thu Apr 6 20:10:47 2000 Katsuyuki Komatsu * ext/extmk.rb.in (create_makefile): BeOS --program-suffix support. * lib/mkmf.rb (create_makefile): ditto. Thu Apr 6 09:55:26 2000 Katsuyuki Komatsu * error.c (rb_sys_fail): need rb_exc_new2() call on BeOS. Mon Apr 3 17:22:27 2000 Yukihiro Matsumoto * io.c (rb_io_reopen): support tempfile. * eval.c (catch_i): should supply argument. Sat Apr 1 22:50:28 2000 Yukihiro Matsumoto * marshal.c (r_object): wrong symbol restoration. Sat Apr 1 21:30:53 2000 WATANABE Hirofumi * io.c (rb_io_printf, rb_f_printf): should use rb_io_write. Sat Apr 1 00:16:05 2000 Yukihiro Matsumoto * gc.c (rb_gc_call_finalizer_at_exit): should be clear flags before calling finalizers. * eval.c (specific_eval): can be called without SecurityError, if $SAFE >= 4. * object.c (sym_inspect): inspect gives ":sym", to_s gives "sym". Fri Mar 31 22:07:04 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.12. * lib/net/protocol.rb: update Net::Protocol::Proxy#connect * lib/net/protocol.rb: ReplyCode is not a class * lib/net/http.rb: header value format was change: values do not include header name * lib/net/http.rb: header is not a Hash, but HTTPResponse Thu Mar 30 12:19:44 2000 Katsuyuki Komatsu * enum.c (enum_find): rb_eval_cmd() should be called with array. Tue Mar 28 13:57:05 2000 Clemens Hintze * ext/dbm/dbm.c (fdbm_invert): should return new hash. * ext/gdbm/gdbm.c (fgdbm_invert): ditto. Tue Mar 28 00:58:03 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.11. * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: does not dispatch any commands while dispatching command. * lib/net/protocol.rb: failed to get error class of inherited ReplyCode * lib/net/http.rb: change feature of "get2", "post2" Mon Mar 27 01:34:58 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.10. * lib/net/http.rb: return value of 'head' was wrong. Sun Mar 26 17:47:35 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.9. * lib/net/smtp.rb: SMTP#do_ready wrongly took no arguments Sat Mar 25 23:21:10 2000 Yukihiro Matsumoto * marshal.c (w_object): symbols should be converted to ID before dumping out. Fri Mar 24 18:26:51 2000 Yukihiro Matsumoto * file.c (test_check): should have checked exact number of arguments. Fri Mar 24 21:02:11 2000 Koji Arai * signal.c (trap): should treat some symbols as the signal. Fri Mar 24 06:58:03 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.8. * lib/net/http.rb: post, get2, post2, get_body * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: separate Command/Socket documentation. Thu Mar 23 02:26:14 2000 Yukihiro Matsumoto * io.c (rb_io_fptr_finalize): fptr may be null. * io.c (rb_io_s_new): now calls `initialize'. * io.c (rb_io_initialize): actual open done in this method. * io.c (rb_file_initialize): ditto. * eval.c (rb_eval): class variables in singleton class definition is now handled properly (I hope). Wed Mar 22 21:49:36 2000 Minero Aoki * st.c (st_delete_safe): skip already deleted entry. * hash.c (rb_hash_delete): modify brace miss. Wed Mar 22 08:53:58 2000 Yukihiro Matsumoto * eval.c (exec_under): do not push cbase if ruby_cbase == under. * node.h (NEW_CREF0): preserve cbase nesting. Tue Mar 21 12:57:50 2000 Yukihiro Matsumoto * object.c (rb_class_s_new): Class::new should call `inherited'. Sat Mar 18 12:36:09 2000 Nobuyoshi Nakada * eval.c (rb_backtrace, make_backtrace): removed unused variable `lev'. * eval.c (rb_attr): calls `method_added' at attribute definition. * eval.c (rb_mod_modfunc): calls `singleton_method_added' while `module_function'. * eval.c (rb_eval): parameter to `method_added' and `singleton_method_added' is Symbol. * eval.c (Init_eval): caches IDs for `method_added' and `singleton_method_added'. Sat Mar 18 11:25:10 2000 Yukihiro Matsumoto * parse.y (rescue): allows `rescue Error in foo'. experimental. which is better this or preparing alias `exception' for `$!'? Fri Mar 17 15:02:45 2000 Yukihiro Matsumoto * variable.c (rb_autoload_id): defining new autoload should be prohibited for $SAFE > 4. * variable.c (rb_autoload_load): autoload should be possible for $SAFE > 4. * eval.c (call_trace_func): should handle T_ICLASS properly. Fri Mar 17 14:34:30 2000 Yukihiro Matsumoto * string.c (str_gsub): forgot to initialize str->orig. Fri Mar 17 01:24:59 2000 Dave Thomas * string.c (rb_str_clone): forgot to copy str->orig if STR_NO_ORIG is set by Array#pack. Wed Mar 15 21:25:04 2000 Minero Aoki * array.c (rb_ary_join): 'result' is always duplicated before concat string. Wed Mar 15 17:26:05 2000 Yukihiro Matsumoto * hash.c (rb_hash_s_create): unexpected recursive call removed. this bug was found by Satoshi Nojo . Wed Mar 15 13:12:39 2000 Yukihiro Matsumoto * eval.c (Init_Thread): Thread.join removed finally. * string.c (rb_str_chomp_bang): forgot to call rb_str_modify(). Mon Mar 13 16:12:13 2000 Yukihiro Matsumoto * eval.c (block_pass): distinguish real orphan block and still on-stack block passed by block argument. Mon Mar 13 00:20:25 2000 Yukihiro Matsumoto * parse.y (f_norm_arg): proper error message when constant comes in formal argument list. this message is suggested by Muvaw Pnazte . * eval.c (rb_f_raise): proper error message when the first argument is not an exception class/object. * string.c (rb_str_dup): dup now postpone buffer copy as long as possible. performance improved by lazy copying. Sun Mar 12 13:58:52 2000 Koji Arai * signal.c (rb_f_kill): should treat some symbols as the signal. Sat Mar 11 22:03:03 2000 Yukihiro Matsumoto * string.c (rb_str_gsub): performance tune by avoiding buffer copy. * eval.c (rb_f_missing): check if argv[0] is ID. Sat Mar 11 15:49:41 2000 Tadayoshi Funaba * struct.c (rb_struct_aref): struct aref by symbol. Sat Mar 11 05:07:11 2000 Yukihiro Matsumoto * process.c (proc_setpriority): should return 0, not nil. * process.c (proc_setpgid): ditto. Fri Mar 10 18:14:54 2000 Yukihiro Matsumoto * file.c (path_check_1): confusing buf and path. this bug found by . Fri Mar 10 09:37:49 2000 Katsuyuki Komatsu * MANIFEST: add beos/GNUmakefile.in. * configure.in: support BeOS R4.5.2 (Intel). * beos/GNUmakefile.in: new file to support BeOS R4.5.2 (Intel). Thu Mar 9 11:13:32 2000 Yukihiro Matsumoto * regex.c (re_compile_fastmap): fixed embarrassing brace bug. Thu Mar 9 01:36:32 2000 WATANABE Hirofumi * missing/flock.c: emulate missing flock() with fcntl(). Thu Mar 9 00:29:35 2000 Yukihiro Matsumoto * object.c (sym_to_s): returns ":sym". * object.c (sym_id2name): separated from to_s; returns "sym". Wed Mar 8 19:16:19 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.7. * lib/net/http.rb (connecting): returns header Wed Mar 8 02:08:43 2000 Yukihiro Matsumoto * parse.y: escape expansion too early. * string.c (rb_f_scan): Kernel#scan added. * regex.c (re_compile_pattern): support \cX et al. Tue Mar 7 01:44:27 2000 Yukihiro Matsumoto * io.c (set_stdin): simplified procedure, allows $stdin = DATA; experimental. * io.c (set_outfile): ditto. * re.c (Init_Regexp): new method Regexp#last_match added; it's an alternative for $~. * configure.in (DEFAULT_KCODE): KCODE_NONE should be the default. * dir.c (dir_s_rmdir): should return 0 on success. * signal.c: remove CWGUSI support. Mon Mar 6 12:28:37 2000 Yukihiro Matsumoto * marshal.c (w_symbol): support symbol object. * util.c: make symbol as separated class. * error.c (Init_Exception): new exception RangeError. * ext/socket/socket.c (ip_addrsetup): should check length of hostname. * ext/socket/socket.c (ip_addrsetup): check newline at the end of hostname. These fixes suggested by Muvaw Pnazte . Sun Mar 5 20:35:45 2000 WATANABE Hirofumi * ext/Win32API/Win32API.c (Win32API_initialize): should call LoadLibrary() everytime and should assign the hdll to Win32API object(protect the hdll from GC). Sun Mar 5 18:49:06 2000 Nakada.Nobuyoshi * misc/ruby-mode.el (ruby-parse-region): not treat method `begin' and `end' as reserved words. * misc/ruby-mode.el (ruby-font-lock-docs): ignore after `=begin' and `=end'. * misc/ruby-mode.el (ruby-font-lock-keywords, hilit-set-mode-patterns): added `yield' to keywords. * misc/ruby-mode.el (ruby-font-lock-keywords, hilit-set-mode-patterns): matches keywords at end of buffer. Sun Mar 5 18:08:53 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.6. * lib/net/http.rb: allow to omit 'start' Tue Feb 29 01:08:26 2000 Yukihiro Matsumoto * range.c (range_initialize): initialization done in `initialize'; `initialize' should not be called more than once. * object.c (Init_Object): default `initialize' should take zero argument. * time.c (time_s_new): call `initialize' in Time::new. Sat Feb 26 22:39:31 2000 EGUCHI Osamu * string.c (rb_str_times): fix String#* with huge string. Sat Feb 26 00:14:59 2000 Yukihiro Matsumoto * dir.c (dir_s_new): call `initialize' in Dir::new. Fri Feb 25 23:01:49 2000 Katsuyuki Komatsu * ruby.h: export ruby_safe_level by EXTERN for mswin32. * win32/ruby.def: regular maintenance. Fri Feb 25 22:12:46 2000 Yukihiro Matsumoto * io.c (rb_io_reopen): IO#reopen should accept path as well. * string.c (rb_str_s_new): call `initialize' in String::new. * hash.c (rb_hash_s_new): call `initialize' in Hash::new. * array.c (rb_ary_s_new): call `initialize' in Array::new. Fri Feb 25 12:50:20 2000 Yukihiro Matsumoto * eval.c (rb_thread_start_timer): interval changed to 10ms from 50ms. Fri Feb 25 06:42:26 2000 GOTOU Yuuzou * ext/socket/socket.c (ip_addrsetup): hostp should remain NULL if host is nil. Thu Feb 24 16:53:47 2000 Yukihiro Matsumoto * eval.c (rb_thread_schedule): priority check for sleep expired threads needed. Wed Feb 23 14:22:32 2000 Yukihiro Matsumoto * array.c (rb_ary_join): forgot to initialize a local variable `taint'. Tue Feb 22 07:40:55 2000 Yukihiro Matsumoto * re.c (Init_Regexp): renamed to MatchData, old name MatchingData remain as alias. Tue Feb 22 00:20:21 2000 Minero Aoki * lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.5. * lib/net/session.rb: rename to protocol.rb * lib/net/protocol.rb: ProtocolSocket -> Net::Socket * lib/net/protocol.rb: Net::Socket#write, write_pendstr can take block * lib/net/smtp.rb: new methods SMTP#ready SMTPCommand#write_mail * lib/net/pop.rb: POPMail#pop can take block Sat Feb 19 23:58:51 2000 Yukihiro Matsumoto * regex.c (re_match): pop_loop should not pop at forward jump. Fri Feb 18 17:15:40 2000 Yukihiro Matsumoto * eval.c (method_clone): method objects are now clonable. Fri Feb 18 00:27:34 2000 Yukihiro Matsumoto * variable.c (rb_shared_variable_declare): shared variable (aka class/module variable) introduced. prefix `@@'. experimental. * class.c (rb_scan_args): new format char '&'. Thu Feb 17 19:09:05 2000 Katsuyuki Komatsu * win32/win32.c (mypopen): don't close handle if it is not assigned. * win32/win32.c (my_open_osfhandle): support O_NOINHERIT flag. * win32/win32.c (win32_getcwd): rename getcwd to win32_getcwd in order to avoid using the C/C++ runtime DLL's getcwd. Use CharNext() to process directory name. * win32/win32.h: map getcwd to win32_getcwd. Wed Feb 16 00:32:49 2000 Yukihiro Matsumoto * eval.c (method_arity): nd_rest is -1 for no rest argument. * process.c (proc_waitpid): returns nil when waitpid(2) returns 0. Tue Feb 15 01:47:00 2000 Yukihiro Matsumoto * process.c (rb_f_waitpid): pid_t should be signed. Mon Feb 14 13:59:01 2000 Yukihiro Matsumoto * parse.y (yylex): yylex yields wrong tokens for `:foo=~expr'. * ruby.c (load_file): exit if reading file is empty. Mon Feb 14 03:34:52 2000 Yukihiro Matsumoto * parse.y (yylex): `foo.bar=1' should be <.><=><1>, not <.><1>. * eval.c (rb_thread_restore_context): process according to RESTORE_* is moved after longjmp(). * eval.c (thread_switch): new function to process RESTORE_*. Sun Feb 13 16:19:49 2000 WATANABE Hirofumi * ruby.c (require_libraries): don't access freed memory. * ruby.c (add_modules): ditto. Fri Feb 11 12:06:22 2000 Yukihiro Matsumoto * parse.y (parse_quotedwords): %w() need to split not only by mere spaces, but by all whitespaces. Thu Feb 10 02:12:04 2000 Yukihiro Matsumoto * string.c (rb_str_index_m): did not support negative offset. Wed Feb 9 21:54:26 2000 Katsuyuki Komatsu * ext/socket/getaddrinfo.c: gcc --traditional support. Rearrange headers to work AC_C_CONST. * ext/socket/getnameinfo.c: ditto. * ext/socket/socket.c: mswin32: use double instead of long long. Wed Feb 9 16:30:41 2000 Yukihiro Matsumoto * numeric.c (num_coerce): should return [y, x]. Wed Feb 9 11:07:30 2000 Yukihiro Matsumoto * ruby.c (ruby_prog_init): loadpath structure changed. Tue Feb 8 02:07:33 2000 Yukihiro Matsumoto * regex.c (re_search): optimize for \G at top. * regex.c (re_compile_pattern): \G introduced. * regex.c (re_match): ditto. * string.c (str_sub_bang): old behavior restored: bang method returns nil if string not changed. * regex.c (re_compile_pattern): support independent subexpression `(?>pattern)'. * regex.c (re_match): ditto. Mon Feb 7 15:51:08 2000 Yukihiro Matsumoto * regex.c (re_match): now understands interrupts under Ruby. Mon Feb 7 07:51:52 2000 Yukihiro Matsumoto * array.c (rb_ary_uniq_bang): always return an Array. * array.c (rb_ary_compact_bang): ditto. * array.c (rb_ary_flatten_bang): ditto. * hash.c (rb_hash_reject): returns a Hash, not an Array. * hash.c (env_reject): ditto. Fri Feb 4 10:20:25 2000 Yukihiro Matsumoto * string.c (scan_once): scan now leaves information about the last successful pattern match in $&. * io.c (rb_io_close): should not check closed IO. Fri Feb 4 05:44:01 2000 Kentaro Inagaki * ext/socket/socket.c (s_recv): TRAP_BEG after retry entry. Wed Feb 2 22:33:45 2000 Nobuyoshi Nakada * eval.c (rb_thread_start): receives argument from outside, like `Thread::start(1,2,3){|a,b,c| ... }'. Wed Feb 2 22:14:40 2000 Yukihiro Matsumoto * re.c (rb_reg_regsub): should check regs->num_regs. * re.c (rb_reg_search): remove matchcache, use static struct re_register instead. * re.c (match_getter): avoid cloning match data. Wed Feb 2 17:12:15 2000 Dave Thomas * samples/eval.rb: Rescue new ScriptError exception Wed Feb 2 02:06:07 2000 Yukihiro Matsumoto * string.c (str_gsub_bang): gsub! now leaves information about the last successful pattern match in $&. Mon Jan 31 15:24:58 2000 Yukihiro Matsumoto * string.c (str_sub_bang): bang method returns string always. experimental. Sun Jan 30 17:58:09 2000 WATANABE Hirofumi * eval.c: arrange to use setitimer(2) for BOW, DJGPP * defines.h: ditto. use random(3) on cygwin b20.1. Sun Jan 30 17:20:16 2000 WATANABE Hirofumi * eval.c: use getrlimit(2) on DJGPP. Thu Jan 27 01:27:10 2000 GOTO Kentaro * dir.c (glob): glob pattern "/*" did not match. Wed Jan 26 22:30:47 2000 Shigeo Kobayashi * numeric.c (flo_modulo): wrong result for negative modulo. Wed Jan 26 02:01:57 2000 Yukihiro Matsumoto * file.c (test_c): should use S_ISCHR. * file.c (rb_stat_c): ditto. * string.c (rb_str_each_line): should propagate tainting. Tue Jan 25 04:01:34 2000 Yukihiro Matsumoto * object.c (rb_obj_freeze): all objects made freezable. Tue Jan 25 00:37:01 2000 WATANABE Hirofumi * configure.in: use AC_CHECK_TOOL for cross compiling. Mon Jan 24 19:01:54 2000 Nobuyoshi Nakada * array.c (rb_protect_inspect): should be checked by id of objects; not by object themselves. Mon Jan 24 18:48:08 2000 Minero Aoki * eval.c (rb_eval): too many warnings; warned on every method overriding. should be on method discarding. Mon Jan 24 02:56:44 2000 Yukihiro Matsumoto * parse.y (yylex): -2.abs should be `(-2).abs' to accomplish the principle of less surprise. `+2' too. * eval.c (rb_eval): when defining class is already there, and superclass differ, throw away the old class. * variable.c (rb_const_set): gives warning again on constant redefinition. * error.c (Init_Exception): SyntaxError, NameError, LoadError and NotImplementError are subclasses of ScriptError * parse.y (parse_quotedwords): no longer use `String#split'. and enable space escape within quoted word list. e.g. %w(a\ b\ c abc) => ["a b c", "abc"]. * string.c (rb_str_slice_bang): new method `slice!'. Fri Jan 21 21:56:08 2000 Minero Aoki * lib/net/session.rb, smtp.rb, pop.rb, http.rb: 1.1.4. * lib/net/http.rb: can receive messages which have no Content-Length:. Fri Jan 21 16:15:59 2000 Yukihiro Matsumoto * eval.c (thgroup_s_new): new class ThreadGroup. Tue Jan 18 12:24:28 2000 Yukihiro Matsumoto * struct.c (Init_Struct): remove Struct's own hash and eql?. Sat Jan 15 22:21:08 2000 Nobuyoshi Nakada * eval.c (search_method): argument klass may be 0. Sat Jan 15 15:03:46 2000 Yukihiro Matsumoto * enum.c (enum_index): remove this method. * enum.c: remove use of pointers to local variables. find, find_all, min, max, index, member?, each_with_index, * eval.c (massign): multiple assignment does not use to_a anymore. experimental. Fri Jan 14 12:22:04 2000 Yukihiro Matsumoto * string.c (rb_str_replace): use memmove instead of memcpy for overwrapping strings (e.g. a[1] = a). Thu Jan 13 11:12:40 2000 Yukihiro Matsumoto * parse.y (arg_add): use new node, ARGSPUSH. Mon Jan 10 18:32:28 2000 Koji Arai * marshal.c (w_object): forgot an argument to call w_ivar(). Sun Jan 9 18:13:51 2000 Katsuyuki Komatsu * random.c: first was not defined unless HAVE_RANDOM. Sat Jan 8 19:02:49 2000 Yukihiro Matsumoto * io.c (rb_io_sysread): raise IOError for buffered IO. * ext/socket/socket.c (s_recv): ditto. Fri Jan 7 00:59:29 2000 Masahiro Tomita * io.c (io_fread): TRAP_BEG/TRAP_END added around getc(). Thu Jan 6 00:39:54 2000 Yukihiro Matsumoto * random.c (rb_f_rand): should be initialized unless srand is called before. Wed Jan 5 16:59:34 2000 Minero Aoki * lib/net/session.rb, smtp.rb, pop.rb, http.rb: 1.1.3. * lib/net/session.rb: Session -> Protocol, ... * lib/net/http.rb: HTTPCommand implementation was changed. Wed Jan 5 02:14:46 2000 EGUCHI Osamu * parse.y: Fix SEGV on empty parens with UMINUS or UPLUS. Tue Jan 4 22:25:54 2000 Yukihiro Matsumoto * parse.y (stmt): `() while cond' dumped core. Tue Jan 4 06:04:14 2000 WATANABE Hirofumi * configure.in: modify for cross-compiling. use target_* instead of host_*. use AC_CANONICAL_TARGET. * Makefile.in: ditto. * cygwin/GNUmakefile.in: ditto. Sat Jan 1 13:26:14 2000 Yukihiro Matsumoto * eval.c (rb_yield_0): force_recycle ruby_dyna_vars to gain performance. * array.c (rb_ary_delete_at_m): takes same argument pattern with rb_ary_aref. Sat Jan 1 10:12:26 2000 Nobuyoshi Nakada * ruby.h,util.c (rb_special_const_p): peep hole optimization. * ruby.h,util.c (rb_test_false_or_nil): removed. * ruby.h (RTEST, SPECIAL_CONST_P): peep hole optimization. * ruby.h (FL_ABLE, FL_SET, FL_UNSET, FL_REVERSE): made expressions not statements. * ruby.h (OBJ_INFECT): newly added macro which copies taint from `s' to `x'. Sat Jan 1 02:04:18 2000 Yukihiro Matsumoto * eval.c (rb_thread_safe_level): new method. * eval.c (rb_yield_0): recycle dyna_var_map to reduce object allocation. Fri Dec 31 00:52:48 1999 Yukihiro Matsumoto * eval.c: thread independent trace_func not needed. Thu Dec 30 14:47:31 1999 akira yamada * configure.in: specifies -soname in LIBRUBY_DLDFLAGS on linux platforms. Thu Dec 30 10:51:27 1999 Yukihiro Matsumoto * array.c,io.c,hash,c,re.c,string.c: `_m' suffix instead of `_method' for wrapper functions to implement method, e.g. `rb_str_join_m()'. Thu Dec 30 02:08:02 1999 Yukihiro Matsumoto * bignum.c (rb_cstr2inum): non-numeric format check added. currently it works only with base == 0 (i.e. Integer()). * bignum.c (rb_str2inum): now takes VALUE to 1st argument. null byte check added. * array.c (rb_ary_replace): unless replacement is an array, replacement shall be converted to array by `[replacement]', not by `replacement.to_a'. * array.c (rb_ary_plus): right operand must be an array. * array.c (rb_ary_concat): argument must be an array. Mon Dec 27 12:35:47 1999 Katsuyuki Komatsu * ext/socket/socket.c (sock_finalize): mswin32: fix socket handle leak. * win32/win32.c (myfdclose): ditto. Sun Dec 26 23:15:13 1999 Katsuyuki Komatsu * win32/win32.c (mypopen): raise catchable error instead of rb_fatal. * win32/win32.c (mypclose): fix process handle leak. Sun Dec 26 16:17:11 1999 Katsuyuki Komatsu * ext/Win32API/Win32API.c (Win32API_initialize): use UINT2NUM instead of INT2NUM to set __dll__ and __proc__. Sat Dec 25 00:08:59 1999 KANEKO Naoshi * ext/Win32API/Win32API.c (Win32API_Call): remove 'dword ptr' from _asm. Fri Dec 24 10:26:47 1999 Koji Oda * win32/win32.h: use "C++" linkage. Fri Dec 24 02:00:57 1999 Yukihiro Matsumoto * eval.c (THREAD_ALLOC): should initialize th->trace. Fri Dec 24 00:43:39 1999 KANEKO Naoshi * io.c (pipe_open): check for `fptr->f == NULL'. * win32/win32.c (mypopen): STDERR does not work during ` function. Wed Dec 22 22:50:40 1999 Minero Aoki * lib/net/session.rb, smtp.rb, pop.rb, http.rb: 1.1.2. * lib/net/http.rb: HTTP support is enhanced a little * lib/net/http.rb: support proxy Tue Dec 21 17:21:28 1999 Koji Oda * ext/socket/socket.c (sock_finalize): mswin32: fix FILE* leak. Tue Dec 21 05:33:56 1999 Minero Aoki * lib/net/session.rb, smtp.rb, pop.rb, http.rb: 1.1.1. * lib/net/http.rb: support HTTP chunk Mon Dec 20 19:08:12 1999 Nobuyoshi Nakada * file.c (rb_file_s_expand_path): handle dir separator correctly. Sun Dec 19 22:56:31 1999 KANEKO Naoshi * lib/find.rb: support dosish root directory. * win32/Makefile: ditto. * win32/config.status: ditto. * win32/win32.c (opendir): ditto. * win32/win32.c (opendir): use CharPrev() to get last character of the directory name. Sat Dec 18 03:00:01 1999 Yukihiro Matsumoto * file.c (path_check_1): check should be done by absolute path. * marshal.c (r_ivar): should restore generic_ivar too. * marshal.c (w_ivar): should dump generic_ivar too. Fri Dec 17 22:46:46 1999 Minero Aoki * lib/net/session.rb, smtp.rb, pop.rb, http.rb: 1.1.0. * lib/net/http.rb: test release * lib/net/session.rb: support class swapping * lib/net/session.rb: Socket#flush_rbuf * lib/net/session.rb: doquote -> Net.quote Fri Dec 17 19:27:43 1999 IWAMURO Motonori * eval.c (rb_load): should initialize ruby_frame->last_class. Wed Dec 15 01:35:29 1999 Yukihiro Matsumoto * ruby.c (proc_options): option to change directory changed to `-C' like tar. * ruby.c (proc_options): argv boundary check for `-X'. Mon Dec 13 15:15:31 1999 Yukihiro Matsumoto * regex.c (re_adjust_startpos): separate startpos adjustment because of major performance drawback. * class.c (rb_singleton_class): tainted status of the singleton class must be synchronized with the object. * eval.c (rb_thread_schedule): implement thread priority. Sat Dec 11 03:34:38 1999 Yukihiro Matsumoto * gc.c (mark_hashentry): key should be VALUE, not ID. * io.c (argf_eof): should check next_p too. Thu Dec 9 18:09:13 1999 EGUCHI Osamu * error.c (exc_set_backtrace): forgot to declare a VALUE argument. Thu Dec 9 14:19:31 1999 Yukihiro Matsumoto * object.c (rb_obj_taint): explicit tainting must be prohibited at level 4 to prevent polluting trusted object by untrusted code. * file.c: file operations (stat, lstat, chmod, chown, umask, truncate, flock) are prohibited in level 2 (was level 4). Wed Dec 8 11:48:23 1999 Yukihiro Matsumoto * eval.c (rb_f_require): prohibiting require() in the secure mode cause serious autoloading error. * variable.c (rb_obj_instance_variables): don't need to prohibit to get list of instance variable names of untainted objects. * variable.c (rb_ivar_get): don't need to prohibit to get instance variables of untainted objects. * variable.c (rb_mod_remove_const): should prohibit constant removals too. Wed Dec 8 09:23:01 1999 Yukihiro Matsumoto * eval.c (rb_eval): should try autoloading before defining class/module at the toplevel. Tue Dec 7 22:15:30 1999 EGUCHI Osamu * configure.in: Modified rb_cv_rshift_sign detect routine and more simple/fast RSHIFT() for hpux-10.x. Tue Dec 7 11:16:30 1999 Yukihiro Matsumoto * eval.c (Init_eval): calculate stack limit from rlimit where getrlimit(2) is available. Tue Dec 7 09:57:33 1999 Katsuyuki Komatsu * file.c (rb_file_ftype): should have removed mode_t. Mon Dec 6 15:55:30 1999 EGUCHI Osamu * numeric.c (fix_rshift): Fix -1 >> 32 returned 0 (should be -1). * numeric.c (fix_rshift): Fix 1 >> -1 returned 0 (should be 2). Mon Dec 6 11:47:23 1999 Yukihiro Matsumoto * sprintf.c (rb_f_sprintf): formatted string must be tainted if any of parameters is a tainted string. * file.c (rb_file_s_expand_path): expanded file path need not to be tainted always. Sun Dec 5 20:25:29 1999 Katsuhiro Ueno * eval.c (Init_Proc): simple typo. * gc.c (add_heap): sizeof(RVALUE*), not sizeof(RVALUE). Sat Dec 4 01:40:22 1999 Yukihiro Matsumoto * regex.c (re_search): adjust startpos for multibyte match unless the first pattern is forced byte match. * bignum.c (rb_big_rand): should not use rand/random where drand48 may be available. RANDOM_NUMBER should be provided from outside. Fri Dec 3 09:54:59 1999 Yukihiro Matsumoto * ruby.c (moreswitches): there may be trailing garbage at #! line. * eval.c (rb_f_require): should check require 'feature.o' too. Thu Dec 2 11:58:15 1999 Koji Arai * eval.c (rb_thread_loading): should maintain loading_tbl. Thu Dec 2 10:21:43 1999 Yukihiro Matsumoto * eval.c (rb_thread_loading_done): wrong parameter to st_delete(). Wed Dec 1 11:24:06 1999 Nobuyoshi Nakada * ruby.c (process_sflag): process -s properly (should not force `--'). Wed Dec 1 09:47:33 1999 Kazunori NISHI * string.c (rb_str_split_method): should increment end too. Tue Nov 30 18:00:45 1999 Yukihiro Matsumoto * marshal.c: MARSHAL_MINOR incremented; format version is 4.2. * marshal.c (w_object): distinguish class and module. * marshal.c (w_object): save hash's default value. * marshal.c (r_object): restore hash's default value. Tue Nov 30 01:46:18 1999 Yukihiro Matsumoto * re.c (rb_reg_source): generated source string must be tainted if regex is tainted. * file.c (rb_file_s_basename): basename should not be tainted unless the original path is tainted. * file.c (rb_file_s_dirname): ditto. Mon Nov 29 20:42:13 1999 Nobuyoshi Nakada * file.c (stat_new): Struct::Stat -> File::Stat; Stat is no longer a Struct. Mon Nov 29 15:28:52 1999 Yukihiro Matsumoto * variable.c (rb_path2class): evaluated value from path should be module or class. Fri Nov 26 18:12:49 1999 Yukihiro Matsumoto * eval.c (rb_exec_end_proc): should remove only end_procs defined within load wrapper. * eval.c (rb_load): save and restore ruby_wrapper around loading. * eval.c (rb_mark_end_proc): mark end procs registered by END{} or at_exit{}. * eval.c (rb_set_end_proc): should not call rb_global_variable() on heap address; it crashed mod_ruby. Mon Nov 22 14:07:24 1999 Koji Arai * ruby.c (proc_options): variable e_script should be visited by garbage collector. Sat Nov 20 10:10:41 1999 Yukihiro Matsumoto * hash.c (inspect_i): value may be nil, check revised. Fri Nov 19 18:06:21 1999 Yukihiro Matsumoto * dir.c (glob): recursive wildcard match by `**' ala zsh. Fri Nov 19 11:44:26 1999 EGUCHI Osamu * variable.c: was returning void value. Fri Nov 19 03:57:22 1999 Nobuyoshi Nakada * file.c: add methods Stat struct class to reduce stat(2). Thu Nov 18 16:18:27 1999 Yukihiro Matsumoto * lib/pstore.rb: mutual lock by flock(2). Thu Nov 18 11:44:13 1999 Masahiro Tomita * io.c (read_all): should check bytes too. Wed Nov 17 02:40:40 1999 Yukihiro Matsumoto * io.c (Init_IO): $defout (alias of $>) added. Tue Nov 16 09:47:14 1999 Yukihiro Matsumoto * lib/pstore.rb: add mutual lock using symlink. Mon Nov 15 16:50:34 1999 Yukihiro Matsumoto * enum.c (enum_grep): non matching grep returns an empty array, no longer returns nil. * enum.c (enum_grep): grep with block returns collection of evaluated values of block over matched elements. Mon Nov 15 04:50:33 1999 Koji Arai * re.c (rb_reg_source): should not call rb_reg_expr_str() everytime. Sat Nov 13 07:34:18 1999 Yukihiro Matsumoto * variable.c (rb_mod_constants): traverse superclasses to collect constants. * eval.c (assign): modified for shared variables. * eval.c (rb_eval): search nested scope, then superclasses to assign shared variables within methods. * eval.c (rb_eval): remove warnings from constants modification, because they are no longer constants. * parse.y (node_assign): modified for shared variables. * parse.y (assignable): allow constant assignment in methods; constants should be called `shared variable'. Fri Nov 12 23:52:19 1999 Katsuyuki Komatsu * process.c (rb_f_system): argument check for NT, __EMX__, DJGPP. Wed Nov 10 21:54:11 1999 EGUCHI Osamu * hash.c (rb_any_cmp): Fixed return without value. Wed Nov 10 17:57:06 1999 Yukihiro Matsumoto * sprintf.c: incorporate 's sprintf patch at [ruby-dev:7754]. Wed Nov 10 08:28:53 1999 Yukihiro Matsumoto * eval.c (rb_call0): supply class parameter for each invocation. Tue Nov 9 13:21:04 1999 EGUCHI Osamu * configure.in: AC_MINIX move to before AC_EXEEXT and AC_OBJEXT. Mon Nov 8 19:52:29 1999 EGUCHI Osamu * configure.in: Renamed AC_CHAR_UNSIGNED to AC_C_CHAR_UNSIGNED. * configure.in: Added default to AC_CHECK_SIZEOF(). Mon Nov 8 14:28:18 1999 Yukihiro Matsumoto * parse.y (stmt): rescue modifier added to the syntax. * keywords: kRESCUE_MOD added. * eval.c (rb_f_eval): fake outer scope when eval() called without bindings. * eval.c (rb_f_binding): should copy last_class in the outer frame too. Sun Nov 7 18:31:04 1999 Yasuhiro Fukuma * eval.c (is_defined): last_class may be 0. Sat Nov 6 19:26:55 1999 EGUCHI Osamu * Makefile.in: Added depend entry make parse.@OBJEXT@ from parse.c for UCB make Thu Nov 4 17:41:18 1999 Yukihiro Matsumoto * regex.c (re_compile_pattern): \< (wordbeg), \> (wordend) disabled. Wed Nov 3 08:52:57 1999 Masaki Fukushima * io.c (Init_IO): forgot to use INT2FIX() around SEEK_SET, etc. Wed Nov 3 00:25:20 1999 Yukihiro Matsumoto * string.c (rb_str_split_method): use mbclen2() to handle kcode option of regexp objects. Mon Nov 1 14:22:15 1999 EGUCHI Osamu * eval.c (rb_eval): reduce recursive calls to rb_eval() case of ||= and &&= . Sun Oct 31 13:12:42 1999 WATANABE Hirofumi * regex.c (re_compile_pattern): wrong [\W] match. Fri Oct 29 16:57:30 1999 Yukihiro Matsumoto * ext/nkf/lib/kconv.rb: new String methods (kconv, tojis, toeuc, tosjis). * time.c (time_s_at): now accepts optional second argument to specify micro second. Thu Oct 28 13:35:40 1999 Yukihiro Matsumoto * string.c (rb_str_split_method): should be mbchar aware with single char separators. Wed Oct 27 12:57:21 1999 Yukihiro Matsumoto * random.c (rb_f_srand): random seed should be unsigned. Tue Oct 26 23:58:15 1999 Yukihiro Matsumoto * array.c (rb_ary_collect): collect for better performance. Tue Oct 26 19:20:54 1999 Koji Arai * marshal.c (r_object): should register class/module objects. Sat Oct 23 15:59:39 1999 Takaaki Tateishi * process.c (rb_f_system): should require at least one argument. Sat Oct 23 12:42:44 1999 Nobuyoshi Nakada * enum.c (enum_collect): collect without block will collect elements in enumerable. Thu Oct 21 16:14:19 1999 Yukihiro Matsumoto * ruby.c (moreswitches): function to process string option; the name is stolen from perl (not implementation). * ruby.c (proc_options): use RUBYOPT environment variable to retrieve the default options. * dir.c (fnmatch): use eban's fnmatch; do not depend on system's fnmatch (which may have portability problem) anymore. Wed Oct 20 15:14:24 1999 Yukihiro Matsumoto * marshal.c (marshal_load): should protect the generated object table (arg->data) from GC. Mon Oct 18 16:15:52 1999 Yukihiro Matsumoto * ext/nkf/nkf.c (rb_nkf_kconv): output should be NUL terminated. Mon Oct 18 09:03:01 1999 Minero Aoki * lib/net/session.rb, smtp.rb, pop.rb: 1.0.3 * lib/net/pop.rb: new methods POP3Command#uidl, POPMail#uidl. Sun Oct 17 03:35:33 1999 Masaki Fukushima * array.c (rb_ary_pop): forgot some freeze checks. Sat Oct 16 12:57:53 1999 EGUCHI Osamu * array.c (rb_ary_sort): always returns the copied array. Fri Oct 15 22:50:41 1999 WATANABE Hirofumi * error.c (sys_nerr): on CYGWIN, it is _sys_nerr. Fri Oct 15 01:32:31 1999 WATANABE Hirofumi * io.c (rb_io_ctl) :need to use NUM2ULONG, not NUM2INT. * ext/Win32API/Win32API.c (Win32API_Call): need to use NUM2ULONG, not NUM2INT. Fri Oct 15 00:22:30 1999 Yukihiro Matsumoto * re.c (Init_Regexp): super class of the MatchingData, which was Data, to be Object. * eval.c (ruby_run): evaluate required libraries before load & compiling the script. * parse.y (lex_getline): retrieve a line from the stream, saving lines in the table in debug mode. * eval.c (call_trace_func): treat the case ruby_sourcefile is null. Thu Oct 14 02:00:10 1999 Yukihiro Matsumoto * parse.y (string): compile time string concatenation. Wed Oct 13 07:28:09 1999 Minero Aoki * lib/net/session.rb, smtp.rb, pop.rb: 1.0.2 * lib/net/session.rb: new method Session#set_pipe. * lib/net/session.rb, smtp.rb, pop.rb: add RD documentation. Wed Oct 13 02:17:05 1999 EGUCHI Osamu * array.c (rb_ary_plus): remove recursion. * array.c (rb_ary_sort_bang): detect modify attempt. Wed Oct 13 02:17:05 1999 Yukihiro Matsumoto * eval.c (block_pass): should copy block to prevent modifications. tag in the structure should be updated from latest prot_tag. * eval.c (proc_s_new): tag in struct BLOCK should not point into unused stack. * dir.c (dir_s_glob): iterate over generated matching filenames if the block is given to the method. * array.c (rb_ary_at): new methods; at, first, last. * hash.c (rb_hash_fetch): raises exception unless the default value is supplied. * hash.c (rb_hash_s_create): need not remove nil from value. * hash.c (rb_hash_aset): setting value to nil does not remove key anymore. Tue Oct 12 22:29:04 1999 Yukihiro Matsumoto * io.c (io_read): length may be 0 or negative. Tue Oct 12 13:26:27 1999 Jun-ichiro itojun Hagino * signal.c (posix_signal): RETSIGTYPE may be void. Tue Oct 12 03:28:03 1999 EGUCHI Osamu * array.c (rb_ary_delete_at): allows negative position. Mon Oct 11 17:42:25 1999 Nobuyoshi Nakada * parse.y (rb_intern): should generate distinct ID_ATTRSET symbols for the name with multiple `='s at the end. * Makefile.in (CPPFLAGS): separate cpp flags from CFLAGS. Mon Oct 11 07:27:05 1999 Yukihiro Matsumoto * eval.c (rb_eval): should not execute the `else' clause on the case the exceptions are handled by the `rescue' clause. * signal.c (Init_signal): ignore SIGPIPE by default. Wed Oct 6 17:13:19 1999 Nobuyoshi Nakada * ruby.c (addpath): rubylib_mangled_path() modified. Mon Oct 4 12:42:32 1999 Kazuhiko Izawa * pack.c (pack_unpack): % in printf format should be %%. Mon Oct 4 10:01:40 1999 Yukihiro Matsumoto * variable.c (rb_obj_instance_variables): should always return array for all object can have instance variables now. Mon Oct 4 00:08:34 1999 Yukihiro Matsumoto * pack.c (OFF16): need to adjust pointer address to pack/unpack on 64bit machines. Sun Oct 3 03:05:59 1999 WATANABE Hirofumi * time.c (time_arg): mktime y2k problem. Sun Sep 26 16:54:45 1999 WATANABE Hirofumi * parse.y (here_document): `\r' handling for here documents. Wed Sep 22 09:20:11 1999 Masahiro Tomita * ext/socket/socket.c: SOCKS5 support. Wed Sep 22 07:33:23 1999 Minero Aoki * lib/net/session.rb, smtp.rb, pop.rb: 1.0.1 * lib/net/pop.rb: APOP did not work. * lib/net/pop.rb: modify the way to make APOP challenge. Wed Sep 22 00:35:30 1999 Yukihiro Matsumoto * string.c (rb_str_include): should return boolean value. * regex.c (re_compile_fastmap): wrong comparison with mbc. * eval.c (specific_eval): default sourcefile name should be "(eval)" for module_eval etc. Wed Sep 22 00:06:07 1999 Katsuyuki Komatsu * win32/Makefile: update rules. * io.c (io_fread): should not assign in char, it maybe -1. Tue Sep 21 23:57:54 1999 Yukihiro Matsumoto * eval.c (call_trace_func): should not propagate retval in trace_func. Mon Sep 20 21:35:39 1999 Katsuyuki Komatsu * win32/win32.c (myselect): assume non socket files are always readable/writable. Mon Sep 20 01:08:02 1999 Yukihiro Matsumoto * io.c (io_fread): should not block other threads. * io.c (rb_io_synchronized): renamed from rb_io_unbuffered(); do not call setbuf(NULL) anymore. Sat Sep 18 13:45:43 1999 Yukihiro Matsumoto * stable version 1.4.2 released. Fri Sep 17 23:24:17 1999 Katsuyuki Komatsu * eval.c (rb_f_missing): dumped core if no argument given. Fri Sep 17 23:21:06 1999 Katsuyuki Komatsu * win32/win32.c (myselect): translate WSAEINTR, WSAENOTSOCK into UNIX errno constants. Fri Sep 17 00:52:27 1999 Yukihiro Matsumoto * parse.y (arg): assignable() may return 0. Thu Sep 16 20:46:23 1999 WATANABE Hirofumi * eval.c (rb_eval): was doubly evaluating the return expression. Thu Sep 16 18:40:08 1999 Yukihiro Matsumoto * stable version 1.4.1 released. Thu Sep 16 11:33:22 1999 WATANABE Hirofumi * string.c (rb_str_match): should return nil. Wed Sep 15 22:46:37 1999 Yukihiro Matsumoto * re.c (rb_reg_s_quote): should quote `-' too. Tue Sep 14 15:23:22 1999 Nobuyoshi Nakada * parse.y (yylex): no need to ignore `\r' here. * parse.y (nextc): strip `\r' from text. * parse.y (nextc): support `__END__\r\n' type terminator. Mon Sep 13 10:49:19 1999 WATANABE Hirofumi * eval.c (rb_eval): needless RTEST(ruby_verbose) removed. Mon Sep 13 09:10:11 1999 Minero Aoki * lib/net/session.rb, smtp.rb, pop.rb: 1.0.0 Wed Sep 8 11:37:38 1999 Tadayoshi Funaba * time.c (make_time_t): bit more strict comparison. Tue Sep 7 00:50:56 1999 Yukihiro Matsumoto * range.c (range_each): use rb_str_upto() for strings. * string.c (rb_str_upto): set upper limit by comparing curr <= end. * range.c (range_each): should check equality to handle magic increment. Mon Sep 6 22:43:33 1999 Yukihiro Matsumoto * eval.c (rb_eval): break/next/redo available within -n/-p loop. Fri Sep 3 11:14:31 1999 Yukihiro Matsumoto * compar.c (cmp_equal): should not raise exception; protect by rb_rescue(). Thu Sep 2 05:23:05 1999 WATANABE Hirofumi * file.c (rb_file_s_expand_path): use dirsep, instead of character literal '/'. * file.c (rb_file_s_expand_path): reduce multiple dirsep at the top. Wed Sep 1 00:28:27 1999 Yukihiro Matsumoto * eval.c (rb_call): call rb_undefined() if a method appears not to be exist explicitly from cache. * eval.c (rb_method_boundp): check method cache before calling rb_get_method_body(). * eval.c (rb_get_method_body): store method non-existence information in the cache. * random.c (rb_f_srand): use getpid(2) to generate seed. * regex.c (re_match): do not apply partial mbc match for charset_not. * regex.c (re_compile_pattern): put extended literal prefix (0xff) only before numeric literals, not before all >0x80 char. * regex.c (re_compile_pattern): put numeric literal in extended charset region, not normal charset bits. * regex.c (re_compile_fastmap): calculate fastmap for charset and charset_not to treat numeric literal (e.g. \246) specially. Fri Aug 28 17:32:55 1999 Yasuhiro Fukuma * eval.c (rb_eval): should set return value (nil) explicitly if a value is omitted for return statement. Sun Aug 26 20:26:40 2001 Koji Arai * ext/readline/readline.c: restore terminal mode even if readline() interrupted. * ext/readline/readline.c: returned string need to be tainted. * ext/readline/readline.c: fixed memory leak. * ext/readline/readline.c: allow negative index. * ext/readline/readline.c: added Readline::HISTORY.size same as Readline::HISTORY.length * ext/readline/readline.c: allow conditional parsing of the ~/.inputrc file by `$if Ruby'. * ext/readline/extconf.rb: check whether the libreadline has the variable `rl_completion_append_character' (this feature was implemented from GNU readline 2.1). Thu Aug 26 15:06:11 1999 Masaki Fukushima * gc.c (rb_gc): local variables may be placed beyond stack_end, so use an address from alloca(1) on non C_ALLOCA platforms. Thu Aug 26 01:24:17 1999 Yukihiro Matsumoto * sprintf.c (rb_f_sprintf): "%%" is legal, but "%3.14%" is not. Mon Aug 23 00:00:54 1999 Tsukada Takuya * regex.c (re_compile_fastmap): wrong macro caused memory leak. Sat Aug 21 11:30:51 1999 Yukihiro Matsumoto * eval.c (ADJ): should not adjust addresses to data on heap. Fri Aug 20 20:50:58 1999 Kenji Nagasawa * defines.h (PATH_SEP): path separator is ";" for OS/2. Thu Aug 19 10:50:43 1999 WATANABE Tetsuya * gc.c (rb_gc): add volatile to avoid GCC optimize bug(?). Wed Aug 18 23:48:10 1999 Yukihiro Matsumoto * due to disk trouble, some change records were lost. several modification made to eval.c, gc.c, io.c, pack.c, ext/extmk.rb.in, and lib/mkmf.rb. Fri Aug 13 15:41:39 1999 Yukihiro Matsumoto * stable version 1.4.0 released. Fri Aug 13 03:16:07 1999 Yukihiro Matsumoto * io.c (argf_forward): since $stdout may be non-IO, ARGF.file is not guaranteed to be IO. check and forwarding added to every ARGF method. * io.c (set_outfile): $stdout/$stderr may not be IO now. * io.c (set_stdin): $stdin may not be IO now. * range.c (rb_range_beg_len): round `end' to length as documented. * io.c (Init_IO): preserve original stdin/stdout/stderr. Thu Aug 12 13:44:33 1999 Yukihiro Matsumoto * eval.c (Init_load): require receives 1 argument. * eval.c (frame_dup): should clear tmp to avoid dangling references. Wed Aug 11 13:33:13 1999 Katsuyuki Komatsu * eval.c (rb_eval): no automatic aggregate initialization. * eval.c (module_setup): ditto. Wed Aug 11 18:18:41 1999 WATANABE Tetsuya * eval.c (yield_under_i): automatic aggregate initialization is an ANSI feature. Wed Aug 11 10:10:02 1999 Yukihiro Matsumoto * parse.y (yylex): parse `[].length==0' as `([].length)==0', not `([].length=)=0' * parse.y (yylex): parse `[].length!=0' as `([].length)!=0', not `([].length!)=0' * parse.y (peek): peek-in lexical buffer. Wed Aug 11 00:34:05 1999 Yukihiro Matsumoto * regex.c (re_match): bug on backward jump adjustment concerning stop_paren. Tue Aug 10 14:54:25 1999 Yukihiro Matsumoto * ext/nkf/nkf.c (rb_nkf_guess): binary detection was wrong. Tue Aug 10 00:07:36 1999 Yukihiro Matsumoto * io.c (rb_io_clone): should use CLONESETUP(). Mon Aug 9 23:57:07 1999 Yukihiro Matsumoto * ruby.h (CLONESETUP): should have copied generic instance variables too. Mon Aug 9 10:46:54 1999 Katsuyuki Komatsu * ext/socket/extconf.rb: add check for and . Sat Aug 7 13:19:06 1999 EGUCHI Osamu * numeric.c (flo_cmp): comparing NaN should not return value. raises FloatDomainError. Sat Aug 7 03:09:08 1999 Yukihiro Matsumoto * eval.c (blk_free): free copied frames too. * eval.c (frame_dup): should copy previous frames from stack to heap to preserve frame information. Fri Aug 6 15:01:07 1999 Yukihiro Matsumoto * version 1.3.7 - version 1.4 beta * ext/socket/socket.c (s_recv): UDPsocket#recvfrom now returns IPsocket#addr information. * array.c (rb_ary_subary): ary[-3,3] should not return nil. Thu Aug 5 10:58:01 1999 Yukihiro Matsumoto * eval.c (thread_mark): protect old ruby_frame from GC during it replaced by eval(). * eval.c (eval): do not modify frame.prev; binding should preserve information about calling() too. * eval.c (rb_yield_0): no arity check for mere yield; but only for Proc#call. Tue Aug 3 22:07:13 1999 Kazuhiro HIWADA * object.c (rb_mod_clone): should check if iv_tbl, m_tbl are initialized. Tue Aug 3 19:03:02 1999 Yukihiro Matsumoto * hash.c (rb_any_cmp): use rb_with_disable_interrupt() to ensure clearance of rb_prohibit_interrupt even on failure. * eval.c (rb_with_disable_interrupt): new function added. Sat Jul 31 23:23:44 1999 Yukihiro Matsumoto * eval.c (rb_thread_create_0): set THREAD_RAISED flag on thread termination by exception. * eval.c (rb_thread_join): `$!' may not be nil for the threads created in rescue clause. * eval.c (rb_thread_status): ditto. * eval.c (rb_thread_join): should re-raise exception for already dead threads too. Fri Jul 30 17:56:54 1999 GOTO Kentaro * object.c (rb_mod_ge): wrong comparison. Fri Jul 30 12:15:44 1999 Katsuyuki Komatsu * ext/tcltklib/extconf.rb: win32 support. * lib/mkmf.rb: use append_library(). * ext/extmk.rb.in: ditto. Fri Jul 30 02:11:48 1999 Yukihiro Matsumoto * array.c (rb_ary_delete): should return nil for deleting non existing item. * io.c (rb_io_close): call rb_sys_wait() on explicit close. * io.c (rb_io_fptr_close): do not call rb_sys_wait() on finalize. * eval.c (yield_under_i): cbase context should be maintained for Module#module_eval(). suggested by . Wed Jul 28 01:18:28 1999 WATANABE Hirofumi * Makefile.in: add -I$(hdrdir)/lib to install using ftools. * util.c: use HAVE_FCNTL_H, not HAVE_FCNTL Wed Jul 28 18:24:45 1999 Yukihiro Matsumoto * version 1.3.6 - version 1.4 alpha Tue Jul 27 09:38:08 1999 EGUCHI Osamu * eval.c (rb_eval): reduce recursive rb_eval() calls by NODE_BLOCKs. Tue Jul 27 01:20:40 1999 WATANABE Hirofumi * file.c (rb_file_s_expand_path): drive letter patch. Mon Jul 26 02:36:31 1999 Shugo Maeda * eval.c (rb_load): should clear ruby_nerr. * eval.c (rb_thread_join): oldbt should not be empty to unshift. Sun Jul 25 12:09:16 1999 Koji Arai * dir.c (push_braces): should treat nested braces. Fri Jul 23 02:49:49 1999 Yukihiro Matsumoto * hash.c (rb_hash_clear): dummy argument added; suggested by . thanks. Thu Jul 22 19:37:22 1999 Yukihiro Matsumoto * eval.c (rb_thread_join): get_backtrace() may return Qnil. typecheck added. Tue Jul 20 14:36:43 1999 WATANABE Hirofumi * range.c (range_each): do not treat String specially (for future override). Tue Jul 20 02:28:34 1999 Yukihiro Matsumoto * io.c (rb_gets): $_ should be nil, when get returns nil. * io.c (rb_f_gets): ditto. Mon Jul 19 17:13:09 1999 Yukihiro Matsumoto * regex.c (re_compile_fastmap): should continue fastmap compile for anychar_repeat, for it's repeat anyway. Mon Jul 26 13:33:45 1999 WATANABE Hirofumi * lib/jcode.rb: replaced by faster code. Mon Jul 19 01:57:28 1999 Yukihiro Matsumoto * lib/mkmf.rb: no longer use install program. * ext/extmk.rb.in: use miniruby to install programs. Sat Jul 17 00:06:21 1999 Yukihiro Matsumoto * ext/socket/socket.c (ipaddr): don't do reverse lookup if attribute do_not_reverse_lookup is set for socket classes. Experimental. Note this is a global attribute. Fri Jul 16 22:18:29 1999 Yukihiro Matsumoto * io.c (rb_io_eof): use feof() to check EOF already met. * io.c (read_all): should return nil at EOF. Fri Jul 16 13:39:42 1999 Wakou Aoyama * lib/telnet.rb: version 0.231. Fri Jul 16 10:58:22 1999 WATANABE Tetsuya * regex.c (re_match): debug print removed. Fri Jul 16 09:58:15 1999 Katsuyuki Komatsu * many files: clean up unused variables found by gcc -Wall. * lib/mkmf.rb: better cygwin support etc. * ext/extmk.rb.in: ditto. * instruby.rb: ditto. Fri Jul 16 01:37:50 1999 Koji Arai * string.c (rb_str_squeeze_bang): the type of local variable `c' should be int, not char. * string.c (rb_str_reverse): should always return copy. Thu Jul 15 23:25:57 1999 NAKAMURA, Hiroshi * lib/debug.rb: better display & frame treatment. Thu Jul 15 21:16:41 1999 Yukihiro Matsumoto * array.c (rb_ary_each): returns self for normal termination; returns nil for break. * string.c: non bang methods (e.g. String#sub) should always return copy of the receiver. Thu Jul 15 21:09:15 1999 Masaki Fukushima * eval.c (find_file): do not add empty string to the path. * configure.in (with-search-path): should not add empty string if the option is not supplied. Thu Jul 15 17:49:08 1999 Ryo HAYASAKA * ext/tcltklib/tcltklib.c: move `#include "ruby.h"' forward. Thu Jul 15 16:54:16 1999 Yukihiro Matsumoto * version 1.3.5 - version 1.4 alpha Wed Jul 14 23:45:33 1999 Katsuyuki Komatsu * eval.c (ruby_init): initialize for the first time only. Tue Jul 13 00:15:19 1999 Yukihiro Matsumoto * hash.c (rb_hash_index): re-defined; method to retrieve a key from the value. * hash.c (Init_Hash): member? should be re-defined for Hash. Tue Jul 12 13:54:51 1999 EGUCHI Osamu * io.c (rb_file_sysopen): wrong number of argument. Mon Jul 12 11:52:35 1999 Yukihiro Matsumoto * eval.c (rb_f_missing): class name included in message. * eval.c (print_undef): better error message. Sun Jul 11 05:36:17 1999 NAKAMURA, Hiroshi * lib/debug.rb: patch to show proper position. Fri Jul 9 23:56:14 1999 WATANABE Hirofumi * dln.c (dln_find_1): path conv. moved to conv_to_posix_path. * dln.c (conv_to_posix_path): path conv. should be done. Fri Jul 9 10:26:47 1999 WATANABE Hirofumi * random.c (RANDOM_NUMBER): should place parentheses. Fri Jul 8 11:00:51 1999 Shugo Maeda * numeric.c (fix_div): division may be out of fixnum range. * bignum.c (bigdivmod): proper sign calculation to result. Wed Jul 7 18:27:41 1999 Yukihiro Matsumoto * st.c (st_delete_safe): was modifying wrong slot. Mon Jul 5 13:17:46 1999 Yukihiro Matsumoto * gc.c (rb_gc_call_finalizer_at_exit): close all files at exit. Fri Jul 2 18:00:21 1999 Minero Aoki * lib/Mail/README: Mail-0.3.0 added to the distribution. Fri Jul 2 01:45:32 1999 Yukihiro Matsumoto * regex.c (re_compile_fastmap): avoid allocation of register variables for each invocation of re_match(). Suggested by Zasukhin Ruslan . Thanks. Tue Jun 29 20:39:24 1999 Koji Arai * ext/tk/lib/tk.rb (TkVariable): bug fix; should value type check be added? * string.c (rb_str_each_line): a bug in paragraph mode. * ruby.c (load_file): shifted too much to skip #!. Tue Jun 29 06:50:21 1999 Wakou Aoyama * lib/CGI.rb: 0.30 - cleanup release, incompatible. * lib/telnet.rb: 0.22 - timeout added. Tue Jun 29 10:49:25 1999 SHIROYAMA Takayuki * configure.in: better Rhapsody support. * lib/mkmf.rb: Rhapsody/NEXTSTEP support. Tue Jun 29 01:42:13 1999 Yukihiro Matsumoto * ext/pty/pty.c (chld_changed): should use POSIX.1 style wait. Mon Jun 28 21:07:36 1999 KIMURA Koichi * ext/extmk.rb.nt: wrong result for have_library(). Mon Jun 28 15:24:05 1999 Yukihiro Matsumoto * missing/isinf.c: OSF/1 raises SIGFPE on one()/zero(). * regex.c (re_search): should search til EOS, for patterns may match beyond the end of range. Mon Jun 28 12:49:12 1999 Yukihiro Matsumoto * io.c (rb_f_select): should not accept Time objects as an argument for it is time interval. * process.c (rb_f_sleep): ditto. * file.c (test_s): should return nil for false condition. Mon Jun 28 12:23:52 1999 Katsuyuki Komatsu * bignum.c (rb_dbl2big): typo. * file.c (rb_f_test): ditto. * string.c (rb_str_crypt): wrong message. Sun Jun 27 19:50:11 1999 Tadayoshi Funaba * eval.c (rb_f_exit): should have treat signed integer status, not VALUE. * process.c (rb_f_exit_bang): should work like exit(). Sun Jun 27 16:21:32 1999 WATANABE Hirofumi * string.c (rb_str_rindex): wrong position to search. Sat Jun 26 04:05:30 1999 Takaaki Tateishi * configure.in (configure_args): --with-search-path to specify additional ruby search path. * ruby.c (ruby_prog_init): additional search path. Fri Jun 25 13:09:12 1999 Yukihiro Matsumoto * pack.c (pack_unpack): needed to initialize natint. * regex.c (re_compile_pattern): add start_paren to avoid too much finalization on maybe_finalize_jump. Fri Jun 25 13:07:20 1999 Koji Oda * missing/isinf.c: include "config.h" added. Fri Jun 25 07:25:05 1999 Katsuyuki Komatsu * lib/mkmf.rb: initialize $(topdir). * ext/extmk.rb.in (install_rb): install lib/*.rb properly. * configure.in (linux): specifies -rpath on --enable-shared. * configure.in (aix): ruby.imp must reside in $(topdir). Thu Jun 24 19:11:29 1999 Yoshida Masato * parse.y (rb_str_extend): multi-byte identifier in expression interpolation in strings. * parse.y (yylex): support multi-byte char identifiers. Thu Jun 24 15:27:13 1999 Yukihiro Matsumoto * parse.y (f_arg): check duplicate argument names. * gc.c (rb_gc_mark): marking wrong member for NODE_ARGS. * string.c (rb_str_rindex): POSITION specifies start point, not end point. Thu Jun 24 13:00:17 1999 Yukihiro Matsumoto * regex.c (print_mbc): wrong boundary. * pack.c (uv_to_utf8): raises ArgError for too big value. Thu Jun 24 11:02:51 1999 Yoshida Masato * pack.c (uv_to_utf8): mask needed. Wed Jun 23 21:03:56 1999 Tadayoshi Funaba * ruby.h (struct RFile): remove iv_tbl from struct. instance variables are handled as generic ivs. Wed Jun 23 22:06:26 1999 Tadayoshi Funaba * pack.c (utf8_to_uv): pack to 7 bytes sequence. * pack.c (uv_to_utf8): wrong boundary. * pack.c (pack_unpack): should treat as unsigned long. Wed Jun 23 15:10:11 1999 Inaba Hiroto * parse.y (parse_string): failed to parse nested braces. * parse.y (parse_regx): nested braces within #{} available. Wed Jun 23 11:18:38 1999 Yukihiro Matsumoto * regex.c (slow_search): wrong shift width for mbcs. * eval.c (rb_thread_save_context): should not clear th->locals. Wed Jun 23 02:06:14 1999 Yukihiro Matsumoto * parse.y (yylex): UMINUS binds too tight with digits. changed so that -2**2 => -4. * parse.y (close_paren): `do' for expr termination now works it used to be. Wed Jun 22 18:26:42 1999 Koji Arai * pack.c (pack_pack): should initialize local variable `j'. Wed Jun 22 15:24:59 1999 Koji Arai * parse.y (here_document): a bug for multiline heredoc. Tue Jun 22 15:06:36 1999 WATANABE Hirofumi * ext/socket/socket.c (ruby_socket): forgot to return fd explicitly. Tue Jun 22 13:34:12 1999 Yukihiro Matsumoto * rubyio.h (MakeOpenFile): should initialize member `iv_tbl'. Wed Jun 22 10:35:51 1999 Katsuyuki Komatsu * io.c (rb_io_gets_internal): getc(3) may not set errno on interrupt. Mon Jun 21 22:39:28 1999 Yukihiro Matsumoto * eval.c (call_required_libraries): ruby_sourceline should be cleared before loading libraries. * io.c (set_stdin): do not use reopen(), so that we don't need to dup original stdin before assigning $stdin. Mon Jun 21 18:04:27 1999 Ryo HAYASAKA * ext/dbm/dbm.c: include for solaris 2.6. Mon Jun 21 15:59:47 1999 Nobuyoshi Nakada * ext/socket/socket.c (ip_addrsetup): forgot to put `else'. Mon Jun 21 15:38:37 1999 Yukihiro Matsumoto * io.c (fptr_finalize): remove rb_syswait() invocation to avoid wait4(2) within GC. rb_syswait() moved to rb_io_fptr_close(). Mon Jun 21 12:05:59 1999 Tadayoshi Funaba * dir.c (dir_s_glob): remove MAXPATHLEN restriction. * ext/md5/md5init.c (md5_hexdigest): should have used "%02x". Sun Jun 20 19:50:38 1999 Minero Aoki * string.c (rb_str_each_line): should have checked string boundary. Sat Jun 19 22:24:12 1999 Kenji Nagasawa * OS/2 patch improved. Fri Jun 18 08:30:17 1999 Yukihiro Matsumoto * marshal.c (r_byte): add data length check. * ext/tcltklib/tcltklib.c (_timer_for_tcl): was doing busy-wait. Tue Jun 15 10:01:21 1999 Katsuyuki Komatsu * configure.in: remove trailing slash from interpreter embedded shared library path. * configure.in (INSTALL_DLLIB): install shared lib with 0555. * instruby.rb: changed mode for shared library into 0555. Fri Jun 11 23:27:00 1999 Tadayoshi Funaba * ext/etc/etc.c (etc_passwd): should return nil, not exception for call after last passwd entry. Fri Jun 11 15:21:21 1999 Yukihiro Matsumoto * gc.c (rb_gc_mark_locations): add safety margin 1. * eval.c (ruby_run): should protect toplevel node tree. * ext/etc/etc.c (etc_group): dumps core if there's no more group. Fri Jun 11 01:50:25 1999 Yukihiro Matsumoto * eval.c (ruby_run): Init_stack() was called too late; local variables happened to be higher (or lower) than stack_start. Thu Jun 10 16:41:48 1999 Yukihiro Matsumoto * io.c: do not call `initialize' for IO objects. So with Array, Hash, Range, and Time objects. * ext/curses/curses.c (curses_getch): made thread aware using rb_read_check(). * ext/curses/curses.c (window_getch): ditto. * ext/curses/curses.c (curses_getstr): made (partially) thread aware using rb_read_check(). * ext/curses/curses.c (window_getstr): ditto. * io.c (rb_read_check): new function to help making something (like extension libraries) thread aware. * eval.c (is_defined): `defined? super' should be true even for private superclass methods. Fri Jun 10 13:42:10 1999 Koji Arai * pack.c (pack_pack): template `Z' should be allowed. Wed Jun 9 13:26:38 1999 Yukihiro Matsumoto * eval.c (rb_thread_loading): modified to avoid nested race condition of require(). * ext/tcltklib/tcltklib.c (ip_invoke): queue invocation on non main threads. * ext/tcltklib/tcltklib.c (lib_mainloop): flush invocation queues periodically. * version.c (ruby_show_version): now print the message to stdout. * version.c (ruby_show_copyright): ditto. Tue Jun 8 00:00:34 1999 Yukihiro Matsumoto * pack.c (pack_unpack): append sentinel (NUL) to the string. * ext/md5/md5init.c (md5_hexdigest): new method to obtain printable hash string. * ext/md5/md5init.c (md5_update): should return self. * pack.c (pack_pack): undocumented template 'U' for UTF8. * pack.c (pack_unpack): ditto. * marshal.c (r_byte): should replace getc() with rb_getc(). * io.c (rb_getc): getc() replacement uses READ_DATA_PENDING() and rb_thread_wait_fd(). Mon Jun 7 23:23:38 1999 Yukihiro Matsumoto * object.c (rb_mod_clone): should call CLOSESETUP(). * eval.c (bind_clone): should call CLONESETUP() for new clone. Sat Jun 5 10:32:40 1999 Yukihiro Matsumoto * string.c (rb_str_oct): binary (e.g. 0b10111) support. * variable.c (rb_const_set): raise warning, not exception. * parse.y (yycompile): initialize parser internal variables. * parse.y (close_paren): set lex_state to EXPR_PAREN after closing parenthesis. * parse.y (yylex): returns kDO for `do' right after method_call. Thu Jun 3 11:05:30 1999 WATANABE Hirofumi * regex.c (read_backslash): should decode \b within class. Thu Jun 3 01:06:18 1999 Katsuyuki Komatsu * dln.c (dln_load): AIX improvement (aix_findmain removed). Wed Jun 2 00:41:31 1999 Yukihiro Matsumoto * pack.c (pack_unpack): new undocumented template Z which strips stuff after first null. * pack.c (pack_pack): should preserve specified length of the resulting string. Tue Jun 1 15:29:33 1999 Yukihiro Matsumoto * ext/socket/socket.c (ruby_socket): retry after GC, if socket(2) failed on EMFILE or ENFILE. * ext/socket/socket.c (sock_s_socketpair): ditto. * eval.c (module_setup): need to add PUSH_VAR/POP_VAR to clear dyna vars link list. * version.h (RUBY_RELEASE_CODE): integer macro constant for source version detection. Sun May 30 22:19:12 1999 Kenji Nagasawa * ext/socket/socket.c: emx/gcc 0.9d now fixes things about AF_UNIX. * process.c: OS/2 EMX kludge. * Makefile.in (strncasecmp.o): added dependency. Mon May 31 16:06:28 1999 Yukihiro Matsumoto * version 1.3.4 - preliminary release for 1.4 Mon May 31 15:57:41 1999 Yukihiro Matsumoto * io.c (rb_io_fptr_close): close on IO which main_thread is waiting cause serious exception, that vanishes the actual fd closing. Invocation of rb_thread_fd_close() is deferred a little. Sat May 29 18:27:13 1999 Koji Arai * regex.c (re_match): stack boundary check needed. Sat May 29 12:27:00 1999 Yukihiro Matsumoto * ext/tcltklib/tcltklib.c (ip_invoke): proper ref count management to avoid leak. I HATE REF COUNTING!! * eval.c (ruby_run): moved ruby_require_libraries() to handle `-r' from ruby_options() to avoid stack corruption for threads created in libraries. Sat May 29 02:22:12 1999 Yukihiro Matsumoto * eval.c (rb_yield_0): when `for' appeared in blocks, it introduced new scope for local variables. Fri May 28 17:16:49 1999 Yukihiro Matsumoto * string.c (rb_str_squeeze_bang): squeeze AND of the arguments. UNDOCUMENTED. * string.c (rb_str_count): new UNDOCUMENTED method. * string.c (rb_str_delete_bang): delete AND of the arg ranges. UNDOCUMENTED FEATURE for 1.3.x. * ext/socket/socket.c (setipaddr): re-wrote using ip_addrsetup(). * ext/socket/socket.c (ip_addrsetup): decode symbolic address . Thu May 27 12:27:42 1999 Yukihiro Matsumoto * string.c (tr_trans): should handle NUL (\0) within strings. Tue May 25 16:45:11 1999 Yukihiro Matsumoto * io.c (rb_f_syscall): syscall may return values other than zero on success. * regex.c (re_match): handle empty loop properly (hopefully). * regex.c (re_match): remove empty group check, because it does not help non-grouping parentheses (?:..). * regex.c (re_compile_fastmap): treating try_next, finalize_push wrong way. * regex.c: remove some obsolete functions such as group_match_null_string_p(). Mon May 24 14:47:54 1999 Yukihiro Matsumoto * regex.c (read_backslash): read backslash by regex. Sun May 23 19:44:58 1999 WATANABE Hirofumi * ext/pty/pty.c (getDevice): portability patch. Fri May 21 23:01:26 1999 Katsuyuki Komatsu * ext/socket/getaddrinfo.c (GET_AI): should set error code. Thu May 20 03:43:44 1999 Jun-ichiro itojun Hagino * ext/socket/socket.c: you should use sockaddr_storage to handle IPv6 addresses. * ext/socket/getaddrinfo.c (getaddrinfo): prevent retrieving AF_INET6 address if hints.ai_flags == AI_PASSIVE. Wed May 19 12:27:07 1999 Yukihiro Matsumoto * eval.c (exec_end_proc): should protect exceptions. * gc.c (run_final): ditto. * parse.y (f_rest_arg): allow just * for rest arg. * parse.y (mlhs_basic): allow * without formal argument. * regex.c (re_match): the variable `part' should be initialized. Tue May 18 15:25:45 1999 Yukihiro Matsumoto * regex.c (re_search): a bug in range adjustment. Tue May 18 11:35:59 1999 WATANABE Hirofumi * dln.c (conv_to_posix_path): path_len argument added. Mon May 17 12:26:31 1999 Yukihiro Matsumoto * numeric.c (fix_rev): should treat Fixnum as signed long. * eval.c (massign): add strict number check for yield (and call). * eval.c (proc_arity): new method to return number of arguments. * eval.c (method_arity): new method to return number of arguments. * parse.y (read_escape): char may be unsigned. * string.c (rb_str_succ): ditto. * string.c (tr_trans): ditto. * object.c (Init_Object): methods `&', `|', `^' are added to nil. * range.c (rb_range_beg_len): it should be OK for [0..-len-1]. * regex.c (re_search): search for byte literal within mbcs. * regex.c (is_in_list): parsh * regex.c (re_compile_fastmap): should have not alter the loop variable `j' if TRASLATE_P(). * regex.c (re_compile_pattern): escaped characters should be read by PATFETCH_RAW(c). Sat May 15 11:23:51 1999 Yukihiro Matsumoto * regex.c (re_match): endline2 (\Z) should not match at the point between a newline and end-of-line, like endline ($). * class.c (include_class_new): should initialize iv_tbl to share between module and iclass. Fri May 14 08:50:27 1999 Akira Endo * regex.c (re_compile_fastmap): it should be k != 0 to skip. Fri May 14 12:46:56 1999 Yukihiro Matsumoto * time.c (time_load): a bug in old marshal format support. * instruby.rb: make site_ruby directory. Fri May 14 10:18:02 1999 WATANABE Tetsuya * regex.c (re_match): a bug in inline `.*' etc. Fri May 14 09:58:46 1999 Minero Aoki * ruby.c (addpath): should have specified string length. Thu May 13 10:40:44 1999 Yukihiro Matsumoto * eval.c (rb_eval_string_wrap): new function. * regex.c (re_compile_pattern): POSIX line match should alter behavior for `^' and `$' to begbuf and endbuf2 respectively. * ext/pty/pty.c: un-ANSI-fy function arguments. Wed May 12 14:19:38 1999 Yukihiro Matsumoto * struct.c (iv_get): in case of inheritance of generated struct class, __member__ and __size__ should also be inherited. Thanks for Pros Yeboah . * io.c (rb_f_gets_internal): should check number of arguments before checking rb_rs == rb_default_rs. Thanks for Koji Arai . Tue May 11 08:29:28 1999 Yukihiro Matsumoto * regex.c (re_compile_pattern): .?, .+ did not work. Mon May 10 00:59:33 1999 Yukihiro Matsumoto * lib/jcode.rb: forgot to squeeze on reverse (complement) case. * string.c (tr_squeeze): should not set modify flag to be honest, if the string is not modified. * signal.c (Init_signal): SIGTERM should not be handled. * regex.c (re_match): seeking for longest match is now optional, which can be set using RE_OPTION_POSIXMATCH. This satisfies POSIX longest match as much as Emacs's posix-* functions, which are known to be incomplete. Sun May 9 13:04:01 1999 Katsuyuki Komatsu * ext/socket/socket.c (sock_s_getaddrinfo): conversion from Fixnums to C integers needed. Sun May 9 11:51:43 1999 Koji Arai * range.c (range_eqq): reverse condition. * range.c (range_s_new): default should be end inclusive. Sat May 8 03:27:51 1999 Yukihiro Matsumoto * ext/socket/socket.c (thread_connect): replace nasty rb_thread_fd_writable() with rb_thread_select(). Fri May 7 20:49:00 1999 Katsuyuki Komatsu * ext/socket/getaddrinfo.c (inet_pton): wrong parameter to inet_aton(). * ext/socket/addrinfo.h (__P): silly cut and paste typo. 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): avoid using struct sockaddr_storage. Thu May 6 13:21:41 1999 Yukihiro Matsumoto * array.c (rb_ary_indexes): should not use rb_ary_concat(). Thu May 4 12:34:18 1999 Koji Arai * parse.y (parse_string): there should be newline escape by backslashes in strings. * parse.y (parse_qstring): ditto. Mon May 3 04:37:20 1999 Koji Arai * ext/tcltklib/extconf.rb: better search for libX11. * range.c (range_s_new): embarrassing =/== typo. * re.c (Init_Regexp): failed to set default kcode. Mon May 3 02:39:55 1999 WATANABE Tetsuya * ext/socket/socket.c (open_inet): typo (res and res0). Tue May 4 02:07:49 1999 Yukihiro Matsumoto * mkconfig.rb: leave undefined $(VARIABLE) unexpanded in the Config::CONFIG hash table. Mon May 3 09:37:22 1999 Yukihiro Matsumoto * regex.c (re_compile_pattern): expand exactn{n} at compile time. handles stop_paren specially. * regex.c (re_compile_pattern): expand x{n} at compile time. * regex.c (re_search): posix line match should be checked. * regex.c (re_search): a bug in anchor condition. Fri Apr 30 18:57:41 1999 Yukihiro Matsumoto * version 1.3.3 * string.c (rb_str_rindex): position should be END point, not START point. * re.c (rb_reg_search): pos means end point on reverse now. * array.c (rb_ary_s_create): should clear ary->ptr to avoid potential gc crash. Fri Apr 30 15:24:58 1999 Yukihiro Matsumoto * ext/socket/addrinfo.h: compatibility hack for ipv4. * ext/socket/socket.c: itojun's ipv6 patches applied. * ext/socket/extconf.rb: detect ipv6 features based on itojun's ipv6 patches. * ext/extmk.rb.in (enable_config): can handle --enable-xxx now. * lib/mkmf.rb (enable_config): ditto. Fri Apr 30 05:22:23 1999 Shugo Maeda * string.c (rb_str_aset): last index should not append. Thu Apr 29 18:55:31 1999 WATANABE Hirofumi * dln.c (conv_to_posix_path): remove const from args. * ruby.c (rubylib_mangle): remove Fatal(), the obsolete function. Tue Apr 27 14:11:45 1999 Yukihiro Matsumoto * parse.y (fname): lazy workaround for keywords did not work well. * ext/extmk.rb.in: `--with-xxx=yyy' argument configuration. * lib/mkmf.rb: ditto. * misc/ruby-mode.el: forgot to handle $`. * ext/extmk.rb.in: better AIX link support proposed by . Mon Apr 26 16:46:59 1999 Yukihiro Matsumoto * ext/extmk.rb.in: AIX shared library support modified. * ext/aix_mksym.rb: ditto. * configure.in: ditto. * sprintf.c (rb_f_sprintf): should allocate proper sized buffer for float numbers. Sat Apr 24 00:00:16 1999 Yukihiro Matsumoto * parse.y (operation): syntax like `a.[]=(1,2)' is allowed. Fri Apr 23 23:54:09 1999 Yukihiro Matsumoto * io.c (argf_binmode): binmode method added to ARGF. Fri Apr 23 13:55:22 1999 Yukihiro Matsumoto * string.c (rb_f_chomp): should assign the result to $_. or maybe sub/gsub/chop/chomp should NOT assign $_ altogether. Thu Apr 22 16:50:54 1999 Yukihiro Matsumoto * eval.c (rb_callcc): call scope_dup() for all scopes in the interpreter stack. Tue Apr 20 11:24:18 1999 Yukihiro Matsumoto * string.c (rb_str_dump): `#' should be escaped. Tue Apr 20 02:32:42 1999 Yukihiro Matsumoto * parse.y (parse_regx): option /p for posix match added. * re.c (rb_reg_desc): did not print options properly. * io.c (rb_file_s_open): initialize was called twice. Mon Apr 19 18:56:21 1999 Yukihiro Matsumoto * configure.in (DEFAULT_KCODE): can specify default code for $KCODE by --with-default-kcode=(euc|sjis|utf8|none). * regex.c (IS_A_LETTER): a byte sequence shorter than mbc should not match with \w etc. Mon Apr 19 13:49:11 1999 Yukihiro Matsumoto * eval.c (eval): should restore ruby_dyna_vars. Fri Apr 16 21:40:43 1999 Nobuyoshi Nakada * io.c (f_backquote): pipe_open may return nil. * io.c (f_open): rb_io_open may return nil. * io.c (io_s_foreach): ditto. * io.c (io_s_readlines): ditto. * io.c (io_defset): wrong message. Fri Apr 16 15:09:20 1999 Yukihiro Matsumoto * bignum.c (rb_str2inum): strtoul() returns long, not int. * eval.c (rb_load): size of VALUE and ID may be different. * util.c (mmprepare): int is too small to cast from pointers. * config.guess: avoid 'linux-gnu' for alpha-unknown-linux. Thu Apr 15 23:46:20 1999 WATANABE Hirofumi * ruby.c (rubylib_mangle): mangle path by RUBYLIB_PREFIX. Wed Apr 14 23:52:51 1999 SHIROYAMA Takayuki * node.h (NODE_LMASK): should be long to avoid overflow. Wed Apr 14 13:14:35 1999 Katsuyuki Komatsu * dln.c: AIX dynamic link. * ext/aix_ld.rb: ditto. Wed Apr 14 12:19:09 1999 Yukihiro Matsumoto * lib/thread.rb: Queue#{enq,deq} added. Tue Apr 13 17:43:56 1999 Yukihiro Matsumoto * hash.c (rb_hash_s_create): Hash::[] acts more like casting. Tue Apr 13 00:33:52 1999 Yukihiro Matsumoto * io.c (rb_io_stdio_set): warning for assignment to the variables $std{in,out,err}. Mon Apr 12 23:12:32 1999 Yukihiro Matsumoto * io.c (rb_io_reopen): check for reopening same IO. Fri Apr 9 17:45:11 1999 Yukihiro Matsumoto * parse.y (rb_compile_string): bug for nested eval(). * regex.c (re_match): should pop non-greedy stack items on failure, after best_regs are fixed. Thu Apr 8 17:30:40 1999 Yukihiro Matsumoto * pack.c (PACK_LENGTH_ADJUST): need to adjust for `*' length. Tue Apr 6 23:28:44 1999 Yukihiro Matsumoto * parse.y (void_check): add void context checks. Mon Apr 5 12:23:42 1999 Yukihiro Matsumoto * time.c (time_s_at): should copy gmt-mode. * eval.c (eval_node): preserve ruby_eval_tree. Fri Apr 2 14:00:34 1999 NAKAMURA, Hiroshi * lib/debug.rb: wrong command interpreting. Fri Apr 2 11:46:22 1999 Yukihiro Matsumoto * version 1.3.2 Fri Apr 2 10:40:04 1999 Yukihiro Matsumoto * io.c (rb_io_s_pipe): forgot to define IO::pipe. Thu Apr 1 14:40:46 1999 Yukihiro Matsumoto * eval.c (assign): modified for rhs change. * parse.y (stmt): unparenthesisized method calls can be right hand side expression of the assignment. Sat Mar 27 22:42:47 1999 Koji Arai * ext/nkf/nkf.c (rb_nkf_kconv): check size output_ctr before decrement. Thu Mar 25 09:11:03 1999 Yukihiro Matsumoto * time.c (time_s_at): preserve gmt-mode for result. * parse.y (rb_compile_string): do not use cur_mid, use compile_for_eval instead. * st.c (PTR_NOT_EQUAL): wrong logical condition. Wed Mar 24 13:06:43 1999 Yukihiro Matsumoto * parse.y (yycompile): should clear cur_mid after compilation. * io.c (next_argv): need to check type for ARGV.shift. * eval.c (blk_copy_prev): need to preserve outer scope as well as outer frames. * parse.y (rb_compile_string): return can appear within eval(). Tue Mar 23 10:15:07 1999 EGUCHI Osamu * configure.in: AC_C_CONST check added. Tue Mar 23 02:07:35 1999 Yukihiro Matsumoto * time.c (time_plus): preserve gmt-mode for result. Mon Mar 22 01:32:37 1999 Yukihiro Matsumoto * eval.c (rb_eval): adjust line numbers before expression interpolation within strings. * eval.c (rb_eval): defined? returns nil for false condition. * numeric.c (num_nonzero_p): returns nil for false condition. Sat Mar 20 13:07:43 1999 Keiju Ishitsuka * lib/weakref.rb: avoid leak for two weakrefs for one object. Fri Mar 19 11:26:45 1999 WATANABE Hirofumi * eval.c (ruby_run): needed to eval END{} on exit. * eval.c (rb_exit): ditto. Fri Mar 19 02:17:27 1999 Yukihiro Matsumoto * signal.c (Init_signal): handles terminating signals HUP, TERM, QUIT, PIPE, etc. Thu Mar 18 15:47:18 1999 Yukihiro Matsumoto * bignum.c (rb_big_and): bug in sign calculation. * bignum.c (rb_big_or): ditto. * io.c (rb_f_select): forgot to use to_io to retrieve IO, after calling select(2). Tue Mar 16 19:54:31 1999 WATANABE Hirofumi * ext/extmk.rb.in: static linking cause infinite make loop. Tue Mar 16 18:50:04 1999 Yoshida Masato * ext/socket/socket.c (tcp_s_gethostbyname): typo, not NUM2INT(), but INT2NUM(). * ext/socket/socket.c (mkhostent): ditto. Tue Mar 16 12:31:44 1999 Ryo HAYASAKA * file.c (utime_internal): suppress warning by const. * time.c (time_gmtime): ditto. Tue Mar 16 10:23:05 1999 Yukihiro Matsumoto * time.c (time_clone): Time object can be cloned. Tue Mar 16 03:13:10 1999 Koji Arai * ruby.c (load_file): argv[argc] should be NULL. Mon Mar 15 22:12:08 1999 Tadayoshi Funaba * sprintf.c (rb_f_sprintf): typo in arg_num check at exit. Mon Mar 15 16:42:22 1999 Yukihiro Matsumoto * array.c (rb_ary_dup): dup2 should copy class too. Mon Mar 15 15:12:53 1999 Yasuhiro Fukuma * lib/mkmf.rb: install program relative path check. Mon Mar 15 14:05:25 1999 Yukihiro Matsumoto * re.c (rb_reg_s_new): 2nd argument is now option. Regexp::EXTENDED can be specified. Fri Mar 12 10:47:49 1999 Yukihiro Matsumoto * string.c (rb_str_index): str.index("") should always match at offset point. * string.c (rb_str_upto): can specify end point exclusion. * string.c (rb_str_index): negative offset. * regex.c (re_match): begline should not match at the point between a newline and end-of-string. endline neither. * regex.c (re_compile_pattern): context_indep_anchors . * parse.y (parse_regx): need not to push backslashes before escaped characters. * eval.c (rb_thread_join): re-raises exception within target. Fri Mar 12 01:09:36 1999 Koji Arai * ext/readline/readline.c (readline_s_vi_editing_mode): wrong number of arguments. Fri Mar 12 02:12:50 1999 Yukihiro Matsumoto * pack.c (PACK_ITEM_ADJUST): "a".unpack("C3") => [97, nil, nil] Thu Mar 11 18:23:50 1999 WATANABE Tetsuya * ext/socket/socket.c (Init_socket): UDPsocket was omitted. Thu Mar 11 16:43:30 1999 Yukihiro Matsumoto * pack.c (PACK_LENGTH_ADJUST): push fixed number of items per template to result array. * pack.c (pack_unpack): I/N/C etc. push nil in the array for "". Tue Mar 9 00:19:21 1999 Yukihiro Matsumoto * hash.c (ruby_unsetenv): use ruby_setenv(name, 0). * hash.c (env_delete): ditto. * string.c (rb_str_upto): do not check `beg * string.c (rb_str_index): wrong end point calculation. Sat Mar 6 02:19:12 1999 Yukihiro Matsumoto * re.c (match_index): MatchingData#index(n) added. * array.c (rb_ary_subseq): ary[n..-1] returns an sub-array unless n is too small negative index. * re.c (rb_reg_match_method): Regexp#match(str) added. * array.c (rb_ary_indexes): understands ranges as indexes. * re.c (match_size): MatchingData#size added. Fri Mar 5 01:04:57 1999 Yukihiro Matsumoto * array.c (rb_ary_fill): modified for range. * array.c (rb_ary_aset): a[n..m] revisited. Thu Mar 4 14:23:29 1999 Yukihiro Matsumoto * string.c (rb_str_subseq): a[n..m] revisited. * parse.y (method_call): allow Const::method{}. * array.c (rb_ary_replace_method): should replace original array. Thu Mar 4 02:30:22 1999 Yukihiro Matsumoto * configure.in: remove --disable-thread, thread feature is no longer optional. Thu Mar 4 00:32:17 1999 Yasuhiro Fukuma * parse.y (read_escape): wrong arguments for scan_oct,scan_hex. Wed Mar 3 11:51:53 1999 Yukihiro Matsumoto * ext/socket/socket.c (Init_socket): rename class names as TCPsocket -> TCPSocket etc. Tue Mar 2 19:46:42 1999 WATANABE Hirofumi * configure.in (LDSHARED): use gcc -Wl,-G for solaris with gcc. Tue Mar 2 17:04:19 1999 Yukihiro Matsumoto * parse.y (yylex): backslashes do not concatenate comment lines anymore. Mon Mar 1 14:05:12 1999 Yukihiro Matsumoto * eval.c (rb_call0): adjust argv for optional arguments. super without arguments emit superclass method with the value from optional arguments. enabled as experiment. Sun Feb 28 14:04:07 1999 WATANABE Hirofumi * parse.y (nextc): backslash at the eof cause infinite loop Sun Feb 28 11:01:26 1999 Tadayoshi Funaba * time.c (make_time_t): month range check added. Sat Feb 27 02:36:05 1999 Yukihiro Matsumoto * re.c (Init_Regexp): add escape as alias of quote. * re.c (rb_reg_s_quote): char-code can be specified now. Fri Feb 26 18:45:36 1999 Yasuhiro Fukuma * eval.c (error_print): bug for error message with newlines. Fri Feb 26 12:00:04 1999 Yukihiro Matsumoto * time.c (make_time_t): future check modified to allow 1969-12-31 at certain timezone. * time.c (time_arg): year >= 1000 should be past. * version.c (Init_version): constant RELEASE_DATE added. Fri Feb 26 01:08:30 1999 Yukihiro Matsumoto * string.c (rb_str_substr): returns nil for out-of-range access. * array.c (rb_ary_subseq): returns nil for out-of-range access. * array.c (rb_ary_store): negative index message has changed. * string.c (rb_str_aset): reallocation needed. * string.c (rb_str_aset): allow char append to the string. Thu Feb 25 23:30:17 1999 Tadayoshi Funaba * time.c (time_load): tm_year should be packed in 17 bits, not 18. Thu Feb 25 12:50:25 1999 Yukihiro Matsumoto * missing/dup2.c: replaced by public domain version. * time.c (make_time_t): add `future check' in loops. * object.c (rb_num2dbl): forbid implicit conversion from nil, or strings. thus `Time.now + str' should raise error. * object.c (rb_Float): convert nil into 0.0. * object.c (rb_Integer): conversion method improved. Thu Feb 25 03:27:50 1999 Shugo Maeda * eval.c (rb_call): should handle T_ICLASS properly. Thu Feb 25 00:04:00 1999 Yukihiro Matsumoto * error.c (Init_Exception): global function Exception() removed. * variable.c (rb_class2name): returns "nil"/"true"/"false" for them. * time.c (time_dump): time marshaling format compressed size from 11 bytes to 8 bytes. thanx to tadf@kt.rim.or.jp. * eval.c (rb_obj_call_init): should specify arguments explicitly. Wed Feb 24 15:43:28 1999 Yukihiro Matsumoto * parse.y (yylex): comment concatenation requires preceding space before backslash at the end of line. * io.c (rb_f_pipe): global pipe is obsolete now. * object.c (Init_Object): remove true.to_i, false.to_i. Tue Feb 23 14:21:41 1999 Yukihiro Matsumoto * parse.y (yylex): warn if identifier! immediately followed by `='. Tue Feb 23 12:32:41 1999 WATANABE Hirofumi * eval.c (rb_load): tilde expansion moved to find_file. * eval.c (find_file): tilde expansion added. Tue Feb 23 10:50:20 1999 Yukihiro Matsumoto * eval.c (require_method): require can handle multiple fnames. * hash.c (rb_hash_foreach_iter): hash key may be nil. Mon Feb 22 17:44:02 1999 Yukihiro Matsumoto * regex.c (re_match): should not pop failure point on success for non-greedy matches. * io.c (Init_IO): remove global_functions getc, readchar, ungetc, seek, tell, rewind. Sat Feb 20 22:54:26 1999 Yukihiro Matsumoto * numeric.c (rb_num2long): no implicit conversion from boolean. Sat Feb 20 09:58:42 1999 EGUCHI Osamu * numeric.c (flo_to_s): portable Infinity and NaN support. Sat Feb 20 07:13:31 1999 WATANABE Tetsuya * io.c (rb_file_sysopen): forgot to initialize a local variable. Fri Feb 19 23:05:07 1999 Yukihiro Matsumoto * string.c (rb_str_subseq): range check changed. * marshal.c: increment MARSHAL_MINOR for Time format change. * time.c (time_old_load): support old marshal format. * time.c (time_load): changed for new format Y/M/D/h/m/s/usec. * time.c (time_dump): marshal dump format has changed. Fri Feb 19 00:25:57 1999 Yukihiro Matsumoto * time.c (time_arg): should reject "sep\0" and such. * time.c (time_plus): Time#+ should not receive Time object operand. * string.c (rb_str_substr): negative length raises exception now. * array.c (beg_len): if end == -1, it points end of the array. * array.c (rb_ary_subseq): negative length raises exception now. Thu Feb 18 20:57:04 1999 Tadayoshi Funaba * time.c (rb_strftime): strftime() may return 0 on success too. * time.c (time_strftime): `\0' within format string should not be omitted in the result. * time.c (rb_strftime): zero length format. * time.c (time_to_a): yday start with 1 now. * time.c (time_zone): support for long timezone name. * time.c (time_yday): yday start with 1 now. * time.c (time_minus): minus calculation was wrong. * time.c (time_minus): sec, usec should be at least `long', maybe they should be `time_t'. * time.c (time_plus): addition with float was wrong. * time.c (time_to_s): support for long timezone name. * time.c (time_gm_or_local): too far future check moved. * time.c (time_arg): treat 2 digit year as 69-99 => 1969-1999, 00-68 => 2000-2068 Thu Feb 18 03:56:47 1999 Yukihiro Matsumoto * missing/fnmatch.c: moved to missing directory. Wed Feb 17 16:22:26 1999 Yukihiro Matsumoto * struct.c (rb_struct_alloc): actual initialization now be done in `initialize'. Wed Feb 17 09:47:15 1999 okabe katsuyuki * regex.c (re_search): use mbclen() instead of ismbchar(). * re.c (rb_reg_s_quote): should handle mbchars properly. Wed Feb 17 01:25:26 1999 Yukihiro Matsumoto * parse.y (yylex): stop comment concatenation by backslash follows after >= 0x80 char. may cause problem with Latin chars. * eval.c (error_print): exception in rb_obj_as_string() caused SEGV. protect it by PUSH_TAG/POP_TAG. * error.c (exc_exception): `Exception#exception' should return self. Wed Feb 17 01:12:22 1999 Hirotaka Ichikawa * configure.in: BeOS patch. Tue Feb 16 14:25:00 1999 Yukihiro Matsumoto * regex.c (re_compile_pattern): should reallocate mbc space for character class unless current_mbctype is ASCII. Mon Feb 15 15:48:30 1999 WATANABE Hirofumi * configure.in: specify `-Wl,-E' only for GNU ld. Mon Feb 15 11:43:22 1999 GOTO Kentaro * array.c (rb_inspecting_p): should return Qfalse. Sun Feb 14 22:36:40 1999 EGUCHI Osamu * sprintf.c (rb_f_sprintf): `%G' was omitted. Sun Feb 14 12:47:48 1999 EGUCHI Osamu * numeric.c (Init_Numeric): allow divide by zero on FreeBSD. * numeric.c (Init_Numeric): FloatDomainError added. * configure.in (AC_REPLACE_FUNCS): add checks for functions isinf, isnan, and finite. Sat Feb 13 01:24:16 1999 Yukihiro Matsumoto * eval.c (rb_thread_create_0): should protect th->thread. Fri Feb 12 16:16:47 1999 Yasuhiro Fukuma * string.c (rb_str_inspect): wrong mbc position. Fri Feb 12 16:21:17 1999 Yukihiro Matsumoto * eval.c (rb_thread_fd_close): * io.c (rb_io_fptr_close): tell scheduler that fd is closed. * io.c (rb_io_reopen): ditto. * io.c (READ_CHECK): check if closed after thread context switch. * ext/socket/socket.c (bsock_close_read): do not check the return value from shutdown(2). * ext/socket/socket.c (bsock_close_write): ditto. * ext/socket/socket.c (sock_new): need to dup(fd) for close_read and close_write. * parse.y (here_document): handle newlines within #{}. * regex.h: should replace symbols for ruby. Fri Feb 12 00:46:28 1999 Shugo Maeda * marshal.c (r_object): should update the method name in message. * marshal.c (w_object): limit should be converted into Fixnum. Wed Feb 10 15:20:03 1999 Yukihiro Matsumoto * regex.c (re_match): empty pattern should not cause infinite pattern match loop. * regex.c (re_compile_pattern): RE_OPTIMIZE_ANCHOR for /.*/, not for /(.|\n)/. * numeric.c (fix_pow): `fixnum**nil' should raise TypeError. * bignum.c (rb_big_pow): need to normalize results. Wed Feb 10 01:42:41 1999 EGUCHI Osamu * numeric.c (fix_pow): `(5**1).type' should be Integer. Tue Feb 9 01:22:49 1999 Yukihiro Matsumoto * parse.y (yylex): do not ignore newlines in mbchars. * io.c (rb_file_s_open): mode can be specified by flags like open(2), e.g. File::open(path, File::CREAT|File::WRONLY). * io.c (rb_f_open): bit-wise mode flags for pipes * io.c (Init_IO): bit flags for open. Sat Feb 6 22:56:21 1999 Yukihiro Matsumoto * string.c (rb_str_sub_bang): should not overwrite match data by regexp match within the block. * string.c (rb_str_gsub_bang): ditto. Sat Feb 6 03:06:17 1999 Yukihiro Matsumoto * re.c (match_getter): accessing $~ without matching caused SEGV. Fri Feb 5 22:11:08 1999 EGUCHI Osamu * parse.y (yylex): binary literal support, like 0b01001. * parse.y (yylex): octal numbers can contain `_'s. * parse.y (yylex): warns if non-octal number follows immediately after octal literal. * parse.y (yylex): now need at least one digit after prefix such as 0x, or 0b. * bignum.c (rb_str2inum): recognize binary numbers like 0b0101. Fri Feb 5 03:26:56 1999 Yasuhiro Fukuma * ruby.c (proc_options): -e without program prints error. Fri Feb 5 00:01:50 1999 Yukihiro Matsumoto * parse.y (terms): needed to clear heredoc_end. * numeric.c (flo_div): allow float division by zero. Thu Feb 4 11:56:24 1999 Yukihiro Matsumoto * missing/strtod.c: for compatibility. * configure.in (strtod): add strtod compatible check. * numeric.c (rb_num2long): missing/vsnprintf.c does not support floating points. * numeric.c (flo_to_s): ditto. Wed Feb 3 23:02:12 1999 Yoshida Masato * regex.c (re_compile_pattern): use ismbchar() to get next char. * regex.c (re_search): wrong mbchar shift. * re.c (rb_reg_search): needed to reset $KCODE after match. * regex.c (re_compile_fastmap): mbchars should match with \w. Wed Feb 3 22:35:12 1999 EGUCHI Osamu * parse.y (yylex): too big float raise warning, not error. Tue Feb 2 23:41:42 1999 Yoshida Masato * regex.c (re_match): wrong boundary. * regex.c (IS_A_LETTER): re_mbctab[c] may not be 1 for mbc. * regex.c (re_search): mbchar support for shifting ranges. * regex.c (MBC2WC): wrong conversion. Wed Feb 3 15:03:16 1999 Yukihiro Matsumoto * parse.y (parse_regx): need to escape parens if terminators are not any kind of parenthesis. * parse.y (parse_qstring): ditto. * parse.y (parse_string): ditto. Tue Feb 2 17:11:26 1999 WATANABE Tetsuya * string.c (rb_str_gsub_bang): too small realloc condition. Mon Feb 1 10:01:17 1999 EGUCHI Osamu * parse.y (yylex): range check for the float literal. Sat Jan 30 18:34:16 1999 Yukihiro Matsumoto * ruby.c (usage): -h option to show brief command description. Sat Jan 30 08:45:16 1999 IKARASHI Akira * lib/cgi-lib.rb: cookie support added. Sat Jan 30 13:38:24 1999 Yukihiro Matsumoto * regex.c (re_compile_pattern): mbchars should match with \w within character class. Was matching with \W. * regex.c (re_match): \w should match with multi byte characters, not its first byte. Sat Jan 30 10:06:41 1999 Yoshida Masato * re.c (rb_reg_s_new): UTF-8 flag handle (/u, /U). * re.c (rb_kcode): $KCODE handle for UTF-8. Sat Jan 30 01:51:16 1999 Yukihiro Matsumoto * array.c (rb_ary_delete_if): RTEST() missing. * hash.c (delete_if_i): ditto. * enum.c (Init_Enumerable): select (=find_all), detect (=find) added as aliases. Fri Jan 29 21:32:19 1999 WATANABE Tetsuya * hash.c (rb_f_setenv): SEGV caused by small typo. Fri Jan 29 00:15:58 1999 Yukihiro Matsumoto * lib/parsedate.rb (parsedate): support date format like 23-Feb-93, which is required by HTTP/1.1. * variable.c (find_class_path): avoid calling rb_iv_set(). * eval.c (backtrace): do not need to modify $SAFE internally. * variable.c (classname): inline __classid__ access. * eval.c (THREAD_ALLOC): needed to initialize wrapper. * lib/ftools.rb (makedirs): allows slash at the end of the path. * numeric.c (rb_fix_induced_from): ensure result to be Fixnum. Thu Jan 28 17:31:43 1999 Yukihiro Matsumoto * numeric.c (flo_to_s): float format changed to "%16.10g". Thu Jan 28 02:13:11 1999 Yoshinori Toki * array.c (rb_ary_store): expand allocated buffer by 3/2. Wed Jan 27 17:50:02 1999 Kazuhiro HIWADA * bignum.c (dbl2big): raised error if double is too big to cast into long. check added. Wed Jan 27 03:16:18 1999 Yukihiro Matsumoto * variable.c (rb_mod_const_at): can't list constants of the untainted objects in safe mode. * class.c (method_list): can't list methods of untainted objects in safe mode. Tue Jan 26 02:40:41 1999 GOTO Kentaro * prec.c: Precision support for numbers. Thu Jan 21 19:08:14 1999 Yukihiro Matsumoto * eval.c (rb_f_raise): calls `exception' method, not `new'. * error.c (exc_exception): renamed from `new'. Wed Jan 20 03:39:48 1999 Yukihiro Matsumoto * parse.y (yycompile): rb_in_compile renamed to ruby_in_compile. * ruby.c (load_file): define DATA if __END__ appeared in script. Tue Jan 19 14:57:51 1999 Yukihiro Matsumoto * parse.y (here_document): need to protect lex_lastline. * parse.y (yylex): disable %//, %'', %``. Tue Jan 19 05:01:16 1999 Koji Arai * array.c (beg_len): round range value too much. Mon Jan 18 13:02:27 1999 Kuroda Jun * hash.c (env_keys): strchr() may return NULL. Mon Jan 18 17:51:47 1999 Yukihiro Matsumoto * instruby.rb (wdir): install libruby.a in archdir. * lib/ftools.rb (install): removes file before installing. Mon Jan 18 16:55:31 1999 MAEDA shugo * eval.c (rb_callcc): experimental continuation support. Sun Jan 17 19:45:37 1999 WATANABE Hirofumi * pack.c (pack_pack): nil packing caused SEGV. Sat Jan 16 13:18:03 1999 Yukihiro Matsumoto * string.c (rb_str_concat): character (fixnum) can be append to strings * array.c (rb_ary_unshift): unshift returns array. Sat Jan 16 01:39:19 1999 Yoshida Masato * string.c (rb_str_split_method): UTF-8 support. * regex.c: UTF-8 support. Thu Jan 14 00:42:55 1999 Yukihiro Matsumoto * string.c (rb_str_gsub_bang): forget to add offset for null match. * eval.c (rb_thread_local_aset): can't modify in tainted mode. * hash.c (env_each_key): avoid generating temporary array. Wed Jan 13 23:58:50 1999 Yukihiro Matsumoto * hash.c (rb_f_setenv): name and value can be tainted. Wed Jan 6 02:42:08 1999 Yukihiro Matsumoto * bignum.c (Init_Bignum): forgot to define Bignum#===. * gc.c (gc_sweep): if add_heap() is called during GC, objects on allocated heap page(s) are not marked, should not be recycled. * gc.c (gc_sweep): should refer latest freelist. * gc.c (id2ref): modified to support performance patch. * object.c (rb_obj_id): performance patch (no bignum for id). Tue Jan 5 01:56:18 1999 Yukihiro Matsumoto * config.guess: merge up-to-date from autoconf 2.12. * array.c (rb_ary_join): avoid calling rb_protect_inspect() till it is really needed. * object.c (rb_obj_inspect): show detailed information for the instance variables (infinite loop can avoid now). * struct.c (rb_struct_inspect): avoid infinite loop. Sun Jan 3 01:37:58 1999 Takao KAWAMURA * misc/ruby-mode.el (ruby-end-of-defun): moved too much. * misc/ruby-mode.el (ruby-mode-variables): set paragraph-separator for the mode. * misc/ruby-mode.el: proper font-lock for `def' and `nil' etc. Sat Jan 2 17:09:06 1999 Yukihiro Matsumoto * eval.c (rb_jump_tag): new api to invoke JUMP_TAG. tag values can obtained from rb_eval_string_protect()/rb_load_protect(). * eval.c (rb_rescue): now catches all exceptions but SystemExit. * eval.c (rb_eval_string_protect): eval string with protection. * eval.c (rb_load_protect): load file with protection. * io.c (rb_io_puts): avoid infinite loop for cyclic arrays. * eval.c (rb_thread_local_aref): thread local hash tables. * object.c (rb_equal): check exact equal before calling `=='. Thu Dec 31 22:28:53 1998 MAEDA shugo * eval.c (rb_f_require): feature names should be provided with DLEXT extension. * marshal.c (Init_marshal): need to provide `marshal.so'. Wed Dec 30 02:29:16 1998 Yukihiro Matsumoto * variable.c (classname): do not call rb_ivar_set(). * eval.c (ruby_run): finalizers were called too early. Fri Dec 25 12:19:30 1998 Fukuda Masaki * gc.c (rb_gc_mark): should not return on FL_EXIVAR. Fri Dec 25 11:56:51 1998 Yukihiro Matsumoto * gc.c (gc_mark): proper scanning for temporary region. * eval.c (TMP_ALLOC): protection for C_ALLOCA was broken. Thu Dec 24 18:26:04 1998 Yukihiro Matsumoto * development version 1.3 released. Thu Dec 24 00:17:00 1998 Yukihiro Matsumoto * eval.c (rb_load): top self should be set properly. * variable.c (classname): check __classpath__ if it is defined. * variable.c (classname): invalid warning at -v with static linked ruby interpreter. * eval.c (is_defined): modified for expr::Const support. * eval.c (rb_eval): invoke method expr::Const if expr is not class nor module. * parse.y (primary): enable expr::identifier as method invocation. Wed Dec 23 03:04:36 1998 Yukihiro Matsumoto * regex.c (re_match): avoid too many loop pops for (?:..). Tue Dec 22 18:01:08 1998 Yukihiro Matsumoto * experimental version 1.1d1 released. Mon Dec 21 01:33:03 1998 Yukihiro Matsumoto * eval.c (TMP_PROTECT): add volatile to ensure GC protection. * string.c (rb_str_gsub_bang): calculate buffer size properly. * parse.y (lex_get_str): needed to return Qnil at EOS. * eval.c (find_file): check policy modified, raise exception immediately for tainted load_path. * hash.c (rb_f_setenv): do not depend on setenv() nor putenv(). Thu Dec 17 06:29:23 1998 Yukihiro Matsumoto * ext/tk/tkutil.c (tk_s_new): use rb_obj_instance_eval(), instead of rb_yield_0(). * eval.c (rb_f_require): forgot to call find_file in some cases. * eval.c (rb_f_require): `require "feature.so"' to load dynamic libraries. old `require "feature.o"' is still OK. * eval.c (rb_eval): yield without value dumped core. Wed Dec 16 16:28:31 1998 Yukihiro Matsumoto * experimental version 1.1d0 (pre1.2) released. Wed Dec 16 10:43:34 1998 Yukihiro Matsumoto * regex.c (re_search): bound check before calling re_match(). Tue Dec 15 13:59:01 1998 Yukihiro Matsumoto * error.c (exc_to_s): returns class name for unset mesg. * error.c (exc_initialize): do not initialize @mesg by "". * parse.y (nextc): __END__ should handle CR+LF newlines. Wed Dec 9 13:37:12 1998 MAEDA shugo * pack.c (encodes): use buffering for B-encoding. * pack.c (pack_pack): Q-encoding by 'M'. Tue Dec 8 14:10:00 1998 Yukihiro Matsumoto * variable.c (generic_ivar_get): any object can have instance variables now. great improvement. * variable.c (rb_name_class): do not set __classpath__ by default, use __classid__ instead. Mon Dec 7 22:08:22 1998 Yukihiro Matsumoto * ruby.h (struct RFile): IO objects can have instance variables now. * parse.y (primary): allows `def obj::foo; .. end'. Mon Dec 7 18:24:50 1998 WATANABE Tetsuya * ruby.c (set_arg0): $0 support for HP-UX. Mon Dec 7 01:30:28 1998 WATANABE Hirofumi * dln.c (dln_strerror): better error messages on win32. Sat Dec 5 23:27:23 1998 Yukihiro Matsumoto * parse.y (here_document): indentable here-doc delimiter by `<<-'. Proposed by Clemens . Thanks. Thu Dec 3 16:50:17 1998 Yukihiro Matsumoto * ext/extmk.rb.in (realclean): trouble on install. Sun Nov 29 22:25:39 1998 Takaaki Tateishi * process.c (f_exec): check number of argument. Thu Nov 26 17:27:30 1998 Yukihiro Matsumoto * version 1.1c9 released. Wed Nov 25 13:07:12 1998 Yukihiro Matsumoto * string.c (rb_str_dup): do not copy additional data (STR_NO_ORIG). * parse.y (yycompile): reduce known memory leak (hard to remove). Wed Nov 25 03:41:21 1998 Yukihiro Matsumoto * st.c (st_init_table_with_size): round size up to prime number. Sat Nov 21 23:27:23 1998 Yukihiro Matsumoto * hash.c (rb_hash_aset): reduce copying key strings. * gc.c (looks_pointerp): declare as inline function if possible. * st.c (PTR_NOT_EQUAL): compare hash values first before calling comparing function. * st.c (ADD_DIRECT): save hash value in entries to reduce hash calculation. * string.c (rb_str_gsub_bang): avoid rb_scan_args() to speed-up. * string.c (rb_str_sub_bang): ditto. Sat Nov 21 18:44:06 1998 Masaki Fukushima * time.c (time_s_now): had memory leak. * ext/md5/md5init.c (md5_new): had memory leak. * ext/md5/md5init.c (md5_clone): ditto. Fri Nov 20 23:23:23 1998 Yukihiro Matsumoto * lib/delegate.rb: do not propagate hash and eql?. Thu Nov 19 01:40:52 1998 Yukihiro Matsumoto * sample/ruby-mode.el (ruby-expr-beg): failed to find reserved word boundary. * eval.c (rb_eval): avoid calling `concat' method. calls rb_ary_concat() directly for efficiency. * eval.c (rb_eval): actual rest arguments extended arrays too much. Wed Nov 18 14:30:24 1998 Yukihiro Matsumoto * class.c (rb_define_global_function): global functions now be module function of the Kernel. Wed Nov 18 10:48:09 1998 Yukihiro Matsumoto * io.c (read_all): SEGV on large files. Tue Nov 17 18:11:20 1998 Yukihiro Matsumoto * version 1.1c8 released. Tue Nov 17 16:58:47 1998 Yukihiro Matsumoto * parse.y (arg): assignment to attribute name start with capital should be allowed. * eval.c (thread_alloc): needed to mark terminated threads too. Tue Nov 17 12:33:48 1998 Motoyuki Kasahara * ext/extmk.rb.in (create_makefile): Set `libdir' to `@libdir@', Set `pkglibdir' to `$libdir/$(RUBY_INSTALL_NAME)'. Tue Nov 17 10:30:46 1998 Yukihiro Matsumoto * sprintf.c (f_sprintf): %l%%c -> %%l%c Tue Nov 17 01:08:50 1998 Yukihiro Matsumoto * parse.y (ret_args): distinguish `a' and `*a' for the arguments of yield and return. * eval.c (rb_eval): flip3 should work like sed. * eval.c (rb_eval): flip{2,3} now have independent state for each scope to work fine with thread. Mon Nov 16 23:26:29 1998 Yukihiro Matsumoto * parse.y (primary): exec else clause if no exception raised. Sun Nov 15 15:44:07 1998 Tadayoshi Funaba * ext/extmk.rb.in (install): bug in target. Sat Nov 14 11:02:05 1998 Motoyuki Kasahara * Makefile.in (install): Give the argument `$(DESTDIR)' to `instruby.rb'. * instruby.rb: Recognize ARG[0] as `destdir'. * instruby.rb: Give the argument `destdir' to `extmk.rb'. * ext/extmk.rb.in: Recognize ARG[1] as `$destdir'. * instruby.rb: Create the installation directories (bindir, libdir, archdir, pkglibdir, archdir, and mandir) under `destdir', and install all files under there. * ext/extmk.rb.in: Likewise. Sat Nov 14 10:56:55 1998 Motoyuki Kasahara * instruby.rb: Add the variable `pkglibdir'. * instruby.rb: Set the variable `libdir' to `$(libdir)', not `$(libdir)/$(ruby_install_name)'. `libruby.so' and `libruby.so.LIB' are installed at `libdir'. * instruby.rb: Set the variable `archdir' to `$(pkglibdir)/$(arch)'. Fri Nov 13 19:43:29 1998 KIMURA Koichi * missing/nt.c (SafeFree): wrong free offset. Thu Nov 12 20:11:53 1998 Koji Arai * sample/ruby-mode.el: wrong highlight. * parse.y (parse_regx): newline in regexp was ignored. Wed Nov 11 10:54:57 1998 Yukihiro Matsumoto * parse.y (here_document): <<'FOO' should not escape anything. * parse.y (here_document): bare << here-doc available, even though it's deprecated. * file.c (rb_file_s_readlink): return value should be tainted. * ext/etc/etc.c (setup_passwd): information (eg. GCOS name) should be tainted (modified at Perl Conference). Tue Nov 10 00:22:11 1998 EGUCHI Osamu * configure.in: elf support for FreeBSD 3.x Tue Nov 10 00:05:43 1998 Yukihiro Matsumoto * parse.y (yylex): here document available in eval. Mon Nov 9 17:55:19 1998 Yukihiro Matsumoto * version 1.1c7 released. Fri Nov 6 19:25:27 1998 Takao KAWAMURA * sample/ruby-mode.el: font-lock patch. Thu Nov 5 15:42:22 1998 Yukihiro Matsumoto * sample/README, lib/README: simple description for each file. Wed Nov 4 18:14:19 1998 Yukihiro Matsumoto * eval.c (assign): attribute assignment should be called as public. Tue Nov 3 23:36:39 1998 Yukihiro Matsumoto * string.c (rb_str_dump): dumps core for negative char value. * regex.c (re_compile_pattern): out of boundary access for empty regexp. Mon Nov 2 22:54:01 1998 Yukihiro Matsumoto * string.c (rb_str_aset): `str[str]' replaces first match. Mon Nov 2 18:24:33 1998 Yukihiro Matsumoto * eval.c (thread_create): was accessing modified status. Sun Nov 1 01:18:52 1998 EGUCHI Osamu * gc.c (xrealloc): size 0 needs round up to 1. Sat Oct 31 23:18:34 1998 Yukihiro Matsumoto * string.c (rb_str_split_method): negative LIMIT means number of split fields are unlimited, as in perl. * string.c (rb_str_split_method): if LIMIT is unspecified, trailing null fields are stripped. Sat Oct 31 04:16:14 1998 Inaba Hiroto * string.c (str_aref): regexp index SEGVed. Fri Oct 30 14:33:47 1998 Yukihiro Matsumoto * re.c (reg_match): returns nil for unmatch. * dir.c (dir_entries): new method. * eval.c (block_pass): do not push block, substitute it. Fri Oct 30 01:28:52 1998 Yukihiro Matsumoto * range.c (range_check): avoid <=> check for Fixnums. * array.c (rb_ary_aset): accept negative index. Wed Oct 28 22:00:54 1998 Yukihiro Matsumoto * regex.c (re_match): access out of boundary fixed. Wed Oct 28 11:37:42 1998 TAMITO * io.c (f_select): fd number comparison bug. Tue Oct 27 23:07:11 1998 Yukihiro Matsumoto * sample/ruby-mode.el (ruby-parse-region): forgot to support %w() style array literal. * eval.c (rb_eval): unused block raises warning. Mon Oct 26 09:37:53 1998 Yukihiro Matsumoto * eval.c (dvar_asgn_push): dvar pushed too many times if variable-in-block first appear in loops. Sun Oct 25 22:59:27 1998 Yukihiro Matsumoto * regex.c (set_list_bits): was using wrong offset. Thu Oct 22 00:07:11 1998 Yukihiro Matsumoto * eval.c (rb_obj_method): method retrieved from tainted object should be tainted too. * eval.c (method_call): safe_level should be restored during Method#call. Wed Oct 21 14:21:06 1998 Yukihiro Matsumoto * io.c (Init_IO): new constants IO::SEEK_{SET,CUR,END}. * io.c (rb_f_ungetc): ungetc pushes a char back into STDIN. Mon Oct 19 11:50:00 1998 Motoyuki Kasahara * ext/extmk.rb: Load '@top_srcdir@/lib/find.rb', not '../lib/find.rb'. * ext/extmk.rb: Distinguish between `top_srcdir' and `topdir'. * Makefile.in (CFLAGS): Add `-I.'. * Makefile.in (lex.c): Give `@srcdir@/keywords' to gperf, not `keywords'. * instruby.rb: Use `CONFIG["bindir"]', instead of `prefix + "/bin"'. * instruby.rb: Use `CONFIG["libdir"]', instead of `prefix + "/lib"'. * instruby.rb Use `CONFIG["mandir"]', instead of `prefix + "/man"'. * instruby.rb (wdir): Add the variable to preserve the current working directory. * instruby.rb: Chdir to wdir before install `config.h' and `rbconfig.rb'. Mon Oct 19 10:07:01 1998 EGUCHI Osamu * eval.c (rb_eval): reduce recursive calls to rb_eval(). Fri Oct 16 15:31:45 1998 Yukihiro Matsumoto * time.c (time_new_internal): timeval must be positive. Thu Oct 15 13:54:48 1998 Yukihiro Matsumoto * parse.y (arg): local variables can be accessed within right side expression in assignment, notably in blocks. Wed Oct 14 00:18:33 1998 Yukihiro Matsumoto * array.c (Init_Array): Array#=== is now for equal check, not inclusion check. * parse.y (when_args): `when a, *b' style new syntax for array expansion in `case'. Tue Oct 13 14:30:32 1998 Yukihiro Matsumoto * object.c (rb_obj_untaint): taint marks can be unset. * eval.c (rb_eval): taint propagation for embedded strings. Mon Oct 12 13:27:15 1998 Yukihiro Matsumoto * eval.c (rb_call0): check stack depth more frequently. Mon Oct 12 08:08:30 1998 Yukihiro Matsumoto * io.c (rb_p): can print even in secure mode. Sun Oct 11 22:50:13 1998 Yukihiro Matsumoto * variable.c (rb_const_set): taint check for modification. * variable.c (rb_ivar_set): taint check for modification. * string.c (rb_str_modify): taint check for modification. * hash.c (rb_hash_modify): taint check for modification. * array.c (rb_ary_modify): taint check for modification. * ruby.h (FL_TAINT): taint for all objects, not only strings. Fri Oct 9 17:01:14 1998 Yukihiro Matsumoto * io.c (read_all): read() returns "" at immediate EOF. * io.c (io_read): read(nil) read all until EOF. Thu Oct 8 13:32:13 1998 Yukihiro Matsumoto * time.c (time_dump): marshal can dump Time object now. * marshal.c (Init_marshal): rename marshal methods `_dump_to' to `_dump', `_load_from' to `_load'. * parse.y (rb_intern): "+=".intern generates proper symbol. Mon Oct 5 18:31:53 1998 Yukihiro Matsumoto * version 1.1c6 released. Fri Oct 2 14:22:33 1998 Yukihiro Matsumoto * regex.c (re_search): `/\s*(--)$/ =~ "- --"' did not match, because of wrong optimize condition. Mon Oct 1 01:55:16 1998 Yukihiro Matsumoto * parse.y (rb_intern): should not raise exceptions. * parse.y (yylex): symbol like `:foo?=' should not be allowed. * ext/extmk.rb.in: makes *.a for static link modules. Wed Sep 30 14:13:06 1998 Yukihiro Matsumoto * eval.c (rb_thread_start): supports making a subclass of the Thread class. Tue Sep 29 17:46:01 1998 Yukihiro Matsumoto * eval.c (rb_thread_join): join is now an instance method. Fri Sep 25 12:01:19 1998 Yukihiro Matsumoto * parse.y (yylex): `@foo!' should be an error. Thu Sep 24 14:55:06 1998 WATANABE Tetsuya * ext/etc/etc.c (Init_etc): wrong field definition. Thu Sep 17 17:09:05 1998 Yukihiro Matsumoto * io.c (io_reopen): was creating FILE* for wrong fd. Tue Sep 15 05:28:11 1998 Koji Arai * regex.c (re_compile_pattern): forgot to fixup for the pattern like (?=(A)|(B)). Tue Sep 15 01:06:08 1998 Yukihiro Matsumoto * io.c (rb_io_gets_internal): do not set $_ by default, only gets/readline set the variable. * eval.c (rb_f_load): load toplevel class is set to anonymous module if safe_level >= 5, to encapsulate modification. * eval.c (rb_f_load): set frame properly. * string.c (rb_str_each_line): do not set $_. Mon Sep 14 14:42:27 1998 Yukihiro Matsumoto * regex.c (re_match): beginning and end of the string, do not automatically match `\b'. * string.c (scan_once): consume at least on character. * regex.c (re_search): wrong behavior for negative range. Sat Sep 12 21:21:26 1998 Koji Arai * regex.c (re_search): range value should be maintained. Thu Sep 10 10:55:00 1998 Yukihiro Matsumoto * parse.y (backref_error): yyerror does not understand formats. Tue Sep 8 18:05:33 1998 Yukihiro Matsumoto * version 1.1c5 released. Tue Sep 8 10:03:39 1998 Yukihiro Matsumoto * string.c (str_each_line): wrong line splitting with newline at top of the string. * string.c: non bang methods return copied string. * eval.c (f_END): needed to initialize frame->argc; Fri Sep 4 11:27:40 1998 Yukihiro Matsumoto * bignum.c (bigadd): proper sign combination. * regex.c (re_search): wrong return value for \A. Thu Sep 3 14:08:14 1998 Yukihiro Matsumoto * version 1.1c4 released. Tue Sep 1 10:47:16 1998 Yukihiro Matsumoto * regex.c (slow_search): do not compare llen and blen. llen may be longer than blen, if little contains 0xff. * regex.c (mbctab_euc): set 0x8e as multibyte character. * string.c (str_inspect): mask character for octal output. Mon Aug 31 15:32:41 1998 Yukihiro Matsumoto * regex.c (re_search): use calculated offset if exactn is the first opcode in the compiled regexp. * regex.c (bm_search): use Boyer-Moore search for simple search. * regex.c (must_instr): wrong length check if pattern includes byte escape by 0xff. * regex.c (re_compile_pattern): need not to check current_mbctype. Sat Aug 29 16:31:40 1998 Yukihiro Matsumoto * eval.c (rb_check_safe_str): avoid calling rb_id2name() in normal cases to speed-up. * eval.c (thread_raise): do not save context of terminated thread. * regex.c (re_compile_pattern): mask \nnn over 256. Sat Aug 29 02:09:46 1998 Koji Arai * sprintf.c (f_sprintf): wrong buffer size check. Fri Aug 28 01:57:04 1998 Yukihiro Matsumoto * regex.c (re_compile_pattern): accepts (?ix-ix) and (?ix-ix:...). Fri Aug 28 12:25:33 1998 Hiroshi Igarashi * ruby.c (ruby_require_modules): load modules in appearing order. Fri Aug 28 01:57:04 1998 Yukihiro Matsumoto * regex.c (re_compile_pattern): accepts (?ix-ix) and (?ix-ix:...). Thu Aug 27 12:54:28 1998 Yukihiro Matsumoto * version 1.1c3 released. Wed Aug 26 14:40:56 1998 Yukihiro Matsumoto * eval.c (rb_eval): check whether ruby_class is properly set, before accessing it. * eval.c (rb_obj_instance_eval): ruby_class should be Qnil for special objects like Fixnums. * ext/tkutil/tkutil.c (Init_tkutil): removes calls to rb_yield_0(). used instance_eval() instead in the tk.rb. Wed Aug 26 11:47:00 1998 Yukihiro Matsumoto * regex.c (re_match): pop non-greedy stack elements on success. Wed Aug 26 09:25:35 1998 WATANABE Hirofumi * ruby.h: add #define environ for cygwin32. Tue Aug 25 08:57:41 1998 Yukihiro Matsumoto * array.c (rb_ary_sort_bang): temporarily freeze sorting array. Mon Aug 24 18:46:44 1998 WATANABE Hirofumi * dln.c (dln_find_1): path check was too strict. Mon Aug 24 15:28:11 1998 WATANABE Hirofumi * parse.y (f_arglist): opt_nl added after f_args. Fri Aug 21 01:06:01 1998 Yukihiro Matsumoto * ext/socket/socket.c: grand renaming on socket.c. * ext/socket/socket.c (inet_aton): supply inet_aton for those systems that do not have it. * ext/socket/socket.c (setipaddr): use inet_aton instead of inet_addr. * ext/socket/socket.c (tcp_s_gethostbyname): new method: works like Socket.gethostbyname but returning array contains ip-addrs as octet decimal string format like "127.0.0.1". * ext/socket/socket.c (mkhostent): return format changed to [host, aliases, type, ipaddr..] as documented. Wed Aug 19 00:31:09 1998 Yukihiro Matsumoto * io.c (io_ctl): forgot to place TRAP_END at right position. Fri Aug 14 11:01:47 1998 Yukihiro Matsumoto * eval.c (call_trace_func): save __FILE__, __LINE__ before executing trace_func, since trace function should not corrupt line number information. Thu Aug 13 15:09:02 1998 Yukihiro Matsumoto * array.c (ary_s_new): was marking unallocated region on GC. Tue Aug 11 11:57:35 1998 Yukihiro Matsumoto * version 1.1c2 released. Mon Aug 10 14:05:30 1998 Yukihiro Matsumoto * process.c (f_system): removed fflush(stdin). Fri Aug 7 17:44:44 1998 Yukihiro Matsumoto * error.c (err_snprintf): replace sprintf for fixed sized buffer, with snprintf to avoid buffer over-run. For systems which does dot provide snprintf, missing/snprintf.c added. Wed Aug 5 00:47:35 1998 Yukihiro Matsumoto * re.c (rb_reg_search): recycle match object. Mon Aug 3 09:17:55 1998 Yukihiro Matsumoto * string.c (rb_str_gsub_bang): do not allocate temporary string. * string.c (rb_str_sub_bang): use inline replace. Wed Jul 29 00:36:08 1998 Yukihiro Matsumoto * hash.c (hash_s_new): the default value can be specified. * hash.c (hash_default): method to set the default value. * hash.c (hash_aref): now returns the default value. Tue Jul 28 13:03:25 1998 Yukihiro Matsumoto * array.c (ary_s_new): argument to specify initial value is added. * array.c (ary_s_new): specifies size, not capacity. Mon Jul 27 12:39:34 1998 Yukihiro Matsumoto * string.c (str_replace): zero fill for expansion gap. * regex.c (mbctab_euc): set flags on for 0xA1-0xFE. suggested by . * string.c (str_inspect): consider current_mbctype. Sun Jul 26 15:37:11 1998 Tadayoshi Funaba * array.c (ary_s_new): Array.new(1<<30) dumps core. Fri Jul 24 13:40:19 1998 Yukihiro Matsumoto * version 1.1c1 released. Fri Jul 24 02:10:22 1998 Yukihiro Matsumoto * marshal.c (r_bytes2): allocated buffer size was too short. * marshal.c (w_object): saves all options, not only casefold flag. * re.c (reg_clone): now copies options properly. * re.c (reg_get_kcode): code number was wrong. Thu Jul 23 13:11:32 1998 Yukihiro Matsumoto * eval.c (rb_attr): argument should be symbol or string. Wed Jul 22 11:59:34 1998 Yukihiro Matsumoto * regex.c (calculate_must_string): wrong offset added. Wed Jul 22 11:59:59 1998 Yukihiro Matsumoto * st.c (rehash): still had a GC problem. fixed. Tue Jul 21 13:19:30 1998 Yukihiro Matsumoto * eval.c (gc_mark_threads): crashed on GC before thread allocation. * st.c (rehash): GC during rehash caused SEGV. Tue Jul 21 01:25:10 1998 Yukihiro Matsumoto * sprintf.c (f_sprintf): integer formatter totally re-written. * sprintf.c (remove_sign_bits): support uppercase hexadecimal. Sat Jul 18 00:14:13 1998 Yukihiro Matsumoto * sprintf.c (f_sprintf): proper sign position for %X and %O. Fri Jul 17 14:10:20 1998 Yukihiro Matsumoto * version 1.1c0 released. Fri Jul 17 08:01:49 1998 Tadayoshi Funaba * process.c (f_exec): Check_SafeStr() added. * process.c (f_system): Check_SafeStr() moved before fork(). Thu Jul 16 22:58:48 1998 Yukihiro Matsumoto * string.c (scan_once): substrings to the block should not be tainted. use reg_nth_match(), not str_substr(). * string.c (str_substr): needed to transfer taint. Thu Jul 16 16:15:57 1998 Yukihiro Matsumoto * gc.c (xmalloc): object allocation count added to GC trigger. * eval.c (thread_save_context): avoid marking uninitialized stack in thread_mark. GC may be triggered by REALLOC_N(). Wed Jul 15 15:11:57 1998 Yukihiro Matsumoto * experimental release 1.1b9_31. Wed Jul 15 15:05:27 1998 Yukihiro Matsumoto * eval.c (thread_create): exit() and abort() in threads now forwarded to main_thread. Tue Jul 14 14:03:47 1998 Yukihiro Matsumoto * variable.c (obj_instance_variables): list names that is not instance variables. * gc.c (GC_MALLOC_LIMIT): choose smaller limit value. Mon Jul 13 12:39:38 1998 Yukihiro Matsumoto * object.c (str2cstr): should not return NULL. Fri Jul 10 11:51:46 1998 Yukihiro Matsumoto * parse.y (gettable): needed to add dyna_in_block() check. Thu Jul 9 17:38:23 1998 Yukihiro Matsumoto * experimental release 1.1b9_30. Thu Jul 9 16:01:48 1998 Yukihiro Matsumoto * sprintf.c (fmt_setup): format specifier for long needed. * sprintf.c (f_sprintf): ditto. * numeric.c (fix2str): ditto. * eval.c (thread_create): no more ITIMER_REAL. * eval.c (thread_create): thread finalization needed before aborting thread if thread_abort is set. Wed Jul 8 18:17:33 1998 Yukihiro Matsumoto * bignum.c (big_pow): abandon power by bignum (too big). Tue Jul 7 13:58:43 1998 Yukihiro Matsumoto * eval.c (rb_catch): add C level catch/throw feature. Mon Jul 6 15:18:09 1998 Yukihiro Matsumoto * parse.y (arg): proper return values for `||=' and `&&='. Fri Jul 3 16:05:11 1998 Yukihiro Matsumoto * experimental release 1.1b9_29. Fri Jul 3 11:20:46 1998 Yukihiro Matsumoto * marshal.c (r_byte): byte should not extend sign bit. * numeric.c (fix_mul): use FIX2LONG() instead of FIX2INT() for 64bit architectures. * marshal.c (r_bytes): remove weird casting between pointer and int. * process.c (proc_setsid): new method Process#setsid(). Thu Jul 2 12:49:21 1998 Yukihiro Matsumoto * marshal.c (w_object): remove `write_bignum' label for 64bit architectures. * marshal.c (r_bytes): needs int, not long. Wed Jul 1 14:21:06 1998 Yukihiro Matsumoto * numeric.c (flo_plus): should not allow addition with strings. Wed Jul 1 13:09:01 1998 Keiju ISHITSUKA * numeric.c (num_uminus): wrong coerce direction. Tue Jun 30 10:13:44 1998 Yukihiro Matsumoto * io.c (f_p): accepts arbitrary number of arguments. * eval.c (rb_yield_0): there's some case that iterator_p() returns true even if the_block was not set. check added. Tue Jun 30 01:05:20 1998 Yukihiro Matsumoto * eval.c (BEGIN_CALLARGS): adjust the_block before evaluating the receiver's value and the arguments. Fri Jun 26 18:02:50 1998 Yukihiro Matsumoto * experimental release 1.1b9_28. Fri Jun 26 11:01:26 1998 WATANABE Hirofumi * string.c (str_aset_method): needed to convert to string. Thu Jun 25 02:05:50 1998 Yukihiro Matsumoto * regex.c (re_search): optimize for `.*' at beginning of the pattern. * regex.c (re_search): optimize for character class repeat at beginning of the pattern. * regex.c (re_compile_pattern): detect optimization potential for the compiled patterns. Thu Jun 25 00:02:26 1998 WATANABE Hirofumi * re.c (reg_s_new): flag value was wrong. Wed Jun 24 23:45:06 1998 Yukihiro Matsumoto * regex.c (re_search): wrong anchor handling for reverse search. Wed Jun 24 02:18:57 1998 Yukihiro Matsumoto * parse.y (mlhs): `((a,b)),c = [[1,2]],3' assigns a=1,b=2,c=3. Tue Jun 23 11:46:16 1998 Yukihiro Matsumoto * parse.y (yylex): `&&=' and `||=' added. Sat Jun 20 02:53:50 1998 Yukihiro Matsumoto * parse.y (assignable): nesting local variables should have higher priority than normal local variables for assignment too. Fri Jun 19 18:28:19 1998 Yukihiro Matsumoto * experimental release 1.1b9_27. Fri Jun 19 14:34:49 1998 Yukihiro Matsumoto * eval.c (assign): support hack for nested multiple assignment. * parse.y (mlhs): nested multiple assignment. * eval.c (rb_eval): in-block variables now honors static scope. * configure.in: RSHIFT check moved to configure. Thu Jun 18 16:46:04 1998 Yukihiro Matsumoto * experimental release 1.1b9_26. Thu Jun 18 13:37:19 1998 Yukihiro Matsumoto * file.c (file_s_ftype): uses lstat(2) instead of stat(2). * dir.c (dir_s_glob): there can be buffer overrun, check added. * eval.c (f_binding): handles in-block variables declared after binding's generation. * numeric.c (flo_floor): floor, ceil, round added to Float. Wed Jun 17 11:20:00 1998 Yukihiro Matsumoto * parse.y (gettable): nesting local variables should have higher priority than normal local variables. Tue Jun 16 12:30:46 1998 Yukihiro Matsumoto * bignum.c (str2inum): handles `+ddd'. * struct.c (make_struct): name parameter can be nil for unnamed structures. Mon Jun 15 16:30:10 1998 Yukihiro Matsumoto * object.c (class_s_inherited): prohibiting to make subclass of class Class. * object.c (module_s_new): support for making subclass of Module. * parse.y (yycompile): clear eval_tree before compiling. Fri Jun 12 17:58:18 1998 Yukihiro Matsumoto * eval.c (eval): write back the_dyna_var into the block. Thu Jun 11 18:19:18 1998 Yukihiro Matsumoto * experimental release 1.1b9_25. * eval.c (dvar_add_compiling): register dyna_var at compile time. * regex.c (re_compile_pattern): RE_DUP_MAX iteration is too big. Wed Jun 10 15:12:04 1998 Yukihiro Matsumoto * io.c (io_eof): do not block other threads. * signal.c (trap): reserve SIGALRM for thread. * eval.c (thread_create): use ITIMER_REAL also to avoid system call blocking. * io.c (f_syscall): add TRAP_BEG, TRAP_END around system calls. * io.c (io_ctl): add TRAP_BEG, TRAP_END around system calls. * enum.c (enum_collect): did not collect false values. * array.c (ary_new2): forgot to initialize capa field. Tue Jun 9 18:36:15 1998 WATANABE Hirofumi * string.c (str_split_method): split dumped core for "\xff". Tue Jun 9 16:22:12 1998 Yukihiro Matsumoto * experimental release 1.1b9_24. Tue Jun 9 16:04:07 1998 WATANABE Hirofumi * ext/kconv/kconv.c (kconv_guess): more precise decision for EUC, using jless algorithm (3 sequential EUC hiragana characters). Tue Jun 9 15:12:44 1998 Yukihiro Matsumoto * ext/kconv/kconv.c (kconv_guess): wrong guess for EUC as SJIS in some cases (0xe0 - 0xef). * gc.c (xmalloc): insert size check for big (negative in signed) allocation size. Tue Jun 9 02:54:51 1998 Yukihiro Matsumoto * lib/parsedate.rb: wday moved to the last in the return values. Mon Jun 8 10:40:16 1998 Yukihiro Matsumoto * string.c (str_split_method): split dumped core for "\0". Sat Jun 6 22:50:52 1998 Yukihiro Matsumoto * regex.c (calculate_must_string): wrong condition for {start,stop}_nowidth. * regex.c (re_match): various features imported from GNU regex.c 0.12, such as nested grouping, avoiding infinite loop with empty match, etc. * regex.c (register_info_type): now use union. * regex.c (re_search): more precise anchor(^) check. Wed Jun 3 18:07:54 1998 Yukihiro Matsumoto * re.c (reg_raise): check rb_in_compile, not rb_in_eval. Mon Jun 1 05:26:06 1998 WATANABE Tetsuya * string.c (trnext): casting to signed char* needed. Tue Jun 2 16:00:12 1998 Yukihiro Matsumoto * ext/socket/socket.c (udp_addrsetup): error check enhanced. * ext/socket/socket.c (sock_s_getservbyaname): use strtoul(), if possible. Sat May 30 07:10:02 1998 Yukihiro Matsumoto * re.c (reg_prepare_re): no more needless regular expression recompile on casefold conditions. Thu May 28 18:02:55 1998 Yukihiro Matsumoto * object.c (nil_plus): no more `+' method for nil. Wed May 27 17:33:46 1998 Yukihiro Matsumoto * hash.c (hash_fetch): new method. * regex.c (re_search): check whether translate table is set. Tue May 26 11:39:50 1998 Yukihiro Matsumoto * experimental release 1.1b9_23. * parse.y (yylex): no UPLUS/UMINUS for 1st argument if parenthesises are omitted. Tue May 26 01:09:55 1998 Yukihiro Matsumoto * regex.c (re_compile_pattern): (?XI) for turns off the corresponding option. Mon May 25 12:38:56 1998 Yukihiro Matsumoto * regex.c (re_compile_pattern): inline i option (?i). * regex.c (re_compile_pattern): inline x option (?x). * regex.c (re_compile_pattern): x option for regexp. * dir.c (dir_s_open): returns block's evaluated value. * io.c (f_open): returns block's evaluated value. * ext/curses/curses.c (curses_addstr): nil argument caused SEGV. Fri May 22 11:52:45 1998 Yukihiro Matsumoto * regex.c (re_compile_pattern): push mark on (?:), so that laststart check for {a,b} can be done. Thu May 21 17:31:16 1998 Yukihiro Matsumoto * regex.c (re_match): wrong match (too non-greedy) for `{a,b}?'. * io.c (io_lineno): new method IO#lineno, IO#lineno=. Wed May 20 06:04:43 1998 MAEDA shugo * BeOS patch. Wed May 20 16:32:19 1998 Yukihiro Matsumoto * bignum.c (BIGDN): use RSHIFT(), instead of mere `>>'. Tue May 19 16:36:26 1998 Yukihiro Matsumoto * experimental release 1.1b9_22. Tue May 19 16:31:57 1998 Yukihiro Matsumoto * parse.y (assignable): specification changed for in-block variable definition. * eval.c (dyna_var_asgn): error in in-block variables' compile time definition. * parse.y (str_extend): wrong nesting detection. Tue May 19 09:47:55 1998 WATANABE Hirofumi * numeric.c (num2int): re-defined (extensions may use this). Mon May 18 16:40:50 1998 MAEDA shugo * error.c (get_syserr): BeOS support. * configure.in: modified for BeOS. * string.c (str_dump): do not call isascii(). * sprintf.c (remove_sign_bits): forgot to initialize end pointer. * glob.c: #include added. Mon May 18 14:52:21 1998 Yukihiro Matsumoto * experimental release 1.1b9_21. Mon May 18 03:27:57 1998 MAEDA shugo * file.c (file_s_expand_path): optional second argument `default_directory' added. Sat May 16 22:06:52 1998 WATANABE Hirofumi * error.c (RAISE_ERROR): wrong error message Fri May 15 14:43:25 1998 Yukihiro Matsumoto * experimental release 1.1b9_20. Thu May 14 14:44:21 1998 WATANABE Hirofumi * sun4 cc patches for intern.h and regex.h. Thu May 14 14:03:16 1998 Yukihiro Matsumoto * random.c (RANDOM_MAX): guessing proper maximum value for random numbers. * random.c (f_rand): use drand48 if possible. Wed May 13 19:05:20 1998 MAEDA shugo * BeOS patches for io.c, error.c and config.guess. Wed May 13 14:56:23 1998 Yukihiro Matsumoto * experimental release 1.1b9_19. * most of the Mac and BeOS patches merged, except path separators. * error.c (err_append): generated SyntaxError was String. * ruby.h: xxx2INT, xxx2UINT checks values as int, not long. * ruby.h: remove typedef's. INT, UINT, UCHAR, USHORT. Tue May 12 17:38:00 1998 Yukihiro Matsumoto * experimental release 1.1b9_18. Tue May 12 11:38:08 1998 Yukihiro Matsumoto * error.c (syserr_errno): returns errno of the SystemCallError. * error.c (rb_sys_fail): saves errno in the Exception. * error.c (set_syserr): no need to protect syserr_list. * error.c (rb_sys_fail): no more bufsize limit. * error.c (set_syserr): integer value of errno can be accessed by Errno::EXXX::Errno. Sun May 10 03:10:33 1998 WATANABE Tetsuya * io.c (io_tell etc.): moved from File class to IO class. Fri May 8 12:26:37 1998 Yukihiro Matsumoto * pack.c (pack_unpack): should be unsigned int (was signed int). Thu May 7 16:34:10 1998 Yukihiro Matsumoto * pack.c (pack_pack): `V', `N' uses newly created NUM2UINT(). * ruby.h (NUM2UINT): new macro. * bignum.c (big2uint): try to convert bignum into UINT. * re.c (reg_match): needed to return false for match with nil. * gc.c (obj_free): wrong condition to free string. Wed May 6 21:08:08 1998 WATANABE Hirofumi * ruby.c (ruby_process_options): modified for DJGPP. Wed May 6 15:48:03 1998 Yukihiro Matsumoto * experimental release 1.1b9_17. Wed May 6 01:37:39 1998 Yukihiro Matsumoto * eval.c: remove global variable `errat'. * eval.c (rb_longjmp): embed error position information in the exception object. Sat May 2 12:20:02 1998 Yukihiro Matsumoto * re.c (reg_search): supports reverse search. * string.c (str_index_method): does update $~ etc. * eval.c (f_load): needed to clear the_dyna_vars. * eval.c (dyna_var_asgn): do not push dyna_var, which is id == 0. * error.c (Init_Exception): NotImplementError is no longer StandardError, which is not handled by default rescue. Fri May 1 00:35:51 1998 Yukihiro Matsumoto * ruby.c (proc_options): `-d' turns on verbose flag too. * error.c (exception): last argument may be the superclass of the defining exception(s). * io.c (Init_IO): EOFError is now subclass of the IOError. * io.c (Init_IO): forgot to define IOError. * error.c (Init_Exception): old Exception class renamed to StandardError. Exception now replaces old GlobalExit. * error.c (Init_Exception): Exception is now the root of the Global Exits. There's no longer GlobalExit class. * util.c (ruby_mktemp): check TMP, TMPDIR first. Thu Apr 30 01:08:35 1998 Yukihiro Matsumoto * lib/tk.rb: call 'unknown', if proc not defined. * eval.c (handle_rescue): default rescue handles `Exceptional' not only the instance of the `Exception's. * eval.c (f_raise): exception can be any object. * time.c (time_gm_or_local): call time_gmtime or time_localtime. * eval.c (f_raise): raises TypeError if the class which is not a subclass of String is specified (checked in exc_new()). * error.c (exc_new): need to check whether invalid class (not a subclass of String) is specified. Wed Apr 29 21:05:44 1998 WATANABE Hirofumi * ruby.c (proc_options): option '-e' via tempfile. Tue Apr 28 15:27:58 1998 Yukihiro Matsumoto * experimental release 1.1b9_16. Tue Apr 28 00:07:38 1998 Yukihiro Matsumoto * eval.c (obj_is_proc): type check predicate. * eval.c (obj_is_block): ditto. Mon Apr 27 16:59:17 1998 Yukihiro Matsumoto * ext/gtk/gtk.c (Init_gtk): use timeout, not idle to avoid consuming CPU too much. * lib/tk.rb: use tcltklib#_invoke instead of `_eval'. Mon Apr 27 16:59:17 1998 Yukihiro Matsumoto * array.c (ary_sort): use dup, not clone. Mon Apr 27 13:46:27 1998 Tadahiro Maebashi * ext/tcltklib/tcltklib.c (ip_invoke): invoke tcl command directly. need not worry about escaping tcl characters. Mon Apr 27 12:04:43 1998 Yukihiro Matsumoto * random.c (f_rand): do not call srand() implicitly. Fri Apr 24 14:35:45 1998 Yukihiro Matsumoto * experimental release 1.1b9_15. * parse.y (assignable): dyna_var_asgn actually defines nested local variables in outer context. * random.c (f_rand): call srand(), if it has not called yet. * random.c (f_srand): use tv_usec as the default seed. * eval.c (rb_eval): values of nested local variables should be independent. * eval.c (rb_yield_0): local variables wrong nested conditions. Wed Apr 22 23:27:17 1998 Yukihiro Matsumoto * io.c (select_get_io): get IO object by `to_io'. * io.c (io_to_io): method to retrieve IO object, from delegating object for example. Wed Apr 22 16:52:37 1998 Yukihiro Matsumoto * experimental release 1.1b9_14. * string.c (str_modify): check for embedded pointer reference. * gc.c (obj_free): ditto. * pack.c (pack_pack): p/P template to embed pointers. Wed Apr 22 00:07:10 1998 Tadayoshi Funaba * array.c (ary_rindex): embarrassing typo. Tue Apr 21 12:31:48 1998 Yukihiro Matsumoto * experimental release 1.1b9_13. * configure.in (RUBY_LIB): supports --program-{prefix,suffix}. * array.c (ary_rindex): new method. * io.c (io_binmode): should return self. Tue Apr 21 08:23:04 1998 Tadayoshi Funaba * parse.y (here_document): calling parse_string with wrong arguments. * struct.c (struct_aset): problem member assignment with name. Mon Apr 20 14:47:49 1998 Yukihiro Matsumoto * experimental release 1.1b9_12. * time.c (time_arg): args may be string (support for reduced implicit type conversion). * lib/base64.rb: changed to use pack/unpack with `m' template. Mon Apr 20 06:23:20 1998 Yukihiro Matsumoto * variable.c (mod_remove_const): new method. Sat Apr 18 03:53:27 1998 Yukihiro Matsumoto * hash.c (hash_each_with_index): removed. use Enumerable's each_with_index instead. * class.c (rb_include_module): check for super modules, since module's included modules may be changed. Fri Apr 17 21:50:47 1998 WATANABE Hirofumi * marshal.c (r_long): r_byte() may return signed byte. Fri Apr 17 11:58:30 1998 NAGAI Hidetoshi * ext/tcltklib/tcltklib.c (lib_mainloop): thread and interrupt check. Fri Apr 17 11:06:30 1998 Yukihiro Matsumoto * eval.c (find_file): try to fopen() to check whether file exists. * ruby.c (load_file): ditto. * struct.c (struct_aset): struct member can be set by member name. Fri Apr 17 00:47:19 1998 WATANABE Hirofumi * ext/extmk.rb.in: added m68k-human support * file.c (LOCK_SH): defines moved. * array.c (ary_flatten_bang): simplified loop. Thu Apr 16 16:52:01 1998 Yukihiro Matsumoto * experimental release 1.1b9_11. * lib/tk.rb: thread support (experimental - maybe slow). * eval.c (rb_longjmp): trace event on exception in raising context, just before raising exception. * struct.c (struct_s_members): forgot to check singletons. * struct.c (struct_aref): members can be accessed by names too. * array.c (ary_flatten): new method. * eval.c (rb_longjmp): prints exception information with `-d'. * object.c (any_to_s): remove class name restriction. Thu Apr 16 01:38:02 1998 Yukihiro Matsumoto * file.c (thread_flock): do not block other threads. * eval.c (thread_trap_eval): signals are now delivered to the current thread again. In case that the current thread is dead, signals are forwarded to the main thread. * string.c (str_new4): need not to duplicate frozen strings. Wed Apr 15 08:33:47 1998 Tadayoshi Funaba * struct.c (struct_inspect): remove restriction for struct names. Wed Apr 15 02:55:02 1998 Kazuya 'Sharl' Masuda * x68 patches to config.sub, ext/extmk.rb.in Wed Apr 15 01:22:56 1998 Yukihiro Matsumoto * string.c (str_dup_frozen): do not duplicate frozen strings. * parse.y (yylex): allow nested parenthesises. * io.c (obj_displayln): prints newline after `display'ing the receiver. * io.c (io_puts): avoid generating "\n" each time. use RS_default instead. * io.c (f_p): ditto. Tue Apr 14 22:18:17 1998 Tadayoshi Funaba * struct.c (struct_aref): should not subtract negative index. Tue Apr 14 11:34:50 1998 Yukihiro Matsumoto * experimental release 1.1b9_10. * parse.y: token names prefixed by `t'. * struct.c (struct_s_def): supports subclassing of Struct. * io.c (io_s_new): supports subclassing of IO. Mon Apr 13 11:07:39 1998 Yukihiro Matsumoto * eval.c (f_binding): need to restore method name. * eval.c (rb_call0): raises SystemStackError, not Fatal. * io.c (obj_display): same as `print self'. * io.c (f_p): can now be called in the method form. * re.c (reg_regsub): needed to be mbchar aware. Mon Apr 13 13:18:32 1998 Yukihiro Matsumoto * eval.c (thread_trap_eval): all signals delivered to main_thread. Mon Apr 13 12:47:03 1998 TAKAHASHI Masayoshi * re.c (kcode_set_option): did not set SJIS on SJIS condition. Sun Apr 12 22:14:07 1998 Kazunori NISHI * array.c (ary_uniq_bang): should be `==', not `='. embarrassing. Sat Apr 11 02:13:30 1998 Yukihiro Matsumoto * array.c (ary_subseq): SEGVed for `[][1,1]'. Fri Apr 10 21:29:06 1998 Tadayoshi Funaba * array.c (ary_subseq): add check for beg larger than array length. Wed Apr 8 17:24:11 1998 MAEDA shugo * dir.c (dir_s_open): can be called with block (like IO#open). * dir.c (dir_s_chdir): print directory path on error. * dir.c (dir_s_chroot): ditto * dir.c (Init_Dir): needed to override `new'. Thu Apr 9 18:24:58 1998 Yukihiro Matsumoto * experimental release 1.1b9_09. * string.c (str_cmp): do not depend on sentinel at the end of the strings. * string.c (str_chomp_bang): forgot to set the sentinel. Wed Apr 8 00:59:13 1998 Yukihiro Matsumoto * bignum.c (big2int): converted int may be too big to fit in signed int. * parse.y (arg): `foo += 1' should not cause an error. * variable.c (rb_const_defined): returned false even if the constant is defined at the top level. * eval.c (f_local_variables): dyna_var->id may be null. should have checked before calling str_new2(). Tue Apr 7 01:15:15 1998 Kaneko Naoshi * re.c (reg_regsub): need to check string boundary. Tue Apr 7 19:19:12 1998 Yukihiro Matsumoto * string.c (str_cmp): returns either 1, 0, -1. * array.c (ary_cmp): should check array length, too Tue Apr 7 18:50:16 1998 Yukihiro Matsumoto * experimental release 1.1b9_08. Tue Apr 7 18:31:27 1998 WATANABE Hirofumi * instruby.rb (mandir): dll installation for cygwin32 Tue Apr 7 01:16:45 1998 Yukihiro Matsumoto * config.sub (maybe_os): TOWNS support? * config.guess: too strict check for libc versions on linuxes. * experimental release 1.1b9_07. * array.c (ary_cmp): compare each element using `<=>'. * hash.c (hash_each_with_index): yields [value, key] pair. * class.c (class_protected_instance_methods): list protected method names. * class.c (ins_methods_i): exclude protected methods. * eval.c (PUSH_BLOCK): dynamic variables can be accessed from eval() with bindings. Mon Apr 6 14:49:06 1998 Yukihiro Matsumoto * eval.c (thread_yield): must return evaluated value. Fri Apr 3 13:07:29 1998 Yukihiro Matsumoto * eval.c (thread_schedule): context switch bypassed on wrong conditions. * variable.c (rb_name_class): set classname by id before String class is initialized (1.0 behavior restored). Fri Apr 3 11:25:45 1998 Yukihiro Matsumoto * numeric.c (num2int): no implicit conversion from string. * numeric.c (num2int): check whether `to_i' returns an Integer. * numeric.c (num_zero_p): new method. * numeric.c (num_nonzero_p): new method. returns the receiver if it's not zero. * eval.c (obj_instance_eval): the_class should be the object's singleton class. * error.c (exc_s_new): message is converted into a string. Thu Apr 2 18:31:46 1998 Yukihiro Matsumoto * eval.c (obj_call_init): every object call `initialize'. Wed Apr 1 08:51:53 1998 Tadayoshi Funaba * parse.y (stmt): UNTIL_MOD should be for stmt, not only for expr. Wed Apr 1 01:20:31 1998 Yukihiro Matsumoto * object.c (true_and): boolean operators &, | and ^. Tue Mar 31 13:23:58 1998 Yukihiro Matsumoto * array.c (ary_compact_bang): returns nil, if it does not modify the array like String's bang methods. * array.c (ary_uniq_bang): new method to remove duplicate items. * eval.c (bind_s_new): new method. * numeric.c (num2int): raise exception if Fixnums too big to convert into `int' in case that sizeof(int) < sizeof(INT). * string.c (str_center): SEGV on negative width. * eval.c (eval): forgot to set sourcefile. Mon Mar 30 11:12:29 1998 Yukihiro Matsumoto * file.c (f_test): raises exception for unknown command. * eval.c (Init_eval): `class_eval': alias to the module_eval. Mon Mar 30 18:50:42 1998 Tadayoshi Funaba * string.c (str_capitalize_bang): did not check string modification. * string.c (str_delete_bang): wrong conversion. * string.c (str_intern): typo in error message. Mon Mar 30 01:44:13 1998 Yukihiro Matsumoto * eval.c (obj_instance_eval): accepts block as evaluation body. No compilation needed each time. * eval.c (mod_module_eval): ditto * file.c (file_s_umask): umask did not return old values, if no argument given. Sun Mar 29 00:54:23 1998 Yukihiro Matsumoto * eval.c (f_throw): nil returned always. Sat Mar 28 20:40:12 1998 Yukihiro Matsumoto * experimental release 1.1b9_06. Sat Mar 28 16:07:11 1998 WATANABE Hirofumi * io.c (io_closed): should not cause exception for closed IO. * string.c (str_tr): returned nil for success. Sat Mar 28 00:47:19 1998 Yukihiro Matsumoto * eval.c (f_local_variables): new method to return an array of local variable names. * variable.c (obj_instance_variables): now returns an array of variable names, as described in the reference. * eval.c (rb_attr): honors default method visibility of the current scope. Fri Mar 27 13:49:27 1998 Yukihiro Matsumoto * experimental release 1.1b9_05. * ruby.c (ruby_prog_init): `site_ruby' added to load_path. * ruby.c (ruby_prog_init): load-path order changed. Paths in the RUBYLIB environment variable comes first in non-tainted mode. Thu Mar 26 11:51:09 1998 Yukihiro Matsumoto * eval.c (rb_call): new feature: `protected' methods. * string.c (str_dump): new method. * eval.c (block_pass): block argument can be nil, which means no block is supplied for the method. Wed Mar 25 21:20:13 1998 Tadayoshi Funaba * string.c (str_reverse_bang): string copied to wrong place. Wed Mar 25 08:12:07 1998 Yukihiro Matsumoto * numeric.c (flo_modulo): caused SEGV if left operand is not a float value. * eval.c (f_eval): optional third and fourth argument to specify file-name and line-number. * eval.c (eval): file-name and line-number set properly. * parse.y (assign_in_cond): literal assignment is now warning, not compile error. * error.c (Warn): Warn() always print message, OTOH Waring() prints when verbose flag is set. Tue Mar 24 12:50:06 1998 Yukihiro Matsumoto * ruby.c (ruby_prog_init): `.' should come last in the load-path. * eval.c (Init_eval): `__send__', alias for `send'. Mon Mar 23 12:44:12 1998 Yukihiro Matsumoto * string.c (str_chomp_bang): now takes `rs' as an argument. * eval.c (thread_free): main_thread should not be freed. Fri Mar 20 16:40:34 1998 Yukihiro Matsumoto * string.c (str_chomp_bang): chomp! (and other ! methods) returns nil if it does not modify the string. * string.c (str_sub_iter_s): should check last pattern since it may be matched to null. Thu Mar 19 13:48:55 1998 Yukihiro Matsumoto * experimental release 1.1b9_04. * parse.y (yylex): `10e0.9' should cause syntax error. Wed Mar 18 17:46:31 1998 Yukihiro Matsumoto * ruby.c (load_file): new file object constant DATA. Only available for the script from the file. * regex.c (re_match): forwarding failure point popped too much. Tue Mar 17 18:23:06 1998 Yukihiro Matsumoto * math.c (math_frexp): newly added. * math.c (math_ldexp): ditto. * bignum.c (bigdivmod): calculates modulo. * numeric.c (fix_remainder): returns reminder, formerly introduced as modulo. * numeric.c (fix_modulo): calculates proper `modulo'. * bignum.c (bigdivmod): wrong sign for reminder. Mon Mar 16 17:07:28 1998 Yukihiro Matsumoto * experimental release 1.1b9_03. Mon Mar 16 16:33:53 1998 WATANABE Hirofumi * io.c (pipe_finalize): needed to add pipe_finalize to pipes on cygwin32. Mon Mar 16 14:11:06 1998 Yukihiro Matsumoto * class.c (ins_methods_i): needed to consider NOEX_UNDEF. Mon Mar 16 13:23:53 1998 WATANABE Hirofumi * io.c (io_check_closed): check for `fptr->f2 == NULL'. * io.c (io_fptr_close): ditto. Mon Mar 16 11:49:25 1998 Yukihiro Matsumoto * io.c (pipe_atexit): free()ing referencing pipe_list. * range.c (range_length): returns zero, if the first is greater than the last. * signal.c (trap_restore_mask): restore signal mask before raising exceptions and throws. Fri Mar 13 13:49:24 1998 Yukihiro Matsumoto * experimental release 1.1b9_02. * object.c (mod_clone): need to dups constants and instance variables. * eval.c (rb_eval): forgot to initialize body for NODE_DEFS. * eval.c (rb_eval): retrieve self from calling frame, since self changes sometimes. * env.h (FRAME): need to save self in the calling frame. * io.c (f_gets_method): rs should be initialized by RS. Thu Mar 12 15:33:57 1998 Yukihiro Matsumoto * experimental release 1.1b9_01. * range.c (range_s_new): check values by `first <= last'. * parse.y (lastline_set): fixed offset for $_ and $~ in the local variable space. Wed Mar 11 02:14:17 1998 Yukihiro Matsumoto * io.c (io_gets): handle normal case specially for speed. * eval.c (rb_disable_super): function to disable superclass's method explicitly. * eval.c (rb_eval): inherits previous method definition's NOEX_UNDEF-ness, if exists. * class.c (rb_define_method): disables superclass's overriding method by default. Wed Mar 11 01:40:48 1998 MAEDA shugo * numeric.c (flo_gt,etc.): do not depend on `<=>', to handle NaN. Tue Mar 10 00:03:24 1998 Yukihiro Matsumoto * ruby.c (load_file): understands multiple options in #! line. * regex.c (re_compile_pattern): support for [:alpha:] etc. Mon Mar 9 16:53:51 1998 Yukihiro Matsumoto * io.h (GetOpenFile): embed io_check_closed in GetOpenFile. * sprintf.c (f_sprintf): zero padding failed for negative integers. * sprintf.c (remove_sign_bits): failed to remove some bits. Sat Mar 7 21:51:46 1998 MAEDA shugo * class.c (ins_methods_i): body may be NULL for some case. Fri Mar 6 17:23:07 1998 Yukihiro Matsumoto * regex.c (mbcinit): table driven mbchar detection. * object.c (obj_alloc): check for allocating instance for the primitive classes (mostly perfect). * ext/curses/curses.c (curses_finalize): restore original state at interpreter termination. * ext/curses/curses.c (curses_addstr): forgot to check argument type (caused SEGV). now uses STR2CSTR() macro. Thu Mar 5 13:47:39 1998 Yukihiro Matsumoto * eval.c (block_pass): accepts method object as block args. * eval.c (f_missing): use any_to_s() for stringify. Wed Mar 4 01:39:52 1998 Yukihiro Matsumoto * parse.y (block_arg): new syntax - block argument in the calling arglist. * eval.c (rb_call): no module search. simplified a lot. * eval.c (rb_eval): block arg support. * parse.y (f_block_arg): new syntax - block argument in the formal arglist. Tue Mar 3 14:20:15 1998 Yukihiro Matsumoto * eval.c (obj_method): returns bound method object. * eval.c (rb_call): argument check for empty methods. * ruby.h (NUM2CHR): new macro, originally from curses module. Tue Mar 3 13:03:35 1998 MAEDA shugo * io.c (io_putc): new method. Tue Mar 3 11:21:28 1998 Yukihiro Matsumoto * string.c (str_inspect): more strict charcode detection. * eval.c (thread_stop): stopping only thread raises ThreadError exception. Tue Mar 3 08:04:56 1998 Tadayoshi Funaba * struct.c (struct_alloc): incomplete struct initialization made GC to access unallocated addresses. Mon Mar 2 16:28:27 1998 Yukihiro Matsumoto * eval.c (thread_stop_method): remove Thread#stop. Fri Feb 27 18:16:26 1998 Yukihiro Matsumoto * version 1.1b9 released. Fri Feb 27 09:36:35 1998 Yukihiro Matsumoto * hash.c (hash_delete_nil): needed to compare value to nil, since nil is the valid key for hashes. * hash.c (hash_foreach_iter): rehashing causes IndexError. * hash.c (hash_foreach_iter): rehash check by pointer comparison. Thu Feb 26 17:22:13 1998 Yukihiro Matsumoto * parse.y (fname): convert reswords into symbols. * parse.y (reswords): reserved words are now embedded in the syntax (sigh). * parse.y: now reserved words can be method names safely. Wed Feb 25 15:50:07 1998 Yukihiro Matsumoto * eval.c (mod_module_eval): clear the_scope's PRIVATE flag before calling eval(). * gc.c (gc_call_finalizer_at_exit): run finalizers before any data object being freed. * eval.c (rb_eval): needed to keep prot_tag->retval before evaluating the ensure clause. Tue Feb 24 11:16:32 1998 Yukihiro Matsumoto * parse.y (yylex): reserved words can be appear as method names at right after 'def' and `.'(dot), like foo.next. * eval.c (return_check): checks for return out of thread (formerly done in return_value). * eval.c (POP_TAG): copy retval to outer level. * eval.c (return_value): just set retval, no check, no unwinding. * parse.y (nextc): line continuation by backslash at end of line. * regex.c (re_compile_pattern): forgot to clear pending_exact on closing parentheses. * parse.y (assignable): should not assign dyna_var to true, if it is already defined. Mon Feb 23 14:35:03 1998 Yukihiro Matsumoto * object.c (obj_is_kind_of): no longer accepts true/false/nil. * object.c ({true,false,nil}_to_i): can be converted into integers. Mon Feb 23 12:11:51 1998 Yukihiro Matsumoto * re.c (reg_s_quote): needed to be mbchar aware. * eval.c (proc_s_new): wrong iter mark. Sat Feb 21 22:59:30 1998 MAEDA shugo * io.c (f_syscall): no argument check. Fri Feb 20 10:17:51 1998 Yukihiro Matsumoto * version 1.1b8 released. * ext/kconv/kconv.c (kconv_kconv): default output code now be determined according to the value of $KCODE. * re.c (rb_get_kcode): can retrieve $KCODE from C code. * parse.y (stmt): if/unless modifiers returns nil, if condition is not established. Thu Feb 19 11:06:47 1998 Yukihiro Matsumoto * ext/kconv/kconv.c (kconv_kconv): charcode can be specified by code name (JIS, SJIS, EUC like value of $KCODE). * regex.c (re_compile_pattern): forgot to fixup_jump for (?:..). * regex.c (re_compile_pattern): needed to clear pending_exact on non-registering grouping (?:...). Wed Feb 18 19:54:21 1998 Yukihiro Matsumoto * parse.y (here_document): needed to set lex_state to EXPR_END. Wed Feb 18 18:45:10 1998 WATANABE Hirofumi * patches for cygwin32 applied. Wed Feb 18 00:41:31 1998 Yukihiro Matsumoto * string.c (str_sub_s): needed to be mbchar aware to increment one character. * regex.c (re_match): \Z matches newline just before the end of the string. Tue Feb 17 00:04:32 1998 Yukihiro Matsumoto * time.c (time_arg): Time.gm and Time.local now understands Time#to_a format. * string.c (str_sub_s): replace happened twice for null pattern. * regex.c (re_search): null pattern should not match after newline at the end of string. * time.c (time_isdst): now returns boolean value. * error.c (rb_check_type): treat special constants in messages. * parse.y (yylex): new form `::Const' to see toplevel constants. * parse.y (cond): SEGV on `if ()'. * gc.c (obj_free): some data needed explicit free(). Mon Feb 16 23:55:40 1998 Yukihiro Matsumoto * eval.c (blk_free): release duplicated block informations. * eval.c (blk_copy_prev): duplicate outer block information into the heap, when proc/binding created. Mon Feb 16 14:38:25 1998 Yukihiro Matsumoto * time.c (time_mon): now 1 for January and so on. * time.c (time_year): year in 19xx (no + 1900 needed anymore). Mon Feb 16 13:28:33 1998 Yukihiro Matsumoto * regex.c (re_compile_pattern): need to fetch mbchar's second byte without translation. Mon Feb 16 12:29:27 1998 MAEDA shugo * eval.c (f_pass_block): pass iterator block to other method. Fri Feb 13 08:16:11 1998 Yukihiro Matsumoto * parse.y (parse_regx): handle \s before read_escape(). * parse.y (read_escape): `\s' in strings as space. Tue Feb 10 17:29:08 1998 Yukihiro Matsumoto * version 1.1b7 released. * string.c (str_aset): string insertion by `str[n] = str2'. * string.c (str_oct): does recognize `0x'. * sprintf.c (f_sprintf): use base 10 for conversion from string to integer. Mon Feb 9 14:51:56 1998 Yukihiro Matsumoto * numeric.c (do_coerce): proper error message. * string.c (str_sum): bug - masked by wrong value. (sigh..) Sat Feb 7 15:11:14 1998 Yukihiro Matsumoto * string.c (str_empty): new method Fri Feb 6 01:42:15 1998 Yukihiro Matsumoto * time.c (time_asctime): use asctime(3), not strftime(3). Thu Feb 5 18:58:46 1998 Yukihiro Matsumoto * io.c (io_fptr_close): do not free path on close(). * array.c (ary_filter): new method. * enum.c (enum_each_with_index): new method. Thu Feb 5 14:10:35 1998 Yukihiro Matsumoto * parse.y (primary): singleton class def can be appeared inside method bodies. * hash.c (hash_replace): replace content. * string.c (str_replace_method): replace content. * array.c (ary_replace_method): replace elements. * string.c (str_succ_bang): String#succ! Thu Feb 5 18:20:30 1998 WATANABE Hirofumi * string.c (str_upcase_bang): multi byte character support. Wed Feb 4 13:55:26 1998 Yukihiro Matsumoto * array.c (ary_reverse): SEGV on empty array reverse. Tue Feb 3 12:24:07 1998 Yukihiro Matsumoto * re.c (match_to_a): non matching element should be nil. * ruby.c (ruby_load_script): load script after all initialization. * bignum.c (str2inum): need to interpret prefix `0' of `0x'. Tue Feb 3 10:00:18 1998 WATANABE Hirofumi * numeric.c (fix_rshift): use `sizeof(INT)*8' instead of 32. Mon Feb 2 14:09:24 1998 Yukihiro Matsumoto * ruby.c (set_arg0): grab environment region too. Thu Jan 29 18:36:25 1998 WATANABE Hirofumi * process.c (rb_proc_exec): check `sh' to be exist. Thu Jan 29 18:18:19 1998 Yukihiro Matsumoto * io.c (io_stdio_set): assignment to $stdin or $stdout does reopen() as well as $stderr. Thu Jan 29 14:18:40 1998 Yukihiro Matsumoto * class.c (mod_ancestors): should not include singleton classes. * object.c (obj_type): should not return internal class. * io.c (io_reopen): unwillingly closes stdio streams. Thu Jan 29 11:50:35 1998 Toshihiko SHIMOKAWA * ext/socket/socket.c (udp_addrsetup): forgot to use htons(). Tue Jan 27 23:15:24 1998 Yukihiro Matsumoto * keywords: __FILE__, __LINE__ are available again. Fri Jan 23 14:19:28 1998 Yukihiro Matsumoto * version 1.1b6 released. * object.c (mod_to_s): need to duplicate classpath. * error.c (exc_inspect): need to duplicate classpath. Thu Jan 22 00:37:47 1998 Yukihiro Matsumoto * ruby.h (STR2CSTR): new macro to retrieve char*. * class.c (rb_define_method): `initialize' should always be private, even if it defined by C extensions. * eval.c (rb_eval): `initialize' should always be private. Thu Jan 22 16:21:08 1998 Yukihiro Matsumoto * eval.c (rb_eval): some singleton class def cause SEGV. * eval.c (TMP_ALLOC): replace ALLOCA_N, where thread context switch may happen. Wed Jan 21 01:43:42 1998 Yukihiro Matsumoto * eval.c (PUSH_FRAME): do not use ALLOCA_N(). crash on some platforms that use missing/alloca.c. * regex.c (re_compile_pattern): too many pops for non register subexpr. * parse.y (yylex): open parentheses after identifiers are argument list, even if whitespaces have seen. Tue Jan 20 15:19:59 1998 Yukihiro Matsumoto * parse.y (terms): quoted word list by %w(a b c). * ext/tcltklib/extconf.rb: more accurate check for tcl/tk libs. * file.c (rb_stat): most of the FileTest methods (and function `test') accept File objects as the argument. Tue Jan 19 18:19:24 1998 WATANABE Hirofumi * ext/extmk.rb.in (install): there should be no newline after install: * re.c (MIN): renamed from min(). there's a local variable named min in the file, so that some cpp will raise an error. Mon Jan 19 16:30:05 1998 Yukihiro Matsumoto * version 1.1b5 released. * process.c (rb_syswait): no exception raised. Fri Jan 16 00:43:43 1998 Yukihiro Matsumoto * ruby.h (CLONESETUP): copies its singleton classes too. * class.c (singleton_class_attached): saves binded object in the singleton classes. * eval.c (rb_eval): calls singleton_method_added even in the singleton class clauses. Fri Jan 15 23:22:43 1998 WATANABE Hirofumi * ruby.c (proc_options): -S does not recognize PATH. Thu Jan 15 02:03:12 1998 Yukihiro Matsumoto * eval.c (rb_clear_cache_by_id): clear only affected cache entries. Wed Jan 14 02:14:48 1998 Yukihiro Matsumoto * ext/socket/socket.c: new UDP/IP socket classes. Tue Jan 13 10:00:18 1998 Yukihiro Matsumoto * string.c (str_cmp): ignorecase($=) works wrong. Fri Jan 9 13:19:55 1998 Yukihiro Matsumoto * version 1.1b4 released. * eval.c (f_missing): class name omitted from the error message. * error.c (exc_inspect): description changed. * string.c (Init_String): GlobalExit's superclass did not filled, since GlobalExit created earlier than String. Thu Jan 8 12:10:09 1998 Yukihiro Matsumoto * parse.y (aryset): expr in the brackets can be null. Wed Jan 7 21:13:56 1998 Yukihiro Matsumoto * io.c (io_reopen): keep stderr unclosed. * io.c (io_errset): keep stderr unclosed. Tue Jan 6 00:27:43 1998 Yukihiro Matsumoto * parse.y: syntax modified for `while expr do .. end' etc. * process.c (f_exec,f_system): can supply arbitrary name for the new process. Mon Jan 5 16:59:13 1998 WATANABE Hirofumi * file.c (file_s_basename): removes any extension by ".*". Sun Jan 4 19:36:22 1998 WATANABE Hirofumi * parse.y (yylex): needed to update lex_p (reading point). Sat Jan 3 19:14:14 1998 WATANABE Hirofumi * class.c,object.c: duplicate defines mKernel and cFinxnum. Fri Jan 2 20:38:59 1998 Yukihiro Matsumoto * ext/curses/curses.c (NUM2CHAR): uses the first character for string arguments. * array.c (ary_fill): did not extend array for ranges. * array.c (beg_len): did not return end pos bigger than size. Fri Jan 2 02:09:16 1998 WATANABE Hirofumi * dir.c (dir_s_chdir): bug in nil check. * array.c (ary_fill): bug in nil check. Tue Dec 30 11:46:23 1997 Yukihiro Matsumoto * hash.c (env_path_tainted): checks directories in PATH environment variable are not world writable. * ruby.c (load_file): invoke specified interpreter if the #! line does not contain the word `ruby'. Fri Dec 26 03:26:41 1997 Yukihiro Matsumoto * string.c (uscore_get): type information included in the error message. * variable.c (f_untrace_var): does not free trace-data within trace procedure. Thu Dec 25 02:50:29 1997 Yukihiro Matsumoto * version 1.1b3 released. * ruby.h: inlining some functions on gcc 2.x Tue Dec 23 02:47:33 1997 Yukihiro Matsumoto * eval.c (rb_eval): public/private information kept in the current scope, to remove undesired state from the class/module. * time.c (time_strftime): remove hidden limit of 100 bytes of result string, using malloc'ed buffer. * hash.c (hash_update): merges the contents of another hash, overriding existing keys. * regex.c (must_instr): totally re-written. * io.c (read_all): try to allocate proper sized buffer using fstat(2) for speedup. Sat Dec 20 00:27:28 1997 Yukihiro Matsumoto * regex.c (must_instr): need to skip 2 bytes for mbchars. Fri Dec 19 01:18:29 1997 Yukihiro Matsumoto * version 1.1b2 released. * eval.c (check_errat): check and convert (if necessary) traceback information before assigning to the variable $@. * eval.c (f_raise): optional third argument to specify traceback information. * io.c (f_open): prevent infinite recursive call. Thu Dec 18 19:33:47 1997 Yukihiro Matsumoto * string.c (str_rindex): now accepts regexp as index. Thu Dec 18 18:42:50 1997 WATANABE Hirofumi * ext/socket/extconf.rb: modified to detect win32 socket lib. Thu Dec 18 00:25:03 1997 Yukihiro Matsumoto * re.c (reg_equal): checks for source and casefold and kcode matching. * marshal.c: became built-in module. * ext/marshal/marshal.c (r_object): displays struct name for non-compatible struct. * string.c (str_index_method): now searches character (fixnum) in the string. * string.c (str_include): redefine `include?'. * regex.c (re_match): start_nowidth saves current stack position to stop_nowidth. * regex.c (re_compile_pattern): add space to stop_nowidth to save runtime stack position. Tue Dec 16 14:57:43 1997 Yukihiro Matsumoto * string.c (scan_once): wrong exception for regexp that match with null string (use substr instead of subseq). Sat Dec 13 00:13:32 1997 Yukihiro Matsumoto * parse.y (expr): remove bare assocs from expr rule. * rbconfig.rb: renamed from config.rb (it was too generic name). Fri Dec 12 00:50:25 1997 Yukihiro Matsumoto * parse.y (expr): warns if BEGIN or END appear in the method bodies. * string.c (str_match): calls y =~ x if y is neither String nor Regexp so that eregex.rb works. * eval.c (f_at_exit): to register end proc. * class.c (rb_define_module_function): define 'function' method for the Module, not private method. * class.c (rb_define_function): function to define `function' method. * eval.c (rb_eval): inherit visibility from superclass's method except when it is set to `function' * eval.c (rb_eval): new visibility status `function'. * parse.y (yycompile): do not clear eval_tree. thus enable multiple command line script by option `-e'. * eval.c (rb_eval): END execute just once. * parse.y (expr): BEGIN/END built in the syntax. Thu Dec 11 13:14:35 1997 Yukihiro Matsumoto * object.c (mod_le): Module (or Class) comparison. * eval.c (rb_remove_method): raises NameError if named method does not exist. * ext/curses/curses.c: remove CHECK macro for BSD curses. Thu Dec 11 12:44:01 1997 WATANABE Hirofumi * pack.c: sun4 cc patch Wed Dec 10 15:21:36 1997 Yukihiro Matsumoto * ext/marshal/marshal.c (marshal_load): can supply evolution proc object as optional second argument. * re.c (reg_source): get source string of the regular expression. Tue Dec 9 10:05:17 1997 Yukihiro Matsumoto * version 1.1b1 released. * parse.y (tokadd): token buffer overrun. * ruby.c (ruby_prog_init): forgot to protect rb_argv0 from gc. * eval.c (ruby_run): call finalizers at process termination. * gc.c (gc_call_finalizer_at_exit): call free proc for every Data Wrapper, and finalizer for specified objects at termination. * version.c (show_version): version format changed. * regex.c (re_match): wrong match with non-greedy if they appear more than once in regular expressions. * sample/ruby-mode.el (ruby-expr-beg): forgot to handle modifiers. Mon Dec 8 19:00:15 1997 Yukihiro Matsumoto * io.c (io_puts): just put a newline if no argument given. * ext/tcltklib/tcltklib.c (lib_mainloop): thread-aware tk handle when $tk_thread_safe is set. * ext/tcltklib/tcltklib.c (lib_mainloop): use Tcl_DoOneEvent() instead of Tk_MainLoop(). Mon Dec 6 07:11:16 1997 MAEDA shugo * io.c (io_puts): core dumped without any argument. Fri Dec 5 18:17:17 1997 Yukihiro Matsumoto * eval.c (mod_remove_method): remove (not undef) a method from the class/module. * variable.c (obj_remove_instance_variable): method to remove instance variables. Thu Dec 4 13:50:29 1997 Yukihiro Matsumoto * version 1.1b0 released. * string.c (str_aref): called str_index for regexp. Mon Dec 1 15:24:41 1997 Yukihiro Matsumoto * compar.c (cmp_between): wrong comparison made. Wed Nov 26 18:18:05 1997 Yukihiro Matsumoto * lib/mkmf.rb: generate Makefile for extension modules out of ruby source tree. use like `ruby -r mkmf extconf.rb'. * numeric.c (fix2str): enlarge buffer to prevent overflow on some machines. * parse.y (here_document): wrong line number generated after here-doc. Fri Nov 21 13:17:12 1997 Yukihiro Matsumoto * parse.y (yylex): skip multibyte characters in comments. Wed Nov 19 17:19:20 1997 Yukihiro Matsumoto * object.c (nil_to_a): nil.to_a => []. * parse.y (call_args): wrong node generation. Tue Nov 18 10:13:08 1997 Yukihiro Matsumoto * array.c (Init_Array): Array#=== works as Array#include? * regex.c (re_compile_pattern): insert initialize code for jump_n, before entering loops. * re.c (reg_search): does not save registers unless $& etc appear in the script. Mon Nov 17 13:01:43 1997 Yukihiro Matsumoto * eval.c (is_defined): add defined? check for receivers and arguments for calls. * re.c (reg_search): cache last match object. * re.c (match_aref): $[0] etc. are available. Sat Nov 15 00:11:36 1997 WATANABE Hirofumi * io.c (io_s_popen): "rb" detection Fri Nov 14 18:28:40 1997 Yukihiro Matsumoto * string.c (scan_once): returns whole match if the pattern does not contain any parentheses. Thu Nov 13 14:39:06 1997 Yukihiro Matsumoto * string.c (str_sub): returns copy of the receiver string, even if any substitution occurred. * regex.c (re_compile_pattern): no-width match by (?=..), (?!..). Wed Nov 12 13:44:47 1997 Yukihiro Matsumoto * time.c: remove coerce from Time class. * regex.c (re_match): non-greedy match by ??, *? +?, {n,m}?. Mon Nov 10 11:24:51 1997 Yukihiro Matsumoto * regex.c (re_compile_pattern): non-registering parens (?:..). * regex.c (re_compile_pattern): new meta character \< (wordbeg) and \> (wordend). * regex.c (re_compile_pattern): embedded comment for regular expression by (?#...). Fri Nov 7 16:58:24 1997 Yukihiro Matsumoto * regex.c (re_compile_pattern): perl5 regexp \A and \Z available. * regex.c (re_compile_pattern): can expand compile stack dynamically. * regex.c (PUSH_FAILURE_POINT): wrong compare condition. Wed Nov 2 16:00:00 1997 WATANABE Hirofumi * string.c (str_sub_s): "".sub! "", "" => "\000" Fri Oct 31 15:52:10 1997 Yukihiro Matsumoto * parse.y (assoc): keyword assoc like {fg->"black"}. Thu Oct 30 17:33:38 1997 Yukihiro Matsumoto * io.c (io_println): print with newline, which is not affected by the values of $/ and $\. Thu Oct 30 16:54:01 1997 WATANABE Hirofumi * string.c (str_chop_bang): "".chop caused SEGV. * string.c (str_chomp_bang): method to chop out last newline. Mon Oct 27 13:49:13 1997 Yukihiro Matsumoto * ext/extmk.rb.in: library may have pathname contains `.' * eval.c (rb_rescue): should not protect SystemError. Fri Oct 24 10:58:53 1997 Yukihiro Matsumoto * io.c (io_s_with_open_stream): ensures to close stream. Thu Oct 23 11:17:44 1997 Yukihiro Matsumoto * io.c (io_errset): value of $stderr can be changed (to any IO object). * io.c (next_argv): $< can be anything that responds to `write'. * file.c (file_s_with_open_file): ensures to close file. * error.c (exception): create error under the current class/module. * range.c (range_eqq): fixnum check for last needed too. Wed Oct 22 12:52:30 1997 Yukihiro Matsumoto * ext/socket/socket.c: Socket::Constants added. * file.c: File::Constants added for inclusion. * array.c (ary_join): call ary_join() recursively for the 1st array element. Mon Oct 20 12:18:29 1997 WATANABE Hirofumi * ruby.c (load_file): wrong condition for #! check with -x. * file.c (file_s_dirname): did return "" for "/a". Fri Oct 17 14:29:09 1997 Yukihiro Matsumoto * ruby.c: now works on alpha-linux. * bignum.c (bigadd): some undefined side effect order assumed. Wed Oct 15 17:49:24 1997 Yukihiro Matsumoto * intern.h: function prototypes added. Mon Oct 13 16:54:18 1997 Yukihiro Matsumoto * class.c (rb_define_class_id): call superclass's `inherited' method when making subclasses. * parse.y (nextc): clear lex_lastline at the end of file. * object.c (Init_Object): need to undef Class#append_features. * eval.c (rb_eval): no warning on extending classes or modules. Thu Oct 9 11:17:50 1997 Yukihiro Matsumoto * eval.c (error_print): the exception name follows after the error message. * eval.c (compile_error): error message slightly changed. * parse.y (nextc): script parsing will be terminated by __END__ at beginning of line. * eval.c (compile_error): `__END__' is no longer a keyword. * parse.y (nextc): protect lastline read from script stream. Tue Oct 7 14:06:06 1997 Yukihiro Matsumoto * version 1.1 alpha9 released. * eval.c (mod_append_features): renamed from extend_class. * eval.c (rb_eval): defining method calls `method_added'. * eval.c (ruby_options): exception while processing options must terminate the interpreter. * error.c (Init_Exception): wrong method configuration. `new' should have been a singleton method. Mon Oct 6 18:55:38 1997 Yukihiro Matsumoto * ext/kconv/kconv.c (kconv_guess): code to guess character code from string. Mon Oct 6 18:38:17 1997 WATANABE Hirofumi * pack.c: now encode/decode base64 by `m' template. Fri Oct 3 10:51:10 1997 Yukihiro Matsumoto * MANIFEST: needed to include lex.c in the distribution. * eval.c (ruby_options): f_require() called too early. * eval.c (rb_provide): module extensions should always be `.o'. Thu Oct 2 11:38:31 1997 Yukihiro Matsumoto * version 1.1 alpha8 released. * ext/marshal/marshal.c (r_object): remove temporal regist for structs. (caused problem if structs form cycles.) * parse.y (match_gen): static binding for match(=~) calls with regexp literals. Wed Oct 1 15:26:55 1997 Yukihiro Matsumoto * eval.c: protect retval in struct tag from GC for C_ALLOCA. * eval.c: no more pointer value from setjmp/longjmp. Wed Oct 1 14:01:49 1997 WATANABE Hirofumi * ext/marshal/marshal.c (w_byte): argument must be char. Wed Oct 1 10:30:22 1997 Yukihiro Matsumoto * variable.c (mod_const_at): global constants now belongs to the class Object. * object.c (Init_Object): new global constant NIL. * ext/marshal/marshal.c (marshal_dump): try to set binmode. * ext/marshal/marshal.c (r_object): forgot to re-regist structs in the object table. * eval.c (ruby_options): call Init_ext() before any require() calls by `-r'. Fri Sep 30 14:29:22 1997 WATANABE Hirofumi * ext/marshal/marshal.c (w_object): marshal dumped core. Tue Sep 30 10:27:39 1997 Yukihiro Matsumoto * sample/test.rb: bignum test suits added. * eval.c (rb_eval): new pseudo variable `true' and `false'. * parse.y: new keywords `true' and `false' added. Mon Sep 29 13:37:58 1997 Yukihiro Matsumoto * ruby.c (forbid_setid): forbid some options in suid mode. * ruby.h (NUM2DBL): new macro to convert into doubles. Mon Sep 27 09:53:48 1997 EGUCHI Osamu * bignum.c: modified for speeding. Fri Sep 26 18:27:59 1997 WATANABE Hirofumi * sample/from.rb: some extensions. Mon Sep 29 13:15:56 1997 Yukihiro Matsumoto * parse.y (lhs): no more syntax error on `obj.CONSTANT = value'. Fri Sep 26 14:41:46 1997 Yukihiro Matsumoto * eval.c (ruby_run): deferred calling Init_ext() just before eval_node. Fri Sep 26 13:27:24 1997 WATANABE Hirofumi * io.c (io_isatty): forgot to return TRUE value. Fri Sep 25 11:10:58 1997 EGUCHI Osamu * eval.c: use _setjmp/_longjmp instead of setjmp/longjmp on some platforms. Wed Sep 24 17:43:13 1997 Yukihiro Matsumoto * string.c (Init_String): String#taint and String#taint? added. * class.c (mod_ancestors): ancestors include the class itself. Wed Sep 24 00:57:00 1997 Katsuyuki Okabe * X68000 patch. Tue Sep 23 20:42:30 1997 EGUCHI Osamu * parse.y (node_newnode): SEGV on null node setup. Mon Sep 22 11:22:46 1997 Yukihiro Matsumoto * ruby.c (ruby_prog_init): wrong safe condition check. Sun Sep 21 14:46:02 1997 MAEDA shugo * error.c (exc_inspect): garbage added to classpath. Fri Sep 19 11:49:23 1997 Yukihiro Matsumoto * parse.y (newtok): forgot to adjust buffer size when shrinking the token buffer. * enum.c (enum_find): rb_eval_cmd() does not return value. * io.c (pipe_open): close fds on pipe exec. fcntl(fd, F_SETFD, 1) no longer used. Tue Sep 16 17:54:25 1997 Yukihiro Matsumoto * file.c (f_test): problem if wrong command specified. * ruby.c (ruby_prog_init): close stdaux and stdprn for MSDOS. * ruby.c (ruby_prog_init): should not add path from environment variable, if ruby is running under setuid. * process.c (init_ids): check suid check for setuid/seteuid etc. Mon Sep 15 00:42:04 1997 WATANABE Hirofumi * regex.c (re_compile_pattern): \w{3} and \W{3} did not work. Thu Sep 11 10:31:48 1997 Yukihiro Matsumoto * version 1.1 alpha7 released. * ext/socket/socket.c (sock_new): no setbuf() for NT. * io.c (rb_fopen,rb_fdopen): set close-on-exec for every fd. Wed Sep 10 15:55:31 1997 Yukihiro Matsumoto * ext/marshal/marshal.c (r_bytes0): extra big length check. Tue Sep 9 16:27:14 1997 Yukihiro Matsumoto * io.c (pipe_fptr_atexit): clean up popen()'ed fptr. * error.c (set_syserr): some system has error code that is bigger than sys_nerr. grrr. Mon Sep 8 18:33:33 1997 Yukihiro Matsumoto * io.c (io_s_new): dereferenced nil for optional mode. Fri Sep 5 10:26:03 1997 Yukihiro Matsumoto * class.c (class_instance_methods): do not include methods which are changed to private in subclasses. Thu Sep 4 12:38:53 1997 Yukihiro Matsumoto * variable.c (f_global_variables): list name of the global variables. * object.c (obj_id): returns unique integer. Wed Sep 3 14:05:16 1997 Yukihiro Matsumoto * version 1.1 alpha6 released. * eval.c (mod_s_constants): context sensitive constant list. * variable.c (mod_constants): no more `all' option. * variable.c (mod_const_of): the values for autoload classes are their name strings. * class.c (class_instance_methods): no special treatment for singleton classes. * object.c (obj_singleton_methods): returns list of singleton method names. * parse.y (yylex): no here document after `class' keyword. * eval.c (f_load): expand path if fname begins with `~'. Tue Sep 2 13:19:48 1997 Yukihiro Matsumoto * class.c (ins_methods_i): do not list undef'ed methods. Mon Sep 1 13:42:48 1997 Yukihiro Matsumoto * version 1.1 alpha5 released. * object.c (mod_attr_reader): create methods to define attribute reader/write/accessor. * class.c (rb_define_attr): always defines accessors. * eval.c (rb_call): alias occurred in the module body caused SEGV. * parse.y: did not generate here document strings properly. Mon Sep 1 11:43:57 1997 WATANABE Hirofumi * parse.y (yylex): heredoc dropped an extra character. Fri Aug 29 11:10:21 1997 Yukihiro Matsumoto * class.c (class_instance_methods): same method names should not appear more than once. * parse.y (yylex): spaces can follow =begin/=end. * variable.c (find_class_path): look for class_tbl also for unnamed fundamental classes, such as Object, String, etc. * variable.c (rb_name_class): can't name class before String class is initialized. * inits.c (rb_call_inits): unrecognized dependency from GC to Array. * variable.c (find_class_path): could not find class if Object's iv_tbl is NULL. Thu Aug 28 13:12:05 1997 Yukihiro Matsumoto * version 1.1 alpha4 released. * variable.c (mod_constants): wrong condition for singleton class. * parse.y (yylex): revised `=begin' skip code. * parse.y (here_document): forgot to free(eos). * parse.y (yylex): spaces after `<<' prohibited for here documents to avoid confusing with operator `<<'. * eval.c (is_defined): separated from rb_eval(). Wed Aug 27 11:32:42 1997 Yukihiro Matsumoto * version 1.1 alpha3 released. * variable.c (mod_name): returns name of the class/module. * parse.y (here_document): finally here document available now. * variable.c (fc_i): some classes/modules does not have iv_tbl. * variable.c (find_class_path): avoid infinite loop. Tue Aug 26 13:43:47 1997 Yukihiro Matsumoto * eval.c (rb_eval): undef'ing non-existing method will raise NameError exception. * object.c (class_s_new): needed to create metaclass too. * eval.c (error_print): no class name print for anonymous class. * eval.c (rb_longjmp): proper exception raised if raise() called without arguments, with $! or $@ set. * object.c (Init_Object): superclass()'s method argument setting was wrong again. * class.c (mod_ancestors): list superclasses and included modules in priority order. Mon Aug 25 11:53:11 1997 Yukihiro Matsumoto * version 1.1 alpha2 released. * sample/ruby-mode.el (ruby-parse-region): auto-indent now supports "\\" in the strings. * struct.c (struct_getmember): new API to get member value from C language side. Sat Aug 23 21:39:05 1997 Yukihiro Matsumoto * parse.y (assignable): remove unnecessary local variable initialize by nil. Fri Aug 22 14:26:40 1997 Yukihiro Matsumoto * eval.c (error_print): modified exception print format. Thu Aug 21 16:10:58 1997 Yukihiro Matsumoto * sample/ruby-mode.el (ruby-calculate-indent): wrong indent level calculated with keyword operators. Thu Aug 21 11:36:58 1997 WATANABE Hirofumi * parse.y (arg): ary[0] += 1 cause SEGV Wed Aug 20 17:28:50 1997 Yukihiro Matsumoto * ruby.c (ruby_process_options): require() all modules after processing all options * process.c (rb_proc_exec): more security checks added. * process.c (rb_proc_exec): insecure path on exec. * hash.c (f_getenv): PATH modification security check. Tue Aug 19 00:15:38 1997 Yukihiro Matsumoto * version 1.1 alpha1 released. * eval.c (mod_eval): work as normal eval() if second binding argument given. * eval.c (rb_call): did not raise ArgumentError if too many arguments more than optional arguments (without rest arg). * eval.c (rb_eval): did not work well for op_asgn2 (attribute self assignment). * eval.c (Init_Thread): returns main thread. Mon Aug 18 09:25:56 1997 Yukihiro Matsumoto * object.c (inspect_i): did not display T_DATA instance variables. * parse.y: provides more accurate line number information. * eval.c (thread_value): include value's backtrace information in the variable `$@'. * eval.c (f_abort): print backtrace and exit. Sat Aug 16 00:17:44 1997 Yukihiro Matsumoto * eval.c (class_new_instance): do not make instance from virtual classes. * object.c (class_s_new): do not make subclass of singleton class. Fri Aug 15 15:49:46 1997 Yukihiro Matsumoto * eval.c (call_trace_func): block context switch in the trace function. * eval.c (rb_eval): clear method cache at class extension. * object.c (obj_type): returns object's class even if it defines singleton methods. Fri Aug 15 19:40:43 1997 WATANABE Hirofumi * ext/socket/socket.c (Init_socket): small typo caused SEGV. Wed Aug 13 17:51:46 1997 Yukihiro Matsumoto * version 1.1 alpha0 released. Local variables: add-log-time-format: (lambda () (let* ((time (current-time)) (diff (+ (cadr time) 32400)) (lo (% diff 65536)) (hi (+ (car time) (/ diff 65536)))) (format-time-string "%a %b %e %H:%M:%S %Y" (list hi lo) t))) indent-tabs-mode: t tab-width: 8 end: ================================================ FILE: doc/NEWS-1.8.0 ================================================ = command line options : -W option new option to specify warning level. -W0 to shut up warnings, -W1 for normal level, -W2 for verbose level. -w equals to -W2. = language syntax : arbitrary delimited string array %W(...) notation, word list literal like %w(...) with the exception that #{} interpolation is allowed. : arbitrary delimited symbol literl :"foo", :"foo#{bar}", etc. : expression interpolation in strings Now arbitrary statements are allowed inside #{} interpolation without escapes. In other hand, they can no longer access to variables defined in eval. : negative number literals Digits preceded minus sign is a literal integer. : array expansion Fixed with the following behavior: a = *[1] p a #=> [1] Now 1-element array in rhs is expanded properly. a = *[1] p a #=> 1 : break and next Extended to take an optional expression, which is used as a value for termination. : direct assignment to Foo::Bar is allowed also, you can define "class Foo::Bar; end". = language core : $stdin, $stdout, $stderr can be assignable again. the original stdio are preserved as STDIN, STDOUT, STDERR. : $VERBOSE now has 3 levels nil - silence, false - medium (default), true - verbose : allocation framework any instance of class can be allocated by class.allocate, (except for a few classes). : comparison of exception classes in a rescue clause changed to use Module#=== for comparing $! with the exception class specified in each rescue clause. as the previous behavior was to use kind_of?, the effect is limited to the SystemCallError case. SystemCallError.=== has been newly defined to return true when the two have the same errno. With this change, SystemCallError's with the same errno, such as Errno::EAGAIN and Errno::EWOULDBLOCK, can both be rescued by listing just one of them. : constants lookup improved at the performance of searching by using an internal hash table. calls const_missing method of the class/module, if constant is not found in the look up path. : expression parenthesis in the first argument altered to get the following code (note the space after p): p ("xx"*2).to_i Interpreted as: p (("xx"*2).to_i) Instead of: (p("xx"*2)).to_i : implicit comparison in conditional expressions Obsoleted except when it is used in -e. : between Range and $. Use explicit comparison instead. : between Regexp and $_ Use the unary method ~/re/ instead. : to_str added to get objects which define to_str() treated as String's. now almost all the built-in methods try each argument with to_str() when they expect it to be a String. foo = Object.new class < -:7:in `open': wrong argument type Object (expected String) (TypeError) ruby 1.6.4 (2001-04-19) [i586-linux] => -:7:in `open': No such file or directory - "foo" (Errno::ENOENT) ruby 1.7.0 (2001-05-02) [i586-linux] : multiple assignment behavior Fixed so that "*a = nil" results in "a == []". = changes in core class library : open Extended so that when the third argument is permission flags it calls open(2) instead of fopen(3). : sprintf new format specifier "%p" is available. : lambda and proc Proc object returns from these methods has the following attributes: * strict argument number check * break and return terminates the proc execution. : warn(message) a method to give warnings. : abort() takes optional terminate message argument. : Object#initialize_copy copy constructor for clone and dup. : Object#instance_variable_set, Object#instance_variable_get added. : Object#singleton_method_removed : Object#singleton_method_undefined Added. : Array#transpose added. : Array#fetch(index [, default]) Added. If a default value isn't given, raises index error if index is out of range. : Array#insert(n, other, ...) Added. [ruby-talk:14289] This is much the same as (({ary[n,0] = [other,...]})) except returing self. ary = [0,1,2,3] ary[2, 0] = [4, 5, 6] p ary ary = [0,1,2,3] ary.insert(2, 4, 5, 6) p ary : Array#sort! Changed to always return self without checking whether the sequence of the elements was modified or not. Beware that this behavior is not guaranteed to continue in the future. Do not rely on its return value. [ruby-dev:12506] : Array#filter Previously deprecated, now removed. Use Array#collect!. : Array#pack, String#unpack Allows comment in template strings. : Array#pack, String#unpack New templates 'q' and 'Q' for 64bit integer (signed and unsigned respectively). : Array#new Now takes block to fill initial values. E.g. Array.new(10) { |i| i + 1 } => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] : Array#fill Takes block to get the values to fill. : Array#fetch Takes block to get the default value. : Array#zip added. : Hash#update Takes block to resolve key conflict. : Hash#merge and Hash#merge! update hash. Hash#merge! is a synonym of Hash#update. : String#split if "sep" argument is a string, regular expression meta characters are escaped internally. : String#rstrip chop off NULs at the end of strings. : String#to_i Now accepts optional base argument. "101".to_i(10) => 101 "101".to_i(2) => 5 "101".to_i(8) => 65 "101".to_i(16) => 257 A base argument of 0 guesses at the base. "101".to_i(0) => 101 "0b101".to_i(0) => 5 "0101".to_i(0) => 65 "0x101".to_i(0) => 257 : String#[regexp, nth] Extended to accepts optional second argument. It tries match between self and REGEXP, then returns the content of the NTH regexp register. : String#casecmp Added. This is a case insensitive version of String#<=>. : String#chomp If $/ == "\n", chops off last newlines (any of \n, \r, \r\n). : String#eql? Changed to be always case sensitive. : String#insert(n, other) Added. This is much the same as (({str[n, 0] = other})) except returing self. : String#lstrip, rstrip, lstrip!, rstrip! Added. These strip only left or right part of a string. : String#match Added. : String/Array methods Returns an instance of receivers class. : String.new The first argument becomes optional. : Symbol#intern Added. : Symbol.all_symbols Added. [ruby-dev:12921] : IO 64bit off_t support by Janathan Baker. : IO#read : IO#sysread takes optinal second argument for read buffer. : IO::sysopen New method to get a raw file descriptor. : IO#sysseek Added. : IO#fsync new method that copies all in-memory parts of a file to disk and waits until the device reports that all parts are on stable storage. Implemented with fsync(2) or equivalent. : IO.open Made public. Can only associate an IO object with a file number like IO.new and IO.for_fd, but can take a block. : IO.for_fd Added as a synonym for IO.new. : IO.read Added. Like IO.readlines, except it returns the entire file as a string. [ruby-talk:9460] : File#fnmatch, File::Constants::FNM_* Added. Refer to the fnmatch(3) manpage for details. Localism is FNM_DOTMATCH which has the opposite meaning of the commonly known FNM_PERIOD, which does not exist in Ruby. e.g. # exclude files matching "*.bak" case-insensitively. files.reject! {|fn| File.fnmatch?("*.bak", fn, File::FNM_CASEFOLD) } : File.lchmod : File.lchown Added. : File.open, IO.open File mode can be specified by flags like open(2), e.g. File::open(path, File::CREAT|File::WRONLY). : Regexp#options Added. : Regexp.last_match(n) Extended to take an optional argument. : MatchData#captures added. : Dir#path Added. : Dir.chdir Extended to take a block. : Dir.glob Made to support meta-character escaping by a backslash. Wildcards and spaces may now be escaped using a backslash. : Dir.open Changed to return what the block returns when a block is given, just as File.open does. (It always returned (({nil})) in 1.6 and prior) : Dir.chdir Changed to warn only when invoked from multiple threads or no block is given. [ruby-dev:13823] Dir.chdir('foo') { Dir.chdir('bar') { # previously warned puts Dir.pwd } } : Dir#pos= Returns the new position instead of self. : Dir::glob Now accepts optional FNM_* flags via the second argument, whereas Dir::[] doesn't. Dir.glob("makefile", File::FNM_CASEFOLD) #=> ['Makefile', 'makefile'] : Class#inherited Method is called when Class is inherited by another class. class A; end def A.inherited(by) puts "A inherited by #{by.inspect}" end class B < A; end Prints out "A inherited by B" : Module#include? Added. [ruby-dev:13941] : Module#included Added. This is a hook called after Module#append_feature. : Module#method_removed : Module#method_undefined Added. : Module.new, Class.new Extended to take block. : Time Extended to accept a negative time_t. (Only when the platform supports it) p Time.at(-1) => Thu Jan 01 08:59:59 JST 1970 : Time#to_a : Time#zone Made to return "UTC" under gmtime. It used to return a platform dependent value, typically "GMT", in 1.6 and prior. : Marshal to use marshal_dump and marshal_load if a dumping object responds to 'marshal_dump', Marshal.dump calls it, and dumps object returned. Marshal.load allocates a new instance using "allocate", then calls its "marshal_load" with dumped data. Marshal format version is now 4.8 (was 4.6 in 1.6.8). : Marshal Fixed not to dump anonymous classes/modules. Fixed with loading modules. : Thread#group new method to get belonging ThreadGroup. : Thread#terminate synonym of Thread#exit : Thread#join Optional argument limits maximum time to wait the thread in second. And returns nil if timed out. : ThreagGroup#enclose prohibits thread movement from/to enclosed groups. : Range#step([step=1]) Added. : SystemCallError SystemCallError's "===" match (used in rescue also) is now based on its errno. : Interrupt Made a subclass of SignalException. (It was a subclass of Exception in 1.6 and prior) : NameError and NoMethodError Moved and now NoMethodError < NameError < StandardError. : NoMethodError Added. [ruby-dev:12763] : NotImplementError Finally obsoleted. Use NotImplementedError. : SystemCallError.=== Added. (See the "Comparison of exception classes in a rescue clause" paragraph above) [ruby-dev:12670] : SystemExit#status Added. : Proc#== Added. : Method#== Added. : UnboundMethod is no longer subclass of Method class hierarchy changed. : Enumerable#all? : Enumerable#any? : Enumerable#inject : Enumerable#sort_by Added. : Math.acos(x) : Math.asin(x) : Math.atan(x) : Math.cosh(x) : Math.hypot(x,y) : Math.sinh(x) : Math.tanh(x) Added. : Process.abort : Process.exit synonym of Kernel#abort, and Kernel#exit respectively. : Process::detach(pid) new method to detach child process. child process will be "wait"ed automagically. : Process.times Moved from Time.times. (Time.times still remains but emits a warning) : Process.waitall Added. : Process::Status Added. (({$?})) is now an instance of this class. : Process::UID, Process::GID, Process::Sys, Added. : Signal Added. This module has module functions Signal.trap and Signal.list. = changes in bundled libraries : lib/cgi.rb cgi[name] returns CGI::QueryExtension::Value that wraps string value, no longer array. : lib/timeout timeout "function" wrapped in Timeout module. : TCPServer#accept, UNIXServer#accept, Socket#accept New methods to return an accepted socket fd. : Date and DateTime lib/date.rb now provides both Date and DateTime. Some methods have been renamed. But the old names are still alive. Some new methods have been added (Date::parse, Date#strftime, etc.). Date#mjd now returns the chronological modified Julian day number. All facilities about tjd have been removed. : Curses Updated. New methods and constants for using the mouse, character attributes, colors and key codes have been added. : Net::HTTP New version of Net::HTTP has introduced seriously incompatible changes. For details, see document embedded in net/http.rb itself. : Socket.pack_sockaddr_in, Socket.unpack_sockaddr_in Added. Utility for direct Socket access. : Socket.pack_sockaddr_un, Socket.unpack_sockaddr_un Added. Utility for direct Socket access. : TCPServer#listen, UNIXServer#listen Added. : TCPSocket.new : TCPSocket.open Extended to take an address and a port number for the local side in optional 3rd and 4th arguments. = newly bundled library : ext/bigdecimal variable precision decimal number : ext/dl an interface to the dynamic linker. : ext/enumerator a helper module for the Enumerable interface. : ext/io/wait IO wait methods. : ext/iconv wrapper library of (({iconv})). : ext/openssl OpenSSL for Ruby : ext/racc/cparse Racc runtime library in C. (Racc is a parser generator for ruby) : ext/stringio Pseudo (({IO})) class from/to (({String})). : ext/strscan Fast string scanner library. : ext/syck fast YAML parser. : lib/abbrev creates an abbreviation table from a list : lib/benchmark Ruby scripts benchmarker : lib/cgi/session/pstore cgi/session back-end using pstore : lib/csv reads/writes CSV files. : lib/date/format strftime for Date class : lib/drb dRuby or distributed Ruby : lib/fileutils file utility library. : lib/generator converts an internal iterator to an external iterator : lib/gserver generic server used by xmlrpc : lib/ipaddr manipulates IP address. : lib/multi-tk to allow safe Tk, etc. : lib/open-uri easy-to-use wrapper for net/http and net/ftp : lib/optparse command line options utility library : lib/pathname handles pathname in OO manner. : lib/pp prettyprinter for Ruby objects : lib/prettyprint implements prettyprint algorithm. : lib/profiler library to implement -r "profile" : lib/racc/parser RACC parser generator runtime in Ruby. : lib/scanf scan string and retrieve object with format : lib/set Set class : lib/runit RubyUnit compatible layer for test/unit : lib/test/unit unit testing framework for Ruby : lib/tmpdir get temporary directory path. : lib/tsort topological sorting library. : lib/rexml REXML XML library : lib/webrick generic internet server kit : lib/xmlrpc simple RPC via XML : lib/un used like 'ruby -run -e cp -- -p foo bar'. neat, isn't it? : lib/win32/registry win32/registry is registry accessor : lib/yaml YAML Ain't Mark-up Language = removed libraries : lib/ftplib use net/ftp instead. : lib/telnet use net/telnet instead. = new port : WindowsCE port : Win32 BCC = interpreter implementation : garbage collector faster, but uses more memory for the worst case. : string concatenation faster by avoiding too frequent realloc(3). ================================================ FILE: doc/forwardable.rd ================================================ -- forwardable.rb $Release Version: 1.1 $ $Revision$ $Date$ Original version by Tosh =begin = Forwardable A Module to define delegations for selected methods to a class. == Usage Using through extending the class. class Foo extend Forwardable def_delegators("@out", "printf", "print") def_delegators(:@in, :gets) def_delegator(:@contents, :[], "content_at") end f = Foo.new f.printf ... f.gets f.content_at(1) == Methods --- Forwardable#def_instance_delegators(accessor, *methods) adding the delegations for each method of ((|methods|)) to ((|accessor|)). --- Forwardable#def_instance_delegator(accessor, method, ali = method) adding the delegation for ((|method|)) to ((|accessor|)). When you give optional argument ((|ali|)), ((|ali|)) is used as the name of the delegation method, instead of ((|method|)). --- Forwardable#def_delegators(accessor, *methods) the alias of ((|Forwardable#def_instance_delegators|)). --- Forwardable#def_delegator(accessor, method, ali = method) the alias of ((|Forwardable#def_instance_delegator|)). = SingleForwardable a Module to define delegations for selected methods to an object. == Usage Using through extending the object. g = Goo.new g.extend SingleForwardable g.def_delegator("@out", :puts) g.puts ... == Methods --- SingleForwardable#def_singleton_delegators(accessor, *methods) adding the delegations for each method of ((|methods|)) to ((|accessor|)). --- SingleForwardable#def_singleton_delegator(accessor, method, ali = method) adding the delegation for ((|method|)) to ((|accessor|)). When you give optional argument ((|ali|)), ((|ali|)) is used as the name of the delegation method, instead of ((|method|)). --- SingleForwardable#def_delegators(accessor, *methods) the alias of ((|SingleForwardable#def_instance_delegators|)). --- SingleForwardable#def_delegator(accessor, method, ali = method) the alias of ((|SingleForwardable#def_instance_delegator|)). =end ================================================ FILE: doc/forwardable.rd.ja ================================================ -- forwatable.rb $Release Version: 1.1 $ $Revision$ $Date$ =begin = Forwardable 饹Ф᥽åɤΰѾǽޤ. == Ȥ 饹ФextendƻȤޤ. class Foo extend Forwardable def_delegators("@out", "printf", "print") def_delegators(:@in, :gets) def_delegator(:@contents, :[], "content_at") end f = Foo.new f.printf ... f.gets f.content_at(1) == ᥽å --- Forwardable#def_instance_delegators(accessor, *methods) ((|methods|))Ϥ줿᥽åɤΥꥹȤ((|accessor|))Ѿ 褦ˤޤ. --- Forwardable#def_instance_delegator(accessor, method, ali = method) ((||method|))Ϥ줿᥽åɤ((|accessor|))˰Ѿ褦ˤ ޤ. ((|ali|))ȤϤ줿Ȥ, ᥽å((|ali|))Ƥ 줿Ȥˤ, ((|accessor|))Ф((|method|))ƤӽФޤ. --- Forwardable#def_delegators(accessor, *methods) ((|Forwardable#def_instance_delegators|))̾Ǥ. --- Forwardable#def_delegator(accessor, method, ali = method) ((|Forwardable#def_instance_delegator|))̾Ǥ. = SingleForwardable ֥ȤФ, ᥽åɤΰѾǽޤ. == Ȥ ֥ȤФ((|extend|))ƻȤޤ. g = Goo.new g.extend SingleForwardable g.def_delegator("@out", :puts) g.puts ... == ᥽å --- SingleForwardable#def_singleton_delegators(accessor, *methods) ((|methods|))Ϥ줿᥽åɤΥꥹȤ((|accessor|))˰Ѿ 褦ˤޤ. --- SingleForwardable#def_singleton_delegator(accessor, method, ali = method) ((|method|))Ϥ줿᥽åɤ((|accessor|))˰Ѿ褦ˤ . ((|ali|))ȤϤ줿Ȥ, ᥽å((|ali|))ƤФ Ȥˤ, ((|accessor|))Ф((|method|))ƤӽФޤ. --- SingleForwardable#def_delegators(accessor, *methods) ((|SingleForwardable#def_singleton_delegators|))̾Ǥ. --- SingleForwardable#def_delegator(accessor, method, ali = method) ((|SingleForwardable#def_singleton_delegator|))̾Ǥ. =end ================================================ FILE: doc/irb/irb-tools.rd.ja ================================================ irbϢޤޥɤȥ饤֥ $Release Version: 0.7.1 $ $Revision$ $Date$ by Keiju ISHITSUKA(Nihon Rational Co.,Ltd.) =begin :ޥ: * rtags -- ruby tags command :ؿ饤֥: * xmp -- irb version of gotoken xmp-function :饹饤֥: * frame.rb -- frame tracer * completion.rb -- irb completor = rtags rtagsemacsڤviѤ, TAGեĤ륳ޥɤǤ. == Ȥ rtags [-vi] file.... ȥǥ쥯ȥemacsѤTAGSե뤬Ǥޤ. -viץ ĤˤviѤtagsեޤ. emacsξ, ̾etags.elΤޤ޻Ȥޤ. ǽʤΤ, * 饹 * ᥽å * ðۥ᥽å * alias * attr줿(ѥ᡼ܥ뤫ʸƥ˸¤) * attr_XXX줿(ѥ᡼ܥ뤫ʸƥ˸¤) Ǥ. CʤɤǻȤäƤΤȰ㤦Τ, ץ꡼˴ؤʬ, ؿ̾, ؿ̾( 饹, ::饹̾::....::饹̾ ᥽åɤ, ::饹̾::....::饹̾#᥽å̾ ðۥ᥽å(饹᥽å) ::饹̾::....::饹̾.᥽å̾ ǥץ꡼ԤʤȤǤ. = xmp.rb Ȥxmpξ̸ߴСǤ. , ˽ŤΤǤȤxmp бǤʤ, ѤɤǤ礦. == Ȥ === ؿȤƻȤ. require "irb/xmp" xmp <1 foo ==>1 === XMP󥹥󥹤Ѥ. ξ, XMPƥȾĤΤ, ѿͤʤɤݻƤ ޤ. require "irb/xmp" xmp = XMP.new xmp.puts <1 foo ==>1 foo ==>1 == ƥȤ˴ؤ XMP᥽åɷΥƥȤ, ƤӽФΥƥȤɾޤ. Ū˥ƥȤꤹȤΥƥȤɾޤ. : xmp "foo", an_binding :: ޥåɤˤбƤޤ. = frame.rb ߼¹Υե졼갷Υ饹Ǥ. * IRB::Frame.top(n = 0) 夫nܤΥƥȤФޤ. n0Ǿ̤ˤʤޤ. * IRB::Frame.bottom(n = 0) nܤΥƥȤФޤ. n0Dz̤ˤʤޤ. * IRB::Frame.sender ˤʤäƤ륪֥ȤФޤ. Ȥ, Υ᥽ ɤƤӽФ¦selfΤȤǤ. :: set_trace_funcѤRubyμ¹Ԥȥ졼Ƥޤ. ޥåɤ бƤޤ. = completion.rb irbcompletionǽ󶡤ΤǤ. == Ȥ % irb -r irb/completion Ȥ뤫, ~/.irbrc require "irb/completion" Ƥ. irb¹ require "irb/completion" Ƥ褤Ǥ. irb¹ (TAB) 򲡤ȥץ졼󤷤ޤ. ȥåץ٥(TAB)򲡤Ȥ٤Ƥιʸ, 饹, ᥽åɤθ䤬 ޤ. 䤬ͣʤд䴰ޤ. irb(main):001:0> in in inspect instance_eval include install_alias_method instance_of? initialize install_aliases instance_variables irb(main):001:0> inspect "main" irb(main):002:0> foo = Object.new # ((|ѿ̾.|))θ(TAB)򲡤, Υ֥ȤΥ᥽åɰǤ . irb(main):003:0> foo. foo.== foo.frozen? foo.protected_methods foo.=== foo.hash foo.public_methods foo.=~ foo.id foo.respond_to? foo.__id__ foo.inspect foo.send foo.__send__ foo.instance_eval foo.singleton_methods foo.class foo.instance_of? foo.taint foo.clone foo.instance_variables foo.tainted? foo.display foo.is_a? foo.to_a foo.dup foo.kind_of? foo.to_s foo.eql? foo.method foo.type foo.equal? foo.methods foo.untaint foo.extend foo.nil? foo.freeze foo.private_methods =end % Begin Emacs Environment % Local Variables: % mode: text % comment-column: 0 % comment-start: "%" % comment-end: "\n" % End: % ================================================ FILE: doc/irb/irb.rd ================================================ irb -- interactive ruby $Release Version: 0.9 $ $Revision$ $Date$ by Keiju ISHITSUKA(keiju@ishitsuka.com) by gotoken-san who is original translater from japanese version =begin = What is irb? irb stands for `interactive ruby'. irb is a tool to execute interactively ruby expressions read from stdin. = Invoking % irb = Usage Use of irb is easy if you know ruby. Executing irb, prompts are displayed as follows. Then, enter expression of ruby. A input is executed when it is syntacticaly completed. dim% irb irb(main):001:0> 1+2 3 irb(main):002:0> class Foo irb(main):003:1> def foo irb(main):004:2> print 1 irb(main):005:2> end irb(main):006:1> end nil irb(main):007:0> And, Readline extesion module can be used with irb. Using Readline is the standard default action if Readline is installed. = Command line option irb.rb [options] file_name opts options: -f suppress read ~/.irbrc -m bc mode (fraction or matrix are available) -d set $DEBUG to true (same as `ruby -d') -Kc same as `ruby -Kc' -r load-module same as `ruby -r' --verbose command input is echoed(default) --noverbose command input isn't echoed --echo commands are echoed immediately before execution(default) --noecho commands aren't echoed immediately before execution --inspect uses `inspect' for output (the default except bc mode) --noinspect doesn't uses inspect for output --readline uses Readline extension module --noreadline doesn't use Readline extension module --prompt prompt-mode --prompt-mode prompt-mode switches prompt mode. Pre-defined prompt modes are `default', `simple', `xmp' and `inf-ruby' --inf-ruby-mode uses prompt appreciate for inf-ruby-mode on emacs. Suppresses --readline. --simple-prompt simple prompt mode --noprompt no prompt --tracer display trace for each execution of commands. --back-trace-limit n displayes backtrace top n and tail n. The default value is 16. --irb_debug n sets internal debug level to n (It shouldn't be used) -v, --version prints the version of irb = Configurations irb reads `~/.irbrc' when it is invoked. If `~/.irbrb' doesn't exist irb try to read in the order `.irbrc', `irb.rc', `_irbrc' then `$irbrc'. The following is altanative to the command line option. To use them type as follows in an irb session. IRB.conf[:IRB_NAME]="irb" IRB.conf[:MATH_MODE]=false IRB.conf[:USE_TRACER]=false IRB.conf[:USE_LOADER]=false IRB.conf[:IGNORE_SIGINT]=true IRB.conf[:IGNORE_EOF]=false IRB.conf[:INSPECT_MODE]=nil IRB.conf[:IRB_RC] = nil IRB.conf[:BACK_TRACE_LIMIT]=16 IRB.conf[:USE_LOADER] = false IRB.conf[:USE_READLINE] = nil IRB.conf[:USE_TRACER] = false IRB.conf[:IGNORE_SIGINT] = true IRB.conf[:IGNORE_EOF] = false IRB.conf[:PROMPT_MODE] = :DEFALUT IRB.conf[:PROMPT] = {...} IRB.conf[:DEBUG_LEVEL]=0 IRB.conf[:VERBOSE]=true == Customizing prompt To costomize the prompt you set a variable IRB.conf[:PROMPT] For example, describe as follows in `.irbrc'. IRB.conf[:PROMPT][:MY_PROMPT] = { # name of prompt mode :PROMPT_I => nil, # normal prompt :PROMPT_S => nil, # prompt for continuated strings :PROMPT_C => nil, # prompt for continuated statement :RETURN => " ==>%s\n" # format to return value } Then, invoke irb with the above prompt mode by % irb --prompt my-prompt Or add the following in `.irbrc'. IRB.conf[:PROMPT_MODE] = :MY_PROMPT Constants PROMPT_I, PROMPT_S and PROMPT_C specifies the format. In the prompt specification, some special strings are available. %N command name which is running %m to_s of main object (self) %M inspect of main object (self) %l type of string(", ', /, ]), `]' is inner %w[...] %NNi indent level. NN is degits and means as same as printf("%NNd"). It can be ommited %NNn line number. %% % For instance, the default prompt mode is defined as follows: IRB.conf[:PROMPT_MODE][:DEFAULT] = { :PROMPT_I => "%N(%m):%03n:%i> ", :PROMPT_S => "%N(%m):%03n:%i%l ", :PROMPT_C => "%N(%m):%03n:%i* ", :RETURN => "%s\n" } RETURN is used to printf. == Configurating subirb The command line option or IRB.conf specify the default behavior of (sub)irb. On the other hand, each conf of in the next sction `6. Command' is used to individually configurate (sub)irb. If proc is set to IRB.conf[:IRB_RC], its subirb will be invoked after execution of that proc under giving the context of irb as its aregument. By this mechanism each subirb can be configurated. = Command For irb commands, both simple name and `irb_'-prefixed name are prepared. --- exit, quit, irb_exit Quits (sub)irb. --- conf, irb_context Displays current configuration. Modifing the configuration is achieved by sending message to `conf'. --- conf.eval_history = N Sets execution result history. N is a integer or nil. If N > 0, the number of historys is N. If N == 0, the number of historys is unlimited. If N is nill, execution result history isn't used(default). --- conf.back_trace_limit Sets display lines of backtrace as top n and tail n. The default value is 16. --- conf.debug_level = N Sets debug level of irb. --- conf.ignore_eof = true/false Whether ^D (control-d) will be ignored or not. If false is set, ^D means quit. --- conf.ignore_sigint= true/false Whether ^C (control-c) will be ignored or not. If false is set, ^D means quit. If true, during input: cancel inputing then return to top level. during execute: abondon current execution. --- conf.inf_ruby_mode = true/false Whether inf-ruby-mode or not. The default value is false. --- conf.inspect_mode = true/false/nil Specifies inspect mode. true: display inspect false: display to_s nil: inspect mode in non math mode, non inspect mode in math mode. --- conf.math_mode Whether bc mode or not. --- conf.use_loader = true/false Whether irb's own file reader method is used when load/require or not. This mode is globaly affected (irb wide). --- conf.prompt_c prompt for a continuating statement (e.g, immediately after of `if') --- conf.prompt_i standard prompt --- conf.prompt_s prompt for a continuating string --- conf.rc Whether ~/.irbrc is read or not. --- conf.use_prompt = true/false Prompting or not. --- conf.use_readline = true/false/nil Whether readline is used or not. true: uses false: doen't use nil: intends to use readline except for inf-ruby-mode (default) # #--- conf.verbose=T/F # Whether verbose messages are display or not. --- cws, chws, irb_change_workspace [obj] obj will be self. If obj is omitted, self will be home-object, or the main object of first started irb. --- pushws, irb_pushws, irb_push_workspace [obj] same as UNIX-shell command pushd. --- popws, irb_popws, irb_pop_workspace same as UNIX-shell command popd --- irb [obj] Invoke subirb. If obj is given, obj will be self. --- jobs, irb_jobs List of subirb --- fg n, irb_fg n Switch into specified subirb. The following is candidates of n: irb number thhread irb object self(obj which is specified of irb obj) --- kill n, irb_kill n Kill subirb. The means of n is as same as the case of irb_fg. --- souce, irb_source path This is a like UNIX-shell command source. evaluate script in path on current context. --- irb_load path, prev irb-version of Ruby's load. = System variable --- _ The latest value of evaluation (it is local) --- __ The history of evaluation values. __[line_no] return an evaluation value of line number. If line_no is a negative, return value before - from latest value. = Session Example dim% ruby irb.rb irb(main):001:0> irb # invoke subirb irb#1(main):001:0> jobs # list of subirbs #0->irb on main (# : stop) #1->irb#1 on main (# : running) nil irb#1(main):002:0> fg 0 # switch job nil irb(main):002:0> class Foo;end nil irb(main):003:0> irb Foo # invoke subirb which has the # context of Foo irb#2(Foo):001:0> def foo # define Foo#foo irb#2(Foo):002:1> print 1 irb#2(Foo):003:1> end nil irb#2(Foo):004:0> fg 0 # switch job nil irb(main):004:0> jobs # list of job #0->irb on main (# : running) #1->irb#1 on main (# : stop) #2->irb#2 on Foo (# : stop) nil irb(main):005:0> Foo.instance_methods # Foo#foo is defined asurely ["foo"] irb(main):006:0> fg 2 # switch job nil irb#2(Foo):005:0> def bar # define Foo#bar irb#2(Foo):006:1> print "bar" irb#2(Foo):007:1> end nil irb#2(Foo):010:0> Foo.instance_methods ["bar", "foo"] irb#2(Foo):011:0> fg 0 nil irb(main):007:0> f = Foo.new # irb(main):008:0> irb f # invoke subirb which has the # context of f (instance of Foo) irb#3(#):001:0> jobs #0->irb on main (# : stop) #1->irb#1 on main (# : stop) #2->irb#2 on Foo (# : stop) #3->irb#3 on # (# : running) nil irb#3(#):002:0> foo # evaluate f.foo 1nil irb#3(#):003:0> bar # evaluate f.bar barnil irb#3(#):004:0> kill 1, 2, 3# kill job nil irb(main):009:0> jobs #0->irb on main (# : running) nil irb(main):010:0> exit # exit dim% = Restrictions Because irb evaluates the inputs immediately after the imput is syntactically completed, irb gives slight different result than directly use ruby. Known difference is pointed out here. == Declaration of the local variable The following causes an error in ruby: eval "foo = 0" foo -- -:2: undefined local variable or method `foo' for # (NameError) --- NameError Though, the above will successfully done by irb. >> eval "foo = 0" => 0 >> foo => 0 Ruby evaluates a code after reading entire of code and determination of the scope of local variables. On the other hand, irb do immediately. More precisely, irb evaluate at first evel "foo = 0" then foo is defined on this timing. It is because of this incompatibility. If you'd like to detect those differences, begin...end can be used: >> begin ?> eval "foo = 0" >> foo >> end NameError: undefined local variable or method `foo' for # (irb):3 (irb_local_binding):1:in `eval' == Here-document Implementation of Here-document is incomplete. == Symbol Irb can not always recognize a symbol as to be Symbol. Concretely, an expression have completed, however Irb regard it as continuation line. =end % Begin Emacs Environment % Local Variables: % mode: text % comment-column: 0 % comment-start: "%" % comment-end: "\n" % End: % ================================================ FILE: doc/irb/irb.rd.ja ================================================ irb -- interactive ruby $Release Version: 0.9.5 $ $Revision$ $Date$ by Keiju ISHITSUKA(keiju@ruby-lang.org) =begin = irbȤ? irbinteractive rubyάǤ. rubyμɸϤñ/¹Ԥ ΥġǤ. = ư % irb ǹԤʤޤ. = Ȥ irbλȤ, RubyΤäƤФäƴñǤ. Ūˤ irb ޥɤ¹ԤǤ. irb¹Ԥ, ʲΤ褦ʥץ ȤɽƤޤ. , rubyμƲ. 뤷Ǽ¹ ޤ. dim% irb irb(main):001:0> 1+2 3 irb(main):002:0> class Foo irb(main):003:1> def foo irb(main):004:2> print 1 irb(main):005:2> end irb(main):006:1> end nil irb(main):007:0> ޤ, irbReadline⥸塼ˤбƤޤ. Readline⥸塼뤬 󥹥ȡ뤵Ƥˤ, ȤΤɸưˤʤޤ. = ޥɥץ irb.rb [options] file_name opts options: -f ~/.irbrc ɤ߹ޤʤ. -m bc⡼(ʬ, η׻Ǥ) -d $DEBUG trueˤ(ruby -d Ʊ) -Kc ruby -KcƱ -r load-module ruby -r Ʊ. --verbose 줫¹ԤԤɽ(ǥե) --noverbose 줫¹ԤԤɽʤ --echo ¹Է̤ɽ(ǥե) --noecho ¹Է̤ɽʤ --inspect ̽ϤinspectѤ(bc⡼ɰʳϥǥե). --noinspect ̽ϤinspectѤʤ. --readline readline饤֥Ѥ. --noreadline readline饤֥Ѥʤ. ǥեȤư, inf-ruby-modeʳreadline饤֥Ѥ褦 Ȥ. --prompt prompt-mode --prompt-mode prompt-mode ץץȥ⡼ɤؤޤ. Ƥ ץȥ⡼ɤ, default, simple, xmp, inf-ruby ѰդƤޤ. ǥեȤdefaultץץȥ⡼ ɤˤʤäƤޤ. --inf-ruby-mode emacsinf-ruby-modeѤΥץץɽԤʤ. ˻꤬ʤ¤, readline饤֥ϻȤʤʤ. --simple-prompt ˥ץʥץץȤѤ⡼ɤǤ. --noprompt ץץɽԤʤʤ. --tracer ޥɼ¹Ի˥ȥ졼Ԥʤ. --back-trace-limit n Хåȥ졼ɽХåȥ졼Ƭ n, nԤʤ. ǥեȤ16 --irb_debug n irbΥǥХåǥХå٥nꤹ(Ѥ ̵Ǥ礦). -v, --version irbΥСɽ = ե졼 irbư``~/.irbrc''ɤ߹ߤޤ. ⤷¸ߤʤ, ``.irbrc'', ``irb.rc'', ``_irbrc'', ``$irbrc''νloadߤޤ. ץꤹ, ʲΥޥɤǤǥեȤư Ǥޤ. IRB.conf[:IRB_NAME]="irb" IRB.conf[:MATH_MODE]=false IRB.conf[:USE_TRACER]=false IRB.conf[:USE_LOADER]=false IRB.conf[:IGNORE_SIGINT]=true IRB.conf[:IGNORE_EOF]=false IRB.conf[:INSPECT_MODE]=nil IRB.conf[:IRB_RC] = nil IRB.conf[:BACK_TRACE_LIMIT]=16 IRB.conf[:USE_LOADER] = false IRB.conf[:USE_READLINE] = nil IRB.conf[:USE_TRACER] = false IRB.conf[:IGNORE_SIGINT] = true IRB.conf[:IGNORE_EOF] = false IRB.conf[:PROMPT_MODE] = :DEFALUT IRB.conf[:PROMPT] = {...} IRB.conf[:DEBUG_LEVEL]=0 IRB.conf[:VERBOSE]=true == ץץȤ ץץȤ򥫥ޥˤ, IRB.conf[:PROMPT] Ѥޤ. 㤨, .irbrcDzΤ褦ʼ򵭽Ҥޤ: IRB.conf[:PROMPT][:MY_PROMPT] = { # ץץȥ⡼ɤ̾ :PROMPT_I => nil, # ̾Υץץ :PROMPT_N => nil, # ³ԤΥץץ :PROMPT_S => nil, # ʸʤɤη³ԤΥץץ :PROMPT_C => nil, # ³ƤΥץץ :RETURN => " ==>%s\n" # ꥿Υץץ } ץץȥ⡼ɤꤷˤ, irb --prompt my-prompt ǤΥץץȥ⡼ɤǵưޤ. ޤ, .irbrc˲򵭽ҤƤ OKǤ. IRB.conf[:PROMPT_MODE] = :MY_PROMPT PROMPT_I, PROMPT_N, PROMPT_S, PROMPT_C, եޥåȤꤷޤ. %N ưƤ륳ޥ̾Ϥ. %m main֥(self)to_sǽϤ. %M main֥(self)inspectƽϤ. %l ʸΥפɽ(", ', /, ], `]'%wλ) %NNi ǥȤΥ٥ɽ. NNϿprintf%NNdƱ. άǽ %NNn ֹɽޤ. %% % 㤨, ǥեȤΥץץȥ⡼ɤ: IRB.conf[:PROMPT_MODE][:DEFAULT] = { :PROMPT_I => "%N(%m):%03n:%i> ", :PROMPT_N => "%N(%m):%03n:%i> ", :PROMPT_S => "%N(%m):%03n:%i%l ", :PROMPT_C => "%N(%m):%03n:%i* ", :RETURN => "%s\n" } ȤʤäƤޤ. RETURN, ߤΤȤprintfǤ. ͤѤ뤫Τޤ. == irb ޥɥ饤󥪥ץ󤪤IRB.conf()irbưΥǥեȤ Τ, `5. ޥ'ˤconfǸ̤()irb꤬ 褦ˤʤäƤޤ. IRB.conf[:IRB_RC]procꤵƤ, irbưˤ procirbΥƥȤȤƸƤӽФޤ. ˤäƸ̤Υ irbȤѤ뤳ȤǤ褦ˤʤޤ. = ޥ irbĥޥɤ, ñ̾Ƭ`irb_'Ĥ̾ξ ޤ. , ñ̾override줿ΤǤ. --- exit, quit, irb_exit λ. irbξ, Υirbλ. --- conf, irb_context irbθߤɽ. ѹ, conf˥å뤳 ȤˤäƹԤʤ. --- conf.eval_history = N ¹Է̤Υҥȥ굡ǽ. nnnil nn>0 ǤФοҥȥˤ롣nn==0λ ̵¤˵롢nilȥҥȥ굡ǽϤ(ǥե). --- Conf.back_trace_limit Хåȥ졼ɽХåȥ졼Ƭn, nԤʤ. ǥեȤ16 --- conf.debug_level = N irbѤΥǥХå٥ --- conf.ignore_eof = true/false ^DϤ줿ưꤹ. trueλ^D̵뤹, false irbλ. --- conf.ignore_sigint= true/false ^CϤ줿ưꤹ. false, irbλ. true ưϰʲΤ褦ˤʤ: : ޤϤΤ򥭥󥻥뤷ȥåץ٥. ¹: ¹Ԥߤ. --- conf.inf_ruby_mode = true/false inf-ruby-modeѤΥץץɽԤʤ. ǥեȤfalse. --- conf.inspect_mode = true/false/nil 󥹥ڥȥ⡼ɤꤹ. true: 󥹥ڥȤɽ. false: ̾printɽ. nil: ̾⡼ɤǤ, inspect modeȤʤ, math⡼ɤλ, non inspect modeȤʤ. --- conf.math_mode ȤΤ. bc⡼(ʬ, η׻Ǥޤ)ɤ? --- conf.use_loader = true/false load/requireirbfileɤ߹ߵǽѤ⡼ɤΥå(ǥե ȤѤʤ). Υ⡼ɤIRBΤȿǤ. --- conf.prompt_c ifľʤ, Ԥ³ƤΥץץ. --- conf.prompt_i ̾Υץץ. --- conf.prompt_s ʸʤɤɽץץ. --- conf.rc ~/.irbrcɤ߹ɤ? --- conf.use_prompt = true/false ץץɽ뤫ɤ? ǥեȤǤϥץץȤɽ. --- conf.use_readline = true/false/nil readlineȤɤ? true: readlineȤ. false: readlineȤʤ. nil: (ǥե)inf-ruby-modeʳreadline饤֥Ѥ Ȥ. # #--- conf.verbose=T/F # irb餤ʥåϤ뤫? --- cws, chws, irb_cws, irb_chws, irb_change_workspace [obj] objselfȤ. objά줿Ȥ, home workspace, ʤ irbưȤmain objectselfȤ. --- pushws, irb_pushws, irb_push_workspace [obj] UNIX륳ޥɤpushdƱ. --- popws, irb_popws, irb_pop_workspace UNIX륳ޥɤpopdƱ. --- irb [obj] irbΩ. objꤵ줿, objselfȤ. --- jobs, irb_jobs irbΥꥹ --- fg n, irb_fg n ꤷirb˥å. n, ΤΤꤹ. irbֹ å irb֥ self(irb objǵưobj) --- kill n, irb_kill n irbkill. nfgƱ. --- souce, irb_source path UNIX륳ޥɤsourceȻƤ. ߤδĶpathΥ ץȤɾ. --- irb_load path, prev Rubyloadirb. = ƥѿ --- _ η׻μ¹Է̤ФƤ(ѿ). --- __ ¹Է̤ФƤ. __[line_no]ǡιԤǼ¹Ԥ̤뤳ȤǤ. line_no ˤϡǿη̤-line_noη̤뤳ȤǤ. = ʲΤ褦ʴǤ. dim% ruby irb.rb irb(main):001:0> irb # irbΩ irb#1(main):001:0> jobs # irbΥꥹ #0->irb on main (# : stop) #1->irb#1 on main (# : running) nil irb#1(main):002:0> fg 0 # jobΥå nil irb(main):002:0> class Foo;end nil irb(main):003:0> irb Foo # Foo򥳥ƥȤirb # Ω irb#2(Foo):001:0> def foo # Foo#foo irb#2(Foo):002:1> print 1 irb#2(Foo):003:1> end nil irb#2(Foo):004:0> fg 0 # job򥹥å nil irb(main):004:0> jobs # jobΥꥹ #0->irb on main (# : running) #1->irb#1 on main (# : stop) #2->irb#2 on Foo (# : stop) nil irb(main):005:0> Foo.instance_methods # Foo#foo # Ƥ ["foo"] irb(main):006:0> fg 2 # job򥹥å nil irb#2(Foo):005:0> def bar # Foo#bar irb#2(Foo):006:1> print "bar" irb#2(Foo):007:1> end nil irb#2(Foo):010:0> Foo.instance_methods ["bar", "foo"] irb#2(Foo):011:0> fg 0 nil irb(main):007:0> f = Foo.new # irb(main):008:0> irb f # FooΥ󥹥󥹤irb # Ω. irb#3(#):001:0> jobs #0->irb on main (# : stop) #1->irb#1 on main (# : stop) #2->irb#2 on Foo (# : stop) #3->irb#3 on # (# : running) nil irb#3(#):002:0> foo # f.fooμ¹ nil irb#3(#):003:0> bar # f.barμ¹ barnil irb#3(#):004:0> kill 1, 2, 3# jobkill nil irb(main):009:0> jobs #0->irb on main (# : running) nil irb(main):010:0> exit # λ dim% = Ѿ irb, ɾǤ(Ĥ)Ǥ༡¹ԤԤʤޤ. , rubyľܻȤä, 㴳ۤʤưԤʤ礬ޤ. 餫ˤʤäƤޤ. == ѿ rubyǤ, ʲΥץϥ顼ˤʤޤ. eval "foo = 0" foo -- -:2: undefined local variable or method `foo' for # (NameError) --- NameError Ȥ, irbѤ >> eval "foo = 0" => 0 >> foo => 0 Ȥʤ, 顼򵯤ޤ. , rubyǽ˥ץΤ򥳥 ѥ뤷ƥѿꤹ뤫Ǥ. Ф, irbϼ¹Բǽ ʤ(Ĥ)ȼưŪɾƤ뤫Ǥ. 嵭Ǥ, evel "foo = 0" ԤʤäɾԤʤ, λѿ뤿, ѿfooƤ뤫Ǥ. Τ褦rubyirbưΰ㤤褷, begin...enddzä ХåŪ˼¹ԤƲ: >> begin ?> eval "foo = 0" >> foo >> end NameError: undefined local variable or method `foo' for # (irb):3 (irb_local_binding):1:in `eval' == ҥɥ ߤΤȤҥɥȤμԴǤ. == ܥ ܥǤ뤫ɤȽǤְ㤨뤳Ȥޤ. Ūˤϼλ ƤΤ˷³ԤȸʤȤޤ. =end % Begin Emacs Environment % Local Variables: % mode: text % comment-column: 0 % comment-start: "%" % comment-end: "\n" % End: % ================================================ FILE: doc/shell.rd ================================================ -- shell.rb $Release Version: 0.6.0 $ $Revision$ $Date$ by Keiju ISHITSUKA(keiju@ishitsuka.com) =begin = What's shell.rb? It realizes a wish to do execution of commands with filters and pipes like sh/csh by using just native facilities of ruby. = Main classes == Shell Every shell object has its own current working directory, and executes each command as if it stands in the directory. --- Shell#cwd --- Shell#dir --- Shell#getwd --- Shell#pwd Returns the current directory --- Shell#system_path Returns the command search path in an array --- Shell#umask Returns the umask == Filter Any result of command exection is a Filter. Filter include Enumerable, therefore a Filter object can use all Enumerable facilities. = Main methods == Command definitions In order to execute a command on your OS, you need to define it as a Shell method. Alternatively, you can execute any command via Shell#system even if it is not defined. --- Shell.def_system_command(command, path = command) Defines a command. Registers as a Shell method . ex) Shell.def_system_command "ls" Defines ls. Shell.def_system_command "sys_sort", "sort" Defines sys_sort as sort. --- Shell.undef_system_command(command) Undefines a commmand --- Shell.alias_command(ali, command, *opts) {...} Aliases a command. ex) Shell.alias_command "lsC", "ls", "-CBF", "--show-control-chars" Shell.alias_command("lsC", "ls"){|*opts| ["-CBF", "--show-control-chars", *opts]} --- Shell.unalias_command(ali) Unaliases a command. --- Shell.install_system_commands(pre = "sys_") Defines all commands in the default_system_path as Shell method, all with
 prefixed to their names.

== Creation

--- Shell.new

      Creates a Shell object which current directory is set to the
      process current directory.

--- Shell.cd(path)

      Creates a Shell object which current directory is set to
      .

== Process management

--- Shell#jobs

      Returns a list of scheduled jobs.

--- Shell#kill sig, job

      Sends a signal  to .

== Current directory operations

--- Shell#cd(path, &block)
--- Shell#chdir

      Changes the current directory to .  If a block is given,
      it restores the current directory when the block ends.

--- Shell#pushd(path = nil, &block)
--- Shell#pushdir

      Pushes the current directory to the directory stack, changing
      the current directory to .  If  is omitted, it
      exchanges its current directory and the top of its directory
      stack.  If a block is given, it restores the current directory
      when the block ends.

--- Shell#popd
--- Shell#popdir

      Pops a directory from the directory stack, and sets the current
      directory to it.

== File and directory operations

--- Shell#foreach(path = nil, &block)

      Same as:
        File#foreach (when path is a file)
        Dir#foreach (when path is a directory)

--- Shell#open(path, mode)

      Same as:
        File#open (when path is a file)
        Dir#open (when path is a directory)

--- Shell#unlink(path)

      Same as:
        Dir#open (when path is a file)
        Dir#unlink (when path is a directory)

--- Shell#test(command, file1, file2)
--- Shell#[command, file1, file2]

      Same as test().
      ex)
          sh[?e, "foo"]
          sh[:e, "foo"]
          sh["e", "foo"]
          sh[:exists?, "foo"]
          sh["exists?", "foo"]

--- Shell#mkdir(*path)

      Same as Dir.mkdir (with multiple directories allowed)

--- Shell#rmdir(*path)

      Same as Dir.rmdir (with multiple directories allowed)

== Command execution

--- System#system(command, *opts)

      Executes  with .

      ex)
        print sh.system("ls", "-l")
        sh.system("ls", "-l") | sh.head > STDOUT

--- System#rehash

      Does rehash.

--- Shell#transact &block

      Executes a block as self.
      ex)
        sh.transact{system("ls", "-l") | head > STDOUT}

--- Shell#out(dev = STDOUT, &block)

      Does transact, with redirecting the result output to .

== Internal commands

--- Shell#echo(*strings)
--- Shell#cat(*files)
--- Shell#glob(patten)
--- Shell#tee(file)

      Return Filter objects, which are results of their execution.

--- Filter#each &block

      Iterates a block for each line of it.

--- Filter#<(src)

      Inputs from , which is either a string of a file name or an
      IO.

--- Filter#>(to)

      Outputs to , which is either a string of a file name or an
      IO.

--- Filter#>>(to)

      Appends the ouput to , which is either a string of a file
      name or an IO.

--- Filter#|(filter)

      Processes a pipeline.

--- Filter#+(filter)

      (filter1 + filter2) outputs filter1, and then outputs filter2.

--- Filter#to_a
--- Filter#to_s

== Built-in commands

--- Shell#atime(file)
--- Shell#basename(file, *opt)
--- Shell#chmod(mode, *files)
--- Shell#chown(owner, group, *file)
--- Shell#ctime(file)
--- Shell#delete(*file)
--- Shell#dirname(file)
--- Shell#ftype(file)
--- Shell#join(*file)
--- Shell#link(file_from, file_to)
--- Shell#lstat(file)
--- Shell#mtime(file)
--- Shell#readlink(file)
--- Shell#rename(file_from, file_to)
--- Shell#split(file)
--- Shell#stat(file)
--- Shell#symlink(file_from, file_to)
--- Shell#truncate(file, length)
--- Shell#utime(atime, mtime, *file)

      Equivalent to the class methods of File with the same names.

--- Shell#blockdev?(file)
--- Shell#chardev?(file)
--- Shell#directory?(file)
--- Shell#executable?(file)
--- Shell#executable_real?(file)
--- Shell#exist?(file)/Shell#exists?(file)
--- Shell#file?(file)
--- Shell#grpowned?(file)
--- Shell#owned?(file)
--- Shell#pipe?(file)
--- Shell#readable?(file)
--- Shell#readable_real?(file)
--- Shell#setgid?(file)
--- Shell#setuid?(file)
--- Shell#size(file)/Shell#size?(file)
--- Shell#socket?(file)
--- Shell#sticky?(file)
--- Shell#symlink?(file)
--- Shell#writable?(file)
--- Shell#writable_real?(file)
--- Shell#zero?(file)

      Equivalent to the class methods of FileTest with the same names.

--- Shell#syscopy(filename_from, filename_to)
--- Shell#copy(filename_from, filename_to)
--- Shell#move(filename_from, filename_to)
--- Shell#compare(filename_from, filename_to)
--- Shell#safe_unlink(*filenames)
--- Shell#makedirs(*filenames)
--- Shell#install(filename_from, filename_to, mode)

      Equivalent to the class methods of FileTools with the same
      names.

      And also, there are some aliases for convenience:

--- Shell#cmp	<- Shell#compare
--- Shell#mv	<- Shell#move
--- Shell#cp	<- Shell#copy
--- Shell#rm_f	<- Shell#safe_unlink
--- Shell#mkpath	<- Shell#makedirs

= Samples

== ex1

  sh = Shell.cd("/tmp")
  sh.mkdir "shell-test-1" unless sh.exists?("shell-test-1")
  sh.cd("shell-test-1")
  for dir in ["dir1", "dir3", "dir5"]
    if !sh.exists?(dir)
      sh.mkdir dir
      sh.cd(dir) do
	f = sh.open("tmpFile", "w")
	f.print "TEST\n"
	f.close
      end
      print sh.pwd
    end
  end

== ex2

  sh = Shell.cd("/tmp")
  sh.transact do
    mkdir "shell-test-1" unless exists?("shell-test-1")
    cd("shell-test-1")
    for dir in ["dir1", "dir3", "dir5"]
      if !exists?(dir)
	mkdir dir
	cd(dir) do
	  f = open("tmpFile", "w")
	  f.print "TEST\n"
	  f.close
	end
	print pwd
      end
    end
  end

== ex3

  sh.cat("/etc/printcap") | sh.tee("tee1") > "tee2"
  (sh.cat < "/etc/printcap") | sh.tee("tee11") > "tee12"
  sh.cat("/etc/printcap") | sh.tee("tee1") >> "tee2"
  (sh.cat < "/etc/printcap") | sh.tee("tee11") >> "tee12"

== ex4

  print sh.cat("/etc/passwd").head.collect{|l| l =~ /keiju/}

=end


================================================
FILE: doc/shell.rd.ja
================================================
 -- shell.rb
				$Release Version: 0.6.0 $
			   	$Revision$
			   	$Date$
			   	by Keiju ISHITSUKA(keiju@ishitsuka.com)

=begin

= Ū

rubysh/cshΤ褦˥ޥɤμ¹Եڤӥե륿󥰤ڤ˹Ԥ.
sh/cshʸrubyεǽѤƼ¸.

= ʥ饹

== Shell

Shell֥Ȥϥȥǥ쥯ȥ, ޥɼ¹ԤϤ
Хѥˤʤޤ.

--- Shell#cwd
--- Shell#dir
--- Shell#getwd
--- Shell#pwd

      ȥǥ쥯ȥ֤

--- Shell#system_path

      ޥɥѥ֤

--- Shell#umask

      umask֤

== Filter

ޥɤμ¹Է̤Ϥ٤FilterȤƤޤ. Enumerableinclude
Ƥޤ.

= ʥ᥽åɰ

== ޥ

OSΥޥɤ¹ԤˤϤޤ, ShellΥ᥽åɤȤޤ.

) ޥɤʤȤľܼ¹ԤǤShell#systemޥɤ⤢ޤ.

--- Shell.def_system_command(command, path = command)

      ShellΥ᥽åɤȤcommandϿޤ. 

      )
      Shell.def_system_command "ls"
        ls 

      Shell.def_system_command "sys_sort", "sort"
        sortޥɤsys_sortȤ

--- Shell.undef_system_command(command)

      commandޤ.

--- Shell.alias_command(ali, command, *opts) {...}

      commandalias򤷤ޤ. 

      )
        Shell.alias_command "lsC", "ls", "-CBF", "--show-control-chars"
        Shell.alias_command("lsC", "ls"){|*opts| ["-CBF", "--show-control-chars", *opts]}

--- Shell.unalias_command(ali)

      commandaliasޤ.

--- Shell.install_system_commands(pre = "sys_")

      system_pathˤƤμ¹ԲǽեShell. ᥽
      ̾ϸΥե̾ƬpreĤΤȤʤ.

== 

--- Shell.new

      ץΥȥǥ쥯ȥ򥫥ȥǥ쥯ȥȤShell
      ֥Ȥޤ.

--- Shell.cd(path)

      path򥫥ȥǥ쥯ȥȤShell֥Ȥޤ.

== ץ

--- Shell#jobs

      塼󥰤Ƥjobΰ֤.

--- Shell#kill sig, job

      job˥ʥsig

== ȥǥ쥯ȥ

--- Shell#cd(path, &block)
--- Shell#chdir

      ȥǥ쥯ȥpathˤ. ƥ졼ȤƸƤФ줿Ȥˤ
      ֥å¹Τߥȥǥ쥯ȥѹ.

--- Shell#pushd(path = nil, &block)
--- Shell#pushdir

      ȥǥ쥯ȥǥ쥯ȥꥹåˤĤ, ȥǥ쥯
      ȥpathˤ. pathά줿Ȥˤ, ȥǥ쥯ȥ
      ǥ쥯ȥꥹåΥȥåפ򴹤. ƥ졼ȤƸƤФ줿
      ˤ, ֥å¹Τpushd.

--- Shell#popd
--- Shell#popdir

      ǥ쥯ȥꥹåݥåפ, 򥫥ȥǥ쥯ȥˤ.

== ե/ǥ쥯ȥ

--- Shell#foreach(path = nil, &block)

      pathեʤ, File#foreach
      pathǥ쥯ȥʤ, Dir#foreach

--- Shell#open(path, mode)

      pathեʤ, File#open
      pathǥ쥯ȥʤ, Dir#open

--- Shell#unlink(path)

      pathեʤ, File#unlink
      pathǥ쥯ȥʤ, Dir#unlink

--- Shell#test(command, file1, file2)
--- Shell#[command, file1, file2]

      եƥȴؿtestƱ. 
      )
          sh[?e, "foo"]
          sh[:e, "foo"]
          sh["e", "foo"]
          sh[:exists?, "foo"]
          sh["exists?", "foo"]

--- Shell#mkdir(*path)

      Dir.mkdirƱ(ʣ)

--- Shell#rmdir(*path)

      Dir.rmdirƱ(ʣ)

== ޥɼ¹

--- System#system(command, *opts)

      command¹Ԥ.
      )
        print sh.system("ls", "-l")
        sh.system("ls", "-l") | sh.head > STDOUT

--- System#rehash

      ϥå夹

--- Shell#transact &block

      ֥åǤshellselfȤƼ¹Ԥ.
      )
        sh.transact{system("ls", "-l") | head > STDOUT}

--- Shell#out(dev = STDOUT, &block)

      transactƤӽФη̤dev˽Ϥ.

== ޥ

--- Shell#echo(*strings)
--- Shell#cat(*files)
--- Shell#glob(patten)
--- Shell#tee(file)

      ϼ¹Ԥ, ƤȤFilter֥Ȥ֤ޤ. 

--- Filter#each &block

      ե륿ΰԤĤblockϤ.

--- Filter#<(src)

      srcե륿ϤȤ. src, ʸʤХե, IOǤ
      Ф򤽤ΤޤϤȤ.

--- Filter#>(to)

      srcե륿νϤȤ. to, ʸʤХե, IOǤ
      Ф򤽤Τޤ޽ϤȤ.

--- Filter#>>(to)

      srcե륿ɲä. to, ʸʤХե, IOǤ
      򤽤Τޤ޽ϤȤ.

--- Filter#|(filter)

      ѥ׷

--- Filter#+(filter)

      filter1 + filter2  filter1νϤθ, filter2νϤԤ.

--- Filter#to_a
--- Filter#to_s

== ȹߥޥ

--- Shell#atime(file)
--- Shell#basename(file, *opt)
--- Shell#chmod(mode, *files)
--- Shell#chown(owner, group, *file)
--- Shell#ctime(file)
--- Shell#delete(*file)
--- Shell#dirname(file)
--- Shell#ftype(file)
--- Shell#join(*file)
--- Shell#link(file_from, file_to)
--- Shell#lstat(file)
--- Shell#mtime(file)
--- Shell#readlink(file)
--- Shell#rename(file_from, file_to)
--- Shell#split(file)
--- Shell#stat(file)
--- Shell#symlink(file_from, file_to)
--- Shell#truncate(file, length)
--- Shell#utime(atime, mtime, *file)

      File饹ˤƱ̾Υ饹᥽åɤƱǤ.

--- Shell#blockdev?(file)
--- Shell#chardev?(file)
--- Shell#directory?(file)
--- Shell#executable?(file)
--- Shell#executable_real?(file)
--- Shell#exist?(file)/Shell#exists?(file)
--- Shell#file?(file)
--- Shell#grpowned?(file)
--- Shell#owned?(file)
--- Shell#pipe?(file)
--- Shell#readable?(file)
--- Shell#readable_real?(file)
--- Shell#setgid?(file)
--- Shell#setuid?(file)
--- Shell#size(file)/Shell#size?(file)
--- Shell#socket?(file)
--- Shell#sticky?(file)
--- Shell#symlink?(file)
--- Shell#writable?(file)
--- Shell#writable_real?(file)
--- Shell#zero?(file)

      FileTest饹ˤƱ̾Υ饹᥽åɤƱǤ.

--- Shell#syscopy(filename_from, filename_to)
--- Shell#copy(filename_from, filename_to)
--- Shell#move(filename_from, filename_to)
--- Shell#compare(filename_from, filename_to)
--- Shell#safe_unlink(*filenames)
--- Shell#makedirs(*filenames)
--- Shell#install(filename_from, filename_to, mode)

      FileTools饹ˤƱ̾Υ饹᥽åɤƱǤ.

      ¾, ʲΤΤꥢƤޤ.

--- Shell#cmp	<- Shell#compare
--- Shell#mv	<- Shell#move
--- Shell#cp	<- Shell#copy
--- Shell#rm_f	<- Shell#safe_unlink
--- Shell#mkpath	<- Shell#makedirs

= ץ

== ex1

  sh = Shell.cd("/tmp")
  sh.mkdir "shell-test-1" unless sh.exists?("shell-test-1")
  sh.cd("shell-test-1")
  for dir in ["dir1", "dir3", "dir5"]
    if !sh.exists?(dir)
      sh.mkdir dir
      sh.cd(dir) do
	f = sh.open("tmpFile", "w")
	f.print "TEST\n"
	f.close
      end
      print sh.pwd
    end
  end

== ex2

  sh = Shell.cd("/tmp")
  sh.transact do
    mkdir "shell-test-1" unless exists?("shell-test-1")
    cd("shell-test-1")
    for dir in ["dir1", "dir3", "dir5"]
      if !exists?(dir)
	mkdir dir
	cd(dir) do
	  f = open("tmpFile", "w")
	  f.print "TEST\n"
	  f.close
	end
	print pwd
      end
    end
  end

== ex3

  sh.cat("/etc/printcap") | sh.tee("tee1") > "tee2"
  (sh.cat < "/etc/printcap") | sh.tee("tee11") > "tee12"
  sh.cat("/etc/printcap") | sh.tee("tee1") >> "tee2"
  (sh.cat < "/etc/printcap") | sh.tee("tee11") >> "tee12"

== ex4

  print sh.cat("/etc/passwd").head.collect{|l| l =~ /keiju/}

=end


================================================
FILE: enum.c
================================================
/**********************************************************************

  enum.c -

  $Author$
  $Date$
  created at: Fri Oct  1 15:15:19 JST 1993

  Copyright (C) 1993-2003 Yukihiro Matsumoto

**********************************************************************/

#include "ruby.h"
#include "node.h"
#include "util.h"

VALUE rb_mEnumerable;
static ID id_each, id_eqq, id_cmp, id_size;

struct iter_method_arg {
    VALUE obj;
    ID mid;
    int argc;
    VALUE *argv;
};

static VALUE iterate_method _((VALUE obj));
static VALUE
iterate_method(obj)
    VALUE obj;
{
    struct iter_method_arg *arg;

    arg = (struct iter_method_arg *)obj;
    return rb_funcall2(arg->obj, arg->mid, arg->argc, arg->argv);
}

VALUE
rb_block_call(obj, mid, argc, argv, bl_proc, data2)
    VALUE obj;
    ID mid;
    int argc;
    VALUE *argv;
    VALUE (*bl_proc) (ANYARGS);
    VALUE data2;
{
    struct iter_method_arg arg;

    arg.obj = obj;
    arg.mid = mid;
    arg.argc = argc;
    arg.argv = argv;
    return rb_iterate(iterate_method, (VALUE)&arg, bl_proc, data2);
}

VALUE
rb_each(obj)
    VALUE obj;
{
    return rb_funcall(obj, id_each, 0, 0);
}

static VALUE
grep_i(i, arg)
    VALUE i, *arg;
{
    if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) {
	rb_ary_push(arg[1], i);
    }
    return Qnil;
}

static VALUE
grep_iter_i(i, arg)
    VALUE i, *arg;
{
    if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) {
	rb_ary_push(arg[1], rb_yield(i));
    }
    return Qnil;
}

/*
 *  call-seq:
 *     enum.grep(pattern)                   => array
 *     enum.grep(pattern) {| obj | block }  => array
 *
 *  Returns an array of every element in enum for which
 *  Pattern === element. If the optional block is
 *  supplied, each matching element is passed to it, and the block's
 *  result is stored in the output array.
 *
 *     (1..100).grep 38..44   #=> [38, 39, 40, 41, 42, 43, 44]
 *     c = IO.constants
 *     c.grep(/SEEK/)         #=> ["SEEK_END", "SEEK_SET", "SEEK_CUR"]
 *     res = c.grep(/SEEK/) {|v| IO.const_get(v) }
 *     res                    #=> [2, 0, 1]
 *
 */

static VALUE
enum_grep(obj, pat)
    VALUE obj, pat;
{
    VALUE ary = rb_ary_new();
    VALUE arg[2];

    arg[0] = pat;
    arg[1] = ary;

    rb_iterate(rb_each, obj, rb_block_given_p() ? grep_iter_i : grep_i, (VALUE)arg);

    return ary;
}

static VALUE count_i _((VALUE, VALUE));
static VALUE
count_i(i, memop)
    VALUE i, memop;
{
    VALUE *memo = (VALUE*)memop;

    if (rb_equal(i, memo[1])) {
	memo[0]++;
    }
    return Qnil;
}

static VALUE count_iter_i _((VALUE, VALUE));
static VALUE
count_iter_i(i, memop)
    VALUE i, memop;
{
    VALUE *memo = (VALUE*)memop;

    if (RTEST(rb_yield(i))) {
	memo[0]++;
    }
    return Qnil;
}

static VALUE count_all_i _((VALUE, VALUE));
static VALUE
count_all_i(i, memop)
    VALUE i, memop;
{
    VALUE *memo = (VALUE*)memop;

    memo[0]++;
    return Qnil;
}

/*
 *  call-seq:
 *     enum.count                   => int
 *     enum.count(item)             => int
 *     enum.count {| obj | block }  => int
 *
 *  Returns the number of items in enum, where #size is called
 *  if it responds to it, otherwise the items are counted through
 *  enumeration.  If an argument is given, counts the number of items
 *  in enum, for which equals to item.  If a block is
 *  given, counts the number of elements yielding a true value.
 *
 *     ary = [1, 2, 4, 2]
 *     ary.count             # => 4
 *     ary.count(2)          # => 2
 *     ary.count{|x|x%2==0}  # => 3
 *
 */

static VALUE
enum_count(argc, argv, obj)
    int argc;
    VALUE *argv;
    VALUE obj;
{
    VALUE memo[2];	/* [count, condition value] */
    rb_block_call_func *func;

    if (argc == 0) {
	if (rb_block_given_p()) {
	    func = count_iter_i;
	}
	else {
	    if (rb_respond_to(obj, id_size)) {
		return rb_funcall(obj, id_size, 0, 0);
	    }
	    func = count_all_i;
	}
    }
    else {
	rb_scan_args(argc, argv, "1", &memo[1]);
	if (rb_block_given_p()) {
	    rb_warn("given block not used");
	}
        func = count_i;
    }

    memo[0] = 0;
    rb_block_call(obj, id_each, 0, 0, func, (VALUE)&memo);
    return INT2NUM(memo[0]);
}

static VALUE
find_i(i, memo)
    VALUE i;
    VALUE *memo;
{
    if (RTEST(rb_yield(i))) {
	*memo = i;
	rb_iter_break();
    }
    return Qnil;
}

/*
 *  call-seq:
 *     enum.detect(ifnone = nil) {| obj | block }  => obj or nil
 *     enum.find(ifnone = nil)   {| obj | block }  => obj or nil
 *
 *  Passes each entry in enum to block. Returns the
 *  first for which block is not false.  If no
 *  object matches, calls ifnone and returns its result when it
 *  is specified, or returns nil
 *
 *     (1..10).detect  {|i| i % 5 == 0 and i % 7 == 0 }   #=> nil
 *     (1..100).detect {|i| i % 5 == 0 and i % 7 == 0 }   #=> 35
 *
 */

static VALUE
enum_find(argc, argv, obj)
    int argc;
    VALUE* argv;
    VALUE obj;
{
    VALUE memo = Qundef;
    VALUE if_none;

    rb_scan_args(argc, argv, "01", &if_none);
    RETURN_ENUMERATOR(obj, argc, argv);
    rb_iterate(rb_each, obj, find_i, (VALUE)&memo);
    if (memo != Qundef) {
	return memo;
    }
    if (!NIL_P(if_none)) {
	return rb_funcall(if_none, rb_intern("call"), 0, 0);
    }
    return Qnil;
}

static VALUE find_index_i _((VALUE, VALUE));
static VALUE
find_index_i(i, memop)
    VALUE i;
    VALUE memop;
{
    VALUE *memo = (VALUE*)memop;

    if (rb_equal(i, memo[2])) {
	memo[0] = UINT2NUM(memo[1]);
	rb_iter_break();
    }
    memo[1]++;
    return Qnil;
}

static VALUE find_index_iter_i _((VALUE, VALUE));
static VALUE
find_index_iter_i(i, memop)
    VALUE i;
    VALUE memop;
{
    VALUE *memo = (VALUE*)memop;

    if (RTEST(rb_yield(i))) {
	memo[0] = UINT2NUM(memo[1]);
	rb_iter_break();
    }
    memo[1]++;
    return Qnil;
}

/*
 *  call-seq:
 *     enum.find_index(value)            => int or nil
 *     enum.find_index {| obj | block }  => int or nil
 *
 *  Compares each entry in enum with value or passes
 *  to block.  Returns the index for the first for which the
 *  evaluated value is non-false.  If no object matches, returns
 *  nil
 *
 *     (1..10).find_index  {|i| i % 5 == 0 and i % 7 == 0 }   #=> nil
 *     (1..100).find_index {|i| i % 5 == 0 and i % 7 == 0 }   #=> 34
 *     (1..100).find_index(50)                                #=> 49
 *
 */

static VALUE
enum_find_index(argc, argv, obj)
    int argc;
    VALUE *argv;
    VALUE obj;
{
    VALUE memo[3];	/* [return value, current index, condition value] */
    rb_block_call_func *func;

    if (argc == 0) {
        RETURN_ENUMERATOR(obj, 0, 0);
        func = find_index_iter_i;
    }
    else {
	rb_scan_args(argc, argv, "1", &memo[2]);
	if (rb_block_given_p()) {
	    rb_warn("given block not used");
	}
        func = find_index_i;
    }

    memo[0] = Qnil;
    memo[1] = 0;
    rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo);
    return memo[0];
}

static VALUE
find_all_i(i, ary)
    VALUE i, ary;
{
    if (RTEST(rb_yield(i))) {
	rb_ary_push(ary, i);
    }
    return Qnil;
}

/*
 *  call-seq:
 *     enum.find_all {| obj | block }  => array
 *     enum.select   {| obj | block }  => array
 *
 *  Returns an array containing all elements of enum for which
 *  block is not false (see also
 *  Enumerable#reject).
 *
 *     (1..10).find_all {|i|  i % 3 == 0 }   #=> [3, 6, 9]
 *
 */

static VALUE
enum_find_all(obj)
    VALUE obj;
{
    VALUE ary = rb_ary_new();

    RETURN_ENUMERATOR(obj, 0, 0);
    rb_iterate(rb_each, obj, find_all_i, ary);

    return ary;
}

static VALUE
reject_i(i, ary)
    VALUE i, ary;
{
    if (!RTEST(rb_yield(i))) {
	rb_ary_push(ary, i);
    }
    return Qnil;
}

/*
 *  call-seq:
 *     enum.reject {| obj | block }  => array
 *
 *  Returns an array for all elements of enum for which
 *  block is false (see also Enumerable#find_all).
 *
 *     (1..10).reject {|i|  i % 3 == 0 }   #=> [1, 2, 4, 5, 7, 8, 10]
 *
 */

static VALUE
enum_reject(obj)
    VALUE obj;
{
    VALUE ary = rb_ary_new();

    RETURN_ENUMERATOR(obj, 0, 0);
    rb_iterate(rb_each, obj, reject_i, ary);

    return ary;
}

static VALUE
collect_i(i, ary)
    VALUE i, ary;
{
    rb_ary_push(ary, rb_yield(i));

    return Qnil;
}

static VALUE
collect_all(i, ary)
    VALUE i, ary;
{
    rb_ary_push(ary, i);

    return Qnil;
}

/*
 *  call-seq:
 *     enum.collect {| obj | block }  => array
 *     enum.map     {| obj | block }  => array
 *
 *  Returns a new array with the results of running block once
 *  for every element in enum.
 *
 *     (1..4).collect {|i| i*i }   #=> [1, 4, 9, 16]
 *     (1..4).collect { "cat"  }   #=> ["cat", "cat", "cat", "cat"]
 *
 */

static VALUE
enum_collect(obj)
    VALUE obj;
{
    VALUE ary = rb_ary_new();

    rb_iterate(rb_each, obj, rb_block_given_p() ? collect_i : collect_all, ary);

    return ary;
}

/*
 *  call-seq:
 *     enum.to_a      =>    array
 *     enum.entries   =>    array
 *
 *  Returns an array containing the items in enum.
 *
 *     (1..7).to_a                       #=> [1, 2, 3, 4, 5, 6, 7]
 *     { 'a'=>1, 'b'=>2, 'c'=>3 }.to_a   #=> [["a", 1], ["b", 2], ["c", 3]]
 */
static VALUE
enum_to_a(argc, argv, obj)
    int argc;
    VALUE *argv;
    VALUE obj;
{
    VALUE ary = rb_ary_new();

    rb_block_call(obj, id_each, argc, argv, collect_all, ary);

    return ary;
}

static VALUE inject_i _((VALUE, VALUE));
static VALUE
inject_i(i, p)
    VALUE i;
    VALUE p;
{
    VALUE *memo = (VALUE *)p;
    if (memo[0] == Qundef) {
	memo[0] = i;
    }
    else {
	memo[0] = rb_yield_values(2, memo[0], i);
    }
    return Qnil;
}

static VALUE inject_op_i _((VALUE, VALUE));
static VALUE
inject_op_i(i, p)
    VALUE i;
    VALUE p;
{
    VALUE *memo = (VALUE *)p;

    if (memo[0] == Qundef) {
	memo[0] = i;
    }
    else {
	memo[0] = rb_funcall(memo[0], (ID)memo[1], 1, i);
    }
    return Qnil;
}

/*
 *  call-seq:
 *     enum.inject(initial, sym) => obj
 *     enum.inject(sym)          => obj
 *     enum.inject(initial) {| memo, obj | block }  => obj
 *     enum.inject          {| memo, obj | block }  => obj
 *
 *     enum.reduce(initial, sym) => obj
 *     enum.reduce(sym)          => obj
 *     enum.reduce(initial) {| memo, obj | block }  => obj
 *     enum.reduce          {| memo, obj | block }  => obj
 *
 *  Combines all elements of enum by applying a binary
 *  operation, specified by a block or a symbol that names a
 *  method or operator.
 *
 *  If you specify a block, then for each element in enum
 *  the block is passed an accumulator value (memo) and the element.
 *  If you specify a symbol instead, then each element in the collection
 *  will be passed to the named method of memo.
 *  In either case, the result becomes the new value for memo.
 *  At the end of the iteration, the final value of memo is the
 *  return value fo the method.
 *
 *  If you do not explicitly specify an initial value for memo,
 *  then uses the first element of collection is used as the initial value
 *  of memo.
 *
 *  Examples:
 *
 *     # Sum some numbers
 *     (5..10).reduce(:+)                            #=> 45
 *     # Same using a block and inject
 *     (5..10).inject {|sum, n| sum + n }            #=> 45
 *     # Multiply some numbers
 *     (5..10).reduce(1, :*)                         #=> 151200
 *     # Same using a block
 *     (5..10).inject(1) {|product, n| product * n } #=> 151200
 *     # find the longest word
 *     longest = %w{ cat sheep bear }.inject do |memo,word|
 *        memo.length > word.length ? memo : word
 *     end
 *     longest                                       #=> "sheep"
 *
 */
static VALUE
enum_inject(argc, argv, obj)
    int argc;
    VALUE *argv;
    VALUE obj;
{
    VALUE memo[2];
    rb_block_call_func *iter = inject_i;

    switch (rb_scan_args(argc, argv, "02", &memo[0], &memo[1])) {
      case 0:
	memo[0] = Qundef;
	break;
      case 1:
	if (rb_block_given_p()) {
	    break;
	}
	memo[1] = (VALUE)rb_to_id(memo[0]);
	memo[0] = Qundef;
	iter = inject_op_i;
	break;
      case 2:
	if (rb_block_given_p()) {
	    rb_warning("given block not used");
	}
	memo[1] = (VALUE)rb_to_id(memo[1]);
	iter = inject_op_i;
	break;
    }
    rb_block_call(obj, id_each, 0, 0, iter, (VALUE)memo);
    if (memo[0] == Qundef) return Qnil;
    return memo[0];
}

static VALUE
partition_i(i, ary)
    VALUE i, *ary;
{
    if (RTEST(rb_yield(i))) {
	rb_ary_push(ary[0], i);
    }
    else {
	rb_ary_push(ary[1], i);
    }
    return Qnil;
}

/*
 *  call-seq:
 *     enum.partition {| obj | block }  => [ true_array, false_array ]
 *
 *  Returns two arrays, the first containing the elements of
 *  enum for which the block evaluates to true, the second
 *  containing the rest.
 *
 *     (1..6).partition {|i| (i&1).zero?}   #=> [[2, 4, 6], [1, 3, 5]]
 *
 */

static VALUE
enum_partition(obj)
    VALUE obj;
{
    VALUE ary[2];

    RETURN_ENUMERATOR(obj, 0, 0);

    ary[0] = rb_ary_new();
    ary[1] = rb_ary_new();
    rb_iterate(rb_each, obj, partition_i, (VALUE)ary);

    return rb_assoc_new(ary[0], ary[1]);
}

static VALUE
group_by_i(i, hash)
    VALUE i;
    VALUE hash;
{
    VALUE group = rb_yield(i);
    VALUE values;

    values = rb_hash_aref(hash, group);
    if (NIL_P(values)) {
	values = rb_ary_new3(1, i);
	rb_hash_aset(hash, group, values);
    }
    else {
	rb_ary_push(values, i);
    }
    return Qnil;
}

/*
 *  call-seq:
 *     enum.group_by {| obj | block }  => a_hash
 *
 *  Returns a hash, which keys are evaluated result from the
 *  block, and values are arrays of elements in enum
 *  corresponding to the key.
 *
 *     (1..6).group_by {|i| i%3}   #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
 *
 */

static VALUE
enum_group_by(obj)
    VALUE obj;
{
    VALUE hash;

    RETURN_ENUMERATOR(obj, 0, 0);

    hash = rb_hash_new();
    rb_block_call(obj, id_each, 0, 0, group_by_i, hash);

    return hash;
}

static VALUE
first_i(i, ary)
    VALUE i;
    VALUE *ary;
{
    if (NIL_P(ary[0])) {
	ary[1] = i;
	rb_iter_break();
    }
    else {
	long n = NUM2LONG(ary[0]);

	rb_ary_push(ary[1], i);
	n--;
	if (n <= 0) {
	    rb_iter_break();
	}
	ary[0] = INT2NUM(n);
    }
    return Qnil;
}

/*
 *  call-seq:
 *     enum.first      -> obj or nil
 *     enum.first(n)   -> an_array
 *
 *  Returns the first element, or the first +n+ elements, of the enumerable.
 *  If the enumerable is empty, the first form returns nil, and the
 *  second form returns an empty array.
 *
 */

static VALUE
enum_first(argc, argv, obj)
    int argc;
    VALUE *argv;
    VALUE obj;
{
    VALUE n, ary[2];

    if (argc == 0) {
	ary[0] = ary[1] = Qnil;
    }
    else {
	long len;
	rb_scan_args(argc, argv, "01", &n);
	len = NUM2LONG(n);
	if (len == 0) return rb_ary_new2(0);
	ary[0] = INT2NUM(len);
	ary[1] = rb_ary_new2(len);
    }
    rb_block_call(obj, id_each, 0, 0, first_i, (VALUE)ary);

    return ary[1];
}


/*
 *  call-seq:
 *     enum.sort                     => array
 *     enum.sort {| a, b | block }   => array
 *
 *  Returns an array containing the items in enum sorted,
 *  either according to their own <=> method, or by using
 *  the results of the supplied block. The block should return -1, 0, or
 *  +1 depending on the comparison between a and b. As of
 *  Ruby 1.8, the method Enumerable#sort_by implements a
 *  built-in Schwartzian Transform, useful when key computation or
 *  comparison is expensive..
 *
 *     %w(rhea kea flea).sort         #=> ["flea", "kea", "rhea"]
 *     (1..10).sort {|a,b| b <=> a}   #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
 */

static VALUE
enum_sort(obj)
    VALUE obj;
{
    return rb_ary_sort(enum_to_a(0, 0, obj));
}

static VALUE
sort_by_i(i, ary)
    VALUE i, ary;
{
    VALUE v;
    NODE *memo;

    v = rb_yield(i);
    if (RBASIC(ary)->klass) {
	rb_raise(rb_eRuntimeError, "sort_by reentered");
    }
    memo = NEW_NODE_EDEN(NODE_MEMO, v, i, 0);
    rb_ary_push(ary, (VALUE)memo);
    return Qnil;
}

static int
sort_by_cmp(aa, bb, data)
    NODE **aa, **bb;
    void *data;
{
    VALUE a = aa[0]->u1.value;
    VALUE b = bb[0]->u1.value;
    VALUE ary = (VALUE)data;

    if (RBASIC(ary)->klass) {
	rb_raise(rb_eRuntimeError, "sort_by reentered");
    }
    return rb_cmpint(rb_funcall(a, id_cmp, 1, b), a, b);
}

/*
 *  call-seq:
 *     enum.sort_by {| obj | block }    => array
 *
 *  Sorts enum using a set of keys generated by mapping the
 *  values in enum through the given block.
 *
 *     %w{ apple pear fig }.sort_by {|word| word.length}
                    #=> ["fig", "pear", "apple"]
 *
 *  The current implementation of sort_by generates an
 *  array of tuples containing the original collection element and the
 *  mapped value. This makes sort_by fairly expensive when
 *  the keysets are simple
 *
 *     require 'benchmark'
 *     include Benchmark
 *
 *     a = (1..100000).map {rand(100000)}
 *
 *     bm(10) do |b|
 *       b.report("Sort")    { a.sort }
 *       b.report("Sort by") { a.sort_by {|a| a} }
 *     end
 *
 *  produces:
 *
 *     user     system      total        real
 *     Sort        0.180000   0.000000   0.180000 (  0.175469)
 *     Sort by     1.980000   0.040000   2.020000 (  2.013586)
 *
 *  However, consider the case where comparing the keys is a non-trivial
 *  operation. The following code sorts some files on modification time
 *  using the basic sort method.
 *
 *     files = Dir["*"]
 *     sorted = files.sort {|a,b| File.new(a).mtime <=> File.new(b).mtime}
 *     sorted   #=> ["mon", "tues", "wed", "thurs"]
 *
 *  This sort is inefficient: it generates two new File
 *  objects during every comparison. A slightly better technique is to
 *  use the Kernel#test method to generate the modification
 *  times directly.
 *
 *     files = Dir["*"]
 *     sorted = files.sort { |a,b|
 *       test(?M, a) <=> test(?M, b)
 *     }
 *     sorted   #=> ["mon", "tues", "wed", "thurs"]
 *
 *  This still generates many unnecessary Time objects. A
 *  more efficient technique is to cache the sort keys (modification
 *  times in this case) before the sort. Perl users often call this
 *  approach a Schwartzian Transform, after Randal Schwartz. We
 *  construct a temporary array, where each element is an array
 *  containing our sort key along with the filename. We sort this array,
 *  and then extract the filename from the result.
 *
 *     sorted = Dir["*"].collect { |f|
 *        [test(?M, f), f]
 *     }.sort.collect { |f| f[1] }
 *     sorted   #=> ["mon", "tues", "wed", "thurs"]
 *
 *  This is exactly what sort_by does internally.
 *
 *     sorted = Dir["*"].sort_by {|f| test(?M, f)}
 *     sorted   #=> ["mon", "tues", "wed", "thurs"]
 */

static VALUE
enum_sort_by(obj)
    VALUE obj;
{
    VALUE ary;
    long i;

    RETURN_ENUMERATOR(obj, 0, 0);

    if (TYPE(obj) == T_ARRAY) {
	ary  = rb_ary_new2(RARRAY(obj)->len);
    }
    else {
	ary = rb_ary_new();
    }
    RBASIC(ary)->klass = 0;
    rb_iterate(rb_each, obj, sort_by_i, ary);
    if (RARRAY(ary)->len > 1) {
	qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE),
	      sort_by_cmp, (void *)ary);
    }
    if (RBASIC(ary)->klass) {
	rb_raise(rb_eRuntimeError, "sort_by reentered");
    }
    for (i=0; ilen; i++) {
	RARRAY(ary)->ptr[i] = RNODE(RARRAY(ary)->ptr[i])->u2.value;
    }
    RBASIC(ary)->klass = rb_cArray;
    return ary;
}

static VALUE
all_i(i, memo)
    VALUE i;
    VALUE *memo;
{
    if (!RTEST(i)) {
	*memo = Qfalse;
	rb_iter_break();
    }
    return Qnil;
}

static VALUE
all_iter_i(i, memo)
    VALUE i;
    VALUE *memo;
{
    return all_i(rb_yield(i), memo);
}

/*
 *  call-seq:
 *     enum.all? [{|obj| block } ]   => true or false
 *
 *  Passes each element of the collection to the given block. The method
 *  returns true if the block never returns
 *  false or nil. If the block is not given,
 *  Ruby adds an implicit block of {|obj| obj} (that is
 *  all? will return true only if none of the
 *  collection members are false or nil.)
 *
 *     %w{ ant bear cat}.all? {|word| word.length >= 3}   #=> true
 *     %w{ ant bear cat}.all? {|word| word.length >= 4}   #=> false
 *     [ nil, true, 99 ].all?                             #=> false
 *
 */

static VALUE
enum_all(obj)
    VALUE obj;
{
    VALUE result = Qtrue;

    rb_iterate(rb_each, obj, rb_block_given_p() ? all_iter_i : all_i, (VALUE)&result);
    return result;
}

static VALUE
any_i(i, memo)
    VALUE i;
    VALUE *memo;
{
    if (RTEST(i)) {
	*memo = Qtrue;
	rb_iter_break();
    }
    return Qnil;
}

static VALUE
any_iter_i(i, memo)
    VALUE i;
    VALUE *memo;
{
    return any_i(rb_yield(i), memo);
}

/*
 *  call-seq:
 *     enum.any? [{|obj| block } ]   => true or false
 *
 *  Passes each element of the collection to the given block. The method
 *  returns true if the block ever returns a value other
 *  than false or nil. If the block is not
 *  given, Ruby adds an implicit block of {|obj| obj} (that
 *  is any? will return true if at least one
 *  of the collection members is not false or
 *  nil.
 *
 *     %w{ ant bear cat}.any? {|word| word.length >= 3}   #=> true
 *     %w{ ant bear cat}.any? {|word| word.length >= 4}   #=> true
 *     [ nil, true, 99 ].any?                             #=> true
 *
 */

static VALUE
enum_any(obj)
    VALUE obj;
{
    VALUE result = Qfalse;

    rb_iterate(rb_each, obj, rb_block_given_p() ? any_iter_i : any_i, (VALUE)&result);
    return result;
}

static VALUE
one_i(i, memo)
    VALUE i;
    VALUE *memo;
{
    if (RTEST(i)) {
	if (*memo == Qundef) {
	    *memo = Qtrue;
	}
	else if (*memo == Qtrue) {
	    *memo = Qfalse;
	    rb_iter_break();
	}
    }
    return Qnil;
}

static VALUE
one_iter_i(i, memo)
    VALUE i;
    VALUE *memo;
{
    return one_i(rb_yield(i), memo);
}

/*
 *  call-seq:
 *     enum.one? [{|obj| block }]   => true or false
 *
 *  Passes each element of the collection to the given block. The method
 *  returns true if the block returns true
 *  exactly once. If the block is not given, one? will return
 *  true only if exactly one of the collection members is
 *  true.
 *
 *     %w{ant bear cat}.one? {|word| word.length == 4}   #=> true
 *     %w{ant bear cat}.one? {|word| word.length > 4}    #=> false
 *     %w{ant bear cat}.one? {|word| word.length < 4}    #=> false
 *     [ nil, true, 99 ].one?                            #=> false
 *     [ nil, true, false ].one?                         #=> true
 *
 */

static VALUE
enum_one(obj)
    VALUE obj;
{
    VALUE result = Qundef;

    rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? one_iter_i : one_i, (VALUE)&result);
    if (result == Qundef) return Qfalse;
    return result;
}

static VALUE
none_i(i, memo)
    VALUE i;
    VALUE *memo;
{
    if (RTEST(i)) {
	*memo = Qfalse;
	rb_iter_break();
    }
    return Qnil;
}

static VALUE
none_iter_i(i, memo)
    VALUE i;
    VALUE *memo;
{
    return none_i(rb_yield(i), memo);
}

/*
 *  call-seq:
 *     enum.none? [{|obj| block }]   => true or false
 *
 *  Passes each element of the collection to the given block. The method
 *  returns true if the block never returns true
 *  for all elements. If the block is not given, none? will return
 *  true only if none of the collection members is true.
 *
 *     %w{ant bear cat}.none? {|word| word.length == 5}  #=> true
 *     %w{ant bear cat}.none? {|word| word.length >= 4}  #=> false
 *     [].none?                                          #=> true
 *     [nil].none?                                       #=> true
 *     [nil,false].none?                                 #=> true
 */
static VALUE
enum_none(obj)
    VALUE obj;
{
    VALUE result = Qtrue;

    rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? none_iter_i : none_i, (VALUE)&result);
    return result;
}

static VALUE
min_i(i, memo)
    VALUE i;
    VALUE *memo;
{
    VALUE cmp;

    if (*memo == Qundef) {
	*memo = i;
    }
    else {
	cmp = rb_funcall(i, id_cmp, 1, *memo);
	if (rb_cmpint(cmp, i, *memo) < 0) {
	    *memo = i;
	}
    }
    return Qnil;
}

static VALUE
min_ii(i, memo)
    VALUE i;
    VALUE *memo;
{
    VALUE cmp;

    if (*memo == Qundef) {
	*memo = i;
    }
    else {
	cmp = rb_yield_values(2, i, *memo);
	if (rb_cmpint(cmp, i, *memo) < 0) {
	    *memo = i;
	}
    }
    return Qnil;
}


/*
 *  call-seq:
 *     enum.min                    => obj
 *     enum.min {| a,b | block }   => obj
 *
 *  Returns the object in enum with the minimum value. The
 *  first form assumes all objects implement Comparable;
 *  the second uses the block to return a <=> b.
 *
 *     a = %w(albatross dog horse)
 *     a.min                                  #=> "albatross"
 *     a.min {|a,b| a.length <=> b.length }   #=> "dog"
 */

static VALUE
enum_min(obj)
    VALUE obj;
{
    VALUE result = Qundef;

    rb_iterate(rb_each, obj, rb_block_given_p() ? min_ii : min_i, (VALUE)&result);
    if (result == Qundef) return Qnil;
    return result;
}

/*
 *  call-seq:
 *     enum.max                    => obj
 *     enum.max {| a,b | block }   => obj
 *
 *  Returns the object in enum with the maximum value. The
 *  first form assumes all objects implement Comparable;
 *  the second uses the block to return a <=> b.
 *
 *     a = %w(albatross dog horse)
 *     a.max                                  #=> "horse"
 *     a.max {|a,b| a.length <=> b.length }   #=> "albatross"
 */

static VALUE
max_i(i, memo)
    VALUE i;
    VALUE *memo;
{
    VALUE cmp;

    if (*memo == Qundef) {
	*memo = i;
    }
    else {
	cmp = rb_funcall(i, id_cmp, 1, *memo);
	if (rb_cmpint(cmp, i, *memo) > 0) {
	    *memo = i;
	}
    }
    return Qnil;
}

static VALUE
max_ii(i, memo)
    VALUE i;
    VALUE *memo;
{
    VALUE cmp;

    if (*memo == Qundef) {
	*memo = i;
    }
    else {
	cmp = rb_yield_values(2, i, *memo);
	if (rb_cmpint(cmp, i, *memo) > 0) {
	    *memo = i;
	}
    }
    return Qnil;
}

/*
 *  call-seq:
 *     enum.max                   => obj
 *     enum.max {|a,b| block }    => obj
 *
 *  Returns the object in _enum_ with the maximum value. The
 *  first form assumes all objects implement Comparable;
 *  the second uses the block to return a <=> b.
 *
 *     a = %w(albatross dog horse)
 *     a.max                                  #=> "horse"
 *     a.max {|a,b| a.length <=> b.length }   #=> "albatross"
 */

static VALUE
enum_max(obj)
    VALUE obj;
{
    VALUE result = Qundef;

    rb_iterate(rb_each, obj, rb_block_given_p() ? max_ii : max_i, (VALUE)&result);
    if (result == Qundef) return Qnil;
    return result;
}

static VALUE
minmax_i(i, memo)
    VALUE i;
    VALUE *memo;
{
    int n;

    if (memo[0] == Qundef) {
	memo[0] = i;
	memo[1] = i;
    }
    else {
	n = rb_cmpint(rb_funcall(i, id_cmp, 1, memo[0]), i, memo[0]);
	if (n < 0) {
	    memo[0] = i;
	}
	n = rb_cmpint(rb_funcall(i, id_cmp, 1, memo[1]), i, memo[1]);
	if (n > 0) {
	    memo[1] = i;
	}
    }
    return Qnil;
}

static VALUE
minmax_ii(i, memo)
    VALUE i;
    VALUE *memo;
{
    int n;

    if (memo[0] == Qundef) {
	memo[0] = i;
	memo[1] = i;
    }
    else {
	VALUE ary = memo[2];

	RARRAY(ary)->ptr[0] = i;
	RARRAY(ary)->ptr[1] = memo[0];
	n = rb_cmpint(rb_yield(ary), i, memo[0]);
	if (n < 0) {
	    memo[0] = i;
	}
	RARRAY(ary)->ptr[0] = i;
	RARRAY(ary)->ptr[1] = memo[1];
	n = rb_cmpint(rb_yield(ary), i, memo[1]);
	if (n > 0) {
	    memo[1] = i;
	}
    }
    return Qnil;
}

/*
 *  call-seq:
 *     enum.minmax                   => [min,max]
 *     enum.minmax {|a,b| block }    => [min,max]
 *
 *  Returns two elements array which contains the minimum and the
 *  maximum value in the enumerable.  The first form assumes all
 *  objects implement Comparable; the second uses the
 *  block to return a <=> b.
 *
 *     a = %w(albatross dog horse)
 *     a.minmax                                  #=> ["albatross", "horse"]
 *     a.minmax {|a,b| a.length <=> b.length }   #=> ["dog", "albatross"]
 */

static VALUE
enum_minmax(obj)
    VALUE obj;
{
    VALUE result[3];
    VALUE ary = rb_ary_new3(2, Qnil, Qnil);

    result[0] = Qundef;
    if (rb_block_given_p()) {
	result[2] = ary;
	rb_block_call(obj, id_each, 0, 0, minmax_ii, (VALUE)result);
    }
    else {
	rb_block_call(obj, id_each, 0, 0, minmax_i, (VALUE)result);
    }
    if (result[0] != Qundef) {
        RARRAY(ary)->ptr[0] = result[0];
        RARRAY(ary)->ptr[1] = result[1];
    }
    return ary;
}

static VALUE
min_by_i(i, memo)
    VALUE i;
    VALUE *memo;
{
    VALUE v;

    v = rb_yield(i);
    if (memo[0] == Qundef) {
	memo[0] = v;
	memo[1] = i;
    }
    else if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo[0]), v, memo[0]) < 0) {
	memo[0] = v;
	memo[1] = i;
    }
    return Qnil;
}

/*
 *  call-seq:
 *     enum.min_by {| obj| block }   => obj
 *
 *  Returns the object in enum that gives the minimum
 *  value from the given block.
 *
 *     a = %w(albatross dog horse)
 *     a.min_by {|x| x.length }   #=> "dog"
 */

static VALUE
enum_min_by(obj)
    VALUE obj;
{
    VALUE memo[2];

    RETURN_ENUMERATOR(obj, 0, 0);

    memo[0] = Qundef;
    memo[1] = Qnil;
    rb_block_call(obj, id_each, 0, 0, min_by_i, (VALUE)memo);
    return memo[1];
}

static VALUE
max_by_i(i, memo)
    VALUE i;
    VALUE *memo;
{
    VALUE v;

    v = rb_yield(i);
    if (memo[0] == Qundef) {
	memo[0] = v;
	memo[1] = i;
    }
    else if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo[0]), v, memo[0]) > 0) {
	memo[0] = v;
	memo[1] = i;
    }
    return Qnil;
}

/*
 *  call-seq:
 *     enum.max_by {| obj| block }   => obj
 *
 *  Returns the object in enum that gives the maximum
 *  value from the given block.
 *
 *     a = %w(albatross dog horse)
 *     a.max_by {|x| x.length }   #=> "albatross"
 */

static VALUE
enum_max_by(obj)
    VALUE obj;
{
    VALUE memo[2];

    RETURN_ENUMERATOR(obj, 0, 0);

    memo[0] = Qundef;
    memo[1] = Qnil;
    rb_block_call(obj, id_each, 0, 0, max_by_i, (VALUE)memo);
    return memo[1];
}

static VALUE
minmax_by_i(i, memo)
    VALUE i;
    VALUE *memo;
{
    VALUE v;

    v = rb_yield(i);
    if (memo[0] == Qundef) {
	memo[0] = v;
	memo[1] = v;
	memo[2] = i;
	memo[3] = i;
    }
    else {
	if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo[0]), v, memo[0]) < 0) {
	    memo[0] = v;
	    memo[2] = i;
	}
	if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo[1]), v, memo[1]) > 0) {
	    memo[1] = v;
	    memo[3] = i;
	}
    }
    return Qnil;
}

/*
 *  call-seq:
 *     enum.minmax_by {| obj| block }   => [min, max]
 *
 *  Returns two elements array array containing the objects in
 *  enum that gives the minimum and maximum values respectively
 *  from the given block.
 *
 *     a = %w(albatross dog horse)
 *     a.minmax_by {|x| x.length }   #=> ["dog", "albatross"]
 */

static VALUE
enum_minmax_by(obj)
    VALUE obj;
{
    VALUE memo[4];

    RETURN_ENUMERATOR(obj, 0, 0);

    memo[0] = Qundef;
    memo[1] = Qundef;
    memo[2] = Qnil;
    memo[3] = Qnil;
    rb_block_call(obj, id_each, 0, 0, minmax_by_i, (VALUE)memo);
    return rb_assoc_new(memo[2], memo[3]);
}

static VALUE
member_i(item, memo)
    VALUE item;
    VALUE *memo;
{
    if (rb_equal(item, memo[0])) {
	memo[1] = Qtrue;
	rb_iter_break();
    }
    return Qnil;
}

/*
 *  call-seq:
 *     enum.include?(obj)     => true or false
 *     enum.member?(obj)      => true or false
 *
 *  Returns true if any member of enum equals
 *  obj. Equality is tested using ==.
 *
 *     IO.constants.include? "SEEK_SET"          #=> true
 *     IO.constants.include? "SEEK_NO_FURTHER"   #=> false
 *
 */

static VALUE
enum_member(obj, val)
    VALUE obj, val;
{
    VALUE memo[2];

    memo[0] = val;
    memo[1] = Qfalse;
    rb_iterate(rb_each, obj, member_i, (VALUE)memo);
    return memo[1];
}

static VALUE
each_with_index_i(val, memo)
    VALUE val;
    VALUE *memo;
{
    rb_yield_values(2, val, INT2FIX(*memo));
    ++*memo;
    return Qnil;
}

/*
 *  call-seq:
 *     enum.each_with_index {|obj, i| block }  -> enum
 *
 *  Calls block with two arguments, the item and its index, for
 *  each item in enum.
 *
 *     hash = Hash.new
 *     %w(cat dog wombat).each_with_index {|item, index|
 *       hash[item] = index
 *     }
 *     hash   #=> {"cat"=>0, "wombat"=>2, "dog"=>1}
 *
 */

static VALUE
enum_each_with_index(obj)
    VALUE obj;
{
    VALUE memo;

    RETURN_ENUMERATOR(obj, 0, 0);

    memo = 0;
    rb_iterate(rb_each, obj, each_with_index_i, (VALUE)&memo);
    return obj;
}

/*
 *  call-seq:
 *     enum.reverse_each {|item| block } 
 *  
 *  Traverses enum in reverse order.
 */

static VALUE
enum_reverse_each(int argc, VALUE *argv, VALUE obj)
{
    VALUE ary;
    long i;

    RETURN_ENUMERATOR(obj, argc, argv);

    ary = enum_to_a(argc, argv, obj);

    for (i = RARRAY_LEN(ary); --i >= 0; ) {
	rb_yield(RARRAY_PTR(ary)[i]);
    }

    return obj;
}


static VALUE
zip_i(val, memo)
    VALUE val;
    VALUE *memo;
{
    VALUE result = memo[0];
    VALUE args = memo[1];
    int idx = memo[2]++;
    VALUE tmp;
    int i;

    tmp = rb_ary_new2(RARRAY(args)->len + 1);
    rb_ary_store(tmp, 0, val);
    for (i=0; ilen; i++) {
	rb_ary_push(tmp, rb_ary_entry(RARRAY(args)->ptr[i], idx));
    }
    if (rb_block_given_p()) {
	rb_yield(tmp);
    }
    else {
	rb_ary_push(result, tmp);
    }
    return Qnil;
}

/*
 *  call-seq:
 *     enum.zip(arg, ...)                   => array
 *     enum.zip(arg, ...) {|arr| block }    => nil
 *
 *  Converts any arguments to arrays, then merges elements of
 *  enum with corresponding elements from each argument. This
 *  generates a sequence of enum#size n-element
 *  arrays, where n is one more that the count of arguments. If
 *  the size of any argument is less than enum#size,
 *  nil values are supplied. If a block given, it is
 *  invoked for each output array, otherwise an array of arrays is
 *  returned.
 *
 *     a = [ 4, 5, 6 ]
 *     b = [ 7, 8, 9 ]
 *
 *     (1..3).zip(a, b)      #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
 *     "cat\ndog".zip([1])   #=> [["cat\n", 1], ["dog", nil]]
 *     (1..3).zip            #=> [[1], [2], [3]]
 *
 */

static VALUE
enum_zip(argc, argv, obj)
    int argc;
    VALUE *argv;
    VALUE obj;
{
    int i;
    VALUE result;
    VALUE memo[3];

    for (i=0; i array
 *
 *  Returns first n elements from enum.
 *
 *     a = [1, 2, 3, 4, 5, 0]
 *     a.take(3)             # => [1, 2, 3]
 *
 */

static VALUE
enum_take(obj, n)
    VALUE obj;
    VALUE n;
{
    VALUE args[2];
    long len = NUM2LONG(n);

    if (len < 0) {
	rb_raise(rb_eArgError, "attempt to take negative size");
    }

    if (len == 0) return rb_ary_new2(0);
    args[1] = len;
    args[0] = rb_ary_new();
    rb_block_call(obj, id_each, 0, 0, take_i, (VALUE)args);
    return args[0];
}


static VALUE
take_while_i(i, ary)
    VALUE i;
    VALUE *ary;
{
    if (!RTEST(rb_yield(i))) rb_iter_break();
    rb_ary_push(*ary, i);
    return Qnil;
}

/*
 *  call-seq:
 *     enum.take_while {|arr| block }   => array
 *
 *  Passes elements to the block until the block returns nil or false,
 *  then stops iterating and returns an array of all prior elements.
 *
 *     a = [1, 2, 3, 4, 5, 0]
 *     a.take_while {|i| i < 3 }   # => [1, 2]
 *
 */

static VALUE
enum_take_while(obj)
    VALUE obj;
{
    VALUE ary;

    RETURN_ENUMERATOR(obj, 0, 0);
    ary = rb_ary_new();
    rb_block_call(obj, id_each, 0, 0, take_while_i, (VALUE)&ary);
    return ary;
}

static VALUE
drop_i(i, arg)
    VALUE i;
    VALUE *arg;
{
    if (arg[1] == 0) {
	rb_ary_push(arg[0], i);
    }
    else {
	arg[1]--;
    }
    return Qnil;
}

/*
 *  call-seq:
 *     enum.drop(n)               => array
 *
 *  Drops first n elements from enum, and returns rest elements
 *  in an array.
 *
 *     a = [1, 2, 3, 4, 5, 0]
 *     a.drop(3)             # => [4, 5, 0]
 *
 */

static VALUE
enum_drop(obj, n)
    VALUE obj;
    VALUE n;
{
    VALUE args[2];
    long len = NUM2LONG(n);

    if (len < 0) {
	rb_raise(rb_eArgError, "attempt to drop negative size");
    }

    args[1] = len;
    args[0] = rb_ary_new();
    rb_block_call(obj, id_each, 0, 0, drop_i, (VALUE)args);
    return args[0];
}


static VALUE
drop_while_i(i, args)
    VALUE i;
    VALUE *args;
{
    if (!args[1] && !RTEST(rb_yield(i))) {
	args[1] = Qtrue;
    }
    if (args[1]) {
	rb_ary_push(args[0], i);
    }
    return Qnil;
}

/*
 *  call-seq:
 *     enum.drop_while {|arr| block }   => array
 *
 *  Drops elements up to, but not including, the first element for
 *  which the block returns nil or false and returns an array
 *  containing the remaining elements.
 *
 *     a = [1, 2, 3, 4, 5, 0]
 *     a.drop_while {|i| i < 3 }   # => [3, 4, 5, 0]
 *
 */

static VALUE
enum_drop_while(obj)
    VALUE obj;
{
    VALUE args[2];

    RETURN_ENUMERATOR(obj, 0, 0);
    args[0] = rb_ary_new();
    args[1] = Qfalse;
    rb_block_call(obj, id_each, 0, 0, drop_while_i, (VALUE)args);
    return args[0];
}

static VALUE
cycle_i(i, ary)
    VALUE i;
    VALUE ary;
{
    rb_ary_push(ary, i);
    rb_yield(i);
    return Qnil;
}

/*
 *  call-seq:
 *     enum.cycle {|obj| block }
 *     enum.cycle(n) {|obj| block }
 *
 *  Calls block for each element of enum repeatedly _n_
 *  times or forever if none or nil is given.  If a non-positive
 *  number is given or the collection is empty, does nothing.  Returns
 *  nil if the loop has finished without getting interrupted.
 *
 *  Enumerable#cycle saves elements in an internal array so changes
 *  to enum after the first pass have no effect.
 *
 *     a = ["a", "b", "c"]
 *     a.cycle {|x| puts x }  # print, a, b, c, a, b, c,.. forever.
 *     a.cycle(2) {|x| puts x }  # print, a, b, c, a, b, c.
 *
 */

static VALUE
enum_cycle(argc, argv, obj)
    int argc;
    VALUE *argv;
    VALUE obj;
{
    VALUE ary;
    VALUE nv = Qnil;
    long n, i, len;

    rb_scan_args(argc, argv, "01", &nv);

    RETURN_ENUMERATOR(obj, argc, argv);
    if (NIL_P(nv)) {
        n = -1;
    }
    else {
        n = NUM2LONG(nv);
        if (n <= 0) return Qnil;
    }
    ary = rb_ary_new();
    RBASIC(ary)->klass = 0;
    rb_block_call(obj, id_each, 0, 0, cycle_i, ary);
    len = RARRAY(ary)->len;
    if (len == 0) return Qnil;
    while (n < 0 || 0 < --n) {
        for (i=0; iptr[i]);
        }
    }
    return Qnil;		/* not reached */
}

/*
 *  The Enumerable mixin provides collection classes with
 *  several traversal and searching methods, and with the ability to
 *  sort. The class must provide a method each, which
 *  yields successive members of the collection. If
 *  Enumerable#max, #min, or
 *  #sort is used, the objects in the collection must also
 *  implement a meaningful <=> operator, as these methods
 *  rely on an ordering between members of the collection.
 */

void
Init_Enumerable()
{
    rb_mEnumerable = rb_define_module("Enumerable");

    rb_define_method(rb_mEnumerable, "to_a", enum_to_a, -1);
    rb_define_method(rb_mEnumerable, "entries", enum_to_a, -1);

    rb_define_method(rb_mEnumerable, "sort", enum_sort, 0);
    rb_define_method(rb_mEnumerable, "sort_by", enum_sort_by, 0);
    rb_define_method(rb_mEnumerable, "grep", enum_grep, 1);
    rb_define_method(rb_mEnumerable, "count", enum_count, -1);
    rb_define_method(rb_mEnumerable, "find", enum_find, -1);
    rb_define_method(rb_mEnumerable, "detect", enum_find, -1);
    rb_define_method(rb_mEnumerable, "find_index", enum_find_index, -1);
    rb_define_method(rb_mEnumerable, "find_all", enum_find_all, 0);
    rb_define_method(rb_mEnumerable, "select", enum_find_all, 0);
    rb_define_method(rb_mEnumerable, "reject", enum_reject, 0);
    rb_define_method(rb_mEnumerable, "collect", enum_collect, 0);
    rb_define_method(rb_mEnumerable, "map", enum_collect, 0);
    rb_define_method(rb_mEnumerable, "inject", enum_inject, -1);
    rb_define_method(rb_mEnumerable, "reduce", enum_inject, -1);
    rb_define_method(rb_mEnumerable, "partition", enum_partition, 0);
    rb_define_method(rb_mEnumerable, "group_by", enum_group_by, 0);
    rb_define_method(rb_mEnumerable, "first", enum_first, -1);
    rb_define_method(rb_mEnumerable, "all?", enum_all, 0);
    rb_define_method(rb_mEnumerable, "any?", enum_any, 0);
    rb_define_method(rb_mEnumerable, "one?", enum_one, 0);
    rb_define_method(rb_mEnumerable, "none?", enum_none, 0);
    rb_define_method(rb_mEnumerable, "min", enum_min, 0);
    rb_define_method(rb_mEnumerable, "max", enum_max, 0);
    rb_define_method(rb_mEnumerable, "minmax", enum_minmax, 0);
    rb_define_method(rb_mEnumerable, "min_by", enum_min_by, 0);
    rb_define_method(rb_mEnumerable, "max_by", enum_max_by, 0);
    rb_define_method(rb_mEnumerable, "minmax_by", enum_minmax_by, 0);
    rb_define_method(rb_mEnumerable, "member?", enum_member, 1);
    rb_define_method(rb_mEnumerable, "include?", enum_member, 1);
    rb_define_method(rb_mEnumerable, "each_with_index", enum_each_with_index, 0);
    rb_define_method(rb_mEnumerable, "enum_with_index", enum_each_with_index, 0);
    rb_define_method(rb_mEnumerable, "reverse_each", enum_reverse_each, -1);
    rb_define_method(rb_mEnumerable, "zip", enum_zip, -1);
    rb_define_method(rb_mEnumerable, "take", enum_take, 1);
    rb_define_method(rb_mEnumerable, "take_while", enum_take_while, 0);
    rb_define_method(rb_mEnumerable, "drop", enum_drop, 1);
    rb_define_method(rb_mEnumerable, "drop_while", enum_drop_while, 0);
    rb_define_method(rb_mEnumerable, "cycle", enum_cycle, -1);

    id_eqq  = rb_intern("===");
    id_each = rb_intern("each");
    id_cmp  = rb_intern("<=>");
    id_size = rb_intern("size");
}



================================================
FILE: enumerator.c
================================================
/************************************************

  enumerator.c - provides Enumerator class

  $Author$

  Copyright (C) 2001-2003 Akinori MUSHA

  $Idaemons: /home/cvs/rb/enumerator/enumerator.c,v 1.1.1.1 2001/07/15 10:12:48 knu Exp $
  $RoughId: enumerator.c,v 1.6 2003/07/27 11:03:24 nobu Exp $
  $Id$

************************************************/

#include "ruby.h"

/*
 * Document-class: Enumerable::Enumerator
 *
 * A class which provides a method `each' to be used as an Enumerable
 * object.
 */
VALUE rb_cEnumerator;
static VALUE sym_each;

VALUE rb_eStopIteration;

struct enumerator {
    VALUE obj;
    ID    meth;
    VALUE proc;
    VALUE args;
    rb_block_call_func *iter;
};

static void enumerator_mark _((void *));
static void
enumerator_mark(p)
    void *p;
{
    struct enumerator *ptr = p;
    rb_gc_mark(ptr->obj);
    rb_gc_mark(ptr->args);
}

static struct enumerator *
enumerator_ptr(obj)
    VALUE obj;
{
    struct enumerator *ptr;

    Data_Get_Struct(obj, struct enumerator, ptr);
    if (RDATA(obj)->dmark != enumerator_mark) {
	rb_raise(rb_eTypeError,
		 "wrong argument type %s (expected Enumerable::Enumerator)",
		 rb_obj_classname(obj));
    }
    if (!ptr || ptr->obj == Qundef) {
	rb_raise(rb_eArgError, "uninitialized enumerator");
    }
    return ptr;
}

/*
 *  call-seq:
 *    obj.to_enum(method = :each, *args)
 *    obj.enum_for(method = :each, *args)
 *
 *  Returns Enumerable::Enumerator.new(self, method, *args).
 *
 *  e.g.:
 *
 *     str = "xyz"
 *
 *     enum = str.enum_for(:each_byte)
 *     a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"]
 *
 *     # protects an array from being modified
 *     a = [1, 2, 3]
 *     some_method(a.to_enum)
 *
 */
static VALUE
obj_to_enum(argc, argv, obj)
    int argc;
    VALUE *argv;
    VALUE obj;
{
    VALUE meth = sym_each;

    if (argc > 0) {
	--argc;
	meth = *argv++;
    }
    return rb_enumeratorize(obj, meth, argc, argv);
}

static VALUE
each_slice_i(val, memo)
    VALUE val;
    VALUE *memo;
{
    VALUE ary = memo[0];
    VALUE v = Qnil;
    long size = (long)memo[1];

    rb_ary_push(ary, val);

    if (RARRAY_LEN(ary) == size) {
	v = rb_yield(ary);
	memo[0] = rb_ary_new2(size);
    }

    return v;
}

/*
 *  call-seq:
 *    e.each_slice(n) {...}
 *    e.each_slice(n)
 *
 *  Iterates the given block for each slice of  elements.  If no
 *  block is given, returns an enumerator.
 *
 *  e.g.:
 *      (1..10).each_slice(3) {|a| p a}
 *      # outputs below
 *      [1, 2, 3]
 *      [4, 5, 6]
 *      [7, 8, 9]
 *      [10]
 *
 */
static VALUE
enum_each_slice(obj, n)
    VALUE obj, n;
{
    long size = NUM2LONG(n);
    VALUE args[2], ary;

    if (size <= 0) rb_raise(rb_eArgError, "invalid slice size");
    RETURN_ENUMERATOR(obj, 1, &n);
    args[0] = rb_ary_new2(size);
    args[1] = (VALUE)size;

    rb_block_call(obj, SYM2ID(sym_each), 0, 0, each_slice_i, (VALUE)args);

    ary = args[0];
    if (RARRAY_LEN(ary) > 0) rb_yield(ary);

    return Qnil;
}

static VALUE
each_cons_i(val, memo)
    VALUE val;
    VALUE *memo;
{
    VALUE ary = memo[0];
    VALUE v = Qnil;
    long size = (long)memo[1];

    if (RARRAY_LEN(ary) == size) {
	rb_ary_shift(ary);
    }
    rb_ary_push(ary, val);
    if (RARRAY_LEN(ary) == size) {
	v = rb_yield(rb_ary_dup(ary));
    }
    return v;
}

/*
 *  call-seq:
 *    each_cons(n) {...}
 *    each_cons(n)
 *
 *  Iterates the given block for each array of consecutive 
 *  elements.  If no block is given, returns an enumerator.a
 *
 *  e.g.:
 *      (1..10).each_cons(3) {|a| p a}
 *      # outputs below
 *      [1, 2, 3]
 *      [2, 3, 4]
 *      [3, 4, 5]
 *      [4, 5, 6]
 *      [5, 6, 7]
 *      [6, 7, 8]
 *      [7, 8, 9]
 *      [8, 9, 10]
 *
 */
static VALUE
enum_each_cons(obj, n)
    VALUE obj, n;
{
    long size = NUM2LONG(n);
    VALUE args[2];

    if (size <= 0) rb_raise(rb_eArgError, "invalid size");
    RETURN_ENUMERATOR(obj, 1, &n);
    args[0] = rb_ary_new2(size);
    args[1] = (VALUE)size;

    rb_block_call(obj, SYM2ID(sym_each), 0, 0, each_cons_i, (VALUE)args);

    return Qnil;
}

static VALUE enumerator_allocate _((VALUE));
static VALUE
enumerator_allocate(klass)
    VALUE klass;
{
    struct enumerator *ptr;
    VALUE enum_obj;

    enum_obj = Data_Make_Struct(klass, struct enumerator,
				enumerator_mark, -1, ptr);
    ptr->obj = Qundef;

    return enum_obj;
}

static VALUE enumerator_each_i _((VALUE, VALUE));
static VALUE
enumerator_each_i(v, enum_obj)
    VALUE v;
    VALUE enum_obj;
{
    return rb_yield(v);
}

static VALUE
enumerator_init(enum_obj, obj, meth, argc, argv)
    VALUE enum_obj;
    VALUE obj;
    VALUE meth;
    int argc;
    VALUE *argv;
{
    struct enumerator *ptr;

    Data_Get_Struct(enum_obj, struct enumerator, ptr);

    if (!ptr) {
	rb_raise(rb_eArgError, "unallocated enumerator");
    }

    ptr->obj  = obj;
    ptr->meth = rb_to_id(meth);
    ptr->iter = enumerator_each_i;
    if (argc) ptr->args = rb_ary_new4(argc, argv);

    return enum_obj;
}

/*
 *  call-seq:
 *    Enumerable::Enumerator.new(obj, method = :each, *args)
 *
 *  Creates a new Enumerable::Enumerator object, which is to be
 *  used as an Enumerable object using the given object's given
 *  method with the given arguments.
 *
 *  Use of this method is discouraged.  Use Kernel#enum_for() instead.
 */
static VALUE
enumerator_initialize(argc, argv, obj)
    int argc;
    VALUE *argv;
    VALUE obj;
{
    VALUE recv, meth = sym_each;

    if (argc == 0)
	rb_raise(rb_eArgError, "wrong number of argument (0 for 1)");
    recv = *argv++;
    if (--argc) {
	meth = *argv++;
	--argc;
    }
    return enumerator_init(obj, recv, meth, argc, argv);
}

/* :nodoc: */
static VALUE
enumerator_init_copy(obj, orig)
    VALUE obj;
    VALUE orig;
{
    struct enumerator *ptr0, *ptr1;

    ptr0 = enumerator_ptr(orig);

    Data_Get_Struct(obj, struct enumerator, ptr1);

    if (!ptr1) {
	rb_raise(rb_eArgError, "unallocated enumerator");
    }

    ptr1->obj  = ptr0->obj;
    ptr1->meth = ptr0->meth;
    ptr1->iter = ptr0->iter;
    ptr1->args = ptr0->args;

    return obj;
}

VALUE
rb_enumeratorize(obj, meth, argc, argv)
    VALUE obj;
    VALUE meth;
    int argc;
    VALUE *argv;
{
    return enumerator_init(enumerator_allocate(rb_cEnumerator), obj, meth, argc, argv);
}

/*
 *  call-seq:
 *    enum.each {...}
 *
 *  Iterates the given block using the object and the method specified
 *  in the first place.  If no block is given, returns self.
 *
 */
static VALUE
enumerator_each(obj)
    VALUE obj;
{
    struct enumerator *e;
    int argc = 0;
    VALUE *argv = 0;

    if (!rb_block_given_p()) return obj;
    e = enumerator_ptr(obj);
    if (e->args) {
	argc = RARRAY_LEN(e->args);
	argv = RARRAY_PTR(e->args);
    }
    return rb_block_call(e->obj, e->meth, argc, argv, e->iter, (VALUE)e);
}

static VALUE
enumerator_with_index_i(val, memo)
    VALUE val;
    VALUE *memo;
{
    val = rb_yield_values(2, val, INT2FIX(*memo));
    ++*memo;
    return val;
}

/*
 *  call-seq:
 *    e.with_index {|(*args), idx| ... }
 *    e.with_index
 *
 *  Iterates the given block for each elements with an index, which
 *  start from 0.  If no block is given, returns an enumerator.
 *
 */
static VALUE
enumerator_with_index(obj)
    VALUE obj;
{
    struct enumerator *e = enumerator_ptr(obj);
    VALUE memo = 0;
    int argc = 0;
    VALUE *argv = 0;

    RETURN_ENUMERATOR(obj, 0, 0);
    if (e->args) {
	argc = RARRAY_LEN(e->args);
	argv = RARRAY_PTR(e->args);
    }
    return rb_block_call(e->obj, e->meth, argc, argv,
			 enumerator_with_index_i, (VALUE)&memo);
}

/*
 * call-seq:
 *   e.next   => object
 *
 * Returns the next object in the enumerator, and move the internal
 * position forward.  When the position reached at the end, internal
 * position is rewinded then StopIteration is raised.
 *
 * Note that enumeration sequence by next method does not affect other
 * non-external enumeration methods, unless underlying iteration
 * methods itself has side-effect, e.g. IO#each_line.
 *
 * Caution: Calling this method causes the "generator" library to be
 * loaded.
 */

static VALUE
enumerator_next(obj)
    VALUE obj;
{
    rb_require("generator");
    return rb_funcall(obj, rb_intern("next"), 0, 0);
}

/*
 * call-seq:
 *   e.rewind   => e
 *
 * Rewinds the enumeration sequence by the next method.
 */

static VALUE
enumerator_rewind(obj)
    VALUE obj;
{
    rb_require("generator");
    return rb_funcall(obj, rb_intern("rewind"), 0, 0);
}

void
Init_Enumerator()
{
    rb_define_method(rb_mKernel, "to_enum", obj_to_enum, -1);
    rb_define_method(rb_mKernel, "enum_for", obj_to_enum, -1);

    rb_define_method(rb_mEnumerable, "each_slice", enum_each_slice, 1);
    rb_define_method(rb_mEnumerable, "enum_slice", enum_each_slice, 1);
    rb_define_method(rb_mEnumerable, "each_cons", enum_each_cons, 1);
    rb_define_method(rb_mEnumerable, "enum_cons", enum_each_cons, 1);

    rb_cEnumerator = rb_define_class_under(rb_mEnumerable, "Enumerator", rb_cObject);
    rb_include_module(rb_cEnumerator, rb_mEnumerable);

    rb_define_alloc_func(rb_cEnumerator, enumerator_allocate);
    rb_define_method(rb_cEnumerator, "initialize", enumerator_initialize, -1);
    rb_define_method(rb_cEnumerator, "initialize_copy", enumerator_init_copy, 1);
    rb_define_method(rb_cEnumerator, "each", enumerator_each, 0);
    rb_define_method(rb_cEnumerator, "each_with_index", enumerator_with_index, 0);
    rb_define_method(rb_cEnumerator, "with_index", enumerator_with_index, 0);
    rb_define_method(rb_cEnumerator, "next", enumerator_next, 0);
    rb_define_method(rb_cEnumerator, "rewind", enumerator_rewind, 0);

    rb_eStopIteration   = rb_define_class("StopIteration", rb_eIndexError);

    sym_each	 	= ID2SYM(rb_intern("each"));

    rb_provide("enumerator.so");	/* for backward compatibility */
}


================================================
FILE: env.h
================================================
/**********************************************************************

  env.h -

  $Author$
  $Date$
  created at: Mon Jul 11 11:53:03 JST 1994

  Copyright (C) 1993-2003 Yukihiro Matsumoto

**********************************************************************/

#ifndef ENV_H
#define ENV_H

extern struct FRAME {
    VALUE self;
    int argc;
    ID last_func;
    ID orig_func;
    VALUE last_class;
    struct FRAME *prev;
    struct FRAME *tmp;
    struct RNode *node;
#ifdef GC_DEBUG
    source_position_t* source_pos;
#endif
    int iter;
    int flags;
    unsigned long uniq;
} *ruby_frame;

void rb_gc_mark_frame _((struct FRAME *));

#ifdef GC_DEBUG
void gc_debug_get_frame_source_pos(struct FRAME* frame);
#endif

#define FRAME_DMETH  1
#define FRAME_FUNC   2

extern struct SCOPE {
    struct RBasic super;
    ID *local_tbl;
    VALUE *local_vars;
    int flags;
} *ruby_scope;

#define SCOPE_ALLOCA  0
#define SCOPE_MALLOC  1
#define SCOPE_NOSTACK 2
#define SCOPE_DONT_RECYCLE 4
#define SCOPE_CLONE   8

extern int ruby_in_eval;

extern VALUE ruby_class;

struct RVarmap {
    struct RBasic super;
    ID id;
    VALUE val;
    struct RVarmap *next;
};
extern struct RVarmap *ruby_dyna_vars;

#endif /* ENV_H */


================================================
FILE: error.c
================================================
/**********************************************************************

  error.c -

  $Author$
  $Date$
  created at: Mon Aug  9 16:11:34 JST 1993

  Copyright (C) 1993-2003 Yukihiro Matsumoto

**********************************************************************/

#include "ruby.h"
#include "env.h"
#include "st.h"

#include 
#ifdef HAVE_STDARG_PROTOTYPES
#include 
#define va_init_list(a,b) va_start(a,b)
#else
#include 
#define va_init_list(a,b) va_start(a)
#endif
#ifdef HAVE_STDLIB_H
#include 
#endif
#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 0
#endif

extern const char *ruby_description;

int ruby_nerrs;

static int
err_position(buf, len)
    char *buf;
    long len;
{
    ruby_set_current_source();
    if (!ruby_sourcefile) {
	return 0;
    }
    else if (ruby_sourceline == 0) {
	return snprintf(buf, len, "%s: ", ruby_sourcefile);
    }
    else {
	return snprintf(buf, len, "%s:%d: ", ruby_sourcefile, ruby_sourceline);
    }
}

static void
err_snprintf(buf, len, fmt, args)
    char *buf;
    long len;
    const char *fmt;
    va_list args;
{
    long n;

    n = err_position(buf, len);
    if (len > n) {
	vsnprintf((char*)buf+n, len-n, fmt, args);
    }
}

static void err_append _((const char*));
static void
err_print(fmt, args)
    const char *fmt;
    va_list args;
{
    char buf[BUFSIZ];

    err_snprintf(buf, BUFSIZ, fmt, args);
    err_append(buf);
}

void
#ifdef HAVE_STDARG_PROTOTYPES
rb_compile_error(const char *fmt, ...)
#else
rb_compile_error(fmt, va_alist)
    const char *fmt;
    va_dcl
#endif
{
    va_list args;

    va_init_list(args, fmt);
    err_print(fmt, args);
    va_end(args);
    ruby_nerrs++;
}

void
#ifdef HAVE_STDARG_PROTOTYPES
rb_compile_error_append(const char *fmt, ...)
#else
rb_compile_error_append(fmt, va_alist)
    const char *fmt;
    va_dcl
#endif
{
    va_list args;
    char buf[BUFSIZ];

    va_init_list(args, fmt);
    vsnprintf(buf, BUFSIZ, fmt, args);
    va_end(args);
    err_append(buf);
}

static void
warn_print(fmt, args)
    const char *fmt;
    va_list args;
{
    char buf[BUFSIZ];
    int len;

    err_snprintf(buf, BUFSIZ, fmt, args);
    len = strlen(buf);
    buf[len++] = '\n';
    rb_write_error2(buf, len);
}

void
#ifdef HAVE_STDARG_PROTOTYPES
rb_warn(const char *fmt, ...)
#else
rb_warn(fmt, va_alist)
    const char *fmt;
    va_dcl
#endif
{
    char buf[BUFSIZ];
    va_list args;

    if (NIL_P(ruby_verbose)) return;

    snprintf(buf, BUFSIZ, "warning: %s", fmt);

    va_init_list(args, fmt);
    warn_print(buf, args);
    va_end(args);
}

/* rb_warning() reports only in verbose mode */
void
#ifdef HAVE_STDARG_PROTOTYPES
rb_warning(const char *fmt, ...)
#else
rb_warning(fmt, va_alist)
    const char *fmt;
    va_dcl
#endif
{
    char buf[BUFSIZ];
    va_list args;

    if (!RTEST(ruby_verbose)) return;

    snprintf(buf, BUFSIZ, "warning: %s", fmt);

    va_init_list(args, fmt);
    warn_print(buf, args);
    va_end(args);
}

/*
 * call-seq:
 *    warn(msg)   => nil
 *
 * Display the given message (followed by a newline) on STDERR unless
 * warnings are disabled (for example with the -W0 flag).
 */

static VALUE
rb_warn_m(self, mesg)
    VALUE self, mesg;
{
    if (!NIL_P(ruby_verbose)) {
	rb_io_write(rb_stderr, mesg);
	rb_io_write(rb_stderr, rb_default_rs);
    }
    return Qnil;
}

void
#ifdef HAVE_STDARG_PROTOTYPES
rb_bug(const char *fmt, ...)
#else
rb_bug(fmt, va_alist)
    const char *fmt;
    va_dcl
#endif
{
    char buf[BUFSIZ];
    va_list args;
    FILE *out = stderr;
    int len = err_position(buf, BUFSIZ);

    if (fwrite(buf, 1, len, out) == len ||
	fwrite(buf, 1, len, (out = stdout)) == len) {
	fputs("[BUG] ", out);
	va_init_list(args, fmt);
	vfprintf(out, fmt, args);
	va_end(args);
	fprintf(out, "\n%s\n\n", ruby_description);
    }
    abort();
}

static struct types {
    int type;
    const char *name;
} builtin_types[] = {
    {T_NIL,	"nil"},
    {T_OBJECT,	"Object"},
    {T_CLASS,	"Class"},
    {T_ICLASS,	"iClass"},	/* internal use: mixed-in module holder */
    {T_MODULE,	"Module"},
    {T_FLOAT,	"Float"},
    {T_STRING,	"String"},
    {T_REGEXP,	"Regexp"},
    {T_ARRAY,	"Array"},
    {T_FIXNUM,	"Fixnum"},
    {T_HASH,	"Hash"},
    {T_STRUCT,	"Struct"},
    {T_BIGNUM,	"Bignum"},
    {T_FILE,	"File"},
    {T_TRUE,	"true"},
    {T_FALSE,	"false"},
    {T_SYMBOL,	"Symbol"},	/* :symbol */
    {T_DATA,	"Data"},	/* internal use: wrapped C pointers */
    {T_MATCH,	"MatchData"},	/* data of $~ */
    {T_VARMAP,	"Varmap"},	/* internal use: dynamic variables */
    {T_SCOPE,	"Scope"},	/* internal use: variable scope */
    {T_NODE,	"Node"},	/* internal use: syntax tree node */
    {T_UNDEF,	"undef"},	/* internal use: #undef; should not happen */
    {-1,	0}
};

void
rb_check_type(x, t)
    VALUE x;
    int t;
{
    struct types *type = builtin_types;

    if (x == Qundef) {
	rb_bug("undef leaked to the Ruby space");
    }

    if (TYPE(x) != t) {
	while (type->type >= 0) {
	    if (type->type == t) {
		const char *etype;

		if (NIL_P(x)) {
		    etype = "nil";
		}
		else if (FIXNUM_P(x)) {
		    etype = "Fixnum";
		}
		else if (SYMBOL_P(x)) {
		    etype = "Symbol";
		}
		else if (rb_special_const_p(x)) {
		    etype = RSTRING(rb_obj_as_string(x))->ptr;
		}
		else {
		    etype = rb_obj_classname(x);
		}
		rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)",
			 etype, type->name);
	    }
	    type++;
	}
	rb_bug("unknown type 0x%x", t);
    }
}

/* exception classes */
#include 

VALUE rb_eException;
VALUE rb_eSystemExit;
VALUE rb_eInterrupt;
VALUE rb_eSignal;
VALUE rb_eFatal;
VALUE rb_eStandardError;
VALUE rb_eRuntimeError;
VALUE rb_eTypeError;
VALUE rb_eArgError;
VALUE rb_eIndexError;
VALUE rb_eRangeError;
VALUE rb_eNameError;
VALUE rb_eNoMethodError;
VALUE rb_eSecurityError;
VALUE rb_eNotImpError;
VALUE rb_eNoMemError;
VALUE rb_cNameErrorMesg;

VALUE rb_eScriptError;
VALUE rb_eSyntaxError;
VALUE rb_eLoadError;

VALUE rb_eSystemCallError;
VALUE rb_mErrno;

VALUE
rb_exc_new(etype, ptr, len)
    VALUE etype;
    const char *ptr;
    long len;
{
    return rb_funcall(etype, rb_intern("new"), 1, rb_str_new(ptr, len));
}

VALUE
rb_exc_new2(etype, s)
    VALUE etype;
    const char *s;
{
    return rb_exc_new(etype, s, strlen(s));
}

VALUE
rb_exc_new3(etype, str)
    VALUE etype, str;
{
    StringValue(str);
    return rb_funcall(etype, rb_intern("new"), 1, str);
}

/*
 * call-seq:
 *    Exception.new(msg = nil)   =>  exception
 *
 *  Construct a new Exception object, optionally passing in
 *  a message.
 */

static VALUE
exc_initialize(argc, argv, exc)
    int argc;
    VALUE *argv;
    VALUE exc;
{
    VALUE arg;

    rb_scan_args(argc, argv, "01", &arg);
    rb_iv_set(exc, "mesg", arg);
    rb_iv_set(exc, "bt", Qnil);

    return exc;
}

/*
 *  Document-method: exception
 *
 *  call-seq:
 *     exc.exception(string) -> an_exception or exc
 *
 *  With no argument, or if the argument is the same as the receiver,
 *  return the receiver. Otherwise, create a new
 *  exception object of the same class as the receiver, but with a
 *  message equal to string.to_str.
 *
 */

static VALUE
exc_exception(argc, argv, self)
    int argc;
    VALUE *argv;
    VALUE self;
{
    VALUE exc;

    if (argc == 0) return self;
    if (argc == 1 && self == argv[0]) return self;
    exc = rb_obj_clone(self);
    exc_initialize(argc, argv, exc);

    return exc;
}

/*
 * call-seq:
 *   exception.to_s   =>  string
 *
 * Returns exception's message (or the name of the exception if
 * no message is set).
 */

static VALUE
exc_to_s(exc)
    VALUE exc;
{
    VALUE mesg = rb_attr_get(exc, rb_intern("mesg"));

    if (NIL_P(mesg)) return rb_class_name(CLASS_OF(exc));
    if (OBJ_TAINTED(exc)) OBJ_TAINT(mesg);
    return mesg;
}

/*
 * call-seq:
 *   exception.message   =>  string
 *   exception.to_str    =>  string
 *
 * Returns the result of invoking exception.to_s.
 * Normally this returns the exception's message or name. By
 * supplying a to_str method, exceptions are agreeing to
 * be used where Strings are expected.
 */

static VALUE
exc_to_str(exc)
    VALUE exc;
{
    return rb_funcall(exc, rb_intern("to_s"), 0, 0);
}

/*
 * call-seq:
 *   exception.inspect   => string
 *
 * Return this exception's class name an message
 */

static VALUE
exc_inspect(exc)
    VALUE exc;
{
    VALUE str, klass;

    klass = CLASS_OF(exc);
    exc = rb_obj_as_string(exc);
    if (RSTRING(exc)->len == 0) {
	return rb_str_dup(rb_class_name(klass));
    }

    str = rb_str_buf_new2("#<");
    klass = rb_class_name(klass);
    rb_str_buf_append(str, klass);
    rb_str_buf_cat(str, ": ", 2);
    rb_str_buf_append(str, exc);
    rb_str_buf_cat(str, ">", 1);

    return str;
}

/*
 *  call-seq:
 *     exception.backtrace    => array
 *
 *  Returns any backtrace associated with the exception. The backtrace
 *  is an array of strings, each containing either ``filename:lineNo: in
 *  `method''' or ``filename:lineNo.''
 *
 *     def a
 *       raise "boom"
 *     end
 *
 *     def b
 *       a()
 *     end
 *
 *     begin
 *       b()
 *     rescue => detail
 *       print detail.backtrace.join("\n")
 *     end
 *
 *  produces:
 *
 *     prog.rb:2:in `a'
 *     prog.rb:6:in `b'
 *     prog.rb:10
*/

static VALUE
exc_backtrace(exc)
    VALUE exc;
{
    static ID bt;

    if (!bt) bt = rb_intern("bt");
    return rb_attr_get(exc, bt);
}

VALUE
rb_check_backtrace(bt)
    VALUE bt;
{
    long i;
    static const char err[] = "backtrace must be Array of String";

    if (!NIL_P(bt)) {
	int t = TYPE(bt);

	if (t == T_STRING) return rb_ary_new3(1, bt);
	if (t != T_ARRAY) {
	    rb_raise(rb_eTypeError, err);
	}
	for (i=0;ilen;i++) {
	    if (TYPE(RARRAY(bt)->ptr[i]) != T_STRING) {
		rb_raise(rb_eTypeError, err);
	    }
	}
    }
    return bt;
}

/*
 *  call-seq:
 *     exc.set_backtrace(array)   =>  array
 *
 *  Sets the backtrace information associated with exc. The
 *  argument must be an array of String objects in the
 *  format described in Exception#backtrace.
 *
 */

static VALUE
exc_set_backtrace(exc, bt)
    VALUE exc;
    VALUE bt;
{
    return rb_iv_set(exc, "bt", rb_check_backtrace(bt));
}

/*
 * call-seq:
 *   SystemExit.new(status=0)   => system_exit
 *
 * Create a new +SystemExit+ exception with the given status.
 */

static VALUE
exit_initialize(argc, argv, exc)
    int argc;
    VALUE *argv;
    VALUE exc;
{
    VALUE status = INT2FIX(EXIT_SUCCESS);
    if (argc > 0 && FIXNUM_P(argv[0])) {
	status = *argv++;
	--argc;
    }
    rb_call_super(argc, argv);
    rb_iv_set(exc, "status", status);
    return exc;
}


/*
 * call-seq:
 *   system_exit.status   => fixnum
 *
 * Return the status value associated with this system exit.
 */

static VALUE
exit_status(exc)
    VALUE exc;
{
    return rb_attr_get(exc, rb_intern("status"));
}


/*
 * call-seq:
 *   system_exit.success?  => true or false
 *
 * Returns +true+ if exiting successful, +false+ if not.
 */

static VALUE
exit_success_p(exc)
    VALUE exc;
{
    VALUE status = rb_attr_get(exc, rb_intern("status"));
    if (NIL_P(status)) return Qtrue;
    if (status == INT2FIX(EXIT_SUCCESS)) return Qtrue;
    return Qfalse;
}

void
#ifdef HAVE_STDARG_PROTOTYPES
rb_name_error(ID id, const char *fmt, ...)
#else
rb_name_error(id, fmt, va_alist)
    ID id;
    const char *fmt;
    va_dcl
#endif
{
    VALUE exc, argv[2];
    va_list args;
    char buf[BUFSIZ];

    va_init_list(args, fmt);
    vsnprintf(buf, BUFSIZ, fmt, args);
    va_end(args);

    argv[0] = rb_str_new2(buf);
    argv[1] = ID2SYM(id);
    exc = rb_class_new_instance(2, argv, rb_eNameError);
    rb_exc_raise(exc);
}

/*
 * call-seq:
 *   NameError.new(msg [, name])  => name_error
 *
 * Construct a new NameError exception. If given the name
 * parameter may subsequently be examined using the NameError.name
 * method.
 */

static VALUE
name_err_initialize(argc, argv, self)
    int argc;
    VALUE *argv;
    VALUE self;
{
    VALUE name;

    name = (argc > 1) ? argv[--argc] : Qnil;
    rb_call_super(argc, argv);
    rb_iv_set(self, "name", name);
    return self;
}

/*
 *  call-seq:
 *    name_error.name    =>  string or nil
 *
 *  Return the name associated with this NameError exception.
 */

static VALUE
name_err_name(self)
    VALUE self;
{
    return rb_attr_get(self, rb_intern("name"));
}

/*
 * call-seq:
 *  name_error.to_s   => string
 *
 * Produce a nicely-formated string representing the +NameError+.
 */

static VALUE
name_err_to_s(exc)
    VALUE exc;
{
    VALUE mesg = rb_attr_get(exc, rb_intern("mesg")), str = mesg;

    if (NIL_P(mesg)) return rb_class_name(CLASS_OF(exc));
    StringValue(str);
    if (str != mesg) {
	rb_iv_set(exc, "mesg", mesg = str);
    }
    if (OBJ_TAINTED(exc)) OBJ_TAINT(mesg);
    return mesg;
}

/*
 * call-seq:
 *   NoMethodError.new(msg, name [, args])  => no_method_error
 *
 * Construct a NoMethodError exception for a method of the given name
 * called with the given arguments. The name may be accessed using
 * the #name method on the resulting object, and the
 * arguments using the #args method.
 */

static VALUE
nometh_err_initialize(argc, argv, self)
    int argc;
    VALUE *argv;
    VALUE self;
{
    VALUE args = (argc > 2) ? argv[--argc] : Qnil;
    name_err_initialize(argc, argv, self);
    rb_iv_set(self, "args", args);
    return self;
}

/* :nodoc: */
static void
name_err_mesg_mark(ptr)
    VALUE *ptr;
{
    rb_gc_mark_locations(ptr, ptr+3);
}

/* :nodoc: */
static VALUE
name_err_mesg_new(obj, mesg, recv, method)
    VALUE obj, mesg, recv, method;
{
    VALUE *ptr = ALLOC_N(VALUE, 3);

    ptr[0] = mesg;
    ptr[1] = recv;
    ptr[2] = method;
    return Data_Wrap_Struct(rb_cNameErrorMesg, name_err_mesg_mark, -1, ptr);
}

/* :nodoc: */
static VALUE
name_err_mesg_to_str(obj)
    VALUE obj;
{
    VALUE *ptr, mesg;
    Data_Get_Struct(obj, VALUE, ptr);

    mesg = ptr[0];
    if (NIL_P(mesg)) return Qnil;
    else {
	const char *desc = 0;
	VALUE d = 0, args[3];

	obj = ptr[1];
	switch (TYPE(obj)) {
	  case T_NIL:
	    desc = "nil";
	    break;
	  case T_TRUE:
	    desc = "true";
	    break;
	  case T_FALSE:
	    desc = "false";
	    break;
	  default:
	    d = rb_protect(rb_inspect, obj, 0);
	    if (NIL_P(d) || RSTRING(d)->len > 65) {
		d = rb_any_to_s(obj);
	    }
	    desc = RSTRING(d)->ptr;
	    break;
	}
	if (desc && desc[0] != '#') {
	    d = rb_str_new2(desc);
	    rb_str_cat2(d, ":");
	    rb_str_cat2(d, rb_obj_classname(obj));
	}
	args[0] = mesg;
	args[1] = ptr[2];
	args[2] = d;
	mesg = rb_f_sprintf(3, args);
    }
    if (OBJ_TAINTED(obj)) OBJ_TAINT(mesg);
    return mesg;
}

/* :nodoc: */
static VALUE
name_err_mesg_load(klass, str)
    VALUE klass, str;
{
    return str;
}

/*
 * call-seq:
 *   no_method_error.args  => obj
 *
 * Return the arguments passed in as the third parameter to
 * the constructor.
 */

static VALUE
nometh_err_args(self)
    VALUE self;
{
    return rb_attr_get(self, rb_intern("args"));
}

void
rb_invalid_str(str, type)
    const char *str, *type;
{
    VALUE s = rb_str_inspect(rb_str_new2(str));

    rb_raise(rb_eArgError, "invalid value for %s: %s", type, RSTRING(s)->ptr);
}

/*
 *  Document-module: Errno
 *
 *  Ruby exception objects are subclasses of Exception.
 *  However, operating systems typically report errors using plain
 *  integers. Module Errno is created dynamically to map
 *  these operating system errors to Ruby classes, with each error
 *  number generating its own subclass of SystemCallError.
 *  As the subclass is created in module Errno, its name
 *  will start Errno::.
 *
 *  The names of the Errno:: classes depend on
 *  the environment in which Ruby runs. On a typical Unix or Windows
 *  platform, there are Errno classes such as
 *  Errno::EACCES, Errno::EAGAIN,
 *  Errno::EINTR, and so on.
 *
 *  The integer operating system error number corresponding to a
 *  particular error is available as the class constant
 *  Errno::error::Errno.
 *
 *     Errno::EACCES::Errno   #=> 13
 *     Errno::EAGAIN::Errno   #=> 11
 *     Errno::EINTR::Errno    #=> 4
 *
 *  The full list of operating system errors on your particular platform
 *  are available as the constants of Errno.
 *
 *     Errno.constants   #=> E2BIG, EACCES, EADDRINUSE, EADDRNOTAVAIL, ...
 */

static st_table *syserr_tbl;

static VALUE
set_syserr(n, name)
    int n;
    const char *name;
{
    VALUE error;

    if (!st_lookup(syserr_tbl, n, &error)) {
	error = rb_define_class_under(rb_mErrno, name, rb_eSystemCallError);
	rb_define_const(error, "Errno", INT2NUM(n));
	st_add_direct(syserr_tbl, n, error);
    }
    else {
	rb_define_const(rb_mErrno, name, error);
    }
    return error;
}

static VALUE
get_syserr(n)
    int n;
{
    VALUE error;

    if (!st_lookup(syserr_tbl, n, &error)) {
	char name[8];	/* some Windows' errno have 5 digits. */

	snprintf(name, sizeof(name), "E%03d", n);
	error = set_syserr(n, name);
    }
    return error;
}

/*
 * call-seq:
 *   SystemCallError.new(msg, errno)  => system_call_error_subclass
 *
 * If _errno_ corresponds to a known system error code, constructs
 * the appropriate Errno class for that error, otherwise
 * constructs a generic SystemCallError object. The
 * error number is subsequently available via the errno
 * method.
 */

static VALUE
syserr_initialize(argc, argv, self)
    int argc;
    VALUE *argv;
    VALUE self;
{
#if !defined(_WIN32) && !defined(__VMS)
    char *strerror();
#endif
    const char *err;
    VALUE mesg, error;
    VALUE klass = rb_obj_class(self);

    if (klass == rb_eSystemCallError) {
	rb_scan_args(argc, argv, "11", &mesg, &error);
	if (argc == 1 && FIXNUM_P(mesg)) {
	    error = mesg; mesg = Qnil;
	}
	if (!NIL_P(error) && st_lookup(syserr_tbl, NUM2LONG(error), &klass)) {
	    /* change class */
	    if (TYPE(self) != T_OBJECT) { /* insurance to avoid type crash */
		rb_raise(rb_eTypeError, "invalid instance type");
	    }
	    RBASIC(self)->klass = klass;
	}
    }
    else {
	rb_scan_args(argc, argv, "01", &mesg);
	error = rb_const_get(klass, rb_intern("Errno"));
    }
    if (!NIL_P(error)) err = strerror(NUM2LONG(error));
    else err = "unknown error";
    if (!NIL_P(mesg)) {
	VALUE str = mesg;
	size_t len;

	StringValue(str);
	len = strlen(err)+RSTRING(str)->len+3;
	mesg = rb_str_new(0, len);
	snprintf(RSTRING(mesg)->ptr, len+1, "%s - %.*s", err,
		(int)RSTRING(str)->len, RSTRING(str)->ptr);
	rb_str_resize(mesg, strlen(RSTRING(mesg)->ptr));
    }
    else {
	mesg = rb_str_new2(err);
    }
    rb_call_super(1, &mesg);
    rb_iv_set(self, "errno", error);
    return self;
}

/*
 * call-seq:
 *   system_call_error.errno   => fixnum
 *
 * Return this SystemCallError's error number.
 */

static VALUE
syserr_errno(self)
    VALUE self;
{
    return rb_attr_get(self, rb_intern("errno"));
}

/*
 * call-seq:
 *   system_call_error === other  => true or false
 *
 * Return +true+ if the receiver is a generic +SystemCallError+, or
 * if the error numbers _self_ and _other_ are the same.
 */


static VALUE
syserr_eqq(self, exc)
    VALUE self, exc;
{
    VALUE num, e;
    ID en = rb_intern("errno");

    if (!rb_obj_is_kind_of(exc, rb_eSystemCallError)) {
	if (!rb_respond_to(exc, en)) return Qfalse;
    }
    else if (self == rb_eSystemCallError) return Qtrue;

    num = rb_attr_get(exc, en);
    if (NIL_P(num)) {
	num = rb_funcall(exc, en, 0, 0);
    }
    e = rb_const_get(self, rb_intern("Errno"));
    if (FIXNUM_P(num) ? num == e : rb_equal(num, e))
	return Qtrue;
    return Qfalse;
}

/*
 *  Descendents of class Exception are used to communicate
 *  between raise methods and rescue
 *  statements in begin/end blocks. Exception
 *  objects carry information about the exception---its type (the
 *  exception's class name), an optional descriptive string, and
 *  optional traceback information. Programs may subclass
 *  Exception to add additional information.
 */

void
Init_Exception()
{
    rb_eException   = rb_define_class("Exception", rb_cObject);
    rb_define_singleton_method(rb_eException, "exception", rb_class_new_instance, -1);
    rb_define_method(rb_eException, "exception", exc_exception, -1);
    rb_define_method(rb_eException, "initialize", exc_initialize, -1);
    rb_define_method(rb_eException, "to_s", exc_to_s, 0);
    rb_define_method(rb_eException, "to_str", exc_to_str, 0);
    rb_define_method(rb_eException, "message", exc_to_str, 0);
    rb_define_method(rb_eException, "inspect", exc_inspect, 0);
    rb_define_method(rb_eException, "backtrace", exc_backtrace, 0);
    rb_define_method(rb_eException, "set_backtrace", exc_set_backtrace, 1);

    rb_eSystemExit  = rb_define_class("SystemExit", rb_eException);
    rb_define_method(rb_eSystemExit, "initialize", exit_initialize, -1);
    rb_define_method(rb_eSystemExit, "status", exit_status, 0);
    rb_define_method(rb_eSystemExit, "success?", exit_success_p, 0);

    rb_eFatal  	    = rb_define_class("fatal", rb_eException);
    rb_eSignal      = rb_define_class("SignalException", rb_eException);
    rb_eInterrupt   = rb_define_class("Interrupt", rb_eSignal);

    rb_eStandardError = rb_define_class("StandardError", rb_eException);
    rb_eTypeError     = rb_define_class("TypeError", rb_eStandardError);
    rb_eArgError      = rb_define_class("ArgumentError", rb_eStandardError);
    rb_eIndexError    = rb_define_class("IndexError", rb_eStandardError);
    rb_eRangeError    = rb_define_class("RangeError", rb_eStandardError);
    rb_eNameError     = rb_define_class("NameError", rb_eStandardError);
    rb_define_method(rb_eNameError, "initialize", name_err_initialize, -1);
    rb_define_method(rb_eNameError, "name", name_err_name, 0);
    rb_define_method(rb_eNameError, "to_s", name_err_to_s, 0);
    rb_cNameErrorMesg = rb_define_class_under(rb_eNameError, "message", rb_cData);
    rb_define_singleton_method(rb_cNameErrorMesg, "!", name_err_mesg_new, 3);
    rb_define_method(rb_cNameErrorMesg, "to_str", name_err_mesg_to_str, 0);
    rb_define_method(rb_cNameErrorMesg, "_dump", name_err_mesg_to_str, 1);
    rb_define_singleton_method(rb_cNameErrorMesg, "_load", name_err_mesg_load, 1);
    rb_eNoMethodError = rb_define_class("NoMethodError", rb_eNameError);
    rb_define_method(rb_eNoMethodError, "initialize", nometh_err_initialize, -1);
    rb_define_method(rb_eNoMethodError, "args", nometh_err_args, 0);

    rb_eScriptError = rb_define_class("ScriptError", rb_eException);
    rb_eSyntaxError = rb_define_class("SyntaxError", rb_eScriptError);
    rb_eLoadError   = rb_define_class("LoadError", rb_eScriptError);
    rb_eNotImpError = rb_define_class("NotImplementedError", rb_eScriptError);

    rb_eRuntimeError = rb_define_class("RuntimeError", rb_eStandardError);
    rb_eSecurityError = rb_define_class("SecurityError", rb_eStandardError);
    rb_eNoMemError = rb_define_class("NoMemoryError", rb_eException);

    syserr_tbl = st_init_numtable();
    rb_eSystemCallError = rb_define_class("SystemCallError", rb_eStandardError);
    rb_define_method(rb_eSystemCallError, "initialize", syserr_initialize, -1);
    rb_define_method(rb_eSystemCallError, "errno", syserr_errno, 0);
    rb_define_singleton_method(rb_eSystemCallError, "===", syserr_eqq, 1);

    rb_mErrno = rb_define_module("Errno");

    rb_define_global_function("warn", rb_warn_m, 1);
}

void
#ifdef HAVE_STDARG_PROTOTYPES
rb_raise(VALUE exc, const char *fmt, ...)
#else
rb_raise(exc, fmt, va_alist)
    VALUE exc;
    const char *fmt;
    va_dcl
#endif
{
    va_list args;
    char buf[BUFSIZ];

    va_init_list(args,fmt);
    vsnprintf(buf, BUFSIZ, fmt, args);
    va_end(args);
    rb_exc_raise(rb_exc_new2(exc, buf));
}

void
#ifdef HAVE_STDARG_PROTOTYPES
rb_loaderror(const char *fmt, ...)
#else
rb_loaderror(fmt, va_alist)
    const char *fmt;
    va_dcl
#endif
{
    va_list args;
    char buf[BUFSIZ];

    va_init_list(args, fmt);
    vsnprintf(buf, BUFSIZ, fmt, args);
    va_end(args);
    rb_exc_raise(rb_exc_new2(rb_eLoadError, buf));
}

void
rb_notimplement()
{
    rb_raise(rb_eNotImpError,
	     "%s() function is unimplemented on this machine",
	     rb_id2name(ruby_frame->last_func));
}

void
#ifdef HAVE_STDARG_PROTOTYPES
rb_fatal(const char *fmt, ...)
#else
rb_fatal(fmt, va_alist)
    const char *fmt;
    va_dcl
#endif
{
    va_list args;
    char buf[BUFSIZ];

    va_init_list(args, fmt);
    vsnprintf(buf, BUFSIZ, fmt, args);
    va_end(args);

    ruby_in_eval = 0;
    rb_exc_fatal(rb_exc_new2(rb_eFatal, buf));
}

void
rb_sys_fail(mesg)
    const char *mesg;
{
    int n = errno;
    VALUE arg;

    errno = 0;
    if (n == 0) {
	rb_bug("rb_sys_fail(%s) - errno == 0", mesg ? mesg : "");
    }

    arg = mesg ? rb_str_new2(mesg) : Qnil;
    rb_exc_raise(rb_class_new_instance(1, &arg, get_syserr(n)));
}

void
#ifdef HAVE_STDARG_PROTOTYPES
rb_sys_warning(const char *fmt, ...)
#else
rb_sys_warning(fmt, va_alist)
     const char *fmt;
     va_dcl
#endif
{
     char buf[BUFSIZ];
     va_list args;
     int errno_save;

     errno_save = errno;

     if (!RTEST(ruby_verbose)) return;

     snprintf(buf, BUFSIZ, "warning: %s", fmt);
     snprintf(buf+strlen(buf), BUFSIZ-strlen(buf), ": %s", strerror(errno_save));

     va_init_list(args, fmt);
     warn_print(buf, args);
     va_end(args);
     errno = errno_save;
}

void
rb_load_fail(path)
    const char *path;
{
    rb_loaderror("%s -- %s", strerror(errno), path);
}

void
rb_error_frozen(what)
    const char *what;
{
    rb_raise(rb_eTypeError, "can't modify frozen %s", what);
}

void
rb_check_frozen(obj)
    VALUE obj;
{
    if (OBJ_FROZEN(obj)) rb_error_frozen(rb_obj_classname(obj));
}

void
Init_syserr()
{
#ifdef EPERM
    set_syserr(EPERM, "EPERM");
#endif
#ifdef ENOENT
    set_syserr(ENOENT, "ENOENT");
#endif
#ifdef ESRCH
    set_syserr(ESRCH, "ESRCH");
#endif
#ifdef EINTR
    set_syserr(EINTR, "EINTR");
#endif
#ifdef EIO
    set_syserr(EIO, "EIO");
#endif
#ifdef ENXIO
    set_syserr(ENXIO, "ENXIO");
#endif
#ifdef E2BIG
    set_syserr(E2BIG, "E2BIG");
#endif
#ifdef ENOEXEC
    set_syserr(ENOEXEC, "ENOEXEC");
#endif
#ifdef EBADF
    set_syserr(EBADF, "EBADF");
#endif
#ifdef ECHILD
    set_syserr(ECHILD, "ECHILD");
#endif
#ifdef EAGAIN
    set_syserr(EAGAIN, "EAGAIN");
#endif
#ifdef ENOMEM
    set_syserr(ENOMEM, "ENOMEM");
#endif
#ifdef EACCES
    set_syserr(EACCES, "EACCES");
#endif
#ifdef EFAULT
    set_syserr(EFAULT, "EFAULT");
#endif
#ifdef ENOTBLK
    set_syserr(ENOTBLK, "ENOTBLK");
#endif
#ifdef EBUSY
    set_syserr(EBUSY, "EBUSY");
#endif
#ifdef EEXIST
    set_syserr(EEXIST, "EEXIST");
#endif
#ifdef EXDEV
    set_syserr(EXDEV, "EXDEV");
#endif
#ifdef ENODEV
    set_syserr(ENODEV, "ENODEV");
#endif
#ifdef ENOTDIR
    set_syserr(ENOTDIR, "ENOTDIR");
#endif
#ifdef EISDIR
    set_syserr(EISDIR, "EISDIR");
#endif
#ifdef EINVAL
    set_syserr(EINVAL, "EINVAL");
#endif
#ifdef ENFILE
    set_syserr(ENFILE, "ENFILE");
#endif
#ifdef EMFILE
    set_syserr(EMFILE, "EMFILE");
#endif
#ifdef ENOTTY
    set_syserr(ENOTTY, "ENOTTY");
#endif
#ifdef ETXTBSY
    set_syserr(ETXTBSY, "ETXTBSY");
#endif
#ifdef EFBIG
    set_syserr(EFBIG, "EFBIG");
#endif
#ifdef ENOSPC
    set_syserr(ENOSPC, "ENOSPC");
#endif
#ifdef ESPIPE
    set_syserr(ESPIPE, "ESPIPE");
#endif
#ifdef EROFS
    set_syserr(EROFS, "EROFS");
#endif
#ifdef EMLINK
    set_syserr(EMLINK, "EMLINK");
#endif
#ifdef EPIPE
    set_syserr(EPIPE, "EPIPE");
#endif
#ifdef EDOM
    set_syserr(EDOM, "EDOM");
#endif
#ifdef ERANGE
    set_syserr(ERANGE, "ERANGE");
#endif
#ifdef EDEADLK
    set_syserr(EDEADLK, "EDEADLK");
#endif
#ifdef ENAMETOOLONG
    set_syserr(ENAMETOOLONG, "ENAMETOOLONG");
#endif
#ifdef ENOLCK
    set_syserr(ENOLCK, "ENOLCK");
#endif
#ifdef ENOSYS
    set_syserr(ENOSYS, "ENOSYS");
#endif
#ifdef ENOTEMPTY
    set_syserr(ENOTEMPTY, "ENOTEMPTY");
#endif
#ifdef ELOOP
    set_syserr(ELOOP, "ELOOP");
#endif
#ifdef EWOULDBLOCK
    set_syserr(EWOULDBLOCK, "EWOULDBLOCK");
#endif
#ifdef ENOMSG
    set_syserr(ENOMSG, "ENOMSG");
#endif
#ifdef EIDRM
    set_syserr(EIDRM, "EIDRM");
#endif
#ifdef ECHRNG
    set_syserr(ECHRNG, "ECHRNG");
#endif
#ifdef EL2NSYNC
    set_syserr(EL2NSYNC, "EL2NSYNC");
#endif
#ifdef EL3HLT
    set_syserr(EL3HLT, "EL3HLT");
#endif
#ifdef EL3RST
    set_syserr(EL3RST, "EL3RST");
#endif
#ifdef ELNRNG
    set_syserr(ELNRNG, "ELNRNG");
#endif
#ifdef EUNATCH
    set_syserr(EUNATCH, "EUNATCH");
#endif
#ifdef ENOCSI
    set_syserr(ENOCSI, "ENOCSI");
#endif
#ifdef EL2HLT
    set_syserr(EL2HLT, "EL2HLT");
#endif
#ifdef EBADE
    set_syserr(EBADE, "EBADE");
#endif
#ifdef EBADR
    set_syserr(EBADR, "EBADR");
#endif
#ifdef EXFULL
    set_syserr(EXFULL, "EXFULL");
#endif
#ifdef ENOANO
    set_syserr(ENOANO, "ENOANO");
#endif
#ifdef EBADRQC
    set_syserr(EBADRQC, "EBADRQC");
#endif
#ifdef EBADSLT
    set_syserr(EBADSLT, "EBADSLT");
#endif
#ifdef EDEADLOCK
    set_syserr(EDEADLOCK, "EDEADLOCK");
#endif
#ifdef EBFONT
    set_syserr(EBFONT, "EBFONT");
#endif
#ifdef ENOSTR
    set_syserr(ENOSTR, "ENOSTR");
#endif
#ifdef ENODATA
    set_syserr(ENODATA, "ENODATA");
#endif
#ifdef ETIME
    set_syserr(ETIME, "ETIME");
#endif
#ifdef ENOSR
    set_syserr(ENOSR, "ENOSR");
#endif
#ifdef ENONET
    set_syserr(ENONET, "ENONET");
#endif
#ifdef ENOPKG
    set_syserr(ENOPKG, "ENOPKG");
#endif
#ifdef EREMOTE
    set_syserr(EREMOTE, "EREMOTE");
#endif
#ifdef ENOLINK
    set_syserr(ENOLINK, "ENOLINK");
#endif
#ifdef EADV
    set_syserr(EADV, "EADV");
#endif
#ifdef ESRMNT
    set_syserr(ESRMNT, "ESRMNT");
#endif
#ifdef ECOMM
    set_syserr(ECOMM, "ECOMM");
#endif
#ifdef EPROTO
    set_syserr(EPROTO, "EPROTO");
#endif
#ifdef EMULTIHOP
    set_syserr(EMULTIHOP, "EMULTIHOP");
#endif
#ifdef EDOTDOT
    set_syserr(EDOTDOT, "EDOTDOT");
#endif
#ifdef EBADMSG
    set_syserr(EBADMSG, "EBADMSG");
#endif
#ifdef EOVERFLOW
    set_syserr(EOVERFLOW, "EOVERFLOW");
#endif
#ifdef ENOTUNIQ
    set_syserr(ENOTUNIQ, "ENOTUNIQ");
#endif
#ifdef EBADFD
    set_syserr(EBADFD, "EBADFD");
#endif
#ifdef EREMCHG
    set_syserr(EREMCHG, "EREMCHG");
#endif
#ifdef ELIBACC
    set_syserr(ELIBACC, "ELIBACC");
#endif
#ifdef ELIBBAD
    set_syserr(ELIBBAD, "ELIBBAD");
#endif
#ifdef ELIBSCN
    set_syserr(ELIBSCN, "ELIBSCN");
#endif
#ifdef ELIBMAX
    set_syserr(ELIBMAX, "ELIBMAX");
#endif
#ifdef ELIBEXEC
    set_syserr(ELIBEXEC, "ELIBEXEC");
#endif
#ifdef EILSEQ
    set_syserr(EILSEQ, "EILSEQ");
#endif
#ifdef ERESTART
    set_syserr(ERESTART, "ERESTART");
#endif
#ifdef ESTRPIPE
    set_syserr(ESTRPIPE, "ESTRPIPE");
#endif
#ifdef EUSERS
    set_syserr(EUSERS, "EUSERS");
#endif
#ifdef ENOTSOCK
    set_syserr(ENOTSOCK, "ENOTSOCK");
#endif
#ifdef EDESTADDRREQ
    set_syserr(EDESTADDRREQ, "EDESTADDRREQ");
#endif
#ifdef EMSGSIZE
    set_syserr(EMSGSIZE, "EMSGSIZE");
#endif
#ifdef EPROTOTYPE
    set_syserr(EPROTOTYPE, "EPROTOTYPE");
#endif
#ifdef ENOPROTOOPT
    set_syserr(ENOPROTOOPT, "ENOPROTOOPT");
#endif
#ifdef EPROTONOSUPPORT
    set_syserr(EPROTONOSUPPORT, "EPROTONOSUPPORT");
#endif
#ifdef ESOCKTNOSUPPORT
    set_syserr(ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT");
#endif
#ifdef EOPNOTSUPP
    set_syserr(EOPNOTSUPP, "EOPNOTSUPP");
#endif
#ifdef EPFNOSUPPORT
    set_syserr(EPFNOSUPPORT, "EPFNOSUPPORT");
#endif
#ifdef EAFNOSUPPORT
    set_syserr(EAFNOSUPPORT, "EAFNOSUPPORT");
#endif
#ifdef EADDRINUSE
    set_syserr(EADDRINUSE, "EADDRINUSE");
#endif
#ifdef EADDRNOTAVAIL
    set_syserr(EADDRNOTAVAIL, "EADDRNOTAVAIL");
#endif
#ifdef ENETDOWN
    set_syserr(ENETDOWN, "ENETDOWN");
#endif
#ifdef ENETUNREACH
    set_syserr(ENETUNREACH, "ENETUNREACH");
#endif
#ifdef ENETRESET
    set_syserr(ENETRESET, "ENETRESET");
#endif
#ifdef ECONNABORTED
    set_syserr(ECONNABORTED, "ECONNABORTED");
#endif
#ifdef ECONNRESET
    set_syserr(ECONNRESET, "ECONNRESET");
#endif
#ifdef ENOBUFS
    set_syserr(ENOBUFS, "ENOBUFS");
#endif
#ifdef EISCONN
    set_syserr(EISCONN, "EISCONN");
#endif
#ifdef ENOTCONN
    set_syserr(ENOTCONN, "ENOTCONN");
#endif
#ifdef ESHUTDOWN
    set_syserr(ESHUTDOWN, "ESHUTDOWN");
#endif
#ifdef ETOOMANYREFS
    set_syserr(ETOOMANYREFS, "ETOOMANYREFS");
#endif
#ifdef ETIMEDOUT
    set_syserr(ETIMEDOUT, "ETIMEDOUT");
#endif
#ifdef ECONNREFUSED
    set_syserr(ECONNREFUSED, "ECONNREFUSED");
#endif
#ifdef EHOSTDOWN
    set_syserr(EHOSTDOWN, "EHOSTDOWN");
#endif
#ifdef EHOSTUNREACH
    set_syserr(EHOSTUNREACH, "EHOSTUNREACH");
#endif
#ifdef EALREADY
    set_syserr(EALREADY, "EALREADY");
#endif
#ifdef EINPROGRESS
    set_syserr(EINPROGRESS, "EINPROGRESS");
#endif
#ifdef ESTALE
    set_syserr(ESTALE, "ESTALE");
#endif
#ifdef EUCLEAN
    set_syserr(EUCLEAN, "EUCLEAN");
#endif
#ifdef ENOTNAM
    set_syserr(ENOTNAM, "ENOTNAM");
#endif
#ifdef ENAVAIL
    set_syserr(ENAVAIL, "ENAVAIL");
#endif
#ifdef EISNAM
    set_syserr(EISNAM, "EISNAM");
#endif
#ifdef EREMOTEIO
    set_syserr(EREMOTEIO, "EREMOTEIO");
#endif
#ifdef EDQUOT
    set_syserr(EDQUOT, "EDQUOT");
#endif
}

static void
err_append(s)
    const char *s;
{
    extern VALUE ruby_errinfo;

    if (ruby_in_eval) {
	if (NIL_P(ruby_errinfo)) {
	    ruby_errinfo = rb_exc_new2(rb_eSyntaxError, s);
	}
	else {
	    VALUE str = rb_obj_as_string(ruby_errinfo);

	    rb_str_cat2(str, "\n");
	    rb_str_cat2(str, s);
	    ruby_errinfo = rb_exc_new3(rb_eSyntaxError, str);
	}
    }
    else {
	rb_write_error(s);
	rb_write_error("\n");
    }
}


================================================
FILE: eval.c
================================================
/**********************************************************************

  eval.c -

  $Author$
  $Date$
  created at: Thu Jun 10 14:22:17 JST 1993

  Copyright (C) 1993-2003 Yukihiro Matsumoto
  Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
  Copyright (C) 2000  Information-technology Promotion Agency, Japan

**********************************************************************/

#include "ruby.h"
#include "node.h"
#include "env.h"
#include "util.h"
#include "rubysig.h"

#ifdef HAVE_STDLIB_H
#include 
#endif
#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 0
#endif
#ifndef EXIT_FAILURE
#define EXIT_FAILURE 1
#endif

#include 

#include "st.h"
#include "dln.h"

#ifdef GC_DEBUG
RUBY_EXTERN int gc_debug_dump;
#endif

#ifdef __APPLE__
#include 
#endif

/* Make alloca work the best possible way.  */
#ifdef __GNUC__
# ifndef atarist
#  ifndef alloca
#   define alloca __builtin_alloca
#  endif
# endif /* atarist */
#else
# ifdef HAVE_ALLOCA_H
#  include 
# else
#  ifndef _AIX
#   ifndef alloca /* predefined by HP cc +Olibcalls */
void *alloca ();
#   endif
#  endif /* AIX */
# endif /* HAVE_ALLOCA_H */
#endif /* __GNUC__ */

#ifdef HAVE_STDARG_PROTOTYPES
#include 
#define va_init_list(a,b) va_start(a,b)
#else
#include 
#define va_init_list(a,b) va_start(a)
#endif

#ifndef HAVE_STRING_H
char *strrchr _((const char*,const char));
#endif

#ifdef HAVE_UNISTD_H
#include 
#endif

#include 
#include 

#if defined(HAVE_FCNTL_H) || defined(_WIN32)
#include 
#elif defined(HAVE_SYS_FCNTL_H)
#include 
#endif
#ifdef __CYGWIN__
#include 
#endif

#if defined(__BEOS__) && !defined(BONE)
#include 
#endif

#ifdef __MACOS__
#include "macruby_private.h"
#endif

#ifdef __VMS
#include "vmsruby_private.h"
#endif

#ifdef USE_CONTEXT

NORETURN(static void rb_jump_context(rb_jmpbuf_t, int));
static inline void
rb_jump_context(env, val)
    rb_jmpbuf_t env;
    int val;
{
    env->status = val;
    setcontext(&env->context);
    abort();                    /* ensure noreturn */
}
/*
 * PRE_GETCONTEXT and POST_GETCONTEXT is a magic for getcontext, gcc,
 * IA64 register stack and SPARC register window combination problem.
 *
 * Assume following code sequence.
 *
 * 1. set a register in the register stack/window such as r32/l0.
 * 2. call getcontext.
 * 3. use the register.
 * 4. update the register for other use.
 * 5. call setcontext indirectly (or directly).
 *
 * This code should be run as 1->2->3->4->5->3->4.
 * But after second getcontext return (second 3),
 * the register is broken (updated).
 * It's because getcontext/setcontext doesn't preserve the content of the
 * register stack/window.
 *
 * setjmp also doesn't preserve the content of the register stack/window.
 * But it has not the problem because gcc knows setjmp may return twice.
 * gcc detects setjmp and generates setjmp safe code.
 *
 * So setjmp calls before and after the getcontext call makes the code
 * somewhat safe.
 * It fix the problem on IA64.
 * It is not required that setjmp is called at run time, since the problem is
 * register usage.
 *
 * Since the magic setjmp is not enough for SPARC,
 * inline asm is used to prohibit registers in register windows.
 *
 * Since the problem is fixed at gcc 4.0.3, the magic is applied only for
 * prior versions of gcc.
 * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21957
 * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22127
 */
#  define GCC_VERSION_BEFORE(major, minor, patchlevel) \
    (defined(__GNUC__) && !defined(__INTEL_COMPILER) && \
     ((__GNUC__ < (major)) ||  \
      (__GNUC__ == (major) && __GNUC_MINOR__ < (minor)) || \
      (__GNUC__ == (major) && __GNUC_MINOR__ == (minor) && __GNUC_PATCHLEVEL__ < (patchlevel))))
#  if GCC_VERSION_BEFORE(4,0,3) && (defined(sparc) || defined(__sparc__))
#    ifdef __pic__
/*
 * %l7 is excluded for PIC because it is PIC register.
 * http://lists.freebsd.org/pipermail/freebsd-sparc64/2006-January/003739.html
 */
#      define PRE_GETCONTEXT \
         ({ __asm__ volatile ("" : : :  \
            "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%o7", \
            "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", \
            "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%i7"); })
#    else
#      define PRE_GETCONTEXT \
         ({ __asm__ volatile ("" : : :  \
            "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%o7", \
            "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7", \
            "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%i7"); })
#    endif
#    define POST_GETCONTEXT PRE_GETCONTEXT
#  elif GCC_VERSION_BEFORE(4,0,3) && defined(__ia64)
static jmp_buf function_call_may_return_twice_jmp_buf;
int function_call_may_return_twice_false_1 = 0;
int function_call_may_return_twice_false_2 = 0;
#    define PRE_GETCONTEXT \
       (function_call_may_return_twice_false_1 ? \
        setjmp(function_call_may_return_twice_jmp_buf) : \
        0)
#    define POST_GETCONTEXT \
       (function_call_may_return_twice_false_2 ? \
        setjmp(function_call_may_return_twice_jmp_buf) : \
        0)
#  elif defined(__FreeBSD__) && __FreeBSD__ < 7
/*
 * workaround for FreeBSD/i386 getcontext/setcontext bug.
 * clear the carry flag by (0 ? ... : ...).
 * FreeBSD PR 92110 http://www.freebsd.org/cgi/query-pr.cgi?pr=92110
 * [ruby-dev:28263]
 */
static int volatile freebsd_clear_carry_flag = 0;
#    define PRE_GETCONTEXT \
       (freebsd_clear_carry_flag ? (freebsd_clear_carry_flag = 0) : 0)
#  endif
#  ifndef PRE_GETCONTEXT
#    define PRE_GETCONTEXT 0
#  endif
#  ifndef POST_GETCONTEXT
#    define POST_GETCONTEXT 0
#  endif
#  define ruby_longjmp(env, val) rb_jump_context(env, val)
#  define ruby_setjmp(just_before_setjmp, j) ((j)->status = 0, \
     (just_before_setjmp), \
     PRE_GETCONTEXT, \
     getcontext(&(j)->context), \
     POST_GETCONTEXT, \
     (j)->status)
#else
#  define ruby_setjmp(just_before_setjmp, env) \
     ((just_before_setjmp), RUBY_SETJMP(env))
#  define ruby_longjmp(env,val) RUBY_LONGJMP(env,val)
#  ifdef __CYGWIN__
int _setjmp(), _longjmp();
#  endif
#endif

#include 
#include 
#include 

#if defined(__VMS)
#pragma nostandard
#endif

#ifdef HAVE_SYS_SELECT_H
#include 
#endif

#include 

VALUE rb_cProc;
VALUE rb_cBinding;
static VALUE proc_invoke _((VALUE,VALUE,VALUE,VALUE));
static VALUE rb_f_binding _((VALUE));
NOINLINE(static void rb_f_END _((void)));
static VALUE rb_f_block_given_p _((void));
static VALUE block_pass _((VALUE,NODE*));
static void eval_check_tick _((void));

VALUE rb_cMethod;
static VALUE method_call _((int, VALUE*, VALUE));
VALUE rb_cUnboundMethod;
static VALUE umethod_bind _((VALUE, VALUE));
static VALUE rb_mod_define_method _((int, VALUE*, VALUE));
NORETURN(static void rb_raise_jump _((VALUE)));
static VALUE rb_make_exception _((int argc, VALUE *argv));

static int scope_vmode;
#define SCOPE_PUBLIC    0
#define SCOPE_PRIVATE   1
#define SCOPE_PROTECTED 2
#define SCOPE_MODFUNC   5
#define SCOPE_MASK      7
#define SCOPE_SET(f)  (scope_vmode=(f))
#define SCOPE_TEST(f) (scope_vmode&(f))

VALUE (*ruby_sandbox_save)_((rb_thread_t));
VALUE (*ruby_sandbox_restore)_((rb_thread_t));
NODE* ruby_current_node;

void
ruby_set_current_source()
{
    if (ruby_current_node) {
        ruby_sourcefile = ruby_current_node->nd_file;
        ruby_sourceline = nd_line(ruby_current_node);
    }
}

int ruby_safe_level = 0;
/* safe-level:
   0 - strings from streams/environment/ARGV are tainted (default)
   1 - no dangerous operation by tainted value
   2 - process/file operations prohibited
   3 - all generated objects are tainted
   4 - no global (non-tainted) variable modification/no direct output
*/

static VALUE safe_getter _((void));
static void safe_setter _((VALUE val));

void
rb_secure(level)
    int level;
{
    if (level <= ruby_safe_level) {
        if (ruby_frame->last_func) {
            rb_raise(rb_eSecurityError, "Insecure operation `%s' at level %d",
                     rb_id2name(ruby_frame->last_func), ruby_safe_level);
        }
        else {
            rb_raise(rb_eSecurityError, "Insecure operation at level %d", ruby_safe_level);
        }
    }
}

void
rb_secure_update(obj)
    VALUE obj;
{
    if (!OBJ_TAINTED(obj)) rb_secure(4);
}

void
rb_check_safe_obj(x)
    VALUE x;
{
    if (ruby_safe_level > 0 && OBJ_TAINTED(x)){
        if (ruby_frame->last_func) {
            rb_raise(rb_eSecurityError, "Insecure operation - %s",
                     rb_id2name(ruby_frame->last_func));
        }
        else {
            rb_raise(rb_eSecurityError, "Insecure operation: -r");
        }
    }
    rb_secure(4);
}

void
rb_check_safe_str(x)
    VALUE x;
{
    rb_check_safe_obj(x);
    if (TYPE(x)!= T_STRING) {
        rb_raise(rb_eTypeError, "wrong argument type %s (expected String)",
                 rb_obj_classname(x));
    }
}

NORETURN(static void print_undef _((VALUE, ID)));
static void
print_undef(klass, id)
    VALUE klass;
    ID id;
{
    rb_name_error(id, "undefined method `%s' for %s `%s'",
                  rb_id2name(id),
                  (TYPE(klass) == T_MODULE) ? "module" : "class",
                  rb_class2name(klass));
}

static ID removed, singleton_removed, undefined, singleton_undefined;

#define CACHE_SIZE 0x800
#define CACHE_MASK 0x7ff
#define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK)

struct cache_entry {            /* method hash table. */
    ID mid;                     /* method's id */
    ID mid0;                    /* method's original id */
    VALUE klass;                /* receiver's class */
    VALUE origin;               /* where method defined  */
    NODE *method;
    int noex;
};

static struct cache_entry cache[CACHE_SIZE];
static int ruby_running = 0;

void
rb_clear_cache()
{
   struct cache_entry *ent, *end;

    if (!ruby_running) return;
    ent = cache; end = ent + CACHE_SIZE;
    while (ent < end) {
        ent->mid = 0;
        ent++;
    }
}

static void
rb_clear_cache_for_undef(klass, id)
    VALUE klass;
    ID id;
{
    struct cache_entry *ent, *end;

    if (!ruby_running) return;
    ent = cache; end = ent + CACHE_SIZE;
    while (ent < end) {
        if (ent->mid == id &&
            (ent->klass == klass ||
             RCLASS(ent->origin)->m_tbl == RCLASS(klass)->m_tbl)) {
            ent->mid = 0;
        }
        ent++;
    }
}

static void
rb_clear_cache_by_id(id)
    ID id;
{
    struct cache_entry *ent, *end;

    if (!ruby_running) return;
    ent = cache; end = ent + CACHE_SIZE;
    while (ent < end) {
        if (ent->mid == id) {
            ent->mid = 0;
        }
        ent++;
    }
}

void
rb_clear_cache_by_class(klass)
    VALUE klass;
{
    struct cache_entry *ent, *end;

    if (!ruby_running) return;
    ent = cache; end = ent + CACHE_SIZE;
    while (ent < end) {
        if (ent->klass == klass || ent->origin == klass) {
            ent->mid = 0;
        }
        ent++;
    }
}

static ID init, eqq, each, aref, aset, match, missing;
static ID added, singleton_added;
static ID __id__, __send__, respond_to;

#define NOEX_TAINTED 8
#define NOEX_SAFE(n) ((n) >> 4)
#define NOEX_WITH(n, v) ((n) | (v) << 4)
#define NOEX_WITH_SAFE(n) NOEX_WITH(n, ruby_safe_level)

void
rb_add_method(klass, mid, node, noex)
    VALUE klass;
    ID mid;
    NODE *node;
    int noex;
{
    NODE *body;

    if (NIL_P(klass)) klass = rb_cObject;
    if (ruby_safe_level >= 4 && (klass == rb_cObject || !OBJ_TAINTED(klass))) {
        rb_raise(rb_eSecurityError, "Insecure: can't define method");
    }
    if (!FL_TEST(klass, FL_SINGLETON) &&
        node && nd_type(node) != NODE_ZSUPER &&
        (mid == rb_intern("initialize" )|| mid == rb_intern("initialize_copy"))) {
        noex = NOEX_PRIVATE | noex;
    }
    else if (FL_TEST(klass, FL_SINGLETON) && node && nd_type(node) == NODE_CFUNC &&
             mid == rb_intern("allocate")) {
        rb_warn("defining %s.allocate is deprecated; use rb_define_alloc_func()",
                rb_class2name(rb_iv_get(klass, "__attached__")));
        mid = ID_ALLOCATOR;
    }
    if (OBJ_FROZEN(klass)) rb_error_frozen("class/module");
    rb_clear_cache_by_id(mid);
    body = NEW_METHOD(node, NOEX_WITH_SAFE(noex));
    st_insert(RCLASS(klass)->m_tbl, mid, (st_data_t)body);
    if (node && mid != ID_ALLOCATOR && ruby_running) {
        if (FL_TEST(klass, FL_SINGLETON)) {
            rb_funcall(rb_iv_get(klass, "__attached__"), singleton_added, 1, ID2SYM(mid));
        }
        else {
            rb_funcall(klass, added, 1, ID2SYM(mid));
        }
    }
}

void
rb_define_alloc_func(klass, func)
    VALUE klass;
    VALUE (*func) _((VALUE));
{
    Check_Type(klass, T_CLASS);
    rb_add_method(rb_singleton_class(klass), ID_ALLOCATOR, NEW_CFUNC(func, 0),
                  NOEX_PRIVATE);
}

void
rb_undef_alloc_func(klass)
    VALUE klass;
{
    Check_Type(klass, T_CLASS);
    rb_add_method(rb_singleton_class(klass), ID_ALLOCATOR, 0, NOEX_UNDEF);
}

NODE*
search_method(klass, id, origin)
    VALUE klass, *origin;
    ID id;
{
    st_data_t body;

    if (!klass) return 0;
    while (!st_lookup(RCLASS(klass)->m_tbl, id, &body)) {
        klass = RCLASS(klass)->super;
        if (!klass) return 0;
    }

    if (origin) *origin = klass;
    return (NODE *)body;
}

static NODE*
rb_get_method_body(klassp, idp, noexp)
    VALUE *klassp;
    ID *idp;
    int *noexp;
{
    ID id = *idp;
    VALUE klass = *klassp;
    VALUE origin = 0;
    NODE * volatile body;
    struct cache_entry *ent;

    if ((body = search_method(klass, id, &origin)) == 0 || !body->nd_body) {
        /* store empty info in cache */
        ent = cache + EXPR1(klass, id);
        ent->klass  = klass;
        ent->origin = klass;
        ent->mid = ent->mid0 = id;
        ent->noex   = 0;
        ent->method = 0;

        return 0;
    }

    if (ruby_running) {
        /* store in cache */
        ent = cache + EXPR1(klass, id);
        ent->klass  = klass;
        ent->noex   = body->nd_noex;
        if (noexp) *noexp = body->nd_noex;
        body = body->nd_body;
        if (nd_type(body) == NODE_FBODY) {
            ent->mid = id;
            *klassp = body->nd_orig;
            ent->origin = body->nd_orig;
            *idp = ent->mid0 = body->nd_mid;
            body = ent->method = body->nd_head;
        }
        else {
            *klassp = origin;
            ent->origin = origin;
            ent->mid = ent->mid0 = id;
            ent->method = body;
        }
    }
    else {
        if (noexp) *noexp = body->nd_noex;
        body = body->nd_body;
        if (nd_type(body) == NODE_FBODY) {
            *klassp = body->nd_orig;
            *idp = body->nd_mid;
            body = body->nd_head;
        }
        else {
            *klassp = origin;
        }
    }

    return body;
}

NODE*
rb_method_node(klass, id)
    VALUE klass;
    ID id;
{
    int noex;

    return rb_get_method_body(&klass, &id, &noex);
}

static void
remove_method(klass, mid)
    VALUE klass;
    ID mid;
{
    st_data_t data;
    NODE *body = 0;

    if (klass == rb_cObject) {
        rb_secure(4);
    }
    if (ruby_safe_level >= 4 && !OBJ_TAINTED(klass)) {
        rb_raise(rb_eSecurityError, "Insecure: can't remove method");
    }
    if (OBJ_FROZEN(klass)) rb_error_frozen("class/module");
    if (mid == __id__ || mid == __send__ || mid == init) {
        rb_warn("removing `%s' may cause serious problem", rb_id2name(mid));
    }
    if (st_lookup(RCLASS(klass)->m_tbl, mid, &data)) {
        body = (NODE *)data;
        if (!body || !body->nd_body) body = 0;
        else {
            st_delete(RCLASS(klass)->m_tbl, &mid, &data);
        }
    }
    if (!body) {
        rb_name_error(mid, "method `%s' not defined in %s",
                      rb_id2name(mid), rb_class2name(klass));
    }
    rb_clear_cache_for_undef(klass, mid);
    if (FL_TEST(klass, FL_SINGLETON)) {
        rb_funcall(rb_iv_get(klass, "__attached__"), singleton_removed, 1, ID2SYM(mid));
    }
    else {
        rb_funcall(klass, removed, 1, ID2SYM(mid));
    }
}

void
rb_remove_method(klass, name)
    VALUE klass;
    const char *name;
{
    remove_method(klass, rb_intern(name));
}

/*
 *  call-seq:
 *     remove_method(symbol)   => self
 *
 *  Removes the method identified by _symbol_ from the current
 *  class. For an example, see Module.undef_method.
 */

static VALUE
rb_mod_remove_method(argc, argv, mod)
    int argc;
    VALUE *argv;
    VALUE mod;
{
    int i;

    for (i=0; ind_body) {
        print_undef(klass, name);
    }
    if (body->nd_noex != noex) {
        if (klass == origin) {
            body->nd_noex = noex;
        }
        else {
            rb_add_method(klass, name, NEW_ZSUPER(), noex);
        }
    }
}

int
rb_method_boundp(klass, id, ex)
    VALUE klass;
    ID id;
    int ex;
{
    struct cache_entry *ent;
    int noex;

    /* is it in the method cache? */
    ent = cache + EXPR1(klass, id);
    if (ent->mid == id && ent->klass == klass) {
        if (ex && (ent->noex & NOEX_PRIVATE))
            return Qfalse;
        if (!ent->method) return Qfalse;
        return Qtrue;
    }
    if (rb_get_method_body(&klass, &id, &noex)) {
        if (ex && (noex & NOEX_PRIVATE))
            return Qfalse;
        return Qtrue;
    }
    return Qfalse;
}

void
rb_attr(klass, id, read, write, ex)
    VALUE klass;
    ID id;
    int read, write, ex;
{
    const char *name;
    char *buf;
    ID attriv;
    int noex;
    size_t len;

    if (!ex) noex = NOEX_PUBLIC;
    else {
        if (SCOPE_TEST(SCOPE_PRIVATE)) {
            noex = NOEX_PRIVATE;
            rb_warning((scope_vmode == SCOPE_MODFUNC) ?
                       "attribute accessor as module_function" :
                       "private attribute?");
        }
        else if (SCOPE_TEST(SCOPE_PROTECTED)) {
            noex = NOEX_PROTECTED;
        }
        else {
            noex = NOEX_PUBLIC;
        }
    }

    if (!rb_is_local_id(id) && !rb_is_const_id(id)) {
        rb_name_error(id, "invalid attribute name `%s'", rb_id2name(id));
    }
    name = rb_id2name(id);
    if (!name) {
        rb_raise(rb_eArgError, "argument needs to be symbol or string");
    }
    GC_DEBUG_SET_SOURCE
    len = strlen(name)+2;
    buf = ALLOCA_N(char,len);
    snprintf(buf, len, "@%s", name);
    attriv = rb_intern(buf);
    if (read) {
        rb_add_method(klass, id, NEW_IVAR(attriv), noex);
    }
    if (write) {
        rb_add_method(klass, rb_id_attrset(id), NEW_ATTRSET(attriv), noex);
    }
}

VALUE ruby_errinfo = Qnil;
extern NODE *ruby_eval_tree_begin;
extern NODE *ruby_eval_tree;
extern int ruby_nerrs;

VALUE rb_eLocalJumpError;
VALUE rb_eSysStackError;

extern VALUE ruby_top_self;

struct FRAME *ruby_frame;
struct SCOPE *ruby_scope;
static struct FRAME *top_frame;
static struct SCOPE *top_scope;

static unsigned long frame_unique = 0;

#ifdef GC_DEBUG
#define CREATE_FRAME_SOURCE_POS(pframe) \
    gc_debug_get_frame_source_pos(pframe);
#define CREATE_FRAME_SOURCE_POS_FOR_PUSH(pframe) \
    _frame.self = 0; \
    _frame.last_func = 0; \
    _frame.orig_func = 0; \
    _frame.last_class = 0; \
    CREATE_FRAME_SOURCE_POS(pframe);
#else
#define CREATE_FRAME_SOURCE_POS(pframe)
#define CREATE_FRAME_SOURCE_POS_FOR_PUSH(pframe)
#endif

#define PUSH_FRAME() do { \
    volatile struct FRAME _frame; \
    _frame.prev = ruby_frame; \
    _frame.node = ruby_current_node; \
    _frame.iter = ruby_iter->iter; \
    _frame.tmp  = 0; \
    _frame.argc = 0; \
    _frame.flags = 0; \
    _frame.uniq = frame_unique++; \
    CREATE_FRAME_SOURCE_POS_FOR_PUSH((struct FRAME *)&_frame) \
    ruby_frame = &_frame;

#define POP_FRAME() \
    ruby_current_node = _frame.node; \
    ruby_frame = _frame.prev; \
} while (0)

struct BLOCK {
    NODE *var;
    NODE *body;
    VALUE self;
    struct FRAME frame;
    struct SCOPE *scope;
    VALUE klass;
    NODE *cref;
    int iter;
    int vmode;
    int flags;
    int uniq;
    struct RVarmap *dyna_vars;
    VALUE orig_thread;
    VALUE wrapper;
    VALUE block_obj;
    struct BLOCK *outer;
    struct BLOCK *prev;
};

#define BLOCK_D_SCOPE 1
#define BLOCK_LAMBDA  2

static struct BLOCK *ruby_block;
static unsigned long block_unique = 1;

#define PUSH_BLOCK(v,b) do {            \
    struct BLOCK _block;                \
    _block.var = (v);                   \
    _block.body = (b);                  \
    _block.self = self;                 \
    _block.frame = *ruby_frame;         \
    _block.klass = ruby_class;          \
    _block.cref = ruby_cref;            \
    _block.frame.node = ruby_current_node;\
    _block.scope = ruby_scope;          \
    _block.prev = ruby_block;           \
    CREATE_FRAME_SOURCE_POS(&_block.frame);     \
    _block.outer = ruby_block;          \
    _block.iter = ruby_iter->iter;      \
    _block.vmode = scope_vmode;         \
    _block.flags = BLOCK_D_SCOPE;       \
    _block.dyna_vars = ruby_dyna_vars;  \
    _block.wrapper = ruby_wrapper;      \
    _block.block_obj = 0;               \
    _block.uniq = (b)?block_unique++:0; \
    if (b) {                            \
        prot_tag->blkid = _block.uniq;  \
    }                                   \
    ruby_block = &_block

#define POP_BLOCK() \
   ruby_block = _block.prev; \
} while (0)

struct RVarmap *ruby_dyna_vars;
#define PUSH_VARS() do { \
    struct RVarmap * volatile _old; \
    _old = ruby_dyna_vars; \
    ruby_dyna_vars = 0

#define POP_VARS() \
    if (_old && (ruby_scope->flags & SCOPE_DONT_RECYCLE)) {\
        if (RBASIC(_old)->flags) /* unless it's already recycled */ \
            FL_SET(_old, DVAR_DONT_RECYCLE); \
    }\
    ruby_dyna_vars = _old; \
} while (0)

#define DVAR_DONT_RECYCLE FL_USER2

#define DMETHOD_P() (ruby_frame->flags & FRAME_DMETH)

static struct RVarmap*
new_dvar(id, value, prev)
    ID id;
    VALUE value;
    struct RVarmap *prev;
{
    NEWOBJ(vars, struct RVarmap);
    OBJSETUP(vars, 0, T_VARMAP);
    vars->id = id;
    vars->val = value;
    vars->next = prev;

    return vars;
}

VALUE
rb_dvar_defined(id)
    ID id;
{
    struct RVarmap *vars = ruby_dyna_vars;

    while (vars) {
        if (vars->id == id) return Qtrue;
        vars = vars->next;
    }
    return Qfalse;
}

VALUE
rb_dvar_curr(id)
    ID id;
{
    struct RVarmap *vars = ruby_dyna_vars;

    while (vars) {
        if (vars->id == 0) break;
        if (vars->id == id) return Qtrue;
        vars = vars->next;
    }
    return Qfalse;
}

VALUE
rb_dvar_ref(id)
    ID id;
{
    struct RVarmap *vars = ruby_dyna_vars;

    while (vars) {
        if (vars->id == id) {
            return vars->val;
        }
        vars = vars->next;
    }
    return Qnil;
}

void
rb_dvar_push(id, value)
    ID id;
    VALUE value;
{
    ruby_dyna_vars = new_dvar(id, value, ruby_dyna_vars);
}

static void
dvar_asgn_internal(id, value, curr)
    ID id;
    VALUE value;
    int curr;
{
    int n = 0;
    struct RVarmap *vars = ruby_dyna_vars;

    while (vars) {
        if (curr && vars->id == 0) {
            /* first null is a dvar header */
            n++;
            if (n == 2) break;
        }
        if (vars->id == id) {
            vars->val = value;
            return;
        }
        vars = vars->next;
    }
    if (!ruby_dyna_vars) {
        ruby_dyna_vars = new_dvar(id, value, 0);
    }
    else {
        vars = new_dvar(id, value, ruby_dyna_vars->next);
        ruby_dyna_vars->next = vars;
    }
}

static inline void
dvar_asgn(id, value)
    ID id;
    VALUE value;
{
    dvar_asgn_internal(id, value, 0);
}

static inline void
dvar_asgn_curr(id, value)
    ID id;
    VALUE value;
{
    dvar_asgn_internal(id, value, 1);
}

VALUE *
rb_svar(cnt)
    int cnt;
{
    struct RVarmap *vars = ruby_dyna_vars;
    ID id;

    if (!ruby_scope->local_tbl) return NULL;
    if ((ID)cnt >= ruby_scope->local_tbl[0]) return NULL;
    id = ruby_scope->local_tbl[cnt+1];
    while (vars) {
        if (vars->id == id) return &vars->val;
        vars = vars->next;
    }
    if (ruby_scope->local_vars == 0) return NULL;
    return &ruby_scope->local_vars[cnt];
}

struct iter {
    int iter;
    struct iter *prev;
};
static struct iter *ruby_iter;

#define ITER_NOT 0
#define ITER_PRE 1
#define ITER_CUR 2
#define ITER_PAS 3

#define PUSH_ITER(i) do {               \
    struct iter _iter;                  \
    _iter.prev = ruby_iter;             \
    _iter.iter = (i);                   \
    ruby_iter = &_iter

#define POP_ITER()                      \
    ruby_iter = _iter.prev;             \
} while (0)

struct tag {
    rb_jmpbuf_t buf;
    struct FRAME *frame;
    struct iter *iter;
    VALUE tag;
    VALUE retval;
    struct SCOPE *scope;
    VALUE dst;
    struct tag *prev;
    int blkid;
};
static struct tag *prot_tag;

#define PUSH_TAG(ptag) do {             \
    struct tag _tag;                    \
    _tag.retval = Qnil;                 \
    _tag.frame = ruby_frame;            \
    _tag.iter = ruby_iter;              \
    _tag.prev = prot_tag;               \
    _tag.scope = ruby_scope;            \
    _tag.tag = ptag;                    \
    _tag.dst = 0;                       \
    _tag.blkid = 0;                     \
    prot_tag = &_tag

#define PROT_EMPTY   Qfalse     /* 0 */
#define PROT_THREAD Qtrue       /* 2 */
#define PROT_FUNC   INT2FIX(0)  /* 1 */
#define PROT_LOOP   INT2FIX(1)  /* 3 */
#define PROT_LAMBDA INT2FIX(2)  /* 5 */
#define PROT_YIELD  INT2FIX(3)  /* 7 */

#if STACK_WIPE_SITES & 0x42
#ifdef __GNUC__
static inline int wipeAfter(int) __attribute__((always_inline));
#endif
static inline int wipeAfter(int status)
{
  rb_gc_wipe_stack();
  return status;
}
#else
#define wipeAfter(status) status
#endif
#if STACK_WIPE_SITES & 2
#define wipeAfterTag(status) wipeAfter(status)
#else
#define wipeAfterTag(status) status
#endif

#define EXEC_TAG_0()  ruby_setjmp(((void)0), prot_tag->buf)
#define EXEC_TAG()    wipeAfterTag(EXEC_TAG_0())

#define JUMP_TAG(st) do {               \
    ruby_frame = prot_tag->frame;       \
    ruby_iter = prot_tag->iter;         \
    ruby_longjmp(prot_tag->buf,(st));   \
} while (0)

#define POP_TAG()                       \
    prot_tag = _tag.prev;               \
} while (0)

#define TAG_DST() (_tag.dst == (VALUE)ruby_frame->uniq)

#define TAG_RETURN      0x1
#define TAG_BREAK       0x2
#define TAG_NEXT        0x3
#define TAG_RETRY       0x4
#define TAG_REDO        0x5
#define TAG_RAISE       0x6
#define TAG_THROW       0x7
#define TAG_FATAL       0x8
#define TAG_MASK        0xf

VALUE ruby_class;
static VALUE ruby_wrapper;      /* security wrapper */

#define PUSH_CLASS(c) do {              \
    volatile VALUE _class = ruby_class; \
    ruby_class = (c)

#define POP_CLASS() ruby_class = _class; \
} while (0)

NODE *ruby_cref = 0;
NODE *ruby_top_cref;
#define PUSH_CREF(c) ruby_cref = NEW_CREF(c,ruby_cref)
#define POP_CREF() ruby_cref = ruby_cref->nd_next

#define PUSH_SCOPE() do {               \
    volatile int _vmode = scope_vmode;  \
    struct SCOPE * volatile _old;       \
    NEWOBJ(_scope, struct SCOPE);       \
    OBJSETUP(_scope, 0, T_SCOPE);       \
    _scope->local_tbl = 0;              \
    _scope->local_vars = 0;             \
    _scope->flags = 0;                  \
    _old = ruby_scope;                  \
    ruby_scope = _scope;                \
    scope_vmode = SCOPE_PUBLIC

rb_thread_t rb_curr_thread;
rb_thread_t rb_main_thread;
#define main_thread rb_main_thread
#define curr_thread rb_curr_thread


#ifndef STACK_FREE_SAFE_DEBUG
#define STACK_FREE_SAFE_DEBUG 0
#endif

#if STACK_FREE_SAFE_DEBUG
#define stack_free_safe(TH,MSG) _stack_free_safe(TH,MSG)
#else
#define stack_free_safe(TH,MSG) _stack_free_safe(TH)
#endif


static void stack_free_safe_all_dead_threads();

static void scope_dup _((struct SCOPE *));

#define POP_SCOPE()                     \
    if (ruby_scope->flags & SCOPE_DONT_RECYCLE) {\
        if (_old) scope_dup(_old);      \
    }                                   \
    if (!(ruby_scope->flags & SCOPE_MALLOC)) {\
        ruby_scope->local_vars = 0;     \
        ruby_scope->local_tbl  = 0;     \
        if (!(ruby_scope->flags & SCOPE_DONT_RECYCLE) && \
            ruby_scope != top_scope) {  \
            rb_gc_force_recycle((VALUE)ruby_scope);\
        }                               \
    }                                   \
    ruby_scope->flags |= SCOPE_NOSTACK; \
    ruby_scope = _old;                  \
    scope_vmode = _vmode;               \
} while (0)

static VALUE rb_eval _((VALUE,NODE*));
static VALUE eval _((VALUE,VALUE,volatile VALUE,const char* volatile,int));
static NODE *compile _((VALUE, const char*, int));

static VALUE rb_yield_0
               _((volatile VALUE, volatile VALUE, VALUE, int, volatile int));

#if STACK_WIPE_SITES & 0x20
#define wipeBeforeYield()  rb_gc_wipe_stack()
#else
#define wipeBeforeYield()  (void)0
#endif

#define YIELD_LAMBDA_CALL 1
#define YIELD_PROC_CALL   2
#define YIELD_PUBLIC_DEF  4
#define YIELD_FUNC_AVALUE 1
#define YIELD_FUNC_SVALUE 2
#define YIELD_FUNC_LAMBDA 3

static VALUE rb_call _((VALUE,VALUE,ID,int,const VALUE*,int,VALUE));
static VALUE module_setup _((VALUE,NODE *volatile));

static VALUE massign _((VALUE,NODE*,VALUE,int));
static void assign _((VALUE,NODE*,VALUE,int));

typedef struct event_hook {
    rb_event_hook_func_t func;
    rb_event_t events;
    struct event_hook *next;
} rb_event_hook_t;

static rb_event_hook_t *event_hooks;

#define EXEC_EVENT_HOOK(event, node, self, id, klass) \
    do { \
        rb_event_hook_t *hook = event_hooks; \
        rb_event_hook_func_t hook_func; \
        rb_event_t events; \
        \
        while (hook) { \
            hook_func = hook->func; \
            events = hook->events; \
            hook = hook->next; \
            if (events & event) \
                (*hook_func)(event, node, self, id, klass); \
        } \
    } while (0)

static VALUE trace_func = 0;
static int tracing = 0;
static void call_trace_func _((rb_event_t,NODE*,VALUE,ID,VALUE));

static void
#ifdef HAVE_STDARG_PROTOTYPES
warn_printf(const char *fmt, ...)
#else
warn_printf(fmt, va_alist)
    const char *fmt;
    va_dcl
#endif
{
    char buf[BUFSIZ];
    va_list args;

    va_init_list(args, fmt);
    vsnprintf(buf, BUFSIZ, fmt, args);
    va_end(args);
    rb_write_error(buf);
}

#define warn_print(x) rb_write_error(x)
#define warn_print2(x,l) rb_write_error2(x,l)

static void
error_pos()
{
    ruby_set_current_source();
    if (ruby_sourcefile) {
        if (ruby_frame->last_func) {
            warn_printf("%s:%d:in `%s'", ruby_sourcefile, ruby_sourceline,
                        rb_id2name(ruby_frame->orig_func));
        }
        else if (ruby_sourceline == 0) {
            warn_printf("%s", ruby_sourcefile);
        }
        else {
            warn_printf("%s:%d", ruby_sourcefile, ruby_sourceline);
        }
    }
}

VALUE rb_check_backtrace(VALUE);

static VALUE
get_backtrace(info)
    VALUE info;
{
    if (NIL_P(info)) return Qnil;
    info = rb_funcall(info, rb_intern("backtrace"), 0);
    if (NIL_P(info)) return Qnil;
    return rb_check_backtrace(info);
}

static void
set_backtrace(info, bt)
    VALUE info, bt;
{
    rb_funcall(info, rb_intern("set_backtrace"), 1, bt);
}

static void
error_print()
{
    VALUE errat;
    volatile VALUE eclass, e;
    const char * einfo;
    long elen;

    if (NIL_P(ruby_errinfo)) return;

    PUSH_TAG(PROT_EMPTY);
    errat = EXEC_TAG() ? Qnil : get_backtrace(ruby_errinfo);
    if (EXEC_TAG()) goto error;
    if (NIL_P(errat)){
        ruby_set_current_source();
        if (ruby_sourcefile)
            warn_printf("%s:%d", ruby_sourcefile, ruby_sourceline);
        else
            warn_printf("%d", ruby_sourceline);
    }
    else if (RARRAY(errat)->len == 0) {
        error_pos();
    }
    else {
        VALUE mesg = RARRAY(errat)->ptr[0];

        if (NIL_P(mesg)) error_pos();
        else {
            warn_print2(RSTRING(mesg)->ptr, RSTRING(mesg)->len);
        }
    }

    eclass = CLASS_OF(ruby_errinfo);
    if (EXEC_TAG() == 0) {
        e = rb_funcall(ruby_errinfo, rb_intern("message"), 0, 0);
        StringValue(e);
        einfo = RSTRING(e)->ptr;
        elen = RSTRING(e)->len;
    }
    else {
        einfo = "";
        elen = 0;
    }
    if (EXEC_TAG()) goto error;
    if (eclass == rb_eRuntimeError && elen == 0) {
        warn_print(": unhandled exception\n");
    }
    else {
        VALUE epath;

        epath = rb_class_name(eclass);
        if (elen == 0) {
            warn_print(": ");
            warn_print2(RSTRING(epath)->ptr, RSTRING(epath)->len);
            warn_print("\n");
        }
        else {
            char *tail  = 0;
            long len = elen;

            if (RSTRING(epath)->ptr[0] == '#') epath = 0;
            if ((tail = memchr(einfo, '\n', elen)) != 0) {
                len = tail - einfo;
                tail++;         /* skip newline */
            }
            warn_print(": ");
            warn_print2(einfo, len);
            if (epath) {
                warn_print(" (");
                warn_print2(RSTRING(epath)->ptr, RSTRING(epath)->len);
                warn_print(")\n");
            }
            if (tail && elen>len+1) {
                warn_print2(tail, elen-len-1);
                if (einfo[elen-1] != '\n') warn_print2("\n", 1);
            }
        }
    }

    if (!NIL_P(errat)) {
        long i;
        struct RArray *ep = RARRAY(errat);
        int truncate = eclass == rb_eSysStackError;

#define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5)
#define TRACE_HEAD 8
#define TRACE_TAIL 5

        ep = RARRAY(errat);
        for (i=1; ilen; i++) {
            if (TYPE(ep->ptr[i]) == T_STRING) {
                warn_printf("\tfrom %s\n", RSTRING(ep->ptr[i])->ptr);
            }
            if (truncate && i == TRACE_HEAD && ep->len > TRACE_MAX) {
                warn_printf("\t ... %ld levels...\n",
                        ep->len - TRACE_HEAD - TRACE_TAIL);
                i = ep->len - TRACE_TAIL;
            }
        }
    }
  error:
    POP_TAG();
}

#if defined(__APPLE__)
#define environ (*_NSGetEnviron())
#elif !defined(_WIN32) && !defined(__MACOS__) || defined(_WIN32_WCE)
extern char **environ;
#endif
char **rb_origenviron;

void rb_call_inits _((void));
void Init_stack _((VALUE*));
void Init_heap _((void));
void Init_ext _((void));

#ifdef HAVE_NATIVETHREAD
static rb_nativethread_t ruby_thid;
int
is_ruby_native_thread() {
    return NATIVETHREAD_EQUAL(ruby_thid, NATIVETHREAD_CURRENT());
}

# ifdef HAVE_NATIVETHREAD_KILL
void
ruby_native_thread_kill(sig)
    int sig;
{
    NATIVETHREAD_KILL(ruby_thid, sig);
}
# endif
#endif

void Init_sym _((void));
void Init_source_filenames _((void));
void Init_source_positions _((void));

#ifdef GC_DEBUG
#define SET_GC_DEBUG_SOURCEFUNC(x) \
        ID old_ruby_sourcefunc = ruby_sourcefunc; \
    ruby_sourcefunc = rb_intern(x);
#define RESET_GC_DEBUG_SOURCEFUNC \
    ruby_sourcefunc = old_ruby_sourcefunc;
#else
#define SET_GC_DEBUG_SOURCEFUNC(x)
#define RESET_GC_DEBUG_SOURCEFUNC
#endif

void
ruby_init()
{
    static int initialized = 0;
    static struct FRAME frame;
    static struct iter iter;
    int state;

    if (initialized)
        return;
    initialized = 1;
#ifdef HAVE_NATIVETHREAD
    ruby_thid = NATIVETHREAD_CURRENT();
#endif

    ruby_frame = top_frame = &frame;
    ruby_iter = &iter;

#ifdef __MACOS__
    rb_origenviron = 0;
#else
    rb_origenviron = environ;
#endif

    Init_stack((void*)&state);
    Init_heap();
    Init_sym();
    Init_source_filenames();
    ruby_current_node = 0;
#ifdef GC_DEBUG
    if (GC_DEBUG_ON && gc_debug_dump) {
        Init_source_positions();
    }
    SET_GC_DEBUG_SOURCEFUNC("")
#endif
    PUSH_SCOPE();
    ruby_scope->local_vars = 0;
    ruby_scope->local_tbl  = 0;
    top_scope = ruby_scope;
    /* default visibility is private at toplevel */
    SCOPE_SET(SCOPE_PRIVATE);

    PUSH_TAG(PROT_EMPTY);
    if ((state = EXEC_TAG()) == 0) {
        rb_call_inits();
        ruby_class = rb_cObject;
        ruby_frame->self = ruby_top_self;
        ruby_top_cref = NEW_CREF(rb_cObject, 0);
        ruby_cref = ruby_top_cref;
        rb_define_global_const("TOPLEVEL_BINDING", rb_f_binding(ruby_top_self));
#ifdef __MACOS__
        _macruby_init();
#elif defined(__VMS)
        _vmsruby_init();
#endif
        ruby_prog_init();
        ALLOW_INTS;
    }
    POP_TAG();
    if (state) {
        error_print();
        exit(EXIT_FAILURE);
    }
    POP_SCOPE();
    ruby_scope = top_scope;
    top_scope->flags &= ~SCOPE_NOSTACK;
    RESET_GC_DEBUG_SOURCEFUNC
    ruby_running = 1;
}

static VALUE
eval_tree(self, node)
    VALUE self;
    NODE *node;
{
    NODE *beg_tree = ruby_eval_tree_begin;

    ruby_eval_tree_begin = 0;
    if (beg_tree) {
        rb_eval(self, beg_tree);
    }

    if (!node) return Qnil;
    return rb_eval(self, node);
}

int ruby_in_eval;

static void rb_thread_cleanup _((void));
static void rb_thread_wait_other_threads _((void));

static int thread_no_ensure _((void));

static VALUE exception_error;
static VALUE sysstack_error;

static int
sysexit_status(err)
    VALUE err;
{
    VALUE st = rb_iv_get(err, "status");
    return NUM2INT(st);
}

static int
error_handle(ex)
    int ex;
{
    int status = EXIT_FAILURE;
    rb_thread_t th = curr_thread;

    if (rb_thread_set_raised(th))
        return EXIT_FAILURE;
    switch (ex & TAG_MASK) {
      case 0:
        status = EXIT_SUCCESS;
        break;

      case TAG_RETURN:
        error_pos();
        warn_print(": unexpected return\n");
        break;
      case TAG_NEXT:
        error_pos();
        warn_print(": unexpected next\n");
        break;
      case TAG_BREAK:
        error_pos();
        warn_print(": unexpected break\n");
        break;
      case TAG_REDO:
        error_pos();
        warn_print(": unexpected redo\n");
        break;
      case TAG_RETRY:
        error_pos();
        warn_print(": retry outside of rescue clause\n");
        break;
      case TAG_THROW:
        if (prot_tag && prot_tag->frame && prot_tag->frame->node) {
            NODE *tag = prot_tag->frame->node;
            warn_printf("%s:%d: uncaught throw\n",
                    tag->nd_file, nd_line(tag));
        }
        else {
            error_pos();
            warn_printf(": unexpected throw\n");
        }
        break;
      case TAG_RAISE:
      case TAG_FATAL:
        if (rb_obj_is_kind_of(ruby_errinfo, rb_eSystemExit)) {
            status = sysexit_status(ruby_errinfo);
        }
        else if (rb_obj_is_instance_of(ruby_errinfo, rb_eSignal)) {
            /* no message when exiting by signal */
        }
        else {
            error_print();
        }
        break;
      default:
        rb_bug("Unknown longjmp status %d", ex);
        break;
    }
    rb_thread_reset_raised(th);
    return status;
}

void
ruby_options(argc, argv)
    int argc;
    char **argv;
{
    int state;
    ruby_current_node = 0;
    SET_GC_DEBUG_SOURCEFUNC("")
    Init_stack((void*)&state);
    PUSH_TAG(PROT_EMPTY);
    if ((state = EXEC_TAG()) == 0) {
        ruby_process_options(argc, argv);
    }
    else {
        trace_func = 0;
        tracing = 0;
        exit(error_handle(state));
    }
    POP_TAG();
    RESET_GC_DEBUG_SOURCEFUNC
}

void rb_exec_end_proc _((void));

static void
ruby_finalize_0()
{
    PUSH_TAG(PROT_EMPTY);
    if (EXEC_TAG() == 0) {
        rb_trap_exit();
    }
    POP_TAG();
    rb_exec_end_proc();
}

static void
ruby_finalize_1()
{
    signal(SIGINT, SIG_DFL);
    ruby_errinfo = 0;
    rb_gc_call_finalizer_at_exit();
    trace_func = 0;
    tracing = 0;
}

void
ruby_finalize()
{
    ruby_finalize_0();
    ruby_finalize_1();
}

int
ruby_cleanup(exArg)
    int exArg;
{
    int state;
    volatile VALUE errs[2];
    unsigned nerr;
    volatile int ex = exArg;

    errs[1] = ruby_errinfo;
    ruby_safe_level = 0;
    Init_stack((void *)&state);
    SET_GC_DEBUG_SOURCEFUNC("")
    ruby_finalize_0();
    errs[0] = ruby_errinfo;
    PUSH_TAG(PROT_EMPTY);
    PUSH_ITER(ITER_NOT);
    if ((state = EXEC_TAG()) == 0) {
        rb_thread_cleanup();
        rb_thread_wait_other_threads();
    }
    else if (ex == 0) {
        ex = state;
    }
    POP_ITER();
    ruby_errinfo = errs[1];
    ex = error_handle(ex);
    ruby_finalize_1();
    POP_TAG();
    RESET_GC_DEBUG_SOURCEFUNC

    for (nerr = 0; nerr < sizeof(errs) / sizeof(errs[0]); ++nerr) {
        VALUE err = errs[nerr];

        if (!RTEST(err)) continue;

        if (rb_obj_is_kind_of(err, rb_eSystemExit)) {
            return sysexit_status(err);
        }
        else if (rb_obj_is_kind_of(err, rb_eSignal)) {
            VALUE sig = rb_iv_get(err, "signo");
            ruby_default_signal(NUM2INT(sig));
        }
        else if (ex == 0) {
            ex = 1;
        }
    }

#if EXIT_SUCCESS != 0 || EXIT_FAILURE != 1
    switch (ex) {
#if EXIT_SUCCESS != 0
      case 0: return EXIT_SUCCESS;
#endif
#if EXIT_FAILURE != 1
      case 1: return EXIT_FAILURE;
#endif
    }
#endif

    return ex;
}

static int
ruby_exec_internal()
{
    int state;

    SET_GC_DEBUG_SOURCEFUNC("");
    PUSH_TAG(PROT_EMPTY);
    PUSH_ITER(ITER_NOT);
    /* default visibility is private at toplevel */
    SCOPE_SET(SCOPE_PRIVATE);
    if ((state = EXEC_TAG()) == 0) {
        eval_tree(ruby_top_self, ruby_eval_tree);
    }
    POP_ITER();
    POP_TAG();
    RESET_GC_DEBUG_SOURCEFUNC
    return state;
}

void
ruby_stop(ex)
    int ex;
{
    exit(ruby_cleanup(ex));
}

int
ruby_exec()
{
    volatile NODE *tmp;

    Init_stack((void*)&tmp);
    return ruby_exec_internal();
}

void
ruby_run()
{
    int state;
    static int ex;

    if (ruby_nerrs > 0) exit(EXIT_FAILURE);
    state = ruby_exec();
    if (state && !ex) ex = state;
    ruby_stop(ex);
}

static void
compile_error(at)
    const char *at;
{
    VALUE str;

    ruby_nerrs = 0;
    str = rb_str_buf_new2("compile error");
    if (at) {
        rb_str_buf_cat2(str, " in ");
        rb_str_buf_cat2(str, at);
    }
    rb_str_buf_cat(str, "\n", 1);
    if (!NIL_P(ruby_errinfo)) {
        rb_str_append(str, rb_obj_as_string(ruby_errinfo));
    }
    rb_exc_raise(rb_exc_new3(rb_eSyntaxError, str));
}

VALUE
rb_eval_string(str)
    const char *str;
{
    VALUE v;
    NODE *oldsrc = ruby_current_node;

    ruby_current_node = 0;
    ruby_sourcefile = rb_source_filename("(eval)");
    SET_GC_DEBUG_SOURCEFUNC("")
    v = eval(ruby_top_self, rb_str_new2(str), Qnil, 0, 0);
    ruby_current_node = oldsrc;
    RESET_GC_DEBUG_SOURCEFUNC
    return v;
}

VALUE
rb_eval_string_protect(str, state)
    const char *str;
    int *state;
{
    return rb_protect((VALUE (*)_((VALUE)))rb_eval_string, (VALUE)str, state);
}

VALUE
rb_eval_string_wrap(str, state)
    const char *str;
    int *state;
{
    int status;
    VALUE self = ruby_top_self;
    VALUE wrapper = ruby_wrapper;
    VALUE val;

    PUSH_CLASS(ruby_wrapper = rb_module_new());
    ruby_top_self = rb_obj_clone(ruby_top_self);
    rb_extend_object(ruby_top_self, ruby_wrapper);
    PUSH_FRAME();
    ruby_frame->last_func = 0;
    ruby_frame->last_class = 0;
    ruby_frame->self = self;
    PUSH_CREF(ruby_wrapper);
    PUSH_SCOPE();

    val = rb_eval_string_protect(str, &status);
    ruby_top_self = self;

    POP_SCOPE();
    POP_FRAME();
    POP_CLASS();
    ruby_wrapper = wrapper;
    if (state) {
        *state = status;
    }
    else if (status) {
        JUMP_TAG(status);
    }
    return val;
}

NORETURN(static void localjump_error(const char*, VALUE, int));
static void
localjump_error(mesg, value, reason)
    const char *mesg;
    VALUE value;
    int reason;
{
    VALUE exc = rb_exc_new2(rb_eLocalJumpError, mesg);
    ID id;

    rb_iv_set(exc, "@exit_value", value);
    switch (reason) {
      case TAG_BREAK:
        id = rb_intern("break"); break;
      case TAG_REDO:
        id = rb_intern("redo"); break;
      case TAG_RETRY:
        id = rb_intern("retry"); break;
      case TAG_NEXT:
        id = rb_intern("next"); break;
      case TAG_RETURN:
        id = rb_intern("return"); break;
      default:
        id = rb_intern("noreason"); break;
    }
    rb_iv_set(exc, "@reason", ID2SYM(id));
    rb_exc_raise(exc);
}

/*
 * call_seq:
 *   local_jump_error.exit_value  => obj
 *
 * Returns the exit value associated with this +LocalJumpError+.
 */
static VALUE
localjump_xvalue(exc)
    VALUE exc;
{
    return rb_iv_get(exc, "@exit_value");
}

/*
 * call-seq:
 *    local_jump_error.reason   => symbol
 *
 * The reason this block was terminated:
 * :break, :redo, :retry, :next, :return, or :noreason.
 */

static VALUE
localjump_reason(exc)
    VALUE exc;
{
    return rb_iv_get(exc, "@reason");
}

NORETURN(static void jump_tag_but_local_jump _((int,VALUE)));
static void
jump_tag_but_local_jump(state, val)
    int state;
    VALUE val;
{

    if (val == Qundef) val = prot_tag->retval;
    switch (state) {
      case 0:
        break;
      case TAG_RETURN:
        localjump_error("unexpected return", val, state);
        break;
      case TAG_BREAK:
        localjump_error("unexpected break", val, state);
        break;
      case TAG_NEXT:
        localjump_error("unexpected next", val, state);
        break;
      case TAG_REDO:
        localjump_error("unexpected redo", Qnil, state);
        break;
      case TAG_RETRY:
        localjump_error("retry outside of rescue clause", Qnil, state);
        break;
      default:
        break;
    }
    JUMP_TAG(state);
}

VALUE
rb_eval_cmd(cmd, arg, level)
    VALUE cmd, arg;
    int level;
{
    int state;
    VALUE val;
    struct SCOPE * volatile saved_scope;
    volatile int safe = ruby_safe_level;

    if (OBJ_TAINTED(cmd)) {
        level = 4;
    }
    if (TYPE(cmd) != T_STRING) {
        PUSH_ITER(ITER_NOT);
        PUSH_TAG(PROT_EMPTY);
        ruby_safe_level = level;
        if ((state = EXEC_TAG()) == 0) {
            val = rb_funcall2(cmd, rb_intern("call"), RARRAY(arg)->len, RARRAY(arg)->ptr);
        }
        ruby_safe_level = safe;
        POP_TAG();
        POP_ITER();
        if (state) JUMP_TAG(state);
        return val;
    }

    saved_scope = ruby_scope;
    ruby_scope = top_scope;
    PUSH_FRAME();
    ruby_frame->last_func = 0;
    ruby_frame->last_class = 0;
    ruby_frame->self = ruby_top_self;
    PUSH_CREF(ruby_wrapper ? ruby_wrapper : rb_cObject);

    ruby_safe_level = level;

    PUSH_TAG(PROT_EMPTY);
    val = (state = EXEC_TAG()) ? Qnil : eval(ruby_top_self, cmd, Qnil, 0, 0);
    if (ruby_scope->flags & SCOPE_DONT_RECYCLE)
        scope_dup(saved_scope);
    ruby_scope = saved_scope;
    ruby_safe_level = safe;
    POP_TAG();
    POP_FRAME();

    if (state) jump_tag_but_local_jump(state, val);
    return val;
}

#define ruby_cbase (ruby_cref->nd_clss)

static VALUE
ev_const_defined(cref, id, self)
    NODE *cref;
    ID id;
    VALUE self;
{
    NODE *cbase = cref;
    VALUE result;

    while (cbase && cbase->nd_next) {
        struct RClass *klass = RCLASS(cbase->nd_clss);

        if (!NIL_P(klass)) {
            if (klass->iv_tbl && st_lookup(klass->iv_tbl, id, &result)) {
                if (result == Qundef && NIL_P(rb_autoload_p((VALUE)klass, id))) {
                    return Qfalse;
                }
                return Qtrue;
            }
        }
        cbase = cbase->nd_next;
    }
    return rb_const_defined(cref->nd_clss, id);
}

NOINLINE(static VALUE ev_const_get _((NODE *cref, ID id, VALUE self)));
NOINLINE(static void eval_cvar_set _((NODE *node, VALUE result, int warn)));
NOINLINE(static void eval_cdecl _((VALUE self, NODE *node, VALUE value)));

static VALUE
ev_const_get(cref, id, self)
    NODE *cref;
    ID id;
    VALUE self;
{
    NODE *cbase = cref;
    VALUE result;

    while (cbase && cbase->nd_next) {
        VALUE klass = cbase->nd_clss;

        if (!NIL_P(klass)) {
            while (RCLASS(klass)->iv_tbl &&
                   st_lookup(RCLASS(klass)->iv_tbl, id, &result)) {
                if (result == Qundef) {
                    if (!RTEST(rb_autoload_load(klass, id))) break;
                    continue;
                }
                return result;
            }
        }
        cbase = cbase->nd_next;
    }
    return rb_const_get(NIL_P(cref->nd_clss) ? CLASS_OF(self): cref->nd_clss, id);
}

static VALUE
cvar_cbase()
{
    NODE *cref = ruby_cref;

    while (cref && cref->nd_next && (NIL_P(cref->nd_clss) || FL_TEST(cref->nd_clss, FL_SINGLETON))) {
        cref = cref->nd_next;
        if (!cref->nd_next) {
            rb_warn("class variable access from toplevel singleton method");
        }
    }
    if (NIL_P(cref->nd_clss)) {
        rb_raise(rb_eTypeError, "no class variables available");
    }
    return cref->nd_clss;
}

/*
 *  call-seq:
 *     Module.nesting    => array
 *
 *  Returns the list of +Modules+ nested at the point of call.
 *
 *     module M1
 *       module M2
 *         $a = Module.nesting
 *       end
 *     end
 *     $a           #=> [M1::M2, M1]
 *     $a[0].name   #=> "M1::M2"
 */

static VALUE
rb_mod_nesting()
{
    NODE *cbase = ruby_cref;
    VALUE ary = rb_ary_new();

    while (cbase && cbase->nd_next) {
        if (!NIL_P(cbase->nd_clss)) rb_ary_push(ary, cbase->nd_clss);
        cbase = cbase->nd_next;
    }
    if (ruby_wrapper && RARRAY(ary)->len == 0) {
        rb_ary_push(ary, ruby_wrapper);
    }
    return ary;
}

/*
 *  call-seq:
 *     Module.constants   => array
 *
 *  Returns an array of the names of all constants defined in the
 *  system. This list includes the names of all modules and classes.
 *
 *     p Module.constants.sort[1..5]
 *
 *  produces:
 *
 *     ["ARGV", "ArgumentError", "Array", "Bignum", "Binding"]
 */

static VALUE
rb_mod_s_constants()
{
    NODE *cbase = ruby_cref;
    void *data = 0;

    while (cbase) {
        if (!NIL_P(cbase->nd_clss)) {
            data = rb_mod_const_at(cbase->nd_clss, data);
        }
        cbase = cbase->nd_next;
    }

    if (!NIL_P(ruby_cbase)) {
        data = rb_mod_const_of(ruby_cbase, data);
    }
    return rb_const_list(data);
}

void
rb_frozen_class_p(klass)
    VALUE klass;
{
    const char *desc = "something(?!)";

    if (OBJ_FROZEN(klass)) {
        if (FL_TEST(klass, FL_SINGLETON))
            desc = "object";
        else {
            switch (TYPE(klass)) {
              case T_MODULE:
              case T_ICLASS:
                desc = "module"; break;
              case T_CLASS:
                desc = "class"; break;
            }
        }
        rb_error_frozen(desc);
    }
}

void
rb_undef(klass, id)
    VALUE klass;
    ID id;
{
    VALUE origin;
    NODE *body;

    if (ruby_cbase == rb_cObject && klass == rb_cObject) {
        rb_secure(4);
    }
    if (ruby_safe_level >= 4 && !OBJ_TAINTED(klass)) {
        rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'", rb_id2name(id));
    }
    rb_frozen_class_p(klass);
    if (id == __id__ || id == __send__ || id == init) {
        rb_warn("undefining `%s' may cause serious problem", rb_id2name(id));
    }
    body = search_method(klass, id, &origin);
    if (!body || !body->nd_body) {
        const char *s0 = " class";
        VALUE c = klass;

        if (FL_TEST(c, FL_SINGLETON)) {
            VALUE obj = rb_iv_get(klass, "__attached__");

            switch (TYPE(obj)) {
              case T_MODULE:
              case T_CLASS:
                c = obj;
                s0 = "";
            }
        }
        else if (TYPE(c) == T_MODULE) {
            s0 = " module";
        }
        rb_name_error(id, "undefined method `%s' for%s `%s'",
                      rb_id2name(id),s0,rb_class2name(c));
    }
    rb_add_method(klass, id, 0, NOEX_PUBLIC);
    if (FL_TEST(klass, FL_SINGLETON)) {
        rb_funcall(rb_iv_get(klass, "__attached__"),
                   singleton_undefined, 1, ID2SYM(id));
    }
    else {
        rb_funcall(klass, undefined, 1, ID2SYM(id));
    }
}

/*
 *  call-seq:
 *     undef_method(symbol)    => self
 *
 *  Prevents the current class from responding to calls to the named
 *  method. Contrast this with remove_method, which deletes
 *  the method from the particular class; Ruby will still search
 *  superclasses and mixed-in modules for a possible receiver.
 *
 *     class Parent
 *       def hello
 *         puts "In parent"
 *       end
 *     end
 *     class Child < Parent
 *       def hello
 *         puts "In child"
 *       end
 *     end
 *
 *
 *     c = Child.new
 *     c.hello
 *
 *
 *     class Child
 *       remove_method :hello  # remove from child, still in parent
 *     end
 *     c.hello
 *
 *
 *     class Child
 *       undef_method :hello   # prevent any calls to 'hello'
 *     end
 *     c.hello
 *
 *  produces:
 *
 *     In child
 *     In parent
 *     prog.rb:23: undefined method `hello' for # (NoMethodError)
 */

static VALUE
rb_mod_undef_method(argc, argv, mod)
    int argc;
    VALUE *argv;
    VALUE mod;
{
    int i;

    for (i=0; ind_body) {
        if (TYPE(klass) == T_MODULE) {
            orig = search_method(rb_cObject, def, &origin);
        }
    }
    if (!orig || !orig->nd_body) {
        print_undef(klass, def);
    }
    if (FL_TEST(klass, FL_SINGLETON)) {
        singleton = rb_iv_get(klass, "__attached__");
    }
    body = orig->nd_body;
    orig->nd_cnt++;
    if (nd_type(body) == NODE_FBODY) { /* was alias */
        def = body->nd_mid;
        origin = body->nd_orig;
        body = body->nd_head;
    }

    rb_clear_cache_by_id(name);
    if (RTEST(ruby_verbose) && st_lookup(RCLASS(klass)->m_tbl, name, &data)) {
        node = (NODE *)data;
        if (node->nd_cnt == 0 && node->nd_body) {
            rb_warning("discarding old %s", rb_id2name(name));
        }
    }
    st_insert(RCLASS(klass)->m_tbl, name,
              (st_data_t)NEW_METHOD(NEW_FBODY(body, def, origin),
                                    NOEX_WITH_SAFE(orig->nd_noex)));

    if (!ruby_running) return;

    if (singleton) {
        rb_funcall(singleton, singleton_added, 1, ID2SYM(name));
    }
    else {
        rb_funcall(klass, added, 1, ID2SYM(name));
    }
}

/*
 *  call-seq:
 *     alias_method(new_name, old_name)   => self
 *
 *  Makes new_name a new copy of the method old_name. This can
 *  be used to retain access to methods that are overridden.
 *
 *     module Mod
 *       alias_method :orig_exit, :exit
 *       def exit(code=0)
 *         puts "Exiting with code #{code}"
 *         orig_exit(code)
 *       end
 *     end
 *     include Mod
 *     exit(99)
 *
 *  produces:
 *
 *     Exiting with code 99
 */

static VALUE
rb_mod_alias_method(mod, newname, oldname)
    VALUE mod, newname, oldname;
{
    rb_alias(mod, rb_to_id(newname), rb_to_id(oldname));
    return mod;
}

NODE *
rb_copy_node_scope(node, rval)
    NODE *node;
    NODE *rval;
{
    NODE *copy;

    GC_DEBUG_SET_SOURCE
    copy=NEW_NODE(NODE_SCOPE,0,rval,node->nd_next);

    if (node->nd_tbl) {
        copy->nd_tbl = ALLOC_N(ID, node->nd_tbl[0]+1);
        MEMCPY(copy->nd_tbl, node->nd_tbl, ID, node->nd_tbl[0]+1);
    }
    else {
        copy->nd_tbl = 0;
    }
    return copy;
}

#ifdef C_ALLOCA
# define TMP_PROTECT NODE * volatile tmp__protect_tmp=0
# define TMP_ALLOC(n)                                                   \
    (tmp__protect_tmp = NEW_NODE(NODE_ALLOCA,                           \
                                 ALLOC_N(VALUE,n),tmp__protect_tmp,n),  \
     (void*)tmp__protect_tmp->nd_head)
#else
# define TMP_PROTECT typedef int foobazzz
# define TMP_ALLOC(n) ALLOCA_N(VALUE,n)
#endif

#define SETUP_ARGS0(anode,extra) do {\
    NODE *n = anode;\
    if (!n) {\
        argc = 0;\
        argv = 0;\
    }\
    else if (nd_type(n) == NODE_ARRAY) {\
        argc=anode->nd_alen;\
        if (argc > 0) {\
            int i;\
            n = anode;\
            argv = TMP_ALLOC(argc+extra);\
            for (i=0;ind_head);\
                n=n->nd_next;\
            }\
        }\
        else {\
            argc = 0;\
            argv = 0;\
        }\
    }\
    else {\
        VALUE args = rb_eval(self,n);\
        if (TYPE(args) != T_ARRAY)\
            args = rb_ary_to_ary(args);\
        argc = RARRAY(args)->len;\
        argv = TMP_ALLOC(argc+extra);\
        MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc);\
    }\
} while (0)

#define SETUP_ARGS(anode) SETUP_ARGS0(anode,0)

#define BEGIN_CALLARGS do {\
    struct BLOCK *tmp_block = ruby_block;\
    int tmp_iter = ruby_iter->iter;\
    switch (tmp_iter) {\
      case ITER_PRE:\
        if (ruby_block) ruby_block = ruby_block->outer;\
      case ITER_PAS:\
        tmp_iter = ITER_NOT;\
    }\
    PUSH_ITER(tmp_iter)

#define END_CALLARGS \
    ruby_block = tmp_block;\
    POP_ITER();\
} while (0)

#define MATCH_DATA *rb_svar(node->nd_cnt)

static const char* is_defined _((VALUE, NODE*, char*));

static const char*
arg_defined(self, node, buf, type)
    VALUE self;
    NODE *node;
    char *buf;
    char *type;
{
    int argc;
    int i;

    if (!node) return type;     /* no args */
    if (nd_type(node) == NODE_ARRAY) {
        argc=node->nd_alen;
        if (argc > 0) {
            for (i=0;ind_head, buf))
                    return 0;
                node = node->nd_next;
            }
        }
    }
    else if (!is_defined(self, node, buf)) {
        return 0;
    }
    return type;
}

static const char*
is_defined(self, node, buf)
    VALUE self;
    NODE *node;
    char *buf;
{
    VALUE val;
    int state;

  again:
    if (!node) return "expression";
    switch (nd_type(node)) {
      case NODE_SUPER:
      case NODE_ZSUPER:
        if (ruby_frame->last_func == 0) return 0;
        else if (ruby_frame->last_class == 0) return 0;
        val = ruby_frame->last_class;
        if (rb_method_boundp(RCLASS(val)->super, ruby_frame->orig_func, 0)) {
            if (nd_type(node) == NODE_SUPER) {
                return arg_defined(self, node->nd_args, buf, "super");
            }
            return "super";
        }
        break;

      case NODE_VCALL:
      case NODE_FCALL:
        val = self;
        goto check_bound;

      case NODE_ATTRASGN:
        val = self;
        if (node->nd_recv == (NODE *)1) goto check_bound;
      case NODE_CALL:
        PUSH_TAG(PROT_EMPTY);
        if ((state = EXEC_TAG()) == 0) {
            val = rb_eval(self, node->nd_recv);
        }
        POP_TAG();
        if (state) {
            ruby_errinfo = Qnil;
            return 0;
        }
      check_bound:
        {
            int call = nd_type(node)==NODE_CALL;

            val = CLASS_OF(val);
            if (call) {
                int noex;
                ID id = node->nd_mid;

                if (!rb_get_method_body(&val, &id, &noex))
                    break;
                if ((noex & NOEX_PRIVATE))
                    break;
                if ((noex & NOEX_PROTECTED) &&
                    !rb_obj_is_kind_of(self, rb_class_real(val)))
                    break;
            }
            else if (!rb_method_boundp(val, node->nd_mid, call))
                break;
            return arg_defined(self, node->nd_args, buf,
                               nd_type(node) == NODE_ATTRASGN ?
                               "assignment" : "method");
        }
        break;

      case NODE_MATCH2:
      case NODE_MATCH3:
        return "method";

      case NODE_YIELD:
        if (rb_block_given_p()) {
            return "yield";
        }
        break;

      case NODE_SELF:
        return "self";

      case NODE_NIL:
        return "nil";

      case NODE_TRUE:
        return "true";

      case NODE_FALSE:
        return "false";

      case NODE_ATTRSET:
      case NODE_OP_ASGN1:
      case NODE_OP_ASGN2:
      case NODE_OP_ASGN_OR:
      case NODE_OP_ASGN_AND:
      case NODE_MASGN:
      case NODE_LASGN:
      case NODE_DASGN:
      case NODE_DASGN_CURR:
      case NODE_GASGN:
      case NODE_IASGN:
      case NODE_CDECL:
      case NODE_CVDECL:
      case NODE_CVASGN:
        return "assignment";

      case NODE_LVAR:
        return "local-variable";
      case NODE_DVAR:
        return "local-variable(in-block)";

      case NODE_GVAR:
        if (rb_gvar_defined(node->nd_entry)) {
            return "global-variable";
        }
        break;

      case NODE_IVAR:
        if (rb_ivar_defined(self, node->nd_vid)) {
            return "instance-variable";
        }
        break;

      case NODE_CONST:
        if (ev_const_defined(ruby_cref, node->nd_vid, self)) {
            return "constant";
        }
        break;

      case NODE_CVAR:
        if (rb_cvar_defined(cvar_cbase(), node->nd_vid)) {
            return "class variable";
        }
        break;

      case NODE_COLON2:
        PUSH_TAG(PROT_EMPTY);
        if ((state = EXEC_TAG()) == 0) {
            val = rb_eval(self, node->nd_head);
        }
        POP_TAG();
        if (state) {
            ruby_errinfo = Qnil;
            return 0;
        }
        else {
            switch (TYPE(val)) {
              case T_CLASS:
              case T_MODULE:
                if (rb_const_defined_from(val, node->nd_mid))
                    return "constant";
                break;
              default:
                if (rb_method_boundp(CLASS_OF(val), node->nd_mid, 1)) {
                    return "method";
                }
            }
        }
        break;

      case NODE_COLON3:
        if (rb_const_defined_from(rb_cObject, node->nd_mid)) {
            return "constant";
        }
        break;

      case NODE_NTH_REF:
        if (RTEST(rb_reg_nth_defined(node->nd_nth, MATCH_DATA))) {
            sprintf(buf, "$%d", (int)node->nd_nth);
            return buf;
        }
        break;

      case NODE_BACK_REF:
        if (RTEST(rb_reg_nth_defined(0, MATCH_DATA))) {
            sprintf(buf, "$%c", (char)node->nd_nth);
            return buf;
        }
        break;

      case NODE_NEWLINE:
        node = node->nd_next;
        goto again;

      default:
        PUSH_TAG(PROT_EMPTY);
        if ((state = EXEC_TAG()) == 0) {
            rb_eval(self, node);
        }
        POP_TAG();
        if (!state) {
            return "expression";
        }
        ruby_errinfo = Qnil;
        break;
    }
    return 0;
}

static int handle_rescue _((VALUE,NODE*));

static void blk_free();

static VALUE
rb_obj_is_proc(proc)
    VALUE proc;
{
    if (TYPE(proc) == T_DATA && RDATA(proc)->dfree == (RUBY_DATA_FUNC)blk_free) {
        return Qtrue;
    }
    return Qfalse;
}

void
rb_add_event_hook(func, events)
    rb_event_hook_func_t func;
    rb_event_t events;
{
    rb_event_hook_t *hook;

    hook = ALLOC(rb_event_hook_t);
    hook->func = func;
    hook->events = events;
    hook->next = event_hooks;
    event_hooks = hook;
}

int
rb_remove_event_hook(func)
    rb_event_hook_func_t func;
{
    rb_event_hook_t *prev, *hook;

    prev = NULL;
    hook = event_hooks;
    while (hook) {
        if (hook->func == func) {
            if (prev) {
                prev->next = hook->next;
            }
            else {
                event_hooks = hook->next;
            }
            xfree(hook);
            return 0;
        }
        prev = hook;
        hook = hook->next;
    }
    return -1;
}

/*
 *  call-seq:
 *     set_trace_func(proc)    => proc
 *     set_trace_func(nil)     => nil
 *
 *  Establishes _proc_ as the handler for tracing, or disables
 *  tracing if the parameter is +nil+. _proc_ takes up
 *  to six parameters: an event name, a filename, a line number, an
 *  object id, a binding, and the name of a class. _proc_ is
 *  invoked whenever an event occurs. Events are: c-call
 *  (call a C-language routine), c-return (return from a
 *  C-language routine), call (call a Ruby method),
 *  class (start a class or module definition),
 *  end (finish a class or module definition),
 *  line (execute code on a new line), raise
 *  (raise an exception), and return (return from a Ruby
 *  method). Tracing is disabled within the context of _proc_.
 *
 *      class Test
 *      def test
 *        a = 1
 *        b = 2
 *      end
 *      end
 *
 *      set_trace_func proc { |event, file, line, id, binding, classname|
 *         printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
 *      }
 *      t = Test.new
 *      t.test
 *
 *        line prog.rb:11               false
 *      c-call prog.rb:11        new    Class
 *      c-call prog.rb:11 initialize   Object
 *    c-return prog.rb:11 initialize   Object
 *    c-return prog.rb:11        new    Class
 *        line prog.rb:12               false
 *        call prog.rb:2        test     Test
 *        line prog.rb:3        test     Test
 *        line prog.rb:4        test     Test
 *      return prog.rb:4        test     Test
 */


static VALUE
set_trace_func(obj, trace)
    VALUE obj, trace;
{
    rb_event_hook_t *hook;

    rb_secure(4);
    if (NIL_P(trace)) {
        trace_func = 0;
        rb_remove_event_hook(call_trace_func);
        return Qnil;
    }
    if (!rb_obj_is_proc(trace)) {
        rb_raise(rb_eTypeError, "trace_func needs to be Proc");
    }
    trace_func = trace;
    for (hook = event_hooks; hook; hook = hook->next) {
        if (hook->func == call_trace_func)
            return trace;
    }
    rb_add_event_hook(call_trace_func, RUBY_EVENT_ALL);
    return trace;
}

static const char *
get_event_name(rb_event_t event)
{
    switch (event) {
      case RUBY_EVENT_LINE:
        return "line";
      case RUBY_EVENT_CLASS:
        return "class";
      case RUBY_EVENT_END:
        return "end";
      case RUBY_EVENT_CALL:
        return "call";
      case RUBY_EVENT_RETURN:
        return "return";
      case RUBY_EVENT_C_CALL:
        return "c-call";
      case RUBY_EVENT_C_RETURN:
        return "c-return";
      case RUBY_EVENT_RAISE:
        return "raise";
      default:
        return "unknown";
    }
}

static void
call_trace_func(event, node, self, id, klass)
    rb_event_t event;
    NODE *node;
    VALUE self;
    ID id;
    VALUE klass;
{
    int state;
    volatile int raised;
    struct FRAME *prev;
    NODE * volatile node_save;
    VALUE srcfile;
    const char *event_name;
    volatile rb_thread_t th = curr_thread;

    if (!trace_func) return;
    if (tracing) return;
    if (ruby_in_compile) return;
    if (id == ID_ALLOCATOR) return;

    if (!(node_save = ruby_current_node)) {
        node_save = NEW_NEWLINE(0);
    }
    tracing = 1;
    prev = ruby_frame;
    PUSH_FRAME();
    *ruby_frame = *prev;
    ruby_frame->prev = prev;
    ruby_frame->iter = 0;       /* blocks not available anyway */

    if (node) {
        ruby_current_node = node;
        ruby_frame->node = node;
        ruby_sourcefile = node->nd_file;
        ruby_sourceline = nd_line(node);
    }
    if (klass) {
        if (TYPE(klass) == T_ICLASS) {
            klass = RBASIC(klass)->klass;
        }
        else if (FL_TEST(klass, FL_SINGLETON)) {
            klass = rb_iv_get(klass, "__attached__");
        }
    }
    PUSH_TAG(PROT_EMPTY);
    raised = rb_thread_reset_raised(th);
    if ((state = EXEC_TAG()) == 0) {
        srcfile = rb_str_new2(ruby_sourcefile?ruby_sourcefile:"(ruby)");
        event_name = get_event_name(event);
        proc_invoke(trace_func, rb_ary_new3(6, rb_str_new2(event_name),
                                            srcfile,
                                            INT2FIX(ruby_sourceline),
                                            id?ID2SYM(id):Qnil,
                                            self?rb_f_binding(self):Qnil,
                                            klass),
                    Qundef, 0);
    }
    if (raised) rb_thread_set_raised(th);
    POP_TAG();
    POP_FRAME();

    tracing = 0;
    ruby_current_node = node_save;
    GC_DEBUG_SET_SOURCE
    if (state) JUMP_TAG(state);
}

static VALUE
avalue_to_svalue(v)
    VALUE v;
{
    VALUE tmp, top;

    tmp = rb_check_array_type(v);
    if (NIL_P(tmp)) {
        return v;
    }
    if (RARRAY(tmp)->len == 0) {
        return Qundef;
    }
    if (RARRAY(tmp)->len == 1) {
        top = rb_check_array_type(RARRAY(tmp)->ptr[0]);
        if (NIL_P(top)) {
            return RARRAY(tmp)->ptr[0];
        }
        if (RARRAY(top)->len > 1) {
            return v;
        }
        return top;
    }
    return tmp;
}

static VALUE
svalue_to_avalue(v)
    VALUE v;
{
    VALUE tmp, top;

    if (v == Qundef) return rb_ary_new2(0);
    tmp = rb_check_array_type(v);
    if (NIL_P(tmp)) {
        return rb_ary_new3(1, v);
    }
    if (RARRAY(tmp)->len == 1) {
        top = rb_check_array_type(RARRAY(tmp)->ptr[0]);
        if (!NIL_P(top) && RARRAY(top)->len > 1) {
            return tmp;
        }
        return rb_ary_new3(1, v);
    }
    return tmp;
}

static VALUE
svalue_to_mrhs(v, lhs)
    VALUE v;
    NODE *lhs;
{
    VALUE tmp;

    if (v == Qundef) return rb_ary_new2(0);
    tmp = rb_check_array_type(v);
    if (NIL_P(tmp)) {
        return rb_ary_new3(1, v);
    }
    /* no lhs means splat lhs only */
    if (!lhs) {
        return rb_ary_new3(1, v);
    }
    return tmp;
}

static VALUE
avalue_splat(v)
    VALUE v;
{
    if (RARRAY(v)->len == 0) {
        return Qundef;
    }
    if (RARRAY(v)->len == 1) {
        return RARRAY(v)->ptr[0];
    }
    return v;
}

#if 1
VALUE
rb_Array(val)
    VALUE val;
{
    VALUE tmp = rb_check_array_type(val);

    if (NIL_P(tmp)) {
        /* hack to avoid invoke Object#to_a */
        VALUE origin;
        ID id = rb_intern("to_a");

        if (search_method(CLASS_OF(val), id, &origin) &&
            RCLASS(origin)->m_tbl != RCLASS(rb_mKernel)->m_tbl) { /* exclude Kernel#to_a */
            val = rb_funcall(val, id, 0);
            if (TYPE(val) != T_ARRAY) {
                rb_raise(rb_eTypeError, "`to_a' did not return Array");
            }
            return val;
        }
        else {
            return rb_ary_new3(1, val);
        }
    }
    return tmp;
}
#endif

static VALUE
splat_value(v)
    VALUE v;
{
    if (NIL_P(v)) return rb_ary_new3(1, Qnil);
    return rb_Array(v);
}

static VALUE
class_prefix(self, cpath)
    VALUE self;
    NODE *cpath;
{
    if (!cpath) {
        rb_bug("class path missing");
    }
    if (cpath->nd_head) {
        VALUE c = rb_eval(self, cpath->nd_head);
        switch (TYPE(c)) {
          case T_CLASS:
          case T_MODULE:
            break;
          default:
            rb_raise(rb_eTypeError, "%s is not a class/module",
                     RSTRING(rb_obj_as_string(c))->ptr);
        }
        return c;
    }
    else if (nd_type(cpath) == NODE_COLON2) {
        return ruby_cbase;
    }
    else if (ruby_wrapper) {
        return ruby_wrapper;
    }
    else {
        return rb_cObject;
    }
}

#define return_value(v) do {\
  if ((prot_tag->retval = (v)) == Qundef) {\
    prot_tag->retval = Qnil;\
  }\
} while (0)

NORETURN(static void return_jump _((VALUE)));
NORETURN(static void break_jump _((VALUE)));
NORETURN(static void next_jump _((VALUE)));
NORETURN(static void unknown_node _((NODE *)));

static void
unknown_node(node)
    NODE *node;
{
    ruby_current_node = 0;
    if (node->flags == 0) {
        rb_bug("terminated node (0x%lx)", node);
    }
    else if (BUILTIN_TYPE(node) != T_NODE) {
        rb_bug("not a node 0x%02lx (0x%lx)", BUILTIN_TYPE(node), node);
    }
    else {
        rb_bug("unknown node type %d (0x%lx)", nd_type(node), node);
    }
}

/*
 *  functions factored out of rb_eval() to reduce its stack frame size
 */
#define eval_node_0(n,retType, self, node)  \
NOINLINE(static retType TOKEN_PASTE(eval_,n) _((self, node)));\
static retType TOKEN_PASTE(eval_,n)(self, node)

#define eval_node(n,retType) \
  eval_node_0(n,retType, VALUE self, NODE *node)
#define eval_node_volatile(n,retType) \
  eval_node_0(n,retType, volatile VALUE self, NODE * volatile node)

eval_node(match2, VALUE)
{
    VALUE l = rb_eval(self,node->nd_recv);
    VALUE r = rb_eval(self,node->nd_value);
    return rb_reg_match(l, r);
}

eval_node(match3, VALUE)
{
  VALUE r = rb_eval(self,node->nd_recv);
  VALUE l = rb_eval(self,node->nd_value);
  return TYPE(l) == T_STRING ? rb_reg_match(r, l) : rb_funcall(l, match, 1, r);
}


eval_node_volatile(opt_n, void)
{
  int state;
  PUSH_TAG(PROT_LOOP);
  switch (state = EXEC_TAG()) {
    case TAG_NEXT:
      state = 0;
    case 0:
      while (!NIL_P(rb_gets())) {
        opt_n_redo:
          rb_eval(self, node->nd_body);
      }
      break;

    case TAG_REDO:
      state = 0;
      goto opt_n_redo;

    case TAG_BREAK:
      state = 0;
    default:
      break;
  }
  POP_TAG();
  if (state) JUMP_TAG(state);
}


eval_node(when, NODE*)
{
  do {
      NODE *tag = node->nd_head;
      while (tag) {
          EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self,
                          ruby_frame->last_func,
                          ruby_frame->last_class);
          if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) {
              VALUE v = rb_eval(self, tag->nd_head->nd_head);
              long i;

              if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(v);
              for (i=0; ilen; i++) {
                  if (RTEST(RARRAY(v)->ptr[i])) return node->nd_body;
              }
              tag = tag->nd_next;
              continue;
          }
          if (RTEST(rb_eval(self, tag->nd_head))) return node->nd_body;
          tag = tag->nd_next;
      }
  } while ((node = node->nd_next) && nd_type(node) == NODE_WHEN);
  return node;
}


eval_node(case, NODE*)
{
  VALUE val = rb_eval(self, node->nd_head);
  node = node->nd_body;
  while (node) {
      NODE *tag;

      if (nd_type(node) != NODE_WHEN) break;
      tag = node->nd_head;
      while (tag) {
          EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self,
                          ruby_frame->last_func,
                          ruby_frame->last_class);
          if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) {
              VALUE v = rb_eval(self, tag->nd_head->nd_head);
              long i;

              if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(v);
              for (i=0; ilen; i++) {
                  if (RTEST(rb_funcall2(RARRAY(v)->ptr[i], eqq, 1, &val)))
                      return node->nd_body;
              }
              tag = tag->nd_next;
              continue;
          }
          if (RTEST(rb_funcall2(rb_eval(self, tag->nd_head), eqq, 1, &val)))
              return node->nd_body;
          tag = tag->nd_next;
      }
      node = node->nd_next;
  }
  return node;
}


eval_node_volatile(while, VALUE)
{
  int state;
  VALUE result;
  PUSH_TAG(PROT_LOOP);
  switch (state = EXEC_TAG()) {
    case 0:
      if (!(node->nd_state) || RTEST(rb_eval(self, node->nd_cond))) {
        do {
          while_redo:
#if STACK_WIPE_SITES & 0x10
            rb_gc_wipe_stack();
#endif
            rb_eval(self, node->nd_body);
          while_next:
            ;
        } while (RTEST(rb_eval(self, node->nd_cond)));
      }  /* fall thru */
    default:
      result=Qnil;
      break;

    case TAG_REDO:
      state = 0;
      goto while_redo;
    case TAG_NEXT:
      state = 0;
      goto while_next;
    case TAG_BREAK:
      if (TAG_DST()) {
          state = 0;
          result = prot_tag->retval;
      }
  }
  POP_TAG();
  if (state) JUMP_TAG(state);
  return result;
}


eval_node_volatile(until, VALUE)
{
  int state;
  VALUE result;
  PUSH_TAG(PROT_LOOP);
  switch (state = EXEC_TAG()) {
    case 0:
      if (!(node->nd_state) || !RTEST(rb_eval(self, node->nd_cond))) {
        do {
          until_redo:
  #if STACK_WIPE_SITES & 0x10
            rb_gc_wipe_stack();
  #endif
            rb_eval(self, node->nd_body);
          until_next:
            ;
        } while (!RTEST(rb_eval(self, node->nd_cond)));
      }  /* fall thru */
    default:
      result=Qnil;
      break;

    case TAG_REDO:
      state = 0;
      goto until_redo;
    case TAG_NEXT:
      state = 0;
      goto until_next;
    case TAG_BREAK:
      if (TAG_DST()) {
          state = 0;
          result = prot_tag->retval;
      }
  }
  POP_TAG();
  if (state) JUMP_TAG(state);
  return result;
}


eval_node_volatile(iter, VALUE)
{
  int state;
  VALUE result;

  PUSH_TAG(PROT_LOOP);
  PUSH_BLOCK(node->nd_var, node->nd_body);

  state = EXEC_TAG();
  switch (state) {
    case TAG_RETRY:
      state = 0;  /* fall thru to case 0 */
    case 0:
      PUSH_ITER(ITER_PRE);
      if (nd_type(node) == NODE_ITER) {
          result = rb_eval(self, node->nd_iter);
      }
      else {
          _block.flags &= ~BLOCK_D_SCOPE;
          BEGIN_CALLARGS;
          result = rb_eval(self, node->nd_iter);
          END_CALLARGS;
          ruby_current_node = (NODE *)node;
          GC_DEBUG_SET_SOURCE
          result = rb_call(CLASS_OF(result),result,each,0,0,0,self);
      }
      POP_ITER();
      break;

    case TAG_BREAK:
      if (TAG_DST()) {
        result = prot_tag->retval;
        state = 0;
      }
  }
  POP_BLOCK();
  POP_TAG();
  if (state) JUMP_TAG(state);
  return result;
}


eval_node_volatile(rescue, VALUE)
{
    volatile VALUE e_info = ruby_errinfo;
    volatile int rescuing = 0;
    int state;
    VALUE result;

    PUSH_TAG(PROT_EMPTY);
    if ((state = EXEC_TAG()) == 0) {
      retry_entry:
        result = rb_eval(self, node->nd_head);
    }
    else if (rescuing) {
        if (rescuing < 0) {
            /* in rescue argument, just reraise */
            result = Qnil;
        }
        else if (state == TAG_RETRY) {
            rescuing = state = 0;
            ruby_errinfo = e_info;
            goto retry_entry;
        }
        else if (state != TAG_RAISE) {
            result = prot_tag->retval;
        }
    }
    else if (state == TAG_RAISE) {
        NODE *resq = node->nd_resq;

        rescuing = -1;
        while (resq) {
            ruby_current_node = resq;
            if (handle_rescue(self, resq)) {
                state = 0;
                rescuing = 1;
                result = rb_eval(self, resq->nd_body);
                break;
            }
            resq = resq->nd_head; /* next rescue */
        }
    }
    else {
        result = prot_tag->retval;
    }
    POP_TAG();
    if (state != TAG_RAISE) ruby_errinfo = e_info;
    if (state) {
        JUMP_TAG(state);
    }
    /* no exception raised */
    if (!rescuing && node->nd_else) { /* else clause given */
        result = Qundef;  /* caller must eval this! */
    }
    return result;
}


eval_node_volatile(ensure, VALUE)
{
  int state;
  VALUE result;

  PUSH_TAG(PROT_EMPTY);
  if ((state = EXEC_TAG()) == 0) {
      result = rb_eval(self, node->nd_head);
  }
  POP_TAG();
  if (node->nd_ensr && !thread_no_ensure()) {
      VALUE retval = prot_tag->retval; /* save retval */
      VALUE errinfo = ruby_errinfo;

      rb_eval(self, node->nd_ensr);
      return_value(retval);
      ruby_errinfo = errinfo;
  }
  if (state) JUMP_TAG(state);
  return result;
}


eval_node(dot, VALUE)
{
  VALUE beg = rb_eval(self, node->nd_beg);
  VALUE end = rb_eval(self, node->nd_end);
  return rb_range_new(beg, end, nd_type(node) == NODE_DOT3);
}


eval_node(flip2, VALUE)
{
  VALUE *flip = rb_svar(node->nd_cnt);
  if (!flip) rb_bug("unexpected local variable");
  if (!RTEST(*flip)) {
    if (!RTEST(rb_eval(self, node->nd_beg)))
      return Qfalse;
    *flip = RTEST(rb_eval(self, node->nd_end))?Qfalse:Qtrue;
  }
  else if (RTEST(rb_eval(self, node->nd_end)))
    *flip = Qfalse;
  return Qtrue;
}


eval_node(flip3, VALUE)
{
  VALUE *flip = rb_svar(node->nd_cnt);
  if (!flip) rb_bug("unexpected local variable");
  if (!RTEST(*flip))
    return *flip = (RTEST(rb_eval(self, node->nd_beg)) ? Qtrue : Qfalse);
  if (RTEST(rb_eval(self, node->nd_end)))
    *flip = Qfalse;
  return Qtrue;
}


eval_node(attrasgn, VALUE)
{
  VALUE recv;
  int argc; VALUE *argv; /* used in SETUP_ARGS */
  int scope;
  TMP_PROTECT;

  BEGIN_CALLARGS;
  if (node->nd_recv == (NODE *)1) {
      recv = self;
      scope = 1;
  }
  else {
      recv = rb_eval(self, node->nd_recv);
      scope = 0;
  }
  SETUP_ARGS(node->nd_args);
  END_CALLARGS;

  ruby_current_node = node;
  GC_DEBUG_SET_SOURCE
  rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,scope,self);
  return argv[argc-1];
}


eval_node(call, VALUE)
{
  VALUE recv;
  int argc; VALUE *argv; /* used in SETUP_ARGS */
  TMP_PROTECT;

  BEGIN_CALLARGS;
  recv = rb_eval(self, node->nd_recv);
  SETUP_ARGS(node->nd_args);
  END_CALLARGS;

  ruby_current_node = node;
  GC_DEBUG_SET_SOURCE
  return rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0,self);
}


eval_node(fcall, VALUE)
{
  int argc; VALUE *argv; /* used in SETUP_ARGS */
  TMP_PROTECT;

  BEGIN_CALLARGS;
  SETUP_ARGS(node->nd_args);
  END_CALLARGS;

  ruby_current_node = node;
  GC_DEBUG_SET_SOURCE
  return rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1,self);
}


eval_node(super, VALUE)
{
  int argc; VALUE *argv; /* used in SETUP_ARGS */
  TMP_PROTECT;

  if (ruby_frame->last_class == 0) {
      if (ruby_frame->last_func) {
          rb_name_error(ruby_frame->last_func,
                        "superclass method `%s' disabled",
                        rb_id2name(ruby_frame->orig_func));
      }
      else {
          rb_raise(rb_eNoMethodError, "super called outside of method");
      }
  }
  if (nd_type(node) == NODE_ZSUPER) {
      argc = ruby_frame->argc;
      if (argc && DMETHOD_P()) {
          if (TYPE(RBASIC(ruby_scope)->klass) != T_ARRAY ||
              RARRAY(RBASIC(ruby_scope)->klass)->len != argc) {
              rb_raise(rb_eRuntimeError,
                       "super: specify arguments explicitly");
          }
          argv = RARRAY(RBASIC(ruby_scope)->klass)->ptr;
      }
      else if (!ruby_scope->local_vars) {
          argc = 0;
          argv = 0;
      }
      else {
          argv = ruby_scope->local_vars + 2;
      }
  }
  else {
      BEGIN_CALLARGS;
      SETUP_ARGS(node->nd_args);
      END_CALLARGS;
      ruby_current_node = node;
  }

  GC_DEBUG_SET_SOURCE
  return rb_call_super(argc, argv);
}

eval_node_volatile(scope, VALUE)
{
  int state;
  VALUE result;
  struct FRAME frame;
  NODE * volatile saved_cref = 0;

  frame = *ruby_frame;
  frame.tmp = ruby_frame;
  ruby_frame = &frame;

  PUSH_SCOPE();
  PUSH_TAG(PROT_EMPTY);
  if (node->nd_rval) {
      saved_cref = ruby_cref;
      ruby_cref = (NODE*)node->nd_rval;
  }
  if (node->nd_tbl) {
      VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1);
      *vars++ = (VALUE)node;
      ruby_scope->local_vars = vars;
      rb_mem_clear(ruby_scope->local_vars, node->nd_tbl[0]);
      ruby_scope->local_tbl = node->nd_tbl;
  }
  else {
      ruby_scope->local_vars = 0;
      ruby_scope->local_tbl  = 0;
  }
  if ((state = EXEC_TAG()) == 0) {
      result = rb_eval(self, node->nd_next);
  }
  POP_TAG();
  POP_SCOPE();
  ruby_frame = frame.tmp;
  if (saved_cref)
      ruby_cref = saved_cref;
  if (state) JUMP_TAG(state);
  return result;
}

eval_node(op_asgn1, VALUE)
{
  int argc; VALUE *argv; /* used in SETUP_ARGS */
  VALUE recv, val, tmp;
  NODE *rval;
  TMP_PROTECT;

  recv = rb_eval(self, node->nd_recv);
  rval = node->nd_args->nd_head;
  SETUP_ARGS0(node->nd_args->nd_body, 1);
  val = rb_funcall3(recv, aref, argc, argv);
  switch (node->nd_mid) {
  case 0: /* OR */
    if (RTEST(val)) return val;
    val = rb_eval(self, rval);
    break;
  case 1: /* AND */
    if (!RTEST(val)) return val;
    val = rb_eval(self, rval);
    break;
  default:
    tmp = rb_eval(self, rval);
    val = rb_funcall3(val, node->nd_mid, 1, &tmp);
  }
  argv[argc] = val;
  rb_funcall2(recv, aset, argc+1, argv);
  return val;
}


eval_node(op_asgn2, VALUE)
{
  ID id = node->nd_next->nd_vid;
  VALUE recv, val, tmp;

  recv = rb_eval(self, node->nd_recv);
  val = rb_funcall3(recv, id, 0, 0);
  switch (node->nd_next->nd_mid) {
  case 0: /* OR */
    if (RTEST(val)) return val;
    val = rb_eval(self, node->nd_value);
    break;
  case 1: /* AND */
    if (!RTEST(val)) return val;
    val = rb_eval(self, node->nd_value);
    break;
  default:
    tmp = rb_eval(self, node->nd_value);
    val = rb_funcall3(val, node->nd_next->nd_mid, 1, &tmp);
  }

  rb_funcall2(recv, node->nd_next->nd_aid, 1, &val);
  return val;
}


eval_node(hash, VALUE)
{
  NODE *list;
  VALUE hash = rb_hash_new();
  VALUE key, val;

  list = node->nd_head;
  while (list) {
      key = rb_eval(self, list->nd_head);
      list = list->nd_next;
      if (list == 0)
          rb_bug("odd number list for Hash");
      val = rb_eval(self, list->nd_head);
      list = list->nd_next;
      rb_hash_aset(hash, key, val);
  }
  return hash;
}


eval_node(array, VALUE)
{
  VALUE ary;
  long i;

  i = node->nd_alen;
  ary = rb_ary_new2(i);
  for (i=0;node;node=node->nd_next) {
      RARRAY(ary)->ptr[i++] = rb_eval(self, node->nd_head);
      RARRAY(ary)->len = i;
  }
  return ary;
}


eval_node(slit, VALUE)
{
  VALUE str, str2;
  NODE *list = node->nd_next;

  str = rb_str_new3(node->nd_lit);
  while (list) {
      if (list->nd_head) {
          switch (nd_type(list->nd_head)) {
            case NODE_STR:
              str2 = list->nd_head->nd_lit;
              break;
            default:
              str2 = rb_eval(self, list->nd_head);
              break;
          }
          rb_str_append(str, str2);
          OBJ_INFECT(str, str2);
      }
      list = list->nd_next;
  }
  switch (nd_type(node)) {
    case NODE_DREGX:
      str2 = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len,
                          node->nd_cflag);
      RB_GC_GUARD(str);  /* ensure str is not GC'd in rb_reg_new */
      return str2;
    case NODE_DREGX_ONCE:       /* regexp expand once */
      str2 = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len,
                          node->nd_cflag);
      nd_set_type(node, NODE_LIT);
      RB_GC_GUARD(str);  /* ensure str is not GC'd in rb_reg_new */
      maybe_add_to_longlife_recent_allocations(node);
      return node->nd_lit = str2;
    case NODE_LIT:
      /* other thread may replace NODE_DREGX_ONCE to NODE_LIT */
      return Qundef;
    case NODE_DXSTR:
      return rb_funcall(self, '`', 1, str);
    case NODE_DSYM:
      return rb_str_intern(str);
  }
  return str;
}


eval_node(defn, void)
{
  NODE *body,  *defn;
  VALUE origin = 0;
  int noex;

  if (NIL_P(ruby_class)) {
      rb_raise(rb_eTypeError, "no class/module to add method");
  }
  if (ruby_class == rb_cObject && node->nd_mid == init) {
      rb_warn("redefining Object#initialize may cause infinite loop");
  }
  if (node->nd_mid == __id__ || node->nd_mid == __send__) {
      rb_warn("redefining `%s' may cause serious problem",
              rb_id2name(node->nd_mid));
  }
  rb_frozen_class_p(ruby_class);
  body = search_method(ruby_class, node->nd_mid, &origin);
  if (body){
      if (RTEST(ruby_verbose) && ruby_class == origin && body->nd_cnt == 0 && body->nd_body) {
          rb_warning("method redefined; discarding old %s", rb_id2name(node->nd_mid));
      }
  }

  if (SCOPE_TEST(SCOPE_PRIVATE) || node->nd_mid == init) {
      noex = NOEX_PRIVATE;
  }
  else if (SCOPE_TEST(SCOPE_PROTECTED)) {
      noex = NOEX_PROTECTED;
  }
  else {
      noex = NOEX_PUBLIC;
  }
  if (body && origin == ruby_class && body->nd_body == 0) {
      noex |= NOEX_NOSUPER;
  }

  defn = rb_copy_node_scope(node->nd_defn, ruby_cref);
  rb_add_method(ruby_class, node->nd_mid, defn, noex);
  if (scope_vmode == SCOPE_MODFUNC) {
      rb_add_method(rb_singleton_class(ruby_class),
                    node->nd_mid, defn, NOEX_PUBLIC);
  }
}


eval_node(defs, void)
{
  VALUE recv = rb_eval(self, node->nd_recv);
  VALUE klass;
  NODE *body = 0, *defn;
  st_data_t data;

  if (ruby_safe_level >= 4 && !OBJ_TAINTED(recv)) {
      rb_raise(rb_eSecurityError, "Insecure: can't define singleton method");
  }
  if (FIXNUM_P(recv) || SYMBOL_P(recv)) {
      rb_raise(rb_eTypeError,
               "can't define singleton method \"%s\" for %s",
               rb_id2name(node->nd_mid),
               rb_obj_classname(recv));
  }

  if (OBJ_FROZEN(recv)) rb_error_frozen("object");
  klass = rb_singleton_class(recv);
  if (st_lookup(RCLASS(klass)->m_tbl, node->nd_mid, &data)) {
      body = (NODE *)data;
      if (ruby_safe_level >= 4) {
          rb_raise(rb_eSecurityError, "redefining method prohibited");
      }
      if (RTEST(ruby_verbose)) {
          rb_warning("redefine %s", rb_id2name(node->nd_mid));
      }
  }
  defn = rb_copy_node_scope(node->nd_defn, ruby_cref);
  rb_add_method(klass, node->nd_mid, defn,
                NOEX_PUBLIC|(body?body->nd_noex&NOEX_UNDEF:0));
}


eval_node(class, VALUE)
{
    VALUE super, klass, tmp, cbase;
    ID cname;
    int gen = Qfalse;

    cbase = class_prefix(self, node->nd_cpath);
    cname = node->nd_cpath->nd_mid;

    if (NIL_P(ruby_cbase)) {
        rb_raise(rb_eTypeError, "no outer class/module");
    }
    if (node->nd_super) {
       super = rb_eval(self, node->nd_super);
       rb_check_inheritable(super);
    }
    else {
        super = 0;
    }

    if (rb_const_defined_at(cbase, cname)) {
        klass = rb_const_get_at(cbase, cname);
        if (TYPE(klass) != T_CLASS) {
            rb_raise(rb_eTypeError, "%s is not a class",
                     rb_id2name(cname));
        }
        if (super) {
            tmp = rb_class_real(RCLASS(klass)->super);
            if (tmp != super) {
                rb_raise(rb_eTypeError, "superclass mismatch for class %s",
                         rb_id2name(cname));
            }
            super = 0;
        }
        if (ruby_safe_level >= 4) {
            rb_raise(rb_eSecurityError, "extending class prohibited");
        }
    }
    else {
        if (!super) super = rb_cObject;
        klass = rb_define_class_id(cname, super);
        rb_set_class_path(klass, cbase, rb_id2name(cname));
        rb_const_set(cbase, cname, klass);
        gen = Qtrue;
    }
    if (ruby_wrapper) {
        rb_extend_object(klass, ruby_wrapper);
        rb_include_module(klass, ruby_wrapper);
    }
    if (super && gen) {
        rb_class_inherited(super, klass);
    }
    return module_setup(klass, node);
}


eval_node(module, VALUE)
{
  VALUE module, cbase;
  ID cname;

  if (NIL_P(ruby_cbase)) {
      rb_raise(rb_eTypeError, "no outer class/module");
  }
  cbase = class_prefix(self, node->nd_cpath);
  cname = node->nd_cpath->nd_mid;
  if (rb_const_defined_at(cbase, cname)) {
      module = rb_const_get_at(cbase, cname);
      if (TYPE(module) != T_MODULE) {
          rb_raise(rb_eTypeError, "%s is not a module",
                   rb_id2name(cname));
      }
      if (ruby_safe_level >= 4) {
          rb_raise(rb_eSecurityError, "extending module prohibited");
      }
  }
  else {
      module = rb_define_module_id(cname);
      rb_set_class_path(module, cbase, rb_id2name(cname));
      rb_const_set(cbase, cname, module);
  }
  if (ruby_wrapper) {
      rb_extend_object(module, ruby_wrapper);
      rb_include_module(module, ruby_wrapper);
  }

  return module_setup(module, node);
}


eval_node(sclass, VALUE)
{
  VALUE klass, result;

  result = rb_eval(self, node->nd_recv);
  if (FIXNUM_P(result) || SYMBOL_P(result)) {
      rb_raise(rb_eTypeError, "no virtual class for %s",
               rb_obj_classname(result));
  }
  if (ruby_safe_level >= 4 && !OBJ_TAINTED(result))
      rb_raise(rb_eSecurityError, "Insecure: can't extend object");
  klass = rb_singleton_class(result);

  if (ruby_wrapper) {
      rb_extend_object(klass, ruby_wrapper);
      rb_include_module(klass, ruby_wrapper);
  }

  return module_setup(klass, node);
}


eval_node(defined, VALUE)
{
    char buf[20];
    const char *desc = is_defined(self, node->nd_head, buf);
    return desc ? rb_str_new2(desc) : Qnil;
}


static void
eval_cvar_set(node, result, warn)
  NODE *node;
  VALUE result;
  int warn;
{
  rb_cvar_set(cvar_cbase(), node->nd_vid, result, warn);
}


static void
eval_cdecl(self, node, result)
  VALUE self, result;
  NODE *node;
{
  if (node->nd_vid == 0)
      rb_const_set(class_prefix(self, node->nd_else),
                          node->nd_else->nd_mid, result);
  else
      rb_const_set(ruby_cbase, node->nd_vid, result);
}


static VALUE
rb_eval(self, node)
  VALUE self;
  NODE * node;
{
  VALUE result;

again:
  eval_check_tick();
  result = Qnil;
  if (node) {
    ruby_current_node = node;
    switch (nd_type(node)) {
      case NODE_BLOCK:
        while (node->nd_next) {
            rb_eval(self, node->nd_head);
            node = node->nd_next;
        }
        node = node->nd_head;
        goto again;

      case NODE_POSTEXE:
        rb_f_END();
        nd_set_type(node, NODE_NIL); /* exec just once */
        break;

        /* begin .. end without clauses */
      case NODE_BEGIN:
        node = node->nd_body;
        goto again;

        /* nodes for speed-up(default match) */
      case NODE_MATCH:
        result = rb_reg_match2(node->nd_lit);
        break;

        /* nodes for speed-up(literal match) */
      case NODE_MATCH2:
        result = eval_match2(self, node);
        break;

        /* nodes for speed-up(literal match) */
      case NODE_MATCH3:
        result = eval_match3(self,node);
        break;

        /* node for speed-up(top-level loop for -n/-p) */
      case NODE_OPT_N:
        eval_opt_n(self, node);
        break;

      case NODE_SELF:
        result = self;
        break;

      case NODE_NIL:
        break;

      case NODE_TRUE:
        result = Qtrue;
        break;

      case NODE_FALSE:
        result = Qfalse;
        break;

      case NODE_IF:
        if (RTEST(rb_eval(self, node->nd_cond))) {
            EXEC_EVENT_HOOK(RUBY_EVENT_LINE, node, self,
                            ruby_frame->last_func,
                            ruby_frame->last_class);
            node = node->nd_body;
        }
        else {
            EXEC_EVENT_HOOK(RUBY_EVENT_LINE, node, self,
                            ruby_frame->last_func,
                            ruby_frame->last_class);
            node = node->nd_else;
        }
        goto again;

      case NODE_WHEN:
        if (node = eval_when(self, node)) goto again;
        break;

      case NODE_CASE:
        if (node = eval_case(self, node)) goto again;
        break;

      case NODE_WHILE:
        result = eval_while(self,node);
        break;

      case NODE_UNTIL:
        result = eval_until(self,node);
        break;

      case NODE_BLOCK_PASS:
        result = block_pass(self, node);
        break;

      case NODE_ITER:
      case NODE_FOR:
        result = eval_iter(self, node);
        break;

      case NODE_BREAK:
        break_jump(rb_eval(self, node->nd_stts));
        break;

      case NODE_NEXT:
        next_jump(rb_eval(self, node->nd_stts));
        break;

      case NODE_REDO:
        JUMP_TAG(TAG_REDO);
        break;

      case NODE_RETRY:
        JUMP_TAG(TAG_RETRY);
        break;

      case NODE_SPLAT:
        result = splat_value(rb_eval(self, node->nd_head));
        break;

      case NODE_TO_ARY:
        result = rb_ary_to_ary(rb_eval(self, node->nd_head));
        break;

      case NODE_SVALUE:
        result = avalue_splat(rb_eval(self, node->nd_head));
        if (result == Qundef) result = Qnil;
        break;

      case NODE_YIELD:
        if (node->nd_head) {
            result = rb_eval(self, node->nd_head);
            ruby_current_node = node;
        }
        else {
            result = Qundef;    /* no arg */
        }
        GC_DEBUG_SET_SOURCE
        result = rb_yield_0(result, 0, 0, 0, node->nd_state);
        break;

      case NODE_RESCUE:
        result = eval_rescue(self,node);
        if (result == Qundef) {  /* handle else clause w/o recursion */
          node = node->nd_else;
          goto again;
        }
        break;

      case NODE_ENSURE:
        result = eval_ensure(self,node);
        break;

      case NODE_AND:
        result = rb_eval(self, node->nd_1st);
        if (!RTEST(result)) break;
        node = node->nd_2nd;
        goto again;

      case NODE_OR:
        result = rb_eval(self, node->nd_1st);
        if (RTEST(result)) break;
        node = node->nd_2nd;
        goto again;

      case NODE_NOT:
        result = RTEST(rb_eval(self, node->nd_body)) ? Qfalse : Qtrue;
        break;

      case NODE_DOT2:
      case NODE_DOT3:
        result = eval_dot(self,node);
        break;

      case NODE_FLIP2:          /* like AWK */
        result = eval_flip2(self,node);
        break;

      case NODE_FLIP3:          /* like SED */
        result = eval_flip3(self,node);
        break;

      case NODE_RETURN:
        return_jump(rb_eval(self, node->nd_stts));
        break;

      case NODE_ARGSCAT:
        result = rb_eval(self, node->nd_head);
        result = rb_ary_concat(result, splat_value(rb_eval(self, node->nd_body)));
        break;

      case NODE_ARGSPUSH:
        result = rb_ary_dup(rb_eval(self, node->nd_head));
        result = rb_ary_push(result, rb_eval(self, node->nd_body));
        break;

      case NODE_ATTRASGN:
        result = eval_attrasgn(self,node);
        break;

      case NODE_CALL:
        result = eval_call(self,node);
        break;

      case NODE_FCALL:
        result = eval_fcall(self,node);
        break;

      case NODE_VCALL:
        GC_DEBUG_SET_SOURCE
        result = rb_call(CLASS_OF(self),self,node->nd_mid,0,0,2,self);
        break;

      case NODE_SUPER:
      case NODE_ZSUPER:
        result = eval_super(self,node);
        break;

      case NODE_SCOPE:
        result = eval_scope(self,node);
        break;

      case NODE_OP_ASGN1:
        result = eval_op_asgn1(self,node);
        break;

      case NODE_OP_ASGN2:
        result = eval_op_asgn2(self,node);
        break;

      case NODE_OP_ASGN_AND:
        result = rb_eval(self, node->nd_head);
        if (!RTEST(result)) break;
        node = node->nd_value;
        goto again;

      case NODE_OP_ASGN_OR:
        if ((node->nd_aid && !is_defined(self, node->nd_head, 0)) ||
            !RTEST(result = rb_eval(self, node->nd_head))) {
            node = node->nd_value;
            goto again;
        }
        break;

      case NODE_MASGN:
        result = massign(self, node, rb_eval(self, node->nd_value), 0);
        break;

      case NODE_LASGN:
        if (ruby_scope->local_vars == 0)
            rb_bug("unexpected local variable assignment");
        result = rb_eval(self, node->nd_value);
        ruby_scope->local_vars[node->nd_cnt] = result;
        break;

      case NODE_DASGN:
        result = rb_eval(self, node->nd_value);
        dvar_asgn(node->nd_vid, result);
        break;

      case NODE_DASGN_CURR:
        result = rb_eval(self, node->nd_value);
        dvar_asgn_curr(node->nd_vid, result);
        break;

      case NODE_GASGN:
        ruby_in_longlife_context++;
        result = rb_eval(self, node->nd_value);
        rb_gvar_set(node->nd_entry, result);
        ruby_in_longlife_context--;
        break;

      case NODE_IASGN:
        result = rb_eval(self, node->nd_value);
        rb_ivar_set(self, node->nd_vid, result);
        break;

      case NODE_CDECL:
        ruby_in_longlife_context++;
        result = rb_eval(self, node->nd_value);
        eval_cdecl(self, node, result);
        ruby_in_longlife_context--;
        break;

      case NODE_CVDECL:
        if (NIL_P(ruby_cbase)) {
            rb_raise(rb_eTypeError, "no class/module to define class variable");
        }
        ruby_in_longlife_context++;
        result = rb_eval(self, node->nd_value);
        eval_cvar_set(node, result, Qtrue);
        ruby_in_longlife_context--;
        break;

      case NODE_CVASGN:
        ruby_in_longlife_context++;
        result = rb_eval(self, node->nd_value);
        eval_cvar_set(node, result, Qfalse);
        ruby_in_longlife_context--;
        break;

      case NODE_LVAR:
        if (ruby_scope->local_vars == 0) {
            rb_bug("unexpected local variable");
        }
        result = ruby_scope->local_vars[node->nd_cnt];
        break;

      case NODE_DVAR:
        result = rb_dvar_ref(node->nd_vid);
        break;

      case NODE_GVAR:
        result = rb_gvar_get(node->nd_entry);
        break;

      case NODE_IVAR:
        result = rb_ivar_get(self, node->nd_vid);
        break;

      case NODE_CONST:
        result = ev_const_get(ruby_cref, node->nd_vid, self);
        break;

      case NODE_CVAR:
        result = rb_cvar_get(cvar_cbase(), node->nd_vid);
        break;

      case NODE_BLOCK_ARG:
        if (ruby_scope->local_vars == 0)
            rb_bug("unexpected block argument");
        if (rb_block_given_p()) {
            result = rb_block_proc();
            ruby_scope->local_vars[node->nd_cnt] = result;
        }
        else {
            result = Qnil;
        }
        break;

      case NODE_COLON2:
        result = rb_eval(self, node->nd_head);
        if (rb_is_const_id(node->nd_mid)) {
            switch (TYPE(result)) {
              case T_CLASS:
              case T_MODULE:
                result = rb_const_get_from(result, node->nd_mid);
                break;
              default:
                rb_raise(rb_eTypeError, "%s is not a class/module",
                         RSTRING(rb_obj_as_string(result))->ptr);
                break;
            }
        }
        else
            result = rb_funcall(result, node->nd_mid, 0, 0);
        break;

      case NODE_COLON3:
        result = rb_const_get_from(rb_cObject, node->nd_mid);
        break;

      case NODE_NTH_REF:
        result = rb_reg_nth_match(node->nd_nth, MATCH_DATA);
        break;

      case NODE_BACK_REF:
        switch (node->nd_nth) {
          case '&':
            result = rb_reg_last_match(MATCH_DATA);
            break;
          case '`':
            result = rb_reg_match_pre(MATCH_DATA);
            break;
          case '\'':
            result = rb_reg_match_post(MATCH_DATA);
            break;
          case '+':
            result = rb_reg_match_last(MATCH_DATA);
            break;
          default:
            rb_bug("unexpected back-ref");
        }
        break;

      case NODE_HASH:
        result = eval_hash(self,node);
        break;

      case NODE_ZARRAY:         /* zero length list */
        result = rb_ary_new();
        break;

      case NODE_ARRAY:
        result = eval_array(self,node);
        break;

      case NODE_STR:
        result = rb_str_new3(node->nd_lit);
        break;

      case NODE_EVSTR:
        result = rb_obj_as_string(rb_eval(self, node->nd_body));
        break;

      case NODE_DSTR:
      case NODE_DXSTR:
      case NODE_DREGX:
      case NODE_DREGX_ONCE:
      case NODE_DSYM:
        result = eval_slit(self, node);
        if (result == Qundef) goto again;
        break;

      case NODE_XSTR:
        result = rb_funcall(self, '`', 1, rb_str_new3(node->nd_lit));
        break;

      case NODE_LIT:
        result = node->nd_lit;
        break;

      case NODE_DEFN:
        if (node->nd_defn)
          eval_defn(self,node);
        break;

      case NODE_DEFS:
        if (node->nd_defn)
          eval_defs(self,node);
        break;

      case NODE_UNDEF:
        if (NIL_P(ruby_class)) {
            rb_raise(rb_eTypeError, "no class to undef method");
        }
        rb_undef(ruby_class, rb_to_id(rb_eval(self, node->u2.node)));
        break;

      case NODE_ALIAS:
        if (NIL_P(ruby_class)) {
            rb_raise(rb_eTypeError, "no class to make alias");
        }
        rb_alias(ruby_class, rb_to_id(rb_eval(self, node->u1.node)),
                             rb_to_id(rb_eval(self, node->u2.node)));
        break;

      case NODE_VALIAS:
        rb_alias_variable(node->u1.id, node->u2.id);
        break;

      case NODE_CLASS:
        result = eval_class(self,node);
        break;

      case NODE_MODULE:
        result = eval_module(self,node);
        break;

      case NODE_SCLASS:
        result = eval_sclass(self,node);
        break;

      case NODE_DEFINED:
        result = eval_defined(self,node);
        break;

      case NODE_NEWLINE:
        EXEC_EVENT_HOOK(RUBY_EVENT_LINE, node, self,
                        ruby_frame->last_func,
                        ruby_frame->last_class);
        node = node->nd_next;
        goto again;

      default:
        unknown_node(node);
    }
  }
  return result;
}

static VALUE
module_setup(module, n)
    VALUE module;
    NODE * volatile n;
{
    NODE *node = n->nd_body;
    int state;
    struct FRAME frame;
    VALUE result;
    TMP_PROTECT;

    frame = *ruby_frame;
    frame.tmp = ruby_frame;
    ruby_frame = &frame;

    PUSH_CLASS(module);
    PUSH_SCOPE();
    PUSH_VARS();

    if (node->nd_tbl) {
        VALUE *vars = TMP_ALLOC(node->nd_tbl[0]+1);
        *vars++ = (VALUE)node;
        ruby_scope->local_vars = vars;
        rb_mem_clear(ruby_scope->local_vars, node->nd_tbl[0]);
        ruby_scope->local_tbl = node->nd_tbl;
    }
    else {
        ruby_scope->local_vars = 0;
        ruby_scope->local_tbl  = 0;
    }

    PUSH_CREF(module);
    PUSH_TAG(PROT_EMPTY);
    if ((state = EXEC_TAG()) == 0) {
        EXEC_EVENT_HOOK(RUBY_EVENT_CLASS, n, ruby_cbase,
                        ruby_frame->last_func, ruby_frame->last_class);
        result = rb_eval(ruby_cbase, node->nd_next);
    }
    POP_TAG();
    POP_CREF();
    POP_VARS();
    POP_SCOPE();
    POP_CLASS();

    ruby_frame = frame.tmp;
    EXEC_EVENT_HOOK(RUBY_EVENT_END, n, 0,
                    ruby_frame->last_func, ruby_frame->last_class);
    if (state) JUMP_TAG(state);

    return result;
}

static NODE *basic_respond_to = 0;

int
rb_obj_respond_to(obj, id, priv)
    VALUE obj;
    ID id;
    int priv;
{
    VALUE klass = CLASS_OF(obj);

    if (rb_method_node(klass, respond_to) == basic_respond_to) {
        return rb_method_boundp(klass, id, !priv);
    }
    else {
        VALUE args[2];
        int n = 0;
        args[n++] = ID2SYM(id);
        if (priv) args[n++] = Qtrue;
        return RTEST(rb_funcall2(obj, respond_to, n, args));
    }
}

int
rb_respond_to(obj, id)
    VALUE obj;
    ID id;
{
    return rb_obj_respond_to(obj, id, Qfalse);
}

/*
 *  call-seq:
 *     obj.respond_to?(symbol, include_private=false) => true or false
 *
 *  Returns +true+> if _obj_ responds to the given
 *  method. Private methods are included in the search only if the
 *  optional second parameter evaluates to +true+.
 */

static VALUE
obj_respond_to(argc, argv, obj)
    int argc;
    VALUE *argv;
    VALUE obj;
{
    VALUE mid, priv;
    ID id;

    rb_scan_args(argc, argv, "11", &mid, &priv);
    id = rb_to_id(mid);
    if (rb_method_boundp(CLASS_OF(obj), id, !RTEST(priv))) {
        return Qtrue;
    }
    return Qfalse;
}

/*
 *  call-seq:
 *     mod.method_defined?(symbol)    => true or false
 *
 *  Returns +true+ if the named method is defined by
 *  _mod_ (or its included modules and, if _mod_ is a class,
 *  its ancestors). Public and protected methods are matched.
 *
 *     module A
 *       def method1()  end
 *     end
 *     class B
 *       def method2()  end
 *     end
 *     class C < B
 *       include A
 *       def method3()  end
 *     end
 *
 *     A.method_defined? :method1    #=> true
 *     C.method_defined? "method1"   #=> true
 *     C.method_defined? "method2"   #=> true
 *     C.method_defined? "method3"   #=> true
 *     C.method_defined? "method4"   #=> false
 */

static VALUE
rb_mod_method_defined(mod, mid)
    VALUE mod, mid;
{
    return rb_method_boundp(mod, rb_to_id(mid), 1);
}

#define VISI_CHECK(x,f) (((x)&NOEX_MASK) == (f))

/*
 *  call-seq:
 *     mod.public_method_defined?(symbol)   => true or false
 *
 *  Returns +true+ if the named public method is defined by
 *  _mod_ (or its included modules and, if _mod_ is a class,
 *  its ancestors).
 *
 *     module A
 *       def method1()  end
 *     end
 *     class B
 *       protected
 *       def method2()  end
 *     end
 *     class C < B
 *       include A
 *       def method3()  end
 *     end
 *
 *     A.method_defined? :method1           #=> true
 *     C.public_method_defined? "method1"   #=> true
 *     C.public_method_defined? "method2"   #=> false
 *     C.method_defined? "method2"          #=> true
 */

static VALUE
rb_mod_public_method_defined(mod, mid)
    VALUE mod, mid;
{
    ID id = rb_to_id(mid);
    int noex;

    if (rb_get_method_body(&mod, &id, &noex)) {
        if (VISI_CHECK(noex, NOEX_PUBLIC))
            return Qtrue;
    }
    return Qfalse;
}

/*
 *  call-seq:
 *     mod.private_method_defined?(symbol)    => true or false
 *
 *  Returns +true+ if the named private method is defined by
 *  _ mod_ (or its included modules and, if _mod_ is a class,
 *  its ancestors).
 *
 *     module A
 *       def method1()  end
 *     end
 *     class B
 *       private
 *       def method2()  end
 *     end
 *     class C < B
 *       include A
 *       def method3()  end
 *     end
 *
 *     A.method_defined? :method1            #=> true
 *     C.private_method_defined? "method1"   #=> false
 *     C.private_method_defined? "method2"   #=> true
 *     C.method_defined? "method2"           #=> false
 */

static VALUE
rb_mod_private_method_defined(mod, mid)
    VALUE mod, mid;
{
    ID id = rb_to_id(mid);
    int noex;

    if (rb_get_method_body(&mod, &id, &noex)) {
        if (VISI_CHECK(noex, NOEX_PRIVATE))
            return Qtrue;
    }
    return Qfalse;
}

/*
 *  call-seq:
 *     mod.protected_method_defined?(symbol)   => true or false
 *
 *  Returns +true+ if the named protected method is defined
 *  by _mod_ (or its included modules and, if _mod_ is a
 *  class, its ancestors).
 *
 *     module A
 *       def method1()  end
 *     end
 *     class B
 *       protected
 *       def method2()  end
 *     end
 *     class C < B
 *       include A
 *       def method3()  end
 *     end
 *
 *     A.method_defined? :method1              #=> true
 *     C.protected_method_defined? "method1"   #=> false
 *     C.protected_method_defined? "method2"   #=> true
 *     C.method_defined? "method2"             #=> true
 */

static VALUE
rb_mod_protected_method_defined(mod, mid)
    VALUE mod, mid;
{
    ID id = rb_to_id(mid);
    int noex;

    if (rb_get_method_body(&mod, &id, &noex)) {
        if (VISI_CHECK(noex, NOEX_PROTECTED))
            return Qtrue;
    }
    return Qfalse;
}

NORETURN(static VALUE terminate_process _((int, VALUE)));
static VALUE
terminate_process(status, mesg)
    int status;
    VALUE mesg;
{
    VALUE args[2];
    args[0] = INT2NUM(status);
    args[1] = mesg;

    rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
}

void
rb_exit(status)
    int status;
{
    if (prot_tag) {
        terminate_process(status, rb_str_new("exit", 4));
    }
    ruby_finalize();
    exit(status);
}


/*
 *  call-seq:
 *     exit(integer=0)
 *     Kernel::exit(integer=0)
 *     Process::exit(integer=0)
 *
 *  Initiates the termination of the Ruby script by raising the
 *  SystemExit exception. This exception may be caught. The
 *  optional parameter is used to return a status code to the invoking
 *  environment.
 *
 *     begin
 *       exit
 *       puts "never get here"
 *     rescue SystemExit
 *       puts "rescued a SystemExit exception"
 *     end
 *     puts "after begin block"
 *
 *  produces:
 *
 *     rescued a SystemExit exception
 *     after begin block
 *
 *  Just prior to termination, Ruby executes any at_exit functions
 *  (see Kernel::at_exit) and runs any object finalizers (see
 *  ObjectSpace::define_finalizer).
 *
 *     at_exit { puts "at_exit function" }
 *     ObjectSpace.define_finalizer("string",  proc { puts "in finalizer" })
 *     exit
 *
 *  produces:
 *
 *     at_exit function
 *     in finalizer
 */

VALUE
rb_f_exit(argc, argv)
    int argc;
    VALUE *argv;
{
    VALUE status;
    int istatus;

    rb_secure(4);
    if (rb_scan_args(argc, argv, "01", &status) == 1) {
        switch (status) {
          case Qtrue:
            istatus = EXIT_SUCCESS;
            break;
          case Qfalse:
            istatus = EXIT_FAILURE;
            break;
          default:
            istatus = NUM2INT(status);
#if EXIT_SUCCESS != 0
            if (istatus == 0) istatus = EXIT_SUCCESS;
#endif
            break;
        }
    }
    else {
        istatus = EXIT_SUCCESS;
    }
    rb_exit(istatus);
    return Qnil;                /* not reached */
}


/*
 *  call-seq:
 *     abort
 *     Kernel::abort
 *     Process::abort
 *
 *  Terminate execution immediately, effectively by calling
 *  Kernel.exit(1). If _msg_ is given, it is written
 *  to STDERR prior to terminating.
 */

VALUE
rb_f_abort(argc, argv)
    int argc;
    VALUE *argv;
{
    rb_secure(4);
    if (argc == 0) {
        if (!NIL_P(ruby_errinfo)) {
            error_print();
        }
        rb_exit(EXIT_FAILURE);
    }
    else {
        VALUE mesg;

        rb_scan_args(argc, argv, "1", &mesg);
        StringValue(mesg);
        rb_io_puts(1, &mesg, rb_stderr);
        terminate_process(EXIT_FAILURE, mesg);
    }
    return Qnil;                /* not reached */
}

void
rb_iter_break()
{
    break_jump(Qnil);
}

NORETURN(static void rb_longjmp _((volatile int, volatile VALUE)));
static VALUE make_backtrace _((void));

static void
rb_longjmp(tag, mesg)
    volatile int tag;
    volatile VALUE mesg;
{
    VALUE at;
    volatile rb_thread_t th = curr_thread;

    if (rb_thread_set_raised(th)) {
        ruby_errinfo = exception_error;
        JUMP_TAG(TAG_FATAL);
    }
    if (NIL_P(mesg)) mesg = ruby_errinfo;
    if (NIL_P(mesg)) {
        mesg = rb_exc_new(rb_eRuntimeError, 0, 0);
    }

    ruby_set_current_source();
    if (ruby_sourcefile && !NIL_P(mesg)) {
        at = get_backtrace(mesg);
        if (NIL_P(at) && !rb_thread_raised_p(th, RAISED_NOMEMORY)) {
            at = make_backtrace();
            if (OBJ_FROZEN(mesg)) {
                mesg = rb_obj_dup(mesg);
            }
            set_backtrace(mesg, at);
        }
    }
    if (!NIL_P(mesg)) {
        ruby_errinfo = mesg;
    }

    if (RTEST(ruby_debug) && !NIL_P(ruby_errinfo)
        && !rb_obj_is_kind_of(ruby_errinfo, rb_eSystemExit)) {
        VALUE e = ruby_errinfo;
        int status;

        PUSH_TAG(PROT_EMPTY);
        if ((status = EXEC_TAG()) == 0) {
            StringValue(e);
            warn_printf("Exception `%s' at %s:%d - %s\n",
                        rb_obj_classname(ruby_errinfo),
                        ruby_sourcefile, ruby_sourceline,
                        RSTRING(e)->ptr);
        }
        POP_TAG();
        if (status == TAG_FATAL && ruby_errinfo == exception_error) {
            ruby_errinfo = mesg;
        }
        else if (status) {
            rb_thread_reset_raised(th);
            JUMP_TAG(status);
        }
    }

    rb_trap_restore_mask();
    if (tag != TAG_FATAL) {
        EXEC_EVENT_HOOK(RUBY_EVENT_RAISE, ruby_current_node,
                        ruby_frame->self,
                        ruby_frame->last_func,
                        ruby_frame->last_class);
    }
    if (!prot_tag) {
        error_print();
    }
    rb_thread_raised_clear(th);
    JUMP_TAG(tag);
}

void
rb_exc_jump(mesg)
    VALUE mesg;
{
    rb_thread_raised_clear(rb_curr_thread);
    ruby_errinfo = mesg;
    JUMP_TAG(TAG_RAISE);
}

void
rb_exc_raise(mesg)
    VALUE mesg;
{
    mesg = rb_make_exception(1, &mesg);
    rb_longjmp(TAG_RAISE, mesg);
}

void
rb_exc_fatal(mesg)
    VALUE mesg;
{
    mesg = rb_make_exception(1, &mesg);
    rb_longjmp(TAG_FATAL, mesg);
}

void
rb_interrupt()
{
    static const char fmt[1] = {'\0'};
    rb_raise(rb_eInterrupt, fmt);
}

/*
 *  call-seq:
 *     raise
 *     raise(string)
 *     raise(exception [, string [, array]])
 *     fail
 *     fail(string)
 *     fail(exception [, string [, array]])
 *
 *  With no arguments, raises the exception in $! or raises
 *  a RuntimeError if $! is +nil+.
 *  With a single +String+ argument, raises a
 *  +RuntimeError+ with the string as a message. Otherwise,
 *  the first parameter should be the name of an +Exception+
 *  class (or an object that returns an +Exception+ object when sent
 *  an +exception+ message). The optional second parameter sets the
 *  message associated with the exception, and the third parameter is an
 *  array of callback information. Exceptions are caught by the
 *  +rescue+ clause of begin...end blocks.
 *
 *     raise "Failed to create socket"
 *     raise ArgumentError, "No parameters", caller
 */

static VALUE
rb_f_raise(argc, argv)
    int argc;
    VALUE *argv;
{
    rb_raise_jump(rb_make_exception(argc, argv));
    return Qnil;                /* not reached */
}

static VALUE
rb_make_exception(argc, argv)
    int argc;
    VALUE *argv;
{
    VALUE mesg;
    ID exception;
    int n;

    mesg = Qnil;
    switch (argc) {
      case 0:
        mesg = Qnil;
        break;
      case 1:
        if (NIL_P(argv[0])) break;
        if (TYPE(argv[0]) == T_STRING) {
            mesg = rb_exc_new3(rb_eRuntimeError, argv[0]);
            break;
        }
        n = 0;
        goto exception_call;

      case 2:
      case 3:
        n = 1;
      exception_call:
        exception = rb_intern("exception");
        if (!rb_respond_to(argv[0], exception)) {
            rb_raise(rb_eTypeError, "exception class/object expected");
        }
        mesg = rb_funcall(argv[0], exception, n, argv[1]);
        break;
      default:
        rb_raise(rb_eArgError, "wrong number of arguments");
        break;
    }
    if (argc > 0) {
        if (!rb_obj_is_kind_of(mesg, rb_eException))
            rb_raise(rb_eTypeError, "exception object expected");
        if (argc>2)
            set_backtrace(mesg, argv[2]);
    }

    return mesg;
}

static void
rb_raise_jump(mesg)
    VALUE mesg;
{
    if (ruby_frame != top_frame) {
        PUSH_FRAME();           /* fake frame */
        *ruby_frame = *_frame.prev->prev;
        rb_longjmp(TAG_RAISE, mesg);
        POP_FRAME();
    }
    rb_longjmp(TAG_RAISE, mesg);
}

void
rb_jump_tag(tag)
    int tag;
{
    JUMP_TAG(tag);
}

int
rb_block_given_p()
{
    if (ruby_frame->iter == ITER_CUR && ruby_block)
        return Qtrue;
    return Qfalse;
}

int
rb_iterator_p()
{
    return rb_block_given_p();
}

/*
 *  call-seq:
 *     block_given?   => true or false
 *     iterator?      => true or false
 *
 *  Returns true if yield would execute a
 *  block in the current context. The iterator? form
 *  is mildly deprecated.
 *
 *     def try
 *       if block_given?
 *         yield
 *       else
 *         "no block"
 *       end
 *     end
 *     try                  #=> "no block"
 *     try { "hello" }      #=> "hello"
 *     try do "hello" end   #=> "hello"
 */


static VALUE
rb_f_block_given_p()
{
    if (ruby_frame->prev && ruby_frame->prev->iter == ITER_CUR && ruby_block)
        return Qtrue;
    return Qfalse;
}

VALUE rb_eThreadError;

NORETURN(static void proc_jump_error(int, VALUE));
static void
proc_jump_error(state, result)
    int state;
    VALUE result;
{
    char mesg[32];
    const char *statement;

    switch (state) {
      case TAG_BREAK:
        statement = "break"; break;
      case TAG_RETURN:
        statement = "return"; break;
      case TAG_RETRY:
        statement = "retry"; break;
      default:
        statement = "local-jump"; break; /* should not happen */
    }
    snprintf(mesg, sizeof mesg, "%s from proc-closure", statement);
    localjump_error(mesg, result, state);
}

static void
return_jump(retval)
    VALUE retval;
{
    struct tag *tt = prot_tag;
    int yield = Qfalse;

    if (retval == Qundef) retval = Qnil;
    while (tt) {
        if (tt->tag == PROT_YIELD) {
            yield = Qtrue;
            tt = tt->prev;
        }
        if (tt->tag == PROT_FUNC && tt->frame->uniq == ruby_frame->uniq) {
            tt->dst = (VALUE)ruby_frame->uniq;
            tt->retval = retval;
            JUMP_TAG(TAG_RETURN);
        }
        if (tt->tag == PROT_LAMBDA && !yield) {
            tt->dst = (VALUE)tt->frame->uniq;
            tt->retval = retval;
            JUMP_TAG(TAG_RETURN);
        }
        if (tt->tag == PROT_THREAD) {
            rb_raise(rb_eThreadError, "return can't jump across threads");
        }
        tt = tt->prev;
    }
    localjump_error("unexpected return", retval, TAG_RETURN);
}

static void
break_jump(retval)
    VALUE retval;
{
    struct tag *tt = prot_tag;

    if (retval == Qundef) retval = Qnil;
    while (tt) {
        switch (tt->tag) {
          case PROT_THREAD:
          case PROT_YIELD:
          case PROT_LOOP:
          case PROT_LAMBDA:
            tt->dst = (VALUE)tt->frame->uniq;
            tt->retval = retval;
            JUMP_TAG(TAG_BREAK);
            break;
          case PROT_FUNC:
            tt = 0;
            continue;
          default:
            break;
        }
        tt = tt->prev;
    }
    localjump_error("unexpected break", retval, TAG_BREAK);
}

static void
next_jump(retval)
    VALUE retval;
{
    struct tag *tt = prot_tag;

    if (retval == Qundef) retval = Qnil;
    while (tt) {
        switch (tt->tag) {
          case PROT_THREAD:
          case PROT_YIELD:
          case PROT_LOOP:
          case PROT_LAMBDA:
          case PROT_FUNC:
            tt->dst = (VALUE)tt->frame->uniq;
            tt->retval = retval;
            JUMP_TAG(TAG_NEXT);
            break;
          default:
            break;
        }
        tt = tt->prev;
    }
    localjump_error("unexpected next", retval, TAG_NEXT);
}

void
rb_need_block()
{
    if (!rb_block_given_p()) {
        localjump_error("no block given", Qnil, 0);
    }
}

static VALUE
rb_yield_0(val, self, klass, flags, avalue)
    volatile VALUE val, self;
    VALUE klass;
    int flags;
    volatile int avalue;
{
    NODE *var, *volatile node;
    volatile VALUE result = Qnil;
    volatile VALUE old_cref;
    volatile VALUE old_wrapper;
    struct BLOCK * volatile block;
    struct SCOPE * volatile old_scope;
    volatile int old_vmode;
    struct FRAME frame;
    NODE *cnode = ruby_current_node;
    volatile int lambda = flags & YIELD_LAMBDA_CALL;
    int state;

    rb_need_block();

    PUSH_VARS();
    block = ruby_block;
    frame = block->frame;
    frame.prev = ruby_frame;
    frame.node = cnode;
    CREATE_FRAME_SOURCE_POS(&frame);
    ruby_frame = &(frame);
    old_cref = (VALUE)ruby_cref;
    ruby_cref = block->cref;
    old_wrapper = ruby_wrapper;
    ruby_wrapper = block->wrapper;
    old_scope = ruby_scope;
    ruby_scope = block->scope;
    old_vmode = scope_vmode;
    scope_vmode = (flags & YIELD_PUBLIC_DEF) ? SCOPE_PUBLIC : block->vmode;
    ruby_block = block->prev;
    if (block->flags & BLOCK_D_SCOPE) {
        /* put place holder for dynamic (in-block) local variables */
        ruby_dyna_vars = new_dvar(0, 0, block->dyna_vars);
    }
    else {
        /* FOR does not introduce new scope */
        ruby_dyna_vars = block->dyna_vars;
    }
    PUSH_CLASS(klass ? klass : block->klass);
    if (!klass) {
        self = block->self;
    }
    node = block->body;
    var = block->var;

    if (var) {
        PUSH_TAG(PROT_EMPTY);
        if ((state = EXEC_TAG()) == 0) {
            NODE *bvar = NULL;
          block_var:
            if (var == (NODE*)1) { /* no parameter || */
                if (lambda && RARRAY(val)->len != 0) {
                    rb_raise(rb_eArgError, "wrong number of arguments (%ld for 0)",
                             RARRAY(val)->len);
                }
            }
            else if (var == (NODE*)2) {
                if (TYPE(val) == T_ARRAY && RARRAY(val)->len != 0) {
                    rb_raise(rb_eArgError, "wrong number of arguments (%ld for 0)",
                             RARRAY(val)->len);
                }
            }
            else if (!bvar && nd_type(var) == NODE_BLOCK_PASS) {
                bvar = var->nd_body;
                var = var->nd_args;
                goto block_var;
            }
            else if (nd_type(var) == NODE_MASGN) {
                if (!avalue) {
                    val = svalue_to_mrhs(val, var->nd_head);
                }
                massign(self, var, val, lambda);
            }
            else {
                int len = 0;
                if (avalue) {
                    len = RARRAY(val)->len;
                    if (len == 0) {
                        goto zero_arg;
                    }
                    if (len == 1) {
                        val = RARRAY(val)->ptr[0];
                    }
                    else {
                        goto multi_values;
                    }
                }
                else if (val == Qundef) {
                  zero_arg:
                    val = Qnil;
                  multi_values:
                    {
                        ruby_current_node = var;
                        rb_warn("multiple values for a block parameter (%d for 1)\n\tfrom %s:%d",
                                len, cnode->nd_file, nd_line(cnode));
                        ruby_current_node = cnode;
                    }
                }
                assign(self, var, val, lambda);
            }
            if (bvar) {
                VALUE blk;
                if (flags & YIELD_PROC_CALL)
                    blk = block->block_obj;
                else
                    blk = rb_block_proc();
                assign(self, bvar, blk, 0);
            }
        }
        POP_TAG();
        if (state) goto pop_state;
    }
    if (!node) {
        state = 0;
        goto pop_state;
    }
    ruby_current_node = node;

    PUSH_ITER(block->iter);
    PUSH_TAG(lambda ? PROT_EMPTY : PROT_YIELD);
    switch (state = EXEC_TAG()) {
      case TAG_REDO:
        state = 0;
        CHECK_INTS;
      case 0:
        if (nd_type(node) == NODE_CFUNC || nd_type(node) == NODE_IFUNC) {
          switch (node->nd_state) {
            case YIELD_FUNC_LAMBDA:
              if (!avalue) {
                  val = (val == Qundef) ? rb_ary_new2(0) : rb_ary_new3(1, val);
              }
              break;
            case YIELD_FUNC_AVALUE:
              if (!avalue) {
                  val = svalue_to_avalue(val);
              }
              break;
            default:
              if (avalue) {
                  val = avalue_to_svalue(val);
              }
              if (val == Qundef && node->nd_state != YIELD_FUNC_SVALUE)
                  val = Qnil;
            }
            result = (*node->nd_cfnc)(val, node->nd_tval, self);
         }else
            result = rb_eval(self, node);
          break;
        case TAG_NEXT:
          if (!lambda) {
              state = 0;
              result = prot_tag->retval;
          }
          break;
        case TAG_BREAK:
          if (TAG_DST()) {
              result = prot_tag->retval;
          }
          else {
              lambda = Qtrue;   /* just pass TAG_BREAK */
          }
        default:
          break;
    }
    POP_TAG();
    POP_ITER();
  pop_state:
    POP_CLASS();
    if (ruby_dyna_vars && (block->flags & BLOCK_D_SCOPE) &&
        !FL_TEST(ruby_dyna_vars, DVAR_DONT_RECYCLE)) {
        struct RVarmap *vars = ruby_dyna_vars;

        if (ruby_dyna_vars->id == 0) {
            vars = ruby_dyna_vars->next;
            rb_gc_force_recycle((VALUE)ruby_dyna_vars);
            while (vars && vars->id != 0 && vars != block->dyna_vars) {
                struct RVarmap *tmp = vars->next;
                rb_gc_force_recycle((VALUE)vars);
                vars = tmp;
            }
        }
    }
    POP_VARS();
    ruby_block = block;
    ruby_frame = ruby_frame->prev;
    ruby_cref = (NODE*)old_cref;
    ruby_wrapper = old_wrapper;
    if (ruby_scope->flags & SCOPE_DONT_RECYCLE)
        scope_dup(old_scope);
    ruby_scope = old_scope;
    scope_vmode = old_vmode;
    switch (state) {
      case 0:
        break;
      case TAG_BREAK:
        if (!lambda) {
            struct tag *tt = prot_tag;

            while (tt) {
                if (tt->tag == PROT_LOOP && tt->blkid == ruby_block->uniq) {
                    tt->dst = (VALUE)tt->frame->uniq;
                    tt->retval = result;
                    JUMP_TAG(TAG_BREAK);
                }
                tt = tt->prev;
            }
            proc_jump_error(TAG_BREAK, result);
        }
        /* fall through */
      default:
        JUMP_TAG(state);
        break;
    }
    ruby_current_node = cnode;
    return result;
}

VALUE
rb_yield(val)
    VALUE val;
{
    wipeBeforeYield();
    return rb_yield_0(val, 0, 0, 0, Qfalse);
}

VALUE
#ifdef HAVE_STDARG_PROTOTYPES
rb_yield_values(int n, ...)
#else
rb_yield_values(n, va_alist)
    int n;
    va_dcl
#endif
{
    va_list args;
    VALUE ary;

    if (n == 0) {
        return rb_yield_0(Qundef, 0, 0, 0, Qfalse);
    }
    ary = rb_ary_new2(n);
    va_init_list(args, n);
    while (n--) {
        rb_ary_push(ary, va_arg(args, VALUE));
    }
    va_end(args);
    return rb_yield_0(ary, 0, 0, 0, Qtrue);
}

VALUE
rb_yield_splat(values)
    VALUE values;
{
    int avalue = Qfalse;

    if (TYPE(values) == T_ARRAY) {
        if (RARRAY(values)->len == 0) {
            values = Qundef;
        }
        else {
            avalue = Qtrue;
        }
    }
    return rb_yield_0(values, 0, 0, 0, avalue);
}

static VALUE
loop_i()
{
    for (;;) {
        wipeBeforeYield();
        rb_yield_0(Qundef, 0, 0, 0, Qfalse);
        CHECK_INTS;
    }
    return Qnil;
}

/*
 *  call-seq:
 *     loop {|| block }
 *
 *  Repeatedly executes the block.
 *
 *     loop do
 *       print "Input: "
 *       line = gets
 *       break if !line or line =~ /^qQ/
 *       # ...
 *     end
 *
 *  StopIteration raised in the block breaks the loop.
 */

static VALUE
rb_f_loop()
{
    rb_rescue2(loop_i, (VALUE)0, 0, 0, rb_eStopIteration, (VALUE)0);
    return Qnil;                /* dummy */
}

static VALUE
massign(self, node, val, pcall)
    VALUE self;
    NODE *node;
    VALUE val;
    int pcall;
{
    NODE *list;
    long i = 0, len;

    len = RARRAY(val)->len;
    list = node->nd_head;
    for (; list && ind_head, RARRAY(val)->ptr[i], pcall);
        list = list->nd_next;
    }
    if (pcall && list) goto arg_error;
    if (node->nd_args) {
        if ((long)(node->nd_args) == -1) {
            /* no check for mere `*' */
        }
        else if (!list && ind_args, rb_ary_new4(len-i, RARRAY(val)->ptr+i), pcall);
        }
        else {
            assign(self, node->nd_args, rb_ary_new2(0), pcall);
        }
    }
    else if (pcall && i < len) {
        goto arg_error;
    }

    while (list) {
        i++;
        assign(self, list->nd_head, Qnil, pcall);
        list = list->nd_next;
    }
    return val;

  arg_error:
    while (list) {
        i++;
        list = list->nd_next;
    }
    rb_raise(rb_eArgError, "wrong number of arguments (%ld for %ld)", len, i);
}

static void
assign(self, lhs, val, pcall)
    VALUE self;
    NODE *lhs;
    VALUE val;
    int pcall;
{
    ruby_current_node = lhs;
    if (val == Qundef) {
        rb_warning("assigning void value");
        val = Qnil;
    }
    switch (nd_type(lhs)) {
      case NODE_GASGN:
        ruby_in_longlife_context++;
        rb_gvar_set(lhs->nd_entry, val);
        ruby_in_longlife_context--;
        break;

      case NODE_IASGN:
        rb_ivar_set(self, lhs->nd_vid, val);
        break;

      case NODE_LASGN:
        if (ruby_scope->local_vars == 0)
            rb_bug("unexpected local variable assignment");
        ruby_scope->local_vars[lhs->nd_cnt] = val;
        break;

      case NODE_DASGN:
        dvar_asgn(lhs->nd_vid, val);
        break;

      case NODE_DASGN_CURR:
        dvar_asgn_curr(lhs->nd_vid, val);
        break;

      case NODE_CDECL:
        ruby_in_longlife_context++;
        if (lhs->nd_vid == 0) {
            rb_const_set(class_prefix(self, lhs->nd_else), lhs->nd_else->nd_mid, val);
        }
        else {
            rb_const_set(ruby_cbase, lhs->nd_vid, val);
        }
        ruby_in_longlife_context--;
        break;

      case NODE_CVDECL:
        ruby_in_longlife_context++;
        if (RTEST(ruby_verbose) && FL_TEST(ruby_cbase, FL_SINGLETON)) {
            rb_warn("declaring singleton class variable");
        }
        rb_cvar_set(cvar_cbase(), lhs->nd_vid, val, Qtrue);
        ruby_in_longlife_context--;
        break;

      case NODE_CVASGN:
        ruby_in_longlife_context++;
        rb_cvar_set(cvar_cbase(), lhs->nd_vid, val, Qfalse);
        ruby_in_longlife_context--;
        break;

      case NODE_MASGN:
        ruby_in_longlife_context++;
        massign(self, lhs, svalue_to_mrhs(val, lhs->nd_head), pcall);
        ruby_in_longlife_context--;
        break;

      case NODE_CALL:
      case NODE_ATTRASGN:
        {
            VALUE recv;
            int scope;
            if (lhs->nd_recv == (NODE *)1) {
                recv = self;
                scope = 1;
            }
            else {
                recv = rb_eval(self, lhs->nd_recv);
                scope = 0;
            }
            if (!lhs->nd_args) {
                /* attr set */
                ruby_current_node = lhs;
                GC_DEBUG_SET_SOURCE
                rb_call(CLASS_OF(recv), recv, lhs->nd_mid, 1, &val, scope, self);
            }
            else {
                /* array set */
                VALUE args;

                args = rb_eval(self, lhs->nd_args);
                rb_ary_push(args, val);
                ruby_current_node = lhs;
                GC_DEBUG_SET_SOURCE
                rb_call(CLASS_OF(recv), recv, lhs->nd_mid,
                        RARRAY(args)->len, RARRAY(args)->ptr, scope, self);
            }
        }
        break;

      default:
        rb_bug("bug in variable assignment");
        break;
    }
}

VALUE
rb_iterate(it_proc, data1, bl_proc, data2)
    VALUE (* volatile it_proc) _((VALUE)), (*bl_proc)(ANYARGS);
    volatile VALUE data1;
    VALUE data2;
{
    int state;
    VALUE retval;
    NODE *node = NEW_IFUNC(bl_proc, data2);
    VALUE self = ruby_top_self;

    PUSH_TAG(PROT_LOOP);
    PUSH_BLOCK(0, node);
    PUSH_ITER(ITER_PRE);
    state = EXEC_TAG();
    if (state == 0) {
  iter_retry:
        retval = (*it_proc)(data1);
    }
    else if (state == TAG_BREAK && TAG_DST()) {
        retval = prot_tag->retval;
        state = 0;
    }
    else if (state == TAG_RETRY) {
        state = 0;
        goto iter_retry;
    }
    POP_ITER();
    POP_BLOCK();
    POP_TAG();

    if (state) JUMP_TAG(state);
    return retval;
}

static int
handle_rescue(self, node)
    VALUE self;
    NODE *node;
{
    int argc; VALUE *argv; /* used in SETUP_ARGS */
    TMP_PROTECT;

    if (!node->nd_args) {
        return rb_obj_is_kind_of(ruby_errinfo, rb_eStandardError);
    }

    BEGIN_CALLARGS;
    SETUP_ARGS(node->nd_args);
    END_CALLARGS;

    while (argc--) {
        if (!rb_obj_is_kind_of(argv[0], rb_cModule)) {
            rb_raise(rb_eTypeError, "class or module required for rescue clause");
        }
        if (RTEST(rb_funcall(*argv, eqq, 1, ruby_errinfo))) return 1;
        argv++;
    }
    return 0;
}

VALUE
#ifdef HAVE_STDARG_PROTOTYPES
rb_rescue2(VALUE (* volatile b_proc)(ANYARGS), volatile VALUE data1,
           VALUE (* volatile r_proc)(ANYARGS), volatile VALUE data2, ...)
#else
rb_rescue2(b_proc, data1, r_proc, data2, va_alist)
    VALUE (* volatile b_proc)(ANYARGS), (* volatile r_proc)(ANYARGS);
    volatile VALUE data1, data2;
    va_dcl
#endif
{
    int state;
    VALUE result;
    volatile VALUE e_info = ruby_errinfo;
    volatile int handle = Qfalse;
    VALUE eclass;
    va_list args;

    PUSH_TAG(PROT_EMPTY);
    switch (state = EXEC_TAG()) {
      case TAG_RETRY:
        if (!handle) break;
        handle = Qfalse;
        state = 0;
        ruby_errinfo = Qnil;
      case 0:
        result = (*b_proc)(data1);
        break;
      case TAG_RAISE:
        if (handle) break;
        handle = Qfalse;
        va_init_list(args, data2);
        while ((eclass = va_arg(args, VALUE)) != 0) {
            if (rb_obj_is_kind_of(ruby_errinfo, eclass)) {
                handle = Qtrue;
                break;
            }
        }
        va_end(args);

        if (handle) {
            state = 0;
            if (r_proc) {
                result = (*r_proc)(data2, ruby_errinfo);
            }
            else {
                result = Qnil;
            }
            ruby_errinfo = e_info;
        }
    }
    POP_TAG();
    if (state) JUMP_TAG(state);

    return result;
}

VALUE
rb_rescue(b_proc, data1, r_proc, data2)
    VALUE (*b_proc)(), (*r_proc)();
    VALUE data1, data2;
{
    return rb_rescue2(b_proc, data1, r_proc, data2, rb_eStandardError, (VALUE)0);
}

static VALUE cont_protect;

VALUE
rb_protect(proc, data, state)
    VALUE (*proc) _((VALUE));
    VALUE data;
    int * volatile state;
{
    VALUE result;
    int status;

    PUSH_TAG(PROT_EMPTY);
    cont_protect = (VALUE)NEW_NODE_EDEN(NODE_MEMO, cont_protect, 0, 0);
    if ((status = EXEC_TAG()) == 0) {
        result = (*proc)(data);
    }
    cont_protect = ((NODE *)cont_protect)->u1.value;
    POP_TAG();
    if (state) {
        *state = status;
    }
    return status ? Qnil : result;
}

VALUE
rb_ensure(b_proc, data1, e_proc, data2)
    VALUE (*b_proc)();
    VALUE data1;
    VALUE (* volatile e_proc)();
    volatile VALUE data2;
{
    int state;
    VALUE result;
    VALUE retval;

    PUSH_TAG(PROT_EMPTY);
    if ((state = EXEC_TAG()) == 0) {
        result = (*b_proc)(data1);
    }
    POP_TAG();
    if (prot_tag) retval = prot_tag->retval;  /* save retval */
    if (!thread_no_ensure()) {
        (*e_proc)(data2);
    }
    if (prot_tag) return_value(retval);
    if (state) JUMP_TAG(state);
    return result;
}

VALUE
rb_with_disable_interrupt(proc, data)
    VALUE (*proc)();
    VALUE data;
{
    VALUE result;
    int status;

    DEFER_INTS;
    {
        int thr_critical = rb_thread_critical;

        rb_thread_critical = Qtrue;
        PUSH_TAG(PROT_EMPTY);
        if ((status = EXEC_TAG()) == 0) {
            result = (*proc)(data);
        }
        POP_TAG();
        rb_thread_critical = thr_critical;
    }
    ENABLE_INTS;
    if (status) JUMP_TAG(status);

    return result;
}

static void
stack_check()
{
    rb_thread_t th = rb_curr_thread;

    if (!rb_thread_raised_p(th, RAISED_STACKOVERFLOW) && ruby_stack_check()) {
        rb_thread_raised_set(th, RAISED_STACKOVERFLOW);
        rb_exc_raise(sysstack_error);
    }
}

static void
eval_check_tick()
{
    static int tick;
    if ((++tick & 0xff) == 0) {
        CHECK_INTS;             /* better than nothing */
        stack_check();
    }
}

static int last_call_status;

#define CSTAT_PRIV  1
#define CSTAT_PROT  2
#define CSTAT_VCALL 4
#define CSTAT_SUPER 8

/*
 *  call-seq:
 *     obj.method_missing(symbol [, *args] )   => result
 *
 *  Invoked by Ruby when obj is sent a message it cannot handle.
 *  symbol is the symbol for the method called, and args
 *  are any arguments that were passed to it. By default, the interpreter
 *  raises an error when this method is called. However, it is possible
 *  to override the method to provide more dynamic behavior.
 *  The example below creates
 *  a class Roman, which responds to methods with names
 *  consisting of roman numerals, returning the corresponding integer
 *  values.
 *
 *     class Roman
 *       def romanToInt(str)
 *         # ...
 *       end
 *       def method_missing(methId)
 *         str = methId.id2name
 *         romanToInt(str)
 *       end
 *     end
 *
 *     r = Roman.new
 *     r.iv      #=> 4
 *     r.xxiii   #=> 23
 *     r.mm      #=> 2000
 */

static VALUE
rb_method_missing(argc, argv, obj)
    int argc;
    VALUE *argv;
    VALUE obj;
{
    ID id;
    VALUE exc = rb_eNoMethodError;
    const char *format = 0;
    NODE *cnode = ruby_current_node;

    if (argc == 0 || !SYMBOL_P(argv[0])) {
        rb_raise(rb_eArgError, "no id given");
    }

    stack_check();

    id = SYM2ID(argv[0]);

    if (last_call_status & CSTAT_PRIV) {
        format = "private method `%s' called for %s";
    }
    else if (last_call_status & CSTAT_PROT) {
        format = "protected method `%s' called for %s";
    }
    else if (last_call_status & CSTAT_VCALL) {
        format = "undefined local variable or method `%s' for %s";
        exc = rb_eNameError;
    }
    else if (last_call_status & CSTAT_SUPER) {
        format = "super: no superclass method `%s' for %s";
    }
    if (!format) {
        format = "undefined method `%s' for %s";
    }

    ruby_current_node = cnode;
    {
        int n = 0;
        VALUE args[3];

        args[n++] = rb_funcall(rb_const_get(exc, rb_intern("message")), '!',
                               3, rb_str_new2(format), obj, argv[0]);
        args[n++] = argv[0];
        if (exc == rb_eNoMethodError) {
            args[n++] = rb_ary_new4(argc-1, argv+1);
        }
        exc = rb_class_new_instance(n, args, exc);
        ruby_frame = ruby_frame->prev; /* pop frame for "method_missing" */
        rb_exc_raise(exc);
    }

    return Qnil;                /* not reached */
}

static VALUE
method_missing(obj, id, argc, argv, call_status)
    VALUE obj;
    ID    id;
    int   argc;
    const VALUE *argv;
    int   call_status;
{
    VALUE *nargv;

    last_call_status = call_status;

    if (id == missing) {
        PUSH_FRAME();
        rb_method_missing(argc, argv, obj);
        POP_FRAME();
    }
    else if (id == ID_ALLOCATOR) {
        rb_raise(rb_eTypeError, "allocator undefined for %s", rb_class2name(obj));
    }
    if (argc < 0) {
        VALUE tmp;

        argc = -argc-1;
        tmp = splat_value(argv[argc]);
        nargv = ALLOCA_N(VALUE, argc + RARRAY(tmp)->len + 1);
        MEMCPY(nargv+1, argv, VALUE, argc);
        MEMCPY(nargv+1+argc, RARRAY(tmp)->ptr, VALUE, RARRAY(tmp)->len);
        argc += RARRAY(tmp)->len;
    }
    else {
        nargv = ALLOCA_N(VALUE, argc+1);
        MEMCPY(nargv+1, argv, VALUE, argc);
    }
    nargv[0] = ID2SYM(id);
    return rb_funcall2(obj, missing, argc+1, nargv);
}

static inline VALUE
call_cfunc(func, recv, len, argc, argv)
    VALUE (*func)();
    VALUE recv;
    int len, argc;
    VALUE *argv;
{
    if (len >= 0 && argc != len) {
        rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
                 argc, len);
    }

    switch (len) {
      case -2:
        return (*func)(recv, rb_ary_new4(argc, argv));
        break;
      case -1:
        return (*func)(argc, argv, recv);
        break;
      case 0:
        return (*func)(recv);
        break;
      case 1:
        return (*func)(recv, argv[0]);
        break;
      case 2:
        return (*func)(recv, argv[0], argv[1]);
        break;
      case 3:
        return (*func)(recv, argv[0], argv[1], argv[2]);
        break;
      case 4:
        return (*func)(recv, argv[0], argv[1], argv[2], argv[3]);
        break;
      case 5:
        return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
        break;
      case 6:
        return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
                       argv[5]);
        break;
      case 7:
        return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
                       argv[5], argv[6]);
        break;
      case 8:
        return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
                       argv[5], argv[6], argv[7]);
        break;
      case 9:
        return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
                       argv[5], argv[6], argv[7], argv[8]);
        break;
      case 10:
        return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
                       argv[5], argv[6], argv[7], argv[8], argv[9]);
        break;
      case 11:
        return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
                       argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]);
        break;
      case 12:
        return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
                       argv[5], argv[6], argv[7], argv[8], argv[9],
                       argv[10], argv[11]);
        break;
      case 13:
        return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
                       argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
                       argv[11], argv[12]);
        break;
      case 14:
        return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
                       argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
                       argv[11], argv[12], argv[13]);
        break;
      case 15:
        return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4],
                       argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
                       argv[11], argv[12], argv[13], argv[14]);
        break;
      default:
        rb_raise(rb_eArgError, "too many arguments (%d)", len);
        break;
    }
    return Qnil;                /* not reached */
}

static VALUE
rb_call0(klass, recv, id, oid, argc, argv, body, flags)
    volatile VALUE klass, recv;
    volatile ID    id;
    ID    oid;
    int argc;
    VALUE *argv;
    NODE *body;
    int flags;
{
    NODE *b2;           /* OK */
    VALUE result;
    int itr;
    TMP_PROTECT;
    volatile int safe = -1;

    if (NOEX_SAFE(flags) > ruby_safe_level && NOEX_SAFE(flags) > 2) {
        rb_raise(rb_eSecurityError, "calling insecure method: %s",
                 rb_id2name(id));
    }
    switch (ruby_iter->iter) {
      case ITER_PRE:
      case ITER_PAS:
        itr = ITER_CUR;
        break;
      case ITER_CUR:
      default:
        itr = ITER_NOT;
        break;
    }

    eval_check_tick();
    if (argc < 0) {
        VALUE tmp;
        VALUE *nargv;

        argc = -argc-1;
        tmp = splat_value(argv[argc]);
        nargv = TMP_ALLOC(argc + RARRAY(tmp)->len);
        MEMCPY(nargv, argv, VALUE, argc);
        MEMCPY(nargv+argc, RARRAY(tmp)->ptr, VALUE, RARRAY(tmp)->len);
        argc += RARRAY(tmp)->len;
        argv = nargv;
    }
    PUSH_ITER(itr);
    PUSH_FRAME();

    ruby_frame->last_func = id;
    ruby_frame->orig_func = oid;
    ruby_frame->last_class = (flags & NOEX_NOSUPER)?0:klass;
    ruby_frame->self = recv;
    ruby_frame->argc = argc;
    ruby_frame->flags = 0;

    switch (nd_type(body)) {
      case NODE_CFUNC:
        {
            int len = body->nd_argc;

            if (len < -2) {
                rb_bug("bad argc (%d) specified for `%s(%s)'",
                       len, rb_class2name(klass), rb_id2name(id));
            }
            if (event_hooks) {
                int state;

                EXEC_EVENT_HOOK(RUBY_EVENT_C_CALL, ruby_current_node,
                                recv, id, klass);
                PUSH_TAG(PROT_FUNC);
                if ((state = EXEC_TAG()) == 0) {
                    result = call_cfunc(body->nd_cfnc, recv, len, argc, argv);
                }
                POP_TAG();
                ruby_current_node = ruby_frame->node;
                EXEC_EVENT_HOOK(RUBY_EVENT_C_RETURN, ruby_current_node,
                                recv, id, klass);
                if (state) JUMP_TAG(state);
            }
            else {
                result = call_cfunc(body->nd_cfnc, recv, len, argc, argv);
            }
        }
        break;

        /* for attr get/set */
      case NODE_IVAR:
        if (argc != 0) {
            rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
        }
        result = rb_attr_get(recv, body->nd_vid);
        break;

      case NODE_ATTRSET:
        if (argc != 1)
            rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc);
        result = rb_ivar_set(recv, body->nd_vid, argv[0]);
        break;

      case NODE_ZSUPER:
        result = rb_call_super(argc, argv);
        break;

      case NODE_DMETHOD:
        result = method_call(argc, argv, umethod_bind(body->nd_cval, recv));
        break;

      case NODE_BMETHOD:
        ruby_frame->flags |= FRAME_DMETH;
        if (event_hooks) {
            struct BLOCK *data;
            Data_Get_Struct(body->nd_cval, struct BLOCK, data);
            EXEC_EVENT_HOOK(RUBY_EVENT_CALL, data->body, recv, id, klass);
        }
        result = proc_invoke(body->nd_cval, rb_ary_new4(argc,argv), recv,klass);
        if (event_hooks) {
            EXEC_EVENT_HOOK(RUBY_EVENT_RETURN,
                            ruby_current_node, recv, id, klass);
        }
        break;

      case NODE_SCOPE:
        {
            int state;
            VALUE *local_vars;  /* OK */
            NODE * volatile saved_cref = 0;

            PUSH_SCOPE();
            if (body->nd_rval) {
                saved_cref = ruby_cref;
                ruby_cref = (NODE*)body->nd_rval;
            }
            PUSH_CLASS(ruby_cbase);
            if (body->nd_tbl) {
                local_vars = TMP_ALLOC(body->nd_tbl[0]+1);
                *local_vars++ = (VALUE)body;
                rb_mem_clear(local_vars, body->nd_tbl[0]);
                ruby_scope->local_tbl = body->nd_tbl;
                ruby_scope->local_vars = local_vars;
            }
            else {
                local_vars = ruby_scope->local_vars = 0;
                ruby_scope->local_tbl  = 0;
            }
            b2 = body = body->nd_next;

            if (NOEX_SAFE(flags) > ruby_safe_level) {
                safe = ruby_safe_level;
                ruby_safe_level = NOEX_SAFE(flags);
            }
            PUSH_VARS();
            PUSH_TAG(PROT_FUNC);
            if ((state = EXEC_TAG()) == 0) {
                NODE *node = 0;
                int i, nopt = 0;

                if (nd_type(body) == NODE_ARGS) {
                    node = body;
                    body = 0;
                }
                else if (nd_type(body) == NODE_BLOCK) {
                    node = body->nd_head;
                    body = body->nd_next;
                }
                if (node) {
                    if (nd_type(node) != NODE_ARGS) {
                        rb_bug("no argument-node");
                    }

                    i = node->nd_cnt;
                    if (i > argc) {
                        rb_raise(rb_eArgError,
                                 "wrong number of arguments (%d for %d)",
                                 argc, i);
                    }
                    if (!node->nd_rest) {
                        NODE *optnode = node->nd_opt;

                        nopt = i;
                        while (optnode) {
                            nopt++;
                            optnode = optnode->nd_next;
                        }
                        if (nopt < argc) {
                            rb_raise(rb_eArgError,
                                     "wrong number of arguments (%d for %d)",
                                     argc, nopt);
                        }
                    }
                    if (local_vars) {
                        if (i > 0) {
                            /* +2 for $_ and $~ */
                            MEMCPY(local_vars+2, argv, VALUE, i);
                        }
                    }
                    argv += i; argc -= i;
                    if (node->nd_opt) {
                        NODE *opt = node->nd_opt;

                        while (opt && argc) {
                            assign(recv, opt->nd_head, *argv, 1);
                            argv++; argc--;
                            ++i;
                            opt = opt->nd_next;
                        }
                        if (opt) {
                            rb_eval(recv, opt);
                            while (opt) {
                                opt = opt->nd_next;
                                ++i;
                            }
                        }
                    }
                    if (!node->nd_rest) {
                        i = nopt;
                    }
                    else {
                        VALUE v;

                        if (argc > 0) {
                            v = rb_ary_new4(argc,argv);
                            i = -i - 1;
                        }
                        else {
                            v = rb_ary_new2(0);
                        }
                        assign(recv, node->nd_rest, v, 1);
                    }
                    ruby_frame->argc = i;
                }
                if (event_hooks) {
                    EXEC_EVENT_HOOK(RUBY_EVENT_CALL, b2, recv, id, klass);
                }
                result = rb_eval(recv, body);
            }
            else if (state == TAG_RETURN && TAG_DST()) {
                result = prot_tag->retval;
                state = 0;
            }
            POP_TAG();
            if (event_hooks) {
                EXEC_EVENT_HOOK(RUBY_EVENT_RETURN, ruby_current_node,
                                recv, id, klass);
            }
            POP_VARS();
            POP_CLASS();
            POP_SCOPE();
            ruby_cref = saved_cref;
            if (safe >= 0) ruby_safe_level = safe;
            switch (state) {
              case 0:
                break;

              case TAG_BREAK:
              case TAG_RETURN:
                JUMP_TAG(state);
                break;

              case TAG_RETRY:
                if (rb_block_given_p()) JUMP_TAG(state);
                /* fall through */
              default:
                jump_tag_but_local_jump(state, result);
                break;
            }
        }
        break;

      default:
        unknown_node(body);
    }
    POP_FRAME();
    POP_ITER();
    return result;
}

static VALUE
rb_call(klass, recv, mid, argc, argv, scope, self)
    VALUE klass, recv;
    ID    mid;
    int argc;                   /* OK */
    const VALUE *argv;          /* OK */
    int scope;
    VALUE self;
{
    NODE  *body;                /* OK */
    int    noex;
    ID     id = mid;
    struct cache_entry *ent;

    if (!klass) {
        rb_raise(rb_eNotImpError, "method `%s' called on terminated object (0x%lx)",
                 rb_id2name(mid), recv);
    }
    /* is it in the method cache? */
    ent = cache + EXPR1(klass, mid);
    if (ent->mid == mid && ent->klass == klass) {
        if (!ent->method)
            goto nomethod;
        klass = ent->origin;
        id    = ent->mid0;
        noex  = ent->noex;
        body  = ent->method;
    }
    else if ((body = rb_get_method_body(&klass, &id, &noex)) == 0) {
      nomethod:
        if (scope == 3) {
            return method_missing(recv, mid, argc, argv, CSTAT_SUPER);
        }
        return method_missing(recv, mid, argc, argv, scope==2?CSTAT_VCALL:0);
    }

    if (mid != missing && scope == 0) {
        /* receiver specified form for private method */
        if (noex & NOEX_PRIVATE)
            return method_missing(recv, mid, argc, argv, CSTAT_PRIV);

        /* self must be kind of a specified form for protected method */
        if (noex & NOEX_PROTECTED) {
            VALUE defined_class = klass;

            if (self == Qundef) self = ruby_frame->self;
            if (TYPE(defined_class) == T_ICLASS) {
                defined_class = RBASIC(defined_class)->klass;
            }
            if (!rb_obj_is_kind_of(self, rb_class_real(defined_class)))
                return method_missing(recv, mid, argc, argv, CSTAT_PROT);
        }
    }

    return rb_call0(klass, recv, mid, id, argc, argv, body, noex);
}

VALUE
rb_apply(recv, mid, args)
    VALUE recv;
    ID mid;
    VALUE args;
{
    int argc;
    VALUE *argv;

    argc = RARRAY(args)->len; /* Assigns LONG, but argc is INT */
    argv = ALLOCA_N(VALUE, argc);
    MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc);
    return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1, Qundef);
}

/*
 *  call-seq:
 *     obj.send(symbol [, args...])        => obj
 *     obj.__send__(symbol [, args...])    => obj
 *
 *  Invokes the method identified by _symbol_, passing it any
 *  arguments specified. You can use \_\_send__ if the name
 *  +send+ clashes with an existing method in _obj_.
 *
 *     class Klass
 *       def hello(*args)
 *         "Hello " + args.join(' ')
 *       end
 *     end
 *     k = Klass.new
 *     k.send :hello, "gentle", "readers"   #=> "Hello gentle readers"
 */

static VALUE
rb_f_send(argc, argv, recv)
    int argc;
    VALUE *argv;
    VALUE recv;
{
    VALUE vid;

    if (argc == 0) rb_raise(rb_eArgError, "no method name given");

    vid = *argv++; argc--;
    PUSH_ITER(rb_block_given_p()?ITER_PRE:ITER_NOT);
    vid = rb_call(CLASS_OF(recv), recv, rb_to_id(vid), argc, argv, 1, Qundef);
    POP_ITER();

    return vid;
}

static VALUE
vafuncall(recv, mid, n, ar)
    VALUE recv;
    ID mid;
    int n;
    va_list *ar;
{
    VALUE *argv;

    if (n > 0) {
        long i;

        argv = ALLOCA_N(VALUE, n);

        for (i=0;ilast_class == 0) {
        rb_name_error(ruby_frame->last_func, "calling `super' from `%s' is prohibited",
                      rb_id2name(ruby_frame->orig_func));
    }

    self = ruby_frame->self;
    klass = ruby_frame->last_class;
    if (RCLASS(klass)->super == 0) {
        return method_missing(self, ruby_frame->orig_func, argc, argv, CSTAT_SUPER);
    }

    PUSH_ITER(ruby_iter->iter ? ITER_PRE : ITER_NOT);
    result = rb_call(RCLASS(klass)->super, self, ruby_frame->orig_func, argc, argv, 3, Qundef);
    POP_ITER();

    return result;
}

static VALUE
backtrace(lev)
    int lev;
{
    struct FRAME *frame = ruby_frame;
    char buf[BUFSIZ];
    VALUE ary;
    NODE *n;

    ary = rb_ary_new();
    if (frame->last_func == ID_ALLOCATOR) {
        frame = frame->prev;
    }
    if (lev < 0) {
        ruby_set_current_source();
        if (frame->last_func) {
            snprintf(buf, BUFSIZ, "%s:%d:in `%s'",
                     ruby_sourcefile, ruby_sourceline,
                     rb_id2name(frame->last_func));
        }
        else if (ruby_sourceline == 0) {
            snprintf(buf, BUFSIZ, "%s", ruby_sourcefile);
        }
        else {
            snprintf(buf, BUFSIZ, "%s:%d", ruby_sourcefile, ruby_sourceline);
        }
        rb_ary_push(ary, rb_str_new2(buf));
        if (lev < -1) return ary;
    }
    else {
        while (lev-- > 0) {
            frame = frame->prev;
            if (!frame) {
                ary = Qnil;
                break;
            }
        }
    }
    for (; frame && (n = frame->node); frame = frame->prev) {
        if (frame->prev && frame->prev->last_func) {
            if (frame->prev->node == n) {
                if (frame->prev->last_func == frame->last_func) continue;
            }
            snprintf(buf, BUFSIZ, "%s:%d:in `%s'",
                     n->nd_file, nd_line(n),
                     rb_id2name(frame->prev->last_func));
        }
        else {
            snprintf(buf, BUFSIZ, "%s:%d", n->nd_file, nd_line(n));
        }
        rb_ary_push(ary, rb_str_new2(buf));
    }

    return ary;
}

/*
 *  call-seq:
 *     caller(start=1)    => array
 *
 *  Returns the current execution stack---an array containing strings in
 *  the form ``file:line'' or ``file:line: in
 *  `method'''. The optional _start_ parameter
 *  determines the number of initial stack entries to omit from the
 *  result.
 *
 *     def a(skip)
 *       caller(skip)
 *     end
 *     def b(skip)
 *       a(skip)
 *     end
 *     def c(skip)
 *       b(skip)
 *     end
 *     c(0)   #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10"]
 *     c(1)   #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11"]
 *     c(2)   #=> ["prog:8:in `c'", "prog:12"]
 *     c(3)   #=> ["prog:13"]
 */

static VALUE
rb_f_caller(argc, argv)
    int argc;
    VALUE *argv;
{
    VALUE level;
    int lev;

    rb_scan_args(argc, argv, "01", &level);

    if (NIL_P(level)) lev = 1;
    else lev = NUM2INT(level);
    if (lev < 0) rb_raise(rb_eArgError, "negative level (%d)", lev);

    return backtrace(lev);
}

void
rb_backtrace()
{
    long i;
    VALUE ary;

    ary = backtrace(-1);
    for (i=0; ilen; i++) {
        printf("\tfrom %s\n", RSTRING(RARRAY(ary)->ptr[i])->ptr);
    }
}

static VALUE
make_backtrace()
{
    return backtrace(-1);
}

ID
rb_frame_last_func()
{
    return ruby_frame->last_func;
}

ID
rb_frame_this_func()
{
    return ruby_frame->orig_func;
}

static NODE*
compile(src, file, line)
    VALUE src;
    const char *file;
    int line;
{
    NODE *node;
    int critical;

    ruby_nerrs = 0;
    StringValue(src);
    critical = rb_thread_critical;
    rb_thread_critical = Qtrue;
    node = rb_compile_string(file, src, line);
    rb_thread_critical = critical;

    if (ruby_nerrs == 0) return node;
    return 0;
}

static VALUE
eval(self, src, scope, file, line)
    VALUE self, src;
    volatile VALUE scope;
    const char * volatile file;
    int line;
{
    struct BLOCK *data = NULL;
    VALUE result;
    struct SCOPE * volatile old_scope;
    struct BLOCK * volatile old_block;
    struct RVarmap * volatile old_dyna_vars;
    VALUE volatile old_cref;
    int volatile old_vmode;
    volatile VALUE old_wrapper;
    struct FRAME frame;
    NODE * volatile nodesave = ruby_current_node;
    volatile int iter = ruby_frame->iter;
    volatile int safe = ruby_safe_level;
    int state;

    if (!NIL_P(scope)) {
        if (!rb_obj_is_proc(scope)) {
            rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc/Binding)",
                     rb_obj_classname(scope));
        }

        Data_Get_Struct(scope, struct BLOCK, data);
        /* PUSH BLOCK from data */
        frame = data->frame;
        frame.tmp = ruby_frame; /* gc protection */
        ruby_frame = &(frame);
        old_scope = ruby_scope;
        ruby_scope = data->scope;
        old_block = ruby_block;
        ruby_block = data->prev;
        old_dyna_vars = ruby_dyna_vars;
        ruby_dyna_vars = data->dyna_vars;
        old_vmode = scope_vmode;
        scope_vmode = data->vmode;
        old_cref = (VALUE)ruby_cref;
        ruby_cref = data->cref;
        old_wrapper = ruby_wrapper;
        ruby_wrapper = data->wrapper;
        if ((file == 0 || (line == 1 && strcmp(file, "(eval)") == 0)) && data->frame.node) {
            file = data->frame.node->nd_file;
            if (!file) file = "__builtin__";
            line = nd_line(data->frame.node);
        }

        self = data->self;
        ruby_frame->iter = data->iter;
    }
    else {
        if (ruby_frame->prev) {
            ruby_frame->iter = ruby_frame->prev->iter;
        }
    }
    if (file == 0) {
        ruby_set_current_source();
        file = ruby_sourcefile;
        line = ruby_sourceline;
    }
    PUSH_CLASS(data ? data->klass : ruby_class);
    ruby_in_eval++;
    if (TYPE(ruby_class) == T_ICLASS) {
        ruby_class = RBASIC(ruby_class)->klass;
    }
    SET_GC_DEBUG_SOURCEFUNC("")
    PUSH_TAG(PROT_EMPTY);
    if ((state = EXEC_TAG()) == 0) {
        NODE *node;

        ruby_safe_level = 0;
        result = ruby_errinfo;
        ruby_errinfo = Qnil;
        node = compile(src, file, line);
        ruby_safe_level = safe;
        if (ruby_nerrs > 0) {
            compile_error(0);
        }
        if (!NIL_P(result)) ruby_errinfo = result;
        result = eval_tree(self, node);
    }
    POP_TAG();
    RESET_GC_DEBUG_SOURCEFUNC
    POP_CLASS();
    ruby_in_eval--;
    if (!NIL_P(scope)) {
        int dont_recycle = ruby_scope->flags & SCOPE_DONT_RECYCLE;

        ruby_wrapper = old_wrapper;
        ruby_cref  = (NODE*)old_cref;
        ruby_frame = frame.tmp;
        ruby_scope = old_scope;
        ruby_block = old_block;
        ruby_dyna_vars = old_dyna_vars;
        data->vmode = scope_vmode; /* write back visibility mode */
        scope_vmode = old_vmode;
        if (dont_recycle) {
            struct tag *tag;
            struct RVarmap *vars;

            scope_dup(ruby_scope);
            for (tag=prot_tag; tag; tag=tag->prev) {
                scope_dup(tag->scope);
            }
            for (vars = ruby_dyna_vars; vars; vars = vars->next) {
                FL_SET(vars, DVAR_DONT_RECYCLE);
            }
        }
    }
    else {
        ruby_frame->iter = iter;
    }
    ruby_current_node = nodesave;
    ruby_set_current_source();
    if (state) {
        if (state == TAG_RAISE) {
            if (strcmp(file, "(eval)") == 0) {
                VALUE mesg, errat, bt2;
                ID id_mesg;

                id_mesg = rb_intern("mesg");
                errat = get_backtrace(ruby_errinfo);
                mesg = rb_attr_get(ruby_errinfo, id_mesg);
                if (!NIL_P(errat) && TYPE(errat) == T_ARRAY &&
                    (bt2 = backtrace(-2), RARRAY_LEN(bt2) > 0)) {
                    if (!NIL_P(mesg) && TYPE(mesg) == T_STRING) {
                        if (OBJ_FROZEN(mesg)) {
                            VALUE m = rb_str_cat(rb_str_dup(RARRAY_PTR(errat)[0]), ": ", 2);
                            rb_ivar_set(ruby_errinfo, id_mesg, rb_str_append(m, mesg));
                        }
                        else {
                            rb_str_update(mesg, 0, 0, rb_str_new2(": "));
                            rb_str_update(mesg, 0, 0, RARRAY_PTR(errat)[0]);
                        }
                    }
                    RARRAY_PTR(errat)[0] = RARRAY_PTR(bt2)[0];
                }
            }
            rb_exc_raise(ruby_errinfo);
        }
        JUMP_TAG(state);
    }

    return result;
}

/*
 *  call-seq:
 *     eval(string [, binding [, filename [,lineno]]])  => obj
 *
 *  Evaluates the Ruby expression(s) in string. If
 *  binding is given, the evaluation is performed in its
 *  context. The binding may be a Binding object or a
 *  Proc object. If the optional filename and
 *  lineno parameters are present, they will be used when
 *  reporting syntax errors.
 *
 *     def getBinding(str)
 *       return binding
 *     end
 *     str = "hello"
 *     eval "str + ' Fred'"                      #=> "hello Fred"
 *     eval "str + ' Fred'", getBinding("bye")   #=> "bye Fred"
 */

static VALUE
rb_f_eval(argc, argv, self)
    int argc;
    VALUE *argv;
    VALUE self;
{
    VALUE src, scope, vfile, vline;
    const char *file = NULL;
    int line = 0;

    rb_scan_args(argc, argv, "13", &src, &scope, &vfile, &vline);
    if (ruby_safe_level >= 4) {
        StringValue(src);
        if (!NIL_P(scope) && !OBJ_TAINTED(scope)) {
            rb_raise(rb_eSecurityError, "Insecure: can't modify trusted binding");
        }
    }
    else {
        SafeStringValue(src);
    }
    if (argc >= 3) {
        StringValue(vfile);
    }
    if (argc >= 4) {
        line = NUM2INT(vline);
    }

    if (!NIL_P(vfile)) file = RSTRING(vfile)->ptr;
    if (NIL_P(scope) && ruby_frame->prev) {
        struct FRAME *prev;
        VALUE val;

        prev = ruby_frame;
        PUSH_FRAME();
        *ruby_frame = *prev->prev;
        ruby_frame->prev = prev;
        val = eval(self, src, scope, file, line);
        POP_FRAME();

        return val;
    }
    return eval(self, src, scope, file, line);
}

/* function to call func under the specified class/module context */
static VALUE
exec_under(func, under, cbase, args)
    VALUE (*func)();
    VALUE under;
    volatile VALUE cbase;
    void *args;
{
    VALUE val;
    int state;
    volatile int mode;
    struct FRAME *f = ruby_frame;

    PUSH_CLASS(under);
    PUSH_FRAME();
    ruby_frame->self = f->self;
    ruby_frame->last_func = f->last_func;
    ruby_frame->orig_func = f->orig_func;
    ruby_frame->last_class = f->last_class;
    ruby_frame->argc = f->argc;
    if (cbase) {
        PUSH_CREF(cbase);
    }

    mode = scope_vmode;
    SCOPE_SET(SCOPE_PUBLIC);
    PUSH_TAG(PROT_EMPTY);
    if ((state = EXEC_TAG()) == 0) {
        val = (*func)(args);
    }
    POP_TAG();
    if (cbase) POP_CREF();
    SCOPE_SET(mode);
    POP_FRAME();
    POP_CLASS();
    if (state) JUMP_TAG(state);

    return val;
}

static VALUE
eval_under_i(args)
    VALUE *args;
{
    struct FRAME *f = ruby_frame;

    if (f && (f = f->prev) && (f = f->prev)) {
        ruby_frame = f;
    }
    return eval(args[0], args[1], Qnil, (char*)args[2], (int)args[3]);
}

/* string eval under the class/module context */
static VALUE
eval_under(under, self, src, file, line)
    VALUE under, self, src;
    const char *file;
    int line;
{
    VALUE args[4];

    if (ruby_safe_level >= 4) {
        StringValue(src);
    }
    else {
        SafeStringValue(src);
    }
    args[0] = self;
    args[1] = src;
    args[2] = (VALUE)file;
    args[3] = (VALUE)line;
    return exec_under(eval_under_i, under, under, args);
}

static VALUE
yield_under_i(self)
    VALUE self;
{
    return rb_yield_0(self, self, ruby_class, YIELD_PUBLIC_DEF, Qfalse);
}

static VALUE
yield_args_under_i(vinfo)
    VALUE vinfo;
{
    VALUE *info = (VALUE *)vinfo;

    return rb_yield_0(info[0], info[1], ruby_class, YIELD_PUBLIC_DEF, Qtrue);
}

/* block eval under the class/module context */
static VALUE
yield_under(under, self, args)
    VALUE under, self, args;
{
    if (args == Qundef) {
        return exec_under(yield_under_i, under, 0, self);
    }
    else {
        VALUE info[2] = { args, self };

        return exec_under(yield_args_under_i, under, 0, (VALUE)info);
    }
}

static VALUE
specific_eval(argc, argv, klass, self)
    int argc;
    VALUE *argv;
    VALUE klass, self;
{
    if (rb_block_given_p()) {
        if (argc > 0) {
            rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
        }
        return yield_under(klass, self, Qundef);
    }
    else {
        const char *file = "(eval)";
        int   line = 1;

        if (argc == 0) {
            rb_raise(rb_eArgError, "block not supplied");
        }
        else {
            if (ruby_safe_level >= 4) {
                StringValue(argv[0]);
            }
            else {
                SafeStringValue(argv[0]);
            }
            if (argc > 3) {
                rb_raise(rb_eArgError, "wrong number of arguments: %s(src) or %s{..}",
                         rb_id2name(ruby_frame->last_func),
                         rb_id2name(ruby_frame->last_func));
            }
            if (argc > 2) line = NUM2INT(argv[2]);
            if (argc > 1) {
                file = StringValuePtr(argv[1]);
            }
        }
        return eval_under(klass, self, argv[0], file, line);
    }
}

/*
 *  call-seq:
 *     obj.instance_eval(string [, filename [, lineno]] )   => obj
 *     obj.instance_eval {| | block }                       => obj
 *
 *  Evaluates a string containing Ruby source code, or the given block,
 *  within the context of the receiver (_obj_). In order to set the
 *  context, the variable +self+ is set to _obj_ while
 *  the code is executing, giving the code access to _obj_'s
 *  instance variables. In the version of instance_eval
 *  that takes a +String+, the optional second and third
 *  parameters supply a filename and starting line number that are used
 *  when reporting compilation errors.
 *
 *     class Klass
 *       def initialize
 *         @secret = 99
 *       end
 *     end
 *     k = Klass.new
 *     k.instance_eval { @secret }   #=> 99
 */

VALUE
rb_obj_instance_eval(argc, argv, self)
    int argc;
    VALUE *argv;
    VALUE self;
{
    VALUE klass, result;

    if (SPECIAL_CONST_P(self)) {
        klass = Qnil;
    }
    else {
        klass = rb_singleton_class(self);
    }
    result = specific_eval(argc, argv, klass, self);

    return result;
}

/*
 *  call-seq:
 *     obj.instance_exec(arg...) {|var...| block }                       => obj
 *
 *  Executes the given block within the context of the receiver
 *  (_obj_). In order to set the context, the variable +self+ is set
 *  to _obj_ while the code is executing, giving the code access to
 *  _obj_'s instance variables.  Arguments are passed as block parameters.
 *
 *     class KlassWithSecret
 *       def initialize
 *         @secret = 99
 *       end
 *     end
 *     k = KlassWithSecret.new
 *     k.instance_exec(5) {|x| @secret+x }   #=> 104
 */

VALUE
rb_obj_instance_exec(argc, argv, self)
    int argc;
    VALUE *argv;
    VALUE self;
{
    VALUE klass;

    if (SPECIAL_CONST_P(self)) {
        klass = Qnil;
    }
    else {
        klass = rb_singleton_class(self);
    }
    return yield_under(klass, self, rb_ary_new4(argc, argv));
}

/*
 *  call-seq:
 *     mod.class_eval(string [, filename [, lineno]])  => obj
 *     mod.module_eval {|| block }                     => obj
 *
 *  Evaluates the string or block in the context of _mod_. This can
 *  be used to add methods to a class. module_eval returns
 *  the result of evaluating its argument. The optional _filename_
 *  and _lineno_ parameters set the text for error messages.
 *
 *     class Thing
 *     end
 *     a = %q{def hello() "Hello there!" end}
 *     Thing.module_eval(a)
 *     puts Thing.new.hello()
 *     Thing.module_eval("invalid code", "dummy", 123)
 *
 *  produces:
 *
 *     Hello there!
 *     dummy:123:in `module_eval': undefined local variable
 *         or method `code' for Thing:Class
 */

VALUE
rb_mod_module_eval(argc, argv, mod)
    int argc;
    VALUE *argv;
    VALUE mod;
{
    return specific_eval(argc, argv, mod, mod);
}

/*
 *  call-seq:
 *     mod.module_exec(arg...) {|var...| block }       => obj
 *     mod.class_exec(arg...) {|var...| block }        => obj
 *
 *  Evaluates the given block in the context of the class/module.
 *  The method defined in the block will belong to the receiver.
 *
 *     class Thing
 *     end
 *     Thing.class_exec{
 *       def hello() "Hello there!" end
 *     }
 *     puts Thing.new.hello()
 *
 *  produces:
 *
 *     Hello there!
 */

VALUE
rb_mod_module_exec(argc, argv, mod)
    int argc;
    VALUE *argv;
    VALUE mod;
{
    return yield_under(mod, mod, rb_ary_new4(argc, argv));
}

VALUE rb_load_path;

NORETURN(static void load_failed _((VALUE)));

void
rb_load(fname, wrap)
    VALUE fname;
    int wrap;
{
    VALUE tmp;
    int state;
    volatile int prohibit_int = rb_prohibit_interrupt;
    volatile ID last_func;
    volatile VALUE wrapper = ruby_wrapper;
    VALUE self = ruby_top_self;
    NODE *volatile last_node;
    NODE *volatile saved_cref = ruby_cref;

    if (wrap && ruby_safe_level >= 4) {
        StringValue(fname);
    }
    else {
        SafeStringValue(fname);
    }
    fname = rb_str_new4(fname);
    tmp = rb_find_file(fname);
    if (!tmp) {
        load_failed(fname);
    }
    fname = tmp;

    ruby_errinfo = Qnil;        /* ensure */
    PUSH_VARS();
    PUSH_CLASS(ruby_wrapper);
    ruby_cref = ruby_top_cref;
    if (!wrap) {
        rb_secure(4);           /* should alter global state */
        ruby_class = rb_cObject;
        ruby_wrapper = 0;
    }
    else {
        /* load in anonymous module as toplevel */
        ruby_class = ruby_wrapper = rb_module_new();
        self = rb_obj_clone(ruby_top_self);
        rb_extend_object(self, ruby_wrapper);
        PUSH_CREF(ruby_wrapper);
    }
    PUSH_ITER(ITER_NOT);
    PUSH_FRAME();
    ruby_frame->last_func = 0;
    ruby_frame->last_class = 0;
    ruby_frame->self = self;
    PUSH_SCOPE();
    /* default visibility is private at loading toplevel */
    SCOPE_SET(SCOPE_PRIVATE);
    PUSH_TAG(PROT_EMPTY);
    state = EXEC_TAG();
    last_func = ruby_frame->last_func;
    last_node = ruby_current_node;
    if (!ruby_current_node && ruby_sourcefile) {
        last_node = NEW_NEWLINE(0);
    }
    ruby_current_node = 0;
    if (state == 0) {
        NODE *node;
        int critical;

        DEFER_INTS;
        ruby_in_eval++;
        critical = rb_thread_critical;
        rb_thread_critical = Qtrue;
        rb_load_file(RSTRING(fname)->ptr);
        ruby_in_eval--;
        node = ruby_eval_tree;
        rb_thread_critical = critical;
        ALLOW_INTS;
        if (ruby_nerrs == 0) {
            eval_tree(self, node);
        }
    }
    ruby_frame->last_func = last_func;
    ruby_current_node = last_node;
    ruby_sourcefile = 0;
    ruby_set_current_source();
    if (ruby_scope->flags == SCOPE_ALLOCA && ruby_class == rb_cObject) {
        if (ruby_scope->local_tbl) /* toplevel was empty */
            free(ruby_scope->local_tbl);
    }
    POP_TAG();
    rb_prohibit_interrupt = prohibit_int;
    ruby_cref = saved_cref;
    POP_SCOPE();
    POP_FRAME();
    POP_ITER();
    POP_CLASS();
    POP_VARS();
    ruby_wrapper = wrapper;
    if (ruby_nerrs > 0) {
        ruby_nerrs = 0;
        rb_exc_raise(ruby_errinfo);
    }
    if (state) jump_tag_but_local_jump(state, Qundef);
    if (!NIL_P(ruby_errinfo))   /* exception during load */
        rb_exc_raise(ruby_errinfo);
}

void
rb_load_protect(fname, wrap, state)
    VALUE fname;
    int wrap;
    int * volatile state;
{
    int status;

    PUSH_TAG(PROT_EMPTY);
    if ((status = EXEC_TAG()) == 0) {
        rb_load(fname, wrap);
    }
    POP_TAG();
    if (state) *state = status;
}

/*
 *  call-seq:
 *     load(filename, wrap=false)   => true
 *
 *  Loads and executes the Ruby
 *  program in the file _filename_. If the filename does not
 *  resolve to an absolute path, the file is searched for in the library
 *  directories listed in $:. If the optional _wrap_
 *  parameter is +true+, the loaded script will be executed
 *  under an anonymous module, protecting the calling program's global
 *  namespace. In no circumstance will any local variables in the loaded
 *  file be propagated to the loading environment.
 */


static VALUE
rb_f_load(argc, argv)
    int argc;
    VALUE *argv;
{
    VALUE fname, wrap;

    rb_scan_args(argc, argv, "11", &fname, &wrap);
    rb_load(fname, RTEST(wrap));
    return Qtrue;
}

VALUE ruby_dln_librefs;
static VALUE rb_features;
static st_table *loading_tbl;

#define IS_SOEXT(e) (strcmp(e, ".so") == 0 || strcmp(e, ".o") == 0)
#ifdef DLEXT2
#define IS_DLEXT(e) (strcmp(e, DLEXT) == 0 || strcmp(e, DLEXT2) == 0)
#else
#define IS_DLEXT(e) (strcmp(e, DLEXT) == 0)
#endif


static const char *const loadable_ext[] = {
    ".rb", DLEXT,
#ifdef DLEXT2
    DLEXT2,
#endif
    0
};

static int rb_feature_p _((const char **, const char *, int));
static int search_required _((VALUE, VALUE *, VALUE *));

static int
rb_feature_p(ftptr, ext, rb)
    const char **ftptr, *ext;
    int rb;
{
    VALUE v;
    const char *f, *e, *feature = *ftptr;
    long i, len, elen;

    if (ext) {
        len = ext - feature;
        elen = strlen(ext);
    }
    else {
        len = strlen(feature);
        elen = 0;
    }
    for (i = 0; i < RARRAY_LEN(rb_features); ++i) {
        v = RARRAY_PTR(rb_features)[i];
        f = StringValuePtr(v);
        if (RSTRING_LEN(v) < len || strncmp(f, feature, len) != 0)
            continue;
        if (!*(e = f + len)) {
            if (ext) continue;
            *ftptr = 0;
            return 'u';
        }
        if (*e != '.') continue;
        if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
            *ftptr = 0;
            return 's';
        }
        if ((rb || !ext) && (strcmp(e, ".rb") == 0)) {
            *ftptr = 0;
            return 'r';
        }
    }
    if (loading_tbl) {
        if (st_lookup(loading_tbl, (st_data_t)feature, (st_data_t *)ftptr)) {
            if (!ext) return 'u';
            return strcmp(ext, ".rb") ? 's' : 'r';
        }
        else {
            char *buf;

            if (ext && *ext) return 0;
            buf = ALLOCA_N(char, len + DLEXT_MAXLEN + 1);
            MEMCPY(buf, feature, char, len);
            for (i = 0; (e = loadable_ext[i]) != 0; i++) {
                strncpy(buf + len, e, DLEXT_MAXLEN + 1);
                if (st_lookup(loading_tbl, (st_data_t)buf, (st_data_t *)ftptr)) {
                    return i ? 's' : 'r';
                }
            }
        }
    }
    return 0;
}
#define rb_feature_p(feature, ext, rb) rb_feature_p(&feature, ext, rb)

int
rb_provided(feature)
    const char *feature;
{
    const char *ext = strrchr(feature, '.');

    if (ext && !strchr(ext, '/')) {
        if (strcmp(".rb", ext) == 0) {
            if (rb_feature_p(feature, ext, Qtrue)) return Qtrue;
            return Qfalse;
        }
        else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
            if (rb_feature_p(feature, ext, Qfalse)) return Qtrue;
            return Qfalse;
        }
    }
    if (rb_feature_p(feature, feature + strlen(feature), Qtrue))
        return Qtrue;

    return Qfalse;
}

static void
rb_provide_feature(feature)
    VALUE feature;
{
    rb_ary_push(rb_features, feature);
}

void
rb_provide(feature)
    const char *feature;
{
    rb_provide_feature(rb_str_new2(feature));
}

static char *
load_lock(ftptr)
    const char *ftptr;
{
    st_data_t th;

    if (!loading_tbl ||
        !st_lookup(loading_tbl, (st_data_t)ftptr, &th))
    {
        /* loading ruby library should be serialized. */
        if (!loading_tbl) {
            loading_tbl = st_init_strtable();
        }
        /* partial state */
        ftptr = ruby_strdup(ftptr);
        st_insert(loading_tbl, (st_data_t)ftptr, (st_data_t)curr_thread);
        return (char *)ftptr;
    }
    do {
        rb_thread_t owner = (rb_thread_t)th;
        if (owner == curr_thread) return 0;
        rb_thread_join(owner->thread, -1.0);
    } while (st_lookup(loading_tbl, (st_data_t)ftptr, &th));
    return 0;
}

static void
load_unlock(const char *ftptr)
{
    if (ftptr) {
        st_data_t key = (st_data_t)ftptr;

        if (st_delete(loading_tbl, &key, 0)) {
            free((char *)key);
        }
    }
}

/*
 *  call-seq:
 *     require(string)    => true or false
 *
 *  Ruby tries to load the library named _string_, returning
 *  +true+ if successful. If the filename does not resolve to
 *  an absolute path, it will be searched for in the directories listed
 *  in $:. If the file has the extension ``.rb'', it is
 *  loaded as a source file; if the extension is ``.so'', ``.o'', or
 *  ``.dll'', or whatever the default shared library extension is on
 *  the current platform, Ruby loads the shared library as a Ruby
 *  extension. Otherwise, Ruby tries adding ``.rb'', ``.so'', and so on
 *  to the name. The name of the loaded feature is added to the array in
 *  $". A feature will not be loaded if it's name already
 *  appears in $". However, the file name is not converted
 *  to an absolute path, so that ``require 'a';require
 *  './a''' will load a.rb twice.
 *
 *     require "my-library.rb"
 *     require "db-driver"
 */

VALUE
rb_f_require(obj, fname)
    VALUE obj, fname;
{
    return rb_require_safe(fname, ruby_safe_level);
}

static int
search_required(fname, featurep, path)
    VALUE fname, *featurep, *path;
{
    VALUE tmp;
    const char *ext, *ftptr;
    int type;

    *featurep = fname;
    *path = 0;
    ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
    if (ext && !strchr(ext, '/')) {
        if (strcmp(".rb", ext) == 0) {
            if (rb_feature_p(ftptr, ext, Qtrue)) {
                if (ftptr) *path = rb_str_new2(ftptr);
                return 'r';
            }
            if ((*path = rb_find_file(fname)) != 0) return 'r';
            return 0;
        }
        else if (IS_SOEXT(ext)) {
            if (rb_feature_p(ftptr, ext, Qfalse)) {
                if (ftptr) *path = rb_str_new2(ftptr);
                return 's';
            }
            tmp = rb_str_new(RSTRING_PTR(fname), ext-RSTRING_PTR(fname));
            *featurep = tmp;
#ifdef DLEXT2
            OBJ_FREEZE(tmp);
            if (rb_find_file_ext(&tmp, loadable_ext+1)) {
                *featurep = tmp;
                *path = rb_find_file(tmp);
                return 's';
            }
#else
            rb_str_cat2(tmp, DLEXT);
            OBJ_FREEZE(tmp);
            if ((*path = rb_find_file(tmp)) != 0) {
                return 's';
            }
#endif
        }
        else if (IS_DLEXT(ext)) {
            if (rb_feature_p(ftptr, ext, Qfalse)) {
                if (ftptr) *path = rb_str_new2(ftptr);
                return 's';
            }
            if ((*path = rb_find_file(fname)) != 0) return 's';
        }
    }
    tmp = fname;
    type = rb_find_file_ext(&tmp, loadable_ext);
    *featurep = tmp;
    switch (type) {
      case 0:
        type = rb_feature_p(ftptr, 0, Qfalse);
        if (type && ftptr) *path = rb_str_new2(ftptr);
        return type;

      default:
        ext = strrchr(ftptr = RSTRING(tmp)->ptr, '.');
        if (!rb_feature_p(ftptr, ext, !--type))
            *path = rb_find_file(tmp);
        else if (ftptr)
            *path = rb_str_new2(ftptr);
    }
    return type ? 's' : 'r';
}

static void
load_failed(fname)
    VALUE fname;
{
    rb_raise(rb_eLoadError, "no such file to load -- %s", RSTRING(fname)->ptr);
}

VALUE
rb_require_safe(fname, safe)
    VALUE fname;
    int safe;
{
    VALUE result;
    volatile VALUE errinfo = ruby_errinfo;
    int state;
    struct {
        NODE *node;
        ID func;
        int vmode, safe;
    } volatile saved;
    char *volatile ftptr = 0;

    if (OBJ_TAINTED(fname)) {
        rb_check_safe_obj(fname);
    }
    StringValue(fname);
    fname = rb_str_new4(fname);
    saved.vmode = scope_vmode;
    saved.node = ruby_current_node;
    saved.func = ruby_frame->last_func;
    saved.safe = ruby_safe_level;
    PUSH_TAG(PROT_EMPTY);
    if ((state = EXEC_TAG()) == 0) {
        VALUE feature, path;
        long handle;
        int found;

        ruby_safe_level = safe;
        found = search_required(fname, &feature, &path);
        if (found) {
            if (!path || !(ftptr = load_lock(RSTRING_PTR(feature)))) {
                result = Qfalse;
            }
            else {
                ruby_safe_level = 0;
                switch (found) {
                  case 'r':
                    rb_load(path, 0);
                    break;

                  case 's':
                    ruby_current_node = 0;
                    ruby_sourcefile = rb_source_filename(RSTRING(path)->ptr);
                    ruby_sourceline = 0;
                    ruby_frame->last_func = 0;
                    SCOPE_SET(SCOPE_PUBLIC);
                    handle = (long)dln_load(RSTRING(path)->ptr);
                    rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
                    break;
                }
                rb_provide_feature(feature);
                result = Qtrue;
            }
        }else
          result = Qnil;
    }
    POP_TAG();
    ruby_current_node = saved.node;
    ruby_set_current_source();
    ruby_frame->last_func = saved.func;
    SCOPE_SET(saved.vmode);
    ruby_safe_level = saved.safe;
    load_unlock(ftptr);
    if (state) JUMP_TAG(state);
    if (NIL_P(result)) {
        load_failed(fname);
    }
    ruby_errinfo = errinfo;

    return result;
}

VALUE
rb_require(fname)
    const char *fname;
{
    VALUE fn = rb_str_new2(fname);
    OBJ_FREEZE(fn);
    return rb_require_safe(fn, ruby_safe_level);
}

void
ruby_init_ext(name, init)
    const char *name;
    void (*init) _((void));
{
    ruby_current_node = 0;
    ruby_sourcefile = rb_source_filename(name);
    ruby_sourceline = 0;
    ruby_frame->last_func = 0;
    ruby_frame->orig_func = 0;
    SCOPE_SET(SCOPE_PUBLIC);
    if (load_lock(name)) {
        (*init)();
        rb_provide(name);
        load_unlock(name);
    }
}

static void
secure_visibility(self)
    VALUE self;
{
    if (ruby_safe_level >= 4 && !OBJ_TAINTED(self)) {
        rb_raise(rb_eSecurityError, "Insecure: can't change method visibility");
    }
}

static void
set_method_visibility(self, argc, argv, ex)
    VALUE self;
    int argc;
    VALUE *argv;
    ID ex;
{
    int i;

    secure_visibility(self);
    for (i=0; i self
 *     public(symbol, ...)    => self
 *
 *  With no arguments, sets the default visibility for subsequently
 *  defined methods to public. With arguments, sets the named methods to
 *  have public visibility.
 */

static VALUE
rb_mod_public(argc, argv, module)
    int argc;
    VALUE *argv;
    VALUE module;
{
    secure_visibility(module);
    if (argc == 0) {
        SCOPE_SET(SCOPE_PUBLIC);
    }
    else {
        set_method_visibility(module, argc, argv, NOEX_PUBLIC);
    }
    return module;
}

/*
 *  call-seq:
 *     protected                => self
 *     protected(symbol, ...)   => self
 *
 *  With no arguments, sets the default visibility for subsequently
 *  defined methods to protected. With arguments, sets the named methods
 *  to have protected visibility.
 */

static VALUE
rb_mod_protected(argc, argv, module)
    int argc;
    VALUE *argv;
    VALUE module;
{
    secure_visibility(module);
    if (argc == 0) {
        SCOPE_SET(SCOPE_PROTECTED);
    }
    else {
        set_method_visibility(module, argc, argv, NOEX_PROTECTED);
    }
    return module;
}

/*
 *  call-seq:
 *     private                 => self
 *     private(symbol, ...)    => self
 *
 *  With no arguments, sets the default visibility for subsequently
 *  defined methods to private. With arguments, sets the named methods
 *  to have private visibility.
 *
 *     module Mod
 *       def a()  end
 *       def b()  end
 *       private
 *       def c()  end
 *       private :a
 *     end
 *     Mod.private_instance_methods   #=> ["a", "c"]
 */

static VALUE
rb_mod_private(argc, argv, module)
    int argc;
    VALUE *argv;
    VALUE module;
{
    secure_visibility(module);
    if (argc == 0) {
        SCOPE_SET(SCOPE_PRIVATE);
    }
    else {
        set_method_visibility(module, argc, argv, NOEX_PRIVATE);
    }
    return module;
}

/*
 *  call-seq:
 *     mod.public_class_method(symbol, ...)    => mod
 *
 *  Makes a list of existing class methods public.
 */

static VALUE
rb_mod_public_method(argc, argv, obj)
    int argc;
    VALUE *argv;
    VALUE obj;
{
    set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PUBLIC);
    return obj;
}

/*
 *  call-seq:
 *     mod.private_class_method(symbol, ...)   => mod
 *
 *  Makes existing class methods private. Often used to hide the default
 *  constructor new.
 *
 *     class SimpleSingleton  # Not thread safe
 *       private_class_method :new
 *       def SimpleSingleton.create(*args, &block)
 *         @me = new(*args, &block) if ! @me
 *         @me
 *       end
 *     end
 */

static VALUE
rb_mod_private_method(argc, argv, obj)
    int argc;
    VALUE *argv;
    VALUE obj;
{
    set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PRIVATE);
    return obj;
}

/*
 *  call-seq:
 *     public
 *     public(symbol, ...)
 *
 *  With no arguments, sets the default visibility for subsequently
 *  defined methods to public. With arguments, sets the named methods to
 *  have public visibility.
 */

static VALUE
top_public(argc, argv)
    int argc;
    VALUE *argv;
{
    return rb_mod_public(argc, argv, rb_cObject);
}

static VALUE
top_private(argc, argv)
    int argc;
    VALUE *argv;
{
    return rb_mod_private(argc, argv, rb_cObject);
}

/*
 *  call-seq:
 *     module_function(symbol, ...)    => self
 *
 *  Creates module functions for the named methods. These functions may
 *  be called with the module as a receiver, and also become available
 *  as instance methods to classes that mix in the module. Module
 *  functions are copies of the original, and so may be changed
 *  independently. The instance-method versions are made private. If
 *  used with no arguments, subsequently defined methods become module
 *  functions.
 *
 *     module Mod
 *       def one
 *         "This is one"
 *       end
 *       module_function :one
 *     end
 *     class Cls
 *       include Mod
 *       def callOne
 *         one
 *       end
 *     end
 *     Mod.one     #=> "This is one"
 *     c = Cls.new
 *     c.callOne   #=> "This is one"
 *     module Mod
 *       def one
 *         "This is the new one"
 *       end
 *     end
 *     Mod.one     #=> "This is one"
 *     c.callOne   #=> "This is the new one"
 */

static VALUE
rb_mod_modfunc(argc, argv, module)
    int argc;
    VALUE *argv;
    VALUE module;
{
    int i;
    ID id;
    NODE *body;

    if (TYPE(module) != T_MODULE) {
        rb_raise(rb_eTypeError, "module_function must be called for modules");
    }

    secure_visibility(module);
    if (argc == 0) {
        SCOPE_SET(SCOPE_MODFUNC);
        return module;
    }

    set_method_visibility(module, argc, argv, NOEX_PRIVATE);
    for (i=0; ind_body == 0) {
                print_undef(module, id);
            }
            if (nd_type(body->nd_body) != NODE_ZSUPER) {
                break;          /* normal case: need not to follow 'super' link */
            }
            m = RCLASS(m)->super;
            if (!m) break;
        }
        rb_add_method(rb_singleton_class(module), id, body->nd_body, NOEX_PUBLIC);
    }
    return module;
}

/*
 *  call-seq:
 *     append_features(mod)   => mod
 *
 *  When this module is included in another, Ruby calls
 *  append_features in this module, passing it the
 *  receiving module in _mod_. Ruby's default implementation is
 *  to add the constants, methods, and module variables of this module
 *  to _mod_ if this module has not already been added to
 *  _mod_ or one of its ancestors. See also Module#include.
 */

static VALUE
rb_mod_append_features(module, include)
    VALUE module, include;
{
    switch (TYPE(include)) {
      case T_CLASS:
      case T_MODULE:
        break;
      default:
        Check_Type(include, T_CLASS);
        break;
    }
    rb_include_module(include, module);

    return module;
}

/*
 *  call-seq:
 *     include(module, ...)    => self
 *
 *  Invokes Module.append_features on each parameter in turn.
 */

static VALUE
rb_mod_include(argc, argv, module)
    int argc;
    VALUE *argv;
    VALUE module;
{
    int i;

    for (i=0; i obj
 *
 *  Extends the specified object by adding this module's constants and
 *  methods (which are added as singleton methods). This is the callback
 *  method used by Object#extend.
 *
 *     module Picky
 *       def Picky.extend_object(o)
 *         if String === o
 *           puts "Can't add Picky to a String"
 *         else
 *           puts "Picky added to #{o.class}"
 *           super
 *         end
 *       end
 *     end
 *     (s = Array.new).extend Picky  # Call Object.extend
 *     (s = "quick brown fox").extend Picky
 *
 *  produces:
 *
 *     Picky added to Array
 *     Can't add Picky to a String
 */

static VALUE
rb_mod_extend_object(mod, obj)
    VALUE mod, obj;
{
    rb_extend_object(obj, mod);
    return obj;
}

/*
 *  call-seq:
 *     obj.extend(module, ...)    => obj
 *
 *  Adds to _obj_ the instance methods from each module given as a
 *  parameter.
 *
 *     module Mod
 *       def hello
 *         "Hello from Mod.\n"
 *       end
 *     end
 *
 *     class Klass
 *       def hello
 *         "Hello from Klass.\n"
 *       end
 *     end
 *
 *     k = Klass.new
 *     k.hello         #=> "Hello from Klass.\n"
 *     k.extend(Mod)   #=> #
 *     k.hello         #=> "Hello from Mod.\n"
 */

static VALUE
rb_obj_extend(argc, argv, obj)
    int argc;
    VALUE *argv;
    VALUE obj;
{
    int i;

    if (argc == 0) {
        rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)");
    }
    for (i=0; i self
 *
 *  Invokes Module.append_features
 *  on each parameter in turn. Effectively adds the methods and constants
 *  in each module to the receiver.
 */

static VALUE
top_include(argc, argv, self)
    int argc;
    VALUE *argv;
    VALUE self;
{
    rb_secure(4);
    if (ruby_wrapper) {
        rb_warning("main#include in the wrapped load is effective only in wrapper module");
        return rb_mod_include(argc, argv, ruby_wrapper);
    }
    return rb_mod_include(argc, argv, rb_cObject);
}

VALUE rb_f_trace_var();
VALUE rb_f_untrace_var();

static void
errinfo_setter(val, id, var)
    VALUE val;
    ID id;
    VALUE *var;
{
    if (!NIL_P(val) && !rb_obj_is_kind_of(val, rb_eException)) {
        rb_raise(rb_eTypeError, "assigning non-exception to $!");
    }
    *var = val;
}

static VALUE
errat_getter(id)
    ID id;
{
    return get_backtrace(ruby_errinfo);
}

static void
errat_setter(val, id, var)
    VALUE val;
    ID id;
    VALUE *var;
{
    if (NIL_P(ruby_errinfo)) {
        rb_raise(rb_eArgError, "$! not set");
    }
    set_backtrace(ruby_errinfo, val);
}

/*
 *  call-seq:
 *     local_variables    => array
 *
 *  Returns the names of the current local variables.
 *
 *     fred = 1
 *     for i in 1..10
 *        # ...
 *     end
 *     local_variables   #=> ["fred", "i"]
 */

static VALUE
rb_f_local_variables()
{
    ID *tbl;
    int n, i;
    VALUE ary = rb_ary_new();
    struct RVarmap *vars;

    tbl = ruby_scope->local_tbl;
    if (tbl) {
        n = *tbl++;
        for (i=2; iid && rb_is_local_id(vars->id)) { /* skip $_, $~ and flip states */
            rb_ary_push(ary, rb_str_new2(rb_id2name(vars->id)));
        }
        vars = vars->next;
    }

    return ary;
}

static VALUE rb_f_catch _((VALUE,VALUE));
NORETURN(static VALUE rb_f_throw _((int,VALUE*)));

struct end_proc_data {
    void (*func)();
    VALUE data;
    int safe;
    struct end_proc_data *next;
};

static struct end_proc_data *end_procs, *ephemeral_end_procs, *tmp_end_procs;

void
rb_set_end_proc(func, data)
    void (*func) _((VALUE));
    VALUE data;
{
    struct end_proc_data *link = ALLOC(struct end_proc_data);
    struct end_proc_data **list;

    if (ruby_wrapper) list = &ephemeral_end_procs;
    else              list = &end_procs;
    link->next = *list;
    link->func = func;
    link->data = data;
    link->safe = ruby_safe_level;
    *list = link;
}

void
rb_mark_end_proc()
{
    struct end_proc_data *link;

    link = end_procs;
    while (link) {
        rb_gc_mark(link->data);
        link = link->next;
    }
    link = ephemeral_end_procs;
    while (link) {
        rb_gc_mark(link->data);
        link = link->next;
    }
    link = tmp_end_procs;
    while (link) {
        rb_gc_mark(link->data);
        link = link->next;
    }
}

static void call_end_proc _((VALUE data));

static void
call_end_proc(data)
    VALUE data;
{
    PUSH_ITER(ITER_NOT);
    PUSH_FRAME();
    ruby_frame->self = ruby_frame->prev->self;
    ruby_frame->node = 0;
    ruby_frame->last_func = 0;
    ruby_frame->last_class = 0;
    proc_invoke(data, rb_ary_new2(0), Qundef, 0);
    POP_FRAME();
    POP_ITER();
}

static void
rb_f_END()
{
    PUSH_FRAME();
    ruby_frame->argc = 0;
    ruby_frame->iter = ITER_CUR;
    rb_set_end_proc(call_end_proc, rb_block_proc());
    POP_FRAME();
}

/*
 *  call-seq:
 *     at_exit { block } -> proc
 *
 *  Converts _block_ to a +Proc+ object (and therefore
 *  binds it at the point of call) and registers it for execution when
 *  the program exits. If multiple handlers are registered, they are
 *  executed in reverse order of registration.
 *
 *     def do_at_exit(str1)
 *       at_exit { print str1 }
 *     end
 *     at_exit { puts "cruel world" }
 *     do_at_exit("goodbye ")
 *     exit
 *
 *  produces:
 *
 *     goodbye cruel world
 */

static VALUE
rb_f_at_exit()
{
    VALUE proc;

    if (!rb_block_given_p()) {
        rb_raise(rb_eArgError, "called without a block");
    }
    proc = rb_block_proc();
    rb_set_end_proc(call_end_proc, proc);
    return proc;
}

void
rb_exec_end_proc()
{
    struct end_proc_data *tmp, *volatile link;
    int status;
    volatile int safe = ruby_safe_level;

    while (ephemeral_end_procs) {
        tmp_end_procs = link = ephemeral_end_procs;
        ephemeral_end_procs = 0;
        while (link) {
            PUSH_TAG(PROT_EMPTY);
            if ((status = EXEC_TAG()) == 0) {
                ruby_safe_level = link->safe;
                (*link->func)(link->data);
            }
            POP_TAG();
            if (status) {
                error_handle(status);
            }
            tmp = link;
            tmp_end_procs = link = link->next;
            free(tmp);
        }
    }
    while (end_procs) {
        tmp_end_procs = link = end_procs;
        end_procs = 0;
        while (link) {
            PUSH_TAG(PROT_EMPTY);
            if ((status = EXEC_TAG()) == 0) {
                ruby_safe_level = link->safe;
                (*link->func)(link->data);
            }
            POP_TAG();
            if (status) {
                error_handle(status);
            }
            tmp = link;
            tmp_end_procs = link = link->next;
            free(tmp);
        }
    }
    ruby_safe_level = safe;
}

/*
 *  call-seq:
 *     __method__         => symbol
 *
 *  Returns the name of the current method as a Symbol.
 *  If called from inside of an aliased method it will return the original
 *  nonaliased name.
 *  If called outside of a method, it returns nil.
 *
 *    def foo
 *      __method__
 *    end
 *    alias bar foo
 *
 *    foo                # => :foo
 *    bar                # => :foo
 *
 */

static VALUE
rb_f_method_name()
{
    struct FRAME* prev = ruby_frame->prev;
    if (prev && prev->orig_func) {
        return ID2SYM(prev->orig_func);
    }
    else {
        return Qnil;
    }
}

/* Hash (Thread => Backtrace) used to collect backtrace for each threads. */
static VALUE backtrace_for_each_thread;

static int backtrace_level_for_each_thread;

static VALUE
switch_thread_context_to_collect_backtrace(rb_thread_t next);

static VALUE
rb_f_caller_for_all_threads();

void
Init_eval()
{
    init = rb_intern("initialize");
    eqq = rb_intern("===");
    each = rb_intern("each");

    aref = rb_intern("[]");
    aset = rb_intern("[]=");
    match = rb_intern("=~");
    missing = rb_intern("method_missing");
    added = rb_intern("method_added");
    singleton_added = rb_intern("singleton_method_added");
    removed = rb_intern("method_removed");
    singleton_removed = rb_intern("singleton_method_removed");
    undefined = rb_intern("method_undefined");
    singleton_undefined = rb_intern("singleton_method_undefined");

    __id__ = rb_intern("__id__");
    __send__ = rb_intern("__send__");

    rb_global_variable((void *)&top_scope);
    rb_global_variable((void *)&ruby_eval_tree_begin);

    rb_global_variable((void *)&ruby_eval_tree);
    rb_global_variable((void *)&ruby_dyna_vars);

    rb_define_virtual_variable("$@", errat_getter, errat_setter);
    rb_define_hooked_variable("$!", &ruby_errinfo, 0, errinfo_setter);

    rb_define_global_function("eval", rb_f_eval, -1);
    rb_define_global_function("iterator?", rb_f_block_given_p, 0);
    rb_define_global_function("block_given?", rb_f_block_given_p, 0);
    rb_define_global_function("method_missing", rb_method_missing, -1);
    rb_define_global_function("loop", rb_f_loop, 0);

    rb_define_method(rb_mKernel, "respond_to?", obj_respond_to, -1);
    respond_to   = rb_intern("respond_to?");
    rb_global_variable((void *)&basic_respond_to);
    basic_respond_to = rb_method_node(rb_cObject, respond_to);

    rb_define_global_function("raise", rb_f_raise, -1);
    rb_define_global_function("fail", rb_f_raise, -1);

    rb_define_global_function("caller", rb_f_caller, -1);
    rb_define_global_function("caller_for_all_threads", rb_f_caller_for_all_threads, -1);

    rb_define_global_function("exit", rb_f_exit, -1);
    rb_define_global_function("abort", rb_f_abort, -1);

    rb_define_global_function("at_exit", rb_f_at_exit, 0);

    rb_define_global_function("catch", rb_f_catch, 1);
    rb_define_global_function("throw", rb_f_throw, -1);
    rb_define_global_function("global_variables", rb_f_global_variables, 0); /* in variable.c */
    rb_define_global_function("local_variables", rb_f_local_variables, 0);

    rb_define_global_function("__method__", rb_f_method_name, 0);

    rb_define_method(rb_mKernel, "send", rb_f_send, -1);
    rb_define_method(rb_mKernel, "__send__", rb_f_send, -1);
    rb_define_method(rb_mKernel, "instance_eval", rb_obj_instance_eval, -1);
    rb_define_method(rb_mKernel, "instance_exec", rb_obj_instance_exec, -1);

    rb_define_private_method(rb_cModule, "append_features", rb_mod_append_features, 1);
    rb_define_private_method(rb_cModule, "extend_object", rb_mod_extend_object, 1);
    rb_define_private_method(rb_cModule, "include", rb_mod_include, -1);
    rb_define_private_method(rb_cModule, "public", rb_mod_public, -1);
    rb_define_private_method(rb_cModule, "protected", rb_mod_protected, -1);
    rb_define_private_method(rb_cModule, "private", rb_mod_private, -1);
    rb_define_private_method(rb_cModule, "module_function", rb_mod_modfunc, -1);
    rb_define_method(rb_cModule, "method_defined?", rb_mod_method_defined, 1);
    rb_define_method(rb_cModule, "public_method_defined?", rb_mod_public_method_defined, 1);
    rb_define_method(rb_cModule, "private_method_defined?", rb_mod_private_method_defined, 1);
    rb_define_method(rb_cModule, "protected_method_defined?", rb_mod_protected_method_defined, 1);
    rb_define_method(rb_cModule, "public_class_method", rb_mod_public_method, -1);
    rb_define_method(rb_cModule, "private_class_method", rb_mod_private_method, -1);
    rb_define_method(rb_cModule, "module_eval", rb_mod_module_eval, -1);
    rb_define_method(rb_cModule, "module_exec", rb_mod_module_exec, -1);
    rb_define_method(rb_cModule, "class_eval", rb_mod_module_eval, -1);
    rb_define_method(rb_cModule, "class_exec", rb_mod_module_exec, -1);

    rb_undef_method(rb_cClass, "module_function");

    rb_define_private_method(rb_cModule, "remove_method", rb_mod_remove_method, -1);
    rb_define_private_method(rb_cModule, "undef_method", rb_mod_undef_method, -1);
    rb_define_private_method(rb_cModule, "alias_method", rb_mod_alias_method, 2);
    rb_define_private_method(rb_cModule, "define_method", rb_mod_define_method, -1);

    rb_define_singleton_method(rb_cModule, "nesting", rb_mod_nesting, 0);
    rb_define_singleton_method(rb_cModule, "constants", rb_mod_s_constants, 0);

    rb_define_singleton_method(ruby_top_self, "include", top_include, -1);
    rb_define_singleton_method(ruby_top_self, "public", top_public, -1);
    rb_define_singleton_method(ruby_top_self, "private", top_private, -1);

    rb_define_method(rb_mKernel, "extend", rb_obj_extend, -1);

    rb_define_global_function("trace_var", rb_f_trace_var, -1); /* in variable.c */
    rb_define_global_function("untrace_var", rb_f_untrace_var, -1); /* in variable.c */

    rb_define_global_function("set_trace_func", set_trace_func, 1);
    rb_global_variable(&trace_func);

    rb_define_virtual_variable("$SAFE", safe_getter, safe_setter);
}

/*
 *  call-seq:
 *     mod.autoload(name, filename)   => nil
 *
 *  Registers _filename_ to be loaded (using Kernel::require)
 *  the first time that _name_ (which may be a String or
 *  a symbol) is accessed in the namespace of _mod_.
 *
 *     module A
 *     end
 *     A.autoload(:B, "b")
 *     A::B.doit            # autoloads "b"
 */

static VALUE
rb_mod_autoload(mod, sym, file)
    VALUE mod;
    VALUE sym;
    VALUE file;
{
    ID id = rb_to_id(sym);

    Check_SafeStr(file);
    rb_autoload(mod, id, RSTRING(file)->ptr);
    return Qnil;
}

/*
 *  call-seq:
 *     mod.autoload?(name)   => String or nil
 *
 *  Returns _filename_ to be loaded if _name_ is registered as
 *  +autoload+ in the namespace of _mod_.
 *
 *     module A
 *     end
 *     A.autoload(:B, "b")
 *     A.autoload?(:B)            # => "b"
 */

static VALUE
rb_mod_autoload_p(mod, sym)
    VALUE mod, sym;
{
    return rb_autoload_p(mod, rb_to_id(sym));
}

/*
 *  call-seq:
 *     autoload(module, filename)   => nil
 *
 *  Registers _filename_ to be loaded (using Kernel::require)
 *  the first time that _module_ (which may be a String or
 *  a symbol) is accessed.
 *
 *     autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
 */

static VALUE
rb_f_autoload(obj, sym, file)
    VALUE obj;
    VALUE sym;
    VALUE file;
{
    if (NIL_P(ruby_cbase)) {
        rb_raise(rb_eTypeError, "no class/module for autoload target");
    }
    return rb_mod_autoload(ruby_cbase, sym, file);
}

/*
 *  call-seq:
 *     autoload(module, filename)   => nil
 *
 *  Registers _filename_ to be loaded (using Kernel::require)
 *  the first time that _module_ (which may be a String or
 *  a symbol) is accessed.
 *
 *     autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
 */

static VALUE
rb_f_autoload_p(obj, sym)
    VALUE obj;
    VALUE sym;
{
    /* use ruby_cbase as same as rb_f_autoload. */
    if (NIL_P(ruby_cbase)) {
        return Qfalse;
    }
    return rb_mod_autoload_p(ruby_cbase, sym);
}

void
Init_load()
{
    rb_define_readonly_variable("$:", &rb_load_path);
    rb_define_readonly_variable("$-I", &rb_load_path);
    rb_define_readonly_variable("$LOAD_PATH", &rb_load_path);
    rb_load_path = rb_ary_new();

    rb_define_readonly_variable("$\"", &rb_features);
    rb_define_readonly_variable("$LOADED_FEATURES", &rb_features);
    rb_features = rb_ary_new();

    rb_define_global_function("load", rb_f_load, -1);
    rb_define_global_function("require", rb_f_require, 1);
    rb_define_method(rb_cModule, "autoload",  rb_mod_autoload,   2);
    rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, 1);
    rb_define_global_function("autoload",  rb_f_autoload,   2);
    rb_define_global_function("autoload?", rb_f_autoload_p, 1);
    rb_global_variable(&ruby_wrapper);

    rb_global_variable(&ruby_dln_librefs);
    ruby_dln_librefs = rb_ary_new();
}

static void
scope_dup(scope)
    struct SCOPE *scope;
{
    ID *tbl;
    VALUE *vars;

    scope->flags |= SCOPE_DONT_RECYCLE;
    if (scope->flags & SCOPE_MALLOC) return;

    if (scope->local_tbl) {
        tbl = scope->local_tbl;
        vars = ALLOC_N(VALUE, tbl[0]+1);
        *vars++ = scope->local_vars[-1];
        MEMCPY(vars, scope->local_vars, VALUE, tbl[0]);
        scope->local_vars = vars;
        scope->flags |= SCOPE_MALLOC;
    }
}

static void
blk_mark(data)
    struct BLOCK *data;
{
    while (data) {
        rb_gc_mark_frame(&data->frame);
        rb_gc_mark((VALUE)data->scope);
        rb_gc_mark((VALUE)data->var);
        rb_gc_mark((VALUE)data->body);
        rb_gc_mark((VALUE)data->self);
        rb_gc_mark((VALUE)data->dyna_vars);
        rb_gc_mark((VALUE)data->cref);
        rb_gc_mark(data->wrapper);
        rb_gc_mark(data->block_obj);
        data = data->prev;
    }
}

static void
frame_free(frame)
    struct FRAME *frame;
{
    struct FRAME *tmp;

    frame = frame->prev;
    while (frame) {
        tmp = frame;
        frame = frame->prev;
        free(tmp);
    }
}

static void
blk_free(data)
    struct BLOCK *data;
{
    void *tmp;

    while (data) {
        frame_free(&data->frame);
        tmp = data;
        data = data->prev;
        free(tmp);
    }
}

static void
frame_dup(frame)
    struct FRAME *frame;
{
    struct FRAME *tmp;

    for (;;) {
        frame->tmp = 0;         /* should not preserve tmp */
        if (!frame->prev) break;
        tmp = ALLOC(struct FRAME);
        *tmp = *frame->prev;
        frame->prev = tmp;
        frame = tmp;
    }
}


static void
blk_copy_prev(block)
    struct BLOCK *block;
{
    struct BLOCK *tmp;
    struct RVarmap* vars;

    while (block->prev) {
        tmp = ALLOC_N(struct BLOCK, 1);
        MEMCPY(tmp, block->prev, struct BLOCK, 1);
        scope_dup(tmp->scope);
        frame_dup(&tmp->frame);

        for (vars = tmp->dyna_vars; vars; vars = vars->next) {
            if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
            FL_SET(vars, DVAR_DONT_RECYCLE);
        }

        block->prev = tmp;
        block = tmp;
    }
}


static void
blk_dup(dup, orig)
    struct BLOCK *dup, *orig;
{
    MEMCPY(dup, orig, struct BLOCK, 1);
    frame_dup(&dup->frame);

    if (dup->iter) {
        blk_copy_prev(dup);
    }
    else {
        dup->prev = 0;
    }
}

/*
 * MISSING: documentation
 */

static VALUE
proc_clone(self)
    VALUE self;
{
    struct BLOCK *orig, *data;
    VALUE bind;

    Data_Get_Struct(self, struct BLOCK, orig);
    bind = Data_Make_Struct(rb_obj_class(self),struct BLOCK,blk_mark,blk_free,data);
    CLONESETUP(bind, self);
    blk_dup(data, orig);

    return bind;
}

/*
 * MISSING: documentation
 */

#define PROC_TSHIFT (FL_USHIFT+1)
#define PROC_TMASK  (FL_USER1|FL_USER2|FL_USER3)
#define PROC_TMAX   (PROC_TMASK >> PROC_TSHIFT)

static int proc_get_safe_level(VALUE);

static VALUE
proc_dup(self)
    VALUE self;
{
    struct BLOCK *orig, *data;
    VALUE bind;
    int safe = proc_get_safe_level(self);

    Data_Get_Struct(self, struct BLOCK, orig);
    bind = Data_Make_Struct(rb_obj_class(self),struct BLOCK,blk_mark,blk_free,data);
    blk_dup(data, orig);
    if (safe > PROC_TMAX) safe = PROC_TMAX;
    FL_SET(bind, (safe << PROC_TSHIFT) & PROC_TMASK);

    return bind;
}

VALUE
rb_block_dup(self, klass, cref)
    VALUE self, klass, cref;
{
    struct BLOCK *block;
    VALUE obj = proc_dup(self);
    Data_Get_Struct(obj, struct BLOCK, block);
    block->klass = klass;
    block->cref = NEW_NODE(nd_type(block->cref), cref, block->cref->u2.node,
                           block->cref->u3.node);
    return obj;
}

/*
 *  call-seq:
 *     binding -> a_binding
 *
 *  Returns a +Binding+ object, describing the variable and
 *  method bindings at the point of call. This object can be used when
 *  calling +eval+ to execute the evaluated command in this
 *  environment. Also see the description of class +Binding+.
 *
 *     def getBinding(param)
 *       return binding
 *     end
 *     b = getBinding("hello")
 *     eval("param", b)   #=> "hello"
 */

static VALUE
rb_f_binding(self)
    VALUE self;
{
    struct BLOCK *data, *p;
    struct RVarmap *vars;
    VALUE bind;

    PUSH_BLOCK(0,0);
    bind = Data_Make_Struct(rb_cBinding,struct BLOCK,blk_mark,blk_free,data);
    *data = *ruby_block;

    data->orig_thread = rb_thread_current();
    data->wrapper = ruby_wrapper;
    data->iter = rb_f_block_given_p();
    frame_dup(&data->frame);
    if (ruby_frame->prev) {
        data->frame.last_func = ruby_frame->prev->last_func;
        data->frame.last_class = ruby_frame->prev->last_class;
        data->frame.orig_func = ruby_frame->prev->orig_func;
    }

    if (data->iter) {
        blk_copy_prev(data);
    }
    else {
        data->prev = 0;
    }

    for (p = data; p; p = p->prev) {
        for (vars = p->dyna_vars; vars; vars = vars->next) {
            if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
            FL_SET(vars, DVAR_DONT_RECYCLE);
        }
    }
    scope_dup(data->scope);
    POP_BLOCK();

    return bind;
}

/*
 *  call-seq:
 *     binding.eval(string [, filename [,lineno]])  => obj
 *
 *  Evaluates the Ruby expression(s) in string, in the
 *  binding's context.  If the optional filename and
 *  lineno parameters are present, they will be used when
 *  reporting syntax errors.
 *
 *     def getBinding(param)
 *       return binding
 *     end
 *     b = getBinding("hello")
 *     b.eval("param")   #=> "hello"
 */

static VALUE
bind_eval(argc, argv, bindval)
    int argc;
    VALUE *argv;
    VALUE bindval;
{
    VALUE args[4];

    rb_scan_args(argc, argv, "12", &args[0], &args[2], &args[3]);
    args[1] = bindval;
    return rb_f_eval(argc+1, args, Qnil /* self will be searched in eval */);
}

#define SAFE_LEVEL_MAX PROC_TMASK

static void
proc_save_safe_level(data)
    VALUE data;
{
    int safe = ruby_safe_level;
    if (safe > PROC_TMAX) safe = PROC_TMAX;
    FL_SET(data, (safe << PROC_TSHIFT) & PROC_TMASK);
}

static int
proc_get_safe_level(data)
    VALUE data;
{
    return (RBASIC(data)->flags & PROC_TMASK) >> PROC_TSHIFT;
}

static void
proc_set_safe_level(data)
    VALUE data;
{
    ruby_safe_level = proc_get_safe_level(data);
}

static VALUE
proc_alloc(klass, proc)
    VALUE klass;
    int proc;
{
    volatile VALUE block;
    struct BLOCK *data, *p;
    struct RVarmap *vars;

    if (!rb_block_given_p() && !rb_f_block_given_p()) {
        rb_raise(rb_eArgError, "tried to create Proc object without a block");
    }
    if (proc && !rb_block_given_p()) {
        rb_warn("tried to create Proc object without a block");
    }

    if (!proc && ruby_block->block_obj && CLASS_OF(ruby_block->block_obj) == klass) {
        return ruby_block->block_obj;
    }
    block = Data_Make_Struct(klass, struct BLOCK, blk_mark, blk_free, data);
    *data = *ruby_block;

    data->orig_thread = rb_thread_current();
    data->wrapper = ruby_wrapper;
    data->iter = data->prev?Qtrue:Qfalse;
    data->block_obj = block;
    frame_dup(&data->frame);
    if (data->iter) {
        blk_copy_prev(data);
    }
    else {
        data->prev = 0;
    }

    for (p = data; p; p = p->prev) {
        for (vars = p->dyna_vars; vars; vars = vars->next) {
            if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
            FL_SET(vars, DVAR_DONT_RECYCLE);
        }
    }
    scope_dup(data->scope);
    proc_save_safe_level(block);
    if (proc) {
        data->flags |= BLOCK_LAMBDA;
    }
    else {
        ruby_block->block_obj = block;
    }

    return block;
}

/*
 *  call-seq:
 *     Proc.new {|...| block } => a_proc
 *     Proc.new                => a_proc
 *
 *  Creates a new Proc object, bound to the current
 *  context. Proc::new may be called without a block only
 *  within a method with an attached block, in which case that block is
 *  converted to the Proc object.
 *
 *     def proc_from
 *       Proc.new
 *     end
 *     proc = proc_from { "hello" }
 *     proc.call   #=> "hello"
 */

static VALUE
proc_s_new(argc, argv, klass)
    int argc;
    VALUE *argv;
    VALUE klass;
{
    VALUE block = proc_alloc(klass, Qfalse);

    rb_obj_call_init(block, argc, argv);
    return block;
}

VALUE
rb_block_proc()
{
    return proc_alloc(rb_cProc, Qfalse);
}

VALUE
rb_f_lambda()
{
    rb_warn("rb_f_lambda() is deprecated; use rb_block_proc() instead");
    return proc_alloc(rb_cProc, Qtrue);
}

/*
 * call-seq:
 *   proc   { |...| block }  => a_proc
 *   lambda { |...| block }  => a_proc
 *
 * Equivalent to Proc.new, except the resulting Proc objects
 * check the number of parameters passed when called.
 */

static VALUE
proc_lambda()
{
    return proc_alloc(rb_cProc, Qtrue);
}

static int
block_orphan(data)
    struct BLOCK *data;
{
    if (data->scope->flags & SCOPE_NOSTACK) {
        return 1;
    }
    if (data->orig_thread != rb_thread_current()) {
        return 1;
    }
    return 0;
}

static VALUE
proc_invoke(proc, args, self, klass)
    VALUE proc, args;           /* OK */
    VALUE self, klass;
{
    struct BLOCK * volatile old_block;
    struct BLOCK _block;
    struct BLOCK *data;
    volatile VALUE result = Qundef;
    int state;
    volatile int safe = ruby_safe_level;
    volatile VALUE old_wrapper = ruby_wrapper;
    volatile int pcall;
    int avalue = Qtrue;
    VALUE tmp = args;
    VALUE bvar = Qnil;

    if (rb_block_given_p() && ruby_frame->last_func) {
        if (klass != ruby_frame->last_class)
            klass = rb_obj_class(proc);
        bvar = rb_block_proc();
    }

    Data_Get_Struct(proc, struct BLOCK, data);
    pcall = (data->flags & BLOCK_LAMBDA) ? YIELD_LAMBDA_CALL : 0;
    if (!pcall && RARRAY(args)->len == 1) {
        avalue = Qfalse;
        args = RARRAY(args)->ptr[0];
    }

    PUSH_VARS();
    ruby_wrapper = data->wrapper;
    ruby_dyna_vars = data->dyna_vars;
    /* PUSH BLOCK from data */
    old_block = ruby_block;
    _block = *data;
    _block.block_obj = bvar;
    if (self != Qundef) _block.frame.self = self;
    if (klass) _block.frame.last_class = klass;
    _block.frame.argc = RARRAY(tmp)->len;
    _block.frame.flags = ruby_frame->flags;
    if (_block.frame.argc && DMETHOD_P()) {
        NEWOBJ(scope, struct SCOPE);
        OBJSETUP(scope, tmp, T_SCOPE);
        scope->local_tbl = _block.scope->local_tbl;
        scope->local_vars = _block.scope->local_vars;
        scope->flags |= SCOPE_CLONE | (_block.scope->flags & SCOPE_MALLOC);
        _block.scope = scope;
    }
    /* modify current frame */
    ruby_block = &_block;
    PUSH_ITER(ITER_CUR);
    ruby_frame->iter = ITER_CUR;
    PUSH_TAG(pcall ? PROT_LAMBDA : PROT_EMPTY);
    state = EXEC_TAG();
    if (state == 0) {
        proc_set_safe_level(proc);
        result = rb_yield_0(args, self, (self!=Qundef)?CLASS_OF(self):0,
                            pcall | YIELD_PROC_CALL, avalue);
    }
    else if (TAG_DST()) {
        result = prot_tag->retval;
    }
    POP_TAG();
    POP_ITER();
    ruby_block = old_block;
    ruby_wrapper = old_wrapper;
    POP_VARS();
    ruby_safe_level = safe;

    switch (state) {
      case 0:
        break;
      case TAG_RETRY:
        proc_jump_error(TAG_RETRY, Qnil); /* xxx */
        JUMP_TAG(state);
        break;
      case TAG_NEXT:
      case TAG_BREAK:
        if (!pcall && result != Qundef) {
            proc_jump_error(state, result);
        }
      case TAG_RETURN:
        if (result != Qundef) {
            if (pcall) break;
            return_jump(result);
        }
      default:
        JUMP_TAG(state);
    }
    return result;
}

/* CHECKME: are the argument checking semantics correct? */

/*
 *  call-seq:
 *     prc.call(params,...)   => obj
 *     prc[params,...]        => obj
 *
 *  Invokes the block, setting the block's parameters to the values in
 *  params using something close to method calling semantics.
 *  Generates a warning if multiple values are passed to a proc that
 *  expects just one (previously this silently converted the parameters
 *  to an array).
 *
 *  For procs created using Kernel.proc, generates an
 *  error if the wrong number of parameters
 *  are passed to a proc with multiple parameters. For procs created using
 *  Proc.new, extra parameters are silently discarded.
 *
 *  Returns the value of the last expression evaluated in the block. See
 *  also Proc#yield.
 *
 *     a_proc = Proc.new {|a, *b| b.collect {|i| i*a }}
 *     a_proc.call(9, 1, 2, 3)   #=> [9, 18, 27]
 *     a_proc[9, 1, 2, 3]        #=> [9, 18, 27]
 *     a_proc = Proc.new {|a,b| a}
 *     a_proc.call(1,2,3)
 *
 *  produces:
 *
 *     prog.rb:5: wrong number of arguments (3 for 2) (ArgumentError)
 *      from prog.rb:4:in `call'
 *      from prog.rb:5
 */

VALUE
rb_proc_call(proc, args)
    VALUE proc, args;           /* OK */
{
    return proc_invoke(proc, args, Qundef, 0);
}

static VALUE bmcall _((VALUE, VALUE));
static VALUE method_arity _((VALUE));

/*
 *  call-seq:
 *     prc.arity -> fixnum
 *
 *  Returns the number of arguments that would not be ignored. If the block
 *  is declared to take no arguments, returns 0. If the block is known
 *  to take exactly n arguments, returns n. If the block has optional
 *  arguments, return -n-1, where n is the number of mandatory
 *  arguments. A proc with no argument declarations
 *  is the same a block declaring || as its arguments.
 *
 *     Proc.new {}.arity          #=>  0
 *     Proc.new {||}.arity        #=>  0
 *     Proc.new {|a|}.arity       #=>  1
 *     Proc.new {|a,b|}.arity     #=>  2
 *     Proc.new {|a,b,c|}.arity   #=>  3
 *     Proc.new {|*a|}.arity      #=> -1
 *     Proc.new {|a,*b|}.arity    #=> -2
 */

static VALUE
proc_arity(proc)
    VALUE proc;
{
    struct BLOCK *data;
    NODE *var, *list;
    int n;

    Data_Get_Struct(proc, struct BLOCK, data);
    var = data->var;
    if (var == 0) {
        if (data->body && nd_type(data->body) == NODE_IFUNC &&
            data->body->nd_cfnc == bmcall) {
            return method_arity(data->body->nd_tval);
        }
        return INT2FIX(-1);
    }
    if (var == (NODE*)1) return INT2FIX(0);
    if (var == (NODE*)2) return INT2FIX(0);
    if (nd_type(var) == NODE_BLOCK_ARG) {
        var = var->nd_args;
        if (var == (NODE*)1) return INT2FIX(0);
        if (var == (NODE*)2) return INT2FIX(0);
    }
    switch (nd_type(var)) {
      default:
        return INT2FIX(1);
      case NODE_MASGN:
        list = var->nd_head;
        n = 0;
        while (list) {
            n++;
            list = list->nd_next;
        }
        if (var->nd_args) return INT2FIX(-n-1);
        return INT2FIX(n);
    }
}

/*
 * call-seq:
 *   prc == other_proc   =>  true or false
 *
 * Return true if prc is the same object as
 * other_proc, or if they are both procs with the same body.
 */

static VALUE
proc_eq(self, other)
    VALUE self, other;
{
    struct BLOCK *data, *data2;

    if (self == other) return Qtrue;
    if (TYPE(other) != T_DATA) return Qfalse;
    if (RDATA(other)->dmark != (RUBY_DATA_FUNC)blk_mark) return Qfalse;
    if (CLASS_OF(self) != CLASS_OF(other)) return Qfalse;
    Data_Get_Struct(self, struct BLOCK, data);
    Data_Get_Struct(other, struct BLOCK, data2);
    if (data->body != data2->body) return Qfalse;
    if (data->var != data2->var) return Qfalse;
    if (data->scope != data2->scope) return Qfalse;
    if (data->dyna_vars != data2->dyna_vars) return Qfalse;
    if (data->flags != data2->flags) return Qfalse;

    return Qtrue;
}

/*
 * call-seq:
 *   prc.to_s   => string
 *
 * Shows the unique identifier for this proc, along with
 * an indication of where the proc was defined.
 */

static VALUE
proc_to_s(self)
    VALUE self;
{
    struct BLOCK *data;
    NODE *node;
    const char *cname = rb_obj_classname(self);
    const int w = (sizeof(VALUE) * CHAR_BIT) / 4;
    long len = strlen(cname)+6+w; /* 6:tags 16:addr */
    VALUE str;

    Data_Get_Struct(self, struct BLOCK, data);
    if ((node = data->frame.node) || (node = data->body)) {
        len += strlen(node->nd_file) + 2 + (SIZEOF_LONG*CHAR_BIT-NODE_LSHIFT)/3;
        str = rb_str_new(0, len);
        snprintf(RSTRING(str)->ptr, len+1,
                 "#<%s:0x%.*lx@%s:%d>", cname, w, (VALUE)data->body,
                 node->nd_file, nd_line(node));
    }
    else {
        str = rb_str_new(0, len);
        snprintf(RSTRING(str)->ptr, len+1,
                 "#<%s:0x%.*lx>", cname, w, (VALUE)data->body);
    }
    RSTRING(str)->len = strlen(RSTRING(str)->ptr);
    if (OBJ_TAINTED(self)) OBJ_TAINT(str);

    return str;
}

/*
 *  call-seq:
 *     prc.to_proc -> prc
 *
 *  Part of the protocol for converting objects to Proc
 *  objects. Instances of class Proc simply return
 *  themselves.
 */

static VALUE
proc_to_self(self)
    VALUE self;
{
    return self;
}

/*
 *  call-seq:
 *     prc.binding    => binding
 *
 *  Returns the binding associated with prc. Note that
 *  Kernel#eval accepts either a Proc or a
 *  Binding object as its second parameter.
 *
 *     def fred(param)
 *       proc {}
 *     end
 *
 *     b = fred(99)
 *     eval("param", b.binding)   #=> 99
 *     eval("param", b)           #=> 99
 */

static VALUE
proc_binding(proc)
    VALUE proc;
{
    struct BLOCK *orig, *data;
    VALUE bind;

    Data_Get_Struct(proc, struct BLOCK, orig);
    bind = Data_Make_Struct(rb_cBinding,struct BLOCK,blk_mark,blk_free,data);
    MEMCPY(data, orig, struct BLOCK, 1);
    frame_dup(&data->frame);

    if (data->iter) {
        blk_copy_prev(data);
    }
    else {
        data->prev = 0;
    }

    return bind;
}

static VALUE
block_pass(self, node)
    VALUE self;
    NODE *node;
{
    VALUE proc = rb_eval(self, node->nd_body);  /* OK */
    VALUE b;
    struct BLOCK * volatile old_block;
    struct BLOCK _block;
    struct BLOCK *data;
    VALUE result;
    int state;
    volatile int orphan;
    volatile int safe = ruby_safe_level;

    if (NIL_P(proc)) {
        PUSH_ITER(ITER_NOT);
        result = rb_eval(self, node->nd_iter);
        POP_ITER();
        return result;
    }
    if (!rb_obj_is_proc(proc)) {
        b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc");
        if (!rb_obj_is_proc(b)) {
            rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc)",
                     rb_obj_classname(proc));
        }
        proc = b;
    }

    if (ruby_safe_level >= 1 && OBJ_TAINTED(proc) &&
        ruby_safe_level > proc_get_safe_level(proc)) {
        rb_raise(rb_eSecurityError, "Insecure: tainted block value");
    }

    if (ruby_block && ruby_block->block_obj == proc) {
        PUSH_ITER(ITER_PAS);
        result = rb_eval(self, node->nd_iter);
        POP_ITER();
        return result;
    }

    Data_Get_Struct(proc, struct BLOCK, data);
    orphan = block_orphan(data);

    /* PUSH BLOCK from data */
    old_block = ruby_block;
    _block = *data;
    _block.outer = ruby_block;
    if (orphan) _block.uniq = block_unique++;
    ruby_block = &_block;
    PUSH_ITER(ITER_PRE);
    if (ruby_frame->iter == ITER_NOT)
        ruby_frame->iter = ITER_PRE;

    PUSH_TAG(PROT_LOOP);
    state = EXEC_TAG();
    switch (state) {
      case TAG_RETRY:
        state = 0;
      case 0:
        proc_set_safe_level(proc);
        if (safe > ruby_safe_level)
            ruby_safe_level = safe;
        result = rb_eval(self, node->nd_iter);
        break;
      case TAG_BREAK:
        result = Qnil;
        if (TAG_DST()) {
          result = prot_tag->retval;
          state = 0;
        }
        break;
      default:
        result = Qnil;
    }
    POP_TAG();
    POP_ITER();
    ruby_block = old_block;
    ruby_safe_level = safe;

    switch (state) {/* escape from orphan block */
      case 0:
        break;
      case TAG_RETURN:
        if (orphan) {
            proc_jump_error(state, prot_tag->retval);
        }
      default:
        JUMP_TAG(state);
    }

    return result;
}

struct METHOD {
    VALUE klass, rklass;
    VALUE recv;
    ID id, oid;
    int safe_level;
    NODE *body;
};

static void
bm_mark(data)
    struct METHOD *data;
{
    rb_gc_mark(data->rklass);
    rb_gc_mark(data->klass);
    rb_gc_mark(data->recv);
    rb_gc_mark((VALUE)data->body);
}

static VALUE
mnew(klass, obj, id, mklass)
    VALUE klass, obj, mklass;
    ID id;
{
    VALUE method;
    NODE *body;
    int noex;
    struct METHOD *data;
    VALUE rklass = klass;
    ID oid = id;

  again:
    if ((body = rb_get_method_body(&klass, &oid, &noex)) == 0) {
        print_undef(rklass, id);
    }

    if (nd_type(body) == NODE_ZSUPER) {
        klass = RCLASS(klass)->super;
        goto again;
    }

    while (rklass != klass &&
           (FL_TEST(rklass, FL_SINGLETON) || TYPE(rklass) == T_ICLASS)) {
        rklass = RCLASS(rklass)->super;
    }
    if (TYPE(klass) == T_ICLASS) klass = RBASIC(klass)->klass;
    method = Data_Make_Struct(mklass, struct METHOD, bm_mark, free, data);
    data->klass = klass;
    data->recv = obj;
    data->id = id;
    data->body = body;
    data->rklass = rklass;
    data->oid = oid;
    data->safe_level = NOEX_WITH_SAFE(noex);
    OBJ_INFECT(method, klass);

    return method;
}


/**********************************************************************
 *
 * Document-class : Method
 *
 *  Method objects are created by Object#method, and are
 *  associated with a particular object (not just with a class). They
 *  may be used to invoke the method within the object, and as a block
 *  associated with an iterator. They may also be unbound from one
 *  object (creating an UnboundMethod) and bound to
 *  another.
 *
 *     class Thing
 *       def square(n)
 *         n*n
 *       end
 *     end
 *     thing = Thing.new
 *     meth  = thing.method(:square)
 *
 *     meth.call(9)                 #=> 81
 *     [ 1, 2, 3 ].collect(&meth)   #=> [1, 4, 9]
 *
 */

/*
 * call-seq:
 *   meth == other_meth  => true or false
 *
 * Two method objects are equal if that are bound to the same
 * object and contain the same body.
 */


static VALUE
method_eq(method, other)
    VALUE method, other;
{
    struct METHOD *m1, *m2;

    if (TYPE(other) != T_DATA || RDATA(other)->dmark != (RUBY_DATA_FUNC)bm_mark)
        return Qfalse;
    if (CLASS_OF(method) != CLASS_OF(other))
        return Qfalse;

    Data_Get_Struct(method, struct METHOD, m1);
    Data_Get_Struct(other, struct METHOD, m2);

    if (m1->klass != m2->klass || m1->rklass != m2->rklass ||
        m1->recv != m2->recv || m1->body != m2->body)
        return Qfalse;

    return Qtrue;
}

/*
 *  call-seq:
 *     meth.unbind    => unbound_method
 *
 *  Dissociates meth from it's current receiver. The resulting
 *  UnboundMethod can subsequently be bound to a new object
 *  of the same class (see UnboundMethod).
 */

static VALUE
method_unbind(obj)
    VALUE obj;
{
    VALUE method;
    struct METHOD *orig, *data;

    Data_Get_Struct(obj, struct METHOD, orig);
    method = Data_Make_Struct(rb_cUnboundMethod, struct METHOD, bm_mark, free, data);
    data->klass = orig->klass;
    data->recv = Qundef;
    data->id = orig->id;
    data->body = orig->body;
    data->rklass = orig->rklass;
    data->oid = orig->oid;
    OBJ_INFECT(method, obj);

    return method;
}

/*
 *  call-seq:
 *     meth.receiver    => object
 *
 *  Returns the bound receiver of the method object.
 */

static VALUE
method_receiver(obj)
    VALUE obj;
{
    struct METHOD *data;

    Data_Get_Struct(obj, struct METHOD, data);
    return data->recv;
}

/*
 *  call-seq:
 *     meth.name    => string
 *
 *  Returns the name of the method.
 */

static VALUE
method_name(obj)
    VALUE obj;
{
    struct METHOD *data;

    Data_Get_Struct(obj, struct METHOD, data);
    return rb_str_new2(rb_id2name(data->id));
}

/*
 *  call-seq:
 *     meth.owner    => class_or_module
 *
 *  Returns the class or module that defines the method.
 */

static VALUE
method_owner(obj)
    VALUE obj;
{
    struct METHOD *data;

    Data_Get_Struct(obj, struct METHOD, data);
    return data->klass;
}

/*
 *  call-seq:
 *     obj.method(sym)    => method
 *
 *  Looks up the named method as a receiver in obj, returning a
 *  Method object (or raising NameError). The
 *  Method object acts as a closure in obj's object
 *  instance, so instance variables and the value of self
 *  remain available.
 *
 *     class Demo
 *       def initialize(n)
 *         @iv = n
 *       end
 *       def hello()
 *         "Hello, @iv = #{@iv}"
 *       end
 *     end
 *
 *     k = Demo.new(99)
 *     m = k.method(:hello)
 *     m.call   #=> "Hello, @iv = 99"
 *
 *     l = Demo.new('Fred')
 *     m = l.method("hello")
 *     m.call   #=> "Hello, @iv = Fred"
 */

VALUE
rb_obj_method(obj, vid)
    VALUE obj;
    VALUE vid;
{
    return mnew(CLASS_OF(obj), obj, rb_to_id(vid), rb_cMethod);
}

/*
 *  call-seq:
 *     mod.instance_method(symbol)   => unbound_method
 *
 *  Returns an +UnboundMethod+ representing the given
 *  instance method in _mod_.
 *
 *     class Interpreter
 *       def do_a() print "there, "; end
 *       def do_d() print "Hello ";  end
 *       def do_e() print "!\n";     end
 *       def do_v() print "Dave";    end
 *       Dispatcher = {
 *        ?a => instance_method(:do_a),
 *        ?d => instance_method(:do_d),
 *        ?e => instance_method(:do_e),
 *        ?v => instance_method(:do_v)
 *       }
 *       def interpret(string)
 *         string.each_byte {|b| Dispatcher[b].bind(self).call }
 *       end
 *     end
 *
 *
 *     interpreter = Interpreter.new
 *     interpreter.interpret('dave')
 *
 *  produces:
 *
 *     Hello there, Dave!
 */

static VALUE
rb_mod_method(mod, vid)
    VALUE mod;
    VALUE vid;
{
    return mnew(mod, Qundef, rb_to_id(vid), rb_cUnboundMethod);
}

/*
 * MISSING: documentation
 */

static VALUE
method_clone(self)
    VALUE self;
{
    VALUE clone;
    struct METHOD *orig, *data;

    Data_Get_Struct(self, struct METHOD, orig);
    clone = Data_Make_Struct(CLASS_OF(self),struct METHOD, bm_mark, free, data);
    CLONESETUP(clone, self);
    *data = *orig;

    return clone;
}

VALUE
rb_method_dup(self, klass, cref)
    VALUE self;
    VALUE klass;
    VALUE cref;
{
    VALUE clone;
    struct METHOD *orig, *data;

    Data_Get_Struct(self, struct METHOD, orig);
    clone = Data_Make_Struct(CLASS_OF(self),struct METHOD, bm_mark, free, data);
    *data = *orig;
    data->rklass = klass;
    if (data->body->nd_rval) {
        NODE *tmp = NEW_NODE(nd_type(data->body->u2.node), cref,
                             data->body->u2.node->u2.node,
                             data->body->u2.node->u3.node);
        data->body = NEW_NODE(nd_type(data->body), data->body->u1.node, tmp,
                              data->body->u3.node);
    }
    return clone;
}

/*
 *  call-seq:
 *     meth.call(args, ...)    => obj
 *     meth[args, ...]         => obj
 *
 *  Invokes the meth with the specified arguments, returning the
 *  method's return value.
 *
 *     m = 12.method("+")
 *     m.call(3)    #=> 15
 *     m.call(20)   #=> 32
 */

static VALUE
method_call(argc, argv, method)
    int argc;
    VALUE *argv;
    VALUE method;
{
    VALUE result = Qnil;        /* OK */
    struct METHOD *data;
    int safe;

    Data_Get_Struct(method, struct METHOD, data);
    if (data->recv == Qundef) {
        rb_raise(rb_eTypeError, "can't call unbound method; bind first");
    }
    if (OBJ_TAINTED(method)) {
        safe = NOEX_WITH(data->safe_level, 4)|NOEX_TAINTED;
    }
    else {
        safe = data->safe_level;
    }
    PUSH_ITER(rb_block_given_p()?ITER_PRE:ITER_NOT);
    result = rb_call0(data->klass,data->recv,data->id,data->oid,argc,argv,data->body,safe);
    POP_ITER();
    return result;
}

/**********************************************************************
 *
 * Document-class: UnboundMethod
 *
 *  Ruby supports two forms of objectified methods. Class
 *  Method is used to represent methods that are associated
 *  with a particular object: these method objects are bound to that
 *  object. Bound method objects for an object can be created using
 *  Object#method.
 *
 *  Ruby also supports unbound methods; methods objects that are not
 *  associated with a particular object. These can be created either by
 *  calling Module#instance_method or by calling
 *  unbind on a bound method object. The result of both of
 *  these is an UnboundMethod object.
 *
 *  Unbound methods can only be called after they are bound to an
 *  object. That object must be be a kind_of? the method's original
 *  class.
 *
 *     class Square
 *       def area
 *         @side * @side
 *       end
 *       def initialize(side)
 *         @side = side
 *       end
 *     end
 *
 *     area_un = Square.instance_method(:area)
 *
 *     s = Square.new(12)
 *     area = area_un.bind(s)
 *     area.call   #=> 144
 *
 *  Unbound methods are a reference to the method at the time it was
 *  objectified: subsequent changes to the underlying class will not
 *  affect the unbound method.
 *
 *     class Test
 *       def test
 *         :original
 *       end
 *     end
 *     um = Test.instance_method(:test)
 *     class Test
 *       def test
 *         :modified
 *       end
 *     end
 *     t = Test.new
 *     t.test            #=> :modified
 *     um.bind(t).call   #=> :original
 *
 */

/*
 *  call-seq:
 *     umeth.bind(obj) -> method
 *
 *  Bind umeth to obj. If Klass was the class
 *  from which umeth was obtained,
 *  obj.kind_of?(Klass) must be true.
 *
 *     class A
 *       def test
 *         puts "In test, class = #{self.class}"
 *       end
 *     end
 *     class B < A
 *     end
 *     class C < B
 *     end
 *
 *
 *     um = B.instance_method(:test)
 *     bm = um.bind(C.new)
 *     bm.call
 *     bm = um.bind(B.new)
 *     bm.call
 *     bm = um.bind(A.new)
 *     bm.call
 *
 *  produces:
 *
 *     In test, class = C
 *     In test, class = B
 *     prog.rb:16:in `bind': bind argument must be an instance of B (TypeError)
 *      from prog.rb:16
 */

static VALUE
umethod_bind(method, recv)
    VALUE method, recv;
{
    struct METHOD *data, *bound;
    VALUE rklass = CLASS_OF(recv);

    Data_Get_Struct(method, struct METHOD, data);
    if (data->rklass != rklass) {
        if (FL_TEST(data->rklass, FL_SINGLETON)) {
            rb_raise(rb_eTypeError, "singleton method bound for a different object");
        }
        if (TYPE(data->rklass) == T_MODULE) {
            st_table *m_tbl = RCLASS(data->rklass)->m_tbl;
            while (RCLASS(rklass)->m_tbl != m_tbl) {
                rklass = RCLASS(rklass)->super;
                if (!rklass) goto not_instace;
            }
        }
        else if (!rb_obj_is_kind_of(recv, data->rklass)) {
          not_instace:
            rb_raise(rb_eTypeError, "bind argument must be an instance of %s",
                     rb_class2name(data->rklass));
        }
    }

    method = Data_Make_Struct(rb_cMethod,struct METHOD,bm_mark,free,bound);
    *bound = *data;
    bound->recv = recv;
    bound->rklass = rklass;

    return method;
}

/*
 *  call-seq:
 *     meth.arity    => fixnum
 *
 *  Returns an indication of the number of arguments accepted by a
 *  method. Returns a nonnegative integer for methods that take a fixed
 *  number of arguments. For Ruby methods that take a variable number of
 *  arguments, returns -n-1, where n is the number of required
 *  arguments. For methods written in C, returns -1 if the call takes a
 *  variable number of arguments.
 *
 *     class C
 *       def one;    end
 *       def two(a); end
 *       def three(*a);  end
 *       def four(a, b); end
 *       def five(a, b, *c);    end
 *       def six(a, b, *c, &d); end
 *     end
 *     c = C.new
 *     c.method(:one).arity     #=> 0
 *     c.method(:two).arity     #=> 1
 *     c.method(:three).arity   #=> -1
 *     c.method(:four).arity    #=> 2
 *     c.method(:five).arity    #=> -3
 *     c.method(:six).arity     #=> -3
 *
 *     "cat".method(:size).arity      #=> 0
 *     "cat".method(:replace).arity   #=> 1
 *     "cat".method(:squeeze).arity   #=> -1
 *     "cat".method(:count).arity     #=> -1
 */

static VALUE
method_arity(method)
    VALUE method;
{
    struct METHOD *data;
    NODE *body;
    int n;

    Data_Get_Struct(method, struct METHOD, data);

    body = data->body;
    switch (nd_type(body)) {
      case NODE_CFUNC:
        if (body->nd_argc < 0) return INT2FIX(-1);
        return INT2FIX(body->nd_argc);
      case NODE_ZSUPER:
        return INT2FIX(-1);
      case NODE_ATTRSET:
        return INT2FIX(1);
      case NODE_IVAR:
        return INT2FIX(0);
      case NODE_BMETHOD:
        return proc_arity(body->nd_cval);
      case NODE_DMETHOD:
        return method_arity(body->nd_cval);
      case NODE_SCOPE:
        body = body->nd_next;   /* skip NODE_SCOPE */
        if (nd_type(body) == NODE_BLOCK)
            body = body->nd_head;
        if (!body) return INT2FIX(0);
        n = body->nd_cnt;
        if (body->nd_opt || body->nd_rest)
            n = -n-1;
        return INT2FIX(n);
      default:
        rb_raise(rb_eArgError, "invalid node 0x%x", nd_type(body));
   }
}

/*
 *  call-seq:
 *   meth.to_s      =>  string
 *   meth.inspect   =>  string
 *
 *  Show the name of the underlying method.
 *
 *    "cat".method(:count).inspect   #=> "#"
 */

static VALUE
method_inspect(method)
    VALUE method;
{
    struct METHOD *data;
    VALUE str;
    const char *s;
    const char *sharp = "#";

    Data_Get_Struct(method, struct METHOD, data);
    str = rb_str_buf_new2("#<");
    s = rb_obj_classname(method);
    rb_str_buf_cat2(str, s);
    rb_str_buf_cat2(str, ": ");

    if (FL_TEST(data->klass, FL_SINGLETON)) {
        VALUE v = rb_iv_get(data->klass, "__attached__");

        if (data->recv == Qundef) {
            rb_str_buf_append(str, rb_inspect(data->klass));
        }
        else if (data->recv == v) {
            rb_str_buf_append(str, rb_inspect(v));
            sharp = ".";
        }
        else {
            rb_str_buf_append(str, rb_inspect(data->recv));
            rb_str_buf_cat2(str, "(");
            rb_str_buf_append(str, rb_inspect(v));
            rb_str_buf_cat2(str, ")");
            sharp = ".";
        }
    }
    else {
        rb_str_buf_cat2(str, rb_class2name(data->rklass));
        if (data->rklass != data->klass) {
            rb_str_buf_cat2(str, "(");
            rb_str_buf_cat2(str, rb_class2name(data->klass));
            rb_str_buf_cat2(str, ")");
        }
    }
    rb_str_buf_cat2(str, sharp);
    rb_str_buf_cat2(str, rb_id2name(data->id));
    rb_str_buf_cat2(str, ">");

    return str;
}

static VALUE
mproc(method)
    VALUE method;
{
    VALUE proc;

    /* emulate ruby's method call */
    PUSH_ITER(ITER_CUR);
    PUSH_FRAME();
    _frame.last_class = 0;
    proc = rb_block_proc();
    POP_FRAME();
    POP_ITER();

    return proc;
}

static VALUE
bmcall(args, method)
    VALUE args, method;
{
    VALUE a = svalue_to_avalue(args);
    VALUE ret = method_call(RARRAY(a)->len, RARRAY(a)->ptr, method);
    RB_GC_GUARD(a);  /* ensure a is not GC'd during method_call */
    return ret;
}

VALUE
rb_proc_new(func, val)
    VALUE (*func)(ANYARGS);     /* VALUE yieldarg[, VALUE procarg] */
    VALUE val;
{
    struct BLOCK *data;
    VALUE proc = rb_iterate((VALUE(*)_((VALUE)))mproc, 0, func, val);

    Data_Get_Struct(proc, struct BLOCK, data);
    data->body->nd_state = YIELD_FUNC_LAMBDA;
    data->flags |= BLOCK_LAMBDA;
    return proc;
}

/*
 *  call-seq:
 *     meth.to_proc    => prc
 *
 *  Returns a Proc object corresponding to this method.
 */

static VALUE
method_proc(method)
    VALUE method;
{
    VALUE proc;
    struct METHOD *mdata;
    struct BLOCK *bdata;

    proc = rb_iterate((VALUE(*)_((VALUE)))mproc, 0, bmcall, method);
    Data_Get_Struct(method, struct METHOD, mdata);
    Data_Get_Struct(proc, struct BLOCK, bdata);
    bdata->body->nd_file = mdata->body->nd_file;
    nd_set_line(bdata->body, nd_line(mdata->body));
    bdata->body->nd_state = YIELD_FUNC_SVALUE;

    return proc;
}

static VALUE
rb_obj_is_method(m)
    VALUE m;
{
    if (TYPE(m) == T_DATA && RDATA(m)->dmark == (RUBY_DATA_FUNC)bm_mark) {
        return Qtrue;
    }
    return Qfalse;
}

/*
 *  call-seq:
 *     define_method(symbol, method)     => new_method
 *     define_method(symbol) { block }   => proc
 *
 *  Defines an instance method in the receiver. The _method_
 *  parameter can be a +Proc+ or +Method+ object.
 *  If a block is specified, it is used as the method body. This block
 *  is evaluated using instance_eval, a point that is
 *  tricky to demonstrate because define_method is private.
 *  (This is why we resort to the +send+ hack in this example.)
 *
 *     class A
 *       def fred
 *         puts "In Fred"
 *       end
 *       def create_method(name, &block)
 *         self.class.send(:define_method, name, &block)
 *       end
 *       define_method(:wilma) { puts "Charge it!" }
 *     end
 *     class B < A
 *       define_method(:barney, instance_method(:fred))
 *     end
 *     a = B.new
 *     a.barney
 *     a.wilma
 *     a.create_method(:betty) { p self }
 *     a.betty
 *
 *  produces:
 *
 *     In Fred
 *     Charge it!
 *     #
 */

static VALUE
rb_mod_define_method(argc, argv, mod)
    int argc;
    VALUE *argv;
    VALUE mod;
{
    ID id;
    VALUE body;
    NODE *node;
    int noex;

    if (argc == 1) {
        id = rb_to_id(argv[0]);
        body = proc_lambda();
    }
    else if (argc == 2) {
        id = rb_to_id(argv[0]);
        body = argv[1];
        if (!rb_obj_is_method(body) && !rb_obj_is_proc(body)) {
            rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc/Method)",
                     rb_obj_classname(body));
        }
    }
    else {
        rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc);
    }
    GC_DEBUG_SET_SOURCE
    if (RDATA(body)->dmark == (RUBY_DATA_FUNC)bm_mark) {
        node = NEW_DMETHOD(method_unbind(body));
    }
    else if (RDATA(body)->dmark == (RUBY_DATA_FUNC)blk_mark) {
        struct BLOCK *block;

        body = proc_clone(body);
        Data_Get_Struct(body, struct BLOCK, block);
        block->frame.last_func = id;
        block->frame.orig_func = id;
        block->frame.last_class = mod;
        node = NEW_BMETHOD(body);
    }
    else {
        /* type error */
        rb_raise(rb_eTypeError, "wrong argument type (expected Proc/Method)");
    }

    noex = NOEX_PUBLIC;
    if (ruby_cbase == mod) {
        if (SCOPE_TEST(SCOPE_PRIVATE)) {
            noex = NOEX_PRIVATE;
        }
        else if (SCOPE_TEST(SCOPE_PROTECTED)) {
            noex = NOEX_PROTECTED;
        }
    }
    rb_add_method(mod, id, node, noex);
    return body;
}


#ifdef MBARI_API
/*
 * call-seq:
 *    meth.__file__  => String
 *
 * returns the filename containing this method's definition
 *
 * raises ArgumentError if method has no associated ruby source code
 *
 * Only available when MBARI_API extentions are enabled at build time
 */

static VALUE
method_source_file_name(VALUE method)
{
    struct METHOD *data;
    NODE *node;

    Data_Get_Struct(method, struct METHOD, data);
    if (node = data->body) {
      const char *filename = node->nd_file;
      if (filename)
        return rb_str_new2(filename);
    }
    rb_raise(rb_eArgError, "native Method");
}

/*
 * call-seq:
 *    meth.__line__  => Fixnum
 *
 * returns the starting line number of this method
 *
 * raises ArgumentError if method has no associated ruby source code
 *
 * Only available when MBARI_API extentions are enabled at build time
 */

static VALUE
method_source_line(VALUE method)
{
    struct METHOD *data;
    NODE *node;

    Data_Get_Struct(method, struct METHOD, data);
    if (node = data->body) {
      int lineno = nd_line(node);
      if (lineno)
        return INT2FIX(nd_line(node));
    }
    rb_raise(rb_eArgError, "native Method");
}


/*
 * call-seq:
 *    prc.__file__  => String
 *
 * returns the filename where this proc is defined
 *
 * raises ArgumentError if proc has no associated ruby source
 *
 * Only available when MBARI_API extentions are enabled at build time
 */

static VALUE
proc_source_file_name(VALUE block)
{
    struct BLOCK *data;
    const char *filename;
    NODE *node;

    Data_Get_Struct(block, struct BLOCK, data);
    if ((node = data->frame.node) || (node = data->body))
      return rb_str_new2(node->nd_file);
    rb_raise(rb_eArgError, "native Proc");
}


/*
 * call-seq:
 *    prc.__line__  => Fixnum
 *
 * returns the starting line number of this proc
 *
 * raises ArgumentError if proc has no associated ruby source code
 *
 * Only available when MBARI_API extentions are enabled at build time
 */

static VALUE
proc_source_line(VALUE block)
{
    struct BLOCK *data;
    NODE *node;

    Data_Get_Struct(block, struct BLOCK, data);
    if ((node = data->frame.node) || (node = data->body))
      return INT2FIX( nd_line(node) );
    rb_raise(rb_eArgError, "native Proc");
}

#endif  /* MBARI_API */


/*
 *  Proc objects are blocks of code that have been bound to
 *  a set of local variables. Once bound, the code may be called in
 *  different contexts and still access those variables.
 *
 *     def gen_times(factor)
 *       return Proc.new {|n| n*factor }
 *     end
 *
 *     times3 = gen_times(3)
 *     times5 = gen_times(5)
 *
 *     times3.call(12)               #=> 36
 *     times5.call(5)                #=> 25
 *     times3.call(times5.call(4))   #=> 60
 *
 */

void
Init_Proc()
{
    rb_eLocalJumpError = rb_define_class("LocalJumpError", rb_eStandardError);
    rb_define_method(rb_eLocalJumpError, "exit_value", localjump_xvalue, 0);
    rb_define_method(rb_eLocalJumpError, "reason", localjump_reason, 0);

    rb_global_variable(&exception_error);
    exception_error = rb_exc_new3(rb_eFatal,
                                  rb_obj_freeze(rb_str_new2("exception reentered")));
    OBJ_TAINT(exception_error);
    OBJ_FREEZE(exception_error);

    rb_eSysStackError = rb_define_class("SystemStackError", rb_eStandardError);
    rb_global_variable(&sysstack_error);
    sysstack_error = rb_exc_new3(rb_eSysStackError,
                                 rb_obj_freeze(rb_str_new2("stack level too deep")));
    OBJ_TAINT(sysstack_error);
    OBJ_FREEZE(sysstack_error);

    rb_cProc = rb_define_class("Proc", rb_cObject);
    rb_undef_alloc_func(rb_cProc);
    rb_define_singleton_method(rb_cProc, "new", proc_s_new, -1);

    rb_define_method(rb_cProc, "clone", proc_clone, 0);
    rb_define_method(rb_cProc, "dup", proc_dup, 0);
    rb_define_method(rb_cProc, "call", rb_proc_call, -2);
    rb_define_method(rb_cProc, "arity", proc_arity, 0);
    rb_define_method(rb_cProc, "[]", rb_proc_call, -2);
    rb_define_method(rb_cProc, "==", proc_eq, 1);
    rb_define_method(rb_cProc, "to_s", proc_to_s, 0);
    rb_define_method(rb_cProc, "to_proc", proc_to_self, 0);
    rb_define_method(rb_cProc, "binding", proc_binding, 0);

    rb_define_global_function("proc", proc_lambda, 0);
    rb_define_global_function("lambda", proc_lambda, 0);

    rb_cMethod = rb_define_class("Method", rb_cObject);
    rb_undef_alloc_func(rb_cMethod);
    rb_undef_method(CLASS_OF(rb_cMethod), "new");
    rb_define_method(rb_cMethod, "==", method_eq, 1);
    rb_define_method(rb_cMethod, "clone", method_clone, 0);
    rb_define_method(rb_cMethod, "call", method_call, -1);
    rb_define_method(rb_cMethod, "[]", method_call, -1);
    rb_define_method(rb_cMethod, "arity", method_arity, 0);
    rb_define_method(rb_cMethod, "inspect", method_inspect, 0);
    rb_define_method(rb_cMethod, "to_s", method_inspect, 0);
    rb_define_method(rb_cMethod, "to_proc", method_proc, 0);
    rb_define_method(rb_cMethod, "receiver", method_receiver, 0);
    rb_define_method(rb_cMethod, "name", method_name, 0);
    rb_define_method(rb_cMethod, "owner", method_owner, 0);
    rb_define_method(rb_cMethod, "unbind", method_unbind, 0);
    rb_define_method(rb_mKernel, "method", rb_obj_method, 1);

    rb_cUnboundMethod = rb_define_class("UnboundMethod", rb_cObject);
    rb_undef_alloc_func(rb_cUnboundMethod);
    rb_undef_method(CLASS_OF(rb_cUnboundMethod), "new");
    rb_define_method(rb_cUnboundMethod, "==", method_eq, 1);
    rb_define_method(rb_cUnboundMethod, "clone", method_clone, 0);
    rb_define_method(rb_cUnboundMethod, "arity", method_arity, 0);
    rb_define_method(rb_cUnboundMethod, "inspect", method_inspect, 0);
    rb_define_method(rb_cUnboundMethod, "to_s", method_inspect, 0);
    rb_define_method(rb_cUnboundMethod, "name", method_name, 0);
    rb_define_method(rb_cUnboundMethod, "owner", method_owner, 0);
    rb_define_method(rb_cUnboundMethod, "bind", umethod_bind, 1);
    rb_define_method(rb_cModule, "instance_method", rb_mod_method, 1);

#ifdef MBARI_API
    rb_define_method(rb_cUnboundMethod, "__file__", method_source_file_name, 0);
    rb_define_method(rb_cUnboundMethod, "__line__", method_source_line, 0);
    rb_define_method(rb_cProc, "__file__", proc_source_file_name, 0);
    rb_define_method(rb_cProc, "__line__", proc_source_line, 0);
    rb_define_method(rb_cMethod, "__file__", method_source_file_name, 0);
    rb_define_method(rb_cMethod, "__line__", method_source_line, 0);
#endif
}

/*
 *  Objects of class Binding encapsulate the execution
 *  context at some particular place in the code and retain this context
 *  for future use. The variables, methods, value of self,
 *  and possibly an iterator block that can be accessed in this context
 *  are all retained. Binding objects can be created using
 *  Kernel#binding, and are made available to the callback
 *  of Kernel#set_trace_func.
 *
 *  These binding objects can be passed as the second argument of the
 *  Kernel#eval method, establishing an environment for the
 *  evaluation.
 *
 *     class Demo
 *       def initialize(n)
 *         @secret = n
 *       end
 *       def getBinding
 *         return binding()
 *       end
 *     end
 *
 *     k1 = Demo.new(99)
 *     b1 = k1.getBinding
 *     k2 = Demo.new(-3)
 *     b2 = k2.getBinding
 *
 *     eval("@secret", b1)   #=> 99
 *     eval("@secret", b2)   #=> -3
 *     eval("@secret")       #=> nil
 *
 *  Binding objects have no class-specific methods.
 *
 */

void
Init_Binding()
{
    rb_cBinding = rb_define_class("Binding", rb_cObject);
    rb_undef_alloc_func(rb_cBinding);
    rb_undef_method(CLASS_OF(rb_cBinding), "new");
    rb_define_method(rb_cBinding, "clone", proc_clone, 0);
    rb_define_method(rb_cBinding, "dup", proc_dup, 0);
    rb_define_method(rb_cBinding, "eval", bind_eval, -1);
    rb_define_global_function("binding", rb_f_binding, 0);
}

/* Windows SEH refers data on the stack. */
#undef SAVE_WIN32_EXCEPTION_LIST
#if defined _WIN32 || defined __CYGWIN__
#if defined __CYGWIN__
typedef unsigned long DWORD;
#endif

static inline DWORD
win32_get_exception_list()
{
    DWORD p;
# if defined _MSC_VER
#   ifdef _M_IX86
#   define SAVE_WIN32_EXCEPTION_LIST
#   if _MSC_VER >= 1310
      /* warning: unsafe assignment to fs:0 ... this is ok */
#     pragma warning(disable: 4733)
#   endif
    __asm mov eax, fs:[0];
    __asm mov p, eax;
#   endif
# elif defined __GNUC__
#   ifdef __i386__
#   define SAVE_WIN32_EXCEPTION_LIST
    __asm__("movl %%fs:0,%0" : "=r"(p));
#   endif
# elif defined __BORLANDC__
#   define SAVE_WIN32_EXCEPTION_LIST
    __emit__(0x64, 0xA1, 0, 0, 0, 0); /* mov eax, fs:[0] */
    p = _EAX;
# endif
    return p;
}

static inline void
win32_set_exception_list(p)
    DWORD p;
{
# if defined _MSC_VER
#   ifdef _M_IX86
    __asm mov eax, p;
    __asm mov fs:[0], eax;
#   endif
# elif defined __GNUC__
#   ifdef __i386__
    __asm__("movl %0,%%fs:0" :: "r"(p));
#   endif
# elif defined __BORLANDC__
    _EAX = p;
    __emit__(0x64, 0xA3, 0, 0, 0, 0); /* mov fs:[0], eax */
# endif
}

#if !defined SAVE_WIN32_EXCEPTION_LIST && !defined _WIN32_WCE
# error unsupported platform
#endif
#endif

int rb_thread_pending = 0;

VALUE rb_cThread;
static unsigned int rb_thread_stack_size;

extern VALUE rb_last_status;

#define WAIT_FD         (1<<0)
#define WAIT_SELECT     (1<<1)
#define WAIT_TIME       (1<<2)
#define WAIT_JOIN       (1<<3)
#define WAIT_PID        (1<<4)
#define WAIT_DONE       (1<<5)

/* +infty, for this purpose */
#define DELAY_INFTY 1E30

#if !defined HAVE_PAUSE
# if defined _WIN32 && !defined __CYGWIN__
#  define pause() Sleep(INFINITE)
# else
#  define pause() sleep(0x7fffffff)
# endif
#endif

#define THREAD_TERMINATING 0x400 /* persistent flag */
#define THREAD_NO_ENSURE   0x800 /* persistent flag */
#define THREAD_FLAGS_MASK 0xfc00 /* mask for persistent flags */

#define FOREACH_THREAD_FROM(f,x) x = f; do { x = x->next;
#define END_FOREACH_FROM(f,x) } while (x != f)

#define FOREACH_THREAD(x) FOREACH_THREAD_FROM(curr_thread,x)
#define END_FOREACH(x)    END_FOREACH_FROM(curr_thread,x)

struct thread_status_t {
    NODE *node;

    int tracing;
    VALUE errinfo;
    VALUE last_status;
    VALUE last_line;
    VALUE last_match;

    int safe;

    enum rb_thread_status status;
    int wait_for;
    int fd;
    fd_set readfds;
    fd_set writefds;
    fd_set exceptfds;
    int select_value;
    double delay;
    rb_thread_t join;
};

#define THREAD_COPY_STATUS(src, dst) (void)(    \
    (dst)->node = (src)->node,                  \
                                                \
    (dst)->tracing = (src)->tracing,            \
    (dst)->errinfo = (src)->errinfo,            \
    (dst)->last_status = (src)->last_status,    \
    (dst)->last_line = (src)->last_line,        \
    (dst)->last_match = (src)->last_match,      \
                                                \
    (dst)->safe = (src)->safe,                  \
                                                \
    (dst)->status = (src)->status,              \
    (dst)->wait_for = (src)->wait_for,          \
    (dst)->fd = (src)->fd,                      \
    (dst)->readfds = (src)->readfds,            \
    (dst)->writefds = (src)->writefds,          \
    (dst)->exceptfds = (src)->exceptfds,        \
    (dst)->select_value = (src)->select_value,  \
    (dst)->delay = (src)->delay,                \
    (dst)->join = (src)->join,                  \
    0)

int
rb_thread_set_raised(th)
    rb_thread_t th;
{
    if (th->flags & RAISED_EXCEPTION) {
        return 1;
    }
    th->flags |= RAISED_EXCEPTION;
    return 0;
}

int
rb_thread_reset_raised(th)
    rb_thread_t th;
{
    if (!(th->flags & RAISED_EXCEPTION)) {
        return 0;
    }
    th->flags &= ~RAISED_EXCEPTION;
    return 1;
}

static int
thread_no_ensure()
{
    return ((curr_thread->flags & THREAD_NO_ENSURE) == THREAD_NO_ENSURE);
}

static void rb_thread_ready _((rb_thread_t));

static VALUE run_trap_eval _((VALUE));
static VALUE
run_trap_eval(arg)
    VALUE arg;
{
    VALUE *p = (VALUE *)arg;
    return rb_eval_cmd(p[0], p[1], (int)p[2]);
}

static VALUE
rb_trap_eval(cmd, sig, safe)
    VALUE cmd;
    int sig, safe;
{
    int state;
    VALUE val = Qnil;           /* OK */
    volatile struct thread_status_t save;
    VALUE arg[3];

    arg[0] = cmd;
    arg[1] = rb_ary_new3(1, INT2FIX(sig));
    arg[2] = (VALUE)safe;
    THREAD_COPY_STATUS(curr_thread, &save);
    rb_thread_ready(curr_thread);
    PUSH_ITER(ITER_NOT);
    val = rb_protect(run_trap_eval, (VALUE)&arg, &state);
    POP_ITER();
    THREAD_COPY_STATUS(&save, curr_thread);

    if (state) {
        rb_trap_immediate = 0;
        rb_thread_ready(curr_thread);
        JUMP_TAG(state);
    }

    if (curr_thread->status == THREAD_STOPPED) {
        rb_thread_schedule();
    }
    errno = EINTR;

    return val;
}

static const char *
thread_status_name(status)
    enum rb_thread_status status;
{
    switch (status) {
      case THREAD_RUNNABLE:
        return "run";
      case THREAD_STOPPED:
        return "sleep";
      case THREAD_TO_KILL:
        return "aborting";
      case THREAD_KILLED:
        return "dead";
      default:
        return "unknown";
    }
}

/* $SAFE accessor */
void
rb_set_safe_level(level)
    int level;
{
    if (level > ruby_safe_level) {
        if (level > SAFE_LEVEL_MAX) level = SAFE_LEVEL_MAX;
        ruby_safe_level = level;
        curr_thread->safe = level;
    }
}

static VALUE
safe_getter()
{
    return INT2NUM(ruby_safe_level);
}

static void
safe_setter(val)
    VALUE val;
{
    int level = NUM2INT(val);

    if (level < ruby_safe_level) {
        rb_raise(rb_eSecurityError, "tried to downgrade safe level from %d to %d",
                 ruby_safe_level, level);
    }
    if (level > SAFE_LEVEL_MAX) level = SAFE_LEVEL_MAX;
    ruby_safe_level = level;
    curr_thread->safe = level;
}

/* Return the current time as a floating-point number */
static double
timeofday()
{
    struct timeval tv;
#ifdef CLOCK_MONOTONIC
    struct timespec tp;

    if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
        return (double)tp.tv_sec + (double)tp.tv_nsec * 1e-9;
    }
#endif
    gettimeofday(&tv, NULL);
    return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6;
}

#define STACK(addr) (th->stk_pos<(VALUE*)(addr) && (VALUE*)(addr)stk_pos+th->stk_len)
#define ADJ(addr) (void*)(STACK(addr)?(((VALUE*)(addr)-th->stk_pos)+th->stk_ptr):(VALUE*)(addr))
static void
thread_mark(th)
    rb_thread_t th;
{
    struct FRAME *frame;
    struct BLOCK *block;

    rb_gc_mark(th->result);
    rb_gc_mark(th->thread);
    if (th->join) rb_gc_mark(th->join->thread);

    if (curr_thread == th) {
      rb_gc_mark(ruby_class);
      rb_gc_mark(ruby_wrapper);
      rb_gc_mark((VALUE)ruby_cref);
      rb_gc_mark((VALUE)ruby_scope);
      rb_gc_mark((VALUE)ruby_dyna_vars);
    } else {
      rb_gc_mark(th->klass);
      rb_gc_mark(th->wrapper);
      rb_gc_mark((VALUE)th->cref);
      rb_gc_mark((VALUE)th->scope);
      rb_gc_mark((VALUE)th->dyna_vars);
    }

    rb_gc_mark(th->errinfo);
    rb_gc_mark(th->last_status);
    rb_gc_mark(th->last_line);
    rb_gc_mark(th->last_match);
    rb_mark_tbl(th->locals);
    rb_gc_mark(th->thgroup);
    rb_gc_mark_maybe(th->sandbox);

    /* mark data in copied stack */
    if (th == main_thread) return;
    if (th->status == THREAD_KILLED) return;
    if (th->stk_len == 0) return;  /* stack not active, no need to mark. */
    if (th->stk_ptr && th != curr_thread) {
      rb_gc_mark_locations(th->stk_pos, th->stk_base);
#if defined(THINK_C) || defined(__human68k__)
        rb_gc_mark_locations(th->stk_ptr+2, th->stk_ptr+th->stk_len+2);
#endif
#ifdef __ia64
        if (th->bstr_ptr) {
            rb_gc_mark_locations(th->bstr_ptr, th->bstr_ptr+th->bstr_len);
        }
#endif
    }

    if (curr_thread == th)
      frame = ruby_frame;
    else
      frame = th->frame;

    while (frame && frame != top_frame) {
        rb_gc_mark_frame(frame);
        if (frame->tmp) {
            struct FRAME *tmp = frame->tmp;
            while (tmp && tmp != top_frame) {
                rb_gc_mark_frame(tmp);
                tmp = tmp->prev;
            }
        }
        frame = frame->prev;
    }

    if (curr_thread == th)
      block = ruby_block;
    else
      block = th->block;

    while (block) {
        rb_gc_mark_frame(&block->frame);
        block = block->prev;
    }
}

static int
mark_loading_thread(key, value, lev)
    ID key;
    VALUE value;
    int lev;
{
    rb_gc_mark(((rb_thread_t)value)->thread);
    return ST_CONTINUE;
}

void
rb_gc_mark_threads()
{
    rb_thread_t th;

    /* static global mark */
    rb_gc_mark((VALUE)ruby_cref);

    if (!curr_thread) return;
    rb_gc_mark(main_thread->thread);
    rb_gc_mark(curr_thread->thread);
    FOREACH_THREAD_FROM(main_thread, th) {
        switch (th->status) {
          case THREAD_TO_KILL:
          case THREAD_RUNNABLE:
            break;
          case THREAD_STOPPED:
            if (th->wait_for) break;
          default:
            continue;
        }
        rb_gc_mark(th->thread);
    } END_FOREACH_FROM(main_thread, th);
    if (loading_tbl) st_foreach(loading_tbl, mark_loading_thread, 0);
}

void
rb_gc_abort_threads()
{
    rb_thread_t th;

    if (!main_thread)
        return;

    FOREACH_THREAD_FROM(main_thread, th) {
        if (rb_gc_is_thread_marked(th->thread)) continue;
        if (th->status == THREAD_STOPPED) {
            th->status = THREAD_TO_KILL;
            rb_gc_mark(th->thread);
        }
    } END_FOREACH_FROM(main_thread, th);
}

static inline void
stack_free(th)
    rb_thread_t th;
{
    if (th->stk_ptr) {
      munmap(th->stk_ptr, th->stk_size);
      th->stk_ptr = 0;
    }
#ifdef __ia64
    if (th->bstr_ptr) {
      free(th->bstr_ptr);
      th->bstr_ptr = 0;
    }
#endif
}

#define THREAD_DATA(threadObject)  ((rb_thread_t)RDATA(threadObject)->data)

static void
thread_free(th)
    rb_thread_t th;
{
    stack_free(th);
    if (th->locals) st_free_table(th->locals);
    if (th->status != THREAD_KILLED) {
        if (th->prev) th->prev->next = th->next;
        if (th->next) th->next->prev = th->prev;
    }
    if (th != main_thread) free(th);
}

static rb_thread_t
rb_thread_check(data)
    VALUE data;
{
    if (TYPE(data) != T_DATA || RDATA(data)->dmark != (RUBY_DATA_FUNC)thread_mark) {
        rb_raise(rb_eTypeError, "wrong argument type %s (expected Thread)",
                 rb_obj_classname(data));
    }
    return THREAD_DATA(data);
}

static VALUE rb_thread_raise _((int, VALUE*, rb_thread_t));

static VALUE th_raise_exception;
static NODE *th_raise_node;
static VALUE th_cmd;
static int   th_sig, th_safe;

#define RESTORE_NORMAL          1
#define RESTORE_FATAL           2
#define RESTORE_INTERRUPT       3
#define RESTORE_TRAP            4
#define RESTORE_RAISE           5
#define RESTORE_SIGNAL          6
#define RESTORE_EXIT            7
#define RESTORE_BACKTRACE       8

extern VALUE *rb_gc_stack_start;
#ifdef __ia64
extern VALUE *rb_gc_register_stack_start;
#endif

static void
rb_thread_save_context(th)
    rb_thread_t th;
{
    VALUE *pos;
    size_t len;
    static VALUE tval;

    len = ruby_stack_length(&pos);
    th->stk_len = len;
    th->stk_pos = pos;
    th->frame = ruby_frame;
    th->scope = ruby_scope;
    ruby_scope->flags |= SCOPE_DONT_RECYCLE;
    th->klass = ruby_class;
    th->wrapper = ruby_wrapper;
    th->cref = ruby_cref;
    th->dyna_vars = ruby_dyna_vars;
    th->block = ruby_block;
    th->flags &= THREAD_FLAGS_MASK;
    th->flags |= (rb_trap_immediate<<8) | scope_vmode;
    th->iter = ruby_iter;
    th->tag = prot_tag;
    th->tracing = tracing;
    th->errinfo = ruby_errinfo;
    th->last_status = rb_last_status;
    tval = rb_lastline_get();
    rb_lastline_set(th->last_line);
    th->last_line = tval;
    tval = rb_backref_get();
    rb_backref_set(th->last_match);
    th->last_match = tval;
    th->safe = ruby_safe_level;

    th->node = ruby_current_node;
    if (ruby_sandbox_save != NULL) {
        ruby_sandbox_save(th);
    }
}

static int
rb_thread_switch(n)
    int n;
{
#if STACK_WIPE_SITES & 1
    rb_gc_wipe_stack();
#endif
    rb_trap_immediate = (curr_thread->flags&0x100)?1:0;
    switch (n) {
      case 0:
        return 0;
      case RESTORE_FATAL:
        JUMP_TAG(TAG_FATAL);
        break;
      case RESTORE_INTERRUPT:
        rb_interrupt();
        break;
      case RESTORE_TRAP:
        rb_trap_eval(th_cmd, th_sig, th_safe);
        break;
      case RESTORE_RAISE:
        ruby_frame->last_func = 0;
        ruby_current_node = th_raise_node;
        rb_raise_jump(th_raise_exception);
        break;
      case RESTORE_SIGNAL:
        rb_thread_signal_raise(th_sig);
        break;
      case RESTORE_EXIT:
        ruby_errinfo = th_raise_exception;
        ruby_current_node = th_raise_node;
        if (!rb_obj_is_kind_of(ruby_errinfo, rb_eSystemExit)) {
            terminate_process(EXIT_FAILURE, ruby_errinfo);
        }
        rb_exc_raise(th_raise_exception);
        break;
      case RESTORE_BACKTRACE:
        rb_hash_aset(backtrace_for_each_thread, curr_thread->thread,
                     backtrace(backtrace_level_for_each_thread));
        if (curr_thread != main_thread) {
            switch_thread_context_to_collect_backtrace(curr_thread->next);
        } else {
                /* Circled back to main thread, cycle is complete. */
        }
        break;
      case RESTORE_NORMAL:
      default:
        break;
    }
    return 1;
}

#define THREAD_SAVE_CONTEXT(th) (rb_thread_switch( wipeAfter(\
                  ruby_setjmp(rb_thread_save_context(th), (th)->context))))

NORETURN(static void rb_thread_restore_context _((rb_thread_t,int)));
NORETURN(NOINLINE(static void rb_thread_restore_context_0(rb_thread_t,int)));
NORETURN(NOINLINE(static void stack_extend(rb_thread_t, int)));

static void
rb_thread_restore_context_0(rb_thread_t th, int exit)
{
    static rb_thread_t tmp;
    static int ex;
    static VALUE tval;

    /* Free any dead thread's stk_ptr. */
    stack_free_safe_all_dead_threads();

    rb_trap_immediate = 0;      /* inhibit interrupts from here */
    if (ruby_sandbox_restore != NULL) {
        ruby_sandbox_restore(th);
    }
    ruby_frame = th->frame;
    ruby_scope = th->scope;
    ruby_class = th->klass;
    ruby_wrapper = th->wrapper;
    ruby_cref = th->cref;
    ruby_dyna_vars = th->dyna_vars;
    ruby_block = th->block;
    scope_vmode = th->flags&SCOPE_MASK;
    ruby_iter = th->iter;
    prot_tag = th->tag;
    tracing = th->tracing;
    ruby_errinfo = th->errinfo;
    rb_last_status = th->last_status;
    ruby_safe_level = th->safe;

    ruby_current_node = th->node;

#ifdef SAVE_WIN32_EXCEPTION_LIST
    win32_set_exception_list(th->win32_exception_list);
#endif
    tmp = th;
    ex = exit;

    tval = rb_lastline_get();
    rb_lastline_set(tmp->last_line);
    tmp->last_line = tval;
    tval = rb_backref_get();
    rb_backref_set(tmp->last_match);
    tmp->last_match = tval;

    ruby_longjmp(tmp->context, ex);
}

#ifdef __ia64
#define C(a) rse_##a##0, rse_##a##1, rse_##a##2, rse_##a##3, rse_##a##4
#define E(a) rse_##a##0= rse_##a##1= rse_##a##2= rse_##a##3= rse_##a##4
static volatile int C(a), C(b), C(c), C(d), C(e);
static volatile int C(f), C(g), C(h), C(i), C(j);
static volatile int C(k), C(l), C(m), C(n), C(o);
static volatile int C(p), C(q), C(r), C(s), C(t);
int rb_dummy_false = 0;
NORETURN(NOINLINE(static void register_stack_extend(rb_thread_t, int, VALUE *)));
static void
register_stack_extend(rb_thread_t th, int exit, VALUE *curr_bsp)
{
    if (rb_dummy_false) {
        /* use registers as much as possible */
        E(a) = E(b) = E(c) = E(d) = E(e) =
        E(f) = E(g) = E(h) = E(i) = E(j) =
        E(k) = E(l) = E(m) = E(n) = E(o) =
        E(p) = E(q) = E(r) = E(s) = E(t) = 0;
        E(a) = E(b) = E(c) = E(d) = E(e) =
        E(f) = E(g) = E(h) = E(i) = E(j) =
        E(k) = E(l) = E(m) = E(n) = E(o) =
        E(p) = E(q) = E(r) = E(s) = E(t) = 0;
    }
    if (curr_bsp < th->bstr_pos+th->bstr_len) {
        register_stack_extend(th, exit, (VALUE*)rb_ia64_bsp());
    }
    stack_extend(th, exit);
}
#undef C
#undef E
#endif

static void
stack_extend(rb_thread_t th, int exit)
{
#define STACK_PAD_SIZE 1024
    volatile VALUE space[STACK_PAD_SIZE];

#if !STACK_GROW_DIRECTION
    if (space < rb_gc_stack_start) {
        /* Stack grows downward */
#endif
#if STACK_GROW_DIRECTION <= 0
        if (space > th->stk_pos) {
# ifdef HAVE_ALLOCA
            (volatile void *)ALLOCA_N(VALUE, &space[0] - th->stk_pos);
# else
            stack_extend(th, exit);
# endif
        }
#endif
#if !STACK_GROW_DIRECTION
    }
    else {
        /* Stack grows upward */
#endif
#if STACK_GROW_DIRECTION >= 0
        if (&space[STACK_PAD_SIZE] < th->stk_pos + th->stk_len) {
# ifdef HAVE_ALLOCA
            (volatile void *)ALLOCA_N(VALUE, th->stk_pos +
                                      th->stk_len - &space[STACK_PAD_SIZE]);
# else
            stack_extend(th, exit);
# endif
        }
#endif
#if !STACK_GROW_DIRECTION
    }
#endif
    rb_thread_restore_context_0(th, exit);
}
#ifdef __ia64
#define stack_extend(th, exit) register_stack_extend(th, exit, (VALUE*)rb_ia64_bsp())
#endif

static void
rb_thread_restore_context(th, exit)
    rb_thread_t th;
    int exit;
{
    if (!th->stk_ptr && th != main_thread) rb_bug("unsaved context");
    rb_thread_restore_context_0(th, exit);
}

static void
rb_thread_ready(th)
    rb_thread_t th;
{
    th->wait_for = 0;
    if (th->status != THREAD_TO_KILL) {
        th->status = THREAD_RUNNABLE;
    }
}

static
rb_thread_t dead_thread_needs_stack_free = 0;

static
int dead_threads_need_stack_free = 0;

static int
_stack_free_safe (th
#if STACK_FREE_SAFE_DEBUG
                 , msg
#endif
                 )
    rb_thread_t th;
#if STACK_FREE_SAFE_DEBUG
    const char *msg;
#endif
{
    if ( th->status == THREAD_KILLED && th->stk_ptr ) {
        void *sp = (void*) &th;
#if STACK_FREE_SAFE_DEBUG
        fprintf(stderr, "\n%s: stack_free_safe(%p): sp (%p): stk [%p, %p): ",
                msg, th, sp, th->stk_ptr, th->stk_ptr + th->stk_size);
#endif
        if ( (void*) th->stk_ptr <= sp && sp < (void*) (th->stk_ptr + th->stk_size) ) {
#if STACK_FREE_SAFE_DEBUG
            fprintf(stderr, "  cannot call stack_free(), yet. \n");
            fflush(stderr);
#endif
            dead_thread_needs_stack_free = th;
            ++ dead_threads_need_stack_free;
        } else {
#if STACK_FREE_SAFE_DEBUG
            fprintf(stderr, "  calling stack_free(). \n");
            fflush(stderr);
#endif
            if ( dead_thread_needs_stack_free == th )
                dead_thread_needs_stack_free = 0;
            stack_free(th);
            return 1; /* stack freed. */
        }
    }
    return 0; /* stack not freed */
}

static void
rb_thread_die(th)
    rb_thread_t th;
{
    th->thgroup = 0;
    th->status = THREAD_KILLED;
    stack_free_safe(th, "rb_thread_die");
}

static void
rb_thread_remove(th)
    rb_thread_t th;
{
    if (th->status == THREAD_KILLED) return;

    rb_thread_ready(th);
    rb_thread_die(th);
    th->prev->next = th->next;
    th->next->prev = th->prev;

#if defined(_THREAD_SAFE) || defined(HAVE_SETITIMER)
    /* if this is the last ruby thread, stop timer signals */
    if (th->next == th->prev && th->next == main_thread) {
        rb_thread_stop_timer();
    }
#endif
}

static int
rb_thread_dead(th)
    rb_thread_t th;
{
    return th->status == THREAD_KILLED;
}

void
rb_thread_fd_close(fd)
    int fd;
{
    rb_thread_t th;

    FOREACH_THREAD(th) {
        if (((th->wait_for & WAIT_FD) && fd == th->fd) ||
            ((th->wait_for & WAIT_SELECT) && (fd < th->fd) &&
             (FD_ISSET(fd, &th->readfds) ||
              FD_ISSET(fd, &th->writefds) ||
              FD_ISSET(fd, &th->exceptfds)))) {
            VALUE exc = rb_exc_new2(rb_eIOError, "stream closed");
            rb_thread_raise(1, &exc, th);
        }
    }
    END_FOREACH(th);
}

NORETURN(static void rb_thread_main_jump _((VALUE, int)));
static void
rb_thread_main_jump(err, tag)
    VALUE err;
    int tag;
{
    curr_thread = main_thread;
    th_raise_exception = err;
    th_raise_node = ruby_current_node;
    rb_thread_restore_context(main_thread, tag);
}

NORETURN(static void rb_thread_deadlock _((void)));
static void
rb_thread_deadlock()
{
    char msg[21+SIZEOF_LONG*2];
    VALUE e;

    sprintf(msg, "Thread(0x%lx): deadlock", curr_thread->thread);
    e = rb_exc_new2(rb_eFatal, msg);
    if (curr_thread == main_thread) {
        rb_exc_raise(e);
    }
    rb_thread_main_jump(e, RESTORE_RAISE);
}

static void
copy_fds(dst, src, max)
    fd_set *dst, *src;
    int max;
{
    int n = 0;
    int i;

    for (i=0; i<=max; i++) {
        if (FD_ISSET(i, src)) {
            n = i;
            FD_SET(i, dst);
        }
    }
}

static int
match_fds(dst, src, max)
    fd_set *dst, *src;
    int max;
{
    int i;

    for (i=0; i<=max; i++) {
        if (FD_ISSET(i, src) && FD_ISSET(i, dst)) {
            return Qtrue;
        }
    }
    return Qfalse;
}

static int
intersect_fds(src, dst, max)
    fd_set *src, *dst;
    int max;
{
    int i, n = 0;

    for (i=0; i<=max; i++) {
        if (FD_ISSET(i, dst)) {
            if (FD_ISSET(i, src)) {
                /* Wake up only one thread per fd. */
                FD_CLR(i, src);
                n++;
            }
            else {
                FD_CLR(i, dst);
            }
        }
    }
    return n;
}

static int
find_bad_fds(dst, src, max)
    fd_set *dst, *src;
    int max;
{
    int i, test = Qfalse;

    for (i=0; i<=max; i++) {
        if (FD_ISSET(i, src) && !FD_ISSET(i, dst)) {
            FD_CLR(i, src);
            test = Qtrue;
        }
    }
    return test;
}

void
rb_thread_schedule()
{
    rb_thread_t next;           /* OK */
    rb_thread_t th;
    rb_thread_t curr;
    int found = 0;

    struct timeval *delay_ptr;
    double delay, now;  /* OK */
    int n, max;
    int need_select = 0;
    int select_timeout = 0;

#ifdef HAVE_NATIVETHREAD
    if (!is_ruby_native_thread()) {
        rb_bug("cross-thread violation on rb_thread_schedule()");
    }
#endif
    rb_thread_pending = 0;
    if (curr_thread == curr_thread->next
        && curr_thread->status == THREAD_RUNNABLE)
        return;

    next = 0;
    curr = curr_thread;         /* starting thread */

    while (curr->status == THREAD_KILLED) {
        curr = curr->prev;
    }

  again:
    max = -1;
    FD_ZERO(&curr->scratch_readfds);
    FD_ZERO(&curr->scratch_writefds);
    FD_ZERO(&curr->scratch_exceptfds);
    bzero(&curr->scratch_delay_tv, sizeof(struct timeval));
    delay = DELAY_INFTY;
    now = -1.0;

    FOREACH_THREAD_FROM(curr, th) {
        th->wait_for &= ~WAIT_DONE;
        if (!found && th->status <= THREAD_RUNNABLE) {
            found = 1;
        }
        if (th->status != THREAD_STOPPED) continue;
        if (th->wait_for & WAIT_JOIN) {
            if (rb_thread_dead(th->join)) {
                th->wait_for = 0;
                th->status = THREAD_RUNNABLE;
                found = 1;
            }
        }
        if (th->wait_for & WAIT_FD) {
            FD_SET(th->fd, &curr->scratch_readfds);
            if (max < th->fd) max = th->fd;
            need_select = 1;
        }
        if (th->wait_for & WAIT_SELECT) {
            copy_fds(&curr->scratch_readfds, &th->readfds, th->fd);
            copy_fds(&curr->scratch_writefds, &th->writefds, th->fd);
            copy_fds(&curr->scratch_exceptfds, &th->exceptfds, th->fd);
            if (max < th->fd) max = th->fd;
            need_select = 1;
            if (th->wait_for & WAIT_TIME) {
                select_timeout = 1;
            }
            th->select_value = 0;
        }
        if (th->wait_for & WAIT_TIME) {
            double th_delay;

            if (now < 0.0) now = timeofday();
            th_delay = th->delay - now;
            if (th_delay <= 0.0) {
                if (th->wait_for & WAIT_SELECT) {
                    need_select = 1;
                }
                else {
                    th->status = THREAD_RUNNABLE;
                }
                found = 1;
            }
            else if (th_delay < delay) {
                delay = th_delay;
                need_select = 1;
            }
            else if (th->delay == DELAY_INFTY) {
                need_select = 1;
            }
        }
    }
    END_FOREACH_FROM(curr, th);

    /* Do the select if needed */
    if (need_select) {
        /* Convert delay to a timeval */
        /* If a thread is runnable, just poll */
        if (found) {
            th->scratch_delay_tv.tv_sec = 0;
            th->scratch_delay_tv.tv_usec = 0;
            delay_ptr = &curr->scratch_delay_tv;
        }
        else if (delay == DELAY_INFTY) {
            delay_ptr = 0;
        }
        else {
            th->scratch_delay_tv.tv_sec = delay;
            th->scratch_delay_tv.tv_usec = (delay - (double)th->scratch_delay_tv.tv_sec)*1e6;
            delay_ptr = &curr->scratch_delay_tv;
        }

        n = select(max+1, &curr->scratch_readfds, &curr->scratch_writefds, &curr->scratch_exceptfds, delay_ptr);
        if (n < 0) {
            int e = errno;

            if (rb_trap_pending) rb_trap_exec();
            if (e == EINTR) goto again;
#ifdef ERESTART
            if (e == ERESTART) goto again;
#endif
            if (e == EBADF) {
                int badfd = -1;
                int fd;
                int dummy;
                for (fd = 0; fd <= max; fd++) {
                    if ((FD_ISSET(fd, &curr->scratch_readfds) ||
                         FD_ISSET(fd, &curr->scratch_writefds) ||
                         FD_ISSET(fd, &curr->scratch_exceptfds)) &&
#ifndef _WIN32
                        fcntl(fd, F_GETFD, &dummy) == -1 &&
#else
                        rb_w32_get_osfhandle(fd) == -1 &&
#endif
                        errno == EBADF) {
                        badfd = fd;
                        break;
                    }
                }
                if (badfd != -1) {
                    FOREACH_THREAD_FROM(curr, th) {
                        if (th->wait_for & WAIT_FD) {
                            if (th->fd == badfd) {
                                found = 1;
                                th->status = THREAD_RUNNABLE;
                                th->fd = 0;
                                break;
                            }
                        }
                        if (th->wait_for & WAIT_SELECT) {
                            if (FD_ISSET(badfd, &th->readfds) ||
                                FD_ISSET(badfd, &th->writefds) ||
                                FD_ISSET(badfd, &th->exceptfds)) {
                                found = 1;
                                th->status = THREAD_RUNNABLE;
                                th->select_value = -EBADF;
                                break;
                            }
                        }
                    }
                    END_FOREACH_FROM(curr, th);
                }
            }
            else {
                FOREACH_THREAD_FROM(curr, th) {
                    if (th->wait_for & WAIT_SELECT) {
                        int v = 0;

                        v |= find_bad_fds(&curr->scratch_readfds, &th->readfds, th->fd);
                        v |= find_bad_fds(&curr->scratch_writefds, &th->writefds, th->fd);
                        v |= find_bad_fds(&curr->scratch_exceptfds, &th->exceptfds, th->fd);
                        if (v) {
                            th->select_value = n;
                            n = max;
                        }
                    }
                }
                END_FOREACH_FROM(curr, th);
            }
        }
        if (select_timeout && n == 0) {
            if (now < 0.0) now = timeofday();
            FOREACH_THREAD_FROM(curr, th) {
                if (((th->wait_for&(WAIT_SELECT|WAIT_TIME)) == (WAIT_SELECT|WAIT_TIME)) &&
                    th->delay <= now) {
                    th->status = THREAD_RUNNABLE;
                    th->wait_for = 0;
                    th->select_value = 0;
                    found = 1;
                    intersect_fds(&curr->scratch_readfds, &th->readfds, max);
                    intersect_fds(&curr->scratch_writefds, &th->writefds, max);
                    intersect_fds(&curr->scratch_exceptfds, &th->exceptfds, max);
                }
            }
            END_FOREACH_FROM(curr, th);
        }
        if (n > 0) {
            now = -1.0;
            /* Some descriptors are ready.
             * The corresponding threads are runnable as next.
             * Mark them with WAIT_DONE.
             * Don't change the status to runnable here because
             * threads which don't run next should not be changed.
             */
            FOREACH_THREAD_FROM(curr, th) {
                if ((th->wait_for&WAIT_FD) && FD_ISSET(th->fd, &curr->scratch_readfds)) {
                    th->wait_for |= WAIT_DONE;
                    found = 1;
                }
                if ((th->wait_for&WAIT_SELECT) &&
                    (match_fds(&curr->scratch_readfds, &th->readfds, max) ||
                     match_fds(&curr->scratch_writefds, &th->writefds, max) ||
                     match_fds(&curr->scratch_exceptfds, &th->exceptfds, max))) {
                    th->wait_for |= WAIT_DONE;
                    found = 1;
                }
            }
            END_FOREACH_FROM(curr, th);
        }
        /* The delays for some of the threads should have expired.
           Go through the loop once more, to check the delays. */
        if (!found && delay != DELAY_INFTY)
            goto again;
    }

    FOREACH_THREAD_FROM(curr, th) {
        if (th->status == THREAD_TO_KILL) {
            next = th;
            break;
        }
        if ((th->status == THREAD_RUNNABLE || (th->wait_for & WAIT_DONE)) && th->stk_ptr) {
            if (!next || next->priority < th->priority) {
                next = th;
            }
        }
    }
    END_FOREACH_FROM(curr, th);

    if (next && (next->wait_for & WAIT_DONE)) {
        next->status = THREAD_RUNNABLE;
        if (next->wait_for&WAIT_FD) {
            next->fd = 0;
        }
        else { /* next->wait_for&WAIT_SELECT */
            n = intersect_fds(&curr->scratch_readfds, &next->readfds, max) +
                intersect_fds(&curr->scratch_writefds, &next->writefds, max) +
                intersect_fds(&curr->scratch_exceptfds, &next->exceptfds, max);
            next->select_value = n;
        }
        next->wait_for = 0;
    }

    if (!next) {
        /* raise fatal error to main thread */
        curr_thread->node = ruby_current_node;
        if (curr->next == curr) {
            TRAP_BEG;
            pause();
            TRAP_END;
        }
        FOREACH_THREAD_FROM(curr, th) {
            int wait_for = th->wait_for & ~WAIT_DONE;
            warn_printf("deadlock 0x%lx: %s:",
                        th->thread, thread_status_name(th->status));
            if (wait_for & WAIT_FD) warn_printf("F(%d)", th->fd);
            if (wait_for & WAIT_SELECT) warn_printf("S");
            if (wait_for & WAIT_TIME) warn_printf("T(%f)", th->delay);
            if (wait_for & WAIT_JOIN)
                warn_printf("J(0x%lx)", th->join ? th->join->thread : 0);
            if (wait_for & WAIT_PID) warn_printf("P");
            if (!wait_for) warn_printf("-");
            warn_printf(" %s - %s:%d\n",
                        th==main_thread ? "(main)" : "",
                        th->node->nd_file, nd_line(th->node));
        }
        END_FOREACH_FROM(curr, th);
        next = main_thread;
        rb_thread_ready(next);
        next->status = THREAD_TO_KILL;
        if (!rb_thread_dead(curr_thread)) {
            rb_thread_save_context(curr_thread);
        }
        rb_thread_deadlock();
    }
    next->wait_for = 0;
    if (next->status == THREAD_RUNNABLE && next == curr_thread) {
        return;
    }

    /* context switch */
    if (curr == curr_thread) {
        if (THREAD_SAVE_CONTEXT(curr)) {
            return;
        }
    }

    curr_thread = next;
    if (next->status == THREAD_TO_KILL) {
        if (!(next->flags & THREAD_TERMINATING)) {
            next->flags |= THREAD_TERMINATING;
            /* terminate; execute ensure-clause if any */
            rb_thread_restore_context(next, RESTORE_FATAL);
        }
    }
    rb_thread_restore_context(next, RESTORE_NORMAL);
}

void
rb_thread_wait_fd(fd)
    int fd;
{
    if (rb_thread_critical) return;
    if (ruby_in_compile) return;
    if (curr_thread == curr_thread->next) return;
    if (curr_thread->status == THREAD_TO_KILL) return;

    curr_thread->status = THREAD_STOPPED;
    curr_thread->fd = fd;
    curr_thread->wait_for = WAIT_FD;
    rb_thread_schedule();
}

int
rb_thread_fd_writable(fd)
    int fd;
{
    if (rb_thread_critical) return Qtrue;
    if (curr_thread == curr_thread->next) return Qtrue;
    if (curr_thread->status == THREAD_TO_KILL) return Qtrue;
    if (curr_thread->status == THREAD_KILLED) return Qtrue;

    curr_thread->status = THREAD_STOPPED;
    FD_ZERO(&curr_thread->readfds);
    FD_ZERO(&curr_thread->writefds);
    FD_SET(fd, &curr_thread->writefds);
    FD_ZERO(&curr_thread->exceptfds);
    curr_thread->fd = fd+1;
    curr_thread->wait_for = WAIT_SELECT;
    rb_thread_schedule();
    return Qfalse;
}

void
rb_thread_wait_for(time)
    struct timeval time;
{
    double date;

    if (rb_thread_critical ||
        curr_thread == curr_thread->next ||
        curr_thread->status == THREAD_TO_KILL) {
        int n;
        int thr_critical = rb_thread_critical;
#ifndef linux
        double d, limit;
        limit = timeofday()+(double)time.tv_sec+(double)time.tv_usec*1e-6;
#endif
        for (;;) {
            rb_thread_critical = Qtrue;
            TRAP_BEG;
            n = select(0, 0, 0, 0, &time);
            rb_thread_critical = thr_critical;
            TRAP_END;
            if (n == 0) return;
            if (n < 0) {
                switch (errno) {
                  case EINTR:
#ifdef ERESTART
                  case ERESTART:
#endif
                    break;
                  default:
                    rb_sys_fail("sleep");
                }
            }
#ifndef linux
            d = limit - timeofday();

            time.tv_sec = (int)d;
            time.tv_usec = (int)((d - (int)d)*1e6);
            if (time.tv_usec < 0) {
                time.tv_usec += (long)1e6;
                time.tv_sec -= 1;
            }
            if (time.tv_sec < 0) return;
#endif
        }
    }

    date = timeofday() + (double)time.tv_sec + (double)time.tv_usec*1e-6;
    curr_thread->status = THREAD_STOPPED;
    curr_thread->delay = date;
    curr_thread->wait_for = WAIT_TIME;
    rb_thread_schedule();
}

void rb_thread_sleep_forever _((void));

int
rb_thread_alone()
{
    return curr_thread == curr_thread->next;
}

int
rb_thread_select(max, read, write, except, timeout)
    int max;
    fd_set *read, *write, *except;
    struct timeval *timeout;
{
#ifndef linux
    double limit;
#endif
    int n;

    if (!read && !write && !except) {
        if (!timeout) {
            rb_thread_sleep_forever();
            return 0;
        }
        rb_thread_wait_for(*timeout);
        return 0;
    }

#ifndef linux
    if (timeout) {
        limit = timeofday()+
            (double)timeout->tv_sec+(double)timeout->tv_usec*1e-6;
    }
#endif

    if (rb_thread_critical ||
        curr_thread == curr_thread->next ||
        curr_thread->status == THREAD_TO_KILL) {
#ifndef linux
        struct timeval tv, *tvp = timeout;

        if (timeout) {
            tv = *timeout;
            tvp = &tv;
        }
#else
        struct timeval *const tvp = timeout;
#endif
        for (;;) {
            TRAP_BEG;
            n = select(max, read, write, except, tvp);
            TRAP_END;
            if (n < 0) {
                switch (errno) {
                  case EINTR:
#ifdef ERESTART
                  case ERESTART:
#endif
#ifndef linux
                    if (timeout) {
                        double d = limit - timeofday();

                        tv.tv_sec = (unsigned int)d;
                        tv.tv_usec = (long)((d-(double)tv.tv_sec)*1e6);
                        if (tv.tv_sec < 0)  tv.tv_sec = 0;
                        if (tv.tv_usec < 0) tv.tv_usec = 0;
                    }
#endif
                    continue;
                  default:
                    break;
                }
            }
            return n;
        }
    }

    curr_thread->status = THREAD_STOPPED;
    if (read) curr_thread->readfds = *read;
    else FD_ZERO(&curr_thread->readfds);
    if (write) curr_thread->writefds = *write;
    else FD_ZERO(&curr_thread->writefds);
    if (except) curr_thread->exceptfds = *except;
    else FD_ZERO(&curr_thread->exceptfds);
    curr_thread->fd = max;
    curr_thread->wait_for = WAIT_SELECT;
    if (timeout) {
        curr_thread->delay = timeofday() +
            (double)timeout->tv_sec + (double)timeout->tv_usec*1e-6;
        curr_thread->wait_for |= WAIT_TIME;
    }
    rb_thread_schedule();
    if (read) *read = curr_thread->readfds;
    if (write) *write = curr_thread->writefds;
    if (except) *except = curr_thread->exceptfds;
    if (curr_thread->select_value < 0) {
        errno = -curr_thread->select_value;
        return -1;
    }
    return curr_thread->select_value;
}

static int rb_thread_join0 _((rb_thread_t, double));
int rb_thread_join _((VALUE, double));

static int
rb_thread_join0(th, limit)
    rb_thread_t th;
    double limit;
{
    enum rb_thread_status last_status = THREAD_RUNNABLE;

    if (rb_thread_critical) rb_thread_deadlock();
    if (!rb_thread_dead(th)) {
        if (th == curr_thread)
            rb_raise(rb_eThreadError, "thread 0x%lx tried to join itself",
                     th->thread);
        if ((th->wait_for & WAIT_JOIN) && th->join == curr_thread)
            rb_raise(rb_eThreadError, "Thread#join: deadlock 0x%lx - mutual join(0x%lx)",
                     curr_thread->thread, th->thread);
        if (curr_thread->status == THREAD_TO_KILL)
            last_status = THREAD_TO_KILL;
        if (limit == 0) return Qfalse;
        curr_thread->status = THREAD_STOPPED;
        curr_thread->join = th;
        curr_thread->wait_for = WAIT_JOIN;
        curr_thread->delay = timeofday() + limit;
        if (limit < DELAY_INFTY) curr_thread->wait_for |= WAIT_TIME;
        rb_thread_schedule();
        curr_thread->status = last_status;
        if (!rb_thread_dead(th)) return Qfalse;
    }

    if (!NIL_P(th->errinfo) && (th->flags & RAISED_EXCEPTION)) {
        VALUE oldbt = get_backtrace(th->errinfo);
        VALUE errat = make_backtrace();
        VALUE errinfo = rb_obj_dup(th->errinfo);

        if (TYPE(oldbt) == T_ARRAY && RARRAY(oldbt)->len > 0) {
            rb_ary_unshift(errat, rb_ary_entry(oldbt, 0));
        }
        set_backtrace(errinfo, errat);
        rb_exc_raise(errinfo);
    }

    return Qtrue;
}

int
rb_thread_join(thread, limit)
    VALUE thread;
    double limit;
{
    if (limit < 0) limit = DELAY_INFTY;
    return rb_thread_join0(THREAD_DATA(thread), limit);
}

void
rb_thread_set_join(thread, join)
    VALUE thread, join;
{
    rb_thread_t th = rb_thread_check(thread);
    rb_thread_t jth = rb_thread_check(join);
    if ( (th->wait_for & WAIT_JOIN) == 0) {
       rb_bug( "Internal consistency failure! Expected thread to already be in waiting to join state %0x, was in %0x", WAIT_JOIN, th->wait_for);
    }

    if (th->join != curr_thread) {
       rb_bug( "Internal consistency failure! Should only invoke rb_thread_set_join from a mutex unlock. Thread join aiming at %0x which something other than current thread %0x", th->join, curr_thread);
    }

    th->join = jth;
}


/*
 *  call-seq:
 *     thr.join          => thr
 *     thr.join(limit)   => thr
 *
 *  The calling thread will suspend execution and run thr. Does not
 *  return until thr exits or until limit seconds have passed. If
 *  the time limit expires, nil will be returned, otherwise
 *  thr is returned.
 *
 *  Any threads not joined will be killed when the main program exits.  If
 *  thr had previously raised an exception and the
 *  abort_on_exception and $DEBUG flags are not set
 *  (so the exception has not yet been processed) it will be processed at this
 *  time.
 *
 *     a = Thread.new { print "a"; sleep(10); print "b"; print "c" }
 *     x = Thread.new { print "x"; Thread.pass; print "y"; print "z" }
 *     x.join # Let x thread finish, a will be killed on exit.
 *
 *  produces:
 *
 *     axyz
 *
 *  The following example illustrates the limit parameter.
 *
 *     y = Thread.new { 4.times { sleep 0.1; puts 'tick... ' }}
 *     puts "Waiting" until y.join(0.15)
 *
 *  produces:
 *
 *     tick...
 *     Waiting
 *     tick...
 *     Waitingtick...
 *
 *
 *     tick...
 */

static VALUE
rb_thread_join_m(argc, argv, thread)
    int argc;
    VALUE *argv;
    VALUE thread;
{
    VALUE limit;
    double delay = DELAY_INFTY;

    rb_scan_args(argc, argv, "01", &limit);
    if (!NIL_P(limit)) delay = rb_num2dbl(limit);
    if (!rb_thread_join0(THREAD_DATA(thread), delay))
        return Qnil;
    return thread;
}


/*
 *  call-seq:
 *     Thread.current   => thread
 *
 *  Returns the currently executing thread.
 *
 *     Thread.current   #=> #
 */

VALUE
rb_thread_current()
{
    return curr_thread->thread;
}


/*
 *  call-seq:
 *     Thread.main   => thread
 *
 *  Returns the main thread for the process.
 *
 *     Thread.main   #=> #
 */

VALUE
rb_thread_main()
{
    return main_thread->thread;
}


/*
 *  call-seq:
 *     Thread.list   => array
 *
 *  Returns an array of Thread objects for all threads that are
 *  either runnable or stopped.
 *
 *     Thread.new { sleep(200) }
 *     Thread.new { 1000000.times {|i| i*i } }
 *     Thread.new { Thread.stop }
 *     Thread.list.each {|t| p t}
 *
 *  produces:
 *
 *     #
 *     #
 *     #
 *     #
 */

VALUE
rb_thread_list()
{
    rb_thread_t th;
    VALUE ary = rb_ary_new();

    FOREACH_THREAD(th) {
        switch (th->status) {
          case THREAD_RUNNABLE:
          case THREAD_STOPPED:
          case THREAD_TO_KILL:
            rb_ary_push(ary, th->thread);
          default:
            break;
        }
    }
    END_FOREACH(th);

    return ary;
}


/*
 *  call-seq:
 *     thr.wakeup   => thr
 *
 *  Marks thr as eligible for scheduling (it may still remain blocked on
 *  I/O, however). Does not invoke the scheduler (see Thread#run).
 *
 *     c = Thread.new { Thread.stop; puts "hey!" }
 *     c.wakeup
 *
 *  produces:
 *
 *     hey!
 */

VALUE
rb_thread_wakeup(thread)
    VALUE thread;
{
    if (!RTEST(rb_thread_wakeup_alive(thread)))
        rb_raise(rb_eThreadError, "killed thread");
    return thread;
}

VALUE
rb_thread_wakeup_alive(thread)
    VALUE thread;
{
    rb_thread_t th = THREAD_DATA(thread);

    if (th->status == THREAD_KILLED)
        return Qnil;
    rb_thread_ready(th);

    return thread;
}


/*
 *  call-seq:
 *     thr.run   => thr
 *
 *  Wakes up thr, making it eligible for scheduling. If not in a critical
 *  section, then invokes the scheduler.
 *
 *     a = Thread.new { puts "a"; Thread.stop; puts "c" }
 *     Thread.pass
 *     puts "Got here"
 *     a.run
 *     a.join
 *
 *  produces:
 *
 *     a
 *     Got here
 *     c
 */

VALUE
rb_thread_run(thread)
    VALUE thread;
{
    rb_thread_wakeup(thread);
    if (!rb_thread_critical) rb_thread_schedule();

    return thread;
}


static void
rb_kill_thread(th, flags)
    rb_thread_t th;
    int flags;
{
    if (th != curr_thread && th->safe < 4) {
        rb_secure(4);
    }
    if (th->status == THREAD_TO_KILL || th->status == THREAD_KILLED)
        return;
    if (th == th->next || th == main_thread) rb_exit(EXIT_SUCCESS);

    rb_thread_ready(th);
    th->flags |= flags;
    th->status = THREAD_TO_KILL;
    if (!rb_thread_critical) rb_thread_schedule();
}


/*
 *  call-seq:
 *     thr.exit        => thr
 *     thr.kill        => thr
 *     thr.terminate   => thr
 *
 *  Terminates thr and schedules another thread to be run, returning
 *  the terminated Thread.  If this is the main thread, or the
 *  last thread, exits the process.
 */

VALUE
rb_thread_kill(thread)
    VALUE thread;
{
    rb_thread_t th = THREAD_DATA(thread);

    rb_kill_thread(th, 0);
    return thread;
}


/*
 *  call-seq:
 *     thr.exit!        => thr
 *     thr.kill!        => thr
 *     thr.terminate!   => thr
 *
 *  Terminates thr without calling ensure clauses and schedules
 *  another thread to be run, returning the terminated Thread.
 *  If this is the main thread, or the last thread, exits the process.
 *
 *  See Thread#exit for the safer version.
 */

static VALUE
rb_thread_kill_bang(thread)
    VALUE thread;
{
    rb_thread_t th = THREAD_DATA(thread);
    rb_kill_thread(th, THREAD_NO_ENSURE);
    return thread;
}

/*
 *  call-seq:
 *     Thread.kill(thread)   => thread
 *
 *  Causes the given thread to exit (see Thread::exit).
 *
 *     count = 0
 *     a = Thread.new { loop { count += 1 } }
 *     sleep(0.1)       #=> 0
 *     Thread.kill(a)   #=> #
 *     count            #=> 93947
 *     a.alive?         #=> false
 */

static VALUE
rb_thread_s_kill(obj, th)
    VALUE obj, th;
{
    return rb_thread_kill(th);
}


/*
 *  call-seq:
 *     Thread.exit   => thread
 *
 *  Terminates the currently running thread and schedules another thread to be
 *  run. If this thread is already marked to be killed, exit
 *  returns the Thread. If this is the main thread, or the last
 *  thread, exit the process.
 */

static VALUE
rb_thread_exit()
{
    return rb_thread_kill(curr_thread->thread);
}


/*
 *  call-seq:
 *     Thread.pass   => nil
 *
 *  Invokes the thread scheduler to pass execution to another thread.
 *
 *     a = Thread.new { print "a"; Thread.pass;
 *                      print "b"; Thread.pass;
 *                      print "c" }
 *     b = Thread.new { print "x"; Thread.pass;
 *                      print "y"; Thread.pass;
 *                      print "z" }
 *     a.join
 *     b.join
 *
 *  produces:
 *
 *     axbycz
 */

static VALUE
rb_thread_pass()
{
    rb_thread_schedule();
    return Qnil;
}


/*
 *  call-seq:
 *     Thread.stop   => nil
 *
 *  Stops execution of the current thread, putting it into a ``sleep'' state,
 *  and schedules execution of another thread. Resets the ``critical'' condition
 *  to false.
 *
 *     a = Thread.new { print "a"; Thread.stop; print "c" }
 *     Thread.pass
 *     print "b"
 *     a.run
 *     a.join
 *
 *  produces:
 *
 *     abc
 */

VALUE
rb_thread_stop()
{
    enum rb_thread_status last_status = THREAD_RUNNABLE;

    rb_thread_critical = 0;
    if (curr_thread == curr_thread->next) {
        rb_raise(rb_eThreadError, "stopping only thread\n\tnote: use sleep to stop forever");
    }
    if (curr_thread->status == THREAD_TO_KILL)
        last_status = THREAD_TO_KILL;
    curr_thread->status = THREAD_STOPPED;
    rb_thread_schedule();
    curr_thread->status = last_status;

    return Qnil;
}

struct timeval rb_time_timeval();

void
rb_thread_polling()
{
    if (curr_thread != curr_thread->next) {
        curr_thread->status = THREAD_STOPPED;
        curr_thread->delay = timeofday() + (double)0.06;
        curr_thread->wait_for = WAIT_TIME;
        rb_thread_schedule();
    }
}

void
rb_thread_sleep(sec)
    int sec;
{
    if (curr_thread == curr_thread->next) {
        TRAP_BEG;
        sleep(sec);
        TRAP_END;
        return;
    }
    rb_thread_wait_for(rb_time_timeval(INT2FIX(sec)));
}

void
rb_thread_sleep_forever()
{
    int thr_critical = rb_thread_critical;
    if (curr_thread == curr_thread->next ||
        curr_thread->status == THREAD_TO_KILL) {
        rb_thread_critical = Qtrue;
        TRAP_BEG;
        pause();
        rb_thread_critical = thr_critical;
        TRAP_END;
        return;
    }

    curr_thread->delay = DELAY_INFTY;
    curr_thread->wait_for = WAIT_TIME;
    curr_thread->status = THREAD_STOPPED;
    rb_thread_schedule();
}


/*
 *  call-seq:
 *     thr.priority   => integer
 *
 *  Returns the priority of thr. Default is inherited from the
 *  current thread which creating the new thread, or zero for the
 *  initial main thread; higher-priority threads will run before
 *  lower-priority threads.
 *
 *     Thread.current.priority   #=> 0
 */

static VALUE
rb_thread_priority(thread)
    VALUE thread;
{
    return INT2NUM(THREAD_DATA(thread)->priority);
}


/*
 *  call-seq:
 *     thr.priority= integer   => thr
 *
 *  Sets the priority of thr to integer. Higher-priority threads
 *  will run before lower-priority threads.
 *
 *     count1 = count2 = 0
 *     a = Thread.new do
 *           loop { count1 += 1 }
 *         end
 *     a.priority = -1
 *
 *     b = Thread.new do
 *           loop { count2 += 1 }
 *         end
 *     b.priority = -2
 *     sleep 1   #=> 1
 *     Thread.critical = 1
 *     count1    #=> 622504
 *     count2    #=> 5832
 */

static VALUE
rb_thread_priority_set(thread, prio)
    VALUE thread, prio;
{
    rb_thread_t th;

    rb_secure(4);
    th = THREAD_DATA(thread);

    th->priority = NUM2INT(prio);
    rb_thread_schedule();
    return prio;
}


/*
 *  call-seq:
 *     thr.safe_level   => integer
 *
 *  Returns the safe level in effect for thr. Setting thread-local safe
 *  levels can help when implementing sandboxes which run insecure code.
 *
 *     thr = Thread.new { $SAFE = 3; sleep }
 *     Thread.current.safe_level   #=> 0
 *     thr.safe_level              #=> 3
 */

static VALUE
rb_thread_safe_level(thread)
    VALUE thread;
{
    rb_thread_t th;

    th = THREAD_DATA(thread);
    if (th == curr_thread) {
        return INT2NUM(ruby_safe_level);
    }
    return INT2NUM(th->safe);
}

static int ruby_thread_abort;
static VALUE thgroup_default;


/*
 *  call-seq:
 *     Thread.abort_on_exception   => true or false
 *
 *  Returns the status of the global ``abort on exception'' condition.  The
 *  default is false. When set to true, or if the
 *  global $DEBUG flag is true (perhaps because the
 *  command line option -d was specified) all threads will abort
 *  (the process will exit(0)) if an exception is raised in any
 *  thread. See also Thread::abort_on_exception=.
 */

static VALUE
rb_thread_s_abort_exc()
{
    return ruby_thread_abort?Qtrue:Qfalse;
}


/*
 *  call-seq:
 *     Thread.abort_on_exception= boolean   => true or false
 *
 *  When set to true, all threads will abort if an exception is
 *  raised. Returns the new state.
 *
 *     Thread.abort_on_exception = true
 *     t1 = Thread.new do
 *       puts  "In new thread"
 *       raise "Exception from thread"
 *     end
 *     sleep(1)
 *     puts "not reached"
 *
 *  produces:
 *
 *     In new thread
 *     prog.rb:4: Exception from thread (RuntimeError)
 *      from prog.rb:2:in `initialize'
 *      from prog.rb:2:in `new'
 *      from prog.rb:2
 */

static VALUE
rb_thread_s_abort_exc_set(self, val)
    VALUE self, val;
{
    rb_secure(4);
    ruby_thread_abort = RTEST(val);
    return val;
}


/*
 *  call-seq:
 *     thr.abort_on_exception   => true or false
 *
 *  Returns the status of the thread-local ``abort on exception'' condition for
 *  thr. The default is false. See also
 *  Thread::abort_on_exception=.
 */

static VALUE
rb_thread_abort_exc(thread)
    VALUE thread;
{
    return THREAD_DATA(thread)->abort?Qtrue:Qfalse;
}


/*
 *  call-seq:
 *     thr.abort_on_exception= boolean   => true or false
 *
 *  When set to true, causes all threads (including the main
 *  program) to abort if an exception is raised in thr. The process will
 *  effectively exit(0).
 */

static VALUE
rb_thread_abort_exc_set(thread, val)
    VALUE thread, val;
{
    rb_secure(4);
    THREAD_DATA(thread)->abort = RTEST(val);
    return val;
}


/*
 *  call-seq:
 *     thr.group   => thgrp or nil
 *
 *  Returns the ThreadGroup which contains thr, or nil if
 *  the thread is not a member of any group.
 *
 *     Thread.main.group   #=> #
 */

VALUE
rb_thread_group(thread)
    VALUE thread;
{
    VALUE group = THREAD_DATA(thread)->thgroup;
    if (!group) {
        group = Qnil;
    }
    return group;
}

#ifdef __ia64
# define IA64_INIT(x) x
#else
# define IA64_INIT(x)
#endif

#define THREAD_ALLOC(th) do {\
    th = ALLOC(struct rb_thread);\
\
    th->next = 0;\
    th->prev = 0;\
\
    th->status = THREAD_RUNNABLE;\
    th->result = 0;\
    th->flags = 0;\
\
    th->stk_ptr = 0;\
    th->stk_len = 0;\
    th->stk_size = 0;\
    th->stk_max = 0;\
    th->wait_for = 0;\
    th->gc_stack_end = (VALUE *) STACK_GROW_DIRECTION;\
    IA64_INIT(th->bstr_ptr = 0);\
    IA64_INIT(th->bstr_len = 0);\
    IA64_INIT(th->bstr_max = 0);\
    FD_ZERO(&th->readfds);\
    FD_ZERO(&th->writefds);\
    FD_ZERO(&th->exceptfds);\
    th->delay = 0.0;\
    th->join = 0;\
\
    th->frame = 0;\
    th->scope = 0;\
    th->klass = 0;\
    th->wrapper = 0;\
    th->cref = ruby_cref;\
    th->dyna_vars = ruby_dyna_vars;\
    th->block = 0;\
    th->iter = 0;\
    th->tag = 0;\
    th->tracing = 0;\
    th->errinfo = Qnil;\
    th->last_status = 0;\
    th->last_line = 0;\
    th->last_match = Qnil;\
    th->abort = 0;\
    th->priority = 0;\
    th->thgroup = thgroup_default;\
    th->locals = 0;\
    th->thread = 0;\
    if (curr_thread == 0) {\
        th->sandbox = Qnil;\
    } else {\
        th->sandbox = curr_thread->sandbox;\
    }\
} while (0)

static rb_thread_t
rb_thread_alloc(klass)
    VALUE klass;
{
    rb_thread_t th;
    struct RVarmap *vars;

    THREAD_ALLOC(th);
    th->thread = Data_Wrap_Struct(klass, thread_mark, thread_free, th);

    /* if main_thread != NULL, then this is NOT the main thread, so
     * we create a heap-stack
     */
    if (main_thread) {
      /* Allocate stack, don't forget to add 1 extra word because of the MATH below */
      unsigned int pagesize = getpagesize();
      unsigned int total_size = rb_thread_stack_size + pagesize + sizeof(int);
      void *stack_area = NULL;

      stack_area = mmap(NULL, total_size, PROT_READ | PROT_WRITE | PROT_EXEC,
                        MAP_PRIVATE | MAP_ANON, -1, 0);

      if (stack_area == MAP_FAILED) {
        rb_memerror();
        fprintf(stderr, "Thread stack allocation failed %d!\n", getpid());
      }

      th->stk_ptr = th->stk_pos = stack_area;
      th->stk_size = total_size;

      if (mprotect(th->stk_ptr, pagesize, PROT_NONE) == -1) {
        fprintf(stderr, "Failed to create thread guard region: %s\n", strerror(errno));
        rb_memerror();
      }

      th->guard = th->stk_ptr + (pagesize/sizeof(VALUE *));

      /* point stk_base at the top of the stack */
      /* ASSUMPTIONS:
       * 1.) The address returned by malloc is "suitably aligned" for anything on this system
       * 2.) Adding a value that is "aligned" for this platform should not unalign the address
       *     returned from malloc.
       * 3.) Don't push anything on to the stack, otherwise it'll get unaligned.
       * 4.) x86_64 ABI says aligned AFTER arguments have been pushed. You *must* then do a call[lq]
       *     or push[lq] something else on to the stack if you inted to do a ret.
       */
      th->stk_base = th->stk_ptr + ((total_size - sizeof(int))/sizeof(VALUE *));
      th->stk_len = rb_thread_stack_size;
    } else {
      th->stk_ptr = th->stk_pos = rb_gc_stack_start;
    }

    for (vars = th->dyna_vars; vars; vars = vars->next) {
        if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
        FL_SET(vars, DVAR_DONT_RECYCLE);
    }
    return th;
}

static int thread_init;

#if defined(POSIX_SIGNAL)
#define CATCH_VTALRM() posix_signal(SIGVTALRM, catch_timer)
#else
#define CATCH_VTALRM() signal(SIGVTALRM, catch_timer)
#endif

#if defined(_THREAD_SAFE)
static void
catch_timer(sig)
    int sig;
{
#if !defined(POSIX_SIGNAL) && !defined(BSD_SIGNAL)
    signal(sig, catch_timer);
#endif
    /* cause EINTR */
}

#define PER_NANO 1000000000

static struct timespec *
get_ts(struct timespec *to, long ns)
{
    struct timeval tv;

#ifdef CLOCK_REALTIME
    if (clock_gettime(CLOCK_REALTIME, to) != 0)
#endif
    {
        gettimeofday(&tv, NULL);
        to->tv_sec = tv.tv_sec;
        to->tv_nsec = tv.tv_usec * 1000;
    }
    if ((to->tv_nsec += ns) >= PER_NANO) {
        to->tv_sec += to->tv_nsec / PER_NANO;
        to->tv_nsec %= PER_NANO;
    }
    return to;
}

static struct timer_thread {
    pthread_cond_t cond;
    pthread_mutex_t lock;
    pthread_t thread;
} time_thread = {PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER};

static int timer_stopping;

#define safe_mutex_lock(lock) \
    pthread_mutex_lock(lock); \
    pthread_cleanup_push((void (*)_((void *)))pthread_mutex_unlock, lock)

static void*
thread_timer(dummy)
    void *dummy;
{
    struct timer_thread *running = ((void **)dummy)[0];
    pthread_cond_t *start = ((void **)dummy)[1];
    struct timespec to;
    int err;

    sigset_t all_signals;

    sigfillset(&all_signals);
    pthread_sigmask(SIG_BLOCK, &all_signals, 0);

    safe_mutex_lock(&running->lock);
    pthread_cond_signal(start);

#define WAIT_FOR_10MS() \
    pthread_cond_timedwait(&running->cond, &running->lock, get_ts(&to, PER_NANO/100))
    while ((err = WAIT_FOR_10MS()) == EINTR || err == ETIMEDOUT) {
      if (timer_stopping)
        break;

        if (!rb_thread_critical) {
            rb_thread_pending = 1;
            if (rb_trap_immediate) {
                pthread_kill(ruby_thid, SIGVTALRM);
            }
        }
    }

    pthread_cleanup_pop(1);

    return NULL;
}

void
rb_thread_start_timer()
{
    void *args[2];
    static pthread_cond_t start = PTHREAD_COND_INITIALIZER;

    if (thread_init) return;
    if (rb_thread_alone()) return;
    CATCH_VTALRM();
    args[0] = &time_thread;
    args[1] = &start;
    safe_mutex_lock(&time_thread.lock);
    if (pthread_create(&time_thread.thread, 0, thread_timer, args) == 0) {
        thread_init = 1;
#if !defined(__NetBSD__) && !defined(__APPLE__) && !defined(linux)
        pthread_atfork(0, 0, rb_thread_stop_timer);
#endif
        pthread_cond_wait(&start, &time_thread.lock);
    }
    pthread_cleanup_pop(1);
}

void
rb_thread_stop_timer()
{
    if (!thread_init) return;
    safe_mutex_lock(&time_thread.lock);
    timer_stopping = 1;
    pthread_cond_signal(&time_thread.cond);
    thread_init = 0;
    pthread_cleanup_pop(1);
    pthread_join(time_thread.thread, NULL);
    timer_stopping = 0;
}
#elif defined(HAVE_SETITIMER)
static void
catch_timer(sig)
    int sig;
{
#if !defined(POSIX_SIGNAL) && !defined(BSD_SIGNAL)
    signal(sig, catch_timer);
#endif
    if (!rb_thread_critical) {
        rb_thread_pending = 1;
    }
    /* cause EINTR */
}

void
rb_thread_start_timer()
{
    struct itimerval tval;

    if (thread_init) return;
    if (rb_thread_alone()) return;
    CATCH_VTALRM();
    tval.it_interval.tv_sec = 0;
    tval.it_interval.tv_usec = 10000;
    tval.it_value = tval.it_interval;
    setitimer(ITIMER_VIRTUAL, &tval, NULL);
    thread_init = 1;
}

void
rb_thread_stop_timer()
{
    struct itimerval tval;

    if (!thread_init) return;
    tval.it_interval.tv_sec = 0;
    tval.it_interval.tv_usec = 0;
    tval.it_value = tval.it_interval;
    setitimer(ITIMER_VIRTUAL, &tval, NULL);
    thread_init = 0;
}
#else  /* !(_THREAD_SAFE || HAVE_SETITIMER) */
int rb_thread_tick = THREAD_TICK;
#endif

struct thread_start_args {
  VALUE (*fn)();
  void *arg;
  rb_thread_t th;
} new_th;

static VALUE
rb_thread_start_2();

#if defined(HAVE_SETITIMER) || defined(_THREAD_SAFE)
#define START_TIMER() (thread_init ? (void)0 : rb_thread_start_timer())
#define STOP_TIMER() (rb_thread_stop_timer())
#else
#define START_TIMER() ((void)0)
#define STOP_TIMER() ((void)0)
#endif

static VALUE
rb_thread_start_0(fn, arg, th)
    VALUE (*fn)();
    void *arg;
    rb_thread_t th;
{
    volatile VALUE thread = th->thread;

    if (OBJ_FROZEN(curr_thread->thgroup)) {
        rb_raise(rb_eThreadError,
                 "can't start a new thread (frozen ThreadGroup)");
    }

    if (THREAD_SAVE_CONTEXT(curr_thread)) {
        return thread;
    }

    new_th.fn = fn;
    new_th.arg = arg;
    new_th.th = th;

#if defined(__i386__)
    __asm__ __volatile__ ("movl %0, %%esp\n\t"
                          "calll *%1\n"
                          :: "r" (th->stk_base),
                             "r" (rb_thread_start_2));
#elif defined(__x86_64__)
    __asm__ __volatile__ ("movq %0, %%rsp\n\t"
                          "callq *%1\n"
                          :: "r" (th->stk_base),
                             "r" (rb_thread_start_2));
#else
    #error unsupported architecture!
#endif
    /* NOTREACHED */
    return 0;
}

static VALUE
rb_thread_start_2()
{
   volatile rb_thread_t th = new_th.th;
   volatile rb_thread_t th_save = th;
   volatile VALUE thread = th->thread;
   struct BLOCK *volatile saved_block = 0;
   enum rb_thread_status status;
   int state;
   struct tag *tag, *new_tag, *prev_tag;
   struct RVarmap *vars;
   struct FRAME dummy_frame;

   if (!th->next) {
        /* merge in thread list */
        th->prev = curr_thread;
        curr_thread->next->prev = th;
        th->next = curr_thread->next;
        curr_thread->next = th;
        th->priority = curr_thread->priority;
        th->thgroup = curr_thread->thgroup;
   }
   curr_thread = th;

   dummy_frame = *ruby_frame;
   dummy_frame.prev = top_frame;
   ruby_frame = &dummy_frame;

   if (ruby_block) {            /* should nail down higher blocks */
        struct BLOCK dummy;

        dummy.prev = ruby_block;
        blk_copy_prev(&dummy);
        saved_block = ruby_block = dummy.prev;
    }
    START_TIMER();

    scope_dup(ruby_scope);
    prev_tag = NULL;
    tag = prot_tag;
    while (tag) {
        new_tag = alloca(sizeof(struct tag));
        memcpy(new_tag, tag, sizeof(struct tag));

        if (prev_tag)
            prev_tag->prev = new_tag;
        else
            prot_tag = new_tag;

        prev_tag = new_tag;
        tag = tag->prev;
    }

    PUSH_TAG(PROT_THREAD);
    if ((state = EXEC_TAG()) == 0) {
        if (THREAD_SAVE_CONTEXT(th) == 0) {
            th->result = (*new_th.fn)(new_th.arg, th);
        }
        th = th_save;
    }
    else if (TAG_DST()) {
        th = th_save;
        th->result = prot_tag->retval;
    }
    POP_TAG();
    status = th->status;

    if (th == main_thread) ruby_stop(state);
    rb_thread_remove(th);

    if (saved_block) {
        blk_free(saved_block);
    }

    if (state && status != THREAD_TO_KILL && !NIL_P(ruby_errinfo)) {
        th->flags |= RAISED_EXCEPTION;
        if (state == TAG_FATAL) {
            /* fatal error within this thread, need to stop whole script */
            main_thread->errinfo = ruby_errinfo;
            rb_thread_cleanup();
        }
        else if (rb_obj_is_kind_of(ruby_errinfo, rb_eSystemExit)) {
            if (th->safe >= 4) {
                char buf[32];

                sprintf(buf, "Insecure exit at level %d", th->safe);
                th->errinfo = rb_exc_new2(rb_eSecurityError, buf);
            }
            else {
                /* delegate exception to main_thread */
                rb_thread_main_jump(ruby_errinfo, RESTORE_RAISE);
            }
        }
        else if (th->safe < 4 && (ruby_thread_abort || th->abort || RTEST(ruby_debug))) {
            /* exit on main_thread */
            error_print();
            rb_thread_main_jump(ruby_errinfo, RESTORE_EXIT);
        }
        else {
            th->errinfo = ruby_errinfo;
        }
    }
    rb_thread_schedule();
    ruby_stop(0);               /* last thread termination */
    return 0;                   /* not reached */
}

VALUE
rb_thread_create(fn, arg)
    VALUE (*fn)();
    void *arg;
{
    Init_stack((void *)&arg);
    return rb_thread_start_0(fn, arg, rb_thread_alloc(rb_cThread));
}

static VALUE
rb_thread_yield(arg, th)
    VALUE arg;
    rb_thread_t th;
{
    const ID *tbl;

    scope_dup(ruby_block->scope);

    tbl = ruby_scope->local_tbl;
    if (tbl) {
        int n = *tbl++;
        for (tbl += 2, n -= 2; n > 0; --n) { /* skip first 2 ($_ and $~) */
            ID id = *tbl++;
            if (id != 0 && !rb_is_local_id(id))  /* push flip states */
                rb_dvar_push(id, Qfalse);
        }
    }
    rb_dvar_push('_', Qnil);
    rb_dvar_push('~', Qnil);
    ruby_block->dyna_vars = ruby_dyna_vars;

    return rb_yield_0(arg, 0, 0, YIELD_LAMBDA_CALL, Qtrue);
}

/*
 *  call-seq:
 *     Thread.new([arg]*) {|args| block }   => thread
 *
 *  Creates and runs a new thread to execute the instructions given in
 *  block. Any arguments passed to Thread::new are passed
 *  into the block.
 *
 *     x = Thread.new { sleep 0.1; print "x"; print "y"; print "z" }
 *     a = Thread.new { print "a"; print "b"; sleep 0.2; print "c" }
 *     x.join # Let the threads finish before
 *     a.join # main thread exits...
 *
 *  produces:
 *
 *     abxyzc
 */

static VALUE
rb_thread_s_new(argc, argv, klass)
    int argc;
    VALUE *argv;
    VALUE klass;
{
    rb_thread_t th = rb_thread_alloc(klass);
    volatile VALUE *pos;

    pos = th->stk_pos;
    rb_obj_call_init(th->thread, argc, argv);
    if (th->stk_pos == 0) {
        rb_raise(rb_eThreadError, "uninitialized thread - check `%s#initialize'",
                 rb_class2name(klass));
    }

    return th->thread;
}


/*
 *  call-seq:
 *     Thread.new([arg]*) {|args| block }   => thread
 *
 *  Creates and runs a new thread to execute the instructions given in
 *  block. Any arguments passed to Thread::new are passed
 *  into the block.
 *
 *     x = Thread.new { sleep 0.1; print "x"; print "y"; print "z" }
 *     a = Thread.new { print "a"; print "b"; sleep 0.2; print "c" }
 *     x.join # Let the threads finish before
 *     a.join # main thread exits...
 *
 *  produces:
 *
 *     abxyzc
 */

static VALUE
rb_thread_initialize(thread, args)
    VALUE thread, args;
{
    rb_thread_t th;

    if (!rb_block_given_p()) {
        rb_raise(rb_eThreadError, "must be called with a block");
    }
    th = THREAD_DATA(thread);
    if (th->stk_max) {
        NODE *node = th->node;
        if (!node) {
            rb_raise(rb_eThreadError, "already initialized thread");
        }
        rb_raise(rb_eThreadError, "already initialized thread - %s:%d",
                 node->nd_file, nd_line(node));
    }
    return rb_thread_start_0(rb_thread_yield, args, th);
}


/*
 *  call-seq:
 *     Thread.start([args]*) {|args| block }   => thread
 *     Thread.fork([args]*) {|args| block }    => thread
 *
 *  Basically the same as Thread::new. However, if class
 *  Thread is subclassed, then calling start in that
 *  subclass will not invoke the subclass's initialize method.
 */

static VALUE
rb_thread_start(klass, args)
    VALUE klass, args;
{
    if (!rb_block_given_p()) {
        rb_raise(rb_eThreadError, "must be called with a block");
    }
    return rb_thread_start_0(rb_thread_yield, args, rb_thread_alloc(klass));
}


/*
 *  call-seq:
 *     thr.value   => obj
 *
 *  Waits for thr to complete (via Thread#join) and returns
 *  its value.
 *
 *     a = Thread.new { 2 + 2 }
 *     a.value   #=> 4
 */

static VALUE
rb_thread_value(thread)
    VALUE thread;
{
    rb_thread_t th = THREAD_DATA(thread);

    while (!rb_thread_join0(th, DELAY_INFTY));

    return th->result;
}


/*
 *  call-seq:
 *     thr.status   => string, false or nil
 *
 *  Returns the status of thr: ``sleep'' if thr is
 *  sleeping or waiting on I/O, ``run'' if thr is executing,
 *  ``aborting'' if thr is aborting, false if
 *  thr terminated normally, and nil if thr
 *  terminated with an exception.
 *
 *     a = Thread.new { raise("die now") }
 *     b = Thread.new { Thread.stop }
 *     c = Thread.new { Thread.exit }
 *     d = Thread.new { sleep }
 *     Thread.critical = true
 *     d.kill                  #=> #
 *     a.status                #=> nil
 *     b.status                #=> "sleep"
 *     c.status                #=> false
 *     d.status                #=> "aborting"
 *     Thread.current.status   #=> "run"
 */

static VALUE
rb_thread_status(thread)
    VALUE thread;
{
    rb_thread_t th = THREAD_DATA(thread);

    if (rb_thread_dead(th)) {
        if (!NIL_P(th->errinfo) && (th->flags & RAISED_EXCEPTION))
            return Qnil;
        return Qfalse;
    }

    return rb_str_new2(thread_status_name(th->status));
}


/*
 *  call-seq:
 *     thr.alive?   => true or false
 *
 *  Returns true if thr is running or sleeping.
 *
 *     thr = Thread.new { }
 *     thr.join                #=> #
 *     Thread.current.alive?   #=> true
 *     thr.alive?              #=> false
 */

VALUE
rb_thread_alive_p(thread)
    VALUE thread;
{
    rb_thread_t th = THREAD_DATA(thread);

    if (rb_thread_dead(th)) return Qfalse;
    return Qtrue;
}


/*
 *  call-seq:
 *     thr.stop?   => true or false
 *
 *  Returns true if thr is dead or sleeping.
 *
 *     a = Thread.new { Thread.stop }
 *     b = Thread.current
 *     a.stop?   #=> true
 *     b.stop?   #=> false
 */

static VALUE
rb_thread_stop_p(thread)
    VALUE thread;
{
    rb_thread_t th = THREAD_DATA(thread);

    if (rb_thread_dead(th)) return Qtrue;
    if (th->status == THREAD_STOPPED) return Qtrue;
    return Qfalse;
}

static void
rb_thread_wait_other_threads()
{
    rb_thread_t th;
    int found;

    /* wait other threads to terminate */
    while (curr_thread != curr_thread->next) {
        found = 0;
        FOREACH_THREAD(th) {
            if (th != curr_thread && th->status != THREAD_STOPPED) {
                found = 1;
                break;
            }
        }
        END_FOREACH(th);
        if (!found) return;
        rb_thread_schedule();
    }
}

static void
stack_free_safe_all_dead_threads()
{
    if ( dead_threads_need_stack_free ) {
        rb_thread_t curr, th;
        int left = dead_threads_need_stack_free;

#if STACK_FREE_SAFE_DEBUG
        fprintf(stderr, "\nstack_free_safe_all_dead_threads(): %d\n", dead_threads_need_stack_free);
        fflush(stderr);
#endif

        /* stack_free_safe() will increment this flag if stack_free_safe(th) cannot call stack_free(). */
        dead_threads_need_stack_free = 0;

        /*
        ** Check the last known dead thread that needs stack_free().
        ** That thread might have been rb_thread_remove()'ed from the thread ring.
        ** Otherwise, start after current thread's stk_ptr, it should not be freeable anyway.
        */
        if ( th = dead_thread_needs_stack_free ) {
            if ( stack_free_safe(th, "stack_free_safe_all_dead_threads") )
                if ( -- left <= 0 ) return;
        }

        curr = curr_thread;
        FOREACH_THREAD_FROM(curr, th) {
            if ( stack_free_safe(th, "stack_free_safe_all_dead_threads") )
                if ( -- left <= 0 ) return;
        }
        END_FOREACH_FROM(curr, th);
    }
}

static void
rb_thread_cleanup()
{
    rb_thread_t curr, th;

    curr = curr_thread;
    while (curr->status == THREAD_KILLED) {
        curr = curr->prev;
    }

    FOREACH_THREAD_FROM(curr, th) {
        if (th->status != THREAD_KILLED) {
            rb_thread_ready(th);
            if (th != main_thread) {
                th->thgroup = 0;
                th->priority = 0;
                th->status = THREAD_TO_KILL;
                RDATA(th->thread)->dfree = NULL;
            }
        }
    }
    END_FOREACH_FROM(curr, th);
}

/*
 * call-seq:
 *    Thread.stack_size    => fixnum
 *
 * Returns the thread stack size in bytes
 */
static VALUE
rb_thread_stacksize_get()
{
  return INT2FIX(rb_thread_stack_size);
}

/*
 * call-seq:
 *    Thread.stack_size= fixnum => Qnil
 *
 * Sets the global thread stacksize and returns Qnil.
 */
static VALUE
rb_thread_stacksize_set(obj, val)
     VALUE obj;
     VALUE val;
{

  unsigned int size = FIX2UINT(val);

  /* 16byte alignment works for both x86 and x86_64 */
  if (size & (~0xf)) {
    size += 0x10;
    size = size & (~0xf);
  }

  rb_thread_stack_size = size;

  return Qnil;
}

int rb_thread_critical;


/*
 *  call-seq:
 *     Thread.critical   => true or false
 *
 *  Returns the status of the global ``thread critical'' condition.
 */

static VALUE
rb_thread_critical_get()
{
    return rb_thread_critical?Qtrue:Qfalse;
}


/*
 *  call-seq:
 *     Thread.critical= boolean   => true or false
 *
 *  Sets the status of the global ``thread critical'' condition and returns
 *  it. When set to true, prohibits scheduling of any existing
 *  thread. Does not block new threads from being created and run. Certain
 *  thread operations (such as stopping or killing a thread, sleeping in the
 *  current thread, and raising an exception) may cause a thread to be scheduled
 *  even when in a critical section.  Thread::critical is not
 *  intended for daily use: it is primarily there to support folks writing
 *  threading libraries.
 */

static VALUE
rb_thread_critical_set(obj, val)
    VALUE obj, val;
{
    rb_thread_critical = RTEST(val);
    return val;
}

void
rb_thread_interrupt()
{
    rb_thread_critical = 0;
    rb_thread_ready(main_thread);
    if (curr_thread == main_thread) {
        rb_interrupt();
    }
    if (!rb_thread_dead(curr_thread)) {
        if (THREAD_SAVE_CONTEXT(curr_thread)) {
            return;
        }
    }
    curr_thread = main_thread;
    rb_thread_restore_context(curr_thread, RESTORE_INTERRUPT);
}

void
rb_thread_signal_raise(sig)
    int sig;
{
    rb_thread_critical = 0;
    if (curr_thread == main_thread) {
        VALUE argv[1];

        rb_thread_ready(curr_thread);
        argv[0] = INT2FIX(sig);
        rb_exc_raise(rb_class_new_instance(1, argv, rb_eSignal));
    }
    rb_thread_ready(main_thread);
    if (!rb_thread_dead(curr_thread)) {
        if (THREAD_SAVE_CONTEXT(curr_thread)) {
            return;
        }
    }
    th_sig = sig;
    curr_thread = main_thread;
    rb_thread_restore_context(curr_thread, RESTORE_SIGNAL);
}

void
rb_thread_trap_eval(cmd, sig, safe)
    VALUE cmd;
    int sig, safe;
{
    rb_thread_critical = 0;
    if (curr_thread == main_thread) {
        rb_trap_eval(cmd, sig, safe);
        return;
    }
    if (!rb_thread_dead(curr_thread)) {
        if (THREAD_SAVE_CONTEXT(curr_thread)) {
            return;
        }
    }
    th_cmd = cmd;
    th_sig = sig;
    th_safe = safe;
    curr_thread = main_thread;
    rb_thread_restore_context(curr_thread, RESTORE_TRAP);
}

void
rb_thread_signal_exit()
{
    VALUE args[2];

    rb_thread_critical = 0;
    if (curr_thread == main_thread) {
        rb_thread_ready(curr_thread);
        rb_exit(EXIT_SUCCESS);
    }
    args[0] = INT2NUM(EXIT_SUCCESS);
    args[1] = rb_str_new2("exit");
    rb_thread_ready(main_thread);
    if (!rb_thread_dead(curr_thread)) {
        if (THREAD_SAVE_CONTEXT(curr_thread)) {
            return;
        }
    }
    rb_thread_main_jump(rb_class_new_instance(2, args, rb_eSystemExit),
                        RESTORE_EXIT);
}

static VALUE
rb_thread_raise(argc, argv, th)
    int argc;
    VALUE *argv;
    rb_thread_t th;
{
    volatile rb_thread_t th_save = th;
    VALUE exc;

    if (!th->next) {
        rb_raise(rb_eArgError, "unstarted thread");
    }
    if (rb_thread_dead(th)) return Qnil;
    exc = rb_make_exception(argc, argv);
    if (curr_thread == th) {
        rb_raise_jump(exc);
    }

    if (!rb_thread_dead(curr_thread)) {
        if (THREAD_SAVE_CONTEXT(curr_thread)) {
            return th_save->thread;
        }
    }

    rb_thread_ready(th);
    curr_thread = th;

    th_raise_exception = exc;
    th_raise_node = ruby_current_node;
    rb_thread_restore_context(curr_thread, RESTORE_RAISE);
    return Qnil;                /* not reached */
}


/*
 *  call-seq:
 *     thr.raise(exception)
 *
 *  Raises an exception (see Kernel::raise) from thr. The
 *  caller does not have to be thr.
 *
 *     Thread.abort_on_exception = true
 *     a = Thread.new { sleep(200) }
 *     a.raise("Gotcha")
 *
 *  produces:
 *
 *     prog.rb:3: Gotcha (RuntimeError)
 *      from prog.rb:2:in `initialize'
 *      from prog.rb:2:in `new'
 *      from prog.rb:2
 */

static VALUE
rb_thread_raise_m(argc, argv, thread)
    int argc;
    VALUE *argv;
    VALUE thread;
{
    rb_thread_t th = THREAD_DATA(thread);

    if (ruby_safe_level > th->safe) {
        rb_secure(4);
    }
    rb_thread_raise(argc, argv, th);
    return Qnil;                /* not reached */
}

VALUE
rb_thread_local_aref(thread, id)
    VALUE thread;
    ID id;
{
    rb_thread_t th;
    VALUE val;

    th = THREAD_DATA(thread);
    if (ruby_safe_level >= 4 && th != curr_thread) {
        rb_raise(rb_eSecurityError, "Insecure: thread locals");
    }
    if (!th->locals) return Qnil;
    if (st_lookup(th->locals, id, &val)) {
        return val;
    }
    return Qnil;
}


/*
 *  call-seq:
 *      thr[sym]   => obj or nil
 *
 *  Attribute Reference---Returns the value of a thread-local variable, using
 *  either a symbol or a string name. If the specified variable does not exist,
 *  returns nil.
 *
 *     a = Thread.new { Thread.current["name"] = "A"; Thread.stop }
 *     b = Thread.new { Thread.current[:name]  = "B"; Thread.stop }
 *     c = Thread.new { Thread.current["name"] = "C"; Thread.stop }
 *     Thread.list.each {|x| puts "#{x.inspect}: #{x[:name]}" }
 *
 *  produces:
 *
 *     #: C
 *     #: B
 *     #: A
 *     #:
 */

static VALUE
rb_thread_aref(thread, id)
    VALUE thread, id;
{
    return rb_thread_local_aref(thread, rb_to_id(id));
}

VALUE
rb_thread_local_aset(thread, id, val)
    VALUE thread;
    ID id;
    VALUE val;
{
    rb_thread_t th = THREAD_DATA(thread);

    if (ruby_safe_level >= 4 && th != curr_thread) {
        rb_raise(rb_eSecurityError, "Insecure: can't modify thread locals");
    }
    if (OBJ_FROZEN(thread)) rb_error_frozen("thread locals");

    if (!th->locals) {
        th->locals = st_init_numtable();
    }
    if (NIL_P(val)) {
        st_delete(th->locals, (st_data_t*)&id, 0);
        return Qnil;
    }
    st_insert(th->locals, id, val);

    return val;
}


/*
 *  call-seq:
 *      thr[sym] = obj   => obj
 *
 *  Attribute Assignment---Sets or creates the value of a thread-local variable,
 *  using either a symbol or a string. See also Thread#[].
 */

static VALUE
rb_thread_aset(thread, id, val)
    VALUE thread, id, val;
{
    return rb_thread_local_aset(thread, rb_to_id(id), val);
}


/*
 *  call-seq:
 *     thr.key?(sym)   => true or false
 *
 *  Returns true if the given string (or symbol) exists as a
 *  thread-local variable.
 *
 *     me = Thread.current
 *     me[:oliver] = "a"
 *     me.key?(:oliver)    #=> true
 *     me.key?(:stanley)   #=> false
 */

static VALUE
rb_thread_key_p(thread, id)
    VALUE thread, id;
{
    rb_thread_t th = THREAD_DATA(thread);

    if (!th->locals) return Qfalse;
    if (st_lookup(th->locals, rb_to_id(id), 0))
        return Qtrue;
    return Qfalse;
}

static int
thread_keys_i(key, value, ary)
    ID key;
    VALUE value, ary;
{
    rb_ary_push(ary, ID2SYM(key));
    return ST_CONTINUE;
}


/*
 *  call-seq:
 *     thr.keys   => array
 *
 *  Returns an an array of the names of the thread-local variables (as Symbols).
 *
 *     thr = Thread.new do
 *       Thread.current[:cat] = 'meow'
 *       Thread.current["dog"] = 'woof'
 *     end
 *     thr.join   #=> #
 *     thr.keys   #=> [:dog, :cat]
 */

static VALUE
rb_thread_keys(thread)
    VALUE thread;
{
    rb_thread_t th = THREAD_DATA(thread);
    VALUE ary = rb_ary_new();

    if (th->locals) {
        st_foreach(th->locals, thread_keys_i, ary);
    }
    return ary;
}

/*
 * call-seq:
 *   thr.inspect   => string
 *
 * Dump the name, id, and status of _thr_ to a string.
 */

static VALUE
rb_thread_inspect(thread)
    VALUE thread;
{
    const char *cname = rb_obj_classname(thread);
    rb_thread_t th = THREAD_DATA(thread);
    const char *status = thread_status_name(th->status);
    VALUE str;
    size_t len = strlen(cname)+7+16+9+1;

    str = rb_str_new(0, len); /* 7:tags 16:addr 9:status 1:nul */
    snprintf(RSTRING(str)->ptr, len, "#<%s:0x%lx %s>", cname, thread, status);
    RSTRING(str)->len = strlen(RSTRING(str)->ptr);
    OBJ_INFECT(str, thread);

    return str;
}

void
rb_thread_atfork()
{
    rb_thread_t th;

    if (rb_thread_alone()) return;
    FOREACH_THREAD(th) {
        if (th != curr_thread) {
            rb_thread_die(th);
        }
    }
    END_FOREACH(th);
    main_thread = curr_thread;
    curr_thread->next = curr_thread;
    curr_thread->prev = curr_thread;
    STOP_TIMER();
}

static inline void
cc_purge(cc)
    rb_thread_t cc;
{  /* free continuation's stack if it has just died */
  if (cc->thread != Qnil && THREAD_DATA(cc->thread)->status == THREAD_KILLED) {
    cc->thread = Qnil;
    rb_thread_die(cc);  /* can't possibly activate this stack */
  }
}

static void
cc_mark(cc)
    rb_thread_t cc;
{
    /* mark this continuation's stack only if its parent thread is still alive */
    cc_purge(cc);
    thread_mark(cc);
}


/*
 *  Document-class: Continuation
 *
 *  Continuation objects are generated by
 *  Kernel#callcc. They hold a return address and execution
 *  context, allowing a nonlocal return to the end of the
 *  callcc block from anywhere within a program.
 *  Continuations are somewhat analogous to a structured version of C's
 *  setjmp/longjmp (although they contain more state, so
 *  you might consider them closer to threads).
 *
 *  For instance:
 *
 *     arr = [ "Freddie", "Herbie", "Ron", "Max", "Ringo" ]
 *     callcc{|$cc|}
 *     puts(message = arr.shift)
 *     $cc.call unless message =~ /Max/
 *
 *  produces:
 *
 *     Freddie
 *     Herbie
 *     Ron
 *     Max
 *
 *  This (somewhat contrived) example allows the inner loop to abandon
 *  processing early:
 *
 *     callcc {|cont|
 *       for i in 0..4
 *         print "\n#{i}: "
 *         for j in i*5...(i+1)*5
 *           cont.call() if j == 17
 *           printf "%3d", j
 *         end
 *       end
 *     }
 *     print "\n"
 *
 *  produces:
 *
 *     0:   0  1  2  3  4
 *     1:   5  6  7  8  9
 *     2:  10 11 12 13 14
 *     3:  15 16
 */

VALUE rb_cCont;


static rb_thread_t prep4callcc(void)
{
  rb_thread_t th;
  struct tag *tag;
  struct RVarmap *vars;

  THREAD_ALLOC(th);
  /* must finish th initialization before any possible gc */
  th->thread = curr_thread->thread;    /* brent@mbari.org */
  th->thgroup = cont_protect;

  scope_dup(ruby_scope);
  for (tag=prot_tag; tag; tag=tag->prev) {
      if (tag->tag == PROT_THREAD) break;
      scope_dup(tag->scope);
  }

  for (vars = ruby_dyna_vars; vars; vars = vars->next) {
      if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
      FL_SET(vars, DVAR_DONT_RECYCLE);
  }
  return th;
}


/*
 *  call-seq:
 *     callcc {|cont| block }   =>  obj
 *
 *  Generates a Continuation object, which it passes to the
 *  associated block. Performing a cont.call will
 *  cause the callcc to return (as will falling through the
 *  end of the block). The value returned by the callcc is
 *  the value of the block, or the value passed to
 *  cont.call. See class Continuation
 *  for more details. Also see Kernel::throw for
 *  an alternative mechanism for unwinding a call stack.
 */

static VALUE
rb_callcc(self)
    VALUE self;
{
    volatile rb_thread_t th = prep4callcc();
    return THREAD_SAVE_CONTEXT(th) ?
      th->result
          :
      rb_yield(Data_Wrap_Struct(rb_cCont, cc_mark, thread_free, th));
}


/*
 *  call-seq:
 *     cont.call(args, ...)
 *     cont[args, ...]
 *
 *  Invokes the continuation. The program continues from the end of the
 *  callcc block. If no arguments are given, the original
 *  callcc returns nil. If one argument is
 *  given, callcc returns it. Otherwise, an array
 *  containing args is returned.
 *
 *     callcc {|cont|  cont.call }           #=> nil
 *     callcc {|cont|  cont.call 1 }         #=> 1
 *     callcc {|cont|  cont.call 1, 2, 3 }   #=> [1, 2, 3]
 */

static VALUE
rb_cont_call(argc, argv, cont)
    int argc;
    VALUE *argv;
    VALUE cont;
{
    rb_thread_t th = THREAD_DATA(cont);

    if (th->thread != curr_thread->thread) {
        rb_raise(rb_eRuntimeError, "continuation called across threads");
    }
    if (th->thgroup != cont_protect) {
        rb_raise(rb_eRuntimeError, "continuation called across trap");
    }
    switch (argc) {
      case 0:
        th->result = Qnil;
        break;
      case 1:
        th->result = argv[0];
        break;
      default:
        th->result = rb_ary_new4(argc, argv);
        break;
    }

    rb_thread_restore_context(th, RESTORE_NORMAL);
    return Qnil;
}

#ifdef MBARI_API
/*
 *  call-seq:
 *     cont.thread
 *
 *  Returns the thread on which this continuation can be called
 *  or nil if that thread has died
 *
 *     t = Thread.new {callcc{|c| $x=c}; sleep 5}
 *     sleep 1
 *     $x.thread                             #=> t
 *     sleep 10
 *     $x.thread                             #=> nil
 *
 *  Only available when MBARI_API extentions are enabled at build time
 */
static VALUE
rb_cont_thread(cont)
  VALUE cont;
{
  rb_thread_t th = THREAD_DATA(cont);
  cc_purge(th);
  return th->thread;
}
#endif


struct thgroup {
    int enclosed;
    VALUE group;
};


/*
 * Document-class: ThreadGroup
 *
 *  ThreadGroup provides a means of keeping track of a number of
 *  threads as a group. A Thread can belong to only one
 *  ThreadGroup at a time; adding a thread to a new group will
 *  remove it from any previous group.
 *
 *  Newly created threads belong to the same group as the thread from which they
 *  were created.
 */

static VALUE thgroup_s_alloc _((VALUE));
static VALUE
thgroup_s_alloc(klass)
    VALUE klass;
{
    VALUE group;
    struct thgroup *data;

    group = Data_Make_Struct(klass, struct thgroup, 0, free, data);
    data->enclosed = 0;
    data->group = group;

    return group;
}


/*
 *  call-seq:
 *     thgrp.list   => array
 *
 *  Returns an array of all existing Thread objects that belong to
 *  this group.
 *
 *     ThreadGroup::Default.list   #=> [#]
 */

static VALUE
thgroup_list(group)
    VALUE group;
{
    struct thgroup *data;
    rb_thread_t th;
    VALUE ary;

    Data_Get_Struct(group, struct thgroup, data);
    ary = rb_ary_new();

    FOREACH_THREAD(th) {
        if (th->thgroup == data->group) {
            rb_ary_push(ary, th->thread);
        }
    }
    END_FOREACH(th);

    return ary;
}


/*
 *  call-seq:
 *     thgrp.enclose   => thgrp
 *
 *  Prevents threads from being added to or removed from the receiving
 *  ThreadGroup. New threads can still be started in an enclosed
 *  ThreadGroup.
 *
 *     ThreadGroup::Default.enclose        #=> #
 *     thr = Thread::new { Thread.stop }   #=> #
 *     tg = ThreadGroup::new               #=> #
 *     tg.add thr
 *
 *  produces:
 *
 *     ThreadError: can't move from the enclosed thread group
 */

static VALUE
thgroup_enclose(group)
    VALUE group;
{
    struct thgroup *data;

    Data_Get_Struct(group, struct thgroup, data);
    data->enclosed = 1;

    return group;
}


/*
 *  call-seq:
 *     thgrp.enclosed?   => true or false
 *
 *  Returns true if thgrp is enclosed. See also
 *  ThreadGroup#enclose.
 */

static VALUE
thgroup_enclosed_p(group)
    VALUE group;
{
    struct thgroup *data;

    Data_Get_Struct(group, struct thgroup, data);
    if (data->enclosed) return Qtrue;
    return Qfalse;
}


/*
 *  call-seq:
 *     thgrp.add(thread)   => thgrp
 *
 *  Adds the given thread to this group, removing it from any other
 *  group to which it may have previously belonged.
 *
 *     puts "Initial group is #{ThreadGroup::Default.list}"
 *     tg = ThreadGroup.new
 *     t1 = Thread.new { sleep }
 *     t2 = Thread.new { sleep }
 *     puts "t1 is #{t1}"
 *     puts "t2 is #{t2}"
 *     tg.add(t1)
 *     puts "Initial group now #{ThreadGroup::Default.list}"
 *     puts "tg group now #{tg.list}"
 *
 *  produces:
 *
 *     Initial group is #
 *     t1 is #
 *     t2 is #
 *     Initial group now ##
 *     tg group now #
 */

static VALUE
thgroup_add(group, thread)
    VALUE group, thread;
{
    rb_thread_t th;
    struct thgroup *data;

    rb_secure(4);
    th = rb_thread_check(thread);

    if (OBJ_FROZEN(group)) {
      rb_raise(rb_eThreadError, "can't move to the frozen thread group");
    }
    Data_Get_Struct(group, struct thgroup, data);
    if (data->enclosed) {
        rb_raise(rb_eThreadError, "can't move to the enclosed thread group");
    }

    if (!th->thgroup) {
        return Qnil;
    }
    if (OBJ_FROZEN(th->thgroup)) {
        rb_raise(rb_eThreadError, "can't move from the frozen thread group");
    }
    Data_Get_Struct(th->thgroup, struct thgroup, data);
    if (data->enclosed) {
        rb_raise(rb_eThreadError, "can't move from the enclosed thread group");
    }

    th->thgroup = group;
    return group;
}


/* variables for recursive traversals */
static ID recursive_key;

static VALUE
recursive_check(hash, obj)
    VALUE hash;
    VALUE obj;
{
    if (NIL_P(hash) || TYPE(hash) != T_HASH) {
        return Qfalse;
    }
    else {
        VALUE list = rb_hash_aref(hash, ID2SYM(rb_frame_last_func()));

        if (NIL_P(list) || TYPE(list) != T_HASH)
            return Qfalse;
        if (NIL_P(rb_hash_lookup(list, obj)))
            return Qfalse;
        return Qtrue;
    }
}

static VALUE
recursive_push(hash, obj)
    VALUE hash;
    VALUE obj;
{
    VALUE list, sym;

    sym = ID2SYM(rb_frame_last_func());
    if (NIL_P(hash) || TYPE(hash) != T_HASH) {
        hash = rb_hash_new();
        rb_thread_local_aset(rb_thread_current(), recursive_key, hash);
        list = Qnil;
    }
    else {
        list = rb_hash_aref(hash, sym);
    }
    if (NIL_P(list) || TYPE(list) != T_HASH) {
        list = rb_hash_new();
        rb_hash_aset(hash, sym, list);
    }
    rb_hash_aset(list, obj, Qtrue);
    return hash;
}

static void
recursive_pop(hash, obj)
    VALUE hash;
    VALUE obj;
{
    VALUE list, sym;

    sym = ID2SYM(rb_frame_last_func());
    if (NIL_P(hash) || TYPE(hash) != T_HASH) {
        VALUE symname;
        VALUE thrname;
        symname = rb_inspect(sym);
        thrname = rb_inspect(rb_thread_current());

        rb_raise(rb_eTypeError, "invalid inspect_tbl hash for %s in %s",
                 StringValuePtr(symname), StringValuePtr(thrname));
    }
    list = rb_hash_aref(hash, sym);
    if (NIL_P(list) || TYPE(list) != T_HASH) {
        VALUE symname = rb_inspect(sym);
        VALUE thrname = rb_inspect(rb_thread_current());
        rb_raise(rb_eTypeError, "invalid inspect_tbl list for %s in %s",
                 StringValuePtr(symname), StringValuePtr(thrname));
    }
    rb_hash_delete(list, obj);
}

VALUE
rb_exec_recursive(func, obj, arg)
    VALUE (*func) _((VALUE, VALUE, int));
    VALUE obj;
    VALUE arg;
{
    volatile VALUE hash =
      rb_thread_local_aref(rb_thread_current(), recursive_key);
    volatile VALUE objid = rb_obj_id(obj);

    if (recursive_check(hash, objid)) {
        return (*func) (obj, arg, Qtrue);
    }
    else {
        VALUE result;
        int state;

        hash = recursive_push(hash, objid);
        PUSH_TAG(PROT_EMPTY);
        result = (state = EXEC_TAG()) ? Qundef : (*func) (obj, arg, Qfalse);
        POP_TAG();
        recursive_pop(hash, objid);
        if (state)
            JUMP_TAG(state);
        return result;
    }
}


/*
 *  +Thread+ encapsulates the behavior of a thread of
 *  execution, including the main thread of the Ruby script.
 *
 *  In the descriptions of the methods in this class, the parameter _sym_
 *  refers to a symbol, which is either a quoted string or a
 *  +Symbol+ (such as :name).
 */

void
Init_Thread()
{
    VALUE cThGroup;

    rb_thread_stack_size = (1024 * 1024);

    recursive_key = rb_intern("__recursive_key__");
    rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError);
    rb_cThread = rb_define_class("Thread", rb_cObject);
    rb_undef_alloc_func(rb_cThread);

    rb_define_singleton_method(rb_cThread, "new", rb_thread_s_new, -1);
    rb_define_method(rb_cThread, "initialize", rb_thread_initialize, -2);
    rb_define_singleton_method(rb_cThread, "start", rb_thread_start, -2);
    rb_define_singleton_method(rb_cThread, "fork", rb_thread_start, -2);

    rb_define_singleton_method(rb_cThread, "stop", rb_thread_stop, 0);
    rb_define_singleton_method(rb_cThread, "kill", rb_thread_s_kill, 1);
    rb_define_singleton_method(rb_cThread, "exit", rb_thread_exit, 0);
    rb_define_singleton_method(rb_cThread, "pass", rb_thread_pass, 0);
    rb_define_singleton_method(rb_cThread, "current", rb_thread_current, 0);
    rb_define_singleton_method(rb_cThread, "main", rb_thread_main, 0);
    rb_define_singleton_method(rb_cThread, "list", rb_thread_list, 0);

    rb_define_singleton_method(rb_cThread, "critical", rb_thread_critical_get, 0);
    rb_define_singleton_method(rb_cThread, "critical=", rb_thread_critical_set, 1);

    rb_define_singleton_method(rb_cThread, "abort_on_exception", rb_thread_s_abort_exc, 0);
    rb_define_singleton_method(rb_cThread, "abort_on_exception=", rb_thread_s_abort_exc_set, 1);

    rb_define_singleton_method(rb_cThread, "stack_size", rb_thread_stacksize_get, 0);
    rb_define_singleton_method(rb_cThread, "stack_size=", rb_thread_stacksize_set, 1);

    rb_define_method(rb_cThread, "run", rb_thread_run, 0);
    rb_define_method(rb_cThread, "wakeup", rb_thread_wakeup, 0);
    rb_define_method(rb_cThread, "kill", rb_thread_kill, 0);
    rb_define_method(rb_cThread, "terminate", rb_thread_kill, 0);
    rb_define_method(rb_cThread, "exit", rb_thread_kill, 0);
    rb_define_method(rb_cThread, "kill!", rb_thread_kill_bang, 0);
    rb_define_method(rb_cThread, "terminate!", rb_thread_kill_bang, 0);
    rb_define_method(rb_cThread, "exit!", rb_thread_kill_bang, 0);
    rb_define_method(rb_cThread, "value", rb_thread_value, 0);
    rb_define_method(rb_cThread, "status", rb_thread_status, 0);
    rb_define_method(rb_cThread, "join", rb_thread_join_m, -1);
    rb_define_method(rb_cThread, "alive?", rb_thread_alive_p, 0);
    rb_define_method(rb_cThread, "stop?", rb_thread_stop_p, 0);
    rb_define_method(rb_cThread, "raise", rb_thread_raise_m, -1);

    rb_define_method(rb_cThread, "abort_on_exception", rb_thread_abort_exc, 0);
    rb_define_method(rb_cThread, "abort_on_exception=", rb_thread_abort_exc_set, 1);

    rb_define_method(rb_cThread, "priority", rb_thread_priority, 0);
    rb_define_method(rb_cThread, "priority=", rb_thread_priority_set, 1);
    rb_define_method(rb_cThread, "safe_level", rb_thread_safe_level, 0);
    rb_define_method(rb_cThread, "group", rb_thread_group, 0);

    rb_define_method(rb_cThread, "[]", rb_thread_aref, 1);
    rb_define_method(rb_cThread, "[]=", rb_thread_aset, 2);
    rb_define_method(rb_cThread, "key?", rb_thread_key_p, 1);
    rb_define_method(rb_cThread, "keys", rb_thread_keys, 0);

    rb_define_method(rb_cThread, "inspect", rb_thread_inspect, 0);

    rb_cCont = rb_define_class("Continuation", rb_cObject);
    rb_undef_alloc_func(rb_cCont);
    rb_undef_method(CLASS_OF(rb_cCont), "new");
    rb_define_method(rb_cCont, "call", rb_cont_call, -1);
    rb_define_method(rb_cCont, "[]", rb_cont_call, -1);
#ifdef MBARI_API
    rb_define_method(rb_cCont, "thread", rb_cont_thread, 0);
#endif
    /* rb_define_global_function("callcc", rb_callcc, 0); */
    rb_global_variable(&cont_protect);

    cThGroup = rb_define_class("ThreadGroup", rb_cObject);
    rb_define_alloc_func(cThGroup, thgroup_s_alloc);
    rb_define_method(cThGroup, "list", thgroup_list, 0);
    rb_define_method(cThGroup, "enclose", thgroup_enclose, 0);
    rb_define_method(cThGroup, "enclosed?", thgroup_enclosed_p, 0);
    rb_define_method(cThGroup, "add", thgroup_add, 1);
    rb_global_variable(&thgroup_default);
    thgroup_default = rb_obj_alloc(cThGroup);
    rb_define_const(cThGroup, "Default", thgroup_default);

    /* allocate main thread */
    main_thread = rb_thread_alloc(rb_cThread);
    curr_thread = main_thread->prev = main_thread->next = main_thread;
}

/*
 *  call-seq:
 *     catch(symbol) {| | block }  > obj
 *
 *  +catch+ executes its block. If a +throw+ is
 *  executed, Ruby searches up its stack for a +catch+ block
 *  with a tag corresponding to the +throw+'s
 *  _symbol_. If found, that block is terminated, and
 *  +catch+ returns the value given to +throw+. If
 *  +throw+ is not called, the block terminates normally, and
 *  the value of +catch+ is the value of the last expression
 *  evaluated. +catch+ expressions may be nested, and the
 *  +throw+ call need not be in lexical scope.
 *
 *     def routine(n)
 *       puts n
 *       throw :done if n <= 0
 *       routine(n-1)
 *     end
 *
 *
 *     catch(:done) { routine(3) }
 *
 *  produces:
 *
 *     3
 *     2
 *     1
 *     0
 */

static VALUE
rb_f_catch(dmy, tag)
    VALUE dmy;
    volatile VALUE tag;
{
    int state;
    VALUE val;

    tag = ID2SYM(rb_to_id(tag));
    PUSH_TAG(tag);
    if ((state = wipeAfter(EXEC_TAG_0())) == 0) {
        val = rb_yield_0(tag, 0, 0, 0, Qfalse);
    }
    else if (state == TAG_THROW && tag == prot_tag->dst) {
        val = prot_tag->retval;
        state = 0;
    }
    POP_TAG();
    if (state) JUMP_TAG(state);

    return val;
}

static VALUE
catch_i(tag)
    VALUE tag;
{
    return rb_funcall(Qnil, rb_intern("catch"), 1, tag);
}

VALUE
rb_catch(tag, func, data)
    const char *tag;
    VALUE (*func)();
    VALUE data;
{
    return rb_iterate((VALUE(*)_((VALUE)))catch_i, ID2SYM(rb_intern(tag)), func, data);
}

/*
 *  call-seq:
 *     throw(symbol [, obj])
 *
 *  Transfers control to the end of the active +catch+ block
 *  waiting for _symbol_. Raises +NameError+ if there
 *  is no +catch+ block for the symbol. The optional second
 *  parameter supplies a return value for the +catch+ block,
 *  which otherwise defaults to +nil+. For examples, see
 *  Kernel::catch.
 */

static VALUE
rb_f_throw(argc, argv)
    int argc;
    VALUE *argv;
{
    VALUE tag, value;
    struct tag *tt = prot_tag;

    rb_scan_args(argc, argv, "11", &tag, &value);
    tag = ID2SYM(rb_to_id(tag));

    while (tt) {
        if (tt->tag == tag) {
            tt->dst = tag;
            tt->retval = value;
            break;
        }
        if (tt->tag == PROT_THREAD) {
            rb_raise(rb_eThreadError, "uncaught throw `%s' in thread 0x%lx",
                     rb_id2name(SYM2ID(tag)),
                     curr_thread);
        }
        tt = tt->prev;
    }
    if (!tt) {
        rb_name_error(SYM2ID(tag), "uncaught throw `%s'", rb_id2name(SYM2ID(tag)));
    }
#if STACK_WIPE_SITES & 0x800
    rb_gc_update_stack_extent();
#endif
    rb_trap_restore_mask();
    JUMP_TAG(TAG_THROW);
#ifndef __GNUC__
    return Qnil;                /* not reached */
#endif
}

void
rb_throw(tag, val)
    const char *tag;
    VALUE val;
{
    VALUE argv[2];

    argv[0] = ID2SYM(rb_intern(tag));
    argv[1] = val;
    rb_f_throw(2, argv);
}

static VALUE
switch_thread_context_to_collect_backtrace(rb_thread_t next)
{
    if (THREAD_SAVE_CONTEXT(curr_thread)) {
        return Qnil;
    }
    curr_thread = next;
    rb_thread_restore_context(next, RESTORE_BACKTRACE);
    return Qnil;
}


/*
 *  call-seq:
 *     caller_for_all_threads(start=1)    => array
 *
 *  Returns the current execution stack for all threads
 *  ---a hash whose keys are thread instances and values
 *  the thread caller backtrace.
 *
 *  Backtraces are array of hashes indicating location on the
 *  stack. Hash keys include ``:line'' or ``:file''
 *  and ``:method'''.
 *
 *  The optional _start_ parameter
 *  determines the number of initial stack entries to omit from the
 *  result.
 *
 *     def a(skip)
 *       caller_for_all_threads(skip)
 *     end
 *     def b(skip)
 *       a(skip)
 *     end
 *     def c(skip)
 *       b(skip)
 *     end
 *     c(0)   #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10"]
 *     c(1)   #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11"]
 *     c(2)   #=> ["prog:8:in `c'", "prog:12"]
 *     c(3)   #=> ["prog:13"]
 */
static VALUE
rb_f_caller_for_all_threads(argc, argv)
    int argc;
    VALUE *argv;
{
    volatile int critical;
    VALUE level;
        VALUE result;

    rb_scan_args(argc, argv, "01", &level);
    backtrace_level_for_each_thread = NIL_P(level) ? 0 : NUM2INT(level);
        if (backtrace_level_for_each_thread < 0) {
                rb_raise(rb_eArgError, "negative level (%d)", backtrace_level_for_each_thread);
        }

        critical = rb_thread_critical;
        rb_thread_critical = Qtrue;

    backtrace_for_each_thread = rb_hash_new();
    switch_thread_context_to_collect_backtrace(main_thread->next);

        result = backtrace_for_each_thread;
        backtrace_for_each_thread = Qnil;
        backtrace_for_each_thread = 0;

        rb_thread_critical = critical;
    return result;
}


================================================
FILE: ext/.cvsignore
================================================
extinit.c
*.log


================================================
FILE: ext/.document
================================================
# Add files to this as they become documented

enumerator/enumerator.c
iconv/iconv.c
nkf/lib/kconv.rb
nkf/nkf.c
socket/socket.c
stringio/stringio.c
strscan/strscan.c
win32ole
zlib/zlib.c


================================================
FILE: ext/Setup
================================================
#option nodynamic

#Win32API
#bigdecimal
#curses
#dbm
#digest
#digest/md5
#digest/rmd160
#digest/sha1
#digest/sha2
#dl
#enumerator
#etc
#fcntl
#gdbm
#iconv
#io/wait
#nkf
#pty
#openssl
#racc/cparse
#rational
#readline
#sdbm
#socket
#stringio
#strscan
#syck
#syslog
#tcltklib
#thread
#tk
#trace
#win32ole
#zlib


================================================
FILE: ext/Setup.atheos
================================================
option nodynamic

#Win32API
bigdecimal
curses
dbm
digest
digest/md5
digest/rmd160
digest/sha1
digest/sha2
dl
enumerator
etc
fcntl
gdbm
iconv
io/wait
nkf
pty
#openssl
racc/parse
rational
readline
sdbm
socket
stringio
strscan
syck
syslog
#tcltklib
thread
#tk
#win32ole
zlib


================================================
FILE: ext/Setup.dj
================================================
option nodynamic

#Win32API
bigdecimal
curses
dbm
digest
digest/md5
digest/rmd160
digest/sha1
digest/sha2
#dl
etc
enumerator
fcntl
gdbm
#iconv
#io/wait
nkf
#pty
#openssl
racc/cparse
rational
readline
sdbm
#socket
stringio
strscan
syck
#syslog
#tcltklib
thread
#tk
#win32ole
zlib


================================================
FILE: ext/Setup.emx
================================================
option nodynamic

#Win32API
bigdecimal
curses
#dbm
digest
digest/md5
digest/rmd160
digest/sha1
digest/sha2
#dl
enumerator
etc
fcntl
#gdbm
#iconv
#io/wait
nkf
#pty
#openssl
racc/cparse
rational
#readline
#sdbm
socket
stringio
strscan
#syck
#syslog
#tcltklib
thread
#tk
#win32ole
#zlib


================================================
FILE: ext/Setup.nt
================================================
#option nodynamic

Win32API
bigdecimal
#curses
#dbm
digest
digest/md5
digest/rmd160
digest/sha1
digest/sha2
dl
enumerator
etc
fcntl
#gdbm
#iconv
#io/wait
nkf
#pty
#openssl
racc/cparse
rational
#readline
sdbm
socket
stringio
strscan
syck
#syslog
#tcltklib
thread
#tk
win32ole
#zlib


================================================
FILE: ext/Setup.x68
================================================
option nodynamic

#Win32API
bigdecimal
#curses
dbm
digest
digest/md5
digest/rmd160
digest/sha1
digest/sha2
#dl
#etc
enumerator
fcntl
#gdbm
#iconv
#io/wait
nkf
#pty
#openssl
racc/cparse
rational
#readline
#sdbm
#socket
stringio
strscan
#syck
#syslog
#tcltklib
thread
#tk
#win32ole
#zlib


================================================
FILE: ext/Win32API/.cvsignore
================================================
Makefile
*.log
*.def


================================================
FILE: ext/Win32API/Win32API.c
================================================
/*
  Win32API - Ruby Win32 API Import Facility
*/

#if !defined _MSC_VER && !defined _WIN32
#define  WIN32_LEAN_AND_MEAN
#include 
#include 
#endif

#define _T_VOID     0
#define _T_NUMBER   1
#define _T_POINTER  2
#define _T_INTEGER  3

#include "ruby.h"

typedef struct {
    HANDLE dll;
    HANDLE proc;
    VALUE dllname;
    VALUE import;
    VALUE export;
} Win32API;

static void
Win32API_FreeLibrary(hdll)
    HINSTANCE hdll;
{
    FreeLibrary(hdll);
}

static VALUE
Win32API_initialize(self, dllname, proc, import, export)
    VALUE self;
    VALUE dllname;
    VALUE proc;
    VALUE import;
    VALUE export;
{
    HANDLE hproc;
    HINSTANCE hdll;
    VALUE str;
    VALUE a_import;
    VALUE *ptr;
    char *s;
    int i;
    int len;
    int ex = _T_VOID;

    SafeStringValue(dllname);
    SafeStringValue(proc);
    hdll = LoadLibrary(RSTRING(dllname)->ptr);
    if (!hdll)
	rb_raise(rb_eRuntimeError, "LoadLibrary: %s\n", RSTRING(dllname)->ptr);
    rb_iv_set(self, "__hdll__", Data_Wrap_Struct(rb_cData, 0, Win32API_FreeLibrary, (void*)hdll));
    hproc = (HANDLE)GetProcAddress(hdll, RSTRING(proc)->ptr);
    if (!hproc) {
	str = rb_str_new3(proc);
	str = rb_str_cat(str, "A", 1);
	hproc = (HANDLE)GetProcAddress(hdll, RSTRING(str)->ptr);
	if (!hproc)
	    rb_raise(rb_eRuntimeError, "GetProcAddress: %s or %s\n",
		RSTRING(proc)->ptr, RSTRING(str)->ptr);
    }
    rb_iv_set(self, "__dll__", UINT2NUM((unsigned long)hdll));
    rb_iv_set(self, "__dllname__", dllname);
    rb_iv_set(self, "__proc__", UINT2NUM((unsigned long)hproc));

    a_import = rb_ary_new();
    switch (TYPE(import)) {
    case T_NIL:
	break;
    case T_ARRAY:
	ptr = RARRAY(import)->ptr;
	for (i = 0, len = RARRAY(import)->len; i < len; i++) {
	    SafeStringValue(ptr[i]);
	    switch (*(char *)RSTRING(ptr[i])->ptr) {
	    case 'N': case 'n': case 'L': case 'l':
		rb_ary_push(a_import, INT2FIX(_T_NUMBER));
		break;
	    case 'P': case 'p':
		rb_ary_push(a_import, INT2FIX(_T_POINTER));
		break;
	    case 'I': case 'i':
		rb_ary_push(a_import, INT2FIX(_T_INTEGER));
		break;
	    }
	}
        break;
    default:
	SafeStringValue(import);
	s = RSTRING(import)->ptr;
	for (i = 0, len = RSTRING(import)->len; i < len; i++) {
	    switch (*s++) {
	    case 'N': case 'n': case 'L': case 'l':
		rb_ary_push(a_import, INT2FIX(_T_NUMBER));
		break;
	    case 'P': case 'p':
		rb_ary_push(a_import, INT2FIX(_T_POINTER));
		break;
	    case 'I': case 'i':
		rb_ary_push(a_import, INT2FIX(_T_INTEGER));
		break;
	    }
	}
        break;
    }

    if (16 < RARRAY(a_import)->len) {
	rb_raise(rb_eRuntimeError, "too many parameters: %ld\n", RARRAY(a_import)->len);
    }

    rb_iv_set(self, "__import__", a_import);

    if (NIL_P(export)) {
	ex = _T_VOID;
    } else {
	SafeStringValue(export);
	switch (*RSTRING(export)->ptr) {
        case 'V': case 'v':
	    ex = _T_VOID;
	    break;
	case 'N': case 'n': case 'L': case 'l':
	    ex = _T_NUMBER;
	    break;
	case 'P': case 'p':
	    ex = _T_POINTER;
	    break;
	case 'I': case 'i':
	    ex = _T_INTEGER;
	    break;
	}
    }
    rb_iv_set(self, "__export__", INT2FIX(ex));

    return Qnil;
}

#ifdef _MSC_VER
#pragma optimize("g", off)
#endif
static VALUE
Win32API_Call(argc, argv, obj)
    int argc;
    VALUE *argv;
    VALUE obj;
{
    VALUE args;
    unsigned long ret;
    int i;
    struct {
	unsigned long params[16];
    } param;
#define params param.params

    VALUE obj_proc = rb_iv_get(obj, "__proc__");
    VALUE obj_import = rb_iv_get(obj, "__import__");
    VALUE obj_export = rb_iv_get(obj, "__export__");
    FARPROC ApiFunction = (FARPROC)NUM2ULONG(obj_proc);
    int items = rb_scan_args(argc, argv, "0*", &args);
    int nimport = RARRAY(obj_import)->len;


    if (items != nimport)
	rb_raise(rb_eRuntimeError, "wrong number of parameters: expected %d, got %d",
	    nimport, items);

    for (i = 0; i < nimport; i++) {
	unsigned long lParam = 0;
	switch (FIX2INT(rb_ary_entry(obj_import, i))) {
	    VALUE str;
	case _T_NUMBER:
	case _T_INTEGER:
	default:
	    lParam = NUM2ULONG(rb_ary_entry(args, i));
	    break;
	case _T_POINTER:
	    str = rb_ary_entry(args, i);
	    if (NIL_P(str)) {
		lParam = 0;
	    } else if (FIXNUM_P(str)) {
		lParam = NUM2ULONG(str);
	    } else {
		StringValue(str);
		rb_str_modify(str);
		lParam = (unsigned long)StringValuePtr(str);
	    }
	    break;
	}
	params[i] = lParam;
    }

    ret = ApiFunction(param);

    switch (FIX2INT(obj_export)) {
    case _T_NUMBER:
    case _T_INTEGER:
	return INT2NUM(ret);
    case _T_POINTER:
	return rb_str_new2((char *)ret);
    case _T_VOID:
    default:
	return INT2NUM(0);
    }
}

void
Init_Win32API()
{
    VALUE cWin32API = rb_define_class("Win32API", rb_cObject);
    rb_define_method(cWin32API, "initialize", Win32API_initialize, 4);
    rb_define_method(cWin32API, "call", Win32API_Call, -1);
    rb_define_alias(cWin32API,  "Call", "call");
}


================================================
FILE: ext/Win32API/depend
================================================
Win32API.o : Win32API.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h


================================================
FILE: ext/Win32API/extconf.rb
================================================
require 'mkmf'

dir_config("win32")
if have_header("windows.h") and have_library("kernel32")
  create_makefile("Win32API")
end


================================================
FILE: ext/Win32API/getch.rb
================================================
require 'Win32API'

getch = Win32API.new("crtdll", "_getch", [], 'L')

puts getch.Call.chr


================================================
FILE: ext/Win32API/lib/win32/registry.rb
================================================
=begin
= Win32 Registry I/F
win32/registry is registry accessor library for Win32 platform.
It uses Win32API to call Win32 Registry APIs.

== example
  Win32::Registry::HKEY_CURRENT_USER.open('SOFTWARE\foo') do |reg|
    value = reg['foo']                               # read a value
    value = reg['foo', Win32::Registry::REG_SZ]      # read a value with type
    type, value = reg.read('foo')                    # read a value
    reg['foo'] = 'bar'                               # write a value
    reg['foo', Win32::Registry::REG_SZ] = 'bar'      # write a value with type
    reg.write('foo', Win32::Registry::REG_SZ, 'bar') # write a value
    
    reg.each_value { |name, type, data| ... }        # Enumerate values
    reg.each_key { |key, wtime| ... }                # Enumerate subkeys
    
    reg.delete_value(name)                         # Delete a value
    reg.delete_key(name)                           # Delete a subkey
    reg.delete_key(name, true)                     # Delete a subkey recursively
  end

= Reference

== Win32::Registry class

=== including modules

* Enumerable
* Registry::Constants

=== class methods
--- Registry.open(key, subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED)
--- Registry.open(key, subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED) { |reg| ... }
    Open the registry key ((|subkey|)) under ((|key|)).
    ((|key|)) is Win32::Registry object of parent key.
    You can use predefined key HKEY_* (see (()))
    
    ((|desired|)) and ((|opt|)) is access mask and key option.
    For detail, see (()).
    
    If block is given, the key is closed automatically.

--- Registry.create(key, subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED)
--- Registry.create(key, subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED) { |reg| ... }
    Create or open the registry key ((|subkey|)) under ((|key|)).
    You can use predefined key HKEY_* (see (()))
    
    If subkey is already exists, key is opened and Registry#(())
    method will return false.
    
    If block is given, the key is closed automatically.

--- Registry.expand_environ(str)
    Replace (({%\w+%})) into the environment value of ((|str|)).
    This method is used for REG_EXPAND_SZ.
    
    For detail, see (()) Win32 API.

--- Registry.type2name(type)
    Convert registry type value to readable string.

--- Registry.wtime2time(wtime)
    Convert 64-bit FILETIME integer into Time object.

--- Registry.time2wtime(time)
    Convert Time object or Integer object into 64-bit FILETIME.

=== instance methods
--- open(subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED)
    Same as (({Win32::(())(self, subkey, desired, opt)}))

--- create(subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED)
    Same as (({Win32::(())(self, subkey, desired, opt)}))

--- close
    Close key.
    
    After closed, most method raises error.

--- read(name, *rtype)
    Read a registry value named ((|name|)) and return array of
    [ ((|type|)), ((|data|)) ].
    When name is nil, the `default' value is read.
    
    ((|type|)) is value type. (see (()))
    ((|data|)) is value data, its class is:
    :REG_SZ, REG_EXPAND_SZ
       String
    :REG_MULTI_SZ
       Array of String
    :REG_DWORD, REG_DWORD_BIG_ENDIAN, REG_QWORD
       Integer
    :REG_BINARY
       String (contains binary data)
    
    When ((|rtype|)) is specified, the value type must be included by
    ((|rtype|)) array, or TypeError is raised.

--- self[name, *rtype]
    Read a registry value named ((|name|)) and return its value data.
    The class of value is same as (()) method returns.
    
    If the value type is REG_EXPAND_SZ, returns value data whose environment
    variables are replaced.
    If the value type is neither REG_SZ, REG_MULTI_SZ, REG_DWORD,
    REG_DWORD_BIG_ENDIAN, nor REG_QWORD, TypeError is raised.
    
    The meaning of ((|rtype|)) is same as (()) method.

--- read_s(name)
--- read_i(name)
--- read_bin(name)
    Read a REG_SZ(read_s), REG_DWORD(read_i), or REG_BINARY(read_bin)
    registry value named ((|name|)).
    
    If the values type does not match, TypeError is raised.

--- read_s_expand(name)
    Read a REG_SZ or REG_EXPAND_SZ registry value named ((|name|)).
    
    If the value type is REG_EXPAND_SZ, environment variables are replaced.
    Unless the value type is REG_SZ or REG_EXPAND_SZ, TypeError is raised.

--- write(name, type, data)
    Write ((|data|)) to a registry value named ((|name|)).
    When name is nil, write to the `default' value.
    
    ((|type|)) is type value. (see (()))
    Class of ((|data|)) must be same as which (())
    method returns.

--- self[name, wtype = nil] = value
    Write ((|value|)) to a registry value named ((|name|)).
    
    If ((|wtype|)) is specified, the value type is it.
    Otherwise, the value type is depend on class of ((|value|)):
    :Integer
      REG_DWORD
    :String
      REG_SZ
    :Array
      REG_MULTI_SZ

--- write_s(name, value)
--- write_i(name, value)
--- write_bin(name, value)
    Write ((|value|)) to a registry value named ((|name|)).
    
    The value type is REG_SZ(write_s), REG_DWORD(write_i), or
    REG_BINARY(write_bin).

--- each { |name, type, value| ... }
--- each_value { |name, type, value| ... }
    Enumerate values.

--- each_key { |subkey, wtime| ... }
    Enumerate subkeys.
    
    ((|subkey|)) is String which contains name of subkey.
    ((|wtime|)) is last write time as FILETIME (64-bit integer).
    (see (()))

--- delete(name)
--- delete_value(name)
    Delete a registry value named ((|name|)).
    We can not delete the `default' value.

--- delete_key(name, recursive = false)
    Delete a subkey named ((|name|)) and all its values.
    
    If ((|recursive|)) is false, the subkey must not have subkeys.
    Otherwise, this method deletes all subkeys and values recursively.

--- flush
    Write all the attributes into the registry file.

--- created?
    Returns if key is created ((*newly*)).
    (see (()))

--- open?
    Returns if key is not closed.

--- hkey
    Returns key handle value.

--- parent
    Win32::Registry object of parent key, or nil if predefeined key.

--- keyname
    Same as ((|subkey|)) value of (()) or
    (()) method.

--- disposition
    Disposition value (REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY).

--- name
--- to_s
    Full path of key such as (({'HKEY_CURRENT_USER\SOFTWARE\foo\bar'})).

--- info
    Returns key information as Array of:
    :num_keys
      The number of subkeys.
    :max_key_length
      Maximum length of name of subkeys.
    :num_values
      The number of values.
    :max_value_name_length
      Maximum length of name of values.
    :max_value_length
      Maximum length of value of values.
    :descriptor_length
      Length of security descriptor.
    :wtime
      Last write time as FILETIME(64-bit integer)
    
    For detail, see (()) Win32 API.

--- num_keys
--- max_key_length
--- num_values
--- max_value_name_length
--- max_value_length
--- descriptor_length
--- wtime
    Returns an item of key information.

=== constants
--- HKEY_CLASSES_ROOT
--- HKEY_CURRENT_USER
--- HKEY_LOCAL_MACHINE
--- HKEY_PERFORMANCE_DATA
--- HKEY_CURRENT_CONFIG
--- HKEY_DYN_DATA
    Win32::Registry object whose key is predefined key.
    For detail, see (()).

== Win32::Registry::Constants module

For detail, see (()).

--- HKEY_*
    Predefined key ((*handle*)).
    These are Integer, not Win32::Registry.

--- REG_*
    Registry value type.

--- KEY_*
    Security access mask.

--- KEY_OPTIONS_*
    Key options.

--- REG_CREATED_NEW_KEY
--- REG_OPENED_EXISTING_KEY
    If the key is created newly or opened existing key.
    See also Registry#(()) method.

=end

require 'Win32API'

module Win32
  class Registry
    module Constants
      HKEY_CLASSES_ROOT = 0x80000000
      HKEY_CURRENT_USER = 0x80000001
      HKEY_LOCAL_MACHINE = 0x80000002
      HKEY_USERS = 0x80000003
      HKEY_PERFORMANCE_DATA = 0x80000004
      HKEY_PERFORMANCE_TEXT = 0x80000050
      HKEY_PERFORMANCE_NLSTEXT = 0x80000060
      HKEY_CURRENT_CONFIG = 0x80000005
      HKEY_DYN_DATA = 0x80000006
      
      REG_NONE = 0
      REG_SZ = 1
      REG_EXPAND_SZ = 2
      REG_BINARY = 3
      REG_DWORD = 4
      REG_DWORD_LITTLE_ENDIAN = 4
      REG_DWORD_BIG_ENDIAN = 5
      REG_LINK = 6
      REG_MULTI_SZ = 7
      REG_RESOURCE_LIST = 8
      REG_FULL_RESOURCE_DESCRIPTOR = 9
      REG_RESOURCE_REQUIREMENTS_LIST = 10
      REG_QWORD = 11
      REG_QWORD_LITTLE_ENDIAN = 11
      
      STANDARD_RIGHTS_READ = 0x00020000
      STANDARD_RIGHTS_WRITE = 0x00020000
      KEY_QUERY_VALUE = 0x0001
      KEY_SET_VALUE = 0x0002
      KEY_CREATE_SUB_KEY = 0x0004
      KEY_ENUMERATE_SUB_KEYS = 0x0008
      KEY_NOTIFY = 0x0010
      KEY_CREATE_LINK = 0x0020
      KEY_READ = STANDARD_RIGHTS_READ |
        KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY
      KEY_WRITE = STANDARD_RIGHTS_WRITE |
        KEY_SET_VALUE | KEY_CREATE_SUB_KEY
      KEY_EXECUTE = KEY_READ
      KEY_ALL_ACCESS = KEY_READ | KEY_WRITE | KEY_CREATE_LINK
      
      REG_OPTION_RESERVED = 0x0000
      REG_OPTION_NON_VOLATILE = 0x0000
      REG_OPTION_VOLATILE = 0x0001
      REG_OPTION_CREATE_LINK = 0x0002
      REG_OPTION_BACKUP_RESTORE = 0x0004
      REG_OPTION_OPEN_LINK = 0x0008
      REG_LEGAL_OPTION = REG_OPTION_RESERVED |
        REG_OPTION_NON_VOLATILE | REG_OPTION_CREATE_LINK |
        REG_OPTION_BACKUP_RESTORE | REG_OPTION_OPEN_LINK
      
      REG_CREATED_NEW_KEY = 1
      REG_OPENED_EXISTING_KEY = 2
      
      REG_WHOLE_HIVE_VOLATILE = 0x0001
      REG_REFRESH_HIVE = 0x0002
      REG_NO_LAZY_FLUSH = 0x0004
      REG_FORCE_RESTORE = 0x0008
      
      MAX_KEY_LENGTH = 514
      MAX_VALUE_LENGTH = 32768
    end
    include Constants
    include Enumerable
    
    #
    # Error
    #
    class Error < ::StandardError
      FormatMessageA = Win32API.new('kernel32.dll', 'FormatMessageA', 'LPLLPLP', 'L')
      def initialize(code)
        @code = code
        msg = "\0" * 1024
        len = FormatMessageA.call(0x1200, 0, code, 0, msg, 1024, 0)
        super msg[0, len].tr("\r", '').chomp
      end
      attr_reader :code
    end
    
    #
    # Predefined Keys
    #
    class PredefinedKey < Registry
      def initialize(hkey, keyname)
        @hkey = hkey
        @parent = nil
        @keyname = keyname
        @disposition = REG_OPENED_EXISTING_KEY
      end
      
      # Predefined keys cannot be closed
      def close
        raise Error.new(5) ## ERROR_ACCESS_DENIED
      end
      
      # Fake class for Registry#open, Registry#create
      def class
        Registry
      end
      
      # Make all
      Constants.constants.grep(/^HKEY_/) do |c|
        Registry.const_set c, new(Constants.const_get(c), c)
      end
    end
    
    #
    # Win32 APIs
    #
    module API
      [
        %w/RegOpenKeyExA    LPLLP        L/,
        %w/RegCreateKeyExA  LPLLLLPPP    L/,
        %w/RegEnumValueA    LLPPPPPP     L/,
        %w/RegEnumKeyExA    LLPPLLLP     L/,
        %w/RegQueryValueExA LPLPPP       L/,
        %w/RegSetValueExA   LPLLPL       L/,
        %w/RegDeleteValue   LP           L/,
        %w/RegDeleteKey     LP           L/,
        %w/RegFlushKey      L            L/,
        %w/RegCloseKey      L            L/,
        %w/RegQueryInfoKey  LPPPPPPPPPPP L/,
      ].each do |fn|
        const_set fn[0].intern, Win32API.new('advapi32.dll', *fn)
      end
      
      module_function
      
      def check(result)
        raise Error, result, caller(2) if result != 0
      end
      
      def packdw(dw)
        [dw].pack('V')
      end
      
      def unpackdw(dw)
        dw += [0].pack('V')
        dw.unpack('V')[0]
      end
      
      def packqw(qw)
        [ qw & 0xFFFFFFFF, qw >> 32 ].pack('VV')
      end
      
      def unpackqw(qw)
        qw = qw.unpack('VV')
        (qw[1] << 32) | qw[0]
      end
      
      def OpenKey(hkey, name, opt, desired)
        result = packdw(0)
        check RegOpenKeyExA.call(hkey, name, opt, desired, result)
        unpackdw(result)
      end
      
      def CreateKey(hkey, name, opt, desired)
        result = packdw(0)
        disp = packdw(0)
        check RegCreateKeyExA.call(hkey, name, 0, 0, opt, desired,
                                   0, result, disp)
        [ unpackdw(result), unpackdw(disp) ]
      end
      
      def EnumValue(hkey, index)
        name = ' ' * Constants::MAX_KEY_LENGTH
        size = packdw(Constants::MAX_KEY_LENGTH)
        check RegEnumValueA.call(hkey, index, name, size, 0, 0, 0, 0)
        name[0, unpackdw(size)]
      end
      
      def EnumKey(hkey, index)
        name = ' ' * Constants::MAX_KEY_LENGTH
        size = packdw(Constants::MAX_KEY_LENGTH)
        wtime = ' ' * 8
        check RegEnumKeyExA.call(hkey, index, name, size, 0, 0, 0, wtime)
        [ name[0, unpackdw(size)], unpackqw(wtime) ]
      end
      
      def QueryValue(hkey, name)
        type = packdw(0)
        size = packdw(0)
        check RegQueryValueExA.call(hkey, name, 0, type, 0, size)
        data = ' ' * unpackdw(size)
        check RegQueryValueExA.call(hkey, name, 0, type, data, size)
        [ unpackdw(type), data[0, unpackdw(size)] ]
      end
      
      def SetValue(hkey, name, type, data, size)
        check RegSetValueExA.call(hkey, name, 0, type, data, size)
      end
      
      def DeleteValue(hkey, name)
        check RegDeleteValue.call(hkey, name)
      end
      
      def DeleteKey(hkey, name)
        check RegDeleteKey.call(hkey, name)
      end
      
      def FlushKey(hkey)
        check RegFlushKey.call(hkey)
      end
      
      def CloseKey(hkey)
        check RegCloseKey.call(hkey)
      end
      
      def QueryInfoKey(hkey)
        subkeys = packdw(0)
        maxsubkeylen = packdw(0)
        values = packdw(0)
        maxvaluenamelen = packdw(0)
        maxvaluelen = packdw(0)
        secdescs = packdw(0)
        wtime = ' ' * 8
        check RegQueryInfoKey.call(hkey, 0, 0, 0, subkeys, maxsubkeylen, 0,
          values, maxvaluenamelen, maxvaluelen, secdescs, wtime)
        [ unpackdw(subkeys), unpackdw(maxsubkeylen), unpackdw(values),
          unpackdw(maxvaluenamelen), unpackdw(maxvaluelen),
          unpackdw(secdescs), unpackqw(wtime) ]
      end
    end
    
    #
    # utility functions
    #
    def self.expand_environ(str)
      str.gsub(/%([^%]+)%/) { ENV[$1] || ENV[$1.upcase] || $& }
    end
    
    @@type2name = { }
    %w[
      REG_NONE REG_SZ REG_EXPAND_SZ REG_BINARY REG_DWORD
      REG_DWORD_BIG_ENDIAN REG_LINK REG_MULTI_SZ
      REG_RESOURCE_LIST REG_FULL_RESOURCE_DESCRIPTOR
      REG_RESOURCE_REQUIREMENTS_LIST REG_QWORD
    ].each do |type|
      @@type2name[Constants.const_get(type)] = type
    end
    
    def self.type2name(type)
      @@type2name[type] || type.to_s
    end
    
    def self.wtime2time(wtime)
      Time.at((wtime - 116444736000000000) / 10000000)
    end
    
    def self.time2wtime(time)
      time.to_i * 10000000 + 116444736000000000
    end
    
    #
    # constructors
    #
    private_class_method :new
    
    def self.open(hkey, subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED)
      subkey = subkey.chomp('\\')
      newkey = API.OpenKey(hkey.hkey, subkey, opt, desired)
      obj = new(newkey, hkey, subkey, REG_OPENED_EXISTING_KEY)
      if block_given?
        begin
          yield obj
        ensure
          obj.close
        end
      else
        obj
      end
    end
    
    def self.create(hkey, subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED)
      newkey, disp = API.CreateKey(hkey.hkey, subkey, opt, desired)
      obj = new(newkey, hkey, subkey, disp)
      if block_given?
        begin
          yield obj
        ensure
          obj.close
        end
      else
        obj
      end
    end
    
    #
    # finalizer
    #
    @@final = proc { |hkey| proc { API.CloseKey(hkey[0]) if hkey[0] } }
    
    #
    # initialize
    #
    def initialize(hkey, parent, keyname, disposition)
      @hkey = hkey
      @parent = parent
      @keyname = keyname
      @disposition = disposition
      @hkeyfinal = [ hkey ]
      ObjectSpace.define_finalizer self, @@final.call(@hkeyfinal)
    end
    attr_reader :hkey, :parent, :keyname, :disposition
    
    #
    # attributes
    #
    def created?
      @disposition == REG_CREATED_NEW_KEY
    end
    
    def open?
      !@hkey.nil?
    end
    
    def name
      parent = self
      name = @keyname
      while parent = parent.parent
        name = parent.keyname + '\\' + name
      end
      name
    end
    
    def inspect
      "\#"
    end
    
    #
    # marshalling
    #
    def _dump(depth)
      raise TypeError, "can't dump Win32::Registry"
    end
    
    #
    # open/close
    #
    def open(subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED, &blk)
      self.class.open(self, subkey, desired, opt, &blk)
    end
    
    def create(subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED, &blk)
      self.class.create(self, subkey, desired, opt, &blk)
    end
    
    def close
      API.CloseKey(@hkey)
      @hkey = @parent = @keyname = nil
      @hkeyfinal[0] = nil
    end
    
    #
    # iterator
    #
    def each_value
      index = 0
      while true
        begin
          subkey = API.EnumValue(@hkey, index)
        rescue Error
          break
        end
        begin
          type, data = read(subkey)
        rescue Error
          next
        end
        yield subkey, type, data
        index += 1
      end
      index
    end
    alias each each_value
    
    def each_key
      index = 0
      while true
        begin
          subkey, wtime = API.EnumKey(@hkey, index)
        rescue Error
          break
        end
        yield subkey, wtime
        index += 1
      end
      index
    end
    
    def keys
      keys_ary = []
      each_key { |key,| keys_ary << key }
      keys_ary
    end
    
    #
    # reader
    #
    def read(name, *rtype)
      type, data = API.QueryValue(@hkey, name)
      unless rtype.empty? or rtype.include?(type)
        raise TypeError, "Type mismatch (expect #{rtype.inspect} but #{type} present)"
      end
      case type
      when REG_SZ, REG_EXPAND_SZ
        [ type, data.chop ]
      when REG_MULTI_SZ
        [ type, data.split(/\0/) ]
      when REG_BINARY
        [ type, data ]
      when REG_DWORD
        [ type, API.unpackdw(data) ]
      when REG_DWORD_BIG_ENDIAN
        [ type, data.unpack('N')[0] ]
      when REG_QWORD
        [ type, API.unpackqw(data) ]
      else
        raise TypeError, "Type #{type} is not supported."
      end
    end
    
    def [](name, *rtype)
      type, data = read(name, *rtype)
      case type
      when REG_SZ, REG_DWORD, REG_QWORD, REG_MULTI_SZ
        data
      when REG_EXPAND_SZ
        Registry.expand_environ(data)
      else
        raise TypeError, "Type #{type} is not supported."
      end
    end
    
    def read_s(name)
      read(name, REG_SZ)[1]
    end
    
    def read_s_expand(name)
      type, data = read(name, REG_SZ, REG_EXPAND_SZ)
      if type == REG_EXPAND_SZ
        Registry.expand_environ(data)
      else
        data
      end
    end
    
    def read_i(name)
      read(name, REG_DWORD, REG_DWORD_BIG_ENDIAN, REG_QWORD)[1]
    end
    
    def read_bin(name)
      read(name, REG_BINARY)[1]
    end
    
    #
    # writer
    #
    def write(name, type, data)
      case type
      when REG_SZ, REG_EXPAND_SZ
        data = data.to_s + "\0"
      when REG_MULTI_SZ
        data = data.to_a.join("\0") + "\0\0"
      when REG_BINARY
        data = data.to_s
      when REG_DWORD
        data = API.packdw(data.to_i)
      when REG_DWORD_BIG_ENDIAN
        data = [data.to_i].pack('N')
      when REG_QWORD
        data = API.packqw(data.to_i)
      else
        raise TypeError, "Unsupported type #{type}"
      end
      API.SetValue(@hkey, name, type, data, data.length)
    end
    
    def []=(name, rtype, value = nil)
      if value
        write name, rtype, value
      else
        case value = rtype
        when Integer
          write name, REG_DWORD, value
        when String
          write name, REG_SZ, value
        when Array
          write name, REG_MULTI_SZ, value
        else
          raise TypeError, "Unexpected type #{value.class}"
        end
      end
      value
    end
    
    def write_s(name, value)
      write name, REG_SZ, value.to_s
    end
    
    def write_i(name, value)
      write name, REG_DWORD, value.to_i
    end
    
    def write_bin(name, value)
      write name, REG_BINARY, value.to_s
    end
    
    #
    # delete
    #
    def delete_value(name)
      API.DeleteValue(@hkey, name)
    end
    alias delete delete_value
    
    def delete_key(name, recursive = false)
      if recursive
        open(name, KEY_ALL_ACCESS) do |reg|
          reg.keys.each do |key|
            begin
              reg.delete_key(key, true)
            rescue Error
              #
            end
          end
        end
        API.DeleteKey(@hkey, name)
      else
        begin
          API.EnumKey @hkey, 0
        rescue Error
          return API.DeleteKey(@hkey, name)
        end
        raise Error.new(5) ## ERROR_ACCESS_DENIED
      end
    end
    
    #
    # flush
    #
    def flush
      API.FlushKey @hkey
    end
    
    #
    # key information
    #
    def info
      API.QueryInfoKey(@hkey)
    end
    %w[
      num_keys max_key_length
      num_values max_value_name_length max_value_length
      descriptor_length wtime
    ].each_with_index do |s, i|
      eval <<-__END__
        def #{s}
          info[#{i}]
        end
      __END__
    end
  end
end


================================================
FILE: ext/Win32API/lib/win32/resolv.rb
================================================
=begin
= Win32 DNS and DHCP I/F

=end

require 'win32/registry'

module Win32
  module Resolv
    API = Registry::API
    
    def self.get_hosts_path
      path = get_hosts_dir
      path = File.expand_path('hosts', path)
      File.exist?(path) ? path : nil
    end
    
    def self.get_resolv_info
      search, nameserver = get_info
      if search.empty?
        search = nil
      else
        search.delete("")
        search.uniq!
      end
      if nameserver.empty?
        nameserver = nil
      else
        nameserver.delete("")
        nameserver.delete("0.0.0.0")
        nameserver.uniq!
      end
      [ search, nameserver ]
    end

getv = Win32API.new('kernel32.dll', 'GetVersionExA', 'P', 'L')
info = [ 148, 0, 0, 0, 0 ].pack('V5') + "\0" * 128
getv.call(info)
if info.unpack('V5')[4] == 2  # VER_PLATFORM_WIN32_NT
#====================================================================
# Windows NT
#====================================================================
  module_eval <<-'__EOS__', __FILE__, __LINE__+1
    TCPIP_NT = 'SYSTEM\CurrentControlSet\Services\Tcpip\Parameters'
    
    class << self
      private
      def get_hosts_dir
        Registry::HKEY_LOCAL_MACHINE.open(TCPIP_NT) do |reg|
          reg.read_s_expand('DataBasePath')
        end
      end
      
      def get_info
        search = nil
        nameserver = []
        Registry::HKEY_LOCAL_MACHINE.open(TCPIP_NT) do |reg|
          begin
            slist = reg.read_s('SearchList')
            search = slist.split(/,\s*/) unless slist.empty?
          rescue Registry::Error
          end
          
          if add_search = search.nil?
            search = []
            begin
              nvdom = reg.read_s('NV Domain')
              unless nvdom.empty?
                @search = [ nvdom ]
                if reg.read_i('UseDomainNameDevolution') != 0
                  if /^[\w\d]+\./ =~ nvdom
                    devo = $'
                  end
                end
              end
            rescue Registry::Error
            end
          end
          
          reg.open('Interfaces') do |reg|
            reg.each_key do |iface,|
              reg.open(iface) do |regif|
                begin
                  [ 'NameServer', 'DhcpNameServer' ].each do |key|
                    ns = regif.read_s(key)
                    unless ns.empty?
                      nameserver.concat(ns.split(/[,\s]\s*/))
                      break
                    end
                  end
                rescue Registry::Error
                end
                
                if add_search
                  begin
                    [ 'Domain', 'DhcpDomain' ].each do |key|
                      dom = regif.read_s(key)
                      unless dom.empty?
                        search.concat(dom.split(/,\s*/))
                        break
                      end
                    end
                  rescue Registry::Error
                  end
                end
              end
            end
          end
          search << devo if add_search and devo
        end
        [ search.uniq, nameserver.uniq ]
      end
    end
  __EOS__
else
#====================================================================
# Windows 9x
#====================================================================
  module_eval <<-'__EOS__', __FILE__, __LINE__+1
    TCPIP_9X = 'SYSTEM\CurrentControlSet\Services\VxD\MSTCP'
    DHCP_9X = 'SYSTEM\CurrentControlSet\Services\VxD\DHCP'
    WINDOWS = 'Software\Microsoft\Windows\CurrentVersion'
    
    class << self
   #   private
      
      def get_hosts_dir
        Registry::HKEY_LOCAL_MACHINE.open(WINDOWS) do |reg|
          reg.read_s_expand('SystemRoot')
        end
      end
      
      def get_info
        search = []
        nameserver = []
        begin
          Registry::HKEY_LOCAL_MACHINE.open(TCPIP_9X) do |reg|
            if reg.read_s("EnableDNS") == "1"
              domain = reg.read_s("Domain")
              ns = reg.read_s("NameServer")
              slist = reg.read_s("SearchList")
              search << domain unless domain.empty?
              search.concat(slist.split(/,\s*/))
              nameserver.concat(ns.split(/[,\s]\s*/))
            end
          end
        rescue Registry::Error
        end
        
        dhcpinfo = get_dhcpinfo
        search.concat(dhcpinfo[0])
        nameserver.concat(dhcpinfo[1])
        [ search, nameserver ]
      end
      
      def get_dhcpinfo
        macaddrs = {}
        ipaddrs = {}
        WsControl.get_iflist.each do |index, macaddr, *ipaddr|
          macaddrs[macaddr] = 1
          ipaddr.each { |ipaddr| ipaddrs[ipaddr] = 1 }
        end
        iflist = [ macaddrs, ipaddrs ]
        
        search = []
        nameserver = []
        version = -1
        Registry::HKEY_LOCAL_MACHINE.open(DHCP_9X) do |reg|
          begin
            version = API.unpackdw(reg.read_bin("Version"))
          rescue Registry::Error
          end
          
          reg.each_key do |key,|
            catch(:not_used) do
              reg.open(key) do |regdi|
                dom, ns = get_dhcpinfo_key(version, regdi, iflist)
                search << dom if dom
                nameserver.concat(ns) if ns
              end
            end
          end
        end
        [ search, nameserver ]
      end
      
      def get_dhcpinfo_95(reg)
        dhcp = reg.read_bin("DhcpInfo")
        [
          API.unpackdw(dhcp[4..7]),
          API.unpackdw(dhcp[8..11]),
          1,
          dhcp[45..50],
          reg.read_bin("OptionInfo"),
        ]
      end
      
      def get_dhcpinfo_98(reg)
        [
          API.unpackdw(reg.read_bin("DhcpIPAddress")),
          API.unpackdw(reg.read_bin("DhcpSubnetMask")),
          API.unpackdw(reg.read_bin("HardwareType")),
          reg.read_bin("HardwareAddress"),
          reg.read_bin("OptionInfo"),
        ]
      end
      
      def get_dhcpinfo_key(version, reg, iflist)
        info = case version
               when 1
                 get_dhcpinfo_95(reg)
               when 2
                 get_dhcpinfo_98(reg)
               else
                 begin
                   get_dhcpinfo_98(reg)
                 rescue Registry::Error
                   get_dhcpinfo_95(reg)
                 end
               end
        ipaddr, netmask, hwtype, macaddr, opt = info
        throw :not_used unless
          ipaddr and ipaddr != 0 and
          netmask and netmask != 0 and
          macaddr and macaddr.size == 6 and
          hwtype == 1 and
          iflist[0][macaddr] and iflist[1][ipaddr]
        
        size = opt.size
        idx = 0
        while idx <= size
          opttype = opt[idx]
          optsize = opt[idx + 1]
          optval  = opt[idx + 2, optsize]
          case opttype
          when 0xFF    ## term
            break
          when 0x0F    ## domain
            domain = optval.chomp("\0")
          when 0x06    ## dns
            nameserver = optval.scan(/..../).collect { |addr|
              "%d.%d.%d.%d" % addr.unpack('C4')
            }
          end
          idx += optsize + 2
        end
        [ domain, nameserver ]
      rescue Registry::Error
        throw :not_used
      end
    end
    
    module WsControl
      WsControl = Win32API.new('wsock32.dll', 'WsControl', 'LLPPPP', 'L')
      WSAGetLastError = Win32API.new('wsock32.dll', 'WSAGetLastError', 'V', 'L')
      
      MAX_TDI_ENTITIES = 512
      IPPROTO_TCP = 6
      WSCTL_TCP_QUERY_INFORMATION = 0
      INFO_CLASS_GENERIC = 0x100
      INFO_CLASS_PROTOCOL = 0x200
      INFO_TYPE_PROVIDER = 0x100
      ENTITY_LIST_ID = 0
      GENERIC_ENTITY = 0
      CL_NL_ENTITY = 0x301
      IF_ENTITY = 0x200
      ENTITY_TYPE_ID = 1
      CL_NL_IP = 0x303
      IF_MIB = 0x202
      IF_MIB_STATS_ID = 1
      IP_MIB_ADDRTABLE_ENTRY_ID = 0x102
      
      def self.wsctl(tei_entity, tei_instance,
                     toi_class, toi_type, toi_id,
                     buffsize)
        reqinfo = [
                  ## TDIEntityID
                    tei_entity, tei_instance,
                  ## TDIObjectID
                    toi_class, toi_type, toi_id,
                  ## TCP_REQUEST_INFORMATION_EX
                    ""
                  ].pack('VVVVVa16')
        reqsize = API.packdw(reqinfo.size)
        buff = "\0" * buffsize
        buffsize = API.packdw(buffsize)
        result = WsControl.call(
                   IPPROTO_TCP,
                   WSCTL_TCP_QUERY_INFORMATION,
                   reqinfo, reqsize,
                   buff, buffsize)
        if result != 0
          raise RuntimeError, "WsControl failed.(#{result})"
        end
        [ buff, API.unpackdw(buffsize) ]
      end
      private_class_method :wsctl
      
      def self.get_iflist
        # Get TDI Entity List
        entities, size =
          wsctl(GENERIC_ENTITY, 0,
                INFO_CLASS_GENERIC,
                INFO_TYPE_PROVIDER,
                ENTITY_LIST_ID,
                MAX_TDI_ENTITIES * 8)  # sizeof(TDIEntityID)
        entities = entities[0, size].
                     scan(/.{8}/).
                     collect { |e| e.unpack('VV') }

        # Get MIB Interface List
        iflist = []
        ifcount = 0
        entities.each do |entity, instance|
          if( (entity & IF_ENTITY)>0 )
            ifcount += 1
            etype, = wsctl(entity, instance,
                           INFO_CLASS_GENERIC,
                           INFO_TYPE_PROVIDER,
                           ENTITY_TYPE_ID,
                           4)
            if( (API.unpackdw(etype) & IF_MIB)==IF_MIB )
              ifentry, = wsctl(entity, instance,
                               INFO_CLASS_PROTOCOL,
                               INFO_TYPE_PROVIDER,
                               IF_MIB_STATS_ID,
                               21 * 4 + 8 + 130)  # sizeof(IFEntry)
              iflist << [
                API.unpackdw(ifentry[0,4]),
                ifentry[20, 6]
              ]
            end
          end
        end
        
        # Get IP Addresses
        entities.each do |entity, instance|
          if entity == CL_NL_ENTITY
            etype, = wsctl(entity, instance,
                           INFO_CLASS_GENERIC,
                           INFO_TYPE_PROVIDER,
                           ENTITY_TYPE_ID,
                           4)
            if API.unpackdw(etype) == CL_NL_IP
              ipentries, = wsctl(entity, instance,
                                 INFO_CLASS_PROTOCOL,
                                 INFO_TYPE_PROVIDER,
                                 IP_MIB_ADDRTABLE_ENTRY_ID,
                                 24 * (ifcount+1))  # sizeof(IPAddrEntry)
              ipentries.scan(/.{24}/) do |ipentry|
                ipaddr, index = ipentry.unpack('VV')
                if ifitem = iflist.assoc(index)
                  ifitem << ipaddr
                end
              end
            end
          end
        end
        iflist
      end
    end
  __EOS__
end
#====================================================================
  end
end


================================================
FILE: ext/Win32API/point.rb
================================================
require 'Win32API'

getCursorPos = Win32API.new("user32", "GetCursorPos", ['P'], 'V')

lpPoint = " " * 8 # store two LONGs
getCursorPos.Call(lpPoint)
x, y = lpPoint.unpack("LL") # get the actual values

print "x: ", x, "\n"
print "y: ", y, "\n"

ods = Win32API.new("kernel32", "OutputDebugString", ['P'], 'V')
ods.Call("Hello, World\n");

GetDesktopWindow = Win32API.new("user32", "GetDesktopWindow", [], 'L')
GetActiveWindow = Win32API.new("user32", "GetActiveWindow", [], 'L')
SendMessage = Win32API.new("user32", "SendMessage", ['L'] * 4, 'L')
SendMessage.Call GetDesktopWindow.Call, 274, 0xf140, 0


================================================
FILE: ext/bigdecimal/.cvsignore
================================================
Makefile
mkmf.log
*.def


================================================
FILE: ext/bigdecimal/README
================================================

  Ruby BIGDECIMAL(Variable Precision) extension library.
  Copyright (C) 1999  by Shigeo Kobayashi(shigeo@tinyforest.gr.jp)

BigDecimal is copyrighted free software by Shigeo Kobayashi .
You can redistribute it and/or modify it under either the terms of the GPL
(see COPYING file), or the conditions below:

  1. You may make and give away verbatim copies of the source form of the
     software without restriction, provided that you duplicate all of the
     original copyright notices and associated disclaimers.

  2. You may modify your copy of the software in any way, provided that
     you do at least ONE of the following:

       a) place your modifications in the Public Domain or otherwise
          make them Freely Available, such as by posting said
	  modifications to Usenet or an equivalent medium, or by allowing
	  the author to include your modifications in the software.

       b) use the modified software only within your corporation or
          organization.

       c) rename any non-standard executables so the names do not conflict
	  with standard executables, which must also be provided.

       d) make other distribution arrangements with the author.

  3. You may distribute the software in object code or executable
     form, provided that you do at least ONE of the following:

       a) distribute the executables and library files of the software,
	  together with instructions (in the manual page or equivalent)
	  on where to get the original distribution.

       b) accompany the distribution with the machine-readable source of
	  the software.

       c) give non-standard executables non-standard names, with
          instructions on where to get the original software distribution.

       d) make other distribution arrangements with the author.

  4. You may modify and include the part of the software into any other
     software (possibly commercial).

  5. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
     IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
     WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
     PURPOSE.

* The Author

Feel free to send comments and bug reports to the author.  Here is the 
author's latest mail address:

  shigeo@tinyforest.gr.jp

-------------------------------------------------------
created at: Thu Dec 22 1999


================================================
FILE: ext/bigdecimal/bigdecimal.c
================================================
/*
 *
 * Ruby BigDecimal(Variable decimal precision) extension library.
 *
 * Copyright(C) 2002 by Shigeo Kobayashi(shigeo@tinyforest.gr.jp)
 *
 * You may distribute under the terms of either the GNU General Public
 * License or the Artistic License, as specified in the README file
 * of this BigDecimal distribution.
 *
 *  NOTE: Change log in this source removed to reduce source code size. 
 *        See rev. 1.25 if needed.
 *
 */

#include "ruby.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "math.h"
#include "version.h"
 
/* #define ENABLE_NUMERIC_STRING */

VALUE rb_cBigDecimal;

#include "bigdecimal.h"

/* MACRO's to guard objects from GC by keeping them in stack */
#define ENTER(n) volatile VALUE vStack[n];int iStack=0
#define PUSH(x)  vStack[iStack++] = (unsigned long)(x);
#define SAVE(p)  PUSH(p->obj);
#define GUARD_OBJ(p,y) {p=y;SAVE(p);}

/*
 * ================== Ruby Interface part ==========================
 */
#define DoSomeOne(x,y) rb_num_coerce_bin(x,y)

#if 0
/* BigDecimal provides arbitrary-precision floating point decimal arithmetic.
 *
 * Copyright (C) 2002 by Shigeo Kobayashi .
 * You may distribute under the terms of either the GNU General Public
 * License or the Artistic License, as specified in the README file
 * of the BigDecimal distribution.
 *
 * Documented by mathew .
 *
 * = Introduction
 *
 * Ruby provides built-in support for arbitrary precision integer arithmetic.
 * For example:
 *
 * 42**13   ->   1265437718438866624512
 *
 * BigDecimal provides similar support for very large or very accurate floating
 * point numbers.
 *
 * Decimal arithmetic is also useful for general calculation, because it
 * provides the correct answers people expect--whereas normal binary floating
 * point arithmetic often introduces subtle errors because of the conversion
 * between base 10 and base 2. For example, try:
 *
 *   sum = 0
 *   for i in (1..10000)
 *     sum = sum + 0.0001
 *   end
 *   print sum
 *
 * and contrast with the output from:
 *
 *   require 'bigdecimal'
 *
 *   sum = BigDecimal.new("0")
 *   for i in (1..10000)
 *     sum = sum + BigDecimal.new("0.0001")
 *   end
 *   print sum
 *
 * Similarly:
 *
 * (BigDecimal.new("1.2") - BigDecimal("1.0")) == BigDecimal("0.2") -> true
 *
 * (1.2 - 1.0) == 0.2 -> false
 *
 * = Special features of accurate decimal arithmetic
 *
 * Because BigDecimal is more accurate than normal binary floating point
 * arithmetic, it requires some special values.
 *
 * == Infinity
 *
 * BigDecimal sometimes needs to return infinity, for example if you divide
 * a value by zero.
 *
 * BigDecimal.new("1.0") / BigDecimal.new("0.0")  -> infinity
 *
 * BigDecimal.new("-1.0") / BigDecimal.new("0.0")  -> -infinity
 *
 * You can represent infinite numbers to BigDecimal using the strings
 * 'Infinity', '+Infinity' and '-Infinity' (case-sensitive)
 *
 * == Not a Number
 *
 * When a computation results in an undefined value, the special value NaN
 * (for 'not a number') is returned.
 *
 * Example:
 *
 * BigDecimal.new("0.0") / BigDecimal.new("0.0") -> NaN
 *
 * You can also create undefined values.  NaN is never considered to be the
 * same as any other value, even NaN itself:
 *
 * n = BigDecimal.new('NaN')
 *
 * n == 0.0 -> nil
 *
 * n == n -> nil
 *
 * == Positive and negative zero
 *
 * If a computation results in a value which is too small to be represented as
 * a BigDecimal within the currently specified limits of precision, zero must
 * be returned.
 *
 * If the value which is too small to be represented is negative, a BigDecimal
 * value of negative zero is returned. If the value is positive, a value of
 * positive zero is returned.
 *
 * BigDecimal.new("1.0") / BigDecimal.new("-Infinity") -> -0.0
 *
 * BigDecimal.new("1.0") / BigDecimal.new("Infinity") -> 0.0
 *
 * (See BigDecimal.mode for how to specify limits of precision.)
 *
 * Note that -0.0 and 0.0 are considered to be the same for the purposes of
 * comparison.
 *
 * Note also that in mathematics, there is no particular concept of negative 
 * or positive zero; true mathematical zero has no sign.
 */
void
Init_BigDecimal()
{
    /* This is a #if-ed out function to fool Rdoc into documenting the class. */
    /* The real init function is Init_bigdecimal() further down. */
}
#endif

/*
 * Returns the BigDecimal version number.
 *
 * Ruby 1.8.0 returns 1.0.0.
 * Ruby 1.8.1 thru 1.8.3 return 1.0.1.
 */
static VALUE
BigDecimal_version(VALUE self)
{
    /*
     * 1.0.0: Ruby 1.8.0
     * 1.0.1: Ruby 1.8.1
    */
    return rb_str_new2("1.0.1");
}

/*
 *   VP routines used in BigDecimal part 
 */
static unsigned short VpGetException(void);
static void  VpSetException(unsigned short f);
static void  VpInternalRound(Real *c,int ixDigit,U_LONG vPrev,U_LONG v);
static int   VpLimitRound(Real *c,U_LONG ixDigit);

/*
 *  **** BigDecimal part ****
 */

static void
BigDecimal_delete(Real *pv)
{
    VpFree(pv);
}

static VALUE
ToValue(Real *p)
{
    if(VpIsNaN(p)) {
        VpException(VP_EXCEPTION_NaN,"Computation results to 'NaN'(Not a Number)",0);
    } else if(VpIsPosInf(p)) {
        VpException(VP_EXCEPTION_INFINITY,"Computation results to 'Infinity'",0);
    } else if(VpIsNegInf(p)) {
        VpException(VP_EXCEPTION_INFINITY,"Computation results to '-Infinity'",0);
    }
    return p->obj;
}

static Real *
GetVpValue(VALUE v, int must)
{
    Real *pv;
    VALUE bg;
    char szD[128];

    switch(TYPE(v))
    {
    case T_DATA:
        if(RDATA(v)->dfree ==(void *) BigDecimal_delete) {
            Data_Get_Struct(v, Real, pv);
            return pv;
        } else {
            goto SomeOneMayDoIt;
        }
        break;
    case T_FIXNUM:
        sprintf(szD, "%ld", FIX2LONG(v));
        return VpCreateRbObject(VpBaseFig() * 2 + 1, szD);

#ifdef ENABLE_NUMERIC_STRING
    case T_STRING:
        SafeStringValue(v);
        return VpCreateRbObject(strlen(RSTRING_PTR(v)) + VpBaseFig() + 1,
                                RSTRING_PTR(v));
#endif /* ENABLE_NUMERIC_STRING */

    case T_BIGNUM:
        bg = rb_big2str(v, 10);
        return VpCreateRbObject(strlen(RSTRING_PTR(bg)) + VpBaseFig() + 1,
                                RSTRING_PTR(bg));
    default:
        goto SomeOneMayDoIt;
    }

SomeOneMayDoIt:
    if(must) {
        rb_raise(rb_eTypeError, "%s can't be coerced into BigDecimal",
                    rb_special_const_p(v)?
                    RSTRING_PTR(rb_inspect(v)):
                    rb_obj_classname(v)
                );
    }
    return NULL; /* NULL means to coerce */
}

/* call-seq:
 * BigDecimal.double_fig
 *
 * The BigDecimal.double_fig class method returns the number of digits a
 * Float number is allowed to have. The result depends upon the CPU and OS
 * in use.
 */
static VALUE
BigDecimal_double_fig(VALUE self)
{
    return INT2FIX(VpDblFig());
}

/* call-seq:
 * precs
 *
 * Returns an Array of two Integer values.
 *
 * The first value is the current number of significant digits in the 
 * BigDecimal. The second value is the maximum number of significant digits
 * for the BigDecimal.
 */
static VALUE
BigDecimal_prec(VALUE self)
{
    ENTER(1);
    Real *p;
    VALUE obj;

    GUARD_OBJ(p,GetVpValue(self,1));
    obj = rb_assoc_new(INT2NUM(p->Prec*VpBaseFig()),
		       INT2NUM(p->MaxPrec*VpBaseFig()));
    return obj;
}

static VALUE
BigDecimal_hash(VALUE self)
{
    ENTER(1);
    Real *p;
    U_LONG hash,i;

    GUARD_OBJ(p,GetVpValue(self,1));
    hash = (U_LONG)p->sign;
    /* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
    if(hash==2) {
        for(i = 0; i < p->Prec;i++) {
            hash = 31 * hash + p->frac[i];
            hash ^= p->frac[i];
        }
        hash += p->exponent;
    }
    return INT2FIX(hash);
}

static VALUE
BigDecimal_dump(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real *vp;
    char *psz;
    VALUE dummy;
    volatile VALUE dump;

    rb_scan_args(argc, argv, "01", &dummy);
    GUARD_OBJ(vp,GetVpValue(self,1));
    dump = rb_str_new(0,VpNumOfChars(vp,"E")+50);
    psz = RSTRING_PTR(dump);
    sprintf(psz,"%lu:",VpMaxPrec(vp)*VpBaseFig());
    VpToString(vp, psz+strlen(psz), 0, 0);
    rb_str_resize(dump, strlen(psz));
    return dump;
}

/*
 * Internal method used to provide marshalling support. See the Marshal module.
 */
static VALUE
BigDecimal_load(VALUE self, VALUE str)
{
    ENTER(2);
    Real *pv;
    unsigned char *pch;
    unsigned char ch;
    unsigned long m=0;

    SafeStringValue(str);
    pch = (unsigned char *)RSTRING_PTR(str);
    /* First get max prec */
    while((*pch)!=(unsigned char)'\0' && (ch=*pch++)!=(unsigned char)':') {
        if(!ISDIGIT(ch)) {
            rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
        }
        m = m*10 + (unsigned long)(ch-'0');
    }
    if(m>VpBaseFig()) m -= VpBaseFig();
    GUARD_OBJ(pv,VpNewRbClass(m,(char *)pch,self));
    m /= VpBaseFig();
    if(m && pv->MaxPrec>m) pv->MaxPrec = m+1;
    return ToValue(pv);
}

 /* call-seq:
  * BigDecimal.mode(mode, value)
  *
  * Controls handling of arithmetic exceptions and rounding. If no value
  * is supplied, the current value is returned.
  *
  * Six values of the mode parameter control the handling of arithmetic
  * exceptions:
  *
  * BigDecimal::EXCEPTION_NaN
  * BigDecimal::EXCEPTION_INFINITY
  * BigDecimal::EXCEPTION_UNDERFLOW
  * BigDecimal::EXCEPTION_OVERFLOW
  * BigDecimal::EXCEPTION_ZERODIVIDE
  * BigDecimal::EXCEPTION_ALL
  *
  * For each mode parameter above, if the value set is false, computation 
  * continues after an arithmetic exception of the appropriate type. 
  * When computation continues, results are as follows:
  *
  * EXCEPTION_NaN:: NaN
  * EXCEPTION_INFINITY:: +infinity or -infinity
  * EXCEPTION_UNDERFLOW:: 0
  * EXCEPTION_OVERFLOW:: +infinity or -infinity
  * EXCEPTION_ZERODIVIDE:: +infinity or -infinity
  *
  * One value of the mode parameter controls the rounding of numeric values:
  * BigDecimal::ROUND_MODE. The values it can take are:
  *
  * ROUND_UP:: round away from zero
  * ROUND_DOWN:: round towards zero (truncate)
  * ROUND_HALF_UP:: round up if the appropriate digit >= 5, otherwise truncate (default)
  * ROUND_HALF_DOWN:: round up if the appropriate digit >= 6, otherwise truncate
  * ROUND_HALF_EVEN:: round towards the even neighbor (Banker's rounding)
  * ROUND_CEILING:: round towards positive infinity (ceil)
  * ROUND_FLOOR:: round towards negative infinity (floor)
  *
  */
static VALUE
BigDecimal_mode(int argc, VALUE *argv, VALUE self)
{
    VALUE which;
    VALUE val;
    unsigned long f,fo;
 
    if(rb_scan_args(argc,argv,"11",&which,&val)==1) val = Qnil;

    Check_Type(which, T_FIXNUM);
    f = (unsigned long)FIX2INT(which);

    if(f&VP_EXCEPTION_ALL) {
        /* Exception mode setting */
        fo = VpGetException();
        if(val==Qnil) return INT2FIX(fo);
        if(val!=Qfalse && val!=Qtrue) {
            rb_raise(rb_eTypeError, "second argument must be true or false");
            return Qnil; /* Not reached */
        }
        if(f&VP_EXCEPTION_INFINITY) {
            VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_INFINITY):
                           (fo&(~VP_EXCEPTION_INFINITY))));
        }
        if(f&VP_EXCEPTION_NaN) {
            VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_NaN):
                           (fo&(~VP_EXCEPTION_NaN))));
        }
        fo = VpGetException();
        return INT2FIX(fo);
    }
    if(VP_ROUND_MODE==f) {
        /* Rounding mode setting */
        fo = VpGetRoundMode();
        if(val==Qnil) return INT2FIX(fo);
        Check_Type(val, T_FIXNUM);
        if(!VpIsRoundMode(FIX2INT(val))) {
            rb_raise(rb_eTypeError, "invalid rounding mode");
            return Qnil;
        }
        fo = VpSetRoundMode((unsigned long)FIX2INT(val));
        return INT2FIX(fo);
    }
    rb_raise(rb_eTypeError, "first argument for BigDecimal#mode invalid");
    return Qnil;
}

static U_LONG
GetAddSubPrec(Real *a, Real *b)
{
    U_LONG mxs;
    U_LONG mx = a->Prec;
    S_INT d;

    if(!VpIsDef(a) || !VpIsDef(b)) return (-1L);
    if(mx < b->Prec) mx = b->Prec;
    if(a->exponent!=b->exponent) {
        mxs = mx;
        d = a->exponent - b->exponent;
        if(d<0) d = -d;
        mx = mx+(U_LONG)d;
        if(mxobj = (VALUE)Data_Wrap_Struct(klass, 0, BigDecimal_delete, pv);
    return pv;
}

VP_EXPORT Real *
VpCreateRbObject(U_LONG mx, const char *str)
{
    Real *pv = VpAlloc(mx,str);
    pv->obj = (VALUE)Data_Wrap_Struct(rb_cBigDecimal, 0, BigDecimal_delete, pv);
    return pv;
}

/* Returns True if the value is Not a Number */
static VALUE
BigDecimal_IsNaN(VALUE self)
{
    Real *p = GetVpValue(self,1);
    if(VpIsNaN(p))  return Qtrue;
    return Qfalse;
}

/* Returns True if the value is infinite */
static VALUE
BigDecimal_IsInfinite(VALUE self)
{
    Real *p = GetVpValue(self,1);
    if(VpIsPosInf(p)) return INT2FIX(1);
    if(VpIsNegInf(p)) return INT2FIX(-1);
    return Qnil;
}

/* Returns True if the value is finite (not NaN or infinite) */
static VALUE
BigDecimal_IsFinite(VALUE self)
{
    Real *p = GetVpValue(self,1);
    if(VpIsNaN(p)) return Qfalse;
    if(VpIsInf(p)) return Qfalse;
    return Qtrue;
}

/* Returns the value as an integer (Fixnum or Bignum).
 *
 * If the BigNumber is infinity or NaN, returns nil.
 */
static VALUE
BigDecimal_to_i(VALUE self)
{
    ENTER(5);
    int e,n,i,nf;
    U_LONG v,b,j;
    volatile VALUE str;
    char *psz,*pch;
    Real *p;

    GUARD_OBJ(p,GetVpValue(self,1));

    /* Infinity or NaN not converted. */
    if(VpIsNaN(p)) {
       VpException(VP_EXCEPTION_NaN,"Computation results to 'NaN'(Not a Number)",0);
       return Qnil;
    } else if(VpIsPosInf(p)) {
       VpException(VP_EXCEPTION_INFINITY,"Computation results to 'Infinity'",0);
       return Qnil;
    } else if(VpIsNegInf(p)) {
       VpException(VP_EXCEPTION_INFINITY,"Computation results to '-Infinity'",0);
       return Qnil;
    }

    e = VpExponent10(p);
    if(e<=0) return INT2FIX(0);
    nf = VpBaseFig();
    if(e<=nf) {
        e = VpGetSign(p)*p->frac[0];
        return INT2FIX(e);
    }
    str = rb_str_new(0, e+nf+2);
    psz = RSTRING_PTR(str);

    n = (e+nf-1)/nf;
    pch = psz;
    if(VpGetSign(p)<0) *pch++ = '-';
    for(i=0;i=(int)p->Prec) {
            while(b) {
                *pch++ = '0';
                b /= 10;
            }
            continue;
        }
        v = p->frac[i];
        while(b) {
            j = v/b;
            *pch++ = (char)(j + '0');
            v -= j*b;
            b /= 10;
        }
    }
    *pch++ = 0;
    return rb_cstr2inum(psz,10);
}

static VALUE
BigDecimal_induced_from(VALUE self, VALUE x)
{
    Real *p = GetVpValue(x,1);
    return p->obj;
}

/* Returns a new Float object having approximately the same value as the
 * BigDecimal number. Normal accuracy limits and built-in errors of binary
 * Float arithmetic apply.
 */
static VALUE
BigDecimal_to_f(VALUE self)
{
    ENTER(1);
    Real *p;
    double d;
    S_LONG e;
    char *buf;
    volatile VALUE str;

    GUARD_OBJ(p,GetVpValue(self,1));
    if(VpVtoD(&d, &e, p)!=1) return rb_float_new(d);
    if (e > DBL_MAX_10_EXP) goto erange;
    str = rb_str_new(0, VpNumOfChars(p,"E"));
    buf = RSTRING_PTR(str);
    VpToString(p, buf, 0, 0);
    errno = 0;
    d = strtod(buf, 0);
    if(errno == ERANGE) {
      erange:
       VpException(VP_EXCEPTION_OVERFLOW,"BigDecimal to Float conversion",0);
       if(d>0.0) d = VpGetDoublePosInf();
       else      d = VpGetDoubleNegInf();
    }
    return rb_float_new(d);
}

/* The coerce method provides support for Ruby type coercion. It is not
 * enabled by default.
 * 
 * This means that binary operations like + * / or - can often be performed 
 * on a BigDecimal and an object of another type, if the other object can
 * be coerced into a BigDecimal value.
 *
 * e.g.
 * a = BigDecimal.new("1.0")
 * b = a / 2.0  -> 0.5
 *
 * Note that coercing a String to a BigDecimal is not supported by default;
 * it requires a special compile-time option when building Ruby.
 */
static VALUE
BigDecimal_coerce(VALUE self, VALUE other)
{
    ENTER(2);
    VALUE obj;
    Real *b;
    if(TYPE(other) == T_FLOAT) {
       obj = rb_assoc_new(other, BigDecimal_to_f(self));
    } else {
       GUARD_OBJ(b,GetVpValue(other,1));
       obj = rb_assoc_new(b->obj, self);
    }
    return obj;
}

static VALUE
BigDecimal_uplus(VALUE self)
{
    return self;
}

 /* call-seq:
  * add(value, digits)
  *
  * Add the specified value. 
  *
  * e.g.
  *   c = a.add(b,n)
  *   c = a + b
  *
  * digits:: If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode.
  */
static VALUE
BigDecimal_add(VALUE self, VALUE r)
{
    ENTER(5);
    Real *c, *a, *b;
    U_LONG mx;
    GUARD_OBJ(a,GetVpValue(self,1));
    b = GetVpValue(r,0);
    if(!b) return DoSomeOne(self,r);
    SAVE(b);
    if(VpIsNaN(b)) return b->obj;
    if(VpIsNaN(a)) return a->obj;
    mx = GetAddSubPrec(a,b);
    if(mx==(-1L)) {
        GUARD_OBJ(c,VpCreateRbObject(VpBaseFig() + 1, "0"));
        VpAddSub(c, a, b, 1);
    } else {
        GUARD_OBJ(c,VpCreateRbObject(mx *(VpBaseFig() + 1), "0"));
        if(!mx) {
            VpSetInf(c,VpGetSign(a));
        } else {
            VpAddSub(c, a, b, 1);
        }
    }
    return ToValue(c);
}

 /* call-seq:
  * sub(value, digits)
  *
  * Subtract the specified value. 
  *
  * e.g.
  *   c = a.sub(b,n)
  *   c = a - b
  *
  * digits:: If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode.
  */
static VALUE
BigDecimal_sub(VALUE self, VALUE r)
{
    ENTER(5);
    Real *c, *a, *b;
    U_LONG mx;

    GUARD_OBJ(a,GetVpValue(self,1));
    b = GetVpValue(r,0);
    if(!b) return DoSomeOne(self,r);
    SAVE(b);

    if(VpIsNaN(b)) return b->obj;
    if(VpIsNaN(a)) return a->obj;

    mx = GetAddSubPrec(a,b);
    if(mx==(-1L)) {
        GUARD_OBJ(c,VpCreateRbObject(VpBaseFig() + 1, "0"));
        VpAddSub(c, a, b, -1);
    } else {
        GUARD_OBJ(c,VpCreateRbObject(mx *(VpBaseFig() + 1), "0"));
        if(!mx) {
            VpSetInf(c,VpGetSign(a));
        } else {
            VpAddSub(c, a, b, -1);
        }
    }
    return ToValue(c);
}

static VALUE
BigDecimalCmp(VALUE self, VALUE r,char op)
{
    ENTER(5);
    S_INT e;
    Real *a, *b;
    GUARD_OBJ(a,GetVpValue(self,1));
    b = GetVpValue(r,0);
    if(!b) {
	switch(op)
	{
	case '*': return rb_num_coerce_cmp(self,r); /* any op */
	case '=': return RTEST(rb_num_coerce_cmp(self,r)) ? Qtrue : Qfalse;
	default: return rb_num_coerce_relop(self,r);
	}
    }
    SAVE(b);
    e = VpComp(a, b);
    if(e==999) return (op == '*') ? Qnil : Qfalse;
    switch(op)
    {
    case '*': return   INT2FIX(e); /* any op */
    case '=': if(e==0) return Qtrue ; return Qfalse;
    case 'G': if(e>=0) return Qtrue ; return Qfalse;
    case '>': if(e> 0) return Qtrue ; return Qfalse;
    case 'L': if(e<=0) return Qtrue ; return Qfalse;
    case '<': if(e< 0) return Qtrue ; return Qfalse;
    }
    rb_bug("Undefined operation in BigDecimalCmp()");
}

/* Returns True if the value is zero. */
static VALUE
BigDecimal_zero(VALUE self)
{
    Real *a = GetVpValue(self,1);
    return VpIsZero(a) ? Qtrue : Qfalse;
}

/* Returns True if the value is non-zero. */
static VALUE
BigDecimal_nonzero(VALUE self)
{
    Real *a = GetVpValue(self,1);
    return VpIsZero(a) ? Qnil : self;
}

/* The comparison operator.
 * a <=> b is 0 if a == b, 1 if a > b, -1 if a < b.
 */
static VALUE
BigDecimal_comp(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '*');
}

/*
 * Tests for value equality; returns true if the values are equal.
 *
 * The == and === operators and the eql? method have the same implementation 
 * for BigDecimal.
 *
 * Values may be coerced to perform the comparison:
 *
 * BigDecimal.new('1.0') == 1.0  -> true
 */
static VALUE
BigDecimal_eq(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '=');
}

/* call-seq:
 * a < b
 *
 * Returns true if a is less than b. Values may be coerced to perform the
 * comparison (see ==, coerce).
 */
static VALUE
BigDecimal_lt(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '<');
}

/* call-seq:
 * a <= b
 *
 * Returns true if a is less than or equal to b. Values may be coerced to 
 * perform the comparison (see ==, coerce).
 */
static VALUE
BigDecimal_le(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, 'L');
}

/* call-seq:
 * a > b
 *
 * Returns true if a is greater than b.  Values may be coerced to 
 * perform the comparison (see ==, coerce).
 */
static VALUE
BigDecimal_gt(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '>');
}

/* call-seq:
 * a >= b
 *
 * Returns true if a is greater than or equal to b. Values may be coerced to 
 * perform the comparison (see ==, coerce)
 */
static VALUE
BigDecimal_ge(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, 'G');
}

static VALUE
BigDecimal_neg(VALUE self)
{
    ENTER(5);
    Real *c, *a;
    GUARD_OBJ(a,GetVpValue(self,1));
    GUARD_OBJ(c,VpCreateRbObject(a->Prec *(VpBaseFig() + 1), "0"));
    VpAsgn(c, a, -1);
    return ToValue(c);
}

 /* call-seq:
  * mult(value, digits)
  *
  * Multiply by the specified value. 
  *
  * e.g.
  *   c = a.mult(b,n)
  *   c = a * b
  *
  * digits:: If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode.
  */
static VALUE
BigDecimal_mult(VALUE self, VALUE r)
{
    ENTER(5);
    Real *c, *a, *b;
    U_LONG mx;

    GUARD_OBJ(a,GetVpValue(self,1));
    b = GetVpValue(r,0);
    if(!b) return DoSomeOne(self,r);
    SAVE(b);

    mx = a->Prec + b->Prec;
    GUARD_OBJ(c,VpCreateRbObject(mx *(VpBaseFig() + 1), "0"));
    VpMult(c, a, b);
    return ToValue(c);
}

static VALUE
BigDecimal_divide(Real **c, Real **res, Real **div, VALUE self, VALUE r)
/* For c = self.div(r): with round operation */
{
    ENTER(5);
    Real *a, *b;
    U_LONG mx;

    GUARD_OBJ(a,GetVpValue(self,1));
    b = GetVpValue(r,0);
    if(!b) return DoSomeOne(self,r);
    SAVE(b);
    *div = b;
    mx =(a->MaxPrec + b->MaxPrec + 1) * VpBaseFig();
    GUARD_OBJ((*c),VpCreateRbObject(mx, "#0"));
    GUARD_OBJ((*res),VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
    VpDivd(*c, *res, a, b);
    return (VALUE)0;
}

 /* call-seq:
  * div(value, digits)
  * quo(value)
  *
  * Divide by the specified value. 
  *
  * e.g.
  *   c = a.div(b,n)
  *
  * digits:: If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode.
  * 
  * If digits is 0, the result is the same as the / operator. If not, the
  * result is an integer BigDecimal, by analogy with Float#div.
  *
  * The alias quo is provided since div(value, 0) is the same as computing
  * the quotient; see divmod.
  */
static VALUE
BigDecimal_div(VALUE self, VALUE r)
/* For c = self/r: with round operation */
{
    ENTER(5);
    Real *c=NULL, *res=NULL, *div = NULL;
    r = BigDecimal_divide(&c, &res, &div, self, r);
    if(r!=(VALUE)0) return r; /* coerced by other */
    SAVE(c);SAVE(res);SAVE(div);
    /* a/b = c + r/b */
    /* c xxxxx
       r 00000yyyyy  ==> (y/b)*BASE >= HALF_BASE
     */
    /* Round */
    if(VpHasVal(div)) { /* frac[0] must be zero for NaN,INF,Zero */
       VpInternalRound(c,0,c->frac[c->Prec-1],(VpBaseVal()*res->frac[0])/div->frac[0]);
    }
    return ToValue(c);
}

/*
 * %: mod = a%b = a - (a.to_f/b).floor * b
 * div = (a.to_f/b).floor
 */
static VALUE
BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
{
    ENTER(8);
    Real *c=NULL, *d=NULL, *res=NULL;
    Real *a, *b;
    U_LONG mx;

    GUARD_OBJ(a,GetVpValue(self,1));
    b = GetVpValue(r,0);
    if(!b) return DoSomeOne(self,r);
    SAVE(b);

    if(VpIsNaN(a) || VpIsNaN(b)) goto NaN;
    if(VpIsInf(a) || VpIsInf(b)) goto NaN;
    if(VpIsZero(b))              goto NaN;
    if(VpIsZero(a)) {
       GUARD_OBJ(c,VpCreateRbObject(1, "0"));
       GUARD_OBJ(d,VpCreateRbObject(1, "0"));
       *div = d;
       *mod = c;
       return (VALUE)0;
    }

    mx = a->Prec;
    if(mxPrec) mx = b->Prec;
    mx =(mx + 1) * VpBaseFig();
    GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
    GUARD_OBJ(res,VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
    VpDivd(c, res, a, b);
    mx = c->Prec *(VpBaseFig() + 1);
    GUARD_OBJ(d,VpCreateRbObject(mx, "0"));
    VpActiveRound(d,c,VP_ROUND_DOWN,0);
    VpMult(res,d,b);
    VpAddSub(c,a,res,-1);
    if(!VpIsZero(c) && (VpGetSign(a)*VpGetSign(b)<0)) {
        VpAddSub(res,d,VpOne(),-1);
        VpAddSub(d  ,c,b,       1);
        *div = res;
        *mod = d;
    } else {
        *div = d;
        *mod = c;
    }
    return (VALUE)0;

NaN:
    GUARD_OBJ(c,VpCreateRbObject(1, "NaN"));
    GUARD_OBJ(d,VpCreateRbObject(1, "NaN"));
    *div = d;
    *mod = c;
    return (VALUE)0;
}

/* call-seq:
 * a % b
 * a.modulo(b)
 *
 * Returns the modulus from dividing by b. See divmod.
 */
static VALUE
BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
{
    ENTER(3);
    VALUE obj;
    Real *div=NULL, *mod=NULL;

    obj = BigDecimal_DoDivmod(self,r,&div,&mod);
    if(obj!=(VALUE)0) return obj;
    SAVE(div);SAVE(mod);
    return ToValue(mod);
}

static VALUE
BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
{
    ENTER(10);
    U_LONG mx;
    Real *a=NULL, *b=NULL, *c=NULL, *res=NULL, *d=NULL, *rr=NULL, *ff=NULL;
    Real *f=NULL;

    GUARD_OBJ(a,GetVpValue(self,1));
    b = GetVpValue(r,0);
    if(!b) return DoSomeOne(self,r);
    SAVE(b);

    mx  =(a->MaxPrec + b->MaxPrec) *VpBaseFig();
    GUARD_OBJ(c  ,VpCreateRbObject(mx, "0"));
    GUARD_OBJ(res,VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
    GUARD_OBJ(rr ,VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
    GUARD_OBJ(ff ,VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));

    VpDivd(c, res, a, b);

    mx = c->Prec *(VpBaseFig() + 1);

    GUARD_OBJ(d,VpCreateRbObject(mx, "0"));
    GUARD_OBJ(f,VpCreateRbObject(mx, "0"));

    VpActiveRound(d,c,VP_ROUND_DOWN,0); /* 0: round off */

    VpFrac(f, c);
    VpMult(rr,f,b);
    VpAddSub(ff,res,rr,1);

    *dv = d;
    *rv = ff;
    return (VALUE)0;
}

/* Returns the remainder from dividing by the value.
 *
 * If the values divided are of the same sign, the remainder is the same as
 * the modulus (see divmod).
 *
 * Otherwise, the remainder is the modulus minus the value divided by.
 */
static VALUE
BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
{
    VALUE  f;
    Real  *d,*rv=0;
    f = BigDecimal_divremain(self,r,&d,&rv);
    if(f!=(VALUE)0) return f;
    return ToValue(rv);
}

/* Divides by the specified value, and returns the quotient and modulus
 * as BigDecimal numbers. The quotient is rounded towards negative infinity.
 *
 * For example:
 *
 * require 'bigdecimal'
 *
 * a = BigDecimal.new("42")
 * b = BigDecimal.new("9")
 *
 * q,m = a.divmod(b)
 *
 * c = q * b + m
 *
 * a == c  -> true
 *
 * The quotient q is (a/b).floor, and the modulus is the amount that must be 
 * added to q * b to get a.
 */
static VALUE
BigDecimal_divmod(VALUE self, VALUE r)
{
    ENTER(5);
    VALUE obj;
    Real *div=NULL, *mod=NULL;

    obj = BigDecimal_DoDivmod(self,r,&div,&mod);
    if(obj!=(VALUE)0) return obj;
    SAVE(div);SAVE(mod);
    obj = rb_assoc_new(ToValue(div), ToValue(mod));
    return obj;
}

static VALUE
BigDecimal_div2(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    VALUE b,n;
    int na = rb_scan_args(argc,argv,"11",&b,&n);
    if(na==1) { /* div in Float sense */
       VALUE obj;
       Real *div=NULL;
       Real *mod;
       obj = BigDecimal_DoDivmod(self,b,&div,&mod);
       if(obj!=(VALUE)0) return obj;
       return ToValue(div);
    } else {    /* div in BigDecimal sense */
       U_LONG ix = (U_LONG)GetPositiveInt(n);
       if(ix==0) return BigDecimal_div(self,b);
       else {
          Real *res=NULL;
          Real *av=NULL, *bv=NULL, *cv=NULL;
          U_LONG mx = (ix+VpBaseFig()*2);
          U_LONG pl = VpSetPrecLimit(0);

          GUARD_OBJ(cv,VpCreateRbObject(mx,"0"));
          GUARD_OBJ(av,GetVpValue(self,1));
          GUARD_OBJ(bv,GetVpValue(b,1));
          mx = av->Prec + bv->Prec + 2;
          if(mx <= cv->MaxPrec) mx = cv->MaxPrec+1;
          GUARD_OBJ(res,VpCreateRbObject((mx * 2  + 2)*VpBaseFig(), "#0"));
          VpDivd(cv,res,av,bv);
          VpSetPrecLimit(pl);
          VpLeftRound(cv,VpGetRoundMode(),ix);
          return ToValue(cv);
       }
    }
}

static VALUE
BigDecimal_add2(VALUE self, VALUE b, VALUE n)
{
    ENTER(2);
    Real   *cv;
    U_LONG mx = (U_LONG)GetPositiveInt(n);
    if(mx==0) return BigDecimal_add(self,b);
    else {
       U_LONG pl = VpSetPrecLimit(0);
       VALUE   c = BigDecimal_add(self,b);
       VpSetPrecLimit(pl);
       GUARD_OBJ(cv,GetVpValue(c,1));
       VpLeftRound(cv,VpGetRoundMode(),mx);
       return ToValue(cv);
    }
}

static VALUE
BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
{
    ENTER(2);
    Real *cv;
    U_LONG mx = (U_LONG)GetPositiveInt(n);
    if(mx==0) return BigDecimal_sub(self,b);
    else {
       U_LONG pl = VpSetPrecLimit(0);
       VALUE   c = BigDecimal_sub(self,b);
       VpSetPrecLimit(pl);
       GUARD_OBJ(cv,GetVpValue(c,1));
       VpLeftRound(cv,VpGetRoundMode(),mx);
       return ToValue(cv);
    }
}

static VALUE
BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
{
    ENTER(2);
    Real *cv;
    U_LONG mx = (U_LONG)GetPositiveInt(n);
    if(mx==0) return BigDecimal_mult(self,b);
    else {
       U_LONG pl = VpSetPrecLimit(0);
       VALUE   c = BigDecimal_mult(self,b);
       VpSetPrecLimit(pl);
       GUARD_OBJ(cv,GetVpValue(c,1));
       VpLeftRound(cv,VpGetRoundMode(),mx);
       return ToValue(cv);
    }
}

/* Returns the absolute value.
 *
 * BigDecimal('5').abs -> 5
 *
 * BigDecimal('-3').abs -> 3
 */
static VALUE
BigDecimal_abs(VALUE self)
{
    ENTER(5);
    Real *c, *a;
    U_LONG mx;

    GUARD_OBJ(a,GetVpValue(self,1));
    mx = a->Prec *(VpBaseFig() + 1);
    GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
    VpAsgn(c, a, 1);
    VpChangeSign(c,(S_INT)1);
    return ToValue(c);
}

/* call-seq:
 * sqrt(n)
 *
 * Returns the square root of the value.
 *
 * If n is specified, returns at least that many significant digits.
 */
static VALUE
BigDecimal_sqrt(VALUE self, VALUE nFig)
{
    ENTER(5);
    Real *c, *a;
    S_INT mx, n;

    GUARD_OBJ(a,GetVpValue(self,1));
    mx = a->Prec *(VpBaseFig() + 1);

    n = GetPositiveInt(nFig) + VpDblFig() + 1;
    if(mx <= n) mx = n;
    GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
    VpSqrt(c, a);
    return ToValue(c);
}

/* Return the integer part of the number.
 */
static VALUE
BigDecimal_fix(VALUE self)
{
    ENTER(5);
    Real *c, *a;
    U_LONG mx;

    GUARD_OBJ(a,GetVpValue(self,1));
    mx = a->Prec *(VpBaseFig() + 1);
    GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
    VpActiveRound(c,a,VP_ROUND_DOWN,0); /* 0: round off */
    return ToValue(c);
}

/* call-seq:
 * round(n,mode)
 *
 * Round to the nearest 1 (by default), returning the result as a BigDecimal.
 *
 * BigDecimal('3.14159').round -> 3
 *
 * BigDecimal('8.7').round -> 9
 *
 * If n is specified and positive, the fractional part of the result has no
 * more than that many digits. 
 *
 * If n is specified and negative, at least that many digits to the left of the
 * decimal point will be 0 in the result.
 *
 * BigDecimal('3.14159').round(3) -> 3.142
 *
 * BigDecimal('13345.234').round(-2) -> 13300.0
 *
 * The value of the optional mode argument can be used to determine how 
 * rounding is performed; see BigDecimal.mode.
 */
static VALUE
BigDecimal_round(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real   *c, *a;
    int    iLoc = 0;
    U_LONG mx;
    VALUE  vLoc;
    VALUE  vRound;
    U_LONG pl;

    int    sw = VpGetRoundMode();

    int na = rb_scan_args(argc,argv,"02",&vLoc,&vRound);
    switch(na) {
    case 0:
        iLoc = 0;
        break;
    case 1:
        Check_Type(vLoc, T_FIXNUM);
        iLoc = FIX2INT(vLoc);
        break;
    case 2:
        Check_Type(vLoc, T_FIXNUM);
        iLoc = FIX2INT(vLoc);
        Check_Type(vRound, T_FIXNUM);
        sw   = FIX2INT(vRound);
        if(!VpIsRoundMode(sw)) {
            rb_raise(rb_eTypeError, "invalid rounding mode");
            return Qnil;
        }
        break;
    }

    pl = VpSetPrecLimit(0);
    GUARD_OBJ(a,GetVpValue(self,1));
    mx = a->Prec *(VpBaseFig() + 1);
    GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
    VpSetPrecLimit(pl);
    VpActiveRound(c,a,sw,iLoc);
    return ToValue(c);
}

/* call-seq:
 * truncate(n)
 *
 * Truncate to the nearest 1, returning the result as a BigDecimal.
 *
 * BigDecimal('3.14159').truncate -> 3
 *
 * BigDecimal('8.7').truncate -> 8
 *
 * If n is specified and positive, the fractional part of the result has no
 * more than that many digits. 
 *
 * If n is specified and negative, at least that many digits to the left of the
 * decimal point will be 0 in the result.
 *
 * BigDecimal('3.14159').truncate(3) -> 3.141
 *
 * BigDecimal('13345.234').truncate(-2) -> 13300.0
 */
static VALUE
BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real *c, *a;
    int iLoc;
    U_LONG mx;
    VALUE vLoc;
    U_LONG pl = VpSetPrecLimit(0);

    if(rb_scan_args(argc,argv,"01",&vLoc)==0) {
        iLoc = 0;
    } else {
        Check_Type(vLoc, T_FIXNUM);
        iLoc = FIX2INT(vLoc);
    }

    GUARD_OBJ(a,GetVpValue(self,1));
    mx = a->Prec *(VpBaseFig() + 1);
    GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
    VpSetPrecLimit(pl);
    VpActiveRound(c,a,VP_ROUND_DOWN,iLoc); /* 0: truncate */
    return ToValue(c);
}

/* Return the fractional part of the number.
 */
static VALUE
BigDecimal_frac(VALUE self)
{
    ENTER(5);
    Real *c, *a;
    U_LONG mx;

    GUARD_OBJ(a,GetVpValue(self,1));
    mx = a->Prec *(VpBaseFig() + 1);
    GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
    VpFrac(c, a);
    return ToValue(c);
}

/* call-seq:
 * floor(n)
 *
 * Return the largest integer less than or equal to the value, as a BigDecimal.
 *
 * BigDecimal('3.14159').floor -> 3
 *
 * BigDecimal('-9.1').floor -> -10
 *
 * If n is specified and positive, the fractional part of the result has no
 * more than that many digits.  
 *
 * If n is specified and negative, at least that
 * many digits to the left of the decimal point will be 0 in the result.
 *
 * BigDecimal('3.14159').floor(3) -> 3.141
 *
 * BigDecimal('13345.234').floor(-2) -> 13300.0
 */
static VALUE
BigDecimal_floor(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real *c, *a;
    U_LONG mx;
    int iLoc;
    VALUE vLoc;
    U_LONG pl = VpSetPrecLimit(0);

    if(rb_scan_args(argc,argv,"01",&vLoc)==0) {
        iLoc = 0;
    } else {
        Check_Type(vLoc, T_FIXNUM);
        iLoc = FIX2INT(vLoc);
    }

    GUARD_OBJ(a,GetVpValue(self,1));
    mx = a->Prec *(VpBaseFig() + 1);
    GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
    VpSetPrecLimit(pl);
    VpActiveRound(c,a,VP_ROUND_FLOOR,iLoc);
    return ToValue(c);
}

/* call-seq:
 * ceil(n)
 *
 * Return the smallest integer greater than or equal to the value, as a BigDecimal.
 *
 * BigDecimal('3.14159').ceil -> 4
 *
 * BigDecimal('-9.1').ceil -> -9
 *
 * If n is specified and positive, the fractional part of the result has no
 * more than that many digits.  
 *
 * If n is specified and negative, at least that
 * many digits to the left of the decimal point will be 0 in the result.
 *
 * BigDecimal('3.14159').ceil(3) -> 3.142
 *
 * BigDecimal('13345.234').ceil(-2) -> 13400.0
 */
static VALUE
BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real *c, *a;
    U_LONG mx;
    int iLoc;
    VALUE vLoc;
    U_LONG pl = VpSetPrecLimit(0);

    if(rb_scan_args(argc,argv,"01",&vLoc)==0) {
        iLoc = 0;
    } else {
        Check_Type(vLoc, T_FIXNUM);
        iLoc = FIX2INT(vLoc);
    }

    GUARD_OBJ(a,GetVpValue(self,1));
    mx = a->Prec *(VpBaseFig() + 1);
    GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
    VpSetPrecLimit(pl);
    VpActiveRound(c,a,VP_ROUND_CEIL,iLoc);
    return ToValue(c);
}

/* call-seq:
 * to_s(s)
 *
 * Converts the value to a string.
 *
 * The default format looks like  0.xxxxEnn.
 *
 * The optional parameter s consists of either an integer; or an optional '+'
 * or ' ', followed by an optional number, followed by an optional 'E' or 'F'.
 *
 * If there is a '+' at the start of s, positive values are returned with
 * a leading '+'.
 *
 * A space at the start of s returns positive values with a leading space.
 *
 * If s contains a number, a space is inserted after each group of that many 
 * fractional digits.
 *
 * If s ends with an 'E', engineering notation (0.xxxxEnn) is used.
 *
 * If s ends with an 'F', conventional floating point notation is used.
 *
 * Examples:
 *
 * BigDecimal.new('-123.45678901234567890').to_s('5F') -> '-123.45678 90123 45678 9'
 *
 * BigDecimal.new('123.45678901234567890').to_s('+8F') -> '+123.45678901 23456789'
 *
 * BigDecimal.new('123.45678901234567890').to_s(' F') -> ' 123.4567890123456789'
 */
static VALUE
BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    int   fmt=0;   /* 0:E format */
    int   fPlus=0; /* =0:default,=1: set ' ' before digits ,set '+' before digits. */
    Real  *vp;
    volatile VALUE str;
    char  *psz;
    char   ch;
    U_LONG nc;
    S_INT  mc = 0;
    VALUE  f;

    GUARD_OBJ(vp,GetVpValue(self,1));
    
    if(rb_scan_args(argc,argv,"01",&f)==1) {
        if(TYPE(f)==T_STRING) {
            SafeStringValue(f);
            psz = RSTRING_PTR(f);
            if(*psz==' ') {
                fPlus = 1; psz++;
            } else if(*psz=='+') {
                fPlus = 2; psz++;
            }
            while((ch=*psz++)!=0) {
                if(ISSPACE(ch)) continue;
                if(!ISDIGIT(ch)) {
                    if(ch=='F' || ch=='f') fmt = 1; /* F format */
                    break;
                }
                mc = mc * 10 + ch - '0';
            }
        } else {
            mc  = GetPositiveInt(f);
        }
    }
    if(fmt) {
        nc = VpNumOfChars(vp,"F");
    } else {
        nc = VpNumOfChars(vp,"E");
    }
    if(mc>0) nc += (nc + mc - 1) / mc + 1;

    str = rb_str_new(0, nc);
    psz = RSTRING_PTR(str);

    if(fmt) {
        VpToFString(vp, psz, mc, fPlus);
    } else {
        VpToString (vp, psz, mc, fPlus);
    }
    rb_str_resize(str, strlen(psz));
    return str;
}

/* Splits a BigDecimal number into four parts, returned as an array of values.
 *
 * The first value represents the sign of the BigDecimal, and is -1 or 1, or 0
 * if the BigDecimal is Not a Number.
 *
 * The second value is a string representing the significant digits of the
 * BigDecimal, with no leading zeros.
 *
 * The third value is the base used for arithmetic (currently always 10) as an
 * Integer.
 *
 * The fourth value is an Integer exponent.
 *
 * If the BigDecimal can be represented as 0.xxxxxx*10**n, then xxxxxx is the 
 * string of significant digits with no leading zeros, and n is the exponent.
 *
 * From these values, you can translate a BigDecimal to a float as follows:
 *
 *   sign, significant_digits, base, exponent = a.split
 *   f = sign * "0.#{significant_digits}".to_f * (base ** exponent)
 *
 * (Note that the to_f method is provided as a more convenient way to translate 
 * a BigDecimal to a Float.)
 */
static VALUE
BigDecimal_split(VALUE self)
{
    ENTER(5);
    Real *vp;
    VALUE obj,str;
    S_LONG e;
    S_LONG s;
    char *psz1;

    GUARD_OBJ(vp,GetVpValue(self,1));
    str = rb_str_new(0, VpNumOfChars(vp,"E"));
    psz1 = RSTRING_PTR(str);
    VpSzMantissa(vp,psz1);
    s = 1;
    if(psz1[0]=='-') {
	int len = strlen(psz1+1);

	memmove(psz1, psz1+1, len);
	psz1[len] = '\0';
        s = -1;
    }
    if(psz1[0]=='N') s=0; /* NaN */
    e = VpExponent10(vp);
    obj  = rb_ary_new2(4);
    rb_ary_push(obj, INT2FIX(s));
    rb_ary_push(obj, str);
    rb_str_resize(str, strlen(psz1));
    rb_ary_push(obj, INT2FIX(10));
    rb_ary_push(obj, INT2NUM(e));
    return obj;
}

/* Returns the exponent of the BigDecimal number, as an Integer.
 *
 * If the number can be represented as 0.xxxxxx*10**n where xxxxxx is a string
 * of digits with no leading zeros, then n is the exponent.
 */
static VALUE
BigDecimal_exponent(VALUE self)
{
    S_LONG e = VpExponent10(GetVpValue(self,1));
    return INT2NUM(e);
}

/* Returns debugging information about the value as a string of comma-separated
 * values in angle brackets with a leading #:
 *
 * BigDecimal.new("1234.5678").inspect ->
 * "#"
 *
 * The first part is the address, the second is the value as a string, and
 * the final part ss(mm) is the current number of significant digits and the
 * maximum number of significant digits, respectively.
 */
static VALUE
BigDecimal_inspect(VALUE self)
{
    ENTER(5);
    Real *vp;
    volatile VALUE obj;
    unsigned int nc;
    char *psz, *tmp;

    GUARD_OBJ(vp,GetVpValue(self,1));
    nc = VpNumOfChars(vp,"E");
    nc +=(nc + 9) / 10;

    obj = rb_str_new(0, nc+256);
    psz = RSTRING_PTR(obj);
    sprintf(psz,"#",VpPrec(vp)*VpBaseFig(),VpMaxPrec(vp)*VpBaseFig());
    rb_str_resize(obj, strlen(psz));
    return obj;
}

/* call-seq:
 * power(n)
 *
 * Returns the value raised to the power of n. Note that n must be an Integer.
 *
 * Also available as the operator **
 */
static VALUE
BigDecimal_power(VALUE self, VALUE p)
{
    ENTER(5);
    Real *x, *y;
    S_LONG mp, ma, n;

    Check_Type(p, T_FIXNUM);
    n = FIX2INT(p);
    ma = n;
    if(ma < 0)  ma = -ma;
    if(ma == 0) ma = 1;

    GUARD_OBJ(x,GetVpValue(self,1));
    if(VpIsDef(x)) {
        mp = x->Prec *(VpBaseFig() + 1);
        GUARD_OBJ(y,VpCreateRbObject(mp *(ma + 1), "0"));
    } else {
        GUARD_OBJ(y,VpCreateRbObject(1, "0"));
    }
    VpPower(y, x, n);
    return ToValue(y);
}

static VALUE
BigDecimal_global_new(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real *pv;
    S_LONG mf;
    VALUE  nFig;
    VALUE  iniValue;

    if(rb_scan_args(argc,argv,"11",&iniValue,&nFig)==1) {
        mf = 0;
    } else {
        mf = GetPositiveInt(nFig);
    }
    SafeStringValue(iniValue);
    GUARD_OBJ(pv,VpCreateRbObject(mf, RSTRING_PTR(iniValue)));
    return ToValue(pv);
}

 /* call-seq:
  * new(initial, digits)
  *
  * Create a new BigDecimal object.
  *
  * initial:: The initial value, as a String. Spaces are ignored, unrecognized characters terminate the value.
  *
  * digits:: The number of significant digits, as a Fixnum. If omitted or 0, the number of significant digits is determined from the initial value.
  *
  * The actual number of significant digits used in computation is usually
  * larger than the specified number.
  */
static VALUE
BigDecimal_new(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real *pv;
    S_LONG mf;
    VALUE  nFig;
    VALUE  iniValue;

    if(rb_scan_args(argc,argv,"11",&iniValue,&nFig)==1) {
        mf = 0;
    } else {
        mf = GetPositiveInt(nFig);
    }
    SafeStringValue(iniValue);
    GUARD_OBJ(pv,VpNewRbClass(mf, RSTRING_PTR(iniValue),self));
    return ToValue(pv);
}

 /* call-seq:
  * BigDecimal.limit(digits)
  *
  * Limit the number of significant digits in newly created BigDecimal 
  * numbers to the specified value. Rounding is performed as necessary, 
  * as specified by BigDecimal.mode.
  *
  * A limit of 0, the default, means no upper limit.
  *
  * The limit specified by this method takes priority over any limit 
  * specified to instance methods such as ceil, floor, truncate, or round.
  */
static VALUE
BigDecimal_limit(int argc, VALUE *argv, VALUE self)
{
    VALUE  nFig;
    VALUE  nCur = INT2NUM(VpGetPrecLimit());

    if(rb_scan_args(argc,argv,"01",&nFig)==1) {
        int nf;
        if(nFig==Qnil) return nCur;
        Check_Type(nFig, T_FIXNUM);
        nf = FIX2INT(nFig);
        if(nf<0) {
            rb_raise(rb_eArgError, "argument must be positive");
        }
        VpSetPrecLimit(nf);
    }
    return nCur;
}

/* Returns the sign of the value.
 *
 * Returns a positive value if > 0, a negative value if < 0, and a 
 * zero if == 0.
 *
 * The specific value returned indicates the type and sign of the BigDecimal, 
 * as follows:
 *
 * BigDecimal::SIGN_NaN:: value is Not a Number
 * BigDecimal::SIGN_POSITIVE_ZERO:: value is +0
 * BigDecimal::SIGN_NEGATIVE_ZERO:: value is -0
 * BigDecimal::SIGN_POSITIVE_INFINITE:: value is +infinity
 * BigDecimal::SIGN_NEGATIVE_INFINITE:: value is -infinity
 * BigDecimal::SIGN_POSITIVE_FINITE:: value is positive
 * BigDecimal::SIGN_NEGATIVE_FINITE:: value is negative
 */
static VALUE
BigDecimal_sign(VALUE self)
{ /* sign */
    int s = GetVpValue(self,1)->sign;
    return INT2FIX(s);
}

void
Init_bigdecimal(void)
{
    /* Initialize VP routines */
    VpInit((U_LONG)0);

    /* Class and method registration */
    rb_cBigDecimal = rb_define_class("BigDecimal",rb_cNumeric);

    /* Global function */
    rb_define_global_function("BigDecimal", BigDecimal_global_new, -1);

    /* Class methods */
    rb_define_singleton_method(rb_cBigDecimal, "new", BigDecimal_new, -1);
    rb_define_singleton_method(rb_cBigDecimal, "mode", BigDecimal_mode, -1);
    rb_define_singleton_method(rb_cBigDecimal, "limit", BigDecimal_limit, -1);
    rb_define_singleton_method(rb_cBigDecimal, "double_fig", BigDecimal_double_fig, 0);
    rb_define_singleton_method(rb_cBigDecimal, "induced_from",BigDecimal_induced_from, 1);
    rb_define_singleton_method(rb_cBigDecimal, "_load", BigDecimal_load, 1);
    rb_define_singleton_method(rb_cBigDecimal, "ver", BigDecimal_version, 0);

    /* Constants definition */

    /* 
     * Base value used in internal calculations.  On a 32 bit system, BASE 
     * is 10000, indicating that calculation is done in groups of 4 digits.  
     * (If it were larger, BASE**2 wouldn't fit in 32 bits, so you couldn't
     * guarantee that two groups could always be multiplied together without 
     * overflow.) 
     */
    rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((S_INT)VpBaseVal()));

    /* Exceptions */

    /*
     * 0xff: Determines whether overflow, underflow or zero divide result in 
     * an exception being thrown. See BigDecimal.mode.
     */
    rb_define_const(rb_cBigDecimal, "EXCEPTION_ALL",INT2FIX(VP_EXCEPTION_ALL));

    /* 
     * 0x02: Determines what happens when the result of a computation is not a 
     * number (NaN). See BigDecimal.mode. 
     */
    rb_define_const(rb_cBigDecimal, "EXCEPTION_NaN",INT2FIX(VP_EXCEPTION_NaN));

    /* 
     * 0x01: Determines what happens when the result of a computation is
     * infinity.  See BigDecimal.mode.
     */
    rb_define_const(rb_cBigDecimal, "EXCEPTION_INFINITY",INT2FIX(VP_EXCEPTION_INFINITY));

    /* 
     * 0x04: Determines what happens when the result of a computation is an
     * underflow (a result too small to be represented). See BigDecimal.mode.
     */
    rb_define_const(rb_cBigDecimal, "EXCEPTION_UNDERFLOW",INT2FIX(VP_EXCEPTION_UNDERFLOW));

    /* 
     * 0x01: Determines what happens when the result of a computation is an
     * underflow (a result too large to be represented). See BigDecimal.mode.
     */
    rb_define_const(rb_cBigDecimal, "EXCEPTION_OVERFLOW",INT2FIX(VP_EXCEPTION_OVERFLOW));

    /* 
     * 0x01: Determines what happens when a division by zero is performed.
     * See BigDecimal.mode.
     */
    rb_define_const(rb_cBigDecimal, "EXCEPTION_ZERODIVIDE",INT2FIX(VP_EXCEPTION_ZERODIVIDE));

    /* 
     * 0x100: Determines what happens when a result must be rounded in order to
     * fit in the appropriate number of significant digits. See
     * BigDecimal.mode.
     */
    rb_define_const(rb_cBigDecimal, "ROUND_MODE",INT2FIX(VP_ROUND_MODE));

    /* 1: Indicates that values should be rounded away from zero. See
     * BigDecimal.mode.
     */
    rb_define_const(rb_cBigDecimal, "ROUND_UP",INT2FIX(VP_ROUND_UP));

    /* 2: Indicates that values should be rounded towards zero. See
     * BigDecimal.mode.
     */
    rb_define_const(rb_cBigDecimal, "ROUND_DOWN",INT2FIX(VP_ROUND_DOWN));

    /* 3: Indicates that digits >= 5 should be rounded up, others rounded down.
     * See BigDecimal.mode. */
    rb_define_const(rb_cBigDecimal, "ROUND_HALF_UP",INT2FIX(VP_ROUND_HALF_UP));

    /* 4: Indicates that digits >= 6 should be rounded up, others rounded down.
     * See BigDecimal.mode.
     */
    rb_define_const(rb_cBigDecimal, "ROUND_HALF_DOWN",INT2FIX(VP_ROUND_HALF_DOWN));
    /* 5: Round towards +infinity. See BigDecimal.mode. */
    rb_define_const(rb_cBigDecimal, "ROUND_CEILING",INT2FIX(VP_ROUND_CEIL));

    /* 6: Round towards -infinity. See BigDecimal.mode. */
    rb_define_const(rb_cBigDecimal, "ROUND_FLOOR",INT2FIX(VP_ROUND_FLOOR));

    /* 7: Round towards the even neighbor. See BigDecimal.mode. */
    rb_define_const(rb_cBigDecimal, "ROUND_HALF_EVEN",INT2FIX(VP_ROUND_HALF_EVEN));

    /* 0: Indicates that a value is not a number. See BigDecimal.sign. */
    rb_define_const(rb_cBigDecimal, "SIGN_NaN",INT2FIX(VP_SIGN_NaN));

    /* 1: Indicates that a value is +0. See BigDecimal.sign. */
    rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_ZERO",INT2FIX(VP_SIGN_POSITIVE_ZERO));

    /* -1: Indicates that a value is -0. See BigDecimal.sign. */
    rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_ZERO",INT2FIX(VP_SIGN_NEGATIVE_ZERO));

    /* 2: Indicates that a value is positive and finite. See BigDecimal.sign. */
    rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_FINITE",INT2FIX(VP_SIGN_POSITIVE_FINITE));

    /* -2: Indicates that a value is negative and finite. See BigDecimal.sign. */
    rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_FINITE",INT2FIX(VP_SIGN_NEGATIVE_FINITE));

    /* 3: Indicates that a value is positive and infinite. See BigDecimal.sign. */
    rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_INFINITE",INT2FIX(VP_SIGN_POSITIVE_INFINITE));

    /* -3: Indicates that a value is negative and infinite. See BigDecimal.sign. */
    rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_INFINITE",INT2FIX(VP_SIGN_NEGATIVE_INFINITE));

    /* instance methods */
    rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);

    rb_define_method(rb_cBigDecimal, "add", BigDecimal_add2, 2);
    rb_define_method(rb_cBigDecimal, "sub", BigDecimal_sub2, 2);
    rb_define_method(rb_cBigDecimal, "mult", BigDecimal_mult2, 2);
    rb_define_method(rb_cBigDecimal, "div",BigDecimal_div2, -1);
    rb_define_method(rb_cBigDecimal, "hash", BigDecimal_hash, 0);
    rb_define_method(rb_cBigDecimal, "to_s", BigDecimal_to_s, -1);
    rb_define_method(rb_cBigDecimal, "to_i", BigDecimal_to_i, 0);
    rb_define_method(rb_cBigDecimal, "to_int", BigDecimal_to_i, 0);
    rb_define_method(rb_cBigDecimal, "split", BigDecimal_split, 0);
    rb_define_method(rb_cBigDecimal, "+", BigDecimal_add, 1);
    rb_define_method(rb_cBigDecimal, "-", BigDecimal_sub, 1);
    rb_define_method(rb_cBigDecimal, "+@", BigDecimal_uplus, 0);
    rb_define_method(rb_cBigDecimal, "-@", BigDecimal_neg, 0);
    rb_define_method(rb_cBigDecimal, "*", BigDecimal_mult, 1);
    rb_define_method(rb_cBigDecimal, "/", BigDecimal_div, 1);
    rb_define_method(rb_cBigDecimal, "quo", BigDecimal_div, 1);
    rb_define_method(rb_cBigDecimal, "%", BigDecimal_mod, 1);
    rb_define_method(rb_cBigDecimal, "modulo", BigDecimal_mod, 1);
    rb_define_method(rb_cBigDecimal, "remainder", BigDecimal_remainder, 1);
    rb_define_method(rb_cBigDecimal, "divmod", BigDecimal_divmod, 1);
    /* rb_define_method(rb_cBigDecimal, "dup", BigDecimal_dup, 0); */
    rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
    rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
    rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
    rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
    rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
    rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
    rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
    rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
    rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, 1);
    rb_define_method(rb_cBigDecimal, "**", BigDecimal_power, 1);
    rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
    rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
    rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
    rb_define_method(rb_cBigDecimal, "eql?", BigDecimal_eq, 1);
    rb_define_method(rb_cBigDecimal, "<", BigDecimal_lt, 1);
    rb_define_method(rb_cBigDecimal, "<=", BigDecimal_le, 1);
    rb_define_method(rb_cBigDecimal, ">", BigDecimal_gt, 1);
    rb_define_method(rb_cBigDecimal, ">=", BigDecimal_ge, 1);
    rb_define_method(rb_cBigDecimal, "zero?", BigDecimal_zero, 0);
    rb_define_method(rb_cBigDecimal, "nonzero?", BigDecimal_nonzero, 0);
    rb_define_method(rb_cBigDecimal, "coerce", BigDecimal_coerce, 1);
    rb_define_method(rb_cBigDecimal, "inspect", BigDecimal_inspect, 0);
    rb_define_method(rb_cBigDecimal, "exponent", BigDecimal_exponent, 0);
    rb_define_method(rb_cBigDecimal, "sign", BigDecimal_sign, 0);
    rb_define_method(rb_cBigDecimal, "nan?",      BigDecimal_IsNaN, 0);
    rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
    rb_define_method(rb_cBigDecimal, "finite?",   BigDecimal_IsFinite, 0);
    rb_define_method(rb_cBigDecimal, "truncate",  BigDecimal_truncate, -1);
    rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
}

/*
 *
 *  ============================================================================
 *
 *  vp_ routines begin from here.
 *
 *  ============================================================================
 *
 */
#ifdef _DEBUG
static int gfDebug = 1;         /* Debug switch */
static int gfCheckVal = 1;      /* Value checking flag in VpNmlz()  */
#endif /* _DEBUG */

static U_LONG gnPrecLimit = 0;  /* Global upper limit of the precision newly allocated */
static U_LONG gfRoundMode = VP_ROUND_HALF_UP; /* Mode for general rounding operation   */

#ifndef BASE_FIG
static U_LONG BASE_FIG = 4;     /* =log10(BASE)  */
static U_LONG BASE = 10000L;    /* Base value(value must be 10**BASE_FIG) */
                /* The value of BASE**2 + BASE must be represented */
                /* within one U_LONG. */
static U_LONG HALF_BASE = 5000L;/* =BASE/2  */
static U_LONG BASE1 = 1000L;    /* =BASE/10  */
#else
#ifndef BASE
#error BASE_FIG is defined but BASE is not
#endif
#define HALF_BASE (BASE/2)
#define BASE1 (BASE/10)
#endif
#ifndef DBLE_FIG
#define DBLE_FIG (DBL_DIG+1)    /* figure of double */
#endif

static Real *VpConstOne;    /* constant 1.0 */
static Real *VpPt5;        /* constant 0.5 */
#define maxnr 100UL    /* Maximum iterations for calcurating sqrt. */
                /* used in VpSqrt() */

/* ETC */
#define MemCmp(x,y,z) memcmp(x,y,z)
#define StrCmp(x,y)   strcmp(x,y)

static int VpIsDefOP(Real *c,Real *a,Real *b,int sw);
static int AddExponent(Real *a,S_INT n);
static U_LONG VpAddAbs(Real *a,Real *b,Real *c);
static U_LONG VpSubAbs(Real *a,Real *b,Real *c);
static U_LONG VpSetPTR(Real *a,Real *b,Real *c,U_LONG *a_pos,U_LONG *b_pos,U_LONG *c_pos,U_LONG *av,U_LONG *bv);
static int VpNmlz(Real *a);
static void VpFormatSt(char *psz,S_INT fFmt);
static int VpRdup(Real *m,U_LONG ind_m);

#ifdef _DEBUG
static int gnAlloc=0; /* Memory allocation counter */
#endif /* _DEBUG */

VP_EXPORT void *
VpMemAlloc(U_LONG mb)
{
    void *p = xmalloc((unsigned int)mb);
    if(!p) {
        VpException(VP_EXCEPTION_MEMORY,"failed to allocate memory",1);
    }
    memset(p,0,mb);
#ifdef _DEBUG
    gnAlloc++; /* Count allocation call */
#endif /* _DEBUG */
    return p;
}

VP_EXPORT void
VpFree(Real *pv)
{
    if(pv != NULL) {
        xfree(pv);
#ifdef _DEBUG
        gnAlloc--; /* Decrement allocation count */
        if(gnAlloc==0) {
            printf(" *************** All memories allocated freed ****************");
            getchar();
        }
        if(gnAlloc<0) {
            printf(" ??????????? Too many memory free calls(%d) ?????????????\n",gnAlloc);
            getchar();
        }
#endif /* _DEBUG */
    }
}

/*
 * EXCEPTION Handling.
 */
static unsigned short gfDoException = 0; /* Exception flag */

static unsigned short
VpGetException (void)
{
    return gfDoException;
}

static void
VpSetException(unsigned short f)
{
    gfDoException = f;
}

/* These 2 functions added at v1.1.7 */
VP_EXPORT U_LONG
VpGetPrecLimit(void)
{
    return gnPrecLimit;
}

VP_EXPORT U_LONG
VpSetPrecLimit(U_LONG n)
{
    U_LONG s = gnPrecLimit;
    gnPrecLimit = n;
    return s;
}

VP_EXPORT unsigned long
VpGetRoundMode(void)
{
    return gfRoundMode;
}

VP_EXPORT int
VpIsRoundMode(unsigned long n)
{
    if(n==VP_ROUND_UP      || n!=VP_ROUND_DOWN      ||
       n==VP_ROUND_HALF_UP || n!=VP_ROUND_HALF_DOWN ||
       n==VP_ROUND_CEIL    || n!=VP_ROUND_FLOOR     ||
       n==VP_ROUND_HALF_EVEN
      ) return 1;
    return 0;
}

VP_EXPORT unsigned long
VpSetRoundMode(unsigned long n)
{
    if(VpIsRoundMode(n)) gfRoundMode = n;
    return gfRoundMode;
}

/*
 *  0.0 & 1.0 generator
 *    These gZero_..... and gOne_..... can be any name
 *    referenced from nowhere except Zero() and One().
 *    gZero_..... and gOne_..... must have global scope
 *    (to let the compiler know they may be changed in outside
 *    (... but not actually..)).
 */
volatile const double gZero_ABCED9B1_CE73__00400511F31D = 0.0;
volatile const double gOne_ABCED9B4_CE73__00400511F31D  = 1.0;
static double
Zero(void)
{
    return gZero_ABCED9B1_CE73__00400511F31D;
}

static double
One(void)
{
    return gOne_ABCED9B4_CE73__00400511F31D;
}

VP_EXPORT U_LONG
VpBaseFig(void)
{
    return BASE_FIG;
}

VP_EXPORT U_LONG
VpDblFig(void)
{
    return DBLE_FIG;
}

VP_EXPORT U_LONG
VpBaseVal(void)
{
    return BASE;
}

/*
  ----------------------------------------------------------------
  Value of sign in Real structure is reserved for future use.
  short sign;
                    ==0 : NaN
                      1 : Positive zero
                     -1 : Negative zero
                      2 : Positive number
                     -2 : Negative number
                      3 : Positive infinite number
                     -3 : Negative infinite number
  ----------------------------------------------------------------
*/

VP_EXPORT double
VpGetDoubleNaN(void) /* Returns the value of NaN */
{
    static double fNaN = 0.0;
    if(fNaN==0.0) fNaN = Zero()/Zero();
    return fNaN;
}

VP_EXPORT double
VpGetDoublePosInf(void) /* Returns the value of +Infinity */
{
    static double fInf = 0.0;
    if(fInf==0.0) fInf = One()/Zero();
    return fInf;
}

VP_EXPORT double
VpGetDoubleNegInf(void) /* Returns the value of -Infinity */
{
    static double fInf = 0.0;
    if(fInf==0.0) fInf = -(One()/Zero());
    return fInf;
}

VP_EXPORT double
VpGetDoubleNegZero(void) /* Returns the value of -0 */
{
    static double nzero = 1000.0;
    if(nzero!=0.0) nzero = (One()/VpGetDoubleNegInf());
    return nzero;
}

VP_EXPORT int
VpIsNegDoubleZero(double v)
{
    double z = VpGetDoubleNegZero();
    return MemCmp(&v,&z,sizeof(v))==0;
}

VP_EXPORT int
VpException(unsigned short f, const char *str,int always)
{
    VALUE exc;
    int   fatal=0;

    if(f==VP_EXCEPTION_OP || f==VP_EXCEPTION_MEMORY) always = 1;

    if(always||(gfDoException&f)) {
        switch(f)
        {
        /*
        case VP_EXCEPTION_ZERODIVIDE:
        case VP_EXCEPTION_OVERFLOW:
        */
        case VP_EXCEPTION_INFINITY:
             exc = rb_eFloatDomainError;
             goto raise;
        case VP_EXCEPTION_NaN:
             exc = rb_eFloatDomainError;
             goto raise;
        case VP_EXCEPTION_UNDERFLOW:
             exc = rb_eFloatDomainError;
             goto raise;
        case VP_EXCEPTION_OP:
             exc = rb_eFloatDomainError;
             goto raise;
        case VP_EXCEPTION_MEMORY:
             fatal = 1;
             goto raise;
        default:
             fatal = 1;
             goto raise;
        }
    }
    return 0; /* 0 Means VpException() raised no exception */

raise:
    if(fatal) rb_fatal("%s", str);
    else   rb_raise(exc, "%s", str);
    return 0;
}

/* Throw exception or returns 0,when resulting c is Inf or NaN */
/*  sw=1:+ 2:- 3:* 4:/ */
static int
VpIsDefOP(Real *c,Real *a,Real *b,int sw)
{
    if(VpIsNaN(a) || VpIsNaN(b)) {
        /* at least a or b is NaN */
        VpSetNaN(c);
        goto NaN;
    }

    if(VpIsInf(a)) {
        if(VpIsInf(b)) {
            switch(sw)
            {
            case 1: /* + */
                if(VpGetSign(a)==VpGetSign(b)) {
                    VpSetInf(c,VpGetSign(a));
                    goto Inf;
                } else {
                    VpSetNaN(c);
                    goto NaN;
                }
            case 2: /* - */
                if(VpGetSign(a)!=VpGetSign(b)) {
                    VpSetInf(c,VpGetSign(a));
                    goto Inf;
                } else {
                    VpSetNaN(c);
                    goto NaN;
                }
                break;
            case 3: /* * */
                VpSetInf(c,VpGetSign(a)*VpGetSign(b));
                goto Inf;
                break;
            case 4: /* / */
                VpSetNaN(c);
                goto NaN;
            }
            VpSetNaN(c);
            goto NaN;
        }
        /* Inf op Finite */
        switch(sw)
        {
        case 1: /* + */
        case 2: /* - */
                VpSetInf(c,VpGetSign(a));
                break;
        case 3: /* * */
                if(VpIsZero(b)) {
                    VpSetNaN(c);
                    goto NaN;
                }
                VpSetInf(c,VpGetSign(a)*VpGetSign(b));
                break;
        case 4: /* / */
                VpSetInf(c,VpGetSign(a)*VpGetSign(b));
        }
        goto Inf;
    }

    if(VpIsInf(b)) {
        switch(sw)
        {
        case 1: /* + */
                VpSetInf(c,VpGetSign(b));
                break;
        case 2: /* - */
                VpSetInf(c,-VpGetSign(b));
                break;
        case 3: /* * */
                if(VpIsZero(a)) {
                    VpSetNaN(c);
                    goto NaN;
                }
                VpSetInf(c,VpGetSign(a)*VpGetSign(b));
                break;
        case 4: /* / */
                VpSetZero(c,VpGetSign(a)*VpGetSign(b));
        }
        goto Inf;
    }
    return 1; /* Results OK */

Inf:
    return VpException(VP_EXCEPTION_INFINITY,"Computation results to 'Infinity'",0);
NaN:
    return VpException(VP_EXCEPTION_NaN,"Computation results to 'NaN'",0);
}

/*
  ----------------------------------------------------------------
*/

/*
 *    returns number of chars needed to represent vp in specified format.
 */
VP_EXPORT U_LONG
VpNumOfChars(Real *vp,const char *pszFmt)
{
    S_INT  ex;
    U_LONG nc;

    if(vp == NULL)   return BASE_FIG*2+6;
    if(!VpIsDef(vp)) return 32; /* not sure,may be OK */

    switch(*pszFmt)
    {
    case 'F':
         nc = BASE_FIG*(vp->Prec + 1)+2;
         ex = vp->exponent;
         if(ex<0) {
             nc += BASE_FIG*(-ex);
         } else {
             if(ex > (S_INT)vp->Prec) {
                 nc += BASE_FIG*(ex - (S_INT)vp->Prec);
             }
         }
         break;
    case 'E':
    default:
         nc = BASE_FIG*(vp->Prec + 2)+6; /* 3: sign + exponent chars */
    }
    return nc;
}

/*
 * Initializer for Vp routines and constants used.
 * [Input]
 *   BaseVal: Base value(assigned to BASE) for Vp calculation.
 *   It must be the form BaseVal=10**n.(n=1,2,3,...)
 *   If Base <= 0L,then the BASE will be calcurated so
 *   that BASE is as large as possible satisfying the
 *   relation MaxVal <= BASE*(BASE+1). Where the value
 *   MaxVal is the largest value which can be represented
 *   by one U_LONG word(LONG) in the computer used.
 *
 * [Returns]
 * DBLE_FIG   ... OK
 */
VP_EXPORT U_LONG
VpInit(U_LONG BaseVal)
{
    /* Setup +/- Inf  NaN -0 */
    VpGetDoubleNaN();
    VpGetDoublePosInf();
    VpGetDoubleNegInf();
    VpGetDoubleNegZero();

#ifndef BASE_FIG
    if(BaseVal <= 0) {
        U_LONG w;
        /* Base <= 0, then determine Base by calcuration. */
        BASE = 1;
        while(
               (BASE > 0) &&
               ((w = BASE *(BASE + 1)) > BASE) &&((w / BASE) ==(BASE + 1))
            ) {
            BaseVal = BASE;
            BASE = BaseVal * 10L;
        }
    }
    /* Set Base Values */
    BASE = BaseVal;
    HALF_BASE = BASE / 2;
    BASE1 = BASE / 10;
    BASE_FIG = 0;
    while(BaseVal /= 10) ++BASE_FIG;
#endif

    /* Allocates Vp constants. */
    VpConstOne = VpAlloc((U_LONG)1, "1");
    VpPt5 = VpAlloc((U_LONG)1, ".5");

#ifdef _DEBUG
    gnAlloc = 0;
#endif /* _DEBUG */

#ifdef _DEBUG
    if(gfDebug) {
        printf("VpInit: BaseVal   = %lu\n", BaseVal);
        printf("  BASE   = %lu\n", BASE);
        printf("  HALF_BASE = %lu\n", HALF_BASE);
        printf("  BASE1  = %lu\n", BASE1);
        printf("  BASE_FIG  = %lu\n", BASE_FIG);
        printf("  DBLE_FIG  = %lu\n", DBLE_FIG);
    }
#endif /* _DEBUG */

    return DBLE_FIG;
}

VP_EXPORT Real *
VpOne(void)
{
    return VpConstOne;
}

/* If exponent overflows,then raise exception or returns 0 */
static int
AddExponent(Real *a,S_INT n)
{
    S_INT e = a->exponent;
    S_INT m = e+n;
    S_INT eb,mb;
    if(e>0) {
        if(n>0) {
            mb = m*BASE_FIG;
            eb = e*BASE_FIG;
            if(mbeb) goto underflow;
    }
    a->exponent = m;
    return 1;

/* Overflow/Underflow ==> Raise exception or returns 0 */
underflow:
    VpSetZero(a,VpGetSign(a));
    return VpException(VP_EXCEPTION_UNDERFLOW,"Exponent underflow",0);

overflow:
    VpSetInf(a,VpGetSign(a));
    return VpException(VP_EXCEPTION_OVERFLOW,"Exponent overflow",0);
}

/*
 * Allocates variable.
 * [Input]
 *   mx ... allocation unit, if zero then mx is determined by szVal.
 *    The mx is the number of effective digits can to be stored.
 *   szVal ... value assigned(char). If szVal==NULL,then zero is assumed.
 *            If szVal[0]=='#' then Max. Prec. will not be considered(1.1.7),
 *            full precision specified by szVal is allocated.
 *
 * [Returns]
 *   Pointer to the newly allocated variable, or
 *   NULL be returned if memory allocation is failed,or any error.
 */
VP_EXPORT Real *
VpAlloc(U_LONG mx, const char *szVal)
{
    U_LONG i, ni, ipn, ipf, nf, ipe, ne, nalloc;
    char v,*psz;
    int  sign=1;
    Real *vp = NULL;
    U_LONG mf = VpGetPrecLimit();
    volatile VALUE buf;

    mx = (mx + BASE_FIG - 1) / BASE_FIG + 1;    /* Determine allocation unit. */
    if(szVal) {
        while(ISSPACE(*szVal)) szVal++;
        if(*szVal!='#') {
             if(mf) {
                mf = (mf + BASE_FIG - 1) / BASE_FIG + 2; /* Needs 1 more for div */
                if(mx>mf) {
                    mx = mf;
                }
            }
        } else {
            ++szVal;
        }
    } else {
       /* necessary to be able to store */
       /* at least mx digits. */
       /* szVal==NULL ==> allocate zero value. */
       vp = (Real *) VpMemAlloc(sizeof(Real) + mx * sizeof(U_LONG));
       /* xmalloc() alway returns(or throw interruption) */
       vp->MaxPrec = mx;    /* set max precision */
       VpSetZero(vp,1);    /* initialize vp to zero. */
       return vp;
    }

    /* Skip all '_' after digit: 2006-6-30 */
    ni = 0;
    buf = rb_str_new(0,strlen(szVal)+1);
    psz = RSTRING_PTR(buf);
    i   = 0;
    ipn = 0;
    while((psz[i]=szVal[ipn])!=0) {
        if(ISDIGIT(psz[i])) ++ni;
        if(psz[i]=='_') {
            if(ni>0) {ipn++;continue;}
            psz[i]=0;
            break;
        }
        ++i; ++ipn;
    }
    /* Skip trailing spaces */
    while((--i)>0) {
        if(ISSPACE(psz[i])) psz[i] = 0;
        else                break;
    }
    szVal = psz;

    /* Check on Inf & NaN */
    if(StrCmp(szVal,SZ_PINF)==0 ||
       StrCmp(szVal,SZ_INF)==0 ) {
        vp = (Real *) VpMemAlloc(sizeof(Real) + sizeof(U_LONG));
        vp->MaxPrec = 1;    /* set max precision */
        VpSetPosInf(vp);
        return vp;
    }
    if(StrCmp(szVal,SZ_NINF)==0) {
        vp = (Real *) VpMemAlloc(sizeof(Real) + sizeof(U_LONG));
        vp->MaxPrec = 1;    /* set max precision */
        VpSetNegInf(vp);
        return vp;
    }
    if(StrCmp(szVal,SZ_NaN)==0) {
        vp = (Real *) VpMemAlloc(sizeof(Real) + sizeof(U_LONG));
        vp->MaxPrec = 1;    /* set max precision */
        VpSetNaN(vp);
        return vp;
    }

    /* check on number szVal[] */
    ipn = i = 0;
    if     (szVal[i] == '-') {sign=-1;++i;}
    else if(szVal[i] == '+')          ++i;
    /* Skip digits */
    ni = 0;            /* digits in mantissa */
    while((v = szVal[i]) != 0) {
        if(!ISDIGIT(v)) break;
        ++i;
        ++ni;
    }
    nf  = 0;
    ipf = 0;
    ipe = 0;
    ne  = 0;
    if(v) {
        /* other than digit nor \0 */
        if(szVal[i] == '.') {    /* xxx. */
            ++i;
            ipf = i;
            while((v = szVal[i]) != 0) {    /* get fraction part. */
                if(!ISDIGIT(v)) break;
                ++i;
                ++nf;
            }
        }
        ipe = 0;        /* Exponent */

        switch(szVal[i]) {
        case '\0': break;
        case 'e':
        case 'E':
        case 'd':
        case 'D':
            ++i;
            ipe = i;
            v = szVal[i];
            if((v == '-') ||(v == '+')) ++i;
            while((v=szVal[i])!=0) {
                if(!ISDIGIT(v)) break;
                ++i;
                ++ne;
            }
            break;
        default:
            break;
        }
    }
    nalloc =(ni + nf + BASE_FIG - 1) / BASE_FIG + 1;    /* set effective allocation  */
    /* units for szVal[]  */
    if(mx <= 0) mx = 1;
    nalloc = Max(nalloc, mx);
    mx = nalloc;
    vp =(Real *) VpMemAlloc(sizeof(Real) + mx * sizeof(U_LONG));
    /* xmalloc() alway returns(or throw interruption) */
    vp->MaxPrec = mx;        /* set max precision */
    VpSetZero(vp,sign);
    VpCtoV(vp, &(szVal[ipn]), ni, &(szVal[ipf]), nf, &(szVal[ipe]), ne);
    return vp;
}

/*
 * Assignment(c=a).
 * [Input]
 *   a   ... RHSV
 *   isw ... switch for assignment.
 *    c = a  when isw > 0
 *    c = -a when isw < 0
 *    if c->MaxPrec < a->Prec,then round operation
 *    will be performed.
 * [Output]
 *  c  ... LHSV
 */
VP_EXPORT int
VpAsgn(Real *c, Real *a, int isw)
{
    U_LONG n;
    if(VpIsNaN(a)) {
        VpSetNaN(c);
        return 0;
    }
    if(VpIsInf(a)) {
        VpSetInf(c,isw*VpGetSign(a));
        return 0;
    }

    /* check if the RHS is zero */
    if(!VpIsZero(a)) {
        c->exponent = a->exponent;    /* store  exponent */
        VpSetSign(c,(isw*VpGetSign(a)));    /* set sign */
        n =(a->Prec < c->MaxPrec) ?(a->Prec) :(c->MaxPrec);
        c->Prec = n;
        memcpy(c->frac, a->frac, n * sizeof(U_LONG));
        /* Needs round ? */
        if(isw!=10) {
            /* Not in ActiveRound */
            if(c->Prec < a->Prec) {
               VpInternalRound(c,n,(n>0)?a->frac[n-1]:0,a->frac[n]);
            } else {
               VpLimitRound(c,0);
            }
        }
    } else {
        /* The value of 'a' is zero.  */
        VpSetZero(c,isw*VpGetSign(a));
        return 1;
    }
    return c->Prec*BASE_FIG;
}

/*
 *   c = a + b  when operation =  1 or 2
 *  = a - b  when operation = -1 or -2.
 *   Returns number of significant digits of c
 */
VP_EXPORT int
VpAddSub(Real *c, Real *a, Real *b, int operation)
{
    S_INT sw, isw;
    Real *a_ptr, *b_ptr;
    U_LONG n, na, nb, i;
    U_LONG mrv;

#ifdef _DEBUG
    if(gfDebug) {
        VPrint(stdout, "VpAddSub(enter) a=% \n", a);
        VPrint(stdout, "     b=% \n", b);
        printf(" operation=%d\n", operation);
    }
#endif /* _DEBUG */

    if(!VpIsDefOP(c,a,b,(operation>0)?1:2)) return 0; /* No significant digits */

    /* check if a or b is zero  */
    if(VpIsZero(a)) {
        /* a is zero,then assign b to c */
        if(!VpIsZero(b)) {
            VpAsgn(c, b, operation);
        } else {
            /* Both a and b are zero. */
            if(VpGetSign(a)<0 && operation*VpGetSign(b)<0) {
                /* -0 -0 */
                VpSetZero(c,-1);
            } else {
                VpSetZero(c,1);
            }
            return 1; /* 0: 1 significant digits */
        }
        return c->Prec*BASE_FIG;
    }
    if(VpIsZero(b)) {
        /* b is zero,then assign a to c. */
        VpAsgn(c, a, 1);
        return c->Prec*BASE_FIG;
    }

    if(operation < 0) sw = -1;
    else              sw =  1;

    /* compare absolute value. As a result,|a_ptr|>=|b_ptr| */
    if(a->exponent > b->exponent) {
        a_ptr = a;
        b_ptr = b;
    }         /* |a|>|b| */
    else if(a->exponent < b->exponent) {
        a_ptr = b;
        b_ptr = a;
    }                /* |a|<|b| */
    else {
        /* Exponent part of a and b is the same,then compare fraction */
        /* part */
        na = a->Prec;
        nb = b->Prec;
        n = Min(na, nb);
        for(i=0;i < n; ++i) {
            if(a->frac[i] > b->frac[i]) {
                a_ptr = a;
                b_ptr = b;
                goto end_if;
            } else if(a->frac[i] < b->frac[i]) {
                a_ptr = b;
                b_ptr = a;
                goto end_if;
            }
        }
        if(na > nb) {
         a_ptr = a;
            b_ptr = b;
            goto end_if;
        } else if(na < nb) {
            a_ptr = b;
            b_ptr = a;
            goto end_if;
        }
        /* |a| == |b| */
        if(VpGetSign(a) + sw *VpGetSign(b) == 0) {
            VpSetZero(c,1);        /* abs(a)=abs(b) and operation = '-'  */
            return c->Prec*BASE_FIG;
        }
        a_ptr = a;
        b_ptr = b;
    }

end_if:
    isw = VpGetSign(a) + sw *VpGetSign(b);
    /*
     *  isw = 0 ...( 1)+(-1),( 1)-( 1),(-1)+(1),(-1)-(-1)
     *      = 2 ...( 1)+( 1),( 1)-(-1)
     *      =-2 ...(-1)+(-1),(-1)-( 1)
     *   If isw==0, then c =(Sign a_ptr)(|a_ptr|-|b_ptr|)
     *              else c =(Sign ofisw)(|a_ptr|+|b_ptr|)
    */
    if(isw) {            /* addition */
        VpSetSign(c,(S_INT)1);
        mrv = VpAddAbs(a_ptr, b_ptr, c);
        VpSetSign(c,isw / 2);
    } else {            /* subtraction */
        VpSetSign(c,(S_INT)1);
        mrv = VpSubAbs(a_ptr, b_ptr, c);
        if(a_ptr == a) {
            VpSetSign(c,VpGetSign(a));
        } else    {
            VpSetSign(c,VpGetSign(a_ptr) * sw);
        }
    }
    VpInternalRound(c,0,(c->Prec>0)?c->frac[c->Prec-1]:0,mrv);

#ifdef _DEBUG
    if(gfDebug) {
        VPrint(stdout, "VpAddSub(result) c=% \n", c);
        VPrint(stdout, "     a=% \n", a);
        VPrint(stdout, "     b=% \n", b);
        printf(" operation=%d\n", operation);
    }
#endif /* _DEBUG */
    return c->Prec*BASE_FIG;
}

/*
 * Addition of two variable precisional variables
 * a and b assuming abs(a)>abs(b).
 *   c = abs(a) + abs(b) ; where |a|>=|b|
 */
static U_LONG
VpAddAbs(Real *a, Real *b, Real *c)
{
    U_LONG word_shift;
    U_LONG carry;
    U_LONG ap;
    U_LONG bp;
    U_LONG cp;
    U_LONG a_pos;
    U_LONG b_pos;
    U_LONG c_pos;
    U_LONG av, bv, mrv;

#ifdef _DEBUG
    if(gfDebug) {
        VPrint(stdout, "VpAddAbs called: a = %\n", a);
        VPrint(stdout, "     b = %\n", b);
    }
#endif /* _DEBUG */

    word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
    a_pos = ap;
    b_pos = bp;
    c_pos = cp;
    if(word_shift==-1L) return 0; /* Overflow */
    if(b_pos == -1L) goto Assign_a;

    mrv = av + bv; /* Most right val. Used for round. */

    /* Just assign the last few digits of b to c because a has no  */
    /* corresponding digits to be added. */
    while(b_pos + word_shift > a_pos) {
        --c_pos;
        if(b_pos > 0) {
            c->frac[c_pos] = b->frac[--b_pos];
        } else {
            --word_shift;
            c->frac[c_pos] = 0;
        }
    }

    /* Just assign the last few digits of a to c because b has no */
    /* corresponding digits to be added. */
    bv = b_pos + word_shift;
    while(a_pos > bv) {
        c->frac[--c_pos] = a->frac[--a_pos];
    }
    carry = 0;    /* set first carry be zero */

    /* Now perform addition until every digits of b will be */
    /* exhausted. */
    while(b_pos > 0) {
        c->frac[--c_pos] = a->frac[--a_pos] + b->frac[--b_pos] + carry;
        if(c->frac[c_pos] >= BASE) {
            c->frac[c_pos] -= BASE;
            carry = 1;
        } else {
            carry = 0;
        }
    }

    /* Just assign the first few digits of a with considering */
    /* the carry obtained so far because b has been exhausted. */
    while(a_pos > 0) {
        c->frac[--c_pos] = a->frac[--a_pos] + carry;
        if(c->frac[c_pos] >= BASE) {
            c->frac[c_pos] -= BASE;
            carry = 1;
        } else {
            carry = 0;
        }
    }
    if(c_pos) c->frac[c_pos - 1] += carry;
    goto Exit;

Assign_a:
    VpAsgn(c, a, 1);
    mrv = 0;

Exit:

#ifdef _DEBUG
    if(gfDebug) {
        VPrint(stdout, "VpAddAbs exit: c=% \n", c);
    }
#endif /* _DEBUG */
    return mrv;
}

/*
 * c = abs(a) - abs(b)
 */
static U_LONG
VpSubAbs(Real *a, Real *b, Real *c)
{
    U_LONG word_shift;
    U_LONG mrv;
    U_LONG borrow;
    U_LONG ap;
    U_LONG bp;
    U_LONG cp;
    U_LONG a_pos;
    U_LONG b_pos;
    U_LONG c_pos;
    U_LONG av, bv;

#ifdef _DEBUG
    if(gfDebug) {
        VPrint(stdout, "VpSubAbs called: a = %\n", a);
        VPrint(stdout, "     b = %\n", b);
    }
#endif /* _DEBUG */

    word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
    a_pos = ap;
    b_pos = bp;
    c_pos = cp;
    if(word_shift==-1L) return 0; /* Overflow */
    if(b_pos == -1L) goto Assign_a;

    if(av >= bv) {
        mrv = av - bv;
        borrow = 0;
    } else {
        mrv    = 0;
        borrow = 1;
    }

    /* Just assign the values which are the BASE subtracted by   */
    /* each of the last few digits of the b because the a has no */
    /* corresponding digits to be subtracted. */
    if(b_pos + word_shift > a_pos) {
        while(b_pos + word_shift > a_pos) {
            --c_pos;
            if(b_pos > 0) {
                c->frac[c_pos] = BASE - b->frac[--b_pos] - borrow;
            } else {
                --word_shift;
                c->frac[c_pos] = BASE - borrow;
            }
            borrow = 1;
        }
    }
    /* Just assign the last few digits of a to c because b has no */
    /* corresponding digits to subtract. */

    bv = b_pos + word_shift;
    while(a_pos > bv) {
        c->frac[--c_pos] = a->frac[--a_pos];
    }

    /* Now perform subtraction until every digits of b will be */
    /* exhausted. */
    while(b_pos > 0) {
        --c_pos;
        if(a->frac[--a_pos] < b->frac[--b_pos] + borrow) {
            c->frac[c_pos] = BASE + a->frac[a_pos] - b->frac[b_pos] - borrow;
            borrow = 1;
        } else {
            c->frac[c_pos] = a->frac[a_pos] - b->frac[b_pos] - borrow;
            borrow = 0;
        }
    }

    /* Just assign the first few digits of a with considering */
    /* the borrow obtained so far because b has been exhausted. */
    while(a_pos > 0) {
        --c_pos;
        if(a->frac[--a_pos] < borrow) {
            c->frac[c_pos] = BASE + a->frac[a_pos] - borrow;
            borrow = 1;
        } else {
            c->frac[c_pos] = a->frac[a_pos] - borrow;
            borrow = 0;
        }
    }
    if(c_pos) c->frac[c_pos - 1] -= borrow;
    goto Exit;

Assign_a:
    VpAsgn(c, a, 1);
    mrv = 0;

Exit:
#ifdef _DEBUG
    if(gfDebug) {
        VPrint(stdout, "VpSubAbs exit: c=% \n", c);
    }
#endif /* _DEBUG */
    return mrv;
}

/*
 * Note: If(av+bv)>= HALF_BASE,then 1 will be added to the least significant
 *    digit of c(In case of addition).
 * ------------------------- figure of output -----------------------------------
 *      a =  xxxxxxxxxxx
 *      b =    xxxxxxxxxx
 *      c =xxxxxxxxxxxxxxx
 *      word_shift =  |   |
 *      right_word =  |    | (Total digits in RHSV)
 *      left_word  = |   |   (Total digits in LHSV)
 *      a_pos      =    |
 *      b_pos      =     |
 *      c_pos      =      |
 */
static U_LONG
VpSetPTR(Real *a, Real *b, Real *c, U_LONG *a_pos, U_LONG *b_pos, U_LONG *c_pos, U_LONG *av, U_LONG *bv)
{
    U_LONG left_word, right_word, word_shift;
    c->frac[0] = 0;
    *av = *bv = 0;
    word_shift =((a->exponent) -(b->exponent));
    left_word = b->Prec + word_shift;
    right_word = Max((a->Prec),left_word);
    left_word =(c->MaxPrec) - 1;    /* -1 ... prepare for round up */
    /*
     * check if 'round' is needed.
     */
    if(right_word > left_word) {    /* round ? */
        /*---------------------------------
         *  Actual size of a = xxxxxxAxx
         *  Actual size of b = xxxBxxxxx
         *  Max. size of   c = xxxxxx
         *  Round off        =   |-----|
         *  c_pos            =   |
         *  right_word       =   |
         *  a_pos            =    |
         */
        *c_pos = right_word = left_word + 1;    /* Set resulting precision */
        /* be equal to that of c */
        if((a->Prec) >=(c->MaxPrec)) {
            /*
             *   a =  xxxxxxAxxx
             *   c =  xxxxxx
             *   a_pos =    |
             */
            *a_pos = left_word;
            *av = a->frac[*a_pos];    /* av is 'A' shown in above. */
        } else {
            /*
             *   a = xxxxxxx
             *   c = xxxxxxxxxx
             *  a_pos =     |
             */
            *a_pos = a->Prec;
        }
        if((b->Prec + word_shift) >= c->MaxPrec) {
            /*
             *   a = xxxxxxxxx
             *   b =  xxxxxxxBxxx
             *   c = xxxxxxxxxxx
             *  b_pos =   |
             */
            if(c->MaxPrec >=(word_shift + 1)) {
                *b_pos = c->MaxPrec - word_shift - 1;
                *bv = b->frac[*b_pos];
            } else {
                *b_pos = -1L;
            }
        } else {
            /*
             *   a = xxxxxxxxxxxxxxxx
             *   b =  xxxxxx
             *   c = xxxxxxxxxxxxx
             *  b_pos =     |
             */
            *b_pos = b->Prec;
        }
    } else {            /* The MaxPrec of c - 1 > The Prec of a + b  */
        /*
         *    a =   xxxxxxx
         *    b =   xxxxxx
         *    c = xxxxxxxxxxx
         *   c_pos =   |
         */
        *b_pos = b->Prec;
        *a_pos = a->Prec;
        *c_pos = right_word + 1;
    }
    c->Prec = *c_pos;
    c->exponent = a->exponent;
    if(!AddExponent(c,(S_LONG)1)) return (-1L);
    return word_shift;
}

/*
 * Return number og significant digits
 *       c = a * b , Where a = a0a1a2 ... an
 *             b = b0b1b2 ... bm
 *             c = c0c1c2 ... cl
 *          a0 a1 ... an   * bm
 *       a0 a1 ... an   * bm-1
 *         .   .    .
 *       .   .   .
 *        a0 a1 .... an    * b0
 *      +_____________________________
 *     c0 c1 c2  ......  cl
 *     nc      <---|
 *     MaxAB |--------------------|
 */
VP_EXPORT int
VpMult(Real *c, Real *a, Real *b)
{
    U_LONG MxIndA, MxIndB, MxIndAB, MxIndC;
    U_LONG ind_c, i, ii, nc;
    U_LONG ind_as, ind_ae, ind_bs, ind_be;
    U_LONG Carry, s;
    Real *w;

#ifdef _DEBUG
    if(gfDebug) {
        VPrint(stdout, "VpMult(Enter): a=% \n", a);
        VPrint(stdout, "      b=% \n", b);
    }
#endif /* _DEBUG */

    if(!VpIsDefOP(c,a,b,3)) return 0; /* No significant digit */

    if(VpIsZero(a) || VpIsZero(b)) {
        /* at least a or b is zero */
        VpSetZero(c,VpGetSign(a)*VpGetSign(b));
        return 1; /* 0: 1 significant digit */
    }

    if(VpIsOne(a)) {
        VpAsgn(c, b, VpGetSign(a));
        goto Exit;
    }
    if(VpIsOne(b)) {
        VpAsgn(c, a, VpGetSign(b));
        goto Exit;
    }
    if((b->Prec) >(a->Prec)) {
        /* Adjust so that digits(a)>digits(b) */
        w = a;
        a = b;
        b = w;
    }
    w = NULL;
    MxIndA = a->Prec - 1;
    MxIndB = b->Prec - 1;
    MxIndC = c->MaxPrec - 1;
    MxIndAB = a->Prec + b->Prec - 1;

    if(MxIndC < MxIndAB) {    /* The Max. prec. of c < Prec(a)+Prec(b) */
        w = c;
        c = VpAlloc((U_LONG)((MxIndAB + 1) * BASE_FIG), "#0");
        MxIndC = MxIndAB;
    }

    /* set LHSV c info */

    c->exponent = a->exponent;    /* set exponent */
    if(!AddExponent(c,b->exponent)) return 0;
    VpSetSign(c,VpGetSign(a)*VpGetSign(b));    /* set sign  */
    Carry = 0;
    nc = ind_c = MxIndAB;
    memset(c->frac, 0, (nc + 1) * sizeof(U_LONG));        /* Initialize c  */
    c->Prec = nc + 1;        /* set precision */
    for(nc = 0; nc < MxIndAB; ++nc, --ind_c) {
        if(nc < MxIndB) {    /* The left triangle of the Fig. */
            ind_as = MxIndA - nc;
            ind_ae = MxIndA;
            ind_bs = MxIndB;
            ind_be = MxIndB - nc;
        } else if(nc <= MxIndA) {    /* The middle rectangular of the Fig. */
            ind_as = MxIndA - nc;
            ind_ae = MxIndA -(nc - MxIndB);
            ind_bs = MxIndB;
            ind_be = 0;
        } else if(nc > MxIndA) {    /*  The right triangle of the Fig. */
            ind_as = 0;
            ind_ae = MxIndAB - nc - 1;
            ind_bs = MxIndB -(nc - MxIndA);
            ind_be = 0;
        }

        for(i = ind_as; i <= ind_ae; ++i) {
            s =((a->frac[i]) *(b->frac[ind_bs--]));
            Carry = s / BASE;
            s = s -(Carry * BASE);
            c->frac[ind_c] += s;
            if(c->frac[ind_c] >= BASE) {
                s = c->frac[ind_c] / BASE;
                Carry += s;
                c->frac[ind_c] -= (s * BASE);
            }
            if(Carry) {
                ii = ind_c;
                while((--ii) >= 0) {
                    c->frac[ii] += Carry;
                    if(c->frac[ii] >= BASE) {
                        Carry = c->frac[ii] / BASE;
                        c->frac[ii] -=(Carry * BASE);
                    } else {
                        break;
                    }
                }
            }
        }
    }
    if(w != NULL) {        /* free work variable */
        VpNmlz(c);
        VpAsgn(w, c, 1);
        VpFree(c);
        c = w;
    } else {
        VpLimitRound(c,0);
    }

Exit:
#ifdef _DEBUG
    if(gfDebug) {
        VPrint(stdout, "VpMult(c=a*b): c=% \n", c);
        VPrint(stdout, "      a=% \n", a);
        VPrint(stdout, "      b=% \n", b);
    }
#endif /*_DEBUG */
    return c->Prec*BASE_FIG;
}

/*
 *   c = a / b,  remainder = r
 */
VP_EXPORT int
VpDivd(Real *c, Real *r, Real *a, Real *b)
{
    U_LONG word_a, word_b, word_c, word_r;
    U_LONG i, n, ind_a, ind_b, ind_c, ind_r;
    U_LONG nLoop;
    U_LONG q, b1, b1p1, b1b2, b1b2p1, r1r2;
    U_LONG borrow, borrow1, borrow2, qb;

#ifdef _DEBUG
    if(gfDebug) {
        VPrint(stdout, " VpDivd(c=a/b)  a=% \n", a);
        VPrint(stdout, "    b=% \n", b);
    }
#endif /*_DEBUG */

    VpSetNaN(r);
    if(!VpIsDefOP(c,a,b,4)) goto Exit;
    if(VpIsZero(a)&&VpIsZero(b)) {
        VpSetNaN(c);
        return VpException(VP_EXCEPTION_NaN,"(VpDivd) 0/0 not defined(NaN)",0);
    }
    if(VpIsZero(b)) {
        VpSetInf(c,VpGetSign(a)*VpGetSign(b));
        return VpException(VP_EXCEPTION_ZERODIVIDE,"(VpDivd) Divide by zero",0);
    }
    if(VpIsZero(a)) {
        /* numerator a is zero  */
        VpSetZero(c,VpGetSign(a)*VpGetSign(b));
        VpSetZero(r,VpGetSign(a)*VpGetSign(b));
        goto Exit;
    }
    if(VpIsOne(b)) {
        /* divide by one  */
        VpAsgn(c, a, VpGetSign(b));
        VpSetZero(r,VpGetSign(a));
        goto Exit;
    }

    word_a = a->Prec;
    word_b = b->Prec;
    word_c = c->MaxPrec;
    word_r = r->MaxPrec;

    ind_c = 0;
    ind_r = 1;

    if(word_a >= word_r) goto space_error;

    r->frac[0] = 0;
    while(ind_r <= word_a) {
        r->frac[ind_r] = a->frac[ind_r - 1];
        ++ind_r;
    }

    while(ind_r < word_r) r->frac[ind_r++] = 0;
    while(ind_c < word_c) c->frac[ind_c++] = 0;

    /* initial procedure */
    b1 = b1p1 = b->frac[0];
    if(b->Prec <= 1) {
        b1b2p1 = b1b2 = b1p1 * BASE;
    } else {
        b1p1 = b1 + 1;
        b1b2p1 = b1b2 = b1 * BASE + b->frac[1];
        if(b->Prec > 2) ++b1b2p1;
    }

    /* */
    /* loop start */
    ind_c = word_r - 1;
    nLoop = Min(word_c,ind_c);
    ind_c = 1;
    while(ind_c < nLoop) {
        if(r->frac[ind_c] == 0) {
            ++ind_c;
            continue;
        }
        r1r2 = r->frac[ind_c] * BASE + r->frac[ind_c + 1];
        if(r1r2 == b1b2) {
            /* The first two word digits is the same */
            ind_b = 2;
            ind_a = ind_c + 2;
            while(ind_b < word_b) {
                if(r->frac[ind_a] < b->frac[ind_b]) goto div_b1p1;
                if(r->frac[ind_a] > b->frac[ind_b]) break;
                ++ind_a;
                ++ind_b;
            }
            /* The first few word digits of r and b is the same and */
            /* the first different word digit of w is greater than that */
            /* of b, so quotinet is 1 and just subtract b from r. */
            borrow = 0;        /* quotient=1, then just r-b */
            ind_b = b->Prec - 1;
            ind_r = ind_c + ind_b;
            if(ind_r >= word_r) goto space_error;
            n = ind_b;
            for(i = 0; i <= n; ++i) {
                if(r->frac[ind_r] < b->frac[ind_b] + borrow) {
                    r->frac[ind_r] +=(BASE -(b->frac[ind_b] + borrow));
                    borrow = 1;
                } else {
                    r->frac[ind_r] = r->frac[ind_r] - b->frac[ind_b] - borrow;
                    borrow = 0;
                }
                --ind_r;
                --ind_b;
            }
            ++(c->frac[ind_c]);
            goto carry;
        }
        /* The first two word digits is not the same, */
        /* then compare magnitude, and divide actually. */
        if(r1r2 >= b1b2p1) {
            q = r1r2 / b1b2p1;
            c->frac[ind_c] += q;
            ind_r = b->Prec + ind_c - 1;
            goto sub_mult;
        }

div_b1p1:
        if(ind_c + 1 >= word_c) goto out_side;
        q = r1r2 / b1p1;
        c->frac[ind_c + 1] += q;
        ind_r = b->Prec + ind_c;

sub_mult:
        borrow1 = borrow2 = 0;
        ind_b = word_b - 1;
        if(ind_r >= word_r) goto space_error;
        n = ind_b;
        for(i = 0; i <= n; ++i) {
            /* now, perform r = r - q * b */
            qb = q *(b->frac[ind_b]);
            if(qb < BASE) borrow1 = 0;
            else {
                borrow1 = qb / BASE;
                qb = qb - borrow1 * BASE;
            }
            if(r->frac[ind_r] < qb) {
                r->frac[ind_r] +=(BASE - qb);
                borrow2 = borrow2 + borrow1 + 1;
            } else {
                r->frac[ind_r] -= qb;
                borrow2 += borrow1;
            }
            if(borrow2) {
                if(r->frac[ind_r - 1] < borrow2) {
                    r->frac[ind_r - 1] +=(BASE - borrow2);
                    borrow2 = 1;
                } else {
                    r->frac[ind_r - 1] -= borrow2;
                    borrow2 = 0;
                }
            }
            --ind_r;
            --ind_b;
        }

        r->frac[ind_r] -= borrow2;
carry:
        ind_r = ind_c;
        while(c->frac[ind_r] >= BASE) {
            c->frac[ind_r] -= BASE;
            --ind_r;
            ++(c->frac[ind_r]);
        }
    }
    /* End of operation, now final arrangement */
out_side:
    c->Prec = word_c;
    c->exponent = a->exponent;
    if(!AddExponent(c,(S_LONG)2))   return 0;
    if(!AddExponent(c,-(b->exponent))) return 0;

    VpSetSign(c,VpGetSign(a)*VpGetSign(b));
    VpNmlz(c);            /* normalize c */
    r->Prec = word_r;
    r->exponent = a->exponent;
    if(!AddExponent(r,(S_LONG)1)) return 0;
    VpSetSign(r,VpGetSign(a));
    VpNmlz(r);            /* normalize r(remainder) */
    goto Exit;

space_error:
#ifdef _DEBUG
    if(gfDebug) {
        printf("   word_a=%lu\n", word_a);
        printf("   word_b=%lu\n", word_b);
        printf("   word_c=%lu\n", word_c);
        printf("   word_r=%lu\n", word_r);
        printf("   ind_r =%lu\n", ind_r);
    }
#endif /* _DEBUG */
    rb_bug("ERROR(VpDivd): space for remainder too small.");

Exit:
#ifdef _DEBUG
    if(gfDebug) {
        VPrint(stdout, " VpDivd(c=a/b), c=% \n", c);
        VPrint(stdout, "    r=% \n", r);
    }
#endif /* _DEBUG */
    return c->Prec*BASE_FIG;
}

/*
 *  Input  a = 00000xxxxxxxx En(5 preceeding zeros)
 *  Output a = xxxxxxxx En-5
 */
static int
VpNmlz(Real *a)
{
    U_LONG ind_a, i;

    if(!VpIsDef(a)) goto NoVal;
    if(VpIsZero(a)) goto NoVal;

    ind_a = a->Prec;
    while(ind_a--) {
        if(a->frac[ind_a]) {
            a->Prec = ind_a + 1;
            i = 0;
            while(a->frac[i] == 0) ++i;        /* skip the first few zeros */
            if(i) {
                a->Prec -= i;
                if(!AddExponent(a,-((S_INT)i))) return 0;
                memmove(&(a->frac[0]),&(a->frac[i]),(a->Prec)*sizeof(U_LONG));
            }
            return 1;
        }
    }
    /* a is zero(no non-zero digit) */
    VpSetZero(a,VpGetSign(a));
    return 0;

NoVal:
    a->frac[0] = 0;
    a->Prec=1;
    return 0;
}

/*
 *  VpComp = 0  ... if a=b,
 *   Pos  ... a>b,
 *   Neg  ... asign - b->sign;
        else             e = a->sign;
        if(e>0)   return  1;
        else if(e<0) return -1;
        else   return  0;
    }
    if(!VpIsDef(b)) {
        e = -b->sign;
        if(e>0) return  1;
        else return -1;
    }
    /* Zero check */
    if(VpIsZero(a)) {
        if(VpIsZero(b))      return 0; /* both zero */
        val = -VpGetSign(b);
        goto Exit;
    }
    if(VpIsZero(b)) {
        val = VpGetSign(a);
        goto Exit;
    }

    /* compare sign */
    if(VpGetSign(a) > VpGetSign(b)) {
        val = 1;        /* a>b */
        goto Exit;
    }
    if(VpGetSign(a) < VpGetSign(b)) {
        val = -1;        /* aexponent) >(b->exponent)) {
        val = VpGetSign(a);
        goto Exit;
    }
    if((a->exponent) <(b->exponent)) {
        val = -VpGetSign(b);
        goto Exit;
    }

    /* a and b have same exponent, then compare significand. */
    mx =((a->Prec) <(b->Prec)) ?(a->Prec) :(b->Prec);
    ind = 0;
    while(ind < mx) {
        if((a->frac[ind]) >(b->frac[ind])) {
            val = VpGetSign(a);
         goto Exit;
        }
        if((a->frac[ind]) <(b->frac[ind])) {
            val = -VpGetSign(b);
            goto Exit;
        }
        ++ind;
    }
    if((a->Prec) >(b->Prec)) {
        val = VpGetSign(a);
    } else if((a->Prec) <(b->Prec)) {
        val = -VpGetSign(b);
    }

Exit:
    if  (val> 1) val =  1;
    else if(val<-1) val = -1;

#ifdef _DEBUG
    if(gfDebug) {
        VPrint(stdout, " VpComp a=%\n", a);
        VPrint(stdout, "  b=%\n", b);
        printf("  ans=%d\n", val);
    }
#endif /* _DEBUG */
    return (int)val;
}

#ifdef _DEBUG
/*
 *    cntl_chr ... ASCIIZ Character, print control characters
 *     Available control codes:
 *      %  ... VP variable. To print '%', use '%%'.
 *      \n ... new line
 *      \b ... backspace
 *           ... tab
 *     Note: % must must not appear more than once
 *    a  ... VP variable to be printed
 */
VP_EXPORT int
VPrint(FILE *fp, char *cntl_chr, Real *a)
{
    U_LONG i, j, nc, nd, ZeroSup;
    U_LONG n, m, e, nn;

    /* Check if NaN & Inf. */
    if(VpIsNaN(a)) {
        fprintf(fp,SZ_NaN);
        return 8;
    }
    if(VpIsPosInf(a)) {
        fprintf(fp,SZ_INF);
        return 8;
    }
    if(VpIsNegInf(a)) {
        fprintf(fp,SZ_NINF);
        return 9;
    }
    if(VpIsZero(a)) {
        fprintf(fp,"0.0");
        return 3;
    }

    j = 0;
    nd = nc = 0;        /*  nd : number of digits in fraction part(every 10 digits, */
    /*    nd<=10). */
    /*  nc : number of caracters printed  */
    ZeroSup = 1;        /* Flag not to print the leading zeros as 0.00xxxxEnn */
    while(*(cntl_chr + j)) {
        if((*(cntl_chr + j) == '%') &&(*(cntl_chr + j + 1) != '%')) {
         nc = 0;
         if(!VpIsZero(a)) {
                if(VpGetSign(a) < 0) {
                    fprintf(fp, "-");
                    ++nc;
                }
                nc += fprintf(fp, "0.");
                n = a->Prec;
                for(i=0;i < n;++i) {
		    m = BASE1;
                    e = a->frac[i];
                    while(m) {
                        nn = e / m;
                        if((!ZeroSup) || nn) {
                            nc += fprintf(fp, "%lu", nn);    /* The reading zero(s) */
                            /* as 0.00xx will not */
                            /* be printed. */
                            ++nd;
                            ZeroSup = 0;    /* Set to print succeeding zeros */
                        }
                        if(nd >= 10) {    /* print ' ' after every 10 digits */
                            nd = 0;
                            nc += fprintf(fp, " ");
                        }
                        e = e - nn * m;
                        m /= 10;
                    }
                }
                nc += fprintf(fp, "E%ld", VpExponent10(a));
            } else {
                nc += fprintf(fp, "0.0");
            }
        } else {
            ++nc;
            if(*(cntl_chr + j) == '\\') {
                switch(*(cntl_chr + j + 1)) {
                case 'n':
                    fprintf(fp, "\n");
                    ++j;
                    break;
                case 't':
                    fprintf(fp, "\t");
                    ++j;
                 break;
                case 'b':
                    fprintf(fp, "\n");
                    ++j;
                    break;
                default:
                    fprintf(fp, "%c", *(cntl_chr + j));
                    break;
                }
            } else {
                fprintf(fp, "%c", *(cntl_chr + j));
                if(*(cntl_chr + j) == '%') ++j;
            }
        }
        j++;
    }
    return (int)nc;
}
#endif /* _DEBUG */

static void
VpFormatSt(char *psz,S_INT fFmt)
{
    U_LONG ie;
    U_LONG i;
    S_INT nf = 0;
    char ch;

    if(fFmt<=0) return;

    ie = strlen(psz);
    for(i = 0; i < ie; ++i) {
        ch = psz[i];
        if(!ch) break;
        if(ISSPACE(ch) || ch=='-' || ch=='+') continue;
        if(ch == '.')                { nf = 0;continue;}
        if(ch == 'E') break;
        nf++;
        if(nf > fFmt) {
            memmove(psz + i + 1, psz + i, ie - i + 1);
            ++ie;
            nf = 0;
            psz[i] = ' ';
        }
    }
}

VP_EXPORT S_LONG
VpExponent10(Real *a)
{
    S_LONG ex;
    U_LONG n;

    if(!VpHasVal(a)) return 0;

    ex =(a->exponent) * BASE_FIG;
    n = BASE1;
    while((a->frac[0] / n) == 0) {
         --ex;
         n /= 10;
    }
    return ex;
}

VP_EXPORT void
VpSzMantissa(Real *a,char *psz)
{
    U_LONG i, ZeroSup;
    U_LONG n, m, e, nn;

    if(VpIsNaN(a)) {
        sprintf(psz,SZ_NaN);
        return;
    }
    if(VpIsPosInf(a)) {
        sprintf(psz,SZ_INF);
        return;
    }
    if(VpIsNegInf(a)) {
        sprintf(psz,SZ_NINF);
        return;
    }

    ZeroSup = 1;        /* Flag not to print the leading zeros as 0.00xxxxEnn */
    if(!VpIsZero(a)) {
        if(VpGetSign(a) < 0) *psz++ = '-';
        n = a->Prec;
        for(i=0;i < n;++i) {
            m = BASE1;
            e = a->frac[i];
            while(m) {
                nn = e / m;
                if((!ZeroSup) || nn) {
                    sprintf(psz, "%lu", nn);    /* The reading zero(s) */
                    psz += strlen(psz);
                    /* as 0.00xx will be ignored. */
                    ZeroSup = 0;    /* Set to print succeeding zeros */
                }
                e = e - nn * m;
                m /= 10;
            }
        }
        *psz = 0;
        while(psz[-1]=='0') *(--psz) = 0;
    } else {
        if(VpIsPosZero(a)) sprintf(psz, "0");
        else      sprintf(psz, "-0");
    }
}

VP_EXPORT int
VpToSpecialString(Real *a,char *psz,int fPlus)
/* fPlus =0:default, =1: set ' ' before digits , =2: set '+' before digits. */
{
    if(VpIsNaN(a)) {
        sprintf(psz,SZ_NaN);
        return 1;
    }

    if(VpIsPosInf(a)) {
        if(fPlus==1) {
           *psz++ = ' ';
        } else if(fPlus==2) {
           *psz++ = '+';
        }
        sprintf(psz,SZ_INF);
        return 1;
    }
    if(VpIsNegInf(a)) {
        sprintf(psz,SZ_NINF);
        return 1;
    }
    if(VpIsZero(a)) {
        if(VpIsPosZero(a)) {
            if(fPlus==1)      sprintf(psz, " 0.0");
            else if(fPlus==2) sprintf(psz, "+0.0");
            else              sprintf(psz, "0.0");
        } else    sprintf(psz, "-0.0");
        return 1;
    }
    return 0;
}

VP_EXPORT void
VpToString(Real *a,char *psz,int fFmt,int fPlus)
/* fPlus =0:default, =1: set ' ' before digits , =2:set '+' before digits. */
{
    U_LONG i, ZeroSup;
    U_LONG n, m, e, nn;
    char *pszSav = psz;
    S_LONG ex;

    if(VpToSpecialString(a,psz,fPlus)) return;

    ZeroSup = 1;    /* Flag not to print the leading zeros as 0.00xxxxEnn */

    if(VpGetSign(a) < 0) *psz++ = '-';
    else if(fPlus==1)    *psz++ = ' ';
    else if(fPlus==2)    *psz++ = '+';

    *psz++ = '0';
    *psz++ = '.';
    n = a->Prec;
    for(i=0;i < n;++i) {
        m = BASE1;
        e = a->frac[i];
        while(m) {
            nn = e / m;
            if((!ZeroSup) || nn) {
                sprintf(psz, "%lu", nn);    /* The reading zero(s) */
                psz += strlen(psz);
                /* as 0.00xx will be ignored. */
                ZeroSup = 0;    /* Set to print succeeding zeros */
            }
            e = e - nn * m;
            m /= 10;
        }
    }
    ex =(a->exponent) * BASE_FIG;
    n = BASE1;
    while((a->frac[0] / n) == 0) {
        --ex;
        n /= 10;
    }
    while(psz[-1]=='0') *(--psz) = 0;
    sprintf(psz, "E%ld", ex);
    if(fFmt) VpFormatSt(pszSav, fFmt);
}

VP_EXPORT void
VpToFString(Real *a,char *psz,int fFmt,int fPlus)
/* fPlus =0:default,=1: set ' ' before digits ,set '+' before digits. */
{
    U_LONG i;
    U_LONG n, m, e, nn;
    char *pszSav = psz;
    S_LONG ex;

    if(VpToSpecialString(a,psz,fPlus)) return;

    if(VpGetSign(a) < 0) *psz++ = '-';
    else if(fPlus==1)    *psz++ = ' ';
    else if(fPlus==2)    *psz++ = '+';

    n  = a->Prec;
    ex = a->exponent;
    if(ex<=0) {
       *psz++ = '0';*psz++ = '.';
       while(ex<0) {
          for(i=0;i= 0) {
           sprintf(psz, "%lu", a->frac[i]);
           psz += strlen(psz);
       } else {
           m = BASE1;
           e = a->frac[i];
           while(m) {
               nn = e / m;
               *psz++ = (char)(nn + '0');
               e = e - nn * m;
               m /= 10;
           }
       }
       if(ex == 0) *psz++ = '.';
    }
    while(--ex>=0) {
       m = BASE;
       while(m/=10) *psz++ = '0';
       if(ex == 0) *psz++ = '.';
    }
    *psz = 0;
    while(psz[-1]=='0') *(--psz) = 0;
    if(psz[-1]=='.') sprintf(psz, "0");
    if(fFmt) VpFormatSt(pszSav, fFmt);
}

/*
 *  [Output]
 *   a[]  ... variable to be assigned the value.
 *  [Input]
 *   int_chr[]  ... integer part(may include '+/-').
 *   ni   ... number of characters in int_chr[],not including '+/-'.
 *   frac[]  ... fraction part.
 *   nf   ... number of characters in frac[].
 *   exp_chr[]  ... exponent part(including '+/-').
 *   ne   ... number of characters in exp_chr[],not including '+/-'.
 */
VP_EXPORT int
VpCtoV(Real *a, const char *int_chr, U_LONG ni, const char *frac, U_LONG nf, const char *exp_chr, U_LONG ne)
{
    U_LONG i, j, ind_a, ma, mi, me;
    U_LONG loc;
    S_INT  e,es, eb, ef;
    S_INT  sign, signe;
    /* get exponent part */
    e = 0;
    ma = a->MaxPrec;
    mi = ni;
    me = ne;
    signe = 1;
    memset(a->frac, 0, ma * sizeof(U_LONG));
    if(ne > 0) {
        i = 0;
        if(exp_chr[0] == '-') {
            signe = -1;
            ++i;
            ++me;
        } else if(exp_chr[0] == '+') {
            ++i;
            ++me;
        }
        while(i < me) {
            es = e*((S_INT)BASE_FIG);
            e = e * 10 + exp_chr[i] - '0';
            if(es>e*((S_INT)BASE_FIG)) {
                return VpException(VP_EXCEPTION_INFINITY,"exponent overflow",0);
            }
            ++i;
        }
    }

    /* get integer part */
    i = 0;
    sign = 1;
    if(ni >= 0) {
        if(int_chr[0] == '-') {
            sign = -1;
            ++i;
            ++mi;
        } else if(int_chr[0] == '+') {
            ++i;
            ++mi;
        }
    }

    e = signe * e;        /* e: The value of exponent part. */
    e = e + ni;        /* set actual exponent size. */

    if(e > 0)    signe = 1;
    else        signe = -1;

    /* Adjust the exponent so that it is the multiple of BASE_FIG. */
    j = 0;
    ef = 1;
    while(ef) {
        if(e>=0) eb =  e;
        else  eb = -e;
        ef = eb / ((S_INT)BASE_FIG);
        ef = eb - ef * ((S_INT)BASE_FIG);
        if(ef) {
            ++j;        /* Means to add one more preceeding zero */
            ++e;
        }
    }

    eb = e / ((S_INT)BASE_FIG);

    ind_a = 0;
    while(i < mi) {
        a->frac[ind_a] = 0;
        while((j < (U_LONG)BASE_FIG) &&(i < mi)) {
            a->frac[ind_a] = a->frac[ind_a] * 10 + int_chr[i] - '0';
            ++j;
            ++i;
        }
        if(i < mi) {
            ++ind_a;
            if(ind_a >= ma) goto over_flow;
            j = 0;
        }
    }
    loc = 1;

    /* get fraction part */

    i = 0;
    while(i < nf) {
        while((j < (U_LONG)BASE_FIG) &&(i < nf)) {
            a->frac[ind_a] = a->frac[ind_a] * 10 + frac[i] - '0';
            ++j;
            ++i;
        }
        if(i < nf) {
            ++ind_a;
            if(ind_a >= ma) goto over_flow;
            j = 0;
        }
    }
    goto Final;

over_flow:
    rb_warn("Conversion from String to BigDecimal overflow (last few digits discarded).");

Final:
    if(ind_a >= ma) ind_a = ma - 1;
    while(j < (U_LONG)BASE_FIG) {
        a->frac[ind_a] = a->frac[ind_a] * 10;
        ++j;
    }
    a->Prec = ind_a + 1;
    a->exponent = eb;
    VpSetSign(a,sign);
    VpNmlz(a);
    return 1;
}

/*
 * [Input]
 *   *m  ... Real
 * [Output]
 *   *d  ... fraction part of m(d = 0.xxxxxxx). where # of 'x's is fig.
 *   *e  ... U_LONG,exponent of m.
 * DBLE_FIG ... Number of digits in a double variable.
 *
 *  m -> d*10**e, 0Prec));
    *d = 0.0;
    div = 1.;
    while(ind_m < mm) {
        div /=(double)((S_INT)BASE);
        *d = *d +((double) ((S_INT)m->frac[ind_m++])) * div;
    }
    *e = m->exponent * ((S_INT)BASE_FIG);
    *d *= VpGetSign(m);

Exit:
#ifdef _DEBUG
    if(gfDebug) {
        VPrint(stdout, " VpVtoD: m=%\n", m);
        printf("   d=%e * 10 **%ld\n", *d, *e);
        printf("   DBLE_FIG = %ld\n", DBLE_FIG);
    }
#endif /*_DEBUG */
    return f;
}

/*
 * m <- d
 */
VP_EXPORT void
VpDtoV(Real *m, double d)
{
    U_LONG i, ind_m, mm;
    U_LONG ne;
    double  val, val2;

    if(isnan(d)) {
        VpSetNaN(m);
        goto Exit;
    }
    if(isinf(d)) {
        if(d>0.0) VpSetPosInf(m);
        else   VpSetNegInf(m);
        goto Exit;
    }

    if(d == 0.0) {
        VpSetZero(m,1);
        goto Exit;
    }
    val =(d > 0.) ? d :(-d);
    ne = 0;
    if(val >= 1.0) {
        while(val >= 1.0) {
            val /=(double)((S_INT)BASE);
            ++ne;
        }
    } else {
        val2 = 1.0 /(double)((S_INT)BASE);
        while(val < val2) {
            val *=(double)((S_INT)BASE);
            --ne;
        }
    }
    /* Now val = 0.xxxxx*BASE**ne */

    mm = m->MaxPrec;
    memset(m->frac, 0, mm * sizeof(U_LONG));
    for(ind_m = 0;val > 0.0 && ind_m < mm;ind_m++) {
        val *=(double)((S_INT)BASE);
        i =(U_LONG) val;
        val -=(double)((S_INT)i);
        m->frac[ind_m] = i;
    }
    if(ind_m >= mm) ind_m = mm - 1;
    if(d > 0.0) {
        VpSetSign(m, (S_INT)1);
    } else {
        VpSetSign(m,-(S_INT)1);
    }
    m->Prec = ind_m + 1;
    m->exponent = ne;

    VpInternalRound(m,0,(m->Prec>0)?m->frac[m->Prec-1]:0,
                      (U_LONG)(val*((double)((S_INT)BASE))));

Exit:
#ifdef _DEBUG
    if(gfDebug) {
        printf("VpDtoV d=%30.30e\n", d);
        VPrint(stdout, "  m=%\n", m);
    }
#endif /* _DEBUG */
    return;
}

/*
 *  m <- ival
 */
VP_EXPORT void
VpItoV(Real *m, S_INT ival)
{
    U_LONG mm, ind_m;
    U_LONG val, v1, v2, v;
    int isign;
    S_INT ne;

    if(ival == 0) {
        VpSetZero(m,1);
        goto Exit;
    }
    isign = 1;
    val = ival;
    if(ival < 0) {
        isign = -1;
        val =(U_LONG)(-ival);
    }
    ne = 0;
    ind_m = 0;
    mm = m->MaxPrec;
    while(ind_m < mm) {
        m->frac[ind_m] = 0;
        ++ind_m;
    }
    ind_m = 0;
    while(val > 0) {
        if(val) {
         v1 = val;
         v2 = 1;
            while(v1 >= BASE) {
                v1 /= BASE;
                v2 *= BASE;
            }
            val = val - v2 * v1;
            v = v1;
        } else {
            v = 0;
        }
        m->frac[ind_m] = v;
        ++ind_m;
        ++ne;
    }
    m->Prec = ind_m - 1;
    m->exponent = ne;
    VpSetSign(m,isign);
    VpNmlz(m);

Exit:
#ifdef _DEBUG
    if(gfDebug) {
        printf(" VpItoV i=%d\n", ival);
        VPrint(stdout, "  m=%\n", m);
    }
#endif /* _DEBUG */
    return;
}

/*
 * y = SQRT(x),  y*y - x =>0
 */
VP_EXPORT int
VpSqrt(Real *y, Real *x)
{
    Real *f = NULL;
    Real *r = NULL;
    S_LONG y_prec, f_prec;
    S_LONG n;
    S_LONG e;
    S_LONG prec;
    S_LONG nr;
    double val;

    /* Zero, NaN or Infinity ? */
    if(!VpHasVal(x)) {
        if(VpIsZero(x)||VpGetSign(x)>0) {
            VpAsgn(y,x,1);
            goto Exit;
        }
        VpSetNaN(y);
        return VpException(VP_EXCEPTION_OP,"(VpSqrt) SQRT(NaN or negative value)",0);
        goto Exit;
    }

     /* Negative ? */
    if(VpGetSign(x) < 0) {
        VpSetNaN(y);
        return VpException(VP_EXCEPTION_OP,"(VpSqrt) SQRT(negative value)",0);
    }

    /* One ? */
    if(VpIsOne(x)) {
        VpSetOne(y);
        goto Exit;
    }

    n = (S_LONG)y->MaxPrec;
    if((S_LONG)x->MaxPrec > n) n = (S_LONG)x->MaxPrec;
    /* allocate temporally variables  */
    f = VpAlloc(y->MaxPrec *(BASE_FIG + 2), "#1");
    r = VpAlloc((n + n) *(BASE_FIG + 2), "#1");

    nr = 0;
    y_prec = (S_LONG)y->MaxPrec;
    f_prec = (S_LONG)f->MaxPrec;

    prec = x->exponent;
    if(prec > 0)    ++prec;
    else            --prec;
    prec = prec - (S_LONG)y->MaxPrec;
    VpVtoD(&val, &e, x);    /* val <- x  */
    e /= ((S_LONG)BASE_FIG);
    n = e / 2;
    if(e - n * 2 != 0) {
        val /=(double)((S_INT)BASE);
        n =(e + 1) / 2;
    }
    VpDtoV(y, sqrt(val));    /* y <- sqrt(val) */
    y->exponent += n;
    n = (DBLE_FIG + BASE_FIG - 1) / BASE_FIG;
    y->MaxPrec = (U_LONG)Min(n , y_prec);
    f->MaxPrec = y->MaxPrec + 1;
    n = y_prec*((S_LONG)BASE_FIG);
    if((U_LONG)nMaxPrec *= 2;
        if(y->MaxPrec > (U_LONG)y_prec) y->MaxPrec = (U_LONG)y_prec;
        f->MaxPrec = y->MaxPrec;
        VpDivd(f, r, x, y);     /* f = x/y    */
        VpAddSub(r, f, y, -1);  /* r = f - y  */
        VpMult(f, VpPt5, r);    /* f = 0.5*r  */
        if(VpIsZero(f))         goto converge;
        VpAddSub(r, f, y, 1);   /* r = y + f  */
        VpAsgn(y, r, 1);        /* y = r      */
        if(f->exponent <= prec) goto converge;
    } while(++nr < n);
    /* */
#ifdef _DEBUG
    if(gfDebug) {
        printf("ERROR(VpSqrt): did not converge within %ld iterations.\n",
            nr);
    }
#endif /* _DEBUG */
    y->MaxPrec = y_prec;

converge:
    VpChangeSign(y,(S_INT)1);
#ifdef _DEBUG
    if(gfDebug) {
        VpMult(r, y, y);
        VpAddSub(f, x, r, -1);
        printf("VpSqrt: iterations = %lu\n", nr);
        VPrint(stdout, "  y =% \n", y);
        VPrint(stdout, "  x =% \n", x);
        VPrint(stdout, "  x-y*y = % \n", f);
    }
#endif /* _DEBUG */
    y->MaxPrec = y_prec;

Exit:
    VpFree(f);
    VpFree(r);
    return 1;
}

/*
 *
 * f = 0: Round off/Truncate, 1: round up, 2:ceil, 3: floor, 4: Banker's rounding
 * nf: digit position for operation.
 *
 */
VP_EXPORT int
VpMidRound(Real *y, int f, int nf)
/*
 * Round reletively from the decimal point.
 *    f: rounding mode
 *   nf: digit location to round from the the decimal point.
 */
{
    /* fracf: any positive digit under rounding position? */
    /* exptoadd: number of digits needed to compensate negative nf */
    int n,i,ix,ioffset,fracf,exptoadd;
    U_LONG v,shifter;
    U_LONG div;

    nf += y->exponent*((int)BASE_FIG);
    exptoadd=0;
    if (nf < 0) {
	/* rounding position too left(large). */
	if((f!=VP_ROUND_CEIL) && (f!=VP_ROUND_FLOOR)) {
	    VpSetZero(y,VpGetSign(y)); /* truncate everything */
	    return 0;
	}
        exptoadd = -nf;
        nf = 0;
    }
    /* ix: x->fraq[ix] contains round position */
    ix = nf/(int)BASE_FIG;
    if(((U_LONG)ix)>=y->Prec) return 0; /* Unable to round */
    ioffset = nf - ix*((int)BASE_FIG);

    v = y->frac[ix];
    /* drop digits after pointed digit */
    n = BASE_FIG - ioffset - 1;
    for(shifter=1,i=0;i 0);
    v /= shifter;
    div = v/10;
    v = v - div*10;
    if (fracf == 0) {
        for(i=ix+1;iPrec;i++) {
            if (y->frac[i]%BASE) {
                fracf = 1;
                break;
            }
        }
    }
    memset(y->frac+ix+1, 0, (y->Prec - (ix+1)) * sizeof(U_LONG));
    switch(f) {
    case VP_ROUND_DOWN: /* Truncate */
         break;
    case VP_ROUND_UP:   /* Roundup */
        if(fracf) ++div;
         break;
    case VP_ROUND_HALF_UP:   /* Round half up  */
        if(v>=5) ++div;
        break;
    case VP_ROUND_HALF_DOWN: /* Round half down  */
        if(v>=6) ++div;
        break;
    case VP_ROUND_CEIL: /* ceil */
        if(fracf && (VpGetSign(y)>0)) ++div;
        break;
    case VP_ROUND_FLOOR: /* floor */
        if(fracf && (VpGetSign(y)<0)) ++div;
        break;
    case VP_ROUND_HALF_EVEN: /* Banker's rounding */
        if(v>5) ++div;
        else if(v==5) {
            if((U_LONG)i==(BASE_FIG-1)) {
                if(ix && (y->frac[ix-1]%2)) ++div;
            } else {
                if(div%2) ++div;
            }
        }
        break;
    }
    for(i=0;i<=n;++i) div *= 10;
    if(div>=BASE) {
        if(ix) {
            y->frac[ix] = 0;
            VpRdup(y,ix);
        } else {
            S_INT s = VpGetSign(y);
            int e = y->exponent;
            VpSetOne(y);
            VpSetSign(y,s);
            y->exponent = e+1;
        }
    } else {
        y->frac[ix] = div;
        VpNmlz(y);
    }
    if (exptoadd > 0) {
        y->exponent += exptoadd/BASE_FIG;
        exptoadd %= BASE_FIG;
        for(i=0;ifrac[0] *= 10;
            if (y->frac[0] >= BASE) {
                y->frac[0] /= BASE;
                y->exponent++;
            }
        }
    }
    return 1;
}

VP_EXPORT int
VpLeftRound(Real *y, int f, int nf)
/*
 * Round from the left hand side of the digits.
 */
{
    U_LONG v;
    if(!VpHasVal(y)) return 0; /* Unable to round */
    v = y->frac[0];
    nf -= VpExponent(y)*BASE_FIG;
    while((v /= 10) != 0) nf--;
    nf += (BASE_FIG-1);
    return VpMidRound(y,f,nf);
}

VP_EXPORT int 
VpActiveRound(Real *y, Real *x, int f, int nf)
{
    /* First,assign whole value in truncation mode */
    if(VpAsgn(y, x, 10)<=1) return 0; /* Zero,NaN,or Infinity */
    return VpMidRound(y,f,nf);
}

static int
VpLimitRound(Real *c,U_LONG ixDigit)
{
    U_LONG ix = VpGetPrecLimit();
    if(!VpNmlz(c))    return -1;
    if(!ix)           return 0;
    if(!ixDigit) ixDigit = c->Prec-1;
    if((ix+BASE_FIG-1)/BASE_FIG > ixDigit+1) return 0;
    return VpLeftRound(c,VpGetRoundMode(),ix);
}

static void 
VpInternalRound(Real *c,int ixDigit,U_LONG vPrev,U_LONG v)
{
    int f = 0;

    if(VpLimitRound(c,ixDigit)) return;
    if(!v)                      return;

    v /= BASE1;
    switch(gfRoundMode) {
    case VP_ROUND_DOWN:
        break;
    case VP_ROUND_UP:
        if(v)                    f = 1;
        break;
    case VP_ROUND_HALF_UP:
        if(v >= 5)               f = 1;
        break;
    case VP_ROUND_HALF_DOWN:
        if(v >= 6)               f = 1;
        break;
    case VP_ROUND_CEIL:  /* ceil */
        if(v && (VpGetSign(c)>0)) f = 1;
        break;
    case VP_ROUND_FLOOR: /* floor */
        if(v && (VpGetSign(c)<0)) f = 1;
        break;
    case VP_ROUND_HALF_EVEN:  /* Banker's rounding */
        if(v>5) f = 1;
        else if(v==5 && vPrev%2)  f = 1;
        break;
    }
    if(f) {
        VpRdup(c,ixDigit);    /* round up */
        VpNmlz(c);
    }
}

/*
 *  Rounds up m(plus one to final digit of m).
 */
static int
VpRdup(Real *m,U_LONG ind_m)
{
    U_LONG carry;

    if(!ind_m) ind_m = m->Prec;

    carry = 1;
    while(carry > 0 && (ind_m--)) {
        m->frac[ind_m] += carry;
        if(m->frac[ind_m] >= BASE) m->frac[ind_m] -= BASE;
        else                       carry = 0;
    }
    if(carry > 0) {        /* Overflow,count exponent and set fraction part be 1  */
        if(!AddExponent(m,(S_LONG)1)) return 0;
        m->Prec = m->frac[0] = 1;
    } else {
        VpNmlz(m);
    }
    return 1;
}

/*
 *  y = x - fix(x)
 */
VP_EXPORT void
VpFrac(Real *y, Real *x)
{
    U_LONG my, ind_y, ind_x;

    if(!VpHasVal(x)) {
        VpAsgn(y,x,1);
        goto Exit;
    }

    if(x->exponent > 0 && (U_LONG)x->exponent >= x->Prec) {
        VpSetZero(y,VpGetSign(x));
        goto Exit;
    } else if(x->exponent <= 0) {
        VpAsgn(y, x, 1);
        goto Exit;
    }

    y->Prec = x->Prec -(U_LONG) x->exponent;
    y->Prec = Min(y->Prec, y->MaxPrec);
    y->exponent = 0;
    VpSetSign(y,VpGetSign(x));
    ind_y = 0;
    my = y->Prec;
    ind_x = x->exponent;
    while(ind_y < my) {
        y->frac[ind_y] = x->frac[ind_x];
        ++ind_y;
        ++ind_x;
    }
    VpNmlz(y);

Exit:
#ifdef _DEBUG
    if(gfDebug) {
        VPrint(stdout, "VpFrac y=%\n", y);
        VPrint(stdout, "    x=%\n", x);
    }
#endif /* _DEBUG */
    return;
}

/*
 *   y = x ** n
 */
VP_EXPORT int
VpPower(Real *y, Real *x, S_INT n)
{
    U_LONG s, ss;
    S_LONG sign;
    Real *w1 = NULL;
    Real *w2 = NULL;

    if(VpIsZero(x)) {
        if(n==0) {
           VpSetOne(y);
           goto Exit;
        }
        sign = VpGetSign(x);
        if(n<0) {
           n = -n;
           if(sign<0) sign = (n%2)?(-1):(1);
           VpSetInf (y,sign);
        } else {
           if(sign<0) sign = (n%2)?(-1):(1);
           VpSetZero(y,sign);
        }
        goto Exit;
    }
    if(!VpIsDef(x)) {
        VpSetNaN(y); /* Not sure !!! */
        goto Exit;
    }

    if((x->exponent == 1) &&(x->Prec == 1) &&(x->frac[0] == 1)) {
        /* abs(x) = 1 */
        VpSetOne(y);
        if(VpGetSign(x) > 0) goto Exit;
        if((n % 2) == 0) goto Exit;
        VpSetSign(y,-(S_INT)1);
        goto Exit;
    }

    if(n > 0) sign = 1;
    else if(n < 0) {
        sign = -1;
        n = -n;
    } else {
        VpSetOne(y);
        goto Exit;
    }

    /* Allocate working variables  */

    w1 = VpAlloc((y->MaxPrec + 2) * BASE_FIG, "#0");
    w2 = VpAlloc((w1->MaxPrec * 2 + 1) * BASE_FIG, "#0");
    /* calculation start */

    VpAsgn(y, x, 1);
    --n;
    while(n > 0) {
        VpAsgn(w1, x, 1);
        s = 1;
loop1:  ss = s;
        s += s;
        if(s >(U_LONG) n) goto out_loop1;
        VpMult(w2, w1, w1);
        VpAsgn(w1, w2, 1);
        goto loop1;
out_loop1:
        n -= ss;
        VpMult(w2, y, w1);
        VpAsgn(y, w2, 1);
    }
    if(sign < 0) {
        VpDivd(w1, w2, VpConstOne, y);
        VpAsgn(y, w1, 1);
    }

Exit:
#ifdef _DEBUG
    if(gfDebug) {
        VPrint(stdout, "VpPower y=%\n", y);
        VPrint(stdout, "VpPower x=%\n", x);
        printf("  n=%d\n", n);
    }
#endif /* _DEBUG */
    VpFree(w2);
    VpFree(w1);
    return 1;
}

#ifdef _DEBUG
int
VpVarCheck(Real * v)
/*
 * Checks the validity of the Real variable v.
 * [Input]
 *   v ... Real *, variable to be checked.
 * [Returns]
 *   0  ... correct v.
 *   other ... error
 */
{
    U_LONG i;

    if(v->MaxPrec <= 0) {
        printf("ERROR(VpVarCheck): Illegal Max. Precision(=%lu)\n",
            v->MaxPrec);
        return 1;
    }
    if((v->Prec <= 0) ||((v->Prec) >(v->MaxPrec))) {
        printf("ERROR(VpVarCheck): Illegal Precision(=%lu)\n", v->Prec);
        printf("       Max. Prec.=%lu\n", v->MaxPrec);
        return 2;
    }
    for(i = 0; i < v->Prec; ++i) {
        if((v->frac[i] >= BASE)) {
            printf("ERROR(VpVarCheck): Illegal fraction\n");
            printf("       Frac[%ld]=%lu\n", i, v->frac[i]);
            printf("       Prec.   =%lu\n", v->Prec);
            printf("       Exp. =%d\n", v->exponent);
            printf("       BASE =%lu\n", BASE);
            return 3;
        }
    }
    return 0;
}
#endif /* _DEBUG */


================================================
FILE: ext/bigdecimal/bigdecimal.def
================================================
EXPORTS
Init_bigdecimal


================================================
FILE: ext/bigdecimal/bigdecimal.h
================================================
/*
 *
 * Ruby BigDecimal(Variable decimal precision) extension library. 
 *
 * Copyright(C) 2002 by Shigeo Kobayashi(shigeo@tinyforest.gr.jp) 
 *
 * You may distribute under the terms of either the GNU General Public 
 * License or the Artistic License, as specified in the README file 
 * of this BigDecimal distribution. 
 *
 * NOTES:
 *   2003-03-28 V1.0 checked in.
 *
 */

#ifndef  ____BIG_DECIMAL__H____
#define  ____BIG_DECIMAL__H____

#if defined(__cplusplus)
extern "C" {
#endif

/*
 *  NaN & Infinity
 */
#define SZ_NaN  "NaN"
#define SZ_INF  "Infinity"
#define SZ_PINF "+Infinity"
#define SZ_NINF "-Infinity"

/*
 *   #define VP_EXPORT other than static to let VP_ routines 
 *   be called from outside of this module.
 */
#define VP_EXPORT static 

#define U_LONG unsigned long
#define S_LONG long
#define U_INT  unsigned int
#define S_INT  int

/* Exception codes */
#define VP_EXCEPTION_ALL        ((unsigned short)0x00FF)
#define VP_EXCEPTION_INFINITY   ((unsigned short)0x0001)
#define VP_EXCEPTION_NaN        ((unsigned short)0x0002)
#define VP_EXCEPTION_UNDERFLOW  ((unsigned short)0x0004)
#define VP_EXCEPTION_OVERFLOW   ((unsigned short)0x0001) /* 0x0008) */
#define VP_EXCEPTION_ZERODIVIDE ((unsigned short)0x0001) /* 0x0010) */

/* Following 2 exceptions cann't controlled by user */
#define VP_EXCEPTION_OP         ((unsigned short)0x0020)
#define VP_EXCEPTION_MEMORY     ((unsigned short)0x0040)

/* Computation mode */
#define VP_ROUND_MODE            ((unsigned short)0x0100)
#define VP_ROUND_UP         1
#define VP_ROUND_DOWN       2
#define VP_ROUND_HALF_UP    3
#define VP_ROUND_HALF_DOWN  4
#define VP_ROUND_CEIL       5
#define VP_ROUND_FLOOR      6
#define VP_ROUND_HALF_EVEN  7

#define VP_SIGN_NaN                0 /* NaN                      */
#define VP_SIGN_POSITIVE_ZERO      1 /* Positive zero            */
#define VP_SIGN_NEGATIVE_ZERO     -1 /* Negative zero            */
#define VP_SIGN_POSITIVE_FINITE    2 /* Positive finite number   */
#define VP_SIGN_NEGATIVE_FINITE   -2 /* Negative finite number   */
#define VP_SIGN_POSITIVE_INFINITE  3 /* Positive infinite number */
#define VP_SIGN_NEGATIVE_INFINITE -3 /* Negative infinite number */

/*
 * VP representation
 *  r = 0.xxxxxxxxx *BASE**exponent
 */
typedef struct {
    VALUE  obj;     /* Back pointer(VALUE) for Ruby object.     */
    U_LONG MaxPrec; /* Maximum precision size                   */
                    /* This is the actual size of pfrac[]       */
                    /*(frac[0] to frac[MaxPrec] are available). */
    U_LONG Prec;    /* Current precision size.                  */
                    /* This indicates how much the.             */
                    /* the array frac[] is actually used.       */
    S_INT  exponent;/* Exponent part.                           */
    short  sign;    /* Attributes of the value.                 */
                    /*
                     *        ==0 : NaN
                     *          1 : Positive zero
                     *         -1 : Negative zero
                     *          2 : Positive number
                     *         -2 : Negative number
                     *          3 : Positive infinite number
                     *         -3 : Negative infinite number
                     */
    short  flag;    /* Not used in vp_routines,space for user.  */
    U_LONG frac[1]; /* Pointer to array of fraction part.       */
} Real;

/*  
 *  ------------------
 *   EXPORTables.
 *  ------------------
 */

VP_EXPORT  Real *
VpNewRbClass(U_LONG mx,char *str,VALUE klass);

VP_EXPORT  Real *VpCreateRbObject(U_LONG mx,const char *str);

VP_EXPORT U_LONG VpBaseFig(void);
VP_EXPORT U_LONG VpDblFig(void);
VP_EXPORT U_LONG VpBaseVal(void);

/* Zero,Inf,NaN (isinf(),isnan() used to check) */
VP_EXPORT double VpGetDoubleNaN(void);
VP_EXPORT double VpGetDoublePosInf(void);
VP_EXPORT double VpGetDoubleNegInf(void);
VP_EXPORT double VpGetDoubleNegZero(void);

/* These 2 functions added at v1.1.7 */
VP_EXPORT U_LONG VpGetPrecLimit(void);
VP_EXPORT U_LONG VpSetPrecLimit(U_LONG n);

/* Round mode */
VP_EXPORT int           VpIsRoundMode(unsigned long n);
VP_EXPORT unsigned long VpGetRoundMode(void);
VP_EXPORT unsigned long VpSetRoundMode(unsigned long n);

VP_EXPORT int VpException(unsigned short f,const char *str,int always);
VP_EXPORT int VpIsNegDoubleZero(double v);
VP_EXPORT U_LONG VpNumOfChars(Real *vp,const char *pszFmt);
VP_EXPORT U_LONG VpInit(U_LONG BaseVal);
VP_EXPORT void *VpMemAlloc(U_LONG mb);
VP_EXPORT void VpFree(Real *pv);
VP_EXPORT Real *VpAlloc(U_LONG mx, const char *szVal);
VP_EXPORT int VpAsgn(Real *c,Real *a,int isw);
VP_EXPORT int VpAddSub(Real *c,Real *a,Real *b,int operation);
VP_EXPORT int VpMult(Real *c,Real *a,Real *b);
VP_EXPORT int VpDivd(Real *c,Real *r,Real *a,Real *b);
VP_EXPORT int VpComp(Real *a,Real *b);
VP_EXPORT S_LONG VpExponent10(Real *a);
VP_EXPORT void VpSzMantissa(Real *a,char *psz);
VP_EXPORT int VpToSpecialString(Real *a,char *psz,int fPlus);
VP_EXPORT void VpToString(Real *a,char *psz,int fFmt,int fPlus);
VP_EXPORT void VpToFString(Real *a,char *psz,int fFmt,int fPlus);
VP_EXPORT int VpCtoV(Real *a,const char *int_chr,U_LONG ni,const char *frac,U_LONG nf,const char *exp_chr,U_LONG ne);
VP_EXPORT int VpVtoD(double *d,S_LONG *e,Real *m);
VP_EXPORT void VpDtoV(Real *m,double d);
VP_EXPORT void VpItoV(Real *m,S_INT ival);
VP_EXPORT int VpSqrt(Real *y,Real *x);
VP_EXPORT int VpActiveRound(Real *y,Real *x,int f,int il);
VP_EXPORT int VpMidRound(Real *y, int f, int nf);
VP_EXPORT int VpLeftRound(Real *y, int f, int nf);
VP_EXPORT void VpFrac(Real *y,Real *x);
VP_EXPORT int VpPower(Real *y,Real *x,S_INT n);

/* VP constants */
VP_EXPORT Real *VpOne(void);

/*  
 *  ------------------
 *  MACRO definitions.
 *  ------------------
 */
#define Abs(a)     (((a)>= 0)?(a):(-(a)))
#define Max(a, b)  (((a)>(b))?(a):(b))
#define Min(a, b)  (((a)>(b))?(b):(a))

#define VpMaxPrec(a)   ((a)->MaxPrec)
#define VpPrec(a)      ((a)->Prec)
#define VpGetFlag(a)   ((a)->flag)

/* Sign */

/* VpGetSign(a) returns 1,-1 if a>0,a<0 respectively */
#define VpGetSign(a) (((a)->sign>0)?1:(-1))
/* Change sign of a to a>0,a<0 if s = 1,-1 respectively */
#define VpChangeSign(a,s) {if((s)>0) (a)->sign=(short)Abs((S_LONG)(a)->sign);else (a)->sign=-(short)Abs((S_LONG)(a)->sign);}
/* Sets sign of a to a>0,a<0 if s = 1,-1 respectively */
#define VpSetSign(a,s)    {if((s)>0) (a)->sign=(short)VP_SIGN_POSITIVE_FINITE;else (a)->sign=(short)VP_SIGN_NEGATIVE_FINITE;}

/* 1 */
#define VpSetOne(a)       {(a)->frac[0]=(a)->exponent=(a)->Prec=1;(a)->sign=VP_SIGN_POSITIVE_FINITE;}

/* ZEROs */
#define VpIsPosZero(a)  ((a)->sign==VP_SIGN_POSITIVE_ZERO)
#define VpIsNegZero(a)  ((a)->sign==VP_SIGN_NEGATIVE_ZERO)
#define VpIsZero(a)     (VpIsPosZero(a) || VpIsNegZero(a))
#define VpSetPosZero(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_POSITIVE_ZERO)
#define VpSetNegZero(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_NEGATIVE_ZERO)
#define VpSetZero(a,s)  ( ((s)>0)?VpSetPosZero(a):VpSetNegZero(a) )

/* NaN */
#define VpIsNaN(a)      ((a)->sign==VP_SIGN_NaN)
#define VpSetNaN(a)     ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_NaN)

/* Infinity */
#define VpIsPosInf(a)   ((a)->sign==VP_SIGN_POSITIVE_INFINITE)
#define VpIsNegInf(a)   ((a)->sign==VP_SIGN_NEGATIVE_INFINITE)
#define VpIsInf(a)      (VpIsPosInf(a) || VpIsNegInf(a))
#define VpIsDef(a)      ( !(VpIsNaN(a)||VpIsInf(a)) )
#define VpSetPosInf(a)  ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_POSITIVE_INFINITE)
#define VpSetNegInf(a)  ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_NEGATIVE_INFINITE)
#define VpSetInf(a,s)   ( ((s)>0)?VpSetPosInf(a):VpSetNegInf(a) )
#define VpHasVal(a)     (a->frac[0])
#define VpIsOne(a)      ((a->Prec==1)&&(a->frac[0]==1)&&(a->exponent==1))
#define VpExponent(a)   (a->exponent)
#ifdef _DEBUG
int VpVarCheck(Real * v);
VP_EXPORT int VPrint(FILE *fp,char *cntl_chr,Real *a);
#endif /* _DEBUG */

#if defined(__cplusplus)
}  /* extern "C" { */
#endif
#endif /* ____BIG_DECIMAL__H____ */


================================================
FILE: ext/bigdecimal/bigdecimal_en.html
================================================






BigDecimal:An extension library for Ruby


BigDecimal(Variable Precision Floating Library for Ruby)


BigDecimal is an extension library for the Ruby interpreter. Using BigDecimal class, you can obtain any number of significant digits in computation. For the details about Ruby see:
NOTE:
This software is provided "AS IS" and without any express or implied warranties,including,without limitation,the implied warranties of merchantibility and fitness for a particular purpose. For the details,see COPYING and README included in this distribution.

Contents


Introduction

Ruby already has builtin (variable length integer number) class Bignum. Using Bignum class,you can obtain any integer value in magnitude. But, variable length decimal number class is not yet built in. This is why I made variable length floating class BigDecimal. Feel free to send any comments or bug reports to me.
shigeo@tinyforest.gr.jp I will try(but can't promise) to fix bugs reported.

Installation

The Ruby latest version can be downloaded from Official Ruby page. Once decompress the downloaded Ruby archive,follow the normal installation procedures according to the documents included.

Usage and methods

Suppose you already know Ruby programming, to create BigDecimal objects,the program would like:
   require 'bigdecimal'
   a=BigDecimal::new("0.123456789123456789")
   b=BigDecimal("123456.78912345678",40)
   c=a+b

List of methods

In 32 bits integer system,every 4 digits(in decimal) are computed simultaneously. This means the number of significant digits in BigDecimal is always a multiple of 4.

Some more methods are available in Ruby code (not C code). Functions such as sin,cos ...,are in math.rb in bigdecimal directory. To use them,require math.rb as:

require "bigdecimal/math.rb"
For details,see the math.rb code and comments. Other utility methods are in util.rb. To use util.rb, require it as:
require "bigdecimal/util.rb"
For details,see the util.rb code.

Class methods

  • new
  • "new" method creates a new BigDecimal object.
    a=BigDecimal::new(s[,n]) or
    a=BigDecimal(s[,n]) or
    where:
    s: Initial value string. Spaces will be ignored. Any unrecognizable character for representing initial value terminates the string.
    n: Maximum number of significant digits of a. n must be a Fixnum object. If n is omitted or is equal to 0,then the maximum number of significant digits of a is determined from the length of s. Actual number of digits handled in computations are usually gretaer than n.
    n is useful when performing divisions like
    BigDecimal("1")    / BigDecimal("3")    # => 0.3333333333 33E0
    BigDecimal("1",10) / BigDecimal("3",10) # => 0.3333333333 3333333333 33333333E0
    
    but the resulting digits obtained may differ in future version.
  • mode
  • f = BigDecimal.mode(s[,v])
    mode method controls BigDecimal computation. If the second argument is not given or is nil,then the value of current setting is returned. Following usage are defined.

    [EXCEPTION control]

    Actions when computation results NaN or Infinity can be defined as follows.

    f = BigDecimal::mode(BigDecimal::EXCEPTION_NaN,flag)
    f = BigDecimal::mode(BigDecimal::EXCEPTION_INFINITY,flag)
    f = BigDecimal::mode(BigDecimal::EXCEPTION_UNDERFLOW,flag)
    f = BigDecimal::mode(BigDecimal::EXCEPTION_OVERFLOW,flag)
    f = BigDecimal::mode(BigDecimal::EXCEPTION_ZERODIVIDE,flag)
    f = BigDecimal::mode(BigDecimal::EXCEPTION_ALL,flag)
    EXCEPTION_NaN controls the execution when computation results to NaN.
    EXCEPTION_INFINITY controls the execution when computation results to Infinity(}Infinity).
    EXCEPTION_UNDERFLOW controls the execution when computation underflows.
    EXCEPTION_OVERFLOW controls the execution when computation overflows.
    EXCEPTION_ZERODIVIDE controls the execution when zero-division occures.
    EXCEPTION_ALL controls the execution for any exception defined occures.
    If the flag is true,then the relating exception is thrown.
    No exception is thrown when the flag is false(default) and computation continues with the result:
    EXCEPTION_NaN results to NaN
    EXCEPTION_INFINITY results to +Infinity or -Infinity
    EXCEPTION_UNDERFLOW results to 0.
    EXCEPTION_OVERFLOW results to +Infinity or -Infinity
    EXCEPTION_ZERODIVIDE results to +Infinity or -Infinity
    EXCEPTION_INFINITY,EXCEPTION_OVERFLOW, and EXCEPTION_ZERODIVIDE are currently the same.
    The return value of mode method is the value set.
    If nil is specified for the second argument,then current setting is returned.
    Suppose the return value of the mode method is f,then f & BigDecimal::EXCEPTION_NaN !=0 means EXCEPTION_NaN is set to on.

    [ROUND error control]

    Rounding operation can be controlled as:

    f = BigDecimal::mode(BigDecimal::ROUND_MODE,flag)
    where flag must be one of:
    ROUND_UPround away from zero.
    ROUND_DOWNround towards zero(truncate).
    ROUND_HALF_UPround up if the digit >= 5 otherwise truncated(default).
    ROUND_HALF_DOWNround up if the digit >= 6 otherwise truncated.
    ROUND_HALF_EVENround towards the even neighbor(Banker's rounding).
    ROUND_CEILINGround towards positive infinity(ceil).
    ROUND_FLOORround towards negative infinity(floor).
    New rounding mode is returned. If nil is specified for the second argument,then current setting is returned.
    The digit location for rounding operation can not be specified by this mode method, use truncate/round/ceil/floor/add/sub/mult/div mthods for each instance instead.
  • limit[(n)]
  • Limits the maximum digits that the newly created BigDecimal objects can hold never exceed n. This means the rounding operation specified by BigDecimal.mode is performed if necessary. limit returns the value before set if n is nil or is not specified. Zero,the default value,means no upper limit.
    The limit has no more priority than instance methods such as truncate,round,ceil,floor,add,sub,mult,and div.
    mf = BigDecimal::limit(n)
  • double_fig
  • double_fig is a class method which returns the number of digits the Float class can have.
      p BigDecimal::double_fig  # ==> 20 (depends on the CPU etc.)
    
    The equivalent C programs which calculates the value of double_fig is:
     double v          = 1.0;
     int    double_fig = 0;
     while(v + 1.0 > 1.0) {
        ++double_fig;
        v /= 10;
     }
    
  • BASE
  • Base value used in the BigDecimal calculation. On 32 bits integer system,the value of BASE is 10000.
    b = BigDecimal::BASE

Instance methods

  • +
  • addition(c = a + b)
    For the resulting number of significant digits of c,see
    Resulting number of significant digits.
  • -
  • subtraction (c = a - b) or negation (c = -a)
    For the resulting number of significant digits of c,see Resulting number of significant digits.
  • *
  • multiplication(c = a * b)
    For the resulting number of significant digits of c,see Resulting number of significant digits.
  • /
  • division(c = a / b)
    For the resulting number of significant digits of c,see Resulting number of significant digits.
  • add(b,n)
  • c = a.add(b,n)
    c = a.add(b,n) performs c = a + b.
    If n is less than the actual significant digits of a + b, then c is rounded properly according to the BigDecimal.limit.
    If n is zero,then the result is the same as +'s.
  • sub(b,n)
  • c = a.sub(b,n)
    c = a.sub(b,n) performs c = a - b.
    If n is less than the actual significant digits of a - b, then c is rounded properly according to the BigDecimal.limit.
    If n is zero,then the result is the same as -'s.
  • mult(b,n)
  • c = a.mult(b,n)
    c = a.mult(b,n) performs c = a * b.
    If n is less than the actual significant digits of a * b, then c is rounded properly according to the BigDecimal.limit.
    If n is zero,then the result is the same as *'s.
  • div(b[,n])
  • c = a.div(b,n)
    c = a.div(b,n) performs c = a / b.
    If n is less than the actual significant digits of a / b, then c is rounded properly according to the BigDecimal.limit.
    If n is zero,then the result is the same as /'s. If n is not given,then the result will be an integer(BigDecimal) like Float#div.
  • fix
  • c = a.fix
    returns integer part of a.
  • frac
  • c = a.frac
    returns fraction part of a.
  • floor[(n)]
  • c = a.floor
    returns the maximum integer value (in BigDecimal) which is less than or equal to a.
     c = BigDecimal("1.23456").floor  #  ==> 1
     c = BigDecimal("-1.23456").floor #  ==> -2
    
    As shown in the following example,an optional integer argument (n) specifying the position of the target digit can be given.
    If n> 0,then the (n+1)th digit counted from the decimal point in fraction part is processed(resulting number of fraction part digits is less than or equal to n).
    If n<0,then the n-th digit counted from the decimal point in integer part is processed(at least n 0's are placed from the decimal point to left).
     c = BigDecimal("1.23456").floor(4)   #  ==> 1.2345
     c = BigDecimal("15.23456").floor(-1) #  ==> 10.0
    
  • ceil[(n)]
  • c = a.ceil
    returns the minimum integer value (in BigDecimal) which is greater than or equal to a.
     c = BigDecimal("1.23456").ceil  #  ==> 2
     c = BigDecimal("-1.23456").ceil #  ==> -1
    
    As shown in the following example,an optional integer argument (n) specifying the position of the target digit can be given.
    If n>0,then the (n+1)th digit counted from the decimal point in fraction part is processed(resulting number of fraction part digits is less than or equal to n).
    If n<0,then the n-th digit counted from the decimal point in integer part is processed(at least n 0's are placed from the decimal point to left).
     c = BigDecimal("1.23456").ceil(4)   # ==> 1.2346
     c = BigDecimal("15.23456").ceil(-1) # ==> 20.0
    
  • round[(n[,b])]
  • c = a.round
    round a to the nearest 1(default)D
     c = BigDecimal("1.23456").round  #  ==> 1
     c = BigDecimal("-1.23456").round #  ==> -1
    
    The rounding operation changes according to BigDecimal::mode(BigDecimal::ROUND_MODE,flag) if specified. As shown in the following example,an optional integer argument (n) specifying the position of the target digit can be given.
    If n>0,then the (n+1)th digit counted from the decimal point in fraction part is processed(resulting number of fraction part digits is less than or equal to n).
    If n<0,then the n-th digit counted from the decimal point in integer part is processed(at least n 0's are placed from the decimal point to left).
    c = BigDecimal::new("1.23456").round(4)   #  ==> 1.2346
    c = BigDecimal::new("15.23456").round(-1) #  ==> 20.0
    
    Rounding operation can be specified by setting the second optional argument b with the valid ROUND_MODE.
    c = BigDecimal::new("1.23456").round(3,BigDecimal::ROUND_HALF_EVEN)   #  ==> 1.234
    c = BigDecimal::new("1.23356").round(3,BigDecimal::ROUND_HALF_EVEN)   #  ==> 1.234
    
  • truncate[(n)]
  • c = a.truncate
    truncate a to the nearest 1D
    As shown in the following example,an optional integer argument (n) specifying the position of the target digit can be given.
    If n>0,then the (n+1)th digit counted from the decimal point in fraction part is processed(resulting number of fraction part digits is less than or equal to n).
    If n<0,then the n-th digit counted from the decimal point in integer part is processed(at least n 0's are placed from the decimal point to left).
    c = BigDecimal::new("1.23456").truncate(4)   #  ==> 1.2345
    c = BigDecimal::new("15.23456").truncate(-1) #  ==> 10.0
    
  • abs
  • c = a.abs
    returns an absolute value of a.
  • to_i
  • changes a to an integer.
    i = a.to_i
    i becomes to Fixnum or Bignum. If a is Infinity or NaN,then i becomes to nil.
  • to_s[(n)]
  • converts to string(default results look like "0.xxxxxEn").
    BigDecimal("1.23456").to_s  #  ==> "0.123456E1"
    
    If n(>0) is given,then a space is inserted to each of two parts divided by the decimal point after every n digits for readability.
    BigDecimal("0.1234567890123456789").to_s(10)   #  ==> "0.1234567890 123456789E0"
    
    n can be a string representing a positive integer number.
    BigDecimal("0.1234567890123456789").to_s("10") #  ==> "0.1234567890 123456789E0"
    
    If the first character is '+'(or ' '),then '+'(or ' ') will be set before value string when the value is positive.
    BigDecimal("0.1234567890123456789").to_s(" 10") #  ==> " 0.1234567890 123456789E0"
    BigDecimal("0.1234567890123456789").to_s("+10") #  ==> "+0.1234567890 123456789E0"
    BigDecimal("-0.1234567890123456789").to_s("10") #  ==> "-0.1234567890 123456789E0"
    
    At the end of the string,'E'(or 'e') or 'F'(or 'f') can be specified to change number representation.
    BigDecimal("1234567890.123456789").to_s("E")  #  ==> "0.1234567890123456789E10"
    BigDecimal("1234567890.123456789").to_s("F")  #  ==> "1234567890.123456789"
    BigDecimal("1234567890.123456789").to_s("5E") #  ==> "0.12345 67890 12345 6789E10"
    BigDecimal("1234567890.123456789").to_s("5F") #  ==> "12345 67890.12345 6789"
    
  • exponent
  • returns an integer holding exponent value of a.
    n = a.exponent
    means a = 0.xxxxxxx*10**n.
  • precs
  • n,m = a.precs
    prec returns number of significant digits (n) and maximum number of significant digits (m) of a.
  • to_f
  • Creates a new Float object having (nearly) the same value. Use split method if you want to convert by yourself.
  • sign
  • n = a.sign
    returns positive value if a > 0,negative value if a < 0, otherwise zero if a == 0.
    where the value of n means that a is:
    n = BigDecimal::SIGN_NaN(0) : a is NaN
    n = BigDecimal::SIGN_POSITIVE_ZERO(1) : a is +0
    n = BigDecimal::SIGN_NEGATIVE_ZERO(-1) : a is -0
    n = BigDecimal::SIGN_POSITIVE_FINITE(2) : a is positive
    n = BigDecimal::SIGN_NEGATIVE_FINITE(-2) : a is negative
    n = BigDecimal::SIGN_POSITIVE_INFINITE(3) : a is +Infinity
    n = BigDecimal::SIGN_NEGATIVE_INFINITE(-3) : a is -Infinity
    The value in () is the actual value,see (Internal structure.
  • nan?
  • a.nan? returns True when a is NaN.
  • infinite?
  • a.infinite? returns 1 when a is +,-1 when a is -, nil otherwise.
  • finite?
  • a.finite? returns true when a is neither nor NaN.
  • zero?
  • c = a.zero?
    returns true if a is equal to 0,otherwise returns false
  • nonzero?
  • c = a.nonzero?
    returns nil if a is 0,otherwise returns a itself.
  • split
  • decomposes a BigDecimal value to 4 parts. All 4 parts are returned as an array.
    Parts consist of a sign(0 when the value is NaN,+1 for positive and -1 for negative value), a string representing fraction part,base value(always 10 currently),and an integer(Fixnum) for exponent respectively. a=BigDecimal::new("3.14159265")
    f,x,y,z = a.split
    where f=+1,x="314159265",y=10 and z=1
    therefore,you can translate BigDecimal value to Float as:
    s = "0."+x
    b = f*(s.to_f)*(y**z)
  • inspect
  • is used for debugging output.
    p a=BigDecimal::new("3.14",10)
    should produce output like "#<0x112344:'0.314E1',4(12)%gt;". where "0x112344" is the address, '0.314E1' is the value,4 is the number of the significant digits, and 12 is the maximum number of the significant digits the object can hold.
  • sqrt
  • c = a.sqrt(n)
    computes square root value of a with significant digit number n at least.
  • **
  • c = a ** n
    returns the value of a powered by n. n must be an integer.
  • power
  • The same as ** method.
    c = a.power(n)
    returns the value of a powered by n(c=a**n). n must be an integer.
  • divmod,quo,modulo,%,remainder
  • See,corresponding methods in Float class.
  • <=>
  • c = a <=> b
    returns 0 if a==b,1 if a > b,and returns -1 if a < b.
Following methods need no explanation.
  • ==
  • ===
  • same as ==,used in case statement.
  • !=
  • <
  • <=
  • >
  • >=

About 'coerce'

For the binary operation like A op B:
1.Both A and B are BigDecimal objects
A op B is normally performed.
2.A is the BigDecimal object but B is other than BigDecimal object
Operation is performed,after B is translated to correcponding BigDecimal object(because BigDecimal supports coerce method).
3.A is not the BigDecimal object but B is BigDecimal object
If A has coerce mthod,then B will translate A to corresponding BigDecimal object and the operation is performed,otherwise an error occures.
String is not translated to BigDecimal in default. Uncomment /* #define ENABLE_NUMERIC_STRING */ in bigdecimal.c, compile and install again if you want to enable string to BigDecimal conversion. Translation stops without error at the character representing non digit. For instance,"10XX" is translated to 10,"XXXX" is translated to 0.
String representing zero or infinity such as "Infinity","+Infinity","-Infinity",and "NaN" can also be translated to BigDecimal unless false is specified by mode method.
BigDecimal class supports coerce method(for the details about coerce method,see Ruby documentations). This means the most binary operation can be performed if the BigDecimal object is at the left hand side of the operation.

For example:
  a = BigDecimal.E(20)
  c = a * "0.123456789123456789123456789" # A String is changed to BigDecimal object.
is performed normally.
But,because String does not have coerce method,the following example can not be performed.
  a = BigDecimal.E(20)
  c = "0.123456789123456789123456789" * a # ERROR
If you actually have any inconvenience about the error above. You can define a new class derived from String class, and define coerce method within the new class.

Infinity,Not a Number(NaN),Zero

Infinite numbers and NaN can be represented by string writing "+Infinity"(or "Infinity"),"-Infinity",and "NaN" respectively in your program. Infinite numbers can be obtained by 1.0/0.0(=Infinity) or -1.0/0.0(=-Infinity).

NaN(Not a number) can be obtained by undefined computation like 0.0/0.0 or Infinity-Infinity. Any computation including NaN results to NaN. Comparisons with NaN never become true,including comparison with NaN itself.

Zero has two different variations as +0.0 and -0.0. But,still, +0.0==-0.0 is true.

Computation results including Infinity,NaN,+0.0 or -0.0 become complicated. Run following program and comfirm the results. Send me any incorrect result if you find.
 require "bigdecimal"
 aa  = %w(1 -1 +0.0 -0.0 +Infinity -Infinity NaN)
 ba  = %w(1 -1 +0.0 -0.0 +Infinity -Infinity NaN)
 opa = %w(+ - * / <=> > >=  < == != <=)
 for a in aa
  for b in ba
    for op in opa
      x = BigDecimal::new(a)
      y = BigDecimal::new(b)
      eval("ans= x #{op} y;print a,' ',op,' ',b,' ==> ',ans.to_s,\"\n\"")
    end
  end
 end

Internal structure

BigDecimal number is defined by the structure Real in BigDecimal.h. Digits representing a float number are kept in the array frac[] defined in the structure. In the program,any floating number(BigDecimal number) is represented as:
= 0.xxxxxxxxx*BASE**n

where 'x' is any digit representing mantissa(kept in the array frac[]), BASE is base value(=10000 in 32 bit integer system), and n is the exponent value.
Larger BASE value enables smaller size of the array frac[],and increases computation speed. The value of BASE is defined ind VpInit(). In 32 bit integer system,this value is 10000. In 64 bit integer system,the value becomes larger. BigDecimal has not yet been compiled and tested on 64 bit integer system. It will be very nice if anyone try to run BigDecimal on 64 bit system and inform me the results. When BASE is 10000,an element of the array frac[] can have vale of from 0 to 9999. (up to 4 digits).
The structure Real is defined in bigdecimal.h as:
  typedef struct {
     VALUE  obj;     /* Back pointer(VALUE) for Ruby object.         */
     unsigned long MaxPrec; /* The size of the array frac[]          */
     unsigned long Prec;    /* Current size of frac[] actually used. */
     short    sign;         /* Attribute of the value.  */
                            /*  ==0 : NaN               */
                            /*    1 : +0                */
                            /*   -1 : -0                */
                            /*    2 : Positive number   */
                            /*   -2 : Negative number   */
                            /*    3 : +Infinity         */
                            /*   -3 : -Infinity         */
     unsigned short flag;   /* Control flag             */
     int      exponent;     /* Exponent value(0.xxxx*BASE**exponent) */
     unsigned long frac[1]; /* An araay holding mantissa(Variable)   */
  } Real;
The decimal value 1234.56784321 is represented as(BASE=10000):
    0.1234 5678 4321*(10000)**1
where frac[0]=1234,frac[1]=5678,frac[2]=4321, Prec=3,sign=2,exponent=1. MaxPrec can be any value greater than or equal to Prec.

Binary or decimal number representation

I adopted decimal number representation for BigDecimal implementation. Of cource,binary number representation is common on the most computers.

Advantages using decimal representation

The reason why I adopted decimal number representation for BigDecimal is:
Easy for debugging
The floating number 1234.56784321 can be easily represented as:
frac[0]=1234,frac[1]=5678,frac[2]=4321,exponent=1,and sign=2.
Exact representation
Following program can add all numbers(in decimal) in a file without any error(no round operation).
   file = File::open(....,"r")
   s = BigDecimal::new("0")
   while line = file.gets
      s = s + line
   end
If the internal representation is binary,translation from decimal to binary is required and the translation error is inevitable. For example, 0.1 can not exactly be represented in binary.
0.1 => b1*2**(-1)+b1*2**(-2)+b3*2**(-3)+b4*2**(-4)....
where b1=0,b2=0,b3=0,b4=1...
bn(n=1,2,3,...) is infinite series of digit with value of 0 or 1, and rounding operation is necessary but where we should round the series ? Of cource,exact "0.1" is printed if the rouding operation is properly done,
Significant digit we can have is automatically determined
In binary representation,0.1 can not be represented in finite series of digit. But we only need one element(frac[0]=1) in decimal representation. This means that we can always determine the size of the array frac[] in Real structure.

Disadvantage of decimal representation

Because most computers have no internal decimal representaion. Once you use BigDecimal,you need to keep using it without considering computation cost if exact computation is required.

Which is the first input?

Because most people uses decimal notatin for numeric data representation, BigDecimal can handle numeric data without loss of translation error.

Resulting number of significant digits

For the fundamental arithmetics such as addition,subtraction, multiplication,and division,I prepared 2 group of methods

1. +,-,*,/

For the operation + - * /,you can not specify the resulting number of significant digits.
Resulting number of significant digits are defined as:
1.1 For *,resulting number of significant digits is the sum of the significant digits of both side of the operator. For / ,resulting number of significant digits is the sum of the maximum significant digits of both side of the operator.
1.2 For + and -,resulting number of significant digits is determined so that no round operation is needed.
For example, c has more than 100 siginificant digits if c is computed as:
c = 0.1+0.1*10**(-100)

As +,-,and * are always exact(no round operation is performed unless BigDecimal.limit is specified), which means more momories are required to keep computation results. But,the division such as c=1.0/3.0 will always be rounded.

2. add,sub,mult,div

The length of the significant digits obtained from +,-,*,/ is always defined by that of right and left side of the operator. To specify the length of the significant digits by your self, use methos add,sub,mult,div.
 BigDecimal("2").div(3,12) # 2.0/3.0 => 0.6666666666 67E0

3. truncate,round,ceil,floor

Using these methods,you can specify rounding location relatively from decimal point.
 BigDecimal("6.66666666666666").round(12) # => 0.6666666666 667E1

4. Example

Following example compute the ratio of the circumference of a circle to its dirmeter(pi=3.14159265358979....) using J.Machin's formula.

#!/usr/local/bin/ruby

require "bigdecimal"
#
# Calculates 3.1415.... (the number of times that a circle's diameter
# will fit around the circle) using J. Machin's formula.
#
def big_pi(sig) # sig: Number of significant figures
  exp    = -sig
  pi     = BigDecimal::new("0")
  two    = BigDecimal::new("2")
  m25    = BigDecimal::new("-0.04")
  m57121 = BigDecimal::new("-57121")

  u = BigDecimal::new("1")
  k = BigDecimal::new("1")
  w = BigDecimal::new("1")
  t = BigDecimal::new("-80")
  while (u.nonzero? && u.exponent >= exp) 
    t   = t*m25
    u   = t.div(k,sig)
    pi  = pi + u
    k   = k+two
  end

  u = BigDecimal::new("1")
  k = BigDecimal::new("1")
  w = BigDecimal::new("1")
  t = BigDecimal::new("956")
  while (u.nonzero? && u.exponent >= exp )
    t   = t.div(m57121,sig)
    u   = t.div(k,sig)
    pi  = pi + u
    k   = k+two
  end
  pi
end

if $0 == __FILE__
  if ARGV.size == 1
    print "PI("+ARGV[0]+"):\n"
    p big_pi(ARGV[0].to_i)
  else
    print "TRY: ruby pi.rb 1000 \n"
  end
end


Shigeo Kobayashi (E-Mail:<shigeo@tinyforest.gr.jp>) ================================================ FILE: ext/bigdecimal/bigdecimal_ja.html ================================================ BigDecimal:An extension library for Ruby

BigDecimal(•ϒ_ZpgCu)


BigDecimal ̓IuWFNgw̋͂ȃXNvgł Ruby ɉ•ϒ_ vZ@\lj邽߂̊gCułB Ruby ɂ‚Ă̏ڂe͈ȉURLQƂĂB

ڎ


͂߂

Ruby ɂ Bignum ƂNXAS̐łvZ邱Ƃł܂B ACӌ̕_ZpNX悤łBŁA Cӌ̕_ZpgCu BigDecimal 쐬܂B s⏕EĂꍇǂǂA
shigeo@tinyforest.gr.jp ܂łm点Bs𒼂C͑傢ɂ܂BAԂȂǂ̊֌WŖ ͂ł܂B܂Aʂɂ‚Ăۏ؂ł̂ł͂܂B \߁AB

̃vÓARɔzzEςč\܂BA쌠͕Ă܂B zzEϓ̌ Ruby ̂ɏ܂Bڂ README ǂłB

CXg[ɂ‚

BigDecimal ܂ Ruby ̍ŐVłRubyy[W_E[hł܂B _E[hŐVł𓀂Aʏ̃CXg[菇sĉB Ruby CXg[΁A BigDecimal pł悤ɂȂ͂łB \[Xt@C bigdecimal.c,bigdecimal.h ̂Q‚݂̂łB

gp@ƃ\bḧꗗ

uRuby͊ɏvƂOŁA
require 'bigdecimal'
a=BigDecimal::new("0.123456789123456789")
b=BigDecimal("123456.78912345678",40)
c=a+b

Ƃ悤ȊŎgp܂B

\bhꗗ

ȉ̃\bhp”\łB uLvƂ BigDecimal xۏ؂錅łB ҂ł͂܂A኱̗]TČvZ܂B ܂AႦ΂RQrbg̃VXeł͂POiłSɌvZ܂B]āAł́A ́uLv͂S̔{ƂȂĂ܂B

ȉ̃\bhȊOɂA(C ł͂Ȃ) Ruby \[X̌` 񋟂Ă̂܂BႦ΁A

require "bigdecimal/math.rb"
Ƃ邱ƂŁAsin cos Ƃ֐gpł悤ɂȂ܂B gp@ȂǁAڍׂ math.rb ̓eQƂĉB ̑AFloat Ƃ̑ݕϊȂǂ̃\bh util.rb ŃT|[gĂ܂B pɂ
require "bigdecimal/util.rb"
̂悤ɂ܂Bڍׂ util.rb ̓eQƂĉB

NX\bh

  • new
  • V BigDecimal IuWFNg𐶐܂B
    a=BigDecimal::new(s[,n]) ܂
    a=BigDecimal(s[,n])
    s ͐\鏉l𕶎Ŏw肵܂B Xy[X͖܂B܂AfłȂo_ ͏ÎƂ݂Ȃ܂B n ͕KvȗLia ̍őLj𐮐Ŏw肵܂B n 0 ܂͏ȗꂽƂ́An ̒l s ̗LƂ݂Ȃ܂B s ̗L n Ƃ n=0 ̂ƂƓłB a ̍őL n ኱傢l̗p܂B őL͈ȉ̂悤ȊZsƂɈӖ܂B
    BigDecimal("1")    / BigDecimal("3")    # => 0.3333333333 33E0
    BigDecimal("1",10) / BigDecimal("3",10) # => 0.3333333333 3333333333 33333333E0
    
    AX̉ZɂőL n ̎舵͏̃o[W ኱ύX”\܂B
  • mode
  • f = BigDecimal.mode(s[,v])
    BigDecimal̎sʂ𐧌䂵܂BQȗA܂ nil w肷 ̐ݒl߂܂B
    ȉ̎gp@`Ă܂B

    [O]

    vZʂ(NaN)[ɂ鏜ZɂȂƂ̏`邱Ƃł܂B

    f = BigDecimal::mode(BigDecimal::EXCEPTION_NaN,flag)
    f = BigDecimal::mode(BigDecimal::EXCEPTION_INFINITY,flag)
    f = BigDecimal::mode(BigDecimal::EXCEPTION_UNDERFLOW,flag)
    f = BigDecimal::mode(BigDecimal::EXCEPTION_OVERFLOW,flag)
    f = BigDecimal::mode(BigDecimal::EXCEPTION_ZERODIVIDE,flag)
    f = BigDecimal::mode(BigDecimal::EXCEPTION_ALL,flag)
    EXCEPTION_NaN ͌ʂ NaN ɂȂƂ̎włB
    EXCEPTION_INFINITY ͌ʂ(}Infinity)ɂȂƂ̎włB
    EXCEPTION_UNDERFLOW ͎wA_[t[Ƃ̎włB
    EXCEPTION_OVERFLOW ͎wI[o[t[Ƃ̎włB
    EXCEPTION_ZERODIVIDE ̓[ɂ銄ZsƂ̎włB
    EXCEPTION_ALL ́A”\ȑSĂɑ΂ĈꊇĐݒ肷ƂɎgp܂B

    flag true ̂Ƃ́Aw肵ԂɂȂƂɗO𔭍s悤ɂȂ܂B
    flag falseiftHgjȂAO͔s܂BvZʂ͈ȉ̂悤ɂȂ܂B
    EXCEPTION_NaN ̂ƂA(NaN)
    EXCEPTION_INFINITY ̂ƂA(+ or -Infinity)
    EXCEPTION_UNDERFLOW ̂ƂA[
    EXCEPTION_OVERFLOW ̂ƂA+Infinity -Infinity
    EXCEPTION_ZERODIVIDE ̂ƂA+Infinity -Infinity
    EXCEPTION_INFINITYAEXCEPTION_OVERFLOWAEXCEPTION_ZERODIVIDE ͍̂Ƃ듯łB
    ߂ĺAݒ̒lłBulv̈Ӗ́AႦ BigDecimal::EXCEPTION_NaNƁulv & [ȊOȂ EXCEPTION_NaNݒ肳ĂƂӖłB

    [ۂߏw]

    vZr̊ۂߑ̎w肪ł܂B

    f = BigDecimal::mode(BigDecimal::ROUND_MODE,flag)
    ̌`Ŏw肵܂B
    ŁAflag ͈ȉ(ʓ͑ΉCX^X\bh)̈‚w肵܂B
    ROUND_UPSĐ؂グ܂B
    ROUND_DOWNSĐ؂̂Ă܂(truncate)B
    ROUND_HALF_UPľܓ܂(ftHg)B
    ROUND_HALF_DOWN܎̘Z܂B
    ROUND_HALF_EVENl̘Z܂BT̎͏ʂP̎̂݌Jグ܂(Banker's rounding)B
    ROUND_CEILINGl̑傫ɌJグ܂(ceil)B
    ROUND_FLOORl̏ɌJ艺܂(floor)B
    ߂l͎w flag ̒lłB Q nil w肷ƁA̐ݒlԂ܂B mode \bhł͊ۂߑ̈ʒu[Uw肷邱Ƃ͂ł܂B ۂߑƈʒuŐ䂵ꍇ BigDecimal::limit truncate/round/ceil/floorA add/sub/mult/div ƂCX^X\bhgpĉB
  • limit([n])
  • BigDecimalIuWFNg̍ő包nɐ܂B ߂l͐ݒ肷O̒lłBݒl̃ftHgl͂OŁAƂӖłB n w肵ȂA܂ n nil ̏ꍇ́A̍ő包Ԃ܂B
    vZ𑱍sԂɁǍɑĂ܂悤ȏꍇ limit ŗ\ߌ𐧌ł܂B̏ꍇ BigDecimal.mode Ŏw肳ꂽ ۂߏs܂B ACX^X\bh (truncate/round/ceil/floor/add/sub/mult/div) limit D悳܂B
    mf = BigDecimal::limit(n)
  • double_fig
  • Ruby Float NXێłL̐Ԃ܂B
      p BigDecimal::double_fig  # ==> 20 (depends on the CPU etc.)
    
    double_fig͈ȉ C vǑʂƓłB
     double v          = 1.0;
     int    double_fig = 0;
     while(v + 1.0 > 1.0) {
        ++double_fig;
        v /= 10;
     }
    
  • BASE
  • Ŏgp̒lłB 32 rbg̏nł10000łB
    b = BigDecimal::BASE

CX^X\bh

  • +
  • Zic = a + bj
    c ̐xɂ‚Ắu
    vZxɂ‚vQƂĂB
  • -
  • Zic = a - bjA܂͕]ic = -aj
    c ̐xɂ‚ẮuvZxɂ‚vQƂĂB
  • *
  • Z(c = a * b)
    c̐x(a̐x)+(b̐x)xłB
    ڂ́uvZxɂ‚vQƂĂB
  • /
  • Z(c = a / b)
    c ̐xɂ‚ẮuvZxɂ‚vQƂĂB
  • add(b,n)
  • ȉ̂悤Ɏgp܂B
    c = a.add(b,n)
    c = a + b ő n ܂ŌvZ܂B
    a + b ̐x n 傫Ƃ BigDecimal.mode Ŏw肳ꂽ@Ŋۂ߂܂B
    n [Ȃ + ƓłB
  • sub(b,n)
  • ȉ̂悤Ɏgp܂B
    c = a.sub(b,n)
    c = a - b ő n ܂ŌvZ܂B
    a - b ̐x n 傫Ƃ BigDecimal.mode Ŏw肳ꂽ@Ŋۂ߂܂B
    n [Ȃ - ƓłB
  • mult(b,n)
  • ȉ̂悤Ɏgp܂B
    c = a.mult(b,n)
    c = a * b ő n ܂ŌvZ܂B
    a * b ̐x n 傫Ƃ BigDecimal.mode Ŏw肳ꂽ@Ŋۂ߂܂B
    n [Ȃ * ƓłB
  • div(b[,n])
  • ȉ̂悤Ɏgp܂B
    c = a.div(b,n)
    c = a / b ő n ܂ŌvZ܂B a / b ̐x n 傫Ƃ BigDecimal.mode Ŏw肳ꂽ@Ŋۂ߂܂B
    n [Ȃ / ƓłB
    n ȗꂽƂ Float#div ƓlɌʂ(BigDecimal)ɂȂ܂B
  • fix
  • a ̏_ȉ̐؂̂āB
    c = a.fix
  • frac
  • a ̐̐؂̂āB
    c = a.frac
  • floor[(n)]
  • c = a.floor
    a ȉ̍ő吮iBigDecimal ljԂ܂B
    c = BigDecimal("1.23456").floor  #  ==> 1
    c = BigDecimal("-1.23456").floor #  ==> -2
    
    ȉ̂悤Ɉ n ^邱Ƃł܂B
    n>=0 ȂA_ȉ n+1 ʂ̐𑀍삵܂(_ȉAő n ɂ܂)B
    n ̂Ƃ͏_ȏ n ڂ𑀍삵܂(_ʒu獶ɏȂƂ n ‚ 0 т܂)B
     c = BigDecimal("1.23456").floor(4)   #  ==> 1.2345
     c = BigDecimal("15.23456").floor(-1) #  ==> 10.0
    
  • ceil[(n)]
  • c = a.ceil
    a ȏ̐̂AłvZA̒liBigDecimal ljԂ܂B
    c = BigDecimal("1.23456").ceil  #  ==> 2
    c = BigDecimal("-1.23456").ceil #  ==> -1
    
    ȉ̂悤Ɉ^āA_ȉ n+1 ʂ̐𑀍삷邱Ƃł܂B
    n>=0 ȂA_ȉ n+1 ʂ̐𑀍삵܂(_ȉAő n ɂ܂)B
    n ̂Ƃ͏_ȏ n ڂ𑀍삵܂(_ʒu獶ɏȂƂ n ‚ 0 т܂)B
     c = BigDecimal("1.23456").ceil(4)   # ==> 1.2346
     c = BigDecimal("15.23456").ceil(-1) # ==> 20.0
    
  • round[(n[,b])]
  • c = a.round
    NX\bh BigDecimal::mode(BigDecimal::ROUND_MODE,flag) Ŏw肵 ROUND_MODE ɏ]Ċۂߑs܂B BigDecimal::mode(BigDecimal::ROUND_MODE,flag) ʼnw肹AA w肵Ȃꍇ́u_ȉʂ̐ľܓĐiBigDecimal ljvɂ܂B
     c = BigDecimal("1.23456").round  #  ==> 1
     c = BigDecimal("-1.23456").round #  ==> -1
    
    ȉ̂悤Ɉ^āA_ȉ n+1 ʂ̐𑀍삷邱Ƃł܂B
    n ̎́A_ȉ n+1 ʂ̐ۂ߂܂(_ȉAő n ɂ܂)B
    n ̂Ƃ͏_ȏ n ڂۂ߂܂(_ʒu獶ɏȂƂ n ‚ 0 т܂)B
    c = BigDecimal("1.23456").round(4)   #  ==> 1.2346
    c = BigDecimal("15.23456").round(-1) #  ==> 20.0
    
    QԖڂ̈w肷ƁABigDecimal#mode ̎w𖳎āAw肳ꂽ@ ۂߑs܂B
    c = BigDecimal("1.23456").round(3,BigDecimal::ROUND_HALF_EVEN)   #  ==> 1.234
    c = BigDecimal("1.23356").round(3,BigDecimal::ROUND_HALF_EVEN)   #  ==> 1.234
    
  • truncate
  • c = a.truncate
    _ȉ̐؂̂ĂĐiBigDecimal ljɂ܂B
    ȉ̂悤Ɉ^āA_ȉ n+1 ʂ̐𑀍삷邱Ƃł܂B
    n ̎́A_ȉ n+1 ʂ̐؂̂Ă܂(_ȉAő n ɂ܂)B n ̂Ƃ͏_ȏ n ڂ𑀍삵܂(_ʒu獶ɏȂƂ n ‚ 0 т܂)B
    c = BigDecimal("1.23456").truncate(4)   #  ==> 1.2345
    c = BigDecimal("15.23456").truncate(-1) #  ==> 10.0
    
  • abs
  • ̐Βl
    c = a.abs
  • to_i
  • _ȉ؂̂ĂĐɕϊ܂B
    i = a.to_i
    i ͒lɉ Fixnum Bignum ɂȂ܂B a Infinity NaN ̂ƂAi nil ɂȂ܂B
  • to_f
  • Float IuWFNgɕϊ܂B 肫ߍׂlKvȂ split \bh𗘗p B
  • to_s[(n)]
  • ɕϊ܂(ftHg "0.xxxxxEn" ̌`ɂȂ܂jB
    BigDecimal("1.23456").to_s  #  ==> "0.123456E1"
    
    n ɐ̐w肳ꂽƂ́A_ŕ鍶EAꂼ n ɋ󔒂ŋ؂܂B
    BigDecimal("0.1234567890123456789").to_s(10)   #  ==> "0.1234567890 123456789E0"
    
    n ɐ̐\w肷邱Ƃł܂B
    BigDecimal("0.1234567890123456789").to_s("10") #  ==> "0.1234567890 123456789E0"
    
    ̍ŏ '+'i܂ ' 'jtƁAl̏ꍇA擪 '+'i܂ ' 'jt܂ ȉꍇ́A '-' t܂BjB
    BigDecimal("0.1234567890123456789").to_s(" 10") #  ==> " 0.1234567890 123456789E0"
    BigDecimal("0.1234567890123456789").to_s("+10") #  ==> "+0.1234567890 123456789E0"
    BigDecimal("-0.1234567890123456789").to_s("10") #  ==> "-0.1234567890 123456789E0"
    
    ɕ̍Ō E(܂ e) F(܂ f) w肷邱ƂŁAȉ̂悤 \`ύX邱Ƃł܂B
    BigDecimal("1234567890.123456789").to_s("E")  #  ==> "0.1234567890123456789E10"
    BigDecimal("1234567890.123456789").to_s("F")  #  ==> "1234567890.123456789"
    BigDecimal("1234567890.123456789").to_s("5E") #  ==> "0.12345 67890 12345 6789E10"
    BigDecimal("1234567890.123456789").to_s("5F") #  ==> "12345 67890.12345 6789"
    
  • exponent
  • w𐮐lŕԂ܂B n = a.exponent
    a ̒l 0.xxxxxxx*10**n Ӗ܂B
  • precs
  • n,m = a.precs
    a ̗L (n) ƍőL (m) ̔zԂ܂B
  • sign
  • l(sign > 0)A(sign < 0)Ȃ(sigh==0)ł邩̏Ԃ܂B n = a.sign
    ƂƂ n ̒l a ȉ̂ƂӖ܂B
    () ̒̐́Aۂ̒lł(u\vQ)B
    n = BigDecimal::SIGN_NaN(0) : a NaN
    n = BigDecimal::SIGN_POSITIVE_ZERO(1) : a +0
    n = BigDecimal::SIGN_NEGATIVE_ZERO(-1) : a -0
    n = BigDecimal::SIGN_POSITIVE_FINITE(2) : a ͐̒l
    n = BigDecimal::SIGN_NEGATIVE_FINITE(-2) : a ͕̒l
    n = BigDecimal::SIGN_POSITIVE_INFINITE(3) : a +Infinity
    n = BigDecimal::SIGN_NEGATIVE_INFINITE(-3) : a -Infinity
  • nan?
  • a.nan? a NaN̂Ƃ^Ԃ܂B
  • infinite?
  • a.infinite? a +̂Ƃ 1 A-̂Ƃ -1AȊÔƂ nil Ԃ܂B
  • finite?
  • a.finite? a ܂ NaN łȂƂ^Ԃ܂B
  • zero?
  • a 0 Ȃ true ɂȂ܂B
    c = a.zero?
  • nonzero?
  • a 0 Ȃ nilA0 ȊOȂ a ̂̂Ԃ܂B
    c = a.nonzero?
  • split
  • BigDecimal l 0.xxxxxxx*10**n ƕ\ƂɁAiNaN̂Ƃ 0AȊO+1-1ɂȂ܂jA ̕i"xxxxxxx"jƁAi10jAXɎw n z Ԃ܂B
    a=BigDecimal::new("3.14159265")
    f,x,y,z = a.split
    ƂƁAf=+1Ax="314159265"Ay=10Az=1ɂȂ܂B
    ]āA
    s = "0."+x
    b = f*(s.to_f)*(y**z)
    Float ɕϊ邱Ƃł܂B
  • inspect
  • fobOo͂Ɏgp܂B
    p a=BigDecimal::new("3.14",10)
    ƂƁA[0x112344:'0.314E1',4(12)]̂悤ɏo͂܂B ŏ16i̓IuWFNg̃AhXA '0.314E1' ͒lA 4݂̗͌L(\኱傫Ƃ܂)A Ō̓IuWFNg蓾ő包ɂȂ܂B
  • **
  • a n vZ܂B͐B
    c = a ** n
    ʂƂ c ̗L a n {ȏɂȂ̂ŒӁB
  • power
  • ** ƓŁAa n vZ܂B͐B
    c = a.power(n)
    ʂƂ c ̗L a n {ȏɂȂ̂ŒӁB
  • sqrt
  • a̗L n ̕in ̕ł͂܂j j[g@ŌvZ܂B
    c = a.sqrt(n)
  • divmod,quo,modulo,%,remainder
  • ڍׂ͑Ή Float ̊e\bhQƂĉB
  • <=>
  • a==b Ȃ 0Aa > b Ȃ 1Aa < b Ȃ -1 ɂȂ܂B
    c = a <=> b
́AǂŎ̔@łB
  • ==
  • ===
  • u==vƓł case Ŏgp܂B
  • !=
  • <
  • <=
  • >
  • >=

coerceɂ‚

BigDecimal IuWFNgZpZq̍ɂƂ́ABigDecimal IuWFNg EɂIuWFNg(KvȂ) BigDecimal ɕϊĂvZ܂B ]āABigDecimal IuWFNgȊOłlӖ̂ȂEɒu Z͉”\łB
ÁiʏjlɎϊ邱Ƃ͂ł܂B 𐔒lɎϊꍇ bigfloat.c u/* #define ENABLE_NUMERIC_STRING */ṽRgOĂA ăRpCAăCXg[Kv܂B Ől^ꍇ͒ӂKvłBlɕϊłȂƁA Pɕϊ~߂邾ŃG[ɂ͂Ȃ܂B"10XX"ȂPOA"XXXX"͂O ƈ܂B
   a = BigDecimal.E(20)
   c = a * "0.123456789123456789123456789" #  BigDecimal ɕϊĂvZ
񐔂\ƂāA"Infinity"A"+Infinity"A"-Infinity"A"NaN" gpł܂(啶Eʂ܂)BAmode \bh false w肵ꍇ͗O܂B
܂ABigDecimalNX coerceiRuby{QƁjT|[gĂ܂B ]āABigDecimal IuWFNgEɂꍇ͑vłB A݂ Ruby C^v^̎dlA񂪍ɂƌvZł܂B
  a = BigDecimal.E(20)
  c = "0.123456789123456789123456789" * a # G[
KvƂ͎v܂񂪁AǂĂƌl String IuWFNgpVȃNX쐬ĂA ̃NX coerce T|[gĂB

A񐔁A[̈

uvƂ͕\łȂ炢傫ȐłBʂɈ߂ +Infinityi̖j -Infinityi̖jƂ 悤ɕ\L܂B 1.0/0.0 ̂悤Ƀ[Ŋ悤ȌvZƂɐ܂B

u񐔁v 0.0/0.0 Infinity-Infinity ̌ʂ`łȂ vZƂɐ܂B񐔂 NaNiNot a Numberjƕ\L܂B NaN ܂ތvZ͑S NaN ɂȂ܂B܂ NaN ͎܂߂āAǂȐ Ƃv܂B

[ +0.0 -0.0 ݂܂BA+0.0==-0.0 true łB

InfinityANaNA +0.0 -0.0 ܂񂾌vZʂ͑gݍ킹 蕡GłB̂ĺAȉ̃vOsČʂ mFĂiʂɂ‚āA^ԈႢ𔭌ꂽ m点肢܂jB

require "bigdecimal"

aa  = %w(1 -1 +0.0 -0.0 +Infinity -Infinity NaN)
ba  = %w(1 -1 +0.0 -0.0 +Infinity -Infinity NaN)
opa = %w(+ - * / <=> > >=  < == != <=)

for a in aa
  for b in ba
    for op in opa
      x = BigDecimal::new(a)
      y = BigDecimal::new(b)
      eval("ans= x #{op} y;print a,' ',op,' ',b,' ==> ',ans.to_s,\"\n\"")
    end
  end
end


\

BigDecimalŕ_͍\(Real)ŕ\܂B ̂ unsigned long ̔z(ȉ̍\̗vffrac)ŊǗ܂B TOIɂ́Aȉ̂悤ɂȂ܂B

<_> = 0.xxxxxxxxx*BASE**n

ŁAx͉\ABASE͊iPOiȂPOjAn͎w\ lłBBASE傫قǁA傫Ȑl\ł܂B‚܂Az̃TCY Ȃł܂BBASE͑傫قǓs悢킯łAfobÔ₷Ȃǂ lāA10000ɂȂĂ܂iBASEVpInit()֐ŎIɌvZ܂jB ́A32rbg̏ꍇłB64rbg̏ꍇ͂Ƒ傫ȒlɂȂ܂B cOȂA64rbgł̃eXg͂܂Ă܂iAꂽ ʂĂ΂肪łjB BASE10000̂Ƃ́Aȉ̉̔z(frac)̊evfɂ͍őłS i[܂B

_\(Real)͈ȉ̂悤ɂȂĂ܂B
  typedef struct {
     unsigned long MaxPrec; // ő吸x(frac[]̔zTCY)
     unsigned long Prec;    // x(frac[]̎gpTCY)
     short    sign;         // ȉ̂悤ɕ̏Ԃ`܂B
                            //  ==0 : NaN
                            //    1 : +0
                            //   -1 : -0
                            //    2 : ̒l
                            //   -2 : ̒l
                            //    3 : +Infinity
                            //   -3 : -Infinity
     unsigned short flag;   // e̐tbO
     int      exponent;     // w̒l(*BASE**exponent)
     unsigned long frac[1]; // ̔z(•)
  } Real;
Ⴆ 1234.56784321 Ƃ(BASE=10000Ȃ)
    0.1234 5678 4321*(10000)**1
ł frac[0]=1234Afrac[1]=5678Afrac[2]=4321A Prec=3Asign=2Aexponent=1 ƂȂ܂BMaxPrec Prec 傫΂‚ł܂܂Bflag gp@͎ɈˑēŎgp܂B

2i10i

BigDecimal <_> = 0.xxxxxxxxx*10**n Ƃ10i`Őlێ܂B AvZ@̕_̓\́A܂łȂ <_> = 0.bbbbbbbb*2**n Ƃ 2i`ʂł(x 0 9 ܂ŁAb 0 1 ̐)B BigDecimal Ȃ10i̓\`̗p̂ȉɐ܂B

10ĩbg

fobÔ₷
܂AvO쐬yłBfrac[0]=1234Afrac[1]=5678Afrac[2]=4321A exponent=1Asign=2 Ȃ琔l 1234.56784321 ł̂͌Βɕ܂B
10i\LꂽlȂmɓ\ɕϊł
Ⴆ΁Aȉ̂悤ȃvO͑S덷 vZ邱Ƃł܂Bȉ̗́AsɈ‚̐l Ăt@C file ̍vl߂̂łB
   file = File::open(....,"r")
   s = BigDecimal::new("0")
   while line = file.gets
      s = s + line
   end
̗2iłƌ덷荞މ”\܂B Ⴆ 0.1 2iŕ\ 0.1 = b1*2**(-1)+b1*2**(-2)+b3*2**(-3)+b4*2**(-4).... ƖɑĂ܂܂(b1=0,b2=0,b3=0,b4=1...)B bn(n=1,2,3,...) 2i\ 0 1 ̐łB]āAǂőł؂Kv܂B ŕϊ덷܂BAēx10i\LɂĈ悤 ꍇ͓K؂ȊۂߑiľܓjɂčĂ "0.1" ƕ\܂BA ł͐m 0.1 ł͂܂B
L͗Lłi‚܂莩łj
0.1 \邽߂̗̈͂‚̔zvfi frac[0]=1 jōς݂܂B zvf̐10il玩IɌł܂B́A•ϒ_Zł 厖ȂƂłBt 0.1 2i\Ƃɂ2i̗L‚ɂ̂ 0.1 ł͌ł܂B

10ĩfbg

͍܂ł̃bǵÂ܂܃fbgɂȂ܂B A10i2iɕϊ悤ȑ͕ϊ덷 𔺂ꍇ邱Ƃ͂ł܂B T̃Rs[^10i̓\ĂȂ̂ŁA BigDecimal 𗘗pČ덷̌vZꍇ́AvZx 𖳎ĂŌ܂ BigDecimal gpKv܂B

ŏ͉H

ŌvZƂɂ킴킴2igl͋ɂ߂Ă܂łB vZ@Ƀf[^͂ƂقƂǂ̏ꍇA 10iœ͂܂B̌ʁAdouble ̌vZ@ \͍ŏ덷Ăꍇ܂B BigDecimal ̓[U͂덷Ŏ荞ނƂł܂B fobO₷̂ƁAf[^ǂ݂ݎɌ덷Ȃ Ƃ̂ۂ̃bgłB

vZxɂ‚

c = a op b ƂvZ(op + - * /)Ƃ̓ ȉ̂悤ɂȂ܂B

PDZ(a ̗L)+(b ̗L)A Z(a ̍őL)+(b ̍őL)̍ő包iۂ́A]TāA 傫Ȃ܂j•ϐ c Vɐ܂B Z̏ꍇ́A덷oȂ̐x c 𐶐܂BႦ c = 0.1+0.1*10**(-100) ̂悤ȏꍇAc ̐x͂POOȏ̐x ‚悤ɂȂ܂B

QD c = a op b ̌vZs܂B

̂悤ɁAZƏZł c ͕Ku덷oȂv̐x Đ܂(BigDecimal.limit w肵Ȃꍇ)B Z(a ̍őL)+(b ̍őL)̍ő包 c ܂Ac = 1.0/3.0 ̂悤ȌvZŖ炩Ȃ悤ɁA c ̍ő吸x𒴂ƂŌvZł؂ꍇ܂B

ɂAc ̍ő吸x a b 傫Ȃ܂̂ c KvƂ [̈͑傫Ȃ邱ƂɒӂĉB

ӁFu+,-,*,/vł͌ʂ̐xiLjŎwł܂B xRg[ꍇ́Aȉ̃CX^X\bhgp܂B
  • add,sub,mult,div
  • ̃\bh͐擪(ō)̐̌wł܂B
     BigDecimal("2").div(3,12) # 2.0/3.0 => 0.6666666666 67E0
    
  • truncate,round,ceil,floor
  • ̃\bh͏_̑Έʒuw肵Č肵܂B
     BigDecimal("6.66666666666666").round(12) # => 0.6666666666 667E1
    

ŐxRg[ꍇ

Őx(L)Rg[ꍇ addAsubAmultAdiv ̃\bh gpł܂B ȉ̉~vZvÔ悤ɁA ߂錅͎Ŏw肷邱Ƃł܂B

#!/usr/local/bin/ruby

require "bigdecimal"
#
# Calculates 3.1415.... (the number of times that a circle's diameter
# will fit around the circle) using J. Machin's formula.
#
def big_pi(sig) # sig: Number of significant figures
  exp    = -sig
  pi     = BigDecimal::new("0")
  two    = BigDecimal::new("2")
  m25    = BigDecimal::new("-0.04")
  m57121 = BigDecimal::new("-57121")

  u = BigDecimal::new("1")
  k = BigDecimal::new("1")
  w = BigDecimal::new("1")
  t = BigDecimal::new("-80")
  while (u.nonzero? && u.exponent >= exp) 
    t   = t*m25
    u   = t.div(k,sig)
    pi  = pi + u
    k   = k+two
  end

  u = BigDecimal::new("1")
  k = BigDecimal::new("1")
  w = BigDecimal::new("1")
  t = BigDecimal::new("956")
  while (u.nonzero? && u.exponent >= exp )
    t   = t.div(m57121,sig)
    u   = t.div(k,sig)
    pi  = pi + u
    k   = k+two
  end
  pi
end

if $0 == __FILE__
  if ARGV.size == 1
    print "PI("+ARGV[0]+"):\n"
    p big_pi(ARGV[0].to_i)
  else
    print "TRY: ruby pi.rb 1000 \n"
  end
end


ΗY (E-Mail:<shigeo@tinyforest.gr.jp>) ================================================ FILE: ext/bigdecimal/depend ================================================ bigdecimal.o: bigdecimal.c bigdecimal.h $(hdrdir)/ruby.h ================================================ FILE: ext/bigdecimal/extconf.rb ================================================ require 'mkmf' base_fig = 0 src = "(BASE * (BASE+1)) / BASE == (BASE+1)" while try_static_assert(src, nil, "-DBASE=10#{'0'*base_fig}UL") base_fig += 1 end $defs << "-DBASE=1#{'0'*base_fig}UL" << "-DBASE_FIG=#{base_fig}" create_makefile('bigdecimal') ================================================ FILE: ext/bigdecimal/lib/bigdecimal/jacobian.rb ================================================ # # require 'bigdecimal/jacobian' # # Provides methods to compute the Jacobian matrix of a set of equations at a # point x. In the methods below: # # f is an Object which is used to compute the Jacobian matrix of the equations. # It must provide the following methods: # # f.values(x):: returns the values of all functions at x # # f.zero:: returns 0.0 # f.one:: returns 1.0 # f.two:: returns 1.0 # f.ten:: returns 10.0 # # f.eps:: returns the convergence criterion (epsilon value) used to determine whether two values are considered equal. If |a-b| < epsilon, the two values are considered equal. # # x is the point at which to compute the Jacobian. # # fx is f.values(x). # module Jacobian #-- def isEqual(a,b,zero=0.0,e=1.0e-8) aa = a.abs bb = b.abs if aa == zero && bb == zero then true else if ((a-b)/(aa+bb)).abs < e then true else false end end end #++ # Computes the derivative of f[i] at x[i]. # fx is the value of f at x. def dfdxi(f,fx,x,i) nRetry = 0 n = x.size xSave = x[i] ok = 0 ratio = f.ten*f.ten*f.ten dx = x[i].abs/ratio dx = fx[i].abs/ratio if isEqual(dx,f.zero,f.zero,f.eps) dx = f.one/f.ten if isEqual(dx,f.zero,f.zero,f.eps) until ok>0 do s = f.zero deriv = [] if(nRetry>100) then raize "Singular Jacobian matrix. No change at x[" + i.to_s + "]" end dx = dx*f.two x[i] += dx fxNew = f.values(x) for j in 0...n do if !isEqual(fxNew[j],fx[j],f.zero,f.eps) then ok += 1 deriv <<= (fxNew[j]-fx[j])/dx else deriv <<= f.zero end end x[i] = xSave end deriv end # Computes the Jacobian of f at x. fx is the value of f at x. def jacobian(f,fx,x) n = x.size dfdx = Array::new(n*n) for i in 0...n do df = dfdxi(f,fx,x,i) for j in 0...n do dfdx[j*n+i] = df[j] end end dfdx end end ================================================ FILE: ext/bigdecimal/lib/bigdecimal/ludcmp.rb ================================================ # # Solves a*x = b for x, using LU decomposition. # module LUSolve # Performs LU decomposition of the n by n matrix a. def ludecomp(a,n,zero=0,one=1) prec = BigDecimal.limit(nil) ps = [] scales = [] for i in 0...n do # pick up largest(abs. val.) element in each row. ps <<= i nrmrow = zero ixn = i*n for j in 0...n do biggst = a[ixn+j].abs nrmrow = biggst if biggst>nrmrow end if nrmrow>zero then scales <<= one.div(nrmrow,prec) else raise "Singular matrix" end end n1 = n - 1 for k in 0...n1 do # Gaussian elimination with partial pivoting. biggst = zero; for i in k...n do size = a[ps[i]*n+k].abs*scales[ps[i]] if size>biggst then biggst = size pividx = i end end raise "Singular matrix" if biggst<=zero if pividx!=k then j = ps[k] ps[k] = ps[pividx] ps[pividx] = j end pivot = a[ps[k]*n+k] for i in (k+1)...n do psin = ps[i]*n a[psin+k] = mult = a[psin+k].div(pivot,prec) if mult!=zero then pskn = ps[k]*n for j in (k+1)...n do a[psin+j] -= mult.mult(a[pskn+j],prec) end end end end raise "Singular matrix" if a[ps[n1]*n+n1] == zero ps end # Solves a*x = b for x, using LU decomposition. # # a is a matrix, b is a constant vector, x is the solution vector. # # ps is the pivot, a vector which indicates the permutation of rows performed # during LU decomposition. def lusolve(a,b,ps,zero=0.0) prec = BigDecimal.limit(nil) n = ps.size x = [] for i in 0...n do dot = zero psin = ps[i]*n for j in 0...i do dot = a[psin+j].mult(x[j],prec) + dot end x <<= b[ps[i]] - dot end (n-1).downto(0) do |i| dot = zero psin = ps[i]*n for j in (i+1)...n do dot = a[psin+j].mult(x[j],prec) + dot end x[i] = (x[i]-dot).div(a[psin+i],prec) end x end end ================================================ FILE: ext/bigdecimal/lib/bigdecimal/math.rb ================================================ # #-- # Contents: # sqrt(x, prec) # sin (x, prec) # cos (x, prec) # atan(x, prec) Note: |x|<1, x=0.9999 may not converge. # exp (x, prec) # log (x, prec) # PI (prec) # E (prec) == exp(1.0,prec) # # where: # x ... BigDecimal number to be computed. # |x| must be small enough to get convergence. # prec ... Number of digits to be obtained. #++ # # Provides mathematical functions. # # Example: # # require "bigdecimal" # require "bigdecimal/math" # # include BigMath # # a = BigDecimal((PI(100)/2).to_s) # puts sin(a,100) # -> 0.10000000000000000000......E1 # module BigMath # Computes the square root of x to the specified number of digits of # precision. # # BigDecimal.new('2').sqrt(16).to_s # -> "0.14142135623730950488016887242096975E1" # def sqrt(x,prec) x.sqrt(prec) end # Computes the sine of x to the specified number of digits of precision. # # If x is infinite or NaN, returns NaN. def sin(x, prec) raise ArgumentError, "Zero or negative precision for sin" if prec <= 0 return BigDecimal("NaN") if x.infinite? || x.nan? n = prec + BigDecimal.double_fig one = BigDecimal("1") two = BigDecimal("2") x1 = x x2 = x.mult(x,n) sign = 1 y = x d = y i = one z = one while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig sign = -sign x1 = x2.mult(x1,n) i += two z *= (i-one) * i d = sign * x1.div(z,m) y += d end y end # Computes the cosine of x to the specified number of digits of precision. # # If x is infinite or NaN, returns NaN. def cos(x, prec) raise ArgumentError, "Zero or negative precision for cos" if prec <= 0 return BigDecimal("NaN") if x.infinite? || x.nan? n = prec + BigDecimal.double_fig one = BigDecimal("1") two = BigDecimal("2") x1 = one x2 = x.mult(x,n) sign = 1 y = one d = y i = BigDecimal("0") z = one while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig sign = -sign x1 = x2.mult(x1,n) i += two z *= (i-one) * i d = sign * x1.div(z,m) y += d end y end # Computes the arctangent of x to the specified number of digits of precision. # # If x is infinite or NaN, returns NaN. # Raises an argument error if x > 1. def atan(x, prec) raise ArgumentError, "Zero or negative precision for atan" if prec <= 0 return BigDecimal("NaN") if x.infinite? || x.nan? raise ArgumentError, "x.abs must be less than 1.0" if x.abs>=1 n = prec + BigDecimal.double_fig y = x d = y t = x r = BigDecimal("3") x2 = x.mult(x,n) while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig t = -t.mult(x2,n) d = t.div(r,m) y += d r += 2 end y end # Computes the value of e (the base of natural logarithms) raised to the # power of x, to the specified number of digits of precision. # # If x is infinite or NaN, returns NaN. # # BigMath::exp(BigDecimal.new('1'), 10).to_s # -> "0.271828182845904523536028752390026306410273E1" def exp(x, prec) raise ArgumentError, "Zero or negative precision for exp" if prec <= 0 return BigDecimal("NaN") if x.infinite? || x.nan? n = prec + BigDecimal.double_fig one = BigDecimal("1") x1 = one y = one d = y z = one i = 0 while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig x1 = x1.mult(x,n) i += 1 z *= i d = x1.div(z,m) y += d end y end # Computes the natural logarithm of x to the specified number of digits # of precision. # # Returns x if x is infinite or NaN. # def log(x, prec) raise ArgumentError, "Zero or negative argument for log" if x <= 0 || prec <= 0 return x if x.infinite? || x.nan? one = BigDecimal("1") two = BigDecimal("2") n = prec + BigDecimal.double_fig x = (x - one).div(x + one,n) x2 = x.mult(x,n) y = x d = y i = one while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig x = x2.mult(x,n) i += two d = x.div(i,m) y += d end y*two end # Computes the value of pi to the specified number of digits of precision. def PI(prec) raise ArgumentError, "Zero or negative argument for PI" if prec <= 0 n = prec + BigDecimal.double_fig zero = BigDecimal("0") one = BigDecimal("1") two = BigDecimal("2") m25 = BigDecimal("-0.04") m57121 = BigDecimal("-57121") pi = zero d = one k = one w = one t = BigDecimal("-80") while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig t = t*m25 d = t.div(k,m) k = k+two pi = pi + d end d = one k = one w = one t = BigDecimal("956") while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig t = t.div(m57121,n) d = t.div(k,m) pi = pi + d k = k+two end pi end # Computes e (the base of natural logarithms) to the specified number of # digits of precision. def E(prec) raise ArgumentError, "Zero or negative precision for E" if prec <= 0 n = prec + BigDecimal.double_fig one = BigDecimal("1") y = one d = y z = one i = 0 while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig i += 1 z *= i d = one.div(z,m) y += d end y end end ================================================ FILE: ext/bigdecimal/lib/bigdecimal/newton.rb ================================================ # # newton.rb # # Solves the nonlinear algebraic equation system f = 0 by Newton's method. # This program is not dependent on BigDecimal. # # To call: # n = nlsolve(f,x) # where n is the number of iterations required, # x is the initial value vector # f is an Object which is used to compute the values of the equations to be solved. # It must provide the following methods: # # f.values(x):: returns the values of all functions at x # # f.zero:: returns 0.0 # f.one:: returns 1.0 # f.two:: returns 1.0 # f.ten:: returns 10.0 # # f.eps:: returns the convergence criterion (epsilon value) used to determine whether two values are considered equal. If |a-b| < epsilon, the two values are considered equal. # # On exit, x is the solution vector. # require "bigdecimal/ludcmp" require "bigdecimal/jacobian" module Newton include LUSolve include Jacobian def norm(fv,zero=0.0) s = zero n = fv.size for i in 0...n do s += fv[i]*fv[i] end s end def nlsolve(f,x) nRetry = 0 n = x.size f0 = f.values(x) zero = f.zero one = f.one two = f.two p5 = one/two d = norm(f0,zero) minfact = f.ten*f.ten*f.ten minfact = one/minfact e = f.eps while d >= e do nRetry += 1 # Not yet converged. => Compute Jacobian matrix dfdx = jacobian(f,f0,x) # Solve dfdx*dx = -f0 to estimate dx dx = lusolve(dfdx,f0,ludecomp(dfdx,n,zero,one),zero) fact = two xs = x.dup begin fact *= p5 if fact < minfact then raise "Failed to reduce function values." end for i in 0...n do x[i] = xs[i] - dx[i]*fact end f0 = f.values(x) dn = norm(f0,zero) end while(dn>=d) d = dn end nRetry end end ================================================ FILE: ext/bigdecimal/lib/bigdecimal/util.rb ================================================ # # BigDecimal utility library. # # To use these functions, require 'bigdecimal/util' # # The following methods are provided to convert other types to BigDecimals: # # String#to_d -> BigDecimal # Float#to_d -> BigDecimal # Rational#to_d -> BigDecimal # # The following method is provided to convert BigDecimals to other types: # # BigDecimal#to_r -> Rational # # ---------------------------------------------------------------------- # class Float < Numeric def to_d BigDecimal(self.to_s) end end class String def to_d BigDecimal(self) end end class BigDecimal < Numeric # Converts a BigDecimal to a String of the form "nnnnnn.mmm". # This method is deprecated; use BigDecimal#to_s("F") instead. def to_digits if self.nan? || self.infinite? || self.zero? self.to_s else i = self.to_i.to_s s,f,y,z = self.frac.split i + "." + ("0"*(-z)) + f end end # Converts a BigDecimal to a Rational. def to_r sign,digits,base,power = self.split numerator = sign*digits.to_i denomi_power = power - digits.size # base is always 10 if denomi_power < 0 Rational(numerator,base ** (-denomi_power)) else Rational(numerator * (base ** denomi_power),1) end end end class Rational < Numeric # Converts a Rational to a BigDecimal def to_d(nFig=0) num = self.numerator.to_s if nFig<=0 nFig = BigDecimal.double_fig*2+1 end BigDecimal.new(num).div(self.denominator,nFig) end end ================================================ FILE: ext/bigdecimal/sample/linear.rb ================================================ #!/usr/local/bin/ruby # # linear.rb # # Solves linear equation system(A*x = b) by LU decomposition method. # where A is a coefficient matrix,x is an answer vector,b is a constant vector. # # USAGE: # ruby linear.rb [input file solved] # require "bigdecimal" require "bigdecimal/ludcmp" # # NOTE: # Change following BigDecimal::limit() if needed. BigDecimal::limit(100) # include LUSolve def rd_order(na) printf("Number of equations ?") if(na <= 0) n = ARGF.gets().to_i end na = ARGV.size zero = BigDecimal::new("0.0") one = BigDecimal::new("1.0") while (n=rd_order(na))>0 a = [] as= [] b = [] if na <= 0 # Read data from console. printf("\nEnter coefficient matrix element A[i,j]\n"); for i in 0...n do for j in 0...n do printf("A[%d,%d]? ",i,j); s = ARGF.gets a << BigDecimal::new(s); as << BigDecimal::new(s); end printf("Contatant vector element b[%d] ? ",i); b << BigDecimal::new(ARGF.gets); end else # Read data from specified file. printf("Coefficient matrix and constant vector.\n"); for i in 0...n do s = ARGF.gets printf("%d) %s",i,s) s = s.split for j in 0...n do a << BigDecimal::new(s[j]); as << BigDecimal::new(s[j]); end b << BigDecimal::new(s[n]); end end x = lusolve(a,b,ludecomp(a,n,zero,one),zero) printf("Answer(x[i] & (A*x-b)[i]) follows\n") for i in 0...n do printf("x[%d]=%s ",i,x[i].to_s) s = zero for j in 0...n do s = s + as[i*n+j]*x[j] end printf(" & %s\n",(s-b[i]).to_s) end end ================================================ FILE: ext/bigdecimal/sample/nlsolve.rb ================================================ #!/usr/local/bin/ruby # # nlsolve.rb # An example for solving nonlinear algebraic equation system. # require "bigdecimal" require "bigdecimal/newton" include Newton class Function def initialize() @zero = BigDecimal::new("0.0") @one = BigDecimal::new("1.0") @two = BigDecimal::new("2.0") @ten = BigDecimal::new("10.0") @eps = BigDecimal::new("1.0e-16") end def zero;@zero;end def one ;@one ;end def two ;@two ;end def ten ;@ten ;end def eps ;@eps ;end def values(x) # <= defines functions solved f = [] f1 = x[0]*x[0] + x[1]*x[1] - @two # f1 = x**2 + y**2 - 2 => 0 f2 = x[0] - x[1] # f2 = x - y => 0 f <<= f1 f <<= f2 f end end f = BigDecimal::limit(100) f = Function.new x = [f.zero,f.zero] # Initial values n = nlsolve(f,x) p x ================================================ FILE: ext/bigdecimal/sample/pi.rb ================================================ #!/usr/local/bin/ruby # # pi.rb # # Calculates 3.1415.... (the number of times that a circle's diameter # will fit around the circle) using J. Machin's formula. # require "bigdecimal" require "bigdecimal/math.rb" include BigMath if ARGV.size == 1 print "PI("+ARGV[0]+"):\n" p PI(ARGV[0].to_i) else print "TRY: ruby pi.rb 1000 \n" end ================================================ FILE: ext/curses/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/curses/curses.c ================================================ /* -*- C -*- * $Id$ * * ext/curses/curses.c * * by MAEDA Shugo (ender@pic-internet.or.jp) * modified by Yukihiro Matsumoto (matz@netlab.co.jp), * Toki Yoshinori, * Hitoshi Takahashi, * and Takaaki Tateishi (ttate@kt.jaist.ac.jp) * * maintainers: * - Takaaki Tateishi (ttate@kt.jaist.ac.jp) */ #include "ruby.h" #include "rubyio.h" #if defined(HAVE_NCURSES_H) # include #elif defined(HAVE_NCURSES_CURSES_H) # include #elif defined(HAVE_CURSES_COLR_CURSES_H) # ifdef HAVE_STDARG_PROTOTYPES # include # else # include # endif # include #else # include # if defined(__bsdi__) || defined(__NetBSD__) || defined(__APPLE__) # if !defined(_maxx) # define _maxx maxx # endif # if !defined(_maxy) # define _maxy maxy # endif # if !defined(_begx) # define _begx begx # endif # if !defined(_begy) # define _begy begy # endif # endif #endif #ifdef HAVE_INIT_COLOR # define USE_COLOR 1 #endif /* supports only ncurses mouse routines */ #ifdef NCURSES_MOUSE_VERSION # define USE_MOUSE 1 #endif #define NUM2CH NUM2LONG #define CH2FIX LONG2FIX static VALUE mCurses; static VALUE mKey; static VALUE cWindow; #ifdef USE_MOUSE static VALUE cMouseEvent; #endif static VALUE rb_stdscr; struct windata { WINDOW *window; }; #define CHECK(c) c static VALUE window_attroff(); static VALUE window_attron(); static VALUE window_attrset(); static void no_window() { rb_raise(rb_eRuntimeError, "already closed window"); } #define GetWINDOW(obj, winp) do {\ if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)\ rb_raise(rb_eSecurityError, "Insecure: operation on untainted window");\ Data_Get_Struct(obj, struct windata, winp);\ if (winp->window == 0) no_window();\ } while (0) static void free_window(winp) struct windata *winp; { if (winp->window && winp->window != stdscr) delwin(winp->window); winp->window = 0; free(winp); } static VALUE prep_window(class, window) VALUE class; WINDOW *window; { VALUE obj; struct windata *winp; if (window == NULL) { rb_raise(rb_eRuntimeError, "failed to create window"); } obj = rb_obj_alloc(class); Data_Get_Struct(obj, struct windata, winp); winp->window = window; return obj; } /*-------------------------- module Curses --------------------------*/ /* def init_screen */ static VALUE curses_init_screen() { rb_secure(4); if (rb_stdscr) return rb_stdscr; initscr(); if (stdscr == 0) { rb_raise(rb_eRuntimeError, "can't initialize curses"); } clear(); rb_stdscr = prep_window(cWindow, stdscr); return rb_stdscr; } /* def stdscr */ #define curses_stdscr curses_init_screen /* def close_screen */ static VALUE curses_close_screen() { curses_stdscr(); #ifdef HAVE_ISENDWIN if (!isendwin()) #endif endwin(); rb_stdscr = 0; return Qnil; } static void curses_finalize(VALUE dummy) { if (stdscr #ifdef HAVE_ISENDWIN && !isendwin() #endif ) endwin(); rb_stdscr = 0; rb_gc_unregister_address(&rb_stdscr); } /* def closed? */ static VALUE curses_closed() { #ifdef HAVE_ISENDWIN curses_stdscr(); if (isendwin()) { return Qtrue; } return Qfalse; #else rb_notimplement(); #endif } /* def clear */ static VALUE curses_clear(obj) VALUE obj; { curses_stdscr(); wclear(stdscr); return Qnil; } /* def clrtoeol */ static VALUE curses_clrtoeol() { curses_stdscr(); clrtoeol(); return Qnil; } /* def refresh */ static VALUE curses_refresh(obj) VALUE obj; { curses_stdscr(); refresh(); return Qnil; } /* def doupdate */ static VALUE curses_doupdate(obj) VALUE obj; { curses_stdscr(); #ifdef HAVE_DOUPDATE doupdate(); #else refresh(); #endif return Qnil; } /* def echo */ static VALUE curses_echo(obj) VALUE obj; { curses_stdscr(); echo(); return Qnil; } /* def noecho */ static VALUE curses_noecho(obj) VALUE obj; { curses_stdscr(); noecho(); return Qnil; } /* def raw */ static VALUE curses_raw(obj) VALUE obj; { curses_stdscr(); raw(); return Qnil; } /* def noraw */ static VALUE curses_noraw(obj) VALUE obj; { curses_stdscr(); noraw(); return Qnil; } /* def cbreak */ static VALUE curses_cbreak(obj) VALUE obj; { curses_stdscr(); cbreak(); return Qnil; } /* def nocbreak */ static VALUE curses_nocbreak(obj) VALUE obj; { curses_stdscr(); nocbreak(); return Qnil; } /* def nl */ static VALUE curses_nl(obj) VALUE obj; { curses_stdscr(); nl(); return Qnil; } /* def nonl */ static VALUE curses_nonl(obj) VALUE obj; { curses_stdscr(); nonl(); return Qnil; } /* def beep */ static VALUE curses_beep(obj) VALUE obj; { #ifdef HAVE_BEEP curses_stdscr(); beep(); #endif return Qnil; } /* def flash */ static VALUE curses_flash(obj) VALUE obj; { #ifdef HAVE_FLASH curses_stdscr(); flash(); #endif return Qnil; } /* def ungetch */ static VALUE curses_ungetch(obj, ch) VALUE obj; VALUE ch; { #ifdef HAVE_UNGETCH curses_stdscr(); ungetch(NUM2INT(ch)); #else rb_notimplement(); #endif return Qnil; } /* def setpos(y, x) */ static VALUE curses_setpos(obj, y, x) VALUE obj; VALUE y; VALUE x; { curses_stdscr(); move(NUM2INT(y), NUM2INT(x)); return Qnil; } /* def standout */ static VALUE curses_standout(obj) VALUE obj; { curses_stdscr(); standout(); return Qnil; } /* def standend */ static VALUE curses_standend(obj) VALUE obj; { curses_stdscr(); standend(); return Qnil; } /* def inch */ static VALUE curses_inch(obj) VALUE obj; { curses_stdscr(); return CH2FIX(inch()); } /* def addch(ch) */ static VALUE curses_addch(obj, ch) VALUE obj; VALUE ch; { curses_stdscr(); addch(NUM2CH(ch)); return Qnil; } /* def insch(ch) */ static VALUE curses_insch(obj, ch) VALUE obj; VALUE ch; { curses_stdscr(); insch(NUM2CH(ch)); return Qnil; } /* def addstr(str) */ static VALUE curses_addstr(obj, str) VALUE obj; VALUE str; { curses_stdscr(); if (!NIL_P(str)) { addstr(STR2CSTR(str)); } return Qnil; } /* def getch */ static VALUE curses_getch(obj) VALUE obj; { rb_read_check(stdin); curses_stdscr(); return UINT2NUM(getch()); } /* def getstr */ static VALUE curses_getstr(obj) VALUE obj; { char rtn[1024]; /* This should be big enough.. I hope */ curses_stdscr(); rb_read_check(stdin); #if defined(HAVE_GETNSTR) getnstr(rtn,1023); #else getstr(rtn); #endif return rb_tainted_str_new2(rtn); } /* def delch */ static VALUE curses_delch(obj) VALUE obj; { curses_stdscr(); delch(); return Qnil; } /* def delelteln */ static VALUE curses_deleteln(obj) VALUE obj; { curses_stdscr(); #if defined(HAVE_DELETELN) || defined(deleteln) deleteln(); #endif return Qnil; } /* def insertln */ static VALUE curses_insertln(obj) VALUE obj; { curses_stdscr(); #if defined(HAVE_INSERTLN) || defined(insertln) insertln(); #endif return Qnil; } /* def keyname */ static VALUE curses_keyname(obj, c) VALUE obj; VALUE c; { #ifdef HAVE_KEYNAME const char *name; curses_stdscr(); name = keyname(NUM2INT(c)); if (name) { return rb_str_new2(name); } else { return Qnil; } #else return Qnil; #endif } static VALUE curses_lines() { return INT2FIX(LINES); } static VALUE curses_cols() { return INT2FIX(COLS); } static VALUE curses_curs_set(VALUE obj, VALUE visibility) { #ifdef HAVE_CURS_SET int n; curses_stdscr(); return (n = curs_set(NUM2INT(visibility)) != ERR) ? INT2FIX(n) : Qnil; #else return Qnil; #endif } static VALUE curses_scrl(VALUE obj, VALUE n) { /* may have to raise exception on ERR */ #ifdef HAVE_SCRL curses_stdscr(); return (scrl(NUM2INT(n)) == OK) ? Qtrue : Qfalse; #else return Qfalse; #endif } static VALUE curses_setscrreg(VALUE obj, VALUE top, VALUE bottom) { /* may have to raise exception on ERR */ #ifdef HAVE_SETSCRREG curses_stdscr(); return (setscrreg(NUM2INT(top), NUM2INT(bottom)) == OK) ? Qtrue : Qfalse; #else return Qfalse; #endif } static VALUE curses_attroff(VALUE obj, VALUE attrs) { curses_stdscr(); return window_attroff(rb_stdscr,attrs); /* return INT2FIX(attroff(NUM2INT(attrs))); */ } static VALUE curses_attron(VALUE obj, VALUE attrs) { curses_stdscr(); return window_attron(rb_stdscr,attrs); /* return INT2FIX(attroff(NUM2INT(attrs))); */ } static VALUE curses_attrset(VALUE obj, VALUE attrs) { curses_stdscr(); return window_attrset(rb_stdscr,attrs); /* return INT2FIX(attroff(NUM2INT(attrs))); */ } static VALUE curses_bkgdset(VALUE obj, VALUE ch) { #ifdef HAVE_BKGDSET curses_stdscr(); bkgdset(NUM2CH(ch)); #endif return Qnil; } static VALUE curses_bkgd(VALUE obj, VALUE ch) { #ifdef HAVE_BKGD curses_stdscr(); return (bkgd(NUM2CH(ch)) == OK) ? Qtrue : Qfalse; #else return Qfalse; #endif } static VALUE curses_resizeterm(VALUE obj, VALUE lin, VALUE col) { #if defined(HAVE_RESIZETERM) curses_stdscr(); return (resizeterm(NUM2INT(lin),NUM2INT(col)) == OK) ? Qtrue : Qfalse; #else return Qnil; #endif } #ifdef USE_COLOR static VALUE curses_start_color(VALUE obj) { /* may have to raise exception on ERR */ curses_stdscr(); return (start_color() == OK) ? Qtrue : Qfalse; } static VALUE curses_init_pair(VALUE obj, VALUE pair, VALUE f, VALUE b) { /* may have to raise exception on ERR */ curses_stdscr(); return (init_pair(NUM2INT(pair),NUM2INT(f),NUM2INT(b)) == OK) ? Qtrue : Qfalse; } static VALUE curses_init_color(VALUE obj, VALUE color, VALUE r, VALUE g, VALUE b) { /* may have to raise exception on ERR */ curses_stdscr(); return (init_color(NUM2INT(color),NUM2INT(r), NUM2INT(g),NUM2INT(b)) == OK) ? Qtrue : Qfalse; } static VALUE curses_has_colors(VALUE obj) { curses_stdscr(); return has_colors() ? Qtrue : Qfalse; } static VALUE curses_can_change_color(VALUE obj) { curses_stdscr(); return can_change_color() ? Qtrue : Qfalse; } static VALUE curses_color_content(VALUE obj, VALUE color) { short r,g,b; curses_stdscr(); color_content(NUM2INT(color),&r,&g,&b); return rb_ary_new3(3,INT2FIX(r),INT2FIX(g),INT2FIX(b)); } static VALUE curses_pair_content(VALUE obj, VALUE pair) { short f,b; curses_stdscr(); pair_content(NUM2INT(pair),&f,&b); return rb_ary_new3(2,INT2FIX(f),INT2FIX(b)); } static VALUE curses_color_pair(VALUE obj, VALUE attrs) { return INT2FIX(COLOR_PAIR(NUM2INT(attrs))); } static VALUE curses_pair_number(VALUE obj, VALUE attrs) { curses_stdscr(); return INT2FIX(PAIR_NUMBER(NUM2INT(attrs))); } #endif /* USE_COLOR */ #ifdef USE_MOUSE struct mousedata { MEVENT *mevent; }; static void no_mevent() { rb_raise(rb_eRuntimeError, "no such mouse event"); } #define GetMOUSE(obj, data) do {\ if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)\ rb_raise(rb_eSecurityError, "Insecure: operation on untainted mouse");\ Data_Get_Struct(obj, struct mousedata, data);\ if (data->mevent == 0) no_mevent();\ } while (0) static void curses_mousedata_free(struct mousedata *mdata) { if (mdata->mevent) free(mdata->mevent); } static VALUE curses_getmouse(VALUE obj) { struct mousedata *mdata; VALUE val; curses_stdscr(); val = Data_Make_Struct(cMouseEvent,struct mousedata, 0,curses_mousedata_free,mdata); mdata->mevent = (MEVENT*)xmalloc(sizeof(MEVENT)); return (getmouse(mdata->mevent) == OK) ? val : Qnil; } static VALUE curses_ungetmouse(VALUE obj, VALUE mevent) { struct mousedata *mdata; curses_stdscr(); GetMOUSE(mevent,mdata); return (ungetmouse(mdata->mevent) == OK) ? Qtrue : Qfalse; } static VALUE curses_mouseinterval(VALUE obj, VALUE interval) { curses_stdscr(); return mouseinterval(NUM2INT(interval)) ? Qtrue : Qfalse; } static VALUE curses_mousemask(VALUE obj, VALUE mask) { curses_stdscr(); return INT2NUM(mousemask(NUM2UINT(mask),NULL)); } #define DEFINE_MOUSE_GET_MEMBER(func_name,mem) \ static VALUE func_name (VALUE mouse) \ { \ struct mousedata *mdata; \ GetMOUSE(mouse, mdata); \ return (UINT2NUM(mdata->mevent -> mem)); \ } DEFINE_MOUSE_GET_MEMBER(curs_mouse_id, id) DEFINE_MOUSE_GET_MEMBER(curs_mouse_x, x) DEFINE_MOUSE_GET_MEMBER(curs_mouse_y, y) DEFINE_MOUSE_GET_MEMBER(curs_mouse_z, z) DEFINE_MOUSE_GET_MEMBER(curs_mouse_bstate, bstate) #undef define_curs_mouse_member #endif /* USE_MOUSE */ static VALUE curses_timeout(VALUE obj, VALUE delay) { #ifdef HAVE_TIMEOUT curses_stdscr(); timeout(NUM2INT(delay)); return Qnil; #else rb_notimplement(); #endif } static VALUE curses_def_prog_mode(VALUE obj) { #ifdef HAVE_DEF_PROG_MODE curses_stdscr(); return def_prog_mode() == OK ? Qtrue : Qfalse; #else rb_notimplement(); #endif } static VALUE curses_reset_prog_mode(VALUE obj) { #ifdef HAVE_RESET_PROG_MODE curses_stdscr(); return reset_prog_mode() == OK ? Qtrue : Qfalse; #else rb_notimplement(); #endif } /*-------------------------- class Window --------------------------*/ /* def self.allocate */ static VALUE window_s_allocate(VALUE class) { struct windata *winp; return Data_Make_Struct(class, struct windata, 0, free_window, winp); } /* def initialize(h, w, top, left) */ static VALUE window_initialize(obj, h, w, top, left) VALUE obj; VALUE h; VALUE w; VALUE top; VALUE left; { struct windata *winp; WINDOW *window; rb_secure(4); curses_init_screen(); Data_Get_Struct(obj, struct windata, winp); if (winp->window) delwin(winp->window); window = newwin(NUM2INT(h), NUM2INT(w), NUM2INT(top), NUM2INT(left)); wclear(window); winp->window = window; return obj; } /* def subwin(height, width, top, left) */ static VALUE window_subwin(obj, height, width, top, left) VALUE obj; VALUE height; VALUE width; VALUE top; VALUE left; { struct windata *winp; WINDOW *window; VALUE win; int h, w, t, l; h = NUM2INT(height); w = NUM2INT(width); t = NUM2INT(top); l = NUM2INT(left); GetWINDOW(obj, winp); window = subwin(winp->window, h, w, t, l); win = prep_window(rb_obj_class(obj), window); return win; } /* def close */ static VALUE window_close(obj) VALUE obj; { struct windata *winp; GetWINDOW(obj, winp); delwin(winp->window); winp->window = 0; return Qnil; } /* def clear */ static VALUE window_clear(obj) VALUE obj; { struct windata *winp; GetWINDOW(obj, winp); wclear(winp->window); return Qnil; } /* def clrtoeol */ static VALUE window_clrtoeol(obj) VALUE obj; { struct windata *winp; GetWINDOW(obj, winp); wclrtoeol(winp->window); return Qnil; } /* def refresh */ static VALUE window_refresh(obj) VALUE obj; { struct windata *winp; GetWINDOW(obj, winp); wrefresh(winp->window); return Qnil; } /* def noutrefresh */ static VALUE window_noutrefresh(obj) VALUE obj; { struct windata *winp; GetWINDOW(obj, winp); #ifdef HAVE_DOUPDATE wnoutrefresh(winp->window); #else wrefresh(winp->window); #endif return Qnil; } /* def move(y, x) */ static VALUE window_move(obj, y, x) VALUE obj; VALUE y; VALUE x; { struct windata *winp; GetWINDOW(obj, winp); mvwin(winp->window, NUM2INT(y), NUM2INT(x)); return Qnil; } /* def setpos(y, x) */ static VALUE window_setpos(obj, y, x) VALUE obj; VALUE y; VALUE x; { struct windata *winp; GetWINDOW(obj, winp); wmove(winp->window, NUM2INT(y), NUM2INT(x)); return Qnil; } /* def cury */ static VALUE window_cury(obj) VALUE obj; { struct windata *winp; int x, y; GetWINDOW(obj, winp); getyx(winp->window, y, x); return INT2FIX(y); } /* def curx */ static VALUE window_curx(obj) VALUE obj; { struct windata *winp; int x, y; GetWINDOW(obj, winp); getyx(winp->window, y, x); return INT2FIX(x); } /* def maxy */ static VALUE window_maxy(obj) VALUE obj; { struct windata *winp; GetWINDOW(obj, winp); #if defined(getmaxy) return INT2FIX(getmaxy(winp->window)); #elif defined(getmaxyx) { int x, y; getmaxyx(winp->window, y, x); return INT2FIX(y); } #else return INT2FIX(winp->window->_maxy+1); #endif } /* def maxx */ static VALUE window_maxx(obj) VALUE obj; { struct windata *winp; GetWINDOW(obj, winp); #if defined(getmaxx) return INT2FIX(getmaxx(winp->window)); #elif defined(getmaxyx) { int x, y; getmaxyx(winp->window, y, x); return INT2FIX(x); } #else return INT2FIX(winp->window->_maxx+1); #endif } /* def begy */ static VALUE window_begy(obj) VALUE obj; { struct windata *winp; int x, y; GetWINDOW(obj, winp); #ifdef getbegyx getbegyx(winp->window, y, x); return INT2FIX(y); #else return INT2FIX(winp->window->_begy); #endif } /* def begx */ static VALUE window_begx(obj) VALUE obj; { struct windata *winp; int x, y; GetWINDOW(obj, winp); #ifdef getbegyx getbegyx(winp->window, y, x); return INT2FIX(x); #else return INT2FIX(winp->window->_begx); #endif } /* def box(vert, hor) */ static VALUE window_box(argc, argv, self) int argc; VALUE argv[], self; { struct windata *winp; VALUE vert, hor, corn; rb_scan_args(argc, argv, "21", &vert, &hor, &corn); GetWINDOW(self, winp); box(winp->window, NUM2CH(vert), NUM2CH(hor)); if (!NIL_P(corn)) { int cur_x, cur_y, x, y; chtype c; c = NUM2CH(corn); getyx(winp->window, cur_y, cur_x); x = NUM2INT(window_maxx(self)) - 1; y = NUM2INT(window_maxy(self)) - 1; wmove(winp->window, 0, 0); waddch(winp->window, c); wmove(winp->window, y, 0); waddch(winp->window, c); wmove(winp->window, y, x); waddch(winp->window, c); wmove(winp->window, 0, x); waddch(winp->window, c); wmove(winp->window, cur_y, cur_x); } return Qnil; } /* def standout */ static VALUE window_standout(obj) VALUE obj; { struct windata *winp; GetWINDOW(obj, winp); wstandout(winp->window); return Qnil; } /* def standend */ static VALUE window_standend(obj) VALUE obj; { struct windata *winp; GetWINDOW(obj, winp); wstandend(winp->window); return Qnil; } /* def inch */ static VALUE window_inch(obj) VALUE obj; { struct windata *winp; GetWINDOW(obj, winp); return CH2FIX(winch(winp->window)); } /* def addch(ch) */ static VALUE window_addch(obj, ch) VALUE obj; VALUE ch; { struct windata *winp; GetWINDOW(obj, winp); waddch(winp->window, NUM2CH(ch)); return Qnil; } /* def insch(ch) */ static VALUE window_insch(obj, ch) VALUE obj; VALUE ch; { struct windata *winp; GetWINDOW(obj, winp); winsch(winp->window, NUM2CH(ch)); return Qnil; } /* def addstr(str) */ static VALUE window_addstr(obj, str) VALUE obj; VALUE str; { if (!NIL_P(str)) { struct windata *winp; GetWINDOW(obj, winp); waddstr(winp->window, STR2CSTR(str)); } return Qnil; } /* def <<(str) */ static VALUE window_addstr2(obj, str) VALUE obj; VALUE str; { window_addstr(obj, str); return obj; } /* def getch */ static VALUE window_getch(obj) VALUE obj; { struct windata *winp; rb_read_check(stdin); GetWINDOW(obj, winp); return UINT2NUM(wgetch(winp->window)); } /* def getstr */ static VALUE window_getstr(obj) VALUE obj; { struct windata *winp; char rtn[1024]; /* This should be big enough.. I hope */ GetWINDOW(obj, winp); rb_read_check(stdin); #if defined(HAVE_WGETNSTR) wgetnstr(winp->window, rtn, 1023); #else wgetstr(winp->window, rtn); #endif return rb_tainted_str_new2(rtn); } /* def delch */ static VALUE window_delch(obj) VALUE obj; { struct windata *winp; GetWINDOW(obj, winp); wdelch(winp->window); return Qnil; } /* def delelteln */ static VALUE window_deleteln(obj) VALUE obj; { #if defined(HAVE_WDELETELN) || defined(wdeleteln) struct windata *winp; GetWINDOW(obj, winp); wdeleteln(winp->window); #endif return Qnil; } /* def insertln */ static VALUE window_insertln(obj) VALUE obj; { #if defined(HAVE_WINSERTLN) || defined(winsertln) struct windata *winp; GetWINDOW(obj, winp); winsertln(winp->window); #endif return Qnil; } static VALUE window_scrollok(VALUE obj, VALUE bf) { struct windata *winp; GetWINDOW(obj, winp); scrollok(winp->window, RTEST(bf) ? TRUE : FALSE); return Qnil; } static VALUE window_idlok(VALUE obj, VALUE bf) { struct windata *winp; GetWINDOW(obj, winp); idlok(winp->window, RTEST(bf) ? TRUE : FALSE); return Qnil; } static VALUE window_setscrreg(VALUE obj, VALUE top, VALUE bottom) { #ifdef HAVE_WSETSCRREG struct windata *winp; int res; GetWINDOW(obj, winp); res = wsetscrreg(winp->window, NUM2INT(top), NUM2INT(bottom)); /* may have to raise exception on ERR */ return (res == OK) ? Qtrue : Qfalse; #else return Qfalse; #endif } #if defined(USE_COLOR) && defined(HAVE_WCOLOR_SET) static VALUE window_color_set(VALUE obj, VALUE col) { struct windata *winp; int res; GetWINDOW(obj, winp); res = wcolor_set(winp->window, NUM2INT(col), NULL); return (res == OK) ? Qtrue : Qfalse; } #endif /* USE_COLOR */ static VALUE window_scroll(VALUE obj) { struct windata *winp; GetWINDOW(obj, winp); /* may have to raise exception on ERR */ return (scroll(winp->window) == OK) ? Qtrue : Qfalse; } static VALUE window_scrl(VALUE obj, VALUE n) { #ifdef HAVE_WSCRL struct windata *winp; GetWINDOW(obj, winp); /* may have to raise exception on ERR */ return (wscrl(winp->window,NUM2INT(n)) == OK) ? Qtrue : Qfalse; #else return Qfalse; #endif } static VALUE window_attroff(VALUE obj, VALUE attrs) { #ifdef HAVE_WATTROFF struct windata *winp; GetWINDOW(obj,winp); return INT2FIX(wattroff(winp->window,NUM2INT(attrs))); #else return Qtrue; #endif } static VALUE window_attron(VALUE obj, VALUE attrs) { #ifdef HAVE_WATTRON struct windata *winp; VALUE val; GetWINDOW(obj,winp); val = INT2FIX(wattron(winp->window,NUM2INT(attrs))); if( rb_block_given_p() ){ rb_yield(val); wattroff(winp->window,NUM2INT(attrs)); return val; } else{ return val; } #else return Qtrue; #endif } static VALUE window_attrset(VALUE obj, VALUE attrs) { #ifdef HAVE_WATTRSET struct windata *winp; GetWINDOW(obj,winp); return INT2FIX(wattrset(winp->window,NUM2INT(attrs))); #else return Qtrue; #endif } static VALUE window_bkgdset(VALUE obj, VALUE ch) { #ifdef HAVE_WBKGDSET struct windata *winp; GetWINDOW(obj,winp); wbkgdset(winp->window, NUM2CH(ch)); #endif return Qnil; } static VALUE window_bkgd(VALUE obj, VALUE ch) { #ifdef HAVE_WBKGD struct windata *winp; GetWINDOW(obj,winp); return (wbkgd(winp->window, NUM2CH(ch)) == OK) ? Qtrue : Qfalse; #else return Qfalse; #endif } static VALUE window_getbkgd(VALUE obj) { #ifdef HAVE_WGETBKGD chtype c; struct windata *winp; GetWINDOW(obj,winp); return (c = getbkgd(winp->window) != ERR) ? CH2FIX(c) : Qnil; #else return Qnil; #endif } static VALUE window_resize(VALUE obj, VALUE lin, VALUE col) { #if defined(HAVE_WRESIZE) struct windata *winp; GetWINDOW(obj,winp); return wresize(winp->window, NUM2INT(lin), NUM2INT(col)) == OK ? Qtrue : Qfalse; #else return Qnil; #endif } static VALUE window_keypad(VALUE obj, VALUE val) { #ifdef HAVE_KEYPAD struct windata *winp; GetWINDOW(obj,winp); /* keypad() of NetBSD's libcurses returns no value */ #if defined(__NetBSD__) && !defined(NCURSES_VERSION) keypad(winp->window,(RTEST(val) ? TRUE : FALSE)); return Qnil; #else /* may have to raise exception on ERR */ return (keypad(winp->window,RTEST(val) ? TRUE : FALSE)) == OK ? Qtrue : Qfalse; #endif #else rb_notimplement(); #endif /* HAVE_KEYPAD */ } static VALUE window_nodelay(VALUE obj, VALUE val) { #ifdef HAVE_NODELAY struct windata *winp; GetWINDOW(obj,winp); /* nodelay() of NetBSD's libcurses returns no value */ #if defined(__NetBSD__) && !defined(NCURSES_VERSION) nodelay(winp->window, RTEST(val) ? TRUE : FALSE); return Qnil; #else return nodelay(winp->window,RTEST(val) ? TRUE : FALSE) == OK ? Qtrue : Qfalse; #endif #else rb_notimplement(); #endif } static VALUE window_timeout(VALUE obj, VALUE delay) { #ifdef HAVE_WTIMEOUT struct windata *winp; GetWINDOW(obj,winp); wtimeout(winp->window,NUM2INT(delay)); return Qnil; #else rb_notimplement(); #endif } /*------------------------- Initialization -------------------------*/ void Init_curses() { mCurses = rb_define_module("Curses"); mKey = rb_define_module_under(mCurses, "Key"); rb_gc_register_address(&rb_stdscr); #ifdef USE_MOUSE cMouseEvent = rb_define_class_under(mCurses,"MouseEvent",rb_cObject); rb_undef_method(CLASS_OF(cMouseEvent),"new"); rb_define_method(cMouseEvent, "eid", curs_mouse_id, 0); rb_define_method(cMouseEvent, "x", curs_mouse_x, 0); rb_define_method(cMouseEvent, "y", curs_mouse_y, 0); rb_define_method(cMouseEvent, "z", curs_mouse_z, 0); rb_define_method(cMouseEvent, "bstate", curs_mouse_bstate, 0); #endif /* USE_MOUSE */ rb_define_module_function(mCurses, "init_screen", curses_init_screen, 0); rb_define_module_function(mCurses, "close_screen", curses_close_screen, 0); rb_define_module_function(mCurses, "closed?", curses_closed, 0); rb_define_module_function(mCurses, "stdscr", curses_stdscr, 0); rb_define_module_function(mCurses, "refresh", curses_refresh, 0); rb_define_module_function(mCurses, "doupdate", curses_doupdate, 0); rb_define_module_function(mCurses, "clear", curses_clear, 0); rb_define_module_function(mCurses, "clrtoeol", curses_clrtoeol, 0); rb_define_module_function(mCurses, "echo", curses_echo, 0); rb_define_module_function(mCurses, "noecho", curses_noecho, 0); rb_define_module_function(mCurses, "raw", curses_raw, 0); rb_define_module_function(mCurses, "noraw", curses_noraw, 0); rb_define_module_function(mCurses, "cbreak", curses_cbreak, 0); rb_define_module_function(mCurses, "nocbreak", curses_nocbreak, 0); rb_define_alias(mCurses, "crmode", "cbreak"); rb_define_alias(mCurses, "nocrmode", "nocbreak"); rb_define_module_function(mCurses, "nl", curses_nl, 0); rb_define_module_function(mCurses, "nonl", curses_nonl, 0); rb_define_module_function(mCurses, "beep", curses_beep, 0); rb_define_module_function(mCurses, "flash", curses_flash, 0); rb_define_module_function(mCurses, "ungetch", curses_ungetch, 1); rb_define_module_function(mCurses, "setpos", curses_setpos, 2); rb_define_module_function(mCurses, "standout", curses_standout, 0); rb_define_module_function(mCurses, "standend", curses_standend, 0); rb_define_module_function(mCurses, "inch", curses_inch, 0); rb_define_module_function(mCurses, "addch", curses_addch, 1); rb_define_module_function(mCurses, "insch", curses_insch, 1); rb_define_module_function(mCurses, "addstr", curses_addstr, 1); rb_define_module_function(mCurses, "getch", curses_getch, 0); rb_define_module_function(mCurses, "getstr", curses_getstr, 0); rb_define_module_function(mCurses, "delch", curses_delch, 0); rb_define_module_function(mCurses, "deleteln", curses_deleteln, 0); rb_define_module_function(mCurses, "insertln", curses_insertln, 0); rb_define_module_function(mCurses, "keyname", curses_keyname, 1); rb_define_module_function(mCurses, "lines", curses_lines, 0); rb_define_module_function(mCurses, "cols", curses_cols, 0); rb_define_module_function(mCurses, "curs_set", curses_curs_set, 1); rb_define_module_function(mCurses, "scrl", curses_scrl, 1); rb_define_module_function(mCurses, "setscrreg", curses_setscrreg, 2); rb_define_module_function(mCurses, "attroff", curses_attroff, 1); rb_define_module_function(mCurses, "attron", curses_attron, 1); rb_define_module_function(mCurses, "attrset", curses_attrset, 1); rb_define_module_function(mCurses, "bkgdset", curses_bkgdset, 1); rb_define_module_function(mCurses, "bkgd", curses_bkgd, 1); rb_define_module_function(mCurses, "resizeterm", curses_resizeterm, 2); rb_define_module_function(mCurses, "resize", curses_resizeterm, 2); #ifdef USE_COLOR rb_define_module_function(mCurses, "start_color", curses_start_color, 0); rb_define_module_function(mCurses, "init_pair", curses_init_pair, 3); rb_define_module_function(mCurses, "init_color", curses_init_color, 4); rb_define_module_function(mCurses, "has_colors?", curses_has_colors, 0); rb_define_module_function(mCurses, "can_change_color?", curses_can_change_color, 0); rb_define_module_function(mCurses, "color_content", curses_color_content, 1); rb_define_module_function(mCurses, "pair_content", curses_pair_content, 1); rb_define_module_function(mCurses, "color_pair", curses_color_pair, 1); rb_define_module_function(mCurses, "pair_number", curses_pair_number, 1); #endif /* USE_COLOR */ #ifdef USE_MOUSE rb_define_module_function(mCurses, "getmouse", curses_getmouse, 0); rb_define_module_function(mCurses, "ungetmouse", curses_ungetmouse, 1); rb_define_module_function(mCurses, "mouseinterval", curses_mouseinterval, 1); rb_define_module_function(mCurses, "mousemask", curses_mousemask, 1); #endif /* USE_MOUSE */ rb_define_module_function(mCurses, "timeout=", curses_timeout, 1); rb_define_module_function(mCurses, "def_prog_mode", curses_def_prog_mode, 0); rb_define_module_function(mCurses, "reset_prog_mode", curses_reset_prog_mode, 0); cWindow = rb_define_class_under(mCurses, "Window", rb_cData); rb_define_alloc_func(cWindow, window_s_allocate); rb_define_method(cWindow, "initialize", window_initialize, 4); rb_define_method(cWindow, "subwin", window_subwin, 4); rb_define_method(cWindow, "close", window_close, 0); rb_define_method(cWindow, "clear", window_clear, 0); rb_define_method(cWindow, "clrtoeol", window_clrtoeol, 0); rb_define_method(cWindow, "refresh", window_refresh, 0); rb_define_method(cWindow, "noutrefresh", window_noutrefresh, 0); rb_define_method(cWindow, "box", window_box, -1); rb_define_method(cWindow, "move", window_move, 2); rb_define_method(cWindow, "setpos", window_setpos, 2); #if defined(USE_COLOR) && defined(HAVE_WCOLOR_SET) rb_define_method(cWindow, "color_set", window_color_set, 1); #endif /* USE_COLOR && HAVE_WCOLOR_SET */ rb_define_method(cWindow, "cury", window_cury, 0); rb_define_method(cWindow, "curx", window_curx, 0); rb_define_method(cWindow, "maxy", window_maxy, 0); rb_define_method(cWindow, "maxx", window_maxx, 0); rb_define_method(cWindow, "begy", window_begy, 0); rb_define_method(cWindow, "begx", window_begx, 0); rb_define_method(cWindow, "standout", window_standout, 0); rb_define_method(cWindow, "standend", window_standend, 0); rb_define_method(cWindow, "inch", window_inch, 0); rb_define_method(cWindow, "addch", window_addch, 1); rb_define_method(cWindow, "insch", window_insch, 1); rb_define_method(cWindow, "addstr", window_addstr, 1); rb_define_method(cWindow, "<<", window_addstr2, 1); rb_define_method(cWindow, "getch", window_getch, 0); rb_define_method(cWindow, "getstr", window_getstr, 0); rb_define_method(cWindow, "delch", window_delch, 0); rb_define_method(cWindow, "deleteln", window_deleteln, 0); rb_define_method(cWindow, "insertln", window_insertln, 0); rb_define_method(cWindow, "scroll", window_scroll, 0); rb_define_method(cWindow, "scrollok", window_scrollok, 1); rb_define_method(cWindow, "idlok", window_idlok, 1); rb_define_method(cWindow, "setscrreg", window_setscrreg, 2); rb_define_method(cWindow, "scrl", window_scrl, 1); rb_define_method(cWindow, "resize", window_resize, 2); rb_define_method(cWindow, "keypad", window_keypad, 1); rb_define_method(cWindow, "keypad=", window_keypad, 1); rb_define_method(cWindow, "attroff", window_attroff, 1); rb_define_method(cWindow, "attron", window_attron, 1); rb_define_method(cWindow, "attrset", window_attrset, 1); rb_define_method(cWindow, "bkgdset", window_bkgdset, 1); rb_define_method(cWindow, "bkgd", window_bkgd, 1); rb_define_method(cWindow, "getbkgd", window_getbkgd, 0); rb_define_method(cWindow, "nodelay=", window_nodelay, 1); rb_define_method(cWindow, "timeout=", window_timeout, 1); #define rb_curses_define_const(c) rb_define_const(mCurses,#c,UINT2NUM(c)) #ifdef USE_COLOR rb_curses_define_const(A_ATTRIBUTES); #ifdef A_NORMAL rb_curses_define_const(A_NORMAL); #endif rb_curses_define_const(A_STANDOUT); rb_curses_define_const(A_UNDERLINE); rb_curses_define_const(A_REVERSE); rb_curses_define_const(A_BLINK); rb_curses_define_const(A_DIM); rb_curses_define_const(A_BOLD); rb_curses_define_const(A_PROTECT); #ifdef A_INVIS /* for NetBSD */ rb_curses_define_const(A_INVIS); #endif rb_curses_define_const(A_ALTCHARSET); rb_curses_define_const(A_CHARTEXT); #ifdef A_HORIZONTAL rb_curses_define_const(A_HORIZONTAL); #endif #ifdef A_LEFT rb_curses_define_const(A_LEFT); #endif #ifdef A_LOW rb_curses_define_const(A_LOW); #endif #ifdef A_RIGHT rb_curses_define_const(A_RIGHT); #endif #ifdef A_TOP rb_curses_define_const(A_TOP); #endif #ifdef A_VERTICAL rb_curses_define_const(A_VERTICAL); #endif rb_curses_define_const(A_COLOR); #ifdef COLORS rb_curses_define_const(COLORS); #endif rb_curses_define_const(COLOR_BLACK); rb_curses_define_const(COLOR_RED); rb_curses_define_const(COLOR_GREEN); rb_curses_define_const(COLOR_YELLOW); rb_curses_define_const(COLOR_BLUE); rb_curses_define_const(COLOR_MAGENTA); rb_curses_define_const(COLOR_CYAN); rb_curses_define_const(COLOR_WHITE); #endif /* USE_COLOR */ #ifdef USE_MOUSE #ifdef BUTTON1_PRESSED rb_curses_define_const(BUTTON1_PRESSED); #endif #ifdef BUTTON1_RELEASED rb_curses_define_const(BUTTON1_RELEASED); #endif #ifdef BUTTON1_CLICKED rb_curses_define_const(BUTTON1_CLICKED); #endif #ifdef BUTTON1_DOUBLE_CLICKED rb_curses_define_const(BUTTON1_DOUBLE_CLICKED); #endif #ifdef BUTTON1_TRIPLE_CLICKED rb_curses_define_const(BUTTON1_TRIPLE_CLICKED); #endif #ifdef BUTTON2_PRESSED rb_curses_define_const(BUTTON2_PRESSED); #endif #ifdef BUTTON2_RELEASED rb_curses_define_const(BUTTON2_RELEASED); #endif #ifdef BUTTON2_CLICKED rb_curses_define_const(BUTTON2_CLICKED); #endif #ifdef BUTTON2_DOUBLE_CLICKED rb_curses_define_const(BUTTON2_DOUBLE_CLICKED); #endif #ifdef BUTTON2_TRIPLE_CLICKED rb_curses_define_const(BUTTON2_TRIPLE_CLICKED); #endif #ifdef BUTTON3_PRESSED rb_curses_define_const(BUTTON3_PRESSED); #endif #ifdef BUTTON3_RELEASED rb_curses_define_const(BUTTON3_RELEASED); #endif #ifdef BUTTON3_CLICKED rb_curses_define_const(BUTTON3_CLICKED); #endif #ifdef BUTTON3_DOUBLE_CLICKED rb_curses_define_const(BUTTON3_DOUBLE_CLICKED); #endif #ifdef BUTTON3_TRIPLE_CLICKED rb_curses_define_const(BUTTON3_TRIPLE_CLICKED); #endif #ifdef BUTTON4_PRESSED rb_curses_define_const(BUTTON4_PRESSED); #endif #ifdef BUTTON4_RELEASED rb_curses_define_const(BUTTON4_RELEASED); #endif #ifdef BUTTON4_CLICKED rb_curses_define_const(BUTTON4_CLICKED); #endif #ifdef BUTTON4_DOUBLE_CLICKED rb_curses_define_const(BUTTON4_DOUBLE_CLICKED); #endif #ifdef BUTTON4_TRIPLE_CLICKED rb_curses_define_const(BUTTON4_TRIPLE_CLICKED); #endif #ifdef BUTTON_SHIFT rb_curses_define_const(BUTTON_SHIFT); #endif #ifdef BUTTON_CTRL rb_curses_define_const(BUTTON_CTRL); #endif #ifdef BUTTON_ALT rb_curses_define_const(BUTTON_ALT); #endif #ifdef ALL_MOUSE_EVENTS rb_curses_define_const(ALL_MOUSE_EVENTS); #endif #ifdef REPORT_MOUSE_POSITION rb_curses_define_const(REPORT_MOUSE_POSITION); #endif #endif /* USE_MOUSE */ #if defined(KEY_MOUSE) && defined(USE_MOUSE) rb_curses_define_const(KEY_MOUSE); rb_define_const(mKey, "MOUSE", INT2NUM(KEY_MOUSE)); #endif #ifdef KEY_MIN rb_curses_define_const(KEY_MIN); rb_define_const(mKey, "MIN", INT2NUM(KEY_MIN)); #endif #ifdef KEY_BREAK rb_curses_define_const(KEY_BREAK); rb_define_const(mKey, "BREAK", INT2NUM(KEY_BREAK)); #endif #ifdef KEY_DOWN rb_curses_define_const(KEY_DOWN); rb_define_const(mKey, "DOWN", INT2NUM(KEY_DOWN)); #endif #ifdef KEY_UP rb_curses_define_const(KEY_UP); rb_define_const(mKey, "UP", INT2NUM(KEY_UP)); #endif #ifdef KEY_LEFT rb_curses_define_const(KEY_LEFT); rb_define_const(mKey, "LEFT", INT2NUM(KEY_LEFT)); #endif #ifdef KEY_RIGHT rb_curses_define_const(KEY_RIGHT); rb_define_const(mKey, "RIGHT", INT2NUM(KEY_RIGHT)); #endif #ifdef KEY_HOME rb_curses_define_const(KEY_HOME); rb_define_const(mKey, "HOME", INT2NUM(KEY_HOME)); #endif #ifdef KEY_BACKSPACE rb_curses_define_const(KEY_BACKSPACE); rb_define_const(mKey, "BACKSPACE", INT2NUM(KEY_BACKSPACE)); #endif #ifdef KEY_F /* KEY_F(n) : 0 <= n <= 63 */ { int i; char c[8]; for( i=0; i<64; i++ ){ sprintf(c, "KEY_F%d", i); rb_define_const(mCurses, c, INT2NUM(KEY_F(i))); sprintf(c, "F%d", i); rb_define_const(mKey, c, INT2NUM(KEY_F(i))); } } #endif #ifdef KEY_DL rb_curses_define_const(KEY_DL); rb_define_const(mKey, "DL", INT2NUM(KEY_DL)); #endif #ifdef KEY_IL rb_curses_define_const(KEY_IL); rb_define_const(mKey, "IL", INT2NUM(KEY_IL)); #endif #ifdef KEY_DC rb_curses_define_const(KEY_DC); rb_define_const(mKey, "DC", INT2NUM(KEY_DC)); #endif #ifdef KEY_IC rb_curses_define_const(KEY_IC); rb_define_const(mKey, "IC", INT2NUM(KEY_IC)); #endif #ifdef KEY_EIC rb_curses_define_const(KEY_EIC); rb_define_const(mKey, "EIC", INT2NUM(KEY_EIC)); #endif #ifdef KEY_CLEAR rb_curses_define_const(KEY_CLEAR); rb_define_const(mKey, "CLEAR", INT2NUM(KEY_CLEAR)); #endif #ifdef KEY_EOS rb_curses_define_const(KEY_EOS); rb_define_const(mKey, "EOS", INT2NUM(KEY_EOS)); #endif #ifdef KEY_EOL rb_curses_define_const(KEY_EOL); rb_define_const(mKey, "EOL", INT2NUM(KEY_EOL)); #endif #ifdef KEY_SF rb_curses_define_const(KEY_SF); rb_define_const(mKey, "SF", INT2NUM(KEY_SF)); #endif #ifdef KEY_SR rb_curses_define_const(KEY_SR); rb_define_const(mKey, "SR", INT2NUM(KEY_SR)); #endif #ifdef KEY_NPAGE rb_curses_define_const(KEY_NPAGE); rb_define_const(mKey, "NPAGE", INT2NUM(KEY_NPAGE)); #endif #ifdef KEY_PPAGE rb_curses_define_const(KEY_PPAGE); rb_define_const(mKey, "PPAGE", INT2NUM(KEY_PPAGE)); #endif #ifdef KEY_STAB rb_curses_define_const(KEY_STAB); rb_define_const(mKey, "STAB", INT2NUM(KEY_STAB)); #endif #ifdef KEY_CTAB rb_curses_define_const(KEY_CTAB); rb_define_const(mKey, "CTAB", INT2NUM(KEY_CTAB)); #endif #ifdef KEY_CATAB rb_curses_define_const(KEY_CATAB); rb_define_const(mKey, "CATAB", INT2NUM(KEY_CATAB)); #endif #ifdef KEY_ENTER rb_curses_define_const(KEY_ENTER); rb_define_const(mKey, "ENTER", INT2NUM(KEY_ENTER)); #endif #ifdef KEY_SRESET rb_curses_define_const(KEY_SRESET); rb_define_const(mKey, "SRESET", INT2NUM(KEY_SRESET)); #endif #ifdef KEY_RESET rb_curses_define_const(KEY_RESET); rb_define_const(mKey, "RESET", INT2NUM(KEY_RESET)); #endif #ifdef KEY_PRINT rb_curses_define_const(KEY_PRINT); rb_define_const(mKey, "PRINT", INT2NUM(KEY_PRINT)); #endif #ifdef KEY_LL rb_curses_define_const(KEY_LL); rb_define_const(mKey, "LL", INT2NUM(KEY_LL)); #endif #ifdef KEY_A1 rb_curses_define_const(KEY_A1); rb_define_const(mKey, "A1", INT2NUM(KEY_A1)); #endif #ifdef KEY_A3 rb_curses_define_const(KEY_A3); rb_define_const(mKey, "A3", INT2NUM(KEY_A3)); #endif #ifdef KEY_B2 rb_curses_define_const(KEY_B2); rb_define_const(mKey, "B2", INT2NUM(KEY_B2)); #endif #ifdef KEY_C1 rb_curses_define_const(KEY_C1); rb_define_const(mKey, "C1", INT2NUM(KEY_C1)); #endif #ifdef KEY_C3 rb_curses_define_const(KEY_C3); rb_define_const(mKey, "C3", INT2NUM(KEY_C3)); #endif #ifdef KEY_BTAB rb_curses_define_const(KEY_BTAB); rb_define_const(mKey, "BTAB", INT2NUM(KEY_BTAB)); #endif #ifdef KEY_BEG rb_curses_define_const(KEY_BEG); rb_define_const(mKey, "BEG", INT2NUM(KEY_BEG)); #endif #ifdef KEY_CANCEL rb_curses_define_const(KEY_CANCEL); rb_define_const(mKey, "CANCEL", INT2NUM(KEY_CANCEL)); #endif #ifdef KEY_CLOSE rb_curses_define_const(KEY_CLOSE); rb_define_const(mKey, "CLOSE", INT2NUM(KEY_CLOSE)); #endif #ifdef KEY_COMMAND rb_curses_define_const(KEY_COMMAND); rb_define_const(mKey, "COMMAND", INT2NUM(KEY_COMMAND)); #endif #ifdef KEY_COPY rb_curses_define_const(KEY_COPY); rb_define_const(mKey, "COPY", INT2NUM(KEY_COPY)); #endif #ifdef KEY_CREATE rb_curses_define_const(KEY_CREATE); rb_define_const(mKey, "CREATE", INT2NUM(KEY_CREATE)); #endif #ifdef KEY_END rb_curses_define_const(KEY_END); rb_define_const(mKey, "END", INT2NUM(KEY_END)); #endif #ifdef KEY_EXIT rb_curses_define_const(KEY_EXIT); rb_define_const(mKey, "EXIT", INT2NUM(KEY_EXIT)); #endif #ifdef KEY_FIND rb_curses_define_const(KEY_FIND); rb_define_const(mKey, "FIND", INT2NUM(KEY_FIND)); #endif #ifdef KEY_HELP rb_curses_define_const(KEY_HELP); rb_define_const(mKey, "HELP", INT2NUM(KEY_HELP)); #endif #ifdef KEY_MARK rb_curses_define_const(KEY_MARK); rb_define_const(mKey, "MARK", INT2NUM(KEY_MARK)); #endif #ifdef KEY_MESSAGE rb_curses_define_const(KEY_MESSAGE); rb_define_const(mKey, "MESSAGE", INT2NUM(KEY_MESSAGE)); #endif #ifdef KEY_MOVE rb_curses_define_const(KEY_MOVE); rb_define_const(mKey, "MOVE", INT2NUM(KEY_MOVE)); #endif #ifdef KEY_NEXT rb_curses_define_const(KEY_NEXT); rb_define_const(mKey, "NEXT", INT2NUM(KEY_NEXT)); #endif #ifdef KEY_OPEN rb_curses_define_const(KEY_OPEN); rb_define_const(mKey, "OPEN", INT2NUM(KEY_OPEN)); #endif #ifdef KEY_OPTIONS rb_curses_define_const(KEY_OPTIONS); rb_define_const(mKey, "OPTIONS", INT2NUM(KEY_OPTIONS)); #endif #ifdef KEY_PREVIOUS rb_curses_define_const(KEY_PREVIOUS); rb_define_const(mKey, "PREVIOUS", INT2NUM(KEY_PREVIOUS)); #endif #ifdef KEY_REDO rb_curses_define_const(KEY_REDO); rb_define_const(mKey, "REDO", INT2NUM(KEY_REDO)); #endif #ifdef KEY_REFERENCE rb_curses_define_const(KEY_REFERENCE); rb_define_const(mKey, "REFERENCE", INT2NUM(KEY_REFERENCE)); #endif #ifdef KEY_REFRESH rb_curses_define_const(KEY_REFRESH); rb_define_const(mKey, "REFRESH", INT2NUM(KEY_REFRESH)); #endif #ifdef KEY_REPLACE rb_curses_define_const(KEY_REPLACE); rb_define_const(mKey, "REPLACE", INT2NUM(KEY_REPLACE)); #endif #ifdef KEY_RESTART rb_curses_define_const(KEY_RESTART); rb_define_const(mKey, "RESTART", INT2NUM(KEY_RESTART)); #endif #ifdef KEY_RESUME rb_curses_define_const(KEY_RESUME); rb_define_const(mKey, "RESUME", INT2NUM(KEY_RESUME)); #endif #ifdef KEY_SAVE rb_curses_define_const(KEY_SAVE); rb_define_const(mKey, "SAVE", INT2NUM(KEY_SAVE)); #endif #ifdef KEY_SBEG rb_curses_define_const(KEY_SBEG); rb_define_const(mKey, "SBEG", INT2NUM(KEY_SBEG)); #endif #ifdef KEY_SCANCEL rb_curses_define_const(KEY_SCANCEL); rb_define_const(mKey, "SCANCEL", INT2NUM(KEY_SCANCEL)); #endif #ifdef KEY_SCOMMAND rb_curses_define_const(KEY_SCOMMAND); rb_define_const(mKey, "SCOMMAND", INT2NUM(KEY_SCOMMAND)); #endif #ifdef KEY_SCOPY rb_curses_define_const(KEY_SCOPY); rb_define_const(mKey, "SCOPY", INT2NUM(KEY_SCOPY)); #endif #ifdef KEY_SCREATE rb_curses_define_const(KEY_SCREATE); rb_define_const(mKey, "SCREATE", INT2NUM(KEY_SCREATE)); #endif #ifdef KEY_SDC rb_curses_define_const(KEY_SDC); rb_define_const(mKey, "SDC", INT2NUM(KEY_SDC)); #endif #ifdef KEY_SDL rb_curses_define_const(KEY_SDL); rb_define_const(mKey, "SDL", INT2NUM(KEY_SDL)); #endif #ifdef KEY_SELECT rb_curses_define_const(KEY_SELECT); rb_define_const(mKey, "SELECT", INT2NUM(KEY_SELECT)); #endif #ifdef KEY_SEND rb_curses_define_const(KEY_SEND); rb_define_const(mKey, "SEND", INT2NUM(KEY_SEND)); #endif #ifdef KEY_SEOL rb_curses_define_const(KEY_SEOL); rb_define_const(mKey, "SEOL", INT2NUM(KEY_SEOL)); #endif #ifdef KEY_SEXIT rb_curses_define_const(KEY_SEXIT); rb_define_const(mKey, "SEXIT", INT2NUM(KEY_SEXIT)); #endif #ifdef KEY_SFIND rb_curses_define_const(KEY_SFIND); rb_define_const(mKey, "SFIND", INT2NUM(KEY_SFIND)); #endif #ifdef KEY_SHELP rb_curses_define_const(KEY_SHELP); rb_define_const(mKey, "SHELP", INT2NUM(KEY_SHELP)); #endif #ifdef KEY_SHOME rb_curses_define_const(KEY_SHOME); rb_define_const(mKey, "SHOME", INT2NUM(KEY_SHOME)); #endif #ifdef KEY_SIC rb_curses_define_const(KEY_SIC); rb_define_const(mKey, "SIC", INT2NUM(KEY_SIC)); #endif #ifdef KEY_SLEFT rb_curses_define_const(KEY_SLEFT); rb_define_const(mKey, "SLEFT", INT2NUM(KEY_SLEFT)); #endif #ifdef KEY_SMESSAGE rb_curses_define_const(KEY_SMESSAGE); rb_define_const(mKey, "SMESSAGE", INT2NUM(KEY_SMESSAGE)); #endif #ifdef KEY_SMOVE rb_curses_define_const(KEY_SMOVE); rb_define_const(mKey, "SMOVE", INT2NUM(KEY_SMOVE)); #endif #ifdef KEY_SNEXT rb_curses_define_const(KEY_SNEXT); rb_define_const(mKey, "SNEXT", INT2NUM(KEY_SNEXT)); #endif #ifdef KEY_SOPTIONS rb_curses_define_const(KEY_SOPTIONS); rb_define_const(mKey, "SOPTIONS", INT2NUM(KEY_SOPTIONS)); #endif #ifdef KEY_SPREVIOUS rb_curses_define_const(KEY_SPREVIOUS); rb_define_const(mKey, "SPREVIOUS", INT2NUM(KEY_SPREVIOUS)); #endif #ifdef KEY_SPRINT rb_curses_define_const(KEY_SPRINT); rb_define_const(mKey, "SPRINT", INT2NUM(KEY_SPRINT)); #endif #ifdef KEY_SREDO rb_curses_define_const(KEY_SREDO); rb_define_const(mKey, "SREDO", INT2NUM(KEY_SREDO)); #endif #ifdef KEY_SREPLACE rb_curses_define_const(KEY_SREPLACE); rb_define_const(mKey, "SREPLACE", INT2NUM(KEY_SREPLACE)); #endif #ifdef KEY_SRIGHT rb_curses_define_const(KEY_SRIGHT); rb_define_const(mKey, "SRIGHT", INT2NUM(KEY_SRIGHT)); #endif #ifdef KEY_SRSUME rb_curses_define_const(KEY_SRSUME); rb_define_const(mKey, "SRSUME", INT2NUM(KEY_SRSUME)); #endif #ifdef KEY_SSAVE rb_curses_define_const(KEY_SSAVE); rb_define_const(mKey, "SSAVE", INT2NUM(KEY_SSAVE)); #endif #ifdef KEY_SSUSPEND rb_curses_define_const(KEY_SSUSPEND); rb_define_const(mKey, "SSUSPEND", INT2NUM(KEY_SSUSPEND)); #endif #ifdef KEY_SUNDO rb_curses_define_const(KEY_SUNDO); rb_define_const(mKey, "SUNDO", INT2NUM(KEY_SUNDO)); #endif #ifdef KEY_SUSPEND rb_curses_define_const(KEY_SUSPEND); rb_define_const(mKey, "SUSPEND", INT2NUM(KEY_SUSPEND)); #endif #ifdef KEY_UNDO rb_curses_define_const(KEY_UNDO); rb_define_const(mKey, "UNDO", INT2NUM(KEY_UNDO)); #endif #ifdef KEY_RESIZE rb_curses_define_const(KEY_RESIZE); rb_define_const(mKey, "RESIZE", INT2NUM(KEY_RESIZE)); #endif #ifdef KEY_MAX rb_curses_define_const(KEY_MAX); rb_define_const(mKey, "MAX", INT2NUM(KEY_MAX)); #endif { int c; char name[] = "KEY_CTRL_x"; for( c = 'A'; c <= 'Z'; c++ ){ sprintf(name, "KEY_CTRL_%c", c); rb_define_const(mCurses, name, INT2FIX(c - 'A' + 1)); } } #undef rb_curses_define_const rb_set_end_proc(curses_finalize, 0); } ================================================ FILE: ext/curses/depend ================================================ curses.o: curses.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h ================================================ FILE: ext/curses/extconf.rb ================================================ require 'mkmf' dir_config('curses') dir_config('ncurses') dir_config('termcap') make=false have_library("mytinfo", "tgetent") if /bow/ =~ RUBY_PLATFORM have_library("tinfo", "tgetent") or have_library("termcap", "tgetent") if have_header(*curses=%w"ncurses.h") and have_library("ncurses", "initscr") make=true elsif have_header(*curses=%w"ncurses/curses.h") and have_library("ncurses", "initscr") make=true elsif have_header(*curses=%w"curses_colr/curses.h") and have_library("cur_colr", "initscr") curses.unshift("varargs.h") make=true elsif have_header(*curses=%w"curses.h") and have_library("curses", "initscr") make=true end if make for f in %w(beep bkgd bkgdset curs_set deleteln doupdate flash getbkgd getnstr init isendwin keyname keypad resizeterm scrl set setscrreg ungetch wattroff wattron wattrset wbkgd wbkgdset wdeleteln wgetnstr wresize wscrl wsetscrreg def_prog_mode reset_prog_mode timeout wtimeout nodelay init_color wcolor_set) have_func(f) || (have_macro(f, curses) && $defs.push(format("-DHAVE_%s", f.upcase))) end flag = "-D_XOPEN_SOURCE_EXTENDED" src = "int test_var[(sizeof(char*)>sizeof(int))*2-1];" if try_compile(cpp_include(%w[stdio.h stdlib.h]+curses)+src , flag) $defs << flag end create_makefile("curses") end ================================================ FILE: ext/curses/hello.rb ================================================ #!/usr/local/bin/ruby require "curses" include Curses def show_message(message) width = message.length + 6 win = Window.new(5, width, (lines - 5) / 2, (cols - width) / 2) win.box(?|, ?-) win.setpos(2, 3) win.addstr(message) win.refresh win.getch win.close end init_screen begin crmode # show_message("Hit any key") setpos((lines - 5) / 2, (cols - 10) / 2) addstr("Hit any key") refresh getch show_message("Hello, World!") refresh ensure close_screen end ================================================ FILE: ext/curses/mouse.rb ================================================ #!/usr/local/bin/ruby require "curses" include Curses def show_message(*msgs) message = msgs.join width = message.length + 6 win = Window.new(5, width, (lines - 5) / 2, (cols - width) / 2) win.keypad = true win.attron(color_pair(COLOR_RED)){ win.box(?|, ?-, ?+) } win.setpos(2, 3) win.addstr(message) win.refresh win.getch win.close end init_screen start_color init_pair(COLOR_BLUE,COLOR_BLUE,COLOR_WHITE) init_pair(COLOR_RED,COLOR_RED,COLOR_WHITE) crmode noecho stdscr.keypad(true) begin mousemask(BUTTON1_CLICKED|BUTTON2_CLICKED|BUTTON3_CLICKED|BUTTON4_CLICKED) setpos((lines - 5) / 2, (cols - 10) / 2) attron(color_pair(COLOR_BLUE)|A_BOLD){ addstr("click") } refresh while( true ) c = getch case c when KEY_MOUSE m = getmouse if( m ) show_message("getch = #{c.inspect}, ", "mouse event = #{'0x%x' % m.bstate}, ", "axis = (#{m.x},#{m.y},#{m.z})") end break end end refresh ensure close_screen end ================================================ FILE: ext/curses/rain.rb ================================================ #!/usr/local/bin/ruby # rain for a curses test require "curses" include Curses def onsig(sig) close_screen exit sig end def ranf rand(32767).to_f / 32767 end # main # for i in 1 .. 15 # SIGHUP .. SIGTERM if trap(i, "SIG_IGN") != 0 then # 0 for SIG_IGN trap(i) {|sig| onsig(sig) } end end init_screen nl noecho srand xpos = {} ypos = {} r = lines - 4 c = cols - 4 for i in 0 .. 4 xpos[i] = (c * ranf).to_i + 2 ypos[i] = (r * ranf).to_i + 2 end i = 0 while TRUE x = (c * ranf).to_i + 2 y = (r * ranf).to_i + 2 setpos(y, x); addstr(".") setpos(ypos[i], xpos[i]); addstr("o") i = if i == 0 then 4 else i - 1 end setpos(ypos[i], xpos[i]); addstr("O") i = if i == 0 then 4 else i - 1 end setpos(ypos[i] - 1, xpos[i]); addstr("-") setpos(ypos[i], xpos[i] - 1); addstr("|.|") setpos(ypos[i] + 1, xpos[i]); addstr("-") i = if i == 0 then 4 else i - 1 end setpos(ypos[i] - 2, xpos[i]); addstr("-") setpos(ypos[i] - 1, xpos[i] - 1); addstr("/ \\") setpos(ypos[i], xpos[i] - 2); addstr("| O |") setpos(ypos[i] + 1, xpos[i] - 1); addstr("\\ /") setpos(ypos[i] + 2, xpos[i]); addstr("-") i = if i == 0 then 4 else i - 1 end setpos(ypos[i] - 2, xpos[i]); addstr(" ") setpos(ypos[i] - 1, xpos[i] - 1); addstr(" ") setpos(ypos[i], xpos[i] - 2); addstr(" ") setpos(ypos[i] + 1, xpos[i] - 1); addstr(" ") setpos(ypos[i] + 2, xpos[i]); addstr(" ") xpos[i] = x ypos[i] = y refresh sleep(0.5) end # end of main ================================================ FILE: ext/curses/view.rb ================================================ #!/usr/local/bin/ruby require "curses" include Curses # # main # if ARGV.size != 1 then printf("usage: view file\n"); exit end begin fp = open(ARGV[0], "r") rescue raise "cannot open file: #{ARGV[1]}" end # signal(SIGINT, finish) init_screen #keypad(stdscr, TRUE) nonl cbreak noecho #scrollok(stdscr, TRUE) # slurp the file data_lines = [] fp.each_line { |l| data_lines.push(l) } fp.close lptr = 0 while TRUE i = 0 while i < lines setpos(i, 0) #clrtoeol addstr(data_lines[lptr + i]) #if data_lines[lptr + i] i += 1 end refresh explicit = FALSE n = 0 while TRUE c = getch.chr if c =~ /[0-9]/ n = 10 * n + c.to_i else break end end n = 1 if !explicit && n == 0 case c when "n" #when KEY_DOWN i = 0 while i < n if lptr + lines < data_lines.size then lptr += 1 else break end i += 1 end #wscrl(i) when "p" #when KEY_UP i = 0 while i < n if lptr > 0 then lptr -= 1 else break end i += 1 end #wscrl(-i) when "q" break end end close_screen ================================================ FILE: ext/curses/view2.rb ================================================ #!/usr/local/bin/ruby require "curses" if ARGV.size != 1 then printf("usage: view file\n"); exit end begin fp = open(ARGV[0], "r") rescue raise "cannot open file: #{ARGV[1]}" end # signal(SIGINT, finish) Curses.init_screen Curses.nonl Curses.cbreak Curses.noecho $screen = Curses.stdscr $screen.scrollok(true) #$screen.keypad(true) # slurp the file $data_lines = [] fp.each_line { |l| $data_lines.push(l.chop) } fp.close $top = 0 $data_lines[0..$screen.maxy-1].each_with_index{|line, idx| $screen.setpos(idx, 0) $screen.addstr(line) } $screen.setpos(0,0) $screen.refresh def scroll_up if( $top > 0 ) $screen.scrl(-1) $top -= 1 str = $data_lines[$top] if( str ) $screen.setpos(0, 0) $screen.addstr(str) end return true else return false end end def scroll_down if( $top + $screen.maxy < $data_lines.length ) $screen.scrl(1) $top += 1 str = $data_lines[$top + $screen.maxy - 1] if( str ) $screen.setpos($screen.maxy - 1, 0) $screen.addstr(str) end return true else return false end end while true result = true c = Curses.getch case c when Curses::KEY_DOWN, Curses::KEY_CTRL_N result = scroll_down when Curses::KEY_UP, Curses::KEY_CTRL_P result = scroll_up when Curses::KEY_NPAGE, ?\s # white space for i in 0..($screen.maxy - 2) if( ! scroll_down ) if( i == 0 ) result = false end break end end when Curses::KEY_PPAGE for i in 0..($screen.maxy - 2) if( ! scroll_up ) if( i == 0 ) result = false end break end end when Curses::KEY_LEFT, Curses::KEY_CTRL_T while( scroll_up ) end when Curses::KEY_RIGHT, Curses::KEY_CTRL_B while( scroll_down ) end when ?q break else $screen.setpos(0,0) $screen.addstr("[unknown key `#{Curses.keyname(c)}'=#{c}] ") end if( !result ) Curses.beep end $screen.setpos(0,0) end Curses.close_screen ================================================ FILE: ext/dbm/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/dbm/dbm.c ================================================ /************************************************ dbm.c - $Author$ $Date$ created at: Mon Jan 24 15:59:52 JST 1994 Copyright (C) 1995-2001 Yukihiro Matsumoto ************************************************/ #include "ruby.h" #ifdef HAVE_CDEFS_H # include #endif #ifdef HAVE_SYS_CDEFS_H # include #endif #include DBM_HDR #include #include static VALUE rb_cDBM, rb_eDBMError; #define RUBY_DBM_RW_BIT 0x20000000 struct dbmdata { int di_size; DBM *di_dbm; }; static void closed_dbm() { rb_raise(rb_eDBMError, "closed DBM file"); } #define GetDBM(obj, dbmp) {\ Data_Get_Struct(obj, struct dbmdata, dbmp);\ if (dbmp == 0) closed_dbm();\ if (dbmp->di_dbm == 0) closed_dbm();\ } #define GetDBM2(obj, data, dbm) {\ GetDBM(obj, data);\ (dbm) = dbmp->di_dbm;\ } static void free_dbm(dbmp) struct dbmdata *dbmp; { if (dbmp) { if (dbmp->di_dbm) dbm_close(dbmp->di_dbm); free(dbmp); } } static VALUE fdbm_close(obj) VALUE obj; { struct dbmdata *dbmp; GetDBM(obj, dbmp); dbm_close(dbmp->di_dbm); dbmp->di_dbm = 0; return Qnil; } static VALUE fdbm_closed(obj) VALUE obj; { struct dbmdata *dbmp; Data_Get_Struct(obj, struct dbmdata, dbmp); if (dbmp == 0) return Qtrue; if (dbmp->di_dbm == 0) return Qtrue; return Qfalse; } static VALUE fdbm_alloc _((VALUE)); static VALUE fdbm_alloc(klass) VALUE klass; { return Data_Wrap_Struct(klass, 0, free_dbm, 0); } static VALUE fdbm_initialize(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE file, vmode, vflags; DBM *dbm; struct dbmdata *dbmp; int mode, flags = 0; if (rb_scan_args(argc, argv, "12", &file, &vmode, &vflags) == 1) { mode = 0666; /* default value */ } else if (NIL_P(vmode)) { mode = -1; /* return nil if DB not exist */ } else { mode = NUM2INT(vmode); } if (!NIL_P(vflags)) flags = NUM2INT(vflags); SafeStringValue(file); if (flags & RUBY_DBM_RW_BIT) { flags &= ~RUBY_DBM_RW_BIT; dbm = dbm_open(RSTRING(file)->ptr, flags, mode); } else { dbm = 0; if (mode >= 0) { dbm = dbm_open(RSTRING(file)->ptr, O_RDWR|O_CREAT, mode); } if (!dbm) { dbm = dbm_open(RSTRING(file)->ptr, O_RDWR, 0); } if (!dbm) { dbm = dbm_open(RSTRING(file)->ptr, O_RDONLY, 0); } } if (!dbm) { if (mode == -1) return Qnil; rb_sys_fail(RSTRING(file)->ptr); } dbmp = ALLOC(struct dbmdata); DATA_PTR(obj) = dbmp; dbmp->di_dbm = dbm; dbmp->di_size = -1; return obj; } static VALUE fdbm_s_open(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { VALUE obj = Data_Wrap_Struct(klass, 0, free_dbm, 0); if (NIL_P(fdbm_initialize(argc, argv, obj))) { return Qnil; } if (rb_block_given_p()) { return rb_ensure(rb_yield, obj, fdbm_close, obj); } return obj; } static VALUE fdbm_fetch(obj, keystr, ifnone) VALUE obj, keystr, ifnone; { datum key, value; struct dbmdata *dbmp; DBM *dbm; StringValue(keystr); key.dptr = RSTRING(keystr)->ptr; key.dsize = RSTRING(keystr)->len; GetDBM2(obj, dbmp, dbm); value = dbm_fetch(dbm, key); if (value.dptr == 0) { if (ifnone == Qnil && rb_block_given_p()) return rb_yield(rb_tainted_str_new(key.dptr, key.dsize)); return ifnone; } return rb_tainted_str_new(value.dptr, value.dsize); } static VALUE fdbm_aref(obj, keystr) VALUE obj, keystr; { return fdbm_fetch(obj, keystr, Qnil); } static VALUE fdbm_fetch_m(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE keystr, valstr, ifnone; rb_scan_args(argc, argv, "11", &keystr, &ifnone); valstr = fdbm_fetch(obj, keystr, ifnone); if (argc == 1 && !rb_block_given_p() && NIL_P(valstr)) rb_raise(rb_eIndexError, "key not found"); return valstr; } static VALUE fdbm_index(obj, valstr) VALUE obj, valstr; { datum key, val; struct dbmdata *dbmp; DBM *dbm; StringValue(valstr); val.dptr = RSTRING(valstr)->ptr; val.dsize = RSTRING(valstr)->len; GetDBM2(obj, dbmp, dbm); for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { val = dbm_fetch(dbm, key); if (val.dsize == RSTRING(valstr)->len && memcmp(val.dptr, RSTRING(valstr)->ptr, val.dsize) == 0) { return rb_tainted_str_new(key.dptr, key.dsize); } } return Qnil; } static VALUE fdbm_indexes(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE new; int i; new = rb_ary_new2(argc); for (i=0; i 0) { rb_raise(rb_eArgError, "wrong number arguments(%d for 0)", argc); } GetDBM2(obj, dbmp, dbm); for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { VALUE assoc, v; val = dbm_fetch(dbm, key); assoc = rb_assoc_new(rb_tainted_str_new(key.dptr, key.dsize), rb_tainted_str_new(val.dptr, val.dsize)); v = rb_yield(assoc); if (RTEST(v)) { rb_ary_push(new, assoc); } GetDBM2(obj, dbmp, dbm); } } else { rb_warn("DBM#select(index..) is deprecated; use DBM#values_at"); for (i=0; iptr; key.dsize = RSTRING(keystr)->len; GetDBM2(obj, dbmp, dbm); value = dbm_fetch(dbm, key); if (value.dptr == 0) { if (rb_block_given_p()) return rb_yield(keystr); return Qnil; } /* need to save value before dbm_delete() */ valstr = rb_tainted_str_new(value.dptr, value.dsize); if (dbm_delete(dbm, key)) { dbmp->di_size = -1; rb_raise(rb_eDBMError, "dbm_delete failed"); } else if (dbmp->di_size >= 0) { dbmp->di_size--; } return valstr; } static VALUE fdbm_shift(obj) VALUE obj; { datum key, val; struct dbmdata *dbmp; DBM *dbm; VALUE keystr, valstr; fdbm_modify(obj); GetDBM2(obj, dbmp, dbm); dbmp->di_size = -1; key = dbm_firstkey(dbm); if (!key.dptr) return Qnil; val = dbm_fetch(dbm, key); keystr = rb_tainted_str_new(key.dptr, key.dsize); valstr = rb_tainted_str_new(val.dptr, val.dsize); dbm_delete(dbm, key); return rb_assoc_new(keystr, valstr); } static VALUE fdbm_delete_if(obj) VALUE obj; { datum key, val; struct dbmdata *dbmp; DBM *dbm; VALUE keystr, valstr; VALUE ret, ary = rb_ary_new(); int i, status = 0, n; fdbm_modify(obj); GetDBM2(obj, dbmp, dbm); n = dbmp->di_size; dbmp->di_size = -1; for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { val = dbm_fetch(dbm, key); keystr = rb_tainted_str_new(key.dptr, key.dsize); valstr = rb_tainted_str_new(val.dptr, val.dsize); ret = rb_protect(rb_yield, rb_assoc_new(rb_str_dup(keystr), valstr), &status); if (status != 0) break; if (RTEST(ret)) rb_ary_push(ary, keystr); GetDBM2(obj, dbmp, dbm); } for (i = 0; i < RARRAY(ary)->len; i++) { keystr = RARRAY(ary)->ptr[i]; StringValue(keystr); key.dptr = RSTRING(keystr)->ptr; key.dsize = RSTRING(keystr)->len; if (dbm_delete(dbm, key)) { rb_raise(rb_eDBMError, "dbm_delete failed"); } } if (status) rb_jump_tag(status); if (n > 0) dbmp->di_size = n - RARRAY(ary)->len; return obj; } static VALUE fdbm_clear(obj) VALUE obj; { datum key; struct dbmdata *dbmp; DBM *dbm; fdbm_modify(obj); GetDBM2(obj, dbmp, dbm); dbmp->di_size = -1; while (key = dbm_firstkey(dbm), key.dptr) { if (dbm_delete(dbm, key)) { rb_raise(rb_eDBMError, "dbm_delete failed"); } } dbmp->di_size = 0; return obj; } static VALUE fdbm_invert(obj) VALUE obj; { datum key, val; struct dbmdata *dbmp; DBM *dbm; VALUE keystr, valstr; VALUE hash = rb_hash_new(); GetDBM2(obj, dbmp, dbm); for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { val = dbm_fetch(dbm, key); keystr = rb_tainted_str_new(key.dptr, key.dsize); valstr = rb_tainted_str_new(val.dptr, val.dsize); rb_hash_aset(hash, valstr, keystr); } return hash; } static VALUE each_pair _((VALUE)); static VALUE each_pair(obj) VALUE obj; { return rb_funcall(obj, rb_intern("each_pair"), 0, 0); } static VALUE fdbm_store _((VALUE,VALUE,VALUE)); static VALUE update_i(pair, dbm) VALUE pair, dbm; { Check_Type(pair, T_ARRAY); if (RARRAY(pair)->len < 2) { rb_raise(rb_eArgError, "pair must be [key, value]"); } fdbm_store(dbm, RARRAY(pair)->ptr[0], RARRAY(pair)->ptr[1]); return Qnil; } static VALUE fdbm_update(obj, other) VALUE obj, other; { rb_iterate(each_pair, other, update_i, obj); return obj; } static VALUE fdbm_replace(obj, other) VALUE obj, other; { fdbm_clear(obj); rb_iterate(each_pair, other, update_i, obj); return obj; } static VALUE fdbm_store(obj, keystr, valstr) VALUE obj, keystr, valstr; { datum key, val; struct dbmdata *dbmp; DBM *dbm; fdbm_modify(obj); keystr = rb_obj_as_string(keystr); valstr = rb_obj_as_string(valstr); key.dptr = RSTRING(keystr)->ptr; key.dsize = RSTRING(keystr)->len; val.dptr = RSTRING(valstr)->ptr; val.dsize = RSTRING(valstr)->len; GetDBM2(obj, dbmp, dbm); dbmp->di_size = -1; if (dbm_store(dbm, key, val, DBM_REPLACE)) { #ifdef HAVE_DBM_CLEARERR dbm_clearerr(dbm); #endif if (errno == EPERM) rb_sys_fail(0); rb_raise(rb_eDBMError, "dbm_store failed"); } return valstr; } static VALUE fdbm_length(obj) VALUE obj; { datum key; struct dbmdata *dbmp; DBM *dbm; int i = 0; GetDBM2(obj, dbmp, dbm); if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size); for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { i++; } dbmp->di_size = i; return INT2FIX(i); } static VALUE fdbm_empty_p(obj) VALUE obj; { datum key; struct dbmdata *dbmp; DBM *dbm; int i = 0; GetDBM2(obj, dbmp, dbm); if (dbmp->di_size < 0) { dbm = dbmp->di_dbm; for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { i++; } } else { i = dbmp->di_size; } if (i == 0) return Qtrue; return Qfalse; } static VALUE fdbm_each_value(obj) VALUE obj; { datum key, val; struct dbmdata *dbmp; DBM *dbm; GetDBM2(obj, dbmp, dbm); for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { val = dbm_fetch(dbm, key); rb_yield(rb_tainted_str_new(val.dptr, val.dsize)); GetDBM2(obj, dbmp, dbm); } return obj; } static VALUE fdbm_each_key(obj) VALUE obj; { datum key; struct dbmdata *dbmp; DBM *dbm; GetDBM2(obj, dbmp, dbm); for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { rb_yield(rb_tainted_str_new(key.dptr, key.dsize)); GetDBM2(obj, dbmp, dbm); } return obj; } static VALUE fdbm_each_pair(obj) VALUE obj; { datum key, val; DBM *dbm; struct dbmdata *dbmp; VALUE keystr, valstr; GetDBM2(obj, dbmp, dbm); for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { val = dbm_fetch(dbm, key); keystr = rb_tainted_str_new(key.dptr, key.dsize); valstr = rb_tainted_str_new(val.dptr, val.dsize); rb_yield(rb_assoc_new(keystr, valstr)); GetDBM2(obj, dbmp, dbm); } return obj; } static VALUE fdbm_keys(obj) VALUE obj; { datum key; struct dbmdata *dbmp; DBM *dbm; VALUE ary; GetDBM2(obj, dbmp, dbm); ary = rb_ary_new(); for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { rb_ary_push(ary, rb_tainted_str_new(key.dptr, key.dsize)); } return ary; } static VALUE fdbm_values(obj) VALUE obj; { datum key, val; struct dbmdata *dbmp; DBM *dbm; VALUE ary; GetDBM2(obj, dbmp, dbm); ary = rb_ary_new(); for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { val = dbm_fetch(dbm, key); rb_ary_push(ary, rb_tainted_str_new(val.dptr, val.dsize)); } return ary; } static VALUE fdbm_has_key(obj, keystr) VALUE obj, keystr; { datum key, val; struct dbmdata *dbmp; DBM *dbm; StringValue(keystr); key.dptr = RSTRING(keystr)->ptr; key.dsize = RSTRING(keystr)->len; GetDBM2(obj, dbmp, dbm); val = dbm_fetch(dbm, key); if (val.dptr) return Qtrue; return Qfalse; } static VALUE fdbm_has_value(obj, valstr) VALUE obj, valstr; { datum key, val; struct dbmdata *dbmp; DBM *dbm; StringValue(valstr); val.dptr = RSTRING(valstr)->ptr; val.dsize = RSTRING(valstr)->len; GetDBM2(obj, dbmp, dbm); for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { val = dbm_fetch(dbm, key); if (val.dsize == RSTRING(valstr)->len && memcmp(val.dptr, RSTRING(valstr)->ptr, val.dsize) == 0) return Qtrue; } return Qfalse; } static VALUE fdbm_to_a(obj) VALUE obj; { datum key, val; struct dbmdata *dbmp; DBM *dbm; VALUE ary; GetDBM2(obj, dbmp, dbm); ary = rb_ary_new(); for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { val = dbm_fetch(dbm, key); rb_ary_push(ary, rb_assoc_new(rb_tainted_str_new(key.dptr, key.dsize), rb_tainted_str_new(val.dptr, val.dsize))); } return ary; } static VALUE fdbm_to_hash(obj) VALUE obj; { datum key, val; struct dbmdata *dbmp; DBM *dbm; VALUE hash; GetDBM2(obj, dbmp, dbm); hash = rb_hash_new(); for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { val = dbm_fetch(dbm, key); rb_hash_aset(hash, rb_tainted_str_new(key.dptr, key.dsize), rb_tainted_str_new(val.dptr, val.dsize)); } return hash; } static VALUE fdbm_reject(obj) VALUE obj; { return rb_hash_delete_if(fdbm_to_hash(obj)); } void Init_dbm() { rb_cDBM = rb_define_class("DBM", rb_cObject); rb_eDBMError = rb_define_class("DBMError", rb_eStandardError); rb_include_module(rb_cDBM, rb_mEnumerable); rb_define_alloc_func(rb_cDBM, fdbm_alloc); rb_define_singleton_method(rb_cDBM, "open", fdbm_s_open, -1); rb_define_method(rb_cDBM, "initialize", fdbm_initialize, -1); rb_define_method(rb_cDBM, "close", fdbm_close, 0); rb_define_method(rb_cDBM, "closed?", fdbm_closed, 0); rb_define_method(rb_cDBM, "[]", fdbm_aref, 1); rb_define_method(rb_cDBM, "fetch", fdbm_fetch_m, -1); rb_define_method(rb_cDBM, "[]=", fdbm_store, 2); rb_define_method(rb_cDBM, "store", fdbm_store, 2); rb_define_method(rb_cDBM, "index", fdbm_index, 1); rb_define_method(rb_cDBM, "indexes", fdbm_indexes, -1); rb_define_method(rb_cDBM, "indices", fdbm_indexes, -1); rb_define_method(rb_cDBM, "select", fdbm_select, -1); rb_define_method(rb_cDBM, "values_at", fdbm_values_at, -1); rb_define_method(rb_cDBM, "length", fdbm_length, 0); rb_define_method(rb_cDBM, "size", fdbm_length, 0); rb_define_method(rb_cDBM, "empty?", fdbm_empty_p, 0); rb_define_method(rb_cDBM, "each", fdbm_each_pair, 0); rb_define_method(rb_cDBM, "each_value", fdbm_each_value, 0); rb_define_method(rb_cDBM, "each_key", fdbm_each_key, 0); rb_define_method(rb_cDBM, "each_pair", fdbm_each_pair, 0); rb_define_method(rb_cDBM, "keys", fdbm_keys, 0); rb_define_method(rb_cDBM, "values", fdbm_values, 0); rb_define_method(rb_cDBM, "shift", fdbm_shift, 0); rb_define_method(rb_cDBM, "delete", fdbm_delete, 1); rb_define_method(rb_cDBM, "delete_if", fdbm_delete_if, 0); rb_define_method(rb_cDBM, "reject!", fdbm_delete_if, 0); rb_define_method(rb_cDBM, "reject", fdbm_reject, 0); rb_define_method(rb_cDBM, "clear", fdbm_clear, 0); rb_define_method(rb_cDBM,"invert", fdbm_invert, 0); rb_define_method(rb_cDBM,"update", fdbm_update, 1); rb_define_method(rb_cDBM,"replace", fdbm_replace, 1); rb_define_method(rb_cDBM, "include?", fdbm_has_key, 1); rb_define_method(rb_cDBM, "has_key?", fdbm_has_key, 1); rb_define_method(rb_cDBM, "member?", fdbm_has_key, 1); rb_define_method(rb_cDBM, "has_value?", fdbm_has_value, 1); rb_define_method(rb_cDBM, "key?", fdbm_has_key, 1); rb_define_method(rb_cDBM, "value?", fdbm_has_value, 1); rb_define_method(rb_cDBM, "to_a", fdbm_to_a, 0); rb_define_method(rb_cDBM, "to_hash", fdbm_to_hash, 0); /* flags for dbm_open() */ rb_define_const(rb_cDBM, "READER", INT2FIX(O_RDONLY|RUBY_DBM_RW_BIT)); rb_define_const(rb_cDBM, "WRITER", INT2FIX(O_RDWR|RUBY_DBM_RW_BIT)); rb_define_const(rb_cDBM, "WRCREAT", INT2FIX(O_RDWR|O_CREAT|RUBY_DBM_RW_BIT)); rb_define_const(rb_cDBM, "NEWDB", INT2FIX(O_RDWR|O_CREAT|O_TRUNC|RUBY_DBM_RW_BIT)); #ifdef DB_VERSION_STRING rb_define_const(rb_cDBM, "VERSION", rb_str_new2(DB_VERSION_STRING)); #else rb_define_const(rb_cDBM, "VERSION", rb_str_new2("unknown")); #endif } ================================================ FILE: ext/dbm/depend ================================================ dbm.o: dbm.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h ================================================ FILE: ext/dbm/extconf.rb ================================================ require 'mkmf' dir_config("dbm") if dblib = with_config("dbm-type", nil) dblib = dblib.split(/[ ,]+/) else dblib = %w(db db2 db1 dbm gdbm gdbm_compat qdbm) end headers = { "db" => ["db.h"], "db1" => ["db1/ndbm.h", "db1.h", "ndbm.h"], "db2" => ["db2/db.h", "db2.h", "db.h"], "dbm" => ["ndbm.h"], "gdbm" => ["gdbm-ndbm.h", "ndbm.h"], "gdbm_compat" => ["gdbm-ndbm.h", "ndbm.h"], "qdbm" => ["relic.h"], } def headers.db_check(db) db_prefix = nil have_gdbm = false hsearch = nil case db when /^db2?$/ db_prefix = "__db_n" hsearch = "-DDB_DBM_HSEARCH " when "gdbm" have_gdbm = true when "gdbm_compat" have_gdbm = true have_library("gdbm") or return false end db_prefix ||= "" if (have_library(db, db_prefix+"dbm_open") || have_func(db_prefix+"dbm_open")) and hdr = self.fetch(db, ["ndbm.h"]).find {|hdr| have_type("DBM", hdr, hsearch)} have_func(db_prefix+"dbm_clearerr") unless have_gdbm $defs << hsearch if hsearch $defs << '-DDBM_HDR="<'+hdr+'>"' true else false end end if dblib.any? {|db| headers.db_check(db)} have_header("cdefs.h") have_header("sys/cdefs.h") create_makefile("dbm") end ================================================ FILE: ext/digest/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/digest/bubblebabble/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/digest/bubblebabble/bubblebabble.c ================================================ /************************************************ bubblebabble.c - BubbleBabble encoding support $Author$ created at: Fri Oct 13 18:31:42 JST 2006 Copyright (C) 2006 Akinori MUSHA $Id$ ************************************************/ #include "ruby.h" #include "digest.h" static ID id_digest; static VALUE bubblebabble_str_new(VALUE str_digest) { char *digest; size_t digest_len; VALUE str; char *p; int i, j, seed = 1; static const char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' }; static const char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' }; StringValue(str_digest); digest = RSTRING_PTR(str_digest); digest_len = RSTRING_LEN(str_digest); if ((LONG_MAX - 2) / 3 < (digest_len | 1)) { rb_raise(rb_eRuntimeError, "digest string too long"); } str = rb_str_new(0, (digest_len | 1) * 3 + 2); p = RSTRING_PTR(str); i = j = 0; p[j++] = 'x'; for (;;) { unsigned char byte1, byte2; if (i >= digest_len) { p[j++] = vowels[seed % 6]; p[j++] = consonants[16]; p[j++] = vowels[seed / 6]; break; } byte1 = digest[i++]; p[j++] = vowels[(((byte1 >> 6) & 3) + seed) % 6]; p[j++] = consonants[(byte1 >> 2) & 15]; p[j++] = vowels[((byte1 & 3) + (seed / 6)) % 6]; if (i >= digest_len) { break; } byte2 = digest[i++]; p[j++] = consonants[(byte2 >> 4) & 15]; p[j++] = '-'; p[j++] = consonants[byte2 & 15]; seed = (seed * 5 + byte1 * 7 + byte2) % 36; } p[j] = 'x'; return str; } /* * call-seq: * Digest.bubblebabble(string) -> bubblebabble_string * * Returns a BubbleBabble encoded version of a given _string_. */ static VALUE rb_digest_s_bubblebabble(VALUE klass, VALUE str) { return bubblebabble_str_new(str); } /* * call-seq: * Digest::Class.bubblebabble(string, ...) -> hash_string * * Returns the BubbleBabble encoded hash value of a given _string_. */ static VALUE rb_digest_class_s_bubblebabble(int argc, VALUE *argv, VALUE klass) { return bubblebabble_str_new(rb_funcall2(klass, id_digest, argc, argv)); } /* * call-seq: * digest_obj.bubblebabble -> hash_string * * Returns the resulting hash value in a Bubblebabble encoded form. */ static VALUE rb_digest_instance_bubblebabble(VALUE self) { return bubblebabble_str_new(rb_funcall(self, id_digest, 0)); } /* * This module adds some methods to Digest classes to perform * BubbleBabble encoding. */ void Init_bubblebabble(void) { VALUE mDigest, mDigest_Instance, cDigest_Class; rb_require("digest"); mDigest = rb_path2class("Digest"); mDigest_Instance = rb_path2class("Digest::Instance"); cDigest_Class = rb_path2class("Digest::Class"); /* Digest::bubblebabble() */ rb_define_module_function(mDigest, "bubblebabble", rb_digest_s_bubblebabble, 1); /* Digest::Class::bubblebabble() */ rb_define_singleton_method(cDigest_Class, "bubblebabble", rb_digest_class_s_bubblebabble, -1); /* Digest::Instance#bubblebabble() */ rb_define_method(mDigest_Instance, "bubblebabble", rb_digest_instance_bubblebabble, 0); id_digest = rb_intern("digest"); } ================================================ FILE: ext/digest/bubblebabble/depend ================================================ bubblebabble.o: bubblebabble.c $(srcdir)/../digest.h $(hdrdir)/ruby.h \ $(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/intern.h \ $(srcdir)/../defs.h ================================================ FILE: ext/digest/bubblebabble/extconf.rb ================================================ require 'mkmf' $defs << "-DHAVE_CONFIG_H" $INCFLAGS << " -I$(srcdir)/.." create_makefile('digest/bubblebabble') ================================================ FILE: ext/digest/defs.h ================================================ /* -*- C -*- * $Id$ */ #ifndef DEFS_H #define DEFS_H #include "ruby.h" #include #if defined(HAVE_SYS_CDEFS_H) # include #endif #if !defined(__BEGIN_DECLS) # define __BEGIN_DECLS # define __END_DECLS #endif #if defined(HAVE_INTTYPES_H) # include #elif !defined __CYGWIN__ || !defined __uint8_t_defined typedef unsigned char uint8_t; typedef unsigned int uint32_t; # if SIZEOF_LONG == 8 typedef unsigned long uint64_t; # elif SIZEOF_LONG_LONG == 8 typedef unsigned LONG_LONG uint64_t; # else # define NO_UINT64_T # endif #endif #endif /* DEFS_H */ ================================================ FILE: ext/digest/depend ================================================ digest.o: digest.c digest.h $(hdrdir)/ruby.h $(topdir)/config.h \ $(hdrdir)/defines.h $(hdrdir)/intern.h ================================================ FILE: ext/digest/digest.c ================================================ /************************************************ digest.c - $Author$ created at: Fri May 25 08:57:27 JST 2001 Copyright (C) 1995-2001 Yukihiro Matsumoto Copyright (C) 2001-2006 Akinori MUSHA $RoughId: digest.c,v 1.16 2001/07/13 15:38:27 knu Exp $ $Id$ ************************************************/ #include "digest.h" static VALUE rb_mDigest; static VALUE rb_mDigest_Instance; static VALUE rb_cDigest_Class; static VALUE rb_cDigest_Base; static ID id_reset, id_update, id_finish, id_digest, id_hexdigest, id_digest_length; static ID id_metadata; RUBY_EXTERN void Init_digest_base(void); /* * Document-module: Digest * * This module provides a framework for message digest libraries. */ static VALUE hexencode_str_new(VALUE str_digest) { char *digest; size_t digest_len; int i; VALUE str; char *p; static const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; StringValue(str_digest); digest = RSTRING_PTR(str_digest); digest_len = RSTRING_LEN(str_digest); if (LONG_MAX / 2 < digest_len) { rb_raise(rb_eRuntimeError, "digest string too long"); } str = rb_str_new(0, digest_len * 2); for (i = 0, p = RSTRING_PTR(str); i < digest_len; i++) { unsigned char byte = digest[i]; p[i + i] = hex[byte >> 4]; p[i + i + 1] = hex[byte & 0x0f]; } return str; } /* * call-seq: * Digest.hexencode(string) -> hexencoded_string * * Generates a hex-encoded version of a given _string_. */ static VALUE rb_digest_s_hexencode(VALUE klass, VALUE str) { return hexencode_str_new(str); } /* * Document-module: Digest::Instance * * This module provides instance methods for a digest implementation * object to calculate message digest values. */ static void rb_digest_instance_method_unimpl(VALUE self, const char *method) { VALUE klass = rb_obj_class(self); rb_raise(rb_eRuntimeError, "%s does not implement %s()", rb_obj_classname(self), method); } /* * call-seq: * digest_obj.update(string) -> digest_obj * digest_obj << string -> digest_obj * * Updates the digest using a given _string_ and returns self. * * The update() method and the left-shift operator are overridden by * each implementation subclass. (One should be an alias for the * other) */ static VALUE rb_digest_instance_update(VALUE self, VALUE str) { rb_digest_instance_method_unimpl(self, "update"); } /* * call-seq: * digest_obj.instance_eval { finish } -> digest_obj * * Finishes the digest and returns the resulting hash value. * * This method is overridden by each implementation subclass and often * made private, because some of those subclasses may leave internal * data uninitialized. Do not call this method from outside. Use * #digest!() instead, which ensures that internal data be reset for * security reasons. */ static VALUE rb_digest_instance_finish(VALUE self) { rb_digest_instance_method_unimpl(self, "finish"); } /* * call-seq: * digest_obj.reset -> digest_obj * * Resets the digest to the initial state and returns self. * * This method is overridden by each implementation subclass. */ static VALUE rb_digest_instance_reset(VALUE self) { rb_digest_instance_method_unimpl(self, "reset"); } /* * call-seq: * digest_obj.new -> another_digest_obj * * Returns a new, initialized copy of the digest object. Equivalent * to digest_obj.clone().reset(). */ static VALUE rb_digest_instance_new(VALUE self) { VALUE clone = rb_obj_clone(self); rb_funcall(clone, id_reset, 0); return clone; } /* * call-seq: * digest_obj.digest -> string * digest_obj.digest(string) -> string * * If none is given, returns the resulting hash value of the digest, * keeping the digest's state. * * If a _string_ is given, returns the hash value for the given * _string_, resetting the digest to the initial state before and * after the process. */ static VALUE rb_digest_instance_digest(int argc, VALUE *argv, VALUE self) { VALUE str, value; if (rb_scan_args(argc, argv, "01", &str) > 0) { rb_funcall(self, id_reset, 0); rb_funcall(self, id_update, 1, str); value = rb_funcall(self, id_finish, 0); rb_funcall(self, id_reset, 0); } else { VALUE clone = rb_obj_clone(self); value = rb_funcall(clone, id_finish, 0); rb_funcall(clone, id_reset, 0); } return value; } /* * call-seq: * digest_obj.digest! -> string * * Returns the resulting hash value and resets the digest to the * initial state. */ static VALUE rb_digest_instance_digest_bang(VALUE self) { VALUE value = rb_funcall(self, id_finish, 0); rb_funcall(self, id_reset, 0); return value; } /* * call-seq: * digest_obj.hexdigest -> string * digest_obj.hexdigest(string) -> string * * If none is given, returns the resulting hash value of the digest in * a hex-encoded form, keeping the digest's state. * * If a _string_ is given, returns the hash value for the given * _string_ in a hex-encoded form, resetting the digest to the initial * state before and after the process. */ static VALUE rb_digest_instance_hexdigest(int argc, VALUE *argv, VALUE self) { VALUE str, value; if (rb_scan_args(argc, argv, "01", &str) > 0) { rb_funcall(self, id_reset, 0); rb_funcall(self, id_update, 1, str); value = rb_funcall(self, id_finish, 0); rb_funcall(self, id_reset, 0); } else { VALUE clone = rb_obj_clone(self); value = rb_funcall(clone, id_finish, 0); rb_funcall(clone, id_reset, 0); } return hexencode_str_new(value); } /* * call-seq: * digest_obj.hexdigest! -> string * * Returns the resulting hash value and resets the digest to the * initial state. */ static VALUE rb_digest_instance_hexdigest_bang(VALUE self) { VALUE value = rb_funcall(self, id_finish, 0); rb_funcall(self, id_reset, 0); return hexencode_str_new(value); } /* * call-seq: * digest_obj.to_s -> string * * Returns digest_obj.hexdigest(). */ static VALUE rb_digest_instance_to_s(VALUE self) { return rb_funcall(self, id_hexdigest, 0); } /* * call-seq: * digest_obj.inspect -> string * * Creates a printable version of the digest object. */ static VALUE rb_digest_instance_inspect(VALUE self) { VALUE str; size_t digest_len = 32; /* about this size at least */ char *cname; cname = rb_obj_classname(self); /* # */ str = rb_str_buf_new(2 + strlen(cname) + 2 + digest_len * 2 + 1); rb_str_buf_cat2(str, "#<"); rb_str_buf_cat2(str, cname); rb_str_buf_cat2(str, ": "); rb_str_buf_append(str, rb_digest_instance_hexdigest(0, 0, self)); rb_str_buf_cat2(str, ">"); return str; } /* * call-seq: * digest_obj == another_digest_obj -> boolean * digest_obj == string -> boolean * * If a string is given, checks whether it is equal to the hex-encoded * hash value of the digest object. If another digest instance is * given, checks whether they have the same hash value. Otherwise * returns false. */ static VALUE rb_digest_instance_equal(VALUE self, VALUE other) { VALUE str1, str2; if (rb_obj_is_kind_of(other, rb_mDigest_Instance) == Qtrue) { str1 = rb_digest_instance_digest(0, 0, self); str2 = rb_digest_instance_digest(0, 0, other); } else { str1 = rb_digest_instance_to_s(self); str2 = other; } /* never blindly assume that subclass methods return strings */ StringValue(str1); StringValue(str2); if (RSTRING_LEN(str1) == RSTRING_LEN(str2) && rb_str_cmp(str1, str2) == 0) { return Qtrue; } return Qfalse; } /* * call-seq: * digest_obj.digest_length -> integer * * Returns the length of the hash value of the digest. * * This method should be overridden by each implementation subclass. * If not, digest_obj.digest().length() is returned. */ static VALUE rb_digest_instance_digest_length(VALUE self) { /* subclasses really should redefine this method */ VALUE digest = rb_digest_instance_digest(0, 0, self); /* never blindly assume that #digest() returns a string */ StringValue(digest); return INT2NUM(RSTRING_LEN(digest)); } /* * call-seq: * digest_obj.length -> integer * digest_obj.size -> integer * * Returns digest_obj.digest_length(). */ static VALUE rb_digest_instance_length(VALUE self) { return rb_funcall(self, id_digest_length, 0); } /* * call-seq: * digest_obj.block_length -> integer * * Returns the block length of the digest. * * This method is overridden by each implementation subclass. */ static VALUE rb_digest_instance_block_length(VALUE self) { rb_digest_instance_method_unimpl(self, "block_length"); } /* * Document-class: Digest::Class * * This module stands as a base class for digest implementation * classes. */ /* * call-seq: * Digest::Class.digest(string, *parameters) -> hash_string * * Returns the hash value of a given _string_. This is equivalent to * Digest::Class.new(*parameters).digest(string), where extra * _parameters_, if any, are passed through to the constructor and the * _string_ is passed to #digest(). */ static VALUE rb_digest_class_s_digest(int argc, VALUE *argv, VALUE klass) { VALUE str; volatile VALUE obj; if (argc < 1) { rb_raise(rb_eArgError, "no data given"); } str = *argv++; argc--; StringValue(str); obj = rb_obj_alloc(klass); rb_obj_call_init(obj, argc, argv); return rb_funcall(obj, id_digest, 1, str); } /* * call-seq: * Digest::Class.hexdigest(string[, ...]) -> hash_string * * Returns the hex-encoded hash value of a given _string_. This is * almost equivalent to * Digest.hexencode(Digest::Class.new(*parameters).digest(string)). */ static VALUE rb_digest_class_s_hexdigest(int argc, VALUE *argv, VALUE klass) { return hexencode_str_new(rb_funcall2(klass, id_digest, argc, argv)); } /* * Document-class: Digest::Base * * This abstract class provides a common interface to message digest * implementation classes written in C. */ static rb_digest_metadata_t * get_digest_base_metadata(VALUE klass) { VALUE p; VALUE obj; rb_digest_metadata_t *algo; for (p = klass; p; p = RCLASS(p)->super) { if (rb_ivar_defined(p, id_metadata)) { obj = rb_ivar_get(p, id_metadata); break; } } if (!p) rb_raise(rb_eRuntimeError, "Digest::Base cannot be directly inherited in Ruby"); Data_Get_Struct(obj, rb_digest_metadata_t, algo); switch (algo->api_version) { case 2: break; /* * put conversion here if possible when API is updated */ default: rb_raise(rb_eRuntimeError, "Incompatible digest API version"); } return algo; } static VALUE rb_digest_base_alloc(VALUE klass) { rb_digest_metadata_t *algo; VALUE obj; void *pctx; if (klass == rb_cDigest_Base) { rb_raise(rb_eNotImpError, "Digest::Base is an abstract class"); } algo = get_digest_base_metadata(klass); pctx = xmalloc(algo->ctx_size); algo->init_func(pctx); obj = Data_Wrap_Struct(klass, 0, free, pctx); return obj; } /* :nodoc: */ static VALUE rb_digest_base_copy(VALUE copy, VALUE obj) { rb_digest_metadata_t *algo; void *pctx1, *pctx2; if (copy == obj) return copy; rb_check_frozen(copy); algo = get_digest_base_metadata(rb_obj_class(copy)); Data_Get_Struct(obj, void, pctx1); Data_Get_Struct(copy, void, pctx2); memcpy(pctx2, pctx1, algo->ctx_size); return copy; } /* :nodoc: */ static VALUE rb_digest_base_reset(VALUE self) { rb_digest_metadata_t *algo; void *pctx; algo = get_digest_base_metadata(rb_obj_class(self)); Data_Get_Struct(self, void, pctx); algo->init_func(pctx); return self; } /* :nodoc: */ static VALUE rb_digest_base_update(VALUE self, VALUE str) { rb_digest_metadata_t *algo; void *pctx; algo = get_digest_base_metadata(rb_obj_class(self)); Data_Get_Struct(self, void, pctx); StringValue(str); algo->update_func(pctx, (unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str)); return self; } /* :nodoc: */ static VALUE rb_digest_base_finish(VALUE self) { rb_digest_metadata_t *algo; void *pctx; VALUE str; algo = get_digest_base_metadata(rb_obj_class(self)); Data_Get_Struct(self, void, pctx); str = rb_str_new(0, algo->digest_len); algo->finish_func(pctx, (unsigned char *)RSTRING_PTR(str)); /* avoid potential coredump caused by use of a finished context */ algo->init_func(pctx); return str; } /* :nodoc: */ static VALUE rb_digest_base_digest_length(VALUE self) { rb_digest_metadata_t *algo; algo = get_digest_base_metadata(rb_obj_class(self)); return INT2NUM(algo->digest_len); } /* :nodoc: */ static VALUE rb_digest_base_block_length(VALUE self) { rb_digest_metadata_t *algo; algo = get_digest_base_metadata(rb_obj_class(self)); return INT2NUM(algo->block_len); } void Init_digest(void) { id_reset = rb_intern("reset"); id_update = rb_intern("update"); id_finish = rb_intern("finish"); id_digest = rb_intern("digest"); id_hexdigest = rb_intern("hexdigest"); id_digest_length = rb_intern("digest_length"); /* * module Digest */ rb_mDigest = rb_define_module("Digest"); /* module functions */ rb_define_module_function(rb_mDigest, "hexencode", rb_digest_s_hexencode, 1); /* * module Digest::Instance */ rb_mDigest_Instance = rb_define_module_under(rb_mDigest, "Instance"); /* instance methods that should be overridden */ rb_define_method(rb_mDigest_Instance, "update", rb_digest_instance_update, 1); rb_define_method(rb_mDigest_Instance, "<<", rb_digest_instance_update, 1); rb_define_private_method(rb_mDigest_Instance, "finish", rb_digest_instance_finish, 0); rb_define_method(rb_mDigest_Instance, "reset", rb_digest_instance_reset, 0); rb_define_method(rb_mDigest_Instance, "digest_length", rb_digest_instance_digest_length, 0); rb_define_method(rb_mDigest_Instance, "block_length", rb_digest_instance_block_length, 0); /* instance methods that may be overridden */ rb_define_method(rb_mDigest_Instance, "==", rb_digest_instance_equal, 1); rb_define_method(rb_mDigest_Instance, "inspect", rb_digest_instance_inspect, 0); /* instance methods that need not usually be overridden */ rb_define_method(rb_mDigest_Instance, "new", rb_digest_instance_new, 0); rb_define_method(rb_mDigest_Instance, "digest", rb_digest_instance_digest, -1); rb_define_method(rb_mDigest_Instance, "digest!", rb_digest_instance_digest_bang, 0); rb_define_method(rb_mDigest_Instance, "hexdigest", rb_digest_instance_hexdigest, -1); rb_define_method(rb_mDigest_Instance, "hexdigest!", rb_digest_instance_hexdigest_bang, 0); rb_define_method(rb_mDigest_Instance, "to_s", rb_digest_instance_to_s, 0); rb_define_method(rb_mDigest_Instance, "length", rb_digest_instance_length, 0); rb_define_method(rb_mDigest_Instance, "size", rb_digest_instance_length, 0); /* * class Digest::Class */ rb_cDigest_Class = rb_define_class_under(rb_mDigest, "Class", rb_cObject); rb_include_module(rb_cDigest_Class, rb_mDigest_Instance); /* class methods */ rb_define_singleton_method(rb_cDigest_Class, "digest", rb_digest_class_s_digest, -1); rb_define_singleton_method(rb_cDigest_Class, "hexdigest", rb_digest_class_s_hexdigest, -1); id_metadata = rb_intern("metadata"); /* class Digest::Base < Digest::Class */ rb_cDigest_Base = rb_define_class_under(rb_mDigest, "Base", rb_cDigest_Class); rb_define_alloc_func(rb_cDigest_Base, rb_digest_base_alloc); rb_define_method(rb_cDigest_Base, "initialize_copy", rb_digest_base_copy, 1); rb_define_method(rb_cDigest_Base, "reset", rb_digest_base_reset, 0); rb_define_method(rb_cDigest_Base, "update", rb_digest_base_update, 1); rb_define_method(rb_cDigest_Base, "<<", rb_digest_base_update, 1); rb_define_private_method(rb_cDigest_Base, "finish", rb_digest_base_finish, 0); rb_define_method(rb_cDigest_Base, "digest_length", rb_digest_base_digest_length, 0); rb_define_method(rb_cDigest_Base, "block_length", rb_digest_base_block_length, 0); } ================================================ FILE: ext/digest/digest.h ================================================ /************************************************ digest.h - header file for ruby digest modules $Author$ created at: Fri May 25 08:54:56 JST 2001 Copyright (C) 2001-2006 Akinori MUSHA $RoughId: digest.h,v 1.3 2001/07/13 15:38:27 knu Exp $ $Id$ ************************************************/ #include "ruby.h" #define RUBY_DIGEST_API_VERSION 2 typedef void (*rb_digest_hash_init_func_t)(void *); typedef void (*rb_digest_hash_update_func_t)(void *, unsigned char *, size_t); typedef void (*rb_digest_hash_finish_func_t)(void *, unsigned char *); typedef struct { int api_version; size_t digest_len; size_t block_len; size_t ctx_size; rb_digest_hash_init_func_t init_func; rb_digest_hash_update_func_t update_func; rb_digest_hash_finish_func_t finish_func; } rb_digest_metadata_t; ================================================ FILE: ext/digest/extconf.rb ================================================ # $RoughId: extconf.rb,v 1.6 2001/07/13 15:38:27 knu Exp $ # $Id$ require "mkmf" $INSTALLFILES = { "digest.h" => "$(RUBYARCHDIR)" } create_makefile("digest") ================================================ FILE: ext/digest/lib/digest.rb ================================================ require 'digest.so' module Digest def self.const_missing(name) case name when :SHA256, :SHA384, :SHA512 lib = 'digest/sha2.so' else lib = File.join('digest', name.to_s.downcase) end begin require lib rescue LoadError => e raise LoadError, "library not found for class Digest::#{name} -- #{lib}", caller(1) end unless Digest.const_defined?(name) raise NameError, "uninitialized constant Digest::#{name}", caller(1) end Digest.const_get(name) end class ::Digest::Class # creates a digest object and reads a given file, _name_. # # p Digest::SHA256.file("X11R6.8.2-src.tar.bz2").hexdigest # # => "f02e3c85572dc9ad7cb77c2a638e3be24cc1b5bea9fdbb0b0299c9668475c534" def self.file(name) new.file(name) end end module Instance # updates the digest with the contents of a given file _name_ and # returns self. def file(name) File.open(name, "rb") {|f| buf = "" while f.read(16384, buf) update buf end } self end end end def Digest(name) Digest.const_get(name) end ================================================ FILE: ext/digest/lib/md5.rb ================================================ # just for compatibility; requiring "md5" is obsoleted # # $RoughId: md5.rb,v 1.4 2001/07/13 15:38:27 knu Exp $ # $Id$ require 'digest/md5' class MD5 < Digest::MD5 class << self alias orig_new new def new(str = nil) if str orig_new.update(str) else orig_new end end def md5(*args) new(*args) end end end ================================================ FILE: ext/digest/lib/sha1.rb ================================================ # just for compatibility; requiring "sha1" is obsoleted # # $RoughId: sha1.rb,v 1.4 2001/07/13 15:38:27 knu Exp $ # $Id$ require 'digest/sha1' class SHA1 < Digest::SHA1 class << self alias orig_new new def new(str = nil) if str orig_new.update(str) else orig_new end end def sha1(*args) new(*args) end end end ================================================ FILE: ext/digest/md5/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/digest/md5/depend ================================================ md5.o: md5.c md5.h $(srcdir)/../defs.h $(hdrdir)/ruby.h $(topdir)/config.h \ $(hdrdir)/defines.h $(hdrdir)/intern.h md5init.o: md5init.c $(srcdir)/../digest.h $(hdrdir)/ruby.h \ $(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/intern.h md5.h \ $(srcdir)/../defs.h md5ossl.o: md5ossl.h ================================================ FILE: ext/digest/md5/extconf.rb ================================================ # $RoughId: extconf.rb,v 1.3 2001/08/14 19:54:51 knu Exp $ # $Id$ require "mkmf" $defs << "-DHAVE_CONFIG_H" $INCFLAGS << " -I$(srcdir)/.." $objs = [ "md5init.#{$OBJEXT}" ] dir_config("openssl") if !with_config("bundled-md5") && have_library("crypto") && have_header("openssl/md5.h") $objs << "md5ossl.#{$OBJEXT}" else $objs << "md5.#{$OBJEXT}" end have_header("sys/cdefs.h") have_header("inttypes.h") have_header("unistd.h") $preload = %w[digest] create_makefile("digest/md5") ================================================ FILE: ext/digest/md5/md5.c ================================================ /* Copyright (C) 1999, 2000 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321. It is derived directly from the text of the RFC and not from the reference implementation. The original and principal author of md5.c is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2000-07-03 lpd Patched to eliminate warnings about "constant is unsigned in ANSI C, signed in traditional"; made test program self-checking. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. */ /* This code was modified for use in Ruby. - Akinori MUSHA */ /*$OrigId: md5c.c,v 1.2 2001/03/26 08:57:14 matz Exp $ */ /*$RoughId: md5.c,v 1.2 2001/07/13 19:48:41 knu Exp $ */ /*$Id$ */ #include "md5.h" #ifdef TEST /* * Compile with -DTEST to create a self-contained executable test program. * The test program should print out the same values as given in section * A.5 of RFC 1321, reproduced below. */ #include main() { static const char *const test[7*2] = { "", "d41d8cd98f00b204e9800998ecf8427e", "a", "0cc175b9c0f1b6a831c399e269772661", "abc", "900150983cd24fb0d6963f7d28e17f72", "message digest", "f96b697d7cb7938d525a2f31aaf161d0", "abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "d174ab98d277d9f5a5611c2c9f419d9f", "12345678901234567890123456789012345678901234567890123456789012345678901234567890", "57edf4a22be3c955ac49da2e2107b67a" }; int i; for (i = 0; i < 7*2; i += 2) { MD5_CTX state; uint8_t digest[16]; char hex_output[16*2 + 1]; int di; MD5_Init(&state); MD5_Update(&state, (const uint8_t *)test[i], strlen(test[i])); MD5_Final(digest, &state); printf("MD5 (\"%s\") = ", test[i]); for (di = 0; di < 16; ++di) sprintf(hex_output + di * 2, "%02x", digest[di]); puts(hex_output); if (strcmp(hex_output, test[i + 1])) printf("**** ERROR, should be: %s\n", test[i + 1]); } return 0; } #endif /* TEST */ /* * For reference, here is the program that computed the T values. */ #ifdef COMPUTE_T_VALUES #include main() { int i; for (i = 1; i <= 64; ++i) { unsigned long v = (unsigned long)(4294967296.0 * fabs(sin((double)i))); /* * The following nonsense is only to avoid compiler warnings about * "integer constant is unsigned in ANSI C, signed with -traditional". */ if (v >> 31) { printf("#define T%d /* 0x%08lx */ (T_MASK ^ 0x%08lx)\n", i, v, (unsigned long)(unsigned int)(~v)); } else { printf("#define T%d 0x%08lx\n", i, v); } } return 0; } #endif /* COMPUTE_T_VALUES */ /* * End of T computation program. */ #ifdef T_MASK #undef T_MASK #endif #define T_MASK ((uint32_t)~0) #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) #define T3 0x242070db #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) #define T6 0x4787c62a #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) #define T9 0x698098d8 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) #define T13 0x6b901122 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) #define T16 0x49b40821 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) #define T19 0x265e5a51 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) #define T22 0x02441453 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) #define T25 0x21e1cde6 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) #define T28 0x455a14ed #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) #define T31 0x676f02d9 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) #define T35 0x6d9d6122 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) #define T38 0x4bdecfa9 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) #define T41 0x289b7ec6 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) #define T44 0x04881d05 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) #define T47 0x1fa27cf8 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) #define T50 0x432aff97 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) #define T53 0x655b59c3 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) #define T57 0x6fa87e4f #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) #define T60 0x4e0811a1 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) #define T63 0x2ad7d2bb #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) static void md5_process(MD5_CTX *pms, const uint8_t *data /*[64]*/) { uint32_t a = pms->state[0], b = pms->state[1], c = pms->state[2], d = pms->state[3]; uint32_t t; #ifdef WORDS_BIGENDIAN /* * On big-endian machines, we must arrange the bytes in the right * order. (This also works on machines of unknown byte order.) */ uint32_t X[16]; const uint8_t *xp = data; int i; for (i = 0; i < 16; ++i, xp += 4) X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); #else /* * On little-endian machines, we can process properly aligned data * without copying it. */ uint32_t xbuf[16]; const uint32_t *X; if (!((data - (const uint8_t *)0) & 3)) { /* data are properly aligned */ X = (const uint32_t *)data; } else { /* not aligned */ memcpy(xbuf, data, 64); X = xbuf; } #endif #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* Round 1. */ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + F(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 7, T1); SET(d, a, b, c, 1, 12, T2); SET(c, d, a, b, 2, 17, T3); SET(b, c, d, a, 3, 22, T4); SET(a, b, c, d, 4, 7, T5); SET(d, a, b, c, 5, 12, T6); SET(c, d, a, b, 6, 17, T7); SET(b, c, d, a, 7, 22, T8); SET(a, b, c, d, 8, 7, T9); SET(d, a, b, c, 9, 12, T10); SET(c, d, a, b, 10, 17, T11); SET(b, c, d, a, 11, 22, T12); SET(a, b, c, d, 12, 7, T13); SET(d, a, b, c, 13, 12, T14); SET(c, d, a, b, 14, 17, T15); SET(b, c, d, a, 15, 22, T16); #undef SET /* Round 2. */ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + G(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 1, 5, T17); SET(d, a, b, c, 6, 9, T18); SET(c, d, a, b, 11, 14, T19); SET(b, c, d, a, 0, 20, T20); SET(a, b, c, d, 5, 5, T21); SET(d, a, b, c, 10, 9, T22); SET(c, d, a, b, 15, 14, T23); SET(b, c, d, a, 4, 20, T24); SET(a, b, c, d, 9, 5, T25); SET(d, a, b, c, 14, 9, T26); SET(c, d, a, b, 3, 14, T27); SET(b, c, d, a, 8, 20, T28); SET(a, b, c, d, 13, 5, T29); SET(d, a, b, c, 2, 9, T30); SET(c, d, a, b, 7, 14, T31); SET(b, c, d, a, 12, 20, T32); #undef SET /* Round 3. */ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ #define H(x, y, z) ((x) ^ (y) ^ (z)) #define SET(a, b, c, d, k, s, Ti)\ t = a + H(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 5, 4, T33); SET(d, a, b, c, 8, 11, T34); SET(c, d, a, b, 11, 16, T35); SET(b, c, d, a, 14, 23, T36); SET(a, b, c, d, 1, 4, T37); SET(d, a, b, c, 4, 11, T38); SET(c, d, a, b, 7, 16, T39); SET(b, c, d, a, 10, 23, T40); SET(a, b, c, d, 13, 4, T41); SET(d, a, b, c, 0, 11, T42); SET(c, d, a, b, 3, 16, T43); SET(b, c, d, a, 6, 23, T44); SET(a, b, c, d, 9, 4, T45); SET(d, a, b, c, 12, 11, T46); SET(c, d, a, b, 15, 16, T47); SET(b, c, d, a, 2, 23, T48); #undef SET /* Round 4. */ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ #define I(x, y, z) ((y) ^ ((x) | ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + I(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 6, T49); SET(d, a, b, c, 7, 10, T50); SET(c, d, a, b, 14, 15, T51); SET(b, c, d, a, 5, 21, T52); SET(a, b, c, d, 12, 6, T53); SET(d, a, b, c, 3, 10, T54); SET(c, d, a, b, 10, 15, T55); SET(b, c, d, a, 1, 21, T56); SET(a, b, c, d, 8, 6, T57); SET(d, a, b, c, 15, 10, T58); SET(c, d, a, b, 6, 15, T59); SET(b, c, d, a, 13, 21, T60); SET(a, b, c, d, 4, 6, T61); SET(d, a, b, c, 11, 10, T62); SET(c, d, a, b, 2, 15, T63); SET(b, c, d, a, 9, 21, T64); #undef SET /* Then perform the following additions. (That is increment each of the four registers by the value it had before this block was started.) */ pms->state[0] += a; pms->state[1] += b; pms->state[2] += c; pms->state[3] += d; } void MD5_Init(MD5_CTX *pms) { pms->count[0] = pms->count[1] = 0; pms->state[0] = 0x67452301; pms->state[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; pms->state[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; pms->state[3] = 0x10325476; } void MD5_Update(MD5_CTX *pms, const uint8_t *data, size_t nbytes) { const uint8_t *p = data; size_t left = nbytes; size_t offset = (pms->count[0] >> 3) & 63; uint32_t nbits = (uint32_t)(nbytes << 3); if (nbytes <= 0) return; /* Update the message length. */ pms->count[1] += nbytes >> 29; pms->count[0] += nbits; if (pms->count[0] < nbits) pms->count[1]++; /* Process an initial partial block. */ if (offset) { size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy(pms->buffer + offset, p, copy); if (offset + copy < 64) return; p += copy; left -= copy; md5_process(pms, pms->buffer); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) md5_process(pms, p); /* Process a final partial block. */ if (left) memcpy(pms->buffer, p, left); } void MD5_Finish(MD5_CTX *pms, uint8_t *digest) { static const uint8_t pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; uint8_t data[8]; size_t i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) data[i] = (uint8_t)(pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ MD5_Update(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ MD5_Update(pms, data, 8); for (i = 0; i < 16; ++i) digest[i] = (uint8_t)(pms->state[i >> 2] >> ((i & 3) << 3)); } ================================================ FILE: ext/digest/md5/md5.h ================================================ /* Copyright (C) 1999 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321. It is derived directly from the text of the RFC and not from the reference implementation. The original and principal author of md5.h is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); added conditionalization for C++ compilation from Martin Purschke . 1999-05-03 lpd Original version. */ /* $OrigId: md5.h,v 1.2 2001/03/26 08:57:14 matz Exp $ */ /* $RoughId: md5.h,v 1.3 2002/02/24 08:14:31 knu Exp $ */ /* $Id$ */ #ifndef MD5_INCLUDED # define MD5_INCLUDED #include "defs.h" /* * This code has some adaptations for the Ghostscript environment, but it * will compile and run correctly in any environment with 8-bit chars and * 32-bit ints. Specifically, it assumes that if the following are * defined, they have the same meaning as in Ghostscript: P1, P2, P3. */ /* Define the state of the MD5 Algorithm. */ typedef struct md5_state_s { uint32_t count[2]; /* message length in bits, lsw first */ uint32_t state[4]; /* digest buffer */ uint8_t buffer[64]; /* accumulate block */ } MD5_CTX; #ifdef RUBY /* avoid name clash */ #define MD5_Init rb_Digest_MD5_Init #define MD5_Update rb_Digest_MD5_Update #define MD5_Finish rb_Digest_MD5_Finish #endif void MD5_Init _((MD5_CTX *pms)); void MD5_Update _((MD5_CTX *pms, const uint8_t *data, size_t nbytes)); void MD5_Finish _((MD5_CTX *pms, uint8_t *digest)); #define MD5_BLOCK_LENGTH 64 #define MD5_DIGEST_LENGTH 16 #define MD5_DIGEST_STRING_LENGTH (MD5_DIGEST_LENGTH * 2 + 1) #endif /* MD5_INCLUDED */ ================================================ FILE: ext/digest/md5/md5init.c ================================================ /* $RoughId: md5init.c,v 1.2 2001/07/13 19:49:10 knu Exp $ */ /* $Id$ */ #include "digest.h" #if defined(HAVE_OPENSSL_MD5_H) #include "md5ossl.h" #else #include "md5.h" #endif static rb_digest_metadata_t md5 = { RUBY_DIGEST_API_VERSION, MD5_DIGEST_LENGTH, MD5_BLOCK_LENGTH, sizeof(MD5_CTX), (rb_digest_hash_init_func_t)MD5_Init, (rb_digest_hash_update_func_t)MD5_Update, (rb_digest_hash_finish_func_t)MD5_Finish, }; /* * A class for calculating message digests using the MD5 * Message-Digest Algorithm by RSA Data Security, Inc., described in * RFC1321. */ void Init_md5() { VALUE mDigest, cDigest_Base, cDigest_MD5; rb_require("digest"); mDigest = rb_path2class("Digest"); cDigest_Base = rb_path2class("Digest::Base"); cDigest_MD5 = rb_define_class_under(mDigest, "MD5", cDigest_Base); rb_ivar_set(cDigest_MD5, rb_intern("metadata"), Data_Wrap_Struct(rb_cObject, 0, 0, &md5)); } ================================================ FILE: ext/digest/md5/md5ossl.c ================================================ /* $Id$ */ #include "md5ossl.h" void MD5_Finish(MD5_CTX *pctx, unsigned char *digest) { MD5_Final(digest, pctx); } ================================================ FILE: ext/digest/md5/md5ossl.h ================================================ /* $Id$ */ #ifndef MD5OSSL_H_INCLUDED #define MD5OSSL_H_INCLUDED #include #include #define MD5_BLOCK_LENGTH MD5_CBLOCK void MD5_Finish(MD5_CTX *pctx, unsigned char *digest); #endif ================================================ FILE: ext/digest/rmd160/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/digest/rmd160/depend ================================================ rmd160.o: rmd160.c rmd160.h $(srcdir)/../defs.h $(hdrdir)/ruby.h \ $(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/intern.h rmd160init.o: rmd160init.c $(srcdir)/../digest.h $(hdrdir)/ruby.h \ $(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/intern.h \ rmd160.h $(srcdir)/../defs.h rmd160ossl.o: rmd160ossl.h $(srcdir)/../defs.h ================================================ FILE: ext/digest/rmd160/extconf.rb ================================================ # $RoughId: extconf.rb,v 1.3 2001/08/14 19:54:51 knu Exp $ # $Id$ require "mkmf" $defs << "-DNDEBUG" << "-DHAVE_CONFIG_H" $INCFLAGS << " -I$(srcdir)/.." $objs = [ "rmd160init.#{$OBJEXT}" ] dir_config("openssl") if !with_config("bundled-rmd160") && have_library("crypto") && have_header("openssl/ripemd.h") $objs << "rmd160ossl.#{$OBJEXT}" else $objs << "rmd160.#{$OBJEXT}" end have_header("sys/cdefs.h") have_header("inttypes.h") have_header("unistd.h") $preload = %w[digest] create_makefile("digest/rmd160") ================================================ FILE: ext/digest/rmd160/rmd160.c ================================================ /* $NetBSD: rmd160.c,v 1.1.1.1 2001/03/06 11:21:05 agc Exp $ */ /* $RoughId: rmd160.c,v 1.2 2001/07/13 19:49:10 knu Exp $ */ /* $Id$ */ /********************************************************************\ * * FILE: rmd160.c * * CONTENTS: A sample C-implementation of the RIPEMD-160 * hash-function. * TARGET: any computer with an ANSI C compiler * * AUTHOR: Antoon Bosselaers, ESAT-COSIC * (Arranged for libc by Todd C. Miller) * DATE: 1 March 1996 * VERSION: 1.0 * * Copyright (c) Katholieke Universiteit Leuven * 1996, All Rights Reserved * \********************************************************************/ #include "rmd160.h" #ifndef lint /* __RCSID("$NetBSD: rmd160.c,v 1.1.1.1 2001/03/06 11:21:05 agc Exp $"); */ #endif /* not lint */ /* header files */ #ifdef HAVE_SYS_ENDIAN_H_ #include #endif #ifdef HAVE_MACHINE_ENDIAN_H_ #include #endif /* #include "namespace.h" */ #include #include #include #include #ifndef _DIAGASSERT #define _DIAGASSERT(cond) assert(cond) #endif /********************************************************************/ /* macro definitions */ /* collect four bytes into one word: */ #define BYTES_TO_DWORD(strptr) \ (((uint32_t) *((strptr)+3) << 24) | \ ((uint32_t) *((strptr)+2) << 16) | \ ((uint32_t) *((strptr)+1) << 8) | \ ((uint32_t) *(strptr))) /* ROL(x, n) cyclically rotates x over n bits to the left */ /* x must be of an unsigned 32 bits type and 0 <= n < 32. */ #define ROL(x, n) (((x) << (n)) | ((x) >> (32-(n)))) /* the three basic functions F(), G() and H() */ #define F(x, y, z) ((x) ^ (y) ^ (z)) #define G(x, y, z) (((x) & (y)) | (~(x) & (z))) #define H(x, y, z) (((x) | ~(y)) ^ (z)) #define I(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define J(x, y, z) ((x) ^ ((y) | ~(z))) /* the eight basic operations FF() through III() */ #define FF(a, b, c, d, e, x, s) { \ (a) += F((b), (c), (d)) + (x); \ (a) = ROL((a), (s)) + (e); \ (c) = ROL((c), 10); \ } #define GG(a, b, c, d, e, x, s) { \ (a) += G((b), (c), (d)) + (x) + 0x5a827999U; \ (a) = ROL((a), (s)) + (e); \ (c) = ROL((c), 10); \ } #define HH(a, b, c, d, e, x, s) { \ (a) += H((b), (c), (d)) + (x) + 0x6ed9eba1U; \ (a) = ROL((a), (s)) + (e); \ (c) = ROL((c), 10); \ } #define II(a, b, c, d, e, x, s) { \ (a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcU; \ (a) = ROL((a), (s)) + (e); \ (c) = ROL((c), 10); \ } #define JJ(a, b, c, d, e, x, s) { \ (a) += J((b), (c), (d)) + (x) + 0xa953fd4eU; \ (a) = ROL((a), (s)) + (e); \ (c) = ROL((c), 10); \ } #define FFF(a, b, c, d, e, x, s) { \ (a) += F((b), (c), (d)) + (x); \ (a) = ROL((a), (s)) + (e); \ (c) = ROL((c), 10); \ } #define GGG(a, b, c, d, e, x, s) { \ (a) += G((b), (c), (d)) + (x) + 0x7a6d76e9U; \ (a) = ROL((a), (s)) + (e); \ (c) = ROL((c), 10); \ } #define HHH(a, b, c, d, e, x, s) { \ (a) += H((b), (c), (d)) + (x) + 0x6d703ef3U; \ (a) = ROL((a), (s)) + (e); \ (c) = ROL((c), 10); \ } #define III(a, b, c, d, e, x, s) { \ (a) += I((b), (c), (d)) + (x) + 0x5c4dd124U; \ (a) = ROL((a), (s)) + (e); \ (c) = ROL((c), 10); \ } #define JJJ(a, b, c, d, e, x, s) { \ (a) += J((b), (c), (d)) + (x) + 0x50a28be6U; \ (a) = ROL((a), (s)) + (e); \ (c) = ROL((c), 10); \ } /********************************************************************/ void RMD160_Init(RMD160_CTX *context) { _DIAGASSERT(context != NULL); /* ripemd-160 initialization constants */ context->state[0] = 0x67452301U; context->state[1] = 0xefcdab89U; context->state[2] = 0x98badcfeU; context->state[3] = 0x10325476U; context->state[4] = 0xc3d2e1f0U; context->length[0] = context->length[1] = 0; context->buflen = 0; } /********************************************************************/ void RMD160_Transform(uint32_t state[5], const uint32_t block[16]) { uint32_t aa, bb, cc, dd, ee; uint32_t aaa, bbb, ccc, ddd, eee; _DIAGASSERT(state != NULL); _DIAGASSERT(block != NULL); aa = aaa = state[0]; bb = bbb = state[1]; cc = ccc = state[2]; dd = ddd = state[3]; ee = eee = state[4]; /* round 1 */ FF(aa, bb, cc, dd, ee, block[ 0], 11); FF(ee, aa, bb, cc, dd, block[ 1], 14); FF(dd, ee, aa, bb, cc, block[ 2], 15); FF(cc, dd, ee, aa, bb, block[ 3], 12); FF(bb, cc, dd, ee, aa, block[ 4], 5); FF(aa, bb, cc, dd, ee, block[ 5], 8); FF(ee, aa, bb, cc, dd, block[ 6], 7); FF(dd, ee, aa, bb, cc, block[ 7], 9); FF(cc, dd, ee, aa, bb, block[ 8], 11); FF(bb, cc, dd, ee, aa, block[ 9], 13); FF(aa, bb, cc, dd, ee, block[10], 14); FF(ee, aa, bb, cc, dd, block[11], 15); FF(dd, ee, aa, bb, cc, block[12], 6); FF(cc, dd, ee, aa, bb, block[13], 7); FF(bb, cc, dd, ee, aa, block[14], 9); FF(aa, bb, cc, dd, ee, block[15], 8); /* round 2 */ GG(ee, aa, bb, cc, dd, block[ 7], 7); GG(dd, ee, aa, bb, cc, block[ 4], 6); GG(cc, dd, ee, aa, bb, block[13], 8); GG(bb, cc, dd, ee, aa, block[ 1], 13); GG(aa, bb, cc, dd, ee, block[10], 11); GG(ee, aa, bb, cc, dd, block[ 6], 9); GG(dd, ee, aa, bb, cc, block[15], 7); GG(cc, dd, ee, aa, bb, block[ 3], 15); GG(bb, cc, dd, ee, aa, block[12], 7); GG(aa, bb, cc, dd, ee, block[ 0], 12); GG(ee, aa, bb, cc, dd, block[ 9], 15); GG(dd, ee, aa, bb, cc, block[ 5], 9); GG(cc, dd, ee, aa, bb, block[ 2], 11); GG(bb, cc, dd, ee, aa, block[14], 7); GG(aa, bb, cc, dd, ee, block[11], 13); GG(ee, aa, bb, cc, dd, block[ 8], 12); /* round 3 */ HH(dd, ee, aa, bb, cc, block[ 3], 11); HH(cc, dd, ee, aa, bb, block[10], 13); HH(bb, cc, dd, ee, aa, block[14], 6); HH(aa, bb, cc, dd, ee, block[ 4], 7); HH(ee, aa, bb, cc, dd, block[ 9], 14); HH(dd, ee, aa, bb, cc, block[15], 9); HH(cc, dd, ee, aa, bb, block[ 8], 13); HH(bb, cc, dd, ee, aa, block[ 1], 15); HH(aa, bb, cc, dd, ee, block[ 2], 14); HH(ee, aa, bb, cc, dd, block[ 7], 8); HH(dd, ee, aa, bb, cc, block[ 0], 13); HH(cc, dd, ee, aa, bb, block[ 6], 6); HH(bb, cc, dd, ee, aa, block[13], 5); HH(aa, bb, cc, dd, ee, block[11], 12); HH(ee, aa, bb, cc, dd, block[ 5], 7); HH(dd, ee, aa, bb, cc, block[12], 5); /* round 4 */ II(cc, dd, ee, aa, bb, block[ 1], 11); II(bb, cc, dd, ee, aa, block[ 9], 12); II(aa, bb, cc, dd, ee, block[11], 14); II(ee, aa, bb, cc, dd, block[10], 15); II(dd, ee, aa, bb, cc, block[ 0], 14); II(cc, dd, ee, aa, bb, block[ 8], 15); II(bb, cc, dd, ee, aa, block[12], 9); II(aa, bb, cc, dd, ee, block[ 4], 8); II(ee, aa, bb, cc, dd, block[13], 9); II(dd, ee, aa, bb, cc, block[ 3], 14); II(cc, dd, ee, aa, bb, block[ 7], 5); II(bb, cc, dd, ee, aa, block[15], 6); II(aa, bb, cc, dd, ee, block[14], 8); II(ee, aa, bb, cc, dd, block[ 5], 6); II(dd, ee, aa, bb, cc, block[ 6], 5); II(cc, dd, ee, aa, bb, block[ 2], 12); /* round 5 */ JJ(bb, cc, dd, ee, aa, block[ 4], 9); JJ(aa, bb, cc, dd, ee, block[ 0], 15); JJ(ee, aa, bb, cc, dd, block[ 5], 5); JJ(dd, ee, aa, bb, cc, block[ 9], 11); JJ(cc, dd, ee, aa, bb, block[ 7], 6); JJ(bb, cc, dd, ee, aa, block[12], 8); JJ(aa, bb, cc, dd, ee, block[ 2], 13); JJ(ee, aa, bb, cc, dd, block[10], 12); JJ(dd, ee, aa, bb, cc, block[14], 5); JJ(cc, dd, ee, aa, bb, block[ 1], 12); JJ(bb, cc, dd, ee, aa, block[ 3], 13); JJ(aa, bb, cc, dd, ee, block[ 8], 14); JJ(ee, aa, bb, cc, dd, block[11], 11); JJ(dd, ee, aa, bb, cc, block[ 6], 8); JJ(cc, dd, ee, aa, bb, block[15], 5); JJ(bb, cc, dd, ee, aa, block[13], 6); /* parallel round 1 */ JJJ(aaa, bbb, ccc, ddd, eee, block[ 5], 8); JJJ(eee, aaa, bbb, ccc, ddd, block[14], 9); JJJ(ddd, eee, aaa, bbb, ccc, block[ 7], 9); JJJ(ccc, ddd, eee, aaa, bbb, block[ 0], 11); JJJ(bbb, ccc, ddd, eee, aaa, block[ 9], 13); JJJ(aaa, bbb, ccc, ddd, eee, block[ 2], 15); JJJ(eee, aaa, bbb, ccc, ddd, block[11], 15); JJJ(ddd, eee, aaa, bbb, ccc, block[ 4], 5); JJJ(ccc, ddd, eee, aaa, bbb, block[13], 7); JJJ(bbb, ccc, ddd, eee, aaa, block[ 6], 7); JJJ(aaa, bbb, ccc, ddd, eee, block[15], 8); JJJ(eee, aaa, bbb, ccc, ddd, block[ 8], 11); JJJ(ddd, eee, aaa, bbb, ccc, block[ 1], 14); JJJ(ccc, ddd, eee, aaa, bbb, block[10], 14); JJJ(bbb, ccc, ddd, eee, aaa, block[ 3], 12); JJJ(aaa, bbb, ccc, ddd, eee, block[12], 6); /* parallel round 2 */ III(eee, aaa, bbb, ccc, ddd, block[ 6], 9); III(ddd, eee, aaa, bbb, ccc, block[11], 13); III(ccc, ddd, eee, aaa, bbb, block[ 3], 15); III(bbb, ccc, ddd, eee, aaa, block[ 7], 7); III(aaa, bbb, ccc, ddd, eee, block[ 0], 12); III(eee, aaa, bbb, ccc, ddd, block[13], 8); III(ddd, eee, aaa, bbb, ccc, block[ 5], 9); III(ccc, ddd, eee, aaa, bbb, block[10], 11); III(bbb, ccc, ddd, eee, aaa, block[14], 7); III(aaa, bbb, ccc, ddd, eee, block[15], 7); III(eee, aaa, bbb, ccc, ddd, block[ 8], 12); III(ddd, eee, aaa, bbb, ccc, block[12], 7); III(ccc, ddd, eee, aaa, bbb, block[ 4], 6); III(bbb, ccc, ddd, eee, aaa, block[ 9], 15); III(aaa, bbb, ccc, ddd, eee, block[ 1], 13); III(eee, aaa, bbb, ccc, ddd, block[ 2], 11); /* parallel round 3 */ HHH(ddd, eee, aaa, bbb, ccc, block[15], 9); HHH(ccc, ddd, eee, aaa, bbb, block[ 5], 7); HHH(bbb, ccc, ddd, eee, aaa, block[ 1], 15); HHH(aaa, bbb, ccc, ddd, eee, block[ 3], 11); HHH(eee, aaa, bbb, ccc, ddd, block[ 7], 8); HHH(ddd, eee, aaa, bbb, ccc, block[14], 6); HHH(ccc, ddd, eee, aaa, bbb, block[ 6], 6); HHH(bbb, ccc, ddd, eee, aaa, block[ 9], 14); HHH(aaa, bbb, ccc, ddd, eee, block[11], 12); HHH(eee, aaa, bbb, ccc, ddd, block[ 8], 13); HHH(ddd, eee, aaa, bbb, ccc, block[12], 5); HHH(ccc, ddd, eee, aaa, bbb, block[ 2], 14); HHH(bbb, ccc, ddd, eee, aaa, block[10], 13); HHH(aaa, bbb, ccc, ddd, eee, block[ 0], 13); HHH(eee, aaa, bbb, ccc, ddd, block[ 4], 7); HHH(ddd, eee, aaa, bbb, ccc, block[13], 5); /* parallel round 4 */ GGG(ccc, ddd, eee, aaa, bbb, block[ 8], 15); GGG(bbb, ccc, ddd, eee, aaa, block[ 6], 5); GGG(aaa, bbb, ccc, ddd, eee, block[ 4], 8); GGG(eee, aaa, bbb, ccc, ddd, block[ 1], 11); GGG(ddd, eee, aaa, bbb, ccc, block[ 3], 14); GGG(ccc, ddd, eee, aaa, bbb, block[11], 14); GGG(bbb, ccc, ddd, eee, aaa, block[15], 6); GGG(aaa, bbb, ccc, ddd, eee, block[ 0], 14); GGG(eee, aaa, bbb, ccc, ddd, block[ 5], 6); GGG(ddd, eee, aaa, bbb, ccc, block[12], 9); GGG(ccc, ddd, eee, aaa, bbb, block[ 2], 12); GGG(bbb, ccc, ddd, eee, aaa, block[13], 9); GGG(aaa, bbb, ccc, ddd, eee, block[ 9], 12); GGG(eee, aaa, bbb, ccc, ddd, block[ 7], 5); GGG(ddd, eee, aaa, bbb, ccc, block[10], 15); GGG(ccc, ddd, eee, aaa, bbb, block[14], 8); /* parallel round 5 */ FFF(bbb, ccc, ddd, eee, aaa, block[12] , 8); FFF(aaa, bbb, ccc, ddd, eee, block[15] , 5); FFF(eee, aaa, bbb, ccc, ddd, block[10] , 12); FFF(ddd, eee, aaa, bbb, ccc, block[ 4] , 9); FFF(ccc, ddd, eee, aaa, bbb, block[ 1] , 12); FFF(bbb, ccc, ddd, eee, aaa, block[ 5] , 5); FFF(aaa, bbb, ccc, ddd, eee, block[ 8] , 14); FFF(eee, aaa, bbb, ccc, ddd, block[ 7] , 6); FFF(ddd, eee, aaa, bbb, ccc, block[ 6] , 8); FFF(ccc, ddd, eee, aaa, bbb, block[ 2] , 13); FFF(bbb, ccc, ddd, eee, aaa, block[13] , 6); FFF(aaa, bbb, ccc, ddd, eee, block[14] , 5); FFF(eee, aaa, bbb, ccc, ddd, block[ 0] , 15); FFF(ddd, eee, aaa, bbb, ccc, block[ 3] , 13); FFF(ccc, ddd, eee, aaa, bbb, block[ 9] , 11); FFF(bbb, ccc, ddd, eee, aaa, block[11] , 11); /* combine results */ ddd += cc + state[1]; /* final result for state[0] */ state[1] = state[2] + dd + eee; state[2] = state[3] + ee + aaa; state[3] = state[4] + aa + bbb; state[4] = state[0] + bb + ccc; state[0] = ddd; } /********************************************************************/ void RMD160_Update(RMD160_CTX *context, const uint8_t *data, size_t nbytes) { uint32_t X[16]; uint32_t ofs = 0; uint32_t i; #ifdef WORDS_BIGENDIAN uint32_t j; #endif _DIAGASSERT(context != NULL); _DIAGASSERT(data != NULL); /* update length[] */ if (context->length[0] + nbytes < context->length[0]) context->length[1]++; /* overflow to msb of length */ context->length[0] += nbytes; (void)memset(X, 0, sizeof(X)); if ( context->buflen + nbytes < 64 ) { (void)memcpy(context->bbuffer + context->buflen, data, nbytes); context->buflen += nbytes; } else { /* process first block */ ofs = 64 - context->buflen; (void)memcpy(context->bbuffer + context->buflen, data, ofs); #ifndef WORDS_BIGENDIAN (void)memcpy(X, context->bbuffer, sizeof(X)); #else for (j=0; j < 16; j++) X[j] = BYTES_TO_DWORD(context->bbuffer + (4 * j)); #endif RMD160_Transform(context->state, X); nbytes -= ofs; /* process remaining complete blocks */ for (i = 0; i < (nbytes >> 6); i++) { #ifndef WORDS_BIGENDIAN (void)memcpy(X, data + (64 * i) + ofs, sizeof(X)); #else for (j=0; j < 16; j++) X[j] = BYTES_TO_DWORD(data + (64 * i) + (4 * j) + ofs); #endif RMD160_Transform(context->state, X); } /* * Put last bytes from data into context's buffer */ context->buflen = nbytes & 63; memcpy(context->bbuffer, data + (64 * i) + ofs, context->buflen); } } /********************************************************************/ void RMD160_Finish(RMD160_CTX *context, uint8_t digest[20]) { uint32_t i; uint32_t X[16]; #ifdef WORDS_BIGENDIAN uint32_t j; #endif _DIAGASSERT(digest != NULL); _DIAGASSERT(context != NULL); /* append the bit m_n == 1 */ context->bbuffer[context->buflen] = (uint8_t)'\200'; (void)memset(context->bbuffer + context->buflen + 1, 0, 63 - context->buflen); #ifndef WORDS_BIGENDIAN (void)memcpy(X, context->bbuffer, sizeof(X)); #else for (j=0; j < 16; j++) X[j] = BYTES_TO_DWORD(context->bbuffer + (4 * j)); #endif if ((context->buflen) > 55) { /* length goes to next block */ RMD160_Transform(context->state, X); (void)memset(X, 0, sizeof(X)); } /* append length in bits */ X[14] = context->length[0] << 3; X[15] = (context->length[0] >> 29) | (context->length[1] << 3); RMD160_Transform(context->state, X); if (digest != NULL) { for (i = 0; i < 20; i += 4) { /* extracts the 8 least significant bits. */ digest[i] = context->state[i>>2]; digest[i + 1] = (context->state[i>>2] >> 8); digest[i + 2] = (context->state[i>>2] >> 16); digest[i + 3] = (context->state[i>>2] >> 24); } } } /************************ end of file rmd160.c **********************/ ================================================ FILE: ext/digest/rmd160/rmd160.h ================================================ /* $NetBSD: rmd160.h,v 1.2 2000/07/07 10:47:06 ad Exp $ */ /* $RoughId: rmd160.h,v 1.3 2002/02/24 08:14:31 knu Exp $ */ /* $Id$ */ /********************************************************************\ * * FILE: rmd160.h * * CONTENTS: Header file for a sample C-implementation of the * RIPEMD-160 hash-function. * TARGET: any computer with an ANSI C compiler * * AUTHOR: Antoon Bosselaers, ESAT-COSIC * DATE: 1 March 1996 * VERSION: 1.0 * * Copyright (c) Katholieke Universiteit Leuven * 1996, All Rights Reserved * \********************************************************************/ /* * from OpenBSD: rmd160.h,v 1.4 1999/08/16 09:59:04 millert Exp */ #ifndef _RMD160_H_ #define _RMD160_H_ #include "defs.h" typedef struct { uint32_t state[5]; /* state (ABCDE) */ uint32_t length[2]; /* number of bits */ uint8_t bbuffer[64]; /* overflow buffer */ uint32_t buflen; /* number of chars in bbuffer */ } RMD160_CTX; #ifdef RUBY #define RMD160_Init rb_Digest_RMD160_Init #define RMD160_Transform rb_Digest_RMD160_Transform #define RMD160_Update rb_Digest_RMD160_Update #define RMD160_Finish rb_Digest_RMD160_Finish #endif __BEGIN_DECLS void RMD160_Init _((RMD160_CTX *)); void RMD160_Transform _((uint32_t[5], const uint32_t[16])); void RMD160_Update _((RMD160_CTX *, const uint8_t *, size_t)); void RMD160_Finish _((RMD160_CTX *, uint8_t[20])); __END_DECLS #define RMD160_BLOCK_LENGTH 64 #define RMD160_DIGEST_LENGTH 20 #define RMD160_DIGEST_STRING_LENGTH (RMD160_DIGEST_LENGTH * 2 + 1) #endif /* !_RMD160_H_ */ ================================================ FILE: ext/digest/rmd160/rmd160init.c ================================================ /* $RoughId: rmd160init.c,v 1.3 2001/07/13 20:00:43 knu Exp $ */ /* $Id$ */ #include "digest.h" #if defined(HAVE_OPENSSL_RIPEMD_H) #include "rmd160ossl.h" #else #include "rmd160.h" #endif static rb_digest_metadata_t rmd160 = { RUBY_DIGEST_API_VERSION, RMD160_DIGEST_LENGTH, RMD160_BLOCK_LENGTH, sizeof(RMD160_CTX), (rb_digest_hash_init_func_t)RMD160_Init, (rb_digest_hash_update_func_t)RMD160_Update, (rb_digest_hash_finish_func_t)RMD160_Finish, }; /* * A class for calculating message digests using RIPEMD-160 * cryptographic hash function, designed by Hans Dobbertin, Antoon * Bosselaers, and Bart Preneel. */ void Init_rmd160() { VALUE mDigest, cDigest_Base, cDigest_RMD160; rb_require("digest"); mDigest = rb_path2class("Digest"); cDigest_Base = rb_path2class("Digest::Base"); cDigest_RMD160 = rb_define_class_under(mDigest, "RMD160", cDigest_Base); rb_ivar_set(cDigest_RMD160, rb_intern("metadata"), Data_Wrap_Struct(rb_cObject, 0, 0, &rmd160)); } ================================================ FILE: ext/digest/rmd160/rmd160ossl.c ================================================ /* $Id$ */ #include "defs.h" #include "rmd160ossl.h" void RMD160_Finish(RMD160_CTX *ctx, char *buf) { RIPEMD160_Final((unsigned char *)buf, ctx); } ================================================ FILE: ext/digest/rmd160/rmd160ossl.h ================================================ /* $Id$ */ #ifndef RMD160OSSL_H_INCLUDED #define RMD160OSSL_H_INCLUDED #include #include #define RMD160_CTX RIPEMD160_CTX #define RMD160_Init RIPEMD160_Init #define RMD160_Update RIPEMD160_Update #define RMD160_BLOCK_LENGTH RIPEMD160_CBLOCK #define RMD160_DIGEST_LENGTH RIPEMD160_DIGEST_LENGTH void RMD160_Finish(RMD160_CTX *ctx, char *buf); #endif ================================================ FILE: ext/digest/sha1/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/digest/sha1/depend ================================================ sha1.o: sha1.c sha1.h $(srcdir)/../defs.h $(hdrdir)/ruby.h \ $(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/intern.h sha1init.o: sha1init.c $(srcdir)/../digest.h $(hdrdir)/ruby.h \ $(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/intern.h \ sha1.h $(srcdir)/../defs.h sha1ossl.o: sha1ossl.h $(srcdir)/../defs.h ================================================ FILE: ext/digest/sha1/extconf.rb ================================================ # $RoughId: extconf.rb,v 1.3 2001/08/14 19:54:51 knu Exp $ # $Id$ require "mkmf" $defs << "-DHAVE_CONFIG_H" $INCFLAGS << " -I$(srcdir)/.." $objs = [ "sha1init.#{$OBJEXT}" ] dir_config("openssl") if !with_config("bundled-sha1") && have_library("crypto") && have_header("openssl/sha.h") $objs << "sha1ossl.#{$OBJEXT}" else $objs << "sha1.#{$OBJEXT}" end have_header("sys/cdefs.h") have_header("inttypes.h") have_header("unistd.h") $preload = %w[digest] create_makefile("digest/sha1") ================================================ FILE: ext/digest/sha1/sha1.c ================================================ /* $NetBSD: sha1.c,v 1.2 2001/03/22 09:51:48 agc Exp $ */ /* $OpenBSD: sha1.c,v 1.9 1997/07/23 21:12:32 kstailey Exp $ */ /* $RoughId: sha1.c,v 1.2 2001/07/13 19:49:10 knu Exp $ */ /* $Id$ */ /* * SHA-1 in C * By Steve Reid * 100% Public Domain * * Test Vectors (from FIPS PUB 180-1) * "abc" * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 * A million repetitions of "a" * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F */ #include "sha1.h" #define SHA1HANDSOFF /* Copies data before messing with it. */ #if defined(_KERNEL) || defined(_STANDALONE) #include #include #define _DIAGASSERT(x) (void)0 #else /* #include "namespace.h" */ #include #include #endif #ifndef _DIAGASSERT #define _DIAGASSERT(cond) assert(cond) #endif /* * XXX Kludge until there is resolution regarding mem*() functions * XXX in the kernel. */ #if defined(_KERNEL) || defined(_STANDALONE) #define memcpy(s, d, l) bcopy((d), (s), (l)) #endif #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) /* * blk0() and blk() perform the initial expand. * I got the idea of expanding during the round function from SSLeay */ #ifndef WORDS_BIGENDIAN # define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ |(rol(block->l[i],8)&0x00FF00FF)) #else # define blk0(i) block->l[i] #endif #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ ^block->l[(i+2)&15]^block->l[i&15],1)) /* * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1 */ #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); typedef union { uint8_t c[64]; uint32_t l[16]; } CHAR64LONG16; #ifdef __sparc_v9__ void do_R01(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *); void do_R2(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *); void do_R3(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *); void do_R4(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *); #define nR0(v,w,x,y,z,i) R0(*v,*w,*x,*y,*z,i) #define nR1(v,w,x,y,z,i) R1(*v,*w,*x,*y,*z,i) #define nR2(v,w,x,y,z,i) R2(*v,*w,*x,*y,*z,i) #define nR3(v,w,x,y,z,i) R3(*v,*w,*x,*y,*z,i) #define nR4(v,w,x,y,z,i) R4(*v,*w,*x,*y,*z,i) void do_R01(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *block) { nR0(a,b,c,d,e, 0); nR0(e,a,b,c,d, 1); nR0(d,e,a,b,c, 2); nR0(c,d,e,a,b, 3); nR0(b,c,d,e,a, 4); nR0(a,b,c,d,e, 5); nR0(e,a,b,c,d, 6); nR0(d,e,a,b,c, 7); nR0(c,d,e,a,b, 8); nR0(b,c,d,e,a, 9); nR0(a,b,c,d,e,10); nR0(e,a,b,c,d,11); nR0(d,e,a,b,c,12); nR0(c,d,e,a,b,13); nR0(b,c,d,e,a,14); nR0(a,b,c,d,e,15); nR1(e,a,b,c,d,16); nR1(d,e,a,b,c,17); nR1(c,d,e,a,b,18); nR1(b,c,d,e,a,19); } void do_R2(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *block) { nR2(a,b,c,d,e,20); nR2(e,a,b,c,d,21); nR2(d,e,a,b,c,22); nR2(c,d,e,a,b,23); nR2(b,c,d,e,a,24); nR2(a,b,c,d,e,25); nR2(e,a,b,c,d,26); nR2(d,e,a,b,c,27); nR2(c,d,e,a,b,28); nR2(b,c,d,e,a,29); nR2(a,b,c,d,e,30); nR2(e,a,b,c,d,31); nR2(d,e,a,b,c,32); nR2(c,d,e,a,b,33); nR2(b,c,d,e,a,34); nR2(a,b,c,d,e,35); nR2(e,a,b,c,d,36); nR2(d,e,a,b,c,37); nR2(c,d,e,a,b,38); nR2(b,c,d,e,a,39); } void do_R3(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *block) { nR3(a,b,c,d,e,40); nR3(e,a,b,c,d,41); nR3(d,e,a,b,c,42); nR3(c,d,e,a,b,43); nR3(b,c,d,e,a,44); nR3(a,b,c,d,e,45); nR3(e,a,b,c,d,46); nR3(d,e,a,b,c,47); nR3(c,d,e,a,b,48); nR3(b,c,d,e,a,49); nR3(a,b,c,d,e,50); nR3(e,a,b,c,d,51); nR3(d,e,a,b,c,52); nR3(c,d,e,a,b,53); nR3(b,c,d,e,a,54); nR3(a,b,c,d,e,55); nR3(e,a,b,c,d,56); nR3(d,e,a,b,c,57); nR3(c,d,e,a,b,58); nR3(b,c,d,e,a,59); } void do_R4(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *block) { nR4(a,b,c,d,e,60); nR4(e,a,b,c,d,61); nR4(d,e,a,b,c,62); nR4(c,d,e,a,b,63); nR4(b,c,d,e,a,64); nR4(a,b,c,d,e,65); nR4(e,a,b,c,d,66); nR4(d,e,a,b,c,67); nR4(c,d,e,a,b,68); nR4(b,c,d,e,a,69); nR4(a,b,c,d,e,70); nR4(e,a,b,c,d,71); nR4(d,e,a,b,c,72); nR4(c,d,e,a,b,73); nR4(b,c,d,e,a,74); nR4(a,b,c,d,e,75); nR4(e,a,b,c,d,76); nR4(d,e,a,b,c,77); nR4(c,d,e,a,b,78); nR4(b,c,d,e,a,79); } #endif /* * Hash a single 512-bit block. This is the core of the algorithm. */ void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]) { uint32_t a, b, c, d, e; CHAR64LONG16 *block; #ifdef SHA1HANDSOFF CHAR64LONG16 workspace; #endif _DIAGASSERT(buffer != 0); _DIAGASSERT(state != 0); #ifdef SHA1HANDSOFF block = &workspace; (void)memcpy(block, buffer, 64); #else block = (CHAR64LONG16 *)(void *)buffer; #endif /* Copy context->state[] to working vars */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; #ifdef __sparc_v9__ do_R01(&a, &b, &c, &d, &e, block); do_R2(&a, &b, &c, &d, &e, block); do_R3(&a, &b, &c, &d, &e, block); do_R4(&a, &b, &c, &d, &e, block); #else /* 4 rounds of 20 operations each. Loop unrolled. */ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); #endif /* Add the working vars back into context.state[] */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; /* Wipe variables */ a = b = c = d = e = 0; } /* * SHA1_Init - Initialize new context */ void SHA1_Init(SHA1_CTX *context) { _DIAGASSERT(context != 0); /* SHA1 initialization constants */ context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; context->state[2] = 0x98BADCFE; context->state[3] = 0x10325476; context->state[4] = 0xC3D2E1F0; context->count[0] = context->count[1] = 0; } /* * Run your data through this. */ void SHA1_Update(SHA1_CTX *context, const uint8_t *data, size_t len) { uint32_t i, j; _DIAGASSERT(context != 0); _DIAGASSERT(data != 0); j = context->count[0]; if ((context->count[0] += len << 3) < j) context->count[1] += (len>>29)+1; j = (j >> 3) & 63; if ((j + len) > 63) { (void)memcpy(&context->buffer[j], data, (i = 64-j)); SHA1_Transform(context->state, context->buffer); for ( ; i + 63 < len; i += 64) SHA1_Transform(context->state, &data[i]); j = 0; } else { i = 0; } (void)memcpy(&context->buffer[j], &data[i], len - i); } /* * Add padding and return the message digest. */ void SHA1_Finish(SHA1_CTX* context, uint8_t digest[20]) { size_t i; uint8_t finalcount[8]; _DIAGASSERT(digest != 0); _DIAGASSERT(context != 0); for (i = 0; i < 8; i++) { finalcount[i] = (uint8_t)((context->count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ } SHA1_Update(context, (const uint8_t *)"\200", 1); while ((context->count[0] & 504) != 448) SHA1_Update(context, (const uint8_t *)"\0", 1); SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */ if (digest) { for (i = 0; i < 20; i++) digest[i] = (uint8_t) ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); } } ================================================ FILE: ext/digest/sha1/sha1.h ================================================ /* $NetBSD: sha1.h,v 1.2 1998/05/29 22:55:44 thorpej Exp $ */ /* $RoughId: sha1.h,v 1.3 2002/02/24 08:14:32 knu Exp $ */ /* $Id$ */ /* * SHA-1 in C * By Steve Reid * 100% Public Domain */ #ifndef _SYS_SHA1_H_ #define _SYS_SHA1_H_ #include "defs.h" typedef struct { uint32_t state[5]; uint32_t count[2]; uint8_t buffer[64]; } SHA1_CTX; #ifdef RUBY /* avoid name clash */ #define SHA1_Transform rb_Digest_SHA1_Transform #define SHA1_Init rb_Digest_SHA1_Init #define SHA1_Update rb_Digest_SHA1_Update #define SHA1_Finish rb_Digest_SHA1_Finish #endif void SHA1_Transform _((uint32_t state[5], const uint8_t buffer[64])); void SHA1_Init _((SHA1_CTX *context)); void SHA1_Update _((SHA1_CTX *context, const uint8_t *data, size_t len)); void SHA1_Finish _((SHA1_CTX *context, uint8_t digest[20])); #define SHA1_BLOCK_LENGTH 64 #define SHA1_DIGEST_LENGTH 20 #define SHA1_DIGEST_STRING_LENGTH (SHA1_DIGEST_LENGTH * 2 + 1) #endif /* _SYS_SHA1_H_ */ ================================================ FILE: ext/digest/sha1/sha1init.c ================================================ /* $RoughId: sha1init.c,v 1.2 2001/07/13 19:49:10 knu Exp $ */ /* $Id$ */ #include "digest.h" #if defined(HAVE_OPENSSL_SHA_H) #include "sha1ossl.h" #else #include "sha1.h" #endif static rb_digest_metadata_t sha1 = { RUBY_DIGEST_API_VERSION, SHA1_DIGEST_LENGTH, SHA1_BLOCK_LENGTH, sizeof(SHA1_CTX), (rb_digest_hash_init_func_t)SHA1_Init, (rb_digest_hash_update_func_t)SHA1_Update, (rb_digest_hash_finish_func_t)SHA1_Finish, }; /* * A class for calculating message digests using the SHA-1 Secure Hash * Algorithm by NIST (the US' National Institute of Standards and * Technology), described in FIPS PUB 180-1. */ void Init_sha1() { VALUE mDigest, cDigest_Base, cDigest_SHA1; rb_require("digest"); mDigest = rb_path2class("Digest"); cDigest_Base = rb_path2class("Digest::Base"); cDigest_SHA1 = rb_define_class_under(mDigest, "SHA1", cDigest_Base); rb_ivar_set(cDigest_SHA1, rb_intern("metadata"), Data_Wrap_Struct(rb_cObject, 0, 0, &sha1)); } ================================================ FILE: ext/digest/sha1/sha1ossl.c ================================================ /* $Id$ */ #include "defs.h" #include "sha1ossl.h" void SHA1_Finish(SHA1_CTX *ctx, char *buf) { SHA1_Final((unsigned char *)buf, ctx); } ================================================ FILE: ext/digest/sha1/sha1ossl.h ================================================ /* $Id$ */ #ifndef SHA1OSSL_H_INCLUDED #define SHA1OSSL_H_INCLUDED #include #include #define SHA1_CTX SHA_CTX #ifdef SHA_BLOCK_LENGTH #define SHA1_BLOCK_LENGTH SHA_BLOCK_LENGTH #else #define SHA1_BLOCK_LENGTH SHA_CBLOCK #endif #define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH void SHA1_Finish(SHA1_CTX *ctx, char *buf); #endif ================================================ FILE: ext/digest/sha2/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/digest/sha2/depend ================================================ sha2.o: sha2.c sha2.h $(srcdir)/../defs.h $(hdrdir)/ruby.h \ $(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/intern.h sha2init.o: sha2init.c $(srcdir)/../digest.h $(hdrdir)/ruby.h \ $(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/intern.h \ sha2.h $(srcdir)/../defs.h ================================================ FILE: ext/digest/sha2/extconf.rb ================================================ # $RoughId: extconf.rb,v 1.4 2001/08/14 19:54:51 knu Exp $ # $Id$ require "mkmf" $defs << "-DHAVE_CONFIG_H" $INCFLAGS << " -I$(srcdir)/.." $objs = [ "sha2.#{$OBJEXT}", "sha2init.#{$OBJEXT}", ] have_header("sys/cdefs.h") have_header("inttypes.h") have_header("unistd.h") $preload = %w[digest] if have_type("uint64_t", "defs.h", $defs.join(' ')) create_makefile("digest/sha2") end ================================================ FILE: ext/digest/sha2/lib/sha2.rb ================================================ #-- # sha2.rb - defines Digest::SHA2 class which wraps up the SHA256, # SHA384, and SHA512 classes. #++ # Copyright (c) 2006 Akinori MUSHA # # All rights reserved. You can redistribute and/or modify it under the same # terms as Ruby. # # $Id$ require 'digest' module Digest # # A meta digest provider class for SHA256, SHA384 and SHA512. # class SHA2 < Digest::Class # call-seq: # Digest::SHA2.new(bitlen = 256) -> digest_obj # # Creates a new SHA2 hash object with a given bit length. def initialize(bitlen = 256) case bitlen when 256 @sha2 = Digest::SHA256.new when 384 @sha2 = Digest::SHA384.new when 512 @sha2 = Digest::SHA512.new else raise ArgumentError, "unsupported bit length: %s" % bitlen.inspect end @bitlen = bitlen end # :nodoc: def reset @sha2.reset self end # :nodoc: def update(str) @sha2.update(str) self end alias << update def finish @sha2.digest! end private :finish def block_length @sha2.block_length end def digest_length @sha2.digest_length end # :nodoc: def initialize_copy(other) @sha2 = other.instance_eval { @sha2.clone } end # :nodoc: def inspect "#<%s:%d %s>" % [self.class.name, @bitlen, hexdigest] end end end ================================================ FILE: ext/digest/sha2/sha2.c ================================================ /* * sha2.c * * Version 1.0.0beta1 * * Written by Aaron D. Gifford * * Copyright 2000 Aaron D. Gifford. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* $RoughId: sha2.c,v 1.3 2002/02/26 22:03:36 knu Exp $ */ /* $Id$ */ #include "sha2.h" #include #include /* memcpy()/memset() or bcopy()/bzero() */ #include /* assert() */ /* * ASSERT NOTE: * Some sanity checking code is included using assert(). On my FreeBSD * system, this additional code can be removed by compiling with NDEBUG * defined. Check your own systems manpage on assert() to see how to * compile WITHOUT the sanity checking code on your system. * * UNROLLED TRANSFORM LOOP NOTE: * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform * loop version for the hash transform rounds (defined using macros * later in this file). Either define on the command line, for example: * * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c * * or define below: * * #define SHA2_UNROLL_TRANSFORM * */ /*** SHA-256/384/512 Machine Architecture Definitions *****************/ typedef uint8_t sha2_byte; /* Exactly 1 byte */ typedef uint32_t sha2_word32; /* Exactly 4 bytes */ typedef uint64_t sha2_word64; /* Exactly 8 bytes */ #if defined(__GNUC__) || defined(_HPUX_SOURCE) || defined(__IBMC__) #define ULL(number) number##ULL #else #define ULL(number) (uint64_t)(number) #endif /*** SHA-256/384/512 Various Length Definitions ***********************/ /* NOTE: Most of these are in sha2.h */ #define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) #define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16) #define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) /*** ENDIAN REVERSAL MACROS *******************************************/ #ifndef WORDS_BIGENDIAN #define REVERSE32(w,x) { \ sha2_word32 tmp = (w); \ tmp = (tmp >> 16) | (tmp << 16); \ (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ } #define REVERSE64(w,x) { \ sha2_word64 tmp = (w); \ tmp = (tmp >> 32) | (tmp << 32); \ tmp = ((tmp & ULL(0xff00ff00ff00ff00)) >> 8) | \ ((tmp & ULL(0x00ff00ff00ff00ff)) << 8); \ (x) = ((tmp & ULL(0xffff0000ffff0000)) >> 16) | \ ((tmp & ULL(0x0000ffff0000ffff)) << 16); \ } #endif /* * Macro for incrementally adding the unsigned 64-bit integer n to the * unsigned 128-bit integer (represented using a two-element array of * 64-bit words): */ #define ADDINC128(w,n) { \ (w)[0] += (sha2_word64)(n); \ if ((w)[0] < (n)) { \ (w)[1]++; \ } \ } /* * Macros for copying blocks of memory and for zeroing out ranges * of memory. Using these macros makes it easy to switch from * using memset()/memcpy() and using bzero()/bcopy(). * * Please define either SHA2_USE_MEMSET_MEMCPY or define * SHA2_USE_BZERO_BCOPY depending on which function set you * choose to use: */ #if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY) /* Default to memset()/memcpy() if no option is specified */ #define SHA2_USE_MEMSET_MEMCPY 1 #endif #if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY) /* Abort with an error if BOTH options are defined */ #error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both! #endif #ifdef SHA2_USE_MEMSET_MEMCPY #define MEMSET_BZERO(p,l) memset((p), 0, (l)) #define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l)) #endif #ifdef SHA2_USE_BZERO_BCOPY #define MEMSET_BZERO(p,l) bzero((p), (l)) #define MEMCPY_BCOPY(d,s,l) bcopy((s), (d), (l)) #endif /*** THE SIX LOGICAL FUNCTIONS ****************************************/ /* * Bit shifting and rotation (used by the six SHA-XYZ logical functions: * * NOTE: The naming of R and S appears backwards here (R is a SHIFT and * S is a ROTATION) because the SHA-256/384/512 description document * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this * same "backwards" definition. */ /* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ #define R(b,x) ((x) >> (b)) /* 32-bit Rotate-right (used in SHA-256): */ #define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) /* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ #define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) /* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ #define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) #define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) /* Four of six logical functions used in SHA-256: */ #define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) #define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) #define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) #define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) /* Four of six logical functions used in SHA-384 and SHA-512: */ #define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) #define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) #define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) #define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) /*** INTERNAL FUNCTION PROTOTYPES *************************************/ /* NOTE: These should not be accessed directly from outside this * library -- they are intended for private internal visibility/use * only. */ void SHA512_Last(SHA512_CTX*); void SHA256_Transform(SHA256_CTX*, const sha2_word32*); void SHA512_Transform(SHA512_CTX*, const sha2_word64*); /*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ /* Hash constant words K for SHA-256: */ const static sha2_word32 K256[64] = { 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL }; /* Initial hash value H for SHA-256: */ const static sha2_word32 sha256_initial_hash_value[8] = { 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL, 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL }; /* Hash constant words K for SHA-384 and SHA-512: */ const static sha2_word64 K512[80] = { ULL(0x428a2f98d728ae22), ULL(0x7137449123ef65cd), ULL(0xb5c0fbcfec4d3b2f), ULL(0xe9b5dba58189dbbc), ULL(0x3956c25bf348b538), ULL(0x59f111f1b605d019), ULL(0x923f82a4af194f9b), ULL(0xab1c5ed5da6d8118), ULL(0xd807aa98a3030242), ULL(0x12835b0145706fbe), ULL(0x243185be4ee4b28c), ULL(0x550c7dc3d5ffb4e2), ULL(0x72be5d74f27b896f), ULL(0x80deb1fe3b1696b1), ULL(0x9bdc06a725c71235), ULL(0xc19bf174cf692694), ULL(0xe49b69c19ef14ad2), ULL(0xefbe4786384f25e3), ULL(0x0fc19dc68b8cd5b5), ULL(0x240ca1cc77ac9c65), ULL(0x2de92c6f592b0275), ULL(0x4a7484aa6ea6e483), ULL(0x5cb0a9dcbd41fbd4), ULL(0x76f988da831153b5), ULL(0x983e5152ee66dfab), ULL(0xa831c66d2db43210), ULL(0xb00327c898fb213f), ULL(0xbf597fc7beef0ee4), ULL(0xc6e00bf33da88fc2), ULL(0xd5a79147930aa725), ULL(0x06ca6351e003826f), ULL(0x142929670a0e6e70), ULL(0x27b70a8546d22ffc), ULL(0x2e1b21385c26c926), ULL(0x4d2c6dfc5ac42aed), ULL(0x53380d139d95b3df), ULL(0x650a73548baf63de), ULL(0x766a0abb3c77b2a8), ULL(0x81c2c92e47edaee6), ULL(0x92722c851482353b), ULL(0xa2bfe8a14cf10364), ULL(0xa81a664bbc423001), ULL(0xc24b8b70d0f89791), ULL(0xc76c51a30654be30), ULL(0xd192e819d6ef5218), ULL(0xd69906245565a910), ULL(0xf40e35855771202a), ULL(0x106aa07032bbd1b8), ULL(0x19a4c116b8d2d0c8), ULL(0x1e376c085141ab53), ULL(0x2748774cdf8eeb99), ULL(0x34b0bcb5e19b48a8), ULL(0x391c0cb3c5c95a63), ULL(0x4ed8aa4ae3418acb), ULL(0x5b9cca4f7763e373), ULL(0x682e6ff3d6b2b8a3), ULL(0x748f82ee5defb2fc), ULL(0x78a5636f43172f60), ULL(0x84c87814a1f0ab72), ULL(0x8cc702081a6439ec), ULL(0x90befffa23631e28), ULL(0xa4506cebde82bde9), ULL(0xbef9a3f7b2c67915), ULL(0xc67178f2e372532b), ULL(0xca273eceea26619c), ULL(0xd186b8c721c0c207), ULL(0xeada7dd6cde0eb1e), ULL(0xf57d4f7fee6ed178), ULL(0x06f067aa72176fba), ULL(0x0a637dc5a2c898a6), ULL(0x113f9804bef90dae), ULL(0x1b710b35131c471b), ULL(0x28db77f523047d84), ULL(0x32caab7b40c72493), ULL(0x3c9ebe0a15c9bebc), ULL(0x431d67c49c100d4c), ULL(0x4cc5d4becb3e42b6), ULL(0x597f299cfc657e2a), ULL(0x5fcb6fab3ad6faec), ULL(0x6c44198c4a475817) }; /* Initial hash value H for SHA-384 */ const static sha2_word64 sha384_initial_hash_value[8] = { ULL(0xcbbb9d5dc1059ed8), ULL(0x629a292a367cd507), ULL(0x9159015a3070dd17), ULL(0x152fecd8f70e5939), ULL(0x67332667ffc00b31), ULL(0x8eb44a8768581511), ULL(0xdb0c2e0d64f98fa7), ULL(0x47b5481dbefa4fa4) }; /* Initial hash value H for SHA-512 */ const static sha2_word64 sha512_initial_hash_value[8] = { ULL(0x6a09e667f3bcc908), ULL(0xbb67ae8584caa73b), ULL(0x3c6ef372fe94f82b), ULL(0xa54ff53a5f1d36f1), ULL(0x510e527fade682d1), ULL(0x9b05688c2b3e6c1f), ULL(0x1f83d9abfb41bd6b), ULL(0x5be0cd19137e2179) }; /*** SHA-256: *********************************************************/ void SHA256_Init(SHA256_CTX* context) { if (context == (SHA256_CTX*)0) { return; } MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH); context->bitcount = 0; } #ifdef SHA2_UNROLL_TRANSFORM /* Unrolled SHA-256 round macros: */ #ifndef WORDS_BIGENDIAN #define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ REVERSE32(*data++, W256[j]); \ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ K256[j] + W256[j]; \ (d) += T1; \ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ j++ #else #define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ K256[j] + (W256[j] = *data++); \ (d) += T1; \ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ j++ #endif #define ROUND256(a,b,c,d,e,f,g,h) \ s0 = W256[(j+1)&0x0f]; \ s0 = sigma0_256(s0); \ s1 = W256[(j+14)&0x0f]; \ s1 = sigma1_256(s1); \ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ (d) += T1; \ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ j++ void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { sha2_word32 a, b, c, d, e, f, g, h, s0, s1; sha2_word32 T1, *W256; int j; W256 = (sha2_word32*)context->buffer; /* Initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { /* Rounds 0 to 15 (unrolled): */ ROUND256_0_TO_15(a,b,c,d,e,f,g,h); ROUND256_0_TO_15(h,a,b,c,d,e,f,g); ROUND256_0_TO_15(g,h,a,b,c,d,e,f); ROUND256_0_TO_15(f,g,h,a,b,c,d,e); ROUND256_0_TO_15(e,f,g,h,a,b,c,d); ROUND256_0_TO_15(d,e,f,g,h,a,b,c); ROUND256_0_TO_15(c,d,e,f,g,h,a,b); ROUND256_0_TO_15(b,c,d,e,f,g,h,a); } while (j < 16); /* Now for the remaining rounds to 64: */ do { ROUND256(a,b,c,d,e,f,g,h); ROUND256(h,a,b,c,d,e,f,g); ROUND256(g,h,a,b,c,d,e,f); ROUND256(f,g,h,a,b,c,d,e); ROUND256(e,f,g,h,a,b,c,d); ROUND256(d,e,f,g,h,a,b,c); ROUND256(c,d,e,f,g,h,a,b); ROUND256(b,c,d,e,f,g,h,a); } while (j < 64); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = 0; } #else /* SHA2_UNROLL_TRANSFORM */ void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { sha2_word32 a, b, c, d, e, f, g, h, s0, s1; sha2_word32 T1, T2, *W256; int j; W256 = (sha2_word32*)context->buffer; /* Initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { #ifndef WORDS_BIGENDIAN /* Copy data while converting to host byte order */ REVERSE32(*data++,W256[j]); /* Apply the SHA-256 compression function to update a..h */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; #else /* Apply the SHA-256 compression function to update a..h with copy */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); #endif T2 = Sigma0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 16); do { /* Part of the message block expansion: */ s0 = W256[(j+1)&0x0f]; s0 = sigma0_256(s0); s1 = W256[(j+14)&0x0f]; s1 = sigma1_256(s1); /* Apply the SHA-256 compression function to update a..h */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); T2 = Sigma0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 64); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = T2 = 0; } #endif /* SHA2_UNROLL_TRANSFORM */ void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { unsigned int freespace, usedspace; if (len == 0) { /* Calling with no data is valid - we do nothing */ return; } /* Sanity check: */ assert(context != NULL && data != NULL); usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; if (usedspace > 0) { /* Calculate how much free space is available in the buffer */ freespace = SHA256_BLOCK_LENGTH - usedspace; if (len >= freespace) { /* Fill the buffer completely and process it */ MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); context->bitcount += freespace << 3; len -= freespace; data += freespace; SHA256_Transform(context, (sha2_word32*)context->buffer); } else { /* The buffer is not yet full */ MEMCPY_BCOPY(&context->buffer[usedspace], data, len); context->bitcount += len << 3; /* Clean up: */ usedspace = freespace = 0; return; } } while (len >= SHA256_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ SHA256_Transform(context, (const sha2_word32*)data); context->bitcount += SHA256_BLOCK_LENGTH << 3; len -= SHA256_BLOCK_LENGTH; data += SHA256_BLOCK_LENGTH; } if (len > 0) { /* There's left-overs, so save 'em */ MEMCPY_BCOPY(context->buffer, data, len); context->bitcount += len << 3; } /* Clean up: */ usedspace = freespace = 0; } void SHA256_Finish(SHA256_CTX* context, sha2_byte digest[]) { sha2_word32 *d = (sha2_word32*)digest; unsigned int usedspace; /* Sanity check: */ assert(context != NULL); /* If no digest buffer is passed, we don't bother doing this: */ if (digest != (sha2_byte*)0) { usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; #ifndef WORDS_BIGENDIAN /* Convert FROM host byte order */ REVERSE64(context->bitcount,context->bitcount); #endif if (usedspace > 0) { /* Begin padding with a 1 bit: */ context->buffer[usedspace++] = 0x80; if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { /* Set-up for the last transform: */ MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); } else { if (usedspace < SHA256_BLOCK_LENGTH) { MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ SHA256_Transform(context, (sha2_word32*)context->buffer); /* And set-up for the last transform: */ MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); } } else { /* Set-up for the last transform: */ MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); /* Begin padding with a 1 bit: */ *context->buffer = 0x80; } /* Set the bit count: */ *(sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; /* Final transform: */ SHA256_Transform(context, (sha2_word32*)context->buffer); #ifndef WORDS_BIGENDIAN { /* Convert TO host byte order */ int j; for (j = 0; j < 8; j++) { REVERSE32(context->state[j],context->state[j]); *d++ = context->state[j]; } } #else MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH); #endif } /* Clean up state data: */ MEMSET_BZERO(context, sizeof(SHA256_CTX)); usedspace = 0; } /*** SHA-512: *********************************************************/ void SHA512_Init(SHA512_CTX* context) { if (context == (SHA512_CTX*)0) { return; } MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH); context->bitcount[0] = context->bitcount[1] = 0; } #ifdef SHA2_UNROLL_TRANSFORM /* Unrolled SHA-512 round macros: */ #ifndef WORDS_BIGENDIAN #define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ REVERSE64(*data++, W512[j]); \ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ K512[j] + W512[j]; \ (d) += T1, \ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ j++ #else #define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ K512[j] + (W512[j] = *data++); \ (d) += T1; \ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ j++ #endif #define ROUND512(a,b,c,d,e,f,g,h) \ s0 = W512[(j+1)&0x0f]; \ s0 = sigma0_512(s0); \ s1 = W512[(j+14)&0x0f]; \ s1 = sigma1_512(s1); \ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ (d) += T1; \ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ j++ void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { sha2_word64 a, b, c, d, e, f, g, h, s0, s1; sha2_word64 T1, *W512 = (sha2_word64*)context->buffer; int j; /* Initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { ROUND512_0_TO_15(a,b,c,d,e,f,g,h); ROUND512_0_TO_15(h,a,b,c,d,e,f,g); ROUND512_0_TO_15(g,h,a,b,c,d,e,f); ROUND512_0_TO_15(f,g,h,a,b,c,d,e); ROUND512_0_TO_15(e,f,g,h,a,b,c,d); ROUND512_0_TO_15(d,e,f,g,h,a,b,c); ROUND512_0_TO_15(c,d,e,f,g,h,a,b); ROUND512_0_TO_15(b,c,d,e,f,g,h,a); } while (j < 16); /* Now for the remaining rounds up to 79: */ do { ROUND512(a,b,c,d,e,f,g,h); ROUND512(h,a,b,c,d,e,f,g); ROUND512(g,h,a,b,c,d,e,f); ROUND512(f,g,h,a,b,c,d,e); ROUND512(e,f,g,h,a,b,c,d); ROUND512(d,e,f,g,h,a,b,c); ROUND512(c,d,e,f,g,h,a,b); ROUND512(b,c,d,e,f,g,h,a); } while (j < 80); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = 0; } #else /* SHA2_UNROLL_TRANSFORM */ void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { sha2_word64 a, b, c, d, e, f, g, h, s0, s1; sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer; int j; /* Initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { #ifndef WORDS_BIGENDIAN /* Convert TO host byte order */ REVERSE64(*data++, W512[j]); /* Apply the SHA-512 compression function to update a..h */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; #else /* Apply the SHA-512 compression function to update a..h with copy */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); #endif T2 = Sigma0_512(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 16); do { /* Part of the message block expansion: */ s0 = W512[(j+1)&0x0f]; s0 = sigma0_512(s0); s1 = W512[(j+14)&0x0f]; s1 = sigma1_512(s1); /* Apply the SHA-512 compression function to update a..h */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); T2 = Sigma0_512(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 80); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = T2 = 0; } #endif /* SHA2_UNROLL_TRANSFORM */ void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { unsigned int freespace, usedspace; if (len == 0) { /* Calling with no data is valid - we do nothing */ return; } /* Sanity check: */ assert(context != NULL && data != NULL); usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; if (usedspace > 0) { /* Calculate how much free space is available in the buffer */ freespace = SHA512_BLOCK_LENGTH - usedspace; if (len >= freespace) { /* Fill the buffer completely and process it */ MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); ADDINC128(context->bitcount, freespace << 3); len -= freespace; data += freespace; SHA512_Transform(context, (const sha2_word64*)context->buffer); } else { /* The buffer is not yet full */ MEMCPY_BCOPY(&context->buffer[usedspace], data, len); ADDINC128(context->bitcount, len << 3); /* Clean up: */ usedspace = freespace = 0; return; } } while (len >= SHA512_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ SHA512_Transform(context, (const sha2_word64*)data); ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); len -= SHA512_BLOCK_LENGTH; data += SHA512_BLOCK_LENGTH; } if (len > 0) { /* There's left-overs, so save 'em */ MEMCPY_BCOPY(context->buffer, data, len); ADDINC128(context->bitcount, len << 3); } /* Clean up: */ usedspace = freespace = 0; } void SHA512_Last(SHA512_CTX* context) { unsigned int usedspace; usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; #ifndef WORDS_BIGENDIAN /* Convert FROM host byte order */ REVERSE64(context->bitcount[0],context->bitcount[0]); REVERSE64(context->bitcount[1],context->bitcount[1]); #endif if (usedspace > 0) { /* Begin padding with a 1 bit: */ context->buffer[usedspace++] = 0x80; if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { /* Set-up for the last transform: */ MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); } else { if (usedspace < SHA512_BLOCK_LENGTH) { MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ SHA512_Transform(context, (const sha2_word64*)context->buffer); /* And set-up for the last transform: */ MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2); } } else { /* Prepare for final transform: */ MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH); /* Begin padding with a 1 bit: */ *context->buffer = 0x80; } /* Store the length of input data (in bits): */ *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; /* Final transform: */ SHA512_Transform(context, (const sha2_word64*)context->buffer); } void SHA512_Finish(SHA512_CTX* context, sha2_byte digest[]) { sha2_word64 *d = (sha2_word64*)digest; /* Sanity check: */ assert(context != NULL); /* If no digest buffer is passed, we don't bother doing this: */ if (digest != (sha2_byte*)0) { SHA512_Last(context); /* Save the hash data for output: */ #ifndef WORDS_BIGENDIAN { /* Convert TO host byte order */ int j; for (j = 0; j < 8; j++) { REVERSE64(context->state[j],context->state[j]); *d++ = context->state[j]; } } #else MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH); #endif } /* Zero out state data */ MEMSET_BZERO(context, sizeof(SHA512_CTX)); } /*** SHA-384: *********************************************************/ void SHA384_Init(SHA384_CTX* context) { if (context == (SHA384_CTX*)0) { return; } MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH); MEMSET_BZERO(context->buffer, SHA384_BLOCK_LENGTH); context->bitcount[0] = context->bitcount[1] = 0; } void SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) { SHA512_Update((SHA512_CTX*)context, data, len); } void SHA384_Finish(SHA384_CTX* context, sha2_byte digest[]) { sha2_word64 *d = (sha2_word64*)digest; /* Sanity check: */ assert(context != NULL); /* If no digest buffer is passed, we don't bother doing this: */ if (digest != (sha2_byte*)0) { SHA512_Last((SHA512_CTX*)context); /* Save the hash data for output: */ #ifndef WORDS_BIGENDIAN { /* Convert TO host byte order */ int j; for (j = 0; j < 6; j++) { REVERSE64(context->state[j],context->state[j]); *d++ = context->state[j]; } } #else MEMCPY_BCOPY(d, context->state, SHA384_DIGEST_LENGTH); #endif } /* Zero out state data */ MEMSET_BZERO(context, sizeof(SHA384_CTX)); } ================================================ FILE: ext/digest/sha2/sha2.h ================================================ /* * sha2.h * * Version 1.0.0beta1 * * Written by Aaron D. Gifford * * Copyright 2000 Aaron D. Gifford. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* $RoughId: sha2.h,v 1.3 2002/02/24 08:14:32 knu Exp $ */ /* $Id$ */ #ifndef __SHA2_H__ #define __SHA2_H__ #ifdef __cplusplus extern "C" { #endif #include "defs.h" /*** SHA-256/384/512 Various Length Definitions ***********************/ #define SHA256_BLOCK_LENGTH 64 #define SHA256_DIGEST_LENGTH 32 #define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) #define SHA384_BLOCK_LENGTH 128 #define SHA384_DIGEST_LENGTH 48 #define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) #define SHA512_BLOCK_LENGTH 128 #define SHA512_DIGEST_LENGTH 64 #define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) /*** SHA-256/384/512 Context Structures *******************************/ typedef struct _SHA256_CTX { uint32_t state[8]; uint64_t bitcount; uint8_t buffer[SHA256_BLOCK_LENGTH]; } SHA256_CTX; typedef struct _SHA512_CTX { uint64_t state[8]; uint64_t bitcount[2]; uint8_t buffer[SHA512_BLOCK_LENGTH]; } SHA512_CTX; typedef SHA512_CTX SHA384_CTX; #ifdef RUBY #define SHA256_Init rb_Digest_SHA256_Init #define SHA256_Update rb_Digest_SHA256_Update #define SHA256_Finish rb_Digest_SHA256_Finish #define SHA384_Init rb_Digest_SHA384_Init #define SHA384_Update rb_Digest_SHA384_Update #define SHA384_Finish rb_Digest_SHA384_Finish #define SHA512_Init rb_Digest_SHA512_Init #define SHA512_Update rb_Digest_SHA512_Update #define SHA512_Finish rb_Digest_SHA512_Finish #endif /*** SHA-256/384/512 Function Prototypes ******************************/ void SHA256_Init _((SHA256_CTX *)); void SHA256_Update _((SHA256_CTX*, const uint8_t*, size_t)); void SHA256_Finish _((SHA256_CTX*, uint8_t[SHA256_DIGEST_LENGTH])); void SHA384_Init _((SHA384_CTX*)); void SHA384_Update _((SHA384_CTX*, const uint8_t*, size_t)); void SHA384_Finish _((SHA384_CTX*, uint8_t[SHA384_DIGEST_LENGTH])); void SHA512_Init _((SHA512_CTX*)); void SHA512_Update _((SHA512_CTX*, const uint8_t*, size_t)); void SHA512_Finish _((SHA512_CTX*, uint8_t[SHA512_DIGEST_LENGTH])); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __SHA2_H__ */ ================================================ FILE: ext/digest/sha2/sha2init.c ================================================ /* $RoughId: sha2init.c,v 1.3 2001/07/13 20:00:43 knu Exp $ */ /* $Id$ */ #include "digest.h" #include "sha2.h" #define FOREACH_BITLEN(func) func(256) func(384) func(512) #define DEFINE_ALGO_METADATA(bitlen) \ static rb_digest_metadata_t sha##bitlen = { \ RUBY_DIGEST_API_VERSION, \ SHA##bitlen##_DIGEST_LENGTH, \ SHA##bitlen##_BLOCK_LENGTH, \ sizeof(SHA##bitlen##_CTX), \ (rb_digest_hash_init_func_t)SHA##bitlen##_Init, \ (rb_digest_hash_update_func_t)SHA##bitlen##_Update, \ (rb_digest_hash_finish_func_t)SHA##bitlen##_Finish, \ }; FOREACH_BITLEN(DEFINE_ALGO_METADATA) /* * Classes for calculating message digests using the SHA-256/384/512 * Secure Hash Algorithm(s) by NIST (the US' National Institute of * Standards and Technology), described in FIPS PUB 180-2. */ void Init_sha2() { VALUE mDigest, cDigest_Base; ID id_metadata; #define DECLARE_ALGO_CLASS(bitlen) \ VALUE cDigest_SHA##bitlen; FOREACH_BITLEN(DECLARE_ALGO_CLASS) rb_require("digest"); id_metadata = rb_intern("metadata"); mDigest = rb_path2class("Digest"); cDigest_Base = rb_path2class("Digest::Base"); #define DEFINE_ALGO_CLASS(bitlen) \ cDigest_SHA##bitlen = rb_define_class_under(mDigest, "SHA" #bitlen, cDigest_Base); \ \ rb_ivar_set(cDigest_SHA##bitlen, id_metadata, \ Data_Wrap_Struct(rb_cObject, 0, 0, &sha##bitlen)); FOREACH_BITLEN(DEFINE_ALGO_CLASS) } ================================================ FILE: ext/digest/test.sh ================================================ #!/bin/sh # # $RoughId: test.sh,v 1.5 2001/07/13 15:38:27 knu Exp $ # $Id$ RUBY=${RUBY:=ruby} MAKE=${MAKE:=make} CFLAGS=${CFLAGS:=-Wall} ${RUBY} extconf.rb --with-cflags="${CFLAGS}" ${MAKE} clean ${MAKE} for algo in md5 rmd160 sha1 sha2; do args=--with-cflags="${CFLAGS}" if [ $WITH_BUNDLED_ENGINES ]; then args="$args --with-bundled-$algo" fi (cd $algo && ${RUBY} extconf.rb $args; ${MAKE} clean; ${MAKE}) ln -sf ../../$algo/$algo.so lib/digest/ done ${RUBY} -I. -I./lib ../../test/digest/test_digest.rb rm lib/digest/*.so ================================================ FILE: ext/dl/.cvsignore ================================================ Makefile mkmf.log dlconfig.h dlconfig.rb *.func *.o *~ *.def ================================================ FILE: ext/dl/depend ================================================ LDSHARED_TEST = $(LDSHARED) $(LDFLAGS) test/test.o -o test/libtest.so $(LOCAL_LIBS) libtest.so: test/libtest.so test/libtest.so: test/test.o $(srcdir)/test/libtest.def $(RUBY) -rftools -e 'ARGV.each do|d|File.mkpath(File.dirname(d))end' $@ $(LDSHARED_TEST:dl.def=test/libtest.def) test/test.o: $(srcdir)/test/test.c @$(RUBY) -rftools -e 'File.mkpath(*ARGV)' test $(CC) $(CFLAGS) $(CPPFLAGS) -c $(srcdir)/test/test.c -o $@ test:: dl.so libtest.so force $(RUBY) -I. -I$(srcdir)/lib $(srcdir)/test/test.rb force: .PHONY: force test allclean: distclean @rm -f $(CLEANFILES) $(DISTCLEANFILES) $(OBJS): ./dlconfig.h sym.o: dl.h call.func dl.o: dl.h callback.func cbtable.func ptr.o: dl.h handle.o: dl.h call.func: $(srcdir)/mkcall.rb ./dlconfig.rb @echo "Generating call.func" @$(RUBY) $(srcdir)/mkcall.rb > $@ callback.func: $(srcdir)/mkcallback.rb ./dlconfig.rb @echo "Generating callback.func" @$(RUBY) $(srcdir)/mkcallback.rb > $@ cbtable.func: $(srcdir)/mkcbtable.rb ./dlconfig.rb @echo "Generating cbtable.func" @$(RUBY) $(srcdir)/mkcbtable.rb > $@ debug: $(MAKE) CPPFLAGS="$(CPPFLAGS) -DDEBUG" ================================================ FILE: ext/dl/dl.c ================================================ /* * $Id$ */ #include #include #include #include "dl.h" VALUE rb_mDL; VALUE rb_eDLError; VALUE rb_eDLTypeError; static VALUE DLFuncTable; static void *rb_dl_callback_table[CALLBACK_TYPES][MAX_CALLBACK]; static ID id_call; static int rb_dl_scan_callback_args(long stack[], const char *proto, int *argc, VALUE argv[]) { int i; long *sp; VALUE val; sp = stack; for (i=1; proto[i]; i++) { switch (proto[i]) { case 'C': { char v; v = (char)(*sp); sp++; val = INT2NUM(v); } break; case 'H': { short v; v = (short)(*sp); sp++; val = INT2NUM(v); } break; case 'I': { int v; v = (int)(*sp); sp++; val = INT2NUM(v); } break; case 'L': { long v; v = (long)(*sp); sp++; val = INT2NUM(v); } break; case 'F': { float v; memcpy(&v, sp, sizeof(float)); sp += sizeof(float)/sizeof(long); val = rb_float_new(v); } break; case 'D': { double v; memcpy(&v, sp, sizeof(double)); sp += sizeof(double)/sizeof(long); val = rb_float_new(v); } break; case 'P': { void *v; memcpy(&v, sp, sizeof(void*)); sp++; val = rb_dlptr_new(v, 0, 0); } break; case 'S': { char *v; memcpy(&v, sp, sizeof(void*)); sp++; val = rb_tainted_str_new2(v); } break; default: rb_raise(rb_eDLTypeError, "unsupported type `%c'", proto[i]); break; } argv[i-1] = val; } *argc = (i - 1); return (*argc); } #include "callback.func" static void init_dl_func_table(){ #include "cbtable.func" } void * dlmalloc(size_t size) { DEBUG_CODE2({ void *ptr; printf("dlmalloc(%d)",size); ptr = xmalloc(size); printf(":0x%x\n",ptr); return ptr; }, { return xmalloc(size); }); } void * dlrealloc(void *ptr, size_t size) { DEBUG_CODE({ printf("dlrealloc(0x%x,%d)\n",ptr,size); }); return xrealloc(ptr, size); } void dlfree(void *ptr) { DEBUG_CODE({ printf("dlfree(0x%x)\n",ptr); }); xfree(ptr); } char* dlstrdup(const char *str) { char *newstr; newstr = (char*)dlmalloc(strlen(str)+1); strcpy(newstr,str); return newstr; } size_t dlsizeof(const char *cstr) { size_t size; int i, len, n, dlen; char *d; len = strlen(cstr); size = 0; for (i=0; ilen; *size = sizeof(float) * len; ary = dlmalloc(*size); for (i=0; i < len; i++) { e = rb_ary_entry(v, i); switch (TYPE(e)) { case T_FLOAT: ary[i] = (float)(RFLOAT(e)->value); break; case T_NIL: ary[i] = 0.0; break; default: rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); break; } } return ary; } static double * c_darray(VALUE v, long *size) { int i, len; double *ary; VALUE e; len = RARRAY(v)->len; *size = sizeof(double) * len; ary = dlmalloc(*size); for (i=0; i < len; i++) { e = rb_ary_entry(v, i); switch (TYPE(e)) { case T_FLOAT: ary[i] = (double)(RFLOAT(e)->value); break; case T_NIL: ary[i] = 0.0; break; default: rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); break; } } return ary; } static long * c_larray(VALUE v, long *size) { int i, len; long *ary; VALUE e; len = RARRAY(v)->len; *size = sizeof(long) * len; ary = dlmalloc(*size); for (i=0; i < len; i++) { e = rb_ary_entry(v, i); switch (TYPE(e)) { case T_FIXNUM: case T_BIGNUM: ary[i] = (long)(NUM2INT(e)); break; case T_NIL: ary[i] = 0; break; default: rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); break; } } return ary; } static int * c_iarray(VALUE v, long *size) { int i, len; int *ary; VALUE e; len = RARRAY(v)->len; *size = sizeof(int) * len; ary = dlmalloc(*size); for (i=0; i < len; i++) { e = rb_ary_entry(v, i); switch (TYPE(e)) { case T_FIXNUM: case T_BIGNUM: ary[i] = (int)(NUM2INT(e)); break; case T_NIL: ary[i] = 0; break; default: rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); break; } } return ary; } static short * c_harray(VALUE v, long *size) { int i, len; short *ary; VALUE e; len = RARRAY(v)->len; *size = sizeof(short) * len; ary = dlmalloc(*size); for (i=0; i < len; i++) { e = rb_ary_entry(v, i); switch (TYPE(e)) { case T_FIXNUM: case T_BIGNUM: ary[i] = (short)(NUM2INT(e)); break; case T_NIL: ary[i] = 0; break; default: rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); break; } } return ary; } static char * c_carray(VALUE v, long *size) { int i, len; char *ary; VALUE e; len = RARRAY(v)->len; *size = sizeof(char) * len; ary = dlmalloc(*size); for (i=0; i < len; i++) { e = rb_ary_entry(v, i); switch (TYPE(e)) { case T_FIXNUM: case T_BIGNUM: ary[i] = (char)(NUM2INT(e)); break; case T_NIL: ary[i] = 0; break; default: rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); break; } } return ary; } static void * c_parray(VALUE v, long *size) { int i, len; void **ary; VALUE e, tmp; len = RARRAY(v)->len; *size = sizeof(void*) * len; ary = dlmalloc(*size); for (i=0; i < len; i++) { e = rb_ary_entry(v, i); switch (TYPE(e)) { default: tmp = rb_check_string_type(e); if (NIL_P(tmp)) { rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); } e = tmp; /* fall through */ case T_STRING: rb_check_safe_str(e); { char *str, *src; src = RSTRING(e)->ptr; str = dlstrdup(src); ary[i] = (void*)str; } break; case T_NIL: ary[i] = NULL; break; case T_DATA: if (rb_obj_is_kind_of(e, rb_cDLPtrData)) { struct ptr_data *pdata; Data_Get_Struct(e, struct ptr_data, pdata); ary[i] = (void*)(pdata->ptr); } else{ e = rb_funcall(e, rb_intern("to_ptr"), 0); if (rb_obj_is_kind_of(e, rb_cDLPtrData)) { struct ptr_data *pdata; Data_Get_Struct(e, struct ptr_data, pdata); ary[i] = (void*)(pdata->ptr); } else{ rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); } } break; } } return ary; } void * rb_ary2cary(char t, VALUE v, long *size) { int len; VALUE val0; val0 = rb_check_array_type(v); if(NIL_P(val0)) { rb_raise(rb_eDLTypeError, "an array is expected."); } v = val0; len = RARRAY(v)->len; if (len == 0) { return NULL; } if (!size) { size = ALLOCA_N(long,1); } val0 = rb_ary_entry(v,0); switch (TYPE(val0)) { case T_FIXNUM: case T_BIGNUM: switch (t) { case 'C': case 'c': return (void*)c_carray(v,size); case 'H': case 'h': return (void*)c_harray(v,size); case 'I': case 'i': return (void*)c_iarray(v,size); case 'L': case 'l': case 0: return (void*)c_larray(v,size); default: rb_raise(rb_eDLTypeError, "type mismatch"); } case T_STRING: return (void*)c_parray(v,size); case T_FLOAT: switch (t) { case 'F': case 'f': return (void*)c_farray(v,size); case 'D': case 'd': case 0: return (void*)c_darray(v,size); } rb_raise(rb_eDLTypeError, "type mismatch"); case T_DATA: if (rb_obj_is_kind_of(val0, rb_cDLPtrData)) { return (void*)c_parray(v,size); } else{ val0 = rb_funcall(val0, rb_intern("to_ptr"), 0); if (rb_obj_is_kind_of(val0, rb_cDLPtrData)) { return (void*)c_parray(v,size); } } rb_raise(rb_eDLTypeError, "type mismatch"); case T_NIL: return (void*)c_parray(v, size); default: rb_raise(rb_eDLTypeError, "unsupported type"); } } VALUE rb_str_to_ptr(VALUE self) { char *ptr; int len; VALUE p; len = RSTRING(self)->len; ptr = (char*)dlmalloc(len + 1); memcpy(ptr, RSTRING(self)->ptr, len); ptr[len] = '\0'; p = rb_dlptr_new((void*)ptr,len,dlfree); OBJ_INFECT(p, self); return p; } VALUE rb_ary_to_ptr(int argc, VALUE argv[], VALUE self) { void *ptr; VALUE t; long size; switch (rb_scan_args(argc, argv, "01", &t)) { case 1: ptr = rb_ary2cary(StringValuePtr(t)[0], self, &size); break; case 0: ptr = rb_ary2cary(0, self, &size); break; } if (ptr) { VALUE p = rb_dlptr_new(ptr, size, dlfree); OBJ_INFECT(p, self); return p; } return Qnil; } VALUE rb_io_to_ptr(VALUE self) { rb_io_t *fptr; FILE *fp; GetOpenFile(self, fptr); fp = fptr->f; return fp ? rb_dlptr_new(fp, 0, 0) : Qnil; } VALUE rb_dl_dlopen(int argc, VALUE argv[], VALUE self) { rb_secure(2); return rb_class_new_instance(argc, argv, rb_cDLHandle); } VALUE rb_dl_malloc(VALUE self, VALUE size) { rb_secure(4); return rb_dlptr_malloc(DLNUM2LONG(size), dlfree); } VALUE rb_dl_strdup(VALUE self, VALUE str) { SafeStringValue(str); return rb_dlptr_new(strdup(RSTRING(str)->ptr), RSTRING(str)->len, dlfree); } static VALUE rb_dl_sizeof(VALUE self, VALUE str) { return INT2NUM(dlsizeof(StringValuePtr(str))); } static VALUE rb_dl_callback(int argc, VALUE argv[], VALUE self) { VALUE type, proc; int rettype, entry, i; char fname[127]; rb_secure(4); proc = Qnil; switch (rb_scan_args(argc, argv, "11", &type, &proc)) { case 1: if (rb_block_given_p()) { proc = rb_block_proc(); } else{ proc = Qnil; } default: break; } StringValue(type); switch (RSTRING(type)->ptr[0]) { case '0': rettype = 0x00; break; case 'C': rettype = 0x01; break; case 'H': rettype = 0x02; break; case 'I': rettype = 0x03; break; case 'L': rettype = 0x04; break; case 'F': rettype = 0x05; break; case 'D': rettype = 0x06; break; case 'P': rettype = 0x07; break; default: rb_raise(rb_eDLTypeError, "unsupported type `%c'", RSTRING(type)->ptr[0]); } entry = -1; for (i=0; i < MAX_CALLBACK; i++) { if (rb_hash_aref(DLFuncTable, rb_assoc_new(INT2NUM(rettype), INT2NUM(i))) == Qnil) { entry = i; break; } } if (entry < 0) { rb_raise(rb_eDLError, "too many callbacks are defined."); } rb_hash_aset(DLFuncTable, rb_assoc_new(INT2NUM(rettype),INT2NUM(entry)), rb_assoc_new(type,proc)); sprintf(fname, "rb_dl_callback_func_%d_%d", rettype, entry); return rb_dlsym_new((void (*)())rb_dl_callback_table[rettype][entry], fname, RSTRING(type)->ptr); } static VALUE rb_dl_remove_callback(VALUE mod, VALUE sym) { freefunc_t f; int i, j; rb_secure(4); f = rb_dlsym2csym(sym); for (i=0; i < CALLBACK_TYPES; i++) { for (j=0; j < MAX_CALLBACK; j++) { if (rb_dl_callback_table[i][j] == f) { rb_hash_aset(DLFuncTable, rb_assoc_new(INT2NUM(i),INT2NUM(j)),Qnil); break; } } } return Qnil; } void Init_dl() { void Init_dlptr(); void Init_dlsym(); void Init_dlhandle(); id_call = rb_intern("call"); rb_mDL = rb_define_module("DL"); rb_eDLError = rb_define_class_under(rb_mDL, "DLError", rb_eStandardError); rb_eDLTypeError = rb_define_class_under(rb_mDL, "DLTypeError", rb_eDLError); DLFuncTable = rb_hash_new(); init_dl_func_table(); rb_define_const(rb_mDL, "FuncTable", DLFuncTable); rb_define_const(rb_mDL, "RTLD_GLOBAL", INT2NUM(RTLD_GLOBAL)); rb_define_const(rb_mDL, "RTLD_LAZY", INT2NUM(RTLD_LAZY)); rb_define_const(rb_mDL, "RTLD_NOW", INT2NUM(RTLD_NOW)); rb_define_const(rb_mDL, "ALIGN_INT", INT2NUM(ALIGN_INT)); rb_define_const(rb_mDL, "ALIGN_LONG", INT2NUM(ALIGN_LONG)); rb_define_const(rb_mDL, "ALIGN_FLOAT", INT2NUM(ALIGN_FLOAT)); rb_define_const(rb_mDL, "ALIGN_SHORT", INT2NUM(ALIGN_SHORT)); rb_define_const(rb_mDL, "ALIGN_DOUBLE",INT2NUM(ALIGN_DOUBLE)); rb_define_const(rb_mDL, "ALIGN_VOIDP", INT2NUM(ALIGN_VOIDP)); rb_define_const(rb_mDL, "MAX_ARG", INT2NUM(MAX_ARG)); rb_define_const(rb_mDL, "DLSTACK", rb_tainted_str_new2(DLSTACK_METHOD)); rb_define_module_function(rb_mDL, "dlopen", rb_dl_dlopen, -1); rb_define_module_function(rb_mDL, "callback", rb_dl_callback, -1); rb_define_module_function(rb_mDL, "define_callback", rb_dl_callback, -1); rb_define_module_function(rb_mDL, "remove_callback", rb_dl_remove_callback, 1); rb_define_module_function(rb_mDL, "malloc", rb_dl_malloc, 1); rb_define_module_function(rb_mDL, "strdup", rb_dl_strdup, 1); rb_define_module_function(rb_mDL, "sizeof", rb_dl_sizeof, 1); Init_dlptr(); Init_dlsym(); Init_dlhandle(); rb_define_const(rb_mDL, "FREE", rb_dlsym_new(dlfree, "free", "0P")); rb_define_method(rb_cString, "to_ptr", rb_str_to_ptr, 0); rb_define_method(rb_cArray, "to_ptr", rb_ary_to_ptr, -1); rb_define_method(rb_cIO, "to_ptr", rb_io_to_ptr, 0); } ================================================ FILE: ext/dl/dl.def ================================================ EXPORTS Init_dl dlfree dlmalloc dlrealloc dlstrdup rb_ary_to_ptr rb_dl_dlopen rb_dl_malloc rb_dl_strdup rb_eDLError rb_eDLTypeError rb_io_to_ptr rb_mDL rb_str_to_ptr Init_dlhandle rb_cDLHandle rb_dlhandle_close rb_dlhandle_disable_close rb_dlhandle_enable_close rb_dlhandle_sym Init_dlptr rb_cDLPtrData rb_dlmem_each rb_dlptr2cptr rb_dlptr_malloc rb_dlptr_aref rb_dlptr_aset rb_dlptr_cmp rb_dlptr_define_data_type rb_dlptr_define_struct rb_dlptr_define_union rb_dlptr_eql rb_dlptr_free_get rb_dlptr_free_set rb_dlptr_get_data_type rb_dlptr_inspect rb_dlptr_minus rb_dlptr_new rb_dlptr_new2 rb_dlptr_null_p rb_dlptr_plus rb_dlptr_ptr rb_dlptr_ref rb_dlptr_to_array rb_dlptr_to_i rb_dlptr_to_s rb_dlptr_to_str rb_mDLMemorySpace Init_dlsym rb_cDLSymbol rb_dlsym2csym rb_dlsym_call rb_dlsym_cproto rb_dlsym_inspect rb_dlsym_name rb_dlsym_new rb_dlsym_proto rb_dlsym_to_ptr ================================================ FILE: ext/dl/dl.h ================================================ /* -*- C -*- * $Id$ */ #ifndef RUBY_DL_H #define RUBY_DL_H #include #include #if defined(HAVE_DLFCN_H) # include # /* some stranger systems may not define all of these */ #ifndef RTLD_LAZY #define RTLD_LAZY 0 #endif #ifndef RTLD_GLOBAL #define RTLD_GLOBAL 0 #endif #ifndef RTLD_NOW #define RTLD_NOW 0 #endif #else # if defined(HAVE_WINDOWS_H) # include # define dlclose(ptr) FreeLibrary((HINSTANCE)ptr) # define dlopen(name,flag) ((void*)LoadLibrary(name)) # define dlerror() "unknown error" # define dlsym(handle,name) ((void*)GetProcAddress(handle,name)) # define RTLD_LAZY -1 # define RTLD_NOW -1 # define RTLD_GLOBAL -1 # endif #endif #if !defined(StringValue) # define StringValue(v) if(TYPE(v) != T_STRING) v = rb_str_to_str(v) #endif #if !defined(StringValuePtr) # define StringValuePtr(v) RSTRING((TYPE(v) == T_STRING) ? (v) : rb_str_to_str(v))->ptr #endif #ifdef DEBUG #define DEBUG_CODE(b) {printf("DEBUG:%d\n",__LINE__);b;} #define DEBUG_CODE2(b1,b2) {printf("DEBUG:%d\n",__LINE__);b1;} #else #define DEBUG_CODE(b) #define DEBUG_CODE2(b1,b2) b2 #endif #define VOID_DLTYPE 0x00 #define CHAR_DLTYPE 0x01 #define SHORT_DLTYPE 0x02 #define INT_DLTYPE 0x03 #define LONG_DLTYPE 0x04 #define FLOAT_DLTYPE 0x05 #define DOUBLE_DLTYPE 0x06 #define VOIDP_DLTYPE 0x07 #define ARG_TYPE(x,i) (((x) & (0x07 << ((i)*3))) >> ((i)*3)) #define PUSH_ARG(x,t) do{x <<= 3; x |= t;}while(0) #define PUSH_0(x) PUSH_ARG(x,VOID_DLTYPE) #if SIZEOF_INT == SIZEOF_LONG # define PUSH_I(x) PUSH_ARG(x,LONG_DLTYPE) # define ANY2I(x) x.l # define DLINT(x) (long)x #else # define PUSH_I(x) PUSH_ARG(x,INT_DLTYPE) # define ANY2I(x) x.i # define DLINT(x) (int)x #endif #define PUSH_L(x) PUSH_ARG(x,LONG_DLTYPE) #define ANY2L(x) x.l #define DLLONG(x) (long)x #if defined(WITH_TYPE_FLOAT) # if SIZEOF_FLOAT == SIZEOF_DOUBLE # define PUSH_F(x) PUSH_ARG(x,DOUBLE_DLTYPE) # define ANY2F(x) (x.d) # define DLFLOAT(x) ((double)x) # else # define PUSH_F(x) PUSH_ARG(x,FLOAT_DLTYPE) # define ANY2F(x) (x.f) # define DLFLOAT(x) ((float)x) # endif #else # define PUSH_F(x) PUSH_ARG(x,DOUBLE_DLTYPE) # define ANY2F(x) (x.d) # define DLFLOAT(x) ((double)x) #endif #define PUSH_D(x) PUSH_ARG(x,DOUBLE_DLTYPE) #define ANY2D(x) (x.d) #define DLDOUBLE(x) ((double)x) #if SIZEOF_INT == SIZEOF_VOIDP && SIZEOF_INT != SIZEOF_LONG # define PUSH_P(x) PUSH_ARG(x,INT_DLTYPE) # define ANY2P(x) (x.i) # define DLVOIDP(x) ((int)x) #elif SIZEOF_LONG == SIZEOF_VOIDP # define PUSH_P(x) PUSH_ARG(x,LONG_DLTYPE) # define ANY2P(x) (x.l) # define DLVOIDP(x) ((long)x) #else # define PUSH_P(x) PUSH_ARG(x,VOIDP_DLTYPE) # define ANY2P(x) (x.p) # define DLVOIDP(x) ((void*)p) #endif #if defined(WITH_TYPE_CHAR) # define PUSH_C(x) PUSH_ARG(x,CHAR_DLTYPE) # define ANY2C(x) (x.c) # define DLCHAR(x) ((char)x) #else # define PUSH_C(x) PUSH_I(x) # define ANY2C(x) ANY2I(x) # define DLCHAR(x) DLINT(x) #endif #if defined(WITH_TYPE_SHORT) # define PUSH_H(x) PUSH_ARG(x,SHORT_DLTYPE) # define ANY2H(x) (x.h) # define DLSHORT(x) ((short)x) #else # define PUSH_H(x) PUSH_I(x) # define ANY2H(x) ANY2I(x) # define DLSHORT(x) DLINT(x) #endif #define PUSH_S(x) PUSH_P(x) #define ANY2S(x) ANY2P(x) #define DLSTR(x) DLVOIDP(x) #define CBPUSH_0(x) PUSH_0(x) #define CBPUSH_C(x) PUSH_C(x) #define CBPUSH_H(x) PUSH_H(x) #define CBPUSH_I(x) PUSH_I(x) #define CBPUSH_L(x) PUSH_L(x) #define CBPUSH_F(x) PUSH_F(x) #define CBPUSH_D(x) PUSH_D(x) #if defined(WITH_CBTYPE_VOIDP) # define CBPUSH_P(x) PUSH_ARG(x,VOIDP_DLTYPE) #else # define CBPUSH_P(x) PUSH_P(x) #endif #if defined(USE_INLINE_ASM) # if defined(__i386__) && defined(__GNUC__) # define DLSTACK # define DLSTACK_METHOD "asm" # define DLSTACK_REVERSE # define DLSTACK_PROTO # define DLSTACK_ARGS # define DLSTACK_START(sym) # define DLSTACK_END(sym) # define DLSTACK_PUSH_C(x) asm volatile ("pushl %0" :: "g" (x)); # define DLSTACK_PUSH_H(x) asm volatile ("pushl %0" :: "g" (x)); # define DLSTACK_PUSH_I(x) asm volatile ("pushl %0" :: "g" (x)); # define DLSTACK_PUSH_L(x) asm volatile ("pushl %0" :: "g" (x)); # define DLSTACK_PUSH_P(x) asm volatile ("pushl %0" :: "g" (x)); # define DLSTACK_PUSH_F(x) asm volatile ("flds %0"::"g"(x));\ asm volatile ("subl $4,%esp");\ asm volatile ("fstps (%esp)"); # define DLSTACK_PUSH_D(x) asm volatile ("fldl %0"::"g"(x));\ asm volatile ("subl $8,%esp");\ asm volatile ("fstpl (%esp)") # else # error --with-asm is not supported on this machine # endif #elif defined(USE_DLSTACK) # define DLSTACK # define DLSTACK_GUARD # define DLSTACK_METHOD "dl" # define DLSTACK_PROTO long,long,long,long,long,\ long,long,long,long,long,\ long,long,long,long,long # define DLSTACK_ARGS stack[0],stack[1],stack[2],stack[3],stack[4],\ stack[5],stack[6],stack[7],stack[8],stack[9],\ stack[10],stack[11],stack[12],stack[13],stack[14] # define DLSTACK_SIZE (sizeof(long)*15) # define DLSTACK_START(sym) # define DLSTACK_END(sym) # define DLSTACK_PUSH_C(x) {long v=(long)x; memcpy(sp,&v,sizeof(long)); sp++;} # define DLSTACK_PUSH_H(x) {long v=(long)x; memcpy(sp,&v,sizeof(long)); sp++;} # define DLSTACK_PUSH_I(x) {long v=(long)x; memcpy(sp,&v,sizeof(long)); sp++;} # define DLSTACK_PUSH_L(x) memcpy(sp,&x,sizeof(long)); sp++; # define DLSTACK_PUSH_P(x) memcpy(sp,&x,sizeof(void*)); sp++; # define DLSTACK_PUSH_F(x) memcpy(sp,&x,sizeof(float)); sp+=sizeof(float)/sizeof(long); # define DLSTACK_PUSH_D(x) memcpy(sp,&x,sizeof(double)); sp+=sizeof(double)/sizeof(long); #else # define DLSTACK_METHOD "none" #endif extern VALUE rb_mDL; extern VALUE rb_mDLMemorySpace; extern VALUE rb_cDLHandle; extern VALUE rb_cDLSymbol; extern VALUE rb_cDLPtrData; extern VALUE rb_cDLStructData; extern VALUE rb_eDLError; extern VALUE rb_eDLTypeError; #if defined(LONG2NUM) && (SIZEOF_LONG == SIZEOF_VOIDP) # define DLLONG2NUM(x) LONG2NUM((long)x) # define DLNUM2LONG(x) (long)(NUM2LONG(x)) #else # define DLLONG2NUM(x) INT2NUM((long)x) # define DLNUM2LONG(x) (long)(NUM2INT(x)) #endif typedef struct { char c; void *x; } s_voidp; typedef struct { char c; short x; } s_short; typedef struct { char c; int x; } s_int; typedef struct { char c; long x; } s_long; typedef struct { char c; float x; } s_float; typedef struct { char c; double x; } s_double; #define ALIGN_VOIDP (sizeof(s_voidp) - sizeof(void *)) #define ALIGN_SHORT (sizeof(s_short) - sizeof(short)) #define ALIGN_INT (sizeof(s_int) - sizeof(int)) #define ALIGN_LONG (sizeof(s_long) - sizeof(long)) #define ALIGN_FLOAT (sizeof(s_float) - sizeof(float)) #define ALIGN_DOUBLE (sizeof(s_double) - sizeof(double)) /* for compatibility */ #define VOIDP_ALIGN ALIGN_VOIDP #define SHORT_ALIGN ALIGN_SHORT #define INT_ALIGN ALIGN_INT #define LONG_ALIGN ALIGN_LONG #define FLOAT_ALIGN ALIGN_FLOAT #define DOUBLE_ALIGN ALIGN_DOUBLE #define DLALIGN(ptr,offset,align) {\ while( (((unsigned long)((char *)ptr + offset)) % align) != 0 ) offset++;\ } typedef void (*freefunc_t)(void *); #define DLFREEFUNC(func) ((freefunc_t)(func)) typedef union { void* p; char c; short h; int i; long l; float f; double d; char *s; } ANY_TYPE; struct dl_handle { void *ptr; int open; int enable_close; }; struct sym_data { void *func; char *name; char *type; int len; }; enum DLPTR_CTYPE { DLPTR_CTYPE_UNKNOWN, DLPTR_CTYPE_STRUCT, DLPTR_CTYPE_UNION }; struct ptr_data { void *ptr; /* a pointer to the data */ freefunc_t free; /* free() */ char *stype; /* array of type specifiers */ int *ssize; /* size[i] = sizeof(type[i]) > 0 */ int slen; /* the number of type specifiers */ ID *ids; int ids_num; int ctype; /* DLPTR_CTYPE_UNKNOWN, DLPTR_CTYPE_STRUCT, DLPTR_CTYPE_UNION */ long size; }; #define RDLPTR(obj) ((struct ptr_data *)(DATA_PTR(obj))) #define RDLSYM(obj) ((struct sym_data *)(DATA_PTR(obj))) void dlfree(void*); void *dlmalloc(size_t); void *dlrealloc(void*,size_t); char *dlstrdup(const char *); size_t dlsizeof(const char *); void *rb_ary2cary(char t, VALUE ary, long *size); /* void rb_dlmem_delete(void *ptr); void rb_dlmem_aset(void *ptr, VALUE obj); VALUE rb_dlmem_aref(void *ptr); */ void dlptr_free(struct ptr_data *data); void dlptr_init(VALUE val); VALUE rb_dlptr_new(void *ptr, long size, freefunc_t func); VALUE rb_dlptr_new2(VALUE klass, void *ptr, long size, freefunc_t func); VALUE rb_dlptr_malloc(long size, freefunc_t func); void *rb_dlptr2cptr(VALUE val); VALUE rb_dlsym_new(void (*func)(), const char *name, const char *type); freefunc_t rb_dlsym2csym(VALUE val); #endif /* RUBY_DL_H */ ================================================ FILE: ext/dl/doc/dl.txt ================================================ =begin = Ruby/DL Ruby/DL provides an interface to the dynamic linker such as dlopen() on UNIX and LoadLibrary() on Windows. = Building and Installing $ ruby extconf.rb # to create the Makefile $ make # to build the library 'dl.so' $ make libtest.so # to build the C library 'libtest.so' for the test script $ make test # to run the test script $ make install # to install the library $ make clean # to remove the created files without Makefile $ make distclean # to remove the all created files = Using Ruby/DL We should usually use DL::Importable module provided by "dl/import.rb". It has high-level functions to access library functions. We use DL::Importable module to extend a module as follows: require "dl/import" module LIBC extend DL::Importable end Now we can use methods dlload and extern in this module. We load the libraries using dlload, and define wrapper methods to library functions using extern respectively as follows: module LIBC extend DL::Importable dlload "libc.so.6","libm.so.6" extern "int strlen(char*)" end # Note that we should not include the module LIBC from some reason. We can call the library function strlen() using LIBC.strlen. If the first character of given function name is an uppercase, the first character of the defined method name becomes lowercase. We can also construct memory images of structures and unions using functions struct and union which are defined in "dl/struct.rb" as follows: require "dl/import" require "dl/struct" module LIBC extend DL::Importable Timeval = struct [ # define timeval structure. "long tv_sec", "long tv_uses", ] end val = LIBC::Timeval.malloc # allocate memory. Notice that the above example takes LIBC::Timeval.malloc to allocate memory, rather than LIBC::Timeval.new. It is because DL::Timeval.new is for wrapping an object, PtrData, which has already been created. We can define a callback using the module function "callback" as follows: module Foo extend DL::Importable def my_comp(str1,str2) str1 <=> str2 end COMPARE = callback "int my_comp(char*,char*)" end where Foo::COMPARE is a Symbol object which invokes the method "my_comp". DL::Importable module is very useful. However, we sometimes encounter a case that we must directly use low-level functions such as dlsym(). In such case, we would use DL module functions. They are described in next section. = DL module Module DL consists of three classes, a few module functions and constants. The class Symbol represents the symbol we can call. The class PtrData indicates a memory block such as a pointer in C. An object instantiated from the class Handle keeps a handle to opened library. == Constants * VERSION * MAJOR_VERSION * MINOR_VERSION * PATCH_VERSION * RTLD_GLOBAL * RTLD_LAZY * RTLD_NOW * MAX_ARG * MAX_CBARG * MAX_CBENT == Functions * handle = dlopen(lib){|handle| ... } * is quite equal to `Handle.new(lib)' * sym = set_callback(cbtype, entry){|args| ... } * sym = set_callback(cbtype, entry, proc) * makes entry-th pre-defined function to call the proc or given block. the entry-th pre-defined function is specified by cbtype and entry. cbtype is a prototype of the callback. see also the section `Type specifiers' about cbtype. * sym = get_callback(cbtype, entry) * returns the Proc object which is given by the above function `set_callback'. * ptr = malloc(size, [free = nil]) * allocates the size bytes, and returns the pointer as a PtrData object ptr. * ptr = strdup(str) * returns a PtrData object ptr which represents the pointer to a new string which is a duplicate of the string str. * size = sizeof(type) * returns the size of type. `sizeof("C") + sizeof("L")' is not equal to `sizeof("CL")'. the latter is assumed to returns the enough size of the structure `struct foo { char c; long l; }', but the size may not equal to `sizeof(foo)' of C. == Handle class * handle = Handle.new(lib){|handle| ... } * opens a library lib and returns a Handle object handle. if a block is given, the handle is automatically closed as the block ends. * Handle#close * closes the handle opened by the above Handle.new(lib). * sym = Handle#sym(func, prototype = "0"), sym = Handle#[func, prototype = nil] * obtains the pointer to a function called func and returns a Symbol object or a DataPtr object. prototype is a string which consists of type specifiers, it indicates the function's prototype. see also the section `Type specifiers'. == Symbol class * sym = Symbol.new(addr, type = nil, name = nil) * creates the Symbol object sym with the type type if type is not nil. addr is the address where the function is allocated. If type is nil, it returns a DataPtr object. * Symbol::char2type(char) * takes a character char that represents a type and returns the type specifier of the C language. * str = Symbol#proto() * returns the function prototype. * str = Symbol#name() * Returns the function name. * str = Symbol#cproto(), str = Symbol#to_s() * returns the prototype of the C language. * str = Symbol#inspect() * returns the inspectable string. * r,rs = Symbol#call(arg1,arg2,...,argN), r,rs = Symbol#[](arg1,arg2,...,argN) * calls the function with parameters arg1, arg2, ..., argN. and the result consists of the return value r and parameters rs. rs is an array. * ptr = Symbol#to_ptr * returns the corresponding PtrData object ptr. == PtrData class * ptr = PtrData.new(addr, [size = 0, free = nil]) * returns the PtrData object representing the pointer which indicates the address addr. GC frees the memory using the free function. * PtrData#free=(sym) * If you specify a symbol object sym, GC frees the memory using the function represented by sym. * sym = PtrData#free * returns a symbol object sym which is used when GC frees the memory. it usually configured by `PtrData#free=' or `PtrData.new'. * size = PtrData#size, PtrData#size=(size) * gets and sets allocated size of the memory. * ary = PtrData#to_a(type, [size]) * returns an array of the type which specified with type. type must be one of 'S','P','I','L','D' and 'F'. * str = PtrData#to_s([len]) * returns a string which length is len. if len is omitted, the end of the string is '\0'. * ptr = PtrData#ptr,+@ * returns the pointed value as a PtrData object ptr. * ptr = PtrData#ref,-@ * returns the reference as a PtrData object ptr. * ptr = PtrData#+ * returns the PtrData object * ptr = PtrData#- * returns the PtrData object * PtrData#struct!(type, *members) * defines the data type to get access to a structure member with a symbol. (see also PtrData#[]) * PtrData#union!(type, *members) * defines the data type to get access to a union member with a symbol. (see also PtrData#[]) * val = PtrData#[key], PtrData#[key, num = 0] * if the key is a string or symbol, this method returns the value of the structure/union member which has the type defined by PtrData# {struct!,union!}. if the key is a integer value and this object represents the pointer ptr, it returns the value of `(ptr + key).to_s(num)' * PtrData#[key,num]=val, PtrData#[key]=val * if the key is a string or symbol, this method substitute the value of the structure/union member with val. if the key is a integer value and val is a string, this method copies num bytes of val to the memory area ptr using memcpy(3). == Type specifiers the prototype consists of the following type specifiers, first element of prototype represents the type of return value, and remaining elements represent the type of each argument. C : char c : char * H : short h : short * I : int i : int * L : long l : long * F : float f : float * D : double d : double * S : const char * s : char * A : const type[] a : type[] (allocates new memory space) P : void * (same as 'p') p : void * (same as 'P') 0 : void function (this must be a first character of the prototype) the cbtype consists of type specifiers 0, C, I, H, L, F, D, S and P. for example: DL.callback('IPP'){|ptr1,ptr2| str1 = ptr1.ptr.to_s str2 = ptr2.ptr.to_s str1 <=> str2 } =end ================================================ FILE: ext/dl/extconf.rb ================================================ require 'mkmf' begin # for the exception SystemExit $:.unshift File.dirname(__FILE__) require 'type' if( ARGV.include?("--help") ) print < --with-callback= --enable-asm use the embedded assembler for passing arguments. (this option is available for i386 machine now.) --enable-dlstack use a stack emulation for constructing function call. EOF exit(0) end ($CPPFLAGS || $CFLAGS) << " -I." if (Config::CONFIG['CC'] =~ /gcc/) # from Win32API $CFLAGS << " -fno-defer-pop -fno-omit-frame-pointer" end $with_dlstack ||= true $with_asm = ! $with_dlstack $with_type_int = try_cpp(<\n") exit(1) end end max_arg ||= 6 max_callback = with_config("callback","10").to_i callback_types = DLTYPE.keys.length $dlconfig_h = <] [-d] [] EOF end while( ARGV[0] ) case( ARGV[0] ) when "-r" ARGV.shift $recursive = true when "-R" ARGV.shift $recursive = false when "-l" ARGV.shift $insert_require = true when "-L" ARGV.shift $insert_require = false when "-c" ARGV.shift $conly = true when "-C" ARGV.shift $conly = false when "-f" ARGV.shift $force = true when "-F" ARGV.shift $force = false when "-I" ARGV.shift $inc_path << ARGV.shift when "-d" ARGV.shift $DEBUG = true when "-h","--help" print_usage() exit 0 when /-.*/ $stderr.print("unknown option '#{ARGV[0]}'.\n") print_usage() exit 0 else $infilename = ARGV.shift end end $inc_dir = File.join(CONFIG["prefix"], "lib", "ruby", CONFIG["MAJOR"] + "." + CONFIG["MINOR"], "dl") class H2RBError < StandardError; end class H2RB def initialize(inc_dir = nil, inc_path = nil, insert_require = nil) @inc_path = inc_path || [] @inc_dir = inc_dir || '.' @indent = 0 @parsed_files = [] @insert_require = insert_require || false end def find_path(file) if( ! file ) return nil end if( File.exist?(file) ) if( file[0] == ?/ ) return file else return file end end @inc_path.each{|path| full = File.join(path, file) if( File.exist?(full) ) return full end } return nil end def strip_comment(line) if( @commented ) if( e = line.index("*/") ) line[0..(e+1)] = "" @commented = false else line = "" end else if( s = line.index("/*") ) if( e = line.index("*/") ) line[s..(e+1)] = "" else line[s..-1] = "" @commented = true end elsif( s = line.index("//") ) line[s..(-1)] = "" end end line.gsub!(/\s+$/,"") return line end def up_indent @indent += 1 end def down_indent @indent -= 1 if( @indent < 0 ) raise end end def indent " " * @indent end def rescue_begin line = "#{indent}begin" up_indent return line end def rescue_nameerror down_indent line = [ "#{indent}rescue NameError => e", "#{indent} raise e if( $DEBUG )", "#{indent}end"].join($/) return line end def parse_enum(line) if( line =~ /enum\s+(\S+\s+)?\{(.+)\}/ ) enum_name = $1 enum_block = $2 if( enum_name ) line = "#{indent}# -- enum #{enum_name}\n" else line = "#{indent}# -- enum\n" end enums = enum_block.split(/,/).collect{|e| e.strip} i = 0 enums.each{|elem| var,val = elem.split(/=/).collect{|e| e.strip} if( val ) i = val.to_i end line += "#{indent}#{var} = #{i.to_s}\n" i += 1 } line += "#{indent}# -- end of enum" return line else return nil end end def parse_define(line) case line when /^#\s*define\s+(\S+)\(\)/ line = nil when /^#\s*define\s+(\S+)\((.+)\)\s+(.+)$/ if( @conly ) line = nil else defname = $1 defargs = $2 defval = $3 if( !valid_ruby_code?(defval) ) defval = "nil # #{defval}" end if( defname[0,1] =~ /^[A-Z]$/ ) line = "#{indent}#{defname} = proc{|#{defargs}| #{defval}}" else line = [ "#{indent}def #{defname}(#{defargs})", "#{indent} #{defval}", "#{indent}end" ].join("\n") end end when /^#\s*define\s+(\S+)\((.+)\)$/ if( @conly ) line = nil else defname = $1 defargs = $2 defval = nil if( !valid_ruby_code?(defval) ) defval = "nil # #{defval}" end if( defname[0,1] =~ /^[A-Z]$/ ) line = "#{indent}#{defname} = proc{|#{defargs}| #{defval}}" else line = [ "#{indent}def #{defname}(#{defargs})", "#{indent} #{defval}", "#{indent}end" ].join("\n") end end when /^#\s*define\s+(\S+)\s+(.+)$/ defname = $1 defval = $2 if( !valid_ruby_code?(defval) ) defval = "nil # #{defval}" end line = [rescue_begin, "#{indent}#{defname} = #{defval}", rescue_nameerror].join($/) when /^#\s*define\s+(\S+)$/ defname = $1 line = "#{indent}#{defname} = nil" else line = nil end return line end def parse_undef(line) case line when /^#\s*undef\s+([A-Z]\S+)$/ defname = $1 line = "#{indent}remove_const(:#{defname})" when /^#\s*undef\s+(\S+)$/ defname = $1 line = "#{indent}#{defname} = nil" else line = nil end return line end def parse_ifdef(line) case line when /^#\s*ifdef\s+(\S+)$/ defname = $1 line = [ rescue_begin, "#{indent}if( defined?(#{defname}) && ! #{defname}.nil? )"].join($/) else line = nil end return line end def parse_ifndef(line) case line when /^#\s*ifndef\s+(\S+)$/ defname = $1 line = [ rescue_begin, "#{indent}if( ! defined?(#{defname}) || #{defname}.nil? )"].join($/) else line = nil end return line end def parse_if(line) case line when /^#\s*if\s+(.+)$/ cond = $1 cond.gsub!(/defined(.+)/){ "defined?(#{$1}) && ! #{$1}.nil?" } if( valid_ruby_code?(cond) ) line = "#{indent}if( #{cond} )" else line = "#{indent}if( false ) # #{cond}" end line = [rescue_begin, line].join($/) else line = nil end return line end def parse_elif(line) case line when /^#\s*elif\s+(.+)$/ cond = $1 cond.gsub!("defined","defined?") line = "#{indent}elsif( #{cond} )" else line = nil end return line end def parse_else(line) case line when /^#\s*else\s*/ line = "#{indent}else" else line = nil end return line end def parse_endif(line) case line when /^#\s*endif\s*$/ line = ["#{indent}end", rescue_nameerror].join($/) else line = nil end return line end def parse_include(line) if( ! @insert_require ) return nil end file = nil case line when /^#\s*include "(.+)"$/ file = $1 line = "#{indent}require '#{file}'" when /^#\s*include \<(.+)\>$/ file = $1 line = "#{indent}require '#{file}'" else line = nil end if( @recursive && file && (!@parsed_files.include?(file)) ) parse(file, @recursive, @force, @conly) end return line end def open_files(infilename) if( ! infilename ) return [$stdin, $stdout] end old_infilename = infilename infilename = find_path(infilename) if( ! infilename ) $stderr.print("'#{old_infilename}' was not found.\n") return [nil,nil] end if( infilename ) if( infilename[0,1] == '/' ) outfilename = File.join(@inc_dir, infilename[1..-1] + ".rb") else outfilename = infilename + ".rb" end File.mkpath(File.dirname(outfilename)) else outfilename = nil end if( infilename ) fin = File.open(infilename,"r") else fin = $stdin end if( outfilename ) if( File.exist?(outfilename) && (!@force) ) $stderr.print("'#{outfilename}' have already existed.\n") return [fin, nil] end fout = File.open(outfilename,"w") else fout = $stdout end $stderr.print("#{infilename} -> #{outfilename}\n") if( fout ) dir = File.dirname(outfilename) if( dir[0,1] != "." && dir != "" ) fout.print("if( ! $LOAD_PATH.include?('#{dir}') )\n", " $LOAD_PATH.push('#{dir}')\n", "end\n") end end return [fin,fout] end def parse(infilename = nil, recursive = false, force = false, conly = false) @commented = false @recursive = recursive @force = force @conly = conly @parsed_files << infilename fin,fout = open_files(infilename) if( !fin ) return end begin line_number = 0 pre_line = nil fin.each_line{|line| line_number += 1 line.chop! if( $DEBUG ) $stderr.print("#{line_number}:(#{@indent}):", line, "\n") end if( pre_line ) line = pre_line + line pre_line = nil end if( line[-1,1] == "\\" ) pre_line = line[0..-2] next end if( eidx = line.index("enum ") ) pre_line = line[eidx .. -1] if( i = line.index("{") && j = line.index("}") ) line = line[0..j] pre_line = nil else next end end line = strip_comment(line) case line when /^enum\s/ line = parse_enum(line) when /^#\s*define\s/ line = parse_define(line) when /^#\s*undef\s/ line = parse_undef(line) when /^#\s*ifdef\s/ line = parse_ifdef(line) up_indent when /^#\s*ifndef\s/ line = parse_ifndef(line) up_indent when /^#\s*if\s/ line = parse_if(line) up_indent when /^#\s*elif\s/ down_indent line = parse_elif(line) up_indent when /^#\s*else/ down_indent line = parse_else(line) up_indent when /^#\s*endif/ down_indent line = parse_endif(line) when /^#\s*include\s/ line = parse_include(line) else line = nil end if( line && fout ) fout.print(line, " # #{line_number}",$/) end } ensure fin.close if fin fout.close if fout end end end h2rb = H2RB.new($inc_dir, $inc_path, $insert_require) h2rb.parse($infilename, $recursive, $force, $conly) ================================================ FILE: ext/dl/handle.c ================================================ /* -*- C -*- * $Id$ */ #include #include "dl.h" VALUE rb_cDLHandle; void dlhandle_free(struct dl_handle *dlhandle) { if (dlhandle->ptr && dlhandle->open && dlhandle->enable_close) { dlclose(dlhandle->ptr); } } VALUE rb_dlhandle_close(VALUE self) { struct dl_handle *dlhandle; Data_Get_Struct(self, struct dl_handle, dlhandle); dlhandle->open = 0; return INT2NUM(dlclose(dlhandle->ptr)); } VALUE rb_dlhandle_s_allocate(VALUE klass) { VALUE obj; struct dl_handle *dlhandle; obj = Data_Make_Struct(rb_cDLHandle, struct dl_handle, 0, dlhandle_free, dlhandle); dlhandle->ptr = 0; dlhandle->open = 0; dlhandle->enable_close = 0; return obj; } VALUE rb_dlhandle_initialize(int argc, VALUE argv[], VALUE self) { void *ptr; struct dl_handle *dlhandle; VALUE lib, flag; char *clib; int cflag; const char *err; switch (rb_scan_args(argc, argv, "11", &lib, &flag)) { case 1: clib = NIL_P(lib) ? NULL : StringValuePtr(lib); cflag = RTLD_LAZY | RTLD_GLOBAL; break; case 2: clib = NIL_P(lib) ? NULL : StringValuePtr(lib); cflag = NUM2INT(flag); break; default: rb_bug("rb_dlhandle_new"); } ptr = dlopen(clib, cflag); #if defined(HAVE_DLERROR) if (!ptr && (err = dlerror())) { rb_raise(rb_eRuntimeError, "%s", err); } #else if (!ptr) { err = dlerror(); rb_raise(rb_eRuntimeError, "%s", err); } #endif Data_Get_Struct(self, struct dl_handle, dlhandle); if (dlhandle->ptr && dlhandle->open && dlhandle->enable_close) { dlclose(dlhandle->ptr); } dlhandle->ptr = ptr; dlhandle->open = 1; dlhandle->enable_close = 0; if (rb_block_given_p()) { rb_ensure(rb_yield, self, rb_dlhandle_close, self); } return Qnil; } VALUE rb_dlhandle_enable_close(VALUE self) { struct dl_handle *dlhandle; Data_Get_Struct(self, struct dl_handle, dlhandle); dlhandle->enable_close = 1; return Qnil; } VALUE rb_dlhandle_disable_close(VALUE self) { struct dl_handle *dlhandle; Data_Get_Struct(self, struct dl_handle, dlhandle); dlhandle->enable_close = 0; return Qnil; } VALUE rb_dlhandle_to_i(VALUE self) { struct dl_handle *dlhandle; Data_Get_Struct(self, struct dl_handle, dlhandle); return DLLONG2NUM(dlhandle); } VALUE rb_dlhandle_to_ptr(VALUE self) { struct dl_handle *dlhandle; Data_Get_Struct(self, struct dl_handle, dlhandle); return rb_dlptr_new(dlhandle, sizeof(dlhandle), 0); } VALUE rb_dlhandle_sym(int argc, VALUE argv[], VALUE self) { VALUE sym, type; void (*func)(); VALUE val; struct dl_handle *dlhandle; void *handle; const char *name, *stype; const char *err; rb_secure(2); if (rb_scan_args(argc, argv, "11", &sym, &type) == 2) { SafeStringValue(type); stype = StringValuePtr(type); } else{ stype = NULL; } if (sym == Qnil) { #if defined(RTLD_NEXT) name = RTLD_NEXT; #else name = NULL; #endif } else{ SafeStringValue(sym); name = StringValuePtr(sym); } Data_Get_Struct(self, struct dl_handle, dlhandle); if (!dlhandle->open) { rb_raise(rb_eRuntimeError, "closed handle"); } handle = dlhandle->ptr; func = dlsym(handle, name); #if defined(HAVE_DLERROR) if (!func && (err = dlerror())) #else if (!func) #endif { #if defined(__CYGWIN__) || defined(WIN32) || defined(__MINGW32__) { int len = strlen(name); char *name_a = (char*)dlmalloc(len+2); strcpy(name_a, name); name_a[len] = 'A'; name_a[len+1] = '\0'; func = dlsym(handle, name_a); dlfree(name_a); #if defined(HAVE_DLERROR) if (!func && (err = dlerror())) #else if (!func) #endif { rb_raise(rb_eRuntimeError, "unknown symbol \"%sA\"", name); } } #else rb_raise(rb_eRuntimeError, "unknown symbol \"%s\"", name); #endif } val = rb_dlsym_new(func, name, stype); return val; } void Init_dlhandle() { rb_cDLHandle = rb_define_class_under(rb_mDL, "Handle", rb_cObject); rb_define_alloc_func(rb_cDLHandle, rb_dlhandle_s_allocate); rb_define_method(rb_cDLHandle, "initialize", rb_dlhandle_initialize, -1); rb_define_method(rb_cDLHandle, "to_i", rb_dlhandle_to_i, 0); rb_define_method(rb_cDLHandle, "to_ptr", rb_dlhandle_to_ptr, 0); rb_define_method(rb_cDLHandle, "close", rb_dlhandle_close, 0); rb_define_method(rb_cDLHandle, "sym", rb_dlhandle_sym, -1); rb_define_method(rb_cDLHandle, "[]", rb_dlhandle_sym, -1); rb_define_method(rb_cDLHandle, "disable_close", rb_dlhandle_disable_close, 0); rb_define_method(rb_cDLHandle, "enable_close", rb_dlhandle_enable_close, 0); } ================================================ FILE: ext/dl/install.rb ================================================ require 'mkmf' require 'ftools' SO_LIBS = ["dl.so"] $ruby_version = CONFIG['MAJOR'] + "." + CONFIG['MINOR'] $prefix = CONFIG['prefix'] $libdir = File.join($prefix,'lib') $rubylibdir = File.join($libdir, 'ruby', $ruby_version) $arch = CONFIG['arch'] $archdir = File.join($rubylibdir, $arch) def find(dir, match = /./) Dir.chdir(dir) files = [] Dir.new(".").each{|file| if( file != "." && file != ".." ) case File.ftype(file) when "file" if( file =~ match ) files.push(File.join(dir,file)) end when "directory" files += find(file, match).collect{|f| File.join(dir,f)} end end } Dir.chdir("..") return files end def install() rb_files = find(File.join(".","lib"), /.rb$/) SO_LIBS.each{|f| File.makedirs($rubylibdir, "#{$archdir}") File.install(f, File.join($archdir,f), 0555, true) } rb_files.each{|f| origfile = f instfile = File.join($rubylibdir, origfile.sub("./lib/","")) instdir = File.dirname(instfile) File.makedirs(instdir) File.install(origfile, instfile, 0644, true) } end install() ================================================ FILE: ext/dl/lib/dl/import.rb ================================================ # -*- ruby -*- require 'dl' require 'dl/types' module DL module Importable LIB_MAP = {} module Internal def init_types() @types ||= ::DL::Types.new end def init_sym() @SYM ||= {} end def [](name) return @SYM[name.to_s][0] end def dlload(*libnames) if( !defined?(@LIBS) ) @LIBS = [] end libnames.each{|libname| if( !LIB_MAP[libname] ) LIB_MAP[libname] = DL.dlopen(libname) end @LIBS.push(LIB_MAP[libname]) } end alias dllink :dlload def parse_cproto(proto) proto = proto.gsub(/\s+/, " ").strip case proto when /^([\d\w\*_\s]+)\(([\d\w\*_\s\,\[\]]*)\)$/ ret = $1 args = $2.strip() ret = ret.split(/\s+/) args = args.split(/\s*,\s*/) func = ret.pop() if( func =~ /^\*/ ) func.gsub!(/^\*+/,"") ret.push("*") end ret = ret.join(" ") return [func, ret, args] else raise(RuntimeError,"can't parse the function prototype: #{proto}") end end # example: # extern "int strlen(char*)" # def extern(proto) func,ret,args = parse_cproto(proto) return import(func, ret, args) end # example: # callback "int method_name(int, char*)" # def callback(proto) func,ret,args = parse_cproto(proto) init_types() init_sym() rty,renc,rdec = @types.encode_return_type(ret) if( !rty ) raise(TypeError, "unsupported type: #{ret}") end ty,enc,dec = encode_argument_types(args) symty = rty + ty module_eval("module_function :#{func}") sym = module_eval([ "DL::callback(\"#{symty}\"){|*args|", " sym,rdec,enc,dec = @SYM['#{func}']", " args = enc.call(args) if enc", " r,rs = #{func}(*args)", " r = renc.call(r) if rdec", " rs = dec.call(rs) if (dec && rs)", " @retval = r", " @args = rs", " r", "}", ].join("\n")) @SYM[func] = [sym,rdec,enc,dec] return sym end # example: # typealias("uint", "unsigned int") # def typealias(alias_type, ty1, enc1=nil, dec1=nil, ty2=nil, enc2=nil, dec2=nil) init_types() @types.typealias(alias_type, ty1, enc1, dec1, ty2||ty1, enc2, dec2) end # example: # symbol "foo_value" # symbol "foo_func", "IIP" # def symbol(name, ty = nil) sym = nil @LIBS.each{|lib| begin if( ty ) sym = lib[name, ty] else sym = lib[name] end rescue next end } if( !sym ) raise(RuntimeError, "can't find the symbol `#{name}'") end return sym end # example: # import("get_length", "int", ["void*", "int"]) # def import(name, rettype, argtypes = nil) init_types() init_sym() rty,_,rdec = @types.encode_return_type(rettype) if( !rty ) raise(TypeError, "unsupported type: #{rettype}") end ty,enc,dec = encode_argument_types(argtypes) symty = rty + ty sym = symbol(name, symty) mname = name.dup if( ?A <= mname[0] && mname[0] <= ?Z ) mname[0,1] = mname[0,1].downcase end @SYM[mname] = [sym,rdec,enc,dec] module_eval [ "def #{mname}(*args)", " sym,rdec,enc,dec = @SYM['#{mname}']", " args = enc.call(args) if enc", if( $DEBUG ) " p \"[DL] call #{mname} with \#{args.inspect}\"" else "" end, " r,rs = sym.call(*args)", if( $DEBUG ) " p \"[DL] retval=\#{r.inspect} args=\#{rs.inspect}\"" else "" end, " r = rdec.call(r) if rdec", " rs = dec.call(rs) if dec", " @retval = r", " @args = rs", " return r", "end", "module_function :#{mname}", ].join("\n") return sym end def _args_ return @args end def _retval_ return @retval end def encode_argument_types(tys) init_types() encty = [] enc = nil dec = nil tys.each_with_index{|ty,idx| ty,c1,c2 = @types.encode_argument_type(ty) if( !ty ) raise(TypeError, "unsupported type: #{ty}") end encty.push(ty) if( enc ) if( c1 ) conv1 = enc enc = proc{|v| v = conv1.call(v); v[idx] = c1.call(v[idx]); v} end else if( c1 ) enc = proc{|v| v[idx] = c1.call(v[idx]); v} end end if( dec ) if( c2 ) conv2 = dec dec = proc{|v| v = conv2.call(v); v[idx] = c2.call(v[idx]); v} end else if( c2 ) dec = proc{|v| v[idx] = c2.call(v[idx]); v} end end } return [encty.join, enc, dec] end end # end of Internal include Internal end # end of Importable end ================================================ FILE: ext/dl/lib/dl/struct.rb ================================================ # -*- ruby -*- require 'dl' require 'dl/import' module DL module Importable module Internal def define_struct(contents) init_types() Struct.new(@types, contents) end alias struct define_struct def define_union(contents) init_types() Union.new(@types, contents) end alias union define_union class Memory def initialize(ptr, names, ty, len, enc, dec) @ptr = ptr @names = names @ty = ty @len = len @enc = enc @dec = dec # define methods @names.each{|name| instance_eval [ "def #{name}", " v = @ptr[\"#{name}\"]", " if( @len[\"#{name}\"] )", " v = v.collect{|x| @dec[\"#{name}\"] ? @dec[\"#{name}\"].call(x) : x }", " else", " v = @dec[\"#{name}\"].call(v) if @dec[\"#{name}\"]", " end", " return v", "end", "def #{name}=(v)", " if( @len[\"#{name}\"] )", " v = v.collect{|x| @enc[\"#{name}\"] ? @enc[\"#{name}\"].call(x) : x }", " else", " v = @enc[\"#{name}\"].call(v) if @enc[\"#{name}\"]", " end", " @ptr[\"#{name}\"] = v", " return v", "end", ].join("\n") } end def to_ptr return @ptr end def size return @ptr.size end end class Struct def initialize(types, contents) @names = [] @ty = {} @len = {} @enc = {} @dec = {} @size = 0 @tys = "" @types = types parse(contents) end def size return @size end def members return @names end # ptr must be a PtrData object. def new(ptr) ptr.struct!(@tys, *@names) mem = Memory.new(ptr, @names, @ty, @len, @enc, @dec) return mem end def malloc(size = nil) if( !size ) size = @size end ptr = DL::malloc(size) return new(ptr) end def parse(contents) contents.each{|elem| name,ty,num,enc,dec = parse_elem(elem) @names.push(name) @ty[name] = ty @len[name] = num @enc[name] = enc @dec[name] = dec if( num ) @tys += "#{ty}#{num}" else @tys += ty end } @size = DL.sizeof(@tys) end def parse_elem(elem) elem.strip! case elem when /^([\w\d_\*]+)([\*\s]+)([\w\d_]+)$/ ty = ($1 + $2).strip name = $3 num = nil; when /^([\w\d_\*]+)([\*\s]+)([\w\d_]+)\[(\d+)\]$/ ty = ($1 + $2).strip name = $3 num = $4.to_i else raise(RuntimeError, "invalid element: #{elem}") end ty,enc,dec = @types.encode_struct_type(ty) if( !ty ) raise(TypeError, "unsupported type: #{ty}") end return [name,ty,num,enc,dec] end end # class Struct class Union < Struct def new ptr = DL::malloc(@size) ptr.union!(@tys, *@names) mem = Memory.new(ptr, @names, @ty, @len, @enc, @dec) return mem end end end # module Internal end # module Importable end # module DL ================================================ FILE: ext/dl/lib/dl/types.rb ================================================ # -*- ruby -*- require 'dl' module DL class Types TYPES = [ # FORMAT: # ["alias name", # "type name", encoding_method, decoding_method, for function prototypes # "type name", encoding_method, decoding_method] for structures (not implemented) # for Windows ["DWORD", "unsigned long", nil, nil, "unsigned long", nil, nil], ["PDWORD", "unsigned long *", nil, nil, "unsigned long *", nil, nil], ["WORD", "unsigned short", nil, nil, "unsigned short", nil, nil], ["PWORD", "unsigned int *", nil, nil, "unsigned int *", nil, nil], ["BYTE", "unsigned char", nil, nil, "unsigned char", nil, nil], ["PBYTE", "unsigned char *", nil, nil, "unsigned char *", nil, nil], ["BOOL", "ibool", nil, nil, "ibool", nil, nil], ["ATOM", "int", nil, nil, "int", nil, nil], ["BYTE", "unsigned char", nil, nil, "unsigned char", nil, nil], ["PBYTE", "unsigned char *", nil, nil, "unsigned char *", nil, nil], ["UINT", "unsigned int", nil, nil, "unsigned int", nil, nil], ["ULONG", "unsigned long", nil, nil, "unsigned long", nil, nil], ["UCHAR", "unsigned char", nil, nil, "unsigned char", nil, nil], ["HANDLE", "unsigned long", nil, nil, "unsigned long", nil, nil], ["PHANDLE","void*", nil, nil, "void*", nil, nil], ["PVOID", "void*", nil, nil, "void*", nil, nil], ["LPCSTR", "char*", nil, nil, "char*", nil, nil], ["HDC", "unsigned int", nil, nil, "unsigned int", nil, nil], ["HWND", "unsigned int", nil, nil, "unsigned int", nil, nil], # Others ["uint", "unsigned int", nil, nil, "unsigned int", nil, nil], ["u_int", "unsigned int", nil, nil, "unsigned int", nil, nil], ["ulong", "unsigned long", nil, nil, "unsigned long", nil, nil], ["u_long", "unsigned long", nil, nil, "unsigned long", nil, nil], # DL::Importable primitive types ["ibool", "I", proc{|v| v ? 1 : 0}, proc{|v| (v != 0) ? true : false}, "I", proc{|v| v ? 1 : 0 }, proc{|v| (v != 0) ? true : false} ], ["cbool", "C", proc{|v| v ? 1 : 0}, proc{|v| (v != 0) ? true : false}, "C", proc{|v,len| v ? 1 : 0}, proc{|v,len| (v != 0) ? true : false}], ["lbool", "L", proc{|v| v ? 1 : 0}, proc{|v| (v != 0) ? true : false}, "L", proc{|v,len| v ? 1 : 0}, proc{|v,len| (v != 0) ? true : false}], ["unsigned char", "C", proc{|v| [v].pack("C").unpack("c")[0]}, proc{|v| [v].pack("c").unpack("C")[0]}, "C", proc{|v| [v].pack("C").unpack("c")[0]}, proc{|v| [v].pack("c").unpack("C")[0]}], ["unsigned short", "H", proc{|v| [v].pack("S").unpack("s")[0]}, proc{|v| [v].pack("s").unpack("S")[0]}, "H", proc{|v| [v].pack("S").unpack("s")[0]}, proc{|v| [v].pack("s").unpack("S")[0]}], ["unsigned int", "I", proc{|v| [v].pack("I").unpack("i")[0]}, proc{|v| [v].pack("i").unpack("I")[0]}, "I", proc{|v| [v].pack("I").unpack("i")[0]}, proc{|v| [v].pack("i").unpack("I")[0]}], ["unsigned long", "L", proc{|v| [v].pack("L").unpack("l")[0]}, proc{|v| [v].pack("l").unpack("L")[0]}, "L", proc{|v| [v].pack("L").unpack("l")[0]}, proc{|v| [v].pack("l").unpack("L")[0]}], ["unsigned char ref", "c", proc{|v| [v].pack("C").unpack("c")[0]}, proc{|v| [v].pack("c").unpack("C")[0]}, nil, nil, nil], ["unsigned int ref", "i", proc{|v| [v].pack("I").unpack("i")[0]}, proc{|v| [v].pack("i").unpack("I")[0]}, nil, nil, nil], ["unsigned long ref", "l", proc{|v| [v].pack("L").unpack("l")[0]}, proc{|v| [v].pack("l").unpack("L")[0]}, nil, nil, nil], ["char ref", "c", nil, nil, nil, nil, nil], ["short ref", "h", nil, nil, nil, nil, nil], ["int ref", "i", nil, nil, nil, nil, nil], ["long ref", "l", nil, nil, nil, nil, nil], ["float ref", "f", nil, nil, nil, nil, nil], ["double ref","d", nil, nil, nil, nil, nil], ["char", "C", nil, nil, "C", nil, nil], ["short", "H", nil, nil, "H", nil, nil], ["int", "I", nil, nil, "I", nil, nil], ["long", "L", nil, nil, "L", nil, nil], ["float", "F", nil, nil, "F", nil, nil], ["double", "D", nil, nil, "D", nil, nil], [/^char\s*\*$/,"s",nil, nil, "S",nil, nil], [/^const char\s*\*$/,"S",nil, nil, "S",nil, nil], [/^.+\*$/, "P", nil, nil, "P", nil, nil], [/^.+\[\]$/, "a", nil, nil, "a", nil, nil], ["void", "0", nil, nil, nil, nil, nil], ] def initialize init_types() end def typealias(ty1, ty2, enc=nil, dec=nil, ty3=nil, senc=nil, sdec=nil) @TYDEFS.unshift([ty1, ty2, enc, dec, ty3, senc, sdec]) end def init_types @TYDEFS = TYPES.dup end def encode_argument_type(alias_type) proc_encode = nil proc_decode = nil @TYDEFS.each{|aty,ty,enc,dec,_,_,_| if( (aty.is_a?(Regexp) && (aty =~ alias_type)) || (aty == alias_type) ) alias_type = alias_type.gsub(aty,ty) if ty alias_type.strip! if alias_type if( proc_encode ) if( enc ) conv1 = proc_encode proc_encode = proc{|v| enc.call(conv1.call(v))} end else if( enc ) proc_encode = enc end end if( proc_decode ) if( dec ) conv2 = proc_decode proc_decode = proc{|v| dec.call(conv2.call(v))} end else if( dec ) proc_decode = dec end end end } return [alias_type, proc_encode, proc_decode] end def encode_return_type(ty) ty, enc, dec = encode_argument_type(ty) return [ty, enc, dec] end def encode_struct_type(alias_type) proc_encode = nil proc_decode = nil @TYDEFS.each{|aty,_,_,_,ty,enc,dec| if( (aty.is_a?(Regexp) && (aty =~ alias_type)) || (aty == alias_type) ) alias_type = alias_type.gsub(aty,ty) if ty alias_type.strip! if alias_type if( proc_encode ) if( enc ) conv1 = proc_encode proc_encode = proc{|v| enc.call(conv1.call(v))} end else if( enc ) proc_encode = enc end end if( proc_decode ) if( dec ) conv2 = proc_decode proc_decode = proc{|v| dec.call(conv2.call(v))} end else if( dec ) proc_decode = dec end end end } return [alias_type, proc_encode, proc_decode] end end # end of Types end ================================================ FILE: ext/dl/lib/dl/win32.rb ================================================ # -*- ruby -*- require 'dl' class Win32API DLL = {} def initialize(dllname, func, import, export = "0") prototype = (export + import.to_s).tr("VPpNnLlIi", "0SSI").sub(/^(.)0*$/, '\1') handle = DLL[dllname] ||= DL::Handle.new(dllname) @sym = handle.sym(func, prototype) end def call(*args) import = @sym.proto.split("", 2)[1] args.each_with_index do |x, i| args[i] = nil if x == 0 and import[i] == ?S args[i], = [x].pack("I").unpack("i") if import[i] == ?I end ret, = @sym.call(*args) return ret || 0 end alias Call call end ================================================ FILE: ext/dl/mkcall.rb ================================================ # -*- ruby -*- require 'mkmf' $:.unshift File.dirname(__FILE__) require 'type' require 'dlconfig' def output_arg(x,i) "args[#{i}].#{DLTYPE[x][:stmem]}" end def output_args(types) t = [] types[1..-1].each_with_index{|x,i| t.push(output_arg(x,i))} t.join(",") end def output_callfunc(types) t = types[0] stmem = DLTYPE[t][:stmem] ctypes = types2ctypes(types) if( t == VOID ) callstm = "(*f)(#{output_args(types)})" else callstm = "ret.#{stmem} = (*f)(#{output_args(types)})" end [ "{", "#{ctypes[0]} (*f)(#{ctypes[1..-1].join(',')}) = func;", "#{callstm};", "}"].join(" ") end def output_case(types) num = types2num(types) callfunc_stm = output_callfunc(types) <len >= #{argc.to_s} )", " rb_raise(rb_eArgError, \"too many arguments\");", " rb_dl_scan_callback_args(buff, RSTRING(proto)->ptr, &argc, argv);", " retval = rb_funcall2(proc, id_call, argc, argv);", "", ret_code, "}", ].join("\n") return code end DLTYPE.keys.sort.each{|t| for n in 0..(MAX_CALLBACK - 1) print(mkfunc(t, n, 15), "\n\n") end } ================================================ FILE: ext/dl/mkcbtable.rb ================================================ # -*- ruby -*- require 'mkmf' $:.unshift File.dirname(__FILE__) require 'type' require 'dlconfig' def mktable(rettype, fnum, argc) code = "rb_dl_callback_table[#{rettype}][#{fnum}] = &rb_dl_callback_func_#{rettype.to_s}_#{fnum};" return code end DLTYPE.keys.sort.each{|t| for n in 0..(MAX_CALLBACK - 1) print(mktable(t, n, 15), "\n") end } ================================================ FILE: ext/dl/ptr.c ================================================ /* -*- C -*- * $Id$ */ #include #include #include "st.h" #include "dl.h" VALUE rb_cDLPtrData; VALUE rb_mDLMemorySpace; static st_table* st_memory_table; #ifndef T_SYMBOL # define T_SYMBOL T_FIXNUM #endif static void rb_dlmem_delete(void *ptr) { rb_secure(4); st_delete(st_memory_table, (st_data_t*)&ptr, NULL); } static void rb_dlmem_aset(void *ptr, VALUE obj) { if (obj == Qnil) { rb_dlmem_delete(ptr); } else{ st_insert(st_memory_table, (st_data_t)ptr, (st_data_t)obj); } } static VALUE rb_dlmem_aref(void *ptr) { VALUE val; if(!st_lookup(st_memory_table, (st_data_t)ptr, &val)) return Qnil; return val == Qundef ? Qnil : val; } void dlptr_free(struct ptr_data *data) { if (data->ptr) { DEBUG_CODE({ printf("dlptr_free(): removing the pointer `0x%x' from the MemorySpace\n", data->ptr); }); rb_dlmem_delete(data->ptr); if (data->free) { DEBUG_CODE({ printf("dlptr_free(): 0x%x(data->ptr:0x%x)\n",data->free,data->ptr); }); (*(data->free))(data->ptr); } } if (data->stype) dlfree(data->stype); if (data->ssize) dlfree(data->ssize); if (data->ids) dlfree(data->ids); } void dlptr_init(VALUE val) { struct ptr_data *data; Data_Get_Struct(val, struct ptr_data, data); DEBUG_CODE({ printf("dlptr_init(): add the pointer `0x%x' to the MemorySpace\n", data->ptr); }); rb_dlmem_aset(data->ptr, val); OBJ_TAINT(val); } VALUE rb_dlptr_new2(VALUE klass, void *ptr, long size, freefunc_t func) { struct ptr_data *data; VALUE val; rb_secure(4); if (ptr) { val = rb_dlmem_aref(ptr); if (val == Qnil) { val = Data_Make_Struct(klass, struct ptr_data, 0, dlptr_free, data); data->ptr = ptr; data->free = func; data->ctype = DLPTR_CTYPE_UNKNOWN; data->stype = NULL; data->ssize = NULL; data->slen = 0; data->size = size; data->ids = NULL; data->ids_num = 0; dlptr_init(val); } else{ if (func) { Data_Get_Struct(val, struct ptr_data, data); data->free = func; } } } else{ val = Qnil; } return val; } VALUE rb_dlptr_new(void *ptr, long size, freefunc_t func) { return rb_dlptr_new2(rb_cDLPtrData, ptr, size, func); } VALUE rb_dlptr_malloc(long size, freefunc_t func) { void *ptr; rb_secure(4); ptr = dlmalloc((size_t)size); memset(ptr,0,(size_t)size); return rb_dlptr_new(ptr, size, func); } void * rb_dlptr2cptr(VALUE val) { struct ptr_data *data; void *ptr; if (rb_obj_is_kind_of(val, rb_cDLPtrData)) { Data_Get_Struct(val, struct ptr_data, data); ptr = data->ptr; } else if (val == Qnil) { ptr = NULL; } else{ rb_raise(rb_eTypeError, "DL::PtrData was expected"); } return ptr; } static VALUE rb_dlptr_s_allocate(VALUE klass) { VALUE obj; struct ptr_data *data; rb_secure(4); obj = Data_Make_Struct(klass, struct ptr_data, 0, dlptr_free, data); data->ptr = 0; data->free = 0; data->ctype = DLPTR_CTYPE_UNKNOWN; data->stype = NULL; data->ssize = NULL; data->slen = 0; data->size = 0; data->ids = NULL; data->ids_num = 0; return obj; } static VALUE rb_dlptr_initialize(int argc, VALUE argv[], VALUE self) { VALUE ptr, sym, size; struct ptr_data *data; void *p = NULL; freefunc_t f = NULL; long s = 0; switch (rb_scan_args(argc, argv, "12", &ptr, &size, &sym)) { case 1: p = (void*)(DLNUM2LONG(rb_Integer(ptr))); break; case 2: p = (void*)(DLNUM2LONG(rb_Integer(ptr))); s = DLNUM2LONG(size); break; case 3: p = (void*)(DLNUM2LONG(rb_Integer(ptr))); s = DLNUM2LONG(size); f = rb_dlsym2csym(sym); break; default: rb_bug("rb_dlptr_initialize"); } if (p) { Data_Get_Struct(self, struct ptr_data, data); if (data->ptr && data->free) { /* Free previous memory. Use of inappropriate initialize may cause SEGV. */ (*(data->free))(data->ptr); } data->ptr = p; data->size = s; data->free = f; } return Qnil; } static VALUE rb_dlptr_s_malloc(int argc, VALUE argv[], VALUE klass) { VALUE size, sym, obj; int s; freefunc_t f = NULL; switch (rb_scan_args(argc, argv, "11", &size, &sym)) { case 1: s = NUM2INT(size); break; case 2: s = NUM2INT(size); f = rb_dlsym2csym(sym); break; default: rb_bug("rb_dlptr_s_malloc"); } obj = rb_dlptr_malloc(s,f); return obj; } VALUE rb_dlptr_to_i(VALUE self) { struct ptr_data *data; Data_Get_Struct(self, struct ptr_data, data); return DLLONG2NUM(data->ptr); } VALUE rb_dlptr_ptr(VALUE self) { struct ptr_data *data; Data_Get_Struct(self, struct ptr_data, data); return rb_dlptr_new(*((void**)(data->ptr)),0,0); } VALUE rb_dlptr_ref(VALUE self) { struct ptr_data *data; Data_Get_Struct(self, struct ptr_data, data); return rb_dlptr_new(&(data->ptr),0,0); } VALUE rb_dlptr_null_p(VALUE self) { struct ptr_data *data; Data_Get_Struct(self, struct ptr_data, data); return data->ptr ? Qfalse : Qtrue; } VALUE rb_dlptr_free_set(VALUE self, VALUE val) { struct ptr_data *data; Data_Get_Struct(self, struct ptr_data, data); data->free = DLFREEFUNC(rb_dlsym2csym(val)); return Qnil; } VALUE rb_dlptr_free_get(VALUE self) { struct ptr_data *pdata; Data_Get_Struct(self, struct ptr_data, pdata); return rb_dlsym_new(pdata->free,"(free)","0P"); } VALUE rb_dlptr_to_array(int argc, VALUE argv[], VALUE self) { struct ptr_data *data; int n; int i; int t; VALUE ary; VALUE type, size; Data_Get_Struct(self, struct ptr_data, data); switch (rb_scan_args(argc, argv, "11", &type, &size)) { case 2: t = StringValuePtr(type)[0]; n = NUM2INT(size); break; case 1: t = StringValuePtr(type)[0]; switch (t) { case 'C': n = data->size; break; case 'H': n = data->size / sizeof(short); break; case 'I': n = data->size / sizeof(int); break; case 'L': n = data->size / sizeof(long); break; case 'F': n = data->size / sizeof(float); break; case 'D': n = data->size / sizeof(double); break; case 'P': case 'p': n = data->size / sizeof(void*); break; case 'S': case 's': n = data->size / sizeof(char*); break; default: n = 0; } break; default: rb_bug("rb_dlptr_to_array"); } ary = rb_ary_new(); for (i=0; i < n; i++) { switch (t) { case 'C': rb_ary_push(ary, INT2NUM(((char*)(data->ptr))[i])); break; case 'H': rb_ary_push(ary, INT2NUM(((short*)(data->ptr))[i])); break; case 'I': rb_ary_push(ary, INT2NUM(((int*)(data->ptr))[i])); break; case 'L': rb_ary_push(ary, DLLONG2NUM(((long*)(data->ptr))[i])); break; case 'D': rb_ary_push(ary, rb_float_new(((double*)(data->ptr))[i])); break; case 'F': rb_ary_push(ary, rb_float_new(((float*)(data->ptr))[i])); break; case 'S': { char *str = ((char**)(data->ptr))[i]; if (str) { rb_ary_push(ary, rb_tainted_str_new2(str)); } else{ rb_ary_push(ary, Qnil); } } break; case 's': { char *str = ((char**)(data->ptr))[i]; if (str) { rb_ary_push(ary, rb_tainted_str_new2(str)); xfree(str); } else{ rb_ary_push(ary, Qnil); } } break; case 'P': rb_ary_push(ary, rb_dlptr_new(((void**)(data->ptr))[i],0,0)); break; case 'p': rb_ary_push(ary, rb_dlptr_new(((void**)(data->ptr))[i],0,dlfree)); break; } } return ary; } VALUE rb_dlptr_to_s(int argc, VALUE argv[], VALUE self) { struct ptr_data *data; VALUE arg1, val; int len; Data_Get_Struct(self, struct ptr_data, data); switch (rb_scan_args(argc, argv, "01", &arg1)) { case 0: val = rb_tainted_str_new2((char*)(data->ptr)); break; case 1: len = NUM2INT(arg1); val = rb_tainted_str_new((char*)(data->ptr), len); break; default: rb_bug("rb_dlptr_to_s"); } return val; } VALUE rb_dlptr_to_str(int argc, VALUE argv[], VALUE self) { struct ptr_data *data; VALUE arg1, val; int len; Data_Get_Struct(self, struct ptr_data, data); switch (rb_scan_args(argc, argv, "01", &arg1)) { case 0: val = rb_tainted_str_new((char*)(data->ptr),data->size); break; case 1: len = NUM2INT(arg1); val = rb_tainted_str_new((char*)(data->ptr), len); break; default: rb_bug("rb_dlptr_to_str"); } return val; } VALUE rb_dlptr_inspect(VALUE self) { struct ptr_data *data; char str[1024]; Data_Get_Struct(self, struct ptr_data, data); snprintf(str, 1023, "#<%s:0x%lx ptr=0x%lx size=%ld free=0x%lx>", rb_class2name(CLASS_OF(self)), data, data->ptr, data->size, (long)data->free); return rb_str_new2(str); } VALUE rb_dlptr_eql(VALUE self, VALUE other) { void *ptr1, *ptr2; ptr1 = rb_dlptr2cptr(self); ptr2 = rb_dlptr2cptr(other); return ptr1 == ptr2 ? Qtrue : Qfalse; } VALUE rb_dlptr_cmp(VALUE self, VALUE other) { void *ptr1, *ptr2; ptr1 = rb_dlptr2cptr(self); ptr2 = rb_dlptr2cptr(other); return DLLONG2NUM((long)ptr1 - (long)ptr2); } VALUE rb_dlptr_plus(VALUE self, VALUE other) { void *ptr; long num, size; ptr = rb_dlptr2cptr(self); size = RDLPTR(self)->size; num = DLNUM2LONG(other); return rb_dlptr_new((char *)ptr + num, size - num, 0); } VALUE rb_dlptr_minus(VALUE self, VALUE other) { void *ptr; long num, size; ptr = rb_dlptr2cptr(self); size = RDLPTR(self)->size; num = DLNUM2LONG(other); return rb_dlptr_new((char *)ptr - num, size + num, 0); } VALUE rb_dlptr_define_data_type(int argc, VALUE argv[], VALUE self) { VALUE data_type, type, rest, vid; struct ptr_data *data; int i, t, num; char *ctype; rb_scan_args(argc, argv, "11*", &data_type, &type, &rest); Data_Get_Struct(self, struct ptr_data, data); if (argc == 1 || (argc == 2 && type == Qnil)) { if (NUM2INT(data_type) == DLPTR_CTYPE_UNKNOWN) { data->ctype = DLPTR_CTYPE_UNKNOWN; data->slen = 0; data->ids_num = 0; if (data->stype) { dlfree(data->stype); data->stype = NULL; } if (data->ids) { dlfree(data->ids); data->ids = NULL; } return Qnil; } else{ rb_raise(rb_eArgError, "wrong arguments"); } } t = NUM2INT(data_type); StringValue(type); Check_Type(rest, T_ARRAY); num = RARRAY(rest)->len; for (i=0; ictype = t; data->slen = num; data->ids_num = num; if (data->stype) dlfree(data->stype); data->stype = (char*)dlmalloc(sizeof(char) * num); if (data->ssize) dlfree(data->ssize); data->ssize = (int*)dlmalloc(sizeof(int) * num); if (data->ids) dlfree(data->ids); data->ids = (ID*)dlmalloc(sizeof(ID) * data->ids_num); ctype = StringValuePtr(type); for (i=0; iids[i] = rb_to_id(vid); data->stype[i] = *ctype; ctype ++; if (isdigit(*ctype)) { char *p, *d; for (p=ctype; isdigit(*p); p++) ; d = ALLOCA_N(char, p - ctype + 1); strncpy(d, ctype, p - ctype); d[p - ctype] = '\0'; data->ssize[i] = atoi(d); ctype = p; } else{ data->ssize[i] = 1; } } if (*ctype) { rb_raise(rb_eArgError, "too few/many arguments"); } if (!data->size) data->size = dlsizeof(RSTRING(type)->ptr); return Qnil; } VALUE rb_dlptr_define_struct(int argc, VALUE argv[], VALUE self) { VALUE *pass_argv; int pass_argc, i; pass_argc = argc + 1; pass_argv = ALLOCA_N(VALUE, pass_argc); pass_argv[0] = INT2FIX(DLPTR_CTYPE_STRUCT); for (i=1; istype) return rb_assoc_new(INT2FIX(data->ctype), rb_tainted_str_new(data->stype, data->slen)); else return rb_assoc_new(INT2FIX(data->ctype), Qnil); } static VALUE cary2ary(void *ptr, char t, int len) { VALUE ary; VALUE elem; int i; if (len < 1) return Qnil; if (len == 1) { switch (t) { case 'I': elem = INT2NUM(*((int*)ptr)); ptr = (char *)ptr + sizeof(int); break; case 'L': elem = DLLONG2NUM(*((long*)ptr)); ptr = (char *)ptr + sizeof(long); break; case 'P': case 'S': elem = rb_dlptr_new(*((void**)ptr),0, 0); ptr = (char *)ptr + sizeof(void*); break; case 'F': elem = rb_float_new(*((float*)ptr)); ptr = (char *)ptr + sizeof(float); break; case 'D': elem = rb_float_new(*((double*)ptr)); ptr = (char *)ptr + sizeof(double); break; case 'C': elem = INT2NUM(*((char*)ptr)); ptr = (char *)ptr + sizeof(char); break; case 'H': elem = INT2NUM(*((short*)ptr)); ptr = (char *)ptr + sizeof(short); break; default: rb_raise(rb_eDLTypeError, "unsupported type '%c'", t); } return elem; } ary = rb_ary_new(); for (i=0; i < len; i++) { switch (t) { case 'I': elem = INT2NUM(*((int*)ptr)); ptr = (char *)ptr + sizeof(int); break; case 'L': elem = DLLONG2NUM(*((long*)ptr)); ptr = (char *)ptr + sizeof(long); break; case 'P': case 'S': elem = rb_dlptr_new(*((void**)ptr), 0, 0); ptr = (char *)ptr + sizeof(void*); break; case 'F': elem = rb_float_new(*((float*)ptr)); ptr = (char *)ptr + sizeof(float); break; case 'D': elem = rb_float_new(*((float*)ptr)); ptr = (char *)ptr + sizeof(double); break; case 'C': elem = INT2NUM(*((char*)ptr)); ptr = (char *)ptr + sizeof(char); break; case 'H': elem = INT2NUM(*((short*)ptr)); ptr = (char *)ptr + sizeof(short); break; default: rb_raise(rb_eDLTypeError, "unsupported type '%c'", t); } rb_ary_push(ary, elem); } return ary; } VALUE rb_dlptr_aref(int argc, VALUE argv[], VALUE self) { VALUE key = Qnil, num = Qnil; ID id; struct ptr_data *data; int i; int offset; if (rb_scan_args(argc, argv, "11", &key, &num) == 1) { num = INT2NUM(0); } if (TYPE(key) == T_FIXNUM || TYPE(key) == T_BIGNUM) { VALUE pass[1]; pass[0] = num; return rb_dlptr_to_str(1, pass, rb_dlptr_plus(self, key)); } rb_to_id(key); if (! (TYPE(key) == T_STRING || TYPE(key) == T_SYMBOL)) { rb_raise(rb_eTypeError, "the key must be a string or symbol"); } id = rb_to_id(key); Data_Get_Struct(self, struct ptr_data, data); offset = 0; switch (data->ctype) { case DLPTR_CTYPE_STRUCT: for (i=0; i < data->ids_num; i++) { switch (data->stype[i]) { case 'I': DLALIGN(data->ptr,offset,INT_ALIGN); break; case 'L': DLALIGN(data->ptr,offset,LONG_ALIGN); break; case 'P': case 'S': DLALIGN(data->ptr,offset,VOIDP_ALIGN); break; case 'F': DLALIGN(data->ptr,offset,FLOAT_ALIGN); break; case 'D': DLALIGN(data->ptr,offset,DOUBLE_ALIGN); break; case 'C': break; case 'H': DLALIGN(data->ptr,offset,SHORT_ALIGN); break; default: rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]); } if (data->ids[i] == id) { return cary2ary((char *)data->ptr + offset, data->stype[i], data->ssize[i]); } switch (data->stype[i]) { case 'I': offset += sizeof(int) * data->ssize[i]; break; case 'L': offset += sizeof(long) * data->ssize[i]; break; case 'P': case 'S': offset += sizeof(void*) * data->ssize[i]; break; case 'F': offset += sizeof(float) * data->ssize[i]; break; case 'D': offset += sizeof(double) * data->ssize[i]; break; case 'C': offset += sizeof(char) * data->ssize[i]; break; case 'H': offset += sizeof(short) * data->ssize[i]; break; default: rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]); } } break; case DLPTR_CTYPE_UNION: for (i=0; i < data->ids_num; i++) { if (data->ids[i] == id) { return cary2ary((char *)data->ptr + offset, data->stype[i], data->ssize[i]); } } break; } /* end of switch */ rb_raise(rb_eNameError, "undefined key `%s' for %s", rb_id2name(id), rb_class2name(CLASS_OF(self))); return Qnil; } static void * ary2cary(char t, VALUE val, long *size) { void *ptr; if (TYPE(val) == T_ARRAY) { ptr = rb_ary2cary(t, val, size); } else{ ptr = rb_ary2cary(t, rb_ary_new3(1, val), size); } return ptr; } VALUE rb_dlptr_aset(int argc, VALUE argv[], VALUE self) { VALUE key = Qnil, num = Qnil, val = Qnil; ID id; struct ptr_data *data; int i; int offset; long memsize; void *memimg; rb_secure(4); switch (rb_scan_args(argc, argv, "21", &key, &num, &val)) { case 2: val = num; num = Qnil; break; } if (TYPE(key) == T_FIXNUM || TYPE(key) == T_BIGNUM) { void *dst, *src; long len; StringValue(val); Data_Get_Struct(self, struct ptr_data, data); dst = (void*)((long)(data->ptr) + DLNUM2LONG(key)); src = RSTRING(val)->ptr; len = RSTRING(val)->len; if (num == Qnil) { memcpy(dst, src, len); } else{ long n = NUM2INT(num); memcpy(dst, src, n < len ? n : len); if (n > len) MEMZERO((char*)dst + len, char, n - len); } return val; } id = rb_to_id(key); Data_Get_Struct(self, struct ptr_data, data); switch (data->ctype) { case DLPTR_CTYPE_STRUCT: offset = 0; for (i=0; i < data->ids_num; i++) { switch (data->stype[i]) { case 'I': DLALIGN(data->ptr,offset,INT_ALIGN); break; case 'L': DLALIGN(data->ptr,offset,LONG_ALIGN); break; case 'P': case 'S': DLALIGN(data->ptr,offset,VOIDP_ALIGN); break; case 'D': DLALIGN(data->ptr,offset,DOUBLE_ALIGN); break; case 'F': DLALIGN(data->ptr,offset,FLOAT_ALIGN); break; case 'C': break; case 'H': DLALIGN(data->ptr,offset,SHORT_ALIGN); break; default: rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]); } if (data->ids[i] == id) { memimg = ary2cary(data->stype[i], val, &memsize); memcpy((char *)data->ptr + offset, memimg, memsize); dlfree(memimg); return val; } switch (data->stype[i]) { case 'I': case 'i': offset += sizeof(int) * data->ssize[i]; break; case 'L': case 'l': offset += sizeof(long) * data->ssize[i]; break; case 'P': case 'p': case 'S': case 's': offset += sizeof(void*) * data->ssize[i]; break; case 'D': case 'd': offset += sizeof(double) * data->ssize[i]; break; case 'F': case 'f': offset += sizeof(float) * data->ssize[i]; break; case 'C': case 'c': offset += sizeof(char) * data->ssize[i]; break; case 'H': case 'h': offset += sizeof(short) * data->ssize[i]; break; default: rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]); } } return val; /* break; */ case DLPTR_CTYPE_UNION: for (i=0; i < data->ids_num; i++) { if (data->ids[i] == id) { switch (data->stype[i]) { case 'I': case 'i': memsize = sizeof(int) * data->ssize[i]; break; case 'L': case 'l': memsize = sizeof(long) * data->ssize[i]; break; case 'P': case 'p': case 'S': case 's': memsize = sizeof(void*) * data->ssize[i]; break; case 'F': case 'f': memsize = sizeof(float) * data->ssize[i]; break; case 'D': case 'd': memsize = sizeof(double) * data->ssize[i]; break; case 'C': case 'c': memsize = sizeof(char) * data->ssize[i]; break; case 'H': case 'h': memsize = sizeof(short) * data->ssize[i]; break; default: rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]); } memimg = ary2cary(data->stype[i], val, NULL); memcpy(data->ptr, memimg, memsize); dlfree(memimg); } } return val; /* break; */ } rb_raise(rb_eNameError, "undefined key `%s' for %s", rb_id2name(id), rb_class2name(CLASS_OF(self))); return Qnil; } VALUE rb_dlptr_size(int argc, VALUE argv[], VALUE self) { VALUE size; if (rb_scan_args(argc, argv, "01", &size) == 0){ return DLLONG2NUM(RDLPTR(self)->size); } else{ RDLPTR(self)->size = DLNUM2LONG(size); return size; } } static int dlmem_each_i(void* key, VALUE value, void* arg) { VALUE vkey = DLLONG2NUM(key); rb_yield(rb_assoc_new(vkey, value)); return Qnil; } VALUE rb_dlmem_each(VALUE self) { st_foreach(st_memory_table, dlmem_each_i, 0); return Qnil; } void Init_dlptr() { rb_cDLPtrData = rb_define_class_under(rb_mDL, "PtrData", rb_cObject); rb_define_alloc_func(rb_cDLPtrData, rb_dlptr_s_allocate); rb_define_singleton_method(rb_cDLPtrData, "malloc", rb_dlptr_s_malloc, -1); rb_define_method(rb_cDLPtrData, "initialize", rb_dlptr_initialize, -1); rb_define_method(rb_cDLPtrData, "free=", rb_dlptr_free_set, 1); rb_define_method(rb_cDLPtrData, "free", rb_dlptr_free_get, 0); rb_define_method(rb_cDLPtrData, "to_i", rb_dlptr_to_i, 0); rb_define_method(rb_cDLPtrData, "ptr", rb_dlptr_ptr, 0); rb_define_method(rb_cDLPtrData, "+@", rb_dlptr_ptr, 0); rb_define_method(rb_cDLPtrData, "ref", rb_dlptr_ref, 0); rb_define_method(rb_cDLPtrData, "-@", rb_dlptr_ref, 0); rb_define_method(rb_cDLPtrData, "null?", rb_dlptr_null_p, 0); rb_define_method(rb_cDLPtrData, "to_a", rb_dlptr_to_array, -1); rb_define_method(rb_cDLPtrData, "to_s", rb_dlptr_to_s, -1); rb_define_method(rb_cDLPtrData, "to_str", rb_dlptr_to_str, -1); rb_define_method(rb_cDLPtrData, "inspect", rb_dlptr_inspect, 0); rb_define_method(rb_cDLPtrData, "<=>", rb_dlptr_cmp, 1); rb_define_method(rb_cDLPtrData, "==", rb_dlptr_eql, 1); rb_define_method(rb_cDLPtrData, "eql?", rb_dlptr_eql, 1); rb_define_method(rb_cDLPtrData, "+", rb_dlptr_plus, 1); rb_define_method(rb_cDLPtrData, "-", rb_dlptr_minus, 1); rb_define_method(rb_cDLPtrData, "define_data_type", rb_dlptr_define_data_type, -1); rb_define_method(rb_cDLPtrData, "struct!", rb_dlptr_define_struct, -1); rb_define_method(rb_cDLPtrData, "union!", rb_dlptr_define_union, -1); rb_define_method(rb_cDLPtrData, "data_type", rb_dlptr_get_data_type, 0); rb_define_method(rb_cDLPtrData, "[]", rb_dlptr_aref, -1); rb_define_method(rb_cDLPtrData, "[]=", rb_dlptr_aset, -1); rb_define_method(rb_cDLPtrData, "size", rb_dlptr_size, -1); rb_define_method(rb_cDLPtrData, "size=", rb_dlptr_size, -1); rb_mDLMemorySpace = rb_define_module_under(rb_mDL, "MemorySpace"); st_memory_table = st_init_numtable(); rb_define_const(rb_mDLMemorySpace, "MemoryTable", Qnil); /* historical */ rb_define_module_function(rb_mDLMemorySpace, "each", rb_dlmem_each, 0); } ================================================ FILE: ext/dl/sample/c++sample.C ================================================ #include class Person { private: const char *name; int age; public: Person(const char *name, int age); const char * get_name(); int get_age(); void set_age(int i); }; Person::Person(const char *name, int age) : name(name), age(age) { /* empty */ } const char * Person::get_name() { return name; } int Person::get_age(){ return age; } void Person::set_age(int i){ age = i; } ================================================ FILE: ext/dl/sample/c++sample.rb ================================================ =begin This script shows how to deal with C++ classes using Ruby/DL. You must build a dynamic loadable library using "c++sample.C" to run this script as follows: $ g++ -o libsample.so -shared c++sample.C =end require 'dl' require 'dl/import' require 'dl/struct' # Give a name of dynamic loadable library LIBNAME = ARGV[0] || "libsample.so" class Person module Core extend DL::Importable dlload LIBNAME # mangled symbol names extern "void __6PersonPCci(void *, const char *, int)" extern "const char *get_name__6Person(void *)" extern "int get_age__6Person(void *)" extern "void set_age__6Personi(void *, int)" Data = struct [ "char *name", "int age", ] end def initialize(name, age) @ptr = Core::Data.alloc Core::__6PersonPCci(@ptr, name, age) end def get_name() str = Core::get_name__6Person(@ptr) if( str ) str.to_s else nil end end def get_age() Core::get_age__6Person(@ptr) end def set_age(age) Core::set_age__6Personi(@ptr, age) end end obj = Person.new("ttate", 1) p obj.get_name() p obj.get_age() obj.set_age(10) p obj.get_age() ================================================ FILE: ext/dl/sample/drives.rb ================================================ # -*- ruby -*- # drives.rb -- find existing drives and show the drive type. require 'dl' require 'dl/import' module Kernel32 extend DL::Importable dlload "kernel32" extern "long GetLogicalDrives()" extern "int GetDriveType(char*)" extern "long GetDiskFreeSpace(char*, long ref, long ref, long ref, long ref)" end include Kernel32 buff = Kernel32.getLogicalDrives() i = 0 ds = [] while( i < 26 ) mask = (1 << i) if( buff & mask > 0 ) ds.push((65+i).chr) end i += 1 end =begin From the cygwin's /usr/include/w32api/winbase.h: #define DRIVE_UNKNOWN 0 #define DRIVE_NO_ROOT_DIR 1 #define DRIVE_REMOVABLE 2 #define DRIVE_FIXED 3 #define DRIVE_REMOTE 4 #define DRIVE_CDROM 5 #define DRIVE_RAMDISK 6 =end types = [ "unknown", "no root dir", "Removable", "Fixed", "Remote", "CDROM", "RAM", ] print("Drive : Type (Free Space/Available Space)\n") ds.each{|d| t = Kernel32.getDriveType(d + ":\\") Kernel32.getDiskFreeSpace(d + ":\\", 0, 0, 0, 0) _,sec_per_clus,byte_per_sec,free_clus,total_clus = Kernel32._args_ fbytes = sec_per_clus * byte_per_sec * free_clus tbytes = sec_per_clus * byte_per_sec * total_clus unit = "B" if( fbytes > 1024 && tbytes > 1024 ) fbytes = fbytes / 1024 tbytes = tbytes / 1024 unit = "K" end if( fbytes > 1024 && tbytes > 1024 ) fbytes = fbytes / 1024 tbytes = tbytes / 1024 unit = "M" end print("#{d} : #{types[t]} (#{fbytes} #{unit}/#{tbytes} #{unit})\n") } ================================================ FILE: ext/dl/sample/getch.rb ================================================ require 'dl' crtdll = DL::dlopen("crtdll") getch = crtdll['_getch', 'L'] print(getch.call, "\n") ================================================ FILE: ext/dl/sample/libc.rb ================================================ require "dl/import" require "dl/struct" module LIBC extend DL::Importable begin dlload "libc.so.6" rescue dlload "libc.so.5" end extern "int atoi(char*)" extern "ibool isdigit(int)" extern "int gettimeofday(struct timeval *, struct timezone *)" extern "char* strcat(char*, char*)" extern "FILE* fopen(char*, char*)" extern "int fclose(FILE*)" extern "int fgetc(FILE*)" extern "int strlen(char*)" extern "void qsort(void*, int, int, void*)" def str_qsort(ary, comp) len = ary.length r,rs = qsort(ary, len, DL.sizeof('P'), comp) return rs[0].to_a('S', len) end Timeval = struct [ "long tv_sec", "long tv_usec", ] Timezone = struct [ "int tz_minuteswest", "int tz_dsttime", ] def my_compare(ptr1, ptr2) ptr1.ptr.to_s <=> ptr2.ptr.to_s end COMPARE = callback("int my_compare(char**, char**)") end $cb1 = DL.callback('IPP'){|ptr1, ptr2| str1 = ptr1.ptr.to_s str2 = ptr2.ptr.to_s str1 <=> str2 } p LIBC.atoi("10") p LIBC.isdigit(?1) p LIBC.isdigit(?a) p LIBC.strcat("a", "b") ary = ["a","c","b"] ptr = ary.to_ptr LIBC.qsort(ptr, ary.length, DL.sizeof('P'), LIBC::COMPARE) p ptr.to_a('S', ary.length) tv = LIBC::Timeval.malloc tz = LIBC::Timezone.malloc LIBC.gettimeofday(tv, tz) p Time.at(tv.tv_sec) ================================================ FILE: ext/dl/sample/msgbox.rb ================================================ # This script works on Windows. require 'dl' User32 = DL.dlopen("user32") Kernel32 = DL.dlopen("kernel32") MB_OK = 0 MB_OKCANCEL = 1 message_box = User32['MessageBoxA', 'ILSSI'] r,rs = message_box.call(0, 'ok?', 'error', MB_OKCANCEL) case r when 1 print("OK!\n") when 2 print("Cancel!\n") end ================================================ FILE: ext/dl/sample/msgbox2.rb ================================================ # This script works on Windows. require 'dl/win32' MB_OK = 0 MB_OKCANCEL = 1 message_box = Win32API.new("user32",'MessageBoxA', 'ISSI', 'I') r = message_box.call(0, 'ok?', 'error', MB_OKCANCEL) case r when 1 print("OK!\n") when 2 print("Cancel!\n") else p r end ================================================ FILE: ext/dl/sample/stream.rb ================================================ # -*- ruby -*- # Display a file name and stream names of a file with those size. require 'dl' require 'dl/import' module NTFS extend DL::Importable dlload "kernel32.dll" OPEN_EXISTING = 3 GENERIC_READ = 0x80000000 BACKUP_DATA = 0x00000001 BACKUP_ALTERNATE_DATA = 0x00000004 FILE_SHARE_READ = 0x00000001 FILE_FLAG_BACKUP_SEMANTICS = 0x02000000 typealias "LPSECURITY_ATTRIBUTES", "void*" extern "BOOL BackupRead(HANDLE, PBYTE, DWORD, PDWORD, BOOL, BOOL, PVOID)" extern "BOOL BackupSeek(HANDLE, DWORD, DWORD, PDWORD, PDWORD, PVOID)" extern "BOOL CloseHandle(HANDLE)" extern "HANDLE CreateFile(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE)" module_function def streams(filename) status = [] h = createFile(filename,GENERIC_READ,FILE_SHARE_READ,nil, OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,0) if( h != 0 ) begin # allocate the memory for backup data used in backupRead(). data = DL.malloc(DL.sizeof("L5")) data.struct!("LLLLL", :id, :attrs, :size_low, :size_high, :name_size) # allocate memories for references to long values used in backupRead(). context = DL.malloc(DL.sizeof("L")) lval = DL.malloc(DL.sizeof("L")) while( backupRead(h, data, data.size, lval, false, false, context) ) size = data[:size_low] + (data[:size_high] << (DL.sizeof("I") * 8)) case data[:id] when BACKUP_ALTERNATE_DATA stream_name = DL.malloc(data[:name_size]) backupRead(h, stream_name, stream_name.size, lval, false, false, context) name = stream_name[0, stream_name.size] name.tr!("\000","") if( name =~ /^:(.*?):.*$/ ) status.push([$1,size]) end when BACKUP_DATA status.push([nil,size]) else raise(RuntimeError, "unknown data type #{data[:id]}.") end l1 = DL.malloc(DL.sizeof("L")) l2 = DL.malloc(DL.sizeof("L")) if( !backupSeek(h, data[:size_low], data[:size_high], l1, l2, context) ) break end end ensure backupRead(h, nil, 0, lval, true, false, context) closeHandle(h) end return status else raise(RuntimeError, "can't open #{filename}.\n") end end end ARGV.each{|filename| if( File.exist?(filename) ) NTFS.streams(filename).each{|name,size| if( name ) print("#{filename}:#{name}\t#{size}bytes\n") else print("#{filename}\t#{size}bytes\n") end } end } ================================================ FILE: ext/dl/sym.c ================================================ /* -*- C -*- * $Id$ */ #include #include #include "dl.h" VALUE rb_cDLSymbol; static const char * char2type(int ch) { switch (ch) { case '0': return "void"; case 'P': return "void *"; case 'p': return "void *"; case 'C': return "char"; case 'c': return "char *"; case 'H': return "short"; case 'h': return "short *"; case 'I': return "int"; case 'i': return "int *"; case 'L': return "long"; case 'l': return "long *"; case 'F': return "double"; case 'f': return "double *"; case 'D': return "double"; case 'd': return "double *"; case 'S': return "const char *"; case 's': return "char *"; case 'A': return "[]"; case 'a': return "[]"; /* ?? */ } return NULL; } void dlsym_free(struct sym_data *data) { if( data->name ){ DEBUG_CODE({ printf("dlsym_free(): free(data->name:%s)\n",data->name); }); free(data->name); } if( data->type ){ DEBUG_CODE({ printf("dlsym_free(): free(data->type:%s)\n",data->type); }); free(data->type); } } VALUE rb_dlsym_new(void (*func)(), const char *name, const char *type) { VALUE val; struct sym_data *data; const char *ptype; rb_secure(4); if( !type || !type[0] ){ return rb_dlptr_new((void*)func, 0, 0); } for( ptype = type; *ptype; ptype ++ ){ if( ! char2type(*ptype) ){ rb_raise(rb_eDLTypeError, "unknown type specifier '%c'", *ptype); } } if( func ){ val = Data_Make_Struct(rb_cDLSymbol, struct sym_data, 0, dlsym_free, data); data->func = func; data->name = name ? strdup(name) : NULL; data->type = type ? strdup(type) : NULL; data->len = type ? strlen(type) : 0; #if !(defined(DLSTACK)) if( data->len - 1 > MAX_ARG ){ rb_raise(rb_eDLError, "maximum number of arguments is %d.", MAX_ARG); } #endif } else{ val = Qnil; } return val; } freefunc_t rb_dlsym2csym(VALUE val) { struct sym_data *data; freefunc_t func; if( rb_obj_is_kind_of(val, rb_cDLSymbol) ){ Data_Get_Struct(val, struct sym_data, data); func = data->func; } else if( val == Qnil ){ func = NULL; } else{ rb_raise(rb_eTypeError, "DL::Symbol was expected"); } return func; } VALUE rb_dlsym_s_allocate(VALUE klass) { VALUE obj; struct sym_data *data; obj = Data_Make_Struct(klass, struct sym_data, 0, dlsym_free, data); data->func = 0; data->name = 0; data->type = 0; data->len = 0; return obj; } VALUE rb_dlsym_initialize(int argc, VALUE argv[], VALUE self) { VALUE addr, name, type; struct sym_data *data; void *saddr; const char *sname, *stype; rb_scan_args(argc, argv, "12", &addr, &name, &type); saddr = (void*)(DLNUM2LONG(rb_Integer(addr))); if (!NIL_P(name)) StringValue(name); stype = NIL_P(type) ? NULL : StringValuePtr(type); sname = NIL_P(name) ? NULL : RSTRING(name)->ptr; if( saddr ){ Data_Get_Struct(self, struct sym_data, data); if( data->name ) free(data->name); if( data->type ) free(data->type); data->func = saddr; data->name = sname ? strdup(sname) : 0; data->type = stype ? strdup(stype) : 0; data->len = stype ? strlen(stype) : 0; } return Qnil; } VALUE rb_s_dlsym_char2type(VALUE self, VALUE ch) { const char *type; type = char2type(StringValuePtr(ch)[0]); if (type == NULL) return Qnil; else return rb_str_new2(type); } VALUE rb_dlsym_name(VALUE self) { struct sym_data *sym; Data_Get_Struct(self, struct sym_data, sym); return sym->name ? rb_tainted_str_new2(sym->name) : Qnil; } VALUE rb_dlsym_proto(VALUE self) { struct sym_data *sym; Data_Get_Struct(self, struct sym_data, sym); return sym->type ? rb_tainted_str_new2(sym->type) : Qnil; } VALUE rb_dlsym_cproto(VALUE self) { struct sym_data *sym; const char *ptype, *typestr; size_t len; VALUE val; Data_Get_Struct(self, struct sym_data, sym); ptype = sym->type; if( ptype ){ typestr = char2type(*ptype++); len = strlen(typestr); val = rb_tainted_str_new(typestr, len); if (typestr[len - 1] != '*') rb_str_cat(val, " ", 1); if( sym->name ){ rb_str_cat2(val, sym->name); } else{ rb_str_cat2(val, "(null)"); } rb_str_cat(val, "(", 1); while (*ptype) { const char *ty = char2type(*ptype++); rb_str_cat2(val, ty); if (*ptype) rb_str_cat(val, ", ", 2); } rb_str_cat(val, ");", 2); } else{ val = rb_tainted_str_new2("void ("); if( sym->name ){ rb_str_cat2(val, sym->name); } else{ rb_str_cat2(val, "(null)"); } rb_str_cat2(val, ")()"); } return val; } VALUE rb_dlsym_inspect(VALUE self) { VALUE proto; VALUE val; char *str; int str_size; struct sym_data *sym; Data_Get_Struct(self, struct sym_data, sym); proto = rb_dlsym_cproto(self); str_size = RSTRING(proto)->len + 100; str = dlmalloc(str_size); snprintf(str, str_size - 1, "#", sym, sym->func, RSTRING(proto)->ptr); val = rb_tainted_str_new2(str); dlfree(str); return val; } static int stack_size(struct sym_data *sym) { int i; int size; size = 0; for( i=1; i < sym->len; i++ ){ switch(sym->type[i]){ case 'C': case 'H': case 'I': case 'L': size += sizeof(long); break; case 'F': size += sizeof(float); break; case 'D': size += sizeof(double); break; case 'c': case 'h': case 'i': case 'l': case 'f': case 'd': case 'p': case 'P': case 's': case 'S': case 'a': case 'A': size += sizeof(void*); break; default: return -(sym->type[i]); } } return size; } static ID rb_dl_id_DLErrno; static VALUE rb_dl_get_last_error(VALUE self) { return rb_thread_local_aref(rb_thread_current(), rb_dl_id_DLErrno); } static VALUE rb_dl_set_last_error(VALUE self, VALUE val) { errno = NUM2INT(val); rb_thread_local_aset(rb_thread_current(), rb_dl_id_DLErrno, val); return Qnil; } #ifdef HAVE_WINDOWS_H #include static ID rb_dl_id_DLW32Error; static VALUE rb_dl_win32_get_last_error(VALUE self) { return rb_thread_local_aref(rb_thread_current(), rb_dl_id_DLW32Error); } static VALUE rb_dl_win32_set_last_error(VALUE self, VALUE val) { SetLastError(NUM2INT(val)); rb_thread_local_aset(rb_thread_current(), rb_dl_id_DLW32Error, val); return Qnil; } #endif #ifdef DLSTACK_GUARD # ifdef __MSVC_RUNTIME_CHECKS # pragma runtime_checks("s", off) # endif # if _MSC_VER >= 1300 __declspec(noinline) # endif static int rb_dlsym_guardcall(char type, ANY_TYPE *ret, long *stack, void *func) { char *volatile guard = ALLOCA_N(char, 1); /* guard stack pointer */ switch(type){ case '0': { void (*f)(DLSTACK_PROTO) = func; f(DLSTACK_ARGS); } break; case 'P': case 'p': { void * (*f)(DLSTACK_PROTO) = func; ret->p = f(DLSTACK_ARGS); } break; case 'C': case 'c': { char (*f)(DLSTACK_PROTO) = func; ret->c = f(DLSTACK_ARGS); } break; case 'H': case 'h': { short (*f)(DLSTACK_PROTO) = func; ret->h = f(DLSTACK_ARGS); } break; case 'I': case 'i': { int (*f)(DLSTACK_PROTO) = func; ret->i = f(DLSTACK_ARGS); } break; case 'L': case 'l': { long (*f)(DLSTACK_PROTO) = func; ret->l = f(DLSTACK_ARGS); } break; case 'F': case 'f': { float (*f)(DLSTACK_PROTO) = func; ret->f = f(DLSTACK_ARGS); } break; case 'D': case 'd': { double (*f)(DLSTACK_PROTO) = func; ret->d = f(DLSTACK_ARGS); } break; case 'S': case 's': { char * (*f)(DLSTACK_PROTO) = func; ret->s = f(DLSTACK_ARGS); } break; default: return 0; } return 1; } # ifdef __MSVC_RUNTIME_CHECKS # pragma runtime_checks("s", restore) # endif #endif /* defined(DLSTACK_GUARD) */ VALUE rb_dlsym_call(int argc, VALUE argv[], VALUE self) { struct sym_data *sym; ANY_TYPE *args; ANY_TYPE *dargs; ANY_TYPE ret; int *dtypes; VALUE val; VALUE dvals; int i; long ftype; void *func; rb_secure_update(self); Data_Get_Struct(self, struct sym_data, sym); DEBUG_CODE({ printf("rb_dlsym_call(): type = '%s', func = 0x%x\n", sym->type, sym->func); }); if( (sym->len - 1) != argc ){ rb_raise(rb_eArgError, "%d arguments are needed", sym->len - 1); } ftype = 0; dvals = Qnil; args = ALLOC_N(ANY_TYPE, sym->len - 1); dargs = ALLOC_N(ANY_TYPE, sym->len - 1); dtypes = ALLOC_N(int, sym->len - 1); #define FREE_ARGS {xfree(args); xfree(dargs); xfree(dtypes);} for( i = sym->len - 2; i >= 0; i-- ){ dtypes[i] = 0; switch( sym->type[i+1] ){ case 'p': dtypes[i] = 'p'; case 'P': { struct ptr_data *data; VALUE pval; if( argv[i] == Qnil ){ ANY2P(args[i]) = DLVOIDP(0); } else{ if( rb_obj_is_kind_of(argv[i], rb_cDLPtrData) ){ pval = argv[i]; } else{ pval = rb_funcall(argv[i], rb_intern("to_ptr"), 0); if( !rb_obj_is_kind_of(pval, rb_cDLPtrData) ){ rb_raise(rb_eDLTypeError, "unexpected type of argument #%d", i); } } rb_check_safe_obj(pval); Data_Get_Struct(pval, struct ptr_data, data); ANY2P(args[i]) = DLVOIDP(data->ptr); } } PUSH_P(ftype); break; case 'a': dtypes[i] = 'a'; case 'A': if( argv[i] == Qnil ){ ANY2P(args[i]) = DLVOIDP(0); } else{ ANY2P(args[i]) = DLVOIDP(rb_ary2cary(0, argv[i], NULL)); } PUSH_P(ftype); break; case 'C': ANY2C(args[i]) = DLCHAR(NUM2CHR(argv[i])); PUSH_C(ftype); break; case 'c': ANY2C(dargs[i]) = DLCHAR(NUM2CHR(argv[i])); ANY2P(args[i]) = DLVOIDP(&(ANY2C(dargs[i]))); dtypes[i] = 'c'; PUSH_P(ftype); break; case 'H': ANY2H(args[i]) = DLSHORT(NUM2INT(argv[i])); PUSH_C(ftype); break; case 'h': ANY2H(dargs[i]) = DLSHORT(NUM2INT(argv[i])); ANY2P(args[i]) = DLVOIDP(&(ANY2H(dargs[i]))); dtypes[i] = 'h'; PUSH_P(ftype); break; case 'I': ANY2I(args[i]) = DLINT(NUM2INT(argv[i])); PUSH_I(ftype); break; case 'i': ANY2I(dargs[i]) = DLINT(NUM2INT(argv[i])); ANY2P(args[i]) = DLVOIDP(&(ANY2I(dargs[i]))); dtypes[i] = 'i'; PUSH_P(ftype); break; case 'L': ANY2L(args[i]) = DLNUM2LONG(argv[i]); PUSH_L(ftype); break; case 'l': ANY2L(dargs[i]) = DLNUM2LONG(argv[i]); ANY2P(args[i]) = DLVOIDP(&(ANY2L(dargs[i]))); dtypes[i] = 'l'; PUSH_P(ftype); break; case 'F': Check_Type(argv[i], T_FLOAT); ANY2F(args[i]) = DLFLOAT(RFLOAT(argv[i])->value); PUSH_F(ftype); break; case 'f': Check_Type(argv[i], T_FLOAT); ANY2F(dargs[i]) = DLFLOAT(RFLOAT(argv[i])->value); ANY2P(args[i]) = DLVOIDP(&(ANY2F(dargs[i]))); dtypes[i] = 'f'; PUSH_P(ftype); break; case 'D': Check_Type(argv[i], T_FLOAT); ANY2D(args[i]) = RFLOAT(argv[i])->value; PUSH_D(ftype); break; case 'd': Check_Type(argv[i], T_FLOAT); ANY2D(dargs[i]) = RFLOAT(argv[i])->value; ANY2P(args[i]) = DLVOIDP(&(ANY2D(dargs[i]))); dtypes[i] = 'd'; PUSH_P(ftype); break; case 'S': if( argv[i] == Qnil ){ ANY2S(args[i]) = DLSTR(0); } else{ VALUE str = argv[i]; SafeStringValue(str); ANY2S(args[i]) = DLSTR(RSTRING(str)->ptr); } PUSH_P(ftype); break; case 's': { VALUE str = argv[i]; SafeStringValue(str); ANY2S(args[i]) = DLSTR(dlmalloc(RSTRING(str)->len + 1)); memcpy((char*)(ANY2S(args[i])), RSTRING(str)->ptr, RSTRING(str)->len + 1); dtypes[i] = 's'; } PUSH_P(ftype); break; default: FREE_ARGS; rb_raise(rb_eDLTypeError, "unknown type '%c' of the return value.", sym->type[i+1]); } } switch( sym->type[0] ){ case '0': PUSH_0(ftype); break; case 'P': case 'p': case 'S': case 's': case 'A': case 'a': PUSH_P(ftype); break; case 'C': case 'c': PUSH_C(ftype); break; case 'H': case 'h': PUSH_H(ftype); break; case 'I': case 'i': PUSH_I(ftype); break; case 'L': case 'l': PUSH_L(ftype); break; case 'F': case 'f': PUSH_F(ftype); break; case 'D': case 'd': PUSH_D(ftype); break; default: FREE_ARGS; rb_raise(rb_eDLTypeError, "unknown type `%c' of the return value.", sym->type[0]); } func = sym->func; #if defined(DLSTACK) { #if defined(DLSTACK_SIZE) int stk_size; long stack[DLSTACK_SIZE]; long *sp; sp = stack; stk_size = stack_size(sym); if( stk_size < 0 ){ FREE_ARGS; rb_raise(rb_eDLTypeError, "unknown type '%c'.", -stk_size); } else if( stk_size > (int)(DLSTACK_SIZE) ){ FREE_ARGS; rb_raise(rb_eArgError, "too many arguments."); } #endif DLSTACK_START(sym); #if defined(DLSTACK_REVERSE) for( i = sym->len - 2; i >= 0; i-- ) #else for( i = 0; i <= sym->len -2; i++ ) #endif { switch( sym->type[i+1] ){ case 'p': case 'P': DLSTACK_PUSH_P(ANY2P(args[i])); break; case 'a': case 'A': DLSTACK_PUSH_P(ANY2P(args[i])); break; case 'C': DLSTACK_PUSH_C(ANY2C(args[i])); break; case 'c': DLSTACK_PUSH_P(ANY2P(args[i])); break; case 'H': DLSTACK_PUSH_H(ANY2H(args[i])); break; case 'h': DLSTACK_PUSH_P(ANY2P(args[i])); break; case 'I': DLSTACK_PUSH_I(ANY2I(args[i])); break; case 'i': DLSTACK_PUSH_P(ANY2P(args[i])); break; case 'L': DLSTACK_PUSH_L(ANY2L(args[i])); break; case 'l': DLSTACK_PUSH_P(ANY2P(args[i])); break; case 'F': DLSTACK_PUSH_F(ANY2F(args[i])); break; case 'f': DLSTACK_PUSH_P(ANY2P(args[i])); break; case 'D': DLSTACK_PUSH_D(ANY2D(args[i])); break; case 'd': DLSTACK_PUSH_P(ANY2P(args[i])); break; case 'S': case 's': DLSTACK_PUSH_P(ANY2S(args[i])); break; } } DLSTACK_END(sym->type); #ifdef DLSTACK_GUARD if(!rb_dlsym_guardcall(sym->type[0], &ret, stack, func)) { FREE_ARGS; rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]); } #else /* defined(DLSTACK_GUARD) */ { switch( sym->type[0] ){ case '0': { void (*f)(DLSTACK_PROTO) = func; f(DLSTACK_ARGS); } break; case 'P': case 'p': { void * (*f)(DLSTACK_PROTO) = func; ret.p = f(DLSTACK_ARGS); } break; case 'C': case 'c': { char (*f)(DLSTACK_PROTO) = func; ret.c = f(DLSTACK_ARGS); } break; case 'H': case 'h': { short (*f)(DLSTACK_PROTO) = func; ret.h = f(DLSTACK_ARGS); } break; case 'I': case 'i': { int (*f)(DLSTACK_PROTO) = func; ret.i = f(DLSTACK_ARGS); } break; case 'L': case 'l': { long (*f)(DLSTACK_PROTO) = func; ret.l = f(DLSTACK_ARGS); } break; case 'F': case 'f': { float (*f)(DLSTACK_PROTO) = func; ret.f = f(DLSTACK_ARGS); } break; case 'D': case 'd': { double (*f)(DLSTACK_PROTO) = func; ret.d = f(DLSTACK_ARGS); } break; case 'S': case 's': { char * (*f)(DLSTACK_PROTO) = func; ret.s = f(DLSTACK_ARGS); } break; default: FREE_ARGS; rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]); } } #endif /* defubed(DLSTACK_GUARD) */ { /* * We should get the value of errno/GetLastError() before calling another functions. */ int last_errno = errno; #ifdef _WIN32 DWORD win32_last_err = GetLastError(); #endif rb_thread_local_aset(rb_thread_current(), rb_dl_id_DLErrno, INT2NUM(last_errno)); #ifdef _WIN32 rb_thread_local_aset(rb_thread_current(), rb_dl_id_DLW32Error, INT2NUM(win32_last_err)); #endif } } #else /* defined(DLSTACK) */ switch(ftype){ #include "call.func" default: FREE_ARGS; rb_raise(rb_eDLTypeError, "unsupported function type `%s'", sym->type); } #endif /* defined(DLSTACK) */ switch( sym->type[0] ){ case '0': val = Qnil; break; case 'P': val = rb_dlptr_new((void*)(ANY2P(ret)), 0, 0); break; case 'p': val = rb_dlptr_new((void*)(ANY2P(ret)), 0, dlfree); break; case 'C': case 'c': val = CHR2FIX((char)(ANY2C(ret))); break; case 'H': case 'h': val = INT2NUM((short)(ANY2H(ret))); break; case 'I': case 'i': val = INT2NUM((int)(ANY2I(ret))); break; case 'L': case 'l': val = DLLONG2NUM((long)(ANY2L(ret))); break; case 'F': case 'f': val = rb_float_new((double)(ANY2F(ret))); break; case 'D': case 'd': val = rb_float_new((double)(ANY2D(ret))); break; case 'S': if( ANY2S(ret) ){ val = rb_tainted_str_new2((char*)(ANY2S(ret))); } else{ val = Qnil; } break; case 's': if( ANY2S(ret) ){ val = rb_tainted_str_new2((char*)(ANY2S(ret))); DEBUG_CODE({ printf("dlfree(%s)\n",(char*)(ANY2S(ret))); }); dlfree((void*)(ANY2S(ret))); } else{ val = Qnil; } break; default: FREE_ARGS; rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]); } dvals = rb_ary_new(); for( i = 0; i <= sym->len - 2; i++ ){ if( dtypes[i] ){ switch( dtypes[i] ){ case 'c': rb_ary_push(dvals, CHR2FIX(*((char*)(ANY2P(args[i]))))); break; case 'h': rb_ary_push(dvals, INT2NUM(*((short*)(ANY2P(args[i]))))); break; case 'i': rb_ary_push(dvals, INT2NUM(*((int*)(ANY2P(args[i]))))); break; case 'l': rb_ary_push(dvals, DLLONG2NUM(*((long*)(ANY2P(args[i]))))); break; case 'f': rb_ary_push(dvals, rb_float_new(*((float*)(ANY2P(args[i]))))); break; case 'd': rb_ary_push(dvals, rb_float_new(*((double*)(ANY2P(args[i]))))); break; case 'p': rb_ary_push(dvals, rb_dlptr_new((void*)(ANY2P(args[i])), 0, 0)); break; case 'a': rb_ary_push(dvals, rb_dlptr_new((void*)ANY2P(args[i]), 0, 0)); break; case 's': rb_ary_push(dvals, rb_tainted_str_new2((char*)ANY2S(args[i]))); DEBUG_CODE({ printf("dlfree(%s)\n",(char*)ANY2S(args[i])); }); dlfree((void*)ANY2S(args[i])); break; default: { char c = dtypes[i]; FREE_ARGS; rb_raise(rb_eRuntimeError, "unknown argument type '%c'", i, c); } } } else{ switch( sym->type[i+1] ){ case 'A': dlfree((void*)ANY2P(args[i])); break; } rb_ary_push(dvals, argv[i]); } } FREE_ARGS; #undef FREE_ARGS return rb_assoc_new(val,dvals); } VALUE rb_dlsym_to_i(VALUE self) { struct sym_data *sym; Data_Get_Struct(self, struct sym_data, sym); return DLLONG2NUM(sym); } VALUE rb_dlsym_to_ptr(VALUE self) { struct sym_data *sym; Data_Get_Struct(self, struct sym_data, sym); return rb_dlptr_new(sym->func, sizeof(freefunc_t), 0); } void Init_dlsym() { rb_cDLSymbol = rb_define_class_under(rb_mDL, "Symbol", rb_cObject); rb_define_alloc_func(rb_cDLSymbol, rb_dlsym_s_allocate); rb_define_singleton_method(rb_cDLSymbol, "char2type", rb_s_dlsym_char2type, 1); rb_define_method(rb_cDLSymbol, "initialize", rb_dlsym_initialize, -1); rb_define_method(rb_cDLSymbol, "call", rb_dlsym_call, -1); rb_define_method(rb_cDLSymbol, "[]", rb_dlsym_call, -1); rb_define_method(rb_cDLSymbol, "name", rb_dlsym_name, 0); rb_define_method(rb_cDLSymbol, "proto", rb_dlsym_proto, 0); rb_define_method(rb_cDLSymbol, "cproto", rb_dlsym_cproto, 0); rb_define_method(rb_cDLSymbol, "inspect", rb_dlsym_inspect, 0); rb_define_method(rb_cDLSymbol, "to_s", rb_dlsym_cproto, 0); rb_define_method(rb_cDLSymbol, "to_ptr", rb_dlsym_to_ptr, 0); rb_define_method(rb_cDLSymbol, "to_i", rb_dlsym_to_i, 0); rb_dl_id_DLErrno = rb_intern("DLErrno"); rb_define_singleton_method(rb_mDL, "last_error", rb_dl_get_last_error, 0); rb_define_singleton_method(rb_mDL, "last_error=", rb_dl_set_last_error, 1); #ifdef _WIN32 rb_dl_id_DLW32Error = rb_intern("DLW32Error"); rb_define_singleton_method(rb_mDL, "win32_last_error", rb_dl_win32_get_last_error, 0); rb_define_singleton_method(rb_mDL, "win32_last_error=", rb_dl_win32_set_last_error, 1); #endif } ================================================ FILE: ext/dl/test/libtest.def ================================================ EXPORTS test_alloc_test_struct test_append test_arylen test_c2i test_call_func1 test_callback1 test_close test_d2f test_f2d test_fill_test_struct test_fill_test_union test_gets test_i2c test_init test_isucc test_lcc test_lsucc test_open test_strcat test_strlen test_succ test_data_init test_data_add test_data_aref test_set_long_value test_get_long_value internal_long_value ================================================ FILE: ext/dl/test/test.c ================================================ #include #include static char internal_string[] = "internal_string"; long internal_long_value = 100; struct test_struct { char c; long l; }; union test_union { char c; int i; long l; void *p; }; struct test_data { char name[1024]; struct test_data *next; }; long test_get_long_value() { return internal_long_value; }; void test_set_long_value(long l) { internal_long_value = l; }; void test_fill_test_struct(struct test_struct *ptr, char c, long l) { ptr->c = c; ptr->l = l; }; void test_fill_test_union(union test_union *ptr, long l) { ptr->l = l; }; struct test_struct * test_alloc_test_struct(char c, long l) { struct test_struct *data; data = (struct test_struct *)malloc(sizeof(struct test_struct)); data->c = c; data->l = l; return data; }; int test_c2i(char c) { return (int)c; }; char test_i2c(int i) { return (char)i; }; long test_lcc(char c1, char c2) { return (long)(c1 + c2); }; double test_f2d(float f) { double d; d = f; return d; }; float test_d2f(double d) { float f; f = d; return f; }; int test_strlen(const char *str) { return strlen(str); }; int test_isucc(int i) { return (i+1); }; long test_lsucc(long l) { return (l+1); }; void test_succ(long *l) { (*l)++; }; char * test_strcat(char *str1, const char *str2) { return strcat(str1, str2); }; int test_arylen(char *ary[]) { int i; for( i=0; ary[i]; i++ ){}; return i; }; void test_append(char *ary[], int len, char *astr) { int i; int size1,size2; char *str; size2 = strlen(astr); for( i=0; i <= len - 1; i++ ){ size1 = strlen(ary[i]); str = (char*)malloc(size1 + size2 + 1); strcpy(str, ary[i]); strcat(str, astr); ary[i] = str; }; }; int test_init(int *argc, char **argv[]) { int i; char s[256]; for( i=0; i < (*argc); i++ ){ sprintf(s, "arg%d", i); if( strcmp((*argv)[i], s) != 0 ){ return 1; } } return 0; } FILE * test_open(const char *filename, const char *mode) { FILE *file; file = fopen(filename,mode); return file; }; void test_close(FILE *file) { fclose(file); }; char * test_gets(char *s, int size, FILE *f) { return fgets(s,size,f); }; typedef int callback1_t(int, char *); #define CALLBACK_MSG "callback message" int test_callback1(int err, const char *msg) { if( strcmp(msg, CALLBACK_MSG) == 0 ){ return 1; } else{ return 0; } } int test_call_func1(callback1_t *func) { if( func ){ return (*func)(0, CALLBACK_MSG); } else{ return 0; } } struct test_data * test_data_init() { struct test_data *data; data = (struct test_data *)malloc(sizeof(struct test_data)); data->next = NULL; memset(data->name, 0, 1024); return data; }; void test_data_add(struct test_data *list, const char *name) { struct test_data *data; data = (struct test_data *)malloc(sizeof(struct test_data)); memset(data->name, 0, 1024); strncpy(data->name, name, 1024); data->next = list->next; list->next = data; }; struct test_data * test_data_aref(struct test_data *list, int i) { struct test_data *data; int j; for( data = list->next, j=0; data; data = data->next, j++ ){ if( i == j ){ return data; }; }; return NULL; }; ================================================ FILE: ext/dl/test/test.rb ================================================ # -*- ruby -*- require 'dl' require 'dl/import' $FAIL = 0 $TOTAL = 0 def assert(label, ty, *conds) $TOTAL += 1 cond = !conds.include?(false) if( cond ) printf("succeed in `#{label}'\n") else $FAIL += 1 case ty when :may printf("fail in `#{label}' ... expected\n") when :must printf("fail in `#{label}' ... unexpected\n") when :raise raise(RuntimeError, "fail in `#{label}'") end end end def debug(*xs) if( $DEBUG ) xs.each{|x| p x } end end print("DLSTACK = #{DL::DLSTACK}\n") print("MAX_ARG = #{DL::MAX_ARG}\n") print("\n") print("DL::FREE = #{DL::FREE.inspect}\n") print("\n") $LIB = nil if( !$LIB && File.exist?("libtest.so") ) $LIB = "./libtest.so" end if( !$LIB && File.exist?("test/libtest.so") ) $LIB = "./test/libtest.so" end module LIBTest extend DL::Importable dlload($LIB) extern "int test_c2i(char)" extern "char test_i2c(int)" extern "long test_lcc(char, char)" extern "double test_f2d(float)" extern "float test_d2f(double)" extern "int test_strlen(char*)" extern "int test_isucc(int)" extern "long test_lsucc(long)" extern "void test_succ(long *)" extern "int test_arylen(int [])" extern "void test_append(char*[], int, char *)" end DL.dlopen($LIB){|h| c2i = h["test_c2i","IC"] debug c2i r,rs = c2i[?a] debug r,rs assert("c2i", :may, r == ?a) assert("extern c2i", :must, r == LIBTest.test_c2i(?a)) i2c = h["test_i2c","CI"] debug i2c r,rs = i2c[?a] debug r,rs assert("i2c", :may, r == ?a) assert("exern i2c", :must, r == LIBTest.test_i2c(?a)) lcc = h["test_lcc","LCC"] debug lcc r,rs = lcc[1,2] assert("lcc", :may, r == 3) assert("extern lcc", :must, r == LIBTest.test_lcc(1,2)) f2d = h["test_f2d","DF"] debug f2d r,rs = f2d[20.001] debug r,rs assert("f2d", :may, r.to_i == 20) assert("extern f2d", :must, r = LIBTest.test_f2d(20.001)) d2f = h["test_d2f","FD"] debug d2f r,rs = d2f[20.001] debug r,rs assert("d2f", :may, r.to_i == 20) assert("extern d2f", :must, r == LIBTest.test_d2f(20.001)) strlen = h["test_strlen","IS"] debug strlen r,rs = strlen["0123456789"] debug r,rs assert("strlen", :must, r == 10) assert("extern strlen", :must, r == LIBTest.test_strlen("0123456789")) isucc = h["test_isucc","II"] debug isucc r,rs = isucc[2] debug r,rs assert("isucc", :must, r == 3) assert("extern isucc", :must, r == LIBTest.test_isucc(2)) lsucc = h["test_lsucc","LL"] debug lsucc r,rs = lsucc[10000000] debug r,rs assert("lsucc", :must, r == 10000001) assert("extern lsucc", :must, r == LIBTest.test_lsucc(10000000)) succ = h["test_succ","0l"] debug succ r,rs = succ[0] debug r,rs assert("succ", :must, rs[0] == 1) l = DL.malloc(DL.sizeof("L")) l.struct!("L",:lval) LIBTest.test_succ(l) assert("extern succ", :must, rs[0] == l[:lval]) arylen = h["test_arylen","IA"] debug arylen r,rs = arylen[["a","b","c","d",nil]] debug r,rs assert("arylen", :must, r == 4) arylen = h["test_arylen","IP"] debug arylen r,rs = arylen[["a","b","c","d",nil]] debug r,rs assert("arylen", :must, r == 4) assert("extern arylen", :must, r == LIBTest.test_arylen(["a","b","c","d",nil])) append = h["test_append","0aIS"] debug append r,rs = append[["a","b","c"],3,"x"] debug r,rs assert("append", :must, rs[0].to_a('S',3) == ["ax","bx","cx"]) LIBTest.test_append(["a","b","c"],3,"x") assert("extern append", :must, rs[0].to_a('S',3) == LIBTest._args_[0].to_a('S',3)) strcat = h["test_strcat","SsS"] debug strcat r,rs = strcat["abc\0","x"] debug r,rs assert("strcat", :must, rs[0].to_s == "abcx") init = h["test_init","IiP"] debug init argc = 3 argv = ["arg0","arg1","arg2"].to_ptr r,rs = init[argc, argv.ref] assert("init", :must, r == 0) } h = DL.dlopen($LIB) sym_open = h["test_open", "PSS"] sym_gets = h["test_gets", "SsIP"] sym_close = h["test_close", "0P"] debug sym_open,sym_gets,sym_close line = "Hello world!\n" File.open("tmp.txt", "w"){|f| f.print(line) } fp,rs = sym_open["tmp.txt", "r"] if( fp ) fp.free = sym_close r,rs = sym_gets[" " * 256, 256, fp] debug r,rs assert("open,gets", :must, rs[0] == line) ObjectSpace.define_finalizer(fp) {File.unlink("tmp.txt")} fp = nil else assert("open,gets", :must, line == nil) File.unlink("tmp.txt") end callback1 = h["test_callback1"] debug callback1 r,rs = h["test_call_func1", "IP"][callback1] debug r,rs assert("callback1", :must, r == 1) callback2 = DL.callback("LLP"){|num,ptr| msg = ptr.to_s if( msg == "callback message" ) 2 else 0 end } debug callback2 r,rs = h["test_call_func1", "IP"][callback2] debug r,rs assert("callback2", :must, r == 2) DL.remove_callback(callback2) ptr = DL.malloc(DL.sizeof('CL')) ptr.struct!("CL", :c, :l) ptr["c"] = 0 ptr["l"] = 0 r,rs = h["test_fill_test_struct","0PIL"][ptr,100,1000] debug r,rs assert("fill_test_struct", :must, ptr["c"] == 100, ptr["l"] == 1000) assert("fill_test_struct", :must, ptr[:c] == 100, ptr[:l] == 1000) unless (Fixnum === :-) r,rs = h["test_alloc_test_struct", "PIL"][100,200] r.free = DL::FREE r.struct!("CL", :c, :l) assert("alloc_test_struct", :must, r["c"] == 100, r["l"] == 200) assert("alloc_test_struct", :must, r[:c] == 100, r[:l] == 200) unless (Fixnum === :-) ptr = h["test_strlen"] sym1 = DL::Symbol.new(ptr,"foo","0") sym2 = h["test_strlen","LS"] assert("Symbol.new", :must, ptr == sym1.to_ptr, sym1.to_ptr == sym2.to_ptr) set_val = h["test_set_long_value","0"] get_val = h["test_get_long_value","L"] lval = get_val[][0] ptr = h["internal_long_value"] ptr.struct!("L", :l) assert("get value", :must, ptr["l"] == lval) assert("get value", :must, ptr[:l] == lval) unless (Fixnum === :-) ptr["l"] = 200 lval = get_val[][0] assert("set value", :must, ptr["l"] == lval) assert("set value", :must, ptr[:l] == lval) unless (Fixnum === :-) data_init = h["test_data_init", "P"] data_add = h["test_data_add", "0PS"] data_aref = h["test_data_aref", "PPI"] r,rs = data_init[] ptr = r data_add[ptr, "name1"] data_add[ptr, "name2"] data_add[ptr, "name3"] r,rs = data_aref[ptr, 1] ptr = r ptr.struct!("C1024P", :name, :next) assert("data_aref", :must, ptr["name"].collect{|c| c.chr}.join.split("\0")[0] == "name2") assert("data_aref", :must, ptr["name"].collect{|c| c.chr}.join.split("\0")[0] == "name2") unless (Fixnum === :-) ptr = ptr["next"] ptr.struct!("C1024P", :name, :next) assert("data_aref", :must, ptr["name"].collect{|c| c.chr}.join.split("\0")[0] == "name1") assert("data_aref", :must, ptr["name"].collect{|c| c.chr}.join.split("\0")[0] == "name1") unless (Fixnum === :-) GC.start ptr = DL::malloc(32) ptr.struct!("CHIL", "c", "h", "i", "l") ptr["c"] = 1 ptr["h"] = 2 ptr["i"] = 3 ptr["l"] = 4 assert("struct!", :must, ptr["c"] == 1 && ptr["h"] == 2 && ptr["i"] == 3 && ptr["l"] == 4) ptr = DL::malloc(DL::sizeof("IP")) ptr.struct!("IP", "n", "ptr") ptr["n"] = 10 ptr["ptr"] = nil assert("struct!", :must, ptr["n"] == 10 && ptr["ptr"] == nil) ptr = DL::malloc(16) ptr.struct!("CICI", "c1", "i1", "c2", "i2") ptr["c1"] = 0xf1 ptr["c2"] = 0xf2 c1 = [ptr["c1"]].pack("c").unpack("C")[0] c2 = [ptr["c2"]].pack("c").unpack("C")[0] assert("struct!", :must, c1 == 0xf1 && c2 == 0xf2) GC.start printf("fail/total = #{$FAIL}/#{$TOTAL}\n") ================================================ FILE: ext/dl/type.rb ================================================ # example: # DLTYPE[INT][:rb2c]["arg0"] => "NUM2INT(arg0)" # DLTYPE[DOUBLE][:c2rb]["r"] => "rb_float_new(r)" DLTYPE = { VOID = 0x00 => { :name => 'VOID', :rb2c => nil, :c2rb => nil, :ctype => "void", :stmem => "v", :sym => true, :cb => true, }, CHAR = 0x01 => { :name => 'CHAR', :rb2c => proc{|x| "NUM2CHR(#{x})"}, :c2rb => proc{|x| "CHR2FIX(#{x})"}, :ctype => "char", :stmem => "c", :sym => false, :cb => false, }, SHORT = 0x02 => { :name => 'SHORT', :rb2c => proc{|x| "FIX2INT(#{x})"}, :c2rb => proc{|x| "INT2FIX(#{x})"}, :ctype => "short", :stmem => "h", :sym => false, :cb => false, }, INT = 0x03 => { :name => 'INT', :rb2c => proc{|x| "NUM2INT(#{x})"}, :c2rb => proc{|x| "INT2NUM(#{x})"}, :ctype => "int", :stmem => "i", :sym => true, :cb => false, }, LONG = 0x04 => { :name => 'LONG', :rb2c => proc{|x| "NUM2INT(#{x})"}, :c2rb => proc{|x| "INT2NUM(#{x})"}, :ctype => "long", :stmem => "l", :sym => true, :cb => true, }, FLOAT = 0x05 => { :name => 'FLOAT', :rb2c => proc{|x| "(float)(RFLOAT(#{x})->value)"}, :c2rb => proc{|x| "rb_float_new((double)#{x})"}, :ctype => "float", :stmem => "f", :sym => false, :cb => false, }, DOUBLE = 0x06 => { :name => 'DOUBLE', :rb2c => proc{|x| "RFLOAT(#{x})->value"}, :c2rb => proc{|x| "rb_float_new(#{x})"}, :ctype => "double", :stmem => "d", :sym => true, :cb => true, }, VOIDP = 0x07 => { :name => 'VOIDP', :rb2c => proc{|x| "rb_dlptr2cptr(#{x})"}, :c2rb => proc{|x| "rb_dlptr_new(#{x},sizeof(void*),0)"}, :ctype => "void *", :stmem => "p", :sym => true, :cb => true, }, } def tpush(t, x) (t << 3)|x end def tget(t, i) (t & (0x07 << (i * 3))) >> (i * 3) end def types2num(types) res = 0x00 r = types.reverse r.each{|t| res = tpush(res,t) } res end def num2types(num) ts = [] i = 0 t = tget(num,i) while( (t != VOID && i > 0) || (i == 0) ) ts.push(DLTYPE[t][:ctype]) i += 1 t = tget(num,i) end ts end def types2ctypes(types) res = [] types.each{|t| res.push(DLTYPE[t][:ctype]) } res end ================================================ FILE: ext/etc/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/etc/depend ================================================ etc.o : etc.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h ================================================ FILE: ext/etc/etc.c ================================================ /************************************************ etc.c - $Author$ $Date$ created at: Tue Mar 22 18:39:19 JST 1994 ************************************************/ #include "ruby.h" #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_GETPWENT #include #endif #ifdef HAVE_GETGRENT #include #endif #ifndef HAVE_TYPE_UID_T #define uid_t int #endif static VALUE sPasswd, sGroup; #ifndef _WIN32 char *getenv(); #endif char *getlogin(); /* Returns the short user name of the currently logged in user. * Unfortunately, it is often rather easy to fool getlogin(). * Avoid getlogin() for security-related purposes. * * e.g. * Etc.getlogin -> 'guest' */ static VALUE etc_getlogin(obj) VALUE obj; { char *login; rb_secure(4); #ifdef HAVE_GETLOGIN login = getlogin(); if (!login) login = getenv("USER"); #else login = getenv("USER"); #endif if (login) return rb_tainted_str_new2(login); return Qnil; } #if defined(HAVE_GETPWENT) || defined(HAVE_GETGRENT) static VALUE safe_setup_str(str) const char *str; { if (str == 0) str = ""; return rb_tainted_str_new2(str); } #endif #ifdef HAVE_GETPWENT static VALUE setup_passwd(pwd) struct passwd *pwd; { if (pwd == 0) rb_sys_fail("/etc/passwd"); return rb_struct_new(sPasswd, safe_setup_str(pwd->pw_name), #ifdef HAVE_ST_PW_PASSWD safe_setup_str(pwd->pw_passwd), #endif PW_UID2VAL(pwd->pw_uid), PW_GID2VAL(pwd->pw_gid), #ifdef HAVE_ST_PW_GECOS safe_setup_str(pwd->pw_gecos), #endif safe_setup_str(pwd->pw_dir), safe_setup_str(pwd->pw_shell), #ifdef HAVE_ST_PW_CHANGE INT2NUM(pwd->pw_change), #endif #ifdef HAVE_ST_PW_QUOTA INT2NUM(pwd->pw_quota), #endif #ifdef HAVE_ST_PW_AGE PW_AGE2VAL(pwd->pw_age), #endif #ifdef HAVE_ST_PW_CLASS safe_setup_str(pwd->pw_class), #endif #ifdef HAVE_ST_PW_COMMENT safe_setup_str(pwd->pw_comment), #endif #ifdef HAVE_ST_PW_EXPIRE INT2NUM(pwd->pw_expire), #endif 0 /*dummy*/ ); } #endif /* Returns the /etc/passwd information for the user with specified integer * user id (uid). * * The information is returned as a Struct::Passwd; see getpwent above for * details. * * e.g. * Etc.getpwuid(0) -> # */ static VALUE etc_getpwuid(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { #if defined(HAVE_GETPWENT) VALUE id; uid_t uid; struct passwd *pwd; rb_secure(4); if (rb_scan_args(argc, argv, "01", &id) == 1) { uid = PW_VAL2UID(id); } else { uid = getuid(); } pwd = getpwuid(uid); if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %d", uid); return setup_passwd(pwd); #else return Qnil; #endif } /* Returns the /etc/passwd information for the user with specified login name. * * The information is returned as a Struct::Passwd; see getpwent above for * details. * * e.g. * Etc.getpwnam('root') -> # */ static VALUE etc_getpwnam(obj, nam) VALUE obj, nam; { #ifdef HAVE_GETPWENT struct passwd *pwd; SafeStringValue(nam); pwd = getpwnam(RSTRING(nam)->ptr); if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %s", RSTRING(nam)->ptr); return setup_passwd(pwd); #else return Qnil; #endif } #ifdef HAVE_GETPWENT static int passwd_blocking = 0; static VALUE passwd_ensure() { passwd_blocking = Qfalse; return Qnil; } static VALUE passwd_iterate() { struct passwd *pw; setpwent(); while (pw = getpwent()) { rb_yield(setup_passwd(pw)); } endpwent(); return Qnil; } #endif /* Provides a convenient Ruby iterator which executes a block for each entry * in the /etc/passwd file. * * The code block is passed an Etc::Passwd struct; see getpwent above for * details. * * Example: * * require 'etc' * * Etc.passwd {|u| * puts u.name + " = " + u.gecos * } * */ static VALUE etc_passwd(obj) VALUE obj; { #ifdef HAVE_GETPWENT struct passwd *pw; rb_secure(4); if (rb_block_given_p()) { if (passwd_blocking) { rb_raise(rb_eRuntimeError, "parallel passwd iteration"); } passwd_blocking = Qtrue; rb_ensure(passwd_iterate, 0, passwd_ensure, 0); } if (pw = getpwent()) { return setup_passwd(pw); } #endif return Qnil; } /* Resets the process of reading the /etc/passwd file, so that the next call * to getpwent will return the first entry again. */ static VALUE etc_setpwent(obj) VALUE obj; { #ifdef HAVE_GETPWENT setpwent(); #endif return Qnil; } /* Ends the process of scanning through the /etc/passwd file begun with * getpwent, and closes the file. */ static VALUE etc_endpwent(obj) VALUE obj; { #ifdef HAVE_GETPWENT endpwent(); #endif return Qnil; } /* Returns an entry from the /etc/passwd file. The first time it is called it * opens the file and returns the first entry; each successive call returns * the next entry, or nil if the end of the file has been reached. * * To close the file when processing is complete, call endpwent. * * Each entry is returned as a Struct::Passwd: * * - Passwd#name contains the short login name of the user as a String. * * - Passwd#passwd contains the encrypted password of the user as a String. * an 'x' is returned if shadow passwords are in use. An '*' is returned * if the user cannot log in using a password. * * - Passwd#uid contains the integer user ID (uid) of the user. * * - Passwd#gid contains the integer group ID (gid) of the user's primary group. * * - Passwd#gecos contains a longer String description of the user, such as * a full name. Some Unix systems provide structured information in the * gecos field, but this is system-dependent. * * - Passwd#dir contains the path to the home directory of the user as a String. * * - Passwd#shell contains the path to the login shell of the user as a String. */ static VALUE etc_getpwent(obj) VALUE obj; { #ifdef HAVE_GETPWENT struct passwd *pw; if (pw = getpwent()) { return setup_passwd(pw); } #endif return Qnil; } #ifdef HAVE_GETGRENT static VALUE setup_group(grp) struct group *grp; { VALUE mem; char **tbl; mem = rb_ary_new(); tbl = grp->gr_mem; while (*tbl) { rb_ary_push(mem, safe_setup_str(*tbl)); tbl++; } return rb_struct_new(sGroup, safe_setup_str(grp->gr_name), #ifdef HAVE_ST_GR_PASSWD safe_setup_str(grp->gr_passwd), #endif PW_GID2VAL(grp->gr_gid), mem); } #endif /* Returns information about the group with specified integer group id (gid), * as found in /etc/group. * * The information is returned as a Struct::Group; see getgrent above for * details. * * e.g. Etc.getgrgid(100) -> # * */ static VALUE etc_getgrgid(obj, id) VALUE obj, id; { #ifdef HAVE_GETGRENT gid_t gid; struct group *grp; rb_secure(4); gid = PW_VAL2GID(id); grp = getgrgid(gid); if (grp == 0) rb_raise(rb_eArgError, "can't find group for %d", gid); return setup_group(grp); #else return Qnil; #endif } /* Returns information about the group with specified String name, as found * in /etc/group. * * The information is returned as a Struct::Group; see getgrent above for * details. * * e.g. Etc.getgrnam('users') -> # * */ static VALUE etc_getgrnam(obj, nam) VALUE obj, nam; { #ifdef HAVE_GETGRENT struct group *grp; rb_secure(4); SafeStringValue(nam); grp = getgrnam(RSTRING(nam)->ptr); if (grp == 0) rb_raise(rb_eArgError, "can't find group for %s", RSTRING(nam)->ptr); return setup_group(grp); #else return Qnil; #endif } #ifdef HAVE_GETGRENT static int group_blocking = 0; static VALUE group_ensure() { group_blocking = Qfalse; return Qnil; } static VALUE group_iterate() { struct group *pw; setgrent(); while (pw = getgrent()) { rb_yield(setup_group(pw)); } endgrent(); return Qnil; } #endif /* Provides a convenient Ruby iterator which executes a block for each entry * in the /etc/group file. * * The code block is passed an Etc::Group struct; see getgrent above for * details. * * Example: * * require 'etc' * * Etc.group {|g| * puts g.name + ": " + g.mem.join(', ') * } * */ static VALUE etc_group(obj) VALUE obj; { #ifdef HAVE_GETGRENT struct group *grp; rb_secure(4); if (rb_block_given_p()) { if (group_blocking) { rb_raise(rb_eRuntimeError, "parallel group iteration"); } group_blocking = Qtrue; rb_ensure(group_iterate, 0, group_ensure, 0); } if (grp = getgrent()) { return setup_group(grp); } #endif return Qnil; } /* Resets the process of reading the /etc/group file, so that the next call * to getgrent will return the first entry again. */ static VALUE etc_setgrent(obj) VALUE obj; { #ifdef HAVE_GETGRENT setgrent(); #endif return Qnil; } /* Ends the process of scanning through the /etc/group file begun by * getgrent, and closes the file. */ static VALUE etc_endgrent(obj) VALUE obj; { #ifdef HAVE_GETGRENT endgrent(); #endif return Qnil; } /* Returns an entry from the /etc/group file. The first time it is called it * opens the file and returns the first entry; each successive call returns * the next entry, or nil if the end of the file has been reached. * * To close the file when processing is complete, call endgrent. * * Each entry is returned as a Struct::Group: * * - Group#name contains the name of the group as a String. * * - Group#passwd contains the encrypted password as a String. An 'x' is * returned if password access to the group is not available; an empty * string is returned if no password is needed to obtain membership of * the group. * * - Group#gid contains the group's numeric ID as an integer. * * - Group#mem is an Array of Strings containing the short login names of the * members of the group. */ static VALUE etc_getgrent(obj) VALUE obj; { #ifdef HAVE_GETGRENT struct group *gr; if (gr = getgrent()) { return setup_group(gr); } #endif return Qnil; } static VALUE mEtc; /* The etc module provides access to information from the /etc/passwd and * /etc/group files on Linux and Unix systems. * * Documented by mathew . */ void Init_etc() { mEtc = rb_define_module("Etc"); rb_define_module_function(mEtc, "getlogin", etc_getlogin, 0); rb_define_module_function(mEtc, "getpwuid", etc_getpwuid, -1); rb_define_module_function(mEtc, "getpwnam", etc_getpwnam, 1); rb_define_module_function(mEtc, "setpwent", etc_setpwent, 0); rb_define_module_function(mEtc, "endpwent", etc_endpwent, 0); rb_define_module_function(mEtc, "getpwent", etc_getpwent, 0); rb_define_module_function(mEtc, "passwd", etc_passwd, 0); rb_define_module_function(mEtc, "getgrgid", etc_getgrgid, 1); rb_define_module_function(mEtc, "getgrnam", etc_getgrnam, 1); rb_define_module_function(mEtc, "group", etc_group, 0); rb_define_module_function(mEtc, "setgrent", etc_setgrent, 0); rb_define_module_function(mEtc, "endgrent", etc_endgrent, 0); rb_define_module_function(mEtc, "getgrent", etc_getgrent, 0); rb_global_variable(&sPasswd); sPasswd = rb_struct_define("Passwd", "name", "passwd", "uid", "gid", #ifdef HAVE_ST_PW_GECOS "gecos", #endif "dir", "shell", #ifdef HAVE_ST_PW_CHANGE "change", #endif #ifdef HAVE_ST_PW_QUOTA "quota", #endif #ifdef HAVE_ST_PW_AGE "age", #endif #ifdef HAVE_ST_PW_CLASS "uclass", #endif #ifdef HAVE_ST_PW_COMMENT "comment", #endif #ifdef HAVE_ST_PW_EXPIRE "expire", #endif NULL); #ifdef HAVE_GETGRENT rb_global_variable(&sGroup); sGroup = rb_struct_define("Group", "name", #ifdef HAVE_ST_GR_PASSWD "passwd", #endif "gid", "mem", NULL); #endif } ================================================ FILE: ext/etc/etc.txt ================================================ .\" etc.txt - -*- Indented-Text -*- created at: Fri Jul 14 00:47:15 JST 1995 ** Etc(Module) The module to retrieve information under /etc directory. Available only on UNIX platforms. All operations defined in this module are module functions, so that you can include Etc module into your class. Module Function: getlogin returns login name of the user. It this fails, try getpwuid(). getpwnam(name) searches in /etc/passwd file (or equivalent database), and returns password entry for the user. The return value is an passwd structure, which has members described below. struct passwd name # user name(string) passwd # encrypted password(string) uid # user ID(integer) gid # group ID(integer) gecos # gecos field(string) dir # home directory(string) shell # login shell(string) # members below are optional change # password change time(integer) quota # quota value(integer) age # password age(integer) class # user access class(string) comment # comment(string) expire # account expiration time(integer) end See getpwnam(3) for detail. getpwuid([uid]) returns passwd entry for the specified user id. If uid is ommitted, use the value from getuid(). See getpwuid(3) for detail. getgrgid(gid) searches in /etc/group file (or equivalent database), and returns group entry for the group id. The return value is an group structure, which has members described below. struct group name # group name(string) passwd # group password(string) gid # group ID(integer) mem # array of the group member names end See getgrgid(3) for detail. getgrnam(name) returns the group entry for the specified name. The return value is the group structure. See getgrnam(3) for detail. group iterates over all group entries. passwd iterates over all passwd entries. ================================================ FILE: ext/etc/etc.txt.ja ================================================ .\" etc.txt.ja - -*- Indented-Text -*- created at: Fri Jul 14 00:47:15 JST 1995 ** Etc(⥸塼) /etcǥ쥯ȥʲξ뤿Υ⥸塼롥饹˥󥯥롼 ƻȤȤǤ롥 Module Function: getlogin ʬlogin֤̾줬Ԥgetpwuid()Ѥ ɤ getpwnam(name) /etc/passwdե(뤤DBMեNISǡ١) name̾passwdȥ֤ͤpasswd¤ ΤǰʲΥФġ struct passwd name # 桼̾(ʸ) passwd # ѥ(ʸ) uid # 桼ID() gid # 롼ID() gecos # gecosե(ʸ) dir # ۡǥ쥯ȥ(ʸ) shell # 󥷥(ʸ) # ʹߤΥФϥƥˤäƤ󶡤ʤ change # ѥѹ() quota # () age # () class # 桼饹(ʸ) comment # (ʸ) expire # ͭ() end ܺ٤getpwnam(3)򻲾ȤΤȡ getpwuid([uid]) uid桼IDȤpasswdȥ֤ͤgetpwnam() ƱͤǤ롥άˤgetuid()ͤѤ롥ܺ٤ getpwuid(3)򻲾ȤΤȡ getgrgid(gid) /etc/groupե(뤤ϡgetpwnam)򸡺gid򥰥롼 IDȤ륰롼ץȥ֤ͤgroup¤Τǰʲ Фġ struct group name # 롼̾(ʸ) passwd # 롼פΥѥ(ʸ) gid # 롼ID() mem # 롼ץ̾ end ܺ٤getgrgid(3)򻲾ȤΤȡ getgrnam(name) nameȤ̾Υ롼ץȥ֤ͤgetgrgid()Ʊ ͤǤ롥ܺ٤getgrnam(3)򻲾ȡ group ƤΥ롼ץȥ˥뤿Υƥ졼 passwd Ƥpasswdȥ˥뤿Υƥ졼 ================================================ FILE: ext/etc/extconf.rb ================================================ require 'mkmf' have_library("sun", "getpwnam") # NIS (== YP) interface for IRIX 4 a = have_func("getlogin") b = have_func("getpwent") c = have_func("getgrent") if a or b or c 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') if have_struct_member('struct passwd', 'pw_age', 'pwd.h') case what_type?('struct passwd', 'pw_age', 'pwd.h') when "string" f = "safe_setup_str" when "long long" f = "LL2NUM" else f = "INT2NUM" end $defs.push("-DPW_AGE2VAL="+f) end have_struct_member('struct passwd', 'pw_class', 'pwd.h') have_struct_member('struct passwd', 'pw_comment', 'pwd.h') unless /cygwin/ === RUBY_PLATFORM have_struct_member('struct passwd', 'pw_expire', 'pwd.h') have_struct_member('struct passwd', 'pw_passwd', 'pwd.h') have_struct_member('struct group', 'gr_passwd', 'grp.h') [%w"uid_t pwd.h", %w"gid_t grp.h"].each do |t, *h| h.unshift("sys/types.h") f = "INT2NUM" if have_type(t, h) if try_static_assert("sizeof(#{t}) > sizeof(long)", h) f = "LL2NUM" end if try_static_assert("(#{t})-1 > 0", h) f = "U#{f}" end end t = t.chomp('_t').upcase $defs.push("-DPW_#{t}2VAL=#{f}") $defs.push("-DPW_VAL2#{t}=#{f.sub(/([A-Z]+)2(NUM)/, '\22\1')}") end create_makefile("etc") end ================================================ FILE: ext/extmk.rb ================================================ #! /usr/local/bin/ruby # -*- ruby -*- $extension = nil $extstatic = nil $force_static = nil $install = nil $destdir = nil $dryrun = false $clean = nil $nodynamic = nil $extinit = nil $extobjs = nil $extflags = "" $extlibs = nil $extpath = nil $ignore = nil $message = nil $progname = $0 alias $PROGRAM_NAME $0 alias $0 $progname $extlist = [] $compiled = {} $:.replace([Dir.pwd]) require 'rbconfig' srcdir = File.dirname(File.dirname(__FILE__)) $:.unshift(srcdir, File.expand_path("lib", srcdir)) $topdir = "." $top_srcdir = srcdir require 'mkmf' require 'optparse/shellwords' def sysquote(x) @quote ||= /human|os2|macos/ =~ (CROSS_COMPILING || RUBY_PLATFORM) @quote ? x.quote : x end def relative_from(path, base) dir = File.join(path, "") if File.expand_path(dir) == File.expand_path(dir, base) path else File.join(base, path) end end def extract_makefile(makefile, keep = true) m = File.read(makefile) if !(target = m[/^TARGET[ \t]*=[ \t]*(\S*)/, 1]) return keep end installrb = {} m.scan(/^install-rb-default:[ \t]*(\S+)\n\1:[ \t]*(\S+)/) {installrb[$2] = $1} oldrb = installrb.keys.sort newrb = install_rb(nil, "").collect {|d, *f| f}.flatten.sort if target_prefix = m[/^target_prefix[ \t]*=[ \t]*\/(.*)/, 1] target = "#{target_prefix}/#{target}" end unless oldrb == newrb if $extout newrb.each {|f| installrb.delete(f)} unless installrb.empty? config = CONFIG.dup install_dirs(target_prefix).each {|var, val| config[var] = val} FileUtils.rm_f(installrb.values.collect {|f| Config.expand(f, config)}, :verbose => true) end end return false end $target = target $extconf_h = m[/^RUBY_EXTCONF_H[ \t]*=[ \t]*(\S+)/, 1] $static ||= m[/^EXTSTATIC[ \t]*=[ \t]*(\S+)/, 1] || false /^STATIC_LIB[ \t]*=[ \t]*\S+/ =~ m or $static = nil $preload = Shellwords.shellwords(m[/^preload[ \t]*=[ \t]*(.*)/, 1] || "") $DLDFLAGS += " " + (m[/^dldflags[ \t]*=[ \t]*(.*)/, 1] || "") if s = m[/^LIBS[ \t]*=[ \t]*(.*)/, 1] s.sub!(/^#{Regexp.quote($LIBRUBYARG)} */, "") s.sub!(/ *#{Regexp.quote($LIBS)}$/, "") $libs = s end $objs = (m[/^OBJS[ \t]*=[ \t](.*)/, 1] || "").split $srcs = (m[/^SRCS[ \t]*=[ \t](.*)/, 1] || "").split $LOCAL_LIBS = m[/^LOCAL_LIBS[ \t]*=[ \t]*(.*)/, 1] || "" $LIBPATH = Shellwords.shellwords(m[/^libpath[ \t]*=[ \t]*(.*)/, 1] || "") - %w[$(libdir) $(topdir)] true end def extmake(target) print "#{$message} #{target}\n" $stdout.flush if $force_static or $static_ext[target] $static = target else $static = false end unless $ignore return true if $nodynamic and not $static end FileUtils.mkpath target unless File.directory?(target) begin dir = Dir.pwd FileUtils.mkpath target unless File.directory?(target) Dir.chdir target top_srcdir = $top_srcdir topdir = $topdir hdrdir = $hdrdir prefix = "../" * (target.count("/")+1) $top_srcdir = relative_from(top_srcdir, prefix) $hdrdir = relative_from(hdrdir, prefix) $topdir = prefix + $topdir $target = target $mdir = target $srcdir = File.join($top_srcdir, "ext", $mdir) $preload = nil $objs = "" $srcs = "" $compiled[target] = false makefile = "./Makefile" ok = File.exist?(makefile) unless $ignore rbconfig0 = Config::CONFIG mkconfig0 = CONFIG rbconfig = { "hdrdir" => $hdrdir, "srcdir" => $srcdir, "topdir" => $topdir, } mkconfig = { "hdrdir" => "$(top_srcdir)", "srcdir" => "$(top_srcdir)/ext/#{$mdir}", "topdir" => $topdir, } rbconfig0.each_pair {|key, val| rbconfig[key] ||= val.dup} mkconfig0.each_pair {|key, val| mkconfig[key] ||= val.dup} Config.module_eval { remove_const(:CONFIG) const_set(:CONFIG, rbconfig) remove_const(:MAKEFILE_CONFIG) const_set(:MAKEFILE_CONFIG, mkconfig) } Object.class_eval { remove_const(:CONFIG) const_set(:CONFIG, mkconfig) } begin $extconf_h = nil ok &&= extract_makefile(makefile) conf = ["#{$srcdir}/makefile.rb", "#{$srcdir}/extconf.rb"].find {|f| File.exist?(f)} if (($extconf_h && !File.exist?($extconf_h)) || !(t = modified?(makefile, MTIMES)) || [conf, "#{$srcdir}/depend"].any? {|f| modified?(f, [t])}) then ok = false init_mkmf Logging::logfile 'mkmf.log' rm_f makefile if conf load $0 = conf else create_makefile(target) end $defs << "-DRUBY_EXPORT" if $static ok = File.exist?(makefile) end rescue SystemExit # ignore ensure rm_f "conftest*" config = $0 $0 = $PROGRAM_NAME end end ok = yield(ok) if block_given? unless ok open(makefile, "w") do |f| f.print dummy_makefile(CONFIG["srcdir"]) end return true end args = sysquote($mflags) unless $destdir.to_s.empty? or $mflags.include?("DESTDIR") args += [sysquote("DESTDIR=" + relative_from($destdir, "../"+prefix))] end if $static args += ["static"] unless $clean $extlist.push [$static, $target, File.basename($target), $preload] end unless system($make, *args) $ignore or $continue or return false end $compiled[target] = true if $clean FileUtils.rm_f("mkmf.log") if $clean != true FileUtils.rm_f([makefile, $extconf_h || "extconf.h"]) end File.unlink(makefile) rescue nil end if $static $extflags ||= "" $extlibs ||= [] $extpath ||= [] unless $mswin $extflags = ($extflags.split | $DLDFLAGS.split | $LDFLAGS.split).join(" ") end $extlibs = merge_libs($extlibs, $libs.split, $LOCAL_LIBS.split) $extpath |= $LIBPATH end ensure unless $ignore Config.module_eval { remove_const(:CONFIG) const_set(:CONFIG, rbconfig0) remove_const(:MAKEFILE_CONFIG) const_set(:MAKEFILE_CONFIG, mkconfig0) } Object.class_eval { remove_const(:CONFIG) const_set(:CONFIG, mkconfig0) } end $top_srcdir = top_srcdir $topdir = topdir $hdrdir = hdrdir Dir.chdir dir end begin Dir.rmdir target target = File.dirname(target) rescue SystemCallError break end while true true end def compiled?(target) $compiled[target] end def parse_args() $mflags = [] opts = nil $optparser ||= OptionParser.new do |opts| opts.on('-n') {$dryrun = true} opts.on('--[no-]extension [EXTS]', Array) do |v| $extension = (v == false ? [] : v) end opts.on('--[no-]extstatic [STATIC]', Array) do |v| if ($extstatic = v) == false $extstatic = [] elsif v $force_static = true if $extstatic.delete("static") $extstatic = nil if $extstatic.empty? end end opts.on('--dest-dir=DIR') do |v| $destdir = v end opts.on('--extout=DIR') do |v| $extout = (v unless v.empty?) end opts.on('--make=MAKE') do |v| $make = v || 'make' end opts.on('--make-flags=FLAGS', '--mflags', Shellwords) do |v| v.grep(/\A([-\w]+)=(.*)/) {$configure_args["--#{$1}"] = $2} if arg = v.first arg.insert(0, '-') if /\A[^-][^=]*\Z/ =~ arg end $mflags.concat(v) end opts.on('--message [MESSAGE]', String) do |v| $message = v end end begin $optparser.parse!(ARGV) rescue OptionParser::InvalidOption => e retry if /^--/ =~ e.args[0] $optparser.warn(e) abort opts.to_s end $destdir ||= '' $make, *rest = Shellwords.shellwords($make) $mflags.unshift(*rest) unless rest.empty? def $mflags.set?(flag) grep(/\A-(?!-).*#{flag.chr}/i) { return true } false end def $mflags.defined?(var) grep(/\A#{var}=(.*)/) {return $1} false end if $mflags.set?(?n) $dryrun = true else $mflags.unshift '-n' if $dryrun end $continue = $mflags.set?(?k) if $extout $extout = '$(topdir)/'+$extout Config::CONFIG["extout"] = CONFIG["extout"] = $extout $extout_prefix = $extout ? "$(extout)$(target_prefix)/" : "" $mflags << "extout=#$extout" << "extout_prefix=#$extout_prefix" end end parse_args() if target = ARGV.shift and /^[a-z-]+$/ =~ target $mflags.push(target) case target when /^(dist|real)?(clean)$/ target = $2 $ignore ||= true $clean = $1 ? $1[0] : true when /^install\b/ $install = true $ignore ||= true $mflags.unshift("INSTALL_PROG=install -c -p -m 0755", "INSTALL_DATA=install -c -p -m 0644", "MAKEDIRS=mkdir -p") if $dryrun end end unless $message if target $message = target.sub(/^(\w+)e?\b/, '\1ing').tr('-', ' ') else $message = "compiling" end end EXEEXT = CONFIG['EXEEXT'] if CROSS_COMPILING $ruby = $mflags.defined?("MINIRUBY") || CONFIG['MINIRUBY'] elsif sep = config_string('BUILD_FILE_SEPARATOR') $ruby = "$(topdir:/=#{sep})#{sep}miniruby" + EXEEXT else $ruby = '$(topdir)/miniruby' + EXEEXT end $ruby << " -I'$(topdir)'" unless CROSS_COMPILING $ruby << " -I'$(top_srcdir)/lib'" $ruby << " -I'$(extout)/$(arch)' -I'$(extout)/common'" if $extout $ruby << " -I./- -I'$(top_srcdir)/ext' -rpurelib.rb" ENV["RUBYLIB"] = "-" ENV["RUBYOPT"] = "-rpurelib.rb" end $config_h = '$(topdir)/config.h' $mflags << "ruby=#$ruby" MTIMES = [__FILE__, 'rbconfig.rb', srcdir+'/lib/mkmf.rb'].collect {|f| File.mtime(f)} # get static-link modules $static_ext = {} if $extstatic $extstatic.each do |target| target = target.downcase if /mswin32|bccwin32/ =~ RUBY_PLATFORM $static_ext[target] = $static_ext.size end end for dir in ["ext", File::join($top_srcdir, "ext")] setup = File::join(dir, CONFIG['setup']) if File.file? setup f = open(setup) while line = f.gets() line.chomp! line.sub!(/#.*$/, '') next if /^\s*$/ =~ line target, opt = line.split(nil, 3) if target == 'option' case opt when 'nodynamic' $nodynamic = true end next end target = target.downcase if /mswin32|bccwin32/ =~ RUBY_PLATFORM $static_ext[target] = $static_ext.size end MTIMES << f.mtime $setup = setup f.close break end end unless $extstatic ext_prefix = "#{$top_srcdir}/ext" exts = $static_ext.sort_by {|t, i| i}.collect {|t, i| t} if $extension exts |= $extension.select {|d| File.directory?("#{ext_prefix}/#{d}")} else withes, withouts = %w[--with --without].collect {|w| if not (w = %w[-extensions -ext].collect {|opt|arg_config(w+opt)}).any? proc {false} elsif (w = w.grep(String)).empty? proc {true} else proc {|c1| w.collect {|opt| opt.split(/,/)}.flatten.any?(&c1)} end } cond = proc {|ext| cond1 = proc {|n| File.fnmatch(n, ext, File::FNM_PATHNAME)} withes.call(cond1) or !withouts.call(cond1) } exts |= Dir.glob("#{ext_prefix}/*/**/extconf.rb").collect {|d| d = File.dirname(d) d.slice!(0, ext_prefix.length + 1) d }.find_all {|ext| with_config(ext, &cond) }.sort end if $extout extout = Config.expand("#{$extout}", Config::CONFIG.merge("topdir"=>$topdir)) unless $ignore FileUtils.mkpath(extout) end end dir = Dir.pwd FileUtils::makedirs('ext') Dir::chdir('ext') hdrdir = $hdrdir $hdrdir = $top_srcdir = relative_from(srcdir, $topdir = "..") exts.each do |d| extmake(d) or abort end $top_srcdir = srcdir $topdir = "." $hdrdir = hdrdir extinit = Struct.new(:c, :o) { def initialize(src) super("#{src}.c", "#{src}.#{$OBJEXT}") end }.new("extinit") if $ignore FileUtils.rm_f(extinit.to_a) if $clean Dir.chdir ".." if $clean Dir.rmdir('ext') rescue nil if $extout FileUtils.rm_rf([extout+"/common", extout+"/include/ruby", extout+"/rdoc"]) FileUtils.rm_rf(extout+"/"+CONFIG["arch"]) if $clean != true FileUtils.rm_rf(extout+"/include/"+CONFIG["arch"]) FileUtils.rm_f($mflags.defined?("INSTALLED_LIST")||ENV["INSTALLED_LIST"]||".installed.list") Dir.rmdir(extout+"/include") rescue nil Dir.rmdir(extout) rescue nil end end end exit end $extinit ||= "" $extobjs ||= "" $extpath ||= [] $extflags ||= "" $extlibs ||= [] unless $extlist.empty? $extinit << "\n" unless $extinit.empty? list = $extlist.dup built = [] while e = list.shift s,t,i,r = e if r and !(r -= built).empty? l = list.size if (while l > 0; break true if r.include?(list[l-=1][1]) end) list.insert(l + 1, e) end next end f = format("%s/%s.%s", s, i, $LIBEXT) if File.exist?(f) $extinit << " init(Init_#{i}, \"#{t}.so\");\n" $extobjs << "ext/#{f} " built << t end end src = %{\ #include "ruby.h" #define init(func, name) {void func _((void)); ruby_init_ext(name, func);} void ruby_init_ext _((const char *name, void (*init)(void))); void Init_ext _((void))\n{\n#$extinit} } if !modified?(extinit.c, MTIMES) || IO.read(extinit.c) != src open(extinit.c, "w") {|f| f.print src} end $extobjs = "ext/#{extinit.o} #{$extobjs}" if RUBY_PLATFORM =~ /m68k-human|beos/ $extflags.delete("-L/usr/local/lib") end $extpath.delete("$(topdir)") $extflags = libpathflag($extpath) << " " << $extflags.strip conf = [ ['LIBRUBY_SO_UPDATE', '$(LIBRUBY_EXTS)'], ['SETUP', $setup], [enable_config("shared", $enable_shared) ? 'DLDOBJS' : 'EXTOBJS', $extobjs], ['EXTLIBS', $extlibs.join(' ')], ['EXTLDFLAGS', $extflags] ].map {|n, v| "#{n}=#{v}" if v and !(v = v.strip).empty? }.compact puts conf $stdout.flush $mflags.concat(conf) else FileUtils.rm_f(extinit.to_a) end rubies = [] %w[RUBY RUBYW STATIC_RUBY].each {|r| n = r if r = arg_config("--"+r.downcase) || config_string(r+"_INSTALL_NAME") rubies << Config.expand(r+=EXEEXT) $mflags << "#{n}=#{r}" end } Dir.chdir ".." unless $destdir.to_s.empty? $mflags.defined?("DESTDIR") or $mflags << "DESTDIR=#{$destdir}" end puts "making #{rubies.join(', ')}" $stdout.flush $mflags.concat(rubies) if $nmake == ?b unless (vars = $mflags.grep(/\A\w+=/n)).empty? open(mkf = "libruby.mk", "wb") do |tmf| tmf.puts("!include Makefile") tmf.puts tmf.puts(*vars.map {|v| v.sub(/=/, " = ")}) tmf.puts("PRE_LIBRUBY_UPDATE = del #{mkf}") end $mflags.unshift("-f#{mkf}") vars.each {|flag| flag.sub!(/\A/, "-D")} end end system($make, *sysquote($mflags)) or exit($?.exitstatus) #Local variables: # mode: ruby #end: ================================================ FILE: ext/fcntl/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/fcntl/depend ================================================ fcntl.o: fcntl.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h ================================================ FILE: ext/fcntl/extconf.rb ================================================ require 'mkmf' create_makefile('fcntl') ================================================ FILE: ext/fcntl/fcntl.c ================================================ /************************************************ fcntl.c - $Author$ created at: Mon Apr 7 18:53:05 JST 1997 Copyright (C) 1997-2001 Yukihiro Matsumoto ************************************************/ /************************************************ = NAME fcntl - load the C fcntl.h defines = SYNOPSIS require "fcntl" m = s.fcntl(Fcntl::F_GETFL, 0) f.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK|m) = DESCRIPTION This module is just a translation of the C file. = NOTE Only #define symbols get translated; you must still correctly pack up your own arguments to pass as args for locking functions, etc. ************************************************/ #include "ruby.h" #include /* Fcntl loads the constants defined in the system's C header * file, and used with both the fcntl(2) and open(2) POSIX system calls. * * Copyright (C) 1997-2001 Yukihiro Matsumoto * * Documented by mathew * * = Usage * * To perform a fcntl(2) operation, use IO::fcntl in the core classes. * * To perform an open(2) operation, use IO::sysopen. * * The set of operations and constants available depends upon specific OS * platform. Some values listed below may not be supported on your system. * * The constants supported by Ruby for use with IO::fcntl are: * * - F_DUPFD - duplicate a close-on-exec file handle to a non-close-on-exec * file handle. * * - F_GETFD - read the close-on-exec flag of a file handle. * * - F_SETFD - set the close-on-exec flag of a file handle. * * - FD_CLOEXEC - the value of the close-on-exec flag. * * - F_GETFL - get file descriptor flags. * * - F_SETFL - set file descriptor flags. * * - O_APPEND, O_NONBLOCK, etc (see below) - file descriptor flag * values for the above. * * - F_GETLK - determine whether a given region of a file is locked. * * - F_SETLK - acquire a lock on a region of a file. * * - F_SETLKW - acquire a lock on a region of a file, waiting if necessary. * * - F_RDLCK, F_WRLCK, F_UNLCK - types of lock for the above. * * The constants supported by Ruby for use with IO::sysopen are: * * - O_APPEND - open file in append mode. * * - O_NOCTTY - open tty without it becoming controlling tty. * * - O_CREAT - create file if it doesn't exist. * * - O_EXCL - used with O_CREAT, fail if file exists. * * - O_TRUNC - truncate file on open. * * - O_NONBLOCK / O_NDELAY - open in non-blocking mode. * * - O_RDONLY - open read-only. * * - O_WRONLY - open write-only. * * - O_RDWR - open read-write. * * - O_ACCMODE - mask to extract read/write flags. * * Example: * * require 'fcntl' * * fd = IO::sysopen('/tmp/tempfile', * Fcntl::O_WRONLY | Fcntl::O_EXCL | Fcntl::O_CREAT) * f = IO.open(fd) * f.syswrite("TEMP DATA") * f.close * */ void Init_fcntl() { VALUE mFcntl = rb_define_module("Fcntl"); #ifdef F_DUPFD rb_define_const(mFcntl, "F_DUPFD", INT2NUM(F_DUPFD)); #endif #ifdef F_GETFD rb_define_const(mFcntl, "F_GETFD", INT2NUM(F_GETFD)); #endif #ifdef F_GETLK rb_define_const(mFcntl, "F_GETLK", INT2NUM(F_GETLK)); #endif #ifdef F_SETFD rb_define_const(mFcntl, "F_SETFD", INT2NUM(F_SETFD)); #endif #ifdef F_GETFL rb_define_const(mFcntl, "F_GETFL", INT2NUM(F_GETFL)); #endif #ifdef F_SETFL rb_define_const(mFcntl, "F_SETFL", INT2NUM(F_SETFL)); #endif #ifdef F_SETLK rb_define_const(mFcntl, "F_SETLK", INT2NUM(F_SETLK)); #endif #ifdef F_SETLKW rb_define_const(mFcntl, "F_SETLKW", INT2NUM(F_SETLKW)); #endif #ifdef FD_CLOEXEC rb_define_const(mFcntl, "FD_CLOEXEC", INT2NUM(FD_CLOEXEC)); #endif #ifdef F_RDLCK rb_define_const(mFcntl, "F_RDLCK", INT2NUM(F_RDLCK)); #endif #ifdef F_UNLCK rb_define_const(mFcntl, "F_UNLCK", INT2NUM(F_UNLCK)); #endif #ifdef F_WRLCK rb_define_const(mFcntl, "F_WRLCK", INT2NUM(F_WRLCK)); #endif #ifdef O_CREAT rb_define_const(mFcntl, "O_CREAT", INT2NUM(O_CREAT)); #endif #ifdef O_EXCL rb_define_const(mFcntl, "O_EXCL", INT2NUM(O_EXCL)); #endif #ifdef O_NOCTTY rb_define_const(mFcntl, "O_NOCTTY", INT2NUM(O_NOCTTY)); #endif #ifdef O_TRUNC rb_define_const(mFcntl, "O_TRUNC", INT2NUM(O_TRUNC)); #endif #ifdef O_APPEND rb_define_const(mFcntl, "O_APPEND", INT2NUM(O_APPEND)); #endif #ifdef O_NONBLOCK rb_define_const(mFcntl, "O_NONBLOCK", INT2NUM(O_NONBLOCK)); #endif #ifdef O_NDELAY rb_define_const(mFcntl, "O_NDELAY", INT2NUM(O_NDELAY)); #endif #ifdef O_RDONLY rb_define_const(mFcntl, "O_RDONLY", INT2NUM(O_RDONLY)); #endif #ifdef O_RDWR rb_define_const(mFcntl, "O_RDWR", INT2NUM(O_RDWR)); #endif #ifdef O_WRONLY rb_define_const(mFcntl, "O_WRONLY", INT2NUM(O_WRONLY)); #endif #ifdef O_ACCMODE rb_define_const(mFcntl, "O_ACCMODE", INT2FIX(O_ACCMODE)); #else rb_define_const(mFcntl, "O_ACCMODE", INT2FIX(O_RDONLY | O_WRONLY | O_RDWR)); #endif } ================================================ FILE: ext/gdbm/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/gdbm/README ================================================ gdbm ext-library for Ruby 1.3 or later ================================================ FILE: ext/gdbm/depend ================================================ gdbm.o: gdbm.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h ================================================ FILE: ext/gdbm/extconf.rb ================================================ require 'mkmf' dir_config("gdbm") if have_library("gdbm", "gdbm_open") and have_header("gdbm.h") create_makefile("gdbm") end ================================================ FILE: ext/gdbm/gdbm.c ================================================ /************************************************ gdbm.c - $Author$ $Date$ modified at: Mon Jan 24 15:59:52 JST 1994 Documentation by Peter Adolphs < futzilogik at users dot sourceforge dot net > ************************************************/ #include "ruby.h" #include #include #include /* * Document-class: GDBM * * == Summary * * Ruby extension for GNU dbm (gdbm) -- a simple database engine for storing * key-value pairs on disk. * * == Description * * GNU dbm is a library for simple databases. A database is a file that stores * key-value pairs. Gdbm allows the user to store, retrieve, and delete data by * key. It furthermore allows a non-sorted traversal of all key-value pairs. * A gdbm database thus provides the same functionality as a hash. As * with objects of the Hash class, elements can be accessed with []. * Furthermore, GDBM mixes in the Enumerable module, thus providing convenient * methods such as #find, #collect, #map, etc. * * A process is allowed to open several different databases at the same time. * A process can open a database as a "reader" or a "writer". Whereas a reader * has only read-access to the database, a writer has read- and write-access. * A database can be accessed either by any number of readers or by exactly one * writer at the same time. * * == Examples * * 1. Opening/creating a database, and filling it with some entries: * * require 'gdbm' * * gdbm = GDBM.new("fruitstore.db") * gdbm["ananas"] = "3" * gdbm["banana"] = "8" * gdbm["cranberry"] = "4909" * gdbm.close * * 2. Reading out a database: * * require 'gdbm' * * gdbm = GDBM.new("fruitstore.db") * gdbm.each_pair do |key, value| * print "#{key}: #{value}\n" * end * gdbm.close * * produces * * banana: 8 * ananas: 3 * cranberry: 4909 * * == Links * * * http://www.gnu.org/software/gdbm/ */ static VALUE rb_cGDBM, rb_eGDBMError, rb_eGDBMFatalError; #define RUBY_GDBM_RW_BIT 0x20000000 #define MY_BLOCK_SIZE (2048) #define MY_FATAL_FUNC rb_gdbm_fatal static void rb_gdbm_fatal(msg) char *msg; { rb_raise(rb_eGDBMFatalError, "%s", msg); } struct dbmdata { int di_size; GDBM_FILE di_dbm; }; static void closed_dbm() { rb_raise(rb_eRuntimeError, "closed GDBM file"); } #define GetDBM(obj, dbmp) do {\ Data_Get_Struct(obj, struct dbmdata, dbmp);\ if (dbmp == 0) closed_dbm();\ if (dbmp->di_dbm == 0) closed_dbm();\ } while (0) #define GetDBM2(obj, data, dbm) {\ GetDBM(obj, data);\ (dbm) = dbmp->di_dbm;\ } static void free_dbm(dbmp) struct dbmdata *dbmp; { if (dbmp) { if (dbmp->di_dbm) gdbm_close(dbmp->di_dbm); free(dbmp); } } /* * call-seq: * gdbm.close -> nil * * Closes the associated database file. */ static VALUE fgdbm_close(obj) VALUE obj; { struct dbmdata *dbmp; GetDBM(obj, dbmp); gdbm_close(dbmp->di_dbm); dbmp->di_dbm = 0; return Qnil; } /* * call-seq: * gdbm.closed? -> true or false * * Returns true if the associated database file has been closed. */ static VALUE fgdbm_closed(obj) VALUE obj; { struct dbmdata *dbmp; Data_Get_Struct(obj, struct dbmdata, dbmp); if (dbmp == 0) return Qtrue; if (dbmp->di_dbm == 0) return Qtrue; return Qfalse; } static VALUE fgdbm_s_alloc _((VALUE)); static VALUE fgdbm_s_alloc(klass) VALUE klass; { return Data_Wrap_Struct(klass, 0, free_dbm, 0); } /* * call-seq: * GDBM.new(filename, mode = 0666, flags = nil) * * Creates a new GDBM instance by opening a gdbm file named _filename_. * If the file does not exist, a new file with file mode _mode_ will be * created. _flags_ may be one of the following: * * *READER* - open as a reader * * *WRITER* - open as a writer * * *WRCREAT* - open as a writer; if the database does not exist, create a new one * * *NEWDB* - open as a writer; overwrite any existing databases * * The values *WRITER*, *WRCREAT* and *NEWDB* may be combined with the following * values by bitwise or: * * *SYNC* - cause all database operations to be synchronized to the disk * * *NOLOCK* - do not lock the database file * * If no _flags_ are specified, the GDBM object will try to open the database * file as a writer and will create it if it does not already exist * (cf. flag WRCREAT). If this fails (for instance, if another process * has already opened the database as a reader), it will try to open the * database file as a reader (cf. flag READER). */ static VALUE fgdbm_initialize(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE file, vmode, vflags; GDBM_FILE dbm; struct dbmdata *dbmp; int mode, flags = 0; if (rb_scan_args(argc, argv, "12", &file, &vmode, &vflags) == 1) { mode = 0666; /* default value */ } else if (NIL_P(vmode)) { mode = -1; /* return nil if DB does not exist */ } else { mode = NUM2INT(vmode); } if (!NIL_P(vflags)) flags = NUM2INT(vflags); SafeStringValue(file); if (flags & RUBY_GDBM_RW_BIT) { flags &= ~RUBY_GDBM_RW_BIT; dbm = gdbm_open(RSTRING(file)->ptr, MY_BLOCK_SIZE, flags, mode, MY_FATAL_FUNC); } else { dbm = 0; if (mode >= 0) dbm = gdbm_open(RSTRING(file)->ptr, MY_BLOCK_SIZE, GDBM_WRCREAT|flags, mode, MY_FATAL_FUNC); if (!dbm) dbm = gdbm_open(RSTRING(file)->ptr, MY_BLOCK_SIZE, GDBM_WRITER|flags, 0, MY_FATAL_FUNC); if (!dbm) dbm = gdbm_open(RSTRING(file)->ptr, MY_BLOCK_SIZE, GDBM_READER|flags, 0, MY_FATAL_FUNC); } if (!dbm) { if (mode == -1) return Qnil; if (gdbm_errno == GDBM_FILE_OPEN_ERROR || gdbm_errno == GDBM_CANT_BE_READER || gdbm_errno == GDBM_CANT_BE_WRITER) rb_sys_fail(RSTRING(file)->ptr); else rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); } dbmp = ALLOC(struct dbmdata); free_dbm(DATA_PTR(obj)); DATA_PTR(obj) = dbmp; dbmp->di_dbm = dbm; dbmp->di_size = -1; return obj; } /* * call-seq: * GDBM.open(filename, mode = 0666, flags = nil) * GDBM.open(filename, mode = 0666, flags = nil) { |gdbm| ... } * * If called without a block, this is synonymous to GDBM::new. * If a block is given, the new GDBM instance will be passed to the block * as a parameter, and the corresponding database file will be closed * after the execution of the block code has been finished. * * Example for an open call with a block: * * require 'gdbm' * GDBM.open("fruitstore.db") do |gdbm| * gdbm.each_pair do |key, value| * print "#{key}: #{value}\n" * end * end */ static VALUE fgdbm_s_open(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { VALUE obj = Data_Wrap_Struct(klass, 0, free_dbm, 0); if (NIL_P(fgdbm_initialize(argc, argv, obj))) { return Qnil; } if (rb_block_given_p()) { return rb_ensure(rb_yield, obj, fgdbm_close, obj); } return obj; } static VALUE rb_gdbm_fetch(dbm, key) GDBM_FILE dbm; datum key; { datum val; VALUE str; val = gdbm_fetch(dbm, key); if (val.dptr == 0) return Qnil; str = rb_str_new(val.dptr, val.dsize); free(val.dptr); OBJ_TAINT(str); return str; } static VALUE rb_gdbm_fetch2(dbm, keystr) GDBM_FILE dbm; VALUE keystr; { datum key; StringValue(keystr); key.dptr = RSTRING(keystr)->ptr; key.dsize = RSTRING(keystr)->len; return rb_gdbm_fetch(dbm, key); } static VALUE rb_gdbm_fetch3(obj, keystr) VALUE obj, keystr; { struct dbmdata *dbmp; GDBM_FILE dbm; GetDBM2(obj, dbmp, dbm); return rb_gdbm_fetch2(dbm, keystr); } static VALUE rb_gdbm_firstkey(dbm) GDBM_FILE dbm; { datum key; VALUE str; key = gdbm_firstkey(dbm); if (key.dptr == 0) return Qnil; str = rb_str_new(key.dptr, key.dsize); free(key.dptr); OBJ_TAINT(str); return str; } static VALUE rb_gdbm_nextkey(dbm, keystr) GDBM_FILE dbm; VALUE keystr; { datum key, key2; VALUE str; key.dptr = RSTRING(keystr)->ptr; key.dsize = RSTRING(keystr)->len; key2 = gdbm_nextkey(dbm, key); if (key2.dptr == 0) return Qnil; str = rb_str_new(key2.dptr, key2.dsize); free(key2.dptr); OBJ_TAINT(str); return str; } static VALUE fgdbm_fetch(obj, keystr, ifnone) VALUE obj, keystr, ifnone; { VALUE valstr; valstr = rb_gdbm_fetch3(obj, keystr); if (NIL_P(valstr)) { if (ifnone == Qnil && rb_block_given_p()) return rb_yield(keystr); return ifnone; } return valstr; } /* * call-seq: * gdbm[key] -> value * * Retrieves the _value_ corresponding to _key_. */ static VALUE fgdbm_aref(obj, keystr) VALUE obj, keystr; { return rb_gdbm_fetch3(obj, keystr); } /* * call-seq: * gdbm.fetch(key [, default]) -> value * * Retrieves the _value_ corresponding to _key_. If there is no value * associated with _key_, _default_ will be returned instead. */ static VALUE fgdbm_fetch_m(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE keystr, valstr, ifnone; rb_scan_args(argc, argv, "11", &keystr, &ifnone); valstr = fgdbm_fetch(obj, keystr, ifnone); if (argc == 1 && !rb_block_given_p() && NIL_P(valstr)) rb_raise(rb_eIndexError, "key not found"); return valstr; } /* * call-seq: * gdbm.index(value) -> key * * Returns the _key_ for a given _value_. If several keys may map to the * same value, the key that is found first will be returned. */ static VALUE fgdbm_index(obj, valstr) VALUE obj, valstr; { struct dbmdata *dbmp; GDBM_FILE dbm; VALUE keystr, valstr2; StringValue(valstr); GetDBM2(obj, dbmp, dbm); for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); keystr = rb_gdbm_nextkey(dbm, keystr)) { valstr2 = rb_gdbm_fetch2(dbm, keystr); if (!NIL_P(valstr2) && RSTRING(valstr)->len == RSTRING(valstr2)->len && memcmp(RSTRING(valstr)->ptr, RSTRING(valstr2)->ptr, RSTRING(valstr)->len) == 0) { return keystr; } } return Qnil; } static VALUE fgdbm_indexes(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE new; int i; new = rb_ary_new2(argc); for (i=0; i array * * Returns a new array of all values of the database for which _block_ * evaluates to true. */ static VALUE fgdbm_select(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE new = rb_ary_new2(argc); int i; if (rb_block_given_p()) { GDBM_FILE dbm; struct dbmdata *dbmp; VALUE keystr; if (argc > 0) { rb_raise(rb_eArgError, "wrong number arguments(%d for 0)", argc); } GetDBM2(obj, dbmp, dbm); for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); keystr = rb_gdbm_nextkey(dbm, keystr)) { VALUE assoc = rb_assoc_new(keystr, rb_gdbm_fetch2(dbm, keystr)); VALUE v = rb_yield(assoc); if (RTEST(v)) { rb_ary_push(new, assoc); } GetDBM2(obj, dbmp, dbm); } } else { rb_warn("GDBM#select(index..) is deprecated; use GDBM#values_at"); for (i=0; i array * * Returns an array of the values associated with each specified _key_. */ static VALUE fgdbm_values_at(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE new = rb_ary_new2(argc); int i; for (i=0; iptr; key.dsize = RSTRING(keystr)->len; GetDBM2(obj, dbmp, dbm); if (!gdbm_exists(dbm, key)) { return Qnil; } if (gdbm_delete(dbm, key)) { dbmp->di_size = -1; rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); } else if (dbmp->di_size >= 0) { dbmp->di_size--; } return obj; } /* * call-seq: * gdbm.delete(key) -> value or nil * * Removes the key-value-pair with the specified _key_ from this database and * returns the corresponding _value_. Returns nil if the database is empty. */ static VALUE fgdbm_delete(obj, keystr) VALUE obj, keystr; { VALUE valstr; valstr = fgdbm_fetch(obj, keystr, Qnil); rb_gdbm_delete(obj, keystr); return valstr; } /* * call-seq: * gdbm.shift -> (key, value) or nil * * Removes a key-value-pair from this database and returns it as a * two-item array [ _key_, _value_ ]. Returns nil if the database is empty. */ static VALUE fgdbm_shift(obj) VALUE obj; { struct dbmdata *dbmp; GDBM_FILE dbm; VALUE keystr, valstr; rb_gdbm_modify(obj); GetDBM2(obj, dbmp, dbm); keystr = rb_gdbm_firstkey(dbm); if (NIL_P(keystr)) return Qnil; valstr = rb_gdbm_fetch2(dbm, keystr); rb_gdbm_delete(obj, keystr); return rb_assoc_new(keystr, valstr); } /* * call-seq: * gdbm.delete_if { |key, value| block } -> gdbm * gdbm.reject! { |key, value| block } -> gdbm * * Deletes every key-value pair from _gdbm_ for which _block_ evaluates to true. */ static VALUE fgdbm_delete_if(obj) VALUE obj; { struct dbmdata *dbmp; GDBM_FILE dbm; VALUE keystr, valstr; VALUE ret, ary = rb_ary_new(); int i, status = 0, n; rb_gdbm_modify(obj); GetDBM2(obj, dbmp, dbm); n = dbmp->di_size; dbmp->di_size = -1; for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); keystr = rb_gdbm_nextkey(dbm, keystr)) { valstr = rb_gdbm_fetch2(dbm, keystr); ret = rb_protect(rb_yield, rb_assoc_new(keystr, valstr), &status); if (status != 0) break; if (RTEST(ret)) rb_ary_push(ary, keystr); GetDBM2(obj, dbmp, dbm); } for (i = 0; i < RARRAY(ary)->len; i++) rb_gdbm_delete(obj, RARRAY(ary)->ptr[i]); if (status) rb_jump_tag(status); if (n > 0) dbmp->di_size = n - RARRAY(ary)->len; return obj; } /* * call-seq: * gdbm.clear -> gdbm * * Removes all the key-value pairs within _gdbm_. */ static VALUE fgdbm_clear(obj) VALUE obj; { datum key, nextkey; struct dbmdata *dbmp; GDBM_FILE dbm; rb_gdbm_modify(obj); GetDBM2(obj, dbmp, dbm); dbmp->di_size = -1; #if 0 while (key = gdbm_firstkey(dbm), key.dptr) { if (gdbm_delete(dbm, key)) { free(key.dptr); rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); } free(key.dptr); } #else while (key = gdbm_firstkey(dbm), key.dptr) { for (; key.dptr; key = nextkey) { nextkey = gdbm_nextkey(dbm, key); if (gdbm_delete(dbm, key)) { free(key.dptr); if (nextkey.dptr) free(nextkey.dptr); rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); } free(key.dptr); } } #endif dbmp->di_size = 0; return obj; } /* * call-seq: * gdbm.invert -> hash * * Returns a hash created by using _gdbm_'s values as keys, and the keys * as values. */ static VALUE fgdbm_invert(obj) VALUE obj; { struct dbmdata *dbmp; GDBM_FILE dbm; VALUE keystr, valstr; VALUE hash = rb_hash_new(); GetDBM2(obj, dbmp, dbm); for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); keystr = rb_gdbm_nextkey(dbm, keystr)) { valstr = rb_gdbm_fetch2(dbm, keystr); rb_hash_aset(hash, valstr, keystr); } return hash; } static VALUE each_pair _((VALUE)); static VALUE each_pair(obj) VALUE obj; { return rb_funcall(obj, rb_intern("each_pair"), 0, 0); } static VALUE fgdbm_store _((VALUE,VALUE,VALUE)); static VALUE update_i(pair, dbm) VALUE pair, dbm; { Check_Type(pair, T_ARRAY); if (RARRAY(pair)->len < 2) { rb_raise(rb_eArgError, "pair must be [key, value]"); } fgdbm_store(dbm, RARRAY(pair)->ptr[0], RARRAY(pair)->ptr[1]); return Qnil; } /* * call-seq: * gdbm.update(other) -> gdbm * * Adds the key-value pairs of _other_ to _gdbm_, overwriting entries with * duplicate keys with those from _other_. _other_ must have an each_pair * method. */ static VALUE fgdbm_update(obj, other) VALUE obj, other; { rb_iterate(each_pair, other, update_i, obj); return obj; } /* * call-seq: * gdbm.replace(other) -> gdbm * * Replaces the content of _gdbm_ with the key-value pairs of _other_. * _other_ must have an each_pair method. */ static VALUE fgdbm_replace(obj, other) VALUE obj, other; { fgdbm_clear(obj); rb_iterate(each_pair, other, update_i, obj); return obj; } /* * call-seq: * gdbm[key]= value -> value * gdbm.store(key, value) -> value * * Associates the value _value_ with the specified _key_. */ static VALUE fgdbm_store(obj, keystr, valstr) VALUE obj, keystr, valstr; { datum key, val; struct dbmdata *dbmp; GDBM_FILE dbm; rb_gdbm_modify(obj); StringValue(keystr); StringValue(valstr); key.dptr = RSTRING(keystr)->ptr; key.dsize = RSTRING(keystr)->len; val.dptr = RSTRING(valstr)->ptr; val.dsize = RSTRING(valstr)->len; GetDBM2(obj, dbmp, dbm); dbmp->di_size = -1; if (gdbm_store(dbm, key, val, GDBM_REPLACE)) { if (errno == EPERM) rb_sys_fail(0); rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); } return valstr; } /* * call-seq: * gdbm.length -> fixnum * gdbm.size -> fixnum * * Returns the number of key-value pairs in this database. */ static VALUE fgdbm_length(obj) VALUE obj; { datum key, nextkey; struct dbmdata *dbmp; GDBM_FILE dbm; int i = 0; GetDBM2(obj, dbmp, dbm); if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size); for (key = gdbm_firstkey(dbm); key.dptr; key = nextkey) { nextkey = gdbm_nextkey(dbm, key); free(key.dptr); i++; } dbmp->di_size = i; return INT2FIX(i); } /* * call-seq: * gdbm.empty? -> true or false * * Returns true if the database is empty. */ static VALUE fgdbm_empty_p(obj) VALUE obj; { datum key; struct dbmdata *dbmp; GDBM_FILE dbm; GetDBM(obj, dbmp); if (dbmp->di_size < 0) { dbm = dbmp->di_dbm; key = gdbm_firstkey(dbm); if (key.dptr) { free(key.dptr); return Qfalse; } return Qtrue; } if (dbmp->di_size == 0) return Qtrue; return Qfalse; } /* * call-seq: * gdbm.each_value { |value| block } -> gdbm * * Executes _block_ for each key in the database, passing the corresponding * _value_ as a parameter. */ static VALUE fgdbm_each_value(obj) VALUE obj; { struct dbmdata *dbmp; GDBM_FILE dbm; VALUE keystr; GetDBM2(obj, dbmp, dbm); for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); keystr = rb_gdbm_nextkey(dbm, keystr)) { rb_yield(rb_gdbm_fetch2(dbm, keystr)); GetDBM2(obj, dbmp, dbm); } return obj; } /* * call-seq: * gdbm.each_key { |key| block } -> gdbm * * Executes _block_ for each key in the database, passing the * _key_ as a parameter. */ static VALUE fgdbm_each_key(obj) VALUE obj; { struct dbmdata *dbmp; GDBM_FILE dbm; VALUE keystr; GetDBM2(obj, dbmp, dbm); for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); keystr = rb_gdbm_nextkey(dbm, keystr)) { rb_yield(keystr); GetDBM2(obj, dbmp, dbm); } return obj; } /* * call-seq: * gdbm.each_pair { |key, value| block } -> gdbm * * Executes _block_ for each key in the database, passing the _key_ and the * correspoding _value_ as a parameter. */ static VALUE fgdbm_each_pair(obj) VALUE obj; { GDBM_FILE dbm; struct dbmdata *dbmp; VALUE keystr; GetDBM2(obj, dbmp, dbm); for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); keystr = rb_gdbm_nextkey(dbm, keystr)) { rb_yield(rb_assoc_new(keystr, rb_gdbm_fetch2(dbm, keystr))); GetDBM2(obj, dbmp, dbm); } return obj; } /* * call-seq: * gdbm.keys -> array * * Returns an array of all keys of this database. */ static VALUE fgdbm_keys(obj) VALUE obj; { struct dbmdata *dbmp; GDBM_FILE dbm; VALUE keystr, ary; GetDBM2(obj, dbmp, dbm); ary = rb_ary_new(); for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); keystr = rb_gdbm_nextkey(dbm, keystr)) { rb_ary_push(ary, keystr); } return ary; } /* * call-seq: * gdbm.values -> array * * Returns an array of all values of this database. */ static VALUE fgdbm_values(obj) VALUE obj; { datum key, nextkey; struct dbmdata *dbmp; GDBM_FILE dbm; VALUE valstr, ary; GetDBM2(obj, dbmp, dbm); ary = rb_ary_new(); for (key = gdbm_firstkey(dbm); key.dptr; key = nextkey) { nextkey = gdbm_nextkey(dbm, key); valstr = rb_gdbm_fetch(dbm, key); free(key.dptr); rb_ary_push(ary, valstr); } return ary; } /* * call-seq: * gdbm.has_key?(k) -> true or false * gdbm.key?(k) -> true or false * * Returns true if the given key _k_ exists within the database. * Returns false otherwise. */ static VALUE fgdbm_has_key(obj, keystr) VALUE obj, keystr; { datum key; struct dbmdata *dbmp; GDBM_FILE dbm; StringValue(keystr); key.dptr = RSTRING(keystr)->ptr; key.dsize = RSTRING(keystr)->len; GetDBM2(obj, dbmp, dbm); if (gdbm_exists(dbm, key)) return Qtrue; return Qfalse; } /* * call-seq: * gdbm.has_value?(v) -> true or false * gdbm.value?(v) -> true or false * * Returns true if the given value _v_ exists within the database. * Returns false otherwise. */ static VALUE fgdbm_has_value(obj, valstr) VALUE obj, valstr; { struct dbmdata *dbmp; GDBM_FILE dbm; VALUE keystr, valstr2; StringValue(valstr); GetDBM2(obj, dbmp, dbm); for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); keystr = rb_gdbm_nextkey(dbm, keystr)) { valstr2 = rb_gdbm_fetch2(dbm, keystr); if (!NIL_P(valstr2) && RSTRING(valstr)->len == RSTRING(valstr2)->len && memcmp(RSTRING(valstr)->ptr, RSTRING(valstr2)->ptr, RSTRING(valstr)->len) == 0) { return Qtrue; } } return Qfalse; } /* * call-seq: * gdbm.to_a -> array * * Returns an array of all key-value pairs contained in the database. */ static VALUE fgdbm_to_a(obj) VALUE obj; { struct dbmdata *dbmp; GDBM_FILE dbm; VALUE keystr, ary; GetDBM2(obj, dbmp, dbm); ary = rb_ary_new(); for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); keystr = rb_gdbm_nextkey(dbm, keystr)) { rb_ary_push(ary, rb_assoc_new(keystr, rb_gdbm_fetch2(dbm, keystr))); } return ary; } /* * call-seq: * gdbm.reorganize -> gdbm * * Reorganizes the database file. This operation removes reserved space of * elements that have already been deleted. It is only useful after a lot of * deletions in the database. */ static VALUE fgdbm_reorganize(obj) VALUE obj; { struct dbmdata *dbmp; GDBM_FILE dbm; rb_gdbm_modify(obj); GetDBM2(obj, dbmp, dbm); gdbm_reorganize(dbm); return obj; } /* * call-seq: * gdbm.sync -> gdbm * * Unless the _gdbm_ object has been opened with the *SYNC* flag, it is not * guarenteed that database modification operations are immediately applied to * the database file. This method ensures that all recent modifications * to the database are written to the file. Blocks until all writing operations * to the disk have been finished. */ static VALUE fgdbm_sync(obj) VALUE obj; { struct dbmdata *dbmp; GDBM_FILE dbm; rb_gdbm_modify(obj); GetDBM2(obj, dbmp, dbm); gdbm_sync(dbm); return obj; } /* * call-seq: * gdbm.cachesize = size -> size * * Sets the size of the internal bucket cache to _size_. */ static VALUE fgdbm_set_cachesize(obj, val) VALUE obj, val; { struct dbmdata *dbmp; GDBM_FILE dbm; int optval; GetDBM2(obj, dbmp, dbm); optval = FIX2INT(val); if (gdbm_setopt(dbm, GDBM_CACHESIZE, &optval, sizeof(optval)) == -1) { rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); } return val; } /* * call-seq: * gdbm.fastmode = boolean -> boolean * * Turns the database's fast mode on or off. If fast mode is turned on, gdbm * does not wait for writes to be flushed to the disk before continuing. * * This option is obsolete for gdbm >= 1.8 since fast mode is turned on by * default. See also: #syncmode= */ static VALUE fgdbm_set_fastmode(obj, val) VALUE obj, val; { struct dbmdata *dbmp; GDBM_FILE dbm; int optval; GetDBM2(obj, dbmp, dbm); optval = 0; if (RTEST(val)) optval = 1; if (gdbm_setopt(dbm, GDBM_FASTMODE, &optval, sizeof(optval)) == -1) { rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); } return val; } /* * call-seq: * gdbm.syncmode = boolean -> boolean * * Turns the database's synchronization mode on or off. If the synchronization * mode is turned on, the database's in-memory state will be synchronized to * disk after every database modification operation. If the synchronization * mode is turned off, GDBM does not wait for writes to be flushed to the disk * before continuing. * * This option is only available for gdbm >= 1.8 where syncmode is turned off * by default. See also: #fastmode= */ static VALUE fgdbm_set_syncmode(obj, val) VALUE obj, val; { #if !defined(GDBM_SYNCMODE) fgdbm_set_fastmode(obj, RTEST(val) ? Qfalse : Qtrue); return val; #else struct dbmdata *dbmp; GDBM_FILE dbm; int optval; GetDBM2(obj, dbmp, dbm); optval = 0; if (RTEST(val)) optval = 1; if (gdbm_setopt(dbm, GDBM_FASTMODE, &optval, sizeof(optval)) == -1) { rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno)); } return val; #endif } /* * call-seq: * gdbm.to_hash -> hash * * Returns a hash of all key-value pairs contained in the database. */ static VALUE fgdbm_to_hash(obj) VALUE obj; { struct dbmdata *dbmp; GDBM_FILE dbm; VALUE keystr, hash; GetDBM2(obj, dbmp, dbm); hash = rb_hash_new(); for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr); keystr = rb_gdbm_nextkey(dbm, keystr)) { rb_hash_aset(hash, keystr, rb_gdbm_fetch2(dbm, keystr)); } return hash; } /* * call-seq: * gdbm.reject { |key, value| block } -> hash * * Returns a hash copy of _gdbm_ where all key-value pairs from _gdbm_ for * which _block_ evaluates to true are removed. See also: #delete_if */ static VALUE fgdbm_reject(obj) VALUE obj; { return rb_hash_delete_if(fgdbm_to_hash(obj)); } void Init_gdbm() { rb_cGDBM = rb_define_class("GDBM", rb_cObject); rb_eGDBMError = rb_define_class("GDBMError", rb_eStandardError); rb_eGDBMFatalError = rb_define_class("GDBMFatalError", rb_eException); rb_include_module(rb_cGDBM, rb_mEnumerable); rb_define_alloc_func(rb_cGDBM, fgdbm_s_alloc); rb_define_singleton_method(rb_cGDBM, "open", fgdbm_s_open, -1); rb_define_method(rb_cGDBM, "initialize", fgdbm_initialize, -1); rb_define_method(rb_cGDBM, "close", fgdbm_close, 0); rb_define_method(rb_cGDBM, "closed?", fgdbm_closed, 0); rb_define_method(rb_cGDBM, "[]", fgdbm_aref, 1); rb_define_method(rb_cGDBM, "fetch", fgdbm_fetch_m, -1); rb_define_method(rb_cGDBM, "[]=", fgdbm_store, 2); rb_define_method(rb_cGDBM, "store", fgdbm_store, 2); rb_define_method(rb_cGDBM, "index", fgdbm_index, 1); rb_define_method(rb_cGDBM, "indexes", fgdbm_indexes, -1); rb_define_method(rb_cGDBM, "indices", fgdbm_indexes, -1); rb_define_method(rb_cGDBM, "select", fgdbm_select, -1); rb_define_method(rb_cGDBM, "values_at", fgdbm_values_at, -1); rb_define_method(rb_cGDBM, "length", fgdbm_length, 0); rb_define_method(rb_cGDBM, "size", fgdbm_length, 0); rb_define_method(rb_cGDBM, "empty?", fgdbm_empty_p, 0); rb_define_method(rb_cGDBM, "each", fgdbm_each_pair, 0); rb_define_method(rb_cGDBM, "each_value", fgdbm_each_value, 0); rb_define_method(rb_cGDBM, "each_key", fgdbm_each_key, 0); rb_define_method(rb_cGDBM, "each_pair", fgdbm_each_pair, 0); rb_define_method(rb_cGDBM, "keys", fgdbm_keys, 0); rb_define_method(rb_cGDBM, "values", fgdbm_values, 0); rb_define_method(rb_cGDBM, "shift", fgdbm_shift, 0); rb_define_method(rb_cGDBM, "delete", fgdbm_delete, 1); rb_define_method(rb_cGDBM, "delete_if", fgdbm_delete_if, 0); rb_define_method(rb_cGDBM, "reject!", fgdbm_delete_if, 0); rb_define_method(rb_cGDBM, "reject", fgdbm_reject, 0); rb_define_method(rb_cGDBM, "clear", fgdbm_clear, 0); rb_define_method(rb_cGDBM, "invert", fgdbm_invert, 0); rb_define_method(rb_cGDBM, "update", fgdbm_update, 1); rb_define_method(rb_cGDBM, "replace", fgdbm_replace, 1); rb_define_method(rb_cGDBM, "reorganize", fgdbm_reorganize, 0); rb_define_method(rb_cGDBM, "sync", fgdbm_sync, 0); /* rb_define_method(rb_cGDBM, "setopt", fgdbm_setopt, 2); */ rb_define_method(rb_cGDBM, "cachesize=", fgdbm_set_cachesize, 1); rb_define_method(rb_cGDBM, "fastmode=", fgdbm_set_fastmode, 1); rb_define_method(rb_cGDBM, "syncmode=", fgdbm_set_syncmode, 1); rb_define_method(rb_cGDBM, "include?", fgdbm_has_key, 1); rb_define_method(rb_cGDBM, "has_key?", fgdbm_has_key, 1); rb_define_method(rb_cGDBM, "member?", fgdbm_has_key, 1); rb_define_method(rb_cGDBM, "has_value?", fgdbm_has_value, 1); rb_define_method(rb_cGDBM, "key?", fgdbm_has_key, 1); rb_define_method(rb_cGDBM, "value?", fgdbm_has_value, 1); rb_define_method(rb_cGDBM, "to_a", fgdbm_to_a, 0); rb_define_method(rb_cGDBM, "to_hash", fgdbm_to_hash, 0); /* flag for #new and #open: open database as a reader */ rb_define_const(rb_cGDBM, "READER", INT2FIX(GDBM_READER|RUBY_GDBM_RW_BIT)); /* flag for #new and #open: open database as a writer */ rb_define_const(rb_cGDBM, "WRITER", INT2FIX(GDBM_WRITER|RUBY_GDBM_RW_BIT)); /* flag for #new and #open: open database as a writer; if the database does not exist, create a new one */ rb_define_const(rb_cGDBM, "WRCREAT", INT2FIX(GDBM_WRCREAT|RUBY_GDBM_RW_BIT)); /* flag for #new and #open: open database as a writer; overwrite any existing databases */ rb_define_const(rb_cGDBM, "NEWDB", INT2FIX(GDBM_NEWDB|RUBY_GDBM_RW_BIT)); /* flag for #new and #open. this flag is obsolete for gdbm >= 1.8 */ rb_define_const(rb_cGDBM, "FAST", INT2FIX(GDBM_FAST)); /* this flag is obsolete in gdbm 1.8. On gdbm 1.8, fast mode is default behavior. */ /* gdbm version 1.8 specific */ #if defined(GDBM_SYNC) /* flag for #new and #open. only for gdbm >= 1.8 */ rb_define_const(rb_cGDBM, "SYNC", INT2FIX(GDBM_SYNC)); #endif #if defined(GDBM_NOLOCK) /* flag for #new and #open */ rb_define_const(rb_cGDBM, "NOLOCK", INT2FIX(GDBM_NOLOCK)); #endif /* version of the gdbm library*/ rb_define_const(rb_cGDBM, "VERSION", rb_str_new2(gdbm_version)); } ================================================ FILE: ext/iconv/.cvsignore ================================================ Makefile mkmf.log *.def iconv.rb config.charset ================================================ FILE: ext/iconv/charset_alias.rb ================================================ #! /usr/bin/ruby # :stopdoc: require 'rbconfig' require 'optparse' # http://www.ctan.org/tex-archive/macros/texinfo/texinfo/intl/config.charset # Fri, 30 May 2003 00:09:00 GMT' OS = Config::CONFIG["target_os"] SHELL = Config::CONFIG['SHELL'] class Hash::Ordered < Hash def [](key) val = super and val.last end def []=(key, val) ary = fetch(key) {return super(key, [self.size, key, val])} and ary << val end def sort values.sort.collect {|i, *rest| rest} end def each(&block) sort.each(&block) end end def charset_alias(config_charset, mapfile, target = OS) map = Hash::Ordered.new comments = [] open(config_charset) do |input| input.find {|line| /^case "\$os" in/ =~ line} or break input.find {|line| /^\s*([-\w\*]+(?:\s*\|\s*[-\w\*]+)*)(?=\))/ =~ line and $&.split('|').any? {|pattern| File.fnmatch?(pattern.strip, target)} } or break input.find do |line| case line when /^\s*echo "(?:\$\w+\.)?([-\w*]+)\s+([-\w]+)"/ sys, can = $1, $2 can.downcase! map[can] = sys false when /^\s*;;/ true else false end end end case target when /linux|-gnu/ # map.delete('ascii') when /cygwin|os2-emx/ # get rid of tilde/yen problem. map['shift_jis'] = 'cp932' end st = Hash.new(0) map = map.sort.collect do |can, *sys| if sys.grep(/^en_us(?=.|$)/i) {break true} == true noen = %r"^(?!en_us)\w+_\w+#{Regexp.new($')}$"i #" sys.reject! {|s| noen =~ s} end sys = sys.first st[sys] += 1 [can, sys] end st.delete_if {|sys, i| i == 1}.empty? st.keys.each {|sys| st[sys] = nil} st.default = nil writer = proc do |f| f.puts("require 'iconv.so'") f.puts f.puts(comments) f.puts("class Iconv") i = 0 map.each do |can, sys| if s = st[sys] sys = s elsif st.key?(sys) sys = (st[sys] = "sys#{i+=1}") + " = '#{sys}'.freeze" else sys = "'#{sys}'.freeze" end f.puts(" charset_map['#{can}'] = #{sys}") end f.puts("end") end if mapfile open(mapfile, "w", &writer) else writer[STDOUT] end end target = OS opt = nil ARGV.options do |opt| opt.banner << " config.status map.rb" opt.on("--target OS") {|t| target = t} opt.parse! and (1..2) === ARGV.size end or abort opt.to_s charset_alias(ARGV[0], ARGV[1], target) ================================================ FILE: ext/iconv/depend ================================================ iconv.o: iconv.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h \ $(hdrdir)/intern.h ================================================ FILE: ext/iconv/extconf.rb ================================================ require 'mkmf' dir_config("iconv") conf = File.exist?(File.join($srcdir, "config.charset")) conf = with_config("config-charset", enable_config("config-charset", conf)) if have_func("iconv", "iconv.h") or have_library("iconv", "iconv", "iconv.h") if checking_for("const of iconv() 2nd argument") do create_tmpsrc(cpp_include("iconv.h") + "---> iconv(cd,0,0,0,0) <---") src = xpopen(cpp_command("")) {|f|f.read} if !(func = src[/^--->\s*(\w+).*\s*<---/, 1]) Logging::message "iconv function name not found" false elsif !(second = src[%r"\b#{func}\s*\(.*?,(.*?),.*?\)\s*;"m, 1]) Logging::message "prototype for #{func}() not found" false else Logging::message $&+"\n" /\bconst\b/ =~ second end end $defs.push('-DICONV_INPTR_CONST') end if conf prefix = '$(srcdir)' prefix = $nmake ? "{#{prefix}}" : "#{prefix}/" if $extout wrapper = "$(RUBYARCHDIR)/iconv.rb" else wrapper = "./iconv.rb" $INSTALLFILES = [[wrapper, "$(RUBYARCHDIR)"]] end if String === conf require 'uri' scheme = URI.parse(conf).scheme else conf = "$(srcdir)/config.charset" end $cleanfiles << wrapper end create_makefile("iconv") if conf open("Makefile", "a") do |mf| mf.print("\nall: #{wrapper}\n\n#{wrapper}: #{prefix}charset_alias.rb") mf.print(" ", conf) unless scheme mf.print("\n\t$(RUBY) $(srcdir)/charset_alias.rb #{conf} $@\n") end end end ================================================ FILE: ext/iconv/iconv.c ================================================ /* -*- mode:c; c-file-style:"ruby" -*- */ /********************************************************************** iconv.c - $Author$ $Date$ created at: Wed Dec 1 20:28:09 JST 1999 All the files in this distribution are covered under the Ruby's license (see the file COPYING). Documentation by Yukihiro Matsumoto and Gavin Sinclair. **********************************************************************/ #include "ruby.h" #include #include #include #include "st.h" #include "intern.h" /* * Document-class: Iconv * * == Summary * * Ruby extension for charset conversion. * * == Abstract * * Iconv is a wrapper class for the UNIX 95 iconv() function family, * which translates string between various encoding systems. * * See Open Group's on-line documents for more details. * * iconv.h: http://www.opengroup.org/onlinepubs/007908799/xsh/iconv.h.html * * iconv_open(): http://www.opengroup.org/onlinepubs/007908799/xsh/iconv_open.html * * iconv(): http://www.opengroup.org/onlinepubs/007908799/xsh/iconv.html * * iconv_close(): http://www.opengroup.org/onlinepubs/007908799/xsh/iconv_close.html * * Which coding systems are available is platform-dependent. * * == Examples * * 1. Simple conversion between two charsets. * * converted_text = Iconv.conv('iso-8859-15', 'utf-8', text) * * 2. Instantiate a new Iconv and use method Iconv#iconv. * * cd = Iconv.new(to, from) * begin * input.each { |s| output << cd.iconv(s) } * output << cd.iconv(nil) # Don't forget this! * ensure * cd.close * end * * 3. Invoke Iconv.open with a block. * * Iconv.open(to, from) do |cd| * input.each { |s| output << cd.iconv(s) } * output << cd.iconv(nil) * end * * 4. Shorthand for (3). * * Iconv.iconv(to, from, *input.to_a) */ /* Invalid value for iconv_t is -1 but 0 for VALUE, I hope VALUE is big enough to keep iconv_t */ #define VALUE2ICONV(v) ((iconv_t)((VALUE)(v) ^ -1)) #define ICONV2VALUE(c) ((VALUE)(c) ^ -1) struct iconv_env_t { iconv_t cd; int argc; VALUE *argv; VALUE ret; VALUE (*append)_((VALUE, VALUE)); }; static VALUE rb_eIconvInvalidEncoding; static VALUE rb_eIconvFailure; static VALUE rb_eIconvIllegalSeq; static VALUE rb_eIconvInvalidChar; static VALUE rb_eIconvOutOfRange; static VALUE rb_eIconvBrokenLibrary; static ID rb_success, rb_failed; static VALUE iconv_fail _((VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env, const char *mesg)); static VALUE iconv_fail_retry _((VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env, const char *mesg)); static VALUE iconv_failure_initialize _((VALUE error, VALUE mesg, VALUE success, VALUE failed)); static VALUE iconv_failure_success _((VALUE self)); static VALUE iconv_failure_failed _((VALUE self)); static iconv_t iconv_create _((VALUE to, VALUE from)); static void iconv_dfree _((void *cd)); static VALUE iconv_free _((VALUE cd)); static VALUE iconv_try _((iconv_t cd, const char **inptr, size_t *inlen, char **outptr, size_t *outlen)); static VALUE rb_str_derive _((VALUE str, const char* ptr, int len)); static VALUE iconv_convert _((iconv_t cd, VALUE str, long start, long length, struct iconv_env_t* env)); static VALUE iconv_s_allocate _((VALUE klass)); static VALUE iconv_initialize _((VALUE self, VALUE to, VALUE from)); static VALUE iconv_s_open _((VALUE self, VALUE to, VALUE from)); static VALUE iconv_s_convert _((struct iconv_env_t* env)); static VALUE iconv_s_iconv _((int argc, VALUE *argv, VALUE self)); static VALUE iconv_init_state _((VALUE cd)); static VALUE iconv_finish _((VALUE self)); static VALUE iconv_iconv _((int argc, VALUE *argv, VALUE self)); static VALUE charset_map; /* * Document-method: charset_map * call-seq: Iconv.charset_map * * Returns the map from canonical name to system dependent name. */ static VALUE charset_map_get _((void)) { return charset_map; } static char * map_charset #ifdef HAVE_PROTOTYPES (VALUE *code) #else /* HAVE_PROTOTYPES */ (code) VALUE *code; #endif /* HAVE_PROTOTYPES */ { VALUE val = *code; if (RHASH(charset_map)->tbl && RHASH(charset_map)->tbl->num_entries) { VALUE key = rb_funcall2(val, rb_intern("downcase"), 0, 0); StringValuePtr(key); if (st_lookup(RHASH(charset_map)->tbl, key, &val)) { *code = val; } } return StringValuePtr(*code); } static iconv_t iconv_create #ifdef HAVE_PROTOTYPES (VALUE to, VALUE from) #else /* HAVE_PROTOTYPES */ (to, from) VALUE to; VALUE from; #endif /* HAVE_PROTOTYPES */ { const char* tocode = map_charset(&to); const char* fromcode = map_charset(&from); iconv_t cd = iconv_open(tocode, fromcode); if (cd == (iconv_t)-1) { switch (errno) { case EMFILE: case ENFILE: case ENOMEM: rb_gc(); cd = iconv_open(tocode, fromcode); } if (cd == (iconv_t)-1) { int inval = errno == EINVAL; const char *s = inval ? "invalid encoding " : "iconv"; volatile VALUE msg = rb_str_new(0, strlen(s) + RSTRING(to)->len + RSTRING(from)->len + 8); sprintf(RSTRING(msg)->ptr, "%s(\"%s\", \"%s\")", s, RSTRING(to)->ptr, RSTRING(from)->ptr); s = RSTRING(msg)->ptr; RSTRING(msg)->len = strlen(s); if (!inval) rb_sys_fail(s); rb_exc_raise(iconv_fail(rb_eIconvInvalidEncoding, Qnil, rb_ary_new3(2, to, from), NULL, s)); } } return cd; } static void iconv_dfree #ifdef HAVE_PROTOTYPES (void *cd) #else /* HAVE_PROTOTYPES */ (cd) void *cd; #endif /* HAVE_PROTOTYPES */ { iconv_close(VALUE2ICONV(cd)); } #define ICONV_FREE iconv_dfree static VALUE iconv_free #ifdef HAVE_PROTOTYPES (VALUE cd) #else /* HAVE_PROTOTYPES */ (cd) VALUE cd; #endif /* HAVE_PROTOTYPES */ { if (cd && iconv_close(VALUE2ICONV(cd)) == -1) rb_sys_fail("iconv_close"); return Qnil; } static VALUE check_iconv #ifdef HAVE_PROTOTYPES (VALUE obj) #else /* HAVE_PROTOTYPES */ (obj) VALUE obj; #endif /* HAVE_PROTOTYPES */ { Check_Type(obj, T_DATA); if (RDATA(obj)->dfree != ICONV_FREE) { rb_raise(rb_eArgError, "Iconv expected (%s)", rb_class2name(CLASS_OF(obj))); } return (VALUE)DATA_PTR(obj); } static VALUE iconv_try #ifdef HAVE_PROTOTYPES (iconv_t cd, const char **inptr, size_t *inlen, char **outptr, size_t *outlen) #else /* HAVE_PROTOTYPES */ (cd, inptr, inlen, outptr, outlen) iconv_t cd; const char **inptr; size_t *inlen; char **outptr; size_t *outlen; #endif /* HAVE_PROTOTYPES */ { #ifdef ICONV_INPTR_CONST #define ICONV_INPTR_CAST #else #define ICONV_INPTR_CAST (char **) #endif size_t ret; errno = 0; ret = iconv(cd, ICONV_INPTR_CAST inptr, inlen, outptr, outlen); if (ret == (size_t)-1) { if (!*inlen) return Qfalse; switch (errno) { case E2BIG: /* try the left in next loop */ break; case EILSEQ: return rb_eIconvIllegalSeq; case EINVAL: return rb_eIconvInvalidChar; case 0: return rb_eIconvBrokenLibrary; default: rb_sys_fail("iconv"); } } else if (*inlen > 0) { /* something goes wrong */ return rb_eIconvIllegalSeq; } else if (ret) { return Qnil; /* conversion */ } return Qfalse; } #define FAILED_MAXLEN 16 static VALUE iconv_failure_initialize #ifdef HAVE_PROTOTYPES (VALUE error, VALUE mesg, VALUE success, VALUE failed) #else /* HAVE_PROTOTYPES */ (error, mesg, success, failed) VALUE error, mesg, success, failed; #endif /* HAVE_PROTOTYPES */ { rb_call_super(1, &mesg); rb_ivar_set(error, rb_success, success); rb_ivar_set(error, rb_failed, failed); return error; } static VALUE iconv_fail #ifdef HAVE_PROTOTYPES (VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env, const char *mesg) #else /* HAVE_PROTOTYPES */ (error, success, failed, env, mesg) VALUE error, success, failed; struct iconv_env_t *env; const char *mesg; #endif /* HAVE_PROTOTYPES */ { VALUE args[3]; if (mesg && *mesg) { args[0] = rb_str_new2(mesg); } else if (TYPE(failed) != T_STRING || RSTRING(failed)->len < FAILED_MAXLEN) { args[0] = rb_inspect(failed); } else { args[0] = rb_inspect(rb_str_substr(failed, 0, FAILED_MAXLEN)); rb_str_cat2(args[0], "..."); } args[1] = success; args[2] = failed; if (env) { args[1] = env->append(rb_obj_dup(env->ret), success); if (env->argc > 0) { *(env->argv) = failed; args[2] = rb_ary_new4(env->argc, env->argv); } } return rb_class_new_instance(3, args, error); } static VALUE iconv_fail_retry(VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env, const char *mesg) { error = iconv_fail(error, success, failed, env, mesg); if (!rb_block_given_p()) rb_exc_raise(error); ruby_errinfo = error; return rb_yield(failed); } static VALUE rb_str_derive #ifdef HAVE_PROTOTYPES (VALUE str, const char* ptr, int len) #else /* HAVE_PROTOTYPES */ (str, ptr, len) VALUE str; const char *ptr; int len; #endif /* HAVE_PROTOTYPES */ { VALUE ret; if (NIL_P(str)) return rb_str_new(ptr, len); if (RSTRING(str)->ptr == ptr && RSTRING(str)->len == len) return str; if (RSTRING(str)->ptr + RSTRING(str)->len == ptr + len) ret = rb_str_substr(str, ptr - RSTRING(str)->ptr, len); else ret = rb_str_new(ptr, len); OBJ_INFECT(ret, str); return ret; } static VALUE iconv_convert #ifdef HAVE_PROTOTYPES (iconv_t cd, VALUE str, long start, long length, struct iconv_env_t* env) #else /* HAVE_PROTOTYPES */ (cd, str, start, length, env) iconv_t cd; VALUE str; long start; long length; struct iconv_env_t *env; #endif /* HAVE_PROTOTYPES */ { VALUE ret = Qfalse; VALUE error = Qfalse; VALUE rescue; const char *inptr, *instart; size_t inlen; /* I believe ONE CHARACTER never exceed this. */ char buffer[BUFSIZ]; char *outptr; size_t outlen; if (cd == (iconv_t)-1) rb_raise(rb_eArgError, "closed iconv"); if (NIL_P(str)) { /* Reset output pointer or something. */ inptr = ""; inlen = 0; outptr = buffer; outlen = sizeof(buffer); error = iconv_try(cd, &inptr, &inlen, &outptr, &outlen); if (RTEST(error)) { unsigned int i; rescue = iconv_fail_retry(error, Qnil, Qnil, env, 0); if (TYPE(rescue) == T_ARRAY) { str = RARRAY(rescue)->len > 0 ? RARRAY(rescue)->ptr[0] : Qnil; } if (FIXNUM_P(str) && (i = FIX2INT(str)) <= 0xff) { char c = i; str = rb_str_new(&c, 1); } else if (!NIL_P(str)) { StringValue(str); } } inptr = NULL; length = 0; } else { int slen; StringValue(str); slen = RSTRING(str)->len; inptr = RSTRING(str)->ptr; inptr += start; if (length < 0 || length > start + slen) length = slen - start; } instart = inptr; inlen = length; do { char errmsg[50]; const char *tmpstart = inptr; outptr = buffer; outlen = sizeof(buffer); errmsg[0] = 0; error = iconv_try(cd, &inptr, &inlen, &outptr, &outlen); if (0 <= outlen && outlen <= sizeof(buffer)) { outlen = sizeof(buffer) - outlen; if (NIL_P(error) || /* something converted */ outlen > inptr - tmpstart || /* input can't contain output */ (outlen < inptr - tmpstart && inlen > 0) || /* something skipped */ memcmp(buffer, tmpstart, outlen)) /* something differs */ { if (NIL_P(str)) { ret = rb_str_new(buffer, outlen); } else { if (ret) { ret = rb_str_buf_cat(ret, instart, tmpstart - instart); } else { ret = rb_str_new(instart, tmpstart - instart); OBJ_INFECT(ret, str); } ret = rb_str_buf_cat(ret, buffer, outlen); instart = inptr; } } else if (!inlen) { inptr = tmpstart + outlen; } } else { /* Some iconv() have a bug, return *outlen out of range */ sprintf(errmsg, "bug?(output length = %ld)", (long)(sizeof(buffer) - outlen)); error = rb_eIconvOutOfRange; } if (RTEST(error)) { long len = 0; if (!ret) ret = rb_str_derive(str, instart, inptr - instart); else if (inptr > instart) rb_str_cat(ret, instart, inptr - instart); str = rb_str_derive(str, inptr, inlen); rescue = iconv_fail_retry(error, ret, str, env, errmsg); if (TYPE(rescue) == T_ARRAY) { if ((len = RARRAY(rescue)->len) > 0) rb_str_concat(ret, RARRAY(rescue)->ptr[0]); if (len > 1 && !NIL_P(str = RARRAY(rescue)->ptr[1])) { StringValue(str); inlen = length = RSTRING(str)->len; instart = inptr = RSTRING(str)->ptr; continue; } } else if (!NIL_P(rescue)) { rb_str_concat(ret, rescue); } break; } } while (inlen > 0); if (!ret) ret = rb_str_derive(str, instart, inptr - instart); else if (inptr > instart) rb_str_cat(ret, instart, inptr - instart); return ret; } static VALUE iconv_s_allocate #ifdef HAVE_PROTOTYPES (VALUE klass) #else /* HAVE_PROTOTYPES */ (klass) VALUE klass; #endif /* HAVE_PROTOTYPES */ { return Data_Wrap_Struct(klass, 0, ICONV_FREE, 0); } /* * Document-method: new * call-seq: Iconv.new(to, from) * * Creates new code converter from a coding-system designated with +from+ * to another one designated with +to+. * * === Parameters * * +to+:: encoding name for destination * +from+:: encoding name for source * * === Exceptions * * TypeError:: if +to+ or +from+ aren't String * InvalidEncoding:: if designated converter couldn't find out * SystemCallError:: if iconv_open(3) fails */ static VALUE iconv_initialize #ifdef HAVE_PROTOTYPES (VALUE self, VALUE to, VALUE from) #else /* HAVE_PROTOTYPES */ (self, to, from) VALUE self; VALUE to; VALUE from; #endif /* HAVE_PROTOTYPES */ { iconv_free(check_iconv(self)); DATA_PTR(self) = NULL; DATA_PTR(self) = (void *)ICONV2VALUE(iconv_create(to, from)); return self; } /* * Document-method: open * call-seq: Iconv.open(to, from) { |iconv| ... } * * Equivalent to Iconv.new except that when it is called with a block, it * yields with the new instance and closes it, and returns the result which * returned from the block. */ static VALUE iconv_s_open #ifdef HAVE_PROTOTYPES (VALUE self, VALUE to, VALUE from) #else /* HAVE_PROTOTYPES */ (self, to, from) VALUE self; VALUE to; VALUE from; #endif /* HAVE_PROTOTYPES */ { VALUE cd = ICONV2VALUE(iconv_create(to, from)); self = Data_Wrap_Struct(self, NULL, ICONV_FREE, (void *)cd); if (rb_block_given_p()) { return rb_ensure(rb_yield, self, (VALUE(*)())iconv_finish, self); } else { return self; } } static VALUE iconv_s_convert #ifdef HAVE_PROTOTYPES (struct iconv_env_t* env) #else /* HAVE_PROTOTYPES */ (env) struct iconv_env_t *env; #endif /* HAVE_PROTOTYPES */ { VALUE last = 0; for (; env->argc > 0; --env->argc, ++env->argv) { VALUE s = iconv_convert(env->cd, last = *(env->argv), 0, -1, env); env->append(env->ret, s); } if (!NIL_P(last)) { VALUE s = iconv_convert(env->cd, Qnil, 0, 0, env); if (RSTRING(s)->len) env->append(env->ret, s); } return env->ret; } /* * Document-method: Iconv::iconv * call-seq: Iconv.iconv(to, from, *strs) * * Shorthand for * Iconv.open(to, from) { |cd| * (strs + [nil]).collect { |s| cd.iconv(s) } * } * * === Parameters * * to, from:: see Iconv.new * strs:: strings to be converted * * === Exceptions * * Exceptions thrown by Iconv.new, Iconv.open and Iconv#iconv. */ static VALUE iconv_s_iconv #ifdef HAVE_PROTOTYPES (int argc, VALUE *argv, VALUE self) #else /* HAVE_PROTOTYPES */ (argc, argv, self) int argc; VALUE *argv; VALUE self; #endif /* HAVE_PROTOTYPES */ { struct iconv_env_t arg; if (argc < 2) /* needs `to' and `from' arguments at least */ rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, 2); arg.argc = argc -= 2; arg.argv = argv + 2; arg.append = rb_ary_push; arg.ret = rb_ary_new2(argc); arg.cd = iconv_create(argv[0], argv[1]); return rb_ensure(iconv_s_convert, (VALUE)&arg, iconv_free, ICONV2VALUE(arg.cd)); } /* * Document-method: Iconv::conv * call-seq: Iconv.conv(to, from, str) * * Shorthand for * Iconv.iconv(to, from, str).join * See Iconv.iconv. */ static VALUE iconv_s_conv #ifdef HAVE_PROTOTYPES (VALUE self, VALUE to, VALUE from, VALUE str) #else /* HAVE_PROTOTYPES */ (self, to, from, str) VALUE self, to, from, str; #endif /* HAVE_PROTOTYPES */ { struct iconv_env_t arg; arg.argc = 1; arg.argv = &str; arg.append = rb_str_append; arg.ret = rb_str_new(0, 0); arg.cd = iconv_create(to, from); return rb_ensure(iconv_s_convert, (VALUE)&arg, iconv_free, ICONV2VALUE(arg.cd)); } /* * Document-method: close * * Finishes conversion. * * After calling this, calling Iconv#iconv will cause an exception, but * multiple calls of #close are guaranteed to end successfully. * * Returns a string containing the byte sequence to change the output buffer to * its initial shift state. */ static VALUE iconv_init_state #ifdef HAVE_PROTOTYPES (VALUE cd) #else /* HAVE_PROTOTYPES */ (cd) VALUE cd; #endif /* HAVE_PROTOTYPES */ { return iconv_convert(VALUE2ICONV(cd), Qnil, 0, 0, NULL); } static VALUE iconv_finish #ifdef HAVE_PROTOTYPES (VALUE self) #else /* HAVE_PROTOTYPES */ (self) VALUE self; #endif /* HAVE_PROTOTYPES */ { VALUE cd = check_iconv(self); if (!cd) return Qnil; DATA_PTR(self) = NULL; return rb_ensure(iconv_init_state, cd, iconv_free, cd); } /* * Document-method: Iconv#iconv * call-seq: iconv(str, start=0, length=-1) * * Converts string and returns the result. * * If +str+ is a String, converts str[start, length] and returns the converted string. * * If +str+ is +nil+, places converter itself into initial shift state and * just returns a string containing the byte sequence to change the output * buffer to its initial shift state. * * Otherwise, raises an exception. * * === Parameters * * str:: string to be converted, or nil * start:: starting offset * length:: conversion length; nil or -1 means whole the string from start * * === Exceptions * * * IconvIllegalSequence * * IconvInvalidCharacter * * IconvOutOfRange * * === Examples * * See the Iconv documentation. */ static VALUE iconv_iconv #ifdef HAVE_PROTOTYPES (int argc, VALUE *argv, VALUE self) #else /* HAVE_PROTOTYPES */ (argc, argv, self) int argc; VALUE *argv; VALUE self; #endif /* HAVE_PROTOTYPES */ { VALUE str, n1, n2; VALUE cd = check_iconv(self); long start = 0, length = 0, slen = 0; rb_scan_args(argc, argv, "12", &str, &n1, &n2); if (!NIL_P(str)) slen = RSTRING_LEN(StringValue(str)); if (argc != 2 || !RTEST(rb_range_beg_len(n1, &start, &length, slen, 0))) { if (NIL_P(n1) || ((start = NUM2LONG(n1)) < 0 ? (start += slen) >= 0 : start < slen)) { if (NIL_P(n2)) { length = -1; } else if ((length = NUM2LONG(n2)) >= slen - start) { length = slen - start; } } } return iconv_convert(VALUE2ICONV(cd), str, start, length, NULL); } /* * Document-class: Iconv::Failure * * Base attributes for Iconv exceptions. */ /* * Document-method: success * call-seq: success * * Returns string(s) translated successfully until the exception occurred. * * In the case of failure occurred within Iconv.iconv, returned * value is an array of strings translated successfully preceding * failure and the last element is string on the way. */ static VALUE iconv_failure_success #ifdef HAVE_PROTOTYPES (VALUE self) #else /* HAVE_PROTOTYPES */ (self) VALUE self; #endif /* HAVE_PROTOTYPES */ { return rb_attr_get(self, rb_success); } /* * Document-method: failed * call-seq: failed * * Returns substring of the original string passed to Iconv that starts at the * character caused the exception. */ static VALUE iconv_failure_failed #ifdef HAVE_PROTOTYPES (VALUE self) #else /* HAVE_PROTOTYPES */ (self) VALUE self; #endif /* HAVE_PROTOTYPES */ { return rb_attr_get(self, rb_failed); } /* * Document-method: inspect * call-seq: inspect * * Returns inspected string like as: #<_class_: _success_, _failed_> */ static VALUE iconv_failure_inspect #ifdef HAVE_PROTOTYPES (VALUE self) #else /* HAVE_PROTOTYPES */ (self) VALUE self; #endif /* HAVE_PROTOTYPES */ { const char *cname = rb_class2name(CLASS_OF(self)); VALUE success = rb_attr_get(self, rb_success); VALUE failed = rb_attr_get(self, rb_failed); VALUE str = rb_str_buf_cat2(rb_str_new2("#<"), cname); str = rb_str_buf_cat(str, ": ", 2); str = rb_str_buf_append(str, rb_inspect(success)); str = rb_str_buf_cat(str, ", ", 2); str = rb_str_buf_append(str, rb_inspect(failed)); return rb_str_buf_cat(str, ">", 1); } /* * Document-class: Iconv::InvalidEncoding * * Requested coding-system is not available on this system. */ /* * Document-class: Iconv::IllegalSequence * * Input conversion stopped due to an input byte that does not belong to * the input codeset, or the output codeset does not contain the * character. */ /* * Document-class: Iconv::InvalidCharacter * * Input conversion stopped due to an incomplete character or shift * sequence at the end of the input buffer. */ /* * Document-class: Iconv::OutOfRange * * Iconv library internal error. Must not occur. */ /* * Document-class: Iconv::BrokenLibrary * * Detected a bug of underlying iconv(3) libray. * * returns an error without setting errno properly */ void Init_iconv _((void)) { VALUE rb_cIconv = rb_define_class("Iconv", rb_cData); rb_define_alloc_func(rb_cIconv, iconv_s_allocate); rb_define_singleton_method(rb_cIconv, "open", iconv_s_open, 2); rb_define_singleton_method(rb_cIconv, "iconv", iconv_s_iconv, -1); rb_define_singleton_method(rb_cIconv, "conv", iconv_s_conv, 3); rb_define_method(rb_cIconv, "initialize", iconv_initialize, 2); rb_define_method(rb_cIconv, "close", iconv_finish, 0); rb_define_method(rb_cIconv, "iconv", iconv_iconv, -1); rb_eIconvFailure = rb_define_module_under(rb_cIconv, "Failure"); rb_define_method(rb_eIconvFailure, "initialize", iconv_failure_initialize, 3); rb_define_method(rb_eIconvFailure, "success", iconv_failure_success, 0); rb_define_method(rb_eIconvFailure, "failed", iconv_failure_failed, 0); rb_define_method(rb_eIconvFailure, "inspect", iconv_failure_inspect, 0); rb_eIconvInvalidEncoding = rb_define_class_under(rb_cIconv, "InvalidEncoding", rb_eArgError); rb_eIconvIllegalSeq = rb_define_class_under(rb_cIconv, "IllegalSequence", rb_eArgError); rb_eIconvInvalidChar = rb_define_class_under(rb_cIconv, "InvalidCharacter", rb_eArgError); rb_eIconvOutOfRange = rb_define_class_under(rb_cIconv, "OutOfRange", rb_eRuntimeError); rb_eIconvBrokenLibrary = rb_define_class_under(rb_cIconv, "BrokenLibrary", rb_eRuntimeError); rb_include_module(rb_eIconvInvalidEncoding, rb_eIconvFailure); rb_include_module(rb_eIconvIllegalSeq, rb_eIconvFailure); rb_include_module(rb_eIconvInvalidChar, rb_eIconvFailure); rb_include_module(rb_eIconvOutOfRange, rb_eIconvFailure); rb_include_module(rb_eIconvBrokenLibrary, rb_eIconvFailure); rb_success = rb_intern("success"); rb_failed = rb_intern("failed"); rb_gc_register_address(&charset_map); charset_map = rb_hash_new(); rb_define_singleton_method(rb_cIconv, "charset_map", charset_map_get, 0); } ================================================ FILE: ext/io/wait/.cvsignore ================================================ Makefile mkmf.log ================================================ FILE: ext/io/wait/extconf.rb ================================================ require 'mkmf' target = "io/wait" unless macro_defined?("DOSISH", "#include ") fionread = %w[sys/ioctl.h sys/filio.h].find do |h| have_macro("FIONREAD", h) end if fionread $defs << "-DFIONREAD_HEADER=\"<#{fionread}>\"" create_makefile(target) end else if have_func("rb_w32_ioctlsocket", "ruby.h") have_func("rb_w32_is_socket", "ruby.h") create_makefile(target) end end ================================================ FILE: ext/io/wait/lib/nonblock.rb ================================================ require "fcntl" class IO def nonblock? (fcntl(Fcntl::F_GETFL) & File::NONBLOCK) != 0 end def nonblock=(nb) f = fcntl(Fcntl::F_GETFL) if nb f |= File::NONBLOCK else f &= ~File::NONBLOCK end fcntl(Fcntl::F_SETFL, f) end def nonblock(nb = true) nb, self.nonblock = nonblock?, nb yield ensure self.nonblock = nb end end if defined?(Fcntl::F_GETFL) ================================================ FILE: ext/io/wait/wait.c ================================================ /********************************************************************** io/wait.c - $Author$ $Date$ created at: Tue Aug 28 09:08:06 JST 2001 All the files in this distribution are covered under the Ruby's license (see the file COPYING). **********************************************************************/ #include "ruby.h" #include "rubyio.h" #include #if defined(FIONREAD_HEADER) #include FIONREAD_HEADER #endif #ifdef HAVE_RB_W32_IOCTLSOCKET #define ioctl ioctlsocket #define ioctl_arg u_long #define ioctl_arg2num(i) ULONG2NUM(i) #else #define ioctl_arg int #define ioctl_arg2num(i) INT2NUM(i) #endif #ifdef HAVE_RB_W32_IS_SOCKET #define FIONREAD_POSSIBLE_P(fd) rb_w32_is_socket(fd) #else #define FIONREAD_POSSIBLE_P(fd) ((fd),Qtrue) #endif static VALUE io_ready_p _((VALUE io)); static VALUE io_wait _((int argc, VALUE *argv, VALUE io)); void Init_wait _((void)); EXTERN struct timeval rb_time_interval _((VALUE time)); /* =begin = IO wait methods. =end */ /* =begin --- IO#ready? returns non-nil if input available without blocking, or nil. =end */ static VALUE io_ready_p(io) VALUE io; { rb_io_t *fptr; FILE *fp; ioctl_arg n; GetOpenFile(io, fptr); rb_io_check_readable(fptr); if (!FIONREAD_POSSIBLE_P(fileno(fptr->f))) return Qfalse; fp = fptr->f; if (feof(fp)) return Qfalse; if (rb_read_pending(fp)) return Qtrue; if (ioctl(fileno(fp), FIONREAD, &n)) rb_sys_fail(0); if (n > 0) return ioctl_arg2num(n); return Qnil; } /* =begin --- IO#wait([timeout]) waits until input available or timed out and returns self, or nil when EOF reached. =end */ static VALUE io_wait(argc, argv, io) int argc; VALUE *argv; VALUE io; { rb_io_t *fptr; fd_set rd; FILE *fp; int fd; ioctl_arg n; VALUE timeout; struct timeval *tp, timerec; GetOpenFile(io, fptr); rb_io_check_readable(fptr); rb_scan_args(argc, argv, "01", &timeout); if (NIL_P(timeout)) { tp = 0; } else { timerec = rb_time_interval(timeout); tp = &timerec; } fp = fptr->f; if (feof(fp)) return Qfalse; if (rb_read_pending(fp)) return Qtrue; fd = fileno(fp); FD_ZERO(&rd); FD_SET(fd, &rd); if (rb_thread_select(fd + 1, &rd, NULL, NULL, tp) < 0) rb_sys_fail(0); rb_io_check_closed(fptr); if (!FIONREAD_POSSIBLE_P(fileno(fptr->f))) return Qfalse; if (ioctl(fileno(fp), FIONREAD, &n)) rb_sys_fail(0); if (n > 0) return io; return Qnil; } void Init_wait() { rb_define_method(rb_cIO, "ready?", io_ready_p, 0); rb_define_method(rb_cIO, "wait", io_wait, -1); } ================================================ FILE: ext/nkf/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/nkf/depend ================================================ nkf.o : nkf.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h $(srcdir)/nkf-utf8/nkf.c $(srcdir)/nkf-utf8/utf8tbl.c $(srcdir)/nkf-utf8/config.h ================================================ FILE: ext/nkf/extconf.rb ================================================ require 'mkmf' create_makefile('nkf') ================================================ FILE: ext/nkf/lib/kconv.rb ================================================ # # kconv.rb - Kanji Converter. # # $Id$ # # ---- # # kconv.rb implements the Kconv class for Kanji Converter. Additionally, # some methods in String classes are added to allow easy conversion. # require 'nkf' # # Kanji Converter for Ruby. # module Kconv # # Public Constants # #Constant of Encoding # Auto-Detect AUTO = NKF::AUTO # ISO-2022-JP JIS = NKF::JIS # EUC-JP EUC = NKF::EUC # Shift_JIS SJIS = NKF::SJIS # BINARY BINARY = NKF::BINARY # NOCONV NOCONV = NKF::NOCONV # ASCII ASCII = NKF::ASCII # UTF-8 UTF8 = NKF::UTF8 # UTF-16 UTF16 = NKF::UTF16 # UTF-32 UTF32 = NKF::UTF32 # UNKNOWN UNKNOWN = NKF::UNKNOWN # # Private Constants # # Revision of kconv.rb REVISION = %q$Revision$ #Regexp of Encoding # Regexp of Shift_JIS string (private constant) RegexpShiftjis = /\A(?: [\x00-\x7f\xa1-\xdf] | [\x81-\x9f\xe0-\xfc][\x40-\x7e\x80-\xfc] )*\z/nx # Regexp of EUC-JP string (private constant) RegexpEucjp = /\A(?: [\x00-\x7f] | \x8e [\xa1-\xdf] | \x8f [\xa1-\xfe] [\xa1-\xfe] | [\xa1-\xfe] [\xa1-\xfe] )*\z/nx # Regexp of UTF-8 string (private constant) RegexpUtf8 = /\A(?: [\x00-\x7f] | [\xc2-\xdf] [\x80-\xbf] | \xe0 [\xa0-\xbf] [\x80-\xbf] | [\xe1-\xef] [\x80-\xbf] [\x80-\xbf] | \xf0 [\x90-\xbf] [\x80-\xbf] [\x80-\xbf] | [\xf1-\xf3] [\x80-\xbf] [\x80-\xbf] [\x80-\xbf] | \xf4 [\x80-\x8f] [\x80-\xbf] [\x80-\xbf] )*\z/nx # # Public Methods # # call-seq: # Kconv.kconv(str, out_code, in_code = Kconv::AUTO) # # Convert str to out_code. # out_code and in_code are given as constants of Kconv. # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want to decode them, use NKF.nkf. def kconv(str, out_code, in_code = AUTO) opt = '-' case in_code when ::NKF::JIS opt << 'J' when ::NKF::EUC opt << 'E' when ::NKF::SJIS opt << 'S' when ::NKF::UTF8 opt << 'W' when ::NKF::UTF16 opt << 'W16' end case out_code when ::NKF::JIS opt << 'j' when ::NKF::EUC opt << 'e' when ::NKF::SJIS opt << 's' when ::NKF::UTF8 opt << 'w' when ::NKF::UTF16 opt << 'w16' when ::NKF::NOCONV return str end opt = '' if opt == '-' ::NKF::nkf(opt, str) end module_function :kconv # # Encode to # # call-seq: # Kconv.tojis(str) -> string # # Convert str to ISO-2022-JP # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-jxm0', str). def tojis(str) ::NKF::nkf('-jm', str) end module_function :tojis # call-seq: # Kconv.toeuc(str) -> string # # Convert str to EUC-JP # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-exm0', str). def toeuc(str) ::NKF::nkf('-em', str) end module_function :toeuc # call-seq: # Kconv.tosjis(str) -> string # # Convert str to Shift_JIS # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-sxm0', str). def tosjis(str) ::NKF::nkf('-sm', str) end module_function :tosjis # call-seq: # Kconv.toutf8(str) -> string # # Convert str to UTF-8 # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-wxm0', str). def toutf8(str) ::NKF::nkf('-wm', str) end module_function :toutf8 # call-seq: # Kconv.toutf16(str) -> string # # Convert str to UTF-16 # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-w16xm0', str). def toutf16(str) ::NKF::nkf('-w16m', str) end module_function :toutf16 # # guess # # call-seq: # Kconv.guess(str) -> integer # # Guess input encoding by NKF.guess2 def guess(str) ::NKF::guess(str) end module_function :guess # call-seq: # Kconv.guess_old(str) -> integer # # Guess input encoding by NKF.guess1 def guess_old(str) ::NKF::guess1(str) end module_function :guess_old # # isEncoding # # call-seq: # Kconv.iseuc(str) -> obj or nil # # Returns whether input encoding is EUC-JP or not. # # *Note* don't expect this return value is MatchData. def iseuc(str) RegexpEucjp.match( str ) end module_function :iseuc # call-seq: # Kconv.issjis(str) -> obj or nil # # Returns whether input encoding is Shift_JIS or not. # # *Note* don't expect this return value is MatchData. def issjis(str) RegexpShiftjis.match( str ) end module_function :issjis # call-seq: # Kconv.isutf8(str) -> obj or nil # # Returns whether input encoding is UTF-8 or not. # # *Note* don't expect this return value is MatchData. def isutf8(str) RegexpUtf8.match( str ) end module_function :isutf8 end class String # call-seq: # String#kconv(out_code, in_code = Kconv::AUTO) # # Convert self to out_code. # out_code and in_code are given as constants of Kconv. # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want to decode them, use NKF.nkf. def kconv(out_code, in_code=Kconv::AUTO) Kconv::kconv(self, out_code, in_code) end # # to Encoding # # call-seq: # String#tojis -> string # # Convert self to ISO-2022-JP # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-jxm0', str). def tojis; Kconv.tojis(self) end # call-seq: # String#toeuc -> string # # Convert self to EUC-JP # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-exm0', str). def toeuc; Kconv.toeuc(self) end # call-seq: # String#tosjis -> string # # Convert self to Shift_JIS # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-sxm0', str). def tosjis; Kconv.tosjis(self) end # call-seq: # String#toutf8 -> string # # Convert self to UTF-8 # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-wxm0', str). def toutf8; Kconv.toutf8(self) end # call-seq: # String#toutf16 -> string # # Convert self to UTF-16 # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-w16xm0', str). def toutf16; Kconv.toutf16(self) end # # is Encoding # # call-seq: # String#iseuc -> obj or nil # # Returns whether self's encoding is EUC-JP or not. # # *Note* don't expect this return value is MatchData. def iseuc; Kconv.iseuc(self) end # call-seq: # String#issjis -> obj or nil # # Returns whether self's encoding is Shift_JIS or not. # # *Note* don't expect this return value is MatchData. def issjis; Kconv.issjis(self) end # call-seq: # String#isutf8 -> obj or nil # # Returns whether self's encoding is UTF-8 or not. # # *Note* don't expect this return value is MatchData. def isutf8; Kconv.isutf8(self) end end ================================================ FILE: ext/nkf/nkf-utf8/nkf.c ================================================ /** Network Kanji Filter. (PDS Version) ************************************************************************ ** Copyright (C) 1987, Fujitsu LTD. (Itaru ICHIKAWA) ** $BO"Mm@h!'(B $B!J3t!KIY;NDL8&5f=j!!%=%U%H#38&!!;T@n!!;j(B ** $B!J(BE-Mail Address: ichikawa@flab.fujitsu.co.jp$B!K(B ** Copyright (C) 1996,1998 ** Copyright (C) 2002 ** $BO"Mm@h!'(B $BN05eBg3X>pJs9)3X2J(B $B2OLn(B $B??<#(B mime/X0208 support ** $B!J(BE-Mail Address: kono@ie.u-ryukyu.ac.jp$B!K(B ** $BO"Mm@h!'(B COW for DOS & Win16 & Win32 & OS/2 ** $B!J(BE-Mail Address: GHG00637@niftyserve.or.p$B!K(B ** ** $B$3$N%=!<%9$N$$$+$J$kJ#e5-$KH?$7$J$$HO0O$G5v2D$7$^$9!#(B ** $B%P%$%J%j$NG[I[$N:]$K$O(Bversion message$B$rJ]B8$9$k$3$H$r>r7o$H$7$^$9!#(B ** $B$3$N%W%m%0%i%`$K$D$$$F$OFC$K2?$NJ]>Z$b$7$J$$!"0-$7$+$i$:!#(B ** ** Everyone is permitted to do anything on this program ** including copying, modifying, improving, ** as long as you don't try to pretend that you wrote it. ** i.e., the above copyright notice has to appear in all copies. ** Binary distribution requires original version messages. ** You don't have to ask before copying, redistribution or publishing. ** THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. ***********************************************************************/ /*********************************************************************** ** UTF-8 $B%5%]!<%H$K$D$$$F(B ** $B=>Mh$N(B nkf $B$HF~$l$+$($F$=$N$^$^;H$($k$h$&$K$J$C$F$$$^$9(B ** nkf -e $B$J$I$H$7$F5/F0$9$k$H!"<+F0H=JL$G(B UTF-8 $B$HH=Dj$5$l$l$P!"(B ** $B$=$N$^$^(B euc-jp $B$KJQ49$5$l$^$9(B ** ** $B$^$@%P%0$,$"$k2DG=@-$,9b$$$G$9!#(B ** ($BFC$K<+F0H=JL!"%3!<%I:.:_!"%(%i!<=hM}7O(B) ** ** $B2?$+LdBj$r8+$D$1$?$i!"(B ** E-Mail: furukawa@tcp-ip.or.jp ** $B$^$G8fO"Mm$r$*4j$$$7$^$9!#(B ***********************************************************************/ /* $Id$ */ #define NKF_VERSION "2.0.8" #define NKF_RELEASE_DATE "2008-11-08" #include "config.h" #include "utf8tbl.h" #define COPY_RIGHT \ "Copyright (C) 1987, FUJITSU LTD. (I.Ichikawa),2000 S. Kono, COW\n" \ "Copyright (C) 2002-2008 Kono, Furukawa, Naruse, mastodon" /* ** ** ** ** USAGE: nkf [flags] [file] ** ** Flags: ** b Output is buffered (DEFAULT) ** u Output is unbuffered ** ** t no operation ** ** j Output code is JIS 7 bit (DEFAULT SELECT) ** s Output code is MS Kanji (DEFAULT SELECT) ** e Output code is AT&T JIS (DEFAULT SELECT) ** w Output code is AT&T JIS (DEFAULT SELECT) ** l Output code is JIS 7bit and ISO8859-1 Latin-1 ** ** m MIME conversion for ISO-2022-JP ** I Convert non ISO-2022-JP charactor to GETA by Pekoe ** i_ Output sequence to designate JIS-kanji (DEFAULT_J) ** o_ Output sequence to designate single-byte roman characters (DEFAULT_R) ** M MIME output conversion ** ** r {de/en}crypt ROT13/47 ** ** v display Version ** ** T Text mode output (for MS-DOS) ** ** x Do not convert X0201 kana into X0208 ** Z Convert X0208 alphabet to ASCII ** ** f60 fold option ** ** m MIME decode ** B try to fix broken JIS, missing Escape ** B[1-9] broken level ** ** O Output to 'nkf.out' file or last file name ** d Delete \r in line feed ** c Add \r in line feed ** -- other long option ** -- ignore following option (don't use with -O ) ** **/ #if (defined(__TURBOC__) || defined(_MSC_VER) || defined(LSI_C) || defined(__MINGW32__) || defined(__EMX__) || defined(__MSDOS__) || defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__)) && !defined(MSDOS) #define MSDOS #if (defined(__Win32__) || defined(_WIN32)) && !defined(__WIN32__) #define __WIN32__ #endif #endif #ifdef PERL_XS #undef OVERWRITE #endif #ifndef PERL_XS #include #endif #include #include #if defined(MSDOS) || defined(__OS2__) #include #include #if defined(_MSC_VER) || defined(__WATCOMC__) #define mktemp _mktemp #endif #endif #ifdef MSDOS #ifdef LSI_C #define setbinmode(fp) fsetbin(fp) #elif defined(__DJGPP__) #include #define setbinmode(fp) djgpp_setbinmode(fp) #else /* Microsoft C, Turbo C */ #define setbinmode(fp) setmode(fileno(fp), O_BINARY) #endif #else /* UNIX */ #define setbinmode(fp) #endif #if defined(__DJGPP__) void djgpp_setbinmode(FILE *fp) { /* we do not use libc's setmode(), which changes COOKED/RAW mode in device. */ int fd, m; fd = fileno(fp); m = (__file_handle_modes[fd] & (~O_TEXT)) | O_BINARY; __file_handle_set(fd, m); } #endif #ifdef _IOFBF /* SysV and MSDOS, Windows */ #define setvbuffer(fp, buf, size) setvbuf(fp, buf, _IOFBF, size) #else /* BSD */ #define setvbuffer(fp, buf, size) setbuffer(fp, buf, size) #endif /*Borland C++ 4.5 EasyWin*/ #if defined(__TURBOC__) && defined(_Windows) && !defined(__WIN32__) /*Easy Win */ #define EASYWIN #ifndef __WIN16__ #define __WIN16__ #endif #include #endif #ifdef OVERWRITE /* added by satoru@isoternet.org */ #if defined(__EMX__) #include #endif #include #if !defined(MSDOS) || defined(__DJGPP__) /* UNIX, djgpp */ #include #if defined(__WATCOMC__) #include #else #include #endif #else /* defined(MSDOS) */ #ifdef __WIN32__ #ifdef __BORLANDC__ /* BCC32 */ #include #else /* !defined(__BORLANDC__) */ #include #endif /* (__BORLANDC__) */ #else /* !defined(__WIN32__) */ #if defined(_MSC_VER) || defined(__MINGW32__) || defined(__WATCOMC__) || defined(__OS2__) || defined(__EMX__) || defined(__IBMC__) || defined(__IBMCPP__) /* VC++, MinGW, Watcom, emx+gcc, IBM VAC++ */ #include #elif defined(__TURBOC__) /* BCC */ #include #elif defined(LSI_C) /* LSI C */ #endif /* (__WIN32__) */ #endif #endif #endif #define FALSE 0 #define TRUE 1 /* state of output_mode and input_mode c2 0 means ASCII X0201 ISO8859_1 X0208 EOF all termination c1 32bit data */ #define ASCII 0 #define X0208 1 #define X0201 2 #define ISO8859_1 8 #define NO_X0201 3 #define X0212 0x2844 #define X0213_1 0x284F #define X0213_2 0x2850 /* Input Assumption */ #define JIS_INPUT 4 #define EUC_INPUT 16 #define SJIS_INPUT 5 #define LATIN1_INPUT 6 #define FIXED_MIME 7 #define STRICT_MIME 8 /* MIME ENCODE */ #define ISO2022JP 9 #define JAPANESE_EUC 10 #define SHIFT_JIS 11 #define UTF8 12 #define UTF8_INPUT 13 #define UTF16_INPUT 1015 #define UTF32_INPUT 1017 /* byte order */ #define ENDIAN_BIG 1234 #define ENDIAN_LITTLE 4321 #define ENDIAN_2143 2143 #define ENDIAN_3412 3412 #define WISH_TRUE 15 /* ASCII CODE */ #define BS 0x08 #define TAB 0x09 #define NL 0x0a #define CR 0x0d #define ESC 0x1b #define SPACE 0x20 #define AT 0x40 #define SSP 0xa0 #define DEL 0x7f #define SI 0x0f #define SO 0x0e #define SSO 0x8e #define SS3 0x8f #define is_alnum(c) \ (('a'<=c && c<='z')||('A'<= c && c<='Z')||('0'<=c && c<='9')) /* I don't trust portablity of toupper */ #define nkf_toupper(c) (('a'<=c && c<='z')?(c-('a'-'A')):c) #define nkf_isoctal(c) ('0'<=c && c<='7') #define nkf_isdigit(c) ('0'<=c && c<='9') #define nkf_isxdigit(c) (nkf_isdigit(c) || ('a'<=c && c<='f') || ('A'<=c && c <= 'F')) #define nkf_isblank(c) (c == SPACE || c == TAB) #define nkf_isspace(c) (nkf_isblank(c) || c == CR || c == NL) #define nkf_isalpha(c) (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) #define nkf_isalnum(c) (nkf_isdigit(c) || nkf_isalpha(c)) #define nkf_isprint(c) (' '<=c && c<='~') #define nkf_isgraph(c) ('!'<=c && c<='~') #define hex2bin(c) (('0'<=c&&c<='9') ? (c-'0') : \ ('A'<=c&&c<='F') ? (c-'A'+10) : \ ('a'<=c&&c<='f') ? (c-'a'+10) : 0 ) #define is_eucg3(c2) (((unsigned short)c2 >> 8) == SS3) #define CP932_TABLE_BEGIN 0xFA #define CP932_TABLE_END 0xFC #define CP932INV_TABLE_BEGIN 0xED #define CP932INV_TABLE_END 0xEE #define is_ibmext_in_sjis(c2) (CP932_TABLE_BEGIN <= c2 && c2 <= CP932_TABLE_END) #define HOLD_SIZE 1024 #if defined(INT_IS_SHORT) #define IOBUF_SIZE 2048 #else #define IOBUF_SIZE 16384 #endif #define DEFAULT_J 'B' #define DEFAULT_R 'B' #define SJ0162 0x00e1 /* 01 - 62 ku offset */ #define SJ6394 0x0161 /* 63 - 94 ku offset */ #define RANGE_NUM_MAX 18 #define GETA1 0x22 #define GETA2 0x2e #if defined(UTF8_OUTPUT_ENABLE) || defined(UTF8_INPUT_ENABLE) #define sizeof_euc_to_utf8_1byte 94 #define sizeof_euc_to_utf8_2bytes 94 #define sizeof_utf8_to_euc_C2 64 #define sizeof_utf8_to_euc_E5B8 64 #define sizeof_utf8_to_euc_2bytes 112 #define sizeof_utf8_to_euc_3bytes 16 #endif /* MIME preprocessor */ #ifdef EASYWIN /*Easy Win */ extern POINT _BufferSize; #endif struct input_code{ char *name; nkf_char stat; nkf_char score; nkf_char index; nkf_char buf[3]; void (*status_func)(struct input_code *, nkf_char); nkf_char (*iconv_func)(nkf_char c2, nkf_char c1, nkf_char c0); int _file_stat; }; static char *input_codename = ""; #ifndef PERL_XS static const char *CopyRight = COPY_RIGHT; #endif #if !defined(PERL_XS) && !defined(WIN32DLL) static nkf_char noconvert(FILE *f); #endif static void module_connection(void); static nkf_char kanji_convert(FILE *f); static nkf_char h_conv(FILE *f,nkf_char c2,nkf_char c1); static nkf_char push_hold_buf(nkf_char c2); static void set_iconv(nkf_char f, nkf_char (*iconv_func)(nkf_char c2,nkf_char c1,nkf_char c0)); static nkf_char s_iconv(nkf_char c2,nkf_char c1,nkf_char c0); static nkf_char s2e_conv(nkf_char c2, nkf_char c1, nkf_char *p2, nkf_char *p1); static nkf_char e_iconv(nkf_char c2,nkf_char c1,nkf_char c0); #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE) /* UCS Mapping * 0: Shift_JIS, eucJP-ascii * 1: eucJP-ms * 2: CP932, CP51932 */ #define UCS_MAP_ASCII 0 #define UCS_MAP_MS 1 #define UCS_MAP_CP932 2 static int ms_ucs_map_f = UCS_MAP_ASCII; #endif #ifdef UTF8_INPUT_ENABLE /* no NEC special, NEC-selected IBM extended and IBM extended characters */ static int no_cp932ext_f = FALSE; /* ignore ZERO WIDTH NO-BREAK SPACE */ static int no_best_fit_chars_f = FALSE; static int input_endian = ENDIAN_BIG; static nkf_char unicode_subchar = '?'; /* the regular substitution character */ static void nkf_each_char_to_hex(void (*f)(nkf_char c2,nkf_char c1), nkf_char c); static void encode_fallback_html(nkf_char c); static void encode_fallback_xml(nkf_char c); static void encode_fallback_java(nkf_char c); static void encode_fallback_perl(nkf_char c); static void encode_fallback_subchar(nkf_char c); static void (*encode_fallback)(nkf_char c) = NULL; static nkf_char w2e_conv(nkf_char c2,nkf_char c1,nkf_char c0,nkf_char *p2,nkf_char *p1); static nkf_char w_iconv(nkf_char c2,nkf_char c1,nkf_char c0); static nkf_char w_iconv16(nkf_char c2,nkf_char c1,nkf_char c0); static nkf_char w_iconv32(nkf_char c2,nkf_char c1,nkf_char c0); static nkf_char unicode_to_jis_common(nkf_char c2,nkf_char c1,nkf_char c0,nkf_char *p2,nkf_char *p1); static nkf_char w_iconv_common(nkf_char c1,nkf_char c0,const unsigned short *const *pp,nkf_char psize,nkf_char *p2,nkf_char *p1); static void w16w_conv(nkf_char val, nkf_char *p2, nkf_char *p1, nkf_char *p0); static nkf_char ww16_conv(nkf_char c2, nkf_char c1, nkf_char c0); static nkf_char w16e_conv(nkf_char val,nkf_char *p2,nkf_char *p1); static void w_status(struct input_code *, nkf_char); #endif #ifdef UTF8_OUTPUT_ENABLE static int output_bom_f = FALSE; static int output_endian = ENDIAN_BIG; static nkf_char e2w_conv(nkf_char c2,nkf_char c1); static void w_oconv(nkf_char c2,nkf_char c1); static void w_oconv16(nkf_char c2,nkf_char c1); static void w_oconv32(nkf_char c2,nkf_char c1); #endif static void e_oconv(nkf_char c2,nkf_char c1); static nkf_char e2s_conv(nkf_char c2, nkf_char c1, nkf_char *p2, nkf_char *p1); static void s_oconv(nkf_char c2,nkf_char c1); static void j_oconv(nkf_char c2,nkf_char c1); static void fold_conv(nkf_char c2,nkf_char c1); static void cr_conv(nkf_char c2,nkf_char c1); static void z_conv(nkf_char c2,nkf_char c1); static void rot_conv(nkf_char c2,nkf_char c1); static void hira_conv(nkf_char c2,nkf_char c1); static void base64_conv(nkf_char c2,nkf_char c1); static void iso2022jp_check_conv(nkf_char c2,nkf_char c1); static void no_connection(nkf_char c2,nkf_char c1); static nkf_char no_connection2(nkf_char c2,nkf_char c1,nkf_char c0); static void code_score(struct input_code *ptr); static void code_status(nkf_char c); static void std_putc(nkf_char c); static nkf_char std_getc(FILE *f); static nkf_char std_ungetc(nkf_char c,FILE *f); static nkf_char broken_getc(FILE *f); static nkf_char broken_ungetc(nkf_char c,FILE *f); static nkf_char mime_begin(FILE *f); static nkf_char mime_getc(FILE *f); static nkf_char mime_ungetc(nkf_char c,FILE *f); static void switch_mime_getc(void); static void unswitch_mime_getc(void); static nkf_char mime_begin_strict(FILE *f); static nkf_char mime_getc_buf(FILE *f); static nkf_char mime_ungetc_buf(nkf_char c,FILE *f); static nkf_char mime_integrity(FILE *f,const unsigned char *p); static nkf_char base64decode(nkf_char c); static void mime_prechar(nkf_char c2, nkf_char c1); static void mime_putc(nkf_char c); static void open_mime(nkf_char c); static void close_mime(void); static void eof_mime(void); static void mimeout_addchar(nkf_char c); #ifndef PERL_XS static void usage(void); static void version(void); #endif static void options(unsigned char *c); #if defined(PERL_XS) || defined(WIN32DLL) static void reinit(void); #endif /* buffers */ #if !defined(PERL_XS) && !defined(WIN32DLL) static unsigned char stdibuf[IOBUF_SIZE]; static unsigned char stdobuf[IOBUF_SIZE]; #endif static unsigned char hold_buf[HOLD_SIZE*2]; static int hold_count = 0; /* MIME preprocessor fifo */ #define MIME_BUF_SIZE (1024) /* 2^n ring buffer */ #define MIME_BUF_MASK (MIME_BUF_SIZE-1) #define Fifo(n) mime_buf[(n)&MIME_BUF_MASK] static unsigned char mime_buf[MIME_BUF_SIZE]; static unsigned int mime_top = 0; static unsigned int mime_last = 0; /* decoded */ static unsigned int mime_input = 0; /* undecoded */ static nkf_char (*mime_iconv_back)(nkf_char c2,nkf_char c1,nkf_char c0) = NULL; /* flags */ static int unbuf_f = FALSE; static int estab_f = FALSE; static int nop_f = FALSE; static int binmode_f = TRUE; /* binary mode */ static int rot_f = FALSE; /* rot14/43 mode */ static int hira_f = FALSE; /* hira/kata henkan */ static int input_f = FALSE; /* non fixed input code */ static int alpha_f = FALSE; /* convert JIx0208 alphbet to ASCII */ static int mime_f = STRICT_MIME; /* convert MIME B base64 or Q */ static int mime_decode_f = FALSE; /* mime decode is explicitly on */ static int mimebuf_f = FALSE; /* MIME buffered input */ static int broken_f = FALSE; /* convert ESC-less broken JIS */ static int iso8859_f = FALSE; /* ISO8859 through */ static int mimeout_f = FALSE; /* base64 mode */ #if defined(MSDOS) || defined(__OS2__) static int x0201_f = TRUE; /* Assume JISX0201 kana */ #else static int x0201_f = NO_X0201; /* Assume NO JISX0201 */ #endif static int iso2022jp_f = FALSE; /* convert ISO-2022-JP */ #ifdef UNICODE_NORMALIZATION static int nfc_f = FALSE; static nkf_char (*i_nfc_getc)(FILE *) = std_getc; /* input of ugetc */ static nkf_char (*i_nfc_ungetc)(nkf_char c ,FILE *f) = std_ungetc; static nkf_char nfc_getc(FILE *f); static nkf_char nfc_ungetc(nkf_char c,FILE *f); #endif #ifdef INPUT_OPTION static int cap_f = FALSE; static nkf_char (*i_cgetc)(FILE *) = std_getc; /* input of cgetc */ static nkf_char (*i_cungetc)(nkf_char c ,FILE *f) = std_ungetc; static nkf_char cap_getc(FILE *f); static nkf_char cap_ungetc(nkf_char c,FILE *f); static int url_f = FALSE; static nkf_char (*i_ugetc)(FILE *) = std_getc; /* input of ugetc */ static nkf_char (*i_uungetc)(nkf_char c ,FILE *f) = std_ungetc; static nkf_char url_getc(FILE *f); static nkf_char url_ungetc(nkf_char c,FILE *f); #endif #if defined(INT_IS_SHORT) #define NKF_INT32_C(n) (n##L) #else #define NKF_INT32_C(n) (n) #endif #define PREFIX_EUCG3 NKF_INT32_C(0x8F00) #define CLASS_MASK NKF_INT32_C(0xFF000000) #define CLASS_UNICODE NKF_INT32_C(0x01000000) #define VALUE_MASK NKF_INT32_C(0x00FFFFFF) #define UNICODE_MAX NKF_INT32_C(0x0010FFFF) #define is_unicode_capsule(c) ((c & CLASS_MASK) == CLASS_UNICODE) #define is_unicode_bmp(c) ((c & VALUE_MASK) <= NKF_INT32_C(0xFFFF)) #ifdef NUMCHAR_OPTION static int numchar_f = FALSE; static nkf_char (*i_ngetc)(FILE *) = std_getc; /* input of ugetc */ static nkf_char (*i_nungetc)(nkf_char c ,FILE *f) = std_ungetc; static nkf_char numchar_getc(FILE *f); static nkf_char numchar_ungetc(nkf_char c,FILE *f); #endif #ifdef CHECK_OPTION static int noout_f = FALSE; static void no_putc(nkf_char c); static nkf_char debug_f = FALSE; static void debug(const char *str); static nkf_char (*iconv_for_check)(nkf_char c2,nkf_char c1,nkf_char c0) = 0; #endif static int guess_f = FALSE; #if !defined PERL_XS static void print_guessed_code(char *filename); #endif static void set_input_codename(char *codename); static int is_inputcode_mixed = FALSE; static int is_inputcode_set = FALSE; #ifdef EXEC_IO static int exec_f = 0; #endif #ifdef SHIFTJIS_CP932 /* invert IBM extended characters to others */ static int cp51932_f = FALSE; /* invert NEC-selected IBM extended characters to IBM extended characters */ static int cp932inv_f = TRUE; /* static nkf_char cp932_conv(nkf_char c2, nkf_char c1); */ #endif /* SHIFTJIS_CP932 */ #ifdef X0212_ENABLE static int x0212_f = FALSE; static nkf_char x0212_shift(nkf_char c); static nkf_char x0212_unshift(nkf_char c); #endif static int x0213_f = FALSE; static unsigned char prefix_table[256]; static void set_code_score(struct input_code *ptr, nkf_char score); static void clr_code_score(struct input_code *ptr, nkf_char score); static void status_disable(struct input_code *ptr); static void status_push_ch(struct input_code *ptr, nkf_char c); static void status_clear(struct input_code *ptr); static void status_reset(struct input_code *ptr); static void status_reinit(struct input_code *ptr); static void status_check(struct input_code *ptr, nkf_char c); static void e_status(struct input_code *, nkf_char); static void s_status(struct input_code *, nkf_char); struct input_code input_code_list[] = { {"EUC-JP", 0, 0, 0, {0, 0, 0}, e_status, e_iconv, 0}, {"Shift_JIS", 0, 0, 0, {0, 0, 0}, s_status, s_iconv, 0}, #ifdef UTF8_INPUT_ENABLE {"UTF-8", 0, 0, 0, {0, 0, 0}, w_status, w_iconv, 0}, {"UTF-16", 0, 0, 0, {0, 0, 0}, NULL, w_iconv16, 0}, {"UTF-32", 0, 0, 0, {0, 0, 0}, NULL, w_iconv32, 0}, #endif {0} }; static int mimeout_mode = 0; static int base64_count = 0; /* X0208 -> ASCII converter */ /* fold parameter */ static int f_line = 0; /* chars in line */ static int f_prev = 0; static int fold_preserve_f = FALSE; /* preserve new lines */ static int fold_f = FALSE; static int fold_len = 0; /* options */ static unsigned char kanji_intro = DEFAULT_J; static unsigned char ascii_intro = DEFAULT_R; /* Folding */ #define FOLD_MARGIN 10 #define DEFAULT_FOLD 60 static int fold_margin = FOLD_MARGIN; /* converters */ #ifdef DEFAULT_CODE_JIS # define DEFAULT_CONV j_oconv #endif #ifdef DEFAULT_CODE_SJIS # define DEFAULT_CONV s_oconv #endif #ifdef DEFAULT_CODE_EUC # define DEFAULT_CONV e_oconv #endif #ifdef DEFAULT_CODE_UTF8 # define DEFAULT_CONV w_oconv #endif /* process default */ static void (*output_conv)(nkf_char c2,nkf_char c1) = DEFAULT_CONV; static void (*oconv)(nkf_char c2,nkf_char c1) = no_connection; /* s_iconv or oconv */ static nkf_char (*iconv)(nkf_char c2,nkf_char c1,nkf_char c0) = no_connection2; static void (*o_zconv)(nkf_char c2,nkf_char c1) = no_connection; static void (*o_fconv)(nkf_char c2,nkf_char c1) = no_connection; static void (*o_crconv)(nkf_char c2,nkf_char c1) = no_connection; static void (*o_rot_conv)(nkf_char c2,nkf_char c1) = no_connection; static void (*o_hira_conv)(nkf_char c2,nkf_char c1) = no_connection; static void (*o_base64conv)(nkf_char c2,nkf_char c1) = no_connection; static void (*o_iso2022jp_check_conv)(nkf_char c2,nkf_char c1) = no_connection; /* static redirections */ static void (*o_putc)(nkf_char c) = std_putc; static nkf_char (*i_getc)(FILE *f) = std_getc; /* general input */ static nkf_char (*i_ungetc)(nkf_char c,FILE *f) =std_ungetc; static nkf_char (*i_bgetc)(FILE *) = std_getc; /* input of mgetc */ static nkf_char (*i_bungetc)(nkf_char c ,FILE *f) = std_ungetc; static void (*o_mputc)(nkf_char c) = std_putc ; /* output of mputc */ static nkf_char (*i_mgetc)(FILE *) = std_getc; /* input of mgetc */ static nkf_char (*i_mungetc)(nkf_char c ,FILE *f) = std_ungetc; /* for strict mime */ static nkf_char (*i_mgetc_buf)(FILE *) = std_getc; /* input of mgetc_buf */ static nkf_char (*i_mungetc_buf)(nkf_char c,FILE *f) = std_ungetc; /* Global states */ static int output_mode = ASCII, /* output kanji mode */ input_mode = ASCII, /* input kanji mode */ shift_mode = FALSE; /* TRUE shift out, or X0201 */ static int mime_decode_mode = FALSE; /* MIME mode B base64, Q hex */ /* X0201 / X0208 conversion tables */ /* X0201 kana conversion table */ /* 90-9F A0-DF */ static const unsigned char cv[]= { 0x21,0x21,0x21,0x23,0x21,0x56,0x21,0x57, 0x21,0x22,0x21,0x26,0x25,0x72,0x25,0x21, 0x25,0x23,0x25,0x25,0x25,0x27,0x25,0x29, 0x25,0x63,0x25,0x65,0x25,0x67,0x25,0x43, 0x21,0x3c,0x25,0x22,0x25,0x24,0x25,0x26, 0x25,0x28,0x25,0x2a,0x25,0x2b,0x25,0x2d, 0x25,0x2f,0x25,0x31,0x25,0x33,0x25,0x35, 0x25,0x37,0x25,0x39,0x25,0x3b,0x25,0x3d, 0x25,0x3f,0x25,0x41,0x25,0x44,0x25,0x46, 0x25,0x48,0x25,0x4a,0x25,0x4b,0x25,0x4c, 0x25,0x4d,0x25,0x4e,0x25,0x4f,0x25,0x52, 0x25,0x55,0x25,0x58,0x25,0x5b,0x25,0x5e, 0x25,0x5f,0x25,0x60,0x25,0x61,0x25,0x62, 0x25,0x64,0x25,0x66,0x25,0x68,0x25,0x69, 0x25,0x6a,0x25,0x6b,0x25,0x6c,0x25,0x6d, 0x25,0x6f,0x25,0x73,0x21,0x2b,0x21,0x2c, 0x00,0x00}; /* X0201 kana conversion table for daguten */ /* 90-9F A0-DF */ static const unsigned char dv[]= { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x25,0x74, 0x00,0x00,0x00,0x00,0x25,0x2c,0x25,0x2e, 0x25,0x30,0x25,0x32,0x25,0x34,0x25,0x36, 0x25,0x38,0x25,0x3a,0x25,0x3c,0x25,0x3e, 0x25,0x40,0x25,0x42,0x25,0x45,0x25,0x47, 0x25,0x49,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x25,0x50,0x25,0x53, 0x25,0x56,0x25,0x59,0x25,0x5c,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00}; /* X0201 kana conversion table for han-daguten */ /* 90-9F A0-DF */ static const unsigned char ev[]= { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x25,0x51,0x25,0x54, 0x25,0x57,0x25,0x5a,0x25,0x5d,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00}; /* X0208 kigou conversion table */ /* 0x8140 - 0x819e */ static const unsigned char fv[] = { 0x00,0x00,0x00,0x00,0x2c,0x2e,0x00,0x3a, 0x3b,0x3f,0x21,0x00,0x00,0x27,0x60,0x00, 0x5e,0x00,0x5f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x2d,0x00,0x2f, 0x5c,0x00,0x00,0x7c,0x00,0x00,0x60,0x27, 0x22,0x22,0x28,0x29,0x00,0x00,0x5b,0x5d, 0x7b,0x7d,0x3c,0x3e,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x2b,0x2d,0x00,0x00, 0x00,0x3d,0x00,0x3c,0x3e,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x24,0x00,0x00,0x25,0x23,0x26,0x2a,0x40, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } ; #define CRLF 1 static int file_out_f = FALSE; #ifdef OVERWRITE static int overwrite_f = FALSE; static int preserve_time_f = FALSE; static int backup_f = FALSE; static char *backup_suffix = ""; static char *get_backup_filename(const char *suffix, const char *filename); #endif static int crmode_f = 0; /* CR, NL, CRLF */ #ifdef EASYWIN /*Easy Win */ static int end_check; #endif /*Easy Win */ #define STD_GC_BUFSIZE (256) nkf_char std_gc_buf[STD_GC_BUFSIZE]; nkf_char std_gc_ndx; #ifdef WIN32DLL #include "nkf32dll.c" #elif defined(PERL_XS) #else /* WIN32DLL */ int main(int argc, char **argv) { FILE *fin; unsigned char *cp; char *outfname = NULL; char *origfname; #ifdef EASYWIN /*Easy Win */ _BufferSize.y = 400;/*Set Scroll Buffer Size*/ #endif for (argc--,argv++; (argc > 0) && **argv == '-'; argc--, argv++) { cp = (unsigned char *)*argv; options(cp); #ifdef EXEC_IO if (exec_f){ int fds[2], pid; if (pipe(fds) < 0 || (pid = fork()) < 0){ abort(); } if (pid == 0){ if (exec_f > 0){ close(fds[0]); dup2(fds[1], 1); }else{ close(fds[1]); dup2(fds[0], 0); } execvp(argv[1], &argv[1]); } if (exec_f > 0){ close(fds[1]); dup2(fds[0], 0); }else{ close(fds[0]); dup2(fds[1], 1); } argc = 0; break; } #endif } if(x0201_f == WISH_TRUE) x0201_f = ((!iso2022jp_f)? TRUE : NO_X0201); if (binmode_f == TRUE) #if defined(__OS2__) && (defined(__IBMC__) || defined(__IBMCPP__)) if (freopen("","wb",stdout) == NULL) return (-1); #else setbinmode(stdout); #endif if (unbuf_f) setbuf(stdout, (char *) NULL); else setvbuffer(stdout, (char *) stdobuf, IOBUF_SIZE); if (argc == 0) { if (binmode_f == TRUE) #if defined(__OS2__) && (defined(__IBMC__) || defined(__IBMCPP__)) if (freopen("","rb",stdin) == NULL) return (-1); #else setbinmode(stdin); #endif setvbuffer(stdin, (char *) stdibuf, IOBUF_SIZE); if (nop_f) noconvert(stdin); else { kanji_convert(stdin); if (guess_f) print_guessed_code(NULL); } } else { int nfiles = argc; int is_argument_error = FALSE; while (argc--) { is_inputcode_mixed = FALSE; is_inputcode_set = FALSE; input_codename = ""; #ifdef CHECK_OPTION iconv_for_check = 0; #endif if ((fin = fopen((origfname = *argv++), "r")) == NULL) { perror(*--argv); *argv++; is_argument_error = TRUE; continue; } else { #ifdef OVERWRITE int fd = 0; int fd_backup = 0; #endif /* reopen file for stdout */ if (file_out_f == TRUE) { #ifdef OVERWRITE if (overwrite_f){ outfname = malloc(strlen(origfname) + strlen(".nkftmpXXXXXX") + 1); if (!outfname){ perror(origfname); return -1; } strcpy(outfname, origfname); #ifdef MSDOS { int i; for (i = strlen(outfname); i; --i){ if (outfname[i - 1] == '/' || outfname[i - 1] == '\\'){ break; } } outfname[i] = '\0'; } strcat(outfname, "ntXXXXXX"); mktemp(outfname); fd = open(outfname, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, S_IREAD | S_IWRITE); #else strcat(outfname, ".nkftmpXXXXXX"); fd = mkstemp(outfname); #endif if (fd < 0 || (fd_backup = dup(fileno(stdout))) < 0 || dup2(fd, fileno(stdout)) < 0 ){ perror(origfname); return -1; } }else #endif if(argc == 1 ) { outfname = *argv++; argc--; } else { outfname = "nkf.out"; } if(freopen(outfname, "w", stdout) == NULL) { perror (outfname); return (-1); } if (binmode_f == TRUE) { #if defined(__OS2__) && (defined(__IBMC__) || defined(__IBMCPP__)) if (freopen("","wb",stdout) == NULL) return (-1); #else setbinmode(stdout); #endif } } if (binmode_f == TRUE) #if defined(__OS2__) && (defined(__IBMC__) || defined(__IBMCPP__)) if (freopen("","rb",fin) == NULL) return (-1); #else setbinmode(fin); #endif setvbuffer(fin, (char *) stdibuf, IOBUF_SIZE); if (nop_f) noconvert(fin); else { char *filename = NULL; kanji_convert(fin); if (nfiles > 1) filename = origfname; if (guess_f) print_guessed_code(filename); } fclose(fin); #ifdef OVERWRITE if (overwrite_f) { struct stat sb; #if defined(MSDOS) && !defined(__MINGW32__) && !defined(__WIN32__) && !defined(__WATCOMC__) && !defined(__EMX__) && !defined(__OS2__) && !defined(__DJGPP__) time_t tb[2]; #else struct utimbuf tb; #endif fflush(stdout); close(fd); if (dup2(fd_backup, fileno(stdout)) < 0){ perror("dup2"); } if (stat(origfname, &sb)) { fprintf(stderr, "Can't stat %s\n", origfname); } /* $B%Q!<%_%C%7%g%s$rI|85(B */ if (chmod(outfname, sb.st_mode)) { fprintf(stderr, "Can't set permission %s\n", outfname); } /* $B%?%$%`%9%?%s%W$rI|85(B */ if(preserve_time_f){ #if defined(MSDOS) && !defined(__MINGW32__) && !defined(__WIN32__) && !defined(__WATCOMC__) && !defined(__EMX__) && !defined(__OS2__) && !defined(__DJGPP__) tb[0] = tb[1] = sb.st_mtime; if (utime(outfname, tb)) { fprintf(stderr, "Can't set timestamp %s\n", outfname); } #else tb.actime = sb.st_atime; tb.modtime = sb.st_mtime; if (utime(outfname, &tb)) { fprintf(stderr, "Can't set timestamp %s\n", outfname); } #endif } if(backup_f){ char *backup_filename = get_backup_filename(backup_suffix, origfname); #ifdef MSDOS unlink(backup_filename); #endif if (rename(origfname, backup_filename)) { perror(backup_filename); fprintf(stderr, "Can't rename %s to %s\n", origfname, backup_filename); } }else{ #ifdef MSDOS if (unlink(origfname)){ perror(origfname); } #endif } if (rename(outfname, origfname)) { perror(origfname); fprintf(stderr, "Can't rename %s to %s\n", outfname, origfname); } free(outfname); } #endif } } if (is_argument_error) return(-1); } #ifdef EASYWIN /*Easy Win */ if (file_out_f == FALSE) scanf("%d",&end_check); else fclose(stdout); #else /* for Other OS */ if (file_out_f == TRUE) fclose(stdout); #endif /*Easy Win */ return (0); } #endif /* WIN32DLL */ #ifdef OVERWRITE char *get_backup_filename(const char *suffix, const char *filename) { char *backup_filename; int asterisk_count = 0; int i, j; int filename_length = strlen(filename); for(i = 0; suffix[i]; i++){ if(suffix[i] == '*') asterisk_count++; } if(asterisk_count){ backup_filename = malloc(strlen(suffix) + (asterisk_count * (filename_length - 1)) + 1); if (!backup_filename){ perror("Can't malloc backup filename."); return NULL; } for(i = 0, j = 0; suffix[i];){ if(suffix[i] == '*'){ backup_filename[j] = '\0'; strncat(backup_filename, filename, filename_length); i++; j += filename_length; }else{ backup_filename[j++] = suffix[i++]; } } backup_filename[j] = '\0'; }else{ j = strlen(suffix) + filename_length; backup_filename = malloc( + 1); strcpy(backup_filename, filename); strcat(backup_filename, suffix); backup_filename[j] = '\0'; } return backup_filename; } #endif static const struct { const char *name; const char *alias; } long_option[] = { {"ic=", ""}, {"oc=", ""}, {"base64","jMB"}, {"euc","e"}, {"euc-input","E"}, {"fj","jm"}, {"help","v"}, {"jis","j"}, {"jis-input","J"}, {"mac","sLm"}, {"mime","jM"}, {"mime-input","m"}, {"msdos","sLw"}, {"sjis","s"}, {"sjis-input","S"}, {"unix","eLu"}, {"version","V"}, {"windows","sLw"}, {"hiragana","h1"}, {"katakana","h2"}, {"katakana-hiragana","h3"}, {"guess", "g"}, {"cp932", ""}, {"no-cp932", ""}, #ifdef X0212_ENABLE {"x0212", ""}, #endif #ifdef UTF8_OUTPUT_ENABLE {"utf8", "w"}, {"utf16", "w16"}, {"ms-ucs-map", ""}, {"fb-skip", ""}, {"fb-html", ""}, {"fb-xml", ""}, {"fb-perl", ""}, {"fb-java", ""}, {"fb-subchar", ""}, {"fb-subchar=", ""}, #endif #ifdef UTF8_INPUT_ENABLE {"utf8-input", "W"}, {"utf16-input", "W16"}, {"no-cp932ext", ""}, {"no-best-fit-chars",""}, #endif #ifdef UNICODE_NORMALIZATION {"utf8mac-input", ""}, #endif #ifdef OVERWRITE {"overwrite", ""}, {"overwrite=", ""}, {"in-place", ""}, {"in-place=", ""}, #endif #ifdef INPUT_OPTION {"cap-input", ""}, {"url-input", ""}, #endif #ifdef NUMCHAR_OPTION {"numchar-input", ""}, #endif #ifdef CHECK_OPTION {"no-output", ""}, {"debug", ""}, #endif #ifdef SHIFTJIS_CP932 {"cp932inv", ""}, #endif #ifdef EXEC_IO {"exec-in", ""}, {"exec-out", ""}, #endif {"prefix=", ""}, }; static int option_mode = 0; void options(unsigned char *cp) { nkf_char i, j; unsigned char *p; unsigned char *cp_back = NULL; char codeset[32]; if (option_mode==1) return; while(*cp && *cp++!='-'); while (*cp || cp_back) { if(!*cp){ cp = cp_back; cp_back = NULL; continue; } p = 0; switch (*cp++) { case '-': /* literal options */ if (!*cp || *cp == SPACE) { /* ignore the rest of arguments */ option_mode = 1; return; } for (i=0;iname); debug(input_codename); } iconv_for_check = iconv; } #endif } #define SCORE_L2 (1) /* $BBh(B2$B?e=`4A;z(B */ #define SCORE_KANA (SCORE_L2 << 1) /* $B$$$o$f$kH>3Q%+%J(B */ #define SCORE_DEPEND (SCORE_KANA << 1) /* $B5!score |= score; } } void clr_code_score(struct input_code *ptr, nkf_char score) { if (ptr){ ptr->score &= ~score; } } void code_score(struct input_code *ptr) { nkf_char c2 = ptr->buf[0]; #ifdef UTF8_OUTPUT_ENABLE nkf_char c1 = ptr->buf[1]; #endif if (c2 < 0){ set_code_score(ptr, SCORE_ERROR); }else if (c2 == SSO){ set_code_score(ptr, SCORE_KANA); #ifdef UTF8_OUTPUT_ENABLE }else if (!e2w_conv(c2, c1)){ set_code_score(ptr, SCORE_NO_EXIST); #endif }else if ((c2 & 0x70) == 0x20){ set_code_score(ptr, score_table_A0[c2 & 0x0f]); }else if ((c2 & 0x70) == 0x70){ set_code_score(ptr, score_table_F0[c2 & 0x0f]); }else if ((c2 & 0x70) >= 0x50){ set_code_score(ptr, SCORE_L2); } } void status_disable(struct input_code *ptr) { ptr->stat = -1; ptr->buf[0] = -1; code_score(ptr); if (iconv == ptr->iconv_func) set_iconv(FALSE, 0); } void status_push_ch(struct input_code *ptr, nkf_char c) { ptr->buf[ptr->index++] = c; } void status_clear(struct input_code *ptr) { ptr->stat = 0; ptr->index = 0; } void status_reset(struct input_code *ptr) { status_clear(ptr); ptr->score = SCORE_INIT; } void status_reinit(struct input_code *ptr) { status_reset(ptr); ptr->_file_stat = 0; } void status_check(struct input_code *ptr, nkf_char c) { if (c <= DEL && estab_f){ status_reset(ptr); } } void s_status(struct input_code *ptr, nkf_char c) { switch(ptr->stat){ case -1: status_check(ptr, c); break; case 0: if (c <= DEL){ break; #ifdef NUMCHAR_OPTION }else if (is_unicode_capsule(c)){ break; #endif }else if (0xa1 <= c && c <= 0xdf){ status_push_ch(ptr, SSO); status_push_ch(ptr, c); code_score(ptr); status_clear(ptr); }else if ((0x81 <= c && c < 0xa0) || (0xe0 <= c && c <= 0xef)){ ptr->stat = 1; status_push_ch(ptr, c); #ifdef SHIFTJIS_CP932 }else if (cp51932_f && is_ibmext_in_sjis(c)){ ptr->stat = 2; status_push_ch(ptr, c); #endif /* SHIFTJIS_CP932 */ #ifdef X0212_ENABLE }else if (x0212_f && 0xf0 <= c && c <= 0xfc){ ptr->stat = 1; status_push_ch(ptr, c); #endif /* X0212_ENABLE */ }else{ status_disable(ptr); } break; case 1: if ((0x40 <= c && c <= 0x7e) || (0x80 <= c && c <= 0xfc)){ status_push_ch(ptr, c); s2e_conv(ptr->buf[0], ptr->buf[1], &ptr->buf[0], &ptr->buf[1]); code_score(ptr); status_clear(ptr); }else{ status_disable(ptr); } break; case 2: #ifdef SHIFTJIS_CP932 if ((0x40 <= c && c <= 0x7e) || (0x80 <= c && c <= 0xfc)){ status_push_ch(ptr, c); if (s2e_conv(ptr->buf[0], ptr->buf[1], &ptr->buf[0], &ptr->buf[1]) == 0){ set_code_score(ptr, SCORE_CP932); status_clear(ptr); break; } } #endif /* SHIFTJIS_CP932 */ #ifndef X0212_ENABLE status_disable(ptr); #endif break; } } void e_status(struct input_code *ptr, nkf_char c) { switch (ptr->stat){ case -1: status_check(ptr, c); break; case 0: if (c <= DEL){ break; #ifdef NUMCHAR_OPTION }else if (is_unicode_capsule(c)){ break; #endif }else if (SSO == c || (0xa1 <= c && c <= 0xfe)){ ptr->stat = 1; status_push_ch(ptr, c); #ifdef X0212_ENABLE }else if (0x8f == c){ ptr->stat = 2; status_push_ch(ptr, c); #endif /* X0212_ENABLE */ }else{ status_disable(ptr); } break; case 1: if (0xa1 <= c && c <= 0xfe){ status_push_ch(ptr, c); code_score(ptr); status_clear(ptr); }else{ status_disable(ptr); } break; #ifdef X0212_ENABLE case 2: if (0xa1 <= c && c <= 0xfe){ ptr->stat = 1; status_push_ch(ptr, c); }else{ status_disable(ptr); } #endif /* X0212_ENABLE */ } } #ifdef UTF8_INPUT_ENABLE void w_status(struct input_code *ptr, nkf_char c) { switch (ptr->stat){ case -1: status_check(ptr, c); break; case 0: if (c <= DEL){ break; #ifdef NUMCHAR_OPTION }else if (is_unicode_capsule(c)){ break; #endif }else if (0xc0 <= c && c <= 0xdf){ ptr->stat = 1; status_push_ch(ptr, c); }else if (0xe0 <= c && c <= 0xef){ ptr->stat = 2; status_push_ch(ptr, c); }else if (0xf0 <= c && c <= 0xf4){ ptr->stat = 3; status_push_ch(ptr, c); }else{ status_disable(ptr); } break; case 1: case 2: if (0x80 <= c && c <= 0xbf){ status_push_ch(ptr, c); if (ptr->index > ptr->stat){ int bom = (ptr->buf[0] == 0xef && ptr->buf[1] == 0xbb && ptr->buf[2] == 0xbf); w2e_conv(ptr->buf[0], ptr->buf[1], ptr->buf[2], &ptr->buf[0], &ptr->buf[1]); if (!bom){ code_score(ptr); } status_clear(ptr); } }else{ status_disable(ptr); } break; case 3: if (0x80 <= c && c <= 0xbf){ if (ptr->index < ptr->stat){ status_push_ch(ptr, c); } else { status_clear(ptr); } }else{ status_disable(ptr); } break; } } #endif void code_status(nkf_char c) { int action_flag = 1; struct input_code *result = 0; struct input_code *p = input_code_list; while (p->name){ if (!p->status_func) { ++p; continue; } if (!p->status_func) continue; (p->status_func)(p, c); if (p->stat > 0){ action_flag = 0; }else if(p->stat == 0){ if (result){ action_flag = 0; }else{ result = p; } } ++p; } if (action_flag){ if (result && !estab_f){ set_iconv(TRUE, result->iconv_func); }else if (c <= DEL){ struct input_code *ptr = input_code_list; while (ptr->name){ status_reset(ptr); ++ptr; } } } } #ifndef WIN32DLL nkf_char std_getc(FILE *f) { if (std_gc_ndx){ return std_gc_buf[--std_gc_ndx]; } return getc(f); } #endif /*WIN32DLL*/ nkf_char std_ungetc(nkf_char c, FILE *f) { if (std_gc_ndx == STD_GC_BUFSIZE){ return EOF; } std_gc_buf[std_gc_ndx++] = c; return c; } #ifndef WIN32DLL void std_putc(nkf_char c) { if(c!=EOF) putchar(c); } #endif /*WIN32DLL*/ #if !defined(PERL_XS) && !defined(WIN32DLL) nkf_char noconvert(FILE *f) { nkf_char c; if (nop_f == 2) module_connection(); while ((c = (*i_getc)(f)) != EOF) (*o_putc)(c); (*o_putc)(EOF); return 1; } #endif void module_connection(void) { oconv = output_conv; o_putc = std_putc; /* replace continucation module, from output side */ /* output redicrection */ #ifdef CHECK_OPTION if (noout_f || guess_f){ o_putc = no_putc; } #endif if (mimeout_f) { o_mputc = o_putc; o_putc = mime_putc; if (mimeout_f == TRUE) { o_base64conv = oconv; oconv = base64_conv; } /* base64_count = 0; */ } if (crmode_f) { o_crconv = oconv; oconv = cr_conv; } if (rot_f) { o_rot_conv = oconv; oconv = rot_conv; } if (iso2022jp_f) { o_iso2022jp_check_conv = oconv; oconv = iso2022jp_check_conv; } if (hira_f) { o_hira_conv = oconv; oconv = hira_conv; } if (fold_f) { o_fconv = oconv; oconv = fold_conv; f_line = 0; } if (alpha_f || x0201_f) { o_zconv = oconv; oconv = z_conv; } i_getc = std_getc; i_ungetc = std_ungetc; /* input redicrection */ #ifdef INPUT_OPTION if (cap_f){ i_cgetc = i_getc; i_getc = cap_getc; i_cungetc = i_ungetc; i_ungetc= cap_ungetc; } if (url_f){ i_ugetc = i_getc; i_getc = url_getc; i_uungetc = i_ungetc; i_ungetc= url_ungetc; } #endif #ifdef NUMCHAR_OPTION if (numchar_f){ i_ngetc = i_getc; i_getc = numchar_getc; i_nungetc = i_ungetc; i_ungetc= numchar_ungetc; } #endif #ifdef UNICODE_NORMALIZATION if (nfc_f && input_f == UTF8_INPUT){ i_nfc_getc = i_getc; i_getc = nfc_getc; i_nfc_ungetc = i_ungetc; i_ungetc= nfc_ungetc; } #endif if (mime_f && mimebuf_f==FIXED_MIME) { i_mgetc = i_getc; i_getc = mime_getc; i_mungetc = i_ungetc; i_ungetc = mime_ungetc; } if (broken_f & 1) { i_bgetc = i_getc; i_getc = broken_getc; i_bungetc = i_ungetc; i_ungetc = broken_ungetc; } if (input_f == JIS_INPUT || input_f == EUC_INPUT || input_f == LATIN1_INPUT) { set_iconv(-TRUE, e_iconv); } else if (input_f == SJIS_INPUT) { set_iconv(-TRUE, s_iconv); #ifdef UTF8_INPUT_ENABLE } else if (input_f == UTF8_INPUT) { set_iconv(-TRUE, w_iconv); } else if (input_f == UTF16_INPUT) { set_iconv(-TRUE, w_iconv16); } else if (input_f == UTF32_INPUT) { set_iconv(-TRUE, w_iconv32); #endif } else { set_iconv(FALSE, e_iconv); } { struct input_code *p = input_code_list; while (p->name){ status_reinit(p++); } } } /* * Check and Ignore BOM */ void check_bom(FILE *f) { int c2; switch(c2 = (*i_getc)(f)){ case 0x00: if((c2 = (*i_getc)(f)) == 0x00){ if((c2 = (*i_getc)(f)) == 0xFE){ if((c2 = (*i_getc)(f)) == 0xFF){ if(!input_f){ set_iconv(TRUE, w_iconv32); } if (iconv == w_iconv32) { input_endian = ENDIAN_BIG; return; } (*i_ungetc)(0xFF,f); }else (*i_ungetc)(c2,f); (*i_ungetc)(0xFE,f); }else if(c2 == 0xFF){ if((c2 = (*i_getc)(f)) == 0xFE){ if(!input_f){ set_iconv(TRUE, w_iconv32); } if (iconv == w_iconv32) { input_endian = ENDIAN_2143; return; } (*i_ungetc)(0xFF,f); }else (*i_ungetc)(c2,f); (*i_ungetc)(0xFF,f); }else (*i_ungetc)(c2,f); (*i_ungetc)(0x00,f); }else (*i_ungetc)(c2,f); (*i_ungetc)(0x00,f); break; case 0xEF: if((c2 = (*i_getc)(f)) == 0xBB){ if((c2 = (*i_getc)(f)) == 0xBF){ if(!input_f){ set_iconv(TRUE, w_iconv); } if (iconv == w_iconv) { return; } (*i_ungetc)(0xBF,f); }else (*i_ungetc)(c2,f); (*i_ungetc)(0xBB,f); }else (*i_ungetc)(c2,f); (*i_ungetc)(0xEF,f); break; case 0xFE: if((c2 = (*i_getc)(f)) == 0xFF){ if((c2 = (*i_getc)(f)) == 0x00){ if((c2 = (*i_getc)(f)) == 0x00){ if(!input_f){ set_iconv(TRUE, w_iconv32); } if (iconv == w_iconv32) { input_endian = ENDIAN_3412; return; } (*i_ungetc)(0x00,f); }else (*i_ungetc)(c2,f); (*i_ungetc)(0x00,f); }else (*i_ungetc)(c2,f); if(!input_f){ set_iconv(TRUE, w_iconv16); } if (iconv == w_iconv16) { input_endian = ENDIAN_BIG; return; } (*i_ungetc)(0xFF,f); }else (*i_ungetc)(c2,f); (*i_ungetc)(0xFE,f); break; case 0xFF: if((c2 = (*i_getc)(f)) == 0xFE){ if((c2 = (*i_getc)(f)) == 0x00){ if((c2 = (*i_getc)(f)) == 0x00){ if(!input_f){ set_iconv(TRUE, w_iconv32); } if (iconv == w_iconv32) { input_endian = ENDIAN_LITTLE; return; } (*i_ungetc)(0x00,f); }else (*i_ungetc)(c2,f); (*i_ungetc)(0x00,f); }else (*i_ungetc)(c2,f); if(!input_f){ set_iconv(TRUE, w_iconv16); } if (iconv == w_iconv16) { input_endian = ENDIAN_LITTLE; return; } (*i_ungetc)(0xFE,f); }else (*i_ungetc)(c2,f); (*i_ungetc)(0xFF,f); break; default: (*i_ungetc)(c2,f); break; } } /* Conversion main loop. Code detection only. */ nkf_char kanji_convert(FILE *f) { nkf_char c3, c2=0, c1, c0=0; int is_8bit = FALSE; if(input_f == SJIS_INPUT || input_f == EUC_INPUT #ifdef UTF8_INPUT_ENABLE || input_f == UTF8_INPUT || input_f == UTF16_INPUT #endif ){ is_8bit = TRUE; } input_mode = ASCII; output_mode = ASCII; shift_mode = FALSE; #define NEXT continue /* no output, get next */ #define SEND ; /* output c1 and c2, get next */ #define LAST break /* end of loop, go closing */ module_connection(); check_bom(f); while ((c1 = (*i_getc)(f)) != EOF) { #ifdef INPUT_CODE_FIX if (!input_f) #endif code_status(c1); if (c2) { /* second byte */ if (c2 > ((input_f == JIS_INPUT && ms_ucs_map_f) ? 0x92 : DEL)) { /* in case of 8th bit is on */ if (!estab_f&&!mime_decode_mode) { /* in case of not established yet */ /* It is still ambiguious */ if (h_conv(f, c2, c1)==EOF) LAST; else c2 = 0; NEXT; } else { /* in case of already established */ if (c1 < AT) { /* ignore bogus code and not CP5022x UCD */ c2 = 0; NEXT; } else { SEND; } } } else /* second byte, 7 bit code */ /* it might be kanji shitfted */ if ((c1 == DEL) || (c1 <= SPACE)) { /* ignore bogus first code */ c2 = 0; NEXT; } else SEND; } else { /* first byte */ #ifdef UTF8_INPUT_ENABLE if (iconv == w_iconv16) { if (input_endian == ENDIAN_BIG) { c2 = c1; if ((c1 = (*i_getc)(f)) != EOF) { if (0xD8 <= c2 && c2 <= 0xDB) { if ((c0 = (*i_getc)(f)) != EOF) { c0 <<= 8; if ((c3 = (*i_getc)(f)) != EOF) { c0 |= c3; } else c2 = EOF; } else c2 = EOF; } } else c2 = EOF; } else { if ((c2 = (*i_getc)(f)) != EOF) { if (0xD8 <= c2 && c2 <= 0xDB) { if ((c3 = (*i_getc)(f)) != EOF) { if ((c0 = (*i_getc)(f)) != EOF) { c0 <<= 8; c0 |= c3; } else c2 = EOF; } else c2 = EOF; } } else c2 = EOF; } SEND; } else if(iconv == w_iconv32){ int c3 = c1; if((c2 = (*i_getc)(f)) != EOF && (c1 = (*i_getc)(f)) != EOF && (c0 = (*i_getc)(f)) != EOF){ switch(input_endian){ case ENDIAN_BIG: c1 = (c2&0xFF)<<16 | (c1&0xFF)<<8 | (c0&0xFF); break; case ENDIAN_LITTLE: c1 = (c3&0xFF) | (c2&0xFF)<<8 | (c1&0xFF)<<16; break; case ENDIAN_2143: c1 = (c3&0xFF)<<16 | (c1&0xFF) | (c0&0xFF)<<8; break; case ENDIAN_3412: c1 = (c3&0xFF)<<8 | (c2&0xFF) | (c0&0xFF)<<16; break; } c2 = 0; }else{ c2 = EOF; } SEND; } else #endif #ifdef NUMCHAR_OPTION if (is_unicode_capsule(c1)){ SEND; } else #endif if (c1 > ((input_f == JIS_INPUT && ms_ucs_map_f) ? 0x92 : DEL)) { /* 8 bit code */ if (!estab_f && !iso8859_f) { /* not established yet */ c2 = c1; NEXT; } else { /* estab_f==TRUE */ if (iso8859_f) { c2 = ISO8859_1; c1 &= 0x7f; SEND; } else if (SSP<=c1 && c1<0xe0 && iconv == s_iconv) { /* SJIS X0201 Case... */ if(iso2022jp_f && x0201_f==NO_X0201) { (*oconv)(GETA1, GETA2); NEXT; } else { c2 = X0201; c1 &= 0x7f; SEND; } } else if (c1==SSO && iconv != s_iconv) { /* EUC X0201 Case */ c1 = (*i_getc)(f); /* skip SSO */ code_status(c1); if (SSP<=c1 && c1<0xe0) { if(iso2022jp_f && x0201_f==NO_X0201) { (*oconv)(GETA1, GETA2); NEXT; } else { c2 = X0201; c1 &= 0x7f; SEND; } } else { /* bogus code, skip SSO and one byte */ NEXT; } } else { /* already established */ c2 = c1; NEXT; } } } else if ((c1 > SPACE) && (c1 != DEL)) { /* in case of Roman characters */ if (shift_mode) { /* output 1 shifted byte */ if (iso8859_f) { c2 = ISO8859_1; SEND; } else if (SPACE<=c1 && c1<(0xe0&0x7f) ){ /* output 1 shifted byte */ if(iso2022jp_f && x0201_f==NO_X0201) { (*oconv)(GETA1, GETA2); NEXT; } else { c2 = X0201; SEND; } } else { /* look like bogus code */ NEXT; } } else if (input_mode == X0208 || input_mode == X0212 || input_mode == X0213_1 || input_mode == X0213_2) { /* in case of Kanji shifted */ c2 = c1; NEXT; } else if (c1 == '=' && mime_f && !mime_decode_mode ) { /* Check MIME code */ if ((c1 = (*i_getc)(f)) == EOF) { (*oconv)(0, '='); LAST; } else if (c1 == '?') { /* =? is mime conversion start sequence */ if(mime_f == STRICT_MIME) { /* check in real detail */ if (mime_begin_strict(f) == EOF) LAST; else NEXT; } else if (mime_begin(f) == EOF) LAST; else NEXT; } else { (*oconv)(0, '='); (*i_ungetc)(c1,f); NEXT; } } else { /* normal ASCII code */ SEND; } } else if (c1 == SI && (!is_8bit || mime_decode_mode)) { shift_mode = FALSE; NEXT; } else if (c1 == SO && (!is_8bit || mime_decode_mode)) { shift_mode = TRUE; NEXT; } else if (c1 == ESC && (!is_8bit || mime_decode_mode)) { if ((c1 = (*i_getc)(f)) == EOF) { /* (*oconv)(0, ESC); don't send bogus code */ LAST; } else if (c1 == '$') { if ((c1 = (*i_getc)(f)) == EOF) { /* (*oconv)(0, ESC); don't send bogus code (*oconv)(0, '$'); */ LAST; } else if (c1 == '@'|| c1 == 'B') { /* This is kanji introduction */ input_mode = X0208; shift_mode = FALSE; set_input_codename("ISO-2022-JP"); #ifdef CHECK_OPTION debug(input_codename); #endif NEXT; } else if (c1 == '(') { if ((c1 = (*i_getc)(f)) == EOF) { /* don't send bogus code (*oconv)(0, ESC); (*oconv)(0, '$'); (*oconv)(0, '('); */ LAST; } else if (c1 == '@'|| c1 == 'B') { /* This is kanji introduction */ input_mode = X0208; shift_mode = FALSE; NEXT; #ifdef X0212_ENABLE } else if (c1 == 'D'){ input_mode = X0212; shift_mode = FALSE; NEXT; #endif /* X0212_ENABLE */ } else if (c1 == (X0213_1&0x7F)){ input_mode = X0213_1; shift_mode = FALSE; NEXT; } else if (c1 == (X0213_2&0x7F)){ input_mode = X0213_2; shift_mode = FALSE; NEXT; } else { /* could be some special code */ (*oconv)(0, ESC); (*oconv)(0, '$'); (*oconv)(0, '('); (*oconv)(0, c1); NEXT; } } else if (broken_f&0x2) { /* accept any ESC-(-x as broken code ... */ input_mode = X0208; shift_mode = FALSE; NEXT; } else { (*oconv)(0, ESC); (*oconv)(0, '$'); (*oconv)(0, c1); NEXT; } } else if (c1 == '(') { if ((c1 = (*i_getc)(f)) == EOF) { /* don't send bogus code (*oconv)(0, ESC); (*oconv)(0, '('); */ LAST; } else { if (c1 == 'I') { /* This is X0201 kana introduction */ input_mode = X0201; shift_mode = X0201; NEXT; } else if (c1 == 'B' || c1 == 'J' || c1 == 'H') { /* This is X0208 kanji introduction */ input_mode = ASCII; shift_mode = FALSE; NEXT; } else if (broken_f&0x2) { input_mode = ASCII; shift_mode = FALSE; NEXT; } else { (*oconv)(0, ESC); (*oconv)(0, '('); /* maintain various input_mode here */ SEND; } } } else if ( c1 == 'N' || c1 == 'n' ){ /* SS2 */ c3 = (*i_getc)(f); /* skip SS2 */ if ( (SPACE<=c3 && c3 < 0x60) || (0xa0<=c3 && c3 < 0xe0)){ c1 = c3; c2 = X0201; SEND; }else{ (*i_ungetc)(c3, f); /* lonely ESC */ (*oconv)(0, ESC); SEND; } } else { /* lonely ESC */ (*oconv)(0, ESC); SEND; } } else if (c1 == ESC && iconv == s_iconv) { /* ESC in Shift_JIS */ if ((c1 = (*i_getc)(f)) == EOF) { /* (*oconv)(0, ESC); don't send bogus code */ LAST; } else if (c1 == '$') { /* J-PHONE emoji */ if ((c1 = (*i_getc)(f)) == EOF) { /* (*oconv)(0, ESC); don't send bogus code (*oconv)(0, '$'); */ LAST; } else { if (('E' <= c1 && c1 <= 'G') || ('O' <= c1 && c1 <= 'Q')) { /* NUM : 0 1 2 3 4 5 BYTE: G E F O P Q C%7 : 1 6 0 2 3 4 C%7 : 0 1 2 3 4 5 6 NUM : 2 0 3 4 5 X 1 */ static const int jphone_emoji_first_table[7] = {2, 0, 3, 4, 5, 0, 1}; c0 = (jphone_emoji_first_table[c1 % 7] << 8) - SPACE + 0xE000 + CLASS_UNICODE; while ((c1 = (*i_getc)(f)) != EOF) { if (SPACE <= c1 && c1 <= 'z') { (*oconv)(0, c1 + c0); } else break; /* c1 == SO */ } } } if (c1 == EOF) LAST; NEXT; } else { /* lonely ESC */ (*oconv)(0, ESC); SEND; } } else if ((c1 == NL || c1 == CR) && broken_f&4) { input_mode = ASCII; set_iconv(FALSE, 0); SEND; } else if (c1 == NL && mime_decode_f && !mime_decode_mode ) { if ((c1=(*i_getc)(f))!=EOF && c1 == SPACE) { i_ungetc(SPACE,f); continue; } else { i_ungetc(c1,f); } c1 = NL; SEND; } else if (c1 == CR && mime_decode_f && !mime_decode_mode ) { if ((c1=(*i_getc)(f))!=EOF) { if (c1==SPACE) { i_ungetc(SPACE,f); continue; } else if (c1 == NL && (c1=(*i_getc)(f))!=EOF && c1 == SPACE) { i_ungetc(SPACE,f); continue; } else { i_ungetc(c1,f); } i_ungetc(NL,f); } else { i_ungetc(c1,f); } c1 = CR; SEND; } else if (c1 == DEL && input_mode == X0208 ) { /* CP5022x */ c2 = c1; NEXT; } else SEND; } /* send: */ switch(input_mode){ case ASCII: switch ((*iconv)(c2, c1, c0)) { /* can be EUC / SJIS / UTF-8 / UTF-16 */ case -2: /* 4 bytes UTF-8 */ if ((c0 = (*i_getc)(f)) != EOF) { code_status(c0); c0 <<= 8; if ((c3 = (*i_getc)(f)) != EOF) { code_status(c3); (*iconv)(c2, c1, c0|c3); } } break; case -1: /* 3 bytes EUC or UTF-8 */ if ((c0 = (*i_getc)(f)) != EOF) { code_status(c0); (*iconv)(c2, c1, c0); } break; } break; case X0208: case X0213_1: if (ms_ucs_map_f && 0x7F <= c2 && c2 <= 0x92 && 0x21 <= c1 && c1 <= 0x7E) { /* CP932 UDC */ if(c1 == 0x7F) return 0; c1 = (c2 - 0x7F) * 94 + c1 - 0x21 + 0xE000 + CLASS_UNICODE; c2 = 0; } (*oconv)(c2, c1); /* this is JIS, not SJIS/EUC case */ break; #ifdef X0212_ENABLE case X0212: (*oconv)(PREFIX_EUCG3 | c2, c1); break; #endif /* X0212_ENABLE */ case X0213_2: (*oconv)(PREFIX_EUCG3 | c2, c1); break; default: (*oconv)(input_mode, c1); /* other special case */ } c2 = 0; c0 = 0; continue; /* goto next_word */ } /* epilogue */ (*iconv)(EOF, 0, 0); if (!is_inputcode_set) { if (is_8bit) { struct input_code *p = input_code_list; struct input_code *result = p; while (p->name){ if (p->score < result->score) result = p; ++p; } set_input_codename(result->name); } } return 1; } nkf_char h_conv(FILE *f, nkf_char c2, nkf_char c1) { nkf_char ret, c3, c0; int hold_index; /** it must NOT be in the kanji shifte sequence */ /** it must NOT be written in JIS7 */ /** and it must be after 2 byte 8bit code */ hold_count = 0; push_hold_buf(c2); push_hold_buf(c1); while ((c1 = (*i_getc)(f)) != EOF) { if (c1 == ESC){ (*i_ungetc)(c1,f); break; } code_status(c1); if (push_hold_buf(c1) == EOF || estab_f){ break; } } if (!estab_f){ struct input_code *p = input_code_list; struct input_code *result = p; if (c1 == EOF){ code_status(c1); } while (p->name){ if (p->status_func && p->score < result->score){ result = p; } ++p; } set_iconv(TRUE, result->iconv_func); } /** now, ** 1) EOF is detected, or ** 2) Code is established, or ** 3) Buffer is FULL (but last word is pushed) ** ** in 1) and 3) cases, we continue to use ** Kanji codes by oconv and leave estab_f unchanged. **/ ret = c1; hold_index = 0; while (hold_index < hold_count){ c2 = hold_buf[hold_index++]; if (c2 <= DEL #ifdef NUMCHAR_OPTION || is_unicode_capsule(c2) #endif ){ (*iconv)(0, c2, 0); continue; }else if (iconv == s_iconv && 0xa1 <= c2 && c2 <= 0xdf){ (*iconv)(X0201, c2, 0); continue; } if (hold_index < hold_count){ c1 = hold_buf[hold_index++]; }else{ c1 = (*i_getc)(f); if (c1 == EOF){ c3 = EOF; break; } code_status(c1); } c0 = 0; switch ((*iconv)(c2, c1, 0)) { /* can be EUC/SJIS/UTF-8 */ case -2: /* 4 bytes UTF-8 */ if (hold_index < hold_count){ c0 = hold_buf[hold_index++]; } else if ((c0 = (*i_getc)(f)) == EOF) { ret = EOF; break; } else { code_status(c0); c0 <<= 8; if (hold_index < hold_count){ c3 = hold_buf[hold_index++]; } else if ((c3 = (*i_getc)(f)) == EOF) { c0 = ret = EOF; break; } else { code_status(c3); (*iconv)(c2, c1, c0|c3); } } break; case -1: /* 3 bytes EUC or UTF-8 */ if (hold_index < hold_count){ c0 = hold_buf[hold_index++]; } else if ((c0 = (*i_getc)(f)) == EOF) { ret = EOF; break; } else { code_status(c0); } (*iconv)(c2, c1, c0); break; } if (c0 == EOF) break; } return ret; } nkf_char push_hold_buf(nkf_char c2) { if (hold_count >= HOLD_SIZE*2) return (EOF); hold_buf[hold_count++] = (unsigned char)c2; return ((hold_count >= HOLD_SIZE*2) ? EOF : hold_count); } nkf_char s2e_conv(nkf_char c2, nkf_char c1, nkf_char *p2, nkf_char *p1) { #if defined(SHIFTJIS_CP932) || defined(X0212_ENABLE) nkf_char val; #endif static const nkf_char shift_jisx0213_s1a3_table[5][2] ={ { 1, 8}, { 3, 4}, { 5,12}, {13,14}, {15, 0} }; #ifdef SHIFTJIS_CP932 if (!cp932inv_f && is_ibmext_in_sjis(c2)){ #if 0 extern const unsigned short shiftjis_cp932[3][189]; #endif val = shiftjis_cp932[c2 - CP932_TABLE_BEGIN][c1 - 0x40]; if (val){ c2 = val >> 8; c1 = val & 0xff; } } if (cp932inv_f && CP932INV_TABLE_BEGIN <= c2 && c2 <= CP932INV_TABLE_END){ #if 0 extern const unsigned short cp932inv[2][189]; #endif nkf_char c = cp932inv[c2 - CP932INV_TABLE_BEGIN][c1 - 0x40]; if (c){ c2 = c >> 8; c1 = c & 0xff; } } #endif /* SHIFTJIS_CP932 */ #ifdef X0212_ENABLE if (!x0213_f && is_ibmext_in_sjis(c2)){ #if 0 extern const unsigned short shiftjis_x0212[3][189]; #endif val = shiftjis_x0212[c2 - 0xfa][c1 - 0x40]; if (val){ if (val > 0x7FFF){ c2 = PREFIX_EUCG3 | ((val >> 8) & 0x7f); c1 = val & 0xff; }else{ c2 = val >> 8; c1 = val & 0xff; } if (p2) *p2 = c2; if (p1) *p1 = c1; return 0; } } #endif if(c2 >= 0x80){ if(x0213_f && c2 >= 0xF0){ if(c2 <= 0xF3 || (c2 == 0xF4 && c1 < 0x9F)){ /* k=1, 3<=k<=5, k=8, 12<=k<=15 */ c2 = PREFIX_EUCG3 | 0x20 | shift_jisx0213_s1a3_table[c2 - 0xF0][0x9E < c1]; }else{ /* 78<=k<=94 */ c2 = PREFIX_EUCG3 | (c2 * 2 - 0x17B); if (0x9E < c1) c2++; } }else{ c2 = c2 + c2 - ((c2 <= 0x9F) ? SJ0162 : SJ6394); if (0x9E < c1) c2++; } if (c1 < 0x9F) c1 = c1 - ((c1 > DEL) ? SPACE : 0x1F); else { c1 = c1 - 0x7E; } } #ifdef X0212_ENABLE c2 = x0212_unshift(c2); #endif if (p2) *p2 = c2; if (p1) *p1 = c1; return 0; } nkf_char s_iconv(nkf_char c2, nkf_char c1, nkf_char c0) { if (c2 == X0201) { c1 &= 0x7f; } else if ((c2 == EOF) || (c2 == 0) || c2 < SPACE) { /* NOP */ } else if (!x0213_f && 0xF0 <= c2 && c2 <= 0xF9 && 0x40 <= c1 && c1 <= 0xFC) { /* CP932 UDC */ if(c1 == 0x7F) return 0; c1 = (c2 - 0xF0) * 188 + (c1 - 0x40 - (0x7E < c1)) + 0xE000 + CLASS_UNICODE; c2 = 0; } else { nkf_char ret = s2e_conv(c2, c1, &c2, &c1); if (ret) return ret; } (*oconv)(c2, c1); return 0; } nkf_char e_iconv(nkf_char c2, nkf_char c1, nkf_char c0) { if (c2 == X0201) { c1 &= 0x7f; #ifdef X0212_ENABLE }else if (c2 == 0x8f){ if (c0 == 0){ return -1; } if (!cp51932_f && !x0213_f && 0xF5 <= c1 && c1 <= 0xFE && 0xA1 <= c0 && c0 <= 0xFE) { /* encoding is eucJP-ms, so invert to Unicode Private User Area */ c1 = (c1 - 0xF5) * 94 + c0 - 0xA1 + 0xE3AC + CLASS_UNICODE; c2 = 0; } else { c2 = (c2 << 8) | (c1 & 0x7f); c1 = c0 & 0x7f; #ifdef SHIFTJIS_CP932 if (cp51932_f){ nkf_char s2, s1; if (e2s_conv(c2, c1, &s2, &s1) == 0){ s2e_conv(s2, s1, &c2, &c1); if (c2 < 0x100){ c1 &= 0x7f; c2 &= 0x7f; } } } #endif /* SHIFTJIS_CP932 */ } #endif /* X0212_ENABLE */ } else if (c2 == SSO){ c2 = X0201; c1 &= 0x7f; } else if ((c2 == EOF) || (c2 == 0) || c2 < SPACE) { /* NOP */ } else { if (!cp51932_f && ms_ucs_map_f && 0xF5 <= c2 && c2 <= 0xFE && 0xA1 <= c1 && c1 <= 0xFE) { /* encoding is eucJP-ms, so invert to Unicode Private User Area */ c1 = (c2 - 0xF5) * 94 + c1 - 0xA1 + 0xE000 + CLASS_UNICODE; c2 = 0; } else { c1 &= 0x7f; c2 &= 0x7f; #ifdef SHIFTJIS_CP932 if (cp51932_f && 0x79 <= c2 && c2 <= 0x7c){ nkf_char s2, s1; if (e2s_conv(c2, c1, &s2, &s1) == 0){ s2e_conv(s2, s1, &c2, &c1); if (c2 < 0x100){ c1 &= 0x7f; c2 &= 0x7f; } } } #endif /* SHIFTJIS_CP932 */ } } (*oconv)(c2, c1); return 0; } #ifdef UTF8_INPUT_ENABLE nkf_char w2e_conv(nkf_char c2, nkf_char c1, nkf_char c0, nkf_char *p2, nkf_char *p1) { nkf_char ret = 0; if (!c1){ *p2 = 0; *p1 = c2; }else if (0xc0 <= c2 && c2 <= 0xef) { ret = unicode_to_jis_common(c2, c1, c0, p2, p1); #ifdef NUMCHAR_OPTION if (ret > 0){ if (p2) *p2 = 0; if (p1) *p1 = CLASS_UNICODE | ww16_conv(c2, c1, c0); ret = 0; } #endif } return ret; } nkf_char w_iconv(nkf_char c2, nkf_char c1, nkf_char c0) { nkf_char ret = 0; static const int w_iconv_utf8_1st_byte[] = { /* 0xC0 - 0xFF */ 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 33, 33, 40, 41, 41, 41, 42, 43, 43, 43, 50, 50, 50, 50, 60, 60, 70, 70}; if (c2 < 0 || 0xff < c2) { }else if (c2 == 0) { /* 0 : 1 byte*/ c0 = 0; } else if ((c2 & 0xc0) == 0x80) { /* 0x80-0xbf : trail byte */ return 0; } else{ switch (w_iconv_utf8_1st_byte[c2 - 0xC0]) { case 21: if (c1 < 0x80 || 0xBF < c1) return 0; break; case 30: if (c0 == 0) return -1; if (c1 < 0xA0 || 0xBF < c1 || (c0 & 0xc0) != 0x80) return 0; break; case 31: case 33: if (c0 == 0) return -1; if ((c1 & 0xc0) != 0x80 || (c0 & 0xc0) != 0x80) return 0; break; case 32: if (c0 == 0) return -1; if (c1 < 0x80 || 0x9F < c1 || (c0 & 0xc0) != 0x80) return 0; break; case 40: if (c0 == 0) return -2; if (c1 < 0x90 || 0xBF < c1 || (c0 & 0xc0c0) != 0x8080) return 0; break; case 41: if (c0 == 0) return -2; if (c1 < 0x80 || 0xBF < c1 || (c0 & 0xc0c0) != 0x8080) return 0; break; case 42: if (c0 == 0) return -2; if (c1 < 0x80 || 0x8F < c1 || (c0 & 0xc0c0) != 0x8080) return 0; break; default: return 0; break; } } if (c2 == 0 || c2 == EOF){ } else if ((c2 & 0xf8) == 0xf0) { /* 4 bytes */ c1 = CLASS_UNICODE | ww16_conv(c2, c1, c0); c2 = 0; } else { ret = w2e_conv(c2, c1, c0, &c2, &c1); } if (ret == 0){ (*oconv)(c2, c1); } return ret; } #endif #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE) void w16w_conv(nkf_char val, nkf_char *p2, nkf_char *p1, nkf_char *p0) { val &= VALUE_MASK; if (val < 0x80){ *p2 = val; *p1 = 0; *p0 = 0; }else if (val < 0x800){ *p2 = 0xc0 | (val >> 6); *p1 = 0x80 | (val & 0x3f); *p0 = 0; } else if (val <= NKF_INT32_C(0xFFFF)) { *p2 = 0xe0 | (val >> 12); *p1 = 0x80 | ((val >> 6) & 0x3f); *p0 = 0x80 | (val & 0x3f); } else if (val <= NKF_INT32_C(0x10FFFF)) { *p2 = 0xe0 | (val >> 16); *p1 = 0x80 | ((val >> 12) & 0x3f); *p0 = 0x8080 | ((val << 2) & 0x3f00)| (val & 0x3f); } else { *p2 = 0; *p1 = 0; *p0 = 0; } } #endif #ifdef UTF8_INPUT_ENABLE nkf_char ww16_conv(nkf_char c2, nkf_char c1, nkf_char c0) { nkf_char val; if (c2 >= 0xf8) { val = -1; } else if (c2 >= 0xf0){ /* c2: 1st, c1: 2nd, c0: 3rd/4th */ val = (c2 & 0x0f) << 18; val |= (c1 & 0x3f) << 12; val |= (c0 & 0x3f00) >> 2; val |= (c0 & 0x3f); }else if (c2 >= 0xe0){ val = (c2 & 0x0f) << 12; val |= (c1 & 0x3f) << 6; val |= (c0 & 0x3f); }else if (c2 >= 0xc0){ val = (c2 & 0x1f) << 6; val |= (c1 & 0x3f); }else{ val = c2; } return val; } nkf_char w16e_conv(nkf_char val, nkf_char *p2, nkf_char *p1) { nkf_char c2, c1, c0; nkf_char ret = 0; val &= VALUE_MASK; if (val < 0x80){ *p2 = 0; *p1 = val; }else{ w16w_conv(val, &c2, &c1, &c0); ret = unicode_to_jis_common(c2, c1, c0, p2, p1); #ifdef NUMCHAR_OPTION if (ret > 0){ *p2 = 0; *p1 = CLASS_UNICODE | val; ret = 0; } #endif } return ret; } #endif #ifdef UTF8_INPUT_ENABLE nkf_char w_iconv16(nkf_char c2, nkf_char c1, nkf_char c0) { nkf_char ret = 0; if ((c2==0 && c1 < 0x80) || c2==EOF) { (*oconv)(c2, c1); return 0; }else if (0xD8 <= c2 && c2 <= 0xDB) { if (c0 < NKF_INT32_C(0xDC00) || NKF_INT32_C(0xDFFF) < c0) return -2; c1 = CLASS_UNICODE | ((c2 << 18) + (c1 << 10) + c0 - NKF_INT32_C(0x35FDC00)); c2 = 0; }else if ((c2>>3) == 27) { /* unpaired surrogate */ /* return 2; */ return 1; }else ret = w16e_conv(((c2 & 0xff)<<8) + c1, &c2, &c1); if (ret) return ret; (*oconv)(c2, c1); return 0; } nkf_char w_iconv32(nkf_char c2, nkf_char c1, nkf_char c0) { int ret = 0; if ((c2 == 0 && c1 < 0x80) || c2==EOF) { } else if (is_unicode_bmp(c1)) { ret = w16e_conv(c1, &c2, &c1); } else { c2 = 0; c1 = CLASS_UNICODE | c1; } if (ret) return ret; (*oconv)(c2, c1); return 0; } nkf_char unicode_to_jis_common(nkf_char c2, nkf_char c1, nkf_char c0, nkf_char *p2, nkf_char *p1) { #if 0 extern const unsigned short *const utf8_to_euc_2bytes[]; extern const unsigned short *const utf8_to_euc_2bytes_ms[]; extern const unsigned short *const utf8_to_euc_2bytes_932[]; extern const unsigned short *const *const utf8_to_euc_3bytes[]; extern const unsigned short *const *const utf8_to_euc_3bytes_ms[]; extern const unsigned short *const *const utf8_to_euc_3bytes_932[]; #endif const unsigned short *const *pp; const unsigned short *const *const *ppp; static const int no_best_fit_chars_table_C2[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 2, 1, 1, 2, 0, 0, 1, 1, 0, 1, 0, 1, 2, 1, 1, 1, 1, 1, 1, 1}; static const int no_best_fit_chars_table_C2_ms[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0}; static const int no_best_fit_chars_table_932_C2[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0}; static const int no_best_fit_chars_table_932_C3[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1}; nkf_char ret = 0; if(c2 < 0x80){ *p2 = 0; *p1 = c2; }else if(c2 < 0xe0){ if(no_best_fit_chars_f){ if(ms_ucs_map_f == UCS_MAP_CP932){ switch(c2){ case 0xC2: if(no_best_fit_chars_table_932_C2[c1&0x3F]) return 1; break; case 0xC3: if(no_best_fit_chars_table_932_C3[c1&0x3F]) return 1; break; } }else if(!cp932inv_f){ switch(c2){ case 0xC2: if(no_best_fit_chars_table_C2[c1&0x3F]) return 1; break; case 0xC3: if(no_best_fit_chars_table_932_C3[c1&0x3F]) return 1; break; } }else if(ms_ucs_map_f == UCS_MAP_MS){ if(c2 == 0xC2 && no_best_fit_chars_table_C2_ms[c1&0x3F]) return 1; } } pp = ms_ucs_map_f == UCS_MAP_CP932 ? utf8_to_euc_2bytes_932 : ms_ucs_map_f == UCS_MAP_MS ? utf8_to_euc_2bytes_ms : utf8_to_euc_2bytes; ret = w_iconv_common(c2, c1, pp, sizeof_utf8_to_euc_2bytes, p2, p1); }else if(c0 < 0xF0){ if(no_best_fit_chars_f){ if(ms_ucs_map_f == UCS_MAP_CP932){ if(c2 == 0xE3 && c1 == 0x82 && c0 == 0x94) return 1; }else if(ms_ucs_map_f == UCS_MAP_MS){ switch(c2){ case 0xE2: switch(c1){ case 0x80: if(c0 == 0x94 || c0 == 0x96 || c0 == 0xBE) return 1; break; case 0x88: if(c0 == 0x92) return 1; break; } break; case 0xE3: if(c1 == 0x80 || c0 == 0x9C) return 1; break; } }else{ switch(c2){ case 0xE2: switch(c1){ case 0x80: if(c0 == 0x95) return 1; break; case 0x88: if(c0 == 0xA5) return 1; break; } break; case 0xEF: switch(c1){ case 0xBC: if(c0 == 0x8D) return 1; break; case 0xBD: if(c0 == 0x9E && !cp932inv_f) return 1; break; case 0xBF: if(0xA0 <= c0 && c0 <= 0xA5) return 1; break; } break; } } } ppp = ms_ucs_map_f == UCS_MAP_CP932 ? utf8_to_euc_3bytes_932 : ms_ucs_map_f == UCS_MAP_MS ? utf8_to_euc_3bytes_ms : utf8_to_euc_3bytes; ret = w_iconv_common(c1, c0, ppp[c2 - 0xE0], sizeof_utf8_to_euc_C2, p2, p1); }else return -1; #ifdef SHIFTJIS_CP932 if (!ret && !cp932inv_f && is_eucg3(*p2)) { nkf_char s2, s1; if (e2s_conv(*p2, *p1, &s2, &s1) == 0) { s2e_conv(s2, s1, p2, p1); }else{ ret = 1; } } #endif return ret; } nkf_char w_iconv_common(nkf_char c1, nkf_char c0, const unsigned short *const *pp, nkf_char psize, nkf_char *p2, nkf_char *p1) { nkf_char c2; const unsigned short *p; unsigned short val; if (pp == 0) return 1; c1 -= 0x80; if (c1 < 0 || psize <= c1) return 1; p = pp[c1]; if (p == 0) return 1; c0 -= 0x80; if (c0 < 0 || sizeof_utf8_to_euc_C2 <= c0) return 1; val = p[c0]; if (val == 0) return 1; if (no_cp932ext_f && ( (val>>8) == 0x2D || /* NEC special characters */ val > NKF_INT32_C(0xF300) /* IBM extended characters */ )) return 1; c2 = val >> 8; if (val > 0x7FFF){ c2 &= 0x7f; c2 |= PREFIX_EUCG3; } if (c2 == SO) c2 = X0201; c1 = val & 0x7f; if (p2) *p2 = c2; if (p1) *p1 = c1; return 0; } void nkf_each_char_to_hex(void (*f)(nkf_char c2,nkf_char c1), nkf_char c) { const char *hex = "0123456789ABCDEF"; int shift = 20; c &= VALUE_MASK; while(shift >= 0){ if(c >= 1<= 0){ (*f)(0, hex[(c>>shift)&0xF]); shift -= 4; } }else{ shift -= 4; } } return; } void encode_fallback_html(nkf_char c) { (*oconv)(0, '&'); (*oconv)(0, '#'); c &= VALUE_MASK; if(c >= NKF_INT32_C(1000000)) (*oconv)(0, 0x30+(c/NKF_INT32_C(1000000))%10); if(c >= NKF_INT32_C(100000)) (*oconv)(0, 0x30+(c/NKF_INT32_C(100000) )%10); if(c >= 10000) (*oconv)(0, 0x30+(c/10000 )%10); if(c >= 1000) (*oconv)(0, 0x30+(c/1000 )%10); if(c >= 100) (*oconv)(0, 0x30+(c/100 )%10); if(c >= 10) (*oconv)(0, 0x30+(c/10 )%10); if(c >= 0) (*oconv)(0, 0x30+ c %10); (*oconv)(0, ';'); return; } void encode_fallback_xml(nkf_char c) { (*oconv)(0, '&'); (*oconv)(0, '#'); (*oconv)(0, 'x'); nkf_each_char_to_hex(oconv, c); (*oconv)(0, ';'); return; } void encode_fallback_java(nkf_char c) { const char *hex = "0123456789ABCDEF"; (*oconv)(0, '\\'); c &= VALUE_MASK; if(!is_unicode_bmp(c)){ (*oconv)(0, 'U'); (*oconv)(0, '0'); (*oconv)(0, '0'); (*oconv)(0, hex[(c>>20)&0xF]); (*oconv)(0, hex[(c>>16)&0xF]); }else{ (*oconv)(0, 'u'); } (*oconv)(0, hex[(c>>12)&0xF]); (*oconv)(0, hex[(c>> 8)&0xF]); (*oconv)(0, hex[(c>> 4)&0xF]); (*oconv)(0, hex[ c &0xF]); return; } void encode_fallback_perl(nkf_char c) { (*oconv)(0, '\\'); (*oconv)(0, 'x'); (*oconv)(0, '{'); nkf_each_char_to_hex(oconv, c); (*oconv)(0, '}'); return; } void encode_fallback_subchar(nkf_char c) { c = unicode_subchar; (*oconv)((c>>8)&0xFF, c&0xFF); return; } #endif #ifdef UTF8_OUTPUT_ENABLE nkf_char e2w_conv(nkf_char c2, nkf_char c1) { #if 0 extern const unsigned short euc_to_utf8_1byte[]; extern const unsigned short *const euc_to_utf8_2bytes[]; extern const unsigned short *const euc_to_utf8_2bytes_ms[]; extern const unsigned short *const x0212_to_utf8_2bytes[]; #endif const unsigned short *p; if (c2 == X0201) { p = euc_to_utf8_1byte; #ifdef X0212_ENABLE } else if (is_eucg3(c2)){ if(ms_ucs_map_f == UCS_MAP_ASCII&& c2 == NKF_INT32_C(0x8F22) && c1 == 0x43){ return 0xA6; } c2 = (c2&0x7f) - 0x21; if (0<=c2 && c2> 6)); (*o_putc)(0x80 | (val & 0x3f)); } else if (val <= NKF_INT32_C(0xFFFF)) { (*o_putc)(0xE0 | (val >> 12)); (*o_putc)(0x80 | ((val >> 6) & 0x3f)); (*o_putc)(0x80 | (val & 0x3f)); } else if (val <= NKF_INT32_C(0x10FFFF)) { (*o_putc)(0xF0 | ( val>>18)); (*o_putc)(0x80 | ((val>>12) & 0x3f)); (*o_putc)(0x80 | ((val>> 6) & 0x3f)); (*o_putc)(0x80 | ( val & 0x3f)); } return; } #endif if (c2 == 0) { output_mode = ASCII; (*o_putc)(c1); } else if (c2 == ISO8859_1) { output_mode = ISO8859_1; (*o_putc)(c1 | 0x080); } else { output_mode = UTF8; val = e2w_conv(c2, c1); if (val){ w16w_conv(val, &c2, &c1, &c0); (*o_putc)(c2); if (c1){ (*o_putc)(c1); if (c0) (*o_putc)(c0); } } } } void w_oconv16(nkf_char c2, nkf_char c1) { if (output_bom_f) { output_bom_f = FALSE; if (output_endian == ENDIAN_LITTLE){ (*o_putc)((unsigned char)'\377'); (*o_putc)('\376'); }else{ (*o_putc)('\376'); (*o_putc)((unsigned char)'\377'); } } if (c2 == EOF) { (*o_putc)(EOF); return; } if (c2 == ISO8859_1) { c2 = 0; c1 |= 0x80; #ifdef NUMCHAR_OPTION } else if (c2 == 0 && is_unicode_capsule(c1)) { if (is_unicode_bmp(c1)) { c2 = (c1 >> 8) & 0xff; c1 &= 0xff; } else { c1 &= VALUE_MASK; if (c1 <= UNICODE_MAX) { c2 = (c1 >> 10) + NKF_INT32_C(0xD7C0); /* high surrogate */ c1 = (c1 & 0x3FF) + NKF_INT32_C(0xDC00); /* low surrogate */ if (output_endian == ENDIAN_LITTLE){ (*o_putc)(c2 & 0xff); (*o_putc)((c2 >> 8) & 0xff); (*o_putc)(c1 & 0xff); (*o_putc)((c1 >> 8) & 0xff); }else{ (*o_putc)((c2 >> 8) & 0xff); (*o_putc)(c2 & 0xff); (*o_putc)((c1 >> 8) & 0xff); (*o_putc)(c1 & 0xff); } } return; } #endif } else if (c2) { nkf_char val = e2w_conv(c2, c1); c2 = (val >> 8) & 0xff; c1 = val & 0xff; if (!val) return; } if (output_endian == ENDIAN_LITTLE){ (*o_putc)(c1); (*o_putc)(c2); }else{ (*o_putc)(c2); (*o_putc)(c1); } } void w_oconv32(nkf_char c2, nkf_char c1) { if (output_bom_f) { output_bom_f = FALSE; if (output_endian == ENDIAN_LITTLE){ (*o_putc)((unsigned char)'\377'); (*o_putc)('\376'); (*o_putc)('\000'); (*o_putc)('\000'); }else{ (*o_putc)('\000'); (*o_putc)('\000'); (*o_putc)('\376'); (*o_putc)((unsigned char)'\377'); } } if (c2 == EOF) { (*o_putc)(EOF); return; } if (c2 == ISO8859_1) { c1 |= 0x80; #ifdef NUMCHAR_OPTION } else if (c2 == 0 && is_unicode_capsule(c1)) { c1 &= VALUE_MASK; #endif } else if (c2) { c1 = e2w_conv(c2, c1); if (!c1) return; } if (output_endian == ENDIAN_LITTLE){ (*o_putc)( c1 & NKF_INT32_C(0x000000FF)); (*o_putc)((c1 & NKF_INT32_C(0x0000FF00)) >> 8); (*o_putc)((c1 & NKF_INT32_C(0x00FF0000)) >> 16); (*o_putc)('\000'); }else{ (*o_putc)('\000'); (*o_putc)((c1 & NKF_INT32_C(0x00FF0000)) >> 16); (*o_putc)((c1 & NKF_INT32_C(0x0000FF00)) >> 8); (*o_putc)( c1 & NKF_INT32_C(0x000000FF)); } } #endif void e_oconv(nkf_char c2, nkf_char c1) { #ifdef NUMCHAR_OPTION if (c2 == 0 && is_unicode_capsule(c1)){ w16e_conv(c1, &c2, &c1); if (c2 == 0 && is_unicode_capsule(c1)){ c2 = c1 & VALUE_MASK; if (x0212_f && 0xE000 <= c2 && c2 <= 0xE757) { /* eucJP-ms UDC */ c1 &= 0xFFF; c2 = c1 / 94; c2 += c2 < 10 ? 0x75 : 0x8FEB; c1 = 0x21 + c1 % 94; if (is_eucg3(c2)){ (*o_putc)(0x8f); (*o_putc)((c2 & 0x7f) | 0x080); (*o_putc)(c1 | 0x080); }else{ (*o_putc)((c2 & 0x7f) | 0x080); (*o_putc)(c1 | 0x080); } return; } else { if (encode_fallback) (*encode_fallback)(c1); return; } } } #endif if (c2 == EOF) { (*o_putc)(EOF); return; } else if (c2 == 0) { output_mode = ASCII; (*o_putc)(c1); } else if (c2 == X0201) { output_mode = JAPANESE_EUC; (*o_putc)(SSO); (*o_putc)(c1|0x80); } else if (c2 == ISO8859_1) { output_mode = ISO8859_1; (*o_putc)(c1 | 0x080); #ifdef X0212_ENABLE } else if (is_eucg3(c2)){ output_mode = JAPANESE_EUC; #ifdef SHIFTJIS_CP932 if (!cp932inv_f){ nkf_char s2, s1; if (e2s_conv(c2, c1, &s2, &s1) == 0){ s2e_conv(s2, s1, &c2, &c1); } } #endif if (c2 == 0) { output_mode = ASCII; (*o_putc)(c1); }else if (is_eucg3(c2)){ if (x0212_f){ (*o_putc)(0x8f); (*o_putc)((c2 & 0x7f) | 0x080); (*o_putc)(c1 | 0x080); } }else{ (*o_putc)((c2 & 0x7f) | 0x080); (*o_putc)(c1 | 0x080); } #endif } else { if (!nkf_isgraph(c1) || !nkf_isgraph(c2)) { set_iconv(FALSE, 0); return; /* too late to rescue this char */ } output_mode = JAPANESE_EUC; (*o_putc)(c2 | 0x080); (*o_putc)(c1 | 0x080); } } #ifdef X0212_ENABLE nkf_char x0212_shift(nkf_char c) { nkf_char ret = c; c &= 0x7f; if (is_eucg3(ret)){ if (0x75 <= c && c <= 0x7f){ ret = c + (0x109 - 0x75); } }else{ if (0x75 <= c && c <= 0x7f){ ret = c + (0x113 - 0x75); } } return ret; } nkf_char x0212_unshift(nkf_char c) { nkf_char ret = c; if (0x7f <= c && c <= 0x88){ ret = c + (0x75 - 0x7f); }else if (0x89 <= c && c <= 0x92){ ret = PREFIX_EUCG3 | 0x80 | (c + (0x75 - 0x89)); } return ret; } #endif /* X0212_ENABLE */ nkf_char e2s_conv(nkf_char c2, nkf_char c1, nkf_char *p2, nkf_char *p1) { nkf_char ndx; if (is_eucg3(c2)){ ndx = c2 & 0x7f; if (x0213_f){ if((0x21 <= ndx && ndx <= 0x2F)){ if (p2) *p2 = ((ndx - 1) >> 1) + 0xec - ndx / 8 * 3; if (p1) *p1 = c1 + ((ndx & 1) ? ((c1 < 0x60) ? 0x1f : 0x20) : 0x7e); return 0; }else if(0x6E <= ndx && ndx <= 0x7E){ if (p2) *p2 = ((ndx - 1) >> 1) + 0xbe; if (p1) *p1 = c1 + ((ndx & 1) ? ((c1 < 0x60) ? 0x1f : 0x20) : 0x7e); return 0; } return 1; } #ifdef X0212_ENABLE else if(nkf_isgraph(ndx)){ nkf_char val = 0; const unsigned short *ptr; #if 0 extern const unsigned short *const x0212_shiftjis[]; #endif ptr = x0212_shiftjis[ndx - 0x21]; if (ptr){ val = ptr[(c1 & 0x7f) - 0x21]; } if (val){ c2 = val >> 8; c1 = val & 0xff; if (p2) *p2 = c2; if (p1) *p1 = c1; return 0; } c2 = x0212_shift(c2); } #endif /* X0212_ENABLE */ } if(0x7F < c2) return 1; if (p2) *p2 = ((c2 - 1) >> 1) + ((c2 <= 0x5e) ? 0x71 : 0xb1); if (p1) *p1 = c1 + ((c2 & 1) ? ((c1 < 0x60) ? 0x1f : 0x20) : 0x7e); return 0; } void s_oconv(nkf_char c2, nkf_char c1) { #ifdef NUMCHAR_OPTION if (c2 == 0 && is_unicode_capsule(c1)){ w16e_conv(c1, &c2, &c1); if (c2 == 0 && is_unicode_capsule(c1)){ c2 = c1 & VALUE_MASK; if (!x0213_f && 0xE000 <= c2 && c2 <= 0xE757) { /* CP932 UDC */ c1 &= 0xFFF; c2 = c1 / 188 + 0xF0; c1 = c1 % 188; c1 += 0x40 + (c1 > 0x3e); (*o_putc)(c2); (*o_putc)(c1); return; } else { if(encode_fallback)(*encode_fallback)(c1); return; } } } #endif if (c2 == EOF) { (*o_putc)(EOF); return; } else if (c2 == 0) { output_mode = ASCII; (*o_putc)(c1); } else if (c2 == X0201) { output_mode = SHIFT_JIS; (*o_putc)(c1|0x80); } else if (c2 == ISO8859_1) { output_mode = ISO8859_1; (*o_putc)(c1 | 0x080); #ifdef X0212_ENABLE } else if (is_eucg3(c2)){ output_mode = SHIFT_JIS; if (e2s_conv(c2, c1, &c2, &c1) == 0){ (*o_putc)(c2); (*o_putc)(c1); } #endif } else { if (!nkf_isprint(c1) || !nkf_isprint(c2)) { set_iconv(FALSE, 0); return; /* too late to rescue this char */ } output_mode = SHIFT_JIS; e2s_conv(c2, c1, &c2, &c1); #ifdef SHIFTJIS_CP932 if (cp932inv_f && CP932INV_TABLE_BEGIN <= c2 && c2 <= CP932INV_TABLE_END){ #if 0 extern const unsigned short cp932inv[2][189]; #endif nkf_char c = cp932inv[c2 - CP932INV_TABLE_BEGIN][c1 - 0x40]; if (c){ c2 = c >> 8; c1 = c & 0xff; } } #endif /* SHIFTJIS_CP932 */ (*o_putc)(c2); if (prefix_table[(unsigned char)c1]){ (*o_putc)(prefix_table[(unsigned char)c1]); } (*o_putc)(c1); } } void j_oconv(nkf_char c2, nkf_char c1) { #ifdef NUMCHAR_OPTION if (c2 == 0 && is_unicode_capsule(c1)){ w16e_conv(c1, &c2, &c1); if (c2 == 0 && is_unicode_capsule(c1)){ c2 = c1 & VALUE_MASK; if (ms_ucs_map_f && 0xE000 <= c2 && c2 <= 0xE757) { /* CP5022x UDC */ c1 &= 0xFFF; c2 = 0x7F + c1 / 94; c1 = 0x21 + c1 % 94; } else { if (encode_fallback) (*encode_fallback)(c1); return; } } } #endif if (c2 == EOF) { if (output_mode !=ASCII && output_mode!=ISO8859_1) { (*o_putc)(ESC); (*o_putc)('('); (*o_putc)(ascii_intro); output_mode = ASCII; } (*o_putc)(EOF); #ifdef X0212_ENABLE } else if (is_eucg3(c2)){ if(x0213_f){ if(output_mode!=X0213_2){ output_mode = X0213_2; (*o_putc)(ESC); (*o_putc)('$'); (*o_putc)('('); (*o_putc)(X0213_2&0x7F); } }else{ if(output_mode!=X0212){ output_mode = X0212; (*o_putc)(ESC); (*o_putc)('$'); (*o_putc)('('); (*o_putc)(X0212&0x7F); } } (*o_putc)(c2 & 0x7f); (*o_putc)(c1); #endif } else if (c2==X0201) { if (output_mode!=X0201) { output_mode = X0201; (*o_putc)(ESC); (*o_putc)('('); (*o_putc)('I'); } (*o_putc)(c1); } else if (c2==ISO8859_1) { /* iso8859 introduction, or 8th bit on */ /* Can we convert in 7bit form using ESC-'-'-A ? Is this popular? */ output_mode = ISO8859_1; (*o_putc)(c1|0x80); } else if (c2 == 0) { if (output_mode !=ASCII && output_mode!=ISO8859_1) { (*o_putc)(ESC); (*o_putc)('('); (*o_putc)(ascii_intro); output_mode = ASCII; } (*o_putc)(c1); } else { if(ms_ucs_map_f ? c2<0x20 || 0x920) { return broken_buf[--broken_counter]; } c= (*i_bgetc)(f); if (c=='$' && broken_last != ESC && (input_mode==ASCII || input_mode==X0201)) { c1= (*i_bgetc)(f); broken_last = 0; if (c1=='@'|| c1=='B') { broken_buf[0]=c1; broken_buf[1]=c; broken_counter=2; return ESC; } else { (*i_bungetc)(c1,f); return c; } } else if (c=='(' && broken_last != ESC && (input_mode==X0208 || input_mode==X0201)) { /* ) */ c1= (*i_bgetc)(f); broken_last = 0; if (c1=='J'|| c1=='B') { broken_buf[0]=c1; broken_buf[1]=c; broken_counter=2; return ESC; } else { (*i_bungetc)(c1,f); return c; } } else { broken_last = c; return c; } } nkf_char broken_ungetc(nkf_char c, FILE *f) { if (broken_counter<2) broken_buf[broken_counter++]=c; return c; } static nkf_char prev_cr = 0; void cr_conv(nkf_char c2, nkf_char c1) { if (prev_cr) { prev_cr = 0; if (! (c2==0&&c1==NL) ) { cr_conv(0,'\n'); } } if (c2) { (*o_crconv)(c2,c1); } else if (c1=='\r') { prev_cr = c1; } else if (c1=='\n') { if (crmode_f==CRLF) { (*o_crconv)(0,'\r'); } else if (crmode_f==CR) { (*o_crconv)(0,'\r'); return; } (*o_crconv)(0,NL); } else if (c1!='\032' || crmode_f!=NL){ (*o_crconv)(c2,c1); } } /* Return value of fold_conv() \n add newline and output char \r add newline and output nothing ' ' space 0 skip 1 (or else) normal output fold state in prev (previous character) >0x80 Japanese (X0208/X0201) <0x80 ASCII \n new line ' ' space This fold algorthm does not preserve heading space in a line. This is the main difference from fmt. */ #define char_size(c2,c1) (c2?2:1) void fold_conv(nkf_char c2, nkf_char c1) { nkf_char prev0; nkf_char fold_state; if (c1== '\r' && !fold_preserve_f) { fold_state=0; /* ignore cr */ }else if (c1== '\n'&&f_prev=='\r' && fold_preserve_f) { f_prev = '\n'; fold_state=0; /* ignore cr */ } else if (c1== BS) { if (f_line>0) f_line--; fold_state = 1; } else if (c2==EOF && f_line != 0) { /* close open last line */ fold_state = '\n'; } else if ((c1=='\n' && !fold_preserve_f) || ((c1=='\r'||(c1=='\n'&&f_prev!='\r')) && fold_preserve_f)) { /* new line */ if (fold_preserve_f) { f_prev = c1; f_line = 0; fold_state = '\r'; } else if ((f_prev == c1 && !fold_preserve_f) || (f_prev == '\n' && fold_preserve_f) ) { /* duplicate newline */ if (f_line) { f_line = 0; fold_state = '\n'; /* output two newline */ } else { f_line = 0; fold_state = 1; } } else { if (f_prev&0x80) { /* Japanese? */ f_prev = c1; fold_state = 0; /* ignore given single newline */ } else if (f_prev==' ') { fold_state = 0; } else { f_prev = c1; if (++f_line<=fold_len) fold_state = ' '; else { f_line = 0; fold_state = '\r'; /* fold and output nothing */ } } } } else if (c1=='\f') { f_prev = '\n'; f_line = 0; fold_state = '\n'; /* output newline and clear */ } else if ( (c2==0 && c1==' ')|| (c2==0 && c1=='\t')|| (c2=='!'&& c1=='!')) { /* X0208 kankaku or ascii space */ if (f_prev == ' ') { fold_state = 0; /* remove duplicate spaces */ } else { f_prev = ' '; if (++f_line<=fold_len) fold_state = ' '; /* output ASCII space only */ else { f_prev = ' '; f_line = 0; fold_state = '\r'; /* fold and output nothing */ } } } else { prev0 = f_prev; /* we still need this one... , but almost done */ f_prev = c1; if (c2 || c2==X0201) f_prev |= 0x80; /* this is Japanese */ f_line += char_size(c2,c1); if (f_line<=fold_len) { /* normal case */ fold_state = 1; } else { if (f_line>fold_len+fold_margin) { /* too many kinsoku suspension */ f_line = char_size(c2,c1); fold_state = '\n'; /* We can't wait, do fold now */ } else if (c2==X0201) { /* simple kinsoku rules return 1 means no folding */ if (c1==(0xde&0x7f)) fold_state = 1; /* $B!+(B*/ else if (c1==(0xdf&0x7f)) fold_state = 1; /* $B!,(B*/ else if (c1==(0xa4&0x7f)) fold_state = 1; /* $B!#(B*/ else if (c1==(0xa3&0x7f)) fold_state = 1; /* $B!$(B*/ else if (c1==(0xa1&0x7f)) fold_state = 1; /* $B!W(B*/ else if (c1==(0xb0&0x7f)) fold_state = 1; /* - */ else if (SPACE<=c1 && c1<=(0xdf&0x7f)) { /* X0201 */ f_line = 1; fold_state = '\n';/* add one new f_line before this character */ } else { f_line = 1; fold_state = '\n';/* add one new f_line before this character */ } } else if (c2==0) { /* kinsoku point in ASCII */ if ( c1==')'|| /* { [ ( */ c1==']'|| c1=='}'|| c1=='.'|| c1==','|| c1=='!'|| c1=='?'|| c1=='/'|| c1==':'|| c1==';' ) { fold_state = 1; /* just after special */ } else if (!is_alnum(prev0)) { f_line = char_size(c2,c1); fold_state = '\n'; } else if ((prev0==' ') || /* ignored new f_line */ (prev0=='\n')|| /* ignored new f_line */ (prev0&0x80)) { /* X0208 - ASCII */ f_line = char_size(c2,c1); fold_state = '\n';/* add one new f_line before this character */ } else { fold_state = 1; /* default no fold in ASCII */ } } else { if (c2=='!') { if (c1=='"') fold_state = 1; /* $B!"(B */ else if (c1=='#') fold_state = 1; /* $B!#(B */ else if (c1=='W') fold_state = 1; /* $B!W(B */ else if (c1=='K') fold_state = 1; /* $B!K(B */ else if (c1=='$') fold_state = 1; /* $B!$(B */ else if (c1=='%') fold_state = 1; /* $B!%(B */ else if (c1=='\'') fold_state = 1; /* $B!\(B */ else if (c1=='(') fold_state = 1; /* $B!((B */ else if (c1==')') fold_state = 1; /* $B!)(B */ else if (c1=='*') fold_state = 1; /* $B!*(B */ else if (c1=='+') fold_state = 1; /* $B!+(B */ else if (c1==',') fold_state = 1; /* $B!,(B */ /* default no fold in kinsoku */ else { fold_state = '\n'; f_line = char_size(c2,c1); /* add one new f_line before this character */ } } else { f_line = char_size(c2,c1); fold_state = '\n'; /* add one new f_line before this character */ } } } } /* terminator process */ switch(fold_state) { case '\n': (*o_fconv)(0,'\n'); (*o_fconv)(c2,c1); break; case 0: return; case '\r': (*o_fconv)(0,'\n'); break; case '\t': case ' ': (*o_fconv)(0,' '); break; default: (*o_fconv)(c2,c1); } } nkf_char z_prev2=0,z_prev1=0; void z_conv(nkf_char c2, nkf_char c1) { /* if (c2) c1 &= 0x7f; assertion */ if (x0201_f && z_prev2==X0201) { /* X0201 */ if (c1==(0xde&0x7f)) { /* $BByE@(B */ z_prev2=0; (*o_zconv)(dv[(z_prev1-SPACE)*2],dv[(z_prev1-SPACE)*2+1]); return; } else if (c1==(0xdf&0x7f)&&ev[(z_prev1-SPACE)*2]) { /* $BH>ByE@(B */ z_prev2=0; (*o_zconv)(ev[(z_prev1-SPACE)*2],ev[(z_prev1-SPACE)*2+1]); return; } else { z_prev2=0; (*o_zconv)(cv[(z_prev1-SPACE)*2],cv[(z_prev1-SPACE)*2+1]); } } if (c2==EOF) { (*o_zconv)(c2,c1); return; } if (x0201_f && c2==X0201) { if (dv[(c1-SPACE)*2]||ev[(c1-SPACE)*2]) { /* wait for $BByE@(B or $BH>ByE@(B */ z_prev1 = c1; z_prev2 = c2; return; } else { (*o_zconv)(cv[(c1-SPACE)*2],cv[(c1-SPACE)*2+1]); return; } } /* JISX0208 Alphabet */ if (alpha_f && c2 == 0x23 ) { c2 = 0; } else if (alpha_f && c2 == 0x21 ) { /* JISX0208 Kigou */ if (0x21==c1) { if (alpha_f&0x2) { c1 = ' '; c2 = 0; } else if (alpha_f&0x4) { (*o_zconv)(0,' '); (*o_zconv)(0,' '); return; } } else if (0x20': entity = ">"; break; case '<': entity = "<"; break; case '\"': entity = """; break; case '&': entity = "&"; break; } if (entity){ while (*entity) (*o_zconv)(0, *entity++); return; } } } } (*o_zconv)(c2,c1); } #define rot13(c) ( \ ( c < 'A' ) ? c: \ (c <= 'M') ? (c + 13): \ (c <= 'Z') ? (c - 13): \ (c < 'a') ? (c): \ (c <= 'm') ? (c + 13): \ (c <= 'z') ? (c - 13): \ (c) \ ) #define rot47(c) ( \ ( c < '!' ) ? c: \ ( c <= 'O' ) ? (c + 47) : \ ( c <= '~' ) ? (c - 47) : \ c \ ) void rot_conv(nkf_char c2, nkf_char c1) { if (c2==0 || c2==X0201 || c2==ISO8859_1) { c1 = rot13(c1); } else if (c2) { c1 = rot47(c1); c2 = rot47(c2); } (*o_rot_conv)(c2,c1); } void hira_conv(nkf_char c2, nkf_char c1) { if (hira_f & 1) { if (c2 == 0x25) { if (0x20 < c1 && c1 < 0x74) { c2 = 0x24; (*o_hira_conv)(c2,c1); return; } else if (c1 == 0x74 && (output_conv == w_oconv || output_conv == w_oconv16)) { c2 = 0; c1 = CLASS_UNICODE | 0x3094; (*o_hira_conv)(c2,c1); return; } } else if (c2 == 0x21 && (c1 == 0x33 || c1 == 0x34)) { c1 += 2; (*o_hira_conv)(c2,c1); return; } } if (hira_f & 2) { if (c2 == 0 && c1 == (CLASS_UNICODE | 0x3094)) { c2 = 0x25; c1 = 0x74; } else if (c2 == 0x24 && 0x20 < c1 && c1 < 0x74) { c2 = 0x25; } else if (c2 == 0x21 && (c1 == 0x35 || c1 == 0x36)) { c1 -= 2; } } (*o_hira_conv)(c2,c1); } void iso2022jp_check_conv(nkf_char c2, nkf_char c1) { static const nkf_char range[RANGE_NUM_MAX][2] = { {0x222f, 0x2239,}, {0x2242, 0x2249,}, {0x2251, 0x225b,}, {0x226b, 0x2271,}, {0x227a, 0x227d,}, {0x2321, 0x232f,}, {0x233a, 0x2340,}, {0x235b, 0x2360,}, {0x237b, 0x237e,}, {0x2474, 0x247e,}, {0x2577, 0x257e,}, {0x2639, 0x2640,}, {0x2659, 0x267e,}, {0x2742, 0x2750,}, {0x2772, 0x277e,}, {0x2841, 0x287e,}, {0x4f54, 0x4f7e,}, {0x7425, 0x747e}, }; nkf_char i; nkf_char start, end, c; if(c2 >= 0x00 && c2 <= 0x20 && c1 >= 0x7f && c1 <= 0xff) { c2 = GETA1; c1 = GETA2; } if((c2 >= 0x29 && c2 <= 0x2f) || (c2 >= 0x75 && c2 <= 0x7e)) { c2 = GETA1; c1 = GETA2; } for (i = 0; i < RANGE_NUM_MAX; i++) { start = range[i][0]; end = range[i][1]; c = (c2 << 8) + c1; if (c >= start && c <= end) { c2 = GETA1; c1 = GETA2; } } (*o_iso2022jp_check_conv)(c2,c1); } /* This converts =?ISO-2022-JP?B?HOGE HOGE?= */ const unsigned char *mime_pattern[] = { (const unsigned char *)"\075?EUC-JP?B?", (const unsigned char *)"\075?SHIFT_JIS?B?", (const unsigned char *)"\075?ISO-8859-1?Q?", (const unsigned char *)"\075?ISO-8859-1?B?", (const unsigned char *)"\075?ISO-2022-JP?B?", (const unsigned char *)"\075?ISO-2022-JP?Q?", #if defined(UTF8_INPUT_ENABLE) (const unsigned char *)"\075?UTF-8?B?", (const unsigned char *)"\075?UTF-8?Q?", #endif (const unsigned char *)"\075?US-ASCII?Q?", NULL }; /* $B3:Ev$9$k%3!<%I$NM%@hEY$r>e$2$k$?$a$NL\0u(B */ nkf_char (*mime_priority_func[])(nkf_char c2, nkf_char c1, nkf_char c0) = { e_iconv, s_iconv, 0, 0, 0, 0, #if defined(UTF8_INPUT_ENABLE) w_iconv, w_iconv, #endif 0, }; const nkf_char mime_encode[] = { JAPANESE_EUC, SHIFT_JIS,ISO8859_1, ISO8859_1, X0208, X0201, #if defined(UTF8_INPUT_ENABLE) UTF8, UTF8, #endif ASCII, 0 }; const nkf_char mime_encode_method[] = { 'B', 'B','Q', 'B', 'B', 'Q', #if defined(UTF8_INPUT_ENABLE) 'B', 'Q', #endif 'Q', 0 }; #define MAXRECOVER 20 void switch_mime_getc(void) { if (i_getc!=mime_getc) { i_mgetc = i_getc; i_getc = mime_getc; i_mungetc = i_ungetc; i_ungetc = mime_ungetc; if(mime_f==STRICT_MIME) { i_mgetc_buf = i_mgetc; i_mgetc = mime_getc_buf; i_mungetc_buf = i_mungetc; i_mungetc = mime_ungetc_buf; } } } void unswitch_mime_getc(void) { if(mime_f==STRICT_MIME) { i_mgetc = i_mgetc_buf; i_mungetc = i_mungetc_buf; } i_getc = i_mgetc; i_ungetc = i_mungetc; if(mime_iconv_back)set_iconv(FALSE, mime_iconv_back); mime_iconv_back = NULL; } nkf_char mime_begin_strict(FILE *f) { nkf_char c1 = 0; int i,j,k; const unsigned char *p,*q; nkf_char r[MAXRECOVER]; /* recovery buffer, max mime pattern length */ mime_decode_mode = FALSE; /* =? has been checked */ j = 0; p = mime_pattern[j]; r[0]='='; r[1]='?'; for(i=2;p[i]>' ';i++) { /* start at =? */ if ( ((r[i] = c1 = (*i_getc)(f))==EOF) || nkf_toupper(c1) != p[i] ) { /* pattern fails, try next one */ q = p; while (mime_pattern[++j]) { p = mime_pattern[j]; for(k=2;k i */ if (p[k]!=q[k]) break; if (k==i && nkf_toupper(c1)==p[k]) break; } p = mime_pattern[j]; if (p) continue; /* found next one, continue */ /* all fails, output from recovery buffer */ (*i_ungetc)(c1,f); for(j=0;j 0){ (*u)(buf[i], f); --i; } return buf[0]; } nkf_char numchar_ungetc(nkf_char c, FILE *f) { return (*i_nungetc)(c, f); } #endif #ifdef UNICODE_NORMALIZATION /* Normalization Form C */ nkf_char nfc_getc(FILE *f) { nkf_char (*g)(FILE *f) = i_nfc_getc; nkf_char (*u)(nkf_char c ,FILE *f) = i_nfc_ungetc; int i=0, j, k=1, lower, upper; nkf_char buf[9]; const nkf_nfchar *array; #if 0 extern const struct normalization_pair normalization_table[]; #endif buf[i] = (*g)(f); while (k > 0 && ((buf[i] & 0xc0) != 0x80)){ lower=0, upper=NORMALIZATION_TABLE_LENGTH-1; while (upper >= lower) { j = (lower+upper) / 2; array = normalization_table[j].nfd; for (k=0; k < NORMALIZATION_TABLE_NFD_LENGTH && array[k]; k++){ if (array[k] != buf[k]){ array[k] < buf[k] ? (lower = j + 1) : (upper = j - 1); k = 0; break; } else if (k >= i) buf[++i] = (*g)(f); } if (k > 0){ array = normalization_table[j].nfc; for (i=0; i < NORMALIZATION_TABLE_NFC_LENGTH && array[i]; i++) buf[i] = (nkf_char)(array[i]); i--; break; } } while (i > 0) (*u)(buf[i--], f); } return buf[0]; } nkf_char nfc_ungetc(nkf_char c, FILE *f) { return (*i_nfc_ungetc)(c, f); } #endif /* UNICODE_NORMALIZATION */ nkf_char mime_getc(FILE *f) { nkf_char c1, c2, c3, c4, cc; nkf_char t1, t2, t3, t4, mode, exit_mode; nkf_char lwsp_count; char *lwsp_buf; char *lwsp_buf_new; nkf_char lwsp_size = 128; if (mime_top != mime_last) { /* Something is in FIFO */ return Fifo(mime_top++); } if (mime_decode_mode==1 ||mime_decode_mode==FALSE) { mime_decode_mode=FALSE; unswitch_mime_getc(); return (*i_getc)(f); } if (mimebuf_f == FIXED_MIME) exit_mode = mime_decode_mode; else exit_mode = FALSE; if (mime_decode_mode == 'Q') { if ((c1 = (*i_mgetc)(f)) == EOF) return (EOF); restart_mime_q: if (c1=='_' && mimebuf_f != FIXED_MIME) return ' '; if (c1<=' ' || DEL<=c1) { mime_decode_mode = exit_mode; /* prepare for quit */ return c1; } if (c1!='=' && (c1!='?' || mimebuf_f == FIXED_MIME)) { return c1; } mime_decode_mode = exit_mode; /* prepare for quit */ if ((c2 = (*i_mgetc)(f)) == EOF) return (EOF); if (c1=='?'&&c2=='=' && mimebuf_f != FIXED_MIME) { /* end Q encoding */ input_mode = exit_mode; lwsp_count = 0; lwsp_buf = malloc((lwsp_size+5)*sizeof(char)); if (lwsp_buf==NULL) { perror("can't malloc"); return -1; } while ((c1=(*i_getc)(f))!=EOF) { switch (c1) { case NL: case CR: if (c1==NL) { if ((c1=(*i_getc)(f))!=EOF && (c1==SPACE||c1==TAB)) { i_ungetc(SPACE,f); continue; } else { i_ungetc(c1,f); } c1 = NL; } else { if ((c1=(*i_getc)(f))!=EOF && c1 == NL) { if ((c1=(*i_getc)(f))!=EOF && (c1==SPACE||c1==TAB)) { i_ungetc(SPACE,f); continue; } else { i_ungetc(c1,f); } i_ungetc(NL,f); } else { i_ungetc(c1,f); } c1 = CR; } break; case SPACE: case TAB: lwsp_buf[lwsp_count] = (unsigned char)c1; if (lwsp_count++>lwsp_size){ lwsp_size <<= 1; lwsp_buf_new = realloc(lwsp_buf, (lwsp_size+5)*sizeof(char)); if (lwsp_buf_new==NULL) { free(lwsp_buf); perror("can't realloc"); return -1; } lwsp_buf = lwsp_buf_new; } continue; } break; } if (lwsp_count > 0 && (c1 != '=' || (lwsp_buf[lwsp_count-1] != SPACE && lwsp_buf[lwsp_count-1] != TAB))) { i_ungetc(c1,f); for(lwsp_count--;lwsp_count>0;lwsp_count--) i_ungetc(lwsp_buf[lwsp_count],f); c1 = lwsp_buf[0]; } free(lwsp_buf); return c1; } if (c1=='='&&c2<' ') { /* this is soft wrap */ while((c1 = (*i_mgetc)(f)) <=' ') { if ((c1 = (*i_mgetc)(f)) == EOF) return (EOF); } mime_decode_mode = 'Q'; /* still in MIME */ goto restart_mime_q; } if (c1=='?') { mime_decode_mode = 'Q'; /* still in MIME */ (*i_mungetc)(c2,f); return c1; } if ((c3 = (*i_mgetc)(f)) == EOF) return (EOF); if (c2<=' ') return c2; mime_decode_mode = 'Q'; /* still in MIME */ return ((hex2bin(c2)<<4) + hex2bin(c3)); } if (mime_decode_mode != 'B') { mime_decode_mode = FALSE; return (*i_mgetc)(f); } /* Base64 encoding */ /* MIME allows line break in the middle of Base64, but we are very pessimistic in decoding in unbuf mode because MIME encoded code may broken by less or editor's control sequence (such as ESC-[-K in unbuffered mode. ignore incomplete MIME. */ mode = mime_decode_mode; mime_decode_mode = exit_mode; /* prepare for quit */ while ((c1 = (*i_mgetc)(f))<=' ') { if (c1==EOF) return (EOF); } mime_c2_retry: if ((c2 = (*i_mgetc)(f))<=' ') { if (c2==EOF) return (EOF); if (mime_f != STRICT_MIME) goto mime_c2_retry; if (mimebuf_f!=FIXED_MIME) input_mode = ASCII; return c2; } if ((c1 == '?') && (c2 == '=')) { input_mode = ASCII; lwsp_count = 0; lwsp_buf = malloc((lwsp_size+5)*sizeof(char)); if (lwsp_buf==NULL) { perror("can't malloc"); return -1; } while ((c1=(*i_getc)(f))!=EOF) { switch (c1) { case NL: case CR: if (c1==NL) { if ((c1=(*i_getc)(f))!=EOF && (c1==SPACE||c1==TAB)) { i_ungetc(SPACE,f); continue; } else { i_ungetc(c1,f); } c1 = NL; } else { if ((c1=(*i_getc)(f))!=EOF) { if (c1==SPACE) { i_ungetc(SPACE,f); continue; } else if ((c1=(*i_getc)(f))!=EOF && (c1==SPACE||c1==TAB)) { i_ungetc(SPACE,f); continue; } else { i_ungetc(c1,f); } i_ungetc(NL,f); } else { i_ungetc(c1,f); } c1 = CR; } break; case SPACE: case TAB: lwsp_buf[lwsp_count] = (unsigned char)c1; if (lwsp_count++>lwsp_size){ lwsp_size <<= 1; lwsp_buf_new = realloc(lwsp_buf, (lwsp_size+5)*sizeof(char)); if (lwsp_buf_new==NULL) { free(lwsp_buf); perror("can't realloc"); return -1; } lwsp_buf = lwsp_buf_new; } continue; } break; } if (lwsp_count > 0 && (c1 != '=' || (lwsp_buf[lwsp_count-1] != SPACE && lwsp_buf[lwsp_count-1] != TAB))) { i_ungetc(c1,f); for(lwsp_count--;lwsp_count>0;lwsp_count--) i_ungetc(lwsp_buf[lwsp_count],f); c1 = lwsp_buf[0]; } free(lwsp_buf); return c1; } mime_c3_retry: if ((c3 = (*i_mgetc)(f))<=' ') { if (c3==EOF) return (EOF); if (mime_f != STRICT_MIME) goto mime_c3_retry; if (mimebuf_f!=FIXED_MIME) input_mode = ASCII; return c3; } mime_c4_retry: if ((c4 = (*i_mgetc)(f))<=' ') { if (c4==EOF) return (EOF); if (mime_f != STRICT_MIME) goto mime_c4_retry; if (mimebuf_f!=FIXED_MIME) input_mode = ASCII; return c4; } mime_decode_mode = mode; /* still in MIME sigh... */ /* BASE 64 decoding */ t1 = 0x3f & base64decode(c1); t2 = 0x3f & base64decode(c2); t3 = 0x3f & base64decode(c3); t4 = 0x3f & base64decode(c4); cc = ((t1 << 2) & 0x0fc) | ((t2 >> 4) & 0x03); if (c2 != '=') { Fifo(mime_last++) = (unsigned char)cc; cc = ((t2 << 4) & 0x0f0) | ((t3 >> 2) & 0x0f); if (c3 != '=') { Fifo(mime_last++) = (unsigned char)cc; cc = ((t3 << 6) & 0x0c0) | (t4 & 0x3f); if (c4 != '=') Fifo(mime_last++) = (unsigned char)cc; } } else { return c1; } return Fifo(mime_top++); } nkf_char mime_ungetc(nkf_char c, FILE *f) { Fifo(--mime_top) = (unsigned char)c; return c; } nkf_char mime_integrity(FILE *f, const unsigned char *p) { nkf_char c,d; unsigned int q; /* In buffered mode, read until =? or NL or buffer full */ mime_input = mime_top; mime_last = mime_top; while(*p) Fifo(mime_input++) = *p++; d = 0; q = mime_input; while((c=(*i_getc)(f))!=EOF) { if (((mime_input-mime_top)&MIME_BUF_MASK)==0) { break; /* buffer full */ } if (c=='=' && d=='?') { /* checked. skip header, start decode */ Fifo(mime_input++) = (unsigned char)c; /* mime_last_input = mime_input; */ mime_input = q; switch_mime_getc(); return 1; } if (!( (c=='+'||c=='/'|| c=='=' || c=='?' || is_alnum(c)))) break; /* Should we check length mod 4? */ Fifo(mime_input++) = (unsigned char)c; d=c; } /* In case of Incomplete MIME, no MIME decode */ Fifo(mime_input++) = (unsigned char)c; mime_last = mime_input; /* point undecoded buffer */ mime_decode_mode = 1; /* no decode on Fifo last in mime_getc */ switch_mime_getc(); /* anyway we need buffered getc */ return 1; } nkf_char base64decode(nkf_char c) { int i; if (c > '@') { if (c < '[') { i = c - 'A'; /* A..Z 0-25 */ } else { i = c - 'G' /* - 'a' + 26 */ ; /* a..z 26-51 */ } } else if (c > '/') { i = c - '0' + '4' /* - '0' + 52 */ ; /* 0..9 52-61 */ } else if (c == '+') { i = '>' /* 62 */ ; /* + 62 */ } else { i = '?' /* 63 */ ; /* / 63 */ } return (i); } static const char basis_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static nkf_char b64c; #define MIMEOUT_BUF_LENGTH (60) char mimeout_buf[MIMEOUT_BUF_LENGTH+1]; int mimeout_buf_count = 0; int mimeout_preserve_space = 0; #define itoh4(c) (c>=10?c+'A'-10:c+'0') void open_mime(nkf_char mode) { const unsigned char *p; int i; int j; p = mime_pattern[0]; for(i=0;mime_encode[i];i++) { if (mode == mime_encode[i]) { p = mime_pattern[i]; break; } } mimeout_mode = mime_encode_method[i]; i = 0; if (base64_count>45) { if (mimeout_buf_count>0 && nkf_isblank(mimeout_buf[i])){ (*o_mputc)(mimeout_buf[i]); i++; } (*o_mputc)(NL); (*o_mputc)(SPACE); base64_count = 1; if (!mimeout_preserve_space && mimeout_buf_count>0 && (mimeout_buf[i]==SPACE || mimeout_buf[i]==TAB || mimeout_buf[i]==CR || mimeout_buf[i]==NL )) { i++; } } if (!mimeout_preserve_space) { for (;i>2]); mimeout_mode=2; base64_count ++; break; case 2: (*o_mputc)(basis_64[((b64c & 0x3)<< 4) | ((c & 0xF0) >> 4)]); b64c=c; mimeout_mode=1; base64_count ++; break; case 1: (*o_mputc)(basis_64[((b64c & 0xF) << 2) | ((c & 0xC0) >>6)]); (*o_mputc)(basis_64[c & 0x3F]); mimeout_mode='B'; base64_count += 2; break; default: (*o_mputc)(c); base64_count++; break; } } nkf_char mime_lastchar2, mime_lastchar1; void mime_prechar(nkf_char c2, nkf_char c1) { if (mimeout_mode){ if (c2){ if (base64_count + mimeout_buf_count/3*4> 66){ (*o_base64conv)(EOF,0); (*o_base64conv)(0,NL); (*o_base64conv)(0,SPACE); } }/*else if (mime_lastchar2){ if (c1 <=DEL && !nkf_isspace(c1)){ (*o_base64conv)(0,SPACE); } }*/ }/*else{ if (c2 && mime_lastchar2 == 0 && mime_lastchar1 && !nkf_isspace(mime_lastchar1)){ (*o_base64conv)(0,SPACE); } }*/ mime_lastchar2 = c2; mime_lastchar1 = c1; } void mime_putc(nkf_char c) { int i, j; nkf_char lastchar; if (mimeout_f == FIXED_MIME){ if (mimeout_mode == 'Q'){ if (base64_count > 71){ if (c!=CR && c!=NL) { (*o_mputc)('='); (*o_mputc)(NL); } base64_count = 0; } }else{ if (base64_count > 71){ eof_mime(); (*o_mputc)(NL); base64_count = 0; } if (c == EOF) { /* c==EOF */ eof_mime(); } } if (c != EOF) { /* c==EOF */ mimeout_addchar(c); } return; } /* mimeout_f != FIXED_MIME */ if (c == EOF) { /* c==EOF */ j = mimeout_buf_count; mimeout_buf_count = 0; i = 0; if (mimeout_mode) { for (;i 0){ lastchar = mimeout_buf[mimeout_buf_count - 1]; }else{ lastchar = -1; } if (!mimeout_mode) { if (c <= DEL && (output_mode==ASCII ||output_mode == ISO8859_1)) { if (nkf_isspace(c)) { if (c==CR || c==NL) { base64_count=0; } for (i=0;i 1 && base64_count + mimeout_buf_count > 76){ (*o_mputc)(NL); base64_count = 0; if (!nkf_isspace(mimeout_buf[0])){ (*o_mputc)(SPACE); base64_count++; } } mimeout_buf[mimeout_buf_count++] = (char)c; if (mimeout_buf_count>MIMEOUT_BUF_LENGTH) { open_mime(output_mode); } } return; }else{ if (lastchar==CR || lastchar == NL){ for (i=0;iMIMEOUT_BUF_LENGTH) { eof_mime(); for (i=0;i0 && SPACEMIMEOUT_BUF_LENGTH) { j = mimeout_buf_count; mimeout_buf_count = 0; for (i=0;i0) { j = mimeout_buf_count; mimeout_buf_count = 0; for (i=0;iname){ status_reinit(p++); } } unbuf_f = FALSE; estab_f = FALSE; nop_f = FALSE; binmode_f = TRUE; rot_f = FALSE; hira_f = FALSE; input_f = FALSE; alpha_f = FALSE; mime_f = STRICT_MIME; mime_decode_f = FALSE; mimebuf_f = FALSE; broken_f = FALSE; iso8859_f = FALSE; mimeout_f = FALSE; #if defined(MSDOS) || defined(__OS2__) x0201_f = TRUE; #else x0201_f = NO_X0201; #endif iso2022jp_f = FALSE; #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE) ms_ucs_map_f = UCS_MAP_ASCII; #endif #ifdef UTF8_INPUT_ENABLE no_cp932ext_f = FALSE; no_best_fit_chars_f = FALSE; encode_fallback = NULL; unicode_subchar = '?'; input_endian = ENDIAN_BIG; #endif #ifdef UTF8_OUTPUT_ENABLE output_bom_f = FALSE; output_endian = ENDIAN_BIG; #endif #ifdef UNICODE_NORMALIZATION nfc_f = FALSE; #endif #ifdef INPUT_OPTION cap_f = FALSE; url_f = FALSE; numchar_f = FALSE; #endif #ifdef CHECK_OPTION noout_f = FALSE; debug_f = FALSE; #endif guess_f = FALSE; is_inputcode_mixed = FALSE; is_inputcode_set = FALSE; #ifdef EXEC_IO exec_f = 0; #endif #ifdef SHIFTJIS_CP932 cp51932_f = TRUE; cp932inv_f = TRUE; #endif #ifdef X0212_ENABLE x0212_f = FALSE; x0213_f = FALSE; #endif { int i; for (i = 0; i < 256; i++){ prefix_table[i] = 0; } } hold_count = 0; mimeout_buf_count = 0; mimeout_mode = 0; base64_count = 0; f_line = 0; f_prev = 0; fold_preserve_f = FALSE; fold_f = FALSE; fold_len = 0; kanji_intro = DEFAULT_J; ascii_intro = DEFAULT_R; fold_margin = FOLD_MARGIN; output_conv = DEFAULT_CONV; oconv = DEFAULT_CONV; o_zconv = no_connection; o_fconv = no_connection; o_crconv = no_connection; o_rot_conv = no_connection; o_hira_conv = no_connection; o_base64conv = no_connection; o_iso2022jp_check_conv = no_connection; o_putc = std_putc; i_getc = std_getc; i_ungetc = std_ungetc; i_bgetc = std_getc; i_bungetc = std_ungetc; o_mputc = std_putc; i_mgetc = std_getc; i_mungetc = std_ungetc; i_mgetc_buf = std_getc; i_mungetc_buf = std_ungetc; output_mode = ASCII; input_mode = ASCII; shift_mode = FALSE; mime_decode_mode = FALSE; file_out_f = FALSE; crmode_f = 0; option_mode = 0; broken_counter = 0; broken_last = 0; z_prev2=0,z_prev1=0; #ifdef CHECK_OPTION iconv_for_check = 0; #endif input_codename = ""; #ifdef WIN32DLL reinitdll(); #endif /*WIN32DLL*/ } #endif void no_connection(nkf_char c2, nkf_char c1) { no_connection2(c2,c1,0); } nkf_char no_connection2(nkf_char c2, nkf_char c1, nkf_char c0) { fprintf(stderr,"nkf internal module connection failure.\n"); exit(1); return 0; /* LINT */ } #ifndef PERL_XS #ifdef WIN32DLL #define fprintf dllprintf #endif void usage(void) { fprintf(stderr,"USAGE: nkf(nkf32,wnkf,nkf2) -[flags] [in file] .. [out file for -O flag]\n"); fprintf(stderr,"Flags:\n"); fprintf(stderr,"b,u Output is buffered (DEFAULT),Output is unbuffered\n"); #ifdef DEFAULT_CODE_SJIS fprintf(stderr,"j,s,e,w Output code is JIS 7 bit, Shift_JIS (DEFAULT), EUC-JP, UTF-8N\n"); #endif #ifdef DEFAULT_CODE_JIS fprintf(stderr,"j,s,e,w Output code is JIS 7 bit (DEFAULT), Shift JIS, EUC-JP, UTF-8N\n"); #endif #ifdef DEFAULT_CODE_EUC fprintf(stderr,"j,s,e,w Output code is JIS 7 bit, Shift JIS, EUC-JP (DEFAULT), UTF-8N\n"); #endif #ifdef DEFAULT_CODE_UTF8 fprintf(stderr,"j,s,e,w Output code is JIS 7 bit, Shift JIS, EUC-JP, UTF-8N (DEFAULT)\n"); #endif #ifdef UTF8_OUTPUT_ENABLE fprintf(stderr," After 'w' you can add more options. -w[ 8 [0], 16 [[BL] [0]] ]\n"); #endif fprintf(stderr,"J,S,E,W Input assumption is JIS 7 bit , Shift JIS, EUC-JP, UTF-8\n"); #ifdef UTF8_INPUT_ENABLE fprintf(stderr," After 'W' you can add more options. -W[ 8, 16 [BL] ] \n"); #endif fprintf(stderr,"t no conversion\n"); fprintf(stderr,"i[@B] Specify the Esc Seq for JIS X 0208-1978/83 (DEFAULT B)\n"); fprintf(stderr,"o[BJH] Specify the Esc Seq for ASCII/Roman (DEFAULT B)\n"); fprintf(stderr,"r {de/en}crypt ROT13/47\n"); fprintf(stderr,"h 1 katakana->hiragana, 2 hiragana->katakana, 3 both\n"); fprintf(stderr,"v Show this usage. V: show version\n"); fprintf(stderr,"m[BQN0] MIME decode [B:base64,Q:quoted,N:non-strict,0:no decode]\n"); fprintf(stderr,"M[BQ] MIME encode [B:base64 Q:quoted]\n"); fprintf(stderr,"l ISO8859-1 (Latin-1) support\n"); fprintf(stderr,"f/F Folding: -f60 or -f or -f60-10 (fold margin 10) F preserve nl\n"); fprintf(stderr,"Z[0-3] Convert X0208 alphabet to ASCII\n"); fprintf(stderr," 1: Kankaku to 1 space 2: to 2 spaces 3: Convert to HTML Entity\n"); fprintf(stderr,"X,x Assume X0201 kana in MS-Kanji, -x preserves X0201\n"); fprintf(stderr,"B[0-2] Broken input 0: missing ESC,1: any X on ESC-[($]-X,2: ASCII on NL\n"); #ifdef MSDOS fprintf(stderr,"T Text mode output\n"); #endif fprintf(stderr,"O Output to File (DEFAULT 'nkf.out')\n"); fprintf(stderr,"I Convert non ISO-2022-JP charactor to GETA\n"); fprintf(stderr,"d,c Convert line breaks -d: LF -c: CRLF\n"); fprintf(stderr,"-L[uwm] line mode u:LF w:CRLF m:CR (DEFAULT noconversion)\n"); fprintf(stderr,"\n"); fprintf(stderr,"Long name options\n"); fprintf(stderr," --ic= --oc=\n"); fprintf(stderr," Specify the input or output codeset\n"); fprintf(stderr," --fj --unix --mac --windows\n"); fprintf(stderr," --jis --euc --sjis --utf8 --utf16 --mime --base64\n"); fprintf(stderr," Convert for the system or code\n"); fprintf(stderr," --hiragana --katakana --katakana-hiragana\n"); fprintf(stderr," To Hiragana/Katakana Conversion\n"); fprintf(stderr," --prefix= Insert escape before troublesome characters of Shift_JIS\n"); #ifdef INPUT_OPTION fprintf(stderr," --cap-input, --url-input Convert hex after ':' or '%%'\n"); #endif #ifdef NUMCHAR_OPTION fprintf(stderr," --numchar-input Convert Unicode Character Reference\n"); #endif #ifdef UTF8_INPUT_ENABLE fprintf(stderr," --fb-{skip, html, xml, perl, java, subchar}\n"); fprintf(stderr," Specify how nkf handles unassigned characters\n"); #endif #ifdef OVERWRITE fprintf(stderr," --in-place[=SUFFIX] --overwrite[=SUFFIX]\n"); fprintf(stderr," Overwrite original listed files by filtered result\n"); fprintf(stderr," --overwrite preserves timestamp of original files\n"); #endif fprintf(stderr," -g --guess Guess the input code\n"); fprintf(stderr," --help --version Show this help/the version\n"); fprintf(stderr," For more information, see also man nkf\n"); fprintf(stderr,"\n"); version(); } void version(void) { fprintf(stderr,"Network Kanji Filter Version %s (%s) " #if defined(MSDOS) && !defined(__WIN32__) && !defined(__WIN16__) && !defined(__OS2__) "for DOS" #endif #if defined(MSDOS) && defined(__WIN16__) "for Win16" #endif #if defined(MSDOS) && defined(__WIN32__) "for Win32" #endif #ifdef __OS2__ "for OS/2" #endif ,NKF_VERSION,NKF_RELEASE_DATE); fprintf(stderr,"\n%s\n",CopyRight); } #endif /*PERL_XS*/ /** ** $B%Q%C%A@):n ** ohta@src.ricoh.co.jp (Junn Ohta) ** inouet@strl.nhk.or.jp (Tomoyuki Inoue) ** kiri@pulser.win.or.jp (Tetsuaki Kiriyama) ** Kimihiko Sato ** a_kuroe@kuroe.aoba.yokohama.jp (Akihiko Kuroe) ** kono@ie.u-ryukyu.ac.jp (Shinji Kono) ** GHG00637@nifty-serve.or.jp (COW) ** **/ /* end */ ================================================ FILE: ext/nkf/nkf-utf8/utf8tbl.c ================================================ #include "config.h" #ifdef UTF8_OUTPUT_ENABLE const unsigned short euc_to_utf8_A1[] = { 0x3000, 0x3001, 0x3002, 0xFF0C, 0xFF0E, 0x30FB, 0xFF1A, 0xFF1B, 0xFF1F, 0xFF01, 0x309B, 0x309C, 0x00B4, 0xFF40, 0x00A8, 0xFF3E, 0x203E, 0xFF3F, 0x30FD, 0x30FE, 0x309D, 0x309E, 0x3003, 0x4EDD, 0x3005, 0x3006, 0x3007, 0x30FC, 0x2014, 0x2010, 0xFF0F, 0xFF3C, 0x301C, 0x2016, 0xFF5C, 0x2026, 0x2025, 0x2018, 0x2019, 0x201C, 0x201D, 0xFF08, 0xFF09, 0x3014, 0x3015, 0xFF3B, 0xFF3D, 0xFF5B, 0xFF5D, 0x3008, 0x3009, 0x300A, 0x300B, 0x300C, 0x300D, 0x300E, 0x300F, 0x3010, 0x3011, 0xFF0B, 0x2212, 0x00B1, 0x00D7, 0x00F7, 0xFF1D, 0x2260, 0xFF1C, 0xFF1E, 0x2266, 0x2267, 0x221E, 0x2234, 0x2642, 0x2640, 0x00B0, 0x2032, 0x2033, 0x2103, 0x00A5, 0xFF04, 0x00A2, 0x00A3, 0xFF05, 0xFF03, 0xFF06, 0xFF0A, 0xFF20, 0x00A7, 0x2606, 0x2605, 0x25CB, 0x25CF, 0x25CE, 0x25C7, }; /* Microsoft UCS Mapping Compatible */ const unsigned short euc_to_utf8_A1_ms[] = { 0x3000, 0x3001, 0x3002, 0xFF0C, 0xFF0E, 0x30FB, 0xFF1A, 0xFF1B, 0xFF1F, 0xFF01, 0x309B, 0x309C, 0x00B4, 0xFF40, 0x00A8, 0xFF3E, 0xFFE3, 0xFF3F, 0x30FD, 0x30FE, 0x309D, 0x309E, 0x3003, 0x4EDD, 0x3005, 0x3006, 0x3007, 0x30FC, 0x2015, 0x2010, 0xFF0F, 0xFF3C, 0xFF5E, 0x2225, 0xFF5C, 0x2026, 0x2025, 0x2018, 0x2019, 0x201C, 0x201D, 0xFF08, 0xFF09, 0x3014, 0x3015, 0xFF3B, 0xFF3D, 0xFF5B, 0xFF5D, 0x3008, 0x3009, 0x300A, 0x300B, 0x300C, 0x300D, 0x300E, 0x300F, 0x3010, 0x3011, 0xFF0B, 0xFF0D, 0x00B1, 0x00D7, 0x00F7, 0xFF1D, 0x2260, 0xFF1C, 0xFF1E, 0x2266, 0x2267, 0x221E, 0x2234, 0x2642, 0x2640, 0x00B0, 0x2032, 0x2033, 0x2103, 0xFFE5, 0xFF04, 0xFFE0, 0xFFE1, 0xFF05, 0xFF03, 0xFF06, 0xFF0A, 0xFF20, 0x00A7, 0x2606, 0x2605, 0x25CB, 0x25CF, 0x25CE, 0x25C7, }; const unsigned short euc_to_utf8_A2[] = { 0x25C6, 0x25A1, 0x25A0, 0x25B3, 0x25B2, 0x25BD, 0x25BC, 0x203B, 0x3012, 0x2192, 0x2190, 0x2191, 0x2193, 0x3013, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2208, 0x220B, 0x2286, 0x2287, 0x2282, 0x2283, 0x222A, 0x2229, 0, 0, 0, 0, 0, 0, 0, 0, 0x2227, 0x2228, 0x00AC, 0x21D2, 0x21D4, 0x2200, 0x2203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2220, 0x22A5, 0x2312, 0x2202, 0x2207, 0x2261, 0x2252, 0x226A, 0x226B, 0x221A, 0x223D, 0x221D, 0x2235, 0x222B, 0x222C, 0, 0, 0, 0, 0, 0, 0, 0x212B, 0x2030, 0x266F, 0x266D, 0x266A, 0x2020, 0x2021, 0x00B6, 0, 0, 0, 0, 0x25EF, }; /* Microsoft UCS Mapping Compatible */ const unsigned short euc_to_utf8_A2_ms[] = { 0x25C6, 0x25A1, 0x25A0, 0x25B3, 0x25B2, 0x25BD, 0x25BC, 0x203B, 0x3012, 0x2192, 0x2190, 0x2191, 0x2193, 0x3013, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2208, 0x220B, 0x2286, 0x2287, 0x2282, 0x2283, 0x222A, 0x2229, 0, 0, 0, 0, 0, 0, 0, 0, 0x2227, 0x2228, 0xFFE2, 0x21D2, 0x21D4, 0x2200, 0x2203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2220, 0x22A5, 0x2312, 0x2202, 0x2207, 0x2261, 0x2252, 0x226A, 0x226B, 0x221A, 0x223D, 0x221D, 0x2235, 0x222B, 0x222C, 0, 0, 0, 0, 0, 0, 0, 0x212B, 0x2030, 0x266F, 0x266D, 0x266A, 0x2020, 0x2021, 0x00B6, 0, 0, 0, 0, 0x25EF, }; const unsigned short euc_to_utf8_A3[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17, 0xFF18, 0xFF19, 0, 0, 0, 0, 0, 0, 0, 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F, 0xFF30, 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38, 0xFF39, 0xFF3A, 0, 0, 0, 0, 0, 0, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0, 0, 0, 0, }; const unsigned short euc_to_utf8_A4[] = { 0x3041, 0x3042, 0x3043, 0x3044, 0x3045, 0x3046, 0x3047, 0x3048, 0x3049, 0x304A, 0x304B, 0x304C, 0x304D, 0x304E, 0x304F, 0x3050, 0x3051, 0x3052, 0x3053, 0x3054, 0x3055, 0x3056, 0x3057, 0x3058, 0x3059, 0x305A, 0x305B, 0x305C, 0x305D, 0x305E, 0x305F, 0x3060, 0x3061, 0x3062, 0x3063, 0x3064, 0x3065, 0x3066, 0x3067, 0x3068, 0x3069, 0x306A, 0x306B, 0x306C, 0x306D, 0x306E, 0x306F, 0x3070, 0x3071, 0x3072, 0x3073, 0x3074, 0x3075, 0x3076, 0x3077, 0x3078, 0x3079, 0x307A, 0x307B, 0x307C, 0x307D, 0x307E, 0x307F, 0x3080, 0x3081, 0x3082, 0x3083, 0x3084, 0x3085, 0x3086, 0x3087, 0x3088, 0x3089, 0x308A, 0x308B, 0x308C, 0x308D, 0x308E, 0x308F, 0x3090, 0x3091, 0x3092, 0x3093, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short euc_to_utf8_A5[] = { 0x30A1, 0x30A2, 0x30A3, 0x30A4, 0x30A5, 0x30A6, 0x30A7, 0x30A8, 0x30A9, 0x30AA, 0x30AB, 0x30AC, 0x30AD, 0x30AE, 0x30AF, 0x30B0, 0x30B1, 0x30B2, 0x30B3, 0x30B4, 0x30B5, 0x30B6, 0x30B7, 0x30B8, 0x30B9, 0x30BA, 0x30BB, 0x30BC, 0x30BD, 0x30BE, 0x30BF, 0x30C0, 0x30C1, 0x30C2, 0x30C3, 0x30C4, 0x30C5, 0x30C6, 0x30C7, 0x30C8, 0x30C9, 0x30CA, 0x30CB, 0x30CC, 0x30CD, 0x30CE, 0x30CF, 0x30D0, 0x30D1, 0x30D2, 0x30D3, 0x30D4, 0x30D5, 0x30D6, 0x30D7, 0x30D8, 0x30D9, 0x30DA, 0x30DB, 0x30DC, 0x30DD, 0x30DE, 0x30DF, 0x30E0, 0x30E1, 0x30E2, 0x30E3, 0x30E4, 0x30E5, 0x30E6, 0x30E7, 0x30E8, 0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EE, 0x30EF, 0x30F0, 0x30F1, 0x30F2, 0x30F3, 0x30F4, 0x30F5, 0x30F6, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short euc_to_utf8_A6[] = { 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0, 0, 0, 0, 0, 0, 0, 0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short euc_to_utf8_A7[] = { 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0401, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0451, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short euc_to_utf8_A8[] = { 0x2500, 0x2502, 0x250C, 0x2510, 0x2518, 0x2514, 0x251C, 0x252C, 0x2524, 0x2534, 0x253C, 0x2501, 0x2503, 0x250F, 0x2513, 0x251B, 0x2517, 0x2523, 0x2533, 0x252B, 0x253B, 0x254B, 0x2520, 0x252F, 0x2528, 0x2537, 0x253F, 0x251D, 0x2530, 0x2525, 0x2538, 0x2542, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short euc_to_utf8_A9[] = { 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467, 0x2468, 0x2469, 0x246A, 0x246B, 0x246C, 0x246D, 0x246E, 0x246F, 0x2470, 0x2471, 0x2472, 0x2473, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2474, 0x2475, 0x2476, 0x2477, 0x2478, 0x2479, 0x247A, 0x247B, 0x247C, 0x247D, 0x247E, 0x247F, 0x2480, 0x2481, 0x2482, 0x2483, 0x2484, 0x2485, 0x2486, 0x2487, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2776, 0x2777, 0x2778, 0x2779, 0x277A, 0x277B, 0x277C, 0x277D, 0x277E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2488, 0x2489, 0x248A, 0x248B, 0x248C, 0x248D, 0x248E, 0x248F, 0x2490, 0, 0, 0, 0, }; const unsigned short euc_to_utf8_AA[] = { 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216A, 0x216B, 0, 0, 0, 0, 0, 0, 0, 0, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x249C, 0x249D, 0x249E, 0x249F, 0x24A0, 0x24A1, 0x24A2, 0x24A3, 0x24A4, 0x24A5, 0x24A6, 0x24A7, 0x24A8, 0x24A9, 0x24AA, 0x24AB, 0x24AC, 0x24AD, 0x24AE, 0x24AF, 0x24B0, 0x24B1, 0x24B2, 0x24B3, 0x24B4, 0x24B5, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short euc_to_utf8_AB[] = { 0x339C, 0x339F, 0x339D, 0x33A0, 0x33A4, 0, 0x33A1, 0x33A5, 0x339E, 0x33A2, 0x338E, 0, 0x338F, 0x33C4, 0x3396, 0x3397, 0x2113, 0x3398, 0x33B3, 0x33B2, 0x33B1, 0x33B0, 0x2109, 0x33D4, 0x33CB, 0x3390, 0x3385, 0x3386, 0x3387, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2116, 0x33CD, 0x2121, 0, }; const unsigned short euc_to_utf8_AC[] = { 0x2664, 0x2667, 0x2661, 0x2662, 0x2660, 0x2663, 0x2665, 0x2666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3020, 0x260E, 0x3004, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x261E, 0x261C, 0x261D, 0x261F, 0x21C6, 0x21C4, 0x21C5, 0, 0x21E8, 0x21E6, 0x21E7, 0x21E9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short euc_to_utf8_AD[] = { 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467, 0x2468, 0x2469, 0x246A, 0x246B, 0x246C, 0x246D, 0x246E, 0x246F, 0x2470, 0x2471, 0x2472, 0x2473, 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0, 0x3349, 0x3314, 0x3322, 0x334D, 0x3318, 0x3327, 0x3303, 0x3336, 0x3351, 0x3357, 0x330D, 0x3326, 0x3323, 0x332B, 0x334A, 0x333B, 0x339C, 0x339D, 0x339E, 0x338E, 0x338F, 0x33C4, 0x33A1, 0, 0, 0, 0, 0, 0, 0, 0, 0x337B, 0x301D, 0x301F, 0x2116, 0x33CD, 0x2121, 0x32A4, 0x32A5, 0x32A6, 0x32A7, 0x32A8, 0x3231, 0x3232, 0x3239, 0x337E, 0x337D, 0x337C, 0x2252, 0x2261, 0x222B, 0x222E, 0x2211, 0x221A, 0x22A5, 0x2220, 0x221F, 0x22BF, 0x2235, 0x2229, 0x222A, 0, 0x3299, }; const unsigned short euc_to_utf8_AE[] = { 0x3349, 0x3322, 0x334D, 0x3314, 0x3316, 0x3305, 0x3333, 0x334E, 0x3303, 0x3336, 0x3318, 0x3315, 0x3327, 0x3351, 0x334A, 0x3339, 0x3357, 0x330D, 0x3342, 0x3323, 0x3326, 0x333B, 0x332B, 0, 0, 0, 0, 0, 0, 0, 0x3300, 0x331E, 0x332A, 0x3331, 0x3347, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x337E, 0x337D, 0x337C, 0x337B, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x337F, 0, 0, }; const unsigned short euc_to_utf8_AF[] = { 0x222E, 0x221F, 0x22BF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x301D, 0x301F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3094, 0, 0x30F7, 0x30F8, 0x30F9, 0x30FA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short euc_to_utf8_B0[] = { 0x4E9C, 0x5516, 0x5A03, 0x963F, 0x54C0, 0x611B, 0x6328, 0x59F6, 0x9022, 0x8475, 0x831C, 0x7A50, 0x60AA, 0x63E1, 0x6E25, 0x65ED, 0x8466, 0x82A6, 0x9BF5, 0x6893, 0x5727, 0x65A1, 0x6271, 0x5B9B, 0x59D0, 0x867B, 0x98F4, 0x7D62, 0x7DBE, 0x9B8E, 0x6216, 0x7C9F, 0x88B7, 0x5B89, 0x5EB5, 0x6309, 0x6697, 0x6848, 0x95C7, 0x978D, 0x674F, 0x4EE5, 0x4F0A, 0x4F4D, 0x4F9D, 0x5049, 0x56F2, 0x5937, 0x59D4, 0x5A01, 0x5C09, 0x60DF, 0x610F, 0x6170, 0x6613, 0x6905, 0x70BA, 0x754F, 0x7570, 0x79FB, 0x7DAD, 0x7DEF, 0x80C3, 0x840E, 0x8863, 0x8B02, 0x9055, 0x907A, 0x533B, 0x4E95, 0x4EA5, 0x57DF, 0x80B2, 0x90C1, 0x78EF, 0x4E00, 0x58F1, 0x6EA2, 0x9038, 0x7A32, 0x8328, 0x828B, 0x9C2F, 0x5141, 0x5370, 0x54BD, 0x54E1, 0x56E0, 0x59FB, 0x5F15, 0x98F2, 0x6DEB, 0x80E4, 0x852D, }; const unsigned short euc_to_utf8_B1[] = { 0x9662, 0x9670, 0x96A0, 0x97FB, 0x540B, 0x53F3, 0x5B87, 0x70CF, 0x7FBD, 0x8FC2, 0x96E8, 0x536F, 0x9D5C, 0x7ABA, 0x4E11, 0x7893, 0x81FC, 0x6E26, 0x5618, 0x5504, 0x6B1D, 0x851A, 0x9C3B, 0x59E5, 0x53A9, 0x6D66, 0x74DC, 0x958F, 0x5642, 0x4E91, 0x904B, 0x96F2, 0x834F, 0x990C, 0x53E1, 0x55B6, 0x5B30, 0x5F71, 0x6620, 0x66F3, 0x6804, 0x6C38, 0x6CF3, 0x6D29, 0x745B, 0x76C8, 0x7A4E, 0x9834, 0x82F1, 0x885B, 0x8A60, 0x92ED, 0x6DB2, 0x75AB, 0x76CA, 0x99C5, 0x60A6, 0x8B01, 0x8D8A, 0x95B2, 0x698E, 0x53AD, 0x5186, 0x5712, 0x5830, 0x5944, 0x5BB4, 0x5EF6, 0x6028, 0x63A9, 0x63F4, 0x6CBF, 0x6F14, 0x708E, 0x7114, 0x7159, 0x71D5, 0x733F, 0x7E01, 0x8276, 0x82D1, 0x8597, 0x9060, 0x925B, 0x9D1B, 0x5869, 0x65BC, 0x6C5A, 0x7525, 0x51F9, 0x592E, 0x5965, 0x5F80, 0x5FDC, }; const unsigned short euc_to_utf8_B2[] = { 0x62BC, 0x65FA, 0x6A2A, 0x6B27, 0x6BB4, 0x738B, 0x7FC1, 0x8956, 0x9D2C, 0x9D0E, 0x9EC4, 0x5CA1, 0x6C96, 0x837B, 0x5104, 0x5C4B, 0x61B6, 0x81C6, 0x6876, 0x7261, 0x4E59, 0x4FFA, 0x5378, 0x6069, 0x6E29, 0x7A4F, 0x97F3, 0x4E0B, 0x5316, 0x4EEE, 0x4F55, 0x4F3D, 0x4FA1, 0x4F73, 0x52A0, 0x53EF, 0x5609, 0x590F, 0x5AC1, 0x5BB6, 0x5BE1, 0x79D1, 0x6687, 0x679C, 0x67B6, 0x6B4C, 0x6CB3, 0x706B, 0x73C2, 0x798D, 0x79BE, 0x7A3C, 0x7B87, 0x82B1, 0x82DB, 0x8304, 0x8377, 0x83EF, 0x83D3, 0x8766, 0x8AB2, 0x5629, 0x8CA8, 0x8FE6, 0x904E, 0x971E, 0x868A, 0x4FC4, 0x5CE8, 0x6211, 0x7259, 0x753B, 0x81E5, 0x82BD, 0x86FE, 0x8CC0, 0x96C5, 0x9913, 0x99D5, 0x4ECB, 0x4F1A, 0x89E3, 0x56DE, 0x584A, 0x58CA, 0x5EFB, 0x5FEB, 0x602A, 0x6094, 0x6062, 0x61D0, 0x6212, 0x62D0, 0x6539, }; const unsigned short euc_to_utf8_B3[] = { 0x9B41, 0x6666, 0x68B0, 0x6D77, 0x7070, 0x754C, 0x7686, 0x7D75, 0x82A5, 0x87F9, 0x958B, 0x968E, 0x8C9D, 0x51F1, 0x52BE, 0x5916, 0x54B3, 0x5BB3, 0x5D16, 0x6168, 0x6982, 0x6DAF, 0x788D, 0x84CB, 0x8857, 0x8A72, 0x93A7, 0x9AB8, 0x6D6C, 0x99A8, 0x86D9, 0x57A3, 0x67FF, 0x86CE, 0x920E, 0x5283, 0x5687, 0x5404, 0x5ED3, 0x62E1, 0x64B9, 0x683C, 0x6838, 0x6BBB, 0x7372, 0x78BA, 0x7A6B, 0x899A, 0x89D2, 0x8D6B, 0x8F03, 0x90ED, 0x95A3, 0x9694, 0x9769, 0x5B66, 0x5CB3, 0x697D, 0x984D, 0x984E, 0x639B, 0x7B20, 0x6A2B, 0x6A7F, 0x68B6, 0x9C0D, 0x6F5F, 0x5272, 0x559D, 0x6070, 0x62EC, 0x6D3B, 0x6E07, 0x6ED1, 0x845B, 0x8910, 0x8F44, 0x4E14, 0x9C39, 0x53F6, 0x691B, 0x6A3A, 0x9784, 0x682A, 0x515C, 0x7AC3, 0x84B2, 0x91DC, 0x938C, 0x565B, 0x9D28, 0x6822, 0x8305, 0x8431, }; const unsigned short euc_to_utf8_B4[] = { 0x7CA5, 0x5208, 0x82C5, 0x74E6, 0x4E7E, 0x4F83, 0x51A0, 0x5BD2, 0x520A, 0x52D8, 0x52E7, 0x5DFB, 0x559A, 0x582A, 0x59E6, 0x5B8C, 0x5B98, 0x5BDB, 0x5E72, 0x5E79, 0x60A3, 0x611F, 0x6163, 0x61BE, 0x63DB, 0x6562, 0x67D1, 0x6853, 0x68FA, 0x6B3E, 0x6B53, 0x6C57, 0x6F22, 0x6F97, 0x6F45, 0x74B0, 0x7518, 0x76E3, 0x770B, 0x7AFF, 0x7BA1, 0x7C21, 0x7DE9, 0x7F36, 0x7FF0, 0x809D, 0x8266, 0x839E, 0x89B3, 0x8ACC, 0x8CAB, 0x9084, 0x9451, 0x9593, 0x9591, 0x95A2, 0x9665, 0x97D3, 0x9928, 0x8218, 0x4E38, 0x542B, 0x5CB8, 0x5DCC, 0x73A9, 0x764C, 0x773C, 0x5CA9, 0x7FEB, 0x8D0B, 0x96C1, 0x9811, 0x9854, 0x9858, 0x4F01, 0x4F0E, 0x5371, 0x559C, 0x5668, 0x57FA, 0x5947, 0x5B09, 0x5BC4, 0x5C90, 0x5E0C, 0x5E7E, 0x5FCC, 0x63EE, 0x673A, 0x65D7, 0x65E2, 0x671F, 0x68CB, 0x68C4, }; const unsigned short euc_to_utf8_B5[] = { 0x6A5F, 0x5E30, 0x6BC5, 0x6C17, 0x6C7D, 0x757F, 0x7948, 0x5B63, 0x7A00, 0x7D00, 0x5FBD, 0x898F, 0x8A18, 0x8CB4, 0x8D77, 0x8ECC, 0x8F1D, 0x98E2, 0x9A0E, 0x9B3C, 0x4E80, 0x507D, 0x5100, 0x5993, 0x5B9C, 0x622F, 0x6280, 0x64EC, 0x6B3A, 0x72A0, 0x7591, 0x7947, 0x7FA9, 0x87FB, 0x8ABC, 0x8B70, 0x63AC, 0x83CA, 0x97A0, 0x5409, 0x5403, 0x55AB, 0x6854, 0x6A58, 0x8A70, 0x7827, 0x6775, 0x9ECD, 0x5374, 0x5BA2, 0x811A, 0x8650, 0x9006, 0x4E18, 0x4E45, 0x4EC7, 0x4F11, 0x53CA, 0x5438, 0x5BAE, 0x5F13, 0x6025, 0x6551, 0x673D, 0x6C42, 0x6C72, 0x6CE3, 0x7078, 0x7403, 0x7A76, 0x7AAE, 0x7B08, 0x7D1A, 0x7CFE, 0x7D66, 0x65E7, 0x725B, 0x53BB, 0x5C45, 0x5DE8, 0x62D2, 0x62E0, 0x6319, 0x6E20, 0x865A, 0x8A31, 0x8DDD, 0x92F8, 0x6F01, 0x79A6, 0x9B5A, 0x4EA8, 0x4EAB, 0x4EAC, }; const unsigned short euc_to_utf8_B6[] = { 0x4F9B, 0x4FA0, 0x50D1, 0x5147, 0x7AF6, 0x5171, 0x51F6, 0x5354, 0x5321, 0x537F, 0x53EB, 0x55AC, 0x5883, 0x5CE1, 0x5F37, 0x5F4A, 0x602F, 0x6050, 0x606D, 0x631F, 0x6559, 0x6A4B, 0x6CC1, 0x72C2, 0x72ED, 0x77EF, 0x80F8, 0x8105, 0x8208, 0x854E, 0x90F7, 0x93E1, 0x97FF, 0x9957, 0x9A5A, 0x4EF0, 0x51DD, 0x5C2D, 0x6681, 0x696D, 0x5C40, 0x66F2, 0x6975, 0x7389, 0x6850, 0x7C81, 0x50C5, 0x52E4, 0x5747, 0x5DFE, 0x9326, 0x65A4, 0x6B23, 0x6B3D, 0x7434, 0x7981, 0x79BD, 0x7B4B, 0x7DCA, 0x82B9, 0x83CC, 0x887F, 0x895F, 0x8B39, 0x8FD1, 0x91D1, 0x541F, 0x9280, 0x4E5D, 0x5036, 0x53E5, 0x533A, 0x72D7, 0x7396, 0x77E9, 0x82E6, 0x8EAF, 0x99C6, 0x99C8, 0x99D2, 0x5177, 0x611A, 0x865E, 0x55B0, 0x7A7A, 0x5076, 0x5BD3, 0x9047, 0x9685, 0x4E32, 0x6ADB, 0x91E7, 0x5C51, 0x5C48, }; const unsigned short euc_to_utf8_B7[] = { 0x6398, 0x7A9F, 0x6C93, 0x9774, 0x8F61, 0x7AAA, 0x718A, 0x9688, 0x7C82, 0x6817, 0x7E70, 0x6851, 0x936C, 0x52F2, 0x541B, 0x85AB, 0x8A13, 0x7FA4, 0x8ECD, 0x90E1, 0x5366, 0x8888, 0x7941, 0x4FC2, 0x50BE, 0x5211, 0x5144, 0x5553, 0x572D, 0x73EA, 0x578B, 0x5951, 0x5F62, 0x5F84, 0x6075, 0x6176, 0x6167, 0x61A9, 0x63B2, 0x643A, 0x656C, 0x666F, 0x6842, 0x6E13, 0x7566, 0x7A3D, 0x7CFB, 0x7D4C, 0x7D99, 0x7E4B, 0x7F6B, 0x830E, 0x834A, 0x86CD, 0x8A08, 0x8A63, 0x8B66, 0x8EFD, 0x981A, 0x9D8F, 0x82B8, 0x8FCE, 0x9BE8, 0x5287, 0x621F, 0x6483, 0x6FC0, 0x9699, 0x6841, 0x5091, 0x6B20, 0x6C7A, 0x6F54, 0x7A74, 0x7D50, 0x8840, 0x8A23, 0x6708, 0x4EF6, 0x5039, 0x5026, 0x5065, 0x517C, 0x5238, 0x5263, 0x55A7, 0x570F, 0x5805, 0x5ACC, 0x5EFA, 0x61B2, 0x61F8, 0x62F3, 0x6372, }; const unsigned short euc_to_utf8_B8[] = { 0x691C, 0x6A29, 0x727D, 0x72AC, 0x732E, 0x7814, 0x786F, 0x7D79, 0x770C, 0x80A9, 0x898B, 0x8B19, 0x8CE2, 0x8ED2, 0x9063, 0x9375, 0x967A, 0x9855, 0x9A13, 0x9E78, 0x5143, 0x539F, 0x53B3, 0x5E7B, 0x5F26, 0x6E1B, 0x6E90, 0x7384, 0x73FE, 0x7D43, 0x8237, 0x8A00, 0x8AFA, 0x9650, 0x4E4E, 0x500B, 0x53E4, 0x547C, 0x56FA, 0x59D1, 0x5B64, 0x5DF1, 0x5EAB, 0x5F27, 0x6238, 0x6545, 0x67AF, 0x6E56, 0x72D0, 0x7CCA, 0x88B4, 0x80A1, 0x80E1, 0x83F0, 0x864E, 0x8A87, 0x8DE8, 0x9237, 0x96C7, 0x9867, 0x9F13, 0x4E94, 0x4E92, 0x4F0D, 0x5348, 0x5449, 0x543E, 0x5A2F, 0x5F8C, 0x5FA1, 0x609F, 0x68A7, 0x6A8E, 0x745A, 0x7881, 0x8A9E, 0x8AA4, 0x8B77, 0x9190, 0x4E5E, 0x9BC9, 0x4EA4, 0x4F7C, 0x4FAF, 0x5019, 0x5016, 0x5149, 0x516C, 0x529F, 0x52B9, 0x52FE, 0x539A, 0x53E3, 0x5411, }; const unsigned short euc_to_utf8_B9[] = { 0x540E, 0x5589, 0x5751, 0x57A2, 0x597D, 0x5B54, 0x5B5D, 0x5B8F, 0x5DE5, 0x5DE7, 0x5DF7, 0x5E78, 0x5E83, 0x5E9A, 0x5EB7, 0x5F18, 0x6052, 0x614C, 0x6297, 0x62D8, 0x63A7, 0x653B, 0x6602, 0x6643, 0x66F4, 0x676D, 0x6821, 0x6897, 0x69CB, 0x6C5F, 0x6D2A, 0x6D69, 0x6E2F, 0x6E9D, 0x7532, 0x7687, 0x786C, 0x7A3F, 0x7CE0, 0x7D05, 0x7D18, 0x7D5E, 0x7DB1, 0x8015, 0x8003, 0x80AF, 0x80B1, 0x8154, 0x818F, 0x822A, 0x8352, 0x884C, 0x8861, 0x8B1B, 0x8CA2, 0x8CFC, 0x90CA, 0x9175, 0x9271, 0x783F, 0x92FC, 0x95A4, 0x964D, 0x9805, 0x9999, 0x9AD8, 0x9D3B, 0x525B, 0x52AB, 0x53F7, 0x5408, 0x58D5, 0x62F7, 0x6FE0, 0x8C6A, 0x8F5F, 0x9EB9, 0x514B, 0x523B, 0x544A, 0x56FD, 0x7A40, 0x9177, 0x9D60, 0x9ED2, 0x7344, 0x6F09, 0x8170, 0x7511, 0x5FFD, 0x60DA, 0x9AA8, 0x72DB, 0x8FBC, }; const unsigned short euc_to_utf8_BA[] = { 0x6B64, 0x9803, 0x4ECA, 0x56F0, 0x5764, 0x58BE, 0x5A5A, 0x6068, 0x61C7, 0x660F, 0x6606, 0x6839, 0x68B1, 0x6DF7, 0x75D5, 0x7D3A, 0x826E, 0x9B42, 0x4E9B, 0x4F50, 0x53C9, 0x5506, 0x5D6F, 0x5DE6, 0x5DEE, 0x67FB, 0x6C99, 0x7473, 0x7802, 0x8A50, 0x9396, 0x88DF, 0x5750, 0x5EA7, 0x632B, 0x50B5, 0x50AC, 0x518D, 0x6700, 0x54C9, 0x585E, 0x59BB, 0x5BB0, 0x5F69, 0x624D, 0x63A1, 0x683D, 0x6B73, 0x6E08, 0x707D, 0x91C7, 0x7280, 0x7815, 0x7826, 0x796D, 0x658E, 0x7D30, 0x83DC, 0x88C1, 0x8F09, 0x969B, 0x5264, 0x5728, 0x6750, 0x7F6A, 0x8CA1, 0x51B4, 0x5742, 0x962A, 0x583A, 0x698A, 0x80B4, 0x54B2, 0x5D0E, 0x57FC, 0x7895, 0x9DFA, 0x4F5C, 0x524A, 0x548B, 0x643E, 0x6628, 0x6714, 0x67F5, 0x7A84, 0x7B56, 0x7D22, 0x932F, 0x685C, 0x9BAD, 0x7B39, 0x5319, 0x518A, 0x5237, }; const unsigned short euc_to_utf8_BB[] = { 0x5BDF, 0x62F6, 0x64AE, 0x64E6, 0x672D, 0x6BBA, 0x85A9, 0x96D1, 0x7690, 0x9BD6, 0x634C, 0x9306, 0x9BAB, 0x76BF, 0x6652, 0x4E09, 0x5098, 0x53C2, 0x5C71, 0x60E8, 0x6492, 0x6563, 0x685F, 0x71E6, 0x73CA, 0x7523, 0x7B97, 0x7E82, 0x8695, 0x8B83, 0x8CDB, 0x9178, 0x9910, 0x65AC, 0x66AB, 0x6B8B, 0x4ED5, 0x4ED4, 0x4F3A, 0x4F7F, 0x523A, 0x53F8, 0x53F2, 0x55E3, 0x56DB, 0x58EB, 0x59CB, 0x59C9, 0x59FF, 0x5B50, 0x5C4D, 0x5E02, 0x5E2B, 0x5FD7, 0x601D, 0x6307, 0x652F, 0x5B5C, 0x65AF, 0x65BD, 0x65E8, 0x679D, 0x6B62, 0x6B7B, 0x6C0F, 0x7345, 0x7949, 0x79C1, 0x7CF8, 0x7D19, 0x7D2B, 0x80A2, 0x8102, 0x81F3, 0x8996, 0x8A5E, 0x8A69, 0x8A66, 0x8A8C, 0x8AEE, 0x8CC7, 0x8CDC, 0x96CC, 0x98FC, 0x6B6F, 0x4E8B, 0x4F3C, 0x4F8D, 0x5150, 0x5B57, 0x5BFA, 0x6148, 0x6301, 0x6642, }; const unsigned short euc_to_utf8_BC[] = { 0x6B21, 0x6ECB, 0x6CBB, 0x723E, 0x74BD, 0x75D4, 0x78C1, 0x793A, 0x800C, 0x8033, 0x81EA, 0x8494, 0x8F9E, 0x6C50, 0x9E7F, 0x5F0F, 0x8B58, 0x9D2B, 0x7AFA, 0x8EF8, 0x5B8D, 0x96EB, 0x4E03, 0x53F1, 0x57F7, 0x5931, 0x5AC9, 0x5BA4, 0x6089, 0x6E7F, 0x6F06, 0x75BE, 0x8CEA, 0x5B9F, 0x8500, 0x7BE0, 0x5072, 0x67F4, 0x829D, 0x5C61, 0x854A, 0x7E1E, 0x820E, 0x5199, 0x5C04, 0x6368, 0x8D66, 0x659C, 0x716E, 0x793E, 0x7D17, 0x8005, 0x8B1D, 0x8ECA, 0x906E, 0x86C7, 0x90AA, 0x501F, 0x52FA, 0x5C3A, 0x6753, 0x707C, 0x7235, 0x914C, 0x91C8, 0x932B, 0x82E5, 0x5BC2, 0x5F31, 0x60F9, 0x4E3B, 0x53D6, 0x5B88, 0x624B, 0x6731, 0x6B8A, 0x72E9, 0x73E0, 0x7A2E, 0x816B, 0x8DA3, 0x9152, 0x9996, 0x5112, 0x53D7, 0x546A, 0x5BFF, 0x6388, 0x6A39, 0x7DAC, 0x9700, 0x56DA, 0x53CE, 0x5468, }; const unsigned short euc_to_utf8_BD[] = { 0x5B97, 0x5C31, 0x5DDE, 0x4FEE, 0x6101, 0x62FE, 0x6D32, 0x79C0, 0x79CB, 0x7D42, 0x7E4D, 0x7FD2, 0x81ED, 0x821F, 0x8490, 0x8846, 0x8972, 0x8B90, 0x8E74, 0x8F2F, 0x9031, 0x914B, 0x916C, 0x96C6, 0x919C, 0x4EC0, 0x4F4F, 0x5145, 0x5341, 0x5F93, 0x620E, 0x67D4, 0x6C41, 0x6E0B, 0x7363, 0x7E26, 0x91CD, 0x9283, 0x53D4, 0x5919, 0x5BBF, 0x6DD1, 0x795D, 0x7E2E, 0x7C9B, 0x587E, 0x719F, 0x51FA, 0x8853, 0x8FF0, 0x4FCA, 0x5CFB, 0x6625, 0x77AC, 0x7AE3, 0x821C, 0x99FF, 0x51C6, 0x5FAA, 0x65EC, 0x696F, 0x6B89, 0x6DF3, 0x6E96, 0x6F64, 0x76FE, 0x7D14, 0x5DE1, 0x9075, 0x9187, 0x9806, 0x51E6, 0x521D, 0x6240, 0x6691, 0x66D9, 0x6E1A, 0x5EB6, 0x7DD2, 0x7F72, 0x66F8, 0x85AF, 0x85F7, 0x8AF8, 0x52A9, 0x53D9, 0x5973, 0x5E8F, 0x5F90, 0x6055, 0x92E4, 0x9664, 0x50B7, 0x511F, }; const unsigned short euc_to_utf8_BE[] = { 0x52DD, 0x5320, 0x5347, 0x53EC, 0x54E8, 0x5546, 0x5531, 0x5617, 0x5968, 0x59BE, 0x5A3C, 0x5BB5, 0x5C06, 0x5C0F, 0x5C11, 0x5C1A, 0x5E84, 0x5E8A, 0x5EE0, 0x5F70, 0x627F, 0x6284, 0x62DB, 0x638C, 0x6377, 0x6607, 0x660C, 0x662D, 0x6676, 0x677E, 0x68A2, 0x6A1F, 0x6A35, 0x6CBC, 0x6D88, 0x6E09, 0x6E58, 0x713C, 0x7126, 0x7167, 0x75C7, 0x7701, 0x785D, 0x7901, 0x7965, 0x79F0, 0x7AE0, 0x7B11, 0x7CA7, 0x7D39, 0x8096, 0x83D6, 0x848B, 0x8549, 0x885D, 0x88F3, 0x8A1F, 0x8A3C, 0x8A54, 0x8A73, 0x8C61, 0x8CDE, 0x91A4, 0x9266, 0x937E, 0x9418, 0x969C, 0x9798, 0x4E0A, 0x4E08, 0x4E1E, 0x4E57, 0x5197, 0x5270, 0x57CE, 0x5834, 0x58CC, 0x5B22, 0x5E38, 0x60C5, 0x64FE, 0x6761, 0x6756, 0x6D44, 0x72B6, 0x7573, 0x7A63, 0x84B8, 0x8B72, 0x91B8, 0x9320, 0x5631, 0x57F4, 0x98FE, }; const unsigned short euc_to_utf8_BF[] = { 0x62ED, 0x690D, 0x6B96, 0x71ED, 0x7E54, 0x8077, 0x8272, 0x89E6, 0x98DF, 0x8755, 0x8FB1, 0x5C3B, 0x4F38, 0x4FE1, 0x4FB5, 0x5507, 0x5A20, 0x5BDD, 0x5BE9, 0x5FC3, 0x614E, 0x632F, 0x65B0, 0x664B, 0x68EE, 0x699B, 0x6D78, 0x6DF1, 0x7533, 0x75B9, 0x771F, 0x795E, 0x79E6, 0x7D33, 0x81E3, 0x82AF, 0x85AA, 0x89AA, 0x8A3A, 0x8EAB, 0x8F9B, 0x9032, 0x91DD, 0x9707, 0x4EBA, 0x4EC1, 0x5203, 0x5875, 0x58EC, 0x5C0B, 0x751A, 0x5C3D, 0x814E, 0x8A0A, 0x8FC5, 0x9663, 0x976D, 0x7B25, 0x8ACF, 0x9808, 0x9162, 0x56F3, 0x53A8, 0x9017, 0x5439, 0x5782, 0x5E25, 0x63A8, 0x6C34, 0x708A, 0x7761, 0x7C8B, 0x7FE0, 0x8870, 0x9042, 0x9154, 0x9310, 0x9318, 0x968F, 0x745E, 0x9AC4, 0x5D07, 0x5D69, 0x6570, 0x67A2, 0x8DA8, 0x96DB, 0x636E, 0x6749, 0x6919, 0x83C5, 0x9817, 0x96C0, 0x88FE, }; const unsigned short euc_to_utf8_C0[] = { 0x6F84, 0x647A, 0x5BF8, 0x4E16, 0x702C, 0x755D, 0x662F, 0x51C4, 0x5236, 0x52E2, 0x59D3, 0x5F81, 0x6027, 0x6210, 0x653F, 0x6574, 0x661F, 0x6674, 0x68F2, 0x6816, 0x6B63, 0x6E05, 0x7272, 0x751F, 0x76DB, 0x7CBE, 0x8056, 0x58F0, 0x88FD, 0x897F, 0x8AA0, 0x8A93, 0x8ACB, 0x901D, 0x9192, 0x9752, 0x9759, 0x6589, 0x7A0E, 0x8106, 0x96BB, 0x5E2D, 0x60DC, 0x621A, 0x65A5, 0x6614, 0x6790, 0x77F3, 0x7A4D, 0x7C4D, 0x7E3E, 0x810A, 0x8CAC, 0x8D64, 0x8DE1, 0x8E5F, 0x78A9, 0x5207, 0x62D9, 0x63A5, 0x6442, 0x6298, 0x8A2D, 0x7A83, 0x7BC0, 0x8AAC, 0x96EA, 0x7D76, 0x820C, 0x8749, 0x4ED9, 0x5148, 0x5343, 0x5360, 0x5BA3, 0x5C02, 0x5C16, 0x5DDD, 0x6226, 0x6247, 0x64B0, 0x6813, 0x6834, 0x6CC9, 0x6D45, 0x6D17, 0x67D3, 0x6F5C, 0x714E, 0x717D, 0x65CB, 0x7A7F, 0x7BAD, 0x7DDA, }; const unsigned short euc_to_utf8_C1[] = { 0x7E4A, 0x7FA8, 0x817A, 0x821B, 0x8239, 0x85A6, 0x8A6E, 0x8CCE, 0x8DF5, 0x9078, 0x9077, 0x92AD, 0x9291, 0x9583, 0x9BAE, 0x524D, 0x5584, 0x6F38, 0x7136, 0x5168, 0x7985, 0x7E55, 0x81B3, 0x7CCE, 0x564C, 0x5851, 0x5CA8, 0x63AA, 0x66FE, 0x66FD, 0x695A, 0x72D9, 0x758F, 0x758E, 0x790E, 0x7956, 0x79DF, 0x7C97, 0x7D20, 0x7D44, 0x8607, 0x8A34, 0x963B, 0x9061, 0x9F20, 0x50E7, 0x5275, 0x53CC, 0x53E2, 0x5009, 0x55AA, 0x58EE, 0x594F, 0x723D, 0x5B8B, 0x5C64, 0x531D, 0x60E3, 0x60F3, 0x635C, 0x6383, 0x633F, 0x63BB, 0x64CD, 0x65E9, 0x66F9, 0x5DE3, 0x69CD, 0x69FD, 0x6F15, 0x71E5, 0x4E89, 0x75E9, 0x76F8, 0x7A93, 0x7CDF, 0x7DCF, 0x7D9C, 0x8061, 0x8349, 0x8358, 0x846C, 0x84BC, 0x85FB, 0x88C5, 0x8D70, 0x9001, 0x906D, 0x9397, 0x971C, 0x9A12, 0x50CF, 0x5897, 0x618E, }; const unsigned short euc_to_utf8_C2[] = { 0x81D3, 0x8535, 0x8D08, 0x9020, 0x4FC3, 0x5074, 0x5247, 0x5373, 0x606F, 0x6349, 0x675F, 0x6E2C, 0x8DB3, 0x901F, 0x4FD7, 0x5C5E, 0x8CCA, 0x65CF, 0x7D9A, 0x5352, 0x8896, 0x5176, 0x63C3, 0x5B58, 0x5B6B, 0x5C0A, 0x640D, 0x6751, 0x905C, 0x4ED6, 0x591A, 0x592A, 0x6C70, 0x8A51, 0x553E, 0x5815, 0x59A5, 0x60F0, 0x6253, 0x67C1, 0x8235, 0x6955, 0x9640, 0x99C4, 0x9A28, 0x4F53, 0x5806, 0x5BFE, 0x8010, 0x5CB1, 0x5E2F, 0x5F85, 0x6020, 0x614B, 0x6234, 0x66FF, 0x6CF0, 0x6EDE, 0x80CE, 0x817F, 0x82D4, 0x888B, 0x8CB8, 0x9000, 0x902E, 0x968A, 0x9EDB, 0x9BDB, 0x4EE3, 0x53F0, 0x5927, 0x7B2C, 0x918D, 0x984C, 0x9DF9, 0x6EDD, 0x7027, 0x5353, 0x5544, 0x5B85, 0x6258, 0x629E, 0x62D3, 0x6CA2, 0x6FEF, 0x7422, 0x8A17, 0x9438, 0x6FC1, 0x8AFE, 0x8338, 0x51E7, 0x86F8, 0x53EA, }; const unsigned short euc_to_utf8_C3[] = { 0x53E9, 0x4F46, 0x9054, 0x8FB0, 0x596A, 0x8131, 0x5DFD, 0x7AEA, 0x8FBF, 0x68DA, 0x8C37, 0x72F8, 0x9C48, 0x6A3D, 0x8AB0, 0x4E39, 0x5358, 0x5606, 0x5766, 0x62C5, 0x63A2, 0x65E6, 0x6B4E, 0x6DE1, 0x6E5B, 0x70AD, 0x77ED, 0x7AEF, 0x7BAA, 0x7DBB, 0x803D, 0x80C6, 0x86CB, 0x8A95, 0x935B, 0x56E3, 0x58C7, 0x5F3E, 0x65AD, 0x6696, 0x6A80, 0x6BB5, 0x7537, 0x8AC7, 0x5024, 0x77E5, 0x5730, 0x5F1B, 0x6065, 0x667A, 0x6C60, 0x75F4, 0x7A1A, 0x7F6E, 0x81F4, 0x8718, 0x9045, 0x99B3, 0x7BC9, 0x755C, 0x7AF9, 0x7B51, 0x84C4, 0x9010, 0x79E9, 0x7A92, 0x8336, 0x5AE1, 0x7740, 0x4E2D, 0x4EF2, 0x5B99, 0x5FE0, 0x62BD, 0x663C, 0x67F1, 0x6CE8, 0x866B, 0x8877, 0x8A3B, 0x914E, 0x92F3, 0x99D0, 0x6A17, 0x7026, 0x732A, 0x82E7, 0x8457, 0x8CAF, 0x4E01, 0x5146, 0x51CB, 0x558B, 0x5BF5, }; const unsigned short euc_to_utf8_C4[] = { 0x5E16, 0x5E33, 0x5E81, 0x5F14, 0x5F35, 0x5F6B, 0x5FB4, 0x61F2, 0x6311, 0x66A2, 0x671D, 0x6F6E, 0x7252, 0x753A, 0x773A, 0x8074, 0x8139, 0x8178, 0x8776, 0x8ABF, 0x8ADC, 0x8D85, 0x8DF3, 0x929A, 0x9577, 0x9802, 0x9CE5, 0x52C5, 0x6357, 0x76F4, 0x6715, 0x6C88, 0x73CD, 0x8CC3, 0x93AE, 0x9673, 0x6D25, 0x589C, 0x690E, 0x69CC, 0x8FFD, 0x939A, 0x75DB, 0x901A, 0x585A, 0x6802, 0x63B4, 0x69FB, 0x4F43, 0x6F2C, 0x67D8, 0x8FBB, 0x8526, 0x7DB4, 0x9354, 0x693F, 0x6F70, 0x576A, 0x58F7, 0x5B2C, 0x7D2C, 0x722A, 0x540A, 0x91E3, 0x9DB4, 0x4EAD, 0x4F4E, 0x505C, 0x5075, 0x5243, 0x8C9E, 0x5448, 0x5824, 0x5B9A, 0x5E1D, 0x5E95, 0x5EAD, 0x5EF7, 0x5F1F, 0x608C, 0x62B5, 0x633A, 0x63D0, 0x68AF, 0x6C40, 0x7887, 0x798E, 0x7A0B, 0x7DE0, 0x8247, 0x8A02, 0x8AE6, 0x8E44, 0x9013, }; const unsigned short euc_to_utf8_C5[] = { 0x90B8, 0x912D, 0x91D8, 0x9F0E, 0x6CE5, 0x6458, 0x64E2, 0x6575, 0x6EF4, 0x7684, 0x7B1B, 0x9069, 0x93D1, 0x6EBA, 0x54F2, 0x5FB9, 0x64A4, 0x8F4D, 0x8FED, 0x9244, 0x5178, 0x586B, 0x5929, 0x5C55, 0x5E97, 0x6DFB, 0x7E8F, 0x751C, 0x8CBC, 0x8EE2, 0x985B, 0x70B9, 0x4F1D, 0x6BBF, 0x6FB1, 0x7530, 0x96FB, 0x514E, 0x5410, 0x5835, 0x5857, 0x59AC, 0x5C60, 0x5F92, 0x6597, 0x675C, 0x6E21, 0x767B, 0x83DF, 0x8CED, 0x9014, 0x90FD, 0x934D, 0x7825, 0x783A, 0x52AA, 0x5EA6, 0x571F, 0x5974, 0x6012, 0x5012, 0x515A, 0x51AC, 0x51CD, 0x5200, 0x5510, 0x5854, 0x5858, 0x5957, 0x5B95, 0x5CF6, 0x5D8B, 0x60BC, 0x6295, 0x642D, 0x6771, 0x6843, 0x68BC, 0x68DF, 0x76D7, 0x6DD8, 0x6E6F, 0x6D9B, 0x706F, 0x71C8, 0x5F53, 0x75D8, 0x7977, 0x7B49, 0x7B54, 0x7B52, 0x7CD6, 0x7D71, 0x5230, }; const unsigned short euc_to_utf8_C6[] = { 0x8463, 0x8569, 0x85E4, 0x8A0E, 0x8B04, 0x8C46, 0x8E0F, 0x9003, 0x900F, 0x9419, 0x9676, 0x982D, 0x9A30, 0x95D8, 0x50CD, 0x52D5, 0x540C, 0x5802, 0x5C0E, 0x61A7, 0x649E, 0x6D1E, 0x77B3, 0x7AE5, 0x80F4, 0x8404, 0x9053, 0x9285, 0x5CE0, 0x9D07, 0x533F, 0x5F97, 0x5FB3, 0x6D9C, 0x7279, 0x7763, 0x79BF, 0x7BE4, 0x6BD2, 0x72EC, 0x8AAD, 0x6803, 0x6A61, 0x51F8, 0x7A81, 0x6934, 0x5C4A, 0x9CF6, 0x82EB, 0x5BC5, 0x9149, 0x701E, 0x5678, 0x5C6F, 0x60C7, 0x6566, 0x6C8C, 0x8C5A, 0x9041, 0x9813, 0x5451, 0x66C7, 0x920D, 0x5948, 0x90A3, 0x5185, 0x4E4D, 0x51EA, 0x8599, 0x8B0E, 0x7058, 0x637A, 0x934B, 0x6962, 0x99B4, 0x7E04, 0x7577, 0x5357, 0x6960, 0x8EDF, 0x96E3, 0x6C5D, 0x4E8C, 0x5C3C, 0x5F10, 0x8FE9, 0x5302, 0x8CD1, 0x8089, 0x8679, 0x5EFF, 0x65E5, 0x4E73, 0x5165, }; const unsigned short euc_to_utf8_C7[] = { 0x5982, 0x5C3F, 0x97EE, 0x4EFB, 0x598A, 0x5FCD, 0x8A8D, 0x6FE1, 0x79B0, 0x7962, 0x5BE7, 0x8471, 0x732B, 0x71B1, 0x5E74, 0x5FF5, 0x637B, 0x649A, 0x71C3, 0x7C98, 0x4E43, 0x5EFC, 0x4E4B, 0x57DC, 0x56A2, 0x60A9, 0x6FC3, 0x7D0D, 0x80FD, 0x8133, 0x81BF, 0x8FB2, 0x8997, 0x86A4, 0x5DF4, 0x628A, 0x64AD, 0x8987, 0x6777, 0x6CE2, 0x6D3E, 0x7436, 0x7834, 0x5A46, 0x7F75, 0x82AD, 0x99AC, 0x4FF3, 0x5EC3, 0x62DD, 0x6392, 0x6557, 0x676F, 0x76C3, 0x724C, 0x80CC, 0x80BA, 0x8F29, 0x914D, 0x500D, 0x57F9, 0x5A92, 0x6885, 0x6973, 0x7164, 0x72FD, 0x8CB7, 0x58F2, 0x8CE0, 0x966A, 0x9019, 0x877F, 0x79E4, 0x77E7, 0x8429, 0x4F2F, 0x5265, 0x535A, 0x62CD, 0x67CF, 0x6CCA, 0x767D, 0x7B94, 0x7C95, 0x8236, 0x8584, 0x8FEB, 0x66DD, 0x6F20, 0x7206, 0x7E1B, 0x83AB, 0x99C1, 0x9EA6, }; const unsigned short euc_to_utf8_C8[] = { 0x51FD, 0x7BB1, 0x7872, 0x7BB8, 0x8087, 0x7B48, 0x6AE8, 0x5E61, 0x808C, 0x7551, 0x7560, 0x516B, 0x9262, 0x6E8C, 0x767A, 0x9197, 0x9AEA, 0x4F10, 0x7F70, 0x629C, 0x7B4F, 0x95A5, 0x9CE9, 0x567A, 0x5859, 0x86E4, 0x96BC, 0x4F34, 0x5224, 0x534A, 0x53CD, 0x53DB, 0x5E06, 0x642C, 0x6591, 0x677F, 0x6C3E, 0x6C4E, 0x7248, 0x72AF, 0x73ED, 0x7554, 0x7E41, 0x822C, 0x85E9, 0x8CA9, 0x7BC4, 0x91C6, 0x7169, 0x9812, 0x98EF, 0x633D, 0x6669, 0x756A, 0x76E4, 0x78D0, 0x8543, 0x86EE, 0x532A, 0x5351, 0x5426, 0x5983, 0x5E87, 0x5F7C, 0x60B2, 0x6249, 0x6279, 0x62AB, 0x6590, 0x6BD4, 0x6CCC, 0x75B2, 0x76AE, 0x7891, 0x79D8, 0x7DCB, 0x7F77, 0x80A5, 0x88AB, 0x8AB9, 0x8CBB, 0x907F, 0x975E, 0x98DB, 0x6A0B, 0x7C38, 0x5099, 0x5C3E, 0x5FAE, 0x6787, 0x6BD8, 0x7435, 0x7709, 0x7F8E, }; const unsigned short euc_to_utf8_C9[] = { 0x9F3B, 0x67CA, 0x7A17, 0x5339, 0x758B, 0x9AED, 0x5F66, 0x819D, 0x83F1, 0x8098, 0x5F3C, 0x5FC5, 0x7562, 0x7B46, 0x903C, 0x6867, 0x59EB, 0x5A9B, 0x7D10, 0x767E, 0x8B2C, 0x4FF5, 0x5F6A, 0x6A19, 0x6C37, 0x6F02, 0x74E2, 0x7968, 0x8868, 0x8A55, 0x8C79, 0x5EDF, 0x63CF, 0x75C5, 0x79D2, 0x82D7, 0x9328, 0x92F2, 0x849C, 0x86ED, 0x9C2D, 0x54C1, 0x5F6C, 0x658C, 0x6D5C, 0x7015, 0x8CA7, 0x8CD3, 0x983B, 0x654F, 0x74F6, 0x4E0D, 0x4ED8, 0x57E0, 0x592B, 0x5A66, 0x5BCC, 0x51A8, 0x5E03, 0x5E9C, 0x6016, 0x6276, 0x6577, 0x65A7, 0x666E, 0x6D6E, 0x7236, 0x7B26, 0x8150, 0x819A, 0x8299, 0x8B5C, 0x8CA0, 0x8CE6, 0x8D74, 0x961C, 0x9644, 0x4FAE, 0x64AB, 0x6B66, 0x821E, 0x8461, 0x856A, 0x90E8, 0x5C01, 0x6953, 0x98A8, 0x847A, 0x8557, 0x4F0F, 0x526F, 0x5FA9, 0x5E45, 0x670D, }; const unsigned short euc_to_utf8_CA[] = { 0x798F, 0x8179, 0x8907, 0x8986, 0x6DF5, 0x5F17, 0x6255, 0x6CB8, 0x4ECF, 0x7269, 0x9B92, 0x5206, 0x543B, 0x5674, 0x58B3, 0x61A4, 0x626E, 0x711A, 0x596E, 0x7C89, 0x7CDE, 0x7D1B, 0x96F0, 0x6587, 0x805E, 0x4E19, 0x4F75, 0x5175, 0x5840, 0x5E63, 0x5E73, 0x5F0A, 0x67C4, 0x4E26, 0x853D, 0x9589, 0x965B, 0x7C73, 0x9801, 0x50FB, 0x58C1, 0x7656, 0x78A7, 0x5225, 0x77A5, 0x8511, 0x7B86, 0x504F, 0x5909, 0x7247, 0x7BC7, 0x7DE8, 0x8FBA, 0x8FD4, 0x904D, 0x4FBF, 0x52C9, 0x5A29, 0x5F01, 0x97AD, 0x4FDD, 0x8217, 0x92EA, 0x5703, 0x6355, 0x6B69, 0x752B, 0x88DC, 0x8F14, 0x7A42, 0x52DF, 0x5893, 0x6155, 0x620A, 0x66AE, 0x6BCD, 0x7C3F, 0x83E9, 0x5023, 0x4FF8, 0x5305, 0x5446, 0x5831, 0x5949, 0x5B9D, 0x5CF0, 0x5CEF, 0x5D29, 0x5E96, 0x62B1, 0x6367, 0x653E, 0x65B9, 0x670B, }; const unsigned short euc_to_utf8_CB[] = { 0x6CD5, 0x6CE1, 0x70F9, 0x7832, 0x7E2B, 0x80DE, 0x82B3, 0x840C, 0x84EC, 0x8702, 0x8912, 0x8A2A, 0x8C4A, 0x90A6, 0x92D2, 0x98FD, 0x9CF3, 0x9D6C, 0x4E4F, 0x4EA1, 0x508D, 0x5256, 0x574A, 0x59A8, 0x5E3D, 0x5FD8, 0x5FD9, 0x623F, 0x66B4, 0x671B, 0x67D0, 0x68D2, 0x5192, 0x7D21, 0x80AA, 0x81A8, 0x8B00, 0x8C8C, 0x8CBF, 0x927E, 0x9632, 0x5420, 0x982C, 0x5317, 0x50D5, 0x535C, 0x58A8, 0x64B2, 0x6734, 0x7267, 0x7766, 0x7A46, 0x91E6, 0x52C3, 0x6CA1, 0x6B86, 0x5800, 0x5E4C, 0x5954, 0x672C, 0x7FFB, 0x51E1, 0x76C6, 0x6469, 0x78E8, 0x9B54, 0x9EBB, 0x57CB, 0x59B9, 0x6627, 0x679A, 0x6BCE, 0x54E9, 0x69D9, 0x5E55, 0x819C, 0x6795, 0x9BAA, 0x67FE, 0x9C52, 0x685D, 0x4EA6, 0x4FE3, 0x53C8, 0x62B9, 0x672B, 0x6CAB, 0x8FC4, 0x4FAD, 0x7E6D, 0x9EBF, 0x4E07, 0x6162, 0x6E80, }; const unsigned short euc_to_utf8_CC[] = { 0x6F2B, 0x8513, 0x5473, 0x672A, 0x9B45, 0x5DF3, 0x7B95, 0x5CAC, 0x5BC6, 0x871C, 0x6E4A, 0x84D1, 0x7A14, 0x8108, 0x5999, 0x7C8D, 0x6C11, 0x7720, 0x52D9, 0x5922, 0x7121, 0x725F, 0x77DB, 0x9727, 0x9D61, 0x690B, 0x5A7F, 0x5A18, 0x51A5, 0x540D, 0x547D, 0x660E, 0x76DF, 0x8FF7, 0x9298, 0x9CF4, 0x59EA, 0x725D, 0x6EC5, 0x514D, 0x68C9, 0x7DBF, 0x7DEC, 0x9762, 0x9EBA, 0x6478, 0x6A21, 0x8302, 0x5984, 0x5B5F, 0x6BDB, 0x731B, 0x76F2, 0x7DB2, 0x8017, 0x8499, 0x5132, 0x6728, 0x9ED9, 0x76EE, 0x6762, 0x52FF, 0x9905, 0x5C24, 0x623B, 0x7C7E, 0x8CB0, 0x554F, 0x60B6, 0x7D0B, 0x9580, 0x5301, 0x4E5F, 0x51B6, 0x591C, 0x723A, 0x8036, 0x91CE, 0x5F25, 0x77E2, 0x5384, 0x5F79, 0x7D04, 0x85AC, 0x8A33, 0x8E8D, 0x9756, 0x67F3, 0x85AE, 0x9453, 0x6109, 0x6108, 0x6CB9, 0x7652, }; const unsigned short euc_to_utf8_CD[] = { 0x8AED, 0x8F38, 0x552F, 0x4F51, 0x512A, 0x52C7, 0x53CB, 0x5BA5, 0x5E7D, 0x60A0, 0x6182, 0x63D6, 0x6709, 0x67DA, 0x6E67, 0x6D8C, 0x7336, 0x7337, 0x7531, 0x7950, 0x88D5, 0x8A98, 0x904A, 0x9091, 0x90F5, 0x96C4, 0x878D, 0x5915, 0x4E88, 0x4F59, 0x4E0E, 0x8A89, 0x8F3F, 0x9810, 0x50AD, 0x5E7C, 0x5996, 0x5BB9, 0x5EB8, 0x63DA, 0x63FA, 0x64C1, 0x66DC, 0x694A, 0x69D8, 0x6D0B, 0x6EB6, 0x7194, 0x7528, 0x7AAF, 0x7F8A, 0x8000, 0x8449, 0x84C9, 0x8981, 0x8B21, 0x8E0A, 0x9065, 0x967D, 0x990A, 0x617E, 0x6291, 0x6B32, 0x6C83, 0x6D74, 0x7FCC, 0x7FFC, 0x6DC0, 0x7F85, 0x87BA, 0x88F8, 0x6765, 0x83B1, 0x983C, 0x96F7, 0x6D1B, 0x7D61, 0x843D, 0x916A, 0x4E71, 0x5375, 0x5D50, 0x6B04, 0x6FEB, 0x85CD, 0x862D, 0x89A7, 0x5229, 0x540F, 0x5C65, 0x674E, 0x68A8, 0x7406, 0x7483, }; const unsigned short euc_to_utf8_CE[] = { 0x75E2, 0x88CF, 0x88E1, 0x91CC, 0x96E2, 0x9678, 0x5F8B, 0x7387, 0x7ACB, 0x844E, 0x63A0, 0x7565, 0x5289, 0x6D41, 0x6E9C, 0x7409, 0x7559, 0x786B, 0x7C92, 0x9686, 0x7ADC, 0x9F8D, 0x4FB6, 0x616E, 0x65C5, 0x865C, 0x4E86, 0x4EAE, 0x50DA, 0x4E21, 0x51CC, 0x5BEE, 0x6599, 0x6881, 0x6DBC, 0x731F, 0x7642, 0x77AD, 0x7A1C, 0x7CE7, 0x826F, 0x8AD2, 0x907C, 0x91CF, 0x9675, 0x9818, 0x529B, 0x7DD1, 0x502B, 0x5398, 0x6797, 0x6DCB, 0x71D0, 0x7433, 0x81E8, 0x8F2A, 0x96A3, 0x9C57, 0x9E9F, 0x7460, 0x5841, 0x6D99, 0x7D2F, 0x985E, 0x4EE4, 0x4F36, 0x4F8B, 0x51B7, 0x52B1, 0x5DBA, 0x601C, 0x73B2, 0x793C, 0x82D3, 0x9234, 0x96B7, 0x96F6, 0x970A, 0x9E97, 0x9F62, 0x66A6, 0x6B74, 0x5217, 0x52A3, 0x70C8, 0x88C2, 0x5EC9, 0x604B, 0x6190, 0x6F23, 0x7149, 0x7C3E, 0x7DF4, 0x806F, }; const unsigned short euc_to_utf8_CF[] = { 0x84EE, 0x9023, 0x932C, 0x5442, 0x9B6F, 0x6AD3, 0x7089, 0x8CC2, 0x8DEF, 0x9732, 0x52B4, 0x5A41, 0x5ECA, 0x5F04, 0x6717, 0x697C, 0x6994, 0x6D6A, 0x6F0F, 0x7262, 0x72FC, 0x7BED, 0x8001, 0x807E, 0x874B, 0x90CE, 0x516D, 0x9E93, 0x7984, 0x808B, 0x9332, 0x8AD6, 0x502D, 0x548C, 0x8A71, 0x6B6A, 0x8CC4, 0x8107, 0x60D1, 0x67A0, 0x9DF2, 0x4E99, 0x4E98, 0x9C10, 0x8A6B, 0x85C1, 0x8568, 0x6900, 0x6E7E, 0x7897, 0x8155, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short euc_to_utf8_D0[] = { 0x5F0C, 0x4E10, 0x4E15, 0x4E2A, 0x4E31, 0x4E36, 0x4E3C, 0x4E3F, 0x4E42, 0x4E56, 0x4E58, 0x4E82, 0x4E85, 0x8C6B, 0x4E8A, 0x8212, 0x5F0D, 0x4E8E, 0x4E9E, 0x4E9F, 0x4EA0, 0x4EA2, 0x4EB0, 0x4EB3, 0x4EB6, 0x4ECE, 0x4ECD, 0x4EC4, 0x4EC6, 0x4EC2, 0x4ED7, 0x4EDE, 0x4EED, 0x4EDF, 0x4EF7, 0x4F09, 0x4F5A, 0x4F30, 0x4F5B, 0x4F5D, 0x4F57, 0x4F47, 0x4F76, 0x4F88, 0x4F8F, 0x4F98, 0x4F7B, 0x4F69, 0x4F70, 0x4F91, 0x4F6F, 0x4F86, 0x4F96, 0x5118, 0x4FD4, 0x4FDF, 0x4FCE, 0x4FD8, 0x4FDB, 0x4FD1, 0x4FDA, 0x4FD0, 0x4FE4, 0x4FE5, 0x501A, 0x5028, 0x5014, 0x502A, 0x5025, 0x5005, 0x4F1C, 0x4FF6, 0x5021, 0x5029, 0x502C, 0x4FFE, 0x4FEF, 0x5011, 0x5006, 0x5043, 0x5047, 0x6703, 0x5055, 0x5050, 0x5048, 0x505A, 0x5056, 0x506C, 0x5078, 0x5080, 0x509A, 0x5085, 0x50B4, 0x50B2, }; const unsigned short euc_to_utf8_D1[] = { 0x50C9, 0x50CA, 0x50B3, 0x50C2, 0x50D6, 0x50DE, 0x50E5, 0x50ED, 0x50E3, 0x50EE, 0x50F9, 0x50F5, 0x5109, 0x5101, 0x5102, 0x5116, 0x5115, 0x5114, 0x511A, 0x5121, 0x513A, 0x5137, 0x513C, 0x513B, 0x513F, 0x5140, 0x5152, 0x514C, 0x5154, 0x5162, 0x7AF8, 0x5169, 0x516A, 0x516E, 0x5180, 0x5182, 0x56D8, 0x518C, 0x5189, 0x518F, 0x5191, 0x5193, 0x5195, 0x5196, 0x51A4, 0x51A6, 0x51A2, 0x51A9, 0x51AA, 0x51AB, 0x51B3, 0x51B1, 0x51B2, 0x51B0, 0x51B5, 0x51BD, 0x51C5, 0x51C9, 0x51DB, 0x51E0, 0x8655, 0x51E9, 0x51ED, 0x51F0, 0x51F5, 0x51FE, 0x5204, 0x520B, 0x5214, 0x520E, 0x5227, 0x522A, 0x522E, 0x5233, 0x5239, 0x524F, 0x5244, 0x524B, 0x524C, 0x525E, 0x5254, 0x526A, 0x5274, 0x5269, 0x5273, 0x527F, 0x527D, 0x528D, 0x5294, 0x5292, 0x5271, 0x5288, 0x5291, 0x8FA8, }; const unsigned short euc_to_utf8_D2[] = { 0x8FA7, 0x52AC, 0x52AD, 0x52BC, 0x52B5, 0x52C1, 0x52CD, 0x52D7, 0x52DE, 0x52E3, 0x52E6, 0x98ED, 0x52E0, 0x52F3, 0x52F5, 0x52F8, 0x52F9, 0x5306, 0x5308, 0x7538, 0x530D, 0x5310, 0x530F, 0x5315, 0x531A, 0x5323, 0x532F, 0x5331, 0x5333, 0x5338, 0x5340, 0x5346, 0x5345, 0x4E17, 0x5349, 0x534D, 0x51D6, 0x535E, 0x5369, 0x536E, 0x5918, 0x537B, 0x5377, 0x5382, 0x5396, 0x53A0, 0x53A6, 0x53A5, 0x53AE, 0x53B0, 0x53B6, 0x53C3, 0x7C12, 0x96D9, 0x53DF, 0x66FC, 0x71EE, 0x53EE, 0x53E8, 0x53ED, 0x53FA, 0x5401, 0x543D, 0x5440, 0x542C, 0x542D, 0x543C, 0x542E, 0x5436, 0x5429, 0x541D, 0x544E, 0x548F, 0x5475, 0x548E, 0x545F, 0x5471, 0x5477, 0x5470, 0x5492, 0x547B, 0x5480, 0x5476, 0x5484, 0x5490, 0x5486, 0x54C7, 0x54A2, 0x54B8, 0x54A5, 0x54AC, 0x54C4, 0x54C8, 0x54A8, }; const unsigned short euc_to_utf8_D3[] = { 0x54AB, 0x54C2, 0x54A4, 0x54BE, 0x54BC, 0x54D8, 0x54E5, 0x54E6, 0x550F, 0x5514, 0x54FD, 0x54EE, 0x54ED, 0x54FA, 0x54E2, 0x5539, 0x5540, 0x5563, 0x554C, 0x552E, 0x555C, 0x5545, 0x5556, 0x5557, 0x5538, 0x5533, 0x555D, 0x5599, 0x5580, 0x54AF, 0x558A, 0x559F, 0x557B, 0x557E, 0x5598, 0x559E, 0x55AE, 0x557C, 0x5583, 0x55A9, 0x5587, 0x55A8, 0x55DA, 0x55C5, 0x55DF, 0x55C4, 0x55DC, 0x55E4, 0x55D4, 0x5614, 0x55F7, 0x5616, 0x55FE, 0x55FD, 0x561B, 0x55F9, 0x564E, 0x5650, 0x71DF, 0x5634, 0x5636, 0x5632, 0x5638, 0x566B, 0x5664, 0x562F, 0x566C, 0x566A, 0x5686, 0x5680, 0x568A, 0x56A0, 0x5694, 0x568F, 0x56A5, 0x56AE, 0x56B6, 0x56B4, 0x56C2, 0x56BC, 0x56C1, 0x56C3, 0x56C0, 0x56C8, 0x56CE, 0x56D1, 0x56D3, 0x56D7, 0x56EE, 0x56F9, 0x5700, 0x56FF, 0x5704, 0x5709, }; const unsigned short euc_to_utf8_D4[] = { 0x5708, 0x570B, 0x570D, 0x5713, 0x5718, 0x5716, 0x55C7, 0x571C, 0x5726, 0x5737, 0x5738, 0x574E, 0x573B, 0x5740, 0x574F, 0x5769, 0x57C0, 0x5788, 0x5761, 0x577F, 0x5789, 0x5793, 0x57A0, 0x57B3, 0x57A4, 0x57AA, 0x57B0, 0x57C3, 0x57C6, 0x57D4, 0x57D2, 0x57D3, 0x580A, 0x57D6, 0x57E3, 0x580B, 0x5819, 0x581D, 0x5872, 0x5821, 0x5862, 0x584B, 0x5870, 0x6BC0, 0x5852, 0x583D, 0x5879, 0x5885, 0x58B9, 0x589F, 0x58AB, 0x58BA, 0x58DE, 0x58BB, 0x58B8, 0x58AE, 0x58C5, 0x58D3, 0x58D1, 0x58D7, 0x58D9, 0x58D8, 0x58E5, 0x58DC, 0x58E4, 0x58DF, 0x58EF, 0x58FA, 0x58F9, 0x58FB, 0x58FC, 0x58FD, 0x5902, 0x590A, 0x5910, 0x591B, 0x68A6, 0x5925, 0x592C, 0x592D, 0x5932, 0x5938, 0x593E, 0x7AD2, 0x5955, 0x5950, 0x594E, 0x595A, 0x5958, 0x5962, 0x5960, 0x5967, 0x596C, 0x5969, }; const unsigned short euc_to_utf8_D5[] = { 0x5978, 0x5981, 0x599D, 0x4F5E, 0x4FAB, 0x59A3, 0x59B2, 0x59C6, 0x59E8, 0x59DC, 0x598D, 0x59D9, 0x59DA, 0x5A25, 0x5A1F, 0x5A11, 0x5A1C, 0x5A09, 0x5A1A, 0x5A40, 0x5A6C, 0x5A49, 0x5A35, 0x5A36, 0x5A62, 0x5A6A, 0x5A9A, 0x5ABC, 0x5ABE, 0x5ACB, 0x5AC2, 0x5ABD, 0x5AE3, 0x5AD7, 0x5AE6, 0x5AE9, 0x5AD6, 0x5AFA, 0x5AFB, 0x5B0C, 0x5B0B, 0x5B16, 0x5B32, 0x5AD0, 0x5B2A, 0x5B36, 0x5B3E, 0x5B43, 0x5B45, 0x5B40, 0x5B51, 0x5B55, 0x5B5A, 0x5B5B, 0x5B65, 0x5B69, 0x5B70, 0x5B73, 0x5B75, 0x5B78, 0x6588, 0x5B7A, 0x5B80, 0x5B83, 0x5BA6, 0x5BB8, 0x5BC3, 0x5BC7, 0x5BC9, 0x5BD4, 0x5BD0, 0x5BE4, 0x5BE6, 0x5BE2, 0x5BDE, 0x5BE5, 0x5BEB, 0x5BF0, 0x5BF6, 0x5BF3, 0x5C05, 0x5C07, 0x5C08, 0x5C0D, 0x5C13, 0x5C20, 0x5C22, 0x5C28, 0x5C38, 0x5C39, 0x5C41, 0x5C46, 0x5C4E, 0x5C53, }; const unsigned short euc_to_utf8_D6[] = { 0x5C50, 0x5C4F, 0x5B71, 0x5C6C, 0x5C6E, 0x4E62, 0x5C76, 0x5C79, 0x5C8C, 0x5C91, 0x5C94, 0x599B, 0x5CAB, 0x5CBB, 0x5CB6, 0x5CBC, 0x5CB7, 0x5CC5, 0x5CBE, 0x5CC7, 0x5CD9, 0x5CE9, 0x5CFD, 0x5CFA, 0x5CED, 0x5D8C, 0x5CEA, 0x5D0B, 0x5D15, 0x5D17, 0x5D5C, 0x5D1F, 0x5D1B, 0x5D11, 0x5D14, 0x5D22, 0x5D1A, 0x5D19, 0x5D18, 0x5D4C, 0x5D52, 0x5D4E, 0x5D4B, 0x5D6C, 0x5D73, 0x5D76, 0x5D87, 0x5D84, 0x5D82, 0x5DA2, 0x5D9D, 0x5DAC, 0x5DAE, 0x5DBD, 0x5D90, 0x5DB7, 0x5DBC, 0x5DC9, 0x5DCD, 0x5DD3, 0x5DD2, 0x5DD6, 0x5DDB, 0x5DEB, 0x5DF2, 0x5DF5, 0x5E0B, 0x5E1A, 0x5E19, 0x5E11, 0x5E1B, 0x5E36, 0x5E37, 0x5E44, 0x5E43, 0x5E40, 0x5E4E, 0x5E57, 0x5E54, 0x5E5F, 0x5E62, 0x5E64, 0x5E47, 0x5E75, 0x5E76, 0x5E7A, 0x9EBC, 0x5E7F, 0x5EA0, 0x5EC1, 0x5EC2, 0x5EC8, 0x5ED0, 0x5ECF, }; const unsigned short euc_to_utf8_D7[] = { 0x5ED6, 0x5EE3, 0x5EDD, 0x5EDA, 0x5EDB, 0x5EE2, 0x5EE1, 0x5EE8, 0x5EE9, 0x5EEC, 0x5EF1, 0x5EF3, 0x5EF0, 0x5EF4, 0x5EF8, 0x5EFE, 0x5F03, 0x5F09, 0x5F5D, 0x5F5C, 0x5F0B, 0x5F11, 0x5F16, 0x5F29, 0x5F2D, 0x5F38, 0x5F41, 0x5F48, 0x5F4C, 0x5F4E, 0x5F2F, 0x5F51, 0x5F56, 0x5F57, 0x5F59, 0x5F61, 0x5F6D, 0x5F73, 0x5F77, 0x5F83, 0x5F82, 0x5F7F, 0x5F8A, 0x5F88, 0x5F91, 0x5F87, 0x5F9E, 0x5F99, 0x5F98, 0x5FA0, 0x5FA8, 0x5FAD, 0x5FBC, 0x5FD6, 0x5FFB, 0x5FE4, 0x5FF8, 0x5FF1, 0x5FDD, 0x60B3, 0x5FFF, 0x6021, 0x6060, 0x6019, 0x6010, 0x6029, 0x600E, 0x6031, 0x601B, 0x6015, 0x602B, 0x6026, 0x600F, 0x603A, 0x605A, 0x6041, 0x606A, 0x6077, 0x605F, 0x604A, 0x6046, 0x604D, 0x6063, 0x6043, 0x6064, 0x6042, 0x606C, 0x606B, 0x6059, 0x6081, 0x608D, 0x60E7, 0x6083, 0x609A, }; const unsigned short euc_to_utf8_D8[] = { 0x6084, 0x609B, 0x6096, 0x6097, 0x6092, 0x60A7, 0x608B, 0x60E1, 0x60B8, 0x60E0, 0x60D3, 0x60B4, 0x5FF0, 0x60BD, 0x60C6, 0x60B5, 0x60D8, 0x614D, 0x6115, 0x6106, 0x60F6, 0x60F7, 0x6100, 0x60F4, 0x60FA, 0x6103, 0x6121, 0x60FB, 0x60F1, 0x610D, 0x610E, 0x6147, 0x613E, 0x6128, 0x6127, 0x614A, 0x613F, 0x613C, 0x612C, 0x6134, 0x613D, 0x6142, 0x6144, 0x6173, 0x6177, 0x6158, 0x6159, 0x615A, 0x616B, 0x6174, 0x616F, 0x6165, 0x6171, 0x615F, 0x615D, 0x6153, 0x6175, 0x6199, 0x6196, 0x6187, 0x61AC, 0x6194, 0x619A, 0x618A, 0x6191, 0x61AB, 0x61AE, 0x61CC, 0x61CA, 0x61C9, 0x61F7, 0x61C8, 0x61C3, 0x61C6, 0x61BA, 0x61CB, 0x7F79, 0x61CD, 0x61E6, 0x61E3, 0x61F6, 0x61FA, 0x61F4, 0x61FF, 0x61FD, 0x61FC, 0x61FE, 0x6200, 0x6208, 0x6209, 0x620D, 0x620C, 0x6214, 0x621B, }; const unsigned short euc_to_utf8_D9[] = { 0x621E, 0x6221, 0x622A, 0x622E, 0x6230, 0x6232, 0x6233, 0x6241, 0x624E, 0x625E, 0x6263, 0x625B, 0x6260, 0x6268, 0x627C, 0x6282, 0x6289, 0x627E, 0x6292, 0x6293, 0x6296, 0x62D4, 0x6283, 0x6294, 0x62D7, 0x62D1, 0x62BB, 0x62CF, 0x62FF, 0x62C6, 0x64D4, 0x62C8, 0x62DC, 0x62CC, 0x62CA, 0x62C2, 0x62C7, 0x629B, 0x62C9, 0x630C, 0x62EE, 0x62F1, 0x6327, 0x6302, 0x6308, 0x62EF, 0x62F5, 0x6350, 0x633E, 0x634D, 0x641C, 0x634F, 0x6396, 0x638E, 0x6380, 0x63AB, 0x6376, 0x63A3, 0x638F, 0x6389, 0x639F, 0x63B5, 0x636B, 0x6369, 0x63BE, 0x63E9, 0x63C0, 0x63C6, 0x63E3, 0x63C9, 0x63D2, 0x63F6, 0x63C4, 0x6416, 0x6434, 0x6406, 0x6413, 0x6426, 0x6436, 0x651D, 0x6417, 0x6428, 0x640F, 0x6467, 0x646F, 0x6476, 0x644E, 0x652A, 0x6495, 0x6493, 0x64A5, 0x64A9, 0x6488, 0x64BC, }; const unsigned short euc_to_utf8_DA[] = { 0x64DA, 0x64D2, 0x64C5, 0x64C7, 0x64BB, 0x64D8, 0x64C2, 0x64F1, 0x64E7, 0x8209, 0x64E0, 0x64E1, 0x62AC, 0x64E3, 0x64EF, 0x652C, 0x64F6, 0x64F4, 0x64F2, 0x64FA, 0x6500, 0x64FD, 0x6518, 0x651C, 0x6505, 0x6524, 0x6523, 0x652B, 0x6534, 0x6535, 0x6537, 0x6536, 0x6538, 0x754B, 0x6548, 0x6556, 0x6555, 0x654D, 0x6558, 0x655E, 0x655D, 0x6572, 0x6578, 0x6582, 0x6583, 0x8B8A, 0x659B, 0x659F, 0x65AB, 0x65B7, 0x65C3, 0x65C6, 0x65C1, 0x65C4, 0x65CC, 0x65D2, 0x65DB, 0x65D9, 0x65E0, 0x65E1, 0x65F1, 0x6772, 0x660A, 0x6603, 0x65FB, 0x6773, 0x6635, 0x6636, 0x6634, 0x661C, 0x664F, 0x6644, 0x6649, 0x6641, 0x665E, 0x665D, 0x6664, 0x6667, 0x6668, 0x665F, 0x6662, 0x6670, 0x6683, 0x6688, 0x668E, 0x6689, 0x6684, 0x6698, 0x669D, 0x66C1, 0x66B9, 0x66C9, 0x66BE, 0x66BC, }; const unsigned short euc_to_utf8_DB[] = { 0x66C4, 0x66B8, 0x66D6, 0x66DA, 0x66E0, 0x663F, 0x66E6, 0x66E9, 0x66F0, 0x66F5, 0x66F7, 0x670F, 0x6716, 0x671E, 0x6726, 0x6727, 0x9738, 0x672E, 0x673F, 0x6736, 0x6741, 0x6738, 0x6737, 0x6746, 0x675E, 0x6760, 0x6759, 0x6763, 0x6764, 0x6789, 0x6770, 0x67A9, 0x677C, 0x676A, 0x678C, 0x678B, 0x67A6, 0x67A1, 0x6785, 0x67B7, 0x67EF, 0x67B4, 0x67EC, 0x67B3, 0x67E9, 0x67B8, 0x67E4, 0x67DE, 0x67DD, 0x67E2, 0x67EE, 0x67B9, 0x67CE, 0x67C6, 0x67E7, 0x6A9C, 0x681E, 0x6846, 0x6829, 0x6840, 0x684D, 0x6832, 0x684E, 0x68B3, 0x682B, 0x6859, 0x6863, 0x6877, 0x687F, 0x689F, 0x688F, 0x68AD, 0x6894, 0x689D, 0x689B, 0x6883, 0x6AAE, 0x68B9, 0x6874, 0x68B5, 0x68A0, 0x68BA, 0x690F, 0x688D, 0x687E, 0x6901, 0x68CA, 0x6908, 0x68D8, 0x6922, 0x6926, 0x68E1, 0x690C, 0x68CD, }; const unsigned short euc_to_utf8_DC[] = { 0x68D4, 0x68E7, 0x68D5, 0x6936, 0x6912, 0x6904, 0x68D7, 0x68E3, 0x6925, 0x68F9, 0x68E0, 0x68EF, 0x6928, 0x692A, 0x691A, 0x6923, 0x6921, 0x68C6, 0x6979, 0x6977, 0x695C, 0x6978, 0x696B, 0x6954, 0x697E, 0x696E, 0x6939, 0x6974, 0x693D, 0x6959, 0x6930, 0x6961, 0x695E, 0x695D, 0x6981, 0x696A, 0x69B2, 0x69AE, 0x69D0, 0x69BF, 0x69C1, 0x69D3, 0x69BE, 0x69CE, 0x5BE8, 0x69CA, 0x69DD, 0x69BB, 0x69C3, 0x69A7, 0x6A2E, 0x6991, 0x69A0, 0x699C, 0x6995, 0x69B4, 0x69DE, 0x69E8, 0x6A02, 0x6A1B, 0x69FF, 0x6B0A, 0x69F9, 0x69F2, 0x69E7, 0x6A05, 0x69B1, 0x6A1E, 0x69ED, 0x6A14, 0x69EB, 0x6A0A, 0x6A12, 0x6AC1, 0x6A23, 0x6A13, 0x6A44, 0x6A0C, 0x6A72, 0x6A36, 0x6A78, 0x6A47, 0x6A62, 0x6A59, 0x6A66, 0x6A48, 0x6A38, 0x6A22, 0x6A90, 0x6A8D, 0x6AA0, 0x6A84, 0x6AA2, 0x6AA3, }; const unsigned short euc_to_utf8_DD[] = { 0x6A97, 0x8617, 0x6ABB, 0x6AC3, 0x6AC2, 0x6AB8, 0x6AB3, 0x6AAC, 0x6ADE, 0x6AD1, 0x6ADF, 0x6AAA, 0x6ADA, 0x6AEA, 0x6AFB, 0x6B05, 0x8616, 0x6AFA, 0x6B12, 0x6B16, 0x9B31, 0x6B1F, 0x6B38, 0x6B37, 0x76DC, 0x6B39, 0x98EE, 0x6B47, 0x6B43, 0x6B49, 0x6B50, 0x6B59, 0x6B54, 0x6B5B, 0x6B5F, 0x6B61, 0x6B78, 0x6B79, 0x6B7F, 0x6B80, 0x6B84, 0x6B83, 0x6B8D, 0x6B98, 0x6B95, 0x6B9E, 0x6BA4, 0x6BAA, 0x6BAB, 0x6BAF, 0x6BB2, 0x6BB1, 0x6BB3, 0x6BB7, 0x6BBC, 0x6BC6, 0x6BCB, 0x6BD3, 0x6BDF, 0x6BEC, 0x6BEB, 0x6BF3, 0x6BEF, 0x9EBE, 0x6C08, 0x6C13, 0x6C14, 0x6C1B, 0x6C24, 0x6C23, 0x6C5E, 0x6C55, 0x6C62, 0x6C6A, 0x6C82, 0x6C8D, 0x6C9A, 0x6C81, 0x6C9B, 0x6C7E, 0x6C68, 0x6C73, 0x6C92, 0x6C90, 0x6CC4, 0x6CF1, 0x6CD3, 0x6CBD, 0x6CD7, 0x6CC5, 0x6CDD, 0x6CAE, 0x6CB1, 0x6CBE, }; const unsigned short euc_to_utf8_DE[] = { 0x6CBA, 0x6CDB, 0x6CEF, 0x6CD9, 0x6CEA, 0x6D1F, 0x884D, 0x6D36, 0x6D2B, 0x6D3D, 0x6D38, 0x6D19, 0x6D35, 0x6D33, 0x6D12, 0x6D0C, 0x6D63, 0x6D93, 0x6D64, 0x6D5A, 0x6D79, 0x6D59, 0x6D8E, 0x6D95, 0x6FE4, 0x6D85, 0x6DF9, 0x6E15, 0x6E0A, 0x6DB5, 0x6DC7, 0x6DE6, 0x6DB8, 0x6DC6, 0x6DEC, 0x6DDE, 0x6DCC, 0x6DE8, 0x6DD2, 0x6DC5, 0x6DFA, 0x6DD9, 0x6DE4, 0x6DD5, 0x6DEA, 0x6DEE, 0x6E2D, 0x6E6E, 0x6E2E, 0x6E19, 0x6E72, 0x6E5F, 0x6E3E, 0x6E23, 0x6E6B, 0x6E2B, 0x6E76, 0x6E4D, 0x6E1F, 0x6E43, 0x6E3A, 0x6E4E, 0x6E24, 0x6EFF, 0x6E1D, 0x6E38, 0x6E82, 0x6EAA, 0x6E98, 0x6EC9, 0x6EB7, 0x6ED3, 0x6EBD, 0x6EAF, 0x6EC4, 0x6EB2, 0x6ED4, 0x6ED5, 0x6E8F, 0x6EA5, 0x6EC2, 0x6E9F, 0x6F41, 0x6F11, 0x704C, 0x6EEC, 0x6EF8, 0x6EFE, 0x6F3F, 0x6EF2, 0x6F31, 0x6EEF, 0x6F32, 0x6ECC, }; const unsigned short euc_to_utf8_DF[] = { 0x6F3E, 0x6F13, 0x6EF7, 0x6F86, 0x6F7A, 0x6F78, 0x6F81, 0x6F80, 0x6F6F, 0x6F5B, 0x6FF3, 0x6F6D, 0x6F82, 0x6F7C, 0x6F58, 0x6F8E, 0x6F91, 0x6FC2, 0x6F66, 0x6FB3, 0x6FA3, 0x6FA1, 0x6FA4, 0x6FB9, 0x6FC6, 0x6FAA, 0x6FDF, 0x6FD5, 0x6FEC, 0x6FD4, 0x6FD8, 0x6FF1, 0x6FEE, 0x6FDB, 0x7009, 0x700B, 0x6FFA, 0x7011, 0x7001, 0x700F, 0x6FFE, 0x701B, 0x701A, 0x6F74, 0x701D, 0x7018, 0x701F, 0x7030, 0x703E, 0x7032, 0x7051, 0x7063, 0x7099, 0x7092, 0x70AF, 0x70F1, 0x70AC, 0x70B8, 0x70B3, 0x70AE, 0x70DF, 0x70CB, 0x70DD, 0x70D9, 0x7109, 0x70FD, 0x711C, 0x7119, 0x7165, 0x7155, 0x7188, 0x7166, 0x7162, 0x714C, 0x7156, 0x716C, 0x718F, 0x71FB, 0x7184, 0x7195, 0x71A8, 0x71AC, 0x71D7, 0x71B9, 0x71BE, 0x71D2, 0x71C9, 0x71D4, 0x71CE, 0x71E0, 0x71EC, 0x71E7, 0x71F5, 0x71FC, }; const unsigned short euc_to_utf8_E0[] = { 0x71F9, 0x71FF, 0x720D, 0x7210, 0x721B, 0x7228, 0x722D, 0x722C, 0x7230, 0x7232, 0x723B, 0x723C, 0x723F, 0x7240, 0x7246, 0x724B, 0x7258, 0x7274, 0x727E, 0x7282, 0x7281, 0x7287, 0x7292, 0x7296, 0x72A2, 0x72A7, 0x72B9, 0x72B2, 0x72C3, 0x72C6, 0x72C4, 0x72CE, 0x72D2, 0x72E2, 0x72E0, 0x72E1, 0x72F9, 0x72F7, 0x500F, 0x7317, 0x730A, 0x731C, 0x7316, 0x731D, 0x7334, 0x732F, 0x7329, 0x7325, 0x733E, 0x734E, 0x734F, 0x9ED8, 0x7357, 0x736A, 0x7368, 0x7370, 0x7378, 0x7375, 0x737B, 0x737A, 0x73C8, 0x73B3, 0x73CE, 0x73BB, 0x73C0, 0x73E5, 0x73EE, 0x73DE, 0x74A2, 0x7405, 0x746F, 0x7425, 0x73F8, 0x7432, 0x743A, 0x7455, 0x743F, 0x745F, 0x7459, 0x7441, 0x745C, 0x7469, 0x7470, 0x7463, 0x746A, 0x7476, 0x747E, 0x748B, 0x749E, 0x74A7, 0x74CA, 0x74CF, 0x74D4, 0x73F1, }; const unsigned short euc_to_utf8_E1[] = { 0x74E0, 0x74E3, 0x74E7, 0x74E9, 0x74EE, 0x74F2, 0x74F0, 0x74F1, 0x74F8, 0x74F7, 0x7504, 0x7503, 0x7505, 0x750C, 0x750E, 0x750D, 0x7515, 0x7513, 0x751E, 0x7526, 0x752C, 0x753C, 0x7544, 0x754D, 0x754A, 0x7549, 0x755B, 0x7546, 0x755A, 0x7569, 0x7564, 0x7567, 0x756B, 0x756D, 0x7578, 0x7576, 0x7586, 0x7587, 0x7574, 0x758A, 0x7589, 0x7582, 0x7594, 0x759A, 0x759D, 0x75A5, 0x75A3, 0x75C2, 0x75B3, 0x75C3, 0x75B5, 0x75BD, 0x75B8, 0x75BC, 0x75B1, 0x75CD, 0x75CA, 0x75D2, 0x75D9, 0x75E3, 0x75DE, 0x75FE, 0x75FF, 0x75FC, 0x7601, 0x75F0, 0x75FA, 0x75F2, 0x75F3, 0x760B, 0x760D, 0x7609, 0x761F, 0x7627, 0x7620, 0x7621, 0x7622, 0x7624, 0x7634, 0x7630, 0x763B, 0x7647, 0x7648, 0x7646, 0x765C, 0x7658, 0x7661, 0x7662, 0x7668, 0x7669, 0x766A, 0x7667, 0x766C, 0x7670, }; const unsigned short euc_to_utf8_E2[] = { 0x7672, 0x7676, 0x7678, 0x767C, 0x7680, 0x7683, 0x7688, 0x768B, 0x768E, 0x7696, 0x7693, 0x7699, 0x769A, 0x76B0, 0x76B4, 0x76B8, 0x76B9, 0x76BA, 0x76C2, 0x76CD, 0x76D6, 0x76D2, 0x76DE, 0x76E1, 0x76E5, 0x76E7, 0x76EA, 0x862F, 0x76FB, 0x7708, 0x7707, 0x7704, 0x7729, 0x7724, 0x771E, 0x7725, 0x7726, 0x771B, 0x7737, 0x7738, 0x7747, 0x775A, 0x7768, 0x776B, 0x775B, 0x7765, 0x777F, 0x777E, 0x7779, 0x778E, 0x778B, 0x7791, 0x77A0, 0x779E, 0x77B0, 0x77B6, 0x77B9, 0x77BF, 0x77BC, 0x77BD, 0x77BB, 0x77C7, 0x77CD, 0x77D7, 0x77DA, 0x77DC, 0x77E3, 0x77EE, 0x77FC, 0x780C, 0x7812, 0x7926, 0x7820, 0x792A, 0x7845, 0x788E, 0x7874, 0x7886, 0x787C, 0x789A, 0x788C, 0x78A3, 0x78B5, 0x78AA, 0x78AF, 0x78D1, 0x78C6, 0x78CB, 0x78D4, 0x78BE, 0x78BC, 0x78C5, 0x78CA, 0x78EC, }; const unsigned short euc_to_utf8_E3[] = { 0x78E7, 0x78DA, 0x78FD, 0x78F4, 0x7907, 0x7912, 0x7911, 0x7919, 0x792C, 0x792B, 0x7940, 0x7960, 0x7957, 0x795F, 0x795A, 0x7955, 0x7953, 0x797A, 0x797F, 0x798A, 0x799D, 0x79A7, 0x9F4B, 0x79AA, 0x79AE, 0x79B3, 0x79B9, 0x79BA, 0x79C9, 0x79D5, 0x79E7, 0x79EC, 0x79E1, 0x79E3, 0x7A08, 0x7A0D, 0x7A18, 0x7A19, 0x7A20, 0x7A1F, 0x7980, 0x7A31, 0x7A3B, 0x7A3E, 0x7A37, 0x7A43, 0x7A57, 0x7A49, 0x7A61, 0x7A62, 0x7A69, 0x9F9D, 0x7A70, 0x7A79, 0x7A7D, 0x7A88, 0x7A97, 0x7A95, 0x7A98, 0x7A96, 0x7AA9, 0x7AC8, 0x7AB0, 0x7AB6, 0x7AC5, 0x7AC4, 0x7ABF, 0x9083, 0x7AC7, 0x7ACA, 0x7ACD, 0x7ACF, 0x7AD5, 0x7AD3, 0x7AD9, 0x7ADA, 0x7ADD, 0x7AE1, 0x7AE2, 0x7AE6, 0x7AED, 0x7AF0, 0x7B02, 0x7B0F, 0x7B0A, 0x7B06, 0x7B33, 0x7B18, 0x7B19, 0x7B1E, 0x7B35, 0x7B28, 0x7B36, 0x7B50, }; const unsigned short euc_to_utf8_E4[] = { 0x7B7A, 0x7B04, 0x7B4D, 0x7B0B, 0x7B4C, 0x7B45, 0x7B75, 0x7B65, 0x7B74, 0x7B67, 0x7B70, 0x7B71, 0x7B6C, 0x7B6E, 0x7B9D, 0x7B98, 0x7B9F, 0x7B8D, 0x7B9C, 0x7B9A, 0x7B8B, 0x7B92, 0x7B8F, 0x7B5D, 0x7B99, 0x7BCB, 0x7BC1, 0x7BCC, 0x7BCF, 0x7BB4, 0x7BC6, 0x7BDD, 0x7BE9, 0x7C11, 0x7C14, 0x7BE6, 0x7BE5, 0x7C60, 0x7C00, 0x7C07, 0x7C13, 0x7BF3, 0x7BF7, 0x7C17, 0x7C0D, 0x7BF6, 0x7C23, 0x7C27, 0x7C2A, 0x7C1F, 0x7C37, 0x7C2B, 0x7C3D, 0x7C4C, 0x7C43, 0x7C54, 0x7C4F, 0x7C40, 0x7C50, 0x7C58, 0x7C5F, 0x7C64, 0x7C56, 0x7C65, 0x7C6C, 0x7C75, 0x7C83, 0x7C90, 0x7CA4, 0x7CAD, 0x7CA2, 0x7CAB, 0x7CA1, 0x7CA8, 0x7CB3, 0x7CB2, 0x7CB1, 0x7CAE, 0x7CB9, 0x7CBD, 0x7CC0, 0x7CC5, 0x7CC2, 0x7CD8, 0x7CD2, 0x7CDC, 0x7CE2, 0x9B3B, 0x7CEF, 0x7CF2, 0x7CF4, 0x7CF6, 0x7CFA, 0x7D06, }; const unsigned short euc_to_utf8_E5[] = { 0x7D02, 0x7D1C, 0x7D15, 0x7D0A, 0x7D45, 0x7D4B, 0x7D2E, 0x7D32, 0x7D3F, 0x7D35, 0x7D46, 0x7D73, 0x7D56, 0x7D4E, 0x7D72, 0x7D68, 0x7D6E, 0x7D4F, 0x7D63, 0x7D93, 0x7D89, 0x7D5B, 0x7D8F, 0x7D7D, 0x7D9B, 0x7DBA, 0x7DAE, 0x7DA3, 0x7DB5, 0x7DC7, 0x7DBD, 0x7DAB, 0x7E3D, 0x7DA2, 0x7DAF, 0x7DDC, 0x7DB8, 0x7D9F, 0x7DB0, 0x7DD8, 0x7DDD, 0x7DE4, 0x7DDE, 0x7DFB, 0x7DF2, 0x7DE1, 0x7E05, 0x7E0A, 0x7E23, 0x7E21, 0x7E12, 0x7E31, 0x7E1F, 0x7E09, 0x7E0B, 0x7E22, 0x7E46, 0x7E66, 0x7E3B, 0x7E35, 0x7E39, 0x7E43, 0x7E37, 0x7E32, 0x7E3A, 0x7E67, 0x7E5D, 0x7E56, 0x7E5E, 0x7E59, 0x7E5A, 0x7E79, 0x7E6A, 0x7E69, 0x7E7C, 0x7E7B, 0x7E83, 0x7DD5, 0x7E7D, 0x8FAE, 0x7E7F, 0x7E88, 0x7E89, 0x7E8C, 0x7E92, 0x7E90, 0x7E93, 0x7E94, 0x7E96, 0x7E8E, 0x7E9B, 0x7E9C, 0x7F38, 0x7F3A, }; const unsigned short euc_to_utf8_E6[] = { 0x7F45, 0x7F4C, 0x7F4D, 0x7F4E, 0x7F50, 0x7F51, 0x7F55, 0x7F54, 0x7F58, 0x7F5F, 0x7F60, 0x7F68, 0x7F69, 0x7F67, 0x7F78, 0x7F82, 0x7F86, 0x7F83, 0x7F88, 0x7F87, 0x7F8C, 0x7F94, 0x7F9E, 0x7F9D, 0x7F9A, 0x7FA3, 0x7FAF, 0x7FB2, 0x7FB9, 0x7FAE, 0x7FB6, 0x7FB8, 0x8B71, 0x7FC5, 0x7FC6, 0x7FCA, 0x7FD5, 0x7FD4, 0x7FE1, 0x7FE6, 0x7FE9, 0x7FF3, 0x7FF9, 0x98DC, 0x8006, 0x8004, 0x800B, 0x8012, 0x8018, 0x8019, 0x801C, 0x8021, 0x8028, 0x803F, 0x803B, 0x804A, 0x8046, 0x8052, 0x8058, 0x805A, 0x805F, 0x8062, 0x8068, 0x8073, 0x8072, 0x8070, 0x8076, 0x8079, 0x807D, 0x807F, 0x8084, 0x8086, 0x8085, 0x809B, 0x8093, 0x809A, 0x80AD, 0x5190, 0x80AC, 0x80DB, 0x80E5, 0x80D9, 0x80DD, 0x80C4, 0x80DA, 0x80D6, 0x8109, 0x80EF, 0x80F1, 0x811B, 0x8129, 0x8123, 0x812F, 0x814B, }; const unsigned short euc_to_utf8_E7[] = { 0x968B, 0x8146, 0x813E, 0x8153, 0x8151, 0x80FC, 0x8171, 0x816E, 0x8165, 0x8166, 0x8174, 0x8183, 0x8188, 0x818A, 0x8180, 0x8182, 0x81A0, 0x8195, 0x81A4, 0x81A3, 0x815F, 0x8193, 0x81A9, 0x81B0, 0x81B5, 0x81BE, 0x81B8, 0x81BD, 0x81C0, 0x81C2, 0x81BA, 0x81C9, 0x81CD, 0x81D1, 0x81D9, 0x81D8, 0x81C8, 0x81DA, 0x81DF, 0x81E0, 0x81E7, 0x81FA, 0x81FB, 0x81FE, 0x8201, 0x8202, 0x8205, 0x8207, 0x820A, 0x820D, 0x8210, 0x8216, 0x8229, 0x822B, 0x8238, 0x8233, 0x8240, 0x8259, 0x8258, 0x825D, 0x825A, 0x825F, 0x8264, 0x8262, 0x8268, 0x826A, 0x826B, 0x822E, 0x8271, 0x8277, 0x8278, 0x827E, 0x828D, 0x8292, 0x82AB, 0x829F, 0x82BB, 0x82AC, 0x82E1, 0x82E3, 0x82DF, 0x82D2, 0x82F4, 0x82F3, 0x82FA, 0x8393, 0x8303, 0x82FB, 0x82F9, 0x82DE, 0x8306, 0x82DC, 0x8309, 0x82D9, }; const unsigned short euc_to_utf8_E8[] = { 0x8335, 0x8334, 0x8316, 0x8332, 0x8331, 0x8340, 0x8339, 0x8350, 0x8345, 0x832F, 0x832B, 0x8317, 0x8318, 0x8385, 0x839A, 0x83AA, 0x839F, 0x83A2, 0x8396, 0x8323, 0x838E, 0x8387, 0x838A, 0x837C, 0x83B5, 0x8373, 0x8375, 0x83A0, 0x8389, 0x83A8, 0x83F4, 0x8413, 0x83EB, 0x83CE, 0x83FD, 0x8403, 0x83D8, 0x840B, 0x83C1, 0x83F7, 0x8407, 0x83E0, 0x83F2, 0x840D, 0x8422, 0x8420, 0x83BD, 0x8438, 0x8506, 0x83FB, 0x846D, 0x842A, 0x843C, 0x855A, 0x8484, 0x8477, 0x846B, 0x84AD, 0x846E, 0x8482, 0x8469, 0x8446, 0x842C, 0x846F, 0x8479, 0x8435, 0x84CA, 0x8462, 0x84B9, 0x84BF, 0x849F, 0x84D9, 0x84CD, 0x84BB, 0x84DA, 0x84D0, 0x84C1, 0x84C6, 0x84D6, 0x84A1, 0x8521, 0x84FF, 0x84F4, 0x8517, 0x8518, 0x852C, 0x851F, 0x8515, 0x8514, 0x84FC, 0x8540, 0x8563, 0x8558, 0x8548, }; const unsigned short euc_to_utf8_E9[] = { 0x8541, 0x8602, 0x854B, 0x8555, 0x8580, 0x85A4, 0x8588, 0x8591, 0x858A, 0x85A8, 0x856D, 0x8594, 0x859B, 0x85EA, 0x8587, 0x859C, 0x8577, 0x857E, 0x8590, 0x85C9, 0x85BA, 0x85CF, 0x85B9, 0x85D0, 0x85D5, 0x85DD, 0x85E5, 0x85DC, 0x85F9, 0x860A, 0x8613, 0x860B, 0x85FE, 0x85FA, 0x8606, 0x8622, 0x861A, 0x8630, 0x863F, 0x864D, 0x4E55, 0x8654, 0x865F, 0x8667, 0x8671, 0x8693, 0x86A3, 0x86A9, 0x86AA, 0x868B, 0x868C, 0x86B6, 0x86AF, 0x86C4, 0x86C6, 0x86B0, 0x86C9, 0x8823, 0x86AB, 0x86D4, 0x86DE, 0x86E9, 0x86EC, 0x86DF, 0x86DB, 0x86EF, 0x8712, 0x8706, 0x8708, 0x8700, 0x8703, 0x86FB, 0x8711, 0x8709, 0x870D, 0x86F9, 0x870A, 0x8734, 0x873F, 0x8737, 0x873B, 0x8725, 0x8729, 0x871A, 0x8760, 0x875F, 0x8778, 0x874C, 0x874E, 0x8774, 0x8757, 0x8768, 0x876E, 0x8759, }; const unsigned short euc_to_utf8_EA[] = { 0x8753, 0x8763, 0x876A, 0x8805, 0x87A2, 0x879F, 0x8782, 0x87AF, 0x87CB, 0x87BD, 0x87C0, 0x87D0, 0x96D6, 0x87AB, 0x87C4, 0x87B3, 0x87C7, 0x87C6, 0x87BB, 0x87EF, 0x87F2, 0x87E0, 0x880F, 0x880D, 0x87FE, 0x87F6, 0x87F7, 0x880E, 0x87D2, 0x8811, 0x8816, 0x8815, 0x8822, 0x8821, 0x8831, 0x8836, 0x8839, 0x8827, 0x883B, 0x8844, 0x8842, 0x8852, 0x8859, 0x885E, 0x8862, 0x886B, 0x8881, 0x887E, 0x889E, 0x8875, 0x887D, 0x88B5, 0x8872, 0x8882, 0x8897, 0x8892, 0x88AE, 0x8899, 0x88A2, 0x888D, 0x88A4, 0x88B0, 0x88BF, 0x88B1, 0x88C3, 0x88C4, 0x88D4, 0x88D8, 0x88D9, 0x88DD, 0x88F9, 0x8902, 0x88FC, 0x88F4, 0x88E8, 0x88F2, 0x8904, 0x890C, 0x890A, 0x8913, 0x8943, 0x891E, 0x8925, 0x892A, 0x892B, 0x8941, 0x8944, 0x893B, 0x8936, 0x8938, 0x894C, 0x891D, 0x8960, 0x895E, }; const unsigned short euc_to_utf8_EB[] = { 0x8966, 0x8964, 0x896D, 0x896A, 0x896F, 0x8974, 0x8977, 0x897E, 0x8983, 0x8988, 0x898A, 0x8993, 0x8998, 0x89A1, 0x89A9, 0x89A6, 0x89AC, 0x89AF, 0x89B2, 0x89BA, 0x89BD, 0x89BF, 0x89C0, 0x89DA, 0x89DC, 0x89DD, 0x89E7, 0x89F4, 0x89F8, 0x8A03, 0x8A16, 0x8A10, 0x8A0C, 0x8A1B, 0x8A1D, 0x8A25, 0x8A36, 0x8A41, 0x8A5B, 0x8A52, 0x8A46, 0x8A48, 0x8A7C, 0x8A6D, 0x8A6C, 0x8A62, 0x8A85, 0x8A82, 0x8A84, 0x8AA8, 0x8AA1, 0x8A91, 0x8AA5, 0x8AA6, 0x8A9A, 0x8AA3, 0x8AC4, 0x8ACD, 0x8AC2, 0x8ADA, 0x8AEB, 0x8AF3, 0x8AE7, 0x8AE4, 0x8AF1, 0x8B14, 0x8AE0, 0x8AE2, 0x8AF7, 0x8ADE, 0x8ADB, 0x8B0C, 0x8B07, 0x8B1A, 0x8AE1, 0x8B16, 0x8B10, 0x8B17, 0x8B20, 0x8B33, 0x97AB, 0x8B26, 0x8B2B, 0x8B3E, 0x8B28, 0x8B41, 0x8B4C, 0x8B4F, 0x8B4E, 0x8B49, 0x8B56, 0x8B5B, 0x8B5A, 0x8B6B, }; const unsigned short euc_to_utf8_EC[] = { 0x8B5F, 0x8B6C, 0x8B6F, 0x8B74, 0x8B7D, 0x8B80, 0x8B8C, 0x8B8E, 0x8B92, 0x8B93, 0x8B96, 0x8B99, 0x8B9A, 0x8C3A, 0x8C41, 0x8C3F, 0x8C48, 0x8C4C, 0x8C4E, 0x8C50, 0x8C55, 0x8C62, 0x8C6C, 0x8C78, 0x8C7A, 0x8C82, 0x8C89, 0x8C85, 0x8C8A, 0x8C8D, 0x8C8E, 0x8C94, 0x8C7C, 0x8C98, 0x621D, 0x8CAD, 0x8CAA, 0x8CBD, 0x8CB2, 0x8CB3, 0x8CAE, 0x8CB6, 0x8CC8, 0x8CC1, 0x8CE4, 0x8CE3, 0x8CDA, 0x8CFD, 0x8CFA, 0x8CFB, 0x8D04, 0x8D05, 0x8D0A, 0x8D07, 0x8D0F, 0x8D0D, 0x8D10, 0x9F4E, 0x8D13, 0x8CCD, 0x8D14, 0x8D16, 0x8D67, 0x8D6D, 0x8D71, 0x8D73, 0x8D81, 0x8D99, 0x8DC2, 0x8DBE, 0x8DBA, 0x8DCF, 0x8DDA, 0x8DD6, 0x8DCC, 0x8DDB, 0x8DCB, 0x8DEA, 0x8DEB, 0x8DDF, 0x8DE3, 0x8DFC, 0x8E08, 0x8E09, 0x8DFF, 0x8E1D, 0x8E1E, 0x8E10, 0x8E1F, 0x8E42, 0x8E35, 0x8E30, 0x8E34, 0x8E4A, }; const unsigned short euc_to_utf8_ED[] = { 0x8E47, 0x8E49, 0x8E4C, 0x8E50, 0x8E48, 0x8E59, 0x8E64, 0x8E60, 0x8E2A, 0x8E63, 0x8E55, 0x8E76, 0x8E72, 0x8E7C, 0x8E81, 0x8E87, 0x8E85, 0x8E84, 0x8E8B, 0x8E8A, 0x8E93, 0x8E91, 0x8E94, 0x8E99, 0x8EAA, 0x8EA1, 0x8EAC, 0x8EB0, 0x8EC6, 0x8EB1, 0x8EBE, 0x8EC5, 0x8EC8, 0x8ECB, 0x8EDB, 0x8EE3, 0x8EFC, 0x8EFB, 0x8EEB, 0x8EFE, 0x8F0A, 0x8F05, 0x8F15, 0x8F12, 0x8F19, 0x8F13, 0x8F1C, 0x8F1F, 0x8F1B, 0x8F0C, 0x8F26, 0x8F33, 0x8F3B, 0x8F39, 0x8F45, 0x8F42, 0x8F3E, 0x8F4C, 0x8F49, 0x8F46, 0x8F4E, 0x8F57, 0x8F5C, 0x8F62, 0x8F63, 0x8F64, 0x8F9C, 0x8F9F, 0x8FA3, 0x8FAD, 0x8FAF, 0x8FB7, 0x8FDA, 0x8FE5, 0x8FE2, 0x8FEA, 0x8FEF, 0x9087, 0x8FF4, 0x9005, 0x8FF9, 0x8FFA, 0x9011, 0x9015, 0x9021, 0x900D, 0x901E, 0x9016, 0x900B, 0x9027, 0x9036, 0x9035, 0x9039, 0x8FF8, }; const unsigned short euc_to_utf8_EE[] = { 0x904F, 0x9050, 0x9051, 0x9052, 0x900E, 0x9049, 0x903E, 0x9056, 0x9058, 0x905E, 0x9068, 0x906F, 0x9076, 0x96A8, 0x9072, 0x9082, 0x907D, 0x9081, 0x9080, 0x908A, 0x9089, 0x908F, 0x90A8, 0x90AF, 0x90B1, 0x90B5, 0x90E2, 0x90E4, 0x6248, 0x90DB, 0x9102, 0x9112, 0x9119, 0x9132, 0x9130, 0x914A, 0x9156, 0x9158, 0x9163, 0x9165, 0x9169, 0x9173, 0x9172, 0x918B, 0x9189, 0x9182, 0x91A2, 0x91AB, 0x91AF, 0x91AA, 0x91B5, 0x91B4, 0x91BA, 0x91C0, 0x91C1, 0x91C9, 0x91CB, 0x91D0, 0x91D6, 0x91DF, 0x91E1, 0x91DB, 0x91FC, 0x91F5, 0x91F6, 0x921E, 0x91FF, 0x9214, 0x922C, 0x9215, 0x9211, 0x925E, 0x9257, 0x9245, 0x9249, 0x9264, 0x9248, 0x9295, 0x923F, 0x924B, 0x9250, 0x929C, 0x9296, 0x9293, 0x929B, 0x925A, 0x92CF, 0x92B9, 0x92B7, 0x92E9, 0x930F, 0x92FA, 0x9344, 0x932E, }; const unsigned short euc_to_utf8_EF[] = { 0x9319, 0x9322, 0x931A, 0x9323, 0x933A, 0x9335, 0x933B, 0x935C, 0x9360, 0x937C, 0x936E, 0x9356, 0x93B0, 0x93AC, 0x93AD, 0x9394, 0x93B9, 0x93D6, 0x93D7, 0x93E8, 0x93E5, 0x93D8, 0x93C3, 0x93DD, 0x93D0, 0x93C8, 0x93E4, 0x941A, 0x9414, 0x9413, 0x9403, 0x9407, 0x9410, 0x9436, 0x942B, 0x9435, 0x9421, 0x943A, 0x9441, 0x9452, 0x9444, 0x945B, 0x9460, 0x9462, 0x945E, 0x946A, 0x9229, 0x9470, 0x9475, 0x9477, 0x947D, 0x945A, 0x947C, 0x947E, 0x9481, 0x947F, 0x9582, 0x9587, 0x958A, 0x9594, 0x9596, 0x9598, 0x9599, 0x95A0, 0x95A8, 0x95A7, 0x95AD, 0x95BC, 0x95BB, 0x95B9, 0x95BE, 0x95CA, 0x6FF6, 0x95C3, 0x95CD, 0x95CC, 0x95D5, 0x95D4, 0x95D6, 0x95DC, 0x95E1, 0x95E5, 0x95E2, 0x9621, 0x9628, 0x962E, 0x962F, 0x9642, 0x964C, 0x964F, 0x964B, 0x9677, 0x965C, 0x965E, }; const unsigned short euc_to_utf8_F0[] = { 0x965D, 0x965F, 0x9666, 0x9672, 0x966C, 0x968D, 0x9698, 0x9695, 0x9697, 0x96AA, 0x96A7, 0x96B1, 0x96B2, 0x96B0, 0x96B4, 0x96B6, 0x96B8, 0x96B9, 0x96CE, 0x96CB, 0x96C9, 0x96CD, 0x894D, 0x96DC, 0x970D, 0x96D5, 0x96F9, 0x9704, 0x9706, 0x9708, 0x9713, 0x970E, 0x9711, 0x970F, 0x9716, 0x9719, 0x9724, 0x972A, 0x9730, 0x9739, 0x973D, 0x973E, 0x9744, 0x9746, 0x9748, 0x9742, 0x9749, 0x975C, 0x9760, 0x9764, 0x9766, 0x9768, 0x52D2, 0x976B, 0x9771, 0x9779, 0x9785, 0x977C, 0x9781, 0x977A, 0x9786, 0x978B, 0x978F, 0x9790, 0x979C, 0x97A8, 0x97A6, 0x97A3, 0x97B3, 0x97B4, 0x97C3, 0x97C6, 0x97C8, 0x97CB, 0x97DC, 0x97ED, 0x9F4F, 0x97F2, 0x7ADF, 0x97F6, 0x97F5, 0x980F, 0x980C, 0x9838, 0x9824, 0x9821, 0x9837, 0x983D, 0x9846, 0x984F, 0x984B, 0x986B, 0x986F, 0x9870, }; const unsigned short euc_to_utf8_F1[] = { 0x9871, 0x9874, 0x9873, 0x98AA, 0x98AF, 0x98B1, 0x98B6, 0x98C4, 0x98C3, 0x98C6, 0x98E9, 0x98EB, 0x9903, 0x9909, 0x9912, 0x9914, 0x9918, 0x9921, 0x991D, 0x991E, 0x9924, 0x9920, 0x992C, 0x992E, 0x993D, 0x993E, 0x9942, 0x9949, 0x9945, 0x9950, 0x994B, 0x9951, 0x9952, 0x994C, 0x9955, 0x9997, 0x9998, 0x99A5, 0x99AD, 0x99AE, 0x99BC, 0x99DF, 0x99DB, 0x99DD, 0x99D8, 0x99D1, 0x99ED, 0x99EE, 0x99F1, 0x99F2, 0x99FB, 0x99F8, 0x9A01, 0x9A0F, 0x9A05, 0x99E2, 0x9A19, 0x9A2B, 0x9A37, 0x9A45, 0x9A42, 0x9A40, 0x9A43, 0x9A3E, 0x9A55, 0x9A4D, 0x9A5B, 0x9A57, 0x9A5F, 0x9A62, 0x9A65, 0x9A64, 0x9A69, 0x9A6B, 0x9A6A, 0x9AAD, 0x9AB0, 0x9ABC, 0x9AC0, 0x9ACF, 0x9AD1, 0x9AD3, 0x9AD4, 0x9ADE, 0x9ADF, 0x9AE2, 0x9AE3, 0x9AE6, 0x9AEF, 0x9AEB, 0x9AEE, 0x9AF4, 0x9AF1, 0x9AF7, }; const unsigned short euc_to_utf8_F2[] = { 0x9AFB, 0x9B06, 0x9B18, 0x9B1A, 0x9B1F, 0x9B22, 0x9B23, 0x9B25, 0x9B27, 0x9B28, 0x9B29, 0x9B2A, 0x9B2E, 0x9B2F, 0x9B32, 0x9B44, 0x9B43, 0x9B4F, 0x9B4D, 0x9B4E, 0x9B51, 0x9B58, 0x9B74, 0x9B93, 0x9B83, 0x9B91, 0x9B96, 0x9B97, 0x9B9F, 0x9BA0, 0x9BA8, 0x9BB4, 0x9BC0, 0x9BCA, 0x9BB9, 0x9BC6, 0x9BCF, 0x9BD1, 0x9BD2, 0x9BE3, 0x9BE2, 0x9BE4, 0x9BD4, 0x9BE1, 0x9C3A, 0x9BF2, 0x9BF1, 0x9BF0, 0x9C15, 0x9C14, 0x9C09, 0x9C13, 0x9C0C, 0x9C06, 0x9C08, 0x9C12, 0x9C0A, 0x9C04, 0x9C2E, 0x9C1B, 0x9C25, 0x9C24, 0x9C21, 0x9C30, 0x9C47, 0x9C32, 0x9C46, 0x9C3E, 0x9C5A, 0x9C60, 0x9C67, 0x9C76, 0x9C78, 0x9CE7, 0x9CEC, 0x9CF0, 0x9D09, 0x9D08, 0x9CEB, 0x9D03, 0x9D06, 0x9D2A, 0x9D26, 0x9DAF, 0x9D23, 0x9D1F, 0x9D44, 0x9D15, 0x9D12, 0x9D41, 0x9D3F, 0x9D3E, 0x9D46, 0x9D48, }; const unsigned short euc_to_utf8_F3[] = { 0x9D5D, 0x9D5E, 0x9D64, 0x9D51, 0x9D50, 0x9D59, 0x9D72, 0x9D89, 0x9D87, 0x9DAB, 0x9D6F, 0x9D7A, 0x9D9A, 0x9DA4, 0x9DA9, 0x9DB2, 0x9DC4, 0x9DC1, 0x9DBB, 0x9DB8, 0x9DBA, 0x9DC6, 0x9DCF, 0x9DC2, 0x9DD9, 0x9DD3, 0x9DF8, 0x9DE6, 0x9DED, 0x9DEF, 0x9DFD, 0x9E1A, 0x9E1B, 0x9E1E, 0x9E75, 0x9E79, 0x9E7D, 0x9E81, 0x9E88, 0x9E8B, 0x9E8C, 0x9E92, 0x9E95, 0x9E91, 0x9E9D, 0x9EA5, 0x9EA9, 0x9EB8, 0x9EAA, 0x9EAD, 0x9761, 0x9ECC, 0x9ECE, 0x9ECF, 0x9ED0, 0x9ED4, 0x9EDC, 0x9EDE, 0x9EDD, 0x9EE0, 0x9EE5, 0x9EE8, 0x9EEF, 0x9EF4, 0x9EF6, 0x9EF7, 0x9EF9, 0x9EFB, 0x9EFC, 0x9EFD, 0x9F07, 0x9F08, 0x76B7, 0x9F15, 0x9F21, 0x9F2C, 0x9F3E, 0x9F4A, 0x9F52, 0x9F54, 0x9F63, 0x9F5F, 0x9F60, 0x9F61, 0x9F66, 0x9F67, 0x9F6C, 0x9F6A, 0x9F77, 0x9F72, 0x9F76, 0x9F95, 0x9F9C, 0x9FA0, }; const unsigned short euc_to_utf8_F4[] = { 0x582F, 0x69C7, 0x9059, 0x7464, 0x51DC, 0x7199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short euc_to_utf8_F5[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFE33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFE31, 0, 0, 0, 0, 0, 0, 0, 0xFE30, 0, 0, 0, 0, 0xFE35, 0xFE36, 0xFE39, 0xFE3A, 0, 0, 0xFE37, 0xFE38, 0xFE3F, 0xFE40, 0xFE3D, 0xFE3E, 0xFE41, 0xFE42, 0xFE43, 0xFE44, 0xFE3B, 0xFE3C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short euc_to_utf8_F9[] = { 0x7E8A, 0x891C, 0x9348, 0x9288, 0x84DC, 0x4FC9, 0x70BB, 0x6631, 0x68C8, 0x92F9, 0x66FB, 0x5F45, 0x4E28, 0x4EE1, 0x4EFC, 0x4F00, 0x4F03, 0x4F39, 0x4F56, 0x4F92, 0x4F8A, 0x4F9A, 0x4F94, 0x4FCD, 0x5040, 0x5022, 0x4FFF, 0x501E, 0x5046, 0x5070, 0x5042, 0x5094, 0x50F4, 0x50D8, 0x514A, 0x5164, 0x519D, 0x51BE, 0x51EC, 0x5215, 0x529C, 0x52A6, 0x52C0, 0x52DB, 0x5300, 0x5307, 0x5324, 0x5372, 0x5393, 0x53B2, 0x53DD, 0xFA0E, 0x549C, 0x548A, 0x54A9, 0x54FF, 0x5586, 0x5759, 0x5765, 0x57AC, 0x57C8, 0x57C7, 0xFA0F, 0xFA10, 0x589E, 0x58B2, 0x590B, 0x5953, 0x595B, 0x595D, 0x5963, 0x59A4, 0x59BA, 0x5B56, 0x5BC0, 0x752F, 0x5BD8, 0x5BEC, 0x5C1E, 0x5CA6, 0x5CBA, 0x5CF5, 0x5D27, 0x5D53, 0xFA11, 0x5D42, 0x5D6D, 0x5DB8, 0x5DB9, 0x5DD0, 0x5F21, 0x5F34, 0x5F67, 0x5FB7, }; const unsigned short euc_to_utf8_FA[] = { 0x5FDE, 0x605D, 0x6085, 0x608A, 0x60DE, 0x60D5, 0x6120, 0x60F2, 0x6111, 0x6137, 0x6130, 0x6198, 0x6213, 0x62A6, 0x63F5, 0x6460, 0x649D, 0x64CE, 0x654E, 0x6600, 0x6615, 0x663B, 0x6609, 0x662E, 0x661E, 0x6624, 0x6665, 0x6657, 0x6659, 0xFA12, 0x6673, 0x6699, 0x66A0, 0x66B2, 0x66BF, 0x66FA, 0x670E, 0xF929, 0x6766, 0x67BB, 0x6852, 0x67C0, 0x6801, 0x6844, 0x68CF, 0xFA13, 0x6968, 0xFA14, 0x6998, 0x69E2, 0x6A30, 0x6A6B, 0x6A46, 0x6A73, 0x6A7E, 0x6AE2, 0x6AE4, 0x6BD6, 0x6C3F, 0x6C5C, 0x6C86, 0x6C6F, 0x6CDA, 0x6D04, 0x6D87, 0x6D6F, 0x6D96, 0x6DAC, 0x6DCF, 0x6DF8, 0x6DF2, 0x6DFC, 0x6E39, 0x6E5C, 0x6E27, 0x6E3C, 0x6EBF, 0x6F88, 0x6FB5, 0x6FF5, 0x7005, 0x7007, 0x7028, 0x7085, 0x70AB, 0x710F, 0x7104, 0x715C, 0x7146, 0x7147, 0xFA15, 0x71C1, 0x71FE, 0x72B1, }; const unsigned short euc_to_utf8_FB[] = { 0x72BE, 0x7324, 0xFA16, 0x7377, 0x73BD, 0x73C9, 0x73D6, 0x73E3, 0x73D2, 0x7407, 0x73F5, 0x7426, 0x742A, 0x7429, 0x742E, 0x7462, 0x7489, 0x749F, 0x7501, 0x756F, 0x7682, 0x769C, 0x769E, 0x769B, 0x76A6, 0xFA17, 0x7746, 0x52AF, 0x7821, 0x784E, 0x7864, 0x787A, 0x7930, 0xFA18, 0xFA19, 0xFA1A, 0x7994, 0xFA1B, 0x799B, 0x7AD1, 0x7AE7, 0xFA1C, 0x7AEB, 0x7B9E, 0xFA1D, 0x7D48, 0x7D5C, 0x7DB7, 0x7DA0, 0x7DD6, 0x7E52, 0x7F47, 0x7FA1, 0xFA1E, 0x8301, 0x8362, 0x837F, 0x83C7, 0x83F6, 0x8448, 0x84B4, 0x8553, 0x8559, 0x856B, 0xFA1F, 0x85B0, 0xFA20, 0xFA21, 0x8807, 0x88F5, 0x8A12, 0x8A37, 0x8A79, 0x8AA7, 0x8ABE, 0x8ADF, 0xFA22, 0x8AF6, 0x8B53, 0x8B7F, 0x8CF0, 0x8CF4, 0x8D12, 0x8D76, 0xFA23, 0x8ECF, 0xFA24, 0xFA25, 0x9067, 0x90DE, 0xFA26, 0x9115, 0x9127, 0x91DA, }; const unsigned short euc_to_utf8_FC[] = { 0x91D7, 0x91DE, 0x91ED, 0x91EE, 0x91E4, 0x91E5, 0x9206, 0x9210, 0x920A, 0x923A, 0x9240, 0x923C, 0x924E, 0x9259, 0x9251, 0x9239, 0x9267, 0x92A7, 0x9277, 0x9278, 0x92E7, 0x92D7, 0x92D9, 0x92D0, 0xFA27, 0x92D5, 0x92E0, 0x92D3, 0x9325, 0x9321, 0x92FB, 0xFA28, 0x931E, 0x92FF, 0x931D, 0x9302, 0x9370, 0x9357, 0x93A4, 0x93C6, 0x93DE, 0x93F8, 0x9431, 0x9445, 0x9448, 0x9592, 0xF9DC, 0xFA29, 0x969D, 0x96AF, 0x9733, 0x973B, 0x9743, 0x974D, 0x974F, 0x9751, 0x9755, 0x9857, 0x9865, 0xFA2A, 0xFA2B, 0x9927, 0xFA2C, 0x999E, 0x9A4E, 0x9AD9, 0x9ADC, 0x9B75, 0x9B72, 0x9B8F, 0x9BB1, 0x9BBB, 0x9C00, 0x9D70, 0x9D6B, 0xFA2D, 0x9E19, 0x9ED1, 0, 0, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0xFFE2, 0x00A6, 0xFF07, 0xFF02, }; /* Microsoft UCS Mapping Compatible */ const unsigned short euc_to_utf8_FC_ms[] = { 0x91D7, 0x91DE, 0x91ED, 0x91EE, 0x91E4, 0x91E5, 0x9206, 0x9210, 0x920A, 0x923A, 0x9240, 0x923C, 0x924E, 0x9259, 0x9251, 0x9239, 0x9267, 0x92A7, 0x9277, 0x9278, 0x92E7, 0x92D7, 0x92D9, 0x92D0, 0xFA27, 0x92D5, 0x92E0, 0x92D3, 0x9325, 0x9321, 0x92FB, 0xFA28, 0x931E, 0x92FF, 0x931D, 0x9302, 0x9370, 0x9357, 0x93A4, 0x93C6, 0x93DE, 0x93F8, 0x9431, 0x9445, 0x9448, 0x9592, 0xF9DC, 0xFA29, 0x969D, 0x96AF, 0x9733, 0x973B, 0x9743, 0x974D, 0x974F, 0x9751, 0x9755, 0x9857, 0x9865, 0xFA2A, 0xFA2B, 0x9927, 0xFA2C, 0x999E, 0x9A4E, 0x9AD9, 0x9ADC, 0x9B75, 0x9B72, 0x9B8F, 0x9BB1, 0x9BBB, 0x9C00, 0x9D70, 0x9D6B, 0xFA2D, 0x9E19, 0x9ED1, 0, 0, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0xFFE2, 0xFFE4, 0xFF07, 0xFF02, }; #ifdef X0212_ENABLE const unsigned short euc_to_utf8_8FA2[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02D8, 0x02C7, 0x00B8, 0x02D9, 0x02DD, 0x00AF, 0x02DB, 0x02DA, 0xFF5E, 0x0384, 0x0385, 0, 0, 0, 0, 0, 0, 0, 0, 0x00A1, 0xFFE4, 0x00BF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00BA, 0x00AA, 0x00A9, 0x00AE, 0x2122, 0x00A4, 0x2116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short euc_to_utf8_8FA6[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0386, 0x0388, 0x0389, 0x038A, 0x03AA, 0, 0x038C, 0, 0x038E, 0x03AB, 0, 0x038F, 0, 0, 0, 0, 0x03AC, 0x03AD, 0x03AE, 0x03AF, 0x03CA, 0x0390, 0x03CC, 0x03C2, 0x03CD, 0x03CB, 0x03B0, 0x03CE, 0, 0, }; const unsigned short euc_to_utf8_8FA7[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x040E, 0x040F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x045E, 0x045F, }; const unsigned short euc_to_utf8_8FA9[] = { 0x00C6, 0x0110, 0, 0x0126, 0, 0x0132, 0, 0x0141, 0x013F, 0, 0x014A, 0x00D8, 0x0152, 0, 0x0166, 0x00DE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00E6, 0x0111, 0x00F0, 0x0127, 0x0131, 0x0133, 0x0138, 0x0142, 0x0140, 0x0149, 0x014B, 0x00F8, 0x0153, 0x00DF, 0x0167, 0x00FE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short euc_to_utf8_8FAA[] = { 0x00C1, 0x00C0, 0x00C4, 0x00C2, 0x0102, 0x01CD, 0x0100, 0x0104, 0x00C5, 0x00C3, 0x0106, 0x0108, 0x010C, 0x00C7, 0x010A, 0x010E, 0x00C9, 0x00C8, 0x00CB, 0x00CA, 0x011A, 0x0116, 0x0112, 0x0118, 0, 0x011C, 0x011E, 0x0122, 0x0120, 0x0124, 0x00CD, 0x00CC, 0x00CF, 0x00CE, 0x01CF, 0x0130, 0x012A, 0x012E, 0x0128, 0x0134, 0x0136, 0x0139, 0x013D, 0x013B, 0x0143, 0x0147, 0x0145, 0x00D1, 0x00D3, 0x00D2, 0x00D6, 0x00D4, 0x01D1, 0x0150, 0x014C, 0x00D5, 0x0154, 0x0158, 0x0156, 0x015A, 0x015C, 0x0160, 0x015E, 0x0164, 0x0162, 0x00DA, 0x00D9, 0x00DC, 0x00DB, 0x016C, 0x01D3, 0x0170, 0x016A, 0x0172, 0x016E, 0x0168, 0x01D7, 0x01DB, 0x01D9, 0x01D5, 0x0174, 0x00DD, 0x0178, 0x0176, 0x0179, 0x017D, 0x017B, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short euc_to_utf8_8FAB[] = { 0x00E1, 0x00E0, 0x00E4, 0x00E2, 0x0103, 0x01CE, 0x0101, 0x0105, 0x00E5, 0x00E3, 0x0107, 0x0109, 0x010D, 0x00E7, 0x010B, 0x010F, 0x00E9, 0x00E8, 0x00EB, 0x00EA, 0x011B, 0x0117, 0x0113, 0x0119, 0x01F5, 0x011D, 0x011F, 0, 0x0121, 0x0125, 0x00ED, 0x00EC, 0x00EF, 0x00EE, 0x01D0, 0, 0x012B, 0x012F, 0x0129, 0x0135, 0x0137, 0x013A, 0x013E, 0x013C, 0x0144, 0x0148, 0x0146, 0x00F1, 0x00F3, 0x00F2, 0x00F6, 0x00F4, 0x01D2, 0x0151, 0x014D, 0x00F5, 0x0155, 0x0159, 0x0157, 0x015B, 0x015D, 0x0161, 0x015F, 0x0165, 0x0163, 0x00FA, 0x00F9, 0x00FC, 0x00FB, 0x016D, 0x01D4, 0x0171, 0x016B, 0x0173, 0x016F, 0x0169, 0x01D8, 0x01DC, 0x01DA, 0x01D6, 0x0175, 0x00FD, 0x00FF, 0x0177, 0x017A, 0x017E, 0x017C, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short euc_to_utf8_8FB0[] = { 0x4E02, 0x4E04, 0x4E05, 0x4E0C, 0x4E12, 0x4E1F, 0x4E23, 0x4E24, 0x4E28, 0x4E2B, 0x4E2E, 0x4E2F, 0x4E30, 0x4E35, 0x4E40, 0x4E41, 0x4E44, 0x4E47, 0x4E51, 0x4E5A, 0x4E5C, 0x4E63, 0x4E68, 0x4E69, 0x4E74, 0x4E75, 0x4E79, 0x4E7F, 0x4E8D, 0x4E96, 0x4E97, 0x4E9D, 0x4EAF, 0x4EB9, 0x4EC3, 0x4ED0, 0x4EDA, 0x4EDB, 0x4EE0, 0x4EE1, 0x4EE2, 0x4EE8, 0x4EEF, 0x4EF1, 0x4EF3, 0x4EF5, 0x4EFD, 0x4EFE, 0x4EFF, 0x4F00, 0x4F02, 0x4F03, 0x4F08, 0x4F0B, 0x4F0C, 0x4F12, 0x4F15, 0x4F16, 0x4F17, 0x4F19, 0x4F2E, 0x4F31, 0x4F60, 0x4F33, 0x4F35, 0x4F37, 0x4F39, 0x4F3B, 0x4F3E, 0x4F40, 0x4F42, 0x4F48, 0x4F49, 0x4F4B, 0x4F4C, 0x4F52, 0x4F54, 0x4F56, 0x4F58, 0x4F5F, 0x4F63, 0x4F6A, 0x4F6C, 0x4F6E, 0x4F71, 0x4F77, 0x4F78, 0x4F79, 0x4F7A, 0x4F7D, 0x4F7E, 0x4F81, 0x4F82, 0x4F84, }; const unsigned short euc_to_utf8_8FB1[] = { 0x4F85, 0x4F89, 0x4F8A, 0x4F8C, 0x4F8E, 0x4F90, 0x4F92, 0x4F93, 0x4F94, 0x4F97, 0x4F99, 0x4F9A, 0x4F9E, 0x4F9F, 0x4FB2, 0x4FB7, 0x4FB9, 0x4FBB, 0x4FBC, 0x4FBD, 0x4FBE, 0x4FC0, 0x4FC1, 0x4FC5, 0x4FC6, 0x4FC8, 0x4FC9, 0x4FCB, 0x4FCC, 0x4FCD, 0x4FCF, 0x4FD2, 0x4FDC, 0x4FE0, 0x4FE2, 0x4FF0, 0x4FF2, 0x4FFC, 0x4FFD, 0x4FFF, 0x5000, 0x5001, 0x5004, 0x5007, 0x500A, 0x500C, 0x500E, 0x5010, 0x5013, 0x5017, 0x5018, 0x501B, 0x501C, 0x501D, 0x501E, 0x5022, 0x5027, 0x502E, 0x5030, 0x5032, 0x5033, 0x5035, 0x5040, 0x5041, 0x5042, 0x5045, 0x5046, 0x504A, 0x504C, 0x504E, 0x5051, 0x5052, 0x5053, 0x5057, 0x5059, 0x505F, 0x5060, 0x5062, 0x5063, 0x5066, 0x5067, 0x506A, 0x506D, 0x5070, 0x5071, 0x503B, 0x5081, 0x5083, 0x5084, 0x5086, 0x508A, 0x508E, 0x508F, 0x5090, }; const unsigned short euc_to_utf8_8FB2[] = { 0x5092, 0x5093, 0x5094, 0x5096, 0x509B, 0x509C, 0x509E, 0x509F, 0x50A0, 0x50A1, 0x50A2, 0x50AA, 0x50AF, 0x50B0, 0x50B9, 0x50BA, 0x50BD, 0x50C0, 0x50C3, 0x50C4, 0x50C7, 0x50CC, 0x50CE, 0x50D0, 0x50D3, 0x50D4, 0x50D8, 0x50DC, 0x50DD, 0x50DF, 0x50E2, 0x50E4, 0x50E6, 0x50E8, 0x50E9, 0x50EF, 0x50F1, 0x50F6, 0x50FA, 0x50FE, 0x5103, 0x5106, 0x5107, 0x5108, 0x510B, 0x510C, 0x510D, 0x510E, 0x50F2, 0x5110, 0x5117, 0x5119, 0x511B, 0x511C, 0x511D, 0x511E, 0x5123, 0x5127, 0x5128, 0x512C, 0x512D, 0x512F, 0x5131, 0x5133, 0x5134, 0x5135, 0x5138, 0x5139, 0x5142, 0x514A, 0x514F, 0x5153, 0x5155, 0x5157, 0x5158, 0x515F, 0x5164, 0x5166, 0x517E, 0x5183, 0x5184, 0x518B, 0x518E, 0x5198, 0x519D, 0x51A1, 0x51A3, 0x51AD, 0x51B8, 0x51BA, 0x51BC, 0x51BE, 0x51BF, 0x51C2, }; const unsigned short euc_to_utf8_8FB3[] = { 0x51C8, 0x51CF, 0x51D1, 0x51D2, 0x51D3, 0x51D5, 0x51D8, 0x51DE, 0x51E2, 0x51E5, 0x51EE, 0x51F2, 0x51F3, 0x51F4, 0x51F7, 0x5201, 0x5202, 0x5205, 0x5212, 0x5213, 0x5215, 0x5216, 0x5218, 0x5222, 0x5228, 0x5231, 0x5232, 0x5235, 0x523C, 0x5245, 0x5249, 0x5255, 0x5257, 0x5258, 0x525A, 0x525C, 0x525F, 0x5260, 0x5261, 0x5266, 0x526E, 0x5277, 0x5278, 0x5279, 0x5280, 0x5282, 0x5285, 0x528A, 0x528C, 0x5293, 0x5295, 0x5296, 0x5297, 0x5298, 0x529A, 0x529C, 0x52A4, 0x52A5, 0x52A6, 0x52A7, 0x52AF, 0x52B0, 0x52B6, 0x52B7, 0x52B8, 0x52BA, 0x52BB, 0x52BD, 0x52C0, 0x52C4, 0x52C6, 0x52C8, 0x52CC, 0x52CF, 0x52D1, 0x52D4, 0x52D6, 0x52DB, 0x52DC, 0x52E1, 0x52E5, 0x52E8, 0x52E9, 0x52EA, 0x52EC, 0x52F0, 0x52F1, 0x52F4, 0x52F6, 0x52F7, 0x5300, 0x5303, 0x530A, 0x530B, }; const unsigned short euc_to_utf8_8FB4[] = { 0x530C, 0x5311, 0x5313, 0x5318, 0x531B, 0x531C, 0x531E, 0x531F, 0x5325, 0x5327, 0x5328, 0x5329, 0x532B, 0x532C, 0x532D, 0x5330, 0x5332, 0x5335, 0x533C, 0x533D, 0x533E, 0x5342, 0x534C, 0x534B, 0x5359, 0x535B, 0x5361, 0x5363, 0x5365, 0x536C, 0x536D, 0x5372, 0x5379, 0x537E, 0x5383, 0x5387, 0x5388, 0x538E, 0x5393, 0x5394, 0x5399, 0x539D, 0x53A1, 0x53A4, 0x53AA, 0x53AB, 0x53AF, 0x53B2, 0x53B4, 0x53B5, 0x53B7, 0x53B8, 0x53BA, 0x53BD, 0x53C0, 0x53C5, 0x53CF, 0x53D2, 0x53D3, 0x53D5, 0x53DA, 0x53DD, 0x53DE, 0x53E0, 0x53E6, 0x53E7, 0x53F5, 0x5402, 0x5413, 0x541A, 0x5421, 0x5427, 0x5428, 0x542A, 0x542F, 0x5431, 0x5434, 0x5435, 0x5443, 0x5444, 0x5447, 0x544D, 0x544F, 0x545E, 0x5462, 0x5464, 0x5466, 0x5467, 0x5469, 0x546B, 0x546D, 0x546E, 0x5474, 0x547F, }; const unsigned short euc_to_utf8_8FB5[] = { 0x5481, 0x5483, 0x5485, 0x5488, 0x5489, 0x548D, 0x5491, 0x5495, 0x5496, 0x549C, 0x549F, 0x54A1, 0x54A6, 0x54A7, 0x54A9, 0x54AA, 0x54AD, 0x54AE, 0x54B1, 0x54B7, 0x54B9, 0x54BA, 0x54BB, 0x54BF, 0x54C6, 0x54CA, 0x54CD, 0x54CE, 0x54E0, 0x54EA, 0x54EC, 0x54EF, 0x54F6, 0x54FC, 0x54FE, 0x54FF, 0x5500, 0x5501, 0x5505, 0x5508, 0x5509, 0x550C, 0x550D, 0x550E, 0x5515, 0x552A, 0x552B, 0x5532, 0x5535, 0x5536, 0x553B, 0x553C, 0x553D, 0x5541, 0x5547, 0x5549, 0x554A, 0x554D, 0x5550, 0x5551, 0x5558, 0x555A, 0x555B, 0x555E, 0x5560, 0x5561, 0x5564, 0x5566, 0x557F, 0x5581, 0x5582, 0x5586, 0x5588, 0x558E, 0x558F, 0x5591, 0x5592, 0x5593, 0x5594, 0x5597, 0x55A3, 0x55A4, 0x55AD, 0x55B2, 0x55BF, 0x55C1, 0x55C3, 0x55C6, 0x55C9, 0x55CB, 0x55CC, 0x55CE, 0x55D1, 0x55D2, }; const unsigned short euc_to_utf8_8FB6[] = { 0x55D3, 0x55D7, 0x55D8, 0x55DB, 0x55DE, 0x55E2, 0x55E9, 0x55F6, 0x55FF, 0x5605, 0x5608, 0x560A, 0x560D, 0x560E, 0x560F, 0x5610, 0x5611, 0x5612, 0x5619, 0x562C, 0x5630, 0x5633, 0x5635, 0x5637, 0x5639, 0x563B, 0x563C, 0x563D, 0x563F, 0x5640, 0x5641, 0x5643, 0x5644, 0x5646, 0x5649, 0x564B, 0x564D, 0x564F, 0x5654, 0x565E, 0x5660, 0x5661, 0x5662, 0x5663, 0x5666, 0x5669, 0x566D, 0x566F, 0x5671, 0x5672, 0x5675, 0x5684, 0x5685, 0x5688, 0x568B, 0x568C, 0x5695, 0x5699, 0x569A, 0x569D, 0x569E, 0x569F, 0x56A6, 0x56A7, 0x56A8, 0x56A9, 0x56AB, 0x56AC, 0x56AD, 0x56B1, 0x56B3, 0x56B7, 0x56BE, 0x56C5, 0x56C9, 0x56CA, 0x56CB, 0x56CF, 0x56D0, 0x56CC, 0x56CD, 0x56D9, 0x56DC, 0x56DD, 0x56DF, 0x56E1, 0x56E4, 0x56E5, 0x56E6, 0x56E7, 0x56E8, 0x56F1, 0x56EB, 0x56ED, }; const unsigned short euc_to_utf8_8FB7[] = { 0x56F6, 0x56F7, 0x5701, 0x5702, 0x5707, 0x570A, 0x570C, 0x5711, 0x5715, 0x571A, 0x571B, 0x571D, 0x5720, 0x5722, 0x5723, 0x5724, 0x5725, 0x5729, 0x572A, 0x572C, 0x572E, 0x572F, 0x5733, 0x5734, 0x573D, 0x573E, 0x573F, 0x5745, 0x5746, 0x574C, 0x574D, 0x5752, 0x5762, 0x5765, 0x5767, 0x5768, 0x576B, 0x576D, 0x576E, 0x576F, 0x5770, 0x5771, 0x5773, 0x5774, 0x5775, 0x5777, 0x5779, 0x577A, 0x577B, 0x577C, 0x577E, 0x5781, 0x5783, 0x578C, 0x5794, 0x5797, 0x5799, 0x579A, 0x579C, 0x579D, 0x579E, 0x579F, 0x57A1, 0x5795, 0x57A7, 0x57A8, 0x57A9, 0x57AC, 0x57B8, 0x57BD, 0x57C7, 0x57C8, 0x57CC, 0x57CF, 0x57D5, 0x57DD, 0x57DE, 0x57E4, 0x57E6, 0x57E7, 0x57E9, 0x57ED, 0x57F0, 0x57F5, 0x57F6, 0x57F8, 0x57FD, 0x57FE, 0x57FF, 0x5803, 0x5804, 0x5808, 0x5809, 0x57E1, }; const unsigned short euc_to_utf8_8FB8[] = { 0x580C, 0x580D, 0x581B, 0x581E, 0x581F, 0x5820, 0x5826, 0x5827, 0x582D, 0x5832, 0x5839, 0x583F, 0x5849, 0x584C, 0x584D, 0x584F, 0x5850, 0x5855, 0x585F, 0x5861, 0x5864, 0x5867, 0x5868, 0x5878, 0x587C, 0x587F, 0x5880, 0x5881, 0x5887, 0x5888, 0x5889, 0x588A, 0x588C, 0x588D, 0x588F, 0x5890, 0x5894, 0x5896, 0x589D, 0x58A0, 0x58A1, 0x58A2, 0x58A6, 0x58A9, 0x58B1, 0x58B2, 0x58C4, 0x58BC, 0x58C2, 0x58C8, 0x58CD, 0x58CE, 0x58D0, 0x58D2, 0x58D4, 0x58D6, 0x58DA, 0x58DD, 0x58E1, 0x58E2, 0x58E9, 0x58F3, 0x5905, 0x5906, 0x590B, 0x590C, 0x5912, 0x5913, 0x5914, 0x8641, 0x591D, 0x5921, 0x5923, 0x5924, 0x5928, 0x592F, 0x5930, 0x5933, 0x5935, 0x5936, 0x593F, 0x5943, 0x5946, 0x5952, 0x5953, 0x5959, 0x595B, 0x595D, 0x595E, 0x595F, 0x5961, 0x5963, 0x596B, 0x596D, }; const unsigned short euc_to_utf8_8FB9[] = { 0x596F, 0x5972, 0x5975, 0x5976, 0x5979, 0x597B, 0x597C, 0x598B, 0x598C, 0x598E, 0x5992, 0x5995, 0x5997, 0x599F, 0x59A4, 0x59A7, 0x59AD, 0x59AE, 0x59AF, 0x59B0, 0x59B3, 0x59B7, 0x59BA, 0x59BC, 0x59C1, 0x59C3, 0x59C4, 0x59C8, 0x59CA, 0x59CD, 0x59D2, 0x59DD, 0x59DE, 0x59DF, 0x59E3, 0x59E4, 0x59E7, 0x59EE, 0x59EF, 0x59F1, 0x59F2, 0x59F4, 0x59F7, 0x5A00, 0x5A04, 0x5A0C, 0x5A0D, 0x5A0E, 0x5A12, 0x5A13, 0x5A1E, 0x5A23, 0x5A24, 0x5A27, 0x5A28, 0x5A2A, 0x5A2D, 0x5A30, 0x5A44, 0x5A45, 0x5A47, 0x5A48, 0x5A4C, 0x5A50, 0x5A55, 0x5A5E, 0x5A63, 0x5A65, 0x5A67, 0x5A6D, 0x5A77, 0x5A7A, 0x5A7B, 0x5A7E, 0x5A8B, 0x5A90, 0x5A93, 0x5A96, 0x5A99, 0x5A9C, 0x5A9E, 0x5A9F, 0x5AA0, 0x5AA2, 0x5AA7, 0x5AAC, 0x5AB1, 0x5AB2, 0x5AB3, 0x5AB5, 0x5AB8, 0x5ABA, 0x5ABB, 0x5ABF, }; const unsigned short euc_to_utf8_8FBA[] = { 0x5AC4, 0x5AC6, 0x5AC8, 0x5ACF, 0x5ADA, 0x5ADC, 0x5AE0, 0x5AE5, 0x5AEA, 0x5AEE, 0x5AF5, 0x5AF6, 0x5AFD, 0x5B00, 0x5B01, 0x5B08, 0x5B17, 0x5B34, 0x5B19, 0x5B1B, 0x5B1D, 0x5B21, 0x5B25, 0x5B2D, 0x5B38, 0x5B41, 0x5B4B, 0x5B4C, 0x5B52, 0x5B56, 0x5B5E, 0x5B68, 0x5B6E, 0x5B6F, 0x5B7C, 0x5B7D, 0x5B7E, 0x5B7F, 0x5B81, 0x5B84, 0x5B86, 0x5B8A, 0x5B8E, 0x5B90, 0x5B91, 0x5B93, 0x5B94, 0x5B96, 0x5BA8, 0x5BA9, 0x5BAC, 0x5BAD, 0x5BAF, 0x5BB1, 0x5BB2, 0x5BB7, 0x5BBA, 0x5BBC, 0x5BC0, 0x5BC1, 0x5BCD, 0x5BCF, 0x5BD6, 0x5BD7, 0x5BD8, 0x5BD9, 0x5BDA, 0x5BE0, 0x5BEF, 0x5BF1, 0x5BF4, 0x5BFD, 0x5C0C, 0x5C17, 0x5C1E, 0x5C1F, 0x5C23, 0x5C26, 0x5C29, 0x5C2B, 0x5C2C, 0x5C2E, 0x5C30, 0x5C32, 0x5C35, 0x5C36, 0x5C59, 0x5C5A, 0x5C5C, 0x5C62, 0x5C63, 0x5C67, 0x5C68, 0x5C69, }; const unsigned short euc_to_utf8_8FBB[] = { 0x5C6D, 0x5C70, 0x5C74, 0x5C75, 0x5C7A, 0x5C7B, 0x5C7C, 0x5C7D, 0x5C87, 0x5C88, 0x5C8A, 0x5C8F, 0x5C92, 0x5C9D, 0x5C9F, 0x5CA0, 0x5CA2, 0x5CA3, 0x5CA6, 0x5CAA, 0x5CB2, 0x5CB4, 0x5CB5, 0x5CBA, 0x5CC9, 0x5CCB, 0x5CD2, 0x5CDD, 0x5CD7, 0x5CEE, 0x5CF1, 0x5CF2, 0x5CF4, 0x5D01, 0x5D06, 0x5D0D, 0x5D12, 0x5D2B, 0x5D23, 0x5D24, 0x5D26, 0x5D27, 0x5D31, 0x5D34, 0x5D39, 0x5D3D, 0x5D3F, 0x5D42, 0x5D43, 0x5D46, 0x5D48, 0x5D55, 0x5D51, 0x5D59, 0x5D4A, 0x5D5F, 0x5D60, 0x5D61, 0x5D62, 0x5D64, 0x5D6A, 0x5D6D, 0x5D70, 0x5D79, 0x5D7A, 0x5D7E, 0x5D7F, 0x5D81, 0x5D83, 0x5D88, 0x5D8A, 0x5D92, 0x5D93, 0x5D94, 0x5D95, 0x5D99, 0x5D9B, 0x5D9F, 0x5DA0, 0x5DA7, 0x5DAB, 0x5DB0, 0x5DB4, 0x5DB8, 0x5DB9, 0x5DC3, 0x5DC7, 0x5DCB, 0x5DD0, 0x5DCE, 0x5DD8, 0x5DD9, 0x5DE0, 0x5DE4, }; const unsigned short euc_to_utf8_8FBC[] = { 0x5DE9, 0x5DF8, 0x5DF9, 0x5E00, 0x5E07, 0x5E0D, 0x5E12, 0x5E14, 0x5E15, 0x5E18, 0x5E1F, 0x5E20, 0x5E2E, 0x5E28, 0x5E32, 0x5E35, 0x5E3E, 0x5E4B, 0x5E50, 0x5E49, 0x5E51, 0x5E56, 0x5E58, 0x5E5B, 0x5E5C, 0x5E5E, 0x5E68, 0x5E6A, 0x5E6B, 0x5E6C, 0x5E6D, 0x5E6E, 0x5E70, 0x5E80, 0x5E8B, 0x5E8E, 0x5EA2, 0x5EA4, 0x5EA5, 0x5EA8, 0x5EAA, 0x5EAC, 0x5EB1, 0x5EB3, 0x5EBD, 0x5EBE, 0x5EBF, 0x5EC6, 0x5ECC, 0x5ECB, 0x5ECE, 0x5ED1, 0x5ED2, 0x5ED4, 0x5ED5, 0x5EDC, 0x5EDE, 0x5EE5, 0x5EEB, 0x5F02, 0x5F06, 0x5F07, 0x5F08, 0x5F0E, 0x5F19, 0x5F1C, 0x5F1D, 0x5F21, 0x5F22, 0x5F23, 0x5F24, 0x5F28, 0x5F2B, 0x5F2C, 0x5F2E, 0x5F30, 0x5F34, 0x5F36, 0x5F3B, 0x5F3D, 0x5F3F, 0x5F40, 0x5F44, 0x5F45, 0x5F47, 0x5F4D, 0x5F50, 0x5F54, 0x5F58, 0x5F5B, 0x5F60, 0x5F63, 0x5F64, 0x5F67, }; const unsigned short euc_to_utf8_8FBD[] = { 0x5F6F, 0x5F72, 0x5F74, 0x5F75, 0x5F78, 0x5F7A, 0x5F7D, 0x5F7E, 0x5F89, 0x5F8D, 0x5F8F, 0x5F96, 0x5F9C, 0x5F9D, 0x5FA2, 0x5FA7, 0x5FAB, 0x5FA4, 0x5FAC, 0x5FAF, 0x5FB0, 0x5FB1, 0x5FB8, 0x5FC4, 0x5FC7, 0x5FC8, 0x5FC9, 0x5FCB, 0x5FD0, 0x5FD1, 0x5FD2, 0x5FD3, 0x5FD4, 0x5FDE, 0x5FE1, 0x5FE2, 0x5FE8, 0x5FE9, 0x5FEA, 0x5FEC, 0x5FED, 0x5FEE, 0x5FEF, 0x5FF2, 0x5FF3, 0x5FF6, 0x5FFA, 0x5FFC, 0x6007, 0x600A, 0x600D, 0x6013, 0x6014, 0x6017, 0x6018, 0x601A, 0x601F, 0x6024, 0x602D, 0x6033, 0x6035, 0x6040, 0x6047, 0x6048, 0x6049, 0x604C, 0x6051, 0x6054, 0x6056, 0x6057, 0x605D, 0x6061, 0x6067, 0x6071, 0x607E, 0x607F, 0x6082, 0x6086, 0x6088, 0x608A, 0x608E, 0x6091, 0x6093, 0x6095, 0x6098, 0x609D, 0x609E, 0x60A2, 0x60A4, 0x60A5, 0x60A8, 0x60B0, 0x60B1, 0x60B7, }; const unsigned short euc_to_utf8_8FBE[] = { 0x60BB, 0x60BE, 0x60C2, 0x60C4, 0x60C8, 0x60C9, 0x60CA, 0x60CB, 0x60CE, 0x60CF, 0x60D4, 0x60D5, 0x60D9, 0x60DB, 0x60DD, 0x60DE, 0x60E2, 0x60E5, 0x60F2, 0x60F5, 0x60F8, 0x60FC, 0x60FD, 0x6102, 0x6107, 0x610A, 0x610C, 0x6110, 0x6111, 0x6112, 0x6113, 0x6114, 0x6116, 0x6117, 0x6119, 0x611C, 0x611E, 0x6122, 0x612A, 0x612B, 0x6130, 0x6131, 0x6135, 0x6136, 0x6137, 0x6139, 0x6141, 0x6145, 0x6146, 0x6149, 0x615E, 0x6160, 0x616C, 0x6172, 0x6178, 0x617B, 0x617C, 0x617F, 0x6180, 0x6181, 0x6183, 0x6184, 0x618B, 0x618D, 0x6192, 0x6193, 0x6197, 0x6198, 0x619C, 0x619D, 0x619F, 0x61A0, 0x61A5, 0x61A8, 0x61AA, 0x61AD, 0x61B8, 0x61B9, 0x61BC, 0x61C0, 0x61C1, 0x61C2, 0x61CE, 0x61CF, 0x61D5, 0x61DC, 0x61DD, 0x61DE, 0x61DF, 0x61E1, 0x61E2, 0x61E7, 0x61E9, 0x61E5, }; const unsigned short euc_to_utf8_8FBF[] = { 0x61EC, 0x61ED, 0x61EF, 0x6201, 0x6203, 0x6204, 0x6207, 0x6213, 0x6215, 0x621C, 0x6220, 0x6222, 0x6223, 0x6227, 0x6229, 0x622B, 0x6239, 0x623D, 0x6242, 0x6243, 0x6244, 0x6246, 0x624C, 0x6250, 0x6251, 0x6252, 0x6254, 0x6256, 0x625A, 0x625C, 0x6264, 0x626D, 0x626F, 0x6273, 0x627A, 0x627D, 0x628D, 0x628E, 0x628F, 0x6290, 0x62A6, 0x62A8, 0x62B3, 0x62B6, 0x62B7, 0x62BA, 0x62BE, 0x62BF, 0x62C4, 0x62CE, 0x62D5, 0x62D6, 0x62DA, 0x62EA, 0x62F2, 0x62F4, 0x62FC, 0x62FD, 0x6303, 0x6304, 0x630A, 0x630B, 0x630D, 0x6310, 0x6313, 0x6316, 0x6318, 0x6329, 0x632A, 0x632D, 0x6335, 0x6336, 0x6339, 0x633C, 0x6341, 0x6342, 0x6343, 0x6344, 0x6346, 0x634A, 0x634B, 0x634E, 0x6352, 0x6353, 0x6354, 0x6358, 0x635B, 0x6365, 0x6366, 0x636C, 0x636D, 0x6371, 0x6374, 0x6375, }; const unsigned short euc_to_utf8_8FC0[] = { 0x6378, 0x637C, 0x637D, 0x637F, 0x6382, 0x6384, 0x6387, 0x638A, 0x6390, 0x6394, 0x6395, 0x6399, 0x639A, 0x639E, 0x63A4, 0x63A6, 0x63AD, 0x63AE, 0x63AF, 0x63BD, 0x63C1, 0x63C5, 0x63C8, 0x63CE, 0x63D1, 0x63D3, 0x63D4, 0x63D5, 0x63DC, 0x63E0, 0x63E5, 0x63EA, 0x63EC, 0x63F2, 0x63F3, 0x63F5, 0x63F8, 0x63F9, 0x6409, 0x640A, 0x6410, 0x6412, 0x6414, 0x6418, 0x641E, 0x6420, 0x6422, 0x6424, 0x6425, 0x6429, 0x642A, 0x642F, 0x6430, 0x6435, 0x643D, 0x643F, 0x644B, 0x644F, 0x6451, 0x6452, 0x6453, 0x6454, 0x645A, 0x645B, 0x645C, 0x645D, 0x645F, 0x6460, 0x6461, 0x6463, 0x646D, 0x6473, 0x6474, 0x647B, 0x647D, 0x6485, 0x6487, 0x648F, 0x6490, 0x6491, 0x6498, 0x6499, 0x649B, 0x649D, 0x649F, 0x64A1, 0x64A3, 0x64A6, 0x64A8, 0x64AC, 0x64B3, 0x64BD, 0x64BE, 0x64BF, }; const unsigned short euc_to_utf8_8FC1[] = { 0x64C4, 0x64C9, 0x64CA, 0x64CB, 0x64CC, 0x64CE, 0x64D0, 0x64D1, 0x64D5, 0x64D7, 0x64E4, 0x64E5, 0x64E9, 0x64EA, 0x64ED, 0x64F0, 0x64F5, 0x64F7, 0x64FB, 0x64FF, 0x6501, 0x6504, 0x6508, 0x6509, 0x650A, 0x650F, 0x6513, 0x6514, 0x6516, 0x6519, 0x651B, 0x651E, 0x651F, 0x6522, 0x6526, 0x6529, 0x652E, 0x6531, 0x653A, 0x653C, 0x653D, 0x6543, 0x6547, 0x6549, 0x6550, 0x6552, 0x6554, 0x655F, 0x6560, 0x6567, 0x656B, 0x657A, 0x657D, 0x6581, 0x6585, 0x658A, 0x6592, 0x6595, 0x6598, 0x659D, 0x65A0, 0x65A3, 0x65A6, 0x65AE, 0x65B2, 0x65B3, 0x65B4, 0x65BF, 0x65C2, 0x65C8, 0x65C9, 0x65CE, 0x65D0, 0x65D4, 0x65D6, 0x65D8, 0x65DF, 0x65F0, 0x65F2, 0x65F4, 0x65F5, 0x65F9, 0x65FE, 0x65FF, 0x6600, 0x6604, 0x6608, 0x6609, 0x660D, 0x6611, 0x6612, 0x6615, 0x6616, 0x661D, }; const unsigned short euc_to_utf8_8FC2[] = { 0x661E, 0x6621, 0x6622, 0x6623, 0x6624, 0x6626, 0x6629, 0x662A, 0x662B, 0x662C, 0x662E, 0x6630, 0x6631, 0x6633, 0x6639, 0x6637, 0x6640, 0x6645, 0x6646, 0x664A, 0x664C, 0x6651, 0x664E, 0x6657, 0x6658, 0x6659, 0x665B, 0x665C, 0x6660, 0x6661, 0x66FB, 0x666A, 0x666B, 0x666C, 0x667E, 0x6673, 0x6675, 0x667F, 0x6677, 0x6678, 0x6679, 0x667B, 0x6680, 0x667C, 0x668B, 0x668C, 0x668D, 0x6690, 0x6692, 0x6699, 0x669A, 0x669B, 0x669C, 0x669F, 0x66A0, 0x66A4, 0x66AD, 0x66B1, 0x66B2, 0x66B5, 0x66BB, 0x66BF, 0x66C0, 0x66C2, 0x66C3, 0x66C8, 0x66CC, 0x66CE, 0x66CF, 0x66D4, 0x66DB, 0x66DF, 0x66E8, 0x66EB, 0x66EC, 0x66EE, 0x66FA, 0x6705, 0x6707, 0x670E, 0x6713, 0x6719, 0x671C, 0x6720, 0x6722, 0x6733, 0x673E, 0x6745, 0x6747, 0x6748, 0x674C, 0x6754, 0x6755, 0x675D, }; const unsigned short euc_to_utf8_8FC3[] = { 0x6766, 0x676C, 0x676E, 0x6774, 0x6776, 0x677B, 0x6781, 0x6784, 0x678E, 0x678F, 0x6791, 0x6793, 0x6796, 0x6798, 0x6799, 0x679B, 0x67B0, 0x67B1, 0x67B2, 0x67B5, 0x67BB, 0x67BC, 0x67BD, 0x67F9, 0x67C0, 0x67C2, 0x67C3, 0x67C5, 0x67C8, 0x67C9, 0x67D2, 0x67D7, 0x67D9, 0x67DC, 0x67E1, 0x67E6, 0x67F0, 0x67F2, 0x67F6, 0x67F7, 0x6852, 0x6814, 0x6819, 0x681D, 0x681F, 0x6828, 0x6827, 0x682C, 0x682D, 0x682F, 0x6830, 0x6831, 0x6833, 0x683B, 0x683F, 0x6844, 0x6845, 0x684A, 0x684C, 0x6855, 0x6857, 0x6858, 0x685B, 0x686B, 0x686E, 0x686F, 0x6870, 0x6871, 0x6872, 0x6875, 0x6879, 0x687A, 0x687B, 0x687C, 0x6882, 0x6884, 0x6886, 0x6888, 0x6896, 0x6898, 0x689A, 0x689C, 0x68A1, 0x68A3, 0x68A5, 0x68A9, 0x68AA, 0x68AE, 0x68B2, 0x68BB, 0x68C5, 0x68C8, 0x68CC, 0x68CF, }; const unsigned short euc_to_utf8_8FC4[] = { 0x68D0, 0x68D1, 0x68D3, 0x68D6, 0x68D9, 0x68DC, 0x68DD, 0x68E5, 0x68E8, 0x68EA, 0x68EB, 0x68EC, 0x68ED, 0x68F0, 0x68F1, 0x68F5, 0x68F6, 0x68FB, 0x68FC, 0x68FD, 0x6906, 0x6909, 0x690A, 0x6910, 0x6911, 0x6913, 0x6916, 0x6917, 0x6931, 0x6933, 0x6935, 0x6938, 0x693B, 0x6942, 0x6945, 0x6949, 0x694E, 0x6957, 0x695B, 0x6963, 0x6964, 0x6965, 0x6966, 0x6968, 0x6969, 0x696C, 0x6970, 0x6971, 0x6972, 0x697A, 0x697B, 0x697F, 0x6980, 0x698D, 0x6992, 0x6996, 0x6998, 0x69A1, 0x69A5, 0x69A6, 0x69A8, 0x69AB, 0x69AD, 0x69AF, 0x69B7, 0x69B8, 0x69BA, 0x69BC, 0x69C5, 0x69C8, 0x69D1, 0x69D6, 0x69D7, 0x69E2, 0x69E5, 0x69EE, 0x69EF, 0x69F1, 0x69F3, 0x69F5, 0x69FE, 0x6A00, 0x6A01, 0x6A03, 0x6A0F, 0x6A11, 0x6A15, 0x6A1A, 0x6A1D, 0x6A20, 0x6A24, 0x6A28, 0x6A30, 0x6A32, }; const unsigned short euc_to_utf8_8FC5[] = { 0x6A34, 0x6A37, 0x6A3B, 0x6A3E, 0x6A3F, 0x6A45, 0x6A46, 0x6A49, 0x6A4A, 0x6A4E, 0x6A50, 0x6A51, 0x6A52, 0x6A55, 0x6A56, 0x6A5B, 0x6A64, 0x6A67, 0x6A6A, 0x6A71, 0x6A73, 0x6A7E, 0x6A81, 0x6A83, 0x6A86, 0x6A87, 0x6A89, 0x6A8B, 0x6A91, 0x6A9B, 0x6A9D, 0x6A9E, 0x6A9F, 0x6AA5, 0x6AAB, 0x6AAF, 0x6AB0, 0x6AB1, 0x6AB4, 0x6ABD, 0x6ABE, 0x6ABF, 0x6AC6, 0x6AC9, 0x6AC8, 0x6ACC, 0x6AD0, 0x6AD4, 0x6AD5, 0x6AD6, 0x6ADC, 0x6ADD, 0x6AE4, 0x6AE7, 0x6AEC, 0x6AF0, 0x6AF1, 0x6AF2, 0x6AFC, 0x6AFD, 0x6B02, 0x6B03, 0x6B06, 0x6B07, 0x6B09, 0x6B0F, 0x6B10, 0x6B11, 0x6B17, 0x6B1B, 0x6B1E, 0x6B24, 0x6B28, 0x6B2B, 0x6B2C, 0x6B2F, 0x6B35, 0x6B36, 0x6B3B, 0x6B3F, 0x6B46, 0x6B4A, 0x6B4D, 0x6B52, 0x6B56, 0x6B58, 0x6B5D, 0x6B60, 0x6B67, 0x6B6B, 0x6B6E, 0x6B70, 0x6B75, 0x6B7D, }; const unsigned short euc_to_utf8_8FC6[] = { 0x6B7E, 0x6B82, 0x6B85, 0x6B97, 0x6B9B, 0x6B9F, 0x6BA0, 0x6BA2, 0x6BA3, 0x6BA8, 0x6BA9, 0x6BAC, 0x6BAD, 0x6BAE, 0x6BB0, 0x6BB8, 0x6BB9, 0x6BBD, 0x6BBE, 0x6BC3, 0x6BC4, 0x6BC9, 0x6BCC, 0x6BD6, 0x6BDA, 0x6BE1, 0x6BE3, 0x6BE6, 0x6BE7, 0x6BEE, 0x6BF1, 0x6BF7, 0x6BF9, 0x6BFF, 0x6C02, 0x6C04, 0x6C05, 0x6C09, 0x6C0D, 0x6C0E, 0x6C10, 0x6C12, 0x6C19, 0x6C1F, 0x6C26, 0x6C27, 0x6C28, 0x6C2C, 0x6C2E, 0x6C33, 0x6C35, 0x6C36, 0x6C3A, 0x6C3B, 0x6C3F, 0x6C4A, 0x6C4B, 0x6C4D, 0x6C4F, 0x6C52, 0x6C54, 0x6C59, 0x6C5B, 0x6C5C, 0x6C6B, 0x6C6D, 0x6C6F, 0x6C74, 0x6C76, 0x6C78, 0x6C79, 0x6C7B, 0x6C85, 0x6C86, 0x6C87, 0x6C89, 0x6C94, 0x6C95, 0x6C97, 0x6C98, 0x6C9C, 0x6C9F, 0x6CB0, 0x6CB2, 0x6CB4, 0x6CC2, 0x6CC6, 0x6CCD, 0x6CCF, 0x6CD0, 0x6CD1, 0x6CD2, 0x6CD4, 0x6CD6, }; const unsigned short euc_to_utf8_8FC7[] = { 0x6CDA, 0x6CDC, 0x6CE0, 0x6CE7, 0x6CE9, 0x6CEB, 0x6CEC, 0x6CEE, 0x6CF2, 0x6CF4, 0x6D04, 0x6D07, 0x6D0A, 0x6D0E, 0x6D0F, 0x6D11, 0x6D13, 0x6D1A, 0x6D26, 0x6D27, 0x6D28, 0x6C67, 0x6D2E, 0x6D2F, 0x6D31, 0x6D39, 0x6D3C, 0x6D3F, 0x6D57, 0x6D5E, 0x6D5F, 0x6D61, 0x6D65, 0x6D67, 0x6D6F, 0x6D70, 0x6D7C, 0x6D82, 0x6D87, 0x6D91, 0x6D92, 0x6D94, 0x6D96, 0x6D97, 0x6D98, 0x6DAA, 0x6DAC, 0x6DB4, 0x6DB7, 0x6DB9, 0x6DBD, 0x6DBF, 0x6DC4, 0x6DC8, 0x6DCA, 0x6DCE, 0x6DCF, 0x6DD6, 0x6DDB, 0x6DDD, 0x6DDF, 0x6DE0, 0x6DE2, 0x6DE5, 0x6DE9, 0x6DEF, 0x6DF0, 0x6DF4, 0x6DF6, 0x6DFC, 0x6E00, 0x6E04, 0x6E1E, 0x6E22, 0x6E27, 0x6E32, 0x6E36, 0x6E39, 0x6E3B, 0x6E3C, 0x6E44, 0x6E45, 0x6E48, 0x6E49, 0x6E4B, 0x6E4F, 0x6E51, 0x6E52, 0x6E53, 0x6E54, 0x6E57, 0x6E5C, 0x6E5D, 0x6E5E, }; const unsigned short euc_to_utf8_8FC8[] = { 0x6E62, 0x6E63, 0x6E68, 0x6E73, 0x6E7B, 0x6E7D, 0x6E8D, 0x6E93, 0x6E99, 0x6EA0, 0x6EA7, 0x6EAD, 0x6EAE, 0x6EB1, 0x6EB3, 0x6EBB, 0x6EBF, 0x6EC0, 0x6EC1, 0x6EC3, 0x6EC7, 0x6EC8, 0x6ECA, 0x6ECD, 0x6ECE, 0x6ECF, 0x6EEB, 0x6EED, 0x6EEE, 0x6EF9, 0x6EFB, 0x6EFD, 0x6F04, 0x6F08, 0x6F0A, 0x6F0C, 0x6F0D, 0x6F16, 0x6F18, 0x6F1A, 0x6F1B, 0x6F26, 0x6F29, 0x6F2A, 0x6F2F, 0x6F30, 0x6F33, 0x6F36, 0x6F3B, 0x6F3C, 0x6F2D, 0x6F4F, 0x6F51, 0x6F52, 0x6F53, 0x6F57, 0x6F59, 0x6F5A, 0x6F5D, 0x6F5E, 0x6F61, 0x6F62, 0x6F68, 0x6F6C, 0x6F7D, 0x6F7E, 0x6F83, 0x6F87, 0x6F88, 0x6F8B, 0x6F8C, 0x6F8D, 0x6F90, 0x6F92, 0x6F93, 0x6F94, 0x6F96, 0x6F9A, 0x6F9F, 0x6FA0, 0x6FA5, 0x6FA6, 0x6FA7, 0x6FA8, 0x6FAE, 0x6FAF, 0x6FB0, 0x6FB5, 0x6FB6, 0x6FBC, 0x6FC5, 0x6FC7, 0x6FC8, 0x6FCA, }; const unsigned short euc_to_utf8_8FC9[] = { 0x6FDA, 0x6FDE, 0x6FE8, 0x6FE9, 0x6FF0, 0x6FF5, 0x6FF9, 0x6FFC, 0x6FFD, 0x7000, 0x7005, 0x7006, 0x7007, 0x700D, 0x7017, 0x7020, 0x7023, 0x702F, 0x7034, 0x7037, 0x7039, 0x703C, 0x7043, 0x7044, 0x7048, 0x7049, 0x704A, 0x704B, 0x7054, 0x7055, 0x705D, 0x705E, 0x704E, 0x7064, 0x7065, 0x706C, 0x706E, 0x7075, 0x7076, 0x707E, 0x7081, 0x7085, 0x7086, 0x7094, 0x7095, 0x7096, 0x7097, 0x7098, 0x709B, 0x70A4, 0x70AB, 0x70B0, 0x70B1, 0x70B4, 0x70B7, 0x70CA, 0x70D1, 0x70D3, 0x70D4, 0x70D5, 0x70D6, 0x70D8, 0x70DC, 0x70E4, 0x70FA, 0x7103, 0x7104, 0x7105, 0x7106, 0x7107, 0x710B, 0x710C, 0x710F, 0x711E, 0x7120, 0x712B, 0x712D, 0x712F, 0x7130, 0x7131, 0x7138, 0x7141, 0x7145, 0x7146, 0x7147, 0x714A, 0x714B, 0x7150, 0x7152, 0x7157, 0x715A, 0x715C, 0x715E, 0x7160, }; const unsigned short euc_to_utf8_8FCA[] = { 0x7168, 0x7179, 0x7180, 0x7185, 0x7187, 0x718C, 0x7192, 0x719A, 0x719B, 0x71A0, 0x71A2, 0x71AF, 0x71B0, 0x71B2, 0x71B3, 0x71BA, 0x71BF, 0x71C0, 0x71C1, 0x71C4, 0x71CB, 0x71CC, 0x71D3, 0x71D6, 0x71D9, 0x71DA, 0x71DC, 0x71F8, 0x71FE, 0x7200, 0x7207, 0x7208, 0x7209, 0x7213, 0x7217, 0x721A, 0x721D, 0x721F, 0x7224, 0x722B, 0x722F, 0x7234, 0x7238, 0x7239, 0x7241, 0x7242, 0x7243, 0x7245, 0x724E, 0x724F, 0x7250, 0x7253, 0x7255, 0x7256, 0x725A, 0x725C, 0x725E, 0x7260, 0x7263, 0x7268, 0x726B, 0x726E, 0x726F, 0x7271, 0x7277, 0x7278, 0x727B, 0x727C, 0x727F, 0x7284, 0x7289, 0x728D, 0x728E, 0x7293, 0x729B, 0x72A8, 0x72AD, 0x72AE, 0x72B1, 0x72B4, 0x72BE, 0x72C1, 0x72C7, 0x72C9, 0x72CC, 0x72D5, 0x72D6, 0x72D8, 0x72DF, 0x72E5, 0x72F3, 0x72F4, 0x72FA, 0x72FB, }; const unsigned short euc_to_utf8_8FCB[] = { 0x72FE, 0x7302, 0x7304, 0x7305, 0x7307, 0x730B, 0x730D, 0x7312, 0x7313, 0x7318, 0x7319, 0x731E, 0x7322, 0x7324, 0x7327, 0x7328, 0x732C, 0x7331, 0x7332, 0x7335, 0x733A, 0x733B, 0x733D, 0x7343, 0x734D, 0x7350, 0x7352, 0x7356, 0x7358, 0x735D, 0x735E, 0x735F, 0x7360, 0x7366, 0x7367, 0x7369, 0x736B, 0x736C, 0x736E, 0x736F, 0x7371, 0x7377, 0x7379, 0x737C, 0x7380, 0x7381, 0x7383, 0x7385, 0x7386, 0x738E, 0x7390, 0x7393, 0x7395, 0x7397, 0x7398, 0x739C, 0x739E, 0x739F, 0x73A0, 0x73A2, 0x73A5, 0x73A6, 0x73AA, 0x73AB, 0x73AD, 0x73B5, 0x73B7, 0x73B9, 0x73BC, 0x73BD, 0x73BF, 0x73C5, 0x73C6, 0x73C9, 0x73CB, 0x73CC, 0x73CF, 0x73D2, 0x73D3, 0x73D6, 0x73D9, 0x73DD, 0x73E1, 0x73E3, 0x73E6, 0x73E7, 0x73E9, 0x73F4, 0x73F5, 0x73F7, 0x73F9, 0x73FA, 0x73FB, 0x73FD, }; const unsigned short euc_to_utf8_8FCC[] = { 0x73FF, 0x7400, 0x7401, 0x7404, 0x7407, 0x740A, 0x7411, 0x741A, 0x741B, 0x7424, 0x7426, 0x7428, 0x7429, 0x742A, 0x742B, 0x742C, 0x742D, 0x742E, 0x742F, 0x7430, 0x7431, 0x7439, 0x7440, 0x7443, 0x7444, 0x7446, 0x7447, 0x744B, 0x744D, 0x7451, 0x7452, 0x7457, 0x745D, 0x7462, 0x7466, 0x7467, 0x7468, 0x746B, 0x746D, 0x746E, 0x7471, 0x7472, 0x7480, 0x7481, 0x7485, 0x7486, 0x7487, 0x7489, 0x748F, 0x7490, 0x7491, 0x7492, 0x7498, 0x7499, 0x749A, 0x749C, 0x749F, 0x74A0, 0x74A1, 0x74A3, 0x74A6, 0x74A8, 0x74A9, 0x74AA, 0x74AB, 0x74AE, 0x74AF, 0x74B1, 0x74B2, 0x74B5, 0x74B9, 0x74BB, 0x74BF, 0x74C8, 0x74C9, 0x74CC, 0x74D0, 0x74D3, 0x74D8, 0x74DA, 0x74DB, 0x74DE, 0x74DF, 0x74E4, 0x74E8, 0x74EA, 0x74EB, 0x74EF, 0x74F4, 0x74FA, 0x74FB, 0x74FC, 0x74FF, 0x7506, }; const unsigned short euc_to_utf8_8FCD[] = { 0x7512, 0x7516, 0x7517, 0x7520, 0x7521, 0x7524, 0x7527, 0x7529, 0x752A, 0x752F, 0x7536, 0x7539, 0x753D, 0x753E, 0x753F, 0x7540, 0x7543, 0x7547, 0x7548, 0x754E, 0x7550, 0x7552, 0x7557, 0x755E, 0x755F, 0x7561, 0x756F, 0x7571, 0x7579, 0x757A, 0x757B, 0x757C, 0x757D, 0x757E, 0x7581, 0x7585, 0x7590, 0x7592, 0x7593, 0x7595, 0x7599, 0x759C, 0x75A2, 0x75A4, 0x75B4, 0x75BA, 0x75BF, 0x75C0, 0x75C1, 0x75C4, 0x75C6, 0x75CC, 0x75CE, 0x75CF, 0x75D7, 0x75DC, 0x75DF, 0x75E0, 0x75E1, 0x75E4, 0x75E7, 0x75EC, 0x75EE, 0x75EF, 0x75F1, 0x75F9, 0x7600, 0x7602, 0x7603, 0x7604, 0x7607, 0x7608, 0x760A, 0x760C, 0x760F, 0x7612, 0x7613, 0x7615, 0x7616, 0x7619, 0x761B, 0x761C, 0x761D, 0x761E, 0x7623, 0x7625, 0x7626, 0x7629, 0x762D, 0x7632, 0x7633, 0x7635, 0x7638, 0x7639, }; const unsigned short euc_to_utf8_8FCE[] = { 0x763A, 0x763C, 0x764A, 0x7640, 0x7641, 0x7643, 0x7644, 0x7645, 0x7649, 0x764B, 0x7655, 0x7659, 0x765F, 0x7664, 0x7665, 0x766D, 0x766E, 0x766F, 0x7671, 0x7674, 0x7681, 0x7685, 0x768C, 0x768D, 0x7695, 0x769B, 0x769C, 0x769D, 0x769F, 0x76A0, 0x76A2, 0x76A3, 0x76A4, 0x76A5, 0x76A6, 0x76A7, 0x76A8, 0x76AA, 0x76AD, 0x76BD, 0x76C1, 0x76C5, 0x76C9, 0x76CB, 0x76CC, 0x76CE, 0x76D4, 0x76D9, 0x76E0, 0x76E6, 0x76E8, 0x76EC, 0x76F0, 0x76F1, 0x76F6, 0x76F9, 0x76FC, 0x7700, 0x7706, 0x770A, 0x770E, 0x7712, 0x7714, 0x7715, 0x7717, 0x7719, 0x771A, 0x771C, 0x7722, 0x7728, 0x772D, 0x772E, 0x772F, 0x7734, 0x7735, 0x7736, 0x7739, 0x773D, 0x773E, 0x7742, 0x7745, 0x7746, 0x774A, 0x774D, 0x774E, 0x774F, 0x7752, 0x7756, 0x7757, 0x775C, 0x775E, 0x775F, 0x7760, 0x7762, }; const unsigned short euc_to_utf8_8FCF[] = { 0x7764, 0x7767, 0x776A, 0x776C, 0x7770, 0x7772, 0x7773, 0x7774, 0x777A, 0x777D, 0x7780, 0x7784, 0x778C, 0x778D, 0x7794, 0x7795, 0x7796, 0x779A, 0x779F, 0x77A2, 0x77A7, 0x77AA, 0x77AE, 0x77AF, 0x77B1, 0x77B5, 0x77BE, 0x77C3, 0x77C9, 0x77D1, 0x77D2, 0x77D5, 0x77D9, 0x77DE, 0x77DF, 0x77E0, 0x77E4, 0x77E6, 0x77EA, 0x77EC, 0x77F0, 0x77F1, 0x77F4, 0x77F8, 0x77FB, 0x7805, 0x7806, 0x7809, 0x780D, 0x780E, 0x7811, 0x781D, 0x7821, 0x7822, 0x7823, 0x782D, 0x782E, 0x7830, 0x7835, 0x7837, 0x7843, 0x7844, 0x7847, 0x7848, 0x784C, 0x784E, 0x7852, 0x785C, 0x785E, 0x7860, 0x7861, 0x7863, 0x7864, 0x7868, 0x786A, 0x786E, 0x787A, 0x787E, 0x788A, 0x788F, 0x7894, 0x7898, 0x78A1, 0x789D, 0x789E, 0x789F, 0x78A4, 0x78A8, 0x78AC, 0x78AD, 0x78B0, 0x78B1, 0x78B2, 0x78B3, }; const unsigned short euc_to_utf8_8FD0[] = { 0x78BB, 0x78BD, 0x78BF, 0x78C7, 0x78C8, 0x78C9, 0x78CC, 0x78CE, 0x78D2, 0x78D3, 0x78D5, 0x78D6, 0x78E4, 0x78DB, 0x78DF, 0x78E0, 0x78E1, 0x78E6, 0x78EA, 0x78F2, 0x78F3, 0x7900, 0x78F6, 0x78F7, 0x78FA, 0x78FB, 0x78FF, 0x7906, 0x790C, 0x7910, 0x791A, 0x791C, 0x791E, 0x791F, 0x7920, 0x7925, 0x7927, 0x7929, 0x792D, 0x7931, 0x7934, 0x7935, 0x793B, 0x793D, 0x793F, 0x7944, 0x7945, 0x7946, 0x794A, 0x794B, 0x794F, 0x7951, 0x7954, 0x7958, 0x795B, 0x795C, 0x7967, 0x7969, 0x796B, 0x7972, 0x7979, 0x797B, 0x797C, 0x797E, 0x798B, 0x798C, 0x7991, 0x7993, 0x7994, 0x7995, 0x7996, 0x7998, 0x799B, 0x799C, 0x79A1, 0x79A8, 0x79A9, 0x79AB, 0x79AF, 0x79B1, 0x79B4, 0x79B8, 0x79BB, 0x79C2, 0x79C4, 0x79C7, 0x79C8, 0x79CA, 0x79CF, 0x79D4, 0x79D6, 0x79DA, 0x79DD, 0x79DE, }; const unsigned short euc_to_utf8_8FD1[] = { 0x79E0, 0x79E2, 0x79E5, 0x79EA, 0x79EB, 0x79ED, 0x79F1, 0x79F8, 0x79FC, 0x7A02, 0x7A03, 0x7A07, 0x7A09, 0x7A0A, 0x7A0C, 0x7A11, 0x7A15, 0x7A1B, 0x7A1E, 0x7A21, 0x7A27, 0x7A2B, 0x7A2D, 0x7A2F, 0x7A30, 0x7A34, 0x7A35, 0x7A38, 0x7A39, 0x7A3A, 0x7A44, 0x7A45, 0x7A47, 0x7A48, 0x7A4C, 0x7A55, 0x7A56, 0x7A59, 0x7A5C, 0x7A5D, 0x7A5F, 0x7A60, 0x7A65, 0x7A67, 0x7A6A, 0x7A6D, 0x7A75, 0x7A78, 0x7A7E, 0x7A80, 0x7A82, 0x7A85, 0x7A86, 0x7A8A, 0x7A8B, 0x7A90, 0x7A91, 0x7A94, 0x7A9E, 0x7AA0, 0x7AA3, 0x7AAC, 0x7AB3, 0x7AB5, 0x7AB9, 0x7ABB, 0x7ABC, 0x7AC6, 0x7AC9, 0x7ACC, 0x7ACE, 0x7AD1, 0x7ADB, 0x7AE8, 0x7AE9, 0x7AEB, 0x7AEC, 0x7AF1, 0x7AF4, 0x7AFB, 0x7AFD, 0x7AFE, 0x7B07, 0x7B14, 0x7B1F, 0x7B23, 0x7B27, 0x7B29, 0x7B2A, 0x7B2B, 0x7B2D, 0x7B2E, 0x7B2F, 0x7B30, }; const unsigned short euc_to_utf8_8FD2[] = { 0x7B31, 0x7B34, 0x7B3D, 0x7B3F, 0x7B40, 0x7B41, 0x7B47, 0x7B4E, 0x7B55, 0x7B60, 0x7B64, 0x7B66, 0x7B69, 0x7B6A, 0x7B6D, 0x7B6F, 0x7B72, 0x7B73, 0x7B77, 0x7B84, 0x7B89, 0x7B8E, 0x7B90, 0x7B91, 0x7B96, 0x7B9B, 0x7B9E, 0x7BA0, 0x7BA5, 0x7BAC, 0x7BAF, 0x7BB0, 0x7BB2, 0x7BB5, 0x7BB6, 0x7BBA, 0x7BBB, 0x7BBC, 0x7BBD, 0x7BC2, 0x7BC5, 0x7BC8, 0x7BCA, 0x7BD4, 0x7BD6, 0x7BD7, 0x7BD9, 0x7BDA, 0x7BDB, 0x7BE8, 0x7BEA, 0x7BF2, 0x7BF4, 0x7BF5, 0x7BF8, 0x7BF9, 0x7BFA, 0x7BFC, 0x7BFE, 0x7C01, 0x7C02, 0x7C03, 0x7C04, 0x7C06, 0x7C09, 0x7C0B, 0x7C0C, 0x7C0E, 0x7C0F, 0x7C19, 0x7C1B, 0x7C20, 0x7C25, 0x7C26, 0x7C28, 0x7C2C, 0x7C31, 0x7C33, 0x7C34, 0x7C36, 0x7C39, 0x7C3A, 0x7C46, 0x7C4A, 0x7C55, 0x7C51, 0x7C52, 0x7C53, 0x7C59, 0x7C5A, 0x7C5B, 0x7C5C, 0x7C5D, 0x7C5E, }; const unsigned short euc_to_utf8_8FD3[] = { 0x7C61, 0x7C63, 0x7C67, 0x7C69, 0x7C6D, 0x7C6E, 0x7C70, 0x7C72, 0x7C79, 0x7C7C, 0x7C7D, 0x7C86, 0x7C87, 0x7C8F, 0x7C94, 0x7C9E, 0x7CA0, 0x7CA6, 0x7CB0, 0x7CB6, 0x7CB7, 0x7CBA, 0x7CBB, 0x7CBC, 0x7CBF, 0x7CC4, 0x7CC7, 0x7CC8, 0x7CC9, 0x7CCD, 0x7CCF, 0x7CD3, 0x7CD4, 0x7CD5, 0x7CD7, 0x7CD9, 0x7CDA, 0x7CDD, 0x7CE6, 0x7CE9, 0x7CEB, 0x7CF5, 0x7D03, 0x7D07, 0x7D08, 0x7D09, 0x7D0F, 0x7D11, 0x7D12, 0x7D13, 0x7D16, 0x7D1D, 0x7D1E, 0x7D23, 0x7D26, 0x7D2A, 0x7D2D, 0x7D31, 0x7D3C, 0x7D3D, 0x7D3E, 0x7D40, 0x7D41, 0x7D47, 0x7D48, 0x7D4D, 0x7D51, 0x7D53, 0x7D57, 0x7D59, 0x7D5A, 0x7D5C, 0x7D5D, 0x7D65, 0x7D67, 0x7D6A, 0x7D70, 0x7D78, 0x7D7A, 0x7D7B, 0x7D7F, 0x7D81, 0x7D82, 0x7D83, 0x7D85, 0x7D86, 0x7D88, 0x7D8B, 0x7D8C, 0x7D8D, 0x7D91, 0x7D96, 0x7D97, 0x7D9D, }; const unsigned short euc_to_utf8_8FD4[] = { 0x7D9E, 0x7DA6, 0x7DA7, 0x7DAA, 0x7DB3, 0x7DB6, 0x7DB7, 0x7DB9, 0x7DC2, 0x7DC3, 0x7DC4, 0x7DC5, 0x7DC6, 0x7DCC, 0x7DCD, 0x7DCE, 0x7DD7, 0x7DD9, 0x7E00, 0x7DE2, 0x7DE5, 0x7DE6, 0x7DEA, 0x7DEB, 0x7DED, 0x7DF1, 0x7DF5, 0x7DF6, 0x7DF9, 0x7DFA, 0x7E08, 0x7E10, 0x7E11, 0x7E15, 0x7E17, 0x7E1C, 0x7E1D, 0x7E20, 0x7E27, 0x7E28, 0x7E2C, 0x7E2D, 0x7E2F, 0x7E33, 0x7E36, 0x7E3F, 0x7E44, 0x7E45, 0x7E47, 0x7E4E, 0x7E50, 0x7E52, 0x7E58, 0x7E5F, 0x7E61, 0x7E62, 0x7E65, 0x7E6B, 0x7E6E, 0x7E6F, 0x7E73, 0x7E78, 0x7E7E, 0x7E81, 0x7E86, 0x7E87, 0x7E8A, 0x7E8D, 0x7E91, 0x7E95, 0x7E98, 0x7E9A, 0x7E9D, 0x7E9E, 0x7F3C, 0x7F3B, 0x7F3D, 0x7F3E, 0x7F3F, 0x7F43, 0x7F44, 0x7F47, 0x7F4F, 0x7F52, 0x7F53, 0x7F5B, 0x7F5C, 0x7F5D, 0x7F61, 0x7F63, 0x7F64, 0x7F65, 0x7F66, 0x7F6D, }; const unsigned short euc_to_utf8_8FD5[] = { 0x7F71, 0x7F7D, 0x7F7E, 0x7F7F, 0x7F80, 0x7F8B, 0x7F8D, 0x7F8F, 0x7F90, 0x7F91, 0x7F96, 0x7F97, 0x7F9C, 0x7FA1, 0x7FA2, 0x7FA6, 0x7FAA, 0x7FAD, 0x7FB4, 0x7FBC, 0x7FBF, 0x7FC0, 0x7FC3, 0x7FC8, 0x7FCE, 0x7FCF, 0x7FDB, 0x7FDF, 0x7FE3, 0x7FE5, 0x7FE8, 0x7FEC, 0x7FEE, 0x7FEF, 0x7FF2, 0x7FFA, 0x7FFD, 0x7FFE, 0x7FFF, 0x8007, 0x8008, 0x800A, 0x800D, 0x800E, 0x800F, 0x8011, 0x8013, 0x8014, 0x8016, 0x801D, 0x801E, 0x801F, 0x8020, 0x8024, 0x8026, 0x802C, 0x802E, 0x8030, 0x8034, 0x8035, 0x8037, 0x8039, 0x803A, 0x803C, 0x803E, 0x8040, 0x8044, 0x8060, 0x8064, 0x8066, 0x806D, 0x8071, 0x8075, 0x8081, 0x8088, 0x808E, 0x809C, 0x809E, 0x80A6, 0x80A7, 0x80AB, 0x80B8, 0x80B9, 0x80C8, 0x80CD, 0x80CF, 0x80D2, 0x80D4, 0x80D5, 0x80D7, 0x80D8, 0x80E0, 0x80ED, 0x80EE, }; const unsigned short euc_to_utf8_8FD6[] = { 0x80F0, 0x80F2, 0x80F3, 0x80F6, 0x80F9, 0x80FA, 0x80FE, 0x8103, 0x810B, 0x8116, 0x8117, 0x8118, 0x811C, 0x811E, 0x8120, 0x8124, 0x8127, 0x812C, 0x8130, 0x8135, 0x813A, 0x813C, 0x8145, 0x8147, 0x814A, 0x814C, 0x8152, 0x8157, 0x8160, 0x8161, 0x8167, 0x8168, 0x8169, 0x816D, 0x816F, 0x8177, 0x8181, 0x8190, 0x8184, 0x8185, 0x8186, 0x818B, 0x818E, 0x8196, 0x8198, 0x819B, 0x819E, 0x81A2, 0x81AE, 0x81B2, 0x81B4, 0x81BB, 0x81CB, 0x81C3, 0x81C5, 0x81CA, 0x81CE, 0x81CF, 0x81D5, 0x81D7, 0x81DB, 0x81DD, 0x81DE, 0x81E1, 0x81E4, 0x81EB, 0x81EC, 0x81F0, 0x81F1, 0x81F2, 0x81F5, 0x81F6, 0x81F8, 0x81F9, 0x81FD, 0x81FF, 0x8200, 0x8203, 0x820F, 0x8213, 0x8214, 0x8219, 0x821A, 0x821D, 0x8221, 0x8222, 0x8228, 0x8232, 0x8234, 0x823A, 0x8243, 0x8244, 0x8245, 0x8246, }; const unsigned short euc_to_utf8_8FD7[] = { 0x824B, 0x824E, 0x824F, 0x8251, 0x8256, 0x825C, 0x8260, 0x8263, 0x8267, 0x826D, 0x8274, 0x827B, 0x827D, 0x827F, 0x8280, 0x8281, 0x8283, 0x8284, 0x8287, 0x8289, 0x828A, 0x828E, 0x8291, 0x8294, 0x8296, 0x8298, 0x829A, 0x829B, 0x82A0, 0x82A1, 0x82A3, 0x82A4, 0x82A7, 0x82A8, 0x82A9, 0x82AA, 0x82AE, 0x82B0, 0x82B2, 0x82B4, 0x82B7, 0x82BA, 0x82BC, 0x82BE, 0x82BF, 0x82C6, 0x82D0, 0x82D5, 0x82DA, 0x82E0, 0x82E2, 0x82E4, 0x82E8, 0x82EA, 0x82ED, 0x82EF, 0x82F6, 0x82F7, 0x82FD, 0x82FE, 0x8300, 0x8301, 0x8307, 0x8308, 0x830A, 0x830B, 0x8354, 0x831B, 0x831D, 0x831E, 0x831F, 0x8321, 0x8322, 0x832C, 0x832D, 0x832E, 0x8330, 0x8333, 0x8337, 0x833A, 0x833C, 0x833D, 0x8342, 0x8343, 0x8344, 0x8347, 0x834D, 0x834E, 0x8351, 0x8355, 0x8356, 0x8357, 0x8370, 0x8378, }; const unsigned short euc_to_utf8_8FD8[] = { 0x837D, 0x837F, 0x8380, 0x8382, 0x8384, 0x8386, 0x838D, 0x8392, 0x8394, 0x8395, 0x8398, 0x8399, 0x839B, 0x839C, 0x839D, 0x83A6, 0x83A7, 0x83A9, 0x83AC, 0x83BE, 0x83BF, 0x83C0, 0x83C7, 0x83C9, 0x83CF, 0x83D0, 0x83D1, 0x83D4, 0x83DD, 0x8353, 0x83E8, 0x83EA, 0x83F6, 0x83F8, 0x83F9, 0x83FC, 0x8401, 0x8406, 0x840A, 0x840F, 0x8411, 0x8415, 0x8419, 0x83AD, 0x842F, 0x8439, 0x8445, 0x8447, 0x8448, 0x844A, 0x844D, 0x844F, 0x8451, 0x8452, 0x8456, 0x8458, 0x8459, 0x845A, 0x845C, 0x8460, 0x8464, 0x8465, 0x8467, 0x846A, 0x8470, 0x8473, 0x8474, 0x8476, 0x8478, 0x847C, 0x847D, 0x8481, 0x8485, 0x8492, 0x8493, 0x8495, 0x849E, 0x84A6, 0x84A8, 0x84A9, 0x84AA, 0x84AF, 0x84B1, 0x84B4, 0x84BA, 0x84BD, 0x84BE, 0x84C0, 0x84C2, 0x84C7, 0x84C8, 0x84CC, 0x84CF, 0x84D3, }; const unsigned short euc_to_utf8_8FD9[] = { 0x84DC, 0x84E7, 0x84EA, 0x84EF, 0x84F0, 0x84F1, 0x84F2, 0x84F7, 0x8532, 0x84FA, 0x84FB, 0x84FD, 0x8502, 0x8503, 0x8507, 0x850C, 0x850E, 0x8510, 0x851C, 0x851E, 0x8522, 0x8523, 0x8524, 0x8525, 0x8527, 0x852A, 0x852B, 0x852F, 0x8533, 0x8534, 0x8536, 0x853F, 0x8546, 0x854F, 0x8550, 0x8551, 0x8552, 0x8553, 0x8556, 0x8559, 0x855C, 0x855D, 0x855E, 0x855F, 0x8560, 0x8561, 0x8562, 0x8564, 0x856B, 0x856F, 0x8579, 0x857A, 0x857B, 0x857D, 0x857F, 0x8581, 0x8585, 0x8586, 0x8589, 0x858B, 0x858C, 0x858F, 0x8593, 0x8598, 0x859D, 0x859F, 0x85A0, 0x85A2, 0x85A5, 0x85A7, 0x85B4, 0x85B6, 0x85B7, 0x85B8, 0x85BC, 0x85BD, 0x85BE, 0x85BF, 0x85C2, 0x85C7, 0x85CA, 0x85CB, 0x85CE, 0x85AD, 0x85D8, 0x85DA, 0x85DF, 0x85E0, 0x85E6, 0x85E8, 0x85ED, 0x85F3, 0x85F6, 0x85FC, }; const unsigned short euc_to_utf8_8FDA[] = { 0x85FF, 0x8600, 0x8604, 0x8605, 0x860D, 0x860E, 0x8610, 0x8611, 0x8612, 0x8618, 0x8619, 0x861B, 0x861E, 0x8621, 0x8627, 0x8629, 0x8636, 0x8638, 0x863A, 0x863C, 0x863D, 0x8640, 0x8642, 0x8646, 0x8652, 0x8653, 0x8656, 0x8657, 0x8658, 0x8659, 0x865D, 0x8660, 0x8661, 0x8662, 0x8663, 0x8664, 0x8669, 0x866C, 0x866F, 0x8675, 0x8676, 0x8677, 0x867A, 0x868D, 0x8691, 0x8696, 0x8698, 0x869A, 0x869C, 0x86A1, 0x86A6, 0x86A7, 0x86A8, 0x86AD, 0x86B1, 0x86B3, 0x86B4, 0x86B5, 0x86B7, 0x86B8, 0x86B9, 0x86BF, 0x86C0, 0x86C1, 0x86C3, 0x86C5, 0x86D1, 0x86D2, 0x86D5, 0x86D7, 0x86DA, 0x86DC, 0x86E0, 0x86E3, 0x86E5, 0x86E7, 0x8688, 0x86FA, 0x86FC, 0x86FD, 0x8704, 0x8705, 0x8707, 0x870B, 0x870E, 0x870F, 0x8710, 0x8713, 0x8714, 0x8719, 0x871E, 0x871F, 0x8721, 0x8723, }; const unsigned short euc_to_utf8_8FDB[] = { 0x8728, 0x872E, 0x872F, 0x8731, 0x8732, 0x8739, 0x873A, 0x873C, 0x873D, 0x873E, 0x8740, 0x8743, 0x8745, 0x874D, 0x8758, 0x875D, 0x8761, 0x8764, 0x8765, 0x876F, 0x8771, 0x8772, 0x877B, 0x8783, 0x8784, 0x8785, 0x8786, 0x8787, 0x8788, 0x8789, 0x878B, 0x878C, 0x8790, 0x8793, 0x8795, 0x8797, 0x8798, 0x8799, 0x879E, 0x87A0, 0x87A3, 0x87A7, 0x87AC, 0x87AD, 0x87AE, 0x87B1, 0x87B5, 0x87BE, 0x87BF, 0x87C1, 0x87C8, 0x87C9, 0x87CA, 0x87CE, 0x87D5, 0x87D6, 0x87D9, 0x87DA, 0x87DC, 0x87DF, 0x87E2, 0x87E3, 0x87E4, 0x87EA, 0x87EB, 0x87ED, 0x87F1, 0x87F3, 0x87F8, 0x87FA, 0x87FF, 0x8801, 0x8803, 0x8806, 0x8809, 0x880A, 0x880B, 0x8810, 0x8819, 0x8812, 0x8813, 0x8814, 0x8818, 0x881A, 0x881B, 0x881C, 0x881E, 0x881F, 0x8828, 0x882D, 0x882E, 0x8830, 0x8832, 0x8835, }; const unsigned short euc_to_utf8_8FDC[] = { 0x883A, 0x883C, 0x8841, 0x8843, 0x8845, 0x8848, 0x8849, 0x884A, 0x884B, 0x884E, 0x8851, 0x8855, 0x8856, 0x8858, 0x885A, 0x885C, 0x885F, 0x8860, 0x8864, 0x8869, 0x8871, 0x8879, 0x887B, 0x8880, 0x8898, 0x889A, 0x889B, 0x889C, 0x889F, 0x88A0, 0x88A8, 0x88AA, 0x88BA, 0x88BD, 0x88BE, 0x88C0, 0x88CA, 0x88CB, 0x88CC, 0x88CD, 0x88CE, 0x88D1, 0x88D2, 0x88D3, 0x88DB, 0x88DE, 0x88E7, 0x88EF, 0x88F0, 0x88F1, 0x88F5, 0x88F7, 0x8901, 0x8906, 0x890D, 0x890E, 0x890F, 0x8915, 0x8916, 0x8918, 0x8919, 0x891A, 0x891C, 0x8920, 0x8926, 0x8927, 0x8928, 0x8930, 0x8931, 0x8932, 0x8935, 0x8939, 0x893A, 0x893E, 0x8940, 0x8942, 0x8945, 0x8946, 0x8949, 0x894F, 0x8952, 0x8957, 0x895A, 0x895B, 0x895C, 0x8961, 0x8962, 0x8963, 0x896B, 0x896E, 0x8970, 0x8973, 0x8975, 0x897A, }; const unsigned short euc_to_utf8_8FDD[] = { 0x897B, 0x897C, 0x897D, 0x8989, 0x898D, 0x8990, 0x8994, 0x8995, 0x899B, 0x899C, 0x899F, 0x89A0, 0x89A5, 0x89B0, 0x89B4, 0x89B5, 0x89B6, 0x89B7, 0x89BC, 0x89D4, 0x89D5, 0x89D6, 0x89D7, 0x89D8, 0x89E5, 0x89E9, 0x89EB, 0x89ED, 0x89F1, 0x89F3, 0x89F6, 0x89F9, 0x89FD, 0x89FF, 0x8A04, 0x8A05, 0x8A07, 0x8A0F, 0x8A11, 0x8A12, 0x8A14, 0x8A15, 0x8A1E, 0x8A20, 0x8A22, 0x8A24, 0x8A26, 0x8A2B, 0x8A2C, 0x8A2F, 0x8A35, 0x8A37, 0x8A3D, 0x8A3E, 0x8A40, 0x8A43, 0x8A45, 0x8A47, 0x8A49, 0x8A4D, 0x8A4E, 0x8A53, 0x8A56, 0x8A57, 0x8A58, 0x8A5C, 0x8A5D, 0x8A61, 0x8A65, 0x8A67, 0x8A75, 0x8A76, 0x8A77, 0x8A79, 0x8A7A, 0x8A7B, 0x8A7E, 0x8A7F, 0x8A80, 0x8A83, 0x8A86, 0x8A8B, 0x8A8F, 0x8A90, 0x8A92, 0x8A96, 0x8A97, 0x8A99, 0x8A9F, 0x8AA7, 0x8AA9, 0x8AAE, 0x8AAF, 0x8AB3, }; const unsigned short euc_to_utf8_8FDE[] = { 0x8AB6, 0x8AB7, 0x8ABB, 0x8ABE, 0x8AC3, 0x8AC6, 0x8AC8, 0x8AC9, 0x8ACA, 0x8AD1, 0x8AD3, 0x8AD4, 0x8AD5, 0x8AD7, 0x8ADD, 0x8ADF, 0x8AEC, 0x8AF0, 0x8AF4, 0x8AF5, 0x8AF6, 0x8AFC, 0x8AFF, 0x8B05, 0x8B06, 0x8B0B, 0x8B11, 0x8B1C, 0x8B1E, 0x8B1F, 0x8B0A, 0x8B2D, 0x8B30, 0x8B37, 0x8B3C, 0x8B42, 0x8B43, 0x8B44, 0x8B45, 0x8B46, 0x8B48, 0x8B52, 0x8B53, 0x8B54, 0x8B59, 0x8B4D, 0x8B5E, 0x8B63, 0x8B6D, 0x8B76, 0x8B78, 0x8B79, 0x8B7C, 0x8B7E, 0x8B81, 0x8B84, 0x8B85, 0x8B8B, 0x8B8D, 0x8B8F, 0x8B94, 0x8B95, 0x8B9C, 0x8B9E, 0x8B9F, 0x8C38, 0x8C39, 0x8C3D, 0x8C3E, 0x8C45, 0x8C47, 0x8C49, 0x8C4B, 0x8C4F, 0x8C51, 0x8C53, 0x8C54, 0x8C57, 0x8C58, 0x8C5B, 0x8C5D, 0x8C59, 0x8C63, 0x8C64, 0x8C66, 0x8C68, 0x8C69, 0x8C6D, 0x8C73, 0x8C75, 0x8C76, 0x8C7B, 0x8C7E, 0x8C86, }; const unsigned short euc_to_utf8_8FDF[] = { 0x8C87, 0x8C8B, 0x8C90, 0x8C92, 0x8C93, 0x8C99, 0x8C9B, 0x8C9C, 0x8CA4, 0x8CB9, 0x8CBA, 0x8CC5, 0x8CC6, 0x8CC9, 0x8CCB, 0x8CCF, 0x8CD6, 0x8CD5, 0x8CD9, 0x8CDD, 0x8CE1, 0x8CE8, 0x8CEC, 0x8CEF, 0x8CF0, 0x8CF2, 0x8CF5, 0x8CF7, 0x8CF8, 0x8CFE, 0x8CFF, 0x8D01, 0x8D03, 0x8D09, 0x8D12, 0x8D17, 0x8D1B, 0x8D65, 0x8D69, 0x8D6C, 0x8D6E, 0x8D7F, 0x8D82, 0x8D84, 0x8D88, 0x8D8D, 0x8D90, 0x8D91, 0x8D95, 0x8D9E, 0x8D9F, 0x8DA0, 0x8DA6, 0x8DAB, 0x8DAC, 0x8DAF, 0x8DB2, 0x8DB5, 0x8DB7, 0x8DB9, 0x8DBB, 0x8DC0, 0x8DC5, 0x8DC6, 0x8DC7, 0x8DC8, 0x8DCA, 0x8DCE, 0x8DD1, 0x8DD4, 0x8DD5, 0x8DD7, 0x8DD9, 0x8DE4, 0x8DE5, 0x8DE7, 0x8DEC, 0x8DF0, 0x8DBC, 0x8DF1, 0x8DF2, 0x8DF4, 0x8DFD, 0x8E01, 0x8E04, 0x8E05, 0x8E06, 0x8E0B, 0x8E11, 0x8E14, 0x8E16, 0x8E20, 0x8E21, 0x8E22, }; const unsigned short euc_to_utf8_8FE0[] = { 0x8E23, 0x8E26, 0x8E27, 0x8E31, 0x8E33, 0x8E36, 0x8E37, 0x8E38, 0x8E39, 0x8E3D, 0x8E40, 0x8E41, 0x8E4B, 0x8E4D, 0x8E4E, 0x8E4F, 0x8E54, 0x8E5B, 0x8E5C, 0x8E5D, 0x8E5E, 0x8E61, 0x8E62, 0x8E69, 0x8E6C, 0x8E6D, 0x8E6F, 0x8E70, 0x8E71, 0x8E79, 0x8E7A, 0x8E7B, 0x8E82, 0x8E83, 0x8E89, 0x8E90, 0x8E92, 0x8E95, 0x8E9A, 0x8E9B, 0x8E9D, 0x8E9E, 0x8EA2, 0x8EA7, 0x8EA9, 0x8EAD, 0x8EAE, 0x8EB3, 0x8EB5, 0x8EBA, 0x8EBB, 0x8EC0, 0x8EC1, 0x8EC3, 0x8EC4, 0x8EC7, 0x8ECF, 0x8ED1, 0x8ED4, 0x8EDC, 0x8EE8, 0x8EEE, 0x8EF0, 0x8EF1, 0x8EF7, 0x8EF9, 0x8EFA, 0x8EED, 0x8F00, 0x8F02, 0x8F07, 0x8F08, 0x8F0F, 0x8F10, 0x8F16, 0x8F17, 0x8F18, 0x8F1E, 0x8F20, 0x8F21, 0x8F23, 0x8F25, 0x8F27, 0x8F28, 0x8F2C, 0x8F2D, 0x8F2E, 0x8F34, 0x8F35, 0x8F36, 0x8F37, 0x8F3A, 0x8F40, 0x8F41, }; const unsigned short euc_to_utf8_8FE1[] = { 0x8F43, 0x8F47, 0x8F4F, 0x8F51, 0x8F52, 0x8F53, 0x8F54, 0x8F55, 0x8F58, 0x8F5D, 0x8F5E, 0x8F65, 0x8F9D, 0x8FA0, 0x8FA1, 0x8FA4, 0x8FA5, 0x8FA6, 0x8FB5, 0x8FB6, 0x8FB8, 0x8FBE, 0x8FC0, 0x8FC1, 0x8FC6, 0x8FCA, 0x8FCB, 0x8FCD, 0x8FD0, 0x8FD2, 0x8FD3, 0x8FD5, 0x8FE0, 0x8FE3, 0x8FE4, 0x8FE8, 0x8FEE, 0x8FF1, 0x8FF5, 0x8FF6, 0x8FFB, 0x8FFE, 0x9002, 0x9004, 0x9008, 0x900C, 0x9018, 0x901B, 0x9028, 0x9029, 0x902F, 0x902A, 0x902C, 0x902D, 0x9033, 0x9034, 0x9037, 0x903F, 0x9043, 0x9044, 0x904C, 0x905B, 0x905D, 0x9062, 0x9066, 0x9067, 0x906C, 0x9070, 0x9074, 0x9079, 0x9085, 0x9088, 0x908B, 0x908C, 0x908E, 0x9090, 0x9095, 0x9097, 0x9098, 0x9099, 0x909B, 0x90A0, 0x90A1, 0x90A2, 0x90A5, 0x90B0, 0x90B2, 0x90B3, 0x90B4, 0x90B6, 0x90BD, 0x90CC, 0x90BE, 0x90C3, }; const unsigned short euc_to_utf8_8FE2[] = { 0x90C4, 0x90C5, 0x90C7, 0x90C8, 0x90D5, 0x90D7, 0x90D8, 0x90D9, 0x90DC, 0x90DD, 0x90DF, 0x90E5, 0x90D2, 0x90F6, 0x90EB, 0x90EF, 0x90F0, 0x90F4, 0x90FE, 0x90FF, 0x9100, 0x9104, 0x9105, 0x9106, 0x9108, 0x910D, 0x9110, 0x9114, 0x9116, 0x9117, 0x9118, 0x911A, 0x911C, 0x911E, 0x9120, 0x9125, 0x9122, 0x9123, 0x9127, 0x9129, 0x912E, 0x912F, 0x9131, 0x9134, 0x9136, 0x9137, 0x9139, 0x913A, 0x913C, 0x913D, 0x9143, 0x9147, 0x9148, 0x914F, 0x9153, 0x9157, 0x9159, 0x915A, 0x915B, 0x9161, 0x9164, 0x9167, 0x916D, 0x9174, 0x9179, 0x917A, 0x917B, 0x9181, 0x9183, 0x9185, 0x9186, 0x918A, 0x918E, 0x9191, 0x9193, 0x9194, 0x9195, 0x9198, 0x919E, 0x91A1, 0x91A6, 0x91A8, 0x91AC, 0x91AD, 0x91AE, 0x91B0, 0x91B1, 0x91B2, 0x91B3, 0x91B6, 0x91BB, 0x91BC, 0x91BD, 0x91BF, }; const unsigned short euc_to_utf8_8FE3[] = { 0x91C2, 0x91C3, 0x91C5, 0x91D3, 0x91D4, 0x91D7, 0x91D9, 0x91DA, 0x91DE, 0x91E4, 0x91E5, 0x91E9, 0x91EA, 0x91EC, 0x91ED, 0x91EE, 0x91EF, 0x91F0, 0x91F1, 0x91F7, 0x91F9, 0x91FB, 0x91FD, 0x9200, 0x9201, 0x9204, 0x9205, 0x9206, 0x9207, 0x9209, 0x920A, 0x920C, 0x9210, 0x9212, 0x9213, 0x9216, 0x9218, 0x921C, 0x921D, 0x9223, 0x9224, 0x9225, 0x9226, 0x9228, 0x922E, 0x922F, 0x9230, 0x9233, 0x9235, 0x9236, 0x9238, 0x9239, 0x923A, 0x923C, 0x923E, 0x9240, 0x9242, 0x9243, 0x9246, 0x9247, 0x924A, 0x924D, 0x924E, 0x924F, 0x9251, 0x9258, 0x9259, 0x925C, 0x925D, 0x9260, 0x9261, 0x9265, 0x9267, 0x9268, 0x9269, 0x926E, 0x926F, 0x9270, 0x9275, 0x9276, 0x9277, 0x9278, 0x9279, 0x927B, 0x927C, 0x927D, 0x927F, 0x9288, 0x9289, 0x928A, 0x928D, 0x928E, 0x9292, 0x9297, }; const unsigned short euc_to_utf8_8FE4[] = { 0x9299, 0x929F, 0x92A0, 0x92A4, 0x92A5, 0x92A7, 0x92A8, 0x92AB, 0x92AF, 0x92B2, 0x92B6, 0x92B8, 0x92BA, 0x92BB, 0x92BC, 0x92BD, 0x92BF, 0x92C0, 0x92C1, 0x92C2, 0x92C3, 0x92C5, 0x92C6, 0x92C7, 0x92C8, 0x92CB, 0x92CC, 0x92CD, 0x92CE, 0x92D0, 0x92D3, 0x92D5, 0x92D7, 0x92D8, 0x92D9, 0x92DC, 0x92DD, 0x92DF, 0x92E0, 0x92E1, 0x92E3, 0x92E5, 0x92E7, 0x92E8, 0x92EC, 0x92EE, 0x92F0, 0x92F9, 0x92FB, 0x92FF, 0x9300, 0x9302, 0x9308, 0x930D, 0x9311, 0x9314, 0x9315, 0x931C, 0x931D, 0x931E, 0x931F, 0x9321, 0x9324, 0x9325, 0x9327, 0x9329, 0x932A, 0x9333, 0x9334, 0x9336, 0x9337, 0x9347, 0x9348, 0x9349, 0x9350, 0x9351, 0x9352, 0x9355, 0x9357, 0x9358, 0x935A, 0x935E, 0x9364, 0x9365, 0x9367, 0x9369, 0x936A, 0x936D, 0x936F, 0x9370, 0x9371, 0x9373, 0x9374, 0x9376, }; const unsigned short euc_to_utf8_8FE5[] = { 0x937A, 0x937D, 0x937F, 0x9380, 0x9381, 0x9382, 0x9388, 0x938A, 0x938B, 0x938D, 0x938F, 0x9392, 0x9395, 0x9398, 0x939B, 0x939E, 0x93A1, 0x93A3, 0x93A4, 0x93A6, 0x93A8, 0x93AB, 0x93B4, 0x93B5, 0x93B6, 0x93BA, 0x93A9, 0x93C1, 0x93C4, 0x93C5, 0x93C6, 0x93C7, 0x93C9, 0x93CA, 0x93CB, 0x93CC, 0x93CD, 0x93D3, 0x93D9, 0x93DC, 0x93DE, 0x93DF, 0x93E2, 0x93E6, 0x93E7, 0x93F9, 0x93F7, 0x93F8, 0x93FA, 0x93FB, 0x93FD, 0x9401, 0x9402, 0x9404, 0x9408, 0x9409, 0x940D, 0x940E, 0x940F, 0x9415, 0x9416, 0x9417, 0x941F, 0x942E, 0x942F, 0x9431, 0x9432, 0x9433, 0x9434, 0x943B, 0x943F, 0x943D, 0x9443, 0x9445, 0x9448, 0x944A, 0x944C, 0x9455, 0x9459, 0x945C, 0x945F, 0x9461, 0x9463, 0x9468, 0x946B, 0x946D, 0x946E, 0x946F, 0x9471, 0x9472, 0x9484, 0x9483, 0x9578, 0x9579, }; const unsigned short euc_to_utf8_8FE6[] = { 0x957E, 0x9584, 0x9588, 0x958C, 0x958D, 0x958E, 0x959D, 0x959E, 0x959F, 0x95A1, 0x95A6, 0x95A9, 0x95AB, 0x95AC, 0x95B4, 0x95B6, 0x95BA, 0x95BD, 0x95BF, 0x95C6, 0x95C8, 0x95C9, 0x95CB, 0x95D0, 0x95D1, 0x95D2, 0x95D3, 0x95D9, 0x95DA, 0x95DD, 0x95DE, 0x95DF, 0x95E0, 0x95E4, 0x95E6, 0x961D, 0x961E, 0x9622, 0x9624, 0x9625, 0x9626, 0x962C, 0x9631, 0x9633, 0x9637, 0x9638, 0x9639, 0x963A, 0x963C, 0x963D, 0x9641, 0x9652, 0x9654, 0x9656, 0x9657, 0x9658, 0x9661, 0x966E, 0x9674, 0x967B, 0x967C, 0x967E, 0x967F, 0x9681, 0x9682, 0x9683, 0x9684, 0x9689, 0x9691, 0x9696, 0x969A, 0x969D, 0x969F, 0x96A4, 0x96A5, 0x96A6, 0x96A9, 0x96AE, 0x96AF, 0x96B3, 0x96BA, 0x96CA, 0x96D2, 0x5DB2, 0x96D8, 0x96DA, 0x96DD, 0x96DE, 0x96DF, 0x96E9, 0x96EF, 0x96F1, 0x96FA, 0x9702, }; const unsigned short euc_to_utf8_8FE7[] = { 0x9703, 0x9705, 0x9709, 0x971A, 0x971B, 0x971D, 0x9721, 0x9722, 0x9723, 0x9728, 0x9731, 0x9733, 0x9741, 0x9743, 0x974A, 0x974E, 0x974F, 0x9755, 0x9757, 0x9758, 0x975A, 0x975B, 0x9763, 0x9767, 0x976A, 0x976E, 0x9773, 0x9776, 0x9777, 0x9778, 0x977B, 0x977D, 0x977F, 0x9780, 0x9789, 0x9795, 0x9796, 0x9797, 0x9799, 0x979A, 0x979E, 0x979F, 0x97A2, 0x97AC, 0x97AE, 0x97B1, 0x97B2, 0x97B5, 0x97B6, 0x97B8, 0x97B9, 0x97BA, 0x97BC, 0x97BE, 0x97BF, 0x97C1, 0x97C4, 0x97C5, 0x97C7, 0x97C9, 0x97CA, 0x97CC, 0x97CD, 0x97CE, 0x97D0, 0x97D1, 0x97D4, 0x97D7, 0x97D8, 0x97D9, 0x97DD, 0x97DE, 0x97E0, 0x97DB, 0x97E1, 0x97E4, 0x97EF, 0x97F1, 0x97F4, 0x97F7, 0x97F8, 0x97FA, 0x9807, 0x980A, 0x9819, 0x980D, 0x980E, 0x9814, 0x9816, 0x981C, 0x981E, 0x9820, 0x9823, 0x9826, }; const unsigned short euc_to_utf8_8FE8[] = { 0x982B, 0x982E, 0x982F, 0x9830, 0x9832, 0x9833, 0x9835, 0x9825, 0x983E, 0x9844, 0x9847, 0x984A, 0x9851, 0x9852, 0x9853, 0x9856, 0x9857, 0x9859, 0x985A, 0x9862, 0x9863, 0x9865, 0x9866, 0x986A, 0x986C, 0x98AB, 0x98AD, 0x98AE, 0x98B0, 0x98B4, 0x98B7, 0x98B8, 0x98BA, 0x98BB, 0x98BF, 0x98C2, 0x98C5, 0x98C8, 0x98CC, 0x98E1, 0x98E3, 0x98E5, 0x98E6, 0x98E7, 0x98EA, 0x98F3, 0x98F6, 0x9902, 0x9907, 0x9908, 0x9911, 0x9915, 0x9916, 0x9917, 0x991A, 0x991B, 0x991C, 0x991F, 0x9922, 0x9926, 0x9927, 0x992B, 0x9931, 0x9932, 0x9933, 0x9934, 0x9935, 0x9939, 0x993A, 0x993B, 0x993C, 0x9940, 0x9941, 0x9946, 0x9947, 0x9948, 0x994D, 0x994E, 0x9954, 0x9958, 0x9959, 0x995B, 0x995C, 0x995E, 0x995F, 0x9960, 0x999B, 0x999D, 0x999F, 0x99A6, 0x99B0, 0x99B1, 0x99B2, 0x99B5, }; const unsigned short euc_to_utf8_8FE9[] = { 0x99B9, 0x99BA, 0x99BD, 0x99BF, 0x99C3, 0x99C9, 0x99D3, 0x99D4, 0x99D9, 0x99DA, 0x99DC, 0x99DE, 0x99E7, 0x99EA, 0x99EB, 0x99EC, 0x99F0, 0x99F4, 0x99F5, 0x99F9, 0x99FD, 0x99FE, 0x9A02, 0x9A03, 0x9A04, 0x9A0B, 0x9A0C, 0x9A10, 0x9A11, 0x9A16, 0x9A1E, 0x9A20, 0x9A22, 0x9A23, 0x9A24, 0x9A27, 0x9A2D, 0x9A2E, 0x9A33, 0x9A35, 0x9A36, 0x9A38, 0x9A47, 0x9A41, 0x9A44, 0x9A4A, 0x9A4B, 0x9A4C, 0x9A4E, 0x9A51, 0x9A54, 0x9A56, 0x9A5D, 0x9AAA, 0x9AAC, 0x9AAE, 0x9AAF, 0x9AB2, 0x9AB4, 0x9AB5, 0x9AB6, 0x9AB9, 0x9ABB, 0x9ABE, 0x9ABF, 0x9AC1, 0x9AC3, 0x9AC6, 0x9AC8, 0x9ACE, 0x9AD0, 0x9AD2, 0x9AD5, 0x9AD6, 0x9AD7, 0x9ADB, 0x9ADC, 0x9AE0, 0x9AE4, 0x9AE5, 0x9AE7, 0x9AE9, 0x9AEC, 0x9AF2, 0x9AF3, 0x9AF5, 0x9AF9, 0x9AFA, 0x9AFD, 0x9AFF, 0x9B00, 0x9B01, 0x9B02, 0x9B03, }; const unsigned short euc_to_utf8_8FEA[] = { 0x9B04, 0x9B05, 0x9B08, 0x9B09, 0x9B0B, 0x9B0C, 0x9B0D, 0x9B0E, 0x9B10, 0x9B12, 0x9B16, 0x9B19, 0x9B1B, 0x9B1C, 0x9B20, 0x9B26, 0x9B2B, 0x9B2D, 0x9B33, 0x9B34, 0x9B35, 0x9B37, 0x9B39, 0x9B3A, 0x9B3D, 0x9B48, 0x9B4B, 0x9B4C, 0x9B55, 0x9B56, 0x9B57, 0x9B5B, 0x9B5E, 0x9B61, 0x9B63, 0x9B65, 0x9B66, 0x9B68, 0x9B6A, 0x9B6B, 0x9B6C, 0x9B6D, 0x9B6E, 0x9B73, 0x9B75, 0x9B77, 0x9B78, 0x9B79, 0x9B7F, 0x9B80, 0x9B84, 0x9B85, 0x9B86, 0x9B87, 0x9B89, 0x9B8A, 0x9B8B, 0x9B8D, 0x9B8F, 0x9B90, 0x9B94, 0x9B9A, 0x9B9D, 0x9B9E, 0x9BA6, 0x9BA7, 0x9BA9, 0x9BAC, 0x9BB0, 0x9BB1, 0x9BB2, 0x9BB7, 0x9BB8, 0x9BBB, 0x9BBC, 0x9BBE, 0x9BBF, 0x9BC1, 0x9BC7, 0x9BC8, 0x9BCE, 0x9BD0, 0x9BD7, 0x9BD8, 0x9BDD, 0x9BDF, 0x9BE5, 0x9BE7, 0x9BEA, 0x9BEB, 0x9BEF, 0x9BF3, 0x9BF7, 0x9BF8, }; const unsigned short euc_to_utf8_8FEB[] = { 0x9BF9, 0x9BFA, 0x9BFD, 0x9BFF, 0x9C00, 0x9C02, 0x9C0B, 0x9C0F, 0x9C11, 0x9C16, 0x9C18, 0x9C19, 0x9C1A, 0x9C1C, 0x9C1E, 0x9C22, 0x9C23, 0x9C26, 0x9C27, 0x9C28, 0x9C29, 0x9C2A, 0x9C31, 0x9C35, 0x9C36, 0x9C37, 0x9C3D, 0x9C41, 0x9C43, 0x9C44, 0x9C45, 0x9C49, 0x9C4A, 0x9C4E, 0x9C4F, 0x9C50, 0x9C53, 0x9C54, 0x9C56, 0x9C58, 0x9C5B, 0x9C5D, 0x9C5E, 0x9C5F, 0x9C63, 0x9C69, 0x9C6A, 0x9C5C, 0x9C6B, 0x9C68, 0x9C6E, 0x9C70, 0x9C72, 0x9C75, 0x9C77, 0x9C7B, 0x9CE6, 0x9CF2, 0x9CF7, 0x9CF9, 0x9D0B, 0x9D02, 0x9D11, 0x9D17, 0x9D18, 0x9D1C, 0x9D1D, 0x9D1E, 0x9D2F, 0x9D30, 0x9D32, 0x9D33, 0x9D34, 0x9D3A, 0x9D3C, 0x9D45, 0x9D3D, 0x9D42, 0x9D43, 0x9D47, 0x9D4A, 0x9D53, 0x9D54, 0x9D5F, 0x9D63, 0x9D62, 0x9D65, 0x9D69, 0x9D6A, 0x9D6B, 0x9D70, 0x9D76, 0x9D77, 0x9D7B, }; const unsigned short euc_to_utf8_8FEC[] = { 0x9D7C, 0x9D7E, 0x9D83, 0x9D84, 0x9D86, 0x9D8A, 0x9D8D, 0x9D8E, 0x9D92, 0x9D93, 0x9D95, 0x9D96, 0x9D97, 0x9D98, 0x9DA1, 0x9DAA, 0x9DAC, 0x9DAE, 0x9DB1, 0x9DB5, 0x9DB9, 0x9DBC, 0x9DBF, 0x9DC3, 0x9DC7, 0x9DC9, 0x9DCA, 0x9DD4, 0x9DD5, 0x9DD6, 0x9DD7, 0x9DDA, 0x9DDE, 0x9DDF, 0x9DE0, 0x9DE5, 0x9DE7, 0x9DE9, 0x9DEB, 0x9DEE, 0x9DF0, 0x9DF3, 0x9DF4, 0x9DFE, 0x9E0A, 0x9E02, 0x9E07, 0x9E0E, 0x9E10, 0x9E11, 0x9E12, 0x9E15, 0x9E16, 0x9E19, 0x9E1C, 0x9E1D, 0x9E7A, 0x9E7B, 0x9E7C, 0x9E80, 0x9E82, 0x9E83, 0x9E84, 0x9E85, 0x9E87, 0x9E8E, 0x9E8F, 0x9E96, 0x9E98, 0x9E9B, 0x9E9E, 0x9EA4, 0x9EA8, 0x9EAC, 0x9EAE, 0x9EAF, 0x9EB0, 0x9EB3, 0x9EB4, 0x9EB5, 0x9EC6, 0x9EC8, 0x9ECB, 0x9ED5, 0x9EDF, 0x9EE4, 0x9EE7, 0x9EEC, 0x9EED, 0x9EEE, 0x9EF0, 0x9EF1, 0x9EF2, 0x9EF5, }; const unsigned short euc_to_utf8_8FED[] = { 0x9EF8, 0x9EFF, 0x9F02, 0x9F03, 0x9F09, 0x9F0F, 0x9F10, 0x9F11, 0x9F12, 0x9F14, 0x9F16, 0x9F17, 0x9F19, 0x9F1A, 0x9F1B, 0x9F1F, 0x9F22, 0x9F26, 0x9F2A, 0x9F2B, 0x9F2F, 0x9F31, 0x9F32, 0x9F34, 0x9F37, 0x9F39, 0x9F3A, 0x9F3C, 0x9F3D, 0x9F3F, 0x9F41, 0x9F43, 0x9F44, 0x9F45, 0x9F46, 0x9F47, 0x9F53, 0x9F55, 0x9F56, 0x9F57, 0x9F58, 0x9F5A, 0x9F5D, 0x9F5E, 0x9F68, 0x9F69, 0x9F6D, 0x9F6E, 0x9F6F, 0x9F70, 0x9F71, 0x9F73, 0x9F75, 0x9F7A, 0x9F7D, 0x9F8F, 0x9F90, 0x9F91, 0x9F92, 0x9F94, 0x9F96, 0x9F97, 0x9F9E, 0x9FA1, 0x9FA2, 0x9FA3, 0x9FA5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short euc_to_utf8_8FF3[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x2160, 0x2161, }; const unsigned short euc_to_utf8_8FF4[] = { 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0xff07, 0xff02, 0x3231, 0x2116, 0x2121, 0x70bb, 0x4efc, 0x50f4, 0x51ec, 0x5307, 0x5324, 0xfa0e, 0x548a, 0x5759, 0xfa0f, 0xfa10, 0x589e, 0x5bec, 0x5cf5, 0x5d53, 0xfa11, 0x5fb7, 0x6085, 0x6120, 0x654e, 0x663b, 0x6665, 0xfa12, 0xf929, 0x6801, 0xfa13, 0xfa14, 0x6a6b, 0x6ae2, 0x6df8, 0x6df2, 0x7028, 0xfa15, 0xfa16, 0x7501, 0x7682, 0x769e, 0xfa17, 0x7930, 0xfa18, 0xfa19, 0xfa1a, 0xfa1b, 0x7ae7, 0xfa1c, 0xfa1d, 0x7da0, 0x7dd6, 0xfa1e, 0x8362, 0xfa1f, 0x85b0, 0xfa20, 0xfa21, 0x8807, 0xfa22, 0x8b7f, 0x8cf4, 0x8d76, 0xfa23, 0xfa24, 0xfa25, 0x90de, 0xfa26, 0x9115, 0xfa27, 0xfa28, 0x9592, 0xf9dc, 0xfa29, 0x973b, 0x974d, 0x9751, 0xfa2a, 0xfa2b, 0xfa2c, 0x999e, 0x9ad9, 0x9b72, 0xfa2d, 0x9ed1, }; #endif /* X0212_ENABLE */ const unsigned short euc_to_utf8_1byte[] = { 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67, 0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F, 0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77, 0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F, 0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, 0xFF86, 0xFF87, 0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F, 0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97, 0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0xFF9F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00A9, 0x2122, }; const unsigned short *const euc_to_utf8_2bytes[] = { euc_to_utf8_A1, euc_to_utf8_A2, euc_to_utf8_A3, euc_to_utf8_A4, euc_to_utf8_A5, euc_to_utf8_A6, euc_to_utf8_A7, euc_to_utf8_A8, euc_to_utf8_A9, euc_to_utf8_AA, euc_to_utf8_AB, euc_to_utf8_AC, euc_to_utf8_AD, euc_to_utf8_AE, euc_to_utf8_AF, euc_to_utf8_B0, euc_to_utf8_B1, euc_to_utf8_B2, euc_to_utf8_B3, euc_to_utf8_B4, euc_to_utf8_B5, euc_to_utf8_B6, euc_to_utf8_B7, euc_to_utf8_B8, euc_to_utf8_B9, euc_to_utf8_BA, euc_to_utf8_BB, euc_to_utf8_BC, euc_to_utf8_BD, euc_to_utf8_BE, euc_to_utf8_BF, euc_to_utf8_C0, euc_to_utf8_C1, euc_to_utf8_C2, euc_to_utf8_C3, euc_to_utf8_C4, euc_to_utf8_C5, euc_to_utf8_C6, euc_to_utf8_C7, euc_to_utf8_C8, euc_to_utf8_C9, euc_to_utf8_CA, euc_to_utf8_CB, euc_to_utf8_CC, euc_to_utf8_CD, euc_to_utf8_CE, euc_to_utf8_CF, euc_to_utf8_D0, euc_to_utf8_D1, euc_to_utf8_D2, euc_to_utf8_D3, euc_to_utf8_D4, euc_to_utf8_D5, euc_to_utf8_D6, euc_to_utf8_D7, euc_to_utf8_D8, euc_to_utf8_D9, euc_to_utf8_DA, euc_to_utf8_DB, euc_to_utf8_DC, euc_to_utf8_DD, euc_to_utf8_DE, euc_to_utf8_DF, euc_to_utf8_E0, euc_to_utf8_E1, euc_to_utf8_E2, euc_to_utf8_E3, euc_to_utf8_E4, euc_to_utf8_E5, euc_to_utf8_E6, euc_to_utf8_E7, euc_to_utf8_E8, euc_to_utf8_E9, euc_to_utf8_EA, euc_to_utf8_EB, euc_to_utf8_EC, euc_to_utf8_ED, euc_to_utf8_EE, euc_to_utf8_EF, euc_to_utf8_F0, euc_to_utf8_F1, euc_to_utf8_F2, euc_to_utf8_F3, euc_to_utf8_F4, euc_to_utf8_F5, 0, 0, 0, euc_to_utf8_F9, euc_to_utf8_FA, euc_to_utf8_FB, euc_to_utf8_FC, 0, 0, }; /* Microsoft UCS Mapping Compatible */ const unsigned short *const euc_to_utf8_2bytes_ms[] = { euc_to_utf8_A1_ms, euc_to_utf8_A2_ms, euc_to_utf8_A3, euc_to_utf8_A4, euc_to_utf8_A5, euc_to_utf8_A6, euc_to_utf8_A7, euc_to_utf8_A8, euc_to_utf8_A9, euc_to_utf8_AA, euc_to_utf8_AB, euc_to_utf8_AC, euc_to_utf8_AD, euc_to_utf8_AE, euc_to_utf8_AF, euc_to_utf8_B0, euc_to_utf8_B1, euc_to_utf8_B2, euc_to_utf8_B3, euc_to_utf8_B4, euc_to_utf8_B5, euc_to_utf8_B6, euc_to_utf8_B7, euc_to_utf8_B8, euc_to_utf8_B9, euc_to_utf8_BA, euc_to_utf8_BB, euc_to_utf8_BC, euc_to_utf8_BD, euc_to_utf8_BE, euc_to_utf8_BF, euc_to_utf8_C0, euc_to_utf8_C1, euc_to_utf8_C2, euc_to_utf8_C3, euc_to_utf8_C4, euc_to_utf8_C5, euc_to_utf8_C6, euc_to_utf8_C7, euc_to_utf8_C8, euc_to_utf8_C9, euc_to_utf8_CA, euc_to_utf8_CB, euc_to_utf8_CC, euc_to_utf8_CD, euc_to_utf8_CE, euc_to_utf8_CF, euc_to_utf8_D0, euc_to_utf8_D1, euc_to_utf8_D2, euc_to_utf8_D3, euc_to_utf8_D4, euc_to_utf8_D5, euc_to_utf8_D6, euc_to_utf8_D7, euc_to_utf8_D8, euc_to_utf8_D9, euc_to_utf8_DA, euc_to_utf8_DB, euc_to_utf8_DC, euc_to_utf8_DD, euc_to_utf8_DE, euc_to_utf8_DF, euc_to_utf8_E0, euc_to_utf8_E1, euc_to_utf8_E2, euc_to_utf8_E3, euc_to_utf8_E4, euc_to_utf8_E5, euc_to_utf8_E6, euc_to_utf8_E7, euc_to_utf8_E8, euc_to_utf8_E9, euc_to_utf8_EA, euc_to_utf8_EB, euc_to_utf8_EC, euc_to_utf8_ED, euc_to_utf8_EE, euc_to_utf8_EF, euc_to_utf8_F0, euc_to_utf8_F1, euc_to_utf8_F2, euc_to_utf8_F3, euc_to_utf8_F4, euc_to_utf8_F5, 0, 0, 0, euc_to_utf8_F9, euc_to_utf8_FA, euc_to_utf8_FB, euc_to_utf8_FC_ms, 0, 0, }; #ifdef X0212_ENABLE const unsigned short *const x0212_to_utf8_2bytes[] = { 0, euc_to_utf8_8FA2, 0, 0, 0, euc_to_utf8_8FA6, euc_to_utf8_8FA7, 0, euc_to_utf8_8FA9, euc_to_utf8_8FAA, euc_to_utf8_8FAB, 0, 0, 0, 0, euc_to_utf8_8FB0, euc_to_utf8_8FB1, euc_to_utf8_8FB2, euc_to_utf8_8FB3, euc_to_utf8_8FB4, euc_to_utf8_8FB5, euc_to_utf8_8FB6, euc_to_utf8_8FB7, euc_to_utf8_8FB8, euc_to_utf8_8FB9, euc_to_utf8_8FBA, euc_to_utf8_8FBB, euc_to_utf8_8FBC, euc_to_utf8_8FBD, euc_to_utf8_8FBE, euc_to_utf8_8FBF, euc_to_utf8_8FC0, euc_to_utf8_8FC1, euc_to_utf8_8FC2, euc_to_utf8_8FC3, euc_to_utf8_8FC4, euc_to_utf8_8FC5, euc_to_utf8_8FC6, euc_to_utf8_8FC7, euc_to_utf8_8FC8, euc_to_utf8_8FC9, euc_to_utf8_8FCA, euc_to_utf8_8FCB, euc_to_utf8_8FCC, euc_to_utf8_8FCD, euc_to_utf8_8FCE, euc_to_utf8_8FCF, euc_to_utf8_8FD0, euc_to_utf8_8FD1, euc_to_utf8_8FD2, euc_to_utf8_8FD3, euc_to_utf8_8FD4, euc_to_utf8_8FD5, euc_to_utf8_8FD6, euc_to_utf8_8FD7, euc_to_utf8_8FD8, euc_to_utf8_8FD9, euc_to_utf8_8FDA, euc_to_utf8_8FDB, euc_to_utf8_8FDC, euc_to_utf8_8FDD, euc_to_utf8_8FDE, euc_to_utf8_8FDF, euc_to_utf8_8FE0, euc_to_utf8_8FE1, euc_to_utf8_8FE2, euc_to_utf8_8FE3, euc_to_utf8_8FE4, euc_to_utf8_8FE5, euc_to_utf8_8FE6, euc_to_utf8_8FE7, euc_to_utf8_8FE8, euc_to_utf8_8FE9, euc_to_utf8_8FEA, euc_to_utf8_8FEB, euc_to_utf8_8FEC, euc_to_utf8_8FED, 0, 0, 0, 0, 0, euc_to_utf8_8FF3, euc_to_utf8_8FF4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; #endif /* X0212_ENABLE */ #endif /* UTF8_OUTPUT_ENABLE */ #ifdef UTF8_INPUT_ENABLE const unsigned short utf8_to_euc_C2[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xA242, 0x2171, 0x2172, 0xA270, 0x216F, 0xA243, 0x2178, 0x212F, 0xA26D, 0xA26C, 0, 0x224C, 0, 0xA26E, 0xA234, 0x216B, 0x215E, 0, 0, 0x212D, 0, 0x2279, 0, 0xA231, 0, 0xA26B, 0, 0, 0, 0, 0xA244, }; const unsigned short utf8_to_euc_C2_ms[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xA242, 0x2171, 0x2172, 0xA270, 0x5C, 0xA243, 0x2178, 0x212F, 0xA26D, 0xA26C, 0, 0x224C, 0, 0xA26E, 0xA234, 0x216B, 0x215E, 0, 0, 0x212D, 0, 0x2279, 0, 0xA231, 0, 0xA26B, 0, 0, 0, 0, 0xA244, }; const unsigned short utf8_to_euc_C2_932[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x21, 0x2171, 0x2172, 0, 0x5C, 0x7C, 0x2178, 0x212F, 0x63, 0x61, 0x2263, 0x224C, 0x2D, 0x52, 0x2131, 0x216B, 0x215E, 0x32, 0x33, 0x212D, 0x264C, 0x2279, 0x2126, 0x2124, 0x31, 0x6F, 0x2264, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_C3[] = { 0xAA22, 0xAA21, 0xAA24, 0xAA2A, 0xAA23, 0xAA29, 0xA921, 0xAA2E, 0xAA32, 0xAA31, 0xAA34, 0xAA33, 0xAA40, 0xAA3F, 0xAA42, 0xAA41, 0, 0xAA50, 0xAA52, 0xAA51, 0xAA54, 0xAA58, 0xAA53, 0x215F, 0xA92C, 0xAA63, 0xAA62, 0xAA65, 0xAA64, 0xAA72, 0xA930, 0xA94E, 0xAB22, 0xAB21, 0xAB24, 0xAB2A, 0xAB23, 0xAB29, 0xA941, 0xAB2E, 0xAB32, 0xAB31, 0xAB34, 0xAB33, 0xAB40, 0xAB3F, 0xAB42, 0xAB41, 0xA943, 0xAB50, 0xAB52, 0xAB51, 0xAB54, 0xAB58, 0xAB53, 0x2160, 0xA94C, 0xAB63, 0xAB62, 0xAB65, 0xAB64, 0xAB72, 0xA950, 0xAB73, }; const unsigned short utf8_to_euc_C3_932[] = { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x215F, 0x4F, 0x55, 0x55, 0x55, 0x55, 0x59, 0x54, 0x73, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x63, 0x65, 0x65, 0x65, 0x65, 0x69, 0x69, 0x69, 0x69, 0x64, 0x6E, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x2160, 0x6F, 0x75, 0x75, 0x75, 0x75, 0x79, 0x74, 0x79, }; const unsigned short utf8_to_euc_C4[] = { 0xAA27, 0xAB27, 0xAA25, 0xAB25, 0xAA28, 0xAB28, 0xAA2B, 0xAB2B, 0xAA2C, 0xAB2C, 0xAA2F, 0xAB2F, 0xAA2D, 0xAB2D, 0xAA30, 0xAB30, 0xA922, 0xA942, 0xAA37, 0xAB37, 0, 0, 0xAA36, 0xAB36, 0xAA38, 0xAB38, 0xAA35, 0xAB35, 0xAA3A, 0xAB3A, 0xAA3B, 0xAB3B, 0xAA3D, 0xAB3D, 0xAA3C, 0, 0xAA3E, 0xAB3E, 0xA924, 0xA944, 0xAA47, 0xAB47, 0xAA45, 0xAB45, 0, 0, 0xAA46, 0xAB46, 0xAA44, 0xA945, 0xA926, 0xA946, 0xAA48, 0xAB48, 0xAA49, 0xAB49, 0xA947, 0xAA4A, 0xAB4A, 0xAA4C, 0xAB4C, 0xAA4B, 0xAB4B, 0xA929, }; const unsigned short utf8_to_euc_C5[] = { 0xA949, 0xA928, 0xA948, 0xAA4D, 0xAB4D, 0xAA4F, 0xAB4F, 0xAA4E, 0xAB4E, 0xA94A, 0xA92B, 0xA94B, 0xAA57, 0xAB57, 0, 0, 0xAA56, 0xAB56, 0xA92D, 0xA94D, 0xAA59, 0xAB59, 0xAA5B, 0xAB5B, 0xAA5A, 0xAB5A, 0xAA5C, 0xAB5C, 0xAA5D, 0xAB5D, 0xAA5F, 0xAB5F, 0xAA5E, 0xAB5E, 0xAA61, 0xAB61, 0xAA60, 0xAB60, 0xA92F, 0xA94F, 0xAA6C, 0xAB6C, 0xAA69, 0xAB69, 0xAA66, 0xAB66, 0xAA6B, 0xAB6B, 0xAA68, 0xAB68, 0xAA6A, 0xAB6A, 0xAA71, 0xAB71, 0xAA74, 0xAB74, 0xAA73, 0xAA75, 0xAB75, 0xAA77, 0xAB77, 0xAA76, 0xAB76, 0, }; const unsigned short utf8_to_euc_C7[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xAA26, 0xAB26, 0xAA43, 0xAB43, 0xAA55, 0xAB55, 0xAA67, 0xAB67, 0xAA70, 0xAB70, 0xAA6D, 0xAB6D, 0xAA6F, 0xAB6F, 0xAA6E, 0xAB6E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xAB39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_CB[] = { 0, 0, 0, 0, 0, 0, 0, 0xA230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xA22F, 0xA232, 0xA236, 0xA235, 0, 0xA233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_CE[] = { 0, 0, 0, 0, 0xA238, 0xA239, 0xA661, 0, 0xA662, 0xA663, 0xA664, 0, 0xA667, 0, 0xA669, 0xA66C, 0xA676, 0x2621, 0x2622, 0x2623, 0x2624, 0x2625, 0x2626, 0x2627, 0x2628, 0x2629, 0x262A, 0x262B, 0x262C, 0x262D, 0x262E, 0x262F, 0x2630, 0x2631, 0, 0x2632, 0x2633, 0x2634, 0x2635, 0x2636, 0x2637, 0x2638, 0xA665, 0xA66A, 0xA671, 0xA672, 0xA673, 0xA674, 0xA67B, 0x2641, 0x2642, 0x2643, 0x2644, 0x2645, 0x2646, 0x2647, 0x2648, 0x2649, 0x264A, 0x264B, 0x264C, 0x264D, 0x264E, 0x264F, }; const unsigned short utf8_to_euc_CF[] = { 0x2650, 0x2651, 0xA678, 0x2652, 0x2653, 0x2654, 0x2655, 0x2656, 0x2657, 0x2658, 0xA675, 0xA67A, 0xA677, 0xA679, 0xA67C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_D0[] = { 0, 0x2727, 0xA742, 0xA743, 0xA744, 0xA745, 0xA746, 0xA747, 0xA748, 0xA749, 0xA74A, 0xA74B, 0xA74C, 0, 0xA74D, 0xA74E, 0x2721, 0x2722, 0x2723, 0x2724, 0x2725, 0x2726, 0x2728, 0x2729, 0x272A, 0x272B, 0x272C, 0x272D, 0x272E, 0x272F, 0x2730, 0x2731, 0x2732, 0x2733, 0x2734, 0x2735, 0x2736, 0x2737, 0x2738, 0x2739, 0x273A, 0x273B, 0x273C, 0x273D, 0x273E, 0x273F, 0x2740, 0x2741, 0x2751, 0x2752, 0x2753, 0x2754, 0x2755, 0x2756, 0x2758, 0x2759, 0x275A, 0x275B, 0x275C, 0x275D, 0x275E, 0x275F, 0x2760, 0x2761, }; const unsigned short utf8_to_euc_D1[] = { 0x2762, 0x2763, 0x2764, 0x2765, 0x2766, 0x2767, 0x2768, 0x2769, 0x276A, 0x276B, 0x276C, 0x276D, 0x276E, 0x276F, 0x2770, 0x2771, 0, 0x2757, 0xA772, 0xA773, 0xA774, 0xA775, 0xA776, 0xA777, 0xA778, 0xA779, 0xA77A, 0xA77B, 0xA77C, 0, 0xA77D, 0xA77E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E280[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x213E, 0, 0, 0, 0x213D, 0x213D, 0x2142, 0, 0x2146, 0x2147, 0, 0, 0x2148, 0x2149, 0, 0, 0x2277, 0x2278, 0, 0, 0, 0x2145, 0x2144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2273, 0, 0x216C, 0x216D, 0, 0, 0, 0, 0, 0, 0, 0x2228, 0, 0, 0x2131, 0, }; const unsigned short utf8_to_euc_E280_ms[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x213E, 0, 0, 0, 0x213D, 0x213D, 0x2142, 0, 0x2146, 0x2147, 0, 0, 0x2148, 0x2149, 0, 0, 0x2277, 0x2278, 0, 0, 0, 0x2145, 0x2144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2273, 0, 0x216C, 0x216D, 0, 0, 0, 0, 0, 0, 0, 0x2228, 0, 0, 0x7E, 0, }; const unsigned short utf8_to_euc_E280_932[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x213E, 0, 0, 0, 0, 0x213D, 0, 0, 0x2146, 0x2147, 0, 0, 0x2148, 0x2149, 0, 0, 0x2277, 0x2278, 0, 0, 0, 0x2145, 0x2144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2273, 0, 0x216C, 0x216D, 0, 0, 0, 0, 0, 0, 0, 0x2228, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E284[] = { 0, 0, 0, 0x216E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2D62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2D64, 0xA26F, 0, 0, 0, 0, 0, 0, 0, 0, 0x2272, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E285[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2D35, 0x2D36, 0x2D37, 0x2D38, 0x2D39, 0x2D3A, 0x2D3B, 0x2D3C, 0x2D3D, 0x2D3E, 0, 0, 0, 0, 0, 0, 0xF373, 0xF374, 0xF375, 0xF376, 0xF377, 0xF378, 0xF379, 0xF37A, 0xF37B, 0xF37C, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E286[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x222B, 0x222C, 0x222A, 0x222D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E287[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x224D, 0, 0x224E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E288[] = { 0x224F, 0, 0x225F, 0x2250, 0, 0, 0, 0x2260, 0x223A, 0, 0, 0x223B, 0, 0, 0, 0, 0, 0x2D74, 0x215D, 0, 0, 0, 0, 0, 0, 0, 0x2265, 0, 0, 0x2267, 0x2167, 0x2D78, 0x225C, 0, 0, 0, 0, 0x2142, 0, 0x224A, 0x224B, 0x2241, 0x2240, 0x2269, 0x226A, 0, 0x2D73, 0, 0, 0, 0, 0, 0x2168, 0x2268, 0, 0, 0, 0, 0, 0, 0, 0x2266, 0, 0, }; const unsigned short utf8_to_euc_E288_932[] = { 0x224F, 0, 0x225F, 0x2250, 0, 0, 0, 0x2260, 0x223A, 0, 0, 0x223B, 0, 0, 0, 0, 0, 0x2D74, 0, 0, 0, 0, 0, 0, 0, 0, 0x2265, 0, 0, 0x2267, 0x2167, 0x2D78, 0x225C, 0, 0, 0, 0, 0x2142, 0, 0x224A, 0x224B, 0x2241, 0x2240, 0x2269, 0x226A, 0, 0x2D73, 0, 0, 0, 0, 0, 0x2168, 0x2268, 0, 0, 0, 0, 0, 0, 0, 0x2266, 0, 0, }; const unsigned short utf8_to_euc_E289[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2262, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2162, 0x2261, 0, 0, 0, 0, 0x2165, 0x2166, 0, 0, 0x2263, 0x2264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E28A[] = { 0, 0, 0x223E, 0x223F, 0, 0, 0x223C, 0x223D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x225D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2D79, }; const unsigned short utf8_to_euc_E28C[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x225E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E291[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2D21, 0x2D22, 0x2D23, 0x2D24, 0x2D25, 0x2D26, 0x2D27, 0x2D28, 0x2D29, 0x2D2A, 0x2D2B, 0x2D2C, 0x2D2D, 0x2D2E, 0x2D2F, 0x2D30, 0x2D31, 0x2D32, 0x2D33, 0x2D34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E294[] = { 0x2821, 0x282C, 0x2822, 0x282D, 0, 0, 0, 0, 0, 0, 0, 0, 0x2823, 0, 0, 0x282E, 0x2824, 0, 0, 0x282F, 0x2826, 0, 0, 0x2831, 0x2825, 0, 0, 0x2830, 0x2827, 0x283C, 0, 0, 0x2837, 0, 0, 0x2832, 0x2829, 0x283E, 0, 0, 0x2839, 0, 0, 0x2834, 0x2828, 0, 0, 0x2838, 0x283D, 0, 0, 0x2833, 0x282A, 0, 0, 0x283A, 0x283F, 0, 0, 0x2835, 0x282B, 0, 0, 0x283B, }; const unsigned short utf8_to_euc_E295[] = { 0, 0, 0x2840, 0, 0, 0, 0, 0, 0, 0, 0, 0x2836, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E296[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2223, 0x2222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2225, 0x2224, 0, 0, 0, 0, 0, 0, 0, 0, 0x2227, 0x2226, 0, 0, }; const unsigned short utf8_to_euc_E297[] = { 0, 0, 0, 0, 0, 0, 0x2221, 0x217E, 0, 0, 0, 0x217B, 0, 0, 0x217D, 0x217C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x227E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E298[] = { 0, 0, 0, 0, 0, 0x217A, 0x2179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E299[] = { 0x216A, 0, 0x2169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2276, 0, 0, 0x2275, 0, 0x2274, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E380[] = { 0x2121, 0x2122, 0x2123, 0x2137, 0, 0x2139, 0x213A, 0x213B, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215A, 0x215B, 0x2229, 0x222E, 0x214C, 0x214D, 0, 0, 0, 0, 0, 0, 0x2141, 0x2D60, 0, 0x2D61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E380_932[] = { 0x2121, 0x2122, 0x2123, 0x2137, 0, 0x2139, 0x213A, 0x213B, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215A, 0x215B, 0x2229, 0x222E, 0x214C, 0x214D, 0, 0, 0, 0, 0, 0, 0, 0x2D60, 0, 0x2D61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E381[] = { 0, 0x2421, 0x2422, 0x2423, 0x2424, 0x2425, 0x2426, 0x2427, 0x2428, 0x2429, 0x242A, 0x242B, 0x242C, 0x242D, 0x242E, 0x242F, 0x2430, 0x2431, 0x2432, 0x2433, 0x2434, 0x2435, 0x2436, 0x2437, 0x2438, 0x2439, 0x243A, 0x243B, 0x243C, 0x243D, 0x243E, 0x243F, 0x2440, 0x2441, 0x2442, 0x2443, 0x2444, 0x2445, 0x2446, 0x2447, 0x2448, 0x2449, 0x244A, 0x244B, 0x244C, 0x244D, 0x244E, 0x244F, 0x2450, 0x2451, 0x2452, 0x2453, 0x2454, 0x2455, 0x2456, 0x2457, 0x2458, 0x2459, 0x245A, 0x245B, 0x245C, 0x245D, 0x245E, 0x245F, }; const unsigned short utf8_to_euc_E382[] = { 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467, 0x2468, 0x2469, 0x246A, 0x246B, 0x246C, 0x246D, 0x246E, 0x246F, 0x2470, 0x2471, 0x2472, 0x2473, 0, 0, 0, 0, 0, 0, 0, 0x212B, 0x212C, 0x2135, 0x2136, 0, 0, 0x2521, 0x2522, 0x2523, 0x2524, 0x2525, 0x2526, 0x2527, 0x2528, 0x2529, 0x252A, 0x252B, 0x252C, 0x252D, 0x252E, 0x252F, 0x2530, 0x2531, 0x2532, 0x2533, 0x2534, 0x2535, 0x2536, 0x2537, 0x2538, 0x2539, 0x253A, 0x253B, 0x253C, 0x253D, 0x253E, 0x253F, }; const unsigned short utf8_to_euc_E382_932[] = { 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467, 0x2468, 0x2469, 0x246A, 0x246B, 0x246C, 0x246D, 0x246E, 0x246F, 0x2470, 0x2471, 0x2472, 0x2473, 0x2574, 0, 0, 0, 0, 0, 0, 0x212B, 0x212C, 0x2135, 0x2136, 0, 0, 0x2521, 0x2522, 0x2523, 0x2524, 0x2525, 0x2526, 0x2527, 0x2528, 0x2529, 0x252A, 0x252B, 0x252C, 0x252D, 0x252E, 0x252F, 0x2530, 0x2531, 0x2532, 0x2533, 0x2534, 0x2535, 0x2536, 0x2537, 0x2538, 0x2539, 0x253A, 0x253B, 0x253C, 0x253D, 0x253E, 0x253F, }; const unsigned short utf8_to_euc_E383[] = { 0x2540, 0x2541, 0x2542, 0x2543, 0x2544, 0x2545, 0x2546, 0x2547, 0x2548, 0x2549, 0x254A, 0x254B, 0x254C, 0x254D, 0x254E, 0x254F, 0x2550, 0x2551, 0x2552, 0x2553, 0x2554, 0x2555, 0x2556, 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D, 0x255E, 0x255F, 0x2560, 0x2561, 0x2562, 0x2563, 0x2564, 0x2565, 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x256B, 0x256C, 0x256D, 0x256E, 0x256F, 0x2570, 0x2571, 0x2572, 0x2573, 0x2574, 0x2575, 0x2576, 0, 0, 0, 0, 0x2126, 0x213C, 0x2133, 0x2134, 0, }; const unsigned short utf8_to_euc_E388[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2D6A, 0x2D6B, 0, 0, 0, 0, 0, 0, 0x2D6C, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E38A[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2D65, 0x2D66, 0x2D67, 0x2D68, 0x2D69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E38C[] = { 0, 0, 0, 0x2D46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2D4A, 0, 0, 0, 0, 0, 0, 0x2D41, 0, 0, 0, 0x2D44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2D42, 0x2D4C, 0, 0, 0x2D4B, 0x2D45, 0, 0, 0, 0x2D4D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2D47, 0, 0, 0, 0, 0x2D4F, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E38D[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2D40, 0x2D4E, 0, 0, 0x2D43, 0, 0, 0, 0x2D48, 0, 0, 0, 0, 0, 0x2D49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2D5F, 0x2D6F, 0x2D6E, 0x2D6D, 0, }; const unsigned short utf8_to_euc_E38E[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2D53, 0x2D54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2D50, 0x2D51, 0x2D52, 0, 0, 0x2D56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E38F[] = { 0, 0, 0, 0, 0x2D55, 0, 0, 0, 0, 0, 0, 0, 0, 0x2D63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E4B8[] = { 0x306C, 0x437A, 0xB021, 0x3C37, 0xB022, 0xB023, 0, 0x4B7C, 0x3E66, 0x3B30, 0x3E65, 0x323C, 0xB024, 0x4954, 0x4D3F, 0, 0x5022, 0x312F, 0xB025, 0, 0x336E, 0x5023, 0x4024, 0x5242, 0x3556, 0x4A3A, 0, 0, 0, 0, 0x3E67, 0xB026, 0, 0x4E3E, 0, 0xB027, 0xB028, 0, 0x4A42, 0, 0xB029, 0, 0x5024, 0xB02A, 0, 0x4366, 0xB02B, 0xB02C, 0xB02D, 0x5025, 0x367A, 0, 0, 0xB02E, 0x5026, 0, 0x345D, 0x4330, 0, 0x3C67, 0x5027, 0, 0, 0x5028, }; const unsigned short utf8_to_euc_E4B9[] = { 0xB02F, 0xB030, 0x5029, 0x4735, 0xB031, 0x3557, 0, 0xB032, 0, 0, 0, 0x4737, 0, 0x4663, 0x3843, 0x4B33, 0, 0xB033, 0, 0, 0, 0x6949, 0x502A, 0x3E68, 0x502B, 0x3235, 0xB034, 0, 0xB035, 0x3665, 0x3870, 0x4C69, 0, 0, 0x5626, 0xB036, 0, 0, 0, 0, 0xB037, 0xB038, 0, 0, 0, 0, 0, 0, 0, 0x4D70, 0, 0x467D, 0xB039, 0xB03A, 0, 0, 0, 0xB03B, 0, 0, 0, 0, 0x3425, 0xB03C, }; const unsigned short utf8_to_euc_E4BA[] = { 0x3535, 0, 0x502C, 0, 0, 0x502D, 0x4E3B, 0, 0x4D3D, 0x4168, 0x502F, 0x3B76, 0x4673, 0xB03D, 0x5032, 0, 0, 0x313E, 0x385F, 0, 0x385E, 0x3066, 0xB03E, 0xB03F, 0x4F4B, 0x4F4A, 0, 0x3A33, 0x3021, 0xB040, 0x5033, 0x5034, 0x5035, 0x4B34, 0x5036, 0, 0x3872, 0x3067, 0x4B72, 0, 0x357C, 0, 0, 0x357D, 0x357E, 0x4462, 0x4E3C, 0xB041, 0x5037, 0, 0, 0x5038, 0, 0, 0x5039, 0, 0, 0xB042, 0x3F4D, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E4BB[] = { 0x3D3A, 0x3F4E, 0x503E, 0xB043, 0x503C, 0, 0x503D, 0x3558, 0, 0, 0x3A23, 0x3270, 0, 0x503B, 0x503A, 0x4A29, 0xB044, 0, 0, 0, 0x3B46, 0x3B45, 0x423E, 0x503F, 0x4955, 0x4067, 0xB045, 0xB046, 0, 0x2138, 0x5040, 0x5042, 0xB047, 0xB048, 0xB049, 0x4265, 0x4E61, 0x304A, 0, 0, 0xB04A, 0, 0, 0, 0, 0x5041, 0x323E, 0xB04B, 0x3644, 0xB04C, 0x4367, 0xB04D, 0, 0xB04E, 0x376F, 0x5043, 0, 0, 0, 0x4724, 0xF42F, 0xB04F, 0xB050, 0xB051, }; const unsigned short utf8_to_euc_E4BC[] = { 0xB052, 0x346B, 0xB053, 0xB054, 0, 0, 0, 0, 0xB055, 0x5044, 0x304B, 0xB056, 0xB057, 0x3860, 0x346C, 0x497A, 0x4832, 0x3559, 0xB058, 0, 0, 0xB059, 0xB05A, 0xB05B, 0, 0xB05C, 0x3271, 0, 0x5067, 0x4541, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xB05D, 0x476C, 0x5046, 0xB05E, 0, 0xB060, 0x483C, 0xB061, 0x4E62, 0xB062, 0x3F2D, 0xB063, 0x3B47, 0xB064, 0x3B77, 0x3240, 0xB065, 0, }; const unsigned short utf8_to_euc_E4BD[] = { 0xB066, 0, 0xB067, 0x4451, 0, 0, 0x4322, 0x504A, 0xB068, 0xB069, 0, 0xB06A, 0xB06B, 0x304C, 0x4463, 0x3D3B, 0x3A34, 0x4D24, 0xB06C, 0x424E, 0xB06D, 0x323F, 0xB06E, 0x5049, 0xB06F, 0x4D3E, 0x5045, 0x5047, 0x3A6E, 0x5048, 0x5524, 0xB070, 0xB05F, 0, 0, 0xB071, 0, 0, 0, 0, 0, 0x5050, 0xB072, 0, 0xB073, 0, 0xB074, 0x5053, 0x5051, 0xB075, 0, 0x3242, 0, 0x4A3B, 0x504B, 0xB076, 0xB077, 0xB078, 0xB079, 0x504F, 0x3873, 0xB07A, 0xB07B, 0x3B48, }; const unsigned short utf8_to_euc_E4BE[] = { 0, 0xB07C, 0xB07D, 0x3426, 0xB07E, 0xB121, 0x5054, 0, 0x504C, 0xB122, 0xB123, 0x4E63, 0xB124, 0x3B78, 0xB125, 0x504D, 0xB126, 0x5052, 0xB127, 0xB128, 0xB129, 0, 0x5055, 0xB12A, 0x504E, 0xB12B, 0xB12C, 0x3621, 0, 0x304D, 0xB12D, 0xB12E, 0x3622, 0x3241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5525, 0, 0x4B79, 0x496E, 0x3874, 0, 0, 0xB12F, 0, 0, 0x3F2F, 0x4E37, 0xB130, 0, 0xB131, 0, 0xB132, 0xB133, 0xB134, 0xB135, 0x4A58, }; const unsigned short utf8_to_euc_E4BF[] = { 0xB136, 0xB137, 0x3738, 0x4225, 0x3264, 0xB138, 0xB139, 0, 0xB13A, 0xB13B, 0x3D53, 0xB13C, 0xB13D, 0xB13E, 0x5059, 0xB13F, 0x505E, 0x505C, 0xB140, 0, 0x5057, 0, 0, 0x422F, 0x505A, 0, 0x505D, 0x505B, 0xB141, 0x4A5D, 0, 0x5058, 0xB142, 0x3F2E, 0xB143, 0x4B73, 0x505F, 0x5060, 0, 0, 0, 0, 0, 0, 0, 0, 0x3D24, 0x506D, 0xB144, 0, 0xB145, 0x4750, 0, 0x4936, 0x5068, 0, 0x4A70, 0, 0x3236, 0, 0xB146, 0xB147, 0x506C, 0xB148, }; const unsigned short utf8_to_euc_E580[] = { 0xB149, 0xB14A, 0, 0, 0xB14B, 0x5066, 0x506F, 0xB14C, 0, 0x4152, 0xB14D, 0x3844, 0xB14E, 0x475C, 0xB14F, 0x6047, 0xB150, 0x506E, 0x455D, 0xB151, 0x5063, 0, 0x3876, 0xB152, 0xB153, 0x3875, 0x5061, 0xB154, 0xB155, 0xB156, 0xB157, 0x3C5A, 0, 0x5069, 0xB158, 0x4A6F, 0x434D, 0x5065, 0x3771, 0xB159, 0x5062, 0x506A, 0x5064, 0x4E51, 0x506B, 0x4F41, 0xB15A, 0, 0xB15B, 0, 0xB15C, 0xB15D, 0, 0xB15E, 0x3666, 0, 0, 0x3770, 0, 0xB176, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E581[] = { 0xB15F, 0xB160, 0xB161, 0x5070, 0, 0xB162, 0xB163, 0x5071, 0x5075, 0x304E, 0xB164, 0, 0xB165, 0, 0xB166, 0x4A50, 0x5074, 0xB167, 0xB168, 0xB169, 0, 0x5073, 0x5077, 0xB16A, 0, 0xB16B, 0x5076, 0, 0x4464, 0, 0, 0xB16C, 0xB16D, 0, 0xB16E, 0xB16F, 0, 0x3772, 0xB170, 0xB171, 0, 0, 0xB172, 0, 0x5078, 0xB173, 0, 0, 0xB174, 0xB175, 0x3C45, 0, 0x4226, 0x4465, 0x3676, 0, 0x5079, 0, 0, 0, 0, 0x3536, 0, 0, }; const unsigned short utf8_to_euc_E582[] = { 0x507A, 0xB177, 0, 0xB178, 0xB179, 0x507C, 0xB17A, 0, 0, 0, 0xB17B, 0, 0, 0x4B35, 0xB17C, 0xB17D, 0xB17E, 0x3766, 0xB221, 0xB222, 0xB223, 0, 0xB224, 0, 0x3B31, 0x4877, 0x507B, 0xB225, 0xB226, 0, 0xB227, 0xB228, 0xB229, 0xB22A, 0xB22B, 0, 0, 0, 0, 0, 0, 0, 0xB22C, 0, 0x3A45, 0x4D43, 0, 0xB22D, 0xB22E, 0, 0x507E, 0x5123, 0x507D, 0x3A44, 0, 0x3D7D, 0, 0xB22F, 0xB230, 0, 0, 0xB231, 0x3739, 0, }; const unsigned short utf8_to_euc_E583[] = { 0xB232, 0, 0x5124, 0xB233, 0xB234, 0x364F, 0, 0xB235, 0, 0x5121, 0x5122, 0, 0xB236, 0x462F, 0xB237, 0x417C, 0xB238, 0x3623, 0, 0xB239, 0xB23A, 0x4B4D, 0x5125, 0, 0xB23B, 0, 0x4E3D, 0, 0xB23C, 0xB23D, 0x5126, 0xB23E, 0, 0, 0xB23F, 0x5129, 0xB240, 0x5127, 0xB241, 0x414E, 0xB242, 0xB243, 0, 0, 0, 0x5128, 0x512A, 0xB244, 0, 0xB245, 0xB251, 0, 0xF430, 0x512C, 0xB246, 0, 0, 0x512B, 0xB247, 0x4A48, 0, 0, 0xB248, 0, }; const unsigned short utf8_to_euc_E584[] = { 0x3537, 0x512E, 0x512F, 0xB249, 0x322F, 0, 0xB24A, 0xB24B, 0xB24C, 0x512D, 0, 0xB24D, 0xB24E, 0xB24F, 0xB250, 0, 0xB252, 0, 0x3C74, 0, 0x5132, 0x5131, 0x5130, 0xB253, 0x5056, 0xB254, 0x5133, 0xB255, 0xB256, 0xB257, 0xB258, 0x3D7E, 0, 0x5134, 0, 0xB259, 0, 0, 0, 0xB25A, 0xB25B, 0, 0x4D25, 0, 0xB25C, 0xB25D, 0, 0xB25E, 0, 0xB25F, 0x4C59, 0xB260, 0xB261, 0xB262, 0, 0x5136, 0xB263, 0xB264, 0x5135, 0x5138, 0x5137, 0, 0, 0x5139, }; const unsigned short utf8_to_euc_E585[] = { 0x513A, 0x3074, 0xB265, 0x3835, 0x373B, 0x3D3C, 0x437B, 0x3624, 0x4068, 0x3877, 0xB266, 0x396E, 0x513C, 0x4C48, 0x4546, 0xB267, 0x3B79, 0, 0x513B, 0xB268, 0x513D, 0xB269, 0, 0xB26A, 0xB26B, 0, 0x455E, 0, 0x3375, 0, 0, 0xB26C, 0, 0, 0x513E, 0, 0xB26D, 0x467E, 0xB26E, 0, 0x4134, 0x5140, 0x5141, 0x482C, 0x3878, 0x4F3B, 0x5142, 0, 0, 0x3626, 0, 0, 0, 0x4A3C, 0x4236, 0x3671, 0x4535, 0, 0, 0, 0x3773, 0, 0xB26F, 0, }; const unsigned short utf8_to_euc_E586[] = { 0x5143, 0, 0x5144, 0xB270, 0xB271, 0x4662, 0x315F, 0, 0, 0x5147, 0x3A7D, 0xB272, 0x5146, 0x3A46, 0xB273, 0x5148, 0x666E, 0x5149, 0x4B41, 0x514A, 0, 0x514B, 0x514C, 0x3E69, 0xB274, 0x3C4C, 0, 0, 0, 0xB275, 0, 0, 0x3427, 0xB276, 0x514F, 0xB277, 0x514D, 0x4C3D, 0x514E, 0, 0x495A, 0x5150, 0x5151, 0x5152, 0x455F, 0xB278, 0, 0, 0x5156, 0x5154, 0x5155, 0x5153, 0x3A63, 0x5157, 0x4C6A, 0x4E64, 0xB279, 0, 0xB27A, 0, 0xB27B, 0x5158, 0xB27C, 0xB27D, }; const unsigned short utf8_to_euc_E587[] = { 0, 0, 0xB27E, 0, 0x4028, 0x5159, 0x3D5A, 0, 0xB321, 0x515A, 0, 0x437C, 0x4E3F, 0x4560, 0, 0xB322, 0, 0xB323, 0xB324, 0xB325, 0, 0xB326, 0x5245, 0, 0xB327, 0, 0, 0x515B, 0x7425, 0x3645, 0xB328, 0, 0x515C, 0x4B5E, 0xB329, 0, 0, 0xB32A, 0x3D68, 0x427C, 0, 0x515E, 0x4664, 0, 0xF431, 0x515F, 0xB32B, 0, 0x5160, 0x332E, 0xB32C, 0xB32D, 0xB32E, 0x5161, 0x3627, 0xB32F, 0x464C, 0x317A, 0x3D50, 0, 0, 0x4821, 0x5162, 0, }; const unsigned short utf8_to_euc_E588[] = { 0x4561, 0xB330, 0xB331, 0x3F4F, 0x5163, 0xB332, 0x4A2C, 0x405A, 0x3422, 0, 0x3429, 0x5164, 0, 0, 0x5166, 0, 0, 0x373A, 0xB333, 0xB334, 0x5165, 0xB335, 0xB336, 0x4E73, 0xB337, 0, 0, 0, 0, 0x3D69, 0, 0, 0, 0, 0xB338, 0, 0x483D, 0x4A4C, 0, 0x5167, 0xB339, 0x4D78, 0x5168, 0, 0, 0, 0x5169, 0, 0x457E, 0xB33A, 0xB33B, 0x516A, 0, 0xB33C, 0x4029, 0x3A7E, 0x3774, 0x516B, 0x3B49, 0x396F, 0xB33D, 0, 0, 0, }; const unsigned short utf8_to_euc_E589[] = { 0, 0, 0, 0x4466, 0x516D, 0xB33E, 0, 0x4227, 0, 0xB33F, 0x3A6F, 0x516E, 0x516F, 0x4130, 0, 0x516C, 0, 0, 0, 0, 0x5171, 0xB340, 0x4B36, 0xB341, 0xB342, 0, 0xB343, 0x3964, 0xB344, 0, 0x5170, 0xB345, 0xB346, 0xB347, 0, 0x3775, 0x3A5E, 0x476D, 0xB348, 0, 0, 0x5174, 0x5172, 0, 0, 0, 0xB349, 0x497B, 0x3E6A, 0x517B, 0x3364, 0x5175, 0x5173, 0x414F, 0, 0xB34A, 0xB34B, 0xB34C, 0, 0, 0, 0x5177, 0, 0x5176, }; const unsigned short utf8_to_euc_E58A[] = { 0xB34D, 0, 0xB34E, 0x3344, 0, 0xB34F, 0, 0x3760, 0x517C, 0x4E2D, 0xB350, 0, 0xB351, 0x5178, 0, 0, 0, 0x517D, 0x517A, 0xB352, 0x5179, 0xB353, 0xB354, 0xB355, 0xB356, 0, 0xB357, 0x4E4F, 0xB358, 0, 0, 0x3879, 0x3243, 0, 0, 0x4E74, 0xB359, 0xB35A, 0xB35B, 0xB35C, 0, 0x3D75, 0x4558, 0x3965, 0x5222, 0x5223, 0, 0xB35D, 0xB35E, 0x4E65, 0, 0, 0x4F2B, 0x5225, 0xB35F, 0xB360, 0xB361, 0x387A, 0xB362, 0xB363, 0x5224, 0xB364, 0x332F, 0, }; const unsigned short utf8_to_euc_E58B[] = { 0xB365, 0x5226, 0, 0x4B56, 0xB366, 0x443C, 0xB367, 0x4D26, 0xB368, 0x4A59, 0, 0, 0xB369, 0x5227, 0, 0xB36A, 0, 0xB36B, 0x7055, 0, 0xB36C, 0x4630, 0xB36D, 0x5228, 0x342A, 0x4C33, 0, 0xB36E, 0xB36F, 0x3E21, 0x5229, 0x4A67, 0x522D, 0xB370, 0x402A, 0x522A, 0x3650, 0xB371, 0x522B, 0x342B, 0xB372, 0xB373, 0xB374, 0, 0xB375, 0, 0, 0, 0xB376, 0xB377, 0x372E, 0x522E, 0xB378, 0x522F, 0xB379, 0xB37A, 0x5230, 0x5231, 0x3C5B, 0, 0, 0, 0x387B, 0x4C5E, }; const unsigned short utf8_to_euc_E58C[] = { 0xB37B, 0x4C68, 0x4677, 0xB37C, 0, 0x4A71, 0x5232, 0xF432, 0x5233, 0, 0xB37D, 0xB37E, 0xB421, 0x5235, 0, 0x5237, 0x5236, 0xB422, 0, 0xB423, 0, 0x5238, 0x323D, 0x4B4C, 0xB424, 0x3A7C, 0x5239, 0xB425, 0xB426, 0x4159, 0xB427, 0xB428, 0x3E22, 0x3629, 0, 0x523A, 0xF433, 0xB429, 0, 0xB42A, 0xB42B, 0xB42C, 0x485B, 0xB42D, 0xB42E, 0xB42F, 0, 0x523B, 0xB430, 0x523C, 0xB431, 0x523D, 0, 0xB432, 0, 0, 0x523E, 0x4924, 0x3668, 0x3065, 0xB433, 0xB434, 0xB435, 0x463F, }; const unsigned short utf8_to_euc_E58D[] = { 0x523F, 0x3D3D, 0xB436, 0x4069, 0, 0x5241, 0x5240, 0x3E23, 0x3861, 0x5243, 0x483E, 0xB438, 0xB437, 0x5244, 0, 0, 0, 0x485C, 0x4234, 0x426E, 0x3628, 0, 0, 0x466E, 0x4331, 0xB439, 0x476E, 0xB43A, 0x4B4E, 0, 0x5246, 0, 0x406A, 0xB43B, 0, 0xB43C, 0, 0xB43D, 0x3735, 0, 0, 0x5247, 0, 0, 0xB43E, 0xB43F, 0x5248, 0x312C, 0x3075, 0x346D, 0xB440, 0x4228, 0x3551, 0x4D71, 0, 0x524B, 0x3237, 0xB441, 0, 0x524A, 0, 0, 0xB442, 0x362A, }; const unsigned short utf8_to_euc_E58E[] = { 0, 0, 0x524C, 0xB443, 0x4C71, 0, 0, 0xB444, 0xB445, 0, 0, 0, 0, 0, 0xB446, 0, 0, 0, 0, 0xB447, 0xB448, 0, 0x524D, 0, 0x4E52, 0xB449, 0x387C, 0, 0, 0xB44A, 0, 0x3836, 0x524E, 0xB44B, 0, 0, 0xB44C, 0x5250, 0x524F, 0, 0x3F5F, 0x3139, 0xB44D, 0xB44E, 0, 0x315E, 0x5251, 0xB44F, 0x5252, 0, 0xB450, 0x3837, 0xB451, 0xB452, 0x5253, 0xB453, 0xB454, 0, 0xB455, 0x356E, 0, 0xB456, 0, 0, }; const unsigned short utf8_to_euc_E58F[] = { 0xB457, 0, 0x3B32, 0x5254, 0, 0xB458, 0, 0, 0x4B74, 0x3A35, 0x355A, 0x4D27, 0x4150, 0x483F, 0x3C7D, 0xB459, 0, 0, 0xB45A, 0xB45B, 0x3D47, 0xB45C, 0x3C68, 0x3C75, 0, 0x3D76, 0xB45D, 0x4840, 0, 0xB45E, 0xB45F, 0x5257, 0xB460, 0x3143, 0x4151, 0x387D, 0x3845, 0x3667, 0xB461, 0xB462, 0x525B, 0x4321, 0x427E, 0x362B, 0x3E24, 0x525C, 0x525A, 0x3244, 0x4266, 0x3C38, 0x3B4B, 0x3126, 0, 0xB463, 0x3370, 0x3966, 0x3B4A, 0, 0x525D, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E590[] = { 0, 0x525E, 0xB464, 0x3549, 0x3346, 0, 0, 0, 0x3967, 0x3548, 0x445F, 0x3125, 0x4631, 0x4C3E, 0x3921, 0x4D79, 0x4547, 0x387E, 0, 0xB465, 0, 0, 0, 0, 0, 0, 0xB466, 0x372F, 0, 0x5267, 0, 0x3663, 0x4B4A, 0xB467, 0, 0, 0, 0, 0x485D, 0xB468, 0xB469, 0x5266, 0xB46A, 0x345E, 0x5261, 0x5262, 0x5264, 0xB46B, 0, 0xB46C, 0, 0, 0xB46D, 0xB46E, 0x5265, 0, 0x355B, 0x3F61, 0, 0x4A2D, 0x5263, 0x525F, 0x3863, 0, }; const unsigned short utf8_to_euc_E591[] = { 0x5260, 0, 0x4F24, 0xB46F, 0xB470, 0, 0x4A72, 0xB471, 0x4468, 0x3862, 0x3970, 0, 0, 0xB472, 0x5268, 0xB473, 0, 0x465D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xB474, 0x526C, 0, 0, 0xB475, 0, 0xB476, 0, 0xB477, 0xB478, 0x3C7E, 0xB479, 0x3C76, 0xB47A, 0, 0xB47B, 0xB47C, 0, 0x526F, 0x526D, 0, 0x4C23, 0xB47D, 0x526A, 0x5273, 0x526E, 0, 0, 0, 0x5271, 0x3846, 0x4C3F, 0, 0xB47E, }; const unsigned short utf8_to_euc_E592[] = { 0x5272, 0xB521, 0, 0xB522, 0x5274, 0xB523, 0x5276, 0, 0xB524, 0xB525, 0xF435, 0x3A70, 0x4F42, 0xB526, 0x526B, 0x5269, 0x5275, 0xB527, 0x5270, 0, 0, 0xB528, 0xB529, 0, 0, 0, 0, 0, 0xB52A, 0, 0, 0xB52B, 0, 0xB52C, 0x5278, 0, 0x5323, 0x527A, 0xB52D, 0xB52E, 0x527E, 0xB52F, 0xB530, 0x5321, 0x527B, 0xB531, 0xB532, 0x533E, 0, 0xB533, 0x3A69, 0x3331, 0, 0, 0, 0xB534, 0x5279, 0xB535, 0xB536, 0xB537, 0x5325, 0x3076, 0x5324, 0xB538, }; const unsigned short utf8_to_euc_E593[] = { 0x3025, 0x494A, 0x5322, 0, 0x527C, 0, 0xB539, 0x5277, 0x527D, 0x3A48, 0xB53A, 0, 0, 0xB53B, 0xB53C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5326, 0, 0, 0, 0, 0, 0, 0, 0xB53D, 0x3077, 0x532F, 0, 0, 0x5327, 0x5328, 0, 0x3E25, 0x4B69, 0xB53E, 0, 0xB53F, 0x532D, 0x532C, 0xB540, 0, 0, 0x452F, 0, 0, 0, 0xB541, 0, 0, 0, 0x532E, 0, 0xB542, 0x532B, 0xB543, 0xB544, }; const unsigned short utf8_to_euc_E594[] = { 0xB545, 0xB546, 0, 0, 0x3134, 0xB547, 0x3A36, 0x3F30, 0xB548, 0xB549, 0, 0, 0xB54A, 0xB54B, 0xB54C, 0x5329, 0x4562, 0, 0, 0, 0x532A, 0xB54D, 0x3022, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xB54E, 0xB54F, 0, 0, 0x5334, 0x4D23, 0, 0x3E27, 0xB550, 0x533A, 0, 0xB551, 0xB552, 0, 0x5339, 0x5330, 0, 0xB553, 0xB554, 0xB555, 0x4243, 0, }; const unsigned short utf8_to_euc_E595[] = { 0x5331, 0xB556, 0, 0, 0x426F, 0x5336, 0x3E26, 0xB557, 0, 0xB558, 0xB559, 0, 0x5333, 0xB55A, 0, 0x4C64, 0xB55B, 0xB55C, 0, 0x373C, 0, 0, 0x5337, 0x5338, 0xB55D, 0, 0xB55E, 0xB55F, 0x5335, 0x533B, 0xB560, 0, 0xB561, 0xB562, 0, 0x5332, 0xB563, 0, 0xB564, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5341, 0x5346, 0, 0x5342, 0xB565, }; const unsigned short utf8_to_euc_E596[] = { 0x533D, 0xB566, 0xB567, 0x5347, 0x4131, 0, 0xB568, 0x5349, 0xB569, 0x3922, 0x533F, 0x437D, 0, 0, 0xB56A, 0xB56B, 0, 0xB56C, 0xB56D, 0xB56E, 0xB56F, 0, 0, 0xB570, 0x5343, 0x533C, 0x342D, 0, 0x346E, 0x3365, 0x5344, 0x5340, 0, 0, 0, 0xB571, 0xB572, 0, 0, 0x3776, 0x534A, 0x5348, 0x4153, 0x354A, 0x362C, 0xB573, 0x5345, 0, 0x3674, 0, 0xB574, 0, 0, 0, 0x3144, 0, 0, 0, 0, 0, 0, 0, 0, 0xB575, }; const unsigned short utf8_to_euc_E597[] = { 0, 0xB576, 0, 0xB577, 0x534E, 0x534C, 0xB578, 0x5427, 0, 0xB579, 0, 0xB57A, 0xB57B, 0, 0xB57C, 0, 0, 0xB57D, 0xB57E, 0xB621, 0x5351, 0, 0, 0xB622, 0xB623, 0, 0x534B, 0xB624, 0x534F, 0, 0xB625, 0x534D, 0, 0, 0xB626, 0x3B4C, 0x5350, 0, 0, 0, 0, 0xB627, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xB628, 0x5353, 0, 0x5358, 0, 0, 0, 0x5356, 0x5355, 0xB629, }; const unsigned short utf8_to_euc_E598[] = { 0, 0, 0, 0, 0, 0xB62A, 0x4332, 0, 0xB62B, 0x3245, 0xB62C, 0, 0, 0xB62D, 0xB62E, 0xB62F, 0xB630, 0xB631, 0xB632, 0, 0x5352, 0, 0x5354, 0x3E28, 0x3133, 0xB633, 0, 0x5357, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x325E, 0, 0, 0xB634, 0, 0, 0x5362, 0xB635, 0x3E7C, 0x535E, 0xB636, 0x535C, 0xB637, 0x535D, 0xB638, 0x535F, 0xB639, 0, 0xB63A, 0xB63B, 0xB63C, 0, 0xB63D, }; const unsigned short utf8_to_euc_E599[] = { 0xB63E, 0xB63F, 0x313D, 0xB640, 0xB641, 0, 0xB642, 0, 0, 0xB643, 0, 0xB644, 0x4139, 0xB645, 0x5359, 0xB646, 0x535A, 0, 0, 0, 0xB647, 0, 0, 0, 0, 0, 0, 0x337A, 0, 0, 0xB648, 0, 0xB649, 0xB64A, 0xB64B, 0xB64C, 0x5361, 0, 0xB64D, 0, 0x346F, 0xB64E, 0x5364, 0x5360, 0x5363, 0xB64F, 0, 0xB650, 0, 0xB651, 0xB652, 0, 0x4A2E, 0xB653, 0, 0, 0x4655, 0, 0x4838, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E59A[] = { 0x5366, 0, 0, 0, 0xB654, 0xB655, 0x5365, 0x3345, 0xB656, 0, 0x5367, 0xB657, 0xB658, 0, 0, 0x536A, 0, 0, 0, 0, 0x5369, 0xB659, 0, 0, 0, 0xB65A, 0xB65B, 0, 0, 0xB65C, 0xB65D, 0xB65E, 0x5368, 0, 0x4739, 0, 0, 0x536B, 0xB65F, 0xB660, 0xB661, 0xB662, 0, 0xB663, 0xB664, 0xB665, 0x536C, 0, 0, 0xB666, 0, 0xB667, 0x536E, 0, 0x536D, 0xB668, 0, 0, 0, 0, 0x5370, 0, 0xB669, 0, }; const unsigned short utf8_to_euc_E59B[] = { 0x5373, 0x5371, 0x536F, 0x5372, 0, 0xB66A, 0, 0, 0x5374, 0xB66B, 0xB66C, 0xB66D, 0xB670, 0xB671, 0x5375, 0xB66E, 0xB66F, 0x5376, 0, 0x5377, 0, 0, 0, 0x5378, 0x5145, 0xB672, 0x3C7C, 0x3B4D, 0xB673, 0xB674, 0x3273, 0xB675, 0x3078, 0xB676, 0, 0x4344, 0xB677, 0xB678, 0xB679, 0xB67A, 0xB67B, 0, 0, 0xB67D, 0, 0xB67E, 0x5379, 0, 0x3A24, 0xB67C, 0x304F, 0x3F5E, 0, 0, 0xB721, 0xB722, 0, 0x537A, 0x3847, 0, 0, 0x3971, 0, 0x537C, }; const unsigned short utf8_to_euc_E59C[] = { 0x537B, 0xB723, 0xB724, 0x4A60, 0x537D, 0, 0, 0xB725, 0x5421, 0x537E, 0xB726, 0x5422, 0xB727, 0x5423, 0, 0x3777, 0, 0xB728, 0x3160, 0x5424, 0, 0xB729, 0x5426, 0, 0x5425, 0, 0xB72A, 0xB72B, 0x5428, 0xB72C, 0, 0x455A, 0xB72D, 0, 0xB72E, 0xB72F, 0xB730, 0xB731, 0x5429, 0x3035, 0x3A5F, 0xB732, 0xB733, 0, 0xB734, 0x373D, 0xB735, 0xB736, 0x434F, 0, 0, 0xB737, 0xB738, 0, 0, 0x542A, 0x542B, 0, 0, 0x542D, 0, 0xB739, 0xB73A, 0xB73B, }; const unsigned short utf8_to_euc_E59D[] = { 0x542E, 0, 0x3A64, 0, 0, 0xB73C, 0xB73D, 0x3651, 0, 0, 0x4B37, 0, 0xB73E, 0xB73F, 0x542C, 0x542F, 0x3A41, 0x3923, 0xB740, 0, 0, 0, 0, 0, 0, 0xF436, 0, 0, 0, 0, 0, 0, 0, 0x5433, 0xB741, 0, 0x3A25, 0xB742, 0x4333, 0xB743, 0xB744, 0x5430, 0x445A, 0xB745, 0, 0xB746, 0xB747, 0xB748, 0xB749, 0xB74A, 0, 0xB74B, 0xB74C, 0xB74D, 0, 0xB74E, 0, 0xB74F, 0xB750, 0xB751, 0xB752, 0, 0xB753, 0x5434, }; const unsigned short utf8_to_euc_E59E[] = { 0, 0xB754, 0x3F62, 0xB755, 0, 0, 0, 0, 0x5432, 0x5435, 0, 0x373F, 0xB756, 0, 0, 0, 0, 0, 0, 0x5436, 0xB757, 0xB760, 0, 0xB758, 0, 0xB759, 0xB75A, 0, 0xB75B, 0xB75C, 0xB75D, 0xB75E, 0x5437, 0xB75F, 0x3924, 0x3340, 0x5439, 0, 0, 0xB761, 0xB762, 0xB763, 0x543A, 0, 0xB764, 0, 0, 0, 0x543B, 0, 0, 0x5438, 0, 0, 0, 0, 0xB765, 0, 0, 0, 0, 0xB766, 0, 0, }; const unsigned short utf8_to_euc_E59F[] = { 0x5431, 0, 0, 0x543C, 0, 0, 0x543D, 0xB767, 0xB768, 0, 0, 0x4B64, 0xB769, 0, 0x3E6B, 0xB76A, 0, 0, 0x543F, 0x5440, 0x543E, 0xB76B, 0x5442, 0, 0, 0, 0, 0, 0x4738, 0xB76C, 0xB76D, 0x3068, 0x4956, 0xB77E, 0, 0x5443, 0xB76E, 0, 0xB76F, 0xB770, 0, 0xB771, 0, 0, 0, 0xB772, 0, 0, 0xB773, 0, 0, 0, 0x3E7D, 0xB774, 0xB775, 0x3C39, 0xB776, 0x475D, 0x3470, 0, 0x3A6B, 0xB777, 0xB778, 0xB779, }; const unsigned short utf8_to_euc_E5A0[] = { 0x4B59, 0, 0x4632, 0xB77A, 0xB77B, 0x3778, 0x424F, 0, 0xB77C, 0xB77D, 0x5441, 0x5444, 0xB821, 0xB822, 0, 0, 0, 0, 0, 0, 0, 0x4244, 0, 0, 0, 0x5445, 0, 0xB823, 0, 0x5446, 0xB824, 0xB825, 0xB826, 0x5448, 0, 0, 0x4469, 0, 0xB827, 0xB828, 0, 0, 0x342E, 0, 0, 0xB829, 0, 0x7421, 0x3161, 0x4A73, 0xB82A, 0, 0x3E6C, 0x4548, 0, 0, 0, 0xB82B, 0x3A66, 0, 0, 0x544E, 0, 0xB82C, }; const unsigned short utf8_to_euc_E5A1[] = { 0x4A3D, 0x4E5D, 0, 0, 0, 0, 0, 0, 0, 0xB82D, 0x3274, 0x544A, 0xB82E, 0xB82F, 0, 0xB830, 0xB831, 0x413A, 0x544D, 0, 0x4563, 0xB832, 0, 0x4549, 0x4564, 0x4839, 0x444D, 0, 0, 0, 0x3A49, 0xB833, 0, 0xB834, 0x5449, 0, 0xB835, 0, 0, 0xB836, 0xB837, 0x3176, 0, 0x4536, 0, 0, 0, 0, 0x544B, 0, 0x5447, 0, 0, 0x3F50, 0, 0, 0xB838, 0x544F, 0, 0, 0xB839, 0, 0x3D4E, 0xB83A, }; const unsigned short utf8_to_euc_E5A2[] = { 0xB83B, 0xB83C, 0, 0x362D, 0, 0x5450, 0, 0xB83D, 0xB83E, 0xB83F, 0xB840, 0, 0xB841, 0xB842, 0, 0xB843, 0xB844, 0, 0, 0x4A68, 0xB845, 0, 0xB846, 0x417D, 0, 0, 0, 0, 0x4446, 0xB847, 0xF439, 0x5452, 0xB848, 0xB849, 0xB84A, 0, 0, 0, 0xB84B, 0, 0x4B4F, 0xB84C, 0, 0x5453, 0, 0, 0x5458, 0, 0, 0xB84D, 0xB84E, 0x4A2F, 0, 0, 0, 0, 0x5457, 0x5451, 0x5454, 0x5456, 0xB850, 0, 0x3A26, 0, }; const unsigned short utf8_to_euc_E5A3[] = { 0, 0x4A49, 0xB851, 0, 0xB84F, 0x5459, 0, 0x4345, 0xB852, 0, 0x3275, 0, 0x3E6D, 0xB853, 0xB854, 0, 0xB855, 0x545B, 0xB856, 0x545A, 0xB857, 0x3968, 0xB858, 0x545C, 0x545E, 0x545D, 0xB859, 0, 0x5460, 0xB85A, 0x5455, 0x5462, 0, 0xB85B, 0xB85C, 0, 0x5461, 0x545F, 0, 0, 0, 0xB85D, 0, 0x3B4E, 0x3F51, 0, 0x4154, 0x5463, 0x403C, 0x306D, 0x4764, 0xB85E, 0, 0, 0, 0x445B, 0, 0x5465, 0x5464, 0x5466, 0x5467, 0x5468, 0, 0, }; const unsigned short utf8_to_euc_E5A4[] = { 0, 0, 0x5469, 0, 0, 0xB85F, 0xB860, 0, 0, 0x4A51, 0x546A, 0xB861, 0xB862, 0, 0, 0x3246, 0x546B, 0, 0xB863, 0xB864, 0xB865, 0x4D3C, 0x3330, 0, 0x5249, 0x3D48, 0x423F, 0x546C, 0x4C6B, 0xB867, 0, 0, 0, 0xB868, 0x4C34, 0xB869, 0xB86A, 0x546E, 0, 0x4267, 0xB86B, 0x4537, 0x4240, 0x4957, 0x546F, 0x5470, 0x317B, 0xB86C, 0xB86D, 0x3C3A, 0x5471, 0xB86E, 0, 0xB86F, 0xB870, 0x3050, 0x5472, 0, 0, 0, 0, 0, 0x5473, 0xB871, }; const unsigned short utf8_to_euc_E5A5[] = { 0, 0, 0, 0xB872, 0x3162, 0, 0xB873, 0x3471, 0x4660, 0x4A74, 0, 0, 0, 0, 0x5477, 0x4155, 0x5476, 0x3740, 0xB874, 0xB875, 0x4B5B, 0x5475, 0, 0x4565, 0x5479, 0xB876, 0x5478, 0xB877, 0, 0xB878, 0xB879, 0xB87A, 0x547B, 0xB87B, 0x547A, 0xB87C, 0, 0x317C, 0, 0x547C, 0x3E29, 0x547E, 0x4325, 0xB87D, 0x547D, 0xB87E, 0x4A33, 0xB921, 0, 0, 0xB922, 0x3D77, 0x455B, 0xB923, 0xB924, 0, 0x5521, 0xB925, 0, 0xB926, 0xB927, 0x3925, 0, 0, }; const unsigned short utf8_to_euc_E5A6[] = { 0, 0x5522, 0x4721, 0x485E, 0x4C51, 0, 0, 0, 0, 0, 0x4725, 0xB928, 0xB929, 0x552B, 0xB92A, 0, 0, 0, 0xB92B, 0x3538, 0, 0xB92C, 0x4D45, 0xB92D, 0, 0x4C2F, 0, 0x562C, 0, 0x5523, 0, 0xB92E, 0, 0, 0, 0x5526, 0xB92F, 0x4245, 0, 0xB930, 0x4B38, 0, 0, 0, 0x454A, 0xB931, 0xB932, 0xB933, 0xB934, 0, 0x5527, 0xB935, 0, 0, 0, 0xB936, 0, 0x4B65, 0xB937, 0x3A4A, 0xB938, 0, 0x3E2A, 0, }; const unsigned short utf8_to_euc_E5A7[] = { 0, 0xB939, 0, 0xB93A, 0xB93B, 0, 0x5528, 0, 0xB93C, 0x3B50, 0xB93D, 0x3B4F, 0, 0xB93E, 0, 0, 0x3039, 0x3848, 0xB93F, 0x402B, 0x3051, 0, 0, 0, 0, 0x552C, 0x552D, 0, 0x552A, 0xB940, 0xB941, 0xB942, 0, 0, 0, 0xB943, 0xB944, 0x3138, 0x342F, 0xB945, 0x5529, 0, 0x4C45, 0x4931, 0, 0, 0xB946, 0xB947, 0, 0xB948, 0xB949, 0, 0xB94A, 0, 0x3028, 0xB94B, 0, 0, 0, 0x3079, 0, 0, 0, 0x3B51, }; const unsigned short utf8_to_euc_E5A8[] = { 0xB94C, 0x3052, 0, 0x3023, 0xB94D, 0, 0, 0, 0, 0x5532, 0, 0, 0xB94E, 0xB94F, 0xB950, 0, 0, 0x5530, 0xB951, 0xB952, 0, 0, 0, 0, 0x4C3C, 0, 0x5533, 0, 0x5531, 0, 0xB953, 0x552F, 0x3F31, 0, 0, 0xB954, 0xB955, 0x552E, 0, 0xB956, 0xB957, 0x4A5A, 0xB958, 0, 0, 0xB959, 0, 0x3864, 0xB95A, 0, 0, 0, 0, 0x5537, 0x5538, 0, 0, 0, 0, 0, 0x3E2B, 0, 0, 0, }; const unsigned short utf8_to_euc_E5A9[] = { 0x5534, 0x4F2C, 0, 0, 0xB95B, 0xB95C, 0x474C, 0xB95D, 0xB95E, 0x5536, 0, 0, 0xB95F, 0, 0, 0, 0xB960, 0, 0, 0, 0, 0xB961, 0, 0, 0, 0, 0x3A27, 0, 0, 0, 0xB962, 0, 0, 0, 0x5539, 0xB963, 0, 0xB964, 0x4958, 0xB965, 0, 0, 0x553A, 0, 0x5535, 0xB966, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xB967, 0, 0, 0xB968, 0xB969, 0, 0, 0xB96A, 0x4C3B, }; const unsigned short utf8_to_euc_E5AA[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xB96B, 0, 0, 0, 0, 0xB96C, 0, 0x475E, 0xB96D, 0, 0, 0xB96E, 0, 0, 0xB96F, 0x553B, 0x4932, 0xB970, 0, 0xB971, 0xB972, 0xB973, 0, 0xB974, 0, 0, 0, 0, 0xB975, 0, 0, 0, 0, 0xB976, 0, 0, 0, 0, 0xB977, 0xB978, 0xB979, 0, 0xB97A, 0, 0, 0xB97B, 0, 0xB97C, 0xB97D, 0x553C, 0x5540, 0x553D, 0xB97E, }; const unsigned short utf8_to_euc_E5AB[] = { 0, 0x3247, 0x553F, 0, 0xBA21, 0, 0xBA22, 0, 0xBA23, 0x3C3B, 0, 0x553E, 0x3779, 0, 0, 0xBA24, 0x554C, 0, 0, 0, 0, 0, 0x5545, 0x5542, 0, 0, 0xBA25, 0, 0xBA26, 0, 0, 0, 0xBA27, 0x4364, 0, 0x5541, 0, 0xBA28, 0x5543, 0, 0, 0x5544, 0xBA29, 0, 0, 0, 0xBA2A, 0, 0, 0, 0, 0, 0, 0xBA2B, 0xBA2C, 0, 0, 0, 0x5546, 0x5547, 0, 0xBA2D, 0, 0, }; const unsigned short utf8_to_euc_E5AC[] = { 0xBA2E, 0xBA2F, 0, 0, 0, 0, 0, 0, 0xBA30, 0x3472, 0, 0x5549, 0x5548, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x554A, 0xBA31, 0, 0xBA33, 0, 0xBA34, 0, 0xBA35, 0, 0, 0, 0xBA36, 0x3E6E, 0, 0, 0xBA37, 0, 0, 0, 0, 0x554D, 0, 0x445C, 0xBA38, 0, 0, 0x3145, 0, 0x554B, 0, 0xBA32, 0, 0x554E, 0, 0xBA39, 0, 0, 0, 0, 0, 0x554F, 0, }; const unsigned short utf8_to_euc_E5AD[] = { 0x5552, 0xBA3A, 0, 0x5550, 0, 0x5551, 0, 0, 0, 0, 0, 0xBA3B, 0xBA3C, 0, 0, 0, 0x3B52, 0x5553, 0xBA3D, 0, 0x3926, 0x5554, 0xBA3E, 0x3B7A, 0x4238, 0, 0x5555, 0x5556, 0x3B5A, 0x3927, 0xBA3F, 0x4C52, 0, 0, 0, 0x3528, 0x3849, 0x5557, 0x3358, 0, 0xBA40, 0x5558, 0, 0x4239, 0, 0, 0xBA41, 0xBA42, 0x5559, 0x5623, 0, 0x555A, 0, 0x555B, 0, 0, 0x555C, 0, 0x555E, 0, 0xBA43, 0xBA44, 0xBA45, 0xBA46, }; const unsigned short utf8_to_euc_E5AE[] = { 0x555F, 0xBA47, 0, 0x5560, 0xBA48, 0x4270, 0xBA49, 0x3127, 0x3C69, 0x3042, 0xBA4A, 0x4157, 0x3430, 0x3C35, 0xBA4B, 0x3928, 0xBA4C, 0xBA4D, 0, 0xBA4E, 0xBA4F, 0x4566, 0xBA50, 0x3D21, 0x3431, 0x4368, 0x446A, 0x3038, 0x3539, 0x4A75, 0, 0x3C42, 0, 0, 0x3552, 0x406B, 0x3C3C, 0x4D28, 0x5561, 0, 0xBA51, 0xBA52, 0, 0, 0xBA53, 0xBA54, 0x355C, 0xBA55, 0x3A4B, 0xBA56, 0xBA57, 0x3332, 0x3163, 0x3E2C, 0x3248, 0xBA58, 0x5562, 0x4D46, 0xBA59, 0, 0xBA5A, 0, 0, 0x3D49, }; const unsigned short utf8_to_euc_E5AF[] = { 0xBA5B, 0xBA5C, 0x3C64, 0x5563, 0x3473, 0x4652, 0x4C29, 0x5564, 0, 0x5565, 0, 0, 0x4959, 0xBA5D, 0, 0xBA5E, 0x5567, 0, 0x3428, 0x3677, 0x5566, 0, 0xBA5F, 0xBA60, 0xBA61, 0xBA62, 0xBA63, 0x3432, 0, 0x3F32, 0x556B, 0x3B21, 0xBA64, 0x3249, 0x556A, 0, 0x5568, 0x556C, 0x5569, 0x472B, 0x5C4D, 0x3F33, 0, 0x556D, 0xF43A, 0, 0x4E40, 0xBA65, 0x556E, 0xBA66, 0, 0x5570, 0xBA67, 0x437E, 0x556F, 0, 0x4023, 0, 0x3B7B, 0, 0, 0xBA68, 0x4250, 0x3C77, }; const unsigned short utf8_to_euc_E5B0[] = { 0, 0x4975, 0x406C, 0, 0x3C4D, 0x5571, 0x3E2D, 0x5572, 0x5573, 0x3053, 0x423A, 0x3F52, 0xBA69, 0x5574, 0x4633, 0x3E2E, 0, 0x3E2F, 0, 0x5575, 0, 0, 0x406D, 0xBA6A, 0, 0, 0x3E30, 0, 0, 0, 0xBA6B, 0xBA6C, 0x5576, 0, 0x5577, 0xBA6D, 0x4C60, 0, 0xBA6E, 0, 0x5578, 0xBA6F, 0, 0xBA70, 0xBA71, 0x3646, 0xBA72, 0, 0xBA73, 0x3D22, 0xBA74, 0, 0, 0xBA75, 0xBA76, 0, 0x5579, 0x557A, 0x3C5C, 0x3F2C, 0x4674, 0x3F54, 0x4878, 0x4722, }; const unsigned short utf8_to_euc_E5B1[] = { 0x3649, 0x557B, 0, 0, 0, 0x356F, 0x557C, 0, 0x367E, 0, 0x464F, 0x3230, 0, 0x3B53, 0x557D, 0x5622, 0x5621, 0x367D, 0, 0x557E, 0, 0x4538, 0, 0, 0, 0xBA77, 0xBA78, 0, 0xBA79, 0, 0x4230, 0, 0x454B, 0x3C48, 0xBA7A, 0xBA7B, 0x4158, 0x4D7A, 0, 0xBA7C, 0xBA7D, 0xBA7E, 0, 0, 0x5624, 0xBB21, 0x5625, 0x4656, 0xBB22, 0x3B33, 0, 0, 0xBB23, 0xBB24, 0x5627, 0, 0, 0x5628, 0xBB25, 0xBB26, 0xBB27, 0xBB28, 0, 0, }; const unsigned short utf8_to_euc_E5B2[] = { 0, 0, 0, 0, 0, 0, 0, 0xBB29, 0xBB2A, 0, 0xBB2B, 0, 0x5629, 0, 0, 0xBB2C, 0x3474, 0x562A, 0xBB2D, 0, 0x562B, 0, 0, 0, 0, 0, 0, 0, 0, 0xBB2E, 0, 0xBB2F, 0xBB30, 0x322C, 0xBB31, 0xBB32, 0, 0, 0xBB33, 0, 0x413B, 0x3464, 0xBB34, 0x562D, 0x4C28, 0, 0, 0, 0, 0x4252, 0xBB35, 0x3359, 0xBB36, 0xBB37, 0x562F, 0x5631, 0x345F, 0, 0xBB38, 0x562E, 0x5630, 0, 0x5633, 0, }; const unsigned short utf8_to_euc_E5B3[] = { 0, 0, 0, 0, 0, 0x5632, 0, 0x5634, 0, 0xBB39, 0, 0xBB3A, 0, 0, 0, 0, 0, 0, 0xBB3B, 0, 0, 0, 0, 0xBB3D, 0, 0x5635, 0, 0, 0, 0xBB3C, 0, 0, 0x463D, 0x362E, 0, 0, 0, 0, 0, 0, 0x3265, 0x5636, 0x563B, 0, 0, 0x5639, 0xBB3E, 0x4A77, 0x4A76, 0xBB3F, 0xBB40, 0, 0xBB41, 0xF43B, 0x4567, 0, 0, 0, 0x5638, 0x3D54, 0, 0x5637, 0, 0, }; const unsigned short utf8_to_euc_E5B4[] = { 0, 0xBB42, 0, 0, 0, 0, 0xBB43, 0x3F72, 0, 0, 0, 0x563C, 0, 0xBB44, 0x3A6A, 0, 0, 0x5642, 0xBB45, 0, 0x5643, 0x563D, 0x3333, 0x563E, 0x5647, 0x5646, 0x5645, 0x5641, 0, 0, 0, 0x5640, 0, 0, 0x5644, 0xBB47, 0xBB48, 0, 0xBB49, 0xBB4A, 0, 0x4A78, 0, 0xBB46, 0, 0, 0, 0, 0, 0xBB4B, 0, 0, 0xBB4C, 0, 0, 0, 0, 0xBB4D, 0, 0, 0, 0xBB4E, 0, 0xBB4F, }; const unsigned short utf8_to_euc_E5B5[] = { 0, 0, 0xBB50, 0xBB51, 0, 0, 0xBB52, 0, 0xBB53, 0, 0xBB57, 0x564B, 0x5648, 0, 0x564A, 0, 0x4D72, 0xBB55, 0x5649, 0xF43C, 0, 0xBB54, 0, 0, 0, 0xBB56, 0, 0, 0x563F, 0, 0, 0xBB58, 0xBB59, 0xBB5A, 0xBB5B, 0, 0xBB5C, 0, 0, 0, 0, 0x3F73, 0xBB5D, 0, 0x564C, 0xBB5E, 0, 0x3A37, 0xBB5F, 0, 0, 0x564D, 0, 0, 0x564E, 0, 0, 0xBB60, 0xBB61, 0, 0, 0, 0xBB62, 0xBB63, }; const unsigned short utf8_to_euc_E5B6[] = { 0, 0xBB64, 0x5651, 0xBB65, 0x5650, 0, 0, 0x564F, 0xBB66, 0, 0xBB67, 0x4568, 0x563A, 0, 0, 0, 0x5657, 0, 0xBB68, 0xBB69, 0xBB6A, 0xBB6B, 0, 0, 0, 0xBB6C, 0, 0xBB6D, 0, 0x5653, 0, 0xBB6E, 0xBB6F, 0, 0x5652, 0, 0, 0, 0, 0xBB70, 0, 0, 0, 0xBB71, 0x5654, 0, 0x5655, 0, 0xBB72, 0, 0xE674, 0, 0xBB73, 0, 0, 0x5658, 0xBB74, 0xBB75, 0x4E66, 0, 0x5659, 0x5656, 0, 0, }; const unsigned short utf8_to_euc_E5B7[] = { 0, 0, 0, 0xBB76, 0, 0, 0, 0xBB77, 0, 0x565A, 0, 0xBB78, 0x3460, 0x565B, 0xBB7A, 0, 0xBB79, 0, 0x565D, 0x565C, 0, 0, 0x565E, 0, 0xBB7B, 0xBB7C, 0, 0x565F, 0, 0x406E, 0x3D23, 0, 0xBB7D, 0x3D64, 0, 0x4163, 0xBB7E, 0x3929, 0x3A38, 0x392A, 0x3570, 0xBC21, 0, 0x5660, 0, 0, 0x3A39, 0, 0, 0x384A, 0x5661, 0x4C26, 0x4743, 0x5662, 0, 0x392B, 0xBC22, 0xBC23, 0, 0x342C, 0, 0x4327, 0x3652, 0, }; const unsigned short utf8_to_euc_E5B8[] = { 0xBC24, 0, 0x3B54, 0x495B, 0, 0, 0x4841, 0xBC25, 0, 0, 0, 0x5663, 0x3475, 0xBC26, 0, 0, 0, 0x5666, 0xBC27, 0, 0xBC28, 0xBC29, 0x4421, 0, 0xBC2A, 0x5665, 0x5664, 0x5667, 0, 0x446B, 0, 0xBC2B, 0xBC2C, 0, 0, 0, 0, 0x3F63, 0, 0, 0xBC2E, 0, 0, 0x3B55, 0, 0x404A, 0xBC2D, 0x4253, 0x3522, 0, 0xBC2F, 0x4422, 0, 0xBC30, 0x5668, 0x5669, 0x3E6F, 0, 0, 0, 0, 0x4B39, 0xBC31, 0, }; const unsigned short utf8_to_euc_E5B9[] = { 0x566C, 0, 0, 0x566B, 0x566A, 0x497D, 0, 0x5673, 0, 0xBC34, 0, 0xBC32, 0x4B5A, 0, 0x566D, 0, 0xBC33, 0xBC35, 0, 0, 0x566F, 0x4B6B, 0xBC36, 0x566E, 0xBC37, 0, 0, 0xBC38, 0xBC39, 0, 0xBC3A, 0x5670, 0, 0x4828, 0x5671, 0x4A3E, 0x5672, 0, 0, 0, 0xBC3B, 0, 0xBC3C, 0xBC3D, 0xBC3E, 0xBC3F, 0xBC40, 0, 0xBC41, 0, 0x3433, 0x4A3F, 0x472F, 0x5674, 0x5675, 0, 0x392C, 0x3434, 0x5676, 0x3838, 0x4D44, 0x4D29, 0x3476, 0x5678, }; const unsigned short utf8_to_euc_E5BA[] = { 0xBC42, 0x4423, 0, 0x392D, 0x3E31, 0, 0, 0x485F, 0, 0, 0x3E32, 0xBC43, 0, 0, 0xBC44, 0x3D78, 0, 0, 0, 0, 0, 0x446C, 0x4A79, 0x4539, 0, 0, 0x392E, 0, 0x495C, 0, 0, 0, 0x5679, 0, 0xBC45, 0, 0xBC46, 0xBC47, 0x4559, 0x3A42, 0xBC48, 0, 0xBC49, 0x384B, 0xBC4A, 0x446D, 0, 0, 0, 0xBC4B, 0, 0xBC4C, 0, 0x3043, 0x3D6E, 0x392F, 0x4D47, 0, 0, 0, 0, 0xBC4D, 0xBC4E, 0xBC4F, }; const unsigned short utf8_to_euc_E5BB[] = { 0, 0x567A, 0x567B, 0x4751, 0, 0, 0xBC50, 0, 0x567C, 0x4E77, 0x4F2D, 0xBC52, 0xBC51, 0, 0xBC53, 0x567E, 0x567D, 0xBC54, 0xBC55, 0x3347, 0xBC56, 0xBC57, 0x5721, 0, 0, 0, 0x5724, 0x5725, 0xBC58, 0x5723, 0xBC59, 0x4940, 0x3E33, 0x5727, 0x5726, 0x5722, 0, 0xBC5A, 0, 0, 0x5728, 0x5729, 0, 0xBC5B, 0x572A, 0, 0, 0, 0x572D, 0x572B, 0, 0x572C, 0x572E, 0, 0x3164, 0x446E, 0x572F, 0, 0x377A, 0x3276, 0x4736, 0, 0x5730, 0x467B, }; const unsigned short utf8_to_euc_E5BC[] = { 0, 0x4A5B, 0xBC5C, 0x5731, 0x4F2E, 0, 0xBC5D, 0xBC5E, 0xBC5F, 0x5732, 0x4A40, 0x5735, 0x5021, 0x5031, 0xBC60, 0x3C30, 0x4675, 0x5736, 0, 0x355D, 0x4424, 0x307A, 0x5737, 0x4A26, 0x3930, 0xBC61, 0, 0x4350, 0xBC62, 0xBC63, 0, 0x446F, 0, 0xBC64, 0xBC65, 0xBC66, 0xBC67, 0x4C6F, 0x3839, 0x384C, 0xBC68, 0x5738, 0, 0xBC69, 0xBC6A, 0x5739, 0xBC6B, 0x573F, 0xBC6C, 0x3C65, 0, 0, 0xBC6D, 0x4425, 0xBC6E, 0x362F, 0x573A, 0, 0, 0xBC6F, 0x492B, 0xBC70, 0x4346, 0xBC71, }; const unsigned short utf8_to_euc_E5BD[] = { 0xBC72, 0x573B, 0, 0, 0xBC73, 0xBC74, 0, 0xBC75, 0x573C, 0, 0x3630, 0, 0x573D, 0xBC76, 0x573E, 0, 0xBC77, 0x5740, 0, 0x4576, 0xBC78, 0, 0x5741, 0x5742, 0xBC79, 0x5743, 0, 0xBC7A, 0x5734, 0x5733, 0, 0, 0xBC7B, 0x5744, 0x3741, 0xBC7C, 0xBC7D, 0, 0x4927, 0xBC7E, 0, 0x3A4C, 0x4937, 0x4426, 0x494B, 0x5745, 0, 0xBD21, 0x3E34, 0x3146, 0xBD22, 0x5746, 0xBD23, 0xBD24, 0, 0x5747, 0xBD25, 0x4C72, 0xBD26, 0, 0x4860, 0xBD27, 0xBD28, 0x574A, }; const unsigned short utf8_to_euc_E5BE[] = { 0x317D, 0x402C, 0x5749, 0x5748, 0x3742, 0x4254, 0, 0x574E, 0x574C, 0xBD29, 0x574B, 0x4E27, 0x3865, 0xBD2A, 0, 0xBD2B, 0x3D79, 0x574D, 0x454C, 0x3D3E, 0, 0, 0xBD2C, 0x4640, 0x5751, 0x5750, 0, 0, 0xBD2D, 0xBD2E, 0x574F, 0, 0x5752, 0x3866, 0xBD2F, 0, 0xBD32, 0, 0, 0xBD30, 0x5753, 0x497C, 0x3D5B, 0xBD31, 0xBD33, 0x5754, 0x4879, 0xBD34, 0xBD35, 0xBD36, 0, 0x4641, 0x4427, 0, 0, 0xF43E, 0xBD37, 0x4530, 0, 0, 0x5755, 0x352B, 0, 0, }; const unsigned short utf8_to_euc_E5BF[] = { 0, 0, 0, 0x3F34, 0xBD38, 0x492C, 0, 0xBD39, 0xBD3A, 0xBD3B, 0, 0xBD3C, 0x3477, 0x4726, 0, 0, 0xBD3D, 0xBD3E, 0xBD3F, 0xBD40, 0xBD41, 0, 0x5756, 0x3B56, 0x4B3A, 0x4B3B, 0, 0, 0x317E, 0x575B, 0xBD42, 0, 0x4369, 0xBD43, 0xBD44, 0, 0x5758, 0, 0, 0, 0xBD45, 0xBD46, 0xBD47, 0x3277, 0xBD48, 0xBD49, 0xBD4A, 0xBD4B, 0x582D, 0x575A, 0xBD4C, 0xBD4D, 0, 0x4730, 0xBD4E, 0, 0x5759, 0, 0xBD4F, 0x5757, 0xBD50, 0x397A, 0, 0x575D, }; const unsigned short utf8_to_euc_E680[] = { 0, 0, 0, 0, 0, 0, 0, 0xBD51, 0, 0, 0xBD52, 0, 0, 0xBD53, 0x5763, 0x5769, 0x5761, 0, 0x455C, 0xBD54, 0xBD55, 0x5766, 0x495D, 0xBD56, 0xBD57, 0x5760, 0xBD58, 0x5765, 0x4E67, 0x3B57, 0, 0xBD59, 0x4255, 0x575E, 0, 0, 0xBD5A, 0x355E, 0x5768, 0x402D, 0x3165, 0x5762, 0x3278, 0x5767, 0, 0xBD5B, 0, 0x3631, 0, 0x5764, 0, 0xBD5C, 0, 0xBD5D, 0, 0, 0, 0, 0x576A, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E681[] = { 0xBD5E, 0x576C, 0x5776, 0x5774, 0, 0, 0x5771, 0xBD5F, 0xBD60, 0xBD61, 0x5770, 0x4E78, 0xBD62, 0x5772, 0, 0, 0x3632, 0xBD63, 0x3931, 0, 0xBD64, 0x3D7A, 0xBD65, 0xBD66, 0, 0x5779, 0x576B, 0, 0, 0xBD67, 0, 0x576F, 0x575F, 0xBD68, 0x327A, 0x5773, 0x5775, 0x4351, 0, 0xBD69, 0x3A28, 0x3238, 0x576D, 0x5778, 0x5777, 0x3633, 0, 0x4229, 0x3366, 0xBD6A, 0, 0, 0, 0x3743, 0, 0x576E, 0, 0, 0, 0, 0, 0, 0xBD6B, 0xBD6C, }; const unsigned short utf8_to_euc_E682[] = { 0, 0x577A, 0xBD6D, 0x577D, 0x5821, 0xF43F, 0xBD6E, 0, 0xBD6F, 0x3C3D, 0xBD70, 0x5827, 0x4470, 0x577B, 0xBD71, 0, 0, 0xBD72, 0x5825, 0xBD73, 0x3279, 0xBD74, 0x5823, 0x5824, 0xBD75, 0, 0x577E, 0x5822, 0, 0xBD76, 0xBD77, 0x3867, 0x4D2A, 0, 0xBD78, 0x3435, 0xBD79, 0xBD7A, 0x3159, 0x5826, 0xBD7B, 0x473A, 0x302D, 0, 0, 0, 0, 0, 0xBD7C, 0xBD7D, 0x4861, 0x575C, 0x582C, 0x5830, 0x4C65, 0xBD7E, 0x5829, 0, 0, 0xBE21, 0x4569, 0x582E, 0xBE22, 0, }; const unsigned short utf8_to_euc_E683[] = { 0, 0, 0xBE23, 0, 0xBE24, 0x3E70, 0x582F, 0x4657, 0xBE25, 0xBE26, 0xBE27, 0xBE28, 0, 0, 0xBE29, 0xBE2A, 0, 0x4F47, 0, 0x582B, 0xBE2B, 0xBE2C, 0, 0, 0x5831, 0xBE2D, 0x397B, 0xBE2E, 0x404B, 0xBE2F, 0xBE30, 0x3054, 0x582A, 0x5828, 0xBE31, 0x415A, 0, 0xBE32, 0, 0x577C, 0x3B34, 0, 0, 0, 0, 0, 0, 0, 0x4246, 0x583D, 0xBE33, 0x415B, 0x5838, 0xBE34, 0x5835, 0x5836, 0xBE35, 0x3C66, 0x5839, 0x583C, 0xBE36, 0xBE37, 0, 0, }; const unsigned short utf8_to_euc_E684[] = { 0x5837, 0x3D25, 0xBE38, 0x583A, 0, 0, 0x5834, 0xBE39, 0x4C7C, 0x4C7B, 0xBE3A, 0, 0xBE3B, 0x583E, 0x583F, 0x3055, 0xBE3C, 0xBE3D, 0xBE3E, 0xBE3F, 0xBE40, 0x5833, 0xBE41, 0xBE42, 0, 0xBE43, 0x3672, 0x3026, 0xBE44, 0, 0xBE45, 0x3436, 0xF440, 0x583B, 0xBE46, 0, 0, 0, 0, 0x5843, 0x5842, 0, 0xBE47, 0xBE48, 0x5847, 0, 0, 0, 0xBE49, 0xBE4A, 0, 0, 0x5848, 0xBE4B, 0xBE4C, 0xBE4D, 0, 0xBE4E, 0, 0, 0x5846, 0x5849, 0x5841, 0x5845, }; const unsigned short utf8_to_euc_E685[] = { 0, 0xBE4F, 0x584A, 0, 0x584B, 0xBE50, 0xBE51, 0x5840, 0x3B7C, 0xBE52, 0x5844, 0x4256, 0x3932, 0x5832, 0x3F35, 0, 0, 0, 0, 0x5858, 0, 0x4A69, 0, 0, 0x584E, 0x584F, 0x5850, 0, 0, 0x5857, 0xBE53, 0x5856, 0xBE54, 0, 0x4B7D, 0x3437, 0, 0x5854, 0, 0x3745, 0x3334, 0, 0, 0x5851, 0xBE55, 0, 0x4E38, 0x5853, 0x3056, 0x5855, 0xBE56, 0x584C, 0x5852, 0x5859, 0x3744, 0x584D, 0xBE57, 0, 0, 0xBE58, 0xBE59, 0, 0x4D5D, 0xBE5A, }; const unsigned short utf8_to_euc_E686[] = { 0xBE5B, 0xBE5C, 0x4D2B, 0xBE5D, 0xBE5E, 0, 0, 0x585C, 0, 0, 0x5860, 0xBE5F, 0, 0xBE60, 0x417E, 0, 0x4E79, 0x5861, 0xBE61, 0xBE62, 0x585E, 0, 0x585B, 0xBE63, 0xBE64, 0x585A, 0x585F, 0, 0xBE65, 0xBE66, 0, 0xBE67, 0xBE68, 0, 0, 0, 0x4A30, 0xBE69, 0, 0x4634, 0xBE6A, 0x3746, 0xBE6B, 0x5862, 0x585D, 0xBE6C, 0x5863, 0, 0, 0, 0x377B, 0, 0, 0, 0x3231, 0, 0xBE6D, 0xBE6E, 0x586B, 0, 0xBE6F, 0, 0x3438, 0, }; const unsigned short utf8_to_euc_E687[] = { 0xBE70, 0xBE71, 0xBE72, 0x5869, 0, 0, 0x586A, 0x3A29, 0x5868, 0x5866, 0x5865, 0x586C, 0x5864, 0x586E, 0xBE73, 0xBE74, 0x327B, 0, 0, 0, 0, 0xBE75, 0, 0, 0, 0, 0, 0, 0xBE76, 0xBE77, 0xBE78, 0xBE79, 0, 0xBE7A, 0xBE7B, 0x5870, 0, 0xBE7E, 0x586F, 0xBE7C, 0, 0xBE7D, 0, 0, 0xBF21, 0xBF22, 0, 0xBF23, 0, 0, 0x4428, 0, 0x5873, 0, 0x5871, 0x5867, 0x377C, 0, 0x5872, 0, 0x5876, 0x5875, 0x5877, 0x5874, }; const unsigned short utf8_to_euc_E688[] = { 0x5878, 0xBF24, 0, 0xBF25, 0xBF26, 0, 0, 0xBF27, 0x5879, 0x587A, 0x4A6A, 0, 0x587C, 0x587B, 0x3D3F, 0, 0x402E, 0x3266, 0x327C, 0xBF28, 0x587D, 0xBF29, 0x303F, 0, 0, 0, 0x404C, 0x587E, 0xBF2A, 0x6C43, 0x5921, 0x3761, 0xBF2B, 0x5922, 0xBF2C, 0xBF2D, 0, 0, 0x406F, 0xBF2E, 0, 0xBF2F, 0x5923, 0xBF30, 0, 0, 0x5924, 0x353A, 0x5925, 0, 0x5926, 0x5927, 0x4257, 0, 0, 0, 0x384D, 0xBF31, 0, 0x4C61, 0, 0xBF32, 0, 0x4B3C, }; const unsigned short utf8_to_euc_E689[] = { 0x3D6A, 0x5928, 0xBF33, 0xBF34, 0xBF35, 0, 0xBF36, 0x4070, 0x6E3D, 0x4862, 0, 0x3C6A, 0xBF37, 0x3A4D, 0x5929, 0, 0xBF38, 0xBF39, 0xBF3A, 0x4247, 0xBF3B, 0x4A27, 0xBF3C, 0, 0x4271, 0, 0xBF3D, 0x592C, 0xBF3E, 0, 0x592A, 0, 0x592D, 0, 0, 0x592B, 0xBF3F, 0, 0, 0, 0x592E, 0, 0, 0, 0, 0xBF40, 0x4A31, 0xBF41, 0, 0x3037, 0, 0xBF42, 0, 0, 0x495E, 0, 0, 0x4863, 0xBF43, 0, 0x592F, 0xBF44, 0x5932, 0x3E35, }; const unsigned short utf8_to_euc_E68A[] = { 0x353B, 0, 0x5930, 0x5937, 0x3E36, 0, 0, 0, 0, 0x5931, 0x4744, 0, 0, 0xBF45, 0xBF46, 0xBF47, 0xBF48, 0x4D5E, 0x5933, 0x5934, 0x5938, 0x456A, 0x5935, 0x3933, 0x405E, 0, 0, 0x5946, 0x4834, 0, 0x4272, 0, 0, 0, 0, 0, 0, 0, 0xBF49, 0, 0xBF4A, 0, 0, 0x4864, 0x5A2D, 0, 0, 0, 0, 0x4A7A, 0, 0xBF4B, 0, 0x4471, 0xBF4C, 0xBF4D, 0, 0x4B75, 0xBF4E, 0x593B, 0x3221, 0x436A, 0xBF4F, 0xBF50, }; const unsigned short utf8_to_euc_E68B[] = { 0, 0, 0x5944, 0, 0xBF51, 0x4334, 0x593E, 0x5945, 0x5940, 0x5947, 0x5943, 0, 0x5942, 0x476F, 0xBF52, 0x593C, 0x327D, 0x593A, 0x3571, 0x4273, 0x5936, 0xBF53, 0xBF54, 0x5939, 0x3934, 0x405B, 0xBF55, 0x3E37, 0x5941, 0x4752, 0, 0, 0x3572, 0x3348, 0, 0, 0, 0, 0, 0, 0, 0, 0xBF56, 0, 0x3367, 0x3F21, 0x5949, 0x594E, 0, 0x594A, 0xBF57, 0x377D, 0xBF58, 0x594F, 0x3B22, 0x3969, 0, 0, 0, 0, 0xBF59, 0xBF5A, 0x3D26, 0x593D, }; const unsigned short utf8_to_euc_E68C[] = { 0, 0x3B7D, 0x594C, 0xBF5B, 0xBF5C, 0, 0, 0x3B58, 0x594D, 0x3044, 0xBF5D, 0xBF5E, 0x5948, 0xBF5F, 0, 0, 0xBF60, 0x4429, 0, 0xBF61, 0, 0, 0xBF62, 0, 0xBF63, 0x3573, 0, 0, 0, 0, 0, 0x3634, 0, 0, 0, 0, 0, 0, 0, 0x594B, 0x3027, 0xBF64, 0xBF65, 0x3A43, 0, 0xBF66, 0, 0x3F36, 0, 0, 0, 0, 0, 0xBF67, 0xBF68, 0, 0, 0xBF69, 0x4472, 0, 0xBF6A, 0x4854, 0x5951, 0x415E, }; const unsigned short utf8_to_euc_E68D[] = { 0, 0xBF6B, 0xBF6C, 0xBF6D, 0xBF6E, 0, 0xBF6F, 0, 0, 0x422A, 0xBF70, 0xBF71, 0x3B2B, 0x5952, 0xBF72, 0x5954, 0x5950, 0, 0xBF73, 0xBF74, 0xBF75, 0x4A61, 0, 0x443D, 0xBF76, 0, 0, 0xBF77, 0x415C, 0, 0, 0, 0, 0, 0, 0, 0, 0xBF78, 0xBF79, 0x4A7B, 0x3C4E, 0x5960, 0, 0x595F, 0xBF7A, 0xBF7B, 0x3F78, 0, 0, 0xBF7C, 0x377E, 0, 0xBF7D, 0xBF7E, 0x5959, 0x3E39, 0xC021, 0, 0x4668, 0x4731, 0xC022, 0xC023, 0, 0xC024, }; const unsigned short utf8_to_euc_E68E[] = { 0x5957, 0, 0xC025, 0x415D, 0xC026, 0, 0, 0xC027, 0x3C78, 0x595C, 0xC028, 0, 0x3E38, 0, 0x5956, 0x595B, 0xC029, 0, 0x4753, 0, 0xC02A, 0xC02B, 0x5955, 0, 0x3721, 0xC02C, 0xC02D, 0x335D, 0, 0, 0xC02E, 0x595D, 0x4E2B, 0x3A4E, 0x4335, 0x595A, 0xC02F, 0x405C, 0xC030, 0x3935, 0x3F64, 0x3166, 0x413C, 0x5958, 0x3545, 0xC031, 0xC032, 0xC033, 0, 0, 0x3747, 0, 0x444F, 0x595E, 0, 0, 0, 0, 0, 0x415F, 0, 0xC034, 0x5961, 0, }; const unsigned short utf8_to_euc_E68F[] = { 0x5963, 0xC035, 0, 0x4237, 0x5969, 0xC036, 0x5964, 0, 0xC037, 0x5966, 0, 0, 0, 0, 0xC038, 0x4941, 0x4473, 0xC039, 0x5967, 0xC03A, 0xC03B, 0xC03C, 0x4D2C, 0, 0, 0, 0x4D48, 0x3439, 0xC03D, 0, 0, 0, 0xC03E, 0x302E, 0, 0x5965, 0, 0xC03F, 0, 0, 0, 0x5962, 0xC040, 0, 0xC041, 0, 0x3478, 0, 0, 0, 0xC042, 0xC043, 0x3167, 0xC044, 0x5968, 0, 0xC045, 0xC046, 0x4D49, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E690[] = { 0, 0, 0, 0, 0, 0, 0x596C, 0, 0, 0xC047, 0xC048, 0, 0, 0x423B, 0, 0x5973, 0xC049, 0, 0xC04A, 0x596D, 0xC04B, 0, 0x596A, 0x5971, 0xC04C, 0, 0, 0, 0x5953, 0, 0xC04D, 0, 0xC04E, 0, 0xC04F, 0, 0xC050, 0xC051, 0x596E, 0, 0x5972, 0xC052, 0xC053, 0, 0x4842, 0x456B, 0, 0xC054, 0xC055, 0, 0, 0, 0x596B, 0xC056, 0x596F, 0, 0, 0, 0x3748, 0, 0, 0xC057, 0x3A71, 0xC058, }; const unsigned short utf8_to_euc_E691[] = { 0, 0, 0x405D, 0, 0, 0, 0, 0, 0, 0, 0, 0xC059, 0, 0, 0x5977, 0xC05A, 0, 0xC05B, 0xC05C, 0xC05D, 0xC05E, 0, 0, 0, 0x4526, 0, 0xC05F, 0xC060, 0xC061, 0xC062, 0, 0xC063, 0xC064, 0xC065, 0, 0xC066, 0, 0, 0, 0x5974, 0, 0x4B60, 0, 0, 0, 0xC067, 0, 0x5975, 0, 0, 0, 0xC068, 0xC069, 0, 0x5976, 0, 0x4C4E, 0, 0x4022, 0xC06A, 0, 0xC06B, 0, 0, }; const unsigned short utf8_to_euc_E692[] = { 0, 0, 0, 0x3762, 0, 0xC06C, 0, 0xC06D, 0x597D, 0, 0, 0, 0, 0, 0, 0xC06E, 0xC06F, 0xC070, 0x3B35, 0x597A, 0, 0x5979, 0, 0, 0xC071, 0xC072, 0x4732, 0xC073, 0, 0xC074, 0x4635, 0xC075, 0, 0xC076, 0, 0xC077, 0x4531, 0x597B, 0xC078, 0, 0xC079, 0x597C, 0, 0x496F, 0xC07A, 0x4745, 0x3B23, 0, 0x4071, 0, 0x4B50, 0xC07B, 0, 0, 0, 0, 0, 0x3349, 0, 0x5A25, 0x597E, 0xC07C, 0xC07D, 0xC07E, }; const unsigned short utf8_to_euc_E693[] = { 0, 0x4D4A, 0x5A27, 0, 0xC121, 0x5A23, 0, 0x5A24, 0, 0xC122, 0xC123, 0xC124, 0xC125, 0x4160, 0xC126, 0, 0xC127, 0xC128, 0x5A22, 0, 0x593F, 0xC129, 0, 0xC12A, 0x5A26, 0, 0x5A21, 0, 0, 0, 0, 0, 0x5A2B, 0x5A2C, 0x4527, 0x5A2E, 0xC12B, 0xC12C, 0x3B24, 0x5A29, 0, 0xC12D, 0xC12E, 0, 0x353C, 0xC12F, 0, 0x5A2F, 0xC130, 0x5A28, 0x5A33, 0, 0x5A32, 0xC131, 0x5A31, 0xC132, 0, 0, 0x5A34, 0xC133, 0, 0x5A36, 0x3E71, 0xC134, }; const unsigned short utf8_to_euc_E694[] = { 0x5A35, 0xC135, 0, 0, 0xC136, 0x5A39, 0, 0, 0xC137, 0xC138, 0xC139, 0, 0, 0, 0, 0xC13A, 0, 0, 0, 0xC13B, 0xC13C, 0, 0xC13D, 0, 0x5A37, 0xC13E, 0, 0xC13F, 0x5A38, 0x5970, 0xC140, 0xC141, 0, 0, 0xC142, 0x5A3B, 0x5A3A, 0, 0xC143, 0, 0, 0xC144, 0x5978, 0x5A3C, 0x5A30, 0, 0xC145, 0x3B59, 0, 0xC146, 0, 0, 0x5A3D, 0x5A3E, 0x5A40, 0x5A3F, 0x5A41, 0x327E, 0xC147, 0x3936, 0xC148, 0xC149, 0x4A7C, 0x402F, }; const unsigned short utf8_to_euc_E695[] = { 0, 0, 0, 0xC14A, 0, 0x384E, 0, 0xC14B, 0x5A43, 0xC14C, 0, 0, 0, 0x5A46, 0xF441, 0x4952, 0xC14D, 0x355F, 0xC14E, 0, 0xC14F, 0x5A45, 0x5A44, 0x4754, 0x5A47, 0x3635, 0, 0, 0, 0x5A49, 0x5A48, 0xC150, 0xC151, 0, 0x343A, 0x3B36, 0, 0, 0x4658, 0xC152, 0, 0, 0, 0xC153, 0x3749, 0, 0, 0, 0x3F74, 0, 0x5A4A, 0, 0x4030, 0x4528, 0, 0x495F, 0x5A4B, 0, 0xC154, 0, 0, 0xC155, 0, 0, }; const unsigned short utf8_to_euc_E696[] = { 0, 0xC156, 0x5A4C, 0x5A4D, 0, 0xC157, 0, 0x4A38, 0x555D, 0x4046, 0xC158, 0, 0x494C, 0, 0x3A58, 0, 0x4865, 0x4843, 0xC159, 0, 0, 0xC15A, 0, 0x454D, 0xC15B, 0x4E41, 0, 0x5A4F, 0x3C50, 0xC15C, 0, 0x5A50, 0xC15D, 0x3036, 0, 0xC15E, 0x3654, 0x404D, 0xC15F, 0x4960, 0, 0, 0, 0x5A51, 0x3B42, 0x4347, 0xC160, 0x3B5B, 0x3F37, 0, 0xC161, 0xC162, 0xC163, 0, 0, 0x5A52, 0, 0x4A7D, 0, 0, 0x3177, 0x3B5C, 0, 0xC164, }; const unsigned short utf8_to_euc_E697[] = { 0, 0x5A55, 0xC165, 0x5A53, 0x5A56, 0x4E39, 0x5A54, 0, 0xC166, 0xC167, 0, 0x407B, 0x5A57, 0, 0xC168, 0x4232, 0xC169, 0, 0x5A58, 0, 0xC16A, 0, 0xC16B, 0x347A, 0xC16C, 0x5A5A, 0, 0x5A59, 0, 0, 0, 0xC16D, 0x5A5B, 0x5A5C, 0x347B, 0, 0, 0x467C, 0x4336, 0x356C, 0x3B5D, 0x4161, 0, 0, 0x3D5C, 0x3030, 0, 0, 0xC16E, 0x5A5D, 0xC16F, 0, 0xC170, 0xC171, 0, 0, 0, 0xC172, 0x3222, 0x5A61, 0, 0, 0xC173, 0xC174, }; const unsigned short utf8_to_euc_E698[] = { 0xC175, 0, 0x3937, 0x5A60, 0xC176, 0, 0x3A2B, 0x3E3A, 0xC177, 0xC178, 0x5A5F, 0, 0x3E3B, 0xC179, 0x4C40, 0x3A2A, 0, 0xC17A, 0xC17B, 0x3057, 0x404E, 0xC17C, 0xC17D, 0, 0, 0, 0, 0, 0x5A66, 0xC17E, 0xC221, 0x4031, 0x3147, 0xC222, 0xC223, 0xC224, 0xC225, 0x3D55, 0xC226, 0x4B66, 0x3A72, 0xC227, 0xC228, 0xC229, 0xC22A, 0x3E3C, 0xC22B, 0x4027, 0xC22C, 0xC22D, 0, 0xC22E, 0x5A65, 0x5A63, 0x5A64, 0xC230, 0, 0xC22F, 0, 0xF442, 0x436B, 0, 0, 0x5B26, }; const unsigned short utf8_to_euc_E699[] = { 0xC231, 0x5A6A, 0x3B7E, 0x3938, 0x5A68, 0xC232, 0xC233, 0, 0, 0x5A69, 0xC234, 0x3F38, 0xC235, 0, 0xC237, 0x5A67, 0, 0xC236, 0x3B2F, 0, 0, 0, 0, 0xC238, 0xC239, 0xC23A, 0, 0xC23B, 0xC23C, 0x5A6C, 0x5A6B, 0x5A70, 0xC23D, 0xC23E, 0x5A71, 0, 0x5A6D, 0xF443, 0x3322, 0x5A6E, 0x5A6F, 0x4855, 0xC240, 0xC241, 0xC242, 0, 0x4961, 0x374A, 0x5A72, 0, 0, 0xC244, 0x4032, 0xC245, 0x3E3D, 0xC247, 0xC248, 0xC249, 0x4352, 0xC24A, 0xC24C, 0, 0xC243, 0xC246, }; const unsigned short utf8_to_euc_E69A[] = { 0xC24B, 0x3647, 0, 0x5A73, 0x5A77, 0, 0, 0x324B, 0x5A74, 0x5A76, 0, 0xC24D, 0xC24E, 0xC24F, 0x5A75, 0, 0xC250, 0x3D6B, 0xC251, 0, 0, 0, 0x4348, 0x3045, 0x5A78, 0xC252, 0xC253, 0xC254, 0xC255, 0x5A79, 0, 0xC256, 0xC257, 0, 0x442A, 0, 0xC258, 0, 0x4E71, 0, 0, 0, 0, 0x3B43, 0, 0xC259, 0x4A6B, 0, 0, 0xC25A, 0xC25B, 0, 0x4B3D, 0xC25C, 0, 0, 0x5B22, 0x5A7B, 0, 0xC25D, 0x5A7E, 0, 0x5A7D, 0xC25E, }; const unsigned short utf8_to_euc_E69B[] = { 0xC25F, 0x5A7A, 0xC260, 0xC261, 0x5B21, 0, 0, 0x465E, 0xC262, 0x5A7C, 0, 0, 0xC263, 0, 0xC264, 0xC265, 0, 0, 0, 0, 0xC266, 0, 0x5B23, 0, 0, 0x3D6C, 0x5B24, 0xC267, 0x4D4B, 0x4778, 0, 0xC268, 0x5B25, 0, 0, 0, 0, 0, 0x5B27, 0, 0xC269, 0x5B28, 0, 0xC26A, 0xC26B, 0, 0xC26C, 0, 0x5B29, 0, 0x364A, 0x3148, 0x3939, 0x5B2A, 0, 0x5B2B, 0x3D71, 0x4162, 0xC26D, 0xC23F, 0x5258, 0x413E, 0x413D, 0x4258, }; const unsigned short utf8_to_euc_E69C[] = { 0x3A47, 0, 0, 0x5072, 0, 0xC26E, 0, 0xC26F, 0x376E, 0x4D2D, 0, 0x4A7E, 0, 0x497E, 0xC270, 0x5B2C, 0, 0, 0, 0xC271, 0x3A73, 0x443F, 0x5B2D, 0x4F2F, 0, 0xC272, 0, 0x4B3E, 0xC273, 0x442B, 0x5B2E, 0x347C, 0xC274, 0, 0xC275, 0, 0, 0, 0x5B2F, 0x5B30, 0x4C5A, 0, 0x4C24, 0x4B76, 0x4B5C, 0x3B25, 0x5B32, 0, 0, 0x3C6B, 0, 0xC276, 0x4B51, 0, 0x5B34, 0x5B37, 0x5B36, 0, 0x3479, 0, 0, 0x3560, 0xC277, 0x5B33, }; const unsigned short utf8_to_euc_E69D[] = { 0, 0x5B35, 0, 0, 0, 0xC278, 0x5B38, 0xC279, 0xC27A, 0x3F79, 0, 0, 0xC27B, 0, 0x4D7B, 0x3049, 0x3A60, 0x423C, 0, 0x3C5D, 0xC27C, 0xC27D, 0x3E73, 0, 0, 0x5B3B, 0, 0, 0x454E, 0xC27E, 0x5B39, 0x422B, 0x5B3A, 0x3E72, 0x4C5D, 0x5B3C, 0x5B3D, 0x4D68, 0xC321, 0, 0, 0, 0x5B42, 0, 0xC322, 0x393A, 0xC323, 0x4755, 0x5B3F, 0x456C, 0x5A5E, 0x5A62, 0xC324, 0x354F, 0xC325, 0x4747, 0, 0, 0, 0xC326, 0x5B41, 0, 0x3E3E, 0x4844, }; const unsigned short utf8_to_euc_E69E[] = { 0, 0xC327, 0, 0, 0xC328, 0x5B47, 0, 0x487A, 0, 0x5B3E, 0, 0x5B44, 0x5B43, 0, 0xC329, 0xC32A, 0x404F, 0xC32B, 0, 0xC32C, 0, 0x4B6D, 0xC32D, 0x4E53, 0xC32E, 0xC32F, 0x4B67, 0xC330, 0x324C, 0x3B5E, 0, 0, 0x4F48, 0x5B46, 0x3F75, 0, 0, 0, 0x5B45, 0, 0, 0x5B40, 0, 0, 0, 0, 0, 0x384F, 0xC331, 0xC332, 0xC333, 0x5B4C, 0x5B4A, 0xC334, 0x324D, 0x5B48, 0x5B4E, 0x5B54, 0, 0xC335, 0xC336, 0xC337, 0, 0, }; const unsigned short utf8_to_euc_E69F[] = { 0xC339, 0x4248, 0xC33A, 0xC33B, 0x4A41, 0xC33C, 0x5B56, 0, 0xC33D, 0xC33E, 0x4922, 0, 0, 0, 0x5B55, 0x4770, 0x4B3F, 0x343B, 0xC33F, 0x4077, 0x3D40, 0, 0, 0xC340, 0x4453, 0xC341, 0x4D2E, 0, 0xC342, 0x5B51, 0x5B50, 0, 0, 0xC343, 0x5B52, 0, 0x5B4F, 0, 0xC344, 0x5B57, 0, 0x5B4D, 0, 0, 0x5B4B, 0, 0x5B53, 0x5B49, 0xC345, 0x436C, 0xC346, 0x4C78, 0x3C46, 0x3A74, 0xC347, 0xC348, 0, 0xC338, 0, 0x3A3A, 0, 0, 0x4B6F, 0x3341, }; const unsigned short utf8_to_euc_E6A0[] = { 0, 0xF446, 0x444E, 0x464A, 0x3149, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x4072, 0xC34A, 0, 0x4034, 0x372A, 0, 0xC34B, 0, 0, 0, 0xC34C, 0x5B59, 0xC34D, 0, 0x393B, 0x337C, 0, 0, 0, 0, 0xC34F, 0xC34E, 0x5B5B, 0x3374, 0x5B61, 0xC350, 0xC351, 0, 0xC352, 0xC353, 0xC354, 0x5B5E, 0xC355, 0x4073, 0, 0, 0, 0x334B, 0x3A2C, 0, 0xC356, 0x334A, 0x3A4F, 0, 0xC357, }; const unsigned short utf8_to_euc_E6A1[] = { 0x5B5C, 0x3765, 0x374B, 0x456D, 0xC358, 0xC359, 0x5B5A, 0, 0x3046, 0, 0xC35A, 0, 0xC35B, 0x5B5D, 0x5B5F, 0, 0x364D, 0x372C, 0xC349, 0x343C, 0x354B, 0xC35C, 0, 0xC35D, 0xC35E, 0x5B62, 0, 0xC35F, 0x3A79, 0x4B71, 0, 0x3B37, 0, 0, 0, 0x5B63, 0, 0, 0, 0x4930, 0, 0, 0, 0xC360, 0, 0, 0xC361, 0xC362, 0xC363, 0xC364, 0xC365, 0, 0x5B6F, 0xC366, 0x3233, 0x5B64, 0, 0xC367, 0xC368, 0xC369, 0xC36A, 0, 0x5B75, 0x5B65, }; const unsigned short utf8_to_euc_E6A2[] = { 0, 0x4E42, 0xC36B, 0x5B6C, 0xC36C, 0x475F, 0xC36D, 0, 0xC36E, 0, 0, 0, 0, 0x5B74, 0, 0x5B67, 0, 0, 0, 0x3034, 0x5B69, 0, 0xC36F, 0x393C, 0xC370, 0, 0xC371, 0x5B6B, 0xC372, 0x5B6A, 0, 0x5B66, 0x5B71, 0xC373, 0x3E3F, 0xC374, 0, 0xC375, 0x546D, 0x3868, 0x4D7C, 0xC376, 0xC377, 0, 0, 0x5B68, 0xC378, 0x4474, 0x3323, 0x3A2D, 0xC379, 0x5B60, 0, 0x5B70, 0x3361, 0, 0, 0x5B6E, 0x5B72, 0xC37A, 0x456E, 0, 0, 0, }; const unsigned short utf8_to_euc_E6A3[] = { 0, 0, 0, 0, 0x347E, 0xC37B, 0x5C32, 0, 0xC37C, 0x4C49, 0x5B77, 0x347D, 0xC37D, 0x5B7E, 0, 0xC37E, 0xC421, 0xC422, 0x4B40, 0xC423, 0x5C21, 0x5C23, 0xC424, 0x5C27, 0x5B79, 0xC425, 0x432A, 0, 0xC426, 0xC427, 0, 0x456F, 0x5C2B, 0x5B7C, 0, 0x5C28, 0, 0xC428, 0, 0x5C22, 0xC429, 0, 0xC42A, 0xC42B, 0xC42C, 0xC42D, 0x3F39, 0x5C2C, 0xC42E, 0xC42F, 0x4033, 0, 0, 0xC430, 0xC431, 0, 0, 0x5C2A, 0x343D, 0xC432, 0xC433, 0xC434, 0, 0, }; const unsigned short utf8_to_euc_E6A4[] = { 0x4F50, 0x5B76, 0, 0, 0x5C26, 0x3058, 0xC435, 0, 0x5B78, 0xC436, 0xC437, 0x4C3A, 0x5B7D, 0x3F22, 0x4447, 0x5B73, 0xC438, 0xC439, 0x5C25, 0xC43A, 0, 0, 0xC43B, 0xC43C, 0, 0x3F7A, 0x5C2F, 0x3371, 0x3821, 0, 0, 0, 0, 0x5C31, 0x5B7A, 0x5C30, 0, 0x5C29, 0x5B7B, 0, 0x5C2D, 0, 0x5C2E, 0, 0, 0, 0, 0, 0x5C3F, 0xC43D, 0, 0xC43E, 0x464E, 0xC43F, 0x5C24, 0, 0xC440, 0x5C3B, 0, 0xC441, 0, 0x5C3D, 0, 0x4458, }; const unsigned short utf8_to_euc_E6A5[] = { 0, 0, 0xC442, 0, 0, 0xC443, 0, 0, 0, 0xC444, 0x4D4C, 0, 0, 0, 0xC445, 0, 0, 0, 0, 0x4976, 0x5C38, 0x424A, 0, 0xC446, 0, 0x5C3E, 0x413F, 0xC447, 0x5C35, 0x5C42, 0x5C41, 0, 0x466F, 0x5C40, 0x466A, 0xC448, 0xC449, 0xC44A, 0xC44B, 0, 0xC44C, 0xC44D, 0x5C44, 0x5C37, 0xC44E, 0x3648, 0x5C3A, 0x3D5D, 0xC44F, 0xC450, 0xC451, 0x4760, 0x5C3C, 0x364B, 0, 0x5C34, 0x5C36, 0x5C33, 0xC452, 0xC453, 0x4F30, 0x335A, 0x5C39, 0xC454, }; const unsigned short utf8_to_euc_E6A6[] = { 0xC455, 0x5C43, 0x3335, 0, 0, 0, 0, 0, 0, 0, 0x3A67, 0, 0, 0xC456, 0x315D, 0, 0, 0x5C54, 0xC457, 0, 0x4F31, 0x5C57, 0xC458, 0, 0xC459, 0, 0, 0x3F3A, 0x5C56, 0, 0, 0, 0x5C55, 0xC45A, 0, 0, 0, 0xC45B, 0xC45C, 0x5C52, 0xC45D, 0, 0, 0xC45E, 0, 0xC45F, 0x5C46, 0xC460, 0, 0x5C63, 0x5C45, 0, 0x5C58, 0, 0, 0xC461, 0xC462, 0, 0xC463, 0x5C50, 0xC464, 0, 0x5C4B, 0x5C48, }; const unsigned short utf8_to_euc_E6A7[] = { 0, 0x5C49, 0, 0x5C51, 0, 0xC465, 0, 0x7422, 0xC466, 0, 0x5C4E, 0x393D, 0x4448, 0x4164, 0x5C4C, 0, 0x5C47, 0xC467, 0, 0x5C4A, 0, 0, 0xC468, 0xC469, 0x4D4D, 0x4B6A, 0, 0, 0, 0x5C4F, 0x5C59, 0, 0, 0, 0xC46A, 0, 0, 0xC46B, 0, 0x5C61, 0x5C5A, 0, 0, 0x5C67, 0, 0x5C65, 0xC46C, 0xC46D, 0, 0xC46E, 0x5C60, 0xC46F, 0, 0xC470, 0, 0, 0, 0x5C5F, 0, 0x4450, 0, 0x4165, 0xC471, 0x5C5D, }; const unsigned short utf8_to_euc_E6A8[] = { 0xC472, 0xC473, 0x5C5B, 0xC474, 0, 0x5C62, 0, 0, 0, 0, 0x5C68, 0x4875, 0x5C6E, 0, 0, 0xC475, 0, 0xC476, 0x5C69, 0x5C6C, 0x5C66, 0xC477, 0, 0x4374, 0, 0x4938, 0xC478, 0x5C5C, 0, 0xC479, 0x5C64, 0x3E40, 0xC47A, 0x4C4F, 0x5C78, 0x5C6B, 0xC47B, 0, 0, 0, 0xC47C, 0x3822, 0x3223, 0x335F, 0, 0, 0x5C53, 0, 0xC47D, 0, 0xC47E, 0, 0xC521, 0x3E41, 0x5C70, 0xC522, 0x5C77, 0x3C79, 0x3372, 0xC523, 0, 0x432E, 0xC524, 0xC525, }; const unsigned short utf8_to_euc_E6A9[] = { 0, 0, 0, 0, 0x5C6D, 0xC526, 0xC527, 0x5C72, 0x5C76, 0xC528, 0xC529, 0x3636, 0, 0, 0xC52A, 0, 0xC52B, 0xC52C, 0xC52D, 0, 0, 0xC52E, 0xC52F, 0, 0x354C, 0x5C74, 0, 0xC530, 0, 0, 0, 0x3521, 0, 0x464B, 0x5C73, 0, 0xC531, 0, 0x5C75, 0xC532, 0, 0, 0xC533, 0xF449, 0, 0, 0, 0, 0, 0xC534, 0x5C6F, 0xC535, 0, 0, 0, 0, 0x5C71, 0, 0, 0, 0, 0, 0xC536, 0x3360, }; const unsigned short utf8_to_euc_E6AA[] = { 0x4349, 0xC537, 0, 0xC538, 0x5C7C, 0, 0xC539, 0xC53A, 0, 0xC53B, 0, 0xC53C, 0, 0x5C7A, 0x3869, 0, 0x5C79, 0xC53D, 0, 0, 0, 0, 0, 0x5D21, 0, 0, 0, 0xC53E, 0x5B58, 0xC53F, 0xC540, 0xC541, 0x5C7B, 0, 0x5C7D, 0x5C7E, 0, 0xC542, 0, 0, 0, 0, 0x5D2C, 0xC543, 0x5D28, 0, 0x5B6D, 0xC544, 0xC545, 0xC546, 0, 0x5D27, 0xC547, 0, 0, 0, 0x5D26, 0, 0, 0x5D23, 0, 0xC548, 0xC549, 0xC54A, }; const unsigned short utf8_to_euc_E6AB[] = { 0, 0x5C6A, 0x5D25, 0x5D24, 0, 0, 0xC54B, 0, 0xC54D, 0xC54C, 0, 0, 0xC54E, 0, 0, 0, 0xC54F, 0x5D2A, 0, 0x4F26, 0xC550, 0xC551, 0xC552, 0, 0, 0, 0x5D2D, 0x367B, 0xC553, 0xC554, 0x5D29, 0x5D2B, 0, 0, 0xF44A, 0, 0xC555, 0, 0, 0xC556, 0x4827, 0, 0x5D2E, 0, 0xC557, 0, 0, 0, 0xC558, 0xC559, 0xC55A, 0, 0, 0, 0, 0, 0, 0, 0x5D32, 0x5D2F, 0xC55B, 0xC55C, 0, 0, }; const unsigned short utf8_to_euc_E6AC[] = { 0, 0, 0xC55D, 0xC55E, 0x4D73, 0x5D30, 0xC55F, 0xC560, 0, 0xC561, 0x5C5E, 0, 0, 0, 0, 0xC562, 0xC563, 0xC564, 0x5D33, 0, 0, 0, 0x5D34, 0xC565, 0, 0, 0, 0xC566, 0, 0x3135, 0xC567, 0x5D36, 0x3767, 0x3C21, 0, 0x3655, 0xC568, 0, 0, 0x3224, 0xC569, 0, 0, 0xC56A, 0xC56B, 0, 0, 0xC56C, 0, 0, 0x4D5F, 0, 0, 0xC56D, 0xC56E, 0x5D38, 0x5D37, 0x5D3A, 0x353D, 0xC56F, 0, 0x3656, 0x343E, 0xC570, }; const unsigned short utf8_to_euc_E6AD[] = { 0, 0, 0, 0x5D3D, 0, 0, 0xC571, 0x5D3C, 0, 0x5D3E, 0xC572, 0, 0x324E, 0xC573, 0x4337, 0, 0x5D3F, 0, 0xC574, 0x343F, 0x5D41, 0, 0xC575, 0, 0xC576, 0x5D40, 0, 0x5D42, 0, 0xC577, 0, 0x5D43, 0xC578, 0x5D44, 0x3B5F, 0x4035, 0x3A21, 0, 0x4970, 0xC579, 0, 0x4A62, 0x4F44, 0xC57A, 0, 0, 0xC57B, 0x3B75, 0xC57C, 0, 0, 0x3A50, 0x4E72, 0xC57D, 0, 0, 0x5D45, 0x5D46, 0, 0x3B60, 0, 0xC57E, 0xC621, 0x5D47, }; const unsigned short utf8_to_euc_E6AE[] = { 0x5D48, 0, 0xC622, 0x5D4A, 0x5D49, 0xC623, 0x4B58, 0, 0, 0x3D5E, 0x3C6C, 0x3B44, 0, 0x5D4B, 0, 0, 0, 0, 0, 0, 0, 0x5D4D, 0x3F23, 0xC624, 0x5D4C, 0, 0, 0xC625, 0, 0, 0x5D4E, 0xC626, 0xC627, 0, 0xC628, 0xC629, 0x5D4F, 0, 0, 0, 0xC62A, 0xC62B, 0x5D50, 0x5D51, 0xC62C, 0xC62D, 0xC62E, 0x5D52, 0xC62F, 0x5D54, 0x5D53, 0x5D55, 0x3225, 0x434A, 0, 0x5D56, 0xC630, 0xC631, 0x3B26, 0x334C, 0x5D57, 0xC632, 0xC633, 0x4542, }; const unsigned short utf8_to_euc_E6AF[] = { 0x544C, 0, 0, 0xC634, 0xC635, 0x3523, 0x5D58, 0, 0, 0xC636, 0, 0x5D59, 0xC637, 0x4A6C, 0x4B68, 0, 0, 0, 0x4647, 0x5D5A, 0x4866, 0, 0xC638, 0, 0x487B, 0, 0xC639, 0x4C53, 0, 0, 0, 0x5D5B, 0, 0xC63A, 0, 0xC63B, 0, 0, 0xC63C, 0xC63D, 0, 0, 0, 0x5D5D, 0x5D5C, 0, 0xC63E, 0x5D5F, 0, 0xC63F, 0, 0x5D5E, 0, 0, 0, 0xC640, 0, 0xC641, 0, 0, 0, 0, 0, 0xC642, }; const unsigned short utf8_to_euc_E6B0[] = { 0, 0, 0xC643, 0, 0xC644, 0xC645, 0, 0, 0x5D61, 0xC646, 0, 0, 0, 0xC647, 0xC648, 0x3B61, 0xC649, 0x4C31, 0xC64A, 0x5D62, 0x5D63, 0, 0, 0x3524, 0, 0xC64B, 0, 0x5D64, 0, 0, 0, 0xC64C, 0, 0, 0, 0x5D66, 0x5D65, 0, 0xC64D, 0xC64E, 0xC64F, 0, 0, 0, 0xC650, 0, 0xC651, 0, 0, 0, 0, 0xC652, 0x3F65, 0xC653, 0xC654, 0x4939, 0x314A, 0, 0xC655, 0xC656, 0, 0, 0x4845, 0xC657, }; const unsigned short utf8_to_euc_E6B1[] = { 0x4475, 0x3D41, 0x3561, 0, 0, 0, 0, 0, 0, 0, 0xC658, 0xC659, 0, 0xC65A, 0x4846, 0xC65B, 0x3C2E, 0, 0xC65C, 0, 0xC65D, 0x5D68, 0, 0x3440, 0, 0xC65E, 0x3178, 0xC65F, 0xC660, 0x4672, 0x5D67, 0x393E, 0x4353, 0, 0x5D69, 0, 0, 0, 0, 0xC736, 0x5D71, 0, 0x5D6A, 0xC661, 0, 0xC662, 0, 0xC663, 0x4241, 0, 0x3562, 0x5D72, 0xC664, 0, 0xC665, 0, 0xC666, 0xC667, 0x3768, 0xC668, 0, 0x3525, 0x5D70, 0, }; const unsigned short utf8_to_euc_E6B2[] = { 0, 0x5D6E, 0x5D6B, 0x4D60, 0, 0xC669, 0xC66A, 0xC66B, 0x4440, 0xC66C, 0, 0, 0x4659, 0x5D6C, 0, 0, 0x5D74, 0, 0x5D73, 0x3723, 0xC66D, 0xC66E, 0x322D, 0xC66F, 0xC670, 0x3A3B, 0x5D6D, 0x5D6F, 0xC671, 0, 0, 0xC672, 0, 0x4B57, 0x4274, 0, 0, 0, 0, 0, 0, 0, 0, 0x4B77, 0, 0, 0x5D7C, 0, 0xC673, 0x5D7D, 0xC674, 0x324F, 0xC675, 0, 0, 0, 0x4A28, 0x4C7D, 0x5E21, 0x3C23, 0x3E42, 0x5D78, 0x5D7E, 0x3168, }; const unsigned short utf8_to_euc_E6B3[] = { 0, 0x3637, 0xC676, 0, 0x5D75, 0x5D7A, 0xC677, 0, 0, 0x4074, 0x4771, 0, 0x4867, 0xC678, 0, 0xC679, 0xC67A, 0xC67B, 0xC67C, 0x5D77, 0xC67D, 0x4B21, 0xC67E, 0x5D79, 0, 0x5E24, 0xC721, 0x5E22, 0xC722, 0x5D7B, 0, 0, 0xC723, 0x4B22, 0x4748, 0x3563, 0, 0x4525, 0, 0xC724, 0x436D, 0xC725, 0x5E25, 0xC726, 0xC727, 0, 0xC728, 0x5E23, 0x4259, 0x5D76, 0xC729, 0x314B, 0xC72A, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E6B4[] = { 0, 0, 0, 0, 0xC72B, 0, 0, 0xC72C, 0, 0, 0xC72D, 0x4D4E, 0x5E30, 0, 0xC72E, 0xC72F, 0, 0xC730, 0x5E2F, 0xC731, 0, 0, 0, 0x4076, 0, 0x5E2C, 0xC732, 0x4D6C, 0, 0, 0x4636, 0x5E26, 0, 0, 0, 0, 0, 0x4445, 0xC733, 0xC734, 0xC735, 0x314C, 0x393F, 0x5E29, 0, 0, 0xC737, 0xC738, 0, 0xC739, 0x3D27, 0x5E2E, 0, 0x5E2D, 0x5E28, 0, 0x5E2B, 0xC73A, 0, 0x3368, 0xC73B, 0x5E2A, 0x4749, 0xC73C, }; const unsigned short utf8_to_euc_E6B5[] = { 0, 0x4E2E, 0, 0, 0x3E74, 0x4075, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xC73D, 0, 0x5E36, 0x5E34, 0, 0x494D, 0, 0xC73E, 0xC73F, 0, 0xC740, 0, 0x5E31, 0x5E33, 0xC741, 0x313A, 0xC742, 0, 0x3940, 0x4F32, 0, 0x333D, 0, 0x4962, 0xC743, 0xC744, 0, 0, 0, 0x4D61, 0, 0, 0x3324, 0x3F3B, 0x5E35, 0, 0, 0xC745, 0, 0, 0, }; const unsigned short utf8_to_euc_E6B6[] = { 0, 0, 0xC746, 0, 0, 0x5E3A, 0, 0xC747, 0x3E43, 0, 0, 0, 0x4D30, 0, 0x5E37, 0, 0, 0xC748, 0xC749, 0x5E32, 0xC74A, 0x5E38, 0xC74B, 0xC74C, 0xC74D, 0x4E5E, 0, 0x4573, 0x4642, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xC74E, 0, 0xC74F, 0, 0, 0x3336, 0, 0, 0x3155, 0, 0xC750, 0x5E3E, 0, 0xC751, 0x5E41, 0xC752, 0, 0, 0x4E43, 0xC753, 0, 0xC754, }; const unsigned short utf8_to_euc_E6B7[] = { 0x4D64, 0, 0, 0, 0xC755, 0x5E48, 0x5E42, 0x5E3F, 0xC756, 0, 0xC757, 0x4E54, 0x5E45, 0, 0xC758, 0xC759, 0, 0x3D4A, 0x5E47, 0, 0, 0x5E4C, 0xC75A, 0, 0x4571, 0x5E4A, 0, 0xC75B, 0, 0xC75C, 0x5E44, 0xC75D, 0xC75E, 0x4338, 0xC75F, 0, 0x5E4B, 0xC760, 0x5E40, 0, 0x5E46, 0xC761, 0x5E4D, 0x307C, 0x5E43, 0, 0x5E4E, 0xC762, 0xC763, 0x3F3C, 0xF44C, 0x3D5F, 0xC764, 0x4A25, 0xC765, 0x3A2E, 0xF44B, 0x5E3B, 0x5E49, 0x453A, 0xC766, 0, 0, 0, }; const unsigned short utf8_to_euc_E6B8[] = { 0xC767, 0, 0, 0, 0xC768, 0x4036, 0, 0x3369, 0x3A51, 0x3E44, 0x5E3D, 0x3D42, 0, 0, 0, 0, 0, 0, 0, 0x374C, 0, 0x5E3C, 0, 0, 0, 0x5E52, 0x3D6D, 0x383A, 0, 0x5E61, 0xC769, 0x5E5B, 0x3574, 0x454F, 0xC76A, 0x5E56, 0x5E5F, 0x302F, 0x3132, 0xC76B, 0, 0x3239, 0, 0x5E58, 0x422C, 0x5E4F, 0x5E51, 0x3941, 0, 0, 0xC76C, 0, 0, 0, 0xC76D, 0, 0x5E62, 0xC76E, 0x5E5D, 0xC76F, 0xC770, 0, 0x5E55, 0, }; const unsigned short utf8_to_euc_E6B9[] = { 0, 0, 0, 0x5E5C, 0xC771, 0xC772, 0, 0, 0xC773, 0xC774, 0x4C2B, 0xC775, 0, 0x5E5A, 0x5E5E, 0xC776, 0, 0xC777, 0xC778, 0xC779, 0xC77A, 0, 0x3850, 0xC77B, 0x3E45, 0, 0, 0x4339, 0xC77C, 0xC77D, 0xC77E, 0x5E54, 0, 0, 0xC821, 0xC822, 0, 0, 0, 0x4D2F, 0xC823, 0, 0, 0x5E57, 0, 0, 0x5E50, 0x4572, 0, 0, 0x5E53, 0xC824, 0, 0, 0x5E59, 0, 0, 0, 0, 0xC825, 0, 0xC826, 0x4F51, 0x3C3E, }; const unsigned short utf8_to_euc_E6BA[] = { 0x4B7E, 0, 0x5E63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x482E, 0xC827, 0, 0x5E6F, 0x383B, 0, 0, 0xC828, 0, 0, 0x3D60, 0, 0x5E65, 0xC829, 0, 0, 0x4E2F, 0x3942, 0, 0x5E72, 0xC82A, 0, 0x306E, 0, 0, 0x5E70, 0, 0xC82B, 0, 0, 0x5E64, 0, 0, 0xC82C, 0xC82D, 0x5E6A, 0, 0xC82E, 0x5E6C, 0xC82F, 0, 0, 0x4D4F, 0x5E67, 0, 0, 0x452E, 0xC830, 0, 0x5E69, 0, 0xC831, }; const unsigned short utf8_to_euc_E6BB[] = { 0xC832, 0xC833, 0x5E71, 0xC834, 0x5E6B, 0x4C47, 0, 0xC835, 0xC836, 0x5E66, 0xC837, 0x3C22, 0x5E7E, 0xC838, 0xC839, 0xC83A, 0, 0x336A, 0, 0x5E68, 0x5E6D, 0x5E6E, 0, 0, 0, 0, 0, 0, 0, 0x426C, 0x425A, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xC83B, 0x5E76, 0xC83C, 0xC83D, 0x5E7C, 0, 0, 0x5E7A, 0, 0x4529, 0, 0, 0x5F23, 0x5E77, 0xC83E, 0, 0xC83F, 0, 0xC840, 0x5E78, 0x5E60, }; const unsigned short utf8_to_euc_E6BC[] = { 0, 0x3579, 0x493A, 0, 0xC841, 0, 0x3C3F, 0, 0xC842, 0x3977, 0xC843, 0, 0xC844, 0xC845, 0, 0x4F33, 0, 0x5E74, 0, 0x5F22, 0x3169, 0x4166, 0xC846, 0, 0xC847, 0, 0xC848, 0xC849, 0, 0, 0, 0, 0x4779, 0, 0x3441, 0x4E7A, 0, 0, 0xC84A, 0, 0, 0xC84B, 0xC84C, 0x4C21, 0x4452, 0xC853, 0, 0xC84D, 0xC84E, 0x5E7B, 0x5E7D, 0xC84F, 0, 0, 0xC850, 0, 0x4132, 0, 0, 0xC851, 0xC852, 0, 0x5F21, 0x5E79, }; const unsigned short utf8_to_euc_E6BD[] = { 0, 0x5E73, 0, 0, 0, 0x3443, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xC854, 0, 0xC855, 0xC856, 0xC857, 0x3769, 0, 0, 0xC858, 0x5F2F, 0xC859, 0xC85A, 0x5F2A, 0x4078, 0xC85B, 0xC85C, 0x3363, 0, 0xC85D, 0xC85E, 0, 0x3D61, 0, 0x5F33, 0, 0xC85F, 0, 0, 0, 0xC860, 0x5F2C, 0x442C, 0x5F29, 0x4459, 0, 0, 0, 0x5F4C, 0, 0, 0, 0x5F26, 0, 0x5F25, 0, 0x5F2E, 0xC861, 0xC862, 0, }; const unsigned short utf8_to_euc_E6BE[] = { 0x5F28, 0x5F27, 0x5F2D, 0xC863, 0x4021, 0, 0x5F24, 0xC864, 0xC865, 0, 0, 0xC866, 0xC867, 0xC868, 0x5F30, 0, 0xC869, 0x5F31, 0xC86A, 0xC86B, 0xC86C, 0, 0xC86D, 0x3442, 0, 0, 0xC86E, 0, 0, 0, 0, 0xC86F, 0xC870, 0x5F36, 0, 0x5F35, 0x5F37, 0xC871, 0xC872, 0xC873, 0xC874, 0, 0x5F3A, 0, 0, 0, 0xC875, 0xC876, 0xC877, 0x4543, 0, 0x5F34, 0, 0xC878, 0xC879, 0, 0, 0x5F38, 0, 0, 0xC87A, 0, 0, 0, }; const unsigned short utf8_to_euc_E6BF[] = { 0x3763, 0x4279, 0x5F32, 0x473B, 0, 0xC87B, 0x5F39, 0xC87C, 0xC87D, 0, 0xC87E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5F3E, 0x5F3C, 0, 0, 0x5F3F, 0, 0xC921, 0x5F42, 0, 0, 0xC922, 0x5F3B, 0x396A, 0x4728, 0, 0, 0x5E39, 0, 0, 0, 0xC923, 0xC924, 0, 0x4D74, 0x5F3D, 0, 0x5F41, 0x4275, 0xC925, 0x5F40, 0, 0x5F2B, 0, 0xC926, 0x6F69, 0, 0, 0xC927, 0x5F45, 0, 0xC928, 0xC929, 0x5F49, 0, }; const unsigned short utf8_to_euc_E780[] = { 0xC92A, 0x5F47, 0, 0, 0, 0xC92B, 0xC92C, 0xC92D, 0, 0x5F43, 0, 0x5F44, 0, 0xC92E, 0, 0x5F48, 0, 0x5F46, 0, 0, 0, 0x494E, 0, 0xC92F, 0x5F4E, 0, 0x5F4B, 0x5F4A, 0, 0x5F4D, 0x4654, 0x5F4F, 0xC930, 0, 0, 0xC931, 0, 0, 0x4375, 0x426D, 0xF44D, 0, 0, 0, 0x4025, 0, 0, 0xC932, 0x5F50, 0, 0x5F52, 0, 0xC933, 0, 0, 0xC934, 0, 0xC935, 0, 0, 0xC936, 0, 0x5F51, 0, }; const unsigned short utf8_to_euc_E781[] = { 0, 0, 0, 0xC937, 0xC938, 0, 0, 0, 0xC939, 0xC93A, 0xC93B, 0xC93C, 0x5E75, 0, 0xC941, 0, 0, 0x5F53, 0, 0, 0xC93D, 0xC93E, 0, 0, 0x4667, 0, 0, 0, 0, 0xC93F, 0xC940, 0, 0, 0, 0, 0x5F54, 0xC942, 0xC943, 0, 0, 0, 0, 0, 0x3250, 0xC944, 0, 0xC945, 0x4574, 0x3325, 0, 0, 0, 0, 0xC946, 0xC947, 0, 0x3564, 0, 0, 0, 0x3C5E, 0x3A52, 0xC948, 0, }; const unsigned short utf8_to_euc_E782[] = { 0, 0xC949, 0, 0, 0, 0xC94A, 0xC94B, 0, 0, 0x4F27, 0x3F66, 0, 0, 0, 0x316A, 0, 0, 0, 0x5F56, 0, 0xC94C, 0xC94D, 0xC94E, 0xC94F, 0xC950, 0x5F55, 0, 0xC951, 0, 0, 0, 0, 0, 0, 0, 0, 0xC952, 0, 0, 0, 0, 0, 0, 0xC953, 0x5F59, 0x433A, 0x5F5C, 0x5F57, 0xC954, 0xC955, 0, 0x5F5B, 0xC956, 0, 0, 0xC957, 0x5F5A, 0x4540, 0x3059, 0xF42E, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E783[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0x4E75, 0, 0xC958, 0x5F5E, 0, 0, 0, 0x3128, 0, 0xC959, 0, 0xC95A, 0xC95B, 0xC95C, 0xC95D, 0, 0xC95E, 0x5F60, 0, 0, 0xC95F, 0x5F5F, 0, 0x5F5D, 0, 0, 0, 0, 0xC960, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5F58, 0, 0, 0, 0, 0, 0, 0, 0x4B23, 0xC961, 0, 0, 0x5F62, 0, 0, }; const unsigned short utf8_to_euc_E784[] = { 0, 0, 0, 0xC962, 0xC963, 0xC964, 0xC965, 0xC966, 0, 0x5F61, 0, 0xC967, 0xC968, 0, 0, 0xC969, 0, 0, 0, 0, 0x316B, 0, 0, 0, 0, 0x5F64, 0x4A32, 0, 0x5F63, 0, 0xC96A, 0, 0xC96B, 0x4C35, 0, 0, 0, 0, 0x3E47, 0, 0, 0, 0, 0xC96C, 0, 0xC96D, 0, 0xC96E, 0xC96F, 0xC970, 0, 0, 0, 0, 0x4133, 0, 0xC971, 0, 0, 0, 0x3E46, 0, 0, 0, }; const unsigned short utf8_to_euc_E785[] = { 0, 0xC972, 0, 0, 0, 0xC973, 0xC974, 0xC975, 0, 0x4E7B, 0xC976, 0xC977, 0x5F6A, 0, 0x4079, 0, 0xC978, 0, 0xC979, 0, 0, 0x5F66, 0x5F6B, 0xC97A, 0, 0x316C, 0xC97B, 0, 0xC97C, 0, 0xC97D, 0, 0xC97E, 0, 0x5F69, 0, 0x4761, 0x5F65, 0x5F68, 0x3E48, 0xCA21, 0x4851, 0, 0, 0x5F6C, 0, 0x3C51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xCA22, 0, 0, 0, 0x407A, 0, 0, }; const unsigned short utf8_to_euc_E786[] = { 0xCA23, 0, 0, 0, 0x5F6F, 0xCA24, 0, 0xCA25, 0x5F67, 0, 0x3727, 0, 0xCA26, 0, 0, 0x5F6D, 0, 0, 0xCA27, 0, 0x4D50, 0x5F70, 0, 0, 0, 0x7426, 0xCA28, 0xCA29, 0, 0, 0, 0x3D4F, 0xCA2A, 0, 0xCA2B, 0, 0, 0, 0, 0, 0x5F71, 0, 0, 0, 0x5F72, 0, 0, 0xCA2C, 0xCA2D, 0x472E, 0xCA2E, 0xCA2F, 0, 0, 0, 0, 0, 0x5F74, 0xCA30, 0, 0, 0, 0x5F75, 0xCA31, }; const unsigned short utf8_to_euc_E787[] = { 0xCA32, 0xCA33, 0, 0x4733, 0xCA34, 0, 0, 0, 0x4575, 0x5F77, 0, 0xCA35, 0xCA36, 0, 0x5F79, 0, 0x4E55, 0, 0x5F76, 0xCA37, 0x5F78, 0x316D, 0xCA38, 0x5F73, 0, 0xCA39, 0xCA3A, 0, 0xCA3B, 0, 0, 0x535B, 0x5F7A, 0, 0, 0, 0, 0x4167, 0x3B38, 0x5F7C, 0, 0, 0, 0, 0x5F7B, 0x3F24, 0x5259, 0, 0, 0, 0, 0, 0, 0x5F7D, 0, 0, 0xCA3C, 0x6021, 0, 0x5F6E, 0x5F7E, 0, 0xCA3D, 0x6022, }; const unsigned short utf8_to_euc_E788[] = { 0xCA3E, 0, 0, 0, 0, 0, 0x477A, 0xCA3F, 0xCA40, 0xCA41, 0, 0, 0, 0x6023, 0, 0, 0x6024, 0, 0, 0xCA42, 0, 0, 0, 0xCA43, 0, 0, 0xCA44, 0x6025, 0, 0xCA45, 0, 0xCA46, 0, 0, 0, 0, 0xCA47, 0, 0, 0, 0x6026, 0, 0x445E, 0xCA48, 0x6028, 0x6027, 0, 0xCA49, 0x6029, 0, 0x602A, 0, 0xCA4A, 0x3C5F, 0x4963, 0, 0xCA4B, 0xCA4C, 0x4C6C, 0x602B, 0x602C, 0x4156, 0x3C24, 0x602D, }; const unsigned short utf8_to_euc_E789[] = { 0x602E, 0xCA4D, 0xCA4E, 0xCA4F, 0, 0xCA50, 0x602F, 0x4A52, 0x4847, 0, 0, 0x6030, 0x4757, 0, 0xCA51, 0xCA52, 0xCA53, 0, 0x442D, 0xCA54, 0, 0xCA55, 0xCA56, 0, 0x6031, 0x3267, 0xCA57, 0x356D, 0xCA58, 0x4C46, 0xCA59, 0x4C36, 0xCA5A, 0x3234, 0x4F34, 0xCA5B, 0, 0, 0, 0x4B52, 0xCA5C, 0x4A2A, 0, 0xCA5D, 0, 0, 0xCA5E, 0xCA5F, 0, 0xCA60, 0x4037, 0, 0x6032, 0, 0, 0xCA61, 0xCA62, 0x4643, 0, 0xCA63, 0xCA64, 0x3823, 0x6033, 0xCA65, }; const unsigned short utf8_to_euc_E78A[] = { 0x3A54, 0x6035, 0x6034, 0, 0xCA66, 0, 0, 0x6036, 0, 0xCA67, 0, 0, 0, 0xCA68, 0xCA69, 0, 0, 0, 0x6037, 0xCA6A, 0, 0, 0x6038, 0, 0, 0, 0, 0xCA6B, 0, 0, 0, 0, 0x353E, 0, 0x6039, 0, 0, 0, 0, 0x603A, 0xCA6C, 0, 0, 0, 0x3824, 0xCA6D, 0xCA6E, 0x4848, 0, 0xCA6F, 0x603C, 0, 0xCA70, 0, 0x3E75, 0, 0, 0x603B, 0, 0, 0, 0, 0xCA71, 0, }; const unsigned short utf8_to_euc_E78B[] = { 0, 0xCA72, 0x3638, 0x603D, 0x603F, 0, 0x603E, 0xCA73, 0, 0xCA74, 0, 0, 0xCA75, 0, 0x6040, 0, 0x3851, 0, 0x6041, 0, 0, 0xCA76, 0xCA77, 0x3669, 0xCA78, 0x4140, 0, 0x397D, 0, 0, 0, 0xCA79, 0x6043, 0x6044, 0x6042, 0, 0, 0xCA7A, 0, 0, 0, 0x3C6D, 0, 0, 0x4648, 0x3639, 0, 0, 0, 0, 0, 0xCA7B, 0xCA7C, 0, 0, 0x6046, 0x432C, 0x6045, 0xCA7D, 0xCA7E, 0x4F35, 0x4762, 0xCB21, 0, }; const unsigned short utf8_to_euc_E78C[] = { 0, 0, 0xCB22, 0, 0xCB23, 0xCB24, 0, 0xCB25, 0, 0, 0x6049, 0xCB26, 0, 0xCB27, 0, 0, 0, 0, 0xCB28, 0xCB29, 0, 0, 0x604B, 0x6048, 0xCB2A, 0xCB2B, 0, 0x4C54, 0x604A, 0x604C, 0xCB2C, 0x4E44, 0, 0, 0xCB2D, 0, 0xCB2E, 0x6050, 0, 0xCB2F, 0xCB30, 0x604F, 0x4376, 0x472D, 0xCB31, 0, 0x3825, 0x604E, 0, 0xCB32, 0xCB33, 0, 0x604D, 0xCB34, 0x4D31, 0x4D32, 0, 0, 0xCB35, 0xCB36, 0, 0xCB37, 0x6051, 0x316E, }; const unsigned short utf8_to_euc_E78D[] = { 0, 0, 0, 0xCB38, 0x3976, 0x3B62, 0, 0, 0, 0, 0, 0, 0, 0xCB39, 0x6052, 0x6053, 0xCB3A, 0, 0xCB3B, 0, 0, 0, 0xCB3C, 0x6055, 0xCB3D, 0, 0, 0, 0, 0xCB3E, 0xCB3F, 0xCB40, 0xCB41, 0, 0, 0x3D43, 0, 0, 0xCB42, 0xCB43, 0x6057, 0xCB44, 0x6056, 0xCB45, 0xCB46, 0, 0xCB47, 0xCB48, 0x6058, 0xCB49, 0x334D, 0, 0, 0x605A, 0, 0xCB4A, 0x6059, 0xCB4B, 0x605C, 0x605B, 0xCB4C, 0, 0, 0, }; const unsigned short utf8_to_euc_E78E[] = { 0xCB4D, 0xCB4E, 0, 0xCB4F, 0x383C, 0xCB50, 0xCB51, 0x4E28, 0, 0x364C, 0, 0x3226, 0, 0, 0xCB52, 0, 0xCB53, 0, 0, 0xCB54, 0, 0xCB55, 0x366A, 0xCB56, 0xCB57, 0, 0, 0, 0xCB58, 0, 0xCB59, 0xCB5A, 0xCB5B, 0, 0xCB5C, 0, 0, 0xCB5D, 0xCB5E, 0, 0, 0x3461, 0xCB5F, 0xCB60, 0, 0xCB61, 0, 0, 0, 0, 0x4E68, 0x605E, 0, 0xCB62, 0, 0xCB63, 0, 0xCB64, 0, 0x6060, 0xCB65, 0xCB66, 0, 0xCB67, }; const unsigned short utf8_to_euc_E78F[] = { 0x6061, 0, 0x3251, 0, 0, 0xCB68, 0xCB69, 0, 0x605D, 0xCB6A, 0x3B39, 0xCB6B, 0xCB6C, 0x4441, 0x605F, 0xCB6D, 0, 0, 0xCB6E, 0xCB6F, 0, 0, 0xCB70, 0, 0, 0xCB71, 0, 0, 0, 0xCB72, 0x6064, 0, 0x3C6E, 0xCB73, 0, 0xCB74, 0, 0x6062, 0xCB75, 0xCB76, 0, 0xCB77, 0x373E, 0, 0, 0x4849, 0x6063, 0, 0, 0x607E, 0, 0, 0xCB78, 0xCB79, 0, 0xCB7A, 0x6069, 0xCB7B, 0xCB7C, 0xCB7D, 0, 0xCB7E, 0x383D, 0xCC21, }; const unsigned short utf8_to_euc_E790[] = { 0xCC22, 0xCC23, 0, 0x3565, 0xCC24, 0x6066, 0x4D7D, 0xCC25, 0, 0x4E30, 0xCC26, 0, 0, 0, 0, 0, 0, 0xCC27, 0, 0, 0, 0, 0, 0, 0, 0, 0xCC28, 0xCC29, 0, 0, 0, 0, 0, 0, 0x4276, 0, 0xCC2A, 0x6068, 0xCC2B, 0, 0xCC2C, 0xCC2D, 0xCC2E, 0xCC2F, 0xCC30, 0xCC31, 0xCC32, 0xCC33, 0xCC34, 0xCC35, 0x606A, 0x4E56, 0x3657, 0x487C, 0x474A, 0, 0, 0xCC36, 0x606B, 0, 0, 0, 0, 0x606D, }; const unsigned short utf8_to_euc_E791[] = { 0xCC37, 0x6070, 0, 0xCC38, 0xCC39, 0, 0xCC3A, 0xCC3B, 0, 0, 0, 0xCC3C, 0, 0xCC3D, 0, 0, 0, 0xCC3E, 0xCC3F, 0, 0, 0x606C, 0, 0xCC40, 0, 0x606F, 0x386A, 0x314D, 0x6071, 0xCC41, 0x3F70, 0x606E, 0x4E5C, 0, 0xCC42, 0x6074, 0x7424, 0, 0xCC43, 0xCC44, 0xCC45, 0x6072, 0x6075, 0xCC46, 0, 0xCC47, 0xCC48, 0x6067, 0x6073, 0xCC49, 0xCC4A, 0x3A3C, 0, 0, 0x6076, 0, 0, 0, 0, 0, 0, 0, 0x6077, 0, }; const unsigned short utf8_to_euc_E792[] = { 0xCC4B, 0xCC4C, 0, 0x4D7E, 0, 0xCC4D, 0xCC4E, 0xCC4F, 0, 0xCC50, 0, 0x6078, 0, 0, 0, 0xCC51, 0xCC52, 0xCC53, 0xCC54, 0, 0, 0, 0, 0, 0xCC55, 0xCC56, 0xCC57, 0, 0xCC58, 0, 0x6079, 0xCC59, 0xCC5A, 0xCC5B, 0x6065, 0xCC5C, 0, 0, 0xCC5D, 0x607A, 0xCC5E, 0xCC5F, 0xCC60, 0xCC61, 0, 0, 0xCC62, 0xCC63, 0x3444, 0xCC64, 0xCC65, 0, 0, 0xCC66, 0, 0, 0, 0xCC67, 0, 0xCC68, 0, 0x3C25, 0, 0xCC69, }; const unsigned short utf8_to_euc_E793[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0xCC6A, 0xCC6B, 0x607B, 0, 0xCC6C, 0, 0, 0x607C, 0xCC6D, 0, 0, 0xCC6E, 0x607D, 0, 0, 0, 0xCC6F, 0, 0xCC70, 0xCC71, 0x313B, 0, 0xCC72, 0xCC73, 0x6121, 0, 0x493B, 0x6122, 0xCC74, 0, 0x3424, 0x6123, 0xCC75, 0x6124, 0xCC76, 0xCC77, 0, 0, 0x6125, 0xCC78, 0x6127, 0x6128, 0x6126, 0, 0xCC79, 0, 0x4953, 0x612A, 0x6129, 0, 0xCC7A, 0xCC7B, 0xCC7C, 0, 0, 0xCC7D, }; const unsigned short utf8_to_euc_E794[] = { 0, 0xF450, 0, 0x612C, 0x612B, 0x612D, 0xCC7E, 0, 0, 0, 0, 0, 0x612E, 0x6130, 0x612F, 0, 0, 0x3979, 0xCD21, 0x6132, 0, 0x6131, 0xCD22, 0xCD23, 0x3445, 0, 0x3F53, 0, 0x453C, 0, 0x6133, 0x4038, 0xCD24, 0xCD25, 0, 0x3B3A, 0xCD26, 0x3179, 0x6134, 0xCD27, 0x4D51, 0xCD28, 0xCD29, 0x4A63, 0x6135, 0, 0, 0xCD2A, 0x4544, 0x4D33, 0x3943, 0x3F3D, 0, 0, 0xCD2B, 0x434B, 0x5234, 0xCD2C, 0x442E, 0x3268, 0x6136, 0xCD2D, 0xCD2E, 0xCD2F, }; const unsigned short utf8_to_euc_E795[] = { 0xCD30, 0, 0, 0xCD31, 0x6137, 0, 0x613C, 0xCD32, 0xCD33, 0x613A, 0x6139, 0x5A42, 0x3326, 0x6138, 0xCD34, 0x305A, 0xCD35, 0x482A, 0xCD36, 0, 0x484A, 0, 0, 0xCD37, 0, 0x4E31, 0x613D, 0x613B, 0x435C, 0x4026, 0xCD38, 0xCD39, 0x482B, 0xCD3A, 0x492D, 0, 0x613F, 0x4E2C, 0x374D, 0x6140, 0, 0x613E, 0x4856, 0x6141, 0, 0x6142, 0, 0xCD3B, 0x305B, 0xCD3C, 0, 0x3E76, 0x6147, 0, 0x6144, 0x466D, 0x6143, 0xCD3D, 0xCD3E, 0xCD3F, 0xCD40, 0xCD41, 0xCD42, 0x3526, }; const unsigned short utf8_to_euc_E796[] = { 0, 0xCD43, 0x614A, 0, 0, 0xCD44, 0x6145, 0x6146, 0, 0x6149, 0x6148, 0x4925, 0, 0, 0x4142, 0x4141, 0xCD45, 0x353F, 0xCD46, 0xCD47, 0x614B, 0xCD48, 0, 0, 0, 0xCD49, 0x614C, 0, 0xCD4A, 0x614D, 0, 0, 0, 0, 0xCD4B, 0x614F, 0xCD4C, 0x614E, 0, 0, 0, 0, 0, 0x3156, 0, 0, 0, 0, 0, 0x6157, 0x4868, 0x6151, 0xCD4D, 0x6153, 0, 0, 0x6155, 0x3F3E, 0xCD4E, 0, 0x6156, 0x6154, 0x3C40, 0xCD4F, }; const unsigned short utf8_to_euc_E797[] = { 0xCD50, 0xCD51, 0x6150, 0x6152, 0xCD52, 0x4942, 0xCD53, 0x3E49, 0, 0, 0x6159, 0, 0xCD54, 0x6158, 0xCD55, 0xCD56, 0, 0, 0x615A, 0, 0x3C26, 0x3A2F, 0, 0xCD57, 0x4577, 0x615B, 0, 0x444B, 0xCD58, 0, 0x615D, 0xCD59, 0xCD5A, 0xCD5B, 0x4E21, 0x615C, 0xCD5C, 0, 0, 0xCD5D, 0, 0x4169, 0, 0, 0xCD5E, 0, 0xCD5F, 0xCD60, 0x6162, 0xCD61, 0x6164, 0x6165, 0x4354, 0, 0, 0, 0, 0xCD62, 0x6163, 0, 0x6160, 0, 0x615E, 0x615F, }; const unsigned short utf8_to_euc_E798[] = { 0xCD63, 0x6161, 0xCD64, 0xCD65, 0xCD66, 0, 0, 0xCD67, 0xCD68, 0x6168, 0xCD69, 0x6166, 0xCD6A, 0x6167, 0, 0xCD6B, 0, 0, 0xCD6C, 0xCD6D, 0, 0xCD6E, 0xCD6F, 0, 0, 0xCD70, 0, 0xCD71, 0xCD72, 0xCD73, 0xCD74, 0x6169, 0x616B, 0x616C, 0x616D, 0xCD75, 0x616E, 0xCD76, 0xCD77, 0x616A, 0, 0xCD78, 0, 0, 0, 0xCD79, 0, 0, 0x6170, 0, 0xCD7A, 0xCD7B, 0x616F, 0xCD7C, 0, 0, 0xCD7D, 0xCD7E, 0xCE21, 0x6171, 0xCE22, 0, 0, 0, }; const unsigned short utf8_to_euc_E799[] = { 0xCE24, 0xCE25, 0x4E45, 0xCE26, 0xCE27, 0xCE28, 0x6174, 0x6172, 0x6173, 0xCE29, 0xCE23, 0xCE2A, 0x3462, 0, 0, 0, 0, 0, 0x4C7E, 0, 0, 0xCE2B, 0x4A4A, 0, 0x6176, 0xCE2C, 0, 0, 0x6175, 0, 0, 0xCE2D, 0, 0x6177, 0x6178, 0, 0xCE2E, 0xCE2F, 0, 0x617C, 0x6179, 0x617A, 0x617B, 0, 0x617D, 0xCE30, 0xCE31, 0xCE32, 0x617E, 0xCE33, 0x6221, 0, 0xCE34, 0, 0x6222, 0, 0x6223, 0, 0x482F, 0x4550, 0x6224, 0x4772, 0x4934, 0, }; const unsigned short utf8_to_euc_E79A[] = { 0x6225, 0xCE35, 0xF451, 0x6226, 0x452A, 0xCE36, 0x3327, 0x3944, 0x6227, 0, 0, 0x6228, 0xCE37, 0xCE38, 0x6229, 0, 0x3B29, 0, 0, 0x622B, 0, 0xCE39, 0x622A, 0, 0, 0x622C, 0x622D, 0xCE3A, 0xCE3B, 0xCE3C, 0xF452, 0xCE3D, 0xCE3E, 0, 0xCE3F, 0xCE40, 0xCE41, 0xCE42, 0xCE43, 0xCE44, 0xCE45, 0, 0xCE46, 0, 0, 0xCE47, 0x4869, 0, 0x622E, 0, 0, 0, 0x622F, 0, 0, 0x7369, 0x6230, 0x6231, 0x6232, 0, 0, 0xCE48, 0, 0x3B2E, }; const unsigned short utf8_to_euc_E79B[] = { 0, 0xCE49, 0x6233, 0x4756, 0, 0xCE4A, 0x4B5F, 0, 0x314E, 0xCE4B, 0x3157, 0xCE4C, 0xCE4D, 0x6234, 0xCE4E, 0, 0, 0, 0x6236, 0, 0xCE4F, 0, 0x6235, 0x4570, 0, 0xCE50, 0, 0x4039, 0x5D39, 0, 0x6237, 0x4C41, 0xCE51, 0x6238, 0, 0x3446, 0x4857, 0x6239, 0xCE52, 0x623A, 0xCE53, 0, 0x623B, 0, 0xCE54, 0, 0x4C5C, 0, 0xCE55, 0xCE56, 0x4C55, 0, 0x443E, 0, 0xCE57, 0, 0x416A, 0xCE58, 0, 0x623D, 0xCE59, 0, 0x3D62, 0, }; const unsigned short utf8_to_euc_E79C[] = { 0xCE5A, 0x3E4A, 0, 0, 0x6240, 0, 0xCE5B, 0x623F, 0x623E, 0x487D, 0xCE5C, 0x3447, 0x3829, 0, 0xCE5D, 0, 0, 0, 0xCE5E, 0, 0xCE5F, 0xCE60, 0, 0xCE61, 0, 0xCE62, 0xCE63, 0x6246, 0xCE64, 0, 0x6243, 0x3F3F, 0x4C32, 0, 0xCE65, 0, 0x6242, 0x6244, 0x6245, 0, 0xCE66, 0x6241, 0, 0, 0, 0xCE67, 0xCE68, 0xCE69, 0, 0, 0, 0, 0xCE6A, 0xCE6B, 0xCE6C, 0x6247, 0x6248, 0xCE6D, 0x442F, 0, 0x3463, 0xCE6E, 0xCE6F, 0, }; const unsigned short utf8_to_euc_E79D[] = { 0x4365, 0, 0xCE70, 0, 0, 0xCE71, 0xCE72, 0x6249, 0, 0, 0xCE73, 0, 0, 0xCE74, 0xCE75, 0xCE76, 0, 0, 0xCE77, 0, 0, 0, 0xCE78, 0xCE79, 0, 0, 0x624A, 0x624D, 0xCE7A, 0, 0xCE7B, 0xCE7C, 0xCE7D, 0x3F67, 0xCE7E, 0x4644, 0xCF21, 0x624E, 0x4B53, 0xCF22, 0x624B, 0, 0xCF23, 0x624C, 0xCF24, 0, 0, 0, 0xCF25, 0, 0xCF26, 0xCF27, 0xCF28, 0, 0, 0, 0, 0x6251, 0xCF29, 0, 0, 0xCF2A, 0x6250, 0x624F, }; const unsigned short utf8_to_euc_E79E[] = { 0xCF2B, 0, 0, 0, 0xCF2C, 0, 0, 0, 0, 0, 0, 0x6253, 0xCF2D, 0xCF2E, 0x6252, 0, 0, 0x6254, 0, 0, 0xCF2F, 0xCF30, 0xCF31, 0, 0, 0, 0xCF32, 0, 0, 0, 0x6256, 0xCF33, 0x6255, 0, 0xCF34, 0, 0, 0x4A4D, 0, 0xCF35, 0, 0, 0xCF36, 0, 0x3D56, 0x4E46, 0xCF37, 0xCF38, 0x6257, 0xCF39, 0, 0x4637, 0, 0xCF3A, 0x6258, 0, 0, 0x6259, 0, 0x625D, 0x625B, 0x625C, 0xCF3B, 0x625A, }; const unsigned short utf8_to_euc_E79F[] = { 0, 0, 0, 0xCF3C, 0, 0, 0, 0x625E, 0, 0xCF3D, 0, 0, 0, 0x625F, 0, 0, 0, 0xCF3E, 0xCF3F, 0, 0, 0xCF40, 0, 0x6260, 0, 0xCF41, 0x6261, 0x4C37, 0x6262, 0, 0xCF42, 0xCF43, 0xCF44, 0, 0x4C70, 0x6263, 0xCF45, 0x434E, 0xCF46, 0x476A, 0, 0x366B, 0xCF47, 0, 0xCF48, 0x433B, 0x6264, 0x363A, 0xCF49, 0xCF4A, 0, 0x4050, 0xCF4B, 0, 0, 0, 0xCF4C, 0, 0, 0xCF4D, 0x6265, 0, 0, 0, }; const unsigned short utf8_to_euc_E7A0[] = { 0, 0, 0x3A3D, 0, 0, 0xCF4E, 0xCF4F, 0, 0, 0xCF50, 0, 0, 0x6266, 0xCF51, 0xCF52, 0, 0, 0xCF53, 0x6267, 0, 0x3826, 0x3A55, 0, 0, 0, 0, 0, 0, 0, 0xCF54, 0, 0, 0x6269, 0xCF55, 0xCF56, 0xCF57, 0, 0x4556, 0x3A56, 0x354E, 0, 0, 0, 0, 0, 0xCF58, 0xCF59, 0, 0xCF5A, 0, 0x4B24, 0, 0x474B, 0xCF5B, 0, 0xCF5C, 0, 0, 0x4557, 0, 0, 0, 0, 0x395C, }; const unsigned short utf8_to_euc_E7A1[] = { 0, 0, 0, 0xCF5D, 0xCF5E, 0x626B, 0, 0xCF5F, 0xCF60, 0, 0, 0, 0xCF61, 0, 0xCF62, 0, 0, 0, 0xCF63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xCF64, 0x3E4B, 0xCF65, 0, 0xCF66, 0xCF67, 0, 0xCF68, 0xCF69, 0, 0, 0, 0xCF6A, 0, 0xCF6B, 0x4E32, 0x3945, 0, 0xCF6C, 0x3827, 0, 0, 0x4823, 0, 0x626D, 0, 0, 0, 0, 0, 0xCF6D, 0, 0x626F, 0, 0xCF6E, 0, }; const unsigned short utf8_to_euc_E7A2[] = { 0, 0x386B, 0, 0, 0, 0, 0x626E, 0x4476, 0, 0, 0xCF6F, 0, 0x6271, 0x3337, 0x626C, 0xCF70, 0, 0x486A, 0, 0x3130, 0xCF71, 0x3A6C, 0, 0x4F52, 0xCF72, 0, 0x6270, 0, 0, 0xCF74, 0xCF75, 0xCF76, 0, 0xCF73, 0, 0x6272, 0xCF77, 0, 0, 0x4A4B, 0xCF78, 0x4059, 0x6274, 0, 0xCF79, 0xCF7A, 0, 0x6275, 0xCF7B, 0xCF7C, 0xCF7D, 0xCF7E, 0, 0x6273, 0, 0, 0, 0, 0x334E, 0xD021, 0x627B, 0xD022, 0x627A, 0xD023, }; const unsigned short utf8_to_euc_E7A3[] = { 0, 0x3C27, 0, 0, 0, 0x627C, 0x6277, 0xD024, 0xD025, 0xD026, 0x627D, 0x6278, 0xD027, 0, 0xD028, 0, 0x4858, 0x6276, 0xD029, 0xD02A, 0x6279, 0xD02B, 0xD02C, 0, 0, 0, 0x6322, 0xD02E, 0, 0, 0, 0xD02F, 0xD030, 0xD031, 0, 0, 0xD02D, 0, 0xD032, 0x6321, 0x4B61, 0, 0xD033, 0, 0x627E, 0, 0, 0x306B, 0, 0, 0xD034, 0xD035, 0x6324, 0, 0xD037, 0xD038, 0, 0, 0xD039, 0xD03A, 0, 0x6323, 0, 0xD03B, }; const unsigned short utf8_to_euc_E7A4[] = { 0xD036, 0x3E4C, 0, 0, 0, 0, 0xD03C, 0x6325, 0, 0, 0, 0, 0xD03D, 0, 0x4143, 0, 0xD03E, 0x6327, 0x6326, 0, 0, 0, 0, 0, 0, 0x6328, 0xD03F, 0, 0xD040, 0, 0xD041, 0xD042, 0xD043, 0, 0, 0, 0, 0xD044, 0x6268, 0xD045, 0, 0xD046, 0x626A, 0x632A, 0x6329, 0xD047, 0, 0, 0xF454, 0xD048, 0, 0, 0xD049, 0xD04A, 0, 0, 0, 0, 0x3C28, 0xD04B, 0x4E69, 0xD04C, 0x3C52, 0xD04D, }; const unsigned short utf8_to_euc_E7A5[] = { 0x632B, 0x3737, 0, 0, 0xD04E, 0xD04F, 0xD050, 0x3540, 0x3527, 0x3B63, 0xD051, 0xD052, 0, 0, 0, 0xD053, 0x4D34, 0xD054, 0, 0x6331, 0xD055, 0x6330, 0x4144, 0x632D, 0xD056, 0, 0x632F, 0xD057, 0xD058, 0x3D4B, 0x3F40, 0x632E, 0x632C, 0, 0x472A, 0, 0, 0x3E4D, 0, 0xD059, 0x493C, 0xD05A, 0, 0xD05B, 0, 0x3A57, 0, 0, 0, 0, 0xD05C, 0, 0, 0, 0, 0x4578, 0, 0xD05D, 0x6332, 0xD05E, 0xD05F, 0, 0xD060, 0x6333, }; const unsigned short utf8_to_euc_E7A6[] = { 0x6349, 0x3658, 0, 0, 0x4F3D, 0x4135, 0, 0, 0, 0, 0x6334, 0xD061, 0xD062, 0x3252, 0x4477, 0x4A21, 0, 0xD063, 0, 0xD064, 0xD065, 0xD066, 0xD067, 0, 0xD068, 0, 0, 0xD069, 0xD06A, 0x6335, 0, 0, 0, 0xD06B, 0, 0, 0, 0, 0x357A, 0x6336, 0xD06C, 0xD06D, 0x6338, 0xD06E, 0, 0, 0x6339, 0xD06F, 0x4729, 0xD070, 0, 0x633A, 0xD071, 0, 0, 0, 0xD072, 0x633B, 0x633C, 0xD073, 0, 0x3659, 0x3253, 0x4645, }; const unsigned short utf8_to_euc_E7A7[] = { 0x3D28, 0x3B64, 0xD074, 0, 0xD075, 0, 0, 0xD076, 0xD077, 0x633D, 0xD078, 0x3D29, 0, 0, 0, 0xD079, 0, 0x324A, 0x4943, 0, 0xD07A, 0x633E, 0xD07B, 0, 0x486B, 0, 0xD07C, 0, 0, 0xD07D, 0xD07E, 0x4145, 0xD121, 0x6341, 0xD122, 0x6342, 0x4769, 0xD123, 0x3F41, 0x633F, 0, 0x4361, 0xD124, 0xD125, 0x6340, 0xD126, 0, 0, 0x3E4E, 0xD127, 0, 0, 0, 0, 0, 0, 0xD128, 0, 0, 0x305C, 0xD129, 0, 0, 0, }; const unsigned short utf8_to_euc_E7A8[] = { 0x3529, 0, 0xD12A, 0xD12B, 0, 0, 0, 0xD12C, 0x6343, 0xD12D, 0xD12E, 0x4478, 0xD12F, 0x6344, 0x4047, 0, 0, 0xD130, 0, 0, 0x4C2D, 0xD131, 0, 0x4923, 0x6345, 0x6346, 0x4355, 0xD132, 0x4E47, 0, 0xD133, 0x6348, 0x6347, 0xD134, 0, 0, 0, 0, 0, 0xD135, 0, 0, 0, 0xD136, 0, 0xD137, 0x3C6F, 0xD138, 0xD139, 0x634A, 0x3070, 0, 0xD13A, 0xD13B, 0, 0x634D, 0xD13C, 0xD13D, 0xD13E, 0x634B, 0x3254, 0x374E, 0x634C, 0x3946, }; const unsigned short utf8_to_euc_E7A9[] = { 0x3972, 0, 0x4A66, 0x634E, 0xD13F, 0xD140, 0x4B54, 0xD141, 0xD142, 0x6350, 0, 0, 0xD143, 0x4051, 0x314F, 0x323A, 0x302C, 0, 0, 0, 0, 0xD144, 0xD145, 0x634F, 0, 0xD146, 0, 0, 0xD147, 0xD148, 0, 0xD149, 0xD14A, 0x6351, 0x6352, 0x3E77, 0, 0xD14B, 0, 0xD14C, 0, 0x6353, 0xD14D, 0x334F, 0, 0xD14E, 0, 0, 0x6355, 0, 0, 0, 0x376A, 0xD14F, 0x3566, 0, 0xD150, 0x6356, 0x3675, 0, 0, 0x6357, 0xD151, 0x407C, }; const unsigned short utf8_to_euc_E7AA[] = { 0xD152, 0x464D, 0xD153, 0x4060, 0x3A75, 0xD154, 0xD155, 0, 0x6358, 0, 0xD156, 0xD157, 0, 0, 0, 0, 0xD158, 0xD159, 0x4362, 0x416B, 0xD15A, 0x635A, 0x635C, 0x6359, 0x635B, 0, 0, 0, 0, 0, 0xD15B, 0x3722, 0xD15C, 0, 0, 0xD15D, 0, 0, 0, 0, 0, 0x635D, 0x3726, 0, 0xD15E, 0, 0x3567, 0x4D52, 0x635F, 0, 0, 0xD15F, 0, 0xD160, 0x6360, 0, 0, 0xD161, 0x312E, 0xD162, 0xD163, 0, 0, 0x6363, }; const unsigned short utf8_to_euc_E7AB[] = { 0, 0, 0, 0x3376, 0x6362, 0x6361, 0xD164, 0x6365, 0x635E, 0xD165, 0x6366, 0x4E29, 0xD166, 0x6367, 0xD167, 0x6368, 0, 0xD168, 0x5474, 0x636A, 0, 0x6369, 0, 0, 0, 0x636B, 0x636C, 0xD169, 0x4E35, 0x636D, 0, 0x706F, 0x3E4F, 0x636E, 0x636F, 0x3D57, 0, 0x4638, 0x6370, 0xF459, 0xD16A, 0xD16B, 0x4328, 0xD16C, 0xD16D, 0x6371, 0, 0x433C, 0x6372, 0xD16E, 0, 0, 0xD16F, 0, 0x3625, 0, 0x513F, 0x435D, 0x3C33, 0xD170, 0, 0xD171, 0xD172, 0x3448, }; const unsigned short utf8_to_euc_E7AC[] = { 0, 0, 0x6373, 0, 0x6422, 0, 0x6376, 0xD173, 0x3568, 0, 0x6375, 0x6424, 0, 0, 0, 0x6374, 0, 0x3E50, 0, 0, 0xD174, 0, 0, 0, 0x6378, 0x6379, 0, 0x452B, 0, 0, 0x637A, 0xD175, 0x335E, 0, 0, 0xD176, 0, 0x3F5A, 0x4964, 0xD177, 0x637C, 0xD178, 0xD179, 0xD17A, 0x4268, 0xD17B, 0xD17C, 0xD17D, 0xD17E, 0xD221, 0, 0x6377, 0xD222, 0x637B, 0x637D, 0, 0, 0x3A7B, 0, 0, 0, 0xD223, 0, 0xD224, }; const unsigned short utf8_to_euc_E7AD[] = { 0xD225, 0xD226, 0, 0, 0, 0x6426, 0x492E, 0xD227, 0x4826, 0x4579, 0, 0x365A, 0x6425, 0x6423, 0xD228, 0x4835, 0x637E, 0x435E, 0x457B, 0, 0x457A, 0xD229, 0x3A76, 0, 0, 0, 0, 0, 0, 0x6438, 0, 0, 0xD22A, 0, 0, 0, 0xD22B, 0x6428, 0xD22C, 0x642A, 0, 0xD22D, 0xD22E, 0, 0x642D, 0xD22F, 0x642E, 0xD230, 0x642B, 0x642C, 0xD231, 0xD232, 0x6429, 0x6427, 0, 0xD233, 0, 0, 0x6421, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E7AE[] = { 0, 0, 0, 0, 0xD234, 0, 0x4A4F, 0x3255, 0, 0xD235, 0, 0x6435, 0, 0x6432, 0xD236, 0x6437, 0xD237, 0xD238, 0x6436, 0, 0x4773, 0x4C27, 0xD239, 0x3B3B, 0x6430, 0x6439, 0x6434, 0xD23A, 0x6433, 0x642F, 0xD23B, 0x6431, 0xD23C, 0x3449, 0, 0, 0, 0xD23D, 0, 0, 0, 0, 0x433D, 0, 0xD23E, 0x407D, 0, 0xD23F, 0xD240, 0x4822, 0xD241, 0, 0x643E, 0xD242, 0xD243, 0, 0x4824, 0, 0xD244, 0xD245, 0xD246, 0xD247, 0, 0, }; const unsigned short utf8_to_euc_E7AF[] = { 0x4061, 0x643B, 0xD248, 0, 0x484F, 0xD249, 0x643F, 0x4A53, 0xD24A, 0x435B, 0xD24B, 0x643A, 0x643C, 0, 0, 0x643D, 0, 0, 0, 0, 0xD24C, 0, 0xD24D, 0xD24E, 0, 0xD24F, 0xD250, 0xD251, 0, 0x6440, 0, 0, 0x3C44, 0, 0, 0, 0x4646, 0x6445, 0x6444, 0, 0xD252, 0x6441, 0xD253, 0, 0, 0x4F36, 0, 0, 0, 0, 0xD254, 0x644A, 0xD255, 0xD256, 0x644E, 0x644B, 0xD257, 0xD258, 0xD259, 0, 0xD25A, 0, 0xD25B, 0, }; const unsigned short utf8_to_euc_E7B0[] = { 0x6447, 0xD25C, 0xD25D, 0xD25E, 0xD25F, 0, 0xD260, 0x6448, 0, 0xD261, 0, 0xD262, 0xD263, 0x644D, 0xD264, 0xD265, 0, 0x6442, 0x5255, 0x6449, 0x6443, 0, 0, 0x644C, 0, 0xD266, 0, 0xD267, 0, 0, 0, 0x6452, 0xD268, 0x344A, 0, 0x644F, 0, 0xD269, 0xD26A, 0x6450, 0xD26B, 0, 0x6451, 0x6454, 0xD26C, 0, 0, 0, 0, 0xD26D, 0, 0xD26E, 0xD26F, 0, 0xD270, 0x6453, 0x4876, 0xD271, 0xD272, 0, 0, 0x6455, 0x4E7C, 0x4A6D, }; const unsigned short utf8_to_euc_E7B1[] = { 0x645A, 0, 0, 0x6457, 0, 0, 0xD273, 0, 0, 0, 0xD274, 0, 0x6456, 0x4052, 0, 0x6459, 0x645B, 0xD276, 0xD277, 0xD278, 0x6458, 0xD275, 0x645F, 0, 0x645C, 0xD279, 0xD27A, 0xD27B, 0xD27C, 0xD27D, 0xD27E, 0x645D, 0x6446, 0xD321, 0, 0xD322, 0x645E, 0x6460, 0, 0xD323, 0, 0xD324, 0, 0, 0x6461, 0xD325, 0xD326, 0, 0xD327, 0, 0xD328, 0x4A46, 0, 0x6462, 0, 0, 0, 0xD329, 0, 0, 0xD32A, 0xD32B, 0x4C62, 0, }; const unsigned short utf8_to_euc_E7B2[] = { 0, 0x364E, 0x3729, 0x6463, 0, 0, 0xD32C, 0xD32D, 0, 0x4A34, 0, 0x3F68, 0, 0x4C30, 0, 0xD32E, 0x6464, 0, 0x4E33, 0, 0xD32F, 0x4774, 0, 0x4146, 0x4734, 0, 0, 0x3D4D, 0, 0, 0xD330, 0x3040, 0xD331, 0x6469, 0x6467, 0, 0x6465, 0x3421, 0xD332, 0x3E51, 0x646A, 0, 0, 0x6468, 0, 0x6466, 0x646E, 0, 0xD333, 0x646D, 0x646C, 0x646B, 0, 0, 0xD334, 0xD335, 0, 0x646F, 0xD336, 0xD337, 0xD338, 0x6470, 0x403A, 0xD339, }; const unsigned short utf8_to_euc_E7B3[] = { 0x6471, 0, 0x6473, 0, 0xD33A, 0x6472, 0, 0xD33B, 0xD33C, 0xD33D, 0x3852, 0, 0, 0xD33E, 0x4138, 0xD33F, 0, 0, 0x6475, 0xD340, 0xD341, 0xD342, 0x457C, 0xD343, 0x6474, 0xD344, 0xD345, 0, 0x6476, 0xD346, 0x4A35, 0x416C, 0x3947, 0, 0x6477, 0, 0, 0, 0xD347, 0x4E48, 0, 0xD348, 0, 0xD349, 0, 0, 0, 0x6479, 0, 0, 0x647A, 0, 0x647B, 0xD34A, 0x647C, 0, 0x3B65, 0, 0x647D, 0x374F, 0, 0, 0x356A, 0, }; const unsigned short utf8_to_euc_E7B4[] = { 0x352A, 0, 0x6521, 0xD34B, 0x4C73, 0x3948, 0x647E, 0xD34C, 0xD34D, 0xD34E, 0x6524, 0x4C66, 0, 0x473C, 0, 0xD34F, 0x4933, 0xD350, 0xD351, 0xD352, 0x3D63, 0x6523, 0xD353, 0x3C53, 0x3949, 0x3B66, 0x3569, 0x4A36, 0x6522, 0xD354, 0xD355, 0, 0x4147, 0x4B42, 0x3A77, 0xD356, 0, 0, 0xD357, 0, 0, 0, 0xD358, 0x3B67, 0x445D, 0xD359, 0x6527, 0x4E5F, 0x3A59, 0xD35A, 0x6528, 0x3F42, 0, 0x652A, 0, 0, 0, 0x3E52, 0x3A30, 0, 0xD35B, 0xD35C, 0xD35D, 0x6529, }; const unsigned short utf8_to_euc_E7B5[] = { 0xD35E, 0xD35F, 0x3D2A, 0x383E, 0x4148, 0x6525, 0x652B, 0xD360, 0xD361, 0, 0, 0x6526, 0x3750, 0xD362, 0x652E, 0x6532, 0x376B, 0xD363, 0, 0xD364, 0, 0, 0x652D, 0xD365, 0, 0xD366, 0xD367, 0x6536, 0xD368, 0xD369, 0x394A, 0, 0, 0x4D6D, 0x303C, 0x6533, 0, 0xD36A, 0x356B, 0xD36B, 0x6530, 0, 0xD36C, 0, 0, 0, 0x6531, 0, 0xD36D, 0x457D, 0x652F, 0x652C, 0, 0x3328, 0x4064, 0, 0xD36E, 0x3828, 0xD36F, 0xD370, 0, 0x6538, 0, 0xD371, }; const unsigned short utf8_to_euc_E7B6[] = { 0, 0xD372, 0xD373, 0xD374, 0, 0xD375, 0xD376, 0, 0xD377, 0x6535, 0, 0xD378, 0xD379, 0xD37A, 0, 0x6537, 0, 0xD37B, 0, 0x6534, 0, 0, 0xD37C, 0xD37D, 0, 0x3751, 0x4233, 0x6539, 0x416E, 0xD37E, 0xD421, 0x6546, 0xF45C, 0, 0x6542, 0x653C, 0, 0, 0xD422, 0xD423, 0, 0, 0xD424, 0x6540, 0x3C7A, 0x305D, 0x653B, 0x6543, 0x6547, 0x394B, 0x4C56, 0xD425, 0x4456, 0x653D, 0xD426, 0xD427, 0x6545, 0xD428, 0x653A, 0x433E, 0, 0x653F, 0x303D, 0x4C4A, }; const unsigned short utf8_to_euc_E7B7[] = { 0, 0, 0xD429, 0xD42A, 0xD42B, 0xD42C, 0xD42D, 0x653E, 0, 0, 0x365B, 0x486C, 0xD42E, 0xD42F, 0xD430, 0x416D, 0, 0x4E50, 0x3D6F, 0, 0, 0x656E, 0xF45D, 0xD431, 0x6548, 0xD432, 0x407E, 0, 0x6544, 0x6549, 0x654B, 0, 0x4479, 0x654E, 0xD434, 0, 0x654A, 0xD435, 0xD436, 0, 0x4A54, 0x344B, 0xD437, 0xD438, 0x4C4B, 0xD439, 0, 0x305E, 0, 0xD43A, 0x654D, 0, 0x4E7D, 0xD43B, 0xD43C, 0, 0, 0xD43D, 0xD43E, 0x654C, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E7B8[] = { 0xD433, 0x316F, 0, 0, 0x466C, 0x654F, 0, 0, 0xD43F, 0x6556, 0x6550, 0x6557, 0, 0, 0, 0, 0xD440, 0xD441, 0x6553, 0, 0, 0xD442, 0, 0xD443, 0, 0, 0, 0x477B, 0xD444, 0xD445, 0x3C4A, 0x6555, 0xD446, 0x6552, 0x6558, 0x6551, 0, 0, 0x3D44, 0xD447, 0xD448, 0, 0, 0x4B25, 0xD449, 0xD44A, 0x3D4C, 0xD44B, 0, 0x6554, 0x6560, 0xD44C, 0, 0x655C, 0xD44D, 0x655F, 0, 0x655D, 0x6561, 0x655B, 0, 0x6541, 0x4053, 0xD44E, }; const unsigned short utf8_to_euc_E7B9[] = { 0, 0x484B, 0, 0x655E, 0xD44F, 0xD450, 0x6559, 0xD451, 0, 0, 0x4121, 0x3752, 0, 0x3D2B, 0xD452, 0, 0xD453, 0, 0xD454, 0, 0x3F25, 0x4136, 0x6564, 0, 0xD455, 0x6566, 0x6567, 0, 0, 0x6563, 0x6565, 0xD456, 0, 0xD457, 0xD458, 0, 0, 0xD459, 0x655A, 0x6562, 0, 0x656A, 0x6569, 0xD45A, 0, 0x4B7A, 0xD45B, 0xD45C, 0x372B, 0, 0, 0xD45D, 0, 0, 0, 0, 0xD45E, 0x6568, 0, 0x656C, 0x656B, 0x656F, 0xD45F, 0x6571, }; const unsigned short utf8_to_euc_E7BA[] = { 0, 0xD460, 0x3B3C, 0x656D, 0, 0, 0xD461, 0xD462, 0x6572, 0x6573, 0xD463, 0, 0x6574, 0xD464, 0x657A, 0x453B, 0x6576, 0xD465, 0x6575, 0x6577, 0x6578, 0xD466, 0x6579, 0, 0xD467, 0, 0xD468, 0x657B, 0x657C, 0xD469, 0xD46A, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E7BC[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x344C, 0, 0x657D, 0, 0x657E, 0xD46C, 0xD46B, 0xD46D, 0xD46E, 0xD46F, }; const unsigned short utf8_to_euc_E7BD[] = { 0, 0, 0, 0xD470, 0xD471, 0x6621, 0, 0xD472, 0, 0, 0, 0, 0x6622, 0x6623, 0x6624, 0xD473, 0x6625, 0x6626, 0xD474, 0xD475, 0x6628, 0x6627, 0, 0, 0x6629, 0, 0, 0xD476, 0xD477, 0xD478, 0, 0x662A, 0x662B, 0xD479, 0, 0xD47A, 0xD47B, 0xD47C, 0xD47D, 0x662E, 0x662C, 0x662D, 0x3A61, 0x3753, 0, 0xD47E, 0x4356, 0, 0x4833, 0xD521, 0x3D70, 0, 0, 0x474D, 0, 0x486D, 0x662F, 0x586D, 0, 0, 0, 0xD522, 0xD523, 0xD524, }; const unsigned short utf8_to_euc_E7BE[] = { 0xD525, 0, 0x6630, 0x6632, 0, 0x4D65, 0x6631, 0x6634, 0x6633, 0, 0x4D53, 0xD526, 0x6635, 0xD527, 0x487E, 0xD528, 0xD529, 0xD52A, 0, 0, 0x6636, 0, 0xD52B, 0xD52C, 0, 0, 0x6639, 0, 0xD52D, 0x6638, 0x6637, 0, 0, 0xD52E, 0xD52F, 0x663A, 0x3732, 0, 0xD530, 0, 0x4122, 0x3541, 0xD531, 0, 0, 0xD532, 0x663E, 0x663B, 0, 0, 0x663C, 0, 0xD533, 0, 0x663F, 0, 0x6640, 0x663D, 0, 0, 0xD534, 0x3129, 0, 0xD535, }; const unsigned short utf8_to_euc_E7BF[] = { 0xD536, 0x3227, 0, 0xD537, 0, 0x6642, 0x6643, 0, 0xD538, 0, 0x6644, 0, 0x4D62, 0, 0xD539, 0xD53A, 0, 0, 0x3D2C, 0, 0x6646, 0x6645, 0, 0, 0, 0, 0, 0xD53B, 0, 0, 0, 0xD53C, 0x3F69, 0x6647, 0, 0xD53D, 0, 0xD53E, 0x6648, 0, 0xD53F, 0x6649, 0, 0x3465, 0xD540, 0, 0xD541, 0xD542, 0x344D, 0, 0xD543, 0x664A, 0, 0, 0, 0, 0, 0x664B, 0xD544, 0x4B5D, 0x4D63, 0xD545, 0xD546, 0xD547, }; const unsigned short utf8_to_euc_E880[] = { 0x4D54, 0x4F37, 0, 0x394D, 0x664E, 0x3C54, 0x664D, 0xD548, 0xD549, 0, 0xD54A, 0x664F, 0x3C29, 0xD54B, 0xD54C, 0xD54D, 0x4251, 0xD54E, 0x6650, 0xD54F, 0xD550, 0x394C, 0xD551, 0x4C57, 0x6651, 0x6652, 0, 0, 0x6653, 0xD552, 0xD553, 0xD554, 0xD555, 0x6654, 0, 0, 0xD556, 0, 0xD557, 0, 0x6655, 0, 0, 0, 0xD558, 0, 0xD559, 0, 0xD55A, 0, 0, 0x3C2A, 0xD55B, 0xD55C, 0x4C6D, 0xD55D, 0, 0xD55E, 0xD55F, 0x6657, 0xD560, 0x433F, 0xD561, 0x6656, }; const unsigned short utf8_to_euc_E881[] = { 0xD562, 0, 0, 0, 0xD563, 0, 0x6659, 0, 0, 0, 0x6658, 0, 0, 0, 0, 0, 0, 0, 0x665A, 0, 0, 0, 0x403B, 0, 0x665B, 0, 0x665C, 0, 0, 0, 0x4A39, 0x665D, 0xD564, 0x416F, 0x665E, 0, 0xD565, 0, 0xD566, 0, 0x665F, 0, 0, 0, 0, 0xD567, 0, 0x4E7E, 0x6662, 0xD568, 0x6661, 0x6660, 0x4430, 0xD569, 0x6663, 0x3F26, 0, 0x6664, 0, 0, 0, 0x6665, 0x4F38, 0x6666, }; const unsigned short utf8_to_euc_E882[] = { 0, 0xD56A, 0, 0, 0x6667, 0x6669, 0x6668, 0x4825, 0xD56B, 0x4679, 0, 0x4F3E, 0x4829, 0, 0xD56C, 0, 0, 0, 0, 0x666B, 0, 0, 0x3E53, 0, 0x492A, 0, 0x666C, 0x666A, 0xD56D, 0x344E, 0xD56E, 0, 0, 0x3854, 0x3B68, 0, 0, 0x486E, 0xD56F, 0xD570, 0, 0x382A, 0x4B43, 0xD571, 0x666F, 0x666D, 0, 0x394E, 0, 0x394F, 0x3069, 0, 0x3A68, 0, 0, 0, 0xD572, 0xD573, 0x4759, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E883[] = { 0, 0, 0, 0x305F, 0x6674, 0, 0x4340, 0, 0xD574, 0, 0, 0, 0x4758, 0xD575, 0x425B, 0xD576, 0, 0, 0xD577, 0, 0xD578, 0xD579, 0x6676, 0xD57A, 0xD57B, 0x6672, 0x6675, 0x6670, 0, 0x6673, 0x4B26, 0, 0xD57C, 0x3855, 0, 0, 0x307D, 0x6671, 0, 0, 0, 0, 0, 0, 0, 0xD57D, 0xD57E, 0x6678, 0xD621, 0x6679, 0xD622, 0xD623, 0x4639, 0, 0xD624, 0, 0x363B, 0xD625, 0xD626, 0, 0x6726, 0x473D, 0xD627, 0, }; const unsigned short utf8_to_euc_E884[] = { 0, 0, 0x3B69, 0xD628, 0, 0x363C, 0x4048, 0x4F46, 0x4C2E, 0x6677, 0x4054, 0xD629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xD62A, 0xD62B, 0xD62C, 0, 0x3553, 0x667A, 0xD62D, 0, 0xD62E, 0, 0xD62F, 0, 0, 0x667C, 0xD630, 0, 0, 0xD631, 0, 0x667B, 0, 0, 0xD632, 0, 0, 0x667D, 0xD633, 0x4326, 0, 0x473E, 0, 0xD634, 0, 0, 0, 0x4431, 0xD635, 0, 0xD636, 0, 0x6723, 0, }; const unsigned short utf8_to_euc_E885[] = { 0, 0, 0, 0, 0, 0xD637, 0x6722, 0xD638, 0, 0, 0xD639, 0x667E, 0xD63A, 0, 0x3F55, 0, 0x4965, 0x6725, 0xD63B, 0x6724, 0x3950, 0x4F53, 0, 0xD63C, 0, 0, 0, 0, 0, 0, 0, 0x6735, 0xD63D, 0xD63E, 0, 0, 0, 0x6729, 0x672A, 0xD63F, 0xD640, 0xD641, 0, 0x3C70, 0, 0xD642, 0x6728, 0xD643, 0x3978, 0x6727, 0, 0, 0x672B, 0, 0, 0xD644, 0x4432, 0x4A22, 0x4123, 0, 0, 0, 0, 0x425C, }; const unsigned short utf8_to_euc_E886[] = { 0x672F, 0xD645, 0x6730, 0x672C, 0xD647, 0xD648, 0xD649, 0, 0x672D, 0, 0x672E, 0xD64A, 0, 0, 0xD64B, 0x3951, 0xD646, 0, 0, 0x6736, 0, 0x6732, 0xD64C, 0, 0xD64D, 0, 0x4966, 0xD64E, 0x4B6C, 0x4928, 0xD64F, 0, 0x6731, 0, 0xD650, 0x6734, 0x6733, 0, 0, 0, 0x4B44, 0x6737, 0, 0, 0, 0, 0xD651, 0, 0x6738, 0, 0xD652, 0x4137, 0xD653, 0x6739, 0, 0, 0x673B, 0, 0x673F, 0xD654, 0, 0x673C, 0x673A, 0x473F, }; const unsigned short utf8_to_euc_E887[] = { 0x673D, 0, 0x673E, 0xD656, 0, 0xD657, 0x3232, 0, 0x6745, 0x6740, 0xD658, 0xD655, 0, 0x6741, 0xD659, 0xD65A, 0, 0x6742, 0, 0x4221, 0, 0xD65B, 0, 0xD65C, 0x6744, 0x6743, 0x6746, 0xD65D, 0, 0xD65E, 0xD65F, 0x6747, 0x6748, 0xD660, 0, 0x3F43, 0xD661, 0x3269, 0, 0x6749, 0x4E57, 0, 0x3C2B, 0xD662, 0xD663, 0x3D2D, 0, 0, 0xD664, 0xD665, 0xD666, 0x3B6A, 0x4357, 0xD667, 0xD668, 0, 0xD669, 0xD66A, 0x674A, 0x674B, 0x3131, 0xD66B, 0x674C, 0xD66C, }; const unsigned short utf8_to_euc_E888[] = { 0xD66D, 0x674D, 0x674E, 0xD66E, 0, 0x674F, 0, 0x6750, 0x363D, 0x5A2A, 0x6751, 0, 0x4065, 0x6752, 0x3C4B, 0xD66F, 0x6753, 0, 0x5030, 0xD670, 0xD671, 0, 0x6754, 0x4A5E, 0x345C, 0xD672, 0xD673, 0x4124, 0x3D58, 0xD674, 0x4971, 0x3D2E, 0, 0xD675, 0xD676, 0, 0, 0, 0, 0, 0xD677, 0x6755, 0x3952, 0x6756, 0x484C, 0, 0x6764, 0, 0, 0, 0xD678, 0x6758, 0xD679, 0x4249, 0x4775, 0x383F, 0x6757, 0x4125, 0xD67A, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E889[] = { 0x6759, 0, 0, 0xD67B, 0xD67C, 0xD67D, 0xD67E, 0x447A, 0, 0, 0, 0xD721, 0, 0, 0xD722, 0xD723, 0, 0xD724, 0, 0, 0, 0, 0xD725, 0, 0x675B, 0x675A, 0x675D, 0, 0xD726, 0x675C, 0, 0x675E, 0xD727, 0, 0x6760, 0xD728, 0x675F, 0, 0x344F, 0xD729, 0x6761, 0, 0x6762, 0x6763, 0, 0xD72A, 0x3A31, 0x4E49, 0, 0x6765, 0x3F27, 0, 0xD72B, 0, 0x3170, 0x6766, 0x6767, 0, 0, 0xD72C, 0, 0xD72D, 0x6768, 0xD72E, }; const unsigned short utf8_to_euc_E88A[] = { 0xD72F, 0xD730, 0, 0xD731, 0xD732, 0, 0, 0xD733, 0, 0xD734, 0xD735, 0x3072, 0, 0x6769, 0xD736, 0, 0, 0xD737, 0x676A, 0, 0xD738, 0, 0xD739, 0, 0xD73A, 0x4967, 0xD73B, 0xD73C, 0, 0x3C47, 0, 0x676C, 0xD73D, 0xD73E, 0, 0xD73F, 0xD740, 0x3329, 0x3032, 0xD741, 0xD742, 0xD743, 0xD744, 0x676B, 0x676E, 0x474E, 0xD745, 0x3F44, 0xD746, 0x3256, 0xD747, 0x4B27, 0xD748, 0, 0, 0xD749, 0x375D, 0x365C, 0xD74A, 0x676D, 0xD74B, 0x326A, 0xD74C, 0xD74D, }; const unsigned short utf8_to_euc_E88B[] = { 0, 0, 0, 0, 0, 0x3423, 0xD74E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xD74F, 0x3171, 0x6772, 0x4E6A, 0x425D, 0xD750, 0, 0x4944, 0, 0x677E, 0xD751, 0x3257, 0x677C, 0, 0x677A, 0x6771, 0xD752, 0x676F, 0xD753, 0x6770, 0xD754, 0x3C63, 0x366C, 0x4377, 0xD755, 0, 0xD756, 0x4651, 0, 0xD757, 0, 0xD758, 0, 0x3151, 0, 0x6774, 0x6773, 0, 0xD759, 0xD75A, 0, 0x6779, 0x6775, 0x6778, 0, 0xD75B, 0xD75C, 0, }; const unsigned short utf8_to_euc_E88C[] = { 0xD75D, 0xD75E, 0x4C50, 0x6777, 0x3258, 0x337D, 0x677B, 0xD75F, 0xD760, 0x677D, 0xD761, 0xD762, 0, 0, 0x3754, 0, 0, 0, 0, 0, 0, 0, 0x6823, 0x682C, 0x682D, 0, 0, 0xD764, 0x302B, 0xD765, 0xD766, 0xD767, 0, 0xD768, 0xD769, 0x6834, 0, 0, 0, 0, 0x3071, 0, 0, 0x682B, 0xD76A, 0xD76B, 0xD76C, 0x682A, 0xD76D, 0x6825, 0x6824, 0xD76E, 0x6822, 0x6821, 0x4363, 0xD76F, 0x427B, 0x6827, 0xD770, 0, 0xD771, 0xD772, 0, 0, }; const unsigned short utf8_to_euc_E88D[] = { 0x6826, 0, 0xD773, 0xD774, 0xD775, 0x6829, 0, 0xD776, 0, 0x4170, 0x3755, 0, 0, 0xD777, 0xD778, 0x3141, 0x6828, 0xD779, 0x3953, 0xD83E, 0xD763, 0xD77A, 0xD77B, 0xD77C, 0x4171, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xF45F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xD77D, 0, 0, 0x683A, 0, 0x683B, 0, 0x3259, 0xD77E, 0, 0, 0x322E, 0x6838, 0xD821, 0, 0xD822, }; const unsigned short utf8_to_euc_E88E[] = { 0xD823, 0, 0xD824, 0, 0xD825, 0x682E, 0xD826, 0x6836, 0, 0x683D, 0x6837, 0, 0, 0xD827, 0x6835, 0, 0, 0, 0xD828, 0x6776, 0xD829, 0xD82A, 0x6833, 0, 0xD82B, 0xD82C, 0x682F, 0xD82D, 0xD82E, 0xD82F, 0x3450, 0x6831, 0x683C, 0, 0x6832, 0, 0, 0, 0xD830, 0xD831, 0x683E, 0xD832, 0x6830, 0x477C, 0xD833, 0xD84C, 0, 0, 0, 0x4D69, 0, 0, 0, 0x6839, 0, 0, 0, 0, 0, 0, 0, 0x684F, 0xD834, 0xD835, }; const unsigned short utf8_to_euc_E88F[] = { 0xD836, 0x6847, 0, 0, 0, 0x3F7B, 0, 0xD837, 0, 0xD838, 0x3546, 0, 0x365D, 0, 0x6842, 0xD839, 0xD83A, 0xD83B, 0, 0x325B, 0xD83C, 0, 0x3E54, 0, 0x6845, 0, 0, 0, 0x3A5A, 0xD83D, 0, 0x4551, 0x684A, 0, 0, 0, 0, 0, 0, 0, 0xD83F, 0x4A6E, 0xD840, 0x6841, 0, 0, 0, 0x325A, 0x3856, 0x4929, 0x684B, 0, 0x683F, 0, 0xD841, 0x6848, 0xD842, 0xD843, 0, 0x6852, 0xD844, 0x6843, 0, 0, }; const unsigned short utf8_to_euc_E890[] = { 0, 0xD845, 0, 0x6844, 0x463A, 0, 0xD846, 0x6849, 0, 0, 0xD847, 0x6846, 0x4B28, 0x684C, 0x3060, 0xD848, 0, 0xD849, 0, 0x6840, 0, 0xD84A, 0, 0, 0, 0xD84B, 0, 0, 0, 0, 0, 0, 0x684E, 0, 0x684D, 0, 0, 0, 0, 0, 0, 0x476B, 0x6854, 0, 0x685F, 0, 0, 0xD84D, 0, 0x337E, 0, 0, 0, 0x6862, 0, 0, 0x6850, 0xD84E, 0, 0, 0x6855, 0x4D6E, 0, 0, }; const unsigned short utf8_to_euc_E891[] = { 0, 0, 0, 0, 0, 0xD84F, 0x685E, 0xD850, 0xD851, 0x4D55, 0xD852, 0, 0, 0xD853, 0x4E2A, 0xD854, 0, 0xD855, 0xD856, 0, 0, 0, 0xD857, 0x4378, 0xD858, 0xD859, 0xD85A, 0x336B, 0xD85B, 0, 0, 0, 0xD85C, 0x4972, 0x6864, 0x4621, 0xD85D, 0xD85E, 0x3031, 0xD85F, 0, 0x685D, 0xD860, 0x6859, 0x4172, 0x6853, 0x685B, 0x6860, 0xD861, 0x472C, 0, 0xD862, 0xD863, 0x302A, 0xD864, 0x6858, 0xD865, 0x6861, 0x4978, 0, 0xD866, 0xD867, 0, 0, }; const unsigned short utf8_to_euc_E892[] = { 0, 0xD868, 0x685C, 0, 0x6857, 0xD869, 0, 0, 0, 0, 0, 0x3E55, 0, 0, 0, 0, 0x3D2F, 0, 0xD86A, 0xD86B, 0x3C2C, 0xD86C, 0, 0, 0, 0x4C58, 0, 0, 0x4947, 0, 0xD86D, 0x6867, 0, 0x6870, 0, 0, 0, 0, 0xD86E, 0, 0xD86F, 0xD870, 0xD871, 0, 0, 0x685A, 0, 0xD872, 0, 0xD873, 0x3377, 0, 0xD874, 0, 0, 0, 0x3E78, 0x6865, 0xD875, 0x686A, 0x4173, 0xD876, 0xD877, 0x6866, }; const unsigned short utf8_to_euc_E893[] = { 0xD878, 0x686D, 0xD879, 0, 0x435F, 0, 0x686E, 0xD87A, 0xD87B, 0x4D56, 0x6863, 0x3338, 0xD87C, 0x6869, 0, 0xD87D, 0x686C, 0x4C2C, 0, 0xD87E, 0, 0, 0x686F, 0, 0, 0x6868, 0x686B, 0, 0xD921, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xD922, 0, 0, 0xD923, 0, 0x4B29, 0, 0x4F21, 0xD924, 0xD925, 0xD926, 0xD927, 0, 0x6873, 0, 0, 0xD928, 0, 0, 0xD92A, 0xD92B, 0x687A, 0xD92C, 0, 0x6872, }; const unsigned short utf8_to_euc_E894[] = { 0x3C43, 0, 0xD92D, 0xD92E, 0, 0, 0x6851, 0xD92F, 0, 0, 0, 0, 0xD930, 0, 0xD931, 0, 0xD932, 0x4A4E, 0, 0x4C22, 0x6879, 0x6878, 0, 0x6874, 0x6875, 0, 0x3136, 0, 0xD933, 0, 0xD934, 0x6877, 0, 0x6871, 0xD935, 0xD936, 0xD937, 0xD938, 0x4455, 0xD939, 0, 0, 0xD93A, 0xD93B, 0x6876, 0x307E, 0, 0xD93C, 0, 0, 0xD929, 0xD93D, 0xD93E, 0x4222, 0xD93F, 0, 0, 0, 0, 0, 0, 0x4A43, 0, 0xD940, }; const unsigned short utf8_to_euc_E895[] = { 0x687B, 0x6921, 0, 0x4859, 0, 0, 0xD941, 0, 0x687E, 0x3E56, 0x3C49, 0x6923, 0, 0, 0x363E, 0xD942, 0xD943, 0xD944, 0xD945, 0xD946, 0, 0x6924, 0xD947, 0x4979, 0x687D, 0xD948, 0x6856, 0, 0xD949, 0xD94A, 0xD94B, 0xD94C, 0xD94D, 0xD94E, 0xD94F, 0x687C, 0xD950, 0, 0, 0, 0x4F4F, 0x4622, 0x4973, 0xD951, 0, 0x692B, 0, 0xD952, 0, 0, 0, 0, 0, 0, 0, 0x6931, 0, 0xD953, 0xD954, 0xD955, 0, 0xD956, 0x6932, 0xD957, }; const unsigned short utf8_to_euc_E896[] = { 0x6925, 0xD958, 0, 0, 0x4776, 0xD959, 0xD95A, 0x692F, 0x6927, 0xD95B, 0x6929, 0xD95C, 0xD95D, 0, 0, 0xD95E, 0x6933, 0x6928, 0, 0xD95F, 0x692C, 0, 0, 0x3172, 0xD960, 0x4665, 0, 0x692D, 0x6930, 0xD961, 0, 0xD962, 0xD963, 0, 0xD964, 0, 0x6926, 0xD965, 0x4126, 0xD966, 0x692A, 0x3B27, 0x3F45, 0x3730, 0x4C74, 0xD974, 0x4C79, 0x3D72, 0xF461, 0, 0, 0, 0xD967, 0, 0xD968, 0xD969, 0xD96A, 0x6937, 0x6935, 0, 0xD96B, 0xD96C, 0xD96D, 0xD96E, }; const unsigned short utf8_to_euc_E897[] = { 0, 0x4F4E, 0xD96F, 0, 0, 0, 0, 0xD970, 0, 0x6934, 0xD971, 0xD972, 0, 0x4D75, 0xD973, 0x6936, 0x6938, 0, 0, 0, 0, 0x6939, 0, 0, 0xD975, 0, 0xD976, 0, 0x693C, 0x693A, 0, 0xD977, 0xD978, 0, 0, 0, 0x4623, 0x693B, 0xD979, 0, 0xD97A, 0x484D, 0x692E, 0, 0, 0xD97B, 0, 0, 0, 0, 0, 0xD97C, 0, 0, 0xD97D, 0x3D73, 0, 0x693D, 0x6942, 0x4174, 0xD97E, 0, 0x6941, 0xDA21, }; const unsigned short utf8_to_euc_E898[] = { 0xDA22, 0, 0x6922, 0, 0xDA23, 0xDA24, 0x6943, 0x4149, 0, 0, 0x693E, 0x6940, 0, 0xDA25, 0xDA26, 0, 0xDA27, 0xDA28, 0xDA29, 0x693F, 0, 0, 0x5D31, 0x5D22, 0xDA2A, 0xDA2B, 0x6945, 0xDA2C, 0, 0, 0xDA2D, 0, 0, 0xDA2E, 0x6944, 0, 0, 0, 0, 0xDA2F, 0, 0xDA30, 0, 0, 0, 0x4D76, 0, 0x623C, 0x6946, 0, 0, 0, 0, 0, 0xDA31, 0, 0xDA32, 0, 0xDA33, 0, 0xDA34, 0xDA35, 0, 0x6947, }; const unsigned short utf8_to_euc_E899[] = { 0xDA36, 0xB866, 0xDA37, 0, 0, 0, 0xDA38, 0, 0, 0, 0, 0, 0, 0x6948, 0x3857, 0, 0x3554, 0, 0xDA39, 0xDA3A, 0x694A, 0x515D, 0xDA3B, 0xDA3C, 0xDA3D, 0xDA3E, 0x3575, 0, 0x4E3A, 0xDA3F, 0x3673, 0x694B, 0xDA40, 0xDA41, 0xDA42, 0xDA43, 0xDA44, 0, 0, 0x694C, 0, 0xDA45, 0, 0x436E, 0xDA46, 0, 0, 0xDA47, 0, 0x694D, 0, 0, 0, 0xDA48, 0xDA49, 0xDA4A, 0, 0x467A, 0xDA4B, 0x303A, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E89A[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0xDA6D, 0, 0x3263, 0x6952, 0x6953, 0xDA4C, 0, 0, 0, 0xDA4D, 0, 0x694E, 0, 0x3B3D, 0xDA4E, 0, 0xDA4F, 0, 0xDA50, 0, 0xDA51, 0, 0, 0, 0, 0xDA52, 0, 0x694F, 0x4742, 0, 0xDA53, 0xDA54, 0xDA55, 0x6950, 0x6951, 0x695B, 0, 0xDA56, 0, 0x6955, 0x6958, 0xDA57, 0, 0xDA58, 0xDA59, 0xDA5A, 0x6954, 0xDA5B, 0xDA5C, 0xDA5D, 0, 0, 0, 0, 0, 0xDA5E, }; const unsigned short utf8_to_euc_E89B[] = { 0xDA5F, 0xDA60, 0, 0xDA61, 0x6956, 0xDA62, 0x6957, 0x3C58, 0, 0x6959, 0, 0x4341, 0, 0x3756, 0x3342, 0, 0, 0xDA63, 0xDA64, 0, 0x695C, 0xDA65, 0, 0xDA66, 0, 0x333F, 0xDA67, 0x6961, 0xDA68, 0, 0x695D, 0x6960, 0xDA69, 0, 0, 0xDA6A, 0x483A, 0xDA6B, 0, 0xDA6C, 0, 0x695E, 0, 0, 0x695F, 0x4948, 0x485A, 0x6962, 0, 0, 0, 0, 0, 0, 0, 0, 0x427D, 0x696C, 0xDA6E, 0x6968, 0xDA6F, 0xDA70, 0x326B, 0, }; const unsigned short utf8_to_euc_E89C[] = { 0x6966, 0, 0x4B2A, 0x6967, 0xDA71, 0xDA72, 0x6964, 0xDA73, 0x6965, 0x696A, 0x696D, 0xDA74, 0, 0x696B, 0xDA75, 0xDA76, 0xDA77, 0x6969, 0x6963, 0xDA78, 0xDA79, 0, 0, 0, 0x4358, 0xDA7A, 0x6974, 0, 0x4C2A, 0, 0xDA7B, 0xDA7C, 0, 0xDA7D, 0, 0xDA7E, 0, 0x6972, 0, 0, 0xDB21, 0x6973, 0, 0, 0, 0, 0xDB22, 0xDB23, 0, 0xDB24, 0xDB25, 0, 0x696E, 0, 0, 0x6970, 0, 0xDB26, 0xDB27, 0x6971, 0xDB28, 0xDB29, 0xDB2A, 0x696F, }; const unsigned short utf8_to_euc_E89D[] = { 0xDB2B, 0, 0, 0xDB2C, 0, 0xDB2D, 0, 0, 0, 0x4066, 0, 0x4F39, 0x6978, 0xDB2E, 0x6979, 0, 0, 0, 0, 0x6A21, 0, 0x3F2A, 0, 0x697B, 0xDB2F, 0x697E, 0, 0, 0, 0xDB30, 0, 0x6976, 0x6975, 0xDB31, 0, 0x6A22, 0xDB32, 0xDB33, 0x325C, 0, 0x697C, 0, 0x6A23, 0, 0, 0, 0x697D, 0xDB34, 0, 0xDB35, 0xDB36, 0, 0x697A, 0, 0x4433, 0, 0x6977, 0, 0, 0xDB37, 0, 0, 0, 0x4768, }; const unsigned short utf8_to_euc_E89E[] = { 0, 0, 0x6A27, 0xDB38, 0xDB39, 0xDB3A, 0xDB3B, 0xDB3C, 0xDB3D, 0xDB3E, 0, 0xDB3F, 0xDB40, 0x4D3B, 0, 0, 0xDB41, 0, 0, 0xDB42, 0, 0xDB43, 0, 0xDB44, 0xDB45, 0xDB46, 0, 0, 0, 0, 0xDB47, 0x6A26, 0xDB48, 0, 0x6A25, 0xDB49, 0, 0, 0, 0xDB4A, 0, 0, 0, 0x6A2E, 0xDB4B, 0xDB4C, 0xDB4D, 0x6A28, 0, 0xDB4E, 0, 0x6A30, 0, 0xDB4F, 0, 0, 0, 0, 0x4D66, 0x6A33, 0, 0x6A2A, 0xDB50, 0xDB51, }; const unsigned short utf8_to_euc_E89F[] = { 0x6A2B, 0xDB52, 0, 0, 0x6A2F, 0, 0x6A32, 0x6A31, 0xDB53, 0xDB54, 0xDB55, 0x6A29, 0, 0, 0xDB56, 0, 0x6A2C, 0, 0x6A3D, 0, 0, 0xDB57, 0xDB58, 0, 0, 0xDB59, 0xDB5A, 0, 0xDB5B, 0, 0, 0xDB5C, 0x6A36, 0, 0xDB5D, 0xDB5E, 0xDB5F, 0, 0, 0, 0, 0, 0xDB60, 0xDB61, 0, 0xDB62, 0, 0x6A34, 0, 0xDB63, 0x6A35, 0xDB64, 0, 0, 0x6A3A, 0x6A3B, 0xDB65, 0x332A, 0xDB66, 0x3542, 0, 0, 0x6A39, 0xDB67, }; const unsigned short utf8_to_euc_E8A0[] = { 0, 0xDB68, 0, 0xDB69, 0, 0x6A24, 0xDB6A, 0xF464, 0, 0xDB6B, 0xDB6C, 0xDB6D, 0, 0x6A38, 0x6A3C, 0x6A37, 0xDB6E, 0x6A3E, 0xDB70, 0xDB71, 0xDB72, 0x6A40, 0x6A3F, 0, 0xDB73, 0xDB6F, 0xDB74, 0xDB75, 0xDB76, 0, 0xDB77, 0xDB78, 0, 0x6A42, 0x6A41, 0x695A, 0, 0, 0, 0x6A46, 0xDB79, 0, 0, 0, 0, 0xDB7A, 0xDB7B, 0, 0xDB7C, 0x6A43, 0xDB7D, 0, 0, 0xDB7E, 0x6A44, 0, 0, 0x6A45, 0xDC21, 0x6A47, 0xDC22, 0, 0, 0, }; const unsigned short utf8_to_euc_E8A1[] = { 0x376C, 0xDC23, 0x6A49, 0xDC24, 0x6A48, 0xDC25, 0x3D30, 0, 0xDC26, 0xDC27, 0xDC28, 0xDC29, 0x3954, 0x5E27, 0xDC2A, 0, 0, 0xDC2B, 0x6A4A, 0x3D51, 0, 0xDC2C, 0xDC2D, 0x3339, 0xDC2E, 0x6A4B, 0xDC2F, 0x3152, 0xDC30, 0x3E57, 0x6A4C, 0xDC31, 0xDC32, 0x3955, 0x6A4D, 0x3061, 0xDC33, 0, 0, 0, 0x493D, 0xDC34, 0, 0x6A4E, 0, 0, 0, 0, 0x3F6A, 0xDC35, 0x6A55, 0, 0, 0x6A52, 0, 0x436F, 0, 0xDC36, 0, 0xDC37, 0, 0x6A53, 0x6A50, 0x365E, }; const unsigned short utf8_to_euc_E8A2[] = { 0xDC38, 0x6A4F, 0x6A56, 0, 0, 0, 0, 0, 0x3736, 0, 0, 0x425E, 0, 0x6A5C, 0, 0, 0, 0, 0x6A58, 0, 0, 0, 0x4235, 0x6A57, 0xDC39, 0x6A5A, 0xDC3A, 0xDC3B, 0xDC3C, 0, 0x6A51, 0xDC3D, 0xDC3E, 0, 0x6A5B, 0, 0x6A5D, 0, 0, 0, 0xDC3F, 0, 0xDC40, 0x486F, 0, 0, 0x6A59, 0, 0x6A5E, 0x6A60, 0, 0, 0x3853, 0x6A54, 0, 0x3041, 0, 0, 0xDC41, 0, 0, 0xDC42, 0xDC43, 0x6A5F, }; const unsigned short utf8_to_euc_E8A3[] = { 0xDC44, 0x3A5B, 0x4E76, 0x6A61, 0x6A62, 0x4175, 0, 0, 0, 0, 0xDC45, 0xDC46, 0xDC47, 0xDC48, 0xDC49, 0x4E22, 0, 0xDC4A, 0xDC4B, 0xDC4C, 0x6A63, 0x4D35, 0, 0, 0x6A64, 0x6A65, 0, 0xDC4D, 0x4A64, 0x6A66, 0xDC4E, 0x3A40, 0, 0x4E23, 0, 0, 0, 0, 0, 0xDC4F, 0x6A6B, 0, 0, 0, 0, 0, 0, 0xDC50, 0xDC51, 0xDC52, 0x6A6C, 0x3E58, 0x6A6A, 0xDC53, 0, 0xDC54, 0x4D67, 0x6A67, 0, 0, 0x6A69, 0x403D, 0x3F7E, 0, }; const unsigned short utf8_to_euc_E8A4[] = { 0, 0xDC55, 0x6A68, 0, 0x6A6D, 0, 0xDC56, 0x4A23, 0, 0, 0x6A6F, 0, 0x6A6E, 0xDC57, 0xDC58, 0xDC59, 0x336C, 0, 0x4B2B, 0x6A70, 0, 0xDC5A, 0xDC5B, 0, 0xDC5C, 0xDC5D, 0xDC5E, 0, 0xDC5F, 0x6A7C, 0x6A72, 0, 0xDC60, 0, 0, 0, 0, 0x6A73, 0xDC61, 0xDC62, 0xDC63, 0, 0x6A74, 0x6A75, 0, 0, 0, 0, 0xDC64, 0xDC65, 0xDC66, 0, 0, 0xDC67, 0x6A79, 0, 0x6A7A, 0xDC68, 0xDC69, 0x6A78, 0, 0, 0xDC6A, 0, }; const unsigned short utf8_to_euc_E8A5[] = { 0xDC6B, 0x6A76, 0xDC6C, 0x6A71, 0x6A77, 0xDC6D, 0xDC6E, 0, 0, 0xDC6F, 0, 0, 0x6A7B, 0x7037, 0, 0xDC70, 0, 0, 0xDC71, 0, 0, 0, 0x3228, 0xDC72, 0, 0, 0xDC73, 0xDC74, 0xDC75, 0, 0x6A7E, 0x365F, 0x6A7D, 0xDC76, 0xDC77, 0xDC78, 0x6B22, 0, 0x6B21, 0, 0, 0, 0x6B24, 0xDC79, 0, 0x6B23, 0xDC7A, 0x6B25, 0xDC7B, 0, 0x3D31, 0xDC7C, 0x6B26, 0xDC7D, 0, 0x6B27, 0, 0, 0xDC7E, 0xDD21, 0xDD22, 0xDD23, 0x6B28, 0x403E, }; const unsigned short utf8_to_euc_E8A6[] = { 0, 0x4D57, 0, 0x6B29, 0, 0, 0x4A24, 0x4746, 0x6B2A, 0xDD24, 0x6B2B, 0x382B, 0, 0xDD25, 0, 0x352C, 0xDD26, 0, 0, 0x6B2C, 0xDD27, 0xDD28, 0x3B6B, 0x4741, 0x6B2D, 0, 0x3350, 0xDD29, 0xDD2A, 0, 0, 0xDD2B, 0xDD2C, 0x6B2E, 0, 0, 0, 0xDD2D, 0x6B30, 0x4D77, 0, 0x6B2F, 0x3F46, 0, 0x6B31, 0, 0, 0x6B32, 0xDD2E, 0, 0x6B33, 0x3451, 0xDD2F, 0xDD30, 0xDD31, 0xDD32, 0, 0, 0x6B34, 0, 0xDD33, 0x6B35, 0, 0x6B36, }; const unsigned short utf8_to_euc_E8A7[] = { 0x6B37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3351, 0, 0xDD34, 0xDD35, 0xDD36, 0xDD37, 0xDD38, 0, 0x6B38, 0, 0x6B39, 0x6B3A, 0, 0, 0, 0, 0, 0x3272, 0, 0xDD39, 0x3F28, 0x6B3B, 0, 0xDD3A, 0, 0xDD3B, 0, 0xDD3C, 0, 0, 0, 0xDD3D, 0, 0xDD3E, 0x6B3C, 0, 0xDD3F, 0, 0x6B3D, 0xDD40, 0, 0, 0, 0xDD41, 0, 0xDD42, }; const unsigned short utf8_to_euc_E8A8[] = { 0x3840, 0, 0x447B, 0x6B3E, 0xDD43, 0xDD44, 0, 0xDD45, 0x3757, 0, 0x3F56, 0, 0x6B41, 0, 0x4624, 0xDD46, 0x6B40, 0xDD47, 0xDD48, 0x3731, 0xDD49, 0xDD4A, 0x6B3F, 0x4277, 0x352D, 0, 0, 0x6B42, 0, 0x6B43, 0xDD4B, 0x3E59, 0xDD4C, 0, 0xDD4D, 0x376D, 0xDD4E, 0x6B44, 0xDD4F, 0, 0, 0, 0x4B2C, 0xDD50, 0xDD51, 0x405F, 0, 0xDD52, 0, 0x3576, 0, 0x4C75, 0x414A, 0xDD53, 0x6B45, 0xDD54, 0, 0, 0x3F47, 0x4370, 0x3E5A, 0xDD55, 0xDD56, 0, }; const unsigned short utf8_to_euc_E8A9[] = { 0xDD57, 0x6B46, 0, 0xDD58, 0, 0xDD59, 0x6B49, 0xDD5A, 0x6B4A, 0xDD5B, 0, 0, 0, 0xDD5C, 0xDD5D, 0, 0x3A3E, 0x4242, 0x6B48, 0xDD5E, 0x3E5B, 0x493E, 0xDD5F, 0xDD60, 0xDD61, 0, 0, 0x6B47, 0xDD62, 0xDD63, 0x3B6C, 0, 0x3153, 0xDD64, 0x6B4E, 0x3758, 0, 0xDD65, 0x3B6E, 0xDD66, 0, 0x3B6D, 0, 0x4F4D, 0x6B4D, 0x6B4C, 0x4127, 0, 0x354D, 0x4F43, 0x333A, 0x3E5C, 0, 0xDD67, 0xDD68, 0xDD69, 0, 0xDD6A, 0xDD6B, 0xDD6C, 0x6B4B, 0, 0xDD6D, 0xDD6E, }; const unsigned short utf8_to_euc_E8AA[] = { 0xDD6F, 0, 0x6B50, 0xDD70, 0x6B51, 0x6B4F, 0xDD71, 0x3858, 0, 0x4D40, 0, 0xDD72, 0x3B6F, 0x4727, 0, 0xDD73, 0xDD74, 0x6B54, 0xDD75, 0x4040, 0, 0x4342, 0xDD76, 0xDD77, 0x4D36, 0xDD78, 0x6B57, 0, 0, 0, 0x386C, 0xDD79, 0x403F, 0x6B53, 0, 0x6B58, 0x386D, 0x6B55, 0x6B56, 0xDD7A, 0x6B52, 0xDD7B, 0, 0, 0x4062, 0x4649, 0xDD7C, 0xDD7D, 0x432F, 0, 0x325D, 0xDD7E, 0, 0, 0xDE21, 0xDE22, 0, 0x4870, 0, 0xDE23, 0x3543, 0, 0xDE24, 0x4434, }; const unsigned short utf8_to_euc_E8AB[] = { 0, 0, 0x6B5B, 0xDE25, 0x6B59, 0, 0xDE26, 0x434C, 0xDE27, 0xDE28, 0xDE29, 0x4041, 0x3452, 0x6B5A, 0, 0x3F5B, 0, 0xDE2A, 0x4E4A, 0xDE2B, 0xDE2C, 0xDE2D, 0x4F40, 0xDE2E, 0, 0, 0x6B5C, 0x6B67, 0x4435, 0xDE2F, 0x6B66, 0xDE30, 0x6B63, 0x6B6B, 0x6B64, 0, 0x6B60, 0, 0x447C, 0x6B5F, 0, 0, 0, 0x6B5D, 0xDE31, 0x4D21, 0x3B70, 0, 0xDE32, 0x6B61, 0, 0x6B5E, 0xDE33, 0xDE34, 0xDE35, 0x6B65, 0x3D74, 0, 0x3841, 0, 0xDE36, 0, 0x427A, 0xDE37, }; const unsigned short utf8_to_euc_E8AC[] = { 0x4B45, 0x315A, 0x3062, 0, 0x4625, 0xDE38, 0xDE39, 0x6B69, 0, 0, 0xDE3F, 0xDE3A, 0x6B68, 0, 0x4666, 0, 0x6B6D, 0xDE3B, 0, 0, 0x6B62, 0, 0x6B6C, 0x6B6E, 0, 0x382C, 0x6B6A, 0x3956, 0xDE3C, 0x3C55, 0xDE3D, 0xDE3E, 0x6B6F, 0x4D58, 0, 0, 0, 0, 0x6B72, 0, 0x6B75, 0, 0, 0x6B73, 0x4935, 0xDE40, 0, 0, 0xDE41, 0, 0, 0x6B70, 0, 0, 0, 0xDE42, 0, 0x3660, 0, 0, 0xDE43, 0, 0x6B74, 0, }; const unsigned short utf8_to_euc_E8AD[] = { 0, 0x6B76, 0xDE44, 0xDE45, 0xDE46, 0xDE47, 0xDE48, 0, 0xDE49, 0x6B7A, 0, 0, 0x6B77, 0xDE4E, 0x6B79, 0x6B78, 0, 0, 0xDE4A, 0xDE4B, 0xDE4C, 0, 0x6B7B, 0, 0x3C31, 0xDE4D, 0x6B7D, 0x6B7C, 0x4968, 0, 0xDE4F, 0x6C21, 0, 0, 0, 0xDE50, 0, 0, 0x3759, 0, 0, 0, 0, 0x6B7E, 0x6C22, 0xDE51, 0, 0x6C23, 0x3544, 0x6641, 0x3E79, 0, 0x6C24, 0, 0xDE52, 0x386E, 0xDE53, 0xDE54, 0, 0, 0xDE55, 0x6C25, 0xDE56, 0xF466, }; const unsigned short utf8_to_euc_E8AE[] = { 0x6C26, 0xDE57, 0, 0x3B3E, 0xDE58, 0xDE59, 0, 0, 0, 0, 0x5A4E, 0xDE5A, 0x6C27, 0xDE5B, 0x6C28, 0xDE5C, 0x3D32, 0, 0x6C29, 0x6C2A, 0xDE5D, 0xDE5E, 0x6C2B, 0, 0, 0x6C2C, 0x6C2D, 0, 0xDE5F, 0, 0xDE60, 0xDE61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E8B0[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x432B, 0xDE62, 0xDE63, 0x6C2E, 0, 0, 0xDE64, 0xDE65, 0x6C30, }; const unsigned short utf8_to_euc_E8B1[] = { 0, 0x6C2F, 0, 0, 0, 0xDE66, 0x4626, 0xDE67, 0x6C31, 0xDE68, 0x4B2D, 0xDE69, 0x6C32, 0, 0x6C33, 0xDE6A, 0x6C34, 0xDE6B, 0, 0xDE6C, 0xDE6D, 0x6C35, 0, 0xDE6E, 0xDE6F, 0xDE72, 0x465A, 0xDE70, 0, 0xDE71, 0, 0, 0, 0x3E5D, 0x6C36, 0xDE73, 0xDE74, 0, 0xDE75, 0, 0xDE76, 0xDE77, 0x396B, 0x502E, 0x6C37, 0xDE78, 0, 0, 0, 0, 0, 0xDE79, 0, 0xDE7A, 0xDE7B, 0, 0x6C38, 0x493F, 0x6C39, 0xDE7C, 0x6C41, 0, 0xDE7D, 0, }; const unsigned short utf8_to_euc_E8B2[] = { 0, 0, 0x6C3A, 0, 0, 0x6C3C, 0xDE7E, 0xDF21, 0, 0x6C3B, 0x6C3D, 0xDF22, 0x4B46, 0x6C3E, 0x6C3F, 0, 0xDF23, 0, 0xDF24, 0xDF25, 0x6C40, 0, 0, 0, 0x6C42, 0xDF26, 0, 0xDF27, 0xDF28, 0x332D, 0x4467, 0, 0x4969, 0x3A62, 0x3957, 0, 0xDF29, 0, 0, 0x494F, 0x325F, 0x484E, 0x6C45, 0x3453, 0x4055, 0x6C44, 0x6C49, 0x4379, 0x4C63, 0, 0x6C47, 0x6C48, 0x352E, 0, 0x6C4A, 0x4763, 0x425F, 0xDF2A, 0xDF2B, 0x4871, 0x453D, 0x6C46, 0, 0x4B47, }; const unsigned short utf8_to_euc_E8B3[] = { 0x326C, 0x6C4C, 0x4F28, 0x4442, 0x4F45, 0xDF2C, 0xDF2D, 0x3B71, 0x6C4B, 0xDF2E, 0x4231, 0xDF2F, 0, 0x6C5C, 0x4128, 0xDF30, 0, 0x4678, 0, 0x4950, 0, 0xDF32, 0xDF31, 0, 0, 0xDF33, 0x6C4F, 0x3B3F, 0x3B72, 0xDF34, 0x3E5E, 0, 0x4765, 0xDF35, 0x382D, 0x6C4E, 0x6C4D, 0, 0x496A, 0, 0xDF36, 0, 0x3C41, 0, 0xDF37, 0x4552, 0, 0xDF38, 0xDF39, 0, 0xDF3A, 0, 0xF467, 0xDF3B, 0, 0xDF3C, 0xDF3D, 0, 0x6C51, 0x6C52, 0x3958, 0x6C50, 0xDF3E, 0xDF3F, }; const unsigned short utf8_to_euc_E8B4[] = { 0, 0xDF40, 0, 0xDF41, 0x6C53, 0x6C54, 0, 0x6C56, 0x4223, 0xDF42, 0x6C55, 0x3466, 0, 0x6C58, 0, 0x6C57, 0x6C59, 0, 0xDF43, 0x6C5B, 0x6C5D, 0, 0x6C5E, 0xDF44, 0, 0, 0, 0xDF45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E8B5[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x4056, 0xDF46, 0x3C4F, 0x6C5F, 0, 0xDF47, 0, 0x3352, 0xDF48, 0x6C60, 0xDF49, 0, 0x4176, 0x6C61, 0, 0x6C62, 0x496B, 0, 0xF468, 0x352F, 0, 0, 0, 0, 0, 0, 0, 0xDF4A, }; const unsigned short utf8_to_euc_E8B6[] = { 0, 0x6C63, 0xDF4B, 0, 0xDF4C, 0x4436, 0, 0, 0xDF4D, 0, 0x315B, 0, 0, 0xDF4E, 0, 0, 0xDF4F, 0xDF50, 0, 0, 0, 0xDF51, 0, 0, 0, 0x6C64, 0, 0, 0, 0, 0xDF52, 0xDF53, 0xDF54, 0, 0, 0x3C71, 0, 0, 0xDF55, 0, 0x3F76, 0, 0, 0xDF56, 0xDF57, 0, 0, 0xDF58, 0, 0, 0xDF59, 0x422D, 0, 0xDF5A, 0, 0xDF5B, 0, 0xDF5C, 0x6C67, 0xDF5D, 0xDF6F, 0, 0x6C66, 0, }; const unsigned short utf8_to_euc_E8B7[] = { 0xDF5E, 0, 0x6C65, 0, 0, 0xDF5F, 0xDF60, 0xDF61, 0xDF62, 0, 0xDF63, 0x6C6D, 0x6C6B, 0, 0xDF64, 0x6C68, 0, 0xDF65, 0, 0, 0xDF66, 0xDF67, 0x6C6A, 0xDF68, 0, 0xDF69, 0x6C69, 0x6C6C, 0, 0x3577, 0, 0x6C70, 0, 0x4057, 0, 0x6C71, 0xDF6A, 0xDF6B, 0, 0xDF6C, 0x3859, 0, 0x6C6E, 0x6C6F, 0xDF6D, 0, 0, 0x4F29, 0xDF6E, 0xDF70, 0xDF71, 0x4437, 0xDF72, 0x4129, 0, 0, 0, 0, 0, 0, 0x6C72, 0xDF73, 0, 0x6C75, }; const unsigned short utf8_to_euc_E8B8[] = { 0, 0xDF74, 0, 0, 0xDF75, 0xDF76, 0xDF77, 0, 0x6C73, 0x6C74, 0x4D59, 0xDF78, 0, 0, 0, 0x4627, 0x6C78, 0xDF79, 0, 0, 0xDF7A, 0, 0xDF7B, 0, 0, 0, 0, 0, 0, 0x6C76, 0x6C77, 0x6C79, 0xDF7C, 0xDF7D, 0xDF7E, 0xE021, 0, 0, 0xE022, 0xE023, 0, 0, 0x6D29, 0, 0, 0, 0, 0, 0x6C7C, 0xE024, 0, 0xE025, 0x6C7D, 0x6C7B, 0xE026, 0xE027, 0xE028, 0xE029, 0, 0, 0, 0xE02A, 0, 0, }; const unsigned short utf8_to_euc_E8B9[] = { 0xE02B, 0xE02C, 0x6C7A, 0, 0x447D, 0, 0, 0x6D21, 0x6D25, 0x6D22, 0x6C7E, 0xE02D, 0x6D23, 0xE02E, 0xE02F, 0xE030, 0x6D24, 0, 0, 0, 0xE031, 0x6D2B, 0, 0, 0, 0x6D26, 0, 0xE032, 0xE033, 0xE034, 0xE035, 0x4058, 0x6D28, 0xE036, 0xE037, 0x6D2A, 0x6D27, 0, 0, 0, 0, 0xE038, 0, 0, 0xE039, 0xE03A, 0, 0xE03B, 0xE03C, 0xE03D, 0x6D2D, 0, 0x3D33, 0, 0x6D2C, 0, 0, 0xE03E, 0xE03F, 0xE040, 0x6D2E, 0, 0, 0, }; const unsigned short utf8_to_euc_E8BA[] = { 0, 0x6D2F, 0xE041, 0xE042, 0x6D32, 0x6D31, 0, 0x6D30, 0, 0xE043, 0x6D34, 0x6D33, 0, 0x4C76, 0, 0, 0xE044, 0x6D36, 0xE045, 0x6D35, 0x6D37, 0xE046, 0, 0, 0, 0x6D38, 0xE047, 0xE048, 0, 0xE049, 0xE04A, 0, 0, 0x6D3A, 0xE04B, 0, 0, 0, 0, 0xE04C, 0, 0xE04D, 0x6D39, 0x3F48, 0x6D3B, 0xE04E, 0xE04F, 0x366D, 0x6D3C, 0x6D3E, 0, 0xE050, 0, 0xE051, 0, 0, 0, 0, 0xE052, 0xE053, 0, 0, 0x6D3F, 0, }; const unsigned short utf8_to_euc_E8BB[] = { 0xE054, 0xE055, 0, 0xE056, 0xE057, 0x6D40, 0x6D3D, 0xE058, 0x6D41, 0, 0x3C56, 0x6D42, 0x3530, 0x3733, 0, 0xE059, 0, 0xE05A, 0x382E, 0, 0xE05B, 0, 0, 0, 0, 0, 0, 0x6D43, 0xE05C, 0, 0, 0x4670, 0, 0, 0x453E, 0x6D44, 0, 0, 0, 0, 0xE05D, 0, 0, 0x6D47, 0, 0xE064, 0xE05E, 0, 0xE05F, 0xE060, 0, 0, 0, 0, 0, 0xE061, 0x3C34, 0xE062, 0xE063, 0x6D46, 0x6D45, 0x375A, 0x6D48, 0, }; const unsigned short utf8_to_euc_E8BC[] = { 0xE065, 0, 0xE066, 0x3353, 0, 0x6D4A, 0, 0xE067, 0xE068, 0x3A5C, 0x6D49, 0, 0x6D52, 0, 0, 0xE069, 0xE06A, 0, 0x6D4C, 0x6D4E, 0x4A65, 0x6D4B, 0xE06B, 0xE06C, 0xE06D, 0x6D4D, 0, 0x6D51, 0x6D4F, 0x3531, 0xE06E, 0x6D50, 0xE06F, 0xE070, 0, 0xE071, 0, 0xE072, 0x6D53, 0xE073, 0xE074, 0x475A, 0x4E58, 0, 0xE075, 0xE076, 0xE077, 0x3D34, 0, 0, 0, 0x6D54, 0xE078, 0xE079, 0xE07A, 0xE07B, 0x4D22, 0x6D56, 0xE07C, 0x6D55, 0, 0, 0x6D59, 0x4D41, }; const unsigned short utf8_to_euc_E8BD[] = { 0xE07D, 0xE07E, 0x6D58, 0xE121, 0x336D, 0x6D57, 0x6D5C, 0xE122, 0, 0x6D5B, 0, 0, 0x6D5A, 0x4532, 0x6D5D, 0xE123, 0, 0xE124, 0xE125, 0xE126, 0xE127, 0xE128, 0, 0x6D5E, 0xE129, 0, 0, 0, 0x6D5F, 0xE12A, 0xE12B, 0x396C, 0, 0x3725, 0x6D60, 0x6D61, 0x6D62, 0xE12C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E8BE[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3F49, 0x6D63, 0xE12D, 0x3C2D, 0x6D64, 0xE12E, 0xE12F, 0, 0x6D65, 0xE130, 0xE131, 0xE132, 0x5221, 0x517E, 0, 0, 0, 0, 0x6D66, 0x6570, 0x6D67, 0x4324, 0x3F2B, 0x4740, 0, 0, 0xE133, 0xE134, 0x6D68, 0xE135, 0, 0x4A55, 0x4454, 0x397E, 0, 0xE136, 0x4329, }; const unsigned short utf8_to_euc_E8BF[] = { 0xE137, 0xE138, 0x312A, 0, 0x4B78, 0x3F57, 0xE139, 0, 0, 0, 0xE13A, 0xE13B, 0, 0xE13C, 0x375E, 0, 0xE13D, 0x3661, 0xE13E, 0xE13F, 0x4A56, 0xE140, 0, 0, 0, 0, 0x6D69, 0, 0, 0, 0, 0, 0xE141, 0, 0x6D6B, 0xE142, 0xE143, 0x6D6A, 0x3260, 0, 0xE144, 0x4676, 0x6D6C, 0x4777, 0, 0x4533, 0xE145, 0x6D6D, 0x3D52, 0xE146, 0, 0, 0x6D6F, 0xE147, 0xE148, 0x4C42, 0x6D7E, 0x6D71, 0x6D72, 0xE149, 0, 0x4449, 0xE14A, 0, }; const unsigned short utf8_to_euc_E980[] = { 0x4260, 0x4177, 0xE14B, 0x4628, 0xE14C, 0x6D70, 0x3555, 0, 0xE14D, 0, 0, 0x6D79, 0xE14E, 0x6D76, 0x6E25, 0x4629, 0x4360, 0x6D73, 0, 0x447E, 0x4553, 0x6D74, 0x6D78, 0x3F60, 0xE14F, 0x4767, 0x444C, 0xE150, 0, 0x4042, 0x6D77, 0x422E, 0x4224, 0x6D75, 0x3029, 0x4F22, 0, 0, 0, 0x6D7A, 0xE151, 0xE152, 0xE154, 0, 0xE155, 0xE156, 0x4261, 0xE153, 0, 0x3D35, 0x3F4A, 0xE157, 0xE158, 0x6D7C, 0x6D7B, 0xE159, 0x306F, 0x6D7D, 0, 0, 0x492F, 0, 0x6E27, 0xE15A, }; const unsigned short utf8_to_euc_E981[] = { 0, 0x465B, 0x3F6B, 0xE15B, 0xE15C, 0x4359, 0, 0x3678, 0, 0x6E26, 0x4D37, 0x313F, 0xE15D, 0x4A57, 0x3261, 0x6E21, 0x6E22, 0x6E23, 0x6E24, 0x463B, 0x4323, 0x3063, 0x6E28, 0, 0x6E29, 0x7423, 0, 0xE15E, 0x423D, 0xE15F, 0x6E2A, 0, 0x3173, 0x414C, 0xE160, 0x382F, 0, 0x4D5A, 0xE161, 0xE162, 0x6E2B, 0x452C, 0, 0, 0xE163, 0x4178, 0x3C57, 0x6E2C, 0xE164, 0, 0x6E2F, 0, 0xE165, 0x3D65, 0x6E2D, 0x412B, 0x412A, 0xE166, 0x3064, 0, 0x4E4B, 0x6E31, 0, 0x4872, }; const unsigned short utf8_to_euc_E982[] = { 0x6E33, 0x6E32, 0x6E30, 0x6364, 0x3454, 0xE167, 0, 0x6D6E, 0xE168, 0x6E35, 0x6E34, 0xE169, 0xE16A, 0, 0xE16B, 0x6E36, 0xE16C, 0x4D38, 0, 0, 0, 0xE16D, 0, 0xE16E, 0xE16F, 0xE170, 0, 0xE171, 0, 0, 0, 0, 0xE172, 0xE173, 0xE174, 0x4661, 0, 0xE175, 0x4B2E, 0, 0x6E37, 0, 0x3C59, 0, 0, 0, 0, 0x6E38, 0xE176, 0x6E39, 0xE177, 0xE178, 0xE179, 0x6E3A, 0xE17A, 0, 0x4521, 0, 0, 0, 0, 0xE17B, 0xE17D, 0, }; const unsigned short utf8_to_euc_E983[] = { 0, 0x306A, 0, 0xE17E, 0xE221, 0xE222, 0, 0xE223, 0xE224, 0, 0x3959, 0, 0xE17C, 0, 0x4F3A, 0, 0, 0, 0xE22D, 0, 0, 0xE225, 0, 0xE226, 0xE227, 0xE228, 0, 0x6E3E, 0xE229, 0xE22A, 0xF46C, 0xE22B, 0, 0x3734, 0x6E3B, 0, 0x6E3C, 0xE22C, 0, 0, 0x4974, 0, 0, 0xE22F, 0, 0x3354, 0, 0xE230, 0xE231, 0, 0, 0, 0xE232, 0x4D39, 0xE22E, 0x363F, 0, 0, 0, 0, 0, 0x4554, 0xE233, 0xE234, }; const unsigned short utf8_to_euc_E984[] = { 0xE235, 0, 0x6E3F, 0, 0xE236, 0xE237, 0xE238, 0, 0xE239, 0, 0, 0, 0, 0xE23A, 0, 0, 0xE23B, 0, 0x6E40, 0, 0xE23C, 0xF46E, 0xE23D, 0xE23E, 0xE23F, 0x6E41, 0xE240, 0, 0xE241, 0, 0xE242, 0, 0xE243, 0, 0xE245, 0xE246, 0, 0xE244, 0, 0xE247, 0, 0xE248, 0, 0, 0, 0x4522, 0xE249, 0xE24A, 0x6E43, 0xE24B, 0x6E42, 0, 0xE24C, 0, 0xE24D, 0xE24E, 0, 0xE24F, 0xE250, 0, 0xE251, 0xE252, 0, 0, }; const unsigned short utf8_to_euc_E985[] = { 0, 0, 0, 0xE253, 0, 0, 0, 0xE254, 0xE255, 0x4653, 0x6E44, 0x3D36, 0x3C60, 0x475B, 0x4371, 0xE256, 0, 0, 0x3C72, 0xE257, 0x3F6C, 0, 0x6E45, 0xE258, 0x6E46, 0xE259, 0xE25A, 0xE25B, 0, 0, 0, 0, 0, 0xE25C, 0x3F5D, 0x6E47, 0xE25D, 0x6E48, 0, 0xE25E, 0, 0x6E49, 0x4D6F, 0, 0x3D37, 0xE25F, 0, 0, 0, 0, 0x6E4B, 0x6E4A, 0xE260, 0x395A, 0, 0x3973, 0x3B40, 0xE261, 0xE262, 0xE263, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E986[] = { 0, 0xE264, 0x6E4E, 0xE265, 0, 0xE266, 0xE267, 0x3D66, 0, 0x6E4D, 0xE268, 0x6E4C, 0, 0x4269, 0xE269, 0, 0x386F, 0xE26A, 0x4043, 0xE26B, 0xE26C, 0xE26D, 0, 0x4830, 0xE26E, 0, 0, 0, 0x3D39, 0, 0xE26F, 0, 0, 0xE270, 0x6E4F, 0, 0x3E5F, 0, 0xE271, 0, 0xE272, 0, 0x6E52, 0x6E50, 0xE273, 0xE274, 0xE275, 0x6E51, 0xE276, 0xE277, 0xE278, 0xE279, 0x6E54, 0x6E53, 0xE27A, 0, 0x3E7A, 0, 0x6E55, 0xE27B, 0xE27C, 0xE27D, 0, 0xE27E, }; const unsigned short utf8_to_euc_E987[] = { 0x6E56, 0x6E57, 0xE321, 0xE322, 0, 0xE323, 0x4850, 0x3A53, 0x3C61, 0x6E58, 0, 0x6E59, 0x4E24, 0x3D45, 0x4C6E, 0x4E4C, 0x6E5A, 0x3662, 0, 0xE324, 0xE325, 0, 0x6E5B, 0xE326, 0x4523, 0xE327, 0xE328, 0x6E5E, 0x3378, 0x3F4B, 0xE329, 0x6E5C, 0, 0x6E5D, 0, 0x4460, 0xE32A, 0xE32B, 0x4B55, 0x367C, 0, 0xE32C, 0xE32D, 0, 0xE32E, 0xE32F, 0xE330, 0xE331, 0xE332, 0xE333, 0, 0, 0, 0x6E60, 0x6E61, 0xE334, 0, 0xE335, 0, 0xE336, 0x6E5F, 0xE337, 0, 0x6E63, }; const unsigned short utf8_to_euc_E988[] = { 0xE338, 0xE339, 0, 0, 0xE33A, 0xE33B, 0xE33C, 0xE33D, 0, 0xE33E, 0xE33F, 0, 0xE340, 0x465F, 0x3343, 0, 0xE341, 0x6E67, 0xE342, 0xE343, 0x6E64, 0x6E66, 0xE344, 0, 0xE345, 0, 0, 0, 0xE346, 0xE347, 0x6E62, 0, 0, 0, 0, 0xE348, 0xE349, 0xE34A, 0xE34B, 0, 0xE34C, 0x6F4F, 0, 0, 0x6E65, 0, 0xE34D, 0xE34E, 0xE34F, 0, 0, 0xE350, 0x4E6B, 0xE351, 0xE352, 0x385A, 0xE353, 0xE354, 0xE355, 0, 0xE356, 0, 0xE357, 0x6E6F, }; const unsigned short utf8_to_euc_E989[] = { 0xE358, 0, 0xE359, 0xE35A, 0x4534, 0x6E6A, 0xE35B, 0xE35C, 0x6E6D, 0x6E6B, 0xE35D, 0x6E70, 0, 0xE35E, 0xE35F, 0xE360, 0x6E71, 0xE361, 0, 0, 0, 0, 0, 0x6E69, 0xE362, 0xE363, 0x6E76, 0x3174, 0xE364, 0xE365, 0x6E68, 0, 0xE366, 0xE367, 0x482D, 0, 0x6E6C, 0xE368, 0x3E60, 0xE369, 0xE36A, 0xE36B, 0, 0, 0, 0, 0xE36C, 0xE36D, 0xE36E, 0x395B, 0, 0, 0, 0xE36F, 0xE370, 0xE371, 0xE372, 0xE373, 0, 0xE374, 0xE375, 0xE376, 0x4B48, 0xE377, }; const unsigned short utf8_to_euc_E98A[] = { 0x3664, 0, 0, 0x3D46, 0, 0x463C, 0, 0, 0xE378, 0xE379, 0xE37A, 0, 0, 0xE37B, 0xE37C, 0, 0, 0x412D, 0xE37D, 0x6E74, 0, 0x6E6E, 0x6E73, 0xE37E, 0x4C43, 0xE421, 0x4438, 0x6E75, 0x6E72, 0, 0, 0xE422, 0xE423, 0, 0, 0, 0xE424, 0xE425, 0, 0xE426, 0xE427, 0, 0, 0xE428, 0, 0x412C, 0, 0xE429, 0, 0, 0xE42A, 0, 0, 0, 0xE42B, 0x6E79, 0xE42C, 0x6E78, 0xE42D, 0xE42E, 0xE42F, 0xE430, 0, 0xE431, }; const unsigned short utf8_to_euc_E98B[] = { 0xE432, 0xE433, 0xE434, 0xE435, 0, 0xE436, 0xE437, 0xE438, 0xE439, 0, 0, 0xE43A, 0xE43B, 0xE43C, 0xE43D, 0x6E77, 0xE43E, 0, 0x4B2F, 0xE43F, 0, 0xE440, 0, 0xE441, 0xE442, 0xE443, 0, 0, 0xE444, 0xE445, 0, 0xE446, 0xE447, 0xE448, 0, 0xE449, 0x3D7B, 0xE44A, 0, 0xE44B, 0xE44C, 0x6E7A, 0x4A5F, 0, 0xE44D, 0x3154, 0xE44E, 0, 0xE44F, 0, 0x4946, 0x4372, 0, 0, 0, 0, 0x3578, 0xE450, 0x6E7C, 0xE451, 0x395D, 0, 0, 0xE452, }; const unsigned short utf8_to_euc_E98C[] = { 0xE453, 0, 0xE454, 0, 0, 0, 0x3B2C, 0, 0xE455, 0, 0, 0, 0, 0xE456, 0, 0x6E7B, 0x3F6D, 0xE457, 0, 0, 0xE458, 0xE459, 0, 0, 0x3F6E, 0x6F21, 0x6F23, 0, 0xE45A, 0xE45B, 0xE45C, 0xE45D, 0x3E7B, 0xE45E, 0x6F22, 0x6F24, 0xE45F, 0xE460, 0x3653, 0xE461, 0x4945, 0xE462, 0xE463, 0x3C62, 0x4F23, 0, 0x6E7E, 0x3A78, 0, 0, 0x4F3F, 0xE464, 0xE465, 0x6F26, 0xE466, 0xE467, 0, 0, 0x6F25, 0x6F27, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E98D[] = { 0, 0, 0, 0, 0x6E7D, 0, 0, 0xE468, 0xE469, 0xE46A, 0, 0x4669, 0, 0x4555, 0, 0, 0xE46B, 0xE46C, 0xE46D, 0, 0x4457, 0xE46E, 0x6F2C, 0xE46F, 0xE470, 0, 0xE471, 0x4343, 0x6F28, 0, 0xE472, 0, 0x6F29, 0, 0, 0, 0xE473, 0xE474, 0, 0xE475, 0, 0xE476, 0xE477, 0, 0x372D, 0xE478, 0x6F2B, 0xE479, 0xE47A, 0xE47B, 0, 0xE47C, 0xE47D, 0x3830, 0xE47E, 0, 0, 0, 0xE521, 0, 0x6F2A, 0xE522, 0x3E61, 0xE523, }; const unsigned short utf8_to_euc_E98E[] = { 0xE524, 0xE525, 0xE526, 0, 0, 0, 0, 0, 0xE527, 0, 0xE528, 0xE529, 0x3379, 0xE52A, 0, 0xE52B, 0, 0, 0xE52C, 0, 0x6F30, 0xE52D, 0x3A3F, 0x4179, 0xE52E, 0, 0x444A, 0xE52F, 0, 0, 0xE530, 0, 0, 0xE531, 0, 0xE532, 0xE533, 0, 0xE534, 0x333B, 0xE535, 0xE53B, 0, 0xE536, 0x6F2E, 0x6F2F, 0x4443, 0, 0x6F2D, 0, 0, 0, 0xE537, 0xE538, 0xE539, 0, 0, 0x6F31, 0xE53A, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E98F[] = { 0, 0xE53C, 0, 0x6F37, 0xE53D, 0xE53E, 0xE53F, 0xE540, 0x6F3A, 0xE541, 0xE542, 0xE543, 0xE544, 0xE545, 0, 0, 0x6F39, 0x452D, 0, 0xE546, 0, 0, 0x6F32, 0x6F33, 0x6F36, 0xE547, 0, 0, 0xE548, 0x6F38, 0xE549, 0xE54A, 0, 0x3640, 0xE54B, 0, 0x6F3B, 0x6F35, 0xE54C, 0xE54D, 0x6F34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xE54F, 0xE550, 0xE54E, 0xE551, 0xE552, 0, 0xE553, 0, 0, }; const unsigned short utf8_to_euc_E990[] = { 0, 0xE554, 0xE555, 0x6F3F, 0xE556, 0, 0, 0x6F40, 0xE557, 0xE558, 0, 0, 0, 0xE559, 0xE55A, 0xE55B, 0x6F41, 0, 0, 0x6F3E, 0x6F3D, 0xE55C, 0xE55D, 0xE55E, 0x3E62, 0x462A, 0x6F3C, 0, 0, 0, 0, 0xE55F, 0, 0x6F45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x6F43, 0, 0, 0xE560, 0xE561, 0, 0xE562, 0xE563, 0xE564, 0xE565, 0x6F44, 0x6F42, 0, 0x4278, 0, 0x6F46, 0xE566, 0, 0xE568, 0, 0xE567, }; const unsigned short utf8_to_euc_E991[] = { 0, 0x6F47, 0, 0xE569, 0x6F49, 0xE56A, 0, 0, 0xE56B, 0, 0xE56C, 0, 0xE56D, 0, 0, 0, 0, 0x3455, 0x6F48, 0x4C7A, 0, 0xE56E, 0, 0, 0, 0xE56F, 0x6F54, 0x6F4A, 0xE570, 0, 0x6F4D, 0xE571, 0x6F4B, 0xE572, 0x6F4C, 0xE573, 0, 0, 0, 0, 0xE574, 0, 0x6F4E, 0xE575, 0, 0xE576, 0xE577, 0xE578, 0x6F50, 0xE579, 0xE57A, 0, 0, 0x6F51, 0, 0x6F52, 0, 0, 0, 0, 0x6F55, 0x6F53, 0x6F56, 0x6F58, }; const unsigned short utf8_to_euc_E992[] = { 0, 0x6F57, 0, 0xE57C, 0xE57B, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E995[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x4439, 0xE57D, 0xE57E, 0, 0, 0, 0, 0xE621, 0, }; const unsigned short utf8_to_euc_E996[] = { 0x4C67, 0, 0x6F59, 0x412E, 0xE622, 0, 0, 0x6F5A, 0xE623, 0x4A44, 0x6F5B, 0x332B, 0xE624, 0xE625, 0xE626, 0x313C, 0, 0x3457, 0xF471, 0x3456, 0x6F5C, 0, 0x6F5D, 0, 0x6F5E, 0x6F5F, 0, 0, 0, 0xE627, 0xE628, 0xE629, 0x6F60, 0xE62A, 0x3458, 0x3355, 0x395E, 0x4836, 0xE62B, 0x6F62, 0x6F61, 0xE62C, 0, 0xE62D, 0xE62E, 0x6F63, 0, 0, 0, 0, 0x315C, 0, 0xE62F, 0, 0xE630, 0, 0, 0x6F66, 0xE631, 0x6F65, 0x6F64, 0xE632, 0x6F67, 0xE633, }; const unsigned short utf8_to_euc_E997[] = { 0, 0, 0, 0x6F6A, 0, 0, 0xE634, 0x3047, 0xE635, 0xE636, 0x6F68, 0xE637, 0x6F6C, 0x6F6B, 0, 0, 0xE638, 0xE639, 0xE63A, 0xE63B, 0x6F6E, 0x6F6D, 0x6F6F, 0, 0x462E, 0xE63C, 0xE63D, 0, 0x6F70, 0xE63E, 0xE63F, 0xE640, 0xE641, 0x6F71, 0x6F73, 0, 0xE642, 0x6F72, 0xE643, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E998[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x496C, 0xE644, 0xE645, 0, 0, 0x6F74, 0xE646, 0, 0xE647, 0xE648, 0xE649, 0, 0x6F75, 0, 0x3A65, 0, 0xE64A, 0, 0x6F76, 0x6F77, 0, 0xE64B, 0x4B49, 0xE64C, 0, 0, 0, 0xE64D, 0xE64E, 0xE64F, 0xE650, 0x414B, 0xE651, 0xE652, 0, 0x3024, }; const unsigned short utf8_to_euc_E999[] = { 0x424B, 0xE653, 0x6F78, 0, 0x496D, 0, 0, 0, 0, 0, 0, 0x6F7B, 0x6F79, 0x395F, 0, 0x6F7A, 0x3842, 0, 0xE654, 0, 0xE655, 0, 0xE656, 0xE657, 0xE658, 0, 0, 0x4A45, 0x6F7D, 0x7021, 0x6F7E, 0x7022, 0, 0xE659, 0x3121, 0x3F58, 0x3D7C, 0x3459, 0x7023, 0, 0, 0, 0x4766, 0, 0x7025, 0, 0xE65A, 0, 0x3122, 0, 0x7024, 0x4444, 0xE65B, 0x4E4D, 0x462B, 0x6F7C, 0x4E26, 0, 0x3831, 0xE65C, 0xE65D, 0x4D5B, 0xE65E, 0xE65F, }; const unsigned short utf8_to_euc_E99A[] = { 0, 0xE660, 0xE661, 0xE662, 0xE663, 0x3679, 0x4E34, 0, 0x3728, 0xE664, 0x4262, 0x6721, 0, 0x7026, 0x332C, 0x3F6F, 0, 0xE665, 0, 0, 0x3356, 0x7028, 0xE666, 0x7029, 0x7027, 0x3764, 0xE667, 0x3A5D, 0x3E63, 0xE668, 0, 0xE669, 0x3123, 0, 0, 0x4E59, 0xE66A, 0xE66B, 0xE66C, 0x702B, 0x6E2E, 0xE66D, 0x702A, 0, 0, 0, 0xE66E, 0xE66F, 0x702E, 0x702C, 0x702D, 0xE670, 0x702F, 0, 0x7030, 0x4E6C, 0x7031, 0x7032, 0xE671, 0x4049, 0x483B, 0, 0, 0, }; const unsigned short utf8_to_euc_E99B[] = { 0x3F7D, 0x3467, 0, 0, 0x4D3A, 0x326D, 0x3D38, 0x385B, 0, 0x7035, 0xE672, 0x7034, 0x3B73, 0x7036, 0x7033, 0, 0, 0x3B28, 0xE673, 0, 0, 0x703A, 0x6A2D, 0, 0xE675, 0x5256, 0xE676, 0x3F77, 0x7038, 0xE677, 0xE678, 0xE679, 0, 0, 0x4E25, 0x4671, 0, 0, 0, 0, 0x312B, 0xE67A, 0x4063, 0x3C36, 0, 0, 0, 0xE67B, 0x4A37, 0xE67C, 0x3140, 0, 0, 0, 0x4E6D, 0x4D6B, 0, 0x703B, 0xE67D, 0x4545, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E99C[] = { 0x3C7B, 0, 0xE67E, 0xE721, 0x703C, 0xE722, 0x703D, 0x3F4C, 0x703E, 0xE723, 0x4E6E, 0, 0, 0x7039, 0x7040, 0x7042, 0, 0x7041, 0, 0x703F, 0, 0, 0x7043, 0, 0, 0x7044, 0xE724, 0xE725, 0x417A, 0xE726, 0x3262, 0, 0, 0xE727, 0xE728, 0xE729, 0x7045, 0, 0, 0x4C38, 0xE72A, 0, 0x7046, 0, 0, 0, 0, 0, 0x7047, 0xE72B, 0x4F2A, 0xE72C, 0, 0, 0, 0, 0x5B31, 0x7048, 0, 0xF474, 0, 0x7049, 0x704A, 0, }; const unsigned short utf8_to_euc_E99D[] = { 0, 0xE72D, 0x704E, 0xE72E, 0x704B, 0, 0x704C, 0, 0x704D, 0x704F, 0xE72F, 0, 0, 0xF475, 0xE730, 0xE731, 0, 0xF476, 0x4044, 0, 0, 0xE732, 0x4C77, 0xE733, 0xE734, 0x4045, 0xE735, 0xE736, 0x7050, 0, 0x4873, 0, 0x7051, 0x7353, 0x4C4C, 0xE737, 0x7052, 0, 0x7053, 0xE738, 0x7054, 0x3357, 0xE739, 0x7056, 0, 0x3F59, 0xE73A, 0, 0, 0x7057, 0, 0xE73B, 0x3724, 0, 0xE73C, 0xE73D, 0xE73E, 0x7058, 0x705C, 0xE73F, 0x705A, 0xE740, 0, 0xE741, }; const unsigned short utf8_to_euc_E99E[] = { 0xE742, 0x705B, 0, 0, 0x3373, 0x7059, 0x705D, 0, 0, 0xE743, 0, 0x705E, 0, 0x3048, 0, 0x705F, 0x7060, 0, 0, 0, 0, 0xE744, 0xE745, 0xE746, 0x3E64, 0xE747, 0xE748, 0, 0x7061, 0, 0xE749, 0xE74A, 0x3547, 0, 0xE74B, 0x7064, 0, 0, 0x7063, 0, 0x7062, 0, 0, 0x6B71, 0xE74C, 0x4A5C, 0xE74D, 0, 0, 0xE74E, 0xE74F, 0x7065, 0x7066, 0xE750, 0xE751, 0, 0xE752, 0xE753, 0xE754, 0, 0xE755, 0, 0xE756, 0xE757, }; const unsigned short utf8_to_euc_E99F[] = { 0, 0xE758, 0, 0x7067, 0xE759, 0xE75A, 0x7068, 0xE75B, 0x7069, 0xE75C, 0xE75D, 0x706A, 0xE75E, 0xE75F, 0xE760, 0, 0xE761, 0xE762, 0, 0x345A, 0xE763, 0, 0, 0xE764, 0xE765, 0xE766, 0, 0xE76A, 0x706B, 0xE767, 0xE768, 0, 0xE769, 0xE76B, 0, 0, 0xE76C, 0, 0, 0, 0, 0, 0, 0, 0, 0x706C, 0x4723, 0xE76D, 0, 0xE76E, 0x706E, 0x323B, 0xE76F, 0x7071, 0x7070, 0xE770, 0xE771, 0, 0xE772, 0x3124, 0, 0, 0, 0x3641, }; const unsigned short utf8_to_euc_E9A0[] = { 0, 0x4A47, 0x443A, 0x3A22, 0, 0x3960, 0x3D67, 0xE773, 0x3F5C, 0, 0xE774, 0, 0x7073, 0xE776, 0xE777, 0x7072, 0x4D42, 0x3468, 0x4852, 0x465C, 0xE778, 0, 0xE779, 0x3F7C, 0x4E4E, 0xE775, 0x375B, 0, 0xE77A, 0, 0xE77B, 0, 0xE77C, 0x7076, 0, 0xE77D, 0x7075, 0xE828, 0xE77E, 0, 0, 0, 0, 0xE821, 0x4B4B, 0x462C, 0xE822, 0xE823, 0xE824, 0, 0xE825, 0xE826, 0x3150, 0xE827, 0, 0x7077, 0x7074, 0, 0, 0x4951, 0x4D6A, 0x7078, 0xE829, 0, }; const unsigned short utf8_to_euc_E9A1[] = { 0, 0, 0, 0, 0xE82A, 0, 0x7079, 0xE82B, 0, 0, 0xE82C, 0x707B, 0x426A, 0x335B, 0x335C, 0x707A, 0, 0xE82D, 0xE82E, 0xE82F, 0x3469, 0x3832, 0xE830, 0xE831, 0x346A, 0xE832, 0xE833, 0x453F, 0, 0, 0x4E60, 0, 0, 0, 0xE834, 0xE835, 0, 0xE836, 0xE837, 0x385C, 0, 0, 0xE838, 0x707C, 0xE839, 0, 0, 0x707D, 0x707E, 0x7121, 0, 0x7123, 0x7122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E9A2[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x4977, 0, 0x7124, 0xE83A, 0, 0xE83B, 0xE83C, 0x7125, 0xE83D, 0x7126, 0, 0, 0xE83E, 0, 0x7127, 0xE83F, 0xE840, 0, 0xE841, 0xE842, 0, 0, 0, 0xE843, }; const unsigned short utf8_to_euc_E9A3[] = { 0, 0, 0xE844, 0x7129, 0x7128, 0xE845, 0x712A, 0, 0xE846, 0, 0, 0, 0xE847, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x4874, 0x664C, 0, 0, 0x3F29, 0, 0xE848, 0x3532, 0xE849, 0, 0xE84A, 0xE84B, 0xE84C, 0, 0x712B, 0xE84D, 0x712C, 0, 0x522C, 0x5D3B, 0x4853, 0, 0, 0x307B, 0xE84E, 0x303B, 0, 0xE84F, 0, 0, 0, 0, 0, 0x3B74, 0x4B30, 0x3E7E, 0, }; const unsigned short utf8_to_euc_E9A4[] = { 0, 0, 0xE850, 0x712D, 0, 0x4C5F, 0, 0xE851, 0xE852, 0x712E, 0x4D5C, 0, 0x3142, 0, 0, 0, 0x3B41, 0xE853, 0x712F, 0x326E, 0x7130, 0xE854, 0xE855, 0xE856, 0x7131, 0, 0xE857, 0xE858, 0xE859, 0x7133, 0x7134, 0xE85A, 0x7136, 0x7132, 0xE85B, 0, 0x7135, 0, 0xE85C, 0xE85D, 0x345B, 0, 0, 0xE85E, 0x7137, 0, 0x7138, 0, 0, 0xE85F, 0xE860, 0xE861, 0xE862, 0xE863, 0, 0, 0, 0xE864, 0xE865, 0xE866, 0xE867, 0x7139, 0x713A, 0, }; const unsigned short utf8_to_euc_E9A5[] = { 0xE868, 0xE869, 0x713B, 0, 0, 0x713D, 0xE86A, 0xE86B, 0xE86C, 0x713C, 0, 0x713F, 0x7142, 0xE86D, 0xE86E, 0, 0x713E, 0x7140, 0x7141, 0, 0xE86F, 0x7143, 0, 0x3642, 0xE870, 0xE871, 0, 0xE872, 0xE873, 0, 0xE874, 0xE875, 0xE876, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E9A6[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3C73, 0x7144, 0x7145, 0x3961, 0, 0xE877, 0, 0xE878, 0xF47A, 0xE879, 0, 0, 0, 0, 0, 0x7146, 0xE87A, 0, 0x333E, 0, 0, 0, 0x474F, 0x7147, 0x7148, 0, 0xE87B, 0xE87C, 0xE87D, 0x435A, 0x466B, 0xE87E, 0, 0, 0, 0xE921, 0xE922, 0, 0x7149, 0xE923, 0, 0xE924, }; const unsigned short utf8_to_euc_E9A7[] = { 0, 0x477D, 0, 0xE925, 0x424C, 0x3158, 0x366E, 0, 0x366F, 0xE926, 0, 0, 0, 0, 0, 0, 0x4373, 0x714E, 0x3670, 0xE927, 0xE928, 0x326F, 0, 0, 0x714D, 0xE929, 0xE92A, 0x714B, 0xE92B, 0x714C, 0xE92C, 0x714A, 0, 0, 0x7158, 0, 0, 0, 0, 0xE92D, 0, 0, 0xE92E, 0xE92F, 0xE930, 0x714F, 0x7150, 0, 0xE931, 0x7151, 0x7152, 0, 0xE932, 0xE933, 0, 0, 0x7154, 0xE934, 0, 0x7153, 0, 0xE935, 0xE936, 0x3D59, }; const unsigned short utf8_to_euc_E9A8[] = { 0, 0x7155, 0xE937, 0xE938, 0xE939, 0x7157, 0, 0, 0, 0, 0, 0xE93A, 0xE93B, 0, 0x3533, 0x7156, 0xE93C, 0xE93D, 0x417B, 0x3833, 0, 0, 0xE93E, 0, 0, 0x7159, 0, 0, 0, 0, 0xE93F, 0, 0xE940, 0, 0xE941, 0xE942, 0xE943, 0, 0, 0xE944, 0x424D, 0, 0, 0x715A, 0, 0xE945, 0xE946, 0, 0x462D, 0, 0, 0xE947, 0, 0xE948, 0xE949, 0x715B, 0xE94A, 0, 0, 0, 0, 0, 0x7160, 0, }; const unsigned short utf8_to_euc_E9A9[] = { 0x715E, 0xE94C, 0x715D, 0x715F, 0xE94D, 0x715C, 0, 0xE94B, 0, 0, 0xE94E, 0xE94F, 0xE950, 0x7162, 0xE951, 0, 0, 0xE952, 0, 0, 0xE953, 0x7161, 0xE954, 0x7164, 0, 0, 0x3643, 0x7163, 0, 0xE955, 0, 0x7165, 0, 0, 0x7166, 0, 0x7168, 0x7167, 0, 0, 0, 0x7169, 0x716B, 0x716A, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E9AA[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x397C, 0, 0xE956, 0, 0xE957, 0x716C, 0xE958, 0xE959, 0x716D, 0, 0xE95A, 0, 0xE95B, 0xE95C, 0xE95D, 0, 0x333C, 0xE95E, 0, 0xE95F, 0x716E, 0, 0xE960, 0xE961, }; const unsigned short utf8_to_euc_E9AB[] = { 0x716F, 0xE962, 0, 0xE963, 0x3F71, 0, 0xE964, 0, 0xE965, 0, 0, 0, 0, 0, 0xE966, 0x7170, 0xE967, 0x7171, 0xE968, 0x7172, 0x7173, 0xE969, 0xE96A, 0xE96B, 0x3962, 0xF47B, 0, 0xE96C, 0xE96D, 0, 0x7174, 0x7175, 0xE96E, 0, 0x7176, 0x7177, 0xE96F, 0xE970, 0x7178, 0xE971, 0, 0xE972, 0x4831, 0x717A, 0xE973, 0x4926, 0x717B, 0x7179, 0, 0x717D, 0xE974, 0xE975, 0x717C, 0xE976, 0, 0x717E, 0, 0xE977, 0xE978, 0x7221, 0, 0xE979, 0, 0xE97A, }; const unsigned short utf8_to_euc_E9AC[] = { 0xE97B, 0xE97C, 0xE97D, 0xE97E, 0xEA21, 0xEA22, 0x7222, 0, 0xEA23, 0xEA24, 0, 0xEA25, 0xEA26, 0xEA27, 0xEA28, 0, 0xEA29, 0, 0xEA2A, 0, 0, 0, 0xEA2B, 0, 0x7223, 0xEA2C, 0x7224, 0xEA2D, 0xEA2E, 0, 0, 0x7225, 0xEA2F, 0, 0x7226, 0x7227, 0, 0x7228, 0xEA30, 0x7229, 0x722A, 0x722B, 0x722C, 0xEA31, 0, 0xEA32, 0x722D, 0x722E, 0, 0x5D35, 0x722F, 0xEA33, 0xEA34, 0xEA35, 0, 0xEA36, 0, 0xEA37, 0xEA38, 0x6478, 0x3534, 0xEA39, 0, 0, }; const unsigned short utf8_to_euc_E9AD[] = { 0, 0x3321, 0x3A32, 0x7231, 0x7230, 0x4C25, 0, 0, 0xEA3A, 0, 0, 0xEA3B, 0xEA3C, 0x7233, 0x7234, 0x7232, 0, 0x7235, 0, 0, 0x4B62, 0xEA3D, 0xEA3E, 0xEA3F, 0x7236, 0, 0x357B, 0xEA40, 0, 0, 0xEA41, 0, 0, 0xEA42, 0, 0xEA43, 0, 0xEA44, 0xEA45, 0, 0xEA46, 0, 0xEA47, 0xEA48, 0xEA49, 0xEA4A, 0xEA4B, 0x4F25, 0, 0, 0xF47C, 0xEA4C, 0x7237, 0xEA4D, 0, 0xEA4E, 0xEA4F, 0xEA50, 0, 0, 0, 0, 0, 0xEA51, }; const unsigned short utf8_to_euc_E9AE[] = { 0xEA52, 0, 0, 0x7239, 0xEA53, 0xEA54, 0xEA55, 0xEA56, 0, 0xEA57, 0xEA58, 0xEA59, 0, 0xEA5A, 0x303E, 0xEA5B, 0xEA5C, 0x723A, 0x4A2B, 0x7238, 0xEA5D, 0, 0x723B, 0x723C, 0, 0, 0xEA5E, 0, 0, 0xEA5F, 0xEA60, 0x723D, 0x723E, 0, 0, 0, 0, 0, 0xEA61, 0xEA62, 0x723F, 0xEA63, 0x4B6E, 0x3B2D, 0xEA64, 0x3A7A, 0x412F, 0, 0xEA65, 0xEA66, 0xEA67, 0, 0x7240, 0, 0, 0xEA68, 0xEA69, 0x7243, 0, 0xEA6A, 0xEA6B, 0, 0xEA6C, 0xEA6D, }; const unsigned short utf8_to_euc_E9AF[] = { 0x7241, 0xEA6E, 0, 0, 0, 0, 0x7244, 0xEA6F, 0xEA70, 0x3871, 0x7242, 0, 0, 0, 0xEA71, 0x7245, 0xEA72, 0x7246, 0x7247, 0, 0x724B, 0, 0x3B2A, 0xEA73, 0xEA74, 0, 0, 0x4264, 0, 0xEA75, 0, 0xEA76, 0, 0x724C, 0x7249, 0x7248, 0x724A, 0xEA77, 0, 0xEA78, 0x375F, 0, 0xEA79, 0xEA7A, 0, 0, 0, 0xEA7B, 0x7250, 0x724F, 0x724E, 0xEA7C, 0, 0x3033, 0, 0xEA7D, 0xEA7E, 0xEB21, 0xEB22, 0, 0, 0xEB23, 0, 0xEB24, }; const unsigned short utf8_to_euc_E9B0[] = { 0xEB25, 0, 0xEB26, 0, 0x725A, 0, 0x7256, 0, 0x7257, 0x7253, 0x7259, 0xEB27, 0x7255, 0x3362, 0, 0xEB28, 0x4F4C, 0xEB29, 0x7258, 0x7254, 0x7252, 0x7251, 0xEB2A, 0, 0xEB2B, 0xEB2C, 0xEB2D, 0x725C, 0xEB2E, 0, 0xEB2F, 0, 0, 0x725F, 0xEB30, 0xEB31, 0x725E, 0x725D, 0xEB32, 0xEB33, 0xEB34, 0xEB35, 0xEB36, 0, 0, 0x4949, 0x725B, 0x3073, 0x7260, 0xEB37, 0x7262, 0, 0, 0xEB38, 0xEB39, 0xEB3A, 0, 0x336F, 0x724D, 0x3137, 0, 0xEB3B, 0x7264, 0, }; const unsigned short utf8_to_euc_E9B1[] = { 0, 0xEB3C, 0, 0xEB3D, 0xEB3E, 0xEB3F, 0x7263, 0x7261, 0x432D, 0xEB40, 0xEB41, 0, 0, 0, 0xEB42, 0xEB43, 0xEB44, 0, 0x4B70, 0xEB45, 0xEB46, 0, 0xEB47, 0x4E5A, 0xEB48, 0, 0x7265, 0xEB49, 0xEB50, 0xEB4A, 0xEB4B, 0xEB4C, 0x7266, 0, 0, 0xEB4D, 0, 0, 0, 0x7267, 0xEB52, 0xEB4E, 0xEB4F, 0xEB51, 0, 0, 0xEB53, 0, 0xEB54, 0, 0xEB55, 0, 0, 0xEB56, 0x7268, 0xEB57, 0x7269, 0, 0, 0xEB58, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E9B3[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x443B, 0xEB59, 0x726A, 0, 0x4837, 0, 0x726F, 0x726B, 0, 0, 0, 0x726C, 0, 0xEB5A, 0x4B31, 0x4C44, 0, 0x4650, 0xEB5B, 0, 0xEB5C, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E9B4[] = { 0, 0, 0xEB5E, 0x7270, 0, 0, 0x7271, 0x463E, 0x726E, 0x726D, 0, 0xEB5D, 0, 0, 0x322A, 0, 0, 0xEB5F, 0x7279, 0, 0, 0x7278, 0, 0xEB60, 0xEB61, 0, 0, 0x3175, 0xEB62, 0xEB63, 0xEB64, 0x7276, 0, 0, 0, 0x7275, 0, 0, 0x7273, 0, 0x337B, 0, 0x7272, 0x3C32, 0x3229, 0, 0, 0xEB65, 0xEB66, 0, 0xEB67, 0xEB68, 0xEB69, 0, 0, 0, 0, 0, 0xEB6A, 0x3963, 0xEB6B, 0xEB6D, 0x727C, 0x727B, }; const unsigned short utf8_to_euc_E9B5[] = { 0, 0x727A, 0xEB6E, 0xEB6F, 0x7277, 0xEB6C, 0x727D, 0xEB70, 0x727E, 0, 0xEB71, 0, 0, 0, 0, 0, 0x7325, 0x7324, 0, 0xEB72, 0xEB73, 0, 0, 0, 0, 0x7326, 0, 0, 0x312D, 0x7321, 0x7322, 0xEB74, 0x3974, 0x4C39, 0xEB76, 0xEB75, 0x7323, 0xEB77, 0, 0, 0, 0xEB78, 0xEB79, 0xEB7A, 0x4B32, 0, 0, 0x732B, 0xEB7B, 0, 0x7327, 0, 0, 0, 0xEB7C, 0xEB7D, 0, 0, 0x732C, 0xEB7E, 0xEC21, 0, 0xEC22, 0, }; const unsigned short utf8_to_euc_E9B6[] = { 0, 0, 0, 0xEC23, 0xEC24, 0, 0xEC25, 0x7329, 0, 0x7328, 0xEC26, 0, 0, 0xEC27, 0xEC28, 0x375C, 0, 0, 0xEC29, 0xEC2A, 0, 0xEC2B, 0xEC2C, 0xEC2D, 0xEC2E, 0, 0x732D, 0, 0, 0, 0, 0, 0, 0xEC2F, 0, 0, 0x732E, 0, 0, 0, 0, 0x732F, 0xEC30, 0x732A, 0xEC31, 0, 0xEC32, 0x7274, 0, 0xEC33, 0x7330, 0, 0x4461, 0xEC34, 0, 0, 0x7334, 0xEC35, 0x7335, 0x7333, 0xEC36, 0, 0, 0xEC37, }; const unsigned short utf8_to_euc_E9B7[] = { 0, 0x7332, 0x7338, 0xEC38, 0x7331, 0, 0x7336, 0xEC39, 0, 0xEC3A, 0xEC3B, 0, 0, 0, 0, 0x7337, 0, 0, 0, 0x733A, 0xEC3C, 0xEC3D, 0xEC3E, 0xEC3F, 0, 0x7339, 0xEC40, 0, 0, 0, 0xEC41, 0xEC42, 0xEC43, 0, 0, 0, 0, 0xEC44, 0x733C, 0xEC45, 0, 0xEC46, 0, 0xEC47, 0, 0x733D, 0xEC48, 0x733E, 0xEC49, 0, 0x4F49, 0xEC4A, 0xEC4B, 0, 0, 0, 0x733B, 0x426B, 0x3A6D, 0, 0, 0x733F, 0xEC4C, 0, }; const unsigned short utf8_to_euc_E9B8[] = { 0, 0, 0xEC4E, 0, 0, 0, 0, 0xEC4F, 0, 0, 0xEC4D, 0, 0, 0, 0xEC50, 0, 0xEC51, 0xEC52, 0xEC53, 0, 0, 0xEC54, 0xEC55, 0, 0, 0xEC56, 0x7340, 0x7341, 0xEC57, 0xEC58, 0x7342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_E9B9[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x7343, 0, 0, 0x3834, 0x7344, 0xEC59, 0xEC5A, 0xEC5B, 0x7345, 0, 0x3C2F, }; const unsigned short utf8_to_euc_E9BA[] = { 0xEC5C, 0x7346, 0xEC5D, 0xEC5E, 0xEC5F, 0xEC60, 0, 0xEC61, 0x7347, 0, 0, 0x7348, 0x7349, 0, 0xEC62, 0xEC63, 0, 0x734C, 0x734A, 0x4F3C, 0, 0x734B, 0xEC64, 0x4E6F, 0xEC65, 0, 0, 0xEC66, 0, 0x734D, 0xEC67, 0x4E5B, 0, 0, 0, 0, 0xEC68, 0x734E, 0x477E, 0, 0xEC69, 0x734F, 0x7351, 0, 0xEC6A, 0x7352, 0xEC6B, 0xEC6C, 0xEC6D, 0, 0, 0xEC6E, 0xEC6F, 0xEC70, 0, 0, 0x7350, 0x396D, 0x4C4D, 0x4B63, 0x5677, 0, 0x5D60, 0x4B7B, }; const unsigned short utf8_to_euc_E9BB[] = { 0, 0, 0, 0, 0x322B, 0, 0xEC71, 0, 0xEC72, 0, 0, 0xEC73, 0x7354, 0x3550, 0x7355, 0x7356, 0x7357, 0xF47E, 0x3975, 0, 0x7358, 0xEC74, 0, 0, 0x6054, 0x4C5B, 0, 0x4263, 0x7359, 0x735B, 0x735A, 0xEC75, 0x735C, 0, 0, 0, 0xEC76, 0x735D, 0, 0xEC77, 0x735E, 0, 0, 0, 0xEC78, 0xEC79, 0xEC7A, 0x735F, 0xEC7B, 0xEC7C, 0xEC7D, 0, 0x7360, 0xEC7E, 0x7361, 0x7362, 0xED21, 0x7363, 0, 0x7364, 0x7365, 0x7366, 0, 0xED22, }; const unsigned short utf8_to_euc_E9BC[] = { 0, 0, 0xED23, 0xED24, 0, 0, 0, 0x7367, 0x7368, 0xED25, 0, 0, 0, 0, 0x4524, 0xED26, 0xED27, 0xED28, 0xED29, 0x385D, 0xED2A, 0x736A, 0xED2B, 0xED2C, 0, 0xED2D, 0xED2E, 0xED2F, 0, 0, 0, 0xED30, 0x414D, 0x736B, 0xED31, 0, 0, 0, 0xED32, 0, 0, 0, 0xED33, 0xED34, 0x736C, 0, 0, 0xED35, 0, 0xED36, 0xED37, 0, 0xED38, 0, 0, 0xED39, 0, 0xED3A, 0xED3B, 0x4921, 0xED3C, 0xED3D, 0x736D, 0xED3E, }; const unsigned short utf8_to_euc_E9BD[] = { 0, 0xED3F, 0, 0xED40, 0xED41, 0xED42, 0xED43, 0xED44, 0, 0, 0x736E, 0x6337, 0, 0, 0x6C5A, 0x706D, 0, 0, 0x736F, 0xED45, 0x7370, 0xED46, 0xED47, 0xED48, 0xED49, 0, 0xED4A, 0, 0, 0xED4B, 0xED4C, 0x7372, 0x7373, 0x7374, 0x4E70, 0x7371, 0, 0, 0x7375, 0x7376, 0xED4D, 0xED4E, 0x7378, 0, 0x7377, 0xED4F, 0xED50, 0xED51, 0xED52, 0xED53, 0x737A, 0xED54, 0, 0xED55, 0x737B, 0x7379, 0, 0, 0xED56, 0, 0, 0xED57, 0, 0, }; const unsigned short utf8_to_euc_E9BE[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x4E36, 0, 0xED58, 0xED59, 0xED5A, 0xED5B, 0, 0xED5C, 0x737C, 0xED5D, 0xED5E, 0, 0, 0, 0, 0x737D, 0x6354, 0xED5F, 0, 0x737E, 0xED60, 0xED61, 0xED62, 0, 0xED63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_EFA4[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xF445, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_EFA7[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xF472, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_EFA8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xF434, 0xF437, 0xF438, 0xF43D, 0xF444, 0xF447, 0xF448, 0xF44E, 0xF44F, 0xF453, 0xF455, 0xF456, 0xF457, 0xF458, 0xF45A, 0xF45B, 0xF45E, 0xF460, 0xF462, 0xF463, 0xF465, 0xF469, 0xF46A, 0xF46B, 0xF46D, 0xF46F, 0xF470, 0xF473, 0xF477, 0xF478, 0xF479, 0xF47D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_EFBC[] = { 0, 0x212A, 0xF42A, 0x2174, 0x2170, 0x2173, 0x2175, 0xF429, 0x214A, 0x214B, 0x2176, 0x215C, 0x2124, 0x215D, 0x2125, 0x213F, 0x2330, 0x2331, 0x2332, 0x2333, 0x2334, 0x2335, 0x2336, 0x2337, 0x2338, 0x2339, 0x2127, 0x2128, 0x2163, 0x2161, 0x2164, 0x2129, 0x2177, 0x2341, 0x2342, 0x2343, 0x2344, 0x2345, 0x2346, 0x2347, 0x2348, 0x2349, 0x234A, 0x234B, 0x234C, 0x234D, 0x234E, 0x234F, 0x2350, 0x2351, 0x2352, 0x2353, 0x2354, 0x2355, 0x2356, 0x2357, 0x2358, 0x2359, 0x235A, 0x214E, 0x2140, 0x214F, 0x2130, 0x2132, }; const unsigned short utf8_to_euc_EFBD[] = { 0x212E, 0x2361, 0x2362, 0x2363, 0x2364, 0x2365, 0x2366, 0x2367, 0x2368, 0x2369, 0x236A, 0x236B, 0x236C, 0x236D, 0x236E, 0x236F, 0x2370, 0x2371, 0x2372, 0x2373, 0x2374, 0x2375, 0x2376, 0x2377, 0x2378, 0x2379, 0x237A, 0x2150, 0x2143, 0x2151, 0xA237, 0, 0, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F, 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, 0x0E38, 0x0E39, 0x0E3A, 0x0E3B, 0x0E3C, 0x0E3D, 0x0E3E, 0x0E3F, }; const unsigned short utf8_to_euc_EFBD_ms[] = { 0x212E, 0x2361, 0x2362, 0x2363, 0x2364, 0x2365, 0x2366, 0x2367, 0x2368, 0x2369, 0x236A, 0x236B, 0x236C, 0x236D, 0x236E, 0x236F, 0x2370, 0x2371, 0x2372, 0x2373, 0x2374, 0x2375, 0x2376, 0x2377, 0x2378, 0x2379, 0x237A, 0x2150, 0x2143, 0x2151, 0x2141, 0, 0, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F, 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, 0x0E38, 0x0E39, 0x0E3A, 0x0E3B, 0x0E3C, 0x0E3D, 0x0E3E, 0x0E3F, }; const unsigned short utf8_to_euc_EFBE[] = { 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F, 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0x0E5C, 0x0E5D, 0x0E5E, 0x0E5F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short utf8_to_euc_EFBF[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2171, 0x2172, 0x224C, 0x2131, 0xA243, 0x216F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short *const utf8_to_euc_E2[] = { utf8_to_euc_E280, 0, 0, 0, utf8_to_euc_E284, utf8_to_euc_E285, utf8_to_euc_E286, utf8_to_euc_E287, utf8_to_euc_E288, utf8_to_euc_E289, utf8_to_euc_E28A, 0, utf8_to_euc_E28C, 0, 0, 0, 0, utf8_to_euc_E291, 0, 0, utf8_to_euc_E294, utf8_to_euc_E295, utf8_to_euc_E296, utf8_to_euc_E297, utf8_to_euc_E298, utf8_to_euc_E299, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short *const utf8_to_euc_E2_ms[] = { utf8_to_euc_E280_ms, 0, 0, 0, utf8_to_euc_E284, utf8_to_euc_E285, utf8_to_euc_E286, utf8_to_euc_E287, utf8_to_euc_E288, utf8_to_euc_E289, utf8_to_euc_E28A, 0, utf8_to_euc_E28C, 0, 0, 0, 0, utf8_to_euc_E291, 0, 0, utf8_to_euc_E294, utf8_to_euc_E295, utf8_to_euc_E296, utf8_to_euc_E297, utf8_to_euc_E298, utf8_to_euc_E299, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short *const utf8_to_euc_E2_932[] = { utf8_to_euc_E280_932, 0, 0, 0, utf8_to_euc_E284, utf8_to_euc_E285, utf8_to_euc_E286, utf8_to_euc_E287, utf8_to_euc_E288_932, utf8_to_euc_E289, utf8_to_euc_E28A, 0, utf8_to_euc_E28C, 0, 0, 0, 0, utf8_to_euc_E291, 0, 0, utf8_to_euc_E294, utf8_to_euc_E295, utf8_to_euc_E296, utf8_to_euc_E297, utf8_to_euc_E298, utf8_to_euc_E299, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short *const utf8_to_euc_E3[] = { utf8_to_euc_E380, utf8_to_euc_E381, utf8_to_euc_E382, utf8_to_euc_E383, 0, 0, 0, 0, utf8_to_euc_E388, 0, utf8_to_euc_E38A, 0, utf8_to_euc_E38C, utf8_to_euc_E38D, utf8_to_euc_E38E, utf8_to_euc_E38F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short *const utf8_to_euc_E3_932[] = { utf8_to_euc_E380_932, utf8_to_euc_E381, utf8_to_euc_E382_932, utf8_to_euc_E383, 0, 0, 0, 0, utf8_to_euc_E388, 0, utf8_to_euc_E38A, 0, utf8_to_euc_E38C, utf8_to_euc_E38D, utf8_to_euc_E38E, utf8_to_euc_E38F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short *const utf8_to_euc_E4[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, utf8_to_euc_E4B8, utf8_to_euc_E4B9, utf8_to_euc_E4BA, utf8_to_euc_E4BB, utf8_to_euc_E4BC, utf8_to_euc_E4BD, utf8_to_euc_E4BE, utf8_to_euc_E4BF, }; const unsigned short *const utf8_to_euc_E5[] = { utf8_to_euc_E580, utf8_to_euc_E581, utf8_to_euc_E582, utf8_to_euc_E583, utf8_to_euc_E584, utf8_to_euc_E585, utf8_to_euc_E586, utf8_to_euc_E587, utf8_to_euc_E588, utf8_to_euc_E589, utf8_to_euc_E58A, utf8_to_euc_E58B, utf8_to_euc_E58C, utf8_to_euc_E58D, utf8_to_euc_E58E, utf8_to_euc_E58F, utf8_to_euc_E590, utf8_to_euc_E591, utf8_to_euc_E592, utf8_to_euc_E593, utf8_to_euc_E594, utf8_to_euc_E595, utf8_to_euc_E596, utf8_to_euc_E597, utf8_to_euc_E598, utf8_to_euc_E599, utf8_to_euc_E59A, utf8_to_euc_E59B, utf8_to_euc_E59C, utf8_to_euc_E59D, utf8_to_euc_E59E, utf8_to_euc_E59F, utf8_to_euc_E5A0, utf8_to_euc_E5A1, utf8_to_euc_E5A2, utf8_to_euc_E5A3, utf8_to_euc_E5A4, utf8_to_euc_E5A5, utf8_to_euc_E5A6, utf8_to_euc_E5A7, utf8_to_euc_E5A8, utf8_to_euc_E5A9, utf8_to_euc_E5AA, utf8_to_euc_E5AB, utf8_to_euc_E5AC, utf8_to_euc_E5AD, utf8_to_euc_E5AE, utf8_to_euc_E5AF, utf8_to_euc_E5B0, utf8_to_euc_E5B1, utf8_to_euc_E5B2, utf8_to_euc_E5B3, utf8_to_euc_E5B4, utf8_to_euc_E5B5, utf8_to_euc_E5B6, utf8_to_euc_E5B7, utf8_to_euc_E5B8, utf8_to_euc_E5B9, utf8_to_euc_E5BA, utf8_to_euc_E5BB, utf8_to_euc_E5BC, utf8_to_euc_E5BD, utf8_to_euc_E5BE, utf8_to_euc_E5BF, }; const unsigned short *const utf8_to_euc_E6[] = { utf8_to_euc_E680, utf8_to_euc_E681, utf8_to_euc_E682, utf8_to_euc_E683, utf8_to_euc_E684, utf8_to_euc_E685, utf8_to_euc_E686, utf8_to_euc_E687, utf8_to_euc_E688, utf8_to_euc_E689, utf8_to_euc_E68A, utf8_to_euc_E68B, utf8_to_euc_E68C, utf8_to_euc_E68D, utf8_to_euc_E68E, utf8_to_euc_E68F, utf8_to_euc_E690, utf8_to_euc_E691, utf8_to_euc_E692, utf8_to_euc_E693, utf8_to_euc_E694, utf8_to_euc_E695, utf8_to_euc_E696, utf8_to_euc_E697, utf8_to_euc_E698, utf8_to_euc_E699, utf8_to_euc_E69A, utf8_to_euc_E69B, utf8_to_euc_E69C, utf8_to_euc_E69D, utf8_to_euc_E69E, utf8_to_euc_E69F, utf8_to_euc_E6A0, utf8_to_euc_E6A1, utf8_to_euc_E6A2, utf8_to_euc_E6A3, utf8_to_euc_E6A4, utf8_to_euc_E6A5, utf8_to_euc_E6A6, utf8_to_euc_E6A7, utf8_to_euc_E6A8, utf8_to_euc_E6A9, utf8_to_euc_E6AA, utf8_to_euc_E6AB, utf8_to_euc_E6AC, utf8_to_euc_E6AD, utf8_to_euc_E6AE, utf8_to_euc_E6AF, utf8_to_euc_E6B0, utf8_to_euc_E6B1, utf8_to_euc_E6B2, utf8_to_euc_E6B3, utf8_to_euc_E6B4, utf8_to_euc_E6B5, utf8_to_euc_E6B6, utf8_to_euc_E6B7, utf8_to_euc_E6B8, utf8_to_euc_E6B9, utf8_to_euc_E6BA, utf8_to_euc_E6BB, utf8_to_euc_E6BC, utf8_to_euc_E6BD, utf8_to_euc_E6BE, utf8_to_euc_E6BF, }; const unsigned short *const utf8_to_euc_E7[] = { utf8_to_euc_E780, utf8_to_euc_E781, utf8_to_euc_E782, utf8_to_euc_E783, utf8_to_euc_E784, utf8_to_euc_E785, utf8_to_euc_E786, utf8_to_euc_E787, utf8_to_euc_E788, utf8_to_euc_E789, utf8_to_euc_E78A, utf8_to_euc_E78B, utf8_to_euc_E78C, utf8_to_euc_E78D, utf8_to_euc_E78E, utf8_to_euc_E78F, utf8_to_euc_E790, utf8_to_euc_E791, utf8_to_euc_E792, utf8_to_euc_E793, utf8_to_euc_E794, utf8_to_euc_E795, utf8_to_euc_E796, utf8_to_euc_E797, utf8_to_euc_E798, utf8_to_euc_E799, utf8_to_euc_E79A, utf8_to_euc_E79B, utf8_to_euc_E79C, utf8_to_euc_E79D, utf8_to_euc_E79E, utf8_to_euc_E79F, utf8_to_euc_E7A0, utf8_to_euc_E7A1, utf8_to_euc_E7A2, utf8_to_euc_E7A3, utf8_to_euc_E7A4, utf8_to_euc_E7A5, utf8_to_euc_E7A6, utf8_to_euc_E7A7, utf8_to_euc_E7A8, utf8_to_euc_E7A9, utf8_to_euc_E7AA, utf8_to_euc_E7AB, utf8_to_euc_E7AC, utf8_to_euc_E7AD, utf8_to_euc_E7AE, utf8_to_euc_E7AF, utf8_to_euc_E7B0, utf8_to_euc_E7B1, utf8_to_euc_E7B2, utf8_to_euc_E7B3, utf8_to_euc_E7B4, utf8_to_euc_E7B5, utf8_to_euc_E7B6, utf8_to_euc_E7B7, utf8_to_euc_E7B8, utf8_to_euc_E7B9, utf8_to_euc_E7BA, 0, utf8_to_euc_E7BC, utf8_to_euc_E7BD, utf8_to_euc_E7BE, utf8_to_euc_E7BF, }; const unsigned short *const utf8_to_euc_E8[] = { utf8_to_euc_E880, utf8_to_euc_E881, utf8_to_euc_E882, utf8_to_euc_E883, utf8_to_euc_E884, utf8_to_euc_E885, utf8_to_euc_E886, utf8_to_euc_E887, utf8_to_euc_E888, utf8_to_euc_E889, utf8_to_euc_E88A, utf8_to_euc_E88B, utf8_to_euc_E88C, utf8_to_euc_E88D, utf8_to_euc_E88E, utf8_to_euc_E88F, utf8_to_euc_E890, utf8_to_euc_E891, utf8_to_euc_E892, utf8_to_euc_E893, utf8_to_euc_E894, utf8_to_euc_E895, utf8_to_euc_E896, utf8_to_euc_E897, utf8_to_euc_E898, utf8_to_euc_E899, utf8_to_euc_E89A, utf8_to_euc_E89B, utf8_to_euc_E89C, utf8_to_euc_E89D, utf8_to_euc_E89E, utf8_to_euc_E89F, utf8_to_euc_E8A0, utf8_to_euc_E8A1, utf8_to_euc_E8A2, utf8_to_euc_E8A3, utf8_to_euc_E8A4, utf8_to_euc_E8A5, utf8_to_euc_E8A6, utf8_to_euc_E8A7, utf8_to_euc_E8A8, utf8_to_euc_E8A9, utf8_to_euc_E8AA, utf8_to_euc_E8AB, utf8_to_euc_E8AC, utf8_to_euc_E8AD, utf8_to_euc_E8AE, 0, utf8_to_euc_E8B0, utf8_to_euc_E8B1, utf8_to_euc_E8B2, utf8_to_euc_E8B3, utf8_to_euc_E8B4, utf8_to_euc_E8B5, utf8_to_euc_E8B6, utf8_to_euc_E8B7, utf8_to_euc_E8B8, utf8_to_euc_E8B9, utf8_to_euc_E8BA, utf8_to_euc_E8BB, utf8_to_euc_E8BC, utf8_to_euc_E8BD, utf8_to_euc_E8BE, utf8_to_euc_E8BF, }; const unsigned short *const utf8_to_euc_E9[] = { utf8_to_euc_E980, utf8_to_euc_E981, utf8_to_euc_E982, utf8_to_euc_E983, utf8_to_euc_E984, utf8_to_euc_E985, utf8_to_euc_E986, utf8_to_euc_E987, utf8_to_euc_E988, utf8_to_euc_E989, utf8_to_euc_E98A, utf8_to_euc_E98B, utf8_to_euc_E98C, utf8_to_euc_E98D, utf8_to_euc_E98E, utf8_to_euc_E98F, utf8_to_euc_E990, utf8_to_euc_E991, utf8_to_euc_E992, 0, 0, utf8_to_euc_E995, utf8_to_euc_E996, utf8_to_euc_E997, utf8_to_euc_E998, utf8_to_euc_E999, utf8_to_euc_E99A, utf8_to_euc_E99B, utf8_to_euc_E99C, utf8_to_euc_E99D, utf8_to_euc_E99E, utf8_to_euc_E99F, utf8_to_euc_E9A0, utf8_to_euc_E9A1, utf8_to_euc_E9A2, utf8_to_euc_E9A3, utf8_to_euc_E9A4, utf8_to_euc_E9A5, utf8_to_euc_E9A6, utf8_to_euc_E9A7, utf8_to_euc_E9A8, utf8_to_euc_E9A9, utf8_to_euc_E9AA, utf8_to_euc_E9AB, utf8_to_euc_E9AC, utf8_to_euc_E9AD, utf8_to_euc_E9AE, utf8_to_euc_E9AF, utf8_to_euc_E9B0, utf8_to_euc_E9B1, 0, utf8_to_euc_E9B3, utf8_to_euc_E9B4, utf8_to_euc_E9B5, utf8_to_euc_E9B6, utf8_to_euc_E9B7, utf8_to_euc_E9B8, utf8_to_euc_E9B9, utf8_to_euc_E9BA, utf8_to_euc_E9BB, utf8_to_euc_E9BC, utf8_to_euc_E9BD, utf8_to_euc_E9BE, 0, }; const unsigned short *const utf8_to_euc_EF[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, utf8_to_euc_EFA4, 0, 0, utf8_to_euc_EFA7, utf8_to_euc_EFA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, utf8_to_euc_EFBC, utf8_to_euc_EFBD, utf8_to_euc_EFBE, utf8_to_euc_EFBF, }; const unsigned short *const utf8_to_euc_EF_ms[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, utf8_to_euc_EFA4, 0, 0, utf8_to_euc_EFA7, utf8_to_euc_EFA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, utf8_to_euc_EFBC, utf8_to_euc_EFBD_ms, utf8_to_euc_EFBE, utf8_to_euc_EFBF, }; const unsigned short *const utf8_to_euc_2bytes[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, utf8_to_euc_C2, utf8_to_euc_C3, utf8_to_euc_C4, utf8_to_euc_C5, 0, utf8_to_euc_C7, 0, 0, 0, utf8_to_euc_CB, 0, 0, utf8_to_euc_CE, utf8_to_euc_CF, utf8_to_euc_D0, utf8_to_euc_D1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short *const utf8_to_euc_2bytes_ms[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, utf8_to_euc_C2_ms, utf8_to_euc_C3, utf8_to_euc_C4, utf8_to_euc_C5, 0, utf8_to_euc_C7, 0, 0, 0, utf8_to_euc_CB, 0, 0, utf8_to_euc_CE, utf8_to_euc_CF, utf8_to_euc_D0, utf8_to_euc_D1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short *const utf8_to_euc_2bytes_932[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, utf8_to_euc_C2_932, utf8_to_euc_C3_932, utf8_to_euc_C4, utf8_to_euc_C5, 0, utf8_to_euc_C7, 0, 0, 0, utf8_to_euc_CB, 0, 0, utf8_to_euc_CE, utf8_to_euc_CF, utf8_to_euc_D0, utf8_to_euc_D1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short *const *const utf8_to_euc_3bytes[] = { 0, 0, utf8_to_euc_E2, utf8_to_euc_E3, utf8_to_euc_E4, utf8_to_euc_E5, utf8_to_euc_E6, utf8_to_euc_E7, utf8_to_euc_E8, utf8_to_euc_E9, 0, 0, 0, 0, 0, utf8_to_euc_EF, }; const unsigned short *const *const utf8_to_euc_3bytes_ms[] = { 0, 0, utf8_to_euc_E2_ms, utf8_to_euc_E3, utf8_to_euc_E4, utf8_to_euc_E5, utf8_to_euc_E6, utf8_to_euc_E7, utf8_to_euc_E8, utf8_to_euc_E9, 0, 0, 0, 0, 0, utf8_to_euc_EF_ms, }; const unsigned short *const *const utf8_to_euc_3bytes_932[] = { 0, 0, utf8_to_euc_E2_932, utf8_to_euc_E3_932, utf8_to_euc_E4, utf8_to_euc_E5, utf8_to_euc_E6, utf8_to_euc_E7, utf8_to_euc_E8, utf8_to_euc_E9, 0, 0, 0, 0, 0, utf8_to_euc_EF_ms, }; #ifdef UNICODE_NORMALIZATION /* Normalization Table by Apple */ /* http://developer.apple.com/technotes/tn/tn1150table.html */ const struct normalization_pair normalization_table[] = { {{0xcd,0xbe}, {0x3b}}, {{0xc3,0x80}, {0x41,0xcc,0x80,0x00}}, {{0xc3,0x81}, {0x41,0xcc,0x81}}, {{0xc3,0x82}, {0x41,0xcc,0x82}}, {{0xe1,0xba,0xa6}, {0x41,0xcc,0x82,0xcc,0x80}}, {{0xe1,0xba,0xa4}, {0x41,0xcc,0x82,0xcc,0x81}}, {{0xe1,0xba,0xaa}, {0x41,0xcc,0x82,0xcc,0x83}}, {{0xe1,0xba,0xa8}, {0x41,0xcc,0x82,0xcc,0x89}}, {{0xc3,0x83}, {0x41,0xcc,0x83}}, {{0xc4,0x80}, {0x41,0xcc,0x84}}, {{0xc4,0x82}, {0x41,0xcc,0x86}}, {{0xe1,0xba,0xb0}, {0x41,0xcc,0x86,0xcc,0x80}}, {{0xe1,0xba,0xae}, {0x41,0xcc,0x86,0xcc,0x81}}, {{0xe1,0xba,0xb4}, {0x41,0xcc,0x86,0xcc,0x83}}, {{0xe1,0xba,0xb2}, {0x41,0xcc,0x86,0xcc,0x89}}, {{0xc7,0xa0}, {0x41,0xcc,0x87,0xcc,0x84}}, {{0xc3,0x84}, {0x41,0xcc,0x88}}, {{0xc7,0x9e}, {0x41,0xcc,0x88,0xcc,0x84}}, {{0xe1,0xba,0xa2}, {0x41,0xcc,0x89}}, {{0xc3,0x85}, {0x41,0xcc,0x8a}}, {{0xc7,0xba}, {0x41,0xcc,0x8a,0xcc,0x81}}, {{0xc7,0x8d}, {0x41,0xcc,0x8c}}, {{0xc8,0x80}, {0x41,0xcc,0x8f}}, {{0xc8,0x82}, {0x41,0xcc,0x91}}, {{0xe1,0xba,0xa0}, {0x41,0xcc,0xa3}}, {{0xe1,0xba,0xac}, {0x41,0xcc,0xa3,0xcc,0x82}}, {{0xe1,0xba,0xb6}, {0x41,0xcc,0xa3,0xcc,0x86}}, {{0xe1,0xb8,0x80}, {0x41,0xcc,0xa5}}, {{0xc4,0x84}, {0x41,0xcc,0xa8}}, {{0xe1,0xb8,0x82}, {0x42,0xcc,0x87}}, {{0xe1,0xb8,0x84}, {0x42,0xcc,0xa3}}, {{0xe1,0xb8,0x86}, {0x42,0xcc,0xb1}}, {{0xc4,0x86}, {0x43,0xcc,0x81}}, {{0xc4,0x88}, {0x43,0xcc,0x82}}, {{0xc4,0x8a}, {0x43,0xcc,0x87}}, {{0xc4,0x8c}, {0x43,0xcc,0x8c}}, {{0xc3,0x87}, {0x43,0xcc,0xa7}}, {{0xe1,0xb8,0x88}, {0x43,0xcc,0xa7,0xcc,0x81}}, {{0xe1,0xb8,0x8a}, {0x44,0xcc,0x87}}, {{0xc4,0x8e}, {0x44,0xcc,0x8c}}, {{0xe1,0xb8,0x8c}, {0x44,0xcc,0xa3}}, {{0xe1,0xb8,0x90}, {0x44,0xcc,0xa7}}, {{0xe1,0xb8,0x92}, {0x44,0xcc,0xad}}, {{0xe1,0xb8,0x8e}, {0x44,0xcc,0xb1}}, {{0xc3,0x88}, {0x45,0xcc,0x80}}, {{0xc3,0x89}, {0x45,0xcc,0x81}}, {{0xc3,0x8a}, {0x45,0xcc,0x82}}, {{0xe1,0xbb,0x80}, {0x45,0xcc,0x82,0xcc,0x80}}, {{0xe1,0xba,0xbe}, {0x45,0xcc,0x82,0xcc,0x81}}, {{0xe1,0xbb,0x84}, {0x45,0xcc,0x82,0xcc,0x83}}, {{0xe1,0xbb,0x82}, {0x45,0xcc,0x82,0xcc,0x89}}, {{0xe1,0xba,0xbc}, {0x45,0xcc,0x83}}, {{0xc4,0x92}, {0x45,0xcc,0x84}}, {{0xe1,0xb8,0x94}, {0x45,0xcc,0x84,0xcc,0x80}}, {{0xe1,0xb8,0x96}, {0x45,0xcc,0x84,0xcc,0x81}}, {{0xc4,0x94}, {0x45,0xcc,0x86}}, {{0xc4,0x96}, {0x45,0xcc,0x87}}, {{0xc3,0x8b}, {0x45,0xcc,0x88}}, {{0xe1,0xba,0xba}, {0x45,0xcc,0x89}}, {{0xc4,0x9a}, {0x45,0xcc,0x8c}}, {{0xc8,0x84}, {0x45,0xcc,0x8f}}, {{0xc8,0x86}, {0x45,0xcc,0x91}}, {{0xe1,0xba,0xb8}, {0x45,0xcc,0xa3}}, {{0xe1,0xbb,0x86}, {0x45,0xcc,0xa3,0xcc,0x82}}, {{0xe1,0xb8,0x9c}, {0x45,0xcc,0xa7,0xcc,0x86}}, {{0xc4,0x98}, {0x45,0xcc,0xa8}}, {{0xe1,0xb8,0x98}, {0x45,0xcc,0xad}}, {{0xe1,0xb8,0x9a}, {0x45,0xcc,0xb0}}, {{0xe1,0xb8,0x9e}, {0x46,0xcc,0x87}}, {{0xc7,0xb4}, {0x47,0xcc,0x81}}, {{0xc4,0x9c}, {0x47,0xcc,0x82}}, {{0xe1,0xb8,0xa0}, {0x47,0xcc,0x84}}, {{0xc4,0x9e}, {0x47,0xcc,0x86}}, {{0xc4,0xa0}, {0x47,0xcc,0x87}}, {{0xc7,0xa6}, {0x47,0xcc,0x8c}}, {{0xc4,0xa2}, {0x47,0xcc,0xa7}}, {{0xc4,0xa4}, {0x48,0xcc,0x82}}, {{0xe1,0xb8,0xa2}, {0x48,0xcc,0x87}}, {{0xe1,0xb8,0xa6}, {0x48,0xcc,0x88}}, {{0xe1,0xb8,0xa4}, {0x48,0xcc,0xa3}}, {{0xe1,0xb8,0xa8}, {0x48,0xcc,0xa7}}, {{0xe1,0xb8,0xaa}, {0x48,0xcc,0xae}}, {{0xc3,0x8c}, {0x49,0xcc,0x80}}, {{0xc3,0x8d}, {0x49,0xcc,0x81}}, {{0xc3,0x8e}, {0x49,0xcc,0x82}}, {{0xc4,0xa8}, {0x49,0xcc,0x83}}, {{0xc4,0xaa}, {0x49,0xcc,0x84}}, {{0xc4,0xac}, {0x49,0xcc,0x86}}, {{0xc4,0xb0}, {0x49,0xcc,0x87}}, {{0xc3,0x8f}, {0x49,0xcc,0x88}}, {{0xe1,0xb8,0xae}, {0x49,0xcc,0x88,0xcc,0x81}}, {{0xe1,0xbb,0x88}, {0x49,0xcc,0x89}}, {{0xc7,0x8f}, {0x49,0xcc,0x8c}}, {{0xc8,0x88}, {0x49,0xcc,0x8f}}, {{0xc8,0x8a}, {0x49,0xcc,0x91}}, {{0xe1,0xbb,0x8a}, {0x49,0xcc,0xa3}}, {{0xc4,0xae}, {0x49,0xcc,0xa8}}, {{0xe1,0xb8,0xac}, {0x49,0xcc,0xb0}}, {{0xc4,0xb4}, {0x4a,0xcc,0x82}}, {{0xe1,0xb8,0xb0}, {0x4b,0xcc,0x81}}, {{0xc7,0xa8}, {0x4b,0xcc,0x8c}}, {{0xe1,0xb8,0xb2}, {0x4b,0xcc,0xa3}}, {{0xc4,0xb6}, {0x4b,0xcc,0xa7}}, {{0xe1,0xb8,0xb4}, {0x4b,0xcc,0xb1}}, {{0xc4,0xb9}, {0x4c,0xcc,0x81}}, {{0xc4,0xbd}, {0x4c,0xcc,0x8c}}, {{0xe1,0xb8,0xb6}, {0x4c,0xcc,0xa3}}, {{0xe1,0xb8,0xb8}, {0x4c,0xcc,0xa3,0xcc,0x84}}, {{0xc4,0xbb}, {0x4c,0xcc,0xa7}}, {{0xe1,0xb8,0xbc}, {0x4c,0xcc,0xad}}, {{0xe1,0xb8,0xba}, {0x4c,0xcc,0xb1}}, {{0xe1,0xb8,0xbe}, {0x4d,0xcc,0x81}}, {{0xe1,0xb9,0x80}, {0x4d,0xcc,0x87}}, {{0xe1,0xb9,0x82}, {0x4d,0xcc,0xa3}}, {{0xc5,0x83}, {0x4e,0xcc,0x81}}, {{0xc3,0x91}, {0x4e,0xcc,0x83}}, {{0xe1,0xb9,0x84}, {0x4e,0xcc,0x87}}, {{0xc5,0x87}, {0x4e,0xcc,0x8c}}, {{0xe1,0xb9,0x86}, {0x4e,0xcc,0xa3}}, {{0xc5,0x85}, {0x4e,0xcc,0xa7}}, {{0xe1,0xb9,0x8a}, {0x4e,0xcc,0xad}}, {{0xe1,0xb9,0x88}, {0x4e,0xcc,0xb1}}, {{0xc3,0x92}, {0x4f,0xcc,0x80}}, {{0xc3,0x93}, {0x4f,0xcc,0x81}}, {{0xc3,0x94}, {0x4f,0xcc,0x82}}, {{0xe1,0xbb,0x92}, {0x4f,0xcc,0x82,0xcc,0x80}}, {{0xe1,0xbb,0x90}, {0x4f,0xcc,0x82,0xcc,0x81}}, {{0xe1,0xbb,0x96}, {0x4f,0xcc,0x82,0xcc,0x83}}, {{0xe1,0xbb,0x94}, {0x4f,0xcc,0x82,0xcc,0x89}}, {{0xc3,0x95}, {0x4f,0xcc,0x83}}, {{0xe1,0xb9,0x8c}, {0x4f,0xcc,0x83,0xcc,0x81}}, {{0xe1,0xb9,0x8e}, {0x4f,0xcc,0x83,0xcc,0x88}}, {{0xc5,0x8c}, {0x4f,0xcc,0x84}}, {{0xe1,0xb9,0x90}, {0x4f,0xcc,0x84,0xcc,0x80}}, {{0xe1,0xb9,0x92}, {0x4f,0xcc,0x84,0xcc,0x81}}, {{0xc5,0x8e}, {0x4f,0xcc,0x86}}, {{0xc3,0x96}, {0x4f,0xcc,0x88}}, {{0xe1,0xbb,0x8e}, {0x4f,0xcc,0x89}}, {{0xc5,0x90}, {0x4f,0xcc,0x8b}}, {{0xc7,0x91}, {0x4f,0xcc,0x8c}}, {{0xc8,0x8c}, {0x4f,0xcc,0x8f}}, {{0xc8,0x8e}, {0x4f,0xcc,0x91}}, {{0xc6,0xa0}, {0x4f,0xcc,0x9b}}, {{0xe1,0xbb,0x9c}, {0x4f,0xcc,0x9b,0xcc,0x80}}, {{0xe1,0xbb,0x9a}, {0x4f,0xcc,0x9b,0xcc,0x81}}, {{0xe1,0xbb,0xa0}, {0x4f,0xcc,0x9b,0xcc,0x83}}, {{0xe1,0xbb,0x9e}, {0x4f,0xcc,0x9b,0xcc,0x89}}, {{0xe1,0xbb,0xa2}, {0x4f,0xcc,0x9b,0xcc,0xa3}}, {{0xe1,0xbb,0x8c}, {0x4f,0xcc,0xa3}}, {{0xe1,0xbb,0x98}, {0x4f,0xcc,0xa3,0xcc,0x82}}, {{0xc7,0xaa}, {0x4f,0xcc,0xa8}}, {{0xc7,0xac}, {0x4f,0xcc,0xa8,0xcc,0x84}}, {{0xe1,0xb9,0x94}, {0x50,0xcc,0x81}}, {{0xe1,0xb9,0x96}, {0x50,0xcc,0x87}}, {{0xc5,0x94}, {0x52,0xcc,0x81}}, {{0xe1,0xb9,0x98}, {0x52,0xcc,0x87}}, {{0xc5,0x98}, {0x52,0xcc,0x8c}}, {{0xc8,0x90}, {0x52,0xcc,0x8f}}, {{0xc8,0x92}, {0x52,0xcc,0x91}}, {{0xe1,0xb9,0x9a}, {0x52,0xcc,0xa3}}, {{0xe1,0xb9,0x9c}, {0x52,0xcc,0xa3,0xcc,0x84}}, {{0xc5,0x96}, {0x52,0xcc,0xa7}}, {{0xe1,0xb9,0x9e}, {0x52,0xcc,0xb1}}, {{0xc5,0x9a}, {0x53,0xcc,0x81}}, {{0xe1,0xb9,0xa4}, {0x53,0xcc,0x81,0xcc,0x87}}, {{0xc5,0x9c}, {0x53,0xcc,0x82}}, {{0xe1,0xb9,0xa0}, {0x53,0xcc,0x87}}, {{0xc5,0xa0}, {0x53,0xcc,0x8c}}, {{0xe1,0xb9,0xa6}, {0x53,0xcc,0x8c,0xcc,0x87}}, {{0xe1,0xb9,0xa2}, {0x53,0xcc,0xa3}}, {{0xe1,0xb9,0xa8}, {0x53,0xcc,0xa3,0xcc,0x87}}, {{0xc5,0x9e}, {0x53,0xcc,0xa7}}, {{0xe1,0xb9,0xaa}, {0x54,0xcc,0x87}}, {{0xc5,0xa4}, {0x54,0xcc,0x8c}}, {{0xe1,0xb9,0xac}, {0x54,0xcc,0xa3}}, {{0xc5,0xa2}, {0x54,0xcc,0xa7}}, {{0xe1,0xb9,0xb0}, {0x54,0xcc,0xad}}, {{0xe1,0xb9,0xae}, {0x54,0xcc,0xb1}}, {{0xc3,0x99}, {0x55,0xcc,0x80}}, {{0xc3,0x9a}, {0x55,0xcc,0x81}}, {{0xc3,0x9b}, {0x55,0xcc,0x82}}, {{0xc5,0xa8}, {0x55,0xcc,0x83}}, {{0xe1,0xb9,0xb8}, {0x55,0xcc,0x83,0xcc,0x81}}, {{0xc5,0xaa}, {0x55,0xcc,0x84}}, {{0xe1,0xb9,0xba}, {0x55,0xcc,0x84,0xcc,0x88}}, {{0xc5,0xac}, {0x55,0xcc,0x86}}, {{0xc3,0x9c}, {0x55,0xcc,0x88}}, {{0xc7,0x9b}, {0x55,0xcc,0x88,0xcc,0x80}}, {{0xc7,0x97}, {0x55,0xcc,0x88,0xcc,0x81}}, {{0xc7,0x95}, {0x55,0xcc,0x88,0xcc,0x84}}, {{0xc7,0x99}, {0x55,0xcc,0x88,0xcc,0x8c}}, {{0xe1,0xbb,0xa6}, {0x55,0xcc,0x89}}, {{0xc5,0xae}, {0x55,0xcc,0x8a}}, {{0xc5,0xb0}, {0x55,0xcc,0x8b}}, {{0xc7,0x93}, {0x55,0xcc,0x8c}}, {{0xc8,0x94}, {0x55,0xcc,0x8f}}, {{0xc8,0x96}, {0x55,0xcc,0x91}}, {{0xc6,0xaf}, {0x55,0xcc,0x9b}}, {{0xe1,0xbb,0xaa}, {0x55,0xcc,0x9b,0xcc,0x80}}, {{0xe1,0xbb,0xa8}, {0x55,0xcc,0x9b,0xcc,0x81}}, {{0xe1,0xbb,0xae}, {0x55,0xcc,0x9b,0xcc,0x83}}, {{0xe1,0xbb,0xac}, {0x55,0xcc,0x9b,0xcc,0x89}}, {{0xe1,0xbb,0xb0}, {0x55,0xcc,0x9b,0xcc,0xa3}}, {{0xe1,0xbb,0xa4}, {0x55,0xcc,0xa3}}, {{0xe1,0xb9,0xb2}, {0x55,0xcc,0xa4}}, {{0xc5,0xb2}, {0x55,0xcc,0xa8}}, {{0xe1,0xb9,0xb6}, {0x55,0xcc,0xad}}, {{0xe1,0xb9,0xb4}, {0x55,0xcc,0xb0}}, {{0xe1,0xb9,0xbc}, {0x56,0xcc,0x83}}, {{0xe1,0xb9,0xbe}, {0x56,0xcc,0xa3}}, {{0xe1,0xba,0x80}, {0x57,0xcc,0x80}}, {{0xe1,0xba,0x82}, {0x57,0xcc,0x81}}, {{0xc5,0xb4}, {0x57,0xcc,0x82}}, {{0xe1,0xba,0x86}, {0x57,0xcc,0x87}}, {{0xe1,0xba,0x84}, {0x57,0xcc,0x88}}, {{0xe1,0xba,0x88}, {0x57,0xcc,0xa3}}, {{0xe1,0xba,0x8a}, {0x58,0xcc,0x87}}, {{0xe1,0xba,0x8c}, {0x58,0xcc,0x88}}, {{0xe1,0xbb,0xb2}, {0x59,0xcc,0x80}}, {{0xc3,0x9d}, {0x59,0xcc,0x81}}, {{0xc5,0xb6}, {0x59,0xcc,0x82}}, {{0xe1,0xbb,0xb8}, {0x59,0xcc,0x83}}, {{0xe1,0xba,0x8e}, {0x59,0xcc,0x87}}, {{0xc5,0xb8}, {0x59,0xcc,0x88}}, {{0xe1,0xbb,0xb6}, {0x59,0xcc,0x89}}, {{0xe1,0xbb,0xb4}, {0x59,0xcc,0xa3}}, {{0xc5,0xb9}, {0x5a,0xcc,0x81}}, {{0xe1,0xba,0x90}, {0x5a,0xcc,0x82}}, {{0xc5,0xbb}, {0x5a,0xcc,0x87}}, {{0xc5,0xbd}, {0x5a,0xcc,0x8c}}, {{0xe1,0xba,0x92}, {0x5a,0xcc,0xa3}}, {{0xe1,0xba,0x94}, {0x5a,0xcc,0xb1}}, {{0xe1,0xbf,0xaf}, {0x60}}, {{0xc3,0xa0}, {0x61,0xcc,0x80}}, {{0xc3,0xa1}, {0x61,0xcc,0x81}}, {{0xc3,0xa2}, {0x61,0xcc,0x82}}, {{0xe1,0xba,0xa7}, {0x61,0xcc,0x82,0xcc,0x80}}, {{0xe1,0xba,0xa5}, {0x61,0xcc,0x82,0xcc,0x81}}, {{0xe1,0xba,0xab}, {0x61,0xcc,0x82,0xcc,0x83}}, {{0xe1,0xba,0xa9}, {0x61,0xcc,0x82,0xcc,0x89}}, {{0xc3,0xa3}, {0x61,0xcc,0x83}}, {{0xc4,0x81}, {0x61,0xcc,0x84}}, {{0xc4,0x83}, {0x61,0xcc,0x86}}, {{0xe1,0xba,0xb1}, {0x61,0xcc,0x86,0xcc,0x80}}, {{0xe1,0xba,0xaf}, {0x61,0xcc,0x86,0xcc,0x81}}, {{0xe1,0xba,0xb5}, {0x61,0xcc,0x86,0xcc,0x83}}, {{0xe1,0xba,0xb3}, {0x61,0xcc,0x86,0xcc,0x89}}, {{0xc7,0xa1}, {0x61,0xcc,0x87,0xcc,0x84}}, {{0xc3,0xa4}, {0x61,0xcc,0x88}}, {{0xc7,0x9f}, {0x61,0xcc,0x88,0xcc,0x84}}, {{0xe1,0xba,0xa3}, {0x61,0xcc,0x89}}, {{0xc3,0xa5}, {0x61,0xcc,0x8a}}, {{0xc7,0xbb}, {0x61,0xcc,0x8a,0xcc,0x81}}, {{0xc7,0x8e}, {0x61,0xcc,0x8c}}, {{0xc8,0x81}, {0x61,0xcc,0x8f}}, {{0xc8,0x83}, {0x61,0xcc,0x91}}, {{0xe1,0xba,0xa1}, {0x61,0xcc,0xa3}}, {{0xe1,0xba,0xad}, {0x61,0xcc,0xa3,0xcc,0x82}}, {{0xe1,0xba,0xb7}, {0x61,0xcc,0xa3,0xcc,0x86}}, {{0xe1,0xb8,0x81}, {0x61,0xcc,0xa5}}, {{0xc4,0x85}, {0x61,0xcc,0xa8}}, {{0xe1,0xb8,0x83}, {0x62,0xcc,0x87}}, {{0xe1,0xb8,0x85}, {0x62,0xcc,0xa3}}, {{0xe1,0xb8,0x87}, {0x62,0xcc,0xb1}}, {{0xc4,0x87}, {0x63,0xcc,0x81}}, {{0xc4,0x89}, {0x63,0xcc,0x82}}, {{0xc4,0x8b}, {0x63,0xcc,0x87}}, {{0xc4,0x8d}, {0x63,0xcc,0x8c}}, {{0xc3,0xa7}, {0x63,0xcc,0xa7}}, {{0xe1,0xb8,0x89}, {0x63,0xcc,0xa7,0xcc,0x81}}, {{0xe1,0xb8,0x8b}, {0x64,0xcc,0x87}}, {{0xc4,0x8f}, {0x64,0xcc,0x8c}}, {{0xe1,0xb8,0x8d}, {0x64,0xcc,0xa3}}, {{0xe1,0xb8,0x91}, {0x64,0xcc,0xa7}}, {{0xe1,0xb8,0x93}, {0x64,0xcc,0xad}}, {{0xe1,0xb8,0x8f}, {0x64,0xcc,0xb1}}, {{0xc3,0xa8}, {0x65,0xcc,0x80}}, {{0xc3,0xa9}, {0x65,0xcc,0x81}}, {{0xc3,0xaa}, {0x65,0xcc,0x82}}, {{0xe1,0xbb,0x81}, {0x65,0xcc,0x82,0xcc,0x80}}, {{0xe1,0xba,0xbf}, {0x65,0xcc,0x82,0xcc,0x81}}, {{0xe1,0xbb,0x85}, {0x65,0xcc,0x82,0xcc,0x83}}, {{0xe1,0xbb,0x83}, {0x65,0xcc,0x82,0xcc,0x89}}, {{0xe1,0xba,0xbd}, {0x65,0xcc,0x83}}, {{0xc4,0x93}, {0x65,0xcc,0x84}}, {{0xe1,0xb8,0x95}, {0x65,0xcc,0x84,0xcc,0x80}}, {{0xe1,0xb8,0x97}, {0x65,0xcc,0x84,0xcc,0x81}}, {{0xc4,0x95}, {0x65,0xcc,0x86}}, {{0xc4,0x97}, {0x65,0xcc,0x87}}, {{0xc3,0xab}, {0x65,0xcc,0x88}}, {{0xe1,0xba,0xbb}, {0x65,0xcc,0x89}}, {{0xc4,0x9b}, {0x65,0xcc,0x8c}}, {{0xc8,0x85}, {0x65,0xcc,0x8f}}, {{0xc8,0x87}, {0x65,0xcc,0x91}}, {{0xe1,0xba,0xb9}, {0x65,0xcc,0xa3}}, {{0xe1,0xbb,0x87}, {0x65,0xcc,0xa3,0xcc,0x82}}, {{0xe1,0xb8,0x9d}, {0x65,0xcc,0xa7,0xcc,0x86}}, {{0xc4,0x99}, {0x65,0xcc,0xa8}}, {{0xe1,0xb8,0x99}, {0x65,0xcc,0xad}}, {{0xe1,0xb8,0x9b}, {0x65,0xcc,0xb0}}, {{0xe1,0xb8,0x9f}, {0x66,0xcc,0x87}}, {{0xc7,0xb5}, {0x67,0xcc,0x81}}, {{0xc4,0x9d}, {0x67,0xcc,0x82}}, {{0xe1,0xb8,0xa1}, {0x67,0xcc,0x84}}, {{0xc4,0x9f}, {0x67,0xcc,0x86}}, {{0xc4,0xa1}, {0x67,0xcc,0x87}}, {{0xc7,0xa7}, {0x67,0xcc,0x8c}}, {{0xc4,0xa3}, {0x67,0xcc,0xa7}}, {{0xc4,0xa5}, {0x68,0xcc,0x82}}, {{0xe1,0xb8,0xa3}, {0x68,0xcc,0x87}}, {{0xe1,0xb8,0xa7}, {0x68,0xcc,0x88}}, {{0xe1,0xb8,0xa5}, {0x68,0xcc,0xa3}}, {{0xe1,0xb8,0xa9}, {0x68,0xcc,0xa7}}, {{0xe1,0xb8,0xab}, {0x68,0xcc,0xae}}, {{0xe1,0xba,0x96}, {0x68,0xcc,0xb1}}, {{0xc3,0xac}, {0x69,0xcc,0x80}}, {{0xc3,0xad}, {0x69,0xcc,0x81}}, {{0xc3,0xae}, {0x69,0xcc,0x82}}, {{0xc4,0xa9}, {0x69,0xcc,0x83}}, {{0xc4,0xab}, {0x69,0xcc,0x84}}, {{0xc4,0xad}, {0x69,0xcc,0x86}}, {{0xc3,0xaf}, {0x69,0xcc,0x88}}, {{0xe1,0xb8,0xaf}, {0x69,0xcc,0x88,0xcc,0x81}}, {{0xe1,0xbb,0x89}, {0x69,0xcc,0x89}}, {{0xc7,0x90}, {0x69,0xcc,0x8c}}, {{0xc8,0x89}, {0x69,0xcc,0x8f}}, {{0xc8,0x8b}, {0x69,0xcc,0x91}}, {{0xe1,0xbb,0x8b}, {0x69,0xcc,0xa3}}, {{0xc4,0xaf}, {0x69,0xcc,0xa8}}, {{0xe1,0xb8,0xad}, {0x69,0xcc,0xb0}}, {{0xc4,0xb5}, {0x6a,0xcc,0x82}}, {{0xc7,0xb0}, {0x6a,0xcc,0x8c}}, {{0xe1,0xb8,0xb1}, {0x6b,0xcc,0x81}}, {{0xc7,0xa9}, {0x6b,0xcc,0x8c}}, {{0xe1,0xb8,0xb3}, {0x6b,0xcc,0xa3}}, {{0xc4,0xb7}, {0x6b,0xcc,0xa7}}, {{0xe1,0xb8,0xb5}, {0x6b,0xcc,0xb1}}, {{0xc4,0xba}, {0x6c,0xcc,0x81}}, {{0xc4,0xbe}, {0x6c,0xcc,0x8c}}, {{0xe1,0xb8,0xb7}, {0x6c,0xcc,0xa3}}, {{0xe1,0xb8,0xb9}, {0x6c,0xcc,0xa3,0xcc,0x84}}, {{0xc4,0xbc}, {0x6c,0xcc,0xa7}}, {{0xe1,0xb8,0xbd}, {0x6c,0xcc,0xad}}, {{0xe1,0xb8,0xbb}, {0x6c,0xcc,0xb1}}, {{0xe1,0xb8,0xbf}, {0x6d,0xcc,0x81}}, {{0xe1,0xb9,0x81}, {0x6d,0xcc,0x87}}, {{0xe1,0xb9,0x83}, {0x6d,0xcc,0xa3}}, {{0xc5,0x84}, {0x6e,0xcc,0x81}}, {{0xc3,0xb1}, {0x6e,0xcc,0x83}}, {{0xe1,0xb9,0x85}, {0x6e,0xcc,0x87}}, {{0xc5,0x88}, {0x6e,0xcc,0x8c}}, {{0xe1,0xb9,0x87}, {0x6e,0xcc,0xa3}}, {{0xc5,0x86}, {0x6e,0xcc,0xa7}}, {{0xe1,0xb9,0x8b}, {0x6e,0xcc,0xad}}, {{0xe1,0xb9,0x89}, {0x6e,0xcc,0xb1}}, {{0xc3,0xb2}, {0x6f,0xcc,0x80}}, {{0xc3,0xb3}, {0x6f,0xcc,0x81}}, {{0xc3,0xb4}, {0x6f,0xcc,0x82}}, {{0xe1,0xbb,0x93}, {0x6f,0xcc,0x82,0xcc,0x80}}, {{0xe1,0xbb,0x91}, {0x6f,0xcc,0x82,0xcc,0x81}}, {{0xe1,0xbb,0x97}, {0x6f,0xcc,0x82,0xcc,0x83}}, {{0xe1,0xbb,0x95}, {0x6f,0xcc,0x82,0xcc,0x89}}, {{0xc3,0xb5}, {0x6f,0xcc,0x83}}, {{0xe1,0xb9,0x8d}, {0x6f,0xcc,0x83,0xcc,0x81}}, {{0xe1,0xb9,0x8f}, {0x6f,0xcc,0x83,0xcc,0x88}}, {{0xc5,0x8d}, {0x6f,0xcc,0x84}}, {{0xe1,0xb9,0x91}, {0x6f,0xcc,0x84,0xcc,0x80}}, {{0xe1,0xb9,0x93}, {0x6f,0xcc,0x84,0xcc,0x81}}, {{0xc5,0x8f}, {0x6f,0xcc,0x86}}, {{0xc3,0xb6}, {0x6f,0xcc,0x88}}, {{0xe1,0xbb,0x8f}, {0x6f,0xcc,0x89}}, {{0xc5,0x91}, {0x6f,0xcc,0x8b}}, {{0xc7,0x92}, {0x6f,0xcc,0x8c}}, {{0xc8,0x8d}, {0x6f,0xcc,0x8f}}, {{0xc8,0x8f}, {0x6f,0xcc,0x91}}, {{0xc6,0xa1}, {0x6f,0xcc,0x9b}}, {{0xe1,0xbb,0x9d}, {0x6f,0xcc,0x9b,0xcc,0x80}}, {{0xe1,0xbb,0x9b}, {0x6f,0xcc,0x9b,0xcc,0x81}}, {{0xe1,0xbb,0xa1}, {0x6f,0xcc,0x9b,0xcc,0x83}}, {{0xe1,0xbb,0x9f}, {0x6f,0xcc,0x9b,0xcc,0x89}}, {{0xe1,0xbb,0xa3}, {0x6f,0xcc,0x9b,0xcc,0xa3}}, {{0xe1,0xbb,0x8d}, {0x6f,0xcc,0xa3}}, {{0xe1,0xbb,0x99}, {0x6f,0xcc,0xa3,0xcc,0x82}}, {{0xc7,0xab}, {0x6f,0xcc,0xa8}}, {{0xc7,0xad}, {0x6f,0xcc,0xa8,0xcc,0x84}}, {{0xe1,0xb9,0x95}, {0x70,0xcc,0x81}}, {{0xe1,0xb9,0x97}, {0x70,0xcc,0x87}}, {{0xc5,0x95}, {0x72,0xcc,0x81}}, {{0xe1,0xb9,0x99}, {0x72,0xcc,0x87}}, {{0xc5,0x99}, {0x72,0xcc,0x8c}}, {{0xc8,0x91}, {0x72,0xcc,0x8f}}, {{0xc8,0x93}, {0x72,0xcc,0x91}}, {{0xe1,0xb9,0x9b}, {0x72,0xcc,0xa3}}, {{0xe1,0xb9,0x9d}, {0x72,0xcc,0xa3,0xcc,0x84}}, {{0xc5,0x97}, {0x72,0xcc,0xa7}}, {{0xe1,0xb9,0x9f}, {0x72,0xcc,0xb1}}, {{0xc5,0x9b}, {0x73,0xcc,0x81}}, {{0xe1,0xb9,0xa5}, {0x73,0xcc,0x81,0xcc,0x87}}, {{0xc5,0x9d}, {0x73,0xcc,0x82}}, {{0xe1,0xb9,0xa1}, {0x73,0xcc,0x87}}, {{0xc5,0xa1}, {0x73,0xcc,0x8c}}, {{0xe1,0xb9,0xa7}, {0x73,0xcc,0x8c,0xcc,0x87}}, {{0xe1,0xb9,0xa3}, {0x73,0xcc,0xa3}}, {{0xe1,0xb9,0xa9}, {0x73,0xcc,0xa3,0xcc,0x87}}, {{0xc5,0x9f}, {0x73,0xcc,0xa7}}, {{0xe1,0xb9,0xab}, {0x74,0xcc,0x87}}, {{0xe1,0xba,0x97}, {0x74,0xcc,0x88}}, {{0xc5,0xa5}, {0x74,0xcc,0x8c}}, {{0xe1,0xb9,0xad}, {0x74,0xcc,0xa3}}, {{0xc5,0xa3}, {0x74,0xcc,0xa7}}, {{0xe1,0xb9,0xb1}, {0x74,0xcc,0xad}}, {{0xe1,0xb9,0xaf}, {0x74,0xcc,0xb1}}, {{0xc3,0xb9}, {0x75,0xcc,0x80}}, {{0xc3,0xba}, {0x75,0xcc,0x81}}, {{0xc3,0xbb}, {0x75,0xcc,0x82}}, {{0xc5,0xa9}, {0x75,0xcc,0x83}}, {{0xe1,0xb9,0xb9}, {0x75,0xcc,0x83,0xcc,0x81}}, {{0xc5,0xab}, {0x75,0xcc,0x84}}, {{0xe1,0xb9,0xbb}, {0x75,0xcc,0x84,0xcc,0x88}}, {{0xc5,0xad}, {0x75,0xcc,0x86}}, {{0xc3,0xbc}, {0x75,0xcc,0x88}}, {{0xc7,0x9c}, {0x75,0xcc,0x88,0xcc,0x80}}, {{0xc7,0x98}, {0x75,0xcc,0x88,0xcc,0x81}}, {{0xc7,0x96}, {0x75,0xcc,0x88,0xcc,0x84}}, {{0xc7,0x9a}, {0x75,0xcc,0x88,0xcc,0x8c}}, {{0xe1,0xbb,0xa7}, {0x75,0xcc,0x89}}, {{0xc5,0xaf}, {0x75,0xcc,0x8a}}, {{0xc5,0xb1}, {0x75,0xcc,0x8b}}, {{0xc7,0x94}, {0x75,0xcc,0x8c}}, {{0xc8,0x95}, {0x75,0xcc,0x8f}}, {{0xc8,0x97}, {0x75,0xcc,0x91}}, {{0xc6,0xb0}, {0x75,0xcc,0x9b}}, {{0xe1,0xbb,0xab}, {0x75,0xcc,0x9b,0xcc,0x80}}, {{0xe1,0xbb,0xa9}, {0x75,0xcc,0x9b,0xcc,0x81}}, {{0xe1,0xbb,0xaf}, {0x75,0xcc,0x9b,0xcc,0x83}}, {{0xe1,0xbb,0xad}, {0x75,0xcc,0x9b,0xcc,0x89}}, {{0xe1,0xbb,0xb1}, {0x75,0xcc,0x9b,0xcc,0xa3}}, {{0xe1,0xbb,0xa5}, {0x75,0xcc,0xa3}}, {{0xe1,0xb9,0xb3}, {0x75,0xcc,0xa4}}, {{0xc5,0xb3}, {0x75,0xcc,0xa8}}, {{0xe1,0xb9,0xb7}, {0x75,0xcc,0xad}}, {{0xe1,0xb9,0xb5}, {0x75,0xcc,0xb0}}, {{0xe1,0xb9,0xbd}, {0x76,0xcc,0x83}}, {{0xe1,0xb9,0xbf}, {0x76,0xcc,0xa3}}, {{0xe1,0xba,0x81}, {0x77,0xcc,0x80}}, {{0xe1,0xba,0x83}, {0x77,0xcc,0x81}}, {{0xc5,0xb5}, {0x77,0xcc,0x82}}, {{0xe1,0xba,0x87}, {0x77,0xcc,0x87}}, {{0xe1,0xba,0x85}, {0x77,0xcc,0x88}}, {{0xe1,0xba,0x98}, {0x77,0xcc,0x8a}}, {{0xe1,0xba,0x89}, {0x77,0xcc,0xa3}}, {{0xe1,0xba,0x8b}, {0x78,0xcc,0x87}}, {{0xe1,0xba,0x8d}, {0x78,0xcc,0x88}}, {{0xe1,0xbb,0xb3}, {0x79,0xcc,0x80}}, {{0xc3,0xbd}, {0x79,0xcc,0x81}}, {{0xc5,0xb7}, {0x79,0xcc,0x82}}, {{0xe1,0xbb,0xb9}, {0x79,0xcc,0x83}}, {{0xe1,0xba,0x8f}, {0x79,0xcc,0x87}}, {{0xc3,0xbf}, {0x79,0xcc,0x88}}, {{0xe1,0xbb,0xb7}, {0x79,0xcc,0x89}}, {{0xe1,0xba,0x99}, {0x79,0xcc,0x8a}}, {{0xe1,0xbb,0xb5}, {0x79,0xcc,0xa3}}, {{0xc5,0xba}, {0x7a,0xcc,0x81}}, {{0xe1,0xba,0x91}, {0x7a,0xcc,0x82}}, {{0xc5,0xbc}, {0x7a,0xcc,0x87}}, {{0xc5,0xbe}, {0x7a,0xcc,0x8c}}, {{0xe1,0xba,0x93}, {0x7a,0xcc,0xa3}}, {{0xe1,0xba,0x95}, {0x7a,0xcc,0xb1}}, {{0xe1,0xbf,0xad}, {0xc2,0xa8,0xcc,0x80}}, {{0xe1,0xbf,0xae}, {0xc2,0xa8,0xcc,0x81}}, {{0xce,0x85}, {0xc2,0xa8,0xcc,0x8d}}, {{0xe1,0xbf,0x81}, {0xc2,0xa8,0xcd,0x82}}, {{0xe1,0xbf,0xbd}, {0xc2,0xb4}}, {{0xce,0x87}, {0xc2,0xb7}}, {{0xd3,0x94}, {0xc3,0x86}}, {{0xc7,0xbc}, {0xc3,0x86,0xcc,0x81}}, {{0xc7,0xa2}, {0xc3,0x86,0xcc,0x84}}, {{0xc7,0xbe}, {0xc3,0x98,0xcc,0x81}}, {{0xd3,0x95}, {0xc3,0xa6}}, {{0xc7,0xbd}, {0xc3,0xa6,0xcc,0x81}}, {{0xc7,0xa3}, {0xc3,0xa6,0xcc,0x84}}, {{0xc7,0xbf}, {0xc3,0xb8,0xcc,0x81}}, {{0xe1,0xba,0x9b}, {0xc5,0xbf,0xcc,0x87}}, {{0xd3,0x98}, {0xc6,0x8f}}, {{0xd3,0x9a}, {0xc6,0x8f,0xcc,0x88}}, {{0xd3,0xa8}, {0xc6,0x9f}}, {{0xd3,0xaa}, {0xc6,0x9f,0xcc,0x88}}, {{0xd3,0xa0}, {0xc6,0xb7}}, {{0xc7,0xae}, {0xc6,0xb7,0xcc,0x8c}}, {{0xd3,0x99}, {0xc9,0x99}}, {{0xd3,0x9b}, {0xc9,0x99,0xcc,0x88}}, {{0xd3,0xa9}, {0xc9,0xb5}}, {{0xd3,0xab}, {0xc9,0xb5,0xcc,0x88}}, {{0xd3,0xa1}, {0xca,0x92}}, {{0xc7,0xaf}, {0xca,0x92,0xcc,0x8c}}, {{0xcd,0xb4}, {0xca,0xb9}}, {{0xcd,0x80}, {0xcc,0x80}}, {{0xcd,0x81}, {0xcc,0x81}}, {{0xcc,0x90}, {0xcc,0x86,0xcc,0x87}}, {{0xcd,0x84}, {0xcc,0x88,0xcc,0x8d}}, {{0xcd,0x83}, {0xcc,0x93}}, {{0xe1,0xbe,0xba}, {0xce,0x91,0xcc,0x80}}, {{0xe1,0xbe,0xbb}, {0xce,0x91,0xcc,0x81}}, {{0xe1,0xbe,0xb9}, {0xce,0x91,0xcc,0x84}}, {{0xe1,0xbe,0xb8}, {0xce,0x91,0xcc,0x86}}, {{0xce,0x86}, {0xce,0x91,0xcc,0x8d}}, {{0xe1,0xbc,0x88}, {0xce,0x91,0xcc,0x93}}, {{0xe1,0xbc,0x8a}, {0xce,0x91,0xcc,0x93,0xcc,0x80}}, {{0xe1,0xbc,0x8c}, {0xce,0x91,0xcc,0x93,0xcc,0x81}}, {{0xe1,0xbc,0x8e}, {0xce,0x91,0xcc,0x93,0xcd,0x82}}, {{0xe1,0xbc,0x89}, {0xce,0x91,0xcc,0x94}}, {{0xe1,0xbc,0x8b}, {0xce,0x91,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbc,0x8d}, {0xce,0x91,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbc,0x8f}, {0xce,0x91,0xcc,0x94,0xcd,0x82}}, {{0xe1,0xbe,0xbc}, {0xce,0x91,0xcd,0x85}}, {{0xe1,0xbe,0x88}, {0xce,0x91,0xcd,0x85,0xcc,0x93}}, {{0xe1,0xbe,0x8a}, {0xce,0x91,0xcd,0x85,0xcc,0x93,0xcc,0x80}}, {{0xe1,0xbe,0x8c}, {0xce,0x91,0xcd,0x85,0xcc,0x93,0xcc,0x81}}, {{0xe1,0xbe,0x8e}, {0xce,0x91,0xcd,0x85,0xcc,0x93,0xcd,0x82}}, {{0xe1,0xbe,0x89}, {0xce,0x91,0xcd,0x85,0xcc,0x94}}, {{0xe1,0xbe,0x8b}, {0xce,0x91,0xcd,0x85,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbe,0x8d}, {0xce,0x91,0xcd,0x85,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbe,0x8f}, {0xce,0x91,0xcd,0x85,0xcc,0x94,0xcd,0x82}}, {{0xe1,0xbf,0x88}, {0xce,0x95,0xcc,0x80}}, {{0xe1,0xbf,0x89}, {0xce,0x95,0xcc,0x81}}, {{0xce,0x88}, {0xce,0x95,0xcc,0x8d}}, {{0xe1,0xbc,0x98}, {0xce,0x95,0xcc,0x93}}, {{0xe1,0xbc,0x9a}, {0xce,0x95,0xcc,0x93,0xcc,0x80}}, {{0xe1,0xbc,0x9c}, {0xce,0x95,0xcc,0x93,0xcc,0x81}}, {{0xe1,0xbc,0x99}, {0xce,0x95,0xcc,0x94}}, {{0xe1,0xbc,0x9b}, {0xce,0x95,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbc,0x9d}, {0xce,0x95,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbf,0x8a}, {0xce,0x97,0xcc,0x80}}, {{0xe1,0xbf,0x8b}, {0xce,0x97,0xcc,0x81}}, {{0xce,0x89}, {0xce,0x97,0xcc,0x8d}}, {{0xe1,0xbc,0xa8}, {0xce,0x97,0xcc,0x93}}, {{0xe1,0xbc,0xaa}, {0xce,0x97,0xcc,0x93,0xcc,0x80}}, {{0xe1,0xbc,0xac}, {0xce,0x97,0xcc,0x93,0xcc,0x81}}, {{0xe1,0xbc,0xae}, {0xce,0x97,0xcc,0x93,0xcd,0x82}}, {{0xe1,0xbc,0xa9}, {0xce,0x97,0xcc,0x94}}, {{0xe1,0xbc,0xab}, {0xce,0x97,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbc,0xad}, {0xce,0x97,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbc,0xaf}, {0xce,0x97,0xcc,0x94,0xcd,0x82}}, {{0xe1,0xbf,0x8c}, {0xce,0x97,0xcd,0x85}}, {{0xe1,0xbe,0x98}, {0xce,0x97,0xcd,0x85,0xcc,0x93}}, {{0xe1,0xbe,0x9a}, {0xce,0x97,0xcd,0x85,0xcc,0x93,0xcc,0x80}}, {{0xe1,0xbe,0x9c}, {0xce,0x97,0xcd,0x85,0xcc,0x93,0xcc,0x81}}, {{0xe1,0xbe,0x9e}, {0xce,0x97,0xcd,0x85,0xcc,0x93,0xcd,0x82}}, {{0xe1,0xbe,0x99}, {0xce,0x97,0xcd,0x85,0xcc,0x94}}, {{0xe1,0xbe,0x9b}, {0xce,0x97,0xcd,0x85,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbe,0x9d}, {0xce,0x97,0xcd,0x85,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbe,0x9f}, {0xce,0x97,0xcd,0x85,0xcc,0x94,0xcd,0x82}}, {{0xe1,0xbf,0x9a}, {0xce,0x99,0xcc,0x80}}, {{0xe1,0xbf,0x9b}, {0xce,0x99,0xcc,0x81}}, {{0xe1,0xbf,0x99}, {0xce,0x99,0xcc,0x84}}, {{0xe1,0xbf,0x98}, {0xce,0x99,0xcc,0x86}}, {{0xce,0xaa}, {0xce,0x99,0xcc,0x88}}, {{0xce,0x8a}, {0xce,0x99,0xcc,0x8d}}, {{0xe1,0xbc,0xb8}, {0xce,0x99,0xcc,0x93}}, {{0xe1,0xbc,0xba}, {0xce,0x99,0xcc,0x93,0xcc,0x80}}, {{0xe1,0xbc,0xbc}, {0xce,0x99,0xcc,0x93,0xcc,0x81}}, {{0xe1,0xbc,0xbe}, {0xce,0x99,0xcc,0x93,0xcd,0x82}}, {{0xe1,0xbc,0xb9}, {0xce,0x99,0xcc,0x94}}, {{0xe1,0xbc,0xbb}, {0xce,0x99,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbc,0xbd}, {0xce,0x99,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbc,0xbf}, {0xce,0x99,0xcc,0x94,0xcd,0x82}}, {{0xe1,0xbf,0xb8}, {0xce,0x9f,0xcc,0x80}}, {{0xe1,0xbf,0xb9}, {0xce,0x9f,0xcc,0x81}}, {{0xce,0x8c}, {0xce,0x9f,0xcc,0x8d}}, {{0xe1,0xbd,0x88}, {0xce,0x9f,0xcc,0x93}}, {{0xe1,0xbd,0x8a}, {0xce,0x9f,0xcc,0x93,0xcc,0x80}}, {{0xe1,0xbd,0x8c}, {0xce,0x9f,0xcc,0x93,0xcc,0x81}}, {{0xe1,0xbd,0x89}, {0xce,0x9f,0xcc,0x94}}, {{0xe1,0xbd,0x8b}, {0xce,0x9f,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbd,0x8d}, {0xce,0x9f,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbf,0xac}, {0xce,0xa1,0xcc,0x94}}, {{0xe1,0xbf,0xaa}, {0xce,0xa5,0xcc,0x80}}, {{0xe1,0xbf,0xab}, {0xce,0xa5,0xcc,0x81}}, {{0xe1,0xbf,0xa9}, {0xce,0xa5,0xcc,0x84}}, {{0xe1,0xbf,0xa8}, {0xce,0xa5,0xcc,0x86}}, {{0xce,0xab}, {0xce,0xa5,0xcc,0x88}}, {{0xce,0x8e}, {0xce,0xa5,0xcc,0x8d}}, {{0xe1,0xbd,0x99}, {0xce,0xa5,0xcc,0x94}}, {{0xe1,0xbd,0x9b}, {0xce,0xa5,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbd,0x9d}, {0xce,0xa5,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbd,0x9f}, {0xce,0xa5,0xcc,0x94,0xcd,0x82}}, {{0xe1,0xbf,0xba}, {0xce,0xa9,0xcc,0x80}}, {{0xe1,0xbf,0xbb}, {0xce,0xa9,0xcc,0x81}}, {{0xce,0x8f}, {0xce,0xa9,0xcc,0x8d}}, {{0xe1,0xbd,0xa8}, {0xce,0xa9,0xcc,0x93}}, {{0xe1,0xbd,0xaa}, {0xce,0xa9,0xcc,0x93,0xcc,0x80}}, {{0xe1,0xbd,0xac}, {0xce,0xa9,0xcc,0x93,0xcc,0x81}}, {{0xe1,0xbd,0xae}, {0xce,0xa9,0xcc,0x93,0xcd,0x82}}, {{0xe1,0xbd,0xa9}, {0xce,0xa9,0xcc,0x94}}, {{0xe1,0xbd,0xab}, {0xce,0xa9,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbd,0xad}, {0xce,0xa9,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbd,0xaf}, {0xce,0xa9,0xcc,0x94,0xcd,0x82}}, {{0xe1,0xbf,0xbc}, {0xce,0xa9,0xcd,0x85}}, {{0xe1,0xbe,0xa8}, {0xce,0xa9,0xcd,0x85,0xcc,0x93}}, {{0xe1,0xbe,0xaa}, {0xce,0xa9,0xcd,0x85,0xcc,0x93,0xcc,0x80}}, {{0xe1,0xbe,0xac}, {0xce,0xa9,0xcd,0x85,0xcc,0x93,0xcc,0x81}}, {{0xe1,0xbe,0xae}, {0xce,0xa9,0xcd,0x85,0xcc,0x93,0xcd,0x82}}, {{0xe1,0xbe,0xa9}, {0xce,0xa9,0xcd,0x85,0xcc,0x94}}, {{0xe1,0xbe,0xab}, {0xce,0xa9,0xcd,0x85,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbe,0xad}, {0xce,0xa9,0xcd,0x85,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbe,0xaf}, {0xce,0xa9,0xcd,0x85,0xcc,0x94,0xcd,0x82}}, {{0xe1,0xbd,0xb0}, {0xce,0xb1,0xcc,0x80}}, {{0xe1,0xbd,0xb1}, {0xce,0xb1,0xcc,0x81}}, {{0xe1,0xbe,0xb1}, {0xce,0xb1,0xcc,0x84}}, {{0xe1,0xbe,0xb0}, {0xce,0xb1,0xcc,0x86}}, {{0xce,0xac}, {0xce,0xb1,0xcc,0x8d}}, {{0xe1,0xbc,0x80}, {0xce,0xb1,0xcc,0x93}}, {{0xe1,0xbc,0x82}, {0xce,0xb1,0xcc,0x93,0xcc,0x80}}, {{0xe1,0xbc,0x84}, {0xce,0xb1,0xcc,0x93,0xcc,0x81}}, {{0xe1,0xbc,0x86}, {0xce,0xb1,0xcc,0x93,0xcd,0x82}}, {{0xe1,0xbc,0x81}, {0xce,0xb1,0xcc,0x94}}, {{0xe1,0xbc,0x83}, {0xce,0xb1,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbc,0x85}, {0xce,0xb1,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbc,0x87}, {0xce,0xb1,0xcc,0x94,0xcd,0x82}}, {{0xe1,0xbe,0xb6}, {0xce,0xb1,0xcd,0x82}}, {{0xe1,0xbe,0xb3}, {0xce,0xb1,0xcd,0x85}}, {{0xe1,0xbe,0xb2}, {0xce,0xb1,0xcd,0x85,0xcc,0x80}}, {{0xe1,0xbe,0xb4}, {0xce,0xb1,0xcd,0x85,0xcc,0x81}}, {{0xe1,0xbe,0x80}, {0xce,0xb1,0xcd,0x85,0xcc,0x93}}, {{0xe1,0xbe,0x82}, {0xce,0xb1,0xcd,0x85,0xcc,0x93,0xcc,0x80}}, {{0xe1,0xbe,0x84}, {0xce,0xb1,0xcd,0x85,0xcc,0x93,0xcc,0x81}}, {{0xe1,0xbe,0x86}, {0xce,0xb1,0xcd,0x85,0xcc,0x93,0xcd,0x82}}, {{0xe1,0xbe,0x81}, {0xce,0xb1,0xcd,0x85,0xcc,0x94}}, {{0xe1,0xbe,0x83}, {0xce,0xb1,0xcd,0x85,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbe,0x85}, {0xce,0xb1,0xcd,0x85,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbe,0x87}, {0xce,0xb1,0xcd,0x85,0xcc,0x94,0xcd,0x82}}, {{0xe1,0xbe,0xb7}, {0xce,0xb1,0xcd,0x85,0xcd,0x82}}, {{0xe1,0xbd,0xb2}, {0xce,0xb5,0xcc,0x80}}, {{0xe1,0xbd,0xb3}, {0xce,0xb5,0xcc,0x81}}, {{0xce,0xad}, {0xce,0xb5,0xcc,0x8d}}, {{0xe1,0xbc,0x90}, {0xce,0xb5,0xcc,0x93}}, {{0xe1,0xbc,0x92}, {0xce,0xb5,0xcc,0x93,0xcc,0x80}}, {{0xe1,0xbc,0x94}, {0xce,0xb5,0xcc,0x93,0xcc,0x81}}, {{0xe1,0xbc,0x91}, {0xce,0xb5,0xcc,0x94}}, {{0xe1,0xbc,0x93}, {0xce,0xb5,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbc,0x95}, {0xce,0xb5,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbd,0xb4}, {0xce,0xb7,0xcc,0x80}}, {{0xe1,0xbd,0xb5}, {0xce,0xb7,0xcc,0x81}}, {{0xce,0xae}, {0xce,0xb7,0xcc,0x8d}}, {{0xe1,0xbc,0xa0}, {0xce,0xb7,0xcc,0x93}}, {{0xe1,0xbc,0xa2}, {0xce,0xb7,0xcc,0x93,0xcc,0x80}}, {{0xe1,0xbc,0xa4}, {0xce,0xb7,0xcc,0x93,0xcc,0x81}}, {{0xe1,0xbc,0xa6}, {0xce,0xb7,0xcc,0x93,0xcd,0x82}}, {{0xe1,0xbc,0xa1}, {0xce,0xb7,0xcc,0x94}}, {{0xe1,0xbc,0xa3}, {0xce,0xb7,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbc,0xa5}, {0xce,0xb7,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbc,0xa7}, {0xce,0xb7,0xcc,0x94,0xcd,0x82}}, {{0xe1,0xbf,0x86}, {0xce,0xb7,0xcd,0x82}}, {{0xe1,0xbf,0x83}, {0xce,0xb7,0xcd,0x85}}, {{0xe1,0xbf,0x82}, {0xce,0xb7,0xcd,0x85,0xcc,0x80}}, {{0xe1,0xbf,0x84}, {0xce,0xb7,0xcd,0x85,0xcc,0x81}}, {{0xe1,0xbe,0x90}, {0xce,0xb7,0xcd,0x85,0xcc,0x93}}, {{0xe1,0xbe,0x92}, {0xce,0xb7,0xcd,0x85,0xcc,0x93,0xcc,0x80}}, {{0xe1,0xbe,0x94}, {0xce,0xb7,0xcd,0x85,0xcc,0x93,0xcc,0x81}}, {{0xe1,0xbe,0x96}, {0xce,0xb7,0xcd,0x85,0xcc,0x93,0xcd,0x82}}, {{0xe1,0xbe,0x91}, {0xce,0xb7,0xcd,0x85,0xcc,0x94}}, {{0xe1,0xbe,0x93}, {0xce,0xb7,0xcd,0x85,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbe,0x95}, {0xce,0xb7,0xcd,0x85,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbe,0x97}, {0xce,0xb7,0xcd,0x85,0xcc,0x94,0xcd,0x82}}, {{0xe1,0xbf,0x87}, {0xce,0xb7,0xcd,0x85,0xcd,0x82}}, {{0xe1,0xbe,0xbe}, {0xce,0xb9}}, {{0xe1,0xbd,0xb6}, {0xce,0xb9,0xcc,0x80}}, {{0xe1,0xbd,0xb7}, {0xce,0xb9,0xcc,0x81}}, {{0xe1,0xbf,0x91}, {0xce,0xb9,0xcc,0x84}}, {{0xe1,0xbf,0x90}, {0xce,0xb9,0xcc,0x86}}, {{0xcf,0x8a}, {0xce,0xb9,0xcc,0x88}}, {{0xe1,0xbf,0x92}, {0xce,0xb9,0xcc,0x88,0xcc,0x80}}, {{0xe1,0xbf,0x93}, {0xce,0xb9,0xcc,0x88,0xcc,0x81}}, {{0xce,0x90}, {0xce,0xb9,0xcc,0x88,0xcc,0x8d}}, {{0xe1,0xbf,0x97}, {0xce,0xb9,0xcc,0x88,0xcd,0x82}}, {{0xce,0xaf}, {0xce,0xb9,0xcc,0x8d}}, {{0xe1,0xbc,0xb0}, {0xce,0xb9,0xcc,0x93}}, {{0xe1,0xbc,0xb2}, {0xce,0xb9,0xcc,0x93,0xcc,0x80}}, {{0xe1,0xbc,0xb4}, {0xce,0xb9,0xcc,0x93,0xcc,0x81}}, {{0xe1,0xbc,0xb6}, {0xce,0xb9,0xcc,0x93,0xcd,0x82}}, {{0xe1,0xbc,0xb1}, {0xce,0xb9,0xcc,0x94}}, {{0xe1,0xbc,0xb3}, {0xce,0xb9,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbc,0xb5}, {0xce,0xb9,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbc,0xb7}, {0xce,0xb9,0xcc,0x94,0xcd,0x82}}, {{0xe1,0xbf,0x96}, {0xce,0xb9,0xcd,0x82}}, {{0xe1,0xbd,0xb8}, {0xce,0xbf,0xcc,0x80}}, {{0xe1,0xbd,0xb9}, {0xce,0xbf,0xcc,0x81}}, {{0xcf,0x8c}, {0xce,0xbf,0xcc,0x8d}}, {{0xe1,0xbd,0x80}, {0xce,0xbf,0xcc,0x93}}, {{0xe1,0xbd,0x82}, {0xce,0xbf,0xcc,0x93,0xcc,0x80}}, {{0xe1,0xbd,0x84}, {0xce,0xbf,0xcc,0x93,0xcc,0x81}}, {{0xe1,0xbd,0x81}, {0xce,0xbf,0xcc,0x94}}, {{0xe1,0xbd,0x83}, {0xce,0xbf,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbd,0x85}, {0xce,0xbf,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbf,0xb4}, {0xce,0xbf,0xcd,0x85,0xcc,0x81}}, {{0xe1,0xbf,0xa4}, {0xcf,0x81,0xcc,0x93}}, {{0xe1,0xbf,0xa5}, {0xcf,0x81,0xcc,0x94}}, {{0xe1,0xbd,0xba}, {0xcf,0x85,0xcc,0x80}}, {{0xe1,0xbd,0xbb}, {0xcf,0x85,0xcc,0x81}}, {{0xe1,0xbf,0xa1}, {0xcf,0x85,0xcc,0x84}}, {{0xe1,0xbf,0xa0}, {0xcf,0x85,0xcc,0x86}}, {{0xcf,0x8b}, {0xcf,0x85,0xcc,0x88}}, {{0xe1,0xbf,0xa2}, {0xcf,0x85,0xcc,0x88,0xcc,0x80}}, {{0xe1,0xbf,0xa3}, {0xcf,0x85,0xcc,0x88,0xcc,0x81}}, {{0xce,0xb0}, {0xcf,0x85,0xcc,0x88,0xcc,0x8d}}, {{0xe1,0xbf,0xa7}, {0xcf,0x85,0xcc,0x88,0xcd,0x82}}, {{0xcf,0x8d}, {0xcf,0x85,0xcc,0x8d}}, {{0xe1,0xbd,0x90}, {0xcf,0x85,0xcc,0x93}}, {{0xe1,0xbd,0x92}, {0xcf,0x85,0xcc,0x93,0xcc,0x80}}, {{0xe1,0xbd,0x94}, {0xcf,0x85,0xcc,0x93,0xcc,0x81}}, {{0xe1,0xbd,0x96}, {0xcf,0x85,0xcc,0x93,0xcd,0x82}}, {{0xe1,0xbd,0x91}, {0xcf,0x85,0xcc,0x94}}, {{0xe1,0xbd,0x93}, {0xcf,0x85,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbd,0x95}, {0xcf,0x85,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbd,0x97}, {0xcf,0x85,0xcc,0x94,0xcd,0x82}}, {{0xe1,0xbf,0xa6}, {0xcf,0x85,0xcd,0x82}}, {{0xe1,0xbd,0xbc}, {0xcf,0x89,0xcc,0x80}}, {{0xe1,0xbd,0xbd}, {0xcf,0x89,0xcc,0x81}}, {{0xcf,0x8e}, {0xcf,0x89,0xcc,0x8d}}, {{0xe1,0xbd,0xa0}, {0xcf,0x89,0xcc,0x93}}, {{0xe1,0xbd,0xa2}, {0xcf,0x89,0xcc,0x93,0xcc,0x80}}, {{0xe1,0xbd,0xa4}, {0xcf,0x89,0xcc,0x93,0xcc,0x81}}, {{0xe1,0xbd,0xa6}, {0xcf,0x89,0xcc,0x93,0xcd,0x82}}, {{0xe1,0xbd,0xa1}, {0xcf,0x89,0xcc,0x94}}, {{0xe1,0xbd,0xa3}, {0xcf,0x89,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbd,0xa5}, {0xcf,0x89,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbd,0xa7}, {0xcf,0x89,0xcc,0x94,0xcd,0x82}}, {{0xe1,0xbf,0xb6}, {0xcf,0x89,0xcd,0x82}}, {{0xe1,0xbf,0xb3}, {0xcf,0x89,0xcd,0x85}}, {{0xe1,0xbf,0xb2}, {0xcf,0x89,0xcd,0x85,0xcc,0x80}}, {{0xe1,0xbe,0xa0}, {0xcf,0x89,0xcd,0x85,0xcc,0x93}}, {{0xe1,0xbe,0xa2}, {0xcf,0x89,0xcd,0x85,0xcc,0x93,0xcc,0x80}}, {{0xe1,0xbe,0xa4}, {0xcf,0x89,0xcd,0x85,0xcc,0x93,0xcc,0x81}}, {{0xe1,0xbe,0xa6}, {0xcf,0x89,0xcd,0x85,0xcc,0x93,0xcd,0x82}}, {{0xe1,0xbe,0xa1}, {0xcf,0x89,0xcd,0x85,0xcc,0x94}}, {{0xe1,0xbe,0xa3}, {0xcf,0x89,0xcd,0x85,0xcc,0x94,0xcc,0x80}}, {{0xe1,0xbe,0xa5}, {0xcf,0x89,0xcd,0x85,0xcc,0x94,0xcc,0x81}}, {{0xe1,0xbe,0xa7}, {0xcf,0x89,0xcd,0x85,0xcc,0x94,0xcd,0x82}}, {{0xe1,0xbf,0xb7}, {0xcf,0x89,0xcd,0x85,0xcd,0x82}}, {{0xcf,0x94}, {0xcf,0x92,0xcc,0x88}}, {{0xcf,0x93}, {0xcf,0x92,0xcc,0x8d}}, {{0xd0,0x87}, {0xd0,0x86,0xcc,0x88}}, {{0xd3,0x90}, {0xd0,0x90,0xcc,0x86}}, {{0xd3,0x92}, {0xd0,0x90,0xcc,0x88}}, {{0xd0,0x83}, {0xd0,0x93,0xcc,0x81}}, {{0xd3,0x96}, {0xd0,0x95,0xcc,0x86}}, {{0xd0,0x81}, {0xd0,0x95,0xcc,0x88}}, {{0xd3,0x81}, {0xd0,0x96,0xcc,0x86}}, {{0xd3,0x9c}, {0xd0,0x96,0xcc,0x88}}, {{0xd3,0x9e}, {0xd0,0x97,0xcc,0x88}}, {{0xd3,0xa2}, {0xd0,0x98,0xcc,0x84}}, {{0xd0,0x99}, {0xd0,0x98,0xcc,0x86}}, {{0xd3,0xa4}, {0xd0,0x98,0xcc,0x88}}, {{0xd0,0x8c}, {0xd0,0x9a,0xcc,0x81}}, {{0xd3,0xa6}, {0xd0,0x9e,0xcc,0x88}}, {{0xd3,0xae}, {0xd0,0xa3,0xcc,0x84}}, {{0xd0,0x8e}, {0xd0,0xa3,0xcc,0x86}}, {{0xd3,0xb0}, {0xd0,0xa3,0xcc,0x88}}, {{0xd3,0xb2}, {0xd0,0xa3,0xcc,0x8b}}, {{0xd3,0xb4}, {0xd0,0xa7,0xcc,0x88}}, {{0xd3,0xb8}, {0xd0,0xab,0xcc,0x88}}, {{0xd3,0x91}, {0xd0,0xb0,0xcc,0x86}}, {{0xd3,0x93}, {0xd0,0xb0,0xcc,0x88}}, {{0xd1,0x93}, {0xd0,0xb3,0xcc,0x81}}, {{0xd3,0x97}, {0xd0,0xb5,0xcc,0x86}}, {{0xd1,0x91}, {0xd0,0xb5,0xcc,0x88}}, {{0xd3,0x82}, {0xd0,0xb6,0xcc,0x86}}, {{0xd3,0x9d}, {0xd0,0xb6,0xcc,0x88}}, {{0xd3,0x9f}, {0xd0,0xb7,0xcc,0x88}}, {{0xd3,0xa3}, {0xd0,0xb8,0xcc,0x84}}, {{0xd0,0xb9}, {0xd0,0xb8,0xcc,0x86}}, {{0xd3,0xa5}, {0xd0,0xb8,0xcc,0x88}}, {{0xd1,0x9c}, {0xd0,0xba,0xcc,0x81}}, {{0xd3,0xa7}, {0xd0,0xbe,0xcc,0x88}}, {{0xd3,0xaf}, {0xd1,0x83,0xcc,0x84}}, {{0xd1,0x9e}, {0xd1,0x83,0xcc,0x86}}, {{0xd3,0xb1}, {0xd1,0x83,0xcc,0x88}}, {{0xd3,0xb3}, {0xd1,0x83,0xcc,0x8b}}, {{0xd3,0xb5}, {0xd1,0x87,0xcc,0x88}}, {{0xd3,0xb9}, {0xd1,0x8b,0xcc,0x88}}, {{0xd1,0x97}, {0xd1,0x96,0xcc,0x88}}, {{0xd1,0xb6}, {0xd1,0xb4,0xcc,0x8f}}, {{0xd1,0xb7}, {0xd1,0xb5,0xcc,0x8f}}, {{0xef,0xac,0xae}, {0xd7,0x90,0xd6,0xb7}}, {{0xef,0xac,0xaf}, {0xd7,0x90,0xd6,0xb8}}, {{0xef,0xac,0xb0}, {0xd7,0x90,0xd6,0xbc}}, {{0xef,0xac,0xb1}, {0xd7,0x91,0xd6,0xbc}}, {{0xef,0xad,0x8c}, {0xd7,0x91,0xd6,0xbf}}, {{0xef,0xac,0xb2}, {0xd7,0x92,0xd6,0xbc}}, {{0xef,0xac,0xb3}, {0xd7,0x93,0xd6,0xbc}}, {{0xef,0xac,0xb4}, {0xd7,0x94,0xd6,0xbc}}, {{0xef,0xad,0x8b}, {0xd7,0x95,0xd6,0xb9}}, {{0xef,0xac,0xb5}, {0xd7,0x95,0xd6,0xbc}}, {{0xef,0xac,0xb6}, {0xd7,0x96,0xd6,0xbc}}, {{0xef,0xac,0xb8}, {0xd7,0x98,0xd6,0xbc}}, {{0xef,0xac,0xb9}, {0xd7,0x99,0xd6,0xbc}}, {{0xef,0xac,0xba}, {0xd7,0x9a,0xd6,0xbc}}, {{0xef,0xac,0xbb}, {0xd7,0x9b,0xd6,0xbc}}, {{0xef,0xad,0x8d}, {0xd7,0x9b,0xd6,0xbf}}, {{0xef,0xac,0xbc}, {0xd7,0x9c,0xd6,0xbc}}, {{0xef,0xac,0xbe}, {0xd7,0x9e,0xd6,0xbc}}, {{0xef,0xad,0x80}, {0xd7,0xa0,0xd6,0xbc}}, {{0xef,0xad,0x81}, {0xd7,0xa1,0xd6,0xbc}}, {{0xef,0xad,0x83}, {0xd7,0xa3,0xd6,0xbc}}, {{0xef,0xad,0x84}, {0xd7,0xa4,0xd6,0xbc}}, {{0xef,0xad,0x8e}, {0xd7,0xa4,0xd6,0xbf}}, {{0xef,0xad,0x86}, {0xd7,0xa6,0xd6,0xbc}}, {{0xef,0xad,0x87}, {0xd7,0xa7,0xd6,0xbc}}, {{0xef,0xad,0x88}, {0xd7,0xa8,0xd6,0xbc}}, {{0xef,0xad,0x89}, {0xd7,0xa9,0xd6,0xbc}}, {{0xef,0xac,0xac}, {0xd7,0xa9,0xd6,0xbc,0xd7,0x81}}, {{0xef,0xac,0xad}, {0xd7,0xa9,0xd6,0xbc,0xd7,0x82}}, {{0xef,0xac,0xaa}, {0xd7,0xa9,0xd7,0x81}}, {{0xef,0xac,0xab}, {0xd7,0xa9,0xd7,0x82}}, {{0xef,0xad,0x8a}, {0xd7,0xaa,0xd6,0xbc}}, {{0xef,0xac,0x9f}, {0xd7,0xb2,0xd6,0xb7}}, {{0xe0,0xa5,0x98}, {0xe0,0xa4,0x95,0xe0,0xa4,0xbc}}, {{0xe0,0xa5,0x99}, {0xe0,0xa4,0x96,0xe0,0xa4,0xbc}}, {{0xe0,0xa5,0x9a}, {0xe0,0xa4,0x97,0xe0,0xa4,0xbc}}, {{0xe0,0xa5,0x9b}, {0xe0,0xa4,0x9c,0xe0,0xa4,0xbc}}, {{0xe0,0xa5,0x9c}, {0xe0,0xa4,0xa1,0xe0,0xa4,0xbc}}, {{0xe0,0xa5,0x9d}, {0xe0,0xa4,0xa2,0xe0,0xa4,0xbc}}, {{0xe0,0xa4,0xa9}, {0xe0,0xa4,0xa8,0xe0,0xa4,0xbc}}, {{0xe0,0xa5,0x9e}, {0xe0,0xa4,0xab,0xe0,0xa4,0xbc}}, {{0xe0,0xa5,0x9f}, {0xe0,0xa4,0xaf,0xe0,0xa4,0xbc}}, {{0xe0,0xa4,0xb1}, {0xe0,0xa4,0xb0,0xe0,0xa4,0xbc}}, {{0xe0,0xa4,0xb4}, {0xe0,0xa4,0xb3,0xe0,0xa4,0xbc}}, {{0xe0,0xa7,0x9c}, {0xe0,0xa6,0xa1,0xe0,0xa6,0xbc}}, {{0xe0,0xa7,0x9d}, {0xe0,0xa6,0xa2,0xe0,0xa6,0xbc}}, {{0xe0,0xa6,0xb0}, {0xe0,0xa6,0xac,0xe0,0xa6,0xbc}}, {{0xe0,0xa7,0x9f}, {0xe0,0xa6,0xaf,0xe0,0xa6,0xbc}}, {{0xe0,0xa7,0x8b}, {0xe0,0xa7,0x87,0xe0,0xa6,0xbe}}, {{0xe0,0xa7,0x8c}, {0xe0,0xa7,0x87,0xe0,0xa7,0x97}}, {{0xe0,0xa9,0x99}, {0xe0,0xa8,0x96,0xe0,0xa8,0xbc}}, {{0xe0,0xa9,0x9a}, {0xe0,0xa8,0x97,0xe0,0xa8,0xbc}}, {{0xe0,0xa9,0x9b}, {0xe0,0xa8,0x9c,0xe0,0xa8,0xbc}}, {{0xe0,0xa9,0x9c}, {0xe0,0xa8,0xa1,0xe0,0xa8,0xbc}}, {{0xe0,0xa9,0x9e}, {0xe0,0xa8,0xab,0xe0,0xa8,0xbc}}, {{0xe0,0xad,0x9c}, {0xe0,0xac,0xa1,0xe0,0xac,0xbc}}, {{0xe0,0xad,0x9d}, {0xe0,0xac,0xa2,0xe0,0xac,0xbc}}, {{0xe0,0xad,0x9f}, {0xe0,0xac,0xaf,0xe0,0xac,0xbc}}, {{0xe0,0xad,0x8b}, {0xe0,0xad,0x87,0xe0,0xac,0xbe}}, {{0xe0,0xad,0x88}, {0xe0,0xad,0x87,0xe0,0xad,0x96}}, {{0xe0,0xad,0x8c}, {0xe0,0xad,0x87,0xe0,0xad,0x97}}, {{0xe0,0xae,0x94}, {0xe0,0xae,0x92,0xe0,0xaf,0x97}}, {{0xe0,0xaf,0x8a}, {0xe0,0xaf,0x86,0xe0,0xae,0xbe}}, {{0xe0,0xaf,0x8c}, {0xe0,0xaf,0x86,0xe0,0xaf,0x97}}, {{0xe0,0xaf,0x8b}, {0xe0,0xaf,0x87,0xe0,0xae,0xbe}}, {{0xe0,0xb1,0x88}, {0xe0,0xb1,0x86,0xe0,0xb1,0x96}}, {{0xe0,0xb3,0x80}, {0xe0,0xb2,0xbf,0xe0,0xb3,0x95}}, {{0xe0,0xb3,0x8a}, {0xe0,0xb3,0x86,0xe0,0xb3,0x82}}, {{0xe0,0xb3,0x8b}, {0xe0,0xb3,0x86,0xe0,0xb3,0x82,0xe0,0xb3,0x95}}, {{0xe0,0xb3,0x87}, {0xe0,0xb3,0x86,0xe0,0xb3,0x95}}, {{0xe0,0xb3,0x88}, {0xe0,0xb3,0x86,0xe0,0xb3,0x96}}, {{0xe0,0xb5,0x8a}, {0xe0,0xb5,0x86,0xe0,0xb4,0xbe}}, {{0xe0,0xb5,0x8c}, {0xe0,0xb5,0x86,0xe0,0xb5,0x97}}, {{0xe0,0xb5,0x8b}, {0xe0,0xb5,0x87,0xe0,0xb4,0xbe}}, {{0xe0,0xb8,0xb3}, {0xe0,0xb9,0x8d,0xe0,0xb8,0xb2}}, {{0xe0,0xba,0xb3}, {0xe0,0xbb,0x8d,0xe0,0xba,0xb2}}, {{0xe0,0xbd,0xa9}, {0xe0,0xbd,0x80,0xe0,0xbe,0xb5}}, {{0xe0,0xbd,0x83}, {0xe0,0xbd,0x82,0xe0,0xbe,0xb7}}, {{0xe0,0xbd,0x8d}, {0xe0,0xbd,0x8c,0xe0,0xbe,0xb7}}, {{0xe0,0xbd,0x92}, {0xe0,0xbd,0x91,0xe0,0xbe,0xb7}}, {{0xe0,0xbd,0x97}, {0xe0,0xbd,0x96,0xe0,0xbe,0xb7}}, {{0xe0,0xbd,0x9c}, {0xe0,0xbd,0x9b,0xe0,0xbe,0xb7}}, {{0xe0,0xbd,0xb3}, {0xe0,0xbd,0xb2,0xe0,0xbd,0xb1}}, {{0xe0,0xbd,0xb5}, {0xe0,0xbd,0xb4,0xe0,0xbd,0xb1}}, {{0xe0,0xbe,0x81}, {0xe0,0xbe,0x80,0xe0,0xbd,0xb1}}, {{0xe0,0xbe,0xb9}, {0xe0,0xbe,0x90,0xe0,0xbe,0xb5}}, {{0xe0,0xbe,0x93}, {0xe0,0xbe,0x92,0xe0,0xbe,0xb7}}, {{0xe0,0xbe,0x9d}, {0xe0,0xbe,0x9c,0xe0,0xbe,0xb7}}, {{0xe0,0xbe,0xa2}, {0xe0,0xbe,0xa1,0xe0,0xbe,0xb7}}, {{0xe0,0xbe,0xa7}, {0xe0,0xbe,0xa6,0xe0,0xbe,0xb7}}, {{0xe0,0xbe,0xac}, {0xe0,0xbe,0xab,0xe0,0xbe,0xb7}}, {{0xe0,0xbd,0xb6}, {0xe0,0xbe,0xb2,0xe0,0xbe,0x80}}, {{0xe0,0xbd,0xb7}, {0xe0,0xbe,0xb2,0xe0,0xbe,0x80,0xe0,0xbd,0xb1}}, {{0xe0,0xbd,0xb8}, {0xe0,0xbe,0xb3,0xe0,0xbe,0x80}}, {{0xe0,0xbd,0xb9}, {0xe0,0xbe,0xb3,0xe0,0xbe,0x80,0xe0,0xbd,0xb1}}, {{0xe1,0xbf,0x8d}, {0xe1,0xbe,0xbf,0xcc,0x80}}, {{0xe1,0xbf,0x8e}, {0xe1,0xbe,0xbf,0xcc,0x81}}, {{0xe1,0xbf,0x8f}, {0xe1,0xbe,0xbf,0xcd,0x82}}, {{0xe1,0xbf,0x9d}, {0xe1,0xbf,0xbe,0xcc,0x80}}, {{0xe1,0xbf,0x9e}, {0xe1,0xbf,0xbe,0xcc,0x81}}, {{0xe1,0xbf,0x9f}, {0xe1,0xbf,0xbe,0xcd,0x82}}, {{0xe3,0x82,0x94}, {0xe3,0x81,0x86,0xe3,0x82,0x99}}, {{0xe3,0x81,0x8c}, {0xe3,0x81,0x8b,0xe3,0x82,0x99}}, {{0xe3,0x81,0x8e}, {0xe3,0x81,0x8d,0xe3,0x82,0x99}}, {{0xe3,0x81,0x90}, {0xe3,0x81,0x8f,0xe3,0x82,0x99}}, {{0xe3,0x81,0x92}, {0xe3,0x81,0x91,0xe3,0x82,0x99}}, {{0xe3,0x81,0x94}, {0xe3,0x81,0x93,0xe3,0x82,0x99}}, {{0xe3,0x81,0x96}, {0xe3,0x81,0x95,0xe3,0x82,0x99}}, {{0xe3,0x81,0x98}, {0xe3,0x81,0x97,0xe3,0x82,0x99}}, {{0xe3,0x81,0x9a}, {0xe3,0x81,0x99,0xe3,0x82,0x99}}, {{0xe3,0x81,0x9c}, {0xe3,0x81,0x9b,0xe3,0x82,0x99}}, {{0xe3,0x81,0x9e}, {0xe3,0x81,0x9d,0xe3,0x82,0x99}}, {{0xe3,0x81,0xa0}, {0xe3,0x81,0x9f,0xe3,0x82,0x99}}, {{0xe3,0x81,0xa2}, {0xe3,0x81,0xa1,0xe3,0x82,0x99}}, {{0xe3,0x81,0xa5}, {0xe3,0x81,0xa4,0xe3,0x82,0x99}}, {{0xe3,0x81,0xa7}, {0xe3,0x81,0xa6,0xe3,0x82,0x99}}, {{0xe3,0x81,0xa9}, {0xe3,0x81,0xa8,0xe3,0x82,0x99}}, {{0xe3,0x81,0xb0}, {0xe3,0x81,0xaf,0xe3,0x82,0x99}}, {{0xe3,0x81,0xb1}, {0xe3,0x81,0xaf,0xe3,0x82,0x9a}}, {{0xe3,0x81,0xb3}, {0xe3,0x81,0xb2,0xe3,0x82,0x99}}, {{0xe3,0x81,0xb4}, {0xe3,0x81,0xb2,0xe3,0x82,0x9a}}, {{0xe3,0x81,0xb6}, {0xe3,0x81,0xb5,0xe3,0x82,0x99}}, {{0xe3,0x81,0xb7}, {0xe3,0x81,0xb5,0xe3,0x82,0x9a}}, {{0xe3,0x81,0xb9}, {0xe3,0x81,0xb8,0xe3,0x82,0x99}}, {{0xe3,0x81,0xba}, {0xe3,0x81,0xb8,0xe3,0x82,0x9a}}, {{0xe3,0x81,0xbc}, {0xe3,0x81,0xbb,0xe3,0x82,0x99}}, {{0xe3,0x81,0xbd}, {0xe3,0x81,0xbb,0xe3,0x82,0x9a}}, {{0xe3,0x82,0x9e}, {0xe3,0x82,0x9d,0xe3,0x82,0x99}}, {{0xe3,0x83,0xb4}, {0xe3,0x82,0xa6,0xe3,0x82,0x99}}, {{0xe3,0x82,0xac}, {0xe3,0x82,0xab,0xe3,0x82,0x99}}, {{0xe3,0x82,0xae}, {0xe3,0x82,0xad,0xe3,0x82,0x99}}, {{0xe3,0x82,0xb0}, {0xe3,0x82,0xaf,0xe3,0x82,0x99}}, {{0xe3,0x82,0xb2}, {0xe3,0x82,0xb1,0xe3,0x82,0x99}}, {{0xe3,0x82,0xb4}, {0xe3,0x82,0xb3,0xe3,0x82,0x99}}, {{0xe3,0x82,0xb6}, {0xe3,0x82,0xb5,0xe3,0x82,0x99}}, {{0xe3,0x82,0xb8}, {0xe3,0x82,0xb7,0xe3,0x82,0x99}}, {{0xe3,0x82,0xba}, {0xe3,0x82,0xb9,0xe3,0x82,0x99}}, {{0xe3,0x82,0xbc}, {0xe3,0x82,0xbb,0xe3,0x82,0x99}}, {{0xe3,0x82,0xbe}, {0xe3,0x82,0xbd,0xe3,0x82,0x99}}, {{0xe3,0x83,0x80}, {0xe3,0x82,0xbf,0xe3,0x82,0x99}}, {{0xe3,0x83,0x82}, {0xe3,0x83,0x81,0xe3,0x82,0x99}}, {{0xe3,0x83,0x85}, {0xe3,0x83,0x84,0xe3,0x82,0x99}}, {{0xe3,0x83,0x87}, {0xe3,0x83,0x86,0xe3,0x82,0x99}}, {{0xe3,0x83,0x89}, {0xe3,0x83,0x88,0xe3,0x82,0x99}}, {{0xe3,0x83,0x90}, {0xe3,0x83,0x8f,0xe3,0x82,0x99}}, {{0xe3,0x83,0x91}, {0xe3,0x83,0x8f,0xe3,0x82,0x9a}}, {{0xe3,0x83,0x93}, {0xe3,0x83,0x92,0xe3,0x82,0x99}}, {{0xe3,0x83,0x94}, {0xe3,0x83,0x92,0xe3,0x82,0x9a}}, {{0xe3,0x83,0x96}, {0xe3,0x83,0x95,0xe3,0x82,0x99}}, {{0xe3,0x83,0x97}, {0xe3,0x83,0x95,0xe3,0x82,0x9a}}, {{0xe3,0x83,0x99}, {0xe3,0x83,0x98,0xe3,0x82,0x99}}, {{0xe3,0x83,0x9a}, {0xe3,0x83,0x98,0xe3,0x82,0x9a}}, {{0xe3,0x83,0x9c}, {0xe3,0x83,0x9b,0xe3,0x82,0x99}}, {{0xe3,0x83,0x9d}, {0xe3,0x83,0x9b,0xe3,0x82,0x9a}}, {{0xe3,0x83,0xb7}, {0xe3,0x83,0xaf,0xe3,0x82,0x99}}, {{0xe3,0x83,0xb8}, {0xe3,0x83,0xb0,0xe3,0x82,0x99}}, {{0xe3,0x83,0xb9}, {0xe3,0x83,0xb1,0xe3,0x82,0x99}}, {{0xe3,0x83,0xba}, {0xe3,0x83,0xb2,0xe3,0x82,0x99}}, {{0xe3,0x83,0xbe}, {0xe3,0x83,0xbd,0xe3,0x82,0x99}}, }; #endif /* UNICODE_NORMALIZATION */ #endif /* UTF8_INPUT_ENABLE */ #ifdef SHIFTJIS_CP932 const unsigned short shiftjis_cp932[3][189] = { { 0xEEEF, 0xEEF0, 0xEEF1, 0xEEF2, 0xEEF3, 0xEEF4, 0xEEF5, 0xEEF6, 0xEEF7, 0xEEF8, 0x8754, 0x8755, 0x8756, 0x8757, 0x8758, 0x8759, 0x875A, 0x875B, 0x875C, 0x875D, 0x81CA, 0xEEFA, 0xEEFB, 0xEEFC, 0x878A, 0x8782, 0x8784, 0x81E6, 0xED40, 0xED41, 0xED42, 0xED43, 0xED44, 0xED45, 0xED46, 0xED47, 0xED48, 0xED49, 0xED4A, 0xED4B, 0xED4C, 0xED4D, 0xED4E, 0xED4F, 0xED50, 0xED51, 0xED52, 0xED53, 0xED54, 0xED55, 0xED56, 0xED57, 0xED58, 0xED59, 0xED5A, 0xED5B, 0xED5C, 0xED5D, 0xED5E, 0xED5F, 0xED60, 0xED61, 0xED62, 0, 0xED63, 0xED64, 0xED65, 0xED66, 0xED67, 0xED68, 0xED69, 0xED6A, 0xED6B, 0xED6C, 0xED6D, 0xED6E, 0xED6F, 0xED70, 0xED71, 0xED72, 0xED73, 0xED74, 0xED75, 0xED76, 0xED77, 0xED78, 0xED79, 0xED7A, 0xED7B, 0xED7C, 0xED7D, 0xED7E, 0xED80, 0xED81, 0xED82, 0xED83, 0xED84, 0xED85, 0xED86, 0xED87, 0xED88, 0xED89, 0xED8A, 0xED8B, 0xED8C, 0xED8D, 0xED8E, 0xED8F, 0xED90, 0xED91, 0xED92, 0xED93, 0xED94, 0xED95, 0xED96, 0xED97, 0xED98, 0xED99, 0xED9A, 0xED9B, 0xED9C, 0xED9D, 0xED9E, 0xED9F, 0xEDA0, 0xEDA1, 0xEDA2, 0xEDA3, 0xEDA4, 0xEDA5, 0xEDA6, 0xEDA7, 0xEDA8, 0xEDA9, 0xEDAA, 0xEDAB, 0xEDAC, 0xEDAD, 0xEDAE, 0xEDAF, 0xEDB0, 0xEDB1, 0xEDB2, 0xEDB3, 0xEDB4, 0xEDB5, 0xEDB6, 0xEDB7, 0xEDB8, 0xEDB9, 0xEDBA, 0xEDBB, 0xEDBC, 0xEDBD, 0xEDBE, 0xEDBF, 0xEDC0, 0xEDC1, 0xEDC2, 0xEDC3, 0xEDC4, 0xEDC5, 0xEDC6, 0xEDC7, 0xEDC8, 0xEDC9, 0xEDCA, 0xEDCB, 0xEDCC, 0xEDCD, 0xEDCE, 0xEDCF, 0xEDD0, 0xEDD1, 0xEDD2, 0xEDD3, 0xEDD4, 0xEDD5, 0xEDD6, 0xEDD7, 0xEDD8, 0xEDD9, 0xEDDA, 0xEDDB, 0xEDDC, 0xEDDD, 0xEDDE, 0xEDDF, 0xEDE0, }, { 0xEDE1, 0xEDE2, 0xEDE3, 0xEDE4, 0xEDE5, 0xEDE6, 0xEDE7, 0xEDE8, 0xEDE9, 0xEDEA, 0xEDEB, 0xEDEC, 0xEDED, 0xEDEE, 0xEDEF, 0xEDF0, 0xEDF1, 0xEDF2, 0xEDF3, 0xEDF4, 0xEDF5, 0xEDF6, 0xEDF7, 0xEDF8, 0xEDF9, 0xEDFA, 0xEDFB, 0xEDFC, 0xEE40, 0xEE41, 0xEE42, 0xEE43, 0xEE44, 0xEE45, 0xEE46, 0xEE47, 0xEE48, 0xEE49, 0xEE4A, 0xEE4B, 0xEE4C, 0xEE4D, 0xEE4E, 0xEE4F, 0xEE50, 0xEE51, 0xEE52, 0xEE53, 0xEE54, 0xEE55, 0xEE56, 0xEE57, 0xEE58, 0xEE59, 0xEE5A, 0xEE5B, 0xEE5C, 0xEE5D, 0xEE5E, 0xEE5F, 0xEE60, 0xEE61, 0xEE62, 0, 0xEE63, 0xEE64, 0xEE65, 0xEE66, 0xEE67, 0xEE68, 0xEE69, 0xEE6A, 0xEE6B, 0xEE6C, 0xEE6D, 0xEE6E, 0xEE6F, 0xEE70, 0xEE71, 0xEE72, 0xEE73, 0xEE74, 0xEE75, 0xEE76, 0xEE77, 0xEE78, 0xEE79, 0xEE7A, 0xEE7B, 0xEE7C, 0xEE7D, 0xEE7E, 0xEE80, 0xEE81, 0xEE82, 0xEE83, 0xEE84, 0xEE85, 0xEE86, 0xEE87, 0xEE88, 0xEE89, 0xEE8A, 0xEE8B, 0xEE8C, 0xEE8D, 0xEE8E, 0xEE8F, 0xEE90, 0xEE91, 0xEE92, 0xEE93, 0xEE94, 0xEE95, 0xEE96, 0xEE97, 0xEE98, 0xEE99, 0xEE9A, 0xEE9B, 0xEE9C, 0xEE9D, 0xEE9E, 0xEE9F, 0xEEA0, 0xEEA1, 0xEEA2, 0xEEA3, 0xEEA4, 0xEEA5, 0xEEA6, 0xEEA7, 0xEEA8, 0xEEA9, 0xEEAA, 0xEEAB, 0xEEAC, 0xEEAD, 0xEEAE, 0xEEAF, 0xEEB0, 0xEEB1, 0xEEB2, 0xEEB3, 0xEEB4, 0xEEB5, 0xEEB6, 0xEEB7, 0xEEB8, 0xEEB9, 0xEEBA, 0xEEBB, 0xEEBC, 0xEEBD, 0xEEBE, 0xEEBF, 0xEEC0, 0xEEC1, 0xEEC2, 0xEEC3, 0xEEC4, 0xEEC5, 0xEEC6, 0xEEC7, 0xEEC8, 0xEEC9, 0xEECA, 0xEECB, 0xEECC, 0xEECD, 0xEECE, 0xEECF, 0xEED0, 0xEED1, 0xEED2, 0xEED3, 0xEED4, 0xEED5, 0xEED6, 0xEED7, 0xEED8, 0xEED9, 0xEEDA, 0xEEDB, 0xEEDC, 0xEEDD, 0xEEDE, 0xEEDF, 0xEEE0, }, { 0xEEE1, 0xEEE2, 0xEEE3, 0xEEE4, 0xEEE5, 0xEEE6, 0xEEE7, 0xEEE8, 0xEEE9, 0xEEEA, 0xEEEB, 0xEEEC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, }; const unsigned short cp932inv[2][189] = { { 0xFA5C, 0xFA5D, 0xFA5E, 0xFA5F, 0xFA60, 0xFA61, 0xFA62, 0xFA63, 0xFA64, 0xFA65, 0xFA66, 0xFA67, 0xFA68, 0xFA69, 0xFA6A, 0xFA6B, 0xFA6C, 0xFA6D, 0xFA6E, 0xFA6F, 0xFA70, 0xFA71, 0xFA72, 0xFA73, 0xFA74, 0xFA75, 0xFA76, 0xFA77, 0xFA78, 0xFA79, 0xFA7A, 0xFA7B, 0xFA7C, 0xFA7D, 0xFA7E, 0xFA80, 0xFA81, 0xFA82, 0xFA83, 0xFA84, 0xFA85, 0xFA86, 0xFA87, 0xFA88, 0xFA89, 0xFA8A, 0xFA8B, 0xFA8C, 0xFA8D, 0xFA8E, 0xFA8F, 0xFA90, 0xFA91, 0xFA92, 0xFA93, 0xFA94, 0xFA95, 0xFA96, 0xFA97, 0xFA98, 0xFA99, 0xFA9A, 0xFA9B, 0, 0xFA9C, 0xFA9D, 0xFA9E, 0xFA9F, 0xFAA0, 0xFAA1, 0xFAA2, 0xFAA3, 0xFAA4, 0xFAA5, 0xFAA6, 0xFAA7, 0xFAA8, 0xFAA9, 0xFAAA, 0xFAAB, 0xFAAC, 0xFAAD, 0xFAAE, 0xFAAF, 0xFAB0, 0xFAB1, 0xFAB2, 0xFAB3, 0xFAB4, 0xFAB5, 0xFAB6, 0xFAB7, 0xFAB8, 0xFAB9, 0xFABA, 0xFABB, 0xFABC, 0xFABD, 0xFABE, 0xFABF, 0xFAC0, 0xFAC1, 0xFAC2, 0xFAC3, 0xFAC4, 0xFAC5, 0xFAC6, 0xFAC7, 0xFAC8, 0xFAC9, 0xFACA, 0xFACB, 0xFACC, 0xFACD, 0xFACE, 0xFACF, 0xFAD0, 0xFAD1, 0xFAD2, 0xFAD3, 0xFAD4, 0xFAD5, 0xFAD6, 0xFAD7, 0xFAD8, 0xFAD9, 0xFADA, 0xFADB, 0xFADC, 0xFADD, 0xFADE, 0xFADF, 0xFAE0, 0xFAE1, 0xFAE2, 0xFAE3, 0xFAE4, 0xFAE5, 0xFAE6, 0xFAE7, 0xFAE8, 0xFAE9, 0xFAEA, 0xFAEB, 0xFAEC, 0xFAED, 0xFAEE, 0xFAEF, 0xFAF0, 0xFAF1, 0xFAF2, 0xFAF3, 0xFAF4, 0xFAF5, 0xFAF6, 0xFAF7, 0xFAF8, 0xFAF9, 0xFAFA, 0xFAFB, 0xFAFC, 0xFB40, 0xFB41, 0xFB42, 0xFB43, 0xFB44, 0xFB45, 0xFB46, 0xFB47, 0xFB48, 0xFB49, 0xFB4A, 0xFB4B, 0xFB4C, 0xFB4D, 0xFB4E, 0xFB4F, 0xFB50, 0xFB51, 0xFB52, 0xFB53, 0xFB54, 0xFB55, 0xFB56, 0xFB57, 0xFB58, 0xFB59, 0xFB5A, 0xFB5B, }, { 0xFB5C, 0xFB5D, 0xFB5E, 0xFB5F, 0xFB60, 0xFB61, 0xFB62, 0xFB63, 0xFB64, 0xFB65, 0xFB66, 0xFB67, 0xFB68, 0xFB69, 0xFB6A, 0xFB6B, 0xFB6C, 0xFB6D, 0xFB6E, 0xFB6F, 0xFB70, 0xFB71, 0xFB72, 0xFB73, 0xFB74, 0xFB75, 0xFB76, 0xFB77, 0xFB78, 0xFB79, 0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D, 0xFB7E, 0xFB80, 0xFB81, 0xFB82, 0xFB83, 0xFB84, 0xFB85, 0xFB86, 0xFB87, 0xFB88, 0xFB89, 0xFB8A, 0xFB8B, 0xFB8C, 0xFB8D, 0xFB8E, 0xFB8F, 0xFB90, 0xFB91, 0xFB92, 0xFB93, 0xFB94, 0xFB95, 0xFB96, 0xFB97, 0xFB98, 0xFB99, 0xFB9A, 0xFB9B, 0, 0xFB9C, 0xFB9D, 0xFB9E, 0xFB9F, 0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3, 0xFBA4, 0xFBA5, 0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9, 0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD, 0xFBAE, 0xFBAF, 0xFBB0, 0xFBB1, 0xFBB2, 0xFBB3, 0xFBB4, 0xFBB5, 0xFBB6, 0xFBB7, 0xFBB8, 0xFBB9, 0xFBBA, 0xFBBB, 0xFBBC, 0xFBBD, 0xFBBE, 0xFBBF, 0xFBC0, 0xFBC1, 0xFBC2, 0xFBC3, 0xFBC4, 0xFBC5, 0xFBC6, 0xFBC7, 0xFBC8, 0xFBC9, 0xFBCA, 0xFBCB, 0xFBCC, 0xFBCD, 0xFBCE, 0xFBCF, 0xFBD0, 0xFBD1, 0xFBD2, 0xFBD3, 0xFBD4, 0xFBD5, 0xFBD6, 0xFBD7, 0xFBD8, 0xFBD9, 0xFBDA, 0xFBDB, 0xFBDC, 0xFBDD, 0xFBDE, 0xFBDF, 0xFBE0, 0xFBE1, 0xFBE2, 0xFBE3, 0xFBE4, 0xFBE5, 0xFBE6, 0xFBE7, 0xFBE8, 0xFBE9, 0xFBEA, 0xFBEB, 0xFBEC, 0xFBED, 0xFBEE, 0xFBEF, 0xFBF0, 0xFBF1, 0xFBF2, 0xFBF3, 0xFBF4, 0xFBF5, 0xFBF6, 0xFBF7, 0xFBF8, 0xFBF9, 0xFBFA, 0xFBFB, 0xFBFC, 0xFC40, 0xFC41, 0xFC42, 0xFC43, 0xFC44, 0xFC45, 0xFC46, 0xFC47, 0xFC48, 0xFC49, 0xFC4A, 0xFC4B, 0, 0, 0xFA40, 0xFA41, 0xFA42, 0xFA43, 0xFA44, 0xFA45, 0xFA46, 0xFA47, 0xFA48, 0xFA49, 0x81CA, 0xFA55, 0xFA56, 0xFA57, }, }; #endif /* SHIFTJIS_CP932 */ #ifdef X0212_ENABLE const unsigned short shiftjis_x0212[3][189] = { { 0xF373, 0xF374, 0xF375, 0xF376, 0xF377, 0xF378, 0xF379, 0xF37A, 0xF37B, 0xF37C, 0xF37D, 0xF37E, 0xF421, 0xF422, 0xF423, 0xF424, 0xF425, 0xF426, 0xF427, 0xF428, 0x224C, 0xA243, 0xF429, 0xF42A, 0xF42B, 0xF42C, 0xF42D, 0x2268, 0xD463, 0xDC5F, 0xE469, 0xE378, 0xD921, 0xB13B, 0xF42E, 0xC22D, 0xC37C, 0xE450, 0xC23F, 0xBC74, 0xB029, 0xB048, 0xF42F, 0xB052, 0xB054, 0xB063, 0xB06E, 0xB127, 0xB123, 0xB12C, 0xB129, 0xB13E, 0xB15F, 0xB158, 0xB148, 0xB157, 0xB163, 0xB174, 0xB161, 0xB223, 0xF430, 0xB23B, 0xB266, 0, 0xB26D, 0xB275, 0xB27C, 0xF431, 0xB335, 0xB358, 0xB35B, 0xB365, 0xB36E, 0xB37B, 0xF432, 0xF433, 0xB440, 0xB447, 0xB450, 0xB45E, 0xF434, 0xB52A, 0xF435, 0xB52F, 0xB544, 0xB568, 0xF436, 0xB742, 0xB764, 0xB768, 0xB767, 0xF437, 0xF438, 0xF439, 0xB84E, 0xB861, 0xB875, 0xB877, 0xB878, 0xB87C, 0xB92F, 0xB937, 0xBA3E, 0xBA5B, 0xCD2A, 0xBA61, 0xF43A, 0xBA6B, 0xBB33, 0xBB38, 0xF43B, 0xBB4A, 0xF43C, 0xF43D, 0xBB50, 0xBB5E, 0xBB74, 0xBB75, 0xBB79, 0xBC64, 0xBC6D, 0xBC7E, 0xF43E, 0xBD42, 0xBD67, 0xF43F, 0xBD70, 0xBE30, 0xBE2C, 0xF440, 0xBE33, 0xBE3D, 0xBE4D, 0xBE49, 0xBE64, 0xBF28, 0xBF49, 0xC044, 0xC064, 0xC074, 0xC126, 0xF441, 0xC175, 0xC17C, 0xF442, 0xC178, 0xC22B, 0xC221, 0xC225, 0xF443, 0xC238, 0xC23A, 0xF444, 0xC244, 0xC252, 0xC257, 0xC25B, 0xC25E, 0xC26D, 0xC270, 0xF445, 0xC321, 0xC335, 0xC349, 0xC339, 0xF446, 0xC358, 0xC37E, 0xF447, 0xC44C, 0xF448, 0xC459, 0xC46A, 0xC47D, 0xF449, 0xC527, 0xC535, 0xC536, 0xF44A, 0xC555, 0xC638, 0xC657, 0xC660, 0xC66A, 0xC663, 0xC721, 0xC72B, 0xC747, 0xC743, }, { 0xC74B, 0xC74F, 0xC759, 0xF44B, 0xF44C, 0xC766, 0xC76E, 0xC77C, 0xC76B, 0xC770, 0xC831, 0xC865, 0xC878, 0xC926, 0xC92B, 0xC92D, 0xF44D, 0xC94A, 0xC953, 0xC969, 0xC963, 0xC97C, 0xC974, 0xC975, 0xF44E, 0xCA33, 0xCA3D, 0xCA6F, 0xCA71, 0xCB2E, 0xF44F, 0xCB4A, 0xCB66, 0xCB6A, 0xCB70, 0xCB74, 0xCB6E, 0xCC25, 0xCB79, 0xCC2B, 0xCC2E, 0xCC2D, 0xCC32, 0xCC42, 0xCC50, 0xCC59, 0xF450, 0xCD3B, 0xF451, 0xCE3B, 0xF452, 0xCE3A, 0xCE43, 0xF453, 0xCE72, 0xB35D, 0xCF55, 0xCF62, 0xCF69, 0xCF6D, 0xF454, 0xF455, 0xF456, 0, 0xF457, 0xD065, 0xF458, 0xD069, 0xD168, 0xF459, 0xF45A, 0xD16C, 0xD23B, 0xF45B, 0xD361, 0xD368, 0xD427, 0xF45C, 0xF45D, 0xD454, 0xD472, 0xD52E, 0xF45E, 0xD75E, 0xF45F, 0xD822, 0xD837, 0xD841, 0xD851, 0xD874, 0xD946, 0xD948, 0xD951, 0xF460, 0xF461, 0xF462, 0xF463, 0xF464, 0xDC53, 0xDD48, 0xDD54, 0xDD6A, 0xDD7A, 0xDE24, 0xDE30, 0xF465, 0xDE35, 0xDE4B, 0xF466, 0xDF39, 0xF467, 0xDF43, 0xF468, 0xF469, 0xE059, 0xF46A, 0xF46B, 0xE162, 0xF46C, 0xF46D, 0xF46E, 0xE247, 0xE328, 0xE326, 0xE329, 0xE32F, 0xE330, 0xE32A, 0xE32B, 0xE33C, 0xE341, 0xE33F, 0xE355, 0xE358, 0xE356, 0xE35F, 0xE363, 0xE361, 0xE354, 0xE369, 0xE426, 0xE371, 0xE372, 0xE44B, 0xE441, 0xE443, 0xE43E, 0xF46F, 0xE440, 0xE447, 0xE43F, 0xE460, 0xE45E, 0xE451, 0xF470, 0xE45C, 0xE452, 0xE45B, 0xE454, 0xE47A, 0xE46F, 0xE533, 0xE53F, 0xE549, 0xE550, 0xE562, 0xE56A, 0xE56B, 0xF471, 0xF472, 0xF473, 0xE668, 0xE66F, 0xE72C, 0xF474, 0xE72E, 0xF475, 0xE731, 0xF476, 0xE732, 0xE831, 0xE836, 0xF477, 0xF478, 0xE85D, 0xF479, 0xF47A, 0xE951, 0xF47B, }, { 0xE96D, 0xEA4D, 0xF47C, 0xEA5B, 0xEA66, 0xEA6A, 0xEB25, 0xEB7B, 0xEB7A, 0xF47D, 0xEC56, 0xF47E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, }; const unsigned short x0212_shiftjis_A2[] = { 0x819F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x8143, 0, 0, 0x8150, 0, 0, 0x8160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_B0[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0xFA68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA6B, 0, 0xFA6C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA6D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA6E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_B1[] = { 0, 0, 0xFA70, 0, 0, 0, 0xFA6F, 0, 0xFA72, 0, 0, 0xFA71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA61, 0, 0, 0xFA73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA77, 0xFA75, 0, 0, 0, 0, 0, 0, 0xFA74, 0, 0xFA7A, 0, 0xFA78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_B2[] = { 0, 0, 0xFA7B, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA7D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA7E, 0, 0, 0, 0, 0, 0, 0xFA80, 0, 0, 0, 0, 0, 0, 0, 0xFA81, 0, 0, 0, 0, 0, 0, 0xFA82, 0, 0, }; const unsigned short x0212_shiftjis_B3[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA85, 0, 0, 0xFA86, 0, 0xFB77, 0, 0, 0, 0, 0, 0, 0, 0xFA87, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA89, 0, 0, 0, }; const unsigned short x0212_shiftjis_B4[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA8C, 0, 0, 0, 0, 0, 0, 0xFA8D, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA8E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA8F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_B5[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA91, 0, 0, 0, 0, 0xFA93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_B7[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA98, 0, 0, 0xFA9A, 0xFA99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_B8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA9E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA9F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAA0, 0, 0xFAA1, 0xFAA2, 0, 0, 0, 0xFAA3, 0, 0, }; const unsigned short x0212_shiftjis_B9[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAA4, 0, 0, 0, 0, 0, 0, 0, 0xFAA5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_BA[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAA6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAA7, 0, 0, 0, 0, 0, 0xFAA9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAAB, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_BB[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAAC, 0, 0, 0, 0, 0xFAAD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAAF, 0, 0, 0, 0, 0, 0xFAB2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAB3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAB4, 0xFAB5, 0, 0, 0, 0xFAB6, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_BC[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAB7, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAB8, 0, 0, 0, 0, 0, 0, 0xFA67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAB9, }; const unsigned short x0212_shiftjis_BD[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFABB, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFABC, 0, 0, 0, 0, 0, 0, 0, 0, 0xFABE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_BE[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAC0, 0, 0, 0, 0xFABF, 0, 0, 0xFAC2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAC3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAC5, 0, 0, 0, 0xFAC4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAC6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_BF[] = { 0, 0, 0, 0, 0, 0, 0, 0xFAC7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAC8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_C0[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAC9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFACA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFACB, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_C1[] = { 0, 0, 0, 0, 0, 0xFACC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFACE, 0, 0, 0xFAD1, 0, 0, 0, 0xFACF, 0, 0, }; const unsigned short x0212_shiftjis_C2[] = { 0xFAD3, 0, 0, 0, 0xFAD4, 0, 0, 0, 0, 0, 0xFAD2, 0, 0xFA63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAD6, 0, 0xFAD7, 0, 0, 0, 0, 0xFA66, 0, 0, 0, 0, 0xFAD9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFADA, 0, 0, 0, 0, 0xFADB, 0, 0, 0, 0xFADC, 0, 0, 0xFADD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFADE, 0, 0, 0xFADF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_C3[] = { 0xFAE1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAE2, 0, 0, 0, 0xFAE4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAE3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAE6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA64, 0, 0xFAE7, }; const unsigned short x0212_shiftjis_C4[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAE9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAEB, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAEC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAED, 0, }; const unsigned short x0212_shiftjis_C5[] = { 0, 0, 0, 0, 0, 0, 0xFAEF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAF0, 0xFAF1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAF3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_C6[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAF4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAF5, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAF6, 0, 0, 0xFAF8, 0, 0, 0, 0, 0, 0, 0xFAF7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_C7[] = { 0xFAF9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAFA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAFC, 0, 0, 0, 0xFAFB, 0, 0, 0, 0xFB40, 0, 0, 0, 0xFB41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB45, 0, 0, 0, 0, 0xFB48, 0, 0, 0xFB46, 0, 0xFB49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB47, 0, 0, }; const unsigned short x0212_shiftjis_C8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB4A, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB4B, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB4C, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_C9[] = { 0, 0, 0, 0, 0, 0xFB4D, 0, 0, 0, 0, 0xFB4E, 0, 0xFB4F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB51, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB54, 0, 0, 0, 0, 0, 0xFB53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB56, 0xFB57, 0, 0, 0, 0, 0, 0, 0xFB55, 0, 0, }; const unsigned short x0212_shiftjis_CA[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB5A, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB5B, 0, 0xFB5C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_CB[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB5D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB5F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB60, 0, 0, 0, 0xFB61, 0, 0, 0, 0xFB64, 0, 0xFB62, 0, 0, 0, 0xFB63, 0, 0, 0, 0, 0xFB66, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_CC[] = { 0, 0, 0, 0, 0xFB65, 0, 0, 0, 0, 0, 0xFB67, 0, 0xFB69, 0xFB68, 0, 0, 0, 0xFB6A, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB6B, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB6C, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB6D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_CD[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFAA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB6F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_CE[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB73, 0xFB71, 0, 0, 0, 0, 0, 0, 0, 0xFB74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_CF[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB79, 0, 0, 0, 0, 0, 0, 0xFB7A, 0, 0, 0, 0xFB7B, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_D0[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB81, 0, 0, 0, 0xFB83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_D1[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB84, 0, 0, 0, 0xFB87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_D2[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_D3[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB8A, 0, 0, 0, 0, 0, 0, 0xFB8B, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_D4[] = { 0, 0, 0, 0, 0, 0, 0xFB8C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB8F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA5C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_D5[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_D7[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_D8[] = { 0, 0xFB95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_D9[] = { 0xFA60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB9A, 0, 0xFB9B, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB9C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_DC[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBA2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA5D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_DD[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBA3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBA4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBA5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBA6, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_DE[] = { 0, 0, 0, 0xFBA7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBA8, 0, 0, 0, 0, 0xFBAA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBAB, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_DF[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBAD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBAF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_E0[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBB2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_E1[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBB5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_E2[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBB9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_E3[] = { 0, 0, 0, 0, 0, 0xFBBB, 0, 0xFBBA, 0xFBBC, 0xFBBF, 0xFBC0, 0, 0, 0, 0xFBBD, 0xFBBE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBC1, 0, 0, 0xFBC3, 0, 0xFBC2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBCA, 0xFBC4, 0xFBC6, 0, 0xFBC5, 0, 0, 0, 0, 0, 0, 0xFBC7, 0, 0xFBC9, 0, 0xFBC8, 0, 0, 0, 0, 0, 0xFBCB, 0, 0, 0, 0, 0, 0, 0, 0xFBCD, 0xFBCE, 0, 0, 0, 0, 0, 0xFA5F, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_E4[] = { 0, 0, 0, 0, 0, 0xFBCC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBD2, 0xFBD6, 0xFBD4, 0xFBD0, 0, 0xFBD1, 0, 0, 0, 0xFBD5, 0, 0, 0, 0xFBCF, 0, 0, 0, 0, 0xFA65, 0xFBD9, 0xFBDC, 0, 0xFBDE, 0, 0, 0, 0, 0, 0, 0xFBDD, 0xFBDB, 0, 0xFBD8, 0, 0xFBD7, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA5E, 0, 0, 0, 0, 0, 0xFBE0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBDF, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_E5[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBE1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBE2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBE3, 0, 0, 0, 0, 0, 0, 0xFBE4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBE5, 0, 0, 0, 0, 0, 0, 0, 0xFBE6, 0xFBE7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_E6[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBEB, 0, 0, 0, 0, 0, 0, 0xFBEC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_E7[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBED, 0, 0xFBEF, 0, 0, 0xFBF1, 0xFBF3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_E8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBF4, 0, 0, 0, 0, 0xFBF5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBF8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_E9[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFBFB, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFC40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_EA[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFC41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFC43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFC44, 0, 0, 0, 0xFC45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_EB[] = { 0, 0, 0, 0, 0xFC46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFC48, 0xFC47, 0, 0, 0, }; const unsigned short x0212_shiftjis_EC[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFC4A, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned short x0212_shiftjis_F3[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFA40, 0xFA41, 0xFA42, 0xFA43, 0xFA44, 0xFA45, 0xFA46, 0xFA47, 0xFA48, 0xFA49, 0xFA4A, 0xFA4B, }; const unsigned short x0212_shiftjis_F4[] = { 0xFA4C, 0xFA4D, 0xFA4E, 0xFA4F, 0xFA50, 0xFA51, 0xFA52, 0xFA53, 0xFA56, 0xFA57, 0xFA58, 0xFA59, 0xFA5A, 0xFA62, 0xFA6A, 0xFA7C, 0xFA83, 0xFA8A, 0xFA8B, 0xFA90, 0xFA92, 0xFA96, 0xFA9B, 0xFA9C, 0xFA9D, 0xFAAA, 0xFAAE, 0xFAB0, 0xFAB1, 0xFABA, 0xFABD, 0xFAC1, 0xFACD, 0xFAD0, 0xFAD5, 0xFAD8, 0xFAE0, 0xFAE5, 0xFAE8, 0xFAEA, 0xFAEE, 0xFAF2, 0xFB43, 0xFB44, 0xFB50, 0xFB58, 0xFB5E, 0xFB6E, 0xFB70, 0xFB72, 0xFB75, 0xFB7C, 0xFB7D, 0xFB7E, 0xFB80, 0xFB82, 0xFB85, 0xFB86, 0xFB89, 0xFB8D, 0xFB8E, 0xFB92, 0xFB94, 0xFB9D, 0xFB9E, 0xFB9F, 0xFBA0, 0xFBA1, 0xFBA9, 0xFBAC, 0xFBAE, 0xFBB0, 0xFBB1, 0xFBB3, 0xFBB4, 0xFBB6, 0xFBB7, 0xFBB8, 0xFBD3, 0xFBDA, 0xFBE8, 0xFBE9, 0xFBEA, 0xFBEE, 0xFBF0, 0xFBF2, 0xFBF6, 0xFBF7, 0xFBF9, 0xFBFA, 0xFBFC, 0xFC42, 0xFC49, 0xFC4B, }; const unsigned short *const x0212_shiftjis[] = { 0, x0212_shiftjis_A2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, x0212_shiftjis_B0, x0212_shiftjis_B1, x0212_shiftjis_B2, x0212_shiftjis_B3, x0212_shiftjis_B4, x0212_shiftjis_B5, 0, x0212_shiftjis_B7, x0212_shiftjis_B8, x0212_shiftjis_B9, x0212_shiftjis_BA, x0212_shiftjis_BB, x0212_shiftjis_BC, x0212_shiftjis_BD, x0212_shiftjis_BE, x0212_shiftjis_BF, x0212_shiftjis_C0, x0212_shiftjis_C1, x0212_shiftjis_C2, x0212_shiftjis_C3, x0212_shiftjis_C4, x0212_shiftjis_C5, x0212_shiftjis_C6, x0212_shiftjis_C7, x0212_shiftjis_C8, x0212_shiftjis_C9, x0212_shiftjis_CA, x0212_shiftjis_CB, x0212_shiftjis_CC, x0212_shiftjis_CD, x0212_shiftjis_CE, x0212_shiftjis_CF, x0212_shiftjis_D0, x0212_shiftjis_D1, x0212_shiftjis_D2, x0212_shiftjis_D3, x0212_shiftjis_D4, x0212_shiftjis_D5, 0, x0212_shiftjis_D7, x0212_shiftjis_D8, x0212_shiftjis_D9, 0, 0, x0212_shiftjis_DC, x0212_shiftjis_DD, x0212_shiftjis_DE, x0212_shiftjis_DF, x0212_shiftjis_E0, x0212_shiftjis_E1, x0212_shiftjis_E2, x0212_shiftjis_E3, x0212_shiftjis_E4, x0212_shiftjis_E5, x0212_shiftjis_E6, x0212_shiftjis_E7, x0212_shiftjis_E8, x0212_shiftjis_E9, x0212_shiftjis_EA, x0212_shiftjis_EB, x0212_shiftjis_EC, 0, 0, 0, 0, 0, 0, x0212_shiftjis_F3, x0212_shiftjis_F4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; #endif /* X0212_ENABLE */ ================================================ FILE: ext/nkf/nkf-utf8/utf8tbl.h ================================================ #ifndef _UTF8TBL_H_ #define _UTF8TBL_H_ #ifdef UTF8_OUTPUT_ENABLE extern const unsigned short euc_to_utf8_1byte[]; extern const unsigned short *const euc_to_utf8_2bytes[]; extern const unsigned short *const euc_to_utf8_2bytes_ms[]; extern const unsigned short *const x0212_to_utf8_2bytes[]; #endif /* UTF8_OUTPUT_ENABLE */ #ifdef UTF8_INPUT_ENABLE extern const unsigned short *const utf8_to_euc_2bytes[]; extern const unsigned short *const utf8_to_euc_2bytes_ms[]; extern const unsigned short *const utf8_to_euc_2bytes_932[]; extern const unsigned short *const *const utf8_to_euc_3bytes[]; extern const unsigned short *const *const utf8_to_euc_3bytes_ms[]; extern const unsigned short *const *const utf8_to_euc_3bytes_932[]; #endif /* UTF8_INPUT_ENABLE */ #ifdef UNICODE_NORMALIZATION extern const struct normalization_pair normalization_table[]; #endif #ifdef SHIFTJIS_CP932 extern const unsigned short shiftjis_cp932[3][189]; extern const unsigned short cp932inv[2][189]; #endif /* SHIFTJIS_CP932 */ #ifdef X0212_ENABLE extern const unsigned short shiftjis_x0212[3][189]; extern const unsigned short *const x0212_shiftjis[]; #endif /* X0212_ENABLE */ #endif ================================================ FILE: ext/nkf/nkf.c ================================================ /* * NKF - Ruby extension for Network Kanji Filter * * original nkf2.x is maintained at http://sourceforge.jp/projects/nkf/ * * $Id$ * */ #define RUBY_NKF_REVISION "$Revision$" #define RUBY_NKF_VERSION NKF_VERSION " (" NKF_RELEASE_DATE ")" #include "ruby.h" /* Encoding Constants */ #define _AUTO 0 #define _JIS 1 #define _EUC 2 #define _SJIS 3 #define _BINARY 4 #define _NOCONV 4 #define _ASCII 5 /* 0b011x is reserved for UTF-8 Family */ #define _UTF8 6 /* 0b10xx is reserved for UTF-16 Family */ #define _UTF16 8 /* 0b11xx is reserved for UTF-32 Family */ #define _UTF32 12 #define _OTHER 16 #define _UNKNOWN _AUTO /* Replace nkf's getchar/putchar for variable modification */ /* we never use getc, ungetc */ #undef getc #undef ungetc #define getc(f) (input_ctr>=i_len?-1:input[input_ctr++]) #define ungetc(c,f) input_ctr-- #define INCSIZE 32 #undef putchar #undef TRUE #undef FALSE #define putchar(c) rb_nkf_putchar(c) /* Input/Output pointers */ static unsigned char *output; static unsigned char *input; static int input_ctr; static int i_len; static int output_ctr; static int o_len; static int incsize; static VALUE result; static int rb_nkf_putchar(c) unsigned int c; { if (output_ctr >= o_len) { o_len += incsize; rb_str_resize(result, o_len); incsize *= 2; output = (unsigned char *)RSTRING(result)->ptr; } output[output_ctr++] = c; return c; } /* Include kanji filter main part */ /* getchar and putchar will be replaced during inclusion */ #define PERL_XS 1 #include "nkf-utf8/config.h" #include "nkf-utf8/utf8tbl.c" #include "nkf-utf8/nkf.c" int nkf_split_options(arg) const char* arg; { int count = 0; char option[256]; int i = 0, j = 0; int is_escaped = FALSE; int is_single_quoted = FALSE; int is_double_quoted = FALSE; for(i = 0; arg[i]; i++){ if(j == 255){ return -1; }else if(is_single_quoted){ if(arg[i] == '\''){ is_single_quoted = FALSE; }else{ option[j++] = arg[i]; } }else if(is_escaped){ is_escaped = FALSE; option[j++] = arg[i]; }else if(arg[i] == '\\'){ is_escaped = TRUE; }else if(is_double_quoted){ if(arg[i] == '"'){ is_double_quoted = FALSE; }else{ option[j++] = arg[i]; } }else if(arg[i] == '\''){ is_single_quoted = TRUE; }else if(arg[i] == '"'){ is_double_quoted = TRUE; }else if(arg[i] == ' '){ option[j] = '\0'; options(option); j = 0; }else{ option[j++] = arg[i]; } } if(j){ option[j] = '\0'; options(option); } return count; } /* * call-seq: * NKF.nkf(opt, str) -> string * * Convert _str_ and return converted result. * Conversion details are specified by _opt_ as String. * * require 'nkf' * output = NKF.nkf("-s", input) * * *Note* * By default, nkf decodes MIME encoded string. * If you want not to decode input, use NKF.nkf with -m0 flag. */ static VALUE rb_nkf_kconv(obj, opt, src) VALUE obj, opt, src; { char *opt_ptr, *opt_end; volatile VALUE v; reinit(); StringValue(opt); opt_ptr = RSTRING(opt)->ptr; opt_end = opt_ptr + RSTRING(opt)->len; nkf_split_options(opt_ptr); incsize = INCSIZE; input_ctr = 0; StringValue(src); input = (unsigned char *)RSTRING(src)->ptr; i_len = RSTRING(src)->len; result = rb_str_new(0, i_len*3 + 10); v = result; output_ctr = 0; output = (unsigned char *)RSTRING(result)->ptr; o_len = RSTRING(result)->len; *output = '\0'; if(x0201_f == WISH_TRUE) x0201_f = ((!iso2022jp_f)? TRUE : NO_X0201); kanji_convert(NULL); RSTRING(result)->ptr[output_ctr] = '\0'; RSTRING(result)->len = output_ctr; OBJ_INFECT(result, src); return result; } /* * call-seq: * NKF.guess1(str) -> integer * * Returns guessed encoding of _str_ as integer. * * Algorithm described in: * Ken Lunde. `Understanding Japanese Information Processing' * Sebastopol, CA: O'Reilly & Associates. * * case NKF.guess1(input) * when NKF::JIS * "ISO-2022-JP" * when NKF::SJIS * "Shift_JIS" * when NKF::EUC * "EUC-JP" * when NKF::UNKNOWN * "UNKNOWN(ASCII)" * when NKF::BINARY * "BINARY" * end */ static VALUE rb_nkf_guess1(obj, src) VALUE obj, src; { unsigned char *p; unsigned char *pend; int sequence_counter = 0; StringValue(src); p = (unsigned char *)RSTRING(src)->ptr; pend = p + RSTRING(src)->len; if (p == pend) return INT2FIX(_UNKNOWN); #define INCR do {\ p++;\ if (p==pend) return INT2FIX(_UNKNOWN);\ sequence_counter++;\ if (sequence_counter % 2 == 1 && *p != 0xa4)\ sequence_counter = 0;\ if (6 <= sequence_counter) {\ sequence_counter = 0;\ return INT2FIX(_EUC);\ }\ } while (0) if (*p == 0xa4) sequence_counter = 1; while (p= 0x40) { if (*p >= 0x81) { if (*p <= 0x8d || (0x8f <= *p && *p <= 0x9f)) { return INT2FIX(_SJIS); } else if (0xfd <= *p && *p <= 0xfe) { return INT2FIX(_EUC); } } INCR; } } else if (*p <= 0x9f) { return INT2FIX(_SJIS); } } else if (0xf0 <= *p && *p <= 0xfe) { return INT2FIX(_EUC); } else if (0xe0 <= *p && *p <= 0xef) { INCR; if ((0x40 <= *p && *p <= 0x7e) || (0x80 <= *p && *p <= 0xa0)) { return INT2FIX(_SJIS); } if (0xfd <= *p && *p <= 0xfe) { return INT2FIX(_EUC); } } INCR; } return INT2FIX(_UNKNOWN); } /* * call-seq: * NKF.guess2(str) -> integer * * Returns guessed encoding of _str_ as integer by nkf routine. * * case NKF.guess(input) * when NKF::ASCII * "ASCII" * when NKF::JIS * "ISO-2022-JP" * when NKF::SJIS * "Shift_JIS" * when NKF::EUC * "EUC-JP" * when NKF::UTF8 * "UTF-8" * when NKF::UTF16 * "UTF-16" * when NKF::UNKNOWN * "UNKNOWN" * when NKF::BINARY * "BINARY" * end */ static VALUE rb_nkf_guess2(obj, src) VALUE obj, src; { int code = _BINARY; reinit(); input_ctr = 0; StringValue(src); input = (unsigned char *)RSTRING(src)->ptr; i_len = RSTRING(src)->len; if(x0201_f == WISH_TRUE) x0201_f = ((!iso2022jp_f)? TRUE : NO_X0201); guess_f = TRUE; kanji_convert( NULL ); guess_f = FALSE; if (!is_inputcode_mixed) { if (strcmp(input_codename, "") == 0) { code = _ASCII; } else if (strcmp(input_codename, "ISO-2022-JP") == 0) { code = _JIS; } else if (strcmp(input_codename, "EUC-JP") == 0) { code = _EUC; } else if (strcmp(input_codename, "Shift_JIS") == 0) { code = _SJIS; } else if (strcmp(input_codename, "UTF-8") == 0) { code = _UTF8; } else if (strcmp(input_codename, "UTF-16") == 0) { code = _UTF16; } else if (strlen(input_codename) > 0) { code = _UNKNOWN; } } return INT2FIX( code ); } /* * NKF - Ruby extension for Network Kanji Filter * * == Description * * This is a Ruby Extension version of nkf (Netowrk Kanji Filter). * It converts the first argument and return converted result. Conversion * details are specified by flags as the first argument. * * *Nkf* is a yet another kanji code converter among networks, hosts and terminals. * It converts input kanji code to designated kanji code * such as ISO-2022-JP, Shift_JIS, EUC-JP, UTF-8 or UTF-16. * * One of the most unique faculty of *nkf* is the guess of the input kanji encodings. * It currently recognizes ISO-2022-JP, Shift_JIS, EUC-JP, UTF-8 and UTF-16. * So users needn't set the input kanji code explicitly. * * By default, X0201 kana is converted into X0208 kana. * For X0201 kana, SO/SI, SSO and ESC-(-I methods are supported. * For automatic code detection, nkf assumes no X0201 kana in Shift_JIS. * To accept X0201 in Shift_JIS, use -X, -x or -S. * * == Flags * * === -b -u * * Output is buffered (DEFAULT), Output is unbuffered. * * === -j -s -e -w -w16 * * Output code is ISO-2022-JP (7bit JIS), Shift_JIS, EUC-JP, * UTF-8N, UTF-16BE. * Without this option and compile option, ISO-2022-JP is assumed. * * === -J -S -E -W -W16 * * Input assumption is JIS 7 bit, Shift_JIS, EUC-JP, * UTF-8, UTF-16LE. * * ==== -J * * Assume JIS input. It also accepts EUC-JP. * This is the default. This flag does not exclude Shift_JIS. * * ==== -S * * Assume Shift_JIS and X0201 kana input. It also accepts JIS. * EUC-JP is recognized as X0201 kana. Without -x flag, * X0201 kana (halfwidth kana) is converted into X0208. * * ==== -E * * Assume EUC-JP input. It also accepts JIS. * Same as -J. * * === -t * * No conversion. * * === -i_ * * Output sequence to designate JIS-kanji. (DEFAULT B) * * === -o_ * * Output sequence to designate ASCII. (DEFAULT B) * * === -r * * {de/en}crypt ROT13/47 * * === -h[123] --hiragana --katakana --katakana-hiragana * * [-h1 --hiragana] Katakana to Hiragana conversion. * * [-h2 --katakana] Hiragana to Katakana conversion. * * [-h3 --katakana-hiragana] Katakana to Hiragana and Hiragana to Katakana conversion. * * === -T * * Text mode output (MS-DOS) * * === -l * * ISO8859-1 (Latin-1) support * * === -f[m [- n]] * * Folding on m length with n margin in a line. * Without this option, fold length is 60 and fold margin is 10. * * === -F * * New line preserving line folding. * * === -Z[0-3] * * Convert X0208 alphabet (Fullwidth Alphabets) to ASCII. * * [-Z -Z0] Convert X0208 alphabet to ASCII. * * [-Z1] Converts X0208 kankaku to single ASCII space. * * [-Z2] Converts X0208 kankaku to double ASCII spaces. * * [-Z3] Replacing Fullwidth >, <, ", & into '>', '<', '"', '&' as in HTML. * * === -X -x * * Assume X0201 kana in MS-Kanji. * With -X or without this option, X0201 is converted into X0208 Kana. * With -x, try to preserve X0208 kana and do not convert X0201 kana to X0208. * In JIS output, ESC-(-I is used. In EUC output, SSO is used. * * === -B[0-2] * * Assume broken JIS-Kanji input, which lost ESC. * Useful when your site is using old B-News Nihongo patch. * * [-B1] allows any char after ESC-( or ESC-$. * * [-B2] forces ASCII after NL. * * === -I * * Replacing non iso-2022-jp char into a geta character * (substitute character in Japanese). * * === -d -c * * Delete \r in line feed, Add \r in line feed. * * === -m[BQN0] * * MIME ISO-2022-JP/ISO8859-1 decode. (DEFAULT) * To see ISO8859-1 (Latin-1) -l is necessary. * * [-mB] Decode MIME base64 encoded stream. Remove header or other part before * conversion. * * [-mQ] Decode MIME quoted stream. '_' in quoted stream is converted to space. * * [-mN] Non-strict decoding. * It allows line break in the middle of the base64 encoding. * * [-m0] No MIME decode. * * === -M * * MIME encode. Header style. All ASCII code and control characters are intact. * Kanji conversion is performed before encoding, so this cannot be used as a picture encoder. * * [-MB] MIME encode Base64 stream. * * [-MQ] Perfome quoted encoding. * * === -l * * Input and output code is ISO8859-1 (Latin-1) and ISO-2022-JP. * -s, -e and -x are not compatible with this option. * * === -L[uwm] * * new line mode * Without this option, nkf doesn't convert line breaks. * * [-Lu] unix (LF) * * [-Lw] windows (CRLF) * * [-Lm] mac (CR) * * === --fj --unix --mac --msdos --windows * * convert for these system * * === --jis --euc --sjis --mime --base64 * * convert for named code * * === --jis-input --euc-input --sjis-input --mime-input --base64-input * * assume input system * * === --ic=input codeset --oc=output codeset * * Set the input or output codeset. * NKF supports following codesets and those codeset name are case insensitive. * * [ISO-2022-JP] a.k.a. RFC1468, 7bit JIS, JUNET * * [EUC-JP (eucJP-nkf)] a.k.a. AT&T JIS, Japanese EUC, UJIS * * [eucJP-ascii] a.k.a. x-eucjp-open-19970715-ascii * * [eucJP-ms] a.k.a. x-eucjp-open-19970715-ms * * [CP51932] Microsoft Version of EUC-JP. * * [Shift_JIS] SJIS, MS-Kanji * * [CP932] a.k.a. Windows-31J * * [UTF-8] same as UTF-8N * * [UTF-8N] UTF-8 without BOM * * [UTF-8-BOM] UTF-8 with BOM * * [UTF-16] same as UTF-16BE * * [UTF-16BE] UTF-16 Big Endian without BOM * * [UTF-16BE-BOM] UTF-16 Big Endian with BOM * * [UTF-16LE] UTF-16 Little Endian without BOM * * [UTF-16LE-BOM] UTF-16 Little Endian with BOM * * [UTF8-MAC] NKDed UTF-8, a.k.a. UTF8-NFD (input only) * * === --fb-{skip, html, xml, perl, java, subchar} * * Specify the way that nkf handles unassigned characters. * Without this option, --fb-skip is assumed. * * === --prefix= escape character target character .. * * When nkf converts to Shift_JIS, * nkf adds a specified escape character to specified 2nd byte of Shift_JIS characters. * 1st byte of argument is the escape character and following bytes are target characters. * * === --disable-cp932ext * * Handle the characters extended in CP932 as unassigned characters. * * === --cap-input * * Decode hex encoded characters. * * === --url-input * * Unescape percent escaped characters. * * === -- * * Ignore rest of -option. */ void Init_nkf() { /* hoge */ VALUE mKconv = rb_define_module("NKF"); /* hoge */ rb_define_module_function(mKconv, "nkf", rb_nkf_kconv, 2); rb_define_module_function(mKconv, "guess1", rb_nkf_guess1, 1); rb_define_module_function(mKconv, "guess2", rb_nkf_guess2, 1); rb_define_alias(mKconv, "guess", "guess2"); rb_define_alias(rb_singleton_class(mKconv), "guess", "guess2"); /* Auto-Detect */ rb_define_const(mKconv, "AUTO", INT2FIX(_AUTO)); /* ISO-2022-JP */ rb_define_const(mKconv, "JIS", INT2FIX(_JIS)); /* EUC-JP */ rb_define_const(mKconv, "EUC", INT2FIX(_EUC)); /* Shift_JIS */ rb_define_const(mKconv, "SJIS", INT2FIX(_SJIS)); /* BINARY */ rb_define_const(mKconv, "BINARY", INT2FIX(_BINARY)); /* No conversion */ rb_define_const(mKconv, "NOCONV", INT2FIX(_NOCONV)); /* ASCII */ rb_define_const(mKconv, "ASCII", INT2FIX(_ASCII)); /* UTF-8 */ rb_define_const(mKconv, "UTF8", INT2FIX(_UTF8)); /* UTF-16 */ rb_define_const(mKconv, "UTF16", INT2FIX(_UTF16)); /* UTF-32 */ rb_define_const(mKconv, "UTF32", INT2FIX(_UTF32)); /* UNKNOWN */ rb_define_const(mKconv, "UNKNOWN", INT2FIX(_UNKNOWN)); /* Full version string of nkf */ rb_define_const(mKconv, "VERSION", rb_str_new2(RUBY_NKF_VERSION)); /* Version of nkf */ rb_define_const(mKconv, "NKF_VERSION", rb_str_new2(NKF_VERSION)); /* Release date of nkf */ rb_define_const(mKconv, "NKF_RELEASE_DATE", rb_str_new2(NKF_RELEASE_DATE)); } ================================================ FILE: ext/openssl/.cvsignore ================================================ GNUmakefile Makefile mkmf.log dep extconf.h ================================================ FILE: ext/openssl/extconf.rb ================================================ =begin = $RCSfile$ -- Generator for Makefile = Info 'OpenSSL for Ruby 2' project Copyright (C) 2002 Michal Rokos All rights reserved. = Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) = Version $Id$ =end require "mkmf" dir_config("openssl") dir_config("kerberos") message "=== OpenSSL for Ruby configurator ===\n" ## # Adds -Wall -DOSSL_DEBUG for compilation and some more targets when GCC is used # To turn it on, use: --with-debug or --enable-debug # if with_config("debug") or enable_config("debug") $defs.push("-DOSSL_DEBUG") unless $defs.include? "-DOSSL_DEBUG" if /gcc/ =~ CONFIG["CC"] $CPPFLAGS += " -Wall" unless $CPPFLAGS.split.include? "-Wall" end end message "=== Checking for system dependent stuff... ===\n" have_library("nsl", "t_open") have_library("socket", "socket") have_header("assert.h") message "=== Checking for required stuff... ===\n" if $mingw have_library("wsock32") have_library("gdi32") end result = have_header("openssl/ssl.h") result &&= %w[crypto libeay32].any? {|lib| have_library(lib, "OpenSSL_add_all_digests")} result &&= %w[ssl ssleay32].any? {|lib| have_library(lib, "SSL_library_init")} if !result unless pkg_config("openssl") and have_header("openssl/ssl.h") message "=== Checking for required stuff failed. ===\n" message "Makefile wasn't created. Fix the errors above.\n" exit 1 end end unless have_header("openssl/conf_api.h") message "OpenSSL 0.9.6 or later required.\n" exit 1 end %w"rb_str_set_len rb_block_call".each {|func| have_func(func, "ruby.h")} message "=== Checking for OpenSSL features... ===\n" have_func("ERR_peek_last_error") have_func("BN_mod_add") have_func("BN_mod_sqr") have_func("BN_mod_sub") have_func("BN_pseudo_rand_range") have_func("BN_rand_range") have_func("CONF_get1_default_config_file") have_func("EVP_CIPHER_CTX_copy") have_func("EVP_CIPHER_CTX_set_padding") have_func("EVP_CipherFinal_ex") have_func("EVP_CipherInit_ex") have_func("EVP_DigestFinal_ex") have_func("EVP_DigestInit_ex") have_func("EVP_MD_CTX_cleanup") have_func("EVP_MD_CTX_create") have_func("EVP_MD_CTX_destroy") have_func("EVP_MD_CTX_init") have_func("HMAC_CTX_cleanup") have_func("HMAC_CTX_copy") have_func("HMAC_CTX_init") have_func("PEM_def_callback") have_func("PKCS5_PBKDF2_HMAC") have_func("PKCS5_PBKDF2_HMAC_SHA1") have_func("X509V3_set_nconf") have_func("X509V3_EXT_nconf_nid") have_func("X509_CRL_add0_revoked") have_func("X509_CRL_set_issuer_name") have_func("X509_CRL_set_version") have_func("X509_CRL_sort") have_func("X509_STORE_get_ex_data") have_func("X509_STORE_set_ex_data") have_func("OBJ_NAME_do_all_sorted") have_func("SSL_SESSION_get_id") have_func("OPENSSL_cleanse") if try_compile("#define FOO(a, ...) foo(a, ##__VA_ARGS__)\n int x(){FOO(1);FOO(1,2);FOO(1,2,3);}\n") $defs.push("-DHAVE_VA_ARGS_MACRO") end if have_header("openssl/engine.h") have_func("ENGINE_add") have_func("ENGINE_load_builtin_engines") have_func("ENGINE_load_openbsd_dev_crypto") have_func("ENGINE_get_digest") have_func("ENGINE_get_cipher") have_func("ENGINE_cleanup") end if try_compile(< #if OPENSSL_VERSION_NUMBER < 0x00907000L # error "OpenSSL version is less than 0.9.7." #endif SRC have_header("openssl/ocsp.h") end have_struct_member("EVP_CIPHER_CTX", "flags", "openssl/evp.h") have_struct_member("EVP_CIPHER_CTX", "engine", "openssl/evp.h") have_struct_member("X509_ATTRIBUTE", "single", "openssl/x509.h") message "=== Checking done. ===\n" create_header create_makefile("openssl") message "Done.\n" ================================================ FILE: ext/openssl/lib/net/ftptls.rb ================================================ =begin = $RCSfile$ -- SSL/TLS enhancement for Net::HTTP. = Info 'OpenSSL for Ruby 2' project Copyright (C) 2003 Blaz Grilc All rights reserved. = Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) = Requirements = Version $Id$ = Notes Tested on FreeBSD 5-CURRENT and 4-STABLE - ruby 1.6.8 (2003-01-17) [i386-freebsd5] - OpenSSL 0.9.7a Feb 19 2003 - ruby-openssl-0.2.0.p0 tested on ftp server: glftpd 1.30 =end require 'socket' require 'openssl' require 'net/ftp' module Net class FTPTLS < FTP def connect(host, port=FTP_PORT) @hostname = host super end def login(user = "anonymous", passwd = nil, acct = nil) store = OpenSSL::X509::Store.new store.set_default_paths ctx = OpenSSL::SSL::SSLContext.new('SSLv23') ctx.cert_store = store ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER ctx.key = nil ctx.cert = nil voidcmd("AUTH TLS") @sock = OpenSSL::SSL::SSLSocket.new(@sock, ctx) @sock.connect @sock.post_connection_check(@hostname) super(user, passwd, acct) voidcmd("PBSZ 0") end end end ================================================ FILE: ext/openssl/lib/net/telnets.rb ================================================ =begin = $RCSfile$ -- SSL/TLS enhancement for Net::Telnet. = Info 'OpenSSL for Ruby 2' project Copyright (C) 2001 GOTOU YUUZOU All rights reserved. = Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) = Version $Id$ 2001/11/06: Contiributed to Ruby/OpenSSL project. == class Net::Telnet This class will initiate SSL/TLS session automaticaly if the server sent OPT_STARTTLS. Some options are added for SSL/TLS. host = Net::Telnet::new({ "Host" => "localhost", "Port" => "telnets", ## follows are new options. 'CertFile' => "user.crt", 'KeyFile' => "user.key", 'CAFile' => "/some/where/certs/casert.pem", 'CAPath' => "/some/where/caserts", 'VerifyMode' => SSL::VERIFY_PEER, 'VerifyCallback' => verify_proc }) Or, the new options ('Cert', 'Key' and 'CACert') are available from Michal Rokos's OpenSSL module. cert_data = File.open("user.crt"){|io| io.read } pkey_data = File.open("user.key"){|io| io.read } cacert_data = File.open("your_ca.pem"){|io| io.read } host = Net::Telnet::new({ "Host" => "localhost", "Port" => "telnets", 'Cert' => OpenSSL::X509::Certificate.new(cert_data) 'Key' => OpenSSL::PKey::RSA.new(pkey_data) 'CACert' => OpenSSL::X509::Certificate.new(cacert_data) 'CAFile' => "/some/where/certs/casert.pem", 'CAPath' => "/some/where/caserts", 'VerifyMode' => SSL::VERIFY_PEER, 'VerifyCallback' => verify_proc }) This class is expected to be a superset of usual Net::Telnet. =end require "net/telnet" require "openssl" module Net class Telnet attr_reader :ssl OPT_STARTTLS = 46.chr # "\056" # "\x2e" # Start TLS TLS_FOLLOWS = 1.chr # "\001" # "\x01" # FOLLOWS (for STARTTLS) alias preprocess_orig preprocess def ssl?; @ssl; end def preprocess(string) # combine CR+NULL into CR string = string.gsub(/#{CR}#{NULL}/no, CR) if @options["Telnetmode"] # combine EOL into "\n" string = string.gsub(/#{EOL}/no, "\n") unless @options["Binmode"] string.gsub(/#{IAC}( [#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]| [#{DO}#{DONT}#{WILL}#{WONT}][#{OPT_BINARY}-#{OPT_EXOPL}]| #{SB}[#{OPT_BINARY}-#{OPT_EXOPL}] (#{IAC}#{IAC}|[^#{IAC}])+#{IAC}#{SE} )/xno) do if IAC == $1 # handle escaped IAC characters IAC elsif AYT == $1 # respond to "IAC AYT" (are you there) self.write("nobody here but us pigeons" + EOL) '' elsif DO[0] == $1[0] # respond to "IAC DO x" if OPT_BINARY[0] == $1[1] @telnet_option["BINARY"] = true self.write(IAC + WILL + OPT_BINARY) elsif OPT_STARTTLS[0] == $1[1] self.write(IAC + WILL + OPT_STARTTLS) self.write(IAC + SB + OPT_STARTTLS + TLS_FOLLOWS + IAC + SE) else self.write(IAC + WONT + $1[1..1]) end '' elsif DONT[0] == $1[0] # respond to "IAC DON'T x" with "IAC WON'T x" self.write(IAC + WONT + $1[1..1]) '' elsif WILL[0] == $1[0] # respond to "IAC WILL x" if OPT_BINARY[0] == $1[1] self.write(IAC + DO + OPT_BINARY) elsif OPT_ECHO[0] == $1[1] self.write(IAC + DO + OPT_ECHO) elsif OPT_SGA[0] == $1[1] @telnet_option["SGA"] = true self.write(IAC + DO + OPT_SGA) else self.write(IAC + DONT + $1[1..1]) end '' elsif WONT[0] == $1[0] # respond to "IAC WON'T x" if OPT_ECHO[0] == $1[1] self.write(IAC + DONT + OPT_ECHO) elsif OPT_SGA[0] == $1[1] @telnet_option["SGA"] = false self.write(IAC + DONT + OPT_SGA) else self.write(IAC + DONT + $1[1..1]) end '' elsif SB[0] == $1[0] # respond to "IAC SB xxx IAC SE" if OPT_STARTTLS[0] == $1[1] && TLS_FOLLOWS[0] == $2[0] @sock = OpenSSL::SSL::SSLSocket.new(@sock) @sock.cert = @options['Cert'] unless @sock.cert @sock.key = @options['Key'] unless @sock.key @sock.ca_cert = @options['CACert'] @sock.ca_file = @options['CAFile'] @sock.ca_path = @options['CAPath'] @sock.timeout = @options['Timeout'] @sock.verify_mode = @options['VerifyMode'] @sock.verify_callback = @options['VerifyCallback'] @sock.verify_depth = @options['VerifyDepth'] @sock.connect if @options['VerifyMode'] != OpenSSL::SSL::VERIFY_NONE @sock.post_connection_check(@options['Host']) end @ssl = true end '' else '' end end end # preprocess alias waitfor_org waitfor def waitfor(options) time_out = @options["Timeout"] waittime = @options["Waittime"] if options.kind_of?(Hash) prompt = if options.has_key?("Match") options["Match"] elsif options.has_key?("Prompt") options["Prompt"] elsif options.has_key?("String") Regexp.new( Regexp.quote(options["String"]) ) end time_out = options["Timeout"] if options.has_key?("Timeout") waittime = options["Waittime"] if options.has_key?("Waittime") else prompt = options end if time_out == false time_out = nil end line = '' buf = '' @rest = '' unless @rest until(prompt === line and not IO::select([@sock], nil, nil, waittime)) unless IO::select([@sock], nil, nil, time_out) raise TimeoutError, "timed-out; wait for the next data" end begin c = @rest + @sock.sysread(1024 * 1024) @dumplog.log_dump('<', c) if @options.has_key?("Dump_log") if @options["Telnetmode"] pos = 0 catch(:next){ while true case c[pos] when IAC[0] case c[pos+1] when DO[0], DONT[0], WILL[0], WONT[0] throw :next unless c[pos+2] pos += 3 when SB[0] ret = detect_sub_negotiation(c, pos) throw :next unless ret pos = ret when nil throw :next else pos += 2 end when nil throw :next else pos += 1 end end } buf = preprocess(c[0...pos]) @rest = c[pos..-1] end @log.print(buf) if @options.has_key?("Output_log") line.concat(buf) yield buf if block_given? rescue EOFError # End of file reached if line == '' line = nil yield nil if block_given? end break end end line end private def detect_sub_negotiation(data, pos) return nil if data.length < pos+6 # IAC SB x param IAC SE pos += 3 while true case data[pos] when IAC[0] if data[pos+1] == SE[0] pos += 2 return pos else pos += 2 end when nil return nil else pos += 1 end end end end end ================================================ FILE: ext/openssl/lib/openssl/bn.rb ================================================ =begin = $RCSfile$ -- Ruby-space definitions that completes C-space funcs for BN = Info 'OpenSSL for Ruby 2' project Copyright (C) 2002 Michal Rokos All rights reserved. = Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) = Version $Id$ =end ## # Should we care what if somebody require this file directly? #require 'openssl' module OpenSSL class BN include Comparable end # BN end # OpenSSL ## # Add double dispatch to Integer # class Integer def to_bn OpenSSL::BN::new(self) end end # Integer ================================================ FILE: ext/openssl/lib/openssl/buffering.rb ================================================ =begin = $RCSfile$ -- Buffering mix-in module. = Info 'OpenSSL for Ruby 2' project Copyright (C) 2001 GOTOU YUUZOU All rights reserved. = Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) = Version $Id$ =end module Buffering include Enumerable attr_accessor :sync BLOCK_SIZE = 1024*16 def initialize(*args) @eof = false @rbuffer = "" @sync = @io.sync end # # for reading. # private def fill_rbuff begin @rbuffer << self.sysread(BLOCK_SIZE) rescue Errno::EAGAIN retry rescue EOFError @eof = true end end def consume_rbuff(size=nil) if @rbuffer.empty? nil else size = @rbuffer.size unless size ret = @rbuffer[0, size] @rbuffer[0, size] = "" ret end end public def read(size=nil, buf=nil) if size == 0 if buf buf.clear else buf = "" end return @eof ? nil : buf end until @eof break if size && size <= @rbuffer.size fill_rbuff end ret = consume_rbuff(size) || "" if buf buf.replace(ret) ret = buf end (size && ret.empty?) ? nil : ret end def readpartial(maxlen, buf=nil) if maxlen == 0 if buf buf.clear else buf = "" end return @eof ? nil : buf end if @rbuffer.empty? begin return sysread(maxlen, buf) rescue Errno::EAGAIN retry end end ret = consume_rbuff(maxlen) if buf buf.replace(ret) ret = buf end raise EOFError if ret.empty? ret end def gets(eol=$/) idx = @rbuffer.index(eol) until @eof break if idx fill_rbuff idx = @rbuffer.index(eol) end if eol.is_a?(Regexp) size = idx ? idx+$&.size : nil else size = idx ? idx+eol.size : nil end consume_rbuff(size) end def each(eol=$/) while line = self.gets(eol) yield line end end alias each_line each def readlines(eol=$/) ary = [] while line = self.gets(eol) ary << line end ary end def readline(eol=$/) raise EOFError if eof? gets(eol) end def getc c = read(1) c ? c[0] : nil end def each_byte while c = getc yield(c) end end def readchar raise EOFError if eof? getc end def ungetc(c) @rbuffer[0,0] = c.chr end def eof? fill_rbuff if !@eof && @rbuffer.empty? @eof && @rbuffer.empty? end alias eof eof? # # for writing. # private def do_write(s) @wbuffer = "" unless defined? @wbuffer @wbuffer << s @sync ||= false if @sync or @wbuffer.size > BLOCK_SIZE or idx = @wbuffer.rindex($/) remain = idx ? idx + $/.size : @wbuffer.length nwritten = 0 while remain > 0 str = @wbuffer[nwritten,remain] begin nwrote = syswrite(str) rescue Errno::EAGAIN retry end remain -= nwrote nwritten += nwrote end @wbuffer[0,nwritten] = "" end end public def write(s) do_write(s) s.length end def << (s) do_write(s) self end def puts(*args) s = "" if args.empty? s << "\n" end args.each{|arg| s << arg.to_s if $/ && /\n\z/ !~ s s << "\n" end } do_write(s) nil end def print(*args) s = "" args.each{ |arg| s << arg.to_s } do_write(s) nil end def printf(s, *args) do_write(s % args) nil end def flush osync = @sync @sync = true do_write "" @sync = osync end def close flush rescue nil sysclose end end ================================================ FILE: ext/openssl/lib/openssl/cipher.rb ================================================ =begin = $RCSfile$ -- Ruby-space predefined Cipher subclasses = Info 'OpenSSL for Ruby 2' project Copyright (C) 2002 Michal Rokos All rights reserved. = Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) = Version $Id$ =end ## # Should we care what if somebody require this file directly? #require 'openssl' module OpenSSL class Cipher %w(AES CAST5 BF DES IDEA RC2 RC4 RC5).each{|name| klass = Class.new(Cipher){ define_method(:initialize){|*args| cipher_name = args.inject(name){|n, arg| "#{n}-#{arg}" } super(cipher_name) } } const_set(name, klass) } %w(128 192 256).each{|keylen| klass = Class.new(Cipher){ define_method(:initialize){|mode| mode ||= "CBC" cipher_name = "AES-#{keylen}-#{mode}" super(cipher_name) } } const_set("AES#{keylen}", klass) } # Generate, set, and return a random key. # You must call cipher.encrypt or cipher.decrypt before calling this method. def random_key str = OpenSSL::Random.random_bytes(self.key_len) self.key = str return str end # Generate, set, and return a random iv. # You must call cipher.encrypt or cipher.decrypt before calling this method. def random_iv str = OpenSSL::Random.random_bytes(self.iv_len) self.iv = str return str end # This class is only provided for backwards compatibility. Use OpenSSL::Digest in the future. class Cipher < Cipher # add warning end end # Cipher end # OpenSSL ================================================ FILE: ext/openssl/lib/openssl/digest.rb ================================================ =begin = $RCSfile$ -- Ruby-space predefined Digest subclasses = Info 'OpenSSL for Ruby 2' project Copyright (C) 2002 Michal Rokos All rights reserved. = Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) = Version $Id$ =end ## # Should we care what if somebody require this file directly? #require 'openssl' module OpenSSL class Digest alg = %w(DSS DSS1 MD2 MD4 MD5 MDC2 RIPEMD160 SHA SHA1) if OPENSSL_VERSION_NUMBER > 0x00908000 alg += %w(SHA224 SHA256 SHA384 SHA512) end def self.digest(name, data) super(data, name) end alg.each{|name| klass = Class.new(Digest){ define_method(:initialize){|*data| if data.length > 1 raise ArgumentError, "wrong number of arguments (#{data.length} for 1)" end super(name, data.first) } } singleton = (class < All rights reserved. = Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) = Version $Id$ =end require "openssl" require "openssl/buffering" require "fcntl" module OpenSSL module SSL class SSLContext DEFAULT_PARAMS = { :ssl_version => "SSLv23", :verify_mode => OpenSSL::SSL::VERIFY_PEER, :ciphers => "ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW", :options => OpenSSL::SSL::OP_ALL, } DEFAULT_CERT_STORE = OpenSSL::X509::Store.new DEFAULT_CERT_STORE.set_default_paths if defined?(OpenSSL::X509::V_FLAG_CRL_CHECK_ALL) DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL end def set_params(params={}) params = DEFAULT_PARAMS.merge(params) self.ssl_version = params.delete(:ssl_version) params.each{|name, value| self.__send__("#{name}=", value) } if self.verify_mode != OpenSSL::SSL::VERIFY_NONE unless self.ca_file or self.ca_path or self.cert_store self.cert_store = DEFAULT_CERT_STORE end end return params end end module SocketForwarder def addr to_io.addr end def peeraddr to_io.peeraddr end def setsockopt(level, optname, optval) to_io.setsockopt(level, optname, optval) end def getsockopt(level, optname) to_io.getsockopt(level, optname) end def fcntl(*args) to_io.fcntl(*args) end def closed? to_io.closed? end def do_not_reverse_lookup=(flag) to_io.do_not_reverse_lookup = flag end end module Nonblock def initialize(*args) flag = File::NONBLOCK flag |= @io.fcntl(Fcntl::F_GETFL) if defined?(Fcntl::F_GETFL) @io.fcntl(Fcntl::F_SETFL, flag) super end end def verify_certificate_identity(cert, hostname) should_verify_common_name = true cert.extensions.each{|ext| next if ext.oid != "subjectAltName" ext.value.split(/,\s+/).each{|general_name| if /\ADNS:(.*)/ =~ general_name should_verify_common_name = false reg = Regexp.escape($1).gsub(/\\\*/, "[^.]+") return true if /\A#{reg}\z/i =~ hostname elsif /\AIP Address:(.*)/ =~ general_name should_verify_common_name = false return true if $1 == hostname end } } if should_verify_common_name cert.subject.to_a.each{|oid, value| if oid == "CN" reg = Regexp.escape(value).gsub(/\\\*/, "[^.]+") return true if /\A#{reg}\z/i =~ hostname end } end return false end module_function :verify_certificate_identity class SSLSocket include Buffering include SocketForwarder include Nonblock def post_connection_check(hostname) unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname) raise SSLError, "hostname was not match with the server certificate" end return true end def session SSL::Session.new(self) rescue SSL::Session::SessionError nil end end class SSLServer include SocketForwarder attr_accessor :start_immediately def initialize(svr, ctx) @svr = svr @ctx = ctx unless ctx.session_id_context session_id = OpenSSL::Digest::MD5.hexdigest($0) @ctx.session_id_context = session_id end @start_immediately = true end def to_io @svr end def listen(backlog=5) @svr.listen(backlog) end def shutdown(how=Socket::SHUT_RDWR) @svr.shutdown(how) end def accept sock = @svr.accept begin ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx) ssl.sync_close = true ssl.accept if @start_immediately ssl rescue SSLError => ex sock.close raise ex end end def close @svr.close end end end end ================================================ FILE: ext/openssl/lib/openssl/x509.rb ================================================ =begin = $RCSfile$ -- Ruby-space definitions that completes C-space funcs for X509 and subclasses = Info 'OpenSSL for Ruby 2' project Copyright (C) 2002 Michal Rokos All rights reserved. = Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) = Version $Id$ =end require "openssl" module OpenSSL module X509 class ExtensionFactory def create_extension(*arg) if arg.size > 1 create_ext(*arg) else send("create_ext_from_"+arg[0].class.name.downcase, arg[0]) end end def create_ext_from_array(ary) raise ExtensionError, "unexpected array form" if ary.size > 3 create_ext(ary[0], ary[1], ary[2]) end def create_ext_from_string(str) # "oid = critical, value" oid, value = str.split(/=/, 2) oid.strip! value.strip! create_ext(oid, value) end def create_ext_from_hash(hash) create_ext(hash["oid"], hash["value"], hash["critical"]) end end class Extension def to_s # "oid = critical, value" str = self.oid str << " = " str << "critical, " if self.critical? str << self.value.gsub(/\n/, ", ") end def to_h # {"oid"=>sn|ln, "value"=>value, "critical"=>true|false} {"oid"=>self.oid,"value"=>self.value,"critical"=>self.critical?} end def to_a [ self.oid, self.value, self.critical? ] end end class Name module RFC2253DN Special = ',=+<>#;' HexChar = /[0-9a-fA-F]/ HexPair = /#{HexChar}#{HexChar}/ HexString = /#{HexPair}+/ Pair = /\\(?:[#{Special}]|\\|"|#{HexPair})/ StringChar = /[^#{Special}\\"]/ QuoteChar = /[^\\"]/ AttributeType = /[a-zA-Z][0-9a-zA-Z]*|[0-9]+(?:\.[0-9]+)*/ AttributeValue = / (?!["#])((?:#{StringChar}|#{Pair})*)| \#(#{HexString})| "((?:#{QuoteChar}|#{Pair})*)" /x TypeAndValue = /\A(#{AttributeType})=#{AttributeValue}/ module_function def expand_pair(str) return nil unless str return str.gsub(Pair){|pair| case pair.size when 2 then pair[1,1] when 3 then Integer("0x#{pair[1,2]}").chr else raise OpenSSL::X509::NameError, "invalid pair: #{str}" end } end def expand_hexstring(str) return nil unless str der = str.gsub(HexPair){|hex| Integer("0x#{hex}").chr } a1 = OpenSSL::ASN1.decode(der) return a1.value, a1.tag end def expand_value(str1, str2, str3) value = expand_pair(str1) value, tag = expand_hexstring(str2) unless value value = expand_pair(str3) unless value return value, tag end def scan(dn) str = dn ary = [] while true if md = TypeAndValue.match(str) matched = md.to_s remain = md.post_match type = md[1] value, tag = expand_value(md[2], md[3], md[4]) rescue nil if value type_and_value = [type, value] type_and_value.push(tag) if tag ary.unshift(type_and_value) if remain.length > 2 && remain[0] == ?, str = remain[1..-1] next elsif remain.length > 2 && remain[0] == ?+ raise OpenSSL::X509::NameError, "multi-valued RDN is not supported: #{dn}" elsif remain.empty? break end end end msg_dn = dn[0, dn.length - str.length] + " =>" + str raise OpenSSL::X509::NameError, "malformed RDN: #{msg_dn}" end return ary end end class <md_ctx, &in->md_ctx); EVP_MD_CTX_copy(&out->i_ctx, &in->i_ctx); EVP_MD_CTX_copy(&out->o_ctx, &in->o_ctx); } #endif /* HAVE_HMAC_CTX_COPY */ #endif /* NO_HMAC */ #if !defined(HAVE_X509_STORE_SET_EX_DATA) int X509_STORE_set_ex_data(X509_STORE *str, int idx, void *data) { return CRYPTO_set_ex_data(&str->ex_data, idx, data); } void *X509_STORE_get_ex_data(X509_STORE *str, int idx) { return CRYPTO_get_ex_data(&str->ex_data, idx); } #endif #if !defined(HAVE_EVP_MD_CTX_CREATE) EVP_MD_CTX * EVP_MD_CTX_create(void) { EVP_MD_CTX *ctx = OPENSSL_malloc(sizeof(EVP_MD_CTX)); if (!ctx) return NULL; memset(ctx, 0, sizeof(EVP_MD_CTX)); return ctx; } #endif #if !defined(HAVE_EVP_MD_CTX_CLEANUP) int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx) { /* FIXME!!! */ memset(ctx, 0, sizeof(EVP_MD_CTX)); return 1; } #endif #if !defined(HAVE_EVP_MD_CTX_DESTROY) void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx) { EVP_MD_CTX_cleanup(ctx); OPENSSL_free(ctx); } #endif #if !defined(HAVE_EVP_MD_CTX_INIT) void EVP_MD_CTX_init(EVP_MD_CTX *ctx) { memset(ctx, 0, sizeof(EVP_MD_CTX)); } #endif #if !defined(HAVE_HMAC_CTX_INIT) void HMAC_CTX_init(HMAC_CTX *ctx) { EVP_MD_CTX_init(&ctx->i_ctx); EVP_MD_CTX_init(&ctx->o_ctx); EVP_MD_CTX_init(&ctx->md_ctx); } #endif #if !defined(HAVE_HMAC_CTX_CLEANUP) void HMAC_CTX_cleanup(HMAC_CTX *ctx) { EVP_MD_CTX_cleanup(&ctx->i_ctx); EVP_MD_CTX_cleanup(&ctx->o_ctx); EVP_MD_CTX_cleanup(&ctx->md_ctx); memset(ctx, 0, sizeof(HMAC_CTX)); } #endif #if !defined(HAVE_EVP_CIPHER_CTX_COPY) /* * this function does not exist in OpenSSL yet... or ever?. * a future version may break this function. * tested on 0.9.7d. */ int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, EVP_CIPHER_CTX *in) { memcpy(out, in, sizeof(EVP_CIPHER_CTX)); #if defined(HAVE_ENGINE_ADD) && defined(HAVE_ST_ENGINE) if (in->engine) ENGINE_add(out->engine); if (in->cipher_data) { out->cipher_data = OPENSSL_malloc(in->cipher->ctx_size); memcpy(out->cipher_data, in->cipher_data, in->cipher->ctx_size); } #endif return 1; } #endif #if !defined(HAVE_X509_CRL_SET_VERSION) int X509_CRL_set_version(X509_CRL *x, long version) { if (x == NULL || x->crl == NULL) return 0; if (x->crl->version == NULL) { x->crl->version = M_ASN1_INTEGER_new(); if (x->crl->version == NULL) return 0; } return ASN1_INTEGER_set(x->crl->version, version); } #endif #if !defined(HAVE_X509_CRL_SET_ISSUER_NAME) int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name) { if (x == NULL || x->crl == NULL) return 0; return X509_NAME_set(&x->crl->issuer, name); } #endif #if !defined(HAVE_X509_CRL_SORT) int X509_CRL_sort(X509_CRL *c) { int i; X509_REVOKED *r; /* sort the data so it will be written in serial * number order */ sk_X509_REVOKED_sort(c->crl->revoked); for (i=0; icrl->revoked); i++) { r=sk_X509_REVOKED_value(c->crl->revoked, i); r->sequence=i; } return 1; } #endif #if !defined(HAVE_X509_CRL_ADD0_REVOKED) static int OSSL_X509_REVOKED_cmp(const X509_REVOKED * const *a, const X509_REVOKED * const *b) { return(ASN1_STRING_cmp( (ASN1_STRING *)(*a)->serialNumber, (ASN1_STRING *)(*b)->serialNumber)); } int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev) { X509_CRL_INFO *inf; inf = crl->crl; if (!inf->revoked) inf->revoked = sk_X509_REVOKED_new(OSSL_X509_REVOKED_cmp); if (!inf->revoked || !sk_X509_REVOKED_push(inf->revoked, rev)) return 0; return 1; } #endif #if !defined(HAVE_BN_MOD_SQR) int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx) { if (!BN_sqr(r, (BIGNUM*)a, ctx)) return 0; return BN_mod(r, r, m, ctx); } #endif #if !defined(HAVE_BN_MOD_ADD) || !defined(HAVE_BN_MOD_SUB) int BN_nnmod(BIGNUM *r, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx) { if (!BN_mod(r,m,d,ctx)) return 0; if (!r->neg) return 1; return (d->neg ? BN_sub : BN_add)(r, r, d); } #endif #if !defined(HAVE_BN_MOD_ADD) int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx) { if (!BN_add(r, a, b)) return 0; return BN_nnmod(r, r, m, ctx); } #endif #if !defined(HAVE_BN_MOD_SUB) int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx) { if (!BN_sub(r, a, b)) return 0; return BN_nnmod(r, r, m, ctx); } #endif #if !defined(HAVE_BN_RAND_RANGE) || !defined(HAVE_BN_PSEUDO_RAND_RANGE) static int bn_rand_range(int pseudo, BIGNUM *r, BIGNUM *range) { int (*bn_rand)(BIGNUM *, int, int, int) = pseudo ? BN_pseudo_rand : BN_rand; int n; if (range->neg || BN_is_zero(range)) return 0; n = BN_num_bits(range); if (n == 1) { if (!BN_zero(r)) return 0; } else if (!BN_is_bit_set(range, n - 2) && !BN_is_bit_set(range, n - 3)) { do { if (!bn_rand(r, n + 1, -1, 0)) return 0; if (BN_cmp(r ,range) >= 0) { if (!BN_sub(r, r, range)) return 0; if (BN_cmp(r, range) >= 0) if (!BN_sub(r, r, range)) return 0; } } while (BN_cmp(r, range) >= 0); } else { do { if (!bn_rand(r, n, -1, 0)) return 0; } while (BN_cmp(r, range) >= 0); } return 1; } #endif #if !defined(HAVE_BN_RAND_RANGE) int BN_rand_range(BIGNUM *r, BIGNUM *range) { return bn_rand_range(0, r, range); } #endif #if !defined(HAVE_BN_PSEUDO_RAND_RANGE) int BN_pseudo_rand_range(BIGNUM *r, BIGNUM *range) { return bn_rand_range(1, r, range); } #endif #if !defined(HAVE_CONF_GET1_DEFAULT_CONFIG_FILE) #define OPENSSL_CONF "openssl.cnf" char * CONF_get1_default_config_file(void) { char *file; int len; file = getenv("OPENSSL_CONF"); if (file) return BUF_strdup(file); len = strlen(X509_get_default_cert_area()); #ifndef OPENSSL_SYS_VMS len++; #endif len += strlen(OPENSSL_CONF); file = OPENSSL_malloc(len + 1); if (!file) return NULL; strcpy(file,X509_get_default_cert_area()); #ifndef OPENSSL_SYS_VMS strcat(file,"/"); #endif strcat(file,OPENSSL_CONF); return file; } #endif #if !defined(HAVE_PEM_DEF_CALLBACK) #define OSSL_PASS_MIN_LENGTH 4 int PEM_def_callback(char *buf, int num, int w, void *key) { int i,j; const char *prompt; if (key) { i = strlen(key); i = (i > num) ? num : i; memcpy(buf, key, i); return i; } prompt = EVP_get_pw_prompt(); if (prompt == NULL) prompt = "Enter PEM pass phrase:"; for (;;) { i = EVP_read_pw_string(buf, num, prompt, w); if (i != 0) { memset(buf, 0, (unsigned int)num); return(-1); } j = strlen(buf); if (j < OSSL_PASS_MIN_LENGTH) { fprintf(stderr, "phrase is too short, needs to be at least %d chars\n", OSSL_PASS_MIN_LENGTH); } else break; } return j; } #endif ================================================ FILE: ext/openssl/openssl_missing.h ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(_OSSL_OPENSSL_MISSING_H_) #define _OSSL_OPENSSL_MISSING_H_ #if defined(__cplusplus) extern "C" { #endif #ifndef TYPEDEF_D2I_OF typedef char *d2i_of_void(); #endif /* * These functions are not included in headers of OPENSSL <= 0.9.6b */ #if !defined(PEM_read_bio_DSAPublicKey) # define PEM_read_bio_DSAPublicKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \ (char *(*)())d2i_DSAPublicKey,PEM_STRING_DSA_PUBLIC,bp,(char **)x,cb,u) #endif #if !defined(PEM_write_bio_DSAPublicKey) # define PEM_write_bio_DSAPublicKey(bp,x) \ PEM_ASN1_write_bio((int (*)())i2d_DSAPublicKey,\ PEM_STRING_DSA_PUBLIC,\ bp,(char *)x, NULL, NULL, 0, NULL, NULL) #endif #if !defined(DSAPrivateKey_dup) # define DSAPrivateKey_dup(dsa) (DSA *)ASN1_dup((int (*)())i2d_DSAPrivateKey, \ (char *(*)())d2i_DSAPrivateKey,(char *)dsa) #endif #if !defined(DSAPublicKey_dup) # define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup((int (*)())i2d_DSAPublicKey, \ (char *(*)())d2i_DSAPublicKey,(char *)dsa) #endif #if !defined(X509_REVOKED_dup) # define X509_REVOKED_dup(rev) (X509_REVOKED *)ASN1_dup((int (*)())i2d_X509_REVOKED, \ (char *(*)())d2i_X509_REVOKED, (char *)rev) #endif #if !defined(PKCS7_SIGNER_INFO_dup) # define PKCS7_SIGNER_INFO_dup(si) (PKCS7_SIGNER_INFO *)ASN1_dup((int (*)())i2d_PKCS7_SIGNER_INFO, \ (char *(*)())d2i_PKCS7_SIGNER_INFO, (char *)si) #endif #if !defined(PKCS7_RECIP_INFO_dup) # define PKCS7_RECIP_INFO_dup(ri) (PKCS7_RECIP_INFO *)ASN1_dup((int (*)())i2d_PKCS7_RECIP_INFO, \ (char *(*)())d2i_PKCS7_RECIP_INFO, (char *)ri) #endif #if !defined(HAVE_EVP_MD_CTX_INIT) void HMAC_CTX_init(HMAC_CTX *ctx); #endif #if !defined(HAVE_HMAC_CTX_COPY) void HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in); #endif #if !defined(HAVE_HMAC_CTX_CLEANUP) void HMAC_CTX_cleanup(HMAC_CTX *ctx); #endif #if !defined(HAVE_EVP_MD_CTX_CREATE) EVP_MD_CTX *EVP_MD_CTX_create(void); #endif #if !defined(HAVE_EVP_MD_CTX_INIT) void EVP_MD_CTX_init(EVP_MD_CTX *ctx); #endif #if !defined(HAVE_EVP_MD_CTX_CLEANUP) int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx); #endif #if !defined(HAVE_EVP_MD_CTX_DESTROY) void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx); #endif #if !defined(HAVE_EVP_CIPHER_CTX_COPY) int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, EVP_CIPHER_CTX *in); #endif #if !defined(HAVE_EVP_DIGESTINIT_EX) # define EVP_DigestInit_ex(ctx, md, engine) EVP_DigestInit(ctx, md) #endif #if !defined(HAVE_EVP_DIGESTFINAL_EX) # define EVP_DigestFinal_ex(ctx, buf, len) EVP_DigestFinal(ctx, buf, len) #endif #if !defined(HAVE_EVP_CIPHERINIT_EX) # define EVP_CipherInit_ex(ctx, type, impl, key, iv, enc) EVP_CipherInit(ctx, type, key, iv, enc) #endif #if !defined(HAVE_EVP_CIPHERFINAL_EX) # define EVP_CipherFinal_ex(ctx, outm, outl) EVP_CipherFinal(ctx, outm, outl) #endif #if !defined(EVP_CIPHER_name) # define EVP_CIPHER_name(e) OBJ_nid2sn(EVP_CIPHER_nid(e)) #endif #if !defined(EVP_MD_name) # define EVP_MD_name(e) OBJ_nid2sn(EVP_MD_type(e)) #endif #if !defined(HAVE_EVP_HMAC_INIT_EX) # define HMAC_Init_ex(ctx, key, len, digest, engine) HMAC_Init(ctx, key, len, digest) #endif #if !defined(PKCS7_is_detached) # define PKCS7_is_detached(p7) (PKCS7_type_is_signed(p7) && PKCS7_get_detached(p7)) #endif #if !defined(PKCS7_type_is_encrypted) # define PKCS7_type_is_encrypted(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_encrypted) #endif #if !defined(HAVE_OPENSSL_CLEANSE) #define OPENSSL_cleanse(p, l) memset(p, 0, l) #endif #if !defined(HAVE_X509_STORE_SET_EX_DATA) void *X509_STORE_get_ex_data(X509_STORE *str, int idx); int X509_STORE_set_ex_data(X509_STORE *str, int idx, void *data); #endif #if !defined(HAVE_X509_CRL_SET_VERSION) int X509_CRL_set_version(X509_CRL *x, long version); #endif #if !defined(HAVE_X509_CRL_SET_ISSUER_NAME) int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name); #endif #if !defined(HAVE_X509_CRL_SORT) int X509_CRL_sort(X509_CRL *c); #endif #if !defined(HAVE_X509_CRL_ADD0_REVOKED) int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev); #endif #if !defined(HAVE_BN_MOD_SQR) int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx); #endif #if !defined(HAVE_BN_MOD_ADD) int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx); #endif #if !defined(HAVE_BN_MOD_SUB) int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx); #endif #if !defined(HAVE_BN_RAND_RANGE) int BN_rand_range(BIGNUM *r, BIGNUM *range); #endif #if !defined(HAVE_BN_PSEUDO_RAND_RANGE) int BN_pseudo_rand_range(BIGNUM *r, BIGNUM *range); #endif #if !defined(HAVE_CONF_GET1_DEFAULT_CONFIG_FILE) char *CONF_get1_default_config_file(void); #endif #if !defined(HAVE_PEM_DEF_CALLBACK) int PEM_def_callback(char *buf, int num, int w, void *key); #endif #if defined(__cplusplus) } #endif #endif /* _OSSL_OPENSSL_MISSING_H_ */ ================================================ FILE: ext/openssl/ossl.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" #include /* for ossl_raise */ /* * String to HEXString conversion */ int string2hex(char *buf, int buf_len, char **hexbuf, int *hexbuf_len) { static const char hex[]="0123456789abcdef"; int i, len = 2 * buf_len; if (buf_len < 0 || len < buf_len) { /* PARANOIA? */ return -1; } if (!hexbuf) { /* if no buf, return calculated len */ if (hexbuf_len) { *hexbuf_len = len; } return len; } if (!(*hexbuf = OPENSSL_malloc(len + 1))) { return -1; } for (i = 0; i < buf_len; i++) { (*hexbuf)[2 * i] = hex[((unsigned char)buf[i]) >> 4]; (*hexbuf)[2 * i + 1] = hex[buf[i] & 0x0f]; } (*hexbuf)[2 * i] = '\0'; if (hexbuf_len) { *hexbuf_len = len; } return len; } /* * Data Conversion */ STACK_OF(X509) * ossl_x509_ary2sk0(VALUE ary) { STACK_OF(X509) *sk; VALUE val; X509 *x509; int i; Check_Type(ary, T_ARRAY); sk = sk_X509_new_null(); if (!sk) ossl_raise(eOSSLError, NULL); for (i = 0; i < RARRAY_LEN(ary); i++) { val = rb_ary_entry(ary, i); if (!rb_obj_is_kind_of(val, cX509Cert)) { sk_X509_pop_free(sk, X509_free); ossl_raise(eOSSLError, "object not X509 cert in array"); } x509 = DupX509CertPtr(val); /* NEED TO DUP */ sk_X509_push(sk, x509); } return sk; } STACK_OF(X509) * ossl_protect_x509_ary2sk(VALUE ary, int *status) { return (STACK_OF(X509)*)rb_protect((VALUE(*)_((VALUE)))ossl_x509_ary2sk0, ary, status); } STACK_OF(X509) * ossl_x509_ary2sk(VALUE ary) { STACK_OF(X509) *sk; int status = 0; sk = ossl_protect_x509_ary2sk(ary, &status); if(status) rb_jump_tag(status); return sk; } #define OSSL_IMPL_SK2ARY(name, type) \ VALUE \ ossl_##name##_sk2ary(STACK_OF(type) *sk) \ { \ type *t; \ int i, num; \ VALUE ary; \ \ if (!sk) { \ OSSL_Debug("empty sk!"); \ return Qnil; \ } \ num = sk_##type##_num(sk); \ if (num < 0) { \ OSSL_Debug("items in sk < -1???"); \ return rb_ary_new(); \ } \ ary = rb_ary_new2(num); \ \ for (i=0; i max_len) { rb_warning("password must be shorter then %d bytes", max_len-1); continue; } memcpy(buf, RSTRING_PTR(pass), len); break; } return len; } /* * Verify callback */ int ossl_verify_cb_idx; VALUE ossl_call_verify_cb_proc(struct ossl_verify_cb_args *args) { return rb_funcall(args->proc, rb_intern("call"), 2, args->preverify_ok, args->store_ctx); } int ossl_verify_cb(int ok, X509_STORE_CTX *ctx) { VALUE proc, rctx, ret; struct ossl_verify_cb_args args; int state = 0; proc = (VALUE)X509_STORE_CTX_get_ex_data(ctx, ossl_verify_cb_idx); if ((void*)proc == 0) proc = (VALUE)X509_STORE_get_ex_data(ctx->ctx, ossl_verify_cb_idx); if ((void*)proc == 0) return ok; if (!NIL_P(proc)) { rctx = rb_protect((VALUE(*)(VALUE))ossl_x509stctx_new, (VALUE)ctx, &state); ret = Qfalse; if (!state) { args.proc = proc; args.preverify_ok = ok ? Qtrue : Qfalse; args.store_ctx = rctx; ret = rb_ensure(ossl_call_verify_cb_proc, (VALUE)&args, ossl_x509stctx_clear_ptr, rctx); } if (ret == Qtrue) { X509_STORE_CTX_set_error(ctx, X509_V_OK); ok = 1; } else{ if (X509_STORE_CTX_get_error(ctx) == X509_V_OK) { X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED); } ok = 0; } } return ok; } /* * main module */ VALUE mOSSL; /* * OpenSSLError < StandardError */ VALUE eOSSLError; /* * Convert to DER string */ ID ossl_s_to_der; VALUE ossl_to_der(VALUE obj) { VALUE tmp; tmp = rb_funcall(obj, ossl_s_to_der, 0); StringValue(tmp); return tmp; } VALUE ossl_to_der_if_possible(VALUE obj) { if(rb_respond_to(obj, ossl_s_to_der)) return ossl_to_der(obj); return obj; } /* * Errors */ void ossl_raise(VALUE exc, const char *fmt, ...) { va_list args; char buf[BUFSIZ]; const char *msg; long e; int len = 0; #ifdef HAVE_ERR_PEEK_LAST_ERROR e = ERR_peek_last_error(); #else e = ERR_peek_error(); #endif if (fmt) { va_start(args, fmt); len = vsnprintf(buf, BUFSIZ, fmt, args); va_end(args); } if (len < BUFSIZ && e) { if (dOSSL == Qtrue) /* FULL INFO */ msg = ERR_error_string(e, NULL); else msg = ERR_reason_error_string(e); fmt = len ? ": %s" : "%s"; len += snprintf(buf+len, BUFSIZ-len, fmt, msg); } if (dOSSL == Qtrue){ /* show all errors on the stack */ while ((e = ERR_get_error()) != 0){ rb_warn("error on stack: %s", ERR_error_string(e, NULL)); } } ERR_clear_error(); if(len > BUFSIZ) len = strlen(buf); rb_exc_raise(rb_exc_new(exc, buf, len)); } /* * call-seq: * OpenSSL.errors -> [String...] * * See any remaining errors held in queue. * * Any errors you see here are probably due to a bug in ruby's OpenSSL implementation. */ VALUE ossl_get_errors() { VALUE ary; long e; ary = rb_ary_new(); while ((e = ERR_get_error()) != 0){ rb_ary_push(ary, rb_str_new2(ERR_error_string(e, NULL))); } return ary; } /* * Debug */ VALUE dOSSL; #if !defined(HAVE_VA_ARGS_MACRO) void ossl_debug(const char *fmt, ...) { va_list args; if (dOSSL == Qtrue) { fprintf(stderr, "OSSL_DEBUG: "); va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); fprintf(stderr, " [CONTEXT N/A]\n"); } } #endif /* * call-seq: * OpenSSL.debug -> true | false */ static VALUE ossl_debug_get(VALUE self) { return dOSSL; } /* * call-seq: * OpenSSL.debug = boolean -> boolean * * Turns on or off CRYPTO_MEM_CHECK. * Also shows some debugging message on stderr. */ static VALUE ossl_debug_set(VALUE self, VALUE val) { VALUE old = dOSSL; dOSSL = val; if (old != dOSSL) { if (dOSSL == Qtrue) { CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); fprintf(stderr, "OSSL_DEBUG: IS NOW ON!\n"); } else if (old == Qtrue) { CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF); fprintf(stderr, "OSSL_DEBUG: IS NOW OFF!\n"); } } return val; } /* * OSSL library init */ void Init_openssl() { /* * Init timezone info */ #if 0 tzset(); #endif /* * Init all digests, ciphers */ /* CRYPTO_malloc_init(); */ /* ENGINE_load_builtin_engines(); */ OpenSSL_add_ssl_algorithms(); OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); SSL_load_error_strings(); /* * FIXME: * On unload do: */ #if 0 CONF_modules_unload(1); destroy_ui_method(); EVP_cleanup(); ENGINE_cleanup(); CRYPTO_cleanup_all_ex_data(); ERR_remove_state(0); ERR_free_strings(); #endif /* * Init main module */ mOSSL = rb_define_module("OpenSSL"); /* * Constants */ rb_define_const(mOSSL, "VERSION", rb_str_new2(OSSL_VERSION)); rb_define_const(mOSSL, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT)); rb_define_const(mOSSL, "OPENSSL_VERSION_NUMBER", INT2NUM(OPENSSL_VERSION_NUMBER)); /* * Generic error, * common for all classes under OpenSSL module */ eOSSLError = rb_define_class_under(mOSSL,"OpenSSLError",rb_eStandardError); /* * Verify callback Proc index for ext-data */ if ((ossl_verify_cb_idx = X509_STORE_CTX_get_ex_new_index(0, "ossl_verify_cb_idx", 0, 0, 0)) < 0) ossl_raise(eOSSLError, "X509_STORE_CTX_get_ex_new_index"); /* * Init debug core */ dOSSL = Qfalse; rb_define_module_function(mOSSL, "debug", ossl_debug_get, 0); rb_define_module_function(mOSSL, "debug=", ossl_debug_set, 1); rb_define_module_function(mOSSL, "errors", ossl_get_errors, 0); /* * Get ID of to_der */ ossl_s_to_der = rb_intern("to_der"); /* * Init components */ Init_ossl_bn(); Init_ossl_cipher(); Init_ossl_config(); Init_ossl_digest(); Init_ossl_hmac(); Init_ossl_ns_spki(); Init_ossl_pkcs12(); Init_ossl_pkcs7(); Init_ossl_pkcs5(); Init_ossl_pkey(); Init_ossl_rand(); Init_ossl_ssl(); Init_ossl_x509(); Init_ossl_ocsp(); Init_ossl_engine(); Init_ossl_asn1(); } #if defined(OSSL_DEBUG) /* * Check if all symbols are OK with 'make LDSHARED=gcc all' */ int main(int argc, char *argv[], char *env[]) { return 0; } #endif /* OSSL_DEBUG */ ================================================ FILE: ext/openssl/ossl.h ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(_OSSL_H_) #define _OSSL_H_ #include RUBY_EXTCONF_H #if defined(__cplusplus) extern "C" { #endif #if 0 mOSSL = rb_define_module("OpenSSL"); mX509 = rb_define_module_under(mOSSL, "X509"); #endif /* * OpenSSL has defined RFILE and Ruby has defined RFILE - so undef it! */ #if defined(RFILE) /*&& !defined(OSSL_DEBUG)*/ # undef RFILE #endif #include #include /* * Check the OpenSSL version * The only supported are: * OpenSSL >= 0.9.7 */ #include #ifdef HAVE_ASSERT_H # include #else # define assert(condition) #endif #if defined(_WIN32) # define OSSL_NO_CONF_API 1 # ifdef USE_WINSOCK2 # include # else # include # endif #endif #include #include #include #include #include #include #include #include #include #include #include #undef X509_NAME #undef PKCS7_SIGNER_INFO #if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ST_ENGINE) # define OSSL_ENGINE_ENABLED # include #endif #if defined(HAVE_OPENSSL_OCSP_H) # define OSSL_OCSP_ENABLED # include #endif /* * Common Module */ extern VALUE mOSSL; /* * Common Error Class */ extern VALUE eOSSLError; /* * CheckTypes */ #define OSSL_Check_Kind(obj, klass) do {\ if (!rb_obj_is_kind_of(obj, klass)) {\ ossl_raise(rb_eTypeError, "wrong argument (%s)! (Expected kind of %s)",\ rb_obj_classname(obj), rb_class2name(klass));\ }\ } while (0) #define OSSL_Check_Instance(obj, klass) do {\ if (!rb_obj_is_instance_of(obj, klass)) {\ ossl_raise(rb_eTypeError, "wrong argument (%s)! (Expected instance of %s)",\ rb_obj_classname(obj), rb_class2name(klass));\ }\ } while (0) #define OSSL_Check_Same_Class(obj1, obj2) do {\ if (!rb_obj_is_instance_of(obj1, rb_obj_class(obj2))) {\ ossl_raise(rb_eTypeError, "wrong argument type");\ }\ } while (0) /* * Compatibility */ #if OPENSSL_VERSION_NUMBER >= 0x10000000L #define OSSL_MORE_CONST const #define STACK _STACK #else #define OSSL_MORE_CONST #endif /* * String to HEXString conversion */ int string2hex(char *, int, char **, int *); /* * Data Conversion */ STACK_OF(X509) *ossl_x509_ary2sk0(VALUE); STACK_OF(X509) *ossl_x509_ary2sk(VALUE); STACK_OF(X509) *ossl_protect_x509_ary2sk(VALUE,int*); VALUE ossl_x509_sk2ary(STACK_OF(X509) *certs); VALUE ossl_x509crl_sk2ary(STACK_OF(X509_CRL) *crl); VALUE ossl_buf2str(char *buf, int len); #define ossl_str_adjust(str, p) \ do{\ int len = RSTRING_LEN(str);\ int newlen = (p) - (unsigned char*)RSTRING_PTR(str);\ assert(newlen <= len);\ rb_str_set_len(str, newlen);\ }while(0) /* * our default PEM callback */ int ossl_pem_passwd_cb(char *, int, int, void *); /* * ERRor messages */ #define OSSL_ErrMsg() ERR_reason_error_string(ERR_get_error()) NORETURN(void ossl_raise(VALUE, const char *, ...)); /* * Verify callback */ extern int ossl_verify_cb_idx; struct ossl_verify_cb_args { VALUE proc; VALUE preverify_ok; VALUE store_ctx; }; VALUE ossl_call_verify_cb_proc(struct ossl_verify_cb_args *); int ossl_verify_cb(int, X509_STORE_CTX *); /* * String to DER String */ extern ID ossl_s_to_der; VALUE ossl_to_der(VALUE); VALUE ossl_to_der_if_possible(VALUE); /* * Debug */ extern VALUE dOSSL; #if defined(HAVE_VA_ARGS_MACRO) #define OSSL_Debug(fmt, ...) do { \ if (dOSSL == Qtrue) { \ fprintf(stderr, "OSSL_DEBUG: "); \ fprintf(stderr, fmt, ##__VA_ARGS__); \ fprintf(stderr, " [%s:%d]\n", __FILE__, __LINE__); \ } \ } while (0) #define OSSL_Warning(fmt, ...) do { \ OSSL_Debug(fmt, ##__VA_ARGS__); \ rb_warning(fmt, ##__VA_ARGS__); \ } while (0) #define OSSL_Warn(fmt, ...) do { \ OSSL_Debug(fmt, ##__VA_ARGS__); \ rb_warn(fmt, ##__VA_ARGS__); \ } while (0) #else void ossl_debug(const char *, ...); #define OSSL_Debug ossl_debug #define OSSL_Warning rb_warning #define OSSL_Warn rb_warn #endif /* * Include all parts */ #include "openssl_missing.h" #include "ruby_missing.h" #include "ossl_asn1.h" #include "ossl_bio.h" #include "ossl_bn.h" #include "ossl_cipher.h" #include "ossl_config.h" #include "ossl_digest.h" #include "ossl_hmac.h" #include "ossl_ns_spki.h" #include "ossl_ocsp.h" #include "ossl_pkcs12.h" #include "ossl_pkcs7.h" #include "ossl_pkcs5.h" #include "ossl_pkey.h" #include "ossl_rand.h" #include "ossl_ssl.h" #include "ossl_version.h" #include "ossl_x509.h" #include "ossl_engine.h" void Init_openssl(void); #if defined(__cplusplus) } #endif #endif /* _OSSL_H_ */ ================================================ FILE: ext/openssl/ossl_asn1.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' team members * Copyright (C) 2003 * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" #if defined(HAVE_SYS_TIME_H) # include #elif !defined(NT) && !defined(_WIN32) struct timeval { long tv_sec; /* seconds */ long tv_usec; /* and microseconds */ }; #endif /* * DATE conversion */ VALUE asn1time_to_time(ASN1_TIME *time) { struct tm tm; VALUE argv[6]; if (!time || !time->data) return Qnil; memset(&tm, 0, sizeof(struct tm)); switch (time->type) { case V_ASN1_UTCTIME: if (sscanf(time->data, "%2d%2d%2d%2d%2d%2dZ", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) { ossl_raise(rb_eTypeError, "bad UTCTIME format"); } if (tm.tm_year < 69) { tm.tm_year += 2000; } else { tm.tm_year += 1900; } break; case V_ASN1_GENERALIZEDTIME: if (sscanf(time->data, "%4d%2d%2d%2d%2d%2dZ", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) { ossl_raise(rb_eTypeError, "bad GENERALIZEDTIME format" ); } break; default: rb_warning("unknown time format"); return Qnil; } argv[0] = INT2NUM(tm.tm_year); argv[1] = INT2NUM(tm.tm_mon); argv[2] = INT2NUM(tm.tm_mday); argv[3] = INT2NUM(tm.tm_hour); argv[4] = INT2NUM(tm.tm_min); argv[5] = INT2NUM(tm.tm_sec); return rb_funcall2(rb_cTime, rb_intern("utc"), 6, argv); } /* * This function is not exported in Ruby's *.h */ extern struct timeval rb_time_timeval(VALUE); time_t time_to_time_t(VALUE time) { return (time_t)NUM2LONG(rb_Integer(time)); } /* * STRING conversion */ VALUE asn1str_to_str(ASN1_STRING *str) { return rb_str_new(str->data, str->length); } /* * ASN1_INTEGER conversions * TODO: Make a decision what's the right way to do this. */ #define DO_IT_VIA_RUBY 0 VALUE asn1integer_to_num(ASN1_INTEGER *ai) { BIGNUM *bn; #if DO_IT_VIA_RUBY char *txt; #endif VALUE num; if (!ai) { ossl_raise(rb_eTypeError, "ASN1_INTEGER is NULL!"); } if (!(bn = ASN1_INTEGER_to_BN(ai, NULL))) { ossl_raise(eOSSLError, NULL); } #if DO_IT_VIA_RUBY if (!(txt = BN_bn2dec(bn))) { BN_free(bn); ossl_raise(eOSSLError, NULL); } num = rb_cstr_to_inum(txt, 10, Qtrue); OPENSSL_free(txt); #else num = ossl_bn_new(bn); #endif BN_free(bn); return num; } #if DO_IT_VIA_RUBY ASN1_INTEGER * num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai) { BIGNUM *bn = NULL; if (RTEST(rb_obj_is_kind_of(obj, cBN))) { bn = GetBNPtr(obj); } else { obj = rb_String(obj); if (!BN_dec2bn(&bn, StringValuePtr(obj))) { ossl_raise(eOSSLError, NULL); } } if (!(ai = BN_to_ASN1_INTEGER(bn, ai))) { BN_free(bn); ossl_raise(eOSSLError, NULL); } BN_free(bn); return ai; } #else ASN1_INTEGER * num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai) { BIGNUM *bn = GetBNPtr(obj); if (!(ai = BN_to_ASN1_INTEGER(bn, ai))) { ossl_raise(eOSSLError, NULL); } return ai; } #endif /********/ /* * ASN1 module */ #define ossl_asn1_get_value(o) rb_attr_get((o),rb_intern("@value")) #define ossl_asn1_get_tag(o) rb_attr_get((o),rb_intern("@tag")) #define ossl_asn1_get_tagging(o) rb_attr_get((o),rb_intern("@tagging")) #define ossl_asn1_get_tag_class(o) rb_attr_get((o),rb_intern("@tag_class")) #define ossl_asn1_set_value(o,v) rb_iv_set((o),"@value",(v)) #define ossl_asn1_set_tag(o,v) rb_iv_set((o),"@tag",(v)) #define ossl_asn1_set_tagging(o,v) rb_iv_set((o),"@tagging",(v)) #define ossl_asn1_set_tag_class(o,v) rb_iv_set((o),"@tag_class",(v)) VALUE mASN1; VALUE eASN1Error; VALUE cASN1Data; VALUE cASN1Primitive; VALUE cASN1Constructive; VALUE cASN1Boolean; /* BOOLEAN */ VALUE cASN1Integer, cASN1Enumerated; /* INTEGER */ VALUE cASN1BitString; /* BIT STRING */ VALUE cASN1OctetString, cASN1UTF8String; /* STRINGs */ VALUE cASN1NumericString, cASN1PrintableString; VALUE cASN1T61String, cASN1VideotexString; VALUE cASN1IA5String, cASN1GraphicString; VALUE cASN1ISO64String, cASN1GeneralString; VALUE cASN1UniversalString, cASN1BMPString; VALUE cASN1Null; /* NULL */ VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */ VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */ VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */ static ID sIMPLICIT, sEXPLICIT; static ID sUNIVERSAL, sAPPLICATION, sCONTEXT_SPECIFIC, sPRIVATE; /* * Ruby to ASN1 converters */ static ASN1_BOOLEAN obj_to_asn1bool(VALUE obj) { return RTEST(obj) ? 0xff : 0x100; } static ASN1_INTEGER* obj_to_asn1int(VALUE obj) { return num_to_asn1integer(obj, NULL); } static ASN1_BIT_STRING* obj_to_asn1bstr(VALUE obj, long unused_bits) { ASN1_BIT_STRING *bstr; if(unused_bits < 0) unused_bits = 0; StringValue(obj); if(!(bstr = ASN1_BIT_STRING_new())) ossl_raise(eASN1Error, NULL); ASN1_BIT_STRING_set(bstr, RSTRING_PTR(obj), RSTRING_LEN(obj)); bstr->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); /* clear */ bstr->flags |= ASN1_STRING_FLAG_BITS_LEFT|(unused_bits&0x07); return bstr; } static ASN1_STRING* obj_to_asn1str(VALUE obj) { ASN1_STRING *str; StringValue(obj); if(!(str = ASN1_STRING_new())) ossl_raise(eASN1Error, NULL); ASN1_STRING_set(str, RSTRING_PTR(obj), RSTRING_LEN(obj)); return str; } static ASN1_NULL* obj_to_asn1null(VALUE obj) { ASN1_NULL *null; if(!NIL_P(obj)) ossl_raise(eASN1Error, "nil expected"); if(!(null = ASN1_NULL_new())) ossl_raise(eASN1Error, NULL); return null; } static ASN1_OBJECT* obj_to_asn1obj(VALUE obj) { ASN1_OBJECT *a1obj; StringValue(obj); a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 0); if(!a1obj) a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 1); if(!a1obj) ossl_raise(eASN1Error, "invalid OBJECT ID"); return a1obj; } static ASN1_UTCTIME* obj_to_asn1utime(VALUE time) { time_t sec; ASN1_UTCTIME *t; sec = time_to_time_t(time); if(!(t = ASN1_UTCTIME_set(NULL, sec))) ossl_raise(eASN1Error, NULL); return t; } static ASN1_GENERALIZEDTIME* obj_to_asn1gtime(VALUE time) { time_t sec; ASN1_GENERALIZEDTIME *t; sec = time_to_time_t(time); if(!(t =ASN1_GENERALIZEDTIME_set(NULL, sec))) ossl_raise(eASN1Error, NULL); return t; } static ASN1_STRING* obj_to_asn1derstr(VALUE obj) { ASN1_STRING *a1str; VALUE str; str = ossl_to_der(obj); if(!(a1str = ASN1_STRING_new())) ossl_raise(eASN1Error, NULL); ASN1_STRING_set(a1str, RSTRING_PTR(str), RSTRING_LEN(str)); return a1str; } /* * DER to Ruby converters */ static VALUE decode_bool(OSSL_MORE_CONST unsigned char* der, int length) { int bool; OSSL_MORE_CONST unsigned char *p; p = der; if((bool = d2i_ASN1_BOOLEAN(NULL, &p, length)) < 0) ossl_raise(eASN1Error, NULL); return bool ? Qtrue : Qfalse; } static VALUE decode_int(OSSL_MORE_CONST unsigned char* der, int length) { ASN1_INTEGER *ai; OSSL_MORE_CONST unsigned char *p; VALUE ret; int status = 0; p = der; if(!(ai = d2i_ASN1_INTEGER(NULL, &p, length))) ossl_raise(eASN1Error, NULL); ret = rb_protect((VALUE(*)_((VALUE)))asn1integer_to_num, (VALUE)ai, &status); ASN1_INTEGER_free(ai); if(status) rb_jump_tag(status); return ret; } static VALUE decode_bstr(OSSL_MORE_CONST unsigned char* der, int length, long *unused_bits) { ASN1_BIT_STRING *bstr; OSSL_MORE_CONST unsigned char *p; unsigned char *buf; long len; VALUE ret; p = der; if(!(bstr = d2i_ASN1_BIT_STRING(NULL, &p, length))) ossl_raise(eASN1Error, NULL); len = bstr->length; if(!(buf = OPENSSL_malloc(len))){ ASN1_BIT_STRING_free(bstr); ossl_raise(eASN1Error, NULL); } *unused_bits = 0; if(bstr->flags & ASN1_STRING_FLAG_BITS_LEFT) *unused_bits = bstr->flags & 0x07; memcpy(buf, bstr->data, len); ASN1_BIT_STRING_free(bstr); ret = ossl_buf2str(buf, len); return ret; } static VALUE decode_enum(OSSL_MORE_CONST unsigned char* der, int length) { ASN1_ENUMERATED *ai; OSSL_MORE_CONST unsigned char *p; VALUE ret; int status = 0; p = der; if(!(ai = d2i_ASN1_ENUMERATED(NULL, &p, length))) ossl_raise(eASN1Error, NULL); ret = rb_protect((VALUE(*)_((VALUE)))asn1integer_to_num, (VALUE)ai, &status); ASN1_ENUMERATED_free(ai); if(status) rb_jump_tag(status); return ret; } static VALUE decode_null(OSSL_MORE_CONST unsigned char* der, int length) { ASN1_NULL *null; OSSL_MORE_CONST unsigned char *p; p = der; if(!(null = d2i_ASN1_NULL(NULL, &p, length))) ossl_raise(eASN1Error, NULL); ASN1_NULL_free(null); return Qnil; } static VALUE decode_obj(OSSL_MORE_CONST unsigned char* der, int length) { ASN1_OBJECT *obj; OSSL_MORE_CONST unsigned char *p; VALUE ret; int nid; BIO *bio; p = der; if(!(obj = d2i_ASN1_OBJECT(NULL, &p, length))) ossl_raise(eASN1Error, NULL); if((nid = OBJ_obj2nid(obj)) != NID_undef){ ASN1_OBJECT_free(obj); ret = rb_str_new2(OBJ_nid2sn(nid)); } else{ if(!(bio = BIO_new(BIO_s_mem()))){ ASN1_OBJECT_free(obj); ossl_raise(eASN1Error, NULL); } i2a_ASN1_OBJECT(bio, obj); ASN1_OBJECT_free(obj); ret = ossl_membio2str(bio); } return ret; } static VALUE decode_time(OSSL_MORE_CONST unsigned char* der, int length) { ASN1_TIME *time; OSSL_MORE_CONST unsigned char *p; VALUE ret; int status = 0; p = der; if(!(time = d2i_ASN1_TIME(NULL, &p, length))) ossl_raise(eASN1Error, NULL); ret = rb_protect((VALUE(*)_((VALUE)))asn1time_to_time, (VALUE)time, &status); ASN1_TIME_free(time); if(status) rb_jump_tag(status); return ret; } /********/ typedef struct { const char *name; VALUE *klass; } ossl_asn1_info_t; static ossl_asn1_info_t ossl_asn1_info[] = { { "EOC", NULL, }, /* 0 */ { "BOOLEAN", &cASN1Boolean, }, /* 1 */ { "INTEGER", &cASN1Integer, }, /* 2 */ { "BIT_STRING", &cASN1BitString, }, /* 3 */ { "OCTET_STRING", &cASN1OctetString, }, /* 4 */ { "NULL", &cASN1Null, }, /* 5 */ { "OBJECT", &cASN1ObjectId, }, /* 6 */ { "OBJECT_DESCRIPTOR", NULL, }, /* 7 */ { "EXTERNAL", NULL, }, /* 8 */ { "REAL", NULL, }, /* 9 */ { "ENUMERATED", &cASN1Enumerated, }, /* 10 */ { "EMBEDDED_PDV", NULL, }, /* 11 */ { "UTF8STRING", &cASN1UTF8String, }, /* 12 */ { "RELATIVE_OID", NULL, }, /* 13 */ { "[UNIVERSAL 14]", NULL, }, /* 14 */ { "[UNIVERSAL 15]", NULL, }, /* 15 */ { "SEQUENCE", &cASN1Sequence, }, /* 16 */ { "SET", &cASN1Set, }, /* 17 */ { "NUMERICSTRING", &cASN1NumericString, }, /* 18 */ { "PRINTABLESTRING", &cASN1PrintableString, }, /* 19 */ { "T61STRING", &cASN1T61String, }, /* 20 */ { "VIDEOTEXSTRING", &cASN1VideotexString, }, /* 21 */ { "IA5STRING", &cASN1IA5String, }, /* 22 */ { "UTCTIME", &cASN1UTCTime, }, /* 23 */ { "GENERALIZEDTIME", &cASN1GeneralizedTime, }, /* 24 */ { "GRAPHICSTRING", &cASN1GraphicString, }, /* 25 */ { "ISO64STRING", &cASN1ISO64String, }, /* 26 */ { "GENERALSTRING", &cASN1GeneralString, }, /* 27 */ { "UNIVERSALSTRING", &cASN1UniversalString, }, /* 28 */ { "CHARACTER_STRING", NULL, }, /* 29 */ { "BMPSTRING", &cASN1BMPString, }, /* 30 */ }; int ossl_asn1_info_size = (sizeof(ossl_asn1_info)/sizeof(ossl_asn1_info[0])); static int ossl_asn1_default_tag(VALUE obj); ASN1_TYPE* ossl_asn1_get_asn1type(VALUE obj) { ASN1_TYPE *ret; VALUE value, rflag; void *ptr; void (*free_func)(); long tag, flag; tag = ossl_asn1_default_tag(obj); value = ossl_asn1_get_value(obj); switch(tag){ case V_ASN1_BOOLEAN: ptr = (void*)obj_to_asn1bool(value); free_func = NULL; break; case V_ASN1_INTEGER: /* FALLTHROUGH */ case V_ASN1_ENUMERATED: ptr = obj_to_asn1int(value); free_func = ASN1_INTEGER_free; break; case V_ASN1_BIT_STRING: rflag = rb_attr_get(obj, rb_intern("@unused_bits")); flag = NIL_P(rflag) ? -1 : NUM2INT(rflag); ptr = obj_to_asn1bstr(value, flag); free_func = ASN1_BIT_STRING_free; break; case V_ASN1_NULL: ptr = obj_to_asn1null(value); free_func = ASN1_NULL_free; break; case V_ASN1_OCTET_STRING: /* FALLTHROUGH */ case V_ASN1_UTF8STRING: /* FALLTHROUGH */ case V_ASN1_NUMERICSTRING: /* FALLTHROUGH */ case V_ASN1_PRINTABLESTRING: /* FALLTHROUGH */ case V_ASN1_T61STRING: /* FALLTHROUGH */ case V_ASN1_VIDEOTEXSTRING: /* FALLTHROUGH */ case V_ASN1_IA5STRING: /* FALLTHROUGH */ case V_ASN1_GRAPHICSTRING: /* FALLTHROUGH */ case V_ASN1_ISO64STRING: /* FALLTHROUGH */ case V_ASN1_GENERALSTRING: /* FALLTHROUGH */ case V_ASN1_UNIVERSALSTRING: /* FALLTHROUGH */ case V_ASN1_BMPSTRING: ptr = obj_to_asn1str(value); free_func = ASN1_STRING_free; break; case V_ASN1_OBJECT: ptr = obj_to_asn1obj(value); free_func = ASN1_OBJECT_free; break; case V_ASN1_UTCTIME: ptr = obj_to_asn1utime(value); free_func = ASN1_TIME_free; break; case V_ASN1_GENERALIZEDTIME: ptr = obj_to_asn1gtime(value); free_func = ASN1_TIME_free; break; case V_ASN1_SET: /* FALLTHROUGH */ case V_ASN1_SEQUENCE: ptr = obj_to_asn1derstr(obj); free_func = ASN1_STRING_free; break; default: ossl_raise(eASN1Error, "unsupported ASN.1 type"); } if(!(ret = OPENSSL_malloc(sizeof(ASN1_TYPE)))){ if(free_func) free_func(ptr); ossl_raise(eASN1Error, "ASN1_TYPE alloc failure"); } memset(ret, 0, sizeof(ASN1_TYPE)); ASN1_TYPE_set(ret, tag, ptr); return ret; } static int ossl_asn1_default_tag(VALUE obj) { int i; for(i = 0; i < ossl_asn1_info_size; i++){ if(ossl_asn1_info[i].klass && rb_obj_is_kind_of(obj, *ossl_asn1_info[i].klass)){ return i; } } ossl_raise(eASN1Error, "universal tag for %s not found", rb_class2name(CLASS_OF(obj))); return -1; /* dummy */ } static int ossl_asn1_tag(VALUE obj) { VALUE tag; tag = ossl_asn1_get_tag(obj); if(NIL_P(tag)) ossl_raise(eASN1Error, "tag number not specified"); return NUM2INT(tag); } static int ossl_asn1_is_explicit(VALUE obj) { VALUE s; int ret = -1; s = ossl_asn1_get_tagging(obj); if(NIL_P(s)) return 0; else if(SYMBOL_P(s)){ if (SYM2ID(s) == sIMPLICIT) ret = 0; else if (SYM2ID(s) == sEXPLICIT) ret = 1; } if(ret < 0){ ossl_raise(eASN1Error, "invalid tag default"); } return ret; } static int ossl_asn1_tag_class(VALUE obj) { VALUE s; int ret = -1; s = ossl_asn1_get_tag_class(obj); if(NIL_P(s)) ret = V_ASN1_UNIVERSAL; else if(SYMBOL_P(s)){ if (SYM2ID(s) == sUNIVERSAL) ret = V_ASN1_UNIVERSAL; else if (SYM2ID(s) == sAPPLICATION) ret = V_ASN1_APPLICATION; else if (SYM2ID(s) == sCONTEXT_SPECIFIC) ret = V_ASN1_CONTEXT_SPECIFIC; else if (SYM2ID(s) == sPRIVATE) ret = V_ASN1_PRIVATE; } if(ret < 0){ ossl_raise(eASN1Error, "invalid tag class"); } return ret; } static VALUE ossl_asn1_class2sym(int tc) { if((tc & V_ASN1_PRIVATE) == V_ASN1_PRIVATE) return ID2SYM(sPRIVATE); else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC) return ID2SYM(sCONTEXT_SPECIFIC); else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION) return ID2SYM(sAPPLICATION); else return ID2SYM(sUNIVERSAL); } static VALUE ossl_asn1data_initialize(VALUE self, VALUE value, VALUE tag, VALUE tag_class) { if(!SYMBOL_P(tag_class)) ossl_raise(eASN1Error, "invalid tag class"); if((SYM2ID(tag_class) == sUNIVERSAL) && NUM2INT(tag) > 31) ossl_raise(eASN1Error, "tag number for Universal too large"); ossl_asn1_set_tag(self, tag); ossl_asn1_set_value(self, value); ossl_asn1_set_tag_class(self, tag_class); return self; } static VALUE join_der_i(VALUE i, VALUE str) { i = ossl_to_der_if_possible(i); StringValue(i); rb_str_append(str, i); return Qnil; } static VALUE join_der(VALUE enumerable) { VALUE str = rb_str_new(0, 0); rb_block_call(enumerable, rb_intern("each"), 0, 0, join_der_i, str); return str; } static VALUE ossl_asn1data_to_der(VALUE self) { VALUE value, der; int tag, tag_class, is_cons = 0; long length; unsigned char *p; value = ossl_asn1_get_value(self); if(rb_obj_is_kind_of(value, rb_cArray)){ is_cons = 1; value = join_der(value); } StringValue(value); tag = ossl_asn1_tag(self); tag_class = ossl_asn1_tag_class(self); if((length = ASN1_object_size(1, RSTRING_LEN(value), tag)) <= 0) ossl_raise(eASN1Error, NULL); der = rb_str_new(0, length); p = RSTRING_PTR(der); ASN1_put_object(&p, is_cons, RSTRING_LEN(value), tag, tag_class); memcpy(p, RSTRING_PTR(value), RSTRING_LEN(value)); p += RSTRING_LEN(value); ossl_str_adjust(der, p); return der; } static VALUE ossl_asn1_decode0(OSSL_MORE_CONST unsigned char **pp, long length, long *offset, long depth, int once, int yield) { OSSL_MORE_CONST unsigned char *start, *p; long len, off = *offset; int hlen, tag, tc, j; VALUE ary, asn1data, value, tag_class; ary = rb_ary_new(); p = *pp; while(length > 0){ start = p; j = ASN1_get_object(&p, &len, &tag, &tc, length); if(j & 0x80) ossl_raise(eASN1Error, NULL); hlen = p - start; if(yield){ VALUE arg = rb_ary_new(); rb_ary_push(arg, LONG2NUM(depth)); rb_ary_push(arg, LONG2NUM(off)); rb_ary_push(arg, LONG2NUM(hlen)); rb_ary_push(arg, LONG2NUM(len)); rb_ary_push(arg, (j & V_ASN1_CONSTRUCTED) ? Qtrue : Qfalse); rb_ary_push(arg, ossl_asn1_class2sym(tc)); rb_ary_push(arg, INT2NUM(tag)); rb_yield(arg); } length -= hlen; off += hlen; if(len > length) ossl_raise(eASN1Error, "value is too short"); if((tc & V_ASN1_PRIVATE) == V_ASN1_PRIVATE) tag_class = sPRIVATE; else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC) tag_class = sCONTEXT_SPECIFIC; else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION) tag_class = sAPPLICATION; else tag_class = sUNIVERSAL; if(j & V_ASN1_CONSTRUCTED){ /* TODO: if j == 0x21 it is indefinite length object. */ if((j == 0x21) && (len == 0)){ long lastoff = off; value = ossl_asn1_decode0(&p, length, &off, depth+1, 0, yield); len = off - lastoff; } else value = ossl_asn1_decode0(&p, len, &off, depth+1, 0, yield); } else{ value = rb_str_new(p, len); p += len; off += len; } if(tag_class == sUNIVERSAL && tag < ossl_asn1_info_size && ossl_asn1_info[tag].klass){ VALUE klass = *ossl_asn1_info[tag].klass; long flag = 0; if(!rb_obj_is_kind_of(value, rb_cArray)){ switch(tag){ case V_ASN1_BOOLEAN: value = decode_bool(start, hlen+len); break; case V_ASN1_INTEGER: value = decode_int(start, hlen+len); break; case V_ASN1_BIT_STRING: value = decode_bstr(start, hlen+len, &flag); break; case V_ASN1_NULL: value = decode_null(start, hlen+len); break; case V_ASN1_ENUMERATED: value = decode_enum(start, hlen+len); break; case V_ASN1_OBJECT: value = decode_obj(start, hlen+len); break; case V_ASN1_UTCTIME: /* FALLTHROUGH */ case V_ASN1_GENERALIZEDTIME: value = decode_time(start, hlen+len); break; default: /* use original value */ break; } } asn1data = rb_funcall(klass, rb_intern("new"), 1, value); if(tag == V_ASN1_BIT_STRING){ rb_iv_set(asn1data, "@unused_bits", LONG2NUM(flag)); } } else{ asn1data = rb_funcall(cASN1Data, rb_intern("new"), 3, value, INT2NUM(tag), ID2SYM(tag_class)); } rb_ary_push(ary, asn1data); length -= len; if(once) break; } *pp = p; *offset = off; return ary; } static VALUE ossl_asn1_traverse(VALUE self, VALUE obj) { OSSL_MORE_CONST unsigned char *p; long offset = 0; volatile VALUE tmp; obj = ossl_to_der_if_possible(obj); tmp = rb_str_new4(StringValue(obj)); p = RSTRING_PTR(tmp); ossl_asn1_decode0(&p, RSTRING_LEN(tmp), &offset, 0, 0, 1); return Qnil; } static VALUE ossl_asn1_decode(VALUE self, VALUE obj) { VALUE ret, ary; OSSL_MORE_CONST unsigned char *p; long offset = 0; volatile VALUE tmp; obj = ossl_to_der_if_possible(obj); tmp = rb_str_new4(StringValue(obj)); p = RSTRING_PTR(tmp); ary = ossl_asn1_decode0(&p, RSTRING_LEN(tmp), &offset, 0, 1, 0); ret = rb_ary_entry(ary, 0); return ret; } static VALUE ossl_asn1_decode_all(VALUE self, VALUE obj) { VALUE ret; OSSL_MORE_CONST unsigned char *p; long offset = 0; volatile VALUE tmp; obj = ossl_to_der_if_possible(obj); tmp = rb_str_new4(StringValue(obj)); p = RSTRING_PTR(tmp); ret = ossl_asn1_decode0(&p, RSTRING_LEN(tmp), &offset, 0, 0, 0); return ret; } static VALUE ossl_asn1_initialize(int argc, VALUE *argv, VALUE self) { VALUE value, tag, tagging, tag_class; rb_scan_args(argc, argv, "13", &value, &tag, &tagging, &tag_class); if(argc > 1){ if(NIL_P(tag)) ossl_raise(eASN1Error, "must specify tag number"); if(NIL_P(tagging)) tagging = ID2SYM(sEXPLICIT); if(!SYMBOL_P(tagging)) ossl_raise(eASN1Error, "invalid tag default"); if(NIL_P(tag_class)) tag_class = ID2SYM(sCONTEXT_SPECIFIC); if(!SYMBOL_P(tag_class)) ossl_raise(eASN1Error, "invalid tag class"); if(SYM2ID(tagging) == sIMPLICIT && NUM2INT(tag) > 31) ossl_raise(eASN1Error, "tag number for Universal too large"); } else{ tag = INT2NUM(ossl_asn1_default_tag(self)); tagging = Qnil; tag_class = ID2SYM(sUNIVERSAL); } ossl_asn1_set_tag(self, tag); ossl_asn1_set_value(self, value); ossl_asn1_set_tagging(self, tagging); ossl_asn1_set_tag_class(self, tag_class); return self; } static int ossl_i2d_ASN1_TYPE(ASN1_TYPE *a, unsigned char **pp) { #if OPENSSL_VERSION_NUMBER < 0x00907000L if(!a) return 0; if(a->type == V_ASN1_BOOLEAN) return i2d_ASN1_BOOLEAN(a->value.boolean, pp); #endif return i2d_ASN1_TYPE(a, pp); } static void ossl_ASN1_TYPE_free(ASN1_TYPE *a) { #if OPENSSL_VERSION_NUMBER < 0x00907000L if(!a) return; if(a->type == V_ASN1_BOOLEAN){ OPENSSL_free(a); return; } #endif ASN1_TYPE_free(a); } static VALUE ossl_asn1prim_to_der(VALUE self) { ASN1_TYPE *asn1; int tn, tc, explicit; long length, reallen; unsigned char *buf, *p; VALUE str; tn = NUM2INT(ossl_asn1_get_tag(self)); tc = ossl_asn1_tag_class(self); explicit = ossl_asn1_is_explicit(self); asn1 = ossl_asn1_get_asn1type(self); length = ASN1_object_size(1, ossl_i2d_ASN1_TYPE(asn1, NULL), tn); if(!(buf = OPENSSL_malloc(length))){ ossl_ASN1_TYPE_free(asn1); ossl_raise(eASN1Error, "cannot alloc buffer"); } p = buf; if(tc == V_ASN1_UNIVERSAL) ossl_i2d_ASN1_TYPE(asn1, &p); else{ if(explicit){ ASN1_put_object(&p, 1, ossl_i2d_ASN1_TYPE(asn1, NULL), tn, tc); ossl_i2d_ASN1_TYPE(asn1, &p); } else{ ossl_i2d_ASN1_TYPE(asn1, &p); *buf = tc | tn | (*buf & V_ASN1_CONSTRUCTED); } } ossl_ASN1_TYPE_free(asn1); reallen = p - buf; assert(reallen <= length); str = ossl_buf2str(buf, reallen); /* buf will be free in ossl_buf2str */ return str; } static VALUE ossl_asn1cons_to_der(VALUE self) { int tag, tn, tc, explicit; long seq_len, length; unsigned char *p; VALUE value, str; tag = ossl_asn1_default_tag(self); tn = NUM2INT(ossl_asn1_get_tag(self)); tc = ossl_asn1_tag_class(self); explicit = ossl_asn1_is_explicit(self); value = join_der(ossl_asn1_get_value(self)); seq_len = ASN1_object_size(1, RSTRING_LEN(value), tag); length = ASN1_object_size(1, seq_len, tn); str = rb_str_new(0, length); p = RSTRING_PTR(str); if(tc == V_ASN1_UNIVERSAL) ASN1_put_object(&p, 1, RSTRING_LEN(value), tn, tc); else{ if(explicit){ ASN1_put_object(&p, 1, seq_len, tn, tc); ASN1_put_object(&p, 1, RSTRING_LEN(value), tag, V_ASN1_UNIVERSAL); } else ASN1_put_object(&p, 1, RSTRING_LEN(value), tn, tc); } memcpy(p, RSTRING_PTR(value), RSTRING_LEN(value)); p += RSTRING_LEN(value); ossl_str_adjust(str, p); return str; } static VALUE ossl_asn1cons_each(VALUE self) { rb_ary_each(ossl_asn1_get_value(self)); return self; } static VALUE ossl_asn1obj_s_register(VALUE self, VALUE oid, VALUE sn, VALUE ln) { StringValue(oid); StringValue(sn); StringValue(ln); if(!OBJ_create(RSTRING_PTR(oid), RSTRING_PTR(sn), RSTRING_PTR(ln))) ossl_raise(eASN1Error, NULL); return Qtrue; } static VALUE ossl_asn1obj_get_sn(VALUE self) { VALUE val, ret = Qnil; int nid; val = ossl_asn1_get_value(self); if ((nid = OBJ_txt2nid(StringValuePtr(val))) != NID_undef) ret = rb_str_new2(OBJ_nid2sn(nid)); return ret; } static VALUE ossl_asn1obj_get_ln(VALUE self) { VALUE val, ret = Qnil; int nid; val = ossl_asn1_get_value(self); if ((nid = OBJ_txt2nid(StringValuePtr(val))) != NID_undef) ret = rb_str_new2(OBJ_nid2ln(nid)); return ret; } static VALUE ossl_asn1obj_get_oid(VALUE self) { VALUE val; ASN1_OBJECT *a1obj; char buf[128]; val = ossl_asn1_get_value(self); a1obj = obj_to_asn1obj(val); OBJ_obj2txt(buf, sizeof(buf), a1obj, 1); ASN1_OBJECT_free(a1obj); return rb_str_new2(buf); } #define OSSL_ASN1_IMPL_FACTORY_METHOD(klass) \ static VALUE ossl_asn1_##klass(int argc, VALUE *argv, VALUE self)\ { return rb_funcall3(cASN1##klass, rb_intern("new"), argc, argv); } OSSL_ASN1_IMPL_FACTORY_METHOD(Boolean) OSSL_ASN1_IMPL_FACTORY_METHOD(Integer) OSSL_ASN1_IMPL_FACTORY_METHOD(Enumerated) OSSL_ASN1_IMPL_FACTORY_METHOD(BitString) OSSL_ASN1_IMPL_FACTORY_METHOD(OctetString) OSSL_ASN1_IMPL_FACTORY_METHOD(UTF8String) OSSL_ASN1_IMPL_FACTORY_METHOD(NumericString) OSSL_ASN1_IMPL_FACTORY_METHOD(PrintableString) OSSL_ASN1_IMPL_FACTORY_METHOD(T61String) OSSL_ASN1_IMPL_FACTORY_METHOD(VideotexString) OSSL_ASN1_IMPL_FACTORY_METHOD(IA5String) OSSL_ASN1_IMPL_FACTORY_METHOD(GraphicString) OSSL_ASN1_IMPL_FACTORY_METHOD(ISO64String) OSSL_ASN1_IMPL_FACTORY_METHOD(GeneralString) OSSL_ASN1_IMPL_FACTORY_METHOD(UniversalString) OSSL_ASN1_IMPL_FACTORY_METHOD(BMPString) OSSL_ASN1_IMPL_FACTORY_METHOD(Null) OSSL_ASN1_IMPL_FACTORY_METHOD(ObjectId) OSSL_ASN1_IMPL_FACTORY_METHOD(UTCTime) OSSL_ASN1_IMPL_FACTORY_METHOD(GeneralizedTime) OSSL_ASN1_IMPL_FACTORY_METHOD(Sequence) OSSL_ASN1_IMPL_FACTORY_METHOD(Set) void Init_ossl_asn1() { VALUE ary; int i; #if 0 /* let rdoc know about mOSSL */ mOSSL = rb_define_module("OpenSSL"); #endif sUNIVERSAL = rb_intern("UNIVERSAL"); sCONTEXT_SPECIFIC = rb_intern("CONTEXT_SPECIFIC"); sAPPLICATION = rb_intern("APPLICATION"); sPRIVATE = rb_intern("PRIVATE"); sEXPLICIT = rb_intern("EXPLICIT"); sIMPLICIT = rb_intern("IMPLICIT"); mASN1 = rb_define_module_under(mOSSL, "ASN1"); eASN1Error = rb_define_class_under(mASN1, "ASN1Error", eOSSLError); rb_define_module_function(mASN1, "traverse", ossl_asn1_traverse, 1); rb_define_module_function(mASN1, "decode", ossl_asn1_decode, 1); rb_define_module_function(mASN1, "decode_all", ossl_asn1_decode_all, 1); ary = rb_ary_new(); rb_define_const(mASN1, "UNIVERSAL_TAG_NAME", ary); for(i = 0; i < ossl_asn1_info_size; i++){ if(ossl_asn1_info[i].name[0] == '[') continue; rb_define_const(mASN1, ossl_asn1_info[i].name, INT2NUM(i)); rb_ary_store(ary, i, rb_str_new2(ossl_asn1_info[i].name)); } cASN1Data = rb_define_class_under(mASN1, "ASN1Data", rb_cObject); rb_attr(cASN1Data, rb_intern("value"), 1, 1, 0); rb_attr(cASN1Data, rb_intern("tag"), 1, 1, 0); rb_attr(cASN1Data, rb_intern("tag_class"), 1, 1, 0); rb_define_method(cASN1Data, "initialize", ossl_asn1data_initialize, 3); rb_define_method(cASN1Data, "to_der", ossl_asn1data_to_der, 0); cASN1Primitive = rb_define_class_under(mASN1, "Primitive", cASN1Data); rb_attr(cASN1Primitive, rb_intern("tagging"), 1, 1, Qtrue); rb_define_method(cASN1Primitive, "initialize", ossl_asn1_initialize, -1); rb_define_method(cASN1Primitive, "to_der", ossl_asn1prim_to_der, 0); cASN1Constructive = rb_define_class_under(mASN1,"Constructive", cASN1Data); rb_include_module(cASN1Constructive, rb_mEnumerable); rb_attr(cASN1Constructive, rb_intern("tagging"), 1, 1, Qtrue); rb_define_method(cASN1Constructive, "initialize", ossl_asn1_initialize, -1); rb_define_method(cASN1Constructive, "to_der", ossl_asn1cons_to_der, 0); rb_define_method(cASN1Constructive, "each", ossl_asn1cons_each, 0); #define OSSL_ASN1_DEFINE_CLASS(name, super) \ do{\ cASN1##name = rb_define_class_under(mASN1, #name, cASN1##super);\ rb_define_module_function(mASN1, #name, ossl_asn1_##name, -1);\ }while(0) OSSL_ASN1_DEFINE_CLASS(Boolean, Primitive); OSSL_ASN1_DEFINE_CLASS(Integer, Primitive); OSSL_ASN1_DEFINE_CLASS(Enumerated, Primitive); OSSL_ASN1_DEFINE_CLASS(BitString, Primitive); OSSL_ASN1_DEFINE_CLASS(OctetString, Primitive); OSSL_ASN1_DEFINE_CLASS(UTF8String, Primitive); OSSL_ASN1_DEFINE_CLASS(NumericString, Primitive); OSSL_ASN1_DEFINE_CLASS(PrintableString, Primitive); OSSL_ASN1_DEFINE_CLASS(T61String, Primitive); OSSL_ASN1_DEFINE_CLASS(VideotexString, Primitive); OSSL_ASN1_DEFINE_CLASS(IA5String, Primitive); OSSL_ASN1_DEFINE_CLASS(GraphicString, Primitive); OSSL_ASN1_DEFINE_CLASS(ISO64String, Primitive); OSSL_ASN1_DEFINE_CLASS(GeneralString, Primitive); OSSL_ASN1_DEFINE_CLASS(UniversalString, Primitive); OSSL_ASN1_DEFINE_CLASS(BMPString, Primitive); OSSL_ASN1_DEFINE_CLASS(Null, Primitive); OSSL_ASN1_DEFINE_CLASS(ObjectId, Primitive); OSSL_ASN1_DEFINE_CLASS(UTCTime, Primitive); OSSL_ASN1_DEFINE_CLASS(GeneralizedTime, Primitive); OSSL_ASN1_DEFINE_CLASS(Sequence, Constructive); OSSL_ASN1_DEFINE_CLASS(Set, Constructive); rb_define_singleton_method(cASN1ObjectId, "register", ossl_asn1obj_s_register, 3); rb_define_method(cASN1ObjectId, "sn", ossl_asn1obj_get_sn, 0); rb_define_method(cASN1ObjectId, "ln", ossl_asn1obj_get_ln, 0); rb_define_method(cASN1ObjectId, "oid", ossl_asn1obj_get_oid, 0); rb_define_alias(cASN1ObjectId, "short_name", "sn"); rb_define_alias(cASN1ObjectId, "long_name", "ln"); rb_attr(cASN1BitString, rb_intern("unused_bits"), 1, 1, 0); } ================================================ FILE: ext/openssl/ossl_asn1.h ================================================ /* * $Id$ * 'OpenSSL for Ruby' team members * Copyright (C) 2003 * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(_OSSL_ASN1_H_) #define _OSSL_ASN1_H_ /* * ASN1_DATE conversions */ VALUE asn1time_to_time(ASN1_TIME *); time_t time_to_time_t(VALUE); /* * ASN1_STRING conversions */ VALUE asn1str_to_str(ASN1_STRING *); /* * ASN1_INTEGER conversions */ VALUE asn1integer_to_num(ASN1_INTEGER *); ASN1_INTEGER *num_to_asn1integer(VALUE, ASN1_INTEGER *); /* * ASN1 module */ extern VALUE mASN1; extern VALUE eASN1Error; extern VALUE cASN1Data; extern VALUE cASN1Primitive; extern VALUE cASN1Constructive; extern VALUE cASN1Boolean; /* BOOLEAN */ extern VALUE cASN1Integer, cASN1Enumerated; /* INTEGER */ extern VALUE cASN1BitString; /* BIT STRING */ extern VALUE cASN1OctetString, cASN1UTF8String; /* STRINGs */ extern VALUE cASN1NumericString, cASN1PrintableString; extern VALUE cASN1T61String, cASN1VideotexString; extern VALUE cASN1IA5String, cASN1GraphicString; extern VALUE cASN1ISO64String, cASN1GeneralString; extern VALUE cASN1UniversalString, cASN1BMPString; extern VALUE cASN1Null; /* NULL */ extern VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */ extern VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */ extern VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */ ASN1_TYPE *ossl_asn1_get_asn1type(VALUE); void Init_ossl_asn1(void); #endif ================================================ FILE: ext/openssl/ossl_bio.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' team members * Copyright (C) 2003 * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" #ifdef HAVE_UNISTD_H #include #endif BIO * ossl_obj2bio(VALUE obj) { BIO *bio; if (TYPE(obj) == T_FILE) { rb_io_t *fptr; FILE *fp; int fd; GetOpenFile(obj, fptr); rb_io_check_readable(fptr); if ((fd = dup(FPTR_TO_FD(fptr))) < 0){ rb_sys_fail(0); } if (!(fp = fdopen(fd, "r"))){ close(fd); rb_sys_fail(0); } if (!(bio = BIO_new_fp(fp, BIO_CLOSE))){ fclose(fp); ossl_raise(eOSSLError, NULL); } } else { StringValue(obj); bio = BIO_new_mem_buf(RSTRING_PTR(obj), RSTRING_LEN(obj)); if (!bio) ossl_raise(eOSSLError, NULL); } return bio; } BIO * ossl_protect_obj2bio(VALUE obj, int *status) { BIO *ret = NULL; ret = (BIO*)rb_protect((VALUE(*)_((VALUE)))ossl_obj2bio, obj, status); return ret; } VALUE ossl_membio2str0(BIO *bio) { VALUE ret; BUF_MEM *buf; BIO_get_mem_ptr(bio, &buf); ret = rb_str_new(buf->data, buf->length); return ret; } VALUE ossl_protect_membio2str(BIO *bio, int *status) { return rb_protect((VALUE(*)_((VALUE)))ossl_membio2str0, (VALUE)bio, status); } VALUE ossl_membio2str(BIO *bio) { VALUE ret; int status = 0; ret = ossl_protect_membio2str(bio, &status); BIO_free(bio); if(status) rb_jump_tag(status); return ret; } ================================================ FILE: ext/openssl/ossl_bio.h ================================================ /* * $Id$ * 'OpenSSL for Ruby' team members * Copyright (C) 2003 * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(_OSSL_BIO_H_) #define _OSSL_BIO_H_ BIO *ossl_obj2bio(VALUE); BIO *ossl_protect_obj2bio(VALUE,int*); VALUE ossl_membio2str0(BIO*); VALUE ossl_membio2str(BIO*); VALUE ossl_protect_membio2str(BIO*,int*); #endif ================================================ FILE: ext/openssl/ossl_bn.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Technorama team * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ /* modified by Michal Rokos */ #include "ossl.h" #define WrapBN(klass, obj, bn) do { \ if (!bn) { \ ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \ } \ obj = Data_Wrap_Struct(klass, 0, BN_clear_free, bn); \ } while (0) #define GetBN(obj, bn) do { \ Data_Get_Struct(obj, BIGNUM, bn); \ if (!bn) { \ ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \ } \ } while (0) #define SafeGetBN(obj, bn) do { \ OSSL_Check_Kind(obj, cBN); \ GetBN(obj, bn); \ } while (0) /* * Classes */ VALUE cBN; VALUE eBNError; /* * Public */ VALUE ossl_bn_new(const BIGNUM *bn) { BIGNUM *newbn; VALUE obj; newbn = bn ? BN_dup(bn) : BN_new(); if (!newbn) { ossl_raise(eBNError, NULL); } WrapBN(cBN, obj, newbn); return obj; } BIGNUM * GetBNPtr(VALUE obj) { BIGNUM *bn = NULL; if (RTEST(rb_obj_is_kind_of(obj, cBN))) { GetBN(obj, bn); } else switch (TYPE(obj)) { case T_FIXNUM: case T_BIGNUM: obj = rb_String(obj); if (!BN_dec2bn(&bn, StringValuePtr(obj))) { ossl_raise(eBNError, NULL); } WrapBN(cBN, obj, bn); /* Handle potencial mem leaks */ break; default: ossl_raise(rb_eTypeError, "Cannot convert into OpenSSL::BN"); } return bn; } /* * Private */ /* * BN_CTX - is used in more difficult math. ops * (Why just 1? Because Ruby itself isn't thread safe, * we don't need to care about threads) */ BN_CTX *ossl_bn_ctx; static VALUE ossl_bn_alloc(VALUE klass) { BIGNUM *bn; VALUE obj; if (!(bn = BN_new())) { ossl_raise(eBNError, NULL); } WrapBN(klass, obj, bn); return obj; } /* * call-seq: * BN.new => aBN * BN.new(bn) => aBN * BN.new(string) => aBN * BN.new(string, 0 | 2 | 10 | 16) => aBN */ static VALUE ossl_bn_initialize(int argc, VALUE *argv, VALUE self) { BIGNUM *bn; VALUE str, bs; int base = 10; if (rb_scan_args(argc, argv, "11", &str, &bs) == 2) { base = NUM2INT(bs); } StringValue(str); GetBN(self, bn); if (RTEST(rb_obj_is_kind_of(str, cBN))) { BIGNUM *other; GetBN(str, other); /* Safe - we checked kind_of? above */ if (!BN_copy(bn, other)) { ossl_raise(eBNError, NULL); } return self; } switch (base) { case 0: if (!BN_mpi2bn(RSTRING_PTR(str), RSTRING_LEN(str), bn)) { ossl_raise(eBNError, NULL); } break; case 2: if (!BN_bin2bn(RSTRING_PTR(str), RSTRING_LEN(str), bn)) { ossl_raise(eBNError, NULL); } break; case 10: if (!BN_dec2bn(&bn, RSTRING_PTR(str))) { ossl_raise(eBNError, NULL); } break; case 16: if (!BN_hex2bn(&bn, RSTRING_PTR(str))) { ossl_raise(eBNError, NULL); } break; default: ossl_raise(rb_eArgError, "illegal radix %d", base); } return self; } /* * call-seq: * bn.to_s => string * bn.to_s(base) => string * * === Parameters * * +base+ - integer * * * Valid values: * * * * 0 - MPI * * * * 2 - binary * * * * 10 - the default * * * * 16 - hex */ static VALUE ossl_bn_to_s(int argc, VALUE *argv, VALUE self) { BIGNUM *bn; VALUE str, bs; int base = 10, len; char *buf; if (rb_scan_args(argc, argv, "01", &bs) == 1) { base = NUM2INT(bs); } GetBN(self, bn); switch (base) { case 0: len = BN_bn2mpi(bn, NULL); str = rb_str_new(0, len); if (BN_bn2mpi(bn, RSTRING_PTR(str)) != len) ossl_raise(eBNError, NULL); break; case 2: len = BN_num_bytes(bn); str = rb_str_new(0, len); if (BN_bn2bin(bn, RSTRING_PTR(str)) != len) ossl_raise(eBNError, NULL); break; case 10: if (!(buf = BN_bn2dec(bn))) ossl_raise(eBNError, NULL); str = ossl_buf2str(buf, strlen(buf)); break; case 16: if (!(buf = BN_bn2hex(bn))) ossl_raise(eBNError, NULL); str = ossl_buf2str(buf, strlen(buf)); break; default: ossl_raise(rb_eArgError, "illegal radix %d", base); } return str; } /* * call-seq: * bn.to_i => integer */ static VALUE ossl_bn_to_i(VALUE self) { BIGNUM *bn; char *txt; VALUE num; GetBN(self, bn); if (!(txt = BN_bn2dec(bn))) { ossl_raise(eBNError, NULL); } num = rb_cstr_to_inum(txt, 10, Qtrue); OPENSSL_free(txt); return num; } static VALUE ossl_bn_to_bn(VALUE self) { return self; } static VALUE ossl_bn_coerce(VALUE self, VALUE other) { switch(TYPE(other)) { case T_STRING: self = ossl_bn_to_s(0, NULL, self); break; case T_FIXNUM: case T_BIGNUM: self = ossl_bn_to_i(self); break; default: if (!RTEST(rb_obj_is_kind_of(other, cBN))) { ossl_raise(rb_eTypeError, "Don't know how to coerce"); } } return rb_assoc_new(other, self); } #define BIGNUM_BOOL1(func) \ /* \ * call-seq: \ * bn.##func -> true | false \ * \ */ \ static VALUE \ ossl_bn_##func(VALUE self) \ { \ BIGNUM *bn; \ GetBN(self, bn); \ if (BN_##func(bn)) { \ return Qtrue; \ } \ return Qfalse; \ } BIGNUM_BOOL1(is_zero); BIGNUM_BOOL1(is_one); BIGNUM_BOOL1(is_odd); #define BIGNUM_1c(func) \ /* \ * call-seq: \ * bn.##func -> aBN \ * \ */ \ static VALUE \ ossl_bn_##func(VALUE self) \ { \ BIGNUM *bn, *result; \ VALUE obj; \ GetBN(self, bn); \ if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ if (!BN_##func(result, bn, ossl_bn_ctx)) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ WrapBN(CLASS_OF(self), obj, result); \ return obj; \ } BIGNUM_1c(sqr); #define BIGNUM_2(func) \ /* \ * call-seq: \ * bn.##func(bn2) -> aBN \ * \ */ \ static VALUE \ ossl_bn_##func(VALUE self, VALUE other) \ { \ BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \ VALUE obj; \ GetBN(self, bn1); \ if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ if (!BN_##func(result, bn1, bn2)) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ WrapBN(CLASS_OF(self), obj, result); \ return obj; \ } BIGNUM_2(add); BIGNUM_2(sub); #define BIGNUM_2c(func) \ /* \ * call-seq: \ * bn.##func(bn2) -> aBN \ * \ */ \ static VALUE \ ossl_bn_##func(VALUE self, VALUE other) \ { \ BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \ VALUE obj; \ GetBN(self, bn1); \ if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ if (!BN_##func(result, bn1, bn2, ossl_bn_ctx)) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ WrapBN(CLASS_OF(self), obj, result); \ return obj; \ } BIGNUM_2c(mul); BIGNUM_2c(mod); BIGNUM_2c(exp); BIGNUM_2c(gcd); BIGNUM_2c(mod_sqr); BIGNUM_2c(mod_inverse); /* * call-seq: * bn1 / bn2 => [result, remainder] */ static VALUE ossl_bn_div(VALUE self, VALUE other) { BIGNUM *bn1, *bn2 = GetBNPtr(other), *r1, *r2; VALUE obj1, obj2; GetBN(self, bn1); if (!(r1 = BN_new())) { ossl_raise(eBNError, NULL); } if (!(r2 = BN_new())) { BN_free(r1); ossl_raise(eBNError, NULL); } if (!BN_div(r1, r2, bn1, bn2, ossl_bn_ctx)) { BN_free(r1); BN_free(r2); ossl_raise(eBNError, NULL); } WrapBN(CLASS_OF(self), obj1, r1); WrapBN(CLASS_OF(self), obj2, r2); return rb_ary_new3(2, obj1, obj2); } #define BIGNUM_3c(func) \ /* \ * call-seq: \ * bn.##func(bn1, bn2) -> aBN \ * \ */ \ static VALUE \ ossl_bn_##func(VALUE self, VALUE other1, VALUE other2) \ { \ BIGNUM *bn1, *bn2 = GetBNPtr(other1); \ BIGNUM *bn3 = GetBNPtr(other2), *result; \ VALUE obj; \ GetBN(self, bn1); \ if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ if (!BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx)) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ WrapBN(CLASS_OF(self), obj, result); \ return obj; \ } BIGNUM_3c(mod_add); BIGNUM_3c(mod_sub); BIGNUM_3c(mod_mul); BIGNUM_3c(mod_exp); #define BIGNUM_BIT(func) \ /* \ * call-seq: \ * bn.##func(bit) -> self \ * \ */ \ static VALUE \ ossl_bn_##func(VALUE self, VALUE bit) \ { \ BIGNUM *bn; \ GetBN(self, bn); \ if (!BN_##func(bn, NUM2INT(bit))) { \ ossl_raise(eBNError, NULL); \ } \ return self; \ } BIGNUM_BIT(set_bit); BIGNUM_BIT(clear_bit); BIGNUM_BIT(mask_bits); /* * call-seq: * bn.bit_set?(bit) => true | false */ static VALUE ossl_bn_is_bit_set(VALUE self, VALUE bit) { int b; BIGNUM *bn; b = NUM2INT(bit); GetBN(self, bn); if (BN_is_bit_set(bn, b)) { return Qtrue; } return Qfalse; } #define BIGNUM_SHIFT(func) \ /* \ * call-seq: \ * bn.##func(bits) -> aBN \ * \ */ \ static VALUE \ ossl_bn_##func(VALUE self, VALUE bits) \ { \ BIGNUM *bn, *result; \ int b; \ VALUE obj; \ b = NUM2INT(bits); \ GetBN(self, bn); \ if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ if (!BN_##func(result, bn, b)) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ WrapBN(CLASS_OF(self), obj, result); \ return obj; \ } BIGNUM_SHIFT(lshift); BIGNUM_SHIFT(rshift); #define BIGNUM_SELF_SHIFT(func) \ /* \ * call-seq: \ * bn.##func!(bits) -> self \ * \ */ \ static VALUE \ ossl_bn_self_##func(VALUE self, VALUE bits) \ { \ BIGNUM *bn; \ int b; \ b = NUM2INT(bits); \ GetBN(self, bn); \ if (!BN_##func(bn, bn, b)) \ ossl_raise(eBNError, NULL); \ return self; \ } BIGNUM_SELF_SHIFT(lshift); BIGNUM_SELF_SHIFT(rshift); #define BIGNUM_RAND(func) \ /* \ * call-seq: \ * BN.##func(bits [, fill [, odd]]) -> aBN \ * \ */ \ static VALUE \ ossl_bn_s_##func(int argc, VALUE *argv, VALUE klass) \ { \ BIGNUM *result; \ int bottom = 0, top = 0, b; \ VALUE bits, fill, odd, obj; \ \ switch (rb_scan_args(argc, argv, "12", &bits, &fill, &odd)) { \ case 3: \ bottom = (odd == Qtrue) ? 1 : 0; \ /* FALLTHROUGH */ \ case 2: \ top = NUM2INT(fill); \ } \ b = NUM2INT(bits); \ if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ if (!BN_##func(result, b, top, bottom)) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ WrapBN(klass, obj, result); \ return obj; \ } BIGNUM_RAND(rand); BIGNUM_RAND(pseudo_rand); #define BIGNUM_RAND_RANGE(func) \ /* \ * call-seq: \ * BN.##func(range) -> aBN \ * \ */ \ static VALUE \ ossl_bn_s_##func##_range(VALUE klass, VALUE range) \ { \ BIGNUM *bn = GetBNPtr(range), *result; \ VALUE obj; \ if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ if (!BN_##func##_range(result, bn)) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ WrapBN(klass, obj, result); \ return obj; \ } BIGNUM_RAND_RANGE(rand); BIGNUM_RAND_RANGE(pseudo_rand); /* * call-seq: * BN.generate_prime(bits, [, safe [, add [, rem]]]) => bn * * === Parameters * * +bits+ - integer * * +safe+ - boolean * * +add+ - BN * * +rem+ - BN */ static VALUE ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass) { BIGNUM *add = NULL, *rem = NULL, *result; int safe = 1, num; VALUE vnum, vsafe, vadd, vrem, obj; rb_scan_args(argc, argv, "13", &vnum, &vsafe, &vadd, &vrem); num = NUM2INT(vnum); if (vsafe == Qfalse) { safe = 0; } if (!NIL_P(vadd)) { add = GetBNPtr(vadd); rem = NIL_P(vrem) ? NULL : GetBNPtr(vrem); } if (!(result = BN_new())) { ossl_raise(eBNError, NULL); } if (!BN_generate_prime(result, num, safe, add, rem, NULL, NULL)) { BN_free(result); ossl_raise(eBNError, NULL); } WrapBN(klass, obj, result); return obj; } #define BIGNUM_NUM(func) \ /* \ * call-seq: \ * bn.##func -> integer \ * \ */ \ static VALUE \ ossl_bn_##func(VALUE self) \ { \ BIGNUM *bn; \ GetBN(self, bn); \ return INT2FIX(BN_##func(bn)); \ } BIGNUM_NUM(num_bytes); BIGNUM_NUM(num_bits); static VALUE ossl_bn_copy(VALUE self, VALUE other) { BIGNUM *bn1, *bn2; rb_check_frozen(self); if (self == other) return self; GetBN(self, bn1); bn2 = GetBNPtr(other); if (!BN_copy(bn1, bn2)) { ossl_raise(eBNError, NULL); } return self; } #define BIGNUM_CMP(func) \ /* \ * call-seq: \ * bn.##func(bn2) -> integer \ * \ */ \ static VALUE \ ossl_bn_##func(VALUE self, VALUE other) \ { \ BIGNUM *bn1, *bn2 = GetBNPtr(other); \ GetBN(self, bn1); \ return INT2FIX(BN_##func(bn1, bn2)); \ } BIGNUM_CMP(cmp); BIGNUM_CMP(ucmp); static VALUE ossl_bn_eql(VALUE self, VALUE other) { if (ossl_bn_cmp(self, other) == INT2FIX(0)) { return Qtrue; } return Qfalse; } /* * call-seq: * bn.prime? => true | false * bn.prime?(checks) => true | false * * === Parameters * * +checks+ - integer */ static VALUE ossl_bn_is_prime(int argc, VALUE *argv, VALUE self) { BIGNUM *bn; VALUE vchecks; int checks = BN_prime_checks; if (rb_scan_args(argc, argv, "01", &vchecks) == 0) { checks = NUM2INT(vchecks); } GetBN(self, bn); switch (BN_is_prime(bn, checks, NULL, ossl_bn_ctx, NULL)) { case 1: return Qtrue; case 0: return Qfalse; default: ossl_raise(eBNError, NULL); } /* not reachable */ return Qnil; } /* * call-seq: * bn.prime_fasttest? => true | false * bn.prime_fasttest?(checks) => true | false * bn.prime_fasttest?(checks, trial_div) => true | false * * === Parameters * * +checks+ - integer * * +trial_div+ - boolean */ static VALUE ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self) { BIGNUM *bn; VALUE vchecks, vtrivdiv; int checks = BN_prime_checks, do_trial_division = 1; rb_scan_args(argc, argv, "02", &vchecks, &vtrivdiv); if (!NIL_P(vchecks)) { checks = NUM2INT(vchecks); } GetBN(self, bn); /* handle true/false */ if (vtrivdiv == Qfalse) { do_trial_division = 0; } switch (BN_is_prime_fasttest(bn, checks, NULL, ossl_bn_ctx, NULL, do_trial_division)) { case 1: return Qtrue; case 0: return Qfalse; default: ossl_raise(eBNError, NULL); } /* not reachable */ return Qnil; } /* * INIT * (NOTE: ordering of methods is the same as in 'man bn') */ void Init_ossl_bn() { #if 0 /* let rdoc know about mOSSL */ mOSSL = rb_define_module("OpenSSL"); #endif if (!(ossl_bn_ctx = BN_CTX_new())) { ossl_raise(rb_eRuntimeError, "Cannot init BN_CTX"); } eBNError = rb_define_class_under(mOSSL, "BNError", eOSSLError); cBN = rb_define_class_under(mOSSL, "BN", rb_cObject); rb_define_alloc_func(cBN, ossl_bn_alloc); rb_define_method(cBN, "initialize", ossl_bn_initialize, -1); rb_define_copy_func(cBN, ossl_bn_copy); rb_define_method(cBN, "copy", ossl_bn_copy, 1); /* swap (=coerce?) */ rb_define_method(cBN, "num_bytes", ossl_bn_num_bytes, 0); rb_define_method(cBN, "num_bits", ossl_bn_num_bits, 0); /* num_bits_word */ rb_define_method(cBN, "+", ossl_bn_add, 1); rb_define_method(cBN, "-", ossl_bn_sub, 1); rb_define_method(cBN, "*", ossl_bn_mul, 1); rb_define_method(cBN, "sqr", ossl_bn_sqr, 0); rb_define_method(cBN, "/", ossl_bn_div, 1); rb_define_method(cBN, "%", ossl_bn_mod, 1); /* nnmod */ rb_define_method(cBN, "mod_add", ossl_bn_mod_add, 2); rb_define_method(cBN, "mod_sub", ossl_bn_mod_sub, 2); rb_define_method(cBN, "mod_mul", ossl_bn_mod_mul, 2); rb_define_method(cBN, "mod_sqr", ossl_bn_mod_sqr, 1); rb_define_method(cBN, "**", ossl_bn_exp, 1); rb_define_method(cBN, "mod_exp", ossl_bn_mod_exp, 2); rb_define_method(cBN, "gcd", ossl_bn_gcd, 1); /* add_word * sub_word * mul_word * div_word * mod_word */ rb_define_method(cBN, "cmp", ossl_bn_cmp, 1); rb_define_alias(cBN, "<=>", "cmp"); rb_define_method(cBN, "ucmp", ossl_bn_ucmp, 1); rb_define_method(cBN, "eql?", ossl_bn_eql, 1); rb_define_alias(cBN, "==", "eql?"); rb_define_alias(cBN, "===", "eql?"); rb_define_method(cBN, "zero?", ossl_bn_is_zero, 0); rb_define_method(cBN, "one?", ossl_bn_is_one, 0); /* is_word */ rb_define_method(cBN, "odd?", ossl_bn_is_odd, 0); /* zero * one * value_one - DON'T IMPL. * set_word * get_word */ rb_define_singleton_method(cBN, "rand", ossl_bn_s_rand, -1); rb_define_singleton_method(cBN, "pseudo_rand", ossl_bn_s_pseudo_rand, -1); rb_define_singleton_method(cBN, "rand_range", ossl_bn_s_rand_range, 1); rb_define_singleton_method(cBN, "pseudo_rand_range", ossl_bn_s_pseudo_rand_range, 1); rb_define_singleton_method(cBN, "generate_prime", ossl_bn_s_generate_prime, -1); rb_define_method(cBN, "prime?", ossl_bn_is_prime, -1); rb_define_method(cBN, "set_bit!", ossl_bn_set_bit, 1); rb_define_method(cBN, "clear_bit!", ossl_bn_clear_bit, 1); rb_define_method(cBN, "bit_set?", ossl_bn_is_bit_set, 1); rb_define_method(cBN, "mask_bits!", ossl_bn_mask_bits, 1); rb_define_method(cBN, "<<", ossl_bn_lshift, 1); rb_define_method(cBN, ">>", ossl_bn_rshift, 1); rb_define_method(cBN, "lshift!", ossl_bn_self_lshift, 1); rb_define_method(cBN, "rshift!", ossl_bn_self_rshift, 1); /* lshift1 - DON'T IMPL. */ /* rshift1 - DON'T IMPL. */ /* * bn2bin * bin2bn * bn2hex * bn2dec * hex2bn * dec2bn - all these are implemented in ossl_bn_initialize, and ossl_bn_to_s * print - NOT IMPL. * print_fp - NOT IMPL. * bn2mpi * mpi2bn */ rb_define_method(cBN, "to_s", ossl_bn_to_s, -1); rb_define_method(cBN, "to_i", ossl_bn_to_i, 0); rb_define_alias(cBN, "to_int", "to_i"); rb_define_method(cBN, "to_bn", ossl_bn_to_bn, 0); rb_define_method(cBN, "coerce", ossl_bn_coerce, 1); /* * TODO: * But how to: from_bin, from_mpi? PACK? * to_bin * to_mpi */ rb_define_method(cBN, "mod_inverse", ossl_bn_mod_inverse, 1); /* RECiProcal * MONTgomery */ /* * TODO: * Where to belong these? */ rb_define_method(cBN, "prime_fasttest?", ossl_bn_is_prime_fasttest, -1); } ================================================ FILE: ext/openssl/ossl_bn.h ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(_OSSL_BN_H_) #define _OSSL_BN_H_ extern VALUE cBN; extern VALUE eBNError; extern BN_CTX *ossl_bn_ctx; VALUE ossl_bn_new(const BIGNUM *); BIGNUM *GetBNPtr(VALUE); void Init_ossl_bn(void); #endif /* _OSS_BN_H_ */ ================================================ FILE: ext/openssl/ossl_cipher.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" #define MakeCipher(obj, klass, ctx) \ obj = Data_Make_Struct(klass, EVP_CIPHER_CTX, 0, ossl_cipher_free, ctx) #define GetCipher(obj, ctx) do { \ Data_Get_Struct(obj, EVP_CIPHER_CTX, ctx); \ if (!ctx) { \ ossl_raise(rb_eRuntimeError, "Cipher not inititalized!"); \ } \ } while (0) #define SafeGetCipher(obj, ctx) do { \ OSSL_Check_Kind(obj, cCipher); \ GetCipher(obj, ctx); \ } while (0) /* * Classes */ VALUE cCipher; VALUE eCipherError; static VALUE ossl_cipher_alloc(VALUE klass); /* * PUBLIC */ const EVP_CIPHER * GetCipherPtr(VALUE obj) { EVP_CIPHER_CTX *ctx; SafeGetCipher(obj, ctx); return EVP_CIPHER_CTX_cipher(ctx); } VALUE ossl_cipher_new(const EVP_CIPHER *cipher) { VALUE ret; EVP_CIPHER_CTX *ctx; ret = ossl_cipher_alloc(cCipher); GetCipher(ret, ctx); EVP_CIPHER_CTX_init(ctx); if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1) ossl_raise(eCipherError, NULL); return ret; } /* * PRIVATE */ static void ossl_cipher_free(EVP_CIPHER_CTX *ctx) { if (ctx) { EVP_CIPHER_CTX_cleanup(ctx); free(ctx); } } static VALUE ossl_cipher_alloc(VALUE klass) { EVP_CIPHER_CTX *ctx; VALUE obj; MakeCipher(obj, klass, ctx); EVP_CIPHER_CTX_init(ctx); return obj; } /* * call-seq: * Cipher.new(string) -> cipher * * The string must contain a valid cipher name like "AES-128-CBC" or "3DES". * * A list of cipher names is available by calling OpenSSL::Cipher.ciphers. */ static VALUE ossl_cipher_initialize(VALUE self, VALUE str) { EVP_CIPHER_CTX *ctx; const EVP_CIPHER *cipher; char *name; name = StringValuePtr(str); GetCipher(self, ctx); if (!(cipher = EVP_get_cipherbyname(name))) { ossl_raise(rb_eRuntimeError, "unsupported cipher algorithm (%s)", name); } if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1) ossl_raise(eCipherError, NULL); return self; } static VALUE ossl_cipher_copy(VALUE self, VALUE other) { EVP_CIPHER_CTX *ctx1, *ctx2; rb_check_frozen(self); if (self == other) return self; GetCipher(self, ctx1); SafeGetCipher(other, ctx2); if (EVP_CIPHER_CTX_copy(ctx1, ctx2) != 1) ossl_raise(eCipherError, NULL); return self; } static void* add_cipher_name_to_ary(const OBJ_NAME *name, VALUE ary) { rb_ary_push(ary, rb_str_new2(name->name)); return NULL; } /* * call-seq: * Cipher.ciphers -> array[string...] * * Returns the names of all available ciphers in an array. */ static VALUE ossl_s_ciphers(VALUE self) { #ifdef HAVE_OBJ_NAME_DO_ALL_SORTED VALUE ary; ary = rb_ary_new(); OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, (void(*)(const OBJ_NAME*,void*))add_cipher_name_to_ary, (void*)ary); return ary; #else rb_notimplement(); #endif } /* * call-seq: * cipher.reset -> self * * Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1). */ static VALUE ossl_cipher_reset(VALUE self) { EVP_CIPHER_CTX *ctx; GetCipher(self, ctx); if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1) != 1) ossl_raise(eCipherError, NULL); return self; } static VALUE ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode) { EVP_CIPHER_CTX *ctx; unsigned char key[EVP_MAX_KEY_LENGTH], *p_key = NULL; unsigned char iv[EVP_MAX_IV_LENGTH], *p_iv = NULL; VALUE pass, init_v; if(rb_scan_args(argc, argv, "02", &pass, &init_v) > 0){ /* * oops. this code mistakes salt for IV. * We deprecated the arguments for this method, but we decided * keeping this behaviour for backward compatibility. */ const char *cname = rb_class2name(rb_obj_class(self)); rb_warn("argumtents for %s#encrypt and %s#decrypt were deprecated; " "use %s#pkcs5_keyivgen to derive key and IV", cname, cname, cname); StringValue(pass); GetCipher(self, ctx); if (NIL_P(init_v)) memcpy(iv, "OpenSSL for Ruby rulez!", sizeof(iv)); else{ StringValue(init_v); if (EVP_MAX_IV_LENGTH > RSTRING_LEN(init_v)) { memset(iv, 0, EVP_MAX_IV_LENGTH); memcpy(iv, RSTRING_PTR(init_v), RSTRING_LEN(init_v)); } else memcpy(iv, RSTRING_PTR(init_v), sizeof(iv)); } EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), EVP_md5(), iv, RSTRING_PTR(pass), RSTRING_LEN(pass), 1, key, NULL); p_key = key; p_iv = iv; } else { GetCipher(self, ctx); } if (EVP_CipherInit_ex(ctx, NULL, NULL, p_key, p_iv, mode) != 1) { ossl_raise(eCipherError, NULL); } return self; } /* * call-seq: * cipher.encrypt -> self * * Make sure to call .encrypt or .decrypt before using any of the following methods: * * [key=, iv=, random_key, random_iv, pkcs5_keyivgen] * * Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 1). */ static VALUE ossl_cipher_encrypt(int argc, VALUE *argv, VALUE self) { return ossl_cipher_init(argc, argv, self, 1); } /* * call-seq: * cipher.decrypt -> self * * Make sure to call .encrypt or .decrypt before using any of the following methods: * * [key=, iv=, random_key, random_iv, pkcs5_keyivgen] * * Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 0). */ static VALUE ossl_cipher_decrypt(int argc, VALUE *argv, VALUE self) { return ossl_cipher_init(argc, argv, self, 0); } /* * call-seq: * cipher.pkcs5_keyivgen(pass [, salt [, iterations [, digest]]] ) -> nil * * Generates and sets the key/iv based on a password. * * WARNING: This method is only PKCS5 v1.5 compliant when using RC2, RC4-40, or DES * with MD5 or SHA1. Using anything else (like AES) will generate the key/iv using an * OpenSSL specific method. Use a PKCS5 v2 key generation method instead. * * === Parameters * +salt+ must be an 8 byte string if provided. * +iterations+ is a integer with a default of 2048. * +digest+ is a Digest object that defaults to 'MD5' * * A minimum of 1000 iterations is recommended. * */ static VALUE ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self) { EVP_CIPHER_CTX *ctx; const EVP_MD *digest; VALUE vpass, vsalt, viter, vdigest; unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH], *salt = NULL; int iter; rb_scan_args(argc, argv, "13", &vpass, &vsalt, &viter, &vdigest); StringValue(vpass); if(!NIL_P(vsalt)){ StringValue(vsalt); if(RSTRING_LEN(vsalt) != PKCS5_SALT_LEN) rb_raise(eCipherError, "salt must be an 8-octet string"); salt = RSTRING_PTR(vsalt); } iter = NIL_P(viter) ? 2048 : NUM2INT(viter); digest = NIL_P(vdigest) ? EVP_md5() : GetDigestPtr(vdigest); GetCipher(self, ctx); EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), digest, salt, RSTRING_PTR(vpass), RSTRING_LEN(vpass), iter, key, iv); if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, -1) != 1) ossl_raise(eCipherError, NULL); OPENSSL_cleanse(key, sizeof key); OPENSSL_cleanse(iv, sizeof iv); return Qnil; } /* * call-seq: * cipher << data -> string * * === Parameters * +data+ is a nonempty string. * * This method is deprecated and not available in 1.9.x or later. */ static VALUE ossl_cipher_update_deprecated(VALUE self, VALUE data) { const char *cname; cname = rb_class2name(rb_obj_class(self)); rb_warning("%s#<< is deprecated; use %s#update instead", cname, cname); return rb_funcall(self, rb_intern("update"), 1, data); } /* * call-seq: * cipher.update(data [, buffer]) -> string or buffer * * === Parameters * +data+ is a nonempty string. * +buffer+ is an optional string to store the result. */ static VALUE ossl_cipher_update(int argc, VALUE *argv, VALUE self) { EVP_CIPHER_CTX *ctx; char *in; int in_len, out_len; VALUE data, str; rb_scan_args(argc, argv, "11", &data, &str); StringValue(data); in = RSTRING_PTR(data); if ((in_len = RSTRING_LEN(data)) == 0) rb_raise(rb_eArgError, "data must not be empty"); GetCipher(self, ctx); out_len = in_len+EVP_CIPHER_CTX_block_size(ctx); if (NIL_P(str)) { str = rb_str_new(0, out_len); } else { StringValue(str); rb_str_resize(str, out_len); } if (!EVP_CipherUpdate(ctx, RSTRING_PTR(str), &out_len, in, in_len)) ossl_raise(eCipherError, NULL); assert(out_len < RSTRING_LEN(str)); rb_str_set_len(str, out_len); return str; } /* * call-seq: * cipher.final -> aString * * Returns the remaining data held in the cipher object. Further calls to update() or final() will return garbage. * * See EVP_CipherFinal_ex for further information. */ static VALUE ossl_cipher_final(VALUE self) { EVP_CIPHER_CTX *ctx; int out_len; VALUE str; GetCipher(self, ctx); str = rb_str_new(0, EVP_CIPHER_CTX_block_size(ctx)); if (!EVP_CipherFinal_ex(ctx, RSTRING_PTR(str), &out_len)) ossl_raise(eCipherError, NULL); assert(out_len <= RSTRING_LEN(str)); rb_str_set_len(str, out_len); return str; } /* * call-seq: * cipher.name -> string * * Returns the name of the cipher which may differ slightly from the original name provided. */ static VALUE ossl_cipher_name(VALUE self) { EVP_CIPHER_CTX *ctx; GetCipher(self, ctx); return rb_str_new2(EVP_CIPHER_name(EVP_CIPHER_CTX_cipher(ctx))); } /* * call-seq: * cipher.key = string -> string * * Sets the cipher key. * * Only call this method after calling cipher.encrypt or cipher.decrypt. */ static VALUE ossl_cipher_set_key(VALUE self, VALUE key) { EVP_CIPHER_CTX *ctx; StringValue(key); GetCipher(self, ctx); if (RSTRING_LEN(key) < EVP_CIPHER_CTX_key_length(ctx)) ossl_raise(eCipherError, "key length too short"); if (EVP_CipherInit_ex(ctx, NULL, NULL, RSTRING_PTR(key), NULL, -1) != 1) ossl_raise(eCipherError, NULL); return key; } /* * call-seq: * cipher.iv = string -> string * * Sets the cipher iv. * * Only call this method after calling cipher.encrypt or cipher.decrypt. */ static VALUE ossl_cipher_set_iv(VALUE self, VALUE iv) { EVP_CIPHER_CTX *ctx; StringValue(iv); GetCipher(self, ctx); if (RSTRING_LEN(iv) < EVP_CIPHER_CTX_iv_length(ctx)) ossl_raise(eCipherError, "iv length too short"); if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, RSTRING_PTR(iv), -1) != 1) ossl_raise(eCipherError, NULL); return iv; } /* * call-seq: * cipher.key_length = integer -> integer * * Sets the key length of the cipher. If the cipher is a fixed length cipher then attempting to set the key * length to any value other than the fixed value is an error. * * Under normal circumstances you do not need to call this method (and probably shouldn't). * * See EVP_CIPHER_CTX_set_key_length for further information. */ static VALUE ossl_cipher_set_key_length(VALUE self, VALUE key_length) { int len = NUM2INT(key_length); EVP_CIPHER_CTX *ctx; GetCipher(self, ctx); if (EVP_CIPHER_CTX_set_key_length(ctx, len) != 1) ossl_raise(eCipherError, NULL); return key_length; } /* * call-seq: * cipher.padding = integer -> integer * * Enables or disables padding. By default encryption operations are padded using standard block padding and the * padding is checked and removed when decrypting. If the pad parameter is zero then no padding is performed, the * total amount of data encrypted or decrypted must then be a multiple of the block size or an error will occur. * * See EVP_CIPHER_CTX_set_padding for further information. */ static VALUE ossl_cipher_set_padding(VALUE self, VALUE padding) { #if defined(HAVE_EVP_CIPHER_CTX_SET_PADDING) EVP_CIPHER_CTX *ctx; int pad = NUM2INT(padding); GetCipher(self, ctx); if (EVP_CIPHER_CTX_set_padding(ctx, pad) != 1) ossl_raise(eCipherError, NULL); #else rb_notimplement(); #endif return padding; } #define CIPHER_0ARG_INT(func) \ static VALUE \ ossl_cipher_##func(VALUE self) \ { \ EVP_CIPHER_CTX *ctx; \ GetCipher(self, ctx); \ return INT2NUM(EVP_CIPHER_##func(EVP_CIPHER_CTX_cipher(ctx))); \ } CIPHER_0ARG_INT(key_length) CIPHER_0ARG_INT(iv_length) CIPHER_0ARG_INT(block_size) #if 0 /* * call-seq: * cipher.key_length -> integer * */ static VALUE ossl_cipher_key_length() { } /* * call-seq: * cipher.iv_length -> integer * */ static VALUE ossl_cipher_iv_length() { } /* * call-seq: * cipher.block_size -> integer * */ static VALUE ossl_cipher_block_size() { } #endif /* * INIT */ void Init_ossl_cipher(void) { #if 0 /* let rdoc know about mOSSL */ mOSSL = rb_define_module("OpenSSL"); #endif cCipher = rb_define_class_under(mOSSL, "Cipher", rb_cObject); eCipherError = rb_define_class_under(cCipher, "CipherError", eOSSLError); rb_define_alloc_func(cCipher, ossl_cipher_alloc); rb_define_copy_func(cCipher, ossl_cipher_copy); rb_define_module_function(cCipher, "ciphers", ossl_s_ciphers, 0); rb_define_method(cCipher, "initialize", ossl_cipher_initialize, 1); rb_define_method(cCipher, "reset", ossl_cipher_reset, 0); rb_define_method(cCipher, "encrypt", ossl_cipher_encrypt, -1); rb_define_method(cCipher, "decrypt", ossl_cipher_decrypt, -1); rb_define_method(cCipher, "pkcs5_keyivgen", ossl_cipher_pkcs5_keyivgen, -1); rb_define_method(cCipher, "update", ossl_cipher_update, -1); #if RUBY_VERSION_CODE < 190 rb_define_method(cCipher, "<<", ossl_cipher_update_deprecated, 1); #endif rb_define_method(cCipher, "final", ossl_cipher_final, 0); rb_define_method(cCipher, "name", ossl_cipher_name, 0); rb_define_method(cCipher, "key=", ossl_cipher_set_key, 1); rb_define_method(cCipher, "key_len=", ossl_cipher_set_key_length, 1); rb_define_method(cCipher, "key_len", ossl_cipher_key_length, 0); rb_define_method(cCipher, "iv=", ossl_cipher_set_iv, 1); rb_define_method(cCipher, "iv_len", ossl_cipher_iv_length, 0); rb_define_method(cCipher, "block_size", ossl_cipher_block_size, 0); rb_define_method(cCipher, "padding=", ossl_cipher_set_padding, 1); } ================================================ FILE: ext/openssl/ossl_cipher.h ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(_OSSL_CIPHER_H_) #define _OSSL_CIPHER_H_ extern VALUE cCipher; extern VALUE eCipherError; const EVP_CIPHER *GetCipherPtr(VALUE); VALUE ossl_cipher_new(const EVP_CIPHER *); void Init_ossl_cipher(void); #endif /* _OSSL_CIPHER_H_ */ ================================================ FILE: ext/openssl/ossl_config.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" #define WrapConfig(klass, obj, conf) do { \ if (!conf) { \ ossl_raise(rb_eRuntimeError, "Config wasn't intitialized!"); \ } \ obj = Data_Wrap_Struct(klass, 0, NCONF_free, conf); \ } while (0) #define GetConfig(obj, conf) do { \ Data_Get_Struct(obj, CONF, conf); \ if (!conf) { \ ossl_raise(rb_eRuntimeError, "Config wasn't intitialized!"); \ } \ } while (0) #define SafeGetConfig(obj, conf) do { \ OSSL_Check_Kind(obj, cConfig); \ GetConfig(obj, conf); \ } while(0); /* * Classes */ VALUE cConfig; VALUE eConfigError; /* * Public */ static CONF *parse_config(VALUE, CONF*); CONF * GetConfigPtr(VALUE obj) { CONF *conf; SafeGetConfig(obj, conf); return conf; } CONF * DupConfigPtr(VALUE obj) { VALUE str; OSSL_Check_Kind(obj, cConfig); str = rb_funcall(obj, rb_intern("to_s"), 0); return parse_config(str, NULL); } /* * Private */ static CONF * parse_config(VALUE str, CONF *dst) { CONF *conf; BIO *bio; long eline = -1; bio = ossl_obj2bio(str); conf = dst ? dst : NCONF_new(NULL); if(!conf){ BIO_free(bio); ossl_raise(eConfigError, NULL); } if(!NCONF_load_bio(conf, bio, &eline)){ BIO_free(bio); if(!dst) NCONF_free(conf); if (eline <= 0) ossl_raise(eConfigError, "wrong config format"); else ossl_raise(eConfigError, "error in line %d", eline); ossl_raise(eConfigError, NULL); } BIO_free(bio); return conf; } static VALUE ossl_config_s_parse(VALUE klass, VALUE str) { CONF *conf; VALUE obj; conf = parse_config(str, NULL); WrapConfig(klass, obj, conf); return obj; } static VALUE ossl_config_s_alloc(VALUE klass) { CONF *conf; VALUE obj; if(!(conf = NCONF_new(NULL))) ossl_raise(eConfigError, NULL); WrapConfig(klass, obj, conf); return obj; } static VALUE ossl_config_copy(VALUE self, VALUE other) { VALUE str; CONF *conf; str = rb_funcall(self, rb_intern("to_s"), 0); GetConfig(other, conf); parse_config(str, conf); return self; } static VALUE ossl_config_initialize(int argc, VALUE *argv, VALUE self) { CONF *conf; long eline = -1; char *filename; VALUE path; rb_scan_args(argc, argv, "01", &path); if(!NIL_P(path)){ SafeStringValue(path); filename = StringValuePtr(path); GetConfig(self, conf); if (!NCONF_load(conf, filename, &eline)){ if (eline <= 0) ossl_raise(eConfigError, "wrong config file %s", filename); else ossl_raise(eConfigError, "error in %s:%d", filename, eline); } } #ifdef OSSL_NO_CONF_API else rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)"); #else else { GetConfig(self, conf); _CONF_new_data(conf); } #endif return self; } static void rb_ossl_config_modify_check(VALUE config) { if (OBJ_FROZEN(config)) rb_error_frozen("OpenSSL::Config"); if (!OBJ_TAINTED(config) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify OpenSSL config"); } static VALUE ossl_config_add_value(VALUE self, VALUE section, VALUE name, VALUE value) { #ifdef OSSL_NO_CONF_API rb_notimplement(); #else CONF *conf; CONF_VALUE *sv, *cv; rb_ossl_config_modify_check(self); StringValue(section); StringValue(name); StringValue(value); GetConfig(self, conf); if(!(sv = _CONF_get_section(conf, RSTRING_PTR(section)))){ if(!(sv = _CONF_new_section(conf, RSTRING_PTR(section)))){ ossl_raise(eConfigError, NULL); } } if(!(cv = OPENSSL_malloc(sizeof(CONF_VALUE)))){ ossl_raise(eConfigError, NULL); } cv->name = BUF_strdup(RSTRING_PTR(name)); cv->value = BUF_strdup(RSTRING_PTR(value)); if(!cv->name || !cv->value || !_CONF_add_string(conf, sv, cv)){ OPENSSL_free(cv->name); OPENSSL_free(cv->value); OPENSSL_free(cv); ossl_raise(eConfigError, "_CONF_add_string failure"); } return value; #endif } static VALUE ossl_config_get_value(VALUE self, VALUE section, VALUE name) { CONF *conf; char *str; StringValue(section); StringValue(name); GetConfig(self, conf); str = NCONF_get_string(conf, RSTRING_PTR(section), RSTRING_PTR(name)); if(!str){ ERR_clear_error(); return Qnil; } return rb_str_new2(str); } static VALUE ossl_config_get_value_old(int argc, VALUE *argv, VALUE self) { VALUE section, name; rb_scan_args(argc, argv, "11", §ion, &name); /* support conf.value(nil, "HOME") -> conf.get_value("", "HOME") */ if (NIL_P(section)) section = rb_str_new2(""); /* support conf.value("HOME") -> conf.get_value("", "HOME") */ if (NIL_P(name)) { name = section; section = rb_str_new2(""); } /* NOTE: Don't care about conf.get_value(nil, nil) */ rb_warn("Config#value is deprecated; use Config#get_value"); return ossl_config_get_value(self, section, name); } static VALUE set_conf_section_i(VALUE i, VALUE *arg) { VALUE name, value; Check_Type(i, T_ARRAY); name = rb_ary_entry(i, 0); value = rb_ary_entry(i, 1); ossl_config_add_value(arg[0], arg[1], name, value); return Qnil; } static VALUE ossl_config_set_section(VALUE self, VALUE section, VALUE hash) { VALUE arg[2]; rb_ossl_config_modify_check(self); arg[0] = self; arg[1] = section; rb_block_call(hash, rb_intern("each"), 0, 0, set_conf_section_i, (VALUE)arg); return hash; } /* * Get all numbers as strings - use str.to_i to convert * long number = CONF_get_number(confp->config, sect, StringValuePtr(item)); */ static VALUE ossl_config_get_section(VALUE self, VALUE section) { CONF *conf; STACK_OF(CONF_VALUE) *sk; CONF_VALUE *entry; int i, entries; VALUE hash; hash = rb_hash_new(); StringValue(section); GetConfig(self, conf); if (!(sk = NCONF_get_section(conf, StringValuePtr(section)))) { ERR_clear_error(); return hash; } if ((entries = sk_CONF_VALUE_num(sk)) < 0) { OSSL_Debug("# of items in section is < 0?!?"); return hash; } for (i=0; iname), rb_str_new2(entry->value)); } return hash; } static VALUE ossl_config_get_section_old(VALUE self, VALUE section) { rb_warn("Config#section is deprecated; use Config#[]"); return ossl_config_get_section(self, section); } #ifdef IMPLEMENT_LHASH_DOALL_ARG_FN static void get_conf_section(CONF_VALUE *cv, VALUE ary) { if(cv->name) return; rb_ary_push(ary, rb_str_new2(cv->section)); } static IMPLEMENT_LHASH_DOALL_ARG_FN(get_conf_section, CONF_VALUE*, VALUE); static VALUE ossl_config_get_sections(VALUE self) { CONF *conf; VALUE ary; GetConfig(self, conf); ary = rb_ary_new(); lh_doall_arg(conf->data, LHASH_DOALL_ARG_FN(get_conf_section), (void*)ary); return ary; } static void dump_conf_value(CONF_VALUE *cv, VALUE str) { STACK_OF(CONF_VALUE) *sk; CONF_VALUE *v; int i, num; if (cv->name) return; sk = (STACK_OF(CONF_VALUE)*)cv->value; num = sk_CONF_VALUE_num(sk); rb_str_cat2(str, "[ "); rb_str_cat2(str, cv->section); rb_str_cat2(str, " ]\n"); for(i = 0; i < num; i++){ v = sk_CONF_VALUE_value(sk, i); rb_str_cat2(str, v->name ? v->name : "None"); rb_str_cat2(str, "="); rb_str_cat2(str, v->value ? v->value : "None"); rb_str_cat2(str, "\n"); } rb_str_cat2(str, "\n"); } static IMPLEMENT_LHASH_DOALL_ARG_FN(dump_conf_value, CONF_VALUE*, VALUE); static VALUE dump_conf(CONF *conf) { VALUE str; str = rb_str_new(0, 0); lh_doall_arg(conf->data, LHASH_DOALL_ARG_FN(dump_conf_value), (void*)str); return str; } static VALUE ossl_config_to_s(VALUE self) { CONF *conf; GetConfig(self, conf); return dump_conf(conf); } static void each_conf_value(CONF_VALUE *cv, void* dummy) { STACK_OF(CONF_VALUE) *sk; CONF_VALUE *v; VALUE section, name, value, args; int i, num; if (cv->name) return; sk = (STACK_OF(CONF_VALUE)*)cv->value; num = sk_CONF_VALUE_num(sk); section = rb_str_new2(cv->section); for(i = 0; i < num; i++){ v = sk_CONF_VALUE_value(sk, i); name = v->name ? rb_str_new2(v->name) : Qnil; value = v->value ? rb_str_new2(v->value) : Qnil; args = rb_ary_new3(3, section, name, value); rb_yield(args); } } static IMPLEMENT_LHASH_DOALL_ARG_FN(each_conf_value, CONF_VALUE*, void*); static VALUE ossl_config_each(VALUE self) { CONF *conf; GetConfig(self, conf); lh_doall_arg(conf->data, LHASH_DOALL_ARG_FN(each_conf_value), (void*)NULL); return self; } #else static VALUE ossl_config_get_sections(VALUE self) { rb_warn("#sections don't work with %s", OPENSSL_VERSION_TEXT); return rb_ary_new(); } static VALUE ossl_config_to_s(VALUE self) { rb_warn("#to_s don't work with %s", OPENSSL_VERSION_TEXT); return rb_str_new(0, 0); } static VALUE ossl_config_each(VALUE self) { rb_warn("#each don't work with %s", OPENSSL_VERSION_TEXT); return self; } #endif static VALUE ossl_config_inspect(VALUE self) { VALUE str, ary = ossl_config_get_sections(self); char *cname = rb_class2name(rb_obj_class(self)); str = rb_str_new2("#<"); rb_str_cat2(str, cname); rb_str_cat2(str, " sections="); rb_str_append(str, rb_inspect(ary)); rb_str_cat2(str, ">"); return str; } /* * INIT */ void Init_ossl_config() { eConfigError = rb_define_class_under(mOSSL, "ConfigError", eOSSLError); cConfig = rb_define_class_under(mOSSL, "Config", rb_cObject); rb_define_const(cConfig, "DEFAULT_CONFIG_FILE", rb_str_new2(CONF_get1_default_config_file())); rb_include_module(cConfig, rb_mEnumerable); rb_define_singleton_method(cConfig, "parse", ossl_config_s_parse, 1); rb_define_alias(CLASS_OF(cConfig), "load", "new"); rb_define_alloc_func(cConfig, ossl_config_s_alloc); rb_define_copy_func(cConfig, ossl_config_copy); rb_define_method(cConfig, "initialize", ossl_config_initialize, -1); rb_define_method(cConfig, "get_value", ossl_config_get_value, 2); rb_define_method(cConfig, "value", ossl_config_get_value_old, -1); rb_define_method(cConfig, "add_value", ossl_config_add_value, 3); rb_define_method(cConfig, "[]", ossl_config_get_section, 1); rb_define_method(cConfig, "section", ossl_config_get_section_old, 1); rb_define_method(cConfig, "[]=", ossl_config_set_section, 2); rb_define_method(cConfig, "sections", ossl_config_get_sections, 0); rb_define_method(cConfig, "to_s", ossl_config_to_s, 0); rb_define_method(cConfig, "each", ossl_config_each, 0); rb_define_method(cConfig, "inspect", ossl_config_inspect, 0); } ================================================ FILE: ext/openssl/ossl_config.h ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(_OSSL_CONFIG_H_) #define _OSSL_CONFIG_H_ extern VALUE cConfig; extern VALUE eConfigError; CONF* GetConfigPtr(VALUE obj); CONF* DupConfigPtr(VALUE obj); void Init_ossl_config(void); #endif /* _OSSL_CONFIG_H_ */ ================================================ FILE: ext/openssl/ossl_digest.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" #define GetDigest(obj, ctx) do { \ Data_Get_Struct(obj, EVP_MD_CTX, ctx); \ if (!ctx) { \ ossl_raise(rb_eRuntimeError, "Digest CTX wasn't initialized!"); \ } \ } while (0) #define SafeGetDigest(obj, ctx) do { \ OSSL_Check_Kind(obj, cDigest); \ GetDigest(obj, ctx); \ } while (0) /* * Classes */ VALUE cDigest; VALUE eDigestError; static VALUE ossl_digest_alloc(VALUE klass); /* * Public */ const EVP_MD * GetDigestPtr(VALUE obj) { const EVP_MD *md; if (TYPE(obj) == T_STRING) { const char *name = STR2CSTR(obj); md = EVP_get_digestbyname(name); if (!md) ossl_raise(rb_eRuntimeError, "Unsupported digest algorithm (%s).", name); } else { EVP_MD_CTX *ctx; SafeGetDigest(obj, ctx); md = EVP_MD_CTX_md(ctx); } return md; } VALUE ossl_digest_new(const EVP_MD *md) { VALUE ret; EVP_MD_CTX *ctx; ret = ossl_digest_alloc(cDigest); GetDigest(ret, ctx); EVP_DigestInit_ex(ctx, md, NULL); return ret; } /* * Private */ static VALUE ossl_digest_alloc(VALUE klass) { EVP_MD_CTX *ctx; VALUE obj; ctx = EVP_MD_CTX_create(); if (ctx == NULL) ossl_raise(rb_eRuntimeError, "EVP_MD_CTX_create() failed"); obj = Data_Wrap_Struct(klass, 0, EVP_MD_CTX_destroy, ctx); return obj; } VALUE ossl_digest_update(VALUE, VALUE); /* * call-seq: * Digest.new(string) -> digest * */ static VALUE ossl_digest_initialize(int argc, VALUE *argv, VALUE self) { EVP_MD_CTX *ctx; const EVP_MD *md; char *name; VALUE type, data; rb_scan_args(argc, argv, "11", &type, &data); md = GetDigestPtr(type); if (!NIL_P(data)) StringValue(data); GetDigest(self, ctx); EVP_DigestInit_ex(ctx, md, NULL); if (!NIL_P(data)) return ossl_digest_update(self, data); return self; } static VALUE ossl_digest_copy(VALUE self, VALUE other) { EVP_MD_CTX *ctx1, *ctx2; rb_check_frozen(self); if (self == other) return self; GetDigest(self, ctx1); SafeGetDigest(other, ctx2); if (!EVP_MD_CTX_copy(ctx1, ctx2)) { ossl_raise(eDigestError, NULL); } return self; } /* * call-seq: * digest.reset -> self * */ static VALUE ossl_digest_reset(VALUE self) { EVP_MD_CTX *ctx; GetDigest(self, ctx); EVP_DigestInit_ex(ctx, EVP_MD_CTX_md(ctx), NULL); return self; } /* * call-seq: * digest.update(string) -> aString * */ VALUE ossl_digest_update(VALUE self, VALUE data) { EVP_MD_CTX *ctx; StringValue(data); GetDigest(self, ctx); EVP_DigestUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)); return self; } /* * call-seq: * digest.finish -> aString * */ static VALUE ossl_digest_finish(int argc, VALUE *argv, VALUE self) { EVP_MD_CTX *ctx; VALUE str; rb_scan_args(argc, argv, "01", &str); GetDigest(self, ctx); if (NIL_P(str)) { str = rb_str_new(NULL, EVP_MD_CTX_size(ctx)); } else { StringValue(str); rb_str_resize(str, EVP_MD_CTX_size(ctx)); } EVP_DigestFinal_ex(ctx, RSTRING_PTR(str), NULL); return str; } /* * call-seq: * digest.name -> string * */ static VALUE ossl_digest_name(VALUE self) { EVP_MD_CTX *ctx; GetDigest(self, ctx); return rb_str_new2(EVP_MD_name(EVP_MD_CTX_md(ctx))); } /* * call-seq: * digest.digest_size -> integer * * Returns the output size of the digest. */ static VALUE ossl_digest_size(VALUE self) { EVP_MD_CTX *ctx; GetDigest(self, ctx); return INT2NUM(EVP_MD_CTX_size(ctx)); } static VALUE ossl_digest_block_length(VALUE self) { EVP_MD_CTX *ctx; GetDigest(self, ctx); return INT2NUM(EVP_MD_CTX_block_size(ctx)); } /* * INIT */ void Init_ossl_digest() { rb_require("openssl"); rb_require("digest"); #if 0 /* let rdoc know about mOSSL */ mOSSL = rb_define_module("OpenSSL"); #endif cDigest = rb_define_class_under(mOSSL, "Digest", rb_path2class("Digest::Class")); eDigestError = rb_define_class_under(cDigest, "DigestError", eOSSLError); rb_define_alloc_func(cDigest, ossl_digest_alloc); rb_define_method(cDigest, "initialize", ossl_digest_initialize, -1); rb_define_copy_func(cDigest, ossl_digest_copy); rb_define_method(cDigest, "reset", ossl_digest_reset, 0); rb_define_method(cDigest, "update", ossl_digest_update, 1); rb_define_alias(cDigest, "<<", "update"); rb_define_private_method(cDigest, "finish", ossl_digest_finish, -1); rb_define_method(cDigest, "digest_length", ossl_digest_size, 0); rb_define_method(cDigest, "block_length", ossl_digest_block_length, 0); rb_define_method(cDigest, "name", ossl_digest_name, 0); } ================================================ FILE: ext/openssl/ossl_digest.h ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(_OSSL_DIGEST_H_) #define _OSSL_DIGEST_H_ extern VALUE cDigest; extern VALUE eDigestError; const EVP_MD *GetDigestPtr(VALUE); VALUE ossl_digest_new(const EVP_MD *); void Init_ossl_digest(void); #endif /* _OSSL_DIGEST_H_ */ ================================================ FILE: ext/openssl/ossl_engine.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2003 GOTOU Yuuzou * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" #if defined(OSSL_ENGINE_ENABLED) #define WrapEngine(klass, obj, engine) do { \ if (!engine) { \ ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \ } \ obj = Data_Wrap_Struct(klass, 0, ENGINE_free, engine); \ } while(0) #define GetEngine(obj, engine) do { \ Data_Get_Struct(obj, ENGINE, engine); \ if (!engine) { \ ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \ } \ } while (0) #define SafeGetEngine(obj, engine) do { \ OSSL_Check_Kind(obj, cEngine); \ GetPKCS7(obj, engine); \ } while (0) /* * Classes */ VALUE cEngine; VALUE eEngineError; /* * Private */ #define OSSL_ENGINE_LOAD_IF_MATCH(x) \ do{\ if(!strcmp(#x, RSTRING_PTR(name))){\ ENGINE_load_##x();\ return Qtrue;\ }\ }while(0) static VALUE ossl_engine_s_load(int argc, VALUE *argv, VALUE klass) { #if !defined(HAVE_ENGINE_LOAD_BUILTIN_ENGINES) return Qnil; #else VALUE name; rb_scan_args(argc, argv, "01", &name); if(NIL_P(name)){ ENGINE_load_builtin_engines(); return Qtrue; } StringValue(name); #ifndef OPENSSL_NO_STATIC_ENGINE OSSL_ENGINE_LOAD_IF_MATCH(dynamic); OSSL_ENGINE_LOAD_IF_MATCH(cswift); OSSL_ENGINE_LOAD_IF_MATCH(chil); OSSL_ENGINE_LOAD_IF_MATCH(atalla); OSSL_ENGINE_LOAD_IF_MATCH(nuron); OSSL_ENGINE_LOAD_IF_MATCH(ubsec); OSSL_ENGINE_LOAD_IF_MATCH(aep); OSSL_ENGINE_LOAD_IF_MATCH(sureware); OSSL_ENGINE_LOAD_IF_MATCH(4758cca); #endif #ifdef HAVE_ENGINE_LOAD_OPENBSD_DEV_CRYPTO OSSL_ENGINE_LOAD_IF_MATCH(openbsd_dev_crypto); #endif OSSL_ENGINE_LOAD_IF_MATCH(openssl); rb_warning("no such builtin loader for `%s'", RSTRING_PTR(name)); return Qnil; #endif /* HAVE_ENGINE_LOAD_BUILTIN_ENGINES */ } static VALUE ossl_engine_s_cleanup(VALUE self) { #if defined(HAVE_ENGINE_CLEANUP) ENGINE_cleanup(); #endif return Qnil; } static VALUE ossl_engine_s_engines(VALUE klass) { ENGINE *e; VALUE ary, obj; ary = rb_ary_new(); for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)){ WrapEngine(klass, obj, e); rb_ary_push(ary, obj); } return ary; } static VALUE ossl_engine_s_by_id(VALUE klass, VALUE id) { ENGINE *e; VALUE obj; StringValue(id); ossl_engine_s_load(1, &id, klass); if(!(e = ENGINE_by_id(RSTRING_PTR(id)))) ossl_raise(eEngineError, NULL); WrapEngine(klass, obj, e); if(rb_block_given_p()) rb_yield(obj); if(!ENGINE_init(e)) ossl_raise(eEngineError, NULL); ENGINE_ctrl(e, ENGINE_CTRL_SET_PASSWORD_CALLBACK, 0, NULL, (void(*)())ossl_pem_passwd_cb); ERR_clear_error(); return obj; } static VALUE ossl_engine_s_alloc(VALUE klass) { ENGINE *e; VALUE obj; if (!(e = ENGINE_new())) { ossl_raise(eEngineError, NULL); } WrapEngine(klass, obj, e); return obj; } static VALUE ossl_engine_get_id(VALUE self) { ENGINE *e; GetEngine(self, e); return rb_str_new2(ENGINE_get_id(e)); } static VALUE ossl_engine_get_name(VALUE self) { ENGINE *e; GetEngine(self, e); return rb_str_new2(ENGINE_get_name(e)); } static VALUE ossl_engine_finish(VALUE self) { ENGINE *e; GetEngine(self, e); if(!ENGINE_finish(e)) ossl_raise(eEngineError, NULL); return Qnil; } static VALUE ossl_engine_get_cipher(VALUE self, VALUE name) { #if defined(HAVE_ENGINE_GET_CIPHER) ENGINE *e; const EVP_CIPHER *ciph, *tmp; char *s; int nid; s = StringValuePtr(name); tmp = EVP_get_cipherbyname(s); if(!tmp) ossl_raise(eEngineError, "no such cipher `%s'", s); nid = EVP_CIPHER_nid(tmp); GetEngine(self, e); ciph = ENGINE_get_cipher(e, nid); if(!ciph) ossl_raise(eEngineError, NULL); return ossl_cipher_new(ciph); #else rb_notimplement(); #endif } static VALUE ossl_engine_get_digest(VALUE self, VALUE name) { #if defined(HAVE_ENGINE_GET_DIGEST) ENGINE *e; const EVP_MD *md, *tmp; char *s; int nid; s = StringValuePtr(name); tmp = EVP_get_digestbyname(s); if(!tmp) ossl_raise(eEngineError, "no such digest `%s'", s); nid = EVP_MD_nid(tmp); GetEngine(self, e); md = ENGINE_get_digest(e, nid); if(!md) ossl_raise(eEngineError, NULL); return ossl_digest_new(md); #else rb_notimplement(); #endif } static VALUE ossl_engine_load_privkey(int argc, VALUE *argv, VALUE self) { ENGINE *e; EVP_PKEY *pkey; VALUE id, data, obj; char *sid, *sdata; rb_scan_args(argc, argv, "02", &id, &data); sid = NIL_P(id) ? NULL : StringValuePtr(id); sdata = NIL_P(data) ? NULL : StringValuePtr(data); GetEngine(self, e); #if OPENSSL_VERSION_NUMBER < 0x00907000L pkey = ENGINE_load_private_key(e, sid, sdata); #else pkey = ENGINE_load_private_key(e, sid, NULL, sdata); #endif if (!pkey) ossl_raise(eEngineError, NULL); obj = ossl_pkey_new(pkey); OSSL_PKEY_SET_PRIVATE(obj); return obj; } static VALUE ossl_engine_load_pubkey(int argc, VALUE *argv, VALUE self) { ENGINE *e; EVP_PKEY *pkey; VALUE id, data; char *sid, *sdata; rb_scan_args(argc, argv, "02", &id, &data); sid = NIL_P(id) ? NULL : StringValuePtr(id); sdata = NIL_P(data) ? NULL : StringValuePtr(data); GetEngine(self, e); #if OPENSSL_VERSION_NUMBER < 0x00907000L pkey = ENGINE_load_public_key(e, sid, sdata); #else pkey = ENGINE_load_public_key(e, sid, NULL, sdata); #endif if (!pkey) ossl_raise(eEngineError, NULL); return ossl_pkey_new(pkey); } static VALUE ossl_engine_set_default(VALUE self, VALUE flag) { ENGINE *e; int f = NUM2INT(flag); GetEngine(self, e); ENGINE_set_default(e, f); return Qtrue; } static VALUE ossl_engine_ctrl_cmd(int argc, VALUE *argv, VALUE self) { ENGINE *e; VALUE cmd, val; int ret; GetEngine(self, e); rb_scan_args(argc, argv, "11", &cmd, &val); StringValue(cmd); if (!NIL_P(val)) StringValue(val); ret = ENGINE_ctrl_cmd_string(e, RSTRING_PTR(cmd), NIL_P(val) ? NULL : RSTRING_PTR(val), 0); if (!ret) ossl_raise(eEngineError, NULL); return self; } static VALUE ossl_engine_cmd_flag_to_name(int flag) { switch(flag){ case ENGINE_CMD_FLAG_NUMERIC: return rb_str_new2("NUMERIC"); case ENGINE_CMD_FLAG_STRING: return rb_str_new2("STRING"); case ENGINE_CMD_FLAG_NO_INPUT: return rb_str_new2("NO_INPUT"); case ENGINE_CMD_FLAG_INTERNAL: return rb_str_new2("INTERNAL"); default: return rb_str_new2("UNKNOWN"); } } static VALUE ossl_engine_get_cmds(VALUE self) { ENGINE *e; const ENGINE_CMD_DEFN *defn, *p; VALUE ary, tmp; GetEngine(self, e); ary = rb_ary_new(); if ((defn = ENGINE_get_cmd_defns(e)) != NULL){ for (p = defn; p->cmd_num > 0; p++){ tmp = rb_ary_new(); rb_ary_push(tmp, rb_str_new2(p->cmd_name)); rb_ary_push(tmp, rb_str_new2(p->cmd_desc)); rb_ary_push(tmp, ossl_engine_cmd_flag_to_name(p->cmd_flags)); rb_ary_push(ary, tmp); } } return ary; } static VALUE ossl_engine_inspect(VALUE self) { VALUE str; char *cname = rb_class2name(rb_obj_class(self)); str = rb_str_new2("#<"); rb_str_cat2(str, cname); rb_str_cat2(str, " id=\""); rb_str_append(str, ossl_engine_get_id(self)); rb_str_cat2(str, "\" name=\""); rb_str_append(str, ossl_engine_get_name(self)); rb_str_cat2(str, "\">"); return str; } #define DefEngineConst(x) rb_define_const(cEngine, #x, INT2NUM(ENGINE_##x)) void Init_ossl_engine() { cEngine = rb_define_class_under(mOSSL, "Engine", rb_cObject); eEngineError = rb_define_class_under(cEngine, "EngineError", eOSSLError); rb_define_alloc_func(cEngine, ossl_engine_s_alloc); rb_define_singleton_method(cEngine, "load", ossl_engine_s_load, -1); rb_define_singleton_method(cEngine, "cleanup", ossl_engine_s_cleanup, 0); rb_define_singleton_method(cEngine, "engines", ossl_engine_s_engines, 0); rb_define_singleton_method(cEngine, "by_id", ossl_engine_s_by_id, 1); rb_undef_method(CLASS_OF(cEngine), "new"); rb_define_method(cEngine, "id", ossl_engine_get_id, 0); rb_define_method(cEngine, "name", ossl_engine_get_name, 0); rb_define_method(cEngine, "finish", ossl_engine_finish, 0); rb_define_method(cEngine, "cipher", ossl_engine_get_cipher, 1); rb_define_method(cEngine, "digest", ossl_engine_get_digest, 1); rb_define_method(cEngine, "load_private_key", ossl_engine_load_privkey, -1); rb_define_method(cEngine, "load_public_key", ossl_engine_load_pubkey, -1); rb_define_method(cEngine, "set_default", ossl_engine_set_default, 1); rb_define_method(cEngine, "ctrl_cmd", ossl_engine_ctrl_cmd, -1); rb_define_method(cEngine, "cmds", ossl_engine_get_cmds, 0); rb_define_method(cEngine, "inspect", ossl_engine_inspect, 0); DefEngineConst(METHOD_RSA); DefEngineConst(METHOD_DSA); DefEngineConst(METHOD_DH); DefEngineConst(METHOD_RAND); #ifdef ENGINE_METHOD_BN_MOD_EXP DefEngineConst(METHOD_BN_MOD_EXP); #endif #ifdef ENGINE_METHOD_BN_MOD_EXP_CRT DefEngineConst(METHOD_BN_MOD_EXP_CRT); #endif #ifdef ENGINE_METHOD_CIPHERS DefEngineConst(METHOD_CIPHERS); #endif #ifdef ENGINE_METHOD_DIGESTS DefEngineConst(METHOD_DIGESTS); #endif DefEngineConst(METHOD_ALL); DefEngineConst(METHOD_NONE); } #else void Init_ossl_engine() { } #endif ================================================ FILE: ext/openssl/ossl_engine.h ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2003 Michal Rokos * Copyright (C) 2003 GOTOU Yuuzou * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(OSSL_ENGINE_H) #define OSSL_ENGINE_H extern VALUE cEngine; extern VALUE eEngineError; void Init_ossl_engine(void); #endif /* OSSL_ENGINE_H */ ================================================ FILE: ext/openssl/ossl_hmac.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(OPENSSL_NO_HMAC) #include "ossl.h" #define MakeHMAC(obj, klass, ctx) \ obj = Data_Make_Struct(klass, HMAC_CTX, 0, ossl_hmac_free, ctx) #define GetHMAC(obj, ctx) do { \ Data_Get_Struct(obj, HMAC_CTX, ctx); \ if (!ctx) { \ ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \ } \ } while (0) #define SafeGetHMAC(obj, ctx) do { \ OSSL_Check_Kind(obj, cHMAC); \ GetHMAC(obj, ctx); \ } while (0) /* * Classes */ VALUE cHMAC; VALUE eHMACError; /* * Public */ /* * Private */ static void ossl_hmac_free(HMAC_CTX *ctx) { HMAC_CTX_cleanup(ctx); free(ctx); } static VALUE ossl_hmac_alloc(VALUE klass) { HMAC_CTX *ctx; VALUE obj; MakeHMAC(obj, klass, ctx); HMAC_CTX_init(ctx); return obj; } /* * call-seq: * HMAC.new(key, digest) -> hmac * */ static VALUE ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest) { HMAC_CTX *ctx; StringValue(key); GetHMAC(self, ctx); HMAC_Init_ex(ctx, RSTRING_PTR(key), RSTRING_LEN(key), GetDigestPtr(digest), NULL); return self; } static VALUE ossl_hmac_copy(VALUE self, VALUE other) { HMAC_CTX *ctx1, *ctx2; rb_check_frozen(self); if (self == other) return self; GetHMAC(self, ctx1); SafeGetHMAC(other, ctx2); HMAC_CTX_copy(ctx1, ctx2); return self; } /* * call-seq: * hmac.update(string) -> self * */ static VALUE ossl_hmac_update(VALUE self, VALUE data) { HMAC_CTX *ctx; StringValue(data); GetHMAC(self, ctx); HMAC_Update(ctx, RSTRING_PTR(data), RSTRING_LEN(data)); return self; } static void hmac_final(HMAC_CTX *ctx, char **buf, int *buf_len) { HMAC_CTX final; HMAC_CTX_copy(&final, ctx); if (!(*buf = OPENSSL_malloc(HMAC_size(&final)))) { HMAC_CTX_cleanup(&final); OSSL_Debug("Allocating %d mem", HMAC_size(&final)); ossl_raise(eHMACError, "Cannot allocate memory for hmac"); } HMAC_Final(&final, *buf, buf_len); HMAC_CTX_cleanup(&final); } /* * call-seq: * hmac.digest -> aString * */ static VALUE ossl_hmac_digest(VALUE self) { HMAC_CTX *ctx; char *buf; int buf_len; VALUE digest; GetHMAC(self, ctx); hmac_final(ctx, &buf, &buf_len); digest = ossl_buf2str(buf, buf_len); return digest; } /* * call-seq: * hmac.hexdigest -> aString * */ static VALUE ossl_hmac_hexdigest(VALUE self) { HMAC_CTX *ctx; char *buf, *hexbuf; int buf_len; VALUE hexdigest; GetHMAC(self, ctx); hmac_final(ctx, &buf, &buf_len); if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * buf_len) { OPENSSL_free(buf); ossl_raise(eHMACError, "Memory alloc error"); } OPENSSL_free(buf); hexdigest = ossl_buf2str(hexbuf, 2 * buf_len); return hexdigest; } /* * call-seq: * hmac.reset -> self * */ static VALUE ossl_hmac_reset(VALUE self) { HMAC_CTX *ctx; GetHMAC(self, ctx); HMAC_Init_ex(ctx, NULL, 0, NULL, NULL); return self; } /* * call-seq: * HMAC.digest(digest, key, data) -> aString * */ static VALUE ossl_hmac_s_digest(VALUE klass, VALUE digest, VALUE key, VALUE data) { char *buf; int buf_len; StringValue(key); StringValue(data); buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LEN(key), RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len); return rb_str_new(buf, buf_len); } /* * call-seq: * HMAC.digest(digest, key, data) -> aString * */ static VALUE ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data) { char *buf, *hexbuf; int buf_len; VALUE hexdigest; StringValue(key); StringValue(data); buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LEN(key), RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len); if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * buf_len) { ossl_raise(eHMACError, "Cannot convert buf to hexbuf"); } hexdigest = ossl_buf2str(hexbuf, 2 * buf_len); return hexdigest; } /* * INIT */ void Init_ossl_hmac() { #if 0 /* let rdoc know about mOSSL */ mOSSL = rb_define_module("OpenSSL"); #endif eHMACError = rb_define_class_under(mOSSL, "HMACError", eOSSLError); cHMAC = rb_define_class_under(mOSSL, "HMAC", rb_cObject); rb_define_alloc_func(cHMAC, ossl_hmac_alloc); rb_define_singleton_method(cHMAC, "digest", ossl_hmac_s_digest, 3); rb_define_singleton_method(cHMAC, "hexdigest", ossl_hmac_s_hexdigest, 3); rb_define_method(cHMAC, "initialize", ossl_hmac_initialize, 2); rb_define_copy_func(cHMAC, ossl_hmac_copy); rb_define_method(cHMAC, "reset", ossl_hmac_reset, 0); rb_define_method(cHMAC, "update", ossl_hmac_update, 1); rb_define_alias(cHMAC, "<<", "update"); rb_define_method(cHMAC, "digest", ossl_hmac_digest, 0); rb_define_method(cHMAC, "hexdigest", ossl_hmac_hexdigest, 0); rb_define_alias(cHMAC, "inspect", "hexdigest"); rb_define_alias(cHMAC, "to_s", "hexdigest"); } #else /* NO_HMAC */ # warning >>> OpenSSL is compiled without HMAC support <<< void Init_ossl_hmac() { rb_warning("HMAC will NOT be avaible: OpenSSL is compiled without HMAC."); } #endif /* NO_HMAC */ ================================================ FILE: ext/openssl/ossl_hmac.h ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(_OSSL_HMAC_H_) #define _OSSL_HMAC_H_ extern VALUE cHMAC; extern VALUE eHMACError; void Init_ossl_hmac(void); #endif /* _OSSL_HMAC_H_ */ ================================================ FILE: ext/openssl/ossl_ns_spki.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" #define WrapSPKI(klass, obj, spki) do { \ if (!spki) { \ ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \ } \ obj = Data_Wrap_Struct(klass, 0, NETSCAPE_SPKI_free, spki); \ } while (0) #define GetSPKI(obj, spki) do { \ Data_Get_Struct(obj, NETSCAPE_SPKI, spki); \ if (!spki) { \ ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \ } \ } while (0) /* * Classes */ VALUE mNetscape; VALUE cSPKI; VALUE eSPKIError; /* * Public functions */ /* * Private functions */ static VALUE ossl_spki_alloc(VALUE klass) { NETSCAPE_SPKI *spki; VALUE obj; if (!(spki = NETSCAPE_SPKI_new())) { ossl_raise(eSPKIError, NULL); } WrapSPKI(klass, obj, spki); return obj; } static VALUE ossl_spki_initialize(int argc, VALUE *argv, VALUE self) { NETSCAPE_SPKI *spki; VALUE buffer; unsigned char *p; if (rb_scan_args(argc, argv, "01", &buffer) == 0) { return self; } StringValue(buffer); if (!(spki = NETSCAPE_SPKI_b64_decode(RSTRING_PTR(buffer), -1))) { p = RSTRING_PTR(buffer); if (!(spki = d2i_NETSCAPE_SPKI(NULL, &p, RSTRING_LEN(buffer)))) { ossl_raise(eSPKIError, NULL); } } NETSCAPE_SPKI_free(DATA_PTR(self)); DATA_PTR(self) = spki; ERR_clear_error(); return self; } static VALUE ossl_spki_to_der(VALUE self) { NETSCAPE_SPKI *spki; VALUE str; long len; unsigned char *p; GetSPKI(self, spki); if ((len = i2d_NETSCAPE_SPKI(spki, NULL)) <= 0) ossl_raise(eX509CertError, NULL); str = rb_str_new(0, len); p = RSTRING_PTR(str); if (i2d_NETSCAPE_SPKI(spki, &p) <= 0) ossl_raise(eX509CertError, NULL); ossl_str_adjust(str, p); return str; } static VALUE ossl_spki_to_pem(VALUE self) { NETSCAPE_SPKI *spki; char *data; VALUE str; GetSPKI(self, spki); if (!(data = NETSCAPE_SPKI_b64_encode(spki))) { ossl_raise(eSPKIError, NULL); } str = ossl_buf2str(data, strlen(data)); return str; } static VALUE ossl_spki_print(VALUE self) { NETSCAPE_SPKI *spki; BIO *out; BUF_MEM *buf; VALUE str; GetSPKI(self, spki); if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eSPKIError, NULL); } if (!NETSCAPE_SPKI_print(out, spki)) { BIO_free(out); ossl_raise(eSPKIError, NULL); } BIO_get_mem_ptr(out, &buf); str = rb_str_new(buf->data, buf->length); BIO_free(out); return str; } static VALUE ossl_spki_get_public_key(VALUE self) { NETSCAPE_SPKI *spki; EVP_PKEY *pkey; GetSPKI(self, spki); if (!(pkey = NETSCAPE_SPKI_get_pubkey(spki))) { /* adds an reference */ ossl_raise(eSPKIError, NULL); } return ossl_pkey_new(pkey); /* NO DUP - OK */ } static VALUE ossl_spki_set_public_key(VALUE self, VALUE key) { NETSCAPE_SPKI *spki; GetSPKI(self, spki); if (!NETSCAPE_SPKI_set_pubkey(spki, GetPKeyPtr(key))) { /* NO NEED TO DUP */ ossl_raise(eSPKIError, NULL); } return key; } static VALUE ossl_spki_get_challenge(VALUE self) { NETSCAPE_SPKI *spki; GetSPKI(self, spki); if (spki->spkac->challenge->length <= 0) { OSSL_Debug("Challenge.length <= 0?"); return rb_str_new(0, 0); } return rb_str_new(spki->spkac->challenge->data, spki->spkac->challenge->length); } static VALUE ossl_spki_set_challenge(VALUE self, VALUE str) { NETSCAPE_SPKI *spki; StringValue(str); GetSPKI(self, spki); if (!ASN1_STRING_set(spki->spkac->challenge, RSTRING_PTR(str), RSTRING_LEN(str))) { ossl_raise(eSPKIError, NULL); } return str; } static VALUE ossl_spki_sign(VALUE self, VALUE key, VALUE digest) { NETSCAPE_SPKI *spki; EVP_PKEY *pkey; const EVP_MD *md; pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ md = GetDigestPtr(digest); GetSPKI(self, spki); if (!NETSCAPE_SPKI_sign(spki, pkey, md)) { ossl_raise(eSPKIError, NULL); } return self; } /* * Checks that cert signature is made with PRIVversion of this PUBLIC 'key' */ static VALUE ossl_spki_verify(VALUE self, VALUE key) { NETSCAPE_SPKI *spki; GetSPKI(self, spki); switch (NETSCAPE_SPKI_verify(spki, GetPKeyPtr(key))) { /* NO NEED TO DUP */ case 0: return Qfalse; case 1: return Qtrue; default: ossl_raise(eSPKIError, NULL); } return Qnil; /* dummy */ } /* * NETSCAPE_SPKI init */ void Init_ossl_ns_spki() { mNetscape = rb_define_module_under(mOSSL, "Netscape"); eSPKIError = rb_define_class_under(mNetscape, "SPKIError", eOSSLError); cSPKI = rb_define_class_under(mNetscape, "SPKI", rb_cObject); rb_define_alloc_func(cSPKI, ossl_spki_alloc); rb_define_method(cSPKI, "initialize", ossl_spki_initialize, -1); rb_define_method(cSPKI, "to_der", ossl_spki_to_der, 0); rb_define_method(cSPKI, "to_pem", ossl_spki_to_pem, 0); rb_define_alias(cSPKI, "to_s", "to_pem"); rb_define_method(cSPKI, "to_text", ossl_spki_print, 0); rb_define_method(cSPKI, "public_key", ossl_spki_get_public_key, 0); rb_define_method(cSPKI, "public_key=", ossl_spki_set_public_key, 1); rb_define_method(cSPKI, "sign", ossl_spki_sign, 2); rb_define_method(cSPKI, "verify", ossl_spki_verify, 1); rb_define_method(cSPKI, "challenge", ossl_spki_get_challenge, 0); rb_define_method(cSPKI, "challenge=", ossl_spki_set_challenge, 1); } ================================================ FILE: ext/openssl/ossl_ns_spki.h ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(_OSSL_NS_SPKI_H_) #define _OSSL_NS_SPKI_H_ extern VALUE mNetscape; extern VALUE cSPKI; extern VALUE eSPKIError; void Init_ossl_ns_spki(void); #endif /* _OSSL_NS_SPKI_H_ */ ================================================ FILE: ext/openssl/ossl_ocsp.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2003 Michal Rokos * Copyright (C) 2003 GOTOU Yuuzou * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" #if defined(OSSL_OCSP_ENABLED) #define WrapOCSPReq(klass, obj, req) do { \ if(!req) ossl_raise(rb_eRuntimeError, "Request wasn't initialized!"); \ obj = Data_Wrap_Struct(klass, 0, OCSP_REQUEST_free, req); \ } while (0) #define GetOCSPReq(obj, req) do { \ Data_Get_Struct(obj, OCSP_REQUEST, req); \ if(!req) ossl_raise(rb_eRuntimeError, "Request wasn't initialized!"); \ } while (0) #define SafeGetOCSPReq(obj, req) do { \ OSSL_Check_Kind(obj, cOCSPReq); \ GetOCSPReq(obj, req); \ } while (0) #define WrapOCSPRes(klass, obj, res) do { \ if(!res) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \ obj = Data_Wrap_Struct(klass, 0, OCSP_RESPONSE_free, res); \ } while (0) #define GetOCSPRes(obj, res) do { \ Data_Get_Struct(obj, OCSP_RESPONSE, res); \ if(!res) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \ } while (0) #define SafeGetOCSPRes(obj, res) do { \ OSSL_Check_Kind(obj, cOCSPRes); \ GetOCSPRes(obj, res); \ } while (0) #define WrapOCSPBasicRes(klass, obj, res) do { \ if(!res) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \ obj = Data_Wrap_Struct(klass, 0, OCSP_BASICRESP_free, res); \ } while (0) #define GetOCSPBasicRes(obj, res) do { \ Data_Get_Struct(obj, OCSP_BASICRESP, res); \ if(!res) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \ } while (0) #define SafeGetOCSPBasicRes(obj, res) do { \ OSSL_Check_Kind(obj, cOCSPBasicRes); \ GetOCSPBasicRes(obj, res); \ } while (0) #define WrapOCSPCertId(klass, obj, cid) do { \ if(!cid) ossl_raise(rb_eRuntimeError, "Cert ID wasn't initialized!"); \ obj = Data_Wrap_Struct(klass, 0, OCSP_CERTID_free, cid); \ } while (0) #define GetOCSPCertId(obj, cid) do { \ Data_Get_Struct(obj, OCSP_CERTID, cid); \ if(!cid) ossl_raise(rb_eRuntimeError, "Cert ID wasn't initialized!"); \ } while (0) #define SafeGetOCSPCertId(obj, cid) do { \ OSSL_Check_Kind(obj, cOCSPCertId); \ GetOCSPCertId(obj, cid); \ } while (0) VALUE mOCSP; VALUE eOCSPError; VALUE cOCSPReq; VALUE cOCSPRes; VALUE cOCSPBasicRes; VALUE cOCSPCertId; /* * Public */ static VALUE ossl_ocspcertid_new(OCSP_CERTID *cid) { VALUE obj; WrapOCSPCertId(cOCSPCertId, obj, cid); return obj; } /* * OCSP::Resquest */ static VALUE ossl_ocspreq_alloc(VALUE klass) { OCSP_REQUEST *req; VALUE obj; if (!(req = OCSP_REQUEST_new())) ossl_raise(eOCSPError, NULL); WrapOCSPReq(klass, obj, req); return obj; } static VALUE ossl_ocspreq_initialize(int argc, VALUE *argv, VALUE self) { VALUE arg; unsigned char *p; rb_scan_args(argc, argv, "01", &arg); if(!NIL_P(arg)){ arg = ossl_to_der_if_possible(arg); StringValue(arg); p = (unsigned char*)RSTRING_PTR(arg); if(!d2i_OCSP_REQUEST((OCSP_REQUEST**)&DATA_PTR(self), &p, RSTRING_LEN(arg))){ ossl_raise(eOCSPError, "cannot load DER encoded request"); } } return self; } static VALUE ossl_ocspreq_add_nonce(int argc, VALUE *argv, VALUE self) { OCSP_REQUEST *req; VALUE val; int ret; rb_scan_args(argc, argv, "01", &val); if(NIL_P(val)) { GetOCSPReq(self, req); ret = OCSP_request_add1_nonce(req, NULL, -1); } else{ StringValue(val); GetOCSPReq(self, req); ret = OCSP_request_add1_nonce(req, RSTRING_PTR(val), RSTRING_LEN(val)); } if(!ret) ossl_raise(eOCSPError, NULL); return self; } /* Check nonce validity in a request and response. * Return value reflects result: * 1: nonces present and equal. * 2: nonces both absent. * 3: nonce present in response only. * 0: nonces both present and not equal. * -1: nonce in request only. * * For most responders clients can check return > 0. * If responder doesn't handle nonces return != 0 may be * necessary. return == 0 is always an error. */ static VALUE ossl_ocspreq_check_nonce(VALUE self, VALUE basic_resp) { OCSP_REQUEST *req; OCSP_BASICRESP *bs; int res; GetOCSPReq(self, req); SafeGetOCSPBasicRes(basic_resp, bs); res = OCSP_check_nonce(req, bs); return INT2NUM(res); } static VALUE ossl_ocspreq_add_certid(VALUE self, VALUE certid) { OCSP_REQUEST *req; OCSP_CERTID *id; GetOCSPReq(self, req); GetOCSPCertId(certid, id); if(!OCSP_request_add0_id(req, OCSP_CERTID_dup(id))) ossl_raise(eOCSPError, NULL); return self; } static VALUE ossl_ocspreq_get_certid(VALUE self) { OCSP_REQUEST *req; OCSP_ONEREQ *one; OCSP_CERTID *id; VALUE ary, tmp; int i, count; GetOCSPReq(self, req); count = OCSP_request_onereq_count(req); ary = (count > 0) ? rb_ary_new() : Qnil; for(i = 0; i < count; i++){ one = OCSP_request_onereq_get0(req, i); if(!(id = OCSP_CERTID_dup(OCSP_onereq_get0_id(one)))) ossl_raise(eOCSPError, NULL); WrapOCSPCertId(cOCSPCertId, tmp, id); rb_ary_push(ary, tmp); } return ary; } static VALUE ossl_ocspreq_sign(int argc, VALUE *argv, VALUE self) { VALUE signer_cert, signer_key, certs, flags; OCSP_REQUEST *req; X509 *signer; EVP_PKEY *key; STACK_OF(X509) *x509s; unsigned long flg; int ret; rb_scan_args(argc, argv, "22", &signer_cert, &signer_key, &certs, &flags); signer = GetX509CertPtr(signer_cert); key = GetPrivPKeyPtr(signer_key); flg = NIL_P(flags) ? 0 : NUM2INT(flags); if(NIL_P(certs)){ x509s = sk_X509_new_null(); flags |= OCSP_NOCERTS; } else x509s = ossl_x509_ary2sk(certs); GetOCSPReq(self, req); ret = OCSP_request_sign(req, signer, key, EVP_sha1(), x509s, flg); sk_X509_pop_free(x509s, X509_free); if(!ret) ossl_raise(eOCSPError, NULL); return self; } static VALUE ossl_ocspreq_verify(int argc, VALUE *argv, VALUE self) { VALUE certs, store, flags; OCSP_REQUEST *req; STACK_OF(X509) *x509s; X509_STORE *x509st; int flg, result; rb_scan_args(argc, argv, "21", &certs, &store, &flags); x509st = GetX509StorePtr(store); flg = NIL_P(flags) ? 0 : INT2NUM(flags); x509s = ossl_x509_ary2sk(certs); GetOCSPReq(self, req); result = OCSP_request_verify(req, x509s, x509st, flg); sk_X509_pop_free(x509s, X509_free); if(!result) rb_warn("%s", ERR_error_string(ERR_peek_error(), NULL)); return result ? Qtrue : Qfalse; } static VALUE ossl_ocspreq_to_der(VALUE self) { OCSP_REQUEST *req; VALUE str; unsigned char *p; long len; GetOCSPReq(self, req); if((len = i2d_OCSP_REQUEST(req, NULL)) <= 0) ossl_raise(eOCSPError, NULL); str = rb_str_new(0, len); p = RSTRING_PTR(str); if(i2d_OCSP_REQUEST(req, &p) <= 0) ossl_raise(eOCSPError, NULL); ossl_str_adjust(str, p); return str; } /* * OCSP::Response */ static VALUE ossl_ocspres_s_create(VALUE klass, VALUE status, VALUE basic_resp) { OCSP_BASICRESP *bs; OCSP_RESPONSE *res; VALUE obj; int st = NUM2INT(status); if(NIL_P(basic_resp)) bs = NULL; else GetOCSPBasicRes(basic_resp, bs); /* NO NEED TO DUP */ if(!(res = OCSP_response_create(st, bs))) ossl_raise(eOCSPError, NULL); WrapOCSPRes(klass, obj, res); return obj; } static VALUE ossl_ocspres_alloc(VALUE klass) { OCSP_RESPONSE *res; VALUE obj; if(!(res = OCSP_RESPONSE_new())) ossl_raise(eOCSPError, NULL); WrapOCSPRes(klass, obj, res); return obj; } static VALUE ossl_ocspres_initialize(int argc, VALUE *argv, VALUE self) { VALUE arg; unsigned char *p; rb_scan_args(argc, argv, "01", &arg); if(!NIL_P(arg)){ arg = ossl_to_der_if_possible(arg); StringValue(arg); p = RSTRING_PTR(arg); if(!d2i_OCSP_RESPONSE((OCSP_RESPONSE**)&DATA_PTR(self), &p, RSTRING_LEN(arg))){ ossl_raise(eOCSPError, "cannot load DER encoded response"); } } return self; } static VALUE ossl_ocspres_status(VALUE self) { OCSP_RESPONSE *res; int st; GetOCSPRes(self, res); st = OCSP_response_status(res); return INT2NUM(st); } static VALUE ossl_ocspres_status_string(VALUE self) { OCSP_RESPONSE *res; int st; GetOCSPRes(self, res); st = OCSP_response_status(res); return rb_str_new2(OCSP_response_status_str(st)); } static VALUE ossl_ocspres_get_basic(VALUE self) { OCSP_RESPONSE *res; OCSP_BASICRESP *bs; VALUE ret; GetOCSPRes(self, res); if(!(bs = OCSP_response_get1_basic(res))) return Qnil; WrapOCSPBasicRes(cOCSPBasicRes, ret, bs); return ret; } static VALUE ossl_ocspres_to_der(VALUE self) { OCSP_RESPONSE *res; VALUE str; long len; unsigned char *p; GetOCSPRes(self, res); if((len = i2d_OCSP_RESPONSE(res, NULL)) <= 0) ossl_raise(eOCSPError, NULL); str = rb_str_new(0, len); p = RSTRING_PTR(str); if(i2d_OCSP_RESPONSE(res, NULL) <= 0) ossl_raise(eOCSPError, NULL); ossl_str_adjust(str, p); return str; } /* * OCSP::BasicResponse */ static VALUE ossl_ocspbres_alloc(VALUE klass) { OCSP_BASICRESP *bs; VALUE obj; if(!(bs = OCSP_BASICRESP_new())) ossl_raise(eOCSPError, NULL); WrapOCSPBasicRes(klass, obj, bs); return obj; } static VALUE ossl_ocspbres_initialize(int argc, VALUE *argv, VALUE self) { return self; } static VALUE ossl_ocspbres_copy_nonce(VALUE self, VALUE request) { OCSP_BASICRESP *bs; OCSP_REQUEST *req; int ret; GetOCSPBasicRes(self, bs); SafeGetOCSPReq(request, req); ret = OCSP_copy_nonce(bs, req); return INT2NUM(ret); } static VALUE ossl_ocspbres_add_nonce(int argc, VALUE *argv, VALUE self) { OCSP_BASICRESP *bs; VALUE val; int ret; rb_scan_args(argc, argv, "01", &val); if(NIL_P(val)) { GetOCSPBasicRes(self, bs); ret = OCSP_basic_add1_nonce(bs, NULL, -1); } else{ StringValue(val); GetOCSPBasicRes(self, bs); ret = OCSP_basic_add1_nonce(bs, RSTRING_PTR(val), RSTRING_LEN(val)); } if(!ret) ossl_raise(eOCSPError, NULL); return self; } static VALUE ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status, VALUE reason, VALUE revtime, VALUE thisupd, VALUE nextupd, VALUE ext) { OCSP_BASICRESP *bs; OCSP_SINGLERESP *single; OCSP_CERTID *id; int st, rsn; ASN1_TIME *ths, *nxt, *rev; int error, i, rstatus = 0; VALUE tmp; st = NUM2INT(status); rsn = NIL_P(status) ? 0 : NUM2INT(reason); if(!NIL_P(ext)){ /* All ary's members should be X509Extension */ Check_Type(ext, T_ARRAY); for (i = 0; i < RARRAY_LEN(ext); i++) OSSL_Check_Kind(RARRAY_PTR(ext)[i], cX509Ext); } error = 0; ths = nxt = rev = NULL; if(!NIL_P(revtime)){ tmp = rb_protect(rb_Integer, revtime, &rstatus); if(rstatus) goto err; rev = X509_gmtime_adj(NULL, NUM2INT(tmp)); } tmp = rb_protect(rb_Integer, thisupd, &rstatus); if(rstatus) goto err; ths = X509_gmtime_adj(NULL, NUM2INT(tmp)); tmp = rb_protect(rb_Integer, nextupd, &rstatus); if(rstatus) goto err; nxt = X509_gmtime_adj(NULL, NUM2INT(tmp)); GetOCSPBasicRes(self, bs); SafeGetOCSPCertId(cid, id); if(!(single = OCSP_basic_add1_status(bs, id, st, rsn, rev, ths, nxt))){ error = 1; goto err; } if(!NIL_P(ext)){ X509_EXTENSION *x509ext; sk_X509_EXTENSION_pop_free(single->singleExtensions, X509_EXTENSION_free); single->singleExtensions = NULL; for(i = 0; i < RARRAY_LEN(ext); i++){ x509ext = DupX509ExtPtr(RARRAY_PTR(ext)[i]); if(!OCSP_SINGLERESP_add_ext(single, x509ext, -1)){ X509_EXTENSION_free(x509ext); error = 1; goto err; } X509_EXTENSION_free(x509ext); } } err: ASN1_TIME_free(ths); ASN1_TIME_free(nxt); ASN1_TIME_free(rev); if(error) ossl_raise(eOCSPError, NULL); if(rstatus) rb_jump_tag(rstatus); return self; } static VALUE ossl_ocspbres_get_status(VALUE self) { OCSP_BASICRESP *bs; OCSP_SINGLERESP *single; OCSP_CERTID *cid; ASN1_TIME *revtime, *thisupd, *nextupd; int status, reason; X509_EXTENSION *x509ext; VALUE ret, ary, ext; int count, ext_count, i, j; GetOCSPBasicRes(self, bs); ret = rb_ary_new(); count = OCSP_resp_count(bs); for(i = 0; i < count; i++){ single = OCSP_resp_get0(bs, i); if(!single) continue; revtime = thisupd = nextupd = NULL; status = OCSP_single_get0_status(single, &reason, &revtime, &thisupd, &nextupd); if(status < 0) continue; if(!(cid = OCSP_CERTID_dup(single->certId))) ossl_raise(eOCSPError, NULL); ary = rb_ary_new(); rb_ary_push(ary, ossl_ocspcertid_new(cid)); rb_ary_push(ary, INT2NUM(status)); rb_ary_push(ary, INT2NUM(reason)); rb_ary_push(ary, revtime ? asn1time_to_time(revtime) : Qnil); rb_ary_push(ary, thisupd ? asn1time_to_time(thisupd) : Qnil); rb_ary_push(ary, nextupd ? asn1time_to_time(nextupd) : Qnil); ext = rb_ary_new(); ext_count = OCSP_SINGLERESP_get_ext_count(single); for(j = 0; j < ext_count; j++){ x509ext = OCSP_SINGLERESP_get_ext(single, j); rb_ary_push(ext, ossl_x509ext_new(x509ext)); } rb_ary_push(ary, ext); rb_ary_push(ret, ary); } return ret; } static VALUE ossl_ocspbres_sign(int argc, VALUE *argv, VALUE self) { VALUE signer_cert, signer_key, certs, flags; OCSP_BASICRESP *bs; X509 *signer; EVP_PKEY *key; STACK_OF(X509) *x509s; unsigned long flg; int ret; rb_scan_args(argc, argv, "22", &signer_cert, &signer_key, &certs, &flags); signer = GetX509CertPtr(signer_cert); key = GetPrivPKeyPtr(signer_key); flg = NIL_P(flags) ? 0 : NUM2INT(flags); if(NIL_P(certs)){ x509s = sk_X509_new_null(); flg |= OCSP_NOCERTS; } else{ x509s = ossl_x509_ary2sk(certs); } GetOCSPBasicRes(self, bs); ret = OCSP_basic_sign(bs, signer, key, EVP_sha1(), x509s, flg); sk_X509_pop_free(x509s, X509_free); if(!ret) ossl_raise(eOCSPError, NULL); return self; } static VALUE ossl_ocspbres_verify(int argc, VALUE *argv, VALUE self) { VALUE certs, store, flags, result; OCSP_BASICRESP *bs; STACK_OF(X509) *x509s; X509_STORE *x509st; int flg; rb_scan_args(argc, argv, "21", &certs, &store, &flags); x509st = GetX509StorePtr(store); flg = NIL_P(flags) ? 0 : INT2NUM(flags); x509s = ossl_x509_ary2sk(certs); GetOCSPBasicRes(self, bs); result = OCSP_basic_verify(bs, x509s, x509st, flg) > 0 ? Qtrue : Qfalse; sk_X509_pop_free(x509s, X509_free); if(!result) rb_warn("%s", ERR_error_string(ERR_peek_error(), NULL)); return result; } /* * OCSP::CertificateId */ static VALUE ossl_ocspcid_alloc(VALUE klass) { OCSP_CERTID *id; VALUE obj; if(!(id = OCSP_CERTID_new())) ossl_raise(eOCSPError, NULL); WrapOCSPCertId(klass, obj, id); return obj; } static VALUE ossl_ocspcid_initialize(VALUE self, VALUE subject, VALUE issuer) { OCSP_CERTID *id, *newid; X509 *x509s, *x509i; x509s = GetX509CertPtr(subject); /* NO NEED TO DUP */ x509i = GetX509CertPtr(issuer); /* NO NEED TO DUP */ if(!(newid = OCSP_cert_to_id(NULL, x509s, x509i))) ossl_raise(eOCSPError, NULL); GetOCSPCertId(self, id); OCSP_CERTID_free(id); RDATA(self)->data = newid; return self; } static VALUE ossl_ocspcid_cmp(VALUE self, VALUE other) { OCSP_CERTID *id, *id2; int result; GetOCSPCertId(self, id); SafeGetOCSPCertId(other, id2); result = OCSP_id_cmp(id, id2); return (result == 0) ? Qtrue : Qfalse; } static VALUE ossl_ocspcid_cmp_issuer(VALUE self, VALUE other) { OCSP_CERTID *id, *id2; int result; GetOCSPCertId(self, id); SafeGetOCSPCertId(other, id2); result = OCSP_id_issuer_cmp(id, id2); return (result == 0) ? Qtrue : Qfalse; } static VALUE ossl_ocspcid_get_serial(VALUE self) { OCSP_CERTID *id; GetOCSPCertId(self, id); return asn1integer_to_num(id->serialNumber); } void Init_ossl_ocsp() { mOCSP = rb_define_module_under(mOSSL, "OCSP"); eOCSPError = rb_define_class_under(mOCSP, "OCSPError", eOSSLError); cOCSPReq = rb_define_class_under(mOCSP, "Request", rb_cObject); rb_define_alloc_func(cOCSPReq, ossl_ocspreq_alloc); rb_define_method(cOCSPReq, "initialize", ossl_ocspreq_initialize, -1); rb_define_method(cOCSPReq, "add_nonce", ossl_ocspreq_add_nonce, -1); rb_define_method(cOCSPReq, "check_nonce", ossl_ocspreq_check_nonce, 1); rb_define_method(cOCSPReq, "add_certid", ossl_ocspreq_add_certid, 1); rb_define_method(cOCSPReq, "certid", ossl_ocspreq_get_certid, 0); rb_define_method(cOCSPReq, "sign", ossl_ocspreq_sign, -1); rb_define_method(cOCSPReq, "verify", ossl_ocspreq_verify, -1); rb_define_method(cOCSPReq, "to_der", ossl_ocspreq_to_der, 0); cOCSPRes = rb_define_class_under(mOCSP, "Response", rb_cObject); rb_define_singleton_method(cOCSPRes, "create", ossl_ocspres_s_create, 2); rb_define_alloc_func(cOCSPRes, ossl_ocspres_alloc); rb_define_method(cOCSPRes, "initialize", ossl_ocspres_initialize, -1); rb_define_method(cOCSPRes, "status", ossl_ocspres_status, 0); rb_define_method(cOCSPRes, "status_string", ossl_ocspres_status_string, 0); rb_define_method(cOCSPRes, "basic", ossl_ocspres_get_basic, 0); rb_define_method(cOCSPRes, "to_der", ossl_ocspres_to_der, 0); cOCSPBasicRes = rb_define_class_under(mOCSP, "BasicResponse", rb_cObject); rb_define_alloc_func(cOCSPBasicRes, ossl_ocspbres_alloc); rb_define_method(cOCSPBasicRes, "initialize", ossl_ocspbres_initialize, -1); rb_define_method(cOCSPBasicRes, "copy_nonce", ossl_ocspbres_copy_nonce, 1); rb_define_method(cOCSPBasicRes, "add_nonce", ossl_ocspbres_add_nonce, -1); rb_define_method(cOCSPBasicRes, "add_status", ossl_ocspbres_add_status, 7); rb_define_method(cOCSPBasicRes, "status", ossl_ocspbres_get_status, 0); rb_define_method(cOCSPBasicRes, "sign", ossl_ocspbres_sign, -1); rb_define_method(cOCSPBasicRes, "verify", ossl_ocspbres_verify, -1); cOCSPCertId = rb_define_class_under(mOCSP, "CertificateId", rb_cObject); rb_define_alloc_func(cOCSPCertId, ossl_ocspcid_alloc); rb_define_method(cOCSPCertId, "initialize", ossl_ocspcid_initialize, 2); rb_define_method(cOCSPCertId, "cmp", ossl_ocspcid_cmp, 1); rb_define_method(cOCSPCertId, "cmp_issuer", ossl_ocspcid_cmp_issuer, 1); rb_define_method(cOCSPCertId, "serial", ossl_ocspcid_get_serial, 0); #define DefOCSPConst(x) rb_define_const(mOCSP, #x, INT2NUM(OCSP_##x)) DefOCSPConst(RESPONSE_STATUS_SUCCESSFUL); DefOCSPConst(RESPONSE_STATUS_MALFORMEDREQUEST); DefOCSPConst(RESPONSE_STATUS_INTERNALERROR); DefOCSPConst(RESPONSE_STATUS_TRYLATER); DefOCSPConst(RESPONSE_STATUS_SIGREQUIRED); DefOCSPConst(RESPONSE_STATUS_UNAUTHORIZED); DefOCSPConst(REVOKED_STATUS_NOSTATUS); DefOCSPConst(REVOKED_STATUS_UNSPECIFIED); DefOCSPConst(REVOKED_STATUS_KEYCOMPROMISE); DefOCSPConst(REVOKED_STATUS_CACOMPROMISE); DefOCSPConst(REVOKED_STATUS_AFFILIATIONCHANGED); DefOCSPConst(REVOKED_STATUS_SUPERSEDED); DefOCSPConst(REVOKED_STATUS_CESSATIONOFOPERATION); DefOCSPConst(REVOKED_STATUS_CERTIFICATEHOLD); DefOCSPConst(REVOKED_STATUS_REMOVEFROMCRL); DefOCSPConst(NOCERTS); DefOCSPConst(NOINTERN); DefOCSPConst(NOSIGS); DefOCSPConst(NOCHAIN); DefOCSPConst(NOVERIFY); DefOCSPConst(NOEXPLICIT); DefOCSPConst(NOCASIGN); DefOCSPConst(NODELEGATED); DefOCSPConst(NOCHECKS); DefOCSPConst(TRUSTOTHER); DefOCSPConst(RESPID_KEY); DefOCSPConst(NOTIME); #define DefOCSPVConst(x) rb_define_const(mOCSP, "V_" #x, INT2NUM(V_OCSP_##x)) DefOCSPVConst(CERTSTATUS_GOOD); DefOCSPVConst(CERTSTATUS_REVOKED); DefOCSPVConst(CERTSTATUS_UNKNOWN); DefOCSPVConst(RESPID_NAME); DefOCSPVConst(RESPID_KEY); } #else /* ! OSSL_OCSP_ENABLED */ void Init_ossl_ocsp() { } #endif ================================================ FILE: ext/openssl/ossl_ocsp.h ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2003 Michal Rokos * Copyright (C) 2003 GOTOU Yuuzou * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(_OSSL_OCSP_H_) #define _OSSL_OCSP_H_ #if defined(OSSL_OCSP_ENABLED) extern VALUE mOCSP; extern VALUE cOPCSReq; extern VALUE cOPCSRes; extern VALUE cOPCSBasicRes; #endif void Init_ossl_ocsp(void); #endif /* _OSSL_OCSP_H_ */ ================================================ FILE: ext/openssl/ossl_pkcs12.c ================================================ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) * $Id$ */ #include "ossl.h" #define WrapPKCS12(klass, obj, p12) do { \ if(!p12) ossl_raise(rb_eRuntimeError, "PKCS12 wasn't initialized."); \ obj = Data_Wrap_Struct(klass, 0, PKCS12_free, p12); \ } while (0) #define GetPKCS12(obj, p12) do { \ Data_Get_Struct(obj, PKCS12, p12); \ if(!p12) ossl_raise(rb_eRuntimeError, "PKCS12 wasn't initialized."); \ } while (0) #define SafeGetPKCS12(obj, p12) do { \ OSSL_Check_Kind(obj, cPKCS12); \ GetPKCS12(obj, p12); \ } while (0) #define ossl_pkcs12_set_key(o,v) rb_iv_set((o), "@key", (v)) #define ossl_pkcs12_set_cert(o,v) rb_iv_set((o), "@certificate", (v)) #define ossl_pkcs12_set_ca_certs(o,v) rb_iv_set((o), "@ca_certs", (v)) #define ossl_pkcs12_get_key(o) rb_iv_get((o), "@key") #define ossl_pkcs12_get_cert(o) rb_iv_get((o), "@certificate") #define ossl_pkcs12_get_ca_certs(o) rb_iv_get((o), "@ca_certs") /* * Classes */ VALUE cPKCS12; VALUE ePKCS12Error; /* * Private */ static VALUE ossl_pkcs12_s_allocate(VALUE klass) { PKCS12 *p12; VALUE obj; if(!(p12 = PKCS12_new())) ossl_raise(ePKCS12Error, NULL); WrapPKCS12(klass, obj, p12); return obj; } /* * call-seq: * PKCS12.create(pass, name, key, cert [, ca, [, key_pbe [, cert_pbe [, key_iter [, mac_iter [, keytype]]]]]]) * * === Parameters * * +pass+ - string * * +name+ - A string describing the key. * * +key+ - Any PKey. * * +cert+ - A X509::Certificate. * * * The public_key portion of the certificate must contain a valid public key. * * * The not_before and not_after fields must be filled in. * * +ca+ - An optional array of X509::Certificate's. * * +key_pbe+ - string * * +cert_pbe+ - string * * +key_iter+ - integer * * +mac_iter+ - integer * * +keytype+ - An integer representing an MSIE specific extension. * * Any optional arguments may be supplied as nil to preserve the OpenSSL defaults. * * See the OpenSSL documentation for PKCS12_create(). */ static VALUE ossl_pkcs12_s_create(int argc, VALUE *argv, VALUE self) { VALUE pass, name, pkey, cert, ca, key_nid, cert_nid, key_iter, mac_iter, keytype; VALUE obj; char *passphrase, *friendlyname; EVP_PKEY *key; X509 *x509; STACK_OF(X509) *x509s; int nkey = 0, ncert = 0, kiter = 0, miter = 0, ktype = 0; PKCS12 *p12; rb_scan_args(argc, argv, "46", &pass, &name, &pkey, &cert, &ca, &key_nid, &cert_nid, &key_iter, &mac_iter, &keytype); passphrase = NIL_P(pass) ? NULL : StringValuePtr(pass); friendlyname = NIL_P(name) ? NULL : StringValuePtr(name); key = GetPKeyPtr(pkey); x509 = GetX509CertPtr(cert); x509s = NIL_P(ca) ? NULL : ossl_x509_ary2sk(ca); /* TODO: make a VALUE to nid function */ if (!NIL_P(key_nid)) { if ((nkey = OBJ_txt2nid(StringValuePtr(key_nid))) == NID_undef) rb_raise(rb_eArgError, "Unknown PBE algorithm %s", StringValuePtr(key_nid)); } if (!NIL_P(cert_nid)) { if ((ncert = OBJ_txt2nid(StringValuePtr(cert_nid))) == NID_undef) rb_raise(rb_eArgError, "Unknown PBE algorithm %s", StringValuePtr(cert_nid)); } if (!NIL_P(key_iter)) kiter = NUM2INT(key_iter); if (!NIL_P(mac_iter)) miter = NUM2INT(mac_iter); if (!NIL_P(keytype)) ktype = NUM2INT(keytype); p12 = PKCS12_create(passphrase, friendlyname, key, x509, x509s, nkey, ncert, kiter, miter, ktype); sk_X509_pop_free(x509s, X509_free); if(!p12) ossl_raise(ePKCS12Error, NULL); WrapPKCS12(cPKCS12, obj, p12); ossl_pkcs12_set_key(obj, pkey); ossl_pkcs12_set_cert(obj, cert); ossl_pkcs12_set_ca_certs(obj, ca); return obj; } /* * call-seq: * PKCS12.new -> pkcs12 * PKCS12.new(str) -> pkcs12 * PKCS12.new(str, pass) -> pkcs12 * * === Parameters * * +str+ - Must be a DER encoded PKCS12 string. * * +pass+ - string */ static VALUE ossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self) { BIO *in; VALUE arg, pass, pkey, cert, ca; char *passphrase; EVP_PKEY *key; X509 *x509; STACK_OF(X509) *x509s = NULL; int st = 0; if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) return self; passphrase = NIL_P(pass) ? NULL : StringValuePtr(pass); in = ossl_obj2bio(arg); d2i_PKCS12_bio(in, (PKCS12 **)&DATA_PTR(self)); BIO_free(in); pkey = cert = ca = Qnil; if(!PKCS12_parse((PKCS12*)DATA_PTR(self), passphrase, &key, &x509, &x509s)) ossl_raise(ePKCS12Error, "PKCS12_parse"); pkey = rb_protect((VALUE(*)_((VALUE)))ossl_pkey_new, (VALUE)key, &st); /* NO DUP */ if(st) goto err; cert = rb_protect((VALUE(*)_((VALUE)))ossl_x509_new, (VALUE)x509, &st); if(st) goto err; if(x509s){ ca = rb_protect((VALUE(*)_((VALUE)))ossl_x509_sk2ary, (VALUE)x509s, &st); if(st) goto err; } err: X509_free(x509); sk_X509_pop_free(x509s, X509_free); ossl_pkcs12_set_key(self, pkey); ossl_pkcs12_set_cert(self, cert); ossl_pkcs12_set_ca_certs(self, ca); if(st) rb_jump_tag(st); return self; } static VALUE ossl_pkcs12_to_der(VALUE self) { PKCS12 *p12; VALUE str; long len; unsigned char *p; GetPKCS12(self, p12); if((len = i2d_PKCS12(p12, NULL)) <= 0) ossl_raise(ePKCS12Error, NULL); str = rb_str_new(0, len); p = RSTRING_PTR(str); if(i2d_PKCS12(p12, &p) <= 0) ossl_raise(ePKCS12Error, NULL); ossl_str_adjust(str, p); return str; } void Init_ossl_pkcs12() { /* * Defines a file format commonly used to store private keys with * accompanying public key certificates, protected with a password-based * symmetric key. */ cPKCS12 = rb_define_class_under(mOSSL, "PKCS12", rb_cObject); ePKCS12Error = rb_define_class_under(cPKCS12, "PKCS12Error", eOSSLError); rb_define_singleton_method(cPKCS12, "create", ossl_pkcs12_s_create, -1); rb_define_alloc_func(cPKCS12, ossl_pkcs12_s_allocate); rb_attr(cPKCS12, rb_intern("key"), 1, 0, Qfalse); rb_attr(cPKCS12, rb_intern("certificate"), 1, 0, Qfalse); rb_attr(cPKCS12, rb_intern("ca_certs"), 1, 0, Qfalse); rb_define_method(cPKCS12, "initialize", ossl_pkcs12_initialize, -1); rb_define_method(cPKCS12, "to_der", ossl_pkcs12_to_der, 0); } ================================================ FILE: ext/openssl/ossl_pkcs12.h ================================================ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) * $Id$ */ #if !defined(_OSSL_PKCS12_H_) #define _OSSL_PKCS12_H_ extern VALUE cPKCS12; extern VALUE ePKCS12Error; void Init_ossl_pkcs12(void); #endif /* _OSSL_PKCS12_H_ */ ================================================ FILE: ext/openssl/ossl_pkcs5.c ================================================ /* * $Id$ * Copyright (C) 2007 Technorama Ltd. */ #include "ossl.h" VALUE mPKCS5; VALUE ePKCS5; /* * call-seq: * PKCS5.pbkdf2_hmac(pass, salt, iter, keylen, digest) => string * * === Parameters * * +pass+ - string * * +salt+ - string * * +iter+ - integer - should be greater than 1000. 2000 is better. * * +keylen+ - integer * * +digest+ - a string or OpenSSL::Digest object. * * Available in OpenSSL 0.9.9?. * * Digests other than SHA1 may not be supported by other cryptography libraries. */ static VALUE ossl_pkcs5_pbkdf2_hmac(VALUE self, VALUE pass, VALUE salt, VALUE iter, VALUE keylen, VALUE digest) { #ifdef HAVE_PKCS5_PBKDF2_HMAC VALUE str; const EVP_MD *md; int len = NUM2INT(keylen); StringValue(pass); StringValue(salt); md = GetDigestPtr(digest); str = rb_str_new(0, len); if (PKCS5_PBKDF2_HMAC(RSTRING_PTR(pass), RSTRING_LEN(pass), RSTRING_PTR(salt), RSTRING_LEN(salt), NUM2INT(iter), md, len, RSTRING_PTR(str)) != 1) ossl_raise(ePKCS5, "PKCS5_PBKDF2_HMAC"); return str; #else rb_notimplement(); #endif } /* * call-seq: * PKCS5.pbkdf2_hmac_sha1(pass, salt, iter, keylen) => string * * === Parameters * * +pass+ - string * * +salt+ - string * * +iter+ - integer - should be greater than 1000. 2000 is better. * * +keylen+ - integer * * This method is available almost any version OpenSSL. * * Conforms to rfc2898. */ static VALUE ossl_pkcs5_pbkdf2_hmac_sha1(VALUE self, VALUE pass, VALUE salt, VALUE iter, VALUE keylen) { #ifdef HAVE_PKCS5_PBKDF2_HMAC_SHA1 VALUE str; int len = NUM2INT(keylen); StringValue(pass); StringValue(salt); str = rb_str_new(0, len); if (PKCS5_PBKDF2_HMAC_SHA1(RSTRING_PTR(pass), RSTRING_LEN(pass), RSTRING_PTR(salt), RSTRING_LEN(salt), NUM2INT(iter), len, RSTRING_PTR(str)) != 1) ossl_raise(ePKCS5, "PKCS5_PBKDF2_HMAC_SHA1"); return str; #else rb_notimplement(); #endif } void Init_ossl_pkcs5() { /* * Password-based Encryption * */ mPKCS5 = rb_define_module_under(mOSSL, "PKCS5"); ePKCS5 = rb_define_class_under(mPKCS5, "PKCS5Error", eOSSLError); rb_define_module_function(mPKCS5, "pbkdf2_hmac", ossl_pkcs5_pbkdf2_hmac, 5); rb_define_module_function(mPKCS5, "pbkdf2_hmac_sha1", ossl_pkcs5_pbkdf2_hmac_sha1, 4); } ================================================ FILE: ext/openssl/ossl_pkcs5.h ================================================ #if !defined(_OSSL_PKCS5_H_) #define _OSSL_PKCS5_H_ void Init_ossl_pkcs5(void); #endif /* _OSSL_PKCS5_H_ */ ================================================ FILE: ext/openssl/ossl_pkcs7.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" #define WrapPKCS7(klass, obj, pkcs7) do { \ if (!pkcs7) { \ ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \ } \ obj = Data_Wrap_Struct(klass, 0, PKCS7_free, pkcs7); \ } while (0) #define GetPKCS7(obj, pkcs7) do { \ Data_Get_Struct(obj, PKCS7, pkcs7); \ if (!pkcs7) { \ ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \ } \ } while (0) #define SafeGetPKCS7(obj, pkcs7) do { \ OSSL_Check_Kind(obj, cPKCS7); \ GetPKCS7(obj, pkcs7); \ } while (0) #define WrapPKCS7si(klass, obj, p7si) do { \ if (!p7si) { \ ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \ } \ obj = Data_Wrap_Struct(klass, 0, PKCS7_SIGNER_INFO_free, p7si); \ } while (0) #define GetPKCS7si(obj, p7si) do { \ Data_Get_Struct(obj, PKCS7_SIGNER_INFO, p7si); \ if (!p7si) { \ ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \ } \ } while (0) #define SafeGetPKCS7si(obj, p7si) do { \ OSSL_Check_Kind(obj, cPKCS7Signer); \ GetPKCS7si(obj, p7si); \ } while (0) #define WrapPKCS7ri(klass, obj, p7ri) do { \ if (!p7ri) { \ ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \ } \ obj = Data_Wrap_Struct(klass, 0, PKCS7_RECIP_INFO_free, p7ri); \ } while (0) #define GetPKCS7ri(obj, p7ri) do { \ Data_Get_Struct(obj, PKCS7_RECIP_INFO, p7ri); \ if (!p7ri) { \ ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \ } \ } while (0) #define SafeGetPKCS7ri(obj, p7ri) do { \ OSSL_Check_Kind(obj, cPKCS7Recipient); \ GetPKCS7ri(obj, p7ri); \ } while (0) #define numberof(ary) (sizeof(ary)/sizeof(ary[0])) #define ossl_pkcs7_set_data(o,v) rb_iv_set((o), "@data", (v)) #define ossl_pkcs7_get_data(o) rb_iv_get((o), "@data") #define ossl_pkcs7_set_err_string(o,v) rb_iv_set((o), "@error_string", (v)) #define ossl_pkcs7_get_err_string(o) rb_iv_get((o), "@error_string") /* * Classes */ VALUE cPKCS7; VALUE cPKCS7Signer; VALUE cPKCS7Recipient; VALUE ePKCS7Error; /* * Public * (MADE PRIVATE UNTIL SOMEBODY WILL NEED THEM) */ static VALUE ossl_pkcs7si_new(PKCS7_SIGNER_INFO *p7si) { PKCS7_SIGNER_INFO *pkcs7; VALUE obj; pkcs7 = p7si ? PKCS7_SIGNER_INFO_dup(p7si) : PKCS7_SIGNER_INFO_new(); if (!pkcs7) ossl_raise(ePKCS7Error, NULL); WrapPKCS7si(cPKCS7Signer, obj, pkcs7); return obj; } static PKCS7_SIGNER_INFO * DupPKCS7SignerPtr(VALUE obj) { PKCS7_SIGNER_INFO *p7si, *pkcs7; SafeGetPKCS7si(obj, p7si); if (!(pkcs7 = PKCS7_SIGNER_INFO_dup(p7si))) { ossl_raise(ePKCS7Error, NULL); } return pkcs7; } static VALUE ossl_pkcs7ri_new(PKCS7_RECIP_INFO *p7ri) { PKCS7_RECIP_INFO *pkcs7; VALUE obj; pkcs7 = p7ri ? PKCS7_RECIP_INFO_dup(p7ri) : PKCS7_RECIP_INFO_new(); if (!pkcs7) ossl_raise(ePKCS7Error, NULL); WrapPKCS7ri(cPKCS7Recipient, obj, pkcs7); return obj; } static PKCS7_RECIP_INFO * DupPKCS7RecipientPtr(VALUE obj) { PKCS7_RECIP_INFO *p7ri, *pkcs7; SafeGetPKCS7ri(obj, p7ri); if (!(pkcs7 = PKCS7_RECIP_INFO_dup(p7ri))) { ossl_raise(ePKCS7Error, NULL); } return pkcs7; } /* * call-seq: * PKCS7.read_smime(string) => pkcs7 */ static VALUE ossl_pkcs7_s_read_smime(VALUE klass, VALUE arg) { BIO *in, *out; PKCS7 *pkcs7; VALUE ret, data; in = ossl_obj2bio(arg); out = NULL; pkcs7 = SMIME_read_PKCS7(in, &out); BIO_free(in); if(!pkcs7) ossl_raise(ePKCS7Error, NULL); data = out ? ossl_membio2str(out) : Qnil; WrapPKCS7(cPKCS7, ret, pkcs7); ossl_pkcs7_set_data(ret, data); ossl_pkcs7_set_err_string(ret, Qnil); return ret; } /* * call-seq: * PKCS7.write_smime(pkcs7 [, data [, flags]]) => string */ static VALUE ossl_pkcs7_s_write_smime(int argc, VALUE *argv, VALUE klass) { VALUE pkcs7, data, flags; BIO *out, *in; PKCS7 *p7; VALUE str; int flg; rb_scan_args(argc, argv, "12", &pkcs7, &data, &flags); flg = NIL_P(flags) ? 0 : NUM2INT(flags); if(NIL_P(data)) data = ossl_pkcs7_get_data(pkcs7); SafeGetPKCS7(pkcs7, p7); if(!NIL_P(data) && PKCS7_is_detached(p7)) flg |= PKCS7_DETACHED; in = NIL_P(data) ? NULL : ossl_obj2bio(data); if(!(out = BIO_new(BIO_s_mem()))){ BIO_free(in); ossl_raise(ePKCS7Error, NULL); } if(!SMIME_write_PKCS7(out, p7, in, flg)){ BIO_free(out); BIO_free(in); ossl_raise(ePKCS7Error, NULL); } BIO_free(in); str = ossl_membio2str(out); return str; } /* * call-seq: * PKCS7.sign(cert, key, data, [, certs [, flags]]) => pkcs7 */ static VALUE ossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass) { VALUE cert, key, data, certs, flags; X509 *x509; EVP_PKEY *pkey; BIO *in; STACK_OF(X509) *x509s; int flg, status = 0; PKCS7 *pkcs7; VALUE ret; rb_scan_args(argc, argv, "32", &cert, &key, &data, &certs, &flags); x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */ pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ flg = NIL_P(flags) ? 0 : NUM2INT(flags); in = ossl_obj2bio(data); if(NIL_P(certs)) x509s = NULL; else{ x509s = ossl_protect_x509_ary2sk(certs, &status); if(status){ BIO_free(in); rb_jump_tag(status); } } if(!(pkcs7 = PKCS7_sign(x509, pkey, x509s, in, flg))){ BIO_free(in); sk_X509_pop_free(x509s, X509_free); ossl_raise(ePKCS7Error, NULL); } WrapPKCS7(cPKCS7, ret, pkcs7); ossl_pkcs7_set_data(ret, data); ossl_pkcs7_set_err_string(ret, Qnil); BIO_free(in); sk_X509_pop_free(x509s, X509_free); return ret; } /* * call-seq: * PKCS7.encrypt(certs, data, [, cipher [, flags]]) => pkcs7 */ static VALUE ossl_pkcs7_s_encrypt(int argc, VALUE *argv, VALUE klass) { VALUE certs, data, cipher, flags; STACK_OF(X509) *x509s; BIO *in; const EVP_CIPHER *ciph; int flg, status = 0; VALUE ret; PKCS7 *p7; rb_scan_args(argc, argv, "22", &certs, &data, &cipher, &flags); if(NIL_P(cipher)){ #if !defined(OPENSSL_NO_RC2) ciph = EVP_rc2_40_cbc(); #elif !defined(OPENSSL_NO_DES) ciph = EVP_des_ede3_cbc(); #elif !defined(OPENSSL_NO_RC2) ciph = EVP_rc2_40_cbc(); #elif !defined(OPENSSL_NO_AES) ciph = EVP_EVP_aes_128_cbc(); #else ossl_raise(ePKCS7Error, "Must specify cipher"); #endif } else ciph = GetCipherPtr(cipher); /* NO NEED TO DUP */ flg = NIL_P(flags) ? 0 : NUM2INT(flags); in = ossl_obj2bio(data); x509s = ossl_protect_x509_ary2sk(certs, &status); if(status){ BIO_free(in); rb_jump_tag(status); } if(!(p7 = PKCS7_encrypt(x509s, in, (EVP_CIPHER*)ciph, flg))){ BIO_free(in); sk_X509_pop_free(x509s, X509_free); ossl_raise(ePKCS7Error, NULL); } BIO_free(in); WrapPKCS7(cPKCS7, ret, p7); ossl_pkcs7_set_data(ret, data); sk_X509_pop_free(x509s, X509_free); return ret; } static VALUE ossl_pkcs7_alloc(VALUE klass) { PKCS7 *pkcs7; VALUE obj; if (!(pkcs7 = PKCS7_new())) { ossl_raise(ePKCS7Error, NULL); } WrapPKCS7(klass, obj, pkcs7); return obj; } /* * call-seq: * PKCS7.new => pkcs7 * PKCS7.new(string) => pkcs7 * * Many methods in this class aren't documented. */ static VALUE ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self) { PKCS7 *p7; BIO *in; VALUE arg; if(rb_scan_args(argc, argv, "01", &arg) == 0) return self; arg = ossl_to_der_if_possible(arg); in = ossl_obj2bio(arg); p7 = PEM_read_bio_PKCS7(in, (PKCS7 **)&DATA_PTR(self), NULL, NULL); if (!p7) { BIO_reset(in); p7 = d2i_PKCS7_bio(in, (PKCS7 **)&DATA_PTR(self)); } BIO_free(in); ossl_pkcs7_set_data(self, Qnil); ossl_pkcs7_set_err_string(self, Qnil); return self; } static VALUE ossl_pkcs7_copy(VALUE self, VALUE other) { PKCS7 *a, *b, *pkcs7; rb_check_frozen(self); if (self == other) return self; GetPKCS7(self, a); SafeGetPKCS7(other, b); pkcs7 = PKCS7_dup(b); if (!pkcs7) { ossl_raise(ePKCS7Error, NULL); } DATA_PTR(self) = pkcs7; PKCS7_free(a); return self; } static int ossl_pkcs7_sym2typeid(VALUE sym) { int i, ret = Qnil; const char *s; static struct { const char *name; int nid; } p7_type_tab[] = { { "signed", NID_pkcs7_signed }, { "data", NID_pkcs7_data }, { "signedAndEnveloped", NID_pkcs7_signedAndEnveloped }, { "enveloped", NID_pkcs7_enveloped }, { "encrypted", NID_pkcs7_encrypted }, { "digest", NID_pkcs7_digest }, { NULL, 0 }, }; if(TYPE(sym) == T_SYMBOL) s = rb_id2name(SYM2ID(sym)); else s = StringValuePtr(sym); for(i = 0; i < numberof(p7_type_tab); i++){ if(p7_type_tab[i].name == NULL) ossl_raise(ePKCS7Error, "unknown type \"%s\"", s); if(strcmp(p7_type_tab[i].name, s) == 0){ ret = p7_type_tab[i].nid; break; } } return ret; } /* * call-seq: * pkcs7.type = type => type */ static VALUE ossl_pkcs7_set_type(VALUE self, VALUE type) { PKCS7 *p7; GetPKCS7(self, p7); if(!PKCS7_set_type(p7, ossl_pkcs7_sym2typeid(type))) ossl_raise(ePKCS7Error, NULL); return type; } /* * call-seq: * pkcs7.type => string or nil */ static VALUE ossl_pkcs7_get_type(VALUE self) { PKCS7 *p7; GetPKCS7(self, p7); if(PKCS7_type_is_signed(p7)) return ID2SYM(rb_intern("signed")); if(PKCS7_type_is_encrypted(p7)) return ID2SYM(rb_intern("encrypted")); if(PKCS7_type_is_enveloped(p7)) return ID2SYM(rb_intern("enveloped")); if(PKCS7_type_is_signedAndEnveloped(p7)) return ID2SYM(rb_intern("signedAndEnveloped")); if(PKCS7_type_is_data(p7)) return ID2SYM(rb_intern("data")); return Qnil; } static VALUE ossl_pkcs7_set_detached(VALUE self, VALUE flag) { PKCS7 *p7; GetPKCS7(self, p7); if(flag != Qtrue && flag != Qfalse) ossl_raise(ePKCS7Error, "must specify a boolean"); if(!PKCS7_set_detached(p7, flag == Qtrue ? 1 : 0)) ossl_raise(ePKCS7Error, NULL); return flag; } static VALUE ossl_pkcs7_get_detached(VALUE self) { PKCS7 *p7; GetPKCS7(self, p7); return PKCS7_get_detached(p7) ? Qtrue : Qfalse; } static VALUE ossl_pkcs7_detached_p(VALUE self) { PKCS7 *p7; GetPKCS7(self, p7); return PKCS7_is_detached(p7) ? Qtrue : Qfalse; } static VALUE ossl_pkcs7_set_cipher(VALUE self, VALUE cipher) { PKCS7 *pkcs7; GetPKCS7(self, pkcs7); if (!PKCS7_set_cipher(pkcs7, GetCipherPtr(cipher))) { ossl_raise(ePKCS7Error, NULL); } return cipher; } static VALUE ossl_pkcs7_add_signer(VALUE self, VALUE signer) { PKCS7 *pkcs7; PKCS7_SIGNER_INFO *p7si; p7si = DupPKCS7SignerPtr(signer); /* NEED TO DUP */ GetPKCS7(self, pkcs7); if (!PKCS7_add_signer(pkcs7, p7si)) { PKCS7_SIGNER_INFO_free(p7si); ossl_raise(ePKCS7Error, "Could not add signer."); } if (PKCS7_type_is_signed(pkcs7)){ PKCS7_add_signed_attribute(p7si, NID_pkcs9_contentType, V_ASN1_OBJECT, OBJ_nid2obj(NID_pkcs7_data)); } return self; } static VALUE ossl_pkcs7_get_signer(VALUE self) { PKCS7 *pkcs7; STACK_OF(PKCS7_SIGNER_INFO) *sk; PKCS7_SIGNER_INFO *si; int num, i; VALUE ary; GetPKCS7(self, pkcs7); if (!(sk = PKCS7_get_signer_info(pkcs7))) { OSSL_Debug("OpenSSL::PKCS7#get_signer_info == NULL!"); return rb_ary_new(); } if ((num = sk_PKCS7_SIGNER_INFO_num(sk)) < 0) { ossl_raise(ePKCS7Error, "Negative number of signers!"); } ary = rb_ary_new2(num); for (i=0; id.enveloped->recipientinfo; else if (PKCS7_type_is_signedAndEnveloped(pkcs7)) sk = pkcs7->d.signed_and_enveloped->recipientinfo; else sk = NULL; if (!sk) return rb_ary_new(); if ((num = sk_PKCS7_RECIP_INFO_num(sk)) < 0) { ossl_raise(ePKCS7Error, "Negative number of recipient!"); } ary = rb_ary_new2(num); for (i=0; itype); switch(i){ case NID_pkcs7_signed: certs = pkcs7->d.sign->cert; break; case NID_pkcs7_signedAndEnveloped: certs = pkcs7->d.signed_and_enveloped->cert; break; default: certs = NULL; } return certs; } static STACK_OF(X509_CRL) * pkcs7_get_crls(VALUE self) { PKCS7 *pkcs7; STACK_OF(X509_CRL) *crls; int i; GetPKCS7(self, pkcs7); i = OBJ_obj2nid(pkcs7->type); switch(i){ case NID_pkcs7_signed: crls = pkcs7->d.sign->crl; break; case NID_pkcs7_signedAndEnveloped: crls = pkcs7->d.signed_and_enveloped->crl; break; default: crls = NULL; } return crls; } static VALUE ossl_pkcs7_set_certs_i(VALUE i, VALUE arg) { return ossl_pkcs7_add_certificate(arg, i); } static VALUE ossl_pkcs7_set_certificates(VALUE self, VALUE ary) { STACK_OF(X509) *certs; X509 *cert; certs = pkcs7_get_certs(self); while((cert = sk_X509_pop(certs))) X509_free(cert); rb_block_call(ary, rb_intern("each"), 0, 0, ossl_pkcs7_set_certs_i, self); return ary; } static VALUE ossl_pkcs7_get_certificates(VALUE self) { return ossl_x509_sk2ary(pkcs7_get_certs(self)); } static VALUE ossl_pkcs7_add_crl(VALUE self, VALUE crl) { PKCS7 *pkcs7; X509_CRL *x509crl; GetPKCS7(self, pkcs7); /* NO DUP needed! */ x509crl = GetX509CRLPtr(crl); if (!PKCS7_add_crl(pkcs7, x509crl)) { ossl_raise(ePKCS7Error, NULL); } return self; } static VALUE ossl_pkcs7_set_crls_i(VALUE i, VALUE arg) { return ossl_pkcs7_add_crl(arg, i); } static VALUE ossl_pkcs7_set_crls(VALUE self, VALUE ary) { STACK_OF(X509_CRL) *crls; X509_CRL *crl; crls = pkcs7_get_crls(self); while((crl = sk_X509_CRL_pop(crls))) X509_CRL_free(crl); rb_block_call(ary, rb_intern("each"), 0, 0, ossl_pkcs7_set_crls_i, self); return ary; } static VALUE ossl_pkcs7_get_crls(VALUE self) { return ossl_x509crl_sk2ary(pkcs7_get_crls(self)); } static VALUE ossl_pkcs7_verify(int argc, VALUE *argv, VALUE self) { VALUE certs, store, indata, flags; STACK_OF(X509) *x509s; X509_STORE *x509st; int flg, ok, status = 0; BIO *in, *out; PKCS7 *p7; VALUE data; const char *msg; rb_scan_args(argc, argv, "22", &certs, &store, &indata, &flags); flg = NIL_P(flags) ? 0 : NUM2INT(flags); if(NIL_P(indata)) indata = ossl_pkcs7_get_data(self); in = NIL_P(indata) ? NULL : ossl_obj2bio(indata); if(NIL_P(certs)) x509s = NULL; else{ x509s = ossl_protect_x509_ary2sk(certs, &status); if(status){ BIO_free(in); rb_jump_tag(status); } } x509st = GetX509StorePtr(store); GetPKCS7(self, p7); if(!(out = BIO_new(BIO_s_mem()))){ BIO_free(in); sk_X509_pop_free(x509s, X509_free); ossl_raise(ePKCS7Error, NULL); } ok = PKCS7_verify(p7, x509s, x509st, in, out, flg); BIO_free(in); if (ok < 0) ossl_raise(ePKCS7Error, NULL); msg = ERR_reason_error_string(ERR_get_error()); ossl_pkcs7_set_err_string(self, msg ? rb_str_new2(msg) : Qnil); ERR_clear_error(); data = ossl_membio2str(out); ossl_pkcs7_set_data(self, data); sk_X509_pop_free(x509s, X509_free); return (ok == 1) ? Qtrue : Qfalse; } static VALUE ossl_pkcs7_decrypt(int argc, VALUE *argv, VALUE self) { VALUE pkey, cert, flags; EVP_PKEY *key; X509 *x509; int flg; PKCS7 *p7; BIO *out; VALUE str; rb_scan_args(argc, argv, "21", &pkey, &cert, &flags); key = GetPrivPKeyPtr(pkey); /* NO NEED TO DUP */ x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */ flg = NIL_P(flags) ? 0 : NUM2INT(flags); GetPKCS7(self, p7); if(!(out = BIO_new(BIO_s_mem()))) ossl_raise(ePKCS7Error, NULL); if(!PKCS7_decrypt(p7, key, x509, out, flg)){ BIO_free(out); ossl_raise(ePKCS7Error, NULL); } str = ossl_membio2str(out); /* out will be free */ return str; } static VALUE ossl_pkcs7_add_data(VALUE self, VALUE data) { PKCS7 *pkcs7; BIO *out, *in; char buf[4096]; int len; in = ossl_obj2bio(data); GetPKCS7(self, pkcs7); if(PKCS7_type_is_signed(pkcs7)){ if(!PKCS7_content_new(pkcs7, NID_pkcs7_data)) ossl_raise(ePKCS7Error, NULL); } if(!(out = PKCS7_dataInit(pkcs7, NULL))) goto err; for(;;){ if((len = BIO_read(in, buf, sizeof(buf))) <= 0) break; if(BIO_write(out, buf, len) != len) goto err; } if(!PKCS7_dataFinal(pkcs7, out)) goto err; ossl_pkcs7_set_data(self, Qnil); err: BIO_free(out); BIO_free(in); if(ERR_peek_error()){ ossl_raise(ePKCS7Error, NULL); } return data; } static VALUE ossl_pkcs7_to_der(VALUE self) { PKCS7 *pkcs7; VALUE str; long len; unsigned char *p; GetPKCS7(self, pkcs7); if((len = i2d_PKCS7(pkcs7, NULL)) <= 0) ossl_raise(ePKCS7Error, NULL); str = rb_str_new(0, len); p = RSTRING_PTR(str); if(i2d_PKCS7(pkcs7, &p) <= 0) ossl_raise(ePKCS7Error, NULL); ossl_str_adjust(str, p); return str; } static VALUE ossl_pkcs7_to_pem(VALUE self) { PKCS7 *pkcs7; BIO *out; VALUE str; GetPKCS7(self, pkcs7); if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(ePKCS7Error, NULL); } if (!PEM_write_bio_PKCS7(out, pkcs7)) { BIO_free(out); ossl_raise(ePKCS7Error, NULL); } str = ossl_membio2str(out); return str; } /* * SIGNER INFO */ static VALUE ossl_pkcs7si_alloc(VALUE klass) { PKCS7_SIGNER_INFO *p7si; VALUE obj; if (!(p7si = PKCS7_SIGNER_INFO_new())) { ossl_raise(ePKCS7Error, NULL); } WrapPKCS7si(klass, obj, p7si); return obj; } static VALUE ossl_pkcs7si_initialize(VALUE self, VALUE cert, VALUE key, VALUE digest) { PKCS7_SIGNER_INFO *p7si; EVP_PKEY *pkey; X509 *x509; const EVP_MD *md; pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */ md = GetDigestPtr(digest); GetPKCS7si(self, p7si); if (!(PKCS7_SIGNER_INFO_set(p7si, x509, pkey, (EVP_MD*)md))) { ossl_raise(ePKCS7Error, NULL); } return self; } static VALUE ossl_pkcs7si_get_issuer(VALUE self) { PKCS7_SIGNER_INFO *p7si; GetPKCS7si(self, p7si); return ossl_x509name_new(p7si->issuer_and_serial->issuer); } static VALUE ossl_pkcs7si_get_serial(VALUE self) { PKCS7_SIGNER_INFO *p7si; GetPKCS7si(self, p7si); return asn1integer_to_num(p7si->issuer_and_serial->serial); } static VALUE ossl_pkcs7si_get_signed_time(VALUE self) { PKCS7_SIGNER_INFO *p7si; ASN1_TYPE *asn1obj; GetPKCS7si(self, p7si); if (!(asn1obj = PKCS7_get_signed_attribute(p7si, NID_pkcs9_signingTime))) { ossl_raise(ePKCS7Error, NULL); } if (asn1obj->type == V_ASN1_UTCTIME) { return asn1time_to_time(asn1obj->value.utctime); } /* * OR * ossl_raise(ePKCS7Error, "..."); * ? */ return Qnil; } /* * RECIPIENT INFO */ static VALUE ossl_pkcs7ri_alloc(VALUE klass) { PKCS7_RECIP_INFO *p7ri; VALUE obj; if (!(p7ri = PKCS7_RECIP_INFO_new())) { ossl_raise(ePKCS7Error, NULL); } WrapPKCS7ri(klass, obj, p7ri); return obj; } static VALUE ossl_pkcs7ri_initialize(VALUE self, VALUE cert) { PKCS7_RECIP_INFO *p7ri; X509 *x509; x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */ GetPKCS7ri(self, p7ri); if (!PKCS7_RECIP_INFO_set(p7ri, x509)) { ossl_raise(ePKCS7Error, NULL); } return self; } static VALUE ossl_pkcs7ri_get_issuer(VALUE self) { PKCS7_RECIP_INFO *p7ri; GetPKCS7ri(self, p7ri); return ossl_x509name_new(p7ri->issuer_and_serial->issuer); } static VALUE ossl_pkcs7ri_get_serial(VALUE self) { PKCS7_RECIP_INFO *p7ri; GetPKCS7ri(self, p7ri); return asn1integer_to_num(p7ri->issuer_and_serial->serial); } static VALUE ossl_pkcs7ri_get_enc_key(VALUE self) { PKCS7_RECIP_INFO *p7ri; GetPKCS7ri(self, p7ri); return asn1str_to_str(p7ri->enc_key); } /* * INIT */ void Init_ossl_pkcs7() { cPKCS7 = rb_define_class_under(mOSSL, "PKCS7", rb_cObject); ePKCS7Error = rb_define_class_under(cPKCS7, "PKCS7Error", eOSSLError); rb_define_singleton_method(cPKCS7, "read_smime", ossl_pkcs7_s_read_smime, 1); rb_define_singleton_method(cPKCS7, "write_smime", ossl_pkcs7_s_write_smime, -1); rb_define_singleton_method(cPKCS7, "sign", ossl_pkcs7_s_sign, -1); rb_define_singleton_method(cPKCS7, "encrypt", ossl_pkcs7_s_encrypt, -1); rb_attr(cPKCS7, rb_intern("data"), 1, 0, Qfalse); rb_attr(cPKCS7, rb_intern("error_string"), 1, 1, Qfalse); rb_define_alloc_func(cPKCS7, ossl_pkcs7_alloc); rb_define_copy_func(cPKCS7, ossl_pkcs7_copy); rb_define_method(cPKCS7, "initialize", ossl_pkcs7_initialize, -1); rb_define_method(cPKCS7, "type=", ossl_pkcs7_set_type, 1); rb_define_method(cPKCS7, "type", ossl_pkcs7_get_type, 0); rb_define_method(cPKCS7, "detached=", ossl_pkcs7_set_detached, 1); rb_define_method(cPKCS7, "detached", ossl_pkcs7_get_detached, 0); rb_define_method(cPKCS7, "detached?", ossl_pkcs7_detached_p, 0); rb_define_method(cPKCS7, "cipher=", ossl_pkcs7_set_cipher, 1); rb_define_method(cPKCS7, "add_signer", ossl_pkcs7_add_signer, 1); rb_define_method(cPKCS7, "signers", ossl_pkcs7_get_signer, 0); rb_define_method(cPKCS7, "add_recipient", ossl_pkcs7_add_recipient, 1); rb_define_method(cPKCS7, "recipients", ossl_pkcs7_get_recipient, 0); rb_define_method(cPKCS7, "add_certificate", ossl_pkcs7_add_certificate, 1); rb_define_method(cPKCS7, "certificates=", ossl_pkcs7_set_certificates, 1); rb_define_method(cPKCS7, "certificates", ossl_pkcs7_get_certificates, 0); rb_define_method(cPKCS7, "add_crl", ossl_pkcs7_add_crl, 1); rb_define_method(cPKCS7, "crls=", ossl_pkcs7_set_crls, 1); rb_define_method(cPKCS7, "crls", ossl_pkcs7_get_crls, 0); rb_define_method(cPKCS7, "add_data", ossl_pkcs7_add_data, 1); rb_define_alias(cPKCS7, "data=", "add_data"); rb_define_method(cPKCS7, "verify", ossl_pkcs7_verify, -1); rb_define_method(cPKCS7, "decrypt", ossl_pkcs7_decrypt, -1); rb_define_method(cPKCS7, "to_pem", ossl_pkcs7_to_pem, 0); rb_define_alias(cPKCS7, "to_s", "to_pem"); rb_define_method(cPKCS7, "to_der", ossl_pkcs7_to_der, 0); cPKCS7Signer = rb_define_class_under(cPKCS7, "SignerInfo", rb_cObject); rb_define_const(cPKCS7, "Signer", cPKCS7Signer); rb_define_alloc_func(cPKCS7Signer, ossl_pkcs7si_alloc); rb_define_method(cPKCS7Signer, "initialize", ossl_pkcs7si_initialize,3); rb_define_method(cPKCS7Signer, "issuer", ossl_pkcs7si_get_issuer, 0); rb_define_alias(cPKCS7Signer, "name", "issuer"); rb_define_method(cPKCS7Signer, "serial", ossl_pkcs7si_get_serial,0); rb_define_method(cPKCS7Signer,"signed_time",ossl_pkcs7si_get_signed_time,0); cPKCS7Recipient = rb_define_class_under(cPKCS7,"RecipientInfo",rb_cObject); rb_define_alloc_func(cPKCS7Recipient, ossl_pkcs7ri_alloc); rb_define_method(cPKCS7Recipient, "initialize", ossl_pkcs7ri_initialize,1); rb_define_method(cPKCS7Recipient, "issuer", ossl_pkcs7ri_get_issuer,0); rb_define_method(cPKCS7Recipient, "serial", ossl_pkcs7ri_get_serial,0); rb_define_method(cPKCS7Recipient, "enc_key", ossl_pkcs7ri_get_enc_key,0); #define DefPKCS7Const(x) rb_define_const(cPKCS7, #x, INT2NUM(PKCS7_##x)) DefPKCS7Const(TEXT); DefPKCS7Const(NOCERTS); DefPKCS7Const(NOSIGS); DefPKCS7Const(NOCHAIN); DefPKCS7Const(NOINTERN); DefPKCS7Const(NOVERIFY); DefPKCS7Const(DETACHED); DefPKCS7Const(BINARY); DefPKCS7Const(NOATTR); DefPKCS7Const(NOSMIMECAP); } ================================================ FILE: ext/openssl/ossl_pkcs7.h ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(_OSSL_PKCS7_H_) #define _OSSL_PKCS7_H_ extern VALUE cPKCS7; extern VALUE cPKCS7Signer; extern VALUE cPKCS7Recipient; extern VALUE ePKCS7Error; void Init_ossl_pkcs7(void); #endif /* _OSSL_PKCS7_H_ */ ================================================ FILE: ext/openssl/ossl_pkey.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" /* * Classes */ VALUE mPKey; VALUE cPKey; VALUE ePKeyError; ID id_private_q; /* * callback for generating keys */ void ossl_generate_cb(int p, int n, void *arg) { VALUE ary; ary = rb_ary_new2(2); rb_ary_store(ary, 0, INT2NUM(p)); rb_ary_store(ary, 1, INT2NUM(n)); rb_yield(ary); } /* * Public */ VALUE ossl_pkey_new(EVP_PKEY *pkey) { if (!pkey) { ossl_raise(ePKeyError, "Cannot make new key from NULL."); } switch (EVP_PKEY_type(pkey->type)) { #if !defined(OPENSSL_NO_RSA) case EVP_PKEY_RSA: return ossl_rsa_new(pkey); #endif #if !defined(OPENSSL_NO_DSA) case EVP_PKEY_DSA: return ossl_dsa_new(pkey); #endif #if !defined(OPENSSL_NO_DH) case EVP_PKEY_DH: return ossl_dh_new(pkey); #endif #if !defined(OPENSSL_NO_EC) && (OPENSSL_VERSION_NUMBER >= 0x0090802fL) case EVP_PKEY_EC: return ossl_ec_new(pkey); #endif default: ossl_raise(ePKeyError, "unsupported key type"); } return Qnil; /* not reached */ } VALUE ossl_pkey_new_from_file(VALUE filename) { FILE *fp; EVP_PKEY *pkey; SafeStringValue(filename); if (!(fp = fopen(RSTRING_PTR(filename), "r"))) { ossl_raise(ePKeyError, "%s", strerror(errno)); } pkey = PEM_read_PrivateKey(fp, NULL, ossl_pem_passwd_cb, NULL); fclose(fp); if (!pkey) { ossl_raise(ePKeyError, NULL); } return ossl_pkey_new(pkey); } EVP_PKEY * GetPKeyPtr(VALUE obj) { EVP_PKEY *pkey; SafeGetPKey(obj, pkey); return pkey; } EVP_PKEY * GetPrivPKeyPtr(VALUE obj) { EVP_PKEY *pkey; if (rb_funcall(obj, id_private_q, 0, NULL) != Qtrue) { ossl_raise(rb_eArgError, "Private key is needed."); } SafeGetPKey(obj, pkey); return pkey; } EVP_PKEY * DupPKeyPtr(VALUE obj) { EVP_PKEY *pkey; SafeGetPKey(obj, pkey); CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY); return pkey; } EVP_PKEY * DupPrivPKeyPtr(VALUE obj) { EVP_PKEY *pkey; if (rb_funcall(obj, id_private_q, 0, NULL) != Qtrue) { ossl_raise(rb_eArgError, "Private key is needed."); } SafeGetPKey(obj, pkey); CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY); return pkey; } /* * Private */ static VALUE ossl_pkey_alloc(VALUE klass) { EVP_PKEY *pkey; VALUE obj; if (!(pkey = EVP_PKEY_new())) { ossl_raise(ePKeyError, NULL); } WrapPKey(klass, obj, pkey); return obj; } static VALUE ossl_pkey_initialize(VALUE self) { if (rb_obj_is_instance_of(self, cPKey)) { ossl_raise(rb_eNotImpError, "OpenSSL::PKey::PKey is an abstract class."); } return self; } static VALUE ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) { EVP_PKEY *pkey; EVP_MD_CTX ctx; int buf_len; VALUE str; if (rb_funcall(self, id_private_q, 0, NULL) != Qtrue) { ossl_raise(rb_eArgError, "Private key is needed."); } GetPKey(self, pkey); EVP_SignInit(&ctx, GetDigestPtr(digest)); StringValue(data); EVP_SignUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data)); str = rb_str_new(0, EVP_PKEY_size(pkey)+16); if (!EVP_SignFinal(&ctx, RSTRING_PTR(str), &buf_len, pkey)) ossl_raise(ePKeyError, NULL); assert(buf_len <= RSTRING_LEN(str)); rb_str_set_len(str, buf_len); return str; } static VALUE ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) { EVP_PKEY *pkey; EVP_MD_CTX ctx; GetPKey(self, pkey); EVP_VerifyInit(&ctx, GetDigestPtr(digest)); StringValue(sig); StringValue(data); EVP_VerifyUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data)); switch (EVP_VerifyFinal(&ctx, RSTRING_PTR(sig), RSTRING_LEN(sig), pkey)) { case 0: return Qfalse; case 1: return Qtrue; default: ossl_raise(ePKeyError, NULL); } return Qnil; /* dummy */ } /* * INIT */ void Init_ossl_pkey() { #if 0 /* let rdoc know about mOSSL */ mOSSL = rb_define_module("OpenSSL"); #endif mPKey = rb_define_module_under(mOSSL, "PKey"); ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError); cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject); rb_define_alloc_func(cPKey, ossl_pkey_alloc); rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0); rb_define_method(cPKey, "sign", ossl_pkey_sign, 2); rb_define_method(cPKey, "verify", ossl_pkey_verify, 3); id_private_q = rb_intern("private?"); /* * INIT rsa, dsa, dh, ec */ Init_ossl_rsa(); Init_ossl_dsa(); Init_ossl_dh(); Init_ossl_ec(); } ================================================ FILE: ext/openssl/ossl_pkey.h ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(_OSSL_PKEY_H_) #define _OSSL_PKEY_H_ extern VALUE mPKey; extern VALUE cPKey; extern VALUE ePKeyError; extern ID id_private_q; #define OSSL_PKEY_SET_PRIVATE(obj) rb_iv_set((obj), "private", Qtrue) #define OSSL_PKEY_SET_PUBLIC(obj) rb_iv_set((obj), "private", Qfalse) #define OSSL_PKEY_IS_PRIVATE(obj) (rb_iv_get((obj), "private") == Qtrue) #define WrapPKey(klass, obj, pkey) do { \ if (!pkey) { \ rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!"); \ } \ obj = Data_Wrap_Struct(klass, 0, EVP_PKEY_free, pkey); \ OSSL_PKEY_SET_PUBLIC(obj); \ } while (0) #define GetPKey(obj, pkey) do {\ Data_Get_Struct(obj, EVP_PKEY, pkey);\ if (!pkey) { \ rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\ } \ } while (0) #define SafeGetPKey(obj, pkey) do { \ OSSL_Check_Kind(obj, cPKey); \ GetPKey(obj, pkey); \ } while (0) void ossl_generate_cb(int, int, void *); VALUE ossl_pkey_new(EVP_PKEY *); VALUE ossl_pkey_new_from_file(VALUE); EVP_PKEY *GetPKeyPtr(VALUE); EVP_PKEY *DupPKeyPtr(VALUE); EVP_PKEY *GetPrivPKeyPtr(VALUE); EVP_PKEY *DupPrivPKeyPtr(VALUE); void Init_ossl_pkey(void); /* * RSA */ extern VALUE cRSA; extern VALUE eRSAError; VALUE ossl_rsa_new(EVP_PKEY *); void Init_ossl_rsa(void); /* * DSA */ extern VALUE cDSA; extern VALUE eDSAError; VALUE ossl_dsa_new(EVP_PKEY *); void Init_ossl_dsa(void); /* * DH */ extern VALUE cDH; extern VALUE eDHError; extern DH *OSSL_DEFAULT_DH_512; extern DH *OSSL_DEFAULT_DH_1024; VALUE ossl_dh_new(EVP_PKEY *); void Init_ossl_dh(void); /* * EC */ extern VALUE cEC; extern VALUE eECError; extern VALUE cEC_GROUP; extern VALUE eEC_GROUP; extern VALUE cEC_POINT; extern VALUE eEC_POINT; VALUE ossl_ec_new(EVP_PKEY *); void Init_ossl_ec(void); #define OSSL_PKEY_BN(keytype, name) \ /* \ * call-seq: \ * key.##name -> aBN \ */ \ static VALUE ossl_##keytype##_get_##name(VALUE self) \ { \ EVP_PKEY *pkey; \ BIGNUM *bn; \ \ GetPKey(self, pkey); \ bn = pkey->pkey.keytype->name; \ if (bn == NULL) \ return Qnil; \ return ossl_bn_new(bn); \ } \ /* \ * call-seq: \ * key.##name = bn -> bn \ */ \ static VALUE ossl_##keytype##_set_##name(VALUE self, VALUE bignum) \ { \ EVP_PKEY *pkey; \ BIGNUM *bn; \ \ GetPKey(self, pkey); \ if (NIL_P(bignum)) { \ BN_clear_free(pkey->pkey.keytype->name); \ pkey->pkey.keytype->name = NULL; \ return Qnil; \ } \ \ bn = GetBNPtr(bignum); \ if (pkey->pkey.keytype->name == NULL) \ pkey->pkey.keytype->name = BN_new(); \ if (pkey->pkey.keytype->name == NULL) \ ossl_raise(eBNError, NULL); \ if (BN_copy(pkey->pkey.keytype->name, bn) == NULL) \ ossl_raise(eBNError, NULL); \ return bignum; \ } #define DEF_OSSL_PKEY_BN(class, keytype, name) \ do { \ rb_define_method(class, #name, ossl_##keytype##_get_##name, 0); \ rb_define_method(class, #name "=", ossl_##keytype##_set_##name, 1);\ } while (0) #endif /* _OSSL_PKEY_H_ */ ================================================ FILE: ext/openssl/ossl_pkey_dh.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(OPENSSL_NO_DH) #include "ossl.h" #define GetPKeyDH(obj, pkey) do { \ GetPKey(obj, pkey); \ if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DH) { /* PARANOIA? */ \ ossl_raise(rb_eRuntimeError, "THIS IS NOT A DH!") ; \ } \ } while (0) #define DH_HAS_PRIVATE(dh) ((dh)->priv_key) #ifdef OSSL_ENGINE_ENABLED # define DH_PRIVATE(dh) (DH_HAS_PRIVATE(dh) || (dh)->engine) #else # define DH_PRIVATE(dh) DH_HAS_PRIVATE(dh) #endif /* * Classes */ VALUE cDH; VALUE eDHError; /* * Public */ static VALUE dh_instance(VALUE klass, DH *dh) { EVP_PKEY *pkey; VALUE obj; if (!dh) { return Qfalse; } if (!(pkey = EVP_PKEY_new())) { return Qfalse; } if (!EVP_PKEY_assign_DH(pkey, dh)) { EVP_PKEY_free(pkey); return Qfalse; } WrapPKey(klass, obj, pkey); return obj; } VALUE ossl_dh_new(EVP_PKEY *pkey) { VALUE obj; if (!pkey) { obj = dh_instance(cDH, DH_new()); } else { if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DH) { ossl_raise(rb_eTypeError, "Not a DH key!"); } WrapPKey(cDH, obj, pkey); } if (obj == Qfalse) { ossl_raise(eDHError, NULL); } return obj; } /* * Private */ static DH * dh_generate(int size, int gen) { DH *dh; dh = DH_generate_parameters(size, gen, rb_block_given_p() ? ossl_generate_cb : NULL, NULL); if (!dh) return 0; if (!DH_generate_key(dh)) { DH_free(dh); return 0; } return dh; } /* * call-seq: * DH.generate(size [, generator]) -> dh * * === Parameters * * +size+ is an integer representing the desired key size. Keys smaller than 1024 should be considered insecure. * * +generator+ is a small number > 1, typically 2 or 5. * */ static VALUE ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass) { DH *dh ; int g = 2; VALUE size, gen, obj; if (rb_scan_args(argc, argv, "11", &size, &gen) == 2) { g = NUM2INT(gen); } dh = dh_generate(NUM2INT(size), g); obj = dh_instance(klass, dh); if (obj == Qfalse) { DH_free(dh); ossl_raise(eDHError, NULL); } return obj; } /* * call-seq: * DH.new([size [, generator] | string]) -> dh * * === Parameters * * +size+ is an integer representing the desired key size. Keys smaller than 1024 should be considered insecure. * * +generator+ is a small number > 1, typically 2 or 5. * * +string+ contains the DER or PEM encoded key. * * === Examples * * DH.new -> dh * * DH.new(1024) -> dh * * DH.new(1024, 5) -> dh * * DH.new(File.read('key.pem')) -> dh */ static VALUE ossl_dh_initialize(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; DH *dh; int g = 2; BIO *in; VALUE arg, gen; GetPKey(self, pkey); if(rb_scan_args(argc, argv, "02", &arg, &gen) == 0) { dh = DH_new(); } else if (FIXNUM_P(arg)) { if (!NIL_P(gen)) { g = NUM2INT(gen); } if (!(dh = dh_generate(FIX2INT(arg), g))) { ossl_raise(eDHError, NULL); } } else { arg = ossl_to_der_if_possible(arg); in = ossl_obj2bio(arg); dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL); if (!dh){ BIO_reset(in); dh = d2i_DHparams_bio(in, NULL); } BIO_free(in); if (!dh) ossl_raise(eDHError, NULL); } if (!EVP_PKEY_assign_DH(pkey, dh)) { DH_free(dh); ossl_raise(eDHError, NULL); } return self; } /* * call-seq: * dh.public? -> true | false * */ static VALUE ossl_dh_is_public(VALUE self) { EVP_PKEY *pkey; GetPKeyDH(self, pkey); return (pkey->pkey.dh->pub_key) ? Qtrue : Qfalse; } /* * call-seq: * dh.private? -> true | false * */ static VALUE ossl_dh_is_private(VALUE self) { EVP_PKEY *pkey; GetPKeyDH(self, pkey); return (DH_PRIVATE(pkey->pkey.dh)) ? Qtrue : Qfalse; } /* * call-seq: * dh.to_pem -> aString * */ static VALUE ossl_dh_export(VALUE self) { EVP_PKEY *pkey; BIO *out; VALUE str; GetPKeyDH(self, pkey); if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eDHError, NULL); } if (!PEM_write_bio_DHparams(out, pkey->pkey.dh)) { BIO_free(out); ossl_raise(eDHError, NULL); } str = ossl_membio2str(out); return str; } /* * call-seq: * dh.to_der -> aString * */ static VALUE ossl_dh_to_der(VALUE self) { EVP_PKEY *pkey; unsigned char *p; long len; VALUE str; GetPKeyDH(self, pkey); if((len = i2d_DHparams(pkey->pkey.dh, NULL)) <= 0) ossl_raise(eDHError, NULL); str = rb_str_new(0, len); p = RSTRING_PTR(str); if(i2d_DHparams(pkey->pkey.dh, &p) < 0) ossl_raise(eDHError, NULL); ossl_str_adjust(str, p); return str; } /* * call-seq: * dh.params -> hash * * Stores all parameters of key to the hash * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! * Don't use :-)) (I's up to you) */ static VALUE ossl_dh_get_params(VALUE self) { EVP_PKEY *pkey; VALUE hash; GetPKeyDH(self, pkey); hash = rb_hash_new(); rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(pkey->pkey.dh->p)); rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(pkey->pkey.dh->g)); rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pkey->pkey.dh->pub_key)); rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(pkey->pkey.dh->priv_key)); return hash; } /* * call-seq: * dh.to_text -> aString * * Prints all parameters of key to buffer * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! * Don't use :-)) (I's up to you) */ static VALUE ossl_dh_to_text(VALUE self) { EVP_PKEY *pkey; BIO *out; VALUE str; GetPKeyDH(self, pkey); if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eDHError, NULL); } if (!DHparams_print(out, pkey->pkey.dh)) { BIO_free(out); ossl_raise(eDHError, NULL); } str = ossl_membio2str(out); return str; } /* * call-seq: * dh.public_key -> aDH * * Makes new instance DH PUBLIC_KEY from PRIVATE_KEY */ static VALUE ossl_dh_to_public_key(VALUE self) { EVP_PKEY *pkey; DH *dh; VALUE obj; GetPKeyDH(self, pkey); dh = DHparams_dup(pkey->pkey.dh); /* err check perfomed by dh_instance */ obj = dh_instance(CLASS_OF(self), dh); if (obj == Qfalse) { DH_free(dh); ossl_raise(eDHError, NULL); } return obj; } /* * call-seq: * dh.check_params -> true | false * */ static VALUE ossl_dh_check_params(VALUE self) { DH *dh; EVP_PKEY *pkey; int codes; GetPKeyDH(self, pkey); dh = pkey->pkey.dh; if (!DH_check(dh, &codes)) { return Qfalse; } return codes == 0 ? Qtrue : Qfalse; } /* * call-seq: * dh.generate_key -> self * */ static VALUE ossl_dh_generate_key(VALUE self) { DH *dh; EVP_PKEY *pkey; GetPKeyDH(self, pkey); dh = pkey->pkey.dh; if (!DH_generate_key(dh)) ossl_raise(eDHError, "Failed to generate key"); return self; } /* * call-seq: * dh.compute_key(pub_bn) -> aString * * === Parameters * * +pub_bn+ is a OpenSSL::BN. * * Returns aString containing a shared secret computed from the other parties public value. * * See DH_compute_key() for further information. * */ static VALUE ossl_dh_compute_key(VALUE self, VALUE pub) { DH *dh; EVP_PKEY *pkey; BIGNUM *pub_key; VALUE str; int len; GetPKeyDH(self, pkey); dh = pkey->pkey.dh; pub_key = GetBNPtr(pub); len = DH_size(dh); str = rb_str_new(0, len); if ((len = DH_compute_key(RSTRING_PTR(str), pub_key, dh)) < 0) { ossl_raise(eDHError, NULL); } rb_str_set_len(str, len); return str; } OSSL_PKEY_BN(dh, p); OSSL_PKEY_BN(dh, g); OSSL_PKEY_BN(dh, pub_key); OSSL_PKEY_BN(dh, priv_key); /* * -----BEGIN DH PARAMETERS----- * MEYCQQD0zXHljRg/mJ9PYLACLv58Cd8VxBxxY7oEuCeURMiTqEhMym16rhhKgZG2 * zk2O9uUIBIxSj+NKMURHGaFKyIvLAgEC * -----END DH PARAMETERS----- */ static unsigned char DEFAULT_DH_512_PRIM[] = { 0xf4, 0xcd, 0x71, 0xe5, 0x8d, 0x18, 0x3f, 0x98, 0x9f, 0x4f, 0x60, 0xb0, 0x02, 0x2e, 0xfe, 0x7c, 0x09, 0xdf, 0x15, 0xc4, 0x1c, 0x71, 0x63, 0xba, 0x04, 0xb8, 0x27, 0x94, 0x44, 0xc8, 0x93, 0xa8, 0x48, 0x4c, 0xca, 0x6d, 0x7a, 0xae, 0x18, 0x4a, 0x81, 0x91, 0xb6, 0xce, 0x4d, 0x8e, 0xf6, 0xe5, 0x08, 0x04, 0x8c, 0x52, 0x8f, 0xe3, 0x4a, 0x31, 0x44, 0x47, 0x19, 0xa1, 0x4a, 0xc8, 0x8b, 0xcb, }; static unsigned char DEFAULT_DH_512_GEN[] = { 0x02 }; DH *OSSL_DEFAULT_DH_512 = NULL; /* * -----BEGIN DH PARAMETERS----- * MIGHAoGBAJ0lOVy0VIr/JebWn0zDwY2h+rqITFOpdNr6ugsgvkDXuucdcChhYExJ * AV/ZD2AWPbrTqV76mGRgJg4EddgT1zG0jq3rnFdMj2XzkBYx3BVvfR0Arnby0RHR * T4h7KZ/2zmjvV+eF8kBUHBJAojUlzxKj4QeO2x20FP9X5xmNUXeDAgEC * -----END DH PARAMETERS----- */ static unsigned char DEFAULT_DH_1024_PRIM[] = { 0x9d, 0x25, 0x39, 0x5c, 0xb4, 0x54, 0x8a, 0xff, 0x25, 0xe6, 0xd6, 0x9f, 0x4c, 0xc3, 0xc1, 0x8d, 0xa1, 0xfa, 0xba, 0x88, 0x4c, 0x53, 0xa9, 0x74, 0xda, 0xfa, 0xba, 0x0b, 0x20, 0xbe, 0x40, 0xd7, 0xba, 0xe7, 0x1d, 0x70, 0x28, 0x61, 0x60, 0x4c, 0x49, 0x01, 0x5f, 0xd9, 0x0f, 0x60, 0x16, 0x3d, 0xba, 0xd3, 0xa9, 0x5e, 0xfa, 0x98, 0x64, 0x60, 0x26, 0x0e, 0x04, 0x75, 0xd8, 0x13, 0xd7, 0x31, 0xb4, 0x8e, 0xad, 0xeb, 0x9c, 0x57, 0x4c, 0x8f, 0x65, 0xf3, 0x90, 0x16, 0x31, 0xdc, 0x15, 0x6f, 0x7d, 0x1d, 0x00, 0xae, 0x76, 0xf2, 0xd1, 0x11, 0xd1, 0x4f, 0x88, 0x7b, 0x29, 0x9f, 0xf6, 0xce, 0x68, 0xef, 0x57, 0xe7, 0x85, 0xf2, 0x40, 0x54, 0x1c, 0x12, 0x40, 0xa2, 0x35, 0x25, 0xcf, 0x12, 0xa3, 0xe1, 0x07, 0x8e, 0xdb, 0x1d, 0xb4, 0x14, 0xff, 0x57, 0xe7, 0x19, 0x8d, 0x51, 0x77, 0x83 }; static unsigned char DEFAULT_DH_1024_GEN[] = { 0x02 }; DH *OSSL_DEFAULT_DH_1024 = NULL; static DH* ossl_create_dh(unsigned char *p, size_t plen, unsigned char *g, size_t glen) { DH *dh; if ((dh = DH_new()) == NULL) ossl_raise(eDHError, NULL); dh->p = BN_bin2bn(p, plen, NULL); dh->g = BN_bin2bn(g, glen, NULL); if (dh->p == NULL || dh->g == NULL){ DH_free(dh); ossl_raise(eDHError, NULL); } return dh; } /* * INIT */ void Init_ossl_dh() { #if 0 /* let rdoc know about mOSSL and mPKey */ mOSSL = rb_define_module("OpenSSL"); mPKey = rb_define_module_under(mOSSL, "PKey"); #endif eDHError = rb_define_class_under(mPKey, "DHError", ePKeyError); cDH = rb_define_class_under(mPKey, "DH", cPKey); rb_define_singleton_method(cDH, "generate", ossl_dh_s_generate, -1); rb_define_method(cDH, "initialize", ossl_dh_initialize, -1); rb_define_method(cDH, "public?", ossl_dh_is_public, 0); rb_define_method(cDH, "private?", ossl_dh_is_private, 0); rb_define_method(cDH, "to_text", ossl_dh_to_text, 0); rb_define_method(cDH, "export", ossl_dh_export, 0); rb_define_alias(cDH, "to_pem", "export"); rb_define_alias(cDH, "to_s", "export"); rb_define_method(cDH, "to_der", ossl_dh_to_der, 0); rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0); rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0); rb_define_method(cDH, "generate_key!", ossl_dh_generate_key, 0); rb_define_method(cDH, "compute_key", ossl_dh_compute_key, 1); DEF_OSSL_PKEY_BN(cDH, dh, p); DEF_OSSL_PKEY_BN(cDH, dh, g); DEF_OSSL_PKEY_BN(cDH, dh, pub_key); DEF_OSSL_PKEY_BN(cDH, dh, priv_key); rb_define_method(cDH, "params", ossl_dh_get_params, 0); OSSL_DEFAULT_DH_512 = ossl_create_dh( DEFAULT_DH_512_PRIM, sizeof(DEFAULT_DH_512_PRIM), DEFAULT_DH_512_GEN, sizeof(DEFAULT_DH_512_GEN)); OSSL_DEFAULT_DH_1024 = ossl_create_dh( DEFAULT_DH_1024_PRIM, sizeof(DEFAULT_DH_1024_PRIM), DEFAULT_DH_1024_GEN, sizeof(DEFAULT_DH_1024_GEN)); } #else /* defined NO_DH */ void Init_ossl_dh() { } #endif /* NO_DH */ ================================================ FILE: ext/openssl/ossl_pkey_dsa.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(OPENSSL_NO_DSA) #include "ossl.h" #define GetPKeyDSA(obj, pkey) do { \ GetPKey(obj, pkey); \ if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DSA) { /* PARANOIA? */ \ ossl_raise(rb_eRuntimeError, "THIS IS NOT A DSA!"); \ } \ } while (0) #define DSA_HAS_PRIVATE(dsa) ((dsa)->priv_key) #define DSA_PRIVATE(obj,dsa) (DSA_HAS_PRIVATE(dsa)||OSSL_PKEY_IS_PRIVATE(obj)) /* * Classes */ VALUE cDSA; VALUE eDSAError; /* * Public */ static VALUE dsa_instance(VALUE klass, DSA *dsa) { EVP_PKEY *pkey; VALUE obj; if (!dsa) { return Qfalse; } if (!(pkey = EVP_PKEY_new())) { return Qfalse; } if (!EVP_PKEY_assign_DSA(pkey, dsa)) { EVP_PKEY_free(pkey); return Qfalse; } WrapPKey(klass, obj, pkey); return obj; } VALUE ossl_dsa_new(EVP_PKEY *pkey) { VALUE obj; if (!pkey) { obj = dsa_instance(cDSA, DSA_new()); } else { if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DSA) { ossl_raise(rb_eTypeError, "Not a DSA key!"); } WrapPKey(cDSA, obj, pkey); } if (obj == Qfalse) { ossl_raise(eDSAError, NULL); } return obj; } /* * Private */ static DSA * dsa_generate(int size) { DSA *dsa; unsigned char seed[20]; int seed_len = 20, counter; unsigned long h; if (!RAND_bytes(seed, seed_len)) { return 0; } dsa = DSA_generate_parameters(size, seed, seed_len, &counter, &h, rb_block_given_p() ? ossl_generate_cb : NULL, NULL); if(!dsa) return 0; if (!DSA_generate_key(dsa)) { DSA_free(dsa); return 0; } return dsa; } /* * call-seq: * DSA.generate(size) -> dsa * * === Parameters * * +size+ is an integer representing the desired key size. * */ static VALUE ossl_dsa_s_generate(VALUE klass, VALUE size) { DSA *dsa = dsa_generate(NUM2INT(size)); /* err handled by dsa_instance */ VALUE obj = dsa_instance(klass, dsa); if (obj == Qfalse) { DSA_free(dsa); ossl_raise(eDSAError, NULL); } return obj; } /* * call-seq: * DSA.new([size | string [, pass]) -> dsa * * === Parameters * * +size+ is an integer representing the desired key size. * * +string+ contains a DER or PEM encoded key. * * +pass+ is a string that contains a optional password. * * === Examples * * DSA.new -> dsa * * DSA.new(1024) -> dsa * * DSA.new(File.read('dsa.pem')) -> dsa * * DSA.new(File.read('dsa.pem'), 'mypassword') -> dsa * */ static VALUE ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; DSA *dsa; BIO *in; char *passwd = NULL; VALUE arg, pass; GetPKey(self, pkey); if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) { dsa = DSA_new(); } else if (FIXNUM_P(arg)) { if (!(dsa = dsa_generate(FIX2INT(arg)))) { ossl_raise(eDSAError, NULL); } } else { if (!NIL_P(pass)) passwd = StringValuePtr(pass); arg = ossl_to_der_if_possible(arg); in = ossl_obj2bio(arg); dsa = PEM_read_bio_DSAPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd); if (!dsa) { BIO_reset(in); dsa = PEM_read_bio_DSAPublicKey(in, NULL, NULL, NULL); } if (!dsa) { BIO_reset(in); dsa = PEM_read_bio_DSA_PUBKEY(in, NULL, NULL, NULL); } if (!dsa) { BIO_reset(in); dsa = d2i_DSAPrivateKey_bio(in, NULL); } if (!dsa) { BIO_reset(in); dsa = d2i_DSA_PUBKEY_bio(in, NULL); } BIO_free(in); if (!dsa) ossl_raise(eDSAError, "Neither PUB key nor PRIV key:"); } if (!EVP_PKEY_assign_DSA(pkey, dsa)) { DSA_free(dsa); ossl_raise(eDSAError, NULL); } return self; } /* * call-seq: * dsa.public? -> true | false * */ static VALUE ossl_dsa_is_public(VALUE self) { EVP_PKEY *pkey; GetPKeyDSA(self, pkey); return (pkey->pkey.dsa->pub_key) ? Qtrue : Qfalse; } /* * call-seq: * dsa.private? -> true | false * */ static VALUE ossl_dsa_is_private(VALUE self) { EVP_PKEY *pkey; GetPKeyDSA(self, pkey); return (DSA_PRIVATE(self, pkey->pkey.dsa)) ? Qtrue : Qfalse; } /* * call-seq: * dsa.to_pem([cipher, password]) -> aString * * === Parameters * +cipher+ is an OpenSSL::Cipher. * +password+ is a string containing your password. * * === Examples * * DSA.to_pem -> aString * * DSA.to_pem(cipher, 'mypassword') -> aString * */ static VALUE ossl_dsa_export(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; BIO *out; const EVP_CIPHER *ciph = NULL; char *passwd = NULL; VALUE cipher, pass, str; GetPKeyDSA(self, pkey); rb_scan_args(argc, argv, "02", &cipher, &pass); if (!NIL_P(cipher)) { ciph = GetCipherPtr(cipher); if (!NIL_P(pass)) { passwd = StringValuePtr(pass); } } if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eDSAError, NULL); } if (DSA_HAS_PRIVATE(pkey->pkey.dsa)) { if (!PEM_write_bio_DSAPrivateKey(out, pkey->pkey.dsa, ciph, NULL, 0, ossl_pem_passwd_cb, passwd)){ BIO_free(out); ossl_raise(eDSAError, NULL); } } else { if (!PEM_write_bio_DSAPublicKey(out, pkey->pkey.dsa)) { BIO_free(out); ossl_raise(eDSAError, NULL); } } str = ossl_membio2str(out); return str; } /* * call-seq: * dsa.to_der -> aString * */ static VALUE ossl_dsa_to_der(VALUE self) { EVP_PKEY *pkey; int (*i2d_func)_((DSA*, unsigned char**)); unsigned char *p; long len; VALUE str; GetPKeyDSA(self, pkey); if(DSA_HAS_PRIVATE(pkey->pkey.dsa)) i2d_func = (int(*)_((DSA*,unsigned char**)))i2d_DSAPrivateKey; else i2d_func = i2d_DSA_PUBKEY; if((len = i2d_func(pkey->pkey.dsa, NULL)) <= 0) ossl_raise(eDSAError, NULL); str = rb_str_new(0, len); p = RSTRING_PTR(str); if(i2d_func(pkey->pkey.dsa, &p) < 0) ossl_raise(eDSAError, NULL); ossl_str_adjust(str, p); return str; } /* * call-seq: * dsa.params -> hash * * Stores all parameters of key to the hash * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! * Don't use :-)) (I's up to you) */ static VALUE ossl_dsa_get_params(VALUE self) { EVP_PKEY *pkey; VALUE hash; GetPKeyDSA(self, pkey); hash = rb_hash_new(); rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(pkey->pkey.dsa->p)); rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(pkey->pkey.dsa->q)); rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(pkey->pkey.dsa->g)); rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pkey->pkey.dsa->pub_key)); rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(pkey->pkey.dsa->priv_key)); return hash; } /* * call-seq: * dsa.to_text -> aString * * Prints all parameters of key to buffer * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! * Don't use :-)) (I's up to you) */ static VALUE ossl_dsa_to_text(VALUE self) { EVP_PKEY *pkey; BIO *out; VALUE str; GetPKeyDSA(self, pkey); if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eDSAError, NULL); } if (!DSA_print(out, pkey->pkey.dsa, 0)) { /* offset = 0 */ BIO_free(out); ossl_raise(eDSAError, NULL); } str = ossl_membio2str(out); return str; } /* * call-seq: * dsa.public_key -> aDSA * * Makes new instance DSA PUBLIC_KEY from PRIVATE_KEY */ static VALUE ossl_dsa_to_public_key(VALUE self) { EVP_PKEY *pkey; DSA *dsa; VALUE obj; GetPKeyDSA(self, pkey); /* err check performed by dsa_instance */ dsa = DSAPublicKey_dup(pkey->pkey.dsa); obj = dsa_instance(CLASS_OF(self), dsa); if (obj == Qfalse) { DSA_free(dsa); ossl_raise(eDSAError, NULL); } return obj; } #define ossl_dsa_buf_size(pkey) (DSA_size((pkey)->pkey.dsa)+16) /* * call-seq: * dsa.syssign(string) -> aString * */ static VALUE ossl_dsa_sign(VALUE self, VALUE data) { EVP_PKEY *pkey; int buf_len; VALUE str; GetPKeyDSA(self, pkey); StringValue(data); if (!DSA_PRIVATE(self, pkey->pkey.dsa)) { ossl_raise(eDSAError, "Private DSA key needed!"); } str = rb_str_new(0, ossl_dsa_buf_size(pkey)); if (!DSA_sign(0, RSTRING_PTR(data), RSTRING_LEN(data), RSTRING_PTR(str), &buf_len, pkey->pkey.dsa)) { /* type is ignored (0) */ ossl_raise(eDSAError, NULL); } rb_str_set_len(str, buf_len); return str; } /* * call-seq: * dsa.sysverify(digest, sig) -> true | false * */ static VALUE ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig) { EVP_PKEY *pkey; int ret; GetPKeyDSA(self, pkey); StringValue(digest); StringValue(sig); /* type is ignored (0) */ ret = DSA_verify(0, RSTRING_PTR(digest), RSTRING_LEN(digest), RSTRING_PTR(sig), RSTRING_LEN(sig), pkey->pkey.dsa); if (ret < 0) { ossl_raise(eDSAError, NULL); } else if (ret == 1) { return Qtrue; } return Qfalse; } OSSL_PKEY_BN(dsa, p); OSSL_PKEY_BN(dsa, q); OSSL_PKEY_BN(dsa, g); OSSL_PKEY_BN(dsa, pub_key); OSSL_PKEY_BN(dsa, priv_key); /* * INIT */ void Init_ossl_dsa() { #if 0 /* let rdoc know about mOSSL and mPKey */ mOSSL = rb_define_module("OpenSSL"); mPKey = rb_define_module_under(mOSSL, "PKey"); #endif eDSAError = rb_define_class_under(mPKey, "DSAError", ePKeyError); cDSA = rb_define_class_under(mPKey, "DSA", cPKey); rb_define_singleton_method(cDSA, "generate", ossl_dsa_s_generate, 1); rb_define_method(cDSA, "initialize", ossl_dsa_initialize, -1); rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0); rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0); rb_define_method(cDSA, "to_text", ossl_dsa_to_text, 0); rb_define_method(cDSA, "export", ossl_dsa_export, -1); rb_define_alias(cDSA, "to_pem", "export"); rb_define_alias(cDSA, "to_s", "export"); rb_define_method(cDSA, "to_der", ossl_dsa_to_der, 0); rb_define_method(cDSA, "public_key", ossl_dsa_to_public_key, 0); rb_define_method(cDSA, "syssign", ossl_dsa_sign, 1); rb_define_method(cDSA, "sysverify", ossl_dsa_verify, 2); DEF_OSSL_PKEY_BN(cDSA, dsa, p); DEF_OSSL_PKEY_BN(cDSA, dsa, q); DEF_OSSL_PKEY_BN(cDSA, dsa, g); DEF_OSSL_PKEY_BN(cDSA, dsa, pub_key); DEF_OSSL_PKEY_BN(cDSA, dsa, priv_key); rb_define_method(cDSA, "params", ossl_dsa_get_params, 0); } #else /* defined NO_DSA */ void Init_ossl_dsa() { } #endif /* NO_DSA */ ================================================ FILE: ext/openssl/ossl_pkey_ec.c ================================================ /* * Copyright (C) 2006-2007 Technorama Ltd. */ #include "ossl.h" #if !defined(OPENSSL_NO_EC) && (OPENSSL_VERSION_NUMBER >= 0x0090802fL) typedef struct { EC_GROUP *group; int dont_free; } ossl_ec_group; typedef struct { EC_POINT *point; int dont_free; } ossl_ec_point; #define EXPORT_PEM 0 #define EXPORT_DER 1 #define GetPKeyEC(obj, pkey) do { \ GetPKey(obj, pkey); \ if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) { \ ossl_raise(rb_eRuntimeError, "THIS IS NOT A EC PKEY!"); \ } \ } while (0) #define SafeGet_ec_group(obj, group) do { \ OSSL_Check_Kind(obj, cEC_GROUP); \ Data_Get_Struct(obj, ossl_ec_group, group); \ } while(0) #define Get_EC_KEY(obj, key) do { \ EVP_PKEY *pkey; \ GetPKeyEC(obj, pkey); \ key = pkey->pkey.ec; \ } while(0) #define Require_EC_KEY(obj, key) do { \ Get_EC_KEY(obj, key); \ if (key == NULL) \ rb_raise(eECError, "EC_KEY is not initialized"); \ } while(0) #define SafeRequire_EC_KEY(obj, key) do { \ OSSL_Check_Kind(obj, cEC); \ Require_EC_KEY(obj, key); \ } while (0) #define Get_EC_GROUP(obj, g) do { \ ossl_ec_group *ec_group; \ Data_Get_Struct(obj, ossl_ec_group, ec_group); \ if (ec_group == NULL) \ rb_raise(eEC_GROUP, "missing ossl_ec_group structure"); \ g = ec_group->group; \ } while(0) #define Require_EC_GROUP(obj, group) do { \ Get_EC_GROUP(obj, group); \ if (group == NULL) \ rb_raise(eEC_GROUP, "EC_GROUP is not initialized"); \ } while(0) #define SafeRequire_EC_GROUP(obj, group) do { \ OSSL_Check_Kind(obj, cEC_GROUP); \ Require_EC_GROUP(obj, group); \ } while(0) #define Get_EC_POINT(obj, p) do { \ ossl_ec_point *ec_point; \ Data_Get_Struct(obj, ossl_ec_point, ec_point); \ if (ec_point == NULL) \ rb_raise(eEC_POINT, "missing ossl_ec_point structure"); \ p = ec_point->point; \ } while(0) #define Require_EC_POINT(obj, point) do { \ Get_EC_POINT(obj, point); \ if (point == NULL) \ rb_raise(eEC_POINT, "EC_POINT is not initialized"); \ } while(0) #define SafeRequire_EC_POINT(obj, point) do { \ OSSL_Check_Kind(obj, cEC_POINT); \ Require_EC_POINT(obj, point); \ } while(0) VALUE cEC; VALUE eECError; VALUE cEC_GROUP; VALUE eEC_GROUP; VALUE cEC_POINT; VALUE eEC_POINT; static ID s_GFp; static ID s_GFp_simple; static ID s_GFp_mont; static ID s_GFp_nist; static ID s_GF2m; static ID s_GF2m_simple; static ID ID_uncompressed; static ID ID_compressed; static ID ID_hybrid; static VALUE ec_instance(VALUE klass, EC_KEY *ec) { EVP_PKEY *pkey; VALUE obj; if (!ec) { return Qfalse; } if (!(pkey = EVP_PKEY_new())) { return Qfalse; } if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { EVP_PKEY_free(pkey); return Qfalse; } WrapPKey(klass, obj, pkey); return obj; } VALUE ossl_ec_new(EVP_PKEY *pkey) { VALUE obj; if (!pkey) { obj = ec_instance(cEC, EC_KEY_new()); } else { if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) { ossl_raise(rb_eTypeError, "Not a EC key!"); } WrapPKey(cEC, obj, pkey); } if (obj == Qfalse) { ossl_raise(eECError, NULL); } return obj; } /* call-seq: * OpenSSL::PKey::EC.new() * OpenSSL::PKey::EC.new(ec_key) * OpenSSL::PKey::EC.new(ec_group) * OpenSSL::PKey::EC.new("secp112r1") * OpenSSL::PKey::EC.new(pem_string) * OpenSSL::PKey::EC.new(der_string) * * See the OpenSSL documentation for: * EC_KEY_* */ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; EC_KEY *ec = NULL; VALUE arg, pass; VALUE group = Qnil; GetPKey(self, pkey); if (pkey->pkey.ec) rb_raise(eECError, "EC_KEY already initialized"); rb_scan_args(argc, argv, "02", &arg, &pass); if (NIL_P(arg)) { ec = EC_KEY_new(); } else { if (rb_obj_is_kind_of(arg, cEC)) { EC_KEY *other_ec = NULL; SafeRequire_EC_KEY(arg, other_ec); ec = EC_KEY_dup(other_ec); } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) { ec = EC_KEY_new(); group = arg; } else { BIO *in = ossl_obj2bio(arg); ec = PEM_read_bio_ECPrivateKey(in, NULL, NULL, NULL); if (!ec) { BIO_reset(in); ec = PEM_read_bio_EC_PUBKEY(in, NULL, NULL, NULL); } if (!ec) { BIO_reset(in); ec = d2i_ECPrivateKey_bio(in, NULL); } if (!ec) { BIO_reset(in); ec = d2i_EC_PUBKEY_bio(in, NULL); } BIO_free(in); if (ec == NULL) { const char *name = STR2CSTR(arg); int nid = OBJ_sn2nid(name); if (nid == NID_undef) ossl_raise(eECError, "unknown curve name (%s)\n", name); if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL) ossl_raise(eECError, "unable to create curve (%s)\n", name); EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE); EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED); } } } if (ec == NULL) ossl_raise(eECError, NULL); if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { EC_KEY_free(ec); ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); } rb_iv_set(self, "@group", Qnil); if (!NIL_P(group)) rb_funcall(self, rb_intern("group="), 1, arg); return self; } /* * call-seq: * key.group => group * * Returns a constant OpenSSL::EC::Group that is tied to the key. * Modifying the returned group can make the key invalid. */ static VALUE ossl_ec_key_get_group(VALUE self) { VALUE group_v; EC_KEY *ec; ossl_ec_group *ec_group; EC_GROUP *group; Require_EC_KEY(self, ec); group_v = rb_iv_get(self, "@group"); if (!NIL_P(group_v)) return group_v; if ((group = (EC_GROUP *)EC_KEY_get0_group(ec)) != NULL) { group_v = rb_obj_alloc(cEC_GROUP); SafeGet_ec_group(group_v, ec_group); ec_group->group = group; ec_group->dont_free = 1; rb_iv_set(group_v, "@key", self); rb_iv_set(self, "@group", group_v); return group_v; } return Qnil; } /* * call-seq: * key.group = group => group * * Returns the same object passed, not the group object associated with the key. * If you wish to access the group object tied to the key call key.group after setting * the group. * * Setting the group will immediately destroy any previously assigned group object. * The group is internally copied by OpenSSL. Modifying the original group after * assignment will not effect the internal key structure. * (your changes may be lost). BE CAREFUL. * * EC_KEY_set_group calls EC_GROUP_free(key->group) then EC_GROUP_dup(), not EC_GROUP_copy. * This documentation is accurate for OpenSSL 0.9.8b. */ static VALUE ossl_ec_key_set_group(VALUE self, VALUE group_v) { VALUE old_group_v; EC_KEY *ec; EC_GROUP *group; Require_EC_KEY(self, ec); SafeRequire_EC_GROUP(group_v, group); old_group_v = rb_iv_get(self, "@group"); if (!NIL_P(old_group_v)) { ossl_ec_group *old_ec_group; SafeGet_ec_group(old_group_v, old_ec_group); old_ec_group->group = NULL; old_ec_group->dont_free = 0; rb_iv_set(old_group_v, "@key", Qnil); } rb_iv_set(self, "@group", Qnil); if (EC_KEY_set_group(ec, group) != 1) ossl_raise(eECError, "EC_KEY_set_group"); return group_v; } /* * call-seq: * key.private_key => OpenSSL::BN * * See the OpenSSL documentation for EC_KEY_get0_private_key() */ static VALUE ossl_ec_key_get_private_key(VALUE self) { EC_KEY *ec; const BIGNUM *bn; Require_EC_KEY(self, ec); if ((bn = EC_KEY_get0_private_key(ec)) == NULL) return Qnil; return ossl_bn_new(bn); } /* * call-seq: * key.private_key = openssl_bn * * See the OpenSSL documentation for EC_KEY_set_private_key() */ static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key) { EC_KEY *ec; BIGNUM *bn = NULL; Require_EC_KEY(self, ec); if (!NIL_P(private_key)) bn = GetBNPtr(private_key); switch (EC_KEY_set_private_key(ec, bn)) { case 1: break; case 0: if (bn == NULL) break; default: ossl_raise(eECError, "EC_KEY_set_private_key"); } return private_key; } static VALUE ossl_ec_point_dup(const EC_POINT *point, VALUE group_v) { VALUE obj; const EC_GROUP *group; ossl_ec_point *new_point; obj = rb_obj_alloc(cEC_POINT); Data_Get_Struct(obj, ossl_ec_point, new_point); SafeRequire_EC_GROUP(group_v, group); new_point->point = EC_POINT_dup(point, group); if (new_point->point == NULL) ossl_raise(eEC_POINT, "EC_POINT_dup"); rb_iv_set(obj, "@group", group_v); return obj; } /* * call-seq: * key.public_key => OpenSSL::PKey::EC::Point * * See the OpenSSL documentation for EC_KEY_get0_public_key() */ static VALUE ossl_ec_key_get_public_key(VALUE self) { EC_KEY *ec; const EC_POINT *point; VALUE group; Require_EC_KEY(self, ec); if ((point = EC_KEY_get0_public_key(ec)) == NULL) return Qnil; group = rb_funcall(self, rb_intern("group"), 0); if (NIL_P(group)) ossl_raise(eECError, "EC_KEY_get0_get0_group (has public_key but no group???"); return ossl_ec_point_dup(point, group); } /* * call-seq: * key.public_key = ec_point * * See the OpenSSL documentation for EC_KEY_set_public_key() */ static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key) { EC_KEY *ec; EC_POINT *point = NULL; Require_EC_KEY(self, ec); if (!NIL_P(public_key)) SafeRequire_EC_POINT(public_key, point); switch (EC_KEY_set_public_key(ec, point)) { case 1: break; case 0: if (point == NULL) break; default: ossl_raise(eECError, "EC_KEY_set_public_key"); } return public_key; } /* * call-seq: * key.public_key? => true or false * * Both public_key? and private_key? may return false at the same time unlike other PKey classes. */ static VALUE ossl_ec_key_is_public_key(VALUE self) { EC_KEY *ec; Require_EC_KEY(self, ec); return (EC_KEY_get0_public_key(ec) ? Qtrue : Qfalse); } /* * call-seq: * key.private_key? => true or false * * Both public_key? and private_key? may return false at the same time unlike other PKey classes. */ static VALUE ossl_ec_key_is_private_key(VALUE self) { EC_KEY *ec; Require_EC_KEY(self, ec); return (EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse); } static VALUE ossl_ec_key_to_string(VALUE self, int format) { EC_KEY *ec; BIO *out; int i = -1; int private = 0; EVP_CIPHER *cipher = NULL; char *password = NULL; VALUE str; Require_EC_KEY(self, ec); if (EC_KEY_get0_public_key(ec) == NULL) rb_raise(eECError, "can't export - no public key set"); if (EC_KEY_check_key(ec) != 1) ossl_raise(eECError, "can't export - EC_KEY_check_key failed"); if (EC_KEY_get0_private_key(ec)) private = 1; if (!(out = BIO_new(BIO_s_mem()))) ossl_raise(eECError, "BIO_new(BIO_s_mem())"); switch(format) { case EXPORT_PEM: if (private) { if (cipher || password) /* BUG: finish cipher/password key export */ rb_notimplement(); i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, NULL, password); } else { if (cipher || password) rb_raise(rb_eArgError, "encryption is not supported when exporting this key type"); i = PEM_write_bio_EC_PUBKEY(out, ec); } break; case EXPORT_DER: if (private) { if (cipher || password) rb_raise(rb_eArgError, "encryption is not supported when exporting this key type"); i = i2d_ECPrivateKey_bio(out, ec); } else { if (cipher || password) rb_raise(rb_eArgError, "encryption is not supported when exporting this key type"); i = i2d_EC_PUBKEY_bio(out, ec); } break; default: BIO_free(out); rb_raise(rb_eRuntimeError, "unknown format (internal error)"); } if (i != 1) { BIO_free(out); ossl_raise(eECError, "outlen=%d", i); } str = ossl_membio2str(out); return str; } /* * call-seq: * key.to_pem => String * * See the OpenSSL documentation for PEM_write_bio_ECPrivateKey() */ static VALUE ossl_ec_key_to_pem(VALUE self) { return ossl_ec_key_to_string(self, EXPORT_PEM); } /* * call-seq: * key.to_der => String * * See the OpenSSL documentation for i2d_ECPrivateKey_bio() */ static VALUE ossl_ec_key_to_der(VALUE self) { return ossl_ec_key_to_string(self, EXPORT_DER); } /* * call-seq: * key.to_text => String * * See the OpenSSL documentation for EC_KEY_print() */ static VALUE ossl_ec_key_to_text(VALUE self) { EC_KEY *ec; BIO *out; VALUE str; Require_EC_KEY(self, ec); if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eECError, "BIO_new(BIO_s_mem())"); } if (!EC_KEY_print(out, ec, 0)) { BIO_free(out); ossl_raise(eECError, "EC_KEY_print"); } str = ossl_membio2str(out); return str; } /* * call-seq: * key.generate_key => self * * See the OpenSSL documentation for EC_KEY_generate_key() */ static VALUE ossl_ec_key_generate_key(VALUE self) { EC_KEY *ec; Require_EC_KEY(self, ec); if (EC_KEY_generate_key(ec) != 1) ossl_raise(eECError, "EC_KEY_generate_key"); return self; } /* * call-seq: * key.check_key => true * * Raises an exception if the key is invalid. * * See the OpenSSL documentation for EC_KEY_check_key() */ static VALUE ossl_ec_key_check_key(VALUE self) { EC_KEY *ec; Require_EC_KEY(self, ec); if (EC_KEY_check_key(ec) != 1) ossl_raise(eECError, "EC_KEY_check_key"); return Qtrue; } /* * call-seq: * key.dh_compute_key(pubkey) => String * * See the OpenSSL documentation for ECDH_compute_key() */ static VALUE ossl_ec_key_dh_compute_key(VALUE self, VALUE pubkey) { EC_KEY *ec; EC_POINT *point; int buf_len; VALUE str; Require_EC_KEY(self, ec); SafeRequire_EC_POINT(pubkey, point); /* BUG: need a way to figure out the maximum string size */ buf_len = 1024; str = rb_str_new(0, buf_len); /* BUG: take KDF as a block */ buf_len = ECDH_compute_key(RSTRING_PTR(str), buf_len, point, ec, NULL); if (buf_len < 0) ossl_raise(eECError, "ECDH_compute_key"); rb_str_resize(str, buf_len); return str; } /* sign_setup */ /* * call-seq: * key.dsa_sign_asn1(data) => String * * See the OpenSSL documentation for ECDSA_sign() */ static VALUE ossl_ec_key_dsa_sign_asn1(VALUE self, VALUE data) { EC_KEY *ec; unsigned int buf_len; VALUE str; Require_EC_KEY(self, ec); StringValue(data); if (EC_KEY_get0_private_key(ec) == NULL) ossl_raise(eECError, "Private EC key needed!"); str = rb_str_new(0, ECDSA_size(ec) + 16); if (ECDSA_sign(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LEN(data), (unsigned char *) RSTRING_PTR(str), &buf_len, ec) != 1) ossl_raise(eECError, "ECDSA_sign"); rb_str_resize(str, buf_len); return str; } /* * call-seq: * key.dsa_verify(data, sig) => true or false * * See the OpenSSL documentation for ECDSA_verify() */ static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig) { EC_KEY *ec; Require_EC_KEY(self, ec); StringValue(data); StringValue(sig); switch (ECDSA_verify(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LEN(data), (unsigned char *) RSTRING_PTR(sig), RSTRING_LEN(sig), ec)) { case 1: return Qtrue; case 0: return Qfalse; default: break; } ossl_raise(eECError, "ECDSA_verify"); } static void ossl_ec_group_free(ossl_ec_group *ec_group) { if (!ec_group->dont_free && ec_group->group) EC_GROUP_clear_free(ec_group->group); free(ec_group); } static VALUE ossl_ec_group_alloc(VALUE klass) { ossl_ec_group *ec_group; VALUE obj; obj = Data_Make_Struct(klass, ossl_ec_group, 0, ossl_ec_group_free, ec_group); return obj; } /* call-seq: * OpenSSL::PKey::EC::Group.new("secp112r1") * OpenSSL::PKey::EC::Group.new(ec_group) * OpenSSL::PKey::EC::Group.new(pem_string) * OpenSSL::PKey::EC::Group.new(der_string) * OpenSSL::PKey::EC::Group.new(pem_file) * OpenSSL::PKey::EC::Group.new(der_file) * OpenSSL::PKey::EC::Group.new(:GFp_simple) * OpenSSL::PKey::EC::Group.new(:GFp_mult) * OpenSSL::PKey::EC::Group.new(:GFp_nist) * OpenSSL::PKey::EC::Group.new(:GF2m_simple) * OpenSSL::PKey::EC::Group.new(:GFp, bignum_p, bignum_a, bignum_b) * OpenSSL::PKey::EC::Group.new(:GF2m, bignum_p, bignum_a, bignum_b) * * See the OpenSSL documentation for EC_GROUP_* */ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self) { VALUE arg1, arg2, arg3, arg4; ossl_ec_group *ec_group; EC_GROUP *group = NULL; Data_Get_Struct(self, ossl_ec_group, ec_group); if (ec_group->group != NULL) rb_raise(rb_eRuntimeError, "EC_GROUP is already initialized"); switch (rb_scan_args(argc, argv, "13", &arg1, &arg2, &arg3, &arg4)) { case 1: if (SYMBOL_P(arg1)) { const EC_METHOD *method = NULL; ID id = SYM2ID(arg1); if (id == s_GFp_simple) { method = EC_GFp_simple_method(); } else if (id == s_GFp_mont) { method = EC_GFp_mont_method(); } else if (id == s_GFp_nist) { method = EC_GFp_nist_method(); } else if (id == s_GF2m_simple) { method = EC_GF2m_simple_method(); } if (method) { if ((group = EC_GROUP_new(method)) == NULL) ossl_raise(eEC_GROUP, "EC_GROUP_new"); } else { rb_raise(rb_eArgError, "unknown symbol, must be :GFp_simple, :GFp_mont, :GFp_nist or :GF2m_simple"); } } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) { const EC_GROUP *arg1_group; SafeRequire_EC_GROUP(arg1, arg1_group); if ((group = EC_GROUP_dup(arg1_group)) == NULL) ossl_raise(eEC_GROUP, "EC_GROUP_dup"); } else { BIO *in = ossl_obj2bio(arg1); group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL); if (!group) { BIO_reset(in); group = d2i_ECPKParameters_bio(in, NULL); } BIO_free(in); if (!group) { const char *name = STR2CSTR(arg1); int nid = OBJ_sn2nid(name); if (nid == NID_undef) ossl_raise(eEC_GROUP, "unknown curve name (%s)", name); group = EC_GROUP_new_by_curve_name(nid); if (group == NULL) ossl_raise(eEC_GROUP, "unable to create curve (%s)", name); EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED); } } break; case 4: if (SYMBOL_P(arg1)) { ID id = SYM2ID(arg1); EC_GROUP *(*new_curve)(const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL; const BIGNUM *p = GetBNPtr(arg2); const BIGNUM *a = GetBNPtr(arg3); const BIGNUM *b = GetBNPtr(arg4); if (id == s_GFp) { new_curve = EC_GROUP_new_curve_GFp; } else if (id == s_GF2m) { new_curve = EC_GROUP_new_curve_GF2m; } else { rb_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m"); } if ((group = new_curve(p, a, b, ossl_bn_ctx)) == NULL) ossl_raise(eEC_GROUP, "EC_GROUP_new_by_GF*"); } else { rb_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m"); } break; default: rb_raise(rb_eArgError, "wrong number of arguments"); } if (group == NULL) ossl_raise(eEC_GROUP, ""); ec_group->group = group; return self; } /* call-seq: * group1 == group2 => true | false * */ static VALUE ossl_ec_group_eql(VALUE a, VALUE b) { EC_GROUP *group1 = NULL, *group2 = NULL; Require_EC_GROUP(a, group1); SafeRequire_EC_GROUP(b, group2); if (EC_GROUP_cmp(group1, group2, ossl_bn_ctx) == 1) return Qfalse; return Qtrue; } /* call-seq: * group.generator => ec_point * * See the OpenSSL documentation for EC_GROUP_get0_generator() */ static VALUE ossl_ec_group_get_generator(VALUE self) { VALUE point_obj; EC_GROUP *group = NULL; Require_EC_GROUP(self, group); point_obj = ossl_ec_point_dup(EC_GROUP_get0_generator(group), self); return point_obj; } /* call-seq: * group.set_generator(generator, order, cofactor) => self * * See the OpenSSL documentation for EC_GROUP_set_generator() */ static VALUE ossl_ec_group_set_generator(VALUE self, VALUE generator, VALUE order, VALUE cofactor) { EC_GROUP *group = NULL; const EC_POINT *point; const BIGNUM *o, *co; Require_EC_GROUP(self, group); SafeRequire_EC_POINT(generator, point); o = GetBNPtr(order); co = GetBNPtr(cofactor); if (EC_GROUP_set_generator(group, point, o, co) != 1) ossl_raise(eEC_GROUP, "EC_GROUP_set_generator"); return self; } /* call-seq: * group.get_order => order_bn * * See the OpenSSL documentation for EC_GROUP_get_order() */ static VALUE ossl_ec_group_get_order(VALUE self) { VALUE bn_obj; BIGNUM *bn; EC_GROUP *group = NULL; Require_EC_GROUP(self, group); bn_obj = ossl_bn_new(NULL); bn = GetBNPtr(bn_obj); if (EC_GROUP_get_order(group, bn, ossl_bn_ctx) != 1) ossl_raise(eEC_GROUP, "EC_GROUP_get_order"); return bn_obj; } /* call-seq: * group.get_cofactor => cofactor_bn * * See the OpenSSL documentation for EC_GROUP_get_cofactor() */ static VALUE ossl_ec_group_get_cofactor(VALUE self) { VALUE bn_obj; BIGNUM *bn; EC_GROUP *group = NULL; Require_EC_GROUP(self, group); bn_obj = ossl_bn_new(NULL); bn = GetBNPtr(bn_obj); if (EC_GROUP_get_cofactor(group, bn, ossl_bn_ctx) != 1) ossl_raise(eEC_GROUP, "EC_GROUP_get_cofactor"); return bn_obj; } /* call-seq: * group.curve_name => String * * See the OpenSSL documentation for EC_GROUP_get_curve_name() */ static VALUE ossl_ec_group_get_curve_name(VALUE self) { EC_GROUP *group = NULL; int nid; Get_EC_GROUP(self, group); if (group == NULL) return Qnil; nid = EC_GROUP_get_curve_name(group); /* BUG: an nid or asn1 object should be returned, maybe. */ return rb_str_new2(OBJ_nid2sn(nid)); } /* call-seq: * EC.builtin_curves => [[name, comment], ...] * * See the OpenSSL documentation for EC_builtin_curves() */ static VALUE ossl_s_builtin_curves(VALUE self) { EC_builtin_curve *curves = NULL; int n; int crv_len = EC_get_builtin_curves(NULL, 0); VALUE ary, ret; curves = ALLOCA_N(EC_builtin_curve, crv_len); if (curves == NULL) return Qnil; if (!EC_get_builtin_curves(curves, crv_len)) ossl_raise(rb_eRuntimeError, "EC_get_builtin_curves"); ret = rb_ary_new2(crv_len); for (n = 0; n < crv_len; n++) { const char *sname = OBJ_nid2sn(curves[n].nid); const char *comment = curves[n].comment; ary = rb_ary_new2(2); rb_ary_push(ary, rb_str_new2(sname)); rb_ary_push(ary, comment ? rb_str_new2(comment) : Qnil); rb_ary_push(ret, ary); } return ret; } /* call-seq: * group.asn1_flag => Fixnum * * See the OpenSSL documentation for EC_GROUP_get_asn1_flag() */ static VALUE ossl_ec_group_get_asn1_flag(VALUE self) { EC_GROUP *group = NULL; int flag; Require_EC_GROUP(self, group); flag = EC_GROUP_get_asn1_flag(group); return INT2FIX(flag); } /* call-seq: * group.asn1_flag = Fixnum => Fixnum * * See the OpenSSL documentation for EC_GROUP_set_asn1_flag() */ static VALUE ossl_ec_group_set_asn1_flag(VALUE self, VALUE flag_v) { EC_GROUP *group = NULL; Require_EC_GROUP(self, group); EC_GROUP_set_asn1_flag(group, NUM2INT(flag_v)); return flag_v; } /* call-seq: * group.point_conversion_form => :uncompressed | :compressed | :hybrid * * See the OpenSSL documentation for EC_GROUP_get_point_conversion_form() */ static VALUE ossl_ec_group_get_point_conversion_form(VALUE self) { EC_GROUP *group = NULL; point_conversion_form_t form; VALUE ret; Require_EC_GROUP(self, group); form = EC_GROUP_get_point_conversion_form(group); switch (form) { case POINT_CONVERSION_UNCOMPRESSED: ret = ID_uncompressed; break; case POINT_CONVERSION_COMPRESSED: ret = ID_compressed; break; case POINT_CONVERSION_HYBRID: ret = ID_hybrid; break; default: rb_raise(eEC_GROUP, "unsupported point conversion form: %d, this module should be updated", form); } return ID2SYM(ret); } /* call-seq: * group.point_conversion_form = form => form * * See the OpenSSL documentation for EC_GROUP_set_point_conversion_form() */ static VALUE ossl_ec_group_set_point_conversion_form(VALUE self, VALUE form_v) { EC_GROUP *group = NULL; point_conversion_form_t form; ID form_id = SYM2ID(form_v); Require_EC_GROUP(self, group); if (form_id == ID_uncompressed) { form = POINT_CONVERSION_UNCOMPRESSED; } else if (form_id == ID_compressed) { form = POINT_CONVERSION_COMPRESSED; } else if (form_id == ID_hybrid) { form = POINT_CONVERSION_HYBRID; } else { rb_raise(rb_eArgError, "form must be :compressed, :uncompressed, or :hybrid"); } EC_GROUP_set_point_conversion_form(group, form); return form_v; } /* call-seq: * group.seed => String or nil * * See the OpenSSL documentation for EC_GROUP_get0_seed() */ static VALUE ossl_ec_group_get_seed(VALUE self) { EC_GROUP *group = NULL; size_t seed_len; Require_EC_GROUP(self, group); seed_len = EC_GROUP_get_seed_len(group); if (seed_len == 0) return Qnil; return rb_str_new(EC_GROUP_get0_seed(group), seed_len); } /* call-seq: * group.seed = seed => seed * * See the OpenSSL documentation for EC_GROUP_set_seed() */ static VALUE ossl_ec_group_set_seed(VALUE self, VALUE seed) { EC_GROUP *group = NULL; Require_EC_GROUP(self, group); StringValue(seed); if (EC_GROUP_set_seed(group, RSTRING_PTR(seed), RSTRING_LEN(seed)) != RSTRING_LEN(seed)) ossl_raise(eEC_GROUP, "EC_GROUP_set_seed"); return seed; } /* get/set curve GFp, GF2m */ /* call-seq: * group.degree => Fixnum * * See the OpenSSL documentation for EC_GROUP_get_degree() */ static VALUE ossl_ec_group_get_degree(VALUE self) { EC_GROUP *group = NULL; Require_EC_GROUP(self, group); return INT2NUM(EC_GROUP_get_degree(group)); } static VALUE ossl_ec_group_to_string(VALUE self, int format) { EC_GROUP *group; BIO *out; int i = -1; VALUE str; Get_EC_GROUP(self, group); if (!(out = BIO_new(BIO_s_mem()))) ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())"); switch(format) { case EXPORT_PEM: i = PEM_write_bio_ECPKParameters(out, group); break; case EXPORT_DER: i = i2d_ECPKParameters_bio(out, group); break; default: BIO_free(out); rb_raise(rb_eRuntimeError, "unknown format (internal error)"); } if (i != 1) { BIO_free(out); ossl_raise(eECError, NULL); } str = ossl_membio2str(out); return str; } /* call-seq: * group.to_pem => String * * See the OpenSSL documentation for PEM_write_bio_ECPKParameters() */ static VALUE ossl_ec_group_to_pem(VALUE self) { return ossl_ec_group_to_string(self, EXPORT_PEM); } /* call-seq: * group.to_der => String * * See the OpenSSL documentation for i2d_ECPKParameters_bio() */ static VALUE ossl_ec_group_to_der(VALUE self) { return ossl_ec_group_to_string(self, EXPORT_DER); } /* call-seq: * group.to_text => String * * See the OpenSSL documentation for ECPKParameters_print() */ static VALUE ossl_ec_group_to_text(VALUE self) { EC_GROUP *group; BIO *out; VALUE str; Require_EC_GROUP(self, group); if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())"); } if (!ECPKParameters_print(out, group, 0)) { BIO_free(out); ossl_raise(eEC_GROUP, NULL); } str = ossl_membio2str(out); return str; } static void ossl_ec_point_free(ossl_ec_point *ec_point) { if (!ec_point->dont_free && ec_point->point) EC_POINT_clear_free(ec_point->point); free(ec_point); } static VALUE ossl_ec_point_alloc(VALUE klass) { ossl_ec_point *ec_point; VALUE obj; obj = Data_Make_Struct(klass, ossl_ec_point, 0, ossl_ec_point_free, ec_point); return obj; } /* * call-seq: * OpenSSL::PKey::EC::Point.new(point) * OpenSSL::PKey::EC::Point.new(group) * OpenSSL::PKey::EC::Point.new(group, bn) * * See the OpenSSL documentation for EC_POINT_* */ static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self) { ossl_ec_point *ec_point; EC_POINT *point = NULL; VALUE arg1, arg2; VALUE group_v = Qnil; const EC_GROUP *group = NULL; Data_Get_Struct(self, ossl_ec_point, ec_point); if (ec_point->point) rb_raise(eEC_POINT, "EC_POINT already initialized"); switch (rb_scan_args(argc, argv, "11", &arg1, &arg2)) { case 1: if (rb_obj_is_kind_of(arg1, cEC_POINT)) { const EC_POINT *arg_point; group_v = rb_iv_get(arg1, "@group"); SafeRequire_EC_GROUP(group_v, group); SafeRequire_EC_POINT(arg1, arg_point); point = EC_POINT_dup(arg_point, group); } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) { group_v = arg1; SafeRequire_EC_GROUP(group_v, group); point = EC_POINT_new(group); } else { rb_raise(eEC_POINT, "wrong argument type: must be OpenSSL::PKey::EC::Point or OpenSSL::Pkey::EC::Group"); } break; case 2: if (!rb_obj_is_kind_of(arg1, cEC_GROUP)) rb_raise(rb_eArgError, "1st argument must be OpenSSL::PKey::EC::Group"); group_v = arg1; SafeRequire_EC_GROUP(group_v, group); if (rb_obj_is_kind_of(arg2, cBN)) { const BIGNUM *bn = GetBNPtr(arg2); point = EC_POINT_bn2point(group, bn, NULL, ossl_bn_ctx); } else { BIO *in = ossl_obj2bio(arg1); /* BUG: finish me */ BIO_free(in); if (point == NULL) { ossl_raise(eEC_POINT, "unknown type for 2nd arg"); } } break; default: rb_raise(rb_eArgError, "wrong number of arguments"); } if (point == NULL) ossl_raise(eEC_POINT, NULL); if (NIL_P(group_v)) rb_raise(rb_eRuntimeError, "missing group (internal error)"); ec_point->point = point; rb_iv_set(self, "@group", group_v); return self; } /* * call-seq: * point1 == point2 => true | false * */ static VALUE ossl_ec_point_eql(VALUE a, VALUE b) { EC_POINT *point1, *point2; VALUE group_v1 = rb_iv_get(a, "@group"); VALUE group_v2 = rb_iv_get(b, "@group"); const EC_GROUP *group; if (ossl_ec_group_eql(group_v1, group_v2) == Qfalse) return Qfalse; Require_EC_POINT(a, point1); SafeRequire_EC_POINT(b, point2); SafeRequire_EC_GROUP(group_v1, group); if (EC_POINT_cmp(group, point1, point2, ossl_bn_ctx) == 1) return Qfalse; return Qtrue; } /* * call-seq: * point.infinity? => true | false * */ static VALUE ossl_ec_point_is_at_infinity(VALUE self) { EC_POINT *point; VALUE group_v = rb_iv_get(self, "@group"); const EC_GROUP *group; Require_EC_POINT(self, point); SafeRequire_EC_GROUP(group_v, group); switch (EC_POINT_is_at_infinity(group, point)) { case 1: return Qtrue; case 0: return Qfalse; default: ossl_raise(cEC_POINT, "EC_POINT_is_at_infinity"); } } /* * call-seq: * point.on_curve? => true | false * */ static VALUE ossl_ec_point_is_on_curve(VALUE self) { EC_POINT *point; VALUE group_v = rb_iv_get(self, "@group"); const EC_GROUP *group; Require_EC_POINT(self, point); SafeRequire_EC_GROUP(group_v, group); switch (EC_POINT_is_on_curve(group, point, ossl_bn_ctx)) { case 1: return Qtrue; case 0: return Qfalse; default: ossl_raise(cEC_POINT, "EC_POINT_is_on_curve"); } } /* * call-seq: * point.make_affine! => self * */ static VALUE ossl_ec_point_make_affine(VALUE self) { EC_POINT *point; VALUE group_v = rb_iv_get(self, "@group"); const EC_GROUP *group; Require_EC_POINT(self, point); SafeRequire_EC_GROUP(group_v, group); if (EC_POINT_make_affine(group, point, ossl_bn_ctx) != 1) ossl_raise(cEC_POINT, "EC_POINT_make_affine"); return self; } /* * call-seq: * point.invert! => self * */ static VALUE ossl_ec_point_invert(VALUE self) { EC_POINT *point; VALUE group_v = rb_iv_get(self, "@group"); const EC_GROUP *group; Require_EC_POINT(self, point); SafeRequire_EC_GROUP(group_v, group); if (EC_POINT_invert(group, point, ossl_bn_ctx) != 1) ossl_raise(cEC_POINT, "EC_POINT_invert"); return self; } /* * call-seq: * point.set_to_infinity! => self * */ static VALUE ossl_ec_point_set_to_infinity(VALUE self) { EC_POINT *point; VALUE group_v = rb_iv_get(self, "@group"); const EC_GROUP *group; Require_EC_POINT(self, point); SafeRequire_EC_GROUP(group_v, group); if (EC_POINT_set_to_infinity(group, point) != 1) ossl_raise(cEC_POINT, "EC_POINT_set_to_infinity"); return self; } /* * call-seq: * point.to_bn => OpenSSL::BN * * See the OpenSSL documentation for EC_POINT_point2bn() */ static VALUE ossl_ec_point_to_bn(VALUE self) { EC_POINT *point; VALUE bn_obj; VALUE group_v = rb_iv_get(self, "@group"); const EC_GROUP *group; point_conversion_form_t form; BIGNUM *bn; Require_EC_POINT(self, point); SafeRequire_EC_GROUP(group_v, group); form = EC_GROUP_get_point_conversion_form(group); bn_obj = rb_obj_alloc(cBN); bn = GetBNPtr(bn_obj); if (EC_POINT_point2bn(group, point, form, bn, ossl_bn_ctx) == NULL) ossl_raise(eEC_POINT, "EC_POINT_point2bn"); return bn_obj; } static void no_copy(VALUE klass) { rb_undef_method(klass, "copy"); rb_undef_method(klass, "clone"); rb_undef_method(klass, "dup"); rb_undef_method(klass, "initialize_copy"); } void Init_ossl_ec() { #ifdef DONT_NEED_RDOC_WORKAROUND mOSSL = rb_define_module("OpenSSL"); mPKey = rb_define_module_under(mOSSL, "PKey"); #endif eECError = rb_define_class_under(mPKey, "ECError", ePKeyError); cEC = rb_define_class_under(mPKey, "EC", cPKey); cEC_GROUP = rb_define_class_under(cEC, "Group", rb_cObject); cEC_POINT = rb_define_class_under(cEC, "Point", rb_cObject); eEC_GROUP = rb_define_class_under(cEC_GROUP, "Error", eOSSLError); eEC_POINT = rb_define_class_under(cEC_POINT, "Error", eOSSLError); s_GFp = rb_intern("GFp"); s_GF2m = rb_intern("GF2m"); s_GFp_simple = rb_intern("GFp_simple"); s_GFp_mont = rb_intern("GFp_mont"); s_GFp_nist = rb_intern("GFp_nist"); s_GF2m_simple = rb_intern("GF2m_simple"); ID_uncompressed = rb_intern("uncompressed"); ID_compressed = rb_intern("compressed"); ID_hybrid = rb_intern("hybrid"); #ifdef OPENSSL_EC_NAMED_CURVE rb_define_const(cEC, "NAMED_CURVE", ULONG2NUM(OPENSSL_EC_NAMED_CURVE)); #endif rb_define_singleton_method(cEC, "builtin_curves", ossl_s_builtin_curves, 0); rb_define_method(cEC, "initialize", ossl_ec_key_initialize, -1); /* copy/dup/cmp */ rb_define_method(cEC, "group", ossl_ec_key_get_group, 0); rb_define_method(cEC, "group=", ossl_ec_key_set_group, 1); rb_define_method(cEC, "private_key", ossl_ec_key_get_private_key, 0); rb_define_method(cEC, "private_key=", ossl_ec_key_set_private_key, 1); rb_define_method(cEC, "public_key", ossl_ec_key_get_public_key, 0); rb_define_method(cEC, "public_key=", ossl_ec_key_set_public_key, 1); rb_define_method(cEC, "private_key?", ossl_ec_key_is_private_key, 0); rb_define_method(cEC, "public_key?", ossl_ec_key_is_public_key, 0); /* rb_define_method(cEC, "", ossl_ec_key_get_, 0); rb_define_method(cEC, "=", ossl_ec_key_set_ 1); set/get enc_flags set/get _conv_from set/get asn1_flag (can use ruby to call self.group.asn1_flag) set/get precompute_mult */ rb_define_method(cEC, "generate_key", ossl_ec_key_generate_key, 0); rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0); rb_define_method(cEC, "dh_compute_key", ossl_ec_key_dh_compute_key, 1); rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1); rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2); /* do_sign/do_verify */ rb_define_method(cEC, "to_pem", ossl_ec_key_to_pem, 0); rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0); rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0); rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc); rb_define_method(cEC_GROUP, "initialize", ossl_ec_group_initialize, -1); rb_define_method(cEC_GROUP, "eql?", ossl_ec_group_eql, 1); rb_define_alias(cEC_GROUP, "==", "eql?"); /* copy/dup/cmp */ rb_define_method(cEC_GROUP, "generator", ossl_ec_group_get_generator, 0); rb_define_method(cEC_GROUP, "set_generator", ossl_ec_group_set_generator, 3); rb_define_method(cEC_GROUP, "order", ossl_ec_group_get_order, 0); rb_define_method(cEC_GROUP, "cofactor", ossl_ec_group_get_cofactor, 0); rb_define_method(cEC_GROUP, "curve_name", ossl_ec_group_get_curve_name, 0); /* rb_define_method(cEC_GROUP, "curve_name=", ossl_ec_group_set_curve_name, 1); */ rb_define_method(cEC_GROUP, "asn1_flag", ossl_ec_group_get_asn1_flag, 0); rb_define_method(cEC_GROUP, "asn1_flag=", ossl_ec_group_set_asn1_flag, 1); rb_define_method(cEC_GROUP, "point_conversion_form", ossl_ec_group_get_point_conversion_form, 0); rb_define_method(cEC_GROUP, "point_conversion_form=", ossl_ec_group_set_point_conversion_form, 1); rb_define_method(cEC_GROUP, "seed", ossl_ec_group_get_seed, 0); rb_define_method(cEC_GROUP, "seed=", ossl_ec_group_set_seed, 1); /* get/set GFp, GF2m */ rb_define_method(cEC_GROUP, "degree", ossl_ec_group_get_degree, 0); /* check* */ rb_define_method(cEC_GROUP, "to_pem", ossl_ec_group_to_pem, 0); rb_define_method(cEC_GROUP, "to_der", ossl_ec_group_to_der, 0); rb_define_method(cEC_GROUP, "to_text", ossl_ec_group_to_text, 0); rb_define_alloc_func(cEC_POINT, ossl_ec_point_alloc); rb_define_method(cEC_POINT, "initialize", ossl_ec_point_initialize, -1); rb_attr(cEC_POINT, rb_intern("group"), 1, 0, 0); rb_define_method(cEC_POINT, "eql?", ossl_ec_point_eql, 1); rb_define_alias(cEC_POINT, "==", "eql?"); rb_define_method(cEC_POINT, "infinity?", ossl_ec_point_is_at_infinity, 0); rb_define_method(cEC_POINT, "on_curve?", ossl_ec_point_is_on_curve, 0); rb_define_method(cEC_POINT, "make_affine!", ossl_ec_point_make_affine, 0); rb_define_method(cEC_POINT, "invert!", ossl_ec_point_invert, 0); rb_define_method(cEC_POINT, "set_to_infinity!", ossl_ec_point_set_to_infinity, 0); /* all the other methods */ rb_define_method(cEC_POINT, "to_bn", ossl_ec_point_to_bn, 0); no_copy(cEC); no_copy(cEC_GROUP); no_copy(cEC_POINT); } #else /* defined NO_EC */ void Init_ossl_ec() { } #endif /* NO_EC */ ================================================ FILE: ext/openssl/ossl_pkey_rsa.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(OPENSSL_NO_RSA) #include "ossl.h" #define GetPKeyRSA(obj, pkey) do { \ GetPKey(obj, pkey); \ if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) { /* PARANOIA? */ \ ossl_raise(rb_eRuntimeError, "THIS IS NOT A RSA!") ; \ } \ } while (0) #define RSA_HAS_PRIVATE(rsa) ((rsa)->p && (rsa)->q) #define RSA_PRIVATE(obj,rsa) (RSA_HAS_PRIVATE(rsa)||OSSL_PKEY_IS_PRIVATE(obj)) /* * Classes */ VALUE cRSA; VALUE eRSAError; /* * Public */ static VALUE rsa_instance(VALUE klass, RSA *rsa) { EVP_PKEY *pkey; VALUE obj; if (!rsa) { return Qfalse; } if (!(pkey = EVP_PKEY_new())) { return Qfalse; } if (!EVP_PKEY_assign_RSA(pkey, rsa)) { EVP_PKEY_free(pkey); return Qfalse; } WrapPKey(klass, obj, pkey); return obj; } VALUE ossl_rsa_new(EVP_PKEY *pkey) { VALUE obj; if (!pkey) { obj = rsa_instance(cRSA, RSA_new()); } else { if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) { ossl_raise(rb_eTypeError, "Not a RSA key!"); } WrapPKey(cRSA, obj, pkey); } if (obj == Qfalse) { ossl_raise(eRSAError, NULL); } return obj; } /* * Private */ static RSA * rsa_generate(int size, int exp) { return RSA_generate_key(size, exp, rb_block_given_p() ? ossl_generate_cb : NULL, NULL); } /* * call-seq: * RSA.generate(size [, exponent]) -> rsa * * === Parameters * * +size+ is an integer representing the desired key size. Keys smaller than 1024 should be considered insecure. * * +exponent+ is an odd number normally 3, 17, or 65537. * */ static VALUE ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass) { /* why does this method exist? why can't initialize take an optional exponent? */ RSA *rsa; VALUE size, exp; VALUE obj; rb_scan_args(argc, argv, "11", &size, &exp); rsa = rsa_generate(NUM2INT(size), NIL_P(exp) ? RSA_F4 : NUM2INT(exp)); /* err handled by rsa_instance */ obj = rsa_instance(klass, rsa); if (obj == Qfalse) { RSA_free(rsa); ossl_raise(eRSAError, NULL); } return obj; } /* * call-seq: * RSA.new([size | encoded_key] [, pass]) -> rsa * * === Parameters * * +size+ is an integer representing the desired key size. * * +encoded_key+ is a string containing PEM or DER encoded key. * * +pass+ is an optional string with the password to decrypt the encoded key. * * === Examples * * RSA.new(2048) -> rsa * * RSA.new(File.read("rsa.pem")) -> rsa * * RSA.new(File.read("rsa.pem"), "mypassword") -> rsa */ static VALUE ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; RSA *rsa; BIO *in; char *passwd = NULL; VALUE arg, pass; GetPKey(self, pkey); if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) { rsa = RSA_new(); } else if (FIXNUM_P(arg)) { rsa = rsa_generate(FIX2INT(arg), NIL_P(pass) ? RSA_F4 : NUM2INT(pass)); if (!rsa) ossl_raise(eRSAError, NULL); } else { if (!NIL_P(pass)) passwd = StringValuePtr(pass); arg = ossl_to_der_if_possible(arg); in = ossl_obj2bio(arg); rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd); if (!rsa) { BIO_reset(in); rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL); } if (!rsa) { BIO_reset(in); rsa = PEM_read_bio_RSA_PUBKEY(in, NULL, NULL, NULL); } if (!rsa) { BIO_reset(in); rsa = d2i_RSAPrivateKey_bio(in, NULL); } if (!rsa) { BIO_reset(in); rsa = d2i_RSAPublicKey_bio(in, NULL); } if (!rsa) { BIO_reset(in); rsa = d2i_RSA_PUBKEY_bio(in, NULL); } BIO_free(in); if (!rsa) ossl_raise(eRSAError, "Neither PUB key nor PRIV key:"); } if (!EVP_PKEY_assign_RSA(pkey, rsa)) { RSA_free(rsa); ossl_raise(eRSAError, NULL); } return self; } /* * call-seq: * rsa.public? -> true * * The return value is always true since every private key is also a public key. * */ static VALUE ossl_rsa_is_public(VALUE self) { EVP_PKEY *pkey; GetPKeyRSA(self, pkey); /* * This method should check for n and e. BUG. */ return Qtrue; } /* * call-seq: * rsa.private? -> true | false * */ static VALUE ossl_rsa_is_private(VALUE self) { EVP_PKEY *pkey; GetPKeyRSA(self, pkey); return (RSA_PRIVATE(self, pkey->pkey.rsa)) ? Qtrue : Qfalse; } /* * call-seq: * rsa.to_pem([cipher, pass]) -> aString * * === Parameters * * +cipher+ is a Cipher object. * * +pass+ is a string. * * === Examples * * rsa.to_pem -> aString * * rsa.to_pem(cipher, pass) -> aString */ static VALUE ossl_rsa_export(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; BIO *out; const EVP_CIPHER *ciph = NULL; char *passwd = NULL; VALUE cipher, pass, str; GetPKeyRSA(self, pkey); rb_scan_args(argc, argv, "02", &cipher, &pass); if (!NIL_P(cipher)) { ciph = GetCipherPtr(cipher); if (!NIL_P(pass)) { passwd = StringValuePtr(pass); } } if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eRSAError, NULL); } if (RSA_HAS_PRIVATE(pkey->pkey.rsa)) { if (!PEM_write_bio_RSAPrivateKey(out, pkey->pkey.rsa, ciph, NULL, 0, ossl_pem_passwd_cb, passwd)) { BIO_free(out); ossl_raise(eRSAError, NULL); } } else { if (!PEM_write_bio_RSAPublicKey(out, pkey->pkey.rsa)) { BIO_free(out); ossl_raise(eRSAError, NULL); } } str = ossl_membio2str(out); return str; } /* * call-seq: * rsa.to_der -> aString * */ static VALUE ossl_rsa_to_der(VALUE self) { EVP_PKEY *pkey; int (*i2d_func)_((const RSA*, unsigned char**)); unsigned char *p; long len; VALUE str; GetPKeyRSA(self, pkey); if(RSA_HAS_PRIVATE(pkey->pkey.rsa)) i2d_func = i2d_RSAPrivateKey; else i2d_func = i2d_RSAPublicKey; if((len = i2d_func(pkey->pkey.rsa, NULL)) <= 0) ossl_raise(eRSAError, NULL); str = rb_str_new(0, len); p = RSTRING_PTR(str); if(i2d_func(pkey->pkey.rsa, &p) < 0) ossl_raise(eRSAError, NULL); ossl_str_adjust(str, p); return str; } #define ossl_rsa_buf_size(pkey) (RSA_size((pkey)->pkey.rsa)+16) /* * call-seq: * rsa.public_encrypt(string [, padding]) -> aString * */ static VALUE ossl_rsa_public_encrypt(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; int buf_len, pad; VALUE str, buffer, padding; GetPKeyRSA(self, pkey); rb_scan_args(argc, argv, "11", &buffer, &padding); pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); StringValue(buffer); str = rb_str_new(0, ossl_rsa_buf_size(pkey)); buf_len = RSA_public_encrypt(RSTRING_LEN(buffer), RSTRING_PTR(buffer), RSTRING_PTR(str), pkey->pkey.rsa, pad); if (buf_len < 0) ossl_raise(eRSAError, NULL); rb_str_set_len(str, buf_len); return str; } /* * call-seq: * rsa.public_decrypt(string [, padding]) -> aString * */ static VALUE ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; int buf_len, pad; VALUE str, buffer, padding; GetPKeyRSA(self, pkey); rb_scan_args(argc, argv, "11", &buffer, &padding); pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); StringValue(buffer); str = rb_str_new(0, ossl_rsa_buf_size(pkey)); buf_len = RSA_public_decrypt(RSTRING_LEN(buffer), RSTRING_PTR(buffer), RSTRING_PTR(str), pkey->pkey.rsa, pad); if (buf_len < 0) ossl_raise(eRSAError, NULL); rb_str_set_len(str, buf_len); return str; } /* * call-seq: * rsa.private_encrypt(string [, padding]) -> aString * */ static VALUE ossl_rsa_private_encrypt(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; int buf_len, pad; VALUE str, buffer, padding; GetPKeyRSA(self, pkey); if (!RSA_PRIVATE(self, pkey->pkey.rsa)) { ossl_raise(eRSAError, "private key needed."); } rb_scan_args(argc, argv, "11", &buffer, &padding); pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); StringValue(buffer); str = rb_str_new(0, ossl_rsa_buf_size(pkey)); buf_len = RSA_private_encrypt(RSTRING_LEN(buffer), RSTRING_PTR(buffer), RSTRING_PTR(str), pkey->pkey.rsa, pad); if (buf_len < 0) ossl_raise(eRSAError, NULL); rb_str_set_len(str, buf_len); return str; } /* * call-seq: * rsa.private_decrypt(string [, padding]) -> aString * */ static VALUE ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; int buf_len, pad; VALUE str, buffer, padding; GetPKeyRSA(self, pkey); if (!RSA_PRIVATE(self, pkey->pkey.rsa)) { ossl_raise(eRSAError, "private key needed."); } rb_scan_args(argc, argv, "11", &buffer, &padding); pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); StringValue(buffer); str = rb_str_new(0, ossl_rsa_buf_size(pkey)); buf_len = RSA_private_decrypt(RSTRING_LEN(buffer), RSTRING_PTR(buffer), RSTRING_PTR(str), pkey->pkey.rsa, pad); if (buf_len < 0) ossl_raise(eRSAError, NULL); rb_str_set_len(str, buf_len); return str; } /* * call-seq: * rsa.params -> hash * * Stores all parameters of key to the hash * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! * Don't use :-)) (I's up to you) */ static VALUE ossl_rsa_get_params(VALUE self) { EVP_PKEY *pkey; VALUE hash; GetPKeyRSA(self, pkey); hash = rb_hash_new(); rb_hash_aset(hash, rb_str_new2("n"), ossl_bn_new(pkey->pkey.rsa->n)); rb_hash_aset(hash, rb_str_new2("e"), ossl_bn_new(pkey->pkey.rsa->e)); rb_hash_aset(hash, rb_str_new2("d"), ossl_bn_new(pkey->pkey.rsa->d)); rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(pkey->pkey.rsa->p)); rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(pkey->pkey.rsa->q)); rb_hash_aset(hash, rb_str_new2("dmp1"), ossl_bn_new(pkey->pkey.rsa->dmp1)); rb_hash_aset(hash, rb_str_new2("dmq1"), ossl_bn_new(pkey->pkey.rsa->dmq1)); rb_hash_aset(hash, rb_str_new2("iqmp"), ossl_bn_new(pkey->pkey.rsa->iqmp)); return hash; } /* * call-seq: * rsa.to_text -> aString * * Prints all parameters of key to buffer * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! * Don't use :-)) (It's up to you) */ static VALUE ossl_rsa_to_text(VALUE self) { EVP_PKEY *pkey; BIO *out; VALUE str; GetPKeyRSA(self, pkey); if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eRSAError, NULL); } if (!RSA_print(out, pkey->pkey.rsa, 0)) { /* offset = 0 */ BIO_free(out); ossl_raise(eRSAError, NULL); } str = ossl_membio2str(out); return str; } /* * call-seq: * rsa.public_key -> aRSA * * Makes new instance RSA PUBLIC_KEY from PRIVATE_KEY */ static VALUE ossl_rsa_to_public_key(VALUE self) { EVP_PKEY *pkey; RSA *rsa; VALUE obj; GetPKeyRSA(self, pkey); /* err check performed by rsa_instance */ rsa = RSAPublicKey_dup(pkey->pkey.rsa); obj = rsa_instance(CLASS_OF(self), rsa); if (obj == Qfalse) { RSA_free(rsa); ossl_raise(eRSAError, NULL); } return obj; } /* * TODO: Test me static VALUE ossl_rsa_blinding_on(VALUE self) { EVP_PKEY *pkey; GetPKeyRSA(self, pkey); if (RSA_blinding_on(pkey->pkey.rsa, ossl_bn_ctx) != 1) { ossl_raise(eRSAError, NULL); } return self; } static VALUE ossl_rsa_blinding_off(VALUE self) { EVP_PKEY *pkey; GetPKeyRSA(self, pkey); RSA_blinding_off(pkey->pkey.rsa); return self; } */ OSSL_PKEY_BN(rsa, n); OSSL_PKEY_BN(rsa, e); OSSL_PKEY_BN(rsa, d); OSSL_PKEY_BN(rsa, p); OSSL_PKEY_BN(rsa, q); OSSL_PKEY_BN(rsa, dmp1); OSSL_PKEY_BN(rsa, dmq1); OSSL_PKEY_BN(rsa, iqmp); /* * INIT */ #define DefRSAConst(x) rb_define_const(cRSA, #x,INT2FIX(RSA_##x)) void Init_ossl_rsa() { #if 0 /* let rdoc know about mOSSL and mPKey */ mOSSL = rb_define_module("OpenSSL"); mPKey = rb_define_module_under(mOSSL, "PKey"); #endif eRSAError = rb_define_class_under(mPKey, "RSAError", ePKeyError); cRSA = rb_define_class_under(mPKey, "RSA", cPKey); rb_define_singleton_method(cRSA, "generate", ossl_rsa_s_generate, -1); rb_define_method(cRSA, "initialize", ossl_rsa_initialize, -1); rb_define_method(cRSA, "public?", ossl_rsa_is_public, 0); rb_define_method(cRSA, "private?", ossl_rsa_is_private, 0); rb_define_method(cRSA, "to_text", ossl_rsa_to_text, 0); rb_define_method(cRSA, "export", ossl_rsa_export, -1); rb_define_alias(cRSA, "to_pem", "export"); rb_define_alias(cRSA, "to_s", "export"); rb_define_method(cRSA, "to_der", ossl_rsa_to_der, 0); rb_define_method(cRSA, "public_key", ossl_rsa_to_public_key, 0); rb_define_method(cRSA, "public_encrypt", ossl_rsa_public_encrypt, -1); rb_define_method(cRSA, "public_decrypt", ossl_rsa_public_decrypt, -1); rb_define_method(cRSA, "private_encrypt", ossl_rsa_private_encrypt, -1); rb_define_method(cRSA, "private_decrypt", ossl_rsa_private_decrypt, -1); DEF_OSSL_PKEY_BN(cRSA, rsa, n); DEF_OSSL_PKEY_BN(cRSA, rsa, e); DEF_OSSL_PKEY_BN(cRSA, rsa, d); DEF_OSSL_PKEY_BN(cRSA, rsa, p); DEF_OSSL_PKEY_BN(cRSA, rsa, q); DEF_OSSL_PKEY_BN(cRSA, rsa, dmp1); DEF_OSSL_PKEY_BN(cRSA, rsa, dmq1); DEF_OSSL_PKEY_BN(cRSA, rsa, iqmp); rb_define_method(cRSA, "params", ossl_rsa_get_params, 0); DefRSAConst(PKCS1_PADDING); DefRSAConst(SSLV23_PADDING); DefRSAConst(NO_PADDING); DefRSAConst(PKCS1_OAEP_PADDING); /* * TODO: Test it rb_define_method(cRSA, "blinding_on!", ossl_rsa_blinding_on, 0); rb_define_method(cRSA, "blinding_off!", ossl_rsa_blinding_off, 0); */ } #else /* defined NO_RSA */ void Init_ossl_rsa() { } #endif /* NO_RSA */ ================================================ FILE: ext/openssl/ossl_rand.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" /* * Classes */ VALUE mRandom; VALUE eRandomError; /* * Struct */ /* * Public */ /* * Private */ /* * call-seq: * seed(str) -> str * */ static VALUE ossl_rand_seed(VALUE self, VALUE str) { StringValue(str); RAND_seed(RSTRING_PTR(str), RSTRING_LEN(str)); return str; } /* * call-seq: * add(str, entropy) -> self * */ static VALUE ossl_rand_add(VALUE self, VALUE str, VALUE entropy) { StringValue(str); RAND_add(RSTRING_PTR(str), RSTRING_LEN(str), NUM2DBL(entropy)); return self; } /* * call-seq: * load_random_file(filename) -> true * */ static VALUE ossl_rand_load_file(VALUE self, VALUE filename) { SafeStringValue(filename); if(!RAND_load_file(RSTRING_PTR(filename), -1)) { ossl_raise(eRandomError, NULL); } return Qtrue; } /* * call-seq: * write_random_file(filename) -> true * */ static VALUE ossl_rand_write_file(VALUE self, VALUE filename) { SafeStringValue(filename); if (RAND_write_file(RSTRING_PTR(filename)) == -1) { ossl_raise(eRandomError, NULL); } return Qtrue; } /* * call-seq: * random_bytes(length) -> aString * */ static VALUE ossl_rand_bytes(VALUE self, VALUE len) { VALUE str; int n = NUM2INT(len); str = rb_str_new(0, n); if (!RAND_bytes(RSTRING_PTR(str), n)) { ossl_raise(eRandomError, NULL); } return str; } /* * call-seq: * pseudo_bytes(length) -> aString * */ static VALUE ossl_rand_pseudo_bytes(VALUE self, VALUE len) { VALUE str; int n = NUM2INT(len); str = rb_str_new(0, n); if (!RAND_pseudo_bytes(RSTRING_PTR(str), n)) { ossl_raise(eRandomError, NULL); } return str; } /* * call-seq: * egd(filename) -> true * */ static VALUE ossl_rand_egd(VALUE self, VALUE filename) { SafeStringValue(filename); if(!RAND_egd(RSTRING_PTR(filename))) { ossl_raise(eRandomError, NULL); } return Qtrue; } /* * call-seq: * egd_bytes(filename, length) -> true * */ static VALUE ossl_rand_egd_bytes(VALUE self, VALUE filename, VALUE len) { long n = NUM2INT(len); SafeStringValue(filename); if (!RAND_egd_bytes(RSTRING_PTR(filename), n)) { ossl_raise(eRandomError, NULL); } return Qtrue; } /* * call-seq: * status? => true | false * * Return true if the PRNG has been seeded with enough data, false otherwise. */ static VALUE ossl_rand_status(VALUE self) { return RAND_status() ? Qtrue : Qfalse; } #define DEFMETH(class, name, func, argc) \ rb_define_method(class, name, func, argc); \ rb_define_singleton_method(class, name, func, argc); /* * INIT */ void Init_ossl_rand() { #if 0 /* let rdoc know about mOSSL */ mOSSL = rb_define_module("OpenSSL"); #endif mRandom = rb_define_module_under(mOSSL, "Random"); eRandomError = rb_define_class_under(mRandom, "RandomError", eOSSLError); DEFMETH(mRandom, "seed", ossl_rand_seed, 1); DEFMETH(mRandom, "random_add", ossl_rand_add, 2); DEFMETH(mRandom, "load_random_file", ossl_rand_load_file, 1); DEFMETH(mRandom, "write_random_file", ossl_rand_write_file, 1); DEFMETH(mRandom, "random_bytes", ossl_rand_bytes, 1); DEFMETH(mRandom, "pseudo_bytes", ossl_rand_pseudo_bytes, 1); DEFMETH(mRandom, "egd", ossl_rand_egd, 1); DEFMETH(mRandom, "egd_bytes", ossl_rand_egd_bytes, 2); DEFMETH(mRandom, "status?", ossl_rand_status, 0) } ================================================ FILE: ext/openssl/ossl_rand.h ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(_OSSL_RAND_H_) #define _OSSL_RAND_H_ extern VALUE mRandom; extern VALUE eRandomError; void Init_ossl_rand(void); #endif /* _OSSL_RAND_H_ */ ================================================ FILE: ext/openssl/ossl_ssl.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2000-2002 GOTOU Yuuzou * Copyright (C) 2001-2002 Michal Rokos * Copyright (C) 2001-2007 Technorama Ltd. * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" #include #include #if defined(HAVE_UNISTD_H) # include /* for read(), and write() */ #endif #define numberof(ary) (sizeof(ary)/sizeof(ary[0])) #ifdef _WIN32 # define TO_SOCKET(s) _get_osfhandle(s) #else # define TO_SOCKET(s) s #endif VALUE mSSL; VALUE eSSLError; VALUE cSSLContext; VALUE cSSLSocket; #define ossl_sslctx_set_cert(o,v) rb_iv_set((o),"@cert",(v)) #define ossl_sslctx_set_key(o,v) rb_iv_set((o),"@key",(v)) #define ossl_sslctx_set_client_ca(o,v) rb_iv_set((o),"@client_ca",(v)) #define ossl_sslctx_set_ca_file(o,v) rb_iv_set((o),"@ca_file",(v)) #define ossl_sslctx_set_ca_path(o,v) rb_iv_set((o),"@ca_path",(v)) #define ossl_sslctx_set_timeout(o,v) rb_iv_set((o),"@timeout",(v)) #define ossl_sslctx_set_verify_mode(o,v) rb_iv_set((o),"@verify_mode",(v)) #define ossl_sslctx_set_verify_dep(o,v) rb_iv_set((o),"@verify_depth",(v)) #define ossl_sslctx_set_verify_cb(o,v) rb_iv_set((o),"@verify_callback",(v)) #define ossl_sslctx_set_options(o,v) rb_iv_set((o),"@options",(v)) #define ossl_sslctx_set_cert_store(o,v) rb_iv_set((o),"@cert_store",(v)) #define ossl_sslctx_set_extra_cert(o,v) rb_iv_set((o),"@extra_chain_cert",(v)) #define ossl_sslctx_set_client_cert_cb(o,v) rb_iv_set((o),"@client_cert_cb",(v)) #define ossl_sslctx_set_tmp_dh_cb(o,v) rb_iv_set((o),"@tmp_dh_callback",(v)) #define ossl_sslctx_set_sess_id_ctx(o, v) rb_iv_get((o),"@session_id_context"(v)) #define ossl_sslctx_get_cert(o) rb_iv_get((o),"@cert") #define ossl_sslctx_get_key(o) rb_iv_get((o),"@key") #define ossl_sslctx_get_client_ca(o) rb_iv_get((o),"@client_ca") #define ossl_sslctx_get_ca_file(o) rb_iv_get((o),"@ca_file") #define ossl_sslctx_get_ca_path(o) rb_iv_get((o),"@ca_path") #define ossl_sslctx_get_timeout(o) rb_iv_get((o),"@timeout") #define ossl_sslctx_get_verify_mode(o) rb_iv_get((o),"@verify_mode") #define ossl_sslctx_get_verify_dep(o) rb_iv_get((o),"@verify_depth") #define ossl_sslctx_get_verify_cb(o) rb_iv_get((o),"@verify_callback") #define ossl_sslctx_get_options(o) rb_iv_get((o),"@options") #define ossl_sslctx_get_cert_store(o) rb_iv_get((o),"@cert_store") #define ossl_sslctx_get_extra_cert(o) rb_iv_get((o),"@extra_chain_cert") #define ossl_sslctx_get_client_cert_cb(o) rb_iv_get((o),"@client_cert_cb") #define ossl_sslctx_get_tmp_dh_cb(o) rb_iv_get((o),"@tmp_dh_callback") #define ossl_sslctx_get_sess_id_ctx(o) rb_iv_get((o),"@session_id_context") static const char *ossl_sslctx_attrs[] = { "cert", "key", "client_ca", "ca_file", "ca_path", "timeout", "verify_mode", "verify_depth", "verify_callback", "options", "cert_store", "extra_chain_cert", "client_cert_cb", "tmp_dh_callback", "session_id_context", "session_get_cb", "session_new_cb", "session_remove_cb", }; #define ossl_ssl_get_io(o) rb_iv_get((o),"@io") #define ossl_ssl_get_ctx(o) rb_iv_get((o),"@context") #define ossl_ssl_get_sync_close(o) rb_iv_get((o),"@sync_close") #define ossl_ssl_get_x509(o) rb_iv_get((o),"@x509") #define ossl_ssl_get_key(o) rb_iv_get((o),"@key") #define ossl_ssl_get_tmp_dh(o) rb_iv_get((o),"@tmp_dh") #define ossl_ssl_set_io(o,v) rb_iv_set((o),"@io",(v)) #define ossl_ssl_set_ctx(o,v) rb_iv_set((o),"@context",(v)) #define ossl_ssl_set_sync_close(o,v) rb_iv_set((o),"@sync_close",(v)) #define ossl_ssl_set_x509(o,v) rb_iv_set((o),"@x509",(v)) #define ossl_ssl_set_key(o,v) rb_iv_set((o),"@key",(v)) #define ossl_ssl_set_tmp_dh(o,v) rb_iv_set((o),"@tmp_dh",(v)) static const char *ossl_ssl_attr_readers[] = { "io", "context", }; static const char *ossl_ssl_attrs[] = { "sync_close", }; ID ID_callback_state; /* * SSLContext class */ struct { const char *name; OSSL_MORE_CONST SSL_METHOD *(*func)(void); } ossl_ssl_method_tab[] = { #define OSSL_SSL_METHOD_ENTRY(name) { #name, name##_method } OSSL_SSL_METHOD_ENTRY(TLSv1), OSSL_SSL_METHOD_ENTRY(TLSv1_server), OSSL_SSL_METHOD_ENTRY(TLSv1_client), OSSL_SSL_METHOD_ENTRY(SSLv2), OSSL_SSL_METHOD_ENTRY(SSLv2_server), OSSL_SSL_METHOD_ENTRY(SSLv2_client), OSSL_SSL_METHOD_ENTRY(SSLv3), OSSL_SSL_METHOD_ENTRY(SSLv3_server), OSSL_SSL_METHOD_ENTRY(SSLv3_client), OSSL_SSL_METHOD_ENTRY(SSLv23), OSSL_SSL_METHOD_ENTRY(SSLv23_server), OSSL_SSL_METHOD_ENTRY(SSLv23_client), #undef OSSL_SSL_METHOD_ENTRY }; int ossl_ssl_ex_vcb_idx; int ossl_ssl_ex_store_p; int ossl_ssl_ex_ptr_idx; int ossl_ssl_ex_client_cert_cb_idx; int ossl_ssl_ex_tmp_dh_callback_idx; static void ossl_sslctx_free(SSL_CTX *ctx) { if(ctx && SSL_CTX_get_ex_data(ctx, ossl_ssl_ex_store_p)== (void*)1) ctx->cert_store = NULL; SSL_CTX_free(ctx); } static VALUE ossl_sslctx_s_alloc(VALUE klass) { SSL_CTX *ctx; ctx = SSL_CTX_new(SSLv23_method()); if (!ctx) { ossl_raise(eSSLError, "SSL_CTX_new:"); } SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); SSL_CTX_set_options(ctx, SSL_OP_ALL); return Data_Wrap_Struct(klass, 0, ossl_sslctx_free, ctx); } static VALUE ossl_sslctx_set_ssl_version(VALUE self, VALUE ssl_method) { OSSL_MORE_CONST SSL_METHOD *method = NULL; const char *s; int i; SSL_CTX *ctx; if(TYPE(ssl_method) == T_SYMBOL) s = rb_id2name(SYM2ID(ssl_method)); else s = StringValuePtr(ssl_method); for (i = 0; i < numberof(ossl_ssl_method_tab); i++) { if (strcmp(ossl_ssl_method_tab[i].name, s) == 0) { method = ossl_ssl_method_tab[i].func(); break; } } if (!method) { ossl_raise(rb_eArgError, "unknown SSL method `%s'.", s); } Data_Get_Struct(self, SSL_CTX, ctx); if (SSL_CTX_set_ssl_version(ctx, method) != 1) { ossl_raise(eSSLError, "SSL_CTX_set_ssl_version:"); } return ssl_method; } /* * call-seq: * SSLContext.new => ctx * SSLContext.new(:TLSv1) => ctx * SSLContext.new("SSLv23_client") => ctx * * You can get a list of valid methods with OpenSSL::SSL::SSLContext::METHODS */ static VALUE ossl_sslctx_initialize(int argc, VALUE *argv, VALUE self) { VALUE ssl_method; int i; for(i = 0; i < numberof(ossl_sslctx_attrs); i++){ char buf[32]; snprintf(buf, sizeof(buf), "@%s", ossl_sslctx_attrs[i]); rb_iv_set(self, buf, Qnil); } if (rb_scan_args(argc, argv, "01", &ssl_method) == 0){ return self; } ossl_sslctx_set_ssl_version(self, ssl_method); return self; } static VALUE ossl_call_client_cert_cb(VALUE obj) { VALUE cb, ary, cert, key; SSL *ssl; Data_Get_Struct(obj, SSL, ssl); cb = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_client_cert_cb_idx); if (NIL_P(cb)) return Qfalse; ary = rb_funcall(cb, rb_intern("call"), 1, obj); Check_Type(ary, T_ARRAY); GetX509CertPtr(cert = rb_ary_entry(ary, 0)); GetPKeyPtr(key = rb_ary_entry(ary, 1)); ossl_ssl_set_x509(obj, cert); ossl_ssl_set_key(obj, key); return Qtrue; } static int ossl_client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey) { VALUE obj; int status, success; obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); success = rb_protect((VALUE(*)_((VALUE)))ossl_call_client_cert_cb, obj, &status); if (status || !success) return 0; *x509 = DupX509CertPtr(ossl_ssl_get_x509(obj)); *pkey = DupPKeyPtr(ossl_ssl_get_key(obj)); return 1; } #if !defined(OPENSSL_NO_DH) static VALUE ossl_call_tmp_dh_callback(VALUE *args) { SSL *ssl; VALUE cb, dh; EVP_PKEY *pkey; Data_Get_Struct(args[0], SSL, ssl); cb = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_tmp_dh_callback_idx); if (NIL_P(cb)) return Qfalse; dh = rb_funcall(cb, rb_intern("call"), 3, args[0], args[1], args[2]); pkey = GetPKeyPtr(dh); if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DH) return Qfalse; ossl_ssl_set_tmp_dh(args[0], dh); return Qtrue; } static DH* ossl_tmp_dh_callback(SSL *ssl, int is_export, int keylength) { VALUE args[3]; int status, success; args[0] = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); args[1] = INT2FIX(is_export); args[2] = INT2FIX(keylength); success = rb_protect((VALUE(*)_((VALUE)))ossl_call_tmp_dh_callback, (VALUE)args, &status); if (status || !success) return NULL; return GetPKeyPtr(ossl_ssl_get_tmp_dh(args[0]))->pkey.dh; } static DH* ossl_default_tmp_dh_callback(SSL *ssl, int is_export, int keylength) { rb_warning("using default DH parameters."); switch(keylength){ case 512: return OSSL_DEFAULT_DH_512; case 1024: return OSSL_DEFAULT_DH_1024; } return NULL; } #endif /* OPENSSL_NO_DH */ static int ossl_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { VALUE cb; SSL *ssl; ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); cb = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_vcb_idx); X509_STORE_CTX_set_ex_data(ctx, ossl_verify_cb_idx, (void*)cb); return ossl_verify_cb(preverify_ok, ctx); } static VALUE ossl_call_session_get_cb(VALUE ary) { VALUE ssl_obj, sslctx_obj, cb, ret; Check_Type(ary, T_ARRAY); ssl_obj = rb_ary_entry(ary, 0); sslctx_obj = rb_iv_get(ssl_obj, "@context"); if (NIL_P(sslctx_obj)) return Qnil; cb = rb_iv_get(sslctx_obj, "@session_get_cb"); if (NIL_P(cb)) return Qnil; return rb_funcall(cb, rb_intern("call"), 1, ary); } /* this method is currently only called for servers (in OpenSSL <= 0.9.8e) */ static SSL_SESSION * ossl_sslctx_session_get_cb(SSL *ssl, unsigned char *buf, int len, int *copy) { VALUE ary, ssl_obj, ret_obj; SSL_SESSION *sess; void *ptr; int state = 0; OSSL_Debug("SSL SESSION get callback entered"); if ((ptr = SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)) == NULL) return NULL; ssl_obj = (VALUE)ptr; ary = rb_ary_new2(2); rb_ary_push(ary, ssl_obj); rb_ary_push(ary, rb_str_new(buf, len)); ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_get_cb, ary, &state); if (state) { rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state)); return NULL; } if (!rb_obj_is_instance_of(ret_obj, cSSLSession)) return NULL; SafeGetSSLSession(ret_obj, sess); *copy = 1; return sess; } static VALUE ossl_call_session_new_cb(VALUE ary) { VALUE ssl_obj, sslctx_obj, cb, ret; Check_Type(ary, T_ARRAY); ssl_obj = rb_ary_entry(ary, 0); sslctx_obj = rb_iv_get(ssl_obj, "@context"); if (NIL_P(sslctx_obj)) return Qnil; cb = rb_iv_get(sslctx_obj, "@session_new_cb"); if (NIL_P(cb)) return Qnil; return rb_funcall(cb, rb_intern("call"), 1, ary); } /* return 1 normal. return 0 removes the session */ static int ossl_sslctx_session_new_cb(SSL *ssl, SSL_SESSION *sess) { VALUE ary, ssl_obj, sess_obj, ret_obj; void *ptr; int state = 0; OSSL_Debug("SSL SESSION new callback entered"); if ((ptr = SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)) == NULL) return 1; ssl_obj = (VALUE)ptr; sess_obj = rb_obj_alloc(cSSLSession); CRYPTO_add(&sess->references, 1, CRYPTO_LOCK_SSL_SESSION); DATA_PTR(sess_obj) = sess; ary = rb_ary_new2(2); rb_ary_push(ary, ssl_obj); rb_ary_push(ary, sess_obj); ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_new_cb, ary, &state); if (state) { rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state)); return 0; /* what should be returned here??? */ } return RTEST(ret_obj) ? 1 : 0; } static VALUE ossl_call_session_remove_cb(VALUE ary) { VALUE sslctx_obj, cb, ret; Check_Type(ary, T_ARRAY); sslctx_obj = rb_ary_entry(ary, 0); cb = rb_iv_get(sslctx_obj, "@session_remove_cb"); if (NIL_P(cb)) return Qnil; return rb_funcall(cb, rb_intern("call"), 1, ary); } static void ossl_sslctx_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess) { VALUE ary, sslctx_obj, sess_obj, ret_obj; void *ptr; int state = 0; OSSL_Debug("SSL SESSION remove callback entered"); if ((ptr = SSL_CTX_get_ex_data(ctx, ossl_ssl_ex_ptr_idx)) == NULL) return; sslctx_obj = (VALUE)ptr; sess_obj = rb_obj_alloc(cSSLSession); CRYPTO_add(&sess->references, 1, CRYPTO_LOCK_SSL_SESSION); DATA_PTR(sess_obj) = sess; ary = rb_ary_new2(2); rb_ary_push(ary, sslctx_obj); rb_ary_push(ary, sess_obj); ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_new_cb, ary, &state); if (state) { /* the SSL_CTX is frozen, nowhere to save state. there is no common accessor method to check it either. rb_ivar_set(sslctx_obj, ID_callback_state, INT2NUM(state)); */ } } static VALUE ossl_sslctx_add_extra_chain_cert_i(VALUE i, VALUE arg) { X509 *x509; SSL_CTX *ctx; Data_Get_Struct(arg, SSL_CTX, ctx); x509 = DupX509CertPtr(i); if(!SSL_CTX_add_extra_chain_cert(ctx, x509)){ ossl_raise(eSSLError, NULL); } return i; } /* * call-seq: * ctx.setup => Qtrue # first time * ctx.setup => nil # thereafter * * This method is called automatically when a new SSLSocket is created. * Normally you do not need to call this method (unless you are writing an extension in C). */ static VALUE ossl_sslctx_setup(VALUE self) { SSL_CTX *ctx; X509 *cert = NULL, *client_ca = NULL; X509_STORE *store; EVP_PKEY *key = NULL; char *ca_path = NULL, *ca_file = NULL; int i, verify_mode; VALUE val; if(OBJ_FROZEN(self)) return Qnil; Data_Get_Struct(self, SSL_CTX, ctx); #if !defined(OPENSSL_NO_DH) if (RTEST(ossl_sslctx_get_tmp_dh_cb(self))){ SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback); } else{ SSL_CTX_set_tmp_dh_callback(ctx, ossl_default_tmp_dh_callback); } #endif SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_ptr_idx, (void*)self); val = ossl_sslctx_get_cert_store(self); if(!NIL_P(val)){ /* * WORKAROUND: * X509_STORE can count references, but * X509_STORE_free() doesn't care it. * So we won't increment it but mark it by ex_data. */ store = GetX509StorePtr(val); /* NO NEED TO DUP */ SSL_CTX_set_cert_store(ctx, store); SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_store_p, (void*)1); } val = ossl_sslctx_get_extra_cert(self); if(!NIL_P(val)){ rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self); } /* private key may be bundled in certificate file. */ val = ossl_sslctx_get_cert(self); cert = NIL_P(val) ? NULL : GetX509CertPtr(val); /* NO DUP NEEDED */ val = ossl_sslctx_get_key(self); key = NIL_P(val) ? NULL : GetPKeyPtr(val); /* NO DUP NEEDED */ if (cert && key) { if (!SSL_CTX_use_certificate(ctx, cert)) { /* Adds a ref => Safe to FREE */ ossl_raise(eSSLError, "SSL_CTX_use_certificate:"); } if (!SSL_CTX_use_PrivateKey(ctx, key)) { /* Adds a ref => Safe to FREE */ ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey:"); } if (!SSL_CTX_check_private_key(ctx)) { ossl_raise(eSSLError, "SSL_CTX_check_private_key:"); } } val = ossl_sslctx_get_client_ca(self); if(!NIL_P(val)){ if(TYPE(val) == T_ARRAY){ for(i = 0; i < RARRAY_LEN(val); i++){ client_ca = GetX509CertPtr(RARRAY_PTR(val)[i]); if (!SSL_CTX_add_client_CA(ctx, client_ca)){ /* Copies X509_NAME => FREE it. */ ossl_raise(eSSLError, "SSL_CTX_add_client_CA"); } } } else{ client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */ if (!SSL_CTX_add_client_CA(ctx, client_ca)){ /* Copies X509_NAME => FREE it. */ ossl_raise(eSSLError, "SSL_CTX_add_client_CA"); } } } val = ossl_sslctx_get_ca_file(self); ca_file = NIL_P(val) ? NULL : StringValuePtr(val); val = ossl_sslctx_get_ca_path(self); ca_path = NIL_P(val) ? NULL : StringValuePtr(val); if(ca_file || ca_path){ if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path)) rb_warning("can't set verify locations"); } val = ossl_sslctx_get_verify_mode(self); verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val); SSL_CTX_set_verify(ctx, verify_mode, ossl_ssl_verify_callback); if (RTEST(ossl_sslctx_get_client_cert_cb(self))) SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb); val = ossl_sslctx_get_timeout(self); if(!NIL_P(val)) SSL_CTX_set_timeout(ctx, NUM2LONG(val)); val = ossl_sslctx_get_verify_dep(self); if(!NIL_P(val)) SSL_CTX_set_verify_depth(ctx, NUM2LONG(val)); val = ossl_sslctx_get_options(self); if(!NIL_P(val)) SSL_CTX_set_options(ctx, NUM2LONG(val)); rb_obj_freeze(self); val = ossl_sslctx_get_sess_id_ctx(self); if (!NIL_P(val)){ StringValue(val); if (!SSL_CTX_set_session_id_context(ctx, RSTRING_PTR(val), RSTRING_LEN(val))){ ossl_raise(eSSLError, "SSL_CTX_set_session_id_context:"); } } if (RTEST(rb_iv_get(self, "@session_get_cb"))) { SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb); OSSL_Debug("SSL SESSION get callback added"); } if (RTEST(rb_iv_get(self, "@session_new_cb"))) { SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb); OSSL_Debug("SSL SESSION new callback added"); } if (RTEST(rb_iv_get(self, "@session_remove_cb"))) { SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb); OSSL_Debug("SSL SESSION remove callback added"); } return Qtrue; } static VALUE ossl_ssl_cipher_to_ary(OSSL_MORE_CONST SSL_CIPHER *cipher) { VALUE ary; int bits, alg_bits; ary = rb_ary_new2(4); rb_ary_push(ary, rb_str_new2(SSL_CIPHER_get_name(cipher))); rb_ary_push(ary, rb_str_new2(SSL_CIPHER_get_version(cipher))); bits = SSL_CIPHER_get_bits(cipher, &alg_bits); rb_ary_push(ary, INT2FIX(bits)); rb_ary_push(ary, INT2FIX(alg_bits)); return ary; } /* * call-seq: * ctx.ciphers => [[name, version, bits, alg_bits], ...] */ static VALUE ossl_sslctx_get_ciphers(VALUE self) { SSL_CTX *ctx; STACK_OF(SSL_CIPHER) *ciphers; SSL_CIPHER *cipher; VALUE ary; int i, num; Data_Get_Struct(self, SSL_CTX, ctx); if(!ctx){ rb_warning("SSL_CTX is not initialized."); return Qnil; } ciphers = ctx->cipher_list; if (!ciphers) return rb_ary_new(); num = sk_num((STACK*)ciphers); ary = rb_ary_new2(num); for(i = 0; i < num; i++){ cipher = (SSL_CIPHER*)sk_value((STACK*)ciphers, i); rb_ary_push(ary, ossl_ssl_cipher_to_ary(cipher)); } return ary; } /* * call-seq: * ctx.ciphers = "cipher1:cipher2:..." * ctx.ciphers = [name, ...] * ctx.ciphers = [[name, version, bits, alg_bits], ...] */ static VALUE ossl_sslctx_set_ciphers(VALUE self, VALUE v) { SSL_CTX *ctx; VALUE str, elem; int i; rb_check_frozen(self); if (NIL_P(v)) return v; else if (TYPE(v) == T_ARRAY) { str = rb_str_new(0, 0); for (i = 0; i < RARRAY_LEN(v); i++) { elem = rb_ary_entry(v, i); if (TYPE(elem) == T_ARRAY) elem = rb_ary_entry(elem, 0); elem = rb_String(elem); rb_str_append(str, elem); if (i < RARRAY_LEN(v)-1) rb_str_cat2(str, ":"); } } else { str = v; StringValue(str); } Data_Get_Struct(self, SSL_CTX, ctx); if(!ctx){ ossl_raise(eSSLError, "SSL_CTX is not initialized."); return Qnil; } if (!SSL_CTX_set_cipher_list(ctx, RSTRING_PTR(str))) { ossl_raise(eSSLError, "SSL_CTX_set_cipher_list:"); } return v; } /* * call-seq: * ctx.session_add(session) -> true | false * */ static VALUE ossl_sslctx_session_add(VALUE self, VALUE arg) { SSL_CTX *ctx; SSL_SESSION *sess; Data_Get_Struct(self, SSL_CTX, ctx); SafeGetSSLSession(arg, sess); return SSL_CTX_add_session(ctx, sess) == 1 ? Qtrue : Qfalse; } /* * call-seq: * ctx.session_remove(session) -> true | false * */ static VALUE ossl_sslctx_session_remove(VALUE self, VALUE arg) { SSL_CTX *ctx; SSL_SESSION *sess; Data_Get_Struct(self, SSL_CTX, ctx); SafeGetSSLSession(arg, sess); return SSL_CTX_remove_session(ctx, sess) == 1 ? Qtrue : Qfalse; } /* * call-seq: * ctx.session_cache_mode -> integer * */ static VALUE ossl_sslctx_get_session_cache_mode(VALUE self) { SSL_CTX *ctx; Data_Get_Struct(self, SSL_CTX, ctx); return LONG2NUM(SSL_CTX_get_session_cache_mode(ctx)); } /* * call-seq: * ctx.session_cache_mode=(integer) -> integer * */ static VALUE ossl_sslctx_set_session_cache_mode(VALUE self, VALUE arg) { SSL_CTX *ctx; Data_Get_Struct(self, SSL_CTX, ctx); SSL_CTX_set_session_cache_mode(ctx, NUM2LONG(arg)); return arg; } /* * call-seq: * ctx.session_cache_size -> integer * */ static VALUE ossl_sslctx_get_session_cache_size(VALUE self) { SSL_CTX *ctx; Data_Get_Struct(self, SSL_CTX, ctx); return LONG2NUM(SSL_CTX_sess_get_cache_size(ctx)); } /* * call-seq: * ctx.session_cache_size=(integer) -> integer * */ static VALUE ossl_sslctx_set_session_cache_size(VALUE self, VALUE arg) { SSL_CTX *ctx; Data_Get_Struct(self, SSL_CTX, ctx); SSL_CTX_sess_set_cache_size(ctx, NUM2LONG(arg)); return arg; } /* * call-seq: * ctx.session_cache_stats -> Hash * */ static VALUE ossl_sslctx_get_session_cache_stats(VALUE self) { SSL_CTX *ctx; VALUE hash; Data_Get_Struct(self, SSL_CTX, ctx); hash = rb_hash_new(); rb_hash_aset(hash, ID2SYM(rb_intern("cache_num")), LONG2NUM(SSL_CTX_sess_number(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("connect")), LONG2NUM(SSL_CTX_sess_connect(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("connect_good")), LONG2NUM(SSL_CTX_sess_connect_good(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("connect_renegotiate")), LONG2NUM(SSL_CTX_sess_connect_renegotiate(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("accept")), LONG2NUM(SSL_CTX_sess_accept(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("accept_good")), LONG2NUM(SSL_CTX_sess_accept_good(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("accept_renegotiate")), LONG2NUM(SSL_CTX_sess_accept_renegotiate(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("cache_hits")), LONG2NUM(SSL_CTX_sess_hits(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("cb_hits")), LONG2NUM(SSL_CTX_sess_cb_hits(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("cache_misses")), LONG2NUM(SSL_CTX_sess_misses(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("cache_full")), LONG2NUM(SSL_CTX_sess_cache_full(ctx))); rb_hash_aset(hash, ID2SYM(rb_intern("timeouts")), LONG2NUM(SSL_CTX_sess_timeouts(ctx))); return hash; } /* * call-seq: * ctx.flush_sessions(time | nil) -> self * */ static VALUE ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self) { VALUE arg1; SSL_CTX *ctx; time_t tm = 0; int cb_state; rb_scan_args(argc, argv, "01", &arg1); Data_Get_Struct(self, SSL_CTX, ctx); if (NIL_P(arg1)) { tm = time(0); } else if (rb_obj_is_instance_of(arg1, rb_cTime)) { tm = NUM2LONG(rb_funcall(arg1, rb_intern("to_i"), 0)); } else { rb_raise(rb_eArgError, "arg must be Time or nil"); } SSL_CTX_flush_sessions(ctx, tm); return self; } /* * SSLSocket class */ static void ossl_ssl_shutdown(SSL *ssl) { if (ssl) { SSL_shutdown(ssl); SSL_clear(ssl); } } static void ossl_ssl_free(SSL *ssl) { ossl_ssl_shutdown(ssl); SSL_free(ssl); } static VALUE ossl_ssl_s_alloc(VALUE klass) { return Data_Wrap_Struct(klass, 0, ossl_ssl_free, NULL); } /* * call-seq: * SSLSocket.new(io) => aSSLSocket * SSLSocket.new(io, ctx) => aSSLSocket * * === Parameters * * +io+ is a real ruby IO object. Not an IO like object that responds to read/write. * * +ctx+ is an OpenSSLSSL::SSLContext. * * The OpenSSL::Buffering module provides additional IO methods. * * This method will freeze the SSLContext if one is provided; * however, session management is still allowed in the frozen SSLContext. */ static VALUE ossl_ssl_initialize(int argc, VALUE *argv, VALUE self) { VALUE io, ctx; if (rb_scan_args(argc, argv, "11", &io, &ctx) == 1) { ctx = rb_funcall(cSSLContext, rb_intern("new"), 0); } OSSL_Check_Kind(ctx, cSSLContext); Check_Type(io, T_FILE); ossl_ssl_set_io(self, io); ossl_ssl_set_ctx(self, ctx); ossl_ssl_set_sync_close(self, Qfalse); ossl_sslctx_setup(ctx); rb_call_super(0, 0); return self; } static VALUE ossl_ssl_setup(VALUE self) { VALUE io, v_ctx, cb; SSL_CTX *ctx; SSL *ssl; rb_io_t *fptr; Data_Get_Struct(self, SSL, ssl); if(!ssl){ v_ctx = ossl_ssl_get_ctx(self); Data_Get_Struct(v_ctx, SSL_CTX, ctx); ssl = SSL_new(ctx); if (!ssl) { ossl_raise(eSSLError, "SSL_new:"); } DATA_PTR(self) = ssl; io = ossl_ssl_get_io(self); GetOpenFile(io, fptr); rb_io_check_readable(fptr); rb_io_check_writable(fptr); SSL_set_fd(ssl, TO_SOCKET(FPTR_TO_FD(fptr))); SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void*)self); cb = ossl_sslctx_get_verify_cb(v_ctx); SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void*)cb); cb = ossl_sslctx_get_client_cert_cb(v_ctx); SSL_set_ex_data(ssl, ossl_ssl_ex_client_cert_cb_idx, (void*)cb); cb = ossl_sslctx_get_tmp_dh_cb(v_ctx); SSL_set_ex_data(ssl, ossl_ssl_ex_tmp_dh_callback_idx, (void*)cb); } return Qtrue; } #ifdef _WIN32 #define ssl_get_error(ssl, ret) (errno = WSAGetLastError(), SSL_get_error(ssl, ret)) #else #define ssl_get_error(ssl, ret) SSL_get_error(ssl, ret) #endif static VALUE ossl_start_ssl(VALUE self, int (*func)(), const char *funcname) { SSL *ssl; rb_io_t *fptr; int ret, ret2; VALUE cb_state; rb_ivar_set(self, ID_callback_state, Qnil); Data_Get_Struct(self, SSL, ssl); GetOpenFile(ossl_ssl_get_io(self), fptr); for(;;){ if((ret = func(ssl)) > 0) break; switch((ret2 = ssl_get_error(ssl, ret))){ case SSL_ERROR_WANT_WRITE: rb_io_wait_writable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_WANT_READ: rb_io_wait_readable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_SYSCALL: if (errno) rb_sys_fail(funcname); ossl_raise(eSSLError, "%s SYSCALL returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl)); default: ossl_raise(eSSLError, "%s returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl)); } } cb_state = rb_ivar_get(self, ID_callback_state); if (!NIL_P(cb_state)) rb_jump_tag(NUM2INT(cb_state)); return self; } /* * call-seq: * ssl.connect => self */ static VALUE ossl_ssl_connect(VALUE self) { ossl_ssl_setup(self); return ossl_start_ssl(self, SSL_connect, "SSL_connect"); } /* * call-seq: * ssl.accept => self */ static VALUE ossl_ssl_accept(VALUE self) { ossl_ssl_setup(self); return ossl_start_ssl(self, SSL_accept, "SSL_accept"); } /* * call-seq: * ssl.sysread(length) => string * ssl.sysread(length, buffer) => buffer * * === Parameters * * +length+ is a positive integer. * * +buffer+ is a string used to store the result. */ static VALUE ossl_ssl_read(int argc, VALUE *argv, VALUE self) { SSL *ssl; int ilen, nread = 0; VALUE len, str; rb_io_t *fptr; rb_scan_args(argc, argv, "11", &len, &str); ilen = NUM2INT(len); if(NIL_P(str)) str = rb_str_new(0, ilen); else{ StringValue(str); rb_str_modify(str); rb_str_resize(str, ilen); } if(ilen == 0) return str; Data_Get_Struct(self, SSL, ssl); GetOpenFile(ossl_ssl_get_io(self), fptr); if (ssl) { if(SSL_pending(ssl) <= 0) rb_thread_wait_fd(FPTR_TO_FD(fptr)); for (;;){ nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LEN(str)); switch(ssl_get_error(ssl, nread)){ case SSL_ERROR_NONE: goto end; case SSL_ERROR_ZERO_RETURN: rb_eof_error(); case SSL_ERROR_WANT_WRITE: rb_io_wait_writable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_WANT_READ: rb_io_wait_readable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_SYSCALL: if(ERR_peek_error() == 0 && nread == 0) rb_eof_error(); rb_sys_fail(0); default: ossl_raise(eSSLError, "SSL_read:"); } } } else { ID id_sysread = rb_intern("sysread"); rb_warning("SSL session is not started yet."); return rb_funcall(ossl_ssl_get_io(self), id_sysread, 2, len, str); } end: rb_str_set_len(str, nread); OBJ_TAINT(str); return str; } /* * call-seq: * ssl.syswrite(string) => integer */ static VALUE ossl_ssl_write(VALUE self, VALUE str) { SSL *ssl; int nwrite = 0; rb_io_t *fptr; StringValue(str); Data_Get_Struct(self, SSL, ssl); GetOpenFile(ossl_ssl_get_io(self), fptr); if (ssl) { for (;;){ nwrite = SSL_write(ssl, RSTRING_PTR(str), RSTRING_LEN(str)); switch(ssl_get_error(ssl, nwrite)){ case SSL_ERROR_NONE: goto end; case SSL_ERROR_WANT_WRITE: rb_io_wait_writable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_WANT_READ: rb_io_wait_readable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_SYSCALL: if (errno) rb_sys_fail(0); default: ossl_raise(eSSLError, "SSL_write:"); } } } else { ID id_syswrite = rb_intern("syswrite"); rb_warning("SSL session is not started yet."); return rb_funcall(ossl_ssl_get_io(self), id_syswrite, 1, str); } end: return INT2NUM(nwrite); } /* * call-seq: * ssl.sysclose => nil */ static VALUE ossl_ssl_close(VALUE self) { SSL *ssl; Data_Get_Struct(self, SSL, ssl); ossl_ssl_shutdown(ssl); if (RTEST(ossl_ssl_get_sync_close(self))) rb_funcall(ossl_ssl_get_io(self), rb_intern("close"), 0); return Qnil; } /* * call-seq: * ssl.cert => cert or nil */ static VALUE ossl_ssl_get_cert(VALUE self) { SSL *ssl; X509 *cert = NULL; Data_Get_Struct(self, SSL, ssl); if (ssl) { rb_warning("SSL session is not started yet."); return Qnil; } /* * Is this OpenSSL bug? Should add a ref? * TODO: Ask for. */ cert = SSL_get_certificate(ssl); /* NO DUPs => DON'T FREE. */ if (!cert) { return Qnil; } return ossl_x509_new(cert); } /* * call-seq: * ssl.peer_cert => cert or nil */ static VALUE ossl_ssl_get_peer_cert(VALUE self) { SSL *ssl; X509 *cert = NULL; VALUE obj; Data_Get_Struct(self, SSL, ssl); if (!ssl){ rb_warning("SSL session is not started yet."); return Qnil; } cert = SSL_get_peer_certificate(ssl); /* Adds a ref => Safe to FREE. */ if (!cert) { return Qnil; } obj = ossl_x509_new(cert); X509_free(cert); return obj; } /* * call-seq: * ssl.peer_cert_chain => [cert, ...] or nil */ static VALUE ossl_ssl_get_peer_cert_chain(VALUE self) { SSL *ssl; STACK_OF(X509) *chain; X509 *cert; VALUE ary; int i, num; Data_Get_Struct(self, SSL, ssl); if(!ssl){ rb_warning("SSL session is not started yet."); return Qnil; } chain = SSL_get_peer_cert_chain(ssl); if(!chain) return Qnil; num = sk_X509_num(chain); ary = rb_ary_new2(num); for (i = 0; i < num; i++){ cert = (X509*)sk_X509_value(chain, i); rb_ary_push(ary, ossl_x509_new(cert)); } return ary; } /* * call-seq: * ssl.cipher => [name, version, bits, alg_bits] */ static VALUE ossl_ssl_get_cipher(VALUE self) { SSL *ssl; OSSL_MORE_CONST SSL_CIPHER *cipher; Data_Get_Struct(self, SSL, ssl); if (!ssl) { rb_warning("SSL session is not started yet."); return Qnil; } cipher = SSL_get_current_cipher(ssl); return ossl_ssl_cipher_to_ary(cipher); } /* * call-seq: * ssl.state => string */ static VALUE ossl_ssl_get_state(VALUE self) { SSL *ssl; VALUE ret; Data_Get_Struct(self, SSL, ssl); if (!ssl) { rb_warning("SSL session is not started yet."); return Qnil; } ret = rb_str_new2(SSL_state_string(ssl)); if (ruby_verbose) { rb_str_cat2(ret, ": "); rb_str_cat2(ret, SSL_state_string_long(ssl)); } return ret; } /* * call-seq: * ssl.pending => integer */ static VALUE ossl_ssl_pending(VALUE self) { SSL *ssl; Data_Get_Struct(self, SSL, ssl); if (!ssl) { rb_warning("SSL session is not started yet."); return Qnil; } return INT2NUM(SSL_pending(ssl)); } /* * call-seq: * ssl.session_reused? -> true | false * */ static VALUE ossl_ssl_session_reused(VALUE self) { SSL *ssl; Data_Get_Struct(self, SSL, ssl); if (!ssl) { rb_warning("SSL session is not started yet."); return Qnil; } switch(SSL_session_reused(ssl)) { case 1: return Qtrue; case 0: return Qfalse; default: ossl_raise(eSSLError, "SSL_session_reused"); } } /* * call-seq: * ssl.session = session -> session * */ static VALUE ossl_ssl_set_session(VALUE self, VALUE arg1) { SSL *ssl; SSL_SESSION *sess; /* why is ossl_ssl_setup delayed? */ ossl_ssl_setup(self); Data_Get_Struct(self, SSL, ssl); if (!ssl) { rb_warning("SSL session is not started yet."); return Qnil; } SafeGetSSLSession(arg1, sess); if (SSL_set_session(ssl, sess) != 1) ossl_raise(eSSLError, "SSL_set_session"); return arg1; } static VALUE ossl_ssl_get_verify_result(VALUE self) { SSL *ssl; Data_Get_Struct(self, SSL, ssl); if (!ssl) { rb_warning("SSL session is not started yet."); return Qnil; } return INT2FIX(SSL_get_verify_result(ssl)); } void Init_ossl_ssl() { int i; VALUE ary; #if 0 /* let rdoc know about mOSSL */ mOSSL = rb_define_module("OpenSSL"); #endif ID_callback_state = rb_intern("@callback_state"); ossl_ssl_ex_vcb_idx = SSL_get_ex_new_index(0,"ossl_ssl_ex_vcb_idx",0,0,0); ossl_ssl_ex_store_p = SSL_get_ex_new_index(0,"ossl_ssl_ex_store_p",0,0,0); ossl_ssl_ex_ptr_idx = SSL_get_ex_new_index(0,"ossl_ssl_ex_ptr_idx",0,0,0); ossl_ssl_ex_client_cert_cb_idx = SSL_get_ex_new_index(0,"ossl_ssl_ex_client_cert_cb_idx",0,0,0); ossl_ssl_ex_tmp_dh_callback_idx = SSL_get_ex_new_index(0,"ossl_ssl_ex_tmp_dh_callback_idx",0,0,0); mSSL = rb_define_module_under(mOSSL, "SSL"); eSSLError = rb_define_class_under(mSSL, "SSLError", eOSSLError); Init_ossl_ssl_session(); /* class SSLContext * * The following attributes are available but don't show up in rdoc. * All attributes must be set before calling SSLSocket.new(io, ctx). * * ssl_version, cert, key, client_ca, ca_file, ca_path, timeout, * * verify_mode, verify_depth client_cert_cb, tmp_dh_callback, * * session_id_context, session_add_cb, session_new_cb, session_remove_cb */ cSSLContext = rb_define_class_under(mSSL, "SSLContext", rb_cObject); rb_define_alloc_func(cSSLContext, ossl_sslctx_s_alloc); for(i = 0; i < numberof(ossl_sslctx_attrs); i++) rb_attr(cSSLContext, rb_intern(ossl_sslctx_attrs[i]), 1, 1, Qfalse); rb_define_alias(cSSLContext, "ssl_timeout", "timeout"); rb_define_method(cSSLContext, "initialize", ossl_sslctx_initialize, -1); rb_define_method(cSSLContext, "ssl_version=", ossl_sslctx_set_ssl_version, 1); rb_define_method(cSSLContext, "ciphers", ossl_sslctx_get_ciphers, 0); rb_define_method(cSSLContext, "ciphers=", ossl_sslctx_set_ciphers, 1); rb_define_method(cSSLContext, "setup", ossl_sslctx_setup, 0); rb_define_const(cSSLContext, "SESSION_CACHE_OFF", LONG2FIX(SSL_SESS_CACHE_OFF)); rb_define_const(cSSLContext, "SESSION_CACHE_CLIENT", LONG2FIX(SSL_SESS_CACHE_CLIENT)); /* doesn't actually do anything in 0.9.8e */ rb_define_const(cSSLContext, "SESSION_CACHE_SERVER", LONG2FIX(SSL_SESS_CACHE_SERVER)); rb_define_const(cSSLContext, "SESSION_CACHE_BOTH", LONG2FIX(SSL_SESS_CACHE_BOTH)); /* no different than CACHE_SERVER in 0.9.8e */ rb_define_const(cSSLContext, "SESSION_CACHE_NO_AUTO_CLEAR", LONG2FIX(SSL_SESS_CACHE_NO_AUTO_CLEAR)); rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_LOOKUP", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)); rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_STORE", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_STORE)); rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL)); rb_define_method(cSSLContext, "session_add", ossl_sslctx_session_add, 1); rb_define_method(cSSLContext, "session_remove", ossl_sslctx_session_remove, 1); rb_define_method(cSSLContext, "session_cache_mode", ossl_sslctx_get_session_cache_mode, 0); rb_define_method(cSSLContext, "session_cache_mode=", ossl_sslctx_set_session_cache_mode, 1); rb_define_method(cSSLContext, "session_cache_size", ossl_sslctx_get_session_cache_size, 0); rb_define_method(cSSLContext, "session_cache_size=", ossl_sslctx_set_session_cache_size, 1); rb_define_method(cSSLContext, "session_cache_stats", ossl_sslctx_get_session_cache_stats, 0); rb_define_method(cSSLContext, "flush_sessions", ossl_sslctx_flush_sessions, -1); ary = rb_ary_new2(numberof(ossl_ssl_method_tab)); for (i = 0; i < numberof(ossl_ssl_method_tab); i++) { rb_ary_push(ary, ID2SYM(rb_intern(ossl_ssl_method_tab[i].name))); } rb_obj_freeze(ary); /* holds a list of available SSL/TLS methods */ rb_define_const(cSSLContext, "METHODS", ary); /* class SSLSocket * * The following attributes are available but don't show up in rdoc. * * io, context, sync_close * */ cSSLSocket = rb_define_class_under(mSSL, "SSLSocket", rb_cObject); rb_define_alloc_func(cSSLSocket, ossl_ssl_s_alloc); for(i = 0; i < numberof(ossl_ssl_attr_readers); i++) rb_attr(cSSLSocket, rb_intern(ossl_ssl_attr_readers[i]), 1, 0, Qfalse); for(i = 0; i < numberof(ossl_ssl_attrs); i++) rb_attr(cSSLSocket, rb_intern(ossl_ssl_attrs[i]), 1, 1, Qfalse); rb_define_alias(cSSLSocket, "to_io", "io"); rb_define_method(cSSLSocket, "initialize", ossl_ssl_initialize, -1); rb_define_method(cSSLSocket, "connect", ossl_ssl_connect, 0); rb_define_method(cSSLSocket, "accept", ossl_ssl_accept, 0); rb_define_method(cSSLSocket, "sysread", ossl_ssl_read, -1); rb_define_method(cSSLSocket, "syswrite", ossl_ssl_write, 1); rb_define_method(cSSLSocket, "sysclose", ossl_ssl_close, 0); rb_define_method(cSSLSocket, "cert", ossl_ssl_get_cert, 0); rb_define_method(cSSLSocket, "peer_cert", ossl_ssl_get_peer_cert, 0); rb_define_method(cSSLSocket, "peer_cert_chain", ossl_ssl_get_peer_cert_chain, 0); rb_define_method(cSSLSocket, "cipher", ossl_ssl_get_cipher, 0); rb_define_method(cSSLSocket, "state", ossl_ssl_get_state, 0); rb_define_method(cSSLSocket, "pending", ossl_ssl_pending, 0); rb_define_method(cSSLSocket, "session_reused?", ossl_ssl_session_reused, 0); rb_define_method(cSSLSocket, "session=", ossl_ssl_set_session, 1); rb_define_method(cSSLSocket, "verify_result", ossl_ssl_get_verify_result, 0); #define ossl_ssl_def_const(x) rb_define_const(mSSL, #x, INT2FIX(SSL_##x)) ossl_ssl_def_const(VERIFY_NONE); ossl_ssl_def_const(VERIFY_PEER); ossl_ssl_def_const(VERIFY_FAIL_IF_NO_PEER_CERT); ossl_ssl_def_const(VERIFY_CLIENT_ONCE); /* Not introduce constants included in OP_ALL such as... * ossl_ssl_def_const(OP_MICROSOFT_SESS_ID_BUG); * ossl_ssl_def_const(OP_NETSCAPE_CHALLENGE_BUG); * ossl_ssl_def_const(OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG); * ossl_ssl_def_const(OP_SSLREF2_REUSE_CERT_TYPE_BUG); * ossl_ssl_def_const(OP_MICROSOFT_BIG_SSLV3_BUFFER); * ossl_ssl_def_const(OP_MSIE_SSLV2_RSA_PADDING); * ossl_ssl_def_const(OP_SSLEAY_080_CLIENT_DH_BUG); * ossl_ssl_def_const(OP_TLS_D5_BUG); * ossl_ssl_def_const(OP_TLS_BLOCK_PADDING_BUG); * ossl_ssl_def_const(OP_DONT_INSERT_EMPTY_FRAGMENTS); */ ossl_ssl_def_const(OP_ALL); #if defined(SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION) ossl_ssl_def_const(OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); #endif #if defined(SSL_OP_SINGLE_ECDH_USE) ossl_ssl_def_const(OP_SINGLE_ECDH_USE); #endif ossl_ssl_def_const(OP_SINGLE_DH_USE); ossl_ssl_def_const(OP_EPHEMERAL_RSA); #if defined(SSL_OP_CIPHER_SERVER_PREFERENCE) ossl_ssl_def_const(OP_CIPHER_SERVER_PREFERENCE); #endif ossl_ssl_def_const(OP_TLS_ROLLBACK_BUG); ossl_ssl_def_const(OP_NO_SSLv2); ossl_ssl_def_const(OP_NO_SSLv3); ossl_ssl_def_const(OP_NO_TLSv1); #if defined(SSL_OP_NO_TICKET) ossl_ssl_def_const(OP_NO_TICKET); #endif ossl_ssl_def_const(OP_PKCS1_CHECK_1); ossl_ssl_def_const(OP_PKCS1_CHECK_2); ossl_ssl_def_const(OP_NETSCAPE_CA_DN_BUG); ossl_ssl_def_const(OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG); } ================================================ FILE: ext/openssl/ossl_ssl.h ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(_OSSL_SSL_H_) #define _OSSL_SSL_H_ #define GetSSLSession(obj, sess) do { \ Data_Get_Struct(obj, SSL_SESSION, sess); \ if (!sess) { \ ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \ } \ } while (0) #define SafeGetSSLSession(obj, sess) do { \ OSSL_Check_Kind(obj, cSSLSession); \ GetSSLSession(obj, sess); \ } while (0) extern VALUE mSSL; extern VALUE eSSLError; extern VALUE cSSLSocket; extern VALUE cSSLContext; extern VALUE cSSLSession; void Init_ossl_ssl(void); void Init_ossl_ssl_session(void); #endif /* _OSSL_SSL_H_ */ ================================================ FILE: ext/openssl/ossl_ssl_session.c ================================================ /* * Copyright (C) 2004-2007 Technorama Ltd. */ #include "ossl.h" #define GetSSLSession(obj, sess) do { \ Data_Get_Struct(obj, SSL_SESSION, sess); \ if (!sess) { \ ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \ } \ } while (0) #define SafeGetSSLSession(obj, sess) do { \ OSSL_Check_Kind(obj, cSSLSession); \ GetSSLSession(obj, sess); \ } while (0) VALUE cSSLSession; static VALUE eSSLSession; static VALUE ossl_ssl_session_alloc(VALUE klass) { return Data_Wrap_Struct(klass, 0, SSL_SESSION_free, NULL); } /* * call-seq: * Session.new(SSLSocket | string) => session * * === Parameters * +SSLSocket+ is an OpenSSL::SSL::SSLSocket * +string+ must be a DER or PEM encoded Session. */ static VALUE ossl_ssl_session_initialize(VALUE self, VALUE arg1) { SSL_SESSION *ctx = NULL; VALUE obj; unsigned char *p; if (RDATA(self)->data) ossl_raise(eSSLSession, "SSL Session already initialized"); if (rb_obj_is_instance_of(arg1, cSSLSocket)) { SSL *ssl; Data_Get_Struct(arg1, SSL, ssl); if (!ssl || (ctx = SSL_get1_session(ssl)) == NULL) ossl_raise(eSSLSession, "no session available"); } else { BIO *in = ossl_obj2bio(arg1); ctx = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL); if (!ctx) { BIO_reset(in); ctx = d2i_SSL_SESSION_bio(in, NULL); } BIO_free(in); if (!ctx) ossl_raise(rb_eArgError, "unknown type"); } /* should not happen */ if (ctx == NULL) ossl_raise(eSSLSession, "ctx not set - internal error"); RDATA(self)->data = ctx; return self; } /* * call-seq: * session1 == session2 -> boolean * */ static VALUE ossl_ssl_session_eq(VALUE val1, VALUE val2) { SSL_SESSION *ctx1, *ctx2; GetSSLSession(val1, ctx1); SafeGetSSLSession(val2, ctx2); switch (SSL_SESSION_cmp(ctx1, ctx2)) { case 0: return Qtrue; default: return Qfalse; } } /* * call-seq: * session.time -> Time * */ static VALUE ossl_ssl_session_get_time(VALUE self) { SSL_SESSION *ctx; time_t t; GetSSLSession(self, ctx); t = SSL_SESSION_get_time(ctx); if (t == 0) return Qnil; return rb_funcall(rb_cTime, rb_intern("at"), 1, LONG2NUM(t)); } /* * call-seq: * session.timeout -> integer * * How long until the session expires in seconds. * */ static VALUE ossl_ssl_session_get_timeout(VALUE self) { SSL_SESSION *ctx; time_t t; GetSSLSession(self, ctx); t = SSL_SESSION_get_timeout(ctx); return ULONG2NUM(t); } #define SSLSESSION_SET_TIME(func) \ static VALUE ossl_ssl_session_set_##func(VALUE self, VALUE time_v) \ { \ SSL_SESSION *ctx; \ time_t t; \ \ GetSSLSession(self, ctx); \ \ if (rb_obj_is_instance_of(time_v, rb_cTime)) { \ time_v = rb_funcall(time_v, rb_intern("to_i"), 0); \ } else if (FIXNUM_P(time_v)) { \ ; \ } else { \ rb_raise(rb_eArgError, "unknown type"); \ } \ \ t = NUM2ULONG(time_v); \ \ SSL_SESSION_set_##func(ctx, t); \ \ return ossl_ssl_session_get_##func(self); \ } SSLSESSION_SET_TIME(time) SSLSESSION_SET_TIME(timeout) #ifdef HAVE_SSL_SESSION_GET_ID /* * call-seq: * session.id -> aString * * Returns the Session ID. */ static VALUE ossl_ssl_session_get_id(VALUE self) { SSL_SESSION *ctx; const unsigned char *p = NULL; unsigned int i = 0; GetSSLSession(self, ctx); p = SSL_SESSION_get_id(ctx, &i); return rb_str_new((const char *) p, i); } #endif /* * call-seq: * session.to_der -> aString * * Returns an ASN1 encoded String that contains the Session object. */ static VALUE ossl_ssl_session_to_der(VALUE self) { SSL_SESSION *ctx; unsigned char buf[1024*10], *p; int len; GetSSLSession(self, ctx); p = buf; len = i2d_SSL_SESSION(ctx, &p); if (len <= 0) ossl_raise(eSSLSession, "i2d_SSL_SESSION"); else if (len >= sizeof(buf)) ossl_raise(eSSLSession, "i2d_SSL_SESSION too large"); return rb_str_new((const char *) p, len); } /* * call-seq: * session.to_pem -> String * * Returns a PEM encoded String that contains the Session object. */ static VALUE ossl_ssl_session_to_pem(VALUE self) { SSL_SESSION *ctx; BIO *out; BUF_MEM *buf; VALUE str; int i; GetSSLSession(self, ctx); if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eSSLSession, "BIO_s_mem()"); } if (!(i=PEM_write_bio_SSL_SESSION(out, ctx))) { BIO_free(out); ossl_raise(eSSLSession, "SSL_SESSION_print()"); } BIO_get_mem_ptr(out, &buf); str = rb_str_new(buf->data, buf->length); BIO_free(out); return str; } /* * call-seq: * session.to_text -> String * * Shows everything in the Session object. */ static VALUE ossl_ssl_session_to_text(VALUE self) { SSL_SESSION *ctx; BIO *out; BUF_MEM *buf; VALUE str; GetSSLSession(self, ctx); if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eSSLSession, "BIO_s_mem()"); } if (!SSL_SESSION_print(out, ctx)) { BIO_free(out); ossl_raise(eSSLSession, "SSL_SESSION_print()"); } BIO_get_mem_ptr(out, &buf); str = rb_str_new(buf->data, buf->length); BIO_free(out); return str; } void Init_ossl_ssl_session(void) { #if 0 /* let rdoc know about mOSSL */ mOSSL = rb_define_module("OpenSSL"); mSSL = rb_define_module_under(mOSSL, "SSL"); #endif cSSLSession = rb_define_class_under(mSSL, "Session", rb_cObject); eSSLSession = rb_define_class_under(cSSLSession, "SessionError", eOSSLError); rb_define_alloc_func(cSSLSession, ossl_ssl_session_alloc); rb_define_method(cSSLSession, "initialize", ossl_ssl_session_initialize, 1); rb_define_method(cSSLSession, "==", ossl_ssl_session_eq, 1); rb_define_method(cSSLSession, "time", ossl_ssl_session_get_time, 0); rb_define_method(cSSLSession, "time=", ossl_ssl_session_set_time, 1); rb_define_method(cSSLSession, "timeout", ossl_ssl_session_get_timeout, 0); rb_define_method(cSSLSession, "timeout=", ossl_ssl_session_set_timeout, 1); #ifdef HAVE_SSL_SESSION_GET_ID rb_define_method(cSSLSession, "id", ossl_ssl_session_get_id, 0); #else rb_undef_method(cSSLSession, "id"); #endif rb_define_method(cSSLSession, "to_der", ossl_ssl_session_to_der, 0); rb_define_method(cSSLSession, "to_pem", ossl_ssl_session_to_pem, 0); rb_define_method(cSSLSession, "to_text", ossl_ssl_session_to_text, 0); } ================================================ FILE: ext/openssl/ossl_version.h ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(_OSSL_VERSION_H_) #define _OSSL_VERSION_H_ #define OSSL_VERSION "1.0.0" #endif /* _OSSL_VERSION_H_ */ ================================================ FILE: ext/openssl/ossl_x509.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" VALUE mX509; #define DefX509Const(x) rb_define_const(mX509, #x,INT2FIX(X509_##x)) #define DefX509Default(x,i) \ rb_define_const(mX509, "DEFAULT_" #x, rb_str_new2(X509_get_default_##i())) void Init_ossl_x509() { mX509 = rb_define_module_under(mOSSL, "X509"); Init_ossl_x509attr(); Init_ossl_x509cert(); Init_ossl_x509crl(); Init_ossl_x509ext(); Init_ossl_x509name(); Init_ossl_x509req(); Init_ossl_x509revoked(); Init_ossl_x509store(); DefX509Const(V_OK); DefX509Const(V_ERR_UNABLE_TO_GET_ISSUER_CERT); DefX509Const(V_ERR_UNABLE_TO_GET_CRL); DefX509Const(V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE); DefX509Const(V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE); DefX509Const(V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY); DefX509Const(V_ERR_CERT_SIGNATURE_FAILURE); DefX509Const(V_ERR_CRL_SIGNATURE_FAILURE); DefX509Const(V_ERR_CERT_NOT_YET_VALID); DefX509Const(V_ERR_CERT_HAS_EXPIRED); DefX509Const(V_ERR_CRL_NOT_YET_VALID); DefX509Const(V_ERR_CRL_HAS_EXPIRED); DefX509Const(V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD); DefX509Const(V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD); DefX509Const(V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD); DefX509Const(V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); DefX509Const(V_ERR_OUT_OF_MEM); DefX509Const(V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT); DefX509Const(V_ERR_SELF_SIGNED_CERT_IN_CHAIN); DefX509Const(V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY); DefX509Const(V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE); DefX509Const(V_ERR_CERT_CHAIN_TOO_LONG); DefX509Const(V_ERR_CERT_REVOKED); DefX509Const(V_ERR_INVALID_CA); DefX509Const(V_ERR_PATH_LENGTH_EXCEEDED); DefX509Const(V_ERR_INVALID_PURPOSE); DefX509Const(V_ERR_CERT_UNTRUSTED); DefX509Const(V_ERR_CERT_REJECTED); DefX509Const(V_ERR_SUBJECT_ISSUER_MISMATCH); DefX509Const(V_ERR_AKID_SKID_MISMATCH); DefX509Const(V_ERR_AKID_ISSUER_SERIAL_MISMATCH); DefX509Const(V_ERR_KEYUSAGE_NO_CERTSIGN); DefX509Const(V_ERR_APPLICATION_VERIFICATION); #if defined(X509_V_FLAG_CRL_CHECK) DefX509Const(V_FLAG_CRL_CHECK); #endif #if defined(X509_V_FLAG_CRL_CHECK_ALL) DefX509Const(V_FLAG_CRL_CHECK_ALL); #endif DefX509Const(PURPOSE_SSL_CLIENT); DefX509Const(PURPOSE_SSL_SERVER); DefX509Const(PURPOSE_NS_SSL_SERVER); DefX509Const(PURPOSE_SMIME_SIGN); DefX509Const(PURPOSE_SMIME_ENCRYPT); DefX509Const(PURPOSE_CRL_SIGN); DefX509Const(PURPOSE_ANY); #if defined(X509_PURPOSE_OCSP_HELPER) DefX509Const(PURPOSE_OCSP_HELPER); #endif DefX509Const(TRUST_COMPAT); DefX509Const(TRUST_SSL_CLIENT); DefX509Const(TRUST_SSL_SERVER); DefX509Const(TRUST_EMAIL); DefX509Const(TRUST_OBJECT_SIGN); #if defined(X509_TRUST_OCSP_SIGN) DefX509Const(TRUST_OCSP_SIGN); #endif #if defined(X509_TRUST_OCSP_REQUEST) DefX509Const(TRUST_OCSP_REQUEST); #endif DefX509Default(CERT_AREA, cert_area); DefX509Default(CERT_DIR, cert_dir); DefX509Default(CERT_FILE, cert_file); DefX509Default(CERT_DIR_ENV, cert_dir_env); DefX509Default(CERT_FILE_ENV, cert_file_env); DefX509Default(PRIVATE_DIR, private_dir); } ================================================ FILE: ext/openssl/ossl_x509.h ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(_OSSL_X509_H_) #define _OSSL_X509_H_ /* * X509 main module */ extern VALUE mX509; void Init_ossl_x509(void); /* * X509Attr */ extern VALUE cX509Attr; extern VALUE eX509AttrError; VALUE ossl_x509attr_new(X509_ATTRIBUTE *); X509_ATTRIBUTE *DupX509AttrPtr(VALUE); void Init_ossl_x509attr(void); /* * X509Cert */ extern VALUE cX509Cert; extern VALUE eX509CertError; VALUE ossl_x509_new(X509 *); VALUE ossl_x509_new_from_file(VALUE); X509 *GetX509CertPtr(VALUE); X509 *DupX509CertPtr(VALUE); void Init_ossl_x509cert(void); /* * X509CRL */ extern VALUE cX509CRL; extern VALUE eX509CRLError; VALUE ossl_x509crl_new(X509_CRL *); X509_CRL *GetX509CRLPtr(VALUE); X509_CRL *DupX509CRLPtr(VALUE); void Init_ossl_x509crl(void); /* * X509Extension */ extern VALUE cX509Ext; extern VALUE cX509ExtFactory; extern VALUE eX509ExtError; VALUE ossl_x509ext_new(X509_EXTENSION *); X509_EXTENSION *GetX509ExtPtr(VALUE); X509_EXTENSION *DupX509ExtPtr(VALUE); void Init_ossl_x509ext(void); /* * X509Name */ extern VALUE cX509Name; extern VALUE eX509NameError; VALUE ossl_x509name_new(X509_NAME *); X509_NAME *GetX509NamePtr(VALUE); void Init_ossl_x509name(void); /* * X509Request */ extern VALUE cX509Req; extern VALUE eX509ReqError; VALUE ossl_x509req_new(X509_REQ *); X509_REQ *GetX509ReqPtr(VALUE); X509_REQ *DupX509ReqPtr(VALUE); void Init_ossl_x509req(void); /* * X509Revoked */ extern VALUE cX509Rev; extern VALUE eX509RevError; VALUE ossl_x509revoked_new(X509_REVOKED *); X509_REVOKED *DupX509RevokedPtr(VALUE); void Init_ossl_x509revoked(void); /* * X509Store and X509StoreContext */ extern VALUE cX509Store; extern VALUE cX509StoreContext; extern VALUE eX509StoreError; VALUE ossl_x509store_new(X509_STORE *); X509_STORE *GetX509StorePtr(VALUE); X509_STORE *DupX509StorePtr(VALUE); VALUE ossl_x509stctx_new(X509_STORE_CTX *); VALUE ossl_x509stctx_clear_ptr(VALUE); X509_STORE_CTX *GetX509StCtxtPtr(VALUE); void Init_ossl_x509store(void); #endif /* _OSSL_X509_H_ */ ================================================ FILE: ext/openssl/ossl_x509attr.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" #define WrapX509Attr(klass, obj, attr) do { \ if (!attr) { \ ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \ } \ obj = Data_Wrap_Struct(klass, 0, X509_ATTRIBUTE_free, attr); \ } while (0) #define GetX509Attr(obj, attr) do { \ Data_Get_Struct(obj, X509_ATTRIBUTE, attr); \ if (!attr) { \ ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \ } \ } while (0) #define SafeGetX509Attr(obj, attr) do { \ OSSL_Check_Kind(obj, cX509Attr); \ GetX509Attr(obj, attr); \ } while (0) /* * Classes */ VALUE cX509Attr; VALUE eX509AttrError; /* * Public */ VALUE ossl_x509attr_new(X509_ATTRIBUTE *attr) { X509_ATTRIBUTE *new; VALUE obj; if (!attr) { new = X509_ATTRIBUTE_new(); } else { new = X509_ATTRIBUTE_dup(attr); } if (!new) { ossl_raise(eX509AttrError, NULL); } WrapX509Attr(cX509Attr, obj, new); return obj; } X509_ATTRIBUTE * DupX509AttrPtr(VALUE obj) { X509_ATTRIBUTE *attr, *new; SafeGetX509Attr(obj, attr); if (!(new = X509_ATTRIBUTE_dup(attr))) { ossl_raise(eX509AttrError, NULL); } return new; } /* * Private */ static VALUE ossl_x509attr_alloc(VALUE klass) { X509_ATTRIBUTE *attr; VALUE obj; if (!(attr = X509_ATTRIBUTE_new())) ossl_raise(eX509AttrError, NULL); WrapX509Attr(klass, obj, attr); return obj; } /* * call-seq: * Attribute.new(oid [, value]) => attr */ static VALUE ossl_x509attr_initialize(int argc, VALUE *argv, VALUE self) { VALUE oid, value; X509_ATTRIBUTE *attr; OSSL_MORE_CONST unsigned char *p; GetX509Attr(self, attr); if(rb_scan_args(argc, argv, "11", &oid, &value) == 1){ oid = ossl_to_der_if_possible(oid); StringValue(oid); p = RSTRING_PTR(oid); if(!d2i_X509_ATTRIBUTE((X509_ATTRIBUTE**)&DATA_PTR(self), &p, RSTRING_LEN(oid))){ ossl_raise(eX509AttrError, NULL); } return self; } rb_funcall(self, rb_intern("oid="), 1, oid); rb_funcall(self, rb_intern("value="), 1, value); return self; } /* * call-seq: * attr.oid = string => string */ static VALUE ossl_x509attr_set_oid(VALUE self, VALUE oid) { X509_ATTRIBUTE *attr; ASN1_OBJECT *obj; char *s; s = StringValuePtr(oid); obj = OBJ_txt2obj(s, 0); if(!obj) obj = OBJ_txt2obj(s, 1); if(!obj) ossl_raise(eX509AttrError, NULL); GetX509Attr(self, attr); X509_ATTRIBUTE_set1_object(attr, obj); return oid; } /* * call-seq: * attr.oid => string */ static VALUE ossl_x509attr_get_oid(VALUE self) { X509_ATTRIBUTE *attr; ASN1_OBJECT *oid; BIO *out; VALUE ret; int nid; GetX509Attr(self, attr); oid = X509_ATTRIBUTE_get0_object(attr); if ((nid = OBJ_obj2nid(oid)) != NID_undef) ret = rb_str_new2(OBJ_nid2sn(nid)); else{ if (!(out = BIO_new(BIO_s_mem()))) ossl_raise(eX509AttrError, NULL); i2a_ASN1_OBJECT(out, oid); ret = ossl_membio2str(out); } return ret; } #if defined(HAVE_ST_X509_ATTRIBUTE_SINGLE) || defined(HAVE_ST_SINGLE) # define OSSL_X509ATTR_IS_SINGLE(attr) ((attr)->single) # define OSSL_X509ATTR_SET_SINGLE(attr) ((attr)->single = 1) #else # define OSSL_X509ATTR_IS_SINGLE(attr) (!(attr)->set) # define OSSL_X509ATTR_SET_SINGLE(attr) ((attr)->set = 0) #endif /* * call-seq: * attr.value = asn1 => asn1 */ static VALUE ossl_x509attr_set_value(VALUE self, VALUE value) { X509_ATTRIBUTE *attr; ASN1_TYPE *a1type; if(!(a1type = ossl_asn1_get_asn1type(value))) ossl_raise(eASN1Error, "could not get ASN1_TYPE"); if(ASN1_TYPE_get(a1type) == V_ASN1_SEQUENCE){ ASN1_TYPE_free(a1type); ossl_raise(eASN1Error, "couldn't set SEQUENCE for attribute value."); } GetX509Attr(self, attr); if(attr->value.set){ if(OSSL_X509ATTR_IS_SINGLE(attr)) ASN1_TYPE_free(attr->value.single); else sk_ASN1_TYPE_free(attr->value.set); } OSSL_X509ATTR_SET_SINGLE(attr); attr->value.single = a1type; return value; } /* * call-seq: * attr.value => asn1 */ static VALUE ossl_x509attr_get_value(VALUE self) { X509_ATTRIBUTE *attr; VALUE str, asn1; long length; unsigned char *p; GetX509Attr(self, attr); if(attr->value.ptr == NULL) return Qnil; if(OSSL_X509ATTR_IS_SINGLE(attr)){ length = i2d_ASN1_TYPE(attr->value.single, NULL); str = rb_str_new(0, length); p = RSTRING_PTR(str); i2d_ASN1_TYPE(attr->value.single, &p); ossl_str_adjust(str, p); } else{ length = i2d_ASN1_SET_OF_ASN1_TYPE(attr->value.set, (unsigned char **) NULL, i2d_ASN1_TYPE, V_ASN1_SET, V_ASN1_UNIVERSAL, 0); str = rb_str_new(0, length); p = RSTRING_PTR(str); i2d_ASN1_SET_OF_ASN1_TYPE(attr->value.set, &p, i2d_ASN1_TYPE, V_ASN1_SET, V_ASN1_UNIVERSAL, 0); ossl_str_adjust(str, p); } asn1 = rb_funcall(mASN1, rb_intern("decode"), 1, str); return asn1; } /* * call-seq: * attr.to_der => string */ static VALUE ossl_x509attr_to_der(VALUE self) { X509_ATTRIBUTE *attr; VALUE str; int len; unsigned char *p; GetX509Attr(self, attr); if((len = i2d_X509_ATTRIBUTE(attr, NULL)) <= 0) ossl_raise(eX509AttrError, NULL); str = rb_str_new(0, len); p = RSTRING_PTR(str); if(i2d_X509_ATTRIBUTE(attr, &p) <= 0) ossl_raise(eX509AttrError, NULL); rb_str_set_len(str, p - (unsigned char*)RSTRING_PTR(str)); return str; } /* * X509_ATTRIBUTE init */ void Init_ossl_x509attr() { eX509AttrError = rb_define_class_under(mX509, "AttributeError", eOSSLError); cX509Attr = rb_define_class_under(mX509, "Attribute", rb_cObject); rb_define_alloc_func(cX509Attr, ossl_x509attr_alloc); rb_define_method(cX509Attr, "initialize", ossl_x509attr_initialize, -1); rb_define_method(cX509Attr, "oid=", ossl_x509attr_set_oid, 1); rb_define_method(cX509Attr, "oid", ossl_x509attr_get_oid, 0); rb_define_method(cX509Attr, "value=", ossl_x509attr_set_value, 1); rb_define_method(cX509Attr, "value", ossl_x509attr_get_value, 0); rb_define_method(cX509Attr, "to_der", ossl_x509attr_to_der, 0); } ================================================ FILE: ext/openssl/ossl_x509cert.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" #define WrapX509(klass, obj, x509) do { \ if (!x509) { \ ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \ } \ obj = Data_Wrap_Struct(klass, 0, X509_free, x509); \ } while (0) #define GetX509(obj, x509) do { \ Data_Get_Struct(obj, X509, x509); \ if (!x509) { \ ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \ } \ } while (0) #define SafeGetX509(obj, x509) do { \ OSSL_Check_Kind(obj, cX509Cert); \ GetX509(obj, x509); \ } while (0) /* * Classes */ VALUE cX509Cert; VALUE eX509CertError; /* * Public */ VALUE ossl_x509_new(X509 *x509) { X509 *new; VALUE obj; if (!x509) { new = X509_new(); } else { new = X509_dup(x509); } if (!new) { ossl_raise(eX509CertError, NULL); } WrapX509(cX509Cert, obj, new); return obj; } VALUE ossl_x509_new_from_file(VALUE filename) { X509 *x509; FILE *fp; VALUE obj; SafeStringValue(filename); if (!(fp = fopen(RSTRING_PTR(filename), "r"))) { ossl_raise(eX509CertError, "%s", strerror(errno)); } x509 = PEM_read_X509(fp, NULL, NULL, NULL); /* * prepare for DER... #if !defined(OPENSSL_NO_FP_API) if (!x509) { rewind(fp); x509 = d2i_X509_fp(fp, NULL); } #endif */ fclose(fp); if (!x509) { ossl_raise(eX509CertError, NULL); } WrapX509(cX509Cert, obj, x509); return obj; } X509 * GetX509CertPtr(VALUE obj) { X509 *x509; SafeGetX509(obj, x509); return x509; } X509 * DupX509CertPtr(VALUE obj) { X509 *x509; SafeGetX509(obj, x509); CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509); return x509; } /* * Private */ static VALUE ossl_x509_alloc(VALUE klass) { X509 *x509; VALUE obj; x509 = X509_new(); if (!x509) ossl_raise(eX509CertError, NULL); WrapX509(klass, obj, x509); return obj; } /* * call-seq: * Certificate.new => cert * Certificate.new(string) => cert */ static VALUE ossl_x509_initialize(int argc, VALUE *argv, VALUE self) { BIO *in; X509 *x509; VALUE arg; if (rb_scan_args(argc, argv, "01", &arg) == 0) { /* create just empty X509Cert */ return self; } arg = ossl_to_der_if_possible(arg); in = ossl_obj2bio(arg); x509 = PEM_read_bio_X509(in, (X509 **)&DATA_PTR(self), NULL, NULL); if (!x509) { BIO_reset(in); x509 = d2i_X509_bio(in, (X509 **)&DATA_PTR(self)); } BIO_free(in); if (!x509) ossl_raise(eX509CertError, NULL); return self; } static VALUE ossl_x509_copy(VALUE self, VALUE other) { X509 *a, *b, *x509; rb_check_frozen(self); if (self == other) return self; GetX509(self, a); SafeGetX509(other, b); x509 = X509_dup(b); if (!x509) ossl_raise(eX509CertError, NULL); DATA_PTR(self) = x509; X509_free(a); return self; } /* * call-seq: * cert.to_der => string */ static VALUE ossl_x509_to_der(VALUE self) { X509 *x509; VALUE str; long len; unsigned char *p; GetX509(self, x509); if ((len = i2d_X509(x509, NULL)) <= 0) ossl_raise(eX509CertError, NULL); str = rb_str_new(0, len); p = RSTRING_PTR(str); if (i2d_X509(x509, &p) <= 0) ossl_raise(eX509CertError, NULL); ossl_str_adjust(str, p); return str; } /* * call-seq: * cert.to_pem => string */ static VALUE ossl_x509_to_pem(VALUE self) { X509 *x509; BIO *out; VALUE str; GetX509(self, x509); out = BIO_new(BIO_s_mem()); if (!out) ossl_raise(eX509CertError, NULL); if (!PEM_write_bio_X509(out, x509)) { BIO_free(out); ossl_raise(eX509CertError, NULL); } str = ossl_membio2str(out); return str; } /* * call-seq: * cert.to_text => string */ static VALUE ossl_x509_to_text(VALUE self) { X509 *x509; BIO *out; VALUE str; GetX509(self, x509); out = BIO_new(BIO_s_mem()); if (!out) ossl_raise(eX509CertError, NULL); if (!X509_print(out, x509)) { BIO_free(out); ossl_raise(eX509CertError, NULL); } str = ossl_membio2str(out); return str; } #if 0 /* * Makes from X509 X509_REQuest */ static VALUE ossl_x509_to_req(VALUE self) { X509 *x509; X509_REQ *req; VALUE obj; GetX509(self, x509); if (!(req = X509_to_X509_REQ(x509, NULL, EVP_md5()))) { ossl_raise(eX509CertError, NULL); } obj = ossl_x509req_new(req); X509_REQ_free(req); return obj; } #endif /* * call-seq: * cert.version => integer */ static VALUE ossl_x509_get_version(VALUE self) { X509 *x509; GetX509(self, x509); return LONG2NUM(X509_get_version(x509)); } /* * call-seq: * cert.version = integer => integer */ static VALUE ossl_x509_set_version(VALUE self, VALUE version) { X509 *x509; long ver; if ((ver = NUM2LONG(version)) < 0) { ossl_raise(eX509CertError, "version must be >= 0!"); } GetX509(self, x509); if (!X509_set_version(x509, ver)) { ossl_raise(eX509CertError, NULL); } return version; } /* * call-seq: * cert.serial => integer */ static VALUE ossl_x509_get_serial(VALUE self) { X509 *x509; GetX509(self, x509); return asn1integer_to_num(X509_get_serialNumber(x509)); } /* * call-seq: * cert.serial = integer => integer */ static VALUE ossl_x509_set_serial(VALUE self, VALUE num) { X509 *x509; GetX509(self, x509); x509->cert_info->serialNumber = num_to_asn1integer(num, X509_get_serialNumber(x509)); return num; } /* * call-seq: * cert.signature_algorithm => string */ static VALUE ossl_x509_get_signature_algorithm(VALUE self) { X509 *x509; BIO *out; VALUE str; GetX509(self, x509); out = BIO_new(BIO_s_mem()); if (!out) ossl_raise(eX509CertError, NULL); if (!i2a_ASN1_OBJECT(out, x509->cert_info->signature->algorithm)) { BIO_free(out); ossl_raise(eX509CertError, NULL); } str = ossl_membio2str(out); return str; } /* * call-seq: * cert.subject => name */ static VALUE ossl_x509_get_subject(VALUE self) { X509 *x509; X509_NAME *name; GetX509(self, x509); if (!(name = X509_get_subject_name(x509))) { /* NO DUP - don't free! */ ossl_raise(eX509CertError, NULL); } return ossl_x509name_new(name); } /* * call-seq: * cert.subject = name => name */ static VALUE ossl_x509_set_subject(VALUE self, VALUE subject) { X509 *x509; GetX509(self, x509); if (!X509_set_subject_name(x509, GetX509NamePtr(subject))) { /* DUPs name */ ossl_raise(eX509CertError, NULL); } return subject; } /* * call-seq: * cert.issuer => name */ static VALUE ossl_x509_get_issuer(VALUE self) { X509 *x509; X509_NAME *name; GetX509(self, x509); if(!(name = X509_get_issuer_name(x509))) { /* NO DUP - don't free! */ ossl_raise(eX509CertError, NULL); } return ossl_x509name_new(name); } /* * call-seq: * cert.issuer = name => name */ static VALUE ossl_x509_set_issuer(VALUE self, VALUE issuer) { X509 *x509; GetX509(self, x509); if (!X509_set_issuer_name(x509, GetX509NamePtr(issuer))) { /* DUPs name */ ossl_raise(eX509CertError, NULL); } return issuer; } /* * call-seq: * cert.not_before => time */ static VALUE ossl_x509_get_not_before(VALUE self) { X509 *x509; ASN1_UTCTIME *asn1time; GetX509(self, x509); if (!(asn1time = X509_get_notBefore(x509))) { /* NO DUP - don't free! */ ossl_raise(eX509CertError, NULL); } return asn1time_to_time(asn1time); } /* * call-seq: * cert.not_before = time => time */ static VALUE ossl_x509_set_not_before(VALUE self, VALUE time) { X509 *x509; time_t sec; sec = time_to_time_t(time); GetX509(self, x509); if (!X509_time_adj(X509_get_notBefore(x509), 0, &sec)) { ossl_raise(eX509CertError, NULL); } return time; } /* * call-seq: * cert.not_after => time */ static VALUE ossl_x509_get_not_after(VALUE self) { X509 *x509; ASN1_TIME *asn1time; GetX509(self, x509); if (!(asn1time = X509_get_notAfter(x509))) { /* NO DUP - don't free! */ ossl_raise(eX509CertError, NULL); } return asn1time_to_time(asn1time); } /* * call-seq: * cert.not_before = time => time */ static VALUE ossl_x509_set_not_after(VALUE self, VALUE time) { X509 *x509; time_t sec; sec = time_to_time_t(time); GetX509(self, x509); if (!X509_time_adj(X509_get_notAfter(x509), 0, &sec)) { ossl_raise(eX509CertError, NULL); } return time; } /* * call-seq: * cert.public_key => key */ static VALUE ossl_x509_get_public_key(VALUE self) { X509 *x509; EVP_PKEY *pkey; GetX509(self, x509); if (!(pkey = X509_get_pubkey(x509))) { /* adds an reference */ ossl_raise(eX509CertError, NULL); } return ossl_pkey_new(pkey); /* NO DUP - OK */ } /* * call-seq: * cert.public_key = key => key */ static VALUE ossl_x509_set_public_key(VALUE self, VALUE key) { X509 *x509; GetX509(self, x509); if (!X509_set_pubkey(x509, GetPKeyPtr(key))) { /* DUPs pkey */ ossl_raise(eX509CertError, NULL); } return key; } /* * call-seq: * cert.sign(key, digest) => self */ static VALUE ossl_x509_sign(VALUE self, VALUE key, VALUE digest) { X509 *x509; EVP_PKEY *pkey; const EVP_MD *md; pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ md = GetDigestPtr(digest); GetX509(self, x509); if (!X509_sign(x509, pkey, md)) { ossl_raise(eX509CertError, NULL); } return self; } /* * call-seq: * cert.verify(key) => true | false * * Checks that cert signature is made with PRIVversion of this PUBLIC 'key' */ static VALUE ossl_x509_verify(VALUE self, VALUE key) { X509 *x509; EVP_PKEY *pkey; int i; pkey = GetPKeyPtr(key); /* NO NEED TO DUP */ GetX509(self, x509); if ((i = X509_verify(x509, pkey)) < 0) { ossl_raise(eX509CertError, NULL); } if (i > 0) { return Qtrue; } return Qfalse; } /* * call-seq: * cert.check_private_key(key) * * Checks if 'key' is PRIV key for this cert */ static VALUE ossl_x509_check_private_key(VALUE self, VALUE key) { X509 *x509; EVP_PKEY *pkey; /* not needed private key, but should be */ pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ GetX509(self, x509); if (!X509_check_private_key(x509, pkey)) { OSSL_Warning("Check private key:%s", OSSL_ErrMsg()); return Qfalse; } return Qtrue; } /* * call-seq: * cert.extensions => [extension...] */ static VALUE ossl_x509_get_extensions(VALUE self) { X509 *x509; int count, i; X509_EXTENSION *ext; VALUE ary; GetX509(self, x509); count = X509_get_ext_count(x509); if (count < 0) { return rb_ary_new(); } ary = rb_ary_new2(count); for (i=0; i [ext...] */ static VALUE ossl_x509_set_extensions(VALUE self, VALUE ary) { X509 *x509; X509_EXTENSION *ext; int i; Check_Type(ary, T_ARRAY); /* All ary's members should be X509Extension */ for (i=0; icert_info->extensions, X509_EXTENSION_free); x509->cert_info->extensions = NULL; for (i=0; i extension */ static VALUE ossl_x509_add_extension(VALUE self, VALUE extension) { X509 *x509; X509_EXTENSION *ext; GetX509(self, x509); ext = DupX509ExtPtr(extension); if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */ X509_EXTENSION_free(ext); ossl_raise(eX509CertError, NULL); } X509_EXTENSION_free(ext); return extension; } static VALUE ossl_x509_inspect(VALUE self) { VALUE str; char *cname = rb_class2name(rb_obj_class(self)); str = rb_str_new2("#<"); rb_str_cat2(str, cname); rb_str_cat2(str, " "); rb_str_cat2(str, "subject="); rb_str_append(str, rb_inspect(ossl_x509_get_subject(self))); rb_str_cat2(str, ", "); rb_str_cat2(str, "issuer="); rb_str_append(str, rb_inspect(ossl_x509_get_issuer(self))); rb_str_cat2(str, ", "); rb_str_cat2(str, "serial="); rb_str_append(str, rb_inspect(ossl_x509_get_serial(self))); rb_str_cat2(str, ", "); rb_str_cat2(str, "not_before="); rb_str_append(str, rb_inspect(ossl_x509_get_not_before(self))); rb_str_cat2(str, ", "); rb_str_cat2(str, "not_after="); rb_str_append(str, rb_inspect(ossl_x509_get_not_after(self))); str = rb_str_cat2(str, ">"); return str; } /* * INIT */ void Init_ossl_x509cert() { eX509CertError = rb_define_class_under(mX509, "CertificateError", eOSSLError); cX509Cert = rb_define_class_under(mX509, "Certificate", rb_cObject); rb_define_alloc_func(cX509Cert, ossl_x509_alloc); rb_define_method(cX509Cert, "initialize", ossl_x509_initialize, -1); rb_define_copy_func(cX509Cert, ossl_x509_copy); rb_define_method(cX509Cert, "to_der", ossl_x509_to_der, 0); rb_define_method(cX509Cert, "to_pem", ossl_x509_to_pem, 0); rb_define_alias(cX509Cert, "to_s", "to_pem"); rb_define_method(cX509Cert, "to_text", ossl_x509_to_text, 0); rb_define_method(cX509Cert, "version", ossl_x509_get_version, 0); rb_define_method(cX509Cert, "version=", ossl_x509_set_version, 1); rb_define_method(cX509Cert, "signature_algorithm", ossl_x509_get_signature_algorithm, 0); rb_define_method(cX509Cert, "serial", ossl_x509_get_serial, 0); rb_define_method(cX509Cert, "serial=", ossl_x509_set_serial, 1); rb_define_method(cX509Cert, "subject", ossl_x509_get_subject, 0); rb_define_method(cX509Cert, "subject=", ossl_x509_set_subject, 1); rb_define_method(cX509Cert, "issuer", ossl_x509_get_issuer, 0); rb_define_method(cX509Cert, "issuer=", ossl_x509_set_issuer, 1); rb_define_method(cX509Cert, "not_before", ossl_x509_get_not_before, 0); rb_define_method(cX509Cert, "not_before=", ossl_x509_set_not_before, 1); rb_define_method(cX509Cert, "not_after", ossl_x509_get_not_after, 0); rb_define_method(cX509Cert, "not_after=", ossl_x509_set_not_after, 1); rb_define_method(cX509Cert, "public_key", ossl_x509_get_public_key, 0); rb_define_method(cX509Cert, "public_key=", ossl_x509_set_public_key, 1); rb_define_method(cX509Cert, "sign", ossl_x509_sign, 2); rb_define_method(cX509Cert, "verify", ossl_x509_verify, 1); rb_define_method(cX509Cert, "check_private_key", ossl_x509_check_private_key, 1); rb_define_method(cX509Cert, "extensions", ossl_x509_get_extensions, 0); rb_define_method(cX509Cert, "extensions=", ossl_x509_set_extensions, 1); rb_define_method(cX509Cert, "add_extension", ossl_x509_add_extension, 1); rb_define_method(cX509Cert, "inspect", ossl_x509_inspect, 0); } ================================================ FILE: ext/openssl/ossl_x509crl.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" #define WrapX509CRL(klass, obj, crl) do { \ if (!crl) { \ ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \ } \ obj = Data_Wrap_Struct(klass, 0, X509_CRL_free, crl); \ } while (0) #define GetX509CRL(obj, crl) do { \ Data_Get_Struct(obj, X509_CRL, crl); \ if (!crl) { \ ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \ } \ } while (0) #define SafeGetX509CRL(obj, crl) do { \ OSSL_Check_Kind(obj, cX509CRL); \ GetX509CRL(obj, crl); \ } while (0) /* * Classes */ VALUE cX509CRL; VALUE eX509CRLError; /* * PUBLIC */ X509_CRL * GetX509CRLPtr(VALUE obj) { X509_CRL *crl; SafeGetX509CRL(obj, crl); return crl; } X509_CRL * DupX509CRLPtr(VALUE obj) { X509_CRL *crl; SafeGetX509CRL(obj, crl); CRYPTO_add(&crl->references, 1, CRYPTO_LOCK_X509_CRL); return crl; } VALUE ossl_x509crl_new(X509_CRL *crl) { X509_CRL *tmp; VALUE obj; tmp = crl ? X509_CRL_dup(crl) : X509_CRL_new(); if(!tmp) ossl_raise(eX509CRLError, NULL); WrapX509CRL(cX509CRL, obj, tmp); return obj; } /* * PRIVATE */ static VALUE ossl_x509crl_alloc(VALUE klass) { X509_CRL *crl; VALUE obj; if (!(crl = X509_CRL_new())) { ossl_raise(eX509CRLError, NULL); } WrapX509CRL(klass, obj, crl); return obj; } static VALUE ossl_x509crl_initialize(int argc, VALUE *argv, VALUE self) { BIO *in; X509_CRL *crl; VALUE arg; if (rb_scan_args(argc, argv, "01", &arg) == 0) { return self; } arg = ossl_to_der_if_possible(arg); in = ossl_obj2bio(arg); crl = PEM_read_bio_X509_CRL(in, (X509_CRL **)&DATA_PTR(self), NULL, NULL); if (!crl) { BIO_reset(in); crl = d2i_X509_CRL_bio(in, (X509_CRL **)&DATA_PTR(self)); } BIO_free(in); if (!crl) ossl_raise(eX509CRLError, NULL); return self; } static VALUE ossl_x509crl_copy(VALUE self, VALUE other) { X509_CRL *a, *b, *crl; rb_check_frozen(self); if (self == other) return self; GetX509CRL(self, a); SafeGetX509CRL(other, b); if (!(crl = X509_CRL_dup(b))) { ossl_raise(eX509CRLError, NULL); } X509_CRL_free(a); DATA_PTR(self) = crl; return self; } static VALUE ossl_x509crl_get_version(VALUE self) { X509_CRL *crl; long ver; GetX509CRL(self, crl); ver = X509_CRL_get_version(crl); return LONG2NUM(ver); } static VALUE ossl_x509crl_set_version(VALUE self, VALUE version) { X509_CRL *crl; long ver; if ((ver = NUM2LONG(version)) < 0) { ossl_raise(eX509CRLError, "version must be >= 0!"); } GetX509CRL(self, crl); if (!X509_CRL_set_version(crl, ver)) { ossl_raise(eX509CRLError, NULL); } return version; } static VALUE ossl_x509crl_get_signature_algorithm(VALUE self) { X509_CRL *crl; BIO *out; BUF_MEM *buf; VALUE str; GetX509CRL(self, crl); if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eX509CRLError, NULL); } if (!i2a_ASN1_OBJECT(out, crl->sig_alg->algorithm)) { BIO_free(out); ossl_raise(eX509CRLError, NULL); } BIO_get_mem_ptr(out, &buf); str = rb_str_new(buf->data, buf->length); BIO_free(out); return str; } static VALUE ossl_x509crl_get_issuer(VALUE self) { X509_CRL *crl; GetX509CRL(self, crl); return ossl_x509name_new(X509_CRL_get_issuer(crl)); /* NO DUP - don't free */ } static VALUE ossl_x509crl_set_issuer(VALUE self, VALUE issuer) { X509_CRL *crl; GetX509CRL(self, crl); if (!X509_CRL_set_issuer_name(crl, GetX509NamePtr(issuer))) { /* DUPs name */ ossl_raise(eX509CRLError, NULL); } return issuer; } static VALUE ossl_x509crl_get_last_update(VALUE self) { X509_CRL *crl; GetX509CRL(self, crl); return asn1time_to_time(X509_CRL_get_lastUpdate(crl)); } static VALUE ossl_x509crl_set_last_update(VALUE self, VALUE time) { X509_CRL *crl; time_t sec; sec = time_to_time_t(time); GetX509CRL(self, crl); if (!X509_time_adj(crl->crl->lastUpdate, 0, &sec)) { ossl_raise(eX509CRLError, NULL); } return time; } static VALUE ossl_x509crl_get_next_update(VALUE self) { X509_CRL *crl; GetX509CRL(self, crl); return asn1time_to_time(X509_CRL_get_nextUpdate(crl)); } static VALUE ossl_x509crl_set_next_update(VALUE self, VALUE time) { X509_CRL *crl; time_t sec; sec = time_to_time_t(time); GetX509CRL(self, crl); /* This must be some thinko in OpenSSL */ if (!(crl->crl->nextUpdate = X509_time_adj(crl->crl->nextUpdate, 0, &sec))){ ossl_raise(eX509CRLError, NULL); } return time; } static VALUE ossl_x509crl_get_revoked(VALUE self) { X509_CRL *crl; int i, num; X509_REVOKED *rev; VALUE ary, revoked; GetX509CRL(self, crl); num = sk_X509_CRL_num(X509_CRL_get_REVOKED(crl)); if (num < 0) { OSSL_Debug("num < 0???"); return rb_ary_new(); } ary = rb_ary_new2(num); for(i=0; icrl->revoked, X509_REVOKED_free); crl->crl->revoked = NULL; for (i=0; idata, buf->length); BIO_free(out); return str; } static VALUE ossl_x509crl_to_pem(VALUE self) { X509_CRL *crl; BIO *out; BUF_MEM *buf; VALUE str; GetX509CRL(self, crl); if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eX509CRLError, NULL); } if (!PEM_write_bio_X509_CRL(out, crl)) { BIO_free(out); ossl_raise(eX509CRLError, NULL); } BIO_get_mem_ptr(out, &buf); str = rb_str_new(buf->data, buf->length); BIO_free(out); return str; } static VALUE ossl_x509crl_to_text(VALUE self) { X509_CRL *crl; BIO *out; BUF_MEM *buf; VALUE str; GetX509CRL(self, crl); if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eX509CRLError, NULL); } if (!X509_CRL_print(out, crl)) { BIO_free(out); ossl_raise(eX509CRLError, NULL); } BIO_get_mem_ptr(out, &buf); str = rb_str_new(buf->data, buf->length); BIO_free(out); return str; } /* * Gets X509v3 extensions as array of X509Ext objects */ static VALUE ossl_x509crl_get_extensions(VALUE self) { X509_CRL *crl; int count, i; X509_EXTENSION *ext; VALUE ary; GetX509CRL(self, crl); count = X509_CRL_get_ext_count(crl); if (count < 0) { OSSL_Debug("count < 0???"); return rb_ary_new(); } ary = rb_ary_new2(count); for (i=0; icrl->extensions, X509_EXTENSION_free); crl->crl->extensions = NULL; for (i=0; i * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" #define WrapX509Ext(klass, obj, ext) do { \ if (!ext) { \ ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \ } \ obj = Data_Wrap_Struct(klass, 0, X509_EXTENSION_free, ext); \ } while (0) #define GetX509Ext(obj, ext) do { \ Data_Get_Struct(obj, X509_EXTENSION, ext); \ if (!ext) { \ ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \ } \ } while (0) #define SafeGetX509Ext(obj, ext) do { \ OSSL_Check_Kind(obj, cX509Ext); \ GetX509Ext(obj, ext); \ } while (0) #define MakeX509ExtFactory(klass, obj, ctx) do { \ if (!(ctx = OPENSSL_malloc(sizeof(X509V3_CTX)))) \ ossl_raise(rb_eRuntimeError, "CTX wasn't allocated!"); \ X509V3_set_ctx(ctx, NULL, NULL, NULL, NULL, 0); \ obj = Data_Wrap_Struct(klass, 0, ossl_x509extfactory_free, ctx); \ } while (0) #define GetX509ExtFactory(obj, ctx) do { \ Data_Get_Struct(obj, X509V3_CTX, ctx); \ if (!ctx) { \ ossl_raise(rb_eRuntimeError, "CTX wasn't initialized!"); \ } \ } while (0) /* * Classes */ VALUE cX509Ext; VALUE cX509ExtFactory; VALUE eX509ExtError; /* * Public */ VALUE ossl_x509ext_new(X509_EXTENSION *ext) { X509_EXTENSION *new; VALUE obj; if (!ext) { new = X509_EXTENSION_new(); } else { new = X509_EXTENSION_dup(ext); } if (!new) { ossl_raise(eX509ExtError, NULL); } WrapX509Ext(cX509Ext, obj, new); return obj; } X509_EXTENSION * GetX509ExtPtr(VALUE obj) { X509_EXTENSION *ext; SafeGetX509Ext(obj, ext); return ext; } X509_EXTENSION * DupX509ExtPtr(VALUE obj) { X509_EXTENSION *ext, *new; SafeGetX509Ext(obj, ext); if (!(new = X509_EXTENSION_dup(ext))) { ossl_raise(eX509ExtError, NULL); } return new; } /* * Private */ /* * Ext factory */ static void ossl_x509extfactory_free(X509V3_CTX *ctx) { OPENSSL_free(ctx); } static VALUE ossl_x509extfactory_alloc(VALUE klass) { X509V3_CTX *ctx; VALUE obj; MakeX509ExtFactory(klass, obj, ctx); return obj; } static VALUE ossl_x509extfactory_set_issuer_cert(VALUE self, VALUE cert) { X509V3_CTX *ctx; GetX509ExtFactory(self, ctx); rb_iv_set(self, "@issuer_certificate", cert); ctx->issuer_cert = GetX509CertPtr(cert); /* NO DUP NEEDED */ return cert; } static VALUE ossl_x509extfactory_set_subject_cert(VALUE self, VALUE cert) { X509V3_CTX *ctx; GetX509ExtFactory(self, ctx); rb_iv_set(self, "@subject_certificate", cert); ctx->subject_cert = GetX509CertPtr(cert); /* NO DUP NEEDED */ return cert; } static VALUE ossl_x509extfactory_set_subject_req(VALUE self, VALUE req) { X509V3_CTX *ctx; GetX509ExtFactory(self, ctx); rb_iv_set(self, "@subject_request", req); ctx->subject_req = GetX509ReqPtr(req); /* NO DUP NEEDED */ return req; } static VALUE ossl_x509extfactory_set_crl(VALUE self, VALUE crl) { X509V3_CTX *ctx; GetX509ExtFactory(self, ctx); rb_iv_set(self, "@crl", crl); ctx->crl = GetX509CRLPtr(crl); /* NO DUP NEEDED */ return crl; } static VALUE ossl_x509extfactory_set_config(VALUE self, VALUE config) { #ifdef HAVE_X509V3_SET_NCONF X509V3_CTX *ctx; CONF *conf; GetX509ExtFactory(self, ctx); rb_iv_set(self, "@config", config); conf = GetConfigPtr(config); /* NO DUP NEEDED */ X509V3_set_nconf(ctx, conf); return config; #else rb_notimplement(); #endif } static VALUE ossl_x509extfactory_initialize(int argc, VALUE *argv, VALUE self) { /*X509V3_CTX *ctx;*/ VALUE issuer_cert, subject_cert, subject_req, crl; /*GetX509ExtFactory(self, ctx);*/ rb_scan_args(argc, argv, "04", &issuer_cert, &subject_cert, &subject_req, &crl); if (!NIL_P(issuer_cert)) ossl_x509extfactory_set_issuer_cert(self, issuer_cert); if (!NIL_P(subject_cert)) ossl_x509extfactory_set_subject_cert(self, subject_cert); if (!NIL_P(subject_req)) ossl_x509extfactory_set_subject_req(self, subject_req); if (!NIL_P(crl)) ossl_x509extfactory_set_crl(self, crl); return self; } /* * Array to X509_EXTENSION * Structure: * ["ln", "value", bool_critical] or * ["sn", "value", bool_critical] or * ["ln", "critical,value"] or the same for sn * ["ln", "value"] => not critical */ static VALUE ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self) { X509V3_CTX *ctx; X509_EXTENSION *ext; VALUE oid, value, critical, valstr, obj; int nid; #ifdef HAVE_X509V3_EXT_NCONF_NID VALUE rconf; CONF *conf; ID i_config; #else static LHASH *empty_lhash; #endif rb_scan_args(argc, argv, "21", &oid, &value, &critical); StringValue(oid); StringValue(value); if(NIL_P(critical)) critical = Qfalse; nid = OBJ_ln2nid(RSTRING_PTR(oid)); if(!nid) nid = OBJ_sn2nid(RSTRING_PTR(oid)); if(!nid) ossl_raise(eX509ExtError, "unknown OID `%s'", RSTRING_PTR(oid)); valstr = rb_str_new2(RTEST(critical) ? "critical," : ""); rb_str_append(valstr, value); GetX509ExtFactory(self, ctx); #ifdef HAVE_X509V3_EXT_NCONF_NID i_config = rb_intern("@config"); if (rb_ivar_defined(self, i_config)) rconf = rb_ivar_get(self, i_config); else rconf = Qnil; conf = NIL_P(rconf) ? NULL : GetConfigPtr(rconf); ext = X509V3_EXT_nconf_nid(conf, ctx, nid, RSTRING_PTR(valstr)); #else if (!empty_lhash) empty_lhash = lh_new(NULL, NULL); ext = X509V3_EXT_conf_nid(empty_lhash, ctx, nid, RSTRING_PTR(valstr)); #endif if (!ext){ ossl_raise(eX509ExtError, "%s = %s", RSTRING_PTR(oid), RSTRING_PTR(value)); } WrapX509Ext(cX509Ext, obj, ext); return obj; } /* * Ext */ static VALUE ossl_x509ext_alloc(VALUE klass) { X509_EXTENSION *ext; VALUE obj; if(!(ext = X509_EXTENSION_new())){ ossl_raise(eX509ExtError, NULL); } WrapX509Ext(klass, obj, ext); return obj; } static VALUE ossl_x509ext_initialize(int argc, VALUE *argv, VALUE self) { VALUE oid, value, critical; OSSL_MORE_CONST unsigned char *p; X509_EXTENSION *ext; GetX509Ext(self, ext); if(rb_scan_args(argc, argv, "12", &oid, &value, &critical) == 1){ oid = ossl_to_der_if_possible(oid); StringValue(oid); p = RSTRING_PTR(oid); if(!d2i_X509_EXTENSION((X509_EXTENSION**)&DATA_PTR(self), &p, RSTRING_LEN(oid))) ossl_raise(eX509ExtError, NULL); return self; } rb_funcall(self, rb_intern("oid="), 1, oid); rb_funcall(self, rb_intern("value="), 1, value); if(argc > 2) rb_funcall(self, rb_intern("critical="), 1, critical); return self; } static VALUE ossl_x509ext_set_oid(VALUE self, VALUE oid) { X509_EXTENSION *ext; ASN1_OBJECT *obj; char *s; s = StringValuePtr(oid); obj = OBJ_txt2obj(s, 0); if(!obj) obj = OBJ_txt2obj(s, 1); if(!obj) ossl_raise(eX509ExtError, NULL); GetX509Ext(self, ext); X509_EXTENSION_set_object(ext, obj); return oid; } static VALUE ossl_x509ext_set_value(VALUE self, VALUE data) { X509_EXTENSION *ext; ASN1_OCTET_STRING *asn1s; char *s; data = ossl_to_der_if_possible(data); StringValue(data); if(!(s = OPENSSL_malloc(RSTRING_LEN(data)))) ossl_raise(eX509ExtError, "malloc error"); memcpy(s, RSTRING_PTR(data), RSTRING_LEN(data)); if(!(asn1s = ASN1_OCTET_STRING_new())){ free(s); ossl_raise(eX509ExtError, NULL); } if(!M_ASN1_OCTET_STRING_set(asn1s, s, RSTRING_LEN(data))){ free(s); ASN1_OCTET_STRING_free(asn1s); ossl_raise(eX509ExtError, NULL); } GetX509Ext(self, ext); X509_EXTENSION_set_data(ext, asn1s); return data; } static VALUE ossl_x509ext_set_critical(VALUE self, VALUE flag) { X509_EXTENSION *ext; GetX509Ext(self, ext); X509_EXTENSION_set_critical(ext, RTEST(flag) ? 1 : 0); return flag; } static VALUE ossl_x509ext_get_oid(VALUE obj) { X509_EXTENSION *ext; ASN1_OBJECT *extobj; BIO *out; VALUE ret; int nid; GetX509Ext(obj, ext); extobj = X509_EXTENSION_get_object(ext); if ((nid = OBJ_obj2nid(extobj)) != NID_undef) ret = rb_str_new2(OBJ_nid2sn(nid)); else{ if (!(out = BIO_new(BIO_s_mem()))) ossl_raise(eX509ExtError, NULL); i2a_ASN1_OBJECT(out, extobj); ret = ossl_membio2str(out); } return ret; } static VALUE ossl_x509ext_get_value(VALUE obj) { X509_EXTENSION *ext; BIO *out; VALUE ret; GetX509Ext(obj, ext); if (!(out = BIO_new(BIO_s_mem()))) ossl_raise(eX509ExtError, NULL); if (!X509V3_EXT_print(out, ext, 0, 0)) M_ASN1_OCTET_STRING_print(out, ext->value); ret = ossl_membio2str(out); return ret; } static VALUE ossl_x509ext_get_critical(VALUE obj) { X509_EXTENSION *ext; GetX509Ext(obj, ext); return X509_EXTENSION_get_critical(ext) ? Qtrue : Qfalse; } static VALUE ossl_x509ext_to_der(VALUE obj) { X509_EXTENSION *ext; unsigned char *p; long len; VALUE str; GetX509Ext(obj, ext); if((len = i2d_X509_EXTENSION(ext, NULL)) <= 0) ossl_raise(eX509ExtError, NULL); str = rb_str_new(0, len); p = RSTRING_PTR(str); if(i2d_X509_EXTENSION(ext, &p) < 0) ossl_raise(eX509ExtError, NULL); ossl_str_adjust(str, p); return str; } /* * INIT */ void Init_ossl_x509ext() { eX509ExtError = rb_define_class_under(mX509, "ExtensionError", eOSSLError); cX509ExtFactory = rb_define_class_under(mX509, "ExtensionFactory", rb_cObject); rb_define_alloc_func(cX509ExtFactory, ossl_x509extfactory_alloc); rb_define_method(cX509ExtFactory, "initialize", ossl_x509extfactory_initialize, -1); rb_attr(cX509ExtFactory, rb_intern("issuer_certificate"), 1, 0, Qfalse); rb_attr(cX509ExtFactory, rb_intern("subject_certificate"), 1, 0, Qfalse); rb_attr(cX509ExtFactory, rb_intern("subject_request"), 1, 0, Qfalse); rb_attr(cX509ExtFactory, rb_intern("crl"), 1, 0, Qfalse); rb_attr(cX509ExtFactory, rb_intern("config"), 1, 0, Qfalse); rb_define_method(cX509ExtFactory, "issuer_certificate=", ossl_x509extfactory_set_issuer_cert, 1); rb_define_method(cX509ExtFactory, "subject_certificate=", ossl_x509extfactory_set_subject_cert, 1); rb_define_method(cX509ExtFactory, "subject_request=", ossl_x509extfactory_set_subject_req, 1); rb_define_method(cX509ExtFactory, "crl=", ossl_x509extfactory_set_crl, 1); rb_define_method(cX509ExtFactory, "config=", ossl_x509extfactory_set_config, 1); rb_define_method(cX509ExtFactory, "create_ext", ossl_x509extfactory_create_ext, -1); cX509Ext = rb_define_class_under(mX509, "Extension", rb_cObject); rb_define_alloc_func(cX509Ext, ossl_x509ext_alloc); rb_define_method(cX509Ext, "initialize", ossl_x509ext_initialize, -1); rb_define_method(cX509Ext, "oid=", ossl_x509ext_set_oid, 1); rb_define_method(cX509Ext, "value=", ossl_x509ext_set_value, 1); rb_define_method(cX509Ext, "critical=", ossl_x509ext_set_critical, 1); rb_define_method(cX509Ext, "oid", ossl_x509ext_get_oid, 0); rb_define_method(cX509Ext, "value", ossl_x509ext_get_value, 0); rb_define_method(cX509Ext, "critical?", ossl_x509ext_get_critical, 0); rb_define_method(cX509Ext, "to_der", ossl_x509ext_to_der, 0); } ================================================ FILE: ext/openssl/ossl_x509name.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" #define WrapX509Name(klass, obj, name) do { \ if (!name) { \ ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \ } \ obj = Data_Wrap_Struct(klass, 0, X509_NAME_free, name); \ } while (0) #define GetX509Name(obj, name) do { \ Data_Get_Struct(obj, X509_NAME, name); \ if (!name) { \ ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \ } \ } while (0) #define SafeGetX509Name(obj, name) do { \ OSSL_Check_Kind(obj, cX509Name); \ GetX509Name(obj, name); \ } while (0) #define OBJECT_TYPE_TEMPLATE \ rb_const_get(cX509Name, rb_intern("OBJECT_TYPE_TEMPLATE")) #define DEFAULT_OBJECT_TYPE \ rb_const_get(cX509Name, rb_intern("DEFAULT_OBJECT_TYPE")) /* * Classes */ VALUE cX509Name; VALUE eX509NameError; /* * Public */ VALUE ossl_x509name_new(X509_NAME *name) { X509_NAME *new; VALUE obj; if (!name) { new = X509_NAME_new(); } else { new = X509_NAME_dup(name); } if (!new) { ossl_raise(eX509NameError, NULL); } WrapX509Name(cX509Name, obj, new); return obj; } X509_NAME * GetX509NamePtr(VALUE obj) { X509_NAME *name; SafeGetX509Name(obj, name); return name; } /* * Private */ static VALUE ossl_x509name_alloc(VALUE klass) { X509_NAME *name; VALUE obj; if (!(name = X509_NAME_new())) { ossl_raise(eX509NameError, NULL); } WrapX509Name(klass, obj, name); return obj; } static int id_aref; static VALUE ossl_x509name_add_entry(int, VALUE*, VALUE); #define rb_aref(obj, key) rb_funcall(obj, id_aref, 1, key) static VALUE ossl_x509name_init_i(VALUE i, VALUE args) { VALUE self = rb_ary_entry(args, 0); VALUE template = rb_ary_entry(args, 1); VALUE entry[3]; Check_Type(i, T_ARRAY); entry[0] = rb_ary_entry(i, 0); entry[1] = rb_ary_entry(i, 1); entry[2] = rb_ary_entry(i, 2); if(NIL_P(entry[2])) entry[2] = rb_aref(template, entry[0]); if(NIL_P(entry[2])) entry[2] = DEFAULT_OBJECT_TYPE; ossl_x509name_add_entry(3, entry, self); return Qnil; } /* * call-seq: * X509::Name.new => name * X509::Name.new(string) => name * X509::Name.new(dn) => name * X509::Name.new(dn, template) => name */ static VALUE ossl_x509name_initialize(int argc, VALUE *argv, VALUE self) { X509_NAME *name; VALUE arg, template; GetX509Name(self, name); if (rb_scan_args(argc, argv, "02", &arg, &template) == 0) { return self; } else { VALUE tmp = rb_check_array_type(arg); if (!NIL_P(tmp)) { VALUE args; if(NIL_P(template)) template = OBJECT_TYPE_TEMPLATE; args = rb_ary_new3(2, self, template); rb_block_call(tmp, rb_intern("each"), 0, 0, ossl_x509name_init_i, args); } else{ unsigned char *p; VALUE str = ossl_to_der_if_possible(arg); StringValue(str); p = RSTRING_PTR(str); if(!d2i_X509_NAME((X509_NAME**)&DATA_PTR(self), &p, RSTRING_LEN(str))){ ossl_raise(eX509NameError, NULL); } } } return self; } /* * call-seq: * name.add_entry(oid, value [, type]) => self */ static VALUE ossl_x509name_add_entry(int argc, VALUE *argv, VALUE self) { X509_NAME *name; VALUE oid, value, type; rb_scan_args(argc, argv, "21", &oid, &value, &type); StringValue(oid); StringValue(value); if(NIL_P(type)) type = rb_aref(OBJECT_TYPE_TEMPLATE, oid); GetX509Name(self, name); if (!X509_NAME_add_entry_by_txt(name, RSTRING_PTR(oid), NUM2INT(type), RSTRING_PTR(value), RSTRING_LEN(value), -1, 0)) { ossl_raise(eX509NameError, NULL); } return self; } static VALUE ossl_x509name_to_s_old(VALUE self) { X509_NAME *name; char *buf; VALUE str; GetX509Name(self, name); buf = X509_NAME_oneline(name, NULL, 0); str = rb_str_new2(buf); OPENSSL_free(buf); return str; } /* * call-seq: * name.to_s => string * name.to_s(integer) => string */ static VALUE ossl_x509name_to_s(int argc, VALUE *argv, VALUE self) { X509_NAME *name; VALUE flag, str; BIO *out; unsigned long iflag; rb_scan_args(argc, argv, "01", &flag); if (NIL_P(flag)) return ossl_x509name_to_s_old(self); else iflag = NUM2ULONG(flag); if (!(out = BIO_new(BIO_s_mem()))) ossl_raise(eX509NameError, NULL); GetX509Name(self, name); if (!X509_NAME_print_ex(out, name, 0, iflag)){ BIO_free(out); ossl_raise(eX509NameError, NULL); } str = ossl_membio2str(out); return str; } /* * call-seq: * name.to_a => [[name, data, type], ...] */ static VALUE ossl_x509name_to_a(VALUE self) { X509_NAME *name; X509_NAME_ENTRY *entry; int i,entries; char long_name[512]; const char *short_name; VALUE ary, ret; GetX509Name(self, name); entries = X509_NAME_entry_count(name); if (entries < 0) { OSSL_Debug("name entries < 0!"); return rb_ary_new(); } ret = rb_ary_new2(entries); for (i=0; iobject)) { ossl_raise(eX509NameError, NULL); } short_name = OBJ_nid2sn(OBJ_ln2nid(long_name)); ary = rb_ary_new3(3, rb_str_new2(short_name), rb_str_new(entry->value->data, entry->value->length), INT2FIX(entry->value->type)); rb_ary_push(ret, ary); } return ret; } static int ossl_x509name_cmp0(VALUE self, VALUE other) { X509_NAME *name1, *name2; GetX509Name(self, name1); SafeGetX509Name(other, name2); return X509_NAME_cmp(name1, name2); } static VALUE ossl_x509name_cmp(VALUE self, VALUE other) { int result; result = ossl_x509name_cmp0(self, other); if (result < 0) return INT2FIX(-1); if (result > 1) return INT2FIX(1); return INT2FIX(0); } static VALUE ossl_x509name_eql(VALUE self, VALUE other) { int result; if(CLASS_OF(other) != cX509Name) return Qfalse; result = ossl_x509name_cmp0(self, other); return (result == 0) ? Qtrue : Qfalse; } /* * call-seq: * name.hash => integer */ static VALUE ossl_x509name_hash(VALUE self) { X509_NAME *name; unsigned long hash; GetX509Name(self, name); hash = X509_NAME_hash(name); return ULONG2NUM(hash); } /* * call-seq: * name.to_der => string */ static VALUE ossl_x509name_to_der(VALUE self) { X509_NAME *name; VALUE str; long len; unsigned char *p; GetX509Name(self, name); if((len = i2d_X509_NAME(name, NULL)) <= 0) ossl_raise(eX509NameError, NULL); str = rb_str_new(0, len); p = RSTRING_PTR(str); if(i2d_X509_NAME(name, &p) <= 0) ossl_raise(eX509NameError, NULL); ossl_str_adjust(str, p); return str; } /* * INIT */ void Init_ossl_x509name() { VALUE utf8str, ptrstr, ia5str, hash; id_aref = rb_intern("[]"); eX509NameError = rb_define_class_under(mX509, "NameError", eOSSLError); cX509Name = rb_define_class_under(mX509, "Name", rb_cObject); rb_define_alloc_func(cX509Name, ossl_x509name_alloc); rb_define_method(cX509Name, "initialize", ossl_x509name_initialize, -1); rb_define_method(cX509Name, "add_entry", ossl_x509name_add_entry, -1); rb_define_method(cX509Name, "to_s", ossl_x509name_to_s, -1); rb_define_method(cX509Name, "to_a", ossl_x509name_to_a, 0); rb_define_method(cX509Name, "cmp", ossl_x509name_cmp, 1); rb_define_alias(cX509Name, "<=>", "cmp"); rb_define_method(cX509Name, "eql?", ossl_x509name_eql, 1); rb_define_method(cX509Name, "hash", ossl_x509name_hash, 0); rb_define_method(cX509Name, "to_der", ossl_x509name_to_der, 0); utf8str = INT2NUM(V_ASN1_UTF8STRING); ptrstr = INT2NUM(V_ASN1_PRINTABLESTRING); ia5str = INT2NUM(V_ASN1_IA5STRING); rb_define_const(cX509Name, "DEFAULT_OBJECT_TYPE", utf8str); hash = rb_hash_new(); RHASH(hash)->ifnone = utf8str; rb_hash_aset(hash, rb_str_new2("C"), ptrstr); rb_hash_aset(hash, rb_str_new2("countryName"), ptrstr); rb_hash_aset(hash, rb_str_new2("serialNumber"), ptrstr); rb_hash_aset(hash, rb_str_new2("dnQualifier"), ptrstr); rb_hash_aset(hash, rb_str_new2("DC"), ia5str); rb_hash_aset(hash, rb_str_new2("domainComponent"), ia5str); rb_hash_aset(hash, rb_str_new2("emailAddress"), ia5str); rb_define_const(cX509Name, "OBJECT_TYPE_TEMPLATE", hash); rb_define_const(cX509Name, "COMPAT", ULONG2NUM(XN_FLAG_COMPAT)); rb_define_const(cX509Name, "RFC2253", ULONG2NUM(XN_FLAG_RFC2253)); rb_define_const(cX509Name, "ONELINE", ULONG2NUM(XN_FLAG_ONELINE)); rb_define_const(cX509Name, "MULTILINE", ULONG2NUM(XN_FLAG_MULTILINE)); } ================================================ FILE: ext/openssl/ossl_x509req.c ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" #define WrapX509Req(klass, obj, req) do { \ if (!req) { \ ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \ } \ obj = Data_Wrap_Struct(klass, 0, X509_REQ_free, req); \ } while (0) #define GetX509Req(obj, req) do { \ Data_Get_Struct(obj, X509_REQ, req); \ if (!req) { \ ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \ } \ } while (0) #define SafeGetX509Req(obj, req) do { \ OSSL_Check_Kind(obj, cX509Req); \ GetX509Req(obj, req); \ } while (0) /* * Classes */ VALUE cX509Req; VALUE eX509ReqError; /* * Public functions */ VALUE ossl_x509req_new(X509_REQ *req) { X509_REQ *new; VALUE obj; if (!req) { new = X509_REQ_new(); } else { new = X509_REQ_dup(req); } if (!new) { ossl_raise(eX509ReqError, NULL); } WrapX509Req(cX509Req, obj, new); return obj; } X509_REQ * GetX509ReqPtr(VALUE obj) { X509_REQ *req; SafeGetX509Req(obj, req); return req; } X509_REQ * DupX509ReqPtr(VALUE obj) { X509_REQ *req, *new; SafeGetX509Req(obj, req); if (!(new = X509_REQ_dup(req))) { ossl_raise(eX509ReqError, NULL); } return new; } /* * Private functions */ static VALUE ossl_x509req_alloc(VALUE klass) { X509_REQ *req; VALUE obj; if (!(req = X509_REQ_new())) { ossl_raise(eX509ReqError, NULL); } WrapX509Req(klass, obj, req); return obj; } static VALUE ossl_x509req_initialize(int argc, VALUE *argv, VALUE self) { BIO *in; X509_REQ *req; VALUE arg; if (rb_scan_args(argc, argv, "01", &arg) == 0) { return self; } arg = ossl_to_der_if_possible(arg); in = ossl_obj2bio(arg); req = PEM_read_bio_X509_REQ(in, (X509_REQ **)&DATA_PTR(self), NULL, NULL); if (!req) { BIO_reset(in); req = d2i_X509_REQ_bio(in, (X509_REQ **)&DATA_PTR(self)); } BIO_free(in); if (!req) ossl_raise(eX509ReqError, NULL); return self; } static VALUE ossl_x509req_copy(VALUE self, VALUE other) { X509_REQ *a, *b, *req; rb_check_frozen(self); if (self == other) return self; GetX509Req(self, a); SafeGetX509Req(other, b); if (!(req = X509_REQ_dup(b))) { ossl_raise(eX509ReqError, NULL); } X509_REQ_free(a); DATA_PTR(self) = req; return self; } static VALUE ossl_x509req_to_pem(VALUE self) { X509_REQ *req; BIO *out; BUF_MEM *buf; VALUE str; GetX509Req(self, req); if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eX509ReqError, NULL); } if (!PEM_write_bio_X509_REQ(out, req)) { BIO_free(out); ossl_raise(eX509ReqError, NULL); } BIO_get_mem_ptr(out, &buf); str = rb_str_new(buf->data, buf->length); BIO_free(out); return str; } static VALUE ossl_x509req_to_der(VALUE self) { X509_REQ *req; VALUE str; long len; unsigned char *p; GetX509Req(self, req); if ((len = i2d_X509_REQ(req, NULL)) <= 0) ossl_raise(eX509CertError, NULL); str = rb_str_new(0, len); p = RSTRING_PTR(str); if (i2d_X509_REQ(req, &p) <= 0) ossl_raise(eX509ReqError, NULL); ossl_str_adjust(str, p); return str; } static VALUE ossl_x509req_to_text(VALUE self) { X509_REQ *req; BIO *out; BUF_MEM *buf; VALUE str; GetX509Req(self, req); if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eX509ReqError, NULL); } if (!X509_REQ_print(out, req)) { BIO_free(out); ossl_raise(eX509ReqError, NULL); } BIO_get_mem_ptr(out, &buf); str = rb_str_new(buf->data, buf->length); BIO_free(out); return str; } #if 0 /* * Makes X509 from X509_REQuest */ static VALUE ossl_x509req_to_x509(VALUE self, VALUE days, VALUE key) { X509_REQ *req; X509 *x509; GetX509Req(self, req); ... if (!(x509 = X509_REQ_to_X509(req, d, pkey))) { ossl_raise(eX509ReqError, NULL); } return ossl_x509_new(x509); } #endif static VALUE ossl_x509req_get_version(VALUE self) { X509_REQ *req; long version; GetX509Req(self, req); version = X509_REQ_get_version(req); return LONG2FIX(version); } static VALUE ossl_x509req_set_version(VALUE self, VALUE version) { X509_REQ *req; long ver; if ((ver = FIX2LONG(version)) < 0) { ossl_raise(eX509ReqError, "version must be >= 0!"); } GetX509Req(self, req); if (!X509_REQ_set_version(req, ver)) { ossl_raise(eX509ReqError, NULL); } return version; } static VALUE ossl_x509req_get_subject(VALUE self) { X509_REQ *req; X509_NAME *name; GetX509Req(self, req); if (!(name = X509_REQ_get_subject_name(req))) { /* NO DUP - don't free */ ossl_raise(eX509ReqError, NULL); } return ossl_x509name_new(name); } static VALUE ossl_x509req_set_subject(VALUE self, VALUE subject) { X509_REQ *req; GetX509Req(self, req); /* DUPs name */ if (!X509_REQ_set_subject_name(req, GetX509NamePtr(subject))) { ossl_raise(eX509ReqError, NULL); } return subject; } static VALUE ossl_x509req_get_signature_algorithm(VALUE self) { X509_REQ *req; BIO *out; BUF_MEM *buf; VALUE str; GetX509Req(self, req); if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eX509ReqError, NULL); } if (!i2a_ASN1_OBJECT(out, req->sig_alg->algorithm)) { BIO_free(out); ossl_raise(eX509ReqError, NULL); } BIO_get_mem_ptr(out, &buf); str = rb_str_new(buf->data, buf->length); BIO_free(out); return str; } static VALUE ossl_x509req_get_public_key(VALUE self) { X509_REQ *req; EVP_PKEY *pkey; GetX509Req(self, req); if (!(pkey = X509_REQ_get_pubkey(req))) { /* adds reference */ ossl_raise(eX509ReqError, NULL); } return ossl_pkey_new(pkey); /* NO DUP - OK */ } static VALUE ossl_x509req_set_public_key(VALUE self, VALUE key) { X509_REQ *req; EVP_PKEY *pkey; GetX509Req(self, req); pkey = GetPKeyPtr(key); /* NO NEED TO DUP */ if (!X509_REQ_set_pubkey(req, pkey)) { ossl_raise(eX509ReqError, NULL); } return key; } static VALUE ossl_x509req_sign(VALUE self, VALUE key, VALUE digest) { X509_REQ *req; EVP_PKEY *pkey; const EVP_MD *md; GetX509Req(self, req); pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ md = GetDigestPtr(digest); if (!X509_REQ_sign(req, pkey, md)) { ossl_raise(eX509ReqError, NULL); } return self; } /* * Checks that cert signature is made with PRIVversion of this PUBLIC 'key' */ static VALUE ossl_x509req_verify(VALUE self, VALUE key) { X509_REQ *req; EVP_PKEY *pkey; int i; GetX509Req(self, req); pkey = GetPKeyPtr(key); /* NO NEED TO DUP */ if ((i = X509_REQ_verify(req, pkey)) < 0) { ossl_raise(eX509ReqError, NULL); } if (i > 0) { return Qtrue; } return Qfalse; } static VALUE ossl_x509req_get_attributes(VALUE self) { X509_REQ *req; int count, i; X509_ATTRIBUTE *attr; VALUE ary; GetX509Req(self, req); count = X509_REQ_get_attr_count(req); if (count < 0) { OSSL_Debug("count < 0???"); return rb_ary_new(); } ary = rb_ary_new2(count); for (i=0; ireq_info->attributes, X509_ATTRIBUTE_free); req->req_info->attributes = NULL; for (i=0;i * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" #define WrapX509Rev(klass, obj, rev) do { \ if (!rev) { \ ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \ } \ obj = Data_Wrap_Struct(klass, 0, X509_REVOKED_free, rev); \ } while (0) #define GetX509Rev(obj, rev) do { \ Data_Get_Struct(obj, X509_REVOKED, rev); \ if (!rev) { \ ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \ } \ } while (0) #define SafeGetX509Rev(obj, rev) do { \ OSSL_Check_Kind(obj, cX509Rev); \ GetX509Rev(obj, rev); \ } while (0) /* * Classes */ VALUE cX509Rev; VALUE eX509RevError; /* * PUBLIC */ VALUE ossl_x509revoked_new(X509_REVOKED *rev) { X509_REVOKED *new; VALUE obj; if (!rev) { new = X509_REVOKED_new(); } else { new = X509_REVOKED_dup(rev); } if (!new) { ossl_raise(eX509RevError, NULL); } WrapX509Rev(cX509Rev, obj, new); return obj; } X509_REVOKED * DupX509RevokedPtr(VALUE obj) { X509_REVOKED *rev, *new; SafeGetX509Rev(obj, rev); if (!(new = X509_REVOKED_dup(rev))) { ossl_raise(eX509RevError, NULL); } return new; } /* * PRIVATE */ static VALUE ossl_x509revoked_alloc(VALUE klass) { X509_REVOKED *rev; VALUE obj; if (!(rev = X509_REVOKED_new())) { ossl_raise(eX509RevError, NULL); } WrapX509Rev(klass, obj, rev); return obj; } static VALUE ossl_x509revoked_initialize(int argc, VALUE *argv, VALUE self) { /* EMPTY */ return self; } static VALUE ossl_x509revoked_get_serial(VALUE self) { X509_REVOKED *rev; GetX509Rev(self, rev); return asn1integer_to_num(rev->serialNumber); } static VALUE ossl_x509revoked_set_serial(VALUE self, VALUE num) { X509_REVOKED *rev; GetX509Rev(self, rev); rev->serialNumber = num_to_asn1integer(num, rev->serialNumber); return num; } static VALUE ossl_x509revoked_get_time(VALUE self) { X509_REVOKED *rev; GetX509Rev(self, rev); return asn1time_to_time(rev->revocationDate); } static VALUE ossl_x509revoked_set_time(VALUE self, VALUE time) { X509_REVOKED *rev; time_t sec; sec = time_to_time_t(time); GetX509Rev(self, rev); if (!X509_time_adj(rev->revocationDate, 0, &sec)) { ossl_raise(eX509RevError, NULL); } return time; } /* * Gets X509v3 extensions as array of X509Ext objects */ static VALUE ossl_x509revoked_get_extensions(VALUE self) { X509_REVOKED *rev; int count, i; X509_EXTENSION *ext; VALUE ary; GetX509Rev(self, rev); count = X509_REVOKED_get_ext_count(rev); if (count < 0) { OSSL_Debug("count < 0???"); return rb_ary_new(); } ary = rb_ary_new2(count); for (i=0; iextensions, X509_EXTENSION_free); rev->extensions = NULL; for (i=0; i * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #include "ossl.h" #include #define WrapX509Store(klass, obj, st) do { \ if (!st) { \ ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \ } \ obj = Data_Wrap_Struct(klass, 0, X509_STORE_free, st); \ } while (0) #define GetX509Store(obj, st) do { \ Data_Get_Struct(obj, X509_STORE, st); \ if (!st) { \ ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \ } \ } while (0) #define SafeGetX509Store(obj, st) do { \ OSSL_Check_Kind(obj, cX509Store); \ GetX509Store(obj, st); \ } while (0) #define WrapX509StCtx(klass, obj, ctx) do { \ if (!ctx) { \ ossl_raise(rb_eRuntimeError, "STORE_CTX wasn't initialized!"); \ } \ obj = Data_Wrap_Struct(klass, 0, ossl_x509stctx_free, ctx); \ } while (0) #define GetX509StCtx(obj, ctx) do { \ Data_Get_Struct(obj, X509_STORE_CTX, ctx); \ if (!ctx) { \ ossl_raise(rb_eRuntimeError, "STORE_CTX is out of scope!"); \ } \ } while (0) #define SafeGetX509StCtx(obj, storep) do { \ OSSL_Check_Kind(obj, cX509StoreContext); \ GetX509Store(obj, ctx); \ } while (0) /* * Classes */ VALUE cX509Store; VALUE cX509StoreContext; VALUE eX509StoreError; /* * Public functions */ VALUE ossl_x509store_new(X509_STORE *store) { VALUE obj; WrapX509Store(cX509Store, obj, store); return obj; } X509_STORE * GetX509StorePtr(VALUE obj) { X509_STORE *store; SafeGetX509Store(obj, store); return store; } X509_STORE * DupX509StorePtr(VALUE obj) { X509_STORE *store; SafeGetX509Store(obj, store); CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE); return store; } /* * Private functions */ static VALUE ossl_x509store_alloc(VALUE klass) { X509_STORE *store; VALUE obj; if((store = X509_STORE_new()) == NULL){ ossl_raise(eX509StoreError, NULL); } WrapX509Store(klass, obj, store); return obj; } /* * General callback for OpenSSL verify */ static VALUE ossl_x509store_set_vfy_cb(VALUE self, VALUE cb) { X509_STORE *store; GetX509Store(self, store); X509_STORE_set_ex_data(store, ossl_verify_cb_idx, (void*)cb); rb_iv_set(self, "@verify_callback", cb); return cb; } /* * call-seq: * X509::Store.new => store * */ static VALUE ossl_x509store_initialize(int argc, VALUE *argv, VALUE self) { X509_STORE *store; /* BUG: This method takes any number of arguments but appears to ignore them. */ GetX509Store(self, store); X509_STORE_set_verify_cb_func(store, ossl_verify_cb); ossl_x509store_set_vfy_cb(self, Qnil); #if (OPENSSL_VERSION_NUMBER < 0x00907000L) rb_iv_set(self, "@flags", INT2NUM(0)); rb_iv_set(self, "@purpose", INT2NUM(0)); rb_iv_set(self, "@trust", INT2NUM(0)); #endif /* last verification status */ rb_iv_set(self, "@error", Qnil); rb_iv_set(self, "@error_string", Qnil); rb_iv_set(self, "@chain", Qnil); rb_iv_set(self, "@time", Qnil); return self; } static VALUE ossl_x509store_set_flags(VALUE self, VALUE flags) { #if (OPENSSL_VERSION_NUMBER >= 0x00907000L) X509_STORE *store; long f = NUM2LONG(flags); GetX509Store(self, store); X509_STORE_set_flags(store, f); #else rb_iv_set(self, "@flags", flags); #endif return flags; } static VALUE ossl_x509store_set_purpose(VALUE self, VALUE purpose) { #if (OPENSSL_VERSION_NUMBER >= 0x00907000L) X509_STORE *store; long p = NUM2LONG(purpose); GetX509Store(self, store); X509_STORE_set_purpose(store, p); #else rb_iv_set(self, "@purpose", purpose); #endif return purpose; } static VALUE ossl_x509store_set_trust(VALUE self, VALUE trust) { #if (OPENSSL_VERSION_NUMBER >= 0x00907000L) X509_STORE *store; long t = NUM2LONG(trust); GetX509Store(self, store); X509_STORE_set_trust(store, t); #else rb_iv_set(self, "@trust", trust); #endif return trust; } static VALUE ossl_x509store_set_time(VALUE self, VALUE time) { rb_iv_set(self, "@time", time); return time; } static VALUE ossl_x509store_add_file(VALUE self, VALUE file) { X509_STORE *store; X509_LOOKUP *lookup; char *path = NULL; if(file != Qnil){ Check_SafeStr(file); path = RSTRING_PTR(file); } GetX509Store(self, store); lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); if(lookup == NULL) ossl_raise(eX509StoreError, NULL); if(X509_LOOKUP_load_file(lookup, path, X509_FILETYPE_PEM) != 1){ ossl_raise(eX509StoreError, NULL); } return self; } static VALUE ossl_x509store_add_path(VALUE self, VALUE dir) { X509_STORE *store; X509_LOOKUP *lookup; char *path = NULL; if(dir != Qnil){ Check_SafeStr(dir); path = RSTRING_PTR(dir); } GetX509Store(self, store); lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); if(lookup == NULL) ossl_raise(eX509StoreError, NULL); if(X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_PEM) != 1){ ossl_raise(eX509StoreError, NULL); } return self; } static VALUE ossl_x509store_set_default_paths(VALUE self) { X509_STORE *store; GetX509Store(self, store); if (X509_STORE_set_default_paths(store) != 1){ ossl_raise(eX509StoreError, NULL); } return Qnil; } static VALUE ossl_x509store_add_cert(VALUE self, VALUE arg) { X509_STORE *store; X509 *cert; cert = GetX509CertPtr(arg); /* NO NEED TO DUP */ GetX509Store(self, store); if (X509_STORE_add_cert(store, cert) != 1){ ossl_raise(eX509StoreError, NULL); } return self; } static VALUE ossl_x509store_add_crl(VALUE self, VALUE arg) { X509_STORE *store; X509_CRL *crl; crl = GetX509CRLPtr(arg); /* NO NEED TO DUP */ GetX509Store(self, store); if (X509_STORE_add_crl(store, crl) != 1){ ossl_raise(eX509StoreError, NULL); } return self; } static VALUE ossl_x509stctx_get_err(VALUE); static VALUE ossl_x509stctx_get_err_string(VALUE); static VALUE ossl_x509stctx_get_chain(VALUE); static VALUE ossl_x509store_verify(int argc, VALUE *argv, VALUE self) { VALUE cert, chain; VALUE ctx, proc, result; rb_scan_args(argc, argv, "11", &cert, &chain); ctx = rb_funcall(cX509StoreContext, rb_intern("new"), 3, self, cert, chain); proc = rb_block_given_p() ? rb_block_proc() : rb_iv_get(self, "@verify_callback"); rb_iv_set(ctx, "@verify_callback", proc); result = rb_funcall(ctx, rb_intern("verify"), 0); rb_iv_set(self, "@error", ossl_x509stctx_get_err(ctx)); rb_iv_set(self, "@error_string", ossl_x509stctx_get_err_string(ctx)); rb_iv_set(self, "@chain", ossl_x509stctx_get_chain(ctx)); return result; } /* * Public Functions */ static void ossl_x509stctx_free(X509_STORE_CTX*); VALUE ossl_x509stctx_new(X509_STORE_CTX *ctx) { VALUE obj; WrapX509StCtx(cX509StoreContext, obj, ctx); return obj; } VALUE ossl_x509stctx_clear_ptr(VALUE obj) { OSSL_Check_Kind(obj, cX509StoreContext); RDATA(obj)->data = NULL; return obj; } /* * Private functions */ static void ossl_x509stctx_free(X509_STORE_CTX *ctx) { if(ctx->untrusted) sk_X509_pop_free(ctx->untrusted, X509_free); if(ctx->cert) X509_free(ctx->cert); X509_STORE_CTX_free(ctx); } static VALUE ossl_x509stctx_alloc(VALUE klass) { X509_STORE_CTX *ctx; VALUE obj; if((ctx = X509_STORE_CTX_new()) == NULL){ ossl_raise(eX509StoreError, NULL); } WrapX509StCtx(klass, obj, ctx); return obj; } static VALUE ossl_x509stctx_set_flags(VALUE, VALUE); static VALUE ossl_x509stctx_set_purpose(VALUE, VALUE); static VALUE ossl_x509stctx_set_trust(VALUE, VALUE); static VALUE ossl_x509stctx_set_time(VALUE, VALUE); static VALUE ossl_x509stctx_initialize(int argc, VALUE *argv, VALUE self) { VALUE store, cert, chain, t; X509_STORE_CTX *ctx; X509_STORE *x509st; X509 *x509 = NULL; STACK_OF(X509) *x509s = NULL; rb_scan_args(argc, argv, "12", &store, &cert, &chain); GetX509StCtx(self, ctx); SafeGetX509Store(store, x509st); if(!NIL_P(cert)) x509 = DupX509CertPtr(cert); /* NEED TO DUP */ if(!NIL_P(chain)) x509s = ossl_x509_ary2sk(chain); #if (OPENSSL_VERSION_NUMBER >= 0x00907000L) if(X509_STORE_CTX_init(ctx, x509st, x509, x509s) != 1){ sk_X509_pop_free(x509s, X509_free); ossl_raise(eX509StoreError, NULL); } #else X509_STORE_CTX_init(ctx, x509st, x509, x509s); ossl_x509stctx_set_flags(self, rb_iv_get(store, "@flags")); ossl_x509stctx_set_purpose(self, rb_iv_get(store, "@purpose")); ossl_x509stctx_set_trust(self, rb_iv_get(store, "@trust")); #endif if (!NIL_P(t = rb_iv_get(store, "@time"))) ossl_x509stctx_set_time(self, t); rb_iv_set(self, "@verify_callback", rb_iv_get(store, "@verify_callback")); rb_iv_set(self, "@cert", cert); return self; } static VALUE ossl_x509stctx_verify(VALUE self) { X509_STORE_CTX *ctx; int result; GetX509StCtx(self, ctx); X509_STORE_CTX_set_ex_data(ctx, ossl_verify_cb_idx, (void*)rb_iv_get(self, "@verify_callback")); result = X509_verify_cert(ctx); return result ? Qtrue : Qfalse; } static VALUE ossl_x509stctx_get_chain(VALUE self) { X509_STORE_CTX *ctx; STACK_OF(X509) *chain; X509 *x509; int i, num; VALUE ary; GetX509StCtx(self, ctx); if((chain = X509_STORE_CTX_get_chain(ctx)) == NULL){ return Qnil; } if((num = sk_X509_num(chain)) < 0){ OSSL_Debug("certs in chain < 0???"); return rb_ary_new(); } ary = rb_ary_new2(num); for(i = 0; i < num; i++) { x509 = sk_X509_value(chain, i); rb_ary_push(ary, ossl_x509_new(x509)); } return ary; } static VALUE ossl_x509stctx_get_err(VALUE self) { X509_STORE_CTX *ctx; GetX509StCtx(self, ctx); return INT2FIX(X509_STORE_CTX_get_error(ctx)); } static VALUE ossl_x509stctx_set_error(VALUE self, VALUE err) { X509_STORE_CTX *ctx; GetX509StCtx(self, ctx); X509_STORE_CTX_set_error(ctx, NUM2INT(err)); return err; } static VALUE ossl_x509stctx_get_err_string(VALUE self) { X509_STORE_CTX *ctx; long err; GetX509StCtx(self, ctx); err = X509_STORE_CTX_get_error(ctx); return rb_str_new2(X509_verify_cert_error_string(err)); } static VALUE ossl_x509stctx_get_err_depth(VALUE self) { X509_STORE_CTX *ctx; GetX509StCtx(self, ctx); return INT2FIX(X509_STORE_CTX_get_error_depth(ctx)); } static VALUE ossl_x509stctx_get_curr_cert(VALUE self) { X509_STORE_CTX *ctx; GetX509StCtx(self, ctx); return ossl_x509_new(X509_STORE_CTX_get_current_cert(ctx)); } static VALUE ossl_x509stctx_get_curr_crl(VALUE self) { #if (OPENSSL_VERSION_NUMBER >= 0x00907000L) X509_STORE_CTX *ctx; GetX509StCtx(self, ctx); if(!ctx->current_crl) return Qnil; return ossl_x509crl_new(ctx->current_crl); #else return Qnil; #endif } static VALUE ossl_x509stctx_cleanup(VALUE self) { X509_STORE_CTX *ctx; GetX509StCtx(self, ctx); X509_STORE_CTX_cleanup(ctx); return self; } static VALUE ossl_x509stctx_set_flags(VALUE self, VALUE flags) { X509_STORE_CTX *store; long f = NUM2LONG(flags); GetX509StCtx(self, store); X509_STORE_CTX_set_flags(store, f); return flags; } static VALUE ossl_x509stctx_set_purpose(VALUE self, VALUE purpose) { X509_STORE_CTX *store; long p = NUM2LONG(purpose); GetX509StCtx(self, store); X509_STORE_CTX_set_purpose(store, p); return purpose; } static VALUE ossl_x509stctx_set_trust(VALUE self, VALUE trust) { X509_STORE_CTX *store; long t = NUM2LONG(trust); GetX509StCtx(self, store); X509_STORE_CTX_set_trust(store, t); return trust; } /* * call-seq: * storectx.time = time => time */ static VALUE ossl_x509stctx_set_time(VALUE self, VALUE time) { X509_STORE_CTX *store; long t; t = NUM2LONG(rb_Integer(time)); GetX509StCtx(self, store); X509_STORE_CTX_set_time(store, 0, t); return time; } /* * INIT */ void Init_ossl_x509store() { VALUE x509stctx; eX509StoreError = rb_define_class_under(mX509, "StoreError", eOSSLError); cX509Store = rb_define_class_under(mX509, "Store", rb_cObject); rb_attr(cX509Store, rb_intern("verify_callback"), 1, 0, Qfalse); rb_attr(cX509Store, rb_intern("error"), 1, 0, Qfalse); rb_attr(cX509Store, rb_intern("error_string"), 1, 0, Qfalse); rb_attr(cX509Store, rb_intern("chain"), 1, 0, Qfalse); rb_define_alloc_func(cX509Store, ossl_x509store_alloc); rb_define_method(cX509Store, "initialize", ossl_x509store_initialize, -1); rb_define_method(cX509Store, "verify_callback=", ossl_x509store_set_vfy_cb, 1); rb_define_method(cX509Store, "flags=", ossl_x509store_set_flags, 1); rb_define_method(cX509Store, "purpose=", ossl_x509store_set_purpose, 1); rb_define_method(cX509Store, "trust=", ossl_x509store_set_trust, 1); rb_define_method(cX509Store, "time=", ossl_x509store_set_time, 1); rb_define_method(cX509Store, "add_path", ossl_x509store_add_path, 1); rb_define_method(cX509Store, "add_file", ossl_x509store_add_file, 1); rb_define_method(cX509Store, "set_default_paths", ossl_x509store_set_default_paths, 0); rb_define_method(cX509Store, "add_cert", ossl_x509store_add_cert, 1); rb_define_method(cX509Store, "add_crl", ossl_x509store_add_crl, 1); rb_define_method(cX509Store, "verify", ossl_x509store_verify, -1); cX509StoreContext = rb_define_class_under(mX509,"StoreContext",rb_cObject); x509stctx = cX509StoreContext; rb_define_alloc_func(cX509StoreContext, ossl_x509stctx_alloc); rb_define_method(x509stctx,"initialize", ossl_x509stctx_initialize, -1); rb_define_method(x509stctx,"verify", ossl_x509stctx_verify, 0); rb_define_method(x509stctx,"chain", ossl_x509stctx_get_chain,0); rb_define_method(x509stctx,"error", ossl_x509stctx_get_err, 0); rb_define_method(x509stctx,"error=", ossl_x509stctx_set_error, 1); rb_define_method(x509stctx,"error_string",ossl_x509stctx_get_err_string,0); rb_define_method(x509stctx,"error_depth", ossl_x509stctx_get_err_depth, 0); rb_define_method(x509stctx,"current_cert",ossl_x509stctx_get_curr_cert, 0); rb_define_method(x509stctx,"current_crl", ossl_x509stctx_get_curr_crl, 0); rb_define_method(x509stctx,"cleanup", ossl_x509stctx_cleanup, 0); rb_define_method(x509stctx,"flags=", ossl_x509stctx_set_flags, 1); rb_define_method(x509stctx,"purpose=", ossl_x509stctx_set_purpose, 1); rb_define_method(x509stctx,"trust=", ossl_x509stctx_set_trust, 1); rb_define_method(x509stctx,"time=", ossl_x509stctx_set_time, 1); } ================================================ FILE: ext/openssl/ruby_missing.h ================================================ /* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2003 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(_OSSL_RUBY_MISSING_H_) #define _OSSL_RUBY_MISSING_H_ #define rb_define_copy_func(klass, func) \ rb_define_method(klass, "initialize_copy", func, 1) #ifndef GetReadFile #define FPTR_TO_FD(fptr) (fptr->fd) #else #define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr))) #endif #ifndef HAVE_RB_IO_T #define rb_io_t OpenFile #endif #ifndef HAVE_RB_STR_SET_LEN /* these methods should probably be backported to 1.8 */ #define rb_str_set_len(str, length) do { \ RSTRING(str)->ptr[length] = 0; \ RSTRING(str)->len = length; \ } while(0) #endif /* ! HAVE_RB_STR_SET_LEN */ #ifndef HAVE_RB_BLOCK_CALL /* the openssl module doesn't use arg[3-4] and arg2 is always rb_each */ #define rb_block_call(arg1, arg2, arg3, arg4, arg5, arg6) rb_iterate(rb_each, arg1, arg5, arg6) #endif /* ! HAVE_RB_BLOCK_CALL */ #endif /* _OSSL_RUBY_MISSING_H_ */ ================================================ FILE: ext/pty/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/pty/README ================================================ 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. When the child process is suspended or finished, an exception is raised. If this function is called with an iterator block, exception is raised only within the block. Child process monitor is terminated on block exit. protect_signal reset_signal These functions are obsolete in this version of pty. 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. ================================================ FILE: ext/pty/README.expect ================================================ 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. ================================================ FILE: ext/pty/README.expect.ja ================================================ 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֤ޤ Υ᥽åɤ֥åդǸƤФ줿ˤϡޥåǤ 󤬥֥åȤϤ졤֥åɾޤ ================================================ FILE: ext/pty/README.ja ================================================ 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 ޤŻҥ᡼ǥХݡȤ꤯ ================================================ FILE: ext/pty/depend ================================================ pty.o: pty.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h ================================================ FILE: ext/pty/expect_sample.rb ================================================ # # sample program of expect.rb # # by A. Ito # # This program reports the latest version of ruby interpreter # by connecting to ftp server at ruby-lang.org. # require 'pty' require 'expect' fnames = [] PTY.spawn("ftp ftp.ruby-lang.org") do |r_f,w_f,pid| w_f.sync = true $expect_verbose = false if !ENV['USER'].nil? username = ENV['USER'] elsif !ENV['LOGNAME'].nil? username = ENV['LOGNAME'] else username = 'guest' end r_f.expect(/^(Name).*: |(word):|> /) do w_f.puts($1 ? "ftp" : $2 ? "#{username}@" : "cd pub/ruby") end r_f.expect("> ") do w_f.print "dir\n" end r_f.expect(/[^\-]> /) 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" ================================================ FILE: ext/pty/extconf.rb ================================================ require 'mkmf' if /mswin32|mingw|bccwin32/ !~ RUBY_PLATFORM have_header("sys/stropts.h") have_func("setresuid") have_header("libutil.h") have_header("pty.h") have_library("util", "openpty") if have_func("openpty") or have_func("_getpty") or have_func("ptsname") or have_func("ioctl") create_makefile('pty') end end ================================================ FILE: ext/pty/lib/expect.rb ================================================ $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) or eof? then result = nil break end c = getc.chr buf << c if $expect_verbose STDOUT.print c STDOUT.flush end if mat=e_pat.match(buf) then result = [buf,*mat.to_a[1..-1]] break end end if block_given? then yield result else return result end nil end end ================================================ FILE: ext/pty/pty.c ================================================ #include "config.h" #include #include #include #include #include #include #include #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_LIBUTIL_H #include #endif #ifdef HAVE_PTY_H #include #endif #ifdef HAVE_SYS_WAIT_H #include #else #define WIFSTOPPED(status) (((status) & 0xff) == 0x7f) #endif #include #include "ruby.h" #include "rubyio.h" #include "util.h" #include #ifdef HAVE_SYS_STROPTS_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #define DEVICELEN 16 #if !defined(HAVE_OPENPTY) #if defined(__hpux) static const char MasterDevice[] = "/dev/ptym/pty%s", SlaveDevice[] = "/dev/pty/tty%s", *const 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, }; #elif defined(_IBMESA) /* AIX/ESA */ static const char MasterDevice[] = "/dev/ptyp%s", SlaveDevice[] = "/dev/ttyp%s", *const 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", }; #elif !defined(HAVE_PTSNAME) static const char MasterDevice[] = "/dev/pty%s", SlaveDevice[] = "/dev/tty%s", *const 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", 0, }; #endif #endif /* !defined(HAVE_OPENPTY) */ #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 */ static VALUE eChildExited; static VALUE echild_status(self) VALUE self; { return rb_ivar_get(self, rb_intern("status")); } struct pty_info { int fd; rb_pid_t child_pid; VALUE thread; }; static void raise_from_wait(state, info) struct pty_info *info; char *state; { extern VALUE rb_last_status; char buf[1024]; VALUE exc; snprintf(buf, sizeof(buf), "pty - %s: %ld", state, (long)info->child_pid); exc = rb_exc_new2(eChildExited, buf); rb_iv_set(exc, "status", rb_last_status); rb_funcall(info->thread, rb_intern("raise"), 1, exc); } static VALUE pty_syswait(info) struct pty_info *info; { int cpid, status; for (;;) { cpid = rb_waitpid(info->child_pid, &status, WUNTRACED); if (cpid == -1) return Qnil; #if defined(WIFSTOPPED) #elif defined(IF_STOPPED) #define WIFSTOPPED(status) IF_STOPPED(status) #else ---->> Either IF_STOPPED or WIFSTOPPED is needed <<---- #endif /* WIFSTOPPED | IF_STOPPED */ if (WIFSTOPPED(status)) { /* suspend */ raise_from_wait("stopped", info); } else if (kill(info->child_pid, 0) == 0) { raise_from_wait("changed", info); } else { raise_from_wait("exited", info); return Qnil; } } } static void getDevice _((int*, int*, char [DEVICELEN])); struct exec_info { int argc; VALUE *argv; }; static VALUE pty_exec _((VALUE v)); static VALUE pty_exec(v) VALUE v; { struct exec_info *arg = (struct exec_info *)v; return rb_f_exec(arg->argc, arg->argv); } static void establishShell(argc, argv, info, SlaveName) int argc; VALUE *argv; struct pty_info *info; char SlaveName[DEVICELEN]; { int i,master,slave; char *p, tmp, *getenv(); struct passwd *pwent; VALUE v; struct exec_info arg; int status; if (argc == 0) { char *shellname; if ((p = getenv("SHELL")) != NULL) { shellname = p; } else { pwent = getpwuid(getuid()); if (pwent && pwent->pw_shell) shellname = pwent->pw_shell; else shellname = "/bin/sh"; } v = rb_str_new2(shellname); argc = 1; argv = &v; } getDevice(&master, &slave, SlaveName); info->thread = rb_thread_current(); if((i = fork()) < 0) { close(master); close(slave); rb_sys_fail("fork failed"); } if(i == 0) { /* child */ /* * 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, getpid()) == -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 write(slave, "", 1); dup2(slave,0); dup2(slave,1); dup2(slave,2); close(slave); #if defined(HAVE_SETEUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRESUID) seteuid(getuid()); #endif arg.argc = argc; arg.argv = argv; rb_protect(pty_exec, (VALUE)&arg, &status); sleep(1); _exit(1); } read(master, &tmp, 1); close(slave); info->child_pid = i; info->fd = master; } static VALUE pty_finalize_syswait(info) struct pty_info *info; { rb_thread_kill(info->thread); rb_funcall(info->thread, rb_intern("value"), 0); rb_detach_process(info->child_pid); return Qnil; } static int get_device_once(master, slave, SlaveName, fail) int *master, *slave, fail; char SlaveName[DEVICELEN]; { #if defined HAVE_OPENPTY /* * Use openpty(3) of 4.3BSD Reno and later, * or the same interface function. */ if (openpty(master, slave, SlaveName, (struct termios *)0, (struct winsize *)0) == -1) { if (!fail) return -1; rb_raise(rb_eRuntimeError, "openpty() failed"); } return 0; #elif defined HAVE__GETPTY char *name; if (!(name = _getpty(master, O_RDWR, 0622, 0))) { if (!fail) return -1; rb_raise(rb_eRuntimeError, "_getpty() failed"); } *slave = open(name, O_RDWR); strncpy(SlaveName, name, sizeof SlaveName); return 0; #else /* HAVE__GETPTY */ int i,j; #ifdef HAVE_PTSNAME 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 defined I_PUSH && !defined linux if(ioctl(j, I_PUSH, "ptem") != -1) { if(ioctl(j, I_PUSH, "ldterm") != -1) { ioctl(j, I_PUSH, "ttcompat"); #endif *master = i; *slave = j; strncpy(SlaveName, pn, sizeof SlaveName); return 0; #if defined I_PUSH && !defined linux } } #endif } } } } close(i); } if (!fail) rb_raise(rb_eRuntimeError, "can't get Master/Slave device"); return -1; #else char **p; char MasterName[DEVICELEN]; for (p = deviceNo; *p != NULL; p++) { snprintf(MasterName, sizeof MasterName, MasterDevice, *p); if ((i = open(MasterName,O_RDWR,0)) >= 0) { *master = i; snprintf(SlaveName, sizeof SlaveName, SlaveDevice, *p); if ((j = open(SlaveName,O_RDWR,0)) >= 0) { *slave = j; chown(SlaveName, getuid(), getgid()); chmod(SlaveName, 0622); return 0; } close(i); } } if (fail) rb_raise(rb_eRuntimeError, "can't get %s", SlaveName); return -1; #endif #endif } static void getDevice(master, slave, slavename) int *master, *slave; char slavename[DEVICELEN]; { if (get_device_once(master, slave, slavename, 0)) { rb_gc(); get_device_once(master, slave, slavename, 1); } } /* ruby function: getpty */ static VALUE pty_getpty(argc, argv, self) int argc; VALUE *argv; VALUE self; { VALUE res; struct pty_info info; struct pty_info thinfo; rb_io_t *wfptr,*rfptr; VALUE rport = rb_obj_alloc(rb_cFile); VALUE wport = rb_obj_alloc(rb_cFile); char SlaveName[DEVICELEN]; MakeOpenFile(rport, rfptr); MakeOpenFile(wport, wfptr); establishShell(argc, argv, &info, SlaveName); rfptr->mode = rb_io_mode_flags("r"); rfptr->f = fdopen(info.fd, "r"); rfptr->path = strdup(SlaveName); wfptr->mode = rb_io_mode_flags("w") | FMODE_SYNC; wfptr->f = fdopen(dup(info.fd), "w"); wfptr->path = strdup(SlaveName); res = rb_ary_new2(3); rb_ary_store(res,0,(VALUE)rport); rb_ary_store(res,1,(VALUE)wport); rb_ary_store(res,2,INT2FIX(info.child_pid)); thinfo.thread = rb_thread_create(pty_syswait, (void*)&info); thinfo.child_pid = info.child_pid; rb_thread_schedule(); if (rb_block_given_p()) { rb_ensure(rb_yield, res, pty_finalize_syswait, (VALUE)&thinfo); return Qnil; } return res; } /* ruby function: protect_signal - obsolete */ static VALUE pty_protect(self) VALUE self; { rb_warn("PTY::protect_signal is no longer needed"); rb_yield(Qnil); return self; } /* ruby function: reset_signal - obsolete */ static VALUE pty_reset_signal(self) VALUE self; { rb_warn("PTY::reset_signal is no longer needed"); 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); eChildExited = rb_define_class_under(cPTY,"ChildExited",rb_eRuntimeError); rb_define_method(eChildExited,"status",echild_status,0); } ================================================ FILE: ext/pty/script.rb ================================================ 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,pid| Thread.new do while true w_pty.print STDIN.getc.chr w_pty.flush end end begin while true c = r_pty.sysread(512) break if c.nil? print c STDOUT.flush logfile.print c end rescue # print $@,':',$!,"\n" logfile.close end end system "stty echo -raw lnext ^v" ================================================ FILE: ext/pty/shl.rb ================================================ # # 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 system "stty -echo raw" 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 system "stty echo -raw" 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 ================================================ FILE: ext/purelib.rb ================================================ nul = nil $:.each_with_index {|path, index| if /\A(?:\.\/)*-\z/ =~ path nul = index break end } if nul $:[nul..-1] = ["."] end ================================================ FILE: ext/racc/cparse/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/racc/cparse/cparse.c ================================================ /* cparse.c -- Racc Runtime Core Copyright (c) 1999-2006 Minero Aoki This library is free software. You can distribute/modify this program under the same terms of ruby. $originalId: cparse.c,v 1.8 2006/07/06 11:39:46 aamine Exp $ */ #include "ruby.h" #include "version.h" /* ----------------------------------------------------------------------- Important Constants ----------------------------------------------------------------------- */ #define RACC_VERSION "1.4.5" #define DEFAULT_TOKEN -1 #define ERROR_TOKEN 1 #define FINAL_TOKEN 0 #define vDEFAULT_TOKEN INT2FIX(DEFAULT_TOKEN) #define vERROR_TOKEN INT2FIX(ERROR_TOKEN) #define vFINAL_TOKEN INT2FIX(FINAL_TOKEN) /* ----------------------------------------------------------------------- File Local Variables ----------------------------------------------------------------------- */ static VALUE RaccBug; static VALUE CparseParams; static ID id_yydebug; static ID id_nexttoken; static ID id_onerror; static ID id_noreduce; static ID id_errstatus; static ID id_d_shift; static ID id_d_reduce; static ID id_d_accept; static ID id_d_read_token; static ID id_d_next_state; static ID id_d_e_pop; /* ----------------------------------------------------------------------- Utils ----------------------------------------------------------------------- */ /* For backward compatibility */ #ifndef ID2SYM # define ID2SYM(i) ULONG2NUM(i) #endif #ifndef SYM2ID # define SYM2ID(v) ((ID)NUM2ULONG(v)) #endif #ifndef SYMBOL_P # define SYMBOL_P(v) FIXNUM_P(v) #endif #ifndef LONG2NUM # define LONG2NUM(i) INT2NUM(i) #endif #if RUBY_VERSION_CODE >= 190 # define HAVE_RB_BLOCK_CALL 1 #endif static ID value_to_id _((VALUE v)); static inline long num_to_long _((VALUE n)); static ID value_to_id(VALUE v) { if (! SYMBOL_P(v)) { rb_raise(rb_eTypeError, "not symbol"); } return SYM2ID(v); } static inline long num_to_long(VALUE n) { return NUM2LONG(n); } #define AREF(s, idx) \ ((0 <= idx && idx < RARRAY(s)->len) ? RARRAY(s)->ptr[idx] : Qnil) /* ----------------------------------------------------------------------- Parser Stack Interfaces ----------------------------------------------------------------------- */ static VALUE get_stack_tail _((VALUE stack, long len)); static void cut_stack_tail _((VALUE stack, long len)); static VALUE get_stack_tail(VALUE stack, long len) { if (len < 0) return Qnil; /* system error */ if (len > RARRAY(stack)->len) len = RARRAY(stack)->len; return rb_ary_new4(len, RARRAY(stack)->ptr + RARRAY(stack)->len - len); } static void cut_stack_tail(VALUE stack, long len) { while (len > 0) { rb_ary_pop(stack); len--; } } #define STACK_INIT_LEN 64 #define NEW_STACK() rb_ary_new2(STACK_INIT_LEN) #define PUSH(s, i) rb_ary_store(s, RARRAY(s)->len, i) #define POP(s) rb_ary_pop(s) #define LAST_I(s) \ ((RARRAY(s)->len > 0) ? RARRAY(s)->ptr[RARRAY(s)->len - 1] : Qnil) #define GET_TAIL(s, len) get_stack_tail(s, len) #define CUT_TAIL(s, len) cut_stack_tail(s, len) /* ----------------------------------------------------------------------- struct cparse_params ----------------------------------------------------------------------- */ struct cparse_params { VALUE value_v; /* VALUE version of this struct */ VALUE parser; /* parser object */ int lex_is_iterator; VALUE lexer; /* scanner object */ ID lexmid; /* name of scanner method (must be an iterator) */ /* State transition tables (immutable) Data structure is from Dragon Book 4.9 */ /* action table */ VALUE action_table; VALUE action_check; VALUE action_default; VALUE action_pointer; /* goto table */ VALUE goto_table; VALUE goto_check; VALUE goto_default; VALUE goto_pointer; long nt_base; /* NonTerminal BASE index */ VALUE reduce_table; /* reduce data table */ VALUE token_table; /* token conversion table */ /* parser stacks and parameters */ VALUE state; long curstate; VALUE vstack; VALUE tstack; VALUE t; long shift_n; long reduce_n; long ruleno; long errstatus; /* nonzero in error recovering mode */ long nerr; /* number of error */ int use_result_var; VALUE retval; /* return value of parser routine */ long fin; /* parse result status */ #define CP_FIN_ACCEPT 1 #define CP_FIN_EOT 2 #define CP_FIN_CANTPOP 3 int debug; /* user level debug */ int sys_debug; /* system level debug */ long i; /* table index */ }; /* ----------------------------------------------------------------------- Parser Main Routines ----------------------------------------------------------------------- */ static VALUE racc_cparse _((VALUE parser, VALUE arg, VALUE sysdebug)); static VALUE racc_yyparse _((VALUE parser, VALUE lexer, VALUE lexmid, VALUE arg, VALUE sysdebug)); static void call_lexer _((struct cparse_params *v)); static VALUE lexer_i _((VALUE block_args, VALUE data, VALUE self)); static VALUE assert_array _((VALUE a)); static long assert_integer _((VALUE n)); static VALUE assert_hash _((VALUE h)); static VALUE initialize_params _((VALUE vparams, VALUE parser, VALUE arg, VALUE lexer, VALUE lexmid)); static void cparse_params_mark _((void *ptr)); static void parse_main _((struct cparse_params *v, VALUE tok, VALUE val, int resume)); static void extract_user_token _((struct cparse_params *v, VALUE block_args, VALUE *tok, VALUE *val)); static void shift _((struct cparse_params* v, long act, VALUE tok, VALUE val)); static int reduce _((struct cparse_params* v, long act)); static VALUE reduce0 _((VALUE block_args, VALUE data, VALUE self)); #ifdef DEBUG # define D_puts(msg) if (v->sys_debug) puts(msg) # define D_printf(fmt,arg) if (v->sys_debug) printf(fmt,arg) #else # define D_puts(msg) # define D_printf(fmt,arg) #endif static VALUE racc_cparse(VALUE parser, VALUE arg, VALUE sysdebug) { volatile VALUE vparams; struct cparse_params *v; vparams = Data_Make_Struct(CparseParams, struct cparse_params, cparse_params_mark, -1, v); D_puts("starting cparse"); v->sys_debug = RTEST(sysdebug); vparams = initialize_params(vparams, parser, arg, Qnil, Qnil); v->lex_is_iterator = Qfalse; parse_main(v, Qnil, Qnil, 0); return v->retval; } static VALUE racc_yyparse(VALUE parser, VALUE lexer, VALUE lexmid, VALUE arg, VALUE sysdebug) { volatile VALUE vparams; struct cparse_params *v; vparams = Data_Make_Struct(CparseParams, struct cparse_params, cparse_params_mark, -1, v); v->sys_debug = RTEST(sysdebug); D_puts("start C yyparse"); vparams = initialize_params(vparams, parser, arg, lexer, lexmid); v->lex_is_iterator = Qtrue; D_puts("params initialized"); parse_main(v, Qnil, Qnil, 0); call_lexer(v); if (!v->fin) { rb_raise(rb_eArgError, "%s() is finished before EndOfToken", rb_id2name(v->lexmid)); } return v->retval; } #ifdef HAVE_RB_BLOCK_CALL static void call_lexer(struct cparse_params *v) { rb_block_call(v->lexer, v->lexmid, 0, NULL, lexer_i, v->value_v); } #else static VALUE lexer_iter(VALUE data) { struct cparse_params *v; Data_Get_Struct(data, struct cparse_params, v); rb_funcall(v->lexer, v->lexmid, 0); return Qnil; } static void call_lexer(struct cparse_params *v) { rb_iterate(lexer_iter, v->value_v, lexer_i, v->value_v); } #endif static VALUE lexer_i(VALUE block_args, VALUE data, VALUE self) { struct cparse_params *v; VALUE tok, val; Data_Get_Struct(data, struct cparse_params, v); if (v->fin) rb_raise(rb_eArgError, "extra token after EndOfToken"); extract_user_token(v, block_args, &tok, &val); parse_main(v, tok, val, 1); if (v->fin && v->fin != CP_FIN_ACCEPT) rb_iter_break(); return Qnil; } static VALUE assert_array(VALUE a) { Check_Type(a, T_ARRAY); return a; } static VALUE assert_hash(VALUE h) { Check_Type(h, T_HASH); return h; } static long assert_integer(VALUE n) { return NUM2LONG(n); } static VALUE initialize_params(VALUE vparams, VALUE parser, VALUE arg, VALUE lexer, VALUE lexmid) { struct cparse_params *v; Data_Get_Struct(vparams, struct cparse_params, v); v->value_v = vparams; v->parser = parser; v->lexer = lexer; if (! NIL_P(lexmid)) v->lexmid = value_to_id(lexmid); v->debug = RTEST(rb_ivar_get(parser, id_yydebug)); Check_Type(arg, T_ARRAY); if (!(13 <= RARRAY(arg)->len && RARRAY(arg)->len <= 14)) rb_raise(RaccBug, "[Racc Bug] wrong arg.size %ld", RARRAY(arg)->len); v->action_table = assert_array (RARRAY(arg)->ptr[ 0]); v->action_check = assert_array (RARRAY(arg)->ptr[ 1]); v->action_default = assert_array (RARRAY(arg)->ptr[ 2]); v->action_pointer = assert_array (RARRAY(arg)->ptr[ 3]); v->goto_table = assert_array (RARRAY(arg)->ptr[ 4]); v->goto_check = assert_array (RARRAY(arg)->ptr[ 5]); v->goto_default = assert_array (RARRAY(arg)->ptr[ 6]); v->goto_pointer = assert_array (RARRAY(arg)->ptr[ 7]); v->nt_base = assert_integer(RARRAY(arg)->ptr[ 8]); v->reduce_table = assert_array (RARRAY(arg)->ptr[ 9]); v->token_table = assert_hash (RARRAY(arg)->ptr[10]); v->shift_n = assert_integer(RARRAY(arg)->ptr[11]); v->reduce_n = assert_integer(RARRAY(arg)->ptr[12]); if (RARRAY(arg)->len > 13) { v->use_result_var = RTEST(RARRAY(arg)->ptr[13]); } else { v->use_result_var = Qtrue; } v->tstack = v->debug ? NEW_STACK() : Qnil; v->vstack = NEW_STACK(); v->state = NEW_STACK(); v->curstate = 0; PUSH(v->state, INT2FIX(0)); v->t = INT2FIX(FINAL_TOKEN + 1); /* must not init to FINAL_TOKEN */ v->nerr = 0; v->errstatus = 0; rb_ivar_set(parser, id_errstatus, LONG2NUM(v->errstatus)); v->retval = Qnil; v->fin = 0; v->lex_is_iterator = Qfalse; rb_iv_set(parser, "@vstack", v->vstack); if (v->debug) { rb_iv_set(parser, "@tstack", v->tstack); } else { rb_iv_set(parser, "@tstack", Qnil); } return vparams; } static void cparse_params_mark(void *ptr) { struct cparse_params *v = (struct cparse_params*)ptr; rb_gc_mark(v->value_v); rb_gc_mark(v->parser); rb_gc_mark(v->lexer); rb_gc_mark(v->action_table); rb_gc_mark(v->action_check); rb_gc_mark(v->action_default); rb_gc_mark(v->action_pointer); rb_gc_mark(v->goto_table); rb_gc_mark(v->goto_check); rb_gc_mark(v->goto_default); rb_gc_mark(v->goto_pointer); rb_gc_mark(v->reduce_table); rb_gc_mark(v->token_table); rb_gc_mark(v->state); rb_gc_mark(v->vstack); rb_gc_mark(v->tstack); rb_gc_mark(v->t); rb_gc_mark(v->retval); } static void extract_user_token(struct cparse_params *v, VALUE block_args, VALUE *tok, VALUE *val) { if (NIL_P(block_args)) { /* EOF */ *tok = Qfalse; *val = rb_str_new("$", 1); return; } if (TYPE(block_args) != T_ARRAY) { rb_raise(rb_eTypeError, "%s() %s %s (must be Array[2])", v->lex_is_iterator ? rb_id2name(v->lexmid) : "next_token", v->lex_is_iterator ? "yielded" : "returned", rb_class2name(CLASS_OF(block_args))); } if (RARRAY(block_args)->len != 2) { rb_raise(rb_eArgError, "%s() %s wrong size of array (%ld for 2)", v->lex_is_iterator ? rb_id2name(v->lexmid) : "next_token", v->lex_is_iterator ? "yielded" : "returned", RARRAY(block_args)->len); } *tok = AREF(block_args, 0); *val = AREF(block_args, 1); } #define SHIFT(v,act,tok,val) shift(v,act,tok,val) #define REDUCE(v,act) do {\ switch (reduce(v,act)) { \ case 0: /* normal */ \ break; \ case 1: /* yyerror */ \ goto user_yyerror; \ case 2: /* yyaccept */ \ D_puts("u accept"); \ goto accept; \ default: \ break; \ } \ } while (0) static void parse_main(struct cparse_params *v, VALUE tok, VALUE val, int resume) { long i; /* table index */ long act; /* action type */ VALUE act_value; /* action type, VALUE version */ int read_next = 1; /* true if we need to read next token */ VALUE tmp; if (resume) goto resume; while (1) { D_puts(""); D_puts("---- enter new loop ----"); D_puts(""); D_printf("(act) k1=%ld\n", v->curstate); tmp = AREF(v->action_pointer, v->curstate); if (NIL_P(tmp)) goto notfound; D_puts("(act) pointer[k1] ok"); i = NUM2LONG(tmp); D_printf("read_next=%d\n", read_next); if (read_next && (v->t != vFINAL_TOKEN)) { if (v->lex_is_iterator) { D_puts("resuming..."); if (v->fin) rb_raise(rb_eArgError, "token given after EOF"); v->i = i; /* save i */ return; resume: D_puts("resumed"); i = v->i; /* load i */ } else { D_puts("next_token"); tmp = rb_funcall(v->parser, id_nexttoken, 0); extract_user_token(v, tmp, &tok, &val); } /* convert token */ v->t = rb_hash_aref(v->token_table, tok); if (NIL_P(v->t)) { v->t = vERROR_TOKEN; } D_printf("(act) t(k2)=%ld\n", NUM2LONG(v->t)); if (v->debug) { rb_funcall(v->parser, id_d_read_token, 3, v->t, tok, val); } } read_next = 0; i += NUM2LONG(v->t); D_printf("(act) i=%ld\n", i); if (i < 0) goto notfound; act_value = AREF(v->action_table, i); if (NIL_P(act_value)) goto notfound; act = NUM2LONG(act_value); D_printf("(act) table[i]=%ld\n", act); tmp = AREF(v->action_check, i); if (NIL_P(tmp)) goto notfound; if (NUM2LONG(tmp) != v->curstate) goto notfound; D_printf("(act) check[i]=%ld\n", NUM2LONG(tmp)); D_puts("(act) found"); act_fixed: D_printf("act=%ld\n", act); goto handle_act; notfound: D_puts("(act) not found: use default"); act_value = AREF(v->action_default, v->curstate); act = NUM2LONG(act_value); goto act_fixed; handle_act: if (act > 0 && act < v->shift_n) { D_puts("shift"); if (v->errstatus > 0) { v->errstatus--; rb_ivar_set(v->parser, id_errstatus, LONG2NUM(v->errstatus)); } SHIFT(v, act, v->t, val); read_next = 1; } else if (act < 0 && act > -(v->reduce_n)) { D_puts("reduce"); REDUCE(v, act); } else if (act == -(v->reduce_n)) { goto error; error_recovered: ; /* goto label requires stmt */ } else if (act == v->shift_n) { D_puts("accept"); goto accept; } else { rb_raise(RaccBug, "[Racc Bug] unknown act value %ld", act); } if (v->debug) { rb_funcall(v->parser, id_d_next_state, 2, LONG2NUM(v->curstate), v->state); } } /* not reach */ accept: if (v->debug) rb_funcall(v->parser, id_d_accept, 0); v->retval = RARRAY(v->vstack)->ptr[0]; v->fin = CP_FIN_ACCEPT; return; error: D_printf("error detected, status=%ld\n", v->errstatus); if (v->errstatus == 0) { v->nerr++; rb_funcall(v->parser, id_onerror, 3, v->t, val, v->vstack); } user_yyerror: if (v->errstatus == 3) { if (v->t == vFINAL_TOKEN) { v->retval = Qfalse; v->fin = CP_FIN_EOT; return; } read_next = 1; } v->errstatus = 3; rb_ivar_set(v->parser, id_errstatus, LONG2NUM(v->errstatus)); /* check if we can shift/reduce error token */ D_printf("(err) k1=%ld\n", v->curstate); D_printf("(err) k2=%d (error)\n", ERROR_TOKEN); while (1) { tmp = AREF(v->action_pointer, v->curstate); if (NIL_P(tmp)) goto error_pop; D_puts("(err) pointer[k1] ok"); i = NUM2LONG(tmp) + ERROR_TOKEN; D_printf("(err) i=%ld\n", i); if (i < 0) goto error_pop; act_value = AREF(v->action_table, i); if (NIL_P(act_value)) { D_puts("(err) table[i] == nil"); goto error_pop; } act = NUM2LONG(act_value); D_printf("(err) table[i]=%ld\n", act); tmp = AREF(v->action_check, i); if (NIL_P(tmp)) { D_puts("(err) check[i] == nil"); goto error_pop; } if (NUM2LONG(tmp) != v->curstate) { D_puts("(err) check[i] != k1"); goto error_pop; } D_puts("(err) found: can handle error token"); break; error_pop: D_puts("(err) act not found: can't handle error token; pop"); if (RARRAY(v->state)->len <= 1) { v->retval = Qnil; v->fin = CP_FIN_CANTPOP; return; } POP(v->state); POP(v->vstack); v->curstate = num_to_long(LAST_I(v->state)); if (v->debug) { POP(v->tstack); rb_funcall(v->parser, id_d_e_pop, 3, v->state, v->tstack, v->vstack); } } /* shift/reduce error token */ if (act > 0 && act < v->shift_n) { D_puts("e shift"); SHIFT(v, act, ERROR_TOKEN, val); } else if (act < 0 && act > -(v->reduce_n)) { D_puts("e reduce"); REDUCE(v, act); } else if (act == v->shift_n) { D_puts("e accept"); goto accept; } else { rb_raise(RaccBug, "[Racc Bug] unknown act value %ld", act); } goto error_recovered; } static void shift(struct cparse_params *v, long act, VALUE tok, VALUE val) { PUSH(v->vstack, val); if (v->debug) { PUSH(v->tstack, tok); rb_funcall(v->parser, id_d_shift, 3, tok, v->tstack, v->vstack); } v->curstate = act; PUSH(v->state, LONG2NUM(v->curstate)); } static int reduce(struct cparse_params *v, long act) { VALUE code; v->ruleno = -act * 3; code = rb_catch("racc_jump", reduce0, v->value_v); v->errstatus = num_to_long(rb_ivar_get(v->parser, id_errstatus)); return NUM2INT(code); } static VALUE reduce0(VALUE val, VALUE data, VALUE self) { struct cparse_params *v; VALUE reduce_to, reduce_len, method_id; long len; ID mid; VALUE tmp, tmp_t = Qundef, tmp_v = Qundef; long i, k1, k2; VALUE goto_state; Data_Get_Struct(data, struct cparse_params, v); reduce_len = RARRAY(v->reduce_table)->ptr[v->ruleno]; reduce_to = RARRAY(v->reduce_table)->ptr[v->ruleno+1]; method_id = RARRAY(v->reduce_table)->ptr[v->ruleno+2]; len = NUM2LONG(reduce_len); mid = value_to_id(method_id); /* call action */ if (len == 0) { tmp = Qnil; if (mid != id_noreduce) tmp_v = rb_ary_new(); if (v->debug) tmp_t = rb_ary_new(); } else { if (mid != id_noreduce) { tmp_v = GET_TAIL(v->vstack, len); tmp = RARRAY(tmp_v)->ptr[0]; } else { tmp = RARRAY(v->vstack)->ptr[ RARRAY(v->vstack)->len - len ]; } CUT_TAIL(v->vstack, len); if (v->debug) { tmp_t = GET_TAIL(v->tstack, len); CUT_TAIL(v->tstack, len); } CUT_TAIL(v->state, len); } if (mid != id_noreduce) { if (v->use_result_var) { tmp = rb_funcall(v->parser, mid, 3, tmp_v, v->vstack, tmp); } else { tmp = rb_funcall(v->parser, mid, 2, tmp_v, v->vstack); } } /* then push result */ PUSH(v->vstack, tmp); if (v->debug) { PUSH(v->tstack, reduce_to); rb_funcall(v->parser, id_d_reduce, 4, tmp_t, reduce_to, v->tstack, v->vstack); } /* calculate transition state */ if (RARRAY(v->state)->len == 0) rb_raise(RaccBug, "state stack unexpectedly empty"); k2 = num_to_long(LAST_I(v->state)); k1 = num_to_long(reduce_to) - v->nt_base; D_printf("(goto) k1=%ld\n", k1); D_printf("(goto) k2=%ld\n", k2); tmp = AREF(v->goto_pointer, k1); if (NIL_P(tmp)) goto notfound; i = NUM2LONG(tmp) + k2; D_printf("(goto) i=%ld\n", i); if (i < 0) goto notfound; goto_state = AREF(v->goto_table, i); if (NIL_P(goto_state)) { D_puts("(goto) table[i] == nil"); goto notfound; } D_printf("(goto) table[i]=%ld (goto_state)\n", NUM2LONG(goto_state)); tmp = AREF(v->goto_check, i); if (NIL_P(tmp)) { D_puts("(goto) check[i] == nil"); goto notfound; } if (tmp != LONG2NUM(k1)) { D_puts("(goto) check[i] != table[i]"); goto notfound; } D_printf("(goto) check[i]=%ld\n", NUM2LONG(tmp)); D_puts("(goto) found"); transit: PUSH(v->state, goto_state); v->curstate = NUM2LONG(goto_state); return INT2FIX(0); notfound: D_puts("(goto) not found: use default"); /* overwrite `goto-state' by default value */ goto_state = AREF(v->goto_default, k1); goto transit; } /* ----------------------------------------------------------------------- Ruby Interface ----------------------------------------------------------------------- */ void Init_cparse(void) { VALUE Racc, Parser; ID id_racc = rb_intern("Racc"); if (rb_const_defined(rb_cObject, id_racc)) { Racc = rb_const_get(rb_cObject, id_racc); Parser = rb_const_get_at(Racc, rb_intern("Parser")); } else { Racc = rb_define_module("Racc"); Parser = rb_define_class_under(Racc, "Parser", rb_cObject); } rb_define_private_method(Parser, "_racc_do_parse_c", racc_cparse, 2); rb_define_private_method(Parser, "_racc_yyparse_c", racc_yyparse, 4); rb_define_const(Parser, "Racc_Runtime_Core_Version_C", rb_str_new2(RACC_VERSION)); rb_define_const(Parser, "Racc_Runtime_Core_Id_C", rb_str_new2("$originalId: cparse.c,v 1.8 2006/07/06 11:39:46 aamine Exp $")); CparseParams = rb_define_class_under(Racc, "CparseParams", rb_cObject); RaccBug = rb_eRuntimeError; id_yydebug = rb_intern("@yydebug"); id_nexttoken = rb_intern("next_token"); id_onerror = rb_intern("on_error"); id_noreduce = rb_intern("_reduce_none"); id_errstatus = rb_intern("@racc_error_status"); id_d_shift = rb_intern("racc_shift"); id_d_reduce = rb_intern("racc_reduce"); id_d_accept = rb_intern("racc_accept"); id_d_read_token = rb_intern("racc_read_token"); id_d_next_state = rb_intern("racc_next_state"); id_d_e_pop = rb_intern("racc_e_pop"); } ================================================ FILE: ext/racc/cparse/depend ================================================ cparse.o: cparse.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h ================================================ FILE: ext/racc/cparse/extconf.rb ================================================ # $Id$ require 'mkmf' create_makefile 'racc/cparse' ================================================ FILE: ext/rational/extconf.rb ================================================ require 'mkmf' create_makefile('rational') ================================================ FILE: ext/rational/lib/rational.rb ================================================ # # rational.rb - # $Release Version: 0.5 $ # $Revision: 1.7 $ # $Date: 1999/08/24 12:49:28 $ # by Keiju ISHITSUKA(SHL Japan Inc.) # # Documentation by Kevin Jackson and Gavin Sinclair. # # Performance improvements by Kurt Stephens. # # When you require 'rational', all interactions between numbers # potentially return a rational result. For example: # # 1.quo(2) # -> 0.5 # require 'rational' # 1.quo(2) # -> Rational(1,2) # # See Rational for full documentation. # # Pull in some optimization require "rational.so" # # Creates a Rational number (i.e. a fraction). +a+ and +b+ should be Integers: # # Rational(1,3) # -> 1/3 # # Note: trying to construct a Rational with floating point or real values # produces errors: # # Rational(1.1, 2.3) # -> NoMethodError # def Rational(a, b = 1) if a.kind_of?(Rational) && b == 1 a else Rational.reduce(a, b) end end # # Rational implements a rational class for numbers. # # A rational number is a number that can be expressed as a fraction p/q # where p and q are integers and q != 0. A rational number p/q is said to have # numerator p and denominator q. Numbers that are not rational are called # irrational numbers. (http://mathworld.wolfram.com/RationalNumber.html) # # To create a Rational Number: # Rational(a,b) # -> a/b # Rational.new!(a,b) # -> a/b # # Examples: # Rational(5,6) # -> 5/6 # Rational(5) # -> 5/1 # # Rational numbers are reduced to their lowest terms: # Rational(6,10) # -> 3/5 # # But not if you use the unusual method "new!": # Rational.new!(6,10) # -> 6/10 # # Division by zero is obviously not allowed: # Rational(3,0) # -> ZeroDivisionError # class Rational < Numeric @RCS_ID='-$Id: rational.rb,v 1.7 1999/08/24 12:49:28 keiju Exp keiju $-' # # Reduces the given numerator and denominator to their lowest terms. Use # Rational() instead. # def Rational.reduce(num, den = 1) raise ZeroDivisionError, "denominator is zero" if den == 0 if den < 0 num = -num den = -den end gcd = num.gcd(den) num = num.div(gcd) den = den.div(gcd) if den == 1 && defined?(Unify) num else new!(num, den) end end # # Implements the constructor. This method does not reduce to lowest terms or # check for division by zero. Therefore #Rational() should be preferred in # normal use. # def Rational.new!(num, den = 1) new(num, den) end private_class_method :new # # This method is actually private. # def initialize(num, den) if den < 0 num = -num den = -den end @numerator = num.to_i @denominator = den.to_i end # # Returns the addition of this value and +a+. # # Examples: # r = Rational(3,4) # -> Rational(3,4) # r + 1 # -> Rational(7,4) # r + 0.5 # -> 1.25 # def + (a) case a when Rational # => Rational | Integer Rational(@numerator * a.denominator + a.numerator * @denominator, @denominator * a.denominator) when Integer # => Rational Rational.reduce(@numerator + a * @denominator, @denominator) when Float self.to_f + a else x, y = a.coerce(self) x + y end end # # Returns the difference of this value and +a+. # subtracted. # # Examples: # r = Rational(3,4) # -> Rational(3,4) # r - 1 # -> Rational(-1,4) # r - 0.5 # -> 0.25 # def - (a) case a when Rational # => Rational | Integer Rational(@numerator * a.denominator - a.numerator * @denominator, @denominator * a.denominator) when Integer # => Rational Rational.reduce(@numerator - a * @denominator, @denominator) when Float self.to_f - a else x, y = a.coerce(self) x - y end end # # Unary Minus--Returns the receiver's value, negated. # def -@ Rational.new!(-@numerator, @denominator) end # # Returns the product of this value and +a+. # # Examples: # r = Rational(3,4) # -> Rational(3,4) # r * 2 # -> Rational(3,2) # r * 4 # -> Rational(3,1) # r * 0.5 # -> 0.375 # r * Rational(1,2) # -> Rational(3,8) # def * (a) case a when Rational Rational(@numerator * a.numerator, @denominator * a.denominator) when Integer Rational(@numerator * a, @denominator) when Float self.to_f * a else x, y = a.coerce(self) x * y end end # # Returns the quotient of this value and +a+. # r = Rational(3,4) # -> Rational(3,4) # r / 2 # -> Rational(3,8) # r / 2.0 # -> 0.375 # r / Rational(1,2) # -> Rational(3,2) # def / (a) case a when Rational Rational(@numerator * a.denominator, @denominator * a.numerator) when Integer raise ZeroDivisionError, "division by zero" if a == 0 Rational(@numerator, @denominator * a) when Float self.to_f / a else x, y = a.coerce(self) x / y end end # # Returns this value raised to the given power. # # Examples: # r = Rational(3,4) # -> Rational(3,4) # r ** 2 # -> Rational(9,16) # r ** 2.0 # -> 0.5625 # r ** Rational(1,2) # -> 0.866025403784439 # def ** (other) case other when Rational, Float self.to_f ** other when Integer if other > 0 Rational.new!(@numerator ** other, @denominator ** other) elsif other < 0 Rational.new!(@denominator ** -other, @numerator ** -other) else Rational.new!(1, 1) # why not Fixnum 1? end else x, y = other.coerce(self) x ** y end end def div(other) (self / other).floor end # # Returns the remainder when this value is divided by +other+. # # Examples: # r = Rational(7,4) # -> Rational(7,4) # r % Rational(1,2) # -> Rational(1,4) # r % 1 # -> Rational(3,4) # r % Rational(1,7) # -> Rational(1,28) # r % 0.26 # -> 0.19 # def % (other) value = (self / other).floor self - other * value end # # Returns the quotient _and_ remainder. # # Examples: # r = Rational(7,4) # -> Rational(7,4) # r.divmod Rational(1,2) # -> [3, Rational(1,4)] # def divmod(other) value = (self / other).floor [value, self - other * value] end # # Returns the absolute value. # def abs if @numerator > 0 self else Rational.new!(-@numerator, @denominator) end end # Returns true or false. def zero? @numerator.zero? end # See Numeric#nonzero? def nonzero? @numerator.nonzero? ? self : nil end # # Returns +true+ iff this value is numerically equal to +other+. # # But beware: # Rational(1,2) == Rational(4,8) # -> true # Rational(1,2) == Rational.new!(4,8) # -> false # # Don't use Rational.new! # def == (other) case other when Rational @numerator == other.numerator && @denominator == other.denominator when Integer @numerator == other && @denominator == 1 when Float self.to_f == other else other == self end end # # Standard comparison operator. # def <=> (other) case other when Rational @numerator * other.denominator <=> other.numerator * @denominator when Integer @numerator <=> other * @denominator when Float self.to_f <=> other else x, y = other.coerce(self) rescue return nil x <=> y end end def coerce(other) case other when Float return other, self.to_f when Integer return Rational.new!(other, 1), self else super end end # # Converts the rational to an Integer. Not the _nearest_ integer, the # truncated integer. Study the following example carefully: # Rational(+7,4).to_i # -> 1 # Rational(-7,4).to_i # -> -1 # (-1.75).to_i # -> -1 # # In other words: # Rational(-7,4) == -1.75 # -> true # Rational(-7,4).to_i == (-1.75).to_i # -> true # def floor() @numerator.div(@denominator) end def ceil() -((-@numerator).div(@denominator)) end def truncate() if @numerator < 0 -((-@numerator).div(@denominator)) else @numerator.div(@denominator) end end alias_method :to_i, :truncate def round() if @numerator < 0 -((@numerator * -2 + @denominator).div(@denominator * 2)) else ((@numerator * 2 + @denominator).div(@denominator * 2)) end end # # Converts the rational to a Float. # def to_f @numerator.to_f/@denominator.to_f end # # Returns a string representation of the rational number. # # Example: # Rational(3,4).to_s # "3/4" # Rational(8).to_s # "8" # def to_s if @denominator == 1 @numerator.to_s else "#{@numerator}/#{@denominator}" end end # # Returns +self+. # def to_r self end # # Returns a reconstructable string representation: # # Rational(5,8).inspect # -> "Rational(5, 8)" # def inspect "Rational(#{@numerator.inspect}, #{@denominator.inspect})" end # # Returns a hash code for the object. # def hash @numerator.hash ^ @denominator.hash end attr :numerator attr :denominator private :initialize end class Integer # # In an integer, the value _is_ the numerator of its rational equivalent. # Therefore, this method returns +self+. # def numerator self end # # In an integer, the denominator is 1. Therefore, this method returns 1. # def denominator 1 end # # Returns a Rational representation of this integer. # def to_r Rational(self, 1) end # # Returns the greatest common denominator of the two numbers (+self+ # and +n+). # # Examples: # 72.gcd 168 # -> 24 # 19.gcd 36 # -> 1 # # The result is positive, no matter the sign of the arguments. # def gcd(other) min = self.abs max = other.abs while min > 0 tmp = min min = max % min max = tmp end max end # # Returns the lowest common multiple (LCM) of the two arguments # (+self+ and +other+). # # Examples: # 6.lcm 7 # -> 42 # 6.lcm 9 # -> 18 # def lcm(other) if self.zero? or other.zero? 0 else (self.div(self.gcd(other)) * other).abs end end # # Returns the GCD _and_ the LCM (see #gcd and #lcm) of the two arguments # (+self+ and +other+). This is more efficient than calculating them # separately. # # Example: # 6.gcdlcm 9 # -> [3, 18] # def gcdlcm(other) gcd = self.gcd(other) if self.zero? or other.zero? [gcd, 0] else [gcd, (self.div(gcd) * other).abs] end end end class Fixnum remove_method :quo # If Rational is defined, returns a Rational number instead of a Float. def quo(other) Rational.new!(self, 1) / other end alias rdiv quo # Returns a Rational number if the result is in fact rational (i.e. +other+ < 0). def rpower (other) if other >= 0 self.power!(other) else Rational.new!(self, 1)**other end end end class Bignum remove_method :quo # If Rational is defined, returns a Rational number instead of a Float. def quo(other) Rational.new!(self, 1) / other end alias rdiv quo # Returns a Rational number if the result is in fact rational (i.e. +other+ < 0). def rpower (other) if other >= 0 self.power!(other) else Rational.new!(self, 1)**other end end end unless defined? 1.power! class Fixnum alias power! ** alias ** rpower end class Bignum alias power! ** alias ** rpower end end ================================================ FILE: ext/rational/rational.c ================================================ #include "ruby.h" /* * call-seq: * fixnum.gcd(fixnum) -> fixnum * * Fixnum-specific optimized version of Integer#gcd. Delegates to * Integer#gcd as necessary. */ static VALUE fix_gcd(self, other) VALUE self, other; { long a, b, min, max; /* * Note: Cannot handle values <= FIXNUM_MIN here due to overflow during negation. */ if (!FIXNUM_P(other) || (a = FIX2LONG(self)) <= FIXNUM_MIN || (b = FIX2LONG(other)) <= FIXNUM_MIN ) { /* Delegate to Integer#gcd */ return rb_call_super(1, &other); } min = a < 0 ? -a : a; max = b < 0 ? -b : b; while (min > 0) { long tmp = min; min = max % min; max = tmp; } return LONG2FIX(max); } void Init_rational() { rb_define_method(rb_cFixnum, "gcd", fix_gcd, 1); } ================================================ FILE: ext/readline/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/readline/README ================================================ Extension for GNU Readline Library Example: require "readline" include Readline line = readline("Prompt> ", true) [Readline] readline(prompt, add_history=nil) Reads one line with line editing. The inputted line is added to the history if add_history is true. completion_proc = proc Specifies a Proc object to determine completion behavior. It should take input-string, and return an array of completion candidates. completion_proc Returns the completion Proc object. completion_case_fold = bool Sets whether or not to ignore case on completion. completion_case_fold Returns true if completion ignores case. completion_append_character = char Specifies a character to be appended on completion. Nothing will be appended if an empty string ("") or nil is specified. completion_append_character Returns a string containing a character to be appended on completion. The default is a space (" "). vi_editing_mode Specifies VI editing mode. emacs_editing_mode Specifies Emacs editing mode. HISTORY The history buffer. It behaves just like an array. ================================================ FILE: ext/readline/README.ja ================================================ GNU Readline LibraryѤ뤿γĥ⥸塼Ǥ require "readline" include Readline line = readline("Prompt> ", true) Τ褦˻ѤƤ [Readline] <⥸塼ؿ> readline(prompt, add_history=nil) Ϥɤ߹ߤޤ add_historytrueξ硢ҥȥɤ߹ʸɲäޤ <饹᥽å> completion_proc = proc 䴰ưꤹProc֥Ȥꤷޤ procϰʸꡢʸ֤褦 Ƥ completion_proc 䴰ưꤹProc֥Ȥ֤ޤ completion_case_fold = case_fold 䴰ʸʸ̤ʤ硢trueꤷޤ completion_case_fold 䴰ʸʸ̤ʤ硢true֤ޤ completion_append_character = char 䴰ղäʸʸǻꤷޤƬΰʸ ꤵ졢ʸ ("") ޤ nil ꤹȲղ ʤʤޤ completion_append_character 䴰ղäʸʸ֤ޤǥեȤ (" ") Ǥ vi_editing_mode VI⡼ɤˤʤޤ emacs_editing_mode Emacs⡼ɤˤʤޤ <饹> HISTORY ҥȥФϤ̤ƹԤäƤ Ʊ褦˰褦ˤʤäƤޤ ================================================ FILE: ext/readline/depend ================================================ readline.o: readline.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h ================================================ FILE: ext/readline/extconf.rb ================================================ require "mkmf" $readline_headers = ["stdio.h"] def have_readline_header(header) if have_header(header) $readline_headers.push(header) return true else return false end end def have_readline_var(var) return have_var(var, $readline_headers) end dir_config('curses') dir_config('ncurses') dir_config('termcap') dir_config("readline") enable_libedit = enable_config("libedit") have_library("user32", nil) if /cygwin/ === RUBY_PLATFORM have_library("ncurses", "tgetnum") || have_library("termcap", "tgetnum") || have_library("curses", "tgetnum") if enable_libedit unless (have_readline_header("editline/readline.h") || have_readline_header("readline/readline.h")) && have_library("edit", "readline") exit end else unless ((have_readline_header("readline/readline.h") && have_readline_header("readline/history.h")) && (have_library("readline", "readline") || have_library("edit", "readline"))) || (have_readline_header("editline/readline.h") && have_library("edit", "readline")) exit end end have_func("rl_filename_completion_function") have_func("rl_username_completion_function") have_func("rl_completion_matches") have_readline_var("rl_deprep_term_function") have_readline_var("rl_completion_append_character") have_readline_var("rl_basic_word_break_characters") have_readline_var("rl_completer_word_break_characters") have_readline_var("rl_basic_quote_characters") have_readline_var("rl_completer_quote_characters") have_readline_var("rl_filename_quote_characters") have_readline_var("rl_attempted_completion_over") have_readline_var("rl_library_version") have_readline_var("rl_event_hook") have_func("rl_cleanup_after_signal") have_func("rl_clear_signals") have_func("rl_vi_editing_mode") have_func("rl_emacs_editing_mode") have_func("replace_history_entry") have_func("remove_history") create_makefile("readline") ================================================ FILE: ext/readline/readline.c ================================================ /* readline.c -- GNU Readline module Copyright (C) 1997-2001 Shugo Maeda */ #include "config.h" #include #include #include #include #ifdef HAVE_READLINE_READLINE_H #include #endif #ifdef HAVE_READLINE_HISTORY_H #include #endif #ifdef HAVE_EDITLINE_READLINE_H #include #endif #include "ruby.h" #include "rubyio.h" #include "rubysig.h" #ifdef HAVE_UNISTD_H #include #endif static VALUE mReadline; #define TOLOWER(c) (isupper(c) ? tolower(c) : c) #define COMPLETION_PROC "completion_proc" #define COMPLETION_CASE_FOLD "completion_case_fold" static ID completion_proc, completion_case_fold; #ifndef HAVE_RL_FILENAME_COMPLETION_FUNCTION # define rl_filename_completion_function filename_completion_function #endif #ifndef HAVE_RL_USERNAME_COMPLETION_FUNCTION # define rl_username_completion_function username_completion_function #endif #ifndef HAVE_RL_COMPLETION_MATCHES # define rl_completion_matches completion_matches #endif static char **readline_attempted_completion_function(const char *text, int start, int end); #ifdef HAVE_RL_EVENT_HOOK #ifdef DOSISH #define BUSY_WAIT 1 #else #define BUSY_WAIT 0 #endif static int readline_event(void); static int readline_event() { #if BUSY_WAIT rb_thread_schedule(); #else fd_set rset; FD_ZERO(&rset); FD_SET(fileno(rl_instream), &rset); rb_thread_select(fileno(rl_instream) + 1, &rset, NULL, NULL, NULL); return 0; #endif } #endif static VALUE readline_readline(argc, argv, self) int argc; VALUE *argv; VALUE self; { VALUE tmp, add_hist, result; char *prompt = NULL; char *buff; int status; rb_io_t *ofp, *ifp; rb_secure(4); if (rb_scan_args(argc, argv, "02", &tmp, &add_hist) > 0) { SafeStringValue(tmp); prompt = RSTRING(tmp)->ptr; } if (!isatty(0) && errno == EBADF) rb_raise(rb_eIOError, "stdin closed"); Check_Type(rb_stdout, T_FILE); GetOpenFile(rb_stdout, ofp); rl_outstream = GetWriteFile(ofp); Check_Type(rb_stdin, T_FILE); GetOpenFile(rb_stdin, ifp); rl_instream = GetReadFile(ifp); buff = (char*)rb_protect((VALUE(*)_((VALUE)))readline, (VALUE)prompt, &status); if (status) { #if defined HAVE_RL_CLEANUP_AFTER_SIGNAL /* restore terminal mode and signal handler*/ rl_cleanup_after_signal(); #elif defined HAVE_RL_DEPREP_TERM_FUNCTION /* restore terminal mode */ if (rl_deprep_term_function != NULL) /* NULL in libedit. [ruby-dev:29116] */ (*rl_deprep_term_function)(); else #else rl_deprep_terminal(); #endif rb_jump_tag(status); } if (RTEST(add_hist) && buff) { add_history(buff); } if (buff) result = rb_tainted_str_new2(buff); else result = Qnil; if (buff) system_free(buff); return result; } static VALUE readline_s_set_completion_proc(self, proc) VALUE self; VALUE proc; { rb_secure(4); if (!rb_respond_to(proc, rb_intern("call"))) rb_raise(rb_eArgError, "argument must respond to `call'"); return rb_ivar_set(mReadline, completion_proc, proc); } static VALUE readline_s_get_completion_proc(self) VALUE self; { rb_secure(4); return rb_attr_get(mReadline, completion_proc); } static VALUE readline_s_set_completion_case_fold(self, val) VALUE self; VALUE val; { rb_secure(4); return rb_ivar_set(mReadline, completion_case_fold, val); } static VALUE readline_s_get_completion_case_fold(self) VALUE self; { rb_secure(4); return rb_attr_get(mReadline, completion_case_fold); } static char ** readline_attempted_completion_function(text, start, end) const char *text; int start; int end; { VALUE proc, ary, temp; char **result; int case_fold; int i, matches; size_t len; proc = rb_attr_get(mReadline, completion_proc); if (NIL_P(proc)) return NULL; #ifdef HAVE_RL_ATTEMPTED_COMPLETION_OVER rl_attempted_completion_over = 1; #endif case_fold = RTEST(rb_attr_get(mReadline, completion_case_fold)); ary = rb_funcall(proc, rb_intern("call"), 1, rb_tainted_str_new2(text)); if (TYPE(ary) != T_ARRAY) ary = rb_Array(ary); matches = RARRAY(ary)->len; if (matches == 0) return NULL; result = system_malloc(sizeof(char *) * (matches + 2)); for (i = 0; i < matches; i++) { temp = rb_obj_as_string(RARRAY(ary)->ptr[i]); result[i + 1] = system_malloc(sizeof(char) * (RSTRING(temp)->len + 1)); strcpy(result[i + 1], RSTRING(temp)->ptr); } result[matches + 1] = NULL; if (matches == 1) { len = strlen(result[1]); result[0] = (char *) system_malloc(sizeof(char) * (len + 1)); memcpy(result[0], result[1], sizeof(char) * len); result[0][len] = '\0'; } else { register int i = 1; int low = 100000; while (i < matches) { register int c1, c2, si; if (case_fold) { for (si = 0; (c1 = TOLOWER(result[i][si])) && (c2 = TOLOWER(result[i + 1][si])); si++) if (c1 != c2) break; } else { for (si = 0; (c1 = result[i][si]) && (c2 = result[i + 1][si]); si++) if (c1 != c2) break; } if (low > si) low = si; i++; } result[0] = system_malloc(sizeof(char) * (low + 1)); strncpy(result[0], result[1], low); result[0][low] = '\0'; } return result; } static VALUE readline_s_vi_editing_mode(self) VALUE self; { #ifdef HAVE_RL_VI_EDITING_MODE rb_secure(4); rl_vi_editing_mode(1,0); return Qnil; #else rb_notimplement(); return Qnil; /* not reached */ #endif /* HAVE_RL_VI_EDITING_MODE */ } static VALUE readline_s_emacs_editing_mode(self) VALUE self; { #ifdef HAVE_RL_EMACS_EDITING_MODE rb_secure(4); rl_emacs_editing_mode(1,0); return Qnil; #else rb_notimplement(); return Qnil; /* not reached */ #endif /* HAVE_RL_EMACS_EDITING_MODE */ } static VALUE readline_s_set_completion_append_character(self, str) VALUE self, str; { #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER rb_secure(4); if (NIL_P(str)) { rl_completion_append_character = '\0'; } else { SafeStringValue(str); if (RSTRING(str)->len == 0) { rl_completion_append_character = '\0'; } else { rl_completion_append_character = RSTRING(str)->ptr[0]; } } return self; #else rb_notimplement(); return Qnil; /* not reached */ #endif /* HAVE_RL_COMPLETION_APPEND_CHARACTER */ } static VALUE readline_s_get_completion_append_character(self) VALUE self; { #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER VALUE str; rb_secure(4); if (rl_completion_append_character == '\0') return Qnil; str = rb_str_new("", 1); RSTRING(str)->ptr[0] = rl_completion_append_character; return str; #else rb_notimplement(); return Qnil; /* not reached */ #endif /* HAVE_RL_COMPLETION_APPEND_CHARACTER */ } static VALUE readline_s_set_basic_word_break_characters(self, str) VALUE self, str; { #ifdef HAVE_RL_BASIC_WORD_BREAK_CHARACTERS static char *basic_word_break_characters = NULL; rb_secure(4); SafeStringValue(str); if (basic_word_break_characters == NULL) { basic_word_break_characters = ALLOC_N(char, RSTRING(str)->len + 1); } else { REALLOC_N(basic_word_break_characters, char, RSTRING(str)->len + 1); } strncpy(basic_word_break_characters, RSTRING(str)->ptr, RSTRING(str)->len); basic_word_break_characters[RSTRING(str)->len] = '\0'; rl_basic_word_break_characters = basic_word_break_characters; return self; #else rb_notimplement(); return Qnil; /* not reached */ #endif /* HAVE_RL_BASIC_WORD_BREAK_CHARACTERS */ } static VALUE readline_s_get_basic_word_break_characters(self, str) VALUE self, str; { #ifdef HAVE_RL_BASIC_WORD_BREAK_CHARACTERS rb_secure(4); if (rl_basic_word_break_characters == NULL) return Qnil; return rb_tainted_str_new2(rl_basic_word_break_characters); #else rb_notimplement(); return Qnil; /* not reached */ #endif /* HAVE_RL_BASIC_WORD_BREAK_CHARACTERS */ } static VALUE readline_s_set_completer_word_break_characters(self, str) VALUE self, str; { #ifdef HAVE_RL_COMPLETER_WORD_BREAK_CHARACTERS static char *completer_word_break_characters = NULL; rb_secure(4); SafeStringValue(str); if (completer_word_break_characters == NULL) { completer_word_break_characters = ALLOC_N(char, RSTRING(str)->len + 1); } else { REALLOC_N(completer_word_break_characters, char, RSTRING(str)->len + 1); } strncpy(completer_word_break_characters, RSTRING(str)->ptr, RSTRING(str)->len); completer_word_break_characters[RSTRING(str)->len] = '\0'; rl_completer_word_break_characters = completer_word_break_characters; return self; #else rb_notimplement(); return Qnil; /* not reached */ #endif /* HAVE_RL_COMPLETER_WORD_BREAK_CHARACTERS */ } static VALUE readline_s_get_completer_word_break_characters(self, str) VALUE self, str; { #ifdef HAVE_RL_COMPLETER_WORD_BREAK_CHARACTERS rb_secure(4); if (rl_completer_word_break_characters == NULL) return Qnil; return rb_tainted_str_new2(rl_completer_word_break_characters); #else rb_notimplement(); return Qnil; /* not reached */ #endif /* HAVE_RL_COMPLETER_WORD_BREAK_CHARACTERS */ } static VALUE readline_s_set_basic_quote_characters(self, str) VALUE self, str; { #ifdef HAVE_RL_BASIC_QUOTE_CHARACTERS static char *basic_quote_characters = NULL; rb_secure(4); SafeStringValue(str); if (basic_quote_characters == NULL) { basic_quote_characters = ALLOC_N(char, RSTRING(str)->len + 1); } else { REALLOC_N(basic_quote_characters, char, RSTRING(str)->len + 1); } strncpy(basic_quote_characters, RSTRING(str)->ptr, RSTRING(str)->len); basic_quote_characters[RSTRING(str)->len] = '\0'; rl_basic_quote_characters = basic_quote_characters; return self; #else rb_notimplement(); return Qnil; /* not reached */ #endif /* HAVE_RL_BASIC_QUOTE_CHARACTERS */ } static VALUE readline_s_get_basic_quote_characters(self, str) VALUE self, str; { #ifdef HAVE_RL_BASIC_QUOTE_CHARACTERS rb_secure(4); if (rl_basic_quote_characters == NULL) return Qnil; return rb_tainted_str_new2(rl_basic_quote_characters); #else rb_notimplement(); return Qnil; /* not reached */ #endif /* HAVE_RL_BASIC_QUOTE_CHARACTERS */ } static VALUE readline_s_set_completer_quote_characters(self, str) VALUE self, str; { #ifdef HAVE_RL_COMPLETER_QUOTE_CHARACTERS static char *completer_quote_characters = NULL; rb_secure(4); SafeStringValue(str); if (completer_quote_characters == NULL) { completer_quote_characters = ALLOC_N(char, RSTRING(str)->len + 1); } else { REALLOC_N(completer_quote_characters, char, RSTRING(str)->len + 1); } strncpy(completer_quote_characters, RSTRING(str)->ptr, RSTRING(str)->len); completer_quote_characters[RSTRING(str)->len] = '\0'; rl_completer_quote_characters = completer_quote_characters; return self; #else rb_notimplement(); return Qnil; /* not reached */ #endif /* HAVE_RL_COMPLETER_QUOTE_CHARACTERS */ } static VALUE readline_s_get_completer_quote_characters(self, str) VALUE self, str; { #ifdef HAVE_RL_COMPLETER_QUOTE_CHARACTERS rb_secure(4); if (rl_completer_quote_characters == NULL) return Qnil; return rb_tainted_str_new2(rl_completer_quote_characters); #else rb_notimplement(); return Qnil; /* not reached */ #endif /* HAVE_RL_COMPLETER_QUOTE_CHARACTERS */ } static VALUE readline_s_set_filename_quote_characters(self, str) VALUE self, str; { #ifdef HAVE_RL_FILENAME_QUOTE_CHARACTERS static char *filename_quote_characters = NULL; rb_secure(4); SafeStringValue(str); if (filename_quote_characters == NULL) { filename_quote_characters = ALLOC_N(char, RSTRING(str)->len + 1); } else { REALLOC_N(filename_quote_characters, char, RSTRING(str)->len + 1); } strncpy(filename_quote_characters, RSTRING(str)->ptr, RSTRING(str)->len); filename_quote_characters[RSTRING(str)->len] = '\0'; rl_filename_quote_characters = filename_quote_characters; return self; #else rb_notimplement(); return Qnil; /* not reached */ #endif /* HAVE_RL_FILENAME_QUOTE_CHARACTERS */ } static VALUE readline_s_get_filename_quote_characters(self, str) VALUE self, str; { #ifdef HAVE_RL_FILENAME_QUOTE_CHARACTERS rb_secure(4); if (rl_filename_quote_characters == NULL) return Qnil; return rb_tainted_str_new2(rl_filename_quote_characters); #else rb_notimplement(); return Qnil; /* not reached */ #endif /* HAVE_RL_FILENAME_QUOTE_CHARACTERS */ } static VALUE hist_to_s(self) VALUE self; { return rb_str_new2("HISTORY"); } static VALUE hist_get(self, index) VALUE self; VALUE index; { HIST_ENTRY *entry; int i; rb_secure(4); i = NUM2INT(index); if (i < 0) { i += history_length; } entry = history_get(history_base + i); if (entry == NULL) { rb_raise(rb_eIndexError, "invalid index"); } return rb_tainted_str_new2(entry->line); } static VALUE hist_set(self, index, str) VALUE self; VALUE index; VALUE str; { #ifdef HAVE_REPLACE_HISTORY_ENTRY HIST_ENTRY *entry; int i; rb_secure(4); i = NUM2INT(index); SafeStringValue(str); if (i < 0) { i += history_length; } entry = replace_history_entry(i, RSTRING(str)->ptr, NULL); if (entry == NULL) { rb_raise(rb_eIndexError, "invalid index"); } return str; #else rb_notimplement(); return Qnil; /* not reached */ #endif } static VALUE hist_push(self, str) VALUE self; VALUE str; { rb_secure(4); SafeStringValue(str); add_history(RSTRING(str)->ptr); return self; } static VALUE hist_push_method(argc, argv, self) int argc; VALUE *argv; VALUE self; { VALUE str; rb_secure(4); while (argc--) { str = *argv++; SafeStringValue(str); add_history(RSTRING(str)->ptr); } return self; } static VALUE rb_remove_history(index) int index; { #ifdef HAVE_REMOVE_HISTORY HIST_ENTRY *entry; VALUE val; rb_secure(4); entry = remove_history(index); if (entry) { val = rb_tainted_str_new2(entry->line); system_free((void *) entry->line); system_free(entry); return val; } return Qnil; #else rb_notimplement(); return Qnil; /* not reached */ #endif } static VALUE hist_pop(self) VALUE self; { rb_secure(4); if (history_length > 0) { return rb_remove_history(history_length - 1); } else { return Qnil; } } static VALUE hist_shift(self) VALUE self; { rb_secure(4); if (history_length > 0) { return rb_remove_history(0); } else { return Qnil; } } static VALUE hist_each(self) VALUE self; { HIST_ENTRY *entry; int i; rb_secure(4); for (i = 0; i < history_length; i++) { entry = history_get(history_base + i); if (entry == NULL) break; rb_yield(rb_tainted_str_new2(entry->line)); } return self; } static VALUE hist_length(self) VALUE self; { rb_secure(4); return INT2NUM(history_length); } static VALUE hist_empty_p(self) VALUE self; { rb_secure(4); return history_length == 0 ? Qtrue : Qfalse; } static VALUE hist_delete_at(self, index) VALUE self; VALUE index; { int i; rb_secure(4); i = NUM2INT(index); if (i < 0) i += history_length; if (i < 0 || i > history_length - 1) { rb_raise(rb_eIndexError, "invalid index"); } return rb_remove_history(i); } static VALUE filename_completion_proc_call(self, str) VALUE self; VALUE str; { VALUE result; char **matches; int i; matches = rl_completion_matches(StringValuePtr(str), rl_filename_completion_function); if (matches) { result = rb_ary_new(); for (i = 0; matches[i]; i++) { rb_ary_push(result, rb_tainted_str_new2(matches[i])); system_free(matches[i]); } system_free(matches); if (RARRAY(result)->len >= 2) rb_ary_shift(result); } else { result = Qnil; } return result; } static VALUE username_completion_proc_call(self, str) VALUE self; VALUE str; { VALUE result; char **matches; int i; matches = rl_completion_matches(StringValuePtr(str), rl_username_completion_function); if (matches) { result = rb_ary_new(); for (i = 0; matches[i]; i++) { rb_ary_push(result, rb_tainted_str_new2(matches[i])); system_free(matches[i]); } system_free(matches); if (RARRAY(result)->len >= 2) rb_ary_shift(result); } else { result = Qnil; } return result; } void Init_readline() { VALUE history, fcomp, ucomp; /* Allow conditional parsing of the ~/.inputrc file. */ rl_readline_name = "Ruby"; using_history(); completion_proc = rb_intern(COMPLETION_PROC); completion_case_fold = rb_intern(COMPLETION_CASE_FOLD); mReadline = rb_define_module("Readline"); rb_define_module_function(mReadline, "readline", readline_readline, -1); rb_define_singleton_method(mReadline, "completion_proc=", readline_s_set_completion_proc, 1); rb_define_singleton_method(mReadline, "completion_proc", readline_s_get_completion_proc, 0); rb_define_singleton_method(mReadline, "completion_case_fold=", readline_s_set_completion_case_fold, 1); rb_define_singleton_method(mReadline, "completion_case_fold", readline_s_get_completion_case_fold, 0); rb_define_singleton_method(mReadline, "vi_editing_mode", readline_s_vi_editing_mode, 0); rb_define_singleton_method(mReadline, "emacs_editing_mode", readline_s_emacs_editing_mode, 0); rb_define_singleton_method(mReadline, "completion_append_character=", readline_s_set_completion_append_character, 1); rb_define_singleton_method(mReadline, "completion_append_character", readline_s_get_completion_append_character, 0); rb_define_singleton_method(mReadline, "basic_word_break_characters=", readline_s_set_basic_word_break_characters, 1); rb_define_singleton_method(mReadline, "basic_word_break_characters", readline_s_get_basic_word_break_characters, 0); rb_define_singleton_method(mReadline, "completer_word_break_characters=", readline_s_set_completer_word_break_characters, 1); rb_define_singleton_method(mReadline, "completer_word_break_characters", readline_s_get_completer_word_break_characters, 0); rb_define_singleton_method(mReadline, "basic_quote_characters=", readline_s_set_basic_quote_characters, 1); rb_define_singleton_method(mReadline, "basic_quote_characters", readline_s_get_basic_quote_characters, 0); rb_define_singleton_method(mReadline, "completer_quote_characters=", readline_s_set_completer_quote_characters, 1); rb_define_singleton_method(mReadline, "completer_quote_characters", readline_s_get_completer_quote_characters, 0); rb_define_singleton_method(mReadline, "filename_quote_characters=", readline_s_set_filename_quote_characters, 1); rb_define_singleton_method(mReadline, "filename_quote_characters", readline_s_get_filename_quote_characters, 0); history = rb_obj_alloc(rb_cObject); rb_extend_object(history, rb_mEnumerable); rb_define_singleton_method(history,"to_s", hist_to_s, 0); rb_define_singleton_method(history,"[]", hist_get, 1); rb_define_singleton_method(history,"[]=", hist_set, 2); rb_define_singleton_method(history,"<<", hist_push, 1); rb_define_singleton_method(history,"push", hist_push_method, -1); rb_define_singleton_method(history,"pop", hist_pop, 0); rb_define_singleton_method(history,"shift", hist_shift, 0); rb_define_singleton_method(history,"each", hist_each, 0); rb_define_singleton_method(history,"length", hist_length, 0); rb_define_singleton_method(history,"size", hist_length, 0); rb_define_singleton_method(history,"empty?", hist_empty_p, 0); rb_define_singleton_method(history,"delete_at", hist_delete_at, 1); rb_define_const(mReadline, "HISTORY", history); fcomp = rb_obj_alloc(rb_cObject); rb_define_singleton_method(fcomp, "call", filename_completion_proc_call, 1); rb_define_const(mReadline, "FILENAME_COMPLETION_PROC", fcomp); ucomp = rb_obj_alloc(rb_cObject); rb_define_singleton_method(ucomp, "call", username_completion_proc_call, 1); rb_define_const(mReadline, "USERNAME_COMPLETION_PROC", ucomp); #if defined HAVE_RL_LIBRARY_VERSION rb_define_const(mReadline, "VERSION", rb_str_new2(rl_library_version)); #else rb_define_const(mReadline, "VERSION", rb_str_new2("2.0 or before version")); #endif rl_attempted_completion_function = readline_attempted_completion_function; #ifdef HAVE_RL_EVENT_HOOK rl_event_hook = readline_event; #endif #ifdef HAVE_RL_CLEAR_SIGNALS rl_clear_signals(); #endif } ================================================ FILE: ext/sdbm/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/sdbm/_sdbm.c ================================================ /* * sdbm - ndbm work-alike hashed database library * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978). * author: oz@nexus.yorku.ca * status: public domain. * * core routines */ #ifndef lint /*char sdbm_rcsid[] = "$Id$";*/ #endif #include "sdbm.h" #include "config.h" /* * sdbm - ndbm work-alike hashed database library * tuning and portability constructs [not nearly enough] * author: oz@nexus.yorku.ca */ #define BYTESIZ 8 #ifdef HAVE_UNISTD_H #include #endif #ifdef BSD42 #define SEEK_SET L_SET #define memset(s,c,n) bzero(s, n) /* only when c is zero */ #define memcpy(s1,s2,n) bcopy(s2, s1, n) #define memcmp(s1,s2,n) bcmp(s1,s2,n) #endif /* * important tuning parms (hah) */ #define SEEDUPS /* always detect duplicates */ #define BADMESS /* generate a message for worst case: cannot make room after SPLTMAX splits */ /* * misc */ #ifdef DEBUG #define debug(x) printf x #else #define debug(x) #endif #ifdef BIG_E #define GET_SHORT(p, i) (((unsigned)((unsigned char *)(p))[(i)*2] << 8) + (((unsigned char *)(p))[(i)*2 + 1])) #define PUT_SHORT(p, i, s) (((unsigned char *)(p))[(i)*2] = (unsigned char)((s) >> 8), ((unsigned char *)(p))[(i)*2 + 1] = (unsigned char)(s)) #else #define GET_SHORT(p, i) ((p)[i]) #define PUT_SHORT(p, i, s) ((p)[i] = (s)) #endif /*#include "pair.h"*/ static int fitpair proto((char *, int)); static void putpair proto((char *, datum, datum)); static datum getpair proto((char *, datum)); static int delpair proto((char *, datum)); static int chkpage proto((char *)); static datum getnkey proto((char *, int)); static void splpage proto((char *, char *, long)); #ifdef SEEDUPS static int duppair proto((char *, datum)); #endif #include #include #ifdef DOSISH #include #endif #include #include #ifdef BSD42 #include #else #include /*#include */ #endif #ifndef O_BINARY #define O_BINARY 0 #endif #include #ifndef EPERM #define EPERM EACCES #endif #include #ifdef __STDC__ #include #endif #ifndef NULL #define NULL 0 #endif /* * externals */ #if !defined sun && !defined MSDOS && !defined _WIN32 && !defined __CYGWIN__ && !defined(errno) extern int errno; #endif /* * forward */ static int getdbit proto((DBM *, long)); static int setdbit proto((DBM *, long)); static int getpage proto((DBM *, long)); static datum getnext proto((DBM *)); static int makroom proto((DBM *, long, int)); /* * useful macros */ #define bad(x) ((x).dptr == NULL || (x).dsize < 0) #define exhash(item) sdbm_hash((item).dptr, (item).dsize) #define ioerr(db) ((db)->flags |= DBM_IOERR) #define OFF_PAG(off) (long) (off) * PBLKSIZ #define OFF_DIR(off) (long) (off) * DBLKSIZ static long masks[] = { 000000000000L, 000000000001L, 000000000003L, 000000000007L, 000000000017L, 000000000037L, 000000000077L, 000000000177L, 000000000377L, 000000000777L, 000000001777L, 000000003777L, 000000007777L, 000000017777L, 000000037777L, 000000077777L, 000000177777L, 000000377777L, 000000777777L, 000001777777L, 000003777777L, 000007777777L, 000017777777L, 000037777777L, 000077777777L, 000177777777L, 000377777777L, 000777777777L, 001777777777L, 003777777777L, 007777777777L, 017777777777L }; datum nullitem = {NULL, 0}; DBM * sdbm_open(file, flags, mode) register char *file; register int flags; register int mode; { register DBM *db; register char *dirname; register char *pagname; register int n; if (file == NULL || !*file) return errno = EINVAL, (DBM *) NULL; /* * need space for two seperate filenames */ n = strlen(file) * 2 + strlen(DIRFEXT) + strlen(PAGFEXT) + 2; if ((dirname = malloc((unsigned) n)) == NULL) return errno = ENOMEM, (DBM *) NULL; /* * build the file names */ dirname = strcat(strcpy(dirname, file), DIRFEXT); pagname = strcpy(dirname + strlen(dirname) + 1, file); pagname = strcat(pagname, PAGFEXT); db = sdbm_prep(dirname, pagname, flags, mode); free((char *) dirname); return db; } DBM * sdbm_prep(dirname, pagname, flags, mode) char *dirname; char *pagname; int flags; int mode; { register DBM *db; struct stat dstat; if ((db = (DBM *) malloc(sizeof(DBM))) == NULL) return errno = ENOMEM, (DBM *) NULL; db->flags = 0; db->hmask = 0; db->blkptr = 0; db->keyptr = 0; /* * adjust user flags so that WRONLY becomes RDWR, * as required by this package. Also set our internal * flag for RDONLY. */ if (flags & O_WRONLY) flags = (flags & ~O_WRONLY) | O_RDWR; if (flags & O_RDONLY) db->flags = DBM_RDONLY; /* * open the files in sequence, and stat the dirfile. * If we fail anywhere, undo everything, return NULL. */ flags |= O_BINARY; if ((db->pagf = open(pagname, flags, mode)) > -1) { if ((db->dirf = open(dirname, flags, mode)) > -1) { /* * need the dirfile size to establish max bit number. */ if (fstat(db->dirf, &dstat) == 0) { /* * zero size: either a fresh database, or one with a single, * unsplit data page: dirpage is all zeros. */ db->dirbno = (!dstat.st_size) ? 0 : -1; db->pagbno = -1; db->maxbno = dstat.st_size * (long) BYTESIZ; (void) memset(db->pagbuf, 0, PBLKSIZ); (void) memset(db->dirbuf, 0, DBLKSIZ); /* * success */ return db; } (void) close(db->dirf); } (void) close(db->pagf); } free((char *) db); return (DBM *) NULL; } void sdbm_close(db) register DBM *db; { if (db == NULL) errno = EINVAL; else { (void) close(db->dirf); (void) close(db->pagf); free((char *) db); } } datum sdbm_fetch(db, key) register DBM *db; datum key; { if (db == NULL || bad(key)) return errno = EINVAL, nullitem; if (getpage(db, exhash(key))) return getpair(db->pagbuf, key); return ioerr(db), nullitem; } int sdbm_delete(db, key) register DBM *db; datum key; { if (db == NULL || bad(key)) return errno = EINVAL, -1; if (sdbm_rdonly(db)) return errno = EPERM, -1; if (getpage(db, exhash(key))) { if (!delpair(db->pagbuf, key)) return -1; /* * update the page file */ if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0 || write(db->pagf, db->pagbuf, PBLKSIZ) < 0) return ioerr(db), -1; return 0; } return ioerr(db), -1; } int sdbm_store(db, key, val, flags) register DBM *db; datum key; datum val; int flags; { int need; register long hash; if (db == NULL || bad(key)) return errno = EINVAL, -1; if (sdbm_rdonly(db)) return errno = EPERM, -1; need = key.dsize + val.dsize; /* * is the pair too big (or too small) for this database ?? */ if (need < 0 || need > PAIRMAX) return errno = EINVAL, -1; if (getpage(db, (hash = exhash(key)))) { /* * if we need to replace, delete the key/data pair * first. If it is not there, ignore. */ if (flags == DBM_REPLACE) (void) delpair(db->pagbuf, key); #ifdef SEEDUPS else if (duppair(db->pagbuf, key)) return 1; #endif /* * if we do not have enough room, we have to split. */ if (!fitpair(db->pagbuf, need)) if (!makroom(db, hash, need)) return ioerr(db), -1; /* * we have enough room or split is successful. insert the key, * and update the page file. */ (void) putpair(db->pagbuf, key, val); if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0 || write(db->pagf, db->pagbuf, PBLKSIZ) < 0) return ioerr(db), -1; /* * success */ return 0; } return ioerr(db), -1; } /* * makroom - make room by splitting the overfull page * this routine will attempt to make room for SPLTMAX times before * giving up. */ static int makroom(db, hash, need) register DBM *db; long hash; int need; { long newp; char twin[PBLKSIZ]; #if defined MSDOS || (defined _WIN32 && !defined __CYGWIN__) char zer[PBLKSIZ]; long oldtail; #endif char *pag = db->pagbuf; char *new = twin; register int smax = SPLTMAX; do { /* * split the current page */ (void) splpage(pag, new, db->hmask + 1); /* * address of the new page */ newp = (hash & db->hmask) | (db->hmask + 1); debug(("newp: %ld\n", newp)); /* * write delay, read avoidence/cache shuffle: * select the page for incoming pair: if key is to go to the new page, * write out the previous one, and copy the new one over, thus making * it the current page. If not, simply write the new page, and we are * still looking at the page of interest. current page is not updated * here, as sdbm_store will do so, after it inserts the incoming pair. */ #if defined MSDOS || (defined _WIN32 && !defined __CYGWIN__) /* * Fill hole with 0 if made it. * (hole is NOT read as 0) */ oldtail = lseek(db->pagf, 0L, SEEK_END); memset(zer, 0, PBLKSIZ); while (OFF_PAG(newp) > oldtail) { if (lseek(db->pagf, 0L, SEEK_END) < 0 || write(db->pagf, zer, PBLKSIZ) < 0) { return 0; } oldtail += PBLKSIZ; } #endif if (hash & (db->hmask + 1)) { if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0 || write(db->pagf, db->pagbuf, PBLKSIZ) < 0) return 0; db->pagbno = newp; (void) memcpy(pag, new, PBLKSIZ); } else if (lseek(db->pagf, OFF_PAG(newp), SEEK_SET) < 0 || write(db->pagf, new, PBLKSIZ) < 0) return 0; if (!setdbit(db, db->curbit)) return 0; /* * see if we have enough room now */ if (fitpair(pag, need)) return 1; /* * try again... update curbit and hmask as getpage would have * done. because of our update of the current page, we do not * need to read in anything. BUT we have to write the current * [deferred] page out, as the window of failure is too great. */ db->curbit = 2 * db->curbit + ((hash & (db->hmask + 1)) ? 2 : 1); db->hmask |= (db->hmask + 1); if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0 || write(db->pagf, db->pagbuf, PBLKSIZ) < 0) return 0; } while (--smax); /* * if we are here, this is real bad news. After SPLTMAX splits, * we still cannot fit the key. say goodnight. */ #ifdef BADMESS (void) write(2, "sdbm: cannot insert after SPLTMAX attempts.\n", 44); #endif return 0; } /* * the following two routines will break if * deletions aren't taken into account. (ndbm bug) */ datum sdbm_firstkey(db) register DBM *db; { if (db == NULL) return errno = EINVAL, nullitem; /* * start at page 0 */ (void) memset(db->pagbuf, 0, PBLKSIZ); if (lseek(db->pagf, OFF_PAG(0), SEEK_SET) < 0 || read(db->pagf, db->pagbuf, PBLKSIZ) < 0) return ioerr(db), nullitem; db->pagbno = 0; db->blkptr = 0; db->keyptr = 0; return getnext(db); } datum sdbm_nextkey(db) register DBM *db; { if (db == NULL) return errno = EINVAL, nullitem; return getnext(db); } /* * all important binary trie traversal */ static int getpage(db, hash) register DBM *db; register long hash; { register int hbit; register long dbit; register long pagb; dbit = 0; hbit = 0; while (dbit < db->maxbno && getdbit(db, dbit)) dbit = 2 * dbit + ((hash & ((long) 1 << hbit++)) ? 2 : 1); debug(("dbit: %d...", dbit)); db->curbit = dbit; db->hmask = masks[hbit]; pagb = hash & db->hmask; /* * see if the block we need is already in memory. * note: this lookaside cache has about 10% hit rate. */ if (pagb != db->pagbno) { /* * note: here, we assume a "hole" is read as 0s. * if not, must zero pagbuf first. */ (void) memset(db->pagbuf, 0, PBLKSIZ); if (lseek(db->pagf, OFF_PAG(pagb), SEEK_SET) < 0 || read(db->pagf, db->pagbuf, PBLKSIZ) < 0) return 0; if (!chkpage(db->pagbuf)) { return 0; } db->pagbno = pagb; debug(("pag read: %d\n", pagb)); } return 1; } static int getdbit(db, dbit) register DBM *db; register long dbit; { register long c; register long dirb; c = dbit / BYTESIZ; dirb = c / DBLKSIZ; if (dirb != db->dirbno) { if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0 || read(db->dirf, db->dirbuf, DBLKSIZ) < 0) return 0; db->dirbno = dirb; debug(("dir read: %d\n", dirb)); } return db->dirbuf[c % DBLKSIZ] & (1 << (dbit % BYTESIZ)); } static int setdbit(db, dbit) register DBM *db; register long dbit; { register long c; register long dirb; c = dbit / BYTESIZ; dirb = c / DBLKSIZ; if (dirb != db->dirbno) { if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0 || read(db->dirf, db->dirbuf, DBLKSIZ) < 0) return 0; db->dirbno = dirb; debug(("dir read: %d\n", dirb)); } db->dirbuf[c % DBLKSIZ] |= (1 << (dbit % BYTESIZ)); if (dbit >= db->maxbno) db->maxbno += (long) DBLKSIZ * BYTESIZ; if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0 || write(db->dirf, db->dirbuf, DBLKSIZ) < 0) return 0; return 1; } /* * getnext - get the next key in the page, and if done with * the page, try the next page in sequence */ static datum getnext(db) register DBM *db; { datum key; for (;;) { db->keyptr++; key = getnkey(db->pagbuf, db->keyptr); if (key.dptr != NULL) return key; /* * we either run out, or there is nothing on this page.. * try the next one... If we lost our position on the * file, we will have to seek. */ db->keyptr = 0; if (db->pagbno != db->blkptr++) if (lseek(db->pagf, OFF_PAG(db->blkptr), SEEK_SET) < 0) break; db->pagbno = db->blkptr; if (read(db->pagf, db->pagbuf, PBLKSIZ) <= 0) break; if (!chkpage(db->pagbuf)) { break; } } return ioerr(db), nullitem; } /* pair.c */ /* * sdbm - ndbm work-alike hashed database library * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978). * author: oz@nexus.yorku.ca * status: public domain. * * page-level routines */ #ifndef lint /*char pair_rcsid[] = "$Id$";*/ #endif #ifndef BSD42 /*#include */ #endif #define exhash(item) sdbm_hash((item).dptr, (item).dsize) /* * forward */ static int seepair proto((char *, int, char *, int)); /* * page format: * +------------------------------+ * ino | n | keyoff | datoff | keyoff | * +------------+--------+--------+ * | datoff | - - - ----> | * +--------+---------------------+ * | F R E E A R E A | * +--------------+---------------+ * | <---- - - - | data | * +--------+-----+----+----------+ * | key | data | key | * +--------+----------+----------+ * * calculating the offsets for free area: if the number * of entries (ino[0]) is zero, the offset to the END of * the free area is the block size. Otherwise, it is the * nth (ino[ino[0]]) entry's offset. */ static int fitpair(pag, need) char *pag; int need; { register int n; register int off; register int free; register short *ino = (short *) pag; off = ((n = GET_SHORT(ino,0)) > 0) ? GET_SHORT(ino,n) : PBLKSIZ; free = off - (n + 1) * sizeof(short); need += 2 * sizeof(short); debug(("free %d need %d\n", free, need)); return need <= free; } static void putpair(pag, key, val) char *pag; datum key; datum val; { register int n; register int off; register short *ino = (short *) pag; off = ((n = GET_SHORT(ino,0)) > 0) ? GET_SHORT(ino,n) : PBLKSIZ; /* * enter the key first */ off -= key.dsize; if (key.dsize) (void) memcpy(pag + off, key.dptr, key.dsize); PUT_SHORT(ino,n + 1,off); /* * now the data */ off -= val.dsize; if (val.dsize) (void) memcpy(pag + off, val.dptr, val.dsize); PUT_SHORT(ino,n + 2,off); /* * adjust item count */ PUT_SHORT(ino,0,GET_SHORT(ino,0) + 2); } static datum getpair(pag, key) char *pag; datum key; { register int i; register int n; datum val; register short *ino = (short *) pag; if ((n = GET_SHORT(ino,0)) == 0) return nullitem; if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0) return nullitem; val.dptr = pag + GET_SHORT(ino,i + 1); val.dsize = GET_SHORT(ino,i) - GET_SHORT(ino,i + 1); return val; } #ifdef SEEDUPS static int duppair(pag, key) char *pag; datum key; { register short *ino = (short *) pag; return GET_SHORT(ino,0) > 0 && seepair(pag, GET_SHORT(ino,0), key.dptr, key.dsize) > 0; } #endif static datum getnkey(pag, num) char *pag; int num; { datum key; register int off; register short *ino = (short *) pag; num = num * 2 - 1; if (GET_SHORT(ino,0) == 0 || num > GET_SHORT(ino,0)) return nullitem; off = (num > 1) ? GET_SHORT(ino,num - 1) : PBLKSIZ; key.dptr = pag + GET_SHORT(ino,num); key.dsize = off - GET_SHORT(ino,num); return key; } static int delpair(pag, key) char *pag; datum key; { register int n; register int i; register short *ino = (short *) pag; if ((n = GET_SHORT(ino,0)) == 0) return 0; if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0) return 0; /* * found the key. if it is the last entry * [i.e. i == n - 1] we just adjust the entry count. * hard case: move all data down onto the deleted pair, * shift offsets onto deleted offsets, and adjust them. * [note: 0 < i < n] */ if (i < n - 1) { register int m; register char *dst = pag + (i == 1 ? PBLKSIZ : GET_SHORT(ino,i - 1)); register char *src = pag + GET_SHORT(ino,i + 1); register int zoo = dst - src; debug(("free-up %d ", zoo)); /* * shift data/keys down */ m = GET_SHORT(ino,i + 1) - GET_SHORT(ino,n); #ifdef DUFF #define MOVB *--dst = *--src if (m > 0) { register int loop = (m + 8 - 1) >> 3; switch (m & (8 - 1)) { case 0: do { MOVB; case 7: MOVB; case 6: MOVB; case 5: MOVB; case 4: MOVB; case 3: MOVB; case 2: MOVB; case 1: MOVB; } while (--loop); } } #else #ifdef MEMMOVE memmove(dst, src, m); #else while (m--) *--dst = *--src; #endif #endif /* * adjust offset index up */ while (i < n - 1) { PUT_SHORT(ino,i, GET_SHORT(ino,i + 2) + zoo); i++; } } PUT_SHORT(ino, 0, GET_SHORT(ino, 0) - 2); return 1; } /* * search for the key in the page. * return offset index in the range 0 < i < n. * return 0 if not found. */ static int seepair(pag, n, key, siz) char *pag; register int n; register char *key; register int siz; { register int i; register int off = PBLKSIZ; register short *ino = (short *) pag; for (i = 1; i < n; i += 2) { if (siz == off - GET_SHORT(ino,i) && memcmp(key, pag + GET_SHORT(ino,i), siz) == 0) return i; off = GET_SHORT(ino,i + 1); } return 0; } static void splpage(pag, new, sbit) char *pag; char *new; long sbit; { datum key; datum val; register int n; register int off = PBLKSIZ; char cur[PBLKSIZ]; register short *ino = (short *) cur; (void) memcpy(cur, pag, PBLKSIZ); (void) memset(pag, 0, PBLKSIZ); (void) memset(new, 0, PBLKSIZ); n = GET_SHORT(ino,0); for (ino++; n > 0; ino += 2) { key.dptr = cur + GET_SHORT(ino,0); key.dsize = off - GET_SHORT(ino,0); val.dptr = cur + GET_SHORT(ino,1); val.dsize = GET_SHORT(ino,0) - GET_SHORT(ino,1); /* * select the page pointer (by looking at sbit) and insert */ (void) putpair((exhash(key) & sbit) ? new : pag, key, val); off = GET_SHORT(ino,1); n -= 2; } debug(("%d split %d/%d\n", ((short *) cur)[0] / 2, ((short *) new)[0] / 2, ((short *) pag)[0] / 2)); } /* * check page sanity: * number of entries should be something * reasonable, and all offsets in the index should be in order. * this could be made more rigorous. */ static int chkpage(pag) char *pag; { register int n; register int off; register short *ino = (short *) pag; if ((n = GET_SHORT(ino,0)) < 0 || n > PBLKSIZ / sizeof(short)) return 0; if (n > 0) { off = PBLKSIZ; for (ino++; n > 0; ino += 2) { if (GET_SHORT(ino,0) > off || GET_SHORT(ino,1) > off || GET_SHORT(ino,1) > GET_SHORT(ino,0)) return 0; off = GET_SHORT(ino,1); n -= 2; } } return 1; } /* hash.c */ /* * sdbm - ndbm work-alike hashed database library * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978). * author: oz@nexus.yorku.ca * status: public domain. keep it that way. * * hashing routine */ /* * polynomial conversion ignoring overflows * [this seems to work remarkably well, in fact better * then the ndbm hash function. Replace at your own risk] * use: 65599 nice. * 65587 even better. */ long sdbm_hash(str, len) register char *str; register int len; { register unsigned long n = 0; #ifdef DUFF #define HASHC n = *str++ + 65599 * n if (len > 0) { register int loop = (len + 8 - 1) >> 3; switch(len & (8 - 1)) { case 0: do { HASHC; case 7: HASHC; case 6: HASHC; case 5: HASHC; case 4: HASHC; case 3: HASHC; case 2: HASHC; case 1: HASHC; } while (--loop); } } #else while (len--) n = ((*str++) & 255) + 65587L * n; #endif return n; } ================================================ FILE: ext/sdbm/depend ================================================ _sdbm.o: _sdbm.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h init.o: init.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h ================================================ FILE: ext/sdbm/extconf.rb ================================================ require 'mkmf' create_makefile("sdbm") ================================================ FILE: ext/sdbm/init.c ================================================ /************************************************ sdbminit.c - $Author$ $Date$ created at: Fri May 7 08:34:24 JST 1999 Copyright (C) 1995-2001 Yukihiro Matsumoto ************************************************/ #include "ruby.h" #include "sdbm.h" #include #include static VALUE rb_cDBM, rb_eDBMError; struct dbmdata { int di_size; DBM *di_dbm; }; static void closed_sdbm() { rb_raise(rb_eDBMError, "closed SDBM file"); } #define GetDBM(obj, dbmp) {\ Data_Get_Struct(obj, struct dbmdata, dbmp);\ if (dbmp == 0) closed_sdbm();\ if (dbmp->di_dbm == 0) closed_sdbm();\ } #define GetDBM2(obj, data, dbm) {\ GetDBM(obj, data);\ (dbm) = dbmp->di_dbm;\ } static void free_sdbm(dbmp) struct dbmdata *dbmp; { if (dbmp->di_dbm) sdbm_close(dbmp->di_dbm); free(dbmp); } static VALUE fsdbm_close(obj) VALUE obj; { struct dbmdata *dbmp; GetDBM(obj, dbmp); sdbm_close(dbmp->di_dbm); dbmp->di_dbm = 0; return Qnil; } static VALUE fsdbm_closed(obj) VALUE obj; { struct dbmdata *dbmp; Data_Get_Struct(obj, struct dbmdata, dbmp); if (dbmp == 0) return Qtrue; if (dbmp->di_dbm == 0) return Qtrue; return Qfalse; } static VALUE fsdbm_alloc _((VALUE)); static VALUE fsdbm_alloc(klass) VALUE klass; { return Data_Wrap_Struct(klass, 0, free_sdbm, 0); } static VALUE fsdbm_initialize(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE file, vmode; DBM *dbm; struct dbmdata *dbmp; int mode; if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) { mode = 0666; /* default value */ } else if (NIL_P(vmode)) { mode = -1; /* return nil if DB not exist */ } else { mode = NUM2INT(vmode); } SafeStringValue(file); dbm = 0; if (mode >= 0) dbm = sdbm_open(RSTRING(file)->ptr, O_RDWR|O_CREAT, mode); if (!dbm) dbm = sdbm_open(RSTRING(file)->ptr, O_RDWR, 0); if (!dbm) dbm = sdbm_open(RSTRING(file)->ptr, O_RDONLY, 0); if (!dbm) { if (mode == -1) return Qnil; rb_sys_fail(RSTRING(file)->ptr); } dbmp = ALLOC(struct dbmdata); DATA_PTR(obj) = dbmp; dbmp->di_dbm = dbm; dbmp->di_size = -1; return obj; } static VALUE fsdbm_s_open(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { VALUE obj = Data_Wrap_Struct(klass, 0, free_sdbm, 0); if (NIL_P(fsdbm_initialize(argc, argv, obj))) { return Qnil; } if (rb_block_given_p()) { return rb_ensure(rb_yield, obj, fsdbm_close, obj); } return obj; } static VALUE fsdbm_fetch(obj, keystr, ifnone) VALUE obj, keystr, ifnone; { datum key, value; struct dbmdata *dbmp; DBM *dbm; StringValue(keystr); key.dptr = RSTRING(keystr)->ptr; key.dsize = RSTRING(keystr)->len; GetDBM2(obj, dbmp, dbm); value = sdbm_fetch(dbm, key); if (value.dptr == 0) { if (ifnone == Qnil && rb_block_given_p()) return rb_yield(rb_tainted_str_new(key.dptr, key.dsize)); return ifnone; } return rb_tainted_str_new(value.dptr, value.dsize); } static VALUE fsdbm_aref(obj, keystr) VALUE obj, keystr; { return fsdbm_fetch(obj, keystr, Qnil); } static VALUE fsdbm_fetch_m(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE keystr, valstr, ifnone; rb_scan_args(argc, argv, "11", &keystr, &ifnone); valstr = fsdbm_fetch(obj, keystr, ifnone); if (argc == 1 && !rb_block_given_p() && NIL_P(valstr)) rb_raise(rb_eIndexError, "key not found"); return valstr; } static VALUE fsdbm_index(obj, valstr) VALUE obj, valstr; { datum key, val; struct dbmdata *dbmp; DBM *dbm; StringValue(valstr); val.dptr = RSTRING(valstr)->ptr; val.dsize = RSTRING(valstr)->len; GetDBM2(obj, dbmp, dbm); for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) { val = sdbm_fetch(dbm, key); if (val.dsize == RSTRING(valstr)->len && memcmp(val.dptr, RSTRING(valstr)->ptr, val.dsize) == 0) return rb_tainted_str_new(key.dptr, key.dsize); } return Qnil; } static VALUE fsdbm_indexes(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE new; int i; new = rb_ary_new2(argc); for (i=0; i 0) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc); } GetDBM2(obj, dbmp, dbm); for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) { VALUE assoc, v; val = sdbm_fetch(dbm, key); assoc = rb_assoc_new(rb_tainted_str_new(key.dptr, key.dsize), rb_tainted_str_new(val.dptr, val.dsize)); v = rb_yield(assoc); if (RTEST(v)) { rb_ary_push(new, assoc); } GetDBM2(obj, dbmp, dbm); } } else { rb_warn("SDBM#select(index..) is deprecated; use SDBM#values_at"); for (i=0; iptr; key.dsize = RSTRING(keystr)->len; GetDBM2(obj, dbmp, dbm); dbmp->di_size = -1; value = sdbm_fetch(dbm, key); if (value.dptr == 0) { if (rb_block_given_p()) return rb_yield(keystr); return Qnil; } /* need to save value before sdbm_delete() */ valstr = rb_tainted_str_new(value.dptr, value.dsize); if (sdbm_delete(dbm, key)) { dbmp->di_size = -1; rb_raise(rb_eDBMError, "dbm_delete failed"); } else if (dbmp->di_size >= 0) { dbmp->di_size--; } return valstr; } static VALUE fsdbm_shift(obj) VALUE obj; { datum key, val; struct dbmdata *dbmp; DBM *dbm; VALUE keystr, valstr; fdbm_modify(obj); GetDBM2(obj, dbmp, dbm); key = sdbm_firstkey(dbm); if (!key.dptr) return Qnil; val = sdbm_fetch(dbm, key); keystr = rb_tainted_str_new(key.dptr, key.dsize); valstr = rb_tainted_str_new(val.dptr, val.dsize); sdbm_delete(dbm, key); if (dbmp->di_size >= 0) { dbmp->di_size--; } return rb_assoc_new(keystr, valstr); } static VALUE fsdbm_delete_if(obj) VALUE obj; { datum key, val; struct dbmdata *dbmp; DBM *dbm; VALUE keystr, valstr; VALUE ret, ary = rb_ary_new(); int i, status = 0, n; fdbm_modify(obj); GetDBM2(obj, dbmp, dbm); n = dbmp->di_size; dbmp->di_size = -1; for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) { val = sdbm_fetch(dbm, key); keystr = rb_tainted_str_new(key.dptr, key.dsize); valstr = rb_tainted_str_new(val.dptr, val.dsize); ret = rb_protect(rb_yield, rb_assoc_new(rb_str_dup(keystr), valstr), &status); if (status != 0) break; if (RTEST(ret)) rb_ary_push(ary, keystr); GetDBM2(obj, dbmp, dbm); } for (i = 0; i < RARRAY(ary)->len; i++) { keystr = RARRAY(ary)->ptr[i]; StringValue(keystr); key.dptr = RSTRING(keystr)->ptr; key.dsize = RSTRING(keystr)->len; if (sdbm_delete(dbm, key)) { rb_raise(rb_eDBMError, "sdbm_delete failed"); } } if (status) rb_jump_tag(status); if (n > 0) dbmp->di_size = n - RARRAY(ary)->len; return obj; } static VALUE fsdbm_clear(obj) VALUE obj; { datum key; struct dbmdata *dbmp; DBM *dbm; fdbm_modify(obj); GetDBM2(obj, dbmp, dbm); dbmp->di_size = -1; while (key = sdbm_firstkey(dbm), key.dptr) { if (sdbm_delete(dbm, key)) { rb_raise(rb_eDBMError, "sdbm_delete failed"); } } dbmp->di_size = 0; return obj; } static VALUE fsdbm_invert(obj) VALUE obj; { datum key, val; struct dbmdata *dbmp; DBM *dbm; VALUE keystr, valstr; VALUE hash = rb_hash_new(); GetDBM2(obj, dbmp, dbm); for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) { val = sdbm_fetch(dbm, key); keystr = rb_tainted_str_new(key.dptr, key.dsize); valstr = rb_tainted_str_new(val.dptr, val.dsize); rb_hash_aset(hash, valstr, keystr); } return hash; } static VALUE each_pair _((VALUE)); static VALUE each_pair(obj) VALUE obj; { return rb_funcall(obj, rb_intern("each_pair"), 0, 0); } static VALUE fsdbm_store _((VALUE,VALUE,VALUE)); static VALUE update_i(pair, dbm) VALUE pair, dbm; { Check_Type(pair, T_ARRAY); if (RARRAY(pair)->len < 2) { rb_raise(rb_eArgError, "pair must be [key, value]"); } fsdbm_store(dbm, RARRAY(pair)->ptr[0], RARRAY(pair)->ptr[1]); return Qnil; } static VALUE fsdbm_update(obj, other) VALUE obj, other; { rb_iterate(each_pair, other, update_i, obj); return obj; } static VALUE fsdbm_replace(obj, other) VALUE obj, other; { fsdbm_clear(obj); rb_iterate(each_pair, other, update_i, obj); return obj; } static VALUE fsdbm_store(obj, keystr, valstr) VALUE obj, keystr, valstr; { datum key, val; struct dbmdata *dbmp; DBM *dbm; if (valstr == Qnil) { fsdbm_delete(obj, keystr); return Qnil; } fdbm_modify(obj); StringValue(keystr); StringValue(valstr); key.dptr = RSTRING(keystr)->ptr; key.dsize = RSTRING(keystr)->len; val.dptr = RSTRING(valstr)->ptr; val.dsize = RSTRING(valstr)->len; GetDBM2(obj, dbmp, dbm); dbmp->di_size = -1; if (sdbm_store(dbm, key, val, DBM_REPLACE)) { #ifdef HAVE_DBM_CLAERERR sdbm_clearerr(dbm); #endif if (errno == EPERM) rb_sys_fail(0); rb_raise(rb_eDBMError, "sdbm_store failed"); } return valstr; } static VALUE fsdbm_length(obj) VALUE obj; { datum key; struct dbmdata *dbmp; DBM *dbm; int i = 0; GetDBM2(obj, dbmp, dbm); if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size); for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) { i++; } dbmp->di_size = i; return INT2FIX(i); } static VALUE fsdbm_empty_p(obj) VALUE obj; { datum key; struct dbmdata *dbmp; DBM *dbm; int i = 0; GetDBM(obj, dbmp); if (dbmp->di_size < 0) { dbm = dbmp->di_dbm; for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) { i++; } } else { i = dbmp->di_size; } if (i == 0) return Qtrue; return Qfalse; } static VALUE fsdbm_each_value(obj) VALUE obj; { datum key, val; struct dbmdata *dbmp; DBM *dbm; GetDBM2(obj, dbmp, dbm); for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) { val = sdbm_fetch(dbm, key); rb_yield(rb_tainted_str_new(val.dptr, val.dsize)); GetDBM2(obj, dbmp, dbm); } return obj; } static VALUE fsdbm_each_key(obj) VALUE obj; { datum key; struct dbmdata *dbmp; DBM *dbm; GetDBM2(obj, dbmp, dbm); for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) { rb_yield(rb_tainted_str_new(key.dptr, key.dsize)); GetDBM2(obj, dbmp, dbm); } return obj; } static VALUE fsdbm_each_pair(obj) VALUE obj; { datum key, val; DBM *dbm; struct dbmdata *dbmp; VALUE keystr, valstr; GetDBM2(obj, dbmp, dbm); for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) { val = sdbm_fetch(dbm, key); keystr = rb_tainted_str_new(key.dptr, key.dsize); valstr = rb_tainted_str_new(val.dptr, val.dsize); rb_yield(rb_assoc_new(keystr, valstr)); GetDBM2(obj, dbmp, dbm); } return obj; } static VALUE fsdbm_keys(obj) VALUE obj; { datum key; struct dbmdata *dbmp; DBM *dbm; VALUE ary; GetDBM2(obj, dbmp, dbm); ary = rb_ary_new(); for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) { rb_ary_push(ary, rb_tainted_str_new(key.dptr, key.dsize)); } return ary; } static VALUE fsdbm_values(obj) VALUE obj; { datum key, val; struct dbmdata *dbmp; DBM *dbm; VALUE ary; GetDBM2(obj, dbmp, dbm); ary = rb_ary_new(); for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) { val = sdbm_fetch(dbm, key); rb_ary_push(ary, rb_tainted_str_new(val.dptr, val.dsize)); } return ary; } static VALUE fsdbm_has_key(obj, keystr) VALUE obj, keystr; { datum key, val; struct dbmdata *dbmp; DBM *dbm; StringValue(keystr); key.dptr = RSTRING(keystr)->ptr; key.dsize = RSTRING(keystr)->len; GetDBM2(obj, dbmp, dbm); val = sdbm_fetch(dbm, key); if (val.dptr) return Qtrue; return Qfalse; } static VALUE fsdbm_has_value(obj, valstr) VALUE obj, valstr; { datum key, val; struct dbmdata *dbmp; DBM *dbm; StringValue(valstr); val.dptr = RSTRING(valstr)->ptr; val.dsize = RSTRING(valstr)->len; GetDBM2(obj, dbmp, dbm); for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) { val = sdbm_fetch(dbm, key); if (val.dsize == RSTRING(valstr)->len && memcmp(val.dptr, RSTRING(valstr)->ptr, val.dsize) == 0) return Qtrue; } return Qfalse; } static VALUE fsdbm_to_a(obj) VALUE obj; { datum key, val; struct dbmdata *dbmp; DBM *dbm; VALUE ary; GetDBM2(obj, dbmp, dbm); ary = rb_ary_new(); for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) { val = sdbm_fetch(dbm, key); rb_ary_push(ary, rb_assoc_new(rb_tainted_str_new(key.dptr, key.dsize), rb_tainted_str_new(val.dptr, val.dsize))); } return ary; } static VALUE fsdbm_to_hash(obj) VALUE obj; { datum key, val; struct dbmdata *dbmp; DBM *dbm; VALUE hash; GetDBM2(obj, dbmp, dbm); hash = rb_hash_new(); for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) { val = sdbm_fetch(dbm, key); rb_hash_aset(hash, rb_tainted_str_new(key.dptr, key.dsize), rb_tainted_str_new(val.dptr, val.dsize)); } return hash; } static VALUE fsdbm_reject(obj) VALUE obj; { return rb_hash_delete_if(fsdbm_to_hash(obj)); } void Init_sdbm() { rb_cDBM = rb_define_class("SDBM", rb_cObject); rb_eDBMError = rb_define_class("SDBMError", rb_eStandardError); rb_include_module(rb_cDBM, rb_mEnumerable); rb_define_alloc_func(rb_cDBM, fsdbm_alloc); rb_define_singleton_method(rb_cDBM, "open", fsdbm_s_open, -1); rb_define_method(rb_cDBM, "initialize", fsdbm_initialize, -1); rb_define_method(rb_cDBM, "close", fsdbm_close, 0); rb_define_method(rb_cDBM, "closed?", fsdbm_closed, 0); rb_define_method(rb_cDBM, "[]", fsdbm_aref, 1); rb_define_method(rb_cDBM, "fetch", fsdbm_fetch_m, -1); rb_define_method(rb_cDBM, "[]=", fsdbm_store, 2); rb_define_method(rb_cDBM, "store", fsdbm_store, 2); rb_define_method(rb_cDBM, "index", fsdbm_index, 1); rb_define_method(rb_cDBM, "indexes", fsdbm_indexes, -1); rb_define_method(rb_cDBM, "indices", fsdbm_indexes, -1); rb_define_method(rb_cDBM, "select", fsdbm_select, -1); rb_define_method(rb_cDBM, "values_at", fsdbm_values_at, -1); rb_define_method(rb_cDBM, "length", fsdbm_length, 0); rb_define_method(rb_cDBM, "size", fsdbm_length, 0); rb_define_method(rb_cDBM, "empty?", fsdbm_empty_p, 0); rb_define_method(rb_cDBM, "each", fsdbm_each_pair, 0); rb_define_method(rb_cDBM, "each_value", fsdbm_each_value, 0); rb_define_method(rb_cDBM, "each_key", fsdbm_each_key, 0); rb_define_method(rb_cDBM, "each_pair", fsdbm_each_pair, 0); rb_define_method(rb_cDBM, "keys", fsdbm_keys, 0); rb_define_method(rb_cDBM, "values", fsdbm_values, 0); rb_define_method(rb_cDBM, "shift", fsdbm_shift, 0); rb_define_method(rb_cDBM, "delete", fsdbm_delete, 1); rb_define_method(rb_cDBM, "delete_if", fsdbm_delete_if, 0); rb_define_method(rb_cDBM, "reject!", fsdbm_delete_if, 0); rb_define_method(rb_cDBM, "reject", fsdbm_reject, 0); rb_define_method(rb_cDBM, "clear", fsdbm_clear, 0); rb_define_method(rb_cDBM,"invert", fsdbm_invert, 0); rb_define_method(rb_cDBM,"update", fsdbm_update, 1); rb_define_method(rb_cDBM,"replace", fsdbm_replace, 1); rb_define_method(rb_cDBM, "include?", fsdbm_has_key, 1); rb_define_method(rb_cDBM, "has_key?", fsdbm_has_key, 1); rb_define_method(rb_cDBM, "member?", fsdbm_has_key, 1); rb_define_method(rb_cDBM, "has_value?", fsdbm_has_value, 1); rb_define_method(rb_cDBM, "key?", fsdbm_has_key, 1); rb_define_method(rb_cDBM, "value?", fsdbm_has_value, 1); rb_define_method(rb_cDBM, "to_a", fsdbm_to_a, 0); rb_define_method(rb_cDBM, "to_hash", fsdbm_to_hash, 0); } ================================================ FILE: ext/sdbm/sdbm.h ================================================ /* * sdbm - ndbm work-alike hashed database library * based on Per-Ake Larson's Dynamic Hashing algorithms. BIT 18 (1978). * author: oz@nexus.yorku.ca * status: public domain. */ #ifndef _SDBM_H_ #define _SDBM_H_ #define DBLKSIZ 4096 #define PBLKSIZ 1024 #define PAIRMAX 1008 /* arbitrary on PBLKSIZ-N */ #define SPLTMAX 10 /* maximum allowed splits */ /* for a single insertion */ #define DIRFEXT ".dir" #define PAGFEXT ".pag" typedef struct { int dirf; /* directory file descriptor */ int pagf; /* page file descriptor */ int flags; /* status/error flags, see below */ long maxbno; /* size of dirfile in bits */ long curbit; /* current bit number */ long hmask; /* current hash mask */ long blkptr; /* current block for nextkey */ int keyptr; /* current key for nextkey */ long blkno; /* current page to read/write */ long pagbno; /* current page in pagbuf */ char pagbuf[PBLKSIZ]; /* page file block buffer */ long dirbno; /* current block in dirbuf */ char dirbuf[DBLKSIZ]; /* directory file block buffer */ } DBM; #define DBM_RDONLY 0x1 /* data base open read-only */ #define DBM_IOERR 0x2 /* data base I/O error */ /* * utility macros */ #define sdbm_rdonly(db) ((db)->flags & DBM_RDONLY) #define sdbm_error(db) ((db)->flags & DBM_IOERR) #define sdbm_clearerr(db) ((db)->flags &= ~DBM_IOERR) /* ouch */ #define sdbm_dirfno(db) ((db)->dirf) #define sdbm_pagfno(db) ((db)->pagf) typedef struct { char *dptr; int dsize; } datum; extern datum nullitem; #if defined(__STDC__) || defined(MSDOS) #define proto(p) p #else #define proto(p) () #endif /* * flags to sdbm_store */ #define DBM_INSERT 0 #define DBM_REPLACE 1 /* * ndbm interface */ extern DBM *sdbm_open proto((char *, int, int)); extern void sdbm_close proto((DBM *)); extern datum sdbm_fetch proto((DBM *, datum)); extern int sdbm_delete proto((DBM *, datum)); extern int sdbm_store proto((DBM *, datum, datum, int)); extern datum sdbm_firstkey proto((DBM *)); extern datum sdbm_nextkey proto((DBM *)); /* * other */ extern DBM *sdbm_prep proto((char *, char *, int, int)); extern long sdbm_hash proto((char *, int)); #endif /* _SDBM_H_ */ ================================================ FILE: ext/socket/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/socket/addrinfo.h ================================================ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef ADDR_INFO_H #define ADDR_INFO_H #ifndef HAVE_GETADDRINFO /* special compatibility hack */ #undef EAI_ADDRFAMILY #undef EAI_AGAIN #undef EAI_BADFLAGS #undef EAI_FAIL #undef EAI_FAMILY #undef EAI_MEMORY #undef EAI_NODATA #undef EAI_NONAME #undef EAI_SERVICE #undef EAI_SOCKTYPE #undef EAI_SYSTEM #undef EAI_BADHINTS #undef EAI_PROTOCOL #undef EAI_MAX #undef AI_PASSIVE #undef AI_CANONNAME #undef AI_NUMERICHOST #undef AI_ALL #undef AI_ADDRCONFIG #undef AI_V4MAPPED #undef AI_DEFAULT #undef NI_NOFQDN #undef NI_NUMERICHOST #undef NI_NAMEREQD #undef NI_NUMERICSERV #undef NI_DGRAM #undef addrinfo #define addrinfo addrinfo__compat #undef getaddrinfo #define getaddrinfo getaddrinfo__compat #undef getnameinfo #define getnameinfo getnameinfo__compat #undef freehostent #define freehostent freehostent__compat #undef freeaddrinfo #define freeaddrinfo freeaddrinfo__compat #ifndef __P # ifdef HAVE_PROTOTYPES # define __P(args) args # else # define __P(args) () # endif #endif /* special compatibility hack -- end*/ /* * Error return codes from getaddrinfo() */ #define EAI_ADDRFAMILY 1 /* address family for hostname not supported */ #define EAI_AGAIN 2 /* temporary failure in name resolution */ #define EAI_BADFLAGS 3 /* invalid value for ai_flags */ #define EAI_FAIL 4 /* non-recoverable failure in name resolution */ #define EAI_FAMILY 5 /* ai_family not supported */ #define EAI_MEMORY 6 /* memory allocation failure */ #define EAI_NODATA 7 /* no address associated with hostname */ #define EAI_NONAME 8 /* hostname nor servname provided, or not known */ #define EAI_SERVICE 9 /* servname not supported for ai_socktype */ #define EAI_SOCKTYPE 10 /* ai_socktype not supported */ #define EAI_SYSTEM 11 /* system error returned in errno */ #define EAI_BADHINTS 12 #define EAI_PROTOCOL 13 #define EAI_MAX 14 /* * Flag values for getaddrinfo() */ #define AI_PASSIVE 0x00000001 /* get address to use bind() */ #define AI_CANONNAME 0x00000002 /* fill ai_canonname */ #define AI_NUMERICHOST 0x00000004 /* prevent name resolution */ /* valid flags for addrinfo */ #define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST) #define AI_ALL 0x00000100 /* IPv6 and IPv4-mapped (with AI_V4MAPPED) */ #define AI_V4MAPPED_CFG 0x00000200 /* accept IPv4-mapped if kernel supports */ #define AI_ADDRCONFIG 0x00000400 /* only if any address is assigned */ #define AI_V4MAPPED 0x00000800 /* accept IPv4-mapped IPv6 address */ /* special recommended flags for getipnodebyname */ #define AI_DEFAULT (AI_V4MAPPED_CFG | AI_ADDRCONFIG) /* * Constants for getnameinfo() */ #ifndef NI_MAXHOST #define NI_MAXHOST 1025 #define NI_MAXSERV 32 #endif /* * Flag values for getnameinfo() */ #define NI_NOFQDN 0x00000001 #define NI_NUMERICHOST 0x00000002 #define NI_NAMEREQD 0x00000004 #define NI_NUMERICSERV 0x00000008 #define NI_DGRAM 0x00000010 struct addrinfo { int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ int ai_family; /* PF_xxx */ int ai_socktype; /* SOCK_xxx */ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ size_t ai_addrlen; /* length of ai_addr */ char *ai_canonname; /* canonical name for hostname */ struct sockaddr *ai_addr; /* binary address */ struct addrinfo *ai_next; /* next structure in linked list */ }; extern int getaddrinfo __P(( const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res)); extern int getnameinfo __P(( const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags)); extern void freehostent __P((struct hostent *)); extern void freeaddrinfo __P((struct addrinfo *)); #if defined __UCLIBC__ const #endif extern char *gai_strerror __P((int)); /* In case there is no definition of offsetof() provided - though any proper Standard C system should have one. */ #ifndef offsetof #define offsetof(p_type,field) ((size_t)&(((p_type *)0)->field)) #endif #endif #endif ================================================ FILE: ext/socket/depend ================================================ socket.o : socket.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/rubyio.h $(hdrdir)/rubysig.h sockport.h getnameinfo.o: getnameinfo.c $(topdir)/config.h addrinfo.h sockport.h getaddrinfo.o: getaddrinfo.c $(topdir)/config.h addrinfo.h sockport.h ================================================ FILE: ext/socket/extconf.rb ================================================ require 'mkmf' case RUBY_PLATFORM when /bccwin32/ test_func = "WSACleanup" have_library("ws2_32", "WSACleanup") when /mswin32|mingw/ test_func = "WSACleanup" if with_config("winsock2") have_library("ws2_32", "WSACleanup") else have_library("wsock32", "WSACleanup") end when /cygwin/ test_func = "socket" when /beos/ test_func = "socket" have_library("net", "socket") have_func("closesocket") when /i386-os2_emx/ test_func = "socket" have_library("socket", "socket") else test_func = "socket" have_library("nsl", "t_open") have_library("socket", "socket") end unless $mswin or $bccwin or $mingw headers = %w end if /solaris/ =~ RUBY_PLATFORM and !try_compile("") # bug of gcc 3.0 on Solaris 8 ? headers << "sys/feature_tests.h" end if have_header("arpa/inet.h") headers << "arpa/inet.h" end ipv6 = false default_ipv6 = /cygwin/ !~ RUBY_PLATFORM if enable_config("ipv6", default_ipv6) if checking_for("ipv6") {try_link(< #include main() { socket(AF_INET6, SOCK_STREAM, 0); } EOF $defs << "-DENABLE_IPV6" << "-DINET6" ipv6 = true end end if ipv6 ipv6lib = nil class << (fmt = "unknown") def %(s) s || self end end idirs, ldirs = dir_config("inet6", %w[/usr/inet6 /usr/local/v6].find {|d| File.directory?(d)}) checking_for("ipv6 type", fmt) do if have_macro("IPV6_INRIA_VERSION", "netinet/in.h") "inria" elsif have_macro("__KAME__", "netinet/in.h") have_library(ipv6lib = "inet6") "kame" elsif have_macro("_TOSHIBA_INET6", "sys/param.h") have_library(ipv6lib = "inet6") and "toshiba" elsif have_macro("__V6D__", "sys/v6config.h") have_library(ipv6lib = "v6") and "v6d" elsif have_macro("_ZETA_MINAMI_INET6", "sys/param.h") have_library(ipv6lib = "inet6") and "zeta" elsif ipv6lib = with_config("ipv6-lib") warn < #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 #endif #ifndef EXIT_FAILURE #define EXIT_FAILURE 1 #endif #ifndef AF_LOCAL #define AF_LOCAL AF_UNIX #endif main() { int passive, gaierr, inet4 = 0, inet6 = 0; struct addrinfo hints, *ai, *aitop; char straddr[INET6_ADDRSTRLEN], strport[16]; for (passive = 0; passive <= 1; passive++) { memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = passive ? AI_PASSIVE : 0; hints.ai_socktype = SOCK_STREAM; if ((gaierr = getaddrinfo(NULL, "54321", &hints, &aitop)) != 0) { (void)gai_strerror(gaierr); goto bad; } for (ai = aitop; ai; ai = ai->ai_next) { if (ai->ai_family == AF_LOCAL) continue; if (ai->ai_addr == NULL) goto bad; #if defined(_AIX) if (ai->ai_family == AF_INET6 && passive) { inet6++; continue; } ai->ai_addr->sa_len = ai->ai_addrlen; ai->ai_addr->sa_family = ai->ai_family; #endif if (ai->ai_addrlen == 0 || getnameinfo(ai->ai_addr, ai->ai_addrlen, straddr, sizeof(straddr), strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { goto bad; } if (strcmp(strport, "54321") != 0) { goto bad; } switch (ai->ai_family) { case AF_INET: if (passive) { if (strcmp(straddr, "0.0.0.0") != 0) { goto bad; } } else { if (strcmp(straddr, "127.0.0.1") != 0) { goto bad; } } inet4++; break; case AF_INET6: if (passive) { if (strcmp(straddr, "::") != 0) { goto bad; } } else { if (strcmp(straddr, "::1") != 0) { goto bad; } } inet6++; break; case AF_UNSPEC: goto bad; break; default: /* another family support? */ break; } } } if (!(inet4 == 0 || inet4 == 2)) goto bad; if (!(inet6 == 0 || inet6 == 2)) goto bad; if (aitop) freeaddrinfo(aitop); exit(EXIT_SUCCESS); bad: if (aitop) freeaddrinfo(aitop); exit(EXIT_FAILURE); } EOF end if ipv6 and not getaddr_info_ok abort < void conftest_gai_strerror_is_const() { *gai_strerror(0) = 0; } EOF $defs << "-DGAI_STRERROR_CONST" end end have_header("arpa/nameser.h") have_header("resolv.h") end unless have_type("socklen_t", headers) $defs << "-Dsocklen_t=int" end have_header("sys/un.h") have_header("sys/uio.h") if have_func(test_func) have_func("hsterror") have_func("getipnodebyname") or have_func("gethostbyname2") have_func("socketpair") unless have_func("gethostname") have_func("uname") end if enable_config("socks", ENV["SOCKS_SERVER"]) if have_library("socks5", "SOCKSinit") $defs << "-DSOCKS5" << "-DSOCKS" elsif have_library("socks", "Rconnect") $defs << "-DSOCKS" end end create_makefile("socket") end ================================================ FILE: ext/socket/getaddrinfo.c ================================================ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator. * * Issues to be discussed: * - Thread safe-ness must be checked. * - Return values. There are nonstandard return values defined and used * in the source code. This is because RFC2133 is silent about which error * code must be returned for which situation. * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag. */ #include "config.h" #ifdef RUBY_EXTCONF_H #include RUBY_EXTCONF_H #endif #include #if !defined(_WIN32) && !defined(__VMS) #include #if defined(__BEOS__) # include #else # include #endif #include #if defined(HAVE_ARPA_INET_H) #include #endif #if defined(HAVE_ARPA_NAMESER_H) #include #endif #include #if defined(HAVE_RESOLV_H) #ifdef _SX #include #endif #include #endif #include #elif defined(__VMS ) #include #include #include #include #else #include #include #endif #include #include #include #include #include #ifdef SOCKS5 #include #endif #include "addrinfo.h" #include "sockport.h" #if defined(__KAME__) && defined(INET6) # define FAITH #endif #define SUCCESS 0 #define ANY 0 #define YES 1 #define NO 0 #ifdef FAITH static int translate = NO; static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT; #endif static const char in_addrany[] = { 0, 0, 0, 0 }; static const char in6_addrany[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const char in_loopback[] = { 127, 0, 0, 1 }; static const char in6_loopback[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; struct sockinet { u_char si_len; u_char si_family; u_short si_port; }; static const struct afd { int a_af; int a_addrlen; int a_socklen; int a_off; const char *a_addrany; const char *a_loopback; } afdl [] = { #ifdef INET6 #define N_INET6 0 {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), offsetof(struct sockaddr_in6, sin6_addr), in6_addrany, in6_loopback}, #define N_INET 1 #else #define N_INET 0 #endif {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), offsetof(struct sockaddr_in, sin_addr), in_addrany, in_loopback}, {0, 0, 0, 0, NULL, NULL}, }; #ifdef INET6 #define PTON_MAX 16 #else #define PTON_MAX 4 #endif static int get_name __P((const char *, const struct afd *, struct addrinfo **, char *, struct addrinfo *, int)); static int get_addr __P((const char *, int, struct addrinfo **, struct addrinfo *, int)); static int str_isnumber __P((const char *)); static const char *const ai_errlist[] = { "success.", "address family for hostname not supported.", /* EAI_ADDRFAMILY */ "temporary failure in name resolution.", /* EAI_AGAIN */ "invalid value for ai_flags.", /* EAI_BADFLAGS */ "non-recoverable failure in name resolution.", /* EAI_FAIL */ "ai_family not supported.", /* EAI_FAMILY */ "memory allocation failure.", /* EAI_MEMORY */ "no address associated with hostname.", /* EAI_NODATA */ "hostname nor servname provided, or not known.",/* EAI_NONAME */ "servname not supported for ai_socktype.", /* EAI_SERVICE */ "ai_socktype not supported.", /* EAI_SOCKTYPE */ "system error returned in errno.", /* EAI_SYSTEM */ "invalid value for hints.", /* EAI_BADHINTS */ "resolved protocol is unknown.", /* EAI_PROTOCOL */ "unknown error.", /* EAI_MAX */ }; #define GET_CANONNAME(ai, str) \ if (pai->ai_flags & AI_CANONNAME) {\ if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\ strcpy((ai)->ai_canonname, (str));\ } else {\ error = EAI_MEMORY;\ goto free;\ }\ } #define GET_AI(ai, afd, addr, port) {\ char *p;\ if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\ ((afd)->a_socklen)))\ == NULL) {\ error = EAI_MEMORY;\ goto free;\ }\ memcpy(ai, pai, sizeof(struct addrinfo));\ (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\ memset((ai)->ai_addr, 0, (afd)->a_socklen);\ SET_SA_LEN((ai)->ai_addr, (ai)->ai_addrlen = (afd)->a_socklen);\ (ai)->ai_addr->sa_family = (ai)->ai_family = (afd)->a_af;\ ((struct sockinet *)(ai)->ai_addr)->si_port = port;\ p = (char *)((ai)->ai_addr);\ memcpy(p + (afd)->a_off, (addr), (afd)->a_addrlen);\ } #define ERR(err) { error = (err); goto bad; } #ifndef HAVE_GAI_STRERROR #ifdef GAI_STRERROR_CONST const #endif char * gai_strerror(ecode) int ecode; { if (ecode < 0 || ecode > EAI_MAX) ecode = EAI_MAX; return (char *)ai_errlist[ecode]; } #endif void freeaddrinfo(ai) struct addrinfo *ai; { struct addrinfo *next; do { next = ai->ai_next; if (ai->ai_canonname) free(ai->ai_canonname); /* no need to free(ai->ai_addr) */ free(ai); } while ((ai = next) != NULL); } static int str_isnumber(p) const char *p; { char *q = (char *)p; while (*q) { if (! isdigit(*q)) return NO; q++; } return YES; } #ifndef HAVE_INET_PTON static int inet_pton(af, hostname, pton) int af; const char *hostname; void *pton; { struct in_addr in; #ifdef HAVE_INET_ATON if (!inet_aton(hostname, &in)) 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; } #endif int getaddrinfo(hostname, servname, hints, res) const char *hostname, *servname; const struct addrinfo *hints; struct addrinfo **res; { struct addrinfo sentinel; struct addrinfo *top = NULL; struct addrinfo *cur; int i, error = 0; char pton[PTON_MAX]; struct addrinfo ai; struct addrinfo *pai; u_short port; #ifdef FAITH static int firsttime = 1; if (firsttime) { /* translator hack */ { char *q = getenv("GAI"); if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1) translate = YES; } firsttime = 0; } #endif /* initialize file static vars */ sentinel.ai_next = NULL; cur = &sentinel; pai = &ai; pai->ai_flags = 0; pai->ai_family = PF_UNSPEC; pai->ai_socktype = ANY; pai->ai_protocol = ANY; pai->ai_addrlen = 0; pai->ai_canonname = NULL; pai->ai_addr = NULL; pai->ai_next = NULL; port = ANY; if (hostname == NULL && servname == NULL) return EAI_NONAME; if (hints) { /* error check for hints */ if (hints->ai_addrlen || hints->ai_canonname || hints->ai_addr || hints->ai_next) ERR(EAI_BADHINTS); /* xxx */ if (hints->ai_flags & ~AI_MASK) ERR(EAI_BADFLAGS); switch (hints->ai_family) { case PF_UNSPEC: case PF_INET: #ifdef INET6 case PF_INET6: #endif break; default: ERR(EAI_FAMILY); } memcpy(pai, hints, sizeof(*pai)); switch (pai->ai_socktype) { case ANY: switch (pai->ai_protocol) { case ANY: break; case IPPROTO_UDP: pai->ai_socktype = SOCK_DGRAM; break; case IPPROTO_TCP: pai->ai_socktype = SOCK_STREAM; break; default: #if defined(SOCK_RAW) pai->ai_socktype = SOCK_RAW; #endif break; } break; #if defined(SOCK_RAW) case SOCK_RAW: break; #endif case SOCK_DGRAM: if (pai->ai_protocol != IPPROTO_UDP && pai->ai_protocol != ANY) ERR(EAI_BADHINTS); /*xxx*/ pai->ai_protocol = IPPROTO_UDP; break; case SOCK_STREAM: if (pai->ai_protocol != IPPROTO_TCP && pai->ai_protocol != ANY) ERR(EAI_BADHINTS); /*xxx*/ pai->ai_protocol = IPPROTO_TCP; break; default: ERR(EAI_SOCKTYPE); break; } } /* * service port */ if (servname) { if (str_isnumber(servname)) { if (pai->ai_socktype == ANY) { /* caller accept *ANY* socktype */ pai->ai_socktype = SOCK_DGRAM; pai->ai_protocol = IPPROTO_UDP; } port = htons((unsigned short)atoi(servname)); } else { struct servent *sp; const char *proto; proto = NULL; switch (pai->ai_socktype) { case ANY: proto = NULL; break; case SOCK_DGRAM: proto = "udp"; break; case SOCK_STREAM: proto = "tcp"; break; default: fprintf(stderr, "panic!\n"); break; } if ((sp = getservbyname((char*)servname, proto)) == NULL) ERR(EAI_SERVICE); port = sp->s_port; if (pai->ai_socktype == ANY) if (strcmp(sp->s_proto, "udp") == 0) { pai->ai_socktype = SOCK_DGRAM; pai->ai_protocol = IPPROTO_UDP; } else if (strcmp(sp->s_proto, "tcp") == 0) { pai->ai_socktype = SOCK_STREAM; pai->ai_protocol = IPPROTO_TCP; } else ERR(EAI_PROTOCOL); /*xxx*/ } } /* * hostname == NULL. * passive socket -> anyaddr (0.0.0.0 or ::) * non-passive socket -> localhost (127.0.0.1 or ::1) */ if (hostname == NULL) { const struct afd *afd; int s; for (afd = &afdl[0]; afd->a_af; afd++) { if (!(pai->ai_family == PF_UNSPEC || pai->ai_family == afd->a_af)) { continue; } /* * filter out AFs that are not supported by the kernel * XXX errno? */ s = socket(afd->a_af, SOCK_DGRAM, 0); if (s < 0) continue; #if defined(HAVE_CLOSESOCKET) closesocket(s); #else close(s); #endif if (pai->ai_flags & AI_PASSIVE) { GET_AI(cur->ai_next, afd, afd->a_addrany, port); /* xxx meaningless? * GET_CANONNAME(cur->ai_next, "anyaddr"); */ } else { GET_AI(cur->ai_next, afd, afd->a_loopback, port); /* xxx meaningless? * GET_CANONNAME(cur->ai_next, "localhost"); */ } cur = cur->ai_next; } top = sentinel.ai_next; if (top) goto good; else ERR(EAI_FAMILY); } /* hostname as numeric name */ for (i = 0; afdl[i].a_af; i++) { if (inet_pton(afdl[i].a_af, hostname, pton)) { u_long v4a; #ifdef INET6 u_char pfx; #endif switch (afdl[i].a_af) { case AF_INET: v4a = ((struct in_addr *)pton)->s_addr; if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) pai->ai_flags &= ~AI_CANONNAME; v4a >>= IN_CLASSA_NSHIFT; if (v4a == 0 || v4a == IN_LOOPBACKNET) pai->ai_flags &= ~AI_CANONNAME; break; #ifdef INET6 case AF_INET6: #ifdef HAVE_ADDR8 pfx = ((struct in6_addr *)pton)->s6_addr8[0]; #else pfx = ((struct in6_addr *)pton)->s6_addr[0]; #endif if (pfx == 0 || pfx == 0xfe || pfx == 0xff) pai->ai_flags &= ~AI_CANONNAME; break; #endif } if (pai->ai_family == afdl[i].a_af || pai->ai_family == PF_UNSPEC) { if (! (pai->ai_flags & AI_CANONNAME)) { GET_AI(top, &afdl[i], pton, port); goto good; } /* * if AI_CANONNAME and if reverse lookup * fail, return ai anyway to pacify * calling application. * * XXX getaddrinfo() is a name->address * translation function, and it looks strange * that we do addr->name translation here. */ get_name(pton, &afdl[i], &top, pton, pai, port); goto good; } else ERR(EAI_FAMILY); /*xxx*/ } } if (pai->ai_flags & AI_NUMERICHOST) ERR(EAI_NONAME); /* hostname as alphabetical name */ error = get_addr(hostname, pai->ai_family, &top, pai, port); if (error == 0) { if (top) { good: *res = top; return SUCCESS; } else error = EAI_FAIL; } free: if (top) freeaddrinfo(top); bad: *res = NULL; return error; } static int get_name(addr, afd, res, numaddr, pai, port0) const char *addr; const struct afd *afd; struct addrinfo **res; char *numaddr; struct addrinfo *pai; int port0; { u_short port = port0 & 0xffff; struct hostent *hp; struct addrinfo *cur; int error = 0; #ifdef INET6 int h_error; #endif #ifdef INET6 hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error); #else hp = gethostbyaddr((char*)addr, afd->a_addrlen, AF_INET); #endif if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) { GET_AI(cur, afd, hp->h_addr_list[0], port); GET_CANONNAME(cur, hp->h_name); } else GET_AI(cur, afd, numaddr, port); #ifdef INET6 if (hp) freehostent(hp); #endif *res = cur; return SUCCESS; free: if (cur) freeaddrinfo(cur); #ifdef INET6 if (hp) freehostent(hp); #endif /* bad: */ *res = NULL; return error; } static int get_addr(hostname, af, res, pai, port0) const char *hostname; int af; struct addrinfo **res; struct addrinfo *pai; int port0; { u_short port = port0 & 0xffff; struct addrinfo sentinel; struct hostent *hp; struct addrinfo *top, *cur; const struct afd *afd; int i, error = 0, h_error; char *ap; top = NULL; sentinel.ai_next = NULL; cur = &sentinel; #ifdef INET6 if (af == AF_UNSPEC) { hp = getipnodebyname(hostname, AF_INET6, AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error); } else hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error); #else hp = gethostbyname((char*)hostname); h_error = h_errno; #endif if (hp == NULL) { switch (h_error) { case HOST_NOT_FOUND: case NO_DATA: error = EAI_NODATA; break; case TRY_AGAIN: error = EAI_AGAIN; break; case NO_RECOVERY: default: error = EAI_FAIL; break; } goto bad; } if ((hp->h_name == NULL) || (hp->h_name[0] == 0) || (hp->h_addr_list[0] == NULL)) ERR(EAI_FAIL); for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) { switch (af) { #ifdef INET6 case AF_INET6: afd = &afdl[N_INET6]; break; #endif #ifndef INET6 default: /* AF_UNSPEC */ #endif case AF_INET: afd = &afdl[N_INET]; break; #ifdef INET6 default: /* AF_UNSPEC */ if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { ap += sizeof(struct in6_addr) - sizeof(struct in_addr); afd = &afdl[N_INET]; } else afd = &afdl[N_INET6]; break; #endif } #ifdef FAITH if (translate && afd->a_af == AF_INET) { struct in6_addr *in6; GET_AI(cur->ai_next, &afdl[N_INET6], ap, port); in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr; memcpy(&in6->s6_addr32[0], &faith_prefix, sizeof(struct in6_addr) - sizeof(struct in_addr)); memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr)); } else #endif /* FAITH */ GET_AI(cur->ai_next, afd, ap, port); if (cur == &sentinel) { top = cur->ai_next; GET_CANONNAME(top, hp->h_name); } cur = cur->ai_next; } #ifdef INET6 freehostent(hp); #endif *res = top; return SUCCESS; free: if (top) freeaddrinfo(top); #ifdef INET6 if (hp) freehostent(hp); #endif bad: *res = NULL; return error; } ================================================ FILE: ext/socket/getnameinfo.c ================================================ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Issues to be discussed: * - Thread safe-ness must be checked * - Return values. There seems to be no standard for return value (RFC2133) * but INRIA implementation returns EAI_xxx defined for getaddrinfo(). */ #include "config.h" #include #include #ifndef _WIN32 #if defined(__BEOS__) # include #else # include #endif #include #if defined(HAVE_ARPA_INET_H) #include #endif #if defined(HAVE_ARPA_NAMESER_H) #include #endif #include #if defined(HAVE_RESOLV_H) #include #endif #endif #ifdef _WIN32 #include #define snprintf _snprintf #endif #include #include #ifdef SOCKS5 #include #endif #include "addrinfo.h" #include "sockport.h" #define SUCCESS 0 #define ANY 0 #define YES 1 #define NO 0 struct sockinet { u_char si_len; u_char si_family; u_short si_port; }; static struct afd { int a_af; int a_addrlen; int a_socklen; int a_off; } afdl [] = { #ifdef INET6 #define N_INET6 0 {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), offsetof(struct sockaddr_in6, sin6_addr)}, #define N_INET 1 #else #define N_INET 0 #endif {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), offsetof(struct sockaddr_in, sin_addr)}, {0, 0, 0, 0}, }; #define ENI_NOSOCKET 0 #define ENI_NOSERVNAME 1 #define ENI_NOHOSTNAME 2 #define ENI_MEMORY 3 #define ENI_SYSTEM 4 #define ENI_FAMILY 5 #define ENI_SALEN 6 #ifndef HAVE_INET_NTOP static const char * inet_ntop(af, addr, numaddr, numaddr_len) int af; const void *addr; char *numaddr; size_t numaddr_len; { #ifdef HAVE_INET_NTOA struct in_addr in; memcpy(&in.s_addr, addr, sizeof(in.s_addr)); snprintf(numaddr, numaddr_len, "%s", 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 int getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) const struct sockaddr *sa; size_t salen; char *host; size_t hostlen; char *serv; size_t servlen; int flags; { struct afd *afd; struct servent *sp; struct hostent *hp; u_short port; int family, len, i; char *addr, *p; u_long v4a; #ifdef INET6 u_char pfx; #endif int h_error; char numserv[512]; char numaddr[512]; if (sa == NULL) return ENI_NOSOCKET; len = SA_LEN(sa); if (len != salen) return ENI_SALEN; family = sa->sa_family; for (i = 0; afdl[i].a_af; i++) if (afdl[i].a_af == family) { afd = &afdl[i]; goto found; } return ENI_FAMILY; found: if (len != afd->a_socklen) return ENI_SALEN; port = ((struct sockinet *)sa)->si_port; /* network byte order */ addr = (char *)sa + afd->a_off; if (serv == NULL || servlen == 0) { /* what we should do? */ } else if (flags & NI_NUMERICSERV) { snprintf(numserv, sizeof(numserv), "%d", ntohs(port)); if (strlen(numserv) + 1 > servlen) return ENI_MEMORY; strcpy(serv, numserv); } else { #if defined(HAVE_GETSERVBYPORT) sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp"); if (sp) { if (strlen(sp->s_name) + 1 > servlen) return ENI_MEMORY; strcpy(serv, sp->s_name); } else return ENI_NOSERVNAME; #else return ENI_NOSERVNAME; #endif } switch (sa->sa_family) { case AF_INET: v4a = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr); if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) flags |= NI_NUMERICHOST; v4a >>= IN_CLASSA_NSHIFT; if (v4a == 0) flags |= NI_NUMERICHOST; break; #ifdef INET6 case AF_INET6: #ifdef HAVE_ADDR8 pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr8[0]; #else pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[0]; #endif if (pfx == 0 || pfx == 0xfe || pfx == 0xff) flags |= NI_NUMERICHOST; break; #endif } if (host == NULL || hostlen == 0) { /* what should we do? */ } else if (flags & NI_NUMERICHOST) { if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) == NULL) return ENI_SYSTEM; if (strlen(numaddr) > hostlen) return ENI_MEMORY; strcpy(host, numaddr); } else { #ifdef INET6 hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error); #else hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af); h_error = h_errno; #endif if (hp) { if (flags & NI_NOFQDN) { p = strchr(hp->h_name, '.'); if (p) *p = '\0'; } if (strlen(hp->h_name) + 1 > hostlen) { #ifdef INET6 freehostent(hp); #endif return ENI_MEMORY; } strcpy(host, hp->h_name); #ifdef INET6 freehostent(hp); #endif } else { if (flags & NI_NAMEREQD) return ENI_NOHOSTNAME; if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) == NULL) return ENI_NOHOSTNAME; if (strlen(numaddr) > hostlen) return ENI_MEMORY; strcpy(host, numaddr); } } return SUCCESS; } ================================================ FILE: ext/socket/socket.c ================================================ /************************************************ socket.c - $Author$ $Date$ created at: Thu Mar 31 12:21:29 JST 1994 Copyright (C) 1993-2001 Yukihiro Matsumoto ************************************************/ #include "ruby.h" #include "rubyio.h" #include "rubysig.h" #include "util.h" #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_UIO_H #include #endif #ifndef _WIN32 #if defined(__BEOS__) # include #else # include # define pseudo_AF_FTIP pseudo_AF_RTIP /* workaround for NetBSD and etc. */ #endif #include #ifdef HAVE_NETINET_IN_SYSTM_H # include #endif #ifdef HAVE_NETINET_TCP_H # include #endif #ifdef HAVE_NETINET_UDP_H # include #endif #ifdef HAVE_ARPA_INET_H # include #endif #include #endif #include #ifdef HAVE_SYS_UN_H #include #endif #if defined(HAVE_FCNTL) #ifdef HAVE_SYS_SELECT_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_FCNTL_H #include #endif #endif #ifndef EWOULDBLOCK #define EWOULDBLOCK EAGAIN #endif #ifndef HAVE_GETADDRINFO # include "addrinfo.h" #endif #include "sockport.h" #if defined(__vms) #include #endif static int do_not_reverse_lookup = 0; VALUE rb_cBasicSocket; VALUE rb_cIPSocket; VALUE rb_cTCPSocket; VALUE rb_cTCPServer; VALUE rb_cUDPSocket; #ifdef AF_UNIX VALUE rb_cUNIXSocket; VALUE rb_cUNIXServer; #endif VALUE rb_cSocket; static VALUE rb_eSocket; #ifdef SOCKS VALUE rb_cSOCKSSocket; #ifdef SOCKS5 #include #else void SOCKSinit(); int Rconnect(); #endif #endif #define INET_CLIENT 0 #define INET_SERVER 1 #define INET_SOCKS 2 #ifndef HAVE_SOCKADDR_STORAGE /* * RFC 2553: protocol-independent placeholder for socket addresses */ #define _SS_MAXSIZE 128 #define _SS_ALIGNSIZE (sizeof(double)) #define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(unsigned char) * 2) #define _SS_PAD2SIZE (_SS_MAXSIZE - sizeof(unsigned char) * 2 - \ _SS_PAD1SIZE - _SS_ALIGNSIZE) struct sockaddr_storage { #ifdef HAVE_SA_LEN unsigned char ss_len; /* address length */ unsigned char ss_family; /* address family */ #else unsigned short ss_family; #endif char __ss_pad1[_SS_PAD1SIZE]; double __ss_align; /* force desired structure storage alignment */ char __ss_pad2[_SS_PAD2SIZE]; }; #endif #if defined(INET6) && (defined(LOOKUP_ORDER_HACK_INET) || defined(LOOKUP_ORDER_HACK_INET6)) #define LOOKUP_ORDERS 3 static int lookup_order_table[LOOKUP_ORDERS] = { #if defined(LOOKUP_ORDER_HACK_INET) PF_INET, PF_INET6, PF_UNSPEC, #elif defined(LOOKUP_ORDER_HACK_INET6) PF_INET6, PF_INET, PF_UNSPEC, #else /* should not happen */ #endif }; static int ruby_getaddrinfo(nodename, servname, hints, res) char *nodename; char *servname; struct addrinfo *hints; struct addrinfo **res; { struct addrinfo tmp_hints; int i, af, error; if (hints->ai_family != PF_UNSPEC) { return getaddrinfo(nodename, servname, hints, res); } for (i = 0; i < LOOKUP_ORDERS; i++) { af = lookup_order_table[i]; MEMCPY(&tmp_hints, hints, struct addrinfo, 1); tmp_hints.ai_family = af; error = getaddrinfo(nodename, servname, &tmp_hints, res); if (error) { if (tmp_hints.ai_family == PF_UNSPEC) { break; } } else { break; } } return error; } #define getaddrinfo(node,serv,hints,res) ruby_getaddrinfo((node),(serv),(hints),(res)) #endif #if defined(_AIX) static int ruby_getaddrinfo__aix(nodename, servname, hints, res) char *nodename; char *servname; struct addrinfo *hints; struct addrinfo **res; { int error = getaddrinfo(nodename, servname, hints, res); struct addrinfo *r; if (error) return error; for (r = *res; r != NULL; r = r->ai_next) { if (r->ai_addr->sa_family == 0) r->ai_addr->sa_family = r->ai_family; if (r->ai_addr->sa_len == 0) r->ai_addr->sa_len = r->ai_addrlen; } return 0; } #undef getaddrinfo #define getaddrinfo(node,serv,hints,res) ruby_getaddrinfo__aix((node),(serv),(hints),(res)) static int ruby_getnameinfo__aix(sa, salen, host, hostlen, serv, servlen, flags) const struct sockaddr *sa; size_t salen; char *host; size_t hostlen; char *serv; size_t servlen; int flags; { struct sockaddr_in6 *sa6; u_int32_t *a6; if (sa->sa_family == AF_INET6) { sa6 = (struct sockaddr_in6 *)sa; a6 = sa6->sin6_addr.u6_addr.u6_addr32; if (a6[0] == 0 && a6[1] == 0 && a6[2] == 0 && a6[3] == 0) { strncpy(host, "::", hostlen); snprintf(serv, servlen, "%d", sa6->sin6_port); return 0; } } return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); } #undef getnameinfo #define getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) \ ruby_getnameinfo__aix((sa), (salen), (host), (hostlen), (serv), (servlen), (flags)) #ifndef CMSG_SPACE # define CMSG_SPACE(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + _CMSG_ALIGN(len)) #endif #ifndef CMSG_LEN # define CMSG_LEN(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + (len)) #endif #endif #ifdef HAVE_CLOSESOCKET #undef close #define close closesocket #endif static VALUE init_sock(sock, fd) VALUE sock; int fd; { rb_io_t *fp; MakeOpenFile(sock, fp); fp->f = rb_fdopen(fd, "r"); fp->f2 = rb_fdopen(fd, "w"); fp->mode = FMODE_READWRITE; rb_io_synchronized(fp); return sock; } static VALUE bsock_s_for_fd(klass, fd) VALUE klass, fd; { rb_io_t *fptr; VALUE sock = init_sock(rb_obj_alloc(klass), NUM2INT(fd)); GetOpenFile(sock, fptr); return sock; } static VALUE bsock_shutdown(argc, argv, sock) int argc; VALUE *argv; VALUE sock; { VALUE howto; int how; rb_io_t *fptr; if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) { rb_raise(rb_eSecurityError, "Insecure: can't shutdown socket"); } rb_scan_args(argc, argv, "01", &howto); if (howto == Qnil) how = 2; else { how = NUM2INT(howto); if (how < 0 || 2 < how) { rb_raise(rb_eArgError, "`how' should be either 0, 1, 2"); } } GetOpenFile(sock, fptr); if (shutdown(fileno(fptr->f), how) == -1) rb_sys_fail(0); return INT2FIX(0); } static VALUE bsock_close_read(sock) VALUE sock; { rb_io_t *fptr; if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) { rb_raise(rb_eSecurityError, "Insecure: can't close socket"); } GetOpenFile(sock, fptr); shutdown(fileno(fptr->f), 0); if (!(fptr->mode & FMODE_WRITABLE)) { return rb_io_close(sock); } fptr->mode &= ~FMODE_READABLE; return Qnil; } static VALUE bsock_close_write(sock) VALUE sock; { rb_io_t *fptr; if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) { rb_raise(rb_eSecurityError, "Insecure: can't close socket"); } GetOpenFile(sock, fptr); if (!(fptr->mode & FMODE_READABLE)) { return rb_io_close(sock); } shutdown(fileno(fptr->f2), 1); fptr->mode &= ~FMODE_WRITABLE; return Qnil; } /* * Document-method: setsockopt * call-seq: setsockopt(level, optname, optval) * * Sets a socket option. These are protocol and system specific, see your * local sytem documentation for details. * * === Parameters * * +level+ is an integer, usually one of the SOL_ constants such as * Socket::SOL_SOCKET, or a protocol level. * * +optname+ is an integer, usually one of the SO_ constants, such * as Socket::SO_REUSEADDR. * * +optval+ is the value of the option, it is passed to the underlying * setsockopt() as a pointer to a certain number of bytes. How this is * done depends on the type: * - Fixnum: value is assigned to an int, and a pointer to the int is * passed, with length of sizeof(int). * - true or false: 1 or 0 (respectively) is assigned to an int, and the * int is passed as for a Fixnum. Note that +false+ must be passed, * not +nil+. * - String: the string's data and length is passed to the socket. * * === Examples * * Some socket options are integers with boolean values, in this case * #setsockopt could be called like this: * sock.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true) * * Some socket options are integers with numeric values, in this case * #setsockopt could be called like this: * sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_TTL, 255) * * Option values may be structs. Passing them can be complex as it involves * examining your system headers to determine the correct definition. An * example is an +ip_mreq+, which may be defined in your system headers as: * struct ip_mreq { * struct in_addr imr_multiaddr; * struct in_addr imr_interface; * }; * * In this case #setsockopt could be called like this: * optval = IPAddr.new("224.0.0.251") + Socket::INADDR_ANY * sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, optval) * */ static VALUE bsock_setsockopt(sock, lev, optname, val) VALUE sock, lev, optname, val; { int level, option; rb_io_t *fptr; int i; char *v; int vlen; rb_secure(2); level = NUM2INT(lev); option = NUM2INT(optname); switch (TYPE(val)) { case T_FIXNUM: i = FIX2INT(val); goto numval; case T_FALSE: i = 0; goto numval; case T_TRUE: i = 1; numval: v = (char*)&i; vlen = sizeof(i); break; default: StringValue(val); v = RSTRING(val)->ptr; vlen = RSTRING(val)->len; break; } GetOpenFile(sock, fptr); if (setsockopt(fileno(fptr->f), level, option, v, vlen) < 0) rb_sys_fail(fptr->path); return INT2FIX(0); } /* * Document-method: getsockopt * call-seq: getsockopt(level, optname) * * Gets a socket option. These are protocol and system specific, see your * local sytem documentation for details. The option is returned as * a String with the data being the binary value of the socket option. * * === Parameters * * +level+ is an integer, usually one of the SOL_ constants such as * Socket::SOL_SOCKET, or a protocol level. * * +optname+ is an integer, usually one of the SO_ constants, such * as Socket::SO_REUSEADDR. * * === Examples * * Some socket options are integers with boolean values, in this case * #getsockopt could be called like this: * optval = sock.getsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR) * optval = optval.unpack "i" * reuseaddr = optval[0] == 0 ? false : true * * Some socket options are integers with numeric values, in this case * #getsockopt could be called like this: * optval = sock.getsockopt(Socket::IPPROTO_IP, Socket::IP_TTL) * ipttl = optval.unpack("i")[0] * * Option values may be structs. Decoding them can be complex as it involves * examining your system headers to determine the correct definition. An * example is a +struct linger+, which may be defined in your system headers * as: * struct linger { * int l_onoff; * int l_linger; * }; * * In this case #getsockopt could be called like this: * optval = sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER) * onoff, linger = optval.unpack "ii" */ static VALUE bsock_getsockopt(sock, lev, optname) VALUE sock, lev, optname; { #if !defined(__BEOS__) int level, option; socklen_t len; char *buf; rb_io_t *fptr; level = NUM2INT(lev); option = NUM2INT(optname); len = 256; buf = ALLOCA_N(char,len); GetOpenFile(sock, fptr); GetOpenFile(sock, fptr); if (getsockopt(fileno(fptr->f), level, option, buf, &len) < 0) rb_sys_fail(fptr->path); return rb_str_new(buf, len); #else rb_notimplement(); #endif } static VALUE bsock_getsockname(sock) VALUE sock; { char buf[1024]; socklen_t len = sizeof buf; rb_io_t *fptr; GetOpenFile(sock, fptr); if (getsockname(fileno(fptr->f), (struct sockaddr*)buf, &len) < 0) rb_sys_fail("getsockname(2)"); return rb_str_new(buf, len); } static VALUE bsock_getpeername(sock) VALUE sock; { char buf[1024]; socklen_t len = sizeof buf; rb_io_t *fptr; GetOpenFile(sock, fptr); if (getpeername(fileno(fptr->f), (struct sockaddr*)buf, &len) < 0) rb_sys_fail("getpeername(2)"); return rb_str_new(buf, len); } static VALUE bsock_send(argc, argv, sock) int argc; VALUE *argv; VALUE sock; { VALUE mesg, to; VALUE flags; rb_io_t *fptr; FILE *f; int fd, n; rb_secure(4); rb_scan_args(argc, argv, "21", &mesg, &flags, &to); StringValue(mesg); if (!NIL_P(to)) StringValue(to); GetOpenFile(sock, fptr); f = GetWriteFile(fptr); fd = fileno(f); rb_thread_fd_writable(fd); retry: if (!NIL_P(to)) { TRAP_BEG; n = sendto(fd, RSTRING(mesg)->ptr, RSTRING(mesg)->len, NUM2INT(flags), (struct sockaddr*)RSTRING(to)->ptr, RSTRING(to)->len); TRAP_END; } else { TRAP_BEG; n = send(fd, RSTRING(mesg)->ptr, RSTRING(mesg)->len, NUM2INT(flags)); TRAP_END; } if (n < 0) { if (rb_io_wait_writable(fd)) { goto retry; } rb_sys_fail("send(2)"); } return INT2FIX(n); } static VALUE ipaddr _((struct sockaddr*)); #ifdef HAVE_SYS_UN_H static VALUE unixaddr _((struct sockaddr_un*, socklen_t)); #endif enum sock_recv_type { RECV_RECV, /* BasicSocket#recv(no from) */ RECV_IP, /* IPSocket#recvfrom */ RECV_UNIX, /* UNIXSocket#recvfrom */ RECV_SOCKET /* Socket#recvfrom */ }; static VALUE s_recvfrom(sock, argc, argv, from) VALUE sock; int argc; VALUE *argv; enum sock_recv_type from; { rb_io_t *fptr; VALUE str; char buf[1024]; socklen_t alen = sizeof buf; VALUE len, flg; long buflen; long slen; int fd, flags; rb_scan_args(argc, argv, "11", &len, &flg); if (flg == Qnil) flags = 0; else flags = NUM2INT(flg); buflen = NUM2INT(len); GetOpenFile(sock, fptr); if (rb_read_pending(fptr->f)) { rb_raise(rb_eIOError, "recv for buffered IO"); } fd = fileno(fptr->f); str = rb_tainted_str_new(0, buflen); retry: rb_str_locktmp(str); rb_thread_wait_fd(fd); TRAP_BEG; slen = recvfrom(fd, RSTRING(str)->ptr, buflen, flags, (struct sockaddr*)buf, &alen); TRAP_END; rb_str_unlocktmp(str); if (slen < 0) { if (rb_io_wait_readable(fd)) { goto retry; } rb_sys_fail("recvfrom(2)"); } if (slen < RSTRING(str)->len) { RSTRING(str)->len = slen; RSTRING(str)->ptr[slen] = '\0'; } rb_obj_taint(str); switch (from) { case RECV_RECV: return (VALUE)str; case RECV_IP: #if 0 if (alen != sizeof(struct sockaddr_in)) { rb_raise(rb_eTypeError, "sockaddr size differs - should not happen"); } #endif if (alen && alen != sizeof(buf)) /* OSX doesn't return a 'from' result from recvfrom for connection-oriented sockets */ return rb_assoc_new(str, ipaddr((struct sockaddr*)buf)); else return rb_assoc_new(str, Qnil); #ifdef HAVE_SYS_UN_H case RECV_UNIX: return rb_assoc_new(str, unixaddr((struct sockaddr_un*)buf, alen)); #endif case RECV_SOCKET: return rb_assoc_new(str, rb_str_new(buf, alen)); default: rb_bug("s_recvfrom called with bad value"); } } static VALUE s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from) { rb_io_t *fptr; VALUE str; char buf[1024]; socklen_t alen = sizeof buf; VALUE len, flg; long buflen; long slen; int fd, flags; VALUE addr = Qnil; rb_scan_args(argc, argv, "11", &len, &flg); if (flg == Qnil) flags = 0; else flags = NUM2INT(flg); buflen = NUM2INT(len); #ifdef MSG_DONTWAIT /* MSG_DONTWAIT avoids the race condition between fcntl and recvfrom. It is not portable, though. */ flags |= MSG_DONTWAIT; #endif GetOpenFile(sock, fptr); if (rb_read_pending(fptr->f)) { rb_raise(rb_eIOError, "recvfrom for buffered IO"); } fd = fileno(fptr->f); str = rb_tainted_str_new(0, buflen); rb_io_check_closed(fptr); rb_io_set_nonblock(fptr); slen = recvfrom(fd, RSTRING(str)->ptr, buflen, flags, (struct sockaddr*)buf, &alen); if (slen < 0) { rb_sys_fail("recvfrom(2)"); } if (slen < RSTRING(str)->len) { RSTRING(str)->len = slen; RSTRING(str)->ptr[slen] = '\0'; } rb_obj_taint(str); switch (from) { case RECV_RECV: return str; case RECV_IP: if (alen && alen != sizeof(buf)) /* connection-oriented socket may not return a from result */ addr = ipaddr((struct sockaddr*)buf); break; case RECV_SOCKET: addr = rb_str_new(buf, alen); break; default: rb_bug("s_recvfrom_nonblock called with bad value"); } return rb_assoc_new(str, addr); } static VALUE bsock_recv(argc, argv, sock) int argc; VALUE *argv; VALUE sock; { return s_recvfrom(sock, argc, argv, RECV_RECV); } /* * call-seq: * basicsocket.recv_nonblock(maxlen) => mesg * basicsocket.recv_nonblock(maxlen, flags) => mesg * * Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after * O_NONBLOCK is set for the underlying file descriptor. * _flags_ is zero or more of the +MSG_+ options. * The result, _mesg_, is the data received. * * When recvfrom(2) returns 0, Socket#recv_nonblock returns * an empty string as data. * The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc. * * === Parameters * * +maxlen+ - the number of bytes to receive from the socket * * +flags+ - zero or more of the +MSG_+ options * * === Example * serv = TCPServer.new("127.0.0.1", 0) * af, port, host, addr = serv.addr * c = TCPSocket.new(addr, port) * s = serv.accept * c.send "aaa", 0 * IO.select([s]) * p s.recv_nonblock(10) #=> "aaa" * * Refer to Socket#recvfrom for the exceptions that may be thrown if the call * to _recv_nonblock_ fails. * * BasicSocket#recv_nonblock may raise any error corresponding to recvfrom(2) failure, * including Errno::EAGAIN. * * === See * * Socket#recvfrom */ static VALUE bsock_recv_nonblock(argc, argv, sock) int argc; VALUE *argv; VALUE sock; { return s_recvfrom_nonblock(sock, argc, argv, RECV_RECV); } static VALUE bsock_do_not_rev_lookup() { return do_not_reverse_lookup?Qtrue:Qfalse; } static VALUE bsock_do_not_rev_lookup_set(self, val) VALUE self, val; { rb_secure(4); do_not_reverse_lookup = RTEST(val); return val; } static void make_ipaddr0(addr, buf, len) struct sockaddr *addr; char *buf; size_t len; { int error; error = getnameinfo(addr, SA_LEN(addr), buf, len, NULL, 0, NI_NUMERICHOST); if (error) { rb_raise(rb_eSocket, "getnameinfo: %s", gai_strerror(error)); } } static VALUE make_ipaddr(addr) struct sockaddr *addr; { char buf[1024]; make_ipaddr0(addr, buf, sizeof(buf)); return rb_str_new2(buf); } static void make_inetaddr(host, buf, len) long host; char *buf; size_t len; { struct sockaddr_in sin; MEMZERO(&sin, struct sockaddr_in, 1); sin.sin_family = AF_INET; SET_SIN_LEN(&sin, sizeof(sin)); sin.sin_addr.s_addr = host; make_ipaddr0((struct sockaddr*)&sin, buf, len); } static int str_isnumber(p) const char *p; { char *ep; if (!p || *p == '\0') return 0; ep = NULL; (void)strtoul(p, &ep, 10); if (ep && *ep == '\0') return 1; else return 0; } static char * host_str(host, hbuf, len) VALUE host; char *hbuf; size_t len; { if (NIL_P(host)) { return NULL; } else if (rb_obj_is_kind_of(host, rb_cInteger)) { unsigned long i = NUM2ULONG(host); make_inetaddr(htonl(i), hbuf, len); return hbuf; } else { char *name; SafeStringValue(host); name = RSTRING(host)->ptr; if (!name || *name == 0 || (name[0] == '<' && strcmp(name, "") == 0)) { make_inetaddr(INADDR_ANY, hbuf, len); } else if (name[0] == '<' && strcmp(name, "") == 0) { make_inetaddr(INADDR_BROADCAST, hbuf, len); } else if (strlen(name) >= len) { rb_raise(rb_eArgError, "hostname too long (%d)", strlen(name)); } else { strcpy(hbuf, name); } return hbuf; } } static char * port_str(port, pbuf, len) VALUE port; char *pbuf; size_t len; { if (NIL_P(port)) { return 0; } else if (FIXNUM_P(port)) { snprintf(pbuf, len, "%ld", FIX2LONG(port)); return pbuf; } else { char *serv; SafeStringValue(port); serv = RSTRING(port)->ptr; if (strlen(serv) >= len) { rb_raise(rb_eArgError, "service name too long (%d)", strlen(serv)); } strcpy(pbuf, serv); return pbuf; } } #ifndef NI_MAXHOST # define NI_MAXHOST 1025 #endif #ifndef NI_MAXSERV # define NI_MAXSERV 32 #endif static struct addrinfo* sock_addrinfo(host, port, socktype, flags) VALUE host, port; int socktype, flags; { struct addrinfo hints; struct addrinfo* res = NULL; char *hostp, *portp; int error; char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; hostp = host_str(host, hbuf, sizeof(hbuf)); portp = port_str(port, pbuf, sizeof(pbuf)); if (socktype == 0 && flags == 0 && str_isnumber(portp)) { socktype = SOCK_DGRAM; } MEMZERO(&hints, struct addrinfo, 1); hints.ai_family = AF_UNSPEC; hints.ai_socktype = socktype; hints.ai_flags = flags; error = getaddrinfo(hostp, portp, &hints, &res); if (error) { if (hostp && hostp[strlen(hostp)-1] == '\n') { rb_raise(rb_eSocket, "newline at the end of hostname"); } rb_raise(rb_eSocket, "getaddrinfo: %s", gai_strerror(error)); } #if defined(__APPLE__) && defined(__MACH__) { struct addrinfo *r; r = res; while (r) { if (! r->ai_socktype) r->ai_socktype = hints.ai_socktype; if (! r->ai_protocol) { if (r->ai_socktype == SOCK_DGRAM) { r->ai_protocol = IPPROTO_UDP; } else if (r->ai_socktype == SOCK_STREAM) { r->ai_protocol = IPPROTO_TCP; } } r = r->ai_next; } } #endif return res; } static VALUE ipaddr(sockaddr) struct sockaddr *sockaddr; { VALUE family, port, addr1, addr2; VALUE ary; int error; char hbuf[1024], pbuf[1024]; switch (sockaddr->sa_family) { case AF_UNSPEC: family = rb_str_new2("AF_UNSPEC"); break; case AF_INET: family = rb_str_new2("AF_INET"); break; #ifdef INET6 case AF_INET6: family = rb_str_new2("AF_INET6"); break; #endif #ifdef AF_LOCAL case AF_LOCAL: family = rb_str_new2("AF_LOCAL"); break; #elif AF_UNIX case AF_UNIX: family = rb_str_new2("AF_UNIX"); break; #endif default: sprintf(pbuf, "unknown:%d", sockaddr->sa_family); family = rb_str_new2(pbuf); break; } addr1 = Qnil; if (!do_not_reverse_lookup) { error = getnameinfo(sockaddr, SA_LEN(sockaddr), hbuf, sizeof(hbuf), NULL, 0, 0); if (! error) { addr1 = rb_str_new2(hbuf); } } error = getnameinfo(sockaddr, SA_LEN(sockaddr), hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV); if (error) { rb_raise(rb_eSocket, "getnameinfo: %s", gai_strerror(error)); } addr2 = rb_str_new2(hbuf); if (addr1 == Qnil) { addr1 = addr2; } port = INT2FIX(atoi(pbuf)); ary = rb_ary_new3(4, family, port, addr1, addr2); return ary; } static int ruby_socket(domain, type, proto) int domain, type, proto; { int fd; fd = socket(domain, type, proto); if (fd < 0) { if (errno == EMFILE || errno == ENFILE) { rb_gc(); fd = socket(domain, type, proto); } } return fd; } static int wait_connectable(fd) int fd; { int sockerr; socklen_t sockerrlen; fd_set fds_w; fd_set fds_e; for (;;) { FD_ZERO(&fds_w); FD_ZERO(&fds_e); FD_SET(fd, &fds_w); FD_SET(fd, &fds_e); rb_thread_select(fd+1, 0, &fds_w, &fds_e, 0); if (FD_ISSET(fd, &fds_w)) { return 0; } else if (FD_ISSET(fd, &fds_e)) { sockerrlen = sizeof(sockerr); if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen) == 0) { if (sockerr == 0) continue; /* workaround for winsock */ errno = sockerr; } return -1; } } return 0; } #ifdef __CYGWIN__ #define WAIT_IN_PROGRESS 10 #endif #ifdef __APPLE__ #define WAIT_IN_PROGRESS 10 #endif #ifdef __linux__ /* returns correct error */ #define WAIT_IN_PROGRESS 0 #endif #ifndef WAIT_IN_PROGRESS /* BSD origin code apparently has a problem */ #define WAIT_IN_PROGRESS 1 #endif static int ruby_connect(fd, sockaddr, len, socks) int fd; struct sockaddr *sockaddr; int len; int socks; { int status; int mode; #if WAIT_IN_PROGRESS > 0 int wait_in_progress = -1; int sockerr; socklen_t sockerrlen; #endif #if defined(HAVE_FCNTL) # if defined(F_GETFL) mode = fcntl(fd, F_GETFL, 0); # else mode = 0; # endif #ifdef O_NDELAY # define NONBLOCKING O_NDELAY #else #ifdef O_NBIO # define NONBLOCKING O_NBIO #else # define NONBLOCKING O_NONBLOCK #endif #endif #ifdef SOCKS5 if (!socks) #endif fcntl(fd, F_SETFL, mode|NONBLOCKING); #endif /* HAVE_FCNTL */ for (;;) { #if defined(SOCKS) && !defined(SOCKS5) if (socks) { status = Rconnect(fd, sockaddr, len); } else #endif { status = connect(fd, sockaddr, len); } if (status < 0) { switch (errno) { case EAGAIN: #ifdef EINPROGRESS case EINPROGRESS: #endif #if WAIT_IN_PROGRESS > 0 sockerrlen = sizeof(sockerr); status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen); if (status) break; if (sockerr) { status = -1; errno = sockerr; break; } #endif #ifdef EALREADY case EALREADY: #endif #if WAIT_IN_PROGRESS > 0 wait_in_progress = WAIT_IN_PROGRESS; #endif status = wait_connectable(fd); if (status) { break; } errno = 0; continue; #if WAIT_IN_PROGRESS > 0 case EINVAL: if (wait_in_progress-- > 0) { /* * connect() after EINPROGRESS returns EINVAL on * some platforms, need to check true error * status. */ sockerrlen = sizeof(sockerr); status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen); if (!status && !sockerr) { struct timeval tv = {0, 100000}; rb_thread_wait_for(tv); continue; } status = -1; errno = sockerr; } break; #endif #ifdef EISCONN case EISCONN: status = 0; errno = 0; break; #endif default: break; } } #ifdef HAVE_FCNTL fcntl(fd, F_SETFL, mode); #endif return status; } } struct inetsock_arg { VALUE sock; struct { VALUE host, serv; struct addrinfo *res; } remote, local; int type; int fd; }; static VALUE inetsock_cleanup(arg) struct inetsock_arg *arg; { if (arg->remote.res) { freeaddrinfo(arg->remote.res); arg->remote.res = 0; } if (arg->local.res) { freeaddrinfo(arg->local.res); arg->local.res = 0; } if (arg->fd >= 0) { close(arg->fd); } return Qnil; } static VALUE init_inetsock_internal(arg) struct inetsock_arg *arg; { int type = arg->type; struct addrinfo *res; int fd, status = 0; char *syscall; arg->remote.res = sock_addrinfo(arg->remote.host, arg->remote.serv, SOCK_STREAM, (type == INET_SERVER) ? AI_PASSIVE : 0); /* * Maybe also accept a local address */ if (type != INET_SERVER && (!NIL_P(arg->local.host) || !NIL_P(arg->local.serv))) { arg->local.res = sock_addrinfo(arg->local.host, arg->local.serv, SOCK_STREAM, 0); } arg->fd = fd = -1; for (res = arg->remote.res; res; res = res->ai_next) { status = ruby_socket(res->ai_family,res->ai_socktype,res->ai_protocol); syscall = "socket(2)"; fd = status; if (fd < 0) { continue; } arg->fd = fd; if (type == INET_SERVER) { #if !defined(_WIN32) && !defined(__CYGWIN__) status = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&status, sizeof(status)); #endif status = bind(fd, res->ai_addr, res->ai_addrlen); syscall = "bind(2)"; } else { if (arg->local.res) { status = bind(fd, arg->local.res->ai_addr, arg->local.res->ai_addrlen); syscall = "bind(2)"; } if (status >= 0) { status = ruby_connect(fd, res->ai_addr, res->ai_addrlen, (type == INET_SOCKS)); syscall = "connect(2)"; } } if (status < 0) { close(fd); arg->fd = fd = -1; continue; } else break; } if (status < 0) { rb_sys_fail(syscall); } arg->fd = -1; if (type == INET_SERVER) listen(fd, 5); /* create new instance */ return init_sock(arg->sock, fd); } static VALUE init_inetsock(sock, remote_host, remote_serv, local_host, local_serv, type) VALUE sock, remote_host, remote_serv, local_host, local_serv; int type; { struct inetsock_arg arg; arg.sock = sock; arg.remote.host = remote_host; arg.remote.serv = remote_serv; arg.remote.res = 0; arg.local.host = local_host; arg.local.serv = local_serv; arg.local.res = 0; arg.type = type; arg.fd = -1; return rb_ensure(init_inetsock_internal, (VALUE)&arg, inetsock_cleanup, (VALUE)&arg); } /* * call-seq: * TCPSocket.new(remote_host, remote_port, local_host=nil, local_port=nil) * * Opens a TCP connection to +remote_host+ on +remote_port+. If +local_host+ * and +local_port+ are specified, then those parameters are used on the local * end to establish the connection. */ static VALUE tcp_init(argc, argv, sock) int argc; VALUE *argv; VALUE sock; { VALUE remote_host, remote_serv; VALUE local_host, local_serv; rb_scan_args(argc, argv, "22", &remote_host, &remote_serv, &local_host, &local_serv); return init_inetsock(sock, remote_host, remote_serv, local_host, local_serv, INET_CLIENT); } #ifdef SOCKS static VALUE socks_init(sock, host, serv) VALUE sock, host, serv; { static init = 0; if (init == 0) { SOCKSinit("ruby"); init = 1; } return init_inetsock(sock, host, serv, Qnil, Qnil, INET_SOCKS); } #ifdef SOCKS5 static VALUE socks_s_close(sock) VALUE sock; { rb_io_t *fptr; if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) { rb_raise(rb_eSecurityError, "Insecure: can't close socket"); } GetOpenFile(sock, fptr); shutdown(fileno(fptr->f), 2); shutdown(fileno(fptr->f2), 2); return rb_io_close(sock); } #endif #endif struct hostent_arg { VALUE host; struct addrinfo* addr; VALUE (*ipaddr)_((struct sockaddr*, size_t)); }; static VALUE make_hostent_internal(arg) struct hostent_arg *arg; { VALUE host = arg->host; struct addrinfo* addr = arg->addr; VALUE (*ipaddr)_((struct sockaddr*, size_t)) = arg->ipaddr; struct addrinfo *ai; struct hostent *h; VALUE ary, names; char **pch; const char* hostp; char hbuf[NI_MAXHOST]; ary = rb_ary_new(); if (addr->ai_canonname) { hostp = addr->ai_canonname; } else { hostp = host_str(host, hbuf, sizeof(hbuf)); } rb_ary_push(ary, rb_str_new2(hostp)); if (addr->ai_canonname && (h = gethostbyname(addr->ai_canonname))) { names = rb_ary_new(); if (h->h_aliases != NULL) { for (pch = h->h_aliases; *pch; pch++) { rb_ary_push(names, rb_str_new2(*pch)); } } } else { names = rb_ary_new2(0); } rb_ary_push(ary, names); rb_ary_push(ary, INT2NUM(addr->ai_family)); for (ai = addr; ai; ai = ai->ai_next) { /* Pushing all addresses regardless of address family is not the * behaviour expected of gethostbyname(). All the addresses in struct * hostent->h_addr_list must be of the same family. */ if(ai->ai_family == addr->ai_family) { rb_ary_push(ary, (*ipaddr)(ai->ai_addr, ai->ai_addrlen)); } } return ary; } static VALUE make_hostent(host, addr, ipaddr) VALUE host; struct addrinfo* addr; VALUE (*ipaddr)_((struct sockaddr*, size_t)); { struct hostent_arg arg; arg.host = host; arg.addr = addr; arg.ipaddr = ipaddr; return rb_ensure(make_hostent_internal, (VALUE)&arg, RUBY_METHOD_FUNC(freeaddrinfo), (VALUE)addr); } VALUE tcp_sockaddr(addr, len) struct sockaddr *addr; size_t len; { return make_ipaddr(addr); } static VALUE tcp_s_gethostbyname(obj, host) VALUE obj, host; { rb_secure(3); return make_hostent(host, sock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME), tcp_sockaddr); } static VALUE tcp_svr_init(argc, argv, sock) int argc; VALUE *argv; VALUE sock; { VALUE arg1, arg2; if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2) return init_inetsock(sock, arg1, arg2, Qnil, Qnil, INET_SERVER); else return init_inetsock(sock, Qnil, arg1, Qnil, Qnil, INET_SERVER); } static void make_fd_nonblock(int fd) { int flags; #ifdef F_GETFL flags = fcntl(fd, F_GETFL); if (flags == -1) { rb_sys_fail(0); } #else flags = 0; #endif flags |= O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) == -1) { rb_sys_fail(0); } } static VALUE s_accept_nonblock(VALUE klass, rb_io_t *fptr, struct sockaddr *sockaddr, socklen_t *len) { int fd2; rb_secure(3); rb_io_set_nonblock(fptr); fd2 = accept(fileno(fptr->f), (struct sockaddr*)sockaddr, len); if (fd2 < 0) { rb_sys_fail("accept(2)"); } make_fd_nonblock(fd2); return init_sock(rb_obj_alloc(klass), fd2); } static VALUE s_accept(klass, fd, sockaddr, len) VALUE klass; int fd; struct sockaddr *sockaddr; socklen_t *len; { int fd2; int retry = 0; rb_secure(3); retry: rb_thread_wait_fd(fd); #if defined(_nec_ews) fd2 = accept(fd, sockaddr, len); #else TRAP_BEG; fd2 = accept(fd, sockaddr, len); TRAP_END; #endif if (fd2 < 0) { switch (errno) { case EMFILE: case ENFILE: if (retry) break; rb_gc(); retry = 1; goto retry; case EWOULDBLOCK: break; default: if (!rb_io_wait_readable(fd)) break; retry = 0; goto retry; } rb_sys_fail(0); } if (!klass) return INT2NUM(fd2); return init_sock(rb_obj_alloc(klass), fd2); } static VALUE tcp_accept(sock) VALUE sock; { rb_io_t *fptr; struct sockaddr_storage from; socklen_t fromlen; GetOpenFile(sock, fptr); fromlen = sizeof(from); return s_accept(rb_cTCPSocket, fileno(fptr->f), (struct sockaddr*)&from, &fromlen); } /* * call-seq: * tcpserver.accept_nonblock => tcpsocket * * Accepts an incoming connection using accept(2) after * O_NONBLOCK is set for the underlying file descriptor. * It returns an accepted TCPSocket for the incoming connection. * * === Example * require 'socket' * serv = TCPServer.new(2202) * begin * sock = serv.accept_nonblock * rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR * IO.select([serv]) * retry * end * # sock is an accepted socket. * * Refer to Socket#accept for the exceptions that may be thrown if the call * to TCPServer#accept_nonblock fails. * * TCPServer#accept_nonblock may raise any error corresponding to accept(2) failure, * including Errno::EAGAIN. * * === See * * TCPServer#accept * * Socket#accept */ static VALUE tcp_accept_nonblock(sock) VALUE sock; { rb_io_t *fptr; struct sockaddr_storage from; socklen_t fromlen; GetOpenFile(sock, fptr); fromlen = sizeof(from); return s_accept_nonblock(rb_cTCPSocket, fptr, (struct sockaddr *)&from, &fromlen); } static VALUE tcp_sysaccept(sock) VALUE sock; { rb_io_t *fptr; struct sockaddr_storage from; socklen_t fromlen; GetOpenFile(sock, fptr); fromlen = sizeof(from); return s_accept(0, fileno(fptr->f), (struct sockaddr*)&from, &fromlen); } #ifdef HAVE_SYS_UN_H struct unixsock_arg { struct sockaddr_un *sockaddr; int fd; }; static VALUE unixsock_connect_internal(arg) struct unixsock_arg *arg; { return (VALUE)ruby_connect(arg->fd, arg->sockaddr, sizeof(*arg->sockaddr), 0); } static VALUE init_unixsock(sock, path, server) VALUE sock; VALUE path; int server; { struct sockaddr_un sockaddr; int fd, status; rb_io_t *fptr; SafeStringValue(path); fd = ruby_socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { rb_sys_fail("socket(2)"); } MEMZERO(&sockaddr, struct sockaddr_un, 1); sockaddr.sun_family = AF_UNIX; if (sizeof(sockaddr.sun_path) <= RSTRING(path)->len) { rb_raise(rb_eArgError, "too long unix socket path (max: %dbytes)", (int)sizeof(sockaddr.sun_path)-1); } strcpy(sockaddr.sun_path, StringValueCStr(path)); if (server) { status = bind(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); } else { int prot; struct unixsock_arg arg; arg.sockaddr = &sockaddr; arg.fd = fd; status = rb_protect(unixsock_connect_internal, (VALUE)&arg, &prot); if (prot) { close(fd); rb_jump_tag(prot); } } if (status < 0) { close(fd); rb_sys_fail(sockaddr.sun_path); } if (server) listen(fd, 5); init_sock(sock, fd); GetOpenFile(sock, fptr); if (server) { fptr->path = strdup(RSTRING(path)->ptr); } return sock; } #endif static VALUE ip_addr(sock) VALUE sock; { rb_io_t *fptr; struct sockaddr_storage addr; socklen_t len = sizeof addr; GetOpenFile(sock, fptr); if (getsockname(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) rb_sys_fail("getsockname(2)"); return ipaddr((struct sockaddr*)&addr); } static VALUE ip_peeraddr(sock) VALUE sock; { rb_io_t *fptr; struct sockaddr_storage addr; socklen_t len = sizeof addr; GetOpenFile(sock, fptr); if (getpeername(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) rb_sys_fail("getpeername(2)"); return ipaddr((struct sockaddr*)&addr); } static VALUE ip_recvfrom(argc, argv, sock) int argc; VALUE *argv; VALUE sock; { return s_recvfrom(sock, argc, argv, RECV_IP); } static VALUE ip_s_getaddress(obj, host) VALUE obj, host; { struct sockaddr_storage addr; struct addrinfo *res = sock_addrinfo(host, Qnil, SOCK_STREAM, 0); /* just take the first one */ memcpy(&addr, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); return make_ipaddr((struct sockaddr*)&addr); } static VALUE udp_init(argc, argv, sock) int argc; VALUE *argv; VALUE sock; { VALUE arg; int socktype = AF_INET; int fd; rb_secure(3); if (rb_scan_args(argc, argv, "01", &arg) == 1) { socktype = NUM2INT(arg); } fd = ruby_socket(socktype, SOCK_DGRAM, 0); if (fd < 0) { rb_sys_fail("socket(2) - udp"); } return init_sock(sock, fd); } struct udp_arg { struct addrinfo *res; int fd; }; static VALUE udp_connect_internal(arg) struct udp_arg *arg; { int fd = arg->fd; struct addrinfo *res; for (res = arg->res; res; res = res->ai_next) { if (ruby_connect(fd, res->ai_addr, res->ai_addrlen, 0) >= 0) { return Qtrue; } } return Qfalse; } static VALUE udp_connect(sock, host, port) VALUE sock, host, port; { rb_io_t *fptr; struct udp_arg arg; VALUE ret; rb_secure(3); arg.res = sock_addrinfo(host, port, SOCK_DGRAM, 0); GetOpenFile(sock, fptr); arg.fd = fileno(fptr->f); ret = rb_ensure(udp_connect_internal, (VALUE)&arg, RUBY_METHOD_FUNC(freeaddrinfo), (VALUE)arg.res); if (!ret) rb_sys_fail("connect(2)"); return INT2FIX(0); } static VALUE udp_bind(sock, host, port) VALUE sock, host, port; { rb_io_t *fptr; struct addrinfo *res0, *res; rb_secure(3); res0 = sock_addrinfo(host, port, SOCK_DGRAM, 0); GetOpenFile(sock, fptr); for (res = res0; res; res = res->ai_next) { if (bind(fileno(fptr->f), res->ai_addr, res->ai_addrlen) < 0) { continue; } freeaddrinfo(res0); return INT2FIX(0); } freeaddrinfo(res0); rb_sys_fail("bind(2)"); return INT2FIX(0); } static VALUE udp_send(argc, argv, sock) int argc; VALUE *argv; VALUE sock; { VALUE mesg, flags, host, port; rb_io_t *fptr; FILE *f; int n; struct addrinfo *res0, *res; if (argc == 2 || argc == 3) { return bsock_send(argc, argv, sock); } rb_secure(4); rb_scan_args(argc, argv, "4", &mesg, &flags, &host, &port); StringValue(mesg); res0 = sock_addrinfo(host, port, SOCK_DGRAM, 0); GetOpenFile(sock, fptr); f = GetWriteFile(fptr); for (res = res0; res; res = res->ai_next) { retry: n = sendto(fileno(f), RSTRING(mesg)->ptr, RSTRING(mesg)->len, NUM2INT(flags), res->ai_addr, res->ai_addrlen); if (n >= 0) { freeaddrinfo(res0); return INT2FIX(n); } if (rb_io_wait_writable(fileno(f))) { goto retry; } } freeaddrinfo(res0); rb_sys_fail("sendto(2)"); return INT2FIX(n); } /* * call-seq: * udpsocket.recvfrom_nonblock(maxlen) => [mesg, sender_inet_addr] * udpsocket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_inet_addr] * * Receives up to _maxlen_ bytes from +udpsocket+ using recvfrom(2) after * O_NONBLOCK is set for the underlying file descriptor. * _flags_ is zero or more of the +MSG_+ options. * The first element of the results, _mesg_, is the data received. * The second element, _sender_inet_addr_, is an array to represent the sender address. * * When recvfrom(2) returns 0, * Socket#recvfrom_nonblock returns an empty string as data. * It means an empty packet. * * === Parameters * * +maxlen+ - the number of bytes to receive from the socket * * +flags+ - zero or more of the +MSG_+ options * * === Example * require 'socket' * s1 = UDPSocket.new * s1.bind("127.0.0.1", 0) * s2 = UDPSocket.new * s2.bind("127.0.0.1", 0) * s2.connect(*s1.addr.values_at(3,1)) * s1.connect(*s2.addr.values_at(3,1)) * s1.send "aaa", 0 * IO.select([s2]) * p s2.recvfrom_nonblock(10) #=> ["aaa", ["AF_INET", 33302, "localhost.localdomain", "127.0.0.1"]] * * Refer to Socket#recvfrom for the exceptions that may be thrown if the call * to _recvfrom_nonblock_ fails. * * UDPSocket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure, * including Errno::EAGAIN. * * === See * * Socket#recvfrom */ static VALUE udp_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock) { return s_recvfrom_nonblock(sock, argc, argv, RECV_IP); } #ifdef HAVE_SYS_UN_H static VALUE unix_init(sock, path) VALUE sock, path; { return init_unixsock(sock, path, 0); } static char * unixpath(struct sockaddr_un *sockaddr, socklen_t len) { if (sockaddr->sun_path < (char*)sockaddr + len) return sockaddr->sun_path; else return ""; } static VALUE unix_path(sock) VALUE sock; { rb_io_t *fptr; GetOpenFile(sock, fptr); if (fptr->path == 0) { struct sockaddr_un addr; socklen_t len = sizeof(addr); if (getsockname(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) rb_sys_fail(0); fptr->path = strdup(unixpath(&addr, len)); } return rb_str_new2(fptr->path); } static VALUE unix_svr_init(sock, path) VALUE sock, path; { return init_unixsock(sock, path, 1); } static VALUE unix_recvfrom(argc, argv, sock) int argc; VALUE *argv; VALUE sock; { return s_recvfrom(sock, argc, argv, RECV_UNIX); } #if defined(HAVE_ST_MSG_CONTROL) && defined(SCM_RIGHTS) #define FD_PASSING_BY_MSG_CONTROL 1 #else #define FD_PASSING_BY_MSG_CONTROL 0 #endif #if defined(HAVE_ST_MSG_ACCRIGHTS) #define FD_PASSING_BY_MSG_ACCRIGHTS 1 #else #define FD_PASSING_BY_MSG_ACCRIGHTS 0 #endif static VALUE unix_send_io(sock, val) VALUE sock, val; { #if defined(HAVE_SENDMSG) && (FD_PASSING_BY_MSG_CONTROL || FD_PASSING_BY_MSG_ACCRIGHTS) int fd; rb_io_t *fptr; struct msghdr msg; struct iovec vec[1]; char buf[1]; #if FD_PASSING_BY_MSG_CONTROL struct { struct cmsghdr hdr; char pad[8+sizeof(int)+8]; } cmsg; #endif if (rb_obj_is_kind_of(val, rb_cIO)) { rb_io_t *valfptr; GetOpenFile(val, valfptr); fd = fileno(valfptr->f); } else if (FIXNUM_P(val)) { fd = FIX2INT(val); } else { rb_raise(rb_eTypeError, "neither IO nor file descriptor"); } GetOpenFile(sock, fptr); msg.msg_name = NULL; msg.msg_namelen = 0; /* Linux and Solaris doesn't work if msg_iov is NULL. */ buf[0] = '\0'; vec[0].iov_base = buf; vec[0].iov_len = 1; msg.msg_iov = vec; msg.msg_iovlen = 1; #if FD_PASSING_BY_MSG_CONTROL msg.msg_control = (caddr_t)&cmsg; msg.msg_controllen = CMSG_LEN(sizeof(int)); msg.msg_flags = 0; MEMZERO((char*)&cmsg, char, sizeof(cmsg)); cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int)); cmsg.hdr.cmsg_level = SOL_SOCKET; cmsg.hdr.cmsg_type = SCM_RIGHTS; *(int *)CMSG_DATA(&cmsg.hdr) = fd; #else msg.msg_accrights = (caddr_t)&fd; msg.msg_accrightslen = sizeof(fd); #endif if (sendmsg(fileno(fptr->f), &msg, 0) == -1) rb_sys_fail("sendmsg(2)"); return Qnil; #else rb_notimplement(); return Qnil; /* not reached */ #endif } #if defined(HAVE_RECVMSG) && (FD_PASSING_BY_MSG_CONTROL || FD_PASSING_BY_MSG_ACCRIGHTS) static void thread_read_select(fd) int fd; { fd_set fds; FD_ZERO(&fds); FD_SET(fd, &fds); rb_thread_select(fd+1, &fds, 0, 0, 0); } #endif static VALUE unix_recv_io(argc, argv, sock) int argc; VALUE *argv; VALUE sock; { #if defined(HAVE_RECVMSG) && (FD_PASSING_BY_MSG_CONTROL || FD_PASSING_BY_MSG_ACCRIGHTS) VALUE klass, mode; rb_io_t *fptr; struct msghdr msg; struct iovec vec[2]; char buf[1]; int fd; #if FD_PASSING_BY_MSG_CONTROL struct { struct cmsghdr hdr; char pad[8+sizeof(int)+8]; } cmsg; #endif rb_scan_args(argc, argv, "02", &klass, &mode); if (argc == 0) klass = rb_cIO; if (argc <= 1) mode = Qnil; GetOpenFile(sock, fptr); thread_read_select(fileno(fptr->f)); msg.msg_name = NULL; msg.msg_namelen = 0; vec[0].iov_base = buf; vec[0].iov_len = sizeof(buf); msg.msg_iov = vec; msg.msg_iovlen = 1; #if FD_PASSING_BY_MSG_CONTROL msg.msg_control = (caddr_t)&cmsg; msg.msg_controllen = CMSG_SPACE(sizeof(int)); msg.msg_flags = 0; cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int)); cmsg.hdr.cmsg_level = SOL_SOCKET; cmsg.hdr.cmsg_type = SCM_RIGHTS; *(int *)CMSG_DATA(&cmsg.hdr) = -1; #else msg.msg_accrights = (caddr_t)&fd; msg.msg_accrightslen = sizeof(fd); fd = -1; #endif if (recvmsg(fileno(fptr->f), &msg, 0) == -1) rb_sys_fail("recvmsg(2)"); #if FD_PASSING_BY_MSG_CONTROL if (msg.msg_controllen != CMSG_SPACE(sizeof(int))) { rb_raise(rb_eSocket, "file descriptor was not passed (msg_controllen=%d, %d expected)", msg.msg_controllen, CMSG_SPACE(sizeof(int))); } if (cmsg.hdr.cmsg_len != CMSG_LEN(sizeof(int))) { rb_raise(rb_eSocket, "file descriptor was not passed (cmsg_len=%d, %d expected)", cmsg.hdr.cmsg_len, CMSG_LEN(sizeof(int))); } if (cmsg.hdr.cmsg_level != SOL_SOCKET) { rb_raise(rb_eSocket, "file descriptor was not passed (cmsg_level=%d, %d expected)", cmsg.hdr.cmsg_level, SOL_SOCKET); } if (cmsg.hdr.cmsg_type != SCM_RIGHTS) { rb_raise(rb_eSocket, "file descriptor was not passed (cmsg_type=%d, %d expected)", cmsg.hdr.cmsg_type, SCM_RIGHTS); } #else if (msg.msg_accrightslen != sizeof(fd)) { rb_raise(rb_eSocket, "file descriptor was not passed (accrightslen) : %d != %d", msg.msg_accrightslen, sizeof(fd)); } #endif #if FD_PASSING_BY_MSG_CONTROL fd = *(int *)CMSG_DATA(&cmsg.hdr); #endif if (klass == Qnil) return INT2FIX(fd); else { static ID for_fd = 0; int ff_argc; VALUE ff_argv[2]; if (!for_fd) for_fd = rb_intern("for_fd"); ff_argc = mode == Qnil ? 1 : 2; ff_argv[0] = INT2FIX(fd); ff_argv[1] = mode; return rb_funcall2(klass, for_fd, ff_argc, ff_argv); } #else rb_notimplement(); return Qnil; /* not reached */ #endif } static VALUE unix_accept(sock) VALUE sock; { rb_io_t *fptr; struct sockaddr_un from; socklen_t fromlen; GetOpenFile(sock, fptr); fromlen = sizeof(struct sockaddr_un); return s_accept(rb_cUNIXSocket, fileno(fptr->f), (struct sockaddr*)&from, &fromlen); } /* * call-seq: * unixserver.accept_nonblock => unixsocket * * Accepts an incoming connection using accept(2) after * O_NONBLOCK is set for the underlying file descriptor. * It returns an accepted UNIXSocket for the incoming connection. * * === Example * require 'socket' * serv = UNIXServer.new("/tmp/sock") * begin * sock = serv.accept_nonblock * rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR * IO.select([serv]) * retry * end * # sock is an accepted socket. * * Refer to Socket#accept for the exceptions that may be thrown if the call * to UNIXServer#accept_nonblock fails. * * UNIXServer#accept_nonblock may raise any error corresponding to accept(2) failure, * including Errno::EAGAIN. * * === See * * UNIXServer#accept * * Socket#accept */ static VALUE unix_accept_nonblock(sock) VALUE sock; { rb_io_t *fptr; struct sockaddr_un from; socklen_t fromlen; GetOpenFile(sock, fptr); fromlen = sizeof(from); return s_accept_nonblock(rb_cUNIXSocket, fptr, (struct sockaddr *)&from, &fromlen); } static VALUE unix_sysaccept(sock) VALUE sock; { rb_io_t *fptr; struct sockaddr_un from; socklen_t fromlen; GetOpenFile(sock, fptr); fromlen = sizeof(struct sockaddr_un); return s_accept(0, fileno(fptr->f), (struct sockaddr*)&from, &fromlen); } static VALUE unixaddr(sockaddr, len) struct sockaddr_un *sockaddr; socklen_t len; { return rb_assoc_new(rb_str_new2("AF_UNIX"), rb_str_new2(unixpath(sockaddr, len))); } static VALUE unix_addr(sock) VALUE sock; { rb_io_t *fptr; struct sockaddr_un addr; socklen_t len = sizeof addr; GetOpenFile(sock, fptr); if (getsockname(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) rb_sys_fail("getsockname(2)"); return unixaddr(&addr, len); } static VALUE unix_peeraddr(sock) VALUE sock; { rb_io_t *fptr; struct sockaddr_un addr; socklen_t len = sizeof addr; GetOpenFile(sock, fptr); if (getpeername(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) rb_sys_fail("getpeername(2)"); return unixaddr(&addr, len); } #endif static void setup_domain_and_type(domain, dv, type, tv) VALUE domain, type; int *dv, *tv; { VALUE tmp; char *ptr; tmp = rb_check_string_type(domain); if (!NIL_P(tmp)) { domain = tmp; rb_check_safe_obj(domain); ptr = RSTRING(domain)->ptr; if (strcmp(ptr, "AF_INET") == 0) *dv = AF_INET; #ifdef AF_UNIX else if (strcmp(ptr, "AF_UNIX") == 0) *dv = AF_UNIX; #endif #ifdef AF_ISO else if (strcmp(ptr, "AF_ISO") == 0) *dv = AF_ISO; #endif #ifdef AF_NS else if (strcmp(ptr, "AF_NS") == 0) *dv = AF_NS; #endif #ifdef AF_IMPLINK else if (strcmp(ptr, "AF_IMPLINK") == 0) *dv = AF_IMPLINK; #endif #ifdef PF_INET else if (strcmp(ptr, "PF_INET") == 0) *dv = PF_INET; #endif #ifdef PF_UNIX else if (strcmp(ptr, "PF_UNIX") == 0) *dv = PF_UNIX; #endif #ifdef PF_IMPLINK else if (strcmp(ptr, "PF_IMPLINK") == 0) *dv = PF_IMPLINK; else if (strcmp(ptr, "AF_IMPLINK") == 0) *dv = AF_IMPLINK; #endif #ifdef PF_AX25 else if (strcmp(ptr, "PF_AX25") == 0) *dv = PF_AX25; #endif #ifdef PF_IPX else if (strcmp(ptr, "PF_IPX") == 0) *dv = PF_IPX; #endif else rb_raise(rb_eSocket, "unknown socket domain %s", ptr); } else { *dv = NUM2INT(domain); } tmp = rb_check_string_type(type); if (!NIL_P(tmp)) { type = tmp; rb_check_safe_obj(type); ptr = RSTRING(type)->ptr; if (strcmp(ptr, "SOCK_STREAM") == 0) *tv = SOCK_STREAM; else if (strcmp(ptr, "SOCK_DGRAM") == 0) *tv = SOCK_DGRAM; #ifdef SOCK_RAW else if (strcmp(ptr, "SOCK_RAW") == 0) *tv = SOCK_RAW; #endif #ifdef SOCK_SEQPACKET else if (strcmp(ptr, "SOCK_SEQPACKET") == 0) *tv = SOCK_SEQPACKET; #endif #ifdef SOCK_RDM else if (strcmp(ptr, "SOCK_RDM") == 0) *tv = SOCK_RDM; #endif #ifdef SOCK_PACKET else if (strcmp(ptr, "SOCK_PACKET") == 0) *tv = SOCK_PACKET; #endif else rb_raise(rb_eSocket, "unknown socket type %s", ptr); } else { *tv = NUM2INT(type); } } static VALUE sock_initialize(sock, domain, type, protocol) VALUE sock, domain, type, protocol; { int fd; int d, t; rb_secure(3); setup_domain_and_type(domain, &d, type, &t); fd = ruby_socket(d, t, NUM2INT(protocol)); if (fd < 0) rb_sys_fail("socket(2)"); return init_sock(sock, fd); } static VALUE sock_s_socketpair(klass, domain, type, protocol) VALUE klass, domain, type, protocol; { #if defined HAVE_SOCKETPAIR int d, t, p, sp[2]; int ret; setup_domain_and_type(domain, &d, type, &t); p = NUM2INT(protocol); ret = socketpair(d, t, p, sp); if (ret < 0 && (errno == EMFILE || errno == ENFILE)) { rb_gc(); ret = socketpair(d, t, p, sp); } if (ret < 0) { rb_sys_fail("socketpair(2)"); } return rb_assoc_new(init_sock(rb_obj_alloc(klass), sp[0]), init_sock(rb_obj_alloc(klass), sp[1])); #else rb_notimplement(); #endif } #ifdef HAVE_SYS_UN_H static VALUE unix_s_socketpair(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { VALUE domain, type, protocol; domain = INT2FIX(PF_UNIX); rb_scan_args(argc, argv, "02", &type, &protocol); if (argc == 0) type = INT2FIX(SOCK_STREAM); if (argc <= 1) protocol = INT2FIX(0); return sock_s_socketpair(klass, domain, type, protocol); } #endif /* * call-seq: * socket.connect(server_sockaddr) => 0 * * Requests a connection to be made on the given +server_sockaddr+. Returns 0 if * successful, otherwise an exception is raised. * * === Parameter * * +server_sockaddr+ - the +struct+ sockaddr contained in a string * * === Example: * # Pull down Google's web page * require 'socket' * include Socket::Constants * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) * sockaddr = Socket.pack_sockaddr_in( 80, 'www.google.com' ) * socket.connect( sockaddr ) * socket.write( "GET / HTTP/1.0\r\n\r\n" ) * results = socket.read * * === Unix-based Exceptions * On unix-based systems the following system exceptions may be raised if * the call to _connect_ fails: * * Errno::EACCES - search permission is denied for a component of the prefix * path or write access to the +socket+ is denided * * Errno::EADDRINUSE - the _sockaddr_ is already in use * * Errno::EADDRNOTAVAIL - the specified _sockaddr_ is not available from the * local machine * * Errno::EAFNOSUPPORT - the specified _sockaddr_ is not a valid address for * the address family of the specified +socket+ * * Errno::EALREADY - a connection is already in progress for the specified * socket * * Errno::EBADF - the +socket+ is not a valid file descriptor * * Errno::ECONNREFUSED - the target _sockaddr_ was not listening for connections * refused the connection request * * Errno::ECONNRESET - the remote host reset the connection request * * Errno::EFAULT - the _sockaddr_ cannot be accessed * * Errno::EHOSTUNREACH - the destination host cannot be reached (probably * because the host is down or a remote router cannot reach it) * * Errno::EINPROGRESS - the O_NONBLOCK is set for the +socket+ and the * connection cnanot be immediately established; the connection will be * established asynchronously * * Errno::EINTR - the attempt to establish the connection was interrupted by * delivery of a signal that was caught; the connection will be established * asynchronously * * Errno::EISCONN - the specified +socket+ is already connected * * Errno::EINVAL - the address length used for the _sockaddr_ is not a valid * length for the address family or there is an invalid family in _sockaddr_ * * Errno::ENAMETOOLONG - the pathname resolved had a length which exceeded * PATH_MAX * * Errno::ENETDOWN - the local interface used to reach the destination is down * * Errno::ENETUNREACH - no route to the network is present * * Errno::ENOBUFS - no buffer space is available * * Errno::ENOSR - there were insufficient STREAMS resources available to * complete the operation * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket * * Errno::EOPNOTSUPP - the calling +socket+ is listening and cannot be connected * * Errno::EPROTOTYPE - the _sockaddr_ has a different type than the socket * bound to the specified peer address * * Errno::ETIMEDOUT - the attempt to connect time out before a connection * was made. * * On unix-based systems if the address family of the calling +socket+ is * AF_UNIX the follow exceptions may be raised if the call to _connect_ * fails: * * Errno::EIO - an i/o error occured while reading from or writing to the * file system * * Errno::ELOOP - too many symbolic links were encountered in translating * the pathname in _sockaddr_ * * Errno::ENAMETOOLLONG - a component of a pathname exceeded NAME_MAX * characters, or an entired pathname exceeded PATH_MAX characters * * Errno::ENOENT - a component of the pathname does not name an existing file * or the pathname is an empty string * * Errno::ENOTDIR - a component of the path prefix of the pathname in _sockaddr_ * is not a directory * * === Windows Exceptions * On Windows systems the following system exceptions may be raised if * the call to _connect_ fails: * * Errno::ENETDOWN - the network is down * * Errno::EADDRINUSE - the socket's local address is already in use * * Errno::EINTR - the socket was cancelled * * Errno::EINPROGRESS - a blocking socket is in progress or the service provider * is still processing a callback function. Or a nonblocking connect call is * in progress on the +socket+. * * Errno::EALREADY - see Errno::EINVAL * * Errno::EADDRNOTAVAIL - the remote address is not a valid address, such as * ADDR_ANY TODO check ADDRANY TO INADDR_ANY * * Errno::EAFNOSUPPORT - addresses in the specified family cannot be used with * with this +socket+ * * Errno::ECONNREFUSED - the target _sockaddr_ was not listening for connections * refused the connection request * * Errno::EFAULT - the socket's internal address or address length parameter * is too small or is not a valid part of the user space address * * Errno::EINVAL - the +socket+ is a listening socket * * Errno::EISCONN - the +socket+ is already connected * * Errno::ENETUNREACH - the network cannot be reached from this host at this time * * Errno::EHOSTUNREACH - no route to the network is present * * Errno::ENOBUFS - no buffer space is available * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket * * Errno::ETIMEDOUT - the attempt to connect time out before a connection * was made. * * Errno::EWOULDBLOCK - the socket is marked as nonblocking and the * connection cannot be completed immediately * * Errno::EACCES - the attempt to connect the datagram socket to the * broadcast address failed * * === See * * connect manual pages on unix-based systems * * connect function in Microsoft's Winsock functions reference */ static VALUE sock_connect(sock, addr) VALUE sock, addr; { rb_io_t *fptr; int fd; StringValue(addr); addr = rb_str_new4(addr); GetOpenFile(sock, fptr); fd = fileno(fptr->f); if (ruby_connect(fd, (struct sockaddr*)RSTRING(addr)->ptr, RSTRING(addr)->len, 0) < 0) { rb_sys_fail("connect(2)"); } return INT2FIX(0); } /* * call-seq: * socket.connect_nonblock(server_sockaddr) => 0 * * Requests a connection to be made on the given +server_sockaddr+ after * O_NONBLOCK is set for the underlying file descriptor. * Returns 0 if successful, otherwise an exception is raised. * * === Parameter * * +server_sockaddr+ - the +struct+ sockaddr contained in a string * * === Example: * # Pull down Google's web page * require 'socket' * include Socket::Constants * socket = Socket.new(AF_INET, SOCK_STREAM, 0) * sockaddr = Socket.sockaddr_in(80, 'www.google.com') * begin * socket.connect_nonblock(sockaddr) * rescue Errno::EINPROGRESS * IO.select(nil, [socket]) * begin * socket.connect_nonblock(sockaddr) * rescue Errno::EISCONN * end * end * socket.write("GET / HTTP/1.0\r\n\r\n") * results = socket.read * * Refer to Socket#connect for the exceptions that may be thrown if the call * to _connect_nonblock_ fails. * * Socket#connect_nonblock may raise any error corresponding to connect(2) failure, * including Errno::EINPROGRESS. * * === See * * Socket#connect */ static VALUE sock_connect_nonblock(sock, addr) VALUE sock, addr; { rb_io_t *fptr; int n; StringValue(addr); addr = rb_str_new4(addr); GetOpenFile(sock, fptr); rb_io_set_nonblock(fptr); n = connect(fileno(fptr->f), (struct sockaddr*)RSTRING(addr)->ptr, RSTRING(addr)->len); if (n < 0) { rb_sys_fail("connect(2)"); } return INT2FIX(n); } /* * call-seq: * socket.bind(server_sockaddr) => 0 * * Binds to the given +struct+ sockaddr. * * === Parameter * * +server_sockaddr+ - the +struct+ sockaddr contained in a string * * === Example * require 'socket' * include Socket::Constants * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) * socket.bind( sockaddr ) * * === Unix-based Exceptions * On unix-based based systems the following system exceptions may be raised if * the call to _bind_ fails: * * Errno::EACCES - the specified _sockaddr_ is protected and the current * user does not have permission to bind to it * * Errno::EADDRINUSE - the specified _sockaddr_ is already in use * * Errno::EADDRNOTAVAIL - the specified _sockaddr_ is not available from the * local machine * * Errno::EAFNOSUPPORT - the specified _sockaddr_ isnot a valid address for * the family of the calling +socket+ * * Errno::EBADF - the _sockaddr_ specified is not a valid file descriptor * * Errno::EFAULT - the _sockaddr_ argument cannot be accessed * * Errno::EINVAL - the +socket+ is already bound to an address, and the * protocol does not support binding to the new _sockaddr_ or the +socket+ * has been shut down. * * Errno::EINVAL - the address length is not a valid length for the address * family * * Errno::ENAMETOOLONG - the pathname resolved had a length which exceeded * PATH_MAX * * Errno::ENOBUFS - no buffer space is available * * Errno::ENOSR - there were insufficient STREAMS resources available to * complete the operation * * Errno::ENOTSOCK - the +socket+ does not refer to a socket * * Errno::EOPNOTSUPP - the socket type of the +socket+ does not support * binding to an address * * On unix-based based systems if the address family of the calling +socket+ is * Socket::AF_UNIX the follow exceptions may be raised if the call to _bind_ * fails: * * Errno::EACCES - search permission is denied for a component of the prefix * path or write access to the +socket+ is denided * * Errno::EDESTADDRREQ - the _sockaddr_ argument is a null pointer * * Errno::EISDIR - same as Errno::EDESTADDRREQ * * Errno::EIO - an i/o error occurred * * Errno::ELOOP - too many symbolic links were encountered in translating * the pathname in _sockaddr_ * * Errno::ENAMETOOLLONG - a component of a pathname exceeded NAME_MAX * characters, or an entired pathname exceeded PATH_MAX characters * * Errno::ENOENT - a component of the pathname does not name an existing file * or the pathname is an empty string * * Errno::ENOTDIR - a component of the path prefix of the pathname in _sockaddr_ * is not a directory * * Errno::EROFS - the name would reside on a read only filesystem * * === Windows Exceptions * On Windows systems the following system exceptions may be raised if * the call to _bind_ fails: * * Errno::ENETDOWN-- the network is down * * Errno::EACCES - the attempt to connect the datagram socket to the * broadcast address failed * * Errno::EADDRINUSE - the socket's local address is already in use * * Errno::EADDRNOTAVAIL - the specified address is not a valid address for this * computer * * Errno::EFAULT - the socket's internal address or address length parameter * is too small or is not a valid part of the user space addressed * * Errno::EINVAL - the +socket+ is already bound to an address * * Errno::ENOBUFS - no buffer space is available * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket * * === See * * bind manual pages on unix-based systems * * bind function in Microsoft's Winsock functions reference */ static VALUE sock_bind(sock, addr) VALUE sock, addr; { rb_io_t *fptr; StringValue(addr); GetOpenFile(sock, fptr); if (bind(fileno(fptr->f), (struct sockaddr*)RSTRING(addr)->ptr, RSTRING(addr)->len) < 0) rb_sys_fail("bind(2)"); return INT2FIX(0); } /* * call-seq: * socket.listen( int ) => 0 * * Listens for connections, using the specified +int+ as the backlog. A call * to _listen_ only applies if the +socket+ is of type SOCK_STREAM or * SOCK_SEQPACKET. * * === Parameter * * +backlog+ - the maximum length of the queue for pending connections. * * === Example 1 * require 'socket' * include Socket::Constants * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) * socket.bind( sockaddr ) * socket.listen( 5 ) * * === Example 2 (listening on an arbitary port, unix-based systems only): * require 'socket' * include Socket::Constants * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) * socket.listen( 1 ) * * === Unix-based Exceptions * On unix based systems the above will work because a new +sockaddr+ struct * is created on the address ADDR_ANY, for an arbitrary port number as handed * off by the kernel. It will not work on Windows, because Windows requires that * the +socket+ is bound by calling _bind_ before it can _listen_. * * If the _backlog_ amount exceeds the implementation-dependent maximum * queue length, the implementation's maximum queue length will be used. * * On unix-based based systems the following system exceptions may be raised if the * call to _listen_ fails: * * Errno::EBADF - the _socket_ argument is not a valid file descriptor * * Errno::EDESTADDRREQ - the _socket_ is not bound to a local address, and * the protocol does not support listening on an unbound socket * * Errno::EINVAL - the _socket_ is already connected * * Errno::ENOTSOCK - the _socket_ argument does not refer to a socket * * Errno::EOPNOTSUPP - the _socket_ protocol does not support listen * * Errno::EACCES - the calling process does not have approriate privileges * * Errno::EINVAL - the _socket_ has been shut down * * Errno::ENOBUFS - insufficient resources are available in the system to * complete the call * * === Windows Exceptions * On Windows systems the following system exceptions may be raised if * the call to _listen_ fails: * * Errno::ENETDOWN - the network is down * * Errno::EADDRINUSE - the socket's local address is already in use. This * usually occurs during the execution of _bind_ but could be delayed * if the call to _bind_ was to a partially wildcard address (involving * ADDR_ANY) and if a specific address needs to be commmitted at the * time of the call to _listen_ * * Errno::EINPROGRESS - a Windows Sockets 1.1 call is in progress or the * service provider is still processing a callback function * * Errno::EINVAL - the +socket+ has not been bound with a call to _bind_. * * Errno::EISCONN - the +socket+ is already connected * * Errno::EMFILE - no more socket descriptors are available * * Errno::ENOBUFS - no buffer space is available * * Errno::ENOTSOC - +socket+ is not a socket * * Errno::EOPNOTSUPP - the referenced +socket+ is not a type that supports * the _listen_ method * * === See * * listen manual pages on unix-based systems * * listen function in Microsoft's Winsock functions reference */ static VALUE sock_listen(sock, log) VALUE sock, log; { rb_io_t *fptr; int backlog; rb_secure(4); backlog = NUM2INT(log); GetOpenFile(sock, fptr); if (listen(fileno(fptr->f), backlog) < 0) rb_sys_fail("listen(2)"); return INT2FIX(0); } /* * call-seq: * socket.recvfrom(maxlen) => [mesg, sender_sockaddr] * socket.recvfrom(maxlen, flags) => [mesg, sender_sockaddr] * * Receives up to _maxlen_ bytes from +socket+. _flags_ is zero or more * of the +MSG_+ options. The first element of the results, _mesg_, is the data * received. The second element, _sender_sockaddr_, contains protocol-specific information * on the sender. * * === Parameters * * +maxlen+ - the number of bytes to receive from the socket * * +flags+ - zero or more of the +MSG_+ options * * === Example * # In one file, start this first * require 'socket' * include Socket::Constants * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) * socket.bind( sockaddr ) * socket.listen( 5 ) * client, client_sockaddr = socket.accept * data = client.recvfrom( 20 )[0].chomp * puts "I only received 20 bytes '#{data}'" * sleep 1 * socket.close * * # In another file, start this second * require 'socket' * include Socket::Constants * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) * socket.connect( sockaddr ) * socket.puts "Watch this get cut short!" * socket.close * * === Unix-based Exceptions * On unix-based based systems the following system exceptions may be raised if the * call to _recvfrom_ fails: * * Errno::EAGAIN - the +socket+ file descriptor is marked as O_NONBLOCK and no * data is waiting to be received; or MSG_OOB is set and no out-of-band data * is available and either the +socket+ file descriptor is marked as * O_NONBLOCK or the +socket+ does not support blocking to wait for * out-of-band-data * * Errno::EWOULDBLOCK - see Errno::EAGAIN * * Errno::EBADF - the +socket+ is not a valid file descriptor * * Errno::ECONNRESET - a connection was forcibly closed by a peer * * Errno::EFAULT - the socket's internal buffer, address or address length * cannot be accessed or written * * Errno::EINTR - a signal interupted _recvfrom_ before any data was available * * Errno::EINVAL - the MSG_OOB flag is set and no out-of-band data is available * * Errno::EIO - an i/o error occurred while reading from or writing to the * filesystem * * Errno::ENOBUFS - insufficient resources were available in the system to * perform the operation * * Errno::ENOMEM - insufficient memory was available to fulfill the request * * Errno::ENOSR - there were insufficient STREAMS resources available to * complete the operation * * Errno::ENOTCONN - a receive is attempted on a connection-mode socket that * is not connected * * Errno::ENOTSOCK - the +socket+ does not refer to a socket * * Errno::EOPNOTSUPP - the specified flags are not supported for this socket type * * Errno::ETIMEDOUT - the connection timed out during connection establishment * or due to a transmission timeout on an active connection * * === Windows Exceptions * On Windows systems the following system exceptions may be raised if * the call to _recvfrom_ fails: * * Errno::ENETDOWN - the network is down * * Errno::EFAULT - the internal buffer and from parameters on +socket+ are not * part of the user address space, or the internal fromlen parameter is * too small to accomodate the peer address * * Errno::EINTR - the (blocking) call was cancelled by an internal call to * the WinSock function WSACancelBlockingCall * * Errno::EINPROGRESS - a blocking Windows Sockets 1.1 call is in progress or * the service provider is still processing a callback function * * Errno::EINVAL - +socket+ has not been bound with a call to _bind_, or an * unknown flag was specified, or MSG_OOB was specified for a socket with * SO_OOBINLINE enabled, or (for byte stream-style sockets only) the internal * len parameter on +socket+ was zero or negative * * Errno::EISCONN - +socket+ is already connected. The call to _recvfrom_ is * not permitted with a connected socket on a socket that is connetion * oriented or connectionless. * * Errno::ENETRESET - the connection has been broken due to the keep-alive * activity detecting a failure while the operation was in progress. * * Errno::EOPNOTSUPP - MSG_OOB was specified, but +socket+ is not stream-style * such as type SOCK_STREAM. OOB data is not supported in the communication * domain associated with +socket+, or +socket+ is unidirectional and * supports only send operations * * Errno::ESHUTDOWN - +socket+ has been shutdown. It is not possible to * call _recvfrom_ on a socket after _shutdown_ has been invoked. * * Errno::EWOULDBLOCK - +socket+ is marked as nonblocking and a call to * _recvfrom_ would block. * * Errno::EMSGSIZE - the message was too large to fit into the specified buffer * and was truncated. * * Errno::ETIMEDOUT - the connection has been dropped, because of a network * failure or because the system on the other end went down without * notice * * Errno::ECONNRESET - the virtual circuit was reset by the remote side * executing a hard or abortive close. The application should close the * socket; it is no longer usable. On a UDP-datagram socket this error * indicates a previous send operation resulted in an ICMP Port Unreachable * message. */ static VALUE sock_recvfrom(argc, argv, sock) int argc; VALUE *argv; VALUE sock; { return s_recvfrom(sock, argc, argv, RECV_SOCKET); } /* * call-seq: * socket.recvfrom_nonblock(maxlen) => [mesg, sender_sockaddr] * socket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_sockaddr] * * Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after * O_NONBLOCK is set for the underlying file descriptor. * _flags_ is zero or more of the +MSG_+ options. * The first element of the results, _mesg_, is the data received. * The second element, _sender_sockaddr_, contains protocol-specific information * on the sender. * * When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns * an empty string as data. * The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc. * * === Parameters * * +maxlen+ - the number of bytes to receive from the socket * * +flags+ - zero or more of the +MSG_+ options * * === Example * # In one file, start this first * require 'socket' * include Socket::Constants * socket = Socket.new(AF_INET, SOCK_STREAM, 0) * sockaddr = Socket.sockaddr_in(2200, 'localhost') * socket.bind(sockaddr) * socket.listen(5) * client, client_sockaddr = socket.accept * begin * pair = client.recvfrom_nonblock(20) * rescue Errno::EAGAIN, Errno::EWOULDBLOCK * IO.select([client]) * retry * end * data = pair[0].chomp * puts "I only received 20 bytes '#{data}'" * sleep 1 * socket.close * * # In another file, start this second * require 'socket' * include Socket::Constants * socket = Socket.new(AF_INET, SOCK_STREAM, 0) * sockaddr = Socket.sockaddr_in(2200, 'localhost') * socket.connect(sockaddr) * socket.puts "Watch this get cut short!" * socket.close * * Refer to Socket#recvfrom for the exceptions that may be thrown if the call * to _recvfrom_nonblock_ fails. * * Socket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure, * including Errno::EAGAIN. * * === See * * Socket#recvfrom */ static VALUE sock_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock) { return s_recvfrom_nonblock(sock, argc, argv, RECV_SOCKET); } /* * call-seq: * socket.accept => [ socket, string ] * * Accepts an incoming connection returning an array containing a new * Socket object and a string holding the +struct+ sockaddr information about * the caller. * * === Example * # In one script, start this first * require 'socket' * include Socket::Constants * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) * socket.bind( sockaddr ) * socket.listen( 5 ) * client, client_sockaddr = socket.accept * puts "The client said, '#{client.readline.chomp}'" * client.puts "Hello from script one!" * socket.close * * # In another script, start this second * require 'socket' * include Socket::Constants * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) * socket.connect( sockaddr ) * socket.puts "Hello from script 2." * puts "The server said, '#{socket.readline.chomp}'" * socket.close * * === Unix-based Exceptions * On unix-based based systems the following system exceptions may be raised if the * call to _accept_ fails: * * Errno::EAGAIN - O_NONBLOCK is set for the +socket+ file descriptor and no * connections are parent to be accepted * * Errno::EWOULDBLOCK - same as Errno::EAGAIN * * Errno::EBADF - the +socket+ is not a valid file descriptor * * Errno::ECONNABORTED - a connection has been aborted * * Errno::EFAULT - the socket's internal address or address length parameter * cannot be access or written * * Errno::EINTR - the _accept_ method was interrupted by a signal that was * caught before a valid connection arrived * * Errno::EINVAL - the +socket+ is not accepting connections * * Errno::EMFILE - OPEN_MAX file descriptors are currently open in the calling * process * * Errno::ENOBUFS - no buffer space is available * * Errno::ENOMEM - there was insufficient memory available to complete the * operation * * Errno::ENOSR - there was insufficient STREAMS resources available to * complete the operation * * Errno::ENFILE - the maximum number of file descriptors in the system are * already open * * Errno::ENOTSOCK - the +socket+ does not refer to a socket * * Errno::EOPNOTSUPP - the socket type for the calling +socket+ does not * support accept connections * * Errno::EPROTO - a protocol error has occurred * * === Windows Exceptions * On Windows systems the following system exceptions may be raised if * the call to _accept_ fails: * * Errno::ECONNRESET - an incoming connection was indicated, but was * terminated by the remote peer prior to accepting the connection * * Errno::EFAULT - the socket's internal address or address length parameter * is too small or is not a valid part of the user space address * * Errno::EINVAL - the _listen_ method was not invoked prior to calling _accept_ * * Errno::EINPROGRESS - a blocking Windows Sockets 1.1 call is in progress or * the service provider is still processing a callback function * * Errno::EMFILE - the queue is not empty, upong etry to _accept_ and there are * no socket descriptors available * * Errno::ENETDOWN - the network is down * * Errno::ENOBUFS - no buffer space is available * * Errno::ENOTSOCK - +socket+ is not a socket * * Errno::EOPNOTSUPP - +socket+ is not a type that supports connection-oriented * service. * * Errno::EWOULDBLOCK - +socket+ is marked as nonblocking and no connections are * present to be accepted * * === See * * accept manual pages on unix-based systems * * accept function in Microsoft's Winsock functions reference */ static VALUE sock_accept(sock) VALUE sock; { rb_io_t *fptr; VALUE sock2; char buf[1024]; socklen_t len = sizeof buf; GetOpenFile(sock, fptr); sock2 = s_accept(rb_cSocket,fileno(fptr->f),(struct sockaddr*)buf,&len); return rb_assoc_new(sock2, rb_str_new(buf, len)); } /* * call-seq: * socket.accept_nonblock => [client_socket, client_sockaddr] * * Accepts an incoming connection using accept(2) after * O_NONBLOCK is set for the underlying file descriptor. * It returns an array containg the accpeted socket * for the incoming connection, _client_socket_, * and a string that contains the +struct+ sockaddr information * about the caller, _client_sockaddr_. * * === Example * # In one script, start this first * require 'socket' * include Socket::Constants * socket = Socket.new(AF_INET, SOCK_STREAM, 0) * sockaddr = Socket.sockaddr_in(2200, 'localhost') * socket.bind(sockaddr) * socket.listen(5) * begin * client_socket, client_sockaddr = socket.accept_nonblock * rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR * IO.select([socket]) * retry * end * puts "The client said, '#{client_socket.readline.chomp}'" * client_socket.puts "Hello from script one!" * socket.close * * # In another script, start this second * require 'socket' * include Socket::Constants * socket = Socket.new(AF_INET, SOCK_STREAM, 0) * sockaddr = Socket.sockaddr_in(2200, 'localhost') * socket.connect(sockaddr) * socket.puts "Hello from script 2." * puts "The server said, '#{socket.readline.chomp}'" * socket.close * * Refer to Socket#accept for the exceptions that may be thrown if the call * to _accept_nonblock_ fails. * * Socket#accept_nonblock may raise any error corresponding to accept(2) failure, * including Errno::EAGAIN. * * === See * * Socket#accept */ static VALUE sock_accept_nonblock(sock) VALUE sock; { rb_io_t *fptr; VALUE sock2; char buf[1024]; socklen_t len = sizeof buf; GetOpenFile(sock, fptr); sock2 = s_accept_nonblock(rb_cSocket, fptr, (struct sockaddr *)buf, &len); return rb_assoc_new(sock2, rb_str_new(buf, len)); } /* * call-seq: * socket.sysaccept => [client_socket_fd, client_sockaddr] * * Accepts an incoming connection returnings an array containg the (integer) * file descriptor for the incoming connection, _client_socket_fd_, * and a string that contains the +struct+ sockaddr information * about the caller, _client_sockaddr_. * * === Example * # In one script, start this first * require 'socket' * include Socket::Constants * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) * socket.bind( sockaddr ) * socket.listen( 5 ) * client_fd, client_sockaddr = socket.sysaccept * client_socket = Socket.for_fd( client_fd ) * puts "The client said, '#{client_socket.readline.chomp}'" * client_socket.puts "Hello from script one!" * socket.close * * # In another script, start this second * require 'socket' * include Socket::Constants * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) * socket.connect( sockaddr ) * socket.puts "Hello from script 2." * puts "The server said, '#{socket.readline.chomp}'" * socket.close * * Refer to Socket#accept for the exceptions that may be thrown if the call * to _sysaccept_ fails. * * === See * * Socket#accept */ static VALUE sock_sysaccept(sock) VALUE sock; { rb_io_t *fptr; VALUE sock2; char buf[1024]; socklen_t len = sizeof buf; GetOpenFile(sock, fptr); sock2 = s_accept(0,fileno(fptr->f),(struct sockaddr*)buf,&len); return rb_assoc_new(sock2, rb_str_new(buf, len)); } #ifdef HAVE_GETHOSTNAME static VALUE sock_gethostname(obj) VALUE obj; { char buf[1024]; rb_secure(3); if (gethostname(buf, (int)sizeof buf - 1) < 0) rb_sys_fail("gethostname"); buf[sizeof buf - 1] = '\0'; return rb_str_new2(buf); } #else #ifdef HAVE_UNAME #include static VALUE sock_gethostname(obj) VALUE obj; { struct utsname un; rb_secure(3); uname(&un); return rb_str_new2(un.nodename); } #else static VALUE sock_gethostname(obj) VALUE obj; { rb_notimplement(); } #endif #endif static VALUE make_addrinfo(res0) struct addrinfo *res0; { VALUE base, ary; struct addrinfo *res; if (res0 == NULL) { rb_raise(rb_eSocket, "host not found"); } base = rb_ary_new(); for (res = res0; res; res = res->ai_next) { ary = ipaddr(res->ai_addr); rb_ary_push(ary, INT2FIX(res->ai_family)); rb_ary_push(ary, INT2FIX(res->ai_socktype)); rb_ary_push(ary, INT2FIX(res->ai_protocol)); rb_ary_push(base, ary); } return base; } /* Returns a String containing the binary value of a struct sockaddr. */ VALUE sock_sockaddr(addr, len) struct sockaddr *addr; size_t len; { char *ptr; switch (addr->sa_family) { case AF_INET: ptr = (char*)&((struct sockaddr_in*)addr)->sin_addr.s_addr; len = sizeof(((struct sockaddr_in*)addr)->sin_addr.s_addr); break; #ifdef INET6 case AF_INET6: ptr = (char*)&((struct sockaddr_in6*)addr)->sin6_addr.s6_addr; len = sizeof(((struct sockaddr_in6*)addr)->sin6_addr.s6_addr); break; #endif default: rb_raise(rb_eSocket, "unknown socket family:%d", addr->sa_family); break; } return rb_str_new(ptr, len); } /* * Document-class: IPSocket * * IPSocket is the parent of TCPSocket and UDPSocket and implements * functionality common to them. * * A number of APIs in IPSocket, Socket, and their descendants return an * address as an array. The members of that array are: * - address family: A string like "AF_INET" or "AF_INET6" if it is one of the * commonly used families, the string "unknown:#" (where `#' is the address * family number) if it is not one of the common ones. The strings map to * the Socket::AF_* constants. * - port: The port number. * - name: Either the canonical name from looking the address up in the DNS, or * the address in presentation format * - address: The address in presentation format (a dotted decimal string for * IPv4, a hex string for IPv6). * * The address and port can be used directly to create sockets and to bind or * connect them to the address. */ /* * Document-class: Socket * * Socket contains a number of generally useful singleton methods and * constants, as well as offering low-level interfaces that can be used to * develop socket applications using protocols other than TCP, UDP, and UNIX * domain sockets. */ /* * Document-method: gethostbyname * call-seq: Socket.gethostbyname(host) => hostent * * Resolve +host+ and return name and address information for it, similarly to * gethostbyname(3). +host+ can be a domain name or the presentation format of * an address. * * Returns an array of information similar to that found in a +struct hostent+: * - cannonical name: the cannonical name for host in the DNS, or a * string representing the address * - aliases: an array of aliases for the canonical name, there may be no aliases * - address family: usually one of Socket::AF_INET or Socket::AF_INET6 * - address: a string, the binary value of the +struct sockaddr+ for this name, in * the indicated address family * - ...: if there are multiple addresses for this host, a series of * strings/+struct sockaddr+s may follow, not all necessarily in the same * address family. Note that the fact that they may not be all in the same * address family is a departure from the behaviour of gethostbyname(3). * * Note: I believe that the fact that the multiple addresses returned are not * necessarily in the same address family may be a bug, since if this function * actually called gethostbyname(3), ALL the addresses returned in the trailing * address list (h_addr_list from struct hostent) would be of the same address * family! Examples from my system, OS X 10.3: * * ["localhost", [], 30, "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001", "\177\000\000\001"] * and * ["ensemble.local", [], 30, "\376\200\000\004\000\000\000\000\002\003\223\377\376\255\010\214", "\300\250{\232" ] * * Similar information can be returned by Socket.getaddrinfo if called as: * * Socket.getaddrinfo(+host+, 0, Socket::AF_UNSPEC, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME) * * == Examples * * Socket.gethostbyname "example.com" * => ["example.com", [], 2, "\300\000\"\246"] * * This name has no DNS aliases, and a single IPv4 address. * * Socket.gethostbyname "smtp.telus.net" * => ["smtp.svc.telus.net", ["smtp.telus.net"], 2, "\307\271\334\371"] * * This name is an an alias so the canonical name is returned, as well as the * alias and a single IPv4 address. * * Socket.gethostbyname "localhost" * => ["localhost", [], 30, "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001", "\177\000\000\001"] * * This machine has no aliases, returns an IPv6 address, and has an additional IPv4 address. * * +host+ can also be an IP address in presentation format, in which case a * reverse lookup is done on the address: * * Socket.gethostbyname("127.0.0.1") * => ["localhost", [], 2, "\177\000\000\001"] * * Socket.gethostbyname("192.0.34.166") * => ["www.example.com", [], 2, "\300\000\"\246"] * * * == See * See: Socket.getaddrinfo */ static VALUE sock_s_gethostbyname(obj, host) VALUE obj, host; { rb_secure(3); return make_hostent(host, sock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME), sock_sockaddr); } static VALUE sock_s_gethostbyaddr(argc, argv) int argc; VALUE *argv; { VALUE addr, type; struct hostent *h; struct sockaddr *sa; char **pch; VALUE ary, names; int t = AF_INET; rb_scan_args(argc, argv, "11", &addr, &type); sa = (struct sockaddr*)StringValuePtr(addr); if (!NIL_P(type)) { t = NUM2INT(type); } #ifdef INET6 else if (RSTRING(addr)->len == 16) { t = AF_INET6; } #endif h = gethostbyaddr(RSTRING(addr)->ptr, RSTRING(addr)->len, t); if (h == NULL) { #ifdef HAVE_HSTRERROR extern int h_errno; rb_raise(rb_eSocket, "%s", (char*)hstrerror(h_errno)); #else rb_raise(rb_eSocket, "host not found"); #endif } ary = rb_ary_new(); rb_ary_push(ary, rb_str_new2(h->h_name)); names = rb_ary_new(); rb_ary_push(ary, names); if (h->h_aliases != NULL) { for (pch = h->h_aliases; *pch; pch++) { rb_ary_push(names, rb_str_new2(*pch)); } } rb_ary_push(ary, INT2NUM(h->h_addrtype)); #ifdef h_addr for (pch = h->h_addr_list; *pch; pch++) { rb_ary_push(ary, rb_str_new(*pch, h->h_length)); } #else rb_ary_push(ary, rb_str_new(h->h_addr, h->h_length)); #endif return ary; } /* * Document-method: getservbyname * call-seq: Socket.getservbyname(name, proto="tcp") => port * * +name+ is a service name ("ftp", "telnet", ...) and proto is a protocol name * ("udp", "tcp", ...). '/etc/services' (or your system's equivalent) is * searched for a service for +name+ and +proto+, and the port number is * returned. * * Note that unlike Socket.getaddrinfo, +proto+ may not be specified using the * Socket::SOCK_* constants, a string must must be used. */ static VALUE sock_s_getservbyaname(argc, argv) int argc; VALUE *argv; { VALUE service, proto; struct servent *sp; int port; rb_scan_args(argc, argv, "11", &service, &proto); if (NIL_P(proto)) proto = rb_str_new2("tcp"); StringValue(service); StringValue(proto); sp = getservbyname(StringValueCStr(service), StringValueCStr(proto)); if (sp) { port = ntohs(sp->s_port); } else { char *s = RSTRING(service)->ptr; char *end; port = strtoul(s, &end, 0); if (*end != '\0') { rb_raise(rb_eSocket, "no such service %s/%s", s, RSTRING(proto)->ptr); } } return INT2FIX(port); } /* Documentation should explain the following: $ pp Socket.getaddrinfo("", 1, Socket::AF_UNSPEC, Socket::SOCK_STREAM, 0, Socket::AI_PASSIVE) [["AF_INET", 1, "0.0.0.0", "0.0.0.0", 2, 1, 6]] $ pp Socket.getaddrinfo(nil, 1, Socket::AF_UNSPEC, Socket::SOCK_STREAM, 0, Socket::AI_PASSIVE) [["AF_INET6", 1, "::", "::", 30, 1, 6], ["AF_INET", 1, "0.0.0.0", "0.0.0.0", 2, 1, 6]] $ pp Socket.getaddrinfo("localhost", 1, Socket::AF_UNSPEC, Socket::SOCK_STREAM, 0, Socket::AI_PASSIVE) [["AF_INET6", 1, "localhost", "::1", 30, 1, 6], ["AF_INET", 1, "localhost", "127.0.0.1", 2, 1, 6]] $ pp Socket.getaddrinfo("ensemble.local.", 1, Socket::AF_UNSPEC, Socket::SOCK_STREAM, 0, Socket::AI_PASSIVE) [["AF_INET", 1, "localhost", "192.168.123.154", 2, 1, 6]] Does it? API suggestion: this method has too many arguments, it would be backwards compatible and easier to understand if limit args were accepted as :family=>..., :flags=>... */ /* * Document-method: getaddrinfo * call-seq: Socket.getaddrinfo(host, service, family=nil, socktype=nil, protocol=nil, flags=nil) => addrinfo * * Return address information for +host+ and +port+. The remaining arguments * are hints that limit the address information returned. * * This method corresponds closely to the POSIX.1g getaddrinfo() definition. * * === Parameters * - +host+ is a host name or an address string (dotted decimal for IPv4, or a hex string * for IPv6) for which to return information. A nil is also allowed, its meaning * depends on +flags+, see below. * - +service+ is a service name ("http", "ssh", ...), or * a port number (80, 22, ...), see Socket.getservbyname for more * information. A nil is also allowed, meaning zero. * - +family+ limits the output to a specific address family, one of the * Socket::AF_* constants. Socket::AF_INET (IPv4) and Socket::AF_INET6 (IPv6) * are the most commonly used families. You will usually pass either nil or * Socket::AF_UNSPEC, allowing the IPv6 information to be returned first if * +host+ is reachable via IPv6, and IPv4 information otherwise. The two * strings "AF_INET" or "AF_INET6" are also allowed, they are converted to * their respective Socket::AF_* constants. * - +socktype+ limits the output to a specific type of socket, one of the * Socket::SOCK_* constants. Socket::SOCK_STREAM (for TCP) and * Socket::SOCK_DGRAM (for UDP) are the most commonly used socket types. If * nil, then information for all types of sockets supported by +service+ will * be returned. You will usually know what type of socket you intend to * create, and should pass that socket type in. * - +protocol+ limits the output to a specific protocol numpber, one of the * Socket::IPPROTO_* constants. It is usually implied by the socket type * (Socket::SOCK_STREAM => Socket::IPPROTO_TCP, ...), if you pass other than * nil you already know what this is for. * - +flags+ is one of the Socket::AI_* constants. They mean: * - Socket::AI_PASSIVE: when set, if +host+ is nil the 'any' address will be * returned, Socket::INADDR_ANY or 0 for IPv4, "0::0" or "::" for IPv6. This * address is suitable for use by servers that will bind their socket and do * a passive listen, thus the name of the flag. Otherwise the local or * loopback address will be returned, this is "127.0.0.1" for IPv4 and "::1' * for IPv6. * - ... * * * === Returns * * Returns an array of arrays, where each subarray contains: * - address family, a string like "AF_INET" or "AF_INET6" * - port number, the port number for +service+ * - host name, either a canonical name for +host+, or it's address in presentation * format if the address could not be looked up. * - host IP, the address of +host+ in presentation format * - address family, as a numeric value (one of the Socket::AF_* constants). * - socket type, as a numeric value (one of the Socket::SOCK_* constants). * - protocol number, as a numeric value (one of the Socket::IPPROTO_* constants). * * The first four values are identical to what is commonly returned as an * address array, see IPSocket for more information. * * === Examples * * Not all input combinations are valid, and while there are many combinations, * only a few cases are common. * * A typical client will call getaddrinfo with the +host+ and +service+ it * wants to connect to. It knows that it will attempt to connect with either * TCP or UDP, and specifies +socktype+ accordingly. It loops through all * returned addresses, and try to connect to them in turn: * * addrinfo = Socket::getaddrinfo('www.example.com', 'www', nil, Socket::SOCK_STREAM) * addrinfo.each do |af, port, name, addr| * begin * sock = TCPSocket.new(addr, port) * # ... * exit 1 * rescue * end * end * * With UDP you don't know if connect suceeded, but if communication fails, * the next address can be tried. * * A typical server will call getaddrinfo with a +host+ of nil, the +service+ * it listens to, and a +flags+ of Socket::AI_PASSIVE. It will listen for * connections on the first returned address: * addrinfo = Socket::getaddrinfo(nil, 'www', nil, Socket::SOCK_STREAM, nil, Socket::AI_PASSIVE) * af, port, name, addr = addrinfo.first * sock = TCPServer(addr, port) * while( client = s.accept ) * # ... * end */ static VALUE sock_s_getaddrinfo(argc, argv) int argc; VALUE *argv; { VALUE host, port, family, socktype, protocol, flags, ret; char hbuf[1024], pbuf[1024]; char *hptr, *pptr, *ap; struct addrinfo hints, *res; int error; host = port = family = socktype = protocol = flags = Qnil; rb_scan_args(argc, argv, "24", &host, &port, &family, &socktype, &protocol, &flags); if (NIL_P(host)) { hptr = NULL; } else { strncpy(hbuf, StringValuePtr(host), sizeof(hbuf)); hbuf[sizeof(hbuf) - 1] = '\0'; hptr = hbuf; } if (NIL_P(port)) { pptr = NULL; } else if (FIXNUM_P(port)) { snprintf(pbuf, sizeof(pbuf), "%ld", FIX2LONG(port)); pptr = pbuf; } else { strncpy(pbuf, StringValuePtr(port), sizeof(pbuf)); pbuf[sizeof(pbuf) - 1] = '\0'; pptr = pbuf; } MEMZERO(&hints, struct addrinfo, 1); if (NIL_P(family)) { hints.ai_family = PF_UNSPEC; } else if (FIXNUM_P(family)) { hints.ai_family = FIX2INT(family); } else if ((ap = StringValuePtr(family)) != 0) { if (strcmp(ap, "AF_INET") == 0) { hints.ai_family = PF_INET; } #ifdef INET6 else if (strcmp(ap, "AF_INET6") == 0) { hints.ai_family = PF_INET6; } #endif } if (!NIL_P(socktype)) { hints.ai_socktype = NUM2INT(socktype); } if (!NIL_P(protocol)) { hints.ai_protocol = NUM2INT(protocol); } if (!NIL_P(flags)) { hints.ai_flags = NUM2INT(flags); } error = getaddrinfo(hptr, pptr, &hints, &res); if (error) { rb_raise(rb_eSocket, "getaddrinfo: %s", gai_strerror(error)); } ret = make_addrinfo(res); freeaddrinfo(res); return ret; } static VALUE sock_s_getnameinfo(argc, argv) int argc; VALUE *argv; { VALUE sa, af = Qnil, host = Qnil, port = Qnil, flags, tmp; char *hptr, *pptr; char hbuf[1024], pbuf[1024]; int fl; struct addrinfo hints, *res = NULL, *r; int error; struct sockaddr_storage ss; struct sockaddr *sap; char *ap; sa = flags = Qnil; rb_scan_args(argc, argv, "11", &sa, &flags); fl = 0; if (!NIL_P(flags)) { fl = NUM2INT(flags); } tmp = rb_check_string_type(sa); if (!NIL_P(tmp)) { sa = tmp; if (sizeof(ss) < RSTRING(sa)->len) { rb_raise(rb_eTypeError, "sockaddr length too big"); } memcpy(&ss, RSTRING(sa)->ptr, RSTRING(sa)->len); if (RSTRING(sa)->len != SA_LEN((struct sockaddr*)&ss)) { rb_raise(rb_eTypeError, "sockaddr size differs - should not happen"); } sap = (struct sockaddr*)&ss; goto call_nameinfo; } tmp = rb_check_array_type(sa); if (!NIL_P(tmp)) { sa = tmp; MEMZERO(&hints, struct addrinfo, 1); if (RARRAY(sa)->len == 3) { af = RARRAY(sa)->ptr[0]; port = RARRAY(sa)->ptr[1]; host = RARRAY(sa)->ptr[2]; } else if (RARRAY(sa)->len >= 4) { af = RARRAY(sa)->ptr[0]; port = RARRAY(sa)->ptr[1]; host = RARRAY(sa)->ptr[3]; if (NIL_P(host)) { host = RARRAY(sa)->ptr[2]; } else { /* * 4th element holds numeric form, don't resolve. * see ipaddr(). */ #ifdef AI_NUMERICHOST /* AIX 4.3.3 doesn't have AI_NUMERICHOST. */ hints.ai_flags |= AI_NUMERICHOST; #endif } } else { rb_raise(rb_eArgError, "array size should be 3 or 4, %ld given", RARRAY(sa)->len); } /* host */ if (NIL_P(host)) { hptr = NULL; } else { strncpy(hbuf, StringValuePtr(host), sizeof(hbuf)); hbuf[sizeof(hbuf) - 1] = '\0'; hptr = hbuf; } /* port */ if (NIL_P(port)) { strcpy(pbuf, "0"); pptr = NULL; } else if (FIXNUM_P(port)) { snprintf(pbuf, sizeof(pbuf), "%ld", NUM2LONG(port)); pptr = pbuf; } else { strncpy(pbuf, StringValuePtr(port), sizeof(pbuf)); pbuf[sizeof(pbuf) - 1] = '\0'; pptr = pbuf; } hints.ai_socktype = (fl & NI_DGRAM) ? SOCK_DGRAM : SOCK_STREAM; /* af */ if (NIL_P(af)) { hints.ai_family = PF_UNSPEC; } else if (FIXNUM_P(af)) { hints.ai_family = FIX2INT(af); } else if ((ap = StringValuePtr(af)) != 0) { if (strcmp(ap, "AF_INET") == 0) { hints.ai_family = PF_INET; } #ifdef INET6 else if (strcmp(ap, "AF_INET6") == 0) { hints.ai_family = PF_INET6; } #endif } error = getaddrinfo(hptr, pptr, &hints, &res); if (error) goto error_exit_addr; sap = res->ai_addr; } else { rb_raise(rb_eTypeError, "expecting String or Array"); } call_nameinfo: error = getnameinfo(sap, SA_LEN(sap), hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), fl); if (error) goto error_exit_name; if (res) { for (r = res->ai_next; r; r = r->ai_next) { char hbuf2[1024], pbuf2[1024]; sap = r->ai_addr; error = getnameinfo(sap, SA_LEN(sap), hbuf2, sizeof(hbuf2), pbuf2, sizeof(pbuf2), fl); if (error) goto error_exit_name; if (strcmp(hbuf, hbuf2) != 0|| strcmp(pbuf, pbuf2) != 0) { freeaddrinfo(res); rb_raise(rb_eSocket, "sockaddr resolved to multiple nodename"); } } freeaddrinfo(res); } return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf)); error_exit_addr: if (res) freeaddrinfo(res); rb_raise(rb_eSocket, "getaddrinfo: %s", gai_strerror(error)); error_exit_name: if (res) freeaddrinfo(res); rb_raise(rb_eSocket, "getnameinfo: %s", gai_strerror(error)); } static VALUE sock_s_pack_sockaddr_in(self, port, host) VALUE self, port, host; { struct addrinfo *res = sock_addrinfo(host, port, 0, 0); VALUE addr = rb_str_new((char*)res->ai_addr, res->ai_addrlen); freeaddrinfo(res); OBJ_INFECT(addr, port); OBJ_INFECT(addr, host); return addr; } static VALUE sock_s_unpack_sockaddr_in(self, addr) VALUE self, addr; { struct sockaddr_in * sockaddr; VALUE host; sockaddr = (struct sockaddr_in*)StringValuePtr(addr); if (((struct sockaddr *)sockaddr)->sa_family != AF_INET #ifdef INET6 && ((struct sockaddr *)sockaddr)->sa_family != AF_INET6 #endif ) { #ifdef INET6 rb_raise(rb_eArgError, "not an AF_INET/AF_INET6 sockaddr"); #else rb_raise(rb_eArgError, "not an AF_INET sockaddr"); #endif } host = make_ipaddr((struct sockaddr*)sockaddr); OBJ_INFECT(host, addr); return rb_assoc_new(INT2NUM(ntohs(sockaddr->sin_port)), host); } #ifdef HAVE_SYS_UN_H static VALUE sock_s_pack_sockaddr_un(self, path) VALUE self, path; { struct sockaddr_un sockaddr; char *sun_path; VALUE addr; MEMZERO(&sockaddr, struct sockaddr_un, 1); sockaddr.sun_family = AF_UNIX; sun_path = StringValueCStr(path); if (sizeof(sockaddr.sun_path) <= strlen(sun_path)) { rb_raise(rb_eArgError, "too long unix socket path (max: %dbytes)", (int)sizeof(sockaddr.sun_path)-1); } strncpy(sockaddr.sun_path, sun_path, sizeof(sockaddr.sun_path)-1); addr = rb_str_new((char*)&sockaddr, sizeof(sockaddr)); OBJ_INFECT(addr, path); return addr; } static VALUE sock_s_unpack_sockaddr_un(self, addr) VALUE self, addr; { struct sockaddr_un * sockaddr; char *sun_path; VALUE path; sockaddr = (struct sockaddr_un*)StringValuePtr(addr); if (((struct sockaddr *)sockaddr)->sa_family != AF_UNIX) { rb_raise(rb_eArgError, "not an AF_UNIX sockaddr"); } if (sizeof(struct sockaddr_un) < RSTRING(addr)->len) { rb_raise(rb_eTypeError, "too long sockaddr_un - %ld longer than %d", RSTRING(addr)->len, sizeof(struct sockaddr_un)); } sun_path = unixpath(sockaddr, RSTRING(addr)->len); if (sizeof(struct sockaddr_un) == RSTRING(addr)->len && sun_path == sockaddr->sun_path && sun_path + strlen(sun_path) == RSTRING(addr)->ptr + RSTRING(addr)->len) { rb_raise(rb_eArgError, "sockaddr_un.sun_path not NUL terminated"); } path = rb_str_new2(sun_path); OBJ_INFECT(path, addr); return path; } #endif static VALUE mConst; static void sock_define_const(name, value) char *name; int value; { rb_define_const(rb_cSocket, name, INT2FIX(value)); rb_define_const(mConst, name, INT2FIX(value)); } /* * Class +Socket+ provides access to the underlying operating system * socket implementations. It can be used to provide more operating system * specific functionality than the protocol-specific socket classes but at the * expense of greater complexity. In particular, the class handles addresses * using +struct sockaddr+ structures packed into Ruby strings, which can be * a joy to manipulate. * * === Exception Handling * Ruby's implementation of +Socket+ causes an exception to be raised * based on the error generated by the system dependent implementation. * This is why the methods are documented in a way that isolate * Unix-based system exceptions from Windows based exceptions. If more * information on particular exception is needed please refer to the * Unix manual pages or the Windows WinSock reference. * * * === Documentation by * * Zach Dennis * * Sam Roberts * * Programming Ruby from The Pragmatic Bookshelf. * * Much material in this documentation is taken with permission from * Programming Ruby from The Pragmatic Bookshelf. */ void Init_socket() { rb_eSocket = rb_define_class("SocketError", rb_eStandardError); rb_cBasicSocket = rb_define_class("BasicSocket", rb_cIO); rb_undef_method(rb_cBasicSocket, "initialize"); rb_define_singleton_method(rb_cBasicSocket, "do_not_reverse_lookup", bsock_do_not_rev_lookup, 0); rb_define_singleton_method(rb_cBasicSocket, "do_not_reverse_lookup=", bsock_do_not_rev_lookup_set, 1); rb_define_singleton_method(rb_cBasicSocket, "for_fd", bsock_s_for_fd, 1); rb_define_method(rb_cBasicSocket, "close_read", bsock_close_read, 0); rb_define_method(rb_cBasicSocket, "close_write", bsock_close_write, 0); rb_define_method(rb_cBasicSocket, "shutdown", bsock_shutdown, -1); rb_define_method(rb_cBasicSocket, "setsockopt", bsock_setsockopt, 3); rb_define_method(rb_cBasicSocket, "getsockopt", bsock_getsockopt, 2); rb_define_method(rb_cBasicSocket, "getsockname", bsock_getsockname, 0); rb_define_method(rb_cBasicSocket, "getpeername", bsock_getpeername, 0); rb_define_method(rb_cBasicSocket, "send", bsock_send, -1); rb_define_method(rb_cBasicSocket, "recv", bsock_recv, -1); rb_define_method(rb_cBasicSocket, "recv_nonblock", bsock_recv_nonblock, -1); rb_cIPSocket = rb_define_class("IPSocket", rb_cBasicSocket); rb_define_global_const("IPsocket", rb_cIPSocket); rb_define_method(rb_cIPSocket, "addr", ip_addr, 0); rb_define_method(rb_cIPSocket, "peeraddr", ip_peeraddr, 0); rb_define_method(rb_cIPSocket, "recvfrom", ip_recvfrom, -1); rb_define_singleton_method(rb_cIPSocket, "getaddress", ip_s_getaddress, 1); rb_cTCPSocket = rb_define_class("TCPSocket", rb_cIPSocket); rb_define_global_const("TCPsocket", rb_cTCPSocket); rb_define_singleton_method(rb_cTCPSocket, "gethostbyname", tcp_s_gethostbyname, 1); rb_define_method(rb_cTCPSocket, "initialize", tcp_init, -1); #ifdef SOCKS rb_cSOCKSSocket = rb_define_class("SOCKSSocket", rb_cTCPSocket); rb_define_global_const("SOCKSsocket", rb_cSOCKSSocket); rb_define_method(rb_cSOCKSSocket, "initialize", socks_init, 2); #ifdef SOCKS5 rb_define_method(rb_cSOCKSSocket, "close", socks_s_close, 0); #endif #endif rb_cTCPServer = rb_define_class("TCPServer", rb_cTCPSocket); rb_define_global_const("TCPserver", rb_cTCPServer); rb_define_method(rb_cTCPServer, "accept", tcp_accept, 0); rb_define_method(rb_cTCPServer, "accept_nonblock", tcp_accept_nonblock, 0); rb_define_method(rb_cTCPServer, "sysaccept", tcp_sysaccept, 0); rb_define_method(rb_cTCPServer, "initialize", tcp_svr_init, -1); rb_define_method(rb_cTCPServer, "listen", sock_listen, 1); rb_cUDPSocket = rb_define_class("UDPSocket", rb_cIPSocket); rb_define_global_const("UDPsocket", rb_cUDPSocket); rb_define_method(rb_cUDPSocket, "initialize", udp_init, -1); rb_define_method(rb_cUDPSocket, "connect", udp_connect, 2); rb_define_method(rb_cUDPSocket, "bind", udp_bind, 2); rb_define_method(rb_cUDPSocket, "send", udp_send, -1); rb_define_method(rb_cUDPSocket, "recvfrom_nonblock", udp_recvfrom_nonblock, -1); #ifdef HAVE_SYS_UN_H rb_cUNIXSocket = rb_define_class("UNIXSocket", rb_cBasicSocket); rb_define_global_const("UNIXsocket", rb_cUNIXSocket); rb_define_method(rb_cUNIXSocket, "initialize", unix_init, 1); rb_define_method(rb_cUNIXSocket, "path", unix_path, 0); rb_define_method(rb_cUNIXSocket, "addr", unix_addr, 0); rb_define_method(rb_cUNIXSocket, "peeraddr", unix_peeraddr, 0); rb_define_method(rb_cUNIXSocket, "recvfrom", unix_recvfrom, -1); rb_define_method(rb_cUNIXSocket, "send_io", unix_send_io, 1); rb_define_method(rb_cUNIXSocket, "recv_io", unix_recv_io, -1); rb_define_singleton_method(rb_cUNIXSocket, "socketpair", unix_s_socketpair, -1); rb_define_singleton_method(rb_cUNIXSocket, "pair", unix_s_socketpair, -1); rb_cUNIXServer = rb_define_class("UNIXServer", rb_cUNIXSocket); rb_define_global_const("UNIXserver", rb_cUNIXServer); rb_define_method(rb_cUNIXServer, "initialize", unix_svr_init, 1); rb_define_method(rb_cUNIXServer, "accept", unix_accept, 0); rb_define_method(rb_cUNIXServer, "accept_nonblock", unix_accept_nonblock, 0); rb_define_method(rb_cUNIXServer, "sysaccept", unix_sysaccept, 0); rb_define_method(rb_cUNIXServer, "listen", sock_listen, 1); #endif rb_cSocket = rb_define_class("Socket", rb_cBasicSocket); rb_define_method(rb_cSocket, "initialize", sock_initialize, 3); rb_define_method(rb_cSocket, "connect", sock_connect, 1); rb_define_method(rb_cSocket, "connect_nonblock", sock_connect_nonblock, 1); rb_define_method(rb_cSocket, "bind", sock_bind, 1); rb_define_method(rb_cSocket, "listen", sock_listen, 1); rb_define_method(rb_cSocket, "accept", sock_accept, 0); rb_define_method(rb_cSocket, "accept_nonblock", sock_accept_nonblock, 0); rb_define_method(rb_cSocket, "sysaccept", sock_sysaccept, 0); rb_define_method(rb_cSocket, "recvfrom", sock_recvfrom, -1); rb_define_method(rb_cSocket, "recvfrom_nonblock", sock_recvfrom_nonblock, -1); rb_define_singleton_method(rb_cSocket, "socketpair", sock_s_socketpair, 3); rb_define_singleton_method(rb_cSocket, "pair", sock_s_socketpair, 3); rb_define_singleton_method(rb_cSocket, "gethostname", sock_gethostname, 0); rb_define_singleton_method(rb_cSocket, "gethostbyname", sock_s_gethostbyname, 1); rb_define_singleton_method(rb_cSocket, "gethostbyaddr", sock_s_gethostbyaddr, -1); rb_define_singleton_method(rb_cSocket, "getservbyname", sock_s_getservbyaname, -1); rb_define_singleton_method(rb_cSocket, "getaddrinfo", sock_s_getaddrinfo, -1); rb_define_singleton_method(rb_cSocket, "getnameinfo", sock_s_getnameinfo, -1); rb_define_singleton_method(rb_cSocket, "sockaddr_in", sock_s_pack_sockaddr_in, 2); rb_define_singleton_method(rb_cSocket, "pack_sockaddr_in", sock_s_pack_sockaddr_in, 2); rb_define_singleton_method(rb_cSocket, "unpack_sockaddr_in", sock_s_unpack_sockaddr_in, 1); #ifdef HAVE_SYS_UN_H rb_define_singleton_method(rb_cSocket, "sockaddr_un", sock_s_pack_sockaddr_un, 1); rb_define_singleton_method(rb_cSocket, "pack_sockaddr_un", sock_s_pack_sockaddr_un, 1); rb_define_singleton_method(rb_cSocket, "unpack_sockaddr_un", sock_s_unpack_sockaddr_un, 1); #endif /* constants */ mConst = rb_define_module_under(rb_cSocket, "Constants"); sock_define_const("SOCK_STREAM", SOCK_STREAM); sock_define_const("SOCK_DGRAM", SOCK_DGRAM); #ifdef SOCK_RAW sock_define_const("SOCK_RAW", SOCK_RAW); #endif #ifdef SOCK_RDM sock_define_const("SOCK_RDM", SOCK_RDM); #endif #ifdef SOCK_SEQPACKET sock_define_const("SOCK_SEQPACKET", SOCK_SEQPACKET); #endif #ifdef SOCK_PACKET sock_define_const("SOCK_PACKET", SOCK_PACKET); #endif sock_define_const("AF_INET", AF_INET); #ifdef PF_INET sock_define_const("PF_INET", PF_INET); #endif #ifdef AF_UNIX sock_define_const("AF_UNIX", AF_UNIX); sock_define_const("PF_UNIX", PF_UNIX); #endif #ifdef AF_AX25 sock_define_const("AF_AX25", AF_AX25); sock_define_const("PF_AX25", PF_AX25); #endif #ifdef AF_IPX sock_define_const("AF_IPX", AF_IPX); sock_define_const("PF_IPX", PF_IPX); #endif #ifdef AF_APPLETALK sock_define_const("AF_APPLETALK", AF_APPLETALK); sock_define_const("PF_APPLETALK", PF_APPLETALK); #endif #ifdef AF_UNSPEC sock_define_const("AF_UNSPEC", AF_UNSPEC); sock_define_const("PF_UNSPEC", PF_UNSPEC); #endif #ifdef INET6 sock_define_const("AF_INET6", AF_INET6); #endif #ifdef INET6 sock_define_const("PF_INET6", PF_INET6); #endif #ifdef AF_LOCAL sock_define_const("AF_LOCAL", AF_LOCAL); #endif #ifdef PF_LOCAL sock_define_const("PF_LOCAL", PF_LOCAL); #endif #ifdef AF_IMPLINK sock_define_const("AF_IMPLINK", AF_IMPLINK); #endif #ifdef PF_IMPLINK sock_define_const("PF_IMPLINK", PF_IMPLINK); #endif #ifdef AF_PUP sock_define_const("AF_PUP", AF_PUP); #endif #ifdef PF_PUP sock_define_const("PF_PUP", PF_PUP); #endif #ifdef AF_CHAOS sock_define_const("AF_CHAOS", AF_CHAOS); #endif #ifdef PF_CHAOS sock_define_const("PF_CHAOS", PF_CHAOS); #endif #ifdef AF_NS sock_define_const("AF_NS", AF_NS); #endif #ifdef PF_NS sock_define_const("PF_NS", PF_NS); #endif #ifdef AF_ISO sock_define_const("AF_ISO", AF_ISO); #endif #ifdef PF_ISO sock_define_const("PF_ISO", PF_ISO); #endif #ifdef AF_OSI sock_define_const("AF_OSI", AF_OSI); #endif #ifdef PF_OSI sock_define_const("PF_OSI", PF_OSI); #endif #ifdef AF_ECMA sock_define_const("AF_ECMA", AF_ECMA); #endif #ifdef PF_ECMA sock_define_const("PF_ECMA", PF_ECMA); #endif #ifdef AF_DATAKIT sock_define_const("AF_DATAKIT", AF_DATAKIT); #endif #ifdef PF_DATAKIT sock_define_const("PF_DATAKIT", PF_DATAKIT); #endif #ifdef AF_CCITT sock_define_const("AF_CCITT", AF_CCITT); #endif #ifdef PF_CCITT sock_define_const("PF_CCITT", PF_CCITT); #endif #ifdef AF_SNA sock_define_const("AF_SNA", AF_SNA); #endif #ifdef PF_SNA sock_define_const("PF_SNA", PF_SNA); #endif #ifdef AF_DEC sock_define_const("AF_DEC", AF_DEC); #endif #ifdef PF_DEC sock_define_const("PF_DEC", PF_DEC); #endif #ifdef AF_DLI sock_define_const("AF_DLI", AF_DLI); #endif #ifdef PF_DLI sock_define_const("PF_DLI", PF_DLI); #endif #ifdef AF_LAT sock_define_const("AF_LAT", AF_LAT); #endif #ifdef PF_LAT sock_define_const("PF_LAT", PF_LAT); #endif #ifdef AF_HYLINK sock_define_const("AF_HYLINK", AF_HYLINK); #endif #ifdef PF_HYLINK sock_define_const("PF_HYLINK", PF_HYLINK); #endif #ifdef AF_ROUTE sock_define_const("AF_ROUTE", AF_ROUTE); #endif #ifdef PF_ROUTE sock_define_const("PF_ROUTE", PF_ROUTE); #endif #ifdef AF_LINK sock_define_const("AF_LINK", AF_LINK); #endif #ifdef PF_LINK sock_define_const("PF_LINK", PF_LINK); #endif #ifdef AF_COIP sock_define_const("AF_COIP", AF_COIP); #endif #ifdef PF_COIP sock_define_const("PF_COIP", PF_COIP); #endif #ifdef AF_CNT sock_define_const("AF_CNT", AF_CNT); #endif #ifdef PF_CNT sock_define_const("PF_CNT", PF_CNT); #endif #ifdef AF_SIP sock_define_const("AF_SIP", AF_SIP); #endif #ifdef PF_SIP sock_define_const("PF_SIP", PF_SIP); #endif #ifdef AF_NDRV sock_define_const("AF_NDRV", AF_NDRV); #endif #ifdef PF_NDRV sock_define_const("PF_NDRV", PF_NDRV); #endif #ifdef AF_ISDN sock_define_const("AF_ISDN", AF_ISDN); #endif #ifdef PF_ISDN sock_define_const("PF_ISDN", PF_ISDN); #endif #ifdef AF_NATM sock_define_const("AF_NATM", AF_NATM); #endif #ifdef PF_NATM sock_define_const("PF_NATM", PF_NATM); #endif #ifdef AF_SYSTEM sock_define_const("AF_SYSTEM", AF_SYSTEM); #endif #ifdef PF_SYSTEM sock_define_const("PF_SYSTEM", PF_SYSTEM); #endif #ifdef AF_NETBIOS sock_define_const("AF_NETBIOS", AF_NETBIOS); #endif #ifdef PF_NETBIOS sock_define_const("PF_NETBIOS", PF_NETBIOS); #endif #ifdef AF_PPP sock_define_const("AF_PPP", AF_PPP); #endif #ifdef PF_PPP sock_define_const("PF_PPP", PF_PPP); #endif #ifdef AF_ATM sock_define_const("AF_ATM", AF_ATM); #endif #ifdef PF_ATM sock_define_const("PF_ATM", PF_ATM); #endif #ifdef AF_NETGRAPH sock_define_const("AF_NETGRAPH", AF_NETGRAPH); #endif #ifdef PF_NETGRAPH sock_define_const("PF_NETGRAPH", PF_NETGRAPH); #endif #ifdef AF_MAX sock_define_const("AF_MAX", AF_MAX); #endif #ifdef PF_MAX sock_define_const("PF_MAX", PF_MAX); #endif #ifdef AF_E164 sock_define_const("AF_E164", AF_E164); #endif #ifdef PF_XTP sock_define_const("PF_XTP", PF_XTP); #endif #ifdef PF_RTIP sock_define_const("PF_RTIP", PF_RTIP); #endif #ifdef PF_PIP sock_define_const("PF_PIP", PF_PIP); #endif #ifdef PF_KEY sock_define_const("PF_KEY", PF_KEY); #endif sock_define_const("MSG_OOB", MSG_OOB); #ifdef MSG_PEEK sock_define_const("MSG_PEEK", MSG_PEEK); #endif #ifdef MSG_DONTROUTE sock_define_const("MSG_DONTROUTE", MSG_DONTROUTE); #endif #ifdef MSG_EOR sock_define_const("MSG_EOR", MSG_EOR); #endif #ifdef MSG_TRUNC sock_define_const("MSG_TRUNC", MSG_TRUNC); #endif #ifdef MSG_CTRUNC sock_define_const("MSG_CTRUNC", MSG_CTRUNC); #endif #ifdef MSG_WAITALL sock_define_const("MSG_WAITALL", MSG_WAITALL); #endif #ifdef MSG_DONTWAIT sock_define_const("MSG_DONTWAIT", MSG_DONTWAIT); #endif #ifdef MSG_EOF sock_define_const("MSG_EOF", MSG_EOF); #endif #ifdef MSG_FLUSH sock_define_const("MSG_FLUSH", MSG_FLUSH); #endif #ifdef MSG_HOLD sock_define_const("MSG_HOLD", MSG_HOLD); #endif #ifdef MSG_SEND sock_define_const("MSG_SEND", MSG_SEND); #endif #ifdef MSG_HAVEMORE sock_define_const("MSG_HAVEMORE", MSG_HAVEMORE); #endif #ifdef MSG_RCVMORE sock_define_const("MSG_RCVMORE", MSG_RCVMORE); #endif #ifdef MSG_COMPAT sock_define_const("MSG_COMPAT", MSG_COMPAT); #endif sock_define_const("SOL_SOCKET", SOL_SOCKET); #ifdef SOL_IP sock_define_const("SOL_IP", SOL_IP); #endif #ifdef SOL_IPX sock_define_const("SOL_IPX", SOL_IPX); #endif #ifdef SOL_AX25 sock_define_const("SOL_AX25", SOL_AX25); #endif #ifdef SOL_ATALK sock_define_const("SOL_ATALK", SOL_ATALK); #endif #ifdef SOL_TCP sock_define_const("SOL_TCP", SOL_TCP); #endif #ifdef SOL_UDP sock_define_const("SOL_UDP", SOL_UDP); #endif #ifdef IPPROTO_IP sock_define_const("IPPROTO_IP", IPPROTO_IP); #else sock_define_const("IPPROTO_IP", 0); #endif #ifdef IPPROTO_ICMP sock_define_const("IPPROTO_ICMP", IPPROTO_ICMP); #else sock_define_const("IPPROTO_ICMP", 1); #endif #ifdef IPPROTO_IGMP sock_define_const("IPPROTO_IGMP", IPPROTO_IGMP); #endif #ifdef IPPROTO_GGP sock_define_const("IPPROTO_GGP", IPPROTO_GGP); #endif #ifdef IPPROTO_TCP sock_define_const("IPPROTO_TCP", IPPROTO_TCP); #else sock_define_const("IPPROTO_TCP", 6); #endif #ifdef IPPROTO_EGP sock_define_const("IPPROTO_EGP", IPPROTO_EGP); #endif #ifdef IPPROTO_PUP sock_define_const("IPPROTO_PUP", IPPROTO_PUP); #endif #ifdef IPPROTO_UDP sock_define_const("IPPROTO_UDP", IPPROTO_UDP); #else sock_define_const("IPPROTO_UDP", 17); #endif #ifdef IPPROTO_IDP sock_define_const("IPPROTO_IDP", IPPROTO_IDP); #endif #ifdef IPPROTO_HELLO sock_define_const("IPPROTO_HELLO", IPPROTO_HELLO); #endif #ifdef IPPROTO_ND sock_define_const("IPPROTO_ND", IPPROTO_ND); #endif #ifdef IPPROTO_TP sock_define_const("IPPROTO_TP", IPPROTO_TP); #endif #ifdef IPPROTO_XTP sock_define_const("IPPROTO_XTP", IPPROTO_XTP); #endif #ifdef IPPROTO_EON sock_define_const("IPPROTO_EON", IPPROTO_EON); #endif #ifdef IPPROTO_BIP sock_define_const("IPPROTO_BIP", IPPROTO_BIP); #endif /**/ #ifdef IPPROTO_RAW sock_define_const("IPPROTO_RAW", IPPROTO_RAW); #else sock_define_const("IPPROTO_RAW", 255); #endif #ifdef IPPROTO_MAX sock_define_const("IPPROTO_MAX", IPPROTO_MAX); #endif /* Some port configuration */ #ifdef IPPORT_RESERVED sock_define_const("IPPORT_RESERVED", IPPORT_RESERVED); #else sock_define_const("IPPORT_RESERVED", 1024); #endif #ifdef IPPORT_USERRESERVED sock_define_const("IPPORT_USERRESERVED", IPPORT_USERRESERVED); #else sock_define_const("IPPORT_USERRESERVED", 5000); #endif /* Some reserved IP v.4 addresses */ #ifdef INADDR_ANY sock_define_const("INADDR_ANY", INADDR_ANY); #else sock_define_const("INADDR_ANY", 0x00000000); #endif #ifdef INADDR_BROADCAST sock_define_const("INADDR_BROADCAST", INADDR_BROADCAST); #else sock_define_const("INADDR_BROADCAST", 0xffffffff); #endif #ifdef INADDR_LOOPBACK sock_define_const("INADDR_LOOPBACK", INADDR_LOOPBACK); #else sock_define_const("INADDR_LOOPBACK", 0x7F000001); #endif #ifdef INADDR_UNSPEC_GROUP sock_define_const("INADDR_UNSPEC_GROUP", INADDR_UNSPEC_GROUP); #else sock_define_const("INADDR_UNSPEC_GROUP", 0xe0000000); #endif #ifdef INADDR_ALLHOSTS_GROUP sock_define_const("INADDR_ALLHOSTS_GROUP", INADDR_ALLHOSTS_GROUP); #else sock_define_const("INADDR_ALLHOSTS_GROUP", 0xe0000001); #endif #ifdef INADDR_MAX_LOCAL_GROUP sock_define_const("INADDR_MAX_LOCAL_GROUP", INADDR_MAX_LOCAL_GROUP); #else sock_define_const("INADDR_MAX_LOCAL_GROUP", 0xe00000ff); #endif #ifdef INADDR_NONE sock_define_const("INADDR_NONE", INADDR_NONE); #else sock_define_const("INADDR_NONE", 0xffffffff); #endif /* IP [gs]etsockopt options */ #ifdef IP_OPTIONS sock_define_const("IP_OPTIONS", IP_OPTIONS); #endif #ifdef IP_HDRINCL sock_define_const("IP_HDRINCL", IP_HDRINCL); #endif #ifdef IP_TOS sock_define_const("IP_TOS", IP_TOS); #endif #ifdef IP_TTL sock_define_const("IP_TTL", IP_TTL); #endif #ifdef IP_RECVOPTS sock_define_const("IP_RECVOPTS", IP_RECVOPTS); #endif #ifdef IP_RECVRETOPTS sock_define_const("IP_RECVRETOPTS", IP_RECVRETOPTS); #endif #ifdef IP_RECVDSTADDR sock_define_const("IP_RECVDSTADDR", IP_RECVDSTADDR); #endif #ifdef IP_RETOPTS sock_define_const("IP_RETOPTS", IP_RETOPTS); #endif #ifdef IP_MULTICAST_IF sock_define_const("IP_MULTICAST_IF", IP_MULTICAST_IF); #endif #ifdef IP_MULTICAST_TTL sock_define_const("IP_MULTICAST_TTL", IP_MULTICAST_TTL); #endif #ifdef IP_MULTICAST_LOOP sock_define_const("IP_MULTICAST_LOOP", IP_MULTICAST_LOOP); #endif #ifdef IP_ADD_MEMBERSHIP sock_define_const("IP_ADD_MEMBERSHIP", IP_ADD_MEMBERSHIP); #endif #ifdef IP_DROP_MEMBERSHIP sock_define_const("IP_DROP_MEMBERSHIP", IP_DROP_MEMBERSHIP); #endif #ifdef IP_DEFAULT_MULTICAST_TTL sock_define_const("IP_DEFAULT_MULTICAST_TTL", IP_DEFAULT_MULTICAST_TTL); #endif #ifdef IP_DEFAULT_MULTICAST_LOOP sock_define_const("IP_DEFAULT_MULTICAST_LOOP", IP_DEFAULT_MULTICAST_LOOP); #endif #ifdef IP_MAX_MEMBERSHIPS sock_define_const("IP_MAX_MEMBERSHIPS", IP_MAX_MEMBERSHIPS); #endif #ifdef SO_DEBUG sock_define_const("SO_DEBUG", SO_DEBUG); #endif sock_define_const("SO_REUSEADDR", SO_REUSEADDR); #ifdef SO_REUSEPORT sock_define_const("SO_REUSEPORT", SO_REUSEPORT); #endif #ifdef SO_TYPE sock_define_const("SO_TYPE", SO_TYPE); #endif #ifdef SO_ERROR sock_define_const("SO_ERROR", SO_ERROR); #endif #ifdef SO_DONTROUTE sock_define_const("SO_DONTROUTE", SO_DONTROUTE); #endif #ifdef SO_BROADCAST sock_define_const("SO_BROADCAST", SO_BROADCAST); #endif #ifdef SO_SNDBUF sock_define_const("SO_SNDBUF", SO_SNDBUF); #endif #ifdef SO_RCVBUF sock_define_const("SO_RCVBUF", SO_RCVBUF); #endif #ifdef SO_KEEPALIVE sock_define_const("SO_KEEPALIVE", SO_KEEPALIVE); #endif #ifdef SO_OOBINLINE sock_define_const("SO_OOBINLINE", SO_OOBINLINE); #endif #ifdef SO_NO_CHECK sock_define_const("SO_NO_CHECK", SO_NO_CHECK); #endif #ifdef SO_PRIORITY sock_define_const("SO_PRIORITY", SO_PRIORITY); #endif #ifdef SO_LINGER sock_define_const("SO_LINGER", SO_LINGER); #endif #ifdef SO_PASSCRED sock_define_const("SO_PASSCRED", SO_PASSCRED); #endif #ifdef SO_PEERCRED sock_define_const("SO_PEERCRED", SO_PEERCRED); #endif #ifdef SO_RCVLOWAT sock_define_const("SO_RCVLOWAT", SO_RCVLOWAT); #endif #ifdef SO_SNDLOWAT sock_define_const("SO_SNDLOWAT", SO_SNDLOWAT); #endif #ifdef SO_RCVTIMEO sock_define_const("SO_RCVTIMEO", SO_RCVTIMEO); #endif #ifdef SO_SNDTIMEO sock_define_const("SO_SNDTIMEO", SO_SNDTIMEO); #endif #ifdef SO_ACCEPTCONN sock_define_const("SO_ACCEPTCONN", SO_ACCEPTCONN); #endif #ifdef SO_USELOOPBACK sock_define_const("SO_USELOOPBACK", SO_USELOOPBACK); #endif #ifdef SO_ACCEPTFILTER sock_define_const("SO_ACCEPTFILTER", SO_ACCEPTFILTER); #endif #ifdef SO_DONTTRUNC sock_define_const("SO_DONTTRUNC", SO_DONTTRUNC); #endif #ifdef SO_WANTMORE sock_define_const("SO_WANTMORE", SO_WANTMORE); #endif #ifdef SO_WANTOOBFLAG sock_define_const("SO_WANTOOBFLAG", SO_WANTOOBFLAG); #endif #ifdef SO_NREAD sock_define_const("SO_NREAD", SO_NREAD); #endif #ifdef SO_NKE sock_define_const("SO_NKE", SO_NKE); #endif #ifdef SO_NOSIGPIPE sock_define_const("SO_NOSIGPIPE", SO_NOSIGPIPE); #endif #ifdef SO_SECURITY_AUTHENTICATION sock_define_const("SO_SECURITY_AUTHENTICATION", SO_SECURITY_AUTHENTICATION); #endif #ifdef SO_SECURITY_ENCRYPTION_TRANSPORT sock_define_const("SO_SECURITY_ENCRYPTION_TRANSPORT", SO_SECURITY_ENCRYPTION_TRANSPORT); #endif #ifdef SO_SECURITY_ENCRYPTION_NETWORK sock_define_const("SO_SECURITY_ENCRYPTION_NETWORK", SO_SECURITY_ENCRYPTION_NETWORK); #endif #ifdef SO_BINDTODEVICE sock_define_const("SO_BINDTODEVICE", SO_BINDTODEVICE); #endif #ifdef SO_ATTACH_FILTER sock_define_const("SO_ATTACH_FILTER", SO_ATTACH_FILTER); #endif #ifdef SO_DETACH_FILTER sock_define_const("SO_DETACH_FILTER", SO_DETACH_FILTER); #endif #ifdef SO_PEERNAME sock_define_const("SO_PEERNAME", SO_PEERNAME); #endif #ifdef SO_TIMESTAMP sock_define_const("SO_TIMESTAMP", SO_TIMESTAMP); #endif #ifdef SOPRI_INTERACTIVE sock_define_const("SOPRI_INTERACTIVE", SOPRI_INTERACTIVE); #endif #ifdef SOPRI_NORMAL sock_define_const("SOPRI_NORMAL", SOPRI_NORMAL); #endif #ifdef SOPRI_BACKGROUND sock_define_const("SOPRI_BACKGROUND", SOPRI_BACKGROUND); #endif #ifdef IPX_TYPE sock_define_const("IPX_TYPE", IPX_TYPE); #endif #ifdef TCP_NODELAY sock_define_const("TCP_NODELAY", TCP_NODELAY); #endif #ifdef TCP_MAXSEG sock_define_const("TCP_MAXSEG", TCP_MAXSEG); #endif #ifdef EAI_ADDRFAMILY sock_define_const("EAI_ADDRFAMILY", EAI_ADDRFAMILY); #endif #ifdef EAI_AGAIN sock_define_const("EAI_AGAIN", EAI_AGAIN); #endif #ifdef EAI_BADFLAGS sock_define_const("EAI_BADFLAGS", EAI_BADFLAGS); #endif #ifdef EAI_FAIL sock_define_const("EAI_FAIL", EAI_FAIL); #endif #ifdef EAI_FAMILY sock_define_const("EAI_FAMILY", EAI_FAMILY); #endif #ifdef EAI_MEMORY sock_define_const("EAI_MEMORY", EAI_MEMORY); #endif #ifdef EAI_NODATA sock_define_const("EAI_NODATA", EAI_NODATA); #endif #ifdef EAI_NONAME sock_define_const("EAI_NONAME", EAI_NONAME); #endif #ifdef EAI_SERVICE sock_define_const("EAI_SERVICE", EAI_SERVICE); #endif #ifdef EAI_SOCKTYPE sock_define_const("EAI_SOCKTYPE", EAI_SOCKTYPE); #endif #ifdef EAI_SYSTEM sock_define_const("EAI_SYSTEM", EAI_SYSTEM); #endif #ifdef EAI_BADHINTS sock_define_const("EAI_BADHINTS", EAI_BADHINTS); #endif #ifdef EAI_PROTOCOL sock_define_const("EAI_PROTOCOL", EAI_PROTOCOL); #endif #ifdef EAI_MAX sock_define_const("EAI_MAX", EAI_MAX); #endif #ifdef AI_PASSIVE sock_define_const("AI_PASSIVE", AI_PASSIVE); #endif #ifdef AI_CANONNAME sock_define_const("AI_CANONNAME", AI_CANONNAME); #endif #ifdef AI_NUMERICHOST sock_define_const("AI_NUMERICHOST", AI_NUMERICHOST); #endif #ifdef AI_MASK sock_define_const("AI_MASK", AI_MASK); #endif #ifdef AI_ALL sock_define_const("AI_ALL", AI_ALL); #endif #ifdef AI_V4MAPPED_CFG sock_define_const("AI_V4MAPPED_CFG", AI_V4MAPPED_CFG); #endif #ifdef AI_ADDRCONFIG sock_define_const("AI_ADDRCONFIG", AI_ADDRCONFIG); #endif #ifdef AI_V4MAPPED sock_define_const("AI_V4MAPPED", AI_V4MAPPED); #endif #ifdef AI_DEFAULT sock_define_const("AI_DEFAULT", AI_DEFAULT); #endif #ifdef NI_MAXHOST sock_define_const("NI_MAXHOST", NI_MAXHOST); #endif #ifdef NI_MAXSERV sock_define_const("NI_MAXSERV", NI_MAXSERV); #endif #ifdef NI_NOFQDN sock_define_const("NI_NOFQDN", NI_NOFQDN); #endif #ifdef NI_NUMERICHOST sock_define_const("NI_NUMERICHOST", NI_NUMERICHOST); #endif #ifdef NI_NAMEREQD sock_define_const("NI_NAMEREQD", NI_NAMEREQD); #endif #ifdef NI_NUMERICSERV sock_define_const("NI_NUMERICSERV", NI_NUMERICSERV); #endif #ifdef NI_DGRAM sock_define_const("NI_DGRAM", NI_DGRAM); #endif #ifdef SHUT_RD sock_define_const("SHUT_RD", SHUT_RD); #else sock_define_const("SHUT_RD", 0); #endif #ifdef SHUT_WR sock_define_const("SHUT_WR", SHUT_WR); #else sock_define_const("SHUT_WR", 1); #endif #ifdef SHUT_RDWR sock_define_const("SHUT_RDWR", SHUT_RDWR); #else sock_define_const("SHUT_RDWR", 2); #endif } ================================================ FILE: ext/socket/sockport.h ================================================ /************************************************ sockport.h - $Author$ $Date$ created at: Fri Apr 30 23:19:34 JST 1999 ************************************************/ #ifndef SOCKPORT_H #define SOCKPORT_H #ifndef SA_LEN # ifdef HAVE_SA_LEN # define SA_LEN(sa) (sa)->sa_len # else # ifdef INET6 # define SA_LEN(sa) \ (((sa)->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) \ : sizeof(struct sockaddr)) # else /* by tradition, sizeof(struct sockaddr) covers most of the sockaddrs */ # define SA_LEN(sa) (sizeof(struct sockaddr)) # endif # endif #endif #ifdef HAVE_SA_LEN # define SET_SA_LEN(sa, len) (sa)->sa_len = (len) #else # define SET_SA_LEN(sa, len) (len) #endif #ifdef HAVE_SIN_LEN # define SIN_LEN(si) (si)->sin_len # define SET_SIN_LEN(si,len) (si)->sin_len = (len) #else # define SIN_LEN(si) sizeof(struct sockaddr_in) # define SET_SIN_LEN(si,len) #endif #ifndef IN_MULTICAST # define IN_CLASSD(i) (((long)(i) & 0xf0000000) == 0xe0000000) # define IN_MULTICAST(i) IN_CLASSD(i) #endif #ifndef IN_EXPERIMENTAL # define IN_EXPERIMENTAL(i) ((((long)(i)) & 0xe0000000) == 0xe0000000) #endif #ifndef IN_CLASSA_NSHIFT # define IN_CLASSA_NSHIFT 24 #endif #ifndef IN_LOOPBACKNET # define IN_LOOPBACKNET 127 #endif #ifndef AF_UNSPEC # define AF_UNSPEC 0 #endif #ifndef PF_UNSPEC # define PF_UNSPEC AF_UNSPEC #endif #ifndef PF_INET # define PF_INET AF_INET #endif #if defined(HOST_NOT_FOUND) && !defined(h_errno) && !defined(__CYGWIN__) extern int h_errno; #endif #endif ================================================ FILE: ext/stringio/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/stringio/README ================================================ -*- rd -*- $Author$ $Date$ =begin = StringIO Pseudo (({IO})) class from/to (({String})). This library is based on MoonWolf version written in Ruby. Thanks a lot. = Differences to (({IO})) * not implemented: (({fcntl})), (({reopen})). * (({fileno})) returns nil. * (({pos=})) returns new position, not 0. * (({ungetc})) does nothing at start of the string. =end ================================================ FILE: ext/stringio/depend ================================================ stringio.o: stringio.c $(hdrdir)/ruby.h $(topdir)/config.h \ $(hdrdir)/defines.h $(hdrdir)/intern.h $(hdrdir)/rubyio.h ================================================ FILE: ext/stringio/extconf.rb ================================================ require 'mkmf' create_makefile('stringio') ================================================ FILE: ext/stringio/stringio.c ================================================ /********************************************************************** stringio.c - $Author$ $Date$ $RoughId: stringio.c,v 1.13 2002/03/14 03:24:18 nobu Exp $ created at: Tue Feb 19 04:10:38 JST 2002 All the files in this distribution are covered under the Ruby's license (see the file COPYING). **********************************************************************/ #include "ruby.h" #include "rubyio.h" #include "re.h" #if defined(HAVE_FCNTL_H) || defined(_WIN32) #include #elif defined(HAVE_SYS_FCNTL_H) #include #endif #define STRIO_EOF FMODE_SYNC struct StringIO { VALUE string; long pos; long lineno; int flags; int count; }; static struct StringIO* strio_alloc _((void)); static void strio_mark _((struct StringIO *)); static void strio_free _((struct StringIO *)); static struct StringIO* check_strio _((VALUE)); static struct StringIO* get_strio _((VALUE)); static struct StringIO* readable _((struct StringIO *)); static struct StringIO* writable _((struct StringIO *)); static void check_modifiable _((struct StringIO *)); #define IS_STRIO(obj) (RDATA(obj)->dmark == (RUBY_DATA_FUNC)strio_mark) #define error_inval(msg) (errno = EINVAL, rb_sys_fail(msg)) static struct StringIO * strio_alloc() { struct StringIO *ptr = ALLOC(struct StringIO); ptr->string = Qnil; ptr->pos = 0; ptr->lineno = 0; ptr->flags = 0; ptr->count = 1; return ptr; } static void strio_mark(ptr) struct StringIO *ptr; { if (ptr) { rb_gc_mark(ptr->string); } } static void strio_free(ptr) struct StringIO *ptr; { if (--ptr->count <= 0) { xfree(ptr); } } static struct StringIO* check_strio(self) VALUE self; { Check_Type(self, T_DATA); if (!IS_STRIO(self)) { rb_raise(rb_eTypeError, "wrong argument type %s (expected StringIO)", rb_class2name(CLASS_OF(self))); } return DATA_PTR(self); } static struct StringIO* get_strio(self) VALUE self; { struct StringIO *ptr = check_strio(self); if (!ptr) { rb_raise(rb_eIOError, "uninitialized stream"); } return ptr; } #define StringIO(obj) get_strio(obj) #define CLOSED(ptr) (!((ptr)->flags & FMODE_READWRITE)) #define READABLE(ptr) ((ptr)->flags & FMODE_READABLE) #define WRITABLE(ptr) ((ptr)->flags & FMODE_WRITABLE) static struct StringIO* readable(ptr) struct StringIO *ptr; { if (!READABLE(ptr)) { rb_raise(rb_eIOError, "not opened for reading"); } return ptr; } static struct StringIO* writable(ptr) struct StringIO *ptr; { if (!WRITABLE(ptr)) { rb_raise(rb_eIOError, "not opened for writing"); } if (!OBJ_TAINTED(ptr->string)) { rb_secure(4); } return ptr; } static void check_modifiable(ptr) struct StringIO *ptr; { if (OBJ_FROZEN(ptr->string)) { rb_raise(rb_eIOError, "not modifiable string"); } } static VALUE strio_s_allocate _((VALUE)); static VALUE strio_s_open _((int, VALUE *, VALUE)); static void strio_init _((int, VALUE *, struct StringIO *)); static VALUE strio_initialize _((int, VALUE *, VALUE)); static VALUE strio_finalize _((VALUE)); static VALUE strio_self _((VALUE)); static VALUE strio_false _((VALUE)); static VALUE strio_nil _((VALUE)); static VALUE strio_0 _((VALUE)); static VALUE strio_first _((VALUE, VALUE)); static VALUE strio_unimpl _((int, VALUE *, VALUE)); static VALUE strio_get_string _((VALUE)); static VALUE strio_set_string _((VALUE, VALUE)); static VALUE strio_close _((VALUE)); static VALUE strio_close_read _((VALUE)); static VALUE strio_close_write _((VALUE)); static VALUE strio_closed _((VALUE)); static VALUE strio_closed_read _((VALUE)); static VALUE strio_closed_write _((VALUE)); static VALUE strio_eof _((VALUE)); static VALUE strio_get_lineno _((VALUE)); static VALUE strio_set_lineno _((VALUE, VALUE)); static VALUE strio_get_pos _((VALUE)); static VALUE strio_set_pos _((VALUE, VALUE)); static VALUE strio_rewind _((VALUE)); static VALUE strio_seek _((int, VALUE *, VALUE)); static VALUE strio_get_sync _((VALUE)); static VALUE strio_each_byte _((VALUE)); static VALUE strio_each_char _((VALUE)); static VALUE strio_getc _((VALUE)); static VALUE strio_ungetc _((VALUE, VALUE)); static VALUE strio_readchar _((VALUE)); static VALUE strio_getline _((int, VALUE *, struct StringIO *)); static VALUE strio_gets _((int, VALUE *, VALUE)); static VALUE strio_readline _((int, VALUE *, VALUE)); static VALUE strio_each _((int, VALUE *, VALUE)); static VALUE strio_readlines _((int, VALUE *, VALUE)); static VALUE strio_write _((VALUE, VALUE)); static VALUE strio_putc _((VALUE, VALUE)); static VALUE strio_read _((int, VALUE *, VALUE)); static VALUE strio_size _((VALUE)); static VALUE strio_truncate _((VALUE, VALUE)); void Init_stringio _((void)); /* Boyer-Moore search: copied from regex.c */ static void bm_init_skip _((long *, const char *, long)); static long bm_search _((const char *, long, const char *, long, const long *)); static VALUE strio_s_allocate(klass) VALUE klass; { return Data_Wrap_Struct(klass, strio_mark, strio_free, 0); } /* * call-seq: StringIO.open(string=""[, mode]) {|strio| ...} * * Equivalent to StringIO.new except that when it is called with a block, it * yields with the new instance and closes it, and returns the result which * returned from the block. */ static VALUE strio_s_open(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { VALUE obj = rb_class_new_instance(argc, argv, klass); if (!rb_block_given_p()) return obj; return rb_ensure(rb_yield, obj, strio_finalize, obj); } /* * call-seq: StringIO.new(string=""[, mode]) * * Creates new StringIO instance from with _string_ and _mode_. */ static VALUE strio_initialize(argc, argv, self) int argc; VALUE *argv; VALUE self; { struct StringIO *ptr = check_strio(self); if (!ptr) { DATA_PTR(self) = ptr = strio_alloc(); } rb_call_super(0, 0); strio_init(argc, argv, ptr); return self; } static void strio_init(argc, argv, ptr) int argc; VALUE *argv; struct StringIO *ptr; { VALUE string, mode; int trunc = Qfalse; switch (rb_scan_args(argc, argv, "02", &string, &mode)) { case 2: if (FIXNUM_P(mode)) { int flags = FIX2INT(mode); ptr->flags = rb_io_modenum_flags(flags); trunc = flags & O_TRUNC; } else { const char *m = StringValueCStr(mode); ptr->flags = rb_io_mode_flags(m); trunc = *m == 'w'; } StringValue(string); if ((ptr->flags & FMODE_WRITABLE) && OBJ_FROZEN(string)) { errno = EACCES; rb_sys_fail(0); } if (trunc) { rb_str_resize(string, 0); } break; case 1: StringValue(string); ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE; break; case 0: string = rb_str_new("", 0); ptr->flags = FMODE_READWRITE; break; } ptr->string = string; ptr->pos = 0; ptr->lineno = 0; } static VALUE strio_finalize(self) VALUE self; { struct StringIO *ptr = StringIO(self); ptr->string = Qnil; ptr->flags &= ~FMODE_READWRITE; return self; } /* * Returns +false+. Just for compatibility to IO. */ static VALUE strio_false(self) VALUE self; { StringIO(self); return Qfalse; } /* * Returns +nil+. Just for compatibility to IO. */ static VALUE strio_nil(self) VALUE self; { StringIO(self); return Qnil; } /* * Returns *strio* itself. Just for compatibility to IO. */ static VALUE strio_self(self) VALUE self; { StringIO(self); return self; } /* * Returns 0. Just for compatibility to IO. */ static VALUE strio_0(self) VALUE self; { StringIO(self); return INT2FIX(0); } /* * Returns the argument unchanged. Just for compatibility to IO. */ static VALUE strio_first(self, arg) VALUE self, arg; { StringIO(self); return arg; } /* * Raises NotImplementedError. */ static VALUE strio_unimpl(argc, argv, self) int argc; VALUE *argv; VALUE self; { StringIO(self); rb_notimplement(); return Qnil; /* not reached */ } /* * call-seq: strio.string -> string * * Returns underlying String object, the subject of IO. */ static VALUE strio_get_string(self) VALUE self; { return StringIO(self)->string; } /* * call-seq: * strio.string = string -> string * * Changes underlying String object, the subject of IO. */ static VALUE strio_set_string(self, string) VALUE self, string; { struct StringIO *ptr = StringIO(self); if (!OBJ_TAINTED(self)) rb_secure(4); ptr->flags &= ~FMODE_READWRITE; StringValue(string); ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE; ptr->pos = 0; ptr->lineno = 0; return ptr->string = string; } /* * call-seq: * strio.close -> nil * * Closes strio. The *strio* is unavailable for any further data * operations; an +IOError+ is raised if such an attempt is made. */ static VALUE strio_close(self) VALUE self; { struct StringIO *ptr = StringIO(self); if (CLOSED(ptr)) { rb_raise(rb_eIOError, "closed stream"); } ptr->flags &= ~FMODE_READWRITE; return Qnil; } /* * call-seq: * strio.close_read -> nil * * Closes the read end of a StringIO. Will raise an +IOError+ if the * *strio* is not readable. */ static VALUE strio_close_read(self) VALUE self; { struct StringIO *ptr = StringIO(self); if (!READABLE(ptr)) { rb_raise(rb_eIOError, "closing non-duplex IO for reading"); } ptr->flags &= ~FMODE_READABLE; return Qnil; } /* * call-seq: * strio.close_write -> nil * * Closes the write end of a StringIO. Will raise an +IOError+ if the * *strio* is not writeable. */ static VALUE strio_close_write(self) VALUE self; { struct StringIO *ptr = StringIO(self); if (!WRITABLE(ptr)) { rb_raise(rb_eIOError, "closing non-duplex IO for writing"); } ptr->flags &= ~FMODE_WRITABLE; return Qnil; } /* * call-seq: * strio.closed? -> true or false * * Returns +true+ if *strio* is completely closed, +false+ otherwise. */ static VALUE strio_closed(self) VALUE self; { struct StringIO *ptr = StringIO(self); if (!CLOSED(ptr)) return Qfalse; return Qtrue; } /* * call-seq: * strio.closed_read? -> true or false * * Returns +true+ if *strio* is not readable, +false+ otherwise. */ static VALUE strio_closed_read(self) VALUE self; { struct StringIO *ptr = StringIO(self); if (READABLE(ptr)) return Qfalse; return Qtrue; } /* * call-seq: * strio.closed_write? -> true or false * * Returns +true+ if *strio* is not writable, +false+ otherwise. */ static VALUE strio_closed_write(self) VALUE self; { struct StringIO *ptr = StringIO(self); if (WRITABLE(ptr)) return Qfalse; return Qtrue; } /* * call-seq: * strio.eof -> true or false * strio.eof? -> true or false * * Returns true if *strio* is at end of file. The stringio must be * opened for reading or an +IOError+ will be raised. */ static VALUE strio_eof(self) VALUE self; { struct StringIO *ptr = readable(StringIO(self)); if (ptr->pos < RSTRING(ptr->string)->len) return Qfalse; return Qtrue; } /* :nodoc: */ static VALUE strio_copy(copy, orig) VALUE copy, orig; { struct StringIO *ptr; orig = rb_convert_type(orig, T_DATA, "StringIO", "to_strio"); if (copy == orig) return copy; ptr = StringIO(orig); if (check_strio(copy)) { strio_free(DATA_PTR(copy)); } DATA_PTR(copy) = ptr; OBJ_INFECT(copy, orig); ++ptr->count; return copy; } /* * call-seq: * strio.lineno -> integer * * Returns the current line number in *strio*. The stringio must be * opened for reading. +lineno+ counts the number of times +gets+ is * called, rather than the number of newlines encountered. The two * values will differ if +gets+ is called with a separator other than * newline. See also the $. variable. */ static VALUE strio_get_lineno(self) VALUE self; { return LONG2NUM(StringIO(self)->lineno); } /* * call-seq: * strio.lineno = integer -> integer * * Manually sets the current line number to the given value. * $. is updated only on the next read. */ static VALUE strio_set_lineno(self, lineno) VALUE self, lineno; { StringIO(self)->lineno = NUM2LONG(lineno); return lineno; } /* call-seq: strio.binmode -> true */ #define strio_binmode strio_self /* call-seq: strio.fcntl */ #define strio_fcntl strio_unimpl /* call-seq: strio.flush -> strio */ #define strio_flush strio_self /* call-seq: strio.fsync -> 0 */ #define strio_fsync strio_0 /* * call-seq: * strio.reopen(other_StrIO) -> strio * strio.reopen(string, mode) -> strio * * Reinitializes *strio* with the given other_StrIO or _string_ * and _mode_ (see StringIO#new). */ static VALUE strio_reopen(argc, argv, self) int argc; VALUE *argv; VALUE self; { if (!OBJ_TAINTED(self)) rb_secure(4); if (argc == 1 && TYPE(*argv) != T_STRING) { return strio_copy(self, *argv); } strio_init(argc, argv, StringIO(self)); return self; } /* * call-seq: * strio.pos -> integer * strio.tell -> integer * * Returns the current offset (in bytes) of *strio*. */ static VALUE strio_get_pos(self) VALUE self; { return LONG2NUM(StringIO(self)->pos); } /* * call-seq: * strio.pos = integer -> integer * * Seeks to the given position (in bytes) in *strio*. */ static VALUE strio_set_pos(self, pos) VALUE self; VALUE pos; { struct StringIO *ptr = StringIO(self); long p = NUM2LONG(pos); if (p < 0) { error_inval(0); } ptr->pos = p; ptr->flags &= ~STRIO_EOF; return pos; } /* * call-seq: * strio.rewind -> 0 * * Positions *strio* to the beginning of input, resetting * +lineno+ to zero. */ static VALUE strio_rewind(self) VALUE self; { struct StringIO *ptr = StringIO(self); ptr->pos = 0; ptr->lineno = 0; ptr->flags &= ~STRIO_EOF; return INT2FIX(0); } /* * call-seq: * strio.seek(amount, whence=SEEK_SET) -> 0 * * Seeks to a given offset _amount_ in the stream according to * the value of _whence_ (see IO#seek). */ static VALUE strio_seek(argc, argv, self) int argc; VALUE *argv; VALUE self; { VALUE whence; struct StringIO *ptr = StringIO(self); long offset; rb_scan_args(argc, argv, "11", NULL, &whence); offset = NUM2LONG(argv[0]); if (CLOSED(ptr)) { rb_raise(rb_eIOError, "closed stream"); } switch (NIL_P(whence) ? 0 : NUM2LONG(whence)) { case 0: break; case 1: offset += ptr->pos; break; case 2: offset += RSTRING(ptr->string)->len; break; default: error_inval("invalid whence"); } if (offset < 0) { error_inval(0); } ptr->pos = offset; ptr->flags &= ~STRIO_EOF; return INT2FIX(0); } /* * call-seq: * strio.sync -> true * * Returns +true+ always. */ static VALUE strio_get_sync(self) VALUE self; { StringIO(self); return Qtrue; } /* call-seq: strio.sync = boolean -> boolean */ #define strio_set_sync strio_first #define strio_tell strio_get_pos /* * call-seq: * strio.each_byte {|byte| block } -> strio * * See IO#each_byte. */ static VALUE strio_each_byte(self) VALUE self; { struct StringIO *ptr = readable(StringIO(self)); RETURN_ENUMERATOR(self, 0, 0); while (ptr->pos < RSTRING_LEN(ptr->string)) { char c = RSTRING_PTR(ptr->string)[ptr->pos++]; rb_yield(CHR2FIX(c)); } return self; } /* * call-seq: * strio.getc -> fixnum or nil * * See IO#getc. */ static VALUE strio_getc(self) VALUE self; { struct StringIO *ptr = readable(StringIO(self)); int c; if (ptr->pos >= RSTRING(ptr->string)->len) { ptr->flags |= STRIO_EOF; return Qnil; } c = RSTRING(ptr->string)->ptr[ptr->pos++]; return CHR2FIX(c); } static void strio_extend(ptr, pos, len) struct StringIO *ptr; long pos, len; { long olen; check_modifiable(ptr); olen = RSTRING(ptr->string)->len; if (pos + len > olen) { rb_str_resize(ptr->string, pos + len); if (pos > olen) MEMZERO(RSTRING(ptr->string)->ptr + olen, char, pos - olen); } else { rb_str_modify(ptr->string); } } /* * call-seq: * strio.ungetc(integer) -> nil * * Pushes back one character (passed as a parameter) onto *strio* * such that a subsequent buffered read will return it. Pushing back * behind the beginning of the buffer string is not possible. Nothing * will be done if such an attempt is made. * In other case, there is no limitation for multiple pushbacks. */ static VALUE strio_ungetc(self, ch) VALUE self, ch; { struct StringIO *ptr = readable(StringIO(self)); int cc = NUM2INT(ch); long len, pos = ptr->pos; if (cc != EOF) { len = RSTRING(ptr->string)->len; if (pos == 0) { char *p; rb_str_resize(ptr->string, len + 1); p = RSTRING(ptr->string)->ptr; memmove(p + 1, p, len); } else { if (len < pos-- || (unsigned char)RSTRING(ptr->string)->ptr[pos] != (unsigned char)cc) { strio_extend(ptr, pos, 1); } --ptr->pos; } RSTRING(ptr->string)->ptr[pos] = cc; OBJ_INFECT(ptr->string, self); ptr->flags &= ~STRIO_EOF; } return Qnil; } /* * call-seq: * strio.readchar -> fixnum * * See IO#readchar. */ static VALUE strio_readchar(self) VALUE self; { VALUE c = strio_getc(self); if (NIL_P(c)) rb_eof_error(); return c; } /* * call-seq: * strio.each_char {|char| block } -> strio * * See IO#each_char. */ static VALUE strio_each_char(self) VALUE self; { struct StringIO *sio; VALUE str; const char *ptr; size_t len; RETURN_ENUMERATOR(self, 0, 0); sio = readable(StringIO(self)); str = sio->string; ptr = RSTRING_PTR(str); len = RSTRING_LEN(str); while (sio->pos < len) { int pos = sio->pos; char c = ptr[pos]; int n = mbclen(c); if (len < pos + n) n = len - pos; sio->pos += n; rb_yield(rb_str_substr(str, pos, n)); } return self; } static void bm_init_skip(skip, pat, m) long *skip; const char *pat; long m; { int c; for (c = 0; c < (1 << CHAR_BIT); c++) { skip[c] = m; } while (--m) { skip[(unsigned char)*pat++] = m; } } static long bm_search(little, llen, big, blen, skip) const char *little; long llen; const char *big; long blen; const long *skip; { long i, j, k; i = llen - 1; while (i < blen) { k = i; j = llen - 1; while (j >= 0 && big[k] == little[j]) { k--; j--; } if (j < 0) return k + 1; i += skip[(unsigned char)big[i]]; } return -1; } static VALUE strio_getline(argc, argv, ptr) int argc; VALUE *argv; struct StringIO *ptr; { const char *s, *e, *p; long n; VALUE str; if (argc == 0) { str = rb_rs; } else { rb_scan_args(argc, argv, "1", &str); if (!NIL_P(str)) StringValue(str); } if (ptr->pos >= (n = RSTRING(ptr->string)->len)) { ptr->flags |= STRIO_EOF; return Qnil; } s = RSTRING(ptr->string)->ptr; e = s + RSTRING(ptr->string)->len; s += ptr->pos; if (NIL_P(str)) { str = rb_str_substr(ptr->string, ptr->pos, e - s); } else if ((n = RSTRING(str)->len) == 0) { p = s; while (*p == '\n') { if (++p == e) { ptr->flags |= STRIO_EOF; return Qnil; } } s = p; while ((p = memchr(p, '\n', e - p)) && (p != e)) { if (*++p == '\n') { e = p; break; } } str = rb_str_substr(ptr->string, s - RSTRING(ptr->string)->ptr, e - s); } else if (n == 1) { if ((p = memchr(s, RSTRING(str)->ptr[0], e - s)) != 0) { e = p + 1; } str = rb_str_substr(ptr->string, ptr->pos, e - s); } else { if (n < e - s) { if (e - s < 1024) { for (p = s; p + n <= e; ++p) { if (MEMCMP(p, RSTRING(str)->ptr, char, n) == 0) { e = p + n; break; } } } else { long skip[1 << CHAR_BIT], pos; p = RSTRING(str)->ptr; bm_init_skip(skip, p, n); if ((pos = bm_search(p, n, s, e - s, skip)) >= 0) { e = s + pos + n; } } } str = rb_str_substr(ptr->string, ptr->pos, e - s); } ptr->pos = e - RSTRING(ptr->string)->ptr; ptr->lineno++; return str; } /* * call-seq: * strio.gets(sep_string=$/) -> string or nil * * See IO#gets. */ static VALUE strio_gets(argc, argv, self) int argc; VALUE *argv; VALUE self; { VALUE str = strio_getline(argc, argv, readable(StringIO(self))); rb_lastline_set(str); return str; } /* * call-seq: * strio.readline(sep_string=$/) -> string * * See IO#readline. */ static VALUE strio_readline(argc, argv, self) int argc; VALUE *argv; VALUE self; { VALUE line = strio_gets(argc, argv, self); if (NIL_P(line)) rb_eof_error(); return line; } /* * call-seq: * strio.each(sep_string=$/) {|line| block } -> strio * strio.each_line(sep_string=$/) {|line| block } -> strio * * See IO#each. */ static VALUE strio_each(argc, argv, self) int argc; VALUE *argv; VALUE self; { struct StringIO *ptr = StringIO(self); VALUE line; RETURN_ENUMERATOR(self, argc, argv); while (!NIL_P(line = strio_getline(argc, argv, readable(ptr)))) { rb_yield(line); } return self; } /* * call-seq: * strio.readlines(sep_string=$/) -> array * * See IO#readlines. */ static VALUE strio_readlines(argc, argv, self) int argc; VALUE *argv; VALUE self; { struct StringIO *ptr = StringIO(self); VALUE ary = rb_ary_new(), line; while (!NIL_P(line = strio_getline(argc, argv, readable(ptr)))) { rb_ary_push(ary, line); } return ary; } /* * call-seq: * strio.write(string) -> integer * strio.syswrite(string) -> integer * * Appends the given string to the underlying buffer string of *strio*. * The stream must be opened for writing. If the argument is not a * string, it will be converted to a string using to_s. * Returns the number of bytes written. See IO#write. */ static VALUE strio_write(self, str) VALUE self, str; { struct StringIO *ptr = writable(StringIO(self)); long len, olen; if (TYPE(str) != T_STRING) str = rb_obj_as_string(str); len = RSTRING(str)->len; if (!len) return INT2FIX(0); check_modifiable(ptr); olen = RSTRING(ptr->string)->len; if (ptr->flags & FMODE_APPEND) { ptr->pos = olen; } if (ptr->pos == olen) { rb_str_cat(ptr->string, RSTRING(str)->ptr, len); } else { strio_extend(ptr, ptr->pos, len); rb_str_update(ptr->string, ptr->pos, len, str); } OBJ_INFECT(ptr->string, self); ptr->pos += len; return LONG2NUM(len); } /* * call-seq: * strio << obj -> strio * * See IO#<<. */ #define strio_addstr rb_io_addstr /* * call-seq: * strio.print() -> nil * strio.print(obj, ...) -> nil * * See IO#print. */ #define strio_print rb_io_print /* * call-seq: * strio.printf(format_string [, obj, ...] ) -> nil * * See IO#printf. */ #define strio_printf rb_io_printf /* * call-seq: * strio.putc(obj) -> obj * * See IO#putc. */ static VALUE strio_putc(self, ch) VALUE self, ch; { struct StringIO *ptr = writable(StringIO(self)); int c = NUM2CHR(ch); long olen; check_modifiable(ptr); olen = RSTRING(ptr->string)->len; if (ptr->flags & FMODE_APPEND) { ptr->pos = olen; } strio_extend(ptr, ptr->pos, 1); RSTRING(ptr->string)->ptr[ptr->pos++] = c; OBJ_INFECT(ptr->string, self); return ch; } /* * call-seq: * strio.puts(obj, ...) -> nil * * See IO#puts. */ #define strio_puts rb_io_puts /* * call-seq: * strio.read([length [, buffer]]) -> string, buffer, or nil * * See IO#read. */ static VALUE strio_read(argc, argv, self) int argc; VALUE *argv; VALUE self; { struct StringIO *ptr = readable(StringIO(self)); VALUE str = Qnil; long len, olen; switch (argc) { case 2: str = argv[1]; StringValue(str); rb_str_modify(str); case 1: if (!NIL_P(argv[0])) { len = olen = NUM2LONG(argv[0]); if (len < 0) { rb_raise(rb_eArgError, "negative length %ld given", len); } if (len > 0 && ptr->pos >= RSTRING(ptr->string)->len) { ptr->flags |= STRIO_EOF; if (!NIL_P(str)) rb_str_resize(str, 0); return Qnil; } else if (ptr->flags & STRIO_EOF) { if (!NIL_P(str)) rb_str_resize(str, 0); return Qnil; } break; } /* fall through */ case 0: olen = -1; len = RSTRING(ptr->string)->len; if (len <= ptr->pos) { ptr->flags |= STRIO_EOF; if (NIL_P(str)) { str = rb_str_new(0, 0); } else { rb_str_resize(str, 0); } return str; } else { len -= ptr->pos; } break; default: rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc); } if (NIL_P(str)) { str = rb_str_substr(ptr->string, ptr->pos, len); } else { long rest = RSTRING(ptr->string)->len - ptr->pos; if (len > rest) len = rest; rb_str_resize(str, len); MEMCPY(RSTRING(str)->ptr, RSTRING(ptr->string)->ptr + ptr->pos, char, len); } if (NIL_P(str)) { if (!(ptr->flags & STRIO_EOF)) str = rb_str_new(0, 0); len = 0; } else { ptr->pos += len = RSTRING(str)->len; } if (olen < 0 || olen > len) ptr->flags |= STRIO_EOF; return str; } /* * call-seq: * strio.sysread(integer[, outbuf]) -> string * * Similar to #read, but raises +EOFError+ at end of string instead of * returning +nil+, as well as IO#sysread does. */ static VALUE strio_sysread(argc, argv, self) int argc; VALUE *argv; VALUE self; { VALUE val = strio_read(argc, argv, self); if (NIL_P(val) || RSTRING(val)->len == 0) { rb_eof_error(); } return val; } #define strio_syswrite strio_write /* call-seq: strio.path -> nil */ #define strio_path strio_nil /* * call-seq: * strio.isatty -> nil * strio.tty? -> nil * */ #define strio_isatty strio_false /* call-seq: strio.pid -> nil */ #define strio_pid strio_nil /* call-seq: strio.fileno -> nil */ #define strio_fileno strio_nil /* * call-seq: * strio.size -> integer * * Returns the size of the buffer string. */ static VALUE strio_size(self) VALUE self; { VALUE string = StringIO(self)->string; if (NIL_P(string)) { rb_raise(rb_eIOError, "not opened"); } return ULONG2NUM(RSTRING(string)->len); } /* * call-seq: * strio.truncate(integer) -> 0 * * Truncates the buffer string to at most _integer_ bytes. The *strio* * must be opened for writing. */ static VALUE strio_truncate(self, len) VALUE self, len; { VALUE string = writable(StringIO(self))->string; long l = NUM2LONG(len); long plen = RSTRING(string)->len; if (l < 0) { error_inval("negative legnth"); } rb_str_resize(string, l); if (plen < l) { MEMZERO(RSTRING(string)->ptr + plen, char, l - plen); } return len; } /* * Pseudo I/O on String object. */ void Init_stringio() { VALUE StringIO = rb_define_class("StringIO", rb_cData); rb_include_module(StringIO, rb_mEnumerable); rb_define_alloc_func(StringIO, strio_s_allocate); rb_define_singleton_method(StringIO, "open", strio_s_open, -1); rb_define_method(StringIO, "initialize", strio_initialize, -1); rb_define_method(StringIO, "initialize_copy", strio_copy, 1); rb_define_method(StringIO, "reopen", strio_reopen, -1); rb_define_method(StringIO, "string", strio_get_string, 0); rb_define_method(StringIO, "string=", strio_set_string, 1); rb_define_method(StringIO, "lineno", strio_get_lineno, 0); rb_define_method(StringIO, "lineno=", strio_set_lineno, 1); rb_define_method(StringIO, "binmode", strio_binmode, 0); rb_define_method(StringIO, "close", strio_close, 0); rb_define_method(StringIO, "close_read", strio_close_read, 0); rb_define_method(StringIO, "close_write", strio_close_write, 0); rb_define_method(StringIO, "closed?", strio_closed, 0); rb_define_method(StringIO, "closed_read?", strio_closed_read, 0); rb_define_method(StringIO, "closed_write?", strio_closed_write, 0); rb_define_method(StringIO, "eof", strio_eof, 0); rb_define_method(StringIO, "eof?", strio_eof, 0); rb_define_method(StringIO, "fcntl", strio_fcntl, -1); rb_define_method(StringIO, "flush", strio_flush, 0); rb_define_method(StringIO, "fsync", strio_fsync, 0); rb_define_method(StringIO, "pos", strio_get_pos, 0); rb_define_method(StringIO, "pos=", strio_set_pos, 1); rb_define_method(StringIO, "rewind", strio_rewind, 0); rb_define_method(StringIO, "seek", strio_seek, -1); rb_define_method(StringIO, "sync", strio_get_sync, 0); rb_define_method(StringIO, "sync=", strio_set_sync, 1); rb_define_method(StringIO, "tell", strio_tell, 0); rb_define_method(StringIO, "path", strio_path, 0); rb_define_method(StringIO, "each", strio_each, -1); rb_define_method(StringIO, "each_line", strio_each, -1); rb_define_method(StringIO, "lines", strio_each, -1); rb_define_method(StringIO, "each_byte", strio_each_byte, 0); rb_define_method(StringIO, "bytes", strio_each_byte, 0); rb_define_method(StringIO, "each_char", strio_each_char, 0); rb_define_method(StringIO, "chars", strio_each_char, 0); rb_define_method(StringIO, "getc", strio_getc, 0); rb_define_method(StringIO, "getbyte", strio_getc, 0); rb_define_method(StringIO, "ungetc", strio_ungetc, 1); rb_define_method(StringIO, "readchar", strio_readchar, 0); rb_define_method(StringIO, "readbyte", strio_readchar, 0); rb_define_method(StringIO, "gets", strio_gets, -1); rb_define_method(StringIO, "readline", strio_readline, -1); rb_define_method(StringIO, "readlines", strio_readlines, -1); rb_define_method(StringIO, "read", strio_read, -1); rb_define_method(StringIO, "sysread", strio_sysread, -1); rb_define_method(StringIO, "write", strio_write, 1); rb_define_method(StringIO, "<<", strio_addstr, 1); rb_define_method(StringIO, "print", strio_print, -1); rb_define_method(StringIO, "printf", strio_printf, -1); rb_define_method(StringIO, "putc", strio_putc, 1); rb_define_method(StringIO, "puts", strio_puts, -1); rb_define_method(StringIO, "syswrite", strio_syswrite, 1); rb_define_method(StringIO, "isatty", strio_isatty, 0); rb_define_method(StringIO, "tty?", strio_isatty, 0); rb_define_method(StringIO, "pid", strio_pid, 0); rb_define_method(StringIO, "fileno", strio_fileno, 0); rb_define_method(StringIO, "size", strio_size, 0); rb_define_method(StringIO, "length", strio_size, 0); rb_define_method(StringIO, "truncate", strio_truncate, 1); } ================================================ FILE: ext/strscan/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/strscan/depend ================================================ strscan.o: strscan.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h ================================================ FILE: ext/strscan/extconf.rb ================================================ require 'mkmf' create_makefile 'strscan' ================================================ FILE: ext/strscan/strscan.c ================================================ /* $Id$ Copyright (c) 1999-2006 Minero Aoki This program is free software. You can distribute/modify this program under the terms of the Ruby License. For details, see the file COPYING. */ #include "ruby.h" #include "re.h" #define STRSCAN_VERSION "0.7.0" /* ======================================================================= Data Type Definitions ======================================================================= */ static VALUE StringScanner; static VALUE ScanError; struct strscanner { /* multi-purpose flags */ unsigned long flags; #define FLAG_MATCHED (1 << 0) /* the string to scan */ VALUE str; /* scan pointers */ long prev; /* legal only when MATCHED_P(s) */ long curr; /* always legal */ /* the regexp register; legal only when MATCHED_P(s) */ struct re_registers regs; }; #define MATCHED_P(s) ((s)->flags & FLAG_MATCHED) #define MATCHED(s) (s)->flags |= FLAG_MATCHED #define CLEAR_MATCH_STATUS(s) (s)->flags &= ~FLAG_MATCHED #define S_PBEG(s) (RSTRING((s)->str)->ptr) #define S_LEN(s) (RSTRING((s)->str)->len) #define S_PEND(s) (S_PBEG(s) + S_LEN(s)) #define CURPTR(s) (S_PBEG(s) + (s)->curr) #define S_RESTLEN(s) (S_LEN(s) - (s)->curr) #define EOS_P(s) ((s)->curr >= RSTRING(p->str)->len) #define GET_SCANNER(obj,var) do {\ Data_Get_Struct(obj, struct strscanner, var);\ if (NIL_P(var->str)) rb_raise(rb_eArgError, "uninitialized StringScanner object");\ } while (0) /* ======================================================================= Function Prototypes ======================================================================= */ static VALUE infect _((VALUE str, struct strscanner *p)); static VALUE extract_range _((struct strscanner *p, long beg_i, long end_i)); static VALUE extract_beg_len _((struct strscanner *p, long beg_i, long len)); static void check_strscan _((VALUE obj)); static void strscan_mark _((struct strscanner *p)); static void strscan_free _((struct strscanner *p)); static VALUE strscan_s_allocate _((VALUE klass)); static VALUE strscan_initialize _((int argc, VALUE *argv, VALUE self)); static VALUE strscan_init_copy _((VALUE vself, VALUE vorig)); static VALUE strscan_s_mustc _((VALUE self)); static VALUE strscan_terminate _((VALUE self)); static VALUE strscan_clear _((VALUE self)); static VALUE strscan_get_string _((VALUE self)); static VALUE strscan_set_string _((VALUE self, VALUE str)); static VALUE strscan_concat _((VALUE self, VALUE str)); static VALUE strscan_get_pos _((VALUE self)); static VALUE strscan_set_pos _((VALUE self, VALUE pos)); static VALUE strscan_do_scan _((VALUE self, VALUE regex, int succptr, int getstr, int headonly)); static VALUE strscan_scan _((VALUE self, VALUE re)); static VALUE strscan_match_p _((VALUE self, VALUE re)); static VALUE strscan_skip _((VALUE self, VALUE re)); static VALUE strscan_check _((VALUE self, VALUE re)); static VALUE strscan_scan_full _((VALUE self, VALUE re, VALUE succp, VALUE getp)); static VALUE strscan_scan_until _((VALUE self, VALUE re)); static VALUE strscan_skip_until _((VALUE self, VALUE re)); static VALUE strscan_check_until _((VALUE self, VALUE re)); static VALUE strscan_search_full _((VALUE self, VALUE re, VALUE succp, VALUE getp)); static void adjust_registers_to_matched _((struct strscanner *p)); static VALUE strscan_getch _((VALUE self)); static VALUE strscan_get_byte _((VALUE self)); static VALUE strscan_getbyte _((VALUE self)); static VALUE strscan_peek _((VALUE self, VALUE len)); static VALUE strscan_peep _((VALUE self, VALUE len)); static VALUE strscan_unscan _((VALUE self)); static VALUE strscan_bol_p _((VALUE self)); static VALUE strscan_eos_p _((VALUE self)); static VALUE strscan_empty_p _((VALUE self)); static VALUE strscan_rest_p _((VALUE self)); static VALUE strscan_matched_p _((VALUE self)); static VALUE strscan_matched _((VALUE self)); static VALUE strscan_matched_size _((VALUE self)); static VALUE strscan_aref _((VALUE self, VALUE idx)); static VALUE strscan_pre_match _((VALUE self)); static VALUE strscan_post_match _((VALUE self)); static VALUE strscan_rest _((VALUE self)); static VALUE strscan_rest_size _((VALUE self)); static VALUE strscan_inspect _((VALUE self)); static VALUE inspect1 _((struct strscanner *p)); static VALUE inspect2 _((struct strscanner *p)); /* ======================================================================= Utils ======================================================================= */ static VALUE infect(VALUE str, struct strscanner *p) { OBJ_INFECT(str, p->str); return str; } static VALUE extract_range(struct strscanner *p, long beg_i, long end_i) { if (beg_i > S_LEN(p)) return Qnil; if (end_i > S_LEN(p)) end_i = S_LEN(p); return infect(rb_str_new(S_PBEG(p) + beg_i, end_i - beg_i), p); } static VALUE extract_beg_len(struct strscanner *p, long beg_i, long len) { if (beg_i > S_LEN(p)) return Qnil; if (beg_i + len > S_LEN(p)) len = S_LEN(p) - beg_i; return infect(rb_str_new(S_PBEG(p) + beg_i, len), p); } /* ======================================================================= Constructor ======================================================================= */ static void strscan_mark(struct strscanner *p) { rb_gc_mark(p->str); } static void strscan_free(struct strscanner *p) { re_free_registers(&(p->regs)); free(p); } static VALUE strscan_s_allocate(VALUE klass) { struct strscanner *p; p = ALLOC(struct strscanner); MEMZERO(p, struct strscanner, 1); CLEAR_MATCH_STATUS(p); MEMZERO(&(p->regs), struct re_registers, 1); p->str = Qnil; return Data_Wrap_Struct(klass, strscan_mark, strscan_free, p); } /* * call-seq: StringScanner.new(string, dup = false) * * Creates a new StringScanner object to scan over the given +string+. * +dup+ argument is obsolete and not used now. */ static VALUE strscan_initialize(int argc, VALUE *argv, VALUE self) { struct strscanner *p; VALUE str, need_dup; Data_Get_Struct(self, struct strscanner, p); rb_scan_args(argc, argv, "11", &str, &need_dup); StringValue(str); p->str = str; return self; } static void check_strscan(VALUE obj) { if (TYPE(obj) != T_DATA || RDATA(obj)->dmark != (RUBY_DATA_FUNC)strscan_mark) { rb_raise(rb_eTypeError, "wrong argument type %s (expected StringScanner)", rb_obj_classname(obj)); } } /* * call-seq: * dup * clone * * Duplicates a StringScanner object. */ static VALUE strscan_init_copy(VALUE vself, VALUE vorig) { struct strscanner *self, *orig; Data_Get_Struct(vself, struct strscanner, self); check_strscan(vorig); Data_Get_Struct(vorig, struct strscanner, orig); if (self != orig) { self->flags = orig->flags; self->str = orig->str; self->prev = orig->prev; self->curr = orig->curr; re_copy_registers(&self->regs, &orig->regs); } return vself; } /* ======================================================================= Instance Methods ======================================================================= */ /* * call-seq: StringScanner.must_C_version * * This method is defined for backward compatibility. */ static VALUE strscan_s_mustc(VALUE self) { return self; } /* * Reset the scan pointer (index 0) and clear matching data. */ static VALUE strscan_reset(VALUE self) { struct strscanner *p; GET_SCANNER(self, p); p->curr = 0; CLEAR_MATCH_STATUS(p); return self; } /* * call-seq: * terminate * clear * * Set the scan pointer to the end of the string and clear matching data. */ static VALUE strscan_terminate(VALUE self) { struct strscanner *p; GET_SCANNER(self, p); p->curr = S_LEN(p); CLEAR_MATCH_STATUS(p); return self; } /* * Equivalent to #terminate. * This method is obsolete; use #terminate instead. */ static VALUE strscan_clear(VALUE self) { rb_warning("StringScanner#clear is obsolete; use #terminate instead"); return strscan_terminate(self); } /* * Returns the string being scanned. */ static VALUE strscan_get_string(VALUE self) { struct strscanner *p; GET_SCANNER(self, p); return p->str; } /* * call-seq: string=(str) * * Changes the string being scanned to +str+ and resets the scanner. * Returns +str+. */ static VALUE strscan_set_string(VALUE self, VALUE str) { struct strscanner *p; Data_Get_Struct(self, struct strscanner, p); StringValue(str); p->str = rb_str_dup(str); rb_obj_freeze(p->str); p->curr = 0; CLEAR_MATCH_STATUS(p); return str; } /* * call-seq: * concat(str) * <<(str) * * Appends +str+ to the string being scanned. * This method does not affect scan pointer. * * s = StringScanner.new("Fri Dec 12 1975 14:39") * s.scan(/Fri /) * s << " +1000 GMT" * s.string # -> "Fri Dec 12 1975 14:39 +1000 GMT" * s.scan(/Dec/) # -> "Dec" */ static VALUE strscan_concat(VALUE self, VALUE str) { struct strscanner *p; GET_SCANNER(self, p); StringValue(str); rb_str_append(p->str, str); return self; } /* * Returns the position of the scan pointer. In the 'reset' position, this * value is zero. In the 'terminated' position (i.e. the string is exhausted), * this value is the length of the string. * * In short, it's a 0-based index into the string. * * s = StringScanner.new('test string') * s.pos # -> 0 * s.scan_until /str/ # -> "test str" * s.pos # -> 8 * s.terminate # -> # * s.pos # -> 11 */ static VALUE strscan_get_pos(VALUE self) { struct strscanner *p; GET_SCANNER(self, p); return INT2FIX(p->curr); } /* * call-seq: pos=(n) * * Modify the scan pointer. * * s = StringScanner.new('test string') * s.pos = 7 # -> 7 * s.rest # -> "ring" */ static VALUE strscan_set_pos(VALUE self, VALUE v) { struct strscanner *p; long i; GET_SCANNER(self, p); i = NUM2INT(v); if (i < 0) i += S_LEN(p); if (i < 0) rb_raise(rb_eRangeError, "index out of range"); if (i > S_LEN(p)) rb_raise(rb_eRangeError, "index out of range"); p->curr = i; return INT2NUM(i); } static VALUE strscan_do_scan(VALUE self, VALUE regex, int succptr, int getstr, int headonly) { struct strscanner *p; int ret; Check_Type(regex, T_REGEXP); GET_SCANNER(self, p); CLEAR_MATCH_STATUS(p); if (S_RESTLEN(p) < 0) { return Qnil; } rb_kcode_set_option(regex); if (headonly) { ret = re_match(RREGEXP(regex)->ptr, CURPTR(p), S_RESTLEN(p), 0, &(p->regs)); } else { ret = re_search(RREGEXP(regex)->ptr, CURPTR(p), S_RESTLEN(p), 0, S_RESTLEN(p), &(p->regs)); } rb_kcode_reset_option(); if (ret == -2) rb_raise(ScanError, "regexp buffer overflow"); if (ret < 0) { /* not matched */ return Qnil; } MATCHED(p); p->prev = p->curr; if (succptr) { p->curr += p->regs.end[0]; } if (getstr) { return extract_beg_len(p, p->prev, p->regs.end[0]); } else { return INT2FIX(p->regs.end[0]); } } /* * call-seq: scan(pattern) => String * * Tries to match with +pattern+ at the current position. If there's a match, * the scanner advances the "scan pointer" and returns the matched string. * Otherwise, the scanner returns +nil+. * * s = StringScanner.new('test string') * p s.scan(/\w+/) # -> "test" * p s.scan(/\w+/) # -> nil * p s.scan(/\s+/) # -> " " * p s.scan(/\w+/) # -> "string" * p s.scan(/./) # -> nil * */ static VALUE strscan_scan(VALUE self, VALUE re) { return strscan_do_scan(self, re, 1, 1, 1); } /* * call-seq: match?(pattern) * * Tests whether the given +pattern+ is matched from the current scan pointer. * Returns the length of the match, or +nil+. The scan pointer is not advanced. * * s = StringScanner.new('test string') * p s.match?(/\w+/) # -> 4 * p s.match?(/\w+/) # -> 4 * p s.match?(/\s+/) # -> nil */ static VALUE strscan_match_p(VALUE self, VALUE re) { return strscan_do_scan(self, re, 0, 0, 1); } /* * call-seq: skip(pattern) * * Attempts to skip over the given +pattern+ beginning with the scan pointer. * If it matches, the scan pointer is advanced to the end of the match, and the * length of the match is returned. Otherwise, +nil+ is returned. * * It's similar to #scan, but without returning the matched string. * * s = StringScanner.new('test string') * p s.skip(/\w+/) # -> 4 * p s.skip(/\w+/) # -> nil * p s.skip(/\s+/) # -> 1 * p s.skip(/\w+/) # -> 6 * p s.skip(/./) # -> nil * */ static VALUE strscan_skip(VALUE self, VALUE re) { return strscan_do_scan(self, re, 1, 0, 1); } /* * call-seq: check(pattern) * * This returns the value that #scan would return, without advancing the scan * pointer. The match register is affected, though. * * s = StringScanner.new("Fri Dec 12 1975 14:39") * s.check /Fri/ # -> "Fri" * s.pos # -> 0 * s.matched # -> "Fri" * s.check /12/ # -> nil * s.matched # -> nil * * Mnemonic: it "checks" to see whether a #scan will return a value. */ static VALUE strscan_check(VALUE self, VALUE re) { return strscan_do_scan(self, re, 0, 1, 1); } /* * call-seq: scan_full(pattern, return_string_p, advance_pointer_p) * * Tests whether the given +pattern+ is matched from the current scan pointer. * Returns the matched string if +return_string_p+ is true. * Advances the scan pointer if +advance_pointer_p+ is true. * The match register is affected. * * "full" means "#scan with full parameters". */ static VALUE strscan_scan_full(VALUE self, VALUE re, VALUE s, VALUE f) { return strscan_do_scan(self, re, RTEST(s), RTEST(f), 1); } /* * call-seq: scan_until(pattern) * * Scans the string _until_ the +pattern+ is matched. Returns the substring up * to and including the end of the match, advancing the scan pointer to that * location. If there is no match, +nil+ is returned. * * s = StringScanner.new("Fri Dec 12 1975 14:39") * s.scan_until(/1/) # -> "Fri Dec 1" * s.pre_match # -> "Fri Dec " * s.scan_until(/XYZ/) # -> nil */ static VALUE strscan_scan_until(VALUE self, VALUE re) { return strscan_do_scan(self, re, 1, 1, 0); } /* * call-seq: exist?(pattern) * * Looks _ahead_ to see if the +pattern+ exists _anywhere_ in the string, * without advancing the scan pointer. This predicates whether a #scan_until * will return a value. * * s = StringScanner.new('test string') * s.exist? /s/ # -> 3 * s.scan /test/ # -> "test" * s.exist? /s/ # -> 6 * s.exist? /e/ # -> nil */ static VALUE strscan_exist_p(VALUE self, VALUE re) { return strscan_do_scan(self, re, 0, 0, 0); } /* * call-seq: skip_until(pattern) * * Advances the scan pointer until +pattern+ is matched and consumed. Returns * the number of bytes advanced, or +nil+ if no match was found. * * Look ahead to match +pattern+, and advance the scan pointer to the _end_ * of the match. Return the number of characters advanced, or +nil+ if the * match was unsuccessful. * * It's similar to #scan_until, but without returning the intervening string. * * s = StringScanner.new("Fri Dec 12 1975 14:39") * s.skip_until /12/ # -> 10 * s # */ static VALUE strscan_skip_until(VALUE self, VALUE re) { return strscan_do_scan(self, re, 1, 0, 0); } /* * call-seq: check_until(pattern) * * This returns the value that #scan_until would return, without advancing the * scan pointer. The match register is affected, though. * * s = StringScanner.new("Fri Dec 12 1975 14:39") * s.check_until /12/ # -> "Fri Dec 12" * s.pos # -> 0 * s.matched # -> 12 * * Mnemonic: it "checks" to see whether a #scan_until will return a value. */ static VALUE strscan_check_until(VALUE self, VALUE re) { return strscan_do_scan(self, re, 0, 1, 0); } /* * call-seq: search_full(pattern, return_string_p, advance_pointer_p) * * Scans the string _until_ the +pattern+ is matched. * Returns the matched string if +return_string_p+ is true, otherwise * returns the number of bytes advanced. * Advances the scan pointer if +advance_pointer_p+, otherwise not. * This method does affect the match register. */ static VALUE strscan_search_full(VALUE self, VALUE re, VALUE s, VALUE f) { return strscan_do_scan(self, re, RTEST(s), RTEST(f), 0); } /* DANGEROUS; need to synchronize with regex.c */ static void adjust_registers_to_matched(struct strscanner *p) { if (p->regs.allocated == 0) { p->regs.beg = ALLOC_N(int, RE_NREGS); p->regs.end = ALLOC_N(int, RE_NREGS); p->regs.allocated = RE_NREGS; } p->regs.num_regs = 1; p->regs.beg[0] = 0; p->regs.end[0] = p->curr - p->prev; } /* * Scans one character and returns it. * This method is multi-byte character sensitive. * See also #get_byte. * * s = StringScanner.new('ab') * s.getch # => "a" * s.getch # => "b" * s.getch # => nil * * $KCODE = 'EUC' * s = StringScanner.new("\244\242") * s.getch # => "\244\242" # Japanese hira-kana "A" in EUC-JP * s.getch # => nil */ static VALUE strscan_getch(VALUE self) { struct strscanner *p; long len; GET_SCANNER(self, p); CLEAR_MATCH_STATUS(p); if (EOS_P(p)) return Qnil; len = mbclen(*CURPTR(p)); if (p->curr + len > S_LEN(p)) { len = S_LEN(p) - p->curr; } p->prev = p->curr; p->curr += len; MATCHED(p); adjust_registers_to_matched(p); return extract_range(p, p->prev + p->regs.beg[0], p->prev + p->regs.end[0]); } /* * Scans one byte and returns it. * This method is NOT multi-byte character sensitive. * See also #getch. * * s = StringScanner.new('ab') * s.get_byte # => "a" * s.get_byte # => "b" * s.get_byte # => nil * * s = StringScanner.new("\244\242") * s.get_byte # => "\244" * s.get_byte # => "\242" * s.get_byte # => nil */ static VALUE strscan_get_byte(VALUE self) { struct strscanner *p; GET_SCANNER(self, p); CLEAR_MATCH_STATUS(p); if (EOS_P(p)) { return Qnil; } p->prev = p->curr; p->curr++; MATCHED(p); adjust_registers_to_matched(p); return extract_range(p, p->prev + p->regs.beg[0], p->prev + p->regs.end[0]); } /* * Equivalent to #get_byte. * This method is obsolete; use #get_byte instead. */ static VALUE strscan_getbyte(VALUE self) { rb_warning("StringScanner#getbyte is obsolete; use #get_byte instead"); return strscan_get_byte(self); } /* * call-seq: peek(len) * * Extracts a string corresponding to string[pos,len], without * advancing the scan pointer. * * s = StringScanner.new('test string') * s.peek(7) # => "test st" * s.peek(7) # => "test st" * */ static VALUE strscan_peek(VALUE self, VALUE vlen) { struct strscanner *p; long len; GET_SCANNER(self, p); len = NUM2LONG(vlen); if (EOS_P(p)) { return infect(rb_str_new("", 0), p); } if (p->curr + len > S_LEN(p)) { len = S_LEN(p) - p->curr; } return extract_beg_len(p, p->curr, len); } /* * Equivalent to #peek. * This method is obsolete; use #peek instead. */ static VALUE strscan_peep(VALUE self, VALUE vlen) { rb_warning("StringScanner#peep is obsolete; use #peek instead"); return strscan_peek(self, vlen); } /* * Set the scan pointer to the previous position. Only one previous position is * remembered, and it changes with each scanning operation. * * s = StringScanner.new('test string') * s.scan(/\w+/) # => "test" * s.unscan * s.scan(/../) # => "te" * s.scan(/\d/) # => nil * s.unscan # ScanError: unscan failed: previous match had failed */ static VALUE strscan_unscan(VALUE self) { struct strscanner *p; GET_SCANNER(self, p); if (! MATCHED_P(p)) { rb_raise(ScanError, "unscan failed: previous match had failed"); } p->curr = p->prev; CLEAR_MATCH_STATUS(p); return self; } /* * Returns +true+ iff the scan pointer is at the beginning of the line. * * s = StringScanner.new("test\ntest\n") * s.bol? # => true * s.scan(/te/) * s.bol? # => false * s.scan(/st\n/) * s.bol? # => true * s.terminate * s.bol? # => true */ static VALUE strscan_bol_p(VALUE self) { struct strscanner *p; GET_SCANNER(self, p); if (CURPTR(p) > S_PEND(p)) return Qnil; if (p->curr == 0) return Qtrue; return (*(CURPTR(p) - 1) == '\n') ? Qtrue : Qfalse; } /* * Returns +true+ if the scan pointer is at the end of the string. * * s = StringScanner.new('test string') * p s.eos? # => false * s.scan(/test/) * p s.eos? # => false * s.terminate * p s.eos? # => true */ static VALUE strscan_eos_p(VALUE self) { struct strscanner *p; GET_SCANNER(self, p); return EOS_P(p) ? Qtrue : Qfalse; } /* * Equivalent to #eos?. * This method is obsolete, use #eos? instead. */ static VALUE strscan_empty_p(VALUE self) { rb_warning("StringScanner#empty? is obsolete; use #eos? instead"); return strscan_eos_p(self); } /* * Returns true iff there is more data in the string. See #eos?. * This method is obsolete; use #eos? instead. * * s = StringScanner.new('test string') * s.eos? # These two * s.rest? # are opposites. */ static VALUE strscan_rest_p(VALUE self) { struct strscanner *p; GET_SCANNER(self, p); return EOS_P(p) ? Qfalse : Qtrue; } /* * Returns +true+ iff the last match was successful. * * s = StringScanner.new('test string') * s.match?(/\w+/) # => 4 * s.matched? # => true * s.match?(/\d+/) # => nil * s.matched? # => false */ static VALUE strscan_matched_p(VALUE self) { struct strscanner *p; GET_SCANNER(self, p); return MATCHED_P(p) ? Qtrue : Qfalse; } /* * Returns the last matched string. * * s = StringScanner.new('test string') * s.match?(/\w+/) # -> 4 * s.matched # -> "test" */ static VALUE strscan_matched(VALUE self) { struct strscanner *p; GET_SCANNER(self, p); if (! MATCHED_P(p)) return Qnil; return extract_range(p, p->prev + p->regs.beg[0], p->prev + p->regs.end[0]); } /* * Returns the size of the most recent match (see #matched), or +nil+ if there * was no recent match. * * s = StringScanner.new('test string') * s.check /\w+/ # -> "test" * s.matched_size # -> 4 * s.check /\d+/ # -> nil * s.matched_size # -> nil */ static VALUE strscan_matched_size(VALUE self) { struct strscanner *p; GET_SCANNER(self, p); if (! MATCHED_P(p)) return Qnil; return INT2NUM(p->regs.end[0] - p->regs.beg[0]); } /* * Equivalent to #matched_size. * This method is obsolete; use #matched_size instead. */ static VALUE strscan_matchedsize(VALUE self) { rb_warning("StringScanner#matchedsize is obsolete; use #matched_size instead"); return strscan_matched_size(self); } /* * call-seq: [](n) * * Return the n-th subgroup in the most recent match. * * s = StringScanner.new("Fri Dec 12 1975 14:39") * s.scan(/(\w+) (\w+) (\d+) /) # -> "Fri Dec 12 " * s[0] # -> "Fri Dec 12 " * s[1] # -> "Fri" * s[2] # -> "Dec" * s[3] # -> "12" * s.post_match # -> "1975 14:39" * s.pre_match # -> "" */ static VALUE strscan_aref(VALUE self, VALUE idx) { struct strscanner *p; long i; GET_SCANNER(self, p); if (! MATCHED_P(p)) return Qnil; i = NUM2LONG(idx); if (i < 0) i += p->regs.num_regs; if (i < 0) return Qnil; if (i >= p->regs.num_regs) return Qnil; if (p->regs.beg[i] == -1) return Qnil; return extract_range(p, p->prev + p->regs.beg[i], p->prev + p->regs.end[i]); } /* * Return the pre-match (in the regular expression sense) of the last scan. * * s = StringScanner.new('test string') * s.scan(/\w+/) # -> "test" * s.scan(/\s+/) # -> " " * s.pre_match # -> "test" * s.post_match # -> "string" */ static VALUE strscan_pre_match(VALUE self) { struct strscanner *p; GET_SCANNER(self, p); if (! MATCHED_P(p)) return Qnil; return extract_range(p, 0, p->prev + p->regs.beg[0]); } /* * Return the post-match (in the regular expression sense) of the last scan. * * s = StringScanner.new('test string') * s.scan(/\w+/) # -> "test" * s.scan(/\s+/) # -> " " * s.pre_match # -> "test" * s.post_match # -> "string" */ static VALUE strscan_post_match(VALUE self) { struct strscanner *p; GET_SCANNER(self, p); if (! MATCHED_P(p)) return Qnil; return extract_range(p, p->prev + p->regs.end[0], S_LEN(p)); } /* * Returns the "rest" of the string (i.e. everything after the scan pointer). * If there is no more data (eos? = true), it returns "". */ static VALUE strscan_rest(VALUE self) { struct strscanner *p; GET_SCANNER(self, p); if (EOS_P(p)) { return infect(rb_str_new("", 0), p); } return extract_range(p, p->curr, S_LEN(p)); } /* * s.rest_size is equivalent to s.rest.size. */ static VALUE strscan_rest_size(VALUE self) { struct strscanner *p; long i; GET_SCANNER(self, p); if (EOS_P(p)) { return INT2FIX(0); } i = S_LEN(p) - p->curr; return INT2FIX(i); } /* * s.restsize is equivalent to s.rest_size. * This method is obsolete; use #rest_size instead. */ static VALUE strscan_restsize(VALUE self) { rb_warning("StringScanner#restsize is obsolete; use #rest_size instead"); return strscan_rest_size(self); } #define INSPECT_LENGTH 5 #define BUFSIZE 256 /* * Returns a string that represents the StringScanner object, showing: * - the current position * - the size of the string * - the characters surrounding the scan pointer * * s = StringScanner.new("Fri Dec 12 1975 14:39") * s.inspect # -> '#' * s.scan_until /12/ # -> "Fri Dec 12" * s.inspect # -> '#' */ static VALUE strscan_inspect(VALUE self) { struct strscanner *p; char buf[BUFSIZE]; long len; VALUE a, b; Data_Get_Struct(self, struct strscanner, p); if (NIL_P(p->str)) { len = snprintf(buf, BUFSIZE, "#<%s (uninitialized)>", rb_class2name(CLASS_OF(self))); return infect(rb_str_new(buf, len), p); } if (EOS_P(p)) { len = snprintf(buf, BUFSIZE, "#<%s fin>", rb_class2name(CLASS_OF(self))); return infect(rb_str_new(buf, len), p); } if (p->curr == 0) { b = inspect2(p); len = snprintf(buf, BUFSIZE, "#<%s %ld/%ld @ %s>", rb_class2name(CLASS_OF(self)), p->curr, S_LEN(p), RSTRING(b)->ptr); return infect(rb_str_new(buf, len), p); } a = inspect1(p); b = inspect2(p); len = snprintf(buf, BUFSIZE, "#<%s %ld/%ld %s @ %s>", rb_class2name(CLASS_OF(self)), p->curr, S_LEN(p), RSTRING(a)->ptr, RSTRING(b)->ptr); return infect(rb_str_new(buf, len), p); } static VALUE inspect1(struct strscanner *p) { char buf[BUFSIZE]; char *bp = buf; long len; if (p->curr == 0) return rb_str_new2(""); if (p->curr > INSPECT_LENGTH) { strcpy(bp, "..."); bp += 3; len = INSPECT_LENGTH; } else { len = p->curr; } memcpy(bp, CURPTR(p) - len, len); bp += len; return rb_str_dump(rb_str_new(buf, bp - buf)); } static VALUE inspect2(struct strscanner *p) { char buf[BUFSIZE]; char *bp = buf; long len; if (EOS_P(p)) return rb_str_new2(""); len = S_LEN(p) - p->curr; if (len > INSPECT_LENGTH) { len = INSPECT_LENGTH; memcpy(bp, CURPTR(p), len); bp += len; strcpy(bp, "..."); bp += 3; } else { memcpy(bp, CURPTR(p), len); bp += len; } return rb_str_dump(rb_str_new(buf, bp - buf)); } /* ======================================================================= Ruby Interface ======================================================================= */ /* * Document-class: StringScanner * * StringScanner provides for lexical scanning operations on a String. Here is * an example of its usage: * * s = StringScanner.new('This is an example string') * s.eos? # -> false * * p s.scan(/\w+/) # -> "This" * p s.scan(/\w+/) # -> nil * p s.scan(/\s+/) # -> " " * p s.scan(/\s+/) # -> nil * p s.scan(/\w+/) # -> "is" * s.eos? # -> false * * p s.scan(/\s+/) # -> " " * p s.scan(/\w+/) # -> "an" * p s.scan(/\s+/) # -> " " * p s.scan(/\w+/) # -> "example" * p s.scan(/\s+/) # -> " " * p s.scan(/\w+/) # -> "string" * s.eos? # -> true * * p s.scan(/\s+/) # -> nil * p s.scan(/\w+/) # -> nil * * Scanning a string means remembering the position of a scan pointer, * which is just an index. The point of scanning is to move forward a bit at * a time, so matches are sought after the scan pointer; usually immediately * after it. * * Given the string "test string", here are the pertinent scan pointer * positions: * * t e s t s t r i n g * 0 1 2 ... 1 * 0 * * When you #scan for a pattern (a regular expression), the match must occur * at the character after the scan pointer. If you use #scan_until, then the * match can occur anywhere after the scan pointer. In both cases, the scan * pointer moves just beyond the last character of the match, ready to * scan again from the next character onwards. This is demonstrated by the * example above. * * == Method Categories * * There are other methods besides the plain scanners. You can look ahead in * the string without actually scanning. You can access the most recent match. * You can modify the string being scanned, reset or terminate the scanner, * find out or change the position of the scan pointer, skip ahead, and so on. * * === Advancing the Scan Pointer * * - #getch * - #get_byte * - #scan * - #scan_until * - #skip * - #skip_until * * === Looking Ahead * * - #check * - #check_until * - #exist? * - #match? * - #peek * * === Finding Where we Are * * - #beginning_of_line? (#bol?) * - #eos? * - #rest? * - #rest_size * - #pos * * === Setting Where we Are * * - #reset * - #terminate * - #pos= * * === Match Data * * - #matched * - #matched? * - #matched_size * - [] * - #pre_match * - #post_match * * === Miscellaneous * * - << * - #concat * - #string * - #string= * - #unscan * * There are aliases to several of the methods. */ void Init_strscan(void) { ID id_scanerr = rb_intern("ScanError"); VALUE tmp; StringScanner = rb_define_class("StringScanner", rb_cObject); ScanError = rb_define_class_under(StringScanner, "Error", rb_eStandardError); if (!rb_const_defined(rb_cObject, id_scanerr)) { rb_const_set(rb_cObject, id_scanerr, ScanError); } tmp = rb_str_new2(STRSCAN_VERSION); rb_obj_freeze(tmp); rb_const_set(StringScanner, rb_intern("Version"), tmp); tmp = rb_str_new2("$Id$"); rb_obj_freeze(tmp); rb_const_set(StringScanner, rb_intern("Id"), tmp); rb_define_alloc_func(StringScanner, strscan_s_allocate); rb_define_private_method(StringScanner, "initialize", strscan_initialize, -1); rb_define_private_method(StringScanner, "initialize_copy", strscan_init_copy, 1); rb_define_singleton_method(StringScanner, "must_C_version", strscan_s_mustc, 0); rb_define_method(StringScanner, "reset", strscan_reset, 0); rb_define_method(StringScanner, "terminate", strscan_terminate, 0); rb_define_method(StringScanner, "clear", strscan_clear, 0); rb_define_method(StringScanner, "string", strscan_get_string, 0); rb_define_method(StringScanner, "string=", strscan_set_string, 1); rb_define_method(StringScanner, "concat", strscan_concat, 1); rb_define_method(StringScanner, "<<", strscan_concat, 1); rb_define_method(StringScanner, "pos", strscan_get_pos, 0); rb_define_method(StringScanner, "pos=", strscan_set_pos, 1); rb_define_method(StringScanner, "pointer", strscan_get_pos, 0); rb_define_method(StringScanner, "pointer=", strscan_set_pos, 1); rb_define_method(StringScanner, "scan", strscan_scan, 1); rb_define_method(StringScanner, "skip", strscan_skip, 1); rb_define_method(StringScanner, "match?", strscan_match_p, 1); rb_define_method(StringScanner, "check", strscan_check, 1); rb_define_method(StringScanner, "scan_full", strscan_scan_full, 3); rb_define_method(StringScanner, "scan_until", strscan_scan_until, 1); rb_define_method(StringScanner, "skip_until", strscan_skip_until, 1); rb_define_method(StringScanner, "exist?", strscan_exist_p, 1); rb_define_method(StringScanner, "check_until", strscan_check_until, 1); rb_define_method(StringScanner, "search_full", strscan_search_full, 3); rb_define_method(StringScanner, "getch", strscan_getch, 0); rb_define_method(StringScanner, "get_byte", strscan_get_byte, 0); rb_define_method(StringScanner, "getbyte", strscan_getbyte, 0); rb_define_method(StringScanner, "peek", strscan_peek, 1); rb_define_method(StringScanner, "peep", strscan_peep, 1); rb_define_method(StringScanner, "unscan", strscan_unscan, 0); rb_define_method(StringScanner, "beginning_of_line?", strscan_bol_p, 0); rb_alias(StringScanner, rb_intern("bol?"), rb_intern("beginning_of_line?")); rb_define_method(StringScanner, "eos?", strscan_eos_p, 0); rb_define_method(StringScanner, "empty?", strscan_empty_p, 0); rb_define_method(StringScanner, "rest?", strscan_rest_p, 0); rb_define_method(StringScanner, "matched?", strscan_matched_p, 0); rb_define_method(StringScanner, "matched", strscan_matched, 0); rb_define_method(StringScanner, "matched_size", strscan_matched_size, 0); rb_define_method(StringScanner, "matchedsize", strscan_matchedsize, 0); rb_define_method(StringScanner, "[]", strscan_aref, 1); rb_define_method(StringScanner, "pre_match", strscan_pre_match, 0); rb_define_method(StringScanner, "post_match", strscan_post_match, 0); rb_define_method(StringScanner, "rest", strscan_rest, 0); rb_define_method(StringScanner, "rest_size", strscan_rest_size, 0); rb_define_method(StringScanner, "restsize", strscan_restsize, 0); rb_define_method(StringScanner, "inspect", strscan_inspect, 0); } ================================================ FILE: ext/syck/.cvsignore ================================================ Makefile mkmf.log *.def ================================================ FILE: ext/syck/bytecode.c ================================================ /* Generated by re2c 0.9.10 on Mon Sep 19 23:21:26 2005 */ #line 1 "bytecode.re" /* * bytecode.re * * $Author$ * $Date$ * * Copyright (C) 2003 why the lucky stiff */ #include "ruby.h" #include "syck.h" #include "gram.h" #define QUOTELEN 128 /* * They do my bidding... */ #define YYCTYPE char #define YYCURSOR parser->cursor #define YYMARKER parser->marker #define YYLIMIT parser->limit #define YYTOKEN parser->token #define YYTOKTMP parser->toktmp #define YYLINEPTR parser->lineptr #define YYLINECTPTR parser->linectptr #define YYLINE parser->linect #define YYFILL(n) syck_parser_read(parser) extern SyckParser *syck_parser_ptr; char *get_inline( SyckParser *parser ); /* * Repositions the cursor at `n' offset from the token start. * Only works in `Header' and `Document' sections. */ #define YYPOS(n) YYCURSOR = YYTOKEN + n /* * Track line numbers */ #define CHK_NL(ptr) if ( *( ptr - 1 ) == '\n' && ptr > YYLINECTPTR ) { YYLINEPTR = ptr; YYLINE++; YYLINECTPTR = YYLINEPTR; } /* * I like seeing the level operations as macros... */ #define ADD_LEVEL(len, status) syck_parser_add_level( parser, len, status ) #define POP_LEVEL() syck_parser_pop_level( parser ) #define CURRENT_LEVEL() syck_parser_current_level( parser ) /* * Force a token next time around sycklex() */ #define FORCE_NEXT_TOKEN(tok) parser->force_token = tok; /* * Adding levels in bytecode requires us to make sure * we've got all our tokens worked out. */ #define ADD_BYTE_LEVEL(lvl, len, s ) \ switch ( lvl->status ) \ { \ case syck_lvl_seq: \ lvl->ncount++; \ ADD_LEVEL(len, syck_lvl_open); \ YYPOS(0); \ return '-'; \ \ case syck_lvl_map: \ lvl->ncount++; \ ADD_LEVEL(len, s); \ break; \ \ case syck_lvl_open: \ lvl->status = s; \ break; \ \ default: \ ADD_LEVEL(len, s); \ break; \ } /* * Nice little macro to ensure we're YAML_IOPENed to the current level. * * Only use this macro in the "Document" section * */ #define ENSURE_YAML_IOPEN(last_lvl, lvl_type, to_len, reset) \ if ( last_lvl->spaces < to_len ) \ { \ if ( last_lvl->status == syck_lvl_iseq || last_lvl->status == syck_lvl_imap ) \ { \ goto Document; \ } \ else \ { \ ADD_LEVEL( to_len, lvl_type ); \ if ( reset == 1 ) YYPOS(0); \ return YAML_IOPEN; \ } \ } /* * Nice little macro to ensure closure of levels. * * Only use this macro in the "Document" section * */ #define ENSURE_YAML_IEND(last_lvl, to_len) \ if ( last_lvl->spaces > to_len ) \ { \ syck_parser_pop_level( parser ); \ YYPOS(0); \ return YAML_IEND; \ } /* * Concatenates string items and manages allocation * to the string */ #define CAT(s, c, i, l) \ { \ if ( i + 1 >= c ) \ { \ c += QUOTELEN; \ S_REALLOC_N( s, char, c ); \ } \ s[i++] = l; \ s[i] = '\0'; \ } /* * Parser for standard YAML Bytecode [UTF-8] */ int sycklex_bytecode_utf8( YYSTYPE *sycklval, SyckParser *parser ) { SyckLevel *lvl; syck_parser_ptr = parser; if ( YYCURSOR == NULL ) { syck_parser_read( parser ); } if ( parser->force_token != 0 ) { int t = parser->force_token; parser->force_token = 0; return t; } #line 172 "bytecode.re" lvl = CURRENT_LEVEL(); if ( lvl->status == syck_lvl_doc ) { goto Document; } /* Header: */ YYTOKEN = YYCURSOR; #line 165 "" { YYCTYPE yych; unsigned int yyaccept; goto yy0; ++YYCURSOR; yy0: if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); yych = *YYCURSOR; switch(yych){ case 0x00: goto yy2; case 'D': goto yy3; default: goto yy5; } yy2: YYCURSOR = YYMARKER; switch(yyaccept){ case 0: goto yy4; } yy3: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 0x0A: goto yy6; case 0x0D: goto yy8; default: goto yy4; } yy4: #line 199 "bytecode.re" { YYPOS(0); goto Document; } #line 195 "" yy5: yych = *++YYCURSOR; goto yy4; yy6: ++YYCURSOR; goto yy7; yy7: #line 186 "bytecode.re" { if ( lvl->status == syck_lvl_header ) { CHK_NL(YYCURSOR); goto Directive; } else { ENSURE_YAML_IEND(lvl, -1); YYPOS(0); return 0; } } #line 214 "" yy8: ++YYCURSOR; switch((yych = *YYCURSOR)) { case 0x0A: goto yy6; default: goto yy2; } } #line 203 "bytecode.re" Document: { lvl = CURRENT_LEVEL(); if ( lvl->status == syck_lvl_header ) { lvl->status = syck_lvl_doc; } YYTOKEN = YYCURSOR; #line 235 "" { YYCTYPE yych; goto yy9; ++YYCURSOR; yy9: if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); yych = *YYCURSOR; switch(yych){ case 0x00: goto yy30; case 0x0A: goto yy27; case 0x0D: goto yy29; case 'A': goto yy19; case 'D': goto yy12; case 'E': goto yy16; case 'M': goto yy14; case 'P': goto yy13; case 'Q': goto yy15; case 'R': goto yy21; case 'S': goto yy17; case 'T': goto yy23; case 'c': goto yy25; default: goto yy11; } yy11:yy12: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy41; case 0x0D: goto yy44; default: goto yy11; } yy13: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy41; case 0x0D: goto yy43; default: goto yy11; } yy14: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy38; case 0x0D: goto yy40; default: goto yy11; } yy15: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy35; case 0x0D: goto yy37; default: goto yy11; } yy16: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy32; case 0x0D: goto yy34; default: goto yy11; } yy17: ++YYCURSOR; goto yy18; yy18: #line 288 "bytecode.re" { ADD_BYTE_LEVEL(lvl, lvl->spaces + 1, syck_lvl_str); goto Scalar; } #line 296 "" yy19: ++YYCURSOR; goto yy20; yy20: #line 292 "bytecode.re" { ADD_BYTE_LEVEL(lvl, lvl->spaces + 1, syck_lvl_open); sycklval->name = get_inline( parser ); syck_hdlr_remove_anchor( parser, sycklval->name ); CHK_NL(YYCURSOR); return YAML_ANCHOR; } #line 307 "" yy21: ++YYCURSOR; goto yy22; yy22: #line 299 "bytecode.re" { ADD_BYTE_LEVEL(lvl, lvl->spaces + 1, syck_lvl_str); sycklval->name = get_inline( parser ); POP_LEVEL(); if ( *( YYCURSOR - 1 ) == '\n' ) YYCURSOR--; return YAML_ALIAS; } #line 318 "" yy23: ++YYCURSOR; goto yy24; yy24: #line 306 "bytecode.re" { char *qstr; ADD_BYTE_LEVEL(lvl, lvl->spaces + 1, syck_lvl_open); qstr = get_inline( parser ); CHK_NL(YYCURSOR); if ( qstr[0] == '!' ) { int qidx = strlen( qstr ); if ( qstr[1] == '\0' ) { free( qstr ); return YAML_ITRANSFER; } lvl = CURRENT_LEVEL(); /* * URL Prefixing */ if ( qstr[1] == '^' ) { sycklval->name = S_ALLOC_N( char, qidx + strlen( lvl->domain ) ); sycklval->name[0] = '\0'; strcat( sycklval->name, lvl->domain ); strncat( sycklval->name, qstr + 2, qidx - 2 ); free( qstr ); } else { char *carat = qstr + 1; char *qend = qstr + qidx; while ( (++carat) < qend ) { if ( *carat == '^' ) break; } if ( carat < qend ) { free( lvl->domain ); lvl->domain = syck_strndup( qstr + 1, carat - ( qstr + 1 ) ); sycklval->name = S_ALLOC_N( char, ( qend - carat ) + strlen( lvl->domain ) ); sycklval->name[0] = '\0'; strcat( sycklval->name, lvl->domain ); strncat( sycklval->name, carat + 1, ( qend - carat ) - 1 ); free( qstr ); } else { sycklval->name = S_ALLOC_N( char, strlen( qstr ) ); sycklval->name[0] = '\0'; S_MEMCPY( sycklval->name, qstr + 1, char, strlen( qstr ) ); free( qstr ); } } return YAML_TRANSFER; } sycklval->name = qstr; return YAML_TAGURI; } #line 382 "" yy25: ++YYCURSOR; goto yy26; yy26: #line 366 "bytecode.re" { goto Comment; } #line 388 "" yy27: ++YYCURSOR; goto yy28; yy28: #line 368 "bytecode.re" { CHK_NL(YYCURSOR); if ( lvl->status == syck_lvl_seq ) { return YAML_INDENT; } else if ( lvl->status == syck_lvl_map ) { if ( lvl->ncount % 2 == 1 ) return ':'; else return YAML_INDENT; } goto Document; } #line 405 "" yy29: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy27; default: goto yy11; } yy30: ++YYCURSOR; goto yy31; yy31: #line 381 "bytecode.re" { ENSURE_YAML_IEND(lvl, -1); YYPOS(0); return 0; } #line 419 "" yy32: ++YYCURSOR; goto yy33; yy33: #line 252 "bytecode.re" { if ( lvl->status == syck_lvl_seq && lvl->ncount == 0 ) { lvl->ncount++; YYPOS(0); FORCE_NEXT_TOKEN( ']' ); return '['; } else if ( lvl->status == syck_lvl_map && lvl->ncount == 0 ) { lvl->ncount++; YYPOS(0); FORCE_NEXT_TOKEN( '}' ); return '{'; } POP_LEVEL(); lvl = CURRENT_LEVEL(); if ( lvl->status == syck_lvl_seq ) { FORCE_NEXT_TOKEN(YAML_INDENT); } else if ( lvl->status == syck_lvl_map ) { if ( lvl->ncount % 2 == 1 ) { FORCE_NEXT_TOKEN(':'); } else { FORCE_NEXT_TOKEN(YAML_INDENT); } } CHK_NL(YYCURSOR); return YAML_IEND; } #line 459 "" yy34: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy32; default: goto yy11; } yy35: ++YYCURSOR; goto yy36; yy36: #line 237 "bytecode.re" { int complex = 0; if ( lvl->ncount % 2 == 0 && ( lvl->status == syck_lvl_map || lvl->status == syck_lvl_seq ) ) { complex = 1; } ADD_BYTE_LEVEL(lvl, lvl->spaces + 1, syck_lvl_seq); CHK_NL(YYCURSOR); if ( complex ) { FORCE_NEXT_TOKEN( YAML_IOPEN ); return '?'; } return YAML_IOPEN; } #line 483 "" yy37: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy35; default: goto yy11; } yy38: ++YYCURSOR; goto yy39; yy39: #line 222 "bytecode.re" { int complex = 0; if ( lvl->ncount % 2 == 0 && ( lvl->status == syck_lvl_map || lvl->status == syck_lvl_seq ) ) { complex = 1; } ADD_BYTE_LEVEL(lvl, lvl->spaces + 1, syck_lvl_map); CHK_NL(YYCURSOR); if ( complex ) { FORCE_NEXT_TOKEN( YAML_IOPEN ); return '?'; } return YAML_IOPEN; } #line 507 "" yy40: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy38; default: goto yy11; } yy41: ++YYCURSOR; goto yy42; yy42: #line 217 "bytecode.re" { ENSURE_YAML_IEND(lvl, -1); YYPOS(0); return 0; } #line 521 "" yy43: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy41; default: goto yy11; } yy44: ++YYCURSOR; switch((yych = *YYCURSOR)) { case 0x0A: goto yy41; default: goto yy11; } } #line 386 "bytecode.re" } Directive: { YYTOKEN = YYCURSOR; #line 543 "" { YYCTYPE yych; unsigned int yyaccept; goto yy45; ++YYCURSOR; yy45: if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); yych = *YYCURSOR; switch(yych){ case 0x00: goto yy47; case 'V': goto yy48; default: goto yy50; } yy47: YYCURSOR = YYMARKER; switch(yyaccept){ case 0: goto yy49; } yy48: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case '.': case '/': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '[': case '\\': case ']': case '^': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy51; default: goto yy49; } yy49: #line 399 "bytecode.re" { YYCURSOR = YYTOKEN; return YAML_DOCSEP; } #line 646 "" yy50: yych = *++YYCURSOR; goto yy49; yy51: ++YYCURSOR; if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); yych = *YYCURSOR; goto yy52; yy52: switch(yych){ case '.': case '/': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ';': case '<': case '=': case '>': case '?': case '@': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '[': case '\\': case ']': case '^': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy51; case ':': goto yy53; default: goto yy47; } yy53: yych = *++YYCURSOR; switch(yych){ case '.': case '/': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '[': case '\\': case ']': case '^': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy54; default: goto yy47; } yy54: ++YYCURSOR; if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); yych = *YYCURSOR; goto yy55; yy55: switch(yych){ case 0x0A: goto yy56; case 0x0D: goto yy58; case '.': case '/': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '[': case '\\': case ']': case '^': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy54; default: goto yy47; } yy56: ++YYCURSOR; goto yy57; yy57: #line 396 "bytecode.re" { CHK_NL(YYCURSOR); goto Directive; } #line 899 "" yy58: ++YYCURSOR; switch((yych = *YYCURSOR)) { case 0x0A: goto yy56; default: goto yy47; } } #line 402 "bytecode.re" } Comment: { YYTOKEN = YYCURSOR; #line 916 "" { YYCTYPE yych; goto yy59; ++YYCURSOR; yy59: if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); yych = *YYCURSOR; switch(yych){ case 0x00: goto yy61; case 0x0A: goto yy62; case 0x0D: goto yy64; default: goto yy66; } yy61:yy62: ++YYCURSOR; goto yy63; yy63: #line 412 "bytecode.re" { CHK_NL(YYCURSOR); goto Document; } #line 936 "" yy64: ++YYCURSOR; switch((yych = *YYCURSOR)) { case 0x0A: goto yy67; default: goto yy65; } yy65: #line 415 "bytecode.re" { goto Comment; } #line 945 "" yy66: yych = *++YYCURSOR; goto yy65; yy67: ++YYCURSOR; yych = *YYCURSOR; goto yy63; } #line 417 "bytecode.re" } Scalar: { int idx = 0; int cap = 100; char *str = S_ALLOC_N( char, cap ); char *tok; str[0] = '\0'; Scalar2: tok = YYCURSOR; #line 970 "" { YYCTYPE yych; goto yy68; ++YYCURSOR; yy68: if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); yych = *YYCURSOR; switch(yych){ case 0x00: goto yy74; case 0x0A: goto yy70; case 0x0D: goto yy72; default: goto yy76; } yy70: ++YYCURSOR; switch((yych = *YYCURSOR)) { case 'C': goto yy78; case 'N': goto yy80; case 'Z': goto yy83; default: goto yy71; } yy71: #line 461 "bytecode.re" { YYCURSOR = tok; goto ScalarEnd; } #line 996 "" yy72: ++YYCURSOR; switch((yych = *YYCURSOR)) { case 0x0A: goto yy77; default: goto yy73; } yy73: #line 469 "bytecode.re" { CAT(str, cap, idx, tok[0]); goto Scalar2; } #line 1007 "" yy74: ++YYCURSOR; goto yy75; yy75: #line 465 "bytecode.re" { YYCURSOR = tok; goto ScalarEnd; } #line 1015 "" yy76: yych = *++YYCURSOR; goto yy73; yy77: yych = *++YYCURSOR; switch(yych){ case 'C': goto yy78; case 'N': goto yy80; case 'Z': goto yy83; default: goto yy71; } yy78: ++YYCURSOR; goto yy79; yy79: #line 435 "bytecode.re" { CHK_NL(tok+1); goto Scalar2; } #line 1031 "" yy80: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy81; yy81: switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy80; default: goto yy82; } yy82: #line 438 "bytecode.re" { CHK_NL(tok+1); if ( tok + 2 < YYCURSOR ) { char *count = tok + 2; int total = strtod( count, NULL ); int i; for ( i = 0; i < total; i++ ) { CAT(str, cap, idx, '\n'); } } else { CAT(str, cap, idx, '\n'); } goto Scalar2; } #line 1068 "" yy83: ++YYCURSOR; goto yy84; yy84: #line 456 "bytecode.re" { CHK_NL(tok+1); CAT(str, cap, idx, '\0'); goto Scalar2; } #line 1077 "" } #line 473 "bytecode.re" ScalarEnd: { SyckNode *n = syck_alloc_str(); n->data.str->ptr = str; n->data.str->len = idx; sycklval->nodeData = n; POP_LEVEL(); if ( parser->implicit_typing == 1 ) { try_tag_implicit( sycklval->nodeData, parser->taguri_expansion ); } return YAML_PLAIN; } } } char * get_inline( SyckParser *parser ) { int idx = 0; int cap = 100; char *str = S_ALLOC_N( char, cap ); char *tok; str[0] = '\0'; Inline: { tok = YYCURSOR; #line 1114 "" { YYCTYPE yych; goto yy85; ++YYCURSOR; yy85: if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); yych = *YYCURSOR; switch(yych){ case 0x00: goto yy91; case 0x0A: goto yy87; case 0x0D: goto yy89; default: goto yy93; } yy87: ++YYCURSOR; goto yy88; yy88: #line 508 "bytecode.re" { CHK_NL(YYCURSOR); return str; } #line 1134 "" yy89: ++YYCURSOR; switch((yych = *YYCURSOR)) { case 0x0A: goto yy94; default: goto yy90; } yy90: #line 515 "bytecode.re" { CAT(str, cap, idx, tok[0]); goto Inline; } #line 1145 "" yy91: ++YYCURSOR; goto yy92; yy92: #line 511 "bytecode.re" { YYCURSOR = tok; return str; } #line 1153 "" yy93: yych = *++YYCURSOR; goto yy90; yy94: ++YYCURSOR; yych = *YYCURSOR; goto yy88; } #line 519 "bytecode.re" } } ================================================ FILE: ext/syck/depend ================================================ ruby_headers = $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h \ $(hdrdir)/missing.h $(hdrdir)/intern.h $(hdrdir)/st.h bytecode.o: bytecode.c syck.h gram.h $(ruby_headers) emitter.o: emitter.c syck.h $(ruby_headers) gram.o: gram.c syck.h $(hdrdir)/st.h handler.o: handler.c syck.h $(ruby_headers) implicit.o: implicit.c syck.h $(ruby_headers) node.o: node.c syck.h $(ruby_headers) rubyext.o: rubyext.c syck.h $(ruby_headers) syck.o: syck.c syck.h $(ruby_headers) token.o: token.c syck.h gram.h $(ruby_headers) yaml2byte.o: yaml2byte.c syck.h yamlbyte.h $(ruby_headers) ================================================ FILE: ext/syck/emitter.c ================================================ /* * emitter.c * * $Author$ * $Date$ * * Copyright (C) 2003 why the lucky stiff * * All Base64 code from Ruby's pack.c. * Ruby is Copyright (C) 1993-2003 Yukihiro Matsumoto */ #include "ruby.h" #include #include #include "syck.h" #define DEFAULT_ANCHOR_FORMAT "id%03d" const char hex_table[] = "0123456789ABCDEF"; static char b64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* * Built-in base64 (from Ruby's pack.c) */ char * syck_base64enc( char *s, long len ) { long i = 0; int padding = '='; char *buff = S_ALLOC_N(char, len * 4 / 3 + 6); while (len >= 3) { buff[i++] = b64_table[077 & (*s >> 2)]; buff[i++] = b64_table[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))]; buff[i++] = b64_table[077 & (((s[1] << 2) & 074) | ((s[2] >> 6) & 03))]; buff[i++] = b64_table[077 & s[2]]; s += 3; len -= 3; } if (len == 2) { buff[i++] = b64_table[077 & (*s >> 2)]; buff[i++] = b64_table[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))]; buff[i++] = b64_table[077 & (((s[1] << 2) & 074) | (('\0' >> 6) & 03))]; buff[i++] = padding; } else if (len == 1) { buff[i++] = b64_table[077 & (*s >> 2)]; buff[i++] = b64_table[077 & (((*s << 4) & 060) | (('\0' >> 4) & 017))]; buff[i++] = padding; buff[i++] = padding; } buff[i++] = '\n'; return buff; } char * syck_base64dec( char *s, long len ) { int a = -1,b = -1,c = 0,d; static int first = 1; static int b64_xtable[256]; char *ptr = syck_strndup( s, len ); char *end = ptr; char *send = s + len; if (first) { int i; first = 0; for (i = 0; i < 256; i++) { b64_xtable[i] = -1; } for (i = 0; i < 64; i++) { b64_xtable[(int)b64_table[i]] = i; } } while (s < send) { while (s[0] == '\r' || s[0] == '\n') { s++; } if ((a = b64_xtable[(int)s[0]]) == -1) break; if ((b = b64_xtable[(int)s[1]]) == -1) break; if ((c = b64_xtable[(int)s[2]]) == -1) break; if ((d = b64_xtable[(int)s[3]]) == -1) break; *end++ = a << 2 | b >> 4; *end++ = b << 4 | c >> 2; *end++ = c << 6 | d; s += 4; } if (a != -1 && b != -1) { if (s + 2 < send && s[2] == '=') *end++ = a << 2 | b >> 4; if (c != -1 && s + 3 < send && s[3] == '=') { *end++ = a << 2 | b >> 4; *end++ = b << 4 | c >> 2; } } *end = '\0'; /*RSTRING(buf)->len = ptr - RSTRING(buf)->ptr;*/ return ptr; } /* * Allocate an emitter */ SyckEmitter * syck_new_emitter() { SyckEmitter *e; e = S_ALLOC( SyckEmitter ); e->headless = 0; e->use_header = 0; e->use_version = 0; e->sort_keys = 0; e->anchor_format = NULL; e->explicit_typing = 0; e->best_width = 80; e->style = scalar_none; e->stage = doc_open; e->indent = 2; e->level = -1; e->anchors = NULL; e->markers = NULL; e->anchored = NULL; e->bufsize = SYCK_BUFFERSIZE; e->buffer = NULL; e->marker = NULL; e->bufpos = 0; e->emitter_handler = NULL; e->output_handler = NULL; e->lvl_idx = 0; e->lvl_capa = ALLOC_CT; e->levels = S_ALLOC_N( SyckLevel, e->lvl_capa ); syck_emitter_reset_levels( e ); e->bonus = NULL; return e; } int syck_st_free_anchors( char *key, char *name, char *arg ) { S_FREE( name ); return ST_CONTINUE; } void syck_emitter_st_free( SyckEmitter *e ) { /* * Free the anchor tables */ if ( e->anchors != NULL ) { st_foreach( e->anchors, syck_st_free_anchors, 0 ); st_free_table( e->anchors ); e->anchors = NULL; } if ( e->anchored != NULL ) { st_free_table( e->anchored ); e->anchored = NULL; } /* * Free the markers tables */ if ( e->markers != NULL ) { st_free_table( e->markers ); e->markers = NULL; } } SyckLevel * syck_emitter_current_level( SyckEmitter *e ) { return &e->levels[e->lvl_idx-1]; } SyckLevel * syck_emitter_parent_level( SyckEmitter *e ) { return &e->levels[e->lvl_idx-2]; } void syck_emitter_pop_level( SyckEmitter *e ) { ASSERT( e != NULL ); /* The root level should never be popped */ if ( e->lvl_idx <= 1 ) return; e->lvl_idx -= 1; free( e->levels[e->lvl_idx].domain ); } void syck_emitter_add_level( SyckEmitter *e, int len, enum syck_level_status status ) { ASSERT( e != NULL ); if ( e->lvl_idx + 1 > e->lvl_capa ) { e->lvl_capa += ALLOC_CT; S_REALLOC_N( e->levels, SyckLevel, e->lvl_capa ); } ASSERT( len > e->levels[e->lvl_idx-1].spaces ); e->levels[e->lvl_idx].spaces = len; e->levels[e->lvl_idx].ncount = 0; e->levels[e->lvl_idx].domain = syck_strndup( e->levels[e->lvl_idx-1].domain, strlen( e->levels[e->lvl_idx-1].domain ) ); e->levels[e->lvl_idx].status = status; e->levels[e->lvl_idx].anctag = 0; e->lvl_idx += 1; } void syck_emitter_reset_levels( SyckEmitter *e ) { while ( e->lvl_idx > 1 ) { syck_emitter_pop_level( e ); } if ( e->lvl_idx < 1 ) { e->lvl_idx = 1; e->levels[0].spaces = -1; e->levels[0].ncount = 0; e->levels[0].domain = syck_strndup( "", 0 ); e->levels[0].anctag = 0; } e->levels[0].status = syck_lvl_header; } void syck_emitter_handler( SyckEmitter *e, SyckEmitterHandler hdlr ) { e->emitter_handler = hdlr; } void syck_output_handler( SyckEmitter *e, SyckOutputHandler hdlr ) { e->output_handler = hdlr; } void syck_free_emitter( SyckEmitter *e ) { /* * Free tables */ syck_emitter_st_free( e ); syck_emitter_reset_levels( e ); S_FREE( e->levels[0].domain ); S_FREE( e->levels ); if ( e->buffer != NULL ) { S_FREE( e->buffer ); } S_FREE( e ); } void syck_emitter_clear( SyckEmitter *e ) { if ( e->buffer == NULL ) { e->buffer = S_ALLOC_N( char, e->bufsize ); S_MEMZERO( e->buffer, char, e->bufsize ); } e->buffer[0] = '\0'; e->marker = e->buffer; e->bufpos = 0; } /* * Raw write to the emitter buffer. */ void syck_emitter_write( SyckEmitter *e, char *str, long len ) { long at; ASSERT( str != NULL ) if ( e->buffer == NULL ) { syck_emitter_clear( e ); } /* * Flush if at end of buffer */ at = e->marker - e->buffer; if ( len + at >= e->bufsize ) { syck_emitter_flush( e, 0 ); for (;;) { long rest = e->bufsize - (e->marker - e->buffer); if (len <= rest) break; S_MEMCPY( e->marker, str, char, rest ); e->marker += rest; str += rest; len -= rest; syck_emitter_flush( e, 0 ); } } /* * Write to buffer */ S_MEMCPY( e->marker, str, char, len ); e->marker += len; } /* * Write a chunk of data out. */ void syck_emitter_flush( SyckEmitter *e, long check_room ) { /* * Check for enough space in the buffer for check_room length. */ if ( check_room > 0 ) { if ( e->bufsize > ( e->marker - e->buffer ) + check_room ) { return; } } else { check_room = e->bufsize; } /* * Commit buffer. */ if ( check_room > e->marker - e->buffer ) { check_room = e->marker - e->buffer; } (e->output_handler)( e, e->buffer, check_room ); e->bufpos += check_room; e->marker -= check_room; } /* * Start emitting from the given node, check for anchoring and then * issue the callback to the emitter handler. */ void syck_emit( SyckEmitter *e, st_data_t n ) { SYMID oid; char *anchor_name = NULL; int indent = 0; long x = 0; SyckLevel *lvl = syck_emitter_current_level( e ); /* * Determine headers. */ if ( e->stage == doc_open && ( e->headless == 0 || e->use_header == 1 ) ) { if ( e->use_version == 1 ) { char *header = S_ALLOC_N( char, 64 ); S_MEMZERO( header, char, 64 ); sprintf( header, "--- %%YAML:%d.%d ", SYCK_YAML_MAJOR, SYCK_YAML_MINOR ); syck_emitter_write( e, header, strlen( header ) ); S_FREE( header ); } else { syck_emitter_write( e, "--- ", 4 ); } e->stage = doc_processing; } /* Add new level */ if ( lvl->spaces >= 0 ) { indent = lvl->spaces + e->indent; } syck_emitter_add_level( e, indent, syck_lvl_open ); lvl = syck_emitter_current_level( e ); /* Look for anchor */ if ( e->anchors != NULL && st_lookup( e->markers, n, (st_data_t *)&oid ) && st_lookup( e->anchors, (st_data_t)oid, (st_data_t *)&anchor_name ) ) { if ( e->anchored == NULL ) { e->anchored = st_init_numtable(); } if ( ! st_lookup( e->anchored, (st_data_t)anchor_name, (st_data_t *)&x ) ) { char *an = S_ALLOC_N( char, strlen( anchor_name ) + 3 ); sprintf( an, "&%s ", anchor_name ); syck_emitter_write( e, an, strlen( anchor_name ) + 2 ); free( an ); x = 1; st_insert( e->anchored, (st_data_t)anchor_name, (st_data_t)x ); lvl->anctag = 1; } else { char *an = S_ALLOC_N( char, strlen( anchor_name ) + 2 ); sprintf( an, "*%s", anchor_name ); syck_emitter_write( e, an, strlen( anchor_name ) + 1 ); free( an ); goto end_emit; } } (e->emitter_handler)( e, n ); /* Pop the level */ end_emit: syck_emitter_pop_level( e ); if ( e->lvl_idx == 1 ) { syck_emitter_write( e, "\n", 1 ); e->headless = 0; e->stage = doc_open; } } /* * Determine what tag needs to be written, based on the taguri of the node * and the implicit tag which would be assigned to this node. If a tag is * required, write the tag. */ void syck_emit_tag( SyckEmitter *e, char *tag, char *ignore ) { SyckLevel *lvl; if ( tag == NULL ) return; if ( ignore != NULL && syck_tagcmp( tag, ignore ) == 0 && e->explicit_typing == 0 ) return; lvl = syck_emitter_current_level( e ); /* implicit */ if ( strlen( tag ) == 0 ) { syck_emitter_write( e, "! ", 2 ); /* global types */ } else if ( strncmp( tag, "tag:", 4 ) == 0 ) { int taglen = strlen( tag ); syck_emitter_write( e, "!", 1 ); if ( strncmp( tag + 4, YAML_DOMAIN, strlen( YAML_DOMAIN ) ) == 0 ) { int skip = 4 + strlen( YAML_DOMAIN ) + 1; syck_emitter_write( e, tag + skip, taglen - skip ); } else { char *subd = tag + 4; while ( *subd != ':' && *subd != '\0' ) subd++; if ( *subd == ':' ) { if ( subd - tag > ( strlen( YAML_DOMAIN ) + 5 ) && strncmp( subd - strlen( YAML_DOMAIN ), YAML_DOMAIN, strlen( YAML_DOMAIN ) ) == 0 ) { syck_emitter_write( e, tag + 4, subd - strlen( YAML_DOMAIN ) - ( tag + 4 ) - 1 ); syck_emitter_write( e, "/", 1 ); syck_emitter_write( e, subd + 1, ( tag + taglen ) - ( subd + 1 ) ); } else { syck_emitter_write( e, tag + 4, subd - ( tag + 4 ) ); syck_emitter_write( e, "/", 1 ); syck_emitter_write( e, subd + 1, ( tag + taglen ) - ( subd + 1 ) ); } } else { /* TODO: Invalid tag (no colon after domain) */ return; } } syck_emitter_write( e, " ", 1 ); /* private types */ } else if ( strncmp( tag, "x-private:", 10 ) == 0 ) { syck_emitter_write( e, "!!", 2 ); syck_emitter_write( e, tag + 10, strlen( tag ) - 10 ); syck_emitter_write( e, " ", 1 ); } lvl->anctag = 1; } /* * Emit a newline and an appropriately spaced indent. */ void syck_emit_indent( SyckEmitter *e ) { int i; SyckLevel *lvl = syck_emitter_current_level( e ); if ( e->bufpos == 0 && ( e->marker - e->buffer ) == 0 ) return; if ( lvl->spaces >= 0 ) { char *spcs = S_ALLOC_N( char, lvl->spaces + 2 ); spcs[0] = '\n'; spcs[lvl->spaces + 1] = '\0'; for ( i = 0; i < lvl->spaces; i++ ) spcs[i+1] = ' '; syck_emitter_write( e, spcs, lvl->spaces + 1 ); free( spcs ); } } /* Clear the scan */ #define SCAN_NONE 0 /* All printable characters? */ #define SCAN_NONPRINT 1 /* Any indented lines? */ #define SCAN_INDENTED 2 /* Larger than the requested width? */ #define SCAN_WIDE 4 /* Opens or closes with whitespace? */ #define SCAN_WHITEEDGE 8 /* Contains a newline */ #define SCAN_NEWLINE 16 /* Contains a single quote */ #define SCAN_SINGLEQ 32 /* Contains a double quote */ #define SCAN_DOUBLEQ 64 /* Starts with a token */ #define SCAN_INDIC_S 128 /* Contains a flow indicator */ #define SCAN_INDIC_C 256 /* Ends without newlines */ #define SCAN_NONL_E 512 /* Ends with many newlines */ #define SCAN_MANYNL_E 1024 /* Contains flow map indicators */ #define SCAN_FLOWMAP 2048 /* Contains flow seq indicators */ #define SCAN_FLOWSEQ 4096 /* Contains a valid doc separator */ #define SCAN_DOCSEP 8192 /* * Basic printable test for LATIN-1 characters. */ int syck_scan_scalar( int req_width, char *cursor, long len ) { long i = 0, start = 0; int flags = SCAN_NONE; if ( len < 1 ) return flags; /* c-indicators from the spec */ if ( cursor[0] == '[' || cursor[0] == ']' || cursor[0] == '{' || cursor[0] == '}' || cursor[0] == '!' || cursor[0] == '*' || cursor[0] == '&' || cursor[0] == '|' || cursor[0] == '>' || cursor[0] == '\'' || cursor[0] == '"' || cursor[0] == '#' || cursor[0] == '%' || cursor[0] == '@' || cursor[0] == '&' ) { flags |= SCAN_INDIC_S; } if ( ( cursor[0] == '-' || cursor[0] == ':' || cursor[0] == '?' || cursor[0] == ',' ) && ( len == 1 || cursor[1] == ' ' || cursor[1] == '\n' ) ) { flags |= SCAN_INDIC_S; } /* whitespace edges */ if ( cursor[len-1] != '\n' ) { flags |= SCAN_NONL_E; } else if ( len > 1 && cursor[len-2] == '\n' ) { flags |= SCAN_MANYNL_E; } if ( ( len > 0 && ( cursor[0] == ' ' || cursor[0] == '\t' ) ) || ( len > 1 && ( cursor[len-1] == ' ' || cursor[len-1] == '\t' ) ) ) { flags |= SCAN_WHITEEDGE; } /* opening doc sep */ if ( len >= 3 && strncmp( cursor, "---", 3 ) == 0 ) flags |= SCAN_DOCSEP; /* scan string */ for ( i = 0; i < len; i++ ) { if ( ! ( cursor[i] == 0x9 || cursor[i] == 0xA || cursor[i] == 0xD || ( cursor[i] >= 0x20 && cursor[i] <= 0x7E ) ) ) { flags |= SCAN_NONPRINT; } else if ( cursor[i] == '\n' ) { flags |= SCAN_NEWLINE; if ( len - i >= 3 && strncmp( &cursor[i+1], "---", 3 ) == 0 ) flags |= SCAN_DOCSEP; if ( cursor[i+1] == ' ' || cursor[i+1] == '\t' ) flags |= SCAN_INDENTED; if ( req_width > 0 && i - start > req_width ) flags |= SCAN_WIDE; start = i; } else if ( cursor[i] == '\'' ) { flags |= SCAN_SINGLEQ; } else if ( cursor[i] == '"' ) { flags |= SCAN_DOUBLEQ; } else if ( cursor[i] == ']' ) { flags |= SCAN_FLOWSEQ; } else if ( cursor[i] == '}' ) { flags |= SCAN_FLOWMAP; } /* remember, if plain collections get implemented, to add nb-plain-flow-char */ else if ( ( cursor[i] == ' ' && cursor[i+1] == '#' ) || ( cursor[i] == ':' && ( cursor[i+1] == ' ' || cursor[i+1] == '\n' || i == len - 1 ) ) ) { flags |= SCAN_INDIC_C; } else if ( cursor[i] == ',' && ( cursor[i+1] == ' ' || cursor[i+1] == '\n' || i == len - 1 ) ) { flags |= SCAN_FLOWMAP; flags |= SCAN_FLOWSEQ; } } /* printf( "---STR---\n%s\nFLAGS: %d\n", cursor, flags ); */ return flags; } /* * All scalars should be emitted through this function, which determines an appropriate style, * tag and indent. */ void syck_emit_scalar( SyckEmitter *e, char *tag, enum scalar_style force_style, int force_indent, int force_width, char keep_nl, char *str, long len ) { enum scalar_style favor_style = scalar_literal; SyckLevel *parent = syck_emitter_parent_level( e ); SyckLevel *lvl = syck_emitter_current_level( e ); int scan = 0; char *implicit; if ( str == NULL ) str = ""; /* No empty nulls as map keys */ if ( len == 0 && ( parent->status == syck_lvl_map || parent->status == syck_lvl_imap ) && parent->ncount % 2 == 1 && syck_tagcmp( tag, "tag:yaml.org,2002:null" ) == 0 ) { str = "~"; len = 1; } scan = syck_scan_scalar( force_width, str, len ); implicit = syck_match_implicit( str, len ); /* quote strings which default to implicits */ implicit = syck_taguri( YAML_DOMAIN, implicit, strlen( implicit ) ); if ( syck_tagcmp( tag, implicit ) != 0 && syck_tagcmp( tag, "tag:yaml.org,2002:str" ) == 0 ) { force_style = scalar_2quote; } else { /* complex key */ if ( parent->status == syck_lvl_map && parent->ncount % 2 == 1 && ( !( tag == NULL || ( implicit != NULL && syck_tagcmp( tag, implicit ) == 0 && e->explicit_typing == 0 ) ) ) ) { syck_emitter_write( e, "? ", 2 ); parent->status = syck_lvl_mapx; } syck_emit_tag( e, tag, implicit ); } S_FREE( implicit ); /* if still arbitrary, sniff a good block style. */ if ( force_style == scalar_none ) { if ( scan & SCAN_NEWLINE ) { force_style = scalar_literal; } else { force_style = scalar_plain; } } if ( e->style == scalar_fold ) { favor_style = scalar_fold; } /* Determine block style */ if ( scan & SCAN_NONPRINT ) { force_style = scalar_2quote; } else if ( scan & SCAN_WHITEEDGE ) { force_style = scalar_2quote; } else if ( force_style != scalar_fold && ( scan & SCAN_INDENTED ) ) { force_style = scalar_literal; } else if ( force_style == scalar_plain && ( scan & SCAN_NEWLINE ) ) { force_style = favor_style; } else if ( force_style == scalar_plain && parent->status == syck_lvl_iseq && ( scan & SCAN_FLOWSEQ ) ) { force_style = scalar_2quote; } else if ( force_style == scalar_plain && parent->status == syck_lvl_imap && ( scan & SCAN_FLOWMAP ) ) { force_style = scalar_2quote; /* } else if ( force_style == scalar_fold && ( ! ( scan & SCAN_WIDE ) ) ) { force_style = scalar_literal; */ } else if ( force_style == scalar_plain && ( scan & SCAN_INDIC_S || scan & SCAN_INDIC_C ) ) { if ( scan & SCAN_NEWLINE ) { force_style = favor_style; } else { force_style = scalar_2quote; } } if ( force_indent > 0 ) { lvl->spaces = parent->spaces + force_indent; } else if ( scan & SCAN_DOCSEP ) { lvl->spaces = parent->spaces + e->indent; } /* For now, all ambiguous keys are going to be double-quoted */ if ( ( parent->status == syck_lvl_map || parent->status == syck_lvl_mapx ) && parent->ncount % 2 == 1 ) { if ( force_style != scalar_plain ) { force_style = scalar_2quote; } } /* If the parent is an inline, double quote anything complex */ if ( parent->status == syck_lvl_imap || parent->status == syck_lvl_iseq ) { if ( force_style != scalar_plain && force_style != scalar_1quote ) { force_style = scalar_2quote; } } /* Fix the ending newlines */ if ( scan & SCAN_NONL_E ) { keep_nl = NL_CHOMP; } else if ( scan & SCAN_MANYNL_E ) { keep_nl = NL_KEEP; } /* Write the text node */ switch ( force_style ) { case scalar_1quote: syck_emit_1quoted( e, force_width, str, len ); break; case scalar_none: case scalar_2quote: syck_emit_2quoted( e, force_width, str, len ); break; case scalar_fold: syck_emit_folded( e, force_width, keep_nl, str, len ); break; case scalar_literal: syck_emit_literal( e, keep_nl, str, len ); break; case scalar_plain: syck_emitter_write( e, str, len ); break; } if ( parent->status == syck_lvl_mapx ) { syck_emitter_write( e, "\n", 1 ); } } void syck_emitter_escape( SyckEmitter *e, char *src, long len ) { int i; for( i = 0; i < len; i++ ) { if( (src[i] < 0x20) || (0x7E < src[i]) ) { syck_emitter_write( e, "\\", 1 ); if( '\0' == src[i] ) syck_emitter_write( e, "0", 1 ); else { syck_emitter_write( e, "x", 1 ); syck_emitter_write( e, (char *)hex_table + ((src[i] & 0xF0) >> 4), 1 ); syck_emitter_write( e, (char *)hex_table + (src[i] & 0x0F), 1 ); } } else { syck_emitter_write( e, src + i, 1 ); if( '\\' == src[i] ) syck_emitter_write( e, "\\", 1 ); } } } /* * Outputs a single-quoted block. */ void syck_emit_1quoted( SyckEmitter *e, int width, char *str, long len ) { char do_indent = 0; char *mark = str; char *start = str; char *end = str; syck_emitter_write( e, "'", 1 ); while ( mark < str + len ) { if ( do_indent ) { syck_emit_indent( e ); do_indent = 0; } switch ( *mark ) { case '\'': syck_emitter_write( e, "'", 1 ); break; case '\n': end = mark + 1; if ( *start != ' ' && *start != '\n' && *end != '\n' && *end != ' ' ) { syck_emitter_write( e, "\n\n", 2 ); } else { syck_emitter_write( e, "\n", 1 ); } do_indent = 1; start = mark + 1; break; case ' ': if ( width > 0 && *start != ' ' && mark - end > width ) { do_indent = 1; end = mark + 1; } else { syck_emitter_write( e, " ", 1 ); } break; default: syck_emitter_write( e, mark, 1 ); break; } mark++; } syck_emitter_write( e, "'", 1 ); } /* * Outputs a double-quoted block. */ void syck_emit_2quoted( SyckEmitter *e, int width, char *str, long len ) { char do_indent = 0; char *mark = str; char *start = str; char *end = str; syck_emitter_write( e, "\"", 1 ); while ( mark < str + len ) { if ( do_indent > 0 ) { if ( do_indent == 2 ) { syck_emitter_write( e, "\\", 1 ); } syck_emit_indent( e ); do_indent = 0; } switch ( *mark ) { /* Escape sequences allowed within double quotes. */ case '"': syck_emitter_write( e, "\\\"", 2 ); break; case '\\': syck_emitter_write( e, "\\\\", 2 ); break; case '\0': syck_emitter_write( e, "\\0", 2 ); break; case '\a': syck_emitter_write( e, "\\a", 2 ); break; case '\b': syck_emitter_write( e, "\\b", 2 ); break; case '\f': syck_emitter_write( e, "\\f", 2 ); break; case '\r': syck_emitter_write( e, "\\r", 2 ); break; case '\t': syck_emitter_write( e, "\\t", 2 ); break; case '\v': syck_emitter_write( e, "\\v", 2 ); break; case 0x1b: syck_emitter_write( e, "\\e", 2 ); break; case '\n': end = mark + 1; syck_emitter_write( e, "\\n", 2 ); do_indent = 2; start = mark + 1; if ( start < str + len && ( *start == ' ' || *start == '\n' ) ) { do_indent = 0; } break; case ' ': if ( width > 0 && *start != ' ' && mark - end > width ) { do_indent = 1; end = mark + 1; } else { syck_emitter_write( e, " ", 1 ); } break; default: syck_emitter_escape( e, mark, 1 ); break; } mark++; } syck_emitter_write( e, "\"", 1 ); } /* * Outputs a literal block. */ void syck_emit_literal( SyckEmitter *e, char keep_nl, char *str, long len ) { char *mark = str; char *start = str; char *end = str; syck_emitter_write( e, "|", 1 ); if ( keep_nl == NL_CHOMP ) { syck_emitter_write( e, "-", 1 ); } else if ( keep_nl == NL_KEEP ) { syck_emitter_write( e, "+", 1 ); } syck_emit_indent( e ); while ( mark < str + len ) { if ( *mark == '\n' ) { end = mark; if ( *start != ' ' && *start != '\n' && *end != '\n' && *end != ' ' ) end += 1; syck_emitter_write( e, start, end - start ); if ( mark + 1 == str + len ) { if ( keep_nl != NL_KEEP ) syck_emitter_write( e, "\n", 1 ); } else { syck_emit_indent( e ); } start = mark + 1; } mark++; } end = str + len; if ( start < end ) { syck_emitter_write( e, start, end - start ); } } /* * Outputs a folded block. */ void syck_emit_folded( SyckEmitter *e, int width, char keep_nl, char *str, long len ) { char *mark = str; char *start = str; char *end = str; syck_emitter_write( e, ">", 1 ); if ( keep_nl == NL_CHOMP ) { syck_emitter_write( e, "-", 1 ); } else if ( keep_nl == NL_KEEP ) { syck_emitter_write( e, "+", 1 ); } syck_emit_indent( e ); if ( width <= 0 ) width = e->best_width; while ( mark < str + len ) { switch ( *mark ) { case '\n': syck_emitter_write( e, end, mark - end ); end = mark + 1; if ( *start != ' ' && *start != '\n' && *end != '\n' && *end != ' ' ) { syck_emitter_write( e, "\n", 1 ); } if ( mark + 1 == str + len ) { if ( keep_nl != NL_KEEP ) syck_emitter_write( e, "\n", 1 ); } else { syck_emit_indent( e ); } start = mark + 1; break; case ' ': if ( *start != ' ' ) { if ( mark - end > width ) { syck_emitter_write( e, end, mark - end ); syck_emit_indent( e ); end = mark + 1; } } break; } mark++; } if ( end < mark ) { syck_emitter_write( e, end, mark - end ); } } /* * Begins emission of a sequence. */ void syck_emit_seq( SyckEmitter *e, char *tag, enum seq_style style ) { SyckLevel *parent = syck_emitter_parent_level( e ); SyckLevel *lvl = syck_emitter_current_level( e ); syck_emit_tag( e, tag, "tag:yaml.org,2002:seq" ); if ( style == seq_inline || ( parent->status == syck_lvl_imap || parent->status == syck_lvl_iseq ) ) { syck_emitter_write( e, "[", 1 ); lvl->status = syck_lvl_iseq; } else { /* complex key */ if ( parent->status == syck_lvl_map && parent->ncount % 2 == 1 ) { syck_emitter_write( e, "? ", 2 ); parent->status = syck_lvl_mapx; } lvl->status = syck_lvl_seq; } } /* * Begins emission of a mapping. */ void syck_emit_map( SyckEmitter *e, char *tag, enum map_style style ) { SyckLevel *parent = syck_emitter_parent_level( e ); SyckLevel *lvl = syck_emitter_current_level( e ); syck_emit_tag( e, tag, "tag:yaml.org,2002:map" ); if ( style == map_inline || ( parent->status == syck_lvl_imap || parent->status == syck_lvl_iseq ) ) { syck_emitter_write( e, "{", 1 ); lvl->status = syck_lvl_imap; } else { /* complex key */ if ( parent->status == syck_lvl_map && parent->ncount % 2 == 1 ) { syck_emitter_write( e, "? ", 2 ); parent->status = syck_lvl_mapx; } lvl->status = syck_lvl_map; } } /* * Handles emitting of a collection item (for both * sequences and maps) */ void syck_emit_item( SyckEmitter *e, st_data_t n ) { SyckLevel *lvl = syck_emitter_current_level( e ); switch ( lvl->status ) { case syck_lvl_seq: { SyckLevel *parent = syck_emitter_parent_level( e ); /* seq-in-map shortcut -- the lvl->anctag check should be unneccesary but * there is a nasty shift/reduce in the parser on this point and * i'm not ready to tickle it. */ if ( lvl->anctag == 0 && parent->status == syck_lvl_map && lvl->ncount == 0 ) { lvl->spaces = parent->spaces; } /* seq-in-seq shortcut */ else if ( lvl->anctag == 0 && parent->status == syck_lvl_seq && lvl->ncount == 0 ) { int spcs = ( lvl->spaces - parent->spaces ) - 2; if ( spcs >= 0 ) { int i = 0; for ( i = 0; i < spcs; i++ ) { syck_emitter_write( e, " ", 1 ); } syck_emitter_write( e, "- ", 2 ); break; } } syck_emit_indent( e ); syck_emitter_write( e, "- ", 2 ); } break; case syck_lvl_iseq: { if ( lvl->ncount > 0 ) { syck_emitter_write( e, ", ", 2 ); } } break; case syck_lvl_map: { SyckLevel *parent = syck_emitter_parent_level( e ); /* map-in-seq shortcut */ if ( lvl->anctag == 0 && parent->status == syck_lvl_seq && lvl->ncount == 0 ) { int spcs = ( lvl->spaces - parent->spaces ) - 2; if ( spcs >= 0 ) { int i = 0; for ( i = 0; i < spcs; i++ ) { syck_emitter_write( e, " ", 1 ); } break; } } if ( lvl->ncount % 2 == 0 ) { syck_emit_indent( e ); } else { syck_emitter_write( e, ": ", 2 ); } } break; case syck_lvl_mapx: { if ( lvl->ncount % 2 == 0 ) { syck_emit_indent( e ); lvl->status = syck_lvl_map; } else { int i; if ( lvl->spaces > 0 ) { char *spcs = S_ALLOC_N( char, lvl->spaces + 1 ); spcs[lvl->spaces] = '\0'; for ( i = 0; i < lvl->spaces; i++ ) spcs[i] = ' '; syck_emitter_write( e, spcs, lvl->spaces ); S_FREE( spcs ); } syck_emitter_write( e, ": ", 2 ); } } break; case syck_lvl_imap: { if ( lvl->ncount > 0 ) { if ( lvl->ncount % 2 == 0 ) { syck_emitter_write( e, ", ", 2 ); } else { syck_emitter_write( e, ": ", 2 ); } } } break; default: break; } lvl->ncount++; syck_emit( e, n ); } /* * Closes emission of a collection. */ void syck_emit_end( SyckEmitter *e ) { SyckLevel *lvl = syck_emitter_current_level( e ); SyckLevel *parent = syck_emitter_parent_level( e ); switch ( lvl->status ) { case syck_lvl_seq: if ( lvl->ncount == 0 ) { syck_emitter_write( e, "[]\n", 3 ); } else if ( parent->status == syck_lvl_mapx ) { syck_emitter_write( e, "\n", 1 ); } break; case syck_lvl_iseq: syck_emitter_write( e, "]\n", 1 ); break; case syck_lvl_map: if ( lvl->ncount == 0 ) { syck_emitter_write( e, "{}\n", 3 ); } else if ( lvl->ncount % 2 == 1 ) { syck_emitter_write( e, ":\n", 1 ); } else if ( parent->status == syck_lvl_mapx ) { syck_emitter_write( e, "\n", 1 ); } break; case syck_lvl_imap: syck_emitter_write( e, "}\n", 1 ); break; default: break; } } /* * Fill markers table with emitter nodes in the * soon-to-be-emitted tree. */ SYMID syck_emitter_mark_node( SyckEmitter *e, st_data_t n ) { SYMID oid = 0; char *anchor_name = NULL; /* * Ensure markers table is initialized. */ if ( e->markers == NULL ) { e->markers = st_init_numtable(); } /* * Markers table initially marks the string position of the * object. Doesn't yet create an anchor, simply notes the * position. */ if ( ! st_lookup( e->markers, n, (st_data_t *)&oid ) ) { /* * Store all markers */ oid = e->markers->num_entries + 1; st_insert( e->markers, n, (st_data_t)oid ); } else { if ( e->anchors == NULL ) { e->anchors = st_init_numtable(); } if ( ! st_lookup( e->anchors, (st_data_t)oid, (st_data_t *)&anchor_name ) ) { int idx = 0; char *anc = ( e->anchor_format == NULL ? DEFAULT_ANCHOR_FORMAT : e->anchor_format ); /* * Second time hitting this object, let's give it an anchor */ idx = e->anchors->num_entries + 1; anchor_name = S_ALLOC_N( char, strlen( anc ) + 10 ); S_MEMZERO( anchor_name, char, strlen( anc ) + 10 ); sprintf( anchor_name, anc, idx ); /* * Insert into anchors table */ st_insert( e->anchors, (st_data_t)oid, (st_data_t)anchor_name ); } } return oid; } ================================================ FILE: ext/syck/extconf.rb ================================================ require 'mkmf' have_header( "st.h" ) create_makefile( "syck" ) ================================================ FILE: ext/syck/gram.c ================================================ /* A Bison parser, made by GNU Bison 1.875d. */ /* Skeleton parser for Yacc-like parsing with Bison, Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 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 2, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* As a special exception, when this file is copied by Bison into a Bison output file, you may use that output file without restriction. This special exception was added by the Free Software Foundation in version 1.24 of Bison. */ /* Written by Richard Stallman by simplifying the original so called ``semantic'' parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 1 /* Using locations. */ #define YYLSP_NEEDED 0 /* If NAME_PREFIX is specified substitute the variables and functions names. */ #define yyparse syckparse #define yylex sycklex #define yyerror syckerror #define yylval sycklval #define yychar syckchar #define yydebug syckdebug #define yynerrs sycknerrs /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum yytokentype { YAML_ANCHOR = 258, YAML_ALIAS = 259, YAML_TRANSFER = 260, YAML_TAGURI = 261, YAML_ITRANSFER = 262, YAML_WORD = 263, YAML_PLAIN = 264, YAML_BLOCK = 265, YAML_DOCSEP = 266, YAML_IOPEN = 267, YAML_INDENT = 268, YAML_IEND = 269 }; #endif #define YAML_ANCHOR 258 #define YAML_ALIAS 259 #define YAML_TRANSFER 260 #define YAML_TAGURI 261 #define YAML_ITRANSFER 262 #define YAML_WORD 263 #define YAML_PLAIN 264 #define YAML_BLOCK 265 #define YAML_DOCSEP 266 #define YAML_IOPEN 267 #define YAML_INDENT 268 #define YAML_IEND 269 /* Copy the first part of user declarations. */ #line 14 "gram.y" #include "syck.h" void apply_seq_in_map( SyckParser *parser, SyckNode *n ); #define YYPARSE_PARAM parser #define YYLEX_PARAM parser #define NULL_NODE(parser, node) \ SyckNode *node = syck_new_str( "", scalar_plain ); \ if ( ((SyckParser *)parser)->taguri_expansion == 1 ) \ { \ node->type_id = syck_taguri( YAML_DOMAIN, "null", 4 ); \ } \ else \ { \ node->type_id = syck_strndup( "null", 4 ); \ } /* Enabling traces. */ #ifndef YYDEBUG # define YYDEBUG 1 #endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else # define YYERROR_VERBOSE 0 #endif #if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) #line 35 "gram.y" typedef union YYSTYPE { SYMID nodeId; SyckNode *nodeData; char *name; } YYSTYPE; /* Line 191 of yacc.c. */ #line 140 "gram.c" # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 # define YYSTYPE_IS_TRIVIAL 1 #endif /* Copy the second part of user declarations. */ /* Line 214 of yacc.c. */ #line 152 "gram.c" #if ! defined (yyoverflow) || YYERROR_VERBOSE # ifndef YYFREE # define YYFREE free # endif # ifndef YYMALLOC # define YYMALLOC malloc # endif /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # define YYSTACK_ALLOC alloca # endif # else # if defined (alloca) || defined (_ALLOCA_H) # define YYSTACK_ALLOC alloca # else # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's `empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # else # if defined (__STDC__) || defined (__cplusplus) # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # endif # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # endif #endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */ #if (! defined (yyoverflow) \ && (! defined (__cplusplus) \ || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { short int yyss; YYSTYPE yyvs; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (short int) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY # if defined (__GNUC__) && 1 < __GNUC__ # define YYCOPY(To, From, Count) \ __builtin_memcpy (To, From, (Count) * sizeof (*(From))) # else # define YYCOPY(To, From, Count) \ do \ { \ register YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (To)[yyi] = (From)[yyi]; \ } \ while (0) # endif # endif /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack, Stack, yysize); \ Stack = &yyptr->Stack; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (0) #endif #if defined (__STDC__) || defined (__cplusplus) typedef signed char yysigned_char; #else typedef short int yysigned_char; #endif /* YYFINAL -- State number of the termination state. */ #define YYFINAL 52 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 396 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 23 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 29 /* YYNRULES -- Number of rules. */ #define YYNRULES 79 /* YYNRULES -- Number of states. */ #define YYNSTATES 128 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 269 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ static const unsigned char yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 21, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 17, 2, 18, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 19, 2, 20, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; #if YYDEBUG /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in YYRHS. */ static const unsigned char yyprhs[] = { 0, 0, 3, 5, 8, 9, 11, 13, 15, 18, 21, 24, 28, 30, 32, 36, 37, 40, 43, 46, 49, 51, 54, 56, 58, 60, 63, 66, 69, 72, 75, 77, 79, 81, 85, 87, 89, 91, 93, 95, 99, 103, 106, 110, 113, 117, 120, 124, 127, 129, 133, 136, 140, 143, 145, 149, 151, 153, 157, 161, 165, 168, 172, 175, 179, 182, 184, 188, 190, 194, 196, 200, 204, 207, 211, 215, 218, 220, 224, 226 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yysigned_char yyrhs[] = { 24, 0, -1, 25, -1, 11, 27, -1, -1, 33, -1, 26, -1, 34, -1, 5, 26, -1, 6, 26, -1, 3, 26, -1, 29, 26, 32, -1, 25, -1, 28, -1, 29, 28, 30, -1, -1, 7, 28, -1, 5, 28, -1, 6, 28, -1, 3, 28, -1, 12, -1, 29, 13, -1, 14, -1, 13, -1, 14, -1, 31, 32, -1, 5, 33, -1, 6, 33, -1, 7, 33, -1, 3, 33, -1, 4, -1, 8, -1, 9, -1, 29, 33, 32, -1, 10, -1, 35, -1, 39, -1, 42, -1, 49, -1, 29, 37, 30, -1, 29, 38, 30, -1, 15, 27, -1, 5, 31, 38, -1, 5, 37, -1, 6, 31, 38, -1, 6, 37, -1, 3, 31, 38, -1, 3, 37, -1, 36, -1, 38, 31, 36, -1, 38, 31, -1, 17, 40, 18, -1, 17, 18, -1, 41, -1, 40, 21, 41, -1, 25, -1, 48, -1, 29, 43, 30, -1, 29, 47, 30, -1, 5, 31, 47, -1, 5, 43, -1, 6, 31, 47, -1, 6, 43, -1, 3, 31, 47, -1, 3, 43, -1, 33, -1, 22, 25, 31, -1, 27, -1, 44, 16, 45, -1, 46, -1, 47, 31, 36, -1, 47, 31, 46, -1, 47, 31, -1, 25, 16, 27, -1, 19, 50, 20, -1, 19, 20, -1, 51, -1, 50, 21, 51, -1, 25, -1, 48, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const unsigned short int yyrline[] = { 0, 56, 56, 60, 65, 70, 71, 74, 75, 80, 85, 94, 100, 101, 104, 109, 113, 121, 126, 131, 145, 146, 149, 152, 155, 156, 164, 169, 174, 182, 186, 194, 207, 208, 218, 219, 220, 221, 222, 228, 232, 238, 244, 249, 254, 259, 264, 268, 274, 278, 283, 292, 296, 302, 306, 313, 314, 320, 325, 332, 337, 342, 347, 352, 356, 362, 363, 369, 379, 396, 397, 409, 417, 426, 434, 438, 444, 445, 454, 461 }; #endif #if YYDEBUG || YYERROR_VERBOSE /* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "$end", "error", "$undefined", "YAML_ANCHOR", "YAML_ALIAS", "YAML_TRANSFER", "YAML_TAGURI", "YAML_ITRANSFER", "YAML_WORD", "YAML_PLAIN", "YAML_BLOCK", "YAML_DOCSEP", "YAML_IOPEN", "YAML_INDENT", "YAML_IEND", "'-'", "':'", "'['", "']'", "'{'", "'}'", "','", "'?'", "$accept", "doc", "atom", "ind_rep", "atom_or_empty", "empty", "indent_open", "indent_end", "indent_sep", "indent_flex_end", "word_rep", "struct_rep", "implicit_seq", "basic_seq", "top_imp_seq", "in_implicit_seq", "inline_seq", "in_inline_seq", "inline_seq_atom", "implicit_map", "top_imp_map", "complex_key", "complex_value", "complex_mapping", "in_implicit_map", "basic_mapping", "inline_map", "in_inline_map", "inline_map_atom", 0 }; #endif # ifdef YYPRINT /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to token YYLEX-NUM. */ static const unsigned short int yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 45, 58, 91, 93, 123, 125, 44, 63 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const unsigned char yyr1[] = { 0, 23, 24, 24, 24, 25, 25, 26, 26, 26, 26, 26, 27, 27, 28, 28, 28, 28, 28, 28, 29, 29, 30, 31, 32, 32, 33, 33, 33, 33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 35, 35, 36, 37, 37, 37, 37, 37, 37, 38, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 43, 43, 43, 43, 44, 44, 45, 46, 47, 47, 47, 47, 48, 49, 49, 50, 50, 51, 51 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const unsigned char yyr2[] = { 0, 2, 1, 2, 0, 1, 1, 1, 2, 2, 2, 3, 1, 1, 3, 0, 2, 2, 2, 2, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 3, 2, 3, 2, 3, 2, 3, 2, 1, 3, 2, 3, 2, 1, 3, 1, 1, 3, 3, 3, 2, 3, 2, 3, 2, 1, 3, 1, 3, 1, 3, 3, 2, 3, 3, 2, 1, 3, 1, 1 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state STATE-NUM when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const unsigned char yydefact[] = { 4, 0, 30, 0, 0, 0, 31, 32, 34, 15, 20, 0, 0, 0, 2, 6, 0, 5, 7, 35, 36, 37, 38, 10, 29, 8, 26, 9, 27, 0, 0, 0, 0, 28, 15, 15, 15, 15, 12, 3, 13, 15, 52, 55, 0, 53, 56, 75, 78, 79, 0, 76, 1, 0, 0, 0, 21, 15, 0, 0, 65, 48, 0, 0, 0, 0, 69, 0, 0, 19, 17, 18, 15, 15, 15, 16, 15, 15, 15, 15, 0, 15, 51, 0, 74, 0, 23, 0, 47, 64, 0, 43, 60, 0, 45, 62, 41, 0, 24, 0, 11, 33, 22, 39, 40, 50, 57, 15, 58, 72, 14, 73, 54, 77, 65, 46, 63, 42, 59, 44, 61, 66, 25, 49, 67, 68, 70, 71 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yysigned_char yydefgoto[] = { -1, 13, 38, 15, 39, 40, 16, 103, 99, 101, 17, 18, 19, 61, 62, 63, 20, 44, 45, 21, 64, 65, 125, 66, 67, 46, 22, 50, 51 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ #define YYPACT_NINF -97 static const short int yypact[] = { 250, 318, -97, 318, 318, 374, -97, -97, -97, 335, -97, 267, 232, 7, -97, -97, 192, -97, -97, -97, -97, -97, -97, -97, -97, -97, -97, -97, -97, 374, 374, 374, 352, -97, 335, 335, 335, 384, -97, -97, -97, 212, -97, 10, 0, -97, -97, -97, 10, -97, -4, -97, -97, 284, 284, 284, -97, 335, 318, 30, 30, -97, -2, 36, -2, 16, -97, 36, 30, -97, -97, -97, 384, 384, 384, -97, 363, 301, 301, 301, -2, 335, -97, 318, -97, 318, -97, 158, -97, -97, 158, -97, -97, 158, -97, -97, -97, 24, -97, 30, -97, -97, -97, -97, -97, 26, -97, 335, -97, 158, -97, -97, -97, -97, -97, 24, 24, 24, 24, 24, 24, -97, -97, -97, -97, -97, -97, -97 }; /* YYPGOTO[NTERM-NUM]. */ static const yysigned_char yypgoto[] = { -97, -97, 8, 81, -56, 109, 33, -53, 74, -54, -1, -97, -97, -96, -31, -32, -97, -97, -44, -97, 77, -97, -97, -52, 9, -6, -97, -97, -29 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If zero, do what YYDEFACT says. If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -1 static const unsigned char yytable[] = { 24, 96, 26, 28, 33, 100, 49, 52, 14, 123, 104, 106, 102, 126, 108, 60, 84, 85, 82, 43, 48, 83, 88, 91, 94, 111, 81, 110, 24, 26, 28, 68, 107, 24, 26, 28, 33, 86, 32, 112, 60, 57, 41, 86, 98, 122, 88, 91, 94, 86, 102, 124, 24, 26, 28, 115, 113, 127, 117, 0, 0, 119, 32, 32, 32, 32, 97, 41, 41, 41, 76, 24, 26, 28, 41, 68, 24, 26, 28, 49, 0, 0, 23, 0, 25, 27, 114, 0, 0, 114, 41, 43, 114, 48, 0, 0, 116, 59, 0, 118, 0, 0, 120, 0, 0, 76, 76, 76, 114, 76, 41, 41, 41, 0, 41, 23, 25, 27, 0, 0, 32, 0, 59, 32, 0, 0, 32, 87, 90, 93, 89, 92, 95, 0, 23, 25, 27, 105, 0, 0, 41, 109, 32, 69, 70, 71, 75, 0, 0, 0, 80, 87, 90, 93, 89, 92, 95, 0, 23, 25, 27, 29, 2, 30, 31, 5, 6, 7, 0, 0, 10, 121, 0, 57, 0, 0, 0, 0, 0, 0, 58, 69, 70, 71, 0, 80, 69, 70, 71, 105, 109, 105, 109, 105, 109, 53, 2, 54, 55, 5, 6, 7, 8, 0, 10, 56, 0, 57, 0, 11, 0, 12, 0, 0, 58, 77, 2, 78, 79, 37, 6, 7, 8, 0, 10, 56, 0, 57, 0, 11, 0, 12, 0, 0, 58, 1, 2, 3, 4, 5, 6, 7, 8, 0, 10, 0, 0, 0, 0, 11, 0, 12, 47, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0, 0, 11, 0, 12, 1, 2, 3, 4, 5, 6, 7, 8, 0, 10, 0, 0, 0, 0, 11, 42, 12, 53, 2, 54, 55, 5, 6, 7, 8, 0, 10, 86, 0, 0, 0, 11, 0, 12, 77, 2, 78, 79, 37, 6, 7, 8, 0, 10, 86, 0, 0, 0, 11, 0, 12, 1, 2, 3, 4, 5, 6, 7, 8, 0, 10, 0, 0, 0, 0, 11, 0, 12, 34, 2, 35, 36, 37, 6, 7, 8, 0, 10, 0, 0, 0, 0, 11, 0, 12, 29, 2, 30, 31, 5, 6, 7, 0, 0, 10, 56, 72, 2, 73, 74, 37, 6, 7, 0, 0, 10, 56, 29, 2, 30, 31, 5, 6, 7, 0, 0, 10, 72, 2, 73, 74, 37, 6, 7, 0, 0, 10 }; static const yysigned_char yycheck[] = { 1, 57, 3, 4, 5, 59, 12, 0, 0, 105, 63, 64, 14, 109, 67, 16, 20, 21, 18, 11, 12, 21, 53, 54, 55, 81, 16, 80, 29, 30, 31, 32, 16, 34, 35, 36, 37, 13, 5, 83, 41, 15, 9, 13, 14, 99, 77, 78, 79, 13, 14, 107, 53, 54, 55, 87, 85, 109, 90, -1, -1, 93, 29, 30, 31, 32, 58, 34, 35, 36, 37, 72, 73, 74, 41, 76, 77, 78, 79, 85, -1, -1, 1, -1, 3, 4, 87, -1, -1, 90, 57, 83, 93, 85, -1, -1, 87, 16, -1, 90, -1, -1, 93, -1, -1, 72, 73, 74, 109, 76, 77, 78, 79, -1, 81, 34, 35, 36, -1, -1, 87, -1, 41, 90, -1, -1, 93, 53, 54, 55, 53, 54, 55, -1, 53, 54, 55, 63, -1, -1, 107, 67, 109, 34, 35, 36, 37, -1, -1, -1, 41, 77, 78, 79, 77, 78, 79, -1, 77, 78, 79, 3, 4, 5, 6, 7, 8, 9, -1, -1, 12, 97, -1, 15, -1, -1, -1, -1, -1, -1, 22, 72, 73, 74, -1, 76, 77, 78, 79, 115, 116, 117, 118, 119, 120, 3, 4, 5, 6, 7, 8, 9, 10, -1, 12, 13, -1, 15, -1, 17, -1, 19, -1, -1, 22, 3, 4, 5, 6, 7, 8, 9, 10, -1, 12, 13, -1, 15, -1, 17, -1, 19, -1, -1, 22, 3, 4, 5, 6, 7, 8, 9, 10, -1, 12, -1, -1, -1, -1, 17, -1, 19, 20, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, -1, -1, -1, -1, 17, -1, 19, 3, 4, 5, 6, 7, 8, 9, 10, -1, 12, -1, -1, -1, -1, 17, 18, 19, 3, 4, 5, 6, 7, 8, 9, 10, -1, 12, 13, -1, -1, -1, 17, -1, 19, 3, 4, 5, 6, 7, 8, 9, 10, -1, 12, 13, -1, -1, -1, 17, -1, 19, 3, 4, 5, 6, 7, 8, 9, 10, -1, 12, -1, -1, -1, -1, 17, -1, 19, 3, 4, 5, 6, 7, 8, 9, 10, -1, 12, -1, -1, -1, -1, 17, -1, 19, 3, 4, 5, 6, 7, 8, 9, -1, -1, 12, 13, 3, 4, 5, 6, 7, 8, 9, -1, -1, 12, 13, 3, 4, 5, 6, 7, 8, 9, -1, -1, 12, 3, 4, 5, 6, 7, 8, 9, -1, -1, 12 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const unsigned char yystos[] = { 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 17, 19, 24, 25, 26, 29, 33, 34, 35, 39, 42, 49, 26, 33, 26, 33, 26, 33, 3, 5, 6, 29, 33, 3, 5, 6, 7, 25, 27, 28, 29, 18, 25, 40, 41, 48, 20, 25, 48, 50, 51, 0, 3, 5, 6, 13, 15, 22, 26, 33, 36, 37, 38, 43, 44, 46, 47, 33, 28, 28, 28, 3, 5, 6, 28, 29, 3, 5, 6, 28, 16, 18, 21, 20, 21, 13, 31, 37, 43, 31, 37, 43, 31, 37, 43, 27, 25, 14, 31, 32, 32, 14, 30, 30, 31, 30, 16, 30, 31, 30, 27, 41, 51, 33, 38, 47, 38, 47, 38, 47, 31, 32, 36, 27, 45, 36, 46 }; #if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) # define YYSIZE_T __SIZE_TYPE__ #endif #if ! defined (YYSIZE_T) && defined (size_t) # define YYSIZE_T size_t #endif #if ! defined (YYSIZE_T) # if defined (__STDC__) || defined (__cplusplus) # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # endif #endif #if ! defined (YYSIZE_T) # define YYSIZE_T unsigned int #endif #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto yyerrlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY && yylen == 1) \ { \ yychar = (Token); \ yylval = (Value); \ yytoken = YYTRANSLATE (yychar); \ YYPOPSTACK; \ goto yybackup; \ } \ else \ { \ yyerror ("syntax error: cannot back up");\ YYERROR; \ } \ while (0) #define YYTERROR 1 #define YYERRCODE 256 /* YYLLOC_DEFAULT -- Compute the default location (before the actions are run). */ #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ ((Current).first_line = (Rhs)[1].first_line, \ (Current).first_column = (Rhs)[1].first_column, \ (Current).last_line = (Rhs)[N].last_line, \ (Current).last_column = (Rhs)[N].last_column) #endif /* YYLEX -- calling `yylex' with the right arguments. */ #ifdef YYLEX_PARAM # define YYLEX yylex (&yylval, YYLEX_PARAM) #else # define YYLEX yylex (&yylval) #endif /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) # define YYDSYMPRINT(Args) \ do { \ if (yydebug) \ yysymprint Args; \ } while (0) # define YYDSYMPRINTF(Title, Token, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yysymprint (stderr, \ Token, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ #if defined (__STDC__) || defined (__cplusplus) static void yy_stack_print (short int *bottom, short int *top) #else static void yy_stack_print (bottom, top) short int *bottom; short int *top; #endif { YYFPRINTF (stderr, "Stack now"); for (/* Nothing. */; bottom <= top; ++bottom) YYFPRINTF (stderr, " %d", *bottom); YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ #if defined (__STDC__) || defined (__cplusplus) static void yy_reduce_print (int yyrule) #else static void yy_reduce_print (yyrule) int yyrule; #endif { int yyi; unsigned int yylno = yyrline[yyrule]; YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ", yyrule - 1, yylno); /* Print the symbols being reduced, and their result. */ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++) YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]); YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]); } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (Rule); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YYDSYMPRINT(Args) # define YYDSYMPRINTF(Title, Token, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #if defined (YYMAXDEPTH) && YYMAXDEPTH == 0 # undef YYMAXDEPTH #endif #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined (__GLIBC__) && defined (_STRING_H) # define yystrlen strlen # else /* Return the length of YYSTR. */ static YYSIZE_T # if defined (__STDC__) || defined (__cplusplus) yystrlen (const char *yystr) # else yystrlen (yystr) const char *yystr; # endif { register const char *yys = yystr; while (*yys++ != '\0') continue; return yys - yystr - 1; } # endif # endif # ifndef yystpcpy # if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ static char * # if defined (__STDC__) || defined (__cplusplus) yystpcpy (char *yydest, const char *yysrc) # else yystpcpy (yydest, yysrc) char *yydest; const char *yysrc; # endif { register char *yyd = yydest; register const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif #endif /* !YYERROR_VERBOSE */ #if YYDEBUG /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ #if defined (__STDC__) || defined (__cplusplus) static void yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep) #else static void yysymprint (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE *yyvaluep; #endif { /* Pacify ``unused variable'' warnings. */ (void) yyvaluep; if (yytype < YYNTOKENS) { YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); # ifdef YYPRINT YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # endif } else YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); switch (yytype) { default: break; } YYFPRINTF (yyoutput, ")"); } #endif /* ! YYDEBUG */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ #if defined (__STDC__) || defined (__cplusplus) static void yydestruct (int yytype, YYSTYPE *yyvaluep) #else static void yydestruct (yytype, yyvaluep) int yytype; YYSTYPE *yyvaluep; #endif { /* Pacify ``unused variable'' warnings. */ (void) yyvaluep; switch (yytype) { default: break; } } /* Prevent warnings from -Wmissing-prototypes. */ #ifdef YYPARSE_PARAM # if defined (__STDC__) || defined (__cplusplus) int yyparse (void *YYPARSE_PARAM); # else int yyparse (); # endif #else /* ! YYPARSE_PARAM */ #if defined (__STDC__) || defined (__cplusplus) int yyparse (void); #else int yyparse (); #endif #endif /* ! YYPARSE_PARAM */ /*----------. | yyparse. | `----------*/ #ifdef YYPARSE_PARAM # if defined (__STDC__) || defined (__cplusplus) int yyparse (void *YYPARSE_PARAM) # else int yyparse (YYPARSE_PARAM) void *YYPARSE_PARAM; # endif #else /* ! YYPARSE_PARAM */ #if defined (__STDC__) || defined (__cplusplus) int yyparse (void) #else int yyparse () #endif #endif { /* The lookahead symbol. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; register int yystate; register int yyn; int yyresult; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* Lookahead token as an internal (translated) token number. */ int yytoken = 0; /* Three stacks and their tools: `yyss': related to states, `yyvs': related to semantic values, `yyls': related to locations. Refer to the stacks thru separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ short int yyssa[YYINITDEPTH]; short int *yyss = yyssa; register short int *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; register YYSTYPE *yyvsp; #define YYPOPSTACK (yyvsp--, yyssp--) YYSIZE_T yystacksize = YYINITDEPTH; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; /* When reducing, the number of symbols on the RHS of the reduced rule. */ int yylen; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ yyssp = yyss; yyvsp = yyvs; goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. so pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; short int *yyss1 = yyss; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow ("parser stack overflow", &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyoverflowlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyoverflowlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { short int *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyoverflowlab; YYSTACK_RELOCATE (yyss); YYSTACK_RELOCATE (yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. */ /* Read a lookahead token if we need one and don't already have one. */ /* yyresume: */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yyn == YYPACT_NINF) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = YYLEX; } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yyn == 0 || yyn == YYTABLE_NINF) goto yyerrlab; yyn = -yyn; goto yyreduce; } if (yyn == YYFINAL) YYACCEPT; /* Shift the lookahead token. */ YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken])); /* Discard the token being shifted unless it is eof. */ if (yychar != YYEOF) yychar = YYEMPTY; *++yyvsp = yylval; /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; yystate = yyn; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: `$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 2: #line 57 "gram.y" { ((SyckParser *)parser)->root = syck_hdlr_add_node( (SyckParser *)parser, yyvsp[0].nodeData ); } break; case 3: #line 61 "gram.y" { ((SyckParser *)parser)->root = syck_hdlr_add_node( (SyckParser *)parser, yyvsp[0].nodeData ); } break; case 4: #line 65 "gram.y" { ((SyckParser *)parser)->eof = 1; } break; case 8: #line 76 "gram.y" { syck_add_transfer( yyvsp[-1].name, yyvsp[0].nodeData, ((SyckParser *)parser)->taguri_expansion ); yyval.nodeData = yyvsp[0].nodeData; } break; case 9: #line 81 "gram.y" { syck_add_transfer( yyvsp[-1].name, yyvsp[0].nodeData, 0 ); yyval.nodeData = yyvsp[0].nodeData; } break; case 10: #line 86 "gram.y" { /* * _Anchors_: The language binding must keep a separate symbol table * for anchors. The actual ID in the symbol table is returned to the * higher nodes, though. */ yyval.nodeData = syck_hdlr_add_anchor( (SyckParser *)parser, yyvsp[-1].name, yyvsp[0].nodeData ); } break; case 11: #line 95 "gram.y" { yyval.nodeData = yyvsp[-1].nodeData; } break; case 14: #line 105 "gram.y" { yyval.nodeData = yyvsp[-1].nodeData; } break; case 15: #line 109 "gram.y" { NULL_NODE( parser, n ); yyval.nodeData = n; } break; case 16: #line 114 "gram.y" { if ( ((SyckParser *)parser)->implicit_typing == 1 ) { try_tag_implicit( yyvsp[0].nodeData, ((SyckParser *)parser)->taguri_expansion ); } yyval.nodeData = yyvsp[0].nodeData; } break; case 17: #line 122 "gram.y" { syck_add_transfer( yyvsp[-1].name, yyvsp[0].nodeData, ((SyckParser *)parser)->taguri_expansion ); yyval.nodeData = yyvsp[0].nodeData; } break; case 18: #line 127 "gram.y" { syck_add_transfer( yyvsp[-1].name, yyvsp[0].nodeData, 0 ); yyval.nodeData = yyvsp[0].nodeData; } break; case 19: #line 132 "gram.y" { /* * _Anchors_: The language binding must keep a separate symbol table * for anchors. The actual ID in the symbol table is returned to the * higher nodes, though. */ yyval.nodeData = syck_hdlr_add_anchor( (SyckParser *)parser, yyvsp[-1].name, yyvsp[0].nodeData ); } break; case 26: #line 165 "gram.y" { syck_add_transfer( yyvsp[-1].name, yyvsp[0].nodeData, ((SyckParser *)parser)->taguri_expansion ); yyval.nodeData = yyvsp[0].nodeData; } break; case 27: #line 170 "gram.y" { syck_add_transfer( yyvsp[-1].name, yyvsp[0].nodeData, 0 ); yyval.nodeData = yyvsp[0].nodeData; } break; case 28: #line 175 "gram.y" { if ( ((SyckParser *)parser)->implicit_typing == 1 ) { try_tag_implicit( yyvsp[0].nodeData, ((SyckParser *)parser)->taguri_expansion ); } yyval.nodeData = yyvsp[0].nodeData; } break; case 29: #line 183 "gram.y" { yyval.nodeData = syck_hdlr_add_anchor( (SyckParser *)parser, yyvsp[-1].name, yyvsp[0].nodeData ); } break; case 30: #line 187 "gram.y" { /* * _Aliases_: The anchor symbol table is scanned for the anchor name. * The anchor's ID in the language's symbol table is returned. */ yyval.nodeData = syck_hdlr_get_anchor( (SyckParser *)parser, yyvsp[0].name ); } break; case 31: #line 195 "gram.y" { SyckNode *n = yyvsp[0].nodeData; if ( ((SyckParser *)parser)->taguri_expansion == 1 ) { n->type_id = syck_taguri( YAML_DOMAIN, "str", 3 ); } else { n->type_id = syck_strndup( "str", 3 ); } yyval.nodeData = n; } break; case 33: #line 209 "gram.y" { yyval.nodeData = yyvsp[-1].nodeData; } break; case 39: #line 229 "gram.y" { yyval.nodeData = yyvsp[-1].nodeData; } break; case 40: #line 233 "gram.y" { yyval.nodeData = yyvsp[-1].nodeData; } break; case 41: #line 239 "gram.y" { yyval.nodeId = syck_hdlr_add_node( (SyckParser *)parser, yyvsp[0].nodeData ); } break; case 42: #line 245 "gram.y" { syck_add_transfer( yyvsp[-2].name, yyvsp[0].nodeData, ((SyckParser *)parser)->taguri_expansion ); yyval.nodeData = yyvsp[0].nodeData; } break; case 43: #line 250 "gram.y" { syck_add_transfer( yyvsp[-1].name, yyvsp[0].nodeData, ((SyckParser *)parser)->taguri_expansion ); yyval.nodeData = yyvsp[0].nodeData; } break; case 44: #line 255 "gram.y" { syck_add_transfer( yyvsp[-2].name, yyvsp[0].nodeData, 0 ); yyval.nodeData = yyvsp[0].nodeData; } break; case 45: #line 260 "gram.y" { syck_add_transfer( yyvsp[-1].name, yyvsp[0].nodeData, 0 ); yyval.nodeData = yyvsp[0].nodeData; } break; case 46: #line 265 "gram.y" { yyval.nodeData = syck_hdlr_add_anchor( (SyckParser *)parser, yyvsp[-2].name, yyvsp[0].nodeData ); } break; case 47: #line 269 "gram.y" { yyval.nodeData = syck_hdlr_add_anchor( (SyckParser *)parser, yyvsp[-1].name, yyvsp[0].nodeData ); } break; case 48: #line 275 "gram.y" { yyval.nodeData = syck_new_seq( yyvsp[0].nodeId ); } break; case 49: #line 279 "gram.y" { syck_seq_add( yyvsp[-2].nodeData, yyvsp[0].nodeId ); yyval.nodeData = yyvsp[-2].nodeData; } break; case 50: #line 284 "gram.y" { yyval.nodeData = yyvsp[-1].nodeData; } break; case 51: #line 293 "gram.y" { yyval.nodeData = yyvsp[-1].nodeData; } break; case 52: #line 297 "gram.y" { yyval.nodeData = syck_alloc_seq(); } break; case 53: #line 303 "gram.y" { yyval.nodeData = syck_new_seq( syck_hdlr_add_node( (SyckParser *)parser, yyvsp[0].nodeData ) ); } break; case 54: #line 307 "gram.y" { syck_seq_add( yyvsp[-2].nodeData, syck_hdlr_add_node( (SyckParser *)parser, yyvsp[0].nodeData ) ); yyval.nodeData = yyvsp[-2].nodeData; } break; case 57: #line 321 "gram.y" { apply_seq_in_map( (SyckParser *)parser, yyvsp[-1].nodeData ); yyval.nodeData = yyvsp[-1].nodeData; } break; case 58: #line 326 "gram.y" { apply_seq_in_map( (SyckParser *)parser, yyvsp[-1].nodeData ); yyval.nodeData = yyvsp[-1].nodeData; } break; case 59: #line 333 "gram.y" { syck_add_transfer( yyvsp[-2].name, yyvsp[0].nodeData, ((SyckParser *)parser)->taguri_expansion ); yyval.nodeData = yyvsp[0].nodeData; } break; case 60: #line 338 "gram.y" { syck_add_transfer( yyvsp[-1].name, yyvsp[0].nodeData, ((SyckParser *)parser)->taguri_expansion ); yyval.nodeData = yyvsp[0].nodeData; } break; case 61: #line 343 "gram.y" { syck_add_transfer( yyvsp[-2].name, yyvsp[0].nodeData, 0 ); yyval.nodeData = yyvsp[0].nodeData; } break; case 62: #line 348 "gram.y" { syck_add_transfer( yyvsp[-1].name, yyvsp[0].nodeData, 0 ); yyval.nodeData = yyvsp[0].nodeData; } break; case 63: #line 353 "gram.y" { yyval.nodeData = syck_hdlr_add_anchor( (SyckParser *)parser, yyvsp[-2].name, yyvsp[0].nodeData ); } break; case 64: #line 357 "gram.y" { yyval.nodeData = syck_hdlr_add_anchor( (SyckParser *)parser, yyvsp[-1].name, yyvsp[0].nodeData ); } break; case 66: #line 364 "gram.y" { yyval.nodeData = yyvsp[-1].nodeData; } break; case 68: #line 380 "gram.y" { yyval.nodeData = syck_new_map( syck_hdlr_add_node( (SyckParser *)parser, yyvsp[-2].nodeData ), syck_hdlr_add_node( (SyckParser *)parser, yyvsp[0].nodeData ) ); } break; case 70: #line 398 "gram.y" { if ( yyvsp[-2].nodeData->shortcut == NULL ) { yyvsp[-2].nodeData->shortcut = syck_new_seq( yyvsp[0].nodeId ); } else { syck_seq_add( yyvsp[-2].nodeData->shortcut, yyvsp[0].nodeId ); } yyval.nodeData = yyvsp[-2].nodeData; } break; case 71: #line 410 "gram.y" { apply_seq_in_map( (SyckParser *)parser, yyvsp[-2].nodeData ); syck_map_update( yyvsp[-2].nodeData, yyvsp[0].nodeData ); syck_free_node( yyvsp[0].nodeData ); yyvsp[0].nodeData = NULL; yyval.nodeData = yyvsp[-2].nodeData; } break; case 72: #line 418 "gram.y" { yyval.nodeData = yyvsp[-1].nodeData; } break; case 73: #line 427 "gram.y" { yyval.nodeData = syck_new_map( syck_hdlr_add_node( (SyckParser *)parser, yyvsp[-2].nodeData ), syck_hdlr_add_node( (SyckParser *)parser, yyvsp[0].nodeData ) ); } break; case 74: #line 435 "gram.y" { yyval.nodeData = yyvsp[-1].nodeData; } break; case 75: #line 439 "gram.y" { yyval.nodeData = syck_alloc_map(); } break; case 77: #line 446 "gram.y" { syck_map_update( yyvsp[-2].nodeData, yyvsp[0].nodeData ); syck_free_node( yyvsp[0].nodeData ); yyvsp[0].nodeData = NULL; yyval.nodeData = yyvsp[-2].nodeData; } break; case 78: #line 455 "gram.y" { NULL_NODE( parser, n ); yyval.nodeData = syck_new_map( syck_hdlr_add_node( (SyckParser *)parser, yyvsp[0].nodeData ), syck_hdlr_add_node( (SyckParser *)parser, n ) ); } break; } /* Line 1010 of yacc.c. */ #line 1651 "gram.c" yyvsp -= yylen; yyssp -= yylen; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*------------------------------------. | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if YYERROR_VERBOSE yyn = yypact[yystate]; if (YYPACT_NINF < yyn && yyn < YYLAST) { YYSIZE_T yysize = 0; int yytype = YYTRANSLATE (yychar); const char* yyprefix; char *yymsg; int yyx; /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yycount = 0; yyprefix = ", expecting "; for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) { yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]); yycount += 1; if (yycount == 5) { yysize = 0; break; } } yysize += (sizeof ("syntax error, unexpected ") + yystrlen (yytname[yytype])); yymsg = (char *) YYSTACK_ALLOC (yysize); if (yymsg != 0) { char *yyp = yystpcpy (yymsg, "syntax error, unexpected "); yyp = yystpcpy (yyp, yytname[yytype]); if (yycount < 5) { yyprefix = ", expecting "; for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) { yyp = yystpcpy (yyp, yyprefix); yyp = yystpcpy (yyp, yytname[yyx]); yyprefix = " or "; } } yyerror (yymsg); YYSTACK_FREE (yymsg); } else yyerror ("syntax error; also virtual memory exhausted"); } else #endif /* YYERROR_VERBOSE */ yyerror ("syntax error"); } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* If at end of input, pop the error token, then the rest of the stack, then return failure. */ if (yychar == YYEOF) for (;;) { YYPOPSTACK; if (yyssp == yyss) YYABORT; YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); yydestruct (yystos[*yyssp], yyvsp); } } else { YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc); yydestruct (yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: #ifdef __GNUC__ /* Pacify GCC when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (0) goto yyerrorlab; #endif yyvsp -= yylen; yyssp -= yylen; yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (yyn != YYPACT_NINF) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); yydestruct (yystos[yystate], yyvsp); YYPOPSTACK; yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } if (yyn == YYFINAL) YYACCEPT; YYDPRINTF ((stderr, "Shifting error token, ")); *++yyvsp = yylval; yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #ifndef yyoverflow /*----------------------------------------------. | yyoverflowlab -- parser overflow comes here. | `----------------------------------------------*/ yyoverflowlab: yyerror ("parser stack overflow"); yyresult = 2; /* Fall through. */ #endif yyreturn: #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif return yyresult; } #line 464 "gram.y" void apply_seq_in_map( SyckParser *parser, SyckNode *n ) { long map_len; if ( n->shortcut == NULL ) { return; } map_len = syck_map_count( n ); syck_map_assign( n, map_value, map_len - 1, syck_hdlr_add_node( parser, n->shortcut ) ); n->shortcut = NULL; } ================================================ FILE: ext/syck/gram.h ================================================ /* A Bison parser, made by GNU Bison 1.875d. */ /* Skeleton parser for Yacc-like parsing with Bison, Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 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 2, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* As a special exception, when this file is copied by Bison into a Bison output file, you may use that output file without restriction. This special exception was added by the Free Software Foundation in version 1.24 of Bison. */ /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum yytokentype { YAML_ANCHOR = 258, YAML_ALIAS = 259, YAML_TRANSFER = 260, YAML_TAGURI = 261, YAML_ITRANSFER = 262, YAML_WORD = 263, YAML_PLAIN = 264, YAML_BLOCK = 265, YAML_DOCSEP = 266, YAML_IOPEN = 267, YAML_INDENT = 268, YAML_IEND = 269 }; #endif #define YAML_ANCHOR 258 #define YAML_ALIAS 259 #define YAML_TRANSFER 260 #define YAML_TAGURI 261 #define YAML_ITRANSFER 262 #define YAML_WORD 263 #define YAML_PLAIN 264 #define YAML_BLOCK 265 #define YAML_DOCSEP 266 #define YAML_IOPEN 267 #define YAML_INDENT 268 #define YAML_IEND 269 #if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) #line 35 "gram.y" typedef union YYSTYPE { SYMID nodeId; SyckNode *nodeData; char *name; } YYSTYPE; /* Line 1285 of yacc.c. */ #line 71 "gram.h" # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 # define YYSTYPE_IS_TRIVIAL 1 #endif ================================================ FILE: ext/syck/handler.c ================================================ /* * handler.c * * $Author$ * $Date$ * * Copyright (C) 2003 why the lucky stiff */ #include "ruby.h" #include "syck.h" SYMID syck_hdlr_add_node( SyckParser *p, SyckNode *n ) { SYMID id; if ( ! n->id ) { n->id = (p->handler)( p, n ); } id = n->id; if ( n->anchor == NULL ) { syck_free_node( n ); } return id; } SyckNode * syck_hdlr_add_anchor( SyckParser *p, char *a, SyckNode *n ) { SyckNode *ntmp = NULL; n->anchor = a; if ( p->bad_anchors != NULL ) { SyckNode *bad; if ( st_lookup( p->bad_anchors, (st_data_t)a, (st_data_t *)&bad ) ) { if ( n->kind != syck_str_kind ) { n->id = bad->id; (p->handler)( p, n ); } } } if ( p->anchors == NULL ) { p->anchors = st_init_strtable(); } if ( st_lookup( p->anchors, (st_data_t)a, (st_data_t *)&ntmp ) ) { if ( ntmp != (void *)1 ) { syck_free_node( ntmp ); } } st_insert( p->anchors, (st_data_t)a, (st_data_t)n ); return n; } void syck_hdlr_remove_anchor( SyckParser *p, char *a ) { char *atmp = a; SyckNode *ntmp; if ( p->anchors == NULL ) { p->anchors = st_init_strtable(); } if ( st_delete( p->anchors, (st_data_t *)&atmp, (st_data_t *)&ntmp ) ) { if ( ntmp != (void *)1 ) { syck_free_node( ntmp ); } } st_insert( p->anchors, (st_data_t)a, (st_data_t)1 ); } SyckNode * syck_hdlr_get_anchor( SyckParser *p, char *a ) { SyckNode *n = NULL; if ( p->anchors != NULL ) { if ( st_lookup( p->anchors, (st_data_t)a, (st_data_t *)&n ) ) { if ( n != (void *)1 ) { S_FREE( a ); return n; } else { if ( p->bad_anchors == NULL ) { p->bad_anchors = st_init_strtable(); } if ( ! st_lookup( p->bad_anchors, (st_data_t)a, (st_data_t *)&n ) ) { n = (p->bad_anchor_handler)( p, a ); st_insert( p->bad_anchors, (st_data_t)a, (st_data_t)n ); } } } } if ( n == NULL ) { n = (p->bad_anchor_handler)( p, a ); } if ( n->anchor ) { S_FREE( a ); } else { n->anchor = a; } return n; } void syck_add_transfer( char *uri, SyckNode *n, int taguri ) { if ( n->type_id != NULL ) { S_FREE( n->type_id ); } if ( taguri == 0 ) { n->type_id = uri; return; } n->type_id = syck_type_id_to_uri( uri ); S_FREE( uri ); } char * syck_xprivate( char *type_id, int type_len ) { char *uri = S_ALLOC_N( char, type_len + 14 ); uri[0] = '\0'; strcat( uri, "x-private:" ); strncat( uri, type_id, type_len ); return uri; } char * syck_taguri( char *domain, char *type_id, int type_len ) { char *uri = S_ALLOC_N( char, strlen( domain ) + type_len + 14 ); uri[0] = '\0'; strcat( uri, "tag:" ); strcat( uri, domain ); strcat( uri, ":" ); strncat( uri, type_id, type_len ); return uri; } int syck_try_implicit( SyckNode *n ) { return 1; } ================================================ FILE: ext/syck/implicit.c ================================================ /* Generated by re2c 0.9.10 on Mon Sep 19 21:46:50 2005 */ #line 1 "implicit.re" /* * implicit.re * * $Author$ * $Date$ * * Copyright (C) 2003 why the lucky stiff */ #include "ruby.h" #include "syck.h" #define YYCTYPE char #define YYCURSOR cursor #define YYMARKER marker #define YYLIMIT limit #define YYFILL(n) void try_tag_implicit( SyckNode *n, int taguri ) { char *tid = ""; switch ( n->kind ) { case syck_str_kind: tid = syck_match_implicit( n->data.str->ptr, n->data.str->len ); break; case syck_seq_kind: tid = "seq"; break; case syck_map_kind: tid = "map"; break; } if ( n->type_id != NULL ) S_FREE( n->type_id ); if ( taguri == 1 ) { n->type_id = syck_taguri( YAML_DOMAIN, tid, strlen( tid ) ); } else { n->type_id = syck_strndup( tid, strlen( tid ) ); } } char *syck_match_implicit( char *str, size_t len ) { char *cursor, *limit, *marker; cursor = str; limit = str + len; #line 55 "" { YYCTYPE yych; unsigned int yyaccept; goto yy0; ++YYCURSOR; yy0: if((YYLIMIT - YYCURSOR) < 26) YYFILL(26); yych = *YYCURSOR; switch(yych){ case 0x00: goto yy6; case '+': goto yy16; case '-': goto yy17; case '.': goto yy20; case '0': goto yy18; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy19; case '<': goto yy22; case '=': goto yy21; case 'F': goto yy15; case 'N': goto yy5; case 'O': goto yy13; case 'T': goto yy11; case 'Y': goto yy9; case 'f': goto yy14; case 'n': goto yy4; case 'o': goto yy12; case 't': goto yy10; case 'y': goto yy8; case '~': goto yy2; default: goto yy23; } yy2: ++YYCURSOR; if((yych = *YYCURSOR) <= 0x00) goto yy6; goto yy3; yy3: #line 123 "implicit.re" { return "str"; } #line 100 "" yy4: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 'o': goto yy172; case 'u': goto yy200; default: goto yy3; } yy5: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 'O': case 'o': goto yy172; case 'U': goto yy195; case 'u': goto yy196; default: goto yy3; } yy6: ++YYCURSOR; goto yy7; yy7: #line 85 "implicit.re" { return "null"; } #line 121 "" yy8: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 'e': goto yy194; default: goto yy3; } yy9: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 'E': goto yy192; case 'e': goto yy193; default: goto yy3; } yy10: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 'r': goto yy190; default: goto yy3; } yy11: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 'R': goto yy186; case 'r': goto yy187; default: goto yy3; } yy12: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 'f': goto yy185; case 'n': goto yy182; default: goto yy3; } yy13: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 'F': goto yy180; case 'N': case 'n': goto yy182; case 'f': goto yy181; default: goto yy3; } yy14: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 'a': goto yy177; default: goto yy3; } yy15: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 'A': goto yy168; case 'a': goto yy169; default: goto yy3; } yy16: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case '.': goto yy167; case '0': goto yy158; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy47; default: goto yy3; } yy17: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case '.': goto yy157; case '0': goto yy158; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy47; default: goto yy3; } yy18: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 0x00: goto yy52; case ',': goto yy142; case '.': goto yy50; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': goto yy140; case '8': case '9': goto yy141; case ':': goto yy49; case 'x': goto yy144; default: goto yy3; } yy19: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 0x00: goto yy52; case ',': goto yy47; case '.': goto yy50; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy46; case ':': goto yy49; default: goto yy3; } yy20: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 'I': goto yy33; case 'N': goto yy31; case 'i': goto yy32; case 'n': goto yy30; default: goto yy3; } yy21: yych = *++YYCURSOR; if(yych <= 0x00) goto yy28; goto yy3; yy22: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case '<': goto yy24; default: goto yy3; } yy23: yych = *++YYCURSOR; goto yy3; yy24: yych = *++YYCURSOR; if(yych <= 0x00) goto yy26; goto yy25; yy25: YYCURSOR = YYMARKER; switch(yyaccept){ case 0: goto yy3; } yy26: ++YYCURSOR; goto yy27; yy27: #line 121 "implicit.re" { return "merge"; } #line 279 "" yy28: ++YYCURSOR; goto yy29; yy29: #line 119 "implicit.re" { return "default"; } #line 285 "" yy30: yych = *++YYCURSOR; switch(yych){ case 'a': goto yy45; default: goto yy25; } yy31: yych = *++YYCURSOR; switch(yych){ case 'A': goto yy40; case 'a': goto yy41; default: goto yy25; } yy32: yych = *++YYCURSOR; switch(yych){ case 'n': goto yy39; default: goto yy25; } yy33: yych = *++YYCURSOR; switch(yych){ case 'N': goto yy34; case 'n': goto yy35; default: goto yy25; } yy34: yych = *++YYCURSOR; switch(yych){ case 'F': goto yy36; default: goto yy25; } yy35: yych = *++YYCURSOR; switch(yych){ case 'f': goto yy36; default: goto yy25; } yy36: yych = *++YYCURSOR; if(yych >= 0x01) goto yy25; goto yy37; yy37: ++YYCURSOR; goto yy38; yy38: #line 105 "implicit.re" { return "float#inf"; } #line 326 "" yy39: yych = *++YYCURSOR; switch(yych){ case 'f': goto yy36; default: goto yy25; } yy40: yych = *++YYCURSOR; switch(yych){ case 'N': goto yy42; default: goto yy25; } yy41: yych = *++YYCURSOR; switch(yych){ case 'N': goto yy42; default: goto yy25; } yy42: yych = *++YYCURSOR; if(yych >= 0x01) goto yy25; goto yy43; yy43: ++YYCURSOR; goto yy44; yy44: #line 109 "implicit.re" { return "float#nan"; } #line 350 "" yy45: yych = *++YYCURSOR; switch(yych){ case 'n': goto yy42; default: goto yy25; } yy46: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy74; default: goto yy48; } yy47: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy48; yy48: switch(yych){ case 0x00: goto yy52; case ',': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy47; case '.': goto yy50; case ':': goto yy49; default: goto yy25; } yy49: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': goto yy66; case '6': case '7': case '8': case '9': goto yy67; default: goto yy25; } yy50: ++YYCURSOR; if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); yych = *YYCURSOR; goto yy51; yy51: switch(yych){ case 0x00: goto yy56; case ',': goto yy54; case '.': goto yy58; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy50; case 'E': case 'e': goto yy60; default: goto yy25; } yy52: ++YYCURSOR; goto yy53; yy53: #line 97 "implicit.re" { return "int"; } #line 432 "" yy54: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy55; yy55: switch(yych){ case 0x00: goto yy56; case ',': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy54; default: goto yy25; } yy56: ++YYCURSOR; goto yy57; yy57: #line 99 "implicit.re" { return "float#fix"; } #line 456 "" yy58: ++YYCURSOR; if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); yych = *YYCURSOR; goto yy59; yy59: switch(yych){ case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy58; case 'E': case 'e': goto yy60; default: goto yy25; } yy60: yych = *++YYCURSOR; switch(yych){ case '+': case '-': goto yy61; default: goto yy25; } yy61: yych = *++YYCURSOR; if(yych <= 0x00) goto yy25; goto yy63; yy62: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy63; yy63: switch(yych){ case 0x00: goto yy64; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy62; default: goto yy25; } yy64: ++YYCURSOR; goto yy65; yy65: #line 101 "implicit.re" { return "float#exp"; } #line 506 "" yy66: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; switch(yych){ case 0x00: goto yy70; case '.': goto yy68; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy67; case ':': goto yy49; default: goto yy25; } yy67: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; switch(yych){ case 0x00: goto yy70; case '.': goto yy68; case ':': goto yy49; default: goto yy25; } yy68: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy69; yy69: switch(yych){ case 0x00: goto yy72; case ',': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy68; default: goto yy25; } yy70: ++YYCURSOR; goto yy71; yy71: #line 95 "implicit.re" { return "int#base60"; } #line 558 "" yy72: ++YYCURSOR; goto yy73; yy73: #line 103 "implicit.re" { return "float#base60"; } #line 564 "" yy74: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy75; default: goto yy48; } yy75: yych = *++YYCURSOR; switch(yych){ case '-': goto yy76; default: goto yy48; } yy76: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy77; default: goto yy25; } yy77: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy78; default: goto yy25; } yy78: yych = *++YYCURSOR; switch(yych){ case '-': goto yy79; default: goto yy25; } yy79: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy80; default: goto yy25; } yy80: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy81; default: goto yy25; } yy81: yych = *++YYCURSOR; switch(yych){ case 0x00: goto yy82; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy25; case 'T': goto yy84; case 't': goto yy85; default: goto yy87; } yy82: ++YYCURSOR; goto yy83; yy83: #line 111 "implicit.re" { return "timestamp#ymd"; } #line 667 "" yy84: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy126; default: goto yy25; } yy85: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy108; default: goto yy25; } yy86: ++YYCURSOR; if((YYLIMIT - YYCURSOR) < 9) YYFILL(9); yych = *YYCURSOR; goto yy87; yy87: switch(yych){ case 0x09: case ' ': goto yy86; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy88; default: goto yy25; } yy88: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy89; default: goto yy25; } yy89: yych = *++YYCURSOR; switch(yych){ case ':': goto yy90; default: goto yy25; } yy90: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy91; default: goto yy25; } yy91: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy92; default: goto yy25; } yy92: yych = *++YYCURSOR; switch(yych){ case ':': goto yy93; default: goto yy25; } yy93: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy94; default: goto yy25; } yy94: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy95; default: goto yy25; } yy95: yych = *++YYCURSOR; switch(yych){ case 0x09: case ' ': goto yy98; case '.': goto yy96; default: goto yy25; } yy96: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy97; yy97: switch(yych){ case 0x09: case ' ': goto yy98; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy96; default: goto yy25; } yy98: ++YYCURSOR; if((YYLIMIT - YYCURSOR) < 7) YYFILL(7); yych = *YYCURSOR; goto yy99; yy99: switch(yych){ case 0x09: case ' ': goto yy98; case '+': case '-': goto yy101; case 'Z': goto yy100; default: goto yy25; } yy100: yych = *++YYCURSOR; if(yych <= 0x00) goto yy105; goto yy25; yy101: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy102; default: goto yy25; } yy102: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy103; default: goto yy25; } yy103: yych = *++YYCURSOR; switch(yych){ case 0x00: goto yy105; case ':': goto yy104; default: goto yy25; } yy104: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy107; default: goto yy25; } yy105: ++YYCURSOR; goto yy106; yy106: #line 115 "implicit.re" { return "timestamp#spaced"; } #line 884 "" yy107: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy100; default: goto yy25; } yy108: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy109; default: goto yy25; } yy109: yych = *++YYCURSOR; switch(yych){ case ':': goto yy110; default: goto yy25; } yy110: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy111; default: goto yy25; } yy111: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy112; default: goto yy25; } yy112: yych = *++YYCURSOR; switch(yych){ case ':': goto yy113; default: goto yy25; } yy113: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy114; default: goto yy25; } yy114: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy115; default: goto yy25; } yy115: yych = *++YYCURSOR; switch(yych){ case '.': goto yy116; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy25; default: goto yy117; } yy116: ++YYCURSOR; if((YYLIMIT - YYCURSOR) < 7) YYFILL(7); yych = *YYCURSOR; goto yy117; yy117: switch(yych){ case '+': case '-': goto yy119; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy116; case 'Z': goto yy118; default: goto yy25; } yy118: yych = *++YYCURSOR; if(yych <= 0x00) goto yy123; goto yy25; yy119: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy120; default: goto yy25; } yy120: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy121; default: goto yy25; } yy121: yych = *++YYCURSOR; switch(yych){ case 0x00: goto yy123; case ':': goto yy122; default: goto yy25; } yy122: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy125; default: goto yy25; } yy123: ++YYCURSOR; goto yy124; yy124: #line 113 "implicit.re" { return "timestamp#iso8601"; } #line 1069 "" yy125: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy118; default: goto yy25; } yy126: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy127; default: goto yy25; } yy127: yych = *++YYCURSOR; switch(yych){ case ':': goto yy128; default: goto yy25; } yy128: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy129; default: goto yy25; } yy129: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy130; default: goto yy25; } yy130: yych = *++YYCURSOR; switch(yych){ case ':': goto yy131; default: goto yy25; } yy131: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy132; default: goto yy25; } yy132: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy133; default: goto yy25; } yy133: yych = *++YYCURSOR; switch(yych){ case '.': goto yy134; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy25; case 'Z': goto yy136; default: goto yy135; } yy134: ++YYCURSOR; if((YYLIMIT - YYCURSOR) < 7) YYFILL(7); yych = *YYCURSOR; goto yy135; yy135: switch(yych){ case '+': case '-': goto yy119; case '0': goto yy134; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy138; case 'Z': goto yy118; default: goto yy25; } yy136: yych = *++YYCURSOR; if(yych >= 0x01) goto yy25; goto yy137; yy137: yych = *++YYCURSOR; goto yy124; yy138: ++YYCURSOR; if((YYLIMIT - YYCURSOR) < 7) YYFILL(7); yych = *YYCURSOR; goto yy139; yy139: switch(yych){ case '+': case '-': goto yy119; case '0': goto yy134; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy138; case 'Z': goto yy136; default: goto yy25; } yy140: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': goto yy155; case '8': case '9': goto yy153; default: goto yy143; } yy141: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy153; default: goto yy152; } yy142: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy143; yy143: switch(yych){ case 0x00: goto yy149; case ',': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': goto yy142; case '.': goto yy50; case '8': case '9': goto yy151; case ':': goto yy49; default: goto yy25; } yy144: yych = *++YYCURSOR; if(yych <= 0x00) goto yy25; goto yy146; yy145: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy146; yy146: switch(yych){ case 0x00: goto yy147; case ',': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': goto yy145; default: goto yy25; } yy147: ++YYCURSOR; goto yy148; yy148: #line 91 "implicit.re" { return "int#hex"; } #line 1307 "" yy149: ++YYCURSOR; goto yy150; yy150: #line 93 "implicit.re" { return "int#oct"; } #line 1313 "" yy151: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy152; yy152: switch(yych){ case ',': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy151; case '.': goto yy50; case ':': goto yy49; default: goto yy25; } yy153: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy154; default: goto yy152; } yy154: yych = *++YYCURSOR; switch(yych){ case '-': goto yy76; default: goto yy152; } yy155: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': goto yy156; case '8': case '9': goto yy154; default: goto yy143; } yy156: yych = *++YYCURSOR; switch(yych){ case '-': goto yy76; default: goto yy143; } yy157: yych = *++YYCURSOR; switch(yych){ case 'I': goto yy160; case 'i': goto yy159; default: goto yy25; } yy158: yych = *++YYCURSOR; switch(yych){ case 0x00: goto yy52; case 'x': goto yy144; default: goto yy143; } yy159: yych = *++YYCURSOR; switch(yych){ case 'n': goto yy166; default: goto yy25; } yy160: yych = *++YYCURSOR; switch(yych){ case 'N': goto yy161; case 'n': goto yy162; default: goto yy25; } yy161: yych = *++YYCURSOR; switch(yych){ case 'F': goto yy163; default: goto yy25; } yy162: yych = *++YYCURSOR; switch(yych){ case 'f': goto yy163; default: goto yy25; } yy163: yych = *++YYCURSOR; if(yych >= 0x01) goto yy25; goto yy164; yy164: ++YYCURSOR; goto yy165; yy165: #line 107 "implicit.re" { return "float#neginf"; } #line 1412 "" yy166: yych = *++YYCURSOR; switch(yych){ case 'f': goto yy163; default: goto yy25; } yy167: yych = *++YYCURSOR; switch(yych){ case 'I': goto yy33; case 'i': goto yy32; default: goto yy25; } yy168: yych = *++YYCURSOR; switch(yych){ case 'L': goto yy175; default: goto yy25; } yy169: yych = *++YYCURSOR; switch(yych){ case 'l': goto yy170; default: goto yy25; } yy170: yych = *++YYCURSOR; switch(yych){ case 's': goto yy171; default: goto yy25; } yy171: yych = *++YYCURSOR; switch(yych){ case 'e': goto yy172; default: goto yy25; } yy172: yych = *++YYCURSOR; if(yych >= 0x01) goto yy25; goto yy173; yy173: ++YYCURSOR; goto yy174; yy174: #line 89 "implicit.re" { return "bool#no"; } #line 1452 "" yy175: yych = *++YYCURSOR; switch(yych){ case 'S': goto yy176; default: goto yy25; } yy176: yych = *++YYCURSOR; switch(yych){ case 'E': goto yy172; default: goto yy25; } yy177: yych = *++YYCURSOR; switch(yych){ case 'l': goto yy178; default: goto yy25; } yy178: yych = *++YYCURSOR; switch(yych){ case 's': goto yy179; default: goto yy25; } yy179: yych = *++YYCURSOR; switch(yych){ case 'e': goto yy172; default: goto yy25; } yy180: yych = *++YYCURSOR; switch(yych){ case 'F': goto yy172; default: goto yy25; } yy181: yych = *++YYCURSOR; switch(yych){ case 'f': goto yy172; default: goto yy25; } yy182: yych = *++YYCURSOR; if(yych >= 0x01) goto yy25; goto yy183; yy183: ++YYCURSOR; goto yy184; yy184: #line 87 "implicit.re" { return "bool#yes"; } #line 1496 "" yy185: yych = *++YYCURSOR; switch(yych){ case 'f': goto yy172; default: goto yy25; } yy186: yych = *++YYCURSOR; switch(yych){ case 'U': goto yy189; default: goto yy25; } yy187: yych = *++YYCURSOR; switch(yych){ case 'u': goto yy188; default: goto yy25; } yy188: yych = *++YYCURSOR; switch(yych){ case 'e': goto yy182; default: goto yy25; } yy189: yych = *++YYCURSOR; switch(yych){ case 'E': goto yy182; default: goto yy25; } yy190: yych = *++YYCURSOR; switch(yych){ case 'u': goto yy191; default: goto yy25; } yy191: yych = *++YYCURSOR; switch(yych){ case 'e': goto yy182; default: goto yy25; } yy192: yych = *++YYCURSOR; switch(yych){ case 'S': goto yy182; default: goto yy25; } yy193: yych = *++YYCURSOR; switch(yych){ case 's': goto yy182; default: goto yy25; } yy194: yych = *++YYCURSOR; switch(yych){ case 's': goto yy182; default: goto yy25; } yy195: yych = *++YYCURSOR; switch(yych){ case 'L': goto yy199; default: goto yy25; } yy196: yych = *++YYCURSOR; switch(yych){ case 'l': goto yy197; default: goto yy25; } yy197: yych = *++YYCURSOR; switch(yych){ case 'l': goto yy198; default: goto yy25; } yy198: yych = *++YYCURSOR; if(yych <= 0x00) goto yy6; goto yy25; yy199: yych = *++YYCURSOR; switch(yych){ case 'L': goto yy198; default: goto yy25; } yy200: yych = *++YYCURSOR; switch(yych){ case 'l': goto yy201; default: goto yy25; } yy201: ++YYCURSOR; switch((yych = *YYCURSOR)) { case 'l': goto yy198; default: goto yy25; } } #line 125 "implicit.re" } /* Remove ending fragment and compare types */ int syck_tagcmp( char *tag1, char *tag2 ) { if ( tag1 == tag2 ) return 1; if ( tag1 == NULL || tag2 == NULL ) return 0; else { int i; char *othorpe; char *tmp1 = syck_strndup( tag1, strlen( tag1 ) ); char *tmp2 = syck_strndup( tag2, strlen( tag2 ) ); othorpe = strstr( tmp1, "#" ); if ( othorpe != NULL ) { othorpe[0] = '\0'; } othorpe = strstr( tmp2, "#" ); if ( othorpe != NULL ) { othorpe[0] = '\0'; } i = strcmp( tmp1, tmp2 ); S_FREE( tmp1 ); S_FREE( tmp2 ); return i; } } char * syck_type_id_to_uri( char *type_id ) { char *cursor, *limit, *marker; cursor = type_id; limit = type_id + strlen( type_id ); #line 1620 "" { YYCTYPE yych; unsigned int yyaccept; goto yy202; ++YYCURSOR; yy202: if((YYLIMIT - YYCURSOR) < 11) YYFILL(11); yych = *YYCURSOR; switch(yych){ case 0x00: goto yy204; case '!': goto yy208; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 'u': case 'v': case 'w': case 'y': case 'z': goto yy210; case 't': goto yy205; case 'x': goto yy207; default: goto yy211; } yy204: YYCURSOR = YYMARKER; switch(yyaccept){ case 0: goto yy206; } yy205: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case ',': goto yy216; case '-': goto yy212; case '.': goto yy217; case '/': goto yy218; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy214; case 'a': goto yy246; default: goto yy206; } yy206: #line 202 "implicit.re" { return syck_taguri( YAML_DOMAIN, type_id, strlen( type_id ) ); } #line 1768 "" yy207: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case ',': case '.': case '/': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy215; case '-': goto yy236; default: goto yy206; } yy208: ++YYCURSOR; goto yy209; yy209: #line 176 "implicit.re" { return syck_xprivate( type_id + 1, strlen( type_id ) - 1 ); } #line 1842 "" yy210: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case ',': goto yy216; case '-': goto yy212; case '.': goto yy217; case '/': goto yy218; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy214; default: goto yy206; } yy211: yych = *++YYCURSOR; goto yy206; yy212: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy213; yy213: switch(yych){ case '-': goto yy212; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy214; default: goto yy204; } yy214: ++YYCURSOR; if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); yych = *YYCURSOR; goto yy215; yy215: switch(yych){ case ',': goto yy216; case '-': goto yy212; case '.': goto yy217; case '/': goto yy218; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy214; default: goto yy204; } yy216: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy224; default: goto yy204; } yy217: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy220; default: goto yy204; } yy218: ++YYCURSOR; goto yy219; yy219: #line 178 "implicit.re" { char *domain = S_ALLOC_N( char, ( YYCURSOR - type_id ) + 15 ); char *uri; domain[0] = '\0'; strncat( domain, type_id, ( YYCURSOR - type_id ) - 1 ); strcat( domain, "." ); strcat( domain, YAML_DOMAIN ); uri = syck_taguri( domain, YYCURSOR, YYLIMIT - YYCURSOR ); S_FREE( domain ); return uri; } #line 2149 "" yy220: ++YYCURSOR; if((YYLIMIT - YYCURSOR) < 12) YYFILL(12); yych = *YYCURSOR; goto yy221; yy221: switch(yych){ case ',': goto yy216; case '-': goto yy222; case '.': goto yy217; case '/': goto yy218; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy220; default: goto yy204; } yy222: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy223; yy223: switch(yych){ case '-': goto yy222; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy220; default: goto yy204; } yy224: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy225; default: goto yy204; } yy225: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy226; default: goto yy204; } yy226: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy227; default: goto yy204; } yy227: yych = *++YYCURSOR; switch(yych){ case '-': goto yy228; case '/': goto yy229; default: goto yy204; } yy228: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy231; default: goto yy204; } yy229: ++YYCURSOR; goto yy230; yy230: #line 191 "implicit.re" { char *domain = S_ALLOC_N( char, YYCURSOR - type_id ); char *uri; domain[0] = '\0'; strncat( domain, type_id, ( YYCURSOR - type_id ) - 1 ); uri = syck_taguri( domain, YYCURSOR, YYLIMIT - YYCURSOR ); S_FREE( domain ); return uri; } #line 2365 "" yy231: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy232; default: goto yy204; } yy232: yych = *++YYCURSOR; switch(yych){ case '-': goto yy233; case '/': goto yy229; default: goto yy204; } yy233: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy234; default: goto yy204; } yy234: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy235; default: goto yy204; } yy235: yych = *++YYCURSOR; switch(yych){ case '/': goto yy229; default: goto yy204; } yy236: yych = *++YYCURSOR; switch(yych){ case 'p': goto yy237; default: goto yy213; } yy237: yych = *++YYCURSOR; switch(yych){ case ',': goto yy216; case '.': goto yy217; case '/': goto yy218; case 'r': goto yy238; default: goto yy213; } yy238: yych = *++YYCURSOR; switch(yych){ case ',': goto yy216; case '.': goto yy217; case '/': goto yy218; case 'i': goto yy239; default: goto yy213; } yy239: yych = *++YYCURSOR; switch(yych){ case ',': goto yy216; case '.': goto yy217; case '/': goto yy218; case 'v': goto yy240; default: goto yy213; } yy240: yych = *++YYCURSOR; switch(yych){ case ',': goto yy216; case '.': goto yy217; case '/': goto yy218; case 'a': goto yy241; default: goto yy213; } yy241: yych = *++YYCURSOR; switch(yych){ case ',': goto yy216; case '.': goto yy217; case '/': goto yy218; case 't': goto yy242; default: goto yy213; } yy242: yych = *++YYCURSOR; switch(yych){ case ',': goto yy216; case '.': goto yy217; case '/': goto yy218; case 'e': goto yy243; default: goto yy213; } yy243: yych = *++YYCURSOR; switch(yych){ case ',': goto yy216; case '.': goto yy217; case '/': goto yy218; case ':': goto yy244; default: goto yy213; } yy244: ++YYCURSOR; goto yy245; yy245: #line 174 "implicit.re" { return syck_strndup( type_id, strlen( type_id ) ); } #line 2485 "" yy246: yych = *++YYCURSOR; switch(yych){ case ',': goto yy216; case '.': goto yy217; case '/': goto yy218; case 'g': goto yy247; default: goto yy213; } yy247: yych = *++YYCURSOR; switch(yych){ case ',': goto yy216; case '.': goto yy217; case '/': goto yy218; case ':': goto yy248; default: goto yy213; } yy248: yych = *++YYCURSOR; switch(yych){ case ',': case '-': case '.': goto yy204; default: goto yy250; } yy249: ++YYCURSOR; if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); yych = *YYCURSOR; goto yy250; yy250: switch(yych){ case ',': goto yy253; case '-': goto yy251; case '.': goto yy254; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy249; default: goto yy204; } yy251: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy252; yy252: switch(yych){ case '-': goto yy251; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy249; default: goto yy204; } yy253: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy259; default: goto yy204; } yy254: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy255; default: goto yy204; } yy255: ++YYCURSOR; if((YYLIMIT - YYCURSOR) < 12) YYFILL(12); yych = *YYCURSOR; goto yy256; yy256: switch(yych){ case ',': goto yy253; case '-': goto yy257; case '.': goto yy254; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy255; default: goto yy204; } yy257: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy258; yy258: switch(yych){ case '-': goto yy257; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy255; default: goto yy204; } yy259: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy260; default: goto yy204; } yy260: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy261; default: goto yy204; } yy261: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy262; default: goto yy204; } yy262: yych = *++YYCURSOR; switch(yych){ case '-': goto yy263; case ':': goto yy264; default: goto yy204; } yy263: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy266; default: goto yy204; } yy264: ++YYCURSOR; goto yy265; yy265: #line 172 "implicit.re" { return syck_strndup( type_id, strlen( type_id ) ); } #line 2932 "" yy266: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy267; default: goto yy204; } yy267: yych = *++YYCURSOR; switch(yych){ case '-': goto yy268; case ':': goto yy264; default: goto yy204; } yy268: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy269; default: goto yy204; } yy269: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy270; default: goto yy204; } yy270: ++YYCURSOR; switch((yych = *YYCURSOR)) { case ':': goto yy264; default: goto yy204; } } #line 204 "implicit.re" } ================================================ FILE: ext/syck/node.c ================================================ /* * node.c * * $Author$ * $Date$ * * Copyright (C) 2003 why the lucky stiff */ #include "ruby.h" #include "syck.h" /* * Node allocation functions */ SyckNode * syck_alloc_node( enum syck_kind_tag type ) { SyckNode *s; s = S_ALLOC( SyckNode ); s->kind = type; s->id = 0; s->type_id = NULL; s->anchor = NULL; s->shortcut = NULL; return s; } void syck_free_node( SyckNode *n ) { syck_free_members( n ); if ( n->type_id != NULL ) { S_FREE( n->type_id ); n->type_id = NULL; } if ( n->anchor != NULL ) { S_FREE( n->anchor ); n->anchor = NULL; } S_FREE( n ); } SyckNode * syck_alloc_map() { SyckNode *n; struct SyckMap *m; m = S_ALLOC( struct SyckMap ); m->style = map_none; m->idx = 0; m->capa = ALLOC_CT; m->keys = S_ALLOC_N( SYMID, m->capa ); m->values = S_ALLOC_N( SYMID, m->capa ); n = syck_alloc_node( syck_map_kind ); n->data.pairs = m; return n; } SyckNode * syck_alloc_seq() { SyckNode *n; struct SyckSeq *s; s = S_ALLOC( struct SyckSeq ); s->style = seq_none; s->idx = 0; s->capa = ALLOC_CT; s->items = S_ALLOC_N( SYMID, s->capa ); n = syck_alloc_node( syck_seq_kind ); n->data.list = s; return n; } SyckNode * syck_alloc_str() { SyckNode *n; struct SyckStr *s; s = S_ALLOC( struct SyckStr ); s->len = 0; s->ptr = NULL; s->style = scalar_none; n = syck_alloc_node( syck_str_kind ); n->data.str = s; return n; } SyckNode * syck_new_str( char *str, enum scalar_style style ) { return syck_new_str2( str, strlen( str ), style ); } SyckNode * syck_new_str2( char *str, long len, enum scalar_style style ) { SyckNode *n; n = syck_alloc_str(); n->data.str->ptr = S_ALLOC_N( char, len + 1 ); n->data.str->len = len; n->data.str->style = style; memcpy( n->data.str->ptr, str, len ); n->data.str->ptr[len] = '\0'; return n; } void syck_replace_str( SyckNode *n, char *str, enum scalar_style style ) { syck_replace_str2( n, str, strlen( str ), style ); } void syck_replace_str2( SyckNode *n, char *str, long len, enum scalar_style style ) { if ( n->data.str != NULL ) { S_FREE( n->data.str->ptr ); n->data.str->ptr = NULL; n->data.str->len = 0; } n->data.str->ptr = S_ALLOC_N( char, len + 1 ); n->data.str->len = len; n->data.str->style = style; memcpy( n->data.str->ptr, str, len ); n->data.str->ptr[len] = '\0'; } void syck_str_blow_away_commas( SyckNode *n ) { char *go, *end; go = n->data.str->ptr; end = go + n->data.str->len; while ( *(++go) != '\0' ) { if ( *go == ',' ) { n->data.str->len -= 1; memmove( go, go + 1, end - go ); end -= 1; } } } char * syck_str_read( SyckNode *n ) { ASSERT( n != NULL ); return n->data.str->ptr; } SyckNode * syck_new_map( SYMID key, SYMID value ) { SyckNode *n; n = syck_alloc_map(); syck_map_add( n, key, value ); return n; } void syck_map_empty( SyckNode *n ) { struct SyckMap *m; ASSERT( n != NULL ); ASSERT( n->data.list != NULL ); S_FREE( n->data.pairs->keys ); S_FREE( n->data.pairs->values ); m = n->data.pairs; m->idx = 0; m->capa = ALLOC_CT; m->keys = S_ALLOC_N( SYMID, m->capa ); m->values = S_ALLOC_N( SYMID, m->capa ); } void syck_map_add( SyckNode *map, SYMID key, SYMID value ) { struct SyckMap *m; long idx; ASSERT( map != NULL ); ASSERT( map->data.pairs != NULL ); m = map->data.pairs; idx = m->idx; m->idx += 1; if ( m->idx > m->capa ) { m->capa += ALLOC_CT; S_REALLOC_N( m->keys, SYMID, m->capa ); S_REALLOC_N( m->values, SYMID, m->capa ); } m->keys[idx] = key; m->values[idx] = value; } void syck_map_update( SyckNode *map1, SyckNode *map2 ) { struct SyckMap *m1, *m2; long new_idx, new_capa; ASSERT( map1 != NULL ); ASSERT( map2 != NULL ); m1 = map1->data.pairs; m2 = map2->data.pairs; if ( m2->idx < 1 ) return; new_idx = m1->idx; new_idx += m2->idx; new_capa = m1->capa; while ( new_idx > new_capa ) { new_capa += ALLOC_CT; } if ( new_capa > m1->capa ) { m1->capa = new_capa; S_REALLOC_N( m1->keys, SYMID, m1->capa ); S_REALLOC_N( m1->values, SYMID, m1->capa ); } for ( new_idx = 0; new_idx < m2->idx; m1->idx++, new_idx++ ) { m1->keys[m1->idx] = m2->keys[new_idx]; m1->values[m1->idx] = m2->values[new_idx]; } } long syck_map_count( SyckNode *map ) { ASSERT( map != NULL ); ASSERT( map->data.pairs != NULL ); return map->data.pairs->idx; } void syck_map_assign( SyckNode *map, enum map_part p, long idx, SYMID id ) { struct SyckMap *m; ASSERT( map != NULL ); m = map->data.pairs; ASSERT( m != NULL ); if ( p == map_key ) { m->keys[idx] = id; } else { m->values[idx] = id; } } SYMID syck_map_read( SyckNode *map, enum map_part p, long idx ) { struct SyckMap *m; ASSERT( map != NULL ); m = map->data.pairs; ASSERT( m != NULL ); if ( p == map_key ) { return m->keys[idx]; } else { return m->values[idx]; } } SyckNode * syck_new_seq( SYMID value ) { SyckNode *n; n = syck_alloc_seq(); syck_seq_add( n, value ); return n; } void syck_seq_empty( SyckNode *n ) { struct SyckSeq *s; ASSERT( n != NULL ); ASSERT( n->data.list != NULL ); S_FREE( n->data.list->items ); s = n->data.list; s->idx = 0; s->capa = ALLOC_CT; s->items = S_ALLOC_N( SYMID, s->capa ); } void syck_seq_add( SyckNode *arr, SYMID value ) { struct SyckSeq *s; long idx; ASSERT( arr != NULL ); ASSERT( arr->data.list != NULL ); s = arr->data.list; idx = s->idx; s->idx += 1; if ( s->idx > s->capa ) { s->capa += ALLOC_CT; S_REALLOC_N( s->items, SYMID, s->capa ); } s->items[idx] = value; } long syck_seq_count( SyckNode *seq ) { ASSERT( seq != NULL ); ASSERT( seq->data.list != NULL ); return seq->data.list->idx; } void syck_seq_assign( SyckNode *seq, long idx, SYMID id ) { struct SyckSeq *s; ASSERT( map != NULL ); s = seq->data.list; ASSERT( m != NULL ); s->items[idx] = id; } SYMID syck_seq_read( SyckNode *seq, long idx ) { struct SyckSeq *s; ASSERT( seq != NULL ); s = seq->data.list; ASSERT( s != NULL ); return s->items[idx]; } void syck_free_members( SyckNode *n ) { if ( n == NULL ) return; switch ( n->kind ) { case syck_str_kind: if ( n->data.str != NULL ) { S_FREE( n->data.str->ptr ); n->data.str->ptr = NULL; n->data.str->len = 0; S_FREE( n->data.str ); n->data.str = NULL; } break; case syck_seq_kind: if ( n->data.list != NULL ) { S_FREE( n->data.list->items ); S_FREE( n->data.list ); n->data.list = NULL; } break; case syck_map_kind: if ( n->data.pairs != NULL ) { S_FREE( n->data.pairs->keys ); S_FREE( n->data.pairs->values ); S_FREE( n->data.pairs ); n->data.pairs = NULL; } break; } } ================================================ FILE: ext/syck/rubyext.c ================================================ /* -*- indent-tabs-mode: nil -*- */ /* * rubyext.c * * $Author$ * $Date$ * * Copyright (C) 2003-2005 why the lucky stiff */ #include "ruby.h" #include "syck.h" #include #include typedef struct RVALUE { union { #if 0 struct { unsigned long flags; /* always 0 for freed obj */ struct RVALUE *next; } free; #endif struct RBasic basic; struct RObject object; struct RClass klass; /*struct RFloat flonum;*/ /*struct RString string;*/ struct RArray array; /*struct RRegexp regexp;*/ struct RHash hash; /*struct RData data;*/ struct RStruct rstruct; /*struct RBignum bignum;*/ /*struct RFile file;*/ } as; } RVALUE; typedef struct { long hash; char *buffer; long length; long remaining; int printed; } bytestring_t; #define RUBY_DOMAIN "ruby.yaml.org,2002" /* * symbols and constants */ static ID s_new, s_utc, s_at, s_to_f, s_to_i, s_read, s_binmode, s_call, s_cmp, s_transfer, s_update, s_dup, s_haskey, s_match, s_keys, s_unpack, s_tr_bang, s_default_set, s_tag_read_class, s_tag_subclasses, s_resolver, s_push, s_emitter, s_level, s_detect_implicit, s_node_import, s_out, s_input, s_intern, s_transform, s_yaml_new, s_yaml_initialize, s_node_export, s_to_yaml, s_write, s_set_resolver; static ID s_tags, s_domain, s_kind, s_name, s_options, s_type_id, s_type_id_set, s_style, s_style_set, s_value, s_value_set; static VALUE sym_model, sym_generic, sym_input, sym_bytecode; static VALUE sym_scalar, sym_seq, sym_map; static VALUE sym_1quote, sym_2quote, sym_fold, sym_literal, sym_plain, sym_inline; static VALUE cDate, cNode, cMap, cSeq, cScalar, cOut, cParser, cResolver, cPrivateType, cDomainType, cYObject, cBadAlias, cDefaultKey, cMergeKey, cEmitter; static VALUE oDefaultResolver, oGenericResolver; /* * my private collection of numerical oddities. */ static double S_zero() { return 0.0; } static double S_one() { return 1.0; } static double S_inf() { return S_one() / S_zero(); } static double S_nan() { return S_zero() / S_zero(); } static VALUE syck_node_transform( VALUE ); /* * handler prototypes */ SYMID rb_syck_load_handler _((SyckParser *, SyckNode *)); void rb_syck_err_handler _((SyckParser *, char *)); SyckNode * rb_syck_bad_anchor_handler _((SyckParser *, char *)); void rb_syck_output_handler _((SyckEmitter *, char *, long)); void rb_syck_emitter_handler _((SyckEmitter *, st_data_t)); int syck_parser_assign_io _((SyckParser *, VALUE *)); VALUE syck_scalar_alloc _((VALUE class)); VALUE syck_seq_alloc _((VALUE class)); VALUE syck_map_alloc _((VALUE class)); struct parser_xtra { VALUE data; /* Borrowed this idea from marshal.c to fix [ruby-core:8067] problem */ VALUE proc; VALUE resolver; int taint; }; struct emitter_xtra { VALUE oid; VALUE data; VALUE port; }; /* * Convert YAML to bytecode */ VALUE rb_syck_compile(self, port) VALUE self, port; { SYMID oid; int taint; char *ret; VALUE bc; bytestring_t *sav; SyckParser *parser = syck_new_parser(); taint = syck_parser_assign_io(parser, &port); syck_parser_handler( parser, syck_yaml2byte_handler ); syck_parser_error_handler( parser, NULL ); syck_parser_implicit_typing( parser, 0 ); syck_parser_taguri_expansion( parser, 0 ); oid = syck_parse( parser ); syck_lookup_sym( parser, oid, (char **)&sav ); ret = S_ALLOCA_N( char, strlen( sav->buffer ) + 3 ); ret[0] = '\0'; strcat( ret, "D\n" ); strcat( ret, sav->buffer ); syck_free_parser( parser ); bc = rb_str_new2( ret ); if ( taint ) OBJ_TAINT( bc ); return bc; } /* * read from io. */ long rb_syck_io_str_read( char *buf, SyckIoStr *str, long max_size, long skip ) { long len = 0; ASSERT( str != NULL ); max_size -= skip; if ( max_size <= 0 ) max_size = 0; else { /* * call io#read. */ VALUE src = (VALUE)str->ptr; VALUE n = LONG2NUM(max_size); VALUE str2 = rb_funcall2(src, s_read, 1, &n); if (!NIL_P(str2)) { StringValue(str2); len = RSTRING(str2)->len; memcpy( buf + skip, RSTRING(str2)->ptr, len ); } } len += skip; buf[len] = '\0'; return len; } /* * determine: are we reading from a string or io? * (returns tainted? boolean) */ int syck_parser_assign_io(parser, pport) SyckParser *parser; VALUE *pport; { int taint = Qtrue; VALUE tmp, port = *pport; if (!NIL_P(tmp = rb_check_string_type(port))) { taint = OBJ_TAINTED(port); /* original taintedness */ port = tmp; syck_parser_str( parser, RSTRING(port)->ptr, RSTRING(port)->len, NULL ); } else if (rb_respond_to(port, s_read)) { if (rb_respond_to(port, s_binmode)) { rb_funcall2(port, s_binmode, 0, 0); } syck_parser_str( parser, (char *)port, 0, rb_syck_io_str_read ); } else { rb_raise(rb_eTypeError, "instance of IO needed"); } *pport = port; return taint; } /* * Get value in hash by key, forcing an empty hash if nil. */ VALUE syck_get_hash_aref(hsh, key) VALUE hsh, key; { VALUE val = rb_hash_aref( hsh, key ); if ( NIL_P( val ) ) { val = rb_hash_new(); rb_hash_aset(hsh, key, val); } return val; } /* * creating timestamps */ SYMID rb_syck_mktime(str, len) char *str; long len; { VALUE time; char *ptr = str; VALUE year = INT2FIX(0); VALUE mon = INT2FIX(0); VALUE day = INT2FIX(0); VALUE hour = INT2FIX(0); VALUE min = INT2FIX(0); VALUE sec = INT2FIX(0); long usec; /* Year*/ if ( ptr[0] != '\0' && len > 0 ) { year = INT2FIX(strtol(ptr, NULL, 10)); } /* Month*/ ptr += 4; if ( ptr[0] != '\0' && len > ptr - str ) { while ( !ISDIGIT( *ptr ) ) ptr++; mon = INT2FIX(strtol(ptr, NULL, 10)); } /* Day*/ ptr += 2; if ( ptr[0] != '\0' && len > ptr - str ) { while ( !ISDIGIT( *ptr ) ) ptr++; day = INT2FIX(strtol(ptr, NULL, 10)); } /* Hour*/ ptr += 2; if ( ptr[0] != '\0' && len > ptr - str ) { while ( !ISDIGIT( *ptr ) ) ptr++; hour = INT2FIX(strtol(ptr, NULL, 10)); } /* Minute */ ptr += 2; if ( ptr[0] != '\0' && len > ptr - str ) { while ( !ISDIGIT( *ptr ) ) ptr++; min = INT2FIX(strtol(ptr, NULL, 10)); } /* Second */ ptr += 2; if ( ptr[0] != '\0' && len > ptr - str ) { while ( !ISDIGIT( *ptr ) ) ptr++; sec = INT2FIX(strtol(ptr, NULL, 10)); } /* Millisecond */ ptr += 2; if ( len > ptr - str && *ptr == '.' ) { char padded[] = "000000"; char *end = ptr + 1; char *p = end; while ( isdigit( *end ) ) end++; if (end - p < sizeof(padded)) { MEMCPY(padded, ptr + 1, char, end - (ptr + 1)); p = padded; } usec = strtol(p, NULL, 10); } else { usec = 0; } /* Time Zone*/ while ( len > ptr - str && *ptr != 'Z' && *ptr != '+' && *ptr != '-' && *ptr != '\0' ) ptr++; if ( len > ptr - str && ( *ptr == '-' || *ptr == '+' ) ) { time_t tz_offset = strtol(ptr, NULL, 10) * 3600; time_t tmp; while ( *ptr != ':' && *ptr != '\0' ) ptr++; if ( *ptr == ':' ) { ptr += 1; if ( tz_offset < 0 ) { tz_offset -= strtol(ptr, NULL, 10) * 60; } else { tz_offset += strtol(ptr, NULL, 10) * 60; } } /* Make TZ time*/ time = rb_funcall(rb_cTime, s_utc, 6, year, mon, day, hour, min, sec); tmp = NUM2LONG(rb_funcall(time, s_to_i, 0)) - tz_offset; return rb_funcall(rb_cTime, s_at, 2, LONG2NUM(tmp), LONG2NUM(usec)); } else { /* Make UTC time*/ return rb_funcall(rb_cTime, s_utc, 7, year, mon, day, hour, min, sec, LONG2NUM(usec)); } } /* * handles merging of an array of hashes * (see http://www.yaml.org/type/merge/) */ VALUE syck_merge_i( entry, hsh ) VALUE entry, hsh; { VALUE tmp; if ( !NIL_P(tmp = rb_check_convert_type(entry, T_HASH, "Hash", "to_hash")) ) { entry = tmp; rb_funcall( hsh, s_update, 1, entry ); } return Qnil; } /* * default handler for ruby.yaml.org types */ int yaml_org_handler( n, ref ) SyckNode *n; VALUE *ref; { char *type_id = n->type_id; int transferred = 0; long i = 0; VALUE obj = Qnil; if ( type_id != NULL && strncmp( type_id, "tag:yaml.org,2002:", 18 ) == 0 ) { type_id += 18; } switch (n->kind) { case syck_str_kind: transferred = 1; if ( type_id == NULL ) { obj = rb_str_new( n->data.str->ptr, n->data.str->len ); } else if ( strcmp( type_id, "null" ) == 0 ) { obj = Qnil; } else if ( strcmp( type_id, "binary" ) == 0 ) { VALUE arr; obj = rb_str_new( n->data.str->ptr, n->data.str->len ); rb_funcall( obj, s_tr_bang, 2, rb_str_new2( "\n\t " ), rb_str_new2( "" ) ); arr = rb_funcall( obj, s_unpack, 1, rb_str_new2( "m" ) ); obj = rb_ary_shift( arr ); } else if ( strcmp( type_id, "bool#yes" ) == 0 ) { obj = Qtrue; } else if ( strcmp( type_id, "bool#no" ) == 0 ) { obj = Qfalse; } else if ( strcmp( type_id, "int#hex" ) == 0 ) { syck_str_blow_away_commas( n ); obj = rb_cstr2inum( n->data.str->ptr, 16 ); } else if ( strcmp( type_id, "int#oct" ) == 0 ) { syck_str_blow_away_commas( n ); obj = rb_cstr2inum( n->data.str->ptr, 8 ); } else if ( strcmp( type_id, "int#base60" ) == 0 ) { char *ptr, *end; long sixty = 1; long total = 0; syck_str_blow_away_commas( n ); ptr = n->data.str->ptr; end = n->data.str->ptr + n->data.str->len; while ( end > ptr ) { long bnum = 0; char *colon = end - 1; while ( colon >= ptr && *colon != ':' ) { colon--; } if ( colon >= ptr && *colon == ':' ) *colon = '\0'; bnum = strtol( colon + 1, NULL, 10 ); total += bnum * sixty; sixty *= 60; end = colon; } obj = INT2FIX(total); } else if ( strncmp( type_id, "int", 3 ) == 0 ) { syck_str_blow_away_commas( n ); obj = rb_cstr2inum( n->data.str->ptr, 10 ); } else if ( strcmp( type_id, "float#base60" ) == 0 ) { char *ptr, *end; long sixty = 1; double total = 0.0; syck_str_blow_away_commas( n ); ptr = n->data.str->ptr; end = n->data.str->ptr + n->data.str->len; while ( end > ptr ) { double bnum = 0; char *colon = end - 1; while ( colon >= ptr && *colon != ':' ) { colon--; } if ( colon >= ptr && *colon == ':' ) *colon = '\0'; bnum = strtod( colon + 1, NULL ); total += bnum * sixty; sixty *= 60; end = colon; } obj = rb_float_new( total ); } else if ( strcmp( type_id, "float#nan" ) == 0 ) { obj = rb_float_new( S_nan() ); } else if ( strcmp( type_id, "float#inf" ) == 0 ) { obj = rb_float_new( S_inf() ); } else if ( strcmp( type_id, "float#neginf" ) == 0 ) { obj = rb_float_new( -S_inf() ); } else if ( strncmp( type_id, "float", 5 ) == 0 ) { double f; syck_str_blow_away_commas( n ); f = strtod( n->data.str->ptr, NULL ); obj = rb_float_new( f ); } else if ( strcmp( type_id, "timestamp#iso8601" ) == 0 ) { obj = rb_syck_mktime( n->data.str->ptr, n->data.str->len ); } else if ( strcmp( type_id, "timestamp#spaced" ) == 0 ) { obj = rb_syck_mktime( n->data.str->ptr, n->data.str->len ); } else if ( strcmp( type_id, "timestamp#ymd" ) == 0 ) { char *ptr = n->data.str->ptr; VALUE year, mon, day; /* Year*/ ptr[4] = '\0'; year = INT2FIX(strtol(ptr, NULL, 10)); /* Month*/ ptr += 4; while ( !ISDIGIT( *ptr ) ) ptr++; mon = INT2FIX(strtol(ptr, NULL, 10)); /* Day*/ ptr += 2; while ( !ISDIGIT( *ptr ) ) ptr++; day = INT2FIX(strtol(ptr, NULL, 10)); if ( !cDate ) { /* * Load Date module */ rb_require( "date" ); cDate = rb_const_get( rb_cObject, rb_intern("Date") ); } obj = rb_funcall( cDate, s_new, 3, year, mon, day ); } else if ( strncmp( type_id, "timestamp", 9 ) == 0 ) { obj = rb_syck_mktime( n->data.str->ptr, n->data.str->len ); } else if ( strncmp( type_id, "merge", 5 ) == 0 ) { obj = rb_funcall( cMergeKey, s_new, 0 ); } else if ( strncmp( type_id, "default", 7 ) == 0 ) { obj = rb_funcall( cDefaultKey, s_new, 0 ); } else if ( n->data.str->style == scalar_plain && n->data.str->len > 1 && strncmp( n->data.str->ptr, ":", 1 ) == 0 ) { obj = rb_funcall( oDefaultResolver, s_transfer, 2, rb_str_new2( "tag:ruby.yaml.org,2002:sym" ), rb_str_new( n->data.str->ptr + 1, n->data.str->len - 1 ) ); } else if ( strcmp( type_id, "str" ) == 0 ) { obj = rb_str_new( n->data.str->ptr, n->data.str->len ); } else { transferred = 0; obj = rb_str_new( n->data.str->ptr, n->data.str->len ); } break; case syck_seq_kind: if ( type_id == NULL || strcmp( type_id, "seq" ) == 0 ) { transferred = 1; } obj = rb_ary_new2( n->data.list->idx ); for ( i = 0; i < n->data.list->idx; i++ ) { rb_ary_store( obj, i, syck_seq_read( n, i ) ); } break; case syck_map_kind: if ( type_id == NULL || strcmp( type_id, "map" ) == 0 ) { transferred = 1; } obj = rb_hash_new(); for ( i = 0; i < n->data.pairs->idx; i++ ) { VALUE k = syck_map_read( n, map_key, i ); VALUE v = syck_map_read( n, map_value, i ); int skip_aset = 0; /* * Handle merge keys */ if ( rb_obj_is_kind_of( k, cMergeKey ) ) { VALUE tmp; if ( !NIL_P(tmp = rb_check_convert_type(v, T_HASH, "Hash", "to_hash")) ) { VALUE dup = rb_funcall( tmp, s_dup, 0 ); rb_funcall( dup, s_update, 1, obj ); obj = dup; skip_aset = 1; } else if ( !NIL_P(tmp = rb_check_array_type(v)) ) { VALUE end = rb_ary_pop( tmp ); VALUE tmph = rb_check_convert_type(end, T_HASH, "Hash", "to_hash"); if ( !NIL_P(tmph) ) { VALUE dup = rb_funcall( tmph, s_dup, 0 ); tmp = rb_ary_reverse( tmp ); rb_ary_push( tmp, obj ); rb_iterate( rb_each, tmp, syck_merge_i, dup ); obj = dup; skip_aset = 1; } } } else if ( rb_obj_is_kind_of( k, cDefaultKey ) ) { rb_funcall( obj, s_default_set, 1, v ); skip_aset = 1; } if ( ! skip_aset ) { rb_hash_aset( obj, k, v ); } } break; } *ref = obj; return transferred; } static void syck_node_mark( SyckNode *n ); /* * {native mode} node handler * - Converts data into native Ruby types */ SYMID rb_syck_load_handler(p, n) SyckParser *p; SyckNode *n; { VALUE obj = Qnil; struct parser_xtra *bonus = (struct parser_xtra *)p->bonus; VALUE resolver = bonus->resolver; if ( NIL_P( resolver ) ) { resolver = oDefaultResolver; } /* * Create node, */ obj = rb_funcall( resolver, s_node_import, 1, Data_Wrap_Struct( cNode, NULL, NULL, n ) ); /* * ID already set, let's alter the symbol table to accept the new object */ if (n->id > 0 && !NIL_P(obj)) { MEMCPY((void *)n->id, (void *)obj, RVALUE, 1); MEMZERO((void *)obj, RVALUE, 1); obj = n->id; } if ( bonus->taint) OBJ_TAINT( obj ); if ( bonus->proc != 0 ) rb_funcall(bonus->proc, s_call, 1, obj); rb_hash_aset(bonus->data, INT2FIX(RHASH(bonus->data)->tbl->num_entries), obj); return obj; } /* * friendly errors. */ void rb_syck_err_handler(p, msg) SyckParser *p; char *msg; { char *endl = p->cursor; while ( *endl != '\0' && *endl != '\n' ) endl++; endl[0] = '\0'; rb_raise(rb_eArgError, "%s on line %d, col %d: `%s'", msg, p->linect, p->cursor - p->lineptr, p->lineptr); } /* * provide bad anchor object to the parser. */ SyckNode * rb_syck_bad_anchor_handler(p, a) SyckParser *p; char *a; { VALUE anchor_name = rb_str_new2( a ); SyckNode *badanc = syck_new_map( rb_str_new2( "name" ), anchor_name ); badanc->type_id = syck_strndup( "tag:ruby.yaml.org,2002:object:YAML::Syck::BadAlias", 53 ); return badanc; } /* * data loaded based on the model requested. */ void syck_set_model( p, input, model ) VALUE p, input, model; { SyckParser *parser; Data_Get_Struct(p, SyckParser, parser); syck_parser_handler( parser, rb_syck_load_handler ); /* WARN: gonna be obsoleted soon!! */ if ( model == sym_generic ) { rb_funcall( p, s_set_resolver, 1, oGenericResolver ); } syck_parser_implicit_typing( parser, 1 ); syck_parser_taguri_expansion( parser, 1 ); if ( NIL_P( input ) ) { input = rb_ivar_get( p, s_input ); } if ( input == sym_bytecode ) { syck_parser_set_input_type( parser, syck_bytecode_utf8 ); } else { syck_parser_set_input_type( parser, syck_yaml_utf8 ); } syck_parser_error_handler( parser, rb_syck_err_handler ); syck_parser_bad_anchor_handler( parser, rb_syck_bad_anchor_handler ); } static int syck_st_mark_nodes( char *key, SyckNode *n, char *arg ) { if ( n != (void *)1 ) syck_node_mark( n ); return ST_CONTINUE; } /* * mark parser nodes */ static void syck_mark_parser(parser) SyckParser *parser; { struct parser_xtra *bonus = (struct parser_xtra *)parser->bonus; rb_gc_mark_maybe(parser->root); rb_gc_mark_maybe(parser->root_on_error); rb_gc_mark( bonus->data ); rb_gc_mark( bonus->proc ); rb_gc_mark( bonus->resolver ); if ( parser->anchors != NULL ) { st_foreach( parser->anchors, syck_st_mark_nodes, 0 ); } if ( parser->bad_anchors != NULL ) { st_foreach( parser->bad_anchors, syck_st_mark_nodes, 0 ); } } /* * Free the parser and any bonus attachment. */ void rb_syck_free_parser(p) SyckParser *p; { S_FREE( p->bonus ); syck_free_parser(p); } /* * YAML::Syck::Parser.allocate */ VALUE syck_parser_s_alloc _((VALUE)); VALUE syck_parser_s_alloc(class) VALUE class; { VALUE pobj; SyckParser *parser = syck_new_parser(); parser->bonus = S_ALLOC( struct parser_xtra ); S_MEMZERO( parser->bonus, struct parser_xtra, 1 ); pobj = Data_Wrap_Struct( class, syck_mark_parser, rb_syck_free_parser, parser ); syck_parser_set_root_on_error( parser, Qnil ); return pobj; } /* * YAML::Syck::Parser.initialize( resolver, options ) */ static VALUE syck_parser_initialize(argc, argv, self) int argc; VALUE *argv; VALUE self; { VALUE options; if (rb_scan_args(argc, argv, "01", &options) == 0) { options = rb_hash_new(); } else { Check_Type(options, T_HASH); } rb_ivar_set(self, s_options, options); rb_ivar_set(self, s_input, Qnil); return self; } /* * YAML::Syck::Parser.bufsize = Integer */ static VALUE syck_parser_bufsize_set( self, size ) VALUE self, size; { SyckParser *parser; if ( rb_respond_to( size, s_to_i ) ) { int n = NUM2INT(rb_funcall(size, s_to_i, 0)); Data_Get_Struct(self, SyckParser, parser); parser->bufsize = n; } return self; } /* * YAML::Syck::Parser.bufsize => Integer */ static VALUE syck_parser_bufsize_get( self ) VALUE self; { SyckParser *parser; Data_Get_Struct(self, SyckParser, parser); return INT2FIX( parser->bufsize ); } /* * YAML::Syck::Parser.load( IO or String ) */ VALUE syck_parser_load(argc, argv, self) int argc; VALUE *argv; VALUE self; { VALUE port, proc, model, input; SyckParser *parser; struct parser_xtra *bonus; rb_scan_args(argc, argv, "11", &port, &proc); input = rb_hash_aref( rb_attr_get( self, s_options ), sym_input ); model = rb_hash_aref( rb_attr_get( self, s_options ), sym_model ); Data_Get_Struct(self, SyckParser, parser); syck_set_model( self, input, model ); bonus = (struct parser_xtra *)parser->bonus; bonus->taint = syck_parser_assign_io(parser, &port); bonus->data = rb_hash_new(); bonus->resolver = rb_attr_get( self, s_resolver ); if ( NIL_P( proc ) ) bonus->proc = 0; else bonus->proc = proc; return syck_parse( parser ); } /* * YAML::Syck::Parser.load_documents( IO or String ) { |doc| } */ VALUE syck_parser_load_documents(argc, argv, self) int argc; VALUE *argv; VALUE self; { VALUE port, proc, v, input, model; SyckParser *parser; struct parser_xtra *bonus; rb_scan_args(argc, argv, "1&", &port, &proc); input = rb_hash_aref( rb_attr_get( self, s_options ), sym_input ); model = rb_hash_aref( rb_attr_get( self, s_options ), sym_model ); Data_Get_Struct(self, SyckParser, parser); syck_set_model( self, input, model ); bonus = (struct parser_xtra *)parser->bonus; bonus->taint = syck_parser_assign_io(parser, &port); bonus->resolver = rb_attr_get( self, s_resolver ); bonus->proc = 0; while ( 1 ) { /* Reset hash for tracking nodes */ bonus->data = rb_hash_new(); /* Parse a document */ v = syck_parse( parser ); if ( parser->eof == 1 ) { break; } /* Pass document to block */ rb_funcall( proc, s_call, 1, v ); } return Qnil; } /* * YAML::Syck::Parser#set_resolver */ VALUE syck_parser_set_resolver( self, resolver ) VALUE self, resolver; { rb_ivar_set( self, s_resolver, resolver ); return self; } /* * YAML::Syck::Resolver.initialize */ static VALUE syck_resolver_initialize( self ) VALUE self; { rb_ivar_set(self, s_tags, rb_hash_new()); return self; } /* * YAML::Syck::Resolver#add_type */ VALUE syck_resolver_add_type( self, taguri, cls ) VALUE self, taguri, cls; { VALUE tags = rb_attr_get(self, s_tags); rb_hash_aset( tags, taguri, cls ); return Qnil; } /* * YAML::Syck::Resolver#use_types_at */ VALUE syck_resolver_use_types_at( self, hsh ) VALUE self, hsh; { rb_ivar_set( self, s_tags, hsh ); return Qnil; } /* * YAML::Syck::Resolver#detect_implicit */ VALUE syck_resolver_detect_implicit( self, val ) VALUE self, val; { return rb_str_new2( "" ); } /* * YAML::Syck::Resolver#node_import */ VALUE syck_resolver_node_import( self, node ) VALUE self, node; { SyckNode *n; VALUE obj; int i = 0; Data_Get_Struct(node, SyckNode, n); switch (n->kind) { case syck_str_kind: obj = rb_str_new( n->data.str->ptr, n->data.str->len ); break; case syck_seq_kind: obj = rb_ary_new2( n->data.list->idx ); for ( i = 0; i < n->data.list->idx; i++ ) { rb_ary_store( obj, i, syck_seq_read( n, i ) ); } break; case syck_map_kind: obj = rb_hash_new(); for ( i = 0; i < n->data.pairs->idx; i++ ) { VALUE k = syck_map_read( n, map_key, i ); VALUE v = syck_map_read( n, map_value, i ); int skip_aset = 0; /* * Handle merge keys */ if ( rb_obj_is_kind_of( k, cMergeKey ) ) { if ( rb_obj_is_kind_of( v, rb_cHash ) ) { VALUE dup = rb_funcall( v, s_dup, 0 ); rb_funcall( dup, s_update, 1, obj ); obj = dup; skip_aset = 1; } else if ( rb_obj_is_kind_of( v, rb_cArray ) ) { VALUE end = rb_ary_pop( v ); if ( rb_obj_is_kind_of( end, rb_cHash ) ) { VALUE dup = rb_funcall( end, s_dup, 0 ); v = rb_ary_reverse( v ); rb_ary_push( v, obj ); rb_iterate( rb_each, v, syck_merge_i, dup ); obj = dup; skip_aset = 1; } } } else if ( rb_obj_is_kind_of( k, cDefaultKey ) ) { rb_funcall( obj, s_default_set, 1, v ); skip_aset = 1; } if ( ! skip_aset ) { rb_hash_aset( obj, k, v ); } } break; } if ( n->type_id != NULL ) { obj = rb_funcall( self, s_transfer, 2, rb_str_new2( n->type_id ), obj ); } return obj; } /* * Set instance variables */ VALUE syck_set_ivars( vars, obj ) VALUE vars, obj; { VALUE ivname = rb_ary_entry( vars, 0 ); char *ivn; StringValue( ivname ); ivn = S_ALLOCA_N( char, RSTRING(ivname)->len + 2 ); ivn[0] = '@'; ivn[1] = '\0'; strncat( ivn, RSTRING(ivname)->ptr, RSTRING(ivname)->len ); rb_iv_set( obj, ivn, rb_ary_entry( vars, 1 ) ); return Qnil; } /* * YAML::Syck::Resolver#const_find */ VALUE syck_const_find( const_name ) VALUE const_name; { VALUE tclass = rb_cObject; VALUE tparts = rb_str_split( const_name, "::" ); int i = 0; for ( i = 0; i < RARRAY(tparts)->len; i++ ) { VALUE tpart = rb_to_id( rb_ary_entry( tparts, i ) ); if ( !rb_const_defined( tclass, tpart ) ) return Qnil; tclass = rb_const_get( tclass, tpart ); } return tclass; } /* * YAML::Syck::Resolver#transfer */ VALUE syck_resolver_transfer( self, type, val ) VALUE self, type, val; { if (NIL_P(type) || RSTRING(StringValue(type))->len == 0) { type = rb_funcall( self, s_detect_implicit, 1, val ); } if ( ! (NIL_P(type) || RSTRING(StringValue(type))->len == 0) ) { VALUE str_xprivate = rb_str_new2( "x-private" ); VALUE colon = rb_str_new2( ":" ); VALUE tags = rb_attr_get(self, s_tags); VALUE target_class = rb_hash_aref( tags, type ); VALUE subclass = target_class; VALUE obj = Qnil; /* * Should no tag match exactly, check for subclass format */ if ( NIL_P( target_class ) ) { VALUE subclass_parts = rb_ary_new(); VALUE parts = rb_str_split( type, ":" ); while ( RARRAY(parts)->len > 1 ) { VALUE partial; rb_ary_unshift( subclass_parts, rb_ary_pop( parts ) ); partial = rb_ary_join( parts, colon ); target_class = rb_hash_aref( tags, partial ); if ( NIL_P( target_class ) ) { rb_str_append( partial, colon ); target_class = rb_hash_aref( tags, partial ); } /* * Possible subclass found, see if it supports subclassing */ if ( ! NIL_P( target_class ) ) { subclass = target_class; if ( RARRAY(subclass_parts)->len > 0 && rb_respond_to( target_class, s_tag_subclasses ) && RTEST( rb_funcall( target_class, s_tag_subclasses, 0 ) ) ) { VALUE subclass_v; subclass = rb_ary_join( subclass_parts, colon ); subclass = rb_funcall( target_class, s_tag_read_class, 1, subclass ); subclass_v = syck_const_find( subclass ); if ( subclass_v != Qnil ) { subclass = subclass_v; } else if ( rb_cObject == target_class && subclass_v == Qnil ) { target_class = cYObject; type = subclass; subclass = cYObject; } else /* workaround for SEGV. real fix please */ { rb_raise( rb_eTypeError, "invalid subclass" ); } } break; } } } /* rb_raise(rb_eTypeError, "invalid typing scheme: %s given", * scheme); */ if ( rb_respond_to( target_class, s_call ) ) { obj = rb_funcall( target_class, s_call, 2, type, val ); } else { if ( rb_respond_to( target_class, s_yaml_new ) ) { obj = rb_funcall( target_class, s_yaml_new, 3, subclass, type, val ); } else if ( !NIL_P( target_class ) ) { if ( subclass == rb_cBignum ) { obj = rb_str2inum( val, 10 ); /* for yaml dumped by 1.8.3 [ruby-core:6159] */ } else { obj = rb_obj_alloc( subclass ); } if ( rb_respond_to( obj, s_yaml_initialize ) ) { rb_funcall( obj, s_yaml_initialize, 2, type, val ); } else if ( !NIL_P( obj ) && rb_obj_is_instance_of( val, rb_cHash ) ) { rb_iterate( rb_each, val, syck_set_ivars, obj ); } } else { VALUE parts = rb_str_split( type, ":" ); VALUE scheme = rb_ary_shift( parts ); if ( rb_str_cmp( scheme, str_xprivate ) == 0 ) { VALUE name = rb_ary_join( parts, colon ); obj = rb_funcall( cPrivateType, s_new, 2, name, val ); } else { VALUE domain = rb_ary_shift( parts ); VALUE name = rb_ary_join( parts, colon ); obj = rb_funcall( cDomainType, s_new, 3, domain, name, val ); } } } val = obj; } return val; } /* * YAML::Syck::Resolver#tagurize */ VALUE syck_resolver_tagurize( self, val ) VALUE self, val; { VALUE tmp = rb_check_string_type(val); if ( !NIL_P(tmp) ) { char *taguri = syck_type_id_to_uri( RSTRING(tmp)->ptr ); val = rb_str_new2( taguri ); S_FREE( taguri ); } return val; } /* * YAML::Syck::DefaultResolver#detect_implicit */ VALUE syck_defaultresolver_detect_implicit( self, val ) VALUE self, val; { char *type_id; VALUE tmp = rb_check_string_type(val); if ( !NIL_P(tmp) ) { val = tmp; type_id = syck_match_implicit( RSTRING(val)->ptr, RSTRING(val)->len ); return rb_str_new2( type_id ); } return rb_str_new2( "" ); } /* * YAML::Syck::DefaultResolver#node_import */ VALUE syck_defaultresolver_node_import( self, node ) VALUE self, node; { SyckNode *n; VALUE obj; Data_Get_Struct( node, SyckNode, n ); if ( !yaml_org_handler( n, &obj ) ) { obj = rb_funcall( self, s_transfer, 2, rb_str_new2( n->type_id ), obj ); } return obj; } /* * YAML::Syck::GenericResolver#node_import */ VALUE syck_genericresolver_node_import( self, node ) VALUE self, node; { SyckNode *n; int i = 0; VALUE t = Qnil, obj = Qnil, v = Qnil, style = Qnil; Data_Get_Struct(node, SyckNode, n); if ( n->type_id != NULL ) { t = rb_str_new2(n->type_id); } switch (n->kind) { case syck_str_kind: { v = rb_str_new( n->data.str->ptr, n->data.str->len ); if ( n->data.str->style == scalar_1quote ) { style = sym_1quote; } else if ( n->data.str->style == scalar_2quote ) { style = sym_2quote; } else if ( n->data.str->style == scalar_fold ) { style = sym_fold; } else if ( n->data.str->style == scalar_literal ) { style = sym_literal; } else if ( n->data.str->style == scalar_plain ) { style = sym_plain; } obj = rb_funcall( cScalar, s_new, 3, t, v, style ); } break; case syck_seq_kind: v = rb_ary_new2( syck_seq_count( n ) ); for ( i = 0; i < syck_seq_count( n ); i++ ) { rb_ary_store( v, i, syck_seq_read( n, i ) ); } if ( n->data.list->style == seq_inline ) { style = sym_inline; } obj = rb_funcall( cSeq, s_new, 3, t, v, style ); rb_iv_set(obj, "@kind", sym_seq); break; case syck_map_kind: v = rb_hash_new(); for ( i = 0; i < syck_map_count( n ); i++ ) { rb_hash_aset( v, syck_map_read( n, map_key, i ), syck_map_read( n, map_value, i ) ); } if ( n->data.pairs->style == map_inline ) { style = sym_inline; } obj = rb_funcall( cMap, s_new, 3, t, v, style ); rb_iv_set(obj, "@kind", sym_map); break; } return obj; } /* * YAML::Syck::BadAlias.initialize */ VALUE syck_badalias_initialize( self, val ) VALUE self, val; { rb_iv_set( self, "@name", val ); return self; } /* * YAML::Syck::BadAlias.<=> */ VALUE syck_badalias_cmp( alias1, alias2 ) VALUE alias1, alias2; { VALUE str1 = rb_ivar_get( alias1, s_name ); VALUE str2 = rb_ivar_get( alias2, s_name ); VALUE val = rb_funcall( str1, s_cmp, 1, str2 ); return val; } /* * YAML::DomainType.initialize */ VALUE syck_domaintype_initialize( self, domain, type_id, val ) VALUE self, domain, type_id, val; { rb_iv_set( self, "@domain", domain ); rb_iv_set( self, "@type_id", type_id ); rb_iv_set( self, "@value", val ); return self; } /* * YAML::Object.initialize */ VALUE syck_yobject_initialize( self, klass, ivars ) VALUE self, klass, ivars; { rb_iv_set( self, "@class", klass ); rb_iv_set( self, "@ivars", ivars ); return self; } /* * YAML::PrivateType.initialize */ VALUE syck_privatetype_initialize( self, type_id, val ) VALUE self, type_id, val; { rb_iv_set( self, "@type_id", type_id ); rb_iv_set( self, "@value", val ); return self; } /* * Mark node contents. */ static void syck_node_mark( n ) SyckNode *n; { int i; rb_gc_mark_maybe( n->id ); switch ( n->kind ) { case syck_seq_kind: for ( i = 0; i < n->data.list->idx; i++ ) { rb_gc_mark( syck_seq_read( n, i ) ); } break; case syck_map_kind: for ( i = 0; i < n->data.pairs->idx; i++ ) { rb_gc_mark( syck_map_read( n, map_key, i ) ); rb_gc_mark( syck_map_read( n, map_value, i ) ); } break; } #if 0 /* maybe needed */ if ( n->shortcut ) syck_node_mark( n->shortcut ); /* caution: maybe cyclic */ #endif } /* * YAML::Syck::Scalar.allocate */ VALUE syck_scalar_alloc( class ) VALUE class; { SyckNode *node = syck_alloc_str(); VALUE obj = Data_Wrap_Struct( class, syck_node_mark, syck_free_node, node ); node->id = obj; return obj; } /* * YAML::Syck::Scalar.initialize */ VALUE syck_scalar_initialize( self, type_id, val, style ) VALUE self, type_id, val, style; { rb_iv_set( self, "@kind", sym_scalar ); rb_funcall( self, s_type_id_set, 1, type_id ); rb_funcall( self, s_value_set, 1, val ); rb_funcall( self, s_style_set, 1, style ); return self; } /* * YAML::Syck::Scalar.style= */ VALUE syck_scalar_style_set( self, style ) VALUE self, style; { SyckNode *node; Data_Get_Struct( self, SyckNode, node ); if ( NIL_P( style ) ) { node->data.str->style = scalar_none; } else if ( style == sym_1quote ) { node->data.str->style = scalar_1quote; } else if ( style == sym_2quote ) { node->data.str->style = scalar_2quote; } else if ( style == sym_fold ) { node->data.str->style = scalar_fold; } else if ( style == sym_literal ) { node->data.str->style = scalar_literal; } else if ( style == sym_plain ) { node->data.str->style = scalar_plain; } rb_iv_set( self, "@style", style ); return self; } /* * YAML::Syck::Scalar.value= */ VALUE syck_scalar_value_set( self, val ) VALUE self, val; { SyckNode *node; Data_Get_Struct( self, SyckNode, node ); StringValue( val ); node->data.str->ptr = syck_strndup( RSTRING(val)->ptr, RSTRING(val)->len ); node->data.str->len = RSTRING(val)->len; node->data.str->style = scalar_none; rb_iv_set( self, "@value", val ); return val; } /* * YAML::Syck::Seq.allocate */ VALUE syck_seq_alloc( class ) VALUE class; { SyckNode *node; VALUE obj; node = syck_alloc_seq(); obj = Data_Wrap_Struct( class, syck_node_mark, syck_free_node, node ); node->id = obj; return obj; } /* * YAML::Syck::Seq.initialize */ VALUE syck_seq_initialize( self, type_id, val, style ) VALUE self, type_id, val, style; { SyckNode *node; Data_Get_Struct( self, SyckNode, node ); rb_iv_set( self, "@kind", sym_seq ); rb_funcall( self, s_type_id_set, 1, type_id ); rb_funcall( self, s_value_set, 1, val ); rb_funcall( self, s_style_set, 1, style ); return self; } /* * YAML::Syck::Seq.value= */ VALUE syck_seq_value_set( self, val ) VALUE self, val; { SyckNode *node; Data_Get_Struct( self, SyckNode, node ); val = rb_check_array_type( val ); if ( !NIL_P( val ) ) { int i; syck_seq_empty( node ); for ( i = 0; i < RARRAY( val )->len; i++ ) { syck_seq_add( node, rb_ary_entry(val, i) ); } } rb_iv_set( self, "@value", val ); return val; } /* * YAML::Syck::Seq.add */ VALUE syck_seq_add_m( self, val ) VALUE self, val; { SyckNode *node; VALUE emitter = rb_ivar_get( self, s_emitter ); Data_Get_Struct( self, SyckNode, node ); if ( rb_respond_to( emitter, s_node_export ) ) { val = rb_funcall( emitter, s_node_export, 1, val ); } syck_seq_add( node, val ); rb_ary_push( rb_ivar_get( self, s_value ), val ); return self; } /* * YAML::Syck::Seq.style= */ VALUE syck_seq_style_set( self, style ) VALUE self, style; { SyckNode *node; Data_Get_Struct( self, SyckNode, node ); if ( style == sym_inline ) { node->data.list->style = seq_inline; } else { node->data.list->style = seq_none; } rb_iv_set( self, "@style", style ); return self; } /* * YAML::Syck::Map.allocate */ VALUE syck_map_alloc( class ) VALUE class; { SyckNode *node; VALUE obj; node = syck_alloc_map(); obj = Data_Wrap_Struct( class, syck_node_mark, syck_free_node, node ); node->id = obj; return obj; } /* * YAML::Syck::Map.initialize */ VALUE syck_map_initialize( self, type_id, val, style ) VALUE self, type_id, val, style; { SyckNode *node; Data_Get_Struct( self, SyckNode, node ); if ( !NIL_P( val ) ) { VALUE hsh = rb_check_convert_type(val, T_HASH, "Hash", "to_hash"); VALUE keys; int i; if ( NIL_P(hsh) ) { rb_raise( rb_eTypeError, "wrong argument type" ); } keys = rb_funcall( hsh, s_keys, 0 ); for ( i = 0; i < RARRAY(keys)->len; i++ ) { VALUE key = rb_ary_entry(keys, i); syck_map_add( node, key, rb_hash_aref(hsh, key) ); } } rb_iv_set( self, "@kind", sym_seq ); rb_funcall( self, s_type_id_set, 1, type_id ); rb_funcall( self, s_value_set, 1, val ); rb_funcall( self, s_style_set, 1, style ); return self; } /* * YAML::Syck::Map.value= */ VALUE syck_map_value_set( self, val ) VALUE self, val; { SyckNode *node; Data_Get_Struct( self, SyckNode, node ); if ( !NIL_P( val ) ) { VALUE hsh = rb_check_convert_type(val, T_HASH, "Hash", "to_hash"); VALUE keys; int i; if ( NIL_P(hsh) ) { rb_raise( rb_eTypeError, "wrong argument type" ); } syck_map_empty( node ); keys = rb_funcall( hsh, s_keys, 0 ); for ( i = 0; i < RARRAY(keys)->len; i++ ) { VALUE key = rb_ary_entry(keys, i); syck_map_add( node, key, rb_hash_aref(hsh, key) ); } } rb_iv_set( self, "@value", val ); return val; } /* * YAML::Syck::Map.add */ VALUE syck_map_add_m( self, key, val ) VALUE self, key, val; { SyckNode *node; VALUE emitter = rb_ivar_get( self, s_emitter ); Data_Get_Struct( self, SyckNode, node ); if ( rb_respond_to( emitter, s_node_export ) ) { key = rb_funcall( emitter, s_node_export, 1, key ); val = rb_funcall( emitter, s_node_export, 1, val ); } syck_map_add( node, key, val ); rb_hash_aset( rb_ivar_get( self, s_value ), key, val ); return self; } /* * YAML::Syck::Map.style= */ VALUE syck_map_style_set( self, style ) VALUE self, style; { SyckNode *node; Data_Get_Struct( self, SyckNode, node ); if ( style == sym_inline ) { node->data.pairs->style = map_inline; } else { node->data.pairs->style = map_none; } rb_iv_set( self, "@style", style ); return self; } /* * Cloning method for all node types */ VALUE syck_node_init_copy( copy, orig ) VALUE copy, orig; { SyckNode *copy_n; SyckNode *orig_n; if ( copy == orig ) return copy; if ( TYPE( orig ) != T_DATA ) { rb_raise( rb_eTypeError, "wrong argument type" ); } Data_Get_Struct( orig, SyckNode, orig_n ); Data_Get_Struct( copy, SyckNode, copy_n ); MEMCPY( copy_n, orig_n, SyckNode, 1 ); return copy; } /* * YAML::Syck::Node#type_id= */ VALUE syck_node_type_id_set( self, type_id ) VALUE self, type_id; { SyckNode *node; Data_Get_Struct( self, SyckNode, node ); S_FREE( node->type_id ); if ( !NIL_P( type_id ) ) { StringValue( type_id ); node->type_id = syck_strndup( RSTRING(type_id)->ptr, RSTRING(type_id)->len ); } rb_iv_set( self, "@type_id", type_id ); return type_id; } /* * YAML::Syck::Node.transform */ VALUE syck_node_transform( self ) VALUE self; { VALUE t; SyckNode *n; SyckNode *orig_n; Data_Get_Struct(self, SyckNode, orig_n); t = Data_Wrap_Struct( cNode, syck_node_mark, syck_free_node, 0 ); switch (orig_n->kind) { case syck_map_kind: { int i; DATA_PTR(t) = n = syck_alloc_map(); for ( i = 0; i < orig_n->data.pairs->idx; i++ ) { syck_map_add( n, rb_funcall( syck_map_read( orig_n, map_key, i ), s_transform, 0 ), rb_funcall( syck_map_read( orig_n, map_value, i ), s_transform, 0 ) ); } } break; case syck_seq_kind: { int i; DATA_PTR(t) = n = syck_alloc_seq(); for ( i = 0; i < orig_n->data.list->idx; i++ ) { syck_seq_add( n, rb_funcall( syck_seq_read( orig_n, i ), s_transform, 0 ) ); } } break; case syck_str_kind: DATA_PTR(t) = n = syck_new_str2( orig_n->data.str->ptr, orig_n->data.str->len, orig_n->data.str->style ); break; } if ( orig_n->type_id != NULL ) { n->type_id = syck_strndup( orig_n->type_id, strlen( orig_n->type_id ) ); } if ( orig_n->anchor != NULL ) { n->anchor = syck_strndup( orig_n->anchor, strlen( orig_n->anchor ) ); } n->id = t; return rb_funcall( oDefaultResolver, s_node_import, 1, t ); } /* * Emitter callback: assembles YAML document events from * Ruby symbols. This is a brilliant way to do it. * No one could possibly object. */ void rb_syck_emitter_handler(e, data) SyckEmitter *e; st_data_t data; { SyckNode *n; Data_Get_Struct((VALUE)data, SyckNode, n); switch (n->kind) { case syck_map_kind: { int i; syck_emit_map( e, n->type_id, n->data.pairs->style ); for ( i = 0; i < n->data.pairs->idx; i++ ) { syck_emit_item( e, syck_map_read( n, map_key, i ) ); syck_emit_item( e, syck_map_read( n, map_value, i ) ); } syck_emit_end( e ); } break; case syck_seq_kind: { int i; syck_emit_seq( e, n->type_id, n->data.list->style ); for ( i = 0; i < n->data.list->idx; i++ ) { syck_emit_item( e, syck_seq_read( n, i ) ); } syck_emit_end( e ); } break; case syck_str_kind: { syck_emit_scalar( e, n->type_id, n->data.str->style, 0, 0, 0, n->data.str->ptr, n->data.str->len ); } break; } } /* * Handle output from the emitter */ void rb_syck_output_handler( emitter, str, len ) SyckEmitter *emitter; char *str; long len; { struct emitter_xtra *bonus = (struct emitter_xtra *)emitter->bonus; VALUE dest = bonus->port; if (TYPE(dest) == T_STRING) { rb_str_cat( dest, str, len ); } else { rb_io_write( dest, rb_str_new( str, len ) ); } } /* * Helper function for marking nodes in the anchor * symbol table. */ void syck_out_mark( emitter, node ) VALUE emitter, node; { SyckEmitter *emitterPtr; struct emitter_xtra *bonus; Data_Get_Struct(emitter, SyckEmitter, emitterPtr); bonus = (struct emitter_xtra *)emitterPtr->bonus; rb_ivar_set( node, s_emitter, emitter ); /* syck_emitter_mark_node( emitterPtr, (st_data_t)node ); */ if ( !NIL_P( bonus->oid ) ) { rb_hash_aset( bonus->data, bonus->oid, node ); } } /* * Mark emitter values. */ static void syck_mark_emitter(emitter) SyckEmitter *emitter; { struct emitter_xtra *bonus = (struct emitter_xtra *)emitter->bonus; rb_gc_mark( bonus->oid ); rb_gc_mark( bonus->data ); rb_gc_mark( bonus->port ); } /* * Free the emitter and any bonus attachment. */ void rb_syck_free_emitter(e) SyckEmitter *e; { S_FREE( e->bonus ); syck_free_emitter(e); } /* * YAML::Syck::Emitter.allocate */ VALUE syck_emitter_s_alloc _((VALUE)); VALUE syck_emitter_s_alloc(class) VALUE class; { VALUE pobj; SyckEmitter *emitter = syck_new_emitter(); emitter->bonus = S_ALLOC( struct emitter_xtra ); S_MEMZERO( emitter->bonus, struct emitter_xtra, 1 ); pobj = Data_Wrap_Struct( class, syck_mark_emitter, rb_syck_free_emitter, emitter ); syck_emitter_handler( emitter, rb_syck_emitter_handler ); syck_output_handler( emitter, rb_syck_output_handler ); rb_ivar_set( pobj, s_out, rb_funcall( cOut, s_new, 1, pobj ) ); return pobj; } /* * YAML::Syck::Emitter.reset( options ) */ VALUE syck_emitter_reset( argc, argv, self ) int argc; VALUE *argv; VALUE self; { VALUE options, tmp; SyckEmitter *emitter; struct emitter_xtra *bonus; Data_Get_Struct(self, SyckEmitter, emitter); bonus = (struct emitter_xtra *)emitter->bonus; bonus->oid = Qnil; bonus->port = rb_str_new2( "" ); bonus->data = rb_hash_new(); if (rb_scan_args(argc, argv, "01", &options) == 0) { options = rb_hash_new(); rb_ivar_set(self, s_options, options); } else if ( !NIL_P(tmp = rb_check_string_type(options)) ) { bonus->port = tmp; } else if ( rb_respond_to( options, s_write ) ) { bonus->port = options; } else { Check_Type(options, T_HASH); rb_ivar_set(self, s_options, options); } emitter->headless = 0; rb_ivar_set(self, s_level, INT2FIX(0)); rb_ivar_set(self, s_resolver, Qnil); return self; } /* * YAML::Syck::Emitter.emit( object_id ) { |out| ... } */ VALUE syck_emitter_emit( argc, argv, self ) int argc; VALUE *argv; VALUE self; { VALUE oid, proc; SyckEmitter *emitter; struct emitter_xtra *bonus; SYMID symple; int level = FIX2INT(rb_ivar_get(self, s_level)) + 1; rb_ivar_set(self, s_level, INT2FIX(level)); rb_scan_args(argc, argv, "1&", &oid, &proc); Data_Get_Struct(self, SyckEmitter, emitter); bonus = (struct emitter_xtra *)emitter->bonus; /* Calculate anchors, normalize nodes, build a simpler symbol table */ bonus->oid = oid; if ( !NIL_P( oid ) && RTEST( rb_funcall( bonus->data, s_haskey, 1, oid ) ) ) { symple = rb_hash_aref( bonus->data, oid ); } else { symple = rb_funcall( proc, s_call, 1, rb_ivar_get( self, s_out ) ); } syck_emitter_mark_node( emitter, (st_data_t)symple ); /* Second pass, build emitted string */ level -= 1; rb_ivar_set(self, s_level, INT2FIX(level)); if ( level == 0 ) { syck_emit(emitter, (st_data_t)symple); syck_emitter_flush(emitter, 0); return bonus->port; } return symple; } /* * YAML::Syck::Emitter#node_export */ VALUE syck_emitter_node_export( self, node ) VALUE self, node; { return rb_funcall( node, s_to_yaml, 1, self ); } /* * YAML::Syck::Emitter#set_resolver */ VALUE syck_emitter_set_resolver( self, resolver ) VALUE self, resolver; { rb_ivar_set( self, s_resolver, resolver ); return self; } /* * YAML::Syck::Out::initialize */ VALUE syck_out_initialize( self, emitter ) VALUE self, emitter; { rb_ivar_set( self, s_emitter, emitter ); return self; } /* * YAML::Syck::Out::map */ VALUE syck_out_map( argc, argv, self ) int argc; VALUE *argv; VALUE self; { VALUE type_id, style, map; if (rb_scan_args(argc, argv, "11", &type_id, &style) == 1) { style = Qnil; } map = rb_funcall( cMap, s_new, 3, type_id, rb_hash_new(), style ); syck_out_mark( rb_ivar_get( self, s_emitter ), map ); rb_yield( map ); return map; } /* * YAML::Syck::Out::seq */ VALUE syck_out_seq( argc, argv, self ) int argc; VALUE *argv; VALUE self; { VALUE type_id, style, seq; if (rb_scan_args(argc, argv, "11", &type_id, &style) == 1) { style = Qnil; } seq = rb_funcall( cSeq, s_new, 3, type_id, rb_ary_new(), style ); syck_out_mark( rb_ivar_get( self, s_emitter ), seq ); rb_yield( seq ); return seq; } /* * YAML::Syck::Out::scalar syck_out_scalar( self, type_id, str, style ) VALUE self, type_id, str, style; */ VALUE syck_out_scalar( argc, argv, self ) int argc; VALUE *argv; VALUE self; { VALUE type_id, str, style, scalar; if (rb_scan_args(argc, argv, "21", &type_id, &str, &style) == 2) { style = Qnil; } scalar = rb_funcall( cScalar, s_new, 3, type_id, str, style ); syck_out_mark( rb_ivar_get( self, s_emitter ), scalar ); return scalar; } /* * Initialize Syck extension */ void Init_syck() { VALUE rb_yaml = rb_define_module( "YAML" ); VALUE rb_syck = rb_define_module_under( rb_yaml, "Syck" ); rb_define_const( rb_syck, "VERSION", rb_str_new2( SYCK_VERSION ) ); rb_define_module_function( rb_syck, "compile", rb_syck_compile, 1 ); /* * Global symbols */ s_new = rb_intern("new"); s_utc = rb_intern("utc"); s_at = rb_intern("at"); s_to_f = rb_intern("to_f"); s_to_i = rb_intern("to_i"); s_read = rb_intern("read"); s_binmode = rb_intern("binmode"); s_transfer = rb_intern("transfer"); s_call = rb_intern("call"); s_cmp = rb_intern("<=>"); s_intern = rb_intern("intern"); s_update = rb_intern("update"); s_detect_implicit = rb_intern("detect_implicit"); s_dup = rb_intern("dup"); s_default_set = rb_intern("default="); s_match = rb_intern("match"); s_push = rb_intern("push"); s_haskey = rb_intern("has_key?"); s_keys = rb_intern("keys"); s_node_import = rb_intern("node_import"); s_tr_bang = rb_intern("tr!"); s_unpack = rb_intern("unpack"); s_write = rb_intern("write"); s_tag_read_class = rb_intern( "yaml_tag_read_class" ); s_tag_subclasses = rb_intern( "yaml_tag_subclasses?" ); s_emitter = rb_intern( "emitter" ); s_set_resolver = rb_intern( "set_resolver" ); s_node_export = rb_intern( "node_export" ); s_to_yaml = rb_intern( "to_yaml" ); s_transform = rb_intern( "transform" ); s_yaml_new = rb_intern("yaml_new"); s_yaml_initialize = rb_intern("yaml_initialize"); s_tags = rb_intern("@tags"); s_name = rb_intern("@name"); s_options = rb_intern("@options"); s_kind = rb_intern("@kind"); s_type_id = rb_intern("@type_id"); s_type_id_set = rb_intern("type_id="); s_resolver = rb_intern("@resolver"); s_level = rb_intern( "@level" ); s_style = rb_intern("@style"); s_style_set = rb_intern("style="); s_value = rb_intern("@value"); s_value_set = rb_intern("value="); s_out = rb_intern("@out"); s_input = rb_intern("@input"); sym_model = ID2SYM(rb_intern("Model")); sym_generic = ID2SYM(rb_intern("Generic")); sym_bytecode = ID2SYM(rb_intern("bytecode")); sym_map = ID2SYM(rb_intern("map")); sym_scalar = ID2SYM(rb_intern("scalar")); sym_seq = ID2SYM(rb_intern("seq")); sym_1quote = ID2SYM(rb_intern("quote1")); sym_2quote = ID2SYM(rb_intern("quote2")); sym_fold = ID2SYM(rb_intern("fold")); sym_literal = ID2SYM(rb_intern("literal")); sym_plain = ID2SYM(rb_intern("plain")); sym_inline = ID2SYM(rb_intern("inline")); /* * Define YAML::Syck::Resolver class */ cResolver = rb_define_class_under( rb_syck, "Resolver", rb_cObject ); rb_define_attr( cResolver, "tags", 1, 1 ); rb_define_method( cResolver, "initialize", syck_resolver_initialize, 0 ); rb_define_method( cResolver, "add_type", syck_resolver_add_type, 2 ); rb_define_method( cResolver, "use_types_at", syck_resolver_use_types_at, 1 ); rb_define_method( cResolver, "detect_implicit", syck_resolver_detect_implicit, 1 ); rb_define_method( cResolver, "transfer", syck_resolver_transfer, 2 ); rb_define_method( cResolver, "node_import", syck_resolver_node_import, 1 ); rb_define_method( cResolver, "tagurize", syck_resolver_tagurize, 1 ); rb_global_variable( &oDefaultResolver ); oDefaultResolver = rb_funcall( cResolver, rb_intern( "new" ), 0 ); rb_define_singleton_method( oDefaultResolver, "node_import", syck_defaultresolver_node_import, 1 ); rb_define_singleton_method( oDefaultResolver, "detect_implicit", syck_defaultresolver_detect_implicit, 1 ); rb_define_const( rb_syck, "DefaultResolver", oDefaultResolver ); rb_global_variable( &oGenericResolver ); oGenericResolver = rb_funcall( cResolver, rb_intern( "new" ), 0 ); rb_define_singleton_method( oGenericResolver, "node_import", syck_genericresolver_node_import, 1 ); rb_define_const( rb_syck, "GenericResolver", oGenericResolver ); /* * Define YAML::Syck::Parser class */ cParser = rb_define_class_under( rb_syck, "Parser", rb_cObject ); rb_define_attr( cParser, "options", 1, 1 ); rb_define_attr( cParser, "resolver", 1, 1 ); rb_define_attr( cParser, "input", 1, 1 ); rb_define_alloc_func( cParser, syck_parser_s_alloc ); rb_define_method(cParser, "initialize", syck_parser_initialize, -1 ); rb_define_method(cParser, "bufsize=", syck_parser_bufsize_set, 1 ); rb_define_method(cParser, "bufsize", syck_parser_bufsize_get, 0 ); rb_define_method(cParser, "load", syck_parser_load, -1); rb_define_method(cParser, "load_documents", syck_parser_load_documents, -1); rb_define_method(cParser, "set_resolver", syck_parser_set_resolver, 1); /* * Define YAML::Syck::Node class */ cNode = rb_define_class_under( rb_syck, "Node", rb_cObject ); rb_define_method( cNode, "initialize_copy", syck_node_init_copy, 1 ); rb_define_attr( cNode, "emitter", 1, 1 ); rb_define_attr( cNode, "resolver", 1, 1 ); rb_define_attr( cNode, "kind", 1, 0 ); rb_define_attr( cNode, "type_id", 1, 0 ); rb_define_attr( cNode, "value", 1, 0 ); rb_define_method( cNode, "type_id=", syck_node_type_id_set, 1 ); rb_define_method( cNode, "transform", syck_node_transform, 0); /* * Define YAML::Syck::Scalar, YAML::Syck::Seq, YAML::Syck::Map -- * all are the publicly usable variants of YAML::Syck::Node */ cScalar = rb_define_class_under( rb_syck, "Scalar", cNode ); rb_define_alloc_func( cScalar, syck_scalar_alloc ); rb_define_method( cScalar, "initialize", syck_scalar_initialize, 3 ); rb_define_method( cScalar, "value=", syck_scalar_value_set, 1 ); rb_define_method( cScalar, "style=", syck_scalar_style_set, 1 ); cSeq = rb_define_class_under( rb_syck, "Seq", cNode ); rb_define_alloc_func( cSeq, syck_seq_alloc ); rb_define_method( cSeq, "initialize", syck_seq_initialize, 3 ); rb_define_method( cSeq, "value=", syck_seq_value_set, 1 ); rb_define_method( cSeq, "add", syck_seq_add_m, 1 ); rb_define_method( cSeq, "style=", syck_seq_style_set, 1 ); cMap = rb_define_class_under( rb_syck, "Map", cNode ); rb_define_alloc_func( cMap, syck_map_alloc ); rb_define_method( cMap, "initialize", syck_map_initialize, 3 ); rb_define_method( cMap, "value=", syck_map_value_set, 1 ); rb_define_method( cMap, "add", syck_map_add_m, 2 ); rb_define_method( cMap, "style=", syck_map_style_set, 1 ); /* * Define YAML::PrivateType class */ cPrivateType = rb_define_class_under( rb_yaml, "PrivateType", rb_cObject ); rb_define_attr( cPrivateType, "type_id", 1, 1 ); rb_define_attr( cPrivateType, "value", 1, 1 ); rb_define_method( cPrivateType, "initialize", syck_privatetype_initialize, 2); /* * Define YAML::DomainType class */ cDomainType = rb_define_class_under( rb_yaml, "DomainType", rb_cObject ); rb_define_attr( cDomainType, "domain", 1, 1 ); rb_define_attr( cDomainType, "type_id", 1, 1 ); rb_define_attr( cDomainType, "value", 1, 1 ); rb_define_method( cDomainType, "initialize", syck_domaintype_initialize, 3); /* * Define YAML::Object class */ cYObject = rb_define_class_under( rb_yaml, "Object", rb_cObject ); rb_define_attr( cYObject, "class", 1, 1 ); rb_define_attr( cYObject, "ivars", 1, 1 ); rb_define_method( cYObject, "initialize", syck_yobject_initialize, 2); rb_define_method( cYObject, "yaml_initialize", syck_yobject_initialize, 2); /* * Define YAML::Syck::BadAlias class */ cBadAlias = rb_define_class_under( rb_syck, "BadAlias", rb_cObject ); rb_define_attr( cBadAlias, "name", 1, 1 ); rb_define_method( cBadAlias, "initialize", syck_badalias_initialize, 1); rb_define_method( cBadAlias, "<=>", syck_badalias_cmp, 1); rb_include_module( cBadAlias, rb_const_get( rb_cObject, rb_intern("Comparable") ) ); /* * Define YAML::Syck::MergeKey class */ cMergeKey = rb_define_class_under( rb_syck, "MergeKey", rb_cObject ); /* * Define YAML::Syck::DefaultKey class */ cDefaultKey = rb_define_class_under( rb_syck, "DefaultKey", rb_cObject ); /* * Define YAML::Syck::Out classes */ cOut = rb_define_class_under( rb_syck, "Out", rb_cObject ); rb_define_attr( cOut, "emitter", 1, 1 ); rb_define_method( cOut, "initialize", syck_out_initialize, 1 ); rb_define_method( cOut, "map", syck_out_map, -1 ); rb_define_method( cOut, "seq", syck_out_seq, -1 ); rb_define_method( cOut, "scalar", syck_out_scalar, -1 ); /* * Define YAML::Syck::Emitter class */ cEmitter = rb_define_class_under( rb_syck, "Emitter", rb_cObject ); rb_define_attr( cEmitter, "level", 1, 1 ); rb_define_alloc_func( cEmitter, syck_emitter_s_alloc ); rb_define_method( cEmitter, "initialize", syck_emitter_reset, -1 ); rb_define_method( cEmitter, "reset", syck_emitter_reset, -1 ); rb_define_method( cEmitter, "emit", syck_emitter_emit, -1 ); rb_define_method( cEmitter, "set_resolver", syck_emitter_set_resolver, 1); rb_define_method( cEmitter, "node_export", syck_emitter_node_export, 1); } ================================================ FILE: ext/syck/syck.c ================================================ /* * syck.c * * $Author$ * $Date$ * * Copyright (C) 2003 why the lucky stiff */ #include "ruby.h" #include #include #include "syck.h" void syck_parser_pop_level( SyckParser * ); /* * Custom assert */ void syck_assert( char *file_name, unsigned line_num ) { fflush( NULL ); fprintf( stderr, "\nAssertion failed: %s, line %u\n", file_name, line_num ); fflush( stderr ); abort(); } /* * Allocates and copies a string */ char * syck_strndup( char *buf, long len ) { char *new = S_ALLOC_N( char, len + 1 ); S_MEMZERO( new, char, len + 1 ); S_MEMCPY( new, buf, char, len ); return new; } /* * Default FILE IO function */ long syck_io_file_read( char *buf, SyckIoFile *file, long max_size, long skip ) { long len = 0; ASSERT( file != NULL ); max_size -= skip; len = fread( buf + skip, sizeof( char ), max_size, file->ptr ); len += skip; buf[len] = '\0'; return len; } /* * Default string IO function */ long syck_io_str_read( char *buf, SyckIoStr *str, long max_size, long skip ) { char *beg; long len = 0; ASSERT( str != NULL ); beg = str->ptr; if ( max_size >= 0 ) { max_size -= skip; if ( max_size <= 0 ) max_size = 0; else str->ptr += max_size; if ( str->ptr > str->end ) { str->ptr = str->end; } } else { /* Use exact string length */ while ( str->ptr < str->end ) { if (*(str->ptr++) == '\n') break; } } if ( beg < str->ptr ) { len = ( str->ptr - beg ); S_MEMCPY( buf + skip, beg, char, len ); } len += skip; buf[len] = '\0'; return len; } void syck_parser_reset_levels( SyckParser *p ) { while ( p->lvl_idx > 1 ) { syck_parser_pop_level( p ); } if ( p->lvl_idx < 1 ) { p->lvl_idx = 1; p->levels[0].spaces = -1; p->levels[0].ncount = 0; p->levels[0].domain = syck_strndup( "", 0 ); } p->levels[0].status = syck_lvl_header; } void syck_parser_reset_cursor( SyckParser *p ) { if ( p->buffer == NULL ) { p->buffer = S_ALLOC_N( char, p->bufsize ); S_MEMZERO( p->buffer, char, p->bufsize ); } p->buffer[0] = '\0'; p->cursor = NULL; p->lineptr = NULL; p->linectptr = NULL; p->token = NULL; p->toktmp = NULL; p->marker = NULL; p->limit = NULL; p->root = 0; p->root_on_error = 0; p->linect = 0; p->eof = 0; p->last_token = 0; p->force_token = 0; } /* * Value to return on a parse error */ void syck_parser_set_root_on_error( SyckParser *p, SYMID roer ) { p->root_on_error = roer; } /* * Allocate the parser */ SyckParser * syck_new_parser() { SyckParser *p; p = S_ALLOC( SyckParser ); S_MEMZERO( p, SyckParser, 1 ); p->lvl_capa = ALLOC_CT; p->levels = S_ALLOC_N( SyckLevel, p->lvl_capa ); p->input_type = syck_yaml_utf8; p->io_type = syck_io_str; p->io.str = NULL; p->syms = NULL; p->anchors = NULL; p->bad_anchors = NULL; p->implicit_typing = 1; p->taguri_expansion = 0; p->bufsize = SYCK_BUFFERSIZE; p->buffer = NULL; p->lvl_idx = 0; syck_parser_reset_levels( p ); return p; } int syck_add_sym( SyckParser *p, char *data ) { SYMID id = 0; if ( p->syms == NULL ) { p->syms = st_init_numtable(); } id = p->syms->num_entries + 1; st_insert( p->syms, id, (st_data_t)data ); return id; } int syck_lookup_sym( SyckParser *p, SYMID id, char **data ) { if ( p->syms == NULL ) return 0; return st_lookup( p->syms, id, (st_data_t *)data ); } int syck_st_free_nodes( char *key, SyckNode *n, char *arg ) { if ( n != (void *)1 ) syck_free_node( n ); n = NULL; return ST_CONTINUE; } void syck_st_free( SyckParser *p ) { /* * Free the anchor tables */ if ( p->anchors != NULL ) { st_foreach( p->anchors, syck_st_free_nodes, 0 ); st_free_table( p->anchors ); p->anchors = NULL; } if ( p->bad_anchors != NULL ) { st_foreach( p->bad_anchors, syck_st_free_nodes, 0 ); st_free_table( p->bad_anchors ); p->bad_anchors = NULL; } } void syck_free_parser( SyckParser *p ) { /* * Free the adhoc symbol table */ if ( p->syms != NULL ) { st_free_table( p->syms ); p->syms = NULL; } /* * Free tables, levels */ syck_st_free( p ); syck_parser_reset_levels( p ); S_FREE( p->levels[0].domain ); S_FREE( p->levels ); if ( p->buffer != NULL ) { S_FREE( p->buffer ); } free_any_io( p ); S_FREE( p ); } void syck_parser_handler( SyckParser *p, SyckNodeHandler hdlr ) { ASSERT( p != NULL ); p->handler = hdlr; } void syck_parser_implicit_typing( SyckParser *p, int flag ) { p->implicit_typing = ( flag == 0 ? 0 : 1 ); } void syck_parser_taguri_expansion( SyckParser *p, int flag ) { p->taguri_expansion = ( flag == 0 ? 0 : 1 ); } void syck_parser_error_handler( SyckParser *p, SyckErrorHandler hdlr ) { ASSERT( p != NULL ); p->error_handler = hdlr; } void syck_parser_bad_anchor_handler( SyckParser *p, SyckBadAnchorHandler hdlr ) { ASSERT( p != NULL ); p->bad_anchor_handler = hdlr; } void syck_parser_set_input_type( SyckParser *p, enum syck_parser_input input_type ) { ASSERT( p != NULL ); p->input_type = input_type; } void syck_parser_file( SyckParser *p, FILE *fp, SyckIoFileRead read ) { ASSERT( p != NULL ); free_any_io( p ); syck_parser_reset_cursor( p ); p->io_type = syck_io_file; p->io.file = S_ALLOC( SyckIoFile ); p->io.file->ptr = fp; if ( read != NULL ) { p->io.file->read = read; } else { p->io.file->read = syck_io_file_read; } } void syck_parser_str( SyckParser *p, char *ptr, long len, SyckIoStrRead read ) { ASSERT( p != NULL ); free_any_io( p ); syck_parser_reset_cursor( p ); p->io_type = syck_io_str; p->io.str = S_ALLOC( SyckIoStr ); p->io.str->beg = ptr; p->io.str->ptr = ptr; p->io.str->end = ptr + len; if ( read != NULL ) { p->io.str->read = read; } else { p->io.str->read = syck_io_str_read; } } void syck_parser_str_auto( SyckParser *p, char *ptr, SyckIoStrRead read ) { syck_parser_str( p, ptr, strlen( ptr ), read ); } SyckLevel * syck_parser_current_level( SyckParser *p ) { return &p->levels[p->lvl_idx-1]; } void syck_parser_pop_level( SyckParser *p ) { ASSERT( p != NULL ); /* The root level should never be popped */ if ( p->lvl_idx <= 1 ) return; p->lvl_idx -= 1; free( p->levels[p->lvl_idx].domain ); } void syck_parser_add_level( SyckParser *p, int len, enum syck_level_status status ) { ASSERT( p != NULL ); if ( p->lvl_idx + 1 > p->lvl_capa ) { p->lvl_capa += ALLOC_CT; S_REALLOC_N( p->levels, SyckLevel, p->lvl_capa ); } ASSERT( len > p->levels[p->lvl_idx-1].spaces ); p->levels[p->lvl_idx].spaces = len; p->levels[p->lvl_idx].ncount = 0; p->levels[p->lvl_idx].domain = syck_strndup( p->levels[p->lvl_idx-1].domain, strlen( p->levels[p->lvl_idx-1].domain ) ); p->levels[p->lvl_idx].status = status; p->lvl_idx += 1; } void free_any_io( SyckParser *p ) { ASSERT( p != NULL ); switch ( p->io_type ) { case syck_io_str: if ( p->io.str != NULL ) { S_FREE( p->io.str ); p->io.str = NULL; } break; case syck_io_file: if ( p->io.file != NULL ) { S_FREE( p->io.file ); p->io.file = NULL; } break; } } long syck_move_tokens( SyckParser *p ) { long count, skip; ASSERT( p->buffer != NULL ); if ( p->token == NULL ) return 0; skip = p->limit - p->token; if ( ( count = p->token - p->buffer ) ) { if (skip > 0) S_MEMMOVE( p->buffer, p->token, char, skip ); p->token = p->buffer; p->marker -= count; p->cursor -= count; p->toktmp -= count; p->limit -= count; p->lineptr -= count; p->linectptr -= count; } return skip; } void syck_check_limit( SyckParser *p, long len ) { if ( p->cursor == NULL ) { p->cursor = p->buffer; p->lineptr = p->buffer; p->linectptr = p->buffer; p->marker = p->buffer; } p->limit = p->buffer + len; } long syck_parser_read( SyckParser *p ) { long len = 0; long skip = 0; ASSERT( p != NULL ); switch ( p->io_type ) { case syck_io_str: skip = syck_move_tokens( p ); len = (p->io.str->read)( p->buffer, p->io.str, SYCK_BUFFERSIZE - 1, skip ); break; case syck_io_file: skip = syck_move_tokens( p ); len = (p->io.file->read)( p->buffer, p->io.file, SYCK_BUFFERSIZE - 1, skip ); break; } syck_check_limit( p, len ); return len; } long syck_parser_readlen( SyckParser *p, long max_size ) { long len = 0; long skip = 0; ASSERT( p != NULL ); switch ( p->io_type ) { case syck_io_str: skip = syck_move_tokens( p ); len = (p->io.str->read)( p->buffer, p->io.str, max_size, skip ); break; case syck_io_file: skip = syck_move_tokens( p ); len = (p->io.file->read)( p->buffer, p->io.file, max_size, skip ); break; } syck_check_limit( p, len ); return len; } SYMID syck_parse( SyckParser *p ) { ASSERT( p != NULL ); syck_st_free( p ); syck_parser_reset_levels( p ); syckparse( p ); return p->root; } void syck_default_error_handler( SyckParser *p, char *msg ) { printf( "Error at [Line %d, Col %d]: %s\n", p->linect, p->cursor - p->lineptr, msg ); } ================================================ FILE: ext/syck/syck.h ================================================ /* * syck.h * * $Author$ * $Date$ * * Copyright (C) 2003 why the lucky stiff */ #ifndef SYCK_H #define SYCK_H #define SYCK_YAML_MAJOR 1 #define SYCK_YAML_MINOR 0 #define SYCK_VERSION "0.60" #define YAML_DOMAIN "yaml.org,2002" #include #include #include #include "st.h" #if defined(__cplusplus) extern "C" { #endif /* * Memory Allocation */ #if defined(HAVE_ALLOCA_H) && !defined(__GNUC__) #include #endif #if DEBUG void syck_assert( char *, unsigned ); # define ASSERT(f) \ if ( f ) \ {} \ else \ syck_assert( __FILE__, __LINE__ ) #else # define ASSERT(f) #endif #ifndef NULL # define NULL (void *)0 #endif #define ALLOC_CT 8 #define SYCK_BUFFERSIZE 4096 #define S_ALLOC_N(type,n) (type*)malloc(sizeof(type)*(n)) #define S_ALLOC(type) (type*)malloc(sizeof(type)) #define S_REALLOC_N(var,type,n) (var)=(type*)realloc((char*)(var),sizeof(type)*(n)) #define S_FREE(n) if (n) { free(n); n = NULL; } #define S_ALLOCA_N(type,n) (type*)alloca(sizeof(type)*(n)) #define S_MEMZERO(p,type,n) memset((p), 0, sizeof(type)*(n)) #define S_MEMCPY(p1,p2,type,n) memcpy((p1), (p2), sizeof(type)*(n)) #define S_MEMMOVE(p1,p2,type,n) memmove((p1), (p2), sizeof(type)*(n)) #define S_MEMCMP(p1,p2,type,n) memcmp((p1), (p2), sizeof(type)*(n)) #define BLOCK_FOLD 10 #define BLOCK_LIT 20 #define BLOCK_PLAIN 30 #define NL_CHOMP 40 #define NL_KEEP 50 /* * Node definitions */ #ifndef ST_DATA_T_DEFINED typedef long st_data_t; #endif #define SYMID unsigned long typedef struct _syck_node SyckNode; enum syck_kind_tag { syck_map_kind, syck_seq_kind, syck_str_kind }; enum map_part { map_key, map_value }; enum map_style { map_none, map_inline }; enum seq_style { seq_none, seq_inline }; enum scalar_style { scalar_none, scalar_1quote, scalar_2quote, scalar_fold, scalar_literal, scalar_plain }; /* * Node metadata struct */ struct _syck_node { /* Symbol table ID */ SYMID id; /* Underlying kind */ enum syck_kind_tag kind; /* Fully qualified tag-uri for type */ char *type_id; /* Anchor name */ char *anchor; union { /* Storage for map data */ struct SyckMap { enum map_style style; SYMID *keys; SYMID *values; long capa; long idx; } *pairs; /* Storage for sequence data */ struct SyckSeq { enum seq_style style; SYMID *items; long capa; long idx; } *list; /* Storage for string data */ struct SyckStr { enum scalar_style style; char *ptr; long len; } *str; } data; /* Shortcut node */ void *shortcut; }; /* * Parser definitions */ typedef struct _syck_parser SyckParser; typedef struct _syck_file SyckIoFile; typedef struct _syck_str SyckIoStr; typedef struct _syck_level SyckLevel; typedef SYMID (*SyckNodeHandler)(SyckParser *, SyckNode *); typedef void (*SyckErrorHandler)(SyckParser *, char *); typedef SyckNode * (*SyckBadAnchorHandler)(SyckParser *, char *); typedef long (*SyckIoFileRead)(char *, SyckIoFile *, long, long); typedef long (*SyckIoStrRead)(char *, SyckIoStr *, long, long); enum syck_io_type { syck_io_str, syck_io_file }; enum syck_parser_input { syck_yaml_utf8, syck_yaml_utf16, syck_yaml_utf32, syck_bytecode_utf8 }; enum syck_level_status { syck_lvl_header, syck_lvl_doc, syck_lvl_open, syck_lvl_seq, syck_lvl_map, syck_lvl_block, syck_lvl_str, syck_lvl_iseq, syck_lvl_imap, syck_lvl_end, syck_lvl_pause, syck_lvl_anctag, syck_lvl_mapx, syck_lvl_seqx }; /* * Parser structs */ struct _syck_file { /* File pointer */ FILE *ptr; /* Function which FILE -> buffer */ SyckIoFileRead read; }; struct _syck_str { /* String buffer pointers */ char *beg, *ptr, *end; /* Function which string -> buffer */ SyckIoStrRead read; }; struct _syck_level { /* Indent */ int spaces; /* Counts nodes emitted at this level, useful for parsing * keys and pairs in bytecode */ int ncount; /* Does node have anchors or tags? */ int anctag; /* Domain prefixing at the given level */ char *domain; /* Keeps a node status */ enum syck_level_status status; }; struct _syck_parser { /* Root node */ SYMID root, root_on_error; /* Implicit typing flag */ int implicit_typing, taguri_expansion; /* Scripting language function to handle nodes */ SyckNodeHandler handler; /* Error handler */ SyckErrorHandler error_handler; /* InvalidAnchor handler */ SyckBadAnchorHandler bad_anchor_handler; /* Parser input type */ enum syck_parser_input input_type; /* IO type */ enum syck_io_type io_type; /* Custom buffer size */ size_t bufsize; /* Buffer pointers */ char *buffer, *linectptr, *lineptr, *toktmp, *token, *cursor, *marker, *limit; /* Line counter */ int linect; /* Last token from yylex() */ int last_token; /* Force a token upon next call to yylex() */ int force_token; /* EOF flag */ int eof; union { SyckIoFile *file; SyckIoStr *str; } io; /* Symbol table for anchors */ st_table *anchors, *bad_anchors; /* Optional symbol table for SYMIDs */ st_table *syms; /* Levels of indentation */ SyckLevel *levels; int lvl_idx; int lvl_capa; /* Pointer for extension's use */ void *bonus; }; /* * Emitter definitions */ typedef struct _syck_emitter SyckEmitter; typedef struct _syck_emitter_node SyckEmitterNode; typedef void (*SyckOutputHandler)(SyckEmitter *, char *, long); typedef void (*SyckEmitterHandler)(SyckEmitter *, st_data_t); enum doc_stage { doc_open, doc_processing }; /* * Emitter struct */ struct _syck_emitter { /* Headerless doc flag */ int headless; /* Force header? */ int use_header; /* Force version? */ int use_version; /* Sort hash keys */ int sort_keys; /* Anchor format */ char *anchor_format; /* Explicit typing on all collections? */ int explicit_typing; /* Best width on folded scalars */ int best_width; /* Use literal[1] or folded[2] blocks on all text? */ enum scalar_style style; /* Stage of written document */ enum doc_stage stage; /* Level counter */ int level; /* Default indentation */ int indent; /* Object ignore ID */ SYMID ignore_id; /* Symbol table for anchors */ st_table *markers, *anchors, *anchored; /* Custom buffer size */ size_t bufsize; /* Buffer */ char *buffer, *marker; /* Absolute position of the buffer */ long bufpos; /* Handler for emitter nodes */ SyckEmitterHandler emitter_handler; /* Handler for output */ SyckOutputHandler output_handler; /* Levels of indentation */ SyckLevel *levels; int lvl_idx; int lvl_capa; /* Pointer for extension's use */ void *bonus; }; /* * Emitter node metadata struct */ struct _syck_emitter_node { /* Node buffer position */ long pos; /* Current indent */ long indent; /* Collection? */ int is_shortcut; }; /* * Handler prototypes */ SYMID syck_hdlr_add_node( SyckParser *, SyckNode * ); SyckNode *syck_hdlr_add_anchor( SyckParser *, char *, SyckNode * ); void syck_hdlr_remove_anchor( SyckParser *, char * ); SyckNode *syck_hdlr_get_anchor( SyckParser *, char * ); void syck_add_transfer( char *, SyckNode *, int ); char *syck_xprivate( char *, int ); char *syck_taguri( char *, char *, int ); int syck_tagcmp( char *, char * ); int syck_add_sym( SyckParser *, char * ); int syck_lookup_sym( SyckParser *, SYMID, char ** ); int syck_try_implicit( SyckNode * ); char *syck_type_id_to_uri( char * ); void try_tag_implicit( SyckNode *, int ); char *syck_match_implicit( char *, size_t ); /* * API prototypes */ char *syck_strndup( char *, long ); long syck_io_file_read( char *, SyckIoFile *, long, long ); long syck_io_str_read( char *, SyckIoStr *, long, long ); char *syck_base64enc( char *, long ); char *syck_base64dec( char *, long ); SyckEmitter *syck_new_emitter(); SYMID syck_emitter_mark_node( SyckEmitter *, st_data_t ); void syck_emitter_ignore_id( SyckEmitter *, SYMID ); void syck_output_handler( SyckEmitter *, SyckOutputHandler ); void syck_emitter_handler( SyckEmitter *, SyckEmitterHandler ); void syck_free_emitter( SyckEmitter * ); void syck_emitter_clear( SyckEmitter * ); void syck_emitter_write( SyckEmitter *, char *, long ); void syck_emitter_escape( SyckEmitter *, char *, long ); void syck_emitter_flush( SyckEmitter *, long ); void syck_emit( SyckEmitter *, st_data_t ); void syck_emit_scalar( SyckEmitter *, char *, enum scalar_style, int, int, char, char *, long ); void syck_emit_1quoted( SyckEmitter *, int, char *, long ); void syck_emit_2quoted( SyckEmitter *, int, char *, long ); void syck_emit_folded( SyckEmitter *, int, char, char *, long ); void syck_emit_literal( SyckEmitter *, char, char *, long ); void syck_emit_seq( SyckEmitter *, char *, enum seq_style ); void syck_emit_item( SyckEmitter *, st_data_t ); void syck_emit_map( SyckEmitter *, char *, enum map_style ); void syck_emit_end( SyckEmitter * ); void syck_emit_tag( SyckEmitter *, char *, char * ); void syck_emit_indent( SyckEmitter * ); SyckLevel *syck_emitter_current_level( SyckEmitter * ); SyckLevel *syck_emitter_parent_level( SyckEmitter * ); void syck_emitter_pop_level( SyckEmitter * ); void syck_emitter_add_level( SyckEmitter *, int, enum syck_level_status ); void syck_emitter_reset_levels( SyckEmitter * ); SyckParser *syck_new_parser(); void syck_free_parser( SyckParser * ); void syck_parser_set_root_on_error( SyckParser *, SYMID ); void syck_parser_implicit_typing( SyckParser *, int ); void syck_parser_taguri_expansion( SyckParser *, int ); int syck_scan_scalar( int, char *, long ); void syck_parser_handler( SyckParser *, SyckNodeHandler ); void syck_parser_error_handler( SyckParser *, SyckErrorHandler ); void syck_parser_bad_anchor_handler( SyckParser *, SyckBadAnchorHandler ); void syck_parser_set_input_type( SyckParser *, enum syck_parser_input ); void syck_parser_file( SyckParser *, FILE *, SyckIoFileRead ); void syck_parser_str( SyckParser *, char *, long, SyckIoStrRead ); void syck_parser_str_auto( SyckParser *, char *, SyckIoStrRead ); SyckLevel *syck_parser_current_level( SyckParser * ); void syck_parser_add_level( SyckParser *, int, enum syck_level_status ); void syck_parser_pop_level( SyckParser * ); void free_any_io( SyckParser * ); long syck_parser_read( SyckParser * ); long syck_parser_readlen( SyckParser *, long ); SYMID syck_parse( SyckParser * ); void syck_default_error_handler( SyckParser *, char * ); SYMID syck_yaml2byte_handler( SyckParser *, SyckNode * ); char *syck_yaml2byte( char * ); /* * Allocation prototypes */ SyckNode *syck_alloc_map(); SyckNode *syck_alloc_seq(); SyckNode *syck_alloc_str(); void syck_free_node( SyckNode * ); void syck_free_members( SyckNode * ); SyckNode *syck_new_str( char *, enum scalar_style ); SyckNode *syck_new_str2( char *, long, enum scalar_style ); void syck_replace_str( SyckNode *, char *, enum scalar_style ); void syck_replace_str2( SyckNode *, char *, long, enum scalar_style ); void syck_str_blow_away_commas( SyckNode * ); char *syck_str_read( SyckNode * ); SyckNode *syck_new_map( SYMID, SYMID ); void syck_map_empty( SyckNode * ); void syck_map_add( SyckNode *, SYMID, SYMID ); SYMID syck_map_read( SyckNode *, enum map_part, long ); void syck_map_assign( SyckNode *, enum map_part, long, SYMID ); long syck_map_count( SyckNode * ); void syck_map_update( SyckNode *, SyckNode * ); SyckNode *syck_new_seq( SYMID ); void syck_seq_empty( SyckNode * ); void syck_seq_add( SyckNode *, SYMID ); void syck_seq_assign( SyckNode *, long, SYMID ); SYMID syck_seq_read( SyckNode *, long ); long syck_seq_count( SyckNode * ); /* * Lexer prototypes */ void syckerror( char * ); int syckparse( void * ); union YYSTYPE; int sycklex( union YYSTYPE *, SyckParser * ); #if defined(__cplusplus) } /* extern "C" { */ #endif #endif /* ifndef SYCK_H */ ================================================ FILE: ext/syck/token.c ================================================ /* Generated by re2c 0.9.10 on Tue Sep 20 17:46:17 2005 */ #line 1 "token.re" /* * token.re * * $Author$ * $Date$ * * Copyright (C) 2003 why the lucky stiff */ #include "ruby.h" #include "syck.h" #include "gram.h" /* * Allocate quoted strings in chunks */ #define QUOTELEN 1024 /* * They do my bidding... */ #define YYCTYPE char #define YYCURSOR parser->cursor #define YYMARKER parser->marker #define YYLIMIT parser->limit #define YYTOKEN parser->token #define YYTOKTMP parser->toktmp #define YYLINEPTR parser->lineptr #define YYLINECTPTR parser->linectptr #define YYLINE parser->linect #define YYFILL(n) syck_parser_read(parser) /* * Repositions the cursor at `n' offset from the token start. * Only works in `Header' and `Document' sections. */ #define YYPOS(n) YYCURSOR = YYTOKEN + n /* * Track line numbers */ #define NEWLINE(ptr) YYLINEPTR = ptr + newline_len(ptr); if ( YYLINEPTR > YYLINECTPTR ) { YYLINE++; YYLINECTPTR = YYLINEPTR; } /* * I like seeing the level operations as macros... */ #define ADD_LEVEL(len, status) syck_parser_add_level( parser, len, status ) #define POP_LEVEL() syck_parser_pop_level( parser ) #define CURRENT_LEVEL() syck_parser_current_level( parser ) /* * Force a token next time around sycklex() */ #define FORCE_NEXT_TOKEN(tok) parser->force_token = tok; /* * Nice little macro to ensure we're YAML_IOPENed to the current level. * * Only use this macro in the "Document" section * */ #define ENSURE_YAML_IOPEN(last_lvl, to_len, reset) \ if ( last_lvl->spaces < to_len ) \ { \ if ( last_lvl->status == syck_lvl_iseq || last_lvl->status == syck_lvl_imap ) \ { \ goto Document; \ } \ else \ { \ ADD_LEVEL( to_len, syck_lvl_doc ); \ if ( reset == 1 ) YYPOS(0); \ return YAML_IOPEN; \ } \ } /* * Nice little macro to ensure closure of levels. * * Only use this macro in the "Document" section * */ #define ENSURE_YAML_IEND(last_lvl, to_len) \ if ( last_lvl->spaces > to_len ) \ { \ syck_parser_pop_level( parser ); \ YYPOS(0); \ return YAML_IEND; \ } /* * Concatenates quoted string items and manages allocation * to the quoted string */ #define QUOTECAT(s, c, i, l) \ { \ if ( i + 1 >= c ) \ { \ c += QUOTELEN; \ S_REALLOC_N( s, char, c ); \ } \ s[i++] = l; \ s[i] = '\0'; \ } #define QUOTECATS(s, c, i, cs, cl) \ { \ while ( i + cl >= c ) \ { \ c += QUOTELEN; \ S_REALLOC_N( s, char, c ); \ } \ S_MEMCPY( s + i, cs, char, cl ); \ i += cl; \ s[i] = '\0'; \ } /* * Tags a plain scalar with a transfer method * * Use only in "Plain" section * */ #define RETURN_IMPLICIT() \ { \ SyckNode *n = syck_alloc_str(); \ YYCURSOR = YYTOKEN; \ n->data.str->ptr = qstr; \ n->data.str->len = qidx; \ n->data.str->style = scalar_plain; \ sycklval->nodeData = n; \ if ( parser->implicit_typing == 1 ) \ { \ try_tag_implicit( sycklval->nodeData, parser->taguri_expansion ); \ } \ return YAML_PLAIN; \ } /* concat the inline characters to the plain scalar */ #define PLAIN_NOT_INL() \ if ( *(YYCURSOR - 1) == ' ' || is_newline( YYCURSOR - 1 ) ) \ { \ YYCURSOR--; \ } \ QUOTECATS(qstr, qcapa, qidx, YYTOKEN, YYCURSOR - YYTOKEN); \ goto Plain2; /* trim spaces off the end in case of indent */ #define PLAIN_IS_INL() \ char *walker = qstr + qidx - 1; \ while ( walker > qstr && ( *walker == '\n' || *walker == ' ' || *walker == '\t' ) ) \ { \ qidx--; \ walker[0] = '\0'; \ walker--; \ } /* * Keep or chomp block? * * Use only in "ScalarBlock" section * */ #define RETURN_YAML_BLOCK() \ { \ SyckNode *n = syck_alloc_str(); \ if ( ((SyckParser *)parser)->taguri_expansion == 1 ) \ { \ n->type_id = syck_taguri( YAML_DOMAIN, "str", 3 ); \ } \ else \ { \ n->type_id = syck_strndup( "str", 3 ); \ } \ n->data.str->ptr = qstr; \ n->data.str->len = qidx; \ if ( blockType == BLOCK_LIT ) { \ n->data.str->style = scalar_literal; \ } else { \ n->data.str->style = scalar_fold; \ } \ if ( qidx > 0 ) \ { \ if ( nlDoWhat != NL_KEEP ) \ { \ char *fc = n->data.str->ptr + n->data.str->len - 1; \ while ( is_newline( fc ) ) fc--; \ if ( nlDoWhat != NL_CHOMP && fc < n->data.str->ptr + n->data.str->len - 1 ) \ fc += 1; \ n->data.str->len = fc - n->data.str->ptr + 1; \ } \ } \ sycklval->nodeData = n; \ return YAML_BLOCK; \ } /* * Handles newlines, calculates indent */ #define GOBBLE_UP_YAML_INDENT( ict, start ) \ char *indent = start; \ NEWLINE(indent); \ while ( indent < YYCURSOR ) \ { \ if ( is_newline( ++indent ) ) \ { \ NEWLINE(indent); \ } \ } \ ict = 0; \ if ( *YYCURSOR == '\0' ) \ { \ ict = -1; \ start = YYCURSOR - 1; \ } \ else if ( *YYLINEPTR == ' ' ) \ { \ ict = YYCURSOR - YYLINEPTR; \ } /* * If an indent exists at the current level, back up. */ #define GET_TRUE_YAML_INDENT(indt_len) \ { \ SyckLevel *lvl_deep = CURRENT_LEVEL(); \ indt_len = lvl_deep->spaces; \ if ( lvl_deep->status == syck_lvl_seq || ( indt_len == YYCURSOR - YYLINEPTR && lvl_deep->status != syck_lvl_map ) ) \ { \ SyckLevel *lvl_over; \ parser->lvl_idx--; \ lvl_over = CURRENT_LEVEL(); \ indt_len = lvl_over->spaces; \ parser->lvl_idx++; \ } \ } /* * Argjh! I hate globals! Here for syckerror() only! */ SyckParser *syck_parser_ptr = NULL; /* * Accessory funcs later in this file. */ void eat_comments( SyckParser * ); char escape_seq( char ); int is_newline( char *ptr ); int newline_len( char *ptr ); int sycklex_yaml_utf8( YYSTYPE *, SyckParser * ); int sycklex_bytecode_utf8( YYSTYPE *, SyckParser * ); int syckwrap(); /* * My own re-entrant sycklex() using re2c. * You really get used to the limited regexp. * It's really nice to not rely on backtracking and such. */ int sycklex( YYSTYPE *sycklval, SyckParser *parser ) { switch ( parser->input_type ) { case syck_yaml_utf8: return sycklex_yaml_utf8( sycklval, parser ); case syck_yaml_utf16: syckerror( "UTF-16 is not currently supported in Syck.\nPlease contribute code to help this happen!" ); break; case syck_yaml_utf32: syckerror( "UTF-32 is not currently supported in Syck.\nPlease contribute code to help this happen!" ); break; case syck_bytecode_utf8: return sycklex_bytecode_utf8( sycklval, parser ); } return YAML_DOCSEP; } /* * Parser for standard YAML [UTF-8] */ int sycklex_yaml_utf8( YYSTYPE *sycklval, SyckParser *parser ) { int doc_level = 0; syck_parser_ptr = parser; if ( YYCURSOR == NULL ) { syck_parser_read( parser ); } if ( parser->force_token != 0 ) { int t = parser->force_token; parser->force_token = 0; return t; } #line 315 "token.re" if ( YYLINEPTR != YYCURSOR ) { goto Document; } Header: YYTOKEN = YYCURSOR; #line 307 "" { YYCTYPE yych; unsigned int yyaccept; goto yy0; ++YYCURSOR; yy0: if((YYLIMIT - YYCURSOR) < 5) YYFILL(5); yych = *YYCURSOR; switch(yych){ case 0x00: goto yy7; case 0x09: case ' ': goto yy12; case 0x0A: goto yy9; case 0x0D: goto yy11; case '#': goto yy5; case '-': goto yy2; case '.': goto yy4; default: goto yy14; } yy2: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case '-': goto yy28; default: goto yy3; } yy3: #line 374 "token.re" { YYPOS(0); goto Document; } #line 337 "" yy4: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case '.': goto yy21; default: goto yy3; } yy5: ++YYCURSOR; goto yy6; yy6: #line 356 "token.re" { eat_comments( parser ); goto Header; } #line 351 "" yy7: ++YYCURSOR; goto yy8; yy8: #line 360 "token.re" { SyckLevel *lvl = CURRENT_LEVEL(); ENSURE_YAML_IEND(lvl, -1); YYPOS(0); return 0; } #line 361 "" yy9: yyaccept = 1; yych = *(YYMARKER = ++YYCURSOR); goto yy18; yy10: #line 366 "token.re" { GOBBLE_UP_YAML_INDENT( doc_level, YYTOKEN ); goto Header; } #line 370 "" yy11: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy17; default: goto yy3; } yy12: ++YYCURSOR; yych = *YYCURSOR; goto yy16; yy13: #line 370 "token.re" { doc_level = YYCURSOR - YYLINEPTR; goto Header; } #line 384 "" yy14: yych = *++YYCURSOR; goto yy3; yy15: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy16; yy16: switch(yych){ case 0x09: case ' ': goto yy15; default: goto yy13; } yy17: yyaccept = 1; YYMARKER = ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy18; yy18: switch(yych){ case 0x0A: case ' ': goto yy17; case 0x0D: goto yy19; default: goto yy10; } yy19: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; switch(yych){ case 0x0A: goto yy17; default: goto yy20; } yy20: YYCURSOR = YYMARKER; switch(yyaccept){ case 1: goto yy10; case 0: goto yy3; } yy21: yych = *++YYCURSOR; switch(yych){ case '.': goto yy22; default: goto yy20; } yy22: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy23; case 0x0D: goto yy27; case ' ': goto yy25; default: goto yy20; } yy23: ++YYCURSOR; goto yy24; yy24: #line 342 "token.re" { SyckLevel *lvl = CURRENT_LEVEL(); if ( lvl->status == syck_lvl_header ) { goto Header; } else { ENSURE_YAML_IEND(lvl, -1); YYPOS(0); return 0; } return 0; } #line 446 "" yy25: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy26; yy26: switch(yych){ case ' ': goto yy25; default: goto yy24; } yy27: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy23; default: goto yy20; } yy28: yych = *++YYCURSOR; switch(yych){ case '-': goto yy29; default: goto yy20; } yy29: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy30; case 0x0D: goto yy34; case ' ': goto yy32; default: goto yy20; } yy30: ++YYCURSOR; goto yy31; yy31: #line 328 "token.re" { SyckLevel *lvl = CURRENT_LEVEL(); if ( lvl->status == syck_lvl_header ) { YYPOS(3); goto Directive; } else { ENSURE_YAML_IEND(lvl, -1); YYPOS(0); return 0; } } #line 489 "" yy32: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy33; yy33: switch(yych){ case ' ': goto yy32; default: goto yy31; } yy34: ++YYCURSOR; switch((yych = *YYCURSOR)) { case 0x0A: goto yy30; default: goto yy20; } } #line 378 "token.re" Document: { SyckLevel *lvl = CURRENT_LEVEL(); if ( lvl->status == syck_lvl_header ) { lvl->status = syck_lvl_doc; } YYTOKEN = YYCURSOR; #line 518 "" { YYCTYPE yych; unsigned int yyaccept; goto yy35; ++YYCURSOR; yy35: if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); yych = *YYCURSOR; switch(yych){ case 0x00: goto yy62; case 0x09: case ' ': goto yy60; case 0x0A: goto yy37; case 0x0D: goto yy39; case '!': goto yy51; case '"': goto yy55; case '#': goto yy58; case '&': goto yy49; case '\'': goto yy53; case '*': goto yy50; case ',': case ':': goto yy47; case '-': case '?': goto yy48; case '>': case '|': goto yy57; case '[': goto yy41; case ']': case '}': goto yy45; case '{': goto yy43; default: goto yy64; } yy37: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); goto yy92; yy38: #line 392 "token.re" { /* Isolate spaces */ int indt_len; GOBBLE_UP_YAML_INDENT( indt_len, YYTOKEN ); lvl = CURRENT_LEVEL(); doc_level = 0; /* XXX: Comment lookahead */ if ( *YYCURSOR == '#' ) { goto Document; } /* Ignore indentation inside inlines */ if ( lvl->status == syck_lvl_iseq || lvl->status == syck_lvl_imap ) { goto Document; } /* Check for open indent */ ENSURE_YAML_IEND(lvl, indt_len); ENSURE_YAML_IOPEN(lvl, indt_len, 0); if ( indt_len == -1 ) { return 0; } return YAML_INDENT; } #line 578 "" yy39: ++YYCURSOR; switch((yych = *YYCURSOR)) { case 0x0A: goto yy91; default: goto yy40; } yy40: #line 497 "token.re" { ENSURE_YAML_IOPEN(lvl, doc_level, 1); goto Plain; } #line 589 "" yy41: ++YYCURSOR; goto yy42; yy42: #line 420 "token.re" { ENSURE_YAML_IOPEN(lvl, doc_level, 1); lvl = CURRENT_LEVEL(); ADD_LEVEL(lvl->spaces + 1, syck_lvl_iseq); return YYTOKEN[0]; } #line 599 "" yy43: ++YYCURSOR; goto yy44; yy44: #line 426 "token.re" { ENSURE_YAML_IOPEN(lvl, doc_level, 1); lvl = CURRENT_LEVEL(); ADD_LEVEL(lvl->spaces + 1, syck_lvl_imap); return YYTOKEN[0]; } #line 609 "" yy45: ++YYCURSOR; goto yy46; yy46: #line 432 "token.re" { POP_LEVEL(); return YYTOKEN[0]; } #line 617 "" yy47: yyaccept = 1; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 0x0A: goto yy86; case 0x0D: goto yy90; case ' ': goto yy88; default: goto yy40; } yy48: yyaccept = 1; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 0x0A: goto yy81; case 0x0D: goto yy85; case ' ': goto yy83; default: goto yy40; } yy49: yych = *++YYCURSOR; switch(yych){ case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy78; default: goto yy40; } yy50: yych = *++YYCURSOR; switch(yych){ case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy75; default: goto yy40; } yy51: ++YYCURSOR; goto yy52; yy52: #line 471 "token.re" { goto TransferMethod; } #line 767 "" yy53: ++YYCURSOR; goto yy54; yy54: #line 473 "token.re" { ENSURE_YAML_IOPEN(lvl, doc_level, 1); goto SingleQuote; } #line 774 "" yy55: ++YYCURSOR; goto yy56; yy56: #line 476 "token.re" { ENSURE_YAML_IOPEN(lvl, doc_level, 1); goto DoubleQuote; } #line 781 "" yy57: yyaccept = 1; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 0x0A: goto yy70; case 0x0D: goto yy74; case ' ': goto yy72; case '+': case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy67; default: goto yy40; } yy58: ++YYCURSOR; goto yy59; yy59: #line 486 "token.re" { eat_comments( parser ); goto Document; } #line 807 "" yy60: ++YYCURSOR; yych = *YYCURSOR; goto yy66; yy61: #line 490 "token.re" { goto Document; } #line 814 "" yy62: ++YYCURSOR; goto yy63; yy63: #line 492 "token.re" { ENSURE_YAML_IEND(lvl, -1); YYPOS(0); return 0; } #line 823 "" yy64: yych = *++YYCURSOR; goto yy40; yy65: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy66; yy66: switch(yych){ case 0x09: case ' ': goto yy65; default: goto yy61; } yy67: ++YYCURSOR; if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); yych = *YYCURSOR; goto yy68; yy68: switch(yych){ case 0x0A: goto yy70; case 0x0D: goto yy74; case ' ': goto yy72; case '+': case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': goto yy67; default: goto yy69; } yy69: YYCURSOR = YYMARKER; switch(yyaccept){ case 0: goto yy38; case 1: goto yy40; } yy70: ++YYCURSOR; goto yy71; yy71: #line 479 "token.re" { if ( is_newline( YYCURSOR - 1 ) ) { YYCURSOR--; } goto ScalarBlock; } #line 869 "" yy72: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy73; yy73: switch(yych){ case ' ': goto yy72; default: goto yy71; } yy74: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy70; default: goto yy69; } yy75: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy76; yy76: switch(yych){ case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy75; default: goto yy77; } yy77: #line 466 "token.re" { ENSURE_YAML_IOPEN(lvl, doc_level, 1); sycklval->name = syck_strndup( YYTOKEN + 1, YYCURSOR - YYTOKEN - 1 ); return YAML_ALIAS; } #line 956 "" yy78: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy79; yy79: switch(yych){ case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy78; default: goto yy80; } yy80: #line 455 "token.re" { sycklval->name = syck_strndup( YYTOKEN + 1, YYCURSOR - YYTOKEN - 1 ); /* * Remove previous anchors of the same name. Since the parser will likely * construct deeper nodes first, we want those nodes to be placed in the * queue for matching at a higher level of indentation. */ syck_hdlr_remove_anchor(parser, sycklval->name); return YAML_ANCHOR; } #line 1036 "" yy81: ++YYCURSOR; goto yy82; yy82: #line 441 "token.re" { ENSURE_YAML_IOPEN(lvl, YYTOKEN - YYLINEPTR, 1); FORCE_NEXT_TOKEN(YAML_IOPEN); if ( *YYCURSOR == '#' || is_newline( YYCURSOR ) || is_newline( YYCURSOR - 1 ) ) { YYCURSOR--; ADD_LEVEL((YYTOKEN + 1) - YYLINEPTR, syck_lvl_seq); } else /* spaces followed by content uses the space as indentation */ { ADD_LEVEL(YYCURSOR - YYLINEPTR, syck_lvl_seq); } return YYTOKEN[0]; } #line 1054 "" yy83: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy84; yy84: switch(yych){ case ' ': goto yy83; default: goto yy82; } yy85: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy81; default: goto yy69; } yy86: ++YYCURSOR; goto yy87; yy87: #line 436 "token.re" { if ( *YYTOKEN == ':' && lvl->status != syck_lvl_imap ) lvl->status = syck_lvl_map; YYPOS(1); return YYTOKEN[0]; } #line 1076 "" yy88: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy89; yy89: switch(yych){ case ' ': goto yy88; default: goto yy87; } yy90: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy86; default: goto yy69; } yy91: yyaccept = 0; YYMARKER = ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy92; yy92: switch(yych){ case 0x0A: case ' ': goto yy91; case 0x0D: goto yy93; default: goto yy38; } yy93: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; switch(yych){ case 0x0A: goto yy91; default: goto yy69; } } #line 501 "token.re" } Directive: { YYTOKTMP = YYCURSOR; #line 1117 "" { YYCTYPE yych; unsigned int yyaccept; goto yy94; ++YYCURSOR; yy94: if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); yych = *YYCURSOR; switch(yych){ case 0x00: goto yy96; case 0x09: case ' ': goto yy99; case '%': goto yy97; default: goto yy101; } yy96: YYCURSOR = YYMARKER; switch(yyaccept){ case 0: goto yy98; } yy97: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case '.': case '/': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '[': case '\\': case ']': case '^': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy104; default: goto yy98; } yy98: #line 514 "token.re" { YYCURSOR = YYTOKTMP; return YAML_DOCSEP; } #line 1221 "" yy99: ++YYCURSOR; yych = *YYCURSOR; goto yy103; yy100: #line 512 "token.re" { goto Directive; } #line 1228 "" yy101: yych = *++YYCURSOR; goto yy98; yy102: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy103; yy103: switch(yych){ case 0x09: case ' ': goto yy102; default: goto yy100; } yy104: ++YYCURSOR; if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); yych = *YYCURSOR; goto yy105; yy105: switch(yych){ case '.': case '/': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ';': case '<': case '=': case '>': case '?': case '@': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '[': case '\\': case ']': case '^': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy104; case ':': goto yy106; default: goto yy96; } yy106: yych = *++YYCURSOR; switch(yych){ case '.': case '/': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '[': case '\\': case ']': case '^': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy107; default: goto yy96; } yy107: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy108; yy108: switch(yych){ case '.': case '/': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '[': case '\\': case ']': case '^': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': goto yy107; default: goto yy109; } yy109: #line 510 "token.re" { goto Directive; } #line 1484 "" } #line 517 "token.re" } Plain: { int qidx = 0; int qcapa = 100; char *qstr = S_ALLOC_N( char, qcapa ); SyckLevel *plvl; int parentIndent; YYCURSOR = YYTOKEN; plvl = CURRENT_LEVEL(); GET_TRUE_YAML_INDENT(parentIndent); Plain2: YYTOKEN = YYCURSOR; Plain3: #line 1509 "" { YYCTYPE yych; unsigned int yyaccept; goto yy110; ++YYCURSOR; yy110: if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); yych = *YYCURSOR; switch(yych){ case 0x00: goto yy124; case 0x09: goto yy126; case 0x0A: goto yy112; case 0x0D: goto yy114; case ' ': goto yy122; case ',': goto yy117; case ':': goto yy116; case ']': goto yy120; case '}': goto yy118; default: goto yy127; } yy112: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); goto yy142; yy113: #line 540 "token.re" { int indt_len, nl_count = 0; SyckLevel *lvl; char *tok = YYTOKEN; GOBBLE_UP_YAML_INDENT( indt_len, tok ); lvl = CURRENT_LEVEL(); if ( indt_len <= parentIndent ) { RETURN_IMPLICIT(); } while ( YYTOKEN < YYCURSOR ) { int nl_len = newline_len( YYTOKEN++ ); if ( nl_len ) { nl_count++; YYTOKEN += nl_len - 1; } } if ( nl_count <= 1 ) { QUOTECAT(qstr, qcapa, qidx, ' '); } else { int i; for ( i = 0; i < nl_count - 1; i++ ) { QUOTECAT(qstr, qcapa, qidx, '\n'); } } goto Plain2; } #line 1570 "" yy114: ++YYCURSOR; switch((yych = *YYCURSOR)) { case 0x0A: goto yy141; default: goto yy115; } yy115: #line 627 "token.re" { QUOTECATS(qstr, qcapa, qidx, YYTOKEN, YYCURSOR - YYTOKEN); goto Plain2; } #line 1581 "" yy116: yyaccept = 1; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 0x0A: goto yy136; case 0x0D: goto yy140; case ' ': goto yy138; default: goto yy115; } yy117: yyaccept = 1; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 0x0A: goto yy130; case 0x0D: goto yy134; case ' ': goto yy132; default: goto yy115; } yy118: ++YYCURSOR; goto yy119; yy119: #line 589 "token.re" { if ( plvl->status != syck_lvl_imap ) { PLAIN_NOT_INL(); } else { PLAIN_IS_INL(); } RETURN_IMPLICIT(); } #line 1612 "" yy120: ++YYCURSOR; goto yy121; yy121: #line 600 "token.re" { if ( plvl->status != syck_lvl_iseq ) { PLAIN_NOT_INL(); } else { PLAIN_IS_INL(); } RETURN_IMPLICIT(); } #line 1627 "" yy122: ++YYCURSOR; switch((yych = *YYCURSOR)) { case '#': goto yy128; default: goto yy123; } yy123: #line 617 "token.re" { if ( qidx == 0 ) { goto Plain2; } else { goto Plain3; } } #line 1644 "" yy124: ++YYCURSOR; goto yy125; yy125: #line 615 "token.re" { RETURN_IMPLICIT(); } #line 1650 "" yy126: yych = *++YYCURSOR; goto yy123; yy127: yych = *++YYCURSOR; goto yy115; yy128: ++YYCURSOR; goto yy129; yy129: #line 611 "token.re" { eat_comments( parser ); RETURN_IMPLICIT(); } #line 1662 "" yy130: ++YYCURSOR; goto yy131; yy131: #line 578 "token.re" { if ( plvl->status != syck_lvl_iseq && plvl->status != syck_lvl_imap ) { PLAIN_NOT_INL(); } else { PLAIN_IS_INL(); } RETURN_IMPLICIT(); } #line 1677 "" yy132: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy133; yy133: switch(yych){ case ' ': goto yy132; default: goto yy131; } yy134: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy130; default: goto yy135; } yy135: YYCURSOR = YYMARKER; switch(yyaccept){ case 0: goto yy113; case 1: goto yy115; } yy136: ++YYCURSOR; goto yy137; yy137: #line 576 "token.re" { RETURN_IMPLICIT(); } #line 1701 "" yy138: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy139; yy139: switch(yych){ case ' ': goto yy138; default: goto yy137; } yy140: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy136; default: goto yy135; } yy141: yyaccept = 0; YYMARKER = ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy142; yy142: switch(yych){ case 0x0A: case ' ': goto yy141; case 0x0D: goto yy143; default: goto yy113; } yy143: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; switch(yych){ case 0x0A: goto yy141; default: goto yy135; } } #line 631 "token.re" } SingleQuote: { int qidx = 0; int qcapa = 100; char *qstr = S_ALLOC_N( char, qcapa ); SingleQuote2: YYTOKEN = YYCURSOR; #line 1747 "" { YYCTYPE yych; unsigned int yyaccept; goto yy144; ++YYCURSOR; yy144: if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); yych = *YYCURSOR; switch(yych){ case 0x00: goto yy152; case 0x0A: goto yy146; case 0x0D: goto yy148; case '\'': goto yy150; default: goto yy153; } yy146: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); goto yy157; yy147: #line 645 "token.re" { int indt_len; int nl_count = 0; SyckLevel *lvl; GOBBLE_UP_YAML_INDENT( indt_len, YYTOKEN ); lvl = CURRENT_LEVEL(); if ( lvl->status != syck_lvl_str ) { ADD_LEVEL( indt_len, syck_lvl_str ); } else if ( indt_len < lvl->spaces ) { /* Error! */ } while ( YYTOKEN < YYCURSOR ) { int nl_len = newline_len( YYTOKEN++ ); if ( nl_len ) { nl_count++; YYTOKEN += nl_len - 1; } } if ( nl_count <= 1 ) { QUOTECAT(qstr, qcapa, qidx, ' '); } else { int i; for ( i = 0; i < nl_count - 1; i++ ) { QUOTECAT(qstr, qcapa, qidx, '\n'); } } goto SingleQuote2; } #line 1807 "" yy148: ++YYCURSOR; switch((yych = *YYCURSOR)) { case 0x0A: goto yy156; default: goto yy149; } yy149: #line 712 "token.re" { QUOTECAT(qstr, qcapa, qidx, *(YYCURSOR - 1)); goto SingleQuote2; } #line 1818 "" yy150: ++YYCURSOR; switch((yych = *YYCURSOR)) { case '\'': goto yy154; default: goto yy151; } yy151: #line 689 "token.re" { SyckLevel *lvl; SyckNode *n = syck_alloc_str(); lvl = CURRENT_LEVEL(); if ( lvl->status == syck_lvl_str ) { POP_LEVEL(); } if ( ((SyckParser *)parser)->taguri_expansion == 1 ) { n->type_id = syck_taguri( YAML_DOMAIN, "str", 3 ); } else { n->type_id = syck_strndup( "str", 3 ); } n->data.str->ptr = qstr; n->data.str->len = qidx; n->data.str->style = scalar_1quote; sycklval->nodeData = n; return YAML_PLAIN; } #line 1848 "" yy152: yych = *++YYCURSOR; goto yy151; yy153: yych = *++YYCURSOR; goto yy149; yy154: ++YYCURSOR; goto yy155; yy155: #line 685 "token.re" { QUOTECAT(qstr, qcapa, qidx, '\''); goto SingleQuote2; } #line 1860 "" yy156: yyaccept = 0; YYMARKER = ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy157; yy157: switch(yych){ case 0x0A: case ' ': goto yy156; case 0x0D: goto yy158; default: goto yy147; } yy158: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; switch(yych){ case 0x0A: goto yy156; default: goto yy159; } yy159: YYCURSOR = YYMARKER; switch(yyaccept){ case 0: goto yy147; } } #line 716 "token.re" } DoubleQuote: { int keep_nl = 1; int qidx = 0; int qcapa = 100; char *qstr = S_ALLOC_N( char, qcapa ); DoubleQuote2: YYTOKEN = YYCURSOR; #line 1901 "" { YYCTYPE yych; unsigned int yyaccept; goto yy160; ++YYCURSOR; yy160: if((YYLIMIT - YYCURSOR) < 4) YYFILL(4); yych = *YYCURSOR; switch(yych){ case 0x00: goto yy167; case 0x0A: goto yy162; case 0x0D: goto yy164; case '"': goto yy169; case '\\': goto yy166; default: goto yy170; } yy162: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); goto yy184; yy163: #line 734 "token.re" { int indt_len; int nl_count = 0; SyckLevel *lvl; GOBBLE_UP_YAML_INDENT( indt_len, YYTOKEN ); lvl = CURRENT_LEVEL(); if ( lvl->status != syck_lvl_str ) { ADD_LEVEL( indt_len, syck_lvl_str ); } else if ( indt_len < lvl->spaces ) { /* FIXME */ } if ( keep_nl == 1 ) { while ( YYTOKEN < YYCURSOR ) { int nl_len = newline_len( YYTOKEN++ ); if ( nl_len ) { nl_count++; YYTOKEN += nl_len - 1; } } if ( nl_count <= 1 ) { QUOTECAT(qstr, qcapa, qidx, ' '); } else { int i; for ( i = 0; i < nl_count - 1; i++ ) { QUOTECAT(qstr, qcapa, qidx, '\n'); } } } keep_nl = 1; goto DoubleQuote2; } #line 1966 "" yy164: ++YYCURSOR; switch((yych = *YYCURSOR)) { case 0x0A: goto yy183; default: goto yy165; } yy165: #line 820 "token.re" { QUOTECAT(qstr, qcapa, qidx, *(YYCURSOR - 1)); goto DoubleQuote2; } #line 1977 "" yy166: yyaccept = 1; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case 0x0A: goto yy174; case 0x0D: goto yy176; case ' ': goto yy171; case '"': case '0': case '\\': case 'a': case 'b': case 'e': case 'f': case 'n': case 'r': case 't': case 'v': goto yy178; case 'x': goto yy177; default: goto yy165; } yy167: ++YYCURSOR; goto yy168; yy168: #line 797 "token.re" { SyckLevel *lvl; SyckNode *n = syck_alloc_str(); lvl = CURRENT_LEVEL(); if ( lvl->status == syck_lvl_str ) { POP_LEVEL(); } if ( ((SyckParser *)parser)->taguri_expansion == 1 ) { n->type_id = syck_taguri( YAML_DOMAIN, "str", 3 ); } else { n->type_id = syck_strndup( "str", 3 ); } n->data.str->ptr = qstr; n->data.str->len = qidx; n->data.str->style = scalar_2quote; sycklval->nodeData = n; return YAML_PLAIN; } #line 2016 "" yy169: yych = *++YYCURSOR; goto yy168; yy170: yych = *++YYCURSOR; goto yy165; yy171: ++YYCURSOR; if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); yych = *YYCURSOR; goto yy172; yy172: switch(yych){ case 0x0A: goto yy174; case 0x0D: goto yy176; case ' ': goto yy171; default: goto yy173; } yy173: YYCURSOR = YYMARKER; switch(yyaccept){ case 0: goto yy163; case 1: goto yy165; } yy174: ++YYCURSOR; goto yy175; yy175: #line 792 "token.re" { keep_nl = 0; YYCURSOR--; goto DoubleQuote2; } #line 2044 "" yy176: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy174; default: goto yy173; } yy177: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': goto yy180; default: goto yy173; } yy178: ++YYCURSOR; goto yy179; yy179: #line 778 "token.re" { char ch = *( YYCURSOR - 1 ); QUOTECAT(qstr, qcapa, qidx, escape_seq( ch )); goto DoubleQuote2; } #line 2082 "" yy180: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': goto yy181; default: goto yy173; } yy181: ++YYCURSOR; goto yy182; yy182: #line 783 "token.re" { long ch; char *chr_text = syck_strndup( YYTOKEN, 4 ); chr_text[0] = '0'; ch = strtol( chr_text, NULL, 16 ); free( chr_text ); QUOTECAT(qstr, qcapa, qidx, ch); goto DoubleQuote2; } #line 2119 "" yy183: yyaccept = 0; YYMARKER = ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy184; yy184: switch(yych){ case 0x0A: case ' ': goto yy183; case 0x0D: goto yy185; default: goto yy163; } yy185: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; switch(yych){ case 0x0A: goto yy183; default: goto yy173; } } #line 824 "token.re" } TransferMethod: { int qidx = 0; int qcapa = 100; char *qstr = S_ALLOC_N( char, qcapa ); TransferMethod2: YYTOKTMP = YYCURSOR; #line 2152 "" { YYCTYPE yych; unsigned int yyaccept; goto yy186; ++YYCURSOR; yy186: if((YYLIMIT - YYCURSOR) < 4) YYFILL(4); yych = *YYCURSOR; switch(yych){ case 0x00: goto yy188; case 0x0A: goto yy190; case 0x0D: goto yy192; case ' ': goto yy191; case '\\': goto yy194; default: goto yy195; } yy188: ++YYCURSOR; goto yy189; yy189: #line 838 "token.re" { SyckLevel *lvl; YYCURSOR = YYTOKTMP; if ( YYCURSOR == YYTOKEN + 1 ) { free( qstr ); return YAML_ITRANSFER; } lvl = CURRENT_LEVEL(); /* * URL Prefixing */ if ( *qstr == '^' ) { sycklval->name = S_ALLOC_N( char, qidx + strlen( lvl->domain ) ); sycklval->name[0] = '\0'; strcat( sycklval->name, lvl->domain ); strncat( sycklval->name, qstr + 1, qidx - 1 ); free( qstr ); } else { char *carat = qstr; char *qend = qstr + qidx; while ( (++carat) < qend ) { if ( *carat == '^' ) break; } if ( carat < qend ) { free( lvl->domain ); lvl->domain = syck_strndup( qstr, carat - qstr ); sycklval->name = S_ALLOC_N( char, ( qend - carat ) + strlen( lvl->domain ) ); sycklval->name[0] = '\0'; strcat( sycklval->name, lvl->domain ); strncat( sycklval->name, carat + 1, ( qend - carat ) - 1 ); free( qstr ); } else { sycklval->name = qstr; } } return YAML_TRANSFER; } #line 2222 "" yy190: yych = *++YYCURSOR; goto yy189; yy191: yych = *++YYCURSOR; goto yy204; yy192: ++YYCURSOR; switch((yych = *YYCURSOR)) { case 0x0A: goto yy188; default: goto yy193; } yy193: #line 905 "token.re" { QUOTECAT(qstr, qcapa, qidx, *(YYCURSOR - 1)); goto TransferMethod2; } #line 2237 "" yy194: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case '"': case '0': case '\\': case 'a': case 'b': case 'e': case 'f': case 'n': case 'r': case 't': case 'v': goto yy198; case 'x': goto yy196; default: goto yy193; } yy195: yych = *++YYCURSOR; goto yy193; yy196: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': goto yy200; default: goto yy197; } yy197: YYCURSOR = YYMARKER; switch(yyaccept){ case 0: goto yy193; } yy198: ++YYCURSOR; goto yy199; yy199: #line 891 "token.re" { char ch = *( YYCURSOR - 1 ); QUOTECAT(qstr, qcapa, qidx, escape_seq( ch )); goto TransferMethod2; } #line 2285 "" yy200: yych = *++YYCURSOR; switch(yych){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': goto yy201; default: goto yy197; } yy201: ++YYCURSOR; goto yy202; yy202: #line 896 "token.re" { long ch; char *chr_text = syck_strndup( YYTOKTMP, 4 ); chr_text[0] = '0'; ch = strtol( chr_text, NULL, 16 ); free( chr_text ); QUOTECAT(qstr, qcapa, qidx, ch); goto TransferMethod2; } #line 2322 "" yy203: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy204; yy204: switch(yych){ case ' ': goto yy203; default: goto yy189; } } #line 910 "token.re" } ScalarBlock: { int qidx = 0; int qcapa = 100; char *qstr = S_ALLOC_N( char, qcapa ); int blockType = 0; int nlDoWhat = 0; int lastIndent = 0; int forceIndent = -1; char *yyt = YYTOKEN; SyckLevel *lvl = CURRENT_LEVEL(); int parentIndent = -1; switch ( *yyt ) { case '|': blockType = BLOCK_LIT; break; case '>': blockType = BLOCK_FOLD; break; } while ( ++yyt <= YYCURSOR ) { if ( *yyt == '-' ) { nlDoWhat = NL_CHOMP; } else if ( *yyt == '+' ) { nlDoWhat = NL_KEEP; } else if ( isdigit( *yyt ) ) { forceIndent = strtol( yyt, NULL, 10 ); } } qstr[0] = '\0'; YYTOKEN = YYCURSOR; ScalarBlock2: YYTOKEN = YYCURSOR; #line 2378 "" { YYCTYPE yych; unsigned int yyaccept; goto yy205; ++YYCURSOR; yy205: if((YYLIMIT - YYCURSOR) < 5) YYFILL(5); yych = *YYCURSOR; switch(yych){ case 0x00: goto yy213; case 0x0A: goto yy207; case 0x0D: goto yy209; case '#': goto yy211; case '-': goto yy215; default: goto yy216; } yy207: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); goto yy226; yy208: #line 956 "token.re" { char *pacer; char *tok = YYTOKEN; int indt_len = 0, nl_count = 0, fold_nl = 0, nl_begin = 0; GOBBLE_UP_YAML_INDENT( indt_len, tok ); lvl = CURRENT_LEVEL(); if ( lvl->status != syck_lvl_block ) { GET_TRUE_YAML_INDENT(parentIndent); if ( forceIndent > 0 ) forceIndent += parentIndent; if ( indt_len > parentIndent ) { int new_spaces = forceIndent > 0 ? forceIndent : indt_len; ADD_LEVEL( new_spaces, syck_lvl_block ); lastIndent = indt_len - new_spaces; nl_begin = 1; lvl = CURRENT_LEVEL(); } else { YYCURSOR = YYTOKEN; RETURN_YAML_BLOCK(); } } /* * Fold only in the event of two lines being on the leftmost * indentation. */ if ( blockType == BLOCK_FOLD && lastIndent == 0 && ( indt_len - lvl->spaces ) == 0 ) { fold_nl = 1; } pacer = YYTOKEN; while ( pacer < YYCURSOR ) { int nl_len = newline_len( pacer++ ); if ( nl_len ) { nl_count++; pacer += nl_len - 1; } } if ( fold_nl == 1 || nl_begin == 1 ) { nl_count--; } if ( nl_count < 1 && nl_begin == 0 ) { QUOTECAT(qstr, qcapa, qidx, ' '); } else { int i; for ( i = 0; i < nl_count; i++ ) { QUOTECAT(qstr, qcapa, qidx, '\n'); } } lastIndent = indt_len - lvl->spaces; YYCURSOR -= lastIndent; if ( indt_len < lvl->spaces ) { POP_LEVEL(); YYCURSOR = YYTOKEN; RETURN_YAML_BLOCK(); } goto ScalarBlock2; } #line 2474 "" yy209: ++YYCURSOR; switch((yych = *YYCURSOR)) { case 0x0A: goto yy225; default: goto yy210; } yy210: #line 1070 "token.re" { QUOTECAT(qstr, qcapa, qidx, *YYTOKEN); goto ScalarBlock2; } #line 2485 "" yy211: ++YYCURSOR; goto yy212; yy212: #line 1032 "token.re" { lvl = CURRENT_LEVEL(); if ( lvl->status != syck_lvl_block ) { eat_comments( parser ); YYTOKEN = YYCURSOR; } else { QUOTECAT(qstr, qcapa, qidx, *YYTOKEN); } goto ScalarBlock2; } #line 2502 "" yy213: ++YYCURSOR; goto yy214; yy214: #line 1046 "token.re" { YYCURSOR--; POP_LEVEL(); RETURN_YAML_BLOCK(); } #line 2511 "" yy215: yyaccept = 1; yych = *(YYMARKER = ++YYCURSOR); switch(yych){ case '-': goto yy217; default: goto yy210; } yy216: yych = *++YYCURSOR; goto yy210; yy217: yych = *++YYCURSOR; switch(yych){ case '-': goto yy219; default: goto yy218; } yy218: YYCURSOR = YYMARKER; switch(yyaccept){ case 0: goto yy208; case 1: goto yy210; } yy219: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy220; case 0x0D: goto yy224; case ' ': goto yy222; default: goto yy218; } yy220: ++YYCURSOR; goto yy221; yy221: #line 1051 "token.re" { if ( YYTOKEN == YYLINEPTR ) { if ( blockType == BLOCK_FOLD && qidx > 0 ) { qidx -= 1; } QUOTECAT(qstr, qcapa, qidx, '\n'); POP_LEVEL(); YYCURSOR = YYTOKEN; RETURN_YAML_BLOCK(); } else { QUOTECAT(qstr, qcapa, qidx, *YYTOKEN); YYCURSOR = YYTOKEN + 1; goto ScalarBlock2; } } #line 2559 "" yy222: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy223; yy223: switch(yych){ case ' ': goto yy222; default: goto yy221; } yy224: yych = *++YYCURSOR; switch(yych){ case 0x0A: goto yy220; default: goto yy218; } yy225: yyaccept = 0; YYMARKER = ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy226; yy226: switch(yych){ case 0x0A: case ' ': goto yy225; case 0x0D: goto yy227; default: goto yy208; } yy227: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; switch(yych){ case 0x0A: goto yy225; default: goto yy218; } } #line 1075 "token.re" } return 0; } void eat_comments( SyckParser *parser ) { Comment: { YYTOKEN = YYCURSOR; #line 2607 "" { YYCTYPE yych; unsigned int yyaccept; goto yy228; ++YYCURSOR; yy228: if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); yych = *YYCURSOR; switch(yych){ case 0x00: goto yy230; case 0x0A: goto yy232; case 0x0D: goto yy233; default: goto yy235; } yy230: ++YYCURSOR; goto yy231; yy231: #line 1091 "token.re" { YYCURSOR = YYTOKEN; return; } #line 2629 "" yy232: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); goto yy237; yy233: ++YYCURSOR; switch((yych = *YYCURSOR)) { case 0x0A: goto yy236; default: goto yy234; } yy234: #line 1095 "token.re" { goto Comment; } #line 2642 "" yy235: yych = *++YYCURSOR; goto yy234; yy236: yyaccept = 0; YYMARKER = ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; goto yy237; yy237: switch(yych){ case 0x0A: goto yy236; case 0x0D: goto yy238; default: goto yy231; } yy238: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; switch(yych){ case 0x0A: goto yy236; default: goto yy239; } yy239: YYCURSOR = YYMARKER; switch(yyaccept){ case 0: goto yy231; } } #line 1098 "token.re" } } char escape_seq( char ch ) { switch ( ch ) { case '0': return '\0'; case 'a': return 7; case 'b': return '\010'; case 'e': return '\033'; case 'f': return '\014'; case 'n': return '\n'; case 'r': return '\015'; case 't': return '\t'; case 'v': return '\013'; default: return ch; } } int is_newline( char *ptr ) { return newline_len( ptr ); } int newline_len( char *ptr ) { if ( *ptr == '\n' ) return 1; if ( *ptr == '\r' && *( ptr + 1 ) == '\n' ) return 2; return 0; } int syckwrap() { return 1; } void syckerror( char *msg ) { if ( syck_parser_ptr->error_handler == NULL ) syck_parser_ptr->error_handler = syck_default_error_handler; syck_parser_ptr->root = syck_parser_ptr->root_on_error; (syck_parser_ptr->error_handler)(syck_parser_ptr, msg); } ================================================ FILE: ext/syck/yaml2byte.c ================================================ /* * yaml2byte.c * * $Author$ * $Date$ * * Copyright (C) 2003 why the lucky stiff, clark evans * * WARNING WARNING WARNING --- THIS IS *NOT JUST* PLAYING * ANYMORE! -- WHY HAS EMBRACED THIS AS THE REAL THING! */ #include "ruby.h" #include #include #define YAMLBYTE_UTF8 #include "yamlbyte.h" #include #define TRACE0(a) \ do { printf(a); printf("\n"); fflush(stdout); } while(0) #define TRACE1(a,b) \ do { printf(a,b); printf("\n"); fflush(stdout); } while(0) #define TRACE2(a,b,c) \ do { printf(a,b,c); printf("\n"); fflush(stdout); } while(0) #define TRACE3(a,b,c,d) \ do { printf(a,b,c,d); printf("\n"); fflush(stdout); } while(0) /* Reinvent the wheel... */ #define CHUNKSIZE 64 #define HASH ((long)0xCAFECAFE) typedef struct { long hash; char *buffer; long length; long remaining; int printed; } bytestring_t; bytestring_t *bytestring_alloc() { bytestring_t *ret; /*TRACE0("bytestring_alloc()");*/ ret = S_ALLOC(bytestring_t); ret->hash = HASH; ret->length = CHUNKSIZE; ret->remaining = ret->length; ret->buffer = S_ALLOC_N(char, ret->length + 1 ); ret->buffer[0] = 0; ret->printed = 0; return ret; } void bytestring_append(bytestring_t *str, char code, char *start, char *finish) { long grow; long length = 2; /* CODE + LF */ char *curr; assert(str && HASH == str->hash); /*TRACE0("bytestring_append()");*/ if(start) { if(!finish) finish = start + strlen(start); length += (finish-start); } if(length > str->remaining) { grow = (length - str->remaining) + CHUNKSIZE; str->remaining += grow; str->length += grow; str->buffer = S_REALLOC_N( str->buffer, char, str->length + 1 ); assert(str->buffer); } curr = str->buffer + (str->length - str->remaining); *curr = code; curr += 1; if(start) while(start < finish) *curr ++ = *start ++; *curr = '\n'; curr += 1; *curr = 0; str->remaining = str->remaining - length; assert( (str->buffer + str->length) - str->remaining ); } void bytestring_extend(bytestring_t *str, bytestring_t *ext) { char *from; char *curr; char *stop; long grow; long length; assert(str && HASH == str->hash); assert(ext && HASH == ext->hash); if(ext->printed) { assert(ext->buffer[0] ==YAMLBYTE_ANCHOR); curr = ext->buffer; while( '\n' != *curr) curr++; bytestring_append(str, YAMLBYTE_ALIAS, ext->buffer + 1, curr); } else { ext->printed = 1; length = (ext->length - ext->remaining); if(length > str->remaining) { grow = (length - str->remaining) + CHUNKSIZE; str->remaining += grow; str->length += grow; str->buffer = S_REALLOC_N( str->buffer, char, str->length + 1 ); } curr = str->buffer + (str->length - str->remaining); from = ext->buffer; stop = ext->buffer + length; while( from < stop ) *curr ++ = *from ++; *curr = 0; str->remaining = str->remaining - length; assert( (str->buffer + str->length) - str->remaining ); } } /* convert SyckNode into yamlbyte_buffer_t objects */ SYMID syck_yaml2byte_handler(p, n) SyckParser *p; SyckNode *n; { SYMID oid; long i; char ch; char nextcode; char *start; char *current; char *finish; bytestring_t *val = NULL; bytestring_t *sav = NULL; /*TRACE0("syck_yaml2byte_handler()");*/ val = bytestring_alloc(); if(n->anchor) bytestring_append(val,YAMLBYTE_ANCHOR, n->anchor, NULL); if ( n->type_id ) { if ( p->taguri_expansion ) { bytestring_append(val,YAMLBYTE_TRANSFER, n->type_id, NULL); } else { char *type_tag = S_ALLOC_N( char, strlen( n->type_id ) + 1 ); type_tag[0] = '\0'; strcat( type_tag, "!" ); strcat( type_tag, n->type_id ); bytestring_append( val, YAMLBYTE_TRANSFER, type_tag, NULL); S_FREE(type_tag); } } switch (n->kind) { case syck_str_kind: nextcode = YAMLBYTE_SCALAR; start = n->data.str->ptr; finish = start + n->data.str->len - 1; current = start; /*TRACE2("SCALAR: %s %d", start, n->data.str->len); */ while(1) { ch = *current; if('\n' == ch || 0 == ch || current > finish) { if(current >= start) { bytestring_append(val, nextcode, start, current); nextcode = YAMLBYTE_CONTINUE; } start = current + 1; if(current > finish) { break; } else if('\n' == ch ) { bytestring_append(val,YAMLBYTE_NEWLINE,NULL,NULL); } else if(0 == ch) { bytestring_append(val,YAMLBYTE_NULLCHAR,NULL,NULL); } else { assert("oops"); } } current += 1; } break; case syck_seq_kind: bytestring_append(val,YAMLBYTE_SEQUENCE,NULL,NULL); for ( i = 0; i < n->data.list->idx; i++ ) { oid = syck_seq_read( n, i ); syck_lookup_sym( p, oid, (char **)&sav ); bytestring_extend(val, sav); } bytestring_append(val,YAMLBYTE_END_BRANCH,NULL,NULL); break; case syck_map_kind: bytestring_append(val,YAMLBYTE_MAPPING,NULL,NULL); for ( i = 0; i < n->data.pairs->idx; i++ ) { oid = syck_map_read( n, map_key, i ); syck_lookup_sym( p, oid, (char **)&sav ); bytestring_extend(val, sav); oid = syck_map_read( n, map_value, i ); syck_lookup_sym( p, oid, (char **)&sav ); bytestring_extend(val, sav); } bytestring_append(val,YAMLBYTE_END_BRANCH,NULL,NULL); break; } oid = syck_add_sym( p, (char *) val ); /*TRACE1("Saving: %s", val->buffer );*/ return oid; } char * syck_yaml2byte(char *yamlstr) { SYMID oid; char *ret; bytestring_t *sav; SyckParser *parser = syck_new_parser(); syck_parser_str_auto( parser, yamlstr, NULL ); syck_parser_handler( parser, syck_yaml2byte_handler ); syck_parser_error_handler( parser, NULL ); syck_parser_implicit_typing( parser, 1 ); syck_parser_taguri_expansion( parser, 1 ); oid = syck_parse( parser ); if ( syck_lookup_sym( parser, oid, (char **)&sav ) == 1 ) { ret = S_ALLOC_N( char, strlen( sav->buffer ) + 3 ); ret[0] = '\0'; strcat( ret, "D\n" ); strcat( ret, sav->buffer ); } else { ret = NULL; } syck_free_parser( parser ); return ret; } #ifdef TEST_YBEXT #include int main() { char *yaml = "test: 1\nand: \"with new\\nline\\n\"\nalso: &3 three\nmore: *3"; printf("--- # YAML \n"); printf(yaml); printf("\n...\n"); printf(syck_yaml2byte(yaml)); return 0; } #endif ================================================ FILE: ext/syck/yamlbyte.h ================================================ /* yamlbyte.h * * The YAML bytecode "C" interface header file. See the YAML bytecode * reference for bytecode sequence rules and for the meaning of each * bytecode. */ #ifndef YAMLBYTE_H #define YAMLBYTE_H #include /* define what a character is */ typedef unsigned char yamlbyte_utf8_t; typedef unsigned short yamlbyte_utf16_t; #ifdef YAMLBYTE_UTF8 #ifdef YAMLBYTE_UTF16 #error Must only define YAMLBYTE_UTF8 or YAMLBYTE_UTF16 #endif typedef yamlbyte_utf8_t yamlbyte_char_t; #else #ifdef YAMLBYTE_UTF16 typedef yamlbyte_utf16_t yamlbyte_char_t; #else #error Must define YAMLBYTE_UTF8 or YAMLBYTE_UTF16 #endif #endif /* specify list of bytecodes */ #define YAMLBYTE_FINISH ((yamlbyte_char_t) 0) #define YAMLBYTE_DOCUMENT ((yamlbyte_char_t)'D') #define YAMLBYTE_DIRECTIVE ((yamlbyte_char_t)'V') #define YAMLBYTE_PAUSE ((yamlbyte_char_t)'P') #define YAMLBYTE_MAPPING ((yamlbyte_char_t)'M') #define YAMLBYTE_SEQUENCE ((yamlbyte_char_t)'Q') #define YAMLBYTE_END_BRANCH ((yamlbyte_char_t)'E') #define YAMLBYTE_SCALAR ((yamlbyte_char_t)'S') #define YAMLBYTE_CONTINUE ((yamlbyte_char_t)'C') #define YAMLBYTE_NEWLINE ((yamlbyte_char_t)'N') #define YAMLBYTE_NULLCHAR ((yamlbyte_char_t)'Z') #define YAMLBYTE_ANCHOR ((yamlbyte_char_t)'A') #define YAMLBYTE_ALIAS ((yamlbyte_char_t)'R') #define YAMLBYTE_TRANSFER ((yamlbyte_char_t)'T') /* formatting bytecodes */ #define YAMLBYTE_COMMENT ((yamlbyte_char_t)'c') #define YAMLBYTE_INDENT ((yamlbyte_char_t)'i') #define YAMLBYTE_STYLE ((yamlbyte_char_t)'s') /* other bytecodes */ #define YAMLBYTE_LINE_NUMBER ((yamlbyte_char_t)'#') #define YAMLBYTE_WHOLE_SCALAR ((yamlbyte_char_t)'<') #define YAMLBYTE_NOTICE ((yamlbyte_char_t)'!') #define YAMLBYTE_SPAN ((yamlbyte_char_t)')') #define YAMLBYTE_ALLOC ((yamlbyte_char_t)'@') /* second level style bytecodes, ie "s>" */ #define YAMLBYTE_FLOW ((yamlbyte_char_t)'>') #define YAMLBYTE_LITERAL ((yamlbyte_char_t)'|') #define YAMLBYTE_BLOCK ((yamlbyte_char_t)'b') #define YAMLBYTE_PLAIN ((yamlbyte_char_t)'p') #define YAMLBYTE_INLINE_MAPPING ((yamlbyte_char_t)'{') #define YAMLBYTE_INLINE_SEQUENCE ((yamlbyte_char_t)'[') #define YAMLBYTE_SINGLE_QUOTED ((yamlbyte_char_t)39) #define YAMLBYTE_DOUBLE_QUOTED ((yamlbyte_char_t)'"') /* * The "C" API has two variants, one based on instructions, * with events delivered via pointers; and the other one * is character based where one or more instructions are * serialized into a buffer. * * Note: In the instruction based API, WHOLE_SCALAR does * not have the ' * * $RoughId: syslog.c,v 1.21 2002/02/25 12:21:17 knu Exp $ * $Id$ */ #include "ruby.h" #include "util.h" #include /* Syslog class */ static VALUE mSyslog, mSyslogConstants; static const char *syslog_ident = NULL; static int syslog_options = -1, syslog_facility = -1, syslog_mask = -1; static int syslog_opened = 0; /* Package helper routines */ static void syslog_write(int pri, int argc, VALUE *argv) { VALUE str; rb_secure(4); if (argc < 1) { rb_raise(rb_eArgError, "no log message supplied"); } if (!syslog_opened) { rb_raise(rb_eRuntimeError, "must open syslog before write"); } str = rb_f_sprintf(argc, argv); syslog(pri, "%s", RSTRING(str)->ptr); } /* Syslog module methods */ static VALUE mSyslog_close(VALUE self) { rb_secure(4); if (!syslog_opened) { rb_raise(rb_eRuntimeError, "syslog not opened"); } closelog(); free((void *)syslog_ident); syslog_ident = NULL; syslog_options = syslog_facility = syslog_mask = -1; syslog_opened = 0; return Qnil; } static VALUE mSyslog_open(int argc, VALUE *argv, VALUE self) { VALUE ident, opt, fac; if (syslog_opened) { rb_raise(rb_eRuntimeError, "syslog already open"); } rb_scan_args(argc, argv, "03", &ident, &opt, &fac); if (NIL_P(ident)) { ident = rb_gv_get("$0"); } #ifdef SafeStringValue SafeStringValue(ident); #else Check_SafeStr(ident); #endif syslog_ident = strdup(RSTRING(ident)->ptr); if (NIL_P(opt)) { syslog_options = LOG_PID | LOG_CONS; } else { syslog_options = NUM2INT(opt); } if (NIL_P(fac)) { syslog_facility = LOG_USER; } else { syslog_facility = NUM2INT(fac); } openlog(syslog_ident, syslog_options, syslog_facility); syslog_opened = 1; setlogmask(syslog_mask = setlogmask(0)); /* be like File.new.open {...} */ if (rb_block_given_p()) { rb_ensure(rb_yield, self, mSyslog_close, self); } return self; } static VALUE mSyslog_reopen(int argc, VALUE *argv, VALUE self) { mSyslog_close(self); return mSyslog_open(argc, argv, self); } static VALUE mSyslog_isopen(VALUE self) { return syslog_opened ? Qtrue : Qfalse; } static VALUE mSyslog_ident(VALUE self) { return syslog_opened ? rb_str_new2(syslog_ident) : Qnil; } static VALUE mSyslog_options(VALUE self) { return syslog_opened ? INT2NUM(syslog_options) : Qnil; } static VALUE mSyslog_facility(VALUE self) { return syslog_opened ? INT2NUM(syslog_facility) : Qnil; } static VALUE mSyslog_get_mask(VALUE self) { return syslog_opened ? INT2NUM(syslog_mask) : Qnil; } static VALUE mSyslog_set_mask(VALUE self, VALUE mask) { rb_secure(4); if (!syslog_opened) { rb_raise(rb_eRuntimeError, "must open syslog before setting log mask"); } setlogmask(syslog_mask = NUM2INT(mask)); return mask; } static VALUE mSyslog_log(int argc, VALUE *argv, VALUE self) { VALUE pri; if (argc < 2) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 2+)", argc); } argc--; pri = *argv++; if (!FIXNUM_P(pri)) { rb_raise(rb_eTypeError, "type mismatch: %s given", rb_class2name(CLASS_OF(pri))); } syslog_write(FIX2INT(pri), argc, argv); return self; } static VALUE mSyslog_inspect(VALUE self) { char buf[1024]; if (syslog_opened) { snprintf(buf, sizeof(buf), "<#%s: opened=true, ident=\"%s\", options=%d, facility=%d, mask=%d>", rb_class2name(self), syslog_ident, syslog_options, syslog_facility, syslog_mask); } else { snprintf(buf, sizeof(buf), "<#%s: opened=false>", rb_class2name(self)); } return rb_str_new2(buf); } static VALUE mSyslog_instance(VALUE self) { return self; } #define define_syslog_shortcut_method(pri, name) \ static VALUE mSyslog_##name(int argc, VALUE *argv, VALUE self) \ { \ syslog_write(pri, argc, argv); \ \ return self; \ } #ifdef LOG_EMERG define_syslog_shortcut_method(LOG_EMERG, emerg) #endif #ifdef LOG_ALERT define_syslog_shortcut_method(LOG_ALERT, alert) #endif #ifdef LOG_CRIT define_syslog_shortcut_method(LOG_CRIT, crit) #endif #ifdef LOG_ERR define_syslog_shortcut_method(LOG_ERR, err) #endif #ifdef LOG_WARNING define_syslog_shortcut_method(LOG_WARNING, warning) #endif #ifdef LOG_NOTICE define_syslog_shortcut_method(LOG_NOTICE, notice) #endif #ifdef LOG_INFO define_syslog_shortcut_method(LOG_INFO, info) #endif #ifdef LOG_DEBUG define_syslog_shortcut_method(LOG_DEBUG, debug) #endif static VALUE mSyslogConstants_LOG_MASK(VALUE klass, VALUE pri) { return INT2FIX(LOG_MASK(FIX2INT(pri))); } static VALUE mSyslogConstants_LOG_UPTO(VALUE klass, VALUE pri) { return INT2FIX(LOG_UPTO(FIX2INT(pri))); } /* Init for package syslog */ void Init_syslog() { mSyslog = rb_define_module("Syslog"); mSyslogConstants = rb_define_module_under(mSyslog, "Constants"); rb_include_module(mSyslog, mSyslogConstants); rb_define_module_function(mSyslog, "open", mSyslog_open, -1); rb_define_module_function(mSyslog, "reopen", mSyslog_reopen, -1); rb_define_module_function(mSyslog, "open!", mSyslog_reopen, -1); rb_define_module_function(mSyslog, "opened?", mSyslog_isopen, 0); rb_define_module_function(mSyslog, "ident", mSyslog_ident, 0); rb_define_module_function(mSyslog, "options", mSyslog_options, 0); rb_define_module_function(mSyslog, "facility", mSyslog_facility, 0); rb_define_module_function(mSyslog, "log", mSyslog_log, -1); rb_define_module_function(mSyslog, "close", mSyslog_close, 0); rb_define_module_function(mSyslog, "mask", mSyslog_get_mask, 0); rb_define_module_function(mSyslog, "mask=", mSyslog_set_mask, 1); rb_define_module_function(mSyslog, "LOG_MASK", mSyslogConstants_LOG_MASK, 1); rb_define_module_function(mSyslog, "LOG_UPTO", mSyslogConstants_LOG_UPTO, 1); rb_define_module_function(mSyslog, "inspect", mSyslog_inspect, 0); rb_define_module_function(mSyslog, "instance", mSyslog_instance, 0); rb_define_module_function(mSyslogConstants, "LOG_MASK", mSyslogConstants_LOG_MASK, 1); rb_define_module_function(mSyslogConstants, "LOG_UPTO", mSyslogConstants_LOG_UPTO, 1); #define rb_define_syslog_const(id) \ rb_define_const(mSyslogConstants, #id, INT2NUM(id)) /* Various options when opening log */ #ifdef LOG_PID rb_define_syslog_const(LOG_PID); #endif #ifdef LOG_CONS rb_define_syslog_const(LOG_CONS); #endif #ifdef LOG_ODELAY rb_define_syslog_const(LOG_ODELAY); /* deprecated */ #endif #ifdef LOG_NDELAY rb_define_syslog_const(LOG_NDELAY); #endif #ifdef LOG_NOWAIT rb_define_syslog_const(LOG_NOWAIT); /* deprecated */ #endif #ifdef LOG_PERROR rb_define_syslog_const(LOG_PERROR); #endif /* Various syslog facilities */ #ifdef LOG_AUTH rb_define_syslog_const(LOG_AUTH); #endif #ifdef LOG_AUTHPRIV rb_define_syslog_const(LOG_AUTHPRIV); #endif #ifdef LOG_CONSOLE rb_define_syslog_const(LOG_CONSOLE); #endif #ifdef LOG_CRON rb_define_syslog_const(LOG_CRON); #endif #ifdef LOG_DAEMON rb_define_syslog_const(LOG_DAEMON); #endif #ifdef LOG_FTP rb_define_syslog_const(LOG_FTP); #endif #ifdef LOG_KERN rb_define_syslog_const(LOG_KERN); #endif #ifdef LOG_LPR rb_define_syslog_const(LOG_LPR); #endif #ifdef LOG_MAIL rb_define_syslog_const(LOG_MAIL); #endif #ifdef LOG_NEWS rb_define_syslog_const(LOG_NEWS); #endif #ifdef LOG_NTP rb_define_syslog_const(LOG_NTP); #endif #ifdef LOG_SECURITY rb_define_syslog_const(LOG_SECURITY); #endif #ifdef LOG_SYSLOG rb_define_syslog_const(LOG_SYSLOG); #endif #ifdef LOG_USER rb_define_syslog_const(LOG_USER); #endif #ifdef LOG_UUCP rb_define_syslog_const(LOG_UUCP); #endif #ifdef LOG_LOCAL0 rb_define_syslog_const(LOG_LOCAL0); #endif #ifdef LOG_LOCAL1 rb_define_syslog_const(LOG_LOCAL1); #endif #ifdef LOG_LOCAL2 rb_define_syslog_const(LOG_LOCAL2); #endif #ifdef LOG_LOCAL3 rb_define_syslog_const(LOG_LOCAL3); #endif #ifdef LOG_LOCAL4 rb_define_syslog_const(LOG_LOCAL4); #endif #ifdef LOG_LOCAL5 rb_define_syslog_const(LOG_LOCAL5); #endif #ifdef LOG_LOCAL6 rb_define_syslog_const(LOG_LOCAL6); #endif #ifdef LOG_LOCAL7 rb_define_syslog_const(LOG_LOCAL7); #endif #define rb_define_syslog_shortcut(name) \ rb_define_module_function(mSyslog, #name, mSyslog_##name, -1) /* Various syslog priorities and the shortcut methods */ #ifdef LOG_EMERG rb_define_syslog_const(LOG_EMERG); rb_define_syslog_shortcut(emerg); #endif #ifdef LOG_ALERT rb_define_syslog_const(LOG_ALERT); rb_define_syslog_shortcut(alert); #endif #ifdef LOG_CRIT rb_define_syslog_const(LOG_CRIT); rb_define_syslog_shortcut(crit); #endif #ifdef LOG_ERR rb_define_syslog_const(LOG_ERR); rb_define_syslog_shortcut(err); #endif #ifdef LOG_WARNING rb_define_syslog_const(LOG_WARNING); rb_define_syslog_shortcut(warning); #endif #ifdef LOG_NOTICE rb_define_syslog_const(LOG_NOTICE); rb_define_syslog_shortcut(notice); #endif #ifdef LOG_INFO rb_define_syslog_const(LOG_INFO); rb_define_syslog_shortcut(info); #endif #ifdef LOG_DEBUG rb_define_syslog_const(LOG_DEBUG); rb_define_syslog_shortcut(debug); #endif } ================================================ FILE: ext/syslog/syslog.txt ================================================ .\" syslog.txt - -*- Indented-Text -*- $RoughId: syslog.txt,v 1.18 2002/02/25 08:20:14 knu Exp $ $Id$ UNIX Syslog extension for Ruby Amos Gouaux, University of Texas at Dallas & Akinori MUSHA Contact: - Akinori MUSHA (current maintainer) ** Syslog(Module) Included Modules: Syslog::Constants require 'syslog' A Simple wrapper for the UNIX syslog system calls that might be handy if you're writing a server in Ruby. For the details of the syslog(8) architecture and constants, see the syslog(3) manual page of your platform. Module Methods: open(ident = $0, logopt = Syslog::LOG_PID | Syslog::LOG_CONS, facility = Syslog::LOG_USER) [{ |syslog| ... }] Opens syslog with the given options and returns the module itself. If a block is given, calls it with an argument of itself. If syslog is already opened, raises RuntimeError. Example: Syslog.open('ftpd', Syslog::LOG_PID | Syslog::LOG_NDELAY, Syslog::LOG_FTP) open!(ident = $0, logopt = Syslog::LOG_PID | Syslog::LOG_CONS, facility = Syslog::LOG_USER) reopen(ident = $0, logopt = Syslog::LOG_PID | Syslog::LOG_CONS, facility = Syslog::LOG_USER) Same as open, but does a close first. opened? Returns true if syslog opened, otherwise false. ident options facility Returns the parameters given in the last open, respectively. Every call of Syslog::open resets these values. log(pri, message, ...) Writes message to syslog. Example: Syslog.log(Syslog::LOG_CRIT, "the sky is falling in %d seconds!", 10) crit(message, ...) emerg(message, ...) alert(message, ...) err(message, ...) warning(message, ...) notice(message, ...) info(message, ...) debug(message, ...) These are shortcut methods of Syslog::log(). The lineup may vary depending on what priorities are defined on your system. Example: Syslog.crit("the sky is falling in %d seconds!", 5) mask mask=(mask) Returns or sets the log priority mask. The value of the mask is persistent and will not be reset by Syslog::open or Syslog::close. Example: Syslog.mask = Syslog::LOG_UPTO(Syslog::LOG_ERR) close Closes syslog. inspect Returns the "inspect" string of the Syslog module. instance Returns the module itself. (Just for backward compatibility) LOG_MASK(pri) Creates a mask for one priority. LOG_UPTO(pri) Creates a mask for all priorities up to pri. ** Syslog::Constants(Module) require 'syslog' include Syslog::Constants This module includes the LOG_* constants available on the system. Module Methods: LOG_MASK(pri) Creates a mask for one priority. LOG_UPTO(pri) Creates a mask for all priorities up to pri. ================================================ FILE: ext/syslog/test.rb ================================================ #!/usr/bin/env ruby # $RoughId: test.rb,v 1.9 2002/02/25 08:20:14 knu Exp $ # $Id$ # Please only run this test on machines reasonable for testing. # If in doubt, ask your admin. require 'test/unit' # Prepend current directory to load path for testing. $:.unshift('.') require 'syslog' class TestSyslog < Test::Unit::TestCase def test_new assert_raises(NoMethodError) { Syslog.new } end def test_instance sl1 = Syslog.instance sl2 = Syslog.open sl3 = Syslog.instance assert_equal(Syslog, sl1) assert_equal(Syslog, sl2) assert_equal(Syslog, sl3) ensure Syslog.close if Syslog.opened? end def test_open # default parameters Syslog.open assert_equal($0, Syslog.ident) assert_equal(Syslog::LOG_PID | Syslog::LOG_CONS, Syslog.options) assert_equal(Syslog::LOG_USER, Syslog.facility) # open without close assert_raises(RuntimeError) { Syslog.open } Syslog.close # given parameters Syslog.open("foo", Syslog::LOG_NDELAY | Syslog::LOG_PERROR, Syslog::LOG_DAEMON) assert_equal('foo', Syslog.ident) assert_equal(Syslog::LOG_NDELAY | Syslog::LOG_PERROR, Syslog.options) assert_equal(Syslog::LOG_DAEMON, Syslog.facility) Syslog.close # default parameters again (after close) Syslog.open Syslog.close assert_equal(nil, Syslog.ident) assert_equal(nil, Syslog.options) assert_equal(nil, Syslog.facility) # block param = nil Syslog.open { |param| } assert_equal(Syslog, param) ensure Syslog.close if Syslog.opened? end def test_opened? assert_equal(false, Syslog.opened?) Syslog.open assert_equal(true, Syslog.opened?) Syslog.close assert_equal(false, Syslog.opened?) Syslog.open { assert_equal(true, Syslog.opened?) } assert_equal(false, Syslog.opened?) end def test_close assert_raises(RuntimeError) { Syslog.close } end def test_mask assert_equal(nil, Syslog.mask) Syslog.open orig = Syslog.mask Syslog.mask = Syslog.LOG_UPTO(Syslog::LOG_ERR) assert_equal(Syslog.LOG_UPTO(Syslog::LOG_ERR), Syslog.mask) Syslog.mask = Syslog.LOG_MASK(Syslog::LOG_CRIT) assert_equal(Syslog.LOG_MASK(Syslog::LOG_CRIT), Syslog.mask) Syslog.mask = orig ensure Syslog.close if Syslog.opened? end def test_log stderr = IO::pipe pid = fork { stderr[0].close STDERR.reopen(stderr[1]) stderr[1].close options = Syslog::LOG_PERROR | Syslog::LOG_NDELAY Syslog.open("syslog_test", options) { |sl| sl.log(Syslog::LOG_NOTICE, "test1 - hello, %s!", "world") sl.notice("test1 - hello, %s!", "world") } Syslog.open("syslog_test", options | Syslog::LOG_PID) { |sl| sl.log(Syslog::LOG_CRIT, "test2 - pid") sl.crit("test2 - pid") } exit! } stderr[1].close Process.waitpid(pid) # LOG_PERROR is not yet implemented on Cygwin. return if RUBY_PLATFORM =~ /cygwin/ 2.times { assert_equal("syslog_test: test1 - hello, world!\n", stderr[0].gets) } 2.times { assert_equal(format("syslog_test[%d]: test2 - pid\n", pid), stderr[0].gets) } end def test_inspect Syslog.open { |sl| assert_equal(format('<#%s: opened=true, ident="%s", options=%d, facility=%d, mask=%d>', Syslog, sl.ident, sl.options, sl.facility, sl.mask), sl.inspect) } assert_equal(format('<#%s: opened=false>', Syslog), Syslog.inspect) end end ================================================ FILE: ext/thread/extconf.rb ================================================ require 'mkmf' enable_config('fastthread', true) or exit if with_config('mem-pools', true) $CPPFLAGS << ' -DUSE_MEM_POOLS' end create_makefile("thread") ================================================ FILE: ext/thread/lib/thread.rb ================================================ unless defined? Thread fail "Thread not available for this ruby interpreter" end require 'thread.so' ================================================ FILE: ext/thread/thread.c ================================================ /* * Optimized Ruby Mutex implementation, loosely based on thread.rb by * Yukihiro Matsumoto * * Copyright 2006-2007 MenTaLguY * * RDoc taken from original. * * This file is made available under the same terms as Ruby. */ #include #include #include static VALUE rb_cMutex; static VALUE rb_cConditionVariable; static VALUE rb_cQueue; static VALUE rb_cSizedQueue; static VALUE set_critical(VALUE value); static VALUE thread_exclusive(VALUE (*func)(ANYARGS), VALUE arg) { VALUE critical = rb_thread_critical; rb_thread_critical = 1; return rb_ensure(func, arg, set_critical, (VALUE)critical); } /* * call-seq: * Thread.exclusive { block } => obj * * Wraps a block in Thread.critical, restoring the original value * upon exit from the critical section, and returns the value of the * block. */ static VALUE rb_thread_exclusive(void) { return thread_exclusive(rb_yield, Qundef); } typedef struct _Entry { VALUE value; struct _Entry *next; } Entry; typedef struct _List { Entry *entries; Entry *last_entry; Entry *entry_pool; unsigned long size; } List; static void init_list(List *list) { list->entries = NULL; list->last_entry = NULL; list->entry_pool = NULL; list->size = 0; } static void mark_list(List *list) { Entry *entry; for (entry = list->entries; entry; entry = entry->next) { rb_gc_mark(entry->value); } } static void free_entries(Entry *first) { Entry *next; while (first) { next = first->next; xfree(first); first = next; } } static void finalize_list(List *list) { free_entries(list->entries); free_entries(list->entry_pool); } static void push_list(List *list, VALUE value) { Entry *entry; if (list->entry_pool) { entry = list->entry_pool; list->entry_pool = entry->next; } else { entry = ALLOC(Entry); } entry->value = value; entry->next = NULL; if (list->last_entry) { list->last_entry->next = entry; } else { list->entries = entry; } list->last_entry = entry; ++list->size; } static void push_multiple_list(List *list, VALUE *values, unsigned count) { unsigned i; for (i = 0; i < count; i++) { push_list(list, values[i]); } } static void recycle_entries(List *list, Entry *first_entry, Entry *last_entry) { #ifdef USE_MEM_POOLS last_entry->next = list->entry_pool; list->entry_pool = first_entry; #else last_entry->next = NULL; free_entries(first_entry); #endif } static VALUE shift_list(List *list) { Entry *entry; VALUE value; entry = list->entries; if (!entry) return Qnil; list->entries = entry->next; if (entry == list->last_entry) { list->last_entry = NULL; } --list->size; value = entry->value; recycle_entries(list, entry, entry); return value; } static void remove_one(List *list, VALUE value) { Entry **ref; Entry *prev; Entry *entry; for (ref = &list->entries, prev = NULL, entry = list->entries; entry != NULL; ref = &entry->next, prev = entry, entry = entry->next) { if (entry->value == value) { *ref = entry->next; list->size--; if (!entry->next) { list->last_entry = prev; } recycle_entries(list, entry, entry); break; } } } static void clear_list(List *list) { if (list->last_entry) { recycle_entries(list, list->entries, list->last_entry); list->entries = NULL; list->last_entry = NULL; list->size = 0; } } static VALUE array_from_list(List const *list) { VALUE ary; Entry *entry; ary = rb_ary_new(); for (entry = list->entries; entry; entry = entry->next) { rb_ary_push(ary, entry->value); } return ary; } static void adjust_join(const List *list, VALUE new) { extern void rb_thread_set_join _((VALUE, VALUE)); Entry *entry; for (entry = list->entries; entry; entry = entry->next) { rb_thread_set_join(entry->value, new); } } static VALUE wake_thread(VALUE thread) { return rb_thread_wakeup_alive(thread); } static VALUE run_thread(VALUE thread) { thread = wake_thread(thread); if (RTEST(thread) && !rb_thread_critical) rb_thread_schedule(); return thread; } static VALUE wake_one(List *list) { VALUE waking; waking = Qnil; while (list->entries && !RTEST(waking)) { waking = wake_thread(shift_list(list)); } return waking; } static VALUE wake_all(List *list) { while (list->entries) { wake_one(list); } return Qnil; } extern int rb_thread_join _((VALUE thread, double limit)); #define DELAY_INFTY 1E30 static VALUE wait_list_inner(VALUE arg) { push_list((List *)arg, rb_thread_current()); rb_thread_stop(); return Qnil; } static VALUE wait_list_cleanup(VALUE arg) { /* cleanup in case of spurious wakeups */ remove_one((List *)arg, rb_thread_current()); return Qnil; } static VALUE wait_list(List *list) { return rb_ensure(wait_list_inner, (VALUE)list, wait_list_cleanup, (VALUE)list); } static void kill_waiting_threads(List *waiting) { Entry *entry; for (entry = waiting->entries; entry; entry = entry->next) { rb_thread_kill(entry->value); } } /* * Document-class: Mutex * * Mutex implements a simple semaphore that can be used to coordinate access to * shared data from multiple concurrent threads. * * Example: * * require 'thread' * semaphore = Mutex.new * * a = Thread.new { * semaphore.synchronize { * # access shared resource * } * } * * b = Thread.new { * semaphore.synchronize { * # access shared resource * } * } * */ typedef struct _Mutex { VALUE owner; List waiting; } Mutex; #define MUTEX_LOCKED_P(mutex) (RTEST((mutex)->owner) && rb_thread_alive_p((mutex)->owner)) static void mark_mutex(Mutex *mutex) { rb_gc_mark(mutex->owner); mark_list(&mutex->waiting); } static void finalize_mutex(Mutex *mutex) { finalize_list(&mutex->waiting); } static void free_mutex(Mutex *mutex) { kill_waiting_threads(&mutex->waiting); finalize_mutex(mutex); xfree(mutex); } static void init_mutex(Mutex *mutex) { mutex->owner = Qnil; init_list(&mutex->waiting); } /* * Document-method: new * call-seq: Mutex.new * * Creates a new Mutex * */ static VALUE rb_mutex_alloc(VALUE klass) { Mutex *mutex; mutex = ALLOC(Mutex); init_mutex(mutex); return Data_Wrap_Struct(klass, mark_mutex, free_mutex, mutex); } /* * Document-method: locked? * call-seq: locked? * * Returns +true+ if this lock is currently held by some thread. * */ static VALUE rb_mutex_locked_p(VALUE self) { Mutex *mutex; Data_Get_Struct(self, Mutex, mutex); return MUTEX_LOCKED_P(mutex) ? Qtrue : Qfalse; } /* * Document-method: try_lock * call-seq: try_lock * * Attempts to obtain the lock and returns immediately. Returns +true+ if the * lock was granted. * */ static VALUE rb_mutex_try_lock(VALUE self) { Mutex *mutex; Data_Get_Struct(self, Mutex, mutex); if (MUTEX_LOCKED_P(mutex)) return Qfalse; mutex->owner = rb_thread_current(); return Qtrue; } static VALUE wait_mutex(VALUE arg) { Mutex *mutex = (Mutex *)arg; VALUE current = rb_thread_current(); push_list(&mutex->waiting, current); do { rb_thread_critical = 0; rb_thread_join(mutex->owner, DELAY_INFTY); rb_thread_critical = 1; if (!MUTEX_LOCKED_P(mutex)) { mutex->owner = current; break; } } while (mutex->owner != current); return Qnil; } /* * Document-method: lock * call-seq: lock * * Attempts to grab the lock and waits if it isn't available. * */ static VALUE lock_mutex(Mutex *mutex) { VALUE current; current = rb_thread_current(); rb_thread_critical = 1; if (!MUTEX_LOCKED_P(mutex)) { mutex->owner = current; } else { rb_ensure(wait_mutex, (VALUE)mutex, wait_list_cleanup, (VALUE)&mutex->waiting); } rb_thread_critical = 0; return Qnil; } static VALUE lock_mutex_call(VALUE mutex) { return lock_mutex((Mutex *)mutex); } static VALUE rb_mutex_lock(VALUE self) { Mutex *mutex; Data_Get_Struct(self, Mutex, mutex); lock_mutex(mutex); return self; } /* * Document-method: unlock * * Releases the lock. Returns +nil+ if ref wasn't locked. * */ static VALUE unlock_mutex_inner(Mutex *mutex) { VALUE waking; if (mutex->owner != rb_thread_current()) { rb_raise(rb_eThreadError, "not owner"); } waking = wake_one(&mutex->waiting); if (!NIL_P(waking)) { adjust_join(&mutex->waiting, waking); } mutex->owner = waking; return waking; } static VALUE set_critical(VALUE value) { rb_thread_critical = (int)value; return Qundef; } static VALUE unlock_mutex(Mutex *mutex) { VALUE waking = thread_exclusive(unlock_mutex_inner, (VALUE)mutex); if (!RTEST(waking)) { return Qfalse; } run_thread(waking); return Qtrue; } static VALUE unlock_mutex_call(VALUE mutex) { return unlock_mutex((Mutex *)mutex); } static VALUE rb_mutex_unlock(VALUE self) { Mutex *mutex; Data_Get_Struct(self, Mutex, mutex); if (RTEST(unlock_mutex(mutex))) { return self; } else { return Qnil; } } /* * Document-method: exclusive_unlock * call-seq: exclusive_unlock { ... } * * If the mutex is locked, unlocks the mutex, wakes one waiting thread, and * yields in a critical section. * */ static VALUE rb_mutex_exclusive_unlock_inner(Mutex *mutex) { VALUE waking; waking = unlock_mutex_inner(mutex); rb_yield(Qundef); return waking; } static VALUE rb_mutex_exclusive_unlock(VALUE self) { Mutex *mutex; VALUE waking; Data_Get_Struct(self, Mutex, mutex); waking = thread_exclusive(rb_mutex_exclusive_unlock_inner, (VALUE)mutex); if (!RTEST(waking)) { return Qnil; } run_thread(waking); return self; } /* * Document-method: synchronize * call-seq: synchronize { ... } * * Obtains a lock, runs the block, and releases the lock when the block * completes. See the example under Mutex. * */ static VALUE rb_mutex_synchronize(VALUE self) { rb_mutex_lock(self); return rb_ensure(rb_yield, Qundef, rb_mutex_unlock, self); } /* * Document-class: ConditionVariable * * ConditionVariable objects augment class Mutex. Using condition variables, * it is possible to suspend while in the middle of a critical section until a * resource becomes available. * * Example: * * require 'thread' * * mutex = Mutex.new * resource = ConditionVariable.new * * a = Thread.new { * mutex.synchronize { * # Thread 'a' now needs the resource * resource.wait(mutex) * # 'a' can now have the resource * } * } * * b = Thread.new { * mutex.synchronize { * # Thread 'b' has finished using the resource * resource.signal * } * } * */ typedef struct _ConditionVariable { List waiting; } ConditionVariable; static void mark_condvar(ConditionVariable *condvar) { mark_list(&condvar->waiting); } static void finalize_condvar(ConditionVariable *condvar) { finalize_list(&condvar->waiting); } static void free_condvar(ConditionVariable *condvar) { kill_waiting_threads(&condvar->waiting); finalize_condvar(condvar); xfree(condvar); } static void init_condvar(ConditionVariable *condvar) { init_list(&condvar->waiting); } /* * Document-method: new * call-seq: ConditionVariable.new * * Creates a new ConditionVariable * */ static VALUE rb_condvar_alloc(VALUE klass) { ConditionVariable *condvar; condvar = ALLOC(ConditionVariable); init_condvar(condvar); return Data_Wrap_Struct(klass, mark_condvar, free_condvar, condvar); } /* * Document-method: wait * call-seq: wait * * Releases the lock held in +mutex+ and waits; reacquires the lock on wakeup. * */ static void condvar_wakeup(Mutex *mutex); static void wait_condvar(ConditionVariable *condvar, Mutex *mutex) { condvar_wakeup(mutex); rb_ensure(wait_list, (VALUE)&condvar->waiting, lock_mutex_call, (VALUE)mutex); } static void condvar_wakeup(Mutex *mutex) { VALUE waking; rb_thread_critical = 1; if (rb_thread_current() != mutex->owner) { rb_thread_critical = 0; rb_raise(rb_eThreadError, "not owner of the synchronization mutex"); } waking = unlock_mutex_inner(mutex); if (RTEST(waking)) { wake_thread(waking); } } static VALUE legacy_exclusive_unlock(VALUE mutex) { return rb_funcall(mutex, rb_intern("exclusive_unlock"), 0); } typedef struct { ConditionVariable *condvar; VALUE mutex; } legacy_wait_args; static VALUE legacy_wait(VALUE unused, legacy_wait_args *args) { wait_list(&args->condvar->waiting); rb_funcall(args->mutex, rb_intern("lock"), 0); return Qnil; } static VALUE rb_condvar_wait(VALUE self, VALUE mutex_v) { ConditionVariable *condvar; Data_Get_Struct(self, ConditionVariable, condvar); if (CLASS_OF(mutex_v) != rb_cMutex) { /* interoperate with legacy mutex */ legacy_wait_args args; args.condvar = condvar; args.mutex = mutex_v; rb_iterate(legacy_exclusive_unlock, mutex_v, legacy_wait, (VALUE)&args); } else { Mutex *mutex; Data_Get_Struct(mutex_v, Mutex, mutex); wait_condvar(condvar, mutex); } return self; } /* * Document-method: broadcast * call-seq: broadcast * * Wakes up all threads waiting for this condition. * */ static VALUE rb_condvar_broadcast(VALUE self) { ConditionVariable *condvar; Data_Get_Struct(self, ConditionVariable, condvar); thread_exclusive(wake_all, (VALUE)&condvar->waiting); rb_thread_schedule(); return self; } /* * Document-method: signal * call-seq: signal * * Wakes up the first thread in line waiting for this condition. * */ static void signal_condvar(ConditionVariable *condvar) { VALUE waking = thread_exclusive(wake_one, (VALUE)&condvar->waiting); if (RTEST(waking)) { run_thread(waking); } } static VALUE signal_condvar_call(VALUE condvar) { signal_condvar((ConditionVariable *)condvar); return Qundef; } static VALUE rb_condvar_signal(VALUE self) { ConditionVariable *condvar; Data_Get_Struct(self, ConditionVariable, condvar); signal_condvar(condvar); return self; } /* * Document-class: Queue * * This class provides a way to synchronize communication between threads. * * Example: * * require 'thread' * * queue = Queue.new * * producer = Thread.new do * 5.times do |i| * sleep rand(i) # simulate expense * queue << i * puts "#{i} produced" * end * end * * consumer = Thread.new do * 5.times do |i| * value = queue.pop * sleep rand(i/2) # simulate expense * puts "consumed #{value}" * end * end * * consumer.join * */ typedef struct _Queue { Mutex mutex; ConditionVariable value_available; ConditionVariable space_available; List values; unsigned long capacity; } Queue; static void mark_queue(Queue *queue) { mark_mutex(&queue->mutex); mark_condvar(&queue->value_available); mark_condvar(&queue->space_available); mark_list(&queue->values); } static void finalize_queue(Queue *queue) { finalize_mutex(&queue->mutex); finalize_condvar(&queue->value_available); finalize_condvar(&queue->space_available); finalize_list(&queue->values); } static void free_queue(Queue *queue) { kill_waiting_threads(&queue->mutex.waiting); kill_waiting_threads(&queue->space_available.waiting); kill_waiting_threads(&queue->value_available.waiting); finalize_queue(queue); xfree(queue); } static void init_queue(Queue *queue) { init_mutex(&queue->mutex); init_condvar(&queue->value_available); init_condvar(&queue->space_available); init_list(&queue->values); queue->capacity = 0; } /* * Document-method: new * call-seq: new * * Creates a new queue. * */ static VALUE rb_queue_alloc(VALUE klass) { Queue *queue; queue = ALLOC(Queue); init_queue(queue); return Data_Wrap_Struct(klass, mark_queue, free_queue, queue); } static VALUE rb_queue_marshal_load(VALUE self, VALUE data) { Queue *queue; VALUE array; Data_Get_Struct(self, Queue, queue); array = rb_marshal_load(data); if (TYPE(array) != T_ARRAY) { rb_raise(rb_eTypeError, "expected Array of queue data"); } if (RARRAY(array)->len < 1) { rb_raise(rb_eArgError, "missing capacity value"); } queue->capacity = NUM2ULONG(rb_ary_shift(array)); push_multiple_list(&queue->values, RARRAY(array)->ptr, (unsigned)RARRAY(array)->len); return self; } static VALUE rb_queue_marshal_dump(VALUE self) { Queue *queue; VALUE array; Data_Get_Struct(self, Queue, queue); array = array_from_list(&queue->values); rb_ary_unshift(array, ULONG2NUM(queue->capacity)); return rb_marshal_dump(array, Qnil); } /* * Document-method: clear * call-seq: clear * * Removes all objects from the queue. * */ static VALUE rb_queue_clear(VALUE self) { Queue *queue; Data_Get_Struct(self, Queue, queue); lock_mutex(&queue->mutex); clear_list(&queue->values); signal_condvar(&queue->space_available); unlock_mutex(&queue->mutex); return self; } /* * Document-method: empty? * call-seq: empty? * * Returns +true+ if the queue is empty. * */ static VALUE rb_queue_empty_p(VALUE self) { Queue *queue; VALUE result; Data_Get_Struct(self, Queue, queue); lock_mutex(&queue->mutex); result = queue->values.size == 0 ? Qtrue : Qfalse; unlock_mutex(&queue->mutex); return result; } /* * Document-method: length * call-seq: length * * Returns the length of the queue. * */ static VALUE rb_queue_length(VALUE self) { Queue *queue; VALUE result; Data_Get_Struct(self, Queue, queue); lock_mutex(&queue->mutex); result = ULONG2NUM(queue->values.size); unlock_mutex(&queue->mutex); return result; } /* * Document-method: num_waiting * call-seq: num_waiting * * Returns the number of threads waiting on the queue. * */ static VALUE rb_queue_num_waiting(VALUE self) { Queue *queue; VALUE result; Data_Get_Struct(self, Queue, queue); lock_mutex(&queue->mutex); result = ULONG2NUM(queue->value_available.waiting.size + queue->space_available.waiting.size); unlock_mutex(&queue->mutex); return result; } static void wait_queue(ConditionVariable *condvar, Mutex *mutex) { condvar_wakeup(mutex); wait_list(&condvar->waiting); lock_mutex(mutex); } static VALUE queue_pop_inner(VALUE arg); /* * Document-method: pop * call_seq: pop(non_block=false) * * Retrieves data from the queue. If the queue is empty, the calling thread is * suspended until data is pushed onto the queue. If +non_block+ is true, the * thread isn't suspended, and an exception is raised. * */ static VALUE rb_queue_pop(int argc, VALUE *argv, VALUE self) { Queue *queue; int should_block; Data_Get_Struct(self, Queue, queue); if (argc == 0) { should_block = 1; } else if (argc == 1) { should_block = !RTEST(argv[0]); } else { rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc); } lock_mutex(&queue->mutex); if (!queue->values.entries && !should_block) { unlock_mutex(&queue->mutex); rb_raise(rb_eThreadError, "queue empty"); } while (!queue->values.entries) { wait_queue(&queue->value_available, &queue->mutex); } return rb_ensure(queue_pop_inner, (VALUE)queue, unlock_mutex_call, (VALUE)&queue->mutex); } static VALUE queue_pop_inner(VALUE arg) { Queue *queue = (Queue *)arg; VALUE result = shift_list(&queue->values); if (queue->capacity && queue->values.size < queue->capacity) { signal_condvar(&queue->space_available); } return result; } /* * Document-method: push * call-seq: push(obj) * * Pushes +obj+ to the queue. * */ static VALUE rb_queue_push(VALUE self, VALUE value) { Queue *queue; Data_Get_Struct(self, Queue, queue); lock_mutex(&queue->mutex); while (queue->capacity && queue->values.size >= queue->capacity) { wait_queue(&queue->space_available, &queue->mutex); } push_list(&queue->values, value); rb_ensure(signal_condvar_call, (VALUE)&queue->value_available, unlock_mutex_call, (VALUE)&queue->mutex); return self; } /* * Document-class: SizedQueue * * This class represents queues of specified size capacity. The push operation * may be blocked if the capacity is full. * * See Queue for an example of how a SizedQueue works. * */ /* * Document-method: new * call-seq: new * * Creates a fixed-length queue with a maximum size of +max+. * */ /* * Document-method: max * call-seq: max * * Returns the maximum size of the queue. * */ static VALUE rb_sized_queue_max(VALUE self) { Queue *queue; VALUE result; Data_Get_Struct(self, Queue, queue); lock_mutex(&queue->mutex); result = ULONG2NUM(queue->capacity); unlock_mutex(&queue->mutex); return result; } /* * Document-method: max= * call-seq: max=(size) * * Sets the maximum size of the queue. * */ static VALUE rb_sized_queue_max_set(VALUE self, VALUE value) { Queue *queue; unsigned long new_capacity; unsigned long difference; Data_Get_Struct(self, Queue, queue); new_capacity = NUM2ULONG(value); if (new_capacity < 1) { rb_raise(rb_eArgError, "value must be positive"); } lock_mutex(&queue->mutex); if (queue->capacity && new_capacity > queue->capacity) { difference = new_capacity - queue->capacity; } else { difference = 0; } queue->capacity = new_capacity; for (; difference > 0; --difference) { signal_condvar(&queue->space_available); } unlock_mutex(&queue->mutex); return self; } /* * Document-method: push * call-seq: push(obj) * * Pushes +obj+ to the queue. If there is no space left in the queue, waits * until space becomes available. * */ /* * Document-method: pop * call-seq: pop(non_block=false) * * Retrieves data from the queue and runs a waiting thread, if any. * */ /* for marshalling mutexes and condvars */ static VALUE dummy_load(VALUE self, VALUE string) { return Qnil; } static VALUE dummy_dump(VALUE self) { return rb_str_new2(""); } void Init_thread(void) { rb_define_singleton_method(rb_cThread, "exclusive", rb_thread_exclusive, 0); rb_cMutex = rb_define_class("Mutex", rb_cObject); rb_define_alloc_func(rb_cMutex, rb_mutex_alloc); rb_define_method(rb_cMutex, "marshal_load", dummy_load, 1); rb_define_method(rb_cMutex, "marshal_dump", dummy_dump, 0); rb_define_method(rb_cMutex, "locked?", rb_mutex_locked_p, 0); rb_define_method(rb_cMutex, "try_lock", rb_mutex_try_lock, 0); rb_define_method(rb_cMutex, "lock", rb_mutex_lock, 0); rb_define_method(rb_cMutex, "unlock", rb_mutex_unlock, 0); rb_define_method(rb_cMutex, "exclusive_unlock", rb_mutex_exclusive_unlock, 0); rb_define_method(rb_cMutex, "synchronize", rb_mutex_synchronize, 0); rb_cConditionVariable = rb_define_class("ConditionVariable", rb_cObject); rb_define_alloc_func(rb_cConditionVariable, rb_condvar_alloc); rb_define_method(rb_cConditionVariable, "marshal_load", dummy_load, 1); rb_define_method(rb_cConditionVariable, "marshal_dump", dummy_dump, 0); rb_define_method(rb_cConditionVariable, "wait", rb_condvar_wait, 1); rb_define_method(rb_cConditionVariable, "broadcast", rb_condvar_broadcast, 0); rb_define_method(rb_cConditionVariable, "signal", rb_condvar_signal, 0); rb_cQueue = rb_define_class("Queue", rb_cObject); rb_define_alloc_func(rb_cQueue, rb_queue_alloc); rb_define_method(rb_cQueue, "marshal_load", rb_queue_marshal_load, 1); rb_define_method(rb_cQueue, "marshal_dump", rb_queue_marshal_dump, 0); rb_define_method(rb_cQueue, "clear", rb_queue_clear, 0); rb_define_method(rb_cQueue, "empty?", rb_queue_empty_p, 0); rb_define_method(rb_cQueue, "length", rb_queue_length, 0); rb_define_method(rb_cQueue, "num_waiting", rb_queue_num_waiting, 0); rb_define_method(rb_cQueue, "pop", rb_queue_pop, -1); rb_define_method(rb_cQueue, "push", rb_queue_push, 1); rb_alias(rb_cQueue, rb_intern("enq"), rb_intern("push")); rb_alias(rb_cQueue, rb_intern("<<"), rb_intern("push")); rb_alias(rb_cQueue, rb_intern("deq"), rb_intern("pop")); rb_alias(rb_cQueue, rb_intern("shift"), rb_intern("pop")); rb_alias(rb_cQueue, rb_intern("size"), rb_intern("length")); rb_cSizedQueue = rb_define_class("SizedQueue", rb_cQueue); rb_define_method(rb_cSizedQueue, "initialize", rb_sized_queue_max_set, 1); rb_define_method(rb_cSizedQueue, "num_waiting", rb_queue_num_waiting, 0); rb_define_method(rb_cSizedQueue, "pop", rb_queue_pop, -1); rb_define_method(rb_cSizedQueue, "push", rb_queue_push, 1); rb_define_method(rb_cSizedQueue, "max", rb_sized_queue_max, 0); rb_define_method(rb_cSizedQueue, "max=", rb_sized_queue_max_set, 1); rb_alias(rb_cSizedQueue, rb_intern("enq"), rb_intern("push")); rb_alias(rb_cSizedQueue, rb_intern("<<"), rb_intern("push")); rb_alias(rb_cSizedQueue, rb_intern("deq"), rb_intern("pop")); rb_alias(rb_cSizedQueue, rb_intern("shift"), rb_intern("pop")); } ================================================ FILE: ext/tk/.cvsignore ================================================ Makefile mkmf.log *.log ================================================ FILE: ext/tk/ChangeLog.tkextlib ================================================ 2008-05-12 Hidetoshi NAGAI * ext/tk/lib/tkextlib/tkDND/shape.rb: wrong package name. --------------< ... some changes ... >------------------ 2007-05-26 Hidetoshi NAGAI * ext/tk/lib/tkextlib/tcllib/tablelist.rb: fix typo. * ext/tk/lib/tkextlib/tile/dialog.rb: forget to give an argument. * ext/tk/lib/tkextlib/version.rb: update RELEASE_DATE. 2007-01-26 Hidetoshi NAGAI * ext/tk/lib/tkextlib/iwidgets/checkbox.rb: wrong number of arguments [ruby-Bugs-7776]. * ext/tk/lib/tkextlib/iwidgets/radiobox.rb: ditto. * ext/tk/lib/tkextlib/blt/tile/checkbutton.rb: change primary name of class [ruby-dev:30080]. * ext/tk/lib/tkextlib/blt/tile/radiobutton.rb: ditto. 2006-11-07 Hidetoshi NAGAI * lib/tkextlib/tile/treeview.rb : minor bug fix. * lib/tkextlib/blt/table.rb: fix bugs which forbade use of '::blt::table' command. Now, probably, it'll works properly. 2006-11-06 Hidetoshi NAGAI * lib/tkextlib/version.rb: keep release date of tkextlib on "Tk::Tkextlib_RELEASE_DATE". * lib/tkextlib/tile/treeview.rb : support Tile 0.7.8. Now, you can handle tree items as objects. 2006-10-04 Hidetoshi NAGAI * lib/tkextlib/tile.rb, lib/tkextlib/tile/* : support Tile 0.7.6. 2006-10-03 Hidetoshi NAGAI * lib/tkextlib/SUPPORT_STATUS: [ruby-talk:211939] check links of extensions. * lib/tkextlib/blt/container.rb: define instance methods properly. * lib/tkextlib/tile/tcombobox.rb: bug fix [ruby-talk:213003]. * lib/tkextlib/tile/tnotebook.rb: ditto. * lib/tkextlib/tile/treeview.rb: ditto. * lib/tkextlib/tile/sizegrip.rb: [new] add 'ttk::sizegrip' widget. 2006-08-31 Hidetoshi NAGAI * lib/tkextlib/blt.rb: double dashes (--) option doesn't work properly on some versions of BLT (wrong description on the manual of `blt::bgexec'?). 2005-12-11 Hidetoshi NAGAI * lib/tkextlib/SUPPORT_STATUS: update to support libraries in ActiveTcl8.4.12.0. * lib/tkextlib/tile/tnotebook.rb: add Tk::Tile::TNotebook#insert. * sample/tkextlib/tile/demo.rb: improve the look of a part of the demo. 2005-11-25 Hidetoshi NAGAI * sample/tkextlib/tile/demo.rb: bug fix * sample/tkextlib/tile/themes/*: add some themes (blue, keramik, and plastik; require Tile-0.5 or later). 2005-11-22 Hidetoshi NAGAI * lib/tkextlib/tile.rb: bug fix (Tk::Tile::USE_TTK_NAMESPACE is not defined). 2005-11-19 Hidetoshi NAGAI * sample/tkextlib/treectrl/demo.rb: remove dependency on Ruby's version (1.8 or 1.9). 2005-10-23 Hidetoshi NAGAI * lib/tkextlib/*: update to support ActiveTcl8.4.11.2 * lib/tkextlib/trofs/*: support Trofs 0.4.3 * lib/tkextlib/tile/*: support Tile 0.7.2 * lib/tkextlib/vu/*: support vu 2.3.0 * lib/tkextlib/tcllib/*: support Tcllib 1.8 (Tklib 0.3 part only) * lib/tkextlib/*: improve conversion of option values 2005-10-04 Hidetoshi NAGAI * lib/tkextlib/tktable/tktable.rb: border_* instance methods don't call 'border' subcommands. 2005-08-10 Hidetoshi NAGAI * lib/tkextlib/blt/component.rb: didn't check __item_ruby2val_optkeys(). 2005-08-09 Hidetoshi NAGAI * lib/tkextlib/blt/barchart.rb: support to treat tkvariable-type configure options. * lib/tkextlib/blt/component.rb: ditto. * lib/tkextlib/blt/dragdrop.rb: ditto. * lib/tkextlib/blt/treeview.rb: ditto. * lib/tkextlib/bwidget/button.rb: ditto. * lib/tkextlib/bwidget/entry.rb: ditto. * lib/tkextlib/bwidget/label.rb: ditto. * lib/tkextlib/bwidget/labelentry.rb: ditto. * lib/tkextlib/bwidget/labelframe.rb: ditto. * lib/tkextlib/bwidget/mainframe.rb: ditto. * lib/tkextlib/bwidget/passwddlg.rb: ditto. * lib/tkextlib/bwidget/spinbox.rb: ditto. * lib/tkextlib/bwidget/tree.rb: ditto. * lib/tkextlib/iwidgets/calendar.rb: ditto. * lib/tkextlib/iwidgets/entryfield.rb: ditto. * lib/tkextlib/iwidgets/hierarchy.rb: ditto. * lib/tkextlib/iwidgets/labeledframe.rb: ditto. * lib/tkextlib/iwidgets/labeledwidget.rb: ditto. * lib/tkextlib/iwidgets/menubar.rb: ditto. * lib/tkextlib/iwidgets/scrolledlistbox.rb: ditto. * lib/tkextlib/iwidgets/spinner.rb: ditto. * lib/tkextlib/iwidgets/toolbar.rb: ditto. * lib/tkextlib/tkimg/pixmap.rb: ditto. * lib/tkextlib/tktable/tktable.rb: ditto. 2005-08-06 ocean * sample/tkextlib/tile/demo.rb: use Tk::Tile::Scale#variable. 2005-08-04 ocean * sample/tkextlib/tile/demo.rb: followed previous changes. 2005-08-04 Hidetoshi NAGAI * lib/tkextlib/tile/t*.rb: aliased class names starting with 'T' to non 'T' ones. (ie. Tk::Tile::TButton -> Tk::Tile::Button) [ruby-dev:26724] * lib/tkextlib/tile.rb: ditto. (autoload support) 2005-08-04 ocean * sample/tkextlib/tile/demo.rb: fixed: Tk::Tile::TProgressbar is supported on tile 0.6 or later, not tile 0.5. * sample/tkextlib/tile/demo.rb: updated scales demo to use Tk::Tile::TProgressbar for tile 0.6 or later. * sample/tkextlib/tile/demo.rb: set some TkVariable default values. 2005-08-03 Hidetoshi NAGAI * lib/tkextlib/tile/treeview.rb: Tk::Tile::Treeview#headingconfigure is now working and more. [ruby-dev:26716] * sample/tkextlib/tile/demo.rb: use Tk::Tile::Treeview#headingconfigure instead of direct Tk.tk_call. 2005-08-02 ocean * lib/tkextlib/tile/tprogressbar.rb: Tk::Tile::TProgressbar#start takes optional argument `interval'. * sample/tkextlib/tile/demo.rb: emulate Tk::Tile::TProgressbar with Tk::Tile::TProgress in tile 0.4. (repeating buttons demo) 2005-08-02 ocean * sample/tkextlib/tile/demo.rb: added repeating buttons demo. * sample/tkextlib/tile/repeater.tcl: ditto. (new file) 2005-08-01 ocean * lib/tkextlib/tile.rb: fixed autoload for Treeview. * lib/tkextlib/tile/treeview.rb: replaced `ary2tk_list(items)' with `*items'. * sample/tkextlib/tile/demo.rb: added treeview demo. (tile 0.5 or later is required) [ruby-dev:26668] 2005-08-01 ocean * sample/tkextlib/tile/demo.rb: added combobox demo. 2005-07-27 ocean * sample/tkextlib/tile/demo.rb: fixed typo. 2005-06-16 Hidetoshi NAGAI * lib/tkextlib/SUPPOPRT_STATUS: add RELEASE_DATE information. * lib/tkextlib/tile/style.rb: add "style element options " command support. 2005-06-08 Hidetoshi NAGAI * lib/tkextlib/ICONS/icons.rb: fail to create instances of Tk::ICONS [ruby-dev:26305]. 2005-06-07 ocean * sample/tkextlib/tile/themes/kroc.{rb,tcl}: also support tile 0.4. 2005-06-07 ocean * sample/tkextlib/tile/themes/kroc.{rb,tcl}: support tile 0.5 or later. ("pixmap" element constructor replaced by "image") 2005-06-05 Hidetoshi NAGAI * sample/tkextlib/tile/demo.rb: fix TypeError & create Console 2005-05-30 Hidetoshi NAGAI * lib/tkextlib/blt.rb: add PACKAGE_NAME information of Tcl/Tk Extension. * lib/tkextlib/bwidget.rb: ditto. * lib/tkextlib/iwidgets.rb: ditto. * lib/tkextlib/tile.rb: ditto. * lib/tkextlib/tkimg.rb: ditto. * lib/tkextlib/vu.rb: ditto. * lib/tkextlib/ICONS/icons.rb: ditto. * lib/tkextlib/itcl/incr_tcl.rb: ditto. * lib/tkextlib/itk/incr_tk.rb: ditto. * lib/tkextlib/tcllib/autoscroll.rb: ditto. * lib/tkextlib/tcllib/ctext.rb: ditto. * lib/tkextlib/tcllib/cursor.rb: ditto. * lib/tkextlib/tcllib/datefield.rb: ditto. * lib/tkextlib/tcllib/ico.rb: ditto. * lib/tkextlib/tcllib/ip_entry.rb: ditto. * lib/tkextlib/tcllib/plotchart.rb: ditto. * lib/tkextlib/tcllib/style.rb: ditto. * lib/tkextlib/tcllib/tkpiechart.rb: ditto. * lib/tkextlib/tclx/tclx.rb: ditto. * lib/tkextlib/tkDND/shape.rb: ditto. * lib/tkextlib/tkDND/tkdnd.rb: ditto. * lib/tkextlib/tkHTML/htmlwidget.rb: ditto. * lib/tkextlib/tkimg/bmp.rb: ditto. * lib/tkextlib/tkimg/gif.rb: ditto. * lib/tkextlib/tkimg/ico.rb: ditto. * lib/tkextlib/tkimg/jpeg.rb: ditto. * lib/tkextlib/tkimg/pcx.rb: ditto. * lib/tkextlib/tkimg/pixmap.rb: ditto. * lib/tkextlib/tkimg/png.rb: ditto. * lib/tkextlib/tkimg/ppm.rb: ditto. * lib/tkextlib/tkimg/ps.rb: ditto. * lib/tkextlib/tkimg/sgi.rb: ditto. * lib/tkextlib/tkimg/sun.rb: ditto. * lib/tkextlib/tkimg/tga.rb: ditto. * lib/tkextlib/tkimg/tiff.rb: ditto. * lib/tkextlib/tkimg/window.rb: ditto. * lib/tkextlib/tkimg/xbm.rb: ditto. * lib/tkextlib/tkimg/xpm.rb: ditto. * lib/tkextlib/tktable/tktable.rb: ditto. * lib/tkextlib/tktrans/tktrans.rb: ditto. * lib/tkextlib/treectrl/tktreectrl.rb: ditto. * lib/tkextlib/winico/winico.rb: ditto. 2005-05-25 Hidetoshi NAGAI * lib/tkextlib/iwidgets/scrolledlistbox.rb: follow the change of tk.rb. modify to attend encoding. * lib/tkextlib/iwidgets/scrolledtext.rb: ditto. * lib/tkextlib/iwidgets/scrolledcanvas.rb: bug fix on TkCanvas#delete when given non-TkcItem arguments. 2005-05-10 Hidetoshi NAGAI * lib/tkextlib/blt/winop.rb: fix typo 2005-05-08 Hidetoshi NAGAI * lib/tkextlib/vu/pie.rb: fix typo 2005-04-10 ocean * sample/tkextlib/treectrl/mailwasher.rb: fixed typo. [ruby-dev:26008] 2005-04-09 Hidetoshi NAGAI * sample/tkextlib/tile/demo.rb: new demo of Tile extension. * sample/tkextlib/tile/iconlib.tcl: part of the demo. * sample/tkextlib/tile/toolbutton.tcl: ditto. * sample/tkextlib/tile/readme.txt: document of the demo. * sample/tkextlib/tile/Orig_LICENSE.txt: ditto. * sample/tkextlib/tile/themes/kroc.tcl: sample theme written with Tcl. * sample/tkextlib/tile/themes/pkgIndex.tcl: pkgIndex of kroc.tcl. * sample/tkextlib/tile/themes/kroc.rb: Kroc theme written with Ruby. * sample/tkextlib/tile/themes/kroc/button-h.gif: images for Kroc theme. * sample/tkextlib/tile/themes/kroc/button-n.gif: ditto. * sample/tkextlib/tile/themes/kroc/button-p.gif: ditto. * sample/tkextlib/tile/themes/kroc/check-hc.gif: ditto. * sample/tkextlib/tile/themes/kroc/check-hu.gif: ditto. * sample/tkextlib/tile/themes/kroc/check-nc.gif: ditto. * sample/tkextlib/tile/themes/kroc/check-nu.gif: ditto. * sample/tkextlib/tile/themes/kroc/radio-hc.gif: ditto. * sample/tkextlib/tile/themes/kroc/radio-hu.gif: ditto. * sample/tkextlib/tile/themes/kroc/radio-nc.gif: ditto. * sample/tkextlib/tile/themes/kroc/radio-nu.gif: ditto. * lib/tkextlib/tile.rb: bug fix (tested on the new demo). * lib/tkextlib/tile/style.rb: ditto. * lib/tkextlib/tile/tbutton.rb: ditto. * lib/tkextlib/tile/tcheckbutton.rb: ditto. * lib/tkextlib/tile/tcombobox.rb: ditto. * lib/tkextlib/tile/tentry.rb: ditto. * lib/tkextlib/tile/tframe.rb: ditto. * lib/tkextlib/tile/tlabel.rb: ditto. * lib/tkextlib/tile/tlabelframe.rb: ditto. * lib/tkextlib/tile/tmenubutton.rb: ditto. * lib/tkextlib/tile/tnotebook.rb: ditto. * lib/tkextlib/tile/tprogressbar.rb: ditto. * lib/tkextlib/tile/tradiobutton.rb: ditto. * lib/tkextlib/tile/treeview.rb: ditto. * lib/tkextlib/tile/tscrollbar.rb: ditto. * lib/tkextlib/tile/tseparator.rb: ditto. * lib/tkextlib/tile/tsquare.rb: ditto. * lib/tkextlib/tile/tpaned.rb: new library * lib/tkextlib/tile/tscale.rb: ditto. * lib/tkextlib/SUPPORT_STATUS: update support status of Tile extension. * lib/tkextlib/tcllib/ctext.rb: use TkCommandNames on create_self(). * lib/tkextlib/tcllib/datefield.rb: ditto. * lib/tkextlib/tcllib/ip_entry.rb: ditto. * lib/tkextlib/tkHTML/htmlwidget.rb: ditto. * lib/tkextlib/treectrl/tktreectrl.rb: ditto. 2005-04-09 ocean * sample/tkextlib/treectrl/explorer.rb: File.executable? returns true even if it's plain text file. (this function only checks access right) 2005-04-09 ocean * sample/tkextlib/treectrl/{help,www-options}.rb: fixed typo. (click or resize column header) 2005-04-09 ocean * sample/tkextlib/treectrl/imovie.rb: fixed typo. (click on clip title) 2005-04-08 ocean * sample/tkextlib/treectrl/random.rb: fixed typo. (drop node outside of widget, or reenter widget while draggging) 2005-04-08 ocean * sample/tkextlib/treectrl/outlook-newgrounp.rb: image had disappered when node was selected. 2005-04-08 ocean * sample/tkextlib/treectrl/{random,outlook-newgroup}.rb: tk::treectrl uses 'afterId' not 'afterID'. * sample/tkextlib/treectrl/{random,outlook-newgroup}.rb: item_firstchild can return empty string. (drop node to leaf node) * sample/tkextlib/treectrl/random.rb: Enumerable#find didn't work properly because tried to compare String with Integer. (drag node and leave widget) * sample/tkextlib/treectrl/random.rb: and some fixes. 2005-04-08 ocean * lib/tkextlib/treectrl/tktreectrl.rb (selection_clear): fixed typo. * sample/tkextlib/treectrl/random.rb: node deselection now works. * sample/tkextlib/treectrl/demo.rb: fixed typo. (popup menu on column header) 2005-04-08 ocean * sample/tkextlib/treectrl/help.rb: fixed typo. (wrong color) 2005-04-08 ocean * sample/tkextlib/treectrl/random.rb: fixed typo. (wrong itemheight) * sample/tkextlib/treectrl/outlook-newgroup.rb: ditto. * sample/tkextlib/treectrl/explorer.rb: ditto. * sample/tkextlib/treectrl/help.rb: ditto. 2005-04-07 ocean * sample/tkextlib/treectrl/*.rb: some speed up... cache the result of version checking. 2005-04-07 Hidetoshi NAGAI * lib/tkextlib/treectrl/tktreectrl.rb: performance tuning by calling tk_send_without_enc. [ruby-dev:25997] 2005-04-04 ocean * lib/tkextlib/tktable/tktable.rb: added Tk::TkTable#selection_present. 2005-04-02 Hidetoshi NAGAI * lib/tkextlib/treectrl/tktreectrl.rb: support TreeCtrl's cvs head. 2005-04-02 Hidetoshi NAGAI * lib/tkextlib/blt/component.rb: add TreeCtrl#legend_window_create(). * sample/tkextlib/blt/graph6.rb: use legend_window_create(). * lib/tkextlib/blt/tree.rb: forget to call tagid(). * lib/tkextlib/blt/treeview.rb: ditto. 2005-04-01 Hidetoshi NAGAI * sample/tkextlib/treectrl/demo.rb: bridge the gap of Hash#index or Hash#key between ruby 1.8 and 1.9 2005-04-01 Hidetoshi NAGAI * lib/tkextlib/blt/component.rb: bug fix on treatment of component objects. * sample/tkextlib/blt/graph6.rb: a new sample script. 2005-03-31 ocean * sample/tkextlib/treectrl/demo.rb: should use Hash#index. * sample/tkextlib/treectrl/demo.rb: TkImage was not cached properly. * sample/tkextlib/treectrl/random.rb: fixed typo. 2005-03-31 Hidetoshi NAGAI * sample/tkextlib/iwidgets/sample/hierarchy.rb: show basename only [ruby-dev:25970] * sample/tkextlib/treectrl/demo.rb: add check for existence of 'backgroundimage' option. * sample/tkextlib/treectrl/bitmaps.rb: ditto. * sample/tkextlib/treectrl/outlook-newgroup.rb: lack of '%I' event callback argument. 2005-03-31 Hidetoshi NAGAI * sample/tkextlib/iwidgets/sample/hierarchy.rb: fail to treat Japanese (i18n?) filenames. 2005-03-30 Hidetoshi NAGAI * sample/tkextlib/bwidget/tree.rb: use 'return' in the Proc object. * sample/tkextlib/tkHTML/hv.rb: ditto. * sample/tkextlib/tkHTML/ss.rb: ditto. * sample/tkextlib/tktable/basic.rb: ditto. * sample/tkextlib/tktable/command.rb: ditto. * sample/tkextlib/tktable/debug.rb: ditto. * sample/tkextlib/tktable/maxsize.rb: ditto. * sample/tkextlib/treectrl/demo.rb: ditto. 2005-03-29 Hidetoshi NAGAI * lib/tkextlib/blt/component.rb: cannot create elements except default type of element. * lib/tkextlib/blt/barchart.rb: ditto. * lib/tkextlib/blt/graph.rb: ditto. * lib/tkextlib/blt/stripchart.rb: ditto. * lib/tkextlib/blt/component.rb: axis command option gets proper object type of arguments. * sample/tkextlib/blt/calendar.rb: new sample. * sample/tkextlib/blt/pareto.rb: ditto. 2005-03-28 ocean * lib/tkextlib/iwidgets/notebook.rb: fixed typo. 2005-03-26 Hidetoshi NAGAI * lib/tkextlib/blt.rb: add commands for zooming. * lib/tkextlib/blt/bitmap.rb (new_with_name): add for using given name. * lib/tkextlib/blt/busy.rb: bug fix on Tk::BLT::Busy::Shild class. * lib/tkextlib/blt/component.rb: typo fix. * lib/tkextlib/blt/component.rb: fix lack of *_create methods * lib/tkextlib/blt/component.rb: proper call on xaxis_* and so on. * lib/tkextlib/blt/htext.rb: add TkVariable object to access special Tcl variables. * lib/tkextlib/treectrl/tktreectrl.rb: typo fix. * lib/tkextlib/treectrl/tktreectrl.rb: proper treatment of 'font' option of element_configure. * lib/tkextlib/treectrl/tktreectrl.rb: bug fix on item_sort. * lib/tkextlib/treectrl/tktreectrl.rb: add methods to call TreeCtrl commands for bindings. * sample/tkextlib/blt/*: add some sample scripts. * sample/tkextlib/treectrl/*: add some sample scripts. 2005-03-18 Hidetoshi NAGAI * lib/tkextlib/treectrl/tktreectrl.rb: bug fix and define some classes for components of Tk::TreeCtrl 2005-03-17 Hidetoshi NAGAI * lib/tkextlib/treectrl/tktreectrl.rb: call wrong method in Tk::TreeCtrl#*_configinfo and current_*_configinfo method 2005-03-16 Hidetoshi NAGAI * lib/tkextlib/SUPPORT_STATUS: change the status of TkImg * lib/tkextlib/treectrl/tktreectrl.rb: bug fix and support TkTreeCtrl-1.1 * lib/tkextlib/SUPPORT_STATUS: change the supported version of TkTreeCtrl 2005-03-15 Hidetoshi NAGAI * sample/tkextlib/tkimg: add sample 2005-03-06 Hidetoshi NAGAI * lib/tkextlib/SUPPORT_STATUS: add version info of each extension 2005-03-05 Hidetoshi NAGAI * lib/tkextlib/tile.rb: lack of "autoload TProgressbar" 2005-03-05 Hidetoshi NAGAI * lib/tkextlib/tile.rb: support tile-0.6 * lib/tkextlib/tile/tbutton.rb: ditto * lib/tkextlib/tile/tcheckbutton.rb: ditto * lib/tkextlib/tile/tlabel.rb: ditto * lib/tkextlib/tile/tmenubutton.rb: ditto * lib/tkextlib/tile/tnotebook.rb: ditto * lib/tkextlib/tile/tradiobutton.rb: ditto * lib/tkextlib/tile/tcombobox.rb: [new] ditto * lib/tkextlib/tile/tentry.rb: [new] ditto * lib/tkextlib/tile/tframe.rb: [new] ditto * lib/tkextlib/tile/tlabelframe.rb: [new] ditto * lib/tkextlib/tile/tprogressbar.rb: [new] ditto * lib/tkextlib/tile/treeview.rb: [new] ditto * lib/tkextlib/tile/tscrollbar.rb: [new] ditto * lib/tkextlib/tile/tseparator.rb: [new] ditto * lib/tkextlib/tile/tsquare.rb: [new] ditto 2005-02-20 Hidetoshi NAGAI * lib/tkextlib/tclx/tclx.rb: warning TclX's 'signal' command. 2005-01-25 Hidetoshi NAGAI * lib/tkextlib/blt/component.rb: bug fix. cannot accept a callback ID string for a command argument. [ruby-dev:25479] * lib/tkextlib/blt/tabset.rb: ditto * lib/tkextlib/blt/treeview.rb: ditto * lib/tkextlib/bwidget/labelentry.rb: ditto * lib/tkextlib/bwidget/listbox.rb: ditto * lib/tkextlib/bwidget/notebook.rb: ditto * lib/tkextlib/bwidget/spinbox.rb: ditto * lib/tkextlib/bwidget/tree.rb: ditto * lib/tkextlib/itk/incr_tk.rb: ditto * lib/tkextlib/iwidgets/scrolledcanvas.rb: ditto * lib/tkextlib/tkDND/tkdnd.rb: ditto * lib/tkextlib/treectrl/tktreectrl.rb: ditto * sample/tkextlib/tkHTML/ss.rb: local variable scope bug fix [ruby-dev:25479] * sample/tkextlib/vu/vu_demo.rb: rename from vu.rb; avoid the bug on Windows version of Tcl/Tk. The trouble based on the bug occurs when the script name (without extension) is a same name as a Tcl/Tk's library file name (without extension) required in the script. 2004-12-24 Hidetoshi NAGAI * lib/tkextlib/blt: add BLT extension support 2004-12-16 Hidetoshi NAGAI * lib/tkextlib/bwidget/labelentry.rb: use TkCore.callback_obj?() * lib/tkextlib/bwidget/listbox.rb: ditto * lib/tkextlib/bwidget/notebook.rb: ditto * lib/tkextlib/bwidget/spinbox.rb: ditto * lib/tkextlib/itk/incr_tk.rb: ditto * lib/tkextlib/iwidgets/scrolledcanvas.rb: ditto * lib/tkextlib/tkDND/tkdnd.rb: ditto * lib/tkextlib/treectrl/tktreectrl.rb: ditto * lib/tkextlib/winico/winico.rb: ditto 2004-12-10 Hidetoshi NAGAI * lib/tkextlib/tile/style.rb: 'theme_use' method bug fix 2004-12-08 Hidetoshi NAGAI * lib/tkextlib/bwidget/notebook.rb: raise method cannot return the raised page. * lib/tkextlib/bwidget/labelentry.rb: bind methods accept subst_args + block * lib/tkextlib/bwidget/listbox.rb: ditto * lib/tkextlib/bwidget/notebook.rb: ditto * lib/tkextlib/bwidget/spinbox.rb: ditto * lib/tkextlib/bwidget/tree.rb: ditto * lib/tkextlib/itk/incr_tk.rb: ditto * lib/tkextlib/iwidgets/scrolledcanvas.rb: ditto * lib/tkextlib/tkDND/tkdnd.rb: ditto * lib/tkextlib/treectrl/tktreectrl.rb: ditto 2004-11-26 Hidetoshi NAGAI * lib/tkextlib/bwidget/notebook.rb: uses epath * lib/tkextlib/bwidget/widget.rb: ditto * lib/tkextlib/tktable/tktable.rb: ditto * lib/tkextlib/tcllib/cursor.rb: ditto, and bug fix 2004-11-10 Hidetoshi NAGAI * lib/tkextlib/tile/style.rb: bug fix 2004-11-07 Hidetoshi NAGAI * lib/tkextlib/iwidgets/scrolledcanvas.rb: bind-event methods accept multi substitution arguments. * lib/tkextlib/tktable/tktable.rb: ditto. * lib/tkextlib/treectrl/tktreectrl.rb: ditto 2004-11-03 Hidetoshi NAGAI * lib/tkextlib/SUPPORT_STATUS: BLT moves to 'plan to support' from 'not determined' * lib/tkextlib/itk/incr_tk.rb: __cget_cmd and __config_cmd are private methods * lib/tkextlib/tcllib/autoscroll.rb: extend TkCore * lib/tkextlib/tcllib/cursor.rb: ditto. * lib/tkextlib/tcllib/plotchart.rb: ditto. * lib/tkextlib/tcllib/style.rb: ditto. * lib/tkextlib/tile/style.rb: ditto. * lib/tkextlib/tkDND/shape.rb: ditto. 2004-10-24 Hidetoshi NAGAI * lib/tkextlib/bwidget/tree.rb: bug fix on Windows 2004-10-16 Hidetoshi NAGAI * lib/tkextlib/tcllib/ico.rb: new library (Tk::Tcllib:ICO) * lib/tkextlib/tcllib.rb: add Tk::Tcllib::ICO (based on tcllib 1.7) 2004-10-06 Hidetoshi NAGAI * lib/tkextlib/bwidget.rb (BWidget.grab): bug fix * lib/tkextlib/tcllib.rb: typo fix 2004-07-28 Hidetoshi NAGAI * lib/tkextlib/add winico support 2004-07-23 Hidetoshi NAGAI * lib/tkextlib/add TclX support (partially; infox command and XPG/3 MsgCat only) 2004-07-15 Hidetoshi NAGAI * bug fix * support TkTable extension 2004-07-12 Hidetoshi NAGAI * bug fix * support Iwidgets extension 2004-07-10 Hidetoshi NAGAI * bug fix * add more part of [incr Widget] support (about 65%? are complete) * use Tk::ValidateConfigure.__def_validcmd() method (new function to define validatecommand methods easier) * tcllib.rb : avoid the loading trouble that almost all part of the extension is not available when some libraries are invalid. 2004-07-09 Hidetoshi NAGAI * add some part of [incr Widget] support (about 50%? are complete) 2004-07-07 Hidetoshi NAGAI * add [incr Tck], [incr Tk] support 2004-07-06 Hidetoshi NAGAI * support BWidget extension * add BWidget extension demo * add ICONS extension demo * many bug fix 2004-07-01 Hidetoshi NAGAI * 1st release of tkextlib ( to support Tcl/Tk extensions ) ================================================ FILE: ext/tk/MANUAL_tcltklib.eng ================================================ (tof) 2005/07/05 Hidetoshi NAGAI This document discribes about the 'tcltklib' library. Although there is the 'tcltk' library (tcltk.rb) under this directory, no description in this document (because it is not maintained recently). ============================================================== module TclTklib : Defines methods to do operations which are independed on : Tcl/Tk interpreters module TclTkLib::EventFlag : Defines flags to define taget events on 'do_one_event' methos. : When to give, please use bit-operator (e.g. WINDOW | DONT_WAIT). [constants] NONE : Is 0. It means "there is no target". But on the real : operation, it is same to ALL. WINDOW : 'window' event is processed. FILE : 'file' event is processed. TIMER : 'timer' event is processed. IDLE : 'idle' operation (e.g. 're-draw'; the operations when the : other kinds of events doesn't occur) is processed. ALL : All kinds of events are processed. : Same to 'WINDOW | FILE | TIMER | IDLE'. DONT_WAIT : Without this flag, 'do_one_event' waits the occurence of : a target event. With this flag, doesn't wait and returns : false if there is no target event for processing. module TclTkLib::VarAccessFlag : Defines flags to give '_get_variable' and so on. When to give, : please use bit-operator (e.g. GLOBAL_ONLY | LEAVE_ERR_MSG ). [constants] NONE : Is 0. It means "set no flag". GLOBAL_ONLY : (site Tcl/Tk's man page) : Under normal circumstances the procedures look up : variables as follows: If a procedure call is active : in interp, a variable is looked up at the current : level of procedure call. Otherwise, a variable is : looked up first in the current namespace, then in : the global namespace. However, if this bit is set : in flags then the variable is looked up only in the : global namespace even if there is a procedure call : active. If both GLOBAL_ONLY and NAMESPACE_ONLY are : given, GLOBAL_ONLY is ignored. : : *** ATTENTION *** : Tcl7.6 doesn't have namespaces. So NAMESPACE_ONLY : is defined as 0, and then GLOBAL_ONLY is available : even if flag is (GLOBAL_ONLY | NAMESPACE_ONLY). NAMESPACE_ONLY : (site Tcl/Tk's man page) : Under normal circumstances the procedures look up : variables as follows: If a procedure call is active : in interp, a variable is looked up at the current : level of procedure call. Otherwise, a variable is : looked up first in the current namespace, then in : the global namespace. However, if this bit is set : in flags then the variable is looked up only in the : current namespace even if there is a procedure call : active. : : *** ATTENTION *** : Tcl7.6 doesn't have namespaces. So NAMESPACE_ONLY : is defined as 0. LEAVE_ERR_MSG : (site Tcl/Tk's man page) : If an error is returned and this bit is set in flags, : then an error message will be left in the interpreter's : result, where it can be retrieved with Tcl_GetObjResult : or Tcl_GetStringResult. If this flag bit isn't set then : no error message is left and the interpreter's result : will not be modified. APPEND_VALUE : (site Tcl/Tk's man page) : If this bit is set then newValue is appended to the : current value, instead of replacing it. If the variable : is currently undefined, then this bit is ignored. LIST_ELEMENT : (site Tcl/Tk's man page) : If this bit is set, then newValue is converted to a : valid Tcl list element before setting (or appending : to) the variable. A separator space is appended before : the new list element unless the list element is going : to be the first element in a list or sublist (i.e. the : variable's current value is empty, or contains the : single character ``{'', or ends in `` }''). PARSE_VARNAME : (site Tcl/Tk's man page) : If this bit is set when calling _set_variable and so : on, var_name argument may contain both an array and an : element name: if the name contains an open parenthesis : and ends with a close parenthesis, then the value : between the parentheses is treated as an element name : (which can have any string value) and the characters : before the first open parenthesis are treated as the : name of an array variable. If the flag PARSE_VARNAME : is given, index_name argument should be 'nil' since the : array and element names are taken from var_name. : : *** ATTENTION *** : Tcl7.6 doesn't have this flag. So PARSE_VARNAME is : defined as 0. module TclTkLib::RELEASE_TYPE : Defines release type number of Tcl/Tk ALPHA : ALPHA release BETA : BETA release FINAL : FINAL release [module methods] get_version() : return an array of major, minor, release-type number, : number, release-type name, and patchlevel of current : Tcl/Tk library. mainloop(check_root = true) : Starts the eventloop. If 'check_root' is true, this method : doesn't return when a root widget exists. : If 'check_root' is false, doen't return by the other : reasons than exceptions. mainloop_thread? : Returns whether the current thread executes the eventloop. : If true, the eventloop is working on the current thread. : If no eventloop is working, this method returns nil. : And if the other thread executes the eventloop, returns false. : : *** ATTENTION *** : When this methods returns false, it is dangerous to call a Tk : interpreter directly. mainloop_watchdog(check_root = true) : On the normal eventloop, some kinds of callback operations : cause deadlock. To avoid some of such deadlocks, this : method starts an eventloop and a watchdog-thread. do_one_event(flag = TclTkLib::EventFlag::ALL | TclTkLib::EventFlag::DONT_WAIT) : Do one event for processing. When processed an event, : returns true. : If NOT set DONT_WAIT flag, this method waits occurrence of : a target event. : If set DONT_WAIT flag and no event for processing, returns : false immediately. : If $SAFE >= 4, or $SAFE >= 1 and the flag is tainted, : force to set DONT_WAIT flag. set_eventloop_tick(timer_tick) : Define the interval of thread-switching with an integer : value of mili-seconds. : Default timer_tick is 0. It means that thread-switching : is based on the count of processed events. : ( see 'set_eventloop_weight' method ) : However, if the eventloop thread is the only thread, : timer_tick cannt be set to 0. If 0, then is set to 100 ms : automatically (see NO_THREAD_INTERRUPT_TIME on tcltklib.c). : On $SAFE >= 4, cannot call this method. get_eventloop_tick : Get current value of 'timer_tick' set_no_event_wait(no_event_wait) : Define sleeping time of the eventloop when two or more : thread are running and there is no event for processing. : Default value is 20 (ms). : If the eventloop thread is the only thread, this value is : invalid. : On $SAFE >= 4, cannot call this method. get_no_event_wait : Get current value of 'no_event_wait'. set_eventloop_weight(loop_max, no_event_tick) : Define the weight parameters for the eventloop thread. : That is invalid when the eventloop is the only thread. : 'loop_max' is the max events for thread-switching. : 'no_event_tick' is the increment value of the event count : when no event for processing (And then, the eventloop thead : sleeps 'no_event_wait' mili-seconds). : 'loop_max == 800' and 'no_event_tick == 10' are defalut. : On $SAFE >= 4, cannot call this method. get_eventloop_weight : Get current values of 'loop_max' and 'no_event_tick'. mainloop_abort_on_exception=(bool) : Define whether the eventloop stops on exception or not. : If true (default value), stops on exception. : If false, show a warinig message but ignore the exception. : If nil, no warning message and ignore the excepsion. : This parameter is sometimes useful when multiple Tk : interpreters are working. Because the only one eventloop : admins all Tk interpreters, sometimes exception on a : interpreter kills the eventloop thread. Even if such : situation, when abort_on_exception == false or nil, : the eventloop ignores the exception and continue to working. : On $SAFE >= 4, cannot call this method. mainloop_abort_on_exception : Get current status of that. num_of_mainwindows : Returns the number of main-windows (root-widget). : Because there is only one main-window for one Tk interpreter, : the value is same to the number of interpreters which has : available Tk functions. _merge_tklist(str, str, ... ) : Get a Tcl's list string from arguments with a Tcl/Tk's : library function. Each arguemnt is converted to a valid : Tcl list element. _conv_listelement(str) : Convert the argument to a valid Tcl list element with : Tcl/Tk's library function. _toUTF8(str, encoding=nil) _fromUTF8(str, encoding=nil) : Call the function (which is internal function of Tcl/Tk) to : convert to/from a UTF8 string. _subst_UTF_backslash(str) _subst_Tcl_backslash(str) : Substitute backslash sequence with Tcl's rule (include \uhhhh; : give a sixteen-bit hexadecimal value for Unicode character). : _subst_Tcl_backslash method parses all backslash sequence. : _subst_UTF_backslash method parses \uhhhh only. encoding_system encoding_system=(encoding) : Get and set Tcl's system encoding. encoding encoding=(encoding) : alias of encoding_system / encoding_system= : ( probably, Ruby/Tk's tk.rb will override them ) class TclTkIp [class methods] new(ip_name=nil, options='') : Generate an instance of TclTkIp class. : If 'ip_name' argument is given as a string, it is the name : of the Tk interpreter which is shown by 'winfo interps' : command. : 'options' argument accepts a string which is the command : line options of wish; such as '-geometry' or '-use'. : The information is used to generate the root widget of the : interpreter. : ( e.g. TclTkIp.new('FOO', '-geometry 500x200 -use 0x2200009') ) : If is given nil or falsr for the 'option' argument, generates : the Tcl interpreter without Tk library. Then the interpreter : doesn't need GUI environment. Therefore, even if a window : system doesn't exist or cannot be used, Ruby can control the : Tcl interpreter and the extention libraries loaded on the : interpreter. [instance methods] create_slave(name, safe=false) : Create a slave interpreter. : The parent of the interpreter is the receiver of this method. : The name of the slave interpreter is given by 'name' argument. : The 'safe' argument decides whether the slave interpreter is : created as a safe interpreter or not. If true, create a safe : interpreter. Default is false. However, if the parent : interpreter is a safe interpreter, the created interpreter is : a safe interpreter (ignore 'safe' argument value). : If $SAFE >= 4, can create a safe interpreter only. make_safe : Make the interpreter to the safe interpreter, and returns : self. If fail, raise RuntimeError. safe? : Check whether the interpreter is the safe interpreter. : If is the safe interpreter, returns true. allow_ruby_exit? : Return the mode whether 'exit' function of ruby or 'exit' : command of Tcl/Tk can quit the ruby process or not on the : interpreter. If false, such a command quit the interpreter : only. : The default value for a master interpreter is true, and : for a slave interpreter is false. allow_ruby_exit=(mode) : Change the mode of 'allow_ruby_exit?'. : If $SAFE >= 4 or the interpreter is a "safe" interpreter, : this is not permitted (raise an exception). delete : Delete the interpreter. : The deleted interpreter doesn't accept command and then : raise an exception. deleted? : Check whether the interpreter is already deleted. : If deleted, returns true. has_mainwindow? : Check whether the interpreter has a MainWindow (root widget). : If has, returns true. If doesn't, returns false. : If IP is already deleted, returns nil. restart : Restart Tk part of the interpreter. : Use this when you need Tk functions after destroying the : root widget. : On $SAFE >= 4, cannot call this method. _eval(str) _invoke(*args) : Estimates the arguments as a command on the Tk interpreter. : The argument of _eval is a script of Tcl/Tk. : Each argument of _invoke is a token of one command line of : Tcl/Tk. : Because the operation of _invoke doesn't through the : command line parser of Tk interpreter, the cost of : estimation is smaller than _eval. However, auto_load : mechanism of the Tk interpreter doesn't work on _invoke. : So _invoke can call only the command which already : registered on the interpreter by 'load' command and so on. : On _eval command, auto_load mechanism words. So if succeed : to _eval and regist the command once, after that, the : command can be called by _invoke. _toUTF8(str, encoding=nil) _fromUTF8(str, encoding=nil) : Call the function (which is internal function of Tcl/Tk) to : convert to/from a UTF8 string. _thread_vwait(var_name) _thread_tkwait(mode, target) : 'vwait' or 'tkwait' with thread support. : The difference from normal 'vwait' or 'tkwait' command is : doing independent wait from the vwait stack when they are : called on the other thread than the eventloop thread. : In the case of Tcl/Tk's vwait / tkwait, if 2nd vwait / : tkwait is called on waiting for 1st vwait / tkwait, : returns the order of [2nd]->[1st] regardless of the order : of when the wait condition was fulfilled. : If _thread_vwait / _thread_tkwait is called on the : eventloop thread, there is no difference from vwait / : tkwait. But if called on the other thread than the : eventloop, stops the thread. And when the wait condition : is fulfilled, the thread restarts. The meaning of : "independent from the vwait stack" is that the timing of : restarting is independent from the waiting status of the : other threads. That is, even if the eventloop thread is : waiting by vwait and is not fulfilled the condition, : _thread_vwait completes the waiting when its waiting : condition is fulfilled and the thread which stopped by : _thread_vwait can continue the operation. _return_value : Get the last result value on the interpreter. _get_variable(var_name, flag) _get_variable2(var_name, index_name, flag) : Get the current value of a variable. If specified a : index_name (see also the PARSE_VARNAME flag), get the : value of the index_name element. _set_variable(var_name, value, flag) _set_variable2(var_name, index_name, value, flag) : Create or modify a variable. If specified a index_name : (see also the PARSE_VARNAME flag), create or modify the : index_name element. _unset_variable(var_name) _unset_variable2(var_name, index_name) : Remove a variable. If specified a index_name (see also : the PARSE_VARNAME flag), remove the index_name element. _get_global_var(var_name) _get_global_var2(var_name, index_name) _set_global_var(var_name, value) _set_global_var2(var_name, index_name, value) _unset_global_var(var_name) _unset_global_var2(var_name, index_name) : Call the associated method with the flag argument : (GLOBAL_ONLY | LEAVE_ERR_MSG). _split_tklist(str) : Split the argument with Tcl/Tk's library function and : get an array as a list of Tcl list elements. _merge_tklist(str, str, ... ) : Get a Tcl's list string from arguments with a Tcl/Tk's : library function. Each arguemnt is converted to a valid : Tcl list element. _conv_listelement(str) : Convert the argument to a valid Tcl list element with : Tcl/Tk's library function. mainloop mainloop_watchdog : If on the slave interpreter, never start an eventloop and : returns nil. : With the exception that, same to the TclTkLib module method : with the same name. do_one_event : With the exception that the argument is forced to set : DONT_WAIT flag on the slave interpreter, same to : TclTkLib#do_one_event. set_eventloop_tick get_eventloop_tick set_no_event_wait get_no_event_wait set_eventloop_weight get_eventloop_weight mainloop_abort_on_exception mainloop_abort_on_exception= : With the exception that it is ignored to set value on the : slave interpreter, same to the TclTkLib module method with : the same name. encoding_table : For Ruby m17n. Return encoding relation table between Ruby's : Encoding object and Tcl's encoding name. class TkCallbackBreak < StandardError class TkCallbackContinue < StandardError : They are exception classes to break or continue the Tk callback : operation. : If raise TkCallbackBreak on the callback procedure, Ruby returns : 'break' code to Tk interpreter (Then the Tk interpreter will : break the operation for the current event). : If raise TkCallbackContinue, returns 'continue' code (Then the Tk : interpreter will break the operateion for the current bindtag and : starts the operation for the next buindtag for the current event). : However, current tcltklib supports Ruby's 'break' and 'next' to : get the same effect. That is, those classes are obsolete. Those : exist for backward compatibility. (eof) ================================================ FILE: ext/tk/MANUAL_tcltklib.eucj ================================================ (tof) 2005/07/05 Hidetoshi NAGAI ܥɥȤˤϸŤ tcltk 饤֥ꡤtcltklib 饤֥ ޤޤƤޤεƤϸŤΤȤʤäƤޤ tcltk 饤֥tcltk.rbˤϸߤǤϥƥʥ󥹤¾Ԥ ʤᡤŤɥȤΤޤͭǤФ tcltklib 饤֥ˤĤƤϡߤ Ruby/Tktk.rb ʲΥ饤֥ 귲ˤƯ뤿濴Ȥƥƥʥ󥹤Ƥ뤿ᡤ 㤤Ƥޤ ǡޤŤʸ򼨤塤ߤ tcltklib 饤֥ˤ Ƥäޤ ʲ饤֥θŤʸǤ ============================================================== MANUAL.euc Sep. 19, 1997 Y. Shigehiro ʲ, tcl/tkפȤɽ, tclsh wish ¸Ƥ, ̤Ǥ Ȥ tcl/tk ؤޤ. tcltk 饤֥, tcltklib 饤֥ פȤɽ, ܥѥå˴ޤޤ ruby ѤΥ饤֥ؤޤ. << tcltk 饤֥ >> tcl/tk C 饤֥Ѥ뤿ι(?)।󥿡ե ޤ. Υ饤֥ ruby tcl/tk 饤֥Ѥ뤿ΤΤ, tcltklib 饤֥ѤƤޤ. [] tcl/tk 󥿥ץ꥿Ǥ, åȤ˲ؼˤ, ̾³ƥѥ᡼񤭤ޤ. ä, åȤ֥ ȤǤ, Фƥ᥽åɤäƤ, ȤߤʤȤǤޤ. , tcl/tk 󥿥ץ꥿Ǥ, Ȥ߹ߥޥɤ, ҤΥåȤ Ʊ褦ʽ񼰤̿Ǽ¹Ԥޤ. ʤ, ޥɤ⥪֥Ȥ ȹͤ뤳ȤǤޤ. Τ褦ʹͤ˴Ť, tcltk 饤֥Ǥ, tcl/tk Υޥɤ䥦 åȤб륪֥Ȥޤ. ֥ȤФ᥽ ɸƤӽФ, e() ᥽åɤˤ¹Ԥޤ. 㤨, tcl/tk info ޥɤб ruby Υ֥Ȥ info Ȥ̾ǤȤ, tcl/tk info commands Ȥ̿ tcltk 饤֥Ǥ info.e("commands") ȵҤޤ. ޤ, .פȤå (wish ¹Ի˼ưŪ 롼ȥå) б ruby Υ֥Ȥ root Ȥ ̾ǤȤ, . configure -height 300 -width 300 Ȥ tcl/tk ̿ root.e("configure -height 300 -width 300") ȵҤޤ. Τ褦ʵҤ, ˤޤ, , ץȤɤͤˤϸŤ餤Τޤ, ºݤ˥ץȤ Ƥߤͽ۳˼ڤǤ. [ˡ] 1. 饤֥ɤ߹. require "tcltk" 2. tcl/tk 󥿥ץ꥿. ip = TclTkInterpreter.new() 3. tcl/tk Υޥɤб륪֥ȤѿƤ. # ޥɤб륪֥Ȥä Hash Ф. c = ip.commands() # Ȥޥɤб륪֥Ȥ̤ѿ. bind, button, info, wm = c.indexes("bind", "button", "info", "wm") 4. ɬפʽԤ. ܤ, ץ򻲾ȤΤ. 5. Ǥ, ٥ȥ롼פ. TclTk.mainloop() (( ʲ, ⥸塼, 饹ͽ.)) << tcltklib 饤֥ >> tcl/tk C 饤֥Ѥ뤿।󥿡ե󶡤 . ѥ/¹Ԥˤ, tcl/tk C 饤֥꤬ɬפǤ. [] Υ饤֥Ѥ, ruby tcl/tk C 饤֥ѤǤ . Ūˤ, ruby 󥿥ץ꥿ tcl/tk 󥿥ץ꥿ƤӽФ ȤǤޤ. , (ruby 󥿥ץ꥿ƤӽФ) tcl/tk 󥿥ץ꥿, դ ruby 󥿥ץ꥿ƤӽФȤǤޤ. [ˡ] require "tcltklib" , ʲΥ⥸塼, 饹ѲǽǤ. ⥸塼 TclTkLib tcl/tk 饤֥ƤӽФ᥽åɤ򽸤᤿⥸塼Ǥ. , tcl/tk 󥿥ץ꥿طΥ᥽åɤϥ饹 TclTkIp ˤޤ. ⥸塼᥽å mainloop() Tk_MainLoop ¹Ԥޤ. Ƥ tk Υɥ̵ʤȽλ ޤ(㤨, tcl/tk ǽ񤯤Ȥ "destroy ." 򤷤). : ̵ : nil 饹 TclTkIp 󥹥󥹤 tcl/tk Υ󥿥ץ꥿бޤ. tcl/tk Υ饤 λ̤, 󥹥󥹤ʣƤưޤ( ʤȤ򤹤ɬפϤޤ̵ϤǤ). 󥿥ץ꥿ wish tcl/tk ޥɤ¹ԤǤޤ. , ʲΥޥɤ¹ԤǤ . ޥ ruby ruby Ǽ¹Ԥޤ(ruby_eval_string ¹Ԥޤ). 1 ĤǤʤФʤޤ. ͤ ruby μ¹Է̤Ǥ. ruby μ¹Է̤ nil String ǤʤФʤޤ. 饹᥽å new() TclTkIp 饹Υ󥹥󥹤ޤ : ̵ (TclTkIp): 줿󥹥 ᥽å _eval(script) 󥿥ץ꥿ script ɾޤ(Tcl_Eval ¹Ԥޤ). Τ褦, ruby ޥɤˤ script ⤫ ruby ץȤ ԤǤޤ. : script (String) - 󥿥ץ꥿ɾ륹ץʸ (String): ɾ ((Tcl_Interp *)->result) ᥽å _return_value() ľ Tcl_Eval ֤ͤޤ. 0(TCL_OK) ェλǤ. : ̵ (Fixnum): ľ Tcl_Eval() ֤. ============================================================== ʲܥɥȺǤ tcltklib 饤֥Ǥ ============================================================== ⥸塼 TclTkLib : ġ Tcl/Tk 󥿡ץ꥿˰¸ʤ ( == ٥ȥ롼 : פ˴ؤ ) ƤӽФ᥽åɤ⥸塼롥 ⥸塼 TclTkLib::EventFlag : do_one_event ƤӽФݤνоݥ٥Ȥꤹ뤿 : ե饰 ( WINDOW|DONT_WAIT Ȥ褦˥ӥåȱ黻ҤϢ뤷 : ) Ȥ⥸塼롥ʲޤޤ롥 NONE : ͤ 0 ǡͤȤƤϤʤΥ٥ȤꤷƤʤ : Ȥˤʤ뤬ºݤν ALL ƱȤư롥 WINDOW : window ٥ȤоݤȤ FILE : file ٥ȤоݤȤ TIMER : timer ٥ȤоݤȤ IDLE : ɥ롼׽ ( ʤɡ¾μΥ٥Ȥȯ : ƤʤȤ˹Ԥ ) оݤȤ ALL : ٤ƤμΥ٥ȤоݤȤ : WINDOW|FILE|TIMER|IDLE Ʊ DONT_WAIT : оݥ٥Ȥ¸ߤʤˡ٥ȯԤ : do_one_event λ ( false ֤ ) ⥸塼 TclTkLib::VarAccessFlag : _get_variable ʤɤǤΥե饰ꤹ뤿ΤΡե饰 : ϰʲ OR Ϣ뤷Ϳ롥 NONE : ͤ 0 ǡե饰ꤷƤʤΤ GLOBAL_ONLY : ̾ѿθϤޤ³ƤӽФԤä٥Ǹ : ˸ߤ֤̾ǸǸ˥Х֤ : ԤΥե饰ꤵ줿ˤϡ : Х֤ǤΤ߸롥 : ⤷ GLOBAL_ONLY NAMESPACE_ONLY Ȥξꤵ줿 : ˤϡGLOBAL_ONLY λ̵뤵롥 NAMESPACE_ONLY : Υե饰ꤵ줿ˤϡߤ֤̾ǤΤ : θԤGLOBAL_ONLY ⻲Ȥ뤳ȡ LEAVE_ERR_MSG : ѿˤƥ顼ȯ硤Υե饰 : ꤵƤС¹Է̤Ȥ Tcl 󥿡ץ꥿˥ : 顼åĤ롥Υե饰ꤵƤʤ : С顼åϰڻĤʤ APPEND_VALUE : Υե饰ꤵƤ硤ѿ֤ͤΤ : Ϥʤߤͤͤɲ (append; ʸϢ) : 롥ѿ̤ä硤Υե饰̵뤵롥 LIST_ELEMENT : Υե饰ꤵƤ硤ͤϤޤ Tcl Υꥹ : ǤȤŬڤȤʤ褦Ѵ롥ͤꥹ : (ޤϥ֥ꥹ) κǽǤȤʤΤǤʤ¤ꡤ : ͤľˤ϶ʸɲä롥 PARSE_VARNAME : _set_variable ʤɤθƤӽФˤƤΥե饰ꤵ : Ƥ硤var_name Ϣ̾̾Ȥξ : ޤǽ (̤ޤߡĤ̤ǽ) : Ȥ򼨤ξ硤̤δ֤̾ꡤǽγ : ̤ޤǤϢ̾Ȥư롥_set_variable2 ʤɤ : Υե饰ꤹ硤Ϣ̾̾ var_name : ФϤǤ뤫顤index_name nil : ͤФʤʤ ⥸塼 TclTkLib::RELEASE_TYPE : Tcl/Tk Υ꡼ֹ ALPHA : ALPHA ꡼ BETA : BETA ꡼ FINAL : FINAL ꡼ ⥸塼᥽å get_version() : Tcl/Tk major, minor, release-type ֹ, release-type ̾, : patchlevel ˤ֤ mainloop(check_root = true) : ٥ȥ롼פư롥check_root true ǤС : root widget ¸ߤ¤ꡤΥ᥽åɤϽλʤ : check_root false ξϡroot widget ǤƤ : Υ᥽åɤϽλʤ ( root widget ǤƤ⡤ : WINDOW ʳΥ٥Ȥȯ뤿 )λˤϡ : Ưݤ ( åɤѤʤ ) ɬס mainloop_thread? : ȥåɤ٥ȥ롼פ¹ԤƤ륹å : ɤ֤ : ٥ȥ롼פ¹ԤƤ륹åɤǤ true : ɤΥåɤǤ⥤٥ȥ롼פ¹ԤƤʤ : nil ¾Υåɤǥ٥ȥ롼פ¹ԤƤ : false ֤ : false κݤ Tk 󥿡ץ꥿ľܸƤ֤ΤϴǤ롥 mainloop_watchdog(check_root = true) : ̾Υ٥ȥ롼פǤϡ٥ȽƤˤäƤ : ǥåɥåǽ (㤨Х٥Ȥ : Ф륳Хå widget 򤷡νλ : ԤĤʤ)Υ᥽åɤϡǥåɥå : 뤿δƻ륹åդǥ٥ȥ롼פư : ( ƻ륹åɤ˥٥ȥ롼פ¹Ԥ ) : ΰ̣ mainloop ƱǤ롥 do_one_event(flag = TclTkLib::EventFlag::ALL | TclTkLib::EventFlag::DONT_WAIT) : ԤΥ٥ 1 Ĥ¹Ԥ롥 : ٥Ȥ true ֤ : ե饰 DONT_WAIT ꤷƤʤ硤ե饰ǽ : ݤȤʤäƤΥ٥ȤȯޤԤ³롥 : DONT_WAIT ꤷƤ硤оݥ٥ȤʤƤ : ˽λ false ֤ : $SAFE >= 4 $SAFE >= 1 flag Ƥʤ : flag ˤ DONT_WAIT Ūդ롥 set_eventloop_tick(timer_tick) : ٥ȥ롼פƱ̥åɤƯƤˡ : ֤˴ŤŪʥåɥå󥰤ɤ٤ : ( ֳִ ) ȯ뤫ߥñ̤ͤǻꤹ롥 : 0 ꤹȡζŪʥå󥰤ϹԤʤ : ɸǤ 0 ꤵƤꡤ٥Ƚ˴Ť : 󥰤Ԥ ( see set_eventloop_weight ) : ƯƤ륹åɤ٥ȥ롼פξ硤 : timer_tick 0 ꤹ뤳ȤϤǤʤ⤷ꤵ : 顤100 ms ( see NO_THREAD_INTERRUPT_TIME ) ˼ư : ꤵ롥 : ܺ٤ά CPU ѥ󤷤Ĥİ : ꤷư¸뤿˼ͤǤ롥 : $SAFE >= 4 Ǥϼ¹Ԥػߤ롥 get_eventloop_tick : timer_tick θ֤ͤ set_no_event_wait(no_event_wait) : ʣΥåɤƯƤǡԤ٥Ȥ : ¸ߤʤäݤ sleep ֤Ĺꤹ롥 : Ưåɤ٥ȥ롼פξˤϰ̣ʤʤ : ǥեȤͤ 20 (ms) : $SAFE >= 4 Ǥϼ¹Ԥػߤ롥 get_no_event_wait : no_event_wait θ֤ͤ set_eventloop_weight(loop_max, no_event_tick) : ʣΥåɤƯƤݤ Ruby/Tk Υ٥ȥ롼 : פ˳ƤŤ뤿Υѥ᡼ꤹ롥 : Ưåɤ٥ȥ롼פξˤϰ̣ʤʤ : ٤Υåڤؤδ֤˽륤٥Ȥκȡ : ԤΥ٥Ȥ¸ߤʤݤβûȤꤹ롥 : Ԥ٥Ȥ¸ߤʤ no_event_wait ( see : set_no_event_wait ) δ sleep ֤롥 : ǥեȤǤϤ줾 800 10 󡤤Ĥޤꡤ800 ĤΥ : ٥ (ɥ륤٥Ȥޤ) Ȥ٥ : ȯʤޤޤ 80 νԤ٥ȸλ : ȤǥȤ 800 ʾˤʤȥåɥå : ȯ뤳Ȥˤʤ롥 : $SAFE >= 4 Ǥϼ¹Ԥػߤ롥 get_eventloop_weight : ߤ loop_max no_event_tick Ȥ֤ͤ : ( see set_eventloop_wait ) mainloop_abort_on_exception=(bool) : Tk 󥿡ץ꥿㳰ȯݤˡ٥ȥ롼פ : 顼ߤ뤫ɤꤹ롥true ꤷ : 顼ߤ뤬false ξ㳰̵뤷ƥ٥ȥ롼 : פ³롥 nil ξϷٹ⡼ɤǤʤ¤ϥ : 顼åνϤάơ㳰̵뤹롥 : ǥեȤǤ true ꤵƤ롥 : ĤΥ󥿡ץ꥿ȤäƤˤϥ顼ˤ : ޤߤƤ̾ʤʣΥ󥿡ץ꥿Ʊ : ưƤˤϡ륤٥ȥ롼פϣ : ĤǤ뤿ᡤ줫Υ󥿡ץ꥿Υ顼ǡ : ¾Υ󥿡ץ꥿ν³Բǽˤʤ뤳Ȥ롥 : 褦ʾǤ⥨顼̵뤷ƥ٥ȥ롼פƯ³ : Ȥǡ¾Υ󥿡ץ꥿ư³뤳ȤǤ롥 : $SAFE >= 4 Ǥϼ¹Ԥػߤ롥 mainloop_abort_on_exception : Tk 󥿡ץ꥿㳰ȯݤˡ٥ȥ롼פ : 顼ߤ뤫ɤ֤ true/false 롥 num_of_mainwindows : ߤΥᥤ󥦥ɥ (롼ȥå) ο֤ : ᥤ󥦥ɥϰĤΥ󥿡ץ꥿դĤǤ : Τǡͤϸ Tk εǽͭǤ륤󥿡ץ꥿ : _merge_tklist(str, str, ... ) : Tcl/Tk Υ饤֥ؿȤäơʸ󤬤줾 : ĤΥꥹǤȤʤ褦Ϣ뤷ʸ֤ _conv_listelement(str) : Tcl/Tk Υ饤֥ؿȤäơʸ Tcl : ĤΥꥹǤȤŬڤɽˤʤ褦Ѵʸ : ֤ _toUTF8(str, encoding=nil) _fromUTF8(str, encoding=nil) : Tcl/Tk ¢Ƥ UTF8 ѴƤӽФ _subst_UTF_backslash(str) _subst_Tcl_backslash(str) : Tcl Υ롼ǥХåå嵭ˡ ( \uhhhh ˤ : Unicode ʸɽޤ ) Ϥ롥 : _subst_Tcl_backslash Ϥ٤ƤΥХåå嵭ˡ : ֤ΤФ_subst_UTF_backslash \uhhhh : ˤ Unicode ʸɽ֤롥 encoding_system encoding_system=(encoding) : Tcl system encoding γ encoding encoding=(encoding) : encoding_system / encoding_system= alias : ( Ruby/Tk tk.rb Ǥ֤ͽΤΡ) 饹 TclTkIp 饹᥽å new(ip_name=nil, options='') : TclTkIp 饹Υ󥹥󥹤롥 : ip_name ʸͿϡ줬 winfo interps ʤɤ : ɽ̾ˤʤ롥 : options ˤϡ-geometry -use ʤɡwish Υޥɥ饤 : ȤͿ륪ץƱͤξʸȤͿ롥 : Ϳ줿ϡroot widget κݤѤ롥 : ( e.g. TclTkIp.new('FOO', '-geometry 500x200 -use 0x2200009') ) : ⤷ options ˴ nil ޤ false Ϳ硤Tk 饤 : ֥꤬ƳƤʤ (Ĥޤ Tcl Τߤ) 󥿡ץ : 롥ξ GUI Ķɬפʤᡤɥ : ƥब¸ߤʤޤϻѤǤʤĶǤ Tcl 󥿡 : ץ꥿Tcl 䤽γĥ饤֥Ѥ뤳ȤǤ롥 󥹥󥹥᥽å create_slave(name, safe=false) : 쥷ФƤȤ name Ȥ̾Υ졼֥󥿡ץ꥿ : 롥 : safe ˤ륤󥿡ץ꥿ safe 󥿡ץ꥿Ȥ : ꤹ롥ǥեȤ false ȤȤˤʤäƤ뤬 : ȤΤ false ꤷƤȤƤ⡤ƤȤʤ륤󥿡 : ץ꥿ safe 󥿡ץ꥿ǤСѤ : safe 󥿡ץ꥿Ȥ롥 : $SAFE >= 4 Ǥϡsafe 󥿡ץ꥿ʳػߤ롥 make_safe : Tcl/Tk 󥿡ץ꥿ safe 󥿡ץ꥿ѹ롥 : ͤϥ쥷ФǤ륤󥿡ץ꥿ȤǤ롥 : Ԥ RuntimeError 㳰ȯ롥 safe? : Tcl/Tk 󥿡ץ꥿ safe 󥿡ץ꥿Ǥ뤫Ĵ٤롥 : safe 󥿡ץ꥿Ǥ true ֤ allow_ruby_exit? : оݤȤʤ륤󥿡ץ꥿ɾǡruby exit ؿޤ : Tcl/Tk exit ޥɤˤä ruby Τλ뤳 : ɤ֤ : ʤоݤΥ󥿡ץ꥿λ롥 : ޥ󥿡ץ꥿Υǥեͤ true졼֥󥿡 : ץ꥿Υǥեͤ false Ǥ롥 allow_ruby_exit=(mode) : оݤȤʤ륤󥿡ץ꥿ allow_ruby_exit? ξ֤ѹ롥 : $SAFE >= 4 ޤϥ󥿡ץ꥿ safe 󥿡ץ꥿ξ : ѹʤ (㳰ȯ) delete : Tcl/Tk 󥿡ץ꥿ delete 롥 : delete 줿󥿡ץ꥿ϡʸڤǤʤʤꡤ : ޥɤäƤ㳰ȯ褦ˤʤ롥 deleted? : Tcl/Tk 󥿡ץ꥿Ǥ delete Ƥ뤫Ĵ٤롥 : delete Ѥߤǥޥɤդʤ֤ˤʤäƤʤ : true ֤ has_mainwindow? : Tcl/Tk 󥿡ץ꥿˥ᥤ󥦥ɥ (root widget) : ¸ߤ true ¸ߤʤ false ֤ : 󥿡ץ꥿ delete ѤߤǤ nil ֤ restart : Tcl/Tk 󥿡ץ꥿ Tk ʬνƵưԤ : ö root widget ˲˺ Tk εǽɬפ : ʤäѤ롥 : $SAFE >= 4 Ǥϼ¹Ԥػߤ롥 _eval(str) _invoke(*args) : Tcl/Tk 󥿡ץ꥿ɾԤ : _eval ɾץȤĤʸǤ뤳ȤФ : _invoke ɾץȤ token Ȥ˰ĤΰȤ : 褦Ϳ롥 : _invoke Tcl/Tk 󥿡ץ꥿λϴѤ : ʤᡤɾ٤꾯ʤƤࡥ : auto_load Τ褦ʵƯload ˤä : Tcl/Tk 󥿡ץ꥿˴ϿѤߤΥޥɤ : ӽФȤǤʤ : _eval Ǥ auto_load Ưᡤ _eval ¹ : ϿСʹߤ _invoke ǤѤ : 褦ˤʤ롥 _toUTF8(str, encoding=nil) _fromUTF8(str, encoding=nil) : Tcl/Tk ¢Ƥ UTF8 ѴƤӽФ _thread_vwait(var_name) _thread_tkwait(mode, target) : åб vwait 뤤 tkwait Υ᥽åɡ : ̾ vwait 뤤 tkwait ޥɤȰۤʤΤϡ٥ : ȥ롼פȤϰۤʤ륹åɤƤӽФ vwait : åȤΩ˾ΩԤʤ뤳ȤǤ롥 : ̾ vwait / tkwait Ǥϡvwait / tkwait (1) Ԥ : Ǥ vwait / tkwait (2) ƤФ줿硤Ԥо : ȤʤäƤΩɤ졤(2)->(1) νԤ : λäƤ롥 : _thread_vwait / _thread_tkwait ϡ٥ȥ롼פΥ : ɤǸƤФ줿̾ vwait / tkwait Ʊͤư : ٥ȥ롼װʳΥåɤǸƤФ줿ˤϤΥ : åɤߤԤꡤ郎Ω˥å : μ¹ԤƳ롥vwait ԤåȤΩפȤ : ̣ϡκƳΥߥ󥰤¾ΥåɤǤԤ : Ȥ̵طȤȤǤ롥Ĥޤꡤ٥ȥ롼¾ : Υåɤ vwait Ԥξ֤ˤäȤƤ⤽δλ : ԤĤȤʤԤ郎Ω衤³ : Ȥˤʤ롥 _return_value : ľ Tcl/Tk Ǥɾμ¹Է̤ȤƤ֤ͤ _get_variable(var_name, flag) _get_variable2(var_name, index_name, flag) : Tcl/Tk var Ȥѿ̾ѿ֤ͤ : ⤷ index_name (PARSE_VARNAME ե饰⻲) : 줿Ϣ var_name index_name Ǥ֤ : flag ˤѿ򸡺ݤξꤹ롥flag Ϳ : ͤϥ⥸塼 TclTkLib::VarAccessFlag 򻲾Ȥ뤳ȡ _set_variable(var_name, value, flag) _set_variable2(var_name, index_name, value, flag) : Tcl/Tk var Ȥѿ̾ѿͤꤹ롥 : ⤷ index_name (PARSE_VARNAME ե饰⻲) : 줿Ϣ var_name index_name Ǥ : 롥 : flag ˤѿ򸡺ݤξꤹ롥flag Ϳ : ͤϥ⥸塼 TclTkLib::VarAccessFlag 򻲾Ȥ뤳ȡ _unset_variable(var_name) _unset_variable2(var_name, index_name) : Tcl/Tk var_name Ȥѿ̾ѿõ롥 : ⤷ index_name (PARSE_VARNAME ե饰⻲) : 줿Ϣ var_name index_name Ǥ : õ롥 _get_global_var(var_name) _get_global_var2(var_name, index_name) _set_global_var(var_name, value) _set_global_var2(var_name, index_name, value) _unset_global_var(var_name) _unset_global_var2(var_name, index_name) : 줾졤бѿ᥽åɤ flag Ф : (GLOBAL_ONLY | LEAVE_ERR_MSG) ͿΡ _split_tklist(str) : Tcl/Tk Υ饤֥ؿȤäơʸ str ꥹȤ : ʬ䤹 (ʸȤ֤) _merge_tklist(str, str, ... ) : Tcl/Tk Υ饤֥ؿȤäơʸ󤬤줾 : ĤΥꥹǤȤʤ褦Ϣ뤷ʸ֤ _conv_listelement(str) : Tcl/Tk Υ饤֥ؿȤäơʸ Tcl : ĤΥꥹǤȤŬڤɽˤʤ褦Ѵʸ : ֤ mainloop mainloop_watchdog : 졼 IP ξˤϥ٥ȥ롼פư nil ֤ : ʳǤϰޤ TclTkLib Ʊ̾᥽åɤƱ do_one_event : 졼 IP ξˤϰΥ٥ȥե饰 DONT_WAIT : Ūɲä (٥Ԥǥ꡼פ뤳Ȥ϶ػ) : ʳǤϰޤ TclTkLib Ʊ̾᥽åɤƱ set_eventloop_tick get_eventloop_tick set_no_event_wait get_no_event_wait set_eventloop_weight get_eventloop_weight mainloop_abort_on_exception mainloop_abort_on_exception= : 졼 IP ξˤ꤬ͤʤ (̵뤵) : ʳǤϰޤ TclTkLib Ʊ̾᥽åɤƱ encoding_table : Ruby m17n Ѥ Ruby Tk Ȥδ֤ encoding бɽ֤ 饹 TkCallbackBreak < StandardError 饹 TkCallbackContinue < StandardError : ϥ٥ȥХåˤơХåŬڤ : ǤꡤΥХɥΥХǥ󥰽˿ʤ᤿ꤹ뤳 : ǽˤ뤿㳰饹Ǥ롥 : Хå break continue ¸뤿ˤϡХå : Ǥ Ruby ³ Tcl/Tk 󥿡ץ꥿¦Ŭڤʥ꥿󥳡 : ɤ֤ɬפ롥Ruby μ³̤֤ͤΤǤϡ줬 : ̤ͤǤΤݤ̤Ǥʤᡤ㳰ȯѤ : ԤäƤ롥 : ߤǤϡХå³ Ruby break, next ǽλ : 뤳ȤƱη̤뤳ȤǤ褦ˤʤäƤ롥椨 : ɬפʤΤǤϤ뤬ߴΤ˻ĤƤ롥 (eof) ================================================ FILE: ext/tk/README.1st ================================================ If you want to use Ruby/Tk (tk.rb and so on), you must have tcltklib.so which is working correctly. When you have some troubles on compiling, please read README.tcltklib and README.ActiveTcl. Even if there is a tcltklib.so on your Ruby library directry, it will not work without Tcl/Tk libraries (e.g. libtcl8.4.so) on your environment. You must also check that your Tcl/Tk is installed properly. -------------------------------------------- ( the following is written in EUC-JP ) Ruby/Tk (tk.rb ʤ) Ȥˤϡtcltklib.so ưƤ Фʤޤ󡥥ѥ˲꤬ϡREADME.tcltklib README.ActiveTcl 򸫤Ƥ Ȥ Ruby Υ饤֥ǥ쥯ȥ tcltklib.so ¸ߤƤȤ ⡤¹ԴĶ Tcl/Tk 饤֥ (libtcl8.4.so ʤ) ʤеǽ Tcl/Tk 󥹥ȡ뤵Ƥ뤫åƤ ========================================================== Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) ================================================ FILE: ext/tk/README.ActiveTcl ================================================ ActiveTcl is ActiveState's quality-assured distribution of Tcl. # see # If you want to use ActiveTcl binary package as the Tcl/Tk libraries, please use the following configure options. --with-tcl-dir= --with-tk-dir= And use the followings if you need. --with-tcllib= --with-tklib= --enable-tcltk-stubs For example, when you install ActiveTcl-8.4.x to '/usr/local/ActiveTcl', configure --with-tcl-dir=/usr/local/ActiveTcl/ \ --with-tk-dir=/usr/local/ActiveTcl/ \ --with-tcllib=tclstub8.4 \ --with-tklib=tkstub8.4 \ --enable-tcltk-stubs It depends on your environment that you have to add the directory of ActiveTcl's libraries to your library path when execute Ruby/Tk. One of the way is to add entries to TCLLIBPATH environment variable, and one of the others add to LD_LIBRARY_PATH environment variable Probably, using TCLLIBPATH is better. The value is appended at the head of Tcl's 'auto_path' variable. You can see the value of the variable by using 'Tk::AUTO_PATH.value' or 'Tk::AUTO_PATH.list'. For example, on Linux, one of the ways is to use LD_LIBRARY_PATH environment variable. ------------------------------------------------------------------------- [bash]$ LD_LIBRARY_PATH=/usr/local/ActiveTcl/lib:$LD_LIBRARY_PATH \ ruby your-Ruby/Tk-script [bash]$ LD_LIBRARY_PATH=/usr/local/ActiveTcl/lib:$LD_LIBRARY_PATH irb ------------------------------------------------------------------------- Based on it, the Tcl interpreter changes auto_path variable's value. Then, you'll be able to use Tcl/Tk extension libraries included in the ActiveTcl package (e.g. call TkPackage.require('BWidget'), and then, use functions/widgets of BWidget extention). Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) ================================================ FILE: ext/tk/README.fork ================================================ Ruby/Tk does NOT support forking the process on which Tk interpreter is running (unless NEVER control Tk interpreter under the forked child process). In the library 'tk.rb', a Tk interpreter is initialized. Therefore, if you want running Tk under a child process, please call "require 'tk'" in the child process. # If do fork and exec() on the child process, you can # control Ruby/Tk interpreter on the child process by 'send' command # of Tcl/Tk. About this, please see Tk.appsend and Tk.rb_appsend, or # 'remote-tk.rb' and the sample 'sample/remote-ip_sample.rb'. For example, the following sample1 will NOT work, and sample2 will work properly. ------------------------------------------ require 'tk' ## init Tk interpreter under parent process exit! if fork ## exit parent process ## child process TkButton.new(:text=>'QUIT', :command=>proc{exit}).pack Tk.mainloop ------------------------------------------------------------- ----------------------------------------- exit! if fork ## exit main process ## child process require 'tk' ## init Tk interpreter under child process TkButton.new(:text=>'QUIT', :command=>proc{exit}).pack Tk.mainloop ------------------------------------------------------------- 2004/05/22 Hidetoshi NAGAI ================================================ FILE: ext/tk/README.macosx-aqua ================================================ *** for MacOS X Aqua (Tcl/Tk Aqua) users *** First of all, please read README.tcltklib to use Tcl/Tk Aqua Framework. With Tcl/Tk Aqua libraries, current tcltklib somtimes freezes when using Aqua specific dialogs (e.g. Tk.messageBox). This is a known bug of Ruby-1.8.4 release. When you meet the trouble on your GUI, you'll be able to avoid the trouble by Tcl/Tk's traditional dialogs. If you want to do that, please call some of the following bits of script after "reqruie 'tk'". ================================================================= # use a traditional dialog for Tk.chooseColor() Tk.ip_eval(<<'EOS') proc ::tk_chooseColor {args} { return [eval tk::dialog::color:: $args] } EOS # use a traditional dialog for Tk.getOpenFile() and Tk.getMultipleOpenFile() Tk.ip_eval(<<'EOS') proc ::tk_getOpenFile {args} { if {$::tk_strictMotif} { return [eval tk::MotifFDialog open $args] } else { return [eval ::tk::dialog::file:: open $args] } } EOS # use a traditional dialog for Tk.getSaveFile() and Tk.getMultipleSaveFile() Tk.ip_eval(<<'EOS') proc ::tk_getSaveFile {args} { if {$::tk_strictMotif} { return [eval tk::MotifFDialog save $args] } else { return [eval ::tk::dialog::file:: save $args] } } EOS # use a traditional dialog for Tk.messageBox() Tk.ip_eval(<<'EOS') proc ::tk_messageBox {args} { return [eval tk::MessageBox $args] } EOS # use a traditional dialog for Tk.chooseDirectory() Tk.ip_eval(<<'EOS') proc ::tk_chooseDirectory {args} { return [eval ::tk::dialog::file::chooseDir:: $args] } EOS ================================================================= Each of them replaces the platform specific dialog command to the traditional one. If you use some MultiTkIp objects, probably, you'll have to call the bits of script for each MultiTkIp object. -- Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) ================================================ FILE: ext/tk/README.tcltklib ================================================ To compile 'tcltklib', you must have Tcl/Tk libraries on your environment. Although 'extconf.rb' script searches Tcl/Tk libraries and header files, sometimes fails to find them. And then, 'tcltklib' cannot be compiled. If Tcl/Tk libraries or header files are installed but are not found, you can give the information by arguments of the 'configure' script. Please give some or all of the following options. --with-tcltkversion= force version of Tcl/Tk libaray (e.g. libtcl8.4g.so ==> --with-tcltkversion=8.4g) --with-tcllib= (e.g. libtcl8.4.so ==> --with-tcllib=tcl8.4) --with-tklib= (e.g. libtk8.4.so ==> --with-tklib=tk8.4) --enable-tcltk-stubs (if you force to enable stubs) --with-tcl-dir= equal to "--with-tcl-include=/include --with-tcl-lib=/lib" --with-tk-dir= equal to "--with-tk-include=/include --with-tk-lib=/lib" --with-tcl-include= the directry contains 'tcl.h' --with-tk-include= the directry contains 'tk.h' --with-tcl-lib= the directry contains 'libtcl.so' --with-tk-lib= the directry contains 'libtk.so' --enable-mac-tcltk-framework (MacOS X) use Tcl/Tk framework (Obsolete. Please use '--enable-tcltk-framework'.) --enable-tcltk-framework use Tcl/Tk framework --with-tcltk-framework= the directory contains Tcl/Tk framework; "/Tcl.framework" and "/Tk.framework". When this option is given, it is assumed that --enable-tcltk-framework option is given also. --with-tcl-framework-header= Tcl framework headers directory (e.g. "/Library/Frameworks/Tcl.framework/Headers") --with-tk-framework-header= Tk framework headers directory (e.g. "/Library/Frameworks/Tk.framework/Headers") --with-X11 / --without-X11 use / not use the X Window System --with-X11-dir= equal to "--with-X11-include=/include --with-X11-lib=/lib" --with-X11-include= the directry contais X11 header files --with-X11-lib= the directry contais X11 libraries If you forgot to give the options when do 'configure' on toplevel directry of Ruby sources, please try something like as the followings. $ cd ext/tcltklib $ rm Makefile $ CONFIGURE_ARGS='--with-tcl-include=/usr/local/include/tcl8.4/ --with-tcllib=tcl8.4 --with-tklib=tk8.4' ruby extconf.rb *** ATTENTION *** When your Tcl/Tk libraries are compiled with "pthread support", Ruby/Tk may cause "Hang-up" or "Segmentation Fault" frequently. If you have such a trouble, please try to use the '--enable-pthread' option of the 'configure' command and re-compile Ruby sources. It may help you to avoid this trouble. The following configure options may be useful. --enable-tcl-thread/--disable-tcl-thread --with-tclConfig-file= It is not need that 'tclConfig.sh' is a normal Tcl/Tk's tclConfig.sh. But the file is expected to include the line "TCL_THREADS=0" or "...=1". When no "TCL_THREADS=?" line, if Tcl version is 7.x or 8.0 which is given by "TCL_MAJOR_VERSION=?" line and "TCL_MINOR_VERSION=?" line, then --disable-tcl-thread is expected. Else, ignore the 'tclConfig.sh'. If --enable-tcl-thread or --disable-tcl-thread option is given, then --with-tclConfig-file option is ignored. ========================================================== Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) ================================================ FILE: ext/tk/depend ================================================ tcltklib.o: tcltklib.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h stubs.o: stubs.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h ================================================ FILE: ext/tk/extconf.rb ================================================ # extconf.rb for tcltklib require 'mkmf' #is_win32 = (/mswin32|mingw|cygwin|bccwin32/ =~ RUBY_PLATFORM) is_win32 = (/mswin|mingw|cygwin|bccwin|wince/ =~ RUBY_PLATFORM) #is_macosx = (/darwin/ =~ RUBY_PLATFORM) def find_framework(tcl_hdr, tk_hdr) if framework_dir = with_config("tcltk-framework") paths = [framework_dir] else unless tcl_hdr || tk_hdr || enable_config("tcltk-framework", false) || enable_config("mac-tcltk-framework", false) return false end paths = ["/Library/Frameworks", "/System/Library/Frameworks"] end checking_for('Tcl/Tk Framework') { paths.find{|dir| dir.strip! dir.chomp!('/') (tcl_hdr || FileTest.directory?(dir + "/Tcl.framework/") ) && (tk_hdr || FileTest.directory?(dir + "/Tk.framework/") ) } } end tcl_framework_header = with_config("tcl-framework-header") tk_framework_header = with_config("tk-framework-header") tcltk_framework = find_framework(tcl_framework_header, tk_framework_header) unless is_win32 have_library("nsl", "t_open") have_library("socket", "socket") have_library("dl", "dlopen") have_library("m", "log") end tk_idir, tk_ldir = dir_config("tk") tcl_idir, tcl_ldir = dir_config("tcl") x11_idir, x11_ldir = dir_config("X11") tk_ldir2 = with_config("tk-lib") tcl_ldir2 = with_config("tcl-lib") x11_ldir2 = with_config("X11-lib") tk_ldir_list = [tk_ldir2, tk_ldir] tcl_ldir_list = [tcl_ldir2, tcl_ldir] tklib = with_config("tklib") tcllib = with_config("tcllib") stubs = enable_config("tcltk_stubs") || with_config("tcltk_stubs") tcltk_version = with_config("tcltkversion") use_X = with_config("X11", (! is_win32)) def check_tcltk_version(version) return [nil, nil] unless version version = version.strip tclver = version.dup tkver = version.dup major = dot = minor = dot = plvl = ext = nil if version =~ /^(\d)(\.?)(\d)(\.?)(\d*)(.*)$/ major = $1; minor_dot = $2; minor = $3; plvl_dot = $4; plvl = $5; ext = $6 dot = ! minor_dot.empty? if plvl_dot.empty? && ! plvl.empty? minor << plvl end elsif version =~ /^(\d)(\.?)(\d?)(.*)$/ major = $1; minor_dot = $2; minor = $3; ext = $4 dot = ! minor_dot.empty? else # unknown -> believe user return [tclver, tkver] end # check Tcl7.6 / Tk4.2 ? if major == "7" # Tcl7.6 ( not support Tclversion < 7.6 ) # Tk4.2 tkver = "4" + ((dot)? ".": "") + ((minor.empty)? "": "2") + ext elsif major == "4" # Tk4.2 ( not support Tkversion < 4.2 ) # Tcl7.6 tclver = "7" + ((dot)? ".": "") + ((minor.empty)? "": "6") + ext end [tclver, tkver] end def find_tcl(tcllib, stubs, version, *opt_paths) default_paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"] default_paths << "/Tcl/lib" # default for ActiveTcl if (paths = opt_paths.compact).empty? paths = default_paths end if stubs func = "Tcl_InitStubs" lib = "tclstub" else func = "Tcl_FindExecutable" lib = "tcl" end if version && ! version.empty? versions = [version] else versions = %w[8.6 8.5 8.4 8.3 8.2 8.1 8.0 7.6] end if tcllib st = find_library(tcllib, func, *paths) else st = versions.find { |ver| find_library("#{lib}#{ver}", func, *paths) or find_library("#{lib}#{ver.delete('.')}", func, *paths) or find_library("#{lib}#{ver}g", func, *paths) or find_library("#{lib}#{ver.delete('.')}g", func, *paths) or find_library("tcl#{ver}", func, *paths) or find_library("tcl#{ver.delete('.')}", func, *paths) or find_library("tcl#{ver}g", func, *paths) or find_library("tcl#{ver.delete('.')}g", func, *paths) } || (!version && find_library(lib, func, *paths)) end unless st puts("Warning:: cannot find Tcl library. tcltklib will not be compiled (tcltklib is disabled on your Ruby == Ruby/Tk will not work). Please check configure options.") end st end def find_tk(tklib, stubs, version, *opt_paths) default_paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"] default_paths << "/Tcl/lib" # default for ActiveTcl if (paths = opt_paths.compact).empty? paths = default_paths end if stubs func = "Tk_InitStubs" lib = "tkstub" else func = "Tk_Init" lib = "tk" end if version && ! version.empty? versions = [version] else versions = %w[8.6 8.5 8.4 8.3 8.2 8.1 8.0 4.2] end if tklib st = find_library(tklib, func, *paths) else st = versions.find { |ver| find_library("#{lib}#{ver}", func, *paths) or find_library("#{lib}#{ver.delete('.')}", func, *paths) or find_library("#{lib}#{ver}g", func, *paths) or find_library("#{lib}#{ver.delete('.')}g", func, *paths) or find_library("tk#{ver}", func, *paths) or find_library("tk#{ver.delete('.')}", func, *paths) or find_library("tk#{ver}g", func, *paths) or find_library("tk#{ver.delete('.')}g", func, *paths) } || (!version && find_library(lib, func, *paths)) end unless st puts("Warning:: cannot find Tk library. tcltklib will not be compiled (tcltklib is disabled on your Ruby == Ruby/Tk will not work). Please check configure options.") end st end def find_X11(*opt_paths) default_paths = [ "/usr/X11/lib", "/usr/lib/X11", "/usr/X11R6/lib", "/usr/openwin/lib" ] paths = opt_paths.compact.concat(default_paths) st = find_library("X11", "XOpenDisplay", *paths) unless st puts("Warning:: cannot find X11 library. tcltklib will not be compiled (tcltklib is disabled on your Ruby == Ruby/Tk will not work). Please check configure options. If your Tcl/Tk don't require X11, please try --without-X11.") end st end def pthread_check() tcl_major_ver = nil tcl_minor_ver = nil # Is tcl-thread given by user ? case enable_config("tcl-thread") when true tcl_enable_thread = true when false tcl_enable_thread = false else tcl_enable_thread = nil end if (tclConfig = with_config("tclConfig-file")) if tcl_enable_thread == true puts("Warning: --with-tclConfig-file option is ignored, because --enable-tcl-thread option is given.") elsif tcl_enable_thread == false puts("Warning: --with-tclConfig-file option is ignored, because --disable-tcl-thread option is given.") else # tcl-thread is unknown and tclConfig.sh is given begin open(tclConfig, "r") do |cfg| while line = cfg.gets() if line =~ /^\s*TCL_THREADS=(0|1)/ tcl_enable_thread = ($1 == "1") break end if line =~ /^\s*TCL_MAJOR_VERSION=("|')(\d+)\1/ tcl_major_ver = $2 if tcl_major_ver =~ /^[1-7]$/ tcl_enable_thread = false break end if tcl_major_ver == "8" && tcl_minor_ver == "0" tcl_enable_thread = false break end end if line =~ /^\s*TCL_MINOR_VERSION=("|')(\d+)\1/ tcl_minor_ver = $2 if tcl_major_ver == "8" && tcl_minor_ver == "0" tcl_enable_thread = false break end end end end if tcl_enable_thread == nil # not find definition if tcl_major_ver puts("Warning: '#{tclConfig}' doesn't include TCL_THREADS definition.") else puts("Warning: '#{tclConfig}' may not be a tclConfig file.") end tclConfig = false end rescue Exception puts("Warning: fail to read '#{tclConfig}'!! --> ignore the file") tclConfig = false end end end if tcl_enable_thread == nil && !tclConfig # tcl-thread is unknown and tclConfig is unavailable begin try_run_available = try_run("int main() { exit(0); }") rescue Exception # cannot try_run. Is CROSS-COMPILE environment? puts(%Q'\ ***************************************************************************** ** ** PTHREAD SUPPORT CHECK WARNING: ** ** We cannot check the consistency of pthread support between Ruby ** and the Tcl/Tk library in your environment (are you perhaps ** cross-compiling?). If pthread support for these 2 packages is ** inconsistent you may find you get errors when running Ruby/Tk ** (e.g. hangs or segmentation faults). We strongly recommend ** you to check the consistency manually. ** ***************************************************************************** ') return true end end if tcl_enable_thread == nil # tcl-thread is unknown if try_run(< int main() { Tcl_Interp *ip; ip = Tcl_CreateInterp(); exit((Tcl_Eval(ip, "set tcl_platform(threaded)") == TCL_OK)? 0: 1); } EOF tcl_enable_thread = true elsif try_run(< static Tcl_ThreadDataKey dataKey; int main() { exit((Tcl_GetThreadData(&dataKey, 1) == dataKey)? 1: 0); } EOF tcl_enable_thread = true else tcl_enable_thread = false end end # check pthread mode if (macro_defined?('HAVE_NATIVETHREAD', '#include "ruby.h"')) # ruby -> enable unless tcl_enable_thread # ruby -> enable && tcl -> disable puts(%Q'\ ***************************************************************************** ** ** PTHREAD SUPPORT MODE WARNING: ** ** Ruby is compiled with --enable-pthread, but your Tcl/Tk library ** seems to be compiled without pthread support. Although you can ** create the tcltklib library, this combination may cause errors ** (e.g. hangs or segmentation faults). If you have no reason to ** keep the current pthread support status, we recommend you reconfigure ** and recompile the libraries so that both or neither support pthreads. ** ** If you want change the status of pthread support, please recompile ** Ruby without "--enable-pthread" configure option or recompile Tcl/Tk ** with "--enable-threads" configure option (if your Tcl/Tk is later ** than or equal to Tcl/Tk 8.1). ** ***************************************************************************** ') end # ruby -> enable && tcl -> enable/disable if tcl_enable_thread $CPPFLAGS += ' -DWITH_TCL_ENABLE_THREAD=1' else $CPPFLAGS += ' -DWITH_TCL_ENABLE_THREAD=0' end return true else # ruby -> disable if tcl_enable_thread # ruby -> disable && tcl -> enable puts(%Q'\ ***************************************************************************** ** ** PTHREAD SUPPORT MODE ERROR: ** ** Ruby is not compiled with --enable-pthread, but your Tcl/Tk ** library seems to be compiled with pthread support. This ** combination may cause frequent hang or segmentation fault ** errors when Ruby/Tk is working. We recommend that you NEVER ** create the library with such a combination of pthread support. ** ** Please recompile Ruby with the "--enable-pthread" configure option ** or recompile Tcl/Tk with the "--disable-threads" configure option. ** ***************************************************************************** ') $CPPFLAGS += ' -DWITH_TCL_ENABLE_THREAD=1' return false else # ruby -> disable && tcl -> disable $CPPFLAGS += ' -DWITH_TCL_ENABLE_THREAD=0' return true end end end tclver, tkver = check_tcltk_version(tcltk_version) if have_header("tcl.h") && have_header("tk.h") && ( tcltk_framework || ( ( !use_X || find_X11(x11_ldir2, x11_ldir) ) && find_tcl(tcllib, stubs, tclver, *tcl_ldir_list) && find_tk(tklib, stubs, tkver, *tk_ldir_list) ) ) $CPPFLAGS += ' -DUSE_TCL_STUBS -DUSE_TK_STUBS' if stubs $CPPFLAGS += ' -D_WIN32' if /cygwin/ =~ RUBY_PLATFORM if tcltk_framework if tcl_framework_header $CPPFLAGS += " -I#{tcl_framework_header}" else $CPPFLAGS += " -I#{tcltk_framework}/Tcl.framework/Headers" end if tk_framework_header $CPPFLAGS += " -I#{tk_framework_header}" else $CPPFLAGS += " -I#{tcltk_framework}/Tk.framework/Headers" end $LDFLAGS += ' -framework Tk -framework Tcl' end if stubs or pthread_check # create Makefile # for SUPPORT_STATUS $INSTALLFILES ||= [] $INSTALLFILES << ["lib/tkextlib/SUPPORT_STATUS", "$(RUBYLIBDIR)", "lib"] have_func("rb_hash_lookup", "ruby.h") # create $defs << %[-DRUBY_VERSION=\\"#{RUBY_VERSION}\\"] $defs << %[-DRUBY_RELEASE_DATE=\\"#{RUBY_RELEASE_DATE}\\"] create_makefile("tcltklib") end end ================================================ FILE: ext/tk/lib/README ================================================ README this file multi-tk.rb multiple Tk interpreter (included safe-Tk) support remotei-tk.rb control remote Tk interpreter on the other process support tk.rb Tk interface tk/ library files construct Ruby/Tk tkextlib/ non-standard Tcl/Tk extension support libraries ********************************************************************* *** The followings exists for backward compatibility only. *** The only thing which they work is that requires current *** library files ( tk/*.rb ). ********************************************************************* tkafter.rb handles Tcl after tkbgerror.rb Tk error module tkcanvas.rb Tk canvas interface tkclass.rb provides generic names for Tk classes tkconsole.rb console command support tkdialog.rb Tk dialog class tkentry.rb Tk entry class tkfont.rb Tk font support tkmacpkg.rb Mac resource support tkmenubar.rb TK menubar utility tkmngfocus.rb focus manager tkpalette.rb pallete support tkscrollbox.rb scroll box, also example of compound widget tktext.rb text classes tkvirtevent.rb virtual event support tkwinpkg.rb Win DDE and registry support ================================================ FILE: ext/tk/lib/multi-tk.rb ================================================ # # multi-tk.rb - supports multi Tk interpreters # by Hidetoshi NAGAI require 'tcltklib' require 'tkutil' require 'thread' if defined? Tk fail RuntimeError,"'multi-tk' library must be required before requiring 'tk'" end ################################################ # ignore exception on the mainloop? TclTkLib.mainloop_abort_on_exception = true # TclTkLib.mainloop_abort_on_exception = false # TclTkLib.mainloop_abort_on_exception = nil ################################################ # add ThreadGroup check to TclTkIp.new class << TclTkIp alias __new__ new private :__new__ def new(*args) if Thread.current.group != ThreadGroup::Default raise SecurityError, 'only ThreadGroup::Default can call TclTkIp.new' end __new__(*args) end end ################################################ # use pseudo-toplevel feature of MultiTkIp ? if (!defined?(Use_PseudoToplevel_Feature_of_MultiTkIp) || Use_PseudoToplevel_Feature_of_MultiTkIp) module MultiTkIp_PseudoToplevel_Evaluable #def pseudo_toplevel_eval(body = Proc.new) # Thread.current[:TOPLEVEL] = self # begin # body.call # ensure # Thread.current[:TOPLEVEL] = nil # end #end def pseudo_toplevel_evaluable? @pseudo_toplevel_evaluable end def pseudo_toplevel_evaluable=(mode) @pseudo_toplevel_evaluable = (mode)? true: false end def self.extended(mod) mod.__send__(:extend_object, mod) mod.instance_variable_set('@pseudo_toplevel_evaluable', true) end end class Object alias __method_missing_alias_for_MultiTkIp__ method_missing private :__method_missing_alias_for_MultiTkIp__ def method_missing(id, *args) begin has_top = (top = MultiTkIp.__getip.__pseudo_toplevel) && top.respond_to?(:pseudo_toplevel_evaluable?) && top.pseudo_toplevel_evaluable? && top.respond_to?(id) rescue Exception => e has_top = false end if has_top top.__send__(id, *args) else __method_missing_alias_for_MultiTkIp__(id, *args) end end end else # dummy module MultiTkIp_PseudoToplevel_Evaluable def pseudo_toplevel_evaluable? false end end end ################################################ # exceptiopn to treat the return value from IP class MultiTkIp_OK < Exception def self.send(thread, ret=nil) thread.raise self.new(ret) end def initialize(ret=nil) super('succeed') @return_value = ret end attr_reader :return_value alias value return_value end MultiTkIp_OK.freeze ################################################ # methods for construction class MultiTkIp BASE_DIR = File.dirname(__FILE__) WITH_RUBY_VM = Object.const_defined?(:VM) && ::VM.class == Class WITH_ENCODING = Object.const_defined?(:Encoding) && ::Encoding.class == Class (@@SLAVE_IP_ID = ['slave'.freeze, '0'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } @@IP_TABLE = {}.taint unless defined?(@@IP_TABLE) @@INIT_IP_ENV = [].taint unless defined?(@@INIT_IP_ENV) # table of Procs @@ADD_TK_PROCS = [].taint unless defined?(@@ADD_TK_PROCS) # table of [name, args, body] @@TK_TABLE_LIST = [].taint unless defined?(@@TK_TABLE_LIST) unless defined?(@@TK_CMD_TBL) @@TK_CMD_TBL = Object.new.taint # @@TK_CMD_TBL.instance_variable_set('@tbl', {}.taint) @@TK_CMD_TBL.instance_variable_set('@tbl', Hash.new{|hash,key| fail IndexError, "unknown command ID '#{key}'" }.taint) class << @@TK_CMD_TBL allow = [ '__send__', '__id__', 'freeze', 'inspect', 'kind_of?', 'object_id', '[]', '[]=', 'delete', 'each', 'has_key?' ] instance_methods.each{|m| undef_method(m) unless allow.index(m.to_s)} def kind_of?(klass) @tbl.kind_of?(klass) end def inspect if Thread.current.group == ThreadGroup::Default @tbl.inspect else ip = MultiTkIp.__getip @tbl.reject{|idx, ent| ent.respond_to?(:ip) && ent.ip != ip}.inspect end end def [](idx) return unless (ent = @tbl[idx]) if Thread.current.group == ThreadGroup::Default ent elsif ent.respond_to?(:ip) (ent.ip == MultiTkIp.__getip)? ent: nil else ent end end def []=(idx,val) if self.has_key?(idx) && Thread.current.group != ThreadGroup::Default fail SecurityError,"cannot change the entried command" end @tbl[idx] = val end def delete(idx, &blk) # if gets an entry, is permited to delete if self[idx] @tbl.delete(idx) elsif blk blk.call(idx) else nil end end def each(&blk) if Thread.current.group == ThreadGroup::Default @tbl.each(&blk) else ip = MultiTkIp.__getip @tbl.each{|idx, ent| blk.call(idx, ent) unless ent.respond_to?(:ip) && ent.ip != ip } end self end def has_key?(k) @tbl.has_key?(k) end alias include? has_key? alias key? has_key? alias member? has_key? end @@TK_CMD_TBL.freeze end ###################################### @@CB_ENTRY_CLASS = Class.new(TkCallbackEntry){ def initialize(ip, cmd) @ip = ip @cmd = cmd self.freeze end attr_reader :ip, :cmd def inspect cmd.inspect end def call(*args) unless @ip.deleted? current = Thread.current backup_ip = current['callback_ip'] current['callback_ip'] = @ip begin ret = @ip.cb_eval(@cmd, *args) fail ret if ret.kind_of?(Exception) ret rescue TkCallbackBreak, TkCallbackContinue => e fail e rescue SecurityError => e # in 'exit', 'exit!', and 'abort' : security error --> delete IP if e.backtrace[0] =~ /^(.+?):(\d+):in `(exit|exit!|abort)'/ @ip.delete elsif @ip.safe? if @ip.respond_to?(:cb_error) @ip.cb_error(e) else nil # ignore end else fail e end rescue Exception => e fail e if e.message =~ /^TkCallback/ if @ip.safe? if @ip.respond_to?(:cb_error) @ip.cb_error(e) else nil # ignore end else fail e end ensure current['callback_ip'] = backup_ip end end end }.freeze ###################################### def _keys2opts(src_keys) return nil if src_keys == nil keys = {}; src_keys.each{|k, v| keys[k.to_s] = v} #keys.collect{|k,v| "-#{k} #{v}"}.join(' ') keys.collect{|k,v| "-#{k} #{TclTkLib._conv_listelement(TkComm::_get_eval_string(v))}"}.join(' ') end private :_keys2opts def _check_and_return(thread, exception, wait=0) unless thread unless exception.kind_of?(MultiTkIp_OK) msg = "#{exception.class}: #{exception.message}" if @interp.deleted? warn("Warning (#{self}): " + msg) return nil end if safe? warn("Warning (#{self}): " + msg) if $DEBUG return nil end begin @interp._eval_without_enc(@interp._merge_tklist('bgerror', msg)) rescue Exception => e warn("Warning (#{self}): " + msg) end end return nil end if wait == 0 # no wait Thread.pass if thread.stop? thread.raise exception end return thread end # wait to stop the caller thread wait.times{ if thread.stop? # ready to send exception thread.raise exception return thread end # wait Thread.pass } # unexpected error thread.raise RuntimeError, "the thread may not wait for the return value" return thread end ###################################### def set_cb_error(cmd = Proc.new) @cb_error_proc[0] = cmd end def cb_error(e) if @cb_error_proc[0].respond_to?(:call) @cb_error_proc[0].call(e) end end ###################################### def set_safe_level(safe) if safe > @safe_level[0] @safe_level[0] = safe @cmd_queue.enq([@system, 'set_safe_level', safe]) end @safe_level[0] end def safe_level=(safe) set_safe_level(safe) end def self.set_safe_level(safe) __getip.set_safe_level(safe) end def self.safe_level=(safe) self.set_safe_level(safe) end def safe_level @safe_level[0] end def self.safe_level __getip.safe_level end def wait_on_mainloop? @wait_on_mainloop[0] end def wait_on_mainloop=(bool) @wait_on_mainloop[0] = bool end def running_mainloop? @wait_on_mainloop[1] > 0 end def _destroy_slaves_of_slaveIP(ip) unless ip.deleted? # ip._split_tklist(ip._invoke('interp', 'slaves')).each{|name| ip._split_tklist(ip._invoke_without_enc('interp', 'slaves')).each{|name| name = _fromUTF8(name) begin # ip._eval_without_enc("#{name} eval {foreach i [after info] {after cancel $i}}") after_ids = ip._eval_without_enc("#{name} eval {after info}") ip._eval_without_enc("#{name} eval {foreach i {#{after_ids}} {after cancel $i}}") rescue Exception end begin # ip._invoke('interp', 'eval', name, 'destroy', '.') ip._invoke(name, 'eval', 'destroy', '.') rescue Exception end # safe_base? if ip._eval_without_enc("catch {::safe::interpConfigure #{name}}") == '0' begin ip._eval_without_enc("::safe::interpDelete #{name}") rescue Exception end end =begin if ip._invoke('interp', 'exists', name) == '1' begin ip._invoke(name, 'eval', 'exit') rescue Exception end end =end unless ip.deleted? if ip._invoke('interp', 'exists', name) == '1' begin ip._invoke('interp', 'delete', name) rescue Exception end end end } end end def _receiver_eval_proc_core(safe_level, thread, cmd, *args) begin #ret = proc{$SAFE = safe_level; cmd.call(*args)}.call #ret = cmd.call(safe_level, *args) normal_ret = false ret = catch(:IRB_EXIT) do # IRB hack retval = cmd.call(safe_level, *args) normal_ret = true retval end unless normal_ret # catch IRB_EXIT exit(ret) end ret rescue SystemExit => e # delete IP unless @interp.deleted? @slave_ip_tbl.each{|name, subip| _destroy_slaves_of_slaveIP(subip) begin # subip._eval_without_enc("foreach i [after info] {after cancel $i}") after_ids = subip._eval_without_enc("after info") subip._eval_without_enc("foreach i {#{after_ids}} {after cancel $i}") rescue Exception end =begin begin subip._invoke('destroy', '.') unless subip.deleted? rescue Exception end =end # safe_base? if @interp._eval_without_enc("catch {::safe::interpConfigure #{name}}") == '0' begin @interp._eval_without_enc("::safe::interpDelete #{name}") rescue Exception else next if subip.deleted? end end if subip.respond_to?(:safe_base?) && subip.safe_base? && !subip.deleted? # do 'exit' to call the delete_hook procedure begin subip._eval_without_enc('exit') rescue Exception end else begin subip.delete unless subip.deleted? rescue Exception end end } begin # @interp._eval_without_enc("foreach i [after info] {after cancel $i}") after_ids = @interp._eval_without_enc("after info") @interp._eval_without_enc("foreach i {#{after_ids}} {after cancel $i}") rescue Exception end begin @interp._invoke('destroy', '.') unless @interp.deleted? rescue Exception end if @safe_base && !@interp.deleted? # do 'exit' to call the delete_hook procedure @interp._eval_without_enc('exit') else @interp.delete unless @interp.deleted? end end if e.backtrace[0] =~ /^(.+?):(\d+):in `(exit|exit!|abort)'/ _check_and_return(thread, MultiTkIp_OK.new($3 == 'exit')) else _check_and_return(thread, MultiTkIp_OK.new(nil)) end # if master? && !safe? && allow_ruby_exit? if !@interp.deleted? && master? && !safe? && allow_ruby_exit? =begin ObjectSpace.each_object(TclTkIp){|obj| obj.delete unless obj.deleted? } =end #exit(e.status) fail e end # break rescue SecurityError => e # in 'exit', 'exit!', and 'abort' : security error --> delete IP if e.backtrace[0] =~ /^(.+?):(\d+):in `(exit|exit!|abort)'/ ret = ($3 == 'exit') unless @interp.deleted? @slave_ip_tbl.each{|name, subip| _destroy_slaves_of_slaveIP(subip) begin # subip._eval_without_enc("foreach i [after info] {after cancel $i}") after_ids = subip._eval_without_enc("after info") subip._eval_without_enc("foreach i {#{after_ids}} {after cancel $i}") rescue Exception end =begin begin subip._invoke('destroy', '.') unless subip.deleted? rescue Exception end =end # safe_base? if @interp._eval_without_enc("catch {::safe::interpConfigure #{name}}") == '0' begin @interp._eval_without_enc("::safe::interpDelete #{name}") rescue Exception else next if subip.deleted? end end if subip.respond_to?(:safe_base?) && subip.safe_base? && !subip.deleted? # do 'exit' to call the delete_hook procedure begin subip._eval_without_enc('exit') rescue Exception end else begin subip.delete unless subip.deleted? rescue Exception end end } begin # @interp._eval_without_enc("foreach i [after info] {after cancel $i}") after_ids = @interp._eval_without_enc("after info") @interp._eval_without_enc("foreach i {#{after_ids}} {after cancel $i}") rescue Exception end =begin begin @interp._invoke('destroy', '.') unless @interp.deleted? rescue Exception end =end if @safe_base && !@interp.deleted? # do 'exit' to call the delete_hook procedure @interp._eval_without_enc('exit') else @interp.delete unless @interp.deleted? end end _check_and_return(thread, MultiTkIp_OK.new(ret)) # break else # raise security error _check_and_return(thread, e) end rescue Exception => e # raise exception begin bt = _toUTF8(e.backtrace.join("\n")) if MultiTkIp::WITH_ENCODING bt.force_encoding('utf-8') else bt.instance_variable_set(:@encoding, 'utf-8') end rescue Exception bt = e.backtrace.join("\n") end begin @interp._set_global_var('errorInfo', bt) rescue Exception end _check_and_return(thread, e) else # no exception _check_and_return(thread, MultiTkIp_OK.new(ret)) end end def _receiver_eval_proc(last_thread, safe_level, thread, cmd, *args) if thread Thread.new{ last_thread.join if last_thread unless @interp.deleted? _receiver_eval_proc_core(safe_level, thread, cmd, *args) end } else Thread.new{ unless @interp.deleted? _receiver_eval_proc_core(safe_level, thread, cmd, *args) end } last_thread end end private :_receiver_eval_proc, :_receiver_eval_proc_core def _receiver_mainloop(check_root) if @evloop_thread[0] && @evloop_thread[0].alive? @evloop_thread[0] else @evloop_thread[0] = Thread.new{ while !@interp.deleted? #if check_root # inf = @interp._invoke_without_enc('info', 'command', '.') # break if !inf.kind_of?(String) || inf != '.' #end break if check_root && !@interp.has_mainwindow? sleep 0.5 end } @evloop_thread[0] end end def _create_receiver_and_watchdog(lvl = $SAFE) lvl = $SAFE if lvl < $SAFE # command-procedures receiver receiver = Thread.new(lvl){|safe_level| last_thread = {} loop do break if @interp.deleted? thread, cmd, *args = @cmd_queue.deq if thread == @system # control command case cmd when 'set_safe_level' begin safe_level = args[0] if safe_level < args[0] rescue Exception end when 'call_mainloop' thread = args.shift _check_and_return(thread, MultiTkIp_OK.new(_receiver_mainloop(*args))) else # ignore end else # procedure last_thread[thread] = _receiver_eval_proc(last_thread[thread], safe_level, thread, cmd, *args) end end } # watchdog of receiver watchdog = Thread.new{ begin loop do sleep 1 receiver.kill if @interp.deleted? break unless receiver.alive? end rescue Exception # ignore all kind of Exception end # receiver is dead loop do thread, cmd, *args = @cmd_queue.deq next unless thread if thread.alive? if @interp.deleted? thread.raise RuntimeError, 'the interpreter is already deleted' else thread.raise RuntimeError, 'the interpreter no longer receives command procedures' end end end } # return threads [receiver, watchdog] end private :_check_and_return, :_create_receiver_and_watchdog ###################################### unless self.const_defined? :RUN_EVENTLOOP_ON_MAIN_THREAD ### Ruby 1.9 !!!!!!!!!!!!!!!!!!!!!!!!!! RUN_EVENTLOOP_ON_MAIN_THREAD = false end if self.const_defined? :DEFAULT_MASTER_NAME name = DEFAULT_MASTER_NAME.to_s else name = nil end if self.const_defined?(:DEFAULT_MASTER_OPTS) && DEFAULT_MASTER_OPTS.kind_of?(Hash) keys = DEFAULT_MASTER_OPTS else keys = {} end @@DEFAULT_MASTER = self.allocate @@DEFAULT_MASTER.instance_eval{ @tk_windows = {}.taint @tk_table_list = [].taint @slave_ip_tbl = {}.taint @slave_ip_top = {}.taint @evloop_thread = [].taint unless keys.kind_of? Hash fail ArgumentError, "expecting a Hash object for the 2nd argument" end if !WITH_RUBY_VM || RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!! @interp = TclTkIp.new(name, _keys2opts(keys)) else ### Ruby 1.9 !!!!!!!!!!! @interp_thread = Thread.new{ current = Thread.current current[:interp] = interp = TclTkIp.new(name, _keys2opts(keys)) #sleep current[:mutex] = mutex = Mutex.new current[:root_check] = cond_var = ConditionVariable.new begin current[:status] = interp.mainloop(true) rescue Exception=>e current[:status] = e ensure mutex.synchronize{ cond_var.broadcast } end current[:status] = interp.mainloop(false) } until @interp_thread[:interp] Thread.pass end # INTERP_THREAD.run @interp = @interp_thread[:interp] def self.mainloop(check_root = true) begin TclTkLib.set_eventloop_window_mode(true) @interp_thread.value ensure TclTkLib.set_eventloop_window_mode(false) end end end @ip_name = nil @callback_status = [].taint @system = Object.new @wait_on_mainloop = [true, 0].taint @threadgroup = Thread.current.group @safe_base = false @safe_level = [$SAFE] @cmd_queue = Queue.new @cmd_receiver, @receiver_watchdog = _create_receiver_and_watchdog(@safe_level[0]) @threadgroup.add @cmd_receiver @threadgroup.add @receiver_watchdog # NOT enclose @threadgroup for @@DEFAULT_MASTER @@IP_TABLE[ThreadGroup::Default] = self @@IP_TABLE[@threadgroup] = self ################################# @pseudo_toplevel = [false, nil] def self.__pseudo_toplevel Thread.current.group == ThreadGroup::Default && MultiTkIp.__getip == @@DEFAULT_MASTER && self.__pseudo_toplevel_evaluable? && @pseudo_toplevel[1] end def self.__pseudo_toplevel=(m) unless (Thread.current.group == ThreadGroup::Default && MultiTkIp.__getip == @@DEFAULT_MASTER) fail SecurityError, "no permission to manipulate" end # if m.kind_of?(Module) && m.respond_to?(:pseudo_toplevel_evaluable?) if m.respond_to?(:pseudo_toplevel_evaluable?) @pseudo_toplevel[0] = true @pseudo_toplevel[1] = m else fail ArgumentError, 'fail to set pseudo-toplevel' end self end def self.__pseudo_toplevel_evaluable? begin @pseudo_toplevel[0] && @pseudo_toplevel[1].pseudo_toplevel_evaluable? rescue Exception false end end def self.__pseudo_toplevel_evaluable=(mode) unless (Thread.current.group == ThreadGroup::Default && MultiTkIp.__getip == @@DEFAULT_MASTER) fail SecurityError, "no permission to manipulate" end @pseudo_toplevel[0] = (mode)? true: false end ################################# @assign_request = Class.new(Exception){ def self.new(target, ret) obj = super() obj.target = target obj.ret = ret obj end attr_accessor :target, :ret } @assign_thread = Thread.new{ loop do begin Thread.stop rescue @assign_request=>req begin req.ret[0] = req.target.instance_eval{ @cmd_receiver, @receiver_watchdog = _create_receiver_and_watchdog(@safe_level[0]) @threadgroup.add @cmd_receiver @threadgroup.add @receiver_watchdog @threadgroup.enclose true } rescue Exception=>e begin req.ret[0] = e rescue Exception # ignore end end rescue Exception # ignore end end } def self.assign_receiver_and_watchdog(target) ret = [nil] @assign_thread.raise(@assign_request.new(target, ret)) while ret[0] == nil unless @assign_thread.alive? raise RuntimeError, 'lost the thread to assign a receiver and a watchdog thread' end end if ret[0].kind_of?(Exception) raise ret[0] else ret[0] end end ################################# @init_ip_env_queue = Queue.new Thread.new{ current = Thread.current loop { mtx, cond, ret, table, script = @init_ip_env_queue.deq begin ret[0] = table.each{|tg, ip| ip._init_ip_env(script) } rescue Exception => e ret[0] = e ensure mtx.synchronize{ cond.signal } end mtx = cond = ret = table = script = nil # clear variables for GC } } def self.__init_ip_env__(table, script) ret = [] mtx = (Thread.current[:MultiTk_ip_Mutex] ||= Mutex.new) cond = (Thread.current[:MultiTk_ip_CondVar] ||= ConditionVariable.new) mtx.synchronize{ @init_ip_env_queue.enq([mtx, cond, ret, table, script]) cond.wait(mtx) } if ret[0].kind_of?(Exception) raise ret[0] else ret[0] end end ################################# class << self undef :instance_eval end } @@DEFAULT_MASTER.freeze # defend against modification ###################################### def self.inherited(subclass) # trust if on ThreadGroup::Default or @@DEFAULT_MASTER's ThreadGroup if @@IP_TABLE[Thread.current.group] == @@DEFAULT_MASTER begin class << subclass self.methods.each{|m| begin unless m == '__id__' || m == '__send__' || m == 'freeze' undef_method(m) end rescue Exception # ignore all exceptions end } end ensure subclass.freeze fail SecurityError, "cannot create subclass of MultiTkIp on a untrusted ThreadGroup" end end end ###################################### @@SAFE_OPT_LIST = [ 'accessPath'.freeze, 'statics'.freeze, 'nested'.freeze, 'deleteHook'.freeze ].freeze def _parse_slaveopts(keys) name = nil safe = false safe_opts = {} tk_opts = {} keys.each{|k,v| k_str = k.to_s if k_str == 'name' name = v elsif k_str == 'safe' safe = v elsif @@SAFE_OPT_LIST.member?(k_str) safe_opts[k_str] = v else tk_opts[k_str] = v end } if keys['without_tk'] || keys[:without_tk] [name, safe, safe_opts, nil] else [name, safe, safe_opts, tk_opts] end end private :_parse_slaveopts def _create_slave_ip_name @@SLAVE_IP_ID.mutex.synchronize{ name = @@SLAVE_IP_ID.join('') @@SLAVE_IP_ID[1].succ! name.freeze } end private :_create_slave_ip_name ###################################### def __check_safetk_optkeys(optkeys) # based on 'safetk.tcl' new_keys = {} optkeys.each{|k,v| new_keys[k.to_s] = v} # check 'display' if !new_keys.key?('display') begin #new_keys['display'] = @interp._invoke('winfo screen .') new_keys['display'] = @interp._invoke('winfo', 'screen', '.') rescue if ENV[DISPLAY] new_keys['display'] = ENV[DISPLAY] elsif !new_keys.key?('use') warn "Warning: no screen info or ENV[DISPLAY], so use ':0.0'" new_keys['display'] = ':0.0' end end end # check 'use' if new_keys.key?('use') # given 'use' case new_keys['use'] when TkWindow new_keys['use'] = TkWinfo.id(new_keys['use']) #assoc_display = @interp._eval('winfo screen .') assoc_display = @interp._invoke('winfo', 'screen', '.') when /^\..*/ new_keys['use'] = @interp._invoke('winfo', 'id', new_keys['use']) assoc_display = @interp._invoke('winfo', 'screen', new_keys['use']) else begin pathname = @interp._invoke('winfo', 'pathname', new_keys['use']) assoc_display = @interp._invoke('winfo', 'screen', pathname) rescue assoc_display = new_keys['display'] end end # match display? if assoc_display != new_keys['display'] if optkeys.key?(:display) || optkeys.key?('display') fail RuntimeError, "conflicting 'display'=>#{new_keys['display']} " + "and display '#{assoc_display}' on 'use'=>#{new_keys['use']}" else new_keys['display'] = assoc_display end end end # return new_keys end private :__check_safetk_optkeys def __create_safetk_frame(slave_ip, slave_name, app_name, keys) # display option is used by ::safe::loadTk loadTk_keys = {} loadTk_keys['display'] = keys['display'] dup_keys = keys.dup # keys for toplevel : allow followings toplevel_keys = {} ['height', 'width', 'background', 'menu'].each{|k| toplevel_keys[k] = dup_keys.delete(k) if dup_keys.key?(k) } toplevel_keys['classname'] = 'SafeTk' toplevel_keys['screen'] = dup_keys.delete('display') # other keys used by pack option of container frame # create toplevel widget begin top = TkToplevel.new(toplevel_keys) rescue NameError => e fail e unless @interp.safe? fail SecurityError, "unable create toplevel on the safe interpreter" end msg = "Untrusted Ruby/Tk applet (#{slave_name})" if app_name.kind_of?(String) top.title "#{app_name} (#{slave_name})" else top.title msg end # procedure to delete slave interpreter slave_delete_proc = proc{ unless slave_ip.deleted? #if slave_ip._invoke('info', 'command', '.') != "" # slave_ip._invoke('destroy', '.') #end #slave_ip.delete slave_ip._eval_without_enc('exit') end begin top.destroy if top.winfo_exist? rescue # ignore end } tag = TkBindTag.new.bind('Destroy', slave_delete_proc) top.bindtags = top.bindtags.unshift(tag) # create control frame TkFrame.new(top, :bg=>'red', :borderwidth=>3, :relief=>'ridge') {|fc| fc.bindtags = fc.bindtags.unshift(tag) TkFrame.new(fc, :bd=>0){|f| TkButton.new(f, :text=>'Delete', :bd=>1, :padx=>2, :pady=>0, :highlightthickness=>0, :command=>slave_delete_proc ).pack(:side=>:right, :fill=>:both) f.pack(:side=>:right, :fill=>:both, :expand=>true) } TkLabel.new(fc, :text=>msg, :padx=>2, :pady=>0, :anchor=>:w).pack(:side=>:left, :fill=>:both, :expand=>true) fc.pack(:side=>:bottom, :fill=>:x) } # container frame for slave interpreter dup_keys['fill'] = :both unless dup_keys.key?('fill') dup_keys['expand'] = true unless dup_keys.key?('expand') c = TkFrame.new(top, :container=>true).pack(dup_keys) c.bind('Destroy', proc{top.destroy}) # return keys loadTk_keys['use'] = TkWinfo.id(c) [loadTk_keys, top.path] end private :__create_safetk_frame def __create_safe_slave_obj(safe_opts, app_name, tk_opts) raise SecurityError, "no permission to manipulate" unless self.manipulable? # safe interpreter ip_name = _create_slave_ip_name slave_ip = @interp.create_slave(ip_name, true) @slave_ip_tbl[ip_name] = slave_ip def slave_ip.safe_base? true end @interp._eval("::safe::interpInit #{ip_name}") slave_ip._invoke('set', 'argv0', app_name) if app_name.kind_of?(String) if tk_opts tk_opts = __check_safetk_optkeys(tk_opts) if tk_opts.key?('use') @slave_ip_top[ip_name] = '' else tk_opts, top_path = __create_safetk_frame(slave_ip, ip_name, app_name, tk_opts) @slave_ip_top[ip_name] = top_path end @interp._eval("::safe::loadTk #{ip_name} #{_keys2opts(tk_opts)}") else @slave_ip_top[ip_name] = nil end if safe_opts.key?('deleteHook') || safe_opts.key?(:deleteHook) @interp._eval("::safe::interpConfigure #{ip_name} " + _keys2opts(safe_opts)) else @interp._eval("::safe::interpConfigure #{ip_name} " + _keys2opts(safe_opts) + '-deleteHook {' + TkComm._get_eval_string(proc{|slave| self._default_delete_hook(slave) }) + '}') end [slave_ip, ip_name] end def __create_trusted_slave_obj(name, keys) raise SecurityError, "no permission to manipulate" unless self.manipulable? ip_name = _create_slave_ip_name slave_ip = @interp.create_slave(ip_name, false) slave_ip._invoke('set', 'argv0', name) if name.kind_of?(String) slave_ip._invoke('set', 'argv', _keys2opts(keys)) @interp._invoke('load', '', 'Tk', ip_name) @slave_ip_tbl[ip_name] = slave_ip [slave_ip, ip_name] end ###################################### def _create_slave_object(keys={}) raise SecurityError, "no permission to manipulate" unless self.manipulable? ip = MultiTkIp.new_slave(self, keys={}) @slave_ip_tbl[ip.name] = ip end ###################################### def initialize(master, safeip=true, keys={}) if $SAFE >= 4 fail SecurityError, "cannot create a new interpreter at level #{$SAFE}" end if safeip == nil && $SAFE >= 2 fail SecurityError, "cannot create a master-ip at level #{$SAFE}" end if master.deleted? && safeip == nil fail RuntimeError, "cannot create a slave of a deleted interpreter" end if !master.deleted? && !master.master? && master.safe? fail SecurityError, "safe-slave-ip cannot create a new interpreter" end if safeip == nil && !master.master? fail SecurityError, "slave-ip cannot create a master-ip" end unless keys.kind_of? Hash fail ArgumentError, "expecting a Hash object for the 2nd argument" end @tk_windows = {} @tk_table_list = [] @slave_ip_tbl = {} @slave_ip_top = {} @cb_error_proc = [] @evloop_thread = [] @tk_windows.taint unless @tk_windows.tainted? @tk_table_list.taint unless @tk_table_list.tainted? @slave_ip_tbl.taint unless @slave_ip_tbl.tainted? @slave_ip_top.taint unless @slave_ip_top.tainted? @cb_error_proc.taint unless @cb_error_proc.tainted? @evloop_thread.taint unless @evloop_thread.tainted? @callback_status = [] name, safe, safe_opts, tk_opts = _parse_slaveopts(keys) safe = 4 if safe && !safe.kind_of?(Fixnum) @safe_base = false if safeip == nil # create master-ip unless WITH_RUBY_VM @interp = TclTkIp.new(name, _keys2opts(tk_opts)) else ### Ruby 1.9 !!!!!!!!!!! @interp_thread = Thread.new{ Thread.current[:interp] = interp = TclTkIp.new(name, _keys2opts(tk_opts)) #sleep TclTkLib.mainloop(true) } until @interp_thread[:interp] Thread.pass end # INTERP_THREAD.run @interp = @interp_thread[:interp] end @ip_name = nil if safe safe = $SAFE if safe < $SAFE @safe_level = [safe] else @safe_level = [$SAFE] end else # create slave-ip if safeip || master.safe? @safe_base = true @interp, @ip_name = master.__create_safe_slave_obj(safe_opts, name, tk_opts) # @interp_thread = nil if RUBY_VERSION < '1.9.0' ### !!!!!!!!!!! @interp_thread = nil unless WITH_RUBY_VM ### Ruby 1.9 !!!!!!!!!!! if safe safe = master.safe_level if safe < master.safe_level @safe_level = [safe] else @safe_level = [4] end else @interp, @ip_name = master.__create_trusted_slave_obj(name, tk_opts) # @interp_thread = nil if RUBY_VERSION < '1.9.0' ### !!!!!!!!!!! @interp_thread = nil unless WITH_RUBY_VM ### Ruby 1.9 !!!!!!!!!!! if safe safe = master.safe_level if safe < master.safe_level @safe_level = [safe] else @safe_level = [master.safe_level] end end @set_alias_proc = proc{|name| master._invoke('interp', 'alias', @ip_name, name, '', name) }.freeze end @system = Object.new @wait_on_mainloop = [true, 0].taint # @wait_on_mainloop = [false, 0].taint @threadgroup = ThreadGroup.new @pseudo_toplevel = [false, nil] @cmd_queue = Queue.new =begin @cmd_receiver, @receiver_watchdog = _create_receiver_and_watchdog(@safe_level[0]) @threadgroup.add @cmd_receiver @threadgroup.add @receiver_watchdog @threadgroup.enclose =end @@DEFAULT_MASTER.assign_receiver_and_watchdog(self) @@IP_TABLE[@threadgroup] = self @@TK_TABLE_LIST.size.times{ (tbl = {}).tainted? || tbl.taint @tk_table_list << tbl } _init_ip_internal(@@INIT_IP_ENV, @@ADD_TK_PROCS) class << self undef :instance_eval end # dummy call for initialization self.eval_proc{ Tk.tk_call('set', 'tcl_patchLevel') } self.freeze # defend against modification end ###################################### def _default_delete_hook(slave) raise SecurityError, "no permission to manipulate" unless self.manipulable? @slave_ip_tbl.delete(slave) top = @slave_ip_top.delete(slave) if top.kind_of?(String) # call default hook of safetk.tcl (ignore exceptions) if top == '' begin @interp._eval("::safe::disallowTk #{slave}") rescue warn("Waring: fail to call '::safe::disallowTk'") if $DEBUG end else # toplevel path begin @interp._eval("::safe::tkDelete {} #{top} #{slave}") rescue warn("Waring: fail to call '::safe::tkDelete'") if $DEBUG begin @interp._eval("destroy #{top}") rescue warn("Waring: fail to destroy toplevel") if $DEBUG end end end end end end # get target IP class MultiTkIp def self._ip_id_ __getip._ip_id_ end def _ip_id_ # for RemoteTkIp '' end def self.__getip current = Thread.current if TclTkLib.mainloop_thread? != false && current['callback_ip'] return current['callback_ip'] end if current.group == ThreadGroup::Default @@DEFAULT_MASTER else ip = @@IP_TABLE[current.group] unless ip fail SecurityError, "cannot call Tk methods on #{Thread.current.inspect}" end ip end end end # aliases of constructor class << MultiTkIp alias __new new private :__new def new_master(safe=nil, keys={}) if MultiTkIp::WITH_RUBY_VM #### TODO !!!!!! fail RuntimeError, 'sorry, still not support multiple master-interpreters on Ruby VM' end if safe.kind_of?(Hash) keys = safe elsif safe.kind_of?(Integer) raise ArgumentError, "unexpected argument(s)" unless keys.kind_of?(Hash) if !keys.key?(:safe) && !keys.key?('safe') keys[:safe] = safe end elsif safe == nil # do nothing else raise ArgumentError, "unexpected argument(s)" end ip = __new(__getip, nil, keys) #ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call) if block_given? if block_given? Thread.new{ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call)} end ip end alias new new_master def new_slave(safe=nil, keys={}) if safe.kind_of?(Hash) keys = safe elsif safe.kind_of?(Integer) raise ArgumentError, "unexpected argument(s)" unless keys.kind_of?(Hash) if !keys.key?(:safe) && !keys.key?('safe') keys[:safe] = safe end elsif safe == nil # do nothing else raise ArgumentError, "unexpected argument(s)" end ip = __new(__getip, false, keys) # ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call) if block_given? if block_given? Thread.new{ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call)} end ip end alias new_trusted_slave new_slave def new_safe_slave(safe=4, keys={}) if safe.kind_of?(Hash) keys = safe elsif safe.kind_of?(Integer) raise ArgumentError, "unexpected argument(s)" unless keys.kind_of?(Hash) if !keys.key?(:safe) && !keys.key?('safe') keys[:safe] = safe end else raise ArgumentError, "unexpected argument(s)" end ip = __new(__getip, true, keys) # ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call) if block_given? if block_given? Thread.new{ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call)} end ip end alias new_safeTk new_safe_slave end # get info class MultiTkIp def inspect s = self.to_s.chop! if self.manipulable? if master? if @interp.deleted? s << ':deleted-master' else s << ':master' end else if @interp.deleted? s << ':deleted-slave' elsif @interp.safe? s << ':safe-slave' else s << ':trusted-slave' end end end s << '>' end def master? if @ip_name false else true end end def self.master? __getip.master? end def slave? not master? end def self.slave? not self.master? end def alive? raise SecurityError, "no permission to manipulate" unless self.manipulable? begin return false unless @cmd_receiver.alive? return false if @interp.deleted? return false if @interp._invoke('interp', 'exists', '') == '0' rescue Exception return false end true end def self.alive? __getip.alive? end def path @ip_name || '' end def self.path __getip.path end def ip_name @ip_name || '' end def self.ip_name __getip.ip_name end def to_eval @ip_name || '' end def self.to_eval __getip.to_eval end def slaves(all = false) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp','slaves').split.map!{|name| if @slave_ip_tbl.key?(name) @slave_ip_tbl[name] elsif all name else nil end }.compact! end def self.slaves(all = false) __getip.slaves(all) end def manipulable? return true if (Thread.current.group == ThreadGroup::Default) ip = MultiTkIp.__getip (ip == self) || ip._is_master_of?(@interp) end def self.manipulable? true end def _is_master_of?(tcltkip_obj) tcltkip_obj.slave_of?(@interp) end protected :_is_master_of? end # instance methods to treat tables class MultiTkIp def _tk_cmd_tbl tbl = {} MultiTkIp.tk_cmd_tbl.each{|id, ent| tbl[id] = ent if ent.ip == self } tbl end def _tk_windows @tk_windows end def _tk_table_list @tk_table_list end def _add_new_tables (@@TK_TABLE_LIST.size - @tk_table_list.size).times{ (tbl = {}).tainted? || tbl.taint @tk_table_list << tbl } end def _init_ip_env(script) self.eval_proc{script.call(self)} end def _add_tk_procs(name, args, body) return if slave? @interp._invoke('proc', name, args, body) if args && body @interp._invoke('interp', 'slaves').split.each{|slave| @interp._invoke('interp', 'alias', slave, name, '', name) } end def _remove_tk_procs(*names) return if slave? names.each{|name| name = name.to_s return if @interp.deleted? @interp._invoke('rename', name, '') return if @interp.deleted? @interp._invoke('interp', 'slaves').split.each{|slave| return if @interp.deleted? @interp._invoke('interp', 'alias', slave, name, '') rescue nil } } end def _init_ip_internal(init_ip_env, add_tk_procs) #init_ip_env.each{|script| self.eval_proc{script.call(self)}} init_ip_env.each{|script| self._init_ip_env(script)} add_tk_procs.each{|name, args, body| if master? @interp._invoke('proc', name, args, body) if args && body else @set_alias_proc.call(name) end } end end # class methods to treat tables class MultiTkIp def self.tk_cmd_tbl @@TK_CMD_TBL end def self.tk_windows __getip._tk_windows end def self.tk_object_table(id) __getip._tk_table_list[id] end def self.create_table if __getip.slave? begin raise SecurityError, "slave-IP has no permission creating a new table" rescue SecurityError => e #p e.backtrace # Is called on a Ruby/Tk library? caller_info = e.backtrace[1] if caller_info =~ %r{^#{MultiTkIp::BASE_DIR}/(tk|tkextlib)/[^:]+\.rb:} # Probably, caller is a Ruby/Tk library --> allow creating else raise e end end end id = @@TK_TABLE_LIST.size obj = Object.new @@TK_TABLE_LIST << obj obj.instance_variable_set(:@id, id) obj.instance_variable_set(:@mutex, Mutex.new) obj.instance_eval{ def self.mutex @mutex end def self.method_missing(m, *args) MultiTkIp.tk_object_table(@id).__send__(m, *args) end } obj.freeze @@IP_TABLE.each{|tg, ip| ip._add_new_tables } return obj end def self.init_ip_env(script = Proc.new) @@INIT_IP_ENV << script if __getip.slave? begin raise SecurityError, "slave-IP has no permission initializing IP env" rescue SecurityError => e #p e.backtrace # Is called on a Ruby/Tk library? caller_info = e.backtrace[1] if caller_info =~ %r{^#{MultiTkIp::BASE_DIR}/(tk|tkextlib)/[^:]+\.rb:} # Probably, caller is a Ruby/Tk library --> allow creating else raise e end end end # @@IP_TABLE.each{|tg, ip| # ip._init_ip_env(script) # } @@DEFAULT_MASTER.__init_ip_env__(@@IP_TABLE, script) end def self.add_tk_procs(name, args=nil, body=nil) if name.kind_of?(Array) # => an array of [name, args, body] name.each{|param| self.add_tk_procs(*param)} else name = name.to_s @@ADD_TK_PROCS << [name, args, body] @@IP_TABLE.each{|tg, ip| ip._add_tk_procs(name, args, body) } end end def self.remove_tk_procs(*names) names.each{|name| name = name.to_s @@ADD_TK_PROCS.delete_if{|elem| elem.kind_of?(Array) && elem[0].to_s == name } } @@IP_TABLE.each{|tg, ip| ip._remove_tk_procs(*names) } end def self.init_ip_internal __getip._init_ip_internal(@@INIT_IP_ENV, @@ADD_TK_PROCS) end end # for callback operation class MultiTkIp def self.cb_entry_class @@CB_ENTRY_CLASS end def self.get_cb_entry(cmd) @@CB_ENTRY_CLASS.new(__getip, cmd).freeze end =begin def cb_eval(cmd, *args) #self.eval_callback{ TkComm._get_eval_string(TkUtil.eval_cmd(cmd, *args)) } #ret = self.eval_callback{ TkComm._get_eval_string(TkUtil.eval_cmd(cmd, *args)) } ret = self.eval_callback(*args){|safe, *params| $SAFE=safe if $SAFE < safe TkComm._get_eval_string(TkUtil.eval_cmd(cmd, *params)) } if ret.kind_of?(Exception) raise ret end ret end =end def cb_eval(cmd, *args) self.eval_callback(*args){|safe, *params| $SAFE=safe if $SAFE < safe # TkUtil.eval_cmd(cmd, *params) TkComm._get_eval_string(TkUtil.eval_cmd(cmd, *params)) } end =begin def cb_eval(cmd, *args) @callback_status[0] ||= TkVariable.new @callback_status[1] ||= TkVariable.new st, val = @callback_status th = Thread.new{ self.eval_callback(*args){|safe, *params| #p [status, val, safe, *params] $SAFE=safe if $SAFE < safe begin TkComm._get_eval_string(TkUtil.eval_cmd(cmd, *params)) rescue TkCallbackContinue st.value = 4 rescue TkCallbackBreak st.value = 3 rescue TkCallbackReturn st.value = 2 rescue Exception => e val.value = e.message st.value = 1 else st.value = 0 end } } begin st.wait status = st.numeric retval = val.value rescue => e fail e end if status == 1 fail RuntimeError, retval elsif status == 2 fail TkCallbackReturn, "Tk callback returns 'return' status" elsif status == 3 fail TkCallbackBreak, "Tk callback returns 'break' status" elsif status == 4 fail TkCallbackContinue, "Tk callback returns 'continue' status" else '' end end =end end # pseudo-toplevel operation support class MultiTkIp # instance method def __pseudo_toplevel ip = MultiTkIp.__getip (ip == @@DEFAULT_MASTER || ip == self) && self.__pseudo_toplevel_evaluable? && @pseudo_toplevel[1] end def __pseudo_toplevel=(m) unless (Thread.current.group == ThreadGroup::Default && MultiTkIp.__getip == @@DEFAULT_MASTER) fail SecurityError, "no permission to manipulate" end # if m.kind_of?(Module) && m.respond_to?(:pseudo_toplevel_evaluable?) if m.respond_to?(:pseudo_toplevel_evaluable?) @pseudo_toplevel[0] = true @pseudo_toplevel[1] = m else fail ArgumentError, 'fail to set pseudo-toplevel' end self end def __pseudo_toplevel_evaluable? begin @pseudo_toplevel[0] && @pseudo_toplevel[1].pseudo_toplevel_evaluable? rescue Exception false end end def __pseudo_toplevel_evaluable=(mode) unless (Thread.current.group == ThreadGroup::Default && MultiTkIp.__getip == @@DEFAULT_MASTER) fail SecurityError, "no permission to manipulate" end @pseudo_toplevel[0] = (mode)? true: false end end # evaluate a procedure on the proper interpreter class MultiTkIp # instance method def eval_proc_core(req_val, cmd, *args) # check raise SecurityError, "no permission to manipulate" unless self.manipulable? unless cmd.kind_of?(Proc) || cmd.kind_of?(Method) raise RuntimeError, "A Proc/Method object is expected for the 'cmd' argument" end # on IP thread if @cmd_receiver == Thread.current || (!req_val && TclTkLib.mainloop_thread? != false) # callback begin ret = cmd.call(safe_level, *args) rescue SystemExit => e # exit IP warn("Warning: "+ $! + " on " + self.inspect) if $DEBUG begin self._eval_without_enc('exit') rescue Exception end self.delete ret = nil rescue Exception => e if $DEBUG warn("Warning: " + e.class.inspect + ((e.message.length > 0)? ' "' + e.message + '"': '') + " on " + self.inspect) end =begin begin bt = _toUTF8(e.backtrace.join("\n")) bt.instance_variable_set(:@encoding, 'utf-8') rescue Exception bt = e.backtrace.join("\n") end begin @interp._set_global_var('errorInfo', bt) rescue Exception end =end ret = e end return ret end # send cmd to the proc-queue unless req_val begin @cmd_queue.enq([nil, cmd, *args]) rescue Exception => e # ignore if $DEBUG warn("Warning: " + e.class.inspect + ((e.message.length > 0)? ' "' + e.message + '"': '') + " on " + self.inspect) end return e end return nil end # send and get return value by exception begin @cmd_queue.enq([Thread.current, cmd, *args]) Thread.stop rescue MultiTkIp_OK => ret # return value return ret.value rescue SystemExit => e # exit IP warn("Warning: " + $! + " on " + self.inspect) if $DEBUG begin self._eval_without_enc('exit') rescue Exception end if !self.deleted? && !safe? && allow_ruby_exit? self.delete fail e else self.delete end rescue Exception => e if $DEBUG warn("Warning: " + e.class.inspect + ((e.message.length > 0)? ' "' + e.message + '"': '') + " on " + self.inspect) end return e end return nil end private :eval_proc_core def eval_callback(*args) if block_given? cmd = Proc.new else cmd = args.shift end current = Thread.current backup_ip = current['callback_ip'] current['callback_ip'] = self begin eval_proc_core(false, cmd, *args) ensure current['callback_ip'] = backup_ip end end def eval_proc(*args) # The scope of the eval-block of 'eval_proc' method is different from # the external. If you want to pass local values to the eval-block, # use arguments of eval_proc method. They are passed to block-arguments. if block_given? cmd = Proc.new else unless (cmd = args.shift) fail ArgumentError, "A Proc or Method object is expected for 1st argument" end end if TclTkLib.mainloop_thread? == true # call from eventloop current = Thread.current backup_ip = current['callback_ip'] current['callback_ip'] = self begin eval_proc_core(false, proc{|safe, *params| $SAFE=safe if $SAFE < safe cmd.call(*params) }, *args) ensure current['callback_ip'] = backup_ip end else eval_proc_core(true, proc{|safe, *params| $SAFE=safe if $SAFE < safe Thread.new(*params, &cmd).value }, *args) end end alias call eval_proc def bg_eval_proc(*args) if block_given? cmd = Proc.new else unless (cmd = args.shift) fail ArgumentError, "A Proc or Method object is expected for 1st argument" end end Thread.new{ eval_proc(cmd, *args) =begin eval_proc_core(false, proc{|safe, *params| $SAFE=safe if $SAFE < safe Thread.new(*params, &cmd).value }, safe_level, *args) =end } end alias background_eval_proc bg_eval_proc alias thread_eval_proc bg_eval_proc alias bg_call bg_eval_proc alias background_call bg_eval_proc def eval_string(cmd, *eval_args) # cmd string ==> proc unless cmd.kind_of?(String) raise RuntimeError, "A String object is expected for the 'cmd' argument" end eval_proc_core(true, proc{|safe| Kernel.eval("$SAFE=#{safe} if $SAFE < #{safe};" << cmd, *eval_args) }) end alias eval_str eval_string def bg_eval_string(cmd, *eval_args) # cmd string ==> proc unless cmd.kind_of?(String) raise RuntimeError, "A String object is expected for the 'cmd' argument" end Thread.new{ eval_proc_core(true, proc{|safe| Kernel.eval("$SAFE=#{safe} if $SAFE < #{safe};" << cmd, *eval_args) }) } end alias background_eval_string bg_eval_string alias bg_eval_str bg_eval_string alias background_eval_str bg_eval_string def eval(*args, &blk) if block_given? eval_proc(*args, &blk) elsif args[0] if args[0].respond_to?(:call) eval_proc(*args) else eval_string(*args) end else fail ArgumentError, "no argument to eval" end end def bg_eval(*args, &blk) if block_given? bg_eval_proc(*args, &blk) elsif args[0] if args[0].respond_to?(:call) bg_eval_proc(*args) else bg_eval_string(*args) end else fail ArgumentError, "no argument to eval" end end alias background_eval bg_eval end class << MultiTkIp # class method def eval_proc(*args, &blk) # class ==> interp object __getip.eval_proc(*args, &blk) end alias call eval_proc def bg_eval_proc(*args, &blk) # class ==> interp object __getip.bg_eval_proc(*args, &blk) end alias background_eval_proc bg_eval_proc alias thread_eval_proc bg_eval_proc alias bg_call bg_eval_proc alias background_call bg_eval_proc def eval_string(cmd, *eval_args) # class ==> interp object __getip.eval_string(cmd, *eval_args) end alias eval_str eval_string def bg_eval_string(cmd, *eval_args) # class ==> interp object __getip.bg_eval_string(cmd, *eval_args) end alias background_eval_string bg_eval_string alias bg_eval_str bg_eval_string alias background_eval_str bg_eval_string def eval(*args, &blk) # class ==> interp object __getip.eval(*args, &blk) end def bg_eval(*args, &blk) # class ==> interp object __getip.bg_eval(*args, &blk) end alias background_eval bg_eval end # event loop # all master/slave IPs are controled by only one event-loop class << MultiTkIp def mainloop(check_root = true) __getip.mainloop(check_root) end def mainloop_watchdog(check_root = true) __getip.mainloop_watchdog(check_root) end def do_one_event(flag = TclTkLib::EventFlag::ALL) __getip.do_one_event(flag) end def mainloop_abort_on_exception # __getip.mainloop_abort_on_exception TclTkLib.mainloop_abort_on_exception end def mainloop_abort_on_exception=(mode) # __getip.mainloop_abort_on_exception=(mode) TclTkLib.mainloop_abort_on_exception=(mode) end def set_eventloop_tick(tick) __getip.set_eventloop_tick(tick) end def get_eventloop_tick __getip.get_eventloop_tick end def set_no_event_wait(tick) __getip.set_no_event_wait(tick) end def get_no_event_wait __getip.get_no_event_wait end def set_eventloop_weight(loop_max, no_event_tick) __getip.set_eventloop_weight(loop_max, no_event_tick) end def get_eventloop_weight __getip.get_eventloop_weight end end # class methods to delegate to TclTkIp class << MultiTkIp def method_missing(id, *args) __getip.__send__(id, *args) end def make_safe __getip.make_safe end def safe? __getip.safe? end def safe_base? begin __getip.safe_base? rescue false end end def allow_ruby_exit? __getip.allow_ruby_exit? end def allow_ruby_exit= (mode) __getip.allow_ruby_exit = mode end def delete __getip.delete end def deleted? __getip.deleted? end def has_mainwindow? __getip.has_mainwindow? end def invalid_namespace? __getip.invalid_namespace? end def abort(msg = nil) __getip.abort(msg) end def exit(st = true) __getip.exit(st) end def exit!(st = false) __getip.exit!(st) end def restart(app_name = nil, keys = {}) init_ip_internal __getip._invoke('set', 'argv0', app_name) if app_name if keys.kind_of?(Hash) __getip._invoke('set', 'argv', _keys2opts(keys)) end __getip.restart end def _eval(str) __getip._eval(str) end def _invoke(*args) __getip._invoke(*args) end def _eval_without_enc(str) __getip._eval_without_enc(str) end def _invoke_without_enc(*args) __getip._invoke_without_enc(*args) end def _eval_with_enc(str) __getip._eval_with_enc(str) end def _invoke_with_enc(*args) __getip._invoke_with_enc(*args) end def _toUTF8(str, encoding=nil) __getip._toUTF8(str, encoding) end def _fromUTF8(str, encoding=nil) __getip._fromUTF8(str, encoding) end def _thread_vwait(var) __getip._thread_vwait(var) end def _thread_tkwait(mode, target) __getip._thread_tkwait(mode, target) end def _return_value __getip._return_value end def _get_variable(var, flag) __getip._get_variable(var, flag) end def _get_variable2(var, idx, flag) __getip._get_variable2(var, idx, flag) end def _set_variable(var, value, flag) __getip._set_variable(var, value, flag) end def _set_variable2(var, idx, value, flag) __getip._set_variable2(var, idx, value, flag) end def _unset_variable(var, flag) __getip._unset_variable(var, flag) end def _unset_variable2(var, idx, flag) __getip._unset_variable2(var, idx, flag) end def _get_global_var(var) __getip._get_global_var(var) end def _get_global_var2(var, idx) __getip._get_global_var2(var, idx) end def _set_global_var(var, value) __getip._set_global_var(var, value) end def _set_global_var2(var, idx, value) __getip._set_global_var2(var, idx, value) end def _unset_global_var(var) __getip._unset_global_var(var) end def _unset_global_var2(var, idx) __getip._unset_global_var2(var, idx) end def _make_menu_embeddable(menu_path) __getip._make_menu_embeddable(menu_path) end def _split_tklist(str) __getip._split_tklist(str) end def _merge_tklist(*args) __getip._merge_tklist(*args) end def _conv_listelement(arg) __getip._conv_listelement(arg) end def _create_console __getip._create_console end end # wrap methods on TclTkLib : not permit calling TclTkLib module methods class << TclTkLib def mainloop(check_root = true) MultiTkIp.mainloop(check_root) end def mainloop_watchdog(check_root = true) MultiTkIp.mainloop_watchdog(check_root) end def do_one_event(flag = TclTkLib::EventFlag::ALL) MultiTkIp.do_one_event(flag) end #def mainloop_abort_on_exception # MultiTkIp.mainloop_abort_on_exception #end #def mainloop_abort_on_exception=(mode) # MultiTkIp.mainloop_abort_on_exception=(mode) #end def set_eventloop_tick(tick) MultiTkIp.set_eventloop_tick(tick) end def get_eventloop_tick MultiTkIp.get_eventloop_tick end def set_no_event_wait(tick) MultiTkIp.set_no_event_wait(tick) end def get_no_event_wait MultiTkIp.get_no_event_wait end def set_eventloop_weight(loop_max, no_event_tick) MultiTkIp.set_eventloop_weight(loop_max, no_event_tick) end def get_eventloop_weight MultiTkIp.get_eventloop_weight end def restart(*args) MultiTkIp.restart(*args) end def _merge_tklist(*args) MultiTkIp._merge_tklist(*args) end def _conv_listelement(arg) MultiTkIp._conv_listelement(arg) end end # depend on TclTkIp class MultiTkIp def mainloop(check_root = true, restart_on_dead = true) raise SecurityError, "no permission to manipulate" unless self.manipulable? if WITH_RUBY_VM ### Ruby 1.9 !!!!!!!!!!! return @interp_thread.value if @interp_thread end #return self if self.slave? #return self if self != @@DEFAULT_MASTER if self != @@DEFAULT_MASTER if @wait_on_mainloop[0] begin @wait_on_mainloop[1] += 1 if $SAFE >= 4 _receiver_mainloop(check_root).join else @cmd_queue.enq([@system, 'call_mainloop', Thread.current, check_root]) Thread.stop end rescue MultiTkIp_OK => ret # return value if ret.value.kind_of?(Thread) return ret.value.value else return ret.value end rescue SystemExit => e # exit IP warn("Warning: " + $! + " on " + self.inspect) if $DEBUG begin self._eval_without_enc('exit') rescue Exception end self.delete rescue StandardError => e if $DEBUG warn("Warning: " + e.class.inspect + ((e.message.length > 0)? ' "' + e.message + '"': '') + " on " + self.inspect) end return e rescue Exception => e return e ensure @wait_on_mainloop[1] -= 1 end end return end unless restart_on_dead @wait_on_mainloop[1] += 1 =begin begin @interp.mainloop(check_root) rescue StandardError => e if $DEBUG warn("Warning: " + e.class.inspect + ((e.message.length > 0)? ' "' + e.message + '"': '') + " on " + self.inspect) end end =end begin @interp.mainloop(check_root) ensure @wait_on_mainloop[1] -= 1 end else loop do break unless self.alive? if check_root begin break if TclTkLib.num_of_mainwindows == 0 rescue StandardError break end end break if @interp.deleted? begin @wait_on_mainloop[1] += 1 @interp.mainloop(check_root) rescue StandardError => e if TclTkLib.mainloop_abort_on_exception != nil #STDERR.print("Warning: Tk mainloop receives ", $!.class.inspect, # " exception (ignore) : ", $!.message, "\n"); if $DEBUG warn("Warning: Tk mainloop receives " << e.class.inspect << " exception (ignore) : " << e.message); end end #raise e rescue Exception => e =begin if TclTkLib.mainloop_abort_on_exception != nil #STDERR.print("Warning: Tk mainloop receives ", $!.class.inspect, # " exception (ignore) : ", $!.message, "\n"); if $DEBUG warn("Warning: Tk mainloop receives " << e.class.inspect << " exception (ignore) : " << e.message); end end =end raise e ensure @wait_on_mainloop[1] -= 1 Thread.pass # avoid eventloop conflict end end end self end def make_safe raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.make_safe end def safe? raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.safe? end def safe_base? raise SecurityError, "no permission to manipulate" unless self.manipulable? @safe_base end def allow_ruby_exit? raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.allow_ruby_exit? end def allow_ruby_exit= (mode) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.allow_ruby_exit = mode end def delete raise SecurityError, "no permission to manipulate" unless self.manipulable? @slave_ip_tbl.each{|name, subip| _destroy_slaves_of_slaveIP(subip) =begin begin subip._invoke('destroy', '.') unless subip.deleted? rescue Exception end =end begin # subip._eval_without_enc("foreach i [after info] {after cancel $i}") unless subip.deleted? after_ids = subip._eval_without_enc("after info") subip._eval_without_enc("foreach i {#{after_ids}} {after cancel $i}") end rescue Exception end # safe_base? if @interp._eval_without_enc("catch {::safe::interpConfigure #{name}}") == '0' begin @interp._eval_without_enc("::safe::interpDelete #{name}") rescue Exception else next if subip.deleted? end end if subip.respond_to?(:safe_base?) && subip.safe_base? && !subip.deleted? # do 'exit' to call the delete_hook procedure begin subip._eval_without_enc('exit') rescue Exception end else begin subip.delete unless subip.deleted? rescue Exception end end } begin # @interp._eval_without_enc("foreach i [after info] {after cancel $i}") after_ids = @interp._eval_without_enc("after info") @interp._eval_without_enc("foreach i {#{after_ids}} {after cancel $i}") rescue Exception end begin @interp._invoke('destroy', '.') unless @interp.deleted? rescue Exception end if @safe_base && !@interp.deleted? # do 'exit' to call the delete_hook procedure @interp._eval_without_enc('exit') end @interp.delete self end def deleted? raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.deleted? end def has_mainwindow? raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.has_mainwindow? end def invalid_namespace? raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.invalid_namespace? end def abort(msg = nil) raise SecurityError, "no permission to manipulate" unless self.manipulable? if master? && !safe? && allow_ruby_exit? if msg Kernel.abort(msg) else Kernel.abort end else # ignore msg delete 1 end end def exit(st = true) raise SecurityError, "no permission to manipulate" unless self.manipulable? if master? && !safe? && allow_ruby_exit? Kernel.exit(st) else delete st end end def exit!(st = false) raise SecurityError, "no permission to manipulate" unless self.manipulable? if master? && !safe? && allow_ruby_exit? Kernel.exit!(st) else delete st end end def restart(app_name = nil, keys = {}) raise SecurityError, "no permission to manipulate" unless self.manipulable? _init_ip_internal(@@INIT_IP_ENV, @@ADD_TK_PROCS) @interp._invoke('set', 'argv0', app_name) if app_name if keys.kind_of?(Hash) @interp._invoke('set', 'argv', _keys2opts(keys)) end @interp.restart end def __eval(str) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.__eval(str) end def __invoke(*args) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.__invoke(*args) end def _eval(str) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._eval(str) end def _invoke(*args) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke(*args) end def _eval_without_enc(str) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._eval_without_enc(str) end def _invoke_without_enc(*args) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke_without_enc(*args) end def _eval_with_enc(str) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._eval_with_enc(str) end def _invoke_with_enc(*args) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke_with_enc(*args) end def _toUTF8(str, encoding=nil) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._toUTF8(str, encoding) end def _fromUTF8(str, encoding=nil) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._fromUTF8(str, encoding) end def _thread_vwait(var) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._thread_vwait(var) end def _thread_tkwait(mode, target) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._thread_tkwait(mode, target) end def _return_value raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._return_value end def _get_variable(var, flag) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._get_variable(var, flag) end def _get_variable2(var, idx, flag) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._get_variable2(var, idx, flag) end def _set_variable(var, value, flag) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._set_variable(var, value, flag) end def _set_variable2(var, idx, value, flag) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._set_variable2(var, idx, value, flag) end def _unset_variable(var, flag) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._unset_variable(var, flag) end def _unset_variable2(var, idx, flag) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._unset_variable2(var, idx, flag) end def _get_global_var(var) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._get_global_var(var) end def _get_global_var2(var, idx) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._get_global_var2(var, idx) end def _set_global_var(var, value) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._set_global_var(var, value) end def _set_global_var2(var, idx, value) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._set_global_var2(var, idx, value) end def _unset_global_var(var) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._unset_global_var(var) end def _unset_global_var2(var, idx) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._unset_global_var2(var, idx) end def _make_menu_embeddable(menu_path) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._make_menu_embeddable(menu_path) end def _split_tklist(str) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._split_tklist(str) end def _merge_tklist(*args) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._merge_tklist(*args) end def _conv_listelement(arg) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._conv_listelement(arg) end end # interp command support class MultiTkIp def _lst2ary(str) return [] if str == "" idx = str.index('{') while idx and idx > 0 and str[idx-1] == ?\\ idx = str.index('{', idx+1) end return str.split unless idx list = str[0,idx].split str = str[idx+1..-1] i = -1 brace = 1 str.each_byte {|c| c = c.chr i += 1 brace += 1 if c == '{' brace -= 1 if c == '}' break if brace == 0 } if i == 0 list.push '' elsif str[0, i] == ' ' list.push ' ' else list.push str[0..i-1] end #list += _lst2ary(str[i+1..-1]) list.concat(_lst2ary(str[i+1..-1])) list end private :_lst2ary def _slavearg(slave) if slave.kind_of?(MultiTkIp) slave.path elsif slave.kind_of?(String) slave else slave.to_s end end private :_slavearg def alias_info(slave, cmd_name) raise SecurityError, "no permission to manipulate" unless self.manipulable? _lst2ary(@interp._invoke('interp', 'alias', _slavearg(slave), cmd_name)) end def self.alias_info(slave, cmd_name) __getip.alias_info(slave, cmd_name) end def alias_delete(slave, cmd_name) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'alias', _slavearg(slave), cmd_name, '') self end def self.alias_delete(slave, cmd_name) __getip.alias_delete(slave, cmd_name) self end def def_alias(slave, new_cmd, org_cmd, *args) raise SecurityError, "no permission to manipulate" unless self.manipulable? ret = @interp._invoke('interp', 'alias', _slavearg(slave), new_cmd, '', org_cmd, *args) (ret == new_cmd)? self: nil end def self.def_alias(slave, new_cmd, org_cmd, *args) ret = __getip.def_alias(slave, new_cmd, org_cmd, *args) (ret == new_cmd)? self: nil end def aliases(slave = '') raise SecurityError, "no permission to manipulate" unless self.manipulable? _lst2ary(@interp._invoke('interp', 'aliases', _slavearg(slave))) end def self.aliases(slave = '') __getip.aliases(slave) end def delete_slaves(*args) raise SecurityError, "no permission to manipulate" unless self.manipulable? slaves = args.collect{|s| _slavearg(s)} @interp._invoke('interp', 'delete', *slaves) if slaves.size > 0 self end def self.delete_slaves(*args) __getip.delete_slaves(*args) self end def exist?(slave = '') raise SecurityError, "no permission to manipulate" unless self.manipulable? ret = @interp._invoke('interp', 'exists', _slavearg(slave)) (ret == '1')? true: false end def self.exist?(slave = '') __getip.exist?(slave) end def delete_cmd(slave, cmd) raise SecurityError, "no permission to manipulate" unless self.manipulable? slave_invoke = @interp._invoke('list', 'rename', cmd, '') @interp._invoke('interp', 'eval', _slavearg(slave), slave_invoke) self end def self.delete_cmd(slave, cmd) __getip.delete_cmd(slave, cmd) self end def expose_cmd(slave, cmd, aliasname = nil) raise SecurityError, "no permission to manipulate" unless self.manipulable? if aliasname @interp._invoke('interp', 'expose', _slavearg(slave), cmd, aliasname) else @interp._invoke('interp', 'expose', _slavearg(slave), cmd) end self end def self.expose_cmd(slave, cmd, aliasname = nil) __getip.expose_cmd(slave, cmd, aliasname) self end def hide_cmd(slave, cmd, aliasname = nil) raise SecurityError, "no permission to manipulate" unless self.manipulable? if aliasname @interp._invoke('interp', 'hide', _slavearg(slave), cmd, aliasname) else @interp._invoke('interp', 'hide', _slavearg(slave), cmd) end self end def self.hide_cmd(slave, cmd, aliasname = nil) __getip.hide_cmd(slave, cmd, aliasname) self end def hidden_cmds(slave = '') raise SecurityError, "no permission to manipulate" unless self.manipulable? _lst2ary(@interp._invoke('interp', 'hidden', _slavearg(slave))) end def self.hidden_cmds(slave = '') __getip.hidden_cmds(slave) end def invoke_hidden(slave, cmd, *args) raise SecurityError, "no permission to manipulate" unless self.manipulable? if args[-1].kind_of?(Hash) keys = _symbolkey2str(args.pop) else keys = [] end keys << _slavearg(slave) if Tk::TCL_MAJOR_VERSION > 8 || (Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION >= 5) keys << '--' end keys << cmd keys.concat(args) @interp._invoke('interp', 'invokehidden', *keys) end def self.invoke_hidden(slave, cmd, *args) __getip.invoke_hidden(slave, cmd, *args) end def invoke_hidden_on_global(slave, cmd, *args) raise SecurityError, "no permission to manipulate" unless self.manipulable? if args[-1].kind_of?(Hash) keys = _symbolkey2str(args.pop) else keys = [] end keys << _slavearg(slave) keys << '-global' if Tk::TCL_MAJOR_VERSION > 8 || (Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION >= 5) keys << '--' end keys << cmd keys.concat(args) @interp._invoke('interp', 'invokehidden', *keys) end def self.invoke_hidden_on_global(slave, cmd, *args) __getip.invoke_hidden_on_global(slave, cmd, *args) end def invoke_hidden_on_namespace(slave, ns, cmd, *args) # for Tcl8.5 or later raise SecurityError, "no permission to manipulate" unless self.manipulable? if args[-1].kind_of?(Hash) keys = _symbolkey2str(args.pop) else keys = [] end keys << _slavearg(slave) keys << '-namespace' << TkComm._get_eval_string(ns) keys << '--' << cmd keys.concat(args) @interp._invoke('interp', 'invokehidden', *keys) end def self.invoke_hidden_on_namespace(slave, ns, cmd, *args) __getip.invoke_hidden_on_namespace(slave, ns, cmd, *args) end def mark_trusted(slave = '') raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'marktrusted', _slavearg(slave)) self end def self.mark_trusted(slave = '') __getip.mark_trusted(slave) self end def set_bgerror_handler(cmd = Proc.new, slave = nil, &b) raise SecurityError, "no permission to manipulate" unless self.manipulable? unless TkComm._callback_entry?(cmd) if !slave && b slave = cmd cmd = Proc.new(&b) end end slave = '' unless slave @interp._invoke('interp', 'bgerror', _slavearg(slave), cmd) end def self.bgerror(cmd = Proc.new, slave = nil, &b) __getip.bgerror(cmd, slave, &b) end def get_bgerror_handler(slave = '') raise SecurityError, "no permission to manipulate" unless self.manipulable? procedure(@interp._invoke('interp', 'bgerror', _slavearg(slave))) end def self.bgerror(slave = '') __getip.bgerror(slave) end def set_limit(limit_type, slave = '', opts = {}) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'limit', _slavearg(slave), limit_type, opts) end def self.set_limit(limit_type, slave = '', opts = {}) __getip.set_limit(limit_type, slave, opts) end def get_limit(limit_type, slave = '', slot = nil) raise SecurityError, "no permission to manipulate" unless self.manipulable? if slot num_or_str(@interp._invoke('interp', 'limit', _slavearg(slave), limit_type, slot)) else l = @interp._split_tklist(@interp._invoke_without_enc('interp', 'limit', _slavearg(slave), limit_type)) l.map!{|s| _fromUTF8(s)} r = {} until l.empty? key = l.shift[1..-1] val = l.shift val = num_or_str(val) if val r[key] = val end r end end def self.get_limit(limit_type, slave = '', slot = nil) __getip.get_limit(limit_type, slave, slot) end def recursion_limit(slave = '', limit = None) raise SecurityError, "no permission to manipulate" unless self.manipulable? number(@interp._invoke('interp', 'recursionlimit', _slavearg(slave), limit)) end def self.recursion_limit(slave = '', limit = None) __getip.recursion_limit(slave) end def alias_target(aliascmd, slave = '') raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'target', _slavearg(slave), aliascmd) end def self.alias_target(aliascmd, slave = '') __getip.alias_target(aliascmd, slave) end def share_stdin(dist, src = '') raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'share', src, 'stdin', dist) self end def self.share_stdin(dist, src = '') __getip.share_stdin(dist, src) self end def share_stdout(dist, src = '') raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'share', src, 'stdout', dist) self end def self.share_stdout(dist, src = '') __getip.share_stdout(dist, src) self end def share_stderr(dist, src = '') raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'share', src, 'stderr', dist) self end def self.share_stderr(dist, src = '') __getip.share_stderr(dist, src) self end def transfer_stdin(dist, src = '') raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'transfer', src, 'stdin', dist) self end def self.transfer_stdin(dist, src = '') __getip.transfer_stdin(dist, src) self end def transfer_stdout(dist, src = '') raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'transfer', src, 'stdout', dist) self end def self.transfer_stdout(dist, src = '') __getip.transfer_stdout(dist, src) self end def transfer_stderr(dist, src = '') raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'transfer', src, 'stderr', dist) self end def self.transfer_stderr(dist, src = '') __getip.transfer_stderr(dist, src) self end def share_stdio(dist, src = '') raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'share', src, 'stdin', dist) @interp._invoke('interp', 'share', src, 'stdout', dist) @interp._invoke('interp', 'share', src, 'stderr', dist) self end def self.share_stdio(dist, src = '') __getip.share_stdio(dist, src) self end def transfer_stdio(dist, src = '') raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'transfer', src, 'stdin', dist) @interp._invoke('interp', 'transfer', src, 'stdout', dist) @interp._invoke('interp', 'transfer', src, 'stderr', dist) self end def self.transfer_stdio(dist, src = '') __getip.transfer_stdio(dist, src) self end end # Safe Base :: manipulating safe interpreter class MultiTkIp def safeip_configure(slot, value=None) # use for '-noStatics' option ==> {statics=>false} # for '-nestedLoadOk' option ==> {nested=>true} if slot.kind_of?(Hash) ip = MultiTkIp.__getip ip._eval('::safe::interpConfigure ' + @ip_name + ' ' + _keys2opts(slot)) else ip._eval('::safe::interpConfigure ' + @ip_name + ' ' + "-#{slot} #{_get_eval_string(value)}") end self end def safeip_configinfo(slot = nil) ip = MultiTkIp.__getip ret = {} if slot conf = _lst2ary(ip._eval("::safe::interpConfigure " + @ip_name + " -#{slot}")) if conf[0] == '-deleteHook' =begin if conf[1] =~ /^rb_out\S* (c(_\d+_)?\d+)/ ret[conf[0][1..-1]] = MultiTkIp._tk_cmd_tbl[$1] =end if conf[1] =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/ ret[conf[0][1..-1]] = MultiTkIp._tk_cmd_tbl[$4] else ret[conf[0][1..-1]] = conf[1] end else ret[conf[0][1..-1]] = conf[1] end else Hash[*_lst2ary(ip._eval("::safe::interpConfigure " + @ip_name))].each{|k, v| if k == '-deleteHook' =begin if v =~ /^rb_out\S* (c(_\d+_)?\d+)/ ret[k[1..-1]] = MultiTkIp._tk_cmd_tbl[$1] =end if v =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/ ret[k[1..-1]] = MultiTkIp._tk_cmd_tbl[$4] else ret[k[1..-1]] = v end else ret[k[1..-1]] = v end } end ret end def safeip_delete ip = MultiTkIp.__getip ip._eval("::safe::interpDelete " + @ip_name) end def safeip_add_to_access_path(dir) ip = MultiTkIp.__getip ip._eval("::safe::interpAddToAccessPath #{@ip_name} #{dir}") end def safeip_find_in_access_path(dir) ip = MultiTkIp.__getip ip._eval("::safe::interpFindInAccessPath #{@ip_name} #{dir}") end def safeip_set_log_cmd(cmd = Proc.new) ip = MultiTkIp.__getip ip._eval("::safe::setLogCmd #{@ip_name} #{_get_eval_string(cmd)}") end end # encoding convert class << MultiTkIp def encoding_table __getip.encoding_table end end class MultiTkIp def encoding_table @interp.encoding_table end def force_default_encoding=(mode) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.force_default_encoding = mode end def force_default_encoding? raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.force_default_encoding? end def default_encoding=(enc) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.default_encoding = enc end def encoding=(enc) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.encoding = enc end def encoding_name raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.encoding_name end def encoding_obj raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.encoding_obj end alias encoding encoding_name alias default_encoding encoding_name def encoding_convertfrom(str, enc=None) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.encoding_convertfrom(str, enc) end alias encoding_convert_from encoding_convertfrom def encoding_convertto(str, enc=None) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.encoding_convertto(str, enc) end alias encoding_convert_to encoding_convertto end # remove methods for security if MultiTkIp::WITH_RUBY_VM && ! MultiTkIp::RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!! class MultiTkIp INTERP_THREAD = @@DEFAULT_MASTER.instance_variable_get('@interp_thread') INTERP_MUTEX = INTERP_THREAD[:mutex] INTERP_ROOT_CHECK = INTERP_THREAD[:root_check] end module TkCore INTERP_THREAD = MultiTkIp::INTERP_THREAD INTERP_MUTEX = MultiTkIp::INTERP_MUTEX INTERP_ROOT_CHECK = MultiTkIp::INTERP_ROOT_CHECK end class MultiTkIp remove_const(:INTERP_THREAD) remove_const(:INTERP_MUTEX) remove_const(:INTERP_ROOT_CHECK) end end class MultiTkIp # undef_method :instance_eval undef_method :instance_variable_get undef_method :instance_variable_set end # end of MultiTkIp definition # defend against modification #MultiTkIp.freeze #TclTkLib.freeze ######################################## # start Tk which depends on MultiTkIp module TkCore INTERP = MultiTkIp end require 'tk' ================================================ FILE: ext/tk/lib/remote-tk.rb ================================================ # # remote-tk.rb - supports to control remote Tk interpreters # by Hidetoshi NAGAI if defined? MultiTkIp fail RuntimeError, "'remote-tk' library must be required before requiring 'multi-tk'" end class MultiTkIp; end class RemoteTkIp < MultiTkIp; end class MultiTkIp @@IP_TABLE = {}.taint unless defined?(@@IP_TABLE) @@TK_TABLE_LIST = [].taint unless defined?(@@TK_TABLE_LIST) def self._IP_TABLE; @@IP_TABLE; end def self._TK_TABLE_LIST; @@TK_TABLE_LIST; end @flag = true def self._DEFAULT_MASTER # work only once if @flag @flag = nil @@DEFAULT_MASTER else nil end end end class RemoteTkIp @@IP_TABLE = MultiTkIp._IP_TABLE unless defined?(@@IP_TABLE) @@TK_TABLE_LIST = MultiTkIp._TK_TABLE_LIST unless defined?(@@TK_TABLE_LIST) end class << MultiTkIp undef _IP_TABLE undef _TK_TABLE_LIST end require 'multi-tk' class RemoteTkIp if defined?(@@DEFAULT_MASTER) MultiTkIp._DEFAULT_MASTER else @@DEFAULT_MASTER = MultiTkIp._DEFAULT_MASTER end end ############################### class << RemoteTkIp undef new_master, new_slave, new_safe_slave undef new_trusted_slave, new_safeTk def new(*args, &b) ip = __new(*args) ip.eval_proc(&b) if b ip end end class RemoteTkIp def initialize(remote_ip, displayof=nil, timeout=5) if $SAFE >= 4 fail SecurityError, "cannot access another interpreter at level #{$SAFE}" end @interp = MultiTkIp.__getip if @interp.safe? fail SecurityError, "safe-IP cannot create RemoteTkIp" end @interp.allow_ruby_exit = false @appname = @interp._invoke('tk', 'appname') @remote = remote_ip.to_s.dup.freeze if displayof.kind_of?(TkWindow) @displayof = displayof.path.dup.freeze else @displayof = nil end if self.deleted? fail RuntimeError, "no Tk application named \"#{@remote}\"" end @tk_windows = {} @tk_table_list = [] @slave_ip_tbl = {} @slave_ip_top = {} @tk_windows.taint unless @tk_windows.tainted? @tk_table_list.taint unless @tk_table_list.tainted? @slave_ip_tbl.taint unless @slave_ip_tbl.tainted? @slave_ip_top.taint unless @slave_ip_top.tainted? @system = Object.new @threadgroup = ThreadGroup.new @safe_level = [$SAFE] @wait_on_mainloop = [true, 0] @cmd_queue = Queue.new =begin @cmd_receiver, @receiver_watchdog = _create_receiver_and_watchdog() @threadgroup.add @cmd_receiver @threadgroup.add @receiver_watchdog @threadgroup.enclose =end @@DEFAULT_MASTER.assign_receiver_and_watchdog(self) @@IP_TABLE[@threadgroup] = self @@TK_TABLE_LIST.size.times{ (tbl = {}).tainted? || tbl.taint @tk_table_list << tbl } @ret_val = TkVariable.new if timeout > 0 && ! _available_check(timeout) fail RuntimeError, "cannot create connection" end @ip_id = _create_connection class << self undef :instance_eval end self.freeze # defend against modification end def manipulable? return true if (Thread.current.group == ThreadGroup::Default) MultiTkIp.__getip == @interp && ! @interp.safe? end def self.manipulable? true end def _is_master_of?(tcltkip_obj) tcltkip_obj == @interp end protected :_is_master_of? def _ip_id_ @ip_id end def _available_check(timeout = 5) raise SecurityError, "no permission to manipulate" unless self.manipulable? return nil if timeout < 1 @ret_val.value = '' @interp._invoke('send', '-async', @remote, 'send', '-async', Tk.appname, "set #{@ret_val.id} ready") Tk.update if @ret_val != 'ready' (1..(timeout*5)).each{ sleep 0.2 Tk.update break if @ret_val == 'ready' } end @ret_val.value == 'ready' end private :_available_check def _create_connection raise SecurityError, "no permission to manipulate" unless self.manipulable? ip_id = '_' + @interp._invoke('send', @remote, <<-'EOS') + '_' if {[catch {set _rubytk_control_ip_id_} ret] != 0} { set _rubytk_control_ip_id_ 0 } else { set _rubytk_control_ip_id_ [expr $ret + 1] } return $_rubytk_control_ip_id_ EOS @interp._invoke('send', @remote, <<-EOS) proc rb_out#{ip_id} args { send #{@appname} rb_out \$args } EOS ip_id end private :_create_connection def _appsend(enc_mode, async, *cmds) raise SecurityError, "no permission to manipulate" unless self.manipulable? p ['_appsend', [@remote, @displayof], enc_mode, async, cmds] if $DEBUG if $SAFE >= 4 fail SecurityError, "cannot send commands at level 4" elsif $SAFE >= 1 && cmds.find{|obj| obj.tainted?} fail SecurityError, "cannot send tainted commands at level #{$SAFE}" end cmds = @interp._merge_tklist(*TkUtil::_conv_args([], enc_mode, *cmds)) if @displayof if async @interp.__invoke('send', '-async', '-displayof', @displayof, '--', @remote, *cmds) else @interp.__invoke('send', '-displayof', @displayof, '--', @remote, *cmds) end else if async @interp.__invoke('send', '-async', '--', @remote, *cmds) else @interp.__invoke('send', '--', @remote, *cmds) end end end private :_appsend def ready?(timeout=5) if timeout < 0 fail ArgumentError, "timeout must be positive number" end _available_check(timeout) end def is_rubytk? return false if _appsend(false, false, 'info', 'command', 'ruby') == "" [ _appsend(false, false, 'ruby', 'RUBY_VERSION'), _appsend(false, false, 'set', 'tk_patchLevel') ] end def appsend(async, *args) raise SecurityError, "no permission to manipulate" unless self.manipulable? if async != true && async != false && async != nil args.unshift(async) async = false end if @displayof Tk.appsend_displayof(@remote, @displayof, async, *args) else Tk.appsend(@remote, async, *args) end end def rb_appsend(async, *args) raise SecurityError, "no permission to manipulate" unless self.manipulable? if async != true && async != false && async != nil args.unshift(async) async = false end if @displayof Tk.rb_appsend_displayof(@remote, @displayof, async, *args) else Tk.rb_appsend(@remote, async, *args) end end def create_slave(name, safe=false) if safe safe_opt = '' else safe_opt = '-safe' end _appsend(false, false, "interp create #{safe_opt} -- #{name}") end def make_safe fail RuntimeError, 'cannot change safe mode of the remote interpreter' end def safe? _appsend(false, false, 'interp issafe') end def safe_base? false end def allow_ruby_exit? false end def allow_ruby_exit= (mode) fail RuntimeError, 'cannot change mode of the remote interpreter' end def delete _appsend(false, true, 'exit') end def deleted? raise SecurityError, "no permission to manipulate" unless self.manipulable? if @displayof lst = @interp._invoke_without_enc('winfo', 'interps', '-displayof', @displayof) else lst = @interp._invoke_without_enc('winfo', 'interps') end # unless @interp._split_tklist(lst).index(@remote) unless @interp._split_tklist(lst).index(_toUTF8(@remote)) true else false end end def has_mainwindow? raise SecurityError, "no permission to manipulate" unless self.manipulable? begin inf = @interp._invoke_without_enc('info', 'command', '.') rescue Exception return nil end if !inf.kind_of?(String) || inf != '.' false else true end end def invalid_namespace? false end def restart fail RuntimeError, 'cannot restart the remote interpreter' end def __eval(str) _appsend(false, false, str) end def _eval(str) _appsend(nil, false, str) end def _eval_without_enc(str) _appsend(false, false, str) end def _eval_with_enc(str) _appsend(true, false, str) end def _invoke(*args) _appsend(nil, false, *args) end def __invoke(*args) _appsend(false, false, *args) end def _invoke(*args) _appsend(nil, false, *args) end def _invoke_without_enc(*args) _appsend(false, false, *args) end def _invoke_with_enc(*args) _appsend(true, false, *args) end def _toUTF8(str, encoding=nil) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._toUTF8(str, encoding) end def _fromUTF8(str, encoding=nil) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._fromUTF8(str, encoding) end def _thread_vwait(var_name) _appsend(false, 'thread_vwait', varname) end def _thread_tkwait(mode, target) _appsend(false, 'thread_tkwait', mode, target) end def _return_value raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._return_value end def _get_variable(var_name, flag) # ignore flag _appsend(false, 'set', TkComm::_get_eval_string(var_name)) end def _get_variable2(var_name, index_name, flag) # ignore flag _appsend(false, 'set', "#{TkComm::_get_eval_string(var_name)}(#{TkComm::_get_eval_string(index_name)})") end def _set_variable(var_name, value, flag) # ignore flag _appsend(false, 'set', TkComm::_get_eval_string(var_name), TkComm::_get_eval_string(value)) end def _set_variable2(var_name, index_name, value, flag) # ignore flag _appsend(false, 'set', "#{TkComm::_get_eval_string(var_name)}(#{TkComm::_get_eval_string(index_name)})", TkComm::_get_eval_string(value)) end def _unset_variable(var_name, flag) # ignore flag _appsend(false, 'unset', TkComm::_get_eval_string(var_name)) end def _unset_variable2(var_name, index_name, flag) # ignore flag _appsend(false, 'unset', "#{var_name}(#{index_name})") end def _get_global_var(var_name) _appsend(false, 'set', TkComm::_get_eval_string(var_name)) end def _get_global_var2(var_name, index_name) _appsend(false, 'set', "#{TkComm::_get_eval_string(var_name)}(#{TkComm::_get_eval_string(index_name)})") end def _set_global_var(var_name, value) _appsend(false, 'set', TkComm::_get_eval_string(var_name), TkComm::_get_eval_string(value)) end def _set_global_var2(var_name, index_name, value) _appsend(false, 'set', "#{TkComm::_get_eval_string(var_name)}(#{TkComm::_get_eval_string(index_name)})", TkComm::_get_eval_string(value)) end def _unset_global_var(var_name) _appsend(false, 'unset', TkComm::_get_eval_string(var_name)) end def _unset_global_var2(var_name, index_name) _appsend(false, 'unset', "#{var_name}(#{index_name})") end def _split_tklist(str) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._split_tklist(str) end def _merge_tklist(*args) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._merge_tklist(*args) end def _conv_listelement(str) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._conv_listelement(str) end def _create_console fail RuntimeError, 'not support "_create_console" on the remote interpreter' end def mainloop fail RuntimeError, 'not support "mainloop" on the remote interpreter' end def mainloop_watchdog fail RuntimeError, 'not support "mainloop_watchdog" on the remote interpreter' end def do_one_evant(flag = nil) fail RuntimeError, 'not support "do_one_event" on the remote interpreter' end def mainloop_abort_on_exception fail RuntimeError, 'not support "mainloop_abort_on_exception" on the remote interpreter' end def mainloop_abort_on_exception=(mode) fail RuntimeError, 'not support "mainloop_abort_on_exception=" on the remote interpreter' end def set_eventloop_tick(*args) fail RuntimeError, 'not support "set_eventloop_tick" on the remote interpreter' end def get_eventloop_tick fail RuntimeError, 'not support "get_eventloop_tick" on the remote interpreter' end def set_no_event_wait(*args) fail RuntimeError, 'not support "set_no_event_wait" on the remote interpreter' end def get_no_event_wait fail RuntimeError, 'not support "get_no_event_wait" on the remote interpreter' end def set_eventloop_weight(*args) fail RuntimeError, 'not support "set_eventloop_weight" on the remote interpreter' end def get_eventloop_weight fail RuntimeError, 'not support "get_eventloop_weight" on the remote interpreter' end end class << RemoteTkIp def mainloop(*args) fail RuntimeError, 'not support "mainloop" on the remote interpreter' end def mainloop_watchdog(*args) fail RuntimeError, 'not support "mainloop_watchdog" on the remote interpreter' end def do_one_evant(flag = nil) fail RuntimeError, 'not support "do_one_event" on the remote interpreter' end def mainloop_abort_on_exception fail RuntimeError, 'not support "mainloop_abort_on_exception" on the remote interpreter' end def mainloop_abort_on_exception=(mode) fail RuntimeError, 'not support "mainloop_abort_on_exception=" on the remote interpreter' end def set_eventloop_tick(*args) fail RuntimeError, 'not support "set_eventloop_tick" on the remote interpreter' end def get_eventloop_tick fail RuntimeError, 'not support "get_eventloop_tick" on the remote interpreter' end def set_no_event_wait(*args) fail RuntimeError, 'not support "set_no_event_wait" on the remote interpreter' end def get_no_event_wait fail RuntimeError, 'not support "get_no_event_wait" on the remote interpreter' end def set_eventloop_weight(*args) fail RuntimeError, 'not support "set_eventloop_weight" on the remote interpreter' end def get_eventloop_weight fail RuntimeError, 'not support "get_eventloop_weight" on the remote interpreter' end end ================================================ FILE: ext/tk/lib/tcltk.rb ================================================ # tof #### tcltk library, more direct manipulation of tcl/tk #### Sep. 5, 1997 Y. Shigehiro require "tcltklib" ################ # module TclTk: collection of tcl/tk utilities (supplies namespace.) module TclTk # initialize Hash to hold unique symbols and such @namecnt = {} # initialize Hash to hold callbacks @callback = {} end # TclTk.mainloop(): call TclTkLib.mainloop() def TclTk.mainloop() print("mainloop: start\n") if $DEBUG TclTkLib.mainloop() print("mainloop: end\n") if $DEBUG end # TclTk.deletecallbackkey(ca): remove callback from TclTk module # this does not remove callbacks from tcl/tk interpreter # without calling this method, TclTkInterpreter will not be GCed # ca: callback(TclTkCallback) def TclTk.deletecallbackkey(ca) print("deletecallbackkey: ", ca.to_s(), "\n") if $DEBUG @callback.delete(ca.to_s) end # TclTk.dcb(ca, wid, W): call TclTk.deletecallbackkey() for each callbacks # in an array. # this is for callback for top-level # ca: array of callbacks(TclTkCallback) # wid: top-level widget(TclTkWidget) # w: information about window given by %W(String) def TclTk.dcb(ca, wid, w) if wid.to_s() == w ca.each{|i| TclTk.deletecallbackkey(i) } end end # TclTk._addcallback(ca): register callback # ca: callback(TclTkCallback) def TclTk._addcallback(ca) print("_addcallback: ", ca.to_s(), "\n") if $DEBUG @callback[ca.to_s()] = ca end # TclTk._callcallback(key, arg): invoke registered callback # key: key to select callback (to_s value of the TclTkCallback) # arg: parameter from tcl/tk interpreter def TclTk._callcallback(key, arg) print("_callcallback: ", @callback[key].inspect, "\n") if $DEBUG @callback[key]._call(arg) # throw out callback value # should return String to satisfy rb_eval_string() return "" end # TclTk._newname(prefix): generate unique name(String) # prefix: prefix of the unique name def TclTk._newname(prefix) # generated name counter is stored in @namecnt if !@namecnt.key?(prefix) # first appearing prefix, initialize @namecnt[prefix] = 1 else # already appeared prefix, generate next name @namecnt[prefix] += 1 end return "#{prefix}#{@namecnt[prefix]}" end ################ # class TclTkInterpreter: tcl/tk interpreter class TclTkInterpreter # initialize(): def initialize() # generate interpreter object @ip = TclTkIp.new() # add ruby_fmt command to tcl interpreter # ruby_fmt command format arguments by `format' and call `ruby' command # (notice ruby command receives only one argument) if $DEBUG @ip._eval("proc ruby_fmt {fmt args} { puts \"ruby_fmt: $fmt $args\" ; set cmd [list ruby [format $fmt $args]] ; uplevel $cmd }") else @ip._eval("proc ruby_fmt {fmt args} { set cmd [list ruby [format $fmt $args]] ; uplevel $cmd }") end # @ip._get_eval_string(*args): generate string to evaluate in tcl interpreter # *args: script which is going to be evaluated under tcl/tk def @ip._get_eval_string(*args) argstr = "" args.each{|arg| argstr += " " if argstr != "" # call to_eval if it is defined if (arg.respond_to?(:to_eval)) argstr += arg.to_eval() else # call to_s unless defined argstr += arg.to_s() end } return argstr end # @ip._eval_args(*args): evaluate string under tcl/tk interpreter # returns result string. # *args: script which is going to be evaluated under tcl/tk def @ip._eval_args(*args) # calculate the string to eval in the interpreter argstr = _get_eval_string(*args) # evaluate under the interpreter print("_eval: \"", argstr, "\"") if $DEBUG res = _eval(argstr) if $DEBUG print(" -> \"", res, "\"\n") elsif _return_value() != 0 print(res, "\n") end fail(%Q/can't eval "#{argstr}"/) if _return_value() != 0 #' return res end # generate tcl/tk command object and register in the hash @commands = {} # for all commands registered in tcl/tk interpreter: @ip._eval("info command").split(/ /).each{|comname| if comname =~ /^[.]/ # if command is a widget (path), generate TclTkWidget, # and register it in the hash @commands[comname] = TclTkWidget.new(@ip, comname) else # otherwise, generate TclTkCommand @commands[comname] = TclTkCommand.new(@ip, comname) end } end # commands(): returns hash of the tcl/tk commands def commands() return @commands end # rootwidget(): returns root widget(TclTkWidget) def rootwidget() return @commands["."] end # _tcltkip(): returns @ip(TclTkIp) def _tcltkip() return @ip end # method_missing(id, *args): execute undefined method as tcl/tk command # id: method symbol # *args: method arguments def method_missing(id, *args) # if command named by id registered, then execute it if @commands.key?(id.id2name) return @commands[id.id2name].e(*args) else # otherwise, exception super end end end # class TclTkObject: base class of the tcl/tk objects class TclTkObject # initialize(ip, exp): # ip: interpreter(TclTkIp) # exp: tcl/tk representation def initialize(ip, exp) fail("type is not TclTkIp") if !ip.kind_of?(TclTkIp) @ip = ip @exp = exp end # to_s(): returns tcl/tk representation def to_s() return @exp end end # class TclTkCommand: tcl/tk commands # you should not call TclTkCommand.new() # commands are created by TclTkInterpreter:initialize() class TclTkCommand < TclTkObject # e(*args): execute command. returns String (e is for exec or eval) # *args: command arguments def e(*args) return @ip._eval_args(to_s(), *args) end end # class TclTkLibCommand: tcl/tk commands in the library class TclTkLibCommand < TclTkCommand # initialize(ip, name): # ip: interpreter(TclTkInterpreter) # name: command name (String) def initialize(ip, name) super(ip._tcltkip, name) end end # class TclTkVariable: tcl/tk variable class TclTkVariable < TclTkObject # initialize(interp, dat): # interp: interpreter(TclTkInterpreter) # dat: the value to set(String) # if nil, not initialize variable def initialize(interp, dat) # auto-generate tcl/tk representation (variable name) exp = TclTk._newname("v_") # initialize TclTkObject super(interp._tcltkip(), exp) # safe this for `set' command @set = interp.commands()["set"] # set value set(dat) if dat end # although you can set/refer variable by using set in tcl/tk, # we provide the method for accessing variables # set(data): set tcl/tk variable using `set' # data: new value def set(data) @set.e(to_s(), data.to_s()) end # get(): read tcl/tk variable(String) using `set' def get() return @set.e(to_s()) end end # class TclTkWidget: tcl/tk widget class TclTkWidget < TclTkCommand # initialize(*args): # *args: parameters def initialize(*args) if args[0].kind_of?(TclTkIp) # in case the 1st argument is TclTkIp: # Wrap tcl/tk widget by TclTkWidget # (used in TclTkInterpreter#initialize()) # need two arguments fail("invalid # of parameter") if args.size != 2 # ip: interpreter(TclTkIp) # exp: tcl/tk representation ip, exp = args # initialize TclTkObject super(ip, exp) elsif args[0].kind_of?(TclTkInterpreter) # in case 1st parameter is TclTkInterpreter: # generate new widget from parent widget # interp: interpreter(TclTkInterpreter) # parent: parent widget # command: widget generating tk command(label ) # *args: argument to the command interp, parent, command, *args = args # generate widget name exp = parent.to_s() exp += "." if exp !~ /[.]$/ exp += TclTk._newname("w_") # initialize TclTkObject super(interp._tcltkip(), exp) # generate widget res = @ip._eval_args(command, exp, *args) # fail("can't create Widget") if res != exp # for tk_optionMenu, it is legal res != exp else fail("first parameter is not TclTkInterpreter") end end end # class TclTkCallback: tcl/tk callbacks class TclTkCallback < TclTkObject # initialize(interp, pr, arg): # interp: interpreter(TclTkInterpreter) # pr: callback procedure(Proc) # arg: string to pass as block parameters of pr # bind command of tcl/tk uses % replacement for parameters # pr can receive replaced data using block parameter # its format is specified by arg string # You should not specify arg for the command like # scrollbar with -command option, which receives parameters # without specifying any replacement def initialize(interp, pr, arg = nil) # auto-generate tcl/tk representation (variable name) exp = TclTk._newname("c_") # initialize TclTkObject super(interp._tcltkip(), exp) # save parameters @pr = pr @arg = arg # register in the module TclTk._addcallback(self) end # to_eval(): retuens string representation for @ip._eval_args def to_eval() if @arg # bind replaces %s before calling ruby_fmt, so %%s is used s = %Q/{ruby_fmt {TclTk._callcallback("#{to_s()}", "%%s")} #{@arg}}/ else s = %Q/{ruby_fmt {TclTk._callcallback("#{to_s()}", "%s")}}/ end return s end # _call(arg): invoke callback # arg: callback parameter def _call(arg) @pr.call(arg) end end # class TclTkImage: tcl/tk images class TclTkImage < TclTkCommand # initialize(interp, t, *args): # generating image is done by TclTkImage.new() # destrying is done by image delete (inconsistent, sigh) # interp: interpreter(TclTkInterpreter) # t: image type (photo, bitmap, etc.) # *args: command argument def initialize(interp, t, *args) # auto-generate tcl/tk representation exp = TclTk._newname("i_") # initialize TclTkObject super(interp._tcltkip(), exp) # generate image res = @ip._eval_args("image create", t, exp, *args) fail("can't create Image") if res != exp end end # eof ================================================ FILE: ext/tk/lib/tk/after.rb ================================================ # # tk/after.rb : methods for Tcl/Tk after command # # $Id$ # require 'tk/timer' ================================================ FILE: ext/tk/lib/tk/autoload.rb ================================================ # # autoload # ############################################ # geometry manager module Tk autoload :Grid, 'tk/grid' def Grid(*args); TkGrid.configure(*args); end autoload :Pack, 'tk/pack' def Pack(*args); TkPack.configure(*args); end autoload :Place, 'tk/place' def Place(*args); TkPlace.configure(*args); end end autoload :TkGrid, 'tk/grid' def TkGrid(*args); TkGrid.configure(*args); end autoload :TkPack, 'tk/pack' def TkPack(*args); TkPack.configure(*args); end autoload :TkPlace, 'tk/place' def TkPlace(*args); TkPlace.configure(*args); end ############################################ # classes on Tk module module Tk autoload :Button, 'tk/button' autoload :Canvas, 'tk/canvas' autoload :CheckButton, 'tk/checkbutton' autoload :Checkbutton, 'tk/checkbutton' autoload :Entry, 'tk/entry' autoload :Frame, 'tk/frame' autoload :Label, 'tk/label' autoload :LabelFrame, 'tk/labelframe' autoload :Labelframe, 'tk/labelframe' autoload :Listbox, 'tk/listbox' autoload :Menu, 'tk/menu' autoload :MenuClone, 'tk/menu' autoload :CloneMenu, 'tk/menu' autoload :SystemMenu, 'tk/menu' autoload :SysMenu_Help, 'tk/menu' autoload :SysMenu_System, 'tk/menu' autoload :SysMenu_Apple, 'tk/menu' autoload :Menubutton, 'tk/menu' autoload :MenuButton, 'tk/menu' autoload :OptionMenubutton, 'tk/menu' autoload :OptionMenBbutton, 'tk/menu' autoload :Message, 'tk/message' autoload :PanedWindow, 'tk/panedwindow' autoload :Panedwindow, 'tk/panedwindow' autoload :RadioButton, 'tk/radiobutton' autoload :Radiobutton, 'tk/radiobutton' autoload :Root, 'tk/root' autoload :Scale, 'tk/scale' autoload :Scrollbar, 'tk/scrollbar' autoload :XScrollbar, 'tk/scrollbar' autoload :YScrollbar, 'tk/scrollbar' autoload :Spinbox, 'tk/spinbox' autoload :Text, 'tk/text' autoload :Toplevel, 'tk/toplevel' end ############################################ # sub-module of Tk module Tk autoload :Clock, 'tk/clock' autoload :OptionObj, 'tk/optionobj' autoload :X_Scrollable, 'tk/scrollable' autoload :Y_Scrollable, 'tk/scrollable' autoload :Scrollable, 'tk/scrollable' autoload :Wm, 'tk/wm' autoload :Wm_for_General, 'tk/wm' autoload :MacResource, 'tk/macpkg' autoload :WinDDE, 'tk/winpkg' autoload :WinRegistry, 'tk/winpkg' autoload :ValidateConfigure, 'tk/validation' autoload :ItemValidateConfigure, 'tk/validation' autoload :EncodedString, 'tk/encodedstr' def Tk.EncodedString(str, enc = nil); Tk::EncodedString.new(str, enc); end autoload :BinaryString, 'tk/encodedstr' def Tk.BinaryString(str); Tk::BinaryString.new(str); end autoload :UTF8_String, 'tk/encodedstr' def Tk.UTF8_String(str); Tk::UTF8_String.new(str); end end ############################################ # toplevel classes/modules (fixed) autoload :TkBgError, 'tk/bgerror' autoload :TkBindTag, 'tk/bindtag' autoload :TkBindTagAll, 'tk/bindtag' autoload :TkDatabaseClass, 'tk/bindtag' autoload :TkConsole, 'tk/console' autoload :TkcItem, 'tk/canvas' autoload :TkcArc, 'tk/canvas' autoload :TkcBitmap, 'tk/canvas' autoload :TkcImage, 'tk/canvas' autoload :TkcLine, 'tk/canvas' autoload :TkcOval, 'tk/canvas' autoload :TkcPolygon, 'tk/canvas' autoload :TkcRectangle, 'tk/canvas' autoload :TkcText, 'tk/canvas' autoload :TkcWindow, 'tk/canvas' autoload :TkcTagAccess, 'tk/canvastag' autoload :TkcTag, 'tk/canvastag' autoload :TkcTagString, 'tk/canvastag' autoload :TkcNamedTag, 'tk/canvastag' autoload :TkcTagAll, 'tk/canvastag' autoload :TkcTagCurrent, 'tk/canvastag' autoload :TkcTagGroup, 'tk/canvastag' autoload :TkClipboard, 'tk/clipboard' autoload :TkComposite, 'tk/composite' autoload :TkConsole, 'tk/console' autoload :TkDialog, 'tk/dialog' autoload :TkDialog2, 'tk/dialog' autoload :TkDialogObj, 'tk/dialog' autoload :TkWarning, 'tk/dialog' autoload :TkWarning2, 'tk/dialog' autoload :TkWarningObj, 'tk/dialog' autoload :TkEvent, 'tk/event' autoload :TkFont, 'tk/font' autoload :TkNamedFont, 'tk/font' autoload :TkImage, 'tk/image' autoload :TkBitmapImage, 'tk/image' autoload :TkPhotoImage, 'tk/image' autoload :TkItemConfigMethod, 'tk/itemconfig' autoload :TkTreatItemFont, 'tk/itemfont' autoload :TkKinput, 'tk/kinput' autoload :TkSystemMenu, 'tk/menu' autoload :TkMenubar, 'tk/menubar' autoload :TkMenuSpec, 'tk/menuspec' autoload :TkManageFocus, 'tk/mngfocus' autoload :TkMsgCatalog, 'tk/msgcat' autoload :TkMsgCat, 'tk/msgcat' autoload :TkNamespace, 'tk/namespace' autoload :TkOptionDB, 'tk/optiondb' autoload :TkOption, 'tk/optiondb' autoload :TkResourceDB, 'tk/optiondb' autoload :TkPackage, 'tk/package' autoload :TkPalette, 'tk/palette' autoload :TkRoot, 'tk/root' autoload :TkScrollbox, 'tk/scrollbox' autoload :TkSelection, 'tk/selection' autoload :TkTreatTagFont, 'tk/tagfont' autoload :TkTextImage, 'tk/textimage' autoload :TktImage, 'tk/textimage' autoload :TkTextMark, 'tk/textmark' autoload :TkTextNamedMark, 'tk/textmark' autoload :TkTextMarkInsert, 'tk/textmark' autoload :TkTextMarkCurrent, 'tk/textmark' autoload :TkTextMarkAnchor, 'tk/textmark' autoload :TktMark, 'tk/textmark' autoload :TktNamedMark, 'tk/textmark' autoload :TktMarkInsert, 'tk/textmark' autoload :TktMarkCurrent, 'tk/textmark' autoload :TktMarkAnchor, 'tk/textmark' autoload :TkTextTag, 'tk/texttag' autoload :TkTextNamedTag, 'tk/texttag' autoload :TkTextTagSel, 'tk/texttag' autoload :TktTag, 'tk/texttag' autoload :TktNamedTag, 'tk/texttag' autoload :TktTagSel, 'tk/texttag' autoload :TkTextWindow, 'tk/textwindow' autoload :TktWindow, 'tk/textwindow' autoload :TkAfter, 'tk/timer' autoload :TkTimer, 'tk/timer' autoload :TkRTTimer, 'tk/timer' autoload :TkTextWin, 'tk/txtwin_abst' autoload :TkValidation, 'tk/validation' autoload :TkValidateCommand, 'tk/validation' autoload :TkVariable, 'tk/variable' autoload :TkVarAccess, 'tk/variable' autoload :TkVirtualEvent, 'tk/virtevent' autoload :TkNamedVirtualEvent,'tk/virtevent' autoload :TkWinfo, 'tk/winfo' autoload :TkXIM, 'tk/xim' ############################################ # toplevel classes/modules (switchable) module Tk @TOPLEVEL_ALIAS_TABLE = {} @TOPLEVEL_ALIAS_TABLE[:Tk] = { :TkButton => 'tk/button', :TkCanvas => 'tk/canvas', :TkCheckButton => 'tk/checkbutton', :TkCheckbutton => 'tk/checkbutton', # :TkDialog => 'tk/dialog', # :TkDialog2 => 'tk/dialog', # :TkDialogObj => 'tk/dialog', # :TkWarning => 'tk/dialog', # :TkWarning2 => 'tk/dialog', # :TkWarningObj => 'tk/dialog', :TkEntry => 'tk/entry', :TkFrame => 'tk/frame', :TkLabel => 'tk/label', :TkLabelFrame => 'tk/labelframe', :TkLabelframe => 'tk/labelframe', :TkListbox => 'tk/listbox', :TkMacResource => 'tk/macpkg', :TkMenu => 'tk/menu', :TkMenuClone => 'tk/menu', :TkCloneMenu => 'tk/menu', # :TkSystemMenu => 'tk/menu', :TkSysMenu_Help => 'tk/menu', :TkSysMenu_System => 'tk/menu', :TkSysMenu_Apple => 'tk/menu', :TkMenubutton => 'tk/menu', :TkMenuButton => 'tk/menu', :TkOptionMenubutton => 'tk/menu', :TkOptionMenuButton => 'tk/menu', :TkMessage => 'tk/message', :TkPanedWindow => 'tk/panedwindow', :TkPanedwindow => 'tk/panedwindow', :TkRadioButton => 'tk/radiobutton', :TkRadiobutton => 'tk/radiobutton', # :TkRoot => 'tk/root', :TkScale => 'tk/scale', :TkScrollbar => 'tk/scrollbar', :TkXScrollbar => 'tk/scrollbar', :TkYScrollbar => 'tk/scrollbar', :TkSpinbox => 'tk/spinbox', :TkText => 'tk/text', :TkToplevel => 'tk/toplevel', :TkWinDDE => 'tk/winpkg', :TkWinRegistry => 'tk/winpkg', } @TOPLEVEL_ALIAS_OWNER = {} @TOPLEVEL_ALIAS_SETUP_PROC = {} @current_default_widget_set = nil end ############################################ # methods to control default widget set ############################################ class << Tk def default_widget_set @current_default_widget_set end def default_widget_set=(target) target = target.to_sym return target if target == @current_default_widget_set if (cmd = @TOPLEVEL_ALIAS_SETUP_PROC[target]) cmd.call(target) end _replace_toplevel_aliases(target) end def __set_toplevel_aliases__(target, obj, *symbols) @TOPLEVEL_ALIAS_TABLE[target = target.to_sym] ||= {} symbols.each{|sym| @TOPLEVEL_ALIAS_TABLE[target][sym = sym.to_sym] = obj # if @current_default_widget_set == target if @TOPLEVEL_ALIAS_OWNER[sym] == target Object.class_eval{remove_const sym} if Object.const_defined?(sym) Object.const_set(sym, obj) end } end ################################### private def _replace_toplevel_aliases(target) # check already autoloaded if (table = @TOPLEVEL_ALIAS_TABLE[current = @current_default_widget_set]) table.each{|sym, file| if !Object.autoload?(sym) && Object.const_defined?(sym) && @TOPLEVEL_ALIAS_TABLE[current][sym].kind_of?(String) # autoload -> class @TOPLEVEL_ALIAS_TABLE[current][sym] = Object.const_get(sym) end } end # setup autoloads @TOPLEVEL_ALIAS_TABLE[target].each{|sym, file| Object.class_eval{remove_const sym} if Object.const_defined?(sym) if file.kind_of?(String) # file => autoload target file Object.autoload(sym, file) else # file => loaded class object Object.const_set(sym, file) end @TOPLEVEL_ALIAS_OWNER[sym] = target } # update current alias @current_default_widget_set = target end end ############################################ # setup default widget set => :Tk Tk.default_widget_set = :Tk ############################################ # depend on the version of Tcl/Tk # major, minor, type, type_name, patchlevel = TclTkLib.get_version ############################################ # Ttk (Tile) support =begin if major > 8 || (major == 8 && minor > 5) || (major == 8 && minor == 5 && type >= TclTkLib::RELEASE_TYPE::BETA) # Tcl/Tk 8.5 beta or later Object.autoload :Ttk, 'tkextlib/tile' Tk.autoload :Tile, 'tkextlib/tile' require 'tk/ttk_selector' end =end Object.autoload :Ttk, 'tkextlib/tile' Tk.autoload :Tile, 'tkextlib/tile' require 'tk/ttk_selector' ================================================ FILE: ext/tk/lib/tk/bgerror.rb ================================================ # # tkbgerror -- bgerror ( tkerror ) module # 1998/07/16 by Hidetoshi Nagai # require 'tk' module TkBgError extend Tk TkCommandNames = ['bgerror'.freeze].freeze def bgerror(message) tk_call('bgerror', message) end alias tkerror bgerror alias show bgerror module_function :bgerror, :tkerror, :show def set_handler(hdlr = Proc.new) #==> handler :: proc{|msg| ...body... } tk_call('proc', 'bgerror', 'msg', install_cmd(hdlr) + ' $msg') end def set_default begin tk_call('rename', 'bgerror', '') rescue RuntimeError end end module_function :set_handler, :set_default end ================================================ FILE: ext/tk/lib/tk/bindtag.rb ================================================ # # tk/bind.rb : control event binding # require 'tk' class TkBindTag include TkBindCore #BTagID_TBL = {} BTagID_TBL = TkCore::INTERP.create_table (Tk_BINDTAG_ID = ["btag".freeze, "00000".taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } TkCore::INTERP.init_ip_env{ BTagID_TBL.mutex.synchronize{ BTagID_TBL.clear } } def TkBindTag.id2obj(id) BTagID_TBL.mutex.synchronize{ (BTagID_TBL[id])? BTagID_TBL[id]: id } end =begin def TkBindTag.new_by_name(name, *args, &b) BTagID_TBL.mutex.synchronize{ return BTagID_TBL[name] if BTagID_TBL[name] } self.new.instance_eval{ BTagID_TBL.mutex.synchronize{ BTagID_TBL.delete @id @id = name BTagID_TBL[@id] = self } bind(*args, &b) if args != [] self } end =end def TkBindTag.new_by_name(name, *args, &b) obj = nil BTagID_TBL.mutex.synchronize{ if BTagID_TBL[name] obj = BTagID_TBL[name] else (obj = BTagID_TBL[name] = self.allocate).instance_eval{ @id = name } end } bind(*args, &b) if obj && args != [] obj end def initialize(*args, &b) Tk_BINDTAG_ID.mutex.synchronize{ # @id = Tk_BINDTAG_ID.join('') @id = Tk_BINDTAG_ID.join(TkCore::INTERP._ip_id_) Tk_BINDTAG_ID[1].succ! } BTagID_TBL.mutex.synchronize{ BTagID_TBL[@id] = self } bind(*args, &b) if args != [] end ALL = self.new_by_name('all') def name @id end def to_eval @id end def inspect #Kernel.format "#", @id '#' end end class TkBindTagAll", @id '#' end end ================================================ FILE: ext/tk/lib/tk/button.rb ================================================ # # tk/button.rb : treat button widget # require 'tk' require 'tk/label' class Tk::Button # require 'tk' require 'tk/canvastag' require 'tk/itemconfig' require 'tk/scrollable' module TkCanvasItemConfig include TkItemConfigMethod def __item_strval_optkeys(id) # maybe need to override super(id) + [ 'fill', 'activefill', 'disabledfill', 'outline', 'activeoutline', 'disabledoutline' ] end private :__item_strval_optkeys def __item_methodcall_optkeys(id) {'coords'=>'coords'} end private :__item_methodcall_optkeys def __item_val2ruby_optkeys(id) # { key=>proc, ... } super(id).update('window'=>proc{|i, v| window(v)}) end private :__item_val2ruby_optkeys def __item_pathname(tagOrId) if tagOrId.kind_of?(TkcItem) || tagOrId.kind_of?(TkcTag) self.path + ';' + tagOrId.id.to_s else self.path + ';' + tagOrId.to_s end end private :__item_pathname end class Tk::Canvasvalue}) end else _fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId), "-#{key}", _get_eval_enc_str(value))) end end self end # def itemconfigure(tagOrId, key, value=None) # if key.kind_of? Hash # tk_send 'itemconfigure', tagid(tagOrId), *hash_kv(key) # else # tk_send 'itemconfigure', tagid(tagOrId), "-#{key}", value # end # end # def itemconfigure(tagOrId, keys) # tk_send 'itemconfigure', tagid(tagOrId), *hash_kv(keys) # end def itemconfiginfo(tagOrId, key=nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if key case key.to_s when 'coords' return ['coords', '', '', '', self.coords(tagOrId)] when 'dash', 'activedash', 'disableddash' conf = tk_split_simplelist(tk_send_without_enc('itemconfigure', tagid(tagOrId), "-#{key}")) if conf[3] && conf[3] =~ /^[0-9]/ conf[3] = list(conf[3]) end if conf[4] && conf[4] =~ /^[0-9]/ conf[4] = list(conf[4]) end when 'text', 'label', 'show', 'data', 'file', 'maskdata', 'maskfile' conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId), "-#{key}"))) when 'font', 'kanjifont' conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId),"-#{key}"))) conf[4] = tagfont_configinfo(tagid(tagOrId), conf[4]) else conf = tk_split_list(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId), "-#{key}"))) end conf[0] = conf[0][1..-1] conf else ret = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId)))).collect{|conflist| conf = tk_split_simplelist(conflist) conf[0] = conf[0][1..-1] case conf[0] when 'text', 'label', 'show', 'data', 'file', 'maskdata', 'maskfile' when 'dash', 'activedash', 'disableddash' if conf[3] && conf[3] =~ /^[0-9]/ conf[3] = list(conf[3]) end if conf[4] && conf[4] =~ /^[0-9]/ conf[4] = list(conf[4]) end else if conf[3] if conf[3].index('{') conf[3] = tk_split_list(conf[3]) else conf[3] = tk_tcl2ruby(conf[3]) end end if conf[4] if conf[4].index('{') conf[4] = tk_split_list(conf[4]) else conf[4] = tk_tcl2ruby(conf[4]) end end end conf[1] = conf[1][1..-1] if conf.size == 2 # alias info conf } fontconf = ret.assoc('font') if fontconf ret.delete_if{|item| item[0] == 'font' || item[0] == 'kanjifont'} fontconf[4] = tagfont_configinfo(tagid(tagOrId), fontconf[4]) ret.push(fontconf) end ret << ['coords', '', '', '', self.coords(tagOrId)] end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY if key case key.to_s when 'coords' {'coords' => ['', '', '', self.coords(tagOrId)]} when 'dash', 'activedash', 'disableddash' conf = tk_split_simplelist(tk_send_without_enc('itemconfigure', tagid(tagOrId), "-#{key}")) if conf[3] && conf[3] =~ /^[0-9]/ conf[3] = list(conf[3]) end if conf[4] && conf[4] =~ /^[0-9]/ conf[4] = list(conf[4]) end when 'text', 'label', 'show', 'data', 'file', 'maskdata', 'maskfile' conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId), "-#{key}"))) when 'font', 'kanjifont' conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId),"-#{key}"))) conf[4] = tagfont_configinfo(tagid(tagOrId), conf[4]) else conf = tk_split_list(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId), "-#{key}"))) end key = conf.shift[1..-1] { key => conf } else ret = {} tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId)))).each{|conflist| conf = tk_split_simplelist(conflist) key = conf.shift[1..-1] case key when 'text', 'label', 'show', 'data', 'file', 'maskdata', 'maskfile' when 'dash', 'activedash', 'disableddash' if conf[2] && conf[2] =~ /^[0-9]/ conf[2] = list(conf[2]) end if conf[3] && conf[3] =~ /^[0-9]/ conf[3] = list(conf[3]) end else if conf[2] if conf[2].index('{') conf[2] = tk_split_list(conf[2]) else conf[2] = tk_tcl2ruby(conf[2]) end end if conf[3] if conf[3].index('{') conf[3] = tk_split_list(conf[3]) else conf[3] = tk_tcl2ruby(conf[3]) end end end if conf.size == 1 ret[key] = conf[0][1..-1] # alias info else ret[key] = conf end } fontconf = ret['font'] if fontconf ret.delete('font') ret.delete('kanjifont') fontconf[3] = tagfont_configinfo(tagid(tagOrId), fontconf[3]) ret['font'] = fontconf end ret['coords'] = ['', '', '', self.coords(tagOrId)] ret end end end def current_itemconfiginfo(tagOrId, key=nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if key conf = itemconfiginfo(tagOrId, key) {conf[0] => conf[4]} else ret = {} itemconfiginfo(tagOrId).each{|conf| ret[conf[0]] = conf[4] if conf.size > 2 } ret end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY ret = {} itemconfiginfo(tagOrId, key).each{|k, conf| ret[k] = conf[-1] if conf.kind_of?(Array) } ret end end =end def lower(tag, below=nil) if below tk_send_without_enc('lower', tagid(tag), tagid(below)) else tk_send_without_enc('lower', tagid(tag)) end self end def move(tag, x, y) tk_send_without_enc('move', tagid(tag), x, y) self end def postscript(keys) tk_send("postscript", *hash_kv(keys)) end def raise(tag, above=nil) if above tk_send_without_enc('raise', tagid(tag), tagid(above)) else tk_send_without_enc('raise', tagid(tag)) end self end def scale(tag, x, y, xs, ys) tk_send_without_enc('scale', tagid(tag), x, y, xs, ys) self end def scan_mark(x, y) tk_send_without_enc('scan', 'mark', x, y) self end def scan_dragto(x, y, gain=None) tk_send_without_enc('scan', 'dragto', x, y, gain) self end def select(mode, *args) r = tk_send_without_enc('select', mode, *args) (mode == 'item')? TkcItem.id2obj(self, r): self end def select_adjust(tagOrId, index) select('adjust', tagid(tagOrId), index) end def select_clear select('clear') end def select_from(tagOrId, index) select('from', tagid(tagOrId), index) end def select_item select('item') end def select_to(tagOrId, index) select('to', tagid(tagOrId), index) end def itemtype(tag) TkcItem.type2class(tk_send('type', tagid(tag))) end end #TkCanvas = Tk::Canvas unless Object.const_defined? :TkCanvas Tk.__set_toplevel_aliases__(:Tk, Tk::Canvas, :TkCanvas) class TkcItem "(t1)&&(t2)" # ltag = tag1 | tag2; ltag.path => "(t1)||(t2)" # ltag = tag1 ^ tag2; ltag.path => "(t1)^(t2)" # ltag = - tag1; ltag.path => "!(t1)" def & (tag) if tag.kind_of? TkObject TkcTagString.new(@c, '(' + @id + ')&&(' + tag.path + ')') else TkcTagString.new(@c, '(' + @id + ')&&(' + tag.to_s + ')') end end def | (tag) if tag.kind_of? TkObject TkcTagString.new(@c, '(' + @id + ')||(' + tag.path + ')') else TkcTagString.new(@c, '(' + @id + ')||(' + tag.to_s + ')') end end def ^ (tag) if tag.kind_of? TkObject TkcTagString.new(@c, '(' + @id + ')^(' + tag.path + ')') else TkcTagString.new(@c, '(' + @id + ')^(' + tag.to_s + ')') end end def -@ TkcTagString.new(@c, '!(' + @id + ')') end end class TkcTag use ancestor's name base_class_name = klass.name end else # not subclass -> use WidgetClassName base_class_name = klass.name end else # klass is invalid for the base frame #if self.class < TkFrame || self.class.superclass < TkComposite if self.class < TkFrame || self.class.superclass < Tk::Frame || self.class.superclass < TkComposite # my class name is valid for the base frame -> use my classname base_class_name = self.class.name if base_class_name == '' # anonymous class -> use TkFrame base_class_name = nil end else # no idea for the base frame -> use TkFrame base_class_name = nil end end elsif self.class::WidgetClassName && ! self.class::WidgetClassName.empty? # unknown WidgetClassName is defined -> use it for the base frame base_class_name = self.class::WidgetClassName else # no valid WidgetClassName #if self.class < TkFrame || self.class.superclass < TkComposite if self.class < TkFrame || self.class.superclass < Tk::Frame || self.class.superclass < TkComposite # my class name is valid for the base frame -> use my classname base_class_name = self.class.name if base_class_name == '' # anonymous class -> use TkFrame base_class_name = nil end else # no idea for the base frame -> use TkFrame base_class_name = nil end end base_class_name end private :_choice_classname_of_baseframe # def initialize(parent=nil, *args) def initialize(*args) @delegates = {} @option_methods = {} @option_setting = {} if args[-1].kind_of?(Hash) keys = _symbolkey2str(args.pop) else keys = {} end parent = args.shift parent = keys.delete('parent') if keys.has_key?('parent') if keys.key?('classname') keys['class'] = keys.delete('classname') end if (base_class_name = (keys.delete('class')).to_s).empty? base_class_name = _choice_classname_of_baseframe end if base_class_name # @frame = Tk::Frame.new(parent, :class=>base_class_name) # --> use current TkFrame class @frame = TkFrame.new(parent, :class=>base_class_name) else # @frame = Tk::Frame.new(parent) # --> use current TkFrame class @frame = TkFrame.new(parent) end @path = @epath = @frame.path args.push(keys) unless keys.empty? initialize_composite(*args) end def database_classname @frame.database_classname end def database_class @frame.database_class end def epath @epath end def initialize_composite(*args) end private :initialize_composite def inspect str = super str.chop << ' @epath=' << @epath.inspect << '>' end def option_methods(*opts) opts.each{|m_set, m_cget, m_info| m_set = m_set.to_s m_cget = m_set if !m_cget && self.method(m_set).arity == -1 m_cget = m_cget.to_s if m_cget m_info = m_info.to_s if m_info @option_methods[m_set] = { :set => m_set, :cget => m_cget, :info => m_info } } end def delegate_alias(alias_opt, option, *wins) if wins.length == 0 fail ArgumentError, "target widgets are not given" end if alias_opt != option && (alias_opt == 'DEFAULT' || option == 'DEFAULT') fail ArgumentError, "cannot alias 'DEFAULT' option" end alias_opt = alias_opt.to_s option = option.to_s if @delegates[alias_opt].kind_of?(Array) if (elem = @delegates[alias_opt].assoc(option)) wins.each{|w| elem[1].push(w)} else @delegates[alias_opt] << [option, wins] end else @delegates[alias_opt] = [ [option, wins] ] end end def delegate(option, *wins) delegate_alias(option, option, *wins) end def __cget_delegates(slot) slot = slot.to_s if @option_methods.include?(slot) if @option_methods[slot][:cget] return self.__send__(@option_methods[slot][:cget]) else if @option_setting[slot] return @option_setting[slot] else return '' end end end tbl = @delegates[slot] tbl = @delegates['DEFAULT'] unless tbl begin if tbl opt, wins = tbl[-1] opt = slot if opt == 'DEFAULT' if wins && wins[-1] # return wins[-1].cget(opt) return wins[-1].cget_strict(opt) end end rescue end return None end private :__cget_delegates def cget(slot) if (ret = __cget_delegates(slot)) == None super(slot) else ret end end def cget_strict(slot) if (ret = __cget_delegates(slot)) == None super(slot) else ret end end =begin def cget(slot) slot = slot.to_s if @option_methods.include?(slot) if @option_methods[slot][:cget] return self.__send__(@option_methods[slot][:cget]) else if @option_setting[slot] return @option_setting[slot] else return '' end end end tbl = @delegates[slot] tbl = @delegates['DEFAULT'] unless tbl begin if tbl opt, wins = tbl[-1] opt = slot if opt == 'DEFAULT' if wins && wins[-1] return wins[-1].cget(opt) end end rescue end super(slot) end =end def configure(slot, value=None) if slot.kind_of? Hash slot.each{|slot,value| configure slot, value} return self end slot = slot.to_s if @option_methods.include?(slot) unless @option_methods[slot][:cget] if value.kind_of?(Symbol) @option_setting[slot] = value.to_s else @option_setting[slot] = value end end return self.__send__(@option_methods[slot][:set], value) end tbl = @delegates[slot] tbl = @delegates['DEFAULT'] unless tbl begin if tbl last = nil tbl.each{|opt, wins| opt = slot if opt == 'DEFAULT' wins.each{|w| last = w.configure(opt, value)} } return last end rescue end super(slot, value) end def configinfo(slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if slot slot = slot.to_s if @option_methods.include?(slot) if @option_methods[slot][:info] return self.__send__(@option_methods[slot][:info]) else return [slot, '', '', '', self.cget(slot)] end end tbl = @delegates[slot] tbl = @delegates['DEFAULT'] unless tbl begin if tbl if tbl.length == 1 opt, wins = tbl[0] if slot == opt || opt == 'DEFAULT' return wins[-1].configinfo(slot) else info = wins[-1].configinfo(opt) info[0] = slot return info end else opt, wins = tbl[-1] return [slot, '', '', '', wins[-1].cget(opt)] end end rescue end super(slot) else # slot == nil info_list = super(slot) tbl = @delegates['DEFAULT'] if tbl wins = tbl[0][1] if wins && wins[-1] wins[-1].configinfo.each{|info| slot = info[0] info_list.delete_if{|i| i[0] == slot} << info } end end @delegates.each{|slot, tbl| next if slot == 'DEFAULT' if tbl.length == 1 opt, wins = tbl[0] next unless wins && wins[-1] if slot == opt info_list.delete_if{|i| i[0] == slot} << wins[-1].configinfo(slot) else info = wins[-1].configinfo(opt) info[0] = slot info_list.delete_if{|i| i[0] == slot} << info end else opt, wins = tbl[-1] info_list.delete_if{|i| i[0] == slot} << [slot, '', '', '', wins[-1].cget(opt)] end } @option_methods.each{|slot, m| if m[:info] info = self.__send__(m[:info]) else info = [slot, '', '', '', self.cget(slot)] end info_list.delete_if{|i| i[0] == slot} << info } info_list end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY if slot slot = slot.to_s if @option_methods.include?(slot) if @option_methods[slot][:info] return self.__send__(@option_methods[slot][:info]) else return {slot => ['', '', '', self.cget(slot)]} end end tbl = @delegates[slot] tbl = @delegates['DEFAULT'] unless tbl begin if tbl if tbl.length == 1 opt, wins = tbl[0] if slot == opt || opt == 'DEFAULT' return wins[-1].configinfo(slot) else return {slot => wins[-1].configinfo(opt)[opt]} end else opt, wins = tbl[-1] return {slot => ['', '', '', wins[-1].cget(opt)]} end end rescue end super(slot) else # slot == nil info_list = super(slot) tbl = @delegates['DEFAULT'] if tbl wins = tbl[0][1] info_list.update(wins[-1].configinfo) if wins && wins[-1] end @delegates.each{|slot, tbl| next if slot == 'DEFAULT' if tbl.length == 1 opt, wins = tbl[0] next unless wins && wins[-1] if slot == opt info_list.update(wins[-1].configinfo(slot)) else info_list.update({slot => wins[-1].configinfo(opt)[opt]}) end else opt, wins = tbl[-1] info_list.update({slot => ['', '', '', wins[-1].cget(opt)]}) end } @option_methods.each{|slot, m| if m[:info] info = self.__send__(m[:info]) else info = {slot => ['', '', '', self.cget(slot)]} end info_list.update(info) } info_list end end end end ================================================ FILE: ext/tk/lib/tk/console.rb ================================================ # # tk/console.rb : control the console on system without a real console # require 'tk' module TkConsole include Tk extend Tk TkCommandNames = ['console'.freeze, 'consoleinterp'.freeze].freeze def self.create TkCore::INTERP._create_console end self.create # initialize console def self.title(str=None) tk_call 'console', str end def self.hide tk_call_without_enc('console', 'hide') end def self.show tk_call_without_enc('console', 'show') end def self.eval(tcl_script) # # supports a Tcl script only # I have no idea to support a Ruby script seamlessly. # _fromUTF8(tk_call_without_enc('console', 'eval', _get_eval_enc_str(tcl_script))) end def self.maininterp_eval(tcl_script) # # supports a Tcl script only # I have no idea to support a Ruby script seamlessly. # _fromUTF8(tk_call_without_enc('consoleinterp', 'eval', _get_eval_enc_str(tcl_script))) end def self.maininterp_record(tcl_script) # # supports a Tcl script only # I have no idea to support a Ruby script seamlessly. # _fromUTF8(tk_call_without_enc('consoleinterp', 'record', _get_eval_enc_str(tcl_script))) end end ================================================ FILE: ext/tk/lib/tk/dialog.rb ================================================ # # tk/dialog.rb : create dialog boxes # require 'tk' require 'tk/variable.rb' class TkDialogObj < TkWindow extend Tk TkCommandNames = ['tk_dialog'.freeze].freeze def self.show(*args) dlog = self.new(*args) dlog.show dlog end def _set_button_config(configs) set_config = proc{|c,i| if $VERBOSE && (c.has_key?('command') || c.has_key?(:command)) STDERR.print("Warning: cannot give a command option " + "to the dialog button#{i}. It was removed.\n") end c.delete('command'); c.delete(:command) # @config << Kernel.format("%s.button%s configure %s; ", # @path, i, hash_kv(c).join(' ')) # @config << @path+'.button'+i.to_s+' configure '+hash_kv(c).join(' ')+'; ' @config << @path+'.button'+i.to_s+' configure '+ array2tk_list(hash_kv(c))+'; ' } case configs when Proc @buttons.each_index{|i| if (c = configs.call(i)).kind_of?(Hash) set_config.call(c,i) end } when Array @buttons.each_index{|i| if (c = configs[i]).kind_of?(Hash) set_config.call(c,i) end } when Hash @buttons.each_with_index{|s,i| if (c = configs[s]).kind_of?(Hash) set_config.call(c,i) end } end # @config = 'after idle {' + @config + '};' if @config != "" @config = array2tk_list(['after', 'idle', @config]) << ';' if @config != "" end private :_set_button_config # initialize tk_dialog def create_self(keys) # @var = TkVariable.new @val = nil @title = title @message = message @message_config = message_config @msgframe_config = msgframe_config @bitmap = bitmap @bitmap_config = message_config @default_button = default_button @buttons = buttons @button_configs = proc{|num| button_configs(num)} @btnframe_config = btnframe_config #@config = "puts [winfo children .w0000];" @config = "" @command = prev_command if keys.kind_of?(Hash) @title = keys['title'] if keys.key? 'title' @message = keys['message'] if keys.key? 'message' @bitmap = keys['bitmap'] if keys.key? 'bitmap' # @bitmap = '{}' if @bitmap == nil || @bitmap == "" @bitmap = '' unless @bitmap @default_button = keys['default'] if keys.key? 'default' @buttons = keys['buttons'] if keys.key? 'buttons' @command = keys['prev_command'] if keys.key? 'prev_command' @message_config = keys['message_config'] if keys.key? 'message_config' @msgframe_config = keys['msgframe_config'] if keys.key? 'msgframe_config' @bitmap_config = keys['bitmap_config'] if keys.key? 'bitmap_config' @button_configs = keys['button_configs'] if keys.key? 'button_configs' @btnframe_config = keys['btnframe_config'] if keys.key? 'btnframe_config' end #if @title.include? ?\s # @title = '{' + @title + '}' #end if @buttons.kind_of?(Array) _set_button_config(@buttons.collect{|cfg| (cfg.kind_of? Array)? cfg[1]: nil}) @buttons = @buttons.collect{|cfg| (cfg.kind_of? Array)? cfg[0]: cfg} end if @buttons.kind_of?(Hash) _set_button_config(@buttons) @buttons = @buttons.keys end @buttons = tk_split_simplelist(@buttons) if @buttons.kind_of?(String) @buttons = [] unless @buttons =begin @buttons = @buttons.collect{|s| if s.kind_of?(Array) s = s.join(' ') end if s.include? ?\s '{' + s + '}' else s end } =end if @message_config.kind_of?(Hash) # @config << Kernel.format("%s.msg configure %s;", # @path, hash_kv(@message_config).join(' ')) # @config << @path+'.msg configure '+hash_kv(@message_config).join(' ')+';' @config << @path+'.msg configure '+ array2tk_list(hash_kv(@message_config))+';' end if @msgframe_config.kind_of?(Hash) # @config << Kernel.format("%s.top configure %s;", # @path, hash_kv(@msgframe_config).join(' ')) # @config << @path+'.top configure '+hash_kv(@msgframe_config).join(' ')+';' @config << @path+'.top configure '+ array2tk_list(hash_kv(@msgframe_config))+';' end if @btnframe_config.kind_of?(Hash) # @config << Kernel.format("%s.bot configure %s;", # @path, hash_kv(@btnframe_config).join(' ')) # @config << @path+'.bot configure '+hash_kv(@btnframe_config).join(' ')+';' @config << @path+'.bot configure '+ array2tk_list(hash_kv(@btnframe_config))+';' end if @bitmap_config.kind_of?(Hash) # @config << Kernel.format("%s.bitmap configure %s;", # @path, hash_kv(@bitmap_config).join(' ')) # @config << @path+'.bitmap configure '+hash_kv(@bitmap_config).join(' ')+';' @config << @path+'.bitmap configure '+ array2tk_list(hash_kv(@bitmap_config))+';' end _set_button_config(@button_configs) if @button_configs end private :create_self def show # if @command.kind_of?(Proc) if TkComm._callback_entry?(@command) @command.call(self) end if @default_button.kind_of?(String) default_button = @buttons.index(@default_button) else default_button = @default_button end # default_button = '{}' if default_button == nil default_button = '' if default_button == nil #Tk.ip_eval('eval {global '+@var.id+';'+@config+ # 'set '+@var.id+' [tk_dialog '+ # @path+" "+@title+" {#{@message}} "+@bitmap+" "+ # String(default_button)+" "+@buttons.join(' ')+']}') Tk.ip_eval(@config) # @val = Tk.ip_eval('tk_dialog ' + @path + ' ' + @title + # ' {' + @message + '} ' + @bitmap + ' ' + # String(default_button) + ' ' + @buttons.join(' ')).to_i # @val = Tk.ip_eval(self.class::TkCommandNames[0] + ' ' + @path + ' ' + # @title + ' {' + @message + '} ' + @bitmap + ' ' + # String(default_button) + ' ' + @buttons.join(' ')).to_i @val = Tk.ip_eval(array2tk_list([ self.class::TkCommandNames[0], @path, @title, @message, @bitmap, String(default_button) ].concat(@buttons))).to_i end def value # @var.value.to_i @val end def name (@val)? @buttons[@val]: nil end ############################################################ # # # following methods should be overridden for each dialog # # # ############################################################ private def title # returns a title string of the dialog window return "DIALOG" end def message # returns a message text to display on the dialog return "MESSAGE" end def message_config # returns a Hash {option=>value, ...} for the message text return nil end def msgframe_config # returns a Hash {option=>value, ...} for the message text frame return nil end def bitmap # returns a bitmap name or a bitmap file path # (@ + path ; e.g. '@/usr/share/bitmap/sample.xbm') return "info" end def bitmap_config # returns nil or a Hash {option=>value, ...} for the bitmap return nil end def default_button # returns a default button's number or name # if nil or null string, set no-default return 0 end def buttons #return "BUTTON1 BUTTON2" return ["BUTTON1", "BUTTON2"] end def button_configs(num) # returns nil / Proc / Array or Hash (see _set_button_config) return nil end def btnframe_config # returns nil or a Hash {option=>value, ...} for the button frame return nil end def prev_command # returns nil or a Proc return nil end end TkDialog2 = TkDialogObj # # TkDialog : with showing at initialize # class TkDialog < TkDialogObj def self.show(*args) self.new(*args) end def initialize(*args) super(*args) show end end # # dialog for warning # class TkWarningObj < TkDialogObj def initialize(parent = nil, mes = nil) if !mes if parent.kind_of?(TkWindow) mes = "" else mes = parent.to_s parent = nil end end super(parent, :message=>mes) end def show(mes = nil) mes_bup = @message @message = mes if mes ret = super() @message = mes_bup ret end ####### private def title return "WARNING"; end def bitmap return "warning"; end def default_button return 0; end def buttons return "OK"; end end TkWarning2 = TkWarningObj class TkWarning < TkWarningObj def self.show(*args) self.new(*args) end def initialize(*args) super(*args) show end end ================================================ FILE: ext/tk/lib/tk/encodedstr.rb ================================================ # # tk/encodedstr.rb : Tk::EncodedString class # require 'tk' ########################################### # string with Tcl's encoding ########################################### module Tk class EncodedString < String Encoding = nil def self.subst_utf_backslash(str) # str.gsub(/\\u([0-9A-Fa-f]{1,4})/){[$1.hex].pack('U')} TclTkLib._subst_UTF_backslash(str) end def self.utf_backslash(str) self.subst_utf_backslash(str) end def self.subst_tk_backslash(str) TclTkLib._subst_Tcl_backslash(str) end def self.utf_to_backslash_sequence(str) str.unpack('U*').collect{|c| if c <= 0xFF # ascii character c.chr else format('\u%X', c) end }.join('') end def self.utf_to_backslash(str) self.utf_to_backslash_sequence(str) end def self.to_backslash_sequence(str) str.unpack('U*').collect{|c| if c <= 0x1F # control character case c when 0x07; '\a' when 0x08; '\b' when 0x09; '\t' when 0x0a; '\n' when 0x0b; '\v' when 0x0c; '\f' when 0x0d; '\r' else format('\x%02X', c) end elsif c <= 0xFF # ascii character c.chr else format('\u%X', c) end }.join('') end def self.new_with_utf_backslash(str, enc = nil) self.new('', enc).replace(self.subst_utf_backslash(str)) end def self.new_without_utf_backslash(str, enc = nil) self.new('', enc).replace(str) end def initialize(str, enc = nil) super(str) # @encoding = ( enc || # ((self.class::Encoding)? # self.class::Encoding : Tk.encoding_system) ) enc ||= (self.class::Encoding)? self.class::Encoding : ((Tk.encoding)? Tk.encoding : Tk.encoding_system) if TkCore::WITH_ENCODING unless encobj = Tk::Encoding::ENCODING_TABLE.get_obj(enc) fail ArgumentError, "unsupported Tk encoding '#{enc}'" end self.force_encoding(encobj) else @encoding = enc end end if TkCore::WITH_ENCODING alias encoding_obj encoding alias __encoding encoding def encoding Tk::Encoding::ENCODING_TABLE.get_name(super()) end else def encoding @encoding end alias encoding_obj encoding end if TkCore::WITH_ENCODING # wrapper methods for compatibility alias __instance_variable_get instance_variable_get alias __instance_variable_set instance_variable_set alias __instance_eval instance_eval alias __instance_variables instance_variables def instance_variable_get(key) if (key.to_s == '@encoding') self.encoding else super(key) end end def instance_variable_set(key, value) if (key.to_s == '@encoding') if value self.force_encoding(value) else self.force_encoding(Tk::Encoding::UNKNOWN) end value else super(key, value) end end def instance_eval(*args, &b) old_enc = @encoding = self.encoding ret = super(*args, &b) if @encoding if @encoding != old_enc # modified by user self.force_encoding(@encoding) end remove_instance_variable(:@encoding) else begin remove_instance_variable(:@encoding) # user sets to nil -> use current default self.force_encoding(Tk.encoding) rescue NameError # removed by user -> ignore, because user don't use @encoding end end ret end end def instance_variables ret = super() ret << :@encoding # fake !! ret end end # def Tk.EncodedString(str, enc = nil) # Tk::EncodedString.new(str, enc) # end ################################## class BinaryString < EncodedString Encoding = 'binary'.freeze end # def Tk.BinaryString(str) # Tk::BinaryString.new(str) # end ################################## class UTF8_String < EncodedString Encoding = 'utf-8'.freeze def self.new(str) super(self.subst_utf_backslash(str)) end def to_backslash_sequence Tk::EncodedString.utf_to_backslash_sequence(self) end alias to_backslash to_backslash_sequence end # def Tk.UTF8_String(str) # Tk::UTF8_String.new(str) # end end ================================================ FILE: ext/tk/lib/tk/entry.rb ================================================ # # tk/entry.rb - Tk entry classes # by Yukihiro Matsumoto require 'tk' require 'tk/label' require 'tk/scrollable' require 'tk/validation' class Tk::Entry flag 'above' => Grp::CONFIG, 'borderwidth' => (Grp::CREATE|Grp::CONFIG), 'button' => Grp::BUTTON, 'count' => Grp::EXPOSE, 'data' => (Grp::VIRTUAL|Grp::STRING_DATA), 'delta' => Grp::MWHEEL, 'detail' => (Grp::FOCUS|Grp::CROSSING), 'focus' => Grp::CROSSING, 'height' => (Grp::EXPOSE|Grp::CONFIG), 'keycode' => Grp::KEY, 'keysym' => Grp::KEY, 'mode' => (Grp::CROSSING|Grp::FOCUS), 'override' => (Grp::CREATE|Grp::MAP|Grp::REPARENT|Grp::CONFIG), 'place' => Grp::CIRC, 'root' => (Grp::KEY_BUTTON_MOTION_VIRTUAL|Grp::CROSSING), 'rootx' => (Grp::KEY_BUTTON_MOTION_VIRTUAL|Grp::CROSSING), 'rooty' => (Grp::KEY_BUTTON_MOTION_VIRTUAL|Grp::CROSSING), 'sendevent' => Grp::ALL, 'serial' => Grp::ALL, 'state' => (Grp::KEY_BUTTON_MOTION_VIRTUAL| Grp::CROSSING|Grp::VISIBILITY), 'subwindow' => (Grp::KEY_BUTTON_MOTION_VIRTUAL|Grp::CROSSING), 'time' => (Grp::KEY_BUTTON_MOTION_VIRTUAL|Grp::CROSSING| Grp::PROP), 'warp' => Grp::KEY_BUTTON_MOTION_VIRTUAL, 'width' => (Grp::EXPOSE|Grp::CREATE|Grp::CONFIG), 'window' => (Grp::CREATE|Grp::UNMAP|Grp::MAP|Grp::REPARENT| Grp::CONFIG|Grp::GRAVITY|Grp::CIRC), 'when' => Grp::ALL, 'x' => (Grp::KEY_BUTTON_MOTION_VIRTUAL|Grp::CROSSING| Grp::EXPOSE|Grp::CREATE|Grp::CONFIG|Grp::GRAVITY| Grp::REPARENT), 'y' => (Grp::KEY_BUTTON_MOTION_VIRTUAL|Grp::CROSSING| Grp::EXPOSE|Grp::CREATE|Grp::CONFIG|Grp::GRAVITY| Grp::REPARENT), } FIELD_OPERATION = { 'root' => proc{|val| begin Tk.tk_call_without_enc('winfo', 'pathname', val) val rescue nil end }, 'subwindow' => proc{|val| begin Tk.tk_call_without_enc('winfo', 'pathname', val) val rescue nil end }, 'window' => proc{|val| nil} } #------------------------------------------- def valid_fields(group_flag=nil) group_flag = self.class.group_flag(self.type) unless group_flag fields = {} FIELD_FLAG.each{|key, flag| next if (flag & group_flag) == 0 begin val = self.__send__(key) rescue next end # next if !val || val == '??' next if !val || (val == '??' && (flag & Grp::STRING_DATA)) fields[key] = val } fields end def valid_for_generate(group_flag=nil) fields = valid_fields(group_flag) FIELD_OPERATION.each{|key, cmd| next unless fields.has_key?(key) val = FIELD_OPERATION[key].call(fields[key]) if val fields[key] = val else fields.delete(key) end } fields end def generate(win, modkeys={}) klass = self.class if modkeys.has_key?(:type) || modkeys.has_key?('type') modkeys = TkComm._symbolkey2str(modkeys) type_id = modkeys.delete('type') else type_id = self.type end type_name = klass.type_name(type_id) unless type_name fail RuntimeError, "type_id #{type_id} is invalid" end group_flag = klass.group_flag(type_id) opts = valid_for_generate(group_flag) modkeys.each{|key, val| if val opts[key.to_s] = val else opts.delete(key.to_s) end } if group_flag != Grp::KEY Tk.event_generate(win, type_name, opts) else # If type is KEY event, focus should be set to target widget. # If not set, original widget will get the same event. # That will make infinite loop. w = Tk.tk_call_without_enc('focus') begin Tk.tk_call_without_enc('focus', win) Tk.event_generate(win, type_name, opts) ensure Tk.tk_call_without_enc('focus', w) end end end ############################################# # [ <'%' subst-key char>, , ] KEY_TBL = [ [ ?#, ?n, :serial ], [ ?a, ?s, :above ], [ ?b, ?n, :num ], [ ?c, ?n, :count ], [ ?d, ?s, :detail ], # ?e [ ?f, ?b, :focus ], # ?g [ ?h, ?n, :height ], [ ?i, ?s, :win_hex ], # ?j [ ?k, ?n, :keycode ], # ?l [ ?m, ?s, :mode ], # ?n [ ?o, ?b, :override ], [ ?p, ?s, :place ], # ?q # ?r [ ?s, ?x, :state ], [ ?t, ?n, :time ], # ?u [ ?v, ?n, :value_mask ], [ ?w, ?n, :width ], [ ?x, ?n, :x ], [ ?y, ?n, :y ], # ?z [ ?A, ?s, :char ], [ ?B, ?n, :borderwidth ], # ?C [ ?D, ?n, :wheel_delta ], [ ?E, ?b, :send_event ], # ?F # ?G # ?H # ?I # ?J [ ?K, ?s, :keysym ], # ?L # ?M [ ?N, ?n, :keysym_num ], # ?O [ ?P, ?s, :property ], # ?Q [ ?R, ?s, :rootwin_id ], [ ?S, ?s, :subwindow ], [ ?T, ?n, :type ], # ?U # ?V [ ?W, ?w, :widget ], [ ?X, ?n, :x_root ], [ ?Y, ?n, :y_root ], # ?Z nil ] # [ <'%' subst-key str>, , ] # the subst-key string will be converted to a bytecode (128+idx). LONGKEY_TBL = [ # for example, for %CTT and %CST subst-key on tkdnd-2.0 # ['CTT', ?l, :drop_target_type], # ['CST', ?l, :drop_source_type], ] # [ , ] PROC_TBL = [ [ ?n, TkComm.method(:num_or_str) ], [ ?s, TkComm.method(:string) ], [ ?b, TkComm.method(:bool) ], [ ?w, TkComm.method(:window) ], [ ?x, proc{|val| begin TkComm::number(val) rescue ArgumentError val end } ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end # setup tables to be used by scan_args, _get_subst_key, _get_all_subst_keys # # _get_subst_key() and _get_all_subst_keys() generates key-string # which describe how to convert callback arguments to ruby objects. # When binding parameters are given, use _get_subst_key(). # But when no parameters are given, use _get_all_subst_keys() to # create a Event class object as a callback parameter. # # scan_args() is used when doing callback. It convert arguments # ( which are Tcl strings ) to ruby objects based on the key string # that is generated by _get_subst_key() or _get_all_subst_keys(). # _setup_subst_table(KEY_TBL, PROC_TBL) # _setup_subst_table(KEY_TBL, LONGKEY_TBL, PROC_TBL) # if use longname-keys # # NOTE: The order of parameters which passed to callback procedure is # , , ... , , , ... # # If you need support extra arguments given by Tcl/Tk, # please override _get_extra_args_tbl # #def self._get_extra_args_tbl # # return an array of convert procs # [] #end =begin alias button num alias delta wheel_delta alias root rootwin_id alias rootx x_root alias root_x x_root alias rooty y_root alias root_y y_root alias sendevent send_event =end ALIAS_TBL = { :button => :num, :data => :detail, :delta => :wheel_delta, :root => :rootwin_id, :rootx => :x_root, :root_x => :x_root, :rooty => :y_root, :root_y => :y_root, :sendevent => :send_event, :window => :widget } _define_attribute_aliases(ALIAS_TBL) end ############################################### def install_bind_for_event_class(klass, cmd, *args) extra_args_tbl = klass._get_extra_args_tbl if args.compact.size > 0 args.map!{|arg| klass._sym2subst(arg)} args = args.join(' ') keys = klass._get_subst_key(args) if cmd.kind_of?(String) id = cmd elsif cmd.kind_of?(TkCallbackEntry) id = install_cmd(cmd) else id = install_cmd(proc{|*arg| ex_args = [] extra_args_tbl.reverse_each{|conv| ex_args << conv.call(arg.pop)} begin TkUtil.eval_cmd(cmd, *(ex_args.concat(klass.scan_args(keys, arg)))) rescue Exception=>e if TkCore::INTERP.kind_of?(TclTkIp) fail e else # MultiTkIp fail Exception, "#{e.class}: #{e.message.dup}" end end }) end else keys, args = klass._get_all_subst_keys if cmd.kind_of?(String) id = cmd elsif cmd.kind_of?(TkCallbackEntry) id = install_cmd(cmd) else id = install_cmd(proc{|*arg| ex_args = [] extra_args_tbl.reverse_each{|conv| ex_args << conv.call(arg.pop)} begin TkUtil.eval_cmd(cmd, *(ex_args << klass.new(*klass.scan_args(keys, arg)))) rescue Exception=>e if TkCore::INTERP.kind_of?(TclTkIp) fail e else # MultiTkIp fail Exception, "#{e.class}: #{e.message.dup}" end end }) end end if TkCore::INTERP.kind_of?(TclTkIp) id + ' ' + args else # MultiTkIp "if {[set st [catch {#{id} #{args}} ret]] != 0} { if {$st == 4} { return -code continue $ret } elseif {$st == 3} { return -code break $ret } elseif {$st == 2} { return -code return $ret } elseif {[regexp {^Exception: (TkCallbackContinue: .*)$} \ $ret m msg]} { return -code continue $msg } elseif {[regexp {^Exception: (TkCallbackBreak: .*)$} $ret m msg]} { return -code break $msg } elseif {[regexp {^Exception: (TkCallbackReturn: .*)$} $ret m msg]} { return -code return $msg } elseif {[regexp {^Exception: (\\S+: .*)$} $ret m msg]} { return -code return $msg } else { return -code error $ret } } else { set ret }" end end def install_bind(cmd, *args) install_bind_for_event_class(TkEvent::Event, cmd, *args) end end ================================================ FILE: ext/tk/lib/tk/font.rb ================================================ # # tk/font.rb - the class to treat fonts on Ruby/Tk # # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' class TkFont include Tk extend TkCore TkCommandNames = ['font'.freeze].freeze (Tk_FontID = ["@font".freeze, "00000".taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } Tk_FontNameTBL = TkCore::INTERP.create_table Tk_FontUseTBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ Tk_FontNameTBL.mutex.synchronize{ Tk_FontNameTBL.clear } Tk_FontUseTBL.mutex.synchronize{ Tk_FontUseTBL.clear } } # option_type : default => string OptionType = Hash.new(?s) OptionType['size'] = ?n OptionType['pointadjust'] = ?n OptionType['underline'] = ?b OptionType['overstrike'] = ?b # metric_type : default => num_or_str MetricType = Hash.new(?n) MetricType['fixed'] = ?b # system font names SYSTEM_FONT_NAMES = [] def SYSTEM_FONT_NAMES.add(font_names) (@mutex ||= Mutex.new).synchronize{ self.replace(self | font_names.map{|name| name.to_s}) } end def SYSTEM_FONT_NAMES.include?(name) (@mutex ||= Mutex.new).synchronize{ super(name.to_s) } end # set default font case Tk::TK_VERSION when /^4\..*/ DEFAULT_LATIN_FONT_NAME = 'a14'.freeze DEFAULT_KANJI_FONT_NAME = 'k14'.freeze when /^8\.[0-4]/ if JAPANIZED_TK begin fontnames = tk_call('font', 'names') case fontnames when /defaultgui/ # Tcl/Tk-JP for Windows ltn = 'defaultgui' knj = 'defaultgui' when /Mincho:Helvetica-Bold-12/ # Tcl/Tk-JP for UNIX/X ltn, knj = tk_split_simplelist(tk_call('font', 'configure', 'Mincho:Helvetica-Bold-12', '-compound')) else # unknown Tcl/Tk-JP #platform = tk_call('set', 'tcl_platform(platform)') platform = Tk::PLATFORM['platform'] case platform when 'unix' ltn = {'family'=>'Helvetica'.freeze, 'size'=>-12, 'weight'=>'bold'.freeze} #knj = 'k14' #knj = '-misc-fixed-medium-r-normal--14-*-*-*-c-*-jisx0208.1983-0' knj = '-*-fixed-bold-r-normal--12-*-*-*-c-*-jisx0208.1983-0' when 'windows' ltn = {'family'=>'MS Sans Serif'.freeze, 'size'=>8} knj = 'mincho' when 'macintosh' ltn = 'system' knj = 'mincho' else # unknown ltn = 'Helvetica' knj = 'mincho' end end rescue ltn = 'Helvetica' knj = 'mincho' end else # not JAPANIZED_TK begin #platform = tk_call('set', 'tcl_platform(platform)') platform = Tk::PLATFORM['platform'] case platform when 'unix' ltn = {'family'=>'Helvetica'.freeze, 'size'=>-12, 'weight'=>'bold'.freeze} when 'windows' ltn = {'family'=>'MS Sans Serif'.freeze, 'size'=>8} when 'macintosh' ltn = 'system' else # unknown ltn = 'Helvetica' end rescue ltn = 'Helvetica' end knj = ltn.dup end DEFAULT_LATIN_FONT_NAME = ltn.freeze DEFAULT_KANJI_FONT_NAME = knj.freeze when /^8\.[5-9]/, /^9\..*/ if tk_call('font', 'names') =~ /\bTkDefaultFont\b/ DEFAULT_LATIN_FONT_NAME = 'TkDefaultFont'.freeze DEFAULT_KANJI_FONT_NAME = 'TkDefaultFont'.freeze else DEFAULT_LATIN_FONT_NAME = 'Helvetica'.freeze DEFAULT_KANJI_FONT_NAME = 'mincho'.freeze end else # unknown version DEFAULT_LATIN_FONT_NAME = 'Helvetica'.freeze DEFAULT_KANJI_FONT_NAME = 'mincho'.freeze end if $DEBUG print "default latin font = "; p DEFAULT_LATIN_FONT_NAME print "default kanji font = "; p DEFAULT_KANJI_FONT_NAME end ################################### class DescendantFont def initialize(compound, type) unless compound.kind_of?(TkFont) fail ArgumentError, "a TkFont object is expected for the 1st argument" end @compound = compound case type when 'kanji', 'latin', 'ascii' @type = type when :kanji, :latin, :ascii @type = type.to_s else fail ArgumentError, "unknown type '#{type}'" end end def dup fail RuntimeError, "cannot dupulicate a descendant font" end def clone fail RuntimeError, "cannot clone a descendant font" end def to_eval @compound.__send__(@type + '_font_id') end def font @compound.__send__(@type + '_font_id') end alias font_id font alias name font alias to_s font def [](slot) @compound.__send__(@type + '_configinfo', slot) end def []=(slot, value) @compound.__send__(@type + '_configure', slot, value) value end def method_missing(id, *args) @compound.__send__(@type + '_' + id.id2name, *args) end end ################################### # class methods ################################### def TkFont.is_system_font?(fnt) # true --> system font which is available on the current system # false --> not system font (or unknown system font) # nil --> system font name, but not available on the current system fnt = fnt.to_s SYSTEM_FONT_NAMES.include?(fnt) && self.names.index(fnt) && true end def TkFont.actual(fnt, option=nil) fnt = '{}' if fnt == '' if fnt.kind_of?(TkFont) fnt.actual(option) else actual_core(fnt, nil, option) end end def TkFont.actual_hash(fnt, option=nil) Hash[TkFont.actual_hash(fnt, option)] end def TkFont.actual_displayof(fnt, win, option=nil) fnt = '{}' if fnt == '' if fnt.kind_of?(TkFont) fnt.actual_displayof(win, option) else win = '.' unless win actual_core(fnt, win, option) end end def TkFont.actual_hash_displayof(fnt, option=nil) Hash[TkFont.actual_hash_displayof(fnt, option)] end def TkFont.configure(fnt, slot, value=None) if fnt.kind_of?(TkFont) fnt.configure(fnt, slot, value) else configure_core(fnt, slot, value) end fnt end def TkFont.configinfo(fnt, slot=nil) if fnt.kind_of?(TkFont) fnt.configinfo(fnt, slot) else configinfo_core(fnt, slot) end end def TkFont.current_configinfo(fnt, slot=nil) if fnt.kind_of?(TkFont) fnt.current_configinfo(fnt, slot) else current_configinfo_core(fnt, slot) end end def TkFont.measure(fnt, text) fnt = '{}' if fnt == '' if fnt.kind_of?(TkFont) fnt.measure(text) else measure_core(fnt, nil, text) end end def TkFont.measure_displayof(fnt, win, text) fnt = '{}' if fnt == '' if fnt.kind_of?(TkFont) fnt.measure_displayof(win, text) else win = '.' unless win measure_core(fnt, win, text) end end def TkFont.metrics(fnt, option=nil) fnt = '{}' if fnt == '' if fnt.kind_of?(TkFont) fnt.metrics(option) else metrics_core(fnt, nil, option) end end def TkFont.metrics_hash(fnt, option=nil) if option val = TkFont.metrics(fnt, option) case TkFont::MetricsType[option.to_s] when ?n val = TkComm::num_or_str(val) when ?b val = TkComm::bool(val) else # do nothing end return val end h = Hash[TkFont.metrics(fnt)] h.keys.each{|k| case TkFont::MetricsType[k.to_s] when ?n h[k] = TkComm::num_or_str(h[k]) when ?b h[k] = TkComm::bool(h[k]) else # do nothing end } h end def TkFont.metrics_displayof(fnt, win, option=nil) fnt = '{}' if fnt == '' if fnt.kind_of?(TkFont) font.metrics_displayof(win, option=nil) else win = '.' unless win metrics_core(fnt, win, option) end end def TkFont.metrics_hash_displayof(fnt, win, option=nil) if option val = TkFont.metrics_displayof(fnt, win, option) case TkFont::MetricsType[option.to_s] when ?n val = TkComm::num_or_str(val) when ?b val = TkComm::bool(val) else # do nothing end return val end h = Hash[TkFont.metrics_displayof(fnt, win, option)] h.keys.each{|k| case TkFont::MetricsType[k.to_s] when ?n h[k] = TkComm::num_or_str(h[k]) when ?b h[k] = TkComm::bool(h[k]) else # do nothing end } h end def TkFont.families(win=nil) case (Tk::TK_VERSION) when /^4\..*/ ['fixed'] when /^8\..*/ if win tk_split_simplelist(tk_call('font', 'families', '-displayof', win)) else tk_split_simplelist(tk_call('font', 'families')) end end end def TkFont.names case (Tk::TK_VERSION) when /^4\..*/ r = ['fixed'] r += ['a14', 'k14'] if JAPANIZED_TK Tk_FontNameTBL.mutex.synchronize{ Tk_FontNameTBL.each_value{|obj| r.push(obj)} } #r | [] r.uniq when /^8\..*/ tk_split_simplelist(tk_call('font', 'names')) end end def TkFont.create_copy(font) fail 'source-font must be a TkFont object' unless font.kind_of? TkFont if TkComm::GET_CONFIGINFOwoRES_AS_ARRAY keys = {} font.configinfo.each{|key,value| keys[key] = value } TkFont.new(font.latin_font_id, font.kanji_font_id, keys) else # ! TkComm::GET_CONFIGINFOwoRES_AS_ARRAY TkFont.new(font.latin_font_id, font.kanji_font_id, font.configinfo) end end def TkFont.get_obj(name) name = name.to_s if name =~ /^(@font[0-9]+)(|c|l|k)$/ Tk_FontNameTBL.mutex.synchronize{ Tk_FontNameTBL[$1] } else Tk_FontNameTBL.mutex.synchronize{ Tk_FontNameTBL[name] } end end def TkFont.init_widget_font(pathname, *args) win, tag, key = pathname.split(';') key = 'font' if key == nil || key == '' path = [win, tag, key].join(';') case (Tk::TK_VERSION) when /^4\..*/ regexp = /^-(|kanji)#{key} / conf_list = tk_split_simplelist(tk_call(*args)). find_all{|prop| prop =~ regexp}. collect{|prop| tk_split_simplelist(prop)} if conf_list.size == 0 raise RuntimeError, "the widget may not support 'font' option" end args << {} ltn_key = "-#{key}" knj_key = "-kanji#{key}" ltn_info = conf_list.find{|conf| conf[0] == ltn_key} ltn = ltn_info[-1] ltn = nil if ltn == [] || ltn == "" knj_info = conf_list.find{|conf| conf[0] == knj_key} knj = knj_info[-1] knj = nil if knj == [] || knj == "" TkFont.new(ltn, knj).call_font_configure([path, key], *args) when /^8\.[0-4]/ regexp = /^-#{key} / conf_list = tk_split_simplelist(tk_call(*args)). find_all{|prop| prop =~ regexp}. collect{|prop| tk_split_simplelist(prop)} if conf_list.size == 0 raise RuntimeError, "the widget may not support 'font' option" end args << {} optkey = "-#{key}" info = conf_list.find{|conf| conf[0] == optkey} fnt = info[-1] fnt = nil if fnt == [] || fnt == "" unless fnt # create dummy # TkFont.new(nil, nil).call_font_configure([path, key], *args) dummy_fnt = TkFont.allocate dummy_fnt.instance_eval{ init_dummy_fontobj() } dummy_fnt else begin compound = tk_split_simplelist( Hash[*tk_split_simplelist(tk_call('font', 'configure', fnt))].collect{|k,v| [k[1..-1], v] }.assoc('compound')[1]) rescue compound = [] end if compound == [] if TkFont.is_system_font?(fnt) TkNamedFont.new(fnt).call_font_configure([path, key], *args) else TkFont.new(fnt).call_font_configure([path, key], *args) end else TkFont.new(compound[0], compound[1]).call_font_configure([path, key], *args) end end when /^8\.[5-9]/, /^9\..*/ regexp = /^-#{key} / conf_list = tk_split_simplelist(tk_call(*args)). find_all{|prop| prop =~ regexp}. collect{|prop| tk_split_simplelist(prop)} if conf_list.size == 0 raise RuntimeError, "the widget may not support 'font' option" end args << {} optkey = "-#{key}" info = conf_list.find{|conf| conf[0] == optkey} fnt = info[-1] fnt = nil if fnt == [] || fnt == "" unless fnt # create dummy # TkFont.new(nil, nil).call_font_configure([path, key], *args) dummy_fnt = TkFont.allocate dummy_fnt.instance_eval{ init_dummy_fontobj() } dummy_fnt else if TkFont.is_system_font?(fnt) TkNamedFont.new(fnt).call_font_configure([path, key], *args) else TkFont.new(fnt).call_font_configure([path, key], *args) end end end end def TkFont.used_on(path=nil) Tk_FontUseTBL.mutex.synchronize{ if path Tk_FontUseTBL[path] else # Tk_FontUseTBL.values | [] Tk_FontUseTBL.values.uniq end } end def TkFont.failsafe(font) begin if /^8\..*/ === Tk::TK_VERSION && JAPANIZED_TK tk_call('font', 'failsafe', font) end rescue end end ################################### # instance methods ################################### private ################################### def init_dummy_fontobj Tk_FontID.mutex.synchronize{ @id = Tk_FontID.join(TkCore::INTERP._ip_id_) Tk_FontID[1].succ! } Tk_FontNameTBL.mutex.synchronize{ Tk_FontNameTBL[@id] = self } # @latin_desscendant = nil # @kanji_desscendant = nil @descendant = [nil, nil] # [latin, kanji] case (Tk::TK_VERSION) when /^4\..*/ @latinfont = "" @kanjifont = "" if JAPANIZED_TK @compoundfont = [[@latinfont], [@kanjifont]] @fontslot = {'font'=>@latinfont, 'kanjifont'=>@kanjifont} else @compoundfont = @latinfont @fontslot = {'font'=>@latinfont} end else @latinfont = @id + 'l' @kanjifont = @id + 'k' @compoundfont = @id + 'c' if JAPANIZED_TK tk_call('font', 'create', @latinfont, '-charset', 'iso8859') tk_call('font', 'create', @kanjifont, '-charset', 'jisx0208.1983') tk_call('font', 'create', @compoundfont, '-compound', [@latinfont, @kanjifont]) else tk_call('font', 'create', @latinfont) tk_call('font', 'create', @kanjifont) tk_call('font', 'create', @compoundfont) end @fontslot = {'font'=>@compoundfont} end self end def initialize(ltn=nil, knj=nil, keys=nil) ltn = '{}' if ltn == '' knj = '{}' if knj == '' Tk_FontID.mutex.synchronize{ # @id = Tk_FontID.join('') @id = Tk_FontID.join(TkCore::INTERP._ip_id_) Tk_FontID[1].succ! } Tk_FontNameTBL.mutex.synchronize{ Tk_FontNameTBL[@id] = self } # @latin_desscendant = nil # @kanji_desscendant = nil @descendant = [nil, nil] # [latin, kanji] # @latinfont = @id + 'l' # @kanjifont = @id + 'k' # @compoundfont = @id + 'c' # @fontslot = {} if knj.kind_of?(Hash) && !keys keys = knj knj = nil end # compound font check if Tk::TK_VERSION == '8.0' && JAPANIZED_TK begin compound = tk_split_simplelist(tk_call('font', 'configure', ltn, '-compound')) if knj == nil if compound != [] ltn, knj = compound end else if compound != [] ltn = compound[0] end compound = tk_split_simplelist(tk_call('font', 'configure', knj, '-compound')) if compound != [] knj = compound[1] end end rescue end end if ltn if JAPANIZED_TK && !knj if Tk::TK_VERSION =~ /^4..*/ knj = DEFAULT_KANJI_FONT_NAME else knj = ltn end end else ltn = DEFAULT_LATIN_FONT_NAME knj = DEFAULT_KANJI_FONT_NAME if JAPANIZED_TK && !knj end create_compoundfont(ltn, knj, keys) end def initialize_copy(font) unless font.kind_of?(TkFont) fail TypeError, '"initialize_copy should take same class object' end if TkComm::GET_CONFIGINFOwoRES_AS_ARRAY keys = {} font.configinfo.each{|key,value| keys[key] = value } initialize(font.latin_font_id, font.kanji_font_id, keys) else # ! TkComm::GET_CONFIGINFOwoRES_AS_ARRAY initialize(font.latin_font_id, font.kanji_font_id, font.configinfo) end end def _get_font_info_from_hash(font) font = _symbolkey2str(font) foundry = (info = font['foundry'] .to_s)? info: '*' family = (info = font['family'] .to_s)? info: '*' weight = (info = font['weight'] .to_s)? info: '*' slant = (info = font['slant'] .to_s)? info: '*' swidth = (info = font['swidth'] .to_s)? info: '*' adstyle = (info = font['adstyle'] .to_s)? info: '*' pixels = (info = font['pixels'] .to_s)? info: '*' points = (info = font['points'] .to_s)? info: '*' resx = (info = font['resx'] .to_s)? info: '*' resy = (info = font['resy'] .to_s)? info: '*' space = (info = font['space'] .to_s)? info: '*' avgWidth = (info = font['avgWidth'].to_s)? info: '*' charset = (info = font['charset'] .to_s)? info: '*' encoding = (info = font['encoding'].to_s)? info: '*' [foundry, family, weight, slant, swidth, adstyle, pixels, points, resx, resy, space, avgWidth, charset, encoding] end def create_latinfont_tk4x(font) if font.kind_of? Hash @latinfont = '-' + _get_font_info_from_hash(font).join('-') + '-' elsif font.kind_of? Array finfo = {} finfo['family'] = font[0].to_s if font[1] fsize = font[1].to_s if fsize != '0' && fsize =~ /^(|\+|-)([0-9]+)$/ if $1 == '-' finfo['pixels'] = $2 else finfo['points'] = $2 end else finfo['points'] = '13' end end font[2..-1].each{|style| case (style) when 'normal' finfo['weight'] = style when 'bold' finfo['weight'] = style when 'roman' finfo['slant'] = 'r' when 'italic' finfo['slant'] = 'i' end } @latinfont = '-' + _get_font_info_from_hash(finfo).join('-') + '-' elsif font.kind_of? TkFont @latinfont = font.latin_font else if font @latinfont = font else @latinfont = DEFAULT_LATIN_FONT_NAME end end end def create_kanjifont_tk4x(font) unless JAPANIZED_TK @kanjifont = "" return end if font.kind_of? Hash @kanjifont = '-' + _get_font_info_from_hash(font).join('-') + '-' elsif font.kind_of? Array finfo = {} finfo['family'] = font[0].to_s if font[1] fsize = font[1].to_s if fsize != '0' && fsize =~ /^(|\+|-)([0-9]+)$/ if $1 == '-' finfo['pixels'] = $2 else finfo['points'] = $2 end else finfo['points'] = '13' end end font[2..-1].each{|style| case (style) when 'normal' finfo['weight'] = style when 'bold' finfo['weight'] = style when 'roman' finfo['slant'] = 'r' when 'italic' finfo['slant'] = 'i' end } @kanjifont = '-' + _get_font_info_from_hash(finfo).join('-') + '-' elsif font.kind_of? TkFont @kanjifont = font.kanji_font_id else if font @kanjifont = font else @kanjifont = DEFAULT_KANJI_FONT_NAME end end end def create_compoundfont_tk4x(ltn, knj, keys) create_latinfont(ltn) create_kanjifont(knj) if JAPANIZED_TK @compoundfont = [[@latinfont], [@kanjifont]] @fontslot = {'font'=>@latinfont, 'kanjifont'=>@kanjifont} # @fontslot.clear # @fontslot['font'] = @latinfont # @fontslot['kanjifont'] = @kanjifont else @compoundfont = @latinfont @fontslot = {'font'=>@latinfont} # @fontslot.clear # @fontslot['font'] = @latinfont end end def create_latinfont_tk8x(font) @latinfont = @id + 'l' if JAPANIZED_TK if font.kind_of? Hash if font[:charset] || font['charset'] tk_call('font', 'create', @latinfont, *hash_kv(font)) else tk_call('font', 'create', @latinfont, '-charset', 'iso8859', *hash_kv(font)) end elsif font.kind_of? Array tk_call('font', 'create', @latinfont, '-copy', array2tk_list(font)) tk_call('font', 'configure', @latinfont, '-charset', 'iso8859') elsif font.kind_of? TkFont tk_call('font', 'create', @latinfont, '-copy', font.latin_font) elsif font tk_call('font', 'create', @latinfont, '-copy', font, '-charset', 'iso8859') else tk_call('font', 'create', @latinfont, '-charset', 'iso8859') end else if font.kind_of? Hash tk_call('font', 'create', @latinfont, *hash_kv(font)) else keys = {} if font.kind_of? Array actual_core(array2tk_list(font)).each{|key,val| keys[key] = val} elsif font.kind_of? TkFont actual_core(font.latin_font).each{|key,val| keys[key] = val} elsif font actual_core(font).each{|key,val| keys[key] = val} end tk_call('font', 'create', @latinfont, *hash_kv(keys)) end if font && @compoundfont keys = {} actual_core(@latinfont).each{|key,val| keys[key] = val} tk_call('font', 'configure', @compoundfont, *hash_kv(keys)) end end end def create_kanjifont_tk8x(font) @kanjifont = @id + 'k' if JAPANIZED_TK if font.kind_of? Hash if font[:charset] || font['charset'] tk_call('font', 'create', @kanjifont, *hash_kv(font)) else tk_call('font', 'create', @kanjifont, '-charset', 'jisx0208.1983', *hash_kv(font)) end elsif font.kind_of? Array tk_call('font', 'create', @kanjifont, '-copy', array2tk_list(font)) tk_call('font', 'configure', @kanjifont, '-charset', 'jisx0208.1983') elsif font.kind_of? TkFont tk_call('font', 'create', @kanjifont, '-copy', font.kanji_font_id) elsif font tk_call('font', 'create', @kanjifont, '-copy', font, '-charset', 'jisx0208.1983') else tk_call('font', 'create', @kanjifont, '-charset', 'jisx0208.1983') end # end of JAPANIZED_TK else if font.kind_of? Hash tk_call('font', 'create', @kanjifont, *hash_kv(font)) else keys = {} if font.kind_of? Array actual_core(array2tk_list(font)).each{|key,val| keys[key] = val} elsif font.kind_of? TkFont actual_core(font.kanji_font_id).each{|key,val| keys[key] = val} elsif font actual_core(font).each{|key,val| keys[key] = val} end tk_call('font', 'create', @kanjifont, *hash_kv(keys)) end if font && @compoundfont keys = {} actual_core(@kanjifont).each{|key,val| keys[key] = val} tk_call('font', 'configure', @compoundfont, *hash_kv(keys)) end end end def create_compoundfont_tk8x(ltn, knj, keys) if knj create_latinfont(ltn) create_kanjifont(knj) else cfnt = ltn create_kanjifont(cfnt) create_latinfont(cfnt) end @compoundfont = @id + 'c' if JAPANIZED_TK unless keys keys = {} else keys = keys.dup end if (tk_call('font', 'configure', @latinfont, '-underline') == '1' && tk_call('font', 'configure', @kanjifont, '-underline') == '1' && !keys.key?('underline')) keys['underline'] = true end if (tk_call('font', 'configure', @latinfont, '-overstrike') == '1' && tk_call('font', 'configure', @kanjifont, '-overstrike') == '1' && !keys.key?('overstrike')) keys['overstrike'] = true end @fontslot = {'font'=>@compoundfont} # @fontslot['font'] = @compoundfont begin tk_call('font', 'create', @compoundfont, '-compound', [@latinfont, @kanjifont], *hash_kv(keys)) rescue RuntimeError => e if ltn == knj if e.message =~ /kanji font .* specified/ tk_call('font', 'delete', @latinfont) create_latinfont(DEFAULT_LATIN_FONT_NAME) opts = [] Hash[*(tk_split_simplelist(tk_call('font', 'configure', @kanjifont)))].each{|k,v| case k when '-size', '-weight', '-slant', '-underline', '-overstrike' opts << k << v end } tk_call('font', 'configure', @latinfont, *opts) tk_call('font', 'create', @compoundfont, '-compound', [@latinfont, @kanjifont], *hash_kv(keys)) elsif e.message =~ /ascii font .* specified/ tk_call('font', 'delete', @kanjifont) create_kanjifont(DEFAULT_KANJI_FONT_NAME) opts = [] Hash[*(tk_split_simplelist(tk_call('font', 'configure', @latinfont)))].each{|k,v| case k when '-size', '-weight', '-slant', '-underline', '-overstrike' opts << k << v end } tk_call('font', 'configure', @kanjifont, *opts) tk_call('font', 'create', @compoundfont, '-compound', [@latinfont, @kanjifont], *hash_kv(keys)) else raise e end else raise e end end else tk_call('font', 'create', @compoundfont) latinkeys = {} begin actual_core(@latinfont).each{|key,val| latinkeys[key] = val} rescue latinkeys = {} end if latinkeys != {} tk_call('font', 'configure', @compoundfont, *hash_kv(latinkeys)) end if knj compoundkeys = nil kanjikeys = {} begin actual_core(@kanjifont).each{|key,val| kanjikeys[key] = val} rescue kanjikeys = {} end if kanjikeys != {} tk_call('font', 'configure', @compoundfont, *hash_kv(kanjikeys)) end end if cfnt if cfnt.kind_of?(Hash) compoundkeys = cfnt.dup else compoundkeys = {} actual_core(cfnt).each{|key,val| compoundkeys[key] = val} end compoundkeys.update(_symbolkey2str(keys)) keys = compoundkeys end @fontslot = {'font'=>@compoundfont} # @fontslot['font'] = @compoundfont tk_call('font', 'configure', @compoundfont, *hash_kv(keys)) end end ################################### public ################################### def inspect sprintf("#<%s:%0x:%s>", self.class.inspect, self.__id__, @compoundfont) end def method_missing(id, *args) name = id.id2name case args.length when 1 if name[-1] == ?= configure name[0..-2], args[0] args[0] else configure name, args[0] self end when 0 begin configinfo name rescue super(id, *args) # fail NameError, "undefined local variable or method `#{name}' for #{self.to_s}", error_at end else super(id, *args) # fail NameError, "undefined method `#{name}' for #{self.to_s}", error_at end end def call_font_configure(path, *args) if path.kind_of?(Array) # [path, optkey] win, tag = path[0].split(';') optkey = path[1].to_s else win, tag, optkey = path.split(';') end fontslot = _symbolkey2str(@fontslot) if optkey && optkey != "" ltn = fontslot.delete('font') knj = fontslot.delete('kanjifont') fontslot[optkey] = ltn if ltn fontslot["kanji#{optkey}"] = knj if knj end keys = _symbolkey2str(args.pop).update(fontslot) args.concat(hash_kv(keys)) begin tk_call(*args) rescue => e unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ fail e end end Tk_FontUseTBL.mutex.synchronize{ Tk_FontUseTBL[[win, tag, optkey].join(';')] = self } self end def used ret = [] table = nil Tk_FontUseTBL.mutex.synchronize{ table = Tk_FontUseTBL.clone # to avoid deadlock } table.each{|key,value| next unless self == value if key.include?(';') win, tag, optkey = key.split(';') winobj = tk_tcl2ruby(win) #if winobj.kind_of? TkText if winobj.kind_of?(TkText) || winobj.kind_of?(Tk::Text) if optkey ret.push([winobj, winobj.tagid2obj(tag), optkey]) else ret.push([winobj, winobj.tagid2obj(tag)]) end #elsif winobj.kind_of? TkCanvas elsif winobj.kind_of?(TkCanvas) || winobj.kind_of?(Tk::Canvas) if (tagobj = TkcTag.id2obj(winobj, tag)).kind_of? TkcTag if optkey ret.push([winobj, tagobj, optkey]) else ret.push([winobj, tagobj]) end elsif (tagobj = TkcItem.id2obj(winobj, tag)).kind_of? TkcItem if optkey ret.push([winobj, tagobj, optkey]) else ret.push([winobj, tagobj]) end else if optkey ret.push([winobj, tag, optkey]) else ret.push([winobj, tag]) end end #elsif winobj.kind_of? TkMenu elsif winobj.kind_of?(TkMenu) || winobj.kind_of?(Tk::Menu) if optkey ret.push([winobj, tag, optkey]) else ret.push([winobj, tag]) end else if optkey ret.push([win, tag, optkey]) else ret.push([win, tag]) end end else ret.push(tk_tcl2ruby(key)) end } ret end def id @id end def to_eval font end def font @compoundfont end alias font_id font alias name font alias to_s font def latin_font_id @latinfont end def latin_font # @latinfont if @descendant[0] # [0] -> latin @descendant[0] else @descendant[0] = DescendantFont.new(self, 'latin') end =begin if @latin_descendant @latin_descendant else @latin_descendant = DescendantFont.new(self, 'latin') end =end end alias latinfont latin_font def kanji_font_id @kanjifont end def kanji_font # @kanjifont if @descendant[1] # [1] -> kanji @descendant[1] else @descendant[1] = DescendantFont.new(self, 'kanji') end =begin if @kanji_descendant @kanji_descendant else @kanji_descendant = DescendantFont.new(self, 'kanji') end =end end alias kanjifont kanji_font def actual(option=nil) actual_core(@compoundfont, nil, option) end def actual_hash(option=nil) Hash[actual(option)] end def actual_displayof(win, option=nil) win = '.' unless win actual_core(@compoundfont, win, option) end def actual_hash_displayof(win, option=nil) Hash[actual_displayof(win, option)] end def latin_actual(option=nil) if @latinfont == nil actual_core(@compoundfont, nil, option) # use @compoundfont else actual_core(@latinfont, nil, option) end end def latin_actual_hash(option=nil) Hash[latin_actual(option)] end def latin_actual_displayof(win, option=nil) win = '.' unless win if @latinfont == nil actual_core(@compoundfont, win, option) # use @compoundfont else actual_core(@latinfont, win, option) end end def latin_actual_hash_displayof(win, option=nil) Hash[latin_actual_displayof(win, option)] end def kanji_actual(option=nil) #if JAPANIZED_TK if @kanjifont == nil actual_core(@compoundfont, nil, option) # use @compoundfont elsif @kanjifont != "" actual_core(@kanjifont, nil, option) else actual_core_tk4x(nil, nil, option) end end def kanji_actual_hash(option=nil) Hash[kanji_actual(option)] end def kanji_actual_displayof(win, option=nil) #if JAPANIZED_TK if @kanjifont == nil actual_core(@compoundfont, nil, option) # use @compoundfont elsif @kanjifont != "" win = '.' unless win actual_core(@kanjifont, win, option) else actual_core_tk4x(nil, win, option) end end def kanji_actual_hash_displayof(win, option=nil) Hash[kanji_actual_displayof(win, option)] end def [](slot) configinfo slot end def []=(slot, val) configure slot, val val end def configure(slot, value=None) configure_core(@compoundfont, slot, value) self end def configinfo(slot=nil) configinfo_core(@compoundfont, slot) end def current_configinfo(slot=nil) current_configinfo_core(@compoundfont, slot) end def delete delete_core end def latin_configure(slot, value=None) if JAPANIZED_TK configure_core(@latinfont, slot, value) else configure(slot, value) end self end def latin_configinfo(slot=nil) if JAPANIZED_TK configinfo_core(@latinfont, slot) else configinfo(slot) end end def latin_current_configinfo(slot=nil) Hash[latin_configinfo(slot)] end def kanji_configure(slot, value=None) #if JAPANIZED_TK if @kanjifont == nil configure_core(@compoundfont, slot, value) # use @compoundfont elsif @kanjifont != "" configure_core(@kanjifont, slot, value) configure('size'=>configinfo('size')) # to reflect new configuration else #"" configure(slot, value) end self end def kanji_configinfo(slot=nil) #if JAPANIZED_TK if @kanjifont == nil configure_core(@compoundfont, slot) # use @compoundfont elsif @kanjifont != "" configinfo_core(@kanjifont, slot) else #[] configinfo(slot) end end def kanji_current_configinfo(slot=nil) Hash[kanji_configinfo(slot)] end def replace(ltn, knj=None) knj = ltn if knj == None latin_replace(ltn) kanji_replace(knj) self end def latin_replace(ltn) if @latinfont latin_replace_core(ltn) reset_pointadjust else # not compound font -> copy properties of ltn latinkeys = {} begin actual_core(ltn).each{|key,val| latinkeys[key] = val} rescue latinkeys = {} end begin tk_call('font', 'configure', @compoundfont, *hash_kv(latinkeys)) rescue # not exist? (deleted?) -> create font tk_call('font', 'create', @compoundfont, *hash_kv(latinkeys)) end end self end def kanji_replace(knj) return self unless @kanjifont # ignore kanji_replace_core(knj) reset_pointadjust self end def measure(text) measure_core(@compoundfont, nil, text) end def measure_displayof(win, text) win = '.' unless win measure_core(@compoundfont, win, text) end def metrics(option=nil) metrics_core(@compoundfont, nil, option) end def metrics_hash(option=nil) if option val = metrics(option) case TkFont::MetricsType[option.to_s] when ?n val = TkComm::num_or_str(val) when ?b val = TkComm::bool(val) else # do nothing end return val end h = Hash[metrics(option)] h.keys.each{|k| case TkFont::MetricsType[k.to_s] when ?n h[k] = TkComm::num_or_str(h[k]) when ?b h[k] = TkComm::bool(h[k]) else # do nothing end } h end def metrics_displayof(win, option=nil) win = '.' unless win metrics_core(@compoundfont, win, option) end def metrics_hash_displayof(win, option=nil) if option val = metrics_displayof(win, option) case TkFont::MetricsType[option.to_s] when ?n val = TkComm::num_or_str(val) when ?b val = TkComm::bool(val) else # do nothing end return val end h = Hash[metrics_displayof(win, option)] h.keys.each{|k| case TkFont::MetricsType[k.to_s] when ?n h[k] = TkComm::num_or_str(h[k]) when ?b h[k] = TkComm::bool(h[k]) else # do nothing end } h end def latin_metrics(option=nil) if @latinfont == nil metrics_core(@compoundfont, nil, option) # use @compoundfont else metrics_core(@latinfont, nil, option) end end def latin_metrics_hash(option=nil) if option val = latin_metrics(option) case TkFont::MetricsType[option.to_s] when ?n val = TkComm::num_or_str(val) when ?b val = TkComm::bool(val) else # do nothing end return val end h = Hash[latin_metrics(option)] h.keys.each{|k| case TkFont::MetricsType[k.to_s] when ?n h[k] = TkComm::num_or_str(h[k]) when ?b h[k] = TkComm::bool(h[k]) else # do nothing end } h end def latin_metrics_displayof(win, option=nil) win = '.' unless win if @latinfont == nil metrics_core(@compoundfont, win, option) # use @compoundfont else metrics_core(@latinfont, win, option) end end def latin_metrics_hash_displayof(win, option=nil) if option val = latin_metrics_displayof(win, option) case TkFont::MetricsType[option.to_s] when ?n val = TkComm::num_or_str(val) when ?b val = TkComm::bool(val) else # do nothing end return val end h = Hash[latin_metrics_displayof(win, option)] h.keys.each{|k| case TkFont::MetricsType[k.to_s] when ?n h[k] = TkComm::num_or_str(h[k]) when ?b h[k] = TkComm::bool(h[k]) else # do nothing end } h end def kanji_metrics(option=nil) if @latinfont == nil metrics_core(@compoundfont, nil, option) # use @compoundfont elsif JAPANIZED_TK metrics_core(@kanjifont, nil, option) else metrics_core_tk4x(nil, nil, option) end end def kanji_metrics_hash(option=nil) if option val = kanji_metrics(option) case TkFont::MetricsType[option.to_s] when ?n val = TkComm::num_or_str(val) when ?b val = TkComm::bool(val) else # do nothing end return val end h = Hash[kanji_metrics(option)] h.keys.each{|k| case TkFont::MetricsType[k.to_s] when ?n h[k] = TkComm::num_or_str(h[k]) when ?b h[k] = TkComm::bool(h[k]) else # do nothing end } h end def kanji_metrics_displayof(win, option=nil) win = '.' unless win if @latinfont == nil metrics_core(@compoundfont, win, option) # use @compoundfont elsif JAPANIZED_TK metrics_core(@kanjifont, win, option) else metrics_core_tk4x(nil, win, option) end end def kanji_metrics_hash_displayof(win, option=nil) if option val = kanji_metrics_displayof(win, option) case TkFont::MetricsType[option.to_s] when ?n val = TkComm::num_or_str(val) when ?b val = TkComm::bool(val) else # do nothing end return val end h = Hash[kanji_metrics_displayof(win, option)] h.keys.each{|k| case TkFont::MetricsType[k.to_s] when ?n h[k] = TkComm::num_or_str(h[k]) when ?b h[k] = TkComm::bool(h[k]) else # do nothing end } h end def reset_pointadjust begin if /^8\..*/ === Tk::TK_VERSION && JAPANIZED_TK configure('pointadjust' => latin_actual.assoc('size')[1].to_f / kanji_actual.assoc('size')[1].to_f ) end rescue end self end ################################### # private alias ################################### case (Tk::TK_VERSION) when /^4\..*/ alias create_latinfont create_latinfont_tk4x alias create_kanjifont create_kanjifont_tk4x alias create_compoundfont create_compoundfont_tk4x when /^8\.[0-5]/ alias create_latinfont create_latinfont_tk8x alias create_kanjifont create_kanjifont_tk8x alias create_compoundfont create_compoundfont_tk8x else alias create_latinfont create_latinfont_tk8x alias create_kanjifont create_kanjifont_tk8x alias create_compoundfont create_compoundfont_tk8x end ################################### # public alias ################################### alias ascii_font latin_font alias asciifont latinfont alias create_asciifont create_latinfont alias ascii_actual latin_actual alias ascii_actual_displayof latin_actual_displayof alias ascii_configure latin_configure alias ascii_configinfo latin_configinfo alias ascii_replace latin_replace alias ascii_metrics latin_metrics ################################### =begin def dup TkFont.new(self) end def clone TkFont.new(self) end =end end module TkFont::CoreMethods include Tk extend TkCore private def actual_core_tk4x(font, win=nil, option=nil) # dummy if option == 'pointadjust' || option == :pointadjust 1.0 elsif option case TkFont::OptionType[option.to_s] when ?n 0 when ?b false else '' end else [['family',''], ['size',0], ['weight',''], ['slant',''], ['underline',false], ['overstrike',false], ['charset',''], ['pointadjust',0]] end end def actual_core_tk8x(font, win=nil, option=nil) font = '{}' if font == '' if option == 'compound' || option == :compound "" elsif option if win val = tk_call('font', 'actual', font, "-displayof", win, "-#{option}") else val = tk_call('font', 'actual', font, "-#{option}") end case TkFont::OptionType[option.to_s] when ?n num_or_str(val) when ?b bool(val) else val end else l = tk_split_simplelist(if win tk_call('font', 'actual', font, "-displayof", win) else tk_call('font', 'actual', font) end) r = [] while key=l.shift if key == '-compound' l.shift else key = key[1..-1] val = l.shift case TkFont::OptionType[key] when ?n r.push [key, num_or_str(val)] when ?b r.push [key, bool(val)] else r.push [key, val] end end end r end end def configure_core_tk4x(font, slot, value=None) #"" self end def configinfo_core_tk4x(font, option=nil) # dummy if TkComm::GET_CONFIGINFOwoRES_AS_ARRAY if option == 'pointadjust' || option == :pointadjust 1.0 elsif option case TkFont::OptionType[option.to_s] when ?n 0 when ?b false else '' end else [['family',''], ['size',0], ['weight',''], ['slant',''], ['underline',false], ['overstrike',false], ['charset',''], ['pointadjust',1.0]] end else # ! TkComm::GET_CONFIGINFOwoRES_AS_ARRAY current_configinfo_core_tk4x(font, option) end end def current_configinfo_core_tk4x(font, option=nil) if option case TkFont::OptionType[option.to_s] when ?n 0 when ?b false else '' end else {'family'=>'', 'size'=>0, 'weight'=>'', 'slant'=>'', 'underline'=>false, 'overstrike'=>false, 'charset'=>false, 'pointadjust'=>1.0} end end def configure_core_tk8x(font, slot, value=None) if JAPANIZED_TK begin padjust = tk_call('font', 'configure', font, '-pointadjust') rescue padjust = nil end else padjust = nil end if slot.kind_of? Hash if JAPANIZED_TK && (slot.key?('family') || slot.key?(:family)) slot = _symbolkey2str(slot) configure_core_tk8x(font, 'family', slot.delete('family')) end if ((slot.key?('size') || slot.key?(:size)) && padjust && !slot.key?('pointadjust') && !slot.key?(:pointadjust)) tk_call('font', 'configure', font, '-pointadjust', padjust, *hash_kv(slot)) else tk_call('font', 'configure', font, *hash_kv(slot)) end elsif (slot == 'size' || slot == :size) && padjust != nil tk_call('font', 'configure', font, "-#{slot}", value, '-pointadjust', padjust) elsif JAPANIZED_TK && (slot == 'family' || slot == :family) # coumpund font? begin compound = tk_split_simplelist(tk_call('font', 'configure', font, '-compound')) rescue tk_call('font', 'configure', font, '-family', value) return self end if compound == [] tk_call('font', 'configure', font, '-family', value) return self end ltn, knj = compound lfnt = tk_call('font', 'create', '-copy', ltn) begin tk_call('font', 'configure', lfnt, '-family', value) latin_replace_core_tk8x(lfnt) rescue RuntimeError => e fail e if $DEBUG ensure tk_call('font', 'delete', lfnt) if lfnt != '' end kfnt = tk_call('font', 'create', '-copy', knj) begin tk_call('font', 'configure', kfnt, '-family', value) kanji_replace_core_tk8x(lfnt) rescue RuntimeError => e fail e if $DEBUG ensure tk_call('font', 'delete', kfnt) if kfnt != '' end else tk_call('font', 'configure', font, "-#{slot}", value) end self end def configinfo_core_tk8x(font, option=nil) if TkComm::GET_CONFIGINFOwoRES_AS_ARRAY if option == 'compound' || option == :compound "" elsif option val = tk_call('font', 'configure', font, "-#{option}") case TkFont::OptionType[option.to_s] when ?n num_or_str(val) when ?b bool(val) else val end else l = tk_split_simplelist(tk_call('font', 'configure', font)) r = [] while key=l.shift if key == '-compound' l.shift else key = key[1..-1] val = l.shift case TkFont::OptionType[key] when ?n r.push [key, num_or_str(val)] when ?b r.push [key, bool(val)] else r.push [key, val] end end end r end else # ! TkComm::GET_CONFIGINFOwoRES_AS_ARRAY current_configinfo_core_tk8x(font, option) end end def current_configinfo_core_tk8x(font, option=nil) if option == 'compound' "" elsif option val = tk_call('font', 'configure', font, "-#{option}") case TkFont::OptionType[option.to_s] when ?n num_or_str(val) when ?b bool(val) else val end else l = tk_split_simplelist(tk_call('font', 'configure', font)) h = {} while key=l.shift if key == '-compound' l.shift else key = key[1..-1] val = l.shift case TkFont::OptionType[key] when ?n h[key] = num_or_str(val) when ?b h[key] = bool(val) else h[key] = val end end end h end end def delete_core_tk4x TkFont::Tk_FontNameTBL.mutex.synchronize{ TkFont::Tk_FontNameTBL.delete(@id) } TkFont::Tk_FontUseTBL.mutex.synchronize{ TkFont::Tk_FontUseTBL.delete_if{|key,value| value == self} } end def delete_core_tk8x begin tk_call('font', 'delete', @latinfont) if @latinfont rescue end begin tk_call('font', 'delete', @kanjifont) if @kanjifont rescue end begin tk_call('font', 'delete', @compoundfont) if @compoundfont rescue end TkFont::Tk_FontNameTBL.mutex.synchronize{ TkFont::Tk_FontNameTBL.delete(@id) } TkFont::Tk_FontUseTBL.mutex.synchronize{ TkFont::Tk_FontUseTBL.delete_if{|key,value| value == self} } end def latin_replace_core_tk4x(ltn) create_latinfont_tk4x(ltn) @compoundfont[0] = [@latinfont] if JAPANIZED_TK @fontslot['font'] = @latinfont table = nil TkFont::Tk_FontUseTBL.mutex.synchronize{ table = TkFont::Tk_FontUseTBL.clone } table.each{|w, fobj| if self == fobj begin if w.include?(';') win, tag, optkey = w.split(';') optkey = 'font' if optkey == nil || optkey == '' winobj = tk_tcl2ruby(win) # winobj.tagfont_configure(tag, {'font'=>@latinfont}) #if winobj.kind_of? TkText if winobj.kind_of?(TkText) || winobj.kind_of?(Tk::Text) tk_call(win, 'tag', 'configure', tag, "-#{optkey}", @latinfont) #elsif winobj.kind_of? TkCanvas elsif winobj.kind_of?(TkCanvas) || winobj.kind_of?(Tk::Canvas) tk_call(win, 'itemconfigure', tag, "-#{optkey}", @latinfont) #elsif winobj.kind_of? TkMenu elsif winobj.kind_of?(TkMenu) || winobj.kind_of?(Tk::Menu) tk_call(win, 'entryconfigure', tag, "-#{optkey}", @latinfont) else raise RuntimeError, "unknown widget type" end else # tk_tcl2ruby(w).font_configure('font'=>@latinfont) tk_call(w, 'configure', '-font', @latinfont) end rescue TkFont::Tk_FontUseTBL.mutex.synchronize{ TkFont::Tk_FontUseTBL.delete(w) } end end } self end def kanji_replace_core_tk4x(knj) return self unless JAPANIZED_TK create_kanjifont_tk4x(knj) @compoundfont[1] = [@kanjifont] @fontslot['kanjifont'] = @kanjifont table = nil TkFont::Tk_FontUseTBL.mutex.synchronize{ table = TkFont::Tk_FontUseTBL.clone } table.dup.each{|w, fobj| if self == fobj begin if w.include?(';') win, tag, optkey = w.split(';') optkey = 'kanjifont' unless optkey winobj = tk_tcl2ruby(win) # winobj.tagfont_configure(tag, {'kanjifont'=>@kanjifont}) #if winobj.kind_of? TkText if winobj.kind_of?(TkText) || winobj.kind_of?(Tk::Text) tk_call(win, 'tag', 'configure', tag, "-#{optkey}", @kanjifont) #elsif winobj.kind_of? TkCanvas elsif winobj.kind_of?(TkCanvas) || winobj.kind_of?(Tk::Canvas) tk_call(win, 'itemconfigure', tag, "-#{optkey}", @kanjifont) #elsif winobj.kind_of? TkMenu elsif winobj.kind_of?(TkMenu) || winobj.kind_of?(Tk::Menu) tk_call(win, 'entryconfigure', tag, "-#{optkey}", @latinfont) else raise RuntimeError, "unknown widget type" end else # tk_tcl2ruby(w).font_configure('kanjifont'=>@kanjifont) tk_call(w, 'configure', '-kanjifont', @kanjifont) end rescue Tk_FontUseTBL.mutex.synchronize{ TkFont::Tk_FontUseTBL.delete(w) } end end } self end def latin_replace_core_tk8x(ltn) ltn = '{}' if ltn == '' if JAPANIZED_TK begin tk_call('font', 'delete', '@font_tmp') rescue end begin fnt_bup = tk_call('font', 'create', '@font_tmp', '-copy', @latinfont) rescue #fnt_bup = '' fnt_bup = TkFont::DEFAULT_LATIN_FONT_NAME end end begin tk_call('font', 'delete', @latinfont) rescue end create_latinfont(ltn) if JAPANIZED_TK keys = self.configinfo tk_call('font', 'delete', @compoundfont) begin tk_call('font', 'create', @compoundfont, '-compound', [@latinfont, @kanjifont], *hash_kv(keys)) =begin latinkeys = {} begin actual_core(@latinfont).each{|key,val| latinkeys[key] = val} rescue latinkeys = {} end if latinkeys != {} tk_call('font', 'configure', @compoundfont, *hash_kv(latinkeys)) end =end rescue RuntimeError => e tk_call('font', 'delete', @latinfont) if fnt_bup && fnt_bup != '' tk_call('font', 'create', @latinfont, '-copy', fnt_bup) tk_call('font', 'create', @compoundfont, '-compound', [@latinfont, @kanjifont], *hash_kv(keys)) tk_call('font', 'delete', fnt_bup) else fail e end end else latinkeys = {} begin actual_core(@latinfont).each{|key,val| latinkeys[key] = val} rescue latinkeys = {} end begin tk_call('font', 'configure', @compoundfont, *hash_kv(latinkeys)) rescue # not exist? (deleted?) -> create font tk_call('font', 'create', @compoundfont, *hash_kv(latinkeys)) end end self end def kanji_replace_core_tk8x(knj) knj = '{}' if knj == '' if JAPANIZED_TK begin tk_call('font', 'delete', '@font_tmp') rescue end begin fnt_bup = tk_call('font', 'create', '@font_tmp', '-copy', @kanjifont) rescue #fnt_bup = '' fnt_bup = TkFont::DEFAULT_KANJI_FONT_NAME end end begin tk_call('font', 'delete', @kanjifont) rescue end create_kanjifont(knj) if JAPANIZED_TK keys = self.configinfo tk_call('font', 'delete', @compoundfont) begin tk_call('font', 'create', @compoundfont, '-compound', [@latinfont, @kanjifont], *hash_kv(keys)) rescue RuntimeError => e tk_call('font', 'delete', @kanjifont) if fnt_bup && fnt_bup != '' tk_call('font', 'create', @kanjifont, '-copy', fnt_bup) tk_call('font', 'create', @compoundfont, '-compound', [@latinfont, @kanjifont], *hash_kv(keys)) tk_call('font', 'delete', fnt_bup) else fail e end end end self end def measure_core_tk4x(font, win, text) 0 end def measure_core_tk8x(font, win, text) font = '{}' if font == '' if win number(tk_call('font', 'measure', font, '-displayof', win, text)) else number(tk_call('font', 'measure', font, text)) end end def metrics_core_tk4x(font, win, option=nil) # dummy if option "" else [['ascent',[]], ['descent',[]], ['linespace',[]], ['fixed',[]]] end end def metrics_core_tk8x(font, win, option=nil) font = '{}' if font == '' if option if win number(tk_call('font', 'metrics', font, "-displayof", win, "-#{option}")) else number(tk_call('font', 'metrics', font, "-#{option}")) end else l = tk_split_list(if win tk_call('font','metrics',font,"-displayof",win) else tk_call('font','metrics',font) end) r = [] while key=l.shift r.push [key[1..-1], l.shift.to_i] =begin if key == '-fixed' # boolean value r.push [key[1..-1], bool(l.shift)] else r.push [key[1..-1], l.shift.to_i] end =end end r end end ################################### # private alias ################################### case (Tk::TK_VERSION) when /^4\..*/ alias actual_core actual_core_tk4x alias configure_core configure_core_tk4x alias configinfo_core configinfo_core_tk4x alias current_configinfo_core current_configinfo_core_tk4x alias delete_core delete_core_tk4x alias latin_replace_core latin_replace_core_tk4x alias kanji_replace_core kanji_replace_core_tk4x alias measure_core measure_core_tk4x alias metrics_core metrics_core_tk4x when /^8\.[0-5]/ alias actual_core actual_core_tk8x alias configure_core configure_core_tk8x alias configinfo_core configinfo_core_tk8x alias current_configinfo_core current_configinfo_core_tk8x alias delete_core delete_core_tk8x alias latin_replace_core latin_replace_core_tk8x alias kanji_replace_core kanji_replace_core_tk8x alias measure_core measure_core_tk8x alias metrics_core metrics_core_tk8x else alias actual_core actual_core_tk8x alias configure_core configure_core_tk8x alias configinfo_core configinfo_core_tk8x alias current_configinfo_core current_configinfo_core_tk8x alias delete_core delete_core_tk8x alias latin_replace_core latin_replace_core_tk8x alias kanji_replace_core kanji_replace_core_tk8x alias measure_core measure_core_tk8x alias metrics_core metrics_core_tk8x end end class TkFont include TkFont::CoreMethods extend TkFont::CoreMethods end class TkNamedFont < TkFont # for built-in named fonts def TkNamedFont.find(name) name = name.to_s unless (obj = Tk_FontNameTBL[name]) obj = self.new(name) if TkFont.is_system_font?(name) end obj end def TkNamedFont.new(name, keys=nil) name = name.to_s obj = nil Tk_FontNameTBL.mutex.synchronize{ unless (obj = Tk_FontNameTBL[name]) (obj = self.allocate).instance_eval{ @id = @compoundfont = name.to_s @latinfont = nil @kanjifont = nil @descendant = [self, self] # [latin, kanji] : dummy Tk_FontNameTBL[@id] = self } end } obj.instance_eval{ initialize(name, keys) } obj end ########################### private ########################### def initialize(name, keys=nil) @id = @compoundfont = name.to_s # if not exist named font, create it. begin if keys tk_call('font', 'configure', @compoundfont, keys) else tk_call('font', 'configure', @compoundfont) end rescue # the named font doesn't exist -> create if keys tk_call('font', 'create', @compoundfont, keys) else tk_call('font', 'create', @compoundfont) end end end def create_latinfont(fnt) # ignore end def create_kanjifont(fnt) # ignore end def create_compoundfont(ltn, knj, keys) # ignore end ########################### public ########################### def latin_font_id @compoundfont end def kanji_font_id @compoundfont end end ####################################### # define system font names ####################################### if Tk::TCL_MAJOR_VERSION > 8 || (Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION >= 5) # add standard fonts of Tcl/Tk 8.5+ TkFont::SYSTEM_FONT_NAMES.add [ 'TkDefaultFont', 'TkTextFont', 'TkFixedFont', 'TkMenuFont', 'TkHeadingFont', 'TkCaptionFont', 'TkSmallCaptionFont', 'TkIconFont', 'TkTooltipFont' ] end # platform-specific fonts # -- windows TkFont::SYSTEM_FONT_NAMES.add [ 'ansifixed', 'ansi', 'device', 'oemfixed', 'systemfixed', 'system' ] # -- macintosh, macosx TkFont::SYSTEM_FONT_NAMES.add ['system', 'application'] if Tk::TCL_MAJOR_VERSION > 8 || (Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION >= 5) TkFont::SYSTEM_FONT_NAMES.add ['menu'] end # -- macosx (Aqua theme) if Tk::TCL_MAJOR_VERSION > 8 || (Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION >= 5) TkFont::SYSTEM_FONT_NAMES.add [ 'systemSystemFont', 'systemEmphasizedSystemFont', 'systemSmallSystemFont', 'systemSmallEmphasizedSystemFont', 'systemApplicationFont', 'systemLabelFont', 'systemViewsFont', 'systemMenuTitleFont', 'systemMenuItemFont', 'systemMenuItemMarkFont', 'systemMenuItemCmdKeyFont', 'systemWindowTitleFont', 'systemPushButtonFont', 'systemUtilityWindowTitleFont', 'systemAlertHeaderFont', 'systemToolbarFont', 'systemMiniSystemFont', 'systemDetailSystemFont', 'systemDetailEmphasizedSystemFont' ] end ================================================ FILE: ext/tk/lib/tk/frame.rb ================================================ # # tk/frame.rb : treat frame widget # require 'tk' class Tk::Frameparent} end end if keys.key?('classname') keys['class'] = keys.delete('classname') end @classname = keys['class'] @colormap = keys['colormap'] @container = keys['container'] @visual = keys['visual'] if !@classname && my_class_name keys['class'] = @classname = my_class_name end if @classname.kind_of? TkBindTag @db_class = @classname @classname = @classname.id elsif @classname @db_class = TkDatabaseClass.new(@classname) else @db_class = self.class @classname = @db_class::WidgetClassName end super(keys) end #def create_self(keys) # if keys and keys != None # tk_call_without_enc('frame', @path, *hash_kv(keys)) # else # tk_call_without_enc( 'frame', @path) # end #end #private :create_self def database_classname @classname end def self.database_class if self == WidgetClassNames[WidgetClassName] || self.name == '' self else TkDatabaseClass.new(self.name) end end def self.database_classname self.database_class.name end def self.bind(*args, &b) if self == WidgetClassNames[WidgetClassName] || self.name == '' super(*args, &b) else TkDatabaseClass.new(self.name).bind(*args, &b) end end def self.bind_append(*args, &b) if self == WidgetClassNames[WidgetClassName] || self.name == '' super(*args, &b) else TkDatabaseClass.new(self.name).bind_append(*args, &b) end end def self.bind_remove(*args) if self == WidgetClassNames[WidgetClassName] || self.name == '' super(*args) else TkDatabaseClass.new(self.name).bind_remove(*args) end end def self.bindinfo(*args) if self == WidgetClassNames[WidgetClassName] || self.name == '' super(*args) else TkDatabaseClass.new(self.name).bindinfo(*args) end end end #TkFrame = Tk::Frame unless Object.const_defined? :TkFrame Tk.__set_toplevel_aliases__(:Tk, Tk::Frame, :TkFrame) ================================================ FILE: ext/tk/lib/tk/grid.rb ================================================ # # tk/grid.rb : control grid geometry manager # require 'tk' module TkGrid include Tk extend Tk TkCommandNames = ['grid'.freeze].freeze def anchor(master, anchor=None) # master = master.epath if master.kind_of?(TkObject) master = _epath(master) tk_call_without_enc('grid', 'anchor', master, anchor) end def bbox(master, *args) # master = master.epath if master.kind_of?(TkObject) master = _epath(master) args.unshift(master) list(tk_call_without_enc('grid', 'bbox', *args)) end =begin def configure(win, *args) if args[-1].kind_of?(Hash) opts = args.pop else opts = {} end params = [] params.push(_epath(win)) args.each{|win| case win when '-', 'x', '^' # RELATIVE PLACEMENT params.push(win) else params.push(_epath(win)) end } opts.each{|k, v| params.push("-#{k}") params.push((v.kind_of?(TkObject))? v.epath: v) } if Tk::TCL_MAJOR_VERSION < 8 || (Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION <= 3) if params[0] == '-' || params[0] == 'x' || params[0] == '^' tk_call_without_enc('grid', *params) else tk_call_without_enc('grid', 'configure', *params) end else tk_call_without_enc('grid', 'configure', *params) end end =end def configure(*args) if args[-1].kind_of?(Hash) opts = args.pop else opts = {} end fail ArgumentError, 'no widget is given' if args.empty? params = [] args.flatten(1).each{|win| case win when '-', ?- # RELATIVE PLACEMENT (increase columnspan) params.push('-') when /^-+$/ # RELATIVE PLACEMENT (increase columnspan) params.concat(win.to_s.split(//)) when '^', ?^ # RELATIVE PLACEMENT (increase rowspan) params.push('^') when /^\^+$/ # RELATIVE PLACEMENT (increase rowspan) params.concat(win.to_s.split(//)) when 'x', :x, ?x, nil, '' # RELATIVE PLACEMENT (empty column) params.push('x') when /^x+$/ # RELATIVE PLACEMENT (empty column) params.concat(win.to_s.split(//)) else params.push(_epath(win)) end } opts.each{|k, v| params.push("-#{k}") params.push(_epath(v)) # have to use 'epath' (hash_kv() is unavailable) } if Tk::TCL_MAJOR_VERSION < 8 || (Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION <= 3) if params[0] == '-' || params[0] == 'x' || params[0] == '^' tk_call_without_enc('grid', *params) else tk_call_without_enc('grid', 'configure', *params) end else tk_call_without_enc('grid', 'configure', *params) end end alias grid configure def columnconfigure(master, index, args) # master = master.epath if master.kind_of?(TkObject) master = _epath(master) tk_call_without_enc("grid", 'columnconfigure', master, index, *hash_kv(args)) end alias column columnconfigure def rowconfigure(master, index, args) # master = master.epath if master.kind_of?(TkObject) master = _epath(master) tk_call_without_enc("grid", 'rowconfigure', master, index, *hash_kv(args)) end alias row rowconfigure def columnconfiginfo(master, index, slot=nil) # master = master.epath if master.kind_of?(TkObject) master = _epath(master) if slot case slot when 'uniform', :uniform tk_call_without_enc('grid', 'columnconfigure', master, index, "-#{slot}") else num_or_str(tk_call_without_enc('grid', 'columnconfigure', master, index, "-#{slot}")) end else #ilist = list(tk_call_without_enc('grid','columnconfigure',master,index)) ilist = simplelist(tk_call_without_enc('grid', 'columnconfigure', master, index)) info = {} while key = ilist.shift case key when 'uniform' info[key[1..-1]] = ilist.shift else info[key[1..-1]] = tk_tcl2ruby(ilist.shift) end end info end end def rowconfiginfo(master, index, slot=nil) # master = master.epath if master.kind_of?(TkObject) master = _epath(master) if slot case slot when 'uniform', :uniform tk_call_without_enc('grid', 'rowconfigure', master, index, "-#{slot}") else num_or_str(tk_call_without_enc('grid', 'rowconfigure', master, index, "-#{slot}")) end else #ilist = list(tk_call_without_enc('grid', 'rowconfigure', master, index)) ilist = simplelist(tk_call_without_enc('grid', 'rowconfigure', master, index)) info = {} while key = ilist.shift case key when 'uniform' info[key[1..-1]] = ilist.shift else info[key[1..-1]] = tk_tcl2ruby(ilist.shift) end end info end end def add(widget, *args) configure(widget, *args) end def forget(*args) return '' if args.size == 0 wins = args.collect{|win| # (win.kind_of?(TkObject))? win.epath: win _epath(win) } tk_call_without_enc('grid', 'forget', *wins) end def info(slave) # slave = slave.epath if slave.kind_of?(TkObject) slave = _epath(slave) #ilist = list(tk_call_without_enc('grid', 'info', slave)) ilist = simplelist(tk_call_without_enc('grid', 'info', slave)) info = {} while key = ilist.shift #info[key[1..-1]] = ilist.shift info[key[1..-1]] = tk_tcl2ruby(ilist.shift) end return info end def location(master, x, y) # master = master.epath if master.kind_of?(TkObject) master = _epath(master) list(tk_call_without_enc('grid', 'location', master, x, y)) end def propagate(master, mode=None) # master = master.epath if master.kind_of?(TkObject) master = _epath(master) if mode == None bool(tk_call_without_enc('grid', 'propagate', master)) else tk_call_without_enc('grid', 'propagate', master, mode) end end def remove(*args) return '' if args.size == 0 wins = args.collect{|win| # (win.kind_of?(TkObject))? win.epath: win _epath(win) } tk_call_without_enc('grid', 'remove', *wins) end def size(master) # master = master.epath if master.kind_of?(TkObject) master = _epath(master) list(tk_call_without_enc('grid', 'size', master)) end def slaves(master, args) # master = master.epath if master.kind_of?(TkObject) master = _epath(master) list(tk_call_without_enc('grid', 'slaves', master, *hash_kv(args))) end module_function :anchor, :bbox, :add, :forget, :propagate, :info module_function :remove, :size, :slaves, :location module_function :grid, :configure, :columnconfigure, :rowconfigure module_function :column, :row, :columnconfiginfo, :rowconfiginfo end =begin def TkGrid(win, *args) if args[-1].kind_of?(Hash) opts = args.pop else opts = {} end params = [] params.push((win.kind_of?(TkObject))? win.epath: win) args.each{|win| case win when '-', 'x', '^' # RELATIVE PLACEMENT params.push(win) else params.push((win.kind_of?(TkObject))? win.epath: win) end } opts.each{|k, v| params.push("-#{k}") params.push((v.kind_of?(TkObject))? v.epath: v) } tk_call_without_enc("grid", *params) end =end ================================================ FILE: ext/tk/lib/tk/image.rb ================================================ # # tk/image.rb : treat Tk image objects # require 'tk' class TkImage e if current_configinfo.has_key?(option.to_s) # error on known option fail e else # unknown option nil end end end end def copy(src, *opts) if opts.size == 0 tk_send('copy', src) elsif opts.size == 1 && opts[0].kind_of?(Hash) tk_send('copy', src, *_photo_hash_kv(opts[0])) else # for backward compatibility args = opts.collect{|term| if term.kind_of?(String) && term.include?(?\s) term.split else term end }.flatten tk_send('copy', src, *args) end self end def data(keys={}) #tk_send('data', *_photo_hash_kv(keys)) tk_split_list(tk_send('data', *_photo_hash_kv(keys))) end def get(x, y) tk_send('get', x, y).split.collect{|n| n.to_i} end def put(data, *opts) if opts == [] tk_send('put', data) elsif opts.size == 1 && opts[0].kind_of?(Hash) tk_send('put', data, *_photo_hash_kv(opts[0])) else # for backward compatibility tk_send('put', data, '-to', *opts) end self end def read(file, *opts) if opts.size == 0 tk_send('read', file) elsif opts.size == 1 && opts[0].kind_of?(Hash) tk_send('read', file, *_photo_hash_kv(opts[0])) else # for backward compatibility args = opts.collect{|term| if term.kind_of?(String) && term.include?(?\s) term.split else term end }.flatten tk_send('read', file, *args) end self end def redither tk_send 'redither' self end def get_transparency(x, y) bool(tk_send('transparency', 'get', x, y)) end def set_transparency(x, y, st) tk_send('transparency', 'set', x, y, st) self end def write(file, *opts) if opts.size == 0 tk_send('write', file) elsif opts.size == 1 && opts[0].kind_of?(Hash) tk_send('write', file, *_photo_hash_kv(opts[0])) else # for backward compatibility args = opts.collect{|term| if term.kind_of?(String) && term.include?(?\s) term.split else term end }.flatten tk_send('write', file, *args) end self end end ================================================ FILE: ext/tk/lib/tk/itemconfig.rb ================================================ # # tk/itemconfig.rb : control item/tag configuration of widget # require 'tk' require 'tkutil' require 'tk/itemfont.rb' module TkItemConfigOptkeys include TkUtil def __item_optkey_aliases(id) {} end private :__item_optkey_aliases def __item_numval_optkeys(id) [] end private :__item_numval_optkeys def __item_numstrval_optkeys(id) [] end private :__item_numstrval_optkeys def __item_boolval_optkeys(id) ['exportselection', 'jump', 'setgrid', 'takefocus'] end private :__item_boolval_optkeys def __item_strval_optkeys(id) # maybe need to override [ 'text', 'label', 'show', 'data', 'file', 'maskdata', 'maskfile', 'activebackground', 'activeforeground', 'background', 'disabledforeground', 'disabledbackground', 'foreground', 'highlightbackground', 'highlightcolor', 'insertbackground', 'selectbackground', 'selectforeground', 'troughcolor' ] end private :__item_strval_optkeys def __item_listval_optkeys(id) [] end private :__item_listval_optkeys def __item_numlistval_optkeys(id) # maybe need to override ['dash', 'activedash', 'disableddash'] end private :__item_numlistval_optkeys def __item_tkvariable_optkeys(id) ['variable', 'textvariable'] end private :__item_tkvariable_optkeys def __item_val2ruby_optkeys(id) # { key=>method, ... } # The method is used to convert a opt-value to a ruby's object. # When get the value of the option "key", "method.call(id, val)" is called. {} end private :__item_val2ruby_optkeys def __item_ruby2val_optkeys(id) # { key=>method, ... } # The method is used to convert a ruby's object to a opt-value. # When set the value of the option "key", "method.call(id, val)" is called. # That is, "-#{key} #{method.call(id, value)}". {} end private :__item_ruby2val_optkeys def __item_methodcall_optkeys(id) # { key=>method, ... } # Use the method for both of get and set. # Usually, the 'key' will not be a widget option. # # maybe need to override # {'coords'=>'coords'} {} end private :__item_methodcall_optkeys ################################################ def __item_keyonly_optkeys(id) # { def_key=>(undef_key|nil), ... } # maybe need to override {} end private :__item_keyonly_optkeys def __conv_item_keyonly_opts(id, keys) return keys unless keys.kind_of?(Hash) keyonly = __item_keyonly_optkeys(id) keys2 = {} keys.each{|k, v| optkey = keyonly.find{|kk,vv| kk.to_s == k.to_s} if optkey defkey, undefkey = optkey if v keys2[defkey.to_s] = None else keys2[undefkey.to_s] = None end else keys2[k.to_s] = v end } keys2 end def itemconfig_hash_kv(id, keys, enc_mode = nil, conf = nil) hash_kv(__conv_item_keyonly_opts(id, keys), enc_mode, conf) end end module TkItemConfigMethod include TkUtil include TkTreatItemFont include TkItemConfigOptkeys def TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ @mode || false end def TkItemConfigMethod.__set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode) fail SecurityError, "can't change the mode" if $SAFE>=4 @mode = (mode)? true: false end def __item_cget_cmd(id) # maybe need to override [self.path, 'itemcget', id] end private :__item_cget_cmd def __item_config_cmd(id) # maybe need to override [self.path, 'itemconfigure', id] end private :__item_config_cmd def __item_confinfo_cmd(id) # maybe need to override __item_config_cmd(id) end private :__item_confinfo_cmd def __item_configinfo_struct(id) # maybe need to override {:key=>0, :alias=>1, :db_name=>1, :db_class=>2, :default_value=>3, :current_value=>4} end private :__item_configinfo_struct ################################################ def tagid(tagOrId) # maybe need to override tagOrId end ################################################ def __itemcget_core(tagOrId, option) orig_opt = option option = option.to_s if option.length == 0 fail ArgumentError, "Invalid option `#{orig_opt.inspect}'" end alias_name, real_name = __item_optkey_aliases(tagid(tagOrId)).find{|k, v| k.to_s == option} if real_name option = real_name.to_s end if ( method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[option] ) optval = tk_call_without_enc(*(__item_cget_cmd(tagid(tagOrId)) << "-#{option}")) begin return method.call(tagOrId, optval) rescue => e warn("Warning:: #{e.message} (when #{method}.call(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG return optval end end if ( method = _symbolkey2str(__item_methodcall_optkeys(tagid(tagOrId)))[option] ) return self.__send__(method, tagOrId) end case option when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/ begin number(tk_call_without_enc(*(__item_cget_cmd(tagid(tagOrId)) << "-#{option}"))) rescue nil end when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/ num_or_str(tk_call_without_enc(*(__item_cget_cmd(tagid(tagOrId)) << "-#{option}"))) when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/ begin bool(tk_call_without_enc(*(__item_cget_cmd(tagid(tagOrId)) << "-#{option}"))) rescue nil end when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/ simplelist(tk_call_without_enc(*(__item_cget_cmd(tagid(tagOrId)) << "-#{option}"))) when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/ conf = tk_call_without_enc(*(__item_cget_cmd(tagid(tagOrId)) << "-#{option}")) if conf =~ /^[0-9]/ list(conf) else conf end when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/ v = tk_call_without_enc(*(__item_cget_cmd(tagid(tagOrId)) << "-#{option}")) (v.empty?)? nil: TkVarAccess.new(v) when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/ _fromUTF8(tk_call_without_enc(*(__item_cget_cmd(tagid(tagOrId)) << "-#{option}"))) when /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/ fontcode = $1 fontkey = $2 fnt = tk_tcl2ruby(tk_call_without_enc(*(__item_cget_cmd(tagid(tagOrId)) << "-#{fontkey}")), true) unless fnt.kind_of?(TkFont) fnt = tagfontobj(tagid(tagOrId), fontkey) end if fontcode == 'kanji' && JAPANIZED_TK && TK_VERSION =~ /^4\.*/ # obsolete; just for compatibility fnt.kanji_font else fnt end else tk_tcl2ruby(tk_call_without_enc(*(__item_cget_cmd(tagid(tagOrId)) << "-#{option}")), true) end end private :__itemcget_core def itemcget(tagOrId, option) unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ __itemcget_core(tagOrId, option) else begin __itemcget_core(tagOrId, option) rescue => e begin if __current_itemconfiginfo(tagOrId).has_key?(option.to_s) # not tag error & option is known -> error on known option fail e else # not tag error & option is unknown nil end rescue fail e # tag error end end end end def itemcget_strict(tagOrId, option) # never use TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ __itemcget_core(tagOrId, option) end def __itemconfigure_core(tagOrId, slot, value=None) if slot.kind_of? Hash slot = _symbolkey2str(slot) __item_optkey_aliases(tagid(tagOrId)).each{|alias_name, real_name| alias_name = alias_name.to_s if slot.has_key?(alias_name) slot[real_name.to_s] = slot.delete(alias_name) end } __item_methodcall_optkeys(tagid(tagOrId)).each{|key, method| value = slot.delete(key.to_s) self.__send__(method, tagOrId, value) if value } __item_ruby2val_optkeys(tagid(tagOrId)).each{|key, method| key = key.to_s slot[key] = method.call(tagOrId, slot[key]) if slot.has_key?(key) } __item_keyonly_optkeys(tagid(tagOrId)).each{|defkey, undefkey| conf = slot.find{|kk, vv| kk == defkey.to_s} if conf k, v = conf if v slot[k] = None else slot[undefkey.to_s] = None if undefkey slot.delete(k) end end } if (slot.find{|k, v| k =~ /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/}) tagfont_configure(tagid(tagOrId), slot) elsif slot.size > 0 tk_call(*(__item_config_cmd(tagid(tagOrId)).concat(hash_kv(slot)))) end else orig_slot = slot slot = slot.to_s if slot.length == 0 fail ArgumentError, "Invalid option `#{orig_slot.inspect}'" end alias_name, real_name = __item_optkey_aliases(tagid(tagOrId)).find{|k, v| k.to_s == slot} if real_name slot = real_name.to_s end if ( conf = __item_keyonly_optkeys(tagid(tagOrId)).find{|k, v| k.to_s == slot } ) defkey, undefkey = conf if value tk_call(*(__item_config_cmd(tagid(tagOrId)) << "-#{defkey}")) elsif undefkey tk_call(*(__item_config_cmd(tagid(tagOrId)) << "-#{undefkey}")) end elsif ( method = _symbolkey2str(__item_ruby2val_optkeys(tagid(tagOrId)))[slot] ) tk_call(*(__item_config_cmd(tagid(tagOrId)) << "-#{slot}" << method.call(tagOrId, value))) elsif ( method = _symbolkey2str(__item_methodcall_optkeys(tagid(tagOrId)))[slot] ) self.__send__(method, tagOrId, value) elsif (slot =~ /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/) if value == None tagfontobj(tagid(tagOrId), $2) else tagfont_configure(tagid(tagOrId), {slot=>value}) end else tk_call(*(__item_config_cmd(tagid(tagOrId)) << "-#{slot}" << value)) end end self end private :__itemconfigure_core def __check_available_itemconfigure_options(tagOrId, keys) id = tagid(tagOrId) availables = self.__current_itemconfiginfo(id).keys # add non-standard keys availables |= __font_optkeys.map{|k| [k.to_s, "latin#{k}", "ascii#{k}", "kanji#{k}"] }.flatten availables |= __item_methodcall_optkeys(id).keys.map{|k| k.to_s} availables |= __item_keyonly_optkeys(id).keys.map{|k| k.to_s} keys = _symbolkey2str(keys) keys.delete_if{|k, v| !(availables.include?(k))} end def itemconfigure(tagOrId, slot, value=None) unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ __itemconfigure_core(tagOrId, slot, value) else if slot.kind_of?(Hash) begin __itemconfigure_core(tagOrId, slot) rescue slot = __check_available_itemconfigure_options(tagOrId, slot) __itemconfigure_core(tagOrId, slot) unless slot.empty? end else begin __itemconfigure_core(tagOrId, slot, value) rescue => e begin if __current_itemconfiginfo(tagOrId).has_key?(slot.to_s) # not tag error & option is known -> error on known option fail e else # not tag error & option is unknown nil end rescue fail e # tag error end end end end self end def __itemconfiginfo_core(tagOrId, slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/) fontkey = $2 # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{fontkey}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{fontkey}")), false, true) conf[__item_configinfo_struct(tagid(tagOrId))[:key]] = conf[__item_configinfo_struct(tagid(tagOrId))[:key]][1..-1] if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \ || conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 ) fnt = conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] if TkFont.is_system_font?(fnt) conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkNamedFont.new(fnt) end conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tagfontobj(tagid(tagOrId), fontkey) elsif ( __item_configinfo_struct(tagid(tagOrId))[:alias] \ && conf.size == __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 \ && conf[__item_configinfo_struct(tagid(tagOrId))[:alias]][0] == ?- ) conf[__item_configinfo_struct(tagid(tagOrId))[:alias]] = conf[__item_configinfo_struct(tagid(tagOrId))[:alias]][1..-1] end conf else if slot slot = slot.to_s alias_name, real_name = __item_optkey_aliases(tagid(tagOrId)).find{|k, v| k.to_s == slot} if real_name slot = real_name.to_s end case slot when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/ method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[slot] conf = tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")), false, true) if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) optval = conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] begin val = method.call(tagOrId, optval) rescue => e warn("Warning:: #{e.message} (when #{method}.call(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG val = optval end conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = val end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) optval = conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] begin val = method.call(tagOrId, optval) rescue => e warn("Warning:: #{e.message} (when #{method}lcall(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG val = optval end conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = val end when /^(#{__item_methodcall_optkeys(tagid(tagOrId)).keys.join('|')})$/ method = _symbolkey2str(__item_methodcall_optkeys(tagid(tagOrId)))[slot] return [slot, '', '', '', self.__send__(method, tagOrId)] when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")), false, true) if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) begin conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = number(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) rescue conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = nil end end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) begin conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = number(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) rescue conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = nil end end when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")), false, true) if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = num_or_str(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = num_or_str(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) end when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")), false, true) if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) begin conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = bool(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) rescue conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = nil end end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) begin conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = bool(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) rescue conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = nil end end when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")), false, true) if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = simplelist(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = simplelist(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) end when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")), false, true) if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] =~ /^[0-9]/ ) conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = list(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] =~ /^[0-9]/ ) conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = list(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) end when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")), false, true) when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/ conf = tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")), false, true) if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) v = conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] if v.empty? conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = nil else conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkVarAccess.new(v) end end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) v = conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] if v.empty? conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = nil else conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = TkVarAccess.new(v) end end else # conf = tk_split_list(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))) conf = tk_split_list(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")), 0, false, true) end conf[__item_configinfo_struct(tagid(tagOrId))[:key]] = conf[__item_configinfo_struct(tagid(tagOrId))[:key]][1..-1] if ( __item_configinfo_struct(tagid(tagOrId))[:alias] \ && conf.size == __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 \ && conf[__item_configinfo_struct(tagid(tagOrId))[:alias]][0] == ?- ) conf[__item_configinfo_struct(tagid(tagOrId))[:alias]] = conf[__item_configinfo_struct(tagid(tagOrId))[:alias]][1..-1] end conf else # ret = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)))))).collect{|conflist| # conf = tk_split_simplelist(conflist) ret = tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)))), false, false).collect{|conflist| conf = tk_split_simplelist(conflist, false, true) conf[__item_configinfo_struct(tagid(tagOrId))[:key]] = conf[__item_configinfo_struct(tagid(tagOrId))[:key]][1..-1] optkey = conf[__item_configinfo_struct(tagid(tagOrId))[:key]] case optkey when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/ method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[optkey] if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) optval = conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] begin val = method(tagOrId, optval) rescue => e warn("Warning:: #{e.message} (when #{method}.call(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG val = optval end conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = val end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) optval = conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] begin val = method.call(tagOrId, optval) rescue => e warn("Warning:: #{e.message} (when #{method}.call(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG val = optval end conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = val end when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/ # do nothing when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/ if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) begin conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = number(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) rescue conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = nil end end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) begin conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = number(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) rescue conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = nil end end when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/ if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = num_or_str(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = num_or_str(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) end when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/ if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) begin conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = bool(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) rescue conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = nil end end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) begin conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = bool(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) rescue conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = nil end end when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/ if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = simplelist(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = simplelist(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) end when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/ if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] =~ /^[0-9]/ ) conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = list(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] =~ /^[0-9]/ ) conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = list(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) end when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/ if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) v = conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] if v.empty? conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = nil else conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkVarAccess.new(v) end end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) v = conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] if v.empty? conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = nil else conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = TkVarAccess.new(v) end end else if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) if conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]].index('{') conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = tk_split_list(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) else conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = tk_tcl2ruby(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) end end if conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] if conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]].index('{') conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tk_split_list(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) else conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tk_tcl2ruby(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) end end end if ( __item_configinfo_struct(tagid(tagOrId))[:alias] \ && conf.size == __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 \ && conf[__item_configinfo_struct(tagid(tagOrId))[:alias]][0] == ?- ) conf[__item_configinfo_struct(tagid(tagOrId))[:alias]] = conf[__item_configinfo_struct(tagid(tagOrId))[:alias]][1..-1] end conf } __item_font_optkeys(tagid(tagOrId)).each{|optkey| optkey = optkey.to_s fontconf = ret.assoc(optkey) if fontconf && fontconf.size > 2 ret.delete_if{|inf| inf[0] =~ /^(|latin|ascii|kanji)#{optkey}$/} fnt = fontconf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] if TkFont.is_system_font?(fnt) fontconf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkNamedFont.new(fnt) end fontconf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tagfontobj(tagid(tagOrId), optkey) ret.push(fontconf) end } __item_methodcall_optkeys(tagid(tagOrId)).each{|optkey, method| ret << [optkey.to_s, '', '', '', self.__send__(method, tagOrId)] } ret end end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/) fontkey = $2 # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{fontkey}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{fontkey}")), false, true) conf[__item_configinfo_struct(tagid(tagOrId))[:key]] = conf[__item_configinfo_struct(tagid(tagOrId))[:key]][1..-1] if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \ || conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 ) fnt = conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] if TkFont.is_system_font?(fnt) conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkNamedFont.new(fnt) end conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tagfontobj(tagid(tagOrId), fontkey) { conf.shift => conf } elsif ( __item_configinfo_struct(tagid(tagOrId))[:alias] \ && conf.size == __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 ) if conf[__item_configinfo_struct(tagid(tagOrId))[:alias]][0] == ?- conf[__item_configinfo_struct(tagid(tagOrId))[:alias]] = conf[__item_configinfo_struct(tagid(tagOrId))[:alias]][1..-1] end { conf[0] => conf[1] } else { conf.shift => conf } end else if slot slot = slot.to_s alias_name, real_name = __item_optkey_aliases(tagid(tagOrId)).find{|k, v| k.to_s == slot} if real_name slot = real_name.to_s end case slot when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/ method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[slot] conf = tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")), false, true) if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) optval = conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] begin val = method.call(tagOrId, optval) rescue => e warn("Warning:: #{e.message} (when #{method}.call(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG val = optval end conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = val end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) optval = conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] begin val = method.call(tagOrId, optval) rescue => e warn("Warning:: #{e.message} (when #{method}.call(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG val = optval end conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = val end when /^(#{__item_methodcall_optkeys(tagid(tagOrId)).keys.join('|')})$/ method = _symbolkey2str(__item_methodcall_optkeys(tagid(tagOrId)))[slot] return {slot => ['', '', '', self.__send__(method, tagOrId)]} when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")), false, true) if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) begin conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = number(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) rescue conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = nil end end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) begin conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = number(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) rescue conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = nil end end when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")), false, true) if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = num_or_stre(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = num_or_str(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) end when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")), false, true) if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) begin conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = bool(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) rescue conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = nil end end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) begin conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = bool(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) rescue conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = nil end end when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")), false, true) if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = simplelist(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = simplelist(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) end when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")), false, true) if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] =~ /^[0-9]/ ) conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = list(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] =~ /^[0-9]/ ) conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = list(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) end when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")), false, true) when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/ conf = tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")), false, true) if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) v = conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] if v.empty? conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = nil else conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkVarAccess.new(v) end end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) v = conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] if v.empty? conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = nil else conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = TkVarAccess.new(v) end end else # conf = tk_split_list(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))) conf = tk_split_list(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")), 0, false, true) end conf[__item_configinfo_struct(tagid(tagOrId))[:key]] = conf[__item_configinfo_struct(tagid(tagOrId))[:key]][1..-1] if ( __item_configinfo_struct(tagid(tagOrId))[:alias] \ && conf.size == __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 ) if conf[__item_configinfo_struct(tagid(tagOrId))[:alias]][0] == ?- conf[__item_configinfo_struct(tagid(tagOrId))[:alias]] = conf[__item_configinfo_struct(tagid(tagOrId))[:alias]][1..-1] end { conf[0] => conf[1] } else { conf.shift => conf } end else ret = {} # tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)))))).each{|conflist| # conf = tk_split_simplelist(conflist) tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)))), false, false).each{|conflist| conf = tk_split_simplelist(conflist, false, true) conf[__item_configinfo_struct(tagid(tagOrId))[:key]] = conf[__item_configinfo_struct(tagid(tagOrId))[:key]][1..-1] optkey = conf[__item_configinfo_struct(tagid(tagOrId))[:key]] case optkey when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/ method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[optkey] if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) optval = conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] begin val = method.call(tagOrId, optval) rescue => e warn("Warning:: #{e.message} (when #{method}.call(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG val = optval end conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = val end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) optval = conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] begin val = method.call(tagOrId, optval) rescue => e warn("Warning:: #{e.message} (when #{method}.call(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG val = optval end conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = val end when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/ # do nothing when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/ if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) begin conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = number(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) rescue conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = nil end end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) begin conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = number(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) rescue conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = nil end end when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/ if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = num_or_str(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = num_or_str(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) end when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/ if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) begin conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = bool(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) rescue conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = nil end end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) begin conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = bool(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) rescue conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = nil end end when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/ if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = simplelist(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = simplelist(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) end when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/ if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] =~ /^[0-9]/ ) conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = list(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] =~ /^[0-9]/ ) conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = list(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) end when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/ if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) v = conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] if v.empty? conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = nil else conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkVarAccess.new(v) end end if ( conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] ) v = conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] if v.empty? conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = nil else conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = TkVarAccess.new(v) end end else if ( __item_configinfo_struct(tagid(tagOrId))[:default_value] \ && conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] ) if conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]].index('{') conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = tk_split_list(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) else conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = tk_tcl2ruby(conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]) end end if conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] if conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]].index('{') conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tk_split_list(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) else conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tk_tcl2ruby(conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]]) end end end if ( __item_configinfo_struct(tagid(tagOrId))[:alias] \ && conf.size == __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 ) if conf[__item_configinfo_struct(tagid(tagOrId))[:alias]][0] == ?- conf[__item_configinfo_struct(tagid(tagOrId))[:alias]] = conf[__item_configinfo_struct(tagid(tagOrId))[:alias]][1..-1] end ret[conf[0]] = conf[1] else ret[conf.shift] = conf end } __item_font_optkeys(tagid(tagOrId)).each{|optkey| optkey = optkey.to_s fontconf = ret[optkey] if fontconf.kind_of?(Array) ret.delete(optkey) ret.delete('latin' << optkey) ret.delete('ascii' << optkey) ret.delete('kanji' << optkey) fnt = fontconf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] if TkFont.is_system_font?(fnt) fontconf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkNamedFont.new(fnt) end fontconf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tagfontobj(tagid(tagOrId), optkey) ret[optkey] = fontconf end } __item_methodcall_optkeys(tagid(tagOrId)).each{|optkey, method| ret[optkey.to_s] = ['', '', '', self.__send__(method, tagOrId)] } ret end end end end private :__itemconfiginfo_core def itemconfiginfo(tagOrId, slot = nil) if slot && TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ begin __itemconfiginfo_core(tagOrId, slot) rescue => e begin __itemconfiginfo_core(tagOrId) # not tag error -> option is unknown Array.new(__item_configinfo_struct.values.max).unshift(slot.to_s) rescue fail e # tag error end end else __itemconfiginfo_core(tagOrId, slot) end end def __current_itemconfiginfo(tagOrId, slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if slot org_slot = slot begin conf = __itemconfiginfo_core(tagOrId, slot) if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \ || conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 ) return {conf[0] => conf[-1]} end slot = conf[__item_configinfo_struct(tagid(tagOrId))[:alias]] end while(org_slot != slot) fail RuntimeError, "there is a configure alias loop about '#{org_slot}'" else ret = {} __itemconfiginfo_core(tagOrId).each{|conf| if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \ || conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 ) ret[conf[0]] = conf[-1] end } ret end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY ret = {} __itemconfiginfo_core(tagOrId, slot).each{|key, conf| ret[key] = conf[-1] if conf.kind_of?(Array) } ret end end def current_itemconfiginfo(tagOrId, slot = nil) __current_itemconfiginfo(tagOrId, slot) end end ================================================ FILE: ext/tk/lib/tk/itemfont.rb ================================================ # # tk/itemfont.rb : control font of widget items # require 'tk' module TkItemFontOptkeys def __item_font_optkeys(id) # maybe need to override ['font'] end private :__item_font_optkeys end module TkTreatItemFont include TkItemFontOptkeys def __item_pathname(id) # maybe need to override [self.path, id].join(';') end private :__item_pathname ################################################ def tagfont_configinfo(tagOrId, key = nil) optkeys = __item_font_optkeys(tagid(tagOrId)) if key && !optkeys.find{|opt| opt.to_s == key.to_s} fail ArgumentError, "unknown font option name `#{key}'" end win, tag = __item_pathname(tagid(tagOrId)).split(';') if key pathname = [win, tag, key].join(';') TkFont.used_on(pathname) || TkFont.init_widget_font(pathname, *(__item_confinfo_cmd(tagid(tagOrId)))) elsif optkeys.size == 1 pathname = [win, tag, optkeys[0]].join(';') TkFont.used_on(pathname) || TkFont.init_widget_font(pathname, *(__item_confinfo_cmd(tagid(tagOrId)))) else fonts = {} optkeys.each{|key| key = key.to_s pathname = [win, tag, key].join(';') fonts[key] = TkFont.used_on(pathname) || TkFont.init_widget_font(pathname, *(__item_confinfo_cmd(tagid(tagOrId)))) } fonts end end alias tagfontobj tagfont_configinfo def tagfont_configure(tagOrId, slot) pathname = __item_pathname(tagid(tagOrId)) slot = _symbolkey2str(slot) __item_font_optkeys(tagid(tagOrId)).each{|optkey| optkey = optkey.to_s l_optkey = 'latin' << optkey a_optkey = 'ascii' << optkey k_optkey = 'kanji' << optkey if slot.key?(optkey) fnt = slot.delete(optkey) if fnt.kind_of?(TkFont) slot.delete(l_optkey) slot.delete(a_optkey) slot.delete(k_optkey) fnt.call_font_configure([pathname, optkey], *(__item_config_cmd(tagid(tagOrId)) << {})) next else if fnt if (slot.key?(l_optkey) || slot.key?(a_optkey) || slot.key?(k_optkey)) fnt = TkFont.new(fnt) lfnt = slot.delete(l_optkey) lfnt = slot.delete(a_optkey) if slot.key?(a_optkey) kfnt = slot.delete(k_optkey) fnt.latin_replace(lfnt) if lfnt fnt.kanji_replace(kfnt) if kfnt fnt.call_font_configure([pathname, optkey], *(__item_config_cmd(tagid(tagOrId)) << {})) next else fnt = hash_kv(fnt) if fnt.kind_of?(Hash) unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ tk_call(*(__item_config_cmd(tagid(tagOrId)) << "-#{optkey}" << fnt)) else begin tk_call(*(__item_config_cmd(tagid(tagOrId)) << "-#{optkey}" << fnt)) rescue => e # ignore end end end end next end end lfnt = slot.delete(l_optkey) lfnt = slot.delete(a_optkey) if slot.key?(a_optkey) kfnt = slot.delete(k_optkey) if lfnt && kfnt TkFont.new(lfnt, kfnt).call_font_configure([pathname, optkey], *(__item_config_cmd(tagid(tagOrId)) << {})) elsif lfnt latintagfont_configure([lfnt, optkey]) elsif kfnt kanjitagfont_configure([kfnt, optkey]) end } # configure other (without font) options tk_call(*(__item_config_cmd(tagid(tagOrId)).concat(hash_kv(slot)))) if slot != {} self end def latintagfont_configure(tagOrId, ltn, keys=nil) if ltn.kind_of?(Array) key = ltn[1] ltn = ltn[0] else key = nil end optkeys = __item_font_optkeys(tagid(tagOrId)) if key && !optkeys.find{|opt| opt.to_s == key.to_s} fail ArgumentError, "unknown font option name `#{key}'" end win, tag = __item_pathname(tagid(tagOrId)).split(';') optkeys = [key] if key optkeys.each{|optkey| optkey = optkey.to_s pathname = [win, tag, optkey].join(';') if (fobj = TkFont.used_on(pathname)) fobj = TkFont.new(fobj) # create a new TkFont object elsif Tk::JAPANIZED_TK fobj = fontobj # create a new TkFont object else ltn = hash_kv(ltn) if ltn.kind_of?(Hash) unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ tk_call(*(__item_config_cmd(tagid(tagOrId)) << "-#{optkey}" << ltn)) else begin tk_call(*(__item_config_cmd(tagid(tagOrId)) << "-#{optkey}" << ltn)) rescue => e # ignore end end next end if fobj.kind_of?(TkFont) if ltn.kind_of?(TkFont) conf = {} ltn.latin_configinfo.each{|key,val| conf[key] = val} if keys fobj.latin_configure(conf.update(keys)) else fobj.latin_configure(conf) end else fobj.latin_replace(ltn) end end fobj.call_font_configure([pathname, optkey], *(__item_config_cmd(tagid(tagOrId)) << {})) } self end alias asciitagfont_configure latintagfont_configure def kanjitagfont_configure(tagOrId, knj, keys=nil) if knj.kind_of?(Array) key = knj[1] knj = knj[0] else key = nil end optkeys = __item_font_optkeys(tagid(tagOrId)) if key && !optkeys.find{|opt| opt.to_s == key.to_s} fail ArgumentError, "unknown font option name `#{key}'" end win, tag = __item_pathname(tagid(tagOrId)).split(';') optkeys = [key] if key optkeys.each{|optkey| optkey = optkey.to_s pathname = [win, tag, optkey].join(';') if (fobj = TkFont.used_on(pathname)) fobj = TkFont.new(fobj) # create a new TkFont object elsif Tk::JAPANIZED_TK fobj = fontobj # create a new TkFont object else knj = hash_kv(knj) if knj.kind_of?(Hash) unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ tk_call(*(__item_config_cmd(tagid(tagOrId)) << "-#{optkey}" << knj)) else begin tk_call(*(__item_config_cmd(tagid(tagOrId)) << "-#{optkey}" << knj)) rescue => e # ignore end end next end if fobj.kind_of?(TkFont) if knj.kind_of?(TkFont) conf = {} knj.kanji_configinfo.each{|key,val| conf[key] = val} if keys fobj.kanji_configure(conf.update(keys)) else fobj.kanji_configure(conf) end else fobj.kanji_replace(knj) end end fobj.call_font_configure([pathname, optkey], *(__item_config_cmd(tagid(tagOrId)) << {})) } self end def tagfont_copy(tagOrId, win, wintag=nil, winkey=nil, targetkey=nil) if wintag if winkey fnt = win.tagfontobj(wintag, winkey).dup else fnt = win.tagfontobj(wintag).dup end else if winkey fnt = win.fontobj(winkey).dup else fnt = win.fontobj.dup end end if targetkey fnt.call_font_configure([__item_pathname(tagid(tagOrId)), targetkey], *(__item_config_cmd(tagid(tagOrId)) << {})) else fnt.call_font_configure(__item_pathname(tagid(tagOrId)), *(__item_config_cmd(tagid(tagOrId)) << {})) end self end def latintagfont_copy(tagOrId, win, wintag=nil, winkey=nil, targetkey=nil) if targetkey fontobj(targetkey).dup.call_font_configure([__item_pathname(tagid(tagOrId)), targetkey], *(__item_config_cmd(tagid(tagOrId)) << {})) else fontobj.dup.call_font_configure(__item_pathname(tagid(tagOrId)), *(__item_config_cmd(tagid(tagOrId)) << {})) end if wintag if winkey fontobj.latin_replace(win.tagfontobj(wintag, winkey).latin_font_id) else fontobj.latin_replace(win.tagfontobj(wintag).latin_font_id) end else if winkey fontobj.latin_replace(win.fontobj(winkey).latin_font_id) else fontobj.latin_replace(win.fontobj.latin_font_id) end end self end alias asciitagfont_copy latintagfont_copy def kanjifont_copy(tagOrId, win, wintag=nil, winkey=nil, targetkey=nil) if targetkey fontobj(targetkey).dup.call_font_configure([__item_pathname(tagid(tagOrId)), targetkey], *(__item_config_cmd(tagid(tagOrId)) << {})) else fontobj.dup.call_font_configure(__item_pathname(tagid(tagOrId)), *(__item_config_cmd(tagid(tagOrId)) << {})) end if wintag if winkey fontobj.kanji_replace(win.tagfontobj(wintag, winkey).kanji_font_id) else fontobj.kanji_replace(win.tagfontobj(wintag).kanji_font_id) end else if winkey fontobj.kanji_replace(win.fontobj(winkey).kanji_font_id) else fontobj.kanji_replace(win.fontobj.kanji_font_id) end end self end end ================================================ FILE: ext/tk/lib/tk/kinput.rb ================================================ # # tk/kinput.rb : control kinput # require 'tk' module TkKinput include Tk extend Tk TkCommandNames = [ 'kinput_start'.freeze, 'kinput_send_spot'.freeze, 'kanjiInput'.freeze ].freeze def TkKinput.start(win, style=None) tk_call('kinput_start', win, style) end def kinput_start(style=None) TkKinput.start(self, style) end def TkKinput.send_spot(win) tk_call('kinput_send_spot', win) end def kinput_send_spot TkKinput.send_spot(self) end def TkKinput.input_start(win, keys=nil) tk_call('kanjiInput', 'start', win, *hash_kv(keys)) end def kanji_input_start(keys=nil) TkKinput.input_start(self, keys) end def TkKinput.attribute_config(win, slot, value=None) if slot.kind_of? Hash tk_call('kanjiInput', 'attribute', win, *hash_kv(slot)) else tk_call('kanjiInput', 'attribute', win, "-#{slot}", value) end end def kinput_attribute_config(slot, value=None) TkKinput.attribute_config(self, slot, value) end def TkKinput.attribute_info(win, slot=nil) if slot conf = tk_split_list(tk_call('kanjiInput', 'attribute', win, "-#{slot}")) conf[0] = conf[0][1..-1] conf else tk_split_list(tk_call('kanjiInput', 'attribute', win)).collect{|conf| conf[0] = conf[0][1..-1] conf } end end def kinput_attribute_info(slot=nil) TkKinput.attribute_info(self, slot) end def TkKinput.input_end(win) tk_call('kanjiInput', 'end', win) end def kanji_input_end TkKinput.input_end(self) end end ================================================ FILE: ext/tk/lib/tk/label.rb ================================================ # # tk/label.rb : treat label widget # require 'tk' class Tk::Labelproc, ... } super().update('labelwidget'=>proc{|v| window(v)}) end private :__val2ruby_optkeys end Tk::Labelframe = Tk::LabelFrame #TkLabelFrame = Tk::LabelFrame unless Object.const_defined? :TkLabelFrame #TkLabelframe = Tk::Labelframe unless Object.const_defined? :TkLabelframe Tk.__set_toplevel_aliases__(:Tk, Tk::LabelFrame, :TkLabelFrame, :TkLabelframe) ================================================ FILE: ext/tk/lib/tk/listbox.rb ================================================ # # tk/listbox.rb : treat listbox widget # require 'tk' require 'tk/itemconfig' require 'tk/scrollable' require 'tk/txtwin_abst' module TkListItemConfig include TkItemConfigMethod def __item_listval_optkeys(id) [] end private :__item_listval_optkeys end class Tk::Listboxval}) end else tk_call('itemconfigure', index, "-#{key}", val) end end self end def itemconfiginfo(index, key=nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if key case key.to_s when 'text', 'label', 'show' conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure',index,"-#{key}"))) when 'font', 'kanjifont' conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure',index,"-#{key}"))) conf[4] = tagfont_configinfo(index, conf[4]) else conf = tk_split_list(_fromUTF8(tk_send_without_enc('itemconfigure',index,"-#{key}"))) end conf[0] = conf[0][1..-1] conf else ret = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure', index))).collect{|conflist| conf = tk_split_simplelist(conflist) conf[0] = conf[0][1..-1] case conf[0] when 'text', 'label', 'show' else if conf[3] if conf[3].index('{') conf[3] = tk_split_list(conf[3]) else conf[3] = tk_tcl2ruby(conf[3]) end end if conf[4] if conf[4].index('{') conf[4] = tk_split_list(conf[4]) else conf[4] = tk_tcl2ruby(conf[4]) end end end conf[1] = conf[1][1..-1] if conf.size == 2 # alias info conf } fontconf = ret.assoc('font') if fontconf ret.delete_if{|item| item[0] == 'font' || item[0] == 'kanjifont'} fontconf[4] = tagfont_configinfo(index, fontconf[4]) ret.push(fontconf) else ret end end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY if key case key.to_s when 'text', 'label', 'show' conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure',index,"-#{key}"))) when 'font', 'kanjifont' conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure',index,"-#{key}"))) conf[4] = tagfont_configinfo(index, conf[4]) else conf = tk_split_list(_fromUTF8(tk_send_without_enc('itemconfigure',index,"-#{key}"))) end key = conf.shift[1..-1] { key => conf } else ret = {} tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure', index))).each{|conflist| conf = tk_split_simplelist(conflist) key = conf.shift[1..-1] case key when 'text', 'label', 'show' else if conf[2] if conf[2].index('{') conf[2] = tk_split_list(conf[2]) else conf[2] = tk_tcl2ruby(conf[2]) end end if conf[3] if conf[3].index('{') conf[3] = tk_split_list(conf[3]) else conf[3] = tk_tcl2ruby(conf[3]) end end end if conf.size == 1 ret[key] = conf[0][1..-1] # alias info else ret[key] = conf end } fontconf = ret['font'] if fontconf ret.delete('font') ret.delete('kanjifont') fontconf[3] = tagfont_configinfo(index, fontconf[3]) ret['font'] = fontconf end ret end end end def current_itemconfiginfo(index, key=nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if key conf = itemconfiginfo(index, key) {conf[0] => conf[4]} else ret = {} itemconfiginfo(index).each{|conf| ret[conf[0]] = conf[4] if conf.size > 2 } ret end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY ret = {} itemconfiginfo(index, key).each{|k, conf| ret[k] = conf[-1] if conf.kind_of?(Array) } ret end end =end end #TkListbox = Tk::Listbox unless Object.const_defined? :TkListbox Tk.__set_toplevel_aliases__(:Tk, Tk::Listbox, :TkListbox) ================================================ FILE: ext/tk/lib/tk/macpkg.rb ================================================ # # tk/macpkg.rb : methods for Tcl/Tk packages for Macintosh # 2000/11/22 by Hidetoshi Nagai # # ATTENTION !! # This is NOT TESTED. Because I have no test-environment. # # require 'tk' module Tk def Tk.load_tclscript_rsrc(resource_name, file=None) # Mac only tk_call('source', '-rsrc', resource_name, file) end def Tk.load_tclscript_rsrcid(resource_id, file=None) # Mac only tk_call('source', '-rsrcid', resource_id, file) end end module Tk::MacResource end #TkMacResource = Tk::MacResource Tk.__set_toplevel_aliases__(:Tk, Tk::MacResource, :TkMacResource) module Tk::MacResource extend Tk extend Tk::MacResource TkCommandNames = ['resource'.freeze].freeze PACKAGE_NAME = 'resource'.freeze def self.package_name PACKAGE_NAME end tk_call_without_enc('package', 'require', 'resource') def close(rsrcRef) tk_call('resource', 'close', rsrcRef) end def delete(rsrcType, opts=nil) tk_call('resource', 'delete', *(hash_kv(opts) << rsrcType)) end def files(rsrcRef=nil) if rsrcRef tk_call('resource', 'files', rsrcRef) else tk_split_simplelist(tk_call('resource', 'files')) end end def list(rsrcType, rsrcRef=nil) tk_split_simplelist(tk_call('resource', 'list', rsrcType, rsrcRef)) end def open(fname, access=nil) tk_call('resource', 'open', fname, access) end def read(rsrcType, rsrcID, rsrcRef=nil) tk_call('resource', 'read', rsrcType, rsrcID, rsrcRef) end def types(rsrcRef=nil) tk_split_simplelist(tk_call('resource', 'types', rsrcRef)) end def write(rsrcType, data, opts=nil) tk_call('resource', 'write', *(hash_kv(opts) << rsrcType << data)) end module_function :close, :delete, :files, :list, :open, :read, :types, :write end ================================================ FILE: ext/tk/lib/tk/menu.rb ================================================ # # tk/menu.rb : treat menu and menubutton # require 'tk' require 'tk/itemconfig' require 'tk/menuspec' module TkMenuEntryConfig include TkItemConfigMethod def __item_cget_cmd(id) [self.path, 'entrycget', id] end private :__item_cget_cmd def __item_config_cmd(id) [self.path, 'entryconfigure', id] end private :__item_config_cmd def __item_strval_optkeys(id) super(id) << 'selectcolor' end private :__item_strval_optkeys def __item_listval_optkeys(id) [] end private :__item_listval_optkeys def __item_val2ruby_optkeys(id) # { key=>proc, ... } super(id).update('menu'=>proc{|i, v| window(v)}) end private :__item_val2ruby_optkeys alias entrycget itemcget alias entrycget_strict itemcget_strict alias entryconfigure itemconfigure alias entryconfiginfo itemconfiginfo alias current_entryconfiginfo current_itemconfiginfo private :itemcget, :itemcget_strict private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo end class Tk::Menuval}) end else tk_call('entryconfigure', index, "-#{key}", val) end end self end def entryconfiginfo(index, key=nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if key case key.to_s when 'text', 'label', 'show' conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('entryconfigure',_get_eval_enc_str(index),"-#{key}"))) when 'font', 'kanjifont' conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('entryconfigure',_get_eval_enc_str(index),"-#{key}"))) conf[4] = tagfont_configinfo(index, conf[4]) else conf = tk_split_list(_fromUTF8(tk_send_without_enc('entryconfigure',_get_eval_enc_str(index),"-#{key}"))) end conf[0] = conf[0][1..-1] conf else ret = tk_split_simplelist(_fromUTF8(tk_send_without_enc('entryconfigure', _get_eval_enc_str(index)))).collect{|conflist| conf = tk_split_simplelist(conflist) conf[0] = conf[0][1..-1] case conf[0] when 'text', 'label', 'show' else if conf[3] if conf[3].index('{') conf[3] = tk_split_list(conf[3]) else conf[3] = tk_tcl2ruby(conf[3]) end end if conf[4] if conf[4].index('{') conf[4] = tk_split_list(conf[4]) else conf[4] = tk_tcl2ruby(conf[4]) end end end conf[1] = conf[1][1..-1] if conf.size == 2 # alias info conf } if fontconf ret.delete_if{|item| item[0] == 'font' || item[0] == 'kanjifont'} fontconf[4] = tagfont_configinfo(index, fontconf[4]) ret.push(fontconf) else ret end end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY if key case key.to_s when 'text', 'label', 'show' conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('entryconfigure',_get_eval_enc_str(index),"-#{key}"))) when 'font', 'kanjifont' conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('entryconfigure',_get_eval_enc_str(index),"-#{key}"))) conf[4] = tagfont_configinfo(index, conf[4]) else conf = tk_split_list(_fromUTF8(tk_send_without_enc('entryconfigure',_get_eval_enc_str(index),"-#{key}"))) end key = conf.shift[1..-1] { key => conf } else ret = {} tk_split_simplelist(_fromUTF8(tk_send_without_enc('entryconfigure', _get_eval_enc_str(index)))).each{|conflist| conf = tk_split_simplelist(conflist) key = conf.shift[1..-1] case key when 'text', 'label', 'show' else if conf[2] if conf[2].index('{') conf[2] = tk_split_list(conf[2]) else conf[2] = tk_tcl2ruby(conf[2]) end end if conf[3] if conf[3].index('{') conf[3] = tk_split_list(conf[3]) else conf[3] = tk_tcl2ruby(conf[3]) end end end if conf.size == 1 ret[key] = conf[0][1..-1] # alias info else ret[key] = conf end } fontconf = ret['font'] if fontconf ret.delete('font') ret.delete('kanjifont') fontconf[3] = tagfont_configinfo(index, fontconf[3]) ret['font'] = fontconf end ret end end end def current_entryconfiginfo(index, key=nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if key conf = entryconfiginfo(index, key) {conf[0] => conf[4]} else ret = {} entryconfiginfo(index).each{|conf| ret[conf[0]] = conf[4] if conf.size > 2 } ret end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY ret = {} entryconfiginfo(index, key).each{|k, conf| ret[k] = conf[-1] if conf.kind_of?(Array) } ret end end =end end #TkMenu = Tk::Menu unless Object.const_defined? :TkMenu Tk.__set_toplevel_aliases__(:Tk, Tk::Menu, :TkMenu) class Tk::MenuClone return value of tk_optionMenu @path = path #TkComm::Tk_WINDOWS[@path] = self TkCore::INTERP.tk_windows[@path] = self end end def initialize(*args) # args :: [parent,] [var,] [value[, ...],] [keys] # parent --> TkWindow or nil # var --> TkVariable or nil # keys --> Hash # keys[:parent] or keys['parent'] --> parent # keys[:variable] or keys['variable'] --> var # keys[:values] or keys['values'] --> value, ... # other Hash keys are menubutton options keys = {} keys = args.pop if args[-1].kind_of?(Hash) keys = _symbolkey2str(keys) parent = nil if args[0].kind_of?(TkWindow) || args[0] == nil keys.delete('parent') # ignore parent = args.shift else parent = keys.delete('parent') end @variable = nil if args[0].kind_of?(TkVariable) || args[0] == nil keys.delete('variable') # ignore @variable = args.shift else @variable = keys.delete('variable') end @variable = TkVariable.new unless @variable (args = keys.delete('values') || []) if args.empty? if args.empty? args << @variable.value else @variable.value = args[0] end install_win(if parent then parent.path end) @menu = OptionMenu.new(tk_call('tk_optionMenu', @path, @variable.id, *args)) configure(keys) if keys end def value @variable.value end def value=(val) @variable.value = val end def activate(index) @menu.activate(index) self end def add(value) @menu.add('radiobutton', 'variable'=>@variable, 'label'=>value, 'value'=>value) self end def index(index) @menu.index(index) end def invoke(index) @menu.invoke(index) end def insert(index, value) @menu.insert(index, 'radiobutton', 'variable'=>@variable, 'label'=>value, 'value'=>value) self end def delete(index, last=None) @menu.delete(index, last) self end def xposition(index) @menu.xposition(index) end def yposition(index) @menu.yposition(index) end def menu @menu end def menucget(key) @menu.cget(key) end def menucget_strict(key) @menu.cget_strict(key) end def menuconfigure(key, val=None) @menu.configure(key, val) self end def menuconfiginfo(key=nil) @menu.configinfo(key) end def current_menuconfiginfo(key=nil) @menu.current_configinfo(key) end def entrycget(index, key) @menu.entrycget(index, key) end def entrycget_strict(index, key) @menu.entrycget_strict(index, key) end def entryconfigure(index, key, val=None) @menu.entryconfigure(index, key, val) self end def entryconfiginfo(index, key=nil) @menu.entryconfiginfo(index, key) end def current_entryconfiginfo(index, key=nil) @menu.current_entryconfiginfo(index, key) end end Tk::OptionMenuButton = Tk::OptionMenubutton #TkOptionMenubutton = Tk::OptionMenubutton unless Object.const_defined? :TkOptionMenubutton #TkOptionMenuButton = Tk::OptionMenuButton unless Object.const_defined? :TkOptionMenuButton Tk.__set_toplevel_aliases__(:Tk, Tk::OptionMenubutton, :TkOptionMenubutton, :TkOptionMenuButton) ================================================ FILE: ext/tk/lib/tk/menubar.rb ================================================ # # tk/menubar.rb # # Original version: # Copyright (C) 1998 maeda shugo. All rights reserved. # This file can be distributed under the terms of the Ruby. # Usage: # # menu_spec = [ # [['File', 0], # ['Open', proc{puts('Open clicked')}, 0], # '---', # ['Quit', proc{exit}, 0]], # [['Edit', 0], # ['Cut', proc{puts('Cut clicked')}, 2], # ['Copy', proc{puts('Copy clicked')}, 0], # ['Paste', proc{puts('Paste clicked')}, 0]] # ] # menubar = TkMenubar.new(nil, menu_spec, # 'tearoff'=>false, # 'foreground'=>'grey40', # 'activeforeground'=>'red', # 'font'=>'-adobe-helvetica-bold-r-*--12-*-iso8859-1') # menubar.pack('side'=>'top', 'fill'=>'x') # # # OR # # # menubar = TkMenubar.new # menubar.add_menu([['File', 0], # ['Open', proc{puts('Open clicked')}, 0], # '---', # ['Quit', proc{exit}, 0]]) # menubar.add_menu([['Edit', 0], # ['Cut', proc{puts('Cut clicked')}, 2], # ['Copy', proc{puts('Copy clicked')}, 0], # ['Paste', proc{puts('Paste clicked')}, 0]]) # menubar.configure('tearoff', false) # menubar.configure('foreground', 'grey40') # menubar.configure('activeforeground', 'red') # menubar.configure('font', '-adobe-helvetica-bold-r-*--12-*-iso8859-1') # menubar.pack('side'=>'top', 'fill'=>'x') # # # OR # # radio_var = TkVariable.new('y') # menu_spec = [ # [['File', 0], # {:label=>'Open', :command=>proc{puts('Open clicked')}, :underline=>0}, # '---', # ['Check_A', TkVariable.new(true), 6], # {:type=>'checkbutton', :label=>'Check_B', # :variable=>TkVariable.new, :underline=>6}, # '---', # ['Radio_X', [radio_var, 'x'], 6], # ['Radio_Y', [radio_var, 'y'], 6], # ['Radio_Z', [radio_var, 'z'], 6], # '---', # ['cascade', [ # ['sss', proc{p 'sss'}, 0], # ['ttt', proc{p 'ttt'}, 0], # ['uuu', proc{p 'uuu'}, 0], # ['vvv', proc{p 'vvv'}, 0], # ], 0], # '---', # ['Quit', proc{exit}, 0]], # [['Edit', 0], # ['Cut', proc{puts('Cut clicked')}, 2], # ['Copy', proc{puts('Copy clicked')}, 0], # ['Paste', proc{puts('Paste clicked')}, 0]] # ] # menubar = TkMenubar.new(nil, menu_spec, # 'tearoff'=>false, # 'foreground'=>'grey40', # 'activeforeground'=>'red', # 'font'=>'Helvetia 12 bold') # menubar.pack('side'=>'top', 'fill'=>'x') # See tk/menuspce.rb about the format of the menu_spec # To use add_menu, configuration must be done by calling configure after # adding all menus by add_menu, not by the constructor arguments. require 'tk' require 'tk/frame' require 'tk/composite' require 'tk/menuspec' class TkMenubar'cascade'). When type is 'cascade', an array of menu_info # is acceptable for 'menu' key (then, create sub-menu). # # NOTE: (*1) # If you want to make special menus (*.help for UNIX, *.system for Win, # and *.apple for Mac), append 'menu_name'=>name (name is 'help' for UNIX, # 'system' for Win, and 'apple' for Mac) option to the configs hash of # menu button/entry information. # # NOTE: (*2) # If you want to configure a cascade menu, add :menu_config=>{...configs..} # to the configs of the cascade entry. module TkMenuSpec def _create_menu(parent, menu_info, menu_name = nil, tearoff = false, default_opts = nil) if tearoff.kind_of?(Hash) default_opts = tearoff tearoff = false end if menu_name.kind_of?(Hash) default_opts = menu_name menu_name = nil tearoff = false end if default_opts.kind_of?(Hash) orig_opts = _symbolkey2str(default_opts) else orig_opts = {} end tearoff = orig_opts.delete('tearoff') if orig_opts.key?('tearoff') if menu_name #menu = Tk::Menu.new(parent, :widgetname=>menu_name, :tearoff=>tearoff) # --> use current TkMenu class menu = TkMenu.new(parent, :widgetname=>menu_name, :tearoff=>tearoff) else #menu = Tk::Menu.new(parent, :tearoff=>tearoff) # --> use current TkMenu class menu = TkMenu.new(parent, :tearoff=>tearoff) end for item_info in menu_info if item_info.kind_of?(Hash) options = orig_opts.dup options.update(_symbolkey2str(item_info)) item_type = (options.delete('type') || 'command').to_s menu_name = options.delete('menu_name') menu_opts = orig_opts.dup menu_opts.update(_symbolkey2str(options.delete('menu_config') || {})) if item_type == 'cascade' && options['menu'].kind_of?(Array) # create cascade menu submenu = _create_menu(menu, options['menu'], menu_name, tearoff, menu_opts) options['menu'] = submenu end menu.add(item_type, options) elsif item_info.kind_of?(Array) options = orig_opts.dup options['label'] = item_info[0] if item_info[0] case item_info[1] when TkVariable # checkbutton item_type = 'checkbutton' options['variable'] = item_info[1] options['onvalue'] = true options['offvalue'] = false when Array # radiobutton or cascade if item_info[1][0].kind_of?(TkVariable) # radiobutton item_type = 'radiobutton' options['variable'] = item_info[1][0] options['value'] = item_info[1][1] if item_info[1][1] else # cascade item_type = 'cascade' menu_opts = orig_opts.dup if item_info[4] && item_info[4].kind_of?(Hash) opts = _symbolkey2str(item_info[4]) menu_name = opts.delete('menu_name') menu_config = opts.delete('menu_config') || {} menu_opts.update(_symbolkey2str(menu_config)) end submenu = _create_menu(menu, item_info[1], menu_name, tearoff, menu_opts) options['menu'] = submenu end else # command item_type = 'command' options['command'] = item_info[1] if item_info[1] end options['underline'] = item_info[2] if item_info[2] options['accelerator'] = item_info[3] if item_info[3] if item_info[4] && item_info[4].kind_of?(Hash) opts = _symbolkey2str(item_info[4]) if item_type == 'cascade' opts.delete('menu_name') opts.delete('menu_config') end options.update(opts) end menu.add(item_type, options) elsif /^-+$/ =~ item_info menu.add('separator') else menu.add('command', 'label' => item_info) end end menu end private :_create_menu def _use_menubar?(parent) use_menubar = false if parent.kind_of?(Tk::Root) || parent.kind_of?(Tk::Toplevel) true elsif parent.current_configinfo.has_key?('menu') true else false end end private :_use_menubar? def _create_menu_for_menubar(parent) #unless (mbar = parent.menu).kind_of?(TkMenu) # --> use current TkMenu class mbar = parent.menu unless mbar.kind_of?(Tk::Menu) || mbar.kind_of?(TkMenu) #mbar = Tk::Menu.new(parent, :tearoff=>false) mbar = TkMenu.new(parent, :tearoff=>false) parent.menu(mbar) end mbar end private :_create_menu_for_menubar def _create_menubutton(parent, menu_info, tearoff=false, default_opts = nil) btn_info = menu_info[0] if tearoff.kind_of?(Hash) default_opts = tearoff tearoff = false end if default_opts.kind_of?(Hash) keys = _symbolkey2str(default_opts) else keys = {} end tearoff = keys.delete('tearoff') if keys.key?('tearoff') if _use_menubar?(parent) # menubar by menu entries mbar = _create_menu_for_menubar(parent) menu_name = nil if btn_info.kind_of?(Hash) keys.update(_symbolkey2str(btn_info)) menu_name = keys.delete('menu_name') keys['label'] = keys.delete('text') if keys.key?('text') elsif btn_info.kind_of?(Array) keys['label'] = btn_info[0] if btn_info[0] keys['underline'] = btn_info[1] if btn_info[1] if btn_info[2]&&btn_info[2].kind_of?(Hash) keys.update(_symbolkey2str(btn_info[2])) menu_name = keys.delete('menu_name') end else keys = {:label=>btn_info} end menu = _create_menu(mbar, menu_info[1..-1], menu_name, tearoff, default_opts) menu.tearoff(tearoff) keys['menu'] = menu mbar.add('cascade', keys) [mbar, menu] else # menubar by menubuttons #mbtn = Tk::Menubutton.new(parent) # --> use current TkMenubutton class mbtn = TkMenubutton.new(parent) menu_name = nil if btn_info.kind_of?(Hash) keys.update(_symbolkey2str(btn_info)) menu_name = keys.delete('menu_name') keys['text'] = keys.delete('label') if keys.key?('label') mbtn.configure(keys) elsif btn_info.kind_of?(Array) mbtn.configure('text', btn_info[0]) if btn_info[0] mbtn.configure('underline', btn_info[1]) if btn_info[1] # mbtn.configure('accelerator', btn_info[2]) if btn_info[2] if btn_info[2]&&btn_info[2].kind_of?(Hash) keys.update(_symbolkey2str(btn_info[2])) menu_name = keys.delete('menu_name') mbtn.configure(keys) end else mbtn.configure('text', btn_info) end mbtn.pack('side' => 'left') menu = _create_menu(mbtn, menu_info[1..-1], menu_name, tearoff, default_opts) mbtn.menu(menu) [mbtn, menu] end end private :_create_menubutton def _get_cascade_menus(menu) menus = [] (0..(menu.index('last'))).each{|idx| if menu.menutype(idx) == 'cascade' submenu = menu.entrycget(idx, 'menu') menus << [submenu, _get_cascade_menus(submenu)] end } menus end private :_get_cascade_menus end ================================================ FILE: ext/tk/lib/tk/message.rb ================================================ # # tk/message.rb : treat message widget # require 'tk' require 'tk/label' class Tk::Message # require 'tk' module TkManageFocus extend Tk TkCommandNames = [ 'tk_focusFollowMouse'.freeze, 'tk_focusNext'.freeze, 'tk_focusPrev'.freeze ].freeze def TkManageFocus.followsMouse tk_call_without_enc('tk_focusFollowsMouse') end def TkManageFocus.next(win) tk_tcl2ruby(tk_call('tk_focusNext', win)) end def focusNext TkManageFocus.next(self) end def TkManageFocus.prev(win) tk_tcl2ruby(tk_call('tk_focusPrev', win)) end def focusPrev TkManageFocus.prev(self) end end ================================================ FILE: ext/tk/lib/tk/msgcat.rb ================================================ # # tk/msgcat.rb : methods for Tcl message catalog # by Hidetoshi Nagai # require 'tk' #class TkMsgCatalog class TkMsgCatalog < TkObject include TkCore extend Tk #extend TkMsgCatalog TkCommandNames = [ '::msgcat::mc'.freeze, '::msgcat::mcmax'.freeze, '::msgcat::mclocale'.freeze, '::msgcat::mcpreferences'.freeze, '::msgcat::mcload'.freeze, '::msgcat::mcset'.freeze, '::msgcat::mcmset'.freeze, '::msgcat::mcunknown'.freeze ].freeze tk_call_without_enc('package', 'require', 'Tcl', '8.2') PACKAGE_NAME = 'msgcat'.freeze def self.package_name PACKAGE_NAME end if self.const_defined? :FORCE_VERSION tk_call_without_enc('package', 'require', 'msgcat', FORCE_VERSION) else tk_call_without_enc('package', 'require', 'msgcat') end MSGCAT_EXT = '.msg' UNKNOWN_CBTBL = Hash.new{|hash,key| hash[key] = {}}.taint TkCore::INTERP.add_tk_procs('::msgcat::mcunknown', 'args', <<-'EOL') if {[set st [catch {eval {ruby_cmd TkMsgCatalog callback} [namespace current] $args} ret]] != 0} { #return -code $st $ret set idx [string first "\n\n" $ret] if {$idx > 0} { return -code $st \ -errorinfo [string range $ret [expr $idx + 2] \ [string length $ret]] \ [string range $ret 0 [expr $idx - 1]] } else { return -code $st $ret } } else { return $ret } EOL def self.callback(namespace, locale, src_str, *args) src_str = sprintf(src_str, *args) unless args.empty? cmd_tbl = TkMsgCatalog::UNKNOWN_CBTBL[TkCore::INTERP.__getip] cmd = cmd_tbl[namespace] cmd = cmd_tbl['::'] unless cmd # use global scope as interp default return src_str unless cmd # no cmd -> return src-str (default action) begin cmd.call(locale, src_str) rescue SystemExit exit(0) rescue Interrupt exit!(1) rescue Exception => e begin msg = _toUTF8(e.class.inspect) + ': ' + _toUTF8(e.message) + "\n" + "\n---< backtrace of Ruby side >-----\n" + _toUTF8(e.backtrace.join("\n")) + "\n---< backtrace of Tk side >-------" if TkCore::WITH_ENCODING msg.force_encoding('utf-8') else msg.instance_variable_set(:@encoding, 'utf-8') end rescue Exception msg = e.class.inspect + ': ' + e.message + "\n" + "\n---< backtrace of Ruby side >-----\n" + e.backtrace.join("\n") + "\n---< backtrace of Tk side >-------" end fail(e, msg) end end def initialize(namespace = nil) if namespace.kind_of?(TkNamespace) @namespace = namespace elsif namespace == nil @namespace = TkNamespace.new('::') # global namespace else @namespace = TkNamespace.new(namespace) end @path = @namespace.path @msgcat_ext = '.msg' end attr_accessor :msgcat_ext def method_missing(id, *args) # locale(src, trans) ==> set_translation(locale, src, trans) loc = id.id2name case args.length when 0 # set locale self.locale=(loc) when 1 # src only, or trans_list if args[0].kind_of?(Array) # trans_list #list = args[0].collect{|src, trans| # [ Tk::UTF8_String.new(src), Tk::UTF8_String.new(trans) ] #} self.set_translation_list(loc, args[0]) else # src #self.set_translation(loc, Tk::UTF8_String.new(args[0])) self.set_translation(loc, args[0]) end when 2 # src and trans, or, trans_list and enc if args[0].kind_of?(Array) else #self.set_translation(loc, args[0], Tk::UTF8_String.new(args[1])) self.set_translation(loc, *args) end when 3 # src and trans and enc self.set_translation(loc, *args) else super(id, *args) # fail NameError, "undefined method `#{name}' for #{self.to_s}", error_at end end # *args ::= form, arg, arg, ... def self.translate(*args) dst = args.collect{|src| tk_call_without_enc('::msgcat::mc', _get_eval_string(src, true)) } Tk.UTF8_String(sprintf(*dst)) end class << self alias mc translate alias [] translate end def translate(*args) dst = args.collect{|src| @namespace.eval{tk_call_without_enc('::msgcat::mc', _get_eval_string(src, true))} } Tk.UTF8_String(sprintf(*dst)) end alias mc translate alias [] translate def self.maxlen(*src_strings) tk_call('::msgcat::mcmax', *src_strings).to_i end def maxlen(*src_strings) @namespace.eval{tk_call('::msgcat::mcmax', *src_strings).to_i} end def self.locale tk_call('::msgcat::mclocale') end def locale @namespace.eval{tk_call('::msgcat::mclocale')} end def self.locale=(locale) tk_call('::msgcat::mclocale', locale) end def locale=(locale) @namespace.eval{tk_call('::msgcat::mclocale', locale)} end def self.preferences tk_split_simplelist(tk_call('::msgcat::mcpreferences')) end def preferences tk_split_simplelist(@namespace.eval{tk_call('::msgcat::mcpreferences')}) end def self.load_tk(dir) number(tk_call('::msgcat::mcload', dir)) end def self.load_rb(dir) count = 0 preferences().each{|loc| file = File.join(dir, loc + self::MSGCAT_EXT) if File.readable?(file) count += 1 eval(open(file){|f| f.read}) end } count end def load_tk(dir) number(@namespace.eval{tk_call('::msgcat::mcload', dir)}) end def load_rb(dir) count = 0 preferences().each{|loc| file = File.join(dir, loc + @msgcat_ext) if File.readable?(file) count += 1 @namespace.eval(open(file){|f| f.read}) end } count end def self.load(dir) self.load_rb(dir) end alias load load_rb def self.set_translation(locale, src_str, trans_str=None, enc='utf-8') if trans_str && trans_str != None trans_str = Tk.UTF8_String(_toUTF8(trans_str, enc)) Tk.UTF8_String(tk_call_without_enc('::msgcat::mcset', locale, _get_eval_string(src_str, true), trans_str)) else Tk.UTF8_String(tk_call_without_enc('::msgcat::mcset', locale, _get_eval_string(src_str, true))) end end def set_translation(locale, src_str, trans_str=None, enc='utf-8') if trans_str && trans_str != None trans_str = Tk.UTF8_String(_toUTF8(trans_str, enc)) Tk.UTF8_String(@namespace.eval{ tk_call_without_enc('::msgcat::mcset', locale, _get_eval_string(src_str, true), trans_str) }) else Tk.UTF8_String(@namespace.eval{ tk_call_without_enc('::msgcat::mcset', locale, _get_eval_string(src_str, true))}) end end def self.set_translation_list(locale, trans_list, enc='utf-8') # trans_list ::= [ [src, trans], [src, trans], ... ] list = [] trans_list.each{|src, trans| if trans && trans != None list << _get_eval_string(src, true) list << Tk.UTF8_Stirng(_toUTF8(trans, enc)) else list << _get_eval_string(src, true) << '' end } number(tk_call_without_enc('::msgcat::mcmset', locale, list)) end def set_translation_list(locale, trans_list, enc='utf-8') # trans_list ::= [ [src, trans], [src, trans], ... ] list = [] trans_list.each{|src, trans| if trans && trans != None list << _get_eval_string(src, true) list << Tk.UTF8_String(_toUTF8(trans, enc)) else list << _get_eval_string(src, true) << '' end } number(@namespace.eval{ tk_call_without_enc('::msgcat::mcmset', locale, list) }) end def self.def_unknown_proc(cmd=Proc.new) TkMsgCatalog::UNKNOWN_CBTBL[TkCore::INTERP.__getip]['::'] = cmd end def def_unknown_proc(cmd=Proc.new) TkMsgCatalog::UNKNOWN_CBTBL[TkCore::INTERP.__getip][@namespace.path] = cmd end end TkMsgCat = TkMsgCatalog ================================================ FILE: ext/tk/lib/tk/namespace.rb ================================================ # # tk/namespace.rb : methods to manipulate Tcl/Tk namespace # by Hidetoshi Nagai # require 'tk' class TkNamespace < TkObject extend Tk TkCommandNames = [ 'namespace'.freeze, ].freeze Tk_Namespace_ID_TBL = TkCore::INTERP.create_table (Tk_Namespace_ID = ["ns".freeze, "00000".taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } Tk_NsCode_RetObjID_TBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ Tk_Namespace_ID_TBL.mutex.synchronize{ Tk_Namespace_ID_TBL.clear } Tk_NsCode_RetObjID_TBL.mutex.synchronize{ Tk_NsCode_RetObjID_TBL.clear } } def TkNamespace.id2obj(id) Tk_Namespace_ID_TBL.mutex.synchronize{ Tk_Namespace_ID_TBL[id]? Tk_Namespace_ID_TBL[id]: id } end ##################################### class Ensemble < TkObject def __cget_cmd ['namespace', 'ensemble', 'configure', self.path] end private :__cget_cmd def __config_cmd ['namespace', 'ensemble', 'configure', self.path] end private :__config_cmd def __configinfo_struct {:key=>0, :alias=>nil, :db_name=>nil, :db_class=>nil, :default_value=>nil, :current_value=>2} end private :__configinfo_struct def __boolval_optkeys ['prefixes'] end private :__boolval_optkeys def __listval_optkeys ['map', 'subcommands', 'unknown'] end private :__listval_optkeys def self.exist?(ensemble) bool(tk_call('namespace', 'ensemble', 'exists', ensemble)) end def initialize(keys = {}) @ensemble = @path = tk_call('namespace', 'ensemble', 'create', keys) end def cget(slot) if slot == :namespace || slot == 'namespace' ns = super(slot) Tk_Namespace_ID_TBL.mutex.synchronize{ if TkNamespace::Tk_Namespace_ID_TBL.key?(ns) TkNamespace::Tk_Namespace_ID_TBL[ns] else ns end } else super(slot) end end def cget_strict(slot) if slot == :namespace || slot == 'namespace' ns = super(slot) Tk_Namespace_ID_TBL.mutex.synchronize{ if TkNamespace::Tk_Namespace_ID_TBL.key?(ns) TkNamespace::Tk_Namespace_ID_TBL[ns] else ns end } else super(slot) end end def configinfo(slot = nil) if slot if slot == :namespace || slot == 'namespace' val = super(slot) Tk_Namespace_ID_TBL.mutex.synchronize{ if TkNamespace::Tk_Namespace_ID_TBL.key?(val) val = TkNamespace::Tk_Namespace_ID_TBL[val] end } else val = super(slot) end if TkComm::GET_CONFIGINFO_AS_ARRAY [slot.to_s, val] else # ! TkComm::GET_CONFIGINFO_AS_ARRAY {slot.to_s => val} end else info = super() if TkComm::GET_CONFIGINFO_AS_ARRAY Tk_Namespace_ID_TBL.mutex.synchronize{ info.map!{|inf| if inf[0] == 'namespace' && TkNamespace::Tk_Namespace_ID_TBL.key?(inf[-1]) [inf[0], TkNamespace::Tk_Namespace_ID_TBL[inf[-1]]] else inf end } } else # ! TkComm::GET_CONFIGINFO_AS_ARRAY val = info['namespace'] Tk_Namespace_ID_TBL.mutex.synchronize{ if TkNamespace::Tk_Namespace_ID_TBL.key?(val) info['namespace'] = TkNamespace::Tk_Namespace_ID_TBL[val] end } end info end end def exists? bool(tk_call('namespace', 'ensemble', 'exists', @path)) end end ##################################### class ScopeArgs < Array include Tk # alias __tk_call tk_call # alias __tk_call_without_enc tk_call_without_enc # alias __tk_call_with_enc tk_call_with_enc def tk_call(*args) #super('namespace', 'eval', @namespace, *args) args = args.collect{|arg| (s = _get_eval_string(arg, true))? s: ''} super('namespace', 'eval', @namespace, TkCore::INTERP._merge_tklist(*args)) end def tk_call_without_enc(*args) #super('namespace', 'eval', @namespace, *args) args = args.collect{|arg| (s = _get_eval_string(arg, true))? s: ''} super('namespace', 'eval', @namespace, TkCore::INTERP._merge_tklist(*args)) end def tk_call_with_enc(*args) #super('namespace', 'eval', @namespace, *args) args = args.collect{|arg| (s = _get_eval_string(arg, true))? s: ''} super('namespace', 'eval', @namespace, TkCore::INTERP._merge_tklist(*args)) end def initialize(namespace, *args) @namespace = namespace super(args.size) self.replace(args) end end ##################################### class NsCode < TkObject def initialize(scope, use_obj_id = false) @scope = scope + ' ' @use_obj_id = use_obj_id end def path @scope end def to_eval @scope end def call(*args) ret = TkCore::INTERP._eval_without_enc(@scope + array2tk_list(args)) if @use_obj_id ret = TkNamespace::Tk_NsCode_RetObjID_TBL.delete(ret.to_i) end ret end end ##################################### def install_cmd(cmd) lst = tk_split_simplelist(super(cmd), false, false) if lst[1] =~ /^::/ lst[1] = @fullname else lst.insert(1, @fullname) end TkCore::INTERP._merge_tklist(*lst) end alias __tk_call tk_call alias __tk_call_without_enc tk_call_without_enc alias __tk_call_with_enc tk_call_with_enc def tk_call(*args) #super('namespace', 'eval', @fullname, *args) args = args.collect{|arg| (s = _get_eval_string(arg, true))? s: ''} super('namespace', 'eval', @fullname, TkCore::INTERP._merge_tklist(*args)) end def tk_call_without_enc(*args) #super('namespace', 'eval', @fullname, *args) args = args.collect{|arg| (s = _get_eval_string(arg, true))? s: ''} super('namespace', 'eval', @fullname, TkCore::INTERP._merge_tklist(*args)) end def tk_call_with_enc(*args) #super('namespace', 'eval', @fullname, *args) args = args.collect{|arg| (s = _get_eval_string(arg, true))? s: ''} super('namespace', 'eval', @fullname, TkCore::INTERP._merge_tklist(*args)) end alias ns_tk_call tk_call alias ns_tk_call_without_enc tk_call_without_enc alias ns_tk_call_with_enc tk_call_with_enc def initialize(name = nil, parent = nil) unless name Tk_Namespace_ID.mutex.synchronize{ # name = Tk_Namespace_ID.join('') name = Tk_Namespace_ID.join(TkCore::INTERP._ip_id_) Tk_Namespace_ID[1].succ! } end name = __tk_call('namespace', 'current') if name == '' if parent if parent =~ /^::/ if name =~ /^::/ @fullname = parent + name else @fullname = parent +'::'+ name end else ancestor = __tk_call('namespace', 'current') ancestor = '' if ancestor == '::' if name =~ /^::/ @fullname = ancestor + '::' + parent + name else @fullname = ancestor + '::'+ parent +'::'+ name end end else # parent == nil ancestor = __tk_call('namespace', 'current') ancestor = '' if ancestor == '::' if name =~ /^::/ @fullname = name else @fullname = ancestor + '::' + name end end @path = @fullname @parent = __tk_call('namespace', 'qualifiers', @fullname) @name = __tk_call('namespace', 'tail', @fullname) # create namespace __tk_call('namespace', 'eval', @fullname, '') Tk_Namespace_ID_TBL.mutex.synchronize{ Tk_Namespace_ID_TBL[@fullname] = self } end def self.children(*args) # args ::= [] [] # must be glob-style pattern tk_split_simplelist(tk_call('namespace', 'children', *args)).collect{|ns| # ns is fullname Tk_Namespace_ID_TBL.mutex.synchronize{ if Tk_Namespace_ID_TBL.key?(ns) Tk_Namespace_ID_TBL[ns] else ns end } } end def children(pattern=None) TkNamespace.children(@fullname, pattern) end def self.code(script = Proc.new) TkNamespace.new('').code(script) end =begin def code(script = Proc.new) if script.kind_of?(String) cmd = proc{|*args| ScopeArgs.new(@fullname,*args).instance_eval(script)} elsif script.kind_of?(Proc) cmd = proc{|*args| ScopeArgs.new(@fullname,*args).instance_eval(&script)} else fail ArgumentError, "String or Proc is expected" end TkNamespace::NsCode.new(tk_call_without_enc('namespace', 'code', _get_eval_string(cmd, false))) end =end def code(script = Proc.new) if script.kind_of?(String) cmd = proc{|*args| if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! obj = ScopeArgs.new(@fullname,*args) ret = obj.instance_exec(obj, script) else ret = ScopeArgs.new(@fullname,*args).instance_eval(script) end id = ret.object_id TkNamespace::Tk_NsCode_RetObjID_TBL[id] = ret id } elsif script.kind_of?(Proc) cmd = proc{|*args| if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! obj = ScopeArgs.new(@fullname,*args) ret = obj.instance_exec(obj, &script) else ret = ScopeArgs.new(@fullname,*args).instance_eval(&script) end id = ret.object_id TkNamespace::Tk_NsCode_RetObjID_TBL[id] = ret id } else fail ArgumentError, "String or Proc is expected" end TkNamespace::NsCode.new(tk_call_without_enc('namespace', 'code', _get_eval_string(cmd, false)), true) end def self.current_path tk_call('namespace', 'current') end def current_path @fullname end def self.current ns = self.current_path Tk_Namespace_ID_TBL.mutex.synchronize{ if Tk_Namespace_ID_TBL.key?(ns) Tk_Namespace_ID_TBL[ns] else ns end } end def current_namespace # ns_tk_call('namespace', 'current') # @fullname self end alias current current_namespace def self.delete(*ns_list) tk_call('namespace', 'delete', *ns_list) ns_list.each{|ns| Tk_Namespace_ID_TBL.mutex.synchronize{ if ns.kind_of?(TkNamespace) Tk_Namespace_ID_TBL.delete(ns.path) else Tk_Namespace_ID_TBL.delete(ns.to_s) end } } end def delete TkNamespece.delete(@fullname) end def self.ensemble_create(*keys) tk_call('namespace', 'ensemble', 'create', *hash_kv(keys)) end def self.ensemble_configure(cmd, slot, value=None) if slot.kind_of?(Hash) tk_call('namespace', 'ensemble', 'configure', cmd, *hash_kv(slot)) else tk_call('namespace', 'ensemble', 'configure', cmd, '-'+slot.to_s, value) end end def self.ensemble_configinfo(cmd, slot = nil) if slot tk_call('namespace', 'ensemble', 'configure', cmd, '-' + slot.to_s) else inf = {} Hash(*tk_split_simplelist(tk_call('namespace', 'ensemble', 'configure', cmd))).each{|k, v| inf[k[1..-1]] = v} inf end end def self.ensemble_exist?(cmd) bool(tk_call('namespace', 'ensemble', 'exists', cmd)) end def self.eval(namespace, cmd = Proc.new, *args) #tk_call('namespace', 'eval', namespace, cmd, *args) TkNamespace.new(namespace).eval(cmd, *args) end =begin def eval(cmd = Proc.new, *args) #TkNamespace.eval(@fullname, cmd, *args) #ns_tk_call(cmd, *args) code_obj = code(cmd) ret = code_obj.call(*args) # uninstall_cmd(TkCore::INTERP._split_tklist(code_obj.path)[-1]) uninstall_cmd(_fromUTF8(TkCore::INTERP._split_tklist(_toUTF8(code_obj.path))[-1])) tk_tcl2ruby(ret) end =end def eval(cmd = Proc.new, *args) code_obj = code(cmd) ret = code_obj.call(*args) uninstall_cmd(_fromUTF8(TkCore::INTERP._split_tklist(_toUTF8(code_obj.path))[-1])) ret end def self.exist?(ns) bool(tk_call('namespace', 'exists', ns)) end def exist? TkNamespece.exist?(@fullname) end def self.export(*patterns) tk_call('namespace', 'export', *patterns) end def self.export_with_clear(*patterns) tk_call('namespace', 'export', '-clear', *patterns) end def export TkNamespace.export(@fullname) end def export_with_clear TkNamespace.export_with_clear(@fullname) end def self.forget(*patterns) tk_call('namespace', 'forget', *patterns) end def forget TkNamespace.forget(@fullname) end def self.import(*patterns) tk_call('namespace', 'import', *patterns) end def self.force_import(*patterns) tk_call('namespace', 'import', '-force', *patterns) end def import TkNamespace.import(@fullname) end def force_import TkNamespace.force_import(@fullname) end def self.inscope(namespace, script, *args) tk_call('namespace', 'inscope', namespace, script, *args) end def inscope(script, *args) TkNamespace.inscope(@fullname, script, *args) end def self.origin(cmd) tk_call('namespace', 'origin', cmd) end def self.parent(namespace=None) ns = tk_call('namespace', 'parent', namespace) Tk_Namespace_ID_TBL.mutex.synchronize{ if Tk_Namespace_ID_TBL.key?(ns) Tk_Namespace_ID_TBL[ns] else ns end } end def parent tk_call('namespace', 'parent', @fullname) end def self.get_path tk_call('namespace', 'path') end def self.set_path(*namespace_list) tk_call('namespace', 'path', array2tk_list(namespace_list)) end def set_path tk_call('namespace', 'path', @fullname) end def self.qualifiers(str) tk_call('namespace', 'qualifiers', str) end def self.tail(str) tk_call('namespace', 'tail', str) end def self.upvar(namespace, *var_pairs) tk_call('namespace', 'upvar', namespace, *(var_pairs.flatten)) end def upvar(*var_pairs) TkNamespace.inscope(@fullname, *(var_pairs.flatten)) end def self.get_unknown_handler tk_tcl2ruby(tk_call('namespace', 'unknown')) end def self.set_unknown_handler(cmd = Proc.new) tk_call('namespace', 'unknown', cmd) end def self.which(name) tk_call('namespace', 'which', name) end def self.which_command(name) tk_call('namespace', 'which', '-command', name) end def self.which_variable(name) tk_call('namespace', 'which', '-variable', name) end end TkNamespace::Global = TkNamespace.new('::') ================================================ FILE: ext/tk/lib/tk/optiondb.rb ================================================ # # tk/optiondb.rb : treat option database # require 'tk' module TkOptionDB include Tk extend Tk TkCommandNames = ['option'.freeze].freeze (CmdClassID = ['CMD_CLASS'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } module Priority WidgetDefault = 20 StartupFile = 40 UserDefault = 60 Interactive = 80 end def add(pat, value, pri=None) # if $SAFE >= 4 # fail SecurityError, "can't call 'TkOptionDB.add' at $SAFE >= 4" # end tk_call('option', 'add', pat, value, pri) end def clear # if $SAFE >= 4 # fail SecurityError, "can't call 'TkOptionDB.crear' at $SAFE >= 4" # end tk_call_without_enc('option', 'clear') end def get(win, name, klass) tk_call('option', 'get', win ,name, klass) end def readfile(file, pri=None) tk_call('option', 'readfile', file, pri) end alias read_file readfile module_function :add, :clear, :get, :readfile, :read_file def read_entries(file, f_enc=nil) if TkCore::INTERP.safe? fail SecurityError, "can't call 'TkOptionDB.read_entries' on a safe interpreter" end i_enc = ((Tk.encoding)? Tk.encoding : Tk.encoding_system) unless f_enc f_enc = i_enc end ent = [] cline = '' open(file, 'r') {|f| while line = f.gets #cline += line.chomp! cline.concat(line.chomp!) case cline when /\\$/ # continue cline.chop! next when /^\s*(!|#)/ # coment cline = '' next when /^([^:]+):(.*)$/ pat = $1.strip val = $2.lstrip p "ResourceDB: #{[pat, val].inspect}" if $DEBUG pat = TkCore::INTERP._toUTF8(pat, f_enc) pat = TkCore::INTERP._fromUTF8(pat, i_enc) val = TkCore::INTERP._toUTF8(val, f_enc) val = TkCore::INTERP._fromUTF8(val, i_enc) ent << [pat, val] cline = '' else # unknown --> ignore cline = '' next end end } ent end module_function :read_entries def read_with_encoding(file, f_enc=nil, pri=None) # try to read the file as an OptionDB file read_entries(file, f_enc).each{|pat, val| add(pat, val, pri) } =begin i_enc = Tk.encoding() unless f_enc f_enc = i_enc end cline = '' open(file, 'r') {|f| while line = f.gets cline += line.chomp! case cline when /\\$/ # continue cline.chop! next when /^\s*!/ # coment cline = '' next when /^([^:]+):\s(.*)$/ pat = $1 val = $2 p "ResourceDB: #{[pat, val].inspect}" if $DEBUG pat = TkCore::INTERP._toUTF8(pat, f_enc) pat = TkCore::INTERP._fromUTF8(pat, i_enc) val = TkCore::INTERP._toUTF8(val, f_enc) val = TkCore::INTERP._fromUTF8(val, i_enc) add(pat, val, pri) cline = '' else # unknown --> ignore cline = '' next end end } =end end module_function :read_with_encoding # support procs on the resource database @@resource_proc_class = Class.new @@resource_proc_class.const_set(:CARRIER, '.'.freeze) @@resource_proc_class.instance_variable_set('@method_tbl', TkCore::INTERP.create_table) @@resource_proc_class.instance_variable_set('@add_method', false) @@resource_proc_class.instance_variable_set('@safe_mode', 4) class << @@resource_proc_class private :new =begin CARRIER = '.'.freeze METHOD_TBL = TkCore::INTERP.create_table ADD_METHOD = false SAFE_MODE = 4 =end =begin def __closed_block_check__(str) depth = 0 str.scan(/[{}]/){|x| if x == "{" depth += 1 elsif x == "}" depth -= 1 end if depth <= 0 && !($' =~ /\A\s*\Z/) fail RuntimeError, "bad string for procedure : #{str.inspect}" end } str end private :__closed_block_check__ =end def __check_proc_string__(str) # If you want to check the proc_string, do it in this method. # Please define this in the block given to 'new_proc_class' method. str end def method_missing(id, *args) #res_proc, proc_str = self::METHOD_TBL[id] res_proc, proc_str = @method_tbl[id] proc_source = TkOptionDB.get(self::CARRIER, id.id2name, '').strip res_proc = nil if proc_str != proc_source # resource is changed # unless res_proc.kind_of?(Proc) unless TkComm._callback_entry?(res_proc) #if id == :new || !(self::METHOD_TBL.has_key?(id) || self::ADD_METHOD) if id == :new || !(@method_tbl.has_key?(id) || @add_method) raise NoMethodError, "not support resource-proc '#{id.id2name}' for #{self.name}" end proc_str = proc_source proc_str = '{' + proc_str + '}' unless /\A\{.*\}\Z/ =~ proc_str #proc_str = __closed_block_check__(proc_str) proc_str = __check_proc_string__(proc_str) res_proc = proc{ begin #eval("$SAFE = #{self::SAFE_MODE};\nProc.new" + proc_str) eval("$SAFE = #{@safe_mode};\nProc.new" + proc_str) rescue SyntaxError=>err raise SyntaxError, TkCore::INTERP._toUTF8(err.message.gsub(/\(eval\):\d:/, "(#{id.id2name}):")) end }.call #self::METHOD_TBL[id] = [res_proc, proc_source] @method_tbl[id] = [res_proc, proc_source] end res_proc.call(*args) end private :__check_proc_string__, :method_missing end @@resource_proc_class.freeze =begin def __create_new_class(klass, func, safe = 4, add = false, parent = nil) klass = klass.to_s if klass.kind_of? Symbol unless (?A..?Z) === klass[0] fail ArgumentError, "bad string '#{klass}' for class name" end unless func.kind_of? Array fail ArgumentError, "method-list must be Array" end func_str = func.join(' ') if parent == nil install_win(parent) elsif parent <= @@resource_proc_class install_win(parent::CARRIER) else fail ArgumentError, "parent must be Resource-Proc class" end carrier = Tk.tk_call_without_enc('frame', @path, '-class', klass) body = <<-"EOD" class #{klass} < TkOptionDB.module_eval('@@resource_proc_class') CARRIER = '#{carrier}'.freeze METHOD_TBL = TkCore::INTERP.create_table ADD_METHOD = #{add} SAFE_MODE = #{safe} %w(#{func_str}).each{|f| METHOD_TBL[f.intern] = nil } end EOD if parent.kind_of?(Class) && parent <= @@resource_proc_class parent.class_eval(body) eval(parent.name + '::' + klass) else eval(body) eval('TkOptionDB::' + klass) end end =end def __create_new_class(klass, func, safe = 4, add = false, parent = nil) if klass.kind_of?(TkWindow) carrier = klass.path CmdClassID.mutex.synchronize{ klass = CmdClassID.join(TkCore::INTERP._ip_id_) CmdClassID[1].succ! } parent = nil # ignore parent else klass = klass.to_s if klass.kind_of?(Symbol) unless (?A..?Z) === klass[0] fail ArgumentError, "bad string '#{klass}' for class name" end if parent == nil install_win(nil) elsif parent.kind_of?(TkWindow) install_win(parent.path) elsif parent <= @@resource_proc_class install_win(parent::CARRIER) else fail ArgumentError, "parent must be Resource-Proc class" end carrier = Tk.tk_call_without_enc('frame', @path, '-class', klass) end unless func.kind_of?(Array) fail ArgumentError, "method-list must be Array" end func_str = func.join(' ') if parent.kind_of?(Class) && parent <= @@resource_proc_class cmd_klass = Class.new(parent) else cmd_klass = Class.new(TkOptionDB.module_eval('@@resource_proc_class')) end cmd_klass.const_set(:CARRIER, carrier.dup.freeze) cmd_klass.instance_variable_set('@method_tbl', TkCore::INTERP.create_table) cmd_klass.instance_variable_set('@add_method', add) cmd_klass.instance_variable_set('@safe_mode', safe) func.each{|f| cmd_klass.instance_variable_get('@method_tbl')[f.to_s.intern] = nil } =begin cmd_klass.const_set(:METHOD_TBL, TkCore::INTERP.create_table) cmd_klass.const_set(:ADD_METHOD, add) cmd_klass.const_set(:SAFE_MODE, safe) func.each{|f| cmd_klass::METHOD_TBL[f.to_s.intern] = nil } =end cmd_klass end module_function :__create_new_class private_class_method :__create_new_class def __remove_methods_of_proc_class(klass) # for security, make these methods invalid class << klass def __null_method(*args); nil; end [ :class_eval, :name, :superclass, :clone, :dup, :autoload, :autoload?, :ancestors, :const_defined?, :const_get, :const_set, :const_missing, :class_variables, :constants, :included_modules, :instance_methods, :method_defined?, :module_eval, :private_instance_methods, :protected_instance_methods, :public_instance_methods, :singleton_methods, :remove_const, :remove_method, :undef_method, :to_s, :inspect, :display, :method, :methods, :respond_to?, :instance_variable_get, :instance_variable_set, :instance_method, :instance_eval, :instance_exec, :instance_variables, :kind_of?, :is_a?, :private_methods, :protected_methods, :public_methods ].each{|m| alias_method(m, :__null_method) } end end module_function :__remove_methods_of_proc_class private_class_method :__remove_methods_of_proc_class RAND_BASE_CNT = [0] RAND_BASE_HEAD = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' RAND_BASE_CHAR = RAND_BASE_HEAD + 'abcdefghijklmnopqrstuvwxyz0123456789_' def __get_random_basename name = '%s%03d' % [RAND_BASE_HEAD[rand(RAND_BASE_HEAD.size),1], RAND_BASE_CNT[0]] len = RAND_BASE_CHAR.size (6+rand(10)).times{ name << RAND_BASE_CHAR[rand(len),1] } RAND_BASE_CNT[0] = RAND_BASE_CNT[0] + 1 name end module_function :__get_random_basename private_class_method :__get_random_basename # define new proc class : # If you want to modify the new class or create a new subclass, # you must do such operation in the block parameter. # Because the created class is flozen after evaluating the block. def new_proc_class(klass, func, safe = 4, add = false, parent = nil, &b) new_klass = __create_new_class(klass, func, safe, add, parent) new_klass.class_eval(&b) if block_given? __remove_methods_of_proc_class(new_klass) new_klass.freeze new_klass end module_function :new_proc_class def eval_under_random_base(parent = nil, &b) new_klass = __create_new_class(__get_random_basename(), [], 4, false, parent) ret = new_klass.class_eval(&b) if block_given? __remove_methods_of_proc_class(new_klass) new_klass.freeze ret end module_function :eval_under_random_base def new_proc_class_random(klass, func, safe = 4, add = false, &b) eval_under_random_base(){ TkOptionDB.new_proc_class(klass, func, safe, add, self, &b) } end module_function :new_proc_class_random end TkOption = TkOptionDB TkResourceDB = TkOptionDB ================================================ FILE: ext/tk/lib/tk/optionobj.rb ================================================ # # tk/optionobj.rb : control options for a group of widgets # # NOTE: If you want to use key-only option (no value), # use Tk::None for the value of the key-only option. # # e.g. hash_kv({'aaa'=>1, 'bbb'=>Tk::None, 'ccc'=>3}) # => ["-aaa", 1, "-bbb", "-ccc", 3] # require 'tk' module Tk class OptionObj < Hash include TkUtil def initialize(hash = nil) super() @observ = [] update_without_notify(_symbolkey2str(hash)) if hash end def observ_info @observ.dup end def observs @observ.collect{|win| if win.kind_of?(Array) win[0] else win end } end def _remove_win(win) if win.kind_of?(Array) widget, method = win @observ.delete_if{|x| if x.kind_of?(Array) x[0] == widget else x == widget end } else @observ.delete_if{|x| if x.kind_of?(Array) x[0] == win else x == win end } end end private :_remove_win def assign(*wins) # win := # widget #==> call widget.configure(hash) # [widget] #==> call widget.configure(hash) # [widget, nil, {src=>target, ... }] # #==> call widget.configure(hash) # with converting hash-key # [widget, method] #==> call widget.method(hash) # [widget, method, {src=>target, ... }] # #==> call widget.method(hash) # with converting hash-key # [widget [receiver, method, arg, ... ]] # #==> call receiver.method(arg, ... , hash) # [widget [receiver, method, arg, ... ], {src=>target, ... }] # #==> call receiver.method(arg, ... , hash) # with onverting hash-key # # src := option_name_on_optobj # # target := # nil #==> not use the src # option_name_on_target_widget # [ option_name_on_target_widget, ... ] # #==> set all of them # wins.each{|win| _remove_win(win) @observ << win notify(win) } self end def unassign(*wins) wins.each{|win| _remove_win(win) } self end def notify(target = nil) if target targets = [target] elsif @observ.empty? return self else targets = @observ.dup end return self if empty? org_hash = _symbolkey2str(self) targets.each{|win| widget = receiver = win hash = org_hash begin if win.kind_of?(Array) widget, method, conv_tbl = win receiver = widget if conv_tbl hash = {} org_hash.each{|key, val| key = conv_tbl[key] if conv_tbl.key?(key) next unless key if key.kind_of?(Array) key.each{|k| hash[k] = val} else hash[key] = val end } end if method.kind_of?(Array) receiver, method, *args = method receiver.__send__(method, *(args << hash)) elsif method widget.__send__(method, hash) else widget.configure(hash) end else widget.configure(self) end rescue => e if ( ( widget.kind_of?(TkObject) \ && widget.respond_to?('exist?') \ && ! receiver.exist? ) \ || ( receiver.kind_of?(TkObject) \ && receiver.respond_to?('exist?') \ && ! receiver.exist? ) ) @observ.delete(win) else fail e end end } self end alias apply notify def +(hash) unless hash.kind_of?(Hash) fail ArgumentError, "expect a Hash" end new_obj = self.dup new_obj.update_without_notify(_symbolkey2str(hash)) new_obj end alias update_without_notify update def update(hash) update_without_notify(_symbolkey2str(hash)) notify end def configure(key, value=nil) if key.kind_of?(Hash) update(key) else store(key,value) end end def [](key) super(key.to_s) end alias cget [] def store(key, val) key = key.to_s super(key, val) notify end def []=(key, val) store(key,val) end def replace(hash) super(_symbolkey2str(hash)) notify end def default(opt) fail RuntimeError, "unknown option `#{opt}'" end private :default undef :default= end end ================================================ FILE: ext/tk/lib/tk/pack.rb ================================================ # # tk/pack.rb : control pack geometry manager # require 'tk' module TkPack include Tk extend Tk TkCommandNames = ['pack'.freeze].freeze =begin def configure(win, *args) if args[-1].kind_of?(Hash) opts = args.pop else opts = {} end params = [] # params.push((win.kind_of?(TkObject))? win.epath: win) params.push(_epath(win)) args.each{|win| # params.push((win.kind_of?(TkObject))? win.epath: win) params.push(_epath(win)) } opts.each{|k, v| params.push("-#{k}") # params.push((v.kind_of?(TkObject))? v.epath: v) params.push(_epath(v)) } tk_call_without_enc("pack", 'configure', *params) end =end def configure(*args) if args[-1].kind_of?(Hash) opts = args.pop else opts = {} end fail ArgumentError, 'no widget is given' if args.empty? params = [] args.flatten(1).each{|win| params.push(_epath(win))} opts.each{|k, v| params.push("-#{k}") params.push(_epath(v)) # have to use 'epath' (hash_kv() is unavailable) } tk_call_without_enc("pack", 'configure', *params) end alias pack configure def forget(*args) return '' if args.size == 0 wins = args.collect{|win| # (win.kind_of?(TkObject))? win.epath: win _epath(win) } tk_call_without_enc('pack', 'forget', *wins) end def info(slave) # slave = slave.epath if slave.kind_of?(TkObject) slave = _epath(slave) ilist = list(tk_call_without_enc('pack', 'info', slave)) info = {} while key = ilist.shift info[key[1..-1]] = ilist.shift end return info end def propagate(master, mode=None) # master = master.epath if master.kind_of?(TkObject) master = _epath(master) if mode == None bool(tk_call_without_enc('pack', 'propagate', master)) else tk_call_without_enc('pack', 'propagate', master, mode) end end def slaves(master) # master = master.epath if master.kind_of?(TkObject) master = _epath(master) list(tk_call_without_enc('pack', 'slaves', master)) end module_function :pack, :configure, :forget, :info, :propagate, :slaves end =begin def TkPack(win, *args) if args[-1].kind_of?(Hash) opts = args.pop else opts = {} end params = [] params.push((win.kind_of?(TkObject))? win.epath: win) args.each{|win| params.push((win.kind_of?(TkObject))? win.epath: win) } opts.each{|k, v| params.push("-#{k}") params.push((v.kind_of?(TkObject))? v.epath: v) } tk_call_without_enc("pack", *params) end =end ================================================ FILE: ext/tk/lib/tk/package.rb ================================================ # # tk/package.rb : package command # require 'tk' module TkPackage include TkCore extend TkPackage TkCommandNames = ['package'.freeze].freeze def add_path(path) Tk::AUTO_PATH.value = Tk::AUTO_PATH.to_a << path end def forget(package) tk_call('package', 'forget', package) nil end def if_needed(pkg, ver, *arg, &b) size = arg.size if size==0 && !b # proc info procedure(tk_call('package', 'ifneeded', pkg, ver)) elsif size==0 && b # set proc cmd = proc(&b) tk_call('package', 'ifneeded', pkg, ver, cmd) cmd elsif size==1 && !b # set proc cmd = arg[0] if cmd tk_call('package', 'ifneeded', pkg, ver, cmd) cmd else # remove proc tk_call('package', 'ifneeded', pkg, ver, '') nil end else fail ArgumentError, 'too many arguments' end end def names tk_split_simplelist(tk_call('package', 'names')) end def provide(package, version=nil) if version tk_call('package', 'provide', package, version) end if (ret = tk_call('package', 'provide', package)) == '' nil else ret end end def present(package, version=None) begin tk_call('package', 'present', package, version) rescue => e fail e.class, 'TkPackage ' << e.message end end def present_exact(package, version) begin tk_call('package', 'present', '-exact', package, version) rescue => e fail e.class, 'TkPackage ' << e.message end end def require(package, version=None) begin tk_call('package', 'require', package, version) rescue => e fail e.class, 'TkPackage ' << e.message end end def require_exact(package, version) begin tk_call('package', 'require', '-exact', package, version) rescue => e fail e.class, 'TkPackage ' << e.message end end def unknown_proc(*arg, &b) size = arg.size if size==0 && !b # proc info procedure(tk_call('package', 'unknown')) elsif size==0 && b # set proc cmd = proc(&b) tk_call('package', 'unknown', cmd) cmd elsif size==1 && !b # set proc cmd = arg[0] if cmd tk_call('package', 'unknown', cmd) cmd else # remove proc tk_call('package', 'unknown', '') nil end else fail ArgumentError, 'too many arguments' end end def versions(package) tk_split_simplelist(tk_call('package', 'versions', package)) end def vcompare(version1, version2) number(tk_call('package', 'vcompare', version1, version2)) end def vsatisfies(version1, version2) bool(tk_call('package', 'vsatisfies', version1, version2)) end def prefer(setting = None) tk_call('package', 'prefer', setting) end end ================================================ FILE: ext/tk/lib/tk/palette.rb ================================================ # # tk/palette.rb : methods for Tcl/Tk standard library 'palette.tcl' # 1998/06/21 by Hidetoshi Nagai # require 'tk' module TkPalette include Tk extend Tk TkCommandNames = [ 'tk_setPalette'.freeze, 'tk_bisque'.freeze, 'tkDarken'.freeze ].freeze def TkPalette.set(*args) args = args[0].to_a.flatten if args[0].kind_of? Hash tk_call('tk_setPalette', *args) end def TkPalette.setPalette(*args) TkPalette.set(*args) end def TkPalette.bisque tk_call('tk_bisque') end def TkPalette.darken(color, percent) tk_call('tkDarken', color, percent) end def TkPalette.recolorTree(win, colors) if not colors.kind_of?(Hash) fail "2nd arg need to be Hash" end tk_call('global', "tkPalette") colors.each{|key, value| begin if win.cget(key) == tk_call('set', "tkPalette(#{key})") win[key] = colors[key] end rescue # ignore end } TkWinfo.children(win).each{|w| TkPalette.recolorTree(w, colors)} end def recolorTree(colors) TkPalette.recolorTree(self, colors) end end ================================================ FILE: ext/tk/lib/tk/panedwindow.rb ================================================ # # tk/panedwindow.rb : treat panedwindow # require 'tk' class Tk::PanedWindow e begin if current_paneconfiginfo(win).has_key?(option.to_s) # not tag error & option is known -> error on known option fail e else # not tag error & option is unknown nil end rescue fail e # tag error end end end end def paneconfigure(win, key, value=nil) # win = win.epath if win.kind_of?(TkObject) win = _epath(win) if key.kind_of? Hash params = [] key.each{|k, v| params.push("-#{k}") # params.push((v.kind_of?(TkObject))? v.epath: v) params.push(_epath(v)) } tk_send_without_enc('paneconfigure', win, *params) else # value = value.epath if value.kind_of?(TkObject) value = _epath(value) tk_send_without_enc('paneconfigure', win, "-#{key}", value) end self end alias pane_config paneconfigure def paneconfiginfo(win, key=nil) if TkComm::GET_CONFIGINFO_AS_ARRAY # win = win.epath if win.kind_of?(TkObject) win = _epath(win) if key #conf = tk_split_list(tk_send_without_enc('paneconfigure', # win, "-#{key}")) conf = tk_split_list(tk_send_without_enc('paneconfigure', win, "-#{key}"), false, true) conf[0] = conf[0][1..-1] if conf[0] == 'hide' conf[3] = bool(conf[3]) unless conf[3].empty? conf[4] = bool(conf[4]) unless conf[4].empty? end conf else #tk_split_simplelist(tk_send_without_enc('paneconfigure', # win)).collect{|conflist| # conf = tk_split_simplelist(conflist) tk_split_simplelist(tk_send_without_enc('paneconfigure', win), false, false).collect{|conflist| conf = tk_split_simplelist(conflist, false, true) conf[0] = conf[0][1..-1] if conf[3] if conf[0] == 'hide' conf[3] = bool(conf[3]) unless conf[3].empty? elsif conf[3].index('{') conf[3] = tk_split_list(conf[3]) else conf[3] = tk_tcl2ruby(conf[3]) end end if conf[4] if conf[0] == 'hide' conf[4] = bool(conf[4]) unless conf[4].empty? elsif conf[4].index('{') conf[4] = tk_split_list(conf[4]) else conf[4] = tk_tcl2ruby(conf[4]) end end conf[1] = conf[1][1..-1] if conf.size == 2 # alias info conf } end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY # win = win.epath if win.kind_of?(TkObject) win = _epath(win) if key #conf = tk_split_list(tk_send_without_enc('paneconfigure', # win, "-#{key}")) conf = tk_split_list(tk_send_without_enc('paneconfigure', win, "-#{key}"), false, true) key = conf.shift[1..-1] if key == 'hide' conf[2] = bool(conf[2]) unless conf[2].empty? conf[3] = bool(conf[3]) unless conf[3].empty? end { key => conf } else ret = {} #tk_split_simplelist(tk_send_without_enc('paneconfigure', # win)).each{|conflist| # conf = tk_split_simplelist(conflist) tk_split_simplelist(tk_send_without_enc('paneconfigure', win), false, false).each{|conflist| conf = tk_split_simplelist(conflist, false, true) key = conf.shift[1..-1] if key if key == 'hide' conf[2] = bool(conf[2]) unless conf[2].empty? elsif conf[2].index('{') conf[2] = tk_split_list(conf[2]) else conf[2] = tk_tcl2ruby(conf[2]) end end if conf[3] if key == 'hide' conf[3] = bool(conf[3]) unless conf[3].empty? elsif conf[3].index('{') conf[3] = tk_split_list(conf[3]) else conf[3] = tk_tcl2ruby(conf[3]) end end if conf.size == 1 ret[key] = conf[0][1..-1] # alias info else ret[key] = conf end } ret end end end alias pane_configinfo paneconfiginfo def current_paneconfiginfo(win, key=nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if key conf = paneconfiginfo(win, key) {conf[0] => conf[4]} else ret = {} paneconfiginfo(win).each{|conf| ret[conf[0]] = conf[4] if conf.size > 2 } ret end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY ret = {} paneconfiginfo(win, key).each{|k, conf| ret[k] = conf[-1] if conf.kind_of?(Array) } ret end end alias current_pane_configinfo current_paneconfiginfo def panes list(tk_send_without_enc('panes')) end end Tk::Panedwindow = Tk::PanedWindow #TkPanedWindow = Tk::PanedWindow unless Object.const_defined? :TkPanedWindow #TkPanedwindow = Tk::Panedwindow unless Object.const_defined? :TkPanedwindow Tk.__set_toplevel_aliases__(:Tk, Tk::PanedWindow, :TkPanedWindow, :TkPanedwindow) ================================================ FILE: ext/tk/lib/tk/place.rb ================================================ # # tk/place.rb : control place geometry manager # require 'tk' module TkPlace include Tk extend Tk TkCommandNames = ['place'.freeze].freeze def configure(win, slot, value=None) # for >= Tk8.4a2 ? # win = win.epath if win.kind_of?(TkObject) win = _epath(win) if slot.kind_of? Hash params = [] slot.each{|k, v| params.push("-#{k}") # params.push((v.kind_of?(TkObject))? v.epath: v) params.push(_epath(v)) } tk_call_without_enc('place', 'configure', win, *params) else # value = value.epath if value.kind_of?(TkObject) value = _epath(value) tk_call_without_enc('place', 'configure', win, "-#{slot}", value) end end alias place configure def configinfo(win, slot = nil) # for >= Tk8.4a2 ? if TkComm::GET_CONFIGINFOwoRES_AS_ARRAY # win = win.epath if win.kind_of?(TkObject) win = _epath(win) if slot #conf = tk_split_list(tk_call_without_enc('place', 'configure', # win, "-#{slot}") ) conf = tk_split_simplelist(tk_call_without_enc('place', 'configure', win, "-#{slot}") ) conf[0] = conf[0][1..-1] conf[1] = tk_tcl2ruby(conf[1]) conf[2] = tk_tcl2ruby(conf[1]) conf[3] = tk_tcl2ruby(conf[1]) conf[4] = tk_tcl2ruby(conf[1]) conf else tk_split_simplelist(tk_call_without_enc('place', 'configure', win)).collect{|conflist| #conf = list(conflist) conf = simplelist(conflist).collect!{|inf| tk_tcl2ruby(inf)} conf[0] = conf[0][1..-1] conf } end else # ! TkComm::GET_CONFIGINFOwoRES_AS_ARRAY current_configinfo(win, slot) end end def current_configinfo(win, slot = nil) # win = win.epath if win.kind_of?(TkObject) win = _epath(win) if slot #conf = tk_split_list(tk_call_without_enc('place', 'configure', # win, "-#{slot}") ) conf = tk_split_simplelist(tk_call_without_enc('place', 'configure', win, "-#{slot}") ) # { conf[0][1..-1] => conf[1] } { conf[0][1..-1] => tk_tcl2ruby(conf[4]) } else ret = {} #tk_split_list(tk_call_without_enc('place','configure',win)).each{|conf| tk_split_simplelist(tk_call_without_enc('place', 'configure', win)).each{|conf_list| #ret[conf[0][1..-1]] = conf[1] conf = simplelist(conf_list) ret[conf[0][1..-1]] = tk_tcl2ruby(conf[4]) } ret end end def forget(win) # win = win.epath if win.kind_of?(TkObject) win = _epath(win) tk_call_without_enc('place', 'forget', win) end def info(win) # win = win.epath if win.kind_of?(TkObject) win = _epath(win) #ilist = list(tk_call_without_enc('place', 'info', win)) ilist = simplelist(tk_call_without_enc('place', 'info', win)) info = {} while key = ilist.shift #info[key[1..-1]] = ilist.shift info[key[1..-1]] = tk_tcl2ruby(ilist.shift) end return info end def slaves(master) # master = master.epath if master.kind_of?(TkObject) master = _epath(master) list(tk_call('place', 'slaves', master)) end module_function :place, :configure, :configinfo, :current_configinfo module_function :forget, :info, :slaves end =begin def TkPlace(win, slot, value=None) win = win.epath if win.kind_of?(TkObject) if slot.kind_of? Hash params = [] slot.each{|k, v| params.push("-#{k}") params.push((v.kind_of?(TkObject))? v.epath: v) } tk_call_without_enc('place', win, *params) else value = value.epath if value.kind_of?(TkObject) tk_call_without_enc('place', win, "-#{slot}", value) end end =end ================================================ FILE: ext/tk/lib/tk/radiobutton.rb ================================================ # # tk/radiobutton.rb : treat radiobutton widget # require 'tk' require 'tk/button' class Tk::RadioButtonproc, ... } { 'variable'=>proc{|v| tk_trace_variable(v)} # for backward compatibility } end private :__ruby2val_optkeys def deselect tk_send_without_enc('deselect') self end def select tk_send_without_enc('select') self end def get_value var = tk_send_without_enc('cget', '-variable') if TkVariable::USE_TCLs_SET_VARIABLE_FUNCTIONS _fromUTF8(INTERP._get_global_var(var)) else INTERP._eval(Kernel.format('global %s; set %s', var, var)) end end def set_value(val) var = tk_send_without_enc('cget', '-variable') if TkVariable::USE_TCLs_SET_VARIABLE_FUNCTIONS _fromUTF8(INTERP._set_global_var(var, _get_eval_string(val, true))) else s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"' INTERP._eval(Kernel.format('global %s; set %s %s', var, var, s)) end end end Tk::Radiobutton = Tk::RadioButton #TkRadioButton = Tk::RadioButton unless Object.const_defined? :TkRadioButton #TkRadiobutton = Tk::Radiobutton unless Object.const_defined? :TkRadiobutton Tk.__set_toplevel_aliases__(:Tk, Tk::RadioButton, :TkRadioButton, :TkRadiobutton) ================================================ FILE: ext/tk/lib/tk/root.rb ================================================ # # tk/root.rb : treat root widget # require 'tk' require 'tk/wm' require 'tk/menuspec' class Tk::Rootmethod, ... } TOPLEVEL_METHODCALL_OPTKEYS end private :__methodcall_optkeys def Root.new(keys=nil, &b) unless TkCore::INTERP.tk_windows['.'] TkCore::INTERP.tk_windows['.'] = super(:without_creating=>true, :widgetname=>'.'){} end root = TkCore::INTERP.tk_windows['.'] keys = _symbolkey2str(keys) # wm commands root.instance_eval{ __methodcall_optkeys.each{|key, method| value = keys.delete(key.to_s) self.__send__(method, value) if value } } if keys # wm commands ( for backward comaptibility ) keys.each{|k,v| if v.kind_of? Array root.__send__(k,*v) else root.__send__(k,v) end } end if block_given? if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! root.instance_exec(root, &b) else root.instance_eval(&b) end end root end WidgetClassName = 'Tk'.freeze WidgetClassNames[WidgetClassName] = self def self.to_eval # self::WidgetClassName '.' end def create_self @path = '.' end private :create_self def path "." end def add_menu(menu_info, tearoff=false, opts=nil) # See tk/menuspec.rb for menu_info. # opts is a hash of default configs for all of cascade menus. # Configs of menu_info can override it. if tearoff.kind_of?(Hash) opts = tearoff tearoff = false end _create_menubutton(self, menu_info, tearoff, opts) end def add_menubar(menu_spec, tearoff=false, opts=nil) # See tk/menuspec.rb for menu_spec. # opts is a hash of default configs for all of cascade menus. # Configs of menu_spec can override it. menu_spec.each{|info| add_menu(info, tearoff, opts)} self.menu end def Root.destroy TkCore::INTERP._invoke('destroy', '.') end end TkRoot = Tk::Root unless Object.const_defined? :TkRoot ================================================ FILE: ext/tk/lib/tk/scale.rb ================================================ # # tk/scale.rb : treat scale widget # require 'tk' class Tk::Scalevalue) end def configure(slot, value=None) if (slot == 'command' || slot == :command) configure('command'=>value) elsif slot.kind_of?(Hash) && (slot.key?('command') || slot.key?(:command)) slot = _symbolkey2str(slot) slot['command'] = _wrap_command_arg(slot.delete('command')) end super(slot, value) end def command(cmd=Proc.new) configure('command'=>cmd) end def get(x=None, y=None) number(tk_send_without_enc('get', x, y)) end def coords(val=None) tk_split_list(tk_send_without_enc('coords', val)) end def identify(x, y) tk_send_without_enc('identify', x, y) end def set(val) tk_send_without_enc('set', val) end def value get end def value= (val) set(val) val end end #TkScale = Tk::Scale unless Object.const_defined? :TkScale Tk.__set_toplevel_aliases__(:Tk, Tk::Scale, :TkScale) ================================================ FILE: ext/tk/lib/tk/scrollable.rb ================================================ # # tk/scrollable.rb : module for scrollable widget # require 'tk' module Tk module XScrollable def xscrollcommand(cmd=Proc.new) configure_cmd 'xscrollcommand', cmd # Tk.update # avoid scrollbar trouble self end def xview(*index) if index.size == 0 list(tk_send_without_enc('xview')) else tk_send_without_enc('xview', *index) self end end def xview_moveto(*index) xview('moveto', *index) end def xview_scroll(*index) xview('scroll', *index) end def xscrollbar(bar=nil) if bar @xscrollbar = bar @xscrollbar.orient 'horizontal' self.xscrollcommand {|*arg| @xscrollbar.set(*arg)} @xscrollbar.command {|*arg| self.xview(*arg)} Tk.update # avoid scrollbar trouble end @xscrollbar end end module YScrollable def yscrollcommand(cmd=Proc.new) configure_cmd 'yscrollcommand', cmd # Tk.update # avoid scrollbar trouble self end def yview(*index) if index.size == 0 list(tk_send_without_enc('yview')) else tk_send_without_enc('yview', *index) self end end def yview_moveto(*index) yview('moveto', *index) end def yview_scroll(*index) yview('scroll', *index) end def yscrollbar(bar=nil) if bar @yscrollbar = bar @yscrollbar.orient 'vertical' self.yscrollcommand {|*arg| @yscrollbar.set(*arg)} @yscrollbar.command {|*arg| self.yview(*arg)} Tk.update # avoid scrollbar trouble end @yscrollbar end end X_Scrollable = XScrollable Y_Scrollable = YScrollable module Scrollable include XScrollable include YScrollable end end ================================================ FILE: ext/tk/lib/tk/scrollbar.rb ================================================ # # tk/scrollbar.rb : treat scrollbar widget # require 'tk' class Tk::Scrollbar # require 'tk' require 'tk/listbox' class TkScrollbox use current TkListbox class list = TkListbox.new(@frame) #scroll = Tk::Scrollbar.new(@frame) # -> use current TkScrollbar class scroll = TkScrollbar.new(@frame) @path = list.path =begin list.configure 'yscroll', scroll.path+" set" list.pack 'side'=>'left','fill'=>'both','expand'=>'yes' scroll.configure 'command', list.path+" yview" scroll.pack 'side'=>'right','fill'=>'y' =end list.yscrollbar(scroll) list.pack('side'=>'left','fill'=>'both','expand'=>'yes') scroll.pack('side'=>'right','fill'=>'y') delegate('DEFAULT', list) delegate('foreground', list) delegate('background', list, scroll) delegate('borderwidth', @frame) delegate('relief', @frame) configure keys if keys end private :initialize_composite end ================================================ FILE: ext/tk/lib/tk/selection.rb ================================================ # # tk/selection.rb : control selection # require 'tk' module TkSelection include Tk extend Tk TkCommandNames = ['selection'.freeze].freeze def self.clear(sel=nil) if sel tk_call_without_enc('selection', 'clear', '-selection', sel) else tk_call_without_enc('selection', 'clear') end end def self.clear_on_display(win, sel=nil) if sel tk_call_without_enc('selection', 'clear', '-displayof', win, '-selection', sel) else tk_call_without_enc('selection', 'clear', '-displayof', win) end end def clear(sel=nil) TkSelection.clear_on_display(self, sel) self end def self.get(keys=nil) #tk_call('selection', 'get', *hash_kv(keys)) _fromUTF8(tk_call_without_enc('selection', 'get', *hash_kv(keys))) end def self.get_on_display(win, keys=nil) #tk_call('selection', 'get', '-displayof', win, *hash_kv(keys)) _fromUTF8(tk_call_without_enc('selection', 'get', '-displayof', win, *hash_kv(keys))) end def get(keys=nil) TkSelection.get_on_display(self, sel) end def self.handle(win, func=Proc.new, keys=nil, &b) if func.kind_of?(Hash) && keys == nil keys = func func = Proc.new(&b) end args = ['selection', 'handle'] args.concat(hash_kv(keys)) args.concat([win, func]) tk_call_without_enc(*args) end def handle(func=Proc.new, keys=nil, &b) TkSelection.handle(self, func, keys, &b) end def self.get_owner(sel=nil) if sel window(tk_call_without_enc('selection', 'own', '-selection', sel)) else window(tk_call_without_enc('selection', 'own')) end end def self.get_owner_on_display(win, sel=nil) if sel window(tk_call_without_enc('selection', 'own', '-displayof', win, '-selection', sel)) else window(tk_call_without_enc('selection', 'own', '-displayof', win)) end end def get_owner(sel=nil) TkSelection.get_owner_on_display(self, sel) self end def self.set_owner(win, keys=nil) tk_call_without_enc('selection', 'own', *(hash_kv(keys) << win)) end def set_owner(keys=nil) TkSelection.set_owner(self, keys) self end end ================================================ FILE: ext/tk/lib/tk/spinbox.rb ================================================ # # tk/spinbox.rb - Tk spinbox classes # by Yukihiro Matsumoto # require 'tk' require 'tk/entry' class Tk::Spinbox String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) (val)? '1': '0' end end def self._config_keys ['command'] end end def __validation_class_list super() << SpinCommand end Tk::ValidateConfigure.__def_validcmd(binding, SpinCommand) #def create_self(keys) # tk_call_without_enc('spinbox', @path) # if keys and keys != None # configure(keys) # end #end #private :create_self def __boolval_optkeys super() << 'wrap' end private :__boolval_optkeys def __strval_optkeys super() << 'buttonbackground' << 'format' end private :__strval_optkeys def __listval_optkeys super() << 'values' end private :__listval_optkeys def identify(x, y) tk_send_without_enc('identify', x, y) end def spinup tk_send_without_enc('invoke', 'spinup') self end def spindown tk_send_without_enc('invoke', 'spindown') self end def set(str) _fromUTF8(tk_send_without_enc('set', _get_eval_enc_str(str))) end end #TkSpinbox = Tk::Spinbox unless Object.const_defined? :TkSpinbox Tk.__set_toplevel_aliases__(:Tk, Tk::Spinbox, :TkSpinbox) ================================================ FILE: ext/tk/lib/tk/tagfont.rb ================================================ # # tk/tagfont.rb : control font of tags # require 'tk' module TkTreatTagFont def font_configinfo @parent.tagfont_configinfo(@id) end # alias font font_configinfo def font_configure(slot) @parent.tagfont_configure(@id, slot) self end def latinfont_configure(ltn, keys=nil) @parent.latintagfont_configure(@id, ltn, keys) self end alias asciifont_configure latinfont_configure def kanjifont_configure(knj, keys=nil) @parent.kanjitagfont_configure(@id, ltn, keys) self end def font_copy(win, wintag=nil) @parent.tagfont_copy(@id, win, wintag) self end def latinfont_copy(win, wintag=nil) @parent.latintagfont_copy(@id, win, wintag) self end alias asciifont_copy latinfont_copy def kanjifont_copy(win, wintag=nil) @parent.kanjitagfont_copy(@id, win, wintag) self end end ================================================ FILE: ext/tk/lib/tk/text.rb ================================================ # # tk/text.rb - Tk text classes # by Yukihiro Matsumoto require 'tk' require 'tk/itemfont' require 'tk/itemconfig' require 'tk/scrollable' require 'tk/txtwin_abst' module TkTextTagConfig include TkTreatItemFont include TkItemConfigMethod def __item_cget_cmd(id) # id := [ type, tagOrId ] [self.path, id[0], 'cget', id[1]] end private :__item_cget_cmd def __item_config_cmd(id) # id := [ type, tagOrId ] [self.path, id[0], 'configure', id[1]] end private :__item_config_cmd def __item_pathname(id) if id.kind_of?(Array) id = tagid(id[1]) end [self.path, id].join(';') end private :__item_pathname def tag_cget(tagOrId, option) itemcget(['tag', tagOrId], option) end def tag_cget_strict(tagOrId, option) itemcget_strict(['tag', tagOrId], option) end def tag_configure(tagOrId, slot, value=None) itemconfigure(['tag', tagOrId], slot, value) end def tag_configinfo(tagOrId, slot=nil) itemconfiginfo(['tag', tagOrId], slot) end def current_tag_configinfo(tagOrId, slot=nil) current_itemconfiginfo(['tag', tagOrId], slot) end def window_cget(tagOrId, option) itemcget(['window', tagOrId], option) end def window_cget_strict(tagOrId, option) itemcget_strict(['window', tagOrId], option) end def window_configure(tagOrId, slot, value=None) itemconfigure(['window', tagOrId], slot, value) end def window_configinfo(tagOrId, slot=nil) itemconfiginfo(['window', tagOrId], slot) end def current_window_configinfo(tagOrId, slot=nil) current_itemconfiginfo(['window', tagOrId], slot) end private :itemcget, :itemcget_strict private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo end class Tk::Text e begin if current_image_configinfo(index).has_key?(slot.to_s) # not tag error & option is known -> error on known option fail e else # not tag error & option is unknown nil end rescue fail e # tag error end end end end def image_configure(index, slot, value=None) if slot.kind_of?(Hash) _fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), *hash_kv(slot, true))) else _fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}", _get_eval_enc_str(value))) end self end def image_configinfo(index, slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if slot case slot.to_s when 'text', 'label', 'show', 'data', 'file' #conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"))) conf = tk_split_simplelist(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"), false, true) else #conf = tk_split_list(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"))) conf = tk_split_list(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"), 0, false, true) end conf[0] = conf[0][1..-1] conf else # tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index)))).collect{|conflist| # conf = tk_split_simplelist(conflist) tk_split_simplelist(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index)), false, false).collect{|conflist| conf = tk_split_simplelist(conflist, false, true) conf[0] = conf[0][1..-1] case conf[0] when 'text', 'label', 'show', 'data', 'file' else if conf[3] if conf[3].index('{') conf[3] = tk_split_list(conf[3]) else conf[3] = tk_tcl2ruby(conf[3]) end end if conf[4] if conf[4].index('{') conf[4] = tk_split_list(conf[4]) else conf[4] = tk_tcl2ruby(conf[4]) end end end conf[1] = conf[1][1..-1] if conf.size == 2 # alias info conf } end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY if slot case slot.to_s when 'text', 'label', 'show', 'data', 'file' #conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"))) conf = tk_split_simplelist(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"), false, true) else #conf = tk_split_list(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"))) conf = tk_split_list(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"), 0, false, true) end key = conf.shift[1..-1] { key => conf } else ret = {} #tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index)))).each{|conflist| # conf = tk_split_simplelist(conflist) tk_split_simplelist(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index)), false, false).each{|conflist| conf = tk_split_simplelist(conflist, false, true) key = conf.shift[1..-1] case key when 'text', 'label', 'show', 'data', 'file' else if conf[2] if conf[2].index('{') conf[2] = tk_split_list(conf[2]) else conf[2] = tk_tcl2ruby(conf[2]) end end if conf[3] if conf[3].index('{') conf[3] = tk_split_list(conf[3]) else conf[3] = tk_tcl2ruby(conf[3]) end end end if conf.size == 1 ret[key] = conf[0][1..-1] # alias info else ret[key] = conf end } ret end end end def current_image_configinfo(index, slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if slot conf = image_configinfo(index, slot) {conf[0] => conf[4]} else ret = {} image_configinfo(index).each{|conf| ret[conf[0]] = conf[4] if conf.size > 2 } ret end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY ret = {} image_configinfo(index, slot).each{|k, conf| ret[k] = conf[-1] if conf.kind_of?(Array) } ret end end def image_names #tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'names'))).collect{|elt| tk_split_simplelist(tk_send_without_enc('image', 'names'), false, true).collect{|elt| tagid2obj(elt) } end def set_insert(index) tk_send_without_enc('mark','set','insert', _get_eval_enc_str(index)) self end def set_current(index) tk_send_without_enc('mark','set','current', _get_eval_enc_str(index)) self end def insert(index, chars, *tags) if tags[0].kind_of?(Array) # multiple chars-taglist argument :: str, [tag,...], str, [tag,...], ... args = [chars] while tags.size > 0 args << tags.shift.collect{|x|_get_eval_string(x)}.join(' ') # taglist args << tags.shift if tags.size > 0 # chars end super(index, *args) else # single chars-taglist argument :: str, tag, tag, ... if tags.size == 0 super(index, chars) else super(index, chars, tags.collect{|x|_get_eval_string(x)}.join(' ')) end end end def destroy @tags = {} unless @tags @tags.each_value do |t| t.destroy end super() end def backspace self.delete 'insert' end def bbox(index) list(tk_send_without_enc('bbox', _get_eval_enc_str(index))) end def compare(idx1, op, idx2) bool(tk_send_without_enc('compare', _get_eval_enc_str(idx1), op, _get_eval_enc_str(idx2))) end def count(idx1, idx2, *opts) # opts are Tk8.5 feature cnt = 0 args = opts.collect{|opt| str = opt.to_s cnt += 1 if str != 'update' '-' + str } args << _get_eval_enc_str(idx1) << _get_eval_enc_str(idx2) if cnt <= 1 number(tk_send_without_enc('count', *opts)) else list(tk_send_without_enc('count', *opts)) end end def count_info(idx1, idx2, update=true) # Tk8.5 feature opts = [ :chars, :displaychars, :displayindices, :displaylines, :indices, :lines, :xpixels, :ypixels ] if update lst = count(idx1, idx2, :update, *opts) else lst = count(idx1, idx2, *opts) end info = {} opts.each_with_index{|key, idx| info[key] = lst[idx]} info end def peer_names() # Tk8.5 feature list(tk_send_without_enc('peer', 'names')) end def replace(idx1, idx2, *opts) tk_send('replace', idx1, idx2, *opts) self end def debug bool(tk_send_without_enc('debug')) end def debug=(boolean) tk_send_without_enc('debug', boolean) #self boolean end def dlineinfo(index) list(tk_send_without_enc('dlineinfo', _get_eval_enc_str(index))) end def modified? bool(tk_send_without_enc('edit', 'modified')) end def modified(mode) tk_send_without_enc('edit', 'modified', mode) self end def modified=(mode) modified(mode) mode end def edit_redo tk_send_without_enc('edit', 'redo') self end def edit_reset tk_send_without_enc('edit', 'reset') self end def edit_separator tk_send_without_enc('edit', 'separator') self end def edit_undo tk_send_without_enc('edit', 'undo') self end def xview_pickplace(index) tk_send_without_enc('xview', '-pickplace', _get_eval_enc_str(index)) self end def yview_pickplace(index) tk_send_without_enc('yview', '-pickplace', _get_eval_enc_str(index)) self end def text_copy # Tk8.4 feature tk_call_without_enc('tk_textCopy', @path) self end def text_cut # Tk8.4 feature tk_call_without_enc('tk_textCut', @path) self end def text_paste # Tk8.4 feature tk_call_without_enc('tk_textPaste', @path) self end def tag_add(tag, index1, index2=None) tk_send_without_enc('tag', 'add', _get_eval_enc_str(tag), _get_eval_enc_str(index1), _get_eval_enc_str(index2)) self end alias addtag tag_add alias add_tag tag_add def tag_delete(*tags) tk_send_without_enc('tag', 'delete', *(tags.collect{|tag| _get_eval_enc_str(tag)})) TkTextTag::TTagID_TBL.mutex.synchronize{ if TkTextTag::TTagID_TBL[@path] tags.each{|tag| if tag.kind_of?(TkTextTag) TkTextTag::TTagID_TBL[@path].delete(tag.id) else TkTextTag::TTagID_TBL[@path].delete(tag) end } end } self end alias deltag tag_delete alias delete_tag tag_delete #def tag_bind(tag, seq, cmd=Proc.new, *args) # _bind([@path, 'tag', 'bind', tag], seq, cmd, *args) # self #end def tag_bind(tag, seq, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind([@path, 'tag', 'bind', tag], seq, cmd, *args) self end #def tag_bind_append(tag, seq, cmd=Proc.new, *args) # _bind_append([@path, 'tag', 'bind', tag], seq, cmd, *args) # self #end def tag_bind_append(tag, seq, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append([@path, 'tag', 'bind', tag], seq, cmd, *args) self end def tag_bind_remove(tag, seq) _bind_remove([@path, 'tag', 'bind', tag], seq) self end def tag_bindinfo(tag, context=nil) _bindinfo([@path, 'tag', 'bind', tag], context) end =begin def tag_cget(tag, key) case key.to_s when 'text', 'label', 'show', 'data', 'file' tk_call_without_enc(@path, 'tag', 'cget', _get_eval_enc_str(tag), "-#{key}") when 'font', 'kanjifont' #fnt = tk_tcl2ruby(tk_send('tag', 'cget', tag, "-#{key}")) fnt = tk_tcl2ruby(_fromUTF8(tk_send_without_enc('tag','cget',_get_eval_enc_str(tag),'-font'))) unless fnt.kind_of?(TkFont) fnt = tagfontobj(tag, fnt) end if key.to_s == 'kanjifont' && JAPANIZED_TK && TK_VERSION =~ /^4\.*/ # obsolete; just for compatibility fnt.kanji_font else fnt end else tk_tcl2ruby(_fromUTF8(tk_call_without_enc(@path,'tag','cget',_get_eval_enc_str(tag),"-#{key}"))) end end def tag_configure(tag, key, val=None) if key.kind_of?(Hash) key = _symbolkey2str(key) if ( key['font'] || key['kanjifont'] \ || key['latinfont'] || key['asciifont'] ) tagfont_configure(tag, key) else tk_send_without_enc('tag', 'configure', _get_eval_enc_str(tag), *hash_kv(key, true)) end else if key == 'font' || key == :font || key == 'kanjifont' || key == :kanjifont || key == 'latinfont' || key == :latinfont || key == 'asciifont' || key == :asciifont if val == None tagfontobj(tag) else tagfont_configure(tag, {key=>val}) end else tk_send_without_enc('tag', 'configure', _get_eval_enc_str(tag), "-#{key}", _get_eval_enc_str(val)) end end self end def tag_configinfo(tag, key=nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if key case key.to_s when 'text', 'label', 'show', 'data', 'file' conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('tag','configure',_get_eval_enc_str(tag),"-#{key}"))) when 'font', 'kanjifont' conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('tag','configure',_get_eval_enc_str(tag),"-#{key}"))) conf[4] = tagfont_configinfo(tag, conf[4]) else conf = tk_split_list(_fromUTF8(tk_send_without_enc('tag','configure',_get_eval_enc_str(tag),"-#{key}"))) end conf[0] = conf[0][1..-1] conf else ret = tk_split_simplelist(_fromUTF8(tk_send('tag','configure',_get_eval_enc_str(tag)))).collect{|conflist| conf = tk_split_simplelist(conflist) conf[0] = conf[0][1..-1] case conf[0] when 'text', 'label', 'show', 'data', 'file' else if conf[3] if conf[3].index('{') conf[3] = tk_split_list(conf[3]) else conf[3] = tk_tcl2ruby(conf[3]) end end if conf[4] if conf[4].index('{') conf[4] = tk_split_list(conf[4]) else conf[4] = tk_tcl2ruby(conf[4]) end end end conf[1] = conf[1][1..-1] if conf.size == 2 # alias info conf } fontconf = ret.assoc('font') if fontconf ret.delete_if{|item| item[0] == 'font' || item[0] == 'kanjifont'} fontconf[4] = tagfont_configinfo(tag, fontconf[4]) ret.push(fontconf) else ret end end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY if key case key.to_s when 'text', 'label', 'show', 'data', 'file' conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('tag','configure',_get_eval_enc_str(tag),"-#{key}"))) when 'font', 'kanjifont' conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('tag','configure',_get_eval_enc_str(tag),"-#{key}"))) conf[4] = tagfont_configinfo(tag, conf[4]) else conf = tk_split_list(_fromUTF8(tk_send_without_enc('tag','configure',_get_eval_enc_str(tag),"-#{key}"))) end key = conf.shift[1..-1] { key => conf } else ret = {} tk_split_simplelist(_fromUTF8(tk_send('tag','configure',_get_eval_enc_str(tag)))).each{|conflist| conf = tk_split_simplelist(conflist) key = conf.shift[1..-1] case key when 'text', 'label', 'show', 'data', 'file' else if conf[2] if conf[2].index('{') conf[2] = tk_split_list(conf[2]) else conf[2] = tk_tcl2ruby(conf[2]) end end if conf[3] if conf[3].index('{') conf[3] = tk_split_list(conf[3]) else conf[3] = tk_tcl2ruby(conf[3]) end end end if conf.size == 1 ret[key] = conf[0][1..-1] # alias info else ret[key] = conf end } fontconf = ret['font'] if fontconf ret.delete('font') ret.delete('kanjifont') fontconf[3] = tagfont_configinfo(tag, fontconf[3]) ret['font'] = fontconf end ret end end end def current_tag_configinfo(tag, key=nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if key conf = tag_configinfo(tag, key) {conf[0] => conf[4]} else ret = {} tag_configinfo(tag).each{|conf| ret[conf[0]] = conf[4] if conf.size > 2 } ret end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY ret = {} tag_configinfo(tag, key).each{|k, conf| ret[k] = conf[-1] if conf.kind_of?(Array) } ret end end =end def tag_raise(tag, above=None) tk_send_without_enc('tag', 'raise', _get_eval_enc_str(tag), _get_eval_enc_str(above)) self end def tag_lower(tag, below=None) tk_send_without_enc('tag', 'lower', _get_eval_enc_str(tag), _get_eval_enc_str(below)) self end def tag_remove(tag, *indices) tk_send_without_enc('tag', 'remove', _get_eval_enc_str(tag), *(indices.collect{|idx| _get_eval_enc_str(idx)})) self end def tag_ranges(tag) #l = tk_split_simplelist(tk_send_without_enc('tag', 'ranges', # _get_eval_enc_str(tag))) l = tk_split_simplelist(tk_send_without_enc('tag', 'ranges', _get_eval_enc_str(tag)), false, true) r = [] while key=l.shift r.push [Tk::Text::IndexString.new(key), Tk::Text::IndexString.new(l.shift)] end r end def tag_nextrange(tag, first, last=None) simplelist(tk_send_without_enc('tag', 'nextrange', _get_eval_enc_str(tag), _get_eval_enc_str(first), _get_eval_enc_str(last))).collect{|idx| Tk::Text::IndexString.new(idx) } end def tag_prevrange(tag, first, last=None) simplelist(tk_send_without_enc('tag', 'prevrange', _get_eval_enc_str(tag), _get_eval_enc_str(first), _get_eval_enc_str(last))).collect{|idx| Tk::Text::IndexString.new(idx) } end =begin def window_cget(index, slot) case slot.to_s when 'text', 'label', 'show', 'data', 'file' _fromUTF8(tk_send_without_enc('window', 'cget', _get_eval_enc_str(index), "-#{slot}")) when 'font', 'kanjifont' #fnt = tk_tcl2ruby(tk_send('window', 'cget', index, "-#{slot}")) fnt = tk_tcl2ruby(_fromUTF8(tk_send_without_enc('window', 'cget', _get_eval_enc_str(index), '-font'))) unless fnt.kind_of?(TkFont) fnt = tagfontobj(index, fnt) end if slot.to_s == 'kanjifont' && JAPANIZED_TK && TK_VERSION =~ /^4\.*/ # obsolete; just for compatibility fnt.kanji_font else fnt end else tk_tcl2ruby(_fromUTF8(tk_send_without_enc('window', 'cget', _get_eval_enc_str(index), "-#{slot}"))) end end def window_configure(index, slot, value=None) if index.kind_of?(TkTextWindow) index.configure(slot, value) else if slot.kind_of?(Hash) slot = _symbolkey2str(slot) win = slot['window'] # slot['window'] = win.epath if win.kind_of?(TkWindow) slot['window'] = _epath(win) if win if slot['create'] p_create = slot['create'] if p_create.kind_of?(Proc) #=begin slot['create'] = install_cmd(proc{ id = p_create.call if id.kind_of?(TkWindow) id.epath else id end }) #=end slot['create'] = install_cmd(proc{_epath(p_create.call)}) end end tk_send_without_enc('window', 'configure', _get_eval_enc_str(index), *hash_kv(slot, true)) else if slot == 'window' || slot == :window # id = value # value = id.epath if id.kind_of?(TkWindow) value = _epath(value) end if slot == 'create' || slot == :create p_create = value if p_create.kind_of?(Proc) #=begin value = install_cmd(proc{ id = p_create.call if id.kind_of?(TkWindow) id.epath else id end }) #=end value = install_cmd(proc{_epath(p_create.call)}) end end tk_send_without_enc('window', 'configure', _get_eval_enc_str(index), "-#{slot}", _get_eval_enc_str(value)) end end self end def window_configinfo(win, slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if slot case slot.to_s when 'text', 'label', 'show', 'data', 'file' conf = tk_split_simplelist(_fromUTF8(tk_send('window', 'configure', _get_eval_enc_str(win), "-#{slot}"))) else conf = tk_split_list(_fromUTF8(tk_send('window', 'configure', _get_eval_enc_str(win), "-#{slot}"))) end conf[0] = conf[0][1..-1] conf else tk_split_simplelist(_fromUTF8(tk_send('window', 'configure', _get_eval_enc_str(win)))).collect{|conflist| conf = tk_split_simplelist(conflist) conf[0] = conf[0][1..-1] case conf[0] when 'text', 'label', 'show', 'data', 'file' else if conf[3] if conf[3].index('{') conf[3] = tk_split_list(conf[3]) else conf[3] = tk_tcl2ruby(conf[3]) end end if conf[4] if conf[4].index('{') conf[4] = tk_split_list(conf[4]) else conf[4] = tk_tcl2ruby(conf[4]) end end end conf[1] = conf[1][1..-1] if conf.size == 2 # alias info conf } end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY if slot case slot.to_s when 'text', 'label', 'show', 'data', 'file' conf = tk_split_simplelist(_fromUTF8(tk_send('window', 'configure', _get_eval_enc_str(win), "-#{slot}"))) else conf = tk_split_list(_fromUTF8(tk_send('window', 'configure', _get_eval_enc_str(win), "-#{slot}"))) end key = conf.shift[1..-1] { key => conf } else ret = {} tk_split_simplelist(_fromUTF8(tk_send('window', 'configure', _get_eval_enc_str(win)))).each{|conflist| conf = tk_split_simplelist(conflist) key = conf.shift[1..-1] case key when 'text', 'label', 'show', 'data', 'file' else if conf[2] if conf[2].index('{') conf[2] = tk_split_list(conf[2]) else conf[2] = tk_tcl2ruby(conf[2]) end end if conf[3] if conf[3].index('{') conf[3] = tk_split_list(conf[3]) else conf[3] = tk_tcl2ruby(conf[3]) end end end if conf.size == 1 ret[key] = conf[0][1..-1] # alias info else ret[key] = conf end } ret end end end def current_window_configinfo(win, slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if slot conf = window_configinfo(win, slot) {conf[0] => conf[4]} else ret = {} window_configinfo(win).each{|conf| ret[conf[0]] = conf[4] if conf.size > 2 } ret end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY ret = {} window_configinfo(win, slot).each{|k, conf| ret[k] = conf[-1] if conf.kind_of?(Array) } ret end end =end def window_names # tk_split_simplelist(_fromUTF8(tk_send_without_enc('window', 'names'))).collect{|elt| tk_split_simplelist(tk_send_without_enc('window', 'names'), false, true).collect{|elt| tagid2obj(elt) } end def _ktext_length(txt) if TkCore::WITH_ENCODING ### Ruby 1.9 !!!!!!!!!!!!! return txt.length end ########################### if $KCODE !~ /n/i return txt.gsub(/[^\Wa-zA-Z_\d]/, ' ').length end # $KCODE == 'NONE' if JAPANIZED_TK tk_call_without_enc('kstring', 'length', _get_eval_enc_str(txt)).to_i else begin tk_call_without_enc('encoding', 'convertto', 'ascii', _get_eval_enc_str(txt)).length rescue StandardError, NameError # sorry, I have no plan txt.length end end end private :_ktext_length def tksearch(*args) # call 'search' subcommand of text widget # args ::= [] [] # If is regexp, then it must be a regular expression of Tcl nocase = false if args[0].kind_of?(Array) opts = args.shift.collect{|opt| s_opt = opt.to_s nocase = true if s_opt == 'nocase' '-' + s_opt } else opts = [] end if args[0].kind_of?(Regexp) regexp = args.shift if !nocase && (regexp.options & Regexp::IGNORECASE) != 0 opts << '-nocase' end args.unshift(regexp.source) end opts << '--' ret = tk_send('search', *(opts + args)) if ret == "" nil else Tk::Text::IndexString.new(ret) end end def tksearch_with_count(*args) # call 'search' subcommand of text widget # args ::= [] [] # If is regexp, then it must be a regular expression of Tcl nocase = false if args[0].kind_of?(Array) opts = args.shift.collect{|opt| s_opt = opt.to_s nocase = true if s_opt == 'nocase' '-' + s_opt } else opts = [] end opts << '-count' << args.shift if args[0].kind_of?(Regexp) regexp = args.shift if !nocase && (regexp.options & Regexp::IGNORECASE) != 0 opts << '-nocase' end args.unshift(regexp.source) end opts << '--' ret = tk_send('search', *(opts + args)) if ret == "" nil else Tk::Text::IndexString.new(ret) end end def search_with_length(pat,start,stop=None) pat = pat.chr if pat.kind_of?(Integer) if stop != None return ["", 0] if compare(start,'>=',stop) txt = get(start,stop) if (pos = txt.index(pat)) match = $& #pos = txt[0..(pos-1)].split('').length if pos > 0 pos = _ktext_length(txt[0..(pos-1)]) if pos > 0 if pat.kind_of?(String) #return [index(start + " + #{pos} chars"), pat.split('').length] return [index(start + " + #{pos} chars"), _ktext_length(pat), pat.dup] else #return [index(start + " + #{pos} chars"), $&.split('').length] return [index(start + " + #{pos} chars"), _ktext_length(match), match] end else return ["", 0] end else txt = get(start,'end - 1 char') if (pos = txt.index(pat)) match = $& #pos = txt[0..(pos-1)].split('').length if pos > 0 pos = _ktext_length(txt[0..(pos-1)]) if pos > 0 if pat.kind_of?(String) #return [index(start + " + #{pos} chars"), pat.split('').length] return [index(start + " + #{pos} chars"), _ktext_length(pat), pat.dup] else #return [index(start + " + #{pos} chars"), $&.split('').length] return [index(start + " + #{pos} chars"), _ktext_length(match), match] end else txt = get('1.0','end - 1 char') if (pos = txt.index(pat)) match = $& #pos = txt[0..(pos-1)].split('').length if pos > 0 pos = _ktext_length(txt[0..(pos-1)]) if pos > 0 if pat.kind_of?(String) #return [index("1.0 + #{pos} chars"), pat.split('').length] return [index("1.0 + #{pos} chars"), _ktext_length(pat), pat.dup] else #return [index("1.0 + #{pos} chars"), $&.split('').length] return [index("1.0 + #{pos} chars"), _ktext_length(match), match] end else return ["", 0] end end end end def search(pat,start,stop=None) search_with_length(pat,start,stop)[0] end def rsearch_with_length(pat,start,stop=None) pat = pat.chr if pat.kind_of?(Integer) if stop != None return ["", 0] if compare(start,'<=',stop) txt = get(stop,start) if (pos = txt.rindex(pat)) match = $& #pos = txt[0..(pos-1)].split('').length if pos > 0 pos = _ktext_length(txt[0..(pos-1)]) if pos > 0 if pat.kind_of?(String) #return [index(stop + " + #{pos} chars"), pat.split('').length] return [index(stop + " + #{pos} chars"), _ktext_length(pat), pat.dup] else #return [index(stop + " + #{pos} chars"), $&.split('').length] return [index(stop + " + #{pos} chars"), _ktext_length(match), match] end else return ["", 0] end else txt = get('1.0',start) if (pos = txt.rindex(pat)) match = $& #pos = txt[0..(pos-1)].split('').length if pos > 0 pos = _ktext_length(txt[0..(pos-1)]) if pos > 0 if pat.kind_of?(String) #return [index("1.0 + #{pos} chars"), pat.split('').length] return [index("1.0 + #{pos} chars"), _ktext_length(pat), pat.dup] else #return [index("1.0 + #{pos} chars"), $&.split('').length] return [index("1.0 + #{pos} chars"), _ktext_length(match), match] end else txt = get('1.0','end - 1 char') if (pos = txt.rindex(pat)) match = $& #pos = txt[0..(pos-1)].split('').length if pos > 0 pos = _ktext_length(txt[0..(pos-1)]) if pos > 0 if pat.kind_of?(String) #return [index("1.0 + #{pos} chars"), pat.split('').length] return [index("1.0 + #{pos} chars"), _ktext_length(pat), pat.dup] else #return [index("1.0 + #{pos} chars"), $&.split('').length] return [index("1.0 + #{pos} chars"), _ktext_length(match), match] end else return ["", 0] end end end end def rsearch(pat,start,stop=None) rsearch_with_length(pat,start,stop)[0] end def dump(type_info, *index, &block) if type_info.kind_of?(Symbol) type_info = [ type_info.to_s ] elsif type_info.kind_of?(String) type_info = [ type_info ] end args = type_info.collect{|inf| '-' + inf} args << '-command' << block if block str = tk_send('dump', *(args + index)) result = [] sel = nil i = 0 while i < str.size # retrieve key idx = str.index(/ /, i) result.push str[i..(idx-1)] i = idx + 1 # retrieve value case result[-1] when 'text' if str[i] == ?{ # text formed as {...} val, i = _retrieve_braced_text(str, i) result.push val else # text which may contain backslahes val, i = _retrieve_backslashed_text(str, i) result.push val end else idx = str.index(/ /, i) val = str[i..(idx-1)] case result[-1] when 'mark' case val when 'insert' result.push TkTextMarkInsert.new(self) when 'current' result.push TkTextMarkCurrent.new(self) when 'anchor' result.push TkTextMarkAnchor.new(self) else result.push tk_tcl2ruby(val) end when 'tagon' if val == 'sel' if sel result.push sel else result.push TkTextTagSel.new(self) end else result.push tk_tcl2ruby(val) end when 'tagoff' result.push tk_tcl2ruby(val) when 'window' result.push tk_tcl2ruby(val) when 'image' result.push tk_tcl2ruby(val) end i = idx + 1 end # retrieve index idx = str.index(/ /, i) if idx result.push(Tk::Text::IndexString.new(str[i..(idx-1)])) i = idx + 1 else result.push(Tk::Text::IndexString.new(str[i..-1])) break end end kvis = [] until result.empty? kvis.push [result.shift, result.shift, result.shift] end kvis # result is [[key1, value1, index1], [key2, value2, index2], ...] end def _retrieve_braced_text(str, i) cnt = 0 idx = i while idx < str.size case str[idx] when ?{ cnt += 1 when ?} cnt -= 1 if cnt == 0 break end end idx += 1 end return str[i+1..idx-1], idx + 2 end private :_retrieve_braced_text def _retrieve_backslashed_text(str, i) j = i idx = nil loop { idx = str.index(/ /, j) if str[idx-1] == ?\\ j += 1 else break end } val = str[i..(idx-1)] val.gsub!(/\\( |\{|\})/, '\1') return val, idx + 1 end private :_retrieve_backslashed_text def dump_all(*index, &block) dump(['all'], *index, &block) end def dump_mark(*index, &block) dump(['mark'], *index, &block) end def dump_tag(*index, &block) dump(['tag'], *index, &block) end def dump_text(*index, &block) dump(['text'], *index, &block) end def dump_window(*index, &block) dump(['window'], *index, &block) end def dump_image(*index, &block) dump(['image'], *index, &block) end end #TkText = Tk::Text unless Object.const_defined? :TkText Tk.__set_toplevel_aliases__(:Tk, Tk::Text, :TkText) ####################################### class Tk::Text::Peer < Tk::Text # Tk8.5 feature def initialize(text, parent=nil, keys={}) unless text.kind_of?(Tk::Text) fail ArgumentError, "Tk::Text is expected for 1st argument" end @src_text = text super(parent, keys) end def create_self(keys) if keys and keys != None tk_call_without_enc(@src_text.path, 'peer', 'create', @path) else tk_call_without_enc(@src_text.path, 'peer', 'create', @path) end end private :create_self end ================================================ FILE: ext/tk/lib/tk/textimage.rb ================================================ # # tk/textimage.rb - treat Tk text image object # require 'tk' require 'tk/text' class TkTextImage 0 tk_call_without_enc(@t.path, 'window', 'configure', @index, *hash_kv(slot, true)) end else if slot == 'window' || slot == :window @id = value # value = @id.epath if @id.kind_of?(TkWindow) value = _epath(@id) if @id end if slot == 'create' || slot == :create self.create=value else tk_call_without_enc(@t.path, 'window', 'configure', @index, "-#{slot}", _get_eval_enc_str(value)) end end self end def configinfo(slot = nil) @t.window_configinfo(@index, slot) end def current_configinfo(slot = nil) @t.current_window_configinfo(@index, slot) end def window @id end def window=(value) @id = value # value = @id.epath if @id.kind_of?(TkWindow) value = _epath(@id) if @id tk_call_without_enc(@t.path, 'window', 'configure', @index, '-window', _get_eval_enc_str(value)) value end def create @p_create end def create=(value) @p_create = value # if @p_create.kind_of?(Proc) if TkComm._callback_entry?(@p_create) value = install_cmd(proc{ @id = @p_create.call if @id.kind_of?(TkWindow) @id.epath else @id end }) end tk_call_without_enc(@t.path, 'window', 'configure', @index, '-create', _get_eval_enc_str(value)) value end end TktWindow = TkTextWindow ================================================ FILE: ext/tk/lib/tk/timer.rb ================================================ # # tk/timer.rb : methods for Tcl/Tk after command # # $Id$ # require 'tk' class TkTimer include TkCore extend TkCore TkCommandNames = ['after'.freeze].freeze (Tk_CBID = ['a'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } Tk_CBTBL = {}.taint TkCore::INTERP.add_tk_procs('rb_after', 'id', <<-'EOL') if {[set st [catch {eval {ruby_cmd TkTimer callback} $id} ret]] != 0} { return -code $st $ret } { return $ret } EOL DEFAULT_IGNORE_EXCEPTIONS = [ NameError, RuntimeError ].freeze ############################### # class methods ############################### def self.start(*args, &b) self.new(*args, &b).start end def self.callback(obj_id) ex_obj = Tk_CBTBL[obj_id] return "" if ex_obj == nil; # canceled ex_obj.cb_call end def self.info(obj = nil) if obj if obj.kind_of?(TkTimer) if obj.after_id inf = tk_split_list(tk_call_without_enc('after','info',obj.after_id)) [Tk_CBTBL[inf[0][1]], inf[1]] else nil end else fail ArgumentError, "TkTimer object is expected" end else tk_call_without_enc('after', 'info').split(' ').collect!{|id| ret = Tk_CBTBL.find{|key,val| val.after_id == id} (ret == nil)? id: ret[1] } end end ############################### # instance methods ############################### def do_callback @in_callback = true @after_id = nil begin @return_value = @current_proc.call(self) rescue SystemExit exit(0) rescue Interrupt exit!(1) rescue Exception => e if @cancel_on_exception && @cancel_on_exception.find{|exc| e.kind_of?(exc)} cancel @return_value = e @in_callback = false return e else fail e end end if @set_next set_next_callback(@current_args) else @set_next = true end @in_callback = false @return_value end def set_callback(sleep, args=nil) if TkCore::INTERP.deleted? self.cancel return self end @after_script = "rb_after #{@id}" @current_args = args @current_script = [sleep, @after_script] @after_id = tk_call_without_enc('after', sleep, @after_script) self end def set_next_callback(args) if @running == false || @proc_max == 0 || @do_loop == 0 Tk_CBTBL.delete(@id) ;# for GC @running = false # @wait_var.value = 0 __at_end__ return end if @current_pos >= @proc_max if @do_loop < 0 || (@do_loop -= 1) > 0 @current_pos = 0 else Tk_CBTBL.delete(@id) ;# for GC @running = false # @wait_var.value = 0 __at_end__ return end end @current_args = args # if @sleep_time.kind_of?(Proc) if TkComm._callback_entry?(@sleep_time) sleep = @sleep_time.call(self) else sleep = @sleep_time end @current_sleep = sleep cmd, *cmd_args = @loop_proc[@current_pos] @current_pos += 1 @current_proc = cmd set_callback(sleep, cmd_args) end def initialize(*args, &b) Tk_CBID.mutex.synchronize{ # @id = Tk_CBID.join('') @id = Tk_CBID.join(TkCore::INTERP._ip_id_) Tk_CBID[1].succ! } @wait_var = TkVariable.new(0) @at_end_proc = nil @cb_cmd = TkCore::INTERP.get_cb_entry(self.method(:do_callback)) @set_next = true @init_sleep = 0 @init_proc = nil @init_args = [] @current_script = [] @current_proc = nil @current_args = nil @return_value = nil @sleep_time = 0 @current_sleep = 0 @loop_exec = 0 @do_loop = 0 @loop_proc = [] @proc_max = 0 @current_pos = 0 @after_id = nil @after_script = nil @cancel_on_exception = DEFAULT_IGNORE_EXCEPTIONS # Unless @cancel_on_exception, Ruby/Tk shows an error dialog box when # an excepsion is raised on TkTimer callback procedure. # If @cancel_on_exception is an array of exception classes and the raised # exception is included in the array, Ruby/Tk cancels executing TkTimer # callback procedures silently (TkTimer#cancel is called and no dialog is # shown). if b case args.size when 0 add_procs(b) when 1 args << -1 << b else args << b end end set_procs(*args) if args != [] @running = false @in_callback = false end attr :after_id attr :after_script attr :current_proc attr :current_args attr :current_sleep alias :current_interval :current_sleep attr :return_value attr_accessor :loop_exec def __at_end__ @at_end_proc.call(self) if @at_end_proc @wait_var.value = 0 # for wait end private :__at_end__ def cb_call @cb_cmd.call end def get_procs [@init_sleep, @init_proc, @init_args, @sleep_time, @loop_exec, @loop_proc] end def current_status [@running, @current_sleep, @current_proc, @current_args, @do_loop, @cancel_on_exception] end def cancel_on_exception? @cancel_on_exception end def cancel_on_exception=(mode) if mode.kind_of?(Array) @cancel_on_exception = mode elsif mode @cancel_on_exception = DEFAULT_IGNORE_EXCEPTIONS else @cancel_on_exception = false end #self end def running? @running end def loop_rest @do_loop end def loop_rest=(rest) @do_loop = rest #self end def set_interval(interval) #if interval != 'idle' && interval != :idle \ # && !interval.kind_of?(Integer) && !interval.kind_of?(Proc) if interval != 'idle' && interval != :idle \ && !interval.kind_of?(Integer) && !TkComm._callback_entry?(interval) fail ArgumentError, "expect Integer or Proc" end @sleep_time = interval end def set_procs(interval, loop_exec, *procs) #if interval != 'idle' && interval != :idle \ # && !interval.kind_of?(Integer) && !interval.kind_of?(Proc) if interval != 'idle' && interval != :idle \ && !interval.kind_of?(Integer) && !TkComm._callback_entry?(interval) fail ArgumentError, "expect Integer or Proc for 1st argument" end @sleep_time = interval @loop_proc = [] procs.each{|e| # if e.kind_of?(Proc) if TkComm._callback_entry?(e) @loop_proc.push([e]) else @loop_proc.push(e) end } @proc_max = @loop_proc.size @current_pos = 0 if loop_exec.kind_of?(Integer) && loop_exec < 0 @loop_exec = -1 elsif loop_exec == true @loop_exec = -1 elsif loop_exec == nil || loop_exec == false || loop_exec == 0 @loop_exec = 0 else if not loop_exec.kind_of?(Integer) fail ArgumentError, "expect Integer for 2nd argument" end @loop_exec = loop_exec end @do_loop = @loop_exec self end def add_procs(*procs) procs.each{|e| # if e.kind_of?(Proc) if TkComm._callback_entry?(e) @loop_proc.push([e]) else @loop_proc.push(e) end } @proc_max = @loop_proc.size self end def delete_procs(*procs) procs.each{|e| # if e.kind_of?(Proc) if TkComm._callback_entry?(e) @loop_proc.delete([e]) else @loop_proc.delete(e) end } @proc_max = @loop_proc.size cancel if @proc_max == 0 self end def delete_at(n) @loop_proc.delete_at(n) @proc_max = @loop_proc.size cancel if @proc_max == 0 self end def set_start_proc(sleep=nil, init_proc=nil, *init_args, &b) # set parameters for 'restart' sleep = @init_sleep unless sleep if sleep != 'idle' && sleep != :idle && !sleep.kind_of?(Integer) fail ArgumentError, "expect Integer or 'idle' for 1st argument" end @init_sleep = sleep @init_proc = init_proc @init_args = init_args @init_proc = b if !@init_proc && b @init_proc = proc{|*args| } if @init_sleep > 0 && !@init_proc self end def start(*init_args, &b) return nil if @running Tk_CBTBL[@id] = self @do_loop = @loop_exec @current_pos = 0 @return_value = nil @after_id = nil @init_sleep = 0 @init_proc = nil @init_args = nil argc = init_args.size if argc > 0 sleep = init_args.shift if sleep != 'idle' && sleep != :idle && !sleep.kind_of?(Integer) fail ArgumentError, "expect Integer or 'idle' for 1st argument" end @init_sleep = sleep end @init_proc = init_args.shift if argc > 1 @init_args = init_args if argc > 2 @init_proc = b if !@init_proc && b @init_proc = proc{|*args| } if @init_sleep > 0 && !@init_proc @current_sleep = @init_sleep @running = true if @init_proc # if not @init_proc.kind_of?(Proc) if !TkComm._callback_entry?(@init_proc) fail ArgumentError, "Argument '#{@init_proc}' need to be Proc" end @current_proc = @init_proc set_callback(@init_sleep, @init_args) @set_next = false if @in_callback else set_next_callback(@init_args) end self end def reset(*reset_args) restart() if @running if @init_proc @return_value = @init_proc.call(self) else @return_value = nil end @current_pos = 0 @current_args = @init_args @current_script = [] @set_next = false if @in_callback self end def restart(*restart_args, &b) cancel if @running if restart_args == [] && !b start(@init_sleep, @init_proc, *@init_args) else start(*restart_args, &b) end end def cancel @running = false # @wait_var.value = 0 __at_end__ tk_call 'after', 'cancel', @after_id if @after_id @after_id = nil Tk_CBTBL.delete(@id) ;# for GC self end alias stop cancel def continue(wait=nil) fail RuntimeError, "is already running" if @running return restart() if @current_script.empty? sleep, cmd = @current_script fail RuntimeError, "no procedure to continue" unless cmd if wait unless wait.kind_of?(Integer) fail ArgumentError, "expect Integer for 1st argument" end sleep = wait end Tk_CBTBL[@id] = self @running = true @after_id = tk_call_without_enc('after', sleep, cmd) self end def skip fail RuntimeError, "is not running now" unless @running cancel Tk_CBTBL[@id] = self @running = true set_next_callback(@current_args) self end def info if @after_id inf = tk_split_list(tk_call_without_enc('after', 'info', @after_id)) [Tk_CBTBL[inf[0][1]], inf[1]] else nil end end def at_end(*arg, &b) if arg.empty? if b @at_end_proc = b else # no proc return @at_end_proc end else fail ArgumentError, "wrong number of arguments" if arg.length != 1 || b @at_end_proc = arg[0] end self end def wait(on_thread = true, check_root = false) if $SAFE >= 4 fail SecurityError, "can't wait timer at $SAFE >= 4" end unless @running if @return_value.kind_of?(Exception) fail @return_value else return @return_value end end @wait_var.wait(on_thread, check_root) if @return_value.kind_of?(Exception) fail @return_value else @return_value end end def eventloop_wait(check_root = false) wait(false, check_root) end def thread_wait(check_root = false) wait(true, check_root) end def tkwait(on_thread = true) wait(on_thread, true) end def eventloop_tkwait wait(false, true) end def thread_tkwait wait(true, true) end end TkAfter = TkTimer class TkRTTimer < TkTimer DEFAULT_OFFSET_LIST_SIZE = 5 def initialize(*args, &b) super(*args, &b) @offset_list = Array.new(DEFAULT_OFFSET_LIST_SIZE){ [0, 0] } @offset_s = 0 @offset_u = 0 @est_time = nil end def start(*args, &b) return nil if @running @est_time = nil @cb_start_time = Time.now super(*args, &b) end def cancel super() @est_time = nil @cb_start_time = Time.now self end alias stop cancel def continue(wait=nil) fail RuntimeError, "is already running" if @running @cb_start_time = Time.now super(wait) end def set_interval(interval) super(interval) @est_time = nil end def _offset_ave size = 0 d_sec = 0; d_usec = 0 @offset_list.each_with_index{|offset, idx| # weight = 1 weight = idx + 1 size += weight d_sec += offset[0] * weight d_usec += offset[1] * weight } offset_s, mod = d_sec.divmod(size) offset_u = ((mod * 1000000 + d_usec) / size.to_f).round [offset_s, offset_u] end private :_offset_ave def set_next_callback(args) if @running == false || @proc_max == 0 || @do_loop == 0 Tk_CBTBL.delete(@id) ;# for GC @running = false # @wait_var.value = 0 __at_end__ return end if @current_pos >= @proc_max if @do_loop < 0 || (@do_loop -= 1) > 0 @current_pos = 0 else Tk_CBTBL.delete(@id) ;# for GC @running = false # @wait_var.value = 0 __at_end__ return end end @current_args = args cmd, *cmd_args = @loop_proc[@current_pos] @current_pos += 1 @current_proc = cmd @offset_s, @offset_u = _offset_ave if TkComm._callback_entry?(@sleep_time) sleep = @sleep_time.call(self) else sleep = @sleep_time end if @est_time @est_time = Time.at(@est_time.to_i, @est_time.usec + sleep*1000) else @est_time = Time.at(@cb_start_time.to_i, @cb_start_time.usec + sleep*1000) end now = Time.now real_sleep = ((@est_time.to_i - now.to_i + @offset_s)*1000.0 + (@est_time.usec - now.usec + @offset_u)/1000.0).round if real_sleep <= 0 real_sleep = 0 @offset_s = now.to_i @offset_u = now.usec end @current_sleep = real_sleep set_callback(real_sleep, cmd_args) end def cb_call if @est_time @offset_list.shift @cb_start_time = Time.now if @current_sleep == 0 @offset_list.push([ @offset_s - @cb_start_time.to_i, @offset_u - @cb_start_time.usec ]) else @offset_list.push([ @offset_s + (@est_time.to_i - @cb_start_time.to_i), @offset_u + (@est_time.usec - @cb_start_time.usec) ]) end end @cb_cmd.call end end ================================================ FILE: ext/tk/lib/tk/toplevel.rb ================================================ # # tk/toplevel.rb : treat toplevel widget # require 'tk' require 'tk/wm' require 'tk/menuspec' class Tk::Toplevelproc, ... } super().update('menu'=>proc{|v| window(v)}) end private :__val2ruby_optkeys def __methodcall_optkeys # { key=>method, ... } TOPLEVEL_METHODCALL_OPTKEYS end private :__methodcall_optkeys def _wm_command_option_chk(keys) keys = {} unless keys new_keys = {} wm_cmds = {} conf_methods = _symbolkey2str(__methodcall_optkeys()) keys.each{|k,v| # k is a String if conf_methods.key?(k) wm_cmds[conf_methods[k]] = v elsif Wm.method_defined?(k) case k when 'screen','class','colormap','container','use','visual' new_keys[k] = v else case self.method(k).arity when -1,1 wm_cmds[k] = v else new_keys[k] = v end end else new_keys[k] = v end } [new_keys, wm_cmds] end private :_wm_command_option_chk def initialize(parent=nil, screen=nil, classname=nil, keys=nil) my_class_name = nil if self.class < WidgetClassNames[WidgetClassName] my_class_name = self.class.name my_class_name = nil if my_class_name == '' end if parent.kind_of? Hash keys = _symbolkey2str(parent) if keys.key?('classname') keys['class'] = keys.delete('classname') end @classname = keys['class'] @colormap = keys['colormap'] @container = keys['container'] @screen = keys['screen'] @use = keys['use'] @visual = keys['visual'] if !@classname && my_class_name keys['class'] = @classname = my_class_name end if @classname.kind_of? TkBindTag @db_class = @classname keys['class'] = @classname = @classname.id elsif @classname @db_class = TkDatabaseClass.new(@classname) keys['class'] = @classname else @db_class = self.class @classname = @db_class::WidgetClassName end keys, cmds = _wm_command_option_chk(keys) super(keys) cmds.each{|k,v| if v.kind_of? Array self.__send__(k,*v) else self.__send__(k,v) end } return end if screen.kind_of? Hash keys = screen else @screen = screen if classname.kind_of? Hash keys = classname else @classname = classname end end if keys.kind_of? Hash keys = _symbolkey2str(keys) if keys.key?('classname') keys['class'] = keys.delete('classname') end @classname = keys['class'] unless @classname @colormap = keys['colormap'] @container = keys['container'] @screen = keys['screen'] unless @screen @use = keys['use'] @visual = keys['visual'] else keys = {} end if !@classname && my_class_name keys['class'] = @classname = my_class_name end if @classname.kind_of? TkBindTag @db_class = @classname keys['class'] = @classname = @classname.id elsif @classname @db_class = TkDatabaseClass.new(@classname) keys['class'] = @classname else @db_class = self.class @classname = @db_class::WidgetClassName end keys, cmds = _wm_command_option_chk(keys) super(parent, keys) cmds.each{|k,v| if v.kind_of? Array self.send(k,*v) else self.send(k,v) end } end #def create_self(keys) # if keys and keys != None # tk_call_without_enc('toplevel', @path, *hash_kv(keys, true)) # else # tk_call_without_enc('toplevel', @path) # end #end #private :create_self def specific_class @classname end def add_menu(menu_info, tearoff=false, opts=nil) # See tk/menuspec.rb for menu_info. # opts is a hash of default configs for all of cascade menus. # Configs of menu_info can override it. if tearoff.kind_of?(Hash) opts = tearoff tearoff = false end _create_menubutton(self, menu_info, tearoff, opts) end def add_menubar(menu_spec, tearoff=false, opts=nil) # See tk/menuspec.rb for menu_spec. # opts is a hash of default configs for all of cascade menus. # Configs of menu_spec can override it. menu_spec.each{|info| add_menu(info, tearoff, opts)} self.menu end def self.database_class if self == WidgetClassNames[WidgetClassName] || self.name == '' self else TkDatabaseClass.new(self.name) end end def self.database_classname self.database_class.name end def self.bind(*args, &b) if self == WidgetClassNames[WidgetClassName] || self.name == '' super(*args, &b) else TkDatabaseClass.new(self.name).bind(*args, &b) end end def self.bind_append(*args, &b) if self == WidgetClassNames[WidgetClassName] || self.name == '' super(*args, &b) else TkDatabaseClass.new(self.name).bind_append(*args, &b) end end def self.bind_remove(*args) if self == WidgetClassNames[WidgetClassName] || self.name == '' super(*args) else TkDatabaseClass.new(self.name).bind_remove(*args) end end def self.bindinfo(*args) if self == WidgetClassNames[WidgetClassName] || self.name == '' super(*args) else TkDatabaseClass.new(self.name).bindinfo(*args) end end end #TkToplevel = Tk::Toplevel unless Object.const_defined? :TkToplevel Tk.__set_toplevel_aliases__(:Tk, Tk::Toplevel, :TkToplevel) ================================================ FILE: ext/tk/lib/tk/ttk_selector.rb ================================================ # # ttk_selector # ###################################### # toplevel classes/modules module Tk @TOPLEVEL_ALIAS_TABLE[:Ttk] = { :TkButton => 'tkextlib/tile/tbutton', :TkCheckbutton => 'tkextlib/tile/tcheckbutton', :TkCheckButton => 'tkextlib/tile/tcheckbutton', # :TkDialog => 'tkextlib/tile/dialog', :TkEntry => 'tkextlib/tile/tentry', :TkCombobox => 'tkextlib/tile/tcombobox', :TkFrame => 'tkextlib/tile/tframe', :TkLabel => 'tkextlib/tile/tlabel', :TkLabelframe => 'tkextlib/tile/tlabelframe', :TkLabelFrame => 'tkextlib/tile/tlabelframe', :TkMenubutton => 'tkextlib/tile/tmenubutton', :TkMenuButton => 'tkextlib/tile/tmenubutton', :TkNotebook => 'tkextlib/tile/tnotebook', # :TkPaned => 'tkextlib/tile/tpaned', :TkPanedwindow => 'tkextlib/tile/tpaned', :TkPanedWindow => 'tkextlib/tile/tpaned', :TkProgressbar => 'tkextlib/tile/tprogressbar', :TkRadiobutton => 'tkextlib/tile/tradiobutton', :TkRadioButton => 'tkextlib/tile/tradiobutton', :TkScale => 'tkextlib/tile/tscale', # :TkProgress => 'tkextlib/tile/tscale', :TkScrollbar => 'tkextlib/tile/tscrollbar', :TkXScrollbar => 'tkextlib/tile/tscrollbar', :TkYScrollbar => 'tkextlib/tile/tscrollbar', :TkSeparator => 'tkextlib/tile/tseparator', :TkSizeGrip => 'tkextlib/tile/sizegrip', :TkSizegrip => 'tkextlib/tile/sizegrip', # :TkSquare => 'tkextlib/tile/tsquare', :TkTreeview => 'tkextlib/tile/treeview', } @TOPLEVEL_ALIAS_TABLE[:Tile] = @TOPLEVEL_ALIAS_TABLE[:Ttk] ################################################ # register some Ttk widgets as default # (Ttk is a standard library on Tcl/Tk8.5+) @TOPLEVEL_ALIAS_TABLE[:Ttk].each{|sym, file| unless Object.autoload?(sym) || Object.const_defined?(sym) Object.autoload(sym, file) end } ################################################ @TOPLEVEL_ALIAS_SETUP_PROC[:Tile] = @TOPLEVEL_ALIAS_SETUP_PROC[:Ttk] = proc{|mod| unless Tk.autoload?(:Tile) || Tk.const_defined?(:Tile) Object.autoload :Ttk, 'tkextlib/tile' Tk.autoload :Tile, 'tkextlib/tile' end } end ================================================ FILE: ext/tk/lib/tk/txtwin_abst.rb ================================================ # # tk/txtwin_abst.rb : TkTextWin abstruct class # require 'tk' class TkTextWinvalue)) end self end =begin def configure(slot, value=TkComm::None) key2class = __get_validate_key2class if slot.kind_of?(Hash) slot = _symbolkey2str(slot) key2class.each{|key, klass| if slot[key].kind_of?(Array) cmd, *args = slot[key] slot[key] = klass.new(cmd, args.join(' ')) elsif slot[key].kind_of?(Proc) || slot[key].kind_of?(Method) slot[key] = klass.new(slot[key]) end } super(slot) else slot = slot.to_s if (klass = key2class[slot]) if value.kind_of?(Array) cmd, *args = value value = klass.new(cmd, args.join(' ')) elsif value.kind_of?(Proc) || value.kind_of?(Method) value = klass.new(value) end end super(slot, value) end self end =end end module ItemValidateConfigure def self.__def_validcmd(scope, klass, keys=nil) keys = klass._config_keys unless keys keys.each{|key| eval("def item_#{key}(id, *args, &b) __item_validcmd_call(#{klass.name}, '#{key}', id, *args, &b) end", scope) } end def __item_validcmd_call(tagOrId, klass, key, *args, &b) return itemcget(tagid(tagOrId), key) if args.empty? && !b cmd = (b)? proc(&b) : args.shift if cmd.kind_of?(klass) itemconfigure(tagid(tagOrId), key, cmd) elsif !args.empty? itemconfigure(tagid(tagOrId), key, [cmd, args]) else itemconfigure(tagid(tagOrId), key, cmd) end end def __item_validation_class_list(id) # maybe need to override [] end def __get_item_validate_key2class(id) k2c = {} __item_validation_class_list(id).each{|klass| klass._config_keys.each{|key| k2c[key.to_s] = klass } } end def __conv_item_vcmd_on_hash_kv(keys) key2class = __get_item_validate_key2class(tagid(tagOrId)) keys = _symbolkey2str(keys) key2class.each{|key, klass| if keys[key].kind_of?(Array) cmd, *args = keys[key] #keys[key] = klass.new(cmd, args.join(' ')) keys[key] = klass.new(cmd, *args) # elsif keys[key].kind_of?(Proc) || keys[key].kind_of?(Method) elsif TkComm._callback_entry?(keys[key]) keys[key] = klass.new(keys[key]) end } keys end def itemconfigure(tagOrId, slot, value=TkComm::None) if slot.kind_of?(Hash) super(__conv_item_vcmd_on_hash_kv(slot)) else super(__conv_item_vcmd_on_hash_kv(slot=>value)) end self end =begin def itemconfigure(tagOrId, slot, value=TkComm::None) key2class = __get_item_validate_key2class(tagid(tagOrId)) if slot.kind_of?(Hash) slot = _symbolkey2str(slot) key2class.each{|key, klass| if slot[key].kind_of?(Array) cmd, *args = slot[key] slot[key] = klass.new(cmd, args.join(' ')) elsif slot[key].kind_of?(Proc) || slot[key].kind_of?(Method) slot[key] = klass.new(slot[key]) end } super(slot) else slot = slot.to_s if (klass = key2class[slot]) if value.kind_of?(Array) cmd, *args = value value = klass.new(cmd, args.join(' ')) elsif value.kind_of?(Proc) || value.kind_of?(Method) value = klass.new(value) end end super(slot, value) end self end =end end end class TkValidateCommand include TkComm extend TkComm class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [ ?d, ?n, :action ], [ ?i, ?x, :index ], [ ?s, ?e, :current ], [ ?v, ?s, :type ], [ ?P, ?e, :value ], [ ?S, ?e, :string ], [ ?V, ?s, :triggered ], [ ?W, ?w, :widget ], nil ] PROC_TBL = [ [ ?n, TkComm.method(:number) ], [ ?s, TkComm.method(:string) ], [ ?w, TkComm.method(:window) ], [ ?e, proc{|val| #enc = Tk.encoding enc = ((Tk.encoding)? Tk.encoding : Tk.encoding_system) if enc Tk.fromUTF8(TkComm::string(val), enc) else TkComm::string(val) end } ], [ ?x, proc{|val| idx = TkComm::number(val) if idx < 0 nil else idx end } ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end _setup_subst_table(KEY_TBL, PROC_TBL); # # NOTE: The order of parameters which passed to callback procedure is # , , ... , , , ... # #def self._get_extra_args_tbl # # return an array of convert procs # [] #end def self.ret_val(val) (val)? '1': '0' end end ############################################### def self._config_keys # array of config-option key (string or symbol) ['vcmd', 'validatecommand', 'invcmd', 'invalidcommand'] end def _initialize_for_cb_class(klass, cmd = Proc.new, *args) extra_args_tbl = klass._get_extra_args_tbl if args.compact.size > 0 args.map!{|arg| klass._sym2subst(arg)} args = args.join(' ') keys = klass._get_subst_key(args) if cmd.kind_of?(String) id = cmd elsif cmd.kind_of?(TkCallbackEntry) @id = install_cmd(cmd) else @id = install_cmd(proc{|*arg| ex_args = [] extra_args_tbl.reverse_each{|conv| ex_args << conv.call(arg.pop)} klass.ret_val(cmd.call( *(ex_args.concat(klass.scan_args(keys, arg))) )) }) + ' ' + args end else keys, args = klass._get_all_subst_keys if cmd.kind_of?(String) id = cmd elsif cmd.kind_of?(TkCallbackEntry) @id = install_cmd(cmd) else @id = install_cmd(proc{|*arg| ex_args = [] extra_args_tbl.reverse_each{|conv| ex_args << conv.call(arg.pop)} klass.ret_val(cmd.call( *(ex_args << klass.new(*klass.scan_args(keys, arg))) )) }) + ' ' + args end end end def initialize(cmd = Proc.new, *args) _initialize_for_cb_class(self.class::ValidateArgs, cmd, *args) end def to_eval @id end end module TkValidation include Tk::ValidateConfigure class ValidateCmd < TkValidateCommand module Action Insert = 1 Delete = 0 Others = -1 Focus = -1 Forced = -1 Textvariable = -1 TextVariable = -1 end end ##################################### def __validation_class_list super() << ValidateCmd end Tk::ValidateConfigure.__def_validcmd(binding, ValidateCmd) =begin def validatecommand(cmd = Proc.new, args = nil) if cmd.kind_of?(ValidateCmd) configure('validatecommand', cmd) elsif args configure('validatecommand', [cmd, args]) else configure('validatecommand', cmd) end end =end # def validatecommand(*args, &b) # __validcmd_call(ValidateCmd, 'validatecommand', *args, &b) # end # alias vcmd validatecommand =begin def invalidcommand(cmd = Proc.new, args = nil) if cmd.kind_of?(ValidateCmd) configure('invalidcommand', cmd) elsif args configure('invalidcommand', [cmd, args]) else configure('invalidcommand', cmd) end end =end # def invalidcommand(*args, &b) # __validcmd_call(ValidateCmd, 'invalidcommand', *args, &b) # end # alias invcmd invalidcommand end ================================================ FILE: ext/tk/lib/tk/variable.rb ================================================ # # tk/variable.rb : treat Tk variable object # require 'tk' class TkVariable include Tk extend TkCore include Comparable #TkCommandNames = ['tkwait'.freeze].freeze TkCommandNames = ['vwait'.freeze].freeze #TkVar_CB_TBL = {} #TkVar_ID_TBL = {} TkVar_CB_TBL = TkCore::INTERP.create_table TkVar_ID_TBL = TkCore::INTERP.create_table (Tk_VARIABLE_ID = ["v".freeze, "00000".taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } TkCore::INTERP.init_ip_env{ TkVar_CB_TBL.mutex.synchronize{ TkVar_CB_TBL.clear } TkVar_ID_TBL.mutex.synchronize{ TkVar_ID_TBL.clear } } major, minor, type, type_name, patchlevel = TclTkLib.get_version USE_OLD_TRACE_OPTION_STYLE = (major < 8) || (major == 8 && minor < 4) #TkCore::INTERP.add_tk_procs('rb_var', 'args', # "ruby [format \"TkVariable.callback %%Q!%s!\" $args]") TkCore::INTERP.add_tk_procs('rb_var', 'args', <<-'EOL') if {[set st [catch {eval {ruby_cmd TkVariable callback} $args} ret]] != 0} { set idx [string first "\n\n" $ret] if {$idx > 0} { global errorInfo set tcl_backtrace $errorInfo set errorInfo [string range $ret [expr $idx + 2] \ [string length $ret]] append errorInfo "\n" $tcl_backtrace bgerror [string range $ret 0 [expr $idx - 1]] } else { bgerror $ret } return "" #return -code $st $ret } else { return $ret } EOL #def TkVariable.callback(args) def TkVariable.callback(id, name1, name2, op) #name1,name2,op = tk_split_list(args) #name1,name2,op = tk_split_simplelist(args) if cb_obj = TkVar_CB_TBL[id] #_get_eval_string(TkVar_CB_TBL[name1].trace_callback(name2,op)) begin _get_eval_string(cb_obj.trace_callback(name2, op)) rescue SystemExit exit(0) rescue Interrupt exit!(1) rescue Exception => e begin msg = _toUTF8(e.class.inspect) + ': ' + _toUTF8(e.message) + "\n" + "\n---< backtrace of Ruby side >-----\n" + _toUTF8(e.backtrace.join("\n")) + "\n---< backtrace of Tk side >-------" if TkCore::WITH_ENCODING msg.force_encoding('utf-8') else msg.instance_variable_set(:@encoding, 'utf-8') end rescue Exception msg = e.class.inspect + ': ' + e.message + "\n" + "\n---< backtrace of Ruby side >-----\n" + e.backtrace.join("\n") + "\n---< backtrace of Tk side >-------" end fail(e, msg) end =begin begin raise 'check backtrace' rescue # ignore backtrace before 'callback' pos = -($!.backtrace.size) end begin _get_eval_string(TkVar_CB_TBL[name1].trace_callback(name2,op)) rescue trace = $!.backtrace raise $!, "\n#{trace[0]}: #{$!.message} (#{$!.class})\n" + "\tfrom #{trace[1..pos].join("\n\tfrom ")}" end =end else '' end end def self.new_hash(val = {}) if val.kind_of?(Hash) self.new(val) else fail ArgumentError, 'Hash is expected' end end # # default_value is available only when the variable is an assoc array. # def default_value(val=nil, &b) if b @def_default = :proc @default_val = proc(&b) else @def_default = :val @default_val = val end self end def set_default_value(val) @def_default = :val @default_val = val self end alias default_value= set_default_value def default_proc(cmd = Proc.new) @def_default = :proc @default_val = cmd self end def undef_default @default_val = nil @def_default = false self end def default_value_type @type end def default_element_value_type(idxs) if idxs.kind_of?(Array) index = idxs.collect{|idx| _get_eval_string(idx, true)}.join(',') else index = _get_eval_string(idxs, true) end @element_type[index] end def _set_default_value_type_core(type, idxs) if type.kind_of?(Class) if type == NilClass type = nil elsif type == Numeric type = :numeric elsif type == TrueClass || type == FalseClass type = :bool elsif type == String type = :string elsif type == Symbol type = :symbol elsif type == Array type = :list elsif type <= TkVariable type = :variable elsif type <= TkWindow type = :window elsif TkComm._callback_entry_class?(type) type = :procedure else type = nil end else case(type) when nil type = nil when :numeric, 'numeric' type = :numeric when true, false, :bool, 'bool' type = :bool when :string, 'string' type = :string when :symbol, 'symbol' type = :symbol when :list, 'list' type = :list when :numlist, 'numlist' type = :numlist when :variable, 'variable' type = :variable when :window, 'window' type = :window when :procedure, 'procedure' type = :procedure else return _set_default_value_type_core(type.class, idxs) end end if idxs if idxs.kind_of?(Array) index = idxs.collect{|idx| _get_eval_string(idx, true)}.join(',') else index = _get_eval_string(idxs, true) end @element_type[index] = type else @type = type end type end private :_set_default_value_type_core def set_default_value_type(type) _set_default_value_type_core(type, nil) self end alias default_value_type= set_default_value_type def set_default_element_value_type(idxs, type) _set_default_value_type_core(type, idxs) self end def _to_default_type(val, idxs = nil) if idxs if idxs.kind_of?(Array) index = idxs.collect{|idx| _get_eval_string(idx, true)}.join(',') else index = _get_eval_string(idxs, true) end type = @element_type[index] else type = @type end return val unless type if val.kind_of?(Hash) val.keys.each{|k| val[k] = _to_default_type(val[k], idxs) } val else begin case(type) when :numeric number(val) when :bool TkComm.bool(val) when :string val when :symbol val.intern when :list tk_split_simplelist(val) when :numlist tk_split_simplelist(val).collect!{|v| number(v)} when :variable TkVarAccess.new(val) when :window TkComm.window(val) when :procedure TkComm.procedure(val) else val end rescue val end end end private :_to_default_type def _to_default_element_type(idxs, val) _to_default_type(val, idxs) end private :_to_default_element_type def initialize(val="", type=nil) # @id = Tk_VARIABLE_ID.join('') begin Tk_VARIABLE_ID.mutex.synchronize{ @id = Tk_VARIABLE_ID.join(TkCore::INTERP._ip_id_) Tk_VARIABLE_ID[1].succ! } end until INTERP._invoke_without_enc('info', 'globals', @id).empty? TkVar_ID_TBL.mutex.synchronize{ TkVar_ID_TBL[@id] = self } @var = @id @elem = nil @def_default = false @default_val = nil @trace_var = nil @trace_elem = nil @trace_opts = nil @type = nil var = self @element_type = Hash.new{|k,v| var.default_value_type } self.default_value_type = type # teach Tk-ip that @id is global var INTERP._invoke_without_enc('global', @id) #INTERP._invoke('global', @id) # create and init if val.kind_of?(Hash) # assoc-array variable self[''] = 0 self.clear end self.value = val =begin if val == [] # INTERP._eval(format('global %s; set %s(0) 0; unset %s(0)', # @id, @id, @id)) elsif val.kind_of?(Array) a = [] # val.each_with_index{|e,i| a.push(i); a.push(array2tk_list(e))} # s = '"' + a.join(" ").gsub(/[\[\]$"]/, '\\\\\&') + '"' val.each_with_index{|e,i| a.push(i); a.push(e)} #s = '"' + array2tk_list(a).gsub(/[\[\]$"]/, '\\\\\&') + '"' s = '"' + array2tk_list(a).gsub(/[\[\]$"\\]/, '\\\\\&') + '"' INTERP._eval(format('global %s; array set %s %s', @id, @id, s)) elsif val.kind_of?(Hash) #s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\ # .gsub(/[\[\]$"]/, '\\\\\&') + '"' s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\ .gsub(/[\[\]$"\\]/, '\\\\\&') + '"' INTERP._eval(format('global %s; array set %s %s', @id, @id, s)) else #s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"' s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"' INTERP._eval(format('global %s; set %s %s', @id, @id, s)) end =end =begin if val.kind_of?(Hash) #s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\ # .gsub(/[\[\]$"]/, '\\\\\&') + '"' s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\ .gsub(/[\[\]$"\\]/, '\\\\\&') + '"' INTERP._eval(Kernel.format('global %s; array set %s %s', @id, @id, s)) else #s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"' s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"' INTERP._eval(Kernel.format('global %s; set %s %s', @id, @id, s)) end =end end def wait(on_thread = false, check_root = false) if $SAFE >= 4 fail SecurityError, "can't wait variable at $SAFE >= 4" end on_thread &= (Thread.list.size != 1) if on_thread if check_root INTERP._thread_tkwait('variable', @id) else INTERP._thread_vwait(@id) end else if check_root INTERP._invoke_without_enc('tkwait', 'variable', @id) else INTERP._invoke_without_enc('vwait', @id) end end end def eventloop_wait(check_root = false) wait(false, check_root) end def thread_wait(check_root = false) wait(true, check_root) end def tkwait(on_thread = true) wait(on_thread, true) end def eventloop_tkwait wait(false, true) end def thread_tkwait wait(true, true) end def id @id end def ref(*idxs) # "#{@id}(#{idxs.collect{|idx| _get_eval_string(idx)}.join(',')})" TkVarAccess.new("#{@id}(#{idxs.collect{|idx| _get_eval_string(idx)}.join(',')})") end def is_hash? #ITNERP._eval("global #{@id}; array exist #{@id}") == '1' INTERP._invoke_without_enc('global', @id) # INTERP._invoke_without_enc('array', 'exist', @id) == '1' TkComm.bool(INTERP._invoke_without_enc('array', 'exist', @id)) end def is_scalar? ! is_hash? end def exist?(*elems) INTERP._invoke_without_enc('global', @id) if elems.empty? TkComm.bool(tk_call('info', 'exist', @id)) else # array index = elems.collect{|idx| _get_eval_string(idx, true)}.join(',') TkComm.bool(tk_call('info', 'exist', "#{@id}")) && TkComm.bool(tk_call('info', 'exist', "#{@id}(#{index})")) end end def keys if (is_scalar?) fail RuntimeError, 'cannot get keys from a scalar variable' end #tk_split_simplelist(INTERP._eval("global #{@id}; array get #{@id}")) INTERP._invoke_without_enc('global', @id) #tk_split_simplelist(INTERP._fromUTF8(INTERP._invoke_without_enc('array', 'names', @id))) tk_split_simplelist(INTERP._invoke_without_enc('array', 'names', @id), false, true) end def size INTERP._invoke_without_enc('global', @id) TkComm.number(INTERP._invoke_without_enc('array', 'size', @id)) end def clear if (is_scalar?) fail RuntimeError, 'cannot clear a scalar variable' end keys.each{|k| unset(k)} self end def update(hash) if (is_scalar?) fail RuntimeError, 'cannot update a scalar variable' end hash.each{|k,v| self[k] = v} self end unless const_defined?(:USE_TCLs_SET_VARIABLE_FUNCTIONS) USE_TCLs_SET_VARIABLE_FUNCTIONS = true end if USE_TCLs_SET_VARIABLE_FUNCTIONS ########################################################################### # use Tcl function version of set tkvariable ########################################################################### def _value #if INTERP._eval("global #{@id}; array exist #{@id}") == '1' INTERP._invoke_without_enc('global', @id) # if INTERP._invoke('array', 'exist', @id) == '1' if TkComm.bool(INTERP._invoke('array', 'exist', @id)) #Hash[*tk_split_simplelist(INTERP._eval("global #{@id}; array get #{@id}"))] Hash[*tk_split_simplelist(INTERP._invoke('array', 'get', @id))] else _fromUTF8(INTERP._get_global_var(@id)) end end def value=(val) val = val._value if !@type && @type != :variable && val.kind_of?(TkVariable) if val.kind_of?(Hash) self.clear val.each{|k, v| #INTERP._set_global_var2(@id, _toUTF8(_get_eval_string(k)), # _toUTF8(_get_eval_string(v))) INTERP._set_global_var2(@id, _get_eval_string(k, true), _get_eval_string(v, true)) } self.value # elsif val.kind_of?(Array) =begin INTERP._set_global_var(@id, '') val.each{|v| #INTERP._set_variable(@id, _toUTF8(_get_eval_string(v)), INTERP._set_variable(@id, _get_eval_string(v, true), TclTkLib::VarAccessFlag::GLOBAL_ONLY | TclTkLib::VarAccessFlag::LEAVE_ERR_MSG | TclTkLib::VarAccessFlag::APPEND_VALUE | TclTkLib::VarAccessFlag::LIST_ELEMENT) } self.value =end # _fromUTF8(INTERP._set_global_var(@id, array2tk_list(val, true))) else #_fromUTF8(INTERP._set_global_var(@id, _toUTF8(_get_eval_string(val)))) _fromUTF8(INTERP._set_global_var(@id, _get_eval_string(val, true))) end end def _element_value(*idxs) index = idxs.collect{|idx| _get_eval_string(idx, true)}.join(',') begin _fromUTF8(INTERP._get_global_var2(@id, index)) rescue => e case @def_default when :proc @default_val.call(self, *idxs) when :val @default_val else fail e end end #_fromUTF8(INTERP._get_global_var2(@id, index)) #_fromUTF8(INTERP._get_global_var2(@id, _toUTF8(_get_eval_string(index)))) #_fromUTF8(INTERP._get_global_var2(@id, _get_eval_string(index, true))) end def []=(*args) val = args.pop type = default_element_value_type(args) val = val._value if !type && type != :variable && val.kind_of?(TkVariable) index = args.collect{|idx| _get_eval_string(idx, true)}.join(',') _fromUTF8(INTERP._set_global_var2(@id, index, _get_eval_string(val, true))) #_fromUTF8(INTERP._set_global_var2(@id, _toUTF8(_get_eval_string(index)), # _toUTF8(_get_eval_string(val)))) #_fromUTF8(INTERP._set_global_var2(@id, _get_eval_string(index, true), # _get_eval_string(val, true))) end def unset(*elems) if elems.empty? INTERP._unset_global_var(@id) else index = elems.collect{|idx| _get_eval_string(idx, true)}.join(',') INTERP._unset_global_var2(@id, index) end end alias remove unset else ########################################################################### # use Ruby script version of set tkvariable (traditional methods) ########################################################################### def _value begin INTERP._eval(Kernel.format('global %s; set %s', @id, @id)) #INTERP._eval(Kernel.format('set %s', @id)) #INTERP._invoke_without_enc('set', @id) rescue if INTERP._eval(Kernel.format('global %s; array exists %s', @id, @id)) != "1" #if INTERP._eval(Kernel.format('array exists %s', @id)) != "1" #if INTERP._invoke_without_enc('array', 'exists', @id) != "1" fail else Hash[*tk_split_simplelist(INTERP._eval(Kernel.format('global %s; array get %s', @id, @id)))] #Hash[*tk_split_simplelist(_fromUTF8(INTERP._invoke_without_enc('array', 'get', @id)))] end end end def value=(val) val = val._value if !@type && @type != :variable && val.kind_of?(TkVariable) begin #s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"' s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"' INTERP._eval(Kernel.format('global %s; set %s %s', @id, @id, s)) #INTERP._eval(Kernel.format('set %s %s', @id, s)) #_fromUTF8(INTERP._invoke_without_enc('set', @id, _toUTF8(s))) rescue if INTERP._eval(Kernel.format('global %s; array exists %s', @id, @id)) != "1" #if INTERP._eval(Kernel.format('array exists %s', @id)) != "1" #if INTERP._invoke_without_enc('array', 'exists', @id) != "1" fail else if val == [] INTERP._eval(Kernel.format('global %s; unset %s; set %s(0) 0; unset %s(0)', @id, @id, @id, @id)) #INTERP._eval(Kernel.format('unset %s; set %s(0) 0; unset %s(0)', # @id, @id, @id)) #INTERP._invoke_without_enc('unset', @id) #INTERP._invoke_without_enc('set', @id+'(0)', 0) #INTERP._invoke_without_enc('unset', @id+'(0)') elsif val.kind_of?(Array) a = [] val.each_with_index{|e,i| a.push(i); a.push(array2tk_list(e, true))} #s = '"' + a.join(" ").gsub(/[\[\]$"]/, '\\\\\&') + '"' s = '"' + a.join(" ").gsub(/[\[\]$"\\]/, '\\\\\&') + '"' INTERP._eval(Kernel.format('global %s; unset %s; array set %s %s', @id, @id, @id, s)) #INTERP._eval(Kernel.format('unset %s; array set %s %s', # @id, @id, s)) #INTERP._invoke_without_enc('unset', @id) #_fromUTF8(INTERP._invoke_without_enc('array','set', @id, _toUTF8(s))) elsif val.kind_of?(Hash) #s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\ # .gsub(/[\[\]$"]/, '\\\\\&') + '"' s = '"' + val.to_a.collect{|e| array2tk_list(e, true)}.join(" ")\ .gsub(/[\[\]$\\"]/, '\\\\\&') + '"' INTERP._eval(Kernel.format('global %s; unset %s; array set %s %s', @id, @id, @id, s)) #INTERP._eval(Kernel.format('unset %s; array set %s %s', # @id, @id, s)) #INTERP._invoke_without_enc('unset', @id) #_fromUTF8(INTERP._invoke_without_enc('array','set', @id, _toUTF8(s))) else fail end end end end def _element_value(*idxs) index = idxs.collect{|idx| _get_eval_string(idx)}.join(',') begin INTERP._eval(Kernel.format('global %s; set %s(%s)', @id, @id, index)) rescue => e case @def_default when :proc @default_val.call(self, *idxs) when :val @default_val else fail e end end #INTERP._eval(Kernel.format('global %s; set %s(%s)', @id, @id, index)) #INTERP._eval(Kernel.format('global %s; set %s(%s)', # @id, @id, _get_eval_string(index))) #INTERP._eval(Kernel.format('set %s(%s)', @id, _get_eval_string(index))) #INTERP._eval('set ' + @id + '(' + _get_eval_string(index) + ')') end def []=(*args) val = args.pop type = default_element_value_type(args) val = val._value if !type && type != :variable && val.kind_of?(TkVariable) index = args.collect{|idx| _get_eval_string(idx)}.join(',') INTERP._eval(Kernel.format('global %s; set %s(%s) %s', @id, @id, index, _get_eval_string(val))) #INTERP._eval(Kernel.format('global %s; set %s(%s) %s', @id, @id, # _get_eval_string(index), _get_eval_string(val))) #INTERP._eval(Kernel.format('set %s(%s) %s', @id, # _get_eval_string(index), _get_eval_string(val))) #INTERP._eval('set ' + @id + '(' + _get_eval_string(index) + ') ' + # _get_eval_string(val)) end def unset(*elems) if elems.empty? INTERP._eval(Kernel.format('global %s; unset %s', @id, @id)) #INTERP._eval(Kernel.format('unset %s', @id)) #INTERP._eval('unset ' + @id) else index = elems.collect{|idx| _get_eval_string(idx, true)}.join(',') INTERP._eval(Kernel.format('global %s; unset %s(%s)', @id, @id, index)) #INTERP._eval(Kernel.format('global %s; unset %s(%s)', # @id, @id, _get_eval_string(elem))) #INTERP._eval(Kernel.format('unset %s(%s)', @id, tk_tcl2ruby(elem))) #INTERP._eval('unset ' + @id + '(' + _get_eval_string(elem) + ')') end end alias remove unset end protected :_value, :_element_value def value _to_default_type(_value) end def [](*idxs) _to_default_element_type(idxs, _element_value(*idxs)) end def set_value(val) self.value = val self end def set_element_value(idxs, val) if idxs.kind_of?(Array) self[*idxs]=val else self[idxs]=val end self end def set_value_type(val) self.default_value_type = val.class self.value = val self end alias value_type= set_value_type def set_element_value_type(idxs, val) self.set_default_element_value_type(idxs, val.class) if idxs.kind_of?(Array) self[*idxs]=val else self[idxs]=val end self end def numeric number(_value) end def numeric_element(*idxs) number(_element_value(*idxs)) end def set_numeric(val) case val when Numeric self.value=(val) when TkVariable self.value=(val.numeric) else raise ArgumentError, "Numeric is expected" end self end alias numeric= set_numeric def set_numeric_element(idxs, val) case val when Numeric val when TkVariable val = val.numeric else raise ArgumentError, "Numeric is expected" end if idxs.kind_of?(Array) self[*idxs]=val else self[idxs]=val end self end def set_numeric_type(val) @type = :numeric self.numeric=(val) self end alias numeric_type= set_numeric_type def set_numeric_element_type(idxs, val) self.set_default_element_value_type(idxs, :numeric) self.set_numeric_element(idxs, val) end def bool TkComm.bool(_value) =begin # see Tcl_GetBoolean man-page case _value.downcase when '0', 'false', 'no', 'off' false else true end =end end def bool_element(*idxs) TkComm.bool(_element_value(*idxs)) end def set_bool(val) if ! val self.value = '0' else case val.to_s.downcase when 'false', '0', 'no', 'off' self.value = '0' else self.value = '1' end end self end alias bool= set_bool def set_bool_element(idxs, val) if ! val val = '0' else case val.to_s.downcase when 'false', '0', 'no', 'off' val = '0' else val = '1' end end if idxs.kind_of?(Array) self[*idxs]=val else self[idxs]=val end self end def set_bool_type(val) @type = :bool self.bool=(val) self end alias bool_type= set_bool_type def set_bool_element_type(idxs, val) self.set_default_element_value_type(idxs, :bool) self.set_bool_element(idxs, val) end def variable # keeps a Tcl's variable name TkVarAccess.new(self._value) end def variable_element(*idxs) TkVarAccess.new(_element_value(*idxs)) end def set_variable(var) var = var.id if var.kind_of?(TkVariable) self.value = var self end alias variable= set_variable def set_variable_element(idxs, var) var = var.id if var.kind_of?(TkVariable) if idxs.kind_of?(Array) self[*idxs]=var else self[idxs]=var end self end def set_variable_type(var) @type = :variable var = var.id if var.kind_of?(TkVariable) self.value = var self end alias variable_type= set_variable_type def set_variable_element_type(idxs, var) self.set_default_element_value_type(idxs, :variable) self.set_variable_element(idxs, var) end def window TkComm.window(self._value) end def window_element(*idxs) TkComm.window(_element_value(*idxs)) end def set_window(win) win = win._value if win.kind_of?(TkVariable) self.value = win self end alias window= set_window def set_window_element(idxs, win) win = win._value if win.kind_of?(TkVariable) if idxs.kind_of?(Array) self[*idxs]=win else self[idxs]=win end self end def set_window_type(win) @type = :window self.window=(win) self end alias window_type= set_window_type def set_window_element_type(idxs, win) self.set_default_element_value_type(idxs, :window) self.set_window_element(idxs, win) end def procedure TkComm.procedure(self._value) end def procedure_element(*idxs) TkComm.procedure(_element_value(*idxs)) end def set_procedure(cmd) self.value = cmd self end alias procedure= set_procedure def set_procedure_element(idxs, cmd) cmd = cmd._value if cmd.kind_of?(TkVariable) if idxs.kind_of?(Array) self[*idxs]=cmd else self[idxs]=cmd end self end def set_procedure_type(cmd) @type = :procedure self.procedure=(cmd) self end alias procedure_type= set_procedure_type def set_procedure_element_type(idxs, cmd) self.set_default_element_value_type(idxs, :procedure) self.set_proceure_element(idxs, cmd) end def to_i number(_value).to_i end def element_to_i(*idxs) number(_element_value(*idxs)).to_i end def to_f number(_value).to_f end def element_to_f(*idxs) number(_element_value(*idxs)).to_f end def to_s #string(value).to_s _value end alias string to_s def element_to_s(*idxs) _element_value(*idxs) end def string_element(*idxs) _element_value(*idxs) end def set_string(val) val = val._value if val.kind_of?(TkVariable) self.value=val self end alias string= set_string def set_string_element(idxs, val) val = val._value if val.kind_of?(TkVariable) if idxs.kind_of?(Array) self[*idxs]=val else self[idxs]=val end self end def set_string_type(val) @type = :string self.string=(val) self end alias string_type= set_string_type def set_string_element_type(idxs, val) self.set_default_element_value_type(idxs, :string) self.set_string_element(idxs, val) end def to_sym _value.intern end alias symbol to_sym def element_to_sym(*idxs) _element_value(*idxs).intern end alias symbol_element element_to_sym def set_symbol(val) val = val._value if val.kind_of?(TkVariable) self.value=val self end alias symbol= set_symbol def set_symbol_element(idxs, val) val = val._value if val.kind_of?(TkVariable) if idxs.kind_of?(Array) self[*idxs]=val else self[idxs]=val end self end def set_symbol_type(val) @type = :symbol self.value=(val) self end alias symbol_type= set_symbol_type def set_symbol_element_type(idxs, val) self.set_default_element_value_type(idxs, :symbol) self.set_symbol_element(idxs, val) end def list #tk_split_list(value) tk_split_simplelist(_value) end alias to_a list def list_element(*idxs) tk_split_simplelist(_element_value(*idxs)) end alias element_to_a list_element def numlist list.collect!{|val| number(val)} end def numlist_element(*idxs) list_element(*idxs).collect!{|val| number(val)} end def set_list(val) case val when Array self.value=(val) when TkVariable self.value=(val.list) else raise ArgumentError, "Array is expected" end self end alias list= set_list alias set_numlist set_list alias numlist= set_numlist def set_list_element(idxs, val) case val when Array val when TkVariable val = val.list else raise ArgumentError, "Array is expected" end if idxs.kind_of?(Array) self[*idxs]=val else self[idxs]=val end self end alias set_numlist_element set_list_element def set_list_type(val) @type = :list self.list=(val) self end alias list_type= set_list_type def set_list_element_type(idxs, val) self.set_default_element_value_type(idxs, :list) self.set_list_element(idxs, val) end def set_numlist_type(val) @type = :numlist self.numlist=(val) self end alias numlist_type= set_numlist_type def set_numlist_element_type(idxs, val) self.set_default_element_value_type(idxs, :numlist) self.set_numlist_element(idxs, val) end def lappend(*elems) tk_call('lappend', @id, *elems) self end def element_lappend(idxs, *elems) if idxs.kind_of?(Array) idxs = idxs.collect{|idx| _get_eval_string(idx, true)}.join(',') end tk_call('lappend', "#{@id}(#{idxs})", *elems) self end def lindex(idx) tk_call('lindex', self._value, idx) end alias lget lindex def element_lindex(elem_idxs, idx) if elem_idxs.kind_of?(Array) val = _element_value(*elem_idxs) else val = _element_value(elem_idxs) end tk_call('lindex', val, idx) end alias element_lget element_lindex def lget_i(idx) number(lget(idx)).to_i end def element_lget_i(elem_idxs, idx) number(element_lget(elem_idxs, idx)).to_i end def lget_f(idx) number(lget(idx)).to_f end def element_lget_f(elem_idxs, idx) number(element_lget(elem_idxs, idx)).to_f end def lset(idx, val) tk_call('lset', @id, idx, val) self end def element_lset(elem_idxs, idx, val) if elem_idxs.kind_of?(Array) idxs = elem_idxs.collect{|i| _get_eval_string(i, true)}.join(',') end tk_call('lset', "#{@id}(#{idxs})", idx, val) self end def inspect #Kernel.format "#", @id '#' end def coerce(other) case other when TkVariable [other._value, self._value] when String [other, self.to_s] when Symbol [other, self.to_sym] when Integer [other, self.to_i] when Float [other, self.to_f] when Array [other, self.to_a] else [other, self._value] end end def &(other) if other.kind_of?(Array) self.to_a & other.to_a else self.to_i & other.to_i end end def |(other) if other.kind_of?(Array) self.to_a | other.to_a else self.to_i | other.to_i end end def +(other) case other when Array self.to_a + other when String self._value + other else begin number(self._value) + other rescue self._value + other.to_s end end end def -(other) if other.kind_of?(Array) self.to_a - other else number(self._value) - other end end def *(other) num_or_str(self._value) * other.to_i #begin # number(self._value) * other #rescue # self._value * other #end end def /(other) number(self._value) / other end def %(other) num_or_str(self._value) % other.to_i #begin # number(self._value) % other #rescue # self._value % other #end end def **(other) number(self._value) ** other end def =~(other) self._value =~ other end def ==(other) case other when TkVariable #self.equal?(other) self._value == other._value when String self.to_s == other when Symbol self.to_sym == other when Integer self.to_i == other when Float self.to_f == other when Array self.to_a == other when Hash # false if self is not an assoc array self._value == other else # false self._value == _get_eval_string(other) end end def zero? numeric.zero? end def nonzero? !(numeric.zero?) end def <=>(other) if other.kind_of?(TkVariable) begin val = other.numeric other = val rescue other = other._value end elsif other.kind_of?(Numeric) begin return self.numeric <=> other rescue return self._value <=> other.to_s end elsif other.kind_of?(Array) return self.list <=> other else return self._value <=> other end end def to_eval @id end def trace_callback(elem, op) if @trace_var.kind_of? Array @trace_var.each{|m,e| e.call(self,elem,op) if m.index(op)} end if elem.kind_of?(String) && elem != '' if @trace_elem.kind_of?(Hash) && @trace_elem[elem].kind_of?(Array) @trace_elem[elem].each{|m,e| e.call(self,elem,op) if m.index(op)} end end end def _check_trace_opt(opts) if opts.kind_of?(Array) opt_str = opts.map{|s| s.to_s}.join(' ') else opt_str = opts.to_s end fail ArgumentError, 'null trace option' if opt_str.empty? if opt_str =~ /[^arwu\s]/ # new format (Tcl/Tk8.4+?) if opts.kind_of?(Array) opt_ary = opts.map{|opt| opt.to_s.strip} else opt_ary = opt_str.split(/\s+|\|/) opt_ary.delete('') end if USE_OLD_TRACE_OPTION_STYLE opt_ary.uniq.map{|opt| case opt when 'array' 'a' when 'read' 'r' when 'write' 'w' when 'unset' 'u' else fail ArgumentError, "unsupported trace option '#{opt}' on Tcl/Tk#{Tk::TCL_PATCHLEVEL}" end }.join else opt_ary end else # old format opt_ary = opt_str.delete('^arwu').split(//).uniq if USE_OLD_TRACE_OPTION_STYLE opt_ary.join else opt_ary.map{|c| case c when 'a' 'array' when 'r' 'read' when 'w' 'write' when 'u' 'unset' end } end end end private :_check_trace_opt def trace(opts, cmd = Proc.new) opts = _check_trace_opt(opts) (@trace_var ||= []).unshift([opts,cmd]) if @trace_opts == nil TkVar_CB_TBL[@id] = self @trace_opts = opts if USE_OLD_TRACE_OPTION_STYLE Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, 'rb_var ' << @id) else Tk.tk_call_without_enc('trace', 'add', 'variable', @id, @trace_opts, 'rb_var ' << @id) end else newopts = @trace_opts.dup if USE_OLD_TRACE_OPTION_STYLE opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} if newopts != @trace_opts Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts, 'rb_var ' << @id) @trace_opts.replace(newopts) Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, 'rb_var ' << @id) end else newopts |= opts unless (newopts - @trace_opts).empty? Tk.tk_call_without_enc('trace', 'remove', 'variable', @id, @trace_opts, 'rb_var ' << @id) @trace_opts.replace(newopts) Tk.tk_call_without_enc('trace', 'add', 'variable', @id, @trace_opts, 'rb_var ' << @id) end end end self end def trace_element(elem, opts, cmd = Proc.new) if @elem fail(RuntimeError, "invalid for a TkVariable which denotes an element of Tcl's array") end opts = _check_trace_opt(opts) ((@trace_elem ||= {})[elem] ||= []).unshift([opts,cmd]) if @trace_opts == nil TkVar_CB_TBL[@id] = self @trace_opts = opts if USE_OLD_TRACE_OPTION_STYLE Tk.tk_call_without_enc('trace', 'add', 'variable', @id, @trace_opts, 'rb_var ' << @id) else Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, 'rb_var ' << @id) end else newopts = @trace_opts.dup if USE_OLD_TRACE_OPTION_STYLE opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} if newopts != @trace_opts Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts, 'rb_var ' << @id) @trace_opts.replace(newopts) Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, 'rb_var ' << @id) end else newopts |= opts unless (newopts - @trace_opts).empty? Tk.tk_call_without_enc('trace', 'remove', 'variable', @id, @trace_opts, 'rb_var ' << @id) @trace_opts.replace(newopts) Tk.tk_call_without_enc('trace', 'add', 'variable', @id, @trace_opts, 'rb_var ' << @id) end end end self end def trace_info return [] unless @trace_var @trace_var.dup end alias trace_vinfo trace_info def trace_info_for_element(elem) if @elem fail(RuntimeError, "invalid for a TkVariable which denotes an element of Tcl's array") end return [] unless @trace_elem return [] unless @trace_elem[elem] @trace_elem[elem].dup end alias trace_vinfo_for_element trace_info_for_element def trace_remove(opts,cmd) return self unless @trace_var.kind_of? Array opts = _check_trace_opt(opts) idx = -1 if USE_OLD_TRACE_OPTION_STYLE newopts = '' @trace_var.each_with_index{|e, i| if idx < 0 && e[1] == cmd diff = false ['a', 'r', 'w', 'u'].each{|c| break if (diff = e[0].index(c) ^ opts.index(c)) } unless diff #find idx = i next end end e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} } else newopts = [] @trace_var.each_with_index{|e, i| if idx < 0 && e[1] == cmd && e[0].size == opts.size && (e[0] - opts).empty? # find idx = i next end newopts |= e[0] } end if idx >= 0 @trace_var.delete_at(idx) else return self end (@trace_elem ||= {}).each{|elem| @trace_elem[elem].each{|e| if USE_OLD_TRACE_OPTION_STYLE e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} else newopts |= e[0] end } } if USE_OLD_TRACE_OPTION_STYLE diff = false @trace_opts.each_byte{|c| break if (diff = ! newopts.index(c))} if diff Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts, 'rb_var ' << @id) @trace_opts.replace(newopts) unless @trace_opts.empty? Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, 'rb_var ' << @id) end end else unless (@trace_opts - newopts).empty? Tk.tk_call_without_enc('trace', 'remove', 'variable', @id, @trace_opts, 'rb_var ' << @id) @trace_opts.replace(newopts) unless @trace_opts.empty? Tk.tk_call_without_enc('trace', 'add', 'variable', @id, @trace_opts, 'rb_var ' << @id) end end end self end alias trace_delete trace_remove alias trace_vdelete trace_remove def trace_remove_for_element(elem,opts,cmd) if @elem fail(RuntimeError, "invalid for a TkVariable which denotes an element of Tcl's array") end return self unless @trace_elem.kind_of? Hash return self unless @trace_elem[elem].kind_of? Array opts = _check_trace_opt(opts) idx = -1 if USE_OLD_TRACE_OPTION_STYLE @trace_elem[elem].each_with_index{|e, i| if idx < 0 && e[1] == cmd diff = false ['a', 'r', 'w', 'u'].each{|c| break if (diff = e[0].index(c) ^ opts.index(c)) } unless diff #find idx = i next end end } else @trace_elem[elem].each_with_index{|e, i| if idx < 0 && e[1] == cmd && e[0].size == opts.size && (e[0] - opts).empty? # find idx = i next end } end if idx >= 0 @trace_elem[elem].delete_at(idx) else return self end if USE_OLD_TRACE_OPTION_STYLE newopts = '' @trace_var.each{|e| e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} } @trace_elem.each{|elem| @trace_elem[elem].each{|e| e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} } } else newopts = [] @trace_var.each{|e| newopts |= e[0] } @trace_elem.each{|elem| @trace_elem[elem].each{|e| e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} } } end if USE_OLD_TRACE_OPTION_STYLE diff = false @trace_opts.each_byte{|c| break if (diff = ! newopts.index(c))} if diff Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts, 'rb_var ' << @id) @trace_opts.replace(newopts) unless @trace_opts.empty? Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, 'rb_var ' << @id) end end else unless (@trace_opts - newopts).empty? Tk.tk_call_without_enc('trace', 'remove', 'variable', @id, @trace_opts, 'rb_var ' << @id) @trace_opts.replace(newopts) unless @trace_opts.empty? Tk.tk_call_without_enc('trace', 'add', 'variable', @id, @trace_opts, 'rb_var ' << @id) end end end self end alias trace_delete_for_element trace_remove_for_element alias trace_vdelete_for_element trace_remove_for_element end class TkVarAccess var == $1, elem == $2 @var = $1 @elem = $2 end # teach Tk-ip that @id is global var INTERP._invoke_without_enc('global', @var) =begin begin INTERP._invoke_without_enc('global', @id) rescue => e if @id =~ /^(.+)\([^()]+\)$/ # is an element --> varname == $1 INTERP._invoke_without_enc('global', $1) else fail e end end =end if val if val.kind_of?(Hash) # assoc-array variable self[''] = 0 self.clear end #s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"' #" #s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"' #" #INTERP._eval(Kernel.format('global %s; set %s %s', @id, @id, s)) #INTERP._set_global_var(@id, _toUTF8(_get_eval_string(val))) self.value = val end end end module Tk begin INTERP._invoke_without_enc('global', 'auto_path') auto_path = INTERP._invoke('set', 'auto_path') rescue => e begin INTERP._invoke_without_enc('global', 'env') auto_path = INTERP._invoke('set', 'env(TCLLIBPATH)') rescue => e auto_path = Tk::LIBRARY end end AUTO_PATH = TkVarAccess.new('auto_path', auto_path) =begin AUTO_OLDPATH = tk_split_simplelist(INTERP._invoke('set', 'auto_oldpath')) AUTO_OLDPATH.each{|s| s.freeze} AUTO_OLDPATH.freeze =end TCL_PACKAGE_PATH = TkVarAccess.new('tcl_pkgPath') PACKAGE_PATH = TCL_PACKAGE_PATH TCL_LIBRARY_PATH = TkVarAccess.new('tcl_libPath') LIBRARY_PATH = TCL_LIBRARY_PATH TCL_PRECISION = TkVarAccess.new('tcl_precision') end ================================================ FILE: ext/tk/lib/tk/virtevent.rb ================================================ # # tk/virtevent.rb : treats virtual events # 1998/07/16 by Hidetoshi Nagai # require 'tk' class TkVirtualEvent)>$/ event = $1 elsif event !~ /^<.*>$/ event = '<' + event + '>' end TkVirtualEvent::TkVirtualEventTBL.mutex.synchronize{ if TkVirtualEvent::TkVirtualEventTBL.has_key?(event) TkVirtualEvent::TkVirtualEventTBL[event] else # super(event, *sequences) (obj = self.allocate).instance_eval{ initialize(event, *sequences) TkVirtualEvent::TkVirtualEventTBL[@id] = self } end } end def initialize(event, *sequences) @path = @id = event _add_sequences(sequences) end end def TkVirtualEvent.getobj(event) obj = nil TkVirtualEventTBL.mutex.synchronize{ obj = TkVirtualEventTBL[event] } if obj obj else if tk_call_without_enc('event', 'info').index("<#{event}>") PreDefVirtEvent.new(event) else fail ArgumentError, "undefined virtual event '<#{event}>'" end end end def TkVirtualEvent.info tk_call_without_enc('event', 'info').split(/\s+/).collect!{|seq| TkVirtualEvent.getobj(seq[1..-2]) } end def initialize(*sequences) TkVirtualEventID.mutex.synchronize{ # @path = @id = '<' + TkVirtualEventID.join('') + '>' @path = @id = '<' + TkVirtualEventID.join(TkCore::INTERP._ip_id_) + '>' TkVirtualEventID[1].succ! } _add_sequences(sequences) end def _add_sequences(seq_ary) unless seq_ary.empty? tk_call_without_enc('event', 'add', "<#{@id}>", *(seq_ary.collect{|seq| "<#{tk_event_sequence(seq)}>" }) ) end self end private :_add_sequences def add(*sequences) if sequences != [] _add_sequences(sequences) TkVirtualEventTBL.mutex.synchronize{ TkVirtualEventTBL[@id] = self } end self end def delete(*sequences) if sequences == [] tk_call_without_enc('event', 'delete', "<#{@id}>") TkVirtualEventTBL.mutex.synchronize{ TkVirtualEventTBL.delete(@id) } else tk_call_without_enc('event', 'delete', "<#{@id}>", *(sequences.collect{|seq| "<#{tk_event_sequence(seq)}>" }) ) if tk_call_without_enc('event','info',"<#{@id}>").empty? TkVirtualEventTBL.mutex.synchronize{ TkVirtualEventTBL.delete(@id) } end end self end def info tk_call_without_enc('event','info',"<#{@id}>").split(/\s+/).collect!{|seq| lst = seq.scan(/<*[^<>]+>*/).collect!{|subseq| case (subseq) when /^<<[^<>]+>>$/ TkVirtualEvent.getobj(subseq[1..-2]) when /^<[^<>]+>$/ subseq[1..-2] else subseq.split('') end }.flatten (lst.size == 1) ? lst[0] : lst } end end TkNamedVirtualEvent = TkVirtualEvent::PreDefVirtEvent ================================================ FILE: ext/tk/lib/tk/winfo.rb ================================================ # # tk/winfo.rb : methods for winfo command # module TkWinfo end require 'tk' module TkWinfo include Tk extend Tk TkCommandNames = ['winfo'.freeze].freeze def TkWinfo.atom(name, win=nil) if win number(tk_call_without_enc('winfo', 'atom', '-displayof', win, _get_eval_enc_str(name))) else number(tk_call_without_enc('winfo', 'atom', _get_eval_enc_str(name))) end end def winfo_atom(name) TkWinfo.atom(name, self) end def TkWinfo.atomname(id, win=nil) if win _fromUTF8(tk_call_without_enc('winfo', 'atomname', '-displayof', win, id)) else _fromUTF8(tk_call_without_enc('winfo', 'atomname', id)) end end def winfo_atomname(id) TkWinfo.atomname(id, self) end def TkWinfo.cells(win) number(tk_call_without_enc('winfo', 'cells', win)) end def winfo_cells TkWinfo.cells self end def TkWinfo.children(win) list(tk_call_without_enc('winfo', 'children', win)) end def winfo_children TkWinfo.children self end def TkWinfo.classname(win) tk_call_without_enc('winfo', 'class', win) end def winfo_classname TkWinfo.classname self end alias winfo_class winfo_classname def TkWinfo.colormapfull(win) bool(tk_call_without_enc('winfo', 'colormapfull', win)) end def winfo_colormapfull TkWinfo.colormapfull self end def TkWinfo.containing(rootX, rootY, win=nil) if win window(tk_call_without_enc('winfo', 'containing', '-displayof', win, rootX, rootY)) else window(tk_call_without_enc('winfo', 'containing', rootX, rootY)) end end def winfo_containing(x, y) TkWinfo.containing(x, y, self) end def TkWinfo.depth(win) number(tk_call_without_enc('winfo', 'depth', win)) end def winfo_depth TkWinfo.depth self end def TkWinfo.exist?(win) bool(tk_call_without_enc('winfo', 'exists', win)) end def winfo_exist? TkWinfo.exist? self end def TkWinfo.fpixels(win, dist) number(tk_call_without_enc('winfo', 'fpixels', win, dist)) end def winfo_fpixels(dist) TkWinfo.fpixels self, dist end def TkWinfo.geometry(win) tk_call_without_enc('winfo', 'geometry', win) end def winfo_geometry TkWinfo.geometry self end def TkWinfo.height(win) number(tk_call_without_enc('winfo', 'height', win)) end def winfo_height TkWinfo.height self end def TkWinfo.id(win) tk_call_without_enc('winfo', 'id', win) end def winfo_id TkWinfo.id self end def TkWinfo.interps(win=nil) if win #tk_split_simplelist(tk_call_without_enc('winfo', 'interps', # '-displayof', win)) tk_split_simplelist(tk_call_without_enc('winfo', 'interps', '-displayof', win), false, true) else #tk_split_simplelist(tk_call_without_enc('winfo', 'interps')) tk_split_simplelist(tk_call_without_enc('winfo', 'interps'), false, true) end end def winfo_interps TkWinfo.interps self end def TkWinfo.mapped?(win) bool(tk_call_without_enc('winfo', 'ismapped', win)) end def winfo_mapped? TkWinfo.mapped? self end def TkWinfo.manager(win) tk_call_without_enc('winfo', 'manager', win) end def winfo_manager TkWinfo.manager self end def TkWinfo.appname(win) tk_call('winfo', 'name', win) end def winfo_appname TkWinfo.appname self end def TkWinfo.parent(win) window(tk_call_without_enc('winfo', 'parent', win)) end def winfo_parent TkWinfo.parent self end def TkWinfo.widget(id, win=nil) if win window(tk_call_without_enc('winfo', 'pathname', '-displayof', win, id)) else window(tk_call_without_enc('winfo', 'pathname', id)) end end def winfo_widget(id) TkWinfo.widget id, self end def TkWinfo.pixels(win, dist) number(tk_call_without_enc('winfo', 'pixels', win, dist)) end def winfo_pixels(dist) TkWinfo.pixels self, dist end def TkWinfo.reqheight(win) number(tk_call_without_enc('winfo', 'reqheight', win)) end def winfo_reqheight TkWinfo.reqheight self end def TkWinfo.reqwidth(win) number(tk_call_without_enc('winfo', 'reqwidth', win)) end def winfo_reqwidth TkWinfo.reqwidth self end def TkWinfo.rgb(win, color) list(tk_call_without_enc('winfo', 'rgb', win, color)) end def winfo_rgb(color) TkWinfo.rgb self, color end def TkWinfo.rootx(win) number(tk_call_without_enc('winfo', 'rootx', win)) end def winfo_rootx TkWinfo.rootx self end def TkWinfo.rooty(win) number(tk_call_without_enc('winfo', 'rooty', win)) end def winfo_rooty TkWinfo.rooty self end def TkWinfo.screen(win) tk_call('winfo', 'screen', win) end def winfo_screen TkWinfo.screen self end def TkWinfo.screencells(win) number(tk_call_without_enc('winfo', 'screencells', win)) end def winfo_screencells TkWinfo.screencells self end def TkWinfo.screendepth(win) number(tk_call_without_enc('winfo', 'screendepth', win)) end def winfo_screendepth TkWinfo.screendepth self end def TkWinfo.screenheight (win) number(tk_call_without_enc('winfo', 'screenheight', win)) end def winfo_screenheight TkWinfo.screenheight self end def TkWinfo.screenmmheight(win) number(tk_call_without_enc('winfo', 'screenmmheight', win)) end def winfo_screenmmheight TkWinfo.screenmmheight self end def TkWinfo.screenmmwidth(win) number(tk_call_without_enc('winfo', 'screenmmwidth', win)) end def winfo_screenmmwidth TkWinfo.screenmmwidth self end def TkWinfo.screenvisual(win) tk_call_without_enc('winfo', 'screenvisual', win) end def winfo_screenvisual TkWinfo.screenvisual self end def TkWinfo.screenwidth(win) number(tk_call_without_enc('winfo', 'screenwidth', win)) end def winfo_screenwidth TkWinfo.screenwidth self end def TkWinfo.server(win) tk_call('winfo', 'server', win) end def winfo_server TkWinfo.server self end def TkWinfo.toplevel(win) window(tk_call_without_enc('winfo', 'toplevel', win)) end def winfo_toplevel TkWinfo.toplevel self end def TkWinfo.visual(win) tk_call_without_enc('winfo', 'visual', win) end def winfo_visual TkWinfo.visual self end def TkWinfo.visualid(win) tk_call_without_enc('winfo', 'visualid', win) end def winfo_visualid TkWinfo.visualid self end def TkWinfo.visualsavailable(win, includeids=false) if includeids list(tk_call_without_enc('winfo', 'visualsavailable', win, "includeids")) else list(tk_call_without_enc('winfo', 'visualsavailable', win)) end end def winfo_visualsavailable(includeids=false) TkWinfo.visualsavailable self, includeids end def TkWinfo.vrootheight(win) number(tk_call_without_enc('winfo', 'vrootheight', win)) end def winfo_vrootheight TkWinfo.vrootheight self end def TkWinfo.vrootwidth(win) number(tk_call_without_enc('winfo', 'vrootwidth', win)) end def winfo_vrootwidth TkWinfo.vrootwidth self end def TkWinfo.vrootx(win) number(tk_call_without_enc('winfo', 'vrootx', win)) end def winfo_vrootx TkWinfo.vrootx self end def TkWinfo.vrooty(win) number(tk_call_without_enc('winfo', 'vrooty', win)) end def winfo_vrooty TkWinfo.vrooty self end def TkWinfo.width(win) number(tk_call_without_enc('winfo', 'width', win)) end def winfo_width TkWinfo.width self end def TkWinfo.x(win) number(tk_call_without_enc('winfo', 'x', win)) end def winfo_x TkWinfo.x self end def TkWinfo.y(win) number(tk_call_without_enc('winfo', 'y', win)) end def winfo_y TkWinfo.y self end def TkWinfo.viewable(win) bool(tk_call_without_enc('winfo', 'viewable', win)) end def winfo_viewable TkWinfo.viewable self end def TkWinfo.pointerx(win) number(tk_call_without_enc('winfo', 'pointerx', win)) end def winfo_pointerx TkWinfo.pointerx self end def TkWinfo.pointery(win) number(tk_call_without_enc('winfo', 'pointery', win)) end def winfo_pointery TkWinfo.pointery self end def TkWinfo.pointerxy(win) list(tk_call_without_enc('winfo', 'pointerxy', win)) end def winfo_pointerxy TkWinfo.pointerxy self end end ================================================ FILE: ext/tk/lib/tk/winpkg.rb ================================================ # # tk/winpkg.rb : methods for Tcl/Tk packages for Microsoft Windows # 2000/11/22 by Hidetoshi Nagai # # ATTENTION !! # This is NOT TESTED. Because I have no test-environment. # require 'tk' module Tk::WinDDE end #TkWinDDE = Tk::WinDDE Tk.__set_toplevel_aliases__(:Tk, Tk::WinDDE, :TkWinDDE) module Tk::WinDDE extend Tk extend Tk::WinDDE TkCommandNames = ['dde'.freeze].freeze PACKAGE_NAME = 'dde'.freeze def self.package_name PACKAGE_NAME end if self.const_defined? :FORCE_VERSION tk_call_without_enc('package', 'require', 'dde', FORCE_VERSION) else tk_call_without_enc('package', 'require', 'dde') end #def servername(topic=None) # tk_call('dde', 'servername', topic) #end def servername(*args) if args.size == 0 tk_call('dde', 'servername') else if args[-1].kind_of?(Hash) # dde 1.2 + keys = _symbolkey2str(args.pop) force = (keys.delete('force'))? '-force': None exact = (keys.delete('exact'))? '-exact': None if keys.size == 0 tk_call('dde', 'servername', force, exact) elsif args.size == 0 tk_call('dde', 'servername', force, exact, *hash_kv(keys)) else tk_call('dde', 'servername', force, exact, *((hash_kv(keys) << '--') + args)) end else tk_call('dde', 'servername', *args) end end end def execute(service, topic, data) tk_call('dde', 'execute', service, topic, data) end def async_execute(service, topic, data) tk_call('dde', '-async', 'execute', service, topic, data) end def poke(service, topic, item, data) tk_call('dde', 'poke', service, topic, item, data) end def request(service, topic, item) tk_call('dde', 'request', service, topic, item) end def binary_request(service, topic, item) tk_call('dde', 'request', '-binary', service, topic, item) end def services(service, topic) tk_call('dde', 'services', service, topic) end def eval(topic, cmd, *args) tk_call('dde', 'eval', topic, cmd, *args) end def async_eval(topic, cmd, *args) tk_call('dde', 'eval', -async, topic, cmd, *args) end module_function :servername, :execute, :async_execute, :poke, :request, :services, :eval end module Tk::WinRegistry end #TkWinRegistry = Tk::WinRegistry Tk.__set_toplevel_aliases__(:Tk, Tk::WinRegistry, :TkWinRegistry) module Tk::WinRegistry extend Tk extend Tk::WinRegistry TkCommandNames = ['registry'.freeze].freeze if self.const_defined? :FORCE_VERSION tk_call('package', 'require', 'registry', FORCE_VERSION) else tk_call('package', 'require', 'registry') end def broadcast(keynam, timeout=nil) if timeout tk_call('registry', 'broadcast', keynam, '-timeout', timeout) else tk_call('registry', 'broadcast', keynam) end end def delete(keynam, valnam=None) tk_call('registry', 'delete', keynam, valnam) end def get(keynam, valnam) tk_call('registry', 'get', keynam, valnam) end def keys(keynam, pattern=nil) lst = tk_split_simplelist(tk_call('registry', 'keys', keynam)) if pattern lst.find_all{|key| key =~ pattern} else lst end end def set(keynam, valnam=None, data=None, dattype=None) tk_call('registry', 'set', keynam, valnam, data, dattype) end def type(keynam, valnam) tk_call('registry', 'type', keynam, valnam) end def values(keynam, pattern=nil) lst = tk_split_simplelist(tk_call('registry', 'values', keynam)) if pattern lst.find_all{|val| val =~ pattern} else lst end end module_function :delete, :get, :keys, :set, :type, :values end ================================================ FILE: ext/tk/lib/tk/wm.rb ================================================ # # tk/wm.rb : methods for wm command # require 'tk' module Tk module Wm #include TkComm extend TkCore TkCommandNames = ['wm'.freeze].freeze TOPLEVEL_METHODCALL_OPTKEYS = {} def Wm.aspect(win, *args) if args.length == 0 list(tk_call_without_enc('wm', 'aspect', win.epath)) else args = args[0] if args.length == 1 && args[0].kind_of?(Array) tk_call('wm', 'aspect', win.epath, *args) win end end def aspect(*args) Wm.aspect(self, *args) end alias wm_aspect aspect TOPLEVEL_METHODCALL_OPTKEYS['aspect'] = 'aspect' def Wm.attributes(win, slot=nil,value=TkComm::None) if slot == nil lst = tk_split_list(tk_call('wm', 'attributes', win.epath)) info = {} while key = lst.shift info[key[1..-1]] = lst.shift end info elsif slot.kind_of? Hash tk_call('wm', 'attributes', win.epath, *hash_kv(slot)) win elsif value == TkComm::None tk_call('wm', 'attributes', win.epath, "-#{slot}") else tk_call('wm', 'attributes', win.epath, "-#{slot}", value) win end end def attributes(slot=nil,value=TkComm::None) Wm.attributes(self, slot, value) end alias wm_attributes attributes TOPLEVEL_METHODCALL_OPTKEYS['attributes'] = 'attributes' def Wm.client(win, name=TkComm::None) if name == TkComm::None tk_call('wm', 'client', win.epath) else name = '' if name == nil tk_call('wm', 'client', win.epath, name) win end end def client(name=TkComm::None) Wm.client(self, name) end alias wm_client client TOPLEVEL_METHODCALL_OPTKEYS['client'] = 'client' def Wm.colormapwindows(win, *args) if args.size == 0 list(tk_call_without_enc('wm', 'colormapwindows', win.epath)) else args = args[0] if args.length == 1 && args[0].kind_of?(Array) tk_call_without_enc('wm', 'colormapwindows', win.epath, *args) win end end def colormapwindows(*args) Wm.colormapwindows(self, *args) end alias wm_colormapwindows colormapwindows TOPLEVEL_METHODCALL_OPTKEYS['colormapwindows'] = 'colormapwindows' def Wm.command(win, value=nil) if value tk_call('wm', 'command', epath, value) win else #procedure(tk_call('wm', 'command', epath)) tk_call('wm', 'command', epath) end end def wm_command(value=nil) Wm.command(self, value) end TOPLEVEL_METHODCALL_OPTKEYS['wm_command'] = 'wm_command' def Wm.deiconify(win, ex = true) if ex tk_call_without_enc('wm', 'deiconify', win.epath) else Wm.iconify(win) end win end def deiconify(ex = true) Wm.deiconify(self, ex) end alias wm_deiconify deiconify def Wm.focusmodel(win, mode = nil) if mode tk_call_without_enc('wm', 'focusmodel', win.epath, mode) win else tk_call_without_enc('wm', 'focusmodel', win.epath) end end def focusmodel(mode = nil) Wm.focusmodel(self, mode) end alias wm_focusmodel focusmodel TOPLEVEL_METHODCALL_OPTKEYS['focusmodel'] = 'focusmodel' def Wm.forget(win) # Tcl/Tk 8.5+ # work with dockable frames tk_call_without_enc('wm', 'forget', win.epath) win end def wm_forget Wm.forget(self) end def Wm.frame(win) tk_call_without_enc('wm', 'frame', win.epath) end def frame Wm.frame(self) end alias wm_frame frame def Wm.geometry(win, geom=nil) if geom tk_call_without_enc('wm', 'geometry', win.epath, geom) win else tk_call_without_enc('wm', 'geometry', win.epath) end end def geometry(geom=nil) Wm.geometry(self, geom) end alias wm_geometry geometry TOPLEVEL_METHODCALL_OPTKEYS['geometry'] = 'geometry' def Wm.grid(win, *args) if args.size == 0 list(tk_call_without_enc('wm', 'grid', win.epath)) else args = args[0] if args.length == 1 && args[0].kind_of?(Array) tk_call_without_enc('wm', 'grid', win.epath, *args) win end end def wm_grid(*args) Wm.grid(self, *args) end TOPLEVEL_METHODCALL_OPTKEYS['wm_grid'] = 'wm_grid' def Wm.group(win, leader = nil) if leader tk_call('wm', 'group', win.epath, leader) win else window(tk_call('wm', 'group', win.epath)) end end def group(leader = nil) Wm.group(self, leader) end alias wm_group group TOPLEVEL_METHODCALL_OPTKEYS['group'] = 'group' def Wm.iconbitmap(win, bmp=nil) if bmp tk_call_without_enc('wm', 'iconbitmap', win.epath, bmp) win else image_obj(tk_call_without_enc('wm', 'iconbitmap', win.epath)) end end def iconbitmap(bmp=nil) Wm.iconbitmap(self, bmp) end alias wm_iconbitmap iconbitmap TOPLEVEL_METHODCALL_OPTKEYS['iconbitmap'] = 'iconbitmap' def Wm.iconphoto(win, *imgs) if imgs.empty? win.instance_eval{ @wm_iconphoto = nil unless defined? @wm_iconphoto return @wm_iconphoto } end imgs = imgs[0] if imgs.length == 1 && imgs[0].kind_of?(Array) tk_call_without_enc('wm', 'iconphoto', win.epath, *imgs) win.instance_eval{ @wm_iconphoto = imgs } win end def iconphoto(*imgs) Wm.iconphoto(self, *imgs) end alias wm_iconphoto iconphoto TOPLEVEL_METHODCALL_OPTKEYS['iconphoto'] = 'iconphoto' def Wm.iconphoto_default(win, *imgs) imgs = imgs[0] if imgs.length == 1 && imgs[0].kind_of?(Array) tk_call_without_enc('wm', 'iconphoto', win.epath, '-default', *imgs) win end def iconphoto_default(*imgs) Wm.iconphoto_default(self, *imgs) end alias wm_iconphoto_default iconphoto_default def Wm.iconify(win, ex = true) if ex tk_call_without_enc('wm', 'iconify', win.epath) else Wm.deiconify(win) end win end def iconify(ex = true) Wm.iconify(self, ex) end alias wm_iconify iconify def Wm.iconmask(win, bmp=nil) if bmp tk_call_without_enc('wm', 'iconmask', win.epath, bmp) win else image_obj(tk_call_without_enc('wm', 'iconmask', win.epath)) end end def iconmask(bmp=nil) Wm.iconmask(self, bmp) end alias wm_iconmask iconmask TOPLEVEL_METHODCALL_OPTKEYS['iconmask'] = 'iconmask' def Wm.iconname(win, name=nil) if name tk_call('wm', 'iconname', win.epath, name) win else tk_call('wm', 'iconname', win.epath) end end def iconname(name=nil) Wm.iconname(self, name) end alias wm_iconname iconname TOPLEVEL_METHODCALL_OPTKEYS['iconname'] = 'iconname' def Wm.iconposition(win, *args) if args.size == 0 list(tk_call_without_enc('wm', 'iconposition', win.epath)) else args = args[0] if args.length == 1 && args[0].kind_of?(Array) tk_call_without_enc('wm', 'iconposition', win.epath, *args) win end end def iconposition(*args) Wm.iconposition(self, *args) end alias wm_iconposition iconposition TOPLEVEL_METHODCALL_OPTKEYS['iconposition'] = 'iconposition' def Wm.iconwindow(win, iconwin = nil) if iconwin tk_call_without_enc('wm', 'iconwindow', win.epath, iconwin) win else w = tk_call_without_enc('wm', 'iconwindow', win.epath) (w == '')? nil: window(w) end end def iconwindow(iconwin = nil) Wm.iconwindow(self, iconwin) end alias wm_iconwindow iconwindow TOPLEVEL_METHODCALL_OPTKEYS['iconwindow'] = 'iconwindow' def Wm.manage(win) # Tcl/Tk 8.5+ feature tk_call_without_enc('wm', 'manage', win.epath) win end def wm_manage Wm.manage(self) end =begin def Wm.manage(win, use_id = nil) # Tcl/Tk 8.5+ feature # -------------------------------------------------------------- # In the future release, I want to support to embed the 'win' # into the container which has window-id 'use-id'. # It may give users frexibility on controlling their GUI. # However, it may be difficult for current Tcl/Tk (Tcl/Tk8.5.1), # because it seems to require to modify Tcl/Tk's source code. # -------------------------------------------------------------- if use_id tk_call_without_enc('wm', 'manage', win.epath, '-use', use_id) else tk_call_without_enc('wm', 'manage', win.epath) end win end =end def Wm.maxsize(win, *args) if args.size == 0 list(tk_call_without_enc('wm', 'maxsize', win.epath)) else args = args[0] if args.length == 1 && args[0].kind_of?(Array) tk_call_without_enc('wm', 'maxsize', win.epath, *args) win end end def maxsize(*args) Wm.maxsize(self, *args) end alias wm_maxsize maxsize TOPLEVEL_METHODCALL_OPTKEYS['maxsize'] = 'maxsize' def Wm.minsize(win, *args) if args.size == 0 list(tk_call_without_enc('wm', 'minsize', win.epath)) else args = args[0] if args.length == 1 && args[0].kind_of?(Array) tk_call_without_enc('wm', 'minsize', win.path, *args) win end end def minsize(*args) Wm.minsize(self, *args) end alias wm_minsize minsize TOPLEVEL_METHODCALL_OPTKEYS['minsize'] = 'minsize' def Wm.overrideredirect(win, mode=TkComm::None) if mode == TkComm::None bool(tk_call_without_enc('wm', 'overrideredirect', win.epath)) else tk_call_without_enc('wm', 'overrideredirect', win.epath, mode) win end end def overrideredirect(mode=TkComm::None) Wm.overrideredirect(self, mode) end alias wm_overrideredirect overrideredirect TOPLEVEL_METHODCALL_OPTKEYS['overrideredirect'] = 'overrideredirect' def Wm.positionfrom(win, who=TkComm::None) if who == TkComm::None r = tk_call_without_enc('wm', 'positionfrom', win.epath) (r == "")? nil: r else tk_call_without_enc('wm', 'positionfrom', win.epath, who) win end end def positionfrom(who=TkComm::None) Wm.positionfrom(self, who) end alias wm_positionfrom positionfrom TOPLEVEL_METHODCALL_OPTKEYS['positionfrom'] = 'positionfrom' def Wm.protocol(win, name=nil, cmd=nil, &b) if cmd tk_call_without_enc('wm', 'protocol', win.epath, name, cmd) win elsif b tk_call_without_enc('wm', 'protocol', win.epath, name, proc(&b)) win elsif name result = tk_call_without_enc('wm', 'protocol', win.epath, name) (result == "")? nil : tk_tcl2ruby(result) else tk_split_simplelist(tk_call_without_enc('wm', 'protocol', win.epath)) end end def protocol(name=nil, cmd=nil, &b) Wm.protocol(self, name, cmd, &b) end alias wm_protocol protocol def Wm.protocols(win, kv=nil) unless kv ret = {} Wm.protocol(win).each{|name| ret[name] = Wm.protocol(win, name) } return ret end unless kv.kind_of?(Hash) fail ArgumentError, 'expect a hash of protocol=>command' end kv.each{|k, v| Wm.protocol(win, k, v)} win end def protocols(kv=nil) Wm.protocols(self, kv) end alias wm_protocols protocols TOPLEVEL_METHODCALL_OPTKEYS['protocols'] = 'protocols' def Wm.resizable(win, *args) if args.length == 0 list(tk_call_without_enc('wm', 'resizable', win.epath)).map!{|e| bool(e)} else args = args[0] if args.length == 1 && args[0].kind_of?(Array) tk_call_without_enc('wm', 'resizable', win.epath, *args) win end end def resizable(*args) Wm.resizable(self, *args) end alias wm_resizable resizable TOPLEVEL_METHODCALL_OPTKEYS['resizable'] = 'resizable' def Wm.sizefrom(win, who=TkComm::None) if who == TkComm::None r = tk_call_without_enc('wm', 'sizefrom', win.epath) (r == "")? nil: r else tk_call_without_enc('wm', 'sizefrom', win.epath, who) win end end def sizefrom(who=TkComm::None) Wm.sizefrom(self, who) end alias wm_sizefrom sizefrom TOPLEVEL_METHODCALL_OPTKEYS['sizefrom'] = 'sizefrom' def Wm.stackorder(win) list(tk_call('wm', 'stackorder', win.epath)) end def stackorder Wm.stackorder(self) end alias wm_stackorder stackorder def Wm.stackorder_isabove(win, target) bool(tk_call('wm', 'stackorder', win.epath, 'isabove', target)) end def Wm.stackorder_is_above(win, target) Wm.stackorder_isabove(win, target) end def stackorder_isabove(target) Wm.stackorder_isabove(self, target) end alias stackorder_is_above stackorder_isabove alias wm_stackorder_isabove stackorder_isabove alias wm_stackorder_is_above stackorder_isabove def Wm.stackorder_isbelow(win, target) bool(tk_call('wm', 'stackorder', win.epath, 'isbelow', target)) end def Wm.stackorder_is_below(win, target) Wm.stackorder_isbelow(win, target) end def stackorder_isbelow(target) Wm.stackorder_isbelow(self, target) end alias stackorder_is_below stackorder_isbelow alias wm_stackorder_isbelow stackorder_isbelow alias wm_stackorder_is_below stackorder_isbelow def Wm.state(win, st=nil) if st tk_call_without_enc('wm', 'state', win.epath, st) win else tk_call_without_enc('wm', 'state', win.epath) end end def state(st=nil) Wm.state(self, st) end alias wm_state state TOPLEVEL_METHODCALL_OPTKEYS['state'] = 'state' def Wm.title(win, str=nil) if str tk_call('wm', 'title', win.epath, str) win else tk_call('wm', 'title', win.epath) end end def title(str=nil) Wm.title(self, str) end alias wm_title title TOPLEVEL_METHODCALL_OPTKEYS['title'] = 'title' def Wm.transient(win, master=nil) if master tk_call_without_enc('wm', 'transient', win.epath, master) win else window(tk_call_without_enc('wm', 'transient', win.epath)) end end def transient(master=nil) Wm.transient(self, master) end alias wm_transient transient TOPLEVEL_METHODCALL_OPTKEYS['transient'] = 'transient' def Wm.withdraw(win, ex = true) if ex tk_call_without_enc('wm', 'withdraw', win.epath) else Wm.deiconify(win) end win end def withdraw(ex = true) Wm.withdraw(self, ex) end alias wm_withdraw withdraw end module Wm_for_General Wm.instance_methods.each{|m| if (m = m.to_s) =~ /^wm_(.*)$/ eval "def #{m}(*args, &b); Tk::Wm.#{$1}(self, *args, &b); end" end } end end ================================================ FILE: ext/tk/lib/tk/xim.rb ================================================ # # tk/xim.rb : control imput_method # require 'tk' module TkXIM include Tk extend Tk TkCommandNames = ['imconfigure'.freeze].freeze def TkXIM.useinputmethods(value = None, win = nil) if value == None if win bool(tk_call_without_enc('tk', 'useinputmethods', '-displayof', win)) else bool(tk_call_without_enc('tk', 'useinputmethods')) end else if win bool(tk_call_without_enc('tk', 'useinputmethods', '-displayof', win, value)) else bool(tk_call_without_enc('tk', 'useinputmethods', value)) end end end def TkXIM.useinputmethods_displayof(win, value = None) TkXIM.useinputmethods(value, win) end def TkXIM.caret(win, keys=nil) if keys tk_call_without_enc('tk', 'caret', win, *hash_kv(keys)) self else lst = tk_split_list(tk_call_without_enc('tk', 'caret', win)) info = {} while key = lst.shift info[key[1..-1]] = lst.shift end info end end def TkXIM.configure(win, slot, value=None) begin if /^8\.*/ === Tk::TK_VERSION && JAPANIZED_TK if slot.kind_of? Hash tk_call('imconfigure', win, *hash_kv(slot)) else tk_call('imconfigure', win, "-#{slot}", value) end end rescue end end def TkXIM.configinfo(win, slot=nil) if TkComm::GET_CONFIGINFOwoRES_AS_ARRAY begin if /^8\.*/ === Tk::TK_VERSION && JAPANIZED_TK if slot conf = tk_split_list(tk_call('imconfigure', win, "-#{slot}")) conf[0] = conf[0][1..-1] conf else tk_split_list(tk_call('imconfigure', win)).collect{|conf| conf[0] = conf[0][1..-1] conf } end else [] end rescue [] end else # ! TkComm::GET_CONFIGINFOwoRES_AS_ARRAY TkXIM.current_configinfo(win, slot) end end def TkXIM.current_configinfo(win, slot=nil) begin if /^8\.*/ === Tk::TK_VERSION && JAPANIZED_TK if slot conf = tk_split_list(tk_call('imconfigure', win, "-#{slot}")) { conf[0][1..-1] => conf[1] } else ret = {} tk_split_list(tk_call('imconfigure', win)).each{|conf| ret[conf[0][1..-1]] = conf[1] } ret end else {} end rescue {} end end def useinputmethods(value=None) TkXIM.useinputmethods(value, self) end def caret(keys=nil) TkXIM.caret(self, keys=nil) end def imconfigure(slot, value=None) TkXIM.configure(self, slot, value) end def imconfiginfo(slot=nil) TkXIM.configinfo(self, slot) end end ================================================ FILE: ext/tk/lib/tk.rb ================================================ # # tk.rb - Tk interface module using tcltklib # by Yukihiro Matsumoto # use Shigehiro's tcltklib require 'tcltklib' require 'tkutil' # autoload require 'tk/autoload' # for Mutex require 'thread' class TclTkIp # backup original (without encoding) _eval and _invoke alias _eval_without_enc _eval alias _invoke_without_enc _invoke def _ip_id_ # for RemoteTkIp '' end end # define TkComm module (step 1: basic functions) module TkComm include TkUtil extend TkUtil WidgetClassNames = {}.taint TkExtlibAutoloadModule = [].taint # None = Object.new ### --> definition is moved to TkUtil module # def None.to_s # 'None' # end # None.freeze #Tk_CMDTBL = {} #Tk_WINDOWS = {} Tk_IDs = ["00000".taint, "00000".taint] # [0]-cmdid, [1]-winid Tk_IDs.instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } # for backward compatibility Tk_CMDTBL = Object.new def Tk_CMDTBL.method_missing(id, *args) TkCore::INTERP.tk_cmd_tbl.__send__(id, *args) end Tk_CMDTBL.freeze Tk_WINDOWS = Object.new def Tk_WINDOWS.method_missing(id, *args) TkCore::INTERP.tk_windows.__send__(id, *args) end Tk_WINDOWS.freeze self.instance_eval{ @cmdtbl = [].taint } unless const_defined?(:GET_CONFIGINFO_AS_ARRAY) # GET_CONFIGINFO_AS_ARRAY = false => returns a Hash { opt =>val, ... } # true => returns an Array [[opt,val], ... ] # val is a list which includes resource info. GET_CONFIGINFO_AS_ARRAY = true end unless const_defined?(:GET_CONFIGINFOwoRES_AS_ARRAY) # for configinfo without resource info; list of [opt, value] pair # false => returns a Hash { opt=>val, ... } # true => returns an Array [[opt,val], ... ] GET_CONFIGINFOwoRES_AS_ARRAY = true end # *** ATTENTION *** # 'current_configinfo' method always returns a Hash under all cases of above. def error_at frames = caller() frames.delete_if do |c| c =~ %r!/tk(|core|thcore|canvas|text|entry|scrollbox)\.rb:\d+! end frames end private :error_at def _genobj_for_tkwidget(path) return TkRoot.new if path == '.' begin #tk_class = TkCore::INTERP._invoke('winfo', 'class', path) tk_class = Tk.ip_invoke_without_enc('winfo', 'class', path) rescue return path end if ruby_class = WidgetClassNames[tk_class] ruby_class_name = ruby_class.name # gen_class_name = ruby_class_name + 'GeneratedOnTk' gen_class_name = ruby_class_name classname_def = '' else # ruby_class == nil mods = TkExtlibAutoloadModule.find_all{|m| m.const_defined?(tk_class)} mods.each{|mod| begin mod.const_get(tk_class) # auto_load break if (ruby_class = WidgetClassNames[tk_class]) rescue LoadError # ignore load error end } unless ruby_class std_class = 'Tk' << tk_class if Object.const_defined?(std_class) Object.const_get(std_class) # auto_load ruby_class = WidgetClassNames[tk_class] end end if ruby_class # found ruby_class_name = ruby_class.name gen_class_name = ruby_class_name classname_def = '' else # unknown ruby_class_name = 'TkWindow' gen_class_name = 'TkWidget_' + tk_class classname_def = "WidgetClassName = '#{tk_class}'.freeze" end end ################################### =begin if ruby_class = WidgetClassNames[tk_class] ruby_class_name = ruby_class.name # gen_class_name = ruby_class_name + 'GeneratedOnTk' gen_class_name = ruby_class_name classname_def = '' else mod = TkExtlibAutoloadModule.find{|m| m.const_defined?(tk_class)} if mod ruby_class_name = mod.name + '::' + tk_class gen_class_name = ruby_class_name classname_def = '' elsif Object.const_defined?('Tk' + tk_class) ruby_class_name = 'Tk' + tk_class # gen_class_name = ruby_class_name + 'GeneratedOnTk' gen_class_name = ruby_class_name classname_def = '' else ruby_class_name = 'TkWindow' # gen_class_name = ruby_class_name + tk_class + 'GeneratedOnTk' gen_class_name = 'TkWidget_' + tk_class classname_def = "WidgetClassName = '#{tk_class}'.freeze" end end =end =begin unless Object.const_defined? gen_class_name Object.class_eval "class #{gen_class_name}<#{ruby_class_name} #{classname_def} end" end Object.class_eval "#{gen_class_name}.new('widgetname'=>'#{path}', 'without_creating'=>true)" =end base = Object gen_class_name.split('::').each{|klass| next if klass == '' if base.const_defined?(klass) base = base.class_eval klass else base = base.class_eval "class #{klass}<#{ruby_class_name} #{classname_def} end #{klass}" end } base.class_eval "#{gen_class_name}.new('widgetname'=>'#{path}', 'without_creating'=>true)" end private :_genobj_for_tkwidget module_function :_genobj_for_tkwidget def _at(x,y=nil) if y "@#{Integer(x)},#{Integer(y)}" else "@#{Integer(x)}" end end module_function :_at def tk_tcl2ruby(val, enc_mode = false, listobj = true) =begin if val =~ /^rb_out\S* (c(_\d+_)?\d+)/ #return Tk_CMDTBL[$1] return TkCore::INTERP.tk_cmd_tbl[$1] #cmd_obj = TkCore::INTERP.tk_cmd_tbl[$1] #if cmd_obj.kind_of?(Proc) || cmd_obj.kind_of?(Method) # cmd_obj #else # cmd_obj.cmd #end end =end if val =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/ return TkCore::INTERP.tk_cmd_tbl[$4] end #if val.include? ?\s # return val.split.collect{|v| tk_tcl2ruby(v)} #end case val when /\A@font\S+\z/ TkFont.get_obj(val) when /\A-?\d+\z/ val.to_i when /\A\.\S*\z/ #Tk_WINDOWS[val] ? Tk_WINDOWS[val] : _genobj_for_tkwidget(val) TkCore::INTERP.tk_windows[val]? TkCore::INTERP.tk_windows[val] : _genobj_for_tkwidget(val) when /\Ai(_\d+_)?\d+\z/ TkImage::Tk_IMGTBL.mutex.synchronize{ TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val } when /\A-?\d+\.?\d*(e[-+]?\d+)?\z/ val.to_f when /\\ / val.gsub(/\\ /, ' ') when /[^\\] / if listobj #tk_split_escstr(val).collect{|elt| # tk_tcl2ruby(elt, enc_mode, listobj) #} val = _toUTF8(val) unless enc_mode tk_split_escstr(val, false, false).collect{|elt| tk_tcl2ruby(elt, true, listobj) } elsif enc_mode _fromUTF8(val) else val end else if enc_mode _fromUTF8(val) else val end end end private :tk_tcl2ruby module_function :tk_tcl2ruby #private_class_method :tk_tcl2ruby unless const_defined?(:USE_TCLs_LIST_FUNCTIONS) USE_TCLs_LIST_FUNCTIONS = true end if USE_TCLs_LIST_FUNCTIONS ########################################################################### # use Tcl function version of split_list ########################################################################### def tk_split_escstr(str, src_enc=true, dst_enc=true) str = _toUTF8(str) if src_enc if dst_enc TkCore::INTERP._split_tklist(str).map!{|s| _fromUTF8(s)} else TkCore::INTERP._split_tklist(str) end end def tk_split_sublist(str, depth=-1, src_enc=true, dst_enc=true) # return [] if str == "" # list = TkCore::INTERP._split_tklist(str) str = _toUTF8(str) if src_enc if depth == 0 return "" if str == "" list = [str] else return [] if str == "" list = TkCore::INTERP._split_tklist(str) end if list.size == 1 # tk_tcl2ruby(list[0], nil, false) tk_tcl2ruby(list[0], dst_enc, false) else list.collect{|token| tk_split_sublist(token, depth - 1, false, dst_enc)} end end def tk_split_list(str, depth=0, src_enc=true, dst_enc=true) return [] if str == "" str = _toUTF8(str) if src_enc TkCore::INTERP._split_tklist(str).map!{|token| tk_split_sublist(token, depth - 1, false, dst_enc) } end def tk_split_simplelist(str, src_enc=true, dst_enc=true) #lst = TkCore::INTERP._split_tklist(str) #if (lst.size == 1 && lst =~ /^\{.*\}$/) # TkCore::INTERP._split_tklist(str[1..-2]) #else # lst #end str = _toUTF8(str) if src_enc if dst_enc TkCore::INTERP._split_tklist(str).map!{|s| _fromUTF8(s)} else TkCore::INTERP._split_tklist(str) end end def array2tk_list(ary, enc=nil) return "" if ary.size == 0 sys_enc = TkCore::INTERP.encoding sys_enc = TclTkLib.encoding_system unless sys_enc dst_enc = (enc == nil)? sys_enc: enc dst = ary.collect{|e| if e.kind_of? Array s = array2tk_list(e, enc) elsif e.kind_of? Hash tmp_ary = [] #e.each{|k,v| tmp_ary << k << v } e.each{|k,v| tmp_ary << "-#{_get_eval_string(k)}" << v } s = array2tk_list(tmp_ary, enc) else s = _get_eval_string(e, enc) end if dst_enc != true && dst_enc != false if (s_enc = s.instance_variable_get(:@encoding)) s_enc = s_enc.to_s elsif TkCore::WITH_ENCODING s_enc = s.encoding.name else s_enc = sys_enc end dst_enc = true if s_enc != dst_enc end s } if sys_enc && dst_enc dst.map!{|s| _toUTF8(s)} ret = TkCore::INTERP._merge_tklist(*dst) if TkCore::WITH_ENCODING if dst_enc.kind_of?(String) ret = _fromUTF8(ret, dst_enc) ret.force_encoding(dst_enc) else ret.force_encoding('utf-8') end else # without encoding if dst_enc.kind_of?(String) ret = _fromUTF8(ret, dst_enc) ret.instance_variable_set(:@encoding, dst_enc) else ret.instance_variable_set(:@encoding, 'utf-8') end end ret else TkCore::INTERP._merge_tklist(*dst) end end else ########################################################################### # use Ruby script version of split_list (traditional methods) ########################################################################### def tk_split_escstr(str, src_enc=true, dst_enc=true) return [] if str == "" list = [] token = nil escape = false brace = 0 str.split('').each {|c| brace += 1 if c == '{' && !escape brace -= 1 if c == '}' && !escape if brace == 0 && c == ' ' && !escape list << token.gsub(/^\{(.*)\}$/, '\1') if token token = nil else token = (token || "") << c end escape = (c == '\\' && !escape) } list << token.gsub(/^\{(.*)\}$/, '\1') if token list end def tk_split_sublist(str, depth=-1, src_enc=true, dst_enc=true) #return [] if str == "" #return [tk_split_sublist(str[1..-2])] if str =~ /^\{.*\}$/ #list = tk_split_escstr(str) if depth == 0 return "" if str == "" str = str[1..-2] if str =~ /^\{.*\}$/ list = [str] else return [] if str == [] return [tk_split_sublist(str[1..-2], depth - 1)] if str =~ /^\{.*\}$/ list = tk_split_escstr(str) end if list.size == 1 tk_tcl2ruby(list[0], nil, false) else list.collect{|token| tk_split_sublist(token, depth - 1)} end end def tk_split_list(str, depth=0, src_enc=true, dst_enc=true) return [] if str == "" tk_split_escstr(str).collect{|token| tk_split_sublist(token, depth - 1) } end def tk_split_simplelist(str, src_enc=true, dst_enc=true) return [] if str == "" list = [] token = nil escape = false brace = 0 str.split('').each {|c| if c == '\\' && !escape escape = true token = (token || "") << c if brace > 0 next end brace += 1 if c == '{' && !escape brace -= 1 if c == '}' && !escape if brace == 0 && c == ' ' && !escape list << token.gsub(/^\{(.*)\}$/, '\1') if token token = nil else token = (token || "") << c end escape = false } list << token.gsub(/^\{(.*)\}$/, '\1') if token list end def array2tk_list(ary, enc=nil) ary.collect{|e| if e.kind_of? Array "{#{array2tk_list(e, enc)}}" elsif e.kind_of? Hash # "{#{e.to_a.collect{|ee| array2tk_list(ee)}.join(' ')}}" e.each{|k,v| tmp_ary << "-#{_get_eval_string(k)}" << v } array2tk_list(tmp_ary, enc) else s = _get_eval_string(e, enc) (s.index(/\s/) || s.size == 0)? "{#{s}}": s end }.join(" ") end end private :tk_split_escstr, :tk_split_sublist private :tk_split_list, :tk_split_simplelist private :array2tk_list module_function :tk_split_escstr, :tk_split_sublist module_function :tk_split_list, :tk_split_simplelist module_function :array2tk_list private_class_method :tk_split_escstr, :tk_split_sublist private_class_method :tk_split_list, :tk_split_simplelist # private_class_method :array2tk_list =begin ### --> definition is moved to TkUtil module def _symbolkey2str(keys) h = {} keys.each{|key,value| h[key.to_s] = value} h end private :_symbolkey2str module_function :_symbolkey2str =end =begin ### --> definition is moved to TkUtil module # def hash_kv(keys, enc_mode = nil, conf = [], flat = false) def hash_kv(keys, enc_mode = nil, conf = nil) # Hash {key=>val, key=>val, ... } or Array [ [key, val], [key, val], ... ] # ==> Array ['-key', val, '-key', val, ... ] dst = [] if keys and keys != None keys.each{|k, v| #dst.push("-#{k}") dst.push('-' + k.to_s) if v != None # v = _get_eval_string(v, enc_mode) if (enc_mode || flat) v = _get_eval_string(v, enc_mode) if enc_mode dst.push(v) end } end if conf conf + dst else dst end end private :hash_kv module_function :hash_kv =end =begin ### --> definition is moved to TkUtil module def bool(val) case val when "1", 1, 'yes', 'true' true else false end end def number(val) case val when /^-?\d+$/ val.to_i when /^-?\d+\.?\d*(e[-+]?\d+)?$/ val.to_f else fail(ArgumentError, "invalid value for Number:'#{val}'") end end def string(val) if val == "{}" '' elsif val[0] == ?{ && val[-1] == ?} val[1..-2] else val end end def num_or_str(val) begin number(val) rescue ArgumentError string(val) end end =end def list(val, depth=0, enc=true) tk_split_list(val, depth, enc, enc) end def simplelist(val, src_enc=true, dst_enc=true) tk_split_simplelist(val, src_enc, dst_enc) end def window(val) if val =~ /^\./ #Tk_WINDOWS[val]? Tk_WINDOWS[val] : _genobj_for_tkwidget(val) TkCore::INTERP.tk_windows[val]? TkCore::INTERP.tk_windows[val] : _genobj_for_tkwidget(val) else nil end end def image_obj(val) if val =~ /^i(_\d+_)?\d+$/ TkImage::Tk_IMGTBL.mutex.synchronize{ TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val } else val end end def procedure(val) =begin if val =~ /^rb_out\S* (c(_\d+_)?\d+)/ #Tk_CMDTBL[$1] #TkCore::INTERP.tk_cmd_tbl[$1] TkCore::INTERP.tk_cmd_tbl[$1].cmd =end if val =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/ return TkCore::INTERP.tk_cmd_tbl[$4].cmd else #nil val end end private :bool, :number, :string, :num_or_str private :list, :simplelist, :window, :procedure module_function :bool, :number, :num_or_str, :string module_function :list, :simplelist, :window, :image_obj, :procedure def subst(str, *opts) # opts := :nobackslashes | :nocommands | novariables tk_call('subst', *(opts.collect{|opt| opt = opt.to_s (opt[0] == ?-)? opt: '-' << opt } << str)) end def _toUTF8(str, encoding = nil) TkCore::INTERP._toUTF8(str, encoding) end def _fromUTF8(str, encoding = nil) TkCore::INTERP._fromUTF8(str, encoding) end private :_toUTF8, :_fromUTF8 module_function :_toUTF8, :_fromUTF8 def _callback_entry_class?(cls) cls <= Proc || cls <= Method || cls <= TkCallbackEntry end private :_callback_entry_class? module_function :_callback_entry_class? def _callback_entry?(obj) obj.kind_of?(Proc) || obj.kind_of?(Method) || obj.kind_of?(TkCallbackEntry) end private :_callback_entry? module_function :_callback_entry? =begin ### --> definition is moved to TkUtil module def _get_eval_string(str, enc_mode = nil) return nil if str == None if str.kind_of?(TkObject) str = str.path elsif str.kind_of?(String) str = _toUTF8(str) if enc_mode elsif str.kind_of?(Symbol) str = str.id2name str = _toUTF8(str) if enc_mode elsif str.kind_of?(Hash) str = hash_kv(str, enc_mode).join(" ") elsif str.kind_of?(Array) str = array2tk_list(str) str = _toUTF8(str) if enc_mode elsif str.kind_of?(Proc) str = install_cmd(str) elsif str == nil str = "" elsif str == false str = "0" elsif str == true str = "1" elsif (str.respond_to?(:to_eval)) str = str.to_eval() str = _toUTF8(str) if enc_mode else str = str.to_s() || '' unless str.kind_of? String fail RuntimeError, "fail to convert the object to a string" end str = _toUTF8(str) if enc_mode end return str end =end =begin def _get_eval_string(obj, enc_mode = nil) case obj when Numeric obj.to_s when String (enc_mode)? _toUTF8(obj): obj when Symbol (enc_mode)? _toUTF8(obj.id2name): obj.id2name when TkObject obj.path when Hash hash_kv(obj, enc_mode).join(' ') when Array (enc_mode)? _toUTF8(array2tk_list(obj)): array2tk_list(obj) when Proc, Method, TkCallbackEntry install_cmd(obj) when false '0' when true '1' when nil '' when None nil else if (obj.respond_to?(:to_eval)) (enc_mode)? _toUTF8(obj.to_eval): obj.to_eval else begin obj = obj.to_s || '' rescue fail RuntimeError, "fail to convert object '#{obj}' to string" end (enc_mode)? _toUTF8(obj): obj end end end private :_get_eval_string module_function :_get_eval_string =end =begin ### --> definition is moved to TkUtil module def _get_eval_enc_str(obj) return obj if obj == None _get_eval_string(obj, true) end private :_get_eval_enc_str module_function :_get_eval_enc_str =end =begin ### --> obsolete def ruby2tcl(v, enc_mode = nil) if v.kind_of?(Hash) v = hash_kv(v) v.flatten! v.collect{|e|ruby2tcl(e, enc_mode)} else _get_eval_string(v, enc_mode) end end private :ruby2tcl =end =begin ### --> definition is moved to TkUtil module def _conv_args(args, enc_mode, *src_args) conv_args = [] src_args.each{|arg| conv_args << _get_eval_string(arg, enc_mode) unless arg == None # if arg.kind_of?(Hash) # arg.each{|k, v| # args << '-' + k.to_s # args << _get_eval_string(v, enc_mode) # } # elsif arg != None # args << _get_eval_string(arg, enc_mode) # end } args + conv_args end private :_conv_args =end def _curr_cmd_id #id = format("c%.4d", Tk_IDs[0]) id = "c" + TkCore::INTERP._ip_id_ + TkComm::Tk_IDs[0] end def _next_cmd_id TkComm::Tk_IDs.mutex.synchronize{ id = _curr_cmd_id #Tk_IDs[0] += 1 TkComm::Tk_IDs[0].succ! id } end private :_curr_cmd_id, :_next_cmd_id module_function :_curr_cmd_id, :_next_cmd_id def TkComm.install_cmd(cmd, local_cmdtbl=nil) return '' if cmd == '' begin ns = TkCore::INTERP._invoke_without_enc('namespace', 'current') ns = nil if ns == '::' # for backward compatibility rescue # probably, Tcl7.6 ns = nil end id = _next_cmd_id #Tk_CMDTBL[id] = cmd if cmd.kind_of?(TkCallbackEntry) TkCore::INTERP.tk_cmd_tbl[id] = cmd else TkCore::INTERP.tk_cmd_tbl[id] = TkCore::INTERP.get_cb_entry(cmd) end @cmdtbl = [] unless defined? @cmdtbl @cmdtbl.taint unless @cmdtbl.tainted? @cmdtbl.push id if local_cmdtbl && local_cmdtbl.kind_of?(Array) begin local_cmdtbl << id rescue Exception # ignore end end #return Kernel.format("rb_out %s", id); if ns 'rb_out' << TkCore::INTERP._ip_id_ << ' ' << ns << ' ' << id else 'rb_out' << TkCore::INTERP._ip_id_ << ' ' << id end end def TkComm.uninstall_cmd(id, local_cmdtbl=nil) #id = $1 if /rb_out\S* (c(_\d+_)?\d+)/ =~ id id = $4 if id =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/ if local_cmdtbl && local_cmdtbl.kind_of?(Array) begin local_cmdtbl.delete(id) rescue Exception # ignore end end @cmdtbl.delete(id) #Tk_CMDTBL.delete(id) TkCore::INTERP.tk_cmd_tbl.delete(id) end # private :install_cmd, :uninstall_cmd # module_function :install_cmd, :uninstall_cmd def install_cmd(cmd) TkComm.install_cmd(cmd, @cmdtbl) end def uninstall_cmd(id) TkComm.uninstall_cmd(id, @cmdtbl) end =begin def install_win(ppath,name=nil) if !name or name == '' #name = format("w%.4d", Tk_IDs[1]) #Tk_IDs[1] += 1 name = "w" + Tk_IDs[1] Tk_IDs[1].succ! end if name[0] == ?. @path = name.dup elsif !ppath or ppath == "." @path = Kernel.format(".%s", name); else @path = Kernel.format("%s.%s", ppath, name) end #Tk_WINDOWS[@path] = self TkCore::INTERP.tk_windows[@path] = self end =end def install_win(ppath,name=nil) if name if name == '' raise ArgumentError, "invalid wiget-name '#{name}'" end if name[0] == ?. @path = '' + name @path.freeze return TkCore::INTERP.tk_windows[@path] = self end else Tk_IDs.mutex.synchronize{ name = "w" + TkCore::INTERP._ip_id_ + Tk_IDs[1] Tk_IDs[1].succ! } end if !ppath or ppath == '.' @path = '.' + name else @path = ppath + '.' + name end @path.freeze TkCore::INTERP.tk_windows[@path] = self end def uninstall_win() #Tk_WINDOWS.delete(@path) TkCore::INTERP.tk_windows.delete(@path) end private :install_win, :uninstall_win def _epath(win) if win.kind_of?(TkObject) win.epath elsif win.respond_to?(:epath) win.epath else win end end private :_epath end # define TkComm module (step 2: event binding) module TkComm include TkEvent extend TkEvent def tk_event_sequence(context) if context.kind_of? TkVirtualEvent context = context.path end if context.kind_of? Array context = context.collect{|ev| if ev.kind_of? TkVirtualEvent ev.path else ev end }.join("><") end if /,/ =~ context context = context.split(/\s*,\s*/).join("><") else context end end def _bind_core(mode, what, context, cmd, *args) id = install_bind(cmd, *args) if cmd begin tk_call_without_enc(*(what + ["<#{tk_event_sequence(context)}>", mode + id])) rescue uninstall_cmd(id) if cmd fail end end def _bind(what, context, cmd, *args) _bind_core('', what, context, cmd, *args) end def _bind_append(what, context, cmd, *args) _bind_core('+', what, context, cmd, *args) end def _bind_remove(what, context) tk_call_without_enc(*(what + ["<#{tk_event_sequence(context)}>", ''])) end def _bindinfo(what, context=nil) if context if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! enum_obj = tk_call_without_enc(*what+["<#{tk_event_sequence(context)}>"]).each_line else enum_obj = tk_call_without_enc(*what+["<#{tk_event_sequence(context)}>"]) end enum_obj.collect {|cmdline| =begin if cmdline =~ /^rb_out\S* (c(?:_\d+_)?\d+)\s+(.*)$/ #[Tk_CMDTBL[$1], $2] [TkCore::INTERP.tk_cmd_tbl[$1], $2] =end if cmdline =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/ [TkCore::INTERP.tk_cmd_tbl[$4], $5] else cmdline end } else tk_split_simplelist(tk_call_without_enc(*what)).collect!{|seq| l = seq.scan(/<*[^<>]+>*/).collect!{|subseq| case (subseq) when /^<<[^<>]+>>$/ TkVirtualEvent.getobj(subseq[1..-2]) when /^<[^<>]+>$/ subseq[1..-2] else subseq.split('') end }.flatten (l.size == 1) ? l[0] : l } end end def _bind_core_for_event_class(klass, mode, what, context, cmd, *args) id = install_bind_for_event_class(klass, cmd, *args) if cmd begin tk_call_without_enc(*(what + ["<#{tk_event_sequence(context)}>", mode + id])) rescue uninstall_cmd(id) if cmd fail end end def _bind_for_event_class(klass, what, context, cmd, *args) _bind_core_for_event_class(klass, '', what, context, cmd, *args) end def _bind_append_for_event_class(klass, what, context, cmd, *args) _bind_core_for_event_class(klass, '+', what, context, cmd, *args) end def _bind_remove_for_event_class(klass, what, context) _bind_remove(what, context) end def _bindinfo_for_event_class(klass, what, context=nil) _bindinfo(what, context) end private :tk_event_sequence private :_bind_core, :_bind, :_bind_append, :_bind_remove, :_bindinfo private :_bind_core_for_event_class, :_bind_for_event_class, :_bind_append_for_event_class, :_bind_remove_for_event_class, :_bindinfo_for_event_class #def bind(tagOrClass, context, cmd=Proc.new, *args) # _bind(["bind", tagOrClass], context, cmd, *args) # tagOrClass #end def bind(tagOrClass, context, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind(["bind", tagOrClass], context, cmd, *args) tagOrClass end #def bind_append(tagOrClass, context, cmd=Proc.new, *args) # _bind_append(["bind", tagOrClass], context, cmd, *args) # tagOrClass #end def bind_append(tagOrClass, context, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append(["bind", tagOrClass], context, cmd, *args) tagOrClass end def bind_remove(tagOrClass, context) _bind_remove(['bind', tagOrClass], context) tagOrClass end def bindinfo(tagOrClass, context=nil) _bindinfo(['bind', tagOrClass], context) end #def bind_all(context, cmd=Proc.new, *args) # _bind(['bind', 'all'], context, cmd, *args) # TkBindTag::ALL #end def bind_all(context, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind(['bind', 'all'], context, cmd, *args) TkBindTag::ALL end #def bind_append_all(context, cmd=Proc.new, *args) # _bind_append(['bind', 'all'], context, cmd, *args) # TkBindTag::ALL #end def bind_append_all(context, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append(['bind', 'all'], context, cmd, *args) TkBindTag::ALL end def bind_remove_all(context) _bind_remove(['bind', 'all'], context) TkBindTag::ALL end def bindinfo_all(context=nil) _bindinfo(['bind', 'all'], context) end end module TkCore include TkComm extend TkComm WITH_RUBY_VM = Object.const_defined?(:VM) && ::VM.class == Class WITH_ENCODING = Object.const_defined?(:Encoding) && ::Encoding.class == Class unless self.const_defined? :RUN_EVENTLOOP_ON_MAIN_THREAD ### Ruby 1.9 !!!!!!!!!!!!!!!!!!!!!!!!!! RUN_EVENTLOOP_ON_MAIN_THREAD = false end unless self.const_defined? :INTERP if self.const_defined? :IP_NAME name = IP_NAME.to_s else #name = nil name = $0 end if self.const_defined? :IP_OPTS if IP_OPTS.kind_of?(Hash) opts = hash_kv(IP_OPTS).join(' ') else opts = IP_OPTS.to_s end else opts = '' end if !WITH_RUBY_VM || RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!! INTERP = TclTkIp.new(name, opts) else INTERP_MUTEX = Mutex.new INTERP_ROOT_CHECK = ConditionVariable.new INTERP_THREAD = Thread.new{ begin Thread.current[:interp] = interp = TclTkIp.new(name, opts) rescue => e Thread.current[:interp] = e raise e end Thread.current[:status] = nil #sleep begin Thread.current[:status] = TclTkLib.mainloop(true) rescue Exception=>e Thread.current[:status] = e ensure INTERP_MUTEX.synchronize{ INTERP_ROOT_CHECK.broadcast } end Thread.current[:status] = TclTkLib.mainloop(false) } until INTERP_THREAD[:interp] Thread.pass end # INTERP_THREAD.run raise INTERP_THREAD[:interp] if INTERP_THREAD[:interp].kind_of? Exception INTERP = INTERP_THREAD[:interp] end def INTERP.__getip self end INTERP.instance_eval{ # @tk_cmd_tbl = {}.taint @tk_cmd_tbl = Hash.new{|hash, key| fail IndexError, "unknown command ID '#{key}'" }.taint def @tk_cmd_tbl.[]=(idx,val) if self.has_key?(idx) && Thread.current.group != ThreadGroup::Default fail SecurityError,"cannot change the entried command" end super(idx,val) end @tk_windows = {}.taint @tk_table_list = [].taint @init_ip_env = [].taint # table of Procs @add_tk_procs = [].taint # table of [name, args, body] @cb_entry_class = Class.new(TkCallbackEntry){ class << self def inspect sprintf("#", self.__id__) end alias to_s inspect end def initialize(ip, cmd) @ip = ip @cmd = cmd end attr_reader :ip, :cmd def call(*args) @ip.cb_eval(@cmd, *args) end def inspect sprintf("#", self.__id__) end alias to_s inspect }.freeze } def INTERP.cb_entry_class @cb_entry_class end def INTERP.tk_cmd_tbl @tk_cmd_tbl end def INTERP.tk_windows @tk_windows end class Tk_OBJECT_TABLE def initialize(id) @id = id @mutex = Mutex.new end def mutex @mutex end def method_missing(m, *args, &b) TkCore::INTERP.tk_object_table(@id).__send__(m, *args, &b) end end def INTERP.tk_object_table(id) @tk_table_list[id] end def INTERP.create_table id = @tk_table_list.size (tbl = {}).tainted? || tbl.taint @tk_table_list << tbl # obj = Object.new # obj.instance_eval <<-EOD # def self.method_missing(m, *args) # TkCore::INTERP.tk_object_table(#{id}).send(m, *args) # end # EOD # return obj Tk_OBJECT_TABLE.new(id) end def INTERP.get_cb_entry(cmd) @cb_entry_class.new(__getip, cmd).freeze end def INTERP.cb_eval(cmd, *args) TkUtil._get_eval_string(TkUtil.eval_cmd(cmd, *args)) end def INTERP.init_ip_env(script = Proc.new) @init_ip_env << script script.call(self) end def INTERP.add_tk_procs(name, args = nil, body = nil) if name.kind_of?(Array) name.each{|param| self.add_tk_procs(*param)} else name = name.to_s @add_tk_procs << [name, args, body] self._invoke('proc', name, args, body) if args && body end end def INTERP.remove_tk_procs(*names) names.each{|name| name = name.to_s @add_tk_procs.delete_if{|elem| elem.kind_of?(Array) && elem[0].to_s == name } self._invoke('rename', name, '') } end def INTERP.init_ip_internal ip = self @init_ip_env.each{|script| script.call(ip)} @add_tk_procs.each{|name,args,body| ip._invoke('proc',name,args,body)} end end WIDGET_DESTROY_HOOK = '' INTERP._invoke_without_enc('event', 'add', "<#{WIDGET_DESTROY_HOOK}>", '') INTERP._invoke_without_enc('bind', 'all', "<#{WIDGET_DESTROY_HOOK}>", install_cmd(proc{|path| unless TkCore::INTERP.deleted? begin if (widget=TkCore::INTERP.tk_windows[path]) if widget.respond_to?(:__destroy_hook__) widget.__destroy_hook__ end end rescue Exception=>e p e if $DEBUG end end }) << ' %W') INTERP.add_tk_procs(TclTkLib::FINALIZE_PROC_NAME, '', "catch { bind all <#{WIDGET_DESTROY_HOOK}> {} }") INTERP.add_tk_procs('rb_out', 'ns args', <<-'EOL') if [regexp {^::} $ns] { set cmd {namespace eval $ns {ruby_cmd TkCore callback} $args} } else { set cmd {eval {ruby_cmd TkCore callback} $ns $args} } if {[set st [catch $cmd ret]] != 0} { #return -code $st $ret set idx [string first "\n\n" $ret] if {$idx > 0} { return -code $st \ -errorinfo [string range $ret [expr $idx + 2] \ [string length $ret]] \ [string range $ret 0 [expr $idx - 1]] } else { return -code $st $ret } } else { return $ret } EOL =begin INTERP.add_tk_procs('rb_out', 'args', <<-'EOL') if {[set st [catch {eval {ruby_cmd TkCore callback} $args} ret]] != 0} { #return -code $st $ret set idx [string first "\n\n" $ret] if {$idx > 0} { return -code $st \ -errorinfo [string range $ret [expr $idx + 2] \ [string length $ret]] \ [string range $ret 0 [expr $idx - 1]] } else { return -code $st $ret } } else { return $ret } EOL =end =begin INTERP.add_tk_procs('rb_out', 'args', <<-'EOL') #regsub -all {\\} $args {\\\\} args #regsub -all {!} $args {\\!} args #regsub -all "{" $args "\\{" args regsub -all {(\\|!|\{|\})} $args {\\\1} args if {[set st [catch {ruby [format "TkCore.callback %%Q!%s!" $args]} ret]] != 0} { #return -code $st $ret set idx [string first "\n\n" $ret] if {$idx > 0} { return -code $st \ -errorinfo [string range $ret [expr $idx + 2] \ [string length $ret]] \ [string range $ret 0 [expr $idx - 1]] } else { return -code $st $ret } } else { return $ret } EOL =end at_exit{ INTERP.remove_tk_procs(TclTkLib::FINALIZE_PROC_NAME) } EventFlag = TclTkLib::EventFlag def callback_break fail TkCallbackBreak, "Tk callback returns 'break' status" end def callback_continue fail TkCallbackContinue, "Tk callback returns 'continue' status" end def callback_return fail TkCallbackReturn, "Tk callback returns 'return' status" end def TkCore.callback(*arg) begin if TkCore::INTERP.tk_cmd_tbl.kind_of?(Hash) #TkCore::INTERP.tk_cmd_tbl[arg.shift].call(*arg) normal_ret = false ret = catch(:IRB_EXIT) do # IRB hack retval = TkCore::INTERP.tk_cmd_tbl[arg.shift].call(*arg) normal_ret = true retval end unless normal_ret # catch IRB_EXIT exit(ret) end ret end rescue SystemExit=>e exit(e.status) rescue Interrupt=>e fail(e) rescue Exception => e begin msg = _toUTF8(e.class.inspect) + ': ' + _toUTF8(e.message) + "\n" + "\n---< backtrace of Ruby side >-----\n" + _toUTF8(e.backtrace.join("\n")) + "\n---< backtrace of Tk side >-------" if TkCore::WITH_ENCODING msg.force_encoding('utf-8') else msg.instance_variable_set(:@encoding, 'utf-8') end rescue Exception msg = e.class.inspect + ': ' + e.message + "\n" + "\n---< backtrace of Ruby side >-----\n" + e.backtrace.join("\n") + "\n---< backtrace of Tk side >-------" end # TkCore::INTERP._set_global_var('errorInfo', msg) # fail(e) fail(e, msg) end end =begin def TkCore.callback(arg_str) # arg = tk_split_list(arg_str) arg = tk_split_simplelist(arg_str) #_get_eval_string(TkUtil.eval_cmd(Tk_CMDTBL[arg.shift], *arg)) #_get_eval_string(TkUtil.eval_cmd(TkCore::INTERP.tk_cmd_tbl[arg.shift], # *arg)) # TkCore::INTERP.tk_cmd_tbl[arg.shift].call(*arg) begin TkCore::INTERP.tk_cmd_tbl[arg.shift].call(*arg) rescue Exception => e raise(e, e.class.inspect + ': ' + e.message + "\n" + "\n---< backtrace of Ruby side >-----\n" + e.backtrace.join("\n") + "\n---< backtrace of Tk side >-------") end #=begin # cb_obj = TkCore::INTERP.tk_cmd_tbl[arg.shift] # unless $DEBUG # cb_obj.call(*arg) # else # begin # raise 'check backtrace' # rescue # # ignore backtrace before 'callback' # pos = -($!.backtrace.size) # end # begin # cb_obj.call(*arg) # rescue # trace = $!.backtrace # raise $!, "\n#{trace[0]}: #{$!.message} (#{$!.class})\n" + # "\tfrom #{trace[1..pos].join("\n\tfrom ")}" # end # end #=end end =end def load_cmd_on_ip(tk_cmd) bool(tk_call('auto_load', tk_cmd)) end def after(ms, cmd=Proc.new) cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(cmdid); ret}) after_id = tk_call_without_enc("after",ms,cmdid) after_id.instance_variable_set('@cmdid', cmdid) after_id end =begin def after(ms, cmd=Proc.new) crit_bup = Thread.critical Thread.critical = true myid = _curr_cmd_id cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(myid); ret}) Thread.critical = crit_bup tk_call_without_enc("after",ms,cmdid) # return id # return # if false #defined? Thread # Thread.start do # ms = Float(ms)/1000 # ms = 10 if ms == 0 # sleep ms/1000 # cmd.call # end # else # cmdid = install_cmd(cmd) # tk_call("after",ms,cmdid) # end end =end def after_idle(cmd=Proc.new) cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(cmdid); ret}) after_id = tk_call_without_enc('after','idle',cmdid) after_id.instance_variable_set('@cmdid', cmdid) after_id end =begin def after_idle(cmd=Proc.new) crit_bup = Thread.critical Thread.critical = true myid = _curr_cmd_id cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(myid); ret}) Thread.critical = crit_bup tk_call_without_enc('after','idle',cmdid) end =end def after_cancel(afterId) tk_call_without_enc('after','cancel',afterId) if (cmdid = afterId.instance_variable_get('@cmdid')) afterId.instance_variable_set('@cmdid', nil) uninstall_cmd(cmdid) end afterId end def windowingsystem tk_call_without_enc('tk', 'windowingsystem') end def scaling(scale=nil) if scale tk_call_without_enc('tk', 'scaling', scale) else Float(number(tk_call_without_enc('tk', 'scaling'))) end end def scaling_displayof(win, scale=nil) if scale tk_call_without_enc('tk', 'scaling', '-displayof', win, scale) else Float(number(tk_call_without_enc('tk', '-displayof', win, 'scaling'))) end end def inactive Integer(tk_call_without_enc('tk', 'inactive')) end def inactive_displayof(win) Integer(tk_call_without_enc('tk', 'inactive', '-displayof', win)) end def reset_inactive tk_call_without_enc('tk', 'inactive', 'reset') end def reset_inactive_displayof(win) tk_call_without_enc('tk', 'inactive', '-displayof', win, 'reset') end def appname(name=None) tk_call('tk', 'appname', name) end def appsend_deny tk_call('rename', 'send', '') end def appsend(interp, async, *args) if $SAFE >= 4 fail SecurityError, "cannot send Tk commands at level 4" elsif $SAFE >= 1 && args.find{|obj| obj.tainted?} fail SecurityError, "cannot send tainted Tk commands at level #{$SAFE}" end if async != true && async != false && async != nil args.unshift(async) async = false end if async tk_call('send', '-async', '--', interp, *args) else tk_call('send', '--', interp, *args) end end def rb_appsend(interp, async, *args) if $SAFE >= 4 fail SecurityError, "cannot send Ruby commands at level 4" elsif $SAFE >= 1 && args.find{|obj| obj.tainted?} fail SecurityError, "cannot send tainted Ruby commands at level #{$SAFE}" end if async != true && async != false && async != nil args.unshift(async) async = false end #args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"]/, '\\\\\&')} args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"\\]/, '\\\\\&')} # args.push(').to_s"') # appsend(interp, async, 'ruby "(', *args) args.push('}.call)"') appsend(interp, async, 'ruby "TkComm._get_eval_string(proc{', *args) end def appsend_displayof(interp, win, async, *args) if $SAFE >= 4 fail SecurityError, "cannot send Tk commands at level 4" elsif $SAFE >= 1 && args.find{|obj| obj.tainted?} fail SecurityError, "cannot send tainted Tk commands at level #{$SAFE}" end win = '.' if win == nil if async != true && async != false && async != nil args.unshift(async) async = false end if async tk_call('send', '-async', '-displayof', win, '--', interp, *args) else tk_call('send', '-displayor', win, '--', interp, *args) end end def rb_appsend_displayof(interp, win, async, *args) if $SAFE >= 4 fail SecurityError, "cannot send Ruby commands at level 4" elsif $SAFE >= 1 && args.find{|obj| obj.tainted?} fail SecurityError, "cannot send tainted Ruby commands at level #{$SAFE}" end win = '.' if win == nil if async != true && async != false && async != nil args.unshift(async) async = false end #args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"]/, '\\\\\&')} args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"\\]/, '\\\\\&')} # args.push(').to_s"') # appsend_displayof(interp, win, async, 'ruby "(', *args) args.push('}.call)"') appsend(interp, win, async, 'ruby "TkComm._get_eval_string(proc{', *args) end def info(*args) tk_call('info', *args) end def mainloop(check_root = true) if !TkCore::WITH_RUBY_VM || TkCore::RUN_EVENTLOOP_ON_MAIN_THREAD TclTkLib.mainloop(check_root) else ### Ruby 1.9 !!!!! begin TclTkLib.set_eventloop_window_mode(true) if check_root INTERP_MUTEX.synchronize{ INTERP_ROOT_CHECK.wait(INTERP_MUTEX) status = INTERP_THREAD[:status] if status INTERP_THREAD[:status] = nil raise status if status.kind_of?(Exception) end } else INTERP_THREAD.value end ensure TclTkLib.set_eventloop_window_mode(false) end end end def mainloop_thread? # true : current thread is mainloop # nil : there is no mainloop # false : mainloop is running on the other thread # ( At then, it is dangerous to call Tk interpreter directly. ) if !TkCore::WITH_RUBY_VM || TkCore::RUN_EVENTLOOP_ON_MAIN_THREAD ### Ruby 1.9 !!!!!!!!!!! TclTkLib.mainloop_thread? else Thread.current == INTERP_THREAD end end def mainloop_exist? TclTkLib.mainloop_thread? != nil end def is_mainloop? TclTkLib.mainloop_thread? == true end def mainloop_watchdog(check_root = true) # watchdog restarts mainloop when mainloop is dead TclTkLib.mainloop_watchdog(check_root) end def do_one_event(flag = TclTkLib::EventFlag::ALL) TclTkLib.do_one_event(flag) end def set_eventloop_tick(timer_tick) TclTkLib.set_eventloop_tick(timer_tick) end def get_eventloop_tick() TclTkLib.get_eventloop_tick end def set_no_event_wait(wait) TclTkLib.set_no_even_wait(wait) end def get_no_event_wait() TclTkLib.get_no_eventloop_wait end def set_eventloop_weight(loop_max, no_event_tick) TclTkLib.set_eventloop_weight(loop_max, no_event_tick) end def get_eventloop_weight() TclTkLib.get_eventloop_weight end def restart(app_name = nil, keys = {}) TkCore::INTERP.init_ip_internal tk_call('set', 'argv0', app_name) if app_name if keys.kind_of?(Hash) # tk_call('set', 'argc', keys.size * 2) tk_call('set', 'argv', hash_kv(keys).join(' ')) end INTERP.restart nil end def event_generate(win, context, keys=nil) #win = win.path if win.kind_of?(TkObject) if context.kind_of?(TkEvent::Event) context.generate(win, ((keys)? keys: {})) elsif keys tk_call_without_enc('event', 'generate', win, "<#{tk_event_sequence(context)}>", *hash_kv(keys, true)) else tk_call_without_enc('event', 'generate', win, "<#{tk_event_sequence(context)}>") end nil end def messageBox(keys) tk_call('tk_messageBox', *hash_kv(keys)) end def getOpenFile(keys = nil) tk_call('tk_getOpenFile', *hash_kv(keys)) end def getMultipleOpenFile(keys = nil) simplelist(tk_call('tk_getOpenFile', '-multiple', '1', *hash_kv(keys))) end def getSaveFile(keys = nil) tk_call('tk_getSaveFile', *hash_kv(keys)) end def getMultipleSaveFile(keys = nil) simplelist(tk_call('tk_getSaveFile', '-multiple', '1', *hash_kv(keys))) end def chooseColor(keys = nil) tk_call('tk_chooseColor', *hash_kv(keys)) end def chooseDirectory(keys = nil) tk_call('tk_chooseDirectory', *hash_kv(keys)) end def _ip_eval_core(enc_mode, cmd_string) case enc_mode when nil res = INTERP._eval(cmd_string) when false res = INTERP._eval_without_enc(cmd_string) when true res = INTERP._eval_with_enc(cmd_string) end if INTERP._return_value() != 0 fail RuntimeError, res, error_at end return res end private :_ip_eval_core def ip_eval(cmd_string) _ip_eval_core(nil, cmd_string) end def ip_eval_without_enc(cmd_string) _ip_eval_core(false, cmd_string) end def ip_eval_with_enc(cmd_string) _ip_eval_core(true, cmd_string) end def _ip_invoke_core(enc_mode, *args) case enc_mode when false res = INTERP._invoke_without_enc(*args) when nil res = INTERP._invoke(*args) when true res = INTERP._invoke_with_enc(*args) end if INTERP._return_value() != 0 fail RuntimeError, res, error_at end return res end private :_ip_invoke_core def ip_invoke(*args) _ip_invoke_core(nil, *args) end def ip_invoke_without_enc(*args) _ip_invoke_core(false, *args) end def ip_invoke_with_enc(*args) _ip_invoke_core(true, *args) end def _tk_call_core(enc_mode, *args) ### puts args.inspect if $DEBUG #args.collect! {|x|ruby2tcl(x, enc_mode)} #args.compact! #args.flatten! args = _conv_args([], enc_mode, *args) puts 'invoke args => ' + args.inspect if $DEBUG ### print "=> ", args.join(" ").inspect, "\n" if $DEBUG begin # res = INTERP._invoke(*args).taint # res = INTERP._invoke(enc_mode, *args) res = _ip_invoke_core(enc_mode, *args) # >>>>> _invoke returns a TAINTED string <<<<< rescue NameError => err # err = $! begin args.unshift "unknown" #res = INTERP._invoke(*args).taint #res = INTERP._invoke(enc_mode, *args) res = _ip_invoke_core(enc_mode, *args) # >>>>> _invoke returns a TAINTED string <<<<< rescue StandardError => err2 fail err2 unless /^invalid command/ =~ err2.message fail err end end if INTERP._return_value() != 0 fail RuntimeError, res, error_at end ### print "==> ", res.inspect, "\n" if $DEBUG return res end private :_tk_call_core def tk_call(*args) _tk_call_core(nil, *args) end def tk_call_without_enc(*args) _tk_call_core(false, *args) end def tk_call_with_enc(*args) _tk_call_core(true, *args) end def _tk_call_to_list_core(depth, arg_enc, val_enc, *args) args = _conv_args([], arg_enc, *args) val = _tk_call_core(false, *args) if !depth.kind_of?(Integer) || depth == 0 tk_split_simplelist(val, false, val_enc) else tk_split_list(val, depth, false, val_enc) end end #private :_tk_call_to_list_core def tk_call_to_list(*args) _tk_call_to_list_core(-1, nil, true, *args) end def tk_call_to_list_without_enc(*args) _tk_call_to_list_core(-1, false, false, *args) end def tk_call_to_list_with_enc(*args) _tk_call_to_list_core(-1, true, true, *args) end def tk_call_to_simplelist(*args) _tk_call_to_list_core(0, nil, true, *args) end def tk_call_to_simplelist_without_enc(*args) _tk_call_to_list_core(0, false, false, *args) end def tk_call_to_simplelist_with_enc(*args) _tk_call_to_list_core(0, true, true, *args) end end module Tk include TkCore extend Tk TCL_VERSION = INTERP._invoke_without_enc("info", "tclversion").freeze TCL_PATCHLEVEL = INTERP._invoke_without_enc("info", "patchlevel").freeze major, minor = TCL_VERSION.split('.') TCL_MAJOR_VERSION = major.to_i TCL_MINOR_VERSION = minor.to_i TK_VERSION = INTERP._invoke_without_enc("set", "tk_version").freeze TK_PATCHLEVEL = INTERP._invoke_without_enc("set", "tk_patchLevel").freeze major, minor = TK_VERSION.split('.') TK_MAJOR_VERSION = major.to_i TK_MINOR_VERSION = minor.to_i JAPANIZED_TK = (INTERP._invoke_without_enc("info", "commands", "kanji") != "").freeze def Tk.const_missing(sym) case(sym) when :TCL_LIBRARY INTERP._invoke_without_enc('global', 'tcl_library') INTERP._invoke("set", "tcl_library").freeze when :TK_LIBRARY INTERP._invoke_without_enc('global', 'tk_library') INTERP._invoke("set", "tk_library").freeze when :LIBRARY INTERP._invoke("info", "library").freeze #when :PKG_PATH, :PACKAGE_PATH, :TCL_PACKAGE_PATH # INTERP._invoke_without_enc('global', 'tcl_pkgPath') # tk_split_simplelist(INTERP._invoke('set', 'tcl_pkgPath')) #when :LIB_PATH, :LIBRARY_PATH, :TCL_LIBRARY_PATH # INTERP._invoke_without_enc('global', 'tcl_libPath') # tk_split_simplelist(INTERP._invoke('set', 'tcl_libPath')) when :PLATFORM, :TCL_PLATFORM if $SAFE >= 4 fail SecurityError, "can't get #{sym} when $SAFE >= 4" end INTERP._invoke_without_enc('global', 'tcl_platform') Hash[*tk_split_simplelist(INTERP._invoke_without_enc('array', 'get', 'tcl_platform'))] when :ENV INTERP._invoke_without_enc('global', 'env') Hash[*tk_split_simplelist(INTERP._invoke('array', 'get', 'env'))] #when :AUTO_PATH #<=== # tk_split_simplelist(INTERP._invoke('set', 'auto_path')) #when :AUTO_OLDPATH # tk_split_simplelist(INTERP._invoke('set', 'auto_oldpath')) when :AUTO_INDEX INTERP._invoke_without_enc('global', 'auto_index') Hash[*tk_split_simplelist(INTERP._invoke('array', 'get', 'auto_index'))] when :PRIV, :PRIVATE, :TK_PRIV priv = {} if INTERP._invoke_without_enc('info', 'vars', 'tk::Priv') != "" var_nam = 'tk::Priv' else var_nam = 'tkPriv' end INTERP._invoke_without_enc('global', var_nam) Hash[*tk_split_simplelist(INTERP._invoke('array', 'get', var_nam))].each{|k,v| k.freeze case v when /^-?\d+$/ priv[k] = v.to_i when /^-?\d+\.?\d*(e[-+]?\d+)?$/ priv[k] = v.to_f else priv[k] = v.freeze end } priv else raise NameError, 'uninitialized constant Tk::' + sym.id2name end end def Tk.errorInfo INTERP._invoke_without_enc('global', 'errorInfo') INTERP._invoke_without_enc('set', 'errorInfo') end def Tk.errorCode INTERP._invoke_without_enc('global', 'errorCode') code = tk_split_simplelist(INTERP._invoke_without_enc('set', 'errorCode')) case code[0] when 'CHILDKILLED', 'CHILDSTATUS', 'CHILDSUSP' begin pid = Integer(code[1]) code[1] = pid rescue end end code end def Tk.has_mainwindow? INTERP.has_mainwindow? end def root Tk::Root.new end def Tk.load_tclscript(file, enc=nil) if enc # TCL_VERSION >= 8.5 tk_call('source', '-encoding', enc, file) else tk_call('source', file) end end def Tk.load_tcllibrary(file, pkg_name=None, interp=None) tk_call('load', file, pkg_name, interp) end def Tk.unload_tcllibrary(*args) if args[-1].kind_of?(Hash) keys = _symbolkey2str(args.pop) nocomp = (keys['nocomplain'])? '-nocomplain': None keeplib = (keys['keeplibrary'])? '-keeplibrary': None tk_call('unload', nocomp, keeplib, '--', *args) else tk_call('unload', *args) end end def Tk.pkgconfig_list(mod) # Tk8.5 feature if mod.kind_of?(Module) if mod.respond_to?(:package_name) pkgname = mod.package_name elsif mod.const_defined?(:PACKAGE_NAME) pkgname = mod::PACKAGE_NAME else fail NotImplementedError, 'may not be a module for a Tcl extension' end else pkgname = mod.to_s end pkgname = '::' << pkgname unless pkgname =~ /^::/ tk_split_list(tk_call(pkgname + '::pkgconfig', 'list')) end def Tk.pkgconfig_get(mod, key) # Tk8.5 feature if mod.kind_of?(Module) if mod.respond_to?(:package_name) pkgname = mod.package_name else fail NotImplementedError, 'may not be a module for a Tcl extension' end else pkgname = mod.to_s end pkgname = '::' << pkgname unless pkgname =~ /^::/ tk_call(pkgname + '::pkgconfig', 'get', key) end def Tk.tcl_pkgconfig_list # Tk8.5 feature Tk.pkgconfig_list('::tcl') end def Tk.tcl_pkgconfig_get(key) # Tk8.5 feature Tk.pkgconfig_get('::tcl', key) end def Tk.tk_pkgconfig_list # Tk8.5 feature Tk.pkgconfig_list('::tk') end def Tk.tk_pkgconfig_get(key) # Tk8.5 feature Tk.pkgconfig_get('::tk', key) end def Tk.bell(nice = false) if nice tk_call_without_enc('bell', '-nice') else tk_call_without_enc('bell') end nil end def Tk.bell_on_display(win, nice = false) if nice tk_call_without_enc('bell', '-displayof', win, '-nice') else tk_call_without_enc('bell', '-displayof', win) end nil end def Tk.destroy(*wins) #tk_call_without_enc('destroy', *wins) tk_call_without_enc('destroy', *(wins.collect{|win| if win.kind_of?(TkWindow) win.epath else win end })) end def Tk.exit tk_call_without_enc('destroy', '.') end ################################################ def Tk.sleep(ms = nil, id = nil) if id var = (id.kind_of?(TkVariable))? id: TkVarAccess.new(id.to_s) else var = TkVariable.new end var.value = tk_call_without_enc('after', ms, proc{ var.value = 0 }) if ms var.thread_wait ms end def Tk.wakeup(id) ((id.kind_of?(TkVariable))? id: TkVarAccess.new(id.to_s)).value = 0 nil end ################################################ def Tk.pack(*args) TkPack.configure(*args) end def Tk.pack_forget(*args) TkPack.forget(*args) end def Tk.unpack(*args) TkPack.forget(*args) end def Tk.grid(*args) TkGrid.configure(*args) end def Tk.grid_forget(*args) TkGrid.forget(*args) end def Tk.ungrid(*args) TkGrid.forget(*args) end def Tk.place(*args) TkPlace.configure(*args) end def Tk.place_forget(*args) TkPlace.forget(*args) end def Tk.unplace(*args) TkPlace.forget(*args) end def Tk.update(idle=nil) if idle tk_call_without_enc('update', 'idletasks') else tk_call_without_enc('update') end end def Tk.update_idletasks update(true) end def update(idle=nil) # only for backward compatibility (This never be recommended to use) Tk.update(idle) self end # NOTE:: # If no eventloop-thread is running, "thread_update" method is same # to "update" method. Else, "thread_update" method waits to complete # idletask operation on the eventloop-thread. def Tk.thread_update(idle=nil) if idle tk_call_without_enc('thread_update', 'idletasks') else tk_call_without_enc('thread_update') end end def Tk.thread_update_idletasks thread_update(true) end def Tk.lower_window(win, below=None) tk_call('lower', _epath(win), _epath(below)) nil end def Tk.raise_window(win, above=None) tk_call('raise', _epath(win), _epath(above)) nil end def Tk.current_grabs(win = nil) if win window(tk_call_without_enc('grab', 'current', win)) else tk_split_list(tk_call_without_enc('grab', 'current')) end end def Tk.focus(display=nil) if display == nil window(tk_call_without_enc('focus')) else window(tk_call_without_enc('focus', '-displayof', display)) end end def Tk.focus_to(win, force=false) if force tk_call_without_enc('focus', '-force', win) else tk_call_without_enc('focus', win) end end def Tk.focus_lastfor(win) window(tk_call_without_enc('focus', '-lastfor', win)) end def Tk.focus_next(win) TkManageFocus.next(win) end def Tk.focus_prev(win) TkManageFocus.prev(win) end def Tk.strictMotif(mode=None) bool(tk_call_without_enc('set', 'tk_strictMotif', mode)) end def Tk.show_kinsoku(mode='both') begin if /^8\.*/ === TK_VERSION && JAPANIZED_TK tk_split_simplelist(tk_call('kinsoku', 'show', mode)) end rescue end end def Tk.add_kinsoku(chars, mode='both') begin if /^8\.*/ === TK_VERSION && JAPANIZED_TK tk_split_simplelist(tk_call('kinsoku', 'add', mode, *(chars.split('')))) else [] end rescue [] end end def Tk.delete_kinsoku(chars, mode='both') begin if /^8\.*/ === TK_VERSION && JAPANIZED_TK tk_split_simplelist(tk_call('kinsoku', 'delete', mode, *(chars.split('')))) end rescue end end def Tk.toUTF8(str, encoding = nil) _toUTF8(str, encoding) end def Tk.fromUTF8(str, encoding = nil) _fromUTF8(str, encoding) end end ########################################### # string with Tcl's encoding ########################################### module Tk def Tk.subst_utf_backslash(str) Tk::EncodedString.subst_utf_backslash(str) end def Tk.subst_tk_backslash(str) Tk::EncodedString.subst_tk_backslash(str) end def Tk.utf_to_backslash_sequence(str) Tk::EncodedString.utf_to_backslash_sequence(str) end def Tk.utf_to_backslash(str) Tk::EncodedString.utf_to_backslash_sequence(str) end def Tk.to_backslash_sequence(str) Tk::EncodedString.to_backslash_sequence(str) end end ########################################### # convert kanji string to/from utf-8 ########################################### if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK) module Tk module Encoding extend Encoding TkCommandNames = ['encoding'.freeze].freeze ############################################# if TkCore::WITH_ENCODING ### Ruby 1.9 RubyEncoding = ::Encoding # for saving GC cost #ENCNAMES_CMD = ['encoding'.freeze, 'names'.freeze] BINARY_NAME = 'binary'.freeze UTF8_NAME = 'utf-8'.freeze DEFAULT_EXTERNAL_NAME = RubyEncoding.default_external.name.freeze BINARY = RubyEncoding.find(BINARY_NAME) UNKNOWN = RubyEncoding.find('ASCII-8BIT') ### start of creating ENCODING_TABLE ENCODING_TABLE = TkCore::INTERP.encoding_table =begin ENCODING_TABLE = { 'binary' => BINARY, # 'UNKNOWN-8BIT' => UNKNOWN, } list = TkCore::INTERP._invoke_without_enc(ENCNAMES_CMD[0], ENCNAMES_CMD[1]) TkCore::INTERP._split_tklist(list).each{|name| begin enc = RubyEncoding.find(name) rescue ArgumentError case name when 'identity' enc = BINARY when 'shiftjis' enc = RubyEncoding.find('Shift_JIS') when 'unicode' enc = RubyEncoding.find('UTF-8') #if Tk.tk_call('set', 'tcl_platform(byteOrder)') =='littleEndian' # enc = RubyEncoding.find('UTF-16LE') #else # enc = RubyEncoding.find('UTF-16BE') #end when 'symbol' # single byte data enc = RubyEncoding.find('ASCII-8BIT') ### ??? else # unsupported on Ruby, but supported on Tk enc = TkCore::INTERP.create_dummy_encoding_for_tk(name) end end ENCODING_TABLE[name.freeze] = enc } =end =begin def ENCODING_TABLE.get_name(enc) orig_enc = enc # unles enc, use system default # 1st: Ruby/Tk default encoding # 2nd: Tcl/Tk default encoding # 3rd: Ruby's default_external enc ||= TkCore::INTERP.encoding enc ||= TclTkLib.encoding_system enc ||= DEFAULT_EXTERNAL_NAME if enc.kind_of?(RubyEncoding) # Ruby's Encoding object if (name = self.key(enc)) return name end # Is it new ? list = TkCore::INTERP._invoke_without_enc(ENCNAMES_CMD[0], ENCNAMES_CMD[1]) TkComm.simplelist(list).each{|name| if ((enc == RubyEncoding.find(name)) rescue false) # new relation!! update table self[name.freeze] = enc return name end } else # String or Symbol ? if self[name = enc.to_s] return name end # Is it new ? if (enc_obj = (RubyEncoding.find(name) rescue false)) list = TkCore::INTERP._invoke_without_enc(ENCNAMES_CMD[0], ENCNAMES_CMD[1]) if TkComm.simplelist(list).index(name) # Tk's encoding name ? self[name.freeze] = enc_obj # new relation!! update table return name else # Ruby's encoding name ? if (name = self.key(enc_obj)) return name end end end end fail ArgumentError, "unsupported Tk encoding '#{orig_enc}'" end def ENCODING_TABLE.get_obj(enc) # returns the encoding object. # If 'enc' is the encoding name on Tk only, it returns nil. ((obj = self[self.get_name(enc)]).kind_of?(RubyEncoding))? obj: nil end =end ### end of creating ENCODING_TABLE end ############################################# if TkCore::WITH_ENCODING ################################ ### Ruby 1.9 ################################ def force_default_encoding(mode) TkCore::INTERP.force_default_encoding = mode end def force_default_encoding? TkCore::INTERP.force_default_encoding? end def default_encoding=(enc) TkCore::INTERP.default_encoding = Tk::Encoding::ENCODING_TABLE.get_name(enc) end def encoding=(enc) TkCore::INTERP.encoding = Tk::Encoding::ENCODING_TABLE.get_name(enc) end def encoding_name Tk::Encoding::ENCODING_TABLE.get_name(TkCore::INTERP.encoding) end def encoding_obj Tk::Encoding::ENCODING_TABLE.get_obj(TkCore::INTERP.encoding) end alias encoding encoding_name alias default_encoding encoding_name def tk_encoding_names TkComm.simplelist(TkCore::INTERP._invoke_without_enc(Tk::Encoding::ENCNAMES_CMD[0], Tk::Encoding::ENCNAMES_CMD[1])) end def encoding_names self.tk_encoding_names.find_all{|name| Tk::Encoding::ENCODING_TABLE.get_name(name) rescue false } end def encoding_objs self.tk_encoding_names.map!{|name| Tk::Encoding::ENCODING_TABLE.get_obj(name) rescue nil }.compact end def encoding_system=(enc) TclTkLib.encoding_system = Tk::Encoding::ENCODING_TABLE.get_name(enc) end def encoding_system_name Tk::Encoding::ENCODING_TABLE.get_name(TclTkLib.encoding_system) end def encoding_system_obj Tk::Encoding::ENCODING_TABLE.get_obj(TclTkLib.encoding_system) end alias encoding_system encoding_system_name ################################ else ################################ ### Ruby 1.8- ################################ def force_default_encoding=(mode) true end def force_default_encoding? true end def default_encoding=(enc) TkCore::INTERP.default_encoding = enc end def encoding=(enc) TkCore::INTERP.encoding = enc end def encoding_obj TkCore::INTERP.encoding end def encoding_name TkCore::INTERP.encoding end alias encoding encoding_name alias default_encoding encoding_name def tk_encoding_names TkComm.simplelist(Tk.tk_call('encoding', 'names')) end def encoding_objs self.tk_encoding_names end def encoding_names self.tk_encoding_names end def encoding_system=(enc) TclTkLib.encoding_system = enc end def encoding_system_name TclTkLib.encoding_system end def encoding_system_obj TclTkLib.encoding_system end alias encoding_system encoding_system_name ################################ end def encoding_convertfrom(str, enc=nil) enc = encoding_system_name unless enc str = str.dup if TkCore::WITH_ENCODING if str.kind_of?(Tk::EncodedString) str.__instance_variable_set('@encoding', nil) else str.instance_variable_set('@encoding', nil) end str.force_encoding('binary') else str.instance_variable_set('@encoding', 'binary') end ret = TkCore::INTERP._invoke_without_enc('encoding', 'convertfrom', enc, str) if TkCore::WITH_ENCODING ret.force_encoding('utf-8') else Tk::UTF8_String.new(ret) end ret end alias encoding_convert_from encoding_convertfrom def encoding_convertto(str, enc=nil) # str must be a UTF-8 string enc = encoding_system_name unless enc ret = TkCore::INTERP._invoke_without_enc('encoding', 'convertto', enc, str) #ret.instance_variable_set('@encoding', 'binary') if TkCore::WITH_ENCODING #ret.force_encoding(Tk::Encoding::ENCODING_TABLE.get_obj('binary')) ret.force_encoding(Tk::Encoding::ENCODING_TABLE.get_obj(enc)) end ret end alias encoding_convert_to encoding_convertto def encoding_dirs # Tcl8.5 feature TkComm.simplelist(Tk.tk_call_without_enc('encoding', 'dirs')) end def encoding_dirs=(dir_list) # an array or a Tcl's list string # Tcl8.5 feature Tk.tk_call_without_enc('encoding', 'dirs', dir_list) end end extend Encoding end class TclTkIp def force_default_encoding=(mode) @force_default_encoding = (mode)? true: false end def force_default_encoding? @force_default_encoding ||= false end def default_encoding=(name) name = name.name if name.kind_of?(::Encoding) if Tk::WITH_ENCODING @encoding = name end # from tkencoding.rb by ttate@jaist.ac.jp #attr_accessor :encoding def encoding=(name) self.force_default_encoding = true # for comaptibility self.default_encoding = name end def encoding_name (@encoding)? @encoding.dup: nil end alias encoding encoding_name alias default_encoding encoding_name def encoding_obj if Tk::WITH_ENCODING Tk::Encoding.tcl2rb_encoding(@encoding) else (@encoding)? @encoding.dup: nil end end alias __toUTF8 _toUTF8 alias __fromUTF8 _fromUTF8 if Object.const_defined?(:Encoding) && ::Encoding.class == Class # with Encoding (Ruby 1.9+) # # use functions on Tcl as default. # but when unsupported encoding on Tcl, use methods on Ruby. # def _toUTF8(str, enc = nil) if enc # use given encoding begin enc_name = Tk::Encoding::ENCODING_TABLE.get_name(enc) rescue # unknown encoding for Tk -> try to convert encoding on Ruby str = str.dup.force_encoding(enc) str.encode!(Tk::Encoding::UTF8_NAME) # modify self !! return str # if no error, probably succeed converting end end enc_name ||= str.instance_variable_get(:@encoding) enc_name ||= Tk::Encoding::ENCODING_TABLE.get_name(str.encoding) rescue nil unless enc_name # str.encoding isn't supported by Tk -> try to convert on Ruby begin return str.encode(Tk::Encoding::UTF8_NAME) # new string rescue # error -> ignore, try to use default encoding of Ruby/Tk end end #enc_name ||= # Tk::Encoding::ENCODING_TABLE.get_name(Tk.encoding) rescue nil enc_name ||= Tk::Encoding::ENCODING_TABLE.get_name(nil) # is 'binary' encoding? if enc_name == Tk::Encoding::BINARY_NAME return str.dup.force_encoding(Tk::Encoding::BINARY_NAME) end # force default encoding? if ! str.kind_of?(Tk::EncodedString) && self.force_default_encoding? enc_name = Tk::Encoding::ENCODING_TABLE.get_name(Tk.default_encoding) end encstr = __toUTF8(str, enc_name) encstr.force_encoding(Tk::Encoding::UTF8_NAME) encstr end def _fromUTF8(str, enc = nil) # str must be UTF-8 or binary. enc_name = str.instance_variable_get(:@encoding) enc_name ||= Tk::Encoding::ENCODING_TABLE.get_name(str.encoding) rescue nil # is 'binary' encoding? if enc_name == Tk::Encoding::BINARY_NAME return str.dup.force_encoding(Tk::Encoding::BINARY_NAME) end # get target encoding name (if enc == nil, use default encoding) begin enc_name = Tk::Encoding::ENCODING_TABLE.get_name(enc) rescue # then, enc != nil # unknown encoding for Tk -> try to convert encoding on Ruby str = str.dup.force_encoding(Tk::Encoding::UTF8_NAME) str.encode!(enc) # modify self !! return str # if no error, probably succeed converting end encstr = __fromUTF8(str, enc_name) encstr.force_encoding(Tk::Encoding::ENCODING_TABLE.get_obj(enc_name)) encstr end ### else # without Encoding (Ruby 1.8) def _toUTF8(str, encoding = nil) __toUTF8(str, encoding) end def _fromUTF8(str, encoding = nil) __fromUTF8(str, encoding) end ### end alias __eval _eval alias __invoke _invoke def _eval(cmd) _fromUTF8(__eval(_toUTF8(cmd))) end def _invoke(*cmds) _fromUTF8(__invoke(*(cmds.collect{|cmd| _toUTF8(cmd)}))) end alias _eval_with_enc _eval alias _invoke_with_enc _invoke =begin #### --> definition is moved to TclTkIp module def _toUTF8(str, encoding = nil) # decide encoding if encoding encoding = encoding.to_s elsif str.kind_of?(Tk::EncodedString) && str.encoding != nil encoding = str.encoding.to_s elsif str.instance_variable_get(:@encoding) encoding = str.instance_variable_get(:@encoding).to_s elsif defined?(@encoding) && @encoding != nil encoding = @encoding.to_s else encoding = __invoke('encoding', 'system') end # convert case encoding when 'utf-8', 'binary' str else __toUTF8(str, encoding) end end def _fromUTF8(str, encoding = nil) unless encoding if defined?(@encoding) && @encoding != nil encoding = @encoding.to_s else encoding = __invoke('encoding', 'system') end end if str.kind_of?(Tk::EncodedString) if str.encoding == 'binary' str else __fromUTF8(str, encoding) end elsif str.instance_variable_get(:@encoding).to_s == 'binary' str else __fromUTF8(str, encoding) end end =end =begin def _eval(cmd) if defined?(@encoding) && @encoding != 'utf-8' ret = if cmd.kind_of?(Tk::EncodedString) case cmd.encoding when 'utf-8', 'binary' __eval(cmd) else __eval(_toUTF8(cmd, cmd.encoding)) end elsif cmd.instance_variable_get(:@encoding) == 'binary' __eval(cmd) else __eval(_toUTF8(cmd, @encoding)) end if ret.kind_of?(String) && ret.instance_variable_get(:@encoding) == 'binary' ret else _fromUTF8(ret, @encoding) end else __eval(cmd) end end def _invoke(*cmds) if defined?(@encoding) && @encoding != 'utf-8' cmds = cmds.collect{|cmd| if cmd.kind_of?(Tk::EncodedString) case cmd.encoding when 'utf-8', 'binary' cmd else _toUTF8(cmd, cmd.encoding) end elsif cmd.instance_variable_get(:@encoding) == 'binary' cmd else _toUTF8(cmd, @encoding) end } ret = __invoke(*cmds) if ret.kind_of?(String) && ret.instance_variable_get(:@encoding) == 'binary' ret else _fromUTF8(ret, @encoding) end else __invoke(*cmds) end end =end end module TclTkLib class << self def force_default_encoding=(mode) TkCore::INTERP.force_default_encoding = mode end def force_default_encoding? TkCore::INTERP.force_default_encoding? end def default_encoding=(name) TkCore::INTERP.default_encoding = name end alias _encoding encoding alias _encoding= encoding= def encoding=(name) name = name.name if name.kind_of?(::Encoding) if Tk::WITH_ENCODING TkCore::INTERP.encoding = name end def encoding_name TkCore::INTERP.encoding end alias encoding encoding_name alias default_encoding encoding_name def encoding_obj if Tk::WITH_ENCODING Tk::Encoding.tcl2rb_encoding(TkCore::INTERP.encoding) else TkCore::INTERP.encoding end end end end # estimate encoding unless TkCore::WITH_ENCODING case $KCODE when /^e/i # EUC Tk.encoding = 'euc-jp' Tk.encoding_system = 'euc-jp' when /^s/i # SJIS begin if Tk.encoding_system == 'cp932' Tk.encoding = 'cp932' else Tk.encoding = 'shiftjis' Tk.encoding_system = 'shiftjis' end rescue StandardError, NameError Tk.encoding = 'shiftjis' Tk.encoding_system = 'shiftjis' end when /^u/i # UTF8 Tk.encoding = 'utf-8' Tk.encoding_system = 'utf-8' else # NONE if defined? DEFAULT_TK_ENCODING Tk.encoding_system = DEFAULT_TK_ENCODING end begin Tk.encoding = Tk.encoding_system rescue StandardError, NameError Tk.encoding = 'utf-8' Tk.encoding_system = 'utf-8' end end else ### Ruby 1.9 !!!!!!!!!!!! loc_enc_obj = ::Encoding.find(::Encoding.locale_charmap) ext_enc_obj = ::Encoding.default_external tksys_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(Tk.encoding_system) # p [Tk.encoding, Tk.encoding_system, loc_enc_obj, ext_enc_obj] =begin if ext_enc_obj == Tk::Encoding::UNKNOWN if defind? DEFAULT_TK_ENCODING if DEFAULT_TK_ENCODING.kind_of?(::Encoding) tk_enc_name = DEFAULT_TK_ENCODING.name tksys_enc_name = DEFAULT_TK_ENCODING.name else tk_enc_name = DEFAULT_TK_ENCODING tksys_enc_name = DEFAULT_TK_ENCODING end else tk_enc_name = loc_enc_obj.name tksys_enc_name = loc_enc_obj.name end else tk_enc_name = ext_enc_obj.name tksys_enc_name = ext_enc_obj.name end # Tk.encoding = tk_enc_name Tk.default_encoding = tk_enc_name Tk.encoding_system = tksys_enc_name =end if ext_enc_obj == Tk::Encoding::UNKNOWN if loc_enc_obj == Tk::Encoding::UNKNOWN # use Tk.encoding_system else # use locale_charmap begin loc_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(loc_enc_obj) if loc_enc_name && loc_enc_name != tksys_enc_name # use locale_charmap Tk.encoding_system = loc_enc_name else # use Tk.encoding_system end rescue ArgumentError # unsupported encoding on Tk -> use Tk.encoding_system end end else begin ext_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(ext_enc_obj) if ext_enc_name && ext_enc_name != tksys_enc_name # use default_external Tk.encoding_system = ext_enc_name else # use Tk.encoding_system end rescue ArgumentError # unsupported encoding on Tk -> use Tk.encoding_system end end # setup Tk.encoding enc_name = nil begin default_def = DEFAULT_TK_ENCODING if ::Encoding.find(default_def.to_s) != Tk::Encoding::UNKNOWN enc_name = Tk::Encoding::ENCODING_TABLE.get_name(default_def) end rescue NameError # ignore enc_name = nil rescue ArgumentError enc_name = nil fail ArgumentError, "DEFAULT_TK_ENCODING has an unknown encoding #{default_def}" end unless enc_name if ext_enc_obj == Tk::Encoding::UNKNOWN if loc_enc_obj == Tk::Encoding::UNKNOWN # use Tk.encoding_system enc_name = tksys_enc_name else # use locale_charmap begin loc_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(loc_enc_obj) if loc_enc_name && loc_enc_name != tksys_enc_name # use locale_charmap enc_name = loc_enc_name else # use Tk.encoding_system enc_name = tksys_enc_name end rescue ArgumentError # unsupported encoding on Tk -> use Tk.encoding_system enc_name = tksys_enc_name end end else begin ext_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(ext_enc_obj) if ext_enc_name && ext_enc_name != tksys_enc_name # use default_external enc_name = ext_enc_name else # use Tk.encoding_system enc_name = tksys_enc_name end rescue ArgumentError # unsupported encoding on Tk -> use Tk.encoding_system enc_name = tksys_enc_name end end end Tk.default_encoding = (enc_name)? enc_name: tksys_enc_name end else # dummy methods module Tk module Encoding extend Encoding def force_default_encoding=(mode) nil end def force_default_encoding? nil end def default_encoding=(enc) nil end def default_encoding nil end def encoding=(name) nil end def encoding nil end def encoding_names nil end def encoding_system nil end def encoding_system=(enc) nil end def encoding_convertfrom(str, enc=None) str end alias encoding_convert_from encoding_convertfrom def encoding_convertto(str, enc=None) str end alias encoding_convert_to encoding_convertto def encoding_dirs nil end def encoding_dirs=(dir_array) nil end end extend Encoding end class TclTkIp attr_accessor :encoding alias __eval _eval alias __invoke _invoke alias _eval_with_enc _eval alias _invoke_with_enc _invoke end end module TkBindCore #def bind(context, cmd=Proc.new, *args) # Tk.bind(self, context, cmd, *args) #end def bind(context, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end Tk.bind(self, context, cmd, *args) end #def bind_append(context, cmd=Proc.new, *args) # Tk.bind_append(self, context, cmd, *args) #end def bind_append(context, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end Tk.bind_append(self, context, cmd, *args) end def bind_remove(context) Tk.bind_remove(self, context) end def bindinfo(context=nil) Tk.bindinfo(self, context) end end module TkTreatFont def __font_optkeys ['font'] end private :__font_optkeys def __pathname self.path end private :__pathname ################################ def font_configinfo(key = nil) optkeys = __font_optkeys if key && !optkeys.find{|opt| opt.to_s == key.to_s} fail ArgumentError, "unknown font option name `#{key}'" end win, tag = __pathname.split(':') if key pathname = [win, tag, key].join(';') TkFont.used_on(pathname) || TkFont.init_widget_font(pathname, *__confinfo_cmd) elsif optkeys.size == 1 pathname = [win, tag, optkeys[0]].join(';') TkFont.used_on(pathname) || TkFont.init_widget_font(pathname, *__confinfo_cmd) else fonts = {} optkeys.each{|key| key = key.to_s pathname = [win, tag, key].join(';') fonts[key] = TkFont.used_on(pathname) || TkFont.init_widget_font(pathname, *__confinfo_cmd) } fonts end end alias fontobj font_configinfo def font_configure(slot) pathname = __pathname slot = _symbolkey2str(slot) __font_optkeys.each{|optkey| optkey = optkey.to_s l_optkey = 'latin' << optkey a_optkey = 'ascii' << optkey k_optkey = 'kanji' << optkey if slot.key?(optkey) fnt = slot.delete(optkey) if fnt.kind_of?(TkFont) slot.delete(l_optkey) slot.delete(a_optkey) slot.delete(k_optkey) fnt.call_font_configure([pathname, optkey], *(__config_cmd << {})) next else if fnt if (slot.key?(l_optkey) || slot.key?(a_optkey) || slot.key?(k_optkey)) fnt = TkFont.new(fnt) lfnt = slot.delete(l_optkey) lfnt = slot.delete(a_optkey) if slot.key?(a_optkey) kfnt = slot.delete(k_optkey) fnt.latin_replace(lfnt) if lfnt fnt.kanji_replace(kfnt) if kfnt fnt.call_font_configure([pathname, optkey], *(__config_cmd << {})) next else fnt = hash_kv(fnt) if fnt.kind_of?(Hash) unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ tk_call(*(__config_cmd << "-#{optkey}" << fnt)) else begin tk_call(*(__config_cmd << "-#{optkey}" << fnt)) rescue # ignore end end end end next end end lfnt = slot.delete(l_optkey) lfnt = slot.delete(a_optkey) if slot.key?(a_optkey) kfnt = slot.delete(k_optkey) if lfnt && kfnt TkFont.new(lfnt, kfnt).call_font_configure([pathname, optkey], *(__config_cmd << {})) elsif lfnt latinfont_configure([lfnt, optkey]) elsif kfnt kanjifont_configure([kfnt, optkey]) end } # configure other (without font) options tk_call(*(__config_cmd.concat(hash_kv(slot)))) if slot != {} self end def latinfont_configure(ltn, keys=nil) if ltn.kind_of?(Array) key = ltn[1] ltn = ltn[0] else key = nil end optkeys = __font_optkeys if key && !optkeys.find{|opt| opt.to_s == key.to_s} fail ArgumentError, "unknown font option name `#{key}'" end win, tag = __pathname.split(':') optkeys = [key] if key optkeys.each{|optkey| optkey = optkey.to_s pathname = [win, tag, optkey].join(';') if (fobj = TkFont.used_on(pathname)) fobj = TkFont.new(fobj) # create a new TkFont object elsif Tk::JAPANIZED_TK fobj = fontobj # create a new TkFont object else ltn = hash_kv(ltn) if ltn.kind_of?(Hash) unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ tk_call(*(__config_cmd << "-#{optkey}" << ltn)) else begin tk_call(*(__config_cmd << "-#{optkey}" << ltn)) rescue => e # ignore end end next end if fobj.kind_of?(TkFont) if ltn.kind_of?(TkFont) conf = {} ltn.latin_configinfo.each{|key,val| conf[key] = val} if keys fobj.latin_configure(conf.update(keys)) else fobj.latin_configure(conf) end else fobj.latin_replace(ltn) end end fobj.call_font_configure([pathname, optkey], *(__config_cmd << {})) } self end alias asciifont_configure latinfont_configure def kanjifont_configure(knj, keys=nil) if knj.kind_of?(Array) key = knj[1] knj = knj[0] else key = nil end optkeys = __font_optkeys if key && !optkeys.find{|opt| opt.to_s == key.to_s} fail ArgumentError, "unknown font option name `#{key}'" end win, tag = __pathname.split(':') optkeys = [key] if key optkeys.each{|optkey| optkey = optkey.to_s pathname = [win, tag, optkey].join(';') if (fobj = TkFont.used_on(pathname)) fobj = TkFont.new(fobj) # create a new TkFont object elsif Tk::JAPANIZED_TK fobj = fontobj # create a new TkFont object else knj = hash_kv(knj) if knj.kind_of?(Hash) unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ tk_call(*(__config_cmd << "-#{optkey}" << knj)) else begin tk_call(*(__config_cmd << "-#{optkey}" << knj)) rescue => e # ignore end end next end if fobj.kind_of?(TkFont) if knj.kind_of?(TkFont) conf = {} knj.kanji_configinfo.each{|key,val| conf[key] = val} if keys fobj.kanji_configure(conf.update(keys)) else fobj.kanji_configure(conf) end else fobj.kanji_replace(knj) end end fobj.call_font_configure([pathname, optkey], *(__config_cmd << {})) } self end def font_copy(win, wintag=nil, winkey=nil, targetkey=nil) if wintag if winkey fnt = win.tagfontobj(wintag, winkey).dup else fnt = win.tagfontobj(wintag).dup end else if winkey fnt = win.fontobj(winkey).dup else fnt = win.fontobj.dup end end if targetkey fnt.call_font_configure([__pathname, targetkey], *(__config_cmd << {})) else fnt.call_font_configure(__pathname, *(__config_cmd << {})) end self end def latinfont_copy(win, wintag=nil, winkey=nil, targetkey=nil) if targetkey fontobj(targetkey).dup.call_font_configure([__pathname, targetkey], *(__config_cmd << {})) else fontobj.dup.call_font_configure(__pathname, *(__config_cmd << {})) end if wintag if winkey fontobj.latin_replace(win.tagfontobj(wintag, winkey).latin_font_id) else fontobj.latin_replace(win.tagfontobj(wintag).latin_font_id) end else if winkey fontobj.latin_replace(win.fontobj(winkey).latin_font_id) else fontobj.latin_replace(win.fontobj.latin_font_id) end end self end alias asciifont_copy latinfont_copy def kanjifont_copy(win, wintag=nil, winkey=nil, targetkey=nil) if targetkey fontobj(targetkey).dup.call_font_configure([__pathname, targetkey], *(__config_cmd << {})) else fontobj.dup.call_font_configure(__pathname, *(__config_cmd << {})) end if wintag if winkey fontobj.kanji_replace(win.tagfontobj(wintag, winkey).kanji_font_id) else fontobj.kanji_replace(win.tagfontobj(wintag).kanji_font_id) end else if winkey fontobj.kanji_replace(win.fontobj(winkey).kanji_font_id) else fontobj.kanji_replace(win.fontobj.kanji_font_id) end end self end end module TkConfigMethod include TkUtil include TkTreatFont def TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ @mode || false end def TkConfigMethod.__set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode) fail SecurityError, "can't change the mode" if $SAFE>=4 @mode = (mode)? true: false end def __cget_cmd [self.path, 'cget'] end private :__cget_cmd def __config_cmd [self.path, 'configure'] end private :__config_cmd def __confinfo_cmd __config_cmd end private :__confinfo_cmd def __configinfo_struct {:key=>0, :alias=>1, :db_name=>1, :db_class=>2, :default_value=>3, :current_value=>4} end private :__configinfo_struct def __optkey_aliases {} end private :__optkey_aliases def __numval_optkeys [] end private :__numval_optkeys def __numstrval_optkeys [] end private :__numstrval_optkeys def __boolval_optkeys ['exportselection', 'jump', 'setgrid', 'takefocus'] end private :__boolval_optkeys def __strval_optkeys [ 'text', 'label', 'show', 'data', 'file', 'activebackground', 'activeforeground', 'background', 'disabledforeground', 'disabledbackground', 'foreground', 'highlightbackground', 'highlightcolor', 'insertbackground', 'selectbackground', 'selectforeground', 'troughcolor' ] end private :__strval_optkeys def __listval_optkeys [] end private :__listval_optkeys def __numlistval_optkeys [] end private :__numlistval_optkeys def __tkvariable_optkeys ['variable', 'textvariable'] end private :__tkvariable_optkeys def __val2ruby_optkeys # { key=>proc, ... } # The method is used to convert a opt-value to a ruby's object. # When get the value of the option "key", "proc.call(value)" is called. {} end private :__val2ruby_optkeys def __ruby2val_optkeys # { key=>proc, ... } # The method is used to convert a ruby's object to a opt-value. # When set the value of the option "key", "proc.call(value)" is called. # That is, "-#{key} #{proc.call(value)}". {} end private :__ruby2val_optkeys def __methodcall_optkeys # { key=>method, ... } # The method is used to both of get and set. # Usually, the 'key' will not be a widget option. {} end private :__methodcall_optkeys def __keyonly_optkeys # { def_key=>undef_key or nil, ... } {} end private :__keyonly_optkeys def __conv_keyonly_opts(keys) return keys unless keys.kind_of?(Hash) keyonly = __keyonly_optkeys keys2 = {} keys.each{|k, v| optkey = keyonly.find{|kk,vv| kk.to_s == k.to_s} if optkey defkey, undefkey = optkey if v keys2[defkey.to_s] = None elsif undefkey keys2[undefkey.to_s] = None else # remove key end else keys2[k.to_s] = v end } keys2 end private :__conv_keyonly_opts def config_hash_kv(keys, enc_mode = nil, conf = nil) hash_kv(__conv_keyonly_opts(keys), enc_mode, conf) end ################################ def [](id) cget(id) end def []=(id, val) configure(id, val) val end def __cget_core(slot) orig_slot = slot slot = slot.to_s if slot.length == 0 fail ArgumentError, "Invalid option `#{orig_slot.inspect}'" end alias_name, real_name = __optkey_aliases.find{|k, v| k.to_s == slot} if real_name slot = real_name.to_s end if ( method = _symbolkey2str(__val2ruby_optkeys())[slot] ) optval = tk_call_without_enc(*(__cget_cmd << "-#{slot}")) begin return method.call(optval) rescue => e warn("Warning:: #{e.message} (when #{method}.call(#{optval.inspect})") if $DEBUG return optval end end if ( method = _symbolkey2str(__methodcall_optkeys)[slot] ) return self.__send__(method) end case slot when /^(#{__numval_optkeys.join('|')})$/ begin number(tk_call_without_enc(*(__cget_cmd << "-#{slot}"))) rescue nil end when /^(#{__numstrval_optkeys.join('|')})$/ num_or_str(tk_call_without_enc(*(__cget_cmd << "-#{slot}"))) when /^(#{__boolval_optkeys.join('|')})$/ begin bool(tk_call_without_enc(*(__cget_cmd << "-#{slot}"))) rescue nil end when /^(#{__listval_optkeys.join('|')})$/ simplelist(tk_call_without_enc(*(__cget_cmd << "-#{slot}"))) when /^(#{__numlistval_optkeys.join('|')})$/ conf = tk_call_without_enc(*(__cget_cmd << "-#{slot}")) if conf =~ /^[0-9+-]/ list(conf) else conf end when /^(#{__strval_optkeys.join('|')})$/ _fromUTF8(tk_call_without_enc(*(__cget_cmd << "-#{slot}"))) when /^(|latin|ascii|kanji)(#{__font_optkeys.join('|')})$/ fontcode = $1 fontkey = $2 fnt = tk_tcl2ruby(tk_call_without_enc(*(__cget_cmd << "-#{fontkey}")), true) unless fnt.kind_of?(TkFont) fnt = fontobj(fontkey) end if fontcode == 'kanji' && JAPANIZED_TK && TK_VERSION =~ /^4\.*/ # obsolete; just for compatibility fnt.kanji_font else fnt end when /^(#{__tkvariable_optkeys.join('|')})$/ v = tk_call_without_enc(*(__cget_cmd << "-#{slot}")) (v.empty?)? nil: TkVarAccess.new(v) else tk_tcl2ruby(tk_call_without_enc(*(__cget_cmd << "-#{slot}")), true) end end private :__cget_core def cget(slot) unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ __cget_core(slot) else begin __cget_core(slot) rescue => e if current_configinfo.has_key?(slot.to_s) # error on known option fail e else # unknown option nil end end end end def cget_strict(slot) # never use TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ __cget_core(slot) end def __configure_core(slot, value=None) if slot.kind_of? Hash slot = _symbolkey2str(slot) __optkey_aliases.each{|alias_name, real_name| alias_name = alias_name.to_s if slot.has_key?(alias_name) slot[real_name.to_s] = slot.delete(alias_name) end } __methodcall_optkeys.each{|key, method| value = slot.delete(key.to_s) self.__send__(method, value) if value } __ruby2val_optkeys.each{|key, method| key = key.to_s slot[key] = method.call(slot[key]) if slot.has_key?(key) } __keyonly_optkeys.each{|defkey, undefkey| conf = slot.find{|kk, vv| kk == defkey.to_s} if conf k, v = conf if v slot[k] = None else slot[undefkey.to_s] = None if undefkey slot.delete(k) end end } if (slot.find{|k, v| k =~ /^(|latin|ascii|kanji)(#{__font_optkeys.join('|')})$/}) font_configure(slot) elsif slot.size > 0 tk_call(*(__config_cmd.concat(hash_kv(slot)))) end else orig_slot = slot slot = slot.to_s if slot.length == 0 fail ArgumentError, "Invalid option `#{orig_slot.inspect}'" end alias_name, real_name = __optkey_aliases.find{|k, v| k.to_s == slot} if real_name slot = real_name.to_s end if ( conf = __keyonly_optkeys.find{|k, v| k.to_s == slot} ) defkey, undefkey = conf if value tk_call(*(__config_cmd << "-#{defkey}")) elsif undefkey tk_call(*(__config_cmd << "-#{undefkey}")) end elsif ( method = _symbolkey2str(__ruby2val_optkeys)[slot] ) tk_call(*(__config_cmd << "-#{slot}" << method.call(value))) elsif ( method = _symbolkey2str(__methodcall_optkeys)[slot] ) self.__send__(method, value) elsif (slot =~ /^(|latin|ascii|kanji)(#{__font_optkeys.join('|')})$/) if value == None fontobj($2) else font_configure({slot=>value}) end else tk_call(*(__config_cmd << "-#{slot}" << value)) end end self end private :__configure_core def __check_available_configure_options(keys) availables = self.current_configinfo.keys # add non-standard keys availables |= __font_optkeys.map{|k| [k.to_s, "latin#{k}", "ascii#{k}", "kanji#{k}"] }.flatten availables |= __methodcall_optkeys.keys.map{|k| k.to_s} availables |= __keyonly_optkeys.keys.map{|k| k.to_s} keys = _symbolkey2str(keys) keys.delete_if{|k, v| !(availables.include?(k))} end def configure(slot, value=None) unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ __configure_core(slot, value) else if slot.kind_of?(Hash) begin __configure_core(slot) rescue slot = __check_available_configure_options(slot) __configure_core(slot) unless slot.empty? end else begin __configure_core(slot, value) rescue => e if current_configinfo.has_key?(slot.to_s) # error on known option fail e else # unknown option nil end end end end self end def configure_cmd(slot, value) configure(slot, install_cmd(value)) end def __configinfo_core(slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__font_optkeys.join('|')})$/) fontkey = $2 # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{fontkey}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{fontkey}")), false, true) conf[__configinfo_struct[:key]] = conf[__configinfo_struct[:key]][1..-1] if ( ! __configinfo_struct[:alias] \ || conf.size > __configinfo_struct[:alias] + 1 ) fnt = conf[__configinfo_struct[:default_value]] if TkFont.is_system_font?(fnt) conf[__configinfo_struct[:default_value]] = TkNamedFont.new(fnt) end conf[__configinfo_struct[:current_value]] = fontobj(fontkey) elsif ( __configinfo_struct[:alias] \ && conf.size == __configinfo_struct[:alias] + 1 \ && conf[__configinfo_struct[:alias]][0] == ?- ) conf[__configinfo_struct[:alias]] = conf[__configinfo_struct[:alias]][1..-1] end conf else if slot slot = slot.to_s alias_name, real_name = __optkey_aliases.find{|k, v| k.to_s == slot} if real_name slot = real_name.to_s end case slot when /^(#{__val2ruby_optkeys().keys.join('|')})$/ method = _symbolkey2str(__val2ruby_optkeys())[slot] conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd() << "-#{slot}")), false, true) if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) optval = conf[__configinfo_struct[:default_value]] begin val = method.call(optval) rescue => e warn("Warning:: #{e.message} (when #{method}.call(#{optval.inspect})") if $DEBUG val = optval end conf[__configinfo_struct[:default_value]] = val end if ( conf[__configinfo_struct[:current_value]] ) optval = conf[__configinfo_struct[:current_value]] begin val = method.call(optval) rescue => e warn("Warning:: #{e.message} (when #{method}.call(#{optval.inspect})") if $DEBUG val = optval end conf[__configinfo_struct[:current_value]] = val end when /^(#{__methodcall_optkeys.keys.join('|')})$/ method = _symbolkey2str(__methodcall_optkeys)[slot] return [slot, '', '', '', self.__send__(method)] when /^(#{__numval_optkeys.join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true) if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]]) begin conf[__configinfo_struct[:default_value]] = number(conf[__configinfo_struct[:default_value]]) rescue conf[__configinfo_struct[:default_value]] = nil end end if ( conf[__configinfo_struct[:current_value]] ) begin conf[__configinfo_struct[:current_value]] = number(conf[__configinfo_struct[:current_value]]) rescue conf[__configinfo_struct[:current_value]] = nil end end when /^(#{__numstrval_optkeys.join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true) if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]]) conf[__configinfo_struct[:default_value]] = num_or_str(conf[__configinfo_struct[:default_value]]) end if ( conf[__configinfo_struct[:current_value]] ) conf[__configinfo_struct[:current_value]] = num_or_str(conf[__configinfo_struct[:current_value]]) end when /^(#{__boolval_optkeys.join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true) if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]]) begin conf[__configinfo_struct[:default_value]] = bool(conf[__configinfo_struct[:default_value]]) rescue conf[__configinfo_struct[:default_value]] = nil end end if ( conf[__configinfo_struct[:current_value]] ) begin conf[__configinfo_struct[:current_value]] = bool(conf[__configinfo_struct[:current_value]]) rescue conf[__configinfo_struct[:current_value]] = nil end end when /^(#{__listval_optkeys.join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true) if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]]) conf[__configinfo_struct[:default_value]] = simplelist(conf[__configinfo_struct[:default_value]]) end if ( conf[__configinfo_struct[:current_value]] ) conf[__configinfo_struct[:current_value]] = simplelist(conf[__configinfo_struct[:current_value]]) end when /^(#{__numlistval_optkeys.join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true) if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] \ && conf[__configinfo_struct[:default_value]] =~ /^[0-9]/ ) conf[__configinfo_struct[:default_value]] = list(conf[__configinfo_struct[:default_value]]) end if ( conf[__configinfo_struct[:current_value]] \ && conf[__configinfo_struct[:current_value]] =~ /^[0-9]/ ) conf[__configinfo_struct[:current_value]] = list(conf[__configinfo_struct[:current_value]]) end when /^(#{__strval_optkeys.join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true) when /^(#{__tkvariable_optkeys.join('|')})$/ conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true) if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]]) v = conf[__configinfo_struct[:default_value]] if v.empty? conf[__configinfo_struct[:default_value]] = nil else conf[__configinfo_struct[:default_value]] = TkVarAccess.new(v) end end if ( conf[__configinfo_struct[:current_value]] ) v = conf[__configinfo_struct[:current_value]] if v.empty? conf[__configinfo_struct[:current_value]] = nil else conf[__configinfo_struct[:current_value]] = TkVarAccess.new(v) end end else # conf = tk_split_list(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")))) conf = tk_split_list(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), 0, false, true) end conf[__configinfo_struct[:key]] = conf[__configinfo_struct[:key]][1..-1] if ( __configinfo_struct[:alias] \ && conf.size == __configinfo_struct[:alias] + 1 \ && conf[__configinfo_struct[:alias]][0] == ?- ) conf[__configinfo_struct[:alias]] = conf[__configinfo_struct[:alias]][1..-1] end conf else # ret = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*__confinfo_cmd))).collect{|conflist| # conf = tk_split_simplelist(conflist) ret = tk_split_simplelist(tk_call_without_enc(*__confinfo_cmd), false, false).collect{|conflist| conf = tk_split_simplelist(conflist, false, true) conf[__configinfo_struct[:key]] = conf[__configinfo_struct[:key]][1..-1] optkey = conf[__configinfo_struct[:key]] case optkey when /^(#{__val2ruby_optkeys().keys.join('|')})$/ method = _symbolkey2str(__val2ruby_optkeys())[optkey] if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) optval = conf[__configinfo_struct[:default_value]] begin val = method.call(optval) rescue => e warn("Warning:: #{e.message} (when #{method}.call(#{optval.inspect})") if $DEBUG val = optval end conf[__configinfo_struct[:default_value]] = val end if ( conf[__configinfo_struct[:current_value]] ) optval = conf[__configinfo_struct[:current_value]] begin val = method.call(optval) rescue => e warn("Warning:: #{e.message} (when #{method}.call(#{optval.inspect})") if $DEBUG val = optval end conf[__configinfo_struct[:current_value]] = val end when /^(#{__strval_optkeys.join('|')})$/ # do nothing when /^(#{__numval_optkeys.join('|')})$/ if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) begin conf[__configinfo_struct[:default_value]] = number(conf[__configinfo_struct[:default_value]]) rescue conf[__configinfo_struct[:default_value]] = nil end end if ( conf[__configinfo_struct[:current_value]] ) begin conf[__configinfo_struct[:current_value]] = number(conf[__configinfo_struct[:current_value]]) rescue conf[__configinfo_struct[:current_value]] = nil end end when /^(#{__numstrval_optkeys.join('|')})$/ if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) conf[__configinfo_struct[:default_value]] = num_or_str(conf[__configinfo_struct[:default_value]]) end if ( conf[__configinfo_struct[:current_value]] ) conf[__configinfo_struct[:current_value]] = num_or_str(conf[__configinfo_struct[:current_value]]) end when /^(#{__boolval_optkeys.join('|')})$/ if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) begin conf[__configinfo_struct[:default_value]] = bool(conf[__configinfo_struct[:default_value]]) rescue conf[__configinfo_struct[:default_value]] = nil end end if ( conf[__configinfo_struct[:current_value]] ) begin conf[__configinfo_struct[:current_value]] = bool(conf[__configinfo_struct[:current_value]]) rescue conf[__configinfo_struct[:current_value]] = nil end end when /^(#{__listval_optkeys.join('|')})$/ if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) conf[__configinfo_struct[:default_value]] = simplelist(conf[__configinfo_struct[:default_value]]) end if ( conf[__configinfo_struct[:current_value]] ) conf[__configinfo_struct[:current_value]] = simplelist(conf[__configinfo_struct[:current_value]]) end when /^(#{__numlistval_optkeys.join('|')})$/ if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] \ && conf[__configinfo_struct[:default_value]] =~ /^[0-9]/ ) conf[__configinfo_struct[:default_value]] = list(conf[__configinfo_struct[:default_value]]) end if ( conf[__configinfo_struct[:current_value]] \ && conf[__configinfo_struct[:current_value]] =~ /^[0-9]/ ) conf[__configinfo_struct[:current_value]] = list(conf[__configinfo_struct[:current_value]]) end when /^(#{__tkvariable_optkeys.join('|')})$/ if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) v = conf[__configinfo_struct[:default_value]] if v.empty? conf[__configinfo_struct[:default_value]] = nil else conf[__configinfo_struct[:default_value]] = TkVarAccess.new(v) end end if ( conf[__configinfo_struct[:current_value]] ) v = conf[__configinfo_struct[:current_value]] if v.empty? conf[__configinfo_struct[:current_value]] = nil else conf[__configinfo_struct[:current_value]] = TkVarAccess.new(v) end end else if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) if conf[__configinfo_struct[:default_value]].index('{') conf[__configinfo_struct[:default_value]] = tk_split_list(conf[__configinfo_struct[:default_value]]) else conf[__configinfo_struct[:default_value]] = tk_tcl2ruby(conf[__configinfo_struct[:default_value]]) end end if conf[__configinfo_struct[:current_value]] if conf[__configinfo_struct[:current_value]].index('{') conf[__configinfo_struct[:current_value]] = tk_split_list(conf[__configinfo_struct[:current_value]]) else conf[__configinfo_struct[:current_value]] = tk_tcl2ruby(conf[__configinfo_struct[:current_value]]) end end end if ( __configinfo_struct[:alias] \ && conf.size == __configinfo_struct[:alias] + 1 \ && conf[__configinfo_struct[:alias]][0] == ?- ) conf[__configinfo_struct[:alias]] = conf[__configinfo_struct[:alias]][1..-1] end conf } __font_optkeys.each{|optkey| optkey = optkey.to_s fontconf = ret.assoc(optkey) if fontconf && fontconf.size > 2 ret.delete_if{|inf| inf[0] =~ /^(|latin|ascii|kanji)#{optkey}$/} fnt = fontconf[__configinfo_struct[:default_value]] if TkFont.is_system_font?(fnt) fontconf[__configinfo_struct[:default_value]] \ = TkNamedFont.new(fnt) end fontconf[__configinfo_struct[:current_value]] = fontobj(optkey) ret.push(fontconf) end } __methodcall_optkeys.each{|optkey, method| ret << [optkey.to_s, '', '', '', self.__send__(method)] } ret end end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__font_optkeys.join('|')})$/) fontkey = $2 # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{fontkey}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{fontkey}")), false, true) conf[__configinfo_struct[:key]] = conf[__configinfo_struct[:key]][1..-1] if ( ! __configinfo_struct[:alias] \ || conf.size > __configinfo_struct[:alias] + 1 ) fnt = conf[__configinfo_struct[:default_value]] if TkFont.is_system_font?(fnt) conf[__configinfo_struct[:default_value]] = TkNamedFont.new(fnt) end conf[__configinfo_struct[:current_value]] = fontobj(fontkey) { conf.shift => conf } elsif ( __configinfo_struct[:alias] \ && conf.size == __configinfo_struct[:alias] + 1 ) if conf[__configinfo_struct[:alias]][0] == ?- conf[__configinfo_struct[:alias]] = conf[__configinfo_struct[:alias]][1..-1] end { conf[0] => conf[1] } else { conf.shift => conf } end else if slot slot = slot.to_s alias_name, real_name = __optkey_aliases.find{|k, v| k.to_s == slot} if real_name slot = real_name.to_s end case slot when /^(#{__val2ruby_optkeys().keys.join('|')})$/ method = _symbolkey2str(__val2ruby_optkeys())[slot] conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true) if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) optval = conf[__configinfo_struct[:default_value]] begin val = method.call(optval) rescue => e warn("Warning:: #{e.message} (when #{method}.call(#{optval.inspect})") if $DEBUG val = optval end conf[__configinfo_struct[:default_value]] = val end if ( conf[__configinfo_struct[:current_value]] ) optval = conf[__configinfo_struct[:current_value]] begin val = method.call(optval) rescue => e warn("Warning:: #{e.message} (when #{method}.call(#{optval.inspect})") if $DEBUG val = optval end conf[__configinfo_struct[:current_value]] = val end when /^(#{__methodcall_optkeys.keys.join('|')})$/ method = _symbolkey2str(__methodcall_optkeys)[slot] return {slot => ['', '', '', self.__send__(method)]} when /^(#{__numval_optkeys.join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true) if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) begin conf[__configinfo_struct[:default_value]] = number(conf[__configinfo_struct[:default_value]]) rescue conf[__configinfo_struct[:default_value]] = nil end end if ( conf[__configinfo_struct[:current_value]] ) begin conf[__configinfo_struct[:current_value]] = number(conf[__configinfo_struct[:current_value]]) rescue conf[__configinfo_struct[:current_value]] = nil end end when /^(#{__numstrval_optkeys.join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true) if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) conf[__configinfo_struct[:default_value]] = num_or_str(conf[__configinfo_struct[:default_value]]) end if ( conf[__configinfo_struct[:current_value]] ) conf[__configinfo_struct[:current_value]] = num_or_str(conf[__configinfo_struct[:current_value]]) end when /^(#{__boolval_optkeys.join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true) if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) begin conf[__configinfo_struct[:default_value]] = bool(conf[__configinfo_struct[:default_value]]) rescue conf[__configinfo_struct[:default_value]] = nil end end if ( conf[__configinfo_struct[:current_value]] ) begin conf[__configinfo_struct[:current_value]] = bool(conf[__configinfo_struct[:current_value]]) rescue conf[__configinfo_struct[:current_value]] = nil end end when /^(#{__listval_optkeys.join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true) if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) conf[__configinfo_struct[:default_value]] = simplelist(conf[__configinfo_struct[:default_value]]) end if ( conf[__configinfo_struct[:current_value]] ) conf[__configinfo_struct[:current_value]] = simplelist(conf[__configinfo_struct[:current_value]]) end when /^(#{__numlistval_optkeys.join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true) if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] \ && conf[__configinfo_struct[:default_value]] =~ /^[0-9]/ ) conf[__configinfo_struct[:default_value]] = list(conf[__configinfo_struct[:default_value]]) end if ( conf[__configinfo_struct[:current_value]] \ && conf[__configinfo_struct[:current_value]] =~ /^[0-9]/ ) conf[__configinfo_struct[:current_value]] = list(conf[__configinfo_struct[:current_value]]) end when /^(#{__tkvariable_optkeys.join('|')})$/ conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true) if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) v = conf[__configinfo_struct[:default_value]] if v.empty? conf[__configinfo_struct[:default_value]] = nil else conf[__configinfo_struct[:default_value]] = TkVarAccess.new(v) end end if ( conf[__configinfo_struct[:current_value]] ) v = conf[__configinfo_struct[:current_value]] if v.empty? conf[__configinfo_struct[:current_value]] = nil else conf[__configinfo_struct[:current_value]] = TkVarAccess.new(v) end end when /^(#{__strval_optkeys.join('|')})$/ # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")))) conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true) else # conf = tk_split_list(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")))) conf = tk_split_list(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), 0, false, true) end conf[__configinfo_struct[:key]] = conf[__configinfo_struct[:key]][1..-1] if ( __configinfo_struct[:alias] \ && conf.size == __configinfo_struct[:alias] + 1 ) if conf[__configinfo_struct[:alias]][0] == ?- conf[__configinfo_struct[:alias]] = conf[__configinfo_struct[:alias]][1..-1] end { conf[0] => conf[1] } else { conf.shift => conf } end else ret = {} # tk_split_simplelist(_fromUTF8(tk_call_without_enc(*__confinfo_cmd))).each{|conflist| # conf = tk_split_simplelist(conflist) tk_split_simplelist(tk_call_without_enc(*__confinfo_cmd), false, false).each{|conflist| conf = tk_split_simplelist(conflist, false, true) conf[__configinfo_struct[:key]] = conf[__configinfo_struct[:key]][1..-1] optkey = conf[__configinfo_struct[:key]] case optkey when /^(#{__val2ruby_optkeys().keys.join('|')})$/ method = _symbolkey2str(__val2ruby_optkeys())[optkey] if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) optval = conf[__configinfo_struct[:default_value]] begin val = method.call(optval) rescue => e warn("Warning:: #{e.message} (when #{method}.call(#{optval.inspect})") if $DEBUG val = optval end conf[__configinfo_struct[:default_value]] = val end if ( conf[__configinfo_struct[:current_value]] ) optval = conf[__configinfo_struct[:current_value]] begin val = method.call(optval) rescue => e warn("Warning:: #{e.message} (when #{method}.call(#{optval.inspect})") if $DEBUG val = optval end conf[__configinfo_struct[:current_value]] = val end when /^(#{__strval_optkeys.join('|')})$/ # do nothing when /^(#{__numval_optkeys.join('|')})$/ if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) begin conf[__configinfo_struct[:default_value]] = number(conf[__configinfo_struct[:default_value]]) rescue conf[__configinfo_struct[:default_value]] = nil end end if ( conf[__configinfo_struct[:current_value]] ) begin conf[__configinfo_struct[:current_value]] = number(conf[__configinfo_struct[:current_value]]) rescue conf[__configinfo_struct[:current_value]] = nil end end when /^(#{__numstrval_optkeys.join('|')})$/ if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) conf[__configinfo_struct[:default_value]] = num_or_str(conf[__configinfo_struct[:default_value]]) end if ( conf[__configinfo_struct[:current_value]] ) conf[__configinfo_struct[:current_value]] = num_or_str(conf[__configinfo_struct[:current_value]]) end when /^(#{__boolval_optkeys.join('|')})$/ if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) begin conf[__configinfo_struct[:default_value]] = bool(conf[__configinfo_struct[:default_value]]) rescue conf[__configinfo_struct[:default_value]] = nil end end if ( conf[__configinfo_struct[:current_value]] ) begin conf[__configinfo_struct[:current_value]] = bool(conf[__configinfo_struct[:current_value]]) rescue conf[__configinfo_struct[:current_value]] = nil end end when /^(#{__listval_optkeys.join('|')})$/ if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) conf[__configinfo_struct[:default_value]] = simplelist(conf[__configinfo_struct[:default_value]]) end if ( conf[__configinfo_struct[:current_value]] ) conf[__configinfo_struct[:current_value]] = simplelist(conf[__configinfo_struct[:current_value]]) end when /^(#{__numlistval_optkeys.join('|')})$/ if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] \ && conf[__configinfo_struct[:default_value]] =~ /^[0-9]/ ) conf[__configinfo_struct[:default_value]] = list(conf[__configinfo_struct[:default_value]]) end if ( conf[__configinfo_struct[:current_value]] \ && conf[__configinfo_struct[:current_value]] =~ /^[0-9]/ ) conf[__configinfo_struct[:current_value]] = list(conf[__configinfo_struct[:current_value]]) end when /^(#{__tkvariable_optkeys.join('|')})$/ if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) v = conf[__configinfo_struct[:default_value]] if v.empty? conf[__configinfo_struct[:default_value]] = nil else conf[__configinfo_struct[:default_value]] = TkVarAccess.new end end if ( conf[__configinfo_struct[:current_value]] ) v = conf[__configinfo_struct[:current_value]] if v.empty? conf[__configinfo_struct[:current_value]] = nil else conf[__configinfo_struct[:current_value]] = TkVarAccess.new end end else if ( __configinfo_struct[:default_value] \ && conf[__configinfo_struct[:default_value]] ) if conf[__configinfo_struct[:default_value]].index('{') conf[__configinfo_struct[:default_value]] = tk_split_list(conf[__configinfo_struct[:default_value]]) else conf[__configinfo_struct[:default_value]] = tk_tcl2ruby(conf[__configinfo_struct[:default_value]]) end end if conf[__configinfo_struct[:current_value]] if conf[__configinfo_struct[:current_value]].index('{') conf[__configinfo_struct[:current_value]] = tk_split_list(conf[__configinfo_struct[:current_value]]) else conf[__configinfo_struct[:current_value]] = tk_tcl2ruby(conf[__configinfo_struct[:current_value]]) end end end if ( __configinfo_struct[:alias] \ && conf.size == __configinfo_struct[:alias] + 1 ) if conf[__configinfo_struct[:alias]][0] == ?- conf[__configinfo_struct[:alias]] = conf[__configinfo_struct[:alias]][1..-1] end ret[conf[0]] = conf[1] else ret[conf.shift] = conf end } __font_optkeys.each{|optkey| optkey = optkey.to_s fontconf = ret[optkey] if fontconf.kind_of?(Array) ret.delete(optkey) ret.delete('latin' << optkey) ret.delete('ascii' << optkey) ret.delete('kanji' << optkey) fnt = fontconf[__configinfo_struct[:default_value]] if TkFont.is_system_font?(fnt) fontconf[__configinfo_struct[:default_value]] \ = TkNamedFont.new(fnt) end fontconf[__configinfo_struct[:current_value]] = fontobj(optkey) ret[optkey] = fontconf end } __methodcall_optkeys.each{|optkey, method| ret[optkey.to_s] = ['', '', '', self.__send__(method)] } ret end end end end private :__configinfo_core def configinfo(slot = nil) if slot && TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ begin __configinfo_core(slot) rescue Array.new(__configinfo_struct.values.max).unshift(slot.to_s) end else __configinfo_core(slot) end end def current_configinfo(slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if slot org_slot = slot begin conf = configinfo(slot) if ( ! __configinfo_struct[:alias] \ || conf.size > __configinfo_struct[:alias] + 1 ) return {conf[0] => conf[-1]} end slot = conf[__configinfo_struct[:alias]] end while(org_slot != slot) fail RuntimeError, "there is a configure alias loop about '#{org_slot}'" else ret = {} configinfo().each{|conf| if ( ! __configinfo_struct[:alias] \ || conf.size > __configinfo_struct[:alias] + 1 ) ret[conf[0]] = conf[-1] end } ret end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY ret = {} configinfo(slot).each{|key, conf| ret[key] = conf[-1] if conf.kind_of?(Array) } ret end end end class TkObject definition is moved to TkUtil module # def path # @path # end def epath @path end def to_eval @path end def tk_send(cmd, *rest) tk_call(path, cmd, *rest) end def tk_send_without_enc(cmd, *rest) tk_call_without_enc(path, cmd, *rest) end def tk_send_with_enc(cmd, *rest) tk_call_with_enc(path, cmd, *rest) end # private :tk_send, :tk_send_without_enc, :tk_send_with_enc def tk_send_to_list(cmd, *rest) tk_call_to_list(path, cmd, *rest) end def tk_send_to_list_without_enc(cmd, *rest) tk_call_to_list_without_enc(path, cmd, *rest) end def tk_send_to_list_with_enc(cmd, *rest) tk_call_to_list_with_enc(path, cmd, *rest) end def tk_send_to_simplelist(cmd, *rest) tk_call_to_simplelist(path, cmd, *rest) end def tk_send_to_simplelist_without_enc(cmd, *rest) tk_call_to_simplelist_without_enc(path, cmd, *rest) end def tk_send_to_simplelist_with_enc(cmd, *rest) tk_call_to_simplelist_with_enc(path, cmd, *rest) end def method_missing(id, *args) name = id.id2name case args.length when 1 if name[-1] == ?= configure name[0..-2], args[0] args[0] else configure name, args[0] self end when 0 begin cget(name) rescue if self.kind_of?(TkWindow) fail NameError, "unknown option '#{id}' for #{self.inspect} (deleted widget?)" else super(id, *args) end # fail NameError, # "undefined local variable or method `#{name}' for #{self.to_s}", # error_at end else super(id, *args) # fail NameError, "undefined method `#{name}' for #{self.to_s}", error_at end end =begin def [](id) cget(id) end def []=(id, val) configure(id, val) val end =end def event_generate(context, keys=nil) if context.kind_of?(TkEvent::Event) context.generate(self, ((keys)? keys: {})) elsif keys #tk_call('event', 'generate', path, # "<#{tk_event_sequence(context)}>", *hash_kv(keys)) tk_call_without_enc('event', 'generate', path, "<#{tk_event_sequence(context)}>", *hash_kv(keys, true)) else #tk_call('event', 'generate', path, "<#{tk_event_sequence(context)}>") tk_call_without_enc('event', 'generate', path, "<#{tk_event_sequence(context)}>") end end def tk_trace_variable(v) #unless v.kind_of?(TkVariable) # fail(ArgumentError, "type error (#{v.class}); must be TkVariable object") #end v end private :tk_trace_variable def destroy #tk_call 'trace', 'vdelete', @tk_vn, 'w', @var_id if @var_id end end class TkWindow If TkCommandNames[0] is a string (not a null string), ## assume the string is a Tcl/Tk's create command of the widget class. WidgetClassName = ''.freeze # WidgetClassNames[WidgetClassName] = self ## ==> If self is a widget class, entry to the WidgetClassNames table. def self.to_eval self::WidgetClassName end def initialize(parent=nil, keys=nil) if parent.kind_of? Hash keys = _symbolkey2str(parent) parent = keys.delete('parent') widgetname = keys.delete('widgetname') install_win(if parent then parent.path end, widgetname) without_creating = keys.delete('without_creating') # if without_creating && !widgetname # fail ArgumentError, # "if set 'without_creating' to true, need to define 'widgetname'" # end elsif keys keys = _symbolkey2str(keys) widgetname = keys.delete('widgetname') install_win(if parent then parent.path end, widgetname) without_creating = keys.delete('without_creating') # if without_creating && !widgetname # fail ArgumentError, # "if set 'without_creating' to true, need to define 'widgetname'" # end else install_win(if parent then parent.path end) end if self.method(:create_self).arity == 0 p 'create_self has no arg' if $DEBUG create_self unless without_creating if keys # tk_call @path, 'configure', *hash_kv(keys) configure(keys) end else p 'create_self has args' if $DEBUG fontkeys = {} methodkeys = {} if keys #['font', 'kanjifont', 'latinfont', 'asciifont'].each{|key| # fontkeys[key] = keys.delete(key) if keys.key?(key) #} __font_optkeys.each{|key| fkey = key.to_s fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey) fkey = "kanji#{key}" fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey) fkey = "latin#{key}" fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey) fkey = "ascii#{key}" fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey) } __optkey_aliases.each{|alias_name, real_name| alias_name = alias_name.to_s if keys.has_key?(alias_name) keys[real_name.to_s] = keys.delete(alias_name) end } __methodcall_optkeys.each{|key| key = key.to_s methodkeys[key] = keys.delete(key) if keys.key?(key) } __ruby2val_optkeys.each{|key, method| key = key.to_s keys[key] = method.call(keys[key]) if keys.has_key?(key) } end if without_creating && keys #configure(keys) configure(__conv_keyonly_opts(keys)) else #create_self(keys) create_self(__conv_keyonly_opts(keys)) end font_configure(fontkeys) unless fontkeys.empty? configure(methodkeys) unless methodkeys.empty? end end def create_self(keys) # may need to override begin cmd = self.class::TkCommandNames[0] fail unless (cmd.kind_of?(String) && cmd.length > 0) rescue fail RuntimeError, "class #{self.class} may be an abstract class" end if keys and keys != None unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ tk_call_without_enc(cmd, @path, *hash_kv(keys, true)) else begin tk_call_without_enc(cmd, @path, *hash_kv(keys, true)) rescue => e tk_call_without_enc(cmd, @path) keys = __check_available_configure_options(keys) unless keys.empty? begin # try to configure configure(keys) rescue # fail => includes options adaptable when creattion only? begin tk_call_without_enc('destroy', @path) rescue # cannot rescue options error fail e else # re-create widget tk_call_without_enc(cmd, @path, *hash_kv(keys, true)) end end end end end else tk_call_without_enc(cmd, @path) end end private :create_self def inspect if @@WIDGET_INSPECT_FULL super else str = super str[0..(str.index(' '))] << '@path=' << @path.inspect << '>' end end def exist? TkWinfo.exist?(self) end def bind_class @db_class || self.class() end def database_classname TkWinfo.classname(self) end def database_class name = database_classname() if WidgetClassNames[name] WidgetClassNames[name] else TkDatabaseClass.new(name) end end def self.database_classname self::WidgetClassName end def self.database_class WidgetClassNames[self::WidgetClassName] end def pack(keys = nil) #tk_call_without_enc('pack', epath, *hash_kv(keys, true)) if keys TkPack.configure(self, keys) else TkPack.configure(self) end self end def pack_in(target, keys = nil) if keys keys = keys.dup keys['in'] = target else keys = {'in'=>target} end #tk_call 'pack', epath, *hash_kv(keys) TkPack.configure(self, keys) self end def pack_forget #tk_call_without_enc('pack', 'forget', epath) TkPack.forget(self) self end alias unpack pack_forget def pack_config(slot, value=None) #if slot.kind_of? Hash # tk_call 'pack', 'configure', epath, *hash_kv(slot) #else # tk_call 'pack', 'configure', epath, "-#{slot}", value #end if slot.kind_of? Hash TkPack.configure(self, slot) else TkPack.configure(self, slot=>value) end end alias pack_configure pack_config def pack_info() #ilist = list(tk_call('pack', 'info', epath)) #info = {} #while key = ilist.shift # info[key[1..-1]] = ilist.shift #end #return info TkPack.info(self) end def pack_propagate(mode=None) #if mode == None # bool(tk_call('pack', 'propagate', epath)) #else # tk_call('pack', 'propagate', epath, mode) # self #end if mode == None TkPack.propagate(self) else TkPack.propagate(self, mode) self end end def pack_slaves() #list(tk_call('pack', 'slaves', epath)) TkPack.slaves(self) end def grid(keys = nil) #tk_call 'grid', epath, *hash_kv(keys) if keys TkGrid.configure(self, keys) else TkGrid.configure(self) end self end def grid_in(target, keys = nil) if keys keys = keys.dup keys['in'] = target else keys = {'in'=>target} end #tk_call 'grid', epath, *hash_kv(keys) TkGrid.configure(self, keys) self end def grid_anchor(anchor=None) if anchor == None TkGrid.anchor(self) else TkGrid.anchor(self, anchor) self end end def grid_forget #tk_call('grid', 'forget', epath) TkGrid.forget(self) self end alias ungrid grid_forget def grid_bbox(*args) #list(tk_call('grid', 'bbox', epath, *args)) TkGrid.bbox(self, *args) end def grid_config(slot, value=None) #if slot.kind_of? Hash # tk_call 'grid', 'configure', epath, *hash_kv(slot) #else # tk_call 'grid', 'configure', epath, "-#{slot}", value #end if slot.kind_of? Hash TkGrid.configure(self, slot) else TkGrid.configure(self, slot=>value) end end alias grid_configure grid_config def grid_columnconfig(index, keys) #tk_call('grid', 'columnconfigure', epath, index, *hash_kv(keys)) TkGrid.columnconfigure(self, index, keys) end alias grid_columnconfigure grid_columnconfig alias grid_column grid_columnconfig def grid_rowconfig(index, keys) #tk_call('grid', 'rowconfigure', epath, index, *hash_kv(keys)) TkGrid.rowconfigure(self, index, keys) end alias grid_rowconfigure grid_rowconfig alias grid_row grid_rowconfig def grid_columnconfiginfo(index, slot=nil) #if slot # tk_call('grid', 'columnconfigure', epath, index, "-#{slot}").to_i #else # ilist = list(tk_call('grid', 'columnconfigure', epath, index)) # info = {} # while key = ilist.shift # info[key[1..-1]] = ilist.shift # end # info #end TkGrid.columnconfiginfo(self, index, slot) end def grid_rowconfiginfo(index, slot=nil) #if slot # tk_call('grid', 'rowconfigure', epath, index, "-#{slot}").to_i #else # ilist = list(tk_call('grid', 'rowconfigure', epath, index)) # info = {} # while key = ilist.shift # info[key[1..-1]] = ilist.shift # end # info #end TkGrid.rowconfiginfo(self, index, slot) end def grid_info() #list(tk_call('grid', 'info', epath)) TkGrid.info(self) end def grid_location(x, y) #list(tk_call('grid', 'location', epath, x, y)) TkGrid.location(self, x, y) end def grid_propagate(mode=None) #if mode == None # bool(tk_call('grid', 'propagate', epath)) #else # tk_call('grid', 'propagate', epath, mode) # self #end if mode == None TkGrid.propagate(self) else TkGrid.propagate(self, mode) self end end def grid_remove() #tk_call 'grid', 'remove', epath TkGrid.remove(self) self end def grid_size() #list(tk_call('grid', 'size', epath)) TkGrid.size(self) end def grid_slaves(args) #list(tk_call('grid', 'slaves', epath, *hash_kv(args))) TkGrid.slaves(self, args) end def place(keys) #tk_call 'place', epath, *hash_kv(keys) TkPlace.configure(self, keys) self end def place_in(target, keys = nil) if keys keys = keys.dup keys['in'] = target else keys = {'in'=>target} end #tk_call 'place', epath, *hash_kv(keys) TkPlace.configure(self, keys) self end def place_forget #tk_call 'place', 'forget', epath TkPlace.forget(self) self end alias unplace place_forget def place_config(slot, value=None) #if slot.kind_of? Hash # tk_call 'place', 'configure', epath, *hash_kv(slot) #else # tk_call 'place', 'configure', epath, "-#{slot}", value #end TkPlace.configure(self, slot, value) end alias place_configure place_config def place_configinfo(slot = nil) # for >= Tk8.4a2 ? #if slot # conf = tk_split_list(tk_call('place', 'configure', epath, "-#{slot}") ) # conf[0] = conf[0][1..-1] # conf #else # tk_split_simplelist(tk_call('place', # 'configure', epath)).collect{|conflist| # conf = tk_split_simplelist(conflist) # conf[0] = conf[0][1..-1] # conf # } #end TkPlace.configinfo(self, slot) end def place_info() #ilist = list(tk_call('place', 'info', epath)) #info = {} #while key = ilist.shift # info[key[1..-1]] = ilist.shift #end #return info TkPlace.info(self) end def place_slaves() #list(tk_call('place', 'slaves', epath)) TkPlace.slaves(self) end def set_focus(force=false) if force tk_call_without_enc('focus', '-force', path) else tk_call_without_enc('focus', path) end self end alias focus set_focus def grab(opt = nil) unless opt tk_call_without_enc('grab', 'set', path) return self end case opt when 'set', :set tk_call_without_enc('grab', 'set', path) return self when 'global', :global #return(tk_call('grab', 'set', '-global', path)) tk_call_without_enc('grab', 'set', '-global', path) return self when 'release', :release #return tk_call('grab', 'release', path) tk_call_without_enc('grab', 'release', path) return self when 'current', :current return window(tk_call_without_enc('grab', 'current', path)) when 'status', :status return tk_call_without_enc('grab', 'status', path) else return tk_call_without_enc('grab', opt, path) end end def grab_current grab('current') end alias current_grab grab_current def grab_release grab('release') end alias release_grab grab_release def grab_set grab('set') end alias set_grab grab_set def grab_set_global grab('global') end alias set_global_grab grab_set_global def grab_status grab('status') end def lower(below=None) # below = below.epath if below.kind_of?(TkObject) below = _epath(below) tk_call 'lower', epath, below self end alias lower_window lower def raise(above=None) #above = above.epath if above.kind_of?(TkObject) above = _epath(above) tk_call 'raise', epath, above self end alias raise_window raise def command(cmd=nil, &b) if cmd configure_cmd('command', cmd) elsif b configure_cmd('command', Proc.new(&b)) else cget('command') end end def colormodel(model=None) tk_call('tk', 'colormodel', path, model) self end def caret(keys=nil) TkXIM.caret(path, keys) end def destroy super children = [] rexp = /^#{self.path}\.[^.]+$/ TkCore::INTERP.tk_windows.each{|path, obj| children << [path, obj] if path =~ rexp } if defined?(@cmdtbl) for id in @cmdtbl uninstall_cmd id end end children.each{|path, obj| obj.instance_eval{ if defined?(@cmdtbl) for id in @cmdtbl uninstall_cmd id end end } TkCore::INTERP.tk_windows.delete(path) } begin tk_call_without_enc('destroy', epath) rescue end uninstall_win end def wait_visibility(on_thread = true) if $SAFE >= 4 fail SecurityError, "can't wait visibility at $SAFE >= 4" end on_thread &= (Thread.list.size != 1) if on_thread INTERP._thread_tkwait('visibility', path) else INTERP._invoke('tkwait', 'visibility', path) end end def eventloop_wait_visibility wait_visibility(false) end def thread_wait_visibility wait_visibility(true) end alias wait wait_visibility alias tkwait wait_visibility alias eventloop_wait eventloop_wait_visibility alias eventloop_tkwait eventloop_wait_visibility alias eventloop_tkwait_visibility eventloop_wait_visibility alias thread_wait thread_wait_visibility alias thread_tkwait thread_wait_visibility alias thread_tkwait_visibility thread_wait_visibility def wait_destroy(on_thread = true) if $SAFE >= 4 fail SecurityError, "can't wait destroy at $SAFE >= 4" end on_thread &= (Thread.list.size != 1) if on_thread INTERP._thread_tkwait('window', epath) else INTERP._invoke('tkwait', 'window', epath) end end alias wait_window wait_destroy def eventloop_wait_destroy wait_destroy(false) end alias eventloop_wait_window eventloop_wait_destroy def thread_wait_destroy wait_destroy(true) end alias thread_wait_window thread_wait_destroy alias tkwait_destroy wait_destroy alias tkwait_window wait_destroy alias eventloop_tkwait_destroy eventloop_wait_destroy alias eventloop_tkwait_window eventloop_wait_destroy alias thread_tkwait_destroy thread_wait_destroy alias thread_tkwait_window thread_wait_destroy def bindtags(taglist=nil) if taglist fail ArgumentError, "taglist must be Array" unless taglist.kind_of? Array tk_call('bindtags', path, taglist) taglist else list(tk_call('bindtags', path)).collect{|tag| if tag.kind_of?(String) if cls = WidgetClassNames[tag] cls elsif btag = TkBindTag.id2obj(tag) btag else tag end else tag end } end end def bindtags=(taglist) bindtags(taglist) taglist end def bindtags_shift taglist = bindtags tag = taglist.shift bindtags(taglist) tag end def bindtags_unshift(tag) bindtags(bindtags().unshift(tag)) end end TkWidget = TkWindow # freeze core modules #TclTkLib.freeze #TclTkIp.freeze #TkUtil.freeze #TkKernel.freeze #TkComm.freeze #TkComm::Event.freeze #TkCore.freeze #Tk.freeze module Tk RELEASE_DATE = '2008-05-23'.freeze autoload :AUTO_PATH, 'tk/variable' autoload :TCL_PACKAGE_PATH, 'tk/variable' autoload :PACKAGE_PATH, 'tk/variable' autoload :TCL_LIBRARY_PATH, 'tk/variable' autoload :LIBRARY_PATH, 'tk/variable' autoload :TCL_PRECISION, 'tk/variable' end # call setup script for Tk extension libraries (base configuration) begin require 'tkextlib/version.rb' require 'tkextlib/setup.rb' rescue LoadError # ignore end ================================================ FILE: ext/tk/lib/tkafter.rb ================================================ # # tkafter.rb - load tk/after.rb # require 'tk/timer' ================================================ FILE: ext/tk/lib/tkbgerror.rb ================================================ # # tkbgerror.rb - load tk/bgerror.rb # require 'tk/bgerror' ================================================ FILE: ext/tk/lib/tkcanvas.rb ================================================ # # tkcanvas.rb - load tk/canvas.rb # require 'tk/canvas' ================================================ FILE: ext/tk/lib/tkclass.rb ================================================ # # tkclass.rb - Tk classes # Date: 2000/11/27 09:23:36 # by Yukihiro Matsumoto # # $Id$ require "tk" TopLevel = TkToplevel Frame = TkFrame Label = TkLabel Button = TkButton Radiobutton = TkRadioButton Checkbutton = TkCheckButton Message = TkMessage Entry = TkEntry Spinbox = TkSpinbox Text = TkText Scale = TkScale Scrollbar = TkScrollbar Listbox = TkListbox Menu = TkMenu Menubutton = TkMenubutton Canvas = TkCanvas Arc = TkcArc Bitmap = TkcBitmap Line = TkcLine Oval = TkcOval Polygon = TkcPolygon Rectangle = TkcRectangle TextItem = TkcText WindowItem = TkcWindow BitmapImage = TkBitmapImage PhotoImage = TkPhotoImage Selection = TkSelection Winfo = TkWinfo Pack = TkPack Grid = TkGrid Place = TkPlace Variable = TkVariable Font = TkFont VirtualEvent = TkVirtualEvent def Mainloop Tk.mainloop end ================================================ FILE: ext/tk/lib/tkconsole.rb ================================================ # # tkconsole.rb - load tk/console.rb # require 'tk/console' ================================================ FILE: ext/tk/lib/tkdialog.rb ================================================ # # tkdialog.rb - load tk/dialog.rb # require 'tk/dialog' ================================================ FILE: ext/tk/lib/tkentry.rb ================================================ # # tkentry.rb - load tk/entry.rb # require 'tk/entry' ================================================ FILE: ext/tk/lib/tkextlib/ICONS/icons.rb ================================================ # # tkextlib/ICONS/icons.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/ICONS/setup.rb' # TkPackage.require('icons', '1.0') TkPackage.require('icons') module Tk class ICONS < TkImage extend Tk PACKAGE_NAME = 'icons'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('icons') rescue '' end end def self.create(*args) # icon, icon, ..., ?option=>value, ...? if args[-1].kind_of?(Hash) keys = args.pop icons = simplelist(tk_call('::icons::icons', 'create', *(hash_kv(keys) << (args.flatten)))) else icons = simplelist(tk_call('::icons::icons', 'create', args.flatten)) end icons.collect{|icon| self.new(icon, :without_creating=>true)} end def self.delete(*icons) # icon, icon, ... icons = icons.flatten return if icons.empty? icons.map!{|icon| if icon.kind_of?(Tk::ICONS) Tk_IMGTBL.delete(icon.path) icon.name elsif icon.to_s =~ /^::icon::(.*)/ name = $1 Tk_IMGTBL.delete(icon) name else Tk_IMGTBL.delete("::icon::#{icon}") icon end } tk_call('::icons::icons', 'delete', icons) end def self.query(*args) # icon, icon, ..., ?option=>value, ...? if args[-1].kind_of?(Hash) keys = args.pop simplelist(tk_call('::icons::icons', 'query', *(hash_kv(keys) << (args.flatten)))) else simplelist(tk_call('::icons::icons', 'query', args.flatten)) end . map{|inf| list(inf) } end ########################################## class << self alias _new new def new(name, keys=nil) if obj = Tk_IMGTBL["::icon::#{name}"] if keys keys = _symbolkey2str(keys) unless keys.delete('without_creating') tk_call('::icons::icons', 'create', *(hash_kv(keys) << obj.name)) end end else obj = _new(name, keys) end obj end end ########################################## def initialize(name, keys=nil) if name.kind_of?(String) && name =~ /^::icon::(.+)$/ @name = $1 @path = name else @name = name.to_s @path = "::icon::#{@name}" end keys = _symbolkey2str(keys) unless keys.delete('without_creating') tk_call('::icons::icons', 'create', *(hash_kv(keys) << @name)) end Tk_IMGTBL[@path] = self end def name @name end def delete Tk_IMGTBL.delete(@path) tk_call('::icons::icons', 'delete', @name) self end def query(keys={}) list(simplelist(tk_call('::icons::icons', 'query', *(hash_kv(keys) << @name)) )[0]) end end end ================================================ FILE: ext/tk/lib/tkextlib/ICONS/setup.rb ================================================ # # setup.rb -- setup script before calling TkPackage.require() # # If you need some setup operations (for example, add a library path # to the library search path) before using Tcl/Tk library packages # wrapped by Ruby scripts in this directory, please write the setup # operations in this file. # ================================================ FILE: ext/tk/lib/tkextlib/ICONS.rb ================================================ # # ICONS support # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/ICONS/setup.rb' # load library require 'tkextlib/ICONS/icons' ================================================ FILE: ext/tk/lib/tkextlib/SUPPORT_STATUS ================================================ [ current support status of Tcl/Tk extensions ] *** RELEASE_DATE of the libraries => see 'tkextlib/version.rb' *** The following list shows *CURRENT* status when this file was modifyed at last. If you want to add other Tcl/Tk extensions to the planed list (or change its status position), please request them at the ruby-talk, ruby-list, or ruby-dev ML. Although we cannot promise to support your requests, we'll try to do. If you want to check that wrapper libraries are ready to use on your environment, please execute 'pkg_checker.rb' with no arguments. The script may give you some hints about that. ***** IMPORTANT NOTE ********************************************** 'support' means that Ruby/Tk's wrapper libraries are released. 'not support' does *NOT* mean that the extension doesn't work on Ruby/Tk. The version number of each extension means the latest version which is checked its feature. That is, it does NOT means only version of working. Library files maybe include some features which is included in the former version but removed from the latest, and maybe able to support the later version then the shown version. Even if the status of the extension is 'not support', you can control the functions/widgets of the extension without wrapper libraries by Tk.tk_call(), Tk.ip_eval(), and so on. If you cannot use installed Tcl/Tk extension, please check the followings. (1) On your Tcl/Tk, does the extention work? (2) Do DLL libraries of the extension exist on DLL load-path? (See also "/ext/tcltklib/README.ActiveTcl") (3) Is the Tcl library directory of the extension included in library search-path of the Tcl interpreter linked Ruby/Tk? The check results may request you to do some setup operations before using the extension. If so, then please write the step of setup oprations into the "setup.rb" file in the directory of the wrapper libraries for the extention (It is the wrapper libraries have the standard structure of the libraries in this directory). The "setup" file is required before requiring the Tcl library package (TkPackage.require()). ******************************************************************* ===< support with some examples (may be beta quality) >======================= Tcllib 1.8 Tklib 0.4.1 http://sourceforge.net/projects/tcllib ==> tcllib IWidgets 4.0.2 http://sourceforge.net/projects/incrtcl ==> iwidgets BWidgets 1.7 http://sourceforge.net/projects/tcllib ==> bwidget TkTable 2.9 http://sourceforge.net/projects/tktable ==> tktable * see also written by Ferenc Engard (ferenc@engard.hu) vu 2.3.0 http://sourceforge.net/projects/tktable ==> vu TkHTML 2.0 http://www.hwaci.com/sw/tkhtml/ ==> tkHTML ICONS 1.0 http://www.satisoft.com/tcltk/icons/ ==> ICONS TkImg 1.3 http://sourceforge.net/projects/tkimg ==> tkimg BLT 2.4z http://sourceforge.net/projects/blt * see also tcltk-ext library on RAA (http://raa.ruby-lang.org/) ==> blt TkTreeCtrl CVS/Hd(2005-12-02) http://sourceforge.net/projects/tktreectrl ==> treectrl Tile 0.8.0/8.5.1 http://sourceforge.net/projects/tktable ==> tile ===< support (may be alpha or beta quality) >================================= IncrTcl CVS/Hd(2005-02-14) http://sourceforge.net/projects/incrtcl ==> itcl, itk TclX CVS/Hd(2005-02-07) http://sourceforge.net/projects/tclx ==> tclx (partial support; infox command and XPG/3 message catalogs only) Trofs 0.4.3 http://math.nist.gov/~DPorter/tcltk/trofs/ ===< possibly available (not tested; alpha quality) >========================= winico 0.6 http://sourceforge.net/projects/tktable ==> winico (win32 only) TkTrans latest(2004-10-11) http://www2.cmp.uea.ac.uk/~fuzz/tktrans/default.html ==> tktrans (win32 only) TkDND 1.0a2 http://sourceforge.net/projects/tkdnd ==> tkDND ===< plan to support (alpha quality libraries may be included) >============== GraphViz *** http://www.graphviz.org/ Tkgeomap *** http://tkgeomap.sourceforge.net/index.html ===< not determined to supprt or not >======================================== Tix *** http://tixlibrary.sourceforge.net/ * see also tcltk-ext library on RAA (http://raa.ruby-lang.org/) TkZinc *** http://www.tkzinc.org/ Wbc *** http://home.t-online.de/home/csaba.nemethi/ Mentry *** http://home.t-online.de/home/csaba.nemethi/ Tablelist *** http://home.t-online.de/home/csaba.nemethi/ ANIGIF *** http://cardtable.sourceforge.net/tcltk/ IMG_ROTATE *** http://cardtable.sourceforge.net/tcltk/ TclVfs *** http://sourceforge.net/projects/tclvfs/ vfwtcl *** http://sourceforge.net/projects/avicaptcl * Win32 only multicast *** http://sourceforge.net/projects/avicaptcl * Win32 only XBit *** http://www.geocities.com/~chengye/ * current implementation is for Windows only QuickTimeTcl *** http://hem.fyristorg.com/matben/qt/ * works under Mac OS (8,9,X) or Windows ===< may not support (already exist, out of Ruby/Tk scope, and so on) >======= TkCon *** http://sourceforge.net/projects/tkcon Expect *** http://sourceforge.net/projects/expect TclXML *** http://sourceforge.net/projects/tclxml TclXSLT *** http://sourceforge.net/projects/tclxml TclDOM *** http://sourceforge.net/projects/tclxml TclSOAP *** http://sourceforge.net/projects/tclsoap Snack *** http://www.speech.kth.se/~kare/snack2.2.tar.gz * use Snack for Ruby (see http://rbsnack.sourceforge.net/) Tcom *** http://www.vex.net/~cthuang/tcom/ tDOM *** http://www.tdom.org Mk4tcl *** http://www.equi4.com/metakit/tcl.html Memchan *** http://sourceforge.net/projects/memchan XOTcl *** http://www.xotcl.org/ ===< tool (may not supprt) >================================================== tbcload/tclcompiler *** http://www.tcl.tk/software/tclpro/ (End of List) ================================================ FILE: ext/tk/lib/tkextlib/blt/barchart.rb ================================================ # # tkextlib/blt/barchart.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/blt.rb' require 'tkextlib/blt/component.rb' module Tk::BLT class Barchart < TkWindow TkCommandNames = ['::blt::barchart'.freeze].freeze WidgetClassName = 'Barchart'.freeze WidgetClassNames[WidgetClassName] = self include PlotComponent include GraphCommand def __boolval_optkeys ['bufferelements', 'buffergraph', 'invertxy'] end private :__boolval_optkeys def __strval_optkeys ['text', 'label', 'title', 'file', 'background', 'plotbackground'] end private :__strval_optkeys def __tkvariable_optkeys super() << 'colormap' << 'fontmap' end private :__tkvariable_optkeys =begin BarElement_ID = ['blt_barchart_bar'.freeze, '00000'.taint].freeze def bar(elem=nil, keys={}) if elem.kind_of?(Hash) keys = elem elem = nil end unless elem elem = BarElement_ID.join(TkCore::INTERP._ip_id_).freeze BarElement_ID[1].succ! end tk_send('bar', elem, keys) Element.new(self, elem, :without_creating=>true) end =end def extents(item) num_or_str(tk_send_without_enc('extents', item)) end def invtransform(x, y) list(tk_send_without_enc('invtransform', x, y)) end def inside(x, y) bool(tk_send_without_enc('inside', x, y)) end def metafile(file=None) # Windows only tk_send('metafile', file) self end def snap(output, keys={}) tk_send_without_enc('snap', *(hash_kv(keys, false) + output)) self end def transform(x, y) list(tk_send_without_enc('transform', x, y)) end end end ================================================ FILE: ext/tk/lib/tkextlib/blt/bitmap.rb ================================================ # # tkextlib/blt/bitmap.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/blt.rb' module Tk::BLT class Bitmap < TkObject extend TkCore TkCommandNames = ['::blt::bitmap'.freeze].freeze BITMAP_ID_TBL = TkCore::INTERP.create_table (BITMAP_ID = ['blt_bitmap_id'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } TkCore::INTERP.init_ip_env{ BITMAP_ID_TBL.mutex.synchronize{ BITMAP_ID_TBL.clear } } def self.data(name) dat = tk_simple_list(tk_call('::blt::bitmap', 'data', name)) [ tk_split_list(dat[0]), tk_simple_list(dat[1]) ] end def self.exist?(name) bool(tk_call('::blt::bitmap', 'exists', name)) end def self.height(name) number(tk_call('::blt::bitmap', 'height', name)) end def self.width(name) number(tk_call('::blt::bitmap', 'width', name)) end def self.source(name) tk_simple_list(tk_call('::blt::bitmap', 'source', name)) end ################################# class << self alias _new new def new(data, keys={}) _new(:data, nil, data, keys) end alias define new def new_with_name(name, data, keys={}) _new(:data, name, data, keys) end alias define_with_name new_with_name def compose(text, keys={}) _new(:text, nil, text, keys) end def compose_with_name(name, text, keys={}) _new(:text, name, text, keys) end end def initialize(type, name, data, keys = {}) if name @id = name else BITMAP_ID.mutex.synchronize{ @id = BITMAP_ID.join(TkCore::INTERP._ip_id_) BITMAP_ID[1].succ! } BITMAP_ID_TBL.mutex.synchronize{ BITMAP_ID_TBL[@id] = self } end @path = @id unless bool(tk_call('::blt::bitmap', 'exists', @id)) if type == :text tk_call('::blt::bitmap', 'compose', @id, data, *hash_kv(keys)) else # :data tk_call('::blt::bitmap', 'define', @id, data, *hash_kv(keys)) end end end def exist? bool(tk_call('::blt::bitmap', 'exists', @id)) end def height number(tk_call('::blt::bitmap', 'height', @id)) end def width number(tk_call('::blt::bitmap', 'width', @id)) end def source tk_simple_list(tk_call('::blt::bitmap', 'source', @id)) end end end ================================================ FILE: ext/tk/lib/tkextlib/blt/busy.rb ================================================ # # tkextlib/blt/busy.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/itemconfig.rb' require 'tkextlib/blt.rb' module Tk::BLT module Busy extend TkCore extend TkItemConfigMethod TkCommandNames = ['::blt::busy'.freeze].freeze ########################### class Shield < TkWindow def self.shield_path(win) win = window(win) unless win.kind_of?(TkWindow) if win.kind_of?(Tk::Toplevel) win.path + '._Busy' else win.path + '_Busy' end end def initialize(win) @path = self.class.shield_path(win) end end def self.shield_path(win) Tk::BLT::Busy::Shield.shield_path(win) end end end class << Tk::BLT::Busy def __item_config_cmd(win) ['::blt::busy', 'configure', win] end private :__item_config_cmd undef itemcget alias configure itemconfigure alias configinfo itemconfiginfo alias current_configinfo current_itemconfiginfo private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo ################################## def hold(win, keys={}) tk_call('::blt::busy', 'hold', win, *hash_kv(keys)) end def release(*wins) tk_call('::blt::busy', 'release', *wins) end def forget(*wins) tk_call('::blt::busy', 'forget', *wins) end def is_busy(pat=None) tk_split_list(tk_call('::blt::busy', 'isbusy', pat)) end def names(pat=None) tk_split_list(tk_call('::blt::busy', 'names', pat)) end alias windows names def check(win) bool(tk_call('::blt::busy', 'check', win)) end def status(win) bool(tk_call('::blt::busy', 'status', win)) end end ================================================ FILE: ext/tk/lib/tkextlib/blt/component.rb ================================================ # # tkextlib/blt/component.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/blt.rb' module Tk::BLT module PlotComponent include TkItemConfigMethod module OptKeys def __item_font_optkeys(id) ['font', 'tickfont', 'titlefont'] end private :__item_font_optkeys def __item_numstrval_optkeys(id) ['xoffset', 'yoffset'] end private :__item_numstrval_optkeys def __item_boolval_optkeys(id) ['hide', 'under', 'descending', 'logscale', 'loose', 'showticks', 'titlealternate', 'scalesymbols', 'minor', 'raised', 'center', 'decoration', 'landscape', 'maxpect'] end private :__item_boolval_optkeys def __item_strval_optkeys(id) ['text', 'label', 'limits', 'title', 'show', 'file', 'maskdata', 'maskfile', 'color', 'titlecolor', 'fill', 'outline', 'offdash'] end private :__item_strval_optkeys def __item_listval_optkeys(id) ['bindtags'] end private :__item_listval_optkeys def __item_numlistval_optkeys(id) ['dashes', 'majorticks', 'minorticks'] end private :__item_numlistval_optkeys def __item_tkvariable_optkeys(id) ['variable', 'textvariable', 'colormap', 'fontmap'] end private :__item_tkvariable_optkeys end include OptKeys def __item_cget_cmd(id) if id.kind_of?(Array) # id := [ type, name ] [self.path, id[0], 'cget', id[1]] else [self.path, id, 'cget'] end end private :__item_cget_cmd def __item_config_cmd(id) if id.kind_of?(Array) # id := [ type, name, ... ] type, *names = id [self.path, type, 'configure'].concat(names) else [self.path, id, 'configure'] end end private :__item_config_cmd def __item_pathname(id) if id.kind_of?(Array) id = tagid(id[1]) end [self.path, id].join(';') end private :__item_pathname def axis_cget(id, option) ret = itemcget(['axis', tagid(id)], option) end def axis_cget_strict(id, option) ret = itemcget_strict(['axis', tagid(id)], option) end def axis_configure(*args) slot = args.pop if slot.kind_of?(Hash) value = None slot = _symbolkey2str(slot) if cmd = slot.delete('command') slot['command'] = proc{|w, tick| cmd.call(TkComm.window(w), TkComm.num_or_str(tick)) } end else value = slot slot = args.pop if slot == :command || slot == 'command' cmd = value value = proc{|w, tick| cmd.call(TkComm.window(w), TkComm.num_or_str(tick)) } end end id_list = args.flatten.collect!{|id| tagid(id)}.unshift('axis') itemconfigure(id_list, slot, value) end def axis_configinfo(id, slot=nil) itemconfiginfo(['axis', tagid(id)], slot) end def current_axis_configinfo(id, slot=nil) current_itemconfiginfo(['axis', tagid(id)], slot) end def crosshairs_cget(option) itemcget('crosshairs', option) end def crosshairs_cget_strict(option) itemcget_strict('crosshairs', option) end def crosshairs_configure(slot, value=None) itemconfigure('crosshairs', slot, value) end def crosshairs_configinfo(slot=nil) itemconfiginfo('crosshairs', slot) end def current_crosshairs_configinfo(slot=nil) current_itemconfiginfo('crosshairs', slot) end def element_cget(id, option) itemcget(['element', tagid(id)], option) end def element_cget_strict(id, option) itemcget_strict(['element', tagid(id)], option) end def element_configure(*args) slot = args.pop if slot.kind_of?(Hash) value = None else value = slot slot = args.pop end id_list = args.flatten.collect!{|id| tagid(id)}.unshift('element') itemconfigure(id_list, slot, value) end def element_configinfo(id, slot=nil) itemconfiginfo(['element', tagid(id)], slot) end def current_element_configinfo(id, slot=nil) current_itemconfiginfo(['element', tagid(id)], slot) end def bar_cget(id, option) itemcget(['bar', tagid(id)], option) end def bar_cget_strict(id, option) itemcget_strict(['bar', tagid(id)], option) end def bar_configure(*args) slot = args.pop if slot.kind_of?(Hash) value = None else value = slot slot = args.pop end id_list = args.flatten.collect!{|id| tagid(id)}.unshift('bar') itemconfigure(id_list, slot, value) end def bar_configinfo(id, slot=nil) itemconfiginfo(['bar', tagid(id)], slot) end def current_bar_configinfo(id, slot=nil) current_itemconfiginfo(['bar', tagid(id)], slot) end def line_cget(id, option) itemcget(['line', tagid(id)], option) end def line_cget_strict(id, option) itemcget_strict(['line', tagid(id)], option) end def line_configure(*args) slot = args.pop if slot.kind_of?(Hash) value = None else value = slot slot = args.pop end id_list = args.flatten.collect!{|id| tagid(id)}.unshift('line') itemconfigure(id_list, slot, value) end def line_configinfo(id, slot=nil) itemconfiginfo(['line', tagid(id)], slot) end def current_line_configinfo(id, slot=nil) current_itemconfiginfo(['line', tagid(id)], slot) end def gridline_cget(option) itemcget('grid', option) end def gridline_cget_strict(option) itemcget_strict('grid', option) end def gridline_configure(slot, value=None) itemconfigure('grid', slot, value) end def gridline_configinfo(slot=nil) itemconfiginfo('grid', slot) end def current_gridline_configinfo(slot=nil) current_itemconfiginfo('grid', slot) end def legend_cget(option) itemcget('legend', option) end def legend_cget_strict(option) itemcget_strict('legend', option) end def legend_configure(slot, value=None) itemconfigure('legend', slot, value) end def legend_configinfo(slot=nil) itemconfiginfo('legend', slot) end def current_legend_configinfo(slot=nil) current_itemconfiginfo('legend', slot) end def pen_cget(id, option) itemcget(['pen', tagid(id)], option) end def pen_cget_strict(id, option) itemcget_strict(['pen', tagid(id)], option) end def pen_configure(*args) slot = args.pop if slot.kind_of?(Hash) value = None else value = slot slot = args.pop end id_list = args.flatten.collect!{|id| tagid(id)}.unshift('pen') itemconfigure(id_list, slot, value) end def pen_configinfo(id, slot=nil) itemconfiginfo(['pen', tagid(id)], slot) end def current_pen_configinfo(id, slot=nil) current_itemconfiginfo(['pen', tagid(id)], slot) end def postscript_cget(option) itemcget('postscript', option) end def postscript_cget_strict(option) itemcget_strict('postscript', option) end def postscript_configure(slot, value=None) itemconfigure('postscript', slot, value) end def postscript_configinfo(slot=nil) itemconfiginfo('postscript', slot) end def current_postscript_configinfo(slot=nil) current_itemconfiginfo('postscript', slot) end def marker_cget(id, option) itemcget(['marker', tagid(id)], option) end def marker_cget_strict(id, option) itemcget_strict(['marker', tagid(id)], option) end def marker_configure(*args) slot = args.pop if slot.kind_of?(Hash) value = None else value = slot slot = args.pop end id_list = args.flatten.collect!{|id| tagid(id)}.unshift('marker') itemconfigure(id_list, slot, value) end def marker_configinfo(id, slot=nil) itemconfiginfo(['marker', tagid(id)], slot) end def current_marker_configinfo(id, slot=nil) current_itemconfiginfo(['marker', tagid(id)], slot) end alias __itemcget itemcget alias __itemcget_strict itemcget_strict alias __itemconfiginfo itemconfiginfo alias __current_itemconfiginfo current_itemconfiginfo private :__itemcget, :__itemconfiginfo, :__current_itemconfiginfo def itemcget_strict(tagOrId, option) ret = __itemcget(tagid(tagOrId), option) if option == 'bindtags' || option == :bindtags ret.collect{|tag| TkBindTag.id2obj(tag)} else ret end end def itemcget(tagOrId, option) unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ itemcget_strict(tagOrId, option) else begin itemcget_strict(tagOrId, option) rescue => e begin if current_itemconfiginfo(tagOrId).has_key?(option.to_s) # error on known option fail e else # unknown option nil end rescue fail e # tag error end end end end def itemconfiginfo(tagOrId, slot = nil) ret = __itemconfiginfo(tagid(tagOrId), slot) if TkComm::GET_CONFIGINFO_AS_ARRAY if slot if slot == 'bindtags' || slot == :bindtags ret[-2] = ret[-2].collect{|tag| TkBindTag.id2obj(tag)} ret[-1] = ret[-1].collect{|tag| TkBindTag.id2obj(tag)} end else if (inf = ret.assoc('bindtags')) inf[-2] = inf[-2].collect{|tag| TkBindTag.id2obj(tag)} inf[-1] = inf[-1].collect{|tag| TkBindTag.id2obj(tag)} end end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY if (inf = ret['bindtags']) inf[-2] = inf[-2].collect{|tag| TkBindTag.id2obj(tag)} inf[-1] = inf[-1].collect{|tag| TkBindTag.id2obj(tag)} ret['bindtags'] = inf end end ret end def current_itemconfiginfo(tagOrId, slot = nil) ret = __current_itemconfiginfo(tagid(tagOrId), slot) if (val = ret['bindtags']) ret['bindtags'] = val.collect{|tag| TkBindTag.id2obj(tag)} end ret end private :itemcget, :itemcget_strict private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo ################# class Axis < TkObject (OBJ_ID = ['blt_chart_axis'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } AxisID_TBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ AxisID_TBL.mutex.synchronize{ AxisID_TBL.clear } } def self.id2obj(chart, id) cpath = chart.path AxisID_TBL.mutex.synchronize{ return id unless AxisID_TBL[cpath] AxisID_TBL[cpath][id]? AxisID_TBL[cpath][id]: id } end def self.new(chart, axis=nil, keys={}) if axis.kind_of?(Hash) keys = axis axis = nil end if keys keys = _symbolkey2str(keys) not_create = keys.delete('without_creating') else not_create = false end obj = nil AxisID_TBL.mutex.synchronize{ chart_path = chart.path AxisID_TBL[chart_path] ||= {} if axis && AxisID_TBL[chart_path][axis] obj = AxisID_TBL[chart_path][axis] else (obj = self.allocate).instance_eval{ if axis @axis = @id = axis.to_s else OBJ_ID.mutex.synchronize{ @axis = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze OBJ_ID[1].succ! } end @path = @id @parent = @chart = chart @cpath = @chart.path Axis::AxisID_TBL[@cpath][@axis] = self unless not_create tk_call(@chart, 'axis', 'create', @axis, keys) return obj end } end } obj.configure(keys) if obj && ! keys.empty? obj end def initialize(chart, axis=nil, keys={}) # dummy:: not called by 'new' method if axis.kind_of?(Hash) keys = axis axis = nil end if axis @axis = @id = axis.to_s else OBJ_ID.mutex.synchronize{ @axis = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze OBJ_ID[1].succ! } end @path = @id @parent = @chart = chart @cpath = @chart.path # Axis::AxisID_TBL[@cpath][@axis] = self keys = _symbolkey2str(keys) unless keys.delete('without_creating') # @chart.axis_create(@axis, keys) tk_call(@chart, 'axis', 'create', @axis, keys) end end def id @id end def to_eval @id end def cget(option) @chart.axis_cget(@id, option) end def cget_strict(option) @chart.axis_cget_strict(@id, option) end def configure(key, value=None) @chart.axis_configure(@id, key, value) self end def configinfo(key=nil) @chart.axis_configinfo(@id, key) end def current_configinfo(key=nil) @chart.current_axis_configinfo(@id, key) end def command(cmd=nil, &b) if cmd configure('command', cmd) elsif b configure('command', Proc.new(&b)) else cget('command') end end def delete @chart.axis_delete(@id) self end def invtransform(val) @chart.axis_invtransform(@id, val) end def limits @chart.axis_limits(@id) end def name @axis end def transform(val) @chart.axis_transform(@id, val) end def view @chart.axis_view(@id) self end def use(name=None) # if @id == xaxis | x2axis | yaxis | y2axis @chart.axis_use(@id, name) end def use_as(axis) # axis := xaxis | x2axis | yaxis | y2axis @chart.axis_use(axis, @id) end end ################# class Crosshairs < TkObject CrosshairsID_TBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ CrosshairsID_TBL.mutex.synchronize{ CrosshairsID_TBL.clear } } def self.new(chart, keys={}) obj = nil CrosshairsID_TBL.mutex.synchronize{ unless (obj = CrosshairsID_TBL[chart.path]) (obj = self.allocate).instance_eval{ @parent = @chart = chart @cpath = @chart.path @path = @id = 'crosshairs' Crosshairs::CrosshairsID_TBL[@cpath] = self } end } chart.crosshair_configure(keys) if obj && ! keys.empty? obj end def initialize(chart, keys={}) # dummy:: not called by 'new' method @parent = @chart = chart @cpath = @chart.path # Crosshairs::CrosshairsID_TBL[@cpath] = self @chart.crosshair_configure(keys) unless keys.empty? @path = @id = 'crosshairs' end def id @id end def to_eval @id end def cget(option) @chart.crosshair_cget(option) end def cget_strict(option) @chart.crosshair_cget_strict(option) end def configure(key, value=None) @chart.crosshair_configure(key, value) self end def configinfo(key=nil) @chart.crosshair_configinfo(key) end def current_configinfo(key=nil) @chart.current_crosshair_configinfo(key) end def off @chart.crosshair_off self end def on @chart.crosshair_on self end def toggle @chart.crosshair_toggle self end end ################# class Element < TkObject extend Tk extend TkItemFontOptkeys extend TkItemConfigOptkeys extend Tk::BLT::PlotComponent::OptKeys ElementTypeName = 'element' ElementTypeToClass = { ElementTypeName=>self } ElementID_TBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ ElementID_TBL.mutex.synchronize{ ElementID_TBL.clear } } (OBJ_ID = ['blt_chart_element'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } def Element.type2class(type) ElementTypeToClass[type] end def Element.id2obj(chart, id) cpath = chart.path ElementID_TBL.mutex.synchronize{ return id unless ElementID_TBL[cpath] ElementID_TBL[cpath][id]? ElementID_TBL[cpath][id]: id } end def self.new(chart, element=nil, keys={}) if element.kind_of?(Hash) keys = element element = nil end if keys keys = _symbolkey2str(keys) not_create = keys.delete('without_creating') else not_create = false end obj = nil ElementID_TBL.mutex.synchronize{ chart_path = chart.path ElementID_TBL[chart_path] ||= {} if element && ElementID_TBL[chart_path][element] obj = ElementID_TBL[chart_path][element] else (obj = self.allocate).instance_eval{ if element @element = @id = element.to_s else OBJ_ID.mutex.synchronize{ @element = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze OBJ_ID[1].succ! } end @path = @id @parent = @chart = chart @cpath = @chart.path @typename = self.class::ElementTypeName Element::ElementID_TBL[@cpath][@element] = self unless not_create tk_call(@chart, @typename, 'create', @element, keys) return obj end } end } obj.configure(keys) if obj && ! keys.empty? obj end def initialize(chart, element=nil, keys={}) # dummy:: not called by 'new' method if element.kind_of?(Hash) keys = element element = nil end if element @element = @id = element.to_s else OBJ_ID.mutex.synchronize{ @element = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze OBJ_ID[1].succ! } end @path = @id @parent = @chart = chart @cpath = @chart.path @typename = self.class::ElementTypeName # Element::ElementID_TBL[@cpath][@element] = self keys = _symbolkey2str(keys) unless keys.delete('without_creating') # @chart.element_create(@element, keys) tk_call(@chart, @typename, 'create', @element, keys) end end def id @id end def to_eval @id end def cget(option) # @chart.element_cget(@id, option) @chart.__send__(@typename + '_cget', @id, option) end def cget_strict(option) @chart.__send__(@typename + '_cget_strict', @id, option) end def configure(key, value=None) # @chart.element_configure(@id, key, value) @chart.__send__(@typename + '_configure', @id, key, value) self end def configinfo(key=nil) # @chart.element_configinfo(@id, key) @chart.__send__(@typename + '_configinfo', @id, key) end def current_configinfo(key=nil) # @chart.current_element_configinfo(@id, key) @chart.__send__('current_' << @typename << '_configinfo', @id, key) end def activate(*args) @chart.element_activate(@id, *args) end def closest(x, y, var, keys={}) # @chart.element_closest(x, y, var, @id, keys) @chart.__send__(@typename + '_closest', x, y, var, @id, keys) end def deactivate @chart.element_deactivate(@id) self end def delete @chart.element_delete(@id) self end def exist? @chart.element_exist?(@id) end def name @element end def type @chart.element_type(@id) end end class Bar < Element ElementTypeName = 'bar'.freeze ElementTypeToClass[ElementTypeName] = self end class Line < Element ElementTypeName = 'line'.freeze ElementTypeToClass[ElementTypeName] = self end ################# class GridLine < TkObject GridLineID_TBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ GridLineID_TBL.mutex.synchronize{ GridLineID_TBL.clear } } def self.new(chart, keys={}) obj = nil GridLineID_TBL.mutex.synchronize{ unless (obj = GridLineID_TBL[chart.path]) (obj = self.allocate).instance_eval{ @parent = @chart = chart @cpath = @chart.path @path = @id = 'grid' GridLine::GridLineID_TBL[@cpath] = self } end } chart.gridline_configure(keys) if obj && ! keys.empty? obj end def initialize(chart, keys={}) # dummy:: not called by 'new' method @parent = @chart = chart @cpath = @chart.path # GridLine::GridLineID_TBL[@cpath] = self @chart.gridline_configure(keys) unless keys.empty? @path = @id = 'grid' end def id @id end def to_eval @id end def cget(option) @chart.gridline_cget(option) end def cget_strict(option) @chart.gridline_cget_strict(option) end def configure(key, value=None) @chart.gridline_configure(key, value) self end def configinfo(key=nil) @chart.gridline_configinfo(key) end def current_configinfo(key=nil) @chart.current_gridline_configinfo(key) end def off @chart.gridline_off self end def on @chart.gridline_on self end def toggle @chart.gridline_toggle self end end ################# class Legend < TkObject LegendID_TBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ LegendID_TBL.mutex.synchronize{ LegendID_TBL.clear } } def self.new(chart, keys={}) obj = nil LegenedID_TBL.mutex.synchronize{ unless (obj = LegenedID_TBL[chart.path]) (obj = self.allocate).instance_eval{ @parent = @chart = chart @cpath = @chart.path @path = @id = 'crosshairs' Legend::LegenedID_TBL[@cpath] = self } end } chart.legend_configure(keys) if obj && ! keys.empty? obj end def initialize(chart, keys={}) # dummy:: not called by 'new' method @parent = @chart = chart @cpath = @chart.path # Legend::LegendID_TBL[@cpath] = self @chart.legend_configure(keys) unless keys.empty? @path = @id = 'legend' end def id @id end def to_eval @id end def cget(option) @chart.legend_cget(option) end def cget_strict(option) @chart.legend_cget_strict(option) end def configure(key, value=None) @chart.legend_configure(key, value) self end def configinfo(key=nil) @chart.legend_configinfo(key) end def current_configinfo(key=nil) @chart.current_legend_configinfo(key) end def activate(*args) @chart.legend_activate(*args) end def deactivate(*args) @chart.legend_deactivate(*args) end def get(pos, y=nil) @chart.legend_get(pos, y) end end ################# class Pen < TkObject (OBJ_ID = ['blt_chart_pen'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } PenID_TBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ PenID_TBL.mutex.synchronize{ PenID_TBL.clear } } def self.id2obj(chart, id) cpath = chart.path PenID_TBL.mutex.synchronize{ return id unless PenID_TBL[cpath] PenID_TBL[cpath][id]? PenID_TBL[cpath][id]: id } end def self.new(chart, pen=nil, keys={}) if pen.kind_of?(Hash) keys = pen pen = nil end if keys keys = _symbolkey2str(keys) not_create = keys.delete('without_creating') else not_create = false end obj = nil PenID_TBL.mutex.synchronize{ chart_path = chart.path PenID_TBL[chart_path] ||= {} if pen && PenID_TBL[chart_path][pen] obj = PenID_TBL[chart_path][pen] else (obj = self.allocate).instance_eval{ if pen @pen = @id = pen.to_s else OBJ_ID.mutex.synchronize{ @pen = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze OBJ_ID[1].succ! } end @path = @id @parent = @chart = chart @cpath = @chart.path Pen::PenID_TBL[@cpath][@pen] = self unless not_create tk_call(@chart, 'pen', 'create', @pen, keys) return obj end } end } obj.configure(keys) if obj && ! keys.empty? obj end def initialize(chart, pen=nil, keys={}) if pen.kind_of?(Hash) keys = pen pen = nil end if pen @pen = @id = pen.to_s else OBJ_ID.mutex.synchronize{ @pen = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze OBJ_ID[1].succ! } end @path = @id @parent = @chart = chart @cpath = @chart.path Pen::PenID_TBL[@cpath][@pen] = self keys = _symbolkey2str(keys) unless keys.delete('without_creating') # @chart.pen_create(@pen, keys) tk_call(@chart, 'pen', 'create', @pen, keys) end end def id @id end def to_eval @id end def cget(option) @chart.pen_cget(@id, option) end def cget_strict(option) @chart.pen_cget_strict(@id, option) end def configure(key, value=None) @chart.pen_configure(@id, key, value) self end def configinfo(key=nil) @chart.pen_configinfo(@id, key) end def current_configinfo(key=nil) @chart.current_pen_configinfo(@id, key) end def delete @chart.pen_delete(@id) self end def name @pen end end ################# class Postscript < TkObject PostscriptID_TBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ PostscriptID_TBL.mutex.synchronize{ PostscriptID_TBL.clear } } def self.new(chart, keys={}) obj = nil PostscriptID_TBL.mutex.synchronize{ unless (obj = PostscriptID_TBL[chart.path]) (obj = self.allocate).instance_eval{ @parent = @chart = chart @cpath = @chart.path @path = @id = 'postscript' Postscript::PostscriptID_TBL[@cpath] = self } end } chart.postscript_configure(keys) if obj && ! keys.empty? obj end def initialize(chart, keys={}) # dummy:: not called by 'new' method @parent = @chart = chart @cpath = @chart.path # Postscript::PostscriptID_TBL[@cpath] = self @chart.postscript_configure(keys) unless keys.empty? @path = @id = 'postscript' end def id @id end def to_eval @id end def cget(option) @chart.postscript_cget(option) end def cget_strict(option) @chart.postscript_cget_strict(option) end def configure(key, value=None) @chart.postscript_configure(key, value) self end def configinfo(key=nil) @chart.postscript_configinfo(key) end def current_configinfo(key=nil) @chart.current_postscript_configinfo(key) end def output(file=nil, keys={}) if file.kind_of?(Hash) keys = file file = nil end ret = @chart.postscript_output(file, keys) if file self else ret end end end ################# class Marker < TkObject extend Tk extend TkItemFontOptkeys extend TkItemConfigOptkeys extend Tk::BLT::PlotComponent::OptKeys MarkerTypeName = nil MarkerTypeToClass = {} MarkerID_TBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ MarkerID_TBL.mutex.synchronize{ MarkerID_TBL.clear } } def Marker.type2class(type) MarkerTypeToClass[type] end def Marker.id2obj(chart, id) cpath = chart.path MarkerID_TBL.mutex.synchronize{ if MarkerID_TBL[cpath] MarkerID_TBL[cpath][id]? MarkerID_TBL[cpath][id]: id else id end } end def self._parse_create_args(keys) fontkeys = {} methodkeys = {} if keys.kind_of? Hash keys = _symbolkey2str(keys) __item_font_optkeys(nil).each{|key| fkey = key.to_s fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey) fkey = "kanji#{key}" fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey) fkey = "latin#{key}" fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey) fkey = "ascii#{key}" fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey) } __item_optkey_aliases(nil).each{|alias_name, real_name| alias_name = alias_name.to_s if keys.has_key?(alias_name) keys[real_name.to_s] = keys.delete(alias_name) end } __item_methodcall_optkeys(nil).each{|key| key = key.to_s methodkeys[key] = keys.delete(key) if keys.key?(key) } __item_ruby2val_optkeys(nil).each{|key, method| key = key.to_s keys[key] = method.call(keys[key]) if keys.has_key?(key) } args = itemconfig_hash_kv(nil, keys) else args = [] end [args, fontkeys] end private_class_method :_parse_create_args def self.create(chart, keys={}) unless self::MarkerTypeName fail RuntimeError, "#{self} is an abstract class" end args, fontkeys = _parse_create_args(keys) idnum = tk_call_without_enc(chart.path, 'marker', 'create', self::MarkerTypeName, *args) chart.marker_configure(idnum, fontkeys) unless fontkeys.empty? idnum.to_i # 'item id' is an integer number end def self.create_type(chart, type, keys={}) args, fontkeys = _parse_create_args(keys) idnum = tk_call_without_enc(chart.path, 'marker', 'create', type, *args) chart.marker_configure(idnum, fontkeys) unless fontkeys.empty? id = idnum.to_i # 'item id' is an integer number obj = self.allocate obj.instance_eval{ @parent = @chart = chart @cpath = chart.path @id = id Tk::BLT::PlotComponent::Marker::MarkerID_TBL.mutex.synchronize{ Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] ||= {} Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self } } obj end def initialize(parent, *args) @parent = @chart = parent @cpath = parent.path @path = @id = create_self(*args) # an integer number as 'item id' Tk::BLT::PlotComponent::Marker::MarkerID_TBL.mutex.synchronize{ Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] ||= {} Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self } end def create_self(*args) self.class.create(@chart, *args) # return an integer as 'item id' end private :create_self def id @id end def to_eval @id end def cget(option) @chart.marker_cget(@id, option) end def cget_strict(option) @chart.marker_cget_strict(@id, option) end def configure(key, value=None) @chart.marker_configure(@id, key, value) self end def configinfo(key=nil) @chart.marker_configinfo(@id, key) end def current_configinfo(key=nil) @chart.current_marker_configinfo(@id, key) end def after(target=None) @chart.marker_after(@id, target) end def before(target=None) @chart.marker_before(@id, target) end def delete @chart.marker_delete(@id) end def exist? @chart.marker_exist(@id) end def type @chart.marker_type(@id) end end class TextMarker < Marker MarkerTypeName = 'text'.freeze MarkerTypeToClass[MarkerTypeName] = self end class LineMarker < Marker MarkerTypeName = 'line'.freeze MarkerTypeToClass[MarkerTypeName] = self end class BitmapMarker < Marker MarkerTypeName = 'bitmap'.freeze MarkerTypeToClass[MarkerTypeName] = self end class ImageMarker < Marker MarkerTypeName = 'image'.freeze MarkerTypeToClass[MarkerTypeName] = self end class PolygonMarker < Marker MarkerTypeName = 'polygon'.freeze MarkerTypeToClass[MarkerTypeName] = self end class WindowMarker < Marker MarkerTypeName = 'window'.freeze MarkerTypeToClass[MarkerTypeName] = self end ################# def __destroy_hook__ Axis::AxisID_TBL.delete(@path) Crosshairs::CrosshairsID_TBL.delete(@path) Element::ElementID_TBL.delete(@path) GridLine::GridLineID_TBL.delete(@path) Legend::LegendID_TBL.delete(@path) Pen::PenID_TBL.delete(@path) Postscript::PostscriptID_TBL.delete(@path) Marker::MarkerID_TBL.delete(@path) super() end ################# def tagid(tag) if tag.kind_of?(Axis) || tag.kind_of?(Crosshairs) || tag.kind_of?(Element) || tag.kind_of?(GridLine) || tag.kind_of?(Legend) || tag.kind_of?(Pen) || tag.kind_of?(Postscript) || tag.kind_of?(Marker) tag.id else tag # maybe an Array of configure paramters end end def _component_bind(target, tag, context, *args) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind([path, target, 'bind', tagid(tag)], context, cmd, *args) self end def _component_bind_append(target, tag, context, *args) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append([path, target, 'bind', tagid(tag)], context, cmd, *args) self end def _component_bind_remove(target, tag, context) _bind_remove([path, target, 'bind', tagid(tag)], context) self end def _component_bindinfo(target, tag, context=nil) _bindinfo([path, target, 'bind', tagid(tag)], context) end private :_component_bind, :_component_bind_append private :_component_bind_remove, :_component_bindinfo def axis_bind(tag, context, *args) _component_bind('axis', tag, context, *args) end def axis_bind_append(tag, context, *args) _component_bind_append('axis', tag, context, *args) end def axis_bind_remove(tag, context) _component_bind_remove('axis', tag, context) end def axis_bindinfo(tag, context=nil) _component_bindinfo('axis', tag, context) end def element_bind(tag, context, *args) _component_bind('element', tag, context, *args) end def element_bind_append(tag, context, *args) _component_bind_append('element', tag, context, *args) end def element_bind_remove(tag, context) _component_bind_remove('element', tag, context) end def element_bindinfo(tag, context=nil) _component_bindinfo('element', tag, context) end def bar_bind(tag, context, *args) _component_bind('bar', tag, context, *args) end def bar_bind_append(tag, context, *args) _component_bind_append('bar', tag, context, *args) end def bar_bind_remove(tag, context) _component_bind_remove('bar', tag, context) end def bar_bindinfo(tag, context=nil) _component_bindinfo('bar', tag, context) end def line_bind(tag, context, *args) _component_bind('line', tag, context, *args) end def line_bind_append(tag, context, *args) _component_bind_append('line', tag, context, *args) end def line_bind_remove(tag, context) _component_bind_remove('line', tag, context) end def line_bindinfo(tag, context=nil) _component_bindinfo('line', tag, context) end def legend_bind(tag, context, *args) _component_bind('legend', tag, context, *args) end def legend_bind_append(tag, context, *args) _component_bind_append('legend', tag, context, *args) end def legend_bind_remove(tag, context) _component_bind_remove('legend', tag, context) end def legend_bindinfo(tag, context=nil) _component_bindinfo('legend', tag, context) end def marker_bind(tag, context, *args) _component_bind('marker', tag, context, *args) end def marker_bind_append(tag, context, *args) _component_bind_append('marker', tag, context, *args) end def marker_bind_remove(tag, context) _component_bind_remove('marker', tag, context) end def marker_bindinfo(tag, context=nil) _component_bindinfo('marker', tag, context) end ################### def axis_create(id=nil, keys={}) # tk_send('axis', 'create', tagid(id), keys) Tk::BLT::PlotComponent::Axis.new(self, tagid(id), keys) end def axis_delete(*ids) tk_send('axis', 'delete', *(ids.collect{|id| tagid(id)})) self end def axis_invtransform(id, val) list(tk_send('axis', 'invtransform', tagid(id), val)) end def axis_limits(id) list(tk_send('axis', 'limits', tagid(id))) end def axis_names(*pats) simplelist(tk_send('axis', 'names', *(pats.collect{|pat| tagid(pat)}))).collect{|axis| Tk::BLT::PlotComponent::Axis.id2obj(self, axis) } end def axis_transform(id, val) list(tk_send('axis', 'transform', tagid(id), val)) end def axis_view(id) tk_send('axis', 'view', tagid(id)) self end def axis_use(id, target=nil) if target Tk::BLT::PlotComponent::Axis.id2obj(self, tk_send('axis', 'use', tagid(id), tagid(target))) else Tk::BLT::PlotComponent::Axis.id2obj(self, tk_send('axis', 'use', tagid(id))) end end ################### def crosshairs_off tk_send_without_enc('crosshairs', 'off') self end def crosshairs_on tk_send_without_enc('crosshairs', 'on') self end def crosshairs_toggle tk_send_without_enc('crosshairs', 'toggle') self end ################### def element_create(id=nil, keys={}) # tk_send('element', 'create', tagid(id), keys) Tk::BLT::PlotComponent::Element.new(self, tagid(id), keys) end def element_activate(*args) if args.empty? list(tk_send('element', 'activate')).collect{|elem| Tk::BLT::PlotComponent::Element.id2obj(self, elem) } else # id, *indices id = args.shift tk_send('element', 'activate', tagid(id), *args) end end def element_closest(x, y, var, *args) if args[-1].kind_of?(Hash) keys = args.pop bool(tk_send('element', 'closest', x, y, var, *(hash_kv(keys).concat(args.collect{|id| tagid(id)})))) else bool(tk_send('element', 'closest', x, y, var, *(args.collect{|id| tagid(id)}))) end end def element_deactivate(*ids) tk_send('element', 'deactivate', *(ids.collect{|id| tagid(id)})) self end def element_delete(*ids) tk_send('element', 'delete', *(ids.collect{|id| tagid(id)})) self end def element_exist?(id) bool(tk_send('element', 'exists', tagid(id))) end def element_names(*pats) simplelist(tk_send('element', 'names', *(pats.collect{|pat| tagid(pat)}))).collect{|elem| Tk::BLT::PlotComponent::Element.id2obj(self, elem) } end def element_show(*names) if names.empty? simplelist(tk_send('element', 'show')) else tk_send('element', 'show', *(names.collect{|n| tagid(n)})) self end end def element_type(id) tk_send('element', 'type', tagid(id)) end ################### def bar_create(id=nil, keys={}) # tk_send('bar', 'create', tagid(id), keys) Tk::BLT::PlotComponent::Bar.new(self, tagid(id), keys) end alias bar bar_create def bar_activate(*args) if args.empty? list(tk_send('bar', 'activate')).collect{|elem| Tk::BLT::PlotComponent::Element.id2obj(self, elem) } else # id, *indices id = args.shift tk_send('bar', 'activate', tagid(id), *args) end end def bar_closest(x, y, var, *args) if args[-1].kind_of?(Hash) keys = args.pop bool(tk_send('bar', 'closest', x, y, var, *(hash_kv(keys).concat(args.collect{|id| tagid(id)})))) else bool(tk_send('bar', 'closest', x, y, var, *(args.collect{|id| tagid(id)}))) end end def bar_deactivate(*ids) tk_send('bar', 'deactivate', *(ids.collect{|id| tagid(id)})) self end def bar_delete(*ids) tk_send('bar', 'delete', *(ids.collect{|id| tagid(id)})) self end def bar_exist?(id) bool(tk_send('bar', 'exists', tagid(id))) end def bar_names(*pats) simplelist(tk_send('bar', 'names', *(pats.collect{|pat| tagid(pat)}))).collect{|elem| Tk::BLT::PlotComponent::Element.id2obj(self, elem) } end def bar_show(*names) if names.empty? simplelist(tk_send('bar', 'show')) else tk_send('bar', 'show', *(names.collect{|n| tagid(n)})) self end end def bar_type(id) tk_send('bar', 'type', tagid(id)) end ################### def line_create(id=nil, keys={}) # tk_send('line', 'create', tagid(id), keys) Tk::BLT::PlotComponent::Line.new(self, tagid(id), keys) end alias bar line_create def line_activate(*args) if args.empty? list(tk_send('line', 'activate')).collect{|elem| Tk::BLT::PlotComponent::Element.id2obj(self, elem) } else # id, *indices id = args.shift tk_send('line', 'activate', tagid(id), *args) end end def line_closest(x, y, var, *args) if args[-1].kind_of?(Hash) keys = args.pop bool(tk_send('line', 'closest', x, y, var, *(hash_kv(keys).concat(args.collect{|id| tagid(id)})))) else bool(tk_send('line', 'closest', x, y, var, *(args.collect{|id| tagid(id)}))) end end def line_deactivate(*ids) tk_send('line', 'deactivate', *(ids.collect{|id| tagid(id)})) self end def line_delete(*ids) tk_send('line', 'delete', *(ids.collect{|id| tagid(id)})) self end def line_exist?(id) bool(tk_send('line', 'exists', tagid(id))) end def line_names(*pats) simplelist(tk_send('line', 'names', *(pats.collect{|pat| tagid(pat)}))).collect{|elem| Tk::BLT::PlotComponent::Element.id2obj(self, elem) } end def line_show(*names) if names.empty? simplelist(tk_send('line', 'show')) else tk_send('line', 'show', *(names.collect{|n| tagid(n)})) self end end def line_type(id) tk_send('line', 'type', tagid(id)) end ################### def gridline_off tk_send_without_enc('grid', 'off') self end def gridline_on tk_send_without_enc('grid', 'on') self end def gridline_toggle tk_send_without_enc('grid', 'toggle') self end ################### def legend_window_create(parent=nil, keys=nil) if parent.kind_of?(Hash) keys = _symbolkey2str(parent) parent = keys.delete('parent') widgetname = keys.delete('widgetname') keys.delete('without_creating') elsif keys keys = _symbolkey2str(keys) widgetname = keys.delete('widgetname') keys.delete('without_creating') end legend = self.class.new(parent, :without_creating=>true, :widgetname=>widgetname) class << legend def __destroy_hook__ TkCore::INTERP.tk_windows.delete(@path) end end if keys self.legend_configure(keys.update('position'=>legend)) else self.legend_configure('position'=>legend) end legend end def legend_activate(*pats) list(tk_send('legend', 'activate', *(pats.collect{|pat| tagid(pat)}))).collect{|elem| Tk::BLT::PlotComponent::Element.id2obj(self, elem) } end def legend_deactivate(*pats) list(tk_send('legend', 'deactivate', *(pats.collect{|pat| tagid(pat)}))).collect{|elem| Tk::BLT::PlotComponent::Element.id2obj(self, elem) } end def legend_get(pos, y=nil) if y Tk::BLT::PlotComponent::Element.id2obj(self, tk_send('legend', 'get', _at(pos, y))) else Tk::BLT::PlotComponent::Element.id2obj(self, tk_send('legend', 'get', pos)) end end ################### def pen_create(id=nil, keys={}) # tk_send('pen', 'create', tagid(id), keys) Tk::BLT::PlotComponent::Pen.new(self, tagid(id), keys) end def pen_delete(*ids) tk_send('pen', 'delete', *(ids.collect{|id| tagid(id)})) self end def pen_names(*pats) simplelist(tk_send('pen', 'names', *(pats.collect{|pat| tagid(pat)}))).collect{|pen| Tk::BLT::PlotComponent::Pen.id2obj(self, pen) } end ################### def postscript_output(file=nil, keys={}) if file.kind_of?(Hash) keys = file file = nil end if file tk_send('postscript', 'output', file, keys) self else tk_send('postscript', 'output', keys) end end ################### def marker_create(type, keys={}) case type when :text, 'text' Tk::BLT::PlotComponent::TextMarker.new(self, keys) when :line, 'line' Tk::BLT::PlotComponent::LineMarker.new(self, keys) when :bitmap, 'bitmap' Tk::BLT::PlotComponent::BitmapMarker.new(self, keys) when :image, 'image' Tk::BLT::PlotComponent::ImageMarker.new(self, keys) when :polygon, 'polygon' Tk::BLT::PlotComponent::PolygonMarker.new(self, keys) when :window, 'window' Tk::BLT::PlotComponent::WindowMarker.new(self, keys) else if type.kind_of?(Tk::BLT::PlotComponent::Marker) type.new(self, keys) else Tk::BLT::PlotComponent::Marker.create_type(self, type, keys) end end end def marker_after(id, target=nil) if target tk_send_without_enc('marker', 'after', tagid(id), tagid(target)) else tk_send_without_enc('marker', 'after', tagid(id)) end self end def marker_before(id, target=None) if target tk_send_without_enc('marker', 'before', tagid(id), tagid(target)) else tk_send_without_enc('marker', 'before', tagid(id)) end self end def marker_delete(*ids) tk_send('marker', 'delete', *(ids.collect{|id| tagid(id)})) self end def marker_exist?(id) bool(tk_send('marker', 'exists', tagid(id))) end def marker_names(*pats) simplelist(tk_send('marker', 'names', *(pats.collect{|pat| tagid(pat)}))).collect{|id| Tk::BLT::PlotComponent::Marker.id2obj(self, id) } end def marker_type(id) tk_send('marker', 'type', tagid(id)) end ################### def xaxis_cget(option) itemcget('xaxis', option) end def xaxis_cget_strict(option) itemcget_strict('xaxis', option) end def xaxis_configure(slot, value=None) if slot.kind_of?(Hash) slot = _symbolkey2str(slot) if cmd = slot.delete('command') slot['command'] = proc{|w, tick| cmd.call(TkComm.window(w), TkComm.num_or_str(tick)) } end elsif slot == :command || slot == 'command' cmd = value value = proc{|w, tick| cmd.call(TkComm.window(w), TkComm.num_or_str(tick)) } end itemconfigure('xaxis', slot, value) end def xaxis_configinfo(slot=nil) itemconfiginfo('xaxis', slot) end def current_xaxis_configinfo(slot=nil) current_itemconfiginfo('xaxis', slot) end def xaxis_bind(context, *args) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind([path, 'xaxis', 'bind'], context, cmd, *args) self end def xaxis_bind_append(context, *args) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append([path, 'xaxis', 'bind'], context, cmd, *args) self end def xaxis_bind_remove(context) _bind_remove([path, 'xaxis', 'bind'], context) self end def xaxis_bindinfo(context=nil) _bindinfo([path, 'xaxis', 'bind'], context) end def xaxis_invtransform(val) list(tk_send('xaxis', 'invtransform', val)) end def xaxis_limits list(tk_send('xaxis', 'limits')) end def xaxis_transform(val) list(tk_send('xaxis', 'transform', val)) end def xaxis_use(target=nil) if target Tk::BLT::PlotComponent::Axis.id2obj(self, tk_send('xaxis', 'use', tagid(target))) else Tk::BLT::PlotComponent::Axis.id2obj(self, tk_send('xaxis', 'use')) end end def x2axis_cget(option) itemcget('x2axis', option) end def x2axis_cget_strict(option) itemcget_strict('x2axis', option) end def x2axis_configure(slot, value=None) if slot.kind_of?(Hash) slot = _symbolkey2str(slot) if cmd = slot.delete('command') slot['command'] = proc{|w, tick| cmd.call(TkComm.window(w), TkComm.num_or_str(tick)) } end elsif slot == :command || slot == 'command' cmd = value value = proc{|w, tick| cmd.call(TkComm.window(w), TkComm.num_or_str(tick)) } end itemconfigure('x2axis', slot, value) end def x2axis_configinfo(slot=nil) itemconfiginfo('x2axis', slot) end def current_x2axis_configinfo(slot=nil) current_itemconfiginfo('x2axis', slot) end def x2axis_bind(context, *args) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind([path, 'x2axis', 'bind'], context, cmd, *args) self end def x2axis_bind_append(context, *args) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append([path, 'x2axis', 'bind'], context, cmd, *args) self end def x2axis_bind_remove(context) _bind_remove([path, 'x2axis', 'bind'], context) self end def x2axis_bindinfo(context=nil) _bindinfo([path, 'x2axis', 'bind'], context) end def x2axis_invtransform(val) list(tk_send('x2axis', 'invtransform', val)) end def x2axis_limits list(tk_send('x2axis', 'limits')) end def x2axis_transform(val) list(tk_send('x2axis', 'transform', val)) end def x2axis_use(target=nil) if target Tk::BLT::PlotComponent::Axis.id2obj(self, tk_send('x2axis', 'use', tagid(target))) else Tk::BLT::PlotComponent::Axis.id2obj(self, tk_send('x2axis', 'use')) end end def yaxis_cget(option) itemcget('yaxis', option) end def yaxis_cget_strict(option) itemcget_strict('yaxis', option) end def yaxis_configure(slot, value=None) if slot.kind_of?(Hash) slot = _symbolkey2str(slot) if cmd = slot.delete('command') slot['command'] = proc{|w, tick| cmd.call(TkComm.window(w), TkComm.num_or_str(tick)) } end elsif slot == :command || slot == 'command' cmd = value value = proc{|w, tick| cmd.call(TkComm.window(w), TkComm.num_or_str(tick)) } end itemconfigure('yaxis', slot, value) end def yaxis_configinfo(slot=nil) itemconfiginfo('yaxis', slot) end def current_yaxis_configinfo(slot=nil) current_itemconfiginfo('yaxis', slot) end def yaxis_bind(context, *args) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind([path, 'yaxis', 'bind'], context, cmd, *args) self end def yaxis_bind_append(context, *args) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append([path, 'yaxis', 'bind'], context, cmd, *args) self end def yaxis_bind_remove(context) _bind_remove([path, 'yaxis', 'bind'], context) self end def yaxis_bindinfo(context=nil) _bindinfo([path, 'yaxis', 'bind'], context) end def yaxis_invtransform(val) list(tk_send('yaxis', 'invtransform', val)) end def yaxis_limits list(tk_send('yaxis', 'limits')) end def yaxis_transform(val) list(tk_send('yaxis', 'transform', val)) end def yaxis_use(target=nil) if target Tk::BLT::PlotComponent::Axis.id2obj(self, tk_send('yaxis', 'use', tagid(target))) else Tk::BLT::PlotComponent::Axis.id2obj(self, tk_send('yaxis', 'use')) end end def y2axis_cget(option) itemcget('y2axis', option) end def y2axis_cget_strict(option) itemcget_strict('y2axis', option) end def y2axis_configure(slot, value=None) if slot.kind_of?(Hash) slot = _symbolkey2str(slot) if cmd = slot.delete('command') slot['command'] = proc{|w, tick| cmd.call(TkComm.window(w), TkComm.num_or_str(tick)) } end elsif slot == :command || slot == 'command' cmd = value value = proc{|w, tick| cmd.call(TkComm.window(w), TkComm.num_or_str(tick)) } end itemconfigure('y2axis', slot, value) end def y2axis_configinfo(slot=nil) axis_configinfo('y2axis', slot) end def current_y2axis_configinfo(slot=nil) current_itemconfiginfo('y2axis', slot) end def y2axis_bind(context, *args) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind([path, 'y2axis', 'bind'], context, cmd, *args) self end def y2axis_bind_append(context, *args) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append([path, 'y2axis', 'bind'], context, cmd, *args) self end def y2axis_bind_remove(context) _bind_remove([path, 'y2axis', 'bind'], context) self end def y2axis_bindinfo(context=nil) _bindinfo([path, 'y2axis', 'bind'], context) end def y2axis_invtransform(val) list(tk_send('y2axis', 'invtransform', val)) end def y2axis_limits list(tk_send('y2axis', 'limits')) end def y2axis_transform(val) list(tk_send('y2axis', 'transform', val)) end def y2axis_use(target=nil) if target Tk::BLT::PlotComponent::Axis.id2obj(self, tk_send('y2axis', 'use', tagid(target))) else Tk::BLT::PlotComponent::Axis.id2obj(self, tk_send('y2axis', 'use')) end end end end ================================================ FILE: ext/tk/lib/tkextlib/blt/container.rb ================================================ # # tkextlib/blt/container.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/blt.rb' module Tk::BLT class Container < TkWindow TkCommandNames = ['::blt::container'.freeze].freeze WidgetClassName = 'Container'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'name' end private :__strval_optkeys def find_command(pat) Hash[*simplelist(tk_send_without_enc('find', '-command', pat))] end def find_name(pat) Hash[*simplelist(tk_send_without_enc('find', '-name', pat))] end end end ================================================ FILE: ext/tk/lib/tkextlib/blt/cutbuffer.rb ================================================ # # tkextlib/blt/cutbuffer.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/blt.rb' module Tk::BLT module CutBuffer TkCommandNames = ['::blt::cutbuffer'.freeze].freeze def self.get(num = 0) Tk.tk_call('::blt::cutbuffer', 'get', num) end def self.rotate(count = 1) Tk.tk_call('::blt::cutbuffer', 'rotate', count) end def self.set(val, num = 0) Tk.tk_call('::blt::cutbuffer', 'set', val, num) end end end ================================================ FILE: ext/tk/lib/tkextlib/blt/dragdrop.rb ================================================ # # tkextlib/blt/dragdrop.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/itemconfig' require 'tkextlib/blt.rb' module Tk::BLT module DragDrop extend TkCore TkCommandNames = ['::blt::drag&drop'.freeze].freeze class Token < TkWindow WidgetClassName = 'DragDropToken'.freeze WidgetClassNames[WidgetClassName] = self def initialize(arg) if arg.kind_of?(Hash) # arg is a hash includes the widgetpath of token arg = _symbolkey2str(arg) install_win(nil, arg['widgetname']) else # arg is a drag&drop source tk_call('::blt::drag&drop', 'source', arg) install_win(nil, tk_call('::blt::drag&drop', 'token', arg)) end end end ################################### extend TkItemConfigMethod extend Tk::ValidateConfigure class << self def __item_config_cmd(id) # id := ['source'|'target', win] ['::blt::drag&drop', id[0], id[1]] end private :__item_config_cmd def __item_boolval_optkeys(id) super(id) << 'selftarget' end private :__item_boolval_optkeys def __item_listval_optkeys(id) super(id) << 'send' end private :__item_listval_optkeys def __item_strval_optkeys(id) super(id) << 'rejectbg' << 'rejectfg' << 'tokenbg' end private :__item_strval_optkeys undef itemcget private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo def source_configure(win, slot, value=None) itemconfigure(['source', win], slot, value) end def source_configinfo(win, slot=nil) itemconfiginfo(['source', win], slot) end def current_source_configinfo(win, slot=nil) current_itemconfiginfo(['source', win], slot) end end class PackageCommand < TkValidateCommand class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [ ?t, ?w, :token ], [ ?W, ?w, :widget ], nil ] PROC_TBL = [ [ ?w, TkComm.method(:window) ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end _setup_subst_table(KEY_TBL, PROC_TBL) def self.ret_val(val) val end end def self._config_keys ['packagecmd'] end end class SiteCommand < TkValidateCommand class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [ ?s, ?b, :compatible ], [ ?t, ?w, :token ], nil ] PROC_TBL = [ [ ?b, TkComm.method(:bool) ], [ ?w, TkComm.method(:window) ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end _setup_subst_table(KEY_TBL, PROC_TBL) def self.ret_val(val) val end end def self._config_keys ['sitecmd'] end end def self.__validation_class_list super() << PackageCommand << SiteCommand end class << self Tk::ValidateConfigure.__def_validcmd(binding, PackageCommand) Tk::ValidateConfigure.__def_validcmd(binding, SiteCommand) end ################################### class DnD_Handle < TkUtil::CallbackSubst KEY_TBL = [ [ ?i, ?s, :ip_name ], [ ?v, ?v, :value ], [ ?W, ?w, :widget ], nil ] PROC_TBL = [ [ ?i, TkComm.method(:string) ], [ ?v, TkComm.method(:tk_tcl2ruby) ], [ ?w, TkComm.method(:window) ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end _setup_subst_table(KEY_TBL, PROC_TBL) end def self.source_handler(win, datatype, cmd=Proc.new, *args) _bind_for_event_class(DnD_Handle, ['::blt::drag&drop', 'source', win, 'handler'], cmd, *args) end def self.target_handler(win, datatype, cmd=Proc.new, *args) _bind_for_event_class(DnD_Handle, ['::blt::drag&drop', 'target', win, 'handler'], cmd, *args) end ################################### def self.init_source(win) tk_call('::blt::drag&drop', 'source', win) end def self.source() list(tk_call('::blt::drag&drop', 'source')) end def self.source_handler_list(win) simplelist(tk_call('::blt::drag&drop', 'source', win, 'handler')) end def self.source_handler_info(win, type) tk_tcl2ruby(tk_call('::blt::drag&drop', 'source', win, 'handler', type)) end def self.target list(tk_call('::blt::drag&drop', 'target')) end def self.target_handler_list(win) simplelist(tk_call('::blt::drag&drop', 'target', win, 'handler')) end def self.handle_target(win, type, val=None) tk_call('::blt::drag&drop', 'target', win, 'handle', type, val) end def self.token(win) window(tk_call('::blt::drag&drop', 'token', win)) end def self.drag(win, x, y) tk_call('::blt::drag&drop', 'drag', win, x, y) end def self.drop(win, x, y) tk_call('::blt::drag&drop', 'drop', win, x, y) end def self.errors(cmd=Proc.new) tk_call('::blt::drag&drop', 'errors', cmd) end def self.active bool(tk_call('::blt::drag&drop', 'active')) end def self.location(x=None, y=None) list(tk_call('::blt::drag&drop', 'location', x, y)) end end end ================================================ FILE: ext/tk/lib/tkextlib/blt/eps.rb ================================================ # # tkextlib/blt/eps.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/canvas' require 'tkextlib/blt.rb' module Tk::BLT class EPS < TkcItem CItemTypeName = 'eps'.freeze CItemTypeToClass[CItemTypeName] = self end end class Tk::Canvas alias __BLT_EPS_item_strval_optkeys __item_strval_optkeys def __item_strval_optkeys(id) __BLT_EPS_item_strval_optkeys(id) + [ 'shadowcolor', 'title', 'titlecolor' ] end private :__item_strval_optkeys alias __BLT_EPS_item_boolval_optkeys __item_boolval_optkeys def __item_boolval_optkeys(id) __BLT_EPS_item_boolval_optkeys(id) + ['showimage'] end private :__item_boolval_optkeys end ================================================ FILE: ext/tk/lib/tkextlib/blt/graph.rb ================================================ # # tkextlib/blt/graph.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/blt.rb' require 'tkextlib/blt/component.rb' module Tk::BLT class Graph < TkWindow TkCommandNames = ['::blt::graph'.freeze].freeze WidgetClassName = 'Graph'.freeze WidgetClassNames[WidgetClassName] = self include PlotComponent include GraphCommand def __boolval_optkeys ['bufferelements', 'invertxy'] end private :__boolval_optkeys def __strval_optkeys ['text', 'label', 'title', 'file', 'plotbackground'] end private :__strval_optkeys =begin BarElement_ID = ['blt_graph_bar'.freeze, '00000'.taint].freeze def bar(elem=nil, keys={}) if elem.kind_of?(Hash) keys = elem elem = nil end unless elem elem = BarElement_ID.join(TkCore::INTERP._ip_id_).freeze BarElement_ID[1].succ! end tk_send('bar', elem, keys) Element.new(self, elem, :without_creating=>true) end =end def extents(item) num_or_str(tk_send_without_enc('extents', item)) end def invtransform(x, y) list(tk_send_without_enc('invtransform', x, y)) end def inside(x, y) bool(tk_send_without_enc('inside', x, y)) end def snap(output, keys={}) tk_send_without_enc('snap', *(hash_kv(keys, false) + output)) self end def transform(x, y) list(tk_send_without_enc('transform', x, y)) end end end ================================================ FILE: ext/tk/lib/tkextlib/blt/htext.rb ================================================ # # tkextlib/blt/htext.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/itemconfig.rb' require 'tkextlib/blt.rb' module Tk::BLT class Htexttrue) end =end def extents(item) num_or_str(tk_send_without_enc('extents', item)) end def invtransform(x, y) list(tk_send_without_enc('invtransform', x, y)) end def inside(x, y) bool(tk_send_without_enc('inside', x, y)) end def metafile(file=None) # Windows only tk_send('metafile', file) self end def snap(output, keys={}) tk_send_without_enc('snap', *(hash_kv(keys, false) + output)) self end def transform(x, y) list(tk_send_without_enc('transform', x, y)) end end end ================================================ FILE: ext/tk/lib/tkextlib/blt/table.rb ================================================ # # tkextlib/blt/table.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/itemconfig.rb' require 'tkextlib/blt.rb' module Tk::BLT module Table include Tk extend Tk extend TkItemConfigMethod TkCommandNames = ['::blt::table'.freeze].freeze module TableContainer def blt_table_add(*args) Tk::BLT::Table.add(self, *args) self end def blt_table_arrange() Tk::BLT::Table.arrange(self) self end def blt_table_cget(*args) Tk::BLT::Table.cget(self, *args) end def blt_table_cget_strict(*args) Tk::BLT::Table.cget_strict(self, *args) end def blt_table_configure(*args) Tk::BLT::Table.configure(self, *args) self end def blt_table_configinfo(*args) Tk::BLT::Table.configinfo(self, *args) end def blt_table_current_configinfo(*args) Tk::BLT::Table.current_configinfo(self, *args) end def blt_table_locate(x, y) Tk::BLT::Table.locate(self, x, y) end def blt_table_delete(*args) Tk::BLT::Table.delete(self, *args) self end def blt_table_extents(item) Tk::BLT::Table.extents(self, item) end def blt_table_insert(*args) Tk::BLT::Table.insert(self, *args) self end def blt_table_insert_before(*args) Tk::BLT::Table.insert_before(self, *args) self end def blt_table_insert_after(*args) Tk::BLT::Table.insert_after(self, *args) self end def blt_table_join(first, last) Tk::BLT::Table.join(self, first, last) self end def blt_table_save() Tk::BLT::Table.save(self) end def blt_table_search(*args) Tk::BLT::Table.search(self, *args) end def blt_table_split(*args) Tk::BLT::Table.split(self, *args) self end def blt_table_itemcget(*args) Tk::BLT::Table.itemcget(self, *args) end def blt_table_itemcget_strict(*args) Tk::BLT::Table.itemcget_strict(self, *args) end def blt_table_itemconfigure(*args) Tk::BLT::Table.itemconfigure(self, *args) self end def blt_table_itemconfiginfo(*args) Tk::BLT::Table.itemconfiginfo(self, *args) end def blt_table_current_itemconfiginfo(*args) Tk::BLT::Table.current_itemconfiginfo(self, *args) end def blt_table_iteminfo(item) Tk::BLT::Table.iteminfo(self, item) end end end end ############################################ class << Tk::BLT::Table def __item_cget_cmd(id) # id := [ container, item ] win = (id[0].kind_of?(TkWindow))? id[0].path: id[0].to_s ['::blt::table', 'cget', win, id[1]] end private :__item_cget_cmd def __item_config_cmd(id) # id := [ container, item, ... ] container, *items = id win = (container.kind_of?(TkWindow))? container.path: container.to_s ['::blt::table', 'configure', win, *items] end private :__item_config_cmd def __item_pathname(id) win = (id[0].kind_of?(TkWindow))? id[0].path: id[0].to_s win + ';' end private :__item_pathname alias __itemcget itemcget alias __itemcget_strict itemcget_strict alias __itemconfigure itemconfigure alias __itemconfiginfo itemconfiginfo alias __current_itemconfiginfo current_itemconfiginfo private :__itemcget, :__itemcget_strict private :__itemconfigure, :__itemconfiginfo, :__current_itemconfiginfo def __boolval_optkeys super() << 'propagate' end private :__boolval_optkeys def tagid(tag) if tag.kind_of?(Array) case tag[0] when Integer # [row, col] tag.join(',') when :c, :C, 'c', 'C', :r, :R, 'r', 'R' # c0 or r1 or C*, and so on tag.collect{|elem| elem.to_s}.join('') else tag end elsif tag.kind_of?(TkWindow) _epath(tag) else tag end end def tagid2obj(tagid) tagid end ############################################ def cget(container, option) __itemcget([container], option) end def cget_strict(container, option) __itemcget_strict([container], option) end def configure(container, *args) __itemconfigure([container], *args) end def configinfo(container, *args) __itemconfiginfo([container], *args) end def current_configinfo(container, *args) __current_itemconfiginfo([container], *args) end def itemcget(container, item, option) __itemcget([container, tagid(item)], option) end def itemcget_strict(container, item, option) __itemcget_strict([container, tagid(item)], option) end def itemconfigure(container, *args) if args[-1].kind_of?(Hash) # container, item, item, ... , hash_optkeys keys = args.pop fail ArgumentError, 'no item is given' if args.empty? id = [container] args.each{|item| id << tagid(item)} __itemconfigure(id, keys) else # container, item, item, ... , option, value val = args.pop opt = args.pop fail ArgumentError, 'no item is given' if args.empty? id = [container] args.each{|item| id << tagid(item)} __itemconfigure(id, opt, val) end container end def itemconfiginfo(container, *args) slot = args[-1] if slot.kind_of?(String) || slot.kind_of?(Symbol) slot = slot.to_s if slot[0] == ?. || slot =~ /^\d+,\d+$/ || slot =~ /^(c|C|r|R)(\*|\d+)/ # widget || row,col || Ci or Ri slot = nil else # option slot = args.pop end else slot = nil end fail ArgumentError, 'no item is given' if args.empty? id = [container] args.each{|item| id << tagid(item)} __itemconfiginfo(id, slot) end def current_itemconfiginfo(container, *args) slot = args[-1] if slot.kind_of?(String) || slot.kind_of?(Symbol) slot = slot.to_s if slot[0] == ?. || slot =~ /^\d+,\d+$/ || slot =~ /^(c|C|r|R)(\*|\d+)/ # widget || row,col || Ci or Ri slot = nil else # option slot = args.pop end else slot = nil end fail ArgumentError, 'no item is given' if args.empty? id = [container] args.each{|item| id << tagid(item)} __current_itemconfiginfo(id, slot) end def info(container) ret = {} inf = list(tk_call('::blt::table', 'info', container)) until inf.empty? opt = inf.slice!(0..1) ret[opt[1..-1]] = opt[1] end ret end def iteminfo(container, item) inf = list(tk_call('::blt::table', 'info', container, tagid(item)).chomp) ret = [] until inf.empty? || (inf[0].kind_of?(String) && inf[0] =~ /^-/) ret << inf.shift end if inf.length > 1 keys = {} while inf.length > 1 opt = inf.slice!(0..1) keys[opt[0][1..-1]] = opt[1] end ret << keys end ret end ############################################ def create_container(container) tk_call('::blt::table', container) begin class << container include Tk::BLT::Table::TableContainer end rescue warn('fail to include TableContainer methods (frozen object?)') end container end def add(container, *args) if args.empty? tk_call('::blt::table', container) else args = args.collect{|arg| if arg.kind_of?(TkWindow) _epath(arg) elsif arg.kind_of?(Array) # index arg.join(',') else arg end } tk_call('::blt::table', container, *args) end container end def arrange(container) tk_call('::blt::table', 'arrange', container) container end def delete(container, *args) tk_call('::blt::table', 'delete', container, *args) end def extents(container, item) ret = [] inf = list(tk_call('::blt::table', 'extents', container, item)) ret << inf.slice!(0..4) until inf.empty? ret end def forget(*wins) wins = wins.collect{|win| _epath(win)} tk_call('::blt::table', 'forget', *wins) end def insert(container, *args) tk_call('::blt::table', 'insert', container, *args) end def insert_before(container, *args) tk_call('::blt::table', 'insert', container, '-before', *args) end def insert_after(container, *args) tk_call('::blt::table', 'insert', container, '-after', *args) end def join(container, first, last) tk_call('::blt::table', 'join', container, first, last) end def locate(container, x, y) tk_call('::blt::table', 'locate', container, x, y) end def containers(arg={}) list(tk_call('::blt::table', 'containers', *hash_kv(arg))) end def containers_pattern(pat) list(tk_call('::blt::table', 'containers', '-pattern', pat)) end def containers_slave(win) list(tk_call('::blt::table', 'containers', '-slave', win)) end def save(container) tk_call('::blt::table', 'save', container) end def search(container, keys={}) list(tk_call('::blt::table', 'containers', *hash_kv(keys))) end def split(container, *args) tk_call('::blt::table', 'split', container, *args) end end ================================================ FILE: ext/tk/lib/tkextlib/blt/tabnotebook.rb ================================================ # # tkextlib/blt/tabnotebook.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/blt.rb' require 'tkextlib/blt/tabset.rb' module Tk::BLT class Tabnotebook < Tabset TkCommandNames = ['::blt::tabnotebook'.freeze].freeze WidgetClassName = 'Tabnotebook'.freeze WidgetClassNames[WidgetClassName] = self def get_tab(index) Tk::BLT::Tabset::Tab.id2obj(tk_send_without_enc('id', tagindex(index))) end alias get_id get_tab end end ================================================ FILE: ext/tk/lib/tkextlib/blt/tabset.rb ================================================ # # tkextlib/blt/tabset.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/blt.rb' module Tk::BLT class Tabset < TkWindow class Tab < TkObject include TkTreatItemFont TabID_TBL = TkCore::INTERP.create_table (TabsetTab_ID = ['blt_tabset_tab'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } TkCore::INTERP.init_ip_env{ TabID_TBL.mutex.synchronize{ TabID_TBL.clear } } def self.id2obj(tabset, id) tpath = tabset.path TabID_TBL.mutex.synchronize{ if TabID_TBL[tpath] TabID_TBL[tpath][id]? TabID_TBL[tpath]: id else id end } end def self.new(parent, pos=nil, name=nil, keys={}) if pos.kind_of?(Hash) keys = pos name = nil pos = nil end if name.kind_of?(Hash) keys = name name = nil end obj = nil TabID_TBL.mutex.synchronize{ if name && TabID_TBL[parent.path] && TabID_TBL[parent.path][name] obj = TabID_TBL[parent.path][name] obj.configure if keys && ! keys.empty? else (obj = self.allocate).instance_eval{ initialize(parent, pos, name, keys) TabID_TBL[@tpath] = {} unless TabID_TBL[@tpath] TabID_TBL[@tpath][@id] = self } end } obj end def initialize(parent, pos, name, keys) @t = parent @tpath = parent.path if name @path = @id = name unless (list(tk_call(@tpath, 'tab', 'names', @id)).empty?) if pos idx = tk_call(@tpath, 'index', '-name', @id) if pos.to_s == 'end' tk_call(@tpath, idx, 'moveto', 'after', 'end') else tk_call(@tpath, idx, 'moveto', 'before', pos) end end tk_call(@tpath, 'tab', 'configure', @id, keys) else pos = 'end' unless pos tk_call(@tpath, 'insert', pos, @id, keys) end else TabsetTab_ID.mutex.synchronize{ @path = @id = TabsetTab_ID.join(TkCore::INTERP._ip_id_) TabsetTab_ID[1].succ! } pos = 'end' unless pos tk_call(@tpath, 'insert', pos, @id, keys) end end #def bind(context, cmd=Proc.new, *args) # @t.tab_bind(@id, context, cmd, *args) # self #end def bind(context, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end @t.tab_bind(@id, context, cmd, *args) self end #def bind_append(context, cmd=Proc.new, *args) # @t.tab_bind_append(@id, context, cmd, *args) # self #end def bind_append(context, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end @t.tab_bind_append(@id, context, cmd, *args) self end def bind_remove(context) @t.tab_bind_remove(@id, context) self end def bindinfo(context=nil) @t.tab_bindinfo(@id, context) end def cget(*args) @t.tab_cget(@id, *args) end def cget_strict(*args) @t.tab_cget_strict(@id, *args) end def configure(*args) @t.tab_configure(@id, *args) end def configinfo(*args) @t.tab_configinfo(@id, *args) end def current_configinfo(*args) @t.current_tab_configinfo(@id, *args) end def delete() @t.delete(@id) TabID_TBL.mutex.synchronize{ TabID_TBL[@tpath].delete(@id) } self end def get_name() @id.dup end def focus() @t.focus(self.index) end def index() @t.index_name(@id) end def invoke() @t.invoke(self.index) end def move_before(idx) @t.move_before(self.index, idx) end def move_after(idx) @t.move_after(self.index, idx) end def perforation_highlight(mode) @t.perforation.highlight(self.index, mode) end def perforation_invoke() @t.perforation.invoke(self.index) end def see() @t.see(self.index) end def tearoff(name=None) @t.tab_tearoff(self.index, *args) end end ######################################## class NamedTab < Tab def self.new(parent, name) super(parent, nil, name, {}) end end ######################################## include X_Scrollable include TkItemConfigMethod TkCommandNames = ['::blt::tabset'.freeze].freeze WidgetClassName = 'Tabset'.freeze WidgetClassNames[WidgetClassName] = self def __destroy_hook__ Tk::BLT::Tabset::Tab::TabID_TBL.mutex.synchronize{ Tk::BLT::Tabset::Tab::TabID_TBL.delete(@path) } end ######################################## def __boolval_optkeys super() << 'samewidth' << 'tearoff' end private :__strval_optkeys def __strval_optkeys super() << 'tabbackground' << 'tabforeground' end private :__strval_optkeys def __item_cget_cmd(id) [self.path, 'tab', 'cget', id] end private :__item_cget_cmd def __item_config_cmd(id) [self.path, 'tab', 'configure', id] end private :__item_config_cmd def __item_pathname(tagOrId) if tagOrId.kind_of?(Tk::BLT::Tabset::Tab) self.path + ';' + tagOrId.id.to_s else self.path + ';' + tagOrId.to_s end end private :__item_pathname alias tab_cget itemcget alias tab_cget_strict itemcget_strict alias tab_configure itemconfigure alias tab_configinfo itemconfiginfo alias current_tab_configinfo current_itemconfiginfo def __item_strval_optkeys(id) super(id) << 'shadow' end private :__item_strval_optkeys def tagid(tab) if tab.kind_of?(Tk::BLT::Tabset::Tab) tab.id else tab end end def tagindex(tab) if tab.kind_of?(Tk::BLT::Tabset::Tab) tab.index else tab end end ######################################## def activate(index) tk_send('activate', tagindex(index)) self end alias highlight activate #def tabbind(tag, context, cmd=Proc.new, *args) # _bind([path, "bind", tagid(tag)], context, cmd, *args) # self #end def tabbind(tag, context, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind([path, "bind", tagid(tag)], context, cmd, *args) self end #def tabbind_append(tag, context, cmd=Proc.new, *args) # _bind_append([path, "bind", tagid(tag)], context, cmd, *args) # self #end def tabbind_append(tag, context, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append([path, "bind", tagid(tag)], context, cmd, *args) self end def tabbind_remove(tag, context) _bind_remove([path, "bind", tagid(tag)], context) self end def tabbindinfo(tag, context=nil) _bindinfo([path, "bind", tagid(tag)], context) end def delete(first, last=None) tk_send('delete', tagindex(first), tagindex(last)) if first.kind_of?(Tk::BLT::Tabset::Tab) TabID_TBL.mutex.synchronize{ TabID_TBL[@path].delete(first.id) } end # middle tabs of the range are unknown if last.kind_of?(Tk::BLT::Tabset::Tab) TabID_TBL.mutex.synchronize{ TabID_TBL[@path].delete(last.id) } end self end def focus(index) tk_send('focus', tagindex(index)) self end def get_tab(index) Tk::BLT::Tabset::Tab.id2obj(tk_send_without_enc('get', tagindex(index))) end def index(str) num_or_str(tk_send('index', str)) end def index_name(tab) num_or_str(tk_send('index', '-mame', tagid(tab))) end def insert(pos, tab, keys={}) Tk::BLT::Tabset::Tab.new(self, tagindex(pos), tagid(tab), keys) end def invoke(index) tk_send('invoke', tagindex(index)) end def move_before(index, base_idx) tk_send('move', tagindex(index), 'before', tagindex(base_idx)) self end def move_after(index, base_idx) tk_send('move', tagindex(index), 'after', tagindex(base_idx)) self end def nearest(x, y) Tk::BLT::Tabset::Tab.id2obj(num_or_str(tk_send_without_enc('nearest', x, y))) end def perforation_highlight(index, mode) tk_send('perforation', 'highlight', tagindex(index), mode) self end def perforation_invoke(index) tk_send('perforation', 'invoke', tagindex(index)) end def scan_mark(x, y) tk_send_without_enc('scan', 'mark', x, y) self end def scan_dragto(x, y) tk_send_without_enc('scan', 'dragto', x, y) self end def see(index) tk_send('see', tagindex(index)) self end def size() number(tk_send_without_enc('size')) end def select(index) tk_send('select', tagindex(index)) self end def tab_names(pat=None) simplelist(tk_send('tab', 'names', pat)).collect{|name| Tk::BLT::Tabset::Tab.id2obj(name) } end def tab_tearoff(index, name=None) window(tk_send('tab', 'tearoff', tagindex(index), name)) end def xscrollcommand(cmd=Proc.new) configure_cmd 'scrollcommand', cmd self end alias scrollcommand xscrollcommand def xview(*index) if index.empty? list(tk_send_without_enc('view')) else tk_send_without_enc('view', *index) self end end alias view xview alias view_moveto xview_moveto alias view_scroll xview_scroll alias scrollbar xscrollbar end end ================================================ FILE: ext/tk/lib/tkextlib/blt/ted.rb ================================================ # # tkextlib/blt/ted.rb # # *** This is alpha version, because there is no document on BLT. *** # # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/blt.rb' module Tk::BLT module Ted extend TkCore TkCommandNames = ['::blt::ted'.freeze].freeze ############################## extend TkItemConfigMethod class << self def __item_cget_cmd(id) ['::blt::ted', 'cget', id] end private :__item_cget_cmd def __item_config_cmd(id) ['::blt::ted', 'configure', id] end private :__item_config_cmd private :itemcget, :itemcget_strict private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo def cget(master, option) itemcget(master, option) end def cget_strict(master, option) itemcget_strict(master, option) end def configure(master, slot, value=None) itemconfigure(master, slot, value) end def configinfo(master, slot=nil) itemconfiginfo(master, slot) end def current_configinfo(master, slot=nil) current_itemconfiginfo(master, slot) end end ############################## def self.edit(master, *args) tk_call('::blt::ted', 'edit', master, *args) end def self.rep(master, *args) tk_call('::blt::ted', 'rep', master, *args) end def self.select(master, *args) tk_call('::blt::ted', 'select', master, *args) end end end ================================================ FILE: ext/tk/lib/tkextlib/blt/tile/button.rb ================================================ # # tkextlib/blt/tile/button.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/button' require 'tkextlib/blt/tile.rb' module Tk::BLT module Tile class Button < Tk::Button TkCommandNames = ['::blt::tile::button'.freeze].freeze end end end ================================================ FILE: ext/tk/lib/tkextlib/blt/tile/checkbutton.rb ================================================ # # tkextlib/blt/tile/checkbutton.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/checkbutton' require 'tkextlib/blt/tile.rb' module Tk::BLT module Tile class CheckButton < Tk::CheckButton TkCommandNames = ['::blt::tile::checkbutton'.freeze].freeze end Checkbutton = CheckButton end end ================================================ FILE: ext/tk/lib/tkextlib/blt/tile/frame.rb ================================================ # # tkextlib/blt/tile/frame.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/frame' require 'tkextlib/blt/tile.rb' module Tk::BLT module Tile class Frame < Tk::Frame TkCommandNames = ['::blt::tile::frame'.freeze].freeze end end end ================================================ FILE: ext/tk/lib/tkextlib/blt/tile/label.rb ================================================ # # tkextlib/blt/tile/label.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/label' require 'tkextlib/blt/tile.rb' module Tk::BLT module Tile class Label < Tk::Label TkCommandNames = ['::blt::tile::label'.freeze].freeze end end end ================================================ FILE: ext/tk/lib/tkextlib/blt/tile/radiobutton.rb ================================================ # # tkextlib/blt/tile/radiobutton.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/radiobutton' require 'tkextlib/blt/tile.rb' module Tk::BLT module Tile class RadioButton < Tk::RadioButton TkCommandNames = ['::blt::tile::radiobutton'.freeze].freeze end Radiobutton = RadioButton end end ================================================ FILE: ext/tk/lib/tkextlib/blt/tile/scrollbar.rb ================================================ # # tkextlib/blt/tile/scrollbar.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/scrollbar' require 'tkextlib/blt/tile.rb' module Tk::BLT module Tile class Scrollbar < Tk::Scrollbar TkCommandNames = ['::blt::tile::scrollbar'.freeze].freeze end end end ================================================ FILE: ext/tk/lib/tkextlib/blt/tile/toplevel.rb ================================================ # # tkextlib/blt/tile/toplevel.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/toplevel' require 'tkextlib/blt/tile.rb' module Tk::BLT module Tile class Toplevel < Tk::Toplevel TkCommandNames = ['::blt::tile::toplevel'.freeze].freeze end end end ================================================ FILE: ext/tk/lib/tkextlib/blt/tile.rb ================================================ # # tkextlib/blt/tile.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/blt.rb' module Tk::BLT module Tile autoload :Button, 'tkextlib/blt/tile/button.rb' autoload :CheckButton, 'tkextlib/blt/tile/checkbutton.rb' autoload :Checkbutton, 'tkextlib/blt/tile/checkbutton.rb' autoload :Radiobutton, 'tkextlib/blt/tile/radiobutton.rb' autoload :RadioButton, 'tkextlib/blt/tile/radiobutton.rb' autoload :Frame, 'tkextlib/blt/tile/frame.rb' autoload :Label, 'tkextlib/blt/tile/label.rb' autoload :Scrollbar, 'tkextlib/blt/tile/scrollbar.rb' autoload :Toplevel, 'tkextlib/blt/tile/toplevel.rb' end end ================================================ FILE: ext/tk/lib/tkextlib/blt/tree.rb ================================================ # # tkextlib/blt/tree.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/blt.rb' module Tk::BLT class Tree < TkObject TkCommandNames = ['::blt::tree'.freeze].freeze ################################### class Node < TkObject TreeNodeID_TBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ TreeNodeID_TBL.mutex.synchronize{ TreeNodeID_TBL.clear } } def self.id2obj(tree, id) tpath = tree.path TreeNodeID_TBL.mutex.synchronize{ if TreeNodeID_TBL[tpath] if TreeNodeID_TBL[tpath][id] TreeNodeID_TBL[tpath][id] else begin # self.new(tree, nil, 'node'=>Integer(id)) id = Integer(id) if bool(tk_call(@tpath, 'exists', id)) (obj = self.allocate).instance_eval{ @parent = @tree = tree @tpath = tpath @path = @id = id TreeNodeID_TBL[@tpath] = {} unless TreeNodeID_TBL[@tpath] TreeNodeID_TBL[@tpath][@id] = self } obj else id end rescue id end end else id end } end def self.new(tree, parent, keys={}) keys = _symbolkey2str(keys) tpath = tree.path TreeNodeID_TBL.mutex.synchronize{ TreeNodeID_TBL[tpath] ||= {} if (id = keys['node']) && (obj = TreeNodeID_TBL[tpath][id]) keys.delete('node') tk_call(tree.path, 'move', id, parent, keys) if parent return obj end (obj = self.allocate).instance_eval{ initialize(tree, parent, keys) TreeNodeID_TBL[tpath][@id] = self } obj } end def initialize(tree, parent, keys={}) @parent = @tree = tree @tpath = @parent.path if (id = keys['node']) && bool(tk_call(@tpath, 'exists', id)) @path = @id = id keys.delete('node') tk_call(@tpath, 'move', @id, parent, keys) if parent else parent = tk_call(@tpath, 'root') unless parent @path = @id = tk_call(@tpath, 'insert', parent, keys) end end def id @id end def apply(keys={}) @tree.apply(@id, keys) self end def children() @tree.children(@id) end def copy(parent, keys={}) @tree.copy(@id, parent, keys) end def copy_to(dest_tree, parent, keys={}) @tree.copy_to(@id, dest_tree, parent, keys) end def degree() @tree.degree(@id) end def delete() @tree.delete(@id) self end def depth() @tree.depth(@id) end def dump() @tree.dump(@id) end def dump_to_file(file) @tree.dump_to_file(@id, file) self end def exist?(keys={}) @tree.exist?(@id, keys) end def find(keys={}) @tree.find(@id, keys) end def find_child(label) @tree.find_child(@id, label) end def first_child() @tree.first_child(@id) end def get() @tree.get(@id) end def get_value(key, default_val=None) @tree.get_value(@id, key, default_val) end def index() @tree.index(@id) end def leaf?() @tree.leaf?(@id) end def link?() @tree.link?(@id) end def root?() @tree.root?(@id) end def keys() @tree.keys(@id) end def label(text = nil) @tree.label(@id, nil) end def label=(text) @tree.label(@id, text) end def last_child() @tree.last_child(@id) end def move(dest, keys={}) @tree.keys(@id, dest, keys) self end def next() @tree.next(@id) end def next_sibling() @tree.next_sibling(@id) end def parent() @tree.parent(@id) end def fullpath() @tree.fullpath(@id) end def position() @tree.position(@id) end def previous() @tree.previous(@id) end def prev_sibling() @tree.prev_sibling(@id) end def restore(str, keys={}) @tree.restore(@id, str, keys) self end def restore_overwrite(str, keys={}) @tree.restore_overwrite(@id, str, keys) self end def restore_from_file(file, keys={}) @tree.restore_from_file(@id, file, keys) self end def restore_overwrite_from_file(file, keys={}) @tree.restore_overwrite_from_file(@id, file, keys) self end def root() @tree.root(@id) self end def set(data) @tree.set(@id, data) self end def size() @tree.size(@id) end def sort(keys={}) @tree.sort(@id, keys) self end def type(key) @tree.type(@id, key) end def unset(*keys) @tree.unset(@id, *keys) self end def values(key=None) @tree.values(@id, key) end end ################################### class Tag < TkObject TreeTagID_TBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ TreeTagID_TBL.mutex.synchronize{ TreeTagID_TBL.clear } } (TreeTag_ID = ['blt_tree_tag'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } def self.id2obj(tree, id) tpath = tree.path TreeTagID_TBL.mutex.synchronize{ if TreeTagID_TBL[tpath] if TreeTagID_TBL[tpath][id] TreeTagID_TBL[tpath][id] else begin # self.new(tree, id) (obj = self.allocate).instance_eval{ @parent = @tree = tree @tpath = @parent.path @path = @id = id.dup.freeze if id TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] TreeTagID_TBL[@tpath][@id] = self } obj rescue id end end else id end } end def initialize(tree, tag_str = nil) @parent = @tree = tree @tpath = @parent.path if tag_str @path = @id = tag_str.dup.freeze else TreeTag_ID.mutex.synchronize{ @path = @id = TreeTag_ID.join(TkCore::INTERP._ip_id_) TreeTag_ID[1].succ! } end TreeTagID_TBL.mutex.synchronize{ TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] TreeTagID_TBL[@tpath][@id] = self } end def id @id end def add(*nodes) tk_call(@tpath, 'tag', 'add', @id, *nodes) self end def delete(*nodes) tk_call(@tpath, 'tag', 'delete', @id, *nodes) self end def forget() tk_call(@tpath, 'tag', 'forget', @id) TreeTagID_TBL.mutex.synchronize{ TreeTagID_TBL[@tpath].delete(@id) } self end def nodes() simplelist(tk_call(@tpath, 'tag', 'nodes', @id)).collect{|node| Tk::BLT::Tree::Node.id2obj(@path, node) } end def set(node) tk_call(@tpath, 'tag', 'set', node, @id) self end def unset(node) tk_call(@tpath, 'tag', 'unset', node, @id) self end end ################################### class Notify < TkObject NotifyID_TBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ NotifyID_TBL.mutex.synchronize{ NotifyID_TBL.clear } } def self.id2obj(tree, id) tpath = tree.path NotifyID_TBL.mutex.synchronize{ if NotifyID_TBL[tpath] if NotifyID_TBL[tpath][id] NotifyID_TBL[tpath][id] else (obj = self.allocate).instance_eval{ @parent = @tree = tree @tpath = @parent.path @path = @id = id NotifyID_TBL[@tpath] ||= {} NotifyID_TBL[@tpath][@id] = self } obj end else return id end } end def self.new(tree, *args, &b) NotifyID_TBL.mutex.synchronize{ if tree.kind_of?(Array) # not create tpath = tree[0].path NotifyID_TBL[tpath] ||= {} unless (obj = NotifyID_TBL[tpath][tree[1]]) (NotifyID_TBL[tpath][tree[1]] = obj = self.allocate).instance_eval{ @parent = @tree = tree[0] @tpath = @parent.path @path = @id = tree[1] } end return obj end (obj = self.allocate).instance_eval{ initialize(tree, *args, &b) NotifyID_TBL[@tpath] ||= {} NotifyID_TBL[@tpath][@id] = self } return obj } end def initialize(tree, *args, &b) @parent = @tree = tree @tpath = @parent.path # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) cmd = args.shift # elsif args[-1].kind_of?(Proc) || args[-1].kind_of?(Method) elsif TkComm._callback_entry?(args[-1]) cmd = args.pop elsif b cmd = Proc.new(&b) else fail ArgumentError, "lack of 'command' argument" end args = args.collect{|arg| '-' << arg.to_s} args << proc{|id, type| cmd.call(Tk::BLT::Tree::Node.id2obj(@tree, id), ((type[0] == ?-)? type[1..-1]: type)) } @path = @id = tk_call(@tpath, 'notify', 'create', *args) end def id @id end def delete() tk_call(@tpath, 'notify', 'delete', @id) NotifyID_TBL.mutex.synchronize{ NotifyID_TBL[@tpath].delete(@id) } self end def info() lst = simplelist(tk_call(@tpath, 'notify', 'info', id)) lst[0] = Tk::BLT::Tree::Notify.id2obj(@tree, lst[0]) lst[1] = simplelist(lst[1]).collect{|flag| flag[1..-1]} lst[2] = tk_tcl2ruby(lst[2]) lst end end ################################### class Trace < TkObject TraceID_TBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ TraceID_TBL.mutex.synchronize{ TraceID_TBL.clear } } def self.id2obj(tree, id) tpath = tree.path TraceID_TBL.mutex.synchronize{ if TraceID_TBL[tpath] if TraceID_TBL[tpath][id] TraceID_TBL[tpath][id] else begin # self.new([tree, id]) (obj = self.allocate).instance_eval{ @parent = @tree = tree @tpath = @parent.path @path = @id = node # == traceID TraceID_TBL[@tpath] ||= {} TraceID_TBL[@tpath][@id] = self } obj rescue id end end else id end } end def self.new(tree, *args, &b) TraceID_TBL.mutex.synchronize{ if tree.kind_of?(Array) # not create tpath = tree[0].path TraceID_TBL[tpath] ||= {} unless (obj = TraceID_TBL[tpath][tree[1]]) (TraceID_TBL[tpath][tree[1]] = obj = self.allocate).instance_eval{ @parent = @tree = tree @tpath = @parent.path @path = @id = tree[1] # == traceID } end return obj end # super(true, tree, *args, &b) (obj = self.allocate).instance_eval{ initialize(tree, *args, &b) TraceID_TBL[@tpath] ||= {} TraceID_TBL[@tpath][@id] = self } return obj } end def initialize(tree, node, key, opts, cmd=nil, &b) @parent = @tree = tree @tpath = @parent.path if !cmd if b cmd = Proc.new(&b) else fail ArgumentError, "lack of 'command' argument" end end @path = @id = tk_call(@tpath, 'trace', 'create', node, key, opts, proc{|t, id, k, ops| tobj = Tk::BLT::Tree.id2obj(t) if tobj.kind_of?(Tk::BLT::Tree) nobj = Tk::BLT::Tree::Node.id2obj(tobj, id) else nobj = id end cmd.call(tobj, nobj, k, ops) }) end def id @id end def delete() tk_call(@tpath, 'trace', 'delete', @id) TraceID_TBL.mutex.synchronize{ TraceID_TBL[tpath].delete(@id) } self end def info() lst = simplelist(tk_call(@tpath, 'trace', 'info', id)) lst[0] = Tk::BLT::Tree::Trace.id2obj(@tree, lst[0]) lst[2] = simplelist(lst[2]) lst[3] = tk_tcl2ruby(lst[3]) lst end end ################################### TreeID_TBL = TkCore::INTERP.create_table (Tree_ID = ['blt_tree'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } def __keyonly_optkeys { # apply / find command 'invert'=>nil, 'leafonly'=>nil, 'nocase'=>nil, # apply / find / sort command 'path'=>nil, # copy / restore / restorefile command 'overwrite'=>nil, # copy command 'recurse'=>nil, 'tags'=>nil, # sort command 'ascii'=>nil, 'decreasing'=>nil, 'disctionary'=>nil, 'integer'=>nil, 'real'=>nil, 'recurse'=>nil, 'reorder'=>nil, } end def self.id2obj(id) TreeID_TBL.mutex.synchronize{ TreeID_TBL[id]? TreeID_TBL[id]: id } end def self.names(pat = None) simplelist(tk_call('::blt::tree', 'names', pat)).collect{|name| id2obj(name) } end def self.destroy(*names) tk_call('::blt::tree', 'destroy', *(names.collect{|n| (n.kind_of?(Tk::BLT::Tree))? n.id: n }) ) end def self.new(name = nil) TreeID_TBL.mutex.synchronize{ if name && TreeID_TBL[name] TreeID_TBL[name] else (obj = self.allocate).instance_eval{ initialize(name) TreeID_TBL[@id] = self } obj end } end def initialzie(name = nil) if name @path = @id = name else Tree_ID.mutex.synchronize{ @path = @id = Tree_ID.join(TkCore::INTERP._ip_id_) Tree_ID[1].succ! } end tk_call('::blt::tree', 'create', @id) end def __destroy_hook__ Tk::BLT::Tree::Node::TreeNodeID_TBL.mutex.synchronize{ Tk::BLT::Tree::Node::TreeNodeID_TBL.delete(@path) } Tk::BLT::Tree::Tag::TreeTagID_TBL.mutex.synchronize{ Tk::BLT::Tree::Tag::TreeTagID_TBL.delete(@path) } Tk::BLT::Tree::Notify::NotifyID_TBL.mutex.synchronize{ Tk::BLT::Tree::Notify::NotifyID_TBL.delete(@path) } Tk::BLT::Tree::Trace::TraceID_TBL.mutex.synchronize{ Tk::BLT::Tree::Trace::TraceID_TBL.delete(@path) } end def tagid(tag) if tag.kind_of?(Tk::BLT::Tree::Node) || tag.kind_of?(Tk::BLT::Tree::Tag) || tag.kind_of?(Tk::BLT::Tree::Notify) || tag.kind_of?(Tk::BLT::Tree::Trace) tag.id else tag # maybe an Array of configure paramters end end def destroy() tk_call('::blt::tree', 'destroy', @id) self end def ancestor(node1, node2) Tk::BLT::Tree::Node.id2obj(self, tk_call('::blt::tree', 'ancestor', tagid(node1), tagid(node2))) end def apply(node, keys={}) tk_call('::blt::tree', 'apply', tagid(node), __conv_keyonly_opts(keys)) self end def attach(tree_obj) tk_call('::blt::tree', 'attach', tree_obj) self end def children(node) simplelist(tk_call('::blt::tree', 'children', tagid(node))).collect{|n| Tk::BLT::Tree::Node.id2obj(self, n) } end def copy(src, parent, keys={}) id = tk_call('::blt::tree', 'copy', tagid(src), tagid(parent), __conv_keyonly_opts(keys)) Tk::BLT::Tree::Node.new(self, nil, 'node'=>id) end def copy_to(src, dest_tree, parent, keys={}) return copy(src, parent, keys={}) unless dest_tree id = tk_call('::blt::tree', 'copy', tagid(src), dest_tree, tagid(parent), __conv_keyonly_opts(keys)) Tk::BLT::Tree::Node.new(dest_tree, nil, 'node'=>id) end def degree(node) number(tk_call('::blt::tree', 'degree', tagid(node))) end def delete(*nodes) tk_call('::blt::tree', 'delete', *(nodes.collect{|node| tagid(node)})) Tk::BLT::Tree::Node::TreeNodeID_TBL.mutex.synchronize{ nodes.each{|node| if node.kind_of?(Tk::BLT::Tree::Node) Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.id) else Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.to_s) end } } self end def depth(node) number(tk_call('::blt::tree', 'depth', tagid(node))) end def dump(node) simplelist(tk_call('::blt::tree', 'dump', tagid(node))).collect{|n| simplelist(n) } end def dump_to_file(node, file) tk_call('::blt::tree', 'dumpfile', tagid(node), file) self end def exist?(node, key=None) bool(tk_call('::blt::tree', 'exists', tagid(node), key)) end def find(node, keys={}) simplelist(tk_call('::blt::tree', 'find', tagid(node), __conv_keyonly_opts(keys))).collect{|n| Tk::BLT::Tree::Node.id2obj(self, n) } end def find_child(node, label) ret = tk_call('::blt::tree', 'findchild', tagid(node), label) (ret == '-1')? nil: Tk::BLT::Tree::Node.id2obj(self, ret) end def first_child(node) ret = tk_call('::blt::tree', 'firstchild', tagid(node)) (ret == '-1')? nil: Tk::BLT::Tree::Node.id2obj(self, ret) end def get(node) Hash[*simplelist(tk_call('::blt::tree', 'get', tagid(node)))] end def get_value(node, key, default_val=None) tk_call('::blt::tree', 'get', tagid(node), key, default_val) end def index(node) Tk::BLT::Tree::Node.id2obj(self, tk_call('::blt::tree', 'index', tagid(node))) end def insert(parent, keys={}) id = tk_call('::blt::tree', 'insert', tagid(parent), keys) Tk::BLT::Tree::Node.new(self, nil, 'node'=>id) end def ancestor?(node1, node2) bool(tk_call('::blt::tree', 'is', 'ancestor', tagid(node1), tagid(node2))) end def before?(node1, node2) bool(tk_call('::blt::tree', 'is', 'before', tagid(node1), tagid(node2))) end def leaf?(node) bool(tk_call('::blt::tree', 'is', 'leaf', tagid(node))) end def link?(node) bool(tk_call('::blt::tree', 'is', 'link', tagid(node))) end def root?(node) bool(tk_call('::blt::tree', 'is', 'root', tagid(node))) end def keys(node, *nodes) if nodes.empty? simplelist(tk_call('blt::tree', 'keys', tagid(node))) else simplelist(tk_call('blt::tree', 'keys', tagid(node), *(nodes.collect{|n| tagid(n)}))).collect{|lst| simplelist(lst) } end end def label(node, text=nil) if text tk_call('::blt::tree', 'label', tagid(node), text) text else tk_call('::blt::tree', 'label', tagid(node)) end end def last_child(node) ret = tk_call('::blt::tree', 'lastchild', tagid(node)) (ret == '-1')? nil: Tk::BLT::Tree::Node.id2obj(self, ret) end def link(parent, node, keys={}) ret = tk_call('::blt::tree', 'link', tagid(parent), tagid(node), __conv_keyonly_opts(keys)) (ret == '-1')? nil: Tk::BLT::Tree::Node.id2obj(self, ret) end def move(node, dest, keys={}) tk_call('::blt::tree', 'move', tagid(node), tagid(dest), keys) self end def next(node) ret = tk_call('::blt::tree', 'next', tagid(node)) (ret == '-1')? nil: Tk::BLT::Tree::Node.id2obj(self, ret) end def next_sibling(node) ret = tk_call('::blt::tree', 'nextsibling', tagid(node)) (ret == '-1')? nil: Tk::BLT::Tree::Node.id2obj(self, ret) end def notify_create(*args, &b) Tk::BLT::Tree::Notify.new(self, *args, &b) end def notify_delete(id) if id.kind_of?(Tk::BLT::Tree::Notify) id.delete else tk_call(@path, 'notify', 'delete', id) Tk::BLT::Tree::Notify::NotifyID_TBL.mutex.synchronize{ Tk::BLT::Tree::Notify::NotifyID_TBL[@path].delete(id.to_s) } end self end def notify_info(id) lst = simplelist(tk_call(@path, 'notify', 'info', tagid(id))) lst[0] = Tk::BLT::Tree::Notify.id2obj(self, lst[0]) lst[1] = simplelist(lst[1]).collect{|flag| flag[1..-1]} lst[2] = tk_tcl2ruby(lst[2]) lst end def notify_names() tk_call(@path, 'notify', 'names').collect{|id| Tk::BLT::Tree::Notify.id2obj(self, id) } end def parent(node) ret = tk_call('::blt::tree', 'parent', tagid(node)) (ret == '-1')? nil: Tk::BLT::Tree::Node.id2obj(self, ret) end def fullpath(node) tk_call('::blt::tree', 'path', tagid(node)) end def position(node) number(tk_call('::blt::tree', 'position', tagid(node))) end def previous(node) ret = tk_call('::blt::tree', 'previous', tagid(node)) (ret == '-1')? nil: Tk::BLT::Tree::Node.id2obj(self, ret) end def prev_sibling(node) ret = tk_call('::blt::tree', 'prevsibling', tagid(node)) (ret == '-1')? nil: Tk::BLT::Tree::Node.id2obj(self, ret) end def restore(node, str, keys={}) tk_call('::blt::tree', 'restore', tagid(node), str, __conv_keyonly_opts(keys)) self end def restore_overwrite(node, str, keys={}) keys = __conv_keyonly_opts(keys) keys.delete('overwrite') keys.delete(:overwrite) tk_call('::blt::tree', 'restore', tagid(node), str, '-overwrite', keys) self end def restore_from_file(node, file, keys={}) tk_call('::blt::tree', 'restorefile', tagid(node), file, __conv_keyonly_opts(keys)) self end def restore_overwrite_from_file(node, file, keys={}) keys = __conv_keyonly_opts(keys) keys.delete('overwrite') keys.delete(:overwrite) tk_call('::blt::tree', 'restorefile', tagid(node), file, '-overwrite', keys) self end def root(node=None) Tk::BLT::Tree::Node.id2obj(self, tk_call('::blt::tree', 'root', tagid(node))) end def set(node, data) unless data.kind_of?(Hash) fail ArgumentError, 'Hash is expected for data' end args = [] data.each{|k, v| args << k << v} tk_call('::blt::tree', 'set', tagid(node), *args) self end def size(node) number(tk_call('::blt::tree', 'size', tagid(node))) end def sort(node, keys={}) tk_call('::blt::tree', 'sort', tagid(node), __conv_keyonly_opts(keys)) self end def tag_add(tag, *nodes) tk_call(@path, 'tag', 'add', tagid(tag), *(nodes.collect{|n| tagid(n)})) self end def tag_delete(tag, *nodes) tk_call(@path, 'tag', 'delete', tagid(tag), *(nodes.collect{|n| tagid(n)})) self end def tag_forget(tag) tag = tag.id if tag.kind_of?(Tk::BLT::Tree::Tag) tk_call(@path, 'tag', 'forget', tag) TreeTagID_TBL.mutex.synchronize{ TreeTagID_TBL[@path].delete(tag) } self end def tag_get(node, *patterns) simplelist(tk_call(@tpath, 'tag', 'get', tagid(node), *(patterns.collect{|pat| tagid(pat)}))).collect{|str| Tk::BLT::Tree::Tag.id2obj(self, str) } end def tag_names(node = None) simplelist(tk_call(@tpath, 'tag', 'names', tagid(node))).collect{|str| Tk::BLT::Tree::Tag.id2obj(self, str) } end def tag_nodes(tag) simplelist(tk_call(@tpath, 'tag', 'nodes', tagid(tag))).collect{|node| Tk::BLT::Tree::Node.id2obj(self, node) } end def tag_set(node, *tags) tk_call(@path, 'tag', 'set', tagid(node), *(tags.collect{|t| tagid(t)})) self end def tag_unset(node, *tags) tk_call(@path, 'tag', 'unset', tagid(node), *(tags.collect{|t| tagid(t)})) self end def trace_create(*args, &b) Tk::BLT::Tree::Trace.new(self, *args, &b) end =begin def trace_delete(*args) args.each{|id| if id.kind_of?(Tk::BLT::Tree::Trace) id.delete else tk_call(@path, 'trace', 'delete', id) Tk::BLT::Tree::Trace::TraceID_TBL[@path].delete(id.to_s) end self } end =end def trace_delete(*args) args = args.collect{|id| tagid(id)} tk_call(@path, 'trace', 'delete', *args) Tk::BLT::Tree::Trace::TraceID_TBL.mutex.synchronize{ args.each{|id| Tk::BLT::Tree::Trace::TraceID_TBL[@path].delete(id.to_s)} } self end def trace_info(id) lst = simplelist(tk_call(@path, 'trace', 'info', tagid(id))) lst[0] = Tk::BLT::Tree::Trace.id2obj(self, lst[0]) lst[2] = simplelist(lst[2]) lst[3] = tk_tcl2ruby(lst[3]) lst end def trace_names() tk_call(@path, 'trace', 'names').collect{|id| Tk::BLT::Tree::Trace.id2obj(self, id) } end def type(node, key) tk_call('::blt::tree', 'type', tagid(node), key) end def unset(node, *keys) tk_call('::blt::tree', 'unset', tagid(node), *keys) self end def values(node, key=None) simplelist(tk_call('::blt::tree', 'values', tagid(node), key)) end end end ================================================ FILE: ext/tk/lib/tkextlib/blt/treeview.rb ================================================ # # tkextlib/blt/treeview.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/blt.rb' require 'tk/validation.rb' module Tk::BLT class Treeview < TkWindow module ConfigMethod end module TagOrID_Methods end class Node < TkObject end class Tag < TkObject end end class Hiertable < Treeview end end ###################################### module Tk::BLT::Treeview::ConfigMethod include TkItemConfigMethod def __item_boolval_optkeys(id) case id when Array # id := [ 'column', name ] ['edit', 'hide'] when 'sort' ['decreasing'] else [] end end private :__item_boolval_optkeys def __item_strval_optkeys(id) case id when Array # id := [ 'column', name ] super() << 'titleforeground' << 'titleshadow' when 'sort' ['decreasing'] else [] end end private :__item_strval_optkeys def __item_listval_optkeys(id) case id when 'entry' ['bindtags'] else [] end end private :__item_listval_optkeys def __item_cget_cmd(id) if id.kind_of?(Array) # id := [ type, name ] [self.path, id[0], 'cget', id[1]] else [self.path, id, 'cget'] end end private :__item_cget_cmd def __item_config_cmd(id) if id.kind_of?(Array) # id := [ type, name ] [self.path, id[0], 'configure', id[1]] else [self.path, id, 'configure'] end end private :__item_config_cmd def __item_pathname(id) if id.kind_of?(Array) id = tagid(id[1]) end [self.path, id].join(';') end private :__item_pathname def column_cget(name, option) itemcget(['column', name], option) end def column_cget_strict(name, option) itemcget_strict(['column', name], option) end def column_configure(name, slot, value=None) itemconfigure(['column', name], slot, value) end def column_configinfo(name, slot=nil) itemconfiginfo(['column', name], slot) end def current_column_configinfo(name, slot=nil) current_itemconfiginfo(['column', name], slot) end def button_cget(option) itemcget('button', option) end def button_cget_strict(option) itemcget_strict('button', option) end def button_configure(slot, value=None) itemconfigure('button', slot, value) end def button_configinfo(slot=nil) itemconfiginfo('button', slot) end def current_button_configinfo(slot=nil) current_itemconfiginfo('button', slot) end def entry_cget(option) ret = itemcget('entry', option) if option == 'bindtags' || option == :bindtags ret.collect{|tag| TkBindTag.id2obj(tag)} else ret end end def entry_cget_strict(option) ret = itemcget_strict('entry', option) if option == 'bindtags' || option == :bindtags ret.collect{|tag| TkBindTag.id2obj(tag)} else ret end end def entry_configure(slot, value=None) itemconfigure('entry', slot, value) end def entry_configinfo(slot=nil) ret = itemconfiginfo('entry', slot) if TkComm::GET_CONFIGINFO_AS_ARRAY if slot if slot == 'bindtags' || slot == :bindtags ret[-2] = ret[-2].collect{|tag| TkBindTag.id2obj(tag)} ret[-1] = ret[-1].collect{|tag| TkBindTag.id2obj(tag)} end else inf = ret.assoc('bindtags') inf[-2] = inf[-2].collect{|tag| TkBindTag.id2obj(tag)} inf[-1] = inf[-1].collect{|tag| TkBindTag.id2obj(tag)} end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY if (inf = ret['bindtags']) inf[-2] = inf[-2].collect{|tag| TkBindTag.id2obj(tag)} inf[-1] = inf[-1].collect{|tag| TkBindTag.id2obj(tag)} ret['bindtags'] = inf end end ret end def current_entry_configinfo(slot=nil) ret = current_itemconfiginfo('entry', slot) if (val = ret['bindtags']) ret['bindtags'] = val.collect{|tag| TkBindTag.id2obj(tag)} end ret end def sort_cget(option) itemcget('sort', option) end def sort_cget_strict(option) itemcget_strict('sort', option) end def sort_configure(slot, value=None) itemconfigure('sort', slot, value) end def sort_configinfo(slot=nil) itemconfiginfo('sort', slot) end def current_sort_configinfo(slot=nil) current_itemconfiginfo('sort', slot) end def text_cget(option) itemcget('text', option) end def text_cget_strict(option) itemcget_strict('text', option) end def text_configure(slot, value=None) itemconfigure('text', slot, value) end def text_configinfo(slot=nil) itemconfiginfo('text', slot) end def current_text_configinfo(slot=nil) current_itemconfiginfo('text', slot) end private :itemcget, :itemcget_strict private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo end class Tk::BLT::Treeview TkCommandNames = ['::blt::treeview'.freeze].freeze WidgetClassName = 'TreeView'.freeze WidgetClassNames[WidgetClassName] = self include Scrollable include ValidateConfigure include ItemValidateConfigure include Tk::BLT::Treeview::ConfigMethod ######################## def __boolval_optkeys ['autocreate', 'allowduplicates', 'exportselection', 'flat', 'hideroot', 'newtags', 'showtitles', 'sortselection'] end private :__boolval_optkeys def __strval_optkeys super() + ['focusforeground', 'linecolor', 'separator', 'trim'] end private :__strval_optkeys ######################## class OpenCloseCommand < TkValidateCommand class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [ ?W, ?w, :widget ], [ ?p, ?s, :name ], [ ?P, ?s, :fullpath ], [ ?#, ?x, :node_id ], nil ] PROC_TBL = [ [ ?x, TkComm.method(:num_or_str) ], [ ?s, TkComm.method(:string) ], [ ?w, TkComm.method(:window) ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) val end end def self._config_keys ['opencommand', 'closecomand'] end end def __validation_class_list super() << OpenCloseCommand end Tk::ValidateConfigure.__def_validcmd(binding, OpenCloseCommand) ######################## def __item_validation_class_list(id) case id when 'entry' super(id) << OpenCloseCommand else super(id) end end Tk::ItemValidateConfigure.__def_validcmd(binding, OpenCloseCommand) ######################## def __destroy_hook__ Tk::BLT::Treeview::Node::TreeNodeID_TBL.mutex.synchronize{ Tk::BLT::Treeview::Node::TreeNodeID_TBL.delete(@path) } Tk::BLT::Treeview::Tag::TreeTagID_TBL.mutex.synchronize{ Tk::BLT::Treeview::Tag::TreeTagID_TBL.delete(@path) } end def tagid(tag) if tag.kind_of?(Tk::BLT::Treeview::Node) \ || tag.kind_of?(Tk::BLT::Treeview::Tag) tag.id else tag # maybe an Array of configure paramters end end private :tagid def tagid2obj(tagid) if tagid.kind_of?(Integer) Tk::BLT::Treeview::Node.id2obj(self, tagid.to_s) elsif tagid.kind_of?(String) if tagid =~ /^\d+$/ Tk::BLT::Treeview::Node.id2obj(self, tagid) else Tk::BLT::Treeview::Tag.id2obj(self, tagid) end else tagid end end def bbox(*tags) list(tk_send('bbox', *(tags.collect{|tag| tagid(tag)}))) end def screen_bbox(*tags) list(tk_send('bbox', '-screen', *(tags.collect{|tag| tagid(tag)}))) end def tag_bind(tag, seq, *args) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind([@path, 'bind', tagid(tag)], seq, cmd, *args) self end def tag_bind_append(tag, seq, *args) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append([@path, 'bind', tagid(tag)], seq, cmd, *args) self end def tag_bind_remove(tag, seq) _bind_remove([@path, 'bind', tagid(tag)], seq) self end def tag_bindinfo(tag, seq=nil) _bindinfo([@path, 'bind', tagid(tag)], seq) end def button_activate(tag) tk_send('button', 'activate', tagid(tag)) self end def button_bind(tag, seq, *args) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind([@path, 'button', 'bind', tagid(tag)], seq, cmd, *args) self end def button_bind_append(tag, seq, *args) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append([@path, 'button', 'bind', tagid(tag)], seq, cmd, *args) self end def button_bind_remove(tag, seq) _bind_remove([@path, 'button', 'bind', tagid(tag)], seq) self end def button_bindinfo(tag, seq=nil) _bindinfo([@path, 'button', 'bind', tagid(tag)], seq) end def close(*tags) tk_send('close', *(tags.collect{|tag| tagid(tag)})) self end def close_recurse(*tags) tk_send('close', '-recurse', *(tags.collect{|tag| tagid(tag)})) self end def column_activate(column=None) if column == None tk_send('column', 'activate') else tk_send('column', 'activate', column) self end end def column_delete(*fields) tk_send('column', 'delete', *fields) self end def column_insert(pos, field, *opts) tk_send('column', 'insert', pos, field, *opts) self end def column_invoke(field) tk_send('column', 'invoke', field) self end def column_move(name, dest) tk_send('column', 'move', name, dest) self end def column_names() simplelist(tk_send('column', 'names')) end def column_nearest(x, y=None) tk_send('column', 'nearest', x, y) end def curselection simplelist(tk_send('curselection')).collect{|id| tagid2obj(id)} end def delete(*tags) tk_send('delete', *(tags.collect{|tag| tagid(tag)})) self end def entry_activate(tag) tk_send('entry', 'activate', tagid(tag)) self end def entry_children(tag, first=None, last=None) simplelist(tk_send('entry', 'children', tagid(tag), first, last)).collect{|id| tagid2obj(id)} end def entry_delete(tag, first=None, last=None) tk_send('entry', 'delete', tagid(tag), first, last) end def entry_before?(tag1, tag2) bool(tk_send('entry', 'isbefore', tagid(tag1), tagid(tag2))) end def entry_hidden?(tag) bool(tk_send('entry', 'ishidden', tagid(tag))) end def entry_open?(tag) bool(tk_send('entry', 'isopen', tagid(tag))) end def entry_size(tag) number(tk_send('entry', 'size', tagid(tag))) end def entry_size_recurse(tag) number(tk_send('entry', 'size', '-recurse', tagid(tag))) end def _search_flags(keys) keys = _symbolkey2str(keys) keys['exact'] = None if keys.delete('exact') keys['glob'] = None if keys.delete('glob') keys['regexp'] = None if keys.delete('regexp') keys['nonmatching'] = None if keys.delete('nonmatching') end private :_search_flags ################################ class FindExecFlagValue < TkValidateCommand class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [ ?W, ?w, :widget ], [ ?p, ?s, :name ], [ ?P, ?s, :fullpath ], [ ?#, ?x, :node_id ], nil ] PROC_TBL = [ [ ?x, TkComm.method(:num_or_str) ], [ ?s, TkComm.method(:string) ], [ ?w, TkComm.method(:window) ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) val end end def self._config_keys [] end end def _find_exec_flag_value(val) if val.kind_of?(Array) cmd, *args = val #FindExecFlagValue.new(cmd, args.join(' ')) FindExecFlagValue.new(cmd, *args) elsif TkComm._callback_entry?(val) FindExecFlagValue.new(val) else val end end ################################ def find(first, last, keys={}) keys = _search_flags(keys) keys['exec'] = _find_exec_flag_value(keys['exec']) if keys.key?('exec') args = hash_kv(keys) << '--' << tagid(first) << tagid(last) simplelist(tk_send('find', *args)).collect{|id| tagid2obj(id)} end def tag_focus(tag) tk_send('focus', tagid(tag)) self end def get(*tags) simplelist(tk_send('get', *(tags.collect{|tag| tagid(tag)}))) end def get_full(*tags) simplelist(tk_send('get', '-full', *(tags.collect{|tag| tagid(tag)}))) end def hide(*tags) if tags[-1].kind_of?(Hash) keys = tags.pop else keys = {} end keys = _search_flags(keys) args = hash_kv(keys) << '--' args.concat(tags.collect{|t| tagid(t)}) tk_send('hide', *args) self end def index(str) tagid2obj(tk_send('index', str)) end def index_at(tag, str) tagid2obj(tk_send('index', '-at', tagid(tag), str)) end def index_at_path(tag, str) tagid2obj(tk_send('index', '-at', tagid(tag), '-path', str)) end def insert(pos, parent=nil, keys={}) Tk::BLT::Treeview::Node.new(pos, parent, keys) end def insert_at(tag, pos, parent=nil, keys={}) if parent.kind_of?(Hash) keys = parent parent = nil end keys = _symbolkey2str(keys) keys['at'] = tagid(tag) Tk::BLT::Treeview::Node.new(pos, parent, keys) end def move_before(tag, dest) tk_send('move', tagid(tag), 'before', tagid(dest)) self end def move_after(tag, dest) tk_send('move', tagid(tag), 'after', tagid(dest)) self end def move_into(tag, dest) tk_send('move', tagid(tag), 'into', tagid(dest)) self end def nearest(x, y, var=None) tagid2obj(tk_send('nearest', x, y, var)) end def open(*tags) tk_send('open', *(tags.collect{|tag| tagid(tag)})) self end def open_recurse(*tags) tk_send('open', '-recurse', *(tags.collect{|tag| tagid(tag)})) self end def range(first, last) simplelist(tk_send('range', tagid(first), tagid(last))).collect{|id| tagid2obj(id) } end def range_open(first, last) simplelist(tk_send('range', '-open', tagid(first), tagid(last))).collect{|id| tagid2obj(id) } end def scan_mark(x, y) tk_send_without_enc('scan', 'mark', x, y) self end def scan_dragto(x, y) tk_send_without_enc('scan', 'dragto', x, y) self end def see(tag) tk_send_without_enc('see', tagid(tag)) self end def see_anchor(anchor, tag) tk_send_without_enc('see', '-anchor', anchor, tagid(tag)) self end def selection_anchor(tag) tk_send_without_enc('selection', 'anchor', tagid(tag)) self end def selection_cancel() tk_send_without_enc('selection', 'cancel') self end def selection_clear(first, last=None) tk_send_without_enc('selection', 'clear', tagid(first), tagid(last)) self end def selection_clear_all() tk_send_without_enc('selection', 'clearall') self end def selection_mark(tag) tk_send_without_enc('selection', 'mark', tagid(tag)) self end def selection_include?(tag) bool(tk_send('selection', 'include', tagid(tag))) end def selection_present?() bool(tk_send('selection', 'present')) end def selection_set(first, last=None) tk_send_without_enc('selection', 'set', tagid(first), tagid(last)) self end def selection_toggle(first, last=None) tk_send_without_enc('selection', 'toggle', tagid(first), tagid(last)) self end def show(*tags) if tags[-1].kind_of?(Hash) keys = tags.pop else keys = {} end keys = _search_flags(keys) args = hash_kv(keys) << '--' args.concat(tags.collect{|t| tagid(t)}) tk_send('show', *args) self end def sort_auto(mode) tk_send('sort', 'auto', mode) self end def sort_auto=(mode) tk_send('sort', 'auto', mode) mode end def sort_auto? bool(tk_send('sort', 'auto')) end def sort_once(*tags) tk_send('sort', 'once', *(tags.collect{|tag| tagid(tag)})) self end def sort_once_recurse(*tags) tk_send('sort', 'once', '-recurse', *(tags.collect{|tag| tagid(tag)})) self end def tag_add(tag, *ids) tk_send('tag', 'add', tagid(tag), *ids) self end def tag_delete(tag, *ids) tk_send('tag', 'delete', tagid(tag), *ids) self end def tag_forget(tag) tk_send('tag', 'forget', tagid(tag)) self end def tag_names(id=nil) id = (id)? tagid(id): None simplelist(tk_send('tag', 'nodes', id)).collect{|tag| Tk::BLT::Treeview::Tag.id2obj(self, tag) } end def tag_nodes(tag) simplelist(tk_send('tag', 'nodes', tagid(tag))).collect{|id| Tk::BLT::Treeview::Node.id2obj(self, id) } end def text_apply tk_send('text', 'apply') self end def text_cancel tk_send('text', 'cancel') self end def text_delete(first, last) tk_send('text', 'delete', first, last) self end def text_get(x, y) tk_send('text', 'get', x, y) end def text_get_root(x, y) tk_send('text', 'get', '-root', x, y) end def text_icursor(idx) tk_send('text', 'icursor', idx) self end def text_index(idx) num_or_str(tk_send('text', 'index', idx)) end def text_insert(idx, str) tk_send('text', 'insert', idx, str) self end def text_selection_adjust(idx) tk_send('text', 'selection', 'adjust', idx) self end def text_selection_clear tk_send('text', 'selection', 'clear') self end def text_selection_from(idx) tk_send('text', 'selection', 'from', idx) self end def text_selection_present num_or_str(tk_send('text', 'selection', 'present')) end def text_selection_range(start, last) tk_send('text', 'selection', 'range', start, last) self end def text_selection_to(idx) tk_send('text', 'selection', 'to', idx) self end def toggle(tag) tk_send('toggle', tagid(tag)) self end end ###################################### module Tk::BLT::Treeview::TagOrID_Methods def bbox @tree.bbox(self) end def screen_bbox @tree.screen_bbox(self) end def bind(seq, *args) @tree.tag_bind(self, seq, *args) self end def bind_append(seq, *args) @tree.tag_bind_append(self, seq, *args) self end def bind_remove(seq) @tree.tag_bind_remove(self, seq) self end def bindinfo(seq=nil) @tree.tag_bindinfo(self, seq) end def button_activate @tree.button_activate(self) self end def button_bind(seq, *args) @tree.button_bind(self, seq, *args) self end def button_bind_append(seq, *args) @tree.button_bind_append(self, seq, *args) self end def button_bind_remove(seq) @tree.button_bind_remove(self, seq) self end def button_bindinfo(seq=nil) @tree.button_bindinfo(self, seq) end def close @tree.close(self) self end def close_recurse @tree.close_recurse(self) self end def delete @tree.delete(self) self end def entry_activate @tree.entry_activate(self) self end def entry_children(first=None, last=None) @tree.entry_children(self, first, last) end def entry_delete(first=None, last=None) @tree.entry_delete(self, first, last) end def entry_before?(tag) @tree.entry_before?(self, tag) end def entry_hidden? @tree.entry_before?(self) end def entry_open? @tree.entry_open?(self) end def entry_size @tree.entry_size(self) end def entry_size_recurse @tree.entry_size_recurse(self) end def focus @tree.tag_focus(self) self end def get @tree.get(self) end def get_full @tree.get_full(self) end def hide @tree.hide(self) self end def index(str) @tree.index_at(self, str) end def index_path(str) @tree.index_at_path(self, str) end def insert(pos, parent=nil, keys={}) @tree.insert_at(self, pos, parent, keys) end def move_before(dest) @tree.move_before(self, dest) self end def move_after(dest) @tree.move_after(self, dest) self end def move_into(dest) @tree.move_into(self, dest) self end def open @tree.open(self) self end def open_recurse @tree.open_recurse(self) self end def range_to(tag) @tree.range(self, tag) end def range_open_to(tag) @tree.range(self, tag) end def see @tree.see(self) self end def see_anchor(anchor) @tree.see_anchor(anchor, self) self end def selection_anchor @tree.selection_anchor(self) self end def selection_clear @tree.selection_clear(self) self end def selection_mark @tree.selection_mark(self) self end def selection_include? @tree.selection_include?(self) end def selection_set @tree.selection_set(self) self end def selection_toggle @tree.selection_toggle(self) self end def show @tree.show(self) self end def sort_once @tree.sort_once(self) self end def sort_once_recurse @tree.sort_once_recurse(self) self end def toggle @tree.toggle(self) self end end ###################################### class Tk::BLT::Treeview::Node < TkObject include Tk::BLT::Treeview::TagOrID_Methods TreeNodeID_TBL = TkCore::INTERP.create_table (TreeNode_ID = ['blt_treeview_node'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } TkCore::INTERP.init_ip_env{ TreeNodeID_TBL.mutex.synchronize{ TreeNodeID_TBL.clear } } def self.id2obj(tree, id) tpath = tree.path TreeNodeID_TBL.mutex.synchronize{ if TreeNodeID_TBL[tpath] if TreeNodeID_TBL[tpath][id] TreeNodeID_TBL[tpath][id] else begin # self.new(tree, nil, nil, 'node'=>Integer(id)) unless (tk_call(@tpath, 'get', id)).empty? id = Integer(id) (obj = self.allocate).instance_eval{ @parent = @tree = tree @tpath = @parent.path @path = @id = id TreeNodeID_TBL[@tpath] ||= {} TreeNodeID_TBL[@tpath][@id] = self } obj else id end rescue id end end else id end } end def self.new(tree, pos, parent=nil, keys={}) if parent.kind_of?(Hash) keys = parent parent = nil end keys = _symbolkey2str(keys) tpath = tree.path TreeNodeID_TBL.mutex.synchronize{ TreeNodeID_TBL[tpath] ||= {} if (id = keys['node']) && (obj = TreeNodeID_TBL[tpath][id]) keys.delete('node') tk_call(tree.path, 'move', id, pos, parent) if parent return obj end #super(tree, pos, parent, keys) (obj = self.allocate).instance_eval{ initialize(tree, pos, parent, keys) TreeNodeID_TBL[tpath][@id] = self } obj } end def initialize(tree, pos, parent, keys) @parent = @tree = tree @tpath = @parent.path if (id = keys['node']) # if tk_call(@tpath, 'get', id).empty? # fail RuntimeError, "not exist the node '#{id}'" # end @path = @id = id tk_call(@tpath, 'move', @id, pos, tagid(parent)) if parent configure(keys) if keys && ! keys.empty? else name = nil TreeNode_ID.mutex.synchronize{ name = TreeNode_ID.join(TkCore::INTERP._ip_id_).freeze TreeNode_ID[1].succ! } at = keys.delete['at'] if parent if parent.kind_of?(Tk::BLT::Treeview::Node) || parent.kind_of?(Tk::BLT::Treeview::Tag) path = [get_full(parent.id)[0], name] at = nil # ignore 'at' option else path = [parent.to_s, name] end else path = name end if at @id = tk_call(@tpath, 'insert', '-at', tagid(at), pos, path, keys) else @id = tk_call(@tpath, 'insert', pos, path, keys) end @path = @id end end def id @id end end ###################################### class Tk::BLT::Treeview::Tag < TkObject include Tk::BLT::Treeview::TagOrID_Methods TreeTagID_TBL = TkCore::INTERP.create_table (TreeTag_ID = ['blt_treeview_tag'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } TkCore::INTERP.init_ip_env{ TreeTagID_TBL.mutex.synchronize{ TreeTagID_TBL.clear } } def self.id2obj(tree, name) tpath = tree.path TreeTagID_TBL.mutex.synchronize{ if TreeTagID_TBL[tpath] if TreeTagID_TBL[tpath][name] TreeTagID_TBL[tpath][name] else #self.new(tree, name) (obj = self.allocate).instance_eval{ @parent = @tree = tree @tpath = @parent.path @path = @id = name TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] TreeTagID_TBL[@tpath][@id] = self } obj end else id end } end def self.new_by_name(tree, name, *ids) TreeTagID_TBL.mutex.synchronize{ unless (obj = TreeTagID_TBL[tree.path][name]) (obj = self.allocate).instance_eval{ initialize(tree, name, ids) TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] TreeTagID_TBL[@tpath][@id] = self } end obj } end def self.new(tree, *ids) TreeTagID_TBL.mutex.synchronize{ (obj = self.allocate).instance_eval{ if tree.kind_of?(Array) initialize(tree[0], tree[1], ids) else initialize(tree, nil, ids) end TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] TreeTagID_TBL[@tpath][@id] = self } obj } end def initialize(tree, name, ids) @parent = @tree = tree @tpath = @parent.path if name @path = @id = name else TreeTag_ID.mutex.synchronize{ @path = @id = TreeTag_ID.join(TkCore::INTERP._ip_id_).freeze TreeTag_ID[1].succ! } end unless ids.empty? tk_call(@tpath, 'tag', 'add', @id, *(ids.collect{|id| tagid(id)})) end end def tagid(tag) if tag.kind_of?(Tk::BLT::Treeview::Node) \ || tag.kind_of?(Tk::BLT::Treeview::Tag) tag.id else tag end end private :tagid def id @id end def add(*ids) tk_call(@tpath, 'tag', 'add', @id, *(ids{|id| tagid(id)})) self end def remove(*ids) tk_call(@tpath, 'tag', 'delete', @id, *(ids{|id| tagid(id)})) self end def forget tk_call(@tpath, 'tag', 'forget', @id) self end def nodes simplelist(tk_call(@tpath, 'tag', 'nodes', @id)).collect{|id| Tk::BLT::Treeview::Node.id2obj(@tree, id) } end end class Tk::BLT::Hiertable TkCommandNames = ['::blt::hiertable'.freeze].freeze WidgetClassName = 'Hiertable'.freeze WidgetClassNames[WidgetClassName] = self end ================================================ FILE: ext/tk/lib/tkextlib/blt/unix_dnd.rb ================================================ # # tkextlib/blt/unix_dnd.rb # # *** This is alpha version, because there is no document on BLT. *** # # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/blt.rb' module Tk::BLT module DnD extend TkCore TkCommandNames = ['::blt::dnd'.freeze].freeze ############################## extend TkItemConfigMethod class << self def __item_cget_cmd(id) ['::blt::dnd', *id] end private :__item_cget_cmd def __item_config_cmd(id) ['::blt::dnd', *id] end private :__item_config_cmd private :itemcget, :itemcget_strict private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo def cget(win, option) itemcget(['cget', win], option) end def cget_strict(win, option) itemcget_strict(['cget', win], option) end def configure(win, slot, value=None) itemconfigure(['configure', win], slot, value) end def configinfo(win, slot=nil) itemconfiginfo(['configure', win], slot) end def current_configinfo(win, slot=nil) current_itemconfiginfo(['configure', win], slot) end def token_cget(win, option) itemcget(['token', 'cget', win], option) end def token_cget_strict(win, option) itemcget_strict(['token', 'cget', win], option) end def token_configure(win, slot, value=None) itemconfigure(['token', 'configure', win], slot, value) end def token_configinfo(win, slot=nil) itemconfiginfo(['token', 'configure', win], slot) end def current_token_configinfo(win, slot=nil) current_itemconfiginfo(['token', 'configure', win], slot) end def token_windowconfigure(win, slot, value=None) itemconfigure(['token', 'window', win], slot, value) end def token_windowconfiginfo(win, slot=nil) itemconfiginfo(['token', 'window', win], slot) end def current_token_windowconfiginfo(win, slot=nil) current_itemconfiginfo(['token', 'window', win], slot) end end ############################## def self.cancel(win) tk_call('::blt::dnd', 'cancel', *wins) end def self.delete(*wins) tk_call('::blt::dnd', 'delete', *wins) end def self.delete_source(*wins) tk_call('::blt::dnd', 'delete', '-source', *wins) end def self.delete_target(*wins) tk_call('::blt::dnd', 'delete', '-target', *wins) end def self.drag(win, x, y, token=None) tk_call('::blt::dnd', 'drag', win, x, y, token) end def self.drop(win, x, y, token=None) tk_call('::blt::dnd', 'drop', win, x, y, token) end def self.get_data(win, fmt=nil, cmd=nil) if fmt tk_call('::blt::dnd', 'getdata', win, fmt, cmd) else list(tk_call('::blt::dnd', 'getdata', win)) end end def self.names(pat=None) list(tk_call('::blt::dnd', 'names', pat)) end def self.source_names(pat=None) list(tk_call('::blt::dnd', 'names', '-source', pat)) end def self.target_names(pat=None) list(tk_call('::blt::dnd', 'names', '-target', pat)) end def self.pull(win, fmt) tk_call('::blt::dnd', 'pull', win, fmt) end def self.register(win, keys={}) tk_call('::blt::dnd', 'register', win, keys) end def self.select(win, x, y, timestamp) tk_call('::blt::dnd', 'select', win, x, y, timestamp) end def self.set_data(win, fmt=nil, cmd=nil) if fmt tk_call('::blt::dnd', 'setdata', win, fmt, cmd) else list(tk_call('::blt::dnd', 'setdata', win)) end end def self.token(*args) tk_call('::blt::dnd', 'token', *args) end end end ================================================ FILE: ext/tk/lib/tkextlib/blt/vector.rb ================================================ # # tkextlib/blt/vector.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/blt.rb' module Tk::BLT class Vector < TkVariable TkCommandNames = ['::blt::vector'.freeze].freeze def self.create(*args) tk_call('::blt::vector', 'create', *args) end def self.destroy(*args) tk_call('::blt::vector', 'destroy', *args) end def self.expr(expression) tk_call('::blt::vector', 'expr', expression) end def self.names(pat=None) list = simplelist(tk_call('::blt::vector', 'names', pat)) TkVar_ID_TBL.mutex.synchronize{ list.collect{|name| if TkVar_ID_TBL[name] TkVar_ID_TBL[name] elsif name[0..1] == '::' && TkVar_ID_TBL[name[2..-1]] TkVar_ID_TBL[name[2..-1]] else name end } } end #################################### def initialize(size=nil, keys={}) if size.kind_of?(Hash) keys = size size = nil end if size.kind_of?(Array) # [first, last] size = size.join(':') end if size @id = TkCore::INTERP._invoke('::blt::vector', 'create', "#auto(#{size})", *hash_kv(keys)) else @id = TkCore::INTERP._invoke('::blt::vector', 'create', "#auto", *hash_kv(keys)) end TkVar_ID_TBL.mutex.synchronize{ TkVar_ID_TBL[@id] = self } @def_default = false @default_val = nil @trace_var = nil @trace_elem = nil @trace_opts = nil # teach Tk-ip that @id is global var TkCore::INTERP._invoke_without_enc('global', @id) end def destroy tk_call('::blt::vector', 'destroy', @id) end def inspect '#' end def to_s @id end def *(item) list(tk_call(@id, '*', item)) end def +(item) list(tk_call(@id, '+', item)) end def -(item) list(tk_call(@id, '-', item)) end def /(item) list(tk_call(@id, '/', item)) end def append(*vectors) tk_call(@id, 'append', *vectors) end def binread(channel, len=None, keys={}) if len.kind_of?(Hash) keys = len len = None end keys = _symbolkey2str(keys) keys['swap'] = None if keys.delete('swap') tk_call(@id, 'binread', channel, len, keys) end def clear() tk_call(@id, 'clear') self end def delete(*indices) tk_call(@id, 'delete', *indices) self end def dup_vector(vec) tk_call(@id, 'dup', vec) self end def expr(expression) tk_call(@id, 'expr', expression) self end def index(idx, val=None) number(tk_call(@id, 'index', idx, val)) end def [](idx) index(idx) end def []=(idx, val) index(idx, val) end def length() number(tk_call(@id, 'length')) end def length=(size) number(tk_call(@id, 'length', size)) end def merge(*vectors) tk_call(@id, 'merge', *vectors) self end def normalize(vec=None) tk_call(@id, 'normalize', vec) self end def notify(keyword) tk_call(@id, 'notify', keyword) self end def offset() number(tk_call(@id, 'offset')) end def offset=(val) number(tk_call(@id, 'offset', val)) end def random() tk_call(@id, 'random') end def populate(vector, density=None) tk_call(@id, 'populate', vector, density) self end def range(first, last=None) list(tk_call(@id, 'range', first, last)) end def search(val1, val2=None) list(tk_call(@id, 'search', val1, val2)) end def set(item) tk_call(@id, 'set', item) self end def seq(start, finish=None, step=None) tk_call(@id, 'seq', start, finish, step) self end def sort(*vectors) tk_call(@id, 'sort', *vectors) self end def sort_reverse(*vectors) tk_call(@id, 'sort', '-reverse', *vectors) self end def split(*vectors) tk_call(@id, 'split', *vectors) self end def variable(var) tk_call(@id, 'variable', var) self end end class VectorAccess < Vector def self.new(name) TkVar_ID_TBL.mutex.synchronize{ if TkVar_ID_TBL[name] TkVar_ID_TBL[name] else (obj = self.allocate).instance_eval{ initialize(name) TkVar_ID_TBL[@id] = self } obj end } end def initialize(vec_name) @id = vec_name @def_default = false @default_val = nil @trace_var = nil @trace_elem = nil @trace_opts = nil # teach Tk-ip that @id is global var TkCore::INTERP._invoke_without_enc('global', @id) end end end ================================================ FILE: ext/tk/lib/tkextlib/blt/watch.rb ================================================ # # tkextlib/blt/watch.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/blt.rb' module Tk::BLT class Watch < TkObject extend TkCore TkCommandNames = ['::blt::watch'.freeze].freeze WATCH_ID_TBL = TkCore::INTERP.create_table (BLT_WATCH_ID = ['blt_watch_id'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } TkCore::INTERP.init_ip_env{ WATCH_ID_TBL.mutex.synchronize{ WATCH_ID_TBL.clear } } def self.names(state = None) lst = tk_split_list(tk_call('::blt::watch', 'names', state)) WATCH_ID_TBL.mutex.synchronize{ lst.collect{|name| WATCH_ID_TBL[name] || name } } end def __numval_optkeys ['maxlevel'] end private :__numval_optkeys def __boolval_optkeys ['active'] end private :__boolval_optkeys def __config_cmd ['::blt::watch', 'configure', self.path] end private :__config_cmd def initialize(name = nil, keys = {}) if name.kind_of?(Hash) keys = name name = nil end if name @id = name.to_s else BLT_WATCH_ID.mutex.synchronize{ @id = BLT_WATCH_ID.join(TkCore::INTERP._ip_id_) BLT_WATCH_ID[1].succ! } end @path = @id WATCH_ID_TBL.mutex.synchronize{ WATCH_ID_TBL[@id] = self } tk_call('::blt::watch', 'create', @id, *hash_kv(keys)) end def activate tk_call('::blt::watch', 'activate', @id) self end def deactivate tk_call('::blt::watch', 'deactivate', @id) self end def delete tk_call('::blt::watch', 'delete', @id) self end def info ret = [] lst = tk_split_simplelist(tk_call('::blt::watch', 'info', @id)) until lst.empty? k, v, *lst = lst k = k[1..-1] case k when /^(#{__strval_optkeys.join('|')})$/ # do nothing when /^(#{__numval_optkeys.join('|')})$/ begin v = number(v) rescue v = nil end when /^(#{__numstrval_optkeys.join('|')})$/ v = num_or_str(v) when /^(#{__boolval_optkeys.join('|')})$/ begin v = bool(v) rescue v = nil end when /^(#{__listval_optkeys.join('|')})$/ v = simplelist(v) when /^(#{__numlistval_optkeys.join('|')})$/ v = list(v) else if v.index('{') v = tk_split_list(v) else v = tk_tcl2ruby(v) end end ret << [k, v] end ret end def configinfo(slot = nil) if slot slot = slot.to_s v = cget(slot) if TkComm::GET_CONFIGINFO_AS_ARRAY [slot, v] else {slot=>v} end else if TkComm::GET_CONFIGINFO_AS_ARRAY info else Hash[*(info.flatten)] end end end def cget_strict(key) key = key.to_s begin info.assoc(key)[1] rescue fail ArgumentError, "unknown option '#{key}'" end end def cget(key) unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ cget_strict(key) else begin cget_strict(key) rescue => e if current_configinfo.has_key?(key.to_s) # error on known option fail e else # unknown option nil end end end end end end ================================================ FILE: ext/tk/lib/tkextlib/blt/win_printer.rb ================================================ # # tkextlib/blt/win_printer.rb # # *** Windows only *** # # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/blt.rb' module Tk::BLT class Printer < TkObject extend TkCore TkCommandNames = ['::blt::printer'.freeze].freeze def self.enum(attribute) simplelist(tk_call('::blt::printer', 'enum', attribute)) end def self.names(pat=None) simplelist(tk_call('::blt::printer', 'names', pat)) end def self.open(printer) self.new(printer) end ################################# def initialize(printer) @printer_id = tk_call('::blt::printer', 'open', printer) end def close tk_call('::blt::print', 'close', @printer_id) self end def get_attrs(var) tk_call('::blt::print', 'getattrs', @printer_id, var) var end def set_attrs(var) tk_call('::blt::print', 'setattrs', @printer_id, var) self end def snap(win) tk_call('::blt::print', 'snap', @printer_id, win) self end def write(str) tk_call('::blt::print', 'write', @printer_id, str) self end def write_with_title(title, str) tk_call('::blt::print', 'write', @printer_id, title, str) self end end end ================================================ FILE: ext/tk/lib/tkextlib/blt/winop.rb ================================================ # # tkextlib/blt/winop.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/blt.rb' module Tk::BLT module Winop extend TkCore TkCommandNames = ['::blt::winop'.freeze].freeze end WinOp = Winop end class << Tk::BLT::Winop def changes(win) tk_call('::blt::winop', 'changes', win) end def colormap(win) Hash[*list(tk_call('::blt::winop', 'colormap', win))] end def convolve(src, dest, filter) tk_call('::blt::winop', 'convolve', src, dest, filter) end def image_convolve(src, dest, filter) tk_call('::blt::winop', 'image', 'convolve', src, dest, filter) end def image_gradient(photo, left, right, type) tk_call('::blt::winop', 'image', 'gradient', photo, left, right, type) end def image_read_jpeg(file, photo) tk_call('::blt::winop', 'image', 'readjpeg', file, photo) end def image_resample(src, dest, horiz_filter=None, vert_filter=None) tk_call('::blt::winop', 'image', 'resample', src, dest, horiz_filter, vert_filter) end def image_rotate(src, dest, angle) tk_call('::blt::winop', 'image', 'rotate', src, dest, angle) end def image_snap(win, photo, width=None, height=None) tk_call('::blt::winop', 'image', 'snap', win, photo, width, height) end def image_subsample(src, dest, x, y, width, height, horiz_filter=None, vert_filter=None) tk_call('::blt::winop', 'image', 'subsample', src, dest, x, y, width, height, horiz_filter, vert_filter) end def quantize(src, dest, colors) tk_call('::blt::winop', 'quantize', src, dest, colors) end def query() tk_call('::blt::winop', 'query') end def read_jpeg(file, photo) tk_call('::blt::winop', 'readjpeg', file, photo) end def resample(src, dest, horiz_filter=None, vert_filter=None) tk_call('::blt::winop', 'resample', src, dest, horiz_filter, vert_filter) end def subsample(src, dest, x, y, width, height, horiz_filter=None, vert_filter=None) tk_call('::blt::winop', 'subsample', src, dest, x, y, width, height, horiz_filter, vert_filter) end def raise(*wins) tk_call('::blt::winop', 'raise', *wins) end def lower(*wins) tk_call('::blt::winop', 'lower', *wins) end def map(*wins) tk_call('::blt::winop', 'map', *wins) end def unmap(*wins) tk_call('::blt::winop', 'unmap', *wins) end def move(win, x, y) tk_call('::blt::winop', 'move', win, x, y) end def snap(win, photo) tk_call('::blt::winop', 'snap', win, photo) end def warpto(win = None) tk_call('::blt::winop', 'warpto', win) end alias warp_to warpto end ================================================ FILE: ext/tk/lib/tkextlib/blt.rb ================================================ # # BLT support # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/variable' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/blt/setup.rb' # load all image format handlers #TkPackage.require('BLT', '2.4') TkPackage.require('BLT') module Tk module BLT TkComm::TkExtlibAutoloadModule.unshift(self) extend TkCore VERSION = tk_call('set', 'blt_version') PATCH_LEVEL = tk_call('set', 'blt_patchLevel') begin lib = TkCore::INTERP._invoke('set', 'blt_library') rescue lib = '' end LIBRARY = TkVarAccess.new('blt_library', lib) begin lib = TkCore::INTERP._invoke('set', 'blt_libPath') rescue lib = '' end LIB_PATH = TkVarAccess.new('blt_libPath', lib) PACKAGE_NAME = 'BLT'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('BLT') rescue '' end end #################################################### def self.beep(percent = 50) tk_call('::blt::beep', percent) end def self.bgexec(*args) if args[0].kind_of?(TkVariable) var = args.shift else var = TkVariable.new end params = [var] params.concat(hash_kv(args.shift, true)) if args[0].kind_of?(Hash) params << '--' if args[0] =~ /^\s*-[^-]/ params.concat(args) tk_call('::blt::bgexec', *params) var end def self.detach_bgexec(*args) if args[0].kind_of?(TkVariable) var = args.shift else var = TkVariable.new end params = [var] params.concat(hash_kv(args.shift, true)) if args[0].kind_of?(Hash) params << '--' if args[0] =~ /^\s*-[^-]/ params.concat(args) params << '&' [var, tk_split_list(tk_call('::blt::bgexec', *params))] end def self.bltdebug(lvl = nil) if lvl tk_call('::blt::bltdebug', lvl) else number(tk_call('::blt::bltdebug')) end end def self.crc32_file(name) tk_call_without_enc('::blt::crc32', name) end def self.crc32_data(dat) tk_call_without_enc('::blt::crc32', '-data', dat) end #################################################### def self.active_legend(graph) tk_call_without_enc('Blt_ActiveLegend', graph) end def self.crosshairs(graph) tk_call_without_enc('Blt_Crosshairs', graph) end def self.zoom_stack(graph) tk_call_without_enc('Blt_ZoomStack', graph) end def self.print_key(graph) tk_call_without_enc('Blt_PrintKey', graph) end def self.closest_point(graph) tk_call_without_enc('Blt_ClosestPoint', graph) end module GraphCommand def active_legend tk_call_without_enc('Blt_ActiveLegend', @path) self end def crosshairs tk_call_without_enc('Blt_Crosshairs', @path) self end def zoom_stack tk_call_without_enc('Blt_ZoomStack', @path) self end def print_key tk_call_without_enc('Blt_PrintKey', @path) self end def closest_point tk_call_without_enc('Blt_ClosestPoint', @path) self end end #################################################### autoload :PlotComponent,'tkextlib/blt/component.rb' autoload :Barchart, 'tkextlib/blt/barchart.rb' autoload :Bitmap, 'tkextlib/blt/bitmap.rb' autoload :Busy, 'tkextlib/blt/busy.rb' autoload :Container, 'tkextlib/blt/container.rb' autoload :CutBuffer, 'tkextlib/blt/cutbuffer.rb' autoload :DragDrop, 'tkextlib/blt/dragdrop.rb' autoload :EPS, 'tkextlib/blt/eps.rb' autoload :Htext, 'tkextlib/blt/htext.rb' autoload :Graph, 'tkextlib/blt/graph.rb' autoload :Spline, 'tkextlib/blt/spline.rb' autoload :Stripchart, 'tkextlib/blt/stripchart.rb' autoload :Table, 'tkextlib/blt/table.rb' autoload :Tabnotebook, 'tkextlib/blt/tabnotebook.rb' autoload :Tabset, 'tkextlib/blt/tabset.rb' autoload :Ted, 'tkextlib/blt/ted.rb' autoload :Tile, 'tkextlib/blt/tile.rb' autoload :Tree, 'tkextlib/blt/tree.rb' autoload :TreeView, 'tkextlib/blt/treeview.rb' autoload :Hiertable, 'tkextlib/blt/treeview.rb' # Hierbox is obsolete autoload :Vector, 'tkextlib/blt/vector.rb' autoload :VectorAccess, 'tkextlib/blt/vector.rb' autoload :Watch, 'tkextlib/blt/watch.rb' autoload :Winop, 'tkextlib/blt/winop.rb' autoload :WinOp, 'tkextlib/blt/winop.rb' # Unix only autoload :DnD, 'tkextlib/blt/unix_dnd.rb' # Windows only autoload :Printer, 'tkextlib/blt/win_printer.rb' end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/arrowbutton.rb ================================================ # # tkextlib/bwidget/arrowbutton.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/bwidget.rb' require 'tkextlib/bwidget/button' module Tk module BWidget class ArrowButton < Tk::BWidget::Button end end end class Tk::BWidget::ArrowButton TkCommandNames = ['ArrowButton'.freeze].freeze WidgetClassName = 'ArrowButton'.freeze WidgetClassNames[WidgetClassName] = self end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/bitmap.rb ================================================ # # tkextlib/bwidget/bitmap.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/image' require 'tkextlib/bwidget.rb' module Tk module BWidget class Bitmap < TkPhotoImage end end end class Tk::BWidget::Bitmap def initialize(name) @path = tk_call_without_enc('Bitmap::get', name) Tk_IMGTBL[@path] = self end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/button.rb ================================================ # # tkextlib/bwidget/button.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/button' require 'tkextlib/bwidget.rb' module Tk module BWidget class Button < Tk::Button end end end class Tk::BWidget::Button TkCommandNames = ['Button'.freeze].freeze WidgetClassName = 'Button'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'helptext' end private :__strval_optkeys def __tkvariable_optkeys super() << 'helpvar' end private :__tkvariable_optkeys end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/buttonbox.rb ================================================ # # tkextlib/bwidget/buttonbox.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/bwidget.rb' require 'tkextlib/bwidget/button' module Tk module BWidget class ButtonBox < TkWindow end end end class Tk::BWidget::ButtonBox TkCommandNames = ['ButtonBox'.freeze].freeze WidgetClassName = 'ButtonBox'.freeze WidgetClassNames[WidgetClassName] = self include TkItemConfigMethod def __boolval_optkeys super() << 'homogeneous' end private :__boolval_optkeys def tagid(tagOrId) if tagOrId.kind_of?(Tk::BWidget::Button) name = tagOrId[:name] return index(name) unless name.empty? end if tagOrId.kind_of?(Tk::Button) return index(tagOrId[:text]) end # index(tagOrId.to_s) index(_get_eval_string(tagOrId)) end def add(keys={}, &b) win = window(tk_send('add', *hash_kv(keys))) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def delete(idx) tk_send('delete', tagid(idx)) self end def index(idx) if idx.kind_of?(Tk::BWidget::Button) name = idx[:name] idx = name unless name.empty? end if idx.kind_of?(Tk::Button) idx = idx[:text] end number(tk_send('index', idx.to_s)) end def insert(idx, keys={}, &b) win = window(tk_send('insert', tagid(idx), *hash_kv(keys))) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def invoke(idx) tk_send('invoke', tagid(idx)) self end def set_focus(idx) tk_send('setfocus', tagid(idx)) self end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/combobox.rb ================================================ # # tkextlib/bwidget/combobox.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/entry' require 'tkextlib/bwidget.rb' require 'tkextlib/bwidget/listbox' require 'tkextlib/bwidget/spinbox' module Tk module BWidget class ComboBox < Tk::BWidget::SpinBox end end end class Tk::BWidget::ComboBox include Scrollable TkCommandNames = ['ComboBox'.freeze].freeze WidgetClassName = 'ComboBox'.freeze WidgetClassNames[WidgetClassName] = self def get_listbox(&b) win = window(tk_send_without_enc('getlistbox')) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def icursor(idx) tk_send_without_enc('icursor', idx) end def post tk_send_without_enc('post') self end def unpost tk_send_without_enc('unpost') self end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/dialog.rb ================================================ # # tkextlib/bwidget/dialog.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/frame' require 'tkextlib/bwidget.rb' require 'tkextlib/bwidget/buttonbox' module Tk module BWidget class Dialog < TkWindow end end end class Tk::BWidget::Dialog TkCommandNames = ['Dialog'.freeze].freeze WidgetClassName = 'Dialog'.freeze WidgetClassNames[WidgetClassName] = self include TkItemConfigMethod def __strval_optkeys super() << 'title' end private :__strval_optkeys def __boolval_optkeys super() << 'transient' << 'homogeneous' end private :__boolval_optkeys def initialize(parent=nil, keys=nil) @relative = '' if parent.kind_of?(Hash) keys = _symbolkey2str(parent) @relative = keys['parent'] if keys.key?('parent') @relative = keys.delete('relative') if keys.key?('relative') super(keys) elsif keys keys = _symbolkey2str(keys) @relative = keys.delete('parent') if keys.key?('parent') @relative = keys.delete('relative') if keys.key?('relative') super(parent, keys) else super(parent) end end def create_self(keys) cmd = self.class::TkCommandNames[0] if keys and keys != None tk_call_without_enc(cmd, @path, '-parent', @relative, *hash_kv(keys, true)) else tk_call_without_enc(cmd, @path, '-parent', @relative) end end def cget_strict(slot) if slot.to_s == 'relative' super('parent') else super(slot) end end def cget(slot) if slot.to_s == 'relative' super('parent') else super(slot) end end def configure(slot, value=None) if slot.kind_of?(Hash) slot = _symbolkey2str(slot) slot['parent'] = slot.delete('relative') if slot.key?('relative') super(slot) else if slot.to_s == 'relative' super('parent', value) else super(slot, value) end end end def configinfo(slot=nil) if slot if slot.to_s == 'relative' super('parent') else super(slot) end else ret = super() if TkComm::GET_CONFIGINFO_AS_ARRAY ret << ['relative', 'parent'] else ret['relative'] = 'parent' end end end def tagid(tagOrId) if tagOrId.kind_of?(Tk::BWidget::Button) name = tagOrId[:name] return index(name) unless name.empty? end if tagOrId.kind_of?(Tk::Button) return index(tagOrId[:text]) end # index(tagOrId.to_s) index(_get_eval_string(tagOrId)) end def add(keys={}, &b) win = window(tk_send('add', *hash_kv(keys))) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def get_frame(&b) win = window(tk_send('getframe')) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def get_buttonbox(&b) win = window(@path + '.bbox') if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def draw(focus_win=None) tk_send('draw', focus_win) end def enddialog(ret) tk_send('enddialog', ret) end def index(idx) get_buttonbox.index(idx) end def invoke(idx) tk_send('invoke', tagid(idx)) self end def set_focus(idx) tk_send('setfocus', tagid(idx)) self end def withdraw tk_send('withdraw') self end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/dragsite.rb ================================================ # # tkextlib/bwidget/dragsite.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/bwidget.rb' module Tk module BWidget module DragSite end end end module Tk::BWidget::DragSite include Tk extend Tk def self.include(klass, type, event) tk_call('DragSite::include', klass, type, event) end def self.register(path, keys={}) tk_call('DragSite::register', path, *hash_kv(keys)) end def self.set_drag(path, subpath, initcmd, endcmd, force=None) tk_call('DragSite::setdrag', path, subpath, initcmd, endcmd, force) end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/dropsite.rb ================================================ # # tkextlib/bwidget/dropsite.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/bwidget.rb' module Tk module BWidget module DropSite end end end module Tk::BWidget::DropSite include Tk extend Tk def self.include(klass, type) tk_call('DropSite::include', klass, type) end def self.register(path, keys={}) tk_call('DropSite::register', path, *hash_kv(keys)) end def self.set_cursor(cursor) tk_call('DropSite::setcursor', cursor) end def self.set_drop(path, subpath, dropover, drop, force=None) tk_call('DropSite::setdrop', path, subpath, dropover, drop, force) end def self.set_operation(op) tk_call('DropSite::setoperation', op) end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/dynamichelp.rb ================================================ # # tkextlib/bwidget/dynamichelp.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/bwidget.rb' module Tk module BWidget module DynamicHelp end end end module Tk::BWidget::DynamicHelp include Tk extend Tk def self.__pathname 'DynamicHelp::configure' end def __strval_optkeys super() << 'topbackground' end private :__strval_optkeys def self.__cget_cmd ['DynamicHelp::configure'] end def self.__config_cmd ['DynamicHelp::configure'] end def self.cget_strict(slot) slot = slot.to_s info = {} self.current_configinfo.each{|k,v| info[k.to_s] = v if k.to_s == slot} fail RuntimeError, "unknown option \"-#{slot}\"" if info.empty? info.values[0] end def self.cget(slot) self.current_configinfo(slot).values[0] end def self.add(widget, keys={}) tk_call('DynamicHelp::add', widget, *hash_kv(keys)) end def self.delete(widget) tk_call('DynamicHelp::delete', widget) end def self.include(klass, type) tk_call('DynamicHelp::include', klass, type) end def self.sethelp(path, subpath, force=None) tk_call('DynamicHelp::sethelp', path, subpath, force) end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/entry.rb ================================================ # # tkextlib/bwidget/entry.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/entry' require 'tkextlib/bwidget.rb' module Tk module BWidget class Entry < Tk::Entry end end end class Tk::BWidget::Entry include Scrollable TkCommandNames = ['Entry'.freeze].freeze WidgetClassName = 'Entry'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'helptext' << 'insertbackground' end private :__strval_optkeys def __boolval_optkeys super() << 'dragenabled' << 'dropenabled' << 'editable' end private :__boolval_optkeys def __tkvariable_optkeys super() << 'helpvar' end private :__tkvariable_optkeys def invoke tk_send_without_enc('invoke') self end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/label.rb ================================================ # # tkextlib/bwidget/label.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/label' require 'tkextlib/bwidget.rb' module Tk module BWidget class Label < Tk::Label end end end class Tk::BWidget::Label TkCommandNames = ['Label'.freeze].freeze WidgetClassName = 'Label'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'helptext' end private :__strval_optkeys def __boolval_optkeys super() << 'dragenabled' << 'dropenabled' end private :__boolval_optkeys def __tkvariable_optkeys super() << 'helpvar' end private :__tkvariable_optkeys def set_focus tk_send_without_enc('setfocus') self end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/labelentry.rb ================================================ # # tkextlib/bwidget/labelentry.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/entry' require 'tkextlib/bwidget.rb' require 'tkextlib/bwidget/labelframe' require 'tkextlib/bwidget/entry' module Tk module BWidget class LabelEntry < Tk::Entry end end end class Tk::BWidget::LabelEntry include Scrollable TkCommandNames = ['LabelEntry'.freeze].freeze WidgetClassName = 'LabelEntry'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'helptext' << 'insertbackground' << 'entryfg' << 'entrybg' end private :__strval_optkeys def __tkvariable_optkeys super() << 'helpvar' end private :__tkvariable_optkeys def __font_optkeys super() << 'labelfont' end private :__font_optkeys #def entrybind(*args) # _bind([path, 'bind'], *args) # self #end def entrybind(context, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind([path, 'bind'], context, cmd, *args) self end #def entrybind_append(*args) # _bind_append([path, 'bind'], *args) # self #end def entrybind_append(context, *args) #if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append([path, 'bind'], context, cmd, *args) self end def entrybind_remove(*args) _bind_remove([path, 'bind'], *args) self end def entrybindinfo(*args) _bindinfo([path, 'bind'], *args) self end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/labelframe.rb ================================================ # # tkextlib/bwidget/labelframe.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/frame' require 'tkextlib/bwidget.rb' require 'tkextlib/bwidget/label' module Tk module BWidget class LabelFrame < TkWindow end end end class Tk::BWidget::LabelFrame TkCommandNames = ['LabelFrame'.freeze].freeze WidgetClassName = 'LabelFrame'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'helptext' end private :__strval_optkeys def __boolval_optkeys super() << 'dragenabled' << 'dropenabled' end private :__boolval_optkeys def __tkvariable_optkeys super() << 'helpvar' end private :__tkvariable_optkeys def self.align(*args) tk_call('LabelFrame::align', *args) end def get_frame(&b) win = window(tk_send_without_enc('getframe')) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/listbox.rb ================================================ # # tkextlib/bwidget/listbox.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/canvas' require 'tkextlib/bwidget.rb' module Tk module BWidget class ListBox < TkWindow # is NOT a subclass of a listbox widget class. # because it constructed on a canvas widget. class Item < TkObject end end end end class Tk::BWidget::ListBox include TkItemConfigMethod include Scrollable TkCommandNames = ['ListBox'.freeze].freeze WidgetClassName = 'ListBox'.freeze WidgetClassNames[WidgetClassName] = self class Event_for_Items < TkEvent::Event def self._get_extra_args_tbl [ TkComm.method(:string) # item idenfier ] end end def __boolval_optkeys super() << 'autofocus' << 'dragenabled' << 'dropenabled' << 'selectfill' end private :__boolval_optkeys def tagid(tag) if tag.kind_of?(Tk::BWidget::ListBox::Item) tag.id else # tag _get_eval_string(tag) end end #def imagebind(*args) # _bind_for_event_class(Event_for_Items, [path, 'bindImage'], *args) # self #end def imagebind(context, *args) #if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_for_event_class(Event_for_Items, [path, 'bindImage'], context, cmd, *args) self end #def imagebind_append(*args) # _bind_append_for_event_class(Event_for_Items, [path, 'bindImage'], *args) # self #end def imagebind_append(context, *args) #if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append_for_event_class(Event_for_Items, [path, 'bindImage'], context, cmd, *args) self end def imagebind_remove(*args) _bind_remove_for_event_class(Event_for_Items, [path, 'bindImage'], *args) self end def imagebindinfo(*args) _bindinfo_for_event_class(Event_for_Items, [path, 'bindImage'], *args) end #def textbind(*args) # _bind_for_event_class(Event_for_Items, [path, 'bindText'], *args) # self #end def textbind(context, *args) #if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_for_event_class(Event_for_Items, [path, 'bindText'], context, cmd, *args) self end #def textbind_append(*args) # _bind_append_for_event_class(Event_for_Items, [path, 'bindText'], *args) # self #end def textbind_append(context, *args) #if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append_for_event_class(Event_for_Items, [path, 'bindText'], context, cmd, *args) self end def textbind_remove(*args) _bind_remove_for_event_class(Event_for_Items, [path, 'bindText'], *args) self end def textbindinfo(*args) _bindinfo_for_event_class(Event_for_Items, [path, 'bindText'], *args) end def delete(*args) tk_send('delete', *args) self end def edit(item, text, *args) tk_send('edit', tagid(item), text, *args) self end def exist?(item) bool(tk_send('exists', tagid(item))) end def index(item) num_or_str(tk_send('index', tagid(item))) end def insert(idx, item, keys={}) tk_send('insert', idx, tagid(item), *hash_kv(keys)) self end def get_item(idx) tk_send('items', idx) end def items(first=None, last=None) list(tk_send('items', first, last)) end def move(item, idx) tk_send('move', tagid(item), idx) self end def reorder(neworder) tk_send('reorder', neworder) self end def see(item) tk_send('see', tagid(item)) self end def selection_clear tk_send_without_enc('selection', 'clear') self end def selection_set(*args) tk_send_without_enc('selection', 'set', *(args.collect{|item| tagid(item)})) self end def selection_add(*args) tk_send_without_enc('selection', 'add', *(args.collect{|item| tagid(item)})) self end def selection_remove(*args) tk_send_without_enc('selection', 'remove', *(args.collect{|item| tagid(item)})) self end def selection_get(*args) simplelist(tk_send_without_enc('selection', 'get')).collect{|item| Tk::BWidget::ListBox::Item.id2obj(self, item) } end end class Tk::BWidget::ListBox::Item include TkTreatTagFont ListItem_TBL = TkCore::INTERP.create_table (ListItem_ID = ['bw:item'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } TkCore::INTERP.init_ip_env{ ListItem_TBL.mutex.synchronize{ ListItem_TBL.clear } } def self.id2obj(lbox, id) lpath = lbox.path ListItem_TBL.mutex.synchronize{ if ListItem_TBL[lpath] ListItem_TBL[lpath][id]? ListItem_TBL[lpath][id]: id else id end } end def initialize(lbox, *args) if lbox.kind_of?(Tk::BWidget::ListBox) @listbox = lbox else fail RuntimeError, "expect Tk::BWidget::ListBox or Tk::BWidget::ListBox::Item for 1st argument" end if args[-1].kind_of?(Hash) keys = _symbolkey2str(args.pop) else keys = {} end index = keys.delete('index') unless args.empty? index = args.shift end index = 'end' unless index unless args.empty? fail RuntimeError, 'too much arguments' end @lpath = @listbox.path if keys.key?('itemname') @path = @id = keys.delete('itemname') else ListItem_ID.mutex.synchronize{ @path = @id = ListItem_ID.join(TkCore::INTERP._ip_id_) ListItem_ID[1].succ! } end ListItem_TBL.mutex.synchronize{ ListItem_TBL[@id] = self ListItem_TBL[@lpath] = {} unless ListItem_TBL[@lpath] ListItem_TBL[@lpath][@id] = self } @listbox.insert(index, @id, keys) end def listbox @listbox end def id @id end def [](key) cget(key) end def []=(key, val) configure(key, val) val end def cget(key) @listbox.itemcget(@id, key) end def cget_strict(key) @listbox.itemcget_strict(@id, key) end def configure(key, val=None) @listbox.itemconfigure(@id, key, val) end def configinfo(key=nil) @listbox.itemconfiginfo(@id, key) end def current_configinfo(key=nil) @listbox.current_itemconfiginfo(@id, key) end def delete @listbox.delete(@id) self end def edit(*args) @listbox.edit(@id, *args) self end def exist? @listbox.exist?(@id) end def index @listbox.index(@id) end def move(index) @listbox.move(@id, index) end def see @listbox.see(@id) end def selection_add @listbox.selection_add(@id) end def selection_remove @listbox.selection_remove(@id) end def selection_set @listbox.selection_set(@id) end def selection_toggle @listbox.selection_toggle(@id) end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/mainframe.rb ================================================ # # tkextlib/bwidget/mainframe.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/frame' require 'tkextlib/bwidget.rb' require 'tkextlib/bwidget/progressbar' module Tk module BWidget class MainFrame < TkWindow end end end class Tk::BWidget::MainFrame TkCommandNames = ['MainFrame'.freeze].freeze WidgetClassName = 'MainFrame'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'progressfg' end private :__strval_optkeys def __tkvariable_optkeys super() << 'progressvar' end private :__tkvariable_optkeys def __val2ruby_optkeys # { key=>proc, ... } # The method is used to convert a opt-value to a ruby's object. # When get the value of the option "key", "proc.call(value)" is called. { 'menu'=>proc{|v| simplelist(v).collect!{|elem| simplelist(v)}} } end private :__val2ruby_optkeys def add_indicator(keys={}, &b) win = window(tk_send('addindicator', *hash_kv(keys))) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def add_toolbar(&b) win = window(tk_send('addtoolbar')) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def get_frame(&b) win = window(tk_send('getframe')) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def get_indicator(idx, &b) win = window(tk_send('getindicator', idx)) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def get_menu(menu_id, &b) win = window(tk_send('getmenu', menu_id)) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def get_toolbar(idx, &b) win = window(tk_send('gettoolbar', idx)) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def set_menustate(tag, state) tk_send('setmenustate', tag, state) self end def show_statusbar(name) tk_send('showstatusbar', name) self end def show_toolbar(idx, mode) tk_send('showtoolbar', idx, mode) self end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/messagedlg.rb ================================================ # # tkextlib/bwidget/messagedlg.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/bwidget.rb' require 'tkextlib/bwidget/dialog.rb' module Tk module BWidget class MessageDlg < TkWindow end end end class Tk::BWidget::MessageDlg TkCommandNames = ['MessageDlg'.freeze].freeze WidgetClassName = 'MessageDlg'.freeze WidgetClassNames[WidgetClassName] = self def initialize(parent=nil, keys=nil) @relative = '' if parent.kind_of?(Hash) keys = _symbolkey2str(parent) @relative = keys['parent'] if keys.key?('parent') @relative = keys.delete('relative') if keys.key?('relative') super(keys) elsif keys keys = _symbolkey2str(keys) @relative = keys.delete('parent') if keys.key?('parent') @relative = keys.delete('relative') if keys.key?('relative') super(parent, keys) else super(parent) end end def create_self(keys) # NOT create widget. # Because the widget no longer exist when returning from creation. @keys = _symbolkey2str(keys).update('parent'=>@relative) @info = nil end private :create_self def __strval_optkeys super() << 'message' << 'title' end private :__strval_optkeys def __listval_optkeys super() << 'buttons' end private :__listval_optkeys def cget(slot) slot = slot.to_s if slot == 'relative' slot = 'parent' end if winfo_exist? val = super(slot) @keys[slot] = val end @keys[slot] end def cget_strict(slot) slot = slot.to_s if slot == 'relative' slot = 'parent' end if winfo_exist? val = super(slot) @keys[slot] = val end @keys[slot] end def configure(slot, value=None) if winfo_exist? super(slot, value) end if slot.kind_of?(Hash) slot = _symbolkey2str(slot) slot['parent'] = slot.delete('relative') if slot.key?('relative') @keys.update(slot) if @info # update @info slot.each{|k, v| if TkComm::GET_CONFIGINFO_AS_ARRAY if (inf = @info.assoc(k)) inf[-1] = v else @info << [k, '', '', '', v] end else if (inf = @info[k]) inf[-1] = v else @info[k] = ['', '', '', v] end end } end else # ! Hash slot = slot.to_s slot = 'parent' if slot == 'relative' @keys[slot] = value if @info # update @info if TkComm::GET_CONFIGINFO_AS_ARRAY if (inf = @info.assoc(slot)) inf[-1] = value else @info << [slot, '', '', '', value] end else if (inf = @info[slot]) inf[-1] = value else @info[slot] = ['', '', '', value] end end end end self end def configinfo(slot=nil) if winfo_exist? @info = super() if TkComm::GET_CONFIGINFO_AS_ARRAY @info << ['relative', 'parent'] else @info['relative'] = 'parent' end end if TkComm::GET_CONFIGINFO_AS_ARRAY if @info if winfo_exist? # update @keys @info.each{|inf| @keys[inf[0]] = inf[-1] if inf.size > 2 } end else @info = [] @keys.each{|k, v| @info << [k, '', '', '', v] } @info << ['relative', 'parent'] end if slot @info.asoc(slot.to_s).dup else @info.dup end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY if @info if winfo_exist? # update @keys @info.each{|k, inf| @keys[k] = inf[-1] if inf.size > 2 } end else @info = {} @keys.each{|k, v| @info[k] = ['', '', '', v] } @info['relative'] = 'parent' end if slot @info[slot.to_s].dup else @info.dup end end end def create # return the index of the pressed button, or nil if it is destroyed ret = num_or_str(tk_call(self.class::TkCommandNames[0], @path, *hash_kv(@keys))) (ret < 0)? nil: ret end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/notebook.rb ================================================ # # tkextlib/bwidget/notebook.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/frame' require 'tkextlib/bwidget.rb' module Tk module BWidget class NoteBook < TkWindow end end end class Tk::BWidget::NoteBook include TkItemConfigMethod TkCommandNames = ['NoteBook'.freeze].freeze WidgetClassName = 'NoteBook'.freeze WidgetClassNames[WidgetClassName] = self class Event_for_Tabs < TkEvent::Event def self._get_extra_args_tbl [ TkComm.method(:string) # page idenfier ] end end def __boolval_optkeys super() << 'homogeneous' end private :__boolval_optkeys def tagid(id) if id.kind_of?(TkWindow) #id.path id.epath elsif id.kind_of?(TkObject) id.to_eval else # id.to_s _get_eval_string(id) end end #def tabbind(*args) # _bind_for_event_class(Event_for_Tabs, [path, 'bindtabs'], *args) # self #end def tabbind(context, *args) #if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_for_event_class(Event_for_Tabs, [path, 'bindtabs'], context, cmd, *args) self end #def tabbind_append(*args) # _bind_append_for_event_class(Event_for_Tabs, [path, 'bindtabs'], *args) # self #end def tabbind_append(context, *args) #if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append_for_event_class(Event_for_Tabs, [path, 'bindtabs'], context, cmd, *args) self end def tabbind_remove(*args) _bind_remove_for_event_class(Event_for_Tabs, [path, 'bindtabs'], *args) self end def tabbindinfo(*args) _bindinfo_for_event_class(Event_for_Tabs, [path, 'bindtabs'], *args) end def add(page, &b) win = window(tk_send('add', tagid(page))) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def compute_size tk_send('compute_size') self end def delete(page, destroyframe=None) tk_send('delete', tagid(page), destroyframe) self end def get_frame(page, &b) win = window(tk_send('getframe', tagid(page))) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def index(page) num_or_str(tk_send('index', tagid(page))) end def insert(index, page, keys={}, &b) win = window(tk_send('insert', index, tagid(page), *hash_kv(keys))) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def move(page, index) tk_send('move', tagid(page), index) self end def get_page(page) tk_send('pages', page) end def pages(first=None, last=None) list(tk_send('pages', first, last)) end def raise(page=nil) if page tk_send('raise', page) self else tk_send('raise') end end def see(page) tk_send('see', page) self end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/pagesmanager.rb ================================================ # # tkextlib/bwidget/pagesmanager.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/frame' require 'tkextlib/bwidget.rb' module Tk module BWidget class PagesManager < TkWindow end end end class Tk::BWidget::PagesManager TkCommandNames = ['PagesManager'.freeze].freeze WidgetClassName = 'PagesManager'.freeze WidgetClassNames[WidgetClassName] = self def tagid(id) # id.to_s _get_eval_string(id) end def add(page, &b) win = window(tk_send('add', tagid(page))) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def compute_size tk_send('compute_size') self end def delete(page) tk_send('delete', tagid(page)) self end def get_frame(page, &b) win = window(tk_send('getframe', tagid(page))) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def get_page(page) tk_send('pages', page) end def pages(first=None, last=None) list(tk_send('pages', first, last)) end def raise(page=None) tk_send('raise', page) self end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/panedwindow.rb ================================================ # # tkextlib/bwidget/panedwindow.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/frame' require 'tkextlib/bwidget.rb' module Tk module BWidget class PanedWindow < TkWindow end end end class Tk::BWidget::PanedWindow TkCommandNames = ['PanedWindow'.freeze].freeze WidgetClassName = 'PanedWindow'.freeze WidgetClassNames[WidgetClassName] = self def add(keys={}) window(tk_send('add', *hash_kv(keys))) end def get_frame(idx, &b) win = window(tk_send_without_enc('getframe', idx)) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/panelframe.rb ================================================ # # tkextlib/bwidget/panelframe.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/frame' require 'tkextlib/bwidget.rb' module Tk module BWidget class PanelFrame < TkWindow end end end class Tk::BWidget::PanelFrame TkCommandNames = ['PanelFrame'.freeze].freeze WidgetClassName = 'PanelFrame'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() + ['panelforeground', 'panelbackground'] end private :__strval_optkeys def add(win, keys={}) tk_send('add', win, keys) self end def delete(*wins) tk_send('delete', *wins) self end def get_frame(&b) win = window(tk_send_without_enc('getframe')) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def items list(tk_send('items')) end def remove(*wins) tk_send('remove', *wins) self end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/passwddlg.rb ================================================ # # tkextlib/bwidget/passwddlg.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/bwidget.rb' require 'tkextlib/bwidget/messagedlg' module Tk module BWidget class PasswdDlg < Tk::BWidget::MessageDlg end end end class Tk::BWidget::PasswdDlg TkCommandNames = ['PasswdDlg'.freeze].freeze WidgetClassName = 'PasswdDlg'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'loginhelptext' << 'loginlabel' << 'logintext' << 'passwdlabel' << 'passwdtext' end private :__strval_optkeys def __boolval_optkeys super() << 'passwdeditable' << 'homogeneous' end private :__boolval_optkeys def __tkvariable_optkeys super() << 'loginhelpvar' << 'logintextvariable' << 'passwdhelpvar' << 'passwdtextvariable' end private :__tkvariable_optkeys def create login, passwd = simplelist(tk_call(self.class::TkCommandNames[0], @path, *hash_kv(@keys))) [login, passwd] end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/progressbar.rb ================================================ # # tkextlib/bwidget/progressbar.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/bwidget.rb' module Tk module BWidget class ProgressBar < TkWindow end end end class Tk::BWidget::ProgressBar TkCommandNames = ['ProgressBar'.freeze].freeze WidgetClassName = 'ProgressBar'.freeze WidgetClassNames[WidgetClassName] = self end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/progressdlg.rb ================================================ # # tkextlib/bwidget/progressdlg.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/variable' require 'tkextlib/bwidget.rb' require 'tkextlib/bwidget/progressbar' require 'tkextlib/bwidget/messagedlg' module Tk module BWidget class ProgressDlg < Tk::BWidget::MessageDlg end end end class Tk::BWidget::ProgressDlg TkCommandNames = ['ProgressDlg'.freeze].freeze WidgetClassName = 'ProgressDlg'.freeze WidgetClassNames[WidgetClassName] = self def create_self(keys) # NOT create widget for reusing the object super(keys) @keys['textvariable'] = TkVariable.new unless @keys.key?('textvariable') @keys['variable'] = TkVariable.new unless @keys.key?('variable') end def textvariable @keys['textvariable'] end def text @keys['textvariable'].value end def text= (txt) @keys['textvariable'].value = txt end def variable @keys['variable'] end def value @keys['variable'].value end def value= (val) @keys['variable'].value = val end def create window(tk_call(self.class::TkCommandNames[0], @path, *hash_kv(@keys))) end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/scrollableframe.rb ================================================ # # tkextlib/bwidget/scrollableframe.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/frame' require 'tkextlib/bwidget.rb' module Tk module BWidget class ScrollableFrame < TkWindow end end end class Tk::BWidget::ScrollableFrame include Scrollable TkCommandNames = ['ScrollableFrame'.freeze].freeze WidgetClassName = 'ScrollableFrame'.freeze WidgetClassNames[WidgetClassName] = self def get_frame(&b) win = window(tk_send_without_enc('getframe')) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def see(win, vert=None, horiz=None) tk_send_without_enc('see', win, vert, horiz) self end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/scrolledwindow.rb ================================================ # # tkextlib/bwidget/scrolledwindow.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/frame' require 'tkextlib/bwidget.rb' module Tk module BWidget class ScrolledWindow < TkWindow end end end class Tk::BWidget::ScrolledWindow TkCommandNames = ['ScrolledWindow'.freeze].freeze WidgetClassName = 'ScrolledWindow'.freeze WidgetClassNames[WidgetClassName] = self def get_frame(&b) win = window(tk_send_without_enc('getframe')) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def set_widget(win) tk_send_without_enc('setwidget', win) self end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/scrollview.rb ================================================ # # tkextlib/bwidget/scrollview.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/bwidget.rb' module Tk module BWidget class ScrollView < TkWindow end end end class Tk::BWidget::ScrollView TkCommandNames = ['ScrollView'.freeze].freeze WidgetClassName = 'ScrollView'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'fill' end private :__strval_optkeys end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/selectcolor.rb ================================================ # # tkextlib/bwidget/selectcolor.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/bwidget.rb' require 'tkextlib/bwidget/messagedlg' module Tk module BWidget class SelectColor < Tk::BWidget::MessageDlg class Dialog < Tk::BWidget::SelectColor end class Menubutton < Tk::Menubutton end MenuButton = Menubutton end end end class Tk::BWidget::SelectColor extend Tk TkCommandNames = ['SelectColor'.freeze].freeze WidgetClassName = 'SelectColor'.freeze WidgetClassNames[WidgetClassName] = self def dialog(keys={}) newkeys = @keys.dup newkeys.update(_symbolkey2str(keys)) tk_call('SelectColor::dialog', @path, *hash_kv(newkeys)) end def menu(*args) if args[-1].kind_of?(Hash) keys = args.pop else keys = {} end place = args.flatten newkeys = @keys.dup newkeys.update(_symbolkey2str(keys)) tk_call('SelectColor::menu', @path, place, *hash_kv(newkeys)) end def self.set_color(idx, color) tk_call('SelectColor::setcolor', idx, color) end end class Tk::BWidget::SelectColor::Dialog def create_self(keys) super(keys) @keys['type'] = 'dialog' end def create @keys['type'] = 'dialog' # 'dialog' type returns color tk_call(Tk::BWidget::SelectColor::TkCommandNames[0], @path, *hash_kv(@keys)) end end class Tk::BWidget::SelectColor::Menubutton def create_self(keys) keys = {} unless keys keys = _symbolkey2str(keys) keys['type'] = 'menubutton' # 'toolbar' type returns widget path window(tk_call(Tk::BWidget::SelectColor::TkCommandNames[0], @path, *hash_kv(keys))) end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/selectfont.rb ================================================ # # tkextlib/bwidget/selectfont.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/bwidget.rb' require 'tkextlib/bwidget/messagedlg' module Tk module BWidget class SelectFont < Tk::BWidget::MessageDlg class Dialog < Tk::BWidget::SelectFont end class Toolbar < TkWindow end end end end class Tk::BWidget::SelectFont extend Tk TkCommandNames = ['SelectFont'.freeze].freeze WidgetClassName = 'SelectFont'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'sampletext' << 'title' end private :__strval_optkeys def __font_optkeys [] # without fontobj operation end private :__font_optkeys def create tk_call(self.class::TkCommandNames[0], @path, *hash_kv(@keys)) end def self.load_font tk_call('SelectFont::loadfont') end end class Tk::BWidget::SelectFont::Dialog def __font_optkeys [] # without fontobj operation end def create_self(keys) super(keys) @keys['type'] = 'dialog' end def configure(slot, value=None) if slot.kind_of?(Hash) slot.delete['type'] slot.delete[:type] return self if slot.empty? else return self if slot == 'type' || slot == :type end super(slot, value) end def create @keys['type'] = 'dialog' # 'dialog' type returns font name tk_call(Tk::BWidget::SelectFont::TkCommandNames[0], @path, *hash_kv(@keys)) end end class Tk::BWidget::SelectFont::Toolbar def __font_optkeys [] # without fontobj operation end def create_self(keys) keys = {} unless keys keys = _symbolkey2str(keys) keys['type'] = 'toolbar' # 'toolbar' type returns widget path window(tk_call(Tk::BWidget::SelectFont::TkCommandNames[0], @path, *hash_kv(keys))) end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/separator.rb ================================================ # # tkextlib/bwidget/separator.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/bwidget.rb' module Tk module BWidget class Separator < TkWindow end end end class Tk::BWidget::Separator TkCommandNames = ['Separator'.freeze].freeze WidgetClassName = 'Separator'.freeze WidgetClassNames[WidgetClassName] = self end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/setup.rb ================================================ # # setup.rb -- setup script before calling TkPackage.require() # # If you need some setup operations (for example, add a library path # to the library search path) before using Tcl/Tk library packages # wrapped by Ruby scripts in this directory, please write the setup # operations in this file. # ================================================ FILE: ext/tk/lib/tkextlib/bwidget/spinbox.rb ================================================ # # tkextlib/bwidget/entry.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/bwidget.rb' require 'tkextlib/bwidget/arrowbutton' require 'tkextlib/bwidget/entry' module Tk module BWidget class SpinBox < Tk::Entry end end end class Tk::BWidget::SpinBox include Scrollable TkCommandNames = ['SpinBox'.freeze].freeze WidgetClassName = 'SpinBox'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'helptext' << 'insertbackground' << 'entryfg' << 'entrybg' end private :__strval_optkeys def __boolval_optkeys super() << 'dragenabled' << 'dropenabled' << 'editable' end private :__boolval_optkeys def __listval_optkeys super() << 'values' end private :__listval_optkeys def __tkvariable_optkeys super() << 'helpvar' end private :__tkvariable_optkeys #def entrybind(*args) # _bind([path, 'bind'], *args) # self #end def entrybind(context, *args) #if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind([path, 'bind'], context, cmd, *args) self end #def entrybind_append(*args) # _bind_append([path, 'bind'], *args) # self #end def entrybind_append(context, *args) #if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append([path, 'bind'], context, cmd, *args) self end def entrybind_remove(*args) _bind_remove([path, 'bind'], *args) self end def entrybindinfo(*args) _bindinfo([path, 'bind'], *args) self end def get_index_of_value number(tk_send_without_enc('getvalue')) end alias get_value get_index_of_value alias get_value_index get_index_of_value def set_value_by_index(idx) idx = "@#{idx}" if idx.kind_of?(Integer) tk_send_without_enc('setvalue', idx) self end alias set_value set_value_by_index alias set_index_value set_value_by_index end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/statusbar.rb ================================================ # # tkextlib/bwidget/statusbar.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/frame' require 'tkextlib/bwidget.rb' module Tk module BWidget class StatusBar < TkWindow end end end class Tk::BWidget::StatusBar TkCommandNames = ['StatusBar'.freeze].freeze WidgetClassName = 'StatusBar'.freeze WidgetClassNames[WidgetClassName] = self def __boolval_optkeys super() << 'showresize' end private :__boolval_optkeys def add(win, keys={}) tk_send('add', win, keys) self end def delete(*wins) tk_send('delete', *wins) self end def get_frame(&b) win = window(tk_send_without_enc('getframe')) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def items list(tk_send('items')) end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/titleframe.rb ================================================ # # tkextlib/bwidget/titleframe.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/frame' require 'tkextlib/bwidget.rb' module Tk module BWidget class TitleFrame < TkWindow end end end class Tk::BWidget::TitleFrame TkCommandNames = ['TitleFrame'.freeze].freeze WidgetClassName = 'TitleFrame'.freeze WidgetClassNames[WidgetClassName] = self def get_frame(&b) win = window(tk_send_without_enc('getframe')) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/tree.rb ================================================ # # tkextlib/bwidget/tree.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/canvas' require 'tkextlib/bwidget.rb' module Tk module BWidget class Tree < TkWindow class Node < TkObject end end end end class Tk::BWidget::Tree include TkItemConfigMethod include Scrollable TkCommandNames = ['Tree'.freeze].freeze WidgetClassName = 'Tree'.freeze WidgetClassNames[WidgetClassName] = self class Event_for_Items < TkEvent::Event def self._get_extra_args_tbl [ TkComm.method(:string) # item idenfier ] end end def __strval_optkeys super() << 'crossfill' << 'linesfill' end private :__strval_optkeys def __boolval_optkeys super() << 'dragenabled' << 'dropenabled' << 'redraw' << 'selectfill' << 'showlines' end private :__boolval_optkeys def __tkvariable_optkeys super() << 'helpvar' end private :__tkvariable_optkeys def tagid(tag) if tag.kind_of?(Tk::BWidget::Tree::Node) tag.id else # tag _get_eval_string(tag) end end #def imagebind(*args) # _bind_for_event_class(Event_for_Items, [path, 'bindImage'], *args) # self #end def imagebind(context, *args) #if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_for_event_class(Event_for_Items, [path, 'bindImage'], context, cmd, *args) self end #def imagebind_append(*args) # _bind_append_for_event_class(Event_for_Items, [path, 'bindImage'], *args) # self #end def imagebind_append(context, *args) #if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append_for_event_class(Event_for_Items, [path, 'bindImage'], context, cmd, *args) self end def imagebind_remove(*args) _bind_remove_for_event_class(Event_for_Items, [path, 'bindImage'], *args) self end def imagebindinfo(*args) _bindinfo_for_event_class(Event_for_Items, [path, 'bindImage'], *args) end #def textbind(*args) # _bind_for_event_class(Event_for_Items, [path, 'bindText'], *args) # self #end def textbind(context, *args) #if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_for_event_class(Event_for_Items, [path, 'bindText'], context, cmd, *args) self end #def textbind_append(*args) # _bind_append_for_event_class(Event_for_Items, [path, 'bindText'], *args) # self #end def textbind_append(context, *args) #if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append_for_event_class(Event_for_Items, [path, 'bindText'], context, cmd, *args) self end def textbind_remove(*args) _bind_remove_for_event_class(Event_for_Items, [path, 'bindText'], *args) self end def textbindinfo(*args) _bindinfo_for_event_class(Event_for_Items, [path, 'bindText'], *args) end def close_tree(node, recurse=None) tk_send('closetree', tagid(node), recurse) self end def delete(*args) tk_send('delete', *(args.collect{|node| tagid(node)})) self end def edit(node, text, *args) tk_send('edit', tagid(node), text, *args) self end def exist?(node) bool(tk_send('exists', tagid(node))) end def index(node) num_or_str(tk_send('index', tagid(node))) end def insert(idx, parent, node, keys={}) tk_send('insert', idx, tagid(parent), tagid(node), *hash_kv(keys)) self end def move(parent, node, idx) tk_send('move', tagid(parent), tagid(node), idx) self end def get_node(node, idx) Tk::BWidget::Tree::Node.id2obj(self, tk_send('nodes', tagid(node), idx)) end def nodes(node, first=None, last=None) simplelist(tk_send('nodes', tagid(node), first, last)).collect{|node| Tk::BWidget::Tree::Node.id2obj(self, node) } end def open?(node) bool(@tree.itemcget(tagid(node), 'open')) end def open_tree(node, recurse=None) tk_send('opentree', tagid(node), recurse) self end def parent(node) Tk::BWidget::Tree::Node.id2obj(self, tk_send('parent', tagid(node))) end def reorder(node, neworder) tk_send('reorder', tagid(node), neworder) self end def see(node) tk_send('see', tagid(node)) self end def selection_add(*args) tk_send_without_enc('selection', 'add', *(args.collect{|node| tagid(node)})) self end def selection_clear tk_send_without_enc('selection', 'clear') self end def selection_get list(tk_send_without_enc('selection', 'get')) end def selection_include?(*args) bool(tk_send_without_enc('selection', 'get', *(args.collect{|node| tagid(node)}))) end def selection_range(*args) tk_send_without_enc('selection', 'range', *(args.collect{|node| tagid(node)})) self end def selection_remove(*args) tk_send_without_enc('selection', 'remove', *(args.collect{|node| tagid(node)})) self end def selection_set(*args) tk_send_without_enc('selection', 'set', *(args.collect{|node| tagid(node)})) self end def selection_toggle(*args) tk_send_without_enc('selection', 'toggle', *(args.collect{|node| tagid(node)})) self end def toggle(node) tk_send_without_enc('toggle', tagid(node)) self end def visible(node) bool(tk_send_without_enc('visible', tagid(node))) end end class Tk::BWidget::Tree::Node include TkTreatTagFont TreeNode_TBL = TkCore::INTERP.create_table (TreeNode_ID = ['bw:node'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } TkCore::INTERP.init_ip_env{ TreeNode_TBL.mutex.synchronize{ TreeNode_TBL.clear } } def self.id2obj(tree, id) tpath = tree.path TreeNode_TBL.mutex.synchronize{ if TreeNode_TBL[tpath] TreeNode_TBL[tpath][id]? TreeNode_TBL[tpath][id]: id else id end } end def initialize(tree, *args) if tree.kind_of?(Tk::BWidget::Tree) @tree = tree parent = args.shift if parent.kind_of?(Tk::BWidget::Tree::Node) if parent.tree.path != @tree.path fail RuntimeError, 'tree of parent node is not match' end end elsif tree.kind_of?(Tk::BWidget::Tree::Node) @tree = tree.tree parent = tree.parent else fail RuntimeError, "expect Tk::BWidget::Tree or Tk::BWidget::Tree::Node for 1st argument" end if args[-1].kind_of?(Hash) keys = _symbolkey2str(args.pop) else keys = {} end index = keys.delete('index') unless args.empty? index = args.shift end index = 'end' unless index unless args.empty? fail RuntimeError, 'too much arguments' end @tpath = @tree.path if keys.key?('nodename') @path = @id = keys.delete('nodename') else TreeNode_ID.mutex.synchronize{ @path = @id = TreeNode_ID.join(TkCore::INTERP._ip_id_) TreeNode_ID[1].succ! } end TreeNode_TBL.mutex.synchronize{ TreeNode_TBL[@id] = self TreeNode_TBL[@tpath] = {} unless TreeNode_TBL[@tpath] TreeNode_TBL[@tpath][@id] = self } @tree.insert(index, parent, @id, keys) end def tree @tree end def id @id end def [](key) cget(key) end def []=(key, val) configure(key, val) val end def cget(key) @tree.itemcget(@id, key) end def cget_strict(key) @tree.itemcget_strict(@id, key) end def configure(key, val=None) @tree.itemconfigure(@id, key, val) end def configinfo(key=nil) @tree.itemconfiginfo(@id, key) end def current_configinfo(key=nil) @tree.current_itemconfiginfo(@id, key) end def close_tree(recurse=None) @tree.close_tree(@id, recurse) self end def delete @tree.delete(@id) self end def edit(*args) @tree.edit(@id, *args) self end def exist? @tree.exist?(@id) end def index @tree.index(@id) end def move(index, parent=nil) if parent @tree.move(parent, @id, index) else @tree.move(self.parent, @id, index) end end def open_tree(recurse=None) @tree.open_tree(@id, recurse) self end def open? bool(@tree.itemcget(@id, 'open')) end def parent @tree.parent(@id) end def reorder(neworder) @tree.reorder(@id, neworder) end def see @tree.see(@id) end def selection_add @tree.selection_add(@id) end def selection_remove @tree.selection_remove(@id) end def selection_set @tree.selection_set(@id) end def selection_toggle @tree.selection_toggle(@id) end def toggle @tree.toggle(@id) end def visible @tree.visible(@id) end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget/widget.rb ================================================ # # tkextlib/bwidget/widget.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/bwidget.rb' module Tk module BWidget module Widget end end end module Tk::BWidget::Widget include Tk extend Tk def self.__pathname 'Widget::configure' end def self.__cget_cmd ['Widget::cget'] end def self.__config_cmd ['Widget::configure'] end def self.cget_strict(slot) slot = slot.to_s info = {} self.current_configinfo.each{|k,v| info[k.to_s] = v if k.to_s == slot} fail RuntimeError, "unknown option \"-#{slot}\"" if info.empty? info.values[0] end def self.cget(slot) self.current_configinfo(slot).values[0] end def self.add_map(klass, subclass, subpath, opts) tk_call('Widget::addmap', klass, subclass, subpath, opts) end def self.bwinclude(klass, subclass, subpath, *args) tk_call('Widget::bwinclude', klass, subclass, subpath, *args) end def self.create(klass, path, rename=None, &b) win = window(tk_call('Widget::create', klass, path, rename)) if b if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! win.instance_exec(self, &b) else win.instance_eval(&b) end end win end def self.declare(klass, optlist) tk_call('Widget::declare', klass, optlist) end def self.define(klass, filename, *args) tk_call('Widget::define', klass, filename, *args) end def self.destroy(win) tk_call('Widget::destroy', _epath(win)) end def self.focus_next(win) tk_call('Widget::focusNext', win) end def self.focus_ok(win) tk_call('Widget::focusOk', win) end def self.focus_prev(win) tk_call('Widget::focusPrev', win) end def self.generate_doc(dir, widgetlist) tk_call('Widget::generate-doc', dir, widgetlist) end def self.generate_widget_doc(klass, iscmd, file) tk_call('Widget::generate-widget-doc', klass, iscmd, file) end def self.get_option(win, option) tk_call('Widget::getoption', win, option) end def self.get_variable(win, varname, my_varname=None) tk_call('Widget::getVariable', win, varname, my_varname) end def self.has_changed(win, option, pvalue) tk_call('Widget::hasChanged', win, option, pvalue) end def self.init(klass, win, options) tk_call('Widget::init', klass, win, options) end def self.set_option(win, option, value) tk_call('Widget::setoption', win, option, value) end def self.sub_cget_strict(win, subwidget) tk_call('Widget::subcget', win, subwidget) end def self.sub_cget(win, subwidget) self.sub_cget_strict(win, subwidget) end def self.sync_options(klass, subclass, subpath, options) tk_call('Widget::syncoptions', klass, subclass, subpath, options) end def self.tkinclude(klass, tkwidget, subpath, *args) tk_call('Widget::tkinclude', klass, tkwidget, subpath, *args) end end ================================================ FILE: ext/tk/lib/tkextlib/bwidget.rb ================================================ # # BWidget extension support # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/bwidget/setup.rb' # load all image format handlers #TkPackage.require('BWidget', '1.7') TkPackage.require('BWidget') module Tk module BWidget TkComm::TkExtlibAutoloadModule.unshift(self) extend TkCore LIBRARY = tk_call('set', '::BWIDGET::LIBRARY') PACKAGE_NAME = 'BWidget'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('BWidget') rescue '' end end def self.XLFDfont(cmd, *args) if args[-1].kind_of?(Hash) keys = args.pop args.concat(hash_kv(keys)) end tk_call('BWidget::XLFDfont', cmd, *args) end def self.assert(exp, msg=None) tk_call('BWidget::assert', exp, msg) end def self.badOptionString(type, value, list) tk_call('BWidget::badOptionString', type, value, list) end def self.bindMouseWheel(widget) tk_call('BWidget::bindMouseWheel', widget) end def self.classes(klass) list(tk_call('BWidget::classes', klass)) end def self.clonename(menu) tk_call('BWidget::clonename', menu) end def self.focus(opt, path) tk_call('BWidget::focus', opt, path) end def self.get3dcolor(path, bgcolor) tk_call('BWidget::get3dcolor', path, bgcolor) end def self.getname(name) tk_call('BWidget::getname', name) end def self.grab(opt, path) tk_call('BWidget::grab', opt, path) end def self.inuse(klass) bool(tk_call('BWidget::inuse', klass)) end def self.library(klass, *klasses) tk_call('BWidget::library', klass, *klasses) end def self.lreorder(list, neworder) tk_call('BWidget::lreorder', list, neworder) end def self.parsetext(text) tk_call('BWidget::parsetext', text) end def self.place(path, w, h, *args) if args[-1].kind_of?(Hash) keys = args.pop args.concat(hash_kv(keys)) end tk_call('BWidget::place', path, w, h, *(args.flatten)) end def self.write(file, mode=None) tk_call('BWidget::write', file, mode) end def self.wrongNumArgsString(str) tk_call('BWidget::wrongNumArgsString', str) end #################################################### autoload :ArrowButton, 'tkextlib/bwidget/arrowbutton' autoload :Bitmap, 'tkextlib/bwidget/bitmap' autoload :Button, 'tkextlib/bwidget/button' autoload :ButtonBox, 'tkextlib/bwidget/buttonbox' autoload :ComboBox, 'tkextlib/bwidget/combobox' autoload :Dialog, 'tkextlib/bwidget/dialog' autoload :DragSite, 'tkextlib/bwidget/dragsite' autoload :DropSite, 'tkextlib/bwidget/dropsite' autoload :DynamicHelp, 'tkextlib/bwidget/dynamichelp' autoload :Entry, 'tkextlib/bwidget/entry' autoload :Label, 'tkextlib/bwidget/label' autoload :LabelEntry, 'tkextlib/bwidget/labelentry' autoload :LabelFrame, 'tkextlib/bwidget/labelframe' autoload :ListBox, 'tkextlib/bwidget/listbox' autoload :MainFrame, 'tkextlib/bwidget/mainframe' autoload :MessageDlg, 'tkextlib/bwidget/messagedlg' autoload :NoteBook, 'tkextlib/bwidget/notebook' autoload :PagesManager, 'tkextlib/bwidget/pagesmanager' autoload :PanedWindow, 'tkextlib/bwidget/panedwindow' autoload :PasswdDlg, 'tkextlib/bwidget/passwddlg' autoload :ProgressBar, 'tkextlib/bwidget/progressbar' autoload :ProgressDlg, 'tkextlib/bwidget/progressdlg' autoload :ScrollableFrame, 'tkextlib/bwidget/scrollableframe' autoload :ScrolledWindow, 'tkextlib/bwidget/scrolledwindow' autoload :ScrollView, 'tkextlib/bwidget/scrollview' autoload :SelectColor, 'tkextlib/bwidget/selectcolor' autoload :SelectFont, 'tkextlib/bwidget/selectfont' autoload :Separator, 'tkextlib/bwidget/separator' autoload :SpinBox, 'tkextlib/bwidget/spinbox' autoload :TitleFrame, 'tkextlib/bwidget/titleframe' autoload :Tree, 'tkextlib/bwidget/tree' autoload :Widget, 'tkextlib/bwidget/widget' end end ================================================ FILE: ext/tk/lib/tkextlib/itcl/incr_tcl.rb ================================================ # # tkextlib/itk/incr_tcl.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script require 'tkextlib/itcl.rb' # TkPackage.require('Itcl', '3.2') TkPackage.require('Itcl') module Tk module Itcl include Tk extend Tk LIBRARY = TkVarAccess.new('::itcl::library') PURIST = TkVarAccess.new('::itcl::purist') VERSION = TkCore::INTERP._invoke("set", "::itcl::version").freeze PATCHLEVEL = TkCore::INTERP._invoke("set", "::itcl::patchLevel").freeze PACKAGE_NAME = 'Itcl'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('Itcl') rescue '' end end ############################################## class ItclObject < TkObject ITCL_CLASSNAME = ''.freeze (ITCL_OBJ_ID = ['itclobj'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } ITCL_OBJ_TBL = {}.taint def initialize(*args) if (@klass = self.class::ITCL_CLASSNAME).empty? fail RuntimeError, 'unknown itcl class (abstract class?)' end Tk::Itcl::ItclObject::ITCL_OBJ_ID.mutex.synchronize{ @id = Tk::Itcl::ItclObject::TCL_OBJ_ID.join(TkCore::INTERP._ip_id_) Tk::Itcl::ItclObject::ITCL_OBJ_ID[1].succ! } @path = @id end def self.call_proc(name, *args) tk_call("#{ITCL_CLASSNAME}::#{cmd}", *args) end def call_method(name, *args) tk_call(@path, name, *args) end def isa(klass) bool(tk_call(@path, 'isa', klass)) end alias itcl_kind_of? isa def info_class tk_call(@path, 'info', 'class') end def info_inherit simplelist(tk_call(@path, 'info', 'inherit')) end def info_heritage list(tk_call(@path, 'info', 'heritage')) end def info_function(*args) if args[-1].kind_of?(Array) params = args.pop params.each{|param| param = param.to_s args << ( (param[0] == ?-)? param: "-#{param}" ) } end list(tk_call(@path, 'info', 'function', *args)) end def info_variable(*args) if args[-1].kind_of?(Array) params = args.pop params.each{|param| param = param.to_s args << ( (param[0] == ?-)? param: "-#{param}" ) } end list(tk_call(@path, 'info', 'variable', *args)) end end ############################################## def self.body(klass, func, args, body) tk_call('::itcl::body', "#{klass}::#{func}", args, body) end def self.code(cmd, *args) tk_call('::itcl::code', cmd, *args) end def self.code_in_namespace(namespace, cmd, *args) tk_call('::itcl::code', '-namespace', namespace, cmd, *args) end def self.configbody(klass, var, body) tk_call('::itcl::configbody', "#{klass}::#{var}", body) end def self.create_itcl_class(name, body) TkCore::INTERP._invoke('::itcl::class', name, body) klass = Class.new(Tk::Itcl::ItclObject) klass.const_set('ITCL_CLASSNAME', name.dup.freeze) klass end def self.delete_itcl_class(*names) tk_call('::itcl::delete', 'class', *names) end def self.delete_itcl_object(*names) tk_call('::itcl::delete', 'object', *names) end def self.delete_namespace(*names) tk_call('::itcl::delete', 'namespace', *names) end def self.ensemble(name, *args) tk_call('::itcl::ensemble', name, *args) end def self.find_classes(pat=None) simplelist(tk_call('::itcl::find', 'classes', pat)) end def self.find_objects(*args) simplelist(tk_call('::itcl::find', 'objects', *args)) end def self.is_itcl_class(target) bool(tk_call('::itcl::is', 'class', target)) end def self.is_itcl_object(target) bool(tk_call('::itcl::is', 'object', target)) end def self.create_local_obj(klass, name, *args) tk_call('::itcl::local', klass, name, *args) end def self.is_itcl_instance(klass, target) bool(tk_call('::itcl::is', 'object', '-class', klass, target)) end def self.scope(var) tk_call('::itcl::scope', var) end end end ================================================ FILE: ext/tk/lib/tkextlib/itcl/setup.rb ================================================ # # setup.rb -- setup script before calling TkPackage.require() # # If you need some setup operations (for example, add a library path # to the library search path) before using Tcl/Tk library packages # wrapped by Ruby scripts in this directory, please write the setup # operations in this file. # # set [incr Tcl] library directory # ENV['ITCL_LIBRARY'] = '/usr/local/ActiveTcl/lib/itcl3.2/' ================================================ FILE: ext/tk/lib/tkextlib/itcl.rb ================================================ # # [incr Tcl] support # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/itcl/setup.rb' # load library require 'tkextlib/itcl/incr_tcl.rb' ================================================ FILE: ext/tk/lib/tkextlib/itk/incr_tk.rb ================================================ # # tkextlib/itk/incr_tk.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/menuspec' require 'tkextlib/itcl.rb' # call setup script require 'tkextlib/itk.rb' #TkPackage.require('Itk', '3.2') TkPackage.require('Itk') module Tk module Itk include Tk extend Tk LIBRARY = TkVarAccess.new('::itk::library') PACKAGE_NAME = 'Itk'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('Itk') rescue '' end end def self.usual(arg, *args) tk_call('::itk::usual', arg, *args) end def self.usual_names list(tk_call('::itk::usual')) end ############################ class Archetype < TkWindow TkCommandNames = [].freeze # WidgetClassName = 'Archetype'.freeze # WidgetClassNames[WidgetClassName] = self def self.to_eval '::itk::' << self::WidgetClassName end def __destroy_hook__ Tk::Itk::Component::ComponentID_TBL.delete(self.path) end #### [incr Tk] public methods def component simplelist(tk_send('component')) end def component_path(name) window(tk_send('component', name)) end alias component_widget component_path def component_invoke(name, cmd, *args) window(tk_send('component', name, cmd, *args)) end def component_obj(*names) names = component if names.empty? names.collect{|name| Tk::Itk::Component.new(self.path, name) } end #### [incr Tk] protected methods =begin def itk_component_add(visibility, name, create_cmds, option_cmds=None) args = [] visibility.each{|v| v = v.to_s; args << ( (v[0] == ?-)? v: "-#{v}" )} args << '--' << name << create_cmd << option_cmds tk_call('itk_component', 'add', *args) end def itk_component_delete(*names) tk_call('itk_component', 'delete', *names) end def itk_initialize(keys={}) tk_call('itk_initialize', keys) end def itk_option_add(*args) tk_call('itk_option', 'add', *args) end def itk_option_define(name, resource, klass, init, config=None) tk_call('itk_option', 'define', name, resource, klass, init, config) end def itk_option_remove(*args) tk_call('itk_option', 'remove', *args) end =end end ############################ class Toplevel < Archetype TkCommandNames = ['::itk::Toplevel'].freeze WidgetClassName = 'Toplevel'.freeze WidgetClassNames[WidgetClassName] = self include Wm include TkMenuSpec def __strval_optkeys super() << 'title' end private :__strval_optkeys end ############################ class Widget < Archetype TkCommandNames = ['::itk::Widget'].freeze WidgetClassName = 'Widget'.freeze WidgetClassNames[WidgetClassName] = self end ############################ class Component < TkObject def __cget_cmd [self.master, 'component', self.name, 'cget'] end private :__cget_cmd def __config_cmd [self.master, 'component', self.name, 'configure'] end private :__config_cmd ComponentID_TBL = TkCore::INTERP.create_table (Itk_Component_ID = ['itk:component'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } TkCore::INTERP.init_ip_env{ ComponentID_TBL.mutex.synchronize{ ComponentID_TBL.clear } } def self.id2obj(master, id) if master.kind_of?(TkObject) master = master.path else master = master.to_s end ComponentID_TBL.mutex.synchronize{ if ComponentID_TBL.key?(master) (ComponentID_TBL[master].key?(id))? ComponentID_TBL[master][id]: id else id end } end def self.new(master, component=nil) if master.kind_of?(TkObject) master = master.path else master = master.to_s end if component.kind_of?(Tk::Itk::Component) component = component.name elsif component component = component.to_s else Itk_Component_ID.mutex.synchronize{ component = Itk_Component_ID.join(TkCore::INTERP._ip_id_) Itk_Component_ID[1].succ! } end ComponentID_TBL.mutex.synchronize{ if ComponentID_TBL.key?(master) if ComponentID_TBL[master].key?(component) return ComponentID_TBL[master][component] end else ComponentID_TBL[master] = {} end } super(master, component) end def initialize(master, component) @master = master @component = component ComponentID_TBL.mutex.synchronize{ ComponentID_TBL[@master][@component] = self } begin @widget = window(tk_call(@master, 'component', @component)) @path = @widget.path rescue @widget = nil @path = nil end end def path unless @path begin @widget = window(tk_call(@master, 'component', @component)) @path = @widget.path rescue fail RuntimeError, 'component is not assigned to a widget' end end @path end def epath path() end def to_eval path() end def master @master end def name @component end def widget unless @widget begin @widget = window(tk_call(@master, 'component', @component)) @path = @widget.path rescue fail RuntimeError, 'component is not assigned to a widget' end end @widget end def widget_class unless @widget begin @widget = window(tk_call(@master, 'component', @component)) @path = @widget.path @widget.classname rescue nil end end end def method_missing(id, *args) name = id.id2name # try 1 : component command begin return tk_call(@master, 'component', @component, name, *args) rescue end # try 2 : component configure len = args.length begin case len when 1 if name[-1] == ?= return configure(name[0..-2], args[0]) else return configure(name, args[0]) end when 0 return cget(name) end rescue end # try 3 : widget method or widget configure begin unless @widget @widget = window(tk_call(@master, 'component', @component)) @path = @widget.path end @widget.__send__(id, *args) rescue end # unknown method super(id, *args) # fail RuntimeError, "unknown method '#{name}' for #{self.inspect}" end def tk_send(cmd, *rest) begin tk_call(@master, 'component', @component, cmd, *rest) rescue unless @path begin @widget = window(tk_call(@master, 'component', @component)) @path = @widget.path rescue fail RuntimeError, 'component is not assigned to a widget' end end tk_call(@path, cmd, *rest) end end def tk_send_without_enc(cmd, *rest) begin tk_call_without_enc(@master, 'component', @component, cmd, *rest) rescue unless @path begin @widget = window(tk_call(@master, 'component', @component)) @path = @widget.path rescue fail RuntimeError, 'component is not assigned to a widget' end end tk_call_without_enc(@path, cmd, *rest) end end def tk_send_with_enc(cmd, *rest) begin tk_call_with_enc(@master, 'component', @component, cmd, *rest) rescue unless @path begin @widget = window(tk_call(@master, 'component', @component)) @path = @widget.path rescue fail RuntimeError, 'component is not assigned to a widget' end end tk_call_with_enc(@path, cmd, *rest) end end #def bind(*args) # unless @widget # begin # @widget = window(tk_call(@master, 'component', @component)) # @path = @widget.path # rescue # fail RuntimeError, 'component is not assigned to a widget' # end # end # @widget.bind(*args) #end def bind(context, *args) unless @widget begin @widget = window(tk_call(@master, 'component', @component)) @path = @widget.path rescue fail RuntimeError, 'component is not assigned to a widget' end end # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end @widget.bind(context, cmd, *args) end #def bind_append(*args) # unless @widget # begin # @widget = window(tk_call(@master, 'component', @component)) # @path = @widget.path # rescue # fail RuntimeError, 'component is not assigned to a widget' # end # end # @widget.bind_append(*args) #end def bind_append(context, *args) unless @widget begin @widget = window(tk_call(@master, 'component', @component)) @path = @widget.path rescue fail RuntimeError, 'component is not assigned to a widget' end end # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end @widget.bind_append(context, cmd, *args) end def bind_remove(*args) unless @widget begin @widget = window(tk_call(@master, 'component', @component)) @path = @widget.path rescue fail RuntimeError, 'component is not assigned to a widget' end end @widget.bind_remove(*args) end def bindinfo(*args) unless @widget begin @widget = window(tk_call(@master, 'component', @component)) @path = @widget.path rescue fail RuntimeError, 'component is not assigned to a widget' end end @widget.bindinfo(*args) end end end end ================================================ FILE: ext/tk/lib/tkextlib/itk/setup.rb ================================================ # # setup.rb -- setup script before calling TkPackage.require() # # If you need some setup operations (for example, add a library path # to the library search path) before using Tcl/Tk library packages # wrapped by Ruby scripts in this directory, please write the setup # operations in this file. # # set [incr Tk] library directory # ENV['ITK_LIBRARY'] = '/usr/local/ActiveTcl/lib/itk3.2/' ================================================ FILE: ext/tk/lib/tkextlib/itk.rb ================================================ # # [incr Tk] support # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/itk/setup.rb' # load library require 'tkextlib/itk/incr_tk.rb' ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/buttonbox.rb ================================================ # # tkextlib/iwidgets/buttonbox.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Buttonbox < Tk::Itk::Widget end end end class Tk::Iwidgets::Buttonbox TkCommandNames = ['::iwidgets::buttonbox'.freeze].freeze WidgetClassName = 'Buttonbox'.freeze WidgetClassNames[WidgetClassName] = self #################################### include TkItemConfigMethod def __item_cget_cmd(id) [self.path, 'buttoncget', id] end private :__item_cget_cmd def __item_config_cmd(id) [self.path, 'buttonconfigure', id] end private :__item_config_cmd def __item_boolval_optkeys(id) super(id) << 'defaultring' end private :__item_boolval_optkeys def tagid(tagOrId) if tagOrId.kind_of?(Tk::Itk::Component) tagOrId.name else #_get_eval_string(tagOrId) tagOrId end end alias buttoncget itemcget alias buttoncget_strict itemcget_strict alias buttonconfigure itemconfigure alias buttonconfiginfo itemconfiginfo alias current_buttonconfiginfo current_itemconfiginfo private :itemcget, :itemcget_strict private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo #################################### def add(tag=nil, keys={}) if tag.kind_of?(Hash) keys = tag tag = nil end if tag tag = Tk::Itk::Component.new(self, tagid(tag)) else tag = Tk::Itk::Component.new(self) end tk_call(@path, 'add', tagid(tag), *hash_kv(keys)) tag end def default(idx) tk_call(@path, 'default', index(idx)) self end def delete(idx) tk_call(@path, 'delete', index(idx)) self end def hide(idx) tk_call(@path, 'hide', index(idx)) self end def index(idx) number(tk_call(@path, 'index', tagid(idx))) end def insert(idx, tag=nil, keys={}) if tag.kind_of?(Hash) keys = tag tag = nil end if tag tag = Tk::Itk::Component.new(self, tagid(tag)) else tag = Tk::Itk::Component.new(self) end tk_call(@path, 'insert', index(idx), tagid(tag), *hash_kv(keys)) tag end def invoke(idx=nil) if idx tk_call(@path, 'invoke', index(idx)) else tk_call(@path, 'invoke') end self end def show(idx) tk_call(@path, 'show', index(idx)) self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/calendar.rb ================================================ # # tkextlib/iwidgets/calendar.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Calendar < Tk::Itk::Widget end end end class Tk::Iwidgets::Calendar TkCommandNames = ['::iwidgets::calendar'.freeze].freeze WidgetClassName = 'Calendar'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() + [ 'buttonforeground', 'outline', 'selectcolor', 'weekdaybackground', 'weekendbackground' ] end private :__strval_optkeys def __listval_optkeys super() << 'days' end private :__listval_optkeys def __font_optkeys super() + ['currentdatefont', 'datefont', 'dayfont', 'titlefont'] end private :__font_optkeys #################################### include Tk::ValidateConfigure class CalendarCommand < TkValidateCommand #class CalCmdArgs < TkUtil::CallbackSubst class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [?d, ?s, :date], nil ] PROC_TBL = [ [?s, TkComm.method(:string) ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) val end end def self._config_keys # array of config-option key (string or symbol) ['command'] end #def initialize(cmd = Proc.new, *args) # _initialize_for_cb_class(CalCmdArgs, cmd, *args) #end end def __validation_class_list super() << CalendarCommand end Tk::ValidateConfigure.__def_validcmd(binding, CalendarCommand) =begin def command(cmd = Proc.new, args = nil) if cmd.kind_of?(CalendarCommand) configure('command', cmd) elsif args configure('command', [cmd, args]) else configure('command', cmd) end end =end #################################### def get_string tk_call(@path, 'get', '-string') end alias get get_string def get_clicks number(tk_call(@path, 'get', '-clicks')) end def select(date) tk_call(@path, 'select', date) self end def show(date) tk_call(@path, 'show', date) self end def show_now tk_call(@path, 'show', 'now') self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/canvasprintbox.rb ================================================ # # tkextlib/iwidgets/canvasprintbox.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Canvasprintbox < Tk::Itk::Widget end end end class Tk::Iwidgets::Canvasprintbox TkCommandNames = ['::iwidgets::canvasprintbox'.freeze].freeze WidgetClassName = 'Canvasprintbox'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'filename' end private :__strval_optkeys def __boolval_optkeys super() << 'stretch' end private :__boolval_optkeys def get_output tk_call(@path, 'getoutput') end def print bool(tk_call(@path, 'print')) end def refresh tk_call(@path, 'refresh') self end def set_canvas(win) tk_call(@path, 'setcanvas', win) self end def stop tk_call(@path, 'stop') self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/canvasprintdialog.rb ================================================ # # tkextlib/iwidgets/canvasprintdialog.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Canvasprintdialog < Tk::Iwidgets::Dialog end end end class Tk::Iwidgets::Canvasprintdialog TkCommandNames = ['::iwidgets::canvasprintdialog'.freeze].freeze WidgetClassName = 'Canvasprintdialog'.freeze WidgetClassNames[WidgetClassName] = self def get_output tk_call(@path, 'getoutput') end def print bool(tk_call(@path, 'print')) end def refresh tk_call(@path, 'refresh') self end def set_canvas(win) tk_call(@path, 'setcanvas', win) self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/checkbox.rb ================================================ # # tkextlib/iwidgets/checkbox.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Checkbox < Tk::Iwidgets::Labeledframe end end end class Tk::Iwidgets::Checkbox TkCommandNames = ['::iwidgets::checkbox'.freeze].freeze WidgetClassName = 'Checkbox'.freeze WidgetClassNames[WidgetClassName] = self #################################### include TkItemConfigMethod def __item_cget_cmd(id) [self.path, 'buttoncget', id] end private :__item_cget_cmd def __item_config_cmd(id) [self.path, 'buttonconfigure', id] end private :__item_config_cmd def __item_boolval_optkeys(id) super(id) << 'defaultring' end private :__item_boolval_optkeys def tagid(tagOrId) if tagOrId.kind_of?(Tk::Itk::Component) tagOrId.name else #_get_eval_string(tagOrId) tagOrId end end alias buttoncget itemcget alias buttoncget_strict itemcget_strict alias buttonconfigure itemconfigure alias buttonconfiginfo itemconfiginfo alias current_buttonconfiginfo current_itemconfiginfo private :itemcget, :itemcget_strict private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo #################################### def add(tag=nil, keys={}) if tag.kind_of?(Hash) keys = tag tag = nil end if tag tag = Tk::Itk::Component.new(self, tagid(tag)) else tag = Tk::Itk::Component.new(self) end tk_call(@path, 'add', tagid(tag), *hash_kv(keys)) tag end def delete(idx) tk_call(@path, 'delete', index(idx)) self end def deselect(idx) tk_call(@path, 'deselect', index(idx)) self end def flash(idx) tk_call(@path, 'flash', index(idx)) self end def get_tags simplelist(tk_call_without_enc(@path, 'get')) end def get_objs simplelist(tk_call_without_enc(@path, 'get')).collect{|id| Tk::Itk::Component.id2obj(self, id) } end def get(idx=nil) if idx bool(tk_call_without_enc(@path, 'get', index(idx))) else get_tags end end def index(idx) number(tk_call(@path, 'index', tagid(idx))) end def insert(idx, tag=nil, keys={}) if tag.kind_of?(Hash) keys = tag tag = nil end if tag tag = Tk::Itk::Component.new(self, tagid(tag)) else tag = Tk::Itk::Component.new(self) end tk_call(@path, 'insert', index(idx), tagid(tag), *hash_kv(keys)) tag end def select(idx) tk_call(@path, 'select', index(idx)) self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/combobox.rb ================================================ # # tkextlib/iwidgets/combobox.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Combobox < Tk::Iwidgets::Entryfield end end end class Tk::Iwidgets::Combobox TkCommandNames = ['::iwidgets::combobox'.freeze].freeze WidgetClassName = 'Combobox'.freeze WidgetClassNames[WidgetClassName] = self def __boolval_optkeys super() << 'completion' << 'dropdown' << 'editable' << 'unique' end private :__boolval_optkeys def clear(component=None) tk_call(@path, 'clear', component) self end def delete_list(first, last=None) tk_call(@path, 'delete', 'list', first, last) self end def delete_entry(first, last=None) tk_call(@path, 'delete', 'entry', first, last) self end def get_list_contents(index) tk_call(@path, 'get', index) end def insert_list(idx, *elems) tk_call(@path, 'insert', 'list', idx, *elems) self end def insert_entry(idx, *elems) tk_call(@path, 'insert', 'entry', idx, *elems) self end # listbox methods def size tk_send_without_enc('size').to_i end def see(index) tk_send_without_enc('see', index) self end def selection_anchor(index) tk_send_without_enc('selection', 'anchor', index) self end def selection_clear(first, last=None) tk_send_without_enc('selection', 'clear', first, last) self end def selection_includes(index) bool(tk_send_without_enc('selection', 'includes', index)) end def selection_set(first, last=None) tk_send_without_enc('selection', 'set', first, last) self end # scrolledlistbox methods def get_curselection tk_call(@path, 'getcurselection') end def justify(dir) tk_call(@path, 'justify', dir) self end def sort(*params, &b) # see 'lsort' man page about params if b tk_call(@path, 'sort', '-command', proc(&b), *params) else tk_call(@path, 'sort', *params) end self end def sort_ascending tk_call(@path, 'sort', 'ascending') self end def sort_descending tk_call(@path, 'sort', 'descending') self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/dateentry.rb ================================================ # # tkextlib/iwidgets/dateentry.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Dateentry < Tk::Iwidgets::Datefield end end end class Tk::Iwidgets::Dateentry TkCommandNames = ['::iwidgets::dateentry'.freeze].freeze WidgetClassName = 'Dateentry'.freeze WidgetClassNames[WidgetClassName] = self end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/datefield.rb ================================================ # # tkextlib/iwidgets/datefield.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Datefield < Tk::Iwidgets::Labeledwidget end end end class Tk::Iwidgets::Datefield TkCommandNames = ['::iwidgets::datefield'.freeze].freeze WidgetClassName = 'Datefield'.freeze WidgetClassNames[WidgetClassName] = self def __boolval_optkeys super() << 'gmt' end private :__boolval_optkeys def __strval_optkeys super() << 'textbackground' end private :__strval_optkeys def __font_optkeys super() << 'textfont' end private :__font_optkeys def get_string tk_call(@path, 'get', '-string') end alias get get_string def get_clicks number(tk_call(@path, 'get', '-clicks')) end def valid? bool(tk_call(@path, 'isvalid')) end alias isvalid? valid? def show(date=None) tk_call(@path, 'show', date) self end def show_now tk_call(@path, 'show', 'now') self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/dialog.rb ================================================ # # tkextlib/iwidgets/dialog.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Dialog < Tk::Iwidgets::Dialogshell end end end class Tk::Iwidgets::Dialog TkCommandNames = ['::iwidgets::dialog'.freeze].freeze WidgetClassName = 'Dialog'.freeze WidgetClassNames[WidgetClassName] = self end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/dialogshell.rb ================================================ # # tkextlib/iwidgets/dialogshell.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Dialogshell < Tk::Iwidgets::Shell end end end class Tk::Iwidgets::Dialogshell TkCommandNames = ['::iwidgets::dialogshell'.freeze].freeze WidgetClassName = 'Dialogshell'.freeze WidgetClassNames[WidgetClassName] = self #################################### include TkItemConfigMethod def __item_cget_cmd(id) [self.path, 'buttoncget', id] end private :__item_cget_cmd def __item_config_cmd(id) [self.path, 'buttonconfigure', id] end private :__item_config_cmd def __item_boolval_optkeys(id) super(id) << 'defaultring' end private :__item_boolval_optkeys def tagid(tagOrId) if tagOrId.kind_of?(Tk::Itk::Component) tagOrId.name else #_get_eval_string(tagOrId) tagOrId end end alias buttoncget itemcget alias buttoncget_strict itemcget_strict alias buttonconfigure itemconfigure alias buttonconfiginfo itemconfiginfo alias current_buttonconfiginfo current_itemconfiginfo private :itemcget, :itemcget_strict private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo #################################### def add(tag=nil, keys={}) if tag.kind_of?(Hash) keys = tag tag = nil end if tag tag = Tk::Itk::Component.new(self, tagid(tag)) else tag = Tk::Itk::Component.new(self) end tk_call(@path, 'add', tagid(tag), *hash_kv(keys)) tag end def default(idx) tk_call(@path, 'default', index(idx)) self end def delete(idx) tk_call(@path, 'delete', index(idx)) self end def hide(idx) tk_call(@path, 'hide', index(idx)) self end def index(idx) number(tk_call(@path, 'index', tagid(idx))) end def insert(idx, tag=nil, keys={}) if tag.kind_of?(Hash) keys = tag tag = nil end if tag tag = Tk::Itk::Component.new(self, tagid(tag)) else tag = Tk::Itk::Component.new(self) end tk_call(@path, 'insert', index(idx), tagid(tag), *hash_kv(keys)) tag end def invoke(idx=nil) if idx tk_call(@path, 'invoke', index(idx)) else tk_call(@path, 'invoke') end self end def show(idx) tk_call(@path, 'show', index(idx)) self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/disjointlistbox.rb ================================================ # # tkextlib/iwidgets/disjointlistbox.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Disjointlistbox < Tk::Itk::Widget end end end class Tk::Iwidgets::Disjointlistbox TkCommandNames = ['::iwidgets::disjointlistbox'.freeze].freeze WidgetClassName = 'Disjointlistbox'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'lhslabeltext' << 'rhslabeltext' << 'lhsbuttonlabel' << 'rhsbuttonlabel' end private :__strval_optkeys def set_lhs(*items) tk_call(@path, 'setlhs', items) self end def set_rhs(*items) tk_call(@path, 'setrhs', items) self end def get_lhs simplelist(tk_call(@path, 'getlhs')) end def get_rhs simplelist(tk_call(@path, 'getrhs')) end def insert_lhs(*items) tk_call(@path, 'insertlhs', items) self end def insert_rhs(*items) tk_call(@path, 'insertrhs', items) self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/entryfield.rb ================================================ # # tkextlib/iwidgets/entryfield.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Entryfield < Tk::Iwidgets::Labeledwidget end end end class Tk::Iwidgets::Entryfield TkCommandNames = ['::iwidgets::entryfield'.freeze].freeze WidgetClassName = 'Entryfield'.freeze WidgetClassNames[WidgetClassName] = self def __font_optkeys super() << 'textfont' end private :__font_optkeys #################################### include Tk::ValidateConfigure class EntryfieldValidate < TkValidateCommand #class CalCmdArgs < TkUtil::CallbackSubst class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [ ?c, ?s, :char ], [ ?P, ?s, :post ], [ ?S, ?s, :current ], [ ?W, ?w, :widget ], nil ] PROC_TBL = [ [ ?s, TkComm.method(:string) ], [ ?w, TkComm.method(:window) ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end _setup_subst_table(KEY_TBL, PROC_TBL); end def self._config_keys ['validate', 'invalid'] end end def __validation_class_list super() << EntryfieldValidate end Tk::ValidateConfigure.__def_validcmd(binding, EntryfieldValidate) =begin def validate(cmd = Proc.new, args = nil) if cmd.kind_of?(ValidateCmd) configure('validate', cmd) elsif args configure('validate', [cmd, args]) else configure('validate', cmd) end end def invalid(cmd = Proc.new, args = nil) if cmd.kind_of?(ValidateCmd) configure('invalid', cmd) elsif args configure('invalid', [cmd, args]) else configure('invalid', cmd) end end =end #################################### def clear tk_call(@path, 'clear') self end def delete(first, last=None) tk_send_without_enc('delete', first, last) self end def value _fromUTF8(tk_send_without_enc('get')) end def value= (val) tk_send_without_enc('delete', 0, 'end') tk_send_without_enc('insert', 0, _get_eval_enc_str(val)) val end alias get value alias set value= def cursor=(index) tk_send_without_enc('icursor', index) #self index end alias icursor cursor= def index(index) number(tk_send_without_enc('index', index)) end def insert(pos,text) tk_send_without_enc('insert', pos, _get_eval_enc_str(text)) self end def mark(pos) tk_send_without_enc('scan', 'mark', pos) self end def dragto(pos) tk_send_without_enc('scan', 'dragto', pos) self end def selection_adjust(index) tk_send_without_enc('selection', 'adjust', index) self end def selection_clear tk_send_without_enc('selection', 'clear') self end def selection_from(index) tk_send_without_enc('selection', 'from', index) self end def selection_present() bool(tk_send_without_enc('selection', 'present')) end def selection_range(s, e) tk_send_without_enc('selection', 'range', s, e) self end def selection_to(index) tk_send_without_enc('selection', 'to', index) self end # based on tk/scrollable.rb def xview(*index) if index.size == 0 list(tk_send_without_enc('xview')) else tk_send_without_enc('xview', *index) self end end def xview_moveto(*index) xview('moveto', *index) end def xview_scroll(*index) xview('scroll', *index) end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/extbutton.rb ================================================ # # tkextlib/iwidgets/extbutton.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Extbutton < Tk::Itk::Widget end end end class Tk::Iwidgets::Extbutton TkCommandNames = ['::iwidgets::extbutton'.freeze].freeze WidgetClassName = 'Extbutton'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'bitmapforeground' << 'ringbackground' end private :__strval_optkeys def __boolval_optkeys super() << 'defaultring' end private :__boolval_optkeys def invoke tk_call(@path, 'invoke') self end def flash tk_call(@path, 'flash') self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/extfileselectionbox.rb ================================================ # # tkextlib/iwidgets/extfileselectionbox.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Extfileselectionbox < Tk::Itk::Widget end end end class Tk::Iwidgets::Extfileselectionbox TkCommandNames = ['::iwidgets::extfileselectionbox'.freeze].freeze WidgetClassName = 'Extfileselectionbox'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() + [ 'dirslabel', 'fileslabel', 'filterlabel', 'mask', 'nomatchstring', 'selectionlabel' ] end private :__strval_optkeys def __boolval_optkeys super() + ['dirson', 'fileson', 'filteron', 'selectionon'] end private :__boolval_optkeys def child_site window(tk_call(@path, 'childsite')) end def filter tk_call(@path, 'filter') self end def get tk_call(@path, 'get') end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/extfileselectiondialog.rb ================================================ # # tkextlib/iwidgets/extfileselectiondialog.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Extfileselectiondialog < Tk::Iwidgets::Dialog end end end class Tk::Iwidgets::Extfileselectiondialog TkCommandNames = ['::iwidgets::extfileselectiondialog'.freeze].freeze WidgetClassName = 'Extfileselectiondialog'.freeze WidgetClassNames[WidgetClassName] = self def child_site window(tk_call(@path, 'childsite')) end def filter tk_call(@path, 'filter') self end def get tk_call(@path, 'get') end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/feedback.rb ================================================ # # tkextlib/iwidgets/feedback.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Feedback < Tk::Iwidgets::Labeledwidget end end end class Tk::Iwidgets::Feedback TkCommandNames = ['::iwidgets::feedback'.freeze].freeze WidgetClassName = 'Feedback'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'barcolor' end private :__strval_optkeys def reset tk_call(@path, 'reset') self end def step(inc=1) tk_call(@path, 'step', inc) self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/fileselectionbox.rb ================================================ # # tkextlib/iwidgets/fileselectionbox.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Fileselectionbox < Tk::Itk::Widget end end end class Tk::Iwidgets::Fileselectionbox TkCommandNames = ['::iwidgets::fileselectionbox'.freeze].freeze WidgetClassName = 'Fileselectionbox'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() + [ 'directory', 'dirslabel', 'fileslabel', 'filterlabel', 'mask', 'nomatchstring', 'selectionlabel' ] end private :__strval_optkeys def __boolval_optkeys super() + ['dirson', 'fileson', 'filteron', 'selectionon'] end private :__boolval_optkeys def child_site window(tk_call(@path, 'childsite')) end def filter tk_call(@path, 'filter') self end def get tk_call(@path, 'get') end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/fileselectiondialog.rb ================================================ # # tkextlib/iwidgets/fileselectiondialog.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Fileselectiondialog < Tk::Iwidgets::Dialog end end end class Tk::Iwidgets::Fileselectiondialog TkCommandNames = ['::iwidgets::fileselectiondialog'.freeze].freeze WidgetClassName = 'Fileselectiondialog'.freeze WidgetClassNames[WidgetClassName] = self def child_site window(tk_call(@path, 'childsite')) end def filter tk_call(@path, 'filter') self end def get tk_call(@path, 'get') end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/finddialog.rb ================================================ # # tkextlib/iwidgets/finddialog.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Finddialog < Tk::Iwidgets::Dialogshell end end end class Tk::Iwidgets::Finddialog TkCommandNames = ['::iwidgets::finddialog'.freeze].freeze WidgetClassName = 'Finddialog'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() + [ 'patternbackground', 'patternforeground', 'searchbackground', 'searchforeground' ] end private :__strval_optkeys def __val2ruby_optkeys # { key=>proc, ... } super().update('textwidget'=>proc{|v| window(v)}) end private :__val2ruby_optkeys def clear tk_call(@path, 'clear') self end def find tk_call(@path, 'find') end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/hierarchy.rb ================================================ # # tkextlib/iwidgets/hierarchy.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/text' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Hierarchy < Tk::Iwidgets::Scrolledwidget end end end class Tk::Iwidgets::Hierarchy ItemConfCMD = ['tag'.freeze, 'configure'.freeze].freeze include TkTextTagConfig TkCommandNames = ['::iwidgets::hierarchy'.freeze].freeze WidgetClassName = 'Hierarchy'.freeze WidgetClassNames[WidgetClassName] = self #################################### include Tk::ValidateConfigure class QueryCommand < TkValidateCommand class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [?n, ?s, :node], nil ] PROC_TBL = [ [?s, TkComm.method(:string) ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) val end end def self._config_keys # array of config-option key (string or symbol) ['querycommand'] end end class IndicatorCommand < TkValidateCommand class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [ ?n, ?s, :node ], [ ?s, ?b, :status ], nil ] PROC_TBL = [ [ ?s, TkComm.method(:string) ], [ ?b, TkComm.method(:bool) ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) val end end def self._config_keys # array of config-option key (string or symbol) ['iconcommand', 'icondblcommand', 'imagedblcommand'] end end class IconCommand < TkValidateCommand class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [ ?n, ?s, :node ], [ ?i, ?s, :icon ], nil ] PROC_TBL = [ [ ?s, TkComm.method(:string) ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) val end end def self._config_keys # array of config-option key (string or symbol) ['dblclickcommand', 'imagecommand', 'selectcommand'] end end def __validation_class_list super() << QueryCommand << IndicatorCommand << IconCommand end Tk::ValidateConfigure.__def_validcmd(binding, QueryCommand) Tk::ValidateConfigure.__def_validcmd(binding, IndicatorCommand) Tk::ValidateConfigure.__def_validcmd(binding, IconCommand) #################################### def __boolval_optkeys super() << 'alwaysquery' << 'expanded' << 'filter' end private :__boolval_optkeys def __strval_optkeys super() << 'markbackground' << 'markforeground' << 'textbackground' end private :__strval_optkeys def __font_optkeys super() << 'textfont' end private :__font_optkeys def clear tk_call(@path, 'clear') self end def collapse(node) tk_call(@path, 'collapse') self end def current tk_call(@path, 'current') end def draw(mode=None) case mode when None # do nothing when 'now', :now mode = '-now' when 'eventually', :eventually mode = '-eventually' when String, Symbol mode = mode.to_s mode = '-' << mode if mode[0] != ?- end tk_call(@path, 'draw', mode) end def expand(node) tk_call(@path, 'expand', node) self end def expanded?(node) bool(tk_call(@path, 'expanded', node)) end def exp_state list(tk_call(@path, 'expState')) end alias expand_state exp_state alias expanded_list exp_state def mark_clear tk_call(@path, 'mark', 'clear') self end def mark_add(*nodes) tk_call(@path, 'mark', 'add', *nodes) self end def mark_remove(*nodes) tk_call(@path, 'mark', 'remove', *nodes) self end def mark_get list(tk_call(@path, 'mark', 'get')) end def refresh(node) tk_call(@path, 'refresh', node) self end def prune(node) tk_call(@path, 'prune', node) self end def selection_clear tk_call(@path, 'selection', 'clear') self end def selection_add(*nodes) tk_call(@path, 'selection', 'add', *nodes) self end def selection_remove(*nodes) tk_call(@path, 'selection', 'remove', *nodes) self end def selection_get list(tk_call(@path, 'selection', 'get')) end def toggle(node) tk_call(@path, 'toggle', node) self end # based on Tk::Text widget def bbox(index) list(tk_send_without_enc('bbox', _get_eval_enc_str(index))) end def compare(idx1, op, idx2) bool(tk_send_without_enc('compare', _get_eval_enc_str(idx1), op, _get_eval_enc_str(idx2))) end def debug bool(tk_send_without_enc('debug')) end def debug=(boolean) tk_send_without_enc('debug', boolean) #self boolean end def delete(first, last=None) tk_send_without_enc('delete', first, last) self end def dlineinfo(index) list(tk_send_without_enc('dlineinfo', _get_eval_enc_str(index))) end def get(*index) _fromUTF8(tk_send_without_enc('get', *index)) end def index(index) tk_send_without_enc('index', _get_eval_enc_str(index)) end def insert(index, chars, *tags) if tags[0].kind_of? Array # multiple chars-taglist argument :: str, [tag,...], str, [tag,...], ... args = [chars] while tags.size > 0 args << tags.shift.collect{|x|_get_eval_string(x)}.join(' ') # taglist args << tags.shift if tags.size > 0 # chars end super(index, *args) else # single chars-taglist argument :: str, tag, tag, ... if tags.size == 0 super(index, chars) else super(index, chars, tags.collect{|x|_get_eval_string(x)}.join(' ')) end end end def scan_mark(x, y) tk_send_without_enc('scan', 'mark', x, y) self end def scan_dragto(x, y) tk_send_without_enc('scan', 'dragto', x, y) self end def see(index) tk_send_without_enc('see', index) self end # based on tk/scrollable.rb def xview(*index) if index.size == 0 list(tk_send_without_enc('xview')) else tk_send_without_enc('xview', *index) self end end def xview_moveto(*index) xview('moveto', *index) end def xview_scroll(*index) xview('scroll', *index) end def yview(*index) if index.size == 0 list(tk_send_without_enc('yview')) else tk_send_without_enc('yview', *index) self end end def yview_moveto(*index) yview('moveto', *index) end def yview_scroll(*index) yview('scroll', *index) end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/hyperhelp.rb ================================================ # # tkextlib/iwidgets/hyperhelp.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Hyperhelp < Tk::Iwidgets::Shell end end end class Tk::Iwidgets::Hyperhelp TkCommandNames = ['::iwidgets::hyperhelp'.freeze].freeze WidgetClassName = 'Hyperhelp'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'helpdir' end private :__strval_optkeys def __listval_optkeys super() << 'topics' end private :__listval_optkeys def show_topic(topic) tk_call(@path, 'showtopic', topic) self end def follow_link(href) tk_call(@path, 'followlink', href) self end def forward tk_call(@path, 'forward') self end def back tk_call(@path, 'back') self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/labeledframe.rb ================================================ # # tkextlib/iwidgets/labeledframe.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Labeledframe < Tk::Itk::Archetype end end end class Tk::Iwidgets::Labeledframe TkCommandNames = ['::iwidgets::labeledframe'.freeze].freeze WidgetClassName = 'Labeledframe'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'labeltext' end private :__strval_optkeys def __tkvariable_optkeys super() << 'labelvariable' end private :__tkvariable_optkeys def __font_optkeys super() << 'labelfont' end private :__font_optkeys def child_site window(tk_call(@path, 'childsite')) end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/labeledwidget.rb ================================================ # # tkextlib/iwidgets/labeledwidget.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Labeledwidget < Tk::Itk::Widget end end end class Tk::Iwidgets::Labeledwidget extend TkCore TkCommandNames = ['::iwidgets::labeledwidget'.freeze].freeze WidgetClassName = 'Labeledwidget'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'labeltext' end private :__strval_optkeys def __tkvariable_optkeys super() << 'labelvariable' end private :__tkvariable_optkeys def __font_optkeys super() << 'labelfont' end private :__font_optkeys def self.alignlabels(*wins) tk_call('::iwidgets::Labeledwidget::alignlabels', *wins) end def child_site window(tk_call(@path, 'childsite')) end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/mainwindow.rb ================================================ # # tkextlib/iwidgets/mainwindow.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Mainwindow < Tk::Iwidgets::Shell end end end class Tk::Iwidgets::Mainwindow TkCommandNames = ['::iwidgets::mainwindow'.freeze].freeze WidgetClassName = 'Mainwindow'.freeze WidgetClassNames[WidgetClassName] = self def __boolval_optkeys super() << 'helpline' << 'statusline' end private :__boolval_optkeys def __strval_optkeys super() << 'menubarbackground' << 'menubarforeground' << 'toolbarforeground' end private :__strval_optkeys def __font_optkeys super() << 'menubarfont' << 'toolbarfont' end private :__font_optkeys def child_site window(tk_call(@path, 'childsite')) end def menubar(*args) unless args.empty? tk_call(@path, 'menubar', *args) end window(tk_call(@path, 'menubar')) end def mousebar(*args) unless args.empty? tk_call(@path, 'mousebar', *args) end window(tk_call(@path, 'mousebar')) end def msgd(*args) unless args.empty? tk_call(@path, 'msgd', *args) end window(tk_call(@path, 'msgd')) end def toolbar(*args) unless args.empty? tk_call(@path, 'toolbar', *args) end window(tk_call(@path, 'toolbar')) end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/menubar.rb ================================================ # # tkextlib/iwidgets/menubar.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Menubar < Tk::Itk::Widget end end end class Tk::Iwidgets::Menubar TkCommandNames = ['::iwidgets::menubar'.freeze].freeze WidgetClassName = 'Menubar'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'menubuttons' end private :__strval_optkeys def __tkvariable_optkeys super() << 'helpvariable' end private :__tkvariable_optkeys #################################### include TkItemConfigMethod def __item_cget_cmd(id) [self.path, 'menucget', id] end private :__item_cget_cmd def __item_config_cmd(id) [self.path, 'menuconfigure', id] end private :__item_config_cmd def __item_strval_optkeys(id) super(id) << 'selectcolor' end private :__item_strval_optkeys def __item_tkvariable_optkeys(id) super(id) << 'helpstr' end private :__item_tkvariable_optkeys def tagid(tagOrId) if tagOrId.kind_of?(Tk::Itk::Component) tagOrId.name else #_get_eval_string(tagOrId) tagOrId end end alias menucget itemcget alias menucget_strict itemcget_strict alias menuconfigure itemconfigure alias menuconfiginfo itemconfiginfo alias current_menuconfiginfo current_itemconfiginfo private :itemcget, :itemcget_strict private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo #################################### def __methodcall_optkeys {'menubuttons'=>'menubuttons'} end def menubuttons(val = nil) unless val return tk_call(@path, 'cget', '-menubuttons') end tk_call(@path, 'configure', '-menubuttons', _parse_menu_spec(val)) self end def _parse_menu_spec(menu_spec) ret = '' menu_spec.each{|spec| next unless spec if spec.kind_of?(Hash) args = [spec] type = 'options' else type, *args = spec end type = type.to_s case type when 'options' keys = args[0] ary = [type] ary.concat(hash_kv(keys)) ret << array2tk_list(ary) << "\n" when 'menubutton', 'cascade' name, keys = args if keys ary = [type, name] keys = _symbolkey2str(keys) keys['menu'] = _parse_menu_spec(keys['menu']) if keys.key?('menu') ary.concat(hash_kv(keys)) ret << array2tk_list(ary) << "\n" else ret << array2tk_list([type, name]) << "\n" end else name, keys = args if keys ary = [type, name] ary.concat(hash_kv(keys)) ret << array2tk_list(ary) << "\n" else ret << array2tk_list([type, name]) << "\n" end end } ret end #################################### def add(type, tag=nil, keys={}) if tag.kind_of?(Hash) keys = tag tag = nil end if tag tag = Tk::Itk::Component.new(self, tagid(tag)) else tag = Tk::Itk::Component.new(self) end keys = _symbolkey2str(keys) keys['menu'] = _parse_menu_spec(keys['menu']) if keys.key?('menu') tk_call(@path, 'add', type, tagid(tag), *hash_kv(keys)) tag end def delete(path1, path2=nil) if path2 else tk_call(@path, 'delete', index(idx)) end self end def index(idx) number(tk_call(@path, 'index', tagid(idx))) end def insert(idx, type, tag=nil, keys={}) if tag.kind_of?(Hash) keys = tag tag = nil end if tag tag = Tk::Itk::Component.new(self, tagid(tag)) else tag = Tk::Itk::Component.new(self) end keys = _symbolkey2str(keys) keys['menu'] = _parse_menu_spec(keys['menu']) if keys.key?('menu') tk_call(@path, 'insert', index(idx), type, tagid(tag), *hash_kv(keys)) tag end def invoke(idx) tk_call(@path, 'invoke', index(idx)) self end def menupath(pat) if (win = tk_call(@path, 'path', pat)) == '-1' return nil end window(win) end def menupath_glob(pat) if (win = tk_call(@path, 'path', '-glob', pat)) == '-1' return nil end window(win) end def menupath_tclregexp(pat) if (win = tk_call(@path, 'path', '-regexp', pat)) == '-1' return nil end window(win) end def type(path) tk_call(@path, 'type', path) end def yposition(path) number(tk_call(@path, 'yposition', path)) end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/messagebox.rb ================================================ # # tkextlib/iwidgets/messagebox.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Messagebox < Tk::Iwidgets::Scrolledwidget end end end class Tk::Iwidgets::Messagebox TkCommandNames = ['::iwidgets::messagebox'.freeze].freeze WidgetClassName = 'Messagebox'.freeze WidgetClassNames[WidgetClassName] = self #################################### include TkItemConfigMethod def __item_cget_cmd(id) [self.path, 'type', 'cget', id] end private :__item_cget_cmd def __item_config_cmd(id) [self.path, 'type', 'configure', id] end private :__item_config_cmd def tagid(tagOrId) if tagOrId.kind_of?(Tk::Itk::Component) tagOrId.name else #_get_eval_string(tagOrId) tagOrId end end def __item_boolval_optkeys(id) super(id) << 'bell' << 'show' end private :__item_boolval_optkeys alias typecget itemcget alias typecget_strict itemcget_strict alias typeconfigure itemconfigure alias typeconfiginfo itemconfiginfo alias current_typeconfiginfo current_itemconfiginfo private :itemcget, :itemcget_strict private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo #################################### def __strval_optkeys super() << 'filename' << 'savedir' end private :__strval_optkeys def type_add(tag=nil, keys={}) if tag.kind_of?(Hash) keys = tag tag = nil end unless tag tag = Tk::Itk::Component.new(self) end tk_call(@path, 'type', 'add', tagid(tag), *hash_kv(keys)) tag end def clear tk_call(@path, 'clear') self end def export(file) tk_call(@path, 'export', file) self end def issue(string, type=None, *args) tk_call(@path, 'issue', string, tagid(type), *args) self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/messagedialog.rb ================================================ # # tkextlib/iwidgets/messagedialog.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Messagedialog < Tk::Iwidgets::Dialog end end end class Tk::Iwidgets::Messagedialog TkCommandNames = ['::iwidgets::messagedialog'.freeze].freeze WidgetClassName = 'Messagedialog'.freeze WidgetClassNames[WidgetClassName] = self end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/notebook.rb ================================================ # # tkextlib/iwidgets/notebook.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Notebook < Tk::Itk::Widget end end end class Tk::Iwidgets::Notebook TkCommandNames = ['::iwidgets::notebook'.freeze].freeze WidgetClassName = 'Notebook'.freeze WidgetClassNames[WidgetClassName] = self #################################### include TkItemConfigMethod def __item_cget_cmd(id) [self.path, 'pagecget', id] end private :__item_cget_cmd def __item_config_cmd(id) [self.path, 'pageconfigure', id] end private :__item_config_cmd def tagid(tagOrId) if tagOrId.kind_of?(Tk::Itk::Component) tagOrId.name else #_get_eval_string(tagOrId) tagOrId end end alias pagecget itemcget alias pagecget_strict itemcget_strict alias pageconfigure itemconfigure alias pageconfiginfo itemconfiginfo alias current_pageconfiginfo current_itemconfiginfo private :itemcget, :itemcget_strict private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo #################################### def __boolval_optkeys super() << 'auto' end private :__boolval_optkeys def add(keys={}) window(tk_call(@path, 'add', *hash_kv(keys))) end def child_site_list list(tk_call(@path, 'childsite')) end def child_site(idx) if (new_idx = self.index(idx)) < 0 new_idx = tagid(idx) end window(tk_call(@path, 'childsite', new_idx)) end def delete(idx1, idx2=nil) if (new_idx1 = self.index(idx1)) < 0 new_idx1 = tagid(idx1) end if idx2 if (new_idx2 = self.index(idx2)) < 0 new_idx2 = tagid(idx2) end tk_call(@path, 'delete', new_idx1, new_idx2) else tk_call(@path, 'delete', new_idx1) end self end def index(idx) number(tk_call(@path, 'index', tagid(idx))) end def insert(idx, keys={}) if (new_idx = self.index(idx)) < 0 new_idx = tagid(idx) end window(tk_call(@path, 'insert', new_idx, *hash_kv(keys))) end def next tk_call(@path, 'next') self end def prev tk_call(@path, 'prev') self end def select(idx) if (new_idx = self.index(idx)) < 0 new_idx = tagid(idx) end tk_call(@path, 'select', new_idx) self end def scrollcommand(cmd=Proc.new) configure_cmd 'scrollcommand', cmd self end alias xscrollcommand scrollcommand alias yscrollcommand scrollcommand def xscrollbar(bar=nil) if bar @scrollbar = bar @scrollbar.orient 'horizontal' self.scrollcommand {|*arg| @scrollbar.set(*arg)} @scrollbar.command {|*arg| self.xview(*arg)} Tk.update # avoid scrollbar trouble end @scrollbar end def yscrollbar(bar=nil) if bar @scrollbar = bar @scrollbar.orient 'vertical' self.scrollcommand {|*arg| @scrollbar.set(*arg)} @scrollbar.command {|*arg| self.yview(*arg)} Tk.update # avoid scrollbar trouble end @scrollbar end alias scrollbar yscrollbar def view(*idxs) if idxs.size == 0 idx = num_or_str(tk_send_without_enc('view')) if idx.kind_of?(Fixnum) && idx < 0 nil else idx end else tk_send_without_enc('view', *idxs) self end end alias xview view alias yview view def view_moveto(*idxs) view('moveto', *idxs) end alias xview_moveto view_moveto alias yview_moveto view_moveto def view_scroll(index, what='pages') view('scroll', index, what) end alias xview_scroll view_scroll alias yview_scroll view_scroll end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/optionmenu.rb ================================================ # # tkextlib/iwidgets/optionmenu.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Optionmenu < Tk::Iwidgets::Labeledwidget end end end class Tk::Iwidgets::Optionmenu TkCommandNames = ['::iwidgets::optionmenu'.freeze].freeze WidgetClassName = 'Optionmenu'.freeze WidgetClassNames[WidgetClassName] = self def __boolval_optkeys super() << 'cyclicon' end private :__boolval_optkeys def delete(first, last=nil) if last tk_call(@path, 'delete', first, last) else tk_call(@path, 'delete', first) end self end def disable(idx) tk_call(@path, 'disable', idx) self end def enable(idx) tk_call(@path, 'enable', idx) self end def get(first=nil, last=nil) if last simplelist(tk_call(@path, 'get', first, last)) elsif first tk_call(@path, 'get', first) else tk_call(@path, 'get') end end def get_range(first, last) get(first, last) end def get_selected get() end def index(idx) number(tk_call(@path, 'index', idx)) end def insert(idx, *args) tk_call(@path, 'insert', idx, *args) self end def select(idx) tk_call(@path, 'select', idx) self end def sort(*params, &b) # see 'lsort' man page about params if b tk_call(@path, 'sort', '-command', proc(&b), *params) else tk_call(@path, 'sort', *params) end self end def sort_ascending tk_call(@path, 'sort', 'ascending') self end def sort_descending tk_call(@path, 'sort', 'descending') self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/panedwindow.rb ================================================ # # tkextlib/iwidgets/panedwindow.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Panedwindow < Tk::Itk::Widget end end end class Tk::Iwidgets::Panedwindow TkCommandNames = ['::iwidgets::panedwindow'.freeze].freeze WidgetClassName = 'Panedwindow'.freeze WidgetClassNames[WidgetClassName] = self #################################### include TkItemConfigMethod def __item_cget_cmd(id) [self.path, 'panecget', id] end private :__item_cget_cmd def __item_config_cmd(id) [self.path, 'paneconfigure', id] end private :__item_config_cmd def tagid(tagOrId) if tagOrId.kind_of?(Tk::Itk::Component) tagOrId.name else #_get_eval_string(tagOrId) tagOrId end end alias panecget itemcget alias panecget_strict itemcget_strict alias paneconfigure itemconfigure alias paneconfiginfo itemconfiginfo alias current_paneconfiginfo current_itemconfiginfo private :itemcget, :itemcget_strict private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo #################################### def __boolval_optkeys super() << 'showhandle' end private :__boolval_optkeys def add(tag=nil, keys={}) if tag.kind_of?(Hash) keys = tag tag = nil end if tag tag = Tk::Itk::Component.new(self, tagid(tag)) else tag = Tk::Itk::Component.new(self) end window(tk_call(@path, 'add', tagid(tag), *hash_kv(keys))) tag end def child_site_list list(tk_call(@path, 'childsite')) end def child_site(idx) window(tk_call(@path, 'childsite', index(idx))) end def delete(idx) tk_call(@path, 'delete', index(idx)) self end def fraction(*percentages) tk_call(@path, 'fraction', *percentages) self end def hide(idx) tk_call(@path, 'hide', index(idx)) self end def index(idx) number(tk_call(@path, 'index', tagid(idx))) end def insert(idx, tag=nil, keys={}) if tag.kind_of?(Hash) keys = tag tag = nil end if tag tag = Tk::Itk::Component.new(self, tagid(tag)) else tag = Tk::Itk::Component.new(self) end window(tk_call(@path, 'insert', index(idx), tagid(tag), *hash_kv(keys))) tag end def invoke(idx=nil) if idx tk_call(@path, 'invoke', index(idx)) else tk_call(@path, 'invoke') end self end def reset tk_call(@path, 'reset') self end def show(idx) tk_call(@path, 'show', index(idx)) self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/promptdialog.rb ================================================ # # tkextlib/iwidgets/promptdialog.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Promptdialog < Tk::Iwidgets::Dialog end end end class Tk::Iwidgets::Promptdialog TkCommandNames = ['::iwidgets::promptdialog'.freeze].freeze WidgetClassName = 'Promptdialog'.freeze WidgetClassNames[WidgetClassName] = self # index method is not available, because it shows index of the entry field def default(name) tk_call(@path, 'default', tagid(name)) self end def hide(name) tk_call(@path, 'hide', tagid(name)) self end def invoke(name=nil) if name tk_call(@path, 'invoke', tagid(name)) else tk_call(@path, 'invoke') end self end def show(name) tk_call(@path, 'show', tagid(name)) self end # based on Tk::Iwidgets::Entryfield def clear tk_call(@path, 'clear') self end def delete(first, last=None) tk_send_without_enc('delete', first, last) self end def value _fromUTF8(tk_send_without_enc('get')) end def value= (val) tk_send_without_enc('delete', 0, 'end') tk_send_without_enc('insert', 0, _get_eval_enc_str(val)) val end alias get value alias set value= def cursor=(index) tk_send_without_enc('icursor', index) #self index end alias icursor cursor= def index(idx) number(tk_send_without_enc('index', idx)) end def insert(pos,text) tk_send_without_enc('insert', pos, _get_eval_enc_str(text)) self end def mark(pos) tk_send_without_enc('scan', 'mark', pos) self end def dragto(pos) tk_send_without_enc('scan', 'dragto', pos) self end def selection_adjust(index) tk_send_without_enc('selection', 'adjust', index) self end def selection_clear tk_send_without_enc('selection', 'clear') self end def selection_from(index) tk_send_without_enc('selection', 'from', index) self end def selection_present() bool(tk_send_without_enc('selection', 'present')) end def selection_range(s, e) tk_send_without_enc('selection', 'range', s, e) self end def selection_to(index) tk_send_without_enc('selection', 'to', index) self end def xview(*index) if index.size == 0 list(tk_send_without_enc('xview')) else tk_send_without_enc('xview', *index) self end end def xview_moveto(*index) xview('moveto', *index) end def xview_scroll(*index) xview('scroll', *index) end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/pushbutton.rb ================================================ # # tkextlib/iwidgets/pushbutton.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Pushbutton < Tk::Itk::Widget end end end class Tk::Iwidgets::Pushbutton TkCommandNames = ['::iwidgets::pushbutton'.freeze].freeze WidgetClassName = 'Pushbutton'.freeze WidgetClassNames[WidgetClassName] = self def __boolval_optkeys super() << 'defaultring' end private :__boolval_optkeys def invoke tk_call_without_enc(@path, 'invoke') self end def flash tk_call_without_enc(@path, 'flash') self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/radiobox.rb ================================================ # # tkextlib/iwidgets/radiobox.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Radiobox < Tk::Iwidgets::Labeledframe end end end class Tk::Iwidgets::Radiobox TkCommandNames = ['::iwidgets::radiobox'.freeze].freeze WidgetClassName = 'Radiobox'.freeze WidgetClassNames[WidgetClassName] = self #################################### include TkItemConfigMethod def __item_cget_cmd(id) [self.path, 'buttoncget', id] end private :__item_cget_cmd def __item_config_cmd(id) [self.path, 'buttonconfigure', id] end private :__item_config_cmd def __item_boolval_optkeys(id) super(id) << 'defaultring' end private :__item_boolval_optkeys def tagid(tagOrId) if tagOrId.kind_of?(Tk::Itk::Component) tagOrId.name else #_get_eval_string(tagOrId) tagOrId end end alias buttoncget itemcget alias buttoncget_strict itemcget_strict alias buttonconfigure itemconfigure alias buttonconfiginfo itemconfiginfo alias current_buttonconfiginfo current_itemconfiginfo private :itemcget, :itemcget_strict private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo #################################### def add(tag=nil, keys={}) if tag.kind_of?(Hash) keys = tag tag = nil end if tag tag = Tk::Itk::Component.new(self, tagid(tag)) else tag = Tk::Itk::Component.new(self) end tk_call(@path, 'add', tagid(tag), *hash_kv(keys)) tag end def delete(idx) tk_call(@path, 'delete', index(idx)) self end def deselect(idx) tk_call(@path, 'deselect', index(idx)) self end def flash(idx) tk_call(@path, 'flash', index(idx)) self end def get_tag ((tag = tk_call_without_enc(@path, 'get')).empty?)? nil: tag end alias get get_tag def get_obj (tag = get_tag)? Tk::Itk::Component.id2obj(self, tag): nil end def index(idx) number(tk_call(@path, 'index', tagid(idx))) end def insert(idx, tag=nil, keys={}) if tag.kind_of?(Hash) keys = tag tag = nil end if tag tag = Tk::Itk::Component.new(self, tagid(tag)) else tag = Tk::Itk::Component.new(self) end tk_call(@path, 'insert', index(idx), tagid(tag), *hash_kv(keys)) tag end def select(idx) tk_call(@path, 'select', index(idx)) self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/scopedobject.rb ================================================ # # tkextlib/iwidgets/buttonbox.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Scopedobject < TkObject end end end class Tk::Iwidgets::Scopedobject TkCommandNames = ['::iwidgets::scopedobject'.freeze].freeze WidgetClassName = 'Scopedobject'.freeze WidgetClassNames[WidgetClassName] = self def initialize(obj_name, keys={}) @path = tk_call(self.class::TkCommandNames[0], obj_name, *hash_kv(keys)) end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb ================================================ # # tkextlib/iwidgets/scrolledcanvas.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/canvas' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Scrolledcanvas < Tk::Iwidgets::Scrolledwidget end end end class Tk::Iwidgets::Scrolledcanvas TkCommandNames = ['::iwidgets::scrolledcanvas'.freeze].freeze WidgetClassName = 'Scrolledcanvas'.freeze WidgetClassNames[WidgetClassName] = self ################################ def __boolval_optkeys super() << 'autoresize' end private :__boolval_optkeys def __strval_optkeys super() << 'textbackground' end private :__strval_optkeys def initialize(*args) super(*args) @canvas = component_widget('canvas') end def method_missing(id, *args) if @canvas.respond_to?(id) @canvas.__send__(id, *args) else super(id, *args) end end ################################ def child_site window(tk_call(@path, 'childsite')) end def justify(dir) tk_call(@path, 'justify', dir) self end ########################## include TkCanvasItemConfig def tagid(tag) if tag.kind_of?(TkcItem) || tag.kind_of?(TkcTag) tag.id elsif tag.kind_of?(Tk::Itk::Component) tag.name else tag # maybe an Array of configure paramters end end private :tagid # create a canvas item without creating a TkcItem object def create(type, *args) type.create(self, *args) end ####################### def addtag(tag, mode, *args) tk_send_without_enc('addtag', tagid(tag), mode, *args) self end def addtag_above(tagOrId, target) addtag(tagOrId, 'above', tagid(target)) end def addtag_all(tagOrId) addtag(tagOrId, 'all') end def addtag_below(tagOrId, target) addtag(tagOrId, 'below', tagid(target)) end def addtag_closest(tagOrId, x, y, halo=None, start=None) addtag(tagOrId, 'closest', x, y, halo, start) end def addtag_enclosed(tagOrId, x1, y1, x2, y2) addtag(tagOrId, 'enclosed', x1, y1, x2, y2) end def addtag_overlapping(tagOrId, x1, y1, x2, y2) addtag(tagOrId, 'overlapping', x1, y1, x2, y2) end def addtag_withtag(tagOrId, tag) addtag(tagOrId, 'withtag', tagid(tag)) end def bbox(tagOrId, *tags) list(tk_send_without_enc('bbox', tagid(tagOrId), *tags.collect{|t| tagid(t)})) end #def itembind(tag, context, cmd=Proc.new, *args) # _bind([path, "bind", tagid(tag)], context, cmd, *args) # self #end def itembind(tag, context, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind([path, "bind", tagid(tag)], context, cmd, *args) self end #def itembind_append(tag, context, cmd=Proc.new, *args) # _bind_append([path, "bind", tagid(tag)], context, cmd, *args) # self #end def itembind_append(tag, context, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append([path, "bind", tagid(tag)], context, cmd, *args) self end def itembind_remove(tag, context) _bind_remove([path, "bind", tagid(tag)], context) self end def itembindinfo(tag, context=nil) _bindinfo([path, "bind", tagid(tag)], context) end def canvasx(screen_x, *args) #tk_tcl2ruby(tk_send_without_enc('canvasx', screen_x, *args)) number(tk_send_without_enc('canvasx', screen_x, *args)) end def canvasy(screen_y, *args) #tk_tcl2ruby(tk_send_without_enc('canvasy', screen_y, *args)) number(tk_send_without_enc('canvasy', screen_y, *args)) end def coords(tag, *args) if args == [] tk_split_list(tk_send_without_enc('coords', tagid(tag))) else tk_send_without_enc('coords', tagid(tag), *(args.flatten)) self end end def dchars(tag, first, last=None) tk_send_without_enc('dchars', tagid(tag), _get_eval_enc_str(first), _get_eval_enc_str(last)) self end def delete(*args) tbl = nil TkcItem::CItemID_TBL.mutex.synchronize{ tbl = TkcItem::CItemID_TBL[self.path] } if tbl find('withtag', *args).each{|item| if item.kind_of?(TkcItem) TkcItem::CItemID_TBL.mutex.synchronize{ tbl.delete(item.id) } end } end tk_send_without_enc('delete', *args.collect{|t| tagid(t)}) self end alias remove delete def dtag(tag, tag_to_del=None) tk_send_without_enc('dtag', tagid(tag), tag_to_del) self end def find(mode, *args) list(tk_send_without_enc('find', mode, *args)).collect!{|id| TkcItem.id2obj(self, id) } end def find_above(target) find('above', tagid(target)) end def find_all find('all') end def find_below(target) find('below', tagid(target)) end def find_closest(x, y, halo=None, start=None) find('closest', x, y, halo, start) end def find_enclosed(x1, y1, x2, y2) find('enclosed', x1, y1, x2, y2) end def find_overlapping(x1, y1, x2, y2) find('overlapping', x1, y1, x2, y2) end def find_withtag(tag) find('withtag', tag) end def itemfocus(tagOrId=nil) if tagOrId tk_send_without_enc('focus', tagid(tagOrId)) self else ret = tk_send_without_enc('focus') if ret == "" nil else TkcItem.id2obj(self, ret) end end end def gettags(tagOrId) list(tk_send_without_enc('gettags', tagid(tagOrId))).collect{|tag| TkcTag.id2obj(self, tag) } end def icursor(tagOrId, index) tk_send_without_enc('icursor', tagid(tagOrId), index) self end def index(tagOrId, idx) number(tk_send_without_enc('index', tagid(tagOrId), idx)) end def insert(tagOrId, index, string) tk_send_without_enc('insert', tagid(tagOrId), index, _get_eval_enc_str(string)) self end def lower(tag, below=nil) if below tk_send_without_enc('lower', tagid(tag), tagid(below)) else tk_send_without_enc('lower', tagid(tag)) end self end def move(tag, x, y) tk_send_without_enc('move', tagid(tag), x, y) self end def postscript(keys) tk_send("postscript", *hash_kv(keys)) end def raise(tag, above=nil) if above tk_send_without_enc('raise', tagid(tag), tagid(above)) else tk_send_without_enc('raise', tagid(tag)) end self end def scale(tag, x, y, xs, ys) tk_send_without_enc('scale', tagid(tag), x, y, xs, ys) self end def scan_mark(x, y) tk_send_without_enc('scan', 'mark', x, y) self end def scan_dragto(x, y) tk_send_without_enc('scan', 'dragto', x, y) self end def select(mode, *args) r = tk_send_without_enc('select', mode, *args) (mode == 'item')? TkcItem.id2obj(self, r): self end def select_adjust(tagOrId, index) select('adjust', tagid(tagOrId), index) end def select_clear select('clear') end def select_from(tagOrId, index) select('from', tagid(tagOrId), index) end def select_item select('item') end def select_to(tagOrId, index) select('to', tagid(tagOrId), index) end def itemtype(tag) TkcItem.type2class(tk_send('type', tagid(tag))) end def xview(*index) if index.size == 0 list(tk_send_without_enc('xview')) else tk_send_without_enc('xview', *index) self end end def xview_moveto(*index) xview('moveto', *index) end def xview_scroll(*index) xview('scroll', *index) end def yview(*index) if index.size == 0 list(tk_send_without_enc('yview')) else tk_send_without_enc('yview', *index) self end end def yview_moveto(*index) yview('moveto', *index) end def yview_scroll(*index) yview('scroll', *index) end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/scrolledframe.rb ================================================ # # tkextlib/iwidgets/scrolledframe.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Scrolledframe < Tk::Iwidgets::Scrolledwidget end end end class Tk::Iwidgets::Scrolledframe TkCommandNames = ['::iwidgets::scrolledframe'.freeze].freeze WidgetClassName = 'Scrolledframe'.freeze WidgetClassNames[WidgetClassName] = self def child_site window(tk_call(@path, 'childsite')) end def justify(dir) tk_call(@path, 'justify', dir) self end def xview(*index) if index.size == 0 list(tk_send_without_enc('xview')) else tk_send_without_enc('xview', *index) self end end def xview_moveto(*index) xview('moveto', *index) end def xview_scroll(*index) xview('scroll', *index) end def yview(*index) if index.size == 0 list(tk_send_without_enc('yview')) else tk_send_without_enc('yview', *index) self end end def yview_moveto(*index) yview('moveto', *index) end def yview_scroll(*index) yview('scroll', *index) end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/scrolledhtml.rb ================================================ # # tkextlib/iwidgets/scrolledhtml.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Scrolledhtml < Tk::Iwidgets::Scrolledtext end end end class Tk::Iwidgets::Scrolledhtml TkCommandNames = ['::iwidgets::scrolledhtml'.freeze].freeze WidgetClassName = 'Scrolledhtml'.freeze WidgetClassNames[WidgetClassName] = self def __boolval_optkeys super() << 'update' end private :__boolval_optkeys def __strval_optkeys super() << 'fontname' << 'link' << 'alink' << 'textbackground' end private :__strval_optkeys def __font_optkeys super() << 'fixedfont' end private :__font_optkeys def import(href) tk_call(@path, 'import', href) self end def import_link(href) tk_call(@path, 'import', '-link', href) self end def pwd tk_call(@path, 'pwd') end def render(htmltext, workdir=None) tk_call(@path, 'render', htmltext, workdir) self end def title tk_call(@path, 'title') end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/scrolledlistbox.rb ================================================ # # tkextlib/iwidgets/scrolledlistbox.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/listbox' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Scrolledlistbox < Tk::Iwidgets::Scrolledwidget end end end class Tk::Iwidgets::Scrolledlistbox TkCommandNames = ['::iwidgets::scrolledlistbox'.freeze].freeze WidgetClassName = 'Scrolledlistbox'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'textbackground' end private :__strval_optkeys def __tkvariable_optkeys super() << 'listvariable' end private :__tkvariable_optkeys def __font_optkeys super() << 'textfont' end private :__font_optkeys ################################ def initialize(*args) super(*args) @listbox = component_widget('listbox') end def method_missing(id, *args) if @listbox.respond_to?(id) @listbox.__send__(id, *args) else super(id, *args) end end ################################ def clear tk_call(@path, 'clear') self end def get_curselection tk_call(@path, 'getcurselection') end def justify(dir) tk_call(@path, 'justify', dir) self end def selected_item_count number(tk_call(@path, 'selecteditemcount')) end def sort(*params, &b) # see 'lsort' man page about params if b tk_call(@path, 'sort', '-command', proc(&b), *params) else tk_call(@path, 'sort', *params) end self end def sort_ascending tk_call(@path, 'sort', 'ascending') self end def sort_descending tk_call(@path, 'sort', 'descending') self end ##################################### def bbox(index) list(tk_send_without_enc('bbox', index)) end def delete(first, last=None) tk_send_without_enc('delete', first, last) self end def get(*index) _fromUTF8(tk_send_without_enc('get', *index)) end def insert(index, *args) tk_send('insert', index, *args) self end def scan_mark(x, y) tk_send_without_enc('scan', 'mark', x, y) self end def scan_dragto(x, y) tk_send_without_enc('scan', 'dragto', x, y) self end def see(index) tk_send_without_enc('see', index) self end ##################################### include TkListItemConfig def tagid(tag) if tag.kind_of?(Tk::Itk::Component) tag.name else super(tag) end end private :tagid ##################################### def activate(y) tk_send_without_enc('activate', y) self end def curselection list(tk_send_without_enc('curselection')) end def get(first, last=nil) if last # tk_split_simplelist(_fromUTF8(tk_send_without_enc('get', first, last))) tk_split_simplelist(tk_send_without_enc('get', first, last), false, true) else _fromUTF8(tk_send_without_enc('get', first)) end end def nearest(y) tk_send_without_enc('nearest', y).to_i end def size tk_send_without_enc('size').to_i end def selection_anchor(index) tk_send_without_enc('selection', 'anchor', index) self end def selection_clear(first, last=None) tk_send_without_enc('selection', 'clear', first, last) self end def selection_includes(index) bool(tk_send_without_enc('selection', 'includes', index)) end def selection_set(first, last=None) tk_send_without_enc('selection', 'set', first, last) self end def index(idx) tk_send_without_enc('index', idx).to_i end ##################################### def xview(*index) if index.size == 0 list(tk_send_without_enc('xview')) else tk_send_without_enc('xview', *index) self end end def xview_moveto(*index) xview('moveto', *index) end def xview_scroll(*index) xview('scroll', *index) end def yview(*index) if index.size == 0 list(tk_send_without_enc('yview')) else tk_send_without_enc('yview', *index) self end end def yview_moveto(*index) yview('moveto', *index) end def yview_scroll(*index) yview('scroll', *index) end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/scrolledtext.rb ================================================ # # tkextlib/iwidgets/scrolledtext.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/text' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Scrolledtext < Tk::Iwidgets::Scrolledwidget end end end class Tk::Iwidgets::Scrolledtext TkCommandNames = ['::iwidgets::scrolledtext'.freeze].freeze WidgetClassName = 'Scrolledtext'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'textbackground' end private :__strval_optkeys def __font_optkeys super() << 'textfont' end private :__font_optkeys ################################ def initialize(*args) super(*args) @text = component_widget('text') end def method_missing(id, *args) if @text.respond_to?(id) @text.__send__(id, *args) else super(id, *args) end end ################################ def child_site window(tk_call(@path, 'childsite')) end def clear tk_call(@path, 'clear') self end def import(file, idx=nil) if idx tk_call(@path, 'import', file, index(idx)) else tk_call(@path, 'import', file) end self end def export(file) tk_call(@path, 'export', file) self end ##################################### include TkTextTagConfig def tagid(tag) if tag.kind_of?(Tk::Itk::Component) tag.name else super(tag) end end private :tagid def bbox(index) list(tk_send('bbox', index)) end def compare(idx1, op, idx2) bool(tk_send_without_enc('compare', _get_eval_enc_str(idx1), op, _get_eval_enc_str(idx2))) end def debug bool(tk_send_without_enc('debug')) end def debug=(boolean) tk_send_without_enc('debug', boolean) #self boolean end def delete(first, last=None) tk_send_without_enc('delete', first, last) self end def dlineinfo(index) list(tk_send_without_enc('dlineinfo', _get_eval_enc_str(index))) end def get(*index) _fromUTF8(tk_send_without_enc('get', *index)) end def get_displaychars(*index) # Tk8.5 feature get('-displaychars', *index) end def image_cget_strict(index, slot) case slot.to_s when 'text', 'label', 'show', 'data', 'file' _fromUTF8(tk_send_without_enc('image', 'cget', _get_eval_enc_str(index), "-#{slot}")) else tk_tcl2ruby(_fromUTF8(tk_send_without_enc('image', 'cget', _get_eval_enc_str(index), "-#{slot}"))) end end def image_cget(index, slot) unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ image_cget_strict(index, slot) else begin image_cget_strict(index, slot) rescue => e begin if current_image_configinfo.has_key?(slot.to_s) # error on known option fail e else # unknown option nil end rescue fail e # tag error end end end end def image_configure(index, slot, value=None) if slot.kind_of? Hash _fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), *hash_kv(slot, true))) else _fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}", _get_eval_enc_str(value))) end self end def image_configinfo(index, slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if slot case slot.to_s when 'text', 'label', 'show', 'data', 'file' #conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"))) conf = tk_split_simplelist(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"), false, true) else #conf = tk_split_list(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"))) conf = tk_split_list(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"), 0, false, true) end conf[0] = conf[0][1..-1] conf else #tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index)))).collect{|conflist| # conf = tk_split_simplelist(conflist) tk_split_simplelist(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index)), false, false).collect{|conflist| conf = tk_split_simplelist(conflist, false, true) conf[0] = conf[0][1..-1] case conf[0] when 'text', 'label', 'show', 'data', 'file' else if conf[3] if conf[3].index('{') conf[3] = tk_split_list(conf[3]) else conf[3] = tk_tcl2ruby(conf[3]) end end if conf[4] if conf[4].index('{') conf[4] = tk_split_list(conf[4]) else conf[4] = tk_tcl2ruby(conf[4]) end end end conf[1] = conf[1][1..-1] if conf.size == 2 # alias info conf } end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY if slot case slot.to_s when 'text', 'label', 'show', 'data', 'file' #conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"))) conf = tk_split_simplelist(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"), false, true) else #conf = tk_split_list(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"))) conf = tk_split_list(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"), 0, false, true) end key = conf.shift[1..-1] { key => conf } else ret = {} #tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index)))).each{|conflist| # conf = tk_split_simplelist(conflist) tk_split_simplelist(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index)), false, false).each{|conflist| conf = tk_split_simplelist(conflist, false, true) key = conf.shift[1..-1] case key when 'text', 'label', 'show', 'data', 'file' else if conf[2] if conf[2].index('{') conf[2] = tk_split_list(conf[2]) else conf[2] = tk_tcl2ruby(conf[2]) end end if conf[3] if conf[3].index('{') conf[3] = tk_split_list(conf[3]) else conf[3] = tk_tcl2ruby(conf[3]) end end end if conf.size == 1 ret[key] = conf[0][1..-1] # alias info else ret[key] = conf end } ret end end end def current_image_configinfo(index, slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if slot conf = image_configinfo(index, slot) {conf[0] => conf[4]} else ret = {} image_configinfo(index).each{|conf| ret[conf[0]] = conf[4] if conf.size > 2 } ret end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY ret = {} image_configinfo(index, slot).each{|k, conf| ret[k] = conf[-1] if conf.kind_of?(Array) } ret end end def image_names #tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'names'))).collect{|elt| tk_split_simplelist(tk_send_without_enc('image', 'names'), false, true).collect{|elt| tagid2obj(elt) } end def index(idx) tk_send_without_enc('index', _get_eval_enc_str(idx)) end def insert(index, *args) tk_send('insert', index, *args) self end def mark_names #tk_split_simplelist(_fromUTF8(tk_send_without_enc('mark', 'names'))).collect{|elt| tk_split_simplelist(tk_send_without_enc('mark', 'names'), false, true).collect{|elt| tagid2obj(elt) } end def mark_gravity(mark, direction=nil) if direction tk_send_without_enc('mark', 'gravity', _get_eval_enc_str(mark), direction) self else tk_send_without_enc('mark', 'gravity', _get_eval_enc_str(mark)) end end def mark_set(mark, index) tk_send_without_enc('mark', 'set', _get_eval_enc_str(mark), _get_eval_enc_str(index)) self end alias set_mark mark_set def mark_unset(*marks) tk_send_without_enc('mark', 'unset', *(marks.collect{|mark| _get_eval_enc_str(mark)})) self end alias unset_mark mark_unset def mark_next(index) tagid2obj(_fromUTF8(tk_send_without_enc('mark', 'next', _get_eval_enc_str(index)))) end alias next_mark mark_next def mark_previous(index) tagid2obj(_fromUTF8(tk_send_without_enc('mark', 'previous', _get_eval_enc_str(index)))) end alias previous_mark mark_previous def scan_mark(x, y) tk_send_without_enc('scan', 'mark', x, y) self end def scan_dragto(x, y) tk_send_without_enc('scan', 'dragto', x, y) self end def _ktext_length(txt) if TkCore::WITH_ENCODING ### Ruby 1.9 !!!!!!!!!!!!! return txt.length end ########################### if $KCODE !~ /n/i return txt.gsub(/[^\Wa-zA-Z_\d]/, ' ').length end # $KCODE == 'NONE' if JAPANIZED_TK tk_call_without_enc('kstring', 'length', _get_eval_enc_str(txt)).to_i else begin tk_call_without_enc('encoding', 'convertto', 'ascii', _get_eval_enc_str(txt)).length rescue StandardError, NameError # sorry, I have no plan txt.length end end end private :_ktext_length def tksearch(*args) # call 'search' subcommand of text widget # args ::= [] [] # If is regexp, then it must be a regular expression of Tcl if args[0].kind_of?(Array) opts = args.shift.collect{|opt| '-' + opt.to_s } else opts = [] end opts << '--' ret = tk_send('search', *(opts + args)) if ret == "" nil else ret end end def tksearch_with_count(*args) # call 'search' subcommand of text widget # args ::= [] [] # If is regexp, then it must be a regular expression of Tcl if args[0].kind_of?(Array) opts = args.shift.collect{|opt| '-' + opt.to_s } else opts = [] end opts << '-count' << args.shift << '--' ret = tk_send('search', *(opts + args)) if ret == "" nil else ret end end def search_with_length(pat,start,stop=None) pat = pat.chr if pat.kind_of? Integer if stop != None return ["", 0] if compare(start,'>=',stop) txt = get(start,stop) if (pos = txt.index(pat)) match = $& #pos = txt[0..(pos-1)].split('').length if pos > 0 pos = _ktext_length(txt[0..(pos-1)]) if pos > 0 if pat.kind_of? String #return [index(start + " + #{pos} chars"), pat.split('').length] return [index(start + " + #{pos} chars"), _ktext_length(pat), pat.dup] else #return [index(start + " + #{pos} chars"), $&.split('').length] return [index(start + " + #{pos} chars"), _ktext_length(match), match] end else return ["", 0] end else txt = get(start,'end - 1 char') if (pos = txt.index(pat)) match = $& #pos = txt[0..(pos-1)].split('').length if pos > 0 pos = _ktext_length(txt[0..(pos-1)]) if pos > 0 if pat.kind_of? String #return [index(start + " + #{pos} chars"), pat.split('').length] return [index(start + " + #{pos} chars"), _ktext_length(pat), pat.dup] else #return [index(start + " + #{pos} chars"), $&.split('').length] return [index(start + " + #{pos} chars"), _ktext_length(match), match] end else txt = get('1.0','end - 1 char') if (pos = txt.index(pat)) match = $& #pos = txt[0..(pos-1)].split('').length if pos > 0 pos = _ktext_length(txt[0..(pos-1)]) if pos > 0 if pat.kind_of? String #return [index("1.0 + #{pos} chars"), pat.split('').length] return [index("1.0 + #{pos} chars"), _ktext_length(pat), pat.dup] else #return [index("1.0 + #{pos} chars"), $&.split('').length] return [index("1.0 + #{pos} chars"), _ktext_length(match), match] end else return ["", 0] end end end end def search(pat,start,stop=None) search_with_length(pat,start,stop)[0] end def rsearch_with_length(pat,start,stop=None) pat = pat.chr if pat.kind_of? Integer if stop != None return ["", 0] if compare(start,'<=',stop) txt = get(stop,start) if (pos = txt.rindex(pat)) match = $& #pos = txt[0..(pos-1)].split('').length if pos > 0 pos = _ktext_length(txt[0..(pos-1)]) if pos > 0 if pat.kind_of? String #return [index(stop + " + #{pos} chars"), pat.split('').length] return [index(stop + " + #{pos} chars"), _ktext_length(pat), pat.dup] else #return [index(stop + " + #{pos} chars"), $&.split('').length] return [index(stop + " + #{pos} chars"), _ktext_length(match), match] end else return ["", 0] end else txt = get('1.0',start) if (pos = txt.rindex(pat)) match = $& #pos = txt[0..(pos-1)].split('').length if pos > 0 pos = _ktext_length(txt[0..(pos-1)]) if pos > 0 if pat.kind_of? String #return [index("1.0 + #{pos} chars"), pat.split('').length] return [index("1.0 + #{pos} chars"), _ktext_length(pat), pat.dup] else #return [index("1.0 + #{pos} chars"), $&.split('').length] return [index("1.0 + #{pos} chars"), _ktext_length(match), match] end else txt = get('1.0','end - 1 char') if (pos = txt.rindex(pat)) match = $& #pos = txt[0..(pos-1)].split('').length if pos > 0 pos = _ktext_length(txt[0..(pos-1)]) if pos > 0 if pat.kind_of? String #return [index("1.0 + #{pos} chars"), pat.split('').length] return [index("1.0 + #{pos} chars"), _ktext_length(pat), pat.dup] else #return [index("1.0 + #{pos} chars"), $&.split('').length] return [index("1.0 + #{pos} chars"), _ktext_length(match), match] end else return ["", 0] end end end end def rsearch(pat,start,stop=None) rsearch_with_length(pat,start,stop)[0] end def see(index) tk_send_without_enc('see', index) self end ############################### def xview(*index) if index.size == 0 list(tk_send_without_enc('xview')) else tk_send_without_enc('xview', *index) self end end def xview_moveto(*index) xview('moveto', *index) end def xview_scroll(*index) xview('scroll', *index) end def yview(*index) if index.size == 0 list(tk_send_without_enc('yview')) else tk_send_without_enc('yview', *index) self end end def yview_moveto(*index) yview('moveto', *index) end def yview_scroll(*index) yview('scroll', *index) end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/scrolledwidget.rb ================================================ # # tkextlib/iwidgets/scrolledwidget.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Scrolledwidget < Tk::Iwidgets::Labeledwidget end end end class Tk::Iwidgets::Scrolledwidget TkCommandNames = ['::iwidgets::scrolledwidget'.freeze].freeze WidgetClassName = 'Scrolledwidget'.freeze WidgetClassNames[WidgetClassName] = self end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/selectionbox.rb ================================================ # # tkextlib/iwidgets/selectionbox.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Selectionbox < Tk::Itk::Widget end end end class Tk::Iwidgets::Selectionbox TkCommandNames = ['::iwidgets::selectionbox'.freeze].freeze WidgetClassName = 'Selectionbox'.freeze WidgetClassNames[WidgetClassName] = self def __boolval_optkeys super() << 'itemson' << 'selectionon' end private :__boolval_optkeys def __strval_optkeys super() << 'itemslabel' << 'selectionlabel' end private :__strval_optkeys def child_site window(tk_call(@path, 'childsite')) end def clear_items tk_call(@path, 'clear', 'items') self end def clear_selection tk_call(@path, 'clear', 'selection') self end def get tk_call(@path, 'get') end def insert_items(idx, *args) tk_call(@path, 'insert', 'items', idx, *args) end def insert_selection(pos, text) tk_call(@path, 'insert', 'selection', pos, text) end def select_item tk_call(@path, 'selectitem') self end # based on Tk::Listbox ( and TkTextWin ) def curselection list(tk_send_without_enc('curselection')) end def delete(first, last=None) tk_send_without_enc('delete', first, last) self end def index(idx) tk_send_without_enc('index', idx).to_i end def nearest(y) tk_send_without_enc('nearest', y).to_i end def scan_mark(x, y) tk_send_without_enc('scan', 'mark', x, y) self end def scan_dragto(x, y) tk_send_without_enc('scan', 'dragto', x, y) self end def selection_anchor(index) tk_send_without_enc('selection', 'anchor', index) self end def selection_clear(first, last=None) tk_send_without_enc('selection', 'clear', first, last) self end def selection_includes(index) bool(tk_send_without_enc('selection', 'includes', index)) end def selection_set(first, last=None) tk_send_without_enc('selection', 'set', first, last) self end def size tk_send_without_enc('size').to_i end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/selectiondialog.rb ================================================ # # tkextlib/iwidgets/selectiondialog.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Selectiondialog < Tk::Iwidgets::Dialog end end end class Tk::Iwidgets::Selectiondialog TkCommandNames = ['::iwidgets::selectiondialog'.freeze].freeze WidgetClassName = 'Selectiondialog'.freeze WidgetClassNames[WidgetClassName] = self def child_site window(tk_call(@path, 'childsite')) end def clear_items tk_call(@path, 'clear', 'items') self end def clear_selection tk_call(@path, 'clear', 'selection') self end def get tk_call(@path, 'get') end def insert_items(idx, *args) tk_call(@path, 'insert', 'items', idx, *args) end def insert_selection(pos, text) tk_call(@path, 'insert', 'selection', pos, text) end def select_item tk_call(@path, 'selectitem') self end # based on Tk::Listbox ( and TkTextWin ) def curselection list(tk_send_without_enc('curselection')) end def delete(first, last=None) tk_send_without_enc('delete', first, last) self end def index(idx) tk_send_without_enc('index', idx).to_i end def nearest(y) tk_send_without_enc('nearest', y).to_i end def scan_mark(x, y) tk_send_without_enc('scan', 'mark', x, y) self end def scan_dragto(x, y) tk_send_without_enc('scan', 'dragto', x, y) self end def selection_anchor(index) tk_send_without_enc('selection', 'anchor', index) self end def selection_clear(first, last=None) tk_send_without_enc('selection', 'clear', first, last) self end def selection_includes(index) bool(tk_send_without_enc('selection', 'includes', index)) end def selection_set(first, last=None) tk_send_without_enc('selection', 'set', first, last) self end def size tk_send_without_enc('size').to_i end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/setup.rb ================================================ # # setup.rb -- setup script before calling TkPackage.require() # # If you need some setup operations (for example, add a library path # to the library search path) before using Tcl/Tk library packages # wrapped by Ruby scripts in this directory, please write the setup # operations in this file. # ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/shell.rb ================================================ # # tkextlib/iwidgets/shell.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Shell < Tk::Itk::Toplevel end end end class Tk::Iwidgets::Shell TkCommandNames = ['::iwidgets::shell'.freeze].freeze WidgetClassName = 'Shell'.freeze WidgetClassNames[WidgetClassName] = self def activate tk_call(@path, 'activate') # may return val of deactibate method end def center(win=None) tk_call(@path, 'center', win) self end def child_site window(tk_call(@path, 'childsite')) end def deactivate(val=None) tk_call(@path, 'deactivate', val) self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/spindate.rb ================================================ # # tkextlib/iwidgets/spindate.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Spindate < Tk::Itk::Widget end end end class Tk::Iwidgets::Spindate TkCommandNames = ['::iwidgets::spindate'.freeze].freeze WidgetClassName = 'Spindate'.freeze WidgetClassNames[WidgetClassName] = self def __boolval_optkeys super() << 'dayon' << 'monthon' << 'yearon' end private :__boolval_optkeys def __strval_optkeys super() << 'daylabel' << 'monthformat' << 'monthlabel' << 'yearlabel' end private :__strval_optkeys def get_string tk_call(@path, 'get', '-string') end alias get get_string def get_clicks number(tk_call(@path, 'get', '-clicks')) end def show(date=None) tk_call(@path, 'show', date) self end def show_now tk_call(@path, 'show', 'now') self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/spinint.rb ================================================ # # tkextlib/iwidgets/spinint.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Spinint < Tk::Iwidgets::Spinner end end end class Tk::Iwidgets::Spinint TkCommandNames = ['::iwidgets::spinint'.freeze].freeze WidgetClassName = 'Spinint'.freeze WidgetClassNames[WidgetClassName] = self def __boolval_optkeys super() << 'wrap' end private :__boolval_optkeys def __numlistval_optkeys super() << 'range' end private :__numlistval_optkeys end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/spinner.rb ================================================ # # tkextlib/iwidgets/spinner.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Spinner < Tk::Iwidgets::Labeledwidget end end end class Tk::Iwidgets::Spinner TkCommandNames = ['::iwidgets::spinner'.freeze].freeze WidgetClassName = 'Spinner'.freeze WidgetClassNames[WidgetClassName] = self #################################### include Tk::ValidateConfigure class EntryfieldValidate < TkValidateCommand #class CalCmdArgs < TkUtil::CallbackSubst class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [ ?c, ?s, :char ], [ ?P, ?s, :post ], [ ?S, ?s, :current ], [ ?W, ?w, :widget ], nil ] PROC_TBL = [ [ ?s, TkComm.method(:string) ], [ ?w, TkComm.method(:window) ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end _setup_subst_table(KEY_TBL, PROC_TBL); end def self._config_keys ['validate', 'invalid'] end end def __validation_class_list super() << EntryfieldValidate end Tk::ValidateConfigure.__def_validcmd(binding, EntryfieldValidate) #################################### def up tk_call_without_enc(@path, 'up') self end def down tk_call_without_enc(@path, 'down') self end def clear tk_call_without_enc(@path, 'clear') self end def delete(first, last=None) tk_send_without_enc('delete', first, last) self end def value _fromUTF8(tk_send_without_enc('get')) end def value= (val) tk_send_without_enc('delete', 0, 'end') tk_send_without_enc('insert', 0, _get_eval_enc_str(val)) val end alias get value alias set value= def cursor=(index) tk_send_without_enc('icursor', index) #self index end alias icursor cursor= def index(idx) number(tk_send_without_enc('index', idx)) end def insert(pos,text) tk_send_without_enc('insert', pos, _get_eval_enc_str(text)) self end def mark(pos) tk_send_without_enc('scan', 'mark', pos) self end def dragto(pos) tk_send_without_enc('scan', 'dragto', pos) self end def selection_adjust(index) tk_send_without_enc('selection', 'adjust', index) self end def selection_clear tk_send_without_enc('selection', 'clear') self end def selection_from(index) tk_send_without_enc('selection', 'from', index) self end def selection_present() bool(tk_send_without_enc('selection', 'present')) end def selection_range(s, e) tk_send_without_enc('selection', 'range', s, e) self end def selection_to(index) tk_send_without_enc('selection', 'to', index) self end # based on tk/scrollable.rb def xview(*index) if index.size == 0 list(tk_send_without_enc('xview')) else tk_send_without_enc('xview', *index) self end end def xview_moveto(*index) xview('moveto', *index) end def xview_scroll(*index) xview('scroll', *index) end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/spintime.rb ================================================ # # tkextlib/iwidgets/spintime.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Spintime < Tk::Itk::Widget end end end class Tk::Iwidgets::Spintime TkCommandNames = ['::iwidgets::spintime'.freeze].freeze WidgetClassName = 'Spintime'.freeze WidgetClassNames[WidgetClassName] = self def __boolval_optkeys super() << 'houron' << 'militaryon' << 'minutelabel' << 'secondlabel' end private :__boolval_optkeys def __strval_optkeys super() << 'hourlabel' << 'minuteon' << 'secondon' end private :__strval_optkeys def get_string tk_call(@path, 'get', '-string') end alias get get_string def get_clicks number(tk_call(@path, 'get', '-clicks')) end def show(date=None) tk_call(@path, 'show', date) self end def show_now tk_call(@path, 'show', 'now') self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/tabnotebook.rb ================================================ # # tkextlib/iwidgets/tabnotebook.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Tabnotebook < Tk::Itk::Widget end end end class Tk::Iwidgets::Tabnotebook TkCommandNames = ['::iwidgets::tabnotebook'.freeze].freeze WidgetClassName = 'Tabnotebook'.freeze WidgetClassNames[WidgetClassName] = self #################################### include TkItemConfigMethod def __item_cget_cmd(id) [self.path, 'pagecget', id] end private :__item_cget_cmd def __item_config_cmd(id) [self.path, 'pageconfigure', id] end private :__item_config_cmd def __item_strval_optkeys(id) super(id) << 'tabbackground' << 'tabforeground' end private :__item_strval_optkeys def tagid(tagOrId) if tagOrId.kind_of?(Tk::Itk::Component) tagOrId.name else #_get_eval_string(tagOrId) tagOrId end end alias pagecget itemcget alias pagecget_strict itemcget_strict alias pageconfigure itemconfigure alias pageconfiginfo itemconfiginfo alias current_pageconfiginfo current_itemconfiginfo private :itemcget, :itemcget_strict private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo #################################### def __boolval_optkeys super() << 'auto' << 'equaltabs' << 'raiseselect' << 'tabborders' end private :__boolval_optkeys def __strval_optkeys super() << 'backdrop' << 'tabbackground' << 'tabforeground' end private :__strval_optkeys def initialize(*args) super(*args) @tabset = self.component_widget('tabset') end def add(keys={}) window(tk_call(@path, 'add', *hash_kv(keys))) end def child_site_list list(tk_call(@path, 'childsite')) end def child_site(idx) window(tk_call(@path, 'childsite', index(idx))) end def delete(idx1, idx2=nil) if idx2 tk_call(@path, 'delete', index(idx1), index(idx2)) else tk_call(@path, 'delete', index(idx1)) end self end def index(idx) #number(tk_call(@path, 'index', tagid(idx))) @tabset.index(tagid(idx)) end def insert(idx, keys={}) window(tk_call(@path, 'insert', index(idx), *hash_kv(keys))) end def next tk_call(@path, 'next') self end def prev tk_call(@path, 'prev') self end def select(idx) tk_call(@path, 'select', index(idx)) self end def show_tab(idx) @tabset.show_tab(idx) self end def scrollcommand(cmd=Proc.new) configure_cmd 'scrollcommand', cmd self end alias xscrollcommand scrollcommand alias yscrollcommand scrollcommand def xscrollbar(bar=nil) if bar @scrollbar = bar @scrollbar.orient 'horizontal' self.scrollcommand {|*arg| @scrollbar.set(*arg)} @scrollbar.command {|*arg| self.xview(*arg)} Tk.update # avoid scrollbar trouble end @scrollbar end def yscrollbar(bar=nil) if bar @scrollbar = bar @scrollbar.orient 'vertical' self.scrollcommand {|*arg| @scrollbar.set(*arg)} @scrollbar.command {|*arg| self.yview(*arg)} Tk.update # avoid scrollbar trouble end @scrollbar end alias scrollbar yscrollbar def view(*index) if index.size == 0 idx = num_or_str(tk_send_without_enc('view')) if idx.kind_of?(Fixnum) && idx < 0 nil else idx end else tk_send_without_enc('view', *index) self end end alias xview view alias yview view def view_moveto(*index) view('moveto', *index) end alias xview_moveto view_moveto alias yview_moveto view_moveto def view_scroll(index, what='pages') view('scroll', index, what) end alias xview_scroll view_scroll alias yview_scroll view_scroll end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/tabset.rb ================================================ # # tkextlib/iwidgets/tabset.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Tabset < Tk::Itk::Widget end end end class Tk::Iwidgets::Tabset TkCommandNames = ['::iwidgets::tabset'.freeze].freeze WidgetClassName = 'Tabset'.freeze WidgetClassNames[WidgetClassName] = self #################################### include TkItemConfigMethod def __item_cget_cmd(id) [self.path, 'tabcget', id] end private :__item_cget_cmd def __item_config_cmd(id) [self.path, 'tabconfigure', id] end private :__item_config_cmd def tagid(tagOrId) if tagOrId.kind_of?(Tk::Itk::Component) tagOrId.name else #_get_eval_string(tagOrId) tagOrId end end alias tabcget itemcget alias tabcget_strict itemcget_strict alias tabconfigure itemconfigure alias tabconfiginfo itemconfiginfo alias current_tabconfiginfo current_itemconfiginfo private :itemcget, :itemcget_strict private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo #################################### def __boolval_optkeys super() << 'equaltabs' << 'raiseselect' << 'tabborders' end private :__boolval_optkeys def __strval_optkeys super() << 'backdrop' end private :__strval_optkeys def add(keys={}) window(tk_call(@path, 'add', *hash_kv(keys))) end def delete(idx1, idx2=nil) if idx2 tk_call(@path, 'delete', index(idx1), index(idx2)) else tk_call(@path, 'delete', index(idx1)) end self end def index(idx) number(tk_call(@path, 'index', tagid(idx))) end def insert(idx, keys={}) window(tk_call(@path, 'insert', index(idx), *hash_kv(keys))) end def next tk_call(@path, 'next') self end def prev tk_call(@path, 'prev') self end def select(idx) tk_call(@path, 'select', index(idx)) self end def show_tab(idx) if index(idx) == 0 self.start = 0 return end reutrn unless @canvas ||= self.winfo_children[0] delta = 1 if (delta = cget(:gap)) == 'overlap' || (delta = self.winfo_pixels(delta) + 1) <= 0 case cget(:tabpos) when 's', 'n' if (head = tabcget(idx, :left)) < 0 self.start -= head return end tabs_size = @canvas.winfo_width tab_start, tab_end = @canvas . find_overlapping(head, 0, head + delta, @canvas.winfo_height) . find_all{|id| @canvas.itemtype(id) == TkcPolygon} . map!{|id| bbox = @canvas.bbox(id); [bbox[0], bbox[2]]} . max when 'e', 'w' if (head = tabcget(idx, :top)) < 0 self.start -= head return end tabs_size = @canvas.winfo_height tab_start, tab_end = @canvas . find_overlapping(0, head, @canvas.winfo_width, head + delta) . find_all{|id| @canvas.itemtype(id) == TkcPolygon} . map!{|id| bbox = @canvas.bbox(id); [bbox[1], bbox[3]]} . max end if (size = tab_end - tab_start + 1) > tabs_size self.start -= tab_start elsif head + size > tabs_size self.start -= head + size - tabs_size end self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/timeentry.rb ================================================ # # tkextlib/iwidgets/timeentry.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Timeentry < Tk::Iwidgets::Timefield end end end class Tk::Iwidgets::Timeentry TkCommandNames = ['::iwidgets::timeentry'.freeze].freeze WidgetClassName = 'Timeentry'.freeze WidgetClassNames[WidgetClassName] = self def __strval_optkeys super() << 'closetext' end private :__strval_optkeys end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/timefield.rb ================================================ # # tkextlib/iwidgets/timefield.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Timefield < Tk::Iwidgets::Labeledwidget end end end class Tk::Iwidgets::Timefield TkCommandNames = ['::iwidgets::timefield'.freeze].freeze WidgetClassName = 'Timefield'.freeze WidgetClassNames[WidgetClassName] = self def __boolval_optkeys super() << 'gmt' end private :__boolval_optkeys def __strval_optkeys super() << 'textbackground' end private :__strval_optkeys def __font_optkeys super() << 'textfont' end private :__font_optkeys def get_string tk_call(@path, 'get', '-string') end alias get get_string def get_clicks number(tk_call(@path, 'get', '-clicks')) end def valid? bool(tk_call(@path, 'isvalid')) end alias isvalid? valid? def show(time=None) tk_call(@path, 'show', time) self end def show_now tk_call(@path, 'show', 'now') self end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/toolbar.rb ================================================ # # tkextlib/iwidgets/toolbar.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Toolbar < Tk::Itk::Widget end end end class Tk::Iwidgets::Toolbar TkCommandNames = ['::iwidgets::toolbar'.freeze].freeze WidgetClassName = 'Toolbar'.freeze WidgetClassNames[WidgetClassName] = self def __tkvariable_optkeys super() << 'helpvariable' end private :__tkvariable_optkeys #################################### include TkItemConfigMethod def __item_cget_cmd(id) [self.path, 'itemcget', self.index(id)] end private :__item_cget_cmd def __item_config_cmd(id) [self.path, 'itemconfigure', self.index(id)] end private :__item_config_cmd def __item_strval_optkeys(id) super(id) << 'helpstr' << 'balloonstr' end private :__item_strval_optkeys def tagid(tagOrId) if tagOrId.kind_of?(Tk::Itk::Component) tagOrId.name else #_get_eval_string(tagOrId) tagOrId end end #################################### def __strval_optkeys super() << 'balloonbackground' << 'balloonforeground' end private :__strval_optkeys def __tkvariable_optkeys super() << 'helpvariable' end private :__tkvariable_optkeys def __font_optkeys super() << 'balloonfont' end private :__font_optkeys def add(type, tag=nil, keys={}) if tag.kind_of?(Hash) keys = tag tag = nil end if tag tag = Tk::Itk::Component.new(self, tagid(tag)) else tag = Tk::Itk::Component.new(self) end window(tk_call(@path, 'add', type, tagid(tag), *hash_kv(keys))) tag end def delete(idx1, idx2=nil) if idx2 tk_call(@path, 'delete', index(idx1), index(idx2)) else tk_call(@path, 'delete', index(idx1)) end self end def index(idx) number(tk_call(@path, 'index', tagid(idx))) end def insert(idx, type, tag=nil, keys={}) if tag.kind_of?(Hash) keys = tag tag = nil end if tag tag = Tk::Itk::Component.new(self, tagid(tag)) else tag = Tk::Itk::Component.new(self) end window(tk_call(@path, 'insert', index(idx), type, tagid(tag), *hash_kv(keys))) tag end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets/watch.rb ================================================ # # tkextlib/iwidgets/watch.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/iwidgets.rb' module Tk module Iwidgets class Watch < Tk::Itk::Widget end end end class Tk::Iwidgets::Watch TkCommandNames = ['::iwidgets::watch'.freeze].freeze WidgetClassName = 'Watch'.freeze WidgetClassNames[WidgetClassName] = self def __boolval_optkeys super() << 'showampm' end private :__boolval_optkeys def __strval_optkeys super() << 'clockcolor' << 'hourcolor' << 'minutecolor' << 'pivotcolor' << 'secondcolor' << 'tickcolor' end private :__strval_optkeys def get_string tk_call(@path, 'get', '-string') end alias get get_string def get_clicks number(tk_call(@path, 'get', '-clicks')) end def show(time=None) tk_call(@path, 'show', time) self end def show_now tk_call(@path, 'show', 'now') self end def watch(*args) unless args.empty? tk_call(@path, 'watch', *args) end component_path('canvas') end end ================================================ FILE: ext/tk/lib/tkextlib/iwidgets.rb ================================================ # # [incr Widgets] support # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/itcl' require 'tkextlib/itk' # call setup script for general 'tkextlib' libraries #require 'tkextlib/setup.rb' # call setup script #require 'tkextlib/iwidgets/setup.rb' # load all image format handlers #TkPackage.require('Iwidgets', '4.0') TkPackage.require('Iwidgets') module Tk module Iwidgets TkComm::TkExtlibAutoloadModule.unshift(self) extend TkCore PACKAGE_NAME = 'Iwidgets'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('Iwidgets') rescue '' end end #################################################### autoload :Buttonbox, 'tkextlib/iwidgets/buttonbox' autoload :Calendar, 'tkextlib/iwidgets/calendar' autoload :Canvasprintbox, 'tkextlib/iwidgets/canvasprintbox' autoload :Canvasprintdialog, 'tkextlib/iwidgets/canvasprintdialog' autoload :Checkbox, 'tkextlib/iwidgets/checkbox' autoload :Combobox, 'tkextlib/iwidgets/combobox' autoload :Dateentry, 'tkextlib/iwidgets/dateentry' autoload :Datefield, 'tkextlib/iwidgets/datefield' autoload :Dialog, 'tkextlib/iwidgets/dialog' autoload :Dialogshell, 'tkextlib/iwidgets/dialogshell' autoload :Disjointlistbox, 'tkextlib/iwidgets/disjointlistbox' autoload :Entryfield, 'tkextlib/iwidgets/entryfield' autoload :Extbutton, 'tkextlib/iwidgets/extbutton' autoload :Extfileselectionbox, 'tkextlib/iwidgets/extfileselectionbox' autoload :Extfileselectiondialog,'tkextlib/iwidgets/extfileselectiondialog' autoload :Feedback, 'tkextlib/iwidgets/feedback' autoload :Fileselectionbox, 'tkextlib/iwidgets/fileselectionbox' autoload :Fileselectiondialog, 'tkextlib/iwidgets/fileselectiondialog' autoload :Finddialog, 'tkextlib/iwidgets/finddialog' autoload :Hierarchy, 'tkextlib/iwidgets/hierarchy' autoload :Hyperhelp, 'tkextlib/iwidgets/hyperhelp' autoload :Labeledframe, 'tkextlib/iwidgets/labeledframe' autoload :Labeledwidget, 'tkextlib/iwidgets/labeledwidget' autoload :Mainwindow, 'tkextlib/iwidgets/mainwindow' autoload :Menubar, 'tkextlib/iwidgets/menubar' autoload :Messagebox, 'tkextlib/iwidgets/messagebox' autoload :Messagedialog, 'tkextlib/iwidgets/messagedialog' autoload :Notebook, 'tkextlib/iwidgets/notebook' autoload :Optionmenu, 'tkextlib/iwidgets/optionmenu' autoload :Panedwindow, 'tkextlib/iwidgets/panedwindow' autoload :Pushbutton, 'tkextlib/iwidgets/pushbutton' autoload :Promptdialog, 'tkextlib/iwidgets/promptdialog' autoload :Radiobox, 'tkextlib/iwidgets/radiobox' autoload :Scrolledcanvas, 'tkextlib/iwidgets/scrolledcanvas' autoload :Scrolledframe, 'tkextlib/iwidgets/scrolledframe' autoload :Scrolledhtml, 'tkextlib/iwidgets/scrolledhtml' autoload :Scrolledlistbox, 'tkextlib/iwidgets/scrolledlistbox' autoload :Scrolledtext, 'tkextlib/iwidgets/scrolledtext' autoload :Scrolledwidget, 'tkextlib/iwidgets/scrolledwidget' autoload :Selectionbox, 'tkextlib/iwidgets/selectionbox' autoload :Selectiondialog, 'tkextlib/iwidgets/selectiondialog' autoload :Shell, 'tkextlib/iwidgets/shell' autoload :Spindate, 'tkextlib/iwidgets/spindate' autoload :Spinint, 'tkextlib/iwidgets/spinint' autoload :Spinner, 'tkextlib/iwidgets/spinner' autoload :Spintime, 'tkextlib/iwidgets/spintime' autoload :Tabnotebook, 'tkextlib/iwidgets/tabnotebook' autoload :Tabset, 'tkextlib/iwidgets/tabset' autoload :Timeentry, 'tkextlib/iwidgets/timeentry' autoload :Timefield, 'tkextlib/iwidgets/timefield' autoload :Toolbar, 'tkextlib/iwidgets/toolbar' autoload :Watch, 'tkextlib/iwidgets/watch' end end ================================================ FILE: ext/tk/lib/tkextlib/pkg_checker.rb ================================================ #!/usr/bin/env ruby # # Ruby/Tk extension library checker # # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' TkRoot.new.withdraw # hide root window name = File.basename(__FILE__) add_path = false verbose = false def help_msg print "Usage: #{$0} [-l] [-v] [-h] [--] [dir]\n" print "\tIf dir is omitted, check the directry that this command exists.\n" print "\tAvailable options are \n" print "\t -l : Add dir to $LOAD_PATH\n" print "\t (If dir == '/tkextlib', add also.)\n" print "\t -v : Verbose mode (show reason of fail)\n" print "\t -h : Show this message\n" print "\t -- : End of options\n" end while(ARGV[0] && ARGV[0][0] == ?-) case ARGV[0] when '--' ARGV.shift break; when '-l' ARGV.shift add_path = true when '-v' ARGV.shift verbose = true when '-h' help_msg exit(0) else print "Argument Error!! : unknown option '#{ARGV[0]}'\n" help_msg exit(1) end end if ARGV[0] dir = File.expand_path(ARGV[0]) else dir = File.dirname(File.expand_path(__FILE__)) end if add_path $LOAD_PATH.unshift(dir) if File.basename(dir) == 'tkextlib' $LOAD_PATH.unshift(File.dirname(dir)) end end print "\nRuby/Tk extension library checker\n" print "( Note:: This check is very simple one. Shown status may be wrong. )\n" print "\n check directory :: #{dir}" print "\n $LOAD_PATH :: #{$LOAD_PATH.inspect}\n" def get_pkg_list(file) pkg_list = [] File.foreach(file){|l| if l =~ /^(?:[^#]+\s|\s*)(?:|;\s*)TkPackage\s*\.\s*require\s*\(?\s*(["'])((\w|:)+)\1/ pkg = [$2, :package] pkg_list << pkg unless pkg_list.member?(pkg) end if l =~ /^(?:[^#]+\s|\s*)(?:|;\s*)Tk\s*\.\s*load_tcllibrary\s*\(?\s*(["'])((\w|:)+)\1/ pkg = [$2, :library] pkg_list << pkg unless pkg_list.member?(pkg) end if l =~ /^(?:[^#]+\s|\s*)(?:|;\s*)Tk\s*\.\s*load_tclscript\s*\(?\s*(["'])((\w|:)+)\1/ pkg = [$2, :script] pkg_list << pkg unless pkg_list.member?(pkg) end if l =~ /^(?:[^#]+\s|\s*)(?:|;\s*)require\s*\(?\s*(["'])((\w|\/|:)+)\1/ pkg = [$2, :require_ruby_lib] pkg_list << pkg unless pkg_list.member?(pkg) end } pkg_list end def check_pkg(file, verbose=false) pkg_list = get_pkg_list(file) error_list = [] success_list = {} pkg_list.each{|name, type| next if success_list[name] begin case type when :package ver = TkPackage.require(name) success_list[name] = ver error_list.delete_if{|n, t| n == name} when :library Tk.load_tcllibrary(name) success_list[name] = :library error_list.delete_if{|n, t| n == name} when :script Tk.load_tclscript(name) success_list[name] = :script error_list.delete_if{|n, t| n == name} when :require_ruby_lib require name end rescue => e if verbose error_list << [name, type, e.message] else error_list << [name, type] end end } success_list.dup.each{|name, ver| unless ver.kind_of?(String) begin ver = TkPackage.require(name) sccess_list[name] = ver rescue end end } [success_list, error_list] end def subdir_check(dir, verbose=false) Dir.foreach(dir){|f| next if f == '.' || f == '..' if File.directory?(f) subdir_check(File.join(dir, f)) elsif File.extname(f) == '.rb' path = File.join(dir, f) suc, err = check_pkg(path, verbose) if err.empty? print 'Ready : ', path, ' : require->', suc.inspect, "\n" else print '*LACK : ', path, ' : require->', suc.inspect, ' FAIL->', err.inspect, "\n" end end } end Dir.chdir(dir) (Dir['*.rb'] - ['setup.rb', name]).each{|f| subdir = File.basename(f, '.*') =begin begin # read 'setup.rb' as if the library has standard structure require File.join(subdir, 'setup.rb') rescue LoadError # ignore error end =end print "\n" suc, err = check_pkg(f, verbose) if err.empty? print 'Ready : ', f, ' : require->', suc.inspect, "\n" else print '*LACK : ', f, ' : require->', suc.inspect, ' FAIL->', err.inspect, "\n" end subdir_check(subdir, verbose) if File.directory?(subdir) } ================================================ FILE: ext/tk/lib/tkextlib/setup.rb ================================================ # # setup.rb -- setup script before using Tk extension libraries # # If you need some setup operations for Tk extensions (for example, # modify the dynamic library path) required, please write the setup # operations in this file. This file is required at the last of # "require 'tk'". # ================================================ FILE: ext/tk/lib/tkextlib/tcllib/README ================================================ [ tcllib extension support files ] Tcllib includes many utilities. But currently, supports TKLib part only (see the following 'tcllib contents'). If you request to support others, please send your message to one of ruby-talk/ruby-list/ruby-dev/ruby-ext mailing lists. --------------------------------- Tcllib is a collection of utility modules for Tcl. These modules provide a wide variety of functionality, from implementations of standard data structures to implementations of common networking protocols. The intent is to collect commonly used function into a single library, which users can rely on to be available and stable. --------------------------------------------------------- -----< tcllib contents (based on tcllib-1.6.1) >--------- Programming tools * cmdline - Procedures to process command lines and options. * comm - A remote communications facility for Tcl (7.6, 8.0, and later) * control - Procedures for control flow structures. * fileutil - Procedures implementing some file utilities * log - Procedures to log messages of libraries and applications. * logger - System to control logging of events. * multiplexer - One-to-many communication with sockets. * snit - Snit's Not Incr Tcl * snitfaq - Snit Frequently Asked Questions * stooop - Object oriented extension. * stoop - Simple Tcl Only Object Oriented Programming * switched - stooop switched class * profiler - Tcl source code profiler Mathematics * math::statistics - Basic statistical functions and procedures * math::calculus - Integration and ordinary differential equations * math::optimize - Optimisation routines * math::fuzzy - Fuzzy comparison of floating-point numbers * counter - Procedures for counters and histograms * combinatorics - Combinatorial functions in the Tcl Math Library Data structures * struct::list - Procedures for manipulating lists * struct::set - Procedures for manipulating sets * struct::stack - Create and manipulate stack objects * struct::queue - Create and manipulate queue objects * struct::prioqueue - Create and manipulate prioqueue objects * struct::skiplist - Create and manipulate skiplists * struct::tree - Create and manipulate tree objects * struct::graph - Create and manipulate directed graph objects * struct::record - Define and create records (similar to 'C' structures) * struct::matrix - Create and manipulate matrix objects * struct::pool - Create and manipulate pool objects (of discrete items) * report - Create and manipulate report objects Text processing * expander - Procedures to process templates and expand text. * base64 - Procedures to encode and decode base64 * yencode - encode/decoding a binary file * uuencode - encode/decoding a binary file * csv - Procedures to handle CSV data. * inifile - Parsing of Windows INI files * htmlparse - Procedures to parse HTML strings * mime - Manipulation of MIME body parts * Tcl MIME - generates and parses MIME body parts * textutil - Procedures to manipulate texts and strings. * exif - Tcl EXIF extracts and parses EXIF fields from digital images * EXIF - extract and parse EXIF fields from digital images Hashes, checksums, and encryption * cksum - calculate a cksum(1) compatible checksum * crc16 - Perform a 16bit Cyclic Redundancy Check * crc32 - Perform a 32bit Cyclic Redundancy Check * des - Perform DES encryption of Tcl data * md4 - MD4 Message-Digest Algorithm * md5 - MD5 Message-Digest Algorithm * ripemd160 - RIPEMD-160 Message-Digest Algorithm * ripemd128 - RIPEMD-128 Message-Digest Algorithm * md5crypt - MD5-based password encryption * sha1 - Perform sha1 hashing * sum - calculate a sum(1) compatible checksum * soundex - Soundex Documentation tools * mpexpand - Markup processor * doctools - Create and manipulate doctools converter object * doctoc_fmt - Specification of simple tcl markup for table of contents * doctools_api - Interface specification for formatter code * doctools_fmt - Specification of simple tcl markup for manpages * docidx - Create and manipulate docidx converter objects * docidx_api - Interface specification for index formatting code * docidx_fmt - Specification of simple tcl markup for an index * doctoc - Create and manipulate doctoc converter objects * doctoc_api - Interface specification for toc formatting code * doctools::changelog - Handle text in Emacs ChangeLog format * doctools::cvs - Handle text in 'cvs log' format Networking * uri - URI utilities * dns - Tcl Domain Name Service Client * ntp_time - Tcl Time Service Client * nntp - Tcl client for the NNTP protocol * pop3 - Tcl client for POP3 email protocol * pop3d - Tcl POP3 server implementation * pop3d::udb - Simple user database for pop3d * pop3d::dbox - Simple mailbox database for pop3d * ftp - Client-side tcl implementation of the ftp protocol * ftp - Client-side tcl implementation of the ftp protocol * ftpd - Tcl FTP server implementation * smtp - Client-side tcl implementation of the smtp protocol * smtpd - Tcl SMTP server implementation * irc - Create IRC connection and interface. CGI programming * ncgi - Procedures to manipulate CGI values. * html - Procedures to generate HTML structures * javascript - Procedures to generate HTML and Java Script structures. Grammars and finite automata * grammar::fa - Create and manipulate finite automatons * grammar::fa::op - Operations on finite automatons * grammar::dacceptor - Create and use deterministic acceptors * grammar::dexec - Execute deterministic finite automatons TKLib * Plotchart - Simple plotting and charting package * autoscroll - Provides for a scrollbar to automatically mapped and unmapped as needed * ctext - An extended text widget with customizable Syntax highlighting * cursor - Procedures to handle CURSOR data * datefield - Tk datefield widget * style - Changes default Tk look&feel * ipentry - An IP address entry widget * tkpiechart - Creates and dynamically updates 2D or 3D pie charts --------------------------------------------------------- ================================================ FILE: ext/tk/lib/tkextlib/tcllib/autoscroll.rb ================================================ # # tkextlib/tcllib/autoscroll.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * Provides for a scrollbar to automatically mapped and unmapped as needed # # (The following is the original description of the library.) # # This package allows scrollbars to be mapped and unmapped as needed # depending on the size and content of the scrollbars scrolled widget. # The scrollbar must be managed by either pack or grid, other geometry # managers are not supported. # # When managed by pack, any geometry changes made in the scrollbars parent # between the time a scrollbar is unmapped, and when it is mapped will be # lost. It is an error to destroy any of the scrollbars siblings while the # scrollbar is unmapped. When managed by grid, if anything becomes gridded # in the same row and column the scrollbar occupied it will be replaced by # the scrollbar when remapped. # # This package may be used on any scrollbar-like widget as long as it # supports the set subcommand in the same style as scrollbar. If the set # subcommand is not used then this package will have no effect. # require 'tk' require 'tk/scrollbar' require 'tkextlib/tcllib.rb' module Tk module Tcllib module Autoscroll PACKAGE_NAME = 'autoscroll'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('autoscroll') rescue '' end end def self.not_available fail RuntimeError, "'tkextlib/tcllib/autoscroll' extension is not available on your current environment." end def self.autoscroll(win) Tk::Tcllib::Autoscroll.not_available end def self.unautoscroll(win) Tk::Tcllib::Autoscroll.not_available end end end end module Tk module Scrollable def autoscroll(mode = nil) case mode when :x, 'x' if @xscrollbar Tk::Tcllib::Autoscroll.autoscroll(@xscrollbar) end when :y, 'y' if @yscrollbar Tk::Tcllib::Autoscroll.autoscroll(@yscrollbar) end when nil, :both, 'both' if @xscrollbar Tk::Tcllib::Autoscroll.autoscroll(@xscrollbar) end if @yscrollbar Tk::Tcllib::Autoscroll.autoscroll(@yscrollbar) end else fail ArgumentError, "'x', 'y' or 'both' (String or Symbol) is expected" end self end def unautoscroll(mode = nil) case mode when :x, 'x' if @xscrollbar Tk::Tcllib::Autoscroll.unautoscroll(@xscrollbar) end when :y, 'y' if @yscrollbar Tk::Tcllib::Autoscroll.unautoscroll(@yscrollbar) end when nil, :both, 'both' if @xscrollbar Tk::Tcllib::Autoscroll.unautoscroll(@xscrollbar) end if @yscrollbar Tk::Tcllib::Autoscroll.unautoscroll(@yscrollbar) end else fail ArgumentError, "'x', 'y' or 'both' (String or Symbol) is expected" end self end end end class Tk::Scrollbar def autoscroll # Arranges for the already existing scrollbar to be mapped # and unmapped as needed. #tk_call_without_enc('::autoscroll::autoscroll', @path) Tk::Tcllib::Autoscroll.autoscroll(self) self end def unautoscroll # Returns the scrollbar to its original static state. #tk_call_without_enc('::autoscroll::unautoscroll', @path) Tk::Tcllib::Autoscroll.unautoscroll(self) self end end # TkPackage.require('autoscroll', '1.0') # TkPackage.require('autoscroll', '1.1') TkPackage.require('autoscroll') module Tk module Tcllib class << Autoscroll undef not_available end module Autoscroll extend TkCore def self.autoscroll(win) tk_call_without_enc('::autoscroll::autoscroll', win.path) end def self.unautoscroll(win) tk_call_without_enc('::autoscroll::unautoscroll', win.path) end def self.wrap # v1.1 tk_call_without_enc('::autoscroll::wrap') end def self.unwrap # v1.1 tk_call_without_enc('::autoscroll::unwrap') end end end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/ctext.rb ================================================ # # tkextlib/tcllib/ctext.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * Overloads the text widget and provides new commands # require 'tk' require 'tk/text' require 'tkextlib/tcllib.rb' # TkPackage.require('ctext', '3.1') TkPackage.require('ctext') module Tk module Tcllib class CText < Tk::Text PACKAGE_NAME = 'ctext'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('ctext') rescue '' end end end end end class Tk::Tcllib::CText TkCommandNames = ['ctext'.freeze].freeze WidgetClassName = 'Ctext'.freeze WidgetClassNames[WidgetClassName] = self def create_self(keys) if keys and keys != None tk_call_without_enc(self.class::TkCommandNames[0], @path, *hash_kv(keys, true)) else tk_call_without_enc(self.class::TkCommandNames[0], @path) end end private :create_self def __strval_optkeys super() << 'linemapfg' << 'linemapbg' << 'linemap_select_fg' << 'linemap_select_bg' end private :__strval_optkeys def __boolval_optkeys super() << 'highlight' << 'linemap_markable' end private :__boolval_optkeys def append(*args) tk_send('append', *args) end def copy tk_send('copy') end def cut tk_send('cut') end def fast_delete(*args) tk_send('fastdelete', *args) end def fast_insert(*args) tk_send('fastinsert', *args) end def highlight(*args) tk_send('highlight', *args) end def paste tk_send('paste') end def edit(*args) tk_send('edit', *args) end def add_highlight_class(klass, col, *keywords) tk_call('ctext::addHighlightClass', @path, klass, col, keywords.flatten) self end def add_highlight_class_for_special_chars(klass, col, *chrs) tk_call('ctext::addHighlightClassForSpecialChars', @path, klass, col, chrs.join('')) self end def add_highlight_class_for_regexp(klass, col, tcl_regexp) tk_call('ctext::addHighlightClassForRegexp', @path, klass, col, tcl_regexp) self end def add_highlight_class_with_only_char_start(klass, col, chr) tk_call('ctext::addHighlightClassWithOnlyCharStart', @path, klass, col, chr) self end def clear_highlight_classes tk_call('ctext::clearHighlightClasses', @path) self end def get_highlight_classes tk_split_simplelist(tk_call('ctext::getHighlightClasses', @path)) end def delete_highlight_class(klass) tk_call('ctext::deleteHighlightClass', @path, klass) self end def enable_C_comments tk_call('ctext::enableComments', @path) self end def disable_C_comments tk_call('ctext::disableComments', @path) self end def find_next_char(idx, chr) tk_call('ctext::findNextChar', @path, idx, chr) end def find_next_space(idx) tk_call('ctext::findNextSpace', @path, idx) end def find_previous_space(idx) tk_call('ctext::findPreviousSpace', @path, idx) end def set_update_proc(cmd=Proc.new) tk_call('proc', 'ctext::update', '', cmd) self end def modified?(mode) bool(tk_call('ctext::modified', @path, mode)) end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/cursor.rb ================================================ # # tkextlib/tcllib/cursor.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * Procedures to handle CURSOR data # require 'tk' require 'tkextlib/tcllib.rb' module Tk module Tcllib module Cursor PACKAGE_NAME = 'cursor'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('cursor') rescue '' end end def self.not_available fail RuntimeError, "'tkextlib/tcllib/cursor' extension is not available on your current environment." end def self.cursor_display(win=None) Tk::Tcllib::Cursor.not_available end def self.cursor_propagate(win, cursor) Tk::Tcllib::Cursor.not_available end def self.cursor_restore(win, cursor = None) Tk::Tcllib::Cursor.not_available end end end def self.cursor_display(parent=None) # Pops up a dialog with a listbox containing all the cursor names. # Selecting a cursor name will display it in that dialog. # This is simply for viewing any available cursors on the platform . #tk_call_without_enc('::cursor::display', parent) Tk::Tcllib::Cursor.cursor_display(parent) end end class TkWindow def cursor_propagate(cursor) # Sets the cursor for self and all its descendants to cursor. #tk_call_without_enc('::cursor::propagate', @path, cursor) Tk::Tcllib::Cursor.cursor_propagate(self, cursor) end def cursor_restore(cursor = None) # Restore the original or previously set cursor for self and all its # descendants. If cursor is specified, that will be used if on any # widget that did not have a preset cursor (set by a previous call # to TkWindow#cursor_propagate). #tk_call_without_enc('::cursor::restore', @path, cursor) Tk::Tcllib::Cursor.cursor_restore(self, cursor) end end # TkPackage.require('cursor', '0.1') TkPackage.require('cursor') module Tk module Tcllib class << Cursor undef not_available end module Cursor extend TkCore def self.cursor_display(win=None) tk_call_without_enc('::cursor::display', _epath(win)) end def self.cursor_propagate(win, cursor) #tk_call_without_enc('::cursor::propagate', win.path, cursor) tk_call_without_enc('::cursor::propagate', _epath(win), cursor) end def self.cursor_restore(win, cursor = None) #tk_call_without_enc('::cursor::restore', win.path, cursor) tk_call_without_enc('::cursor::restore', _epath(win), cursor) end end end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/datefield.rb ================================================ # # tkextlib/tcllib/datefield.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * Tk datefield widget # # (The following is the original description of the library.) # # The datefield package provides the datefield widget which is an enhanced # text entry widget for the purpose of date entry. Only valid dates of the # form MM/DD/YYYY can be entered. # # The datefield widget is, in fact, just an entry widget with specialized # bindings. This means all the command and options for an entry widget apply # equally here. require 'tk' require 'tk/entry' require 'tkextlib/tcllib.rb' # TkPackage.require('datefield', '0.1') TkPackage.require('datefield') module Tk module Tcllib class Datefield < Tk::Entry PACKAGE_NAME = 'datefield'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('datefield') rescue '' end end end DateField = Datefield end end class Tk::Tcllib::Datefield TkCommandNames = ['::datefield::datefield'.freeze].freeze def create_self(keys) if keys and keys != None tk_call_without_enc(self.class::TkCommandNames[0], @path, *hash_kv(keys, true)) else tk_call_without_enc(self.class::TkCommandNames[0], @path) end end private :create_self end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/dialog.rb ================================================ # # tkextlib/tcllib/dialog.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * Generic dialog widget (themed) # require 'tk' require 'tkextlib/tcllib.rb' # TkPackage.require('widget::dialog', '1.2') TkPackage.require('widget::dialog') module Tk::Tcllib module Widget class Dialog < TkWindow PACKAGE_NAME = 'widget::dialog'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('widget::dialog') rescue '' end end end end end class Tk::Tcllib::Widget::Dialog TkCommandNames = ['::widget::dialog'.freeze].freeze def __boolval_optkeys ['separator', 'synchronous', 'transient'] end private :__boolval_optkeys def create_self(keys) if keys and keys != None tk_call_without_enc(self.class::TkCommandNames[0], @path, *hash_kv(keys, true)) else tk_call_without_enc(self.class::TkCommandNames[0], @path) end end private :create_self def add(what, *args) window(tk_send('add', *args)) end def get_frame window(tk_send('getframe')) end def set_widget(widget) tk_send('setwidget', widget) self end def display tk_send('display') self end alias show display def cancel tk_send('cancel') self end def close(reason = None) tk_send('close', reason) end def withdraw tk_send('withdraw') self end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/getstring.rb ================================================ # # tkextlib/tcllib/getstring.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * A dialog which consists of an Entry, OK, and Cancel buttons. # require 'tk' require 'tk/entry' require 'tkextlib/tcllib.rb' # TkPackage.require('getstring', '0.1') TkPackage.require('getstring') module Tk::Tcllib class GetString_Dialog < TkWindow PACKAGE_NAME = 'getstring'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('getstring') rescue '' end end end end class Tk::Tcllib::GetString_Dialog TkCommandNames = ['::getstring::tk_getString'.freeze].freeze WidgetClassName = 'TkSDialog'.freeze WidgetClassNames[WidgetClassName] = self def self.show(*args) dialog = self.new(*args) dialog.show [dialog.status, dialog.value] end def self.display(*args) self.show(*args) end def initialize(*args) # args = (parent=nil, text='', keys=nil) keys = args.pop if keys.kind_of?(Hash) text = args.pop @keys = _symbolkey2str(keys) args.push(keys) else text = keys @keys = {} end if text @text = text.dup else @text = '' end @variable = TkVariable.new @status = nil super(*args) end def create_self(keys) # dummy end private :create_self def show @variable.value = '' @status = bool(tk_call(self.class::TkCommandNames[0], @path, @variable, @text, *hash_kv(@keys))) end alias display show def status @status end def value @variable.value end def cget_strict(slot) slot = slot.to_s if slot == 'text' @text else @keys[slot] end end def cget(slot) cget_strict(slot) end def configure(slot, value=None) if slot.kind_of?(Hash) slot.each{|k, v| configure(k, v)} else slot = slot.to_s value = _symbolkey2str(value) if value.kind_of?(Hash) if value && value != None if slot == 'text' @text = value.to_s else @keys[slot] = value end else if slot == 'text' @text = '' else @keys.delete(slot) end end end self end def configinfo(slot = nil) if slot slot = slot.to_s [ slot, nil, nil, nil, ( (slot == 'text')? @text: @keys[slot] ) ] else @keys.collect{|k, v| [ k, nil, nil, nil, v ] } \ << [ 'text', nil, nil, nil, @text ] end end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/history.rb ================================================ # # tkextlib/tcllib/history.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * Provides a history for Entry widgets # require 'tk' require 'tk/entry' require 'tkextlib/tcllib.rb' # TkPackage.require('history', '0.1') TkPackage.require('history') module Tk::Tcllib module History PACKAGE_NAME = 'history'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('history') rescue '' end end end end module Tk::Tcllib::History extend TkCore def self.init(entry, length=None) tk_call_without_enc('::history::init', entry.path, length) entry.extend(self) # add methods to treat history to the entry widget end def self.remove(entry) tk_call_without_enc('::history::remove', entry.path) entry end def history_remove tk_call_without_enc('::history::remove', @path) self end def history_add(text) tk_call('::history::add', @path, text) self end def history_get simplelist(tk_call_without_enc('::history::get', @path)) end def history_clear tk_call_without_enc('::history::clear', @path) self end def history_configure(opt, value) tk_call('::history::configure', @path, opt, value) self end def history_configinfo(opt) tk_call('::history::configure', @path, opt) end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/ico.rb ================================================ # # tkextlib/tcllib/ico.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * Reading and writing windows icons # require 'tk' require 'tk/image' require 'tkextlib/tcllib.rb' # TkPackage.require('ico', '0.3') TkPackage.require('ico') module Tk module Tcllib class ICO < TkImage PACKAGE_NAME = 'ico'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('ico') rescue '' end end end end end class Tk::Tcllib::ICO def self.list(file, keys=nil) tk_split_list(tk_call_without_enc('::ico::getIconList', file, *hash_kv(keys, true))) end def self.get(file, index, keys=nil) tk_call_without_enc('::ico::getIcon', file, index, *hash_kv(keys, true)) end def self.get_image(file, index, keys={}) keys = _symbolkey2str(keys) keys.delete('format') self.new(file, index, keys) end def self.get_data(file, index, keys={}) keys['format'] = 'data' tk_split_list(tk_call_without_enc('::ico::getIcon', file, index, *hash_kv(keys, true))) end def self.write(file, index, depth, data, keys=nil) tk_call_without_enc('::ico::writeIcon', file, index, depth, data, *hash_kv(keys, true)) end def self.copy(from_file, from_index, to_file, to_index, keys=nil) tk_call_without_enc('::ico::copyIcon', from_file, from_index, to_file, to_index, *hash_kv(keys, true)) end def self.exe_to_ico(exe_file, ico_file, keys=nil) tk_call_without_enc('::ico::copyIcon', exe_file, ico_file, *hash_kv(keys, true)) end def self.clear_cache(file=None) tk_call_without_enc('::ico::clearCache', file) end def self.transparent_color(image, color) if image.kind_of?(Array) tk_split_list(tk_call_without_enc('::ico::transparentColor', image, color)) else tk_call_without_enc('::ico::transparentColor', image, color) end end def self.show(file, keys=nil) tk_call_without_enc('::ico::Show', file, *hash_kv(keys, true)) end ########################### def initialize(file, index, keys=nil) keys = _symbolkey2str(keys) if keys.key?('name') @path = keys['name'].to_s else Tk_Image_ID.mutex.synchronize{ @path = Tk_Image_ID.join(TkCore::INTERP._ip_id_) Tk_Image_ID[1].succ! } end tk_call_without_enc('::ico::getIcon', file, index, '-name', @path, '-format', 'image', *hash_kv(keys, true)) Tk_IMGTBL[@path] = self end def write(file, index, depth, keys=nil) Tk::Tcllib::ICO.write(file, index, depth, @path, keys=nil) self end def transparent_color(color) tk_call_without_enc('::ico::transparentColor', @path, color) self end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/ip_entry.rb ================================================ # # tkextlib/tcllib/ip_entry.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * An IP address entry widget # # (The following is the original description of the library.) # # This package provides a widget for the entering of a IP address. # It guarantees a valid address at all times. require 'tk' require 'tkextlib/tcllib.rb' # TkPackage.require('ipentry', '0.1') TkPackage.require('ipentry') module Tk module Tcllib class IP_Entry < Tk::Entry PACKAGE_NAME = 'ipentry'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('ipentry') rescue '' end end end IPEntry = IP_Entry end end class Tk::Tcllib::IP_Entry TkCommandNames = ['::ipentry::ipentry'.freeze].freeze WidgetClassName = 'IPEntry'.freeze WidgetClassNames[WidgetClassName] = self def create_self(keys) if keys and keys != None tk_call_without_enc(self.class::TkCommandNames[0], @path, *hash_kv(keys, true)) else tk_call_without_enc(self.class::TkCommandNames[0], @path) end end private :create_self def __strval_optkeys super() << 'fg' << 'bg' << 'insertbackground' end private :__strval_optkeys def complete? bool(tk_send_without_enc('complete')) end def insert(*ip) tk_send_without_enc('insert', array2tk_list(ip.flatten)) end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/panelframe.rb ================================================ # # tkextlib/tcllib/panelframe.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * Create PanelFrame widgets. # require 'tk' require 'tkextlib/tcllib.rb' # TkPackage.require('widget::panelframe', '1.0') TkPackage.require('widget::panelframe') module Tk::Tcllib module Widget class PanelFrame < TkWindow PACKAGE_NAME = 'widget::panelframe'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('widget::panelframe') rescue '' end end end Panelframe = PanelFrame end end class Tk::Tcllib::Widget::PanelFrame TkCommandNames = ['::widget::panelframe'.freeze].freeze def create_self(keys) if keys and keys != None tk_call_without_enc(self.class::TkCommandNames[0], @path, *hash_kv(keys, true)) else tk_call_without_enc(self.class::TkCommandNames[0], @path) end end private :create_self def add(what, *args) window(tk_send('add', *args)) end #def get_frame # window(tk_send('getframe')) #end def set_widget(widget) tk_send('setwidget', widget) self end def remove(*wins) tk_send('remove', *wins) end def remove_destroy(*wins) tk_send('remove', '-destroy', *wins) end alias delete remove_destroy def items simplelist(tk_send('items')).collect!{|w| window(w)} end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/plotchart.rb ================================================ # # tkextlib/tcllib/plotchart.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * Simple plotting and charting package # # (The following is the original description of the library.) # # Plotchart is a Tcl-only package that focuses on the easy creation of # xy-plots, barcharts and other common types of graphical presentations. # The emphasis is on ease of use, rather than flexibility. The procedures # that create a plot use the entire canvas window, making the layout of the # plot completely automatic. # # This results in the creation of an xy-plot in, say, ten lines of code: # -------------------------------------------------------------------- # package require Plotchart # # canvas .c -background white -width 400 -height 200 # pack .c -fill both # # # # # Create the plot with its x- and y-axes # # # set s [::Plotchart::createXYPlot .c {0.0 100.0 10.0} {0.0 100.0 20.0}] # # foreach {x y} {0.0 32.0 10.0 50.0 25.0 60.0 78.0 11.0 } { # $s plot series1 $x $y # } # # $s title "Data series" # -------------------------------------------------------------------- # # A drawback of the package might be that it does not do any data management. # So if the canvas that holds the plot is to be resized, the whole plot must # be redrawn. The advantage, though, is that it offers a number of plot and # chart types: # # * XY-plots like the one shown above with any number of data series. # * Stripcharts, a kind of XY-plots where the horizontal axis is adjusted # automatically. The result is a kind of sliding window on the data # series. # * Polar plots, where the coordinates are polar instead of cartesian. # * Isometric plots, where the scale of the coordinates in the two # directions is always the same, i.e. a circle in world coordinates # appears as a circle on the screen. # You can zoom in and out, as well as pan with these plots (Note: this # works best if no axes are drawn, the zooming and panning routines do # not distinguish the axes), using the mouse buttons with the control # key and the arrow keys with the control key. # * Piecharts, with automatic scaling to indicate the proportions. # * Barcharts, with either vertical or horizontal bars, stacked bars or # bars side by side. # * Timecharts, where bars indicate a time period and milestones or other # important moments in time are represented by triangles. # * 3D plots (both for displaying surfaces and 3D bars) # require 'tk' require 'tkextlib/tcllib.rb' # TkPackage.require('Plotchart', '0.9') # TkPackage.require('Plotchart', '1.1') TkPackage.require('Plotchart') module Tk module Tcllib module Plotchart PACKAGE_NAME = 'Plotchart'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('Plotchart') rescue '' end end end end end module Tk::Tcllib::Plotchart extend TkCore ############################ def self.view_port(w, *args) # args := pxmin, pymin, pxmax, pymax tk_call_without_enc('::Plotchart::viewPort', w.path, *(args.flatten)) end def self.world_coordinates(w, *args) # args := xmin, ymin, xmax, ymax tk_call_without_enc('::Plotchart::worldCoordinates', w.path, *(args.flatten)) end def self.world_3D_coordinates(w, *args) # args := xmin, ymin, zmin, xmax, ymax, zmax tk_call_without_enc('::Plotchart::world3DCoordinates', w.path, *(args.flatten)) end def self.coords_to_pixel(w, x, y) list(tk_call_without_enc('::Plotchart::coordsToPixel', w.path, x, y)) end def self.coords_3D_to_pixel(w, x, y, z) list(tk_call_without_enc('::Plotchart::coords3DToPixel', w.path, x, y, z)) end def self.polar_coordinates(w, radmax) tk_call_without_enc('::Plotchart::polarCoordinates', w.path, radmax) end def self.polar_to_pixel(w, rad, phi) list(tk_call_without_enc('::Plotchart::polarToPixel', w.path, rad, phi)) end def self.pixel_to_coords(w, x, y) list(tk_call_without_enc('::Plotchart::coordsToPixel', w.path, x, y)) end def self.determine_scale(w, xmax, ymax) tk_call_without_enc('::Plotchart::determineScale', w.path, xmax, ymax) end def self.set_zoom_pan(w) tk_call_without_enc('::Plotchart::setZoomPan', w.path) end ############################ module ChartMethod include TkCore def title(str) tk_call_without_enc(@chart, 'title', _get_eval_enc_str(str)) self end def save_plot(filename) tk_call_without_enc(@chart, 'saveplot', filename) self end def xtext(str) tk_call_without_enc(@chart, 'xtext', _get_eval_enc_str(str)) self end def ytext(str) tk_call_without_enc(@chart, 'ytext', _get_eval_enc_str(str)) self end def xconfig(key, value=None) if key.kind_of?(Hash) tk_call_without_enc(@chart, 'xconfig', *hash_kv(key, true)) else tk_call_without_enc(@chart, 'xconfig', "-#{key}", _get_eval_enc_str(value)) end self end def yconfig(key, value=None) if key.kind_of?(Hash) tk_call_without_enc(@chart, 'yconfig', *hash_kv(key, true)) else tk_call_without_enc(@chart, 'yconfig', "-#{key}", _get_eval_enc_str(value)) end self end ############################ def view_port(*args) # args := pxmin, pymin, pxmax, pymax tk_call_without_enc('::Plotchart::viewPort', @path, *(args.flatten)) self end def world_coordinates(*args) # args := xmin, ymin, xmax, ymax tk_call_without_enc('::Plotchart::worldCoordinates', @path, *(args.flatten)) self end def world_3D_coordinates(*args) # args := xmin, ymin, zmin, xmax, ymax, zmax tk_call_without_enc('::Plotchart::world3DCoordinates', @path, *(args.flatten)) self end def coords_to_pixel(x, y) list(tk_call_without_enc('::Plotchart::coordsToPixel', @path, x, y)) end def coords_3D_to_pixel(x, y, z) list(tk_call_without_enc('::Plotchart::coords3DToPixel', @path, x, y, z)) end def polar_coordinates(radmax) tk_call_without_enc('::Plotchart::polarCoordinates', @path, radmax) self end def polar_to_pixel(rad, phi) list(tk_call_without_enc('::Plotchart::polarToPixel', @path, rad, phi)) end def pixel_to_coords(x, y) list(tk_call_without_enc('::Plotchart::coordsToPixel', @path, x, y)) end def determine_scale(xmax, ymax) tk_call_without_enc('::Plotchart::determineScale', @path, xmax, ymax) self end def set_zoom_pan() tk_call_without_enc('::Plotchart::setZoomPan', @path) self end end ############################ class XYPlot < Tk::Canvas include ChartMethod TkCommandNames = [ 'canvas'.freeze, '::Plotchart::createXYPlot'.freeze ].freeze def initialize(*args) # args := ([parent,] xaxis, yaxis [, keys]) # xaxis := Array of [minimum, maximum, stepsize] # yaxis := Array of [minimum, maximum, stepsize] if args[0].kind_of?(Array) @xaxis = args.shift @yaxis = args.shift super(*args) # create canvas widget else parent = args.shift @xaxis = args.shift @yaxis = args.shift if parent.kind_of?(Tk::Canvas) @path = parent.path else super(parent, *args) # create canvas widget end end @chart = _create_chart end def _create_chart p self.class::TkCommandNames[1] if $DEBUG tk_call_without_enc(self.class::TkCommandNames[1], @path, array2tk_list(@xaxis), array2tk_list(@yaxis)) end private :_create_chart def __destroy_hook__ Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.mutex.synchronize{ Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) } end def plot(series, x, y) tk_call_without_enc(@chart, 'plot', _get_eval_enc_str(series), x, y) self end def contourlines(xcrd, ycrd, vals, clss=None) xcrd = array2tk_list(xcrd) if xcrd.kind_of?(Array) ycrd = array2tk_list(ycrd) if ycrd.kind_of?(Array) vals = array2tk_list(vals) if vals.kind_of?(Array) clss = array2tk_list(clss) if clss.kind_of?(Array) tk_call_without_enc(@chart, 'contourlines', xcrd, ycrd, vals, clss) self end def contourfill(xcrd, ycrd, vals, klasses=None) xcrd = array2tk_list(xcrd) if xcrd.kind_of?(Array) ycrd = array2tk_list(ycrd) if ycrd.kind_of?(Array) vals = array2tk_list(vals) if vals.kind_of?(Array) clss = array2tk_list(clss) if clss.kind_of?(Array) tk_call_without_enc(@chart, 'contourfill', xcrd, ycrd, vals, clss) self end def contourbox(xcrd, ycrd, vals, klasses=None) xcrd = array2tk_list(xcrd) if xcrd.kind_of?(Array) ycrd = array2tk_list(ycrd) if ycrd.kind_of?(Array) vals = array2tk_list(vals) if vals.kind_of?(Array) clss = array2tk_list(clss) if clss.kind_of?(Array) tk_call_without_enc(@chart, 'contourbox', xcrd, ycrd, vals, clss) self end def color_map(colors) colors = array2tk_list(colors) if colors.kind_of?(Array) tk_call_without_enc(@chart, 'colorMap', colors) self end def grid_cells(xcrd, ycrd) xcrd = array2tk_list(xcrd) if xcrd.kind_of?(Array) ycrd = array2tk_list(ycrd) if ycrd.kind_of?(Array) tk_call_without_enc(@chart, 'grid', xcrd, ycrd) self end def dataconfig(series, key, value=None) if key.kind_of?(Hash) tk_call_without_enc(@chart, 'dataconfig', series, *hash_kv(key, true)) else tk_call_without_enc(@chart, 'dataconfig', series, "-#{key}", _get_eval_enc_str(value)) end end end ############################ class Stripchart < XYPlot TkCommandNames = [ 'canvas'.freeze, '::Plotchart::createStripchart'.freeze ].freeze end ############################ class PolarPlot < Tk::Canvas include ChartMethod TkCommandNames = [ 'canvas'.freeze, '::Plotchart::createPolarplot'.freeze ].freeze def initialize(*args) # args := ([parent,] radius_data [, keys]) # radius_data := Array of [maximum_radius, stepsize] if args[0].kind_of?(Array) @radius_data = args.shift super(*args) # create canvas widget else parent = args.shift @radius_data = args.shift if parent.kind_of?(Tk::Canvas) @path = parent.path else super(parent, *args) # create canvas widget end end @chart = _create_chart end def _create_chart p self.class::TkCommandNames[1] if $DEBUG tk_call_without_enc(self.class::TkCommandNames[1], @path, array2tk_list(@radius_data)) end private :_create_chart def __destroy_hook__ Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.mutex.synchronize{ Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) } end def plot(series, radius, angle) tk_call_without_enc(@chart, 'plot', _get_eval_enc_str(series), radius, angle) self end def dataconfig(series, key, value=None) if key.kind_of?(Hash) tk_call_without_enc(@chart, 'dataconfig', series, *hash_kv(key, true)) else tk_call_without_enc(@chart, 'dataconfig', series, "-#{key}", _get_eval_enc_str(value)) end end end Polarplot = PolarPlot ############################ class IsometricPlot < Tk::Canvas include ChartMethod TkCommandNames = [ 'canvas'.freeze, '::Plotchart::createIsometricPlot'.freeze ].freeze def initialize(*args) # args := ([parent,] xaxis, yaxis, [, step] [, keys]) # xaxis := Array of [minimum, maximum] # yaxis := Array of [minimum, maximum] # step := Float of stepsize | "noaxes" | :noaxes if args[0].kind_of?(Array) @xaxis = args.shift @yaxis = args.shift if args[0].kind_of?(Hash) @stepsize = :noaxes else @stepsize = args.shift end super(*args) # create canvas widget else parent = args.shift @xaxis = args.shift @yaxis = args.shift if args[0].kind_of?(Hash) @stepsize = :noaxes else @stepsize = args.shift end if parent.kind_of?(Tk::Canvas) @path = parent.path else super(parent, *args) # create canvas widget end end @chart = _create_chart end def _create_chart p self.class::TkCommandNames[1] if $DEBUG tk_call_without_enc(self.class::TkCommandNames[1], @path, array2tk_list(@xaxis), array2tk_list(@yaxis), @stepsize) end private :_create_chart def plot(type, *args) self.__send__("plot_#{type.to_s.tr('-', '_')}", *args) end def plot_rectangle(*args) # args := x1, y1, x2, y2, color tk_call_without_enc(@chart, 'plot', 'rectangle', *(args.flatten)) self end def plot_filled_rectangle(*args) # args := x1, y1, x2, y2, color tk_call_without_enc(@chart, 'plot', 'filled-rectangle', *(args.flatten)) self end def plot_circle(*args) # args := xc, yc, radius, color tk_call_without_enc(@chart, 'plot', 'circle', *(args.flatten)) self end def plot_filled_circle(*args) # args := xc, yc, radius, color tk_call_without_enc(@chart, 'plot', 'filled-circle', *(args.flatten)) self end end Isometricplot = IsometricPlot ############################ class Plot3D < Tk::Canvas include ChartMethod TkCommandNames = [ 'canvas'.freeze, '::Plotchart::create3DPlot'.freeze ].freeze def initialize(*args) # args := ([parent,] xaxis, yaxis, zaxis [, keys]) # xaxis := Array of [minimum, maximum, stepsize] # yaxis := Array of [minimum, maximum, stepsize] # zaxis := Array of [minimum, maximum, stepsize] if args[0].kind_of?(Array) @xaxis = args.shift @yaxis = args.shift @zaxis = args.shift super(*args) # create canvas widget else parent = args.shift @xaxis = args.shift @yaxis = args.shift @zaxis = args.shift if parent.kind_of?(Tk::Canvas) @path = parent.path else super(parent, *args) # create canvas widget end end @chart = _create_chart end def _create_chart p self.class::TkCommandNames[1] if $DEBUG tk_call_without_enc(self.class::TkCommandNames[1], @path, array2tk_list(@xaxis), array2tk_list(@yaxis), array2tk_list(@zaxis)) end private :_create_chart def plot_function(cmd=Proc.new) Tk.ip_eval("proc #{@path}_#{@chart} {x y} {#{install_cmd(cmd)} $x $y}") tk_call_without_enc(@chart, 'plotfunc', "#{@path}_#{@chart}") self end def plot_funcont(conts, cmd=Proc.new) conts = array2tk_list(conts) if conts.kind_of?(Array) Tk.ip_eval("proc #{@path}_#{@chart} {x y} {#{install_cmd(cmd)} $x $y}") tk_call_without_enc(@chart, 'plotfuncont', "#{@path}_#{@chart}", conts) self end def grid_size(nxcells, nycells) tk_call_without_enc(@chart, 'gridsize', nxcells, nycells) self end def plot_data(dat) # dat has to be provided as a 2 level array. # 1st level contains rows, drawn in y-direction, # and each row is an array whose elements are drawn in x-direction, # for the columns. tk_call_without_enc(@chart, 'plotdata', dat) self end def colour(fill, border) # configure the colours to use for polygon borders and inner area tk_call_without_enc(@chart, 'colour', fill, border) self end alias colours colour alias colors colour alias color colour end ############################ class Piechart < Tk::Canvas include ChartMethod TkCommandNames = [ 'canvas'.freeze, '::Plotchart::createPiechart'.freeze ].freeze def initialize(*args) # args := ([parent] [, keys]) if args[0].kind_of?(Tk::Canvas) parent = args.shift @path = parent.path else super(*args) # create canvas widget end @chart = _create_chart end def _create_chart p self.class::TkCommandNames[1] if $DEBUG tk_call_without_enc(self.class::TkCommandNames[1], @path) end private :_create_chart def plot(*dat) # argument is a list of [label, value] tk_call_without_enc(@chart, 'plot', dat.flatten) self end end ############################ class Barchart < Tk::Canvas include ChartMethod TkCommandNames = [ 'canvas'.freeze, '::Plotchart::createBarchart'.freeze ].freeze def initialize(*args) # args := ([parent,] xlabels, ylabels [, series] [, keys]) # xlabels, ylabels := labels | axis ( depend on normal or horizontal ) # labels := Array of [label, label, ...] # (It determines the number of bars that will be plotted per series.) # axis := Array of [minimum, maximum, stepsize] # series := Integer number of data series | 'stacked' | :stacked if args[0].kind_of?(Array) @xlabels = args.shift @ylabels = args.shift if args[0].kind_of?(Hash) @series_size = :stacked else @series_size = args.shift end super(*args) # create canvas widget else parent = args.shift @xlabels = args.shift @ylabels = args.shift if args[0].kind_of?(Hash) @series_size = :stacked else @series_size = args.shift end if parent.kind_of?(Tk::Canvas) @path = parent.path else super(parent, *args) # create canvas widget end end @chart = _create_chart end def _create_chart p self.class::TkCommandNames[1] if $DEBUG tk_call_without_enc(self.class::TkCommandNames[1], @path, array2tk_list(@xlabels), array2tk_list(@ylabels), @series_size) end private :_create_chart def __destroy_hook__ Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.mutex.synchronize{ Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) } end def plot(series, dat, col=None) tk_call_without_enc(@chart, 'plot', series, dat, col) self end def colours(*cols) # set the colours to be used tk_call_without_enc(@chart, 'colours', *cols) self end alias colour colours alias colors colours alias color colours end ############################ class HorizontalBarchart < Barchart TkCommandNames = [ 'canvas'.freeze, '::Plotchart::createHorizontalBarchart'.freeze ].freeze end ############################ class Timechart < Tk::Canvas include ChartMethod TkCommandNames = [ 'canvas'.freeze, '::Plotchart::createTimechart'.freeze ].freeze def initialize(*args) # args := ([parent,] time_begin, time_end, items [, keys]) # time_begin := String of time format (e.g. "1 january 2004") # time_end := String of time format (e.g. "1 january 2004") # items := Expected/maximum number of items # ( This determines the vertical spacing. ) if args[0].kind_of?(String) @time_begin = args.shift @time_end = args.shift @items = args.shift super(*args) # create canvas widget else parent = args.shift @time_begin = args.shift @time_end = args.shift @items = args.shift if parent.kind_of?(Tk::Canvas) @path = parent.path else super(parent, *args) # create canvas widget end end @chart = _create_chart end def _create_chart p self.class::TkCommandNames[1] if $DEBUG tk_call_without_enc(self.class::TkCommandNames[1], @path, @time_begin, @time_end, @items) end private :_create_chart def period(txt, time_begin, time_end, col=None) tk_call_without_enc(@chart, 'period', txt, time_begin, time_end, col) self end def milestone(txt, time, col=None) tk_call_without_enc(@chart, 'milestone', txt, time, col) self end def vertline(txt, time) tk_call_without_enc(@chart, 'vertline', txt, time) self end end ############################ class Gnattchart < Tk::Canvas include ChartMethod TkCommandNames = [ 'canvas'.freeze, '::Plotchart::createGnattchart'.freeze ].freeze def initialize(*args) # args := ([parent,] time_begin, time_end, items [, text_width] [, keys]) # time_begin := String of time format (e.g. "1 january 2004") # time_end := String of time format (e.g. "1 january 2004") # items := Expected/maximum number of items # ( This determines the vertical spacing. ) if args[0].kind_of?(String) @time_begin = args.shift @time_end = args.shift @items = args.shift if args[0].kind_of?(Fixnum) @text_width = args.shift else @text_width = None end super(*args) # create canvas widget else parent = args.shift @time_begin = args.shift @time_end = args.shift @items = args.shift if args[0].kind_of?(Fixnum) @text_width = args.shift else @text_width = None end if parent.kind_of?(Tk::Canvas) @path = parent.path else super(parent, *args) # create canvas widget end end @chart = _create_chart end def _create_chart p self.class::TkCommandNames[1] if $DEBUG tk_call_without_enc(self.class::TkCommandNames[1], @path, @time_begin, @time_end, @items, @text_width) end private :_create_chart def task(txt, time_begin, time_end, completed=0.0) list(tk_call_without_enc(@chart, 'task', txt, time_begin, time_end, completed)).collect!{|id| TkcItem.id2obj(self, id) } end def milestone(txt, time, col=None) tk_call_without_enc(@chart, 'milestone', txt, time, col) self end def vertline(txt, time) tk_call_without_enc(@chart, 'vertline', txt, time) self end def connect(from_task, to_task) from_task = array2tk_list(from_task) if from_task.kind_of?(Array) to_task = array2tk_list(to_task) if to_task.kind_of?(Array) tk_call_without_enc(@chart, 'connect', from_task, to_task) self end def summary(txt, tasks) tasks = array2tk_list(tasks) if tasks.kind_of?(Array) tk_call_without_enc(@chart, 'summary', tasks) self end def color_of_part(keyword, newcolor) tk_call_without_enc(@chart, 'color', keyword, newcolor) self end def font_of_part(keyword, newfont) tk_call_without_enc(@chart, 'font', keyword, newfont) self end end ############################ class PlotSeries < TkObject SeriesID_TBL = TkCore::INTERP.create_table (Series_ID = ['series'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } TkCore::INTERP.init_ip_env{ SeriesID_TBL.mutex.synchronize{ SeriesID_TBL.clear } } def self.id2obj(chart, id) path = chart.path SeriesID_TBL.mutex.synchronize{ if SeriesID_TBL[path] SeriesID_TBL[path][id]? SeriesID_TBL[path][id]: id else id end } end def initialize(chart, keys=nil) @parent = @chart_obj = chart @ppath = @chart_obj.path Series_ID.mutex.synchronize{ @path = @series = @id = Series_ID.join(TkCore::INTERP._ip_id_) Series_ID[1].succ! } SeriesID_TBL.mutex.synchronize{ SeriesID_TBL[@ppath] ||= {} SeriesID_TBL[@ppath][@id] = self } dataconfig(keys) if keys.kind_of?(Hash) end def plot(*args) @chart_obj.plot(@series, *args) end def dataconfig(key, value=None) @chart_obj.dataconfig(@series, key, value) end end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/ruler.rb ================================================ # # tkextlib/tcllib/ruler.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * ruler widget # require 'tk' require 'tkextlib/tcllib.rb' # TkPackage.require('widget::ruler', '1.0') TkPackage.require('widget::ruler') module Tk::Tcllib module Widget class Ruler < TkWindow PACKAGE_NAME = 'widget::ruler'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('widget::ruler') rescue '' end end end end end class Tk::Tcllib::Widget::Ruler TkCommandNames = ['::widget::ruler'.freeze].freeze def __boolval_optkeys ['showvalues', 'outline', 'grid'] end private :__boolval_optkeys def __numlistval_optkeys ['interval', 'sizes'] end private :__numlistval_optkeys def create_self(keys) if keys and keys != None tk_call_without_enc(self.class::TkCommandNames[0], @path, *hash_kv(keys, true)) else tk_call_without_enc(self.class::TkCommandNames[0], @path) end end private :create_self def redraw tk_send('redraw') self end def shade(org, dest, frac) tk_send('shade', org, dest, frac) end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/screenruler.rb ================================================ # # tkextlib/tcllib/screenruler.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * screenruler dialog # require 'tk' require 'tkextlib/tcllib.rb' # TkPackage.require('widget::screenruler', '1.1') TkPackage.require('widget::screenruler') module Tk::Tcllib module Widget class ScreenRuler < TkWindow PACKAGE_NAME = 'widget::ruler'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('widget::screenruler') rescue '' end end end Screenruler = ScreenRuler end end class Tk::Tcllib::Widget::ScreenRuler TkCommandNames = ['::widget::screenruler'.freeze].freeze def __boolval_optkeys ['topmost', 'reflect'] end private :__boolval_optkeys def __numlistval_optkeys ['alpha'] end private :__numlistval_optkeys def create_self(keys) if keys and keys != None tk_call_without_enc(self.class::TkCommandNames[0], @path, *hash_kv(keys, true)) else tk_call_without_enc(self.class::TkCommandNames[0], @path) end end private :create_self def display tk_send('display') self end alias show display def hide tk_send('hide') self end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/scrollwin.rb ================================================ # # tkextlib/tcllib/scrollwin.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * Scrolled widget # require 'tk' require 'tkextlib/tcllib.rb' # TkPackage.require('widget::scrolledwindow', '1.0') TkPackage.require('widget::scrolledwindow') module Tk::Tcllib module Widget class ScrolledWindow < TkWindow PACKAGE_NAME = 'widget::scrolledwindow'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('widget::scrolledwindow') rescue '' end end end Scrolledwindow = ScrolledWindow end end class Tk::Tcllib::Widget::ScrolledWindow TkCommandNames = ['::widget::scrolledwindow'.freeze].freeze def __numlistval_optkeys ['ipad'] end private :__numlistval_optkeys def create_self(keys) if keys and keys != None tk_call_without_enc(self.class::TkCommandNames[0], @path, *hash_kv(keys, true)) else tk_call_without_enc(self.class::TkCommandNames[0], @path) end end private :create_self def get_frame window(tk_send('getframe')) end def set_widget(widget) tk_send('setwidget', widget) self end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/setup.rb ================================================ # # setup.rb -- setup script before calling TkPackage.require() # # If you need some setup operations (for example, add a library path # to the library search path) before using Tcl/Tk library packages # wrapped by Ruby scripts in this directory, please write the setup # operations in this file. # ================================================ FILE: ext/tk/lib/tkextlib/tcllib/style.rb ================================================ # # tkextlib/tcllib/style.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * select and use some 'style' of option (resource) DB # require 'tk' require 'tkextlib/tcllib.rb' module Tk::Tcllib module Style PACKAGE_NAME = 'style'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('style') rescue '' end end def self.not_available fail RuntimeError, "'tkextlib/tcllib/style' extension is not available on your current environment." end def self.names Tk::Tcllib::Style.not_available end def self.use(style) Tk::Tcllib::Style.not_available end end end # TkPackage.require('style', '0.1') # TkPackage.require('style', '0.3') TkPackage.require('style') module Tk::Tcllib class << Style undef not_available end module Style extend TkCore def self.names tk_split_simplelist(tk_call('style::names')) end def self.use(style) tk_call('style::use', style) end end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/superframe.rb ================================================ # # tkextlib/tcllib/superframe.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * Superframe widget - enhanced labelframe widget # require 'tk' require 'tkextlib/tcllib.rb' # TkPackage.require('widget::superframe', '1.0') TkPackage.require('widget::superframe') module Tk::Tcllib module Widget class SuperFrame < TkWindow PACKAGE_NAME = 'widget::superframe'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('widget::superframe') rescue '' end end end Superframe = SuperlFrame end end class Tk::Tcllib::Widget::SuperFrame TkCommandNames = ['::widget::superframe'.freeze].freeze def create_self(keys) if keys and keys != None tk_call_without_enc(self.class::TkCommandNames[0], @path, *hash_kv(keys, true)) else tk_call_without_enc(self.class::TkCommandNames[0], @path) end end private :create_self def labelwidget window(tk_send('labelwidget')) end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/swaplist.rb ================================================ # # tkextlib/tcllib/swaplist.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * A dialog which allows a user to move options between two lists # require 'tk' require 'tkextlib/tcllib.rb' # TkPackage.require('swaplist', '0.1') TkPackage.require('swaplist') module Tk::Tcllib class Swaplist_Dialog < TkWindow PACKAGE_NAME = 'swaplist'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('swaplist') rescue '' end end end end class Tk::Tcllib::Swaplist_Dialog TkCommandNames = ['::swaplist::swaplist'.freeze].freeze WidgetClassName = 'Swaplist'.freeze WidgetClassNames[WidgetClassName] = self def self.show(*args) dialog = self.new(*args) dialog.show [dialog.status, dialog.value] end def self.display(*args) self.show(*args) end def initialize(*args) # args = (parent=nil, complete_list=[], selected_list=[], keys=nil) keys = args.pop if keys.kind_of?(Hash) @selected_list = args.pop @complete_list = args.pop @keys = _symbolkey2str(keys) args.push(keys) else @selected_list = keys @complete_list = args.pop @keys = {} end @selected_list = [] unless @selected_list @complete_list = [] unless @complete_list @variable = TkVariable.new @status = nil super(*args) end def create_self(keys) # dummy end private :create_self def show @variable.value = '' @status = bool(tk_call(self.class::TkCommandNames[0], @path, @variable, @complete_list, @selected_list, *hash_kv(@keys))) end alias display show def status @status end def value @variable.list end alias selected value def cget_strict(slot) slot = slot.to_s if slot == 'complete_list' @complete_list elsif slot == 'selected_list' @selected_list else @keys[slot] end end def cget(slot) cget_strict(slot) end def configure(slot, value=None) if slot.kind_of?(Hash) slot.each{|k, v| configure(k, v)} else slot = slot.to_s value = _symbolkey2str(value) if value.kind_of?(Hash) if value && value != None if slot == 'complete_list' @complete_list = value elsif slot == 'selected_list' @selected_list = value else @keys[slot] = value end else if slot == 'complete_list' @complete_list = [] elsif slot == 'selected_list' @selected_list = [] else @keys.delete(slot) end end end self end def configinfo(slot = nil) if slot slot = slot.to_s if slot == 'complete_list' [ slot, nil, nil, nil, @complete_list ] elsif slot == 'selected_list' [ slot, nil, nil, nil, @selected_list ] else [ slot, nil, nil, nil, @keys[slot] ] end else @keys.collect{|k, v| [ k, nil, nil, nil, v ] } \ << [ 'complete_list', nil, nil, nil, @complete_list ] \ << [ 'selected_list', nil, nil, nil, @selected_list ] end end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/tablelist.rb ================================================ # # tkextlib/tcllib/tablelist.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * A multi-column listbox require 'tk' require 'tkextlib/tcllib.rb' # check Tile extension :: If already loaded, use tablelist_tile. unless defined? Tk::Tcllib::Tablelist_usingTile Tk::Tcllib::Tablelist_usingTile = TkPackage.provide('tile') end if Tk::Tcllib::Tablelist_usingTile # with Tile require 'tkextlib/tcllib/tablelist_tile' else # without Tile # TkPackage.require('Tablelist', '4.2') TkPackage.require('Tablelist') require 'tkextlib/tcllib/tablelist_core' end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/tablelist_core.rb ================================================ # # tkextlib/tcllib/tablelist_core.rb # # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * This file is required by 'tkextlib/tcllib/tablelist.rb' or # 'tkextlib/tcllib/tablelist_tile.rb'. # module Tk module Tcllib class Tablelist < TkWindow if Tk::Tcllib::Tablelist_usingTile PACKAGE_NAME = 'Tablelist_tile'.freeze else PACKAGE_NAME = 'Tablelist'.freeze end def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require(self.package_name) rescue '' end end def self.use_Tile? (Tk::Tcllib::Tablelist_usingTile)? true: false end end TableList = Tablelist end end module Tk::Tcllib::TablelistItemConfig include TkItemConfigMethod def _to_idx(idx) if idx.kind_of?(Array) idx.collect{|elem| _get_eval_string(elem)}.join(',') else idx end end def _from_idx(idx) return idx unless idx.kind_of?(String) if idx[0] == ?@ # '@x,y' idx elsif idx =~ /([^,]+),([^,]+)/ row = $1, column = $2 [num_or_str(row), num_or_str(column)] else num_or_str(idx) end end private :_to_idx, :_from_idx def __item_cget_cmd(mixed_id) [self.path, mixed_id[0] + 'cget', _to_idx(mixed_id[1])] end def __item_config_cmd(mixed_id) [self.path, mixed_id[0] + 'configure', _to_idx(mixed_id[1])] end def cell_cget(tagOrId, option) itemcget(['cell', tagOrId], option) end def cell_cget_strict(tagOrId, option) itemcget_strict(['cell', tagOrId], option) end def cell_configure(tagOrId, slot, value=None) itemconfigure(['cell', tagOrId], slot, value) end def cell_configinfo(tagOrId, slot=nil) itemconfiginfo(['cell', tagOrId], slot) end def current_cell_configinfo(tagOrId, slot=nil) current_itemconfiginfo(['cell', tagOrId], slot) end alias cellcget cell_cget alias cellcget_strict cell_cget_strict alias cellconfigure cell_configure alias cellconfiginfo cell_configinfo alias current_cellconfiginfo current_cell_configinfo def column_cget(tagOrId, option) itemcget(['column', tagOrId], option) end def column_cget_strict(tagOrId, option) itemcget_strict(['column', tagOrId], option) end def column_configure(tagOrId, slot, value=None) itemconfigure(['column', tagOrId], slot, value) end def column_configinfo(tagOrId, slot=nil) itemconfiginfo(['column', tagOrId], slot) end def current_column_configinfo(tagOrId, slot=nil) current_itemconfiginfo(['column', tagOrId], slot) end alias columncget column_cget alias columncget_strict column_cget_strict alias columnconfigure column_configure alias columnconfiginfo column_configinfo alias current_columnconfiginfo current_column_configinfo def row_cget(tagOrId, option) itemcget(['row', tagOrId], option) end def row_cget_strict(tagOrId, option) itemcget_strict(['row', tagOrId], option) end def row_configure(tagOrId, slot, value=None) itemconfigure(['row', tagOrId], slot, value) end def row_configinfo(tagOrId, slot=nil) itemconfiginfo(['row', tagOrId], slot) end def current_row_configinfo(tagOrId, slot=nil) current_itemconfiginfo(['row', tagOrId], slot) end alias rowcget row_cget alias rowcget_strict row_cget_strict alias rowconfigure row_configure alias rowconfiginfo row_configinfo alias current_rowconfiginfo current_row_configinfo private :itemcget, :itemcget_strict private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo end class Tk::Tcllib::Tablelist include Tk::Tcllib::TablelistItemConfig include Scrollable TkCommandNames = ['::tablelist::tablelist'.freeze].freeze WidgetClassName = 'Tablelist'.freeze WidgetClassNames[WidgetClassName] = self def create_self(keys) if keys and keys != None tk_call_without_enc(self.class::TkCommandNames[0], @path, *hash_kv(keys, true)) else tk_call_without_enc(self.class::TkCommandNames[0], @path) end end private :create_self ########################## def __numval_optkeys super() + ['titlecolumns'] end private :__numval_optkeys def __strval_optkeys super() + ['snipstring'] end private :__strval_optkeys def __boolval_optkeys super() + [ 'forceeditendcommand', 'movablecolumns', 'movablerows', 'protecttitlecolumns', 'resizablecolumns', 'showarrow', 'showlabels', 'showseparators' ] end private :__boolval_optkeys def __listval_optkeys super() + ['columns'] end private :__listval_optkeys def __tkvariable_optkeys super() + ['listvariable'] end private :__tkvariable_optkeys def __val2ruby_optkeys # { key=>proc, ... } # The method is used to convert a opt-value to a ruby's object. # When get the value of the option "key", "proc.call(value)" is called. super().update('stretch'=>proc{|v| (v == 'all')? v: simplelist(v)}) end private :__val2ruby_optkeys def __ruby2val_optkeys # { key=>proc, ... } # The method is used to convert a ruby's object to a opt-value. # When set the value of the option "key", "proc.call(value)" is called. # That is, "-#{key} #{proc.call(value)}". super().update('stretch'=>proc{|v| (v.kind_of?(Array))? v.collect{|e| _to_idx(e)}: v }) end private :__ruby2val_optkeys def __font_optkeys super() + ['labelfont'] end private :__font_optkeys ########################## def __item_strval_optkeys(id) if id[0] == 'cell' super(id) + ['title'] else super(id) - ['text'] + ['title'] end end private :__item_strval_optkeys def __item_boolval_optkeys(id) super(id) + [ 'editable', 'hide', 'resizable', 'showarrow', 'stretchable', ] end private :__item_boolval_optkeys def __item_listval_optkeys(id) if id[0] == 'cell' super(id) else super(id) + ['text'] end end private :__item_listval_optkeys def __item_font_optkeys(id) # maybe need to override super(id) + ['labelfont'] end private :__item_font_optkeys ########################## def activate(index) tk_send('activate', _to_idx(index)) self end def activate_cell(index) tk_send('activatecell', _to_idx(index)) self end alias activatecell activate_cell def get_attrib(name=nil) if name && name != None tk_send('attrib', name) else ret = [] lst = simplelist(tk_send('attrib')) until lst.empty? ret << ( [lst.shift] << lst.shift ) end ret end end def set_attrib(*args) tk_send('attrib', *(args.flatten)) self end def bbox(index) list(tk_send('bbox', _to_idx(index))) end def bodypath window(tk_send('bodypath')) end def bodytag TkBindTag.new_by_name(tk_send('bodytag')) end def cancel_editing tk_send('cancelediting') self end alias cancelediting cancel_editing def cellindex(idx) _from_idx(tk_send('cellindex', _to_idx(idx))) end def cellselection_anchor(idx) tk_send('cellselection', 'anchor', _to_idx(idx)) self end def cellselection_clear(first, last=nil) if first.kind_of?(Array) tk_send('cellselection', 'clear', first.collect{|idx| _to_idx(idx)}) else first = _to_idx(first) last = (last)? _to_idx(last): first tk_send('cellselection', 'clear', first, last) end self end def cellselection_includes(idx) bool(tk_send('cellselection', 'includes', _to_idx(idx))) end def cellselection_set(first, last=nil) if first.kind_of?(Array) tk_send('cellselection', 'set', first.collect{|idx| _to_idx(idx)}) else first = _to_idx(first) last = (last)? _to_idx(last): first tk_send('cellselection', 'set', first, last) end self end def columncount number(tk_send('columncount')) end def columnindex(idx) number(tk_send('columnindex', _to_idx(idx))) end def containing(y) idx = num_or_str(tk_send('containing', y)) (idx.kind_of?(Fixnum) && idx < 0)? nil: idx end def containing_cell(x, y) idx = _from_idx(tk_send('containingcell', x, y)) if idx.kind_of?(Array) [ ((idx[0].kind_of?(Fixnum) && idx[0] < 0)? nil: idx[0]), ((idx[1].kind_of?(Fixnum) && idx[1] < 0)? nil: idx[1]) ] else idx end end alias containingcell containing_cell def containing_column(x) idx = num_or_str(tk_send('containingcolumn', x)) (idx.kind_of?(Fixnum) && idx < 0)? nil: idx end alias containingcolumn containing_column def curcellselection simplelist(tk_send('curcellselection')).collect!{|idx| _from_idx(idx)} end def curselection list(tk_send('curselection')) end def delete_items(first, last=nil) if first.kind_of?(Array) tk_send('delete', first.collect{|idx| _to_idx(idx)}) else first = _to_idx(first) last = (last)? _to_idx(last): first tk_send('delete', first, last) end self end alias delete delete_items alias deleteitems delete_items def delete_columns(first, last=nil) if first.kind_of?(Array) tk_send('deletecolumns', first.collect{|idx| _to_idx(idx)}) else first = _to_idx(first) last = (last)? _to_idx(last): first tk_send('deletecolumns', first, last) end self end alias deletecolumns delete_columns def edit_cell(idx) tk_send('editcell', _to_idx(idx)) self end alias editcell edit_cell def editwinpath window(tk_send('editwinpath')) end def entrypath window(tk_send('entrypath')) end def fill_column(idx, txt) tk_send('fillcolumn', _to_idx(idx), txt) self end alias fillcolumn fill_column def finish_editing tk_send('finishediting') self end alias finishediting finish_editing def get(first, last=nil) if first.kind_of?(Array) simplelist(tk_send('get', first.collect{|idx| _to_idx(idx)})).collect!{|elem| simplelist(elem) } else first = _to_idx(first) last = (last)? _to_idx(last): first simplelist(tk_send('get', first, last)) end end def get_cells(first, last=nil) if first.kind_of?(Array) simplelist(tk_send('getcells', first.collect{|idx| _to_idx(idx)})).collect!{|elem| simplelist(elem) } else first = _to_idx(first) last = (last)? _to_idx(last): first simplelist(tk_send('getcells', first, last)) end end alias getcells get_cells def get_columns(first, last=nil) if first.kind_of?(Array) simplelist(tk_send('getcolumns', first.collect{|idx| _to_idx(idx)})).collect!{|elem| simplelist(elem) } else first = _to_idx(first) last = (last)? _to_idx(last): first simplelist(tk_send('getcolumns', first, last)) end end alias getcolumns get_columns def get_keys(first, last=nil) if first.kind_of?(Array) simplelist(tk_send('getkeys', first.collect{|idx| _to_idx(idx)})).collect!{|elem| simplelist(elem) } else first = _to_idx(first) last = (last)? _to_idx(last): first simplelist(tk_send('getkeys', first, last)) end end alias getkeys get_keys def imagelabelpath(idx) window(tk_send('imagelabelpath', _to_idx(idx))) end def index(idx) number(tk_send('index', _to_idx(idx))) end def insert(idx, *items) tk_send('insert', _to_idx(idx), *items) self end def insert_columnlist(idx, columnlist) tk_send('insertcolumnlist', _to_idx(idx), columnlist) self end alias insertcolumnlist insert_columnlist def insert_columns(idx, *args) tk_send('insertcolums', _to_idx(idx), *args) self end alias insertcolumns insert_columns def insert_list(idx, list) tk_send('insertlist', _to_idx(idx), list) self end alias insertlist insert_list def itemlistvar TkVarAccess.new(tk_send('itemlistvar')) end def labelpath(idx) window(tk_send('labelpath', _to_idx(idx))) end def labels simplelist(tk_send('labels')) end def move(src, target) tk_send('move', _to_idx(src), _to_idx(target)) self end def move_column(src, target) tk_send('movecolumn', _to_idx(src), _to_idx(target)) self end alias movecolumn move_column def nearest(y) _from_idx(tk_send('nearest', y)) end def nearest_cell(x, y) _from_idx(tk_send('nearestcell', x, y)) end alias nearestcell nearest_cell def nearest_column(x) _from_idx(tk_send('nearestcolumn', x)) end alias nearestcolumn nearest_column def reject_input tk_send('rejectinput') self end alias rejectinput reject_input def reset_sortinfo tk_send('resetsortinfo') self end alias resetsortinfo reset_sortinfo def scan_mark(x, y) tk_send('scan', 'mark', x, y) self end def scan_dragto(x, y) tk_send('scan', 'dragto', x, y) self end def see(idx) tk_send('see', _to_idx(idx)) self end def see_cell(idx) tk_send('seecell', _to_idx(idx)) self end alias seecell see_cell def see_column(idx) tk_send('seecolumn', _to_idx(idx)) self end alias seecolumn see_column def selection_anchor(idx) tk_send('selection', 'anchor', _to_idx(idx)) self end def selection_clear(first, last=nil) if first.kind_of?(Array) tk_send('selection', 'clear', first.collect{|idx| _to_idx(idx)}) else first = _to_idx(first) last = (last)? _to_idx(last): first tk_send('selection', 'clear', first, last) end self end def selection_includes(idx) bool(tk_send('selection', 'includes', _to_idx(idx))) end def selection_set(first, last=nil) if first.kind_of?(Array) tk_send('selection', 'set', first.collect{|idx| _to_idx(idx)}) else first = _to_idx(first) last = (last)? _to_idx(last): first tk_send('selection', 'set', first, last) end self end def separatorpath(idx=nil) if idx window(tk_send('separatorpath', _to_idx(idx))) else window(tk_send('separatorpath')) end end def separators simplelist(tk_send('separators')).collect!{|w| window(w)} end def size number(tk_send('size')) end def sort(order=nil) if order order = order.to_s order = '-' << order if order[0] != ?- if order.length < 2 order = nil end end if order tk_send('sort', order) else tk_send('sort') end self end def sort_increasing tk_send('sort', '-increasing') self end def sort_decreasing tk_send('sort', '-decreasing') self end DEFAULT_sortByColumn_cmd = '::tablelist::sortByColumn' def sort_by_column(idx, order=nil) if order order = order.to_s order = '-' << order if order[0] != ?- if order.length < 2 order = nil end end if order tk_send('sortbycolumn', _to_idx(idx), order) else tk_send('sortbycolumn', _to_idx(idx)) end self end def sort_by_column_increasing(idx) tk_send('sortbycolumn', _to_idx(idx), '-increasing') self end def sort_by_column_decreasing(idx) tk_send('sortbycolumn', _to_idx(idx), '-decreasing') self end def sortcolumn idx = num_or_str(tk_send('sortcolum')) (idx.kind_of?(Fixnum) && idx < 0)? nil: idx end def sortorder tk_send('sortorder') end def toggle_visibility(first, last=nil) if first.kind_of?(Array) tk_send('togglevisibility', first.collect{|idx| _to_idx(idx)}) else first = _to_idx(first) last = (last)? _to_idx(last): first tk_send('togglevisibility', first, last) end self end alias togglevisibility toggle_visibility def windowpath(idx) window(tk_send('windowpath', _to_idx(idx))) end end class << Tk::Tcllib::Tablelist ############################################################ # helper commands def getTablelistPath(descendant) window(Tk.tk_call('::tablelist::getTablelistPath', descendant)) end def convEventFields(descendant, x, y) window(Tk.tk_call('::tablelist::convEventFields', descendant, x, y)) end ############################################################ # with the BWidget package def addBWidgetEntry(name=None) Tk.tk_call('::tablelist::addBWidgetEntry', name) end def addBWidgetSpinBox(name=None) Tk.tk_call('::tablelist::addBWidgetSpinBox', name) end def addBWidgetComboBox(name=None) Tk.tk_call('::tablelist::addBWidgetComboBox', name) end ############################################################ # with the Iwidgets ([incr Widgets]) package def addIncrEntryfield(name=None) Tk.tk_call('::tablelist::addIncrEntry', name) end def addIncrDateTimeWidget(type, seconds=false, name=None) # type := 'datefield'|'dateentry'|timefield'|'timeentry' if seconds && seconds != None seconds = '-seconds' else seconds = None end Tk.tk_call('::tablelist::addDateTimeWidget', type, seconds, name) end def addIncrSpinner(name=None) Tk.tk_call('::tablelist::addIncrSpinner', name) end def addIncrSpinint(name=None) Tk.tk_call('::tablelist::addIncrSpinint', name) end def addIncrCombobox(name=None) Tk.tk_call('::tablelist::addIncrCombobox', name) end ############################################################ # with Bryan Oakley's combobox package def addOakleyCombobox(name=None) Tk.tk_call('::tablelist::addOakleyCombobox', name) end ############################################################ # with the multi-entry package Mentry is a library extension def addDateMentry(format, separator, gmt=false, name=None) if gmt && gmt != None gmt = '-gmt' else gmt = None end Tk.tk_call('::tablelist::addDateMentry', format, separator, gmt, name) end def addTimeMentry(format, separator, gmt=false, name=None) if gmt && gmt != None gmt = '-gmt' else gmt = None end Tk.tk_call('::tablelist::addTimeMentry', format, separator, gmt, name) end def addFixedPointMentry(count1, count2, comma=false, name=None) if comma && comma != None comma = '-comma' else comma = None end Tk.tk_call('::tablelist::addFixedPoingMentry', count1, count2, comma, name) end def addIPAddrMentry(name=None) Tk.tk_call('::tablelist::addIPAddrMentry', name) end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/tablelist_tile.rb ================================================ # # tkextlib/tcllib/tablelist_tlie.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * A multi-column listbox require 'tk' require 'tkextlib/tcllib.rb' # TkPackage.require('tablelist_tile', '4.2') TkPackage.require('Tablelist_tile') unless defined? Tk::Tcllib::Tablelist_usingTile Tk::Tcllib::Tablelist_usingTile = true end requrie 'tkextlib/tcllib/tablelist_core' module Tk module Tcllib Tablelist_Tile = Tablelist TableList_Tile = Tablelist end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/tkpiechart.rb ================================================ # # tkextlib/tcllib/tkpiechart.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * Create 2D or 3D pies with labels in Tcl canvases # require 'tk' require 'tk/canvas' require 'tkextlib/tcllib.rb' # TkPackage.require('tkpiechart', '6.6') TkPackage.require('tkpiechart') module Tk module Tcllib module Tkpiechart end end end module Tk::Tcllib::Tkpiechart PACKAGE_NAME = 'tkpiechart'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('tkpiechart') rescue '' end end module ConfigMethod include TkConfigMethod def __pathname self.path + ';' + self.tag end private :__pathname def __cget_cmd ['::switched::cget', self.tag] end def __config_cmd ['::switched::configure', self.tag] end private :__config_cmd def __configinfo_struct {:key=>0, :alias=>nil, :db_name=>nil, :db_class=>nil, :default_value=>1, :current_value=>2} end private :__configinfo_struct def __boolval_optkeys super() << 'select' << 'autoupdate' << 'selectable' end private :__boolval_optkeys def __strval_optkeys super() << 'bordercolor' << 'textbackground' << 'widestvaluetext' << 'title' end private :__strval_optkeys def __listval_optkeys super() << 'colors' end private :__listval_optkeys end #################################### class PieChartObj < TkcItem include ConfigMethod def __font_optkeys ['titlefont'] end private :__font_optkeys end #################################### class Pie < TkcItem include ConfigMethod def create_self(x, y, width, height, keys=None) if keys and keys != None @tag_key = tk_call_without_enc('::stooop::new', 'pie', @c, x, y, *hash_kv(keys, true)) else @tag_key = tk_call_without_enc('::stooop::new', 'pie', @c, x, y) end @slice_tbl = {} id = "pie(#{@tag_key})" @tag = @tag_pie = TkcNamedTag(@c, id) @tag_slices = TkcNamedTag(@c, "pieSlices(#{@tag_key})") id end private :create_self def tag_key @tag_key end def tag @tag end def canvas @c end def _entry_slice(slice) @slice_tbl[slice.to_eval] = slice end def _delete_slice(slice) @slice_tbl.delete(slice.to_eval) end def delete tk_call_without_enc('::stooop::delete', @tag_key) CItemID_TBL.mutex.synchronize{ CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] } self end def new_slice(text=None) Slice.new(self, text) end def delete_slice(slice) unless slice.kind_of?(Slice) unless (slice = @slice_tbl[slice]) return tk_call_without_enc('pie::deleteSlice', @tag_key, slice) end end unless slice.kind_of?(Slice) && slice.pie == self fail ArgumentError, "argument is not a slice of self" end slice.delete end def selected_slices tk_split_simplelist(tk_call_without_enc('pie::selectedSlices', @tag_key)).collect{|slice| @slice_tbl[slice] || Slice.new(:no_create, self, slice) } end end #################################### class Slice < TkcItem include ConfigMethod def __config_cmd ['::switched::configure', self.tag] end private :__config_cmd #------------------------ def initialize(pie, *args) unless pie.kind_of?(Pie) && pie != :no_create fail ArgumentError, "expects TkPiechart::Pie for 1st argument" end if pie == :no_create @pie, @tag_key = args else text = args[0] || None @pie = pie @tag_key = tk_call_without_enc('pie::newSlice', @pie.tag_key, text) end @parent = @c = @pie.canvas @path = @parent.path @pie._entry_slice(self) @id = "slices(#{@tag_key})" @tag = TkcNamedTag.new(@pie.canvas, @id) CItemID_TBL.mutex.synchronize{ CItemID_TBL[@path] = {} unless CItemID_TBL[@path] CItemID_TBL[@path][@id] = self } end def tag_key @tag_key end def tag @tag end def pie @pie end def delete tk_call_without_enc('pie::deleteSlice', @pie.tag_key, @tag_key) CItemID_TBL.mutex.synchronize{ CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] } @pie._delete_slice(self) self end def size(share, disp=None) tk_call_without_enc('pie::sizeSlice', @pie.tag_key, @tag_key, share, disp) self end def label(text) tk_call_without_enc('pie::labelSlice', @pie.tag_key, @tag_key, text) self end end #################################### class BoxLabeler < TkcItem include ConfigMethod def __config_cmd ['::switched::configure', self.tag] end private :__config_cmd #------------------------ def create_self(keys=None) if keys and keys != None @tag_key = tk_call_without_enc('::stooop::new', 'pieBoxLabeler', *hash_kv(keys, true)) else @tag_key = tk_call_without_enc('::stooop::new', 'pieBoxLabeler') end id = "pieBoxLabeler(#{@tag_key})" @tag = TkcNamedTag(@c, id) id end private :create_self end #################################### class PeripheralLabeler < TkcItem include ConfigMethod def __font_optkeys ['font', 'smallfont'] end private :__font_optkeys def __config_cmd ['::switched::configure', self.tag] end private :__config_cmd #------------------------ def create_self(keys=None) if keys and keys != None @tag_key = tk_call_without_enc('::stooop::new', 'piePeripheralLabeler', *hash_kv(keys, true)) else @tag_key = tk_call_without_enc('::stooop::new', 'piePeripheralLabeler') end id = "piePeripheralLabeler(#{@tag_key})" @tag = TkcNamedTag(@c, id) id end private :create_self end #################################### class Label < TkcItem include ConfigMethod def __config_cmd ['::switched::configure', self.tag] end private :__config_cmd #------------------------ def create_self(x, y, keys=None) if keys and keys != None @tag_key = tk_call_without_enc('::stooop::new', 'canvasLabel', @c, x, y, width, height, *hash_kv(keys, true)) else @tag_key = tk_call_without_enc('::stooop::new', 'canvasLabel', @c, x, y, width, height) end id = "canvasLabel(#{@tag_key})" @tag = TkcNamedTag(@c, id) id end private :create_self end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/tooltip.rb ================================================ # # tkextlib/tcllib/tooltip.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * Provides tooltips, a small text message that is displayed when the # mouse hovers over a widget. # require 'tk' require 'tkextlib/tcllib.rb' # TkPackage.require('tooltip', '1.1') TkPackage.require('tooltip') module Tk::Tcllib module Tooltip PACKAGE_NAME = 'tooltip'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('tooltip') rescue '' end end end end module Tk::Tcllib::Tooltip extend TkCore WidgetClassName = 'Tooltip'.freeze def self.database_classname self::WidgetClassName end def self.database_class WidgetClassNames[self::WidgetClassName] end def self.clear(glob_path_pat = None) self.clear_glob(glob_path_pat) end def self.clear_glob(glob_path_pat) tk_call_without_enc('::tooltip::tooltip', 'clear', glob_path_pat) end def self.clear_widgets(*args) self.clear_glob("{#{args.collect{|w| _get_eval_string(w)}.join(',')}}") end def self.clear_children(*args) self.clear_glob("{#{args.collect{|w| s = _get_eval_string(w); "#{s},#{s}.*"}.join(',')}}") end def self.delay(millisecs=None) number(tk_call_without_enc('::tooltip::tooltip', 'delay', millisecs)) end def self.delay=(millisecs) self.delay(millisecs) end def self.disable tk_call_without_enc('::tooltip::tooltip', 'disable') false end def self.off self.disable end def self.enable tk_call_without_enc('::tooltip::tooltip', 'enable') true end def self.on self.enable end def self.register(widget, msg, keys=nil) if keys.kind_of?(Hash) args = hash_kv(keys) << msg else args = msg end tk_call_without_enc('::tooltip::tooltip', widget.path, *args) end def self.erase(widget) tk_call_without_enc('::tooltip::tooltip', widget.path, '') end end ================================================ FILE: ext/tk/lib/tkextlib/tcllib/widget.rb ================================================ # # tkextlib/tcllib/widget.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # * Part of tcllib extension # * megawidget package that uses snit as the object system (snidgets) # require 'tk' require 'tkextlib/tcllib.rb' # TkPackage.require('widget', '3.0') TkPackage.require('widget') module Tk::Tcllib module Widget PACKAGE_NAME = 'widget'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('widget') rescue '' end end end end module Tk::Tcllib::Widget autoload :Dialog, 'tkextlib/tcllib/dialog' autoload :Panelframe, 'tkextlib/tcllib/panelframe' autoload :PanelFrame, 'tkextlib/tcllib/panelframe' autoload :Ruler, 'tkextlib/tcllib/ruler' autoload :Screenruler, 'tkextlib/tcllib/screenruler' autoload :ScreenRuler, 'tkextlib/tcllib/screenruler' autoload :Scrolledwindow, 'tkextlib/tcllib/scrollwin' autoload :ScrolledWindow, 'tkextlib/tcllib/scrollwin' autoload :Superframe, 'tkextlib/tcllib/superframe' autoload :SuperFrame, 'tkextlib/tcllib/superframe' end ================================================ FILE: ext/tk/lib/tkextlib/tcllib.rb ================================================ # # tcllib extension support # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/tcllib/setup.rb' err = '' # package:: autoscroll target = 'tkextlib/tcllib/autoscroll' begin require target rescue => e err << "\n ['" << target << "'] " << e.class.name << ' : ' << e.message end # package:: cursor target = 'tkextlib/tcllib/cursor' begin require target rescue => e err << "\n ['" << target << "'] " << e.class.name << ' : ' << e.message end # package:: style target = 'tkextlib/tcllib/style' begin require target rescue => e err << "\n ['" << target << "'] " << e.class.name << ' : ' << e.message end # autoload module Tk module Tcllib TkComm::TkExtlibAutoloadModule.unshift(self) # package:: ctext autoload :CText, 'tkextlib/tcllib/ctext' # package:: getstring autoload :GetString_Dialog, 'tkextlib/tcllib/getstring' # package:: history autoload :History, 'tkextlib/tcllib/history' # package:: datefield autoload :Datefield, 'tkextlib/tcllib/datefield' autoload :DateField, 'tkextlib/tcllib/datefield' # package:: ico autoload :ICO, 'tkextlib/tcllib/ico' # package:: ipentry autoload :IP_Entry, 'tkextlib/tcllib/ip_entry' autoload :IPEntry, 'tkextlib/tcllib/ip_entry' # package:: swaplist autoload :Swaplist_Dialog, 'tkextlib/tcllib/swaplist' # package:: Plotchart autoload :Plotchart, 'tkextlib/tcllib/plotchart' # package:: tablelist autoload :Tablelist, 'tkextlib/tcllib/tablelist' autoload :TableList, 'tkextlib/tcllib/tablelist' autoload :Tablelist_Tile, 'tkextlib/tcllib/tablelist_tile' autoload :TableList_Tile, 'tkextlib/tcllib/tablelist_tile' # package:: tkpiechart autoload :Tkpiechart, 'tkextlib/tcllib/tkpiechart' # package:: tooltip autoload :Tooltip, 'tkextlib/tcllib/tooltip' # package:: widget autoload :Wdiget, 'tkextlib/tcllib/widget' end end if $VERBOSE && !err.empty? warn("Warning: some sub-packages are failed to require : " + err) end ================================================ FILE: ext/tk/lib/tkextlib/tclx/setup.rb ================================================ # # setup.rb -- setup script before calling TkPackage.require() # # If you need some setup operations (for example, add a library path # to the library search path) before using Tcl/Tk library packages # wrapped by Ruby scripts in this directory, please write the setup # operations in this file. # ================================================ FILE: ext/tk/lib/tkextlib/tclx/tclx.rb ================================================ # # tclx/tclx.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/tclx/setup.rb' # TkPackage.require('Tclx', '8.0') TkPackage.require('Tclx') module Tk module TclX PACKAGE_NAME = 'Tclx'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('Tclx') rescue '' end end def self.infox(*args) Tk.tk_call('infox', *args) end def self.signal(*args) warn("Warning: Don't recommend to use TclX's 'signal' command. Please use Ruby's 'Signal.trap' method") Tk.tk_call('signal', *args) end def self.signal_restart(*args) warn("Warning: Don't recommend to use TclX's 'signal' command. Please use Ruby's 'Signal.trap' method") Tk.tk_call('signal', '-restart', *args) end ############################## class XPG3_MsgCat class << self alias open new end def initialize(catname, fail_mode=false) if fail_mode @msgcat_id = Tk.tk_call('catopen', '-fail', catname) else @msgcat_id = Tk.tk_call('catopen', '-nofail', catname) end end def close(fail_mode=false) if fail_mode Tk.tk_call('catclose', '-fail', @msgcat_id) else Tk.tk_call('catclose', '-nofail', @msgcat_id) end self end def get(setnum, msgnum, defaultstr) Tk.tk_call('catgets', @msgcat_id, setnum, msgnum, defaultstr) end end end end ================================================ FILE: ext/tk/lib/tkextlib/tclx.rb ================================================ # # TclX support # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/tclx/setup.rb' # load library require 'tkextlib/tclx/tclx' ================================================ FILE: ext/tk/lib/tkextlib/tile/dialog.rb ================================================ # # ttk::dialog (tile-0.7+) # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile class Dialog < TkWindow end end end class Tk::Tile::Dialog TkCommandNames = ['::ttk::dialog'.freeze].freeze def self.show(*args) dialog = self.new(*args) dialog.show [dialog.status, dialog.value] end def self.display(*args) self.show(*args) end def self.define_dialog_type(name, keys) Tk.tk_call('::ttk::dialog::define', name, keys) name end def self.style(*args) ['Dialog', *(args.map!{|a| _get_eval_string(a)})].join('.') end ######################### def initialize(keys={}) @keys = _symbolkey2str(keys) super(*args) end def create_self(keys) # dummy end private :create_self def show tk_call(self.class::TkCommandNames[0], @path, *hash_kv(@keys)) end alias display show def client_frame window(tk_call_without_enc('::ttk::dialog::clientframe', @path)) end def cget_strict(slot) @keys[slot.to_s] end def cget(slot) @keys[slot.to_s] end =begin def cget(slot) unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ cget_strict(slot) else cget_strict(slot) rescue nil end end =end def configure(slot, value=None) if slot.kind_of?(Hash) slot.each{|k, v| configure(k, v)} else slot = slot.to_s value = _symbolkey2str(value) if value.kind_of?(Hash) if value && value != None @keys[slot] = value else @keys.delete(slot) end end self end def configinfo(slot = nil) if slot slot = slot.to_s [ slot, nil, nil, nil, @keys[slot] ] else @keys.collect{|k, v| [ k, nil, nil, nil, v ] } end end end ================================================ FILE: ext/tk/lib/tkextlib/tile/setup.rb ================================================ # # setup.rb -- setup script before calling TkPackage.require() # # If you need some setup operations (for example, add a library path # to the library search path) before using Tcl/Tk library packages # wrapped by Ruby scripts in this directory, please write the setup # operations in this file. # ================================================ FILE: ext/tk/lib/tkextlib/tile/sizegrip.rb ================================================ # # ttk::sizegrip widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile class SizeGrip < TkWindow end Sizegrip = SizeGrip end end Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Sizegrip, :TkSizegrip, :TkSizeGrip) class Tk::Tile::SizeGrip < TkWindow include Tk::Tile::TileWidget TkCommandNames = ['::ttk::sizegrip'.freeze].freeze WidgetClassName = 'TSizegrip'.freeze WidgetClassNames[WidgetClassName] = self def self.style(*args) [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end end ================================================ FILE: ext/tk/lib/tkextlib/tile/style.rb ================================================ # # style commands # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile module Style end end end module Tk::Tile::Style extend TkCore end class << Tk::Tile::Style if Tk::Tile::TILE_SPEC_VERSION_ID < 8 TkCommandNames = ['style'.freeze].freeze # --- Tk::Tile::Style.__define_wrapper_proc_for_compatibility__! --- # On Ttk (Tile) extension, 'style' command has imcompatible changes # depend on the version of the extention. It requires modifying the # Tcl/Tk scripts to define local styles. The rule for modification # is a simple one. But, if users want to keep compatibility between # versions of the extension, they will have to contrive to do that. # It may be troublesome, especially for Ruby/Tk users. # This method may help such work. This method make some definitions # on the Tcl/Tk interpreter to work with different version of style # command format. Please give attention to use this method. It may # conflict with some definitions on Tcl/Tk scripts. if Tk::Tile::TILE_SPEC_VERSION_ID < 7 def __define_wrapper_proc_for_compatibility__! __define_themes_and_setTheme_proc__! unless Tk.info(:commands, '::ttk::style').empty? # fail RuntimeError, # "can't define '::ttk::style' command (already exist)" # do nothing !!! warn "Warning: can't define '::ttk::style' command (already exist)" if $DEBUG return end TkCore::INTERP.add_tk_procs('::ttk::style', 'args', <<-'EOS') if [string equal [lrange $args 0 1] {element create}] { if [string equal [lindex $args 3] image] { set spec [lindex $args 4] set map [lrange $spec 1 end] if [llength $map] { # return [eval [concat [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]]] return [uplevel 1 [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]] } } } # return [eval "::style $args"] return [uplevel 1 ::style $args] EOS ######################### end else ### TILE_SPEC_VERSION_ID == 7 def __define_wrapper_proc_for_compatibility__! __define_themes_and_setTheme_proc__! unless Tk.info(:commands, '::ttk::style').empty? # fail RuntimeError, # "can't define '::ttk::style' command (already exist)" # do nothing !!! warn "Warning: can't define '::ttk::style' command (already exist)" if $DEBUG return end TkCore::INTERP.add_tk_procs('::ttk::style', 'args', <<-'EOS') if [string equal [lrange $args 0 1] {element create}] { if [string equal [lindex $args 3] image] { set spec [lindex $args 4] set map [lrange $spec 1 end] if [llength $map] { # return [eval [concat [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]]] return [uplevel 1 [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]]] } } } elseif [string equal [lindex $args 0] default] { # return [eval "::style [lreplace $args 0 0 configure]"] return [uplevel 1 ::style [lreplace $args 0 0 configure]] } # return [eval "::style $args"] return [uplevel 1 ::style $args] EOS ######################### end end else ### TILE_SPEC_VERSION_ID >= 8 TkCommandNames = ['::ttk::style'.freeze].freeze def __define_wrapper_proc_for_compatibility__! __define_themes_and_setTheme_proc__! unless Tk.info(:commands, '::style').empty? # fail RuntimeError, "can't define '::style' command (already exist)" # do nothing !!! warn "Warning: can't define '::style' command (already exist)" if $DEBUG return end TkCore::INTERP.add_tk_procs('::style', 'args', <<-'EOS') if [string equal [lrange $args 0 1] {element create}] { if [string equal [lindex $args 3] image] { set name [lindex $args 4] set opts [lrange $args 5 end] set idx [lsearch $opts -map] if {$idx >= 0 && [expr $idx % 2 == 0]} { # return [eval [concat [list ::ttk::style element create [lindex $args 2] image [concat $name [lindex $opts [expr $idx + 1]]]] [lreplace $opts $idx [expr $idx + 1]]]] return [uplevel 1 [list ::ttk::style element create [lindex $args 2] image [concat $name [lindex $opts [expr $idx + 1]]]] [lreplace $opts $idx [expr $idx + 1]]] } } } elseif [string equal [lindex $args 0] default] { # return [eval "::ttk::style [lreplace $args 0 0 configure]"] return [uplevel 1 ::ttk::style [lreplace $args 0 0 configure]] } # return [eval "::ttk::style $args"] return [uplevel 1 ::ttk::style $args] EOS ######################### end end def __define_themes_and_setTheme_proc__! TkCore::INTERP.add_tk_procs('::ttk::themes', '{ptn *}', <<-'EOS') #set themes [list] set themes [::ttk::style theme names] foreach pkg [lsearch -inline -all -glob [package names] ttk::theme::$ptn] { set theme [namespace tail $pkg] if {[lsearch -exact $themes $theme] < 0} { lappend themes $theme } } foreach pkg [lsearch -inline -all -glob [package names] tile::theme::$ptn] { set theme [namespace tail $pkg] if {[lsearch -exact $themes $theme] < 0} { lappend themes $theme } } return $themes EOS ######################### TkCore::INTERP.add_tk_procs('::ttk::setTheme', 'theme', <<-'EOS') variable currentTheme if {[lsearch -exact [::ttk::style theme names] $theme] < 0} { package require [lsearch -inline -regexp [package names] (ttk|tile)::theme::$theme] } ::ttk::style theme use $theme set currentTheme $theme EOS end private :__define_themes_and_setTheme_proc__! def configure(style=nil, keys=nil) if style.kind_of?(Hash) keys = style style = nil end style = '.' unless style if Tk::Tile::TILE_SPEC_VERSION_ID < 7 sub_cmd = 'default' else sub_cmd = 'configure' end if keys && keys != None tk_call(TkCommandNames[0], sub_cmd, style, *hash_kv(keys)) else tk_call(TkCommandNames[0], sub_cmd, style) end end alias default configure def map(style=nil, keys=nil) if style.kind_of?(Hash) keys = style style = nil end style = '.' unless style if keys && keys != None if keys.kind_of?(Hash) tk_call(TkCommandNames[0], 'map', style, *hash_kv(keys)) else simplelist(tk_call(TkCommandNames[0], 'map', style, '-' << keys.to_s)) end else ret = {} Hash[*(simplelist(tk_call(TkCommandNames[0], 'map', style)))].each{|k, v| ret[k[1..-1]] = list(v) } ret end end alias map_configure map def map_configinfo(style=nil, key=None) style = '.' unless style map(style, key) end def map_default_configinfo(key=None) map('.', key) end def lookup(style, opt, state=None, fallback_value=None) tk_call(TkCommandNames[0], 'lookup', style, '-' << opt.to_s, state, fallback_value) end include Tk::Tile::ParseStyleLayout def layout(style=nil, spec=nil) if style.kind_of?(Hash) spec = style style = nil end style = '.' unless style if spec tk_call(TkCommandNames[0], 'layout', style, spec) else _style_layout(list(tk_call(TkCommandNames[0], 'layout', style))) end end def element_create(name, type, *args) if type == 'image' || type == :image element_create_image(name, *args) else tk_call(TkCommandNames[0], 'element', 'create', name, type, *args) end end def element_create_image(name, *args) fail ArgumentError, 'Must supply a base image' unless (spec = args.shift) if (opts = args.shift) if opts.kind_of?(Hash) opts = _symbolkey2str(opts) else fail ArgumentError, 'bad option' end end fail ArgumentError, 'too many arguments' unless args.empty? if spec.kind_of?(Array) # probably, command format is tile 0.8+ (Tcl/Tk8.5+) style if Tk::Tile::TILE_SPEC_VERSION_ID >= 8 if opts tk_call(TkCommandNames[0], 'element', 'create', name, 'image', spec, opts) else tk_call(TkCommandNames[0], 'element', 'create', name, 'image', spec) end else fail ArgumentError, 'illegal arguments' if opts.key?('map') base = spec.shift opts['map'] = spec tk_call(TkCommandNames[0], 'element', 'create', name, 'image', base, opts) end else # probably, command format is tile 0.7.8 or older style if Tk::Tile::TILE_SPEC_VERSION_ID >= 8 spec = [spec, *(opts.delete('map'))] if opts.key?('map') end if opts tk_call(TkCommandNames[0], 'element', 'create', name, 'image', spec, opts) else tk_call(TkCommandNames[0], 'element', 'create', name, 'image', spec) end end end def element_names() list(tk_call(TkCommandNames[0], 'element', 'names')) end def element_options(elem) simplelist(tk_call(TkCommandNames[0], 'element', 'options', elem)) end def theme_create(name, keys=nil) name = name.to_s if keys && keys != None tk_call(TkCommandNames[0], 'theme', 'create', name, *hash_kv(keys)) else tk_call(TkCommandNames[0], 'theme', 'create', name) end name end def theme_settings(name, cmd=nil, &b) name = name.to_s cmd = Proc.new(&b) if !cmd && b tk_call(TkCommandNames[0], 'theme', 'settings', name, cmd) name end def theme_names() list(tk_call(TkCommandNames[0], 'theme', 'names')) end def theme_use(name) name = name.to_s tk_call(TkCommandNames[0], 'theme', 'use', name) name end end ================================================ FILE: ext/tk/lib/tkextlib/tile/tbutton.rb ================================================ # # tbutton widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile class TButton < Tk::Button end Button = TButton end end Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Button, :TkButton) class Tk::Tile::TButton < Tk::Button include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE TkCommandNames = ['::ttk::button'.freeze].freeze else TkCommandNames = ['::tbutton'.freeze].freeze end WidgetClassName = 'TButton'.freeze WidgetClassNames[WidgetClassName] = self def self.style(*args) [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end end ================================================ FILE: ext/tk/lib/tkextlib/tile/tcheckbutton.rb ================================================ # # tcheckbutton widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile class TCheckButton < Tk::CheckButton end TCheckbutton = TCheckButton CheckButton = TCheckButton Checkbutton = TCheckButton end end Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Checkbutton, :TkCheckbutton, :TkCheckButton) class Tk::Tile::TCheckButton < Tk::CheckButton include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE TkCommandNames = ['::ttk::checkbutton'.freeze].freeze else TkCommandNames = ['::tcheckbutton'.freeze].freeze end WidgetClassName = 'TCheckbutton'.freeze WidgetClassNames[WidgetClassName] = self def self.style(*args) [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end end ================================================ FILE: ext/tk/lib/tkextlib/tile/tcombobox.rb ================================================ # # tcombobox widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile class TCombobox < Tk::Tile::TEntry end Combobox = TCombobox end end Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Combobox, :TkCombobox) class Tk::Tile::TCombobox < Tk::Tile::TEntry include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE TkCommandNames = ['::ttk::combobox'.freeze].freeze else TkCommandNames = ['::tcombobox'.freeze].freeze end WidgetClassName = 'TCombobox'.freeze WidgetClassNames[WidgetClassName] = self def __boolval_optkeys super() << 'exportselection' end private :__boolval_optkeys def __listval_optkeys super() << 'values' end private :__listval_optkeys def self.style(*args) [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end def current number(tk_send_without_enc('current')) end def current=(idx) tk_send_without_enc('current', idx) end def set(val) tk_send('set', val) end end ================================================ FILE: ext/tk/lib/tkextlib/tile/tentry.rb ================================================ # # tentry widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile class TEntry < Tk::Entry end Entry = TEntry end end Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Entry, :TkEntry) class Tk::Tile::TEntry < Tk::Entry include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE TkCommandNames = ['::ttk::entry'.freeze].freeze else TkCommandNames = ['::tentry'.freeze].freeze end WidgetClassName = 'TEntry'.freeze WidgetClassNames[WidgetClassName] = self def __optkey_aliases {:vcmd=>:validatecommand, :invcmd=>:invalidcommand} end private :__optkey_aliases def __boolval_optkeys super() << 'exportselection' end private :__boolval_optkeys def __strval_optkeys super() << 'show' end private :__strval_optkeys def self.style(*args) [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end end ================================================ FILE: ext/tk/lib/tkextlib/tile/tframe.rb ================================================ # # tframe widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile class TFrame < Tk::Frame end Frame = TFrame end end Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Frame, :TkFrame) class Tk::Tile::TFrame < Tk::Frame include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE TkCommandNames = ['::ttk::frame'.freeze].freeze else TkCommandNames = ['::tframe'.freeze].freeze end WidgetClassName = 'TFrame'.freeze WidgetClassNames[WidgetClassName] = self def self.style(*args) [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end end ================================================ FILE: ext/tk/lib/tkextlib/tile/tlabel.rb ================================================ # # tlabel widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile class TLabel < Tk::Label end Label = TLabel end end Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Label, :TkLabel) class Tk::Tile::TLabel < Tk::Label include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE TkCommandNames = ['::ttk::label'.freeze].freeze else TkCommandNames = ['::tlabel'.freeze].freeze end WidgetClassName = 'TLabel'.freeze WidgetClassNames[WidgetClassName] = self def self.style(*args) [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end end ================================================ FILE: ext/tk/lib/tkextlib/tile/tlabelframe.rb ================================================ # # tlabelframe widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile class TLabelframe < Tk::Tile::TFrame end TLabelFrame = TLabelframe Labelframe = TLabelframe LabelFrame = TLabelframe end end Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Labelframe, :TkLabelframe, :TkLabelFrame) class Tk::Tile::TLabelframe < Tk::Tile::TFrame include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE TkCommandNames = ['::ttk::labelframe'.freeze].freeze else TkCommandNames = ['::tlabelframe'.freeze].freeze end WidgetClassName = 'TLabelframe'.freeze WidgetClassNames[WidgetClassName] = self def self.style(*args) [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end end ================================================ FILE: ext/tk/lib/tkextlib/tile/tmenubutton.rb ================================================ # # tmenubutton widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile class TMenubutton < Tk::Menubutton end TMenuButton = TMenubutton Menubutton = TMenubutton MenuButton = TMenubutton end end Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Menubutton, :TkMenubutton, :TkMenuButton) class Tk::Tile::TMenubutton < Tk::Menubutton include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE TkCommandNames = ['::ttk::menubutton'.freeze].freeze else TkCommandNames = ['::tmenubutton'.freeze].freeze end WidgetClassName = 'TMenubutton'.freeze WidgetClassNames[WidgetClassName] = self def self.style(*args) [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end end ================================================ FILE: ext/tk/lib/tkextlib/tile/tnotebook.rb ================================================ # # tnotebook widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile class TNotebook < TkWindow end Notebook = TNotebook end end Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Notebook, :TkNotebook) class Tk::Tile::TNotebook < TkWindow ################################ include TkItemConfigMethod def __item_cget_cmd(id) [self.path, 'tab', id] end private :__item_cget_cmd def __item_config_cmd(id) [self.path, 'tab', id] end private :__item_config_cmd def __item_listval_optkeys(id) [] end private :__item_listval_optkeys def __item_methodcall_optkeys(id) # { key=>method, ... } {} end private :__item_methodcall_optkeys #alias tabcget itemcget #alias tabcget_strict itemcget_strict alias tabconfigure itemconfigure alias tabconfiginfo itemconfiginfo alias current_tabconfiginfo current_itemconfiginfo def tabcget_strict(tagOrId, option) tabconfigure(tagOrId, option)[-1] end def tabcget(tagOrId, option) unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ tabcget_strict(tagOrId, option) else begin tabcget_strict(tagOrId, option) rescue => e begin if current_tabconfiginfo(tagOrId).has_key?(option.to_s) # not tag error & option is known -> error on known option fail e else # not tag error & option is unknown nil end rescue fail e # tag error end end end end ################################ include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE TkCommandNames = ['::ttk::notebook'.freeze].freeze else TkCommandNames = ['::tnotebook'.freeze].freeze end WidgetClassName = 'TNotebook'.freeze WidgetClassNames[WidgetClassName] = self def self.style(*args) [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end def enable_traversal() if Tk::Tile::TILE_SPEC_VERSION_ID < 5 tk_call_without_enc('::tile::enableNotebookTraversal', @path) elsif Tk::Tile::TILE_SPEC_VERSION_ID < 7 tk_call_without_enc('::tile::notebook::enableTraversal', @path) else tk_call_without_enc('::ttk::notebook::enableTraversal', @path) end self end def add(child, keys=nil) if keys && keys != None tk_send('add', _epath(child), *hash_kv(keys)) else tk_send('add', _epath(child)) end self end def forget(idx) tk_send('forget', idx) self end def index(idx) number(tk_send('index', idx)) end def insert(idx, subwin, keys=nil) if keys && keys != None tk_send('insert', idx, subwin, *hash_kv(keys)) else tk_send('insert', idx, subwin) end self end def select(idx) tk_send('select', idx) self end def selected window(tk_send_without_enc('select')) end def tabs list(tk_send('tabs')) end end ================================================ FILE: ext/tk/lib/tkextlib/tile/tpaned.rb ================================================ # # tpaned widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile class TPaned < TkWindow end PanedWindow = Panedwindow = Paned = TPaned end end Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Panedwindow, :TkPanedwindow, :TkPanedWindow) class Tk::Tile::TPaned < TkWindow include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE if Tk::Tile::TILE_SPEC_VERSION_ID < 8 TkCommandNames = ['::ttk::paned'.freeze].freeze else TkCommandNames = ['::ttk::panedwindow'.freeze].freeze end else TkCommandNames = ['::tpaned'.freeze].freeze end WidgetClassName = 'TPaned'.freeze WidgetClassNames[WidgetClassName] = self def self.style(*args) [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end def add(*args) keys = args.pop fail ArgumentError, "no window in arguments" unless keys if keys && keys.kind_of?(Hash) fail ArgumentError, "no window in arguments" if args == [] opts = hash_kv(keys) else args.push(keys) if keys opts = [] end args.each{|win| tk_send_without_enc('add', _epath(win), *opts) } self end def forget(pane) pane = _epath(pane) tk_send_without_enc('forget', pane) self end def insert(pos, win, keys) win = _epath(win) tk_send_without_enc('insert', pos, win, *hash_kv(keys)) self end def panecget_strict(pane, slot) pane = _epath(pane) tk_tcl2ruby(tk_send_without_enc('pane', pane, "-#{slot}")) end alias pane_cget_strict panecget_strict def panecget(pane, slot) unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ panecget_strict(pane, slot) else begin panecget_strict(pane, slot) rescue => e begin if current_paneconfiginfo(pane).has_key?(slot.to_s) # not tag error & option is known -> error on known option fail e else # not tag error & option is unknown nil end rescue fail e # tag error end end end end alias pane_cget panecget def paneconfigure(pane, key, value=nil) pane = _epath(pane) if key.kind_of? Hash params = [] key.each{|k, v| params.push("-#{k}") # params.push((v.kind_of?(TkObject))? v.epath: v) params.push(_epath(v)) } tk_send_without_enc('pane', pane, *params) else # value = value.epath if value.kind_of?(TkObject) value = _epath(value) tk_send_without_enc('pane', pane, "-#{key}", value) end self end alias pane_config paneconfigure alias pane_configure paneconfigure def paneconfiginfo(win) if TkComm::GET_CONFIGINFO_AS_ARRAY win = _epath(win) if key conf = tk_split_list(tk_send_without_enc('pane', win, "-#{key}")) conf[0] = conf[0][1..-1] if conf[0] == 'hide' conf[3] = bool(conf[3]) unless conf[3].empty? conf[4] = bool(conf[4]) unless conf[4].empty? end conf else tk_split_simplelist(tk_send_without_enc('pane', win)).collect{|conflist| conf = tk_split_simplelist(conflist) conf[0] = conf[0][1..-1] if conf[3] if conf[0] == 'hide' conf[3] = bool(conf[3]) unless conf[3].empty? elsif conf[3].index('{') conf[3] = tk_split_list(conf[3]) else conf[3] = tk_tcl2ruby(conf[3]) end end if conf[4] if conf[0] == 'hide' conf[4] = bool(conf[4]) unless conf[4].empty? elsif conf[4].index('{') conf[4] = tk_split_list(conf[4]) else conf[4] = tk_tcl2ruby(conf[4]) end end conf[1] = conf[1][1..-1] if conf.size == 2 # alias info conf } end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY win = _epath(win) if key conf = tk_split_list(tk_send_without_enc('pane', win, "-#{key}")) key = conf.shift[1..-1] if key == 'hide' conf[2] = bool(conf[2]) unless conf[2].empty? conf[3] = bool(conf[3]) unless conf[3].empty? end { key => conf } else ret = {} tk_split_simplelist(tk_send_without_enc('pane', win)).each{|conflist| conf = tk_split_simplelist(conflist) key = conf.shift[1..-1] if key if key == 'hide' conf[2] = bool(conf[2]) unless conf[2].empty? elsif conf[2].index('{') conf[2] = tk_split_list(conf[2]) else conf[2] = tk_tcl2ruby(conf[2]) end end if conf[3] if key == 'hide' conf[3] = bool(conf[3]) unless conf[3].empty? elsif conf[3].index('{') conf[3] = tk_split_list(conf[3]) else conf[3] = tk_tcl2ruby(conf[3]) end end if conf.size == 1 ret[key] = conf[0][1..-1] # alias info else ret[key] = conf end } ret end end end alias pane_configinfo paneconfiginfo def current_paneconfiginfo(win, key=nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if key conf = paneconfiginfo(win, key) {conf[0] => conf[4]} else ret = {} paneconfiginfo(win).each{|conf| ret[conf[0]] = conf[4] if conf.size > 2 } ret end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY ret = {} paneconfiginfo(win, key).each{|k, conf| ret[k] = conf[-1] if conf.kind_of?(Array) } ret end end alias current_pane_configinfo current_paneconfiginfo def identify(x, y) list(tk_send_without_enc('identify', x, y)) end def sashpos(idx, newpos=None) num_or_str(tk_send_without_enc('sashpos', idx, newpos)) end end ================================================ FILE: ext/tk/lib/tkextlib/tile/tprogressbar.rb ================================================ # # tprogressbar widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile class TProgressbar < TkWindow end Progressbar = TProgressbar end end Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Progressbar, :TkProgressbar) class Tk::Tile::TProgressbar include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE TkCommandNames = ['::ttk::progressbar'.freeze].freeze else TkCommandNames = ['::tprogressbar'.freeze].freeze end WidgetClassName = 'TProgressbar'.freeze WidgetClassNames[WidgetClassName] = self def self.style(*args) [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end def step(amount=None) tk_send_without_enc('step', amount).to_f end #def step=(amount) # tk_send_without_enc('step', amount) #end def start(interval=None) if Tk::Tile::TILE_SPEC_VERSION_ID < 5 tk_call_without_enc('::tile::progressbar::start', @path, interval) else tk_send_without_enc('start', interval) end end def stop(amount=None) if Tk::Tile::TILE_SPEC_VERSION_ID < 5 tk_call_without_enc('::tile::progressbar::stop', @path) else tk_send_without_enc('stop', amount) end end end ================================================ FILE: ext/tk/lib/tkextlib/tile/tradiobutton.rb ================================================ # # tradiobutton widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile class TRadioButton < Tk::RadioButton end TRadiobutton = TRadioButton RadioButton = TRadioButton Radiobutton = TRadioButton end end Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Radiobutton, :TkRadiobutton, :TkRadioButton) class Tk::Tile::TRadioButton < Tk::RadioButton include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE TkCommandNames = ['::ttk::radiobutton'.freeze].freeze else TkCommandNames = ['::tradiobutton'.freeze].freeze end WidgetClassName = 'TRadiobutton'.freeze WidgetClassNames[WidgetClassName] = self def self.style(*args) [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end end ================================================ FILE: ext/tk/lib/tkextlib/tile/treeview.rb ================================================ # # treeview widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile class Treeview < TkWindow end end end Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Treeview, :TkTreeview) module Tk::Tile::TreeviewConfig include TkItemConfigMethod def __item_configinfo_struct(id) # maybe need to override {:key=>0, :alias=>nil, :db_name=>nil, :db_class=>nil, :default_value=>nil, :current_value=>1} end private :__item_configinfo_struct def __itemconfiginfo_core(tagOrId, slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/) fontkey = $2 return [slot.to_s, tagfontobj(tagid(tagOrId), fontkey)] else if slot slot = slot.to_s alias_name, real_name = __item_optkey_aliases(tagid(tagOrId)).find{|k, v| k.to_s == slot} if real_name slot = real_name.to_s end case slot when /^(#{__tile_specific_item_optkeys(tagid(tagOrId)).join('|')})$/ begin # On tile-0.7.{2-8}, 'state' options has no '-' at its head. val = tk_call(*(__item_confinfo_cmd(tagid(tagOrId)) << slot)) rescue # Maybe, 'state' option has '-' in future. val = tk_call(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")) end return [slot, val] when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/ method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[slot] optval = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")) begin val = method.call(tagOrId, optval) rescue => e warn("Warning:: #{e.message} (when #{method}lcall(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG val = optval end return [slot, val] when /^(#{__item_methodcall_optkeys(tagid(tagOrId)).keys.join('|')})$/ method = _symbolkey2str(__item_methodcall_optkeys(tagid(tagOrId)))[slot] return [slot, self.__send__(method, tagOrId)] when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/ begin val = number(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))) rescue val = nil end return [slot, val] when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/ val = num_or_str(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))) return [slot, val] when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/ begin val = bool(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))) rescue val = nil end return [slot, val] when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/ val = simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))) return [slot, val] when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/ val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")) if val =~ /^[0-9]/ return [slot, list(val)] else return [slot, val] end when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/ val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")) return [slot, val] when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/ val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")) if val.empty? return [slot, nil] else return [slot, TkVarAccess.new(val)] end else val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")) if val.index('{') return [slot, tk_split_list(val)] else return [slot, tk_tcl2ruby(val)] end end else # ! slot ret = Hash[*(tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)))), false, false))].to_a.collect{|conf| conf[0] = conf[0][1..-1] if conf[0][0] == ?- case conf[0] when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/ method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[conf[0]] optval = conf[1] begin val = method.call(tagOrId, optval) rescue => e warn("Warning:: #{e.message} (when #{method}.call(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG val = optval end conf[1] = val when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/ # do nothing when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/ begin conf[1] = number(conf[1]) rescue conf[1] = nil end when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/ conf[1] = num_or_str(conf[1]) when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/ begin conf[1] = bool(conf[1]) rescue conf[1] = nil end when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/ conf[1] = simplelist(conf[1]) when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/ if conf[1] =~ /^[0-9]/ conf[1] = list(conf[1]) end when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/ if conf[1].empty? conf[1] = nil else conf[1] = TkVarAccess.new(conf[1]) end else if conf[1].index('{') conf[1] = tk_split_list(conf[1]) else conf[1] = tk_tcl2ruby(conf[1]) end end conf } __item_font_optkeys(tagid(tagOrId)).each{|optkey| optkey = optkey.to_s fontconf = ret.assoc(optkey) if fontconf ret.delete_if{|inf| inf[0] =~ /^(|latin|ascii|kanji)#{optkey}$/} fontconf[1] = tagfontobj(tagid(tagOrId), optkey) ret.push(fontconf) end } __item_methodcall_optkeys(tagid(tagOrId)).each{|optkey, method| ret << [optkey.to_s, self.__send__(method, tagOrId)] } ret end end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/) fontkey = $2 return {slot.to_s => tagfontobj(tagid(tagOrId), fontkey)} else if slot slot = slot.to_s alias_name, real_name = __item_optkey_aliases(tagid(tagOrId)).find{|k, v| k.to_s == slot} if real_name slot = real_name.to_s end case slot when /^(#{__tile_specific_item_optkeys(tagid(tagOrId)).join('|')})$/ begin # On tile-0.7.{2-8}, 'state' option has no '-' at its head. val = tk_call(*(__item_confinfo_cmd(tagid(tagOrId)) << slot)) rescue # Maybe, 'state' option has '-' in future. val = tk_call(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")) end return {slot => val} when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/ method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[slot] optval = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")) begin val = method.call(tagOrId, optval) rescue => e warn("Warning:: #{e.message} (when #{method}lcall(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG val = optval end return {slot => val} when /^(#{__item_methodcall_optkeys(tagid(tagOrId)).keys.join('|')})$/ method = _symbolkey2str(__item_methodcall_optkeys(tagid(tagOrId)))[slot] return {slot => self.__send__(method, tagOrId)} when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/ begin val = number(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))) rescue val = nil end return {slot => val} when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/ val = num_or_str(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))) return {slot => val} when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/ begin val = bool(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))) rescue val = nil end return {slot => val} when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/ val = simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))) return {slot => val} when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/ val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")) if val =~ /^[0-9]/ return {slot => list(val)} else return {slot => val} end when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/ val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")) return {slot => val} when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/ val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")) if val.empty? return {slot => nil} else return {slot => TkVarAccess.new(val)} end else val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")) if val.index('{') return {slot => tk_split_list(val)} else return {slot => tk_tcl2ruby(val)} end end else # ! slot ret = {} ret = Hash[*(tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)))), false, false))].to_a.collect{|conf| conf[0] = conf[0][1..-1] if conf[0][0] == ?- optkey = conf[0] case optkey when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/ method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[optkey] optval = conf[1] begin val = method.call(tagOrId, optval) rescue => e warn("Warning:: #{e.message} (when #{method}.call(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG val = optval end conf[1] = val when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/ # do nothing when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/ begin conf[1] = number(conf[1]) rescue conf[1] = nil end when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/ conf[1] = num_or_str(conf[1]) when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/ begin conf[1] = bool(conf[1]) rescue conf[1] = nil end when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/ conf[1] = simplelist(conf[1]) when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/ if conf[1] =~ /^[0-9]/ conf[1] = list(conf[1]) end when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/ if conf[1].empty? conf[1] = nil else conf[1] = TkVarAccess.new(conf[1]) end else if conf[1].index('{') return [slot, tk_split_list(conf[1])] else return [slot, tk_tcl2ruby(conf[1])] end end ret[conf[0]] = conf[1] } __item_font_optkeys(tagid(tagOrId)).each{|optkey| optkey = optkey.to_s fontconf = ret[optkey] if fontconf.kind_of?(Array) ret.delete(optkey) ret.delete('latin' << optkey) ret.delete('ascii' << optkey) ret.delete('kanji' << optkey) fontconf[1] = tagfontobj(tagid(tagOrId), optkey) ret[optkey] = fontconf end } __item_methodcall_optkeys(tagid(tagOrId)).each{|optkey, method| ret[optkey.to_s] = self.__send__(method, tagOrId) } ret end end end end ################### def __item_cget_cmd(id) [self.path, id[0], id[1]] end private :__item_cget_cmd def __item_config_cmd(id) [self.path, id[0], id[1]] end private :__item_config_cmd def __item_numstrval_optkeys(id) case id[0] when :item, 'item' ['width'] when :column, 'column' super(id[1]) + ['minwidth'] when :tag, 'tag' super(id[1]) when :heading, 'heading' super(id[1]) else super(id[1]) end end private :__item_numstrval_optkeys def __item_strval_optkeys(id) case id[0] when :item, 'item' super(id) + ['id'] when :column, 'column' super(id[1]) when :tag, 'tag' super(id[1]) when :heading, 'heading' super(id[1]) else super(id[1]) end end private :__item_strval_optkeys def __item_boolval_optkeys(id) case id[0] when :item, 'item' ['open'] when :column, 'column' super(id[1]) + ['stretch'] when :tag, 'tag' super(id[1]) when :heading, 'heading' super(id[1]) end end private :__item_boolval_optkeys def __item_listval_optkeys(id) case id[0] when :item, 'item' ['values'] when :column, 'column' [] when :heading, 'heading' [] else [] end end private :__item_listval_optkeys def __item_val2ruby_optkeys(id) case id[0] when :item, 'item' { 'tags'=>proc{|arg_id, val| simplelist(val).collect{|tag| Tk::Tile::Treeview::Tag.id2obj(self, tag) } } } when :column, 'column' {} when :heading, 'heading' {} else {} end end private :__item_val2ruby_optkeys def __tile_specific_item_optkeys(id) case id[0] when :item, 'item' [] when :column, 'column' [] when :heading, 'heading' ['state'] # On tile-0.7.{2-8}, 'state' options has no '-' at its head. else [] end end private :__item_val2ruby_optkeys def itemconfiginfo(tagOrId, slot = nil) __itemconfiginfo_core(tagOrId, slot) end def current_itemconfiginfo(tagOrId, slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if slot org_slot = slot begin conf = __itemconfiginfo_core(tagOrId, slot) if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \ || conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 ) return {conf[0] => conf[-1]} end slot = conf[__item_configinfo_struct(tagid(tagOrId))[:alias]] end while(org_slot != slot) fail RuntimeError, "there is a configure alias loop about '#{org_slot}'" else ret = {} __itemconfiginfo_core(tagOrId).each{|conf| if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \ || conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 ) ret[conf[0]] = conf[-1] end } ret end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY ret = {} __itemconfiginfo_core(tagOrId, slot).each{|key, conf| ret[key] = conf[-1] if conf.kind_of?(Array) } ret end end alias __itemcget itemcget alias __itemcget_strict itemcget_strict alias __itemconfigure itemconfigure alias __itemconfiginfo itemconfiginfo alias __current_itemconfiginfo current_itemconfiginfo private :__itemcget, :__itemcget_strict private :__itemconfigure, :__itemconfiginfo, :__current_itemconfiginfo # Treeview Item def itemcget(tagOrId, option) __itemcget([:item, tagOrId], option) end def itemcget_strict(tagOrId, option) __itemcget_strict([:item, tagOrId], option) end def itemconfigure(tagOrId, slot, value=None) __itemconfigure([:item, tagOrId], slot, value) end def itemconfiginfo(tagOrId, slot=nil) __itemconfiginfo([:item, tagOrId], slot) end def current_itemconfiginfo(tagOrId, slot=nil) __current_itemconfiginfo([:item, tagOrId], slot) end # Treeview Column def columncget(tagOrId, option) __itemcget([:column, tagOrId], option) end def columncget_strict(tagOrId, option) __itemcget_strict([:column, tagOrId], option) end def columnconfigure(tagOrId, slot, value=None) __itemconfigure([:column, tagOrId], slot, value) end def columnconfiginfo(tagOrId, slot=nil) __itemconfiginfo([:column, tagOrId], slot) end def current_columnconfiginfo(tagOrId, slot=nil) __current_itemconfiginfo([:column, tagOrId], slot) end alias column_cget columncget alias column_cget_strict columncget_strict alias column_configure columnconfigure alias column_configinfo columnconfiginfo alias current_column_configinfo current_columnconfiginfo # Treeview Heading def headingcget_strict(tagOrId, option) if __tile_specific_item_optkeys([:heading, tagOrId]).index(option.to_s) begin # On tile-0.7.{2-8}, 'state' options has no '-' at its head. tk_call(*(__item_cget_cmd([:heading, tagOrId]) << option.to_s)) rescue # Maybe, 'state' option has '-' in future. tk_call(*(__item_cget_cmd([:heading, tagOrId]) << "-#{option}")) end else __itemcget_strict([:heading, tagOrId], option) end end def headingcget(tagOrId, option) unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ headingcget_strict(tagOrId, option) else begin headingcget_strict(tagOrId, option) rescue => e begin if current_headingconfiginfo(tagOrId).has_key?(option.to_s) # not tag error & option is known -> error on known option fail e else # not tag error & option is unknown nil end rescue fail e # tag error end end end end def headingconfigure(tagOrId, slot, value=None) if slot.kind_of?(Hash) slot = _symbolkey2str(slot) sp_kv = [] __tile_specific_item_optkeys([:heading, tagOrId]).each{|k| sp_kv << k << _get_eval_string(slot.delete(k)) if slot.has_key?(k) } tk_call(*(__item_config_cmd([:heading, tagOrId]).concat(sp_kv))) tk_call(*(__item_config_cmd([:heading, tagOrId]).concat(hash_kv(slot)))) elsif __tile_specific_item_optkeys([:heading, tagOrId]).index(slot.to_s) begin # On tile-0.7.{2-8}, 'state' options has no '-' at its head. tk_call(*(__item_cget_cmd([:heading, tagOrId]) << slot.to_s << value)) rescue # Maybe, 'state' option has '-' in future. tk_call(*(__item_cget_cmd([:heading, tagOrId]) << "-#{slot}" << value)) end else __itemconfigure([:heading, tagOrId], slot, value) end self end def headingconfiginfo(tagOrId, slot=nil) __itemconfiginfo([:heading, tagOrId], slot) end def current_headingconfiginfo(tagOrId, slot=nil) __current_itemconfiginfo([:heading, tagOrId], slot) end alias heading_cget headingcget alias heading_cget_strict headingcget_strict alias heading_configure headingconfigure alias heading_configinfo headingconfiginfo alias current_heading_configinfo current_headingconfiginfo # Treeview Tag def tagcget(tagOrId, option) __itemcget([:tag, tagOrId], option) end def tagcget_strict(tagOrId, option) __itemcget_strict([:tag, tagOrId], option) end def tagconfigure(tagOrId, slot, value=None) __itemconfigure([:tag, tagOrId], slot, value) end def tagconfiginfo(tagOrId, slot=nil) __itemconfiginfo([:tag, tagOrId], slot) end def current_tagconfiginfo(tagOrId, slot=nil) __current_itemconfiginfo([:tag, tagOrId], slot) end alias tag_cget tagcget alias tag_cget_strict tagcget_strict alias tag_configure tagconfigure alias tag_configinfo tagconfiginfo alias current_tag_configinfo current_tagconfiginfo end ######################## class Tk::Tile::Treeview::Item < TkObject ItemID_TBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ Tk::Tile::Treeview::Item::ItemID_TBL.clear } } def self.id2obj(tree, id) tpath = tree.path Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] (Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id])? \ Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id]: id else id end } end def self.assign(tree, id) tpath = tree.path obj = nil Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] && Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] return Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] end obj = self.allocate obj.instance_eval{ @parent = @t = tree @tpath = tpath @path = @id = id } Tk::Tile::Treeview::Item::ItemID_TBL[tpath] ||= {} Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] = obj } obj end def _insert_item(tree, parent_item, idx, keys={}) keys = _symbolkey2str(keys) id = keys.delete('id') if id num_or_str(tk_call(tree, 'insert', parent_item, idx, '-id', id, *hash_kv(keys))) else num_or_str(tk_call(tree, 'insert', parent_item, idx, *hash_kv(keys))) end end private :_insert_item def initialize(tree, parent_item = '', idx = 'end', keys = {}) if parent_item.kind_of?(Hash) keys = parent_item idx = 'end' parent_item = '' elsif idx.kind_of?(Hash) keys = idx idx = 'end' end @parent = @t = tree @tpath = tree.path @path = @id = _insert_item(@t, parent_item, idx, keys) Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ ItemID_TBL[@tpath] = {} unless ItemID_TBL[@tpath] ItemID_TBL[@tpath][@id] = self } end def id @id end def cget(option) @t.itemcget(@id, option) end def cget_strict(option) @t.itemcget_strict(@id, option) end def configure(key, value=None) @t.itemconfigure(@id, key, value) self end def configinfo(key=nil) @t.itemconfiginfo(@id, key) end def current_configinfo(key=nil) @t.current_itemconfiginfo(@id, key) end def open? cget('open') end def open configure('open', true) self end def close configure('open', false) self end def bbox(column=None) @t.bbox(@id, column) end def children @t.children(@id) end def set_children(*items) @t.set_children(@id, *items) self end def delete @t.delete(@id) self end def detach @t.detach(@id) self end def exist? @t.exist?(@id) end def focus @t.focus_item(@id) end def index @t.index(@id) end def insert(idx='end', keys={}) @t.insert(@id, idx, keys) end def move(parent, idx) @t.move(@id, parent, idx) self end def next_item @t.next_item(@id) end def parent_item @t.parent_item(@id) end def prev_item @t.prev_item(@id) end def see @t.see(@id) self end def selection_add @t.selection_add(@id) self end def selection_remove @t.selection_remove(@id) self end def selection_set @t.selection_set(@id) self end def selection_toggle @t.selection_toggle(@id) self end def get_directory @t.get_directory(@id) end alias get_dictionary get_directory def get(col) @t.get(@id, col) end def set(col, value) @t.set(@id, col, value) end end ######################## class Tk::Tile::Treeview::Root < Tk::Tile::Treeview::Item def self.new(tree, keys = {}) tpath = tree.path obj = nil Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] && Tk::Tile::Treeview::Item::ItemID_TBL[tpath][''] obj = Tk::Tile::Treeview::Item::ItemID_TBL[tpath][''] else #super(tree, keys) (obj = self.allocate).instance_eval{ @parent = @t = tree @tpath = tree.path @path = @id = '' Tk::Tile::Treeview::Item::ItemID_TBL[@tpath] ||= {} Tk::Tile::Treeview::Item::ItemID_TBL[@tpath][@id] = self } end } obj.configure(keys) if keys && ! keys.empty? obj end def initialize(tree, keys = {}) # dummy:: not called by 'new' method @parent = @t = tree @tpath = tree.path @path = @id = '' Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ Tk::Tile::Treeview::Item::ItemID_TBL[@tpath] ||= {} Tk::Tile::Treeview::Item::ItemID_TBL[@tpath][@id] = self } end end ######################## class Tk::Tile::Treeview::Tag < TkObject include TkTreatTagFont TagID_TBL = TkCore::INTERP.create_table (Tag_ID = ['tile_treeview_tag'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } TkCore::INTERP.init_ip_env{ Tk::Tile::Treeview::Tag::TagID_TBL.mutex.synchronize{ Tk::Tile::Treeview::Tag::TagID_TBL.clear } } def self.id2obj(tree, id) tpath = tree.path Tk::Tile::Treeview::Tag::TagID_TBL.mutex.synchronize{ if Tk::Tile::Treeview::Tag::TagID_TBL[tpath] (Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id])? \ Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id]: id else id end } end def initialize(tree, keys=nil) @parent = @t = tree @tpath = tree.path Tag_ID.mutex.synchronize{ @path = @id = Tag_ID.join(TkCore::INTERP._ip_id_) Tag_ID[1].succ! } TagID_TBL.mutex.synchronize{ TagID_TBL[@tpath] = {} unless TagID_TBL[@tpath] TagID_TBL[@tpath][@id] = self } if keys && keys != None tk_call_without_enc(@tpath, 'tag', 'configure', *hash_kv(keys, true)) end end def id @id end def bind(seq, *args) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end @t.tag_bind(@id, seq, cmd, *args) self end def bind_append(seq, *args) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end @t.tag_bind_append(@id, seq, cmd, *args) self end def bind_remove(seq) @t.tag_bind_remove(@id, seq) self end def bindinfo(seq=nil) @t.tag_bindinfo(@id, seq) end def cget(option) @t.tagcget(@id, option) end def cget_strict(option) @t.tagcget_strict(@id, option) end def configure(key, value=None) @t.tagconfigure(@id, key, value) self end def configinfo(key=nil) @t.tagconfiginfo(@id, key) end def current_configinfo(key=nil) @t.current_tagconfiginfo(@id, key) end end ######################## class Tk::Tile::Treeview < TkWindow include Tk::Tile::TileWidget include Scrollable include Tk::Tile::TreeviewConfig if Tk::Tile::USE_TTK_NAMESPACE TkCommandNames = ['::ttk::treeview'.freeze].freeze else TkCommandNames = ['::treeview'.freeze].freeze end WidgetClassName = 'Treeview'.freeze WidgetClassNames[WidgetClassName] = self def __destroy_hook__ Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ Tk::Tile::Treeview::Item::ItemID_TBL.delete(@path) } Tk::Tile::Treeview::Tag::ItemID_TBL.mutex.synchronize{ Tk::Tile::Treeview::Tag::ItemID_TBL.delete(@path) } end def self.style(*args) [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end def tagid(id) if id.kind_of?(Tk::Tile::Treeview::Item) || id.kind_of?(Tk::Tile::Treeview::Tag) id.id elsif id.kind_of?(Array) [id[0], _get_eval_string(id[1])] else _get_eval_string(id) end end def root Tk::Tile::Treeview::Root.new(self) end def bbox(item, column=None) list(tk_send('item', 'bbox', item, column)) end def children(item) simplelist(tk_send_without_enc('children', item)).collect{|id| Tk::Tile::Treeview::Item.id2obj(self, id) } end def set_children(item, *items) tk_send_without_enc('children', item, array2tk_list(items.flatten, true)) self end def delete(*items) tk_send_without_enc('delete', array2tk_list(items.flatten, true)) self end def detach(*items) tk_send_without_enc('detach', array2tk_list(items.flatten, true)) self end def exist?(item) bool(tk_send_without_enc('exists', _get_eval_enc_str(item))) end def focus_item(item = nil) if item tk_send('focus', item) item else id = tk_send('focus') (id.empty?)? nil: Tk::Tile::Treeview::Item.id2obj(self, id) end end def identify(x, y) # tile-0.7.2 or previous ret = simplelist(tk_send('identify', x, y)) case ret[0] when 'heading', 'separator' ret[-1] = num_or_str(ret[-1]) when 'cell' ret[1] = Tk::Tile::Treeview::Item.id2obj(self, ret[1]) ret[-1] = num_or_str(ret[-1]) when 'item', 'row' ret[1] = Tk::Tile::Treeview::Item.id2obj(self, ret[1]) end end def row_identify(x, y) id = tk_send('identify', 'row', x, y) (id.empty?)? nil: Tk::Tile::Treeview::Item.id2obj(self, id) end def column_identify(x, y) tk_send('identify', 'column', x, y) end def index(item) number(tk_send('index', item)) end # def insert(parent, idx='end', keys={}) # keys = _symbolkey2str(keys) # id = keys.delete('id') # if id # num_or_str(tk_send('insert', parent, idx, '-id', id, *hash_kv(keys))) # else # num_or_str(tk_send('insert', parent, idx, *hash_kv(keys))) # end # end def insert(parent, idx='end', keys={}) Tk::Tile::Treeview::Item.new(self, parent, idx, keys) end # def instate(spec, cmd=Proc.new) # tk_send('instate', spec, cmd) # end # def state(spec=None) # tk_send('state', spec) # end def move(item, parent, idx) tk_send('move', item, parent, idx) self end def next_item(item) id = tk_send('next', item) (id.empty?)? nil: Tk::Tile::Treeview::Item.id2obj(self, id) end def parent_item(item) if (id = tk_send('parent', item)).empty? Tk::Tile::Treeview::Root.new(self) else Tk::Tile::Treeview::Item.id2obj(self, id) end end def prev_item(item) id = tk_send('prev', item) (id.empty?)? nil: Tk::Tile::Treeview::Item.id2obj(self, id) end def see(item) tk_send('see', item) self end def selection simplelist(tk_send('selection')).collect{|id| Tk::Tile::Treeview::Item.id2obj(self, id) } end alias selection_get selection def selection_add(*items) tk_send('selection', 'add', array2tk_list(items.flatten, true)) self end def selection_remove(*items) tk_send('selection', 'remove', array2tk_list(items.flatten, true)) self end def selection_set(*items) tk_send('selection', 'set', array2tk_list(items.flatten, true)) self end def selection_toggle(*items) tk_send('selection', 'toggle', array2tk_list(items.flatten, true)) self end def get_directory(item) # tile-0.7+ ret = [] lst = simplelist(tk_send('set', item)) until lst.empty? col = lst.shift val = lst.shift ret << [col, val] end ret end alias get_dictionary get_directory def get(item, col) tk_send('set', item, col) end def set(item, col, value) tk_send('set', item, col, value) self end def tag_bind(tag, seq, *args) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind([@path, 'tag', 'bind', tag], seq, cmd, *args) self end alias tagbind tag_bind def tag_bind_append(tag, seq, *args) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append([@path, 'tag', 'bind', tag], seq, cmd, *args) self end alias tagbind_append tag_bind_append def tag_bind_remove(tag, seq) _bind_remove([@path, 'tag', 'bind', tag], seq) self end alias tagbind_remove tag_bind_remove def tag_bindinfo(tag, context=nil) _bindinfo([@path, 'tag', 'bind', tag], context) end alias tagbindinfo tag_bindinfo end ================================================ FILE: ext/tk/lib/tkextlib/tile/tscale.rb ================================================ # # tscale & tprogress widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile class TScale < Tk::Scale end Scale = TScale class TProgress < TScale end Progress = TProgress end end Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Scale, :TkScale) class Tk::Tile::TScale < Tk::Scale include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE TkCommandNames = ['::ttk::scale'.freeze].freeze else TkCommandNames = ['::tscale'.freeze].freeze end WidgetClassName = 'TScale'.freeze WidgetClassNames[WidgetClassName] = self def self.style(*args) [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end end class Tk::Tile::TProgress < Tk::Tile::TScale include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE TkCommandNames = ['::ttk::progress'.freeze].freeze else TkCommandNames = ['::tprogress'.freeze].freeze end WidgetClassName = 'TProgress'.freeze WidgetClassNames[WidgetClassName] = self def self.style(*args) [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end end ================================================ FILE: ext/tk/lib/tkextlib/tile/tscrollbar.rb ================================================ # # tscrollbar widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile class TScrollbar < Tk::Scrollbar end Scrollbar = TScrollbar end end Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Scrollbar, :TkScrollbar) class Tk::Tile::TScrollbar < Tk::Scrollbar include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE TkCommandNames = ['::ttk::scrollbar'.freeze].freeze else TkCommandNames = ['::tscrollbar'.freeze].freeze end WidgetClassName = 'TScrollbar'.freeze WidgetClassNames[WidgetClassName] = self def self.style(*args) [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end end class Tk::Tile::XScrollbar < Tk::Tile::TScrollbar def create_self(keys) keys = {} unless keys keys['orient'] = 'horizontal' super(keys) end private :create_self end class Tk::Tile::YScrollbar < Tk::Tile::TScrollbar def create_self(keys) keys = {} unless keys keys['orient'] = 'vertical' super(keys) end private :create_self end Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::XScrollbar, :TkXScrollbar) Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::YScrollbar, :TkYScrollbar) ================================================ FILE: ext/tk/lib/tkextlib/tile/tseparator.rb ================================================ # # tseparator widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile class TSeparator < TkWindow end Separator = TSeparator end end Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Separator, :TkSeparator) class Tk::Tile::TSeparator < TkWindow include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE TkCommandNames = ['::ttk::separator'.freeze].freeze else TkCommandNames = ['::tseparator'.freeze].freeze end WidgetClassName = 'TSeparator'.freeze WidgetClassNames[WidgetClassName] = self def self.style(*args) [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end end ================================================ FILE: ext/tk/lib/tkextlib/tile/tsquare.rb ================================================ # # tsquare widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tkextlib/tile.rb' module Tk module Tile class TSquare < TkWindow end Square = TSquare end end class Tk::Tile::TSquare < TkWindow include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE TkCommandNames = ['::ttk::square'.freeze].freeze else TkCommandNames = ['::tsquare'.freeze].freeze end WidgetClassName = 'TSquare'.freeze WidgetClassNames[WidgetClassName] = self def self.style(*args) [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end end ================================================ FILE: ext/tk/lib/tkextlib/tile.rb ================================================ # # Tile theme engin (tile widget set) support # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/ttk_selector' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # library directory require 'tkextlib/tile/setup.rb' # load package # TkPackage.require('tile', '0.4') # TkPackage.require('tile', '0.6') # TkPackage.require('tile', '0.7') if Tk::TK_MAJOR_VERSION > 8 || (Tk::TK_MAJOR_VERSION == 8 && Tk::TK_MINOR_VERSION >= 5) TkPackage.require('tile') # for compatibility (version check of 'tile') verstr = TkPackage.require('Ttk') else verstr = TkPackage.require('tile') end ver = verstr.split('.') if ver[0].to_i == 0 # Tile extension package if ver[1].to_i <= 4 # version 0.4 or former module Tk module Tile USE_TILE_NAMESPACE = true USE_TTK_NAMESPACE = false TILE_SPEC_VERSION_ID = 0 end end elsif ver[1].to_i <= 6 # version 0.5 -- version 0.6 module Tk module Tile USE_TILE_NAMESPACE = true USE_TTK_NAMESPACE = true TILE_SPEC_VERSION_ID = 5 end end elsif ver[1].to_i <= 7 module Tk module Tile USE_TILE_NAMESPACE = false USE_TTK_NAMESPACE = true TILE_SPEC_VERSION_ID = 7 end end else # version 0.8 or later module Tk module Tile USE_TILE_NAMESPACE = false USE_TTK_NAMESPACE = true TILE_SPEC_VERSION_ID = 8 end end end module Tk::Tile PACKAGE_NAME = 'tile'.freeze end else # Ttk package merged Tcl/Tk core (Tcl/Tk 8.5+) module Tk module Tile USE_TILE_NAMESPACE = false USE_TTK_NAMESPACE = true TILE_SPEC_VERSION_ID = 8 PACKAGE_NAME = 'Ttk'.freeze end end end # autoload module Tk module Tile TkComm::TkExtlibAutoloadModule.unshift(self) def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require(PACKAGE_NAME) rescue '' end end def self.__Import_Tile_Widgets__! warn 'Warning: "Tk::Tile::__Import_Tile_Widgets__!" is obsolete.' << ' To control default widget set, use "Tk.default_widget_set = :Ttk"' Tk.tk_call('namespace', 'import', '-force', 'ttk::*') end def self.__define_LoadImages_proc_for_compatibility__! # Ttk 8.5 (Tile 0.8) lost 'LoadImages' utility procedure. # So, some old scripts doen't work, because those scripts use the # procedure to define local styles. # Of course, rewriting such Tcl/Tk scripts isn't difficult for # Tcl/Tk users. However, it may be troublesome for Ruby/Tk users # who use such Tcl/Tk scripts as it is. # This method may help Ruby/Tk users who don't want to modify old # Tcl/Tk scripts for the latest version of Ttk (Tile) extension. # This method defines a comaptible 'LoadImages' procedure on the # Tcl/Tk interpreter working under Ruby/Tk. # Please give attention to use this method. It may conflict with # some definitions on Tcl/Tk scripts. klass_name = self.name proc_name = 'LoadImages' if Tk::Tile::USE_TTK_NAMESPACE ns_list = ['::tile'] if Tk.info(:commands, "::ttk::#{proc_name}").empty? ns_list << '::ttk' end else # Tk::Tile::USE_TILE_NAMESPACE ns_list = ['::ttk'] if Tk.info(:commands, "::tile::#{proc_name}").empty? ns_list << '::tile' end end ns_list.each{|ns| cmd = "#{ns}::#{proc_name}" unless Tk.info(:commands, cmd).empty? #fail RuntimeError, "can't define '#{cmd}' command (already exist)" # do nothing !!! warn "Warning: can't define '#{cmd}' command (already exist)" if $DEBUG next end TkNamespace.eval(ns){ TkCore::INTERP.add_tk_procs(proc_name, 'imgdir {patterns {*.gif}}', <<-'EOS') foreach pattern $patterns { foreach file [glob -directory $imgdir $pattern] { set img [file tail [file rootname $file]] if {![info exists images($img)]} { set images($img) [image create photo -file $file] } } } return [array get images] EOS } } end def self.load_images(imgdir, pat=nil) if Tk::Tile::TILE_SPEC_VERSION_ID < 8 if Tk::Tile::USE_TTK_NAMESPACE cmd = '::ttk::LoadImages' else # Tk::Tile::USE_TILE_NAMESPACE cmd = '::tile::LoadImages' end pat ||= TkComm::None images = Hash[*TkComm.simplelist(Tk.tk_call(cmd, imgdir, pat))] images.keys.each{|k| images[k] = TkPhotoImage.new(:imagename=>images[k], :without_creating=>true) } else ## TILE_SPEC_VERSION_ID >= 8 pat ||= '*.gif' if pat.kind_of?(Array) pat_list = pat else pat_list = [ pat ] end Dir.chdir(imgdir){ pat_list.each{|pat| Dir.glob(pat).each{|f| img = File.basename(f, '.*') unless TkComm.bool(Tk.info('exists', "images(#{img})")) Tk.tk_call('set', "images(#{img})", Tk.tk_call('image', 'create', 'photo', '-file', f)) end } } } images = Hash[*TkComm.simplelist(Tk.tk_call('array', 'get', 'images'))] images.keys.each{|k| images[k] = TkPhotoImage.new(:imagename=>images[k], :without_creating=>true) } end images end def self.style(*args) args.map!{|arg| TkComm._get_eval_string(arg)}.join('.') end def self.themes(glob_ptn = nil) if TILE_SPEC_VERSION_ID < 8 && Tk.info(:commands, '::ttk::themes').empty? fail RuntimeError, 'not support glob option' if glob_ptn cmd = ['::tile::availableThemes'] else glob_ptn = '*' unless glob_ptn cmd = ['::ttk::themes', glob_ptn] end begin TkComm.simplelist(Tk.tk_call_without_enc(*cmd)) rescue TkComm.simplelist(Tk.tk_call('lsearch', '-all', '-inline', Tk::Tile::Style.theme_names, glob_ptn)) end end def self.set_theme(theme) if TILE_SPEC_VERSION_ID < 8 && Tk.info(:commands, '::ttk::setTheme').empty? cmd = '::tile::setTheme' else cmd = '::ttk::setTheme' end begin Tk.tk_call_without_enc(cmd, theme) rescue Tk::Tile::Style.theme_use(theme) end end module KeyNav if Tk::Tile::TILE_SPEC_VERSION_ID < 8 def self.enableMnemonics(w) Tk.tk_call('::keynav::enableMnemonics', w) end def self.defaultButton(w) Tk.tk_call('::keynav::defaultButton', w) end else # dummy def self.enableMnemonics(w) "" end def self.defaultButton(w) "" end end end module Font Default = 'TkDefaultFont' Text = 'TkTextFont' Heading = 'TkHeadingFont' Caption = 'TkCaptionFont' Tooltip = 'TkTooltipFont' Fixed = 'TkFixedFont' Menu = 'TkMenuFont' SmallCaption = 'TkSmallCaptionFont' Icon = 'TkIconFont' TkFont::SYSTEM_FONT_NAMES.add [ 'TkDefaultFont', 'TkTextFont', 'TkHeadingFont', 'TkCaptionFont', 'TkTooltipFont', 'TkFixedFont', 'TkMenuFont', 'TkSmallCaptionFont', 'TkIconFont' ] end module ParseStyleLayout def _style_layout(lst) ret = [] until lst.empty? sub = [lst.shift] keys = {} until lst.empty? if lst[0][0] == ?- k = lst.shift[1..-1] children = lst.shift children = _style_layout(children) if children.kind_of?(Array) keys[k] = children else break end end sub << keys unless keys.empty? ret << sub end ret end private :_style_layout end module TileWidget include Tk::Tile::ParseStyleLayout def __val2ruby_optkeys # { key=>proc, ... } # The method is used to convert a opt-value to a ruby's object. # When get the value of the option "key", "proc.call(value)" is called. super().update('style'=>proc{|v| _style_layout(list(v))}) end private :__val2ruby_optkeys def ttk_instate(state, script=nil, &b) if script tk_send('instate', state, script) elsif b tk_send('instate', state, Proc.new(&b)) else bool(tk_send('instate', state)) end end alias tile_instate ttk_instate def ttk_state(state=nil) if state tk_send('state', state) else list(tk_send('state')) end end alias tile_state ttk_state def ttk_identify(x, y) ret = tk_send_without_enc('identify', x, y) (ret.empty?)? nil: ret end alias tile_identify ttk_identify # remove instate/state/identify method # to avoid the conflict with widget options if Tk.const_defined?(:USE_OBSOLETE_TILE_STATE_METHOD) && Tk::USE_OBSOLETE_TILE_STATE_METHOD alias instate ttk_instate alias state ttk_state alias identify ttk_identify end end ###################################### autoload :TButton, 'tkextlib/tile/tbutton' autoload :Button, 'tkextlib/tile/tbutton' autoload :TCheckButton, 'tkextlib/tile/tcheckbutton' autoload :CheckButton, 'tkextlib/tile/tcheckbutton' autoload :TCheckbutton, 'tkextlib/tile/tcheckbutton' autoload :Checkbutton, 'tkextlib/tile/tcheckbutton' autoload :Dialog, 'tkextlib/tile/dialog' autoload :TEntry, 'tkextlib/tile/tentry' autoload :Entry, 'tkextlib/tile/tentry' autoload :TCombobox, 'tkextlib/tile/tcombobox' autoload :Combobox, 'tkextlib/tile/tcombobox' autoload :TFrame, 'tkextlib/tile/tframe' autoload :Frame, 'tkextlib/tile/tframe' autoload :TLabelframe, 'tkextlib/tile/tlabelframe' autoload :Labelframe, 'tkextlib/tile/tlabelframe' autoload :TLabelFrame, 'tkextlib/tile/tlabelframe' autoload :LabelFrame, 'tkextlib/tile/tlabelframe' autoload :TLabel, 'tkextlib/tile/tlabel' autoload :Label, 'tkextlib/tile/tlabel' autoload :TMenubutton, 'tkextlib/tile/tmenubutton' autoload :Menubutton, 'tkextlib/tile/tmenubutton' autoload :TMenuButton, 'tkextlib/tile/tmenubutton' autoload :MenuButton, 'tkextlib/tile/tmenubutton' autoload :TNotebook, 'tkextlib/tile/tnotebook' autoload :Notebook, 'tkextlib/tile/tnotebook' autoload :TPaned, 'tkextlib/tile/tpaned' autoload :Paned, 'tkextlib/tile/tpaned' autoload :PanedWindow, 'tkextlib/tile/tpaned' autoload :Panedwindow, 'tkextlib/tile/tpaned' autoload :TProgressbar, 'tkextlib/tile/tprogressbar' autoload :Progressbar, 'tkextlib/tile/tprogressbar' autoload :TRadioButton, 'tkextlib/tile/tradiobutton' autoload :RadioButton, 'tkextlib/tile/tradiobutton' autoload :TRadiobutton, 'tkextlib/tile/tradiobutton' autoload :Radiobutton, 'tkextlib/tile/tradiobutton' autoload :TScale, 'tkextlib/tile/tscale' autoload :Scale, 'tkextlib/tile/tscale' autoload :TProgress, 'tkextlib/tile/tscale' autoload :Progress, 'tkextlib/tile/tscale' autoload :TScrollbar, 'tkextlib/tile/tscrollbar' autoload :Scrollbar, 'tkextlib/tile/tscrollbar' autoload :XScrollbar, 'tkextlib/tile/tscrollbar' autoload :YScrollbar, 'tkextlib/tile/tscrollbar' autoload :TSeparator, 'tkextlib/tile/tseparator' autoload :Separator, 'tkextlib/tile/tseparator' autoload :TSquare, 'tkextlib/tile/tsquare' autoload :Square, 'tkextlib/tile/tsquare' autoload :SizeGrip, 'tkextlib/tile/sizegrip' autoload :Sizegrip, 'tkextlib/tile/sizegrip' autoload :Treeview, 'tkextlib/tile/treeview' autoload :Style, 'tkextlib/tile/style' end end Ttk = Tk::Tile ================================================ FILE: ext/tk/lib/tkextlib/tkDND/setup.rb ================================================ # # setup.rb -- setup script before calling TkPackage.require() # # If you need some setup operations (for example, add a library path # to the library search path) before using Tcl/Tk library packages # wrapped by Ruby scripts in this directory, please write the setup # operations in this file. # ================================================ FILE: ext/tk/lib/tkextlib/tkDND/shape.rb ================================================ # # tkextlib/tkDND/shape.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/tkDND/setup.rb' # TkPackage.require('Shape', '0.3') TkPackage.require('Shape') module Tk module TkDND module Shape extend TkCore PACKAGE_NAME = 'Shape'.freeze def self.package_name PACKAGE_NAME end =begin def self.package_version begin TkPackage.require('Shape') rescue '' end end =end class << self def package_version Tk.tk_call('set', 'shape_version') end alias shape_version package_version def package_patchlevel Tk.tk_call('set', 'shape_patchLevel') end alias shape_patchlevel package_patchlevel def version tk_call('shape', 'version') end alias xshape_version version end ############################ def shape_bounds(kind=nil) if kind ret = tk_call('shape', 'bounds', @path, "-#{kind}") else ret = tk_call('shape', 'bounds', @path) end if ret == "" nil else list(ret) end end def shape_get(kind=nil) if kind list(tk_call('shape', 'get', @path, "-#{kind}")) else list(tk_call('shape', 'get', @path)) end end def shape_offset(x, y, kind=nil) if kind tk_call('shape', 'get', @path, "-#{kind}", x, y) else tk_call('shape', 'get', @path, x, y) end self end def _parse_shapespec_param(args) cmd = [] kind_keys = ['bounding', 'clip', 'both'] offset_keys = ['offset'] srckind_keys = ['bitmap', 'rectangles', 'reset', 'test', 'window'] cmd << "-#{args.shift}" if kind_keys.member?(args[0].to_s) if offset_keys.member?(args[0].to_s) cmd << "-#{args.shift}" cmd << args.shift # xOffset cmd << args.shift # yOffset end if srckind_keys.member?(args[0].to_s) cmd << "-#{args.shift}" end cmd.concat(args) cmd end private :_parse_shapespec_param def shape_set(*args) # ?kind? ?offset ? srckind ?arg ...? tk_call('shape', 'set', @path, *(_parse_shapespec_param(args))) self end def shape_update(op, *args) # ?kind? ?offset ? srckind ?arg ...? tk_call('shape', 'update', @path, op, *(_parse_shapespec_param(args))) self end end end end class TkWindow include Tk::TkDND::Shape end ================================================ FILE: ext/tk/lib/tkextlib/tkDND/tkdnd.rb ================================================ # # tkextlib/tkDND/tkdnd.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/tkDND/setup.rb' TkPackage.require('tkdnd') module Tk module TkDND PACKAGE_NAME = 'tkdnd'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('tkdnd') rescue '' end end class DND_Subst < TkUtil::CallbackSubst KEY_TBL = [ [ ?a, ?l, :actions ], [ ?A, ?s, :action ], [ ?b, ?L, :codes ], [ ?c, ?s, :code ], [ ?d, ?l, :descriptions ], [ ?D, ?l, :data ], [ ?L, ?l, :source_types ], [ ?m, ?l, :modifiers ], [ ?t, ?l, :types ], [ ?T, ?s, :type ], [ ?W, ?w, :widget ], [ ?x, ?n, :x ], [ ?X, ?n, :x_root ], [ ?y, ?n, :y ], [ ?Y, ?n, :y_root ], nil ] PROC_TBL = [ [ ?n, TkComm.method(:num_or_str) ], [ ?s, TkComm.method(:string) ], [ ?l, TkComm.method(:list) ], [ ?L, TkComm.method(:simplelist) ], [ ?w, TkComm.method(:window) ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end # setup tables _setup_subst_table(KEY_TBL, PROC_TBL); end module DND def self.version begin TkPackage.require('tkdnd') rescue '' end end def dnd_bindtarget_info(type=nil, event=nil) if event procedure(tk_call('dnd', 'bindtarget', @path, type, event)) elsif type procedure(tk_call('dnd', 'bindtarget', @path, type)) else simplelist(tk_call('dnd', 'bindtarget', @path)) end end #def dnd_bindtarget(type, event, cmd=Proc.new, prior=50, *args) # event = tk_event_sequence(event) # if prior.kind_of?(Numeric) # tk_call('dnd', 'bindtarget', @path, type, event, # install_bind_for_event_class(DND_Subst, cmd, *args), # prior) # else # tk_call('dnd', 'bindtarget', @path, type, event, # install_bind_for_event_class(DND_Subst, cmd, prior, *args)) # end # self #end def dnd_bindtarget(type, event, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end prior = 50 prior = args.shift unless args.empty? event = tk_event_sequence(event) if prior.kind_of?(Numeric) tk_call('dnd', 'bindtarget', @path, type, event, install_bind_for_event_class(DND_Subst, cmd, *args), prior) else tk_call('dnd', 'bindtarget', @path, type, event, install_bind_for_event_class(DND_Subst, cmd, prior, *args)) end self end def dnd_cleartarget tk_call('dnd', 'cleartarget', @path) self end def dnd_bindsource_info(type=nil) if type procedure(tk_call('dnd', 'bindsource', @path, type)) else simplelist(tk_call('dnd', 'bindsource', @path)) end end #def dnd_bindsource(type, cmd=Proc.new, prior=None) # tk_call('dnd', 'bindsource', @path, type, cmd, prior) # self #end def dnd_bindsource(type, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end args = [None] if args.empty tk_call('dnd', 'bindsource', @path, type, cmd, *args) self end def dnd_clearsource() tk_call('dnd', 'clearsource', @path) self end def dnd_drag(keys=nil) tk_call('dnd', 'drag', @path, *hash_kv(keys)) self end end end end class TkWindow include Tk::TkDND::DND end ================================================ FILE: ext/tk/lib/tkextlib/tkDND.rb ================================================ # # TkDND (Tk Drag & Drop Extension) support # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/tkDND/setup.rb' module Tk module TkDND autoload :DND, 'tkextlib/tkDND/tkdnd' autoload :Shape, 'tkextlib/tkDND/shape' end end ================================================ FILE: ext/tk/lib/tkextlib/tkHTML/htmlwidget.rb ================================================ # # tkextlib/tkHTML/htmlwidget.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/tkHTML/setup.rb' # TkPackage.require('Tkhtml', '2.0') TkPackage.require('Tkhtml') module Tk class HTML_Widget < TkWindow PACKAGE_NAME = 'Tkhtml'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('Tkhtml') rescue '' end end class ClippingWindow < TkWindow end end end class Tk::HTML_Widget::ClippingWindow WidgetClassName = 'HtmlClip'.freeze WidgetClassNames[WidgetClassName] = self HtmlClip_TBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ HtmlClip_TBL.mutex.synchronize{ HtmlClip_TBL.clear } } def self.new(parent, keys={}) if parent.kind_of?(Hash) keys = TkComm._symbolkey2str(parent) parent = keys.delete('parent') end if parent.kind_of?(String) ppath = parent.path elsif parent ppath = parent else ppath = '' end HtmlClip_TBL.mutex.synchronize{ return HtmlClip_TBL[ppath] if HtmlClip_TBL[ppath] } widgetname = keys.delete('widgetname') if widgetname =~ /^(.*)\.[^.]+$/ ppath2 = $1 if ppath2[0] != ?. ppath2 = ppath + '.' + ppath2 end HtmlClip_TBL.mutex.synchronize{ return HtmlClip_TBL[ppath2] if HtmlClip_TBL[ppath2] } ppath = ppath2 end parent = TkComm._genobj_for_tkwidget(ppath) unless parent.kind_of?(Tk::HTML_Widget) fail ArgumentError, "parent must be a Tk::HTML_Widget instance" end super(parent) end def initialize(parent) @parent = parent @ppath = parent.path @path = @id = @ppath + '.x' HtmlClip_TBL.mutex.synchronize{ HtmlClip_TBL[@ppath] = self } end def method_missing(m, *args, &b) @parent.__send__(m, *args, &b) end end class Tk::HTML_Widget include Scrollable TkCommandNames = ['html'.freeze].freeze WidgetClassName = 'Html'.freeze WidgetClassNames[WidgetClassName] = self def create_self(keys) if keys and keys != None tk_call_without_enc(self.class::TkCommandNames[0], @path, *hash_kv(keys, true)) else tk_call_without_enc(self.class::TkCommandNames[0], @path) end end private :create_self def __strval_optkeys super() << 'base' << 'selectioncolor' << 'unvisitedcolor' << 'visitedcolor' end private :__strval_optkeys ################################### # class methods ################################### def self.reformat(src, dst, txt) tk_call('html', 'reformat', src, dst, txt) end def self.url_join(*args) # args := sheme authority path query fragment tk_call('html', 'urljoin', *args) end def self.url_split(uri) tk_call('html', 'urlsplit', uri) end def self.lockcopy(src, dst) tk_call('html', 'lockcopy', src, dst) end def self.gzip_file(file, dat) tk_call('html', 'gzip', 'file', file, dat) end def self.gunzip_file(file, dat) tk_call('html', 'gunzip', 'file', filet) end def self.gzip_data(dat) tk_call('html', 'gzip', 'data', file, dat) end def self.gunzip_data(dat) tk_call('html', 'gunzip', 'data', filet) end def self.base64_encode(dat) tk_call('html', 'base64', 'encode', dat) end def self.base64_decode(dat) tk_call('html', 'base64', 'encode', dat) end def self.text_format(dat, len) tk_call('html', 'text', 'format', dat, len) end def self.xor(cmd, *args) tk_call('html', 'xor', cmd, *args) end def self.stdchan(cmd, channel) tk_call('html', 'stdchan', cmd, channel) end def self.crc32(data) tk_call('html', 'crc32', data) end ################################### # instance methods ################################### def clipping_window ClippingWindow.new(self) end alias clipwin clipping_window alias htmlclip clipping_window def bgimage(image, tid=None) tk_send('bgimage', image, tid) self end def clear() tk_send('clear') self end def coords(index=None, percent=None) tk_send('coords', index, percent) end def forminfo(*args) tk_send('forminfo', *args) end alias form_info forminfo def href(x, y) simplelist(tk_send('href', x, y)) end def image_add(id, img) tk_send('imageadd', id, img) self end def image_at(x, y) tk_send('imageat', x, y) end def images() list(tk_send('images')) end def image_set(id, num) tk_send('imageset', id, num) self end def image_update(id, imgs) tk_send('imageupdate', id, imgs) self end def index(idx, count=None, unit=None) tk_send('index', idx, count, unit) end def insert_cursor(idx) tk_send('insert', idx) end def names() simple_list(tk_send('names')) end def on_screen(id, x, y) bool(tk_send('onscreen', id, x, y)) end def over(x, y) list(tk_send('over', x, y)) end def over_markup(x, y) list(tk_send('over', x, y, '-muponly')) end def over_attr(x, y, attrs) list(tk_send('overattr', x, y, attrs)) end def parse(txt) tk_send('parse', txt) self end def resolver(*uri_args) tk_send('resolver', *uri_args) end def selection_clear() tk_send('selection', 'clear') self end def selection_set(first, last) tk_send('selection', 'set', first, last) self end def refresh(*opts) tk_send('refresh', *opts) end def layout() tk_send('layout') end def sizewindow(*args) tk_send('sizewindow', *args) end def postscript(*args) tk_send('postscript', *args) end def source() tk_send('source') end def plain_text(first, last) tk_send('text', 'ascii', first, last) end alias ascii_text plain_text alias text_ascii plain_text def text_delete(first, last) tk_send('text', 'delete', first, last) self end def html_text(first, last) tk_send('text', 'html', first, last) end alias text_html html_text def text_insert(idx, txt) tk_send('text', 'insert', idx, txt) self end def break_text(idx) tk_send('text', 'break', idx) end alias text_break break_text def text_find(txt, *args) tk_send('text', 'find', txt, *args) end def text_table(idx, imgs=None, attrs=None) tk_send('text', 'table', idx, imgs, attrs) end def token_append(tag, *args) tk_send('token', 'append', tag, *args) self end def token_delete(first, last=None) tk_send('token', 'delete', first, last) self end def token_define(*args) tk_send('token', 'defile', *args) self end def token_find(tag, *args) list(tk_send('token', 'find', tag, *args)) end def token_get(first, last=None) list(tk_send('token', 'get', first, last)) end def token_list(first, last=None) list(tk_send('token', 'list', first, last)) end def token_markup(first, last=None) list(tk_send('token', 'markup', first, last)) end def token_DOM(first, last=None) list(tk_send('token', 'domtokens', first, last)) end alias token_dom token_DOM alias token_domtokens token_DOM alias token_dom_tokens token_DOM def token_get_end(idx) tk_send('token', 'getend', idx) end alias token_getend token_get_end def token_offset(start, num1, num2) list(tk_send('token', 'offset', start, num1, num2)) end def token_get_attr(idx, name=None) list(tk_send('token', 'attr', idx, name)) end def token_set_attr(idx, name=None, val=None) tk_send('token', 'attr', idx, name, val) self end def token_handler(tag, cmd=nil, &b) cmd = Proc.new(&b) if !cmd && b if cmd tk_send('token', 'handler', tag, cmd) return self else return tk_send('token', 'handler', tag) end end def token_insert(idx, tag, *args) tk_send('token', 'insert', idx, tag, *args) self end def token_attrs(*args) list(tk_send('token', 'attrs', *args)) end def token_unique(*args) list(tk_send('token', 'unique', *args)) end def token_on_events(*args) list(tk_send('token', 'onEvents', *args)) end def dom_nameidx(tag, name) number(tk_send('dom', 'nameidx', tag, name)) end alias dom_name_index dom_nameidx def dom_radioidx(tag, name) number(tk_send('dom', 'radioidx', tag, name)) end alias dom_radio_index dom_radioidx def dom_id(*spec) tk_send('dom', 'id', *spec) end def dom_ids(*spec) list(tk_send('dom', 'ids', *spec)) end def dom_value(*spec) list(tk_send('dom', 'value', *spec)) end def dom_attr(idx) tk_send('dom', 'attr', idx) end def dom_formel(name) tk_send('dom', 'formel', name) end alias dom_form_element dom_formel def dom_tree(idx, val) list(tk_send('dom', 'tree', idx, val)) end end ================================================ FILE: ext/tk/lib/tkextlib/tkHTML/setup.rb ================================================ # # setup.rb -- setup script before calling TkPackage.require() # # If you need some setup operations (for example, add a library path # to the library search path) before using Tcl/Tk library packages # wrapped by Ruby scripts in this directory, please write the setup # operations in this file. # ================================================ FILE: ext/tk/lib/tkextlib/tkHTML.rb ================================================ # # TkHtml support # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/tkHTML/setup.rb' # load library require 'tkextlib/tkHTML/htmlwidget' ================================================ FILE: ext/tk/lib/tkextlib/tkimg/README ================================================ [ Tcl/Tk Image formats (TkImg) support ] TkImg contains a collection of format handlers for the Tk photo image type, and a new image type, pixmaps. Supported formats of TkImg version 1.3 are ------------------------------------------------------- bmp : Windows Bitmap Format gif : Graphics Interchange Format ico : Windows Icon Format jpeg : Joint Picture Expert Group format pcx : Paintbrush Format pixmap : Pixmap Image type png : Portable Network Graphics format ppm : Portable Pixmap format ps : Adobe PostScript Format sgi : SGI Native Format sun : Sun Raster Format tga : Truevision Targa Format tiff : Tagged Image File Format window : Tk Windows xbm : X Window Bitmap Format xpm : X Window Pixmap Format ------------------------------------------------------- ================================================ FILE: ext/tk/lib/tkextlib/tkimg/bmp.rb ================================================ # # TkImg - format 'bmp' # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/tkimg/setup.rb' #TkPackage.require('img::bmp', '1.3') TkPackage.require('img::bmp') module Tk module Img module BMP PACKAGE_NAME = 'img::bmp'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('img::bmp') rescue '' end end end end end ================================================ FILE: ext/tk/lib/tkextlib/tkimg/gif.rb ================================================ # # TkImg - format 'gif' # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/tkimg/setup.rb' # TkPackage.require('img::gif', '1.3') TkPackage.require('img::gif') module Tk module Img module GIF PACKAGE_NAME = 'img::gif'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('img::gif') rescue '' end end end end end ================================================ FILE: ext/tk/lib/tkextlib/tkimg/ico.rb ================================================ # # TkImg - format 'ico' # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/tkimg/setup.rb' # TkPackage.require('img::ico', '1.3') TkPackage.require('img::ico') module Tk module Img module ICO PACKAGE_NAME = 'img::ico'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('img::ico') rescue '' end end end end end ================================================ FILE: ext/tk/lib/tkextlib/tkimg/jpeg.rb ================================================ # # TkImg - format 'jpeg' # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/tkimg/setup.rb' # TkPackage.require('img::jpeg', '1.3') TkPackage.require('img::jpeg') module Tk module Img module JPEG PACKAGE_NAME = 'img::jpeg'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('img::jpeg') rescue '' end end end end end ================================================ FILE: ext/tk/lib/tkextlib/tkimg/pcx.rb ================================================ # # TkImg - format 'pcx' # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)# require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/tkimg/setup.rb' # TkPackage.require('img::pcx', '1.3') TkPackage.require('img::pcx') module Tk module Img module PCX PACKAGE_NAME = 'img::pcx'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('img::pcx') rescue '' end end end end end ================================================ FILE: ext/tk/lib/tkextlib/tkimg/pixmap.rb ================================================ # # TkImg - format 'pixmap' # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/tkimg/setup.rb' # TkPackage.require('img::pixmap', '1.3') TkPackage.require('img::pixmap') module Tk module Img module PIXMAP PACKAGE_NAME = 'img::pixmap'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('img::pixmap') rescue '' end end end end end class TkPixmapImagemethod, ... } super(id).update('window'=>proc{|v| window(v)}) end private :__item_val2ruby_optkeys def tag_cget(tagOrId, option) itemcget(['tag', tagid(tagOrId)], option) end def tag_cget_strict(tagOrId, option) itemcget_strict(['tag', tagid(tagOrId)], option) end def tag_configure(tagOrId, slot, value=None) itemconfigure(['tag', tagid(tagOrId)], slot, value) end def tag_configinfo(tagOrId, slot=nil) itemconfiginfo(['tag', tagid(tagOrId)], slot) end def current_tag_configinfo(tagOrId, slot=nil) current_itemconfiginfo(['tag', tagid(tagOrId)], slot) end def window_cget(tagOrId, option) itemcget(['window', tagid(tagOrId)], option) end def window_cget_strict(tagOrId, option) itemcget_strict(['window', tagid(tagOrId)], option) end def window_configure(tagOrId, slot, value=None) if slot == :window || slot == 'window' value = _epath(value) elsif slot.kind_of?(Hash) if slot.key?(:window) || slot.key?('window') slot = _symbolkey2str(slot) slot['window'] = _epath(slot['window']) end end itemconfigure(['window', tagid(tagOrId)], slot, value) end def window_configinfo(tagOrId, slot=nil) itemconfiginfo(['window', tagid(tagOrId)], slot) end def current_window_configinfo(tagOrId, slot=nil) current_itemconfiginfo(['window', tagid(tagOrId)], slot) end private :itemcget, :itemcget_strict private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo end ##################################################### class Tk::TkTable::CellTag include TkTreatTagFont CellTagID_TBL = TkCore::INTERP.create_table (CellTag_ID = ['tktbl:celltag'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } TkCore::INTERP.init_ip_env{ CellTagID_TBL.mutex.synchronize{ CellTagID_TBL.clear } } def self.id2obj(table, id) tpath = table.path CellTagID_TBL.mutex.synchronize{ if CellTagID_TBL[tpath] CellTagID_TBL[tpath][id]? CellTagID_TBL[tpath][id] : id else id end } end def initialize(parent, keys=nil) @parent = @t = parent @tpath - parent.path CellTag_ID.mutex.synchronize{ @path = @id = CellTag_ID.join(TkCore::INTERP._ip_id_) CellTag_ID[1].succ! } CellTagID_TBL.mutex.synchronize{ CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath] CellTagID_TBL[@tpath][@id] = self } configure(keys) if keys end def id @id end def destroy tk_call(@tpath, 'tag', 'delete', @id) CellTagID_TBL.mutex.synchronize{ CellTagID_TBL[@tpath].delete(@id) if CellTagID_TBL[@tpath] } self end alias delete destroy def exist? @t.tag_exist?(@id) end def include?(idx) @t.tag_include?(@id, idx) end def add_cell(*args) @t.tag_cell(@id, *args) end def add_col(*args) @t.tag_col(@id, *args) end def add_row(*args) @t.tag_row(@id, *args) end def raise(target=None) @t.tag_raise(@id, target) end def lower(target=None) @t.tag_lower(@id, target) end def cget(key) @t.tag_cget(@id, key) end def cget_strict(key) @t.tag_cget_strict(@id, key) end def configure(key, val=None) @t.tag_configure(@id, key, val) end def configinfo(key=nil) @t.tag_configinfo(@id, key) end def current_configinfo(key=nil) @t.current_tag_configinfo(@id, key) end end class Tk::TkTable::NamedCellTag < Tk::TkTable::CellTag def self.new(parent, name, keys=nil) obj = nil CellTagID_TBL.mutex.synchronize{ if CellTagID_TBL[parent.path] && CellTagID_TBL[parent.path][name] obj = CellTagID_TBL[parent.path][name] else #super(parent, name, keys) (obj = self.allocate).instance_eval{ @parent = @t = parent @tpath = parent.path @path = @id = name CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath] CellTagID_TBL[@tpath][@id] = self } end } obj.configure(keys) if keys && ! keys.empty? obj end def initialize(parent, name, keys=nil) # dummy:: not called by 'new' method @parent = @t = parent @tpath = parent.path @path = @id = name CellTagID_TBL.mutex.synchronize{ CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath] CellTagID_TBL[@tpath][@id] = self } configure(keys) if keys && ! keys.empty? end end ##################################################### class Tk::TkTable TkCommandNames = ['table'.freeze].freeze WidgetClassName = 'Table'.freeze WidgetClassNames[WidgetClassName] = self include Scrollable include Tk::TkTable::ConfigMethod include Tk::ValidateConfigure def __destroy_hook__ Tk::TkTable::CelTag::CellTagID_TBL.mutex.synchronize{ Tk::TkTable::CelTag::CellTagID_TBL.delete(@path) } end def __boolval_optkeys super() << 'autoclear' << 'flashmode' << 'invertselected' << 'multiline' << 'selecttitle' << 'wrap' end private :__boolval_optkeys def __strval_optkeys super() << 'colseparator' << 'ellipsis' << 'rowseparator' << 'sparsearray' end private :__strval_optkeys ################################# class BrowseCommand < TkValidateCommand class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [ ?c, ?n, :column ], [ ?C, ?s, :index ], [ ?i, ?x, :cursor ], [ ?r, ?n, :row ], [ ?s, ?s, :last_index ], [ ?S, ?s, :new_index ], [ ?W, ?w, :widget ], nil ] PROC_TBL = [ [ ?n, TkComm.method(:number) ], [ ?x, TkComm.method(:num_or_str) ], [ ?s, TkComm.method(:string) ], [ ?w, TkComm.method(:window) ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) val end end def self._config_keys ['browsecommand', 'browsecmd'] end end #-------------------------------- class CellCommand < TkValidateCommand class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [ ?c, ?n, :column ], [ ?C, ?s, :index ], [ ?i, ?m, :rw_mode ], [ ?r, ?n, :row ], [ ?s, ?v, :value ], [ ?W, ?w, :widget ], nil ] PROC_TBL = [ [ ?n, TkComm.method(:number) ], [ ?s, TkComm.method(:string) ], [ ?w, TkComm.method(:window) ], [ ?m, proc{|val| (val == '0')? (:r) : (:w)} ], [ ?v, proc{|val| TkComm.tk_tcl2ruby(val, true, false)} ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) TkComm._get_eval_string(val) end end def self._config_keys ['command'] end end #-------------------------------- class SelectionCommand < TkValidateCommand class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [ ?c, ?n, :sel_columns ], [ ?C, ?s, :sel_area ], [ ?i, ?n, :total ], [ ?r, ?n, :sel_rows ], [ ?s, ?s, :value ], [ ?W, ?w, :widget ], nil ] PROC_TBL = [ [ ?n, TkComm.method(:number) ], [ ?s, TkComm.method(:string) ], [ ?w, TkComm.method(:window) ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) val.to_s end end def self._config_keys ['selectioncommand', 'selcmd'] end end #-------------------------------- class ValidateCommand < TkValidateCommand class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [ ?c, ?n, :column ], [ ?C, ?s, :index ], [ ?i, ?x, :cursor ], [ ?r, ?n, :row ], [ ?s, ?v, :current_value ], [ ?S, ?v, :new_value ], [ ?W, ?w, :widget ], nil ] PROC_TBL = [ [ ?n, TkComm.method(:number) ], [ ?x, TkComm.method(:num_or_str) ], [ ?s, TkComm.method(:string) ], [ ?w, TkComm.method(:window) ], [ ?v, proc{|val| TkComm.tk_tcl2ruby(val, true, false)} ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end _setup_subst_table(KEY_TBL, PROC_TBL); end def self._config_keys ['vcmd', 'validatecommand'] end end ################################# def __validation_class_list super() << BrowseCommand << CellCommand << SelectionCommand << ValidateCommand end Tk::ValidateConfigure.__def_validcmd(binding, BrowseCommand) Tk::ValidateConfigure.__def_validcmd(binding, CellCommand) Tk::ValidateConfigure.__def_validcmd(binding, SelectionCommand) Tk::ValidateConfigure.__def_validcmd(binding, ValidateCommand) ################################# def activate(idx) tk_send('activate', tagid(idx)) end def bbox(idx) list(tk_send('bbox', tagid(idx))) end def border_mark(x, y) simplelist(tk_send('border', 'mark', x, y)) end def border_mark_row(x, y) tk_send('border', 'mark', x, y, 'row') end def border_mark_col(x, y) tk_send('border', 'mark', x, y, 'col') end def border_dragto(x, y) tk_send('border', 'dragto', x, y) end def clear_cache(first=None, last=None) tk_send('clear', 'cache', tagid(first), tagid(last)) self end def clear_sizes(first=None, last=None) tk_send('clear', 'sizes', tagid(first), tagid(last)) self end def clear_tags(first=None, last=None) tk_send('clear', 'tags', tagid(first), tagid(last)) self end def clear_all(first=None, last=None) tk_send('clear', 'all', tagid(first), tagid(last)) self end def curselection simplelist(tk_send('curselection')) end def curselection=(val) tk_send('curselection', val) val end def curvalue tk_tcl2ruby(tk_send('curvalue'), true, false) end def curvalue=(val) tk_send('curvalue', val) val end def delete_active(idx1, idx2=None) tk_send('delete', 'active', tagid(idx1), tagid(idx2)) self end def delete_cols(*args) # ?switches_array?, index, ?count? params = [] if args[0].kind_of?(Array) switches = args.shift switches.each{|k| params << "-#{k}"} end params << '--' params << tagid(args.shift) params.concat(args) tk_send('delete', 'cols', *params) self end def delete_rows(*args) # ?switches_array?, index, ?count? params = [] if args[0].kind_of?(Array) switches = args.shift switches.each{|k| params << "-#{k}"} end params << '--' params << tagid(args.shift) params.concat(args) tk_send('delete', 'rows', *params) self end def get(idx) tk_tcl2ruby(tk_send('get', tagid(idx)), true, false) end def get_area(idx1, idx2) simplelist(tk_send('get', tagid(idx1), tagid(idx2))).collect{|v| tk_tcl2ruby(v, true, false) } end def height_list list(tk_send('height')) end def height(row) number(tk_send('height', row)) end def set_height(*pairs) tk_send('height', *(pairs.flatten)) self end def hidden_list simplelist(tk_send('hidden')) end def hidden?(idx, *args) if args.empty? if (ret = tk_send('hidden', tagid(idx))) == '' false else ret end else bool(tk_send('hidden', tagid(idx), *(args.collect{|i| tagid(i)}))) end end def icursor number(tk_send('icursor')) end def icursor_set(idx) number(tk_send('icursor', tagid(idx))) end def index(idx) tk_send('index', tagid(idx)) end def row_index(idx) number(tk_send('index', tagid(idx), 'row')) end def col_index(idx) number(tk_send('index', tagid(idx), 'col')) end def insert_active(idx, val) tk_send('insert', 'active', tagid(idx), val) self end def insert_cols(*args) # ?switches_array?, index, ?count? params = [] if args[0].kind_of?(Array) switches = args.shift switches.each{|k| params << "-#{k}"} end params << '--' params.concat(args) params << tagid(args.shift) tk_send('insert', 'cols', *params) self end def insert_rows(*args) # ?switches_array?, index, ?count? params = [] if args[0].kind_of?(Array) switches = args.shift switches.each{|k| params << "-#{k}"} end params << '--' params << tagid(args.shift) params.concat(args) tk_send('insert', 'rows', *params) self end # def postscript(*args) # tk_send('postscript', *args) # end def reread tk_send('reread') self end def scan_mark(x, y) tk_send('scan', 'mark', x, y) self end def scan_dragto(x, y) tk_send('scan', 'dragto', x, y) self end def see(idx) tk_send('see', tagid(idx)) self end def selection_anchor(idx) tk_send('selection', 'anchor', tagid(idx)) self end def selection_clear(first, last=None) tk_send('selection', 'clear', tagid(first), tagid(last)) self end def selection_clear_all selection_clear('all') end def selection_include?(idx) bool(tk_send('selection', 'includes', tagid(idx))) end def selection_present bool(tk_send('selection', 'present')) end def selection_set(first, last=None) tk_send('selection', 'set', tagid(first), tagid(last)) self end def set(*pairs) # idx, val, idx, val, ... args = [] 0.step(pairs.size-1, 2){|i| args << tagid(pairs[i]) args << pairs[i+1] } tk_send('set', *args) self end def set_row(*pairs) # idx, val, idx, val, ... args = [] 0.step(pairs.size-1, 2){|i| args << tagid(pairs[i]) args << pairs[i+1] } tk_send('set', 'row', *args) self end def set_col(*pairs) # idx, val, idx, val, ... args = [] 0.step(pairs.size-1, 2){|i| args << tagid(pairs[i]) args << pairs[i+1] } tk_send('set', 'col', *args) self end =begin def set(*pairs) # idx, val, idx, val, ... OR [idx, val], [idx, val], ... if pairs[0].kind_of?(Array) # [idx, val], [idx, val], ... args = [] pairs.each{|idx, val| args << tagid(idx) << val } tk_send('set', *args) else # idx, val, idx, val, ... args = [] 0.step(pairs.size-1, 2){|i| args << tagid(pairs[i]) args << pairs[i+1] } tk_send('set', *args) end self end def set_row(*pairs) if pairs[0].kind_of?(Array) # [idx, val], [idx, val], ... args = [] pairs.each{|idx, val| args << tagid(idx) << val } tk_send('set', 'row', *args) else # idx, val, idx, val, ... args = [] 0.step(pairs.size-1, 2){|i| args << tagid(pairs[i]) args << pairs[i+1] } tk_send('set', 'row', *args) end self end def set_col(*pairs) if pairs[0].kind_of?(Array) # [idx, val], [idx, val], ... args = [] pairs.each{|idx, val| args << idx << val } tk_send('set', 'col', *args) else # idx, val, idx, val, ... args = [] 0.step(pairs.size-1, 2){|i| args << tagid(pairs[i]) args << pairs[i+1] } tk_send('set', 'col', *args) end self end =end def spans simplelist(tk_send('spans')).collect{|inf| lst = simplelist(inf) idx = lst[0] rows, cols = lst[1].split(',').map!{|n| Integer(n)} [idx [rows, cols]] } end alias span_list spans def span(idx) lst = simplelist(tk_send('spans', tagid(idx))) idx = lst[0] rows, cols = lst[1].split(',').map!{|n| Integer(n)} [idx [rows, cols]] end def set_spans(*pairs) # idx, val, idx, val, ... args = [] 0.step(pairs.size-1, 2){|i| args << tagid(pairs[i]) val = pairs[i+1] if val.kind_of?(Array) args << val.join(',') else args << val end } tk_send('spans', *args) self end =begin def set_spans(*pairs) if pairs[0].kind_of?(Array) # [idx, val], [idx, val], ... args = [] pairs.each{|idx, val| args << tagid(idx) if val.kind_of?(Array) args << val.join(',') else args << val end } tk_send('spans', *args) else # idx, val, idx, val, ... args = [] 0.step(pairs.size-1, 2){|i| args << tagid(pairs[i]) val = pairs[i+1] if val.kind_of?(Array) args << val.join(',') else args << val end } tk_send('spans', *args) end self end =end def tagid(tag) if tag.kind_of?(Tk::TkTable::CellTag) tag.id elsif tag.kind_of?(Array) if tag[0].kind_of?(Integer) && tag[1].kind_of?(Integer) # [row, col] tag.join(',') else tag end else tag end end def tagid2obj(tagid) Tk::TkTable::CellTag::CellTagID_TBL.mutex.synchronize{ if Tk::TkTable::CellTag::CellTagID_TBL.key?(@path) if Tk::TkTable::CellTag::CellTagID_TBL[@path].key?(tagid) Tk::TkTable::CellTag::CellTagID_TBL[@path][tagid] else tagid end else tagid end } end def tag_cell(tag, *cells) tk_send('tag', 'cell', tagid(tag), *(cells.collect{|idx| tagid(idx)})) self end def tag_reset(*cells) tk_send('tag', 'cell', '', *(cells.collect{|idx| tagid(idx)})) self end def tag_col(tag, *cols) tk_send('tag', 'col', tagid(tag), *cols) self end def tag_col_reset(*cols) tk_send('tag', 'col', '', *cols) self end def tag_delete(tag) tk_send('tag', 'delete', tagid(tag)) Tk::TkTable::CellTag::CellTagID_TBL.mutex.synchronize{ if Tk::TkTable::CellTag::CellTagID_TBL[@path] if tag.kind_of? Tk::TkTable::CellTag Tk::TkTable::CellTag::CellTagID_TBL[@path].delete(tag.id) else Tk::TkTable::CellTag::CellTagID_TBL[@path].delete(tag) end end } self end def tag_exist?(tag) bool(tk_send('tag', 'exists', tagid(tag))) end def tag_include?(tag, idx) bool(tk_send('tag', 'includes', tagid(tag), tagid(idx))) end def tag_lower(tag, target=None) tk_send('tag', 'lower', tagid(tag), tagid(target)) self end def tag_names(pat=None) simplelist(tk_send('tag', 'names', pat)).collect{|tag| tagid2obj(tag)} end def tag_raise(tag, target=None) tk_send('tag', 'raise', tagid(tag), tagid(target)) self end def tag_row(tag, *rows) tk_send('tag', 'row', tagid(tag), *rows) self end def tag_row_reset(*rows) tk_send('tag', 'row', '', *rows) self end def validate(idx) bool(tk_send('validate', tagid(idx))) end def width_list list(tk_send('width')) end def width(row) number(tk_send('width', row)) end def set_width(*pairs) tk_send('width', *(pairs.flatten)) self end def window_delete(*args) tk_send('window', 'delete', *(args.collect{|idx| tagid(idx)})) self end def window_move(from_idx, to_idx) tk_send('window', 'move', tagid(from_idx), tagid(to_idx)) self end def window_names(pat=None) simplelist(tk_send('window', 'names', pat)) end end ================================================ FILE: ext/tk/lib/tkextlib/tktable.rb ================================================ # # TkTable support # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/tktable/setup.rb' # load library require 'tkextlib/tktable/tktable' ================================================ FILE: ext/tk/lib/tkextlib/tktrans/setup.rb ================================================ # # setup.rb -- setup script before calling TkPackage.require() # # If you need some setup operations (for example, add a library path # to the library search path) before using Tcl/Tk library packages # wrapped by Ruby scripts in this directory, please write the setup # operations in this file. # ================================================ FILE: ext/tk/lib/tkextlib/tktrans/tktrans.rb ================================================ # # TkTrans support (win32 only) # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/tktrans/setup.rb' TkPackage.require('tktrans') rescue Tk.load_tcllibrary('tktrans') module Tk module TkTrans PACKAGE_NAME = 'tktrans'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('tktrans') rescue '' end end end end class TkWindow def tktrans_set_image(img) tk_send('tktrans::setwidget', @path, img) self end def tktrans_get_image() tk_send('tktrans::setwidget', @path) end end class Tk::Root undef tktrans_set_image, tktrans_get_image def tktrans_set_image(img) tk_send('tktrans::settoplevel', @path, img) self end def tktrans_get_image() tk_send('tktrans::settoplevel', @path) end end class Tk::Toplevel undef tktrans_set_image, tktrans_get_image def tktrans_set_image(img) tk_send('tktrans::settoplevel', @path, img) self end def tktrans_get_image() tk_send('tktrans::settoplevel', @path) end end ================================================ FILE: ext/tk/lib/tkextlib/tktrans.rb ================================================ # # TkTrans support (win32 only) # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/tktrans/setup.rb' # load library require 'tkextlib/tktrans/tktrans' ================================================ FILE: ext/tk/lib/tkextlib/treectrl/setup.rb ================================================ # # setup.rb -- setup script before calling TkPackage.require() # # If you need some setup operations (for example, add a library path # to the library search path) before using Tcl/Tk library packages # wrapped by Ruby scripts in this directory, please write the setup # operations in this file. # ================================================ FILE: ext/tk/lib/tkextlib/treectrl/tktreectrl.rb ================================================ # # tkextlib/treectrl/tktreectrl.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/treectrl/setup.rb' # TkPackage.require('treectrl', '1.0') # TkPackage.require('treectrl', '1.1') TkPackage.require('treectrl') module Tk class TreeCtrl < TkWindow BindTag_FileList = TkBindTag.new_by_name('TreeCtrlFileList') PACKAGE_NAME = 'treectrl'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('treectrl') rescue '' end end HasColumnCreateCommand = (TkPackage.vcompare(self.package_version, '1.1') >= 0) # dummy :: # pkgIndex.tcl of TreeCtrl-1.0 doesn't support auto_load for # 'loupe' command (probably it is bug, I think). # So, calling a 'treectrl' command for loading the dll with # the auto_load facility. begin tk_call('treectrl') rescue end def self.loupe(img, x, y, w, h, zoom) # NOTE: platform == 'unix' only # img => TkPhotoImage # x, y => screen coords # w, h => magnifier width and height # zoom => zooming rate Tk.tk_call_without_enc('loupe', img, x, y, w, h, zoom) end def self.text_layout(font, text, keys={}) TkComm.list(Tk.tk_call_without_enc('textlayout', font, text, keys)) end def self.image_tint(img, color, alpha) Tk.tk_call_without_enc('imagetint', img, color, alpha) end class NotifyEvent < TkUtil::CallbackSubst end module ConfigMethod end end TreeCtrl_Widget = TreeCtrl end ############################################## class Tk::TreeCtrl::NotifyEvent # [ <'%' subst-key char>, , ] KEY_TBL = [ [ ?c, ?n, :item_num ], [ ?d, ?s, :detail ], [ ?D, ?l, :items ], [ ?e, ?e, :event ], [ ?I, ?n, :id ], [ ?l, ?n, :lower_bound ], [ ?p, ?n, :active_id ], [ ?P, ?e, :pattern ], [ ?S, ?l, :sel_items ], [ ?T, ?w, :widget ], [ ?u, ?n, :upper_bound ], [ ?W, ?o, :object ], [ ??, ?x, :parm_info ], nil ] # [ , ] PROC_TBL = [ [ ?n, TkComm.method(:num_or_str) ], [ ?s, TkComm.method(:string) ], [ ?l, TkComm.method(:list) ], [ ?w, TkComm.method(:window) ], [ ?e, proc{|val| case val when /^<<[^<>]+>>$/ TkVirtualEvent.getobj(val[1..-2]) when /^<[^<>]+>$/ val[1..-2] else val end } ], [ ?o, proc{|val| TkComm.tk_tcl2ruby(val)} ], [ ?x, proc{|val| begin inf = {} Hash[*(TkComm.list(val))].each{|k, v| if keyinfo = KEY_TBL.assoc(k[0]) if cmd = PROC_TBL.assoc(keyinfo[1]) begin new_v = cmd.call(v) v = new_v rescue end end end inf[k] = v } inf rescue val end } ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end # setup tables to be used by scan_args, _get_subst_key, _get_all_subst_keys # # _get_subst_key() and _get_all_subst_keys() generates key-string # which describe how to convert callback arguments to ruby objects. # When binding parameters are given, use _get_subst_key(). # But when no parameters are given, use _get_all_subst_keys() to # create a Event class object as a callback parameter. # # scan_args() is used when doing callback. It convert arguments # ( which are Tcl strings ) to ruby objects based on the key string # that is generated by _get_subst_key() or _get_all_subst_keys(). # _setup_subst_table(KEY_TBL, PROC_TBL); end ############################################## module Tk::TreeCtrl::ConfigMethod include TkItemConfigMethod def treectrl_tagid(key, obj) if key.kind_of?(Array) key = key.join(' ') else key = key.to_s end if (obj.kind_of?(Tk::TreeCtrl::Column) || obj.kind_of?(Tk::TreeCtrl::Element) || obj.kind_of?(Tk::TreeCtrl::Item) || obj.kind_of?(Tk::TreeCtrl::Style)) obj = obj.id end case key when 'column' obj when 'debug' None when 'dragimage' None when 'element' obj when 'item element' obj when 'marquee' None when 'notify' obj when 'style' obj else obj end end def tagid(mixed_id) if mixed_id == 'debug' ['debug', None] elsif mixed_id == 'dragimage' ['dragimage', None] elsif mixed_id == 'marquee' ['marquee', None] elsif mixed_id.kind_of?(Array) [mixed_id[0], treectrl_tagid(*mixed_id)] else tagid(mixed_id.split(':')) end end def __item_cget_cmd(mixed_id) if mixed_id[0] == 'column' && mixed_id[1] == 'drag' return [self.path, 'column', 'dragcget'] end if mixed_id[1].kind_of?(Array) id = mixed_id[1] else id = [mixed_id[1]] end if mixed_id[0].kind_of?(Array) ([self.path].concat(mixed_id[0]) << 'cget').concat(id) else [self.path, mixed_id[0], 'cget'].concat(id) end end private :__item_cget_cmd def __item_config_cmd(mixed_id) if mixed_id[0] == 'column' && mixed_id[1] == 'drag' return [self.path, 'column', 'dragconfigure'] end if mixed_id[1].kind_of?(Array) id = mixed_id[1] else id = [mixed_id[1]] end if mixed_id[0].kind_of?(Array) ([self.path].concat(mixed_id[0]) << 'configure').concat(id) else [self.path, mixed_id[0], 'configure'].concat(id) end end private :__item_config_cmd def __item_pathname(id) if id.kind_of?(Array) key = id[0] if key.kind_of?(Array) key = key.join(' ') end tag = id[1] if tag.kind_of?(Array) tag = tag.join(' ') end id = [key, tag].join(':') end [self.path, id].join(';') end private :__item_pathname def __item_configinfo_struct(id) if id.kind_of?(Array) && id[0].to_s == 'notify' {:key=>0, :alias=>nil, :db_name=>nil, :db_class=>nil, :default_value=>nil, :current_value=>1} else {:key=>0, :alias=>1, :db_name=>1, :db_class=>2, :default_value=>3, :current_value=>4} end end private :__item_configinfo_struct def __item_font_optkeys(id) if id.kind_of?(Array) && (id[0] == 'element' || (id[0].kind_of?(Array) && id[0][1] == 'element')) [] else ['font'] end end private :__item_font_optkeys def __item_numstrval_optkeys(id) if id == 'debug' ['displaydelay'] else super(id) end end private :__item_numstrval_optkeys def __item_boolval_optkeys(id) if id == 'debug' ['data', 'display', 'enable'] elsif id == 'dragimage' ['visible'] elsif id == 'marquee' ['visible'] elsif id.kind_of?(Array) case id[0] when 'item' ['button', 'visible'] when 'column' if id[1] == 'drag' ['enable'] else ['button', 'expand', 'resize', 'squeeze', 'sunken', 'visible', 'widthhack'] end when 'element' ['draw', 'filled', 'showfocus', 'destroy'] when 'notify' ['active'] when 'style' ['detach'] else if id[0].kind_of?(Array) && id[0][1] == 'element' ['filled', 'showfocus'] else super(id) end end else super(id) end end private :__item_boolval_optkeys def __item_strval_optkeys(id) if id == 'debug' ['erasecolor'] elsif id.kind_of?(Array) case id[0] when 'column' if id[1] == 'drag' ['indicatorcolor'] else super(id) << 'textcolor' end when 'element' super(id) << 'fill' << 'outline' << 'format' else super(id) end else super(id) end end private :__item_strval_optkeys def __item_listval_optkeys(id) if id.kind_of?(Array) case id[0] when 'column' ['itembackground'] when 'element' ['relief'] when 'style' ['union'] else if id[0].kind_of?(Array) && id[0][1] == 'element' ['relief'] else [] end end else [] end end private :__item_listval_optkeys def __item_keyonly_optkeys(id) # { def_key=>(undef_key|nil), ... } { 'notreally'=>nil, 'increasing'=>'decreasing', 'decreasing'=>'increasing', 'ascii'=>nil, 'dictionary'=>nil, 'integer'=>nil, 'real'=>nil } end private :__item_keyonly_optkeys def column_cget(tagOrId, option) itemcget(['column', tagOrId], option) end def column_cget_strict(tagOrId, option) itemcget_strict(['column', tagOrId], option) end def column_configure(tagOrId, slot, value=None) itemconfigure(['column', tagOrId], slot, value) end def column_configinfo(tagOrId, slot=nil) itemconfiginfo(['column', tagOrId], slot) end def current_column_configinfo(tagOrId, slot=nil) current_itemconfiginfo(['column', tagOrId], slot) end def column_dragcget(option) itemcget(['column', 'drag'], option) end def column_dragcget_strict(option) itemcget_strict(['column', 'drag'], option) end def column_dragconfigure(slot, value=None) itemconfigure(['column', 'drag'], slot, value) end def column_dragconfiginfo(slot=nil) itemconfiginfo(['column', 'drag'], slot) end def current_column_dragconfiginfo(slot=nil) current_itemconfiginfo(['column', 'drag'], slot) end def debug_cget(option) itemcget('debug', option) end def debug_cget_strict(option) itemcget_strict('debug', option) end def debug_configure(slot, value=None) itemconfigure('debug', slot, value) end def debug_configinfo(slot=nil) itemconfiginfo('debug', slot) end def current_debug_configinfo(slot=nil) current_itemconfiginfo('debug', slot) end def dragimage_cget(option) itemcget('dragimage', option) end def dragimage_cget_strict(option) itemcget_strict('dragimage', option) end def dragimage_configure(slot, value=None) itemconfigure('dragimage', slot, value) end def dragimage_configinfo(slot=nil) itemconfiginfo('dragimage', slot) end def current_dragimage_configinfo(slot=nil) current_itemconfiginfo('dragimage', slot) end def element_cget(tagOrId, option) itemcget(['element', tagOrId], option) end def element_cget_strict(tagOrId, option) itemcget_strict(['element', tagOrId], option) end def element_configure(tagOrId, slot, value=None) itemconfigure(['element', tagOrId], slot, value) end def element_configinfo(tagOrId, slot=nil) itemconfiginfo(['element', tagOrId], slot) end def current_element_configinfo(tagOrId, slot=nil) current_itemconfiginfo(['element', tagOrId], slot) end def item_cget(tagOrId, option) itemcget(['item', tagOrId], option) end def item_cget_strict(tagOrId, option) itemcget_strict(['item', tagOrId], option) end def item_configure(tagOrId, slot, value=None) itemconfigure(['item', tagOrId], slot, value) end def item_configinfo(tagOrId, slot=nil) itemconfiginfo(['item', tagOrId], slot) end def current_item_configinfo(tagOrId, slot=nil) current_itemconfiginfo(['item', tagOrId], slot) end def item_element_cget(item, column, elem, option) itemcget([['item', 'element'], [item, column, elem]], option) end def item_element_cget_strict(item, column, elem, option) itemcget_strict([['item', 'element'], [item, column, elem]], option) end def item_element_configure(item, column, elem, slot, value=None) itemconfigure([['item', 'element'], [item, column, elem]], slot, value) end def item_element_configinfo(item, column, elem, slot=nil) itemconfiginfo([['item', 'element'], [item, column, elem]], slot) end def current_item_element_configinfo(item, column, elem, slot=nil) current_itemconfiginfo([['item', 'element'], [item, column, elem]], slot) end def marquee_cget(option) itemcget('marquee', option) end def marquee_cget_strict(option) itemcget_strict('marquee', option) end def marquee_configure(slot, value=None) itemconfigure('marquee', slot, value) end def marquee_configinfo(slot=nil) itemconfiginfo('marquee', slot) end def current_marquee_configinfo(slot=nil) current_itemconfiginfo('marquee', slot) end def notify_cget(win, pattern, option) pattern = "<#{pattern}>" # "notify" doesn't have cget subcommand. current_itemconfiginfo(['notify', [win, pattern]])[option.to_s] end def notify_cget_strict(win, pattern, option) pattern = "<#{pattern}>" # "notify" doesn't have cget subcommand. info = current_itemconfiginfo(['notify', [win, pattern]]) option = option.to_s unless info.has_key?(option) fail RuntimeError, "unknown option \"#{option}\"" else info[option] end end def notify_configure(win, pattern, slot, value=None) pattern = "<#{pattern}>" itemconfigure(['notify', [win, pattern]], slot, value) end def notify_configinfo(win, pattern, slot=nil) pattern = "<#{pattern}>" itemconfiginfo(['notify', [win, pattern]], slot) end def current_notify_configinfo(tagOrId, slot=nil) pattern = "<#{pattern}>" current_itemconfiginfo(['notify', [win, pattern]], slot) end def style_cget(tagOrId, option) itemcget(['style', tagOrId], option) end def style_cget_strict(tagOrId, option) itemcget_strict(['style', tagOrId], option) end def style_configure(tagOrId, slot, value=None) itemconfigure(['style', tagOrId], slot, value) end def style_configinfo(tagOrId, slot=nil) itemconfiginfo(['style', tagOrId], slot) end def current_style_configinfo(tagOrId, slot=nil) current_itemconfiginfo(['style', tagOrId], slot) end private :itemcget, :itemcget_strict private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo end ############################################## class Tk::TreeCtrl include Tk::TreeCtrl::ConfigMethod include Scrollable TkCommandNames = ['treectrl'.freeze].freeze WidgetClassName = 'TreeCtrl'.freeze WidgetClassNames[WidgetClassName] = self ######################### def __destroy_hook__ Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.delete(@path) } Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.delete(@path) } Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.delete(@path) } Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.delete(@path) } end ######################### def __strval_optkeys super() + [ 'buttoncolor', 'columnprefix', 'itemprefix', 'linecolor' ] end private :__strval_optkeys def __boolval_optkeys [ 'itemwidthequal', 'usetheme', 'showbuttons', 'showheader', 'showlines', 'showroot', 'showrootbutton', 'showrootlines', ] end private :__boolval_optkeys def __listval_optkeys [ 'defaultstyle' ] end private :__listval_optkeys ######################### def install_bind(cmd, *args) install_bind_for_event_class(Tk::TreeCtrl::NotifyEvent, cmd, *args) end ######################### def create_self(keys) if keys and keys != None tk_call_without_enc(self.class::TkCommandNames[0], @path, *hash_kv(keys, true)) else tk_call_without_enc(self.class::TkCommandNames[0], @path) end end private :create_self ######################### def activate(desc) tk_send('activate', desc) self end def canvasx(x) number(tk_send('canvasx', x)) end def canvasy(y) number(tk_send('canvasy', y)) end def collapse(*dsc) tk_send_without_enc('collapse', *(dsc.map!{|d| _get_eval_string(d, true)})) self end def collapse_recurse(*dsc) tk_send_without_enc('collapse', '-recurse', *(dsc.map!{|d| _get_eval_string(d, true)})) self end def column_bbox(idx) list(tk_send('column', 'bbox', idx)) end def column_compare(column1, op, column2) bool(tk_send('column', 'compare', column1, op, column2)) end def column_count num_or_str(tk_send('column', 'count')) end def column_create(keys=nil) if keys && keys.kind_of?(Hash) num_or_str(tk_send('column', 'create', *hash_kv(keys))) else num_or_str(tk_send('column', 'create')) end end def column_delete(idx) Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ if Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[self.path] Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[self.path].delete(idx) end } tk_send('column', 'delete', idx) self end def column_index(idx) num_or_str(tk_send('column', 'index', idx)) end def column_id(idx) tk_send('column', 'id', idx) end def column_list(visible=false) if visible simplelist(tk_send('column', 'list', '-visible')) else simplelist(tk_send('column', 'list')) end end def column_visible_list column_list(true) end def column_move(idx, before) tk_send('column', 'move', idx, before) self end def column_needed_width(idx) num_or_str(tk_send('column', 'neededwidth', idx)) end alias column_neededwidth column_needed_width def column_order(column, visible=false) if visible num_or_str(tk_send('column', 'order', column, '-visible')) else num_or_str(tk_send('column', 'order', column)) end end def column_visible_order(column) column_order(column, true) end def column_width(idx) num_or_str(tk_send('column', 'width', idx)) end def compare(item1, op, item2) bool(tk_send('compare', item1, op, item2)) end def contentbox() list(tk_send('contentbox')) end def depth(item=None) num_or_str(tk_send_without_enc('depth', _get_eval_string(item, true))) end def dragimage_add(item, *args) tk_send('dragimage', 'add', item, *args) self end def dragimage_clear() tk_send('dragimage', 'clear') self end def dragimage_offset(*args) # x, y if args.empty? list(tk_send('dragimage', 'offset')) else tk_send('dragimage', 'offset', *args) self end end def dragimage_visible(*args) # mode if args..empty? bool(tk_send('dragimage', 'visible')) else tk_send('dragimage', 'visible', *args) self end end def dragimage_visible? dragimage_visible() end def debug_dinfo tk_send('debug', 'dinfo') self end def debug_scroll tk_send('debug', 'scroll') end def element_create(elem, type, keys=nil) if keys && keys.kind_of?(Hash) tk_send('element', 'create', elem, type, *hash_kv(keys)) else tk_send('element', 'create', elem, type) end end def element_delete(*elems) Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ if Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[self.path] elems.each{|elem| Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[self.path].delete(elem) } end } tk_send('element', 'delete', *elems) self end def element_names() list(tk_send('element', 'names')).collect!{|elem| Tk::TreeCtrl::Element.id2obj(self, elem) } end def _conv_element_perstate_val(opt, val) case opt when 'background', 'foreground', 'fill', 'outline', 'format' val when 'draw', 'filled', 'showfocus', 'destroy' bool(val) else tk_tcl2ruby(val) end end private :_conv_element_perstate_val def element_perstate(elem, opt, st_list) tk_send('element', 'perstate', elem, "-{opt}", st_list) end def element_type(elem) tk_send('element', 'type', elem) end def element_class(elem) Tk::TreeCtrl::Element.type2class(element_type(elem)) end def expand(*dsc) tk_send('expand', *dsc) self end def expand_recurse(*dsc) tk_send('expand', '-recurse', *dsc) self end def identify(x, y) lst = list(tk_send('identify', x, y)) if lst[0] == 'item' lst[1] = Tk::TreeCtrl::Item.id2obj(self, lst[1]) size = lst.size i = 2 while i < size case lst[i] when 'line' i += 1 lst[i] = Tk::TreeCtrl::Item.id2obj(self, lst[i]) i += 1 when 'button' i += 1 when 'column' i += 2 when 'elem' i += 1 lst[i] = Tk::TreeCtrl::Element.id2obj(self, lst[i]) i += 1 else i += 1 end end end lst end def index(idx) num_or_str(tk_send('index', idx)) end def item_ancestors(item) list(tk_send('item', 'ancestors', item)).collect!{|id| Tk::TreeCtrl::Item.id2obj(self, id) } end def item_bbox(item, *args) list(tk_send('item', 'bbox', item, *args)) end def item_children(item) list(tk_send('item', 'children', item)).collect!{|id| Tk::TreeCtrl::Item.id2obj(self, id) } end def item_collapse(item) tk_send_without_enc('item', 'collapse', _get_eval_string(item, true)) self end def item_collapse_recurse(item) tk_send_without_enc('item', 'collapse', _get_eval_string(item, true), '-recurse') self end def item_compare(item1, op, item2) bool(tk_send('item', 'compare', item1, op, item2)) end def item_complex(item, *args) tk_send_without_enc('item', 'complex', _get_eval_string(item, true), *(args.map!{|arg| _get_eval_string(arg, true)})) self end def item_count num_or_str(tk_send('item', 'count')) end def item_create(keys={}) num_or_str(tk_send_without_enc('item', 'create', *hash_kv(keys, true))) end def _erase_children(item) item_children(item).each{|i| _erase_children(i)} # table is already locked Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path].delete(item) end private :_erase_children def item_delete(first, last=None) Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ if Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path] if first == 'all' || first == :all || last == 'all' || last == :all Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path].clear elsif last == None _erase_children(first) else self.range(first, last).each{|id| _erase_children(id) } end end } tk_send('item', 'delete', first, last) self end def item_dump(item) list(tk_send('item', 'dump', item)) end def item_dump_hash(item) Hash[*list(tk_send('item', 'dump', item))] end def item_element_actual(item, column, elem, key) tk_send('item', 'element', 'actual', item, column, elem, "-#{key}") end def item_element_perstate(elem, opt, st_list) tk_send('item', 'element', 'perstate', elem, "-{opt}", st_list) end def item_expand(item) tk_send('item', 'expand', item) self end def item_expand_recurse(item) tk_send('item', 'expand', item, '-recurse') self end def item_firstchild(parent, child=nil) if child tk_send_without_enc('item', 'firstchild', _get_eval_string(parent, true), _get_eval_string(child, true)) self else id = num_or_str(tk_send_without_enc('item', 'firstchild', _get_eval_string(parent, true))) Tk::TreeCtrl::Item.id2obj(self, id) end end alias item_first_child item_firstchild def item_hasbutton(item, st=None) if st == None bool(tk_send_without_enc('item', 'hasbutton', _get_eval_string(item, true))) else tk_send_without_enc('item', 'hasbutton', _get_eval_string(item, true), _get_eval_string(st)) self end end alias item_has_button item_hasbutton def item_hasbutton?(item) item_hasbutton(item) end alias item_has_button? item_hasbutton? def item_id(item) tk_send('item', 'id', item) end def item_image(item, column=nil, *args) if args.empty? if column img = tk_send('item', 'image', item, column) TkImage::Tk_IMGTBL[img]? TkImage::Tk_IMGTBL[img] : img else simplelist(tk_send('item', 'image', item)).collect!{|img| TkImage::Tk_IMGTBL[img]? TkImage::Tk_IMGTBL[img] : img } end else tk_send('item', 'image', item, column, *args) self end end def get_item_image(item, column=nil) item_image(item, column) end def set_item_image(item, col, img, *args) item_image(item, col, img, *args) end def item_index(item) list(tk_send('item', 'index', item)) end def item_isancestor(item, des) bool(tk_send('item', 'isancestor', item, des)) end alias item_is_ancestor item_isancestor alias item_isancestor? item_isancestor alias item_is_ancestor? item_isancestor def item_isopen(item) bool(tk_send('item', 'isopen', item)) end alias item_is_open item_isopen alias item_isopen? item_isopen alias item_is_open? item_isopen alias item_isopened? item_isopen alias item_is_opened? item_isopen def item_lastchild(parent, child=nil) if child tk_send_without_enc('item', 'lastchild', _get_eval_string(parent, true), _get_eval_string(child, true)) self else id = num_or_str(tk_send_without_enc('item', 'lastchild', _get_eval_string(parent, true))) Tk::TreeCtrl::Item.id2obj(self, id) end end alias item_last_child item_lastchild def item_nextsibling(sibling, nxt=nil) if nxt tk_send('item', 'nextsibling', sibling, nxt) self else id = num_or_str(tk_send('item', 'nextsibling', sibling)) Tk::TreeCtrl::Item.id2obj(self, id) end end alias item_next_sibling item_nextsibling def item_numchildren(item) number(tk_send_without_enc('item', 'numchildren', _get_eval_string(item, true))) end alias item_num_children item_numchildren alias item_children_size item_numchildren def item_order(item, visible=false) if visible ret = num_or_str(tk_send('item', 'order', item, '-visible')) else ret = num_or_str(tk_send('item', 'order', item)) end (ret.kind_of?(Fixnum) && ret < 0)? nil: ret end def item_visible_order(item) item_order(item, true) end def item_parent(item) id = num_or_str(tk_send('item', 'parent', item)) Tk::TreeCtrl::Item.id2obj(self, id) end def item_prevsibling(sibling, prev=nil) if prev tk_send('item', 'prevsibling', sibling, prev) self else id = num_or_str(tk_send('item', 'prevsibling', sibling)) Tk::TreeCtrl::Item.id2obj(self, id) end end alias item_prev_sibling item_prevsibling def item_range(first, last) simplelist(tk_send('item', 'range', first, last)) end def item_remove(item) tk_send('item', 'remove', item) self end def item_rnc(item) list(tk_send('item', 'rnc', item)) end def _item_sort_core(real_sort, item, *opts) # opts ::= sort_param [, sort_param, ... ] # sort_param ::= {key=>val, ...} # [type, desc, {key=>val, ...}] # param opts = opts.collect{|param| if param.kind_of?(Hash) param = _symbolkey2str(param) if param.key?('column') key = '-column' desc = param.delete('column') elsif param.key?('element') key = '-element' desc = param.delete('element') else key = nil end if param.empty? param = None else param = hash_kv(__conv_item_keyonly_opts(item, param)) end if key [key, desc].concat(param) else param end elsif param.kind_of?(Array) if param[2].kind_of?(Hash) param[2] = hash_kv(__conv_item_keyonly_opts(item, param[2])) end param elsif param.kind_of?(String) && param =~ /\A[a-z]+\Z/ '-' << param elsif param.kind_of?(Symbol) '-' << param.to_s else param end }.flatten if real_sort tk_send('item', 'sort', item, *opts) self else list(tk_send('item', 'sort', item, '-notreally', *opts)) end end private :_item_sort_core def item_sort(item, *opts) _item_sort_core(true, item, *opts) end def item_sort_not_really(item, *opts) _item_sort_core(false, item, *opts) end def item_span(item, column=nil, *args) if args.empty? if column list(tk_send('item', 'span', item, column)) else simplelist(tk_send('item', 'span', item)).collect!{|elem| list(elem)} end else tk_send('item', 'span', item, column, *args) self end end def get_item_span(item, column=nil) item_span(item, column) end def set_item_span(item, col, num, *args) item_span(item, col, num, *args) end def item_state_forcolumn(item, column, *args) tk_send('item', 'state', 'forcolumn', item, column, *args) end alias item_state_for_column item_state_forcolumn def item_state_get(item, *args) if args.empty? list(tk_send('item', 'state', 'get', item *args)) else bool(tk_send('item', 'state', 'get', item)) end end def item_state_set(item, *args) tk_send('item', 'state', 'set', item, *args) end def item_style_elements(item, column) list(tk_send('item', 'style', 'elements', item, column)).collect!{|id| Tk::TreeCtrl::Style.id2obj(self, id) } end def item_style_map(item, column, style, map) tk_send('item', 'style', 'map', item, column, style, map) self end def item_style_set(item, column=nil, *args) if args.empty? if column id = tk_send_without_enc('item', 'style', 'set', _get_eval_string(item, true), _get_eval_string(column, true)) Tk::TreeCtrl::Style.id2obj(self, id) else list(tk_send_without_enc('item', 'style', 'set', _get_eval_string(item, true))).collect!{|id| Tk::TreeCtrl::Style.id2obj(self, id) } end else tk_send_without_enc('item', 'style', 'set', _get_eval_string(item, true), _get_eval_string(column, true), *(args.flatten.map!{|arg| _get_eval_string(arg, true) })) self end end def item_text(item, column, txt=nil, *args) if args.empty? if txt tk_send('item', 'text', item, column, txt) self else tk_send('item', 'text', item, column) end else tk_send('item', 'text', item, column, txt, *args) self end end def item_toggle(item) tk_send('item', 'toggle', item) self end def item_toggle_recurse(item) tk_send('item', 'toggle', item, '-recurse') self end def item_visible(item, st=None) if st == None bool(tk_send('item', 'visible', item)) else tk_send('item', 'visible', item, st) self end end def item_visible?(item) item_visible(item) end def marquee_anchor(*args) if args.empty? list(tk_send('marquee', 'anchor')) else tk_send('marquee', 'anchor', *args) self end end def marquee_coords(*args) if args.empty? list(tk_send('marquee', 'coords')) else tk_send('marquee', 'coords', *args) self end end def marquee_corner(*args) if args.empty? tk_send('marquee', 'corner') else tk_send('marquee', 'corner', *args) self end end def marquee_identify() list(tk_send('marquee', 'identify')).collect!{|id| Tk::TreeCtrl::Item.id2obj(self, id) } end def marquee_visible(st=None) if st == None bool(tk_send('marquee', 'visible')) else tk_send('marquee', 'visible', st) self end end def marquee_visible?() marquee_visible() end #def notify_bind(obj, event, cmd=Proc.new, *args) # _bind([@path, 'notify', 'bind', obj], event, cmd, *args) # self #end def notify_bind(obj, event, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind([@path, 'notify', 'bind', obj], event, cmd, *args) self end #def notify_bind_append(obj, event, cmd=Proc.new, *args) # _bind_append([@path, 'notify', 'bind', obj], event, cmd, *args) # self #end def notify_bind_append(obj, event, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new end _bind_append([@path, 'notify', 'bind', obj], event, cmd, *args) self end def notify_bind_remove(obj, event) _bind_remove([@path, 'notify', 'bind', obj], event) self end def notify_bindinfo(obj, event=nil) _bindinfo([@path, 'notify', 'bind', obj], event) end def notify_detailnames(event) list(tk_send('notify', 'detailnames', event)) end def notify_eventnames() list(tk_send('notify', 'eventnames')) end def notify_generate(pattern, char_map=None, percents_cmd=None) pattern = "<#{pattern}>" tk_send('notify', 'generate', pattern, char_map, percents_cmd) self end def notify_install(pattern, percents_cmd=nil, &b) pattern = "<#{pattern}>" percents_cmd = Proc.new(&b) if !percents_cmd && b if percents_cmd procedure(tk_send('notify', 'install', pattern, percents_cmd)) else procedure(tk_send('notify', 'install', pattern)) end end def notify_install_detail(event, detail, percents_cmd=nil, &b) percents_cmd = Proc.new(&b) if !percents_cmd && b if percents_cmd tk_send('notify', 'install', 'detail', event, detail, percents_cmd) else tk_send('notify', 'install', 'detail', event, detail) end end def notify_install_event(event, percents_cmd=nil, &b) percents_cmd = Proc.new(&b) if !percents_cmd && b if percents_cmd tk_send('notify', 'install', 'event', event, percents_cmd) else tk_send('notify', 'install', 'event', event) end end def notify_linkage(pattern, detail=None) if detail != None tk_send('notify', 'linkage', pattern, detail) else begin if pattern.to_s.index(?-) # TreeCtrl 1.1 format? begin tk_send('notify', 'linkage', "<#{pattern}>") rescue # TreeCtrl 1.0? tk_send('notify', 'linkage', pattern) end else # TreeCtrl 1.0 format? begin tk_send('notify', 'linkage', pattern) rescue # TreeCtrl 1.1? tk_send('notify', 'linkage', "<#{pattern}>") end end end end end def notify_unbind(pattern=nil) if pattern tk_send('notify', 'unbind', "<#{pattern}>") else tk_send('notify', 'unbind') end self end def notify_uninstall(pattern) pattern = "<#{pattern}>" tk_send('notify', 'uninstall', pattern) self end def notify_uninstall_detail(event, detail) tk_send('notify', 'uninstall', 'detail', event, detail) self end def notify_uninstall_event(event) tk_send('notify', 'uninstall', 'event', event) self end def numcolumns() num_or_str(tk_send('numcolumns')) end alias num_columns numcolumns alias columns_size numcolumns def numitems() num_or_str(tk_send('numitems')) end alias num_items numitems alias items_size numitems def orphans() list(tk_send('orphans')).collect!{|id| Tk::TreeCtrl::Item.id2obj(self, id) } end def range(first, last) list(tk_send('range', first, last)).collect!{|id| Tk::TreeCtrl::Item.id2obj(self, id) } end def state_define(name) tk_send('state', 'define', name) self end def state_linkage(name) tk_send('state', 'linkage', name) end def state_names() list(tk_send('state', 'names')) end def state_undefine(*names) tk_send('state', 'undefine', *names) self end def see(item) tk_send('see', item) self end def selection_add(first, last=None) tk_send('selection', 'add', first, last) self end def selection_anchor(item=None) id = num_or_str(tk_send('selection', 'anchor', item)) Tk::TreeCtrl::Item.id2obj(self, id) end def selection_clear(*args) # first, last tk_send('selection', 'clear', *args) self end def selection_count() number(tk_send('selection', 'count')) end def selection_get() list(tk_send('selection', 'get')).collect!{|id| Tk::TreeCtrl::Item.id2obj(self, id) } end def selection_includes(item) bool(tk_send('selection', 'includes', item)) end def selection_modify(sel, desel) tk_send('selection', 'modify', sel, desel) self end def style_create(style, keys=None) if keys && keys != None tk_send('style', 'create', style, *hash_kv(keys)) else tk_send('style', 'create', style) end end def style_delete(*args) Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ if Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[self.path] args.each{|sty| Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[self.path].delete(sty) } end } tk_send('style', 'delete', *args) self end def style_elements(style, *elems) if elems.empty? list(tk_send('style', 'elements', style)).collect!{|id| Tk::TreeCtrl::Element.id2obj(self, id) } else tk_send('style', 'elements', style, elems.flatten) self end end def _conv_style_layout_val(sty, val) case sty.to_s when 'padx', 'pady', 'ipadx', 'ipady' lst = list(val) (lst.size == 1)? lst[0]: lst when 'detach', 'indent' bool(val) when 'union' simplelist(val).collect!{|elem| Tk::TreeCtrl::Element.id2obj(self, elem) } else val end end private :_conv_style_layout_val def style_layout(style, elem, keys=None) if keys && keys != None if keys.kind_of?(Hash) tk_send('style', 'layout', style, elem, *hash_kv(keys)) self else _conv_style_layout_val(keys, tk_send('style', 'layout', style, elem, "-#{keys}")) end else ret = Hash.new Hash[*simplelist(tk_send('style', 'layout', style, elem))].each{|k, v| k = k[1..-1] ret[k] = _conv_style_layout_val(k, v) } ret end end def get_style_layout(style, elem, opt=None) style_layout(style, elem, opt) end def set_style_layout(style, elem, slot, value=None) if slot.kind_of?(Hash) style_layout(style, elem, slot) else style_layout(style, elem, {slot=>value}) end end def style_names() list(tk_send('style', 'names')).collect!{|id| Tk::TreeCtrl::Style.id2obj(self, id) } end def toggle(*items) tk_send('toggle', *items) self end def toggle_recurse() tk_send('toggle', '-recurse', *items) self end end ##################### class Tk::TreeCtrl::Column < TkObject TreeCtrlColumnID_TBL = TkCore::INTERP.create_table (TreeCtrlColumnID = ['treectrl_column'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } TkCore::INTERP.init_ip_env{ Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.clear } } def self.id2obj(tree, id) tpath = tree.path Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ if Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath] Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath][id]? \ Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath][id] : id else id end } end def initialize(parent, keys={}) @tree = parent @tpath = parent.path keys = _symbolkey2str(keys) Tk::TreeCtrl::Column::TreeCtrlColumnID.mutex.synchronize{ @path = @id = keys.delete('tag') || Tk::TreeCtrl::Column::TreeCtrlColumnID.join(TkCore::INTERP._ip_id_) Tk::TreeCtrl::Column::TreeCtrlColumnID[1].succ! } keys['tag'] = @id Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath] ||= {} Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath][@id] = self } @tree.column_create(keys) end def id @id end def to_s @id.to_s.dup end def cget(opt) @tree.column_cget(@tree.column_index(@id), opt) end def cget_strict(opt) @tree.column_cget_strict(@tree.column_index(@id), opt) end def configure(*args) @tree.column_configure(@tree.column_index(@id), *args) end def configinfo(*args) @tree.column_configinfo(@tree.column_index(@id), *args) end def current_configinfo(*args) @tree.current_column_configinfo(@tree.column_index(@id), *args) end def delete @tree.column_delete(@tree.column_index(@id)) self end def index @tree.column_index(@id) end def move(before) @tree.column_move(@tree.column_index(@id), before) self end def needed_width @tree.column_needed_width(@tree.column_index(@id)) end alias neededwidth needed_width def current_width @tree.column_width(@tree.column_index(@id)) end end ##################### class Tk::TreeCtrl::Element < TkObject TreeCtrlElementID_TBL = TkCore::INTERP.create_table (TreeCtrlElementID = ['treectrl_element'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } TreeCtrlElemTypeToClass = {} TkCore::INTERP.init_ip_env{ Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.clear } } def self.type2class(type) TreeCtrlElemTypeToClass[type] || type end def self.id2obj(tree, id) tpath = tree.path Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ if Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath] Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath][id]? \ Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath][id] : id else id end } end def initialize(parent, type, keys=nil) @tree = parent @tpath = parent.path @type = type.to_s Tk::TreeCtrl::Element::TreeCtrlElementID.mutex.synchronize{ @path = @id = Tk::TreeCtrl::Element::TreeCtrlElementID.join(TkCore::INTERP._ip_id_) Tk::TreeCtrl::Element::TreeCtrlElementID[1].succ! } Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath] ||= {} Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath][@id] = self } @tree.element_create(@id, @type, keys) end def id @id end def to_s @id.dup end def cget(opt) @tree.element_cget(@id, opt) end def cget_strict(opt) @tree.element_cget_strict(@id, opt) end def configure(*args) @tree.element_configure(@id, *args) end def configinfo(*args) @tree.element_configinfo(@id, *args) end def current_configinfo(*args) @tree.current_element_configinfo(@id, *args) end def delete @tree.element_delete(@id) self end def element_type @tree.element_type(@id) end def element_class @tree.element_class(@id) end end class Tk::TreeCtrl::BitmapElement < Tk::TreeCtrl::Element TreeCtrlElemTypeToClass['bitmap'] = self def initialize(parent, keys=nil) super(parent, 'bitmap', keys) end end class Tk::TreeCtrl::BorderElement < Tk::TreeCtrl::Element TreeCtrlElemTypeToClass['border'] = self def initialize(parent, keys=nil) super(parent, 'border', keys) end end class Tk::TreeCtrl::ImageElement < Tk::TreeCtrl::Element TreeCtrlElemTypeToClass['image'] = self def initialize(parent, keys=nil) super(parent, 'image', keys) end end class Tk::TreeCtrl::RectangleElement < Tk::TreeCtrl::Element TreeCtrlElemTypeToClass['rect'] = self def initialize(parent, keys=nil) super(parent, 'rect', keys) end end ##################### class Tk::TreeCtrl::Item < TkObject TreeCtrlItemID_TBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.clear } } def self.id2obj(tree, id) tpath = tree.path Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ if Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath] Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath][id]? \ Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath][id] : id else id end } end def initialize(parent, keys={}) @tree = parent @tpath = parent.path @path = @id = @tree.item_create(keys) Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath] ||= {} Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath][@id] = self } end def id @id end def to_s @id.to_s.dup end def ancestors @tree.item_ancestors(@id) end def bbox(*args) @tree.item_bbox(@id, *args) end def children @tree.item_children(@id) end def collapse @tree.item_collapse(@id) self end def collapse_recurse @tree.item_collapse_recurse(@id) self end def complex(*args) @tree.item_complex(@id, *args) self end def cget(opt) @tree.item_cget(@id, opt) end def cget_strict(opt) @tree.item_cget_strict(@id, opt) end def configure(*args) @tree.item_configure(@id, *args) end def configinfo(*args) @tree.item_configinfo(@id, *args) end def current_configinfo(*args) @tree.current_item_configinfo(@id, *args) end def delete @tree.item_delete(@id) self end def element_dump @tree.item_dump(@id) end def element_dump_hash @tree.item_dump_hash(@id) end def element_actual(column, elem, key) @tree.item_element_actual(@id, column, elem, key) end def element_cget(opt) @tree.item_element_cget(@id, opt) end def element_cget_strict(opt) @tree.item_element_cget_strict(@id, opt) end def element_configure(*args) @tree.item_element_configure(@id, *args) end def element_configinfo(*args) @tree.item_element_configinfo(@id, *args) end def current_element_configinfo(*args) @tree.current_item_element_configinfo(@id, *args) end def expand @tree.item_expand(@id) self end def expand_recurse @tree.item_expand_recurse(@id) self end def firstchild(child=nil) if child @tree.item_firstchild(@id, child) self else @tree.item_firstchild(@id) end end alias first_child firstchild def hasbutton(st=None) if st == None @tree.item_hasbutton(@id) else @tree.item_hasbutton(@id, st) self end end alias has_button hasbutton def hasbutton? @tree.item_hasbutton(@id) end alias has_button? hasbutton? def index @tree.item_index(@id) end def isancestor(des) @tree.item_isancestor(@id, des) end alias is_ancestor isancestor alias isancestor? isancestor alias is_ancestor? isancestor alias ancestor? isancestor def isopen @tree.item_isopen(@id) end alias is_open isopen alias isopen? isopen alias is_open? isopen alias isopened? isopen alias is_opened? isopen alias open? isopen def lastchild(child=nil) if child @tree.item_lastchild(@id, child) self else @tree.item_lastchild(@id) end end alias last_child lastchild def nextsibling(nxt=nil) if nxt @tree.item_nextsibling(@id, nxt) self else @tree.item_nextsibling(@id) end end alias next_sibling nextsibling def numchildren @tree.item_numchildren(@id) end alias num_children numchildren alias children_size numchildren def parent_index @tree.item_parent(@id) end def prevsibling(nxt=nil) if nxt @tree.item_prevsibling(@id, nxt) self else @tree.item_prevsibling(@id) end end alias prev_sibling prevsibling def remove @tree.item_remove(@id) end def rnc @tree.item_rnc(@id) end def sort(*opts) @tree.item_sort(@id, *opts) end def sort_not_really(*opts) @tree.item_sort_not_really(@id, *opts) self end def state_forcolumn(column, *args) @tree.item_state_forcolumn(@id, column, *args) self end alias state_for_column state_forcolumn def state_get(*args) @tree.item_state_get(@id, *args) end def state_set(*args) @tree.item_state_set(@id, *args) self end def style_elements(column) @tree.item_style_elements(@id, column) end def style_map(column, style, map) @tree.item_style_map(@id, column, style, map) self end def style_set(column=nil, *args) if args.empty? @tree.item_style_set(@id, column) else @tree.item_style_set(@id, column, *args) self end end def item_text(column, txt=nil, *args) if args.empty? if txt @tree.item_text(@id, column, txt) self else @tree.item_text(@id, column) end else @tree.item_text(@id, column, txt, *args) self end end def toggle @tree.item_toggle(@id) self end def toggle_recurse @tree.item_toggle_recurse(@id) self end def visible(st=None) if st == None @tree.item_visible(@id) else @tree.item_visible(@id, st) self end end end ##################### class Tk::TreeCtrl::Style < TkObject TreeCtrlStyleID_TBL = TkCore::INTERP.create_table (TreeCtrlStyleID = ['treectrl_style'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } TkCore::INTERP.init_ip_env{ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.clear } } def self.id2obj(tree, id) tpath = tree.path Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ if Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath] Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath][id]? \ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath][id] : id else id end } end def initialize(parent, keys=nil) @tree = parent @tpath = parent.path Tk::TreeCtrl::Style::TreeCtrlStyleID.mutex.synchronize{ @path = @id = Tk::TreeCtrl::Style::TreeCtrlStyleID.join(TkCore::INTERP._ip_id_) Tk::TreeCtrl::Style::TreeCtrlStyleID[1].succ! } Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath] ||= {} Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath][@id] = self } @tree.style_create(@id, keys) end def id @id end def to_s @id.dup end def cget(opt) @tree.style_cget(@id, opt) end def cget_strict(opt) @tree.style_cget_strict(@id, opt) end def configure(*args) @tree.style_configure(@id, *args) end def configinfo(*args) @tree.style_configinfo(@id, *args) end def current_configinfo(*args) @tree.current_style_configinfo(@id, *args) end def delete @tree.style_delete(@id) self end def elements(*elems) if elems.empty? @tree.style_elements(@id) else @tree.style_elements(@id, *elems) self end end def layout(elem, keys=None) if keys && keys != None && keys.kind_of?(Hash) @tree.style_layout(@id, elem, keys) self else @tree.style_layout(@id, elem, keys) end end end module Tk::TreeCtrl::BindCallback include Tk extend Tk end class << Tk::TreeCtrl::BindCallback def percentsCmd(*args) tk_call('::TreeCtrl::PercentsCmd', *args) end def cursorCheck(w, x, y) tk_call('::TreeCtrl::CursorCheck', w, x, y) end def cursorCheckAux(w) tk_call('::TreeCtrl::CursorCheckAux', w) end def cursorCancel(w) tk_call('::TreeCtrl::CursorCancel', w) end def buttonPress1(w, x, y) tk_call('::TreeCtrl::ButtonPress1', w, x, y) end def doubleButton1(w, x, y) tk_call('::TreeCtrl::DoubleButton1', w, x, y) end def motion1(w, x, y) tk_call('::TreeCtrl::Motion1', w, x, y) end def leave1(w, x, y) tk_call('::TreeCtrl::Leave1', w, x, y) end def release1(w, x, y) tk_call('::TreeCtrl::Release1', w, x, y) end def beginSelect(w, el) tk_call('::TreeCtrl::BeginSelect', w, el) end def motion(w, le) tk_call('::TreeCtrl::Motion', w, el) end def beginExtend(w, el) tk_call('::TreeCtrl::BeginExtend', w, el) end def beginToggle(w, el) tk_call('::TreeCtrl::BeginToggle', w, el) end def cancelRepeat tk_call('::TreeCtrl::CancelRepeat') end def autoScanCheck(w, x, y) tk_call('::TreeCtrl::AutoScanCheck', w, x, y) end def autoScanCheckAux(w) tk_call('::TreeCtrl::AutoScanCheckAux', w) end def autoScanCancel(w) tk_call('::TreeCtrl::AutoScanCancel', w) end def up_down(w, n) tk_call('::TreeCtrl::UpDown', w, n) end def left_right(w, n) tk_call('::TreeCtrl::LeftRight', w, n) end def setActiveItem(w, idx) tk_call('::TreeCtrl::SetActiveItem', w, idx) end def extendUpDown(w, amount) tk_call('::TreeCtrl::ExtendUpDown', w, amount) end def dataExtend(w, el) tk_call('::TreeCtrl::DataExtend', w, el) end def cancel(w) tk_call('::TreeCtrl::Cancel', w) end def selectAll(w) tk_call('::TreeCtrl::selectAll', w) end def marqueeBegin(w, x, y) tk_call('::TreeCtrl::MarqueeBegin', w, x, y) end def marqueeUpdate(w, x, y) tk_call('::TreeCtrl::MarqueeUpdate', w, x, y) end def marqueeEnd(w, x, y) tk_call('::TreeCtrl::MarqueeEnd', w, x, y) end def scanMark(w, x, y) tk_call('::TreeCtrl::ScanMark', w, x, y) end def scanDrag(w, x, y) tk_call('::TreeCtrl::ScanDrag', w, x, y) end # filelist-bindings def fileList_button1(w, x, y) tk_call('::TreeCtrl::FileListButton1', w, x, y) end def fileList_motion1(w, x, y) tk_call('::TreeCtrl::FileListMotion1', w, x, y) end def fileList_motion(w, x, y) tk_call('::TreeCtrl::FileListMotion', w, x, y) end def fileList_leave1(w, x, y) tk_call('::TreeCtrl::FileListLeave1', w, x, y) end def fileList_release1(w, x, y) tk_call('::TreeCtrl::FileListRelease1', w, x, y) end def fileList_edit(w, i, s, e) tk_call('::TreeCtrl::FileListEdit', w, i, s, e) end def fileList_editCancel(w) tk_call('::TreeCtrl::FileListEditCancel', w) end def fileList_autoScanCheck(w, x, y) tk_call('::TreeCtrl::FileListAutoScanCheck', w, x, y) end def fileList_autoScanCheckAux(w) tk_call('::TreeCtrl::FileListAutoScanCheckAux', w) end def entryOpen(w, item, col, elem) tk_call('::TreeCtrl::EntryOpen', w, item, col, elem) end def entryExpanderOpen(w, item, col, elem) tk_call('::TreeCtrl::EntryExpanderOpen', w, item, col, elem) end def entryClose(w, accept) tk_call('::TreeCtrl::EntryClose', w, accept) end def entryExpanderKeypress(w) tk_call('::TreeCtrl::EntryExpanderKeypress', w) end def textOpen(w, item, col, elem, width=0, height=0) tk_call('::TreeCtrl::TextOpen', w, item, col, elem, width, height) end def textExpanderOpen(w, item, col, elem, width) tk_call('::TreeCtrl::TextOpen', w, item, col, elem, width) end def textClose(w, accept) tk_call('::TreeCtrl::TextClose', w, accept) end def textExpanderKeypress(w) tk_call('::TreeCtrl::TextExpanderKeypress', w) end end ================================================ FILE: ext/tk/lib/tkextlib/treectrl.rb ================================================ # # TkTreeCtrl support # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/treectrl/setup.rb' # load library require 'tkextlib/treectrl/tktreectrl' ================================================ FILE: ext/tk/lib/tkextlib/trofs/setup.rb ================================================ # # setup.rb -- setup script before calling TkPackage.require() # # If you need some setup operations (for example, add a library path # to the library search path) before using Tcl/Tk library packages # wrapped by Ruby scripts in this directory, please write the setup # operations in this file. # ================================================ FILE: ext/tk/lib/tkextlib/trofs/trofs.rb ================================================ # # tkextlib/trofs/trofs.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/trofs/setup.rb' # TkPackage.require('trofs', '0.4') TkPackage.require('trofs') module Tk module Trofs extend TkCore PACKAGE_NAME = 'trofs'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('trofs') rescue '' end end ############################################## def self.create_archive(dir, archive) tk_call('::trofs::archive', dir, archive) archive end def self.mount(archive, mountpoint=None) # returns the normalized path to mountpoint tk_call('::trofs::mount', archive, mountpoint) end def self.umount(mountpoint) tk_call('::trofs::umount', mountpoint) mountpoint end end end ================================================ FILE: ext/tk/lib/tkextlib/trofs.rb ================================================ # # trofs support # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/trofs/setup.rb' # load library require 'tkextlib/trofs/trofs.rb' ================================================ FILE: ext/tk/lib/tkextlib/version.rb ================================================ # # release date of tkextlib # module Tk Tkextlib_RELEASE_DATE = '2008-05-23'.freeze end ================================================ FILE: ext/tk/lib/tkextlib/vu/bargraph.rb ================================================ # # ::vu::bargraph widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # create module/class module Tk module Vu class Bargraph < TkWindow end end end # call setup script -- /tkextlib/vu.rb require 'tkextlib/vu.rb' class Tk::Vu::Bargraph < TkWindow TkCommandNames = ['::vu::bargraph'.freeze].freeze WidgetClassName = 'Bargraph'.freeze WidgetClassNames[WidgetClassName] = self ############################### def __boolval_optkeys ['showminmax', 'showvalue'] end private :__boolval_optkeys def __strval_optkeys super() + [ 'title', 'barbackground', 'barcolor', 'barcolour', 'tickcolor', 'tickcolour', 'textcolor', 'textcolour', ] end private :__strval_optkeys def __listval_optkeys ['alabels', 'blabels'] end private :__listval_optkeys def __font_optkeys ['alabfont', 'blabfont'] end private :__font_optkeys ############################### def set(val = None) tk_call_without_enc(@path, 'set', val) self end def get() num_or_str(tk_call_without_enc(@path, 'get')) end end ================================================ FILE: ext/tk/lib/tkextlib/vu/charts.rb ================================================ # # charts -- Create and manipulate canvas Add-On Items # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' require 'tk/canvas' # call setup script -- /tkextlib/vu.rb require 'tkextlib/vu.rb' module Tk module Vu module ChartsConfig include TkItemConfigOptkeys def __item_boolval_optkeys(id) super(id) << 'lefttrunc' << 'autocolor' end private :__item_boolval_optkeys def __item_strval_optkeys(id) super(id) << 'bar' << 'color' << 'outline' << 'fill' << 'scaleline' << 'stripline' end private :__item_strval_optkeys def __item_listval_optkeys(id) super(id) << 'values' << 'tags' end private :__item_listval_optkeys end class TkcSticker < TkcItem include ChartsConfig CItemTypeName = 'sticker'.freeze CItemTypeToClass[CItemTypeName] = self end class TkcStripchart < TkcItem include ChartsConfig CItemTypeName = 'stripchart'.freeze CItemTypeToClass[CItemTypeName] = self end class TkcBarchart < TkcItem include ChartsConfig CItemTypeName = 'barchart'.freeze CItemTypeToClass[CItemTypeName] = self end end end ================================================ FILE: ext/tk/lib/tkextlib/vu/dial.rb ================================================ # # ::vu::dial widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # create module/class module Tk module Vu class Dial < TkWindow end end end # call setup script -- /tkextlib/vu.rb require 'tkextlib/vu.rb' # define module/class class Tk::Vu::Dial < TkWindow TkCommandNames = ['::vu::dial'.freeze].freeze WidgetClassName = 'Dial'.freeze WidgetClassNames[WidgetClassName] = self ############################### def __methodcall_optkeys # { key=>method, ... } {'coords'=>'coords'} end private :__methodcall_optkeys ############################### def coords(val = nil) if val tk_split_list(tk_send_without_enc('coords')) else tk_send_without_enc('coords', val) self end end def constrain(val = None) num_or_str(tk_call(@path, 'constrain', val)) end def get(*args) num_or_str(tk_call(@path, 'get', *args)) end def identify(x, y) tk_call(@path, 'identify', x, y) end def get_label(val=nil) if val tk_call(@path, 'label', val) else ret = [] lst = simplelist(tk_call(@path, 'label')) while lst.size > 0 ret << ([num_or_str(lst.shift)] << lst.shift) end end end def set_label(val, str, *args) tk_call(@path, 'label', val, str, *args) self end def set_label_constrain(val, str, *args) tk_call(@path, 'label', '-constrain', val, str, *args) self end def get_tag(val=nil) if val tk_call(@path, 'tag', val) else ret = [] lst = simplelist(tk_call(@path, 'tag')) while lst.size > 0 ret << ([num_or_str(lst.shift)] << lst.shift) end end end def set_tag(val, str, *args) tk_call(@path, 'tag', val, str, *args) self end def set_tag_constrain(val, str, *args) tk_call(@path, 'tag', '-constrain', val, str, *args) self end def set(val = None) tk_call_without_enc(@path, 'set', val) self end end ================================================ FILE: ext/tk/lib/tkextlib/vu/pie.rb ================================================ # # ::vu::pie widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # create module/class module Tk module Vu module PieSliceConfigMethod end class Pie < TkWindow end class PieSlice < TkObject end class NamedPieSlice < PieSlice end end end # call setup script -- /tkextlib/vu.rb require 'tkextlib/vu.rb' module Tk::Vu::PieSliceConfigMethod include TkItemConfigMethod def __item_pathname(tagOrId) if tagOrId.kind_of?(Tk::Vu::PieSlice) self.path + ';' + tagOrId.id.to_s else self.path + ';' + tagOrId.to_s end end private :__item_pathname end class Tk::Vu::Pie < TkWindow TkCommandNames = ['::vu::pie'.freeze].freeze WidgetClassName = 'Pie'.freeze WidgetClassNames[WidgetClassName] = self def __destroy_hook__ Tk::Vu::PieSlice::SliceID_TBL.delete(@path) end ############################### include Tk::Vu::PieSliceConfigMethod def tagid(tag) if tag.kind_of?(Tk::Vu::PieSlice) tag.id else # tag _get_eval_string(tag) end end ############################### def delete(*glob_pats) tk_call(@path, 'delete', *glob_pats) self end def explode(slice, *args) tk_call(@path, 'explode', slice, *args) self end def explode_value(slice) num_or_str(tk_call(@path, 'explode', slice)) end def lower(slice, below=None) tk_call(@path, 'lower', slice, below) self end def names(*glob_pats) simplelist(tk_call(@path, 'names', *glob_pats)) end alias slices names def order(*args) tk_call(@path, 'order', *args) self end def raise(slice, above=None) tk_call(@path, 'raise', slice, above) self end def swap(slice1, slice2) tk_call(@path, 'swap', slice1, slice2) self end def set(slice, *args) num_or_str(tk_call(@path, 'set', slice, *args)) end alias set_value set alias set_values set alias create set def slice_value(slice) num_or_str(tk_call(@path, 'set', slice)) end def value(val = None) num_or_str(tk_call_without_enc(@path, 'value')) end alias sum_value value end class Tk::Vu::PieSlice SliceID_TBL = TkCore::INTERP.create_table (Pie_Slice_ID = ['vu:pie'.freeze, '00000'.taint]).instance_eval{ @mutex = Mutex.new def mutex; @mutex; end freeze } TkCore::INTERP.init_ip_env{ SliceID_TBL.mutex.synchronize{ SliceID_TBL.clear } } def self.id2obj(pie, id) pie_path = pie.path SliceID_TBL.mutex.synchronize{ if SliceID_TBL[pie_path] SliceID_TBL[pie_path][id]? SliceID_TBL[pie_path][id]: id else id end } end def initialize(parent, *args) unless parent.kind_of?(Tk::Vu::Pie) fail ArgumentError, "expect a Tk::Vu::Pie instance for 1st argument" end @parent = @pie = parent @ppath = parent.path Pie_Slice_ID.mutex.synchronize{ @path = @id = Pie_Slice_ID.join(TkCore::INTERP._ip_id_) Pie_Slice_ID[1].succ! } SliceID_TBL.mutex.synchronize{ SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath] SliceID_TBL[@ppath][@id] = self } if args[-1].kind_of?(Hash) keys = args.unshift end @pie.set(@id, *args) configure(keys) end def id @id end def [](key) cget key end def []=(key,val) configure key, val val end def cget(slot) @pie.itemcget(@id, slot) end def cget_strict(slot) @pie.itemcget_strict(@id, slot) end def configure(*args) @pie.itemconfigure(@id, *args) self end def configinfo(*args) @pie.itemconfiginfo(@id, *args) end def current_configinfo(*args) @pie.current_itemconfiginfo(@id, *args) end def delete @pie.delete(@id) end def explode(value) @pie.explode(@id, value) self end def explode_value @pie.explode_value(@id) end def lower(other=None) @pie.lower(@id, other) self end def raise(other=None) @pie.raise(@id, other) self end def set(value) @pie.set(@id, value) self end alias set_value set def value @pie.set(@id) end end class Tk::Vu::NamedPieSlice def self.new(parent, name, *args) obj = nil SliceID_TBL.mutex.synchronize{ if SliceID_TBL[parent.path] && SliceID_TBL[parent.path][name] obj = SliceID_TBL[parent.path][name] else #super(parent, name, *args) unless parent.kind_of?(Tk::Vu::Pie) fail ArgumentError, "expect a Tk::Vu::Pie instance for 1st argument" end obj = self.allocate obj.instance_eval{ @parent = @pie = parent @ppath = parent.path @path = @id = name.to_s SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath] SliceID_TBL[@ppath][@id] = self } end } obj.instance_eval{ if args[-1].kind_of?(Hash) keys = args.unshift end @pie.set(@id, *args) configure(keys) } obj end def initialize(parent, name, *args) # dummy:: not called by 'new' method unless parent.kind_of?(Tk::Vu::Pie) fail ArgumentError, "expect a Tk::Vu::Pie instance for 1st argument" end @parent = @pie = parent @ppath = parent.path @path = @id = name.to_s SliceID_TBL.mutex.synchronize{ SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath] SliceID_TBL[@ppath][@id] = self } if args[-1].kind_of?(Hash) keys = args.unshift end @pie.set(@id, *args) configure(keys) end end ================================================ FILE: ext/tk/lib/tkextlib/vu/setup.rb ================================================ # # setup.rb -- setup script before calling TkPackage.require() # # If you need some setup operations (for example, add a library path # to the library search path) before using Tcl/Tk library packages # wrapped by Ruby scripts in this directory, please write the setup # operations in this file. # ================================================ FILE: ext/tk/lib/tkextlib/vu/spinbox.rb ================================================ # # ::vu::spinbox widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # a standard spinbox (<= 8.3) # This is the same as the 8.4 core spinbox widget. # require 'tk' if (Tk::TK_MAJOR_VERSION < 8 || (Tk::TK_MAJOR_VERSION == 8 && Tk::TK_MINOR_VERSION < 4)) # call setup script -- /tkextlib/vu.rb require 'tkextlib/vu.rb' Tk.tk_call('namespace', 'import', '::vu::spinbox') end module Tk module Vu Spinbox = Tk::Spinbox end end ================================================ FILE: ext/tk/lib/tkextlib/vu.rb ================================================ # # The vu widget set support # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/vu/setup.rb' # load package # TkPackage.require('vu', '2.1') TkPackage.require('vu') # autoload module Tk module Vu TkComm::TkExtlibAutoloadModule.unshift(self) PACKAGE_NAME = 'vu'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('vu') rescue '' end end ########################################## autoload :Dial, 'tkextlib/vu/dial' autoload :Pie, 'tkextlib/vu/pie' autoload :PieSlice, 'tkextlib/vu/pie' autoload :NamedPieSlice, 'tkextlib/vu/pie' autoload :Spinbox, 'tkextlib/vu/spinbox' autoload :Bargraph, 'tkextlib/vu/bargraph' end end ================================================ FILE: ext/tk/lib/tkextlib/winico/setup.rb ================================================ # # setup.rb -- setup script before calling TkPackage.require() # # If you need some setup operations (for example, add a library path # to the library search path) before using Tcl/Tk library packages # wrapped by Ruby scripts in this directory, please write the setup # operations in this file. # ================================================ FILE: ext/tk/lib/tkextlib/winico/winico.rb ================================================ # # tkextlib/winico/winico.rb # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/winico/setup.rb' # TkPackage.require('winico', '0.5') # TkPackage.require('winico', '0.6') TkPackage.require('winico') module Tk class Winico < TkObject PACKAGE_NAME = 'winico'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin TkPackage.require('winico') rescue '' end end end end class Tk::Winico WinicoID_TBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ WinicoID_TBL.mutex.synchronize{ WinicoID_TBL.clear } } def self.id2obj(id) WinicoID_TBL.mutex.synchronize{ (WinicoID_TBL.key?(id))? WinicoID_TBL[id] : id } end def self.info simplelist(Tk.tk_call('winico', 'info')).collect{|id| Tk::Winico.id2obj(id) } end def self.icon_info(id) simplelist(Tk.tk_call('winico', 'info', id)).collect{|inf| h = Hash[*list(inf)] h.keys.each{|k| h[k[1..-1]] = h.delete(k)} } end ################################# def self.new_from_file(file_name) self.new(file_name) end def self.new_from_resource(resource_name, file_name = nil) self.new(file_name, resource_name) end def initialize(file_name, resource_name=nil, winico_id=nil) if resource_name # from resource if file_name @id = Tk.tk_call('winico', 'load', resource_name, file_name) else @id = Tk.tk_call('winico', 'load', resource_name) end elsif file_name # from .ico file @id = Tk.tk_call('winico', 'createfrom', file_name) elsif winico_id @id = winico_id else fail ArgumentError, "must be given proper information from where loading icons" end @path = @id WinicoID_TBL.mutex.synchronize{ WinicoID_TBL[@id] = self } end def id @id end def set_window(win_id, *opts) # opts := ?'big'|'small'?, ?pos? # NOTE:: the window, which is denoted by win_id, MUST BE MAPPED. # If not, then this may fail or crash. tk_call('winico', 'setwindow', win_id, @id, *opts) end def delete tk_call('winico', 'delete', @id) WinicoID_TBL.mutex.synchronize{ WinicoID_TBL.delete(@id) } self end alias destroy delete def info Tk::Winico.icon_info(@id) end ################################# class Winico_callback < TkValidateCommand class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [ ?m, ?s, :message ], [ ?i, ?x, :icon ], [ ?x, ?n, :x ], [ ?y, ?n, :y ], [ ?X, ?n, :last_x ], [ ?Y, ?n, :last_y ], [ ?t, ?n, :tickcount ], [ ?w, ?n, :icon_idnum ], [ ?l, ?n, :msg_idnum ], nil ] PROC_TBL = [ [ ?n, TkComm.method(:number) ], [ ?s, TkComm.method(:string) ], [ ?x, proc{|id| Tk::Winico::WinicoID_TBL.mutex.synchronize{ if Tk::Winico::WinicoID_TBL.key?(id) obj = Tk::Winico::WinicoID_TBL[id] else # Tk::Winico.new(nil, nil, id) obj = Tk::Winico.allocate obj.instance_eval{ @path = @id = id } Tk::Winico::WinicoID_TBL[id] = obj end obj } } ], nil ] =begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) end inf } PROC_TBL.map!{|inf| if inf.kind_of?(Array) inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) end inf } =end _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) val end end def self._config_keys ['callback'] end end ################################# def add_to_taskbar(keys = {}) keys = _symbolkey2str(keys) Winico_callback._config_keys.each{|k| if keys[k].kind_of?(Array) cmd, *args = keys[k] #keys[k] = Winico_callback.new(cmd, args.join(' ')) keys[k] = Winico_callback.new(cmd, *args) # elsif keys[k].kind_of?(Proc) elsif TkComm._callback_entry?(keys[k]) keys[k] = Winico_callback.new(keys[k]) end } tk_call('winico', 'taskbar', 'add', @id, *(hash_kv(keys))) self end alias taskbar_add add_to_taskbar def modify_taskbar(keys = {}) keys = _symbolkey2str(keys) Winico_callback._config_keys.each{|k| if keys[k].kind_of?(Array) cmd, *args = keys[k] #keys[k] = Winico_callback.new(cmd, args.join(' ')) keys[k] = Winico_callback.new(cmd, *args) # elsif keys[k].kind_of?(Proc) elsif TkComm._callback_entry?(keys[k]) keys[k] = Winico_callback.new(keys[k]) end } tk_call('winico', 'taskbar', 'modify', @id, *(hash_kv(keys))) self end alias taskbar_modify modify_taskbar def delete_from_taskbar tk_call('winico', 'taskbar', 'delete', @id) self end alias taskbar_delete delete_from_taskbar end ================================================ FILE: ext/tk/lib/tkextlib/winico.rb ================================================ # # winico -- Windows Icon extension support # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' # call setup script require 'tkextlib/tktable/setup.rb' # load library require 'tkextlib/winico/winico' ================================================ FILE: ext/tk/lib/tkfont.rb ================================================ # # tkfont.rb - load tk/font.rb # require 'tk/font' ================================================ FILE: ext/tk/lib/tkmacpkg.rb ================================================ # # tkmacpkg.rb - load tk/macpkg.rb # require 'tk/macpkg' ================================================ FILE: ext/tk/lib/tkmenubar.rb ================================================ # # tkmenubar.rb - load tk/menubar.rb # require 'tk/menubar' ================================================ FILE: ext/tk/lib/tkmngfocus.rb ================================================ # # tkmngfocus.rb - load tk/mngfocus.rb # require 'tk/mngfocus' ================================================ FILE: ext/tk/lib/tkpalette.rb ================================================ # # tkpalette.rb - load tk/palette.rb # require 'tk/palette' ================================================ FILE: ext/tk/lib/tkscrollbox.rb ================================================ # # tkscrollbox.rb - load tk/scrollbox.rb # require 'tk/scrollbox' ================================================ FILE: ext/tk/lib/tktext.rb ================================================ # # tktext.rb - load tk/text.rb # require 'tk/text' ================================================ FILE: ext/tk/lib/tkvirtevent.rb ================================================ # # tkvirtevent.rb - load tk/virtevent.rb # require 'tk/virtevent' ================================================ FILE: ext/tk/lib/tkwinpkg.rb ================================================ # # tkwinpkg.rb - load tk/winpkg.rb # require 'tk/winpkg' ================================================ FILE: ext/tk/old-README.tcltklib.eucj ================================================ (tof) 2003/06/19 Hidetoshi NAGAI ܥɥȤˤϸŤ tcltk 饤֥ꡤtcltklib 饤֥ ޤޤƤޤεƤϸŤΤȤʤäƤޤ ޤߤ Ruby/Tk 濴Ǥ tk.rb wish ƤӽФϤ tcltklib 饤֥ wrap ưΤȤʤäƤޤ ᡤŤҤǽҤ٤Ƥ褦ʥץ̿ˤ륪 إåɤ¸ߤޤ ߤ tcltklib 饤֥Ǥ⡤Tcl/Tk C 饤֥󥯤 ľܤưȤǡХإåɤ򲡤Ĥ Tcl/Tk 󥿡ץ꥿ Τۤǽʳĥ饤֥ޤˤȤƱǤ Ϥۤܡtk.rb ʲΥ饤֥ŪƯ뤿ΤΡ ȸʤƤꡤŪǥƥʥ󥹤Ƥޤ tk.rb ιⵡǽȼäơΥ饤֥Ǥ tcltk 饤֥ tcltk.rbˤϤ¸߰յ򸺤ƤꡤߤǤϥƥʥ󥹤ϹԤ Ƥޤ ʤŤǤϥХǥ󥰤ˤ륹ץȤɲäϤǤʤ ȤȤʤäƤޤߤ tk.rb ǤϤǽǤ뤳Ȥ­ ޤ ʲ饤֥θŤʸǤ ============================================================== tcltk 饤֥ tcltklib 饤֥ Sep. 19, 1997 Y. Shigehiro ʲ, tcl/tkפȤɽ, tclsh wish ¸Ƥ, ̤Ǥ Ȥ tcl/tk ؤޤ. tcltk 饤֥, tcltklib 饤֥ פȤɽ, ܥѥå˴ޤޤ ruby ѤΥ饤֥ؤޤ. [եˤĤ] README.euc : Υե(, ħ, 󥹥ȡˡ). MANUAL.euc : ޥ˥奢. lib/, ext/ : 饤֥μ. sample/ : ޥ˥奢Υץץ. sample/sample0.rb : tcltklib 饤֥Υƥ. sample/sample1.rb : tcltk 饤֥Υƥ. tcl/tk (wish) ǤǤʤȤ̤񤤤Ƥߤޤ. sample/sample2.rb : tcltk 饤֥Υץ. maeda shugo (shugo@po.aianet.ne.jp) ˤ (`rb.tk' ǽ񤫤Ƥ) ruby Υץץ http://www.aianet.or.jp/~shugo/ruby/othello.rb.gz tcltk 饤֥Ȥ褦, ŪѹƤߤޤ. demo/ : 100 ܤ 100 ǥץ. ǽ˶롼פλ֤¬ꤷ, ³Ƽºݤ֤¬ꤷޤ. tcl/tk ()ΤȤ backing store Ȥ鷺Χ 10000 (?) Τ, ()Ϥ, ޥ󤬤ʤŤʤޤ. demo/lines0.tcl : wish ѤΥץ. demo/lines1.rb : `tk.rb' ѤΥץ. demo/lines2.rb : tcltk 饤֥ѤΥץ. [] ѥ/¹Ԥˤ, tcl/tk C 饤֥꤬ɬפǤ. Υ饤֥, ruby-1.0-970701, ruby-1.0-970911, ruby-1.0-970919 FreeBSD 2.2.2-RELEASE ӤΥѥå jp-tcl-7.6.tgz, jp-tk-4.2.tgz Ǻ/ưǧޤ. ¾δĶǤư뤫ɤ狼ޤ. TclTkLib.mainloop ¹ Control-C ʤΤؤʤΤ, ruby Υ򻲹ͤ, #include "sig.h" trap_immediate Ƥ , ruby README.EXT ˤ񤤤ƤʤΤ, ʤȤ򤷤ɤΤ ɤ狼ޤ. -d ץǥǥХåɽ뤿, ruby Υ򻲹ͤ, debug Ȥѿ򻲾ȤƤޤ, ruby README.EXT ˤ񤤤 ʤΤ, ʤȤ򤷤ɤΤɤ狼ޤ. extconf.rb Ͻ񤭤ޤ, (ʰ̣)ɤΤɤʬ ޤ. [ħ] ruby tcl/tk 饤֥ѤǤޤ. tcl/tk 󥿥ץ꥿ΥץȤ, Ū tcltk 饤֥Ѥ ruby ץȤѴǤޤ. (`tk.rb' Ȥΰ㤤) 1. tcl/tk 󥿥ץ꥿ΥץȤ, ɤΤ褦, tcltk 饤֥Ѥ ruby ץȤѴ뤫Ǥ, ޥ˥奢ब̵ `tk.rb' Ȥϰۤʤ tcl/tk Υޥ˥奢䥪饤ɥȤѤ Ψɤץߥ󥰤ԤȤǤޤ. ˡ狼ʤ, ޥɤͿѥ᡼狼ʤ... - Canvas.new { ... } , ʤƥ졼֥å񤱤?? - Canvas bbox ϿͤΥꥹȤ֤Τ, xview ʸ֤?? , , 饤֥ΥɤɬפϤޤ. 2. ġεǽ(ץ)̽ˤꥵݡȤƤ, Τ᥵ ݡȤƤʤǽϻȤȤǤʤ(ϻȤʤȤʤ Ǥ) `tk.rb' Ȥϰۤʤ, tcl/tk 󥿥ץ꥿DzǽʤȤ ۤȤ ruby ¹ԤǤޤ. , ruby ¹ԤǤʤȤǧ ƤΤ, bind ޥɤǥץȤɲä빽ʸ bind tag sequence +script ^ ΤߤǤ. - `. configure -width' 򤷤褦Ȥ, `Tk.root.height()' Ƚ Τ, `undefined method `height'' ܤƤޤä. tk.rb ɤǤߤ, . ǤʤΤ... ȤȤϤޤ. 3. wish ץưץ̿ wish Ѥ `tk.rb' Ȥ ۤʤ, tcl/tk C 饤֥󥯤 ® (ȤäƤ, פä®ʤǤ) Ԥޤ. 4. `tk.rb' ۤ, ʥ󥿡եƤʤ, tcl/tk 󥿥ץ꥿ 鲿ޤǼʬǵ ʤФʤޤ(, tcl/tk 饤֥λ̤, tcl/tk 󥿥ץ꥿ʣ뤳ȤǤޤ). 󥿡ե(餯) ruby λۤ˱äΤǤϤޤ. ޤ, ץȤεҤ Ǥ. ץȤ, 츫, ɤߤŤ餤ΤȤʤޤ. , 񤯿ͤˤȤ Ƥ, ۤѤ路ΤǤϤʤȻפޤ. [󥹥ȡˡ] 0. ruby Υե(ruby-1.0-ʤ󤿤.tgz)ŸƤޤ. 1. ruby-1.0-ʤ󤿤/ext ext/tcltklib 򥳥ԡޤ. cp -r ext/tcltklib ???/ruby-1.0-ʤ󤿤/ext/ 2. ruby Υ󥹥ȡˡ˽ make 򤷤ޤ. 3. ruby Υ饤֥־ lib/* 򥳥ԡޤ. cp lib/* /usr/local/lib/ruby/ (eof) ================================================ FILE: ext/tk/sample/24hr_clock.rb ================================================ #!/usr/bin/env ruby require 'tk' class Clock def initialize(clock24 = true) @clock = (clock24)? 24: 12 @size = 200 @cdot_size = 5 @cdot_color = 'black' @hour_hand_color = 'black' @minute_hand_color = 'gray25' @second_hand_color = 'gray50' @mark_font = 'Helvetica -14' @mark_width = 3 @mark_color = 'black' @submark_color = 'gray50' @c = TkCanvas.new(:width=>2*@size, :height=>2*@size, :scrollregion=>[-@size, -@size, @size, @size] ).pack(:fill=>:both, :expand=>true) @tag = TkcTag.new(@c) @hand_tag = TkcTag.new(@c) @circle_coords = [[-0.9*@size, -0.9*@size], [0.9*@size, 0.9*@size]] @oval = TkcOval.new(@c, @circle_coords, :fill=>'white', :tags=>[@tag]) f = TkFrame.new.pack TkLabel.new(f, :text=>'CURRENT:').pack(:side=>:left) @now = TkLabel.new(f, :text=>'00:00:00').pack(:side=>:left, :padx=>2) TkLabel.new(f, :text=>' ').pack(:side=>:left) TkLabel.new(f, :text=>' ').pack(:side=>:right) @l = TkLabel.new(f, :text=>'00:00').pack(:side=>:right, :padx=>2) TkLabel.new(f, :text=>'MOUSE-POINTER:').pack(:side=>:right) cmd = proc{|x, y| @l.text = '%02d:%02d' % coords_to_time(@c.canvasx(x), @c.canvasy(y)) } @c.bind('Motion', cmd, '%x %y') @tag.bind('Motion', cmd, '%x %y') _create_hands _create_marks timer_proc = proc{ t = Time.now @now.text = '%02d:%02d:%02d' % [t.hour, t.min, t.sec] set_hands(t.hour, t.min, t.sec) } timer_proc.call @timer = TkRTTimer.start(100, -1, timer_proc) end def _create_marks @mark_tag = TkcTag.new(@c) TkcLine.new(@c, 0, -0.90*@size, 0, -0.85*@size, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@mark_color) TkcLine.new(@c, 0.90*@size, 0, 0.85*@size, 0, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@mark_color) TkcLine.new(@c, 0, 0.90*@size, 0, 0.85*@size, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@mark_color) TkcLine.new(@c, -0.90*@size, 0, -0.85*@size, 0, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@mark_color) TkcText.new(@c, [0, -0.92*@size], :text=>0, :anchor=>'s', :fill=>@mark_color) TkcText.new(@c, [0.92*@size, 0], :text=>@clock.div(4), :anchor=>'w', :fill=>@mark_color) TkcText.new(@c, [0, 0.92*@size], :text=>@clock.div(2), :anchor=>'n', :fill=>@mark_color) TkcText.new(@c, [-0.92*@size, 0], :text=>@clock.div(4)*3, :anchor=>'e', :fill=>@mark_color) [30.0, 60.0].each{|angle| rad = Math::PI * angle / 180.0 x_base = @size*Math::sin(rad) y_base = @size*Math::cos(rad) x1 = 0.90*x_base y1 = 0.90*y_base x2 = 0.85*x_base y2 = 0.85*y_base TkcLine.new(@c, x1, y1, x2, y2, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@mark_color) TkcLine.new(@c, x1, -y1, x2, -y2, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@mark_color) TkcLine.new(@c, -x1, y1, -x2, y2, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@mark_color) TkcLine.new(@c, -x1, -y1, -x2, -y2, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@mark_color) x3 = 0.92*x_base y3 = 0.92*y_base if @clock == 24 dh = angle.to_i/15 else # @clock == 12 dh = angle.to_i/30 end TkcText.new(@c, x3, -y3, :text=>dh, :anchor=>'sw', :fill=>@mark_color) TkcText.new(@c, x3, y3, :text=>@clock.div(2)-dh, :anchor=>'nw', :fill=>@mark_color) TkcText.new(@c, -x3, y3, :text=>@clock.div(2)+dh, :anchor=>'ne', :fill=>@mark_color) TkcText.new(@c, -x3, -y3, :text=>@clock-dh, :anchor=>'se', :fill=>@mark_color) } if @clock == 24 [15.0, 45.0, 75.0].each{|angle| rad = Math::PI * angle / 180.0 x_base = @size*Math::sin(rad) y_base = @size*Math::cos(rad) x1 = 0.90*x_base y1 = 0.90*y_base x2 = 0.875*x_base y2 = 0.875*y_base TkcLine.new(@c, x1, y1, x2, y2, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@submark_color) TkcLine.new(@c, x1, -y1, x2, -y2, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@submark_color) TkcLine.new(@c, -x1, y1, -x2, y2, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@submark_color) TkcLine.new(@c, -x1, -y1, -x2, -y2, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@submark_color) } end end def _create_hands hour_hand_len = 0.55*@size minute_hand_len = 0.85*@size second_hand_len = 0.88*@size hour_hand_width = 1.8*@cdot_size minute_hand_width = 1.0*@cdot_size second_hand_width = 1 # 0.4*@cdot_size @hour_hand_coords = [ [0, -0.5*@cdot_size], [hour_hand_width, -0.5*@cdot_size-hour_hand_width], [hour_hand_width, -hour_hand_len+hour_hand_width], [0, -hour_hand_len], [-hour_hand_width, -hour_hand_len+hour_hand_width], [-hour_hand_width, -0.5*@cdot_size-hour_hand_width], ] @minute_hand_coords = [ [0, -0.5*@cdot_size], [minute_hand_width, -0.5*@cdot_size - minute_hand_width], [minute_hand_width, -minute_hand_len+minute_hand_width], [0, -minute_hand_len], [-minute_hand_width, -minute_hand_len+minute_hand_width], [-minute_hand_width, -0.5*@cdot_size-minute_hand_width], ] @second_hand_coords = [ [0, -0.5*@cdot_size], [second_hand_width, -0.5*@cdot_size - second_hand_width], [second_hand_width, -second_hand_len+second_hand_width], [0, -second_hand_len], [-second_hand_width, -second_hand_len+second_hand_width], [-second_hand_width, -0.5*@cdot_size-second_hand_width], ] @hour_hand = TkcPolygon.new(@c, @hour_hand_coords, :tags=>[@tag, @hand_tag], :outline=>@hour_hand_color, :fill=>@hour_hand_color) @minute_hand = TkcPolygon.new(@c, @minute_hand_coords, :tags=>[@tag, @hand_tag], :outline=>@minute_hand_color, :fill=>@minute_hand_color) @second_hand = TkcPolygon.new(@c, @second_hand_coords, :tags=>[@tag, @hand_tag], :outline=>@second_hand_color, :fill=>@second_hand_color) @center_dot = TkcOval.new(@c, [-@cdot_size, -@cdot_size], [@cdot_size, @cdot_size], :outline=>@cdot_color, :fill=>@cdot_color) end private :_create_hands def _raise_hands @hour_hand.raise @minute_hand.raise @second_hand.raise @center_dot.raise end private :_raise_hands def _raise_marks @mark_tag.raise end private :_raise_marks def set_hands(hh, mm, ss) ss_angle = Math::PI * ss / 30.0 mm_angle = Math::PI * (mm + ss/60.0) / 30.0 hh_angle = Math::PI * (hh + (mm + ss/60.0)/60.0) / (@clock.div(2)) @second_hand.coords = @second_hand_coords.collect{|x, y| r = Math::hypot(y, x) a = Math::atan2(y, x) + ss_angle [Math::cos(a) * r, Math::sin(a) * r] } @minute_hand.coords = @minute_hand_coords.collect{|x, y| r = Math::hypot(y, x) a = Math::atan2(y, x) + mm_angle [Math::cos(a) * r, Math::sin(a) * r] } @hour_hand.coords = @hour_hand_coords.collect{|x, y| r = Math::hypot(y, x) a = Math::atan2(y, x) + hh_angle [Math::cos(a) * r, Math::sin(a) * r] } _raise_hands _raise_marks end def coords_to_time(x, y) return ((y < 0)? [0, 0]: [@clock.div(2), 0]) if x == 0 if @clock == 24 offset = (x<0&&y<0)? 1800.0: 360.0 m_half = 720.0 else # @clock == 12 offset = (x<0&&y<0)? 900.0: 180.0 m_half = 360.0 end (offset + m_half*Math.atan2(y,x)/Math::PI).round.divmod(60) end def create_pie(hh, mm, span, color='red') if @clock == 24 start = 90.0 - (hh*60 + mm)/4.0 # 360.0*(hh*60+mm)/(24*60) extent = -span/4.0 else # @clock == 12 start = 90.0 - (hh*60 + mm)/2.0 # 360.0*(hh*60+mm)/(12*60) extent = -span/2.0 end pie = TkcArc.new(@c, @circle_coords, :tags=>[@tag], :outline=>'black', 'fill'=>color, :start=>start, :extent=>extent) _raise_hands _raise_marks pie end end sched = Clock.new sched.create_pie(0,0, 60) # 60 minutes from 00:00 sched.create_pie(6,30, 280, 'green') # 280 minutes from 06:30 sched.create_pie(15,20, 90, 'blue') # 90 minutes from 15:20 Tk.mainloop ================================================ FILE: ext/tk/sample/binding_sample.rb ================================================ #!/usr/bin/env ruby require 'tk' class Button_clone < TkLabel def initialize(*args) @command = nil if args[-1].kind_of?(Hash) keys = _symbolkey2str(args.pop) @command = keys.delete('command') keys['highlightthickness'] = 1 unless keys.key?('highlightthickness') keys['padx'] = '3m' unless keys.key?('padx') keys['pady'] = '1m' unless keys.key?('pady') keys['relief'] = 'raised' unless keys.key?('relief') args.push(keys) end super(*args) @press = false self.bind('Enter', proc{self.background(self.activebackground)}) self.bind('Leave', proc{ @press = false self.background(self.highlightbackground) self.relief('raised') }) self.bind('ButtonPress-1', proc{@press = true; self.relief('sunken')}) self.bind('ButtonRelease-1', proc{ self.relief('raised') @command.call if @press && @command @press = false }) end def command(cmd = Proc.new) @command = cmd end def invoke if @command @command.call else '' end end end TkLabel.new(:text=><'red').pack(:pady=>3) v = TkVariable.new(0) TkFrame.new{|f| TkLabel.new(f, :text=>'click count : ').pack(:side=>:left) TkLabel.new(f, :textvariable=>v).pack(:side=>:left) }.pack TkButton.new(:text=>'normal Button widget', :command=>proc{ puts 'button is clicked!!' lbl.text 'button is clicked!!' v.numeric += 1 }){ pack(:fill=>:x, :expand=>true) } Button_clone.new(:text=>'Label with Button binding', :command=>proc{ puts 'label is clicked!!' lbl.text 'label is clicked!!' v.numeric += 1 }){ pack(:fill=>:x, :expand=>true) } Tk.mainloop ================================================ FILE: ext/tk/sample/bindtag_sample.rb ================================================ #!/usr/bin/env ruby require 'tk' TkLabel.new(:text=><:left).pack This is a sample of bindtags and usage of Tk.callback_break/Tk.callback_continue. Please check the work of following buttons (attend the difference between before/after pressing the bottom button), and see the source code. EOT def set_class_bind TkButton.bind('ButtonPress-1', proc{puts 'bind "ButtonPress-1" of TkButton class'}) TkButton.bind('ButtonRelease-1', proc{puts 'bind "ButtonRelease-1" of TkButton class'}) end # set root binding r = TkRoot.new r.bind('ButtonPress-1', proc{puts 'bind "ButtonPress-1" of root widget'}) r.bind('ButtonRelease-1', proc{puts 'bind "ButtonRelease-1" of root widget'}) # set 'all' binding TkBindTag::ALL.bind('ButtonPress-1', proc{puts 'bind "ButtonPress-1" of the tag "all"'}) TkBindTag::ALL.bind('ButtonRelease-1', proc{puts 'bind "ButtonRelease-1" of the tag "all"'}) # create buttons b1 = TkButton.new(:text=>'button-1', :command=>proc{puts "command of button-1"}).pack b2 = TkButton.new(:text=>'button-2', :command=>proc{puts "command of button-2"}).pack b3 = TkButton.new(:text=>'button-3', :command=>proc{puts "command of button-3"}).pack b4 = TkButton.new(:text=>'button-4', :command=>proc{puts "command of button-4"}).pack b5 = TkButton.new(:text=>'button-5', :command=>proc{puts "command of button-5"}).pack # set button binding b1.bind('ButtonPress-1', proc{puts 'bind "ButtonPress-1" of button-1'}) b1.bind('ButtonRelease-1', proc{puts 'bind "ButtonRelease-1" of button-1'}) b2.bind('ButtonPress-1', proc{puts 'bind "ButtonPress-1" of button-2'}) b2.bind('ButtonRelease-1', proc{puts 'bind "ButtonRelease-1" of button-2'}) b3.bind('ButtonPress-1', proc{puts 'bind "ButtonPress-1" of button-3'}) b3.bind('ButtonRelease-1', proc{puts 'bind "ButtonRelease-1" of button-3'}) b4.bind('ButtonPress-1', proc{puts 'bind "ButtonPress-1" of button-4'}) b4.bind('ButtonRelease-1', proc{puts 'bind "ButtonRelease-1" of button-4'}) b5.bind('ButtonPress-1', proc{puts 'bind "ButtonPress-1" of button-5'}) b5.bind('ButtonRelease-1', proc{puts 'bind "ButtonRelease-1" of button-5'}) # create bindtag and set binding tag1 = TkBindTag.new tag1.bind('ButtonPress-1', proc{puts 'bind "ButtonPress-1" of tag1'}) tag1.bind('ButtonRelease-1', proc{puts 'bind "ButtonRelease-1" of tag1'}) tag2 = TkBindTag.new tag2.bind('ButtonPress-1', proc{ puts 'bind "ButtonPress-1" of tag2' puts 'call Tk.callback_continue' Tk.callback_continue puts 'never see this message' }) tag2.bind('ButtonRelease-1', proc{ puts 'bind "ButtonRelease-1" of tag2' puts 'call Tk.callback_continue' Tk.callback_continue puts 'never see this message' }) tag3 = TkBindTag.new tag3.bind('ButtonPress-1', proc{ puts 'bind "ButtonPress-1" of tag3' puts 'call Tk.callback_break' Tk.callback_break puts 'never see this message' }) tag3.bind('ButtonRelease-1', proc{ puts 'bind "ButtonRelease-1" of tag3' puts 'call Tk.callback_break' Tk.callback_break puts 'never see this message' }) # set bindtags p b1.bindtags tags = b2.bindtags tags[2,0] = tag1 tags[0,0] = tag1 b2.bindtags(tags) p b2.bindtags tags = b3.bindtags tags[2,0] = tag2 tags[0,0] = tag2 b3.bindtags(tags) p b3.bindtags tags = b4.bindtags tags[2,0] = tag3 tags[0,0] = tag3 b4.bindtags(tags) p b4.bindtags b5.bindtags([tag1, TkButton, tag2, b5]) # create button to set button class binding TkButton.new(:text=>'set binding to TkButton class', :command=>proc{ puts 'call "set_class_bind"' set_class_bind }).pack(:pady=>7) # start event-loop Tk.mainloop ================================================ FILE: ext/tk/sample/binstr_usage.rb ================================================ #!/usr/bin/env ruby require "tk" TkMessage.new(:width=>360, :text=><ImgFile) p ph1.configinfo b_str = Tk::BinaryString(IO.read(ImgFile)) p [b_str, b_str.encoding] ph2 = TkPhotoImage.new(:data=>b_str) p ph2.configinfo p ph2.data(:grayscale=>true) ph3 = TkPhotoImage.new(:palette=>256) ph3.put(ph2.data) ph4 = TkPhotoImage.new() ph4.put(ph2.data(:grayscale=>true)) #p [b_str.encoding, b_str.rb_encoding] f = TkFrame.new.pack TkButton.new(:parent=>f, :image=>ph1, :command=>proc{exit}).pack(:side=>:left) TkButton.new(:parent=>f, :image=>ph2, :command=>proc{exit}).pack(:side=>:left) TkButton.new(:parent=>f, :image=>ph3, :command=>proc{exit}).pack(:side=>:left) TkButton.new(:parent=>f, :image=>ph4, :command=>proc{exit}).pack(:side=>:left) Tk.mainloop ================================================ FILE: ext/tk/sample/btn_with_frame.rb ================================================ require 'tk' class Button_with_Frame < TkButton def create_self(keys) @frame = TkFrame.new('widgetname'=>@path, 'background'=>'yellow') install_win(@path) # create new @path which is a daughter of old @path super(keys) TkPack(@path, :padx=>7, :pady=>7) @epath = @frame.path end def epath @epath end end Button_with_Frame.new(:text=>'QUIT', :command=>proc{exit}) { pack(:padx=>15, :pady=>5) } Tk.mainloop ================================================ FILE: ext/tk/sample/cd_timer.rb ================================================ #!/usr/bin/env ruby # # countdown timer # usage: cd_timer min [, min ... ] # ( e.g. cd_timer 0.5 1 3 5 10 ) # require 'tk' if ARGV.empty? $stderr.puts 'Error:: No time arguments for counting down' exit(1) end width = 10 TkButton.new(:text=>'exit', :command=>proc{exit}).pack(:side=>:bottom, :fill=>:x) b = TkButton.new(:text=>'start').pack(:side=>:top, :fill=>:x) f = TkFrame.new(:relief=>:ridge, :borderwidth=>2).pack(:fill=>:x) TkLabel.new(f, :relief=>:flat, :pady=>3, :background=>'black', :foreground=>'white', :text=>' elapsed: ').pack(:fill=>:x, :side=>:left, :expand=>true) now = TkLabel.new(f, :width=>width, :relief=>:flat, :pady=>3, :anchor=>:w, :background=>'black', :foreground=>'white', :text=>'%4d:%02d.00' % [0, 0]).pack(:side=>:right) timers = [ TkRTTimer.new(10){|tm| t = (tm.return_value || 0) + 1 s, u = t.divmod(100) m, s = s.divmod(60) now.text('%4d:%02d.%02d' % [m, s, u]) t }.set_start_proc(0, proc{ now.text('%4d:%02d.00' % [0,0]) now.foreground('white') 0 }) ] ARGV.collect{|arg| (Float(arg) * 60).to_i}.sort.each_with_index{|time, idx| f = TkFrame.new(:relief=>:ridge, :borderwidth=>2).pack(:fill=>:x) TkLabel.new(f, :relief=>:flat, :pady=>3, :text=>' %4d:%02d --> ' % (time.divmod(60))).pack(:side=>:left) l = TkLabel.new(f, :width=>width, :relief=>:flat, :pady=>3, :anchor=>:w, :text=>'%4d:%02d' % (time.divmod(60))).pack(:side=>:right) timers << TkRTTimer.new(1000){|tm| t = (tm.return_value || time) - 1 if t < 0 l.text('%4d:%02d' % ((-t).divmod(60))) else l.text('%4d:%02d' % (t.divmod(60))) end if t.zero? l.foreground('red') idx.times{Tk.bell} end t }.set_start_proc(0, proc{ l.text('%4d:%02d' % (time.divmod(60))) l.foreground('black') time }) } mode = :start b.command(proc{ if mode == :start timers.each{|timer| timer.restart} b.text('reset') mode = :reset else timers.each{|timer| timer.stop.reset} b.text('start') mode = :start end }) Tk.mainloop ================================================ FILE: ext/tk/sample/cmd_res_test.rb ================================================ require 'tk' TkOptionDB.readfile(File.expand_path('cmd_resource', File.dirname(__FILE__))) f = TkFrame.new(:class=>'BtnFrame').pack b = TkButton.new(:parent=>f, :widgetname=>'hello').pack cmd1 = TkOptionDB.new_proc_class(b, [:show_msg, :bye_msg], 3) cmd2 = TkOptionDB.new_proc_class(:ZZZ, [:show_msg, :bye_msg], 3, false, cmd1) cmd3 = TkOptionDB.new_proc_class(:ZZZ, [:show_msg, :bye_msg], 3, false, b) cmd4 = TkOptionDB.new_proc_class(:BTN_CMD, [:show_msg, :bye_msg], 3){ def self.__check_proc_string__(str) "{|arg| print [arg, $SAFE].inspect, ': '; Proc.new#{str}.call(arg)}" end } cmd1.show_msg('cmd1') cmd2.show_msg('cmd2') cmd3.show_msg('cmd3') cmd4.show_msg('cmd4') ================================================ FILE: ext/tk/sample/cmd_resource ================================================ *BtnFrame.hello.text: HELLO *BtnFrame.hello.command: ruby {puts "Hello World!!"} *BTN_CMD.show_msg: {|arg| print "Hello, #{arg}!!\n"} *hello.show_msg: {|arg| print "Hello, Hello, #{arg}!!\n"} *hello.ZZZ.show_msg: {|arg| print "Hello, Hello, ZZZ:#{arg}!!\n"} ================================================ FILE: ext/tk/sample/demos-en/ChangeLog ================================================ 2002-08-29 16:30 matt * ChangeLog: ChangeLog is auto-generated *from* CVS log. 2002-08-29 16:27 matt * ChangeLog.prev: [no log message] 2002-08-28 18:07 matt * browse1, browse2, hello, ixset, rmt, rolodex, rolodex-j, square, tcolor, timer, widget: Changed #! lines to the slightly more portable '#!/usr/bin/env ruby'. 2002-08-28 17:56 matt * icon.rb, items.rb, label.rb, menu.rb, ruler.rb: Changed bitmap file extensions from .bmp to .xbm. 2002-08-28 17:55 matt * images/: face.bmp, face.xbm, flagdown.bmp, flagdown.xbm, flagup.bmp, flagup.xbm, gray25.bmp, gray25.xbm, letters.bmp, letters.xbm, noletter.bmp, noletter.xbm, pattern.bmp, pattern.xbm: Changed X bitmap file extensions from .bmp to the more intuitive .xbm. 2002-08-28 17:35 matt * bitmap.rb, colors.rb, cscroll.rb, ctext.rb, hello, ixset, menubu.rb, patch_1.1c1, rmt, style.rb, timer, ChangeLog, README, README.tkencoding, arrow.rb, bind.rb, browse1, browse2, button.rb, check.rb, clrpick.rb, dialog1.rb, dialog2.rb, entry1.rb, entry2.rb, filebox.rb, floor.rb, form.rb, hscale.rb, icon.rb, image1.rb, image2.rb, items.rb, label.rb, menu.rb, msgbox.rb, plot.rb, puzzle.rb, radio.rb, rolodex, rolodex-j, ruler.rb, sayings.rb, search.rb, square, states.rb, tcolor, text.rb, tkencoding.rb, twind.rb, vscale.rb, widget, doc.org/README, doc.org/README.JP, doc.org/README.tk80, doc.org/license.terms, doc.org/license.terms.tk80, images/earth.gif, images/earthris.gif, images/face.bmp, images/flagdown.bmp, images/flagup.bmp, images/gray25.bmp, images/grey.25, images/grey.5, images/letters.bmp, images/noletter.bmp, images/pattern.bmp, images/tcllogo.gif, images/teapot.ppm: Initial revision 2002-08-28 17:35 matt * bitmap.rb, colors.rb, cscroll.rb, ctext.rb, hello, ixset, menubu.rb, patch_1.1c1, rmt, style.rb, timer, ChangeLog, README, README.tkencoding, arrow.rb, bind.rb, browse1, browse2, button.rb, check.rb, clrpick.rb, dialog1.rb, dialog2.rb, entry1.rb, entry2.rb, filebox.rb, floor.rb, form.rb, hscale.rb, icon.rb, image1.rb, image2.rb, items.rb, label.rb, menu.rb, msgbox.rb, plot.rb, puzzle.rb, radio.rb, rolodex, rolodex-j, ruler.rb, sayings.rb, search.rb, square, states.rb, tcolor, text.rb, tkencoding.rb, twind.rb, vscale.rb, widget, doc.org/README, doc.org/README.JP, doc.org/README.tk80, doc.org/license.terms, doc.org/license.terms.tk80, images/earth.gif, images/earthris.gif, images/face.bmp, images/flagdown.bmp, images/flagup.bmp, images/gray25.bmp, images/grey.25, images/grey.5, images/letters.bmp, images/noletter.bmp, images/pattern.bmp, images/tcllogo.gif, images/teapot.ppm: Taking over demo package from Jonathan Conway. ================================================ FILE: ext/tk/sample/demos-en/ChangeLog.prev ================================================ 2001-07-26 * Moved files to directory ruby-tk81-demos-english in tarball. 2001-07-26 * Added test to widget and hello versus Tk::TCL_VERSION & Tk::JAPANIZED_TK (per Guy Decoux in [ruby-talk:18559]) before requiring tkencoding.rb. ================================================ FILE: ext/tk/sample/demos-en/README ================================================ Current Maintainer: Jonathan Conway rise@knavery.net Please direct all bug reports/requests/suggestions to the above address. Notes: * The files hello and widget have been changed to test Tk::TCL_VERSION and Tk::JAPANIZED_TK before requiring tkencoding.rb to prevent an infinite loop. This test was taken from a message in [ruby-talk:18559] by Guy Decoux. * The .bmp files in the images directory are X bitmaps (i.e. XBM to many graphics packages), not Windows bitmaps (.bmp). You will not be able to use images exported by a graphics program as Windows bitmaps with this demo collection nor will you be able to edit the included images without setting the file type correctly. -- Jonathan Conway, 2001-07-26 #------------------------------------------------------------------------------ # ==== Introduction. ==== # # To create this version of the Ruby/Tk widget demo, I took the # ruby-tk81-demos and removed all the Kanji strings and comments. I # have tried to restore the original English strings and comments # using the Tcl/Tk8.2.2 version of the widget demo. # # When I tried running the Kanji version, all I got was a mostly blank # panel with a non-functional "File" button. I disovered that if all # non-ASCII characters were replaced with blanks, then I could get the # gutted stuff running. # # Since English Ruby/Tk documentation is lacking and I needed this # code to see how it worked and to use as the basis of my try-it # prototype (The Ruby Yielding Interactive Toolkit), plus the fact # that no help was forthcoming for making the Kanji version work (plus # the fact that I can't read Kanji anyway), I decided to embark on # this English restoration project. # # Thanks to everyone who worked on the original Ruby/Tk widget demo # (and the preceding Tcl/Tk version for that matter). The # comparatively simple task of changing text strings and comments has # made me appreciate the great amount of original work that went into # this. # # -- Conrad Schneiker, 2000-07-23. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ # ==== Known bugs. ==== # # ^C-ing the demo gives Ruby interrupt and stack message; clean exit needed. # Font settings don't work correctly. # Dismissing the embedded windows demo (tkwind.rb) kills the widget demo. # Rerunning the canvas item demo from the code widow get errors. # The "press me" button in the canvas item demo doesn't time out. # The simple 2 d plot starts up extremely slow compared to the Tcl version. # The first item message on the icon menu on the menu and cascades demo doesn't work. #------------------------------------------------------------------------------ ###################### Original README ######################################## Ruby/Tk81 widget-demo 1999/08/13 Φüʳظ Ω Tcl/Tk8.1Ǥunicode(UTF8)Ѥ졢unicodeѴ줿ܸǤ Widgetɽ뤳ȤǽǤܥ֤ˤϰ˱ʰ椵濴 ʤƺ줿Ruby/TkΥץ˽äʲδĶˤƤư ǧΤǤ * ruby-1.3.7,ruby-1.4.0 * tcl8.1, tk8.1 * linux-2.2 Windows(Cygwin)ˤơץưˤruby-KeȤץ ƵưɤǤ 󶡡դ ---------------------------------------------------------------------------- Ruby/Tk widget-demo version 1.1 ( 1998/07/24 ) ʰǽ幩 (nagai@ai.kyutech.ac.jp) ɸۤ Tcl/Tk ĥѥå Ruby (ʲ Ruby/Tk ȸƤӤޤ) ǤϡTk widget Ѥ GUI κԤȤǤޤºݤ GUI Ƥˤ͡ʼ㤬ץȤ¸ߤʤΤǤRuby/Tk ˤϤΤ褦Ŭʥץ륹ץȽ¸ߤޤǤФ ĥѥåθǤ Tcl/Tk ˤϡTk widget ѤƤɤΤ褦ʤȤ 뤫򼨤ΤȤ widget-demo ¸ߤꡤTcl/Tk Ѥ GUI κ ݤɽŪץȤʤäƤޤܥ֤ϡRuby/Tk ν ɽŪʥץ륹ץȤȤ٤Tcl/Tk widget-demo ܿ ΤǤ ܥ֤˴ޤޤ륹ץȤ¹Ԥ뤿ˤϡruby-1.1c2 ʾǤ뤳 ȤɬפǤ1.1c1 ξϡܥ֤˴ޤޤ patck_1.1c1 Ruby 饤֥ˤƤƤȤ߹ Tk ΥСϡ4.2 Ǥ 8.0 Ǥ⽤ ʤưϤǤܸǤǤΰܿȤʤäƤ뤿ᡤܸ첽 줿 Tk ѤץȤΥƥȤϡTk4.2jp Tk8.0jp ξǹ ޤ (ˤǤϤʤǤ) ܥ֤˴ޤޤ륹ץȤ¿ϡȤʤäƤ Tcl/Tk ǤŪ ץȵҤȤʤ褦ˤƤޤΤᡤRuby/Tk Υץȸ ϡޤ Ruby 餷ʤȤǤ礦ˤ⤫餺Τ褦ʵ äƤͳϡRuby/Tk Υɥ­ˤޤ Tcl/Tk ˤŬʻͽ񤬲¸ߤƤޤ顤Ruby/Tk ץȤ ݤϡΤ褦 Tcl/Tk λͽǾ䤤ʤ뤳ȤˤʤȻ ޤ widget λȤơTcl/Tk widget-demo 򻲾Ȥ뤳Ȥ⤢ Ǥ礦Ruby/Tk ǤεҤ widget-demo Tcl/Tk ǤεҤ˶ᤤΤˤ СˤäơRuby/Tk 뤳ȤǤȹͤޤ ö Ruby/Tk Ǥ widget λˡƤޤСRuby 餷 ץȤ뤳Ȥ񤷤ʤǤ礦ܥ֤ΥץȤϡRuby/Tk ǽ˽ޤǤƧȤѤƤйǤ widget-demo ΰܿˤäƤϡˤܿץȤ󶡤Ƥ ޤ˴դΰդɽޤ ΩСJAIST (ttate@jaist.ac.jp) ʿͻ (hiramatu@cdrom.co.jp) ʿˤ Ruby/Tk Web page (http://www.cdrom.co.jp/~hiramatu/) Ruby/Tk νͭѤȻפޤΤǡҤȤ ޤ (maebashi@iij.ad.jp) ϤȤơwidget-demo ΰܿ˺ݤ ɬפȤʤä Ruby Tk Ϣ饤֥꽤ˤĤơХλŦ Ƥˤⴶפޤ ƺǸ˺δդ Ruby ߷׼Ԥ ޤĤ 椭Ҥ (matz@netlab.co.jp) Ȼפޤ ================================================ FILE: ext/tk/sample/demos-en/README.1st ================================================ There are Ruby/Tk demo scripts. Files with '.rb' extension are sub-scripts which are launched 'widget' script. Those files don't work independently. Please call them from 'widget' script. If you want start some sub-scripts at same time when the launcher script tarts, please give the sub-script names as arguments. (e.g. /usr/local/bin/ruby widget button.rb entry1.rb text.rb ) You can ommit '.rb' of the sub-scripts (e.g. /usr/local/bin/ruby widget button entry1 text ) If you don't need launcher's main window, give -n option. (e.g. /usr/local/bin/ruby widget -n button.rb entry1.rb text.rb ) Others (browse1, hello, and so on) are standalone scripts. 2004/04/14 Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) ================================================ FILE: ext/tk/sample/demos-en/README.tkencoding ================================================ This is a original document of 'tkencoding.rb'. The library 'tkencoding.rb' is obsolete. Functions of tkencoding.rb is already included into Ruby/Tk. ------------------------------------------------- tkencoding.rbѤܸɽˤĤ Copyright (C) 1999/07, Takaaki Tateishi 1. tkencoding.rbȤϡ tkencoding.rbTcl/Tk8.1ѤRuby/TkΤΥ饤֥ Ǥtkencoding.rbrequire뤳ȤˤäWedgetɽ ƥȤunicode(UTF8)Ѵޤ 2. Ȥ tkencoding.rbrequireTk.encodingǻѤƤʸ ꤷƲ㤨аʲΤ褦ʴˤʤޤ ---- require 'tk' require 'tkencoding' Tk.encoding = "euc-jp" # Tk.encoding = "shiftjis" --- ================================================ FILE: ext/tk/sample/demos-en/anilabel.rb ================================================ # # animated label widget demo (called by 'widget') # # based on Tcl/Tk8.5a2 widget demos if defined?($anilabel_demo) && $anilabel_demo $anilabel_demo.destroy $anilabel_demo = nil end # demo toplevel widget $anilabel_demo = TkToplevel.new {|w| title("Animated Label Demonstration") iconname("anilabel") positionWindow(w) } base_frame = TkFrame.new($anilabel_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "Four animated labels are displayed below; each of the labels on the left is animated by making the text message inside it appear to scroll, and the label on the right is animated by animating the image that it displays." } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $anilabel_demo $anilabel_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'See Code' command proc{showCode 'anilabel'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # create frame for label demo f_left = TkLabelFrame.new(base_frame, :text=>'Scrolling Texts') f_right = TkLabelFrame.new(base_frame, :text=>'GIF Image') Tk.pack(f_left, f_right, 'side'=>'left', 'expand'=>'yes', 'fill'=>'both', 'padx'=>10, 'pady'=>10) # animated label class AnimatedTextLabel < TkLabel def initialize(*args) super(*args) @timer = TkTimer.new{ _animation_callback } @timer.loop_exec = -1 # bind('Destroy'){ @timer.stop } @btag = TkBindTag.new('Destroy'){ @timer.stop } self.bindtags_unshift(@btag) end def _animation_callback() txt = self.text self.text = (txt[1..-1] << txt[0]) end private :_animation_callback def start(interval) @timer.set_interval(interval) @timer.start end def stop @timer.stop end end # animated image class AnimatedImageLabel < AnimatedTextLabel def initialize(*args) super(*args) @destroy_image = false @btag.bind_append('Destroy'){ if @destroy_image begin self.image.delete rescue end end } end attr_accessor :destroy_image def _animation_callback() img = self.image fmt = img.format if fmt.kind_of?(Array) if fmt[1].kind_of?(Hash) # fmt == ['GIF', {'index'=>idx}] idx = fmt[1]['index'] else # fmt == ['GIF', '-index', idx] :: Ruby1.8.2 returns this. idx = fmt[2] end elsif fmt.kind_of?(String) && fmt =~ /GIF -index (\d+)/ idx = $1.to_i else idx = -1 end begin img.format("GIF -index #{idx + 1}") rescue => e img.format("GIF -index 0") end end private :_animation_callback end # create labels l1 = AnimatedTextLabel.new(f_left, :borderwidth=>4, :relief=>:ridge, :font=>{:family=>'Courier', :size=>10}) l2 = AnimatedTextLabel.new(f_left, :borderwidth=>4, :relief=>:groove, :font=>{:family=>'Courier', :size=>10}) l3 = AnimatedTextLabel.new(f_left, :borderwidth=>4, :relief=>:flat, :font=>{:family=>'Courier', :size=>10}, :width=>18) Tk.pack(l1, l2, l3, :side=>:top, :expand=>true, :anchor=>:w, :padx=>10, :pady=>10) limg = AnimatedImageLabel.new(f_right, :borderwidth=>0) limg.pack(:side=>:top, :expand=>true, :padx=>10, :pady=>10) # base64-encoded animated GIF file tclPowerdData = <'GIF', :data=>tclPowerdData)).start(100) ================================================ FILE: ext/tk/sample/demos-en/aniwave.rb ================================================ # # animated wave demo (called by 'widget') # # based on Tcl/Tk8.5a2 widget demos # destroy toplevel widget for this demo script if defined?($aniwave_demo) && $aniwave_demo $aniwave_demo.destroy $aniwave_demo = nil end # create toplevel widget $aniwave_demo = TkToplevel.new {|w| title("Animated Wave Demonstration") iconname("aniwave") positionWindow(w) } base_frame = TkFrame.new($aniwave_demo).pack(:fill=>:both, :expand=>true) # create label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text 'This demonstration contains a canvas widget with a line item inside it. The animation routines work by adjusting the coordinates list of the line.' } msg.pack('side'=>'top') # create frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $aniwave_demo $aniwave_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'See Code' command proc{showCode 'aniwave'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # animated wave class AnimatedWaveDemo def initialize(frame, dir=:left) @direction = dir # create canvas widget @c = TkCanvas.new(frame, :width=>300, :height=>200, :background=>'black') @c.pack(:padx=>10, :pady=>10, :expand=>true) # Creates a coordinates list of a wave. @waveCoords = [] @backupCoords = [] n = 0 (-10..300).step(5){|n| @waveCoords << [n, 100]; @backupCoords << [n, 100] } n = 305 @waveCoords << [n, 0]; @backupCoords << [n, 0] @waveCoords << [n+5, 200]; @backupCoords << [n+5, 200] @coordsLen = @waveCoords.length # Create a smoothed line and arrange for its coordinates to be the # contents of the variable waveCoords. @line = TkcLine.new(@c, @waveCoords, :width=>1, :fill=>'green', :smooth=>true) # Main animation "loop". # Theoretically 100 frames-per-second (==10ms between frames) @timer = TkTimer.new(10){ basicMotion; reverser } # Arrange for the animation loop to stop when the canvas is deleted @c.bindtags_unshift(TkBindTag.new('Destroy'){ @timer.stop }) end # Basic motion handler. Given what direction the wave is travelling # in, it advances the y coordinates in the coordinate-list one step in # that direction. def basicMotion @backupCoords, @waveCoords = @waveCoords, @backupCoords (0...@coordsLen).each{|idx| if @direction == :left @waveCoords[idx][1] = @backupCoords[(idx+1 == @coordsLen)? 0: idx+1][1] else @waveCoords[idx][1] = @backupCoords[(idx == 0)? -1: idx-1][1] end } @line.coords(@waveCoords) end # Oscillation handler. This detects whether to reverse the direction # of the wave by checking to see if the peak of the wave has moved off # the screen (whose size we know already.) def reverser if @waveCoords[0][1] < 10 @direction = :right elsif @waveCoords[-1][1] < 10 @direction = :left end end # animation control def move @timer.start end def stop @timer.stop end end # Start the animation processing AnimatedWaveDemo.new(base_frame, :left).move ================================================ FILE: ext/tk/sample/demos-en/arrow.rb ================================================ # arrow.rb # # This demonstration script creates a canvas widget that displays a # large line with an arrowhead whose shape can be edited interactively. # # arrowhead widget demo (called by 'widget') # # arrowSetup -- # This method regenerates all the text and graphics in the canvas # window. It's called when the canvas is initially created, and also # whenever any of the parameters of the arrow head are changed # interactively. # # Arguments: # c - Name of the canvas widget. def arrowSetup(c) v = $demo_arrowInfo # Remember the current box, if there is one. tags = c.gettags('current') if tags != [] cur = tags.find{|t| t.kind_of?(String) && t =~ /^box[1-3]$/ } else cur = nil end # Create the arrow and outline. c.delete('all') TkcLine.new(c, v.x1, v.y, v.x2, v.y, { 'width'=>10 * v.width, 'arrowshape'=>[10*v.a, 10*v.b, 10*v.c], 'arrow'=>'last' }.update(v.bigLineStyle) ) xtip = v.x2 - 10*v.b deltaY = 10*v.c + 5*v.width TkcLine.new(c, v.x2, v.y, xtip, v.y + deltaY, v.x2 - 10*v.a, v.y, xtip, v.y - deltaY, v.x2, v.y, 'width'=>2, 'capstyle'=>'round', 'joinstyle'=>'round') # Create the boxes for reshaping the line and arrowhead. TkcRectangle.new(c, v.x2-10*v.a-5, v.y-5, v.x2-10*v.a+5, v.y+5, {'tags'=>['box1', $arrowTag_box]}.update(v.boxStyle) ) TkcRectangle.new(c, xtip-5, v.y-deltaY-5, xtip+5, v.y-deltaY+5, {'tags'=>['box2', $arrowTag_box]}.update(v.boxStyle) ) TkcRectangle.new(c, v.x1-5, v.y-5*v.width-5, v.x1+5, v.y-5*v.width+5, {'tags'=>['box3', $arrowTag_box]}.update(v.boxStyle) ) c.itemconfigure cur, v.activeStyle if cur # Create three arrows in actual size with the same parameters TkcLine.new(c, v.x2+50, 0, v.x2+50, 1000, 'width'=>2) tmp = v.x2+100 TkcLine.new(c, tmp, v.y-125, tmp, v.y-75, 'width'=>v.width, 'arrow'=>'both', 'arrowshape'=>[v.a, v.b, v.c]) TkcLine.new(c, tmp-25, v.y, tmp+25, v.y, 'width'=>v.width, 'arrow'=>'both', 'arrowshape'=>[v.a, v.b, v.c]) TkcLine.new(c, tmp-25, v.y+75, tmp+25, v.y+125, 'width'=>v.width, 'arrow'=>'both', 'arrowshape'=>[v.a, v.b, v.c]) # Create a bunch of other arrows and text items showing the # current dimensions. tmp = v.x2+10 TkcLine.new(c, tmp, v.y-5*v.width, tmp, v.y-deltaY, 'arrow'=>'both', 'arrowshape'=>v.smallTips) TkcText.new(c, v.x2+15, v.y-deltaY+5*v.c, 'text'=>v.c, 'anchor'=>'w') tmp = v.x1-10 TkcLine.new(c, tmp, v.y-5*v.width, tmp, v.y+5*v.width, 'arrow'=>'both', 'arrowshape'=>v.smallTips) TkcText.new(c, v.x1-15, v.y, 'text'=>v.width, 'anchor'=>'e') tmp = v.y+5*v.width+10*v.c+10 TkcLine.new(c, v.x2-10*v.a, tmp, v.x2, tmp, 'arrow'=>'both', 'arrowshape'=>v.smallTips) TkcText.new(c, v.x2-5*v.a, tmp+5, 'text'=>v.a, 'anchor'=>'n') tmp = tmp+25 TkcLine.new(c, v.x2-10*v.b, tmp, v.x2, tmp, 'arrow'=>'both', 'arrowshape'=>v.smallTips) TkcText.new(c, v.x2-5*v.b, tmp+5, 'text'=>v.b, 'anchor'=>'n') if $tk_version =~ /^4.*/ TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w', 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') TkcText.new(c, v.x1, 330, 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]",'anchor'=>'w', 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') else TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w', 'font'=>'Helvetica 18') TkcText.new(c, v.x1, 330, 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]", 'anchor'=>'w', 'font'=>'Helvetica 18') end v.count += 1 end # toplevel widget if defined?($arrow_demo) && $arrow_demo $arrow_demo.destroy $arrow_demo = nil end # demo toplevel widget $arrow_demo = TkToplevel.new {|w| title("Arrowhead Editor Demonstration") iconname("arrow") positionWindow(w) } base_frame = TkFrame.new($arrow_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left', 'text'=>"This widget allows you to experiment with different widths and arrowhead shapes for lines in canvases. To change the line width or the shape of the arrowhead, drag any of the three boxes attached to the oversized arrow. The arrows on the right give examples at normal scale. The text at the bottom shows the configuration options as you'd enter them for a canvas line item."){ pack('side'=>'top') } # frame $arrow_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $arrow_demo $arrow_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'arrow'} }.pack('side'=>'left', 'expand'=>'yes') } $arrow_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # canvas $arrow_canvas = TkCanvas.new(base_frame, 'width'=>500, 'height'=>350, 'relief'=>'sunken', 'borderwidth'=>2) $arrow_canvas.pack('expand'=>'yes', 'fill'=>'both') # unless Struct.const_defined?("ArrowInfo") $demo_arrowInfo = Struct.new("ArrowInfo", :a, :b, :c, :width, :motionProc, :x1, :x2, :y, :smallTips, :count, :bigLineStyle, :boxStyle, :activeStyle).new end $demo_arrowInfo.a = 8 $demo_arrowInfo.b = 10 $demo_arrowInfo.c = 3 $demo_arrowInfo.width = 2 $demo_arrowInfo.motionProc = proc{} $demo_arrowInfo.x1 = 40 $demo_arrowInfo.x2 = 350 $demo_arrowInfo.y = 150 $demo_arrowInfo.smallTips = [5, 5, 2] $demo_arrowInfo.count = 0 if TkWinfo.depth($arrow_canvas) > 1 $demo_arrowInfo.bigLineStyle = {'fill'=>'SkyBlue1'} $demo_arrowInfo.boxStyle = {'fill'=>'', 'outline'=>'black', 'width'=>1} $demo_arrowInfo.activeStyle = {'fill'=>'red', 'outline'=>'black', 'width'=>1} else $demo_arrowInfo.bigLineStyle = {'fill'=>'black', 'stipple'=>'@'+[$demo_dir,'..','images','grey.25'].join(File::Separator)} $demo_arrowInfo.boxStyle = {'fill'=>'', 'outline'=>'black', 'width'=>1} $demo_arrowInfo.activeStyle = {'fill'=>'black','outline'=>'black','width'=>1} end $arrowTag_box = TkcTag.new($arrow_canvas) arrowSetup $arrow_canvas $arrowTag_box.bind('Enter', proc{$arrow_canvas.itemconfigure('current', $demo_arrowInfo.activeStyle)}) $arrowTag_box.bind('Leave', proc{$arrow_canvas.itemconfigure('current', $demo_arrowInfo.boxStyle)}) $arrowTag_box.bind('B1-Enter', proc{}) $arrowTag_box.bind('B1-Leave', proc{}) $arrow_canvas.itembind('box1', '1', proc{$demo_arrowInfo.motionProc \ = proc{|x,y| arrowMove1 $arrow_canvas, x, y}}) $arrow_canvas.itembind('box2', '1', proc{$demo_arrowInfo.motionProc \ = proc{|x,y| arrowMove2 $arrow_canvas, x, y}}) $arrow_canvas.itembind('box3', '1', proc{$demo_arrowInfo.motionProc \ = proc{|x,y| arrowMove3 $arrow_canvas, x, y}}) $arrowTag_box.bind('B1-Motion', proc{|x,y| $demo_arrowInfo.motionProc.call(x,y)}, "%x %y") $arrow_canvas.bind('Any-ButtonRelease-1', proc{arrowSetup $arrow_canvas}) # arrowMove1 -- # This method is called for each mouse motion event on box1 (the # one at the vertex of the arrow). It updates the controlling parameters # for the line and arrowhead. # # Arguments: # c - The name of the canvas window. # x, y - The coordinates of the mouse. def arrowMove1(c,x,y) v = $demo_arrowInfo newA = (v.x2+5-c.canvasx(x).round)/10 newA = 0 if newA < 0 newA = 25 if newA > 25 if newA != v.a c.move('box1', 10*(v.a-newA), 0) v.a = newA end end # arrowMove2 -- # This method is called for each mouse motion event on box2 (the # one at the trailing tip of the arrowhead). It updates the controlling # parameters for the line and arrowhead. # # Arguments: # c - The name of the canvas window. # x, y - The coordinates of the mouse. def arrowMove2(c,x,y) v = $demo_arrowInfo newB = (v.x2+5-c.canvasx(x).round)/10 newB = 0 if newB < 0 newB = 25 if newB > 25 newC = (v.y+5-c.canvasy(y).round-5*v.width)/10 newC = 0 if newC < 0 newC = 20 if newC > 20 if newB != v.b || newC != v.c c.move('box2', 10*(v.b-newB), 10*(v.c-newC)) v.b = newB v.c = newC end end # arrowMove3 -- # This method is called for each mouse motion event on box3 (the # one that controls the thickness of the line). It updates the # controlling parameters for the line and arrowhead. # # Arguments: # c - The name of the canvas window. # x, y - The coordinates of the mouse. def arrowMove3(c,x,y) v = $demo_arrowInfo newWidth = (v.y+2-c.canvasy(y).round)/5 newWidth = 0 if newWidth < 0 newWidth = 20 if newWidth > 20 if newWidth != v.width c.move('box3', 0, 5*(v.width-newWidth)) v.width = newWidth end end ================================================ FILE: ext/tk/sample/demos-en/bind.rb ================================================ # bind.rb # # This demonstration script creates a text widget with bindings set # up for hypertext-like effects. # # text (tag bindings) widget demo (called by 'widget') # # toplevel widget if defined?($bind_demo) && $bind_demo $bind_demo.destroy $bind_demo = nil end # demo toplevel widget $bind_demo = TkToplevel.new {|w| title("Text Demonstration - Tag Bindings") iconname("bind") positionWindow(w) } base_frame = TkFrame.new($bind_demo).pack(:fill=>:both, :expand=>true) # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $bind_demo $bind_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'bind'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # bind def tag_binding_for_bind_demo(tag, enter_style, leave_style) tag.bind('Any-Enter', proc{tag.configure enter_style}) tag.bind('Any-Leave', proc{tag.configure leave_style}) end # text txt = TkText.new(base_frame){|t| # setgrid 'true' #width 60 #height 24 font $font wrap 'word' TkScrollbar.new(base_frame) {|s| pack('side'=>'right', 'fill'=>'y') command proc{|*args| t.yview(*args)} t.yscrollcommand proc{|first,last| s.set first,last} } pack('expand'=>'yes', 'fill'=>'both') # if TkWinfo.depth($root).to_i > 1 tagstyle_bold = {'background'=>'#43ce80', 'relief'=>'raised', 'borderwidth'=>1} tagstyle_normal = {'background'=>'', 'relief'=>'flat'} else tagstyle_bold = {'foreground'=>'white', 'background'=>'black'} tagstyle_normal = {'foreground'=>'', 'background'=>''} end # insert text insert 'insert', "The same tag mechanism that controls display styles in text widgets can also be used to associate Tcl commands with regions of text, so that mouse or keyboard actions on the text cause particular Tcl commands to be invoked. For example, in the text below the descriptions of the canvas demonstrations have been tagged. When you move the mouse over a demo description the description lights up, and when you press button 1 over a description then that particular demonstration is invoked. " insert('end', '1. Samples of all the different types of items that can be created in canvas widgets.', (d1 = TkTextTag.new(t)) ) insert('end', "\n\n") insert('end', '2. A simple two-dimensional plot that allows you to adjust the positions of the data points.', (d2 = TkTextTag.new(t)) ) insert('end', "\n\n") insert('end', '3. Anchoring and justification modes for text items.', (d3 = TkTextTag.new(t)) ) insert('end', "\n\n") insert('end', '4. An editor for arrow-head shapes for line items.', (d4 = TkTextTag.new(t)) ) insert('end', "\n\n") insert('end', '5. A ruler with facilities for editing tab stops.', (d5 = TkTextTag.new(t)) ) insert('end', "\n\n") insert('end', '6. A grid that demonstrates how canvases can be scrolled.', (d6 = TkTextTag.new(t)) ) # binding [d1, d2, d3, d4, d5, d6].each{|tag| tag_binding_for_bind_demo(tag, tagstyle_bold, tagstyle_normal) } d1.bind('1', proc{ eval_samplecode(`cat #{[$demo_dir,'items.rb'].join(File::Separator)}`, 'items.rb') }) d2.bind('1', proc{ eval_samplecode(`cat #{[$demo_dir,'plot.rb'].join(File::Separator)}`, 'plot.rb') }) d3.bind('1', proc{ eval_samplecode(`cat #{[$demo_dir,'ctext.rb'].join(File::Separator)}`, 'ctext.rb') }) d4.bind('1', proc{ eval_samplecode(`cat #{[$demo_dir,'arrow.rb'].join(File::Separator)}`, 'arrow.rb') }) d5.bind('1', proc{ eval_samplecode(`cat #{[$demo_dir,'ruler.rb'].join(File::Separator)}`, 'ruler.rb') }) d6.bind('1', proc{ eval_samplecode(`cat #{[$demo_dir,'cscroll.rb'].join(File::Separator)}`, 'cscroll.rb') }) TkTextMarkInsert.new(t, '0.0') configure('state','disabled') } txt.width 60 txt.height 24 ================================================ FILE: ext/tk/sample/demos-en/bitmap.rb ================================================ # bitmap.rb # # This demonstration script creates a toplevel window that displays # all of Tk's built-in bitmaps.# # bitmap widget demo (called by 'widget') # # bitmapRow -- # Create a row of bitmap items in a window. # # Arguments: # w - The parent window that is to contain the row. # args - The names of one or more bitmaps, which will be displayed # in a new row across the bottom of w along with their # names. def bitmapRow(w,*args) TkFrame.new(w){|row| pack('side'=>'top', 'fill'=>'both') for bitmap in args TkFrame.new(row){|base| pack('side'=>'left', 'fill'=>'both', 'pady'=>'.25c', 'padx'=>'.25c') TkLabel.new(base, 'text'=>bitmap, 'width'=>9).pack('side'=>'bottom') Tk::Label.new(base, 'bitmap'=>bitmap).pack('side'=>'bottom') } end } end # toplevel widget if defined?($bitmap_demo) && $bitmap_demo $bitmap_demo.destroy $bitmap_demo = nil end # demo toplevel widget $bitmap_demo = TkToplevel.new {|w| title("Bitmap Demonstration") iconname("bitmap") positionWindow(w) } base_frame = TkFrame.new($bitmap_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left', 'text'=>"This window displays all of Tk's built-in bitmaps, along with the names you can use for them in Tcl scripts."){ pack('side'=>'top') } # frame $bitmap_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $bitmap_demo $bitmap_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'bitmap'} }.pack('side'=>'left', 'expand'=>'yes') } $bitmap_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame TkFrame.new(base_frame){|f| bitmapRow(f,'error','gray25','gray50','hourglass') bitmapRow(f,'info','question','questhead','warning') pack('side'=>'top', 'expand'=>'yes', 'fill'=>'both') } ================================================ FILE: ext/tk/sample/demos-en/browse1 ================================================ #!/usr/bin/env ruby # browse -- # This script generates a directory browser, which lists the working # directory and allow you to open files or subdirectories by # double-clicking. require 'tk' # Create a scrollbar on the right side of the main window and a listbox # on the left side. listbox = TkListbox.new(nil, 'relief'=>'sunken', 'width'=>20, 'height'=>20, 'setgrid'=>'yes') {|l| TkScrollbar.new(nil, 'command'=>proc{|*args| l.yview *args}) {|s| pack('side'=>'right', 'fill'=>'y') l.yscrollcommand(proc{|first,last| s.set(first,last)}) } pack('side'=>'left', 'fill'=>'both', 'expand'=>'yes') } root = TkRoot.new root.minsize(1,1) # The procedure below is invoked to open a browser on a given file; if the # file is a directory then another instance of this program is invoked; if # the file is a regular file then the Mx editor is invoked to display # the file. def browse (dir, file) file = dir + File::Separator + file if dir != '.' type = File.ftype(file) if type == 'directory' system($0 + ' ' + file + ' &') else if type == 'file' if ENV['EDITOR'] system(ENV['EDITOR'] + ' ' + file + ' &') else system('xedit ' + file + ' &') end else STDOUT.print "\"#{file}\" isn't a directory or regular file" end end end # Fill the listbox with a list of all the files in the directory (run # the "ls" command to get that information). dir = ARGV[0] ? ARGV[0] : '.' open("|ls -a #{dir}", 'r'){|fid| fid.readlines}.each{|fname| listbox.insert('end', fname.chomp) } # Set up bindings for the browser. Tk.bind_all('Control-c', proc{root.destroy}) listbox.bind('Double-Button-1', proc{TkSelection.get.each{|f| browse dir, f}}) Tk.mainloop ================================================ FILE: ext/tk/sample/demos-en/browse2 ================================================ #!/usr/bin/env ruby # browse -- # This script generates a directory browser, which lists the working # directory and allow you to open files or subdirectories by # double-clicking. require 'tk' class Browse BROWSE_WIN_COUNTER = TkVariable.new(0) def initialize(dir) BROWSE_WIN_COUNTER.value = BROWSE_WIN_COUNTER.to_i + 1 # create base frame base = TkToplevel.new { minsize(1,1) title('Browse : ' + dir) } # Create a scrollbar on the right side of the main window and a listbox # on the left side. list = TkListbox.new(base, 'relief'=>'sunken', 'width'=>20, 'height'=>20, 'setgrid'=>'yes') {|l| TkScrollbar.new(base, 'command'=>proc{|*args| l.yview *args}) {|s| pack('side'=>'right', 'fill'=>'y') l.yscrollcommand(proc{|first,last| s.set(first,last)}) } pack('side'=>'left', 'fill'=>'both', 'expand'=>'yes') # Fill the listbox with a list of all the files in the directory (run # the "ls" command to get that information). open("|ls -a #{dir}", 'r'){|fid| fid.readlines}.each{|fname| l.insert('end', fname.chomp) } } # Set up bindings for the browser. base.bind('Destroy', proc{ Browse::BROWSE_WIN_COUNTER.value = \ Browse::BROWSE_WIN_COUNTER.to_i - 1 }) base.bind('Control-c', proc{base.destroy}) list.bind('Double-Button-1', proc{TkSelection.get.each{|f| self.browse dir, f}}) end # The method below is invoked to open a browser on a given file; if the # file is a directory then another instance of this program is invoked; if # the file is a regular file then the Mx editor is invoked to display # the file. def browse (dir, file) file = dir + File::Separator + file if dir != '.' type = File.ftype(file) if type == 'directory' Browse.new(file) else if type == 'file' if ENV['EDITOR'] system(ENV['EDITOR'] + ' ' + file + ' &') else system('xedit ' + file + ' &') end else STDOUT.print "\"#{file}\" isn't a directory or regular file" end end end end Browse.new(ARGV[0] ? ARGV[0] : '.') TkRoot.new { withdraw Browse::BROWSE_WIN_COUNTER.trace('w', proc{exit if Browse::BROWSE_WIN_COUNTER.to_i == 0}) } Tk.mainloop ================================================ FILE: ext/tk/sample/demos-en/button.rb ================================================ # button.rb # # This demonstration script creates a toplevel window containing # several button widgets. # # button widget demo (called by 'widget') # # toplevel widget if defined?($button_demo) && $button_demo $button_demo.destroy $button_demo = nil end # demo toplevel widget $button_demo = TkToplevel.new {|w| title("Button Demonstration") iconname("button") positionWindow(w) } # label msg = TkLabel.new($button_demo) { font $kanji_font wraplength '4i' justify 'left' text "If you click on any of the four buttons below, the background of the button area will change to the color indicated in the button. You can press Tab to move among the buttons, then press Space to invoke the current button." } msg.pack('side'=>'top') # frame $button_buttons = Tk::Frame.new($button_demo) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $button_demo $button_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'See Code' command proc{showCode 'button'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # button TkButton.new($button_demo){ text "Peach Puff" width 10 command proc{ $button_demo.configure('bg','PeachPuff1') $button_buttons.configure('bg','PeachPuff1') } }.pack('side'=>'top', 'expand'=>'yes', 'pady'=>2) TkButton.new($button_demo){ text "Light Blue" width 10 command proc{ $button_demo.configure('bg','LightBlue1') $button_buttons.configure('bg','LightBlue1') } }.pack('side'=>'top', 'expand'=>'yes', 'pady'=>2) TkButton.new($button_demo){ text "Sea Green" width 10 command proc{ $button_demo.configure('bg','SeaGreen2') $button_buttons.configure('bg','SeaGreen2') } }.pack('side'=>'top', 'expand'=>'yes', 'pady'=>2) TkButton.new($button_demo){ text "Yellow" width 10 command proc{ $button_demo.configure('bg','Yellow1') $button_buttons.configure('bg','Yellow1') } }.pack('side'=>'top', 'expand'=>'yes', 'pady'=>2) ================================================ FILE: ext/tk/sample/demos-en/check.rb ================================================ # check.rb # # This demonstration script creates a toplevel window containing # several checkbuttons. # # checkbutton widget demo (called by 'widget') # # toplevel widget if defined?($check_demo) && $check_demo $check_demo.destroy $check_demo = nil end # demo toplevel widget $check_demo = TkToplevel.new {|w| title("Checkbutton Demonstration") iconname("check") positionWindow(w) } base_frame = TkFrame.new($check_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "Three checkbuttons are displayed below. If you click on a button, it will toggle the button's selection state and set a Tcl variable to a value indicating the state of the checkbutton. Click the \"See Variables\" button to see the current values of the variables." } msg.pack('side'=>'top') # wipers = TkVariable.new(0) brakes = TkVariable.new(0) sober = TkVariable.new(0) # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $check_demo $check_demo = nil $showVarsWin[tmppath.path] = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'check'} }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'See Variables' command proc{ showVars(base_frame, ['wipers', wipers], ['brakes', brakes], ['sober', sober]) } }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # checkbutton [ TkCheckButton.new(base_frame, 'text'=>'Wipers OK', 'variable'=>wipers), TkCheckButton.new(base_frame, 'text'=>'Brakes OK', 'variable'=>brakes), TkCheckButton.new(base_frame, 'text'=>'Driver Sober', 'variable'=>sober) ].each{|w| w.relief('flat'); w.pack('side'=>'top', 'pady'=>2, 'anchor'=>'w')} ================================================ FILE: ext/tk/sample/demos-en/check2.rb ================================================ # # checkbutton widget demo2 (called by 'widget') # # delete old toplevel widget if defined?($check2_demo) && $check2_demo $check2_demo.destroy $check2_demo = nil end # create demo toplevel widget $check2_demo = TkToplevel.new {|w| title("Checkbutton Demonstration 2") iconname("check2") positionWindow(w) } base_frame = TkFrame.new($check2_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "Four checkbuttons are displayed below. If you click on a button, it will toggle the button's selection state and set a Tcl variable to a value indicating the state of the checkbutton. The first button also follows the state of the other three. If only some of the three are checked, the first button will display the tri-state mode. Click the \"See Variables\" button to see the current values of the variables." } msg.pack('side'=>'top') # variable safety = TkVariable.new(0) wipers = TkVariable.new(0) brakes = TkVariable.new(0) sober = TkVariable.new(0) # frame TkFrame.new(base_frame) {|frame| TkGrid(TkFrame.new(frame, :height=>2, :relief=>:sunken, :bd=>2), :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', TkButton.new(frame, :text=>'See Variables', :image=>$image['view'], :compound=>:left, :command=>proc{ showVars($check2_demo, ['safety', safety], ['wipers', wipers], ['brakes', brakes], ['sober', sober]) }), TkButton.new(frame, :text=>'See Code', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'check2'}), TkButton.new(frame, :text=>'Dismiss', :image=>$image['delete'], :compound=>:left, :command=>proc{ tmppath = $check2_demo $check2_demo = nil $showVarsWin[tmppath.path] = nil tmppath.destroy }), :padx=>4, :pady=>4) frame.grid_columnconfigure(0, :weight=>1) }.pack('side'=>'bottom', 'fill'=>'x') # checkbutton TkCheckButton.new(base_frame, :text=>'Safety Check', :variable=>safety, :relief=>:flat, :onvalue=>'all', :offvalue=>'none', :tristatevalue=>'partial'){ pack('side'=>'top', 'pady'=>2, 'anchor'=>'w') } [ TkCheckButton.new(base_frame, 'text'=>'Wipers OK', 'variable'=>wipers), TkCheckButton.new(base_frame, 'text'=>'Brakes OK', 'variable'=>brakes), TkCheckButton.new(base_frame, 'text'=>'Driver Sober', 'variable'=>sober) ].each{|w| w.relief('flat') w.pack('side'=>'top', 'padx'=>15, 'pady'=>2, 'anchor'=>'w') } # tristate check in_check = false tristate_check = proc{|n1,n2,op| unless in_check in_check = true begin if n1 == safety if safety == 'none' wipers.value = 0 brakes.value = 0 sober.value = 0 elsif safety == 'all' wipers.value = 1 brakes.value = 1 sober.value = 1 end else if wipers == 1 && brakes == 1 && sober == 1 safety.value = 'all' elsif wipers == 1 || brakes == 1 || sober == 1 safety.value = 'partial' else safety.value = 'none' end end ensure in_check = false end end } [wipers, brakes, sober, safety].each{|v| v.trace('w', tristate_check)} ================================================ FILE: ext/tk/sample/demos-en/clrpick.rb ================================================ # clrpick.rb # # This demonstration script prompts the user to select a color. # # widget demo prompts the user to select a color (called by 'widget') # # Note: don't support ttk_wrapper. work with standard widgets only. # # toplevel widget if defined?($clrpick_demo) && $clrpick_demo $clrpick_demo.destroy $clrpick_demo = nil end # demo toplevel widget $clrpick_demo = TkToplevel.new {|w| title("Color Selection Dialogs") iconname("colors") positionWindow(w) } base_frame = TkFrame.new($clrpick_demo).pack(:fill=>:both, :expand=>true) # label #TkLabel.new($clrpick_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left', Tk::Label.new($clrpick_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left', 'text'=>"Press the buttons below to choose the foreground and background colors for the widgets in this window.").pack('side'=>'top') # frame #TkFrame.new($clrpick_demo) {|frame| Tk::Frame.new($clrpick_demo) {|frame| # TkButton.new(frame) { Tk::Button.new(frame) { text 'Dismiss' command proc{ tmppath = $clrpick_demo $clrpick_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') # TkButton.new(frame) { Tk::Button.new(frame) { text 'Show Code' command proc{showCode 'clrpick'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # button # TkButton.new($clrpick_demo, 'text'=>'Set background color ...') {|b| Tk::Button.new($clrpick_demo, 'text'=>'Set background color ...') {|b| command(proc{setColor $clrpick_demo, b, 'background', ['background', 'highlightbackground']}) pack('side'=>'top', 'anchor'=>'c', 'pady'=>'2m') } # TkButton.new($clrpick_demo, 'text'=>'Set foreground color ...') {|b| Tk::Button.new($clrpick_demo, 'text'=>'Set foreground color ...') {|b| command(proc{setColor $clrpick_demo, b, 'foreground', ['foreground']}) pack('side'=>'top', 'anchor'=>'c', 'pady'=>'2m') } def setColor(w,button,name,options) w.grab initialColor = button[name] color = Tk.chooseColor('title'=>"Choose a #{name} color", 'parent'=>w, 'initialcolor'=>initialColor) if color != "" setColor_helper(w,options,color) end w.grab('release') end def setColor_helper(w, options, color) options.each{|opt| begin w[opt] = color rescue end } TkWinfo.children(w).each{|child| setColor_helper child, options, color } end ================================================ FILE: ext/tk/sample/demos-en/colors.rb ================================================ # colors.rb # # This demonstration script creates a listbox widget that displays # many of the colors from the X color database. You can click on # a color to change the application's palette. # # listbox widget demo 'colors' (called by 'widget') # # toplevel widget if defined?($colors_demo) && $colors_demo $colors_demo.destroy $colors_demo = nil end # demo toplevel widget $colors_demo = TkToplevel.new {|w| title("Listbox Demonstration (colors)") iconname("colors") positionWindow(w) } base_frame = TkFrame.new($colors_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "A listbox containing several color names is displayed below, along with a scrollbar. You can scan the list either using the scrollbar or by dragging in the listbox window with button 2 pressed. If you double-click button 1 on a color, then the application's color palette will be set to match that color" } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $colors_demo $colors_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'colors'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame colors_lbox = nil TkFrame.new(base_frame, 'borderwidth'=>10) {|w| s = TkScrollbar.new(w) colors_lbox = TkListbox.new(w) { setgrid 1 width 10 height 12 yscrollcommand proc{|first,last| s.set first,last} } s.command(proc{|*args| colors_lbox.yview(*args)}) s.pack('side'=>'right', 'fill'=>'y') colors_lbox.pack('side'=>'left', 'expand'=>1, 'fill'=>'both') }.pack('side'=>'top', 'expand'=>'yes', 'fill'=>'y') #colors_lbox.bind('Double-1', proc{TkPalette.setPalette TkSelection.get}) colors_lbox.bind('Double-1', proc{ begin TkPalette.setPalette TkSelection.get rescue => e p e Tk.tk_call_without_enc('destroy', '.___tk_set_palette') end }) ins_data = [ 'gray60','gray70','gray80','gray85','gray90','gray95', 'snow1','snow2','snow3','snow4','seashell1','seashell2', 'seashell3','seashell4','AntiqueWhite1','AntiqueWhite2', 'AntiqueWhite3','AntiqueWhite4','bisque1','bisque2', 'bisque3','bisque4','PeachPuff1','PeachPuff2', 'PeachPuff3','PeachPuff4','NavajoWhite1','NavajoWhite2', 'NavajoWhite3','NavajoWhite4','LemonChiffon1', 'LemonChiffon2','LemonChiffon3','LemonChiffon4', 'cornsilk1','cornsilk2','cornsilk3','cornsilk4', 'ivory1','ivory2','ivory3','ivory4','honeydew1', 'honeydew2','honeydew3','honeydew4','LavenderBlush1', 'LavenderBlush2','LavenderBlush3','LavenderBlush4', 'MistyRose1','MistyRose2','MistyRose3','MistyRose4', 'azure1','azure2','azure3','azure4','SlateBlue1', 'SlateBlue2','SlateBlue3','SlateBlue4','RoyalBlue1', 'RoyalBlue2','RoyalBlue3','RoyalBlue4','blue1','blue2', 'blue3','blue4','DodgerBlue1','DodgerBlue2', 'DodgerBlue3','DodgerBlue4','SteelBlue1','SteelBlue2', 'SteelBlue3','SteelBlue4','DeepSkyBlue1','DeepSkyBlue2', 'DeepSkyBlue3','DeepSkyBlue4','SkyBlue1','SkyBlue2', 'SkyBlue3','SkyBlue4','LightSkyBlue1','LightSkyBlue2', 'LightSkyBlue3','LightSkyBlue4','SlateGray1', 'SlateGray2','SlateGray3','SlateGray4', 'LightSteelBlue1','LightSteelBlue2','LightSteelBlue3', 'LightSteelBlue4','LightBlue1','LightBlue2', 'LightBlue3','LightBlue4','LightCyan1','LightCyan2', 'LightCyan3','LightCyan4','PaleTurquoise1', 'PaleTurquoise2','PaleTurquoise3','PaleTurquoise4', 'CadetBlue1','CadetBlue2','CadetBlue3','CadetBlue4', 'turquoise1','turquoise2','turquoise3','turquoise4', 'cyan1','cyan2','cyan3','cyan4','DarkSlateGray1', 'DarkSlateGray2','DarkSlateGray3','DarkSlateGray4', 'aquamarine1','aquamarine2','aquamarine3','aquamarine4', 'DarkSeaGreen1','DarkSeaGreen2','DarkSeaGreen3', 'DarkSeaGreen4','SeaGreen1','SeaGreen2','SeaGreen3', 'SeaGreen4','PaleGreen1','PaleGreen2','PaleGreen3', 'PaleGreen4','SpringGreen1','SpringGreen2', 'SpringGreen3','SpringGreen4','green1','green2', 'green3','green4','chartreuse1','chartreuse2', 'chartreuse3','chartreuse4','OliveDrab1','OliveDrab2', 'OliveDrab3','OliveDrab4','DarkOliveGreen1', 'DarkOliveGreen2','DarkOliveGreen3','DarkOliveGreen4', 'khaki1','khaki2','khaki3','khaki4','LightGoldenrod1', 'LightGoldenrod2','LightGoldenrod3','LightGoldenrod4', 'LightYellow1','LightYellow2','LightYellow3', 'LightYellow4','yellow1','yellow2','yellow3','yellow4', 'gold1','gold2','gold3','gold4','goldenrod1', 'goldenrod2','goldenrod3','goldenrod4','DarkGoldenrod1', 'DarkGoldenrod2','DarkGoldenrod3','DarkGoldenrod4', 'RosyBrown1','RosyBrown2','RosyBrown3','RosyBrown4', 'IndianRed1','IndianRed2','IndianRed3','IndianRed4', 'sienna1','sienna2','sienna3','sienna4','burlywood1', 'burlywood2','burlywood3','burlywood4','wheat1', 'wheat2','wheat3','wheat4','tan1','tan2','tan3','tan4', 'chocolate1','chocolate2','chocolate3','chocolate4', 'firebrick1','firebrick2','firebrick3','firebrick4', 'brown1','brown2','brown3','brown4','salmon1','salmon2', 'salmon3','salmon4','LightSalmon1','LightSalmon2', 'LightSalmon3','LightSalmon4','orange1','orange2', 'orange3','orange4','DarkOrange1','DarkOrange2', 'DarkOrange3','DarkOrange4','coral1','coral2','coral3', 'coral4','tomato1','tomato2','tomato3','tomato4', 'OrangeRed1','OrangeRed2','OrangeRed3','OrangeRed4', 'red1','red2','red3','red4','DeepPink1','DeepPink2', 'DeepPink3','DeepPink4','HotPink1','HotPink2', 'HotPink3','HotPink4','pink1','pink2','pink3','pink4', 'LightPink1','LightPink2','LightPink3','LightPink4', 'PaleVioletRed1','PaleVioletRed2','PaleVioletRed3', 'PaleVioletRed4','maroon1','maroon2','maroon3', 'maroon4','VioletRed1','VioletRed2','VioletRed3', 'VioletRed4','magenta1','magenta2','magenta3', 'magenta4','orchid1','orchid2','orchid3','orchid4', 'plum1','plum2','plum3','plum4','MediumOrchid1', 'MediumOrchid2','MediumOrchid3','MediumOrchid4', 'DarkOrchid1','DarkOrchid2','DarkOrchid3', 'DarkOrchid4','purple1','purple2','purple3','purple4', 'MediumPurple1','MediumPurple2','MediumPurple3', 'MediumPurple4','thistle1','thistle2','thistle3', 'thistle4' ] colors_lbox.insert(0, *ins_data) ================================================ FILE: ext/tk/sample/demos-en/combo.rb ================================================ # combo.rb -- # # This demonstration script creates several combobox widgets. # # based on "Id: combo.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp" if defined?($combo_demo) && $combo_demo $combo_demo.destroy $combo_demo = nil end $combo_demo = TkToplevel.new {|w| title("Combobox Demonstration") iconname("combo") positionWindow(w) } base_frame = TkFrame.new($combo_demo).pack(:fill=>:both, :expand=>true) Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'5i', :justify=>:left, :text=><:top, :fill=>:x) Three different combo-boxes are displayed below. \ You can add characters to the first \ one by pointing, clicking and typing, just as with an entry; pressing \ Return will cause the current value to be added to the list that is \ selectable from the drop-down list, and you can choose other values \ by pressing the Down key, using the arrow keys to pick another one, \ and pressing Return again. The second combo-box is fixed to a \ particular value, and cannot be modified at all. The third one only \ allows you to select values from its drop-down list of Australian \ cities. EOL ## variables firstValue = TkVariable.new secondValue = TkVariable.new ozCity = TkVariable.new ## See Code / Dismiss buttons Ttk::Frame.new(base_frame) {|frame| sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'See Variables', :image=>$image['view'], :compound=>:left, :command=>proc{ showVars(base_frame, ['firstVariable', firstValue], ['secondVariable', secondValue], ['ozCity', ozCity]) }), Ttk::Button.new(frame, :text=>'See Code', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'combo'}), Ttk::Button.new(frame, :text=>'Dismiss', :image=>$image['delete'], :compound=>:left, :command=>proc{ $combo_demo.destroy $combo_demo = nil }), :padx=>4, :pady=>4) grid_columnconfigure(0, :weight=>1) pack(:side=>:bottom, :fill=>:x) } frame = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true) australianCities = [ 'Canberra', 'Sydney', 'Melbourne', 'Perth', 'Adelaide', 'Brisbane', 'Hobart', 'Darwin', 'Alice Springs' ] secondValue.value = 'unchangable' ozCity.value = 'Sydney' Tk.pack(Ttk::Labelframe.new(frame, :text=>'Fully Editable'){|f| Ttk::Combobox.new(f, :textvariable=>firstValue){|b| b.bind('Return', '%W'){|w| w.values <<= w.value unless w.values.include?(w.value) } }.pack(:pady=>5, :padx=>10) }, Ttk::LabelFrame.new(frame, :text=>'Disabled'){|f| Ttk::Combobox.new(f, :textvariable=>secondValue, :state=>:disabled) . pack(:pady=>5, :padx=>10) }, Ttk::LabelFrame.new(frame, :text=>'Defined List Only'){|f| Ttk::Combobox.new(f, :textvariable=>ozCity, :state=>:readonly, :values=>australianCities) . pack(:pady=>5, :padx=>10) }, :side=>:top, :pady=>5, :padx=>10) ================================================ FILE: ext/tk/sample/demos-en/cscroll.rb ================================================ # cscroll.rb # # This demonstration script creates a simple canvas that can be # scrolled in two dimensions. # # simple scrollable canvas widget demo (called by 'widget') # # toplevel widget if defined?($cscroll_demo) && $cscroll_demo $cscroll_demo.destroy $cscroll_demo = nil end # demo toplevel widget $cscroll_demo = TkToplevel.new {|w| title("Scrollable Canvas Demonstration") iconname("cscroll") positionWindow(w) } base_frame = TkFrame.new($cscroll_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'4i', 'justify'=>'left', 'text'=>"This window displays a canvas widget that can be scrolled either using the scrollbars or by dragging with button 2 in the canvas. If you click button 1 on one of the rectangles, its indices will be printed on stdout."){ pack('side'=>'top') } # frame $cscroll_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $cscroll_demo $cscroll_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'cscroll'} }.pack('side'=>'left', 'expand'=>'yes') } $cscroll_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame unless $tk_version =~ /^4\.[01]/ $cscroll_grid = TkFrame.new(base_frame) { pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1) } TkGrid.rowconfigure($cscroll_grid, 0, 'weight'=>1, 'minsize'=>0) TkGrid.columnconfigure($cscroll_grid, 0, 'weight'=>1, 'minsize'=>0) end # canvas $cscroll_canvas = TkCanvas.new(base_frame, 'relief'=>'sunken', 'borderwidth'=>2, 'scrollregion'=>['-11c', '-11c', '50c', '20c'] ) {|c| if $tk_version =~ /^4\.[01]/ pack('expand'=>'yes', 'fill'=>'both') else grid('in'=>$cscroll_grid, 'padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') end TkScrollbar.new(base_frame, 'command'=>proc{|*args| c.yview(*args)}) {|vs| c.yscrollcommand(proc{|first,last| vs.set first,last}) if $tk_version =~ /^4\.[01]/ pack('side'=>'right', 'fill'=>'y') else grid('in'=>$cscroll_grid, 'padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>1, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') end } TkScrollbar.new(base_frame, 'orient'=>'horiz', 'command'=>proc{|*args| c.xview(*args)}) {|hs| c.xscrollcommand(proc{|first,last| hs.set first,last}) if $tk_version =~ /^4\.[01]/ pack('side'=>'bottom', 'fill'=>'x') else grid('in'=>$cscroll_grid, 'padx'=>1, 'pady'=>1, 'row'=>1, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') end } } bg = $cscroll_canvas.configinfo('bg')[4] (0..19).each{|i| x = -10+3*i y = -10 (0..9).each{|j| TkcRectangle.new($cscroll_canvas, "#{x}c", "#{y}c", "#{x+2}c", "#{y+2}c", 'outline'=>'black', 'fill'=>bg, 'tags'=>'rect') TkcText.new($cscroll_canvas, "#{x+1}c", "#{y+1}c", 'text'=>"#{i},#{j}", 'anchor'=>'center', 'tags'=>'text') y += 3 } } $cscroll_canvas.itembind('all', 'Any-Enter', proc{scrollEnter $cscroll_canvas}) $cscroll_canvas.itembind('all', 'Any-Leave', proc{scrollLeave $cscroll_canvas}) $cscroll_canvas.itembind('all', '1', proc{scrollButton $cscroll_canvas}) $cscroll_canvas.itembind('all', 'Any-Enter', proc{scrollEnter $cscroll_canvas}) $cscroll_canvas.bind('2', proc{|x,y| $cscroll_canvas.scan_mark(x,y)}, '%x %y') $cscroll_canvas.bind('B2-Motion', proc{|x,y| $cscroll_canvas.scan_dragto(x,y)}, '%x %y') def scrollEnter(c) id = c.find_withtag('current')[0].id id -= 1 if c.gettags('current').include?('text') $oldFill = c.itemconfiginfo(id, 'fill')[4] if TkWinfo.depth(c) > 1 c.itemconfigure(id, 'fill'=>'SeaGreen1') else c.itemconfigure(id, 'fill'=>'black') c.itemconfigure(id+1, 'fill'=>'white') end end def scrollLeave(c) id = c.find_withtag('current')[0].id id -= 1 if c.gettags('current').include?('text') c.itemconfigure(id, 'fill'=>$oldFill) c.itemconfigure(id+1, 'fill'=>'black') end def scrollButton(c) id = c.find_withtag('current')[0].id id += 1 unless c.gettags('current').include?('text') print "You buttoned at #{c.itemconfiginfo(id,'text')[4]}\n" end ================================================ FILE: ext/tk/sample/demos-en/ctext.rb ================================================ # ctext.rb # # This demonstration script creates a canvas widget with a text # item that can be edited and reconfigured in various ways. # # Canvas Text widget demo (called by 'widget') # # toplevel widget if defined?($ctext_demo) && $ctext_demo $ctext_demo.destroy $ctext_demo = nil end # demo toplevel widget $ctext_demo = TkToplevel.new {|w| title("Canvas Text Demonstration") iconname("Text") positionWindow(w) } base_frame = TkFrame.new($ctext_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left', 'text'=>"This window displays a string of text to demonstrate the text facilities of canvas widgets. You can click in the boxes to adjust the position of the text relative to its positioning point or change its justification. The text also supports the following simple bindings for editing: 1. You can point, click, and type. 2. You can also select with button 1. 3. You can copy the selection to the mouse position with button 2. 4. Backspace and Control+h delete the selection if there is one; otherwise they delete the character just before the insertion cursor. 5. Delete deletes the selection if there is one; otherwise it deletes the character just after the insertion cursor."){ pack('side'=>'top') } # frame $ctext_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $ctext_demo $ctext_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'ctext'} }.pack('side'=>'left', 'expand'=>'yes') } $ctext_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # canvas $ctext_canvas = TkCanvas.new(base_frame, 'relief'=>'flat', 'borderwidth'=>0, 'width'=>500, 'height'=>350) $ctext_canvas.pack('side'=>'top', 'expand'=>'yes', 'fill'=>'both') # font if $tk_version =~ /^4.*/ textFont = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*' else textFont = 'Helvetica 24' end # canvas TkcRectangle.new($ctext_canvas, 245, 195, 255, 205, 'outline'=>'black', 'fill'=>'red') ctag_text_param = { 'text'=>"This is just a string of text to demonstrate the text facilities of canvas widgets. Bindings have been been defined to support editing (see above).", 'width'=>440, 'anchor'=>'n', 'justify'=>'left' } if $tk_version =~ /^4.*/ ctag_text_param['font'] = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*' else ctag_text_param['font'] = 'Helvetica 24' end $ctag_text = TkcTag.new($ctext_canvas) $ctag_text.withtag(TkcText.new($ctext_canvas, 250, 200, ctag_text_param)) $ctag_text.bind('1', proc{|x,y| textB1Press $ctext_canvas,x,y}, "%x %y") $ctag_text.bind('B1-Motion', proc{|x,y| textB1Move $ctext_canvas,x,y}, "%x %y") $ctag_text.bind('Shift-1', proc{|x,y| $ctext_canvas.seleect_adjust 'current', "@#{x},#{y}"}, "%x %y") $ctag_text.bind('Shift-B1-Motion', proc{|x,y| textB1Move $ctext_canvas,x,y}, "%x %y") $ctag_text.bind('KeyPress', proc{|a| textInsert $ctext_canvas,a}, "%A") $ctag_text.bind('Return', proc{textInsert $ctext_canvas,"\n"}) $ctag_text.bind('Control-h', proc{textBs $ctext_canvas}) $ctag_text.bind('BackSpace', proc{textBs $ctext_canvas}) $ctag_text.bind('Delete', proc{textDel $ctext_canvas}) $ctag_text.bind('2', proc{|x,y| textPaste $ctext_canvas, "@#{x},#{y}"}, "%x %y") # Next, create some items that allow the text's anchor position # to be edited. def mkTextConfig(w,x,y,option,value,color) item = TkcRectangle.new(w, x, y, x+30, y+30, 'outline'=>'black', 'fill'=>color, 'width'=>1) item.bind('1', proc{$ctag_text.configure option, value}) w.addtag_withtag('config', item) end x = 50 y = 50 color = 'LightSkyBlue1' mkTextConfig $ctext_canvas, x, y, 'anchor', 'se', color mkTextConfig $ctext_canvas, x+30, y, 'anchor', 's', color mkTextConfig $ctext_canvas, x+60, y, 'anchor', 'sw', color mkTextConfig $ctext_canvas, x, y+30, 'anchor', 'e', color mkTextConfig $ctext_canvas, x+30, y+30, 'anchor', 'center', color mkTextConfig $ctext_canvas, x+60, y+30, 'anchor', 'w', color mkTextConfig $ctext_canvas, x, y+60, 'anchor', 'ne', color mkTextConfig $ctext_canvas, x+30, y+60, 'anchor', 'n', color mkTextConfig $ctext_canvas, x+60, y+60, 'anchor', 'nw', color item = TkcRectangle.new($ctext_canvas, x+40, y+40, x+50, y+50, 'outline'=>'black', 'fill'=>'red') item.bind('1', proc{$ctag_text.configure 'anchor', 'center'}) if $tk_version =~ /^4.*/ TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position', 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', 'anchor'=>'s', 'fill'=>'brown') else TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position', 'font'=>'Times 24', 'anchor'=>'s', 'fill'=>'brown') end # Lastly, create some items that allow the text's justification to be # changed. x = 350 y = 50 color = 'SeaGreen2' mkTextConfig $ctext_canvas, x, y, 'justify', 'left', color mkTextConfig $ctext_canvas, x+30, y, 'justify', 'center', color mkTextConfig $ctext_canvas, x+60, y, 'justify', 'right', color if $tk_version =~ /^4.*/ TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification', 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', 'anchor'=>'s', 'fill'=>'brown') else TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification', 'font'=>'Times 24', 'anchor'=>'s', 'fill'=>'brown') end $ctext_canvas.itembind('config', 'Enter', proc{textEnter $ctext_canvas}) $ctext_canvas.itembind('config', 'Leave', proc{$ctext_canvas\ .itemconfigure('current', 'fill'=>$textConfigFill)}) $textConfigFill = '' def textEnter(w) $textConfigFill = (w.itemconfiginfo 'current', 'fill')[4] w.itemconfigure 'current', 'fill', 'black' end def textInsert(w, string) return if string == "" begin $ctag_text.dchars 'sel.first', 'sel.last' rescue end $ctag_text.insert 'insert', string end def textPaste(w, pos) begin $ctag_text.insert pos, TkSelection.get rescue end end def textB1Press(w,x,y) w.icursor 'current', "@#{x},#{y}" w.itemfocus 'current' w.focus w.select_from 'current', "@#{x},#{y}" end def textB1Move(w,x,y) w.select_to 'current', "@#{x},#{y}" end def textBs(w) begin $ctag_text.dchars 'sel.first', 'sel.last' rescue char = $ctag_text.index('insert').to_i - 1 $ctag_text.dchars(char) if char >= 0 end end def textDel(w) begin $ctag_text.dchars 'sel.first', 'sel.last' rescue $ctag_text.dchars 'insert' end end ================================================ FILE: ext/tk/sample/demos-en/dialog1.rb ================================================ # # a dialog box with a local grab (called by 'widget') # class TkDialog_Demo1 < TkDialog ############### private ############### def title "Dialog with local grab" end def message 'This is a modal dialog box. It uses Tk\'s "grab" command to create a "local grab" on the dialog box. The grab prevents any pointer-related events from getting to any other windows in the application until you have answered the dialog by invoking one of the buttons below. However, you can still interact with other applications.' end def bitmap 'info' end def default_button 0 end def buttons # ["Dismiss", "", "Show Code"] ["OK", "Cancel", "Show Code"] end end ret = TkDialog_Demo1.new('message_config'=>{'wraplength'=>'4i'}).value case ret when 0 print "You pressed OK\n" when 1 print "You pressed Cancel\n" when 2 showCode 'dialog1' end ================================================ FILE: ext/tk/sample/demos-en/dialog2.rb ================================================ # # a dialog box with a global grab (called by 'widget') # class TkDialog_Demo2 < TkDialog ############### private ############### def title "Dialog with global grab" end def message "This dialog box uses a global grab, so it prevents you from interacting with anything on your display until you invoke one of the buttons below. Global grabs are almost always a bad idea; don't use them unless you're truly desperate." end def bitmap 'info' end def default_button 0 end def buttons ["OK", "Cancel", "Show Code"] end end ret = TkDialog_Demo2.new('message_config'=>{'wraplength'=>'4i'}, 'prev_command'=>proc{|dialog| Tk.after 100, proc{dialog.grab('global')} }).value case ret when 0 print "\You pressed OK\n" when 1 print "You pressed Cancel\n" when 2 showCode 'dialog2' end ================================================ FILE: ext/tk/sample/demos-en/doc.org/README ================================================ This directory contains a collection of demonstration programs that are translated into Japanese. You need to use a Japanized "wish" to see these Japanese-translated demonstration programs. You also need to put this directory ("demos.jp") at the next to "demos" since some of the programs refer to the image files at "demos". Please refer to the README file at "demos" for more detail. ================================================ FILE: ext/tk/sample/demos-en/doc.org/README.JP ================================================ This directory contains "widget" demo for the Japanized Tcl7.6/Tk4.2. Most of the messages in the original are translated to Japanese. But other tools in this directory are not translated. Following 2 kanji fonts are defined at the beginning of the file "widget." -*--24-*-jisx0208.1983-0 -*--16-*-jisx0208.1983-0 These fonts are all part of the core distribution of X11R5, so if you are running X11R5, you don't have to modify the file. But if you don't have these fonts, replace them with appropriate ones. "-*--14-*-jisx0208.1983-0" will be a good choice. ================================================ FILE: ext/tk/sample/demos-en/doc.org/README.tk80 ================================================ This directory contains a collection of programs to demonstrate the features of the Tk toolkit. The programs are all scripts for "wish", a windowing shell. If wish has been installed in /usr/local then you can invoke any of the programs in this directory just by typing its file name to your command shell. Otherwise invoke wish with the file as its first argument, e.g., "wish hello". The rest of this file contains a brief description of each program. Files with names ending in ".tcl" are procedure packages used by one or more of the demo programs; they can't be used as programs by themselves so they aren't described below. hello - Creates a single button; if you click on it, a message is typed and the application terminates. widget - Contains a collection of demonstrations of the widgets currently available in the Tk library. Most of the .tcl files are scripts for individual demos available through the "widget" program. ixset - A simple Tk-based wrapper for the "xset" program, which allows you to interactively query and set various X options such as mouse acceleration and bell volume. Thanks to Pierre David for contributing this example. rolodex - A mock-up of a simple rolodex application. It has much of the user interface for such an application but no back-end database. This program was written in response to Tom LaStrange's toolkit benchmark challenge. tcolor - A color editor. Allows you to edit colors in several different ways, and will also perform automatic updates using "send". rmt - Allows you to "hook-up" remotely to any Tk application on the display. Select an application with the menu, then just type commands: they'll go to that application. timer - Displays a seconds timer with start and stop buttons. Control-c and control-q cause it to exit. browse - A simple directory browser. Invoke it with and argument giving the name of the directory you'd like to browse. Double-click on files or subdirectories to browse them. Control-c and control-q cause the program to exit. sccs id = SCCS: @(#) README 1.3 96/02/16 10:49:14 ================================================ FILE: ext/tk/sample/demos-en/doc.org/license.terms ================================================ This software is copyrighted by the Regents of the University of California, Sun Microsystems, Inc., and other parties. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. ================================================ FILE: ext/tk/sample/demos-en/doc.org/license.terms.tk80 ================================================ This software is copyrighted by the Regents of the University of California, Sun Microsystems, Inc., and other parties. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. ================================================ FILE: ext/tk/sample/demos-en/entry1.rb ================================================ # # entry (no scrollbars) widget demo (called by 'widget') # # toplevel widget if defined?($entry1_demo) && $entry1_demo $entry1_demo.destroy $entry1_demo = nil end # demo toplevel widget $entry1_demo = TkToplevel.new {|w| title("Entry Demonstration (no scrollbars)") iconname("entry1") positionWindow(w) } base_frame = TkFrame.new($entry1_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '5i' justify 'left' text "Three different entries are displayed below. You can add characters by pointing, clicking and typing. The normal Motif editing characters are supported, along with many Emacs bindings. For example, Backspace and Control-h delete the character to the left of the insertion cursor and Delete and Control-d delete the chararacter to the right of the insertion cursor. For entries that are too large to fit in the window all at once, you can scan through the entries by dragging with mouse button2 pressed." } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $entry1_demo $entry1_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'entry1'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # e1 = TkEntry.new(base_frame, 'relief'=>'sunken') e2 = TkEntry.new(base_frame, 'relief'=>'sunken') e3 = TkEntry.new(base_frame, 'relief'=>'sunken') [e1,e2,e3].each{|w| w.pack('side'=>'top', 'padx'=>10, 'pady'=>5, 'fill'=>'x')} # e1.insert(0, 'Initial value') e2.insert('end', "This entry contains a long value, much too long ") e2.insert('end', "to fit in the window at one time, so long in fact ") e2.insert('end', "that you'll have to scan or scroll to see the end.") e2.insert('end', "") ================================================ FILE: ext/tk/sample/demos-en/entry2.rb ================================================ # entry2.rb # # This demonstration script is the same as the entry1.tcl script # except that it creates scrollbars for the entries. # # entry (with scrollbars) widget demo (called by 'widget') # # toplevel widget if defined?($entry2_demo) && $entry2_demo $entry2_demo.destroy $entry2_demo = nil end # demo toplevel widget $entry2_demo = TkToplevel.new {|w| title("Entry Demonstration (with scrollbars)") iconname("entry2") positionWindow(w) } base_frame = TkFrame.new($entry2_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '5i' justify 'left' text "Three different entries are displayed below, with a scrollbar for each entry. You can add characters by pointing, clicking and typing. The normal Motif editing characters are supported, along with many Emacs bindings. For example, Backspace and Control-h delete the character to the left of the insertion cursor and Delete and Control-d delete the chararacter to the right of the insertion cursor. For entries that are too large to fit in the window all at once, you can scan through the entries with the scrollbars, or by dragging with mouse button2 pressed." } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $entry2_demo $entry2_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'entry2'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame TkFrame.new(base_frame, 'borderwidth'=>10) {|w| # entry 1 s1 = TkScrollbar.new(w, 'relief'=>'sunken', 'orient'=>'horiz') e1 = TkEntry.new(w, 'relief'=>'sunken') { xscrollcommand proc{|first,last| s1.set first,last} } s1.command(proc{|*args| e1.xview(*args)}) e1.pack('side'=>'top', 'fill'=>'x') s1.pack('side'=>'top', 'fill'=>'x') # spacer TkFrame.new(w, 'width'=>20, 'height'=>10).pack('side'=>'top', 'fill'=>'x') # entry 2 s2 = TkScrollbar.new(w, 'relief'=>'sunken', 'orient'=>'horiz') e2 = TkEntry.new(w, 'relief'=>'sunken') { xscrollcommand proc{|first,last| s2.set first,last} } s2.command(proc{|*args| e2.xview(*args)}) e2.pack('side'=>'top', 'fill'=>'x') s2.pack('side'=>'top', 'fill'=>'x') # spacer TkFrame.new(w, 'width'=>20, 'height'=>10).pack('side'=>'top', 'fill'=>'x') # entry 3 s3 = TkScrollbar.new(w, 'relief'=>'sunken', 'orient'=>'horiz') e3 = TkEntry.new(w, 'relief'=>'sunken') { xscrollcommand proc{|first,last| s3.set first,last} } s3.command(proc{|*args| e3.xview(*args)}) e3.pack('side'=>'top', 'fill'=>'x') s3.pack('side'=>'top', 'fill'=>'x') # e1.insert(0, 'Initial value') e2.insert('end', "This entry contains a long value, much too long ") e2.insert('end', "to fit in the window at one time, so long in fact ") e2.insert('end', "that you'll have to scan or scroll to see the end.") e2.insert('end', "") }.pack('side'=>'top', 'fill'=>'x', 'expand'=>'yes') ================================================ FILE: ext/tk/sample/demos-en/entry3.rb ================================================ # entry3.rb -- # # This demonstration script creates several entry widgets whose # permitted input is constrained in some way. It also shows off a # password entry. # # based on Tcl/Tk8.4.4 widget demos if defined?($entry3_demo) && $entry3_demo $entry3_demo.destroy $entry3_demo = nil end $entry3_demo = TkToplevel.new {|w| title("Constrained Entry Demonstration") iconname("entry3") positionWindow(w) } base_frame = TkFrame.new($entry3_demo).pack(:fill=>:both, :expand=>true) TkLabel.new(base_frame, :font=>$font, :wraplength=>'5i', :justify=>:left, :text=><:top) Four different entries are displayed below. You can add characters \ by pointing, clicking and typing, though each is constrained in what \ it will accept. The first only accepts integers or the empty string \ (checking when focus leaves it) and will flash to indicate any \ problem. The second only accepts strings with fewer than ten \ characters and sounds the bell when an attempt to go over the limit \ is made. The third accepts US phone numbers, mapping letters to \ their digit equivalent and sounding the bell on encountering an \ invalid character or if trying to type over a character that is not \ a digit. The fourth is a password field that accepts up to eight \ characters (silently ignoring further ones), and displaying them as \ asterisk characters. EOL TkFrame.new(base_frame){|f| pack(:side=>:bottom, :fill=>:x, :pady=>'2m') TkButton.new(f, :text=>'Dismiss', :width=>15, :command=>proc{ $entry3_demo.destroy $entry3_demo = nil }).pack(:side=>:left, :expand=>true) TkButton.new(f, :text=>'See Code', :width=>15, :command=>proc{ showCode 'entry3' }).pack(:side=>:left, :expand=>true) } # focusAndFlash -- # Error handler for entry widgets that forces the focus onto the # widget and makes the widget flash by exchanging the foreground and # background colours at intervals of 200ms (i.e. at approximately # 2.5Hz). # # Arguments: # widget - entry widget to flash # fg - Initial foreground colour # bg - Initial background colour # count - Counter to control the number of times flashed def focusAndFlash(widget, fg, bg, count=5) return if count <= 0 if fg && !fg.empty? && bg && !bg.empty? TkTimer.new(200, count, proc{widget.configure(:foreground=>bg, :background=>fg)}, proc{widget.configure(:foreground=>fg, :background=>bg)} ).start else # TkTimer.new(150, 3){Tk.bell}.start Tk.bell TkTimer.new(200, count, proc{widget.configure(:foreground=>'white', :background=>'black')}, proc{widget.configure(:foreground=>'black', :background=>'white')} ).at_end{begin widget.configure(:foreground=>fg, :background=>bg) rescue # ignore end}.start end widget.focus(true) end l1 = TkLabelFrame.new(base_frame, :text=>"Integer Entry") TkEntry.new(l1, :validate=>:focus, :vcmd=>[ proc{|s| s == '' || /^[+-]?\d+$/ =~ s }, '%P' ]) {|e| fg = e.foreground bg = e.background invalidcommand [proc{|w| focusAndFlash(w, fg, bg)}, '%W'] pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m') } l2 = TkLabelFrame.new(base_frame, :text=>"Length-Constrained Entry") TkEntry.new(l2, :validate=>:key, :invcmd=>proc{Tk.bell}, :vcmd=>[proc{|s| s.length < 10}, '%P'] ).pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m') ### PHONE NUMBER ENTRY ### # Note that the source to this is quite a bit longer as the behaviour # demonstrated is a lot more ambitious than with the others. # Initial content for the third entry widget entry3content = TkVariable.new("1-(000)-000-0000") # Mapping from alphabetic characters to numbers. $phoneNumberMap = {} Hash[*(%w(abc 2 def 3 ghi 4 jkl 5 mno 6 pqrs 7 tuv 8 wxyz 9))].each{|chars, n| chars.split('').each{|c| $phoneNumberMap[c] = n $phoneNumberMap[c.upcase] = n } } # phoneSkipLeft -- # Skip over fixed characters in a phone-number string when moving left. # # Arguments: # widget - The entry widget containing the phone-number. def phoneSkipLeft(widget) idx = widget.index('insert') if idx == 8 # Skip back two extra characters widget.cursor = idx - 2 elsif idx == 7 || idx == 12 # Skip back one extra character widget.cursor = idx - 1 elsif idx <= 3 # Can't move any further Tk.bell Tk.callback_break end end # phoneSkipRight -- # Skip over fixed characters in a phone-number string when moving right. # # Arguments: # widget - The entry widget containing the phone-number. # add - Offset to add to index before calculation (used by validation.) def phoneSkipRight(widget, add = 0) idx = widget.index('insert') if (idx + add == 5) # Skip forward two extra characters widget.cursor = idx + 2 elsif (idx + add == 6 || idx + add == 10) # Skip forward one extra character widget.cursor = idx + 1 elsif (idx + add == 15 && add == 0) # Can't move any further Tk.bell Tk.callback_break end end # validatePhoneChange -- # Checks that the replacement (mapped to a digit) of the given # character in an entry widget at the given position will leave a # valid phone number in the widget. # # widget - entry widget to validate # vmode - The widget's validation mode # idx - The index where replacement is to occur # char - The character (or string, though that will always be # refused) to be overwritten at that point. def validatePhoneChange(widget, vmode, idx, char) return true if idx == nil Tk.after_idle(proc{widget.configure(:validate=>vmode, :invcmd=>proc{Tk.bell})}) if !(idx<3 || idx==6 || idx==7 || idx==11 || idx>15) && char =~ /[0-9A-Za-z]/ widget.delete(idx) widget.insert(idx, $phoneNumberMap[char] || char) Tk.after_idle(proc{phoneSkipRight(widget, -1)}) return true # Tk.update(true) # <- Don't work 'update' inter validation callback. # It depends on Tcl/Tk side (tested on Tcl/Tk8.5a1). end return false end l3 = TkLabelFrame.new(base_frame, :text=>"US Phone-Number Entry") TkEntry.new(l3, :validate=>:key, :invcmd=>proc{Tk.bell}, :textvariable=>entry3content, :vcmd=>[ proc{|w,v,i,s| validatePhoneChange(w,v,i,s)}, "%W %v %i %S" ]){|e| # Click to focus goes to the first editable character... bind('FocusIn', proc{|d,w| if d != "NotifyAncestor" w.cursor = 3 Tk.after_idle(proc{w.selection_clear}) end }, '%d %W') bind('Left', proc{|w| phoneSkipLeft(w)}, '%W') bind('Right', proc{|w| phoneSkipRight(w)}, '%W') pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m') } l4 = TkLabelFrame.new(base_frame, :text=>"Password Entry") TkEntry.new(l4, :validate=>:key, :show=>'*', :vcmd=>[ proc{|s| s.length <= 8}, '%P' ]).pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m') TkFrame.new(base_frame){|f| lower TkGrid.configure(l1, l2, :in=>f, :padx=>'3m', :pady=>'1m', :sticky=>:ew) TkGrid.configure(l3, l4, :in=>f, :padx=>'3m', :pady=>'1m', :sticky=>:ew) TkGrid.columnconfigure(f, [0,1], :uniform=>1) pack(:fill=>:both, :expand=>true) } ================================================ FILE: ext/tk/sample/demos-en/filebox.rb ================================================ # filebox.rb # # This demonstration script prompts the user to select a file.# # widget demo prompts the user to select a file (called by 'widget') # # toplevel widget if defined?($filebox_demo) && $filebox_demo $filebox_demo.destroy $filebox_demo = nil end # demo toplevel widget $filebox_demo = TkToplevel.new {|w| title("File Selection Dialogs") iconname("filebox") positionWindow(w) } base_frame = TkFrame.new($filebox_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left', 'text'=>"Enter a file name in the entry box or click on the \"Browse\" buttons to select a file name using the file selection dialog.").pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $filebox_demo $filebox_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'filebox'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame ['open', 'save'].each{|type| TkFrame.new(base_frame) {|f| TkLabel.new(f, 'text'=>"Select a file to #{type}: ", 'anchor'=>'e')\ .pack('side'=>'left') TkEntry.new(f, 'width'=>20) {|e| pack('side'=>'left', 'expand'=>'yes', 'fill'=>'x') TkButton.new(f, 'text'=>'Browse ...', 'command'=>proc{fileDialog base_frame,e,type})\ .pack('side'=>'left') } pack('fill'=>'x', 'padx'=>'1c', 'pady'=>3) } } $tk_strictMotif = TkVarAccess.new('tk_strictMotif') if ($tk_platform['platform'] == 'unix') TkCheckButton.new(base_frame, 'text'=>'Use Motif Style Dialog', 'variable'=>$tk_strictMotif, 'onvalue'=>1, 'offvalue'=>0 ).pack('anchor'=>'c') end def fileDialog(w,ent,operation) # Type names Extension(s) Mac File Type(s) # #-------------------------------------------------------- types = [ ['Text files', ['.txt','.doc'] ], ['Text files', [], 'TEXT' ], ['Ruby Scripts', ['.rb'], 'TEXT' ], ['Tcl Scripts', ['.tcl'], 'TEXT' ], ['C Source Files', ['.c','.h'] ], ['All Source Files', ['.rb','.tcl','.c','.h'] ], ['Image Files', ['.gif'] ], ['Image Files', ['.jpeg','.jpg'] ], ['Image Files', [], ['GIFF','JPEG']], ['All files', '*' ] ] if operation == 'open' file = Tk.getOpenFile('filetypes'=>types, 'parent'=>w) else file = Tk.getSaveFile('filetypes'=>types, 'parent'=>w, 'initialfile'=>'Untitled', 'defaultextension'=>'.txt') end if file != "" ent.delete 0, 'end' ent.insert 0, file # ent.xview 'end' Tk.update_idletasks # need this for Tk::Tile::Entry # (to find right position of 'xview'). ent.xview(ent.index('end')) end end ================================================ FILE: ext/tk/sample/demos-en/floor.rb ================================================ # floor.rb # # This demonstration script creates a canvas widet that displays the # floorplan for DEC's Western Research Laboratory. # # floorDisplay widget demo (called by 'widget') # # floorDisplay -- # Recreate the floorplan display in the canvas given by "w". The # floor given by "active" is displayed on top with its office structure # visible. # # Arguments: # w - Name of the canvas window. # active - Number of active floor (1, 2, or 3). def floorDisplay(w,active) return if $activeFloor == active w.delete('all') $activeFloor = active # First go through the three floors, displaying the backgrounds for # each floor. floor_bg1(w,$floor_colors['bg1'],$floor_colors['outline1']) floor_bg2(w,$floor_colors['bg2'],$floor_colors['outline2']) floor_bg3(w,$floor_colors['bg3'],$floor_colors['outline3']) # Raise the background for the active floor so that it's on top. w.raise("floor#{active}") # Create a dummy item just to mark this point in the display list, # so we can insert highlights here. TkcRectangle.new(w,0,100,1,101, 'fill'=>'', 'outline'=>'', 'tags'=>'marker') # Add the walls and labels for the active floor, along with # transparent polygons that define the rooms on the floor. # Make sure that the room polygons are on top. $floorLabels.clear $floorItems.clear send("floor_fg#{active}", w, $floor_colors['offices']) w.raise('room') # Offset the floors diagonally from each other. w.move('floor1', '2c', '2c') w.move('floor2', '1c', '1c') # Create items for the room entry and its label. TkcWindow.new(w, 600, 100, 'anchor'=>'w', 'window'=>$floor_entry) TkcText.new(w, 600, 100, 'anchor'=>'e', 'text'=>"Room: ") w['scrollregion'] = w.bbox('all') end # newRoom -- # This method is invoked whenever the mouse enters a room # in the floorplan. It changes tags so that the current room is # highlighted. # # Arguments: # w - The name of the canvas window. def newRoom(w) id = w.find_withtag('current')[0] $currentRoom.value = $floorLabels[id.id] if id != "" Tk.update(true) end # roomChanged -- # This method is invoked whenever the currentRoom variable changes. # It highlights the current room and unhighlights any previous room. # # Arguments: # w - The canvas window displaying the floorplan. # args - Not used. def roomChanged(w,*args) w.delete('highlight') item = $floorItems[$currentRoom.value] return if item == nil new = TkcPolygon.new(w, *(w.coords(item))) new.configure('fill'=>$floor_colors['active'], 'tags'=>'highlight') w.raise(new, 'marker') end # floor_bg1 -- # This method represents part of the floorplan database. When # invoked, it instantiates the background information for the first # floor. # # Arguments: # w - The canvas window. # fill - Fill color to use for the floor's background. # outline - Color to use for the floor's outline. def floor_bg1(w,fill,outline) TkcPolygon.new(w,347,80,349,82,351,84,353,85,363,92,375,99,386,104, 386,129,398,129,398,162,484,162,484,129,559,129,559,133,725, 133,725,129,802,129,802,389,644,389,644,391,559,391,559,327, 508,327,508,311,484,311,484,278,395,278,395,288,400,288,404, 288,409,290,413,292,418,297,421,302,422,309,421,318,417,325, 411,330,405,332,397,333,344,333,340,334,336,336,335,338,332, 342,331,347,332,351,334,354,336,357,341,359,340,360,335,363, 331,365,326,366,304,366,304,355,258,355,258,387,60,387,60,391, 0,391,0,337,3,337,3,114,8,114,8,25,30,25,30,5,93,5,98,5,104,7, 110,10,116,16,119,20,122,28,123,32,123,68,220,68,220,34,221, 22,223,17,227,13,231,8,236,4,242,2,246,0,260,0,283,1,300,5, 321,14,335,22,348,25,365,29,363,39,358,48,352,56,337,70, 344,76,347,80, 'tags'=>['floor1','bg'], 'fill'=>fill) TkcLine.new(w,386,129,398,129, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,258,355,258,387, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,60,387,60,391, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,0,337,0,391, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,60,391,0,391, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,3,114,3,337, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,258,387,60,387, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,484,162,398,162, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,398,162,398,129, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,484,278,484,311, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,484,311,508,311, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,508,327,508,311, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,559,327,508,327, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,644,391,559,391, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,644,389,644,391, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,559,129,484,129, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,484,162,484,129, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,725,133,559,133, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,559,129,559,133, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,725,129,802,129, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,802,389,802,129, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,3,337,0,337, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,559,391,559,327, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,802,389,644,389, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,725,133,725,129, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,8,25,8,114, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,8,114,3,114, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,30,25,8,25, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,484,278,395,278, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,30,25,30,5, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,93,5,30,5, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,98,5,93,5, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,104,7,98,5, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,110,10,104,7, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,116,16,110,10, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,119,20,116,16, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,122,28,119,20, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,123,32,122,28, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,123,68,123,32, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,220,68,123,68, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,386,129,386,104, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,386,104,375,99, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,375,99,363,92, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,353,85,363,92, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,220,68,220,34, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,337,70,352,56, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,352,56,358,48, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,358,48,363,39, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,363,39,365,29, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,365,29,348,25, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,348,25,335,22, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,335,22,321,14, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,321,14,300,5, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,300,5,283,1, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,283,1,260,0, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,260,0,246,0, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,246,0,242,2, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,242,2,236,4, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,236,4,231,8, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,231,8,227,13, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,223,17,227,13, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,221,22,223,17, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,220,34,221,22, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,340,360,335,363, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,335,363,331,365, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,331,365,326,366, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,326,366,304,366, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,304,355,304,366, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,395,288,400,288, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,404,288,400,288, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,409,290,404,288, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,413,292,409,290, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,418,297,413,292, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,421,302,418,297, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,422,309,421,302, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,421,318,422,309, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,421,318,417,325, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,417,325,411,330, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,411,330,405,332, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,405,332,397,333, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,397,333,344,333, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,344,333,340,334, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,340,334,336,336, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,336,336,335,338, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,335,338,332,342, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,331,347,332,342, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,332,351,331,347, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,334,354,332,351, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,336,357,334,354, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,341,359,336,357, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,341,359,340,360, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,395,288,395,278, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,304,355,258,355, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,347,80,344,76, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,344,76,337,70, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,349,82,347,80, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,351,84,349,82, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,353,85,351,84, 'fill'=>outline, 'tags'=>['floor1','bg']) end # floor_bg2 -- # This method represents part of the floorplan database. When # invoked, it instantiates the background information for the first # floor. # # Arguments: # w - The canvas window. # fill - Fill color to use for the floor's background. # outline - Color to use for the floor's outline. def floor_bg2(w,fill,outline) TkcPolygon.new(w,559,129,484,129,484,162,398,162,398,129,315,129, 315,133,176,133,176,129,96,129,96,133,3,133,3,339,0,339,0,391, 60,391,60,387,258,387,258,329,350,329,350,311,395,311,395,280, 484,280,484,311,508,311,508,327,558,327,558,391,644,391,644, 367,802,367,802,129,725,129,725,133,559,133,559,129, 'tags'=>['floor2','bg'], 'fill'=>fill) TkcLine.new(w,350,311,350,329, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,398,129,398,162, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,802,367,802,129, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,802,129,725,129, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,725,133,725,129, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,559,129,559,133, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,559,133,725,133, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,484,162,484,129, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,559,129,484,129, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,802,367,644,367, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,644,367,644,391, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,644,391,558,391, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,558,327,558,391, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,558,327,508,327, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,508,327,508,311, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,484,311,508,311, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,484,280,484,311, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,398,162,484,162, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,484,280,395,280, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,395,280,395,311, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,258,387,60,387, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,3,133,3,339, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,3,339,0,339, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,60,391,0,391, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,0,339,0,391, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,60,387,60,391, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,258,329,258,387, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,350,329,258,329, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,395,311,350,311, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,398,129,315,129, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,176,133,315,133, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,176,129,96,129, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,3,133,96,133, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,315,133,315,129, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,176,133,176,129, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,96,133,96,129, 'fill'=>outline, 'tags'=>['floor2','bg']) end # floor_bg3 -- # This method represents part of the floorplan database. When # invoked, it instantiates the background information for the first # floor. # # Arguments: # w - The canvas window. # fill - Fill color to use for the floor's background. # outline - Color to use for the floor's outline. def floor_bg3(w,fill,outline) TkcPolygon.new(w,159,300,107,300,107,248,159,248,159,129,96,129,96, 133,21,133,21,331,0,331,0,391,60,391,60,370,159,370,159,300, 'tags'=>['floor3','bg'], 'fill'=>fill) TkcPolygon.new(w,258,370,258,329,350,329,350,311,399,311,399,129, 315,129,315,133,176,133,176,129,159,129,159,370,258,370, 'tags'=>['floor3','bg'], 'fill'=>fill) TkcLine.new(w,96,133,96,129, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,176,129,96,129, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,176,129,176,133, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,315,133,176,133, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,315,133,315,129, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,399,129,315,129, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,399,311,399,129, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,399,311,350,311, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,350,329,350,311, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,350,329,258,329, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,258,370,258,329, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,60,370,258,370, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,60,370,60,391, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,60,391,0,391, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,0,391,0,331, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,21,331,0,331, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,21,331,21,133, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,96,133,21,133, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,107,300,159,300,159,248,107,248,107,300, 'fill'=>outline, 'tags'=>['floor3','bg']) end # floor_fg1 -- # This method represents part of the floorplan database. When # invoked, it instantiates the foreground information for the first # floor (office outlines and numbers). # # Arguments: # w - The canvas window. # color - Color to use for drawing foreground information. def floor_fg1(w,color) i = TkcPolygon.new(w,375,246,375,172,341,172,341,246, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '101' $floorItems['101'] = i TkcText.new(w,358,209, 'text'=>'101', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,307,240,339,240,339,206,307,206, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'Pub Lift1' $floorItems['Pub Lift1'] = i TkcText.new(w,323,223, 'text'=>'Pub Lift1', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,339,205,307,205,307,171,339,171, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'Priv Lift1' $floorItems['Priv Lift1'] = i TkcText.new(w,323,188, 'text'=>'Priv Lift1', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,42,389,42,337,1,337,1,389, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '110' $floorItems['110'] = i TkcText.new(w,21.5,363, 'text'=>'110', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,59,389,59,385,90,385,90,337,44,337,44,389, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '109' $floorItems['109'] = i TkcText.new(w,67,363, 'text'=>'109', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,51,300,51,253,6,253,6,300, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '111' $floorItems['111'] = i TkcText.new(w,28.5,276.5, 'text'=>'111', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,98,248,98,309,79,309,79,248, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '117B' $floorItems['117B'] = i TkcText.new(w,88.5,278.5, 'text'=>'117B', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,51,251,51,204,6,204,6,251, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '112' $floorItems['112'] = i TkcText.new(w,28.5,227.5, 'text'=>'112', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,6,156,51,156,51,203,6,203, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '113' $floorItems['113'] = i TkcText.new(w,28.5,179.5, 'text'=>'113', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,85,169,79,169,79,192,85,192, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '117A' $floorItems['117A'] = i TkcText.new(w,82,180.5, 'text'=>'117A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,77,302,77,168,53,168,53,302, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '117' $floorItems['117'] = i TkcText.new(w,65,235, 'text'=>'117', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,51,155,51,115,6,115,6,155, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '114' $floorItems['114'] = i TkcText.new(w,28.5,135, 'text'=>'114', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,95,115,53,115,53,168,95,168, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '115' $floorItems['115'] = i TkcText.new(w,74,141.5, 'text'=>'115', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,87,113,87,27,10,27,10,113, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '116' $floorItems['116'] = i TkcText.new(w,48.5,70, 'text'=>'116', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,89,91,128,91,128,113,89,131, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '118' $floorItems['118'] = i TkcText.new(w,108.5,102, 'text'=>'118', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,178,128,178,132,216,132,216,91, 163,91,163,112,149,112,149,128, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '120' $floorItems['120'] = i TkcText.new(w,189.5,111.5, 'text'=>'120', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,79,193,87,193,87,169,136,169,136,192, 156,192,156,169,175,169,175,246,79,246, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '122' $floorItems['122'] = i TkcText.new(w,131,207.5, 'text'=>'122', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,138,169,154,169,154,191,138,191, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '121' $floorItems['121'] = i TkcText.new(w,146,180, 'text'=>'121', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,99,300,126,300,126,309,99,309, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '106A' $floorItems['106A'] = i TkcText.new(w,112.5,304.5, 'text'=>'106A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,128,299,128,309,150,309,150,248,99,248,99,299, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '105' $floorItems['105'] = i TkcText.new(w,124.5,278.5, 'text'=>'105', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,174,309,174,300,152,300,152,309, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '106B' $floorItems['106B'] = i TkcText.new(w,163,304.5, 'text'=>'106B', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,176,299,176,309,216,309,216,248,152,248,152,299, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '104' $floorItems['104'] = i TkcText.new(w,184,278.5, 'text'=>'104', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,138,385,138,337,91,337,91,385, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '108' $floorItems['108'] = i TkcText.new(w,114.5,361, 'text'=>'108', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,256,337,140,337,140,385,256,385, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '107' $floorItems['107'] = i TkcText.new(w,198,361, 'text'=>'107', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,300,353,300,329,260,329,260,353, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'Smoking' $floorItems['Smoking'] = i TkcText.new(w,280,341, 'text'=>'Smoking', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,314,135,314,170,306,170,306,246,177,246,177,135, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '123' $floorItems['123'] = i TkcText.new(w,245.5,190.5, 'text'=>'123', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,217,248,301,248,301,326,257,326,257,310,217,310, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '103' $floorItems['103'] = i TkcText.new(w,259,287, 'text'=>'103', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,396,188,377,188,377,169,316,169,316,131,396,131, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '124' $floorItems['124'] = i TkcText.new(w,356,150, 'text'=>'124', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,397,226,407,226,407,189,377,189,377,246,397,246, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '125' $floorItems['125'] = i TkcText.new(w,392,217.5, 'text'=>'125', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,399,187,409,187,409,207,474,207,474,164,399,164, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '126' $floorItems['126'] = i TkcText.new(w,436.5,185.5, 'text'=>'126', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,409,209,409,229,399,229,399,253, 486,253,486,239,474,239,474,209, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '127' $floorItems['127'] = i TkcText.new(w,436.5,'231', 'text'=>'127', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,501,164,501,174,495,174,495,188, 490,188,490,204,476,204,476,164, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'MShower' $floorItems['MShower'] = i TkcText.new(w,488.5,'184', 'text'=>'MShower', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,497,176,513,176,513,204,492,204,492,190,497,190, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'Closet' $floorItems['Closet'] = i TkcText.new(w,502.5,190, 'text'=>'Closet', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,476,237,476,206,513,206,513,254,488,254,488,237, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'WShower' $floorItems['WShower'] = i TkcText.new(w,494.5,230, 'text'=>'WShower', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,486,131,558,131,558,135,724,135,724,166, 697,166,697,275,553,275,531,254,515,254, 515,174,503,174,503,161,486,161, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '130' $floorItems['130'] = i TkcText.new(w,638.5,205, 'text'=>'130', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,308,242,339,242,339,248,342,248, 342,246,397,246,397,276,393,276, 393,309,300,309,300,248,308,248, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '102' $floorItems['102'] = i TkcText.new(w,367.5,278.5, 'text'=>'102', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,397,255,486,255,486,276,397,276, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '128' $floorItems['128'] = i TkcText.new(w,441.5,265.5, 'text'=>'128', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,510,309,486,309,486,255,530,255, 552,277,561,277,561,325,510,325, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '129' $floorItems['129'] = i TkcText.new(w,535.5,293, 'text'=>'129', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,696,281,740,281,740,387,642,387, 642,389,561,389,561,277,696,277, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '133' $floorItems['133'] = i TkcText.new(w,628.5,335, 'text'=>'133', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,742,387,742,281,800,281,800,387, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '132' $floorItems['132'] = i TkcText.new(w,771,334, 'text'=>'132', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,800,168,800,280,699,280,699,168, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '134' $floorItems['134'] = i TkcText.new(w,749.5,224, 'text'=>'134', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,726,131,726,166,800,166,800,131, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '135' $floorItems['135'] = i TkcText.new(w,763,148.5, 'text'=>'135', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,340,360,335,363,331,365,326,366,304,366, 304,312,396,312,396,288,400,288,404,288, 409,290,413,292,418,297,421,302,422,309, 421,318,417,325,411,330,405,332,397,333, 344,333,340,334,336,336,335,338,332,342, 331,347,332,351,334,354,336,357,341,359, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'Ramona Stair' $floorItems['Ramona Stair'] = i TkcText.new(w,368,323, 'text'=>'Ramona Stair', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,30,23,30,5,93,5,98,5,104,7,110,10,116,16,119,20, 122,28,123,32,123,68,220,68,220,87,90,87,90,23, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'University Stair' $floorItems['University Stair'] = i TkcText.new(w,155,77.5, 'text'=>'University Stair', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,282,37,295,40,312,49,323,56,337,70,352,56, 358,48,363,39,365,29,348,25,335,22,321,14, 300,5,283,1,260,0,246,0,242,2,236,4,231,8, 227,13,223,17,221,22,220,34,260,34, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'Plaza Stair' $floorItems['Plaza Stair'] = i TkcText.new(w,317.5,28.5, 'text'=>'Plaza Stair', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,220,34,260,34,282,37,295,40,312,49, 323,56,337,70,350,83,365,94,377,100, 386,104,386,128,220,128, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'Plaza Deck' $floorItems['Plaza Deck'] = i TkcText.new(w,303,81, 'text'=>'Plaza Deck', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,257,336,77,336,6,336,6,301,77,301,77,310,257,310, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '106' $floorItems['106'] = i TkcText.new(w,131.5,318.5, 'text'=>'106', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,146,110,162,110,162,91,130,91,130,115,95,115, 95,128,114,128,114,151,157,151,157,153,112,153, 112,130,97,130,97,168,175,168,175,131,146,131, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '119' $floorItems['119'] = i TkcText.new(w,143.5,133, 'text'=>'119', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) TkcLine.new(w,155,191,155,189, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,155,177,155,169, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,96,129,96,169, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,78,169,176,169, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,176,247,176,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,340,206,307,206, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,340,187,340,170, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,340,210,340,201, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,340,247,340,224, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,340,241,307,241, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,376,246,376,170, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,307,247,307,170, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,376,170,307,170, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,315,129,315,170, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,147,129,176,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,202,133,176,133, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,398,129,315,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,258,352,258,387, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,60,387,60,391, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,0,337,0,391, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,60,391,0,391, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,3,114,3,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,258,387,60,387, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,52,237,52,273, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,52,189,52,225, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,52,140,52,177, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,395,306,395,311, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,531,254,398,254, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,475,178,475,238, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,502,162,398,162, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,398,129,398,188, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,383,188,376,188, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,408,188,408,194, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,398,227,398,254, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,408,227,398,227, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,408,222,408,227, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,408,206,408,210, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,408,208,475,208, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,484,278,484,311, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,484,311,508,311, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,508,327,508,311, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,559,327,508,327, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,644,391,559,391, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,644,389,644,391, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,514,205,475,205, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,496,189,496,187, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,559,129,484,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,484,162,484,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,725,133,559,133, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,559,129,559,133, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,725,149,725,167, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,725,129,802,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,802,389,802,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,739,167,802,167, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,396,188,408,188, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,0,337,9,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,58,337,21,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,43,391,43,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,105,337,75,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,91,387,91,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,154,337,117,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,139,387,139,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,227,337,166,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,258,337,251,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,258,328,302,328, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,302,355,302,311, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,395,311,302,311, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,484,278,395,278, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,395,294,395,278, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,473,278,473,275, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,473,256,473,254, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,533,257,531,254, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,553,276,551,274, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,698,276,553,276, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,559,391,559,327, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,802,389,644,389, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,741,314,741,389, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,698,280,698,167, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,707,280,698,280, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,802,280,731,280, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,741,280,741,302, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,698,167,727,167, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,725,137,725,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,514,254,514,175, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,496,175,514,175, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,502,175,502,162, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,475,166,475,162, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,496,176,496,175, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,491,189,496,189, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,491,205,491,189, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,487,238,475,238, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,487,240,487,238, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,487,252,487,254, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,315,133,304,133, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,256,133,280,133, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,78,247,270,247, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,307,247,294,247, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,214,133,232,133, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,217,247,217,266, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,217,309,217,291, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,217,309,172,309, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,154,309,148,309, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,175,300,175,309, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,151,300,175,300, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,151,247,151,309, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,78,237,78,265, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,78,286,78,309, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,106,309,78,309, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,130,309,125,309, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,99,309,99,247, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,127,299,99,299, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,127,309,127,299, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,155,191,137,191, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,137,169,137,191, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,78,171,78,169, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,78,190,78,218, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,86,192,86,169, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,86,192,78,192, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,52,301,3,301, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,52,286,52,301, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,52,252,3,252, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,52,203,3,203, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,3,156,52,156, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,8,25,8,114, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,63,114,3,114, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,75,114,97,114, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,108,114,129,114, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,129,114,129,89, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,52,114,52,128, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,132,89,88,89, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,88,25,88,89, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,88,114,88,89, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,218,89,144,89, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,147,111,147,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,162,111,147,111, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,162,109,162,111, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,162,96,162,89, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,218,89,218,94, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,218,89,218,119, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,8,25,88,25, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,258,337,258,328, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,113,129,96,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,302,355,258,355, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,386,104,386,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,377,100,386,104, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,365,94,377,100, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,350,83,365,94, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,337,70,350,83, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,337,70,323,56, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,312,49,323,56, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,295,40,312,49, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,282,37,295,40, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,260,34,282,37, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,253,34,260,34, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,386,128,386,104, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,113,152,156,152, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,113,152,156,152, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,113,152,113,129, 'fill'=>color, 'tags'=>['floor1','wall']) end # floor_fg2 -- # This method represents part of the floorplan database. When # invoked, it instantiates the foreground information for the second # floor (office outlines and numbers). # # Arguments: # w - The canvas window. # color - Color to use for drawing foreground information. def floor_fg2(w,color) i = TkcPolygon.new(w,748,188,755,188,755,205,758,205,758,222, 800,222,800,168,748,168, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '238' $floorItems['238'] = i TkcText.new(w,774,195, 'text'=>'238', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,726,188,746,188,746,166,800,166,800,131,726,131, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '237' $floorItems['237'] = i TkcText.new(w,763,148.5, 'text'=>'237', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,497,187,497,204,559,204,559,324,641,324, 643,324,643,291,641,291,641,205,696,205, 696,291,694,291,694,314,715,314,715,291, 715,205,755,205,755,190,724,190,724,187, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '246' $floorItems['246'] = i TkcText.new(w,600,264, 'text'=>'246', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,694,279,643,279,643,314,694,314, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '247' $floorItems['247'] = i TkcText.new(w,668.5,296.5, 'text'=>'247', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,232,250,308,250,308,242,339,242,339,246, 397,246,397,255,476,255,476,250,482,250,559,250, 559,274,482,274,482,278,396,278,396,274,232,274, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '202' $floorItems['202'] = i TkcText.new(w,285.5,260, 'text'=>'202', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,53,228,53,338,176,338,233,338,233,196, 306,196,306,180,175,180,175,169,156,169, 156,196,176,196,176,228, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '206' $floorItems['206'] = i TkcText.new(w,143,267, 'text'=>'206', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,51,277,6,277,6,338,51,338, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '212' $floorItems['212'] = i TkcText.new(w,28.5,307.5, 'text'=>'212', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,557,276,486,276,486,309,510,309,510,325,557,325, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '245' $floorItems['245'] = i TkcText.new(w,521.5,300.5, 'text'=>'245', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,560,389,599,389,599,326,560,326, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '244' $floorItems['244'] = i TkcText.new(w,579.5,357.5, 'text'=>'244', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,601,389,601,326,643,326,643,389, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '243' $floorItems['243'] = i TkcText.new(w,622,357.5, 'text'=>'243', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,688,316,645,316,645,365,688,365, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '242' $floorItems['242'] = i TkcText.new(w,666.5,340.5, 'text'=>'242', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,802,367,759,367,759,226,802,226, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = 'Barbecue Deck' $floorItems['Barbecue Deck'] = i TkcText.new(w,780.5,296.5, 'text'=>'Barbecue Deck', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,755,262,755,314,717,314,717,262, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '240' $floorItems['240'] = i TkcText.new(w,736,288, 'text'=>'240', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,755,316,689,316,689,365,755,365, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '241' $floorItems['241'] = i TkcText.new(w,722,340.5, 'text'=>'241', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,755,206,717,206,717,261,755,261, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '239' $floorItems['239'] = i TkcText.new(w,736,233.5, 'text'=>'239', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,695,277,643,277,643,206,695,206, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '248' $floorItems['248'] = i TkcText.new(w,669,241.5, 'text'=>'248', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,676,135,676,185,724,185,724,135, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '236' $floorItems['236'] = i TkcText.new(w,700,160, 'text'=>'236', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,675,135,635,135,635,145,628,145,628,185,675,185, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '235' $floorItems['235'] = i TkcText.new(w,651.5,160, 'text'=>'235', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,626,143,633,143,633,135,572,135, 572,143,579,143,579,185,626,185, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '234' $floorItems['234'] = i TkcText.new(w,606,160, 'text'=>'234', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,557,135,571,135,571,145,578,145, 578,185,527,185,527,131,557,131, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '233' $floorItems['233'] = i TkcText.new(w,552.5,158, 'text'=>'233', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,476,249,557,249,557,205,476,205, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '230' $floorItems['230'] = i TkcText.new(w,516.5,227, 'text'=>'230', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,476,164,486,164,486,131,525,131,525,185,476,185, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '232' $floorItems['232'] = i TkcText.new(w,500.5,158, 'text'=>'232', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,476,186,495,186,495,204,476,204, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '229' $floorItems['229'] = i TkcText.new(w,485.5,195, 'text'=>'229', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,474,207,409,207,409,187,399,187,399,164,474,164, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '227' $floorItems['227'] = i TkcText.new(w,436.5,185.5, 'text'=>'227', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,399,228,399,253,474,253,474,209,409,209,409,228, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '228' $floorItems['228'] = i TkcText.new(w,436.5,231, 'text'=>'228', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,397,246,397,226,407,226,407,189,377,189,377,246, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '226' $floorItems['226'] = i TkcText.new(w,392,217.5, 'text'=>'226', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,377,169,316,169,316,131,397,131,397,188,377,188, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '225' $floorItems['225'] = i TkcText.new(w,356.5,150, 'text'=>'225', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,234,198,306,198,306,249,234,249, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '224' $floorItems['224'] = i TkcText.new(w,270,223.5, 'text'=>'224', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,270,179,306,179,306,170,314,170,314,135,270,135, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '223' $floorItems['223'] = i TkcText.new(w,292,157, 'text'=>'223', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,268,179,221,179,221,135,268,135, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '222' $floorItems['222'] = i TkcText.new(w,244.5,157, 'text'=>'222', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,177,179,219,179,219,135,177,135, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '221' $floorItems['221'] = i TkcText.new(w,198,157, 'text'=>'221', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,299,327,349,327,349,284,341,284,341,276,299,276, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '204' $floorItems['204'] = i TkcText.new(w,324,301.5, 'text'=>'204', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,234,276,297,276,297,327,257,327,257,338,234,338, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '205' $floorItems['205'] = i TkcText.new(w,265.5,307, 'text'=>'205', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,256,385,256,340,212,340,212,385, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '207' $floorItems['207'] = i TkcText.new(w,234,362.5, 'text'=>'207', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,210,340,164,340,164,385,210,385, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '208' $floorItems['208'] = i TkcText.new(w,187,362.5, 'text'=>'208', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,115,340,162,340,162,385,115,385, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '209' $floorItems['209'] = i TkcText.new(w,138.5,362.5, 'text'=>'209', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,89,228,89,156,53,156,53,228, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '217' $floorItems['217'] = i TkcText.new(w,71,192, 'text'=>'217', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,89,169,97,169,97,190,89,190, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '217A' $floorItems['217A'] = i TkcText.new(w,93,179.5, 'text'=>'217A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,89,156,89,168,95,168,95,135,53,135,53,156, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '216' $floorItems['216'] = i TkcText.new(w,71,145.5, 'text'=>'216', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,51,179,51,135,6,135,6,179, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '215' $floorItems['215'] = i TkcText.new(w,28.5,157, 'text'=>'215', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,51,227,6,227,6,180,51,180, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '214' $floorItems['214'] = i TkcText.new(w,28.5,203.5, 'text'=>'214', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,51,275,6,275,6,229,51,229, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '213' $floorItems['213'] = i TkcText.new(w,28.5,252, 'text'=>'213', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,114,340,67,340,67,385,114,385, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '210' $floorItems['210'] = i TkcText.new(w,90.5,362.5, 'text'=>'210', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,59,389,59,385,65,385,65,340,1,340,1,389, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '211' $floorItems['211'] = i TkcText.new(w,33,364.5, 'text'=>'211', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,393,309,350,309,350,282,342,282,342,276,393,276, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '203' $floorItems['203'] = i TkcText.new(w,367.5,292.5, 'text'=>'203', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,99,191,91,191,91,226,174,226,174,198, 154,198,154,192,109,192,109,169,99,169, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '220' $floorItems['220'] = i TkcText.new(w,132.5,208.5, 'text'=>'220', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,339,205,307,205,307,171,339,171, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = 'Priv Lift2' $floorItems['Priv Lift2'] = i TkcText.new(w,323,188, 'text'=>'Priv Lift2', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,307,240,339,240,339,206,307,206, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = 'Pub Lift 2' $floorItems['Pub Lift 2'] = i TkcText.new(w,323,223, 'text'=>'Pub Lift 2', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,175,168,97,168,97,131,175,131, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '218' $floorItems['218'] = i TkcText.new(w,136,149.5, 'text'=>'218', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,154,191,111,191,111,169,154,169, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '219' $floorItems['219'] = i TkcText.new(w,132.5,180, 'text'=>'219', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,375,246,375,172,341,172,341,246, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '201' $floorItems['201'] = i TkcText.new(w,358,209, 'text'=>'201', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) TkcLine.new(w,641,186,678,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,757,350,757,367, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,634,133,634,144, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,634,144,627,144, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,572,133,572,144, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,572,144,579,144, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,398,129,398,162, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,174,197,175,197, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,175,197,175,227, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,757,206,757,221, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,396,188,408,188, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,727,189,725,189, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,747,167,802,167, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,747,167,747,189, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,755,189,739,189, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,769,224,757,224, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,802,224,802,129, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,802,129,725,129, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,725,189,725,129, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,725,186,690,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,676,133,676,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,627,144,627,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,629,186,593,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,579,144,579,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,559,129,559,133, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,725,133,559,133, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,484,162,484,129, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,559,129,484,129, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,526,129,526,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,540,186,581,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,528,186,523,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,511,186,475,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,496,190,496,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,496,205,496,202, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,475,205,527,205, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,558,205,539,205, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,558,205,558,249, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,558,249,475,249, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,662,206,642,206, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,695,206,675,206, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,695,278,642,278, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,642,291,642,206, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,695,291,695,206, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,716,208,716,206, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,757,206,716,206, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,757,221,757,224, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,793,224,802,224, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,757,262,716,262, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,716,220,716,264, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,716,315,716,276, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,757,315,703,315, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,757,325,757,224, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,757,367,644,367, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,689,367,689,315, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,647,315,644,315, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,659,315,691,315, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,600,325,600,391, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,627,325,644,325, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,644,391,644,315, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,615,325,575,325, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,644,391,558,391, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,563,325,558,325, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,558,391,558,314, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,558,327,508,327, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,558,275,484,275, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,558,302,558,275, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,508,327,508,311, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,484,311,508,311, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,484,275,484,311, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,475,208,408,208, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,408,206,408,210, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,408,222,408,227, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,408,227,398,227, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,398,227,398,254, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,408,188,408,194, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,383,188,376,188, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,398,188,398,162, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,398,162,484,162, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,475,162,475,254, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,398,254,475,254, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,484,280,395,280, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,395,311,395,275, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,307,197,293,197, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,278,197,233,197, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,233,197,233,249, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,307,179,284,179, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,233,249,278,249, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,269,179,269,133, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,220,179,220,133, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,155,191,110,191, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,90,190,98,190, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,98,169,98,190, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,52,133,52,165, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,52,214,52,177, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,52,226,52,262, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,52,274,52,276, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,234,275,234,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,226,339,258,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,211,387,211,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,214,339,177,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,258,387,60,387, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,3,133,3,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,165,339,129,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,117,339,80,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,68,339,59,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,0,339,46,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,60,391,0,391, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,0,339,0,391, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,60,387,60,391, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,258,329,258,387, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,350,329,258,329, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,395,311,350,311, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,398,129,315,129, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,176,133,315,133, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,176,129,96,129, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,3,133,96,133, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,66,387,66,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,115,387,115,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,163,387,163,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,234,275,276,275, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,288,275,309,275, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,298,275,298,329, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,341,283,350,283, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,321,275,341,275, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,375,275,395,275, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,315,129,315,170, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,376,170,307,170, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,307,250,307,170, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,376,245,376,170, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,340,241,307,241, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,340,245,340,224, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,340,210,340,201, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,340,187,340,170, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,340,206,307,206, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,293,250,307,250, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,271,179,238,179, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,226,179,195,179, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,176,129,176,179, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,182,179,176,179, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,174,169,176,169, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,162,169,90,169, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,96,169,96,129, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,175,227,90,227, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,90,190,90,227, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,52,179,3,179, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,52,228,3,228, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,52,276,3,276, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,155,177,155,169, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,110,191,110,169, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,155,189,155,197, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,350,283,350,329, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,162,197,155,197, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,341,275,341,283, 'fill'=>color, 'tags'=>['floor2','wall']) end # floor_fg3 -- # This method represents part of the floorplan database. When # invoked, it instantiates the foreground information for the third # floor (office outlines and numbers). # # Arguments: # w - The canvas window. # color - Color to use for drawing foreground information. def floor_fg3(w,color) i = TkcPolygon.new(w,89,228,89,180,70,180,70,228, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '316' $floorItems['316'] = i TkcText.new(w,79.5,204, 'text'=>'316', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,115,368,162,368,162,323,115,323, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '309' $floorItems['309'] = i TkcText.new(w,138.5,345.5, 'text'=>'309', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,164,323,164,368,211,368,211,323, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '308' $floorItems['308'] = i TkcText.new(w,187.5,345.5, 'text'=>'308', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,256,368,212,368,212,323,256,323, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '307' $floorItems['307'] = i TkcText.new(w,234,345.5, 'text'=>'307', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,244,276,297,276,297,327,260,327,260,321,244,321, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '305' $floorItems['305'] = i TkcText.new(w,270.5,301.5, 'text'=>'305', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,251,219,251,203,244,203,244,219, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '324B' $floorItems['324B'] = i TkcText.new(w,247.5,211, 'text'=>'324B', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,251,249,244,249,244,232,251,232, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '324A' $floorItems['324A'] = i TkcText.new(w,247.5,240.5, 'text'=>'324A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,223,135,223,179,177,179,177,135, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '320' $floorItems['320'] = i TkcText.new(w,200,157, 'text'=>'320', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,114,368,114,323,67,323,67,368, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '310' $floorItems['310'] = i TkcText.new(w,90.5,345.5, 'text'=>'310', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,23,277,23,321,68,321,68,277, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '312' $floorItems['312'] = i TkcText.new(w,45.5,299, 'text'=>'312', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,23,229,68,229,68,275,23,275, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '313' $floorItems['313'] = i TkcText.new(w,45.5,252, 'text'=>'313', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,68,227,23,227,23,180,68,180, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '314' $floorItems['314'] = i TkcText.new(w,40.5,203.5, 'text'=>'314', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,95,179,95,135,23,135,23,179, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '315' $floorItems['315'] = i TkcText.new(w,59,157, 'text'=>'315', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,99,226,99,204,91,204,91,226, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '316B' $floorItems['316B'] = i TkcText.new(w,95,215, 'text'=>'316B', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,91,202,99,202,99,180,91,180, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '316A' $floorItems['316A'] = i TkcText.new(w,95,191, 'text'=>'316A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,97,169,109,169,109,192,154,192,154,198, 174,198,174,226,101,226,101,179,97,179, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '319' $floorItems['319'] = i TkcText.new(w,141.5,209, 'text'=>'319', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,65,368,58,368,58,389,1,389,1,333,23,333,23,323,65,323, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '311' $floorItems['311'] = i TkcText.new(w,29.5,361, 'text'=>'311', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,154,191,111,191,111,169,154,169, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '318' $floorItems['318'] = i TkcText.new(w,132.5,180, 'text'=>'318', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,175,168,97,168,97,131,175,131, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '317' $floorItems['317'] = i TkcText.new(w,136,149.5, 'text'=>'317', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,274,194,274,221,306,221,306,194, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '323' $floorItems['323'] = i TkcText.new(w,290,207.5, 'text'=>'323', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,306,222,274,222,274,249,306,249, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '325' $floorItems['325'] = i TkcText.new(w,290,235.5, 'text'=>'325', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,263,179,224,179,224,135,263,135, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '321' $floorItems['321'] = i TkcText.new(w,243.5,157, 'text'=>'321', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,314,169,306,169,306,192,273,192, 264,181,264,135,314,135, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '322' $floorItems['322'] = i TkcText.new(w,293.5,163.5, 'text'=>'322', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,307,240,339,240,339,206,307,206, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = 'Pub Lift3' $floorItems['Pub Lift3'] = i TkcText.new(w,323,223, 'text'=>'Pub Lift3', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,339,205,307,205,307,171,339,171, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = 'Priv Lift3' $floorItems['Priv Lift3'] = i TkcText.new(w,323,188, 'text'=>'Priv Lift3', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,350,284,376,284,376,276,397,276,397,309,350,309, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '303' $floorItems['303'] = i TkcText.new(w,373.5,292.5, 'text'=>'303', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,272,203,272,249,252,249,252,230, 244,230,244,221,252,221,252,203, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '324' $floorItems['324'] = i TkcText.new(w,262,226, 'text'=>'324', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,299,276,299,327,349,327,349,284,341,284,341,276, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '304' $floorItems['304'] = i TkcText.new(w,324,301.5, 'text'=>'304', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,375,246,375,172,341,172,341,246, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '301' $floorItems['301'] = i TkcText.new(w,358,209, 'text'=>'301', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,397,246,377,246,377,185,397,185, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '327' $floorItems['327'] = i TkcText.new(w,387,215.5, 'text'=>'327', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,316,131,316,169,377,169,377,185,397,185,397,131, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '326' $floorItems['326'] = i TkcText.new(w,365.5,150, 'text'=>'326', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,308,251,242,251,242,274,342,274,342,282,375, 282, 375,274,397,274,397,248,339,248,339,242,308,242, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '302' $floorItems['302'] = i TkcText.new(w,319.5,261, 'text'=>'302', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,70,321,242,321,242,200,259,200,259,203,272,203, 272,193,263,180,242,180,175,180,175,169,156,169, 156,196,177,196,177,228,107,228,70,228,70,275,107,275, 107,248,160,248,160,301,107,301,107,275,70,275, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '306' $floorItems['306'] = i TkcText.new(w,200.5,284.5, 'text'=>'306', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) TkcLine.new(w,341,275,341,283, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,162,197,155,197, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,396,247,399,247, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,399,129,399,311, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,258,202,243,202, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,350,283,350,329, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,251,231,243,231, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,243,220,251,220, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,243,250,243,202, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,155,197,155,190, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,110,192,110,169, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,155,192,110,192, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,155,177,155,169, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,176,197,176,227, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,69,280,69,274, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,21,276,69,276, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,69,262,69,226, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,21,228,69,228, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,21,179,75,179, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,69,179,69,214, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,90,220,90,227, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,90,204,90,202, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,90,203,100,203, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,90,187,90,179, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,90,227,176,227, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,100,179,100,227, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,100,179,87,179, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,96,179,96,129, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,162,169,96,169, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,173,169,176,169, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,182,179,176,179, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,176,129,176,179, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,195,179,226,179, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,224,133,224,179, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,264,179,264,133, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,238,179,264,179, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,273,207,273,193, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,273,235,273,250, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,273,224,273,219, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,273,193,307,193, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,273,222,307,222, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,273,250,307,250, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,384,247,376,247, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,340,206,307,206, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,340,187,340,170, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,340,210,340,201, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,340,247,340,224, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,340,241,307,241, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,376,247,376,170, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,307,250,307,170, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,376,170,307,170, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,315,129,315,170, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,376,283,366,283, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,376,283,376,275, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,399,275,376,275, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,341,275,320,275, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,341,283,350,283, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,298,275,298,329, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,308,275,298,275, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,243,322,243,275, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,243,275,284,275, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,258,322,226,322, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,212,370,212,322, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,214,322,177,322, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,163,370,163,322, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,165,322,129,322, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,84,322,117,322, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,71,322,64,322, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,115,322,115,370, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,66,322,66,370, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,52,322,21,322, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,21,331,0,331, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,21,331,21,133, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,96,133,21,133, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,176,129,96,129, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,315,133,176,133, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,315,129,399,129, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,399,311,350,311, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,350,329,258,329, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,258,322,258,370, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,60,370,258,370, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,60,370,60,391, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,0,391,0,331, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,60,391,0,391, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,307,250,307,242, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,273,250,307,250, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,258,250,243,250, 'fill'=>color, 'tags'=>['floor3','wall']) end # Below is the "main program" that creates the floorplan demonstration. # toplevel widget if defined?($floor_demo) && $floor_demo $floor_demo.destroy $floor_demo = nil end # demo toplevel widget $floor_demo = TkToplevel.new {|w| title("Floorplan Canvas Demonstration") iconname("Floorplan") positionWindow(w) geometry('+20+20') minsize(100,100) } base_frame = TkFrame.new($floor_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'8i', 'justify'=>'left', 'text'=>"This window contains a canvas widget showing the floorplan of Digital Equipment Corporation's Western Research Laboratory. It has three levels. At any given time one of the levels is active, meaning that you can see its room structure. To activate a level, click the left mouse button anywhere on it. As the mouse moves over the active level, the room under the mouse lights up and its room number appears in the \"Room:\" entry. You can also type a room number in the entry and the room will light up."){ pack('side'=>'top') } # frame $floor_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $floor_demo $floor_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'floor'} }.pack('side'=>'left', 'expand'=>'yes') } $floor_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # $floorLabels = {} $floorItems = {} # canvas if $tk_version =~ /^4\.[01]/ $floor_canvas_frame = TkFrame.new(base_frame,'bd'=>2,'relief'=>'sunken', 'highlightthickness'=>2) $floor_canvas = TkCanvas.new($floor_canvas_frame, 'width'=>900, 'height'=>500, 'borderwidth'=>0, 'highlightthickness'=>0) {|c| TkScrollbar.new(base_frame, 'orient'=>'horiz', 'command'=>proc{|*args| c.xview(*args)}){|hs| c.xscrollcommand(proc{|first,last| hs.set first,last}) pack('side'=>'bottom', 'fill'=>'x') } TkScrollbar.new(base_frame, 'command'=>proc{|*args| c.yview(*args)}){|vs| c.yscrollcommand(proc{|first,last| vs.set first,last}) pack('side'=>'right', 'fill'=>'y') } } $floor_canvas_frame.pack('side'=>'top','fill'=>'both', 'expand'=>'yes') $floor_canvas.pack('expand'=>'yes', 'fill'=>'both') else TkFrame.new(base_frame) {|f| pack('side'=>'top', 'fill'=>'both', 'expand'=>'yes') h = TkScrollbar.new(f, 'highlightthickness'=>0, 'orient'=>'horizontal') v = TkScrollbar.new(f, 'highlightthickness'=>0, 'orient'=>'vertical') TkFrame.new(f, 'bd'=>2, 'relief'=>'sunken') {|f1| $floor_canvas = TkCanvas.new(f1, 'width'=>900, 'height'=>500, 'borderwidth'=>0, 'highlightthickness'=>0) { xscrollcommand(proc{|first,last| h.set first,last}) yscrollcommand(proc{|first,last| v.set first,last}) pack('expand'=>'yes', 'fill'=>'both') } grid('padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') } v.grid('padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>1, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') h.grid('padx'=>1, 'pady'=>1, 'row'=>1, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') TkGrid.rowconfigure(f, 0, 'weight'=>1, 'minsize'=>0) TkGrid.columnconfigure(f, 0, 'weight'=>1, 'minsize'=>0) pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1) v.command(proc{|*args| $floor_canvas.yview(*args)}) h.command(proc{|*args| $floor_canvas.xview(*args)}) } end # Create an entry for displaying and typing in current room. $currentRoom = TkVariable.new $floor_entry = TkEntry.new($floor_canvas, 'width'=>10, 'relief'=>'sunken', 'bd'=>2, 'textvariable'=>$currentRoom) # Choose colors, then fill in the floorplan. $floor_colors = {} if TkWinfo.depth($floor_canvas) > 1 $floor_colors['bg1'] = '#a9c1da' $floor_colors['outline1'] = '#77889a' $floor_colors['bg2'] = '#9ab0c6' $floor_colors['outline2'] = '#687786' $floor_colors['bg3'] = '#8ba0b3' $floor_colors['outline3'] = '#596673' $floor_colors['offices'] = 'Black' $floor_colors['active'] = '#c4d1df' else $floor_colors['bg1'] = 'white' $floor_colors['outline1'] = 'black' $floor_colors['bg2'] = 'white' $floor_colors['outline2'] = 'black' $floor_colors['bg3'] = 'white' $floor_colors['outline3'] = 'black' $floor_colors['offices'] = 'Black' $floor_colors['active'] = 'black' end $activeFloor = '' floorDisplay $floor_canvas,3 # Set up event bindings for canvas: $floor_canvas.itembind('floor1', '1', proc{floorDisplay $floor_canvas,1}) $floor_canvas.itembind('floor2', '1', proc{floorDisplay $floor_canvas,2}) $floor_canvas.itembind('floor3', '1', proc{floorDisplay $floor_canvas,3}) $floor_canvas.itembind('room', 'Enter', proc{newRoom $floor_canvas}) $floor_canvas.itembind('room', 'Leave', proc{$currentRoom.value = ''}) $floor_canvas.bind('2', proc{|x,y| $floor_canvas.scan_mark x,y}, '%x %y') $floor_canvas.bind('B2-Motion', proc{|x,y| $floor_canvas.scan_dragto x,y}, '%x %y') $floor_canvas.bind('Destroy', proc{$currentRoom.unset}) $currentRoom.value = '' $currentRoom.trace('w',proc{roomChanged $floor_canvas}) ================================================ FILE: ext/tk/sample/demos-en/floor2.rb ================================================ %# floor2.rb # # This demonstration script creates a canvas widet that displays the # floorplan for DEC's Western Research Laboratory. # # floorDisplay widget demo (called by 'widget') # # floorDisplay2 -- # Recreate the floorplan display in the canvas given by "w". The # floor given by "active" is displayed on top with its office structure # visible. # # Arguments: # w - Name of the canvas window. # active - Number of active floor (1, 2, or 3). def floorDisplay2(w,active) return if $activeFloor2 == active w.delete('all') $activeFloor2 = active # First go through the three floors, displaying the backgrounds for # each floor. floor2_bg1(w,$floor2_colors['bg1'],$floor2_colors['outline1']) floor2_bg2(w,$floor2_colors['bg2'],$floor2_colors['outline2']) floor2_bg3(w,$floor2_colors['bg3'],$floor2_colors['outline3']) # Raise the background for the active floor so that it's on top. w.raise("floor#{active}") # Create a dummy item just to mark this point in the display list, # so we can insert highlights here. w.create(TkcRectangle,0,100,1,101,'fill'=>'','outline'=>'','tags'=>'marker') # Add the walls and labels for the active floor, along with # transparent polygons that define the rooms on the floor. # Make sure that the room polygons are on top. $floorLabels2.clear $floorItems2.clear send("floor2_fg#{active}", w, $floor2_colors['offices']) w.raise('room') # Offset the floors diagonally from each other. w.move('floor1', '2c', '2c') w.move('floor2', '1c', '1c') # Create items for the room entry and its label. w.create(TkcWindow, 600, 100, 'anchor'=>'w', 'window'=>$floor2_entry) w.create(TkcText, 600, 100, 'anchor'=>'e', 'text'=>"Room: ") w['scrollregion'] = w.bbox('all') end # newRoom2 -- # This method is invoked whenever the mouse enters a room # in the floorplan. It changes tags so that the current room is # highlighted. # # Arguments: # w - The name of the canvas window. def newRoom2(w) id = w.find_withtag('current')[0] $currentRoom2.value = $floorLabels2[id.id] if id != "" Tk.update(true) end # roomChanged2 -- # This method is invoked whenever the currentRoom variable changes. # It highlights the current room and unhighlights any previous room. # # Arguments: # w - The canvas window displaying the floorplan. # args - Not used. def roomChanged2(w,*args) w.delete('highlight') item = $floorItems2[$currentRoom2.value] return if item == nil new = TkcPolygon.new(w, *(w.coords(item))) new.configure('fill'=>$floor2_colors['active'], 'tags'=>'highlight') w.raise(new, 'marker') end # floor2_bg1 -- # This method represents part of the floorplan database. When # invoked, it instantiates the background information for the first # floor. # # Arguments: # w - The canvas window. # fill - Fill color to use for the floor's background. # outline - Color to use for the floor's outline. def floor2_bg1(w,fill,outline) w.create(TkcPolygon,347,80,349,82,351,84,353,85,363,92,375,99,386,104, 386,129,398,129,398,162,484,162,484,129,559,129,559,133,725, 133,725,129,802,129,802,389,644,389,644,391,559,391,559,327, 508,327,508,311,484,311,484,278,395,278,395,288,400,288,404, 288,409,290,413,292,418,297,421,302,422,309,421,318,417,325, 411,330,405,332,397,333,344,333,340,334,336,336,335,338,332, 342,331,347,332,351,334,354,336,357,341,359,340,360,335,363, 331,365,326,366,304,366,304,355,258,355,258,387,60,387,60,391, 0,391,0,337,3,337,3,114,8,114,8,25,30,25,30,5,93,5,98,5,104,7, 110,10,116,16,119,20,122,28,123,32,123,68,220,68,220,34,221, 22,223,17,227,13,231,8,236,4,242,2,246,0,260,0,283,1,300,5, 321,14,335,22,348,25,365,29,363,39,358,48,352,56,337,70, 344,76,347,80, 'tags'=>['floor1','bg'], 'fill'=>fill) w.create(TkcLine,386,129,398,129, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,258,355,258,387, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,60,387,60,391, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,0,337,0,391, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,60,391,0,391, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,3,114,3,337, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,258,387,60,387, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,484,162,398,162, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,398,162,398,129, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,484,278,484,311, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,484,311,508,311, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,508,327,508,311, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,559,327,508,327, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,644,391,559,391, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,644,389,644,391, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,559,129,484,129, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,484,162,484,129, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,725,133,559,133, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,559,129,559,133, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,725,129,802,129, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,802,389,802,129, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,3,337,0,337, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,559,391,559,327, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,802,389,644,389, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,725,133,725,129, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,8,25,8,114, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,8,114,3,114, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,30,25,8,25, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,484,278,395,278, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,30,25,30,5, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,93,5,30,5, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,98,5,93,5, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,104,7,98,5, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,110,10,104,7, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,116,16,110,10, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,119,20,116,16, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,122,28,119,20, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,123,32,122,28, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,123,68,123,32, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,220,68,123,68, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,386,129,386,104, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,386,104,375,99, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,375,99,363,92, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,353,85,363,92, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,220,68,220,34, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,337,70,352,56, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,352,56,358,48, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,358,48,363,39, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,363,39,365,29, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,365,29,348,25, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,348,25,335,22, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,335,22,321,14, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,321,14,300,5, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,300,5,283,1, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,283,1,260,0, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,260,0,246,0, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,246,0,242,2, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,242,2,236,4, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,236,4,231,8, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,231,8,227,13, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,223,17,227,13, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,221,22,223,17, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,220,34,221,22, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,340,360,335,363, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,335,363,331,365, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,331,365,326,366, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,326,366,304,366, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,304,355,304,366, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,395,288,400,288, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,404,288,400,288, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,409,290,404,288, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,413,292,409,290, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,418,297,413,292, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,421,302,418,297, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,422,309,421,302, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,421,318,422,309, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,421,318,417,325, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,417,325,411,330, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,411,330,405,332, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,405,332,397,333, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,397,333,344,333, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,344,333,340,334, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,340,334,336,336, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,336,336,335,338, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,335,338,332,342, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,331,347,332,342, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,332,351,331,347, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,334,354,332,351, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,336,357,334,354, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,341,359,336,357, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,341,359,340,360, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,395,288,395,278, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,304,355,258,355, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,347,80,344,76, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,344,76,337,70, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,349,82,347,80, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,351,84,349,82, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,353,85,351,84, 'fill'=>outline, 'tags'=>['floor1','bg']) end # floor2_bg2 -- # This method represents part of the floorplan database. When # invoked, it instantiates the background information for the first # floor. # # Arguments: # w - The canvas window. # fill - Fill color to use for the floor's background. # outline - Color to use for the floor's outline. def floor2_bg2(w,fill,outline) w.create(TkcPolygon,559,129,484,129,484,162,398,162,398,129,315,129, 315,133,176,133,176,129,96,129,96,133,3,133,3,339,0,339,0,391, 60,391,60,387,258,387,258,329,350,329,350,311,395,311,395,280, 484,280,484,311,508,311,508,327,558,327,558,391,644,391,644, 367,802,367,802,129,725,129,725,133,559,133,559,129, 'tags'=>['floor2','bg'], 'fill'=>fill) w.create(TkcLine,350,311,350,329, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,398,129,398,162, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,802,367,802,129, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,802,129,725,129, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,725,133,725,129, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,559,129,559,133, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,559,133,725,133, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,484,162,484,129, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,559,129,484,129, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,802,367,644,367, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,644,367,644,391, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,644,391,558,391, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,558,327,558,391, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,558,327,508,327, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,508,327,508,311, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,484,311,508,311, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,484,280,484,311, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,398,162,484,162, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,484,280,395,280, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,395,280,395,311, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,258,387,60,387, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,3,133,3,339, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,3,339,0,339, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,60,391,0,391, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,0,339,0,391, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,60,387,60,391, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,258,329,258,387, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,350,329,258,329, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,395,311,350,311, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,398,129,315,129, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,176,133,315,133, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,176,129,96,129, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,3,133,96,133, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,315,133,315,129, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,176,133,176,129, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,96,133,96,129, 'fill'=>outline, 'tags'=>['floor2','bg']) end # floor2_bg3 -- # This method represents part of the floorplan database. When # invoked, it instantiates the background information for the first # floor. # # Arguments: # w - The canvas window. # fill - Fill color to use for the floor's background. # outline - Color to use for the floor's outline. def floor2_bg3(w,fill,outline) w.create(TkcPolygon,159,300,107,300,107,248,159,248,159,129,96,129,96, 133,21,133,21,331,0,331,0,391,60,391,60,370,159,370,159,300, 'tags'=>['floor3','bg'], 'fill'=>fill) w.create(TkcPolygon,258,370,258,329,350,329,350,311,399,311,399,129, 315,129,315,133,176,133,176,129,159,129,159,370,258,370, 'tags'=>['floor3','bg'], 'fill'=>fill) w.create(TkcLine,96,133,96,129, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,176,129,96,129, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,176,129,176,133, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,315,133,176,133, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,315,133,315,129, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,399,129,315,129, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,399,311,399,129, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,399,311,350,311, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,350,329,350,311, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,350,329,258,329, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,258,370,258,329, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,60,370,258,370, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,60,370,60,391, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,60,391,0,391, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,0,391,0,331, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,21,331,0,331, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,21,331,21,133, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,96,133,21,133, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,107,300,159,300,159,248,107,248,107,300, 'fill'=>outline, 'tags'=>['floor3','bg']) end # floor2_fg1 -- # This method represents part of the floorplan database. When # invoked, it instantiates the foreground information for the first # floor (office outlines and numbers). # # Arguments: # w - The canvas window. # color - Color to use for drawing foreground information. def floor2_fg1(w,color) i = TkcPolygon.new(w,375,246,375,172,341,172,341,246, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '101' $floorItems2['101'] = i w.create(TkcText,358,209, 'text'=>'101', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,307,240,339,240,339,206,307,206, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'Pub Lift1' $floorItems2['Pub Lift1'] = i w.create(TkcText,323,223, 'text'=>'Pub Lift1', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,339,205,307,205,307,171,339,171, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'Priv Lift1' $floorItems2['Priv Lift1'] = i w.create(TkcText,323,188, 'text'=>'Priv Lift1', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,42,389,42,337,1,337,1,389, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '110' $floorItems2['110'] = i w.create(TkcText,21.5,363, 'text'=>'110', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,59,389,59,385,90,385,90,337,44,337,44,389, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '109' $floorItems2['109'] = i w.create(TkcText,67,363, 'text'=>'109', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,51,300,51,253,6,253,6,300, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '111' $floorItems2['111'] = i w.create(TkcText,28.5,276.5, 'text'=>'111', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,98,248,98,309,79,309,79,248, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '117B' $floorItems2['117B'] = i w.create(TkcText,88.5,278.5, 'text'=>'117B', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,51,251,51,204,6,204,6,251, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '112' $floorItems2['112'] = i w.create(TkcText,28.5,227.5, 'text'=>'112', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,6,156,51,156,51,203,6,203, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '113' $floorItems2['113'] = i w.create(TkcText,28.5,179.5, 'text'=>'113', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,85,169,79,169,79,192,85,192, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '117A' $floorItems2['117A'] = i w.create(TkcText,82,180.5, 'text'=>'117A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,77,302,77,168,53,168,53,302, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '117' $floorItems2['117'] = i w.create(TkcText,65,235, 'text'=>'117', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,51,155,51,115,6,115,6,155, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '114' $floorItems2['114'] = i w.create(TkcText,28.5,135, 'text'=>'114', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,95,115,53,115,53,168,95,168, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '115' $floorItems2['115'] = i w.create(TkcText,74,141.5, 'text'=>'115', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,87,113,87,27,10,27,10,113, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '116' $floorItems2['116'] = i w.create(TkcText,48.5,70, 'text'=>'116', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,89,91,128,91,128,113,89,131, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '118' $floorItems2['118'] = i w.create(TkcText,108.5,102, 'text'=>'118', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,178,128,178,132,216,132,216,91, 163,91,163,112,149,112,149,128, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '120' $floorItems2['120'] = i w.create(TkcText,189.5,111.5, 'text'=>'120', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,79,193,87,193,87,169,136,169,136,192, 156,192,156,169,175,169,175,246,79,246, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '122' $floorItems2['122'] = i w.create(TkcText,131,207.5, 'text'=>'122', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,138,169,154,169,154,191,138,191, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '121' $floorItems2['121'] = i w.create(TkcText,146,180, 'text'=>'121', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,99,300,126,300,126,309,99,309, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '106A' $floorItems2['106A'] = i w.create(TkcText,112.5,304.5, 'text'=>'106A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,128,299,128,309,150,309,150,248,99,248,99,299, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '105' $floorItems2['105'] = i w.create(TkcText,124.5,278.5, 'text'=>'105', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,174,309,174,300,152,300,152,309, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '106B' $floorItems2['106B'] = i w.create(TkcText,163,304.5, 'text'=>'106B', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,176,299,176,309,216,309,216,248,152,248,152,299, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '104' $floorItems2['104'] = i w.create(TkcText,184,278.5, 'text'=>'104', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,138,385,138,337,91,337,91,385, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '108' $floorItems2['108'] = i w.create(TkcText,114.5,361, 'text'=>'108', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,256,337,140,337,140,385,256,385, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '107' $floorItems2['107'] = i w.create(TkcText,198,361, 'text'=>'107', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,300,353,300,329,260,329,260,353, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'Smoking' $floorItems2['Smoking'] = i w.create(TkcText,280,341, 'text'=>'Smoking', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,314,135,314,170,306,170,306,246,177,246,177,135, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '123' $floorItems2['123'] = i w.create(TkcText,245.5,190.5, 'text'=>'123', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,217,248,301,248,301,326,257,326,257,310,217,310, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '103' $floorItems2['103'] = i w.create(TkcText,259,287, 'text'=>'103', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,396,188,377,188,377,169,316,169,316,131,396,131, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '124' $floorItems2['124'] = i w.create(TkcText,356,150, 'text'=>'124', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,397,226,407,226,407,189,377,189,377,246,397,246, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '125' $floorItems2['125'] = i w.create(TkcText,392,217.5, 'text'=>'125', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,399,187,409,187,409,207,474,207,474,164,399,164, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '126' $floorItems2['126'] = i w.create(TkcText,436.5,185.5, 'text'=>'126', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,409,209,409,229,399,229,399,253, 486,253,486,239,474,239,474,209, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '127' $floorItems2['127'] = i w.create(TkcText,436.5,'231', 'text'=>'127', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,501,164,501,174,495,174,495,188, 490,188,490,204,476,204,476,164, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'MShower' $floorItems2['MShower'] = i w.create(TkcText,488.5,'184', 'text'=>'MShower', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,497,176,513,176,513,204,492,204,492,190,497,190, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'Closet' $floorItems2['Closet'] = i w.create(TkcText,502.5,190, 'text'=>'Closet', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,476,237,476,206,513,206,513,254,488,254,488,237, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'WShower' $floorItems2['WShower'] = i w.create(TkcText,494.5,230, 'text'=>'WShower', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,486,131,558,131,558,135,724,135,724,166, 697,166,697,275,553,275,531,254,515,254, 515,174,503,174,503,161,486,161, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '130' $floorItems2['130'] = i w.create(TkcText,638.5,205, 'text'=>'130', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,308,242,339,242,339,248,342,248, 342,246,397,246,397,276,393,276, 393,309,300,309,300,248,308,248, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '102' $floorItems2['102'] = i w.create(TkcText,367.5,278.5, 'text'=>'102', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,397,255,486,255,486,276,397,276, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '128' $floorItems2['128'] = i w.create(TkcText,441.5,265.5, 'text'=>'128', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,510,309,486,309,486,255,530,255, 552,277,561,277,561,325,510,325, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '129' $floorItems2['129'] = i w.create(TkcText,535.5,293, 'text'=>'129', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,696,281,740,281,740,387,642,387, 642,389,561,389,561,277,696,277, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '133' $floorItems2['133'] = i w.create(TkcText,628.5,335, 'text'=>'133', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,742,387,742,281,800,281,800,387, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '132' $floorItems2['132'] = i w.create(TkcText,771,334, 'text'=>'132', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,800,168,800,280,699,280,699,168, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '134' $floorItems2['134'] = i w.create(TkcText,749.5,224, 'text'=>'134', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,726,131,726,166,800,166,800,131, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '135' $floorItems2['135'] = i w.create(TkcText,763,148.5, 'text'=>'135', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,340,360,335,363,331,365,326,366,304,366, 304,312,396,312,396,288,400,288,404,288, 409,290,413,292,418,297,421,302,422,309, 421,318,417,325,411,330,405,332,397,333, 344,333,340,334,336,336,335,338,332,342, 331,347,332,351,334,354,336,357,341,359, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'Ramona Stair' $floorItems2['Ramona Stair'] = i w.create(TkcText,368,323, 'text'=>'Ramona Stair', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,30,23,30,5,93,5,98,5,104,7,110,10,116,16,119,20, 122,28,123,32,123,68,220,68,220,87,90,87,90,23, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'University Stair' $floorItems2['University Stair'] = i w.create(TkcText,155,77.5, 'text'=>'University Stair', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,282,37,295,40,312,49,323,56,337,70,352,56, 358,48,363,39,365,29,348,25,335,22,321,14, 300,5,283,1,260,0,246,0,242,2,236,4,231,8, 227,13,223,17,221,22,220,34,260,34, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'Plaza Stair' $floorItems2['Plaza Stair'] = i w.create(TkcText,317.5,28.5, 'text'=>'Plaza Stair', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,220,34,260,34,282,37,295,40,312,49, 323,56,337,70,350,83,365,94,377,100, 386,104,386,128,220,128, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'Plaza Deck' $floorItems2['Plaza Deck'] = i w.create(TkcText,303,81, 'text'=>'Plaza Deck', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,257,336,77,336,6,336,6,301,77,301,77,310,257,310, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '106' $floorItems2['106'] = i w.create(TkcText,131.5,318.5, 'text'=>'106', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,146,110,162,110,162,91,130,91,130,115,95,115, 95,128,114,128,114,151,157,151,157,153,112,153, 112,130,97,130,97,168,175,168,175,131,146,131, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '119' $floorItems2['119'] = i w.create(TkcText,143.5,133, 'text'=>'119', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) w.create(TkcLine,155,191,155,189, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,155,177,155,169, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,96,129,96,169, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,78,169,176,169, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,176,247,176,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,340,206,307,206, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,340,187,340,170, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,340,210,340,201, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,340,247,340,224, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,340,241,307,241, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,376,246,376,170, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,307,247,307,170, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,376,170,307,170, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,315,129,315,170, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,147,129,176,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,202,133,176,133, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,398,129,315,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,258,352,258,387, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,60,387,60,391, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,0,337,0,391, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,60,391,0,391, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,3,114,3,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,258,387,60,387, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,52,237,52,273, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,52,189,52,225, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,52,140,52,177, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,395,306,395,311, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,531,254,398,254, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,475,178,475,238, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,502,162,398,162, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,398,129,398,188, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,383,188,376,188, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,408,188,408,194, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,398,227,398,254, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,408,227,398,227, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,408,222,408,227, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,408,206,408,210, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,408,208,475,208, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,484,278,484,311, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,484,311,508,311, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,508,327,508,311, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,559,327,508,327, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,644,391,559,391, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,644,389,644,391, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,514,205,475,205, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,496,189,496,187, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,559,129,484,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,484,162,484,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,725,133,559,133, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,559,129,559,133, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,725,149,725,167, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,725,129,802,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,802,389,802,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,739,167,802,167, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,396,188,408,188, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,0,337,9,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,58,337,21,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,43,391,43,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,105,337,75,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,91,387,91,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,154,337,117,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,139,387,139,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,227,337,166,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,258,337,251,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,258,328,302,328, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,302,355,302,311, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,395,311,302,311, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,484,278,395,278, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,395,294,395,278, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,473,278,473,275, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,473,256,473,254, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,533,257,531,254, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,553,276,551,274, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,698,276,553,276, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,559,391,559,327, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,802,389,644,389, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,741,314,741,389, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,698,280,698,167, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,707,280,698,280, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,802,280,731,280, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,741,280,741,302, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,698,167,727,167, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,725,137,725,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,514,254,514,175, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,496,175,514,175, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,502,175,502,162, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,475,166,475,162, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,496,176,496,175, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,491,189,496,189, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,491,205,491,189, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,487,238,475,238, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,487,240,487,238, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,487,252,487,254, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,315,133,304,133, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,256,133,280,133, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,78,247,270,247, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,307,247,294,247, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,214,133,232,133, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,217,247,217,266, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,217,309,217,291, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,217,309,172,309, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,154,309,148,309, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,175,300,175,309, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,151,300,175,300, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,151,247,151,309, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,78,237,78,265, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,78,286,78,309, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,106,309,78,309, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,130,309,125,309, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,99,309,99,247, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,127,299,99,299, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,127,309,127,299, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,155,191,137,191, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,137,169,137,191, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,78,171,78,169, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,78,190,78,218, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,86,192,86,169, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,86,192,78,192, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,52,301,3,301, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,52,286,52,301, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,52,252,3,252, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,52,203,3,203, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,3,156,52,156, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,8,25,8,114, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,63,114,3,114, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,75,114,97,114, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,108,114,129,114, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,129,114,129,89, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,52,114,52,128, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,132,89,88,89, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,88,25,88,89, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,88,114,88,89, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,218,89,144,89, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,147,111,147,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,162,111,147,111, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,162,109,162,111, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,162,96,162,89, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,218,89,218,94, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,218,89,218,119, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,8,25,88,25, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,258,337,258,328, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,113,129,96,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,302,355,258,355, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,386,104,386,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,377,100,386,104, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,365,94,377,100, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,350,83,365,94, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,337,70,350,83, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,337,70,323,56, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,312,49,323,56, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,295,40,312,49, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,282,37,295,40, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,260,34,282,37, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,253,34,260,34, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,386,128,386,104, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,113,152,156,152, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,113,152,156,152, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,113,152,113,129, 'fill'=>color, 'tags'=>['floor1','wall']) end # floor2_fg2 -- # This method represents part of the floorplan database. When # invoked, it instantiates the foreground information for the second # floor (office outlines and numbers). # # Arguments: # w - The canvas window. # color - Color to use for drawing foreground information. def floor2_fg2(w,color) i = TkcPolygon.new(w,748,188,755,188,755,205,758,205,758,222, 800,222,800,168,748,168, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '238' $floorItems2['238'] = i w.create(TkcText,774,195, 'text'=>'238', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,726,188,746,188,746,166,800,166,800,131,726,131, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '237' $floorItems2['237'] = i w.create(TkcText,763,148.5, 'text'=>'237', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,497,187,497,204,559,204,559,324,641,324, 643,324,643,291,641,291,641,205,696,205, 696,291,694,291,694,314,715,314,715,291, 715,205,755,205,755,190,724,190,724,187, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '246' $floorItems2['246'] = i w.create(TkcText,600,264, 'text'=>'246', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,694,279,643,279,643,314,694,314, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '247' $floorItems2['247'] = i w.create(TkcText,668.5,296.5, 'text'=>'247', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,232,250,308,250,308,242,339,242,339,246, 397,246,397,255,476,255,476,250,482,250,559,250, 559,274,482,274,482,278,396,278,396,274,232,274, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '202' $floorItems2['202'] = i w.create(TkcText,285.5,260, 'text'=>'202', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,53,228,53,338,176,338,233,338,233,196, 306,196,306,180,175,180,175,169,156,169, 156,196,176,196,176,228, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '206' $floorItems2['206'] = i w.create(TkcText,143,267, 'text'=>'206', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,51,277,6,277,6,338,51,338, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '212' $floorItems2['212'] = i w.create(TkcText,28.5,307.5, 'text'=>'212', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,557,276,486,276,486,309,510,309,510,325,557,325, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '245' $floorItems2['245'] = i w.create(TkcText,521.5,300.5, 'text'=>'245', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,560,389,599,389,599,326,560,326, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '244' $floorItems2['244'] = i w.create(TkcText,579.5,357.5, 'text'=>'244', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,601,389,601,326,643,326,643,389, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '243' $floorItems2['243'] = i w.create(TkcText,622,357.5, 'text'=>'243', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,688,316,645,316,645,365,688,365, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '242' $floorItems2['242'] = i w.create(TkcText,666.5,340.5, 'text'=>'242', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,802,367,759,367,759,226,802,226, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = 'Barbecue Deck' $floorItems2['Barbecue Deck'] = i w.create(TkcText,780.5,296.5, 'text'=>'Barbecue Deck', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,755,262,755,314,717,314,717,262, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '240' $floorItems2['240'] = i w.create(TkcText,736,288, 'text'=>'240', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,755,316,689,316,689,365,755,365, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '241' $floorItems2['241'] = i w.create(TkcText,722,340.5, 'text'=>'241', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,755,206,717,206,717,261,755,261, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '239' $floorItems2['239'] = i w.create(TkcText,736,233.5, 'text'=>'239', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,695,277,643,277,643,206,695,206, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '248' $floorItems2['248'] = i w.create(TkcText,669,241.5, 'text'=>'248', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,676,135,676,185,724,185,724,135, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '236' $floorItems2['236'] = i w.create(TkcText,700,160, 'text'=>'236', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,675,135,635,135,635,145,628,145,628,185,675,185, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '235' $floorItems2['235'] = i w.create(TkcText,651.5,160, 'text'=>'235', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,626,143,633,143,633,135,572,135, 572,143,579,143,579,185,626,185, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '234' $floorItems2['234'] = i w.create(TkcText,606,160, 'text'=>'234', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,557,135,571,135,571,145,578,145, 578,185,527,185,527,131,557,131, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '233' $floorItems2['233'] = i w.create(TkcText,552.5,158, 'text'=>'233', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,476,249,557,249,557,205,476,205, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '230' $floorItems2['230'] = i w.create(TkcText,516.5,227, 'text'=>'230', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,476,164,486,164,486,131,525,131,525,185,476,185, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '232' $floorItems2['232'] = i w.create(TkcText,500.5,158, 'text'=>'232', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,476,186,495,186,495,204,476,204, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '229' $floorItems2['229'] = i w.create(TkcText,485.5,195, 'text'=>'229', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,474,207,409,207,409,187,399,187,399,164,474,164, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '227' $floorItems2['227'] = i w.create(TkcText,436.5,185.5, 'text'=>'227', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,399,228,399,253,474,253,474,209,409,209,409,228, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '228' $floorItems2['228'] = i w.create(TkcText,436.5,231, 'text'=>'228', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,397,246,397,226,407,226,407,189,377,189,377,246, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '226' $floorItems2['226'] = i w.create(TkcText,392,217.5, 'text'=>'226', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,377,169,316,169,316,131,397,131,397,188,377,188, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '225' $floorItems2['225'] = i w.create(TkcText,356.5,150, 'text'=>'225', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,234,198,306,198,306,249,234,249, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '224' $floorItems2['224'] = i w.create(TkcText,270,223.5, 'text'=>'224', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,270,179,306,179,306,170,314,170,314,135,270,135, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '223' $floorItems2['223'] = i w.create(TkcText,292,157, 'text'=>'223', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,268,179,221,179,221,135,268,135, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '222' $floorItems2['222'] = i w.create(TkcText,244.5,157, 'text'=>'222', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,177,179,219,179,219,135,177,135, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '221' $floorItems2['221'] = i w.create(TkcText,198,157, 'text'=>'221', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,299,327,349,327,349,284,341,284,341,276,299,276, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '204' $floorItems2['204'] = i w.create(TkcText,324,301.5, 'text'=>'204', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,234,276,297,276,297,327,257,327,257,338,234,338, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '205' $floorItems2['205'] = i w.create(TkcText,265.5,307, 'text'=>'205', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,256,385,256,340,212,340,212,385, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '207' $floorItems2['207'] = i w.create(TkcText,234,362.5, 'text'=>'207', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,210,340,164,340,164,385,210,385, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '208' $floorItems2['208'] = i w.create(TkcText,187,362.5, 'text'=>'208', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,115,340,162,340,162,385,115,385, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '209' $floorItems2['209'] = i w.create(TkcText,138.5,362.5, 'text'=>'209', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,89,228,89,156,53,156,53,228, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '217' $floorItems2['217'] = i w.create(TkcText,71,192, 'text'=>'217', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,89,169,97,169,97,190,89,190, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '217A' $floorItems2['217A'] = i w.create(TkcText,93,179.5, 'text'=>'217A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,89,156,89,168,95,168,95,135,53,135,53,156, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '216' $floorItems2['216'] = i w.create(TkcText,71,145.5, 'text'=>'216', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,51,179,51,135,6,135,6,179, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '215' $floorItems2['215'] = i w.create(TkcText,28.5,157, 'text'=>'215', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,51,227,6,227,6,180,51,180, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '214' $floorItems2['214'] = i w.create(TkcText,28.5,203.5, 'text'=>'214', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,51,275,6,275,6,229,51,229, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '213' $floorItems2['213'] = i w.create(TkcText,28.5,252, 'text'=>'213', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,114,340,67,340,67,385,114,385, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '210' $floorItems2['210'] = i w.create(TkcText,90.5,362.5, 'text'=>'210', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,59,389,59,385,65,385,65,340,1,340,1,389, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '211' $floorItems2['211'] = i w.create(TkcText,33,364.5, 'text'=>'211', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,393,309,350,309,350,282,342,282,342,276,393,276, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '203' $floorItems2['203'] = i w.create(TkcText,367.5,292.5, 'text'=>'203', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,99,191,91,191,91,226,174,226,174,198, 154,198,154,192,109,192,109,169,99,169, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '220' $floorItems2['220'] = i w.create(TkcText,132.5,208.5, 'text'=>'220', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,339,205,307,205,307,171,339,171, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = 'Priv Lift2' $floorItems2['Priv Lift2'] = i w.create(TkcText,323,188, 'text'=>'Priv Lift2', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,307,240,339,240,339,206,307,206, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = 'Pub Lift 2' $floorItems2['Pub Lift 2'] = i w.create(TkcText,323,223, 'text'=>'Pub Lift 2', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,175,168,97,168,97,131,175,131, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '218' $floorItems2['218'] = i w.create(TkcText,136,149.5, 'text'=>'218', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,154,191,111,191,111,169,154,169, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '219' $floorItems2['219'] = i w.create(TkcText,132.5,180, 'text'=>'219', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,375,246,375,172,341,172,341,246, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '201' $floorItems2['201'] = i w.create(TkcText,358,209, 'text'=>'201', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) w.create(TkcLine,641,186,678,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,757,350,757,367, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,634,133,634,144, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,634,144,627,144, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,572,133,572,144, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,572,144,579,144, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,398,129,398,162, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,174,197,175,197, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,175,197,175,227, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,757,206,757,221, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,396,188,408,188, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,727,189,725,189, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,747,167,802,167, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,747,167,747,189, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,755,189,739,189, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,769,224,757,224, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,802,224,802,129, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,802,129,725,129, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,725,189,725,129, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,725,186,690,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,676,133,676,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,627,144,627,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,629,186,593,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,579,144,579,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,559,129,559,133, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,725,133,559,133, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,484,162,484,129, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,559,129,484,129, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,526,129,526,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,540,186,581,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,528,186,523,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,511,186,475,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,496,190,496,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,496,205,496,202, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,475,205,527,205, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,558,205,539,205, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,558,205,558,249, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,558,249,475,249, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,662,206,642,206, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,695,206,675,206, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,695,278,642,278, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,642,291,642,206, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,695,291,695,206, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,716,208,716,206, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,757,206,716,206, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,757,221,757,224, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,793,224,802,224, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,757,262,716,262, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,716,220,716,264, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,716,315,716,276, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,757,315,703,315, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,757,325,757,224, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,757,367,644,367, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,689,367,689,315, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,647,315,644,315, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,659,315,691,315, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,600,325,600,391, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,627,325,644,325, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,644,391,644,315, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,615,325,575,325, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,644,391,558,391, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,563,325,558,325, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,558,391,558,314, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,558,327,508,327, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,558,275,484,275, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,558,302,558,275, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,508,327,508,311, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,484,311,508,311, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,484,275,484,311, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,475,208,408,208, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,408,206,408,210, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,408,222,408,227, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,408,227,398,227, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,398,227,398,254, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,408,188,408,194, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,383,188,376,188, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,398,188,398,162, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,398,162,484,162, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,475,162,475,254, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,398,254,475,254, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,484,280,395,280, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,395,311,395,275, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,307,197,293,197, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,278,197,233,197, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,233,197,233,249, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,307,179,284,179, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,233,249,278,249, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,269,179,269,133, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,220,179,220,133, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,155,191,110,191, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,90,190,98,190, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,98,169,98,190, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,52,133,52,165, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,52,214,52,177, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,52,226,52,262, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,52,274,52,276, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,234,275,234,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,226,339,258,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,211,387,211,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,214,339,177,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,258,387,60,387, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,3,133,3,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,165,339,129,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,117,339,80,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,68,339,59,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,0,339,46,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,60,391,0,391, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,0,339,0,391, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,60,387,60,391, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,258,329,258,387, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,350,329,258,329, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,395,311,350,311, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,398,129,315,129, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,176,133,315,133, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,176,129,96,129, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,3,133,96,133, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,66,387,66,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,115,387,115,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,163,387,163,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,234,275,276,275, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,288,275,309,275, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,298,275,298,329, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,341,283,350,283, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,321,275,341,275, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,375,275,395,275, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,315,129,315,170, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,376,170,307,170, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,307,250,307,170, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,376,245,376,170, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,340,241,307,241, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,340,245,340,224, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,340,210,340,201, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,340,187,340,170, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,340,206,307,206, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,293,250,307,250, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,271,179,238,179, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,226,179,195,179, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,176,129,176,179, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,182,179,176,179, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,174,169,176,169, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,162,169,90,169, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,96,169,96,129, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,175,227,90,227, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,90,190,90,227, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,52,179,3,179, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,52,228,3,228, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,52,276,3,276, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,155,177,155,169, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,110,191,110,169, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,155,189,155,197, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,350,283,350,329, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,162,197,155,197, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,341,275,341,283, 'fill'=>color, 'tags'=>['floor2','wall']) end # floor2_fg3 -- # This method represents part of the floorplan database. When # invoked, it instantiates the foreground information for the third # floor (office outlines and numbers). # # Arguments: # w - The canvas window. # color - Color to use for drawing foreground information. def floor2_fg3(w,color) i = TkcPolygon.new(w,89,228,89,180,70,180,70,228, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '316' $floorItems2['316'] = i w.create(TkcText,79.5,204, 'text'=>'316', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,115,368,162,368,162,323,115,323, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '309' $floorItems2['309'] = i w.create(TkcText,138.5,345.5, 'text'=>'309', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,164,323,164,368,211,368,211,323, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '308' $floorItems2['308'] = i w.create(TkcText,187.5,345.5, 'text'=>'308', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,256,368,212,368,212,323,256,323, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '307' $floorItems2['307'] = i w.create(TkcText,234,345.5, 'text'=>'307', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,244,276,297,276,297,327,260,327,260,321,244,321, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '305' $floorItems2['305'] = i w.create(TkcText,270.5,301.5, 'text'=>'305', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,251,219,251,203,244,203,244,219, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '324B' $floorItems2['324B'] = i w.create(TkcText,247.5,211, 'text'=>'324B', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,251,249,244,249,244,232,251,232, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '324A' $floorItems2['324A'] = i w.create(TkcText,247.5,240.5, 'text'=>'324A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,223,135,223,179,177,179,177,135, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '320' $floorItems2['320'] = i w.create(TkcText,200,157, 'text'=>'320', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,114,368,114,323,67,323,67,368, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '310' $floorItems2['310'] = i w.create(TkcText,90.5,345.5, 'text'=>'310', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,23,277,23,321,68,321,68,277, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '312' $floorItems2['312'] = i w.create(TkcText,45.5,299, 'text'=>'312', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,23,229,68,229,68,275,23,275, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '313' $floorItems2['313'] = i w.create(TkcText,45.5,252, 'text'=>'313', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,68,227,23,227,23,180,68,180, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '314' $floorItems2['314'] = i w.create(TkcText,40.5,203.5, 'text'=>'314', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,95,179,95,135,23,135,23,179, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '315' $floorItems2['315'] = i w.create(TkcText,59,157, 'text'=>'315', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,99,226,99,204,91,204,91,226, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '316B' $floorItems2['316B'] = i w.create(TkcText,95,215, 'text'=>'316B', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,91,202,99,202,99,180,91,180, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '316A' $floorItems2['316A'] = i w.create(TkcText,95,191, 'text'=>'316A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,97,169,109,169,109,192,154,192,154,198, 174,198,174,226,101,226,101,179,97,179, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '319' $floorItems2['319'] = i w.create(TkcText,141.5,209, 'text'=>'319', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,65,368,58,368,58,389,1,389,1,333,23,333,23,323,65,323, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '311' $floorItems2['311'] = i w.create(TkcText,29.5,361, 'text'=>'311', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,154,191,111,191,111,169,154,169, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '318' $floorItems2['318'] = i w.create(TkcText,132.5,180, 'text'=>'318', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,175,168,97,168,97,131,175,131, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '317' $floorItems2['317'] = i w.create(TkcText,136,149.5, 'text'=>'317', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,274,194,274,221,306,221,306,194, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '323' $floorItems2['323'] = i w.create(TkcText,290,207.5, 'text'=>'323', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,306,222,274,222,274,249,306,249, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '325' $floorItems2['325'] = i w.create(TkcText,290,235.5, 'text'=>'325', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,263,179,224,179,224,135,263,135, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '321' $floorItems2['321'] = i w.create(TkcText,243.5,157, 'text'=>'321', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,314,169,306,169,306,192,273,192, 264,181,264,135,314,135, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '322' $floorItems2['322'] = i w.create(TkcText,293.5,163.5, 'text'=>'322', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,307,240,339,240,339,206,307,206, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = 'Pub Lift3' $floorItems2['Pub Lift3'] = i w.create(TkcText,323,223, 'text'=>'Pub Lift3', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,339,205,307,205,307,171,339,171, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = 'Priv Lift3' $floorItems2['Priv Lift3'] = i w.create(TkcText,323,188, 'text'=>'Priv Lift3', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,350,284,376,284,376,276,397,276,397,309,350,309, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '303' $floorItems2['303'] = i w.create(TkcText,373.5,292.5, 'text'=>'303', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,272,203,272,249,252,249,252,230, 244,230,244,221,252,221,252,203, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '324' $floorItems2['324'] = i w.create(TkcText,262,226, 'text'=>'324', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,299,276,299,327,349,327,349,284,341,284,341,276, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '304' $floorItems2['304'] = i w.create(TkcText,324,301.5, 'text'=>'304', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,375,246,375,172,341,172,341,246, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '301' $floorItems2['301'] = i w.create(TkcText,358,209, 'text'=>'301', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,397,246,377,246,377,185,397,185, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '327' $floorItems2['327'] = i w.create(TkcText,387,215.5, 'text'=>'327', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,316,131,316,169,377,169,377,185,397,185,397,131, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '326' $floorItems2['326'] = i w.create(TkcText,365.5,150, 'text'=>'326', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,308,251,242,251,242,274,342,274,342,282,375, 282, 375,274,397,274,397,248,339,248,339,242,308,242, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '302' $floorItems2['302'] = i w.create(TkcText,319.5,261, 'text'=>'302', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,70,321,242,321,242,200,259,200,259,203,272,203, 272,193,263,180,242,180,175,180,175,169,156,169, 156,196,177,196,177,228,107,228,70,228,70,275,107,275, 107,248,160,248,160,301,107,301,107,275,70,275, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '306' $floorItems2['306'] = i w.create(TkcText,200.5,284.5, 'text'=>'306', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) w.create(TkcLine,341,275,341,283, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,162,197,155,197, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,396,247,399,247, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,399,129,399,311, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,258,202,243,202, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,350,283,350,329, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,251,231,243,231, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,243,220,251,220, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,243,250,243,202, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,155,197,155,190, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,110,192,110,169, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,155,192,110,192, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,155,177,155,169, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,176,197,176,227, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,69,280,69,274, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,21,276,69,276, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,69,262,69,226, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,21,228,69,228, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,21,179,75,179, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,69,179,69,214, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,90,220,90,227, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,90,204,90,202, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,90,203,100,203, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,90,187,90,179, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,90,227,176,227, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,100,179,100,227, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,100,179,87,179, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,96,179,96,129, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,162,169,96,169, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,173,169,176,169, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,182,179,176,179, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,176,129,176,179, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,195,179,226,179, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,224,133,224,179, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,264,179,264,133, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,238,179,264,179, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,273,207,273,193, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,273,235,273,250, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,273,224,273,219, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,273,193,307,193, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,273,222,307,222, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,273,250,307,250, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,384,247,376,247, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,340,206,307,206, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,340,187,340,170, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,340,210,340,201, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,340,247,340,224, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,340,241,307,241, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,376,247,376,170, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,307,250,307,170, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,376,170,307,170, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,315,129,315,170, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,376,283,366,283, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,376,283,376,275, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,399,275,376,275, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,341,275,320,275, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,341,283,350,283, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,298,275,298,329, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,308,275,298,275, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,243,322,243,275, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,243,275,284,275, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,258,322,226,322, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,212,370,212,322, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,214,322,177,322, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,163,370,163,322, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,165,322,129,322, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,84,322,117,322, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,71,322,64,322, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,115,322,115,370, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,66,322,66,370, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,52,322,21,322, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,21,331,0,331, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,21,331,21,133, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,96,133,21,133, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,176,129,96,129, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,315,133,176,133, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,315,129,399,129, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,399,311,350,311, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,350,329,258,329, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,258,322,258,370, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,60,370,258,370, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,60,370,60,391, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,0,391,0,331, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,60,391,0,391, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,307,250,307,242, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,273,250,307,250, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,258,250,243,250, 'fill'=>color, 'tags'=>['floor3','wall']) end # Below is the "main program" that creates the floorplan demonstration. # toplevel widget if defined?($floor2_demo) && $floor2_demo $floor2_demo.destroy $floor2_demo = nil end # demo toplevel widget $floor2_demo = TkToplevel.new {|w| title("Floorplan Canvas Demonstration 2") iconname("Floorplan2") positionWindow(w) geometry('+20+20') minsize(100,100) } base_frame = TkFrame.new($floor2_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'8i', 'justify'=>'left', 'text'=>"This window contains a canvas widget showing the floorplan of Digital Equipment Corporation's Western Research Laboratory. It has three levels. At any given time one of the levels is active, meaning that you can see its room structure. To activate a level, click the left mouse button anywhere on it. As the mouse moves over the active level, the room under the mouse lights up and its room number appears in the \"Room:\" entry. You can also type a room number in the entry and the room will light up."){ pack('side'=>'top') } # frame $floor2_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $floor2_demo $floor2_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'floor2'} }.pack('side'=>'left', 'expand'=>'yes') } $floor2_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # $floorLabels2 = {} $floorItems2 = {} # canvas if $tk_version =~ /^4\.[01]/ $floor2_canvas_frame = TkFrame.new(base_frame,'bd'=>2,'relief'=>'sunken', 'highlightthickness'=>2) $floor2_canvas = TkCanvas.new($floor2_canvas_frame, 'width'=>900, 'height'=>500, 'borderwidth'=>0, 'highlightthickness'=>0) {|c| TkScrollbar.new(base_frame, 'orient'=>'horiz', 'command'=>proc{|*args| c.xview(*args)}){|hs| c.xscrollcommand(proc{|first,last| hs.set first,last}) pack('side'=>'bottom', 'fill'=>'x') } TkScrollbar.new(base_frame, 'command'=>proc{|*args| c.yview(*args)}){|vs| c.yscrollcommand(proc{|first,last| vs.set first,last}) pack('side'=>'right', 'fill'=>'y') } } $floor2_canvas_frame.pack('side'=>'top','fill'=>'both', 'expand'=>'yes') $floor2_canvas.pack('expand'=>'yes', 'fill'=>'both') else TkFrame.new(base_frame) {|f| pack('side'=>'top', 'fill'=>'both', 'expand'=>'yes') h = TkScrollbar.new(f, 'highlightthickness'=>0, 'orient'=>'horizontal') v = TkScrollbar.new(f, 'highlightthickness'=>0, 'orient'=>'vertical') TkFrame.new(f, 'bd'=>2, 'relief'=>'sunken') {|f1| $floor2_canvas = TkCanvas.new(f1, 'width'=>900, 'height'=>500, 'borderwidth'=>0, 'highlightthickness'=>0) { xscrollcommand(proc{|first,last| h.set first,last}) yscrollcommand(proc{|first,last| v.set first,last}) pack('expand'=>'yes', 'fill'=>'both') } grid('padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') } v.grid('padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>1, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') h.grid('padx'=>1, 'pady'=>1, 'row'=>1, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') TkGrid.rowconfigure(f, 0, 'weight'=>1, 'minsize'=>0) TkGrid.columnconfigure(f, 0, 'weight'=>1, 'minsize'=>0) pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1) v.command(proc{|*args| $floor2_canvas.yview(*args)}) h.command(proc{|*args| $floor2_canvas.xview(*args)}) } end # Create an entry for displaying and typing in current room. $currentRoom2 = TkVariable.new $floor2_entry = TkEntry.new($floor2_canvas, 'width'=>10, 'relief'=>'sunken', 'bd'=>2, 'textvariable'=>$currentRoom2) # Choose colors, then fill in the floorplan. $floor2_colors = {} if TkWinfo.depth($floor2_canvas) > 1 $floor2_colors['bg1'] = '#a9c1da' $floor2_colors['outline1'] = '#77889a' $floor2_colors['bg2'] = '#9ab0c6' $floor2_colors['outline2'] = '#687786' $floor2_colors['bg3'] = '#8ba0b3' $floor2_colors['outline3'] = '#596673' $floor2_colors['offices'] = 'Black' $floor2_colors['active'] = '#c4d1df' else $floor2_colors['bg1'] = 'white' $floor2_colors['outline1'] = 'black' $floor2_colors['bg2'] = 'white' $floor2_colors['outline2'] = 'black' $floor2_colors['bg3'] = 'white' $floor2_colors['outline3'] = 'black' $floor2_colors['offices'] = 'Black' $floor2_colors['active'] = 'black' end $activeFloor2 = '' floorDisplay2 $floor2_canvas,3 # Set up event bindings for canvas: $floor2_canvas.itembind('floor1', '1', proc{floorDisplay2 $floor2_canvas,1}) $floor2_canvas.itembind('floor2', '1', proc{floorDisplay2 $floor2_canvas,2}) $floor2_canvas.itembind('floor3', '1', proc{floorDisplay2 $floor2_canvas,3}) $floor2_canvas.itembind('room', 'Enter', proc{newRoom2 $floor2_canvas}) $floor2_canvas.itembind('room', 'Leave', proc{$currentRoom2.value = ''}) $floor2_canvas.bind('2', proc{|x,y| $floor2_canvas.scan_mark x,y}, '%x %y') $floor2_canvas.bind('B2-Motion', proc{|x,y| $floor2_canvas.scan_dragto x,y}, '%x %y') $floor2_canvas.bind('Destroy', proc{$currentRoom2.unset}) $currentRoom2.value = '' $currentRoom2.trace('w',proc{roomChanged2 $floor2_canvas}) ================================================ FILE: ext/tk/sample/demos-en/form.rb ================================================ # # form widget demo (called by 'widget') # # toplevel widget if defined?($form_demo) && $form_demo $form_demo.destroy $form_demo = nil end # demo toplevel widget $form_demo = TkToplevel.new {|w| title("Form Demonstration") iconname("form") positionWindow(w) } base_frame = TkFrame.new($form_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "This window contains a simple form where you can type in the various entries and use tabs to move circularly between the entries." } msg.pack('side'=>'top', 'fill'=>'x') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $form_demo $form_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'form'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # entry form_data = [] (1..5).each{|i| f = TkFrame.new(base_frame, 'bd'=>2) e = TkEntry.new(f, 'relief'=>'sunken', 'width'=>40) l = TkLabel.new(f) e.pack('side'=>'right') l.pack('side'=>'left') form_data[i] = {'frame'=>f, 'entry'=>e, 'label'=>l} } # form_data[1]['label'].text('Name:') form_data[2]['label'].text('Address:') form_data[5]['label'].text('Phone:') # pack (1..5).each{|i| form_data[i]['frame'].pack('side'=>'top', 'fill'=>'x')} ================================================ FILE: ext/tk/sample/demos-en/goldberg.rb ================================================ # # Ruby/Tk Goldverg demo (called by 'widget') # # Based on Tcl/Tk8.5a2 widget demos. # The following is the original comment of TkGoldberg.tcl. # #>>##+################################################################# #>># #>># TkGoldberg.tcl #>># by Keith Vetter, March 13, 2003 #>># #>># "Man will always find a difficult means to perform a simple task" #>># Rube Goldberg #>># #>># Reproduced here with permission. #>># #>>##+################################################################# #>># #>># Keith Vetter 2003-03-21: this started out as a simple little program #>># but was so much fun that it grew and grew. So I apologize about the #>># size but I just couldn't resist sharing it. #>># #>># This is a whizzlet that does a Rube Goldberg type animation, the #>># design of which comes from an New Years e-card from IncrediMail. #>># That version had nice sound effects which I eschewed. On the other #>># hand, that version was in black and white (actually dark blue and #>># light blue) and this one is fully colorized. #>># #>># One thing I learned from this project is that drawing filled complex #>># objects on a canvas is really hard. More often than not I had to #>># draw each item twice--once with the desired fill color but no #>># outline, and once with no fill but with the outline. Another trick #>># is erasing by drawing with the background color. Having a flood fill #>># command would have been extremely helpful. #>># #>># Two wiki pages were extremely helpful: Drawing rounded rectangles #>># which I generalized into Drawing rounded polygons, and regular #>># polygons which allowed me to convert ovals and arcs into polygons #>># which could then be rotated (see Canvas Rotation). I also wrote #>># Named Colors to aid in the color selection. #>># #>># I could comment on the code, but it's just 26 state machines with #>># lots of canvas create and move calls. if defined?($goldberg_demo) && $goldberg_demo $goldberg_demo.destroy $goldberg_demo = nil end # demo toplevel widget $goldberg_demo = TkToplevel.new {|w| title("Tk Goldberg (demonstration)") iconname("goldberg") # positionWindow(w) } base_frame = TkFrame.new($goldberg_demo).pack(:fill=>:both, :expand=>true) =begin # label msg = TkLabel.new($goldberg_demo) { font 'Arial 10' wraplength '4i' justify 'left' text "This is a demonstration of just how complex you can make your animations become. Click the ball to start things moving!\n\n\"Man will always find a difficult means to perform a simple task\"\n - Rube Goldberg" } msg.pack('side'=>'top') =end =begin # frame TkFrame.new($goldberg_demo) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $goldberg_demo $goldberg_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'See Code' command proc{showCode 'goldberg'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') =end ######################################### class TkGoldberg_Demo def initialize(parent) @parent = parent @S = {} @S['title'] = 'Tk Goldberg' @S['speed'] = TkVariable.new(5) @S['cnt'] = TkVariable.new(0) @S['message'] = TkVariable.new("\\nWelcome\\nto\\nRuby/Tk") @S['pause'] = TkVariable.new @S['details'] = TkVariable.new(true) @S['mode'] = TkVariable.new(:MSTART, :symbol) # :MSTART, :MGO, :MPAUSE, :MSSTEP, :MBSTEP, :MDONE, :MDEBUG # 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 @speed = [1, 10, 20, 50, 80, 100, 150, 200, 300, 400, 500] # colors @C = {} @C['fg'] = 'black' # @C['bg'] = 'gray75' @C['bg'] = 'cornflowerblue' @C['0'] = 'white'; @C['1a'] = 'darkgreen'; @C['1b'] = 'yellow' @C['2'] = 'red'; @C['3a'] = 'green'; @C['3b'] = 'darkblue' @C['4'] = @C['fg']; @C['5a'] = 'brown'; @C['5b'] = 'white' @C['6'] = 'magenta'; @C['7'] = 'green'; @C['8'] = @C['fg'] @C['9'] = 'blue4'; @C['10a'] = 'white'; @C['10b'] = 'cyan' @C['11a'] = 'yellow'; @C['11b'] = 'mediumblue'; @C['12'] = 'tan2' @C['13a'] = 'yellow'; @C['13b'] = 'red'; @C['14'] = 'white' @C['15a'] = 'green'; @C['15b'] = 'yellow'; @C['16'] = 'gray65' @C['17'] = '#A65353'; @C['18'] = @C['fg']; @C['19'] = 'gray50' @C['20'] = 'cyan'; @C['21'] = 'gray65'; @C['22'] = @C['20'] @C['23a'] = 'blue'; @C['23b'] = 'red'; @C['23c'] = 'yellow' @C['24a'] = 'red'; @C['24b'] = 'white'; @STEP = TkVariable.new_hash @STEP.default_value_type = :numeric @XY = {} @XY6 = { '-1'=>[366, 207], '-2'=>[349, 204], '-3'=>[359, 193], '-4'=>[375, 192], '-5'=>[340, 190], '-6'=>[349, 177], '-7'=>[366, 177], '-8'=>[380, 176], '-9'=>[332, 172], '-10'=>[342, 161], '-11'=>[357, 164], '-12'=>[372, 163], '-13'=>[381, 149], '-14'=>[364, 151], '-15'=>[349, 146], '-16'=>[333, 148], '0'=>[357, 219], '1'=>[359, 261], '2'=>[359, 291], '3'=>[359, 318], '4'=>[361, 324], '5'=>[365, 329], '6'=>[367, 334], '7'=>[367, 340], '8'=>[366, 346], '9'=>[364, 350], '10'=>[361, 355], '11'=>[359, 370], '12'=>[359, 391], '13,0'=>[360, 456], '13,1'=>[376, 456], '13,2'=>[346, 456], '13,3'=>[330, 456], '13,4'=>[353, 444], '13,5'=>[368, 443], '13,6'=>[339, 442], '13,7'=>[359, 431], '13,8'=>[380, 437], '13,9'=>[345, 428], '13,10'=>[328, 434], '13,11'=>[373, 424], '13,12'=>[331, 420], '13,13'=>[360, 417], '13,14'=>[345, 412], '13,15'=>[376, 410], '13,16'=>[360, 403] } @timer = TkTimer.new(@speed[@S['speed'].numeric]){|timer| timer.set_interval(go) } do_display reset # Start everything going @timer.start end def do_display() @ctrl = TkFrame.new(@parent, :relief=>:ridge, :bd=>2, :padx=>5, :pady=>5) @screen = TkFrame.new(@parent, :bd=>2, :relief=>:raised).pack(:side=>:left, :fill=>:both, :expand=>true) @canvas = TkCanvas.new(@parent, :width=>850, :height=>700, :bg=>@C['bg'], :highlightthickness=>0){ scrollregion([0, 0, 1000, 1000]) # Kludge to move everything up yview_moveto(0.05) }.pack(:in=>@screen, :side=>:top, :fill=>:both, :expand=>true) @canvas.bind('3'){ @pause.invoke } @canvas.bind('Destroy'){ @timer.stop } do_ctrl_frame do_detail_frame # msg = TkLabel.new(@parent, :bg=>@C['bg'], :fg=>'white') { msg = Tk::Label.new(@parent, :bg=>@C['bg'], :fg=>'white') { font 'Arial 10' wraplength 600 justify 'left' text "This is a demonstration of just how complex you can make your animations become. Click the ball to start things moving!\n\"Man will always find a difficult means to perform a simple task\" - Rube Goldberg" } msg.place(:in=>@canvas, :relx=>0, :rely=>0, :anchor=>:nw) frame = TkFrame.new(@parent, :bg=>@C['bg']) # TkButton.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) { Tk::Button.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) { text 'Dismiss' command proc{ tmppath = $goldberg_demo $goldberg_demo = nil tmppath.destroy } }.pack('side'=>'left') # TkButton.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) { Tk::Button.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) { text 'See Code' command proc{showCode 'goldberg'} }.pack('side'=>'left', 'padx'=>5) # @show = TkButton.new(frame, :text=>'>>', :command=>proc{show_ctrl}, @show = Tk::Button.new(frame, :text=>'>>', :command=>proc{show_ctrl}, :bg=>@C['bg'], :activebackground=>@C['bg']) @show.pack('side'=>'left') frame.place(:in=>@canvas, :relx=>1, :rely=>0, :anchor=>:ne) Tk.update end def do_ctrl_frame @start = Tk::Button.new(@parent, :text=>'Start', :bd=>6, :command=>proc{do_button(0)}) if font = @start['font'] @start.font(font.weight('bold')) end @pause = TkCheckbutton.new(@parent, :text=>'Pause', :font=>font, :command=>proc{do_button(1)}, :relief=>:raised, :variable=>@S['pause']) @step = TkButton.new(@parent, :text=>'Single Step', :font=>font, :command=>proc{do_button(2)}) @bstep = TkButton.new(@parent, :text=>'Big Step', :font=>font, :command=>proc{do_button(4)}) @reset = TkButton.new(@parent, :text=>'Reset', :font=>font, :command=>proc{do_button(3)}) @details = TkFrame.new(@parent, :bd=>2, :relief=>:ridge) @detail = TkCheckbutton.new(@parent, :text=>'Details', :font=>font, :relief=>:raised, :variable=>@S['details']) @msg_entry = TkEntry.new(@parent, :textvariable=>@S['message'], :justify=>:center) @speed_scale = TkScale.new(@parent, :orient=>:horizontal, :from=>1, :to=>10, :font=>font, :variable=>@S['speed'], :bd=>2, :relief=>:ridge, :showvalue=>false) @about = TkButton.new(@parent, :text=>'About', :command=>proc{about}, :font=>font) Tk.grid(@start, :in=>@ctrl, :row=>0, :sticky=>:ew) @ctrl.grid_rowconfigure(1, :minsize=>10) Tk.grid(@pause, :in=>@ctrl, :row=>2, :sticky=>:ew) Tk.grid(@step, :in=>@ctrl, :sticky=>:ew) Tk.grid(@bstep, :in=>@ctrl, :sticky=>:ew) Tk.grid(@reset, :in=>@ctrl, :sticky=>:ew) @ctrl.grid_rowconfigure(10, :minsize=>20) Tk.grid(@details, :in=>@ctrl, :row=>11, :sticky=>:ew) Tk.grid(@detail, :in=>@details, :row=>0, :sticky=>:ew) @ctrl.grid_rowconfigure(50, :weight=>1) @S['mode'].trace('w', proc{|*args| active_GUI(*args)}) @S['details'].trace('w', proc{|*args| active_GUI(*args)}) @S['speed'].trace('w', proc{|*args| active_GUI(*args)}) Tk.grid(@msg_entry, :in=>@ctrl, :row=>98, :sticky=>:ew, :pady=>5) Tk.grid(@speed_scale, :in=>@ctrl, :row=>99, :sticky=>:ew) Tk.grid(@about, :in=>@ctrl, :row=>100, :sticky=>:ew) @reset.bind('3'){@S['mode'].value = -1} # Debugging end def do_detail_frame @f_details = TkFrame.new(@details) @label = TkLabel.new(@f_details, :textvariable=>@S['cnt'], :bd=>1, :relief=>:solid, :bg=>'white') Tk.grid(@label, '-', '-', '-', :sticky=>:ew, :row=>0) idx = 1 loop { break unless respond_to?("move#{idx}") l = TkLabel.new(@f_details, :text=>idx, :anchor=>:e, :width=>2, :bd=>1, :relief=>:solid, :bg=>'white') @STEP[idx] = 0 ll = TkLabel.new(@f_details, :textvariable=>@STEP.ref(idx), :width=>5, :bd=>1, :relief=>:solid, :bg=>'white') row = (idx + 1)/2 col = ((idx + 1) & 1) * 2 Tk.grid(l, :sticky=>:ew, :row=>row, :column=>col) Tk.grid(ll, :sticky=>:ew, :row=>row, :column=>(col + 1)) idx += 1 } @f_details.grid_columnconfigure(1, :weight=>1) end def show_ctrl if @ctrl.winfo_mapped? @ctrl.pack_forget @show.text('>>') else @ctrl.pack(:side=>:right, :fill=>:both, :ipady=>5) @show.text('<<') end end def draw_all reset_step @canvas.delete(:all) idx = 0 loop{ m = "draw#{idx}" break unless respond_to?(m) send(m) idx += 1 } end def active_GUI(var1, var2, op) st = {false=>:disabled, true=>:normal} m = @S['mode'].to_sym @S['pause'].value = (m == :MPAUSE) @start.state(st[m != :MGO]) @pause.state(st[m != :MSTART && m != :MDONE]) @step.state(st[m != :MGO && m != :MDONE]) @bstep.state(st[m != :MGO && m != :MDONE]) @reset.state(st[m != :MSTART]) if @S['details'].bool Tk.grid(@f_details, :in=>@details, :row=>2, :sticky=>:ew) else Tk.grid_forget(@f_details) end @speed_scale.label("Speed: #{@S['speed'].value}") end def start @S['mode'].value = :MGO end def do_button(what) case what when 0 # Start reset if @S['mode'].to_sym == :MDONE @S['mode'].value = :MGO when 1 # Pause @S['mode'].value = ((@S['pause'].bool)? :MPAUSE: :MGO) when 2 # Step @S['mode'].value = :MSSTEP when 3 # Reset reset when 4 # Big step @S['mode'].value = :MBSTEP end end def go(who = nil) now = Tk::Clock.clicks(:miliseconds) if who # Start here for debugging @S['active'] = [who] @S['mode'].value = :MGO end return if @S['mode'].to_sym == :MDEBUG # Debugging # If not paused, do the next move n = next_step if @S['mode'].to_sym != :MPAUSE @S['mode'].value = :MPAUSE if @S['mode'].to_sym == :MSSTEP # Single step @S['mode'].value = :MSSTEP if @S['mode'].to_sym == :MBSTEP && n # big step elapsed = Tk::Clock.clicks(:miliseconds) - now delay = @speed[@S['speed'].to_i] - elapsed delay = 1 if delay <= 0 return delay end def next_step retval = false # Return value if @S['mode'].to_sym != :MSTART && @S['mode'].to_sym != :MDONE @S['cnt'].numeric += 1 end alive = [] @S['active'].each{|who| who = who.to_i n = send("move#{who}") if (n & 1).nonzero? # This guy still alive alive << who end if (n & 2).nonzero? # Next guy is active alive << (who + 1) retval = true end if (n & 4).nonzero? # End of puzzle flag @S['mode'].value = :MDONE # Done mode @S['active'] = [] # No more animation return true end } @S['active'] = alive return retval end def about msg = "Ruby/Tk Version ::\nby Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)\n\n" msg += "Original Version ::\n" msg += "#{@S['title']}\nby Keith Vetter, March 2003\n(Reproduced by kind permission of the author)\n\n" msg += "Man will always find a difficult means to perform a simple task" msg += "\nRube Goldberg" Tk.messageBox(:message=>msg, :title=>'About') end ################################################################ # # All the drawing and moving routines # # START HERE! banner def draw0 color = @C['0'] TkcText.new(@canvas, [579, 119], :text=>'START HERE!', :fill=>color, :anchor=>:w, :tag=>'I0', :font=>['Times Roman', 12, :italic, :bold]) TkcLine.new(@canvas, [719, 119, 763, 119], :tag=>'I0', :fill=>color, :width=>5, :arrow=>:last, :arrowshape=>[18, 18, 5]) @canvas.itembind('I0', '1'){ start } end def move0(step = nil) step = get_step(0, step) if @S['mode'].to_sym != :MSTART # Start the ball rolling move_abs('I0', [-100, -100]) # Hide the banner return 2 end pos = [ [673, 119], [678, 119], [683, 119], [688, 119], [693, 119], [688, 119], [683, 119], [678, 119] ] step = step % pos.length move_abs('I0', pos[step]) return 1 end # Dropping ball def draw1 color = @C['1a'] color2 = @C['1b'] TkcPolygon.new(@canvas, [ 844, 133, 800, 133, 800, 346, 820, 346, 820, 168, 844, 168, 844, 133 ], :width=>3, :fill=>color, :outline=>'') TkcPolygon.new(@canvas, [ 771, 133, 685, 133, 685, 168, 751, 168, 751, 346, 771, 346, 771, 133 ], :width=>3, :fill=>color, :outline=>'') TkcOval.new(@canvas, box(812, 122, 9), :tag=>'I1', :fill=>color2, :outline=>'') @canvas.itembind('I1', '1'){ start } end def move1(step = nil) step = get_step(1, step) pos = [ [807, 122], [802, 122], [797, 123], [793, 124], [789, 129], [785, 153], [785, 203], [785, 278, :x], [785, 367], [810, 392], [816, 438], [821, 503], [824, 585, :y], [838, 587], [848, 593], [857, 601], [-100, -100] ] return 0 if step >= pos.length where = pos[step] move_abs('I1', where) move15a if where[2] == :y return 3 if where[2] == :x return 1 end # Lighting the match def draw2 color = @C['2'] # Fulcrum TkcPolygon.new(@canvas, [750, 369, 740, 392, 760, 392], :fill=>@C['fg'], :outline=>@C['fg']) # Strike box TkcRectangle.new(@canvas, [628, 335, 660, 383], :fill=>'', :outline=>@C['fg']) (0..2).each{|y| yy = 335 + y*16 TkcBitmap.new(@canvas, [628, yy], :bitmap=>'gray25', :anchor=>:nw, :foreground=>@C['fg']) TkcBitmap.new(@canvas, [644, yy], :bitmap=>'gray25', :anchor=>:nw, :foreground=>@C['fg']) } # Lever TkcLine.new(@canvas, [702, 366, 798, 366], :fill=>@C['fg'], :width=>6, :tag=>'I2_0') # R strap TkcLine.new(@canvas, [712, 363, 712, 355], :fill=>@C['fg'], :width=>3, :tag=>'I2_1') # L strap TkcLine.new(@canvas, [705, 363, 705, 355], :fill=>@C['fg'], :width=>3, :tag=>'I2_2') # Match stick TkcLine.new(@canvas, [679, 356, 679, 360, 717, 360, 717, 356, 679, 356], :fill=>@C['fg'], :width=>3, :tag=>'I2_3') # Match head TkcPolygon.new(@canvas, [ 671, 352, 677.4, 353.9, 680, 358.5, 677.4, 363.1, 671, 365, 664.6, 363.1, 662, 358.5, 664.6, 353.9 ], :fill=>color, :outline=>color, :tag=>'I2_4') end def move2(step = nil) step = get_step(2, step) stages = [0, 0, 1, 2, 0, 2, 1, 0, 1, 2, 0, 2, 1] xy = [] xy[0] = [ 686, 333, 692, 323, 682, 316, 674, 309, 671, 295, 668, 307, 662, 318, 662, 328, 671, 336 ] xy[1] = [ 687, 331, 698, 322, 703, 295, 680, 320, 668, 297, 663, 311, 661, 327, 671, 335 ] xy[2] = [ 686, 331, 704, 322, 688, 300, 678, 283, 678, 283, 674, 298, 666, 309, 660, 324, 672, 336 ] if step >= stages.length @canvas.delete('I2') return 0 end if step == 0 # Rotate the match beta = 20 ox, oy = anchor('I2_0', :s) # Where to pivot i = 0 until @canvas.find_withtag("I2_#{i}").empty? rotate_item("I2_#{i}", ox, oy, beta) i += 1 end # For the flame TkcPolygon.new(@canvas, [], :tag=>'I2', :smooth=>true, :fill=>@C['2']) return 1 end @canvas.coords('I2', xy[stages[step]]) return ((step == 7)? 3: 1) end # Weight and pulleys def draw3 color = @C['3a'] color2 = @C['3b'] xy = [ [602, 296], [577, 174], [518, 174] ] xy.each{|x, y| # 3 Pulleys TkcOval.new(@canvas, box(x, y, 13), :fill=>color, :outline=>@C['fg'], :width=>3) TkcOval.new(@canvas, box(x, y, 2), :fill=>@C['fg'], :outline=>@C['fg']) } # Wall to flame TkcLine.new(@canvas, [750, 309, 670, 309], :tag=>'I3_s', :width=>3, :fill=>@C['fg'], :smooth=>true) # Flame to pulley 1 TkcLine.new(@canvas, [670, 309, 650, 309], :tag=>'I3_0', :width=>3, :fill=>@C['fg'], :smooth=>true) TkcLine.new(@canvas, [650, 309, 600, 309], :tag=>'I3_1', :width=>3, :fill=>@C['fg'], :smooth=>true) # Pulley 1 half way to 2 TkcLine.new(@canvas, [589, 296, 589, 235], :tag=>'I3_2', :width=>3, :fill=>@C['fg']) # Pulley 1 other half to 2 TkcLine.new(@canvas, [589, 235, 589, 174], :width=>3, :fill=>@C['fg']) # Across the top TkcLine.new(@canvas, [577, 161, 518, 161], :width=>3, :fill=>@C['fg']) # Down to weight TkcLine.new(@canvas, [505, 174, 505, 205], :tag=>'I3_w', :width=>3, :fill=>@C['fg']) # Draw the weight as 2 circles, two rectangles and 1 rounded rectangle x1, y1, x2, y2 = [515, 207, 495, 207] TkcOval.new(@canvas, box(x1, y1, 6), :tag=>'I3_', :fill=>color2, :outline=>color2) TkcOval.new(@canvas, box(x2, y2, 6), :tag=>'I3_', :fill=>color2, :outline=>color2) TkcRectangle.new(@canvas, x1, y1 - 6, x2, y2 + 6, :tag=>'I3_', :fill=>color2, :outline=>color2) TkcPolygon.new(@canvas, round_rect([492, 220, 518, 263], 15), :smooth=>true, :tag=>'I3_', :fill=>color2, :outline=>color2) TkcLine.new(@canvas, [500, 217, 511, 217], :tag=>'I3_', :fill=>color2, :width=>10) # Bottom weight target TkcLine.new(@canvas, [502, 393, 522, 393, 522, 465], :tag=>'I3__', :fill=>@C['fg'], :joinstyle=>:miter, :width=>10) end def move3(step = nil) step = get_step(3, step) pos = [ [505, 247], [505, 297], [505, 386.5], [505, 386.5] ] rope = [] rope[0] = [750, 309, 729, 301, 711, 324, 690, 300] rope[1] = [750, 309, 737, 292, 736, 335, 717, 315, 712, 320] rope[2] = [750, 309, 737, 309, 740, 343, 736, 351, 725, 340] rope[3] = [750, 309, 738, 321, 746, 345, 742, 356] return 0 if step >= pos.length @canvas.delete("I3_#{step}") # Delete part of the rope move_abs('I3_', pos[step]) # Move weight down @canvas.coords('I3_s', rope[step]) # Flapping rope end @canvas.coords('I3_w', [505, 174].concat(pos[step])) if step == 2 @canvas.move('I3__', 0, 30) return 2 end return 1 end # Cage and door def draw4 color = @C['4'] x0, y0, x1, y1 = [527, 356, 611, 464] # Horizontal bars y0.step(y1, 12){|y| TkcLine.new(@canvas, [x0, y, x1, y], :fill=>color, :width=>1) } # Vertical bars x0.step(x1, 12){|x| TkcLine.new(@canvas, [x, y0, x, y1], :fill=>color, :width=>1) } # Swing gate TkcLine.new(@canvas, [518, 464, 518, 428], :tag=>'I4', :fill=>color, :width=>1) end def move4(step = nil) step = get_step(4, step) angles = [-10, -20, -30, -30] return 0 if step >= angles.length rotate_item('I4', 518, 464, angles[step]) @canvas.raise('I4') return((step == 3)? 3: 1) end # Mouse def draw5 color = @C['5a'] color2 = @C['5b'] xy = [377, 248, 410, 248, 410, 465, 518, 465] # Mouse course xy.concat [518, 428, 451, 428, 451, 212, 377, 212] TkcPolygon.new(@canvas, xy, :fill=>color2, :outline=>@C['fg'], :width=>3) xy = [ 534.5, 445.5, 541, 440, 552, 436, 560, 436, 569, 440, 574, 446, 575, 452, 574, 454, 566, 456, 554, 456, 545, 456, 537, 454, 530, 452 ] TkcPolygon.new(@canvas, xy, :tag=>['I5', 'I5_0'], :fill=>color) TkcLine.new(@canvas, [573, 452, 592, 458, 601, 460, 613, 456], # Tail :tag=>['I5', 'I5_1'], :fill=>color, :smooth=>true, :width=>3) xy = box(540, 446, 2) # Eye xy = [540, 444, 541, 445, 541, 447, 540, 448, 538, 447, 538, 445] TkcPolygon.new(@canvas, xy, :tag=>['I5', 'I5_2'], :fill=>@C['bg'], :outline=>'', :smooth=>true) xy = [538, 454, 535, 461] # Front leg TkcLine.new(@canvas, xy, :tag=>['I5', 'I5_3'], :fill=>color, :width=>2) xy = [566, 455, 569, 462] # Back leg TkcLine.new(@canvas, xy, :tag=>['I5', 'I5_4'], :fill=>color, :width=>2) xy = [544, 455, 545, 460] # 2nd front leg TkcLine.new(@canvas, xy, :tag=>['I5', 'I5_5'], :fill=>color, :width=>2) xy = [560, 455, 558, 460] # 2nd back leg TkcLine.new(@canvas, xy, :tag=>['I5', 'I5_6'], :fill=>color, :width=>2) end def move5(step = nil) step = get_step(5, step) pos = [ [553, 452], [533, 452], [513, 452], [493, 452], [473, 452], [463, 442, 30], [445.5, 441.5, 30], [425.5, 434.5, 30], [422, 414], [422, 394], [422, 374], [422, 354], [422, 334], [422, 314], [422, 294], [422, 274, -30], [422, 260.5, -30, :x], [422.5, 248.5, -28], [425, 237] ] return 0 if step >= pos.length x, y, beta, nxt = pos[step] move_abs('I5', [x, y]) if beta ox, oy = centroid('I5_0') (0..6).each{|id| rotate_item("I5_#{id}", ox, oy, beta) } end return 3 if nxt == :x return 1 end # Dropping gumballs def draw6 color = @C['6'] xy = [324, 130, 391, 204] # Ball holder xy = round_rect(xy, 10) TkcPolygon.new(@canvas, xy, :smooth=>true, :outline=>@C['fg'], :width=>3, :fill=>color) xy = [339, 204, 376, 253] # Below the ball holder TkcRectangle.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :fill=>color, :tag=>'I6c') xy = box(346, 339, 28) TkcOval.new(@canvas, xy, :fill=>color, :outline=>'') # Roter TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>2, :style=>:arc, :start=>80, :extent=>205) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>2, :style=>:arc, :start=>-41, :extent=>85) xy = box(346, 339, 15) # Center of rotor TkcOval.new(@canvas, xy, :outline=>@C['fg'], :fill=>@C['fg'], :tag=>'I6m') xy = [352, 312, 352, 254, 368, 254, 368, 322] # Top drop to rotor TkcPolygon.new(@canvas, xy, :fill=>color, :outline=>'') TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2) xy = [353, 240, 367, 300] # Poke bottom hole TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>'') xy = [341, 190, 375, 210] # Poke another hole TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>'') xy = [ 368, 356, 368, 403, 389, 403, 389, 464, 320, 464, 320, 403, 352, 403, 352, 366 ] TkcPolygon.new(@canvas, xy, :fill=>color, :outline=>'', :width=>2) # Below rotor TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2) xy = box(275, 342, 7) # On/off rotor TkcOval.new(@canvas, xy, :outline=>@C['fg'], :fill=>@C['fg']) xy = [276, 334, 342, 325] # Fan belt top TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) xy = [276, 349, 342, 353] # Fan belt bottom TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) xy = [337, 212, 337, 247] # What the mouse pushes TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I6_') xy = [392, 212, 392, 247] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I6_') xy = [337, 230, 392, 230] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>7, :tag=>'I6_') who = -1 # All the balls colors = %w(red cyan orange green blue darkblue) colors *= 3 (0..16).each{|i| loc = -i color = colors[i] x, y = @XY6["#{loc}"] TkcOval.new(@canvas, box(x, y, 5), :fill=>color, :outline=>color, :tag=>"I6_b#{i}") } draw6a(12) # The wheel end def draw6a(beta) @canvas.delete('I6_0') ox, oy = [346, 339] (0..3).each{|i| b = beta + i * 45 x, y = rotate_c(28, 0, 0, 0, b) xy = [ox + x, oy + y, ox - x, oy - y] TkcLine.new(@canvas, xy, :tag=>'I6_0', :fill=>@C['fg'], :width=>2) } end def move6(step = nil) step = get_step(6, step) return 0 if step > 62 if step < 2 # Open gate for balls to drop @canvas.move('I6_', -7, 0) if step == 1 # Poke a hole xy = [348, 226, 365, 240] TkcRectangle.new(@canvas, xy, :fill=>@canvas.itemcget('I6c', :fill), :outline=>'') end return 1 end s = step - 1 # Do the gumball drop dance (0..(((s - 1)/3).to_i)).each{|i| tag = "I6_b#{i}" break if @canvas.find_withtag(tag).empty? loc = s - 3*i if @XY6["#{loc},#{i}"] move_abs(tag, @XY6["#{loc},#{i}"]) elsif @XY6["#{loc}"] move_abs(tag, @XY6["#{loc}"]) end } if s % 3 == 1 first = (s + 2)/3 i = first loop { tag = "I6_b#{i}" break if @canvas.find_withtag(tag).empty? loc = first - i move_abs(tag, @XY6["#{loc}"]) i += 1 } end if s >= 3 # Rotate the motor idx = s % 3 draw6a(12 + s * 15) end return((s == 3)? 3 : 1) end # On/off switch def draw7 color = @C['7'] xy = [198, 306, 277, 374] # Box TkcRectangle.new(@canvas, xy, :outline=>@C['fg'], :width=>2, :fill=>color, :tag=>'I7z') @canvas.lower('I7z') xy = [275, 343, 230, 349] TkcLine.new(@canvas, xy, :tag=>'I7', :fill=>@C['fg'], :arrow=>:last, :arrowshape=>[23, 23, 8], :width=>6) xy = [225, 324] # On button x, y = xy TkcOval.new(@canvas, box(x, y, 3), :fill=>@C['fg'], :outline=>@C['fg']) xy = [218, 323] # On text font = ['Times Roman', 8] TkcText.new(@canvas, xy, :text=>'on', :anchor=>:e, :fill=>@C['fg'], :font=>font) xy = [225, 350] # Off button x, y = xy TkcOval.new(@canvas, box(x, y, 3), :fill=>@C['fg'], :outline=>@C['fg']) xy = [218, 349] # Off text TkcText.new(@canvas, xy, :text=>'off', :anchor=>:e, :fill=>@C['fg'], :font=>font) end def move7(step = nil) step = get_step(7, step) numsteps = 30 return 0 if step > numsteps beta = 30.0 / numsteps rotate_item('I7', 275, 343, beta) return((step == numsteps)? 3: 1) end # Electricity to the fan def draw8 sine([271, 248, 271, 306], 5, 8, :tag=>'I8_s', :fill=>@C['8'], :width=>3) end def move8(step = nil) step = get_step(8, step) return 0 if step > 3 if step == 0 sparkle(anchor('I8_s', :s), 'I8') return 1 elsif step == 1 move_abs('I8', anchor('I8_s', :c)) elsif step == 2 move_abs('I8', anchor('I8_s', :n)) else @canvas.delete('I8') end return((step == 2)? 3: 1) end # Fan def draw9 color = @C['9'] xy = [266, 194, 310, 220] TkcOval.new(@canvas, xy, :outline=>color, :fill=>color) xy = [280, 209, 296, 248] TkcOval.new(@canvas, xy, :outline=>color, :fill=>color) xy = [ 288, 249, 252, 249, 260, 240, 280, 234, 296, 234, 316, 240, 324, 249, 288, 249 ] TkcPolygon.new(@canvas, xy, :fill=>color, :smooth=>true) xy = [248, 205, 265, 214, 264, 205, 265, 196] # Spinner TkcPolygon.new(@canvas, xy, :fill=>color) xy = [255, 206, 265, 234] # Fan blades TkcOval.new(@canvas, xy, :fill=>'', :outline=>@C['fg'], :width=>3, :tag=>'I9_0') xy = [255, 176, 265, 204] TkcOval.new(@canvas, xy, :fill=>'', :outline=>@C['fg'], :width=>3, :tag=>'I9_0') xy = [255, 206, 265, 220] TkcOval.new(@canvas, xy, :fill=>'', :outline=>@C['fg'], :width=>1, :tag=>'I9_1') xy = [255, 190, 265, 204] TkcOval.new(@canvas, xy, :fill=>'', :outline=>@C['fg'], :width=>1, :tag=>'I9_1') end def move9(step = nil) step = get_step(9, step) if (step & 1).nonzero? @canvas.itemconfigure('I9_0', :width=>4) @canvas.itemconfigure('I9_1', :width=>1) @canvas.lower('I9_1', 'I9_0') else @canvas.itemconfigure('I9_0', :width=>1) @canvas.itemconfigure('I9_1', :width=>4) @canvas.lower('I9_0', 'I9_1') end return 3 if step == 0 return 1 end # Boat def draw10 color = @C['10a'] color2 = @C['10b'] xy = [191, 230, 233, 230, 233, 178, 191, 178] # Sail TkcPolygon.new(@canvas, xy, :fill=>color, :width=>3, :outline=>@C['fg'], :tag=>'I10') xy = box(209, 204, 31) # Front TkcArc.new(@canvas, xy, :outline=>'', :fill=>color, :style=>:pie, :start=>120, :extent=>120, :tag=>'I10') TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, :start=>120, :extent=>120, :tag=>'I10') xy = box(249, 204, 31) # Back TkcArc.new(@canvas, xy, :outline=>'', :fill=>@C['bg'], :width=>3, :style=>:pie, :start=>120, :extent=>120, :tag=>'I10') TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, :start=>120, :extent=>120, :tag=>'I10') xy = [200, 171, 200, 249] # Mast TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I10') xy = [159, 234, 182, 234] # Bow sprit TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I10') xy = [180, 234, 180, 251, 220, 251] # Hull TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>6, :tag=>'I10') xy = [92, 255, 221, 255] # Waves sine(xy, 2, 25, :fill=>color2, :width=>1, :tag=>'I10w') xy = @canvas.coords('I10w')[4..-5] # Water xy.concat([222, 266, 222, 277, 99, 277]) TkcPolygon.new(@canvas, xy, :fill=>color2, :outline=>color2) xy = [222, 266, 222, 277, 97, 277, 97, 266] # Water bottom TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) xy = box(239, 262, 17) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, :start=>95, :extent=>103) xy = box(76, 266, 21) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, :extent=>190) end def move10(step = nil) step = get_step(10, step) pos = [ [195, 212], [193, 212], [190, 212], [186, 212], [181, 212], [176, 212], [171, 212], [166, 212], [161, 212], [156, 212], [151, 212], [147, 212], [142, 212], [137, 212], [132, 212, :x], [127, 212], [121, 212], [116, 212], [111, 212] ] return 0 if step >= pos.length where = pos[step] move_abs('I10', where) return 3 if where[2] == :x return 1 end # 2nd ball drop def draw11 color = @C['11a'] color2 = @C['11b'] xy = [23, 264, 55, 591] # Color the down tube TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>'') xy = box(71, 460, 48) # Color the outer loop TkcOval.new(@canvas, xy, :fill=>color, :outline=>'') xy = [55, 264, 55, 458] # Top right side TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) xy = [55, 504, 55, 591] # Bottom right side TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) xy = box(71, 460, 48) # Outer loop TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, :start=>110, :extent=>-290, :tag=>'I11i') xy = box(71, 460, 16) # Inner loop TkcOval.new(@canvas, xy, :outline=>@C['fg'], :fill=>'', :width=>3, :tag=>'I11i') TkcOval.new(@canvas, xy, :outline=>@C['fg'], :fill=>@C['bg'], :width=>3) xy = [23, 264, 23, 591] # Left side TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) xy = box(1, 266, 23) # Top left curve TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, :extent=>90) xy = box(75, 235, 9) # The ball TkcOval.new(@canvas, xy, :fill=>color2, :outline=>'', :width=>3, :tag=>'I11') end def move11(step = nil) step = get_step(11, step) pos = [ [75, 235], [70, 235], [65, 237], [56, 240], [46, 247], [38, 266], [38, 296], [38, 333], [38, 399], [38, 475], [74, 496], [105, 472], [100, 437], [65, 423], [-100, -100], [38, 505], [38, 527, :x], [38, 591] ] return 0 if step >= pos.length where = pos[step] move_abs('I11', where) return 3 if where[2] == :x return 1 end # Hand def draw12 xy = [ 20, 637, 20, 617, 20, 610, 20, 590, 40, 590, 40, 590, 60, 590, 60, 610, 60, 610 ] xy.concat([60, 610, 65, 620, 60, 631]) # Thumb xy.concat([60, 631, 60, 637, 60, 662, 60, 669, 52, 669, 56, 669, 50, 669, 50, 662, 50, 637]) y0 = 637 # Bumps for fingers y1 = 645 50.step(21, -10){|x| x1 = x - 5 x2 = x - 10 xy << x << y0 << x1 << y1 << x2 << y0 } TkcPolygon.new(@canvas, xy, :fill=>@C['12'], :outline=>@C['fg'], :smooth=>true, :tag=>'I12', :width=>3) end def move12(step = nil) step = get_step(12, step) pos = [[42.5, 641, :x]] return 0 if step >= pos.length where = pos[step] move_abs('I12', where) return 3 if where[2] == :x return 1 end # Fax def draw13 color = @C['13a'] xy = [86, 663, 149, 663, 149, 704, 50, 704, 50, 681, 64, 681, 86, 671] xy2 = [ 784, 663, 721, 663, 721, 704, 820, 704, 820, 681, 806, 681, 784, 671 ] radii = [2, 9, 9, 8, 5, 5, 2] round_poly(@canvas, xy, radii, :width=>3, :outline=>@C['fg'], :fill=>color) round_poly(@canvas, xy2, radii, :width=>3, :outline=>@C['fg'], :fill=>color) xy = [56, 677] x, y = xy TkcRectangle.new(@canvas, box(x, y, 4), :fill=>'', :outline=>@C['fg'], :width=>3, :tag=>'I13') xy = [809, 677] x, y = xy TkcRectangle.new(@canvas, box(x, y, 4), :fill=>'', :outline=>@C['fg'], :width=>3, :tag=>'I13R') xy = [112, 687] # Label TkcText.new(@canvas, xy, :text=>'FAX', :fill=>@C['fg'], :font=>['Times Roman', 12, :bold]) xy = [762, 687] TkcText.new(@canvas, xy, :text=>'FAX', :fill=>@C['fg'], :font=>['Times Roman', 12, :bold]) xy = [138, 663, 148, 636, 178, 636] # Paper guide TkcLine.new(@canvas, xy, :smooth=>true, :fill=>@C['fg'], :width=>3) xy = [732, 663, 722, 636, 692, 636] TkcLine.new(@canvas, xy, :smooth=>true, :fill=>@C['fg'], :width=>3) sine([149, 688, 720, 688], 5, 15, :tag=>'I13_s', :fill=>@C['fg'], :width=>3) end def move13(step = nil) step = get_step(13, step) numsteps = 7 if step == numsteps + 2 move_abs('I13_star', [-100, -100]) @canvas.itemconfigure('I13R', :fill=>@C['13b'], :width=>2) return 2 end if step == 0 # Button down @canvas.delete('I13') sparkle([-100, -100], 'I13_star') # Create off screen return 1 end x0, y0 = anchor('I13_s', :w) x1, y1 = anchor('I13_s', :e) x = x0 + (x1 - x0) * (step - 1) / numsteps.to_f move_abs('I13_star', [x, y0]) return 1 end # Paper in fax def draw14 color = @C['14'] xy = [102, 661, 113, 632, 130, 618] # Left paper edge TkcLine.new(@canvas, xy, :smooth=>true, :fill=>color, :width=>3, :tag=>'I14L_0') xy = [148, 629, 125, 640, 124, 662] # Right paper edge TkcLine.new(@canvas, xy, :smooth=>true, :fill=>color, :width=>3, :tag=>'I14L_1') draw14a('L') xy = [ 768.0, 662.5, 767.991316225, 662.433786215, 767.926187912, 662.396880171 ] TkcLine.new(@canvas, xy, :smooth=>true, :fill=>color, :width=>3, :tag=>'I14R_0') @canvas.lower('I14R_0') # NB. these numbers are VERY sensitive, you must start with final size # and shrink down to get the values xy = [ 745.947897349, 662.428358855, 745.997829056, 662.452239237, 746.0, 662.5 ] TkcLine.new(@canvas, xy, :smooth=>true, :fill=>color, :width=>3, :tag=>'I14R_1') @canvas.lower('I14R_1') end def draw14a(side) color = @C['14'] xy = @canvas.coords("I14#{side}_0") xy2 = @canvas.coords("I14#{side}_1") x0, y0, x1, y1, x2, y2 = xy x3, y3, x4, y4, x5, y5 = xy2 zz = [ x0, y0, x0, y0, xy, x2, y2, x2, y2, x3, y3, x3, y3, xy2, x5, y5, x5, y5 ].flatten @canvas.delete("I14#{side}") TkcPolygon.new(@canvas, zz, :tag=>"I14#{side}", :smooth=>true, :fill=>color, :outline=>color, :width=>3) @canvas.lower("I14#{side}") end def move14(step = nil) step = get_step(14, step) # Paper going down sc = 0.9 - 0.05*step if sc < 0.3 @canvas.delete('I14L') return 0 end ox, oy = @canvas.coords('I14L_0') @canvas.scale('I14L_0', ox, oy, sc, sc) ox, oy = @canvas.coords('I14L_1')[-2..-1] @canvas.scale('I14L_1', ox, oy, sc, sc) draw14a('L') # Paper going up sc = 0.35 + 0.05*step sc = 1/sc ox, oy = @canvas.coords('I14R_0') @canvas.scale('I14R_0', ox, oy, sc, sc) ox, oy = @canvas.coords('I14R_1')[-2..-1] @canvas.scale('I14R_1', ox, oy, sc, sc) draw14a('R') return((step == 10)? 3: 1) end # Light beam def draw15 color = @C['15a'] xy = [824, 599, 824, 585, 820, 585, 829, 585] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I15a') xy = [789, 599, 836, 643] TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>3) xy = [778, 610, 788, 632] TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>3) xy = [766, 617, 776, 625] TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>3) xy = [633, 600, 681, 640] TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>3) xy = [635, 567, 657, 599] TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>2) xy = [765, 557, 784, 583] TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>2) sine([658, 580, 765, 580], 3, 15, :tag=>'I15_s', :fill=>@C['fg'], :width=>3) end def move15a color = @C['15b'] @canvas.scale('I15a', 824, 599, 1, 0.3) # Button down xy = [765, 621, 681, 621] TkcLine.new(@canvas, xy, :dash=>'-', :width=>3, :fill=>color, :tag=>'I15') end def move15(step = nil) step = get_step(15, step) numsteps = 6 if step == numsteps + 2 move_abs('I15_star', [-100, -100]) return 2 end if step == 0 # Break the light beam sparkle([-100, -100], 'I15_star') xy = [765, 621, 745, 621] @canvas.coords('I15', xy) return 1 end x0, y0 = anchor('I15_s', :w) x1, y1 = anchor('I15_s', :e) x = x0 + (x1 - x0) * (step - 1) / numsteps.to_f move_abs('I15_star', [x, y0]) return 1 end # Bell def draw16 color = @C['16'] xy = [722, 485, 791, 556] TkcRectangle.new(@canvas, xy, :fill=>'', :outline=>@C['fg'], :width=>3) xy = box(752, 515, 25) # Bell TkcOval.new(@canvas, xy, :fill=>color, :outline=>'black', :tag=>'I16b', :width=>2) xy = box(752, 515, 5) # Bell button TkcOval.new(@canvas, xy, :fill=>'black', :outline=>'black', :tag=>'I16b') xy = [784, 523, 764, 549] # Clapper TkcLine.new(@canvas, xy, :width=>3, :tag=>'I16c', :fill=>@C['fg']) xy = box(784, 523, 4) TkcOval.new(@canvas, xy, :fill=>@C['fg'], :outline=>@C['fg'], :tag=>'I16d') end def move16(step = nil) step = get_step(16, step) # Note: we never stop ox, oy = [760, 553] if (step & 1).nonzero? beta = 12 @canvas.move('I16b', 3, 0) else beta = -12 @canvas.move('I16b', -3, 0) end rotate_item('I16c', ox, oy, beta) rotate_item('I16d', ox, oy, beta) return ((step == 1)? 3: 1) end # Cat def draw17 color = @C['17'] xy = [584, 556, 722, 556] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) xy = [584, 485, 722, 485] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) xy = [664, 523, 717, 549] # Body TkcArc.new(@canvas, xy, :outline=>@C['fg'], :fill=>color, :width=>3, :style=>:chord, :start=>128, :extent=>260, :tag=>'I17') xy = [709, 554, 690, 543] # Paw TkcOval.new(@canvas, xy, :outline=>@C['fg'], :fill=>color, :width=>3, :tag=>'I17') xy = [657, 544, 676, 555] TkcOval.new(@canvas, xy, :outline=>@C['fg'], :fill=>color, :width=>3, :tag=>'I17') xy = box(660, 535, 15) # Lower face TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, :start=>150, :extent=>240, :tag=>'I17_') TkcArc.new(@canvas, xy, :outline=>'', :fill=>color, :width=>1, :style=>:chord, :start=>150, :extent=>240, :tag=>'I17_') xy = [674, 529, 670, 513, 662, 521, 658, 521, 650, 513, 647, 529] # Ears TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') TkcPolygon.new(@canvas, xy, :fill=>color, :outline=>'', :width=>1, :tag=>['I17_', 'I17_c']) xy = [652, 542, 628, 539] # Whiskers TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') xy = [652, 543, 632, 545] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') xy = [652, 546, 632, 552] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') xy = [668, 543, 687, 538] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>['I17_', 'I17_w']) xy = [668, 544, 688, 546] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>['I17_', 'I17_w']) xy = [668, 547, 688, 553] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>['I17_', 'I17_w']) xy = [649, 530, 654, 538, 659, 530] # Left eye TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2, :smooth=>true, :tag=>'I17') xy = [671, 530, 666, 538, 661, 530] # Right eye TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2, :smooth=>true, :tag=>'I17') xy = [655, 543, 660, 551, 665, 543] # Mouth TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2, :smooth=>true, :tag=>'I17') end def move17(step = nil) step = get_step(17, step) if step == 0 @canvas.delete('I17') # Delete most of the cat xy = [655, 543, 660, 535, 665, 543] # Mouth TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :smooth=>true, :tag=>'I17_') xy = box(654, 530, 4) # Left eye TkcOval.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :fill=>'', :tag=>'I17_') xy = box(666, 530, 4) # Right eye TkcOval.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :fill=>'', :tag=>'I17_') @canvas.move('I17_', 0, -20) # Move face up xy = [652, 528, 652, 554] # Front leg TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') xy = [670, 528, 670, 554] # 2nd front leg TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') xy = [ # Body 675, 506, 694, 489, 715, 513, 715, 513, 715, 513, 716, 525, 716, 525, 716, 525, 706, 530, 695, 530, 679, 535, 668, 527, 668, 527, 668, 527, 675, 522, 676, 517, 677, 512 ] TkcPolygon.new(@canvas, xy, :fill=>@canvas.itemcget('I17_c', :fill), :outline=>@C['fg'], :width=>3, :smooth=>true, :tag=>'I17_') xy = [716, 514, 716, 554] # Back leg TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') xy = [694, 532, 694, 554] # 2nd back leg TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') xy = [715, 514, 718, 506, 719, 495, 716, 488] # Tail TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :smooth=>true, :tag=>'I17_') @canvas.raise('I17w') # Make whiskers visible @canvas.move('I17_', -5, 0) # Move away from the wall a bit return 2 end return 0 end # Sling shot def draw18 color = @C['18'] xy = [721, 506, 627, 506] # Sling hold TkcLine.new(@canvas, xy, :width=>4, :fill=>@C['fg'], :tag=>'I18') xy = [607, 500, 628, 513] # Sling rock TkcOval.new(@canvas, xy, :fill=>color, :outline=>'', :tag=>'I18a') xy = [526, 513, 606, 507, 494, 502] # Sling band TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>4, :tag=>'I18b') xy = [485, 490, 510, 540, 510, 575, 510, 540, 535, 491] # Sling TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>6) end def move18(step = nil) step = get_step(18, step) pos = [ [587, 506], [537, 506], [466, 506], [376, 506], [266, 506, :x], [136, 506], [16, 506], [-100, -100] ] b = [] b[0] = [490, 502, 719, 507, 524, 512] # Band collapsing b[1] = [ 491, 503, 524, 557, 563, 505, 559, 496, 546, 506, 551, 525, 553, 536, 538, 534, 532, 519, 529, 499 ] b[2] = [ 491, 503, 508, 563, 542, 533, 551, 526, 561, 539, 549, 550, 530, 500 ] b[3] = [ 491, 503, 508, 563, 530, 554, 541, 562, 525, 568, 519, 544, 530, 501 ] return 0 if step >= pos.length if step == 0 @canvas.delete('I18') @canvas.itemconfigure('I18b', :smooth=>true) end if b[step] @canvas.coords('I18b', b[step]) end where = pos[step] move_abs('I18a', where) return 3 if where[2] == :x return 1 end # Water pipe def draw19 color = @C['19'] xx = [[249, 181], [155, 118], [86, 55], [22, 0]] xx.each{|x1, x2| TkcRectangle.new(@canvas, x1, 453, x2, 467, :fill=>color, :outline=>'', :tag=>'I19') TkcLine.new(@canvas, x1, 453, x2, 453, :fill=>@C['fg'], :width=>1) # Pipe top TkcLine.new(@canvas, x1, 467, x2, 467, :fill=>@C['fg'], :width=>1) # Pipe bottom } @canvas.raise('I11i') xy = box(168, 460, 16) # Bulge by the joint TkcOval.new(@canvas, xy, :fill=>color, :outline=>'') TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>21, :extent=>136) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>-21, :extent=>-130) xy = [249, 447, 255, 473] # First joint 26x6 TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>1) xy = box(257, 433, 34) # Bend up TkcArc.new(@canvas, xy, :outline=>'', :fill=>color, :width=>1, :style=>:pie, :start=>0, :extent=>-91) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>0, :extent=>-90) xy = box(257, 433, 20) TkcArc.new(@canvas, xy, :outline=>'', :fill=>@C['bg'], :width=>1, :style=>:pie, :start=>0, :extent=>-92) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>0, :extent=>-90) xy = box(257, 421, 34) # Bend left TkcArc.new(@canvas, xy, :outline=>'', :fill=>color, :width=>1, :style=>:pie, :start=>0, :extent=>91) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>0, :extent=>90) xy = box(257, 421, 20) TkcArc.new(@canvas, xy, :outline=>'', :fill=>@C['bg'], :width=>1, :style=>:pie, :start=>0, :extent=>90) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>0, :extent=>90) xy = box(243, 421, 34) # Bend down TkcArc.new(@canvas, xy, :outline=>'', :fill=>color, :width=>1, :style=>:pie, :start=>90, :extent=>90) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>90, :extent=>90) xy = box(243, 421, 20) TkcArc.new(@canvas, xy, :outline=>'', :fill=>@C['bg'], :width=>1, :style=>:pie, :start=>90, :extent=>90) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>90, :extent=>90) xy = [270, 427, 296, 433] # 2nd joint bottom TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>1) xy = [270, 421, 296, 427] # 2nd joint top TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>1) xy = [249, 382, 255, 408] # Third joint right TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>1) xy = [243, 382, 249, 408] # Third joint left TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>1) xy = [203, 420, 229, 426] # Last joint TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>1) xy = box(168, 460, 6) # Handle joint TkcOval.new(@canvas, xy, :fill=>@C['fg'], :outline=>'', :tag=>'I19a') xy = [168, 460, 168, 512] # Handle bar TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>5, :tag=>'I19b') end def move19(step = nil) step = get_step(19, step) angles = [30, 30, 30] return 2 if step == angles.length ox, oy = centroid('I19a') rotate_item('I19b', ox, oy, angles[step]) return 1 end # Water pouring def draw20 # do nothing end def move20(step = nil) step = get_step(20, step) pos = [451, 462, 473, 484, 496, 504, 513, 523, 532] freq = [20, 40, 40, 40, 40, 40, 40, 40, 40] pos = [ [451, 20], [462, 40], [473, 40], [484, 40], [496, 40], [504, 40], [513, 40], [523, 40], [532, 40, :x] ] return 0 if step >= pos.length @canvas.delete('I20') where = pos[step] y, f = where h20(y, f) return 3 if where[2] == :x return 1 end def h20(y, f) color = @C['20'] @canvas.delete('I20') sine([208, 428, 208, y], 4, f, :tag=>['I20', 'I20s'], :width=>3, :fill=>color, :smooth=>true) TkcLine.new(@canvas, @canvas.coords('I20s'), :width=>3, :fill=>color, :smooth=>1, :tag=>['I20', 'I20a']) TkcLine.new(@canvas, @canvas.coords('I20s'), :width=>3, :fill=>color, :smooth=>1, :tag=>['I20', 'I20b']) @canvas.move('I20a', 8, 0) @canvas.move('I20b', 16, 0) end # Bucket def draw21 color = @C['21'] xy = [217, 451, 244, 490] # Right handle TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2, :tag=>'I21_a') xy = [201, 467, 182, 490] # Left handle TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2, :tag=>'I21_a') xy = [245, 490, 237, 535] # Right side xy2 = [189, 535, 181, 490] # Left side TkcPolygon.new(@canvas, xy + xy2, :fill=>color, :outline=>'', :tag=>['I21', 'I21f']) TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2, :tag=>'I21') TkcLine.new(@canvas, xy2, :fill=>@C['fg'], :width=>2, :tag=>'I21') xy = [182, 486, 244, 498] # Top TkcOval.new(@canvas, xy, :fill=>color, :outline=>'', :width=>2, :tag=>['I21', 'I21f']) TkcOval.new(@canvas, xy, :fill=>'', :outline=>@C['fg'], :width=>2, :tag=>['I21', 'I21t']) xy = [189, 532, 237, 540] # Bottom TkcOval.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>2, :tag=>['I21', 'I21b']) end def move21(step = nil) step = get_step(21, step) numsteps = 30 return 0 if step >= numsteps x1, y1, x2, y2 = @canvas.coords('I21b') # lx1, ly1, lx2, ly2 = @canvas.coords('I21t') lx1, ly1, lx2, ly2 = [183, 492, 243, 504] f = step / numsteps.to_f y2 = y2 - 3 xx1 = x1 + (lx1 - x1) * f yy1 = y1 + (ly1 - y1) * f xx2 = x2 + (lx2 - x2) * f yy2 = y2 + (ly2 - y2) * f @canvas.itemconfigure('I21b', :fill=>@C['20']) @canvas.delete('I21w') TkcPolygon.new(@canvas, x2, y2, x1, y1, xx1, yy1, xx2, yy1, :tag=>['I21', 'I21w'], :outline=>'', :fill=>@C['20']) @canvas.lower('I21w', 'I21') @canvas.raise('I21b') @canvas.lower('I21f') return((step == numsteps - 1)? 3: 1) end # Bucket drop def draw22 # do nothing end def move22(step = nil) step = get_step(22, step) pos = [[213, 513], [213, 523], [213, 543, :x], [213, 583], [213, 593]] @canvas.itemconfigure('I21f', :fill=>@C['22']) if step == 0 return 0 if step >= pos.length where = pos[step] move_abs('I21', where) h20(where[1], 40) @canvas.delete('I21_a') # Delete handles return 3 if where[2] == :x return 1 end # Blow dart def draw23 color = @C['23a'] color2 = @C['23b'] color3 = @C['23c'] xy = [185, 623, 253, 650] # Block TkcRectangle.new(@canvas, xy, :fill=>'black', :outline=>@C['fg'], :width=>2, :tag=>'I23a') xy = [187, 592, 241, 623] # Balloon TkcOval.new(@canvas, xy, :outline=>'', :fill=>color, :tag=>'I23b') TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :tag=>'I23b', :style=>:arc, :start=>12, :extent=>336) xy = [239, 604, 258, 589, 258, 625, 239, 610] # Balloon nozzle TkcPolygon.new(@canvas, xy, :outline=>'', :fill=>color, :tag=>'I23b') TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I23b') xy = [285, 611, 250, 603] # Dart body TkcOval.new(@canvas, xy, :fill=>color2, :outline=>@C['fg'], :width=>3, :tag=>'I23d') xy = [249, 596, 249, 618, 264, 607, 249, 596] # Dart tail TkcPolygon.new(@canvas, xy, :fill=>color3, :outline=>@C['fg'], :width=>3, :tag=>'I23d') xy = [249, 607, 268, 607] # Dart detail TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I23d') xy = [285, 607, 305, 607] # Dart needle TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I23d') end def move23(step = nil) step = get_step(23, step) pos = [ [277, 607], [287, 607], [307, 607, :x], [347, 607], [407, 607], [487, 607], [587, 607], [687, 607], [787, 607], [-100, -100] ] return 0 if step >= pos.length if step <= 1 ox, oy = anchor('I23a', :n) @canvas.scale('I23b', ox, oy, 0.9, 0.5) end where = pos[step] move_abs('I23d', where) return 3 if where[2] == :x return 1 end # Balloon def draw24 color = @C['24a'] xy = [366, 518, 462, 665] # Balloon TkcOval.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>3, :tag=>'I24') xy = [414, 666, 414, 729] # String TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I24') xy = [410, 666, 404, 673, 422, 673, 418, 666] # Nozzle TkcPolygon.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>3, :tag=>'I24') xy = [387, 567, 390, 549, 404, 542] # Reflections TkcLine.new(@canvas, xy, :fill=>@C['fg'], :smooth=>true, :width=>2, :tag=>'I24') xy = [395, 568, 399, 554, 413, 547] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :smooth=>true, :width=>2, :tag=>'I24') xy = [403, 570, 396, 555, 381, 553] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :smooth=>true, :width=>2, :tag=>'I24') xy = [408, 564, 402, 547, 386, 545] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :smooth=>true, :width=>2, :tag=>'I24') end def move24(step = nil) step = get_step(24, step) return 0 if step > 4 return 2 if step == 4 if step == 0 @canvas.delete('I24') # Exploding balloon xy = [ 347, 465, 361, 557, 271, 503, 272, 503, 342, 574, 259, 594, 259, 593, 362, 626, 320, 737, 320, 740, 398, 691, 436, 738, 436, 739, 476, 679, 528, 701, 527, 702, 494, 627, 548, 613, 548, 613, 480, 574, 577, 473, 577, 473, 474, 538, 445, 508, 431, 441, 431, 440, 400, 502, 347, 465, 347, 465 ] TkcPolygon.new(@canvas, xy, :tag=>'I24', :fill=>@C['24b'], :outline=>@C['24a'], :width=>10, :smooth=>true) msg = Tk.subst(@S['message'].value) TkcText.new(@canvas, centroid('I24'), :text=>msg, :tag=>['I24', 'I24t'], :justify=>:center, :font=>['Times Roman', 18, :bold]) return 1 end @canvas.itemconfigure('I24t', :font=>['Times Roman', 18 + 6*step, :bold]) @canvas.move('I24', 0, -60) ox, oy = centroid('I24') @canvas.scale('I24', ox, oy, 1.25, 1.25) return 1 end # Displaying the message def move25(step = nil) step = get_step(25, step) if step == 0 @XY['25'] = Tk::Clock.clicks(:miliseconds) return 1 end elapsed = Tk::Clock.clicks(:miliseconds) - @XY['25'] return 1 if elapsed < 5000 return 2 end # Collapsing balloon def move26(step = nil) step = get_step(26, step) if step >= 3 @canvas.delete('I24', 'I26') TkcText.new(@canvas, 430, 740, :anchor=>:s, :tag=>'I26', :text=>'click to continue', :font=>['Times Roman', 24, :bold]) @canvas.bind('1', proc{reset}) return 4 end ox, oy = centroid('I24') @canvas.scale('I24', ox, oy, 0.8, 0.8) @canvas.move('I24', 0, 60) @canvas.itemconfigure('I24t', :font=>['Times Roman', 30 - 6*step, :bold]) return 1 end ################################################################ # # Helper functions # def box(x, y, r) [x - r, y - r, x + r, y + r] end def move_abs(item, xy) x, y = xy ox, oy = centroid(item) dx = x - ox dy = y - oy @canvas.move(item, dx, dy) end def rotate_item(item, ox, oy, beta) xy = @canvas.coords(item) xy2 = [] 0.step(xy.length - 1, 2){|idx| x, y = xy[idx, 2] xy2.concat(rotate_c(x, y, ox, oy, beta)) } @canvas.coords(item, xy2) end def rotate_c(x, y, ox, oy, beta) # rotates vector (ox,oy)->(x,y) by beta degrees clockwise x -= ox # Shift to origin y -= oy beta = beta * Math.atan(1) * 4 / 180.0 # Radians xx = x * Math.cos(beta) - y * Math.sin(beta) # Rotate yy = x * Math.sin(beta) + y * Math.cos(beta) xx += ox # Shift back yy += oy [xx, yy] end def reset draw_all @canvas.bind_remove('1') @S['mode'].value = :MSTART @S['active'] = [0] end # Each Move## keeps its state info in STEP, this retrieves and increments it def get_step(who, step) if step @STEP[who] = step else if !@STEP.exist?(who) || @STEP[who] == "" @STEP[who] = 0 else @STEP[who] += 1 end end @STEP[who] end def reset_step @S['cnt'].value = 0 @STEP.keys.each{|k| @STEP[k] = ''} end def sine(xy0, amp, freq, opts = {}) x0, y0, x1, y1 = xy0 step = 2 xy = [] if y0 == y1 # Horizontal x0.step(x1, step){|x| beta = (x - x0) * 2 * Math::PI / freq y = y0 + amp * Math.sin(beta) xy << x << y } else y0.step(y1, step){|y| beta = (y - y0) * 2 * Math::PI / freq x = x0 + amp * Math.sin(beta) xy << x << y } end TkcLine.new(@canvas, xy, opts) end def round_rect(xy, radius, opts={}) x0, y0, x3, y3 = xy r = @canvas.winfo_pixels(radius) d = 2 * r # Make sure that the radius of the curve is less than 3/8 size of the box! maxr = 0.75 if d > maxr * (x3 - x0) d = maxr * (x3 - x0) end if d > maxr * (y3 - y0) d = maxr * (y3 - y0) end x1 = x0 + d x2 = x3 - d y1 = y0 + d y2 = y3 - d xy = [x0, y0, x1, y0, x2, y0, x3, y0, x3, y1, x3, y2] xy.concat([x3, y3, x2, y3, x1, y3, x0, y3, x0, y2, x0, y1]) return xy end def round_poly(canv, xy, radii, opts) lenXY = xy.length lenR = radii.length if lenXY != 2*lenR raise "wrong number of vertices and radii" end knots = [] x0 = xy[-2]; y0 = xy[-1] x1 = xy[0]; y1 = xy[1] xy << xy[0] << xy[1] 0.step(lenXY - 1, 2){|i| radius = radii[i/2] r = canv.winfo_pixels(radius) x2 = xy[i+2]; y2 = xy[i+3] z = _round_poly2(x0, y0, x1, y1, x2, y2, r) knots.concat(z) x0 = x1; y0 = y1 x1 = x2; y1 = y2 } TkcPolygon.new(canv, knots, {:smooth=>true}.update(opts)) end def _round_poly2(x0, y0, x1, y1, x2, y2, radius) d = 2 * radius maxr = 0.75 v1x = x0 - x1 v1y = y0 - y1 v2x = x2 - x1 v2y = y2 - y1 vlen1 = Math.sqrt(v1x*v1x + v1y*v1y) vlen2 = Math.sqrt(v2x*v2x + v2y*v2y) if d > maxr * vlen1 d = maxr * vlen1 end if d > maxr * vlen2 d = maxr * vlen2 end xy = [] xy << (x1 + d * v1x / vlen1) << (y1 + d * v1y / vlen1) xy << x1 << y1 xy << (x1 + d * v2x / vlen2) << (y1 + d * v2y / vlen2) return xy end def sparkle(oxy, tag) xy = [ [299, 283], [298, 302], [295, 314], [271, 331], [239, 310], [242, 292], [256, 274], [281, 273] ] xy.each{|x, y| TkcLine.new(@canvas, 271, 304, x, y, :fill=>'white', :width=>3, :tag=>tag) } move_abs(tag, oxy) end def centroid(item) anchor(item, :c) end def anchor(item, where) x1, y1, x2, y2 = @canvas.bbox(item) case(where) when :n y = y1 when :s y = y2 else y = (y1 + y2) / 2.0 end case(where) when :w x = x1 when :e x = x2 else x = (x1 + x2) / 2.0 end return [x, y] end end TkGoldberg_Demo.new(base_frame) ================================================ FILE: ext/tk/sample/demos-en/hello ================================================ #!/usr/bin/env ruby require 'tk' #unless /^8\.[1-9]/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK # require 'tkencoding' #end TkButton.new(nil, 'text'=>"Hello Ruby world!", 'font'=>TkFont.new('k14'), 'command'=>proc{print "Hello Ruby world!\n"; exit} ).pack Tk.mainloop ================================================ FILE: ext/tk/sample/demos-en/hscale.rb ================================================ require "tkcanvas" if defined?($hscale_demo) && $hscale_demo $hscale_demo.destroy $hscale_demo = nil end $hscale_demo = TkToplevel.new {|w| title("Horizontal Scale Demonstration") iconname("hscale") } positionWindow($hscale_demo) base_frame = TkFrame.new($hscale_demo).pack(:fill=>:both, :expand=>true) msg = TkLabel.new(base_frame) { font $font wraplength '3.5i' justify 'left' text "An arrow and a horizontal scale are displayed below. If you click or drag mouse button 1 in the scale, you can change the length of the arrow." } msg.pack('side'=>'top') TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc { tmppath = $hscale_demo $hscale_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc { showCode 'hscale' } }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') def setWidth(w, width) width = width + 21 x2 = width - 30 if x2 < 21 x2 = 21 end w.coords 'poly',20,15,20,35,x2,35,x2,45,width,25,x2,5,x2,15,20,15 w.coords 'line',20,15,20,35,x2,35,x2,45,width,25,x2,5,x2,15,20,15 end TkFrame.new(base_frame) {|frame| canvas = TkCanvas.new(frame) {|c| width 50 height 50 bd 0 highlightthickness 0 TkcPolygon.new(c, '0', '0', '1', '1', '2', '2') { fill 'DeepSkyBlue' tags 'poly' } TkcLine.new(c, '0', '0', '1', '1', '2', '2', '0', '0') { fill 'black' tags 'line' } }.pack('side'=>'top', 'expand'=>'yes', 'anchor'=>'s', 'fill'=>'x', 'padx'=>'15') scale = TkScale.new(frame) { orient 'horizontal' length 284 from 0 to 250 command proc{|value| setWidth(canvas, value)} tickinterval 50 }.pack('side'=>'bottom', 'expand'=>'yes', 'anchor'=>'n') scale.set 75 }.pack('side'=>'top', 'fill'=>'x') ================================================ FILE: ext/tk/sample/demos-en/icon.rb ================================================ # icon.rb # # This demonstration script creates a toplevel window containing # buttons that display bitmaps instead of text. # # iconic button widget demo (called by 'widget') # # toplevel widget if defined?($icon_demo) && $icon_demo $icon_demo.destroy $icon_demo = nil end # demo toplevel widget $icon_demo = TkToplevel.new {|w| title("Iconic Button Demonstration") iconname("icon") positionWindow(w) } base_frame = TkFrame.new($icon_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '5i' justify 'left' text "This window shows three ways of using bitmaps or images in radiobuttons and checkbuttons. On the left are two radiobuttons, each of which displays a bitmap and an indicator. In the middle is a checkbutton that displays a different image depending on whether it is selected or not. On the right is a checkbutton that displays a single bitmap but changes its background color to indicate whether or not it is selected. (This change is visible when the mouse pointer is not directy over the button.)" } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $icon_demo $icon_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'icon'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # image flagup = \ TkBitmapImage.new('file'=>[$demo_dir,'..', 'images','flagup.xbm'].join(File::Separator), 'maskfile'=>\ [$demo_dir,'..','images','flagup.xbm'].join(File::Separator)) flagdown = \ TkBitmapImage.new('file'=>[$demo_dir,'..', 'images','flagdown.xbm'].join(File::Separator), 'maskfile'=>\ [$demo_dir,'..', 'images','flagdown.xbm'].join(File::Separator)) # create variable letters = TkVariable.new # frame TkFrame.new(base_frame, 'borderwidth'=>10){|w| TkFrame.new(w) {|f| # TkRadioButton.new(f){ Tk::RadioButton.new(f){ bitmap '@' + [$demo_dir,'..', 'images','letters.xbm'].join(File::Separator) variable letters value 'full' }.pack('side'=>'top', 'expand'=>'yes') # TkRadioButton.new(f){ Tk::RadioButton.new(f){ bitmap '@' + [$demo_dir,'..', 'images','noletter.xbm'].join(File::Separator) variable letters value 'empty' }.pack('side'=>'top', 'expand'=>'yes') }.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'5m') # TkCheckButton.new(w) { Tk::CheckButton.new(w) { image flagdown selectimage flagup indicatoron 0 selectcolor self['background'] }.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'5m') # TkCheckButton.new(w) { Tk::CheckButton.new(w) { bitmap '@' + [$demo_dir,'..', 'images','letters.xbm'].join(File::Separator) indicatoron 0 selectcolor 'SeaGreen1' }.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'5m') }.pack('side'=>'top') ================================================ FILE: ext/tk/sample/demos-en/image1.rb ================================================ ## image1.rb # # This demonstration script displays two image widgets. # # two image widgets demo (called by 'widget') # # toplevel widget if defined?($image1_demo) && $image1_demo $image1_demo.destroy $image1_demo = nil end # demo toplevel widget $image1_demo = TkToplevel.new {|w| title('Image Demonstration #1') iconname("Image1") positionWindow(w) } base_frame = TkFrame.new($image1_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "This demonstration displays two images, each in a separate label widget." } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $image1_demo $image1_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'image1'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # image image1a = \ TkPhotoImage.new('file'=>[$demo_dir,'..', 'images','earth.gif'].join(File::Separator)) image1b = \ TkPhotoImage.new('file'=>[$demo_dir,'..', 'images','earthris.gif'].join(File::Separator)) # label #[ TkLabel.new(base_frame, 'image'=>image1a, 'bd'=>1, 'relief'=>'sunken'), # TkLabel.new(base_frame, 'image'=>image1b, 'bd'=>1, 'relief'=>'sunken') #].each{|w| w.pack('side'=>'top', 'padx'=>'.5m', 'pady'=>'.5m')} [ Tk::Label.new(base_frame, 'image'=>image1a, 'bd'=>1, 'relief'=>'sunken'), Tk::Label.new(base_frame, 'image'=>image1b, 'bd'=>1, 'relief'=>'sunken') ].each{|w| w.pack('side'=>'top', 'padx'=>'.5m', 'pady'=>'.5m')} ================================================ FILE: ext/tk/sample/demos-en/image2.rb ================================================ # image2.rb # # This demonstration script creates a simple collection of widgets # that allow you to select and view images in a Tk label. # # widget demo 'load image' (called by 'widget') # # toplevel widget if defined?($image2_demo) && $image2_demo $image2_demo.destroy $image2_demo = nil end # demo toplevel widget $image2_demo = TkToplevel.new {|w| title('Image Demonstration #2') iconname("Image2") positionWindow(w) } base_frame = TkFrame.new($image2_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "This demonstration allows you to view images using a Tk \"photo\" image. First type a directory name in the listbox, then press Enter to load the directory into the listbox. Then double-click on a file name in the listbox to see that image." } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $image2_demo $image2_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'image2'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # create variable $dirName = TkVariable.new([$demo_dir,'..','images'].join(File::Separator)) # image $image2a = TkPhotoImage.new # TkLabel.new(base_frame, 'text'=>'Directory:')\ .pack('side'=>'top', 'anchor'=>'w') image2_e = TkEntry.new(base_frame) { width 30 textvariable $dirName }.pack('side'=>'top', 'anchor'=>'w') TkFrame.new(base_frame, 'height'=>'3m', 'width'=>20)\ .pack('side'=>'top', 'anchor'=>'w') TkLabel.new(base_frame, 'text'=>'File:')\ .pack('side'=>'top', 'anchor'=>'w') TkFrame.new(base_frame){|w| s = TkScrollbar.new(w) l = TkListbox.new(w) { width 20 height 10 yscrollcommand proc{|first,last| s.set first,last} } s.command(proc{|*args| l.yview(*args)}) l.pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y') s.pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y') #l.insert(0,'earth.gif', 'earthris.gif', 'mickey.gif', 'teapot.ppm') l.insert(0,'earth.gif', 'earthris.gif', 'teapot.ppm') l.bind('Double-1', proc{|x,y| loadImage $image2a,l,x,y}, '%x %y') image2_e.bind 'Return', proc{loadDir l} }.pack('side'=>'top', 'anchor'=>'w') # image [ TkFrame.new(base_frame, 'height'=>'3m', 'width'=>20), TkLabel.new(base_frame, 'text'=>'Image:'), TkLabel.new(base_frame, 'image'=>$image2a) ].each{|w| w.pack('side'=>'top', 'anchor'=>'w')} # def loadDir(w) w.delete(0,'end') Dir.glob([$dirName,'*'].join(File::Separator)).sort.each{|f| w.insert('end',File.basename(f)) } end def loadImage(img,w,x,y) img.file([$dirName, w.get("@#{x},#{y}")].join(File::Separator)) end ================================================ FILE: ext/tk/sample/demos-en/image3.rb ================================================ # image3.rb # # This demonstration script creates a simple collection of widgets # that allow you to select and view images in a Tk label. # # widget demo 'load image' (called by 'widget') # # toplevel widget if defined?($image3_demo) && $image3_demo $image3_demo.destroy $image3_demo = nil end # demo toplevel widget $image3_demo = TkToplevel.new {|w| title('Image Demonstration #3') iconname("Image3") positionWindow(w) } base_frame = TkFrame.new($image3_demo).pack(:fill=>:both, :expand=>true) # def loadDir3(w) w.delete(0,'end') Dir.glob([$dirName,'*'].join(File::Separator)).sort.each{|f| w.insert('end',File.basename(f)) } end # selectAndLoadDir3 -- # This procedure pops up a dialog to ask for a directory to load into # the listobx and (if the user presses OK) reloads the directory # listbox from the directory named in the demo's entry. # # Arguments: # w - Name of the toplevel window of the demo. def selectAndLoadDir3(w, lbox) dir = Tk.chooseDirectory(:initialdir=>$dirName.value, :parent=>w, :mustexist=>true) if dir.length > 0 $dirName.value = dir loadDir3(lbox) end end def loadImage(w,x,y) $image3a.file([$dirName, w.get("@#{x},#{y}")].join(File::Separator)) end # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "This demonstration allows you to view images using a Tk \"photo\" image. First type a directory name in the listbox, then type Return to load the directory into the listbox. Then double-click on a file name in the listbox to see that image." } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $image3_demo $image3_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'image3'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # variable $dirName = TkVariable.new([$demo_dir,'..','images'].join(File::Separator)) # image begin $image3a.delete rescue end $image3a = TkPhotoImage.new # image3_f = TkFrame.new(base_frame).pack(:fill=>:both, :expand=>true) image3_df = TkLabelFrame.new(base_frame, :text=>'Directory:') image3_ff = TkLabelFrame.new(base_frame, :text=>'File:', :padx=>'2m', :pady=>'2m') image3_lbx = TkListbox.new(image3_ff, :width=>20, :height=>10) { pack(:side=>:left, :fill=>:y, :expand=>true) yscrollbar(TkScrollbar.new(image3_ff).pack(:side=>:left, :fill=>:y, :expand=>true)) insert(0, *(%w(earth.gif earthris.gif teapot.ppm))) bind('Double-1', proc{|x,y| loadImage(self, x, y)}, '%x %y') } image3_ent = TkEntry.new(image3_df, :width=>30, :textvariable=>$dirName){ pack(:side=>:left, :fill=>:both, :padx=>'2m', :pady=>'2m', :expand=>true) bind('Return', proc{loadDir3(image3_lbx)}) } TkButton.new(image3_df, :pady=>0, :padx=>'2m', :text=>"Select Dir.", :command=>proc{selectAndLoadDir3(image3_ent, image3_lbx)}) { pack(:side=>:left, :fill=>:y, :padx=>[0, '2m'], :pady=>'2m') } image3_if = TkLabelFrame.new(base_frame, :text=>'Image:') {|f| # TkLabel.new(f, :image=>$image3a).pack(:padx=>'2m', :pady=>'2m') Tk::Label.new(f, :image=>$image3a).pack(:padx=>'2m', :pady=>'2m') } Tk.grid(image3_df, '-', :sticky=>:ew, :padx=>'1m', :pady=>'1m', :in=>image3_f) Tk.grid(image3_ff, image3_if, :sticky=>:nw, :padx=>'1m', :pady=>'1m', :in=>image3_f) TkGrid.columnconfigure(image3_f, 1, :weight=>1) ================================================ FILE: ext/tk/sample/demos-en/items.rb ================================================ # items.rb # # This demonstration script creates a canvas that displays the # canvas item types. # # canvas item types widget demo (called by 'widget') # # toplevel widget if defined?($items_demo) && $items_demo $items_demo.destroy $items_demo = nil end # demo toplevel widget $items_demo = TkToplevel.new {|w| title("Canvas Item Demonstration") iconname("Items") positionWindow(w) } base_frame = TkFrame.new($items_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame) { font $font wraplength '5i' justify 'left' text "This window contains a canvas widget with examples of the various kinds of items supported by canvases. The following operations are supported:\n Button-1 drag:\tmoves item under pointer.\n Button-2 drag:\trepositions view.\n Button-3 drag:\tstrokes out area.\n Ctrl+f:\t\tprints items under area." }.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $items_demo $items_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'items'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame cvs = nil TkFrame.new(base_frame) {|cf| # canvas cvs = TkCanvas.new(cf) {|c| focus scrollregion '0c 0c 30c 24c' width '15c' height '10c' relief 'sunken' borderwidth 2 hs = TkScrollbar.new(cf) {|s| orient 'horizontal' command proc{|*args| c.xview(*args)} c.xscrollcommand proc{|first,last| s.set first,last} } vs = TkScrollbar.new(cf) {|s| command proc{|*args| c.yview(*args)} c.yscrollcommand proc{|first,last| s.set first,last} } if $tk_version =~ /^4\.[01]/ hs.pack('side'=>'bottom', 'fill'=>'x') vs.pack('side'=>'right', 'fill'=>'y') c.pack('in'=>cf, 'expand'=>'yes', 'fill'=>'both') else c.grid('in'=>cf, 'row'=>0, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') vs.grid('row'=>0, 'column'=>1, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') hs.grid('row'=>1, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') TkGrid.rowconfigure(cf, 0, 'weight'=>1, 'minsize'=>0) TkGrid.columnconfigure(cf, 0, 'weight'=>1, 'minsize'=>0) end } }.pack('side'=>'top', 'fill'=>'both', 'expand'=>'yes') # Display a 3x3 rectangular grid TkcRectangle.new(cvs, '0c', '0c', '30c', '24c', 'width'=>2) TkcLine.new(cvs, '0c', '8c', '30c', '8c', 'width'=>2) TkcLine.new(cvs, '0c', '16c', '30c', '16c', 'width'=>2) TkcLine.new(cvs, '10c', '0c', '10c', '24c', 'width'=>2) TkcLine.new(cvs, '20c', '0c', '20c', '24c', 'width'=>2) if $tk_version =~ /^4.*/ font1 = '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*' font2 = '-Adobe-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*' else font1 = 'Helvetica 12' font2 = 'Helvetica 24 bold' end if TkWinfo.depth($root).to_i > 1 blue = 'DeepSkyBlue3' red = 'red' bisque = 'bisque3' green = 'SeaGreen3' else blue = 'black' red = 'black' bisque = 'black' green = 'black' end # tag $tag_item = TkcGroup.new(cvs) # Set up demos within each of the areas of the grid. TkcText.new(cvs, '5c', '.2c', 'text'=>'Lines', 'anchor'=>'n') TkcLine.new(cvs, '1c', '1c', '3c', '1c', '1c', '4c', '3c', '4c', 'width'=>2, 'fill'=>blue, 'capstyle'=>'butt', 'join'=>'miter', 'tags'=>$tag_item ) TkcLine.new(cvs, '4.67c','1c','4.67c','4c', 'arrow'=>'last', 'tags'=>$tag_item) TkcLine.new(cvs, '6.33c','1c','6.33c','4c', 'arrow'=>'both', 'tags'=>$tag_item) TkcLine.new(cvs, '5c','6c','9c','6c','9c','1c','8c','1c','8c','4.8c','8.8c', '4.8c','8.8c','1.2c','8.2c','1.2c','8.2c','4.6c','8.6c','4.6c', '8.6c','1.4c','8.4c','1.4c','8.4c','4.4c', 'width'=>3, 'fill'=>red, 'tags'=>$tag_item ) TkcLine.new(cvs, '1c','5c','7c','5c','7c','7c','9c','7c', 'width'=>'.5c', 'stipple'=>'@'+[$demo_dir,'..', 'images','gray25.xbm'].join(File::Separator), 'arrow'=>'both', 'arrowshape'=>'15 15 7', 'tags'=>$tag_item ) TkcLine.new(cvs, '1c','7c','1.75c','5.8c','2.5c','7c','3.25c','5.8c','4c','7c', 'width'=>'.5c', 'capstyle'=>'round', 'join'=>'round', 'tags'=>$tag_item ) TkcText.new(cvs, '15c', '.2c', 'text'=>'Curves (smoothed lines)', 'anchor'=>'n') TkcLine.new(cvs, '11c','4c','11.5c','1c','13.5c','1c','14c','4c', 'smooth'=>'on', 'fill'=>blue, 'tags'=>$tag_item ) TkcLine.new(cvs, '15.5c','1c','19.5c','1.5c','15.5c','4.5c','19.5c','4c', 'smooth'=>'on', 'arrow'=>'both', 'width'=>3, 'tags'=>$tag_item ) TkcLine.new(cvs, '12c','6c','13.5c','4.5c','16.5c','7.5c','18c','6c', '16.5c','4.5c','13.5c','7.5c','12c','6c', 'smooth'=>'on', 'width'=>'3m', 'capstyle'=>'round', 'stipple'=>'@'+[$demo_dir, '..', 'images', 'gray25.xbm'].join(File::Separator), 'fill'=>red, 'tags'=>$tag_item ) TkcText.new(cvs, '25c', '.2c', 'text'=>'Polygons', 'anchor'=>'n') TkcPolygon.new(cvs, '21c','1.0c','22.5c','1.75c','24c','1.0c','23.25c','2.5c', '24c','4.0c','22.5c','3.25c','21c','4.0c','21.75c','2.5c', 'fill'=>'green', 'outline'=>'black', 'width'=>4, 'tags'=>$tag_item ) TkcPolygon.new(cvs, '25c','4c','25c','4c','25c','1c','26c','1c','27c','4c', '28c','1c','29c','1c','29c','4c','29c','4c', 'fill'=>red, 'smooth'=>'on', 'tags'=> $tag_item) TkcPolygon.new(cvs, '22c','4.5c','25c','4.5c','25c','6.75c','28c','6.75c', '28c','5.25c','24c','5.25c','24c','6.0c','26c','6c','26c', '7.5c','22c','7.5c', 'stipple'=>'@' + [$demo_dir, '..', 'images', 'gray25.xbm'].join(File::Separator), 'outline'=>'black', 'tags'=>$tag_item ) TkcText.new(cvs, '5c', '8.2c', 'text'=>'Rectangles', 'anchor'=>'n') TkcRectangle.new(cvs, '1c','9.5c','4c','12.5c', 'outline'=>red, 'width'=>'3m', 'tags'=>$tag_item) TkcRectangle.new(cvs, '0.5c','13.5c','4.5c','15.5c', 'fill'=>green, 'tags'=>$tag_item ) TkcRectangle.new(cvs, '6c','10c','9c','15c', 'outline'=>'', 'stipple'=>'@'+[$demo_dir,'..', 'images','gray25.xbm'].join(File::Separator), 'fill'=>blue, 'tags'=>$tag_item ) TkcText.new(cvs, '15c', '8.2c', 'text'=>'Ovals', 'anchor'=>'n') TkcOval.new(cvs, '11c','9.5c','14c','12.5c', 'outline'=>red, 'width'=>'3m', 'tags'=>$tag_item) TkcOval.new(cvs, '10.5c','13.5c','14.5c','15.5c', 'fill'=>green, 'tags'=>$tag_item ) TkcOval.new(cvs, '16c','10c','19c','15c', 'outline'=>'', 'stipple'=>'@'+[$demo_dir,'..', 'images','gray25.xbm'].join(File::Separator), 'fill'=>blue, 'tags'=>$tag_item ) TkcText.new(cvs, '25c', '8.2c', 'text'=>'Text', 'anchor'=>'n') TkcRectangle.new(cvs, '22.4c','8.9c','22.6c','9.1c') TkcText.new(cvs, '22.5c', '9c', 'anchor'=>'n', 'font'=>font1, 'width'=>'4c', 'text'=>'A short string of text, word-wrapped, justified left, and anchored north (at the top). The rectangles show the anchor points for each piece of text.', 'tags'=>$tag_item ) TkcRectangle.new(cvs, '25.4c','10.9c','25.6c','11.1c') TkcText.new(cvs, '25.5c', '11c', 'anchor'=>'w', 'font'=>font1, 'fill'=>blue, 'text'=>"Several lines,\n each centered\nindividually,\nand all anchored\nat the left edge.", 'justify'=>'center', 'tags'=>$tag_item ) TkcRectangle.new(cvs, '24.9c','13.9c','25.1c','14.1c') if $tk_version =~ /^4\.[01]/ TkcText.new(cvs, '25c', '14c', 'anchor'=>'c', 'font'=>font2, 'fill'=>red, 'stipple'=>'@' + [$demo_dir, '..', 'images', 'grey.5'].join(File::Separator), 'text'=>'Stippled characters', 'tags'=>$tag_item ) else TkcText.new(cvs, '25c', '14c', 'anchor'=>'c', 'font'=>font2, 'fill'=>red, 'stipple'=>'gray50', 'text'=>'Stippled characters', 'tags'=>$tag_item ) end TkcText.new(cvs, '5c', '16.2c', 'text'=>'Arcs', 'anchor'=>'n') TkcArc.new(cvs, '0.5c','17c','7c','20c', 'fill'=>green, 'outline'=>'black', 'start'=>45, 'extent'=>270, 'style'=>'pieslice', 'tags'=>$tag_item) #TkcArc.new(cvs, '6.5c','17c','9.5c','20c', 'width'=>'4m', 'style'=>'arc', # 'outline'=>blue, 'start'=>135, 'extent'=>270, # 'outlinestipple'=>'@' + ['images', 'grey.25'].join(File::Separator), # 'tags'=>$tag_item) TkcArc.new(cvs, '6.5c','17c','9.5c','20c', 'width'=>'4m', 'style'=>'arc', 'outline'=>blue, 'start'=>135, 'extent'=>270, 'outlinestipple'=>'@'+[$demo_dir, '..', 'images','gray25.xbm'].join(File::Separator), 'tags'=>$tag_item) TkcArc.new(cvs, '0.5c','20c','9.5c','24c', 'width'=>'4m', 'style'=>'pieslice', 'fill'=>'', 'outline'=>red, 'start'=>225, 'extent'=>90, 'tags'=>$tag_item) TkcArc.new(cvs, '5.5c','20.5c','9.5c','23.5c', 'width'=>'4m', 'style'=>'chord', 'fill'=>blue, 'outline'=>'', 'start'=>45, 'extent'=>270, 'tags'=>$tag_item) TkcText.new(cvs, '15c', '16.2c', 'text'=>'Bitmaps', 'anchor'=>'n') #TkcBitmap.new(cvs, '13c','20c', # 'bitmap'=>'@' + ['images', 'face'].join(File::Separator), # 'tags'=>$tag_item) TkcBitmap.new(cvs, '13c','20c', 'bitmap'=>'@' + [$demo_dir, '..', 'images', 'face.xbm'].join(File::Separator), 'tags'=>$tag_item) #TkcBitmap.new(cvs, '17c','18.5c', # 'bitmap'=>'@' + ['images', 'noletters'].join(File::Separator), # 'tags'=>$tag_item) TkcBitmap.new(cvs, '17c','18.5c', 'bitmap'=>'@' + [$demo_dir, '..', 'images', 'noletter.xbm'].join(File::Separator), 'tags'=>$tag_item) #TkcBitmap.new(cvs, '17c','21.5c', # 'bitmap'=>'@' + ['images', 'letters'].join(File::Separator), # 'tags'=>$tag_item) # TkcBitmap.new(cvs, '17c','21.5c') { bitmap '@' + [$demo_dir, '..', 'images', 'letters.xbm'].join(File::Separator) tags $tag_item } #TkcBitmap.new(cvs, '17c','21.5c') { # bitmap '@' + ['images', 'letters'].join(File::Separator) # tags $tag_item #} TkcText.new(cvs, '25c', '16.2c', 'text'=>'Windows', 'anchor'=>'n') TkButton.new(cvs) {|b| text 'Press Me' command proc{butPress cvs, red} TkcWindow.new(cvs, '21c','18c', 'window'=>b, 'anchor'=>'nw', 'tags'=>$tag_item) } TkEntry.new(cvs, 'width'=>20, 'relief'=>'sunken') {|e| insert 'end', 'Edit this text' TkcWindow.new(cvs, '21c','21c', 'window'=>e, 'anchor'=>'nw', 'tags'=>$tag_item) } TkScale.new(cvs, 'from'=>0, 'to'=>100, 'length'=>'6c', 'sliderlength'=>'.4c', 'width'=>'.5c', 'tickinterval'=>0 ) {|scl| TkcWindow.new(cvs, '28.5c','17.5c', 'window'=>scl, 'anchor'=>'n', 'tags'=>$tag_item) } TkcText.new(cvs, '21c', '17.9c', 'text'=>'Button:', 'anchor'=>'sw') TkcText.new(cvs, '21c', '20.9c', 'text'=>'Entry:', 'anchor'=>'sw') TkcText.new(cvs, '28.5c', '17.4c', 'text'=>'Scale:', 'anchor'=>'s') # Set up event bindings for canvas: cvs.itembind($tag_item, 'Any-Enter', proc{itemEnter cvs}) cvs.itembind($tag_item, 'Any-Leave', proc{itemLeave cvs}) cvs.bind('2', proc{|x,y| cvs.scan_mark x,y}, '%x %y') cvs.bind('B2-Motion', proc{|x,y| cvs.scan_dragto x,y}, '%x %y') cvs.bind('3', proc{|x,y| itemMark cvs,x,y}, '%x %y') cvs.bind('B3-Motion', proc{|x,y| itemStroke cvs,x,y}, '%x %y') cvs.bind('Control-f', proc{itemsUnderArea cvs}) cvs.bind('1', proc{|x,y| itemStartDrag cvs,x,y}, '%x %y') cvs.bind('B1-Motion', proc{|x,y| itemDrag cvs,x,y}, '%x %y') # Utility methods for highlighting the item under the pointer $restoreCmd = nil def itemEnter (c) if TkWinfo.depth(c).to_i == 1 $restoreCmd = nil return end type = c.itemtype('current') if type == TkcWindow $restoreCmd = nil return end if type == TkcBitmap bg = (c.itemconfiginfo('current', 'background'))[4] $restoreCmd = proc{c.itemconfigure 'current', 'background', bg} c.itemconfigure 'current', 'background', 'SteelBlue2' return end fill = (c.itemconfiginfo('current', 'fill'))[4] if (type == TkcRectangle || type == TkcOval || type == TkcArc) && fill == [] outline = (c.itemconfiginfo('current', 'outline'))[4] $restoreCmd = proc{c.itemconfigure 'current', 'outline', outline} c.itemconfigure 'current', 'outline', 'SteelBlue2' else $restoreCmd = proc{c.itemconfigure 'current', 'fill', fill} c.itemconfigure 'current', 'fill', 'SteelBlue2' end end def itemLeave(c) $restoreCmd.call if $restoreCmd end # Utility methods for stroking out a rectangle and printing what's # underneath the rectangle's area. def itemMark(c,x,y) $areaX1 = c.canvasx(x) $areaY1 = c.canvasy(y) c.delete 'area' end def itemStroke(c,x,y) x = c.canvasx(x) y = c.canvasy(y) if $areaX1 != x && $areaY1 != y c.delete 'area' c.addtag_withtag 'area', TkcRectangle.new(c, $areaX1, $areaY1, x, y, '-outline', 'black') $areaX2 = x $areaY2 = y end end def itemsUnderArea(c) area = c.find_withtag('area') items = [] c.find_enclosed($areaX1,$areaY1,$areaX2,$areaY2).each{|i| items.push(i) if i.gettags.include?($tag_item) } print "Items enclosed by area: #{items.inspect}\n"; STDOUT.flush items.clear c.find_overlapping($areaX1,$areaY1,$areaX2,$areaY2).each{|i| items.push(i) if i.gettags.include?($tag_item) } print "Items overlapping area: #{items.inspect}\n"; STDOUT.flush end $areaX1 = 0 $areaY1 = 0 $areaX2 = 0 $areaY2 = 0 # Utility methods to support dragging of items. def itemStartDrag(c,x,y) $lastX = c.canvasx(x) $lastY = c.canvasy(y) end def itemDrag(c,x,y) x = c.canvasx(x) y = c.canvasy(y) c.move 'current', x - $lastX, y - $lastY $lastX = x $lastY = y end # Method that's invoked when the button embedded in the canvas # is invoked. def butPress(w,color) i = TkcText.new(w, '25c', '18.1c', 'text'=>'Ouch!!', 'fill'=>color, 'anchor'=>'n') Tk.after(500, proc{w.delete i}) end ================================================ FILE: ext/tk/sample/demos-en/ixset ================================================ #!/usr/bin/env ruby # ixset -- # A nice interface to "xset" to change X server settings # require 'tk' class Xsettings # # Button actions # def quit @root.destroy end def ok writesettings quit end def cancel readsettings dispsettings end # apply is just "writesettings" # # Read current settings # def readsettings xfd = open("|xset q", 'r') xfd.readlines.each{|line| fields = line.chomp.strip.split(/\s+/) case fields[0] when "auto" if fields[1] == 'repeat:' @kbdrep = fields[2] @w_kbdrep.set(@kbdrep) @kbdcli = fields[6] end when "bell" @bellvol = fields[2] @bellpit = fields[5] @belldur = fields[8] when "acceleration:" @mouseacc = fields[1] @mousethr = fields[3] when "prefer" if fields[2] == 'yes' @screenbla = 'blank' else @screenbla = 'noblank' end @w_screenbla.set(@screenbla) when "timeout:" @screentim = fields[1] @screencyc = fields[3] end } xfd.close end # # Write settings into the X server # def writesettings @bellvol = @w_bellvol.get @bellpit = @w_bellpit.get @belldur = @w_belldur.get @kbdrep = @w_kbdrep.get if @kbdrep == 'on' @kbdcli = @w_kbdcli.get else @kbdcli = 'off' end @mouseacc = @w_mouseacc.get @mousethr = @w_mousethr.get @screentim = @w_screentim.get @screencyc = @w_screencyc.get @screenbla = @w_screenbla.get system("xset \ b #{@bellvol} #{@bellpit} #{@belldur} \ c #{@kbdcli} \ r #{@kbdrep} \ m #{@mouseacc} #{@mousethr} \ s #{@screentim} #{@screencyc} \ s #{@screenbla}") end # # Sends all settings to the window # def dispsettings @w_bellvol.set(@bellvol) @w_bellpit.set(@bellpit) @w_belldur.set(@belldur) @w_kbdonoff.set(@w_kbdrep.get) @w_kbdcli.set(@kbdcli) @w_mouseacc.set(@mouseacc) @w_mousethr.set(@mousethr) @w_screenblank.set(@w_screenbla.get) @w_screenpat.set(@w_screenbla.get) @w_screentim.set(@screentim) @w_screencyc.set(@screencyc) end # # Create all windows, and pack them # class LabelEntry def initialize(parent, text, length) @frame = TkFrame.new(parent) TkLabel.new(@frame, 'text'=>text).pack('side'=>'left','expand'=>'y') @entry = TkEntry.new(@frame, 'width'=>length, 'relief'=>'sunken') { pack('side'=>'left','expand'=>'y') } end def pack(keys) @frame.pack(keys) end def get @entry.value end def set(value) @entry.delete(0,'end') @entry.insert(0, value) end end def createwindows win = self # # Buttons # buttons = TkFrame.new(@root) {|f| [ TkButton.new(f, 'command'=>proc{win.ok}, 'text'=>'Ok'), TkButton.new(f, 'command'=>proc{win.writesettings}, 'text'=>'Apply'), TkButton.new(f, 'command'=>proc{win.cancel}, 'text'=>'Cancel'), TkButton.new(f, 'command'=>proc{win.quit}, 'text'=>'Quit') ].each{|b| b.pack('side'=>'left', 'expand'=>'yes', 'pady'=>5) } } # # Bell settings # bell = TkFrame.new(@root, 'relief'=>'raised', 'borderwidth'=>2) l = TkLabel.new(bell, 'text'=>'Bell Settings') @w_bellvol = TkScale.new(bell, 'from'=>0, 'to'=>100, 'length'=>200, 'tickinterval'=>20, 'orient'=>'horizontal', 'label'=>"Volume (%)") f = TkFrame.new(bell) @w_bellpit = LabelEntry.new(f, "Pitch (Hz)", 6) @w_bellpit.pack('side'=>'left', 'padx'=>5) @w_belldur = LabelEntry.new(f, "Duration (ms)", 6) @w_belldur.pack('side'=>'right', 'padx'=>5) l.pack('side'=>'top', 'expand'=>'yes') @w_bellvol.pack('side'=>'top', 'expand'=>'yes') f.pack('side'=>'top', 'expand'=>'yes') # # Keyboard settings # kbdonoff = nil kbdcli = nil kbd = TkFrame.new(@root, 'relief'=>'raised', 'borderwidth'=>2) l = TkLabel.new(kbd, 'text'=>'Keyboard Repeat Settings') f = TkFrame.new(kbd) @w_kbdonoff = TkCheckButton.new(f, 'text'=>'On', 'relief'=>'flat', 'onvalue'=>'on', 'offvalue'=>'off', 'variable'=>@w_kbdrep ) { def self.set(value) if value == 'on' self.select else self.deselect end end pack('side'=>'left', 'expand'=>'yes', 'fill'=>'both') } @w_kbdcli = TkScale.new(f, 'from'=>0, 'to'=>100, 'length'=>200, 'tickinterval'=>20, 'orient'=>'horizontal', 'label'=>'Click Volume (%)') @w_kbdcli.pack('side'=>'left', 'expand'=>'yes') l.pack('side'=>'top', 'expand'=>'yes') f.pack('side'=>'top', 'expand'=>'yes', 'pady'=>2, 'fill'=>'x') # # Mouse settings # mouse = TkFrame.new(@root, 'relief'=>'raised', 'borderwidth'=>2) l = TkLabel.new(mouse, 'text'=>'Mouse Settings') f = TkFrame.new(mouse) @w_mouseacc = LabelEntry.new(f, 'Acceleration', 3) @w_mouseacc.pack('side'=>'left') @w_mousethr = LabelEntry.new(f, 'Threshold (pixels)', 3) @w_mousethr.pack('side'=>'right') l.pack('side'=>'top') f.pack('side'=>'top', 'expand'=>'yes') # # Screen Saver settings # screen = TkFrame.new(@root, 'relief'=>'raised', 'borderwidth'=>2) l = TkLabel.new(screen, 'text'=>'Screen-saver Settings') f = TkFrame.new(screen) ff1 = TkFrame.new(f) [ @w_screenblank = TkRadioButton.new(ff1, 'text'=>'Blank', 'relief'=>'flat', 'variable'=>@w_screenbla, 'value'=>'blank') { def self.set(value) if value == 'blank' self.select else self.deselect end end }, @w_screenpat = TkRadioButton.new(ff1, 'text'=>'Pattern', 'relief'=>'flat', 'variable'=>@w_screenbla, 'value'=>'noblank') { def self.set(value) if value != 'blank' self.select else self.deselect end end } ].each {|w| w.pack('side'=>'top', 'pady'=>2, 'anchor'=>'w') } ff2 = TkFrame.new(f) [ @w_screentim = LabelEntry.new(ff2, 'Timeout (s)', 5), @w_screencyc = LabelEntry.new(ff2, 'Cycle (s)', 5) ].each{|w| w.pack('side'=>'top', 'pady'=>2, 'anchor'=>'e') } ff1.pack('side'=>'left') ff2.pack('side'=>'left') l.pack('side'=>'top') f.pack('side'=>'top', 'expand'=>'yes') # # Main window # buttons.pack('side'=>'top', 'fill'=>'both') bell.pack('side'=>'top', 'fill'=>'both', 'ipady'=>5, 'expand'=>'yes') kbd.pack('side'=>'top', 'fill'=>'both', 'ipady'=>5, 'expand'=>'yes') mouse.pack('side'=>'top', 'fill'=>'both', 'ipady'=>5, 'expand'=>'yes') screen.pack('side'=>'top', 'fill'=>'both', 'ipady'=>5, 'expand'=>'yes') # # Let the user resize our window # @root.minsize(10,10) end def initialize @root = TkRoot.new @kbdrep = 'on' @w_kbdrep = TkVariable.new(@kbdrep) def @w_kbdrep.get self.value end def @w_kbdrep.set(val) self.value=val end @kbdcli = 0 @bellvol = 100 @bellpit = 440 @belldur = 100 @mouseacc = "3/1" @mousethr = 4 @screenbla = "blank" @w_screenbla = TkVariable.new(@screenbla) def @w_screenbla.get self.value end def @w_screenbla.set(val) self.value=val end @screentim = 600 @screencyc = 600 # # Listen what "xset" tells us... # readsettings # # Create all windows # createwindows # # Write xset parameters # dispsettings end end Xsettings.new Tk.mainloop ================================================ FILE: ext/tk/sample/demos-en/ixset2 ================================================ #!/usr/bin/env ruby # # ixset -- # A nice interface to "xset" to change X server settings # require 'tk' class Xsettings # # Button actions # def quit @root.destroy end def ok writesettings quit end def cancel readsettings dispsettings @btn_APPLY.state(:disabled) @btn_CANCEL.state(:disabled) end # apply is just "writesettings" def apply writesettings @btn_APPLY.state(:disabled) @btn_CANCEL.state(:disabled) end # # Read current settings # def readsettings xfd = open("|xset q", 'r') xfd.readlines.each{|line| fields = line.chomp.strip.split(/\s+/) case fields[0] when "auto" if fields[1] == 'repeat:' @kbdrep = fields[2] @w_kbdrep.set(@kbdrep) @kbdcli = fields[6] end when "bell" @bellvol = fields[2] @bellpit = fields[5] @belldur = fields[8] when "acceleration:" @mouseacc = fields[1] @mousethr = fields[3] when "prefer" if fields[2] == 'yes' @screenbla = 'blank' else @screenbla = 'noblank' end @w_screenbla.set(@screenbla) when "timeout:" @screentim = fields[1] @screencyc = fields[3] end } xfd.close end # # Write settings into the X server # def writesettings @bellvol = @w_bellvol.get @bellpit = @w_bellpit.get @belldur = @w_belldur.get @kbdrep = @w_kbdrep.get if @kbdrep == 'on' @kbdcli = @w_kbdcli.get else @kbdcli = 'off' end @mouseacc = @w_mouseacc.get @mousethr = @w_mousethr.get @screentim = @w_screentim.get @screencyc = @w_screencyc.get @screenbla = @w_screenbla.get system("xset \ b #{@bellvol} #{@bellpit} #{@belldur} \ c #{@kbdcli} \ r #{@kbdrep} \ m #{@mouseacc} #{@mousethr} \ s #{@screentim} #{@screencyc} \ s #{@screenbla}") end # # Sends all settings to the window # def dispsettings @w_bellvol.set(@bellvol) @w_bellpit.set(@bellpit) @w_belldur.set(@belldur) @w_kbdonoff.set(@w_kbdrep.get) @w_kbdcli.set(@kbdcli) @w_mouseacc.set(@mouseacc) @w_mousethr.set(@mousethr) @w_screenblank.set(@w_screenbla.get) @w_screenpat.set(@w_screenbla.get) @w_screentim.set(@screentim) @w_screencyc.set(@screencyc) end # # Create all windows, and pack them # class LabelEntry def initialize(parent, text, length, range=[]) @frame = TkFrame.new(parent) TkLabel.new(@frame, 'text'=>text).pack('side'=>'left') if range.size > 0 @entry = TkSpinbox.new(@frame, 'width'=>length, 'relief'=>'sunken', 'from'=>range[0], 'to'=>range[1]) else @entry = TkEntry.new(@frame, 'width'=>length, 'relief'=>'sunken') end @entry.pack('side'=>'right','expand'=>'y', 'fill'=>'x') end def epath @frame end def pack(keys) @frame.pack(keys) end def get @entry.value end def set(value) @entry.delete(0,'end') @entry.insert(0, value) end end def createwindows win = self # # Buttons # btn_frame = TkFrame.new(@root) buttons = [ @btn_OK = TkButton.new(btn_frame, 'command'=>proc{win.ok}, 'default'=>'active', 'text'=>'Ok'), @btn_APPLY = TkButton.new(btn_frame, 'command'=>proc{win.writesettings}, 'default'=>'normal', 'text'=>'Apply', 'state'=>'disabled'), @btn_CANCEL = TkButton.new(btn_frame, 'command'=>proc{win.cancel}, 'default'=>'normal', 'text'=>'Cancel', 'state'=>'disabled'), @btn_QUIT = TkButton.new(btn_frame, 'command'=>proc{win.quit}, 'default'=>'normal', 'text'=>'Quit') ] buttons.each{|b| b.pack('side'=>'left', 'expand'=>'yes', 'pady'=>5) } @root.bind('Return', proc{@btn_OK.flash; @btn_OK.invoke}) @root.bind('Escape', proc{@btn_QUIT.flash; @btn_QUIT.invoke}) @root.bind('1', proc{|w| unless buttons.index(w) @btn_APPLY.state(:normal) @btn_CANCEL.state(:normal) end }, '%W') @root.bind('Key', proc{|w, k| unless buttons.index(w) case k when 'Return', 'Escape', 'Tab', /.*Shift.*/ # do nothing else @btn_APPLY.state(:normal) @btn_CANCEL.state(:normal) end end }, '%W %K') # # Bell settings # bell = TkLabelframe.new(@root, 'text'=>'Bell Settings', 'padx'=>'1.5m', 'pady'=>'1.5m') @w_bellvol = TkScale.new(bell, 'from'=>0, 'to'=>100, 'length'=>200, 'tickinterval'=>20, 'orient'=>'horizontal', 'label'=>"Volume (%)") f = TkFrame.new(bell) @w_bellpit = LabelEntry.new(f, "Pitch (Hz)", 6, [25, 20000]) @w_bellpit.pack('side'=>'left', 'padx'=>5) @w_belldur = LabelEntry.new(f, "Duration (ms)", 6, [1, 10000]) @w_belldur.pack('side'=>'right', 'padx'=>5) @w_bellvol.pack('side'=>'top', 'expand'=>'yes') f.pack('side'=>'top', 'expand'=>'yes') # # Keyboard settings # kbdonoff = nil kbdcli = nil kbd = TkLabelframe.new(@root, 'text'=>'Keyboard Repeat Settings', 'padx'=>'1.5m', 'pady'=>'1.5m') f = TkFrame.new(kbd) @w_kbdonoff = TkCheckButton.new(f, 'text'=>'On', 'relief'=>'flat', 'onvalue'=>'on', 'offvalue'=>'off', 'variable'=>@w_kbdrep ) { def self.set(value) if value == 'on' self.select else self.deselect end end pack('side'=>'left', 'expand'=>'yes', 'fill'=>'x', 'padx'=>[0, '1m']) } @w_kbdcli = TkScale.new(f, 'from'=>0, 'to'=>100, 'length'=>200, 'tickinterval'=>20, 'orient'=>'horizontal', 'label'=>'Click Volume (%)') @w_kbdcli.pack('side'=>'left', 'expand'=>'yes', 'fill'=>'x', 'padx'=>['1m', 0]) f.pack('side'=>'top', 'expand'=>'yes', 'pady'=>2, 'fill'=>'x') # # Mouse settings # mouse = TkLabelframe.new(@root, 'text'=>'Mouse Settings', 'padx'=>'1.5m', 'pady'=>'1.5m') f = TkFrame.new(mouse) @w_mouseacc = LabelEntry.new(f, 'Acceleration', 5) @w_mouseacc.pack('side'=>'left', 'padx'=>[0, '1m']) @w_mousethr = LabelEntry.new(f, 'Threshold (pixels)', 3, [1, 2000]) @w_mousethr.pack('side'=>'right', 'padx'=>['1m', 0]) f.pack('side'=>'top', 'expand'=>'yes') # # Screen Saver settings # screen = TkLabelframe.new(@root, 'text'=>'Screen-saver Settings', 'padx'=>'1.5m', 'pady'=>'1.5m') @w_screenblank = TkRadioButton.new(screen, 'text'=>'Blank', 'relief'=>'flat', 'anchor'=>'w', 'variable'=>@w_screenbla, 'value'=>'blank') { def self.set(value) if value == 'blank' self.select else self.deselect end end } @w_screenpat = TkRadioButton.new(screen, 'text'=>'Pattern', 'relief'=>'flat', 'anchor'=>'w', 'variable'=>@w_screenbla, 'value'=>'noblank') { def self.set(value) if value != 'blank' self.select else self.deselect end end } @w_screentim = LabelEntry.new(screen, 'Timeout (s)', 5, [1, 100000]) @w_screencyc = LabelEntry.new(screen, 'Cycle (s)', 5, [1, 100000]) Tk.grid(@w_screenblank, @w_screentim, 'sticky'=>'e') Tk.grid(@w_screenpat, @w_screencyc, 'sticky'=>'e') TkGrid.configure(@w_screenblank, @w_screenpat, 'sticky'=>'ew') # # Main window # param = { 'side'=>'top', 'fill'=>'both', 'expand'=>'yes', 'padx'=>'1m', 'pady'=>'1m' } btn_frame.pack('side'=>'top', 'fill'=>'both') bell.pack(param) kbd.pack(param) mouse.pack(param) screen.pack(param) # # Let the user resize our window # @root.minsize(10,10) end def initialize(title) @root = TkRoot.new('title'=>title) @kbdrep = 'on' @w_kbdrep = TkVariable.new(@kbdrep) def @w_kbdrep.get self.value end def @w_kbdrep.set(val) self.value=val end @kbdcli = 0 @bellvol = 100 @bellpit = 440 @belldur = 100 @mouseacc = "3/1" @mousethr = 4 @screenbla = "blank" @w_screenbla = TkVariable.new(@screenbla) def @w_screenbla.get self.value end def @w_screenbla.set(val) self.value=val end @screentim = 600 @screencyc = 600 # # Listen what "xset" tells us... # readsettings # # Create all windows # createwindows # # Write xset parameters # dispsettings end end Xsettings.new(File.basename($0,'.rb')) Tk.mainloop ================================================ FILE: ext/tk/sample/demos-en/knightstour.rb ================================================ # Based on the widget demo of Tcl/Tk8.5.2 # The following is the original copyright text. #---------------------------------------------------------------------------- # Copyright (C) 2008 Pat Thoyts # # Calculate a Knight's tour of a chessboard. # # This uses Warnsdorff's rule to calculate the next square each # time. This specifies that the next square should be the one that # has the least number of available moves. # # Using this rule it is possible to get to a position where # there are no squares available to move into. In this implementation # this occurs when the starting square is d6. # # To solve this fault an enhancement to the rule is that if we # have a choice of squares with an equal score, we should choose # the one nearest the edge of the board. # # If the call to the Edgemost function is commented out you can see # this occur. # # You can drag the knight to a specific square to start if you wish. # If you let it repeat then it will choose random start positions # for each new tour. #---------------------------------------------------------------------------- require 'tk' class Knights_Tour # Return a list of accessible squares from a given square def valid_moves(square) moves = [] [ [-1,-2], [-2,-1], [-2,1], [-1,2], [1,2], [2,1], [2,-1], [1,-2] ].each{|col_delta, row_delta| col = (square % 8) + col_delta row = (square.div(8)) + row_delta moves << (row * 8 + col) if row > -1 && row < 8 && col > -1 && col < 8 } moves end # Return the number of available moves for this square def check_square(square) valid_moves(square).find_all{|pos| ! @visited.include?(pos)}.length end # Select the next square to move to. Returns -1 if there are no available # squares remaining that we can move to. def next_square(square) minimum = 9 nxt = -1 valid_moves(square).each{|pos| unless @visited.include?(pos) cnt = check_square(pos) if cnt < minimum minimum = cnt nxt = pos elsif cnt == minimum nxt = edgemost(nxt, pos) end end } nxt end # Select the square nearest the edge of the board def edgemost(nxt, pos) col_A = 3 - ((3.5 - nxt % 8).abs.to_i) col_B = 3 - ((3.5 - pos % 8).abs.to_i) row_A = 3 - ((3.5 - nxt.div(8)).abs.to_i) row_B = 3 - ((3.5 - pos.div(8)).abs.to_i) (col_A * row_A < col_B * row_B)? nxt : pos end # Display a square number as a standard chess square notation. def _N(square) '%c%d' % [(97 + square % 8), (square.div(8) + 1)] end # Perform a Knight's move and schedule the next move. def move_piece(last, square) @log.insert(:end, "#{@visited.length}. #{_N last} -> #{_N square}\n", '') @log.see(:end) @board.itemconfigure(1+last, :state=>:normal, :outline=>'black') @board.itemconfigure(1+square, :state=>:normal, :outline=>'red') @knight.coords(@board.coords(1+square)[0..1]) @visited << square if (nxt = next_square(square)) != -1 @after_id = Tk.after(@delay.numeric){move_piece(square, nxt) rescue nil} else @start_btn.state :normal if @visited.length == 64 if @initial == square @log.insert :end, 'Closed tour!' else @log.insert :end, "Success\n", {} Tk.after(@delay.numeric * 2){tour(rand(64))} if @continuous.bool end else @log.insert :end, "FAILED!\n", {} end end end # Begin a new tour of the board given a random start position def tour(square = nil) @visited.clear @log.clear @start_btn.state :disabled 1.upto(64){|n| @board.itemconfigure(n, :state=>:disabled, :outline=>'black') } unless square square = @board.find_closest(*(@knight.coords << 0 << 65))[0].to_i - 1 end @initial = square Tk.after_idle{ move_piece(@initial, @initial) rescue nil } end def _stop Tk.after_cancel(@after_id) rescue nil end def _exit _stop $knightstour.destroy end def set_delay(new) @delay.numeric = new.to_i end def drag_start(w, x, y) w.dtag('selected') w.addtag('selected', :withtag, 'current') @dragging = [x, y] end def drag_motion(w, x, y) return unless @dragging w.move('selected', x - @dragging[0], y - @dragging[1]) @dragging = [x, y] end def drag_end(w, x, y) square = w.find_closest(x, y, 0, 65) w.coords('selected', w.coords(square)[0..1]) w.dtag('selected') @dragging = nil end def make_SeeDismiss ## See Code / Dismiss frame = Ttk::Frame.new($knightstour) sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'See Code', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'knightstour'}), Ttk::Button.new(frame, :text=>'Dismiss', :image=>$image['delete'], :compound=>:left, :command=>proc{ $knightstour.destroy $knightstour = nil }), :padx=>4, :pady=>4) frame.grid_columnconfigure(0, :weight=>1) frame end def create_gui(parent = nil) $knightstour.destroy rescue nil $knightstour = Tk::Toplevel.new(parent, :title=>"Knight's tour") $knightstour.withdraw base_f = Ttk::Frame.new($knightstour) @board = Tk::Canvas.new(base_f, :width=>240, :height=>240) @log = Tk::Text.new(base_f, :width=>12, :height=>1, :font=>'Arial 8', :background=>'white') scr = @log.yscrollbar(Ttk::Scrollbar.new(base_f)) @visited = [] @delay = TkVariable.new(600) @continuous = TkVariable.new(false) tool_f = Ttk::Frame.new($knightstour) label = Ttk::Label.new(tool_f, :text=>'Speed') scale = Ttk::Scale.new(tool_f, :from=>8, :to=>2000, :variable=>@delay, :command=>proc{|n| set_delay(n)}) check = Ttk::Checkbutton.new(tool_f, :text=>'Repeat', :variable=>@continuous) @start_btn = Ttk::Button.new(tool_f, :text=>'Start', :command=>proc{tour()}) @exit_btn = Ttk::Button.new(tool_f, :text=>'Exit', :command=>proc{_exit()}) 7.downto(0){|row| 0.upto(7){|col| if ((col & 1) ^ (row & 1)).zero? fill = 'bisque' dfill = 'bisque3' else fill = 'tan3' dfill = 'tan4' end coords = [col * 30 + 4, row * 30 + 4, col * 30 + 30, row * 30 + 30] @board.create(TkcRectangle, coords, :fill=>fill, :disabledfill=>dfill, :width=>2, :state=>:disabled) } } @knight_font = TkFont.new(:size=>-24) @knight = TkcText.new(@board, 0, 0, :font=>@knight_font, :text=>Tk::UTF8_String.new('\u265e'), :anchor=>'nw', # :tags=>'knight', :fill=>'black', :activefill=>'#600000') @knight.coords(@board.coords(rand(64)+1)[0..1]) @knight.bind('ButtonPress-1', '%W %x %y'){|w,x,y| drag_start(w,x,y)} @knight.bind('Motion', '%W %x %y'){|w,x,y| drag_motion(w,x,y)} @knight.bind('ButtonRelease-1', '%W %x %y'){|w,x,y| drag_end(w,x,y)} Tk.grid(@board, @log, scr, :sticky=>'news') base_f.grid_rowconfigure(0, :weight=>1) base_f.grid_columnconfigure(0, :weight=>1) Tk.grid(base_f, '-', '-', '-', '-', '-', :sticky=>'news') widgets = [label, scale, check, @start_btn] sg = nil unless $RubyTk_WidgetDemo widgets << @exit_btn if Tk.windowingsystem != 'aqua' #widgets.unshift(Ttk::SizeGrip.new(tool_f)) Ttk::SizeGrip.new(tool_f).pack(:side=>:right, :anchor=>'se') end end Tk.pack(widgets, :side=>:right) if Tk.windowingsystem == 'aqua' TkPack.configure(widgets, :padx=>[4, 4], :pady=>[12, 12]) TkPack.configure(widgets[0], :padx=>[4, 24]) TkPack.configure(widgets[-1], :padx=>[16, 4]) end Tk.grid(tool_f, '-', '-', '-', '-', '-', :sticky=>'ew') if $RubyTk_WidgetDemo Tk.grid(make_SeeDismiss(), '-', '-', '-', '-', '-', :sticky=>'ew') end $knightstour.grid_rowconfigure(0, :weight=>1) $knightstour.grid_columnconfigure(0, :weight=>1) $knightstour.bind('Control-F2'){TkConsole.show} $knightstour.bind('Return'){@start_btn.invoke} $knightstour.bind('Escape'){@exit_btn.invoke} $knightstour.bind('Destroy'){ _stop } $knightstour.protocol('WM_DELETE_WINDOW'){ _exit } $knightstour.deiconify $knightstour.tkwait_destroy end def initialize(parent = nil) create_gui(parent) end end Tk.root.withdraw unless $RubyTk_WidgetDemo Thread.new{Tk.mainloop} if __FILE__ == $0 Knights_Tour.new ================================================ FILE: ext/tk/sample/demos-en/label.rb ================================================ # label.rb # # This demonstration script creates a toplevel window containing # several label widgets. # # label widget demo (called by 'widget') # # toplevel widget if defined?($label_demo) && $label_demo $label_demo.destroy $label_demo = nil end # demo toplevel widget $label_demo = TkToplevel.new {|w| title("Label Demonstration") iconname("label") positionWindow(w) } base_frame = TkFrame.new($label_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "Five labels are displayed below: three textual ones on the left, and a bitmap label and a text label on the right. Labels are pretty boring because you can't do anything with them." } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $label_demo $label_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'See Code' command proc{showCode 'label'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # label demo f_left = TkFrame.new(base_frame) f_right = TkFrame.new(base_frame) [f_left, f_right].each{|w| w.pack('side'=>'left', 'expand'=>'yes', 'padx'=>10, 'pady'=>10, 'fill'=>'both')} # label [ TkLabel.new(f_left, 'text'=>'First label'), TkLabel.new(f_left, 'text'=>'Second label, raised', 'relief'=>'raised'), TkLabel.new(f_left, 'text'=>'Third label, sunken', 'relief'=>'sunken') ].each{|w| w.pack('side'=>'top', 'expand'=>'yes', 'pady'=>2, 'anchor'=>'w')} # TkLabel.new(f_right) { Tk::Label.new(f_right) { bitmap('@' + [$demo_dir,'..','images','face.xbm'].join(File::Separator)) borderwidth 2 relief 'sunken' }.pack('side'=>'top') TkLabel.new(f_right) { text 'Tcl/Tk Proprietor' }.pack('side'=>'top') ================================================ FILE: ext/tk/sample/demos-en/labelframe.rb ================================================ # labelframe.rb # # This demonstration script creates a toplevel window containing # several labelframe widgets. # # based on "Id: labelframe.tcl,v 1.2 2001/10/30 11:21:50 dkf Exp" if defined?($labelframe_demo) && $labelframe_demo $labelframe_demo.destroy $labelframe_demo = nil end $labelframe_demo = TkToplevel.new {|w| title("Labelframe Demonstration") iconname("labelframe") positionWindow(w) } base_frame = TkFrame.new($labelframe_demo).pack(:fill=>:both, :expand=>true) # Some information TkLabel.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left, :text=><:top) Labelframes are used to group related widgets together. \ The label may be either plain text or another widget. \ If your Tk library linked to Ruby doesn't include a 'labelframe' widget, \ this demo doesn't work. Please use later version of Tk \ which supports a 'labelframe' widget. EOL # The bottom buttons TkFrame.new(base_frame){|f| pack(:side=>:bottom, :fill=>:x, :pady=>'2m') TkButton.new(f, :text=>'Dismiss', :width=>15, :command=>proc{ $labelframe_demo.destroy $labelframe_demo = nil }).pack(:side=>:left, :expand=>true) TkButton.new(f, :text=>'See Code', :width=>15, :command=>proc{ showCode 'labelframe' }).pack(:side=>:left, :expand=>true) } # Demo area w = TkFrame.new(base_frame).pack(:side=>:bottom, :fill=>:both, :expand=>true) # A group of radiobuttons in a labelframe TkLabelFrame.new(w, :text=>'Value', :padx=>2, :pady=>2) {|f| grid(:row=>0, :column=>0, :pady=>'2m', :padx=>'2m') v = TkVariable.new (1..4).each{|i| TkRadiobutton.new(f, :text=>"This is value #{i}", :variable=>v, :value=>i) { pack(:side=>:top, :fill=>:x, :pady=>2) } } } # Using a label window to control a group of options. $lfdummy = TkVariable.new(0) def lfEnableButtons(w) TkWinfo.children(w).each{|child| next if child.path =~ /\.cb$/ if $lfdummy == 1 child.state(:normal) else child.state(:disabled) end } end TkLabelFrame.new(w, :pady=>2, :padx=>2){|f| TkCheckButton.new(f, :widgetname=>'cb', :variable=>$lfdummy, :text=>"Use this option.", :padx=>0) {|cb| command proc{lfEnableButtons(f)} f.labelwidget(cb) } grid(:row=>0, :column=>1, :pady=>'2m', :padx=>'2m') %w(Option1 Option2 Option3).each{|str| TkCheckbutton.new(f, :text=>str).pack(:side=>:top, :fill=>:x, :pady=>2) } lfEnableButtons(f) } TkGrid.columnconfigure(w, [0,1], :weight=>1) ================================================ FILE: ext/tk/sample/demos-en/mclist.rb ================================================ # mclist.rb -- # # This demonstration script creates a toplevel window containing a Ttk # tree widget configured as a multi-column listbox. # # based on "Id: mclist.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp" if defined?($mclist_demo) && $mclist_demo $mclist_demo.destroy $mclist_demo = nil end $mclist_demo = TkToplevel.new {|w| title("Multi-Column List") iconname("mclist") positionWindow(w) } base_frame = TkFrame.new($mclist_demo).pack(:fill=>:both, :expand=>true) ## Explanatory text Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left, :anchor=>'n', :padding=>[10, 2, 10, 6], :text=><:x) Ttk is the new Tk themed widget set. \ One of the widgets it includes is a tree widget, \ which can be configured to display multiple columns of informational data \ without displaying the tree itself. \ This is a simple way to build a listbox that has multiple columns. \ Clicking on the heading for a column will sort the data by that column. \ You can also change the width of the columns \ by dragging the boundary between them. EOL ## See Code / Dismiss Ttk::Frame.new(base_frame) {|frame| sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'See Code', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'mclist'}), Ttk::Button.new(frame, :text=>'Dismiss', :image=>$image['delete'], :compound=>:left, :command=>proc{ $mclist_demo.destroy $mclist_demo = nil }), :padx=>4, :pady=>4) grid_columnconfigure(0, :weight=>1) pack(:side=>:bottom, :fill=>:x) } container = Ttk::Frame.new(base_frame) tree = Ttk::Treeview.new(base_frame, :columns=>%w(country capital currency), :show=>:headings) if Tk.windowingsystem != 'aqua' vsb = tree.yscrollbar(Ttk::Scrollbar.new(base_frame)) hsb = tree.xscrollbar(Ttk::Scrollbar.new(base_frame)) else vsb = tree.yscrollbar(Tk::Scrollbar.new(base_frame)) hsb = tree.xscrollbar(Tk::Scrollbar.new(base_frame)) end container.pack(:fill=>:both, :expand=>true) Tk.grid(tree, vsb, :in=>container, :sticky=>'nsew') Tk.grid(hsb, :in=>container, :sticky=>'nsew') container.grid_columnconfigure(0, :weight=>1) container.grid_rowconfigure(0, :weight=>1) ## The data we're going to insert data = [ ['Argentina', 'Buenos Aires', 'ARS'], ['Australia', 'Canberra', 'AUD'], ['Brazil', 'Brazilia', 'BRL'], ['Canada', 'Ottawa', 'CAD'], ['China', 'Beijing', 'CNY'], ['France', 'Paris', 'EUR'], ['Germany', 'Berlin', 'EUR'], ['India', 'New Delhi', 'INR'], ['Italy', 'Rome', 'EUR'], ['Japan', 'Tokyo', 'JPY'], ['Mexico', 'Mexico City', 'MXN'], ['Russia', 'Moscow', 'RUB'], ['South Africa', 'Pretoria', 'ZAR'], ['United Kingdom', 'London', 'GBP'], ['United States', 'Washington, D.C.', 'USD'], ] ## Code to insert the data nicely font = Ttk::Style.lookup(tree[:style], :font) cols = %w(country capital currency) cols.zip(%w(Country Capital Currency)).each{|col, name| tree.heading_configure(col, :text=>name, :command=>proc{sort_by(tree, col, false)}) tree.column_configure(col, :width=>TkFont.measure(font, name)) } data.each{|country, capital, currency| #tree.insert('', :end, :values=>[country, capital, currency]) tree.insert(nil, :end, :values=>[country, capital, currency]) cols.zip([country, capital, currency]).each{|col, val| len = TkFont.measure(font, "#{val} ") if tree.column_cget(col, :width) < len tree.column_configure(col, :width=>len) end } } ## Code to do the sorting of the tree contents when clicked on def sort_by(tree, col, direction) tree.children(nil).map!{|row| [tree.get(row, col), row.id]} . sort(&((direction)? proc{|x, y| y <=> x}: proc{|x, y| x <=> y})) . each_with_index{|info, idx| tree.move(info[1], nil, idx)} tree.heading_configure(col, :command=>proc{sort_by(tree, col, ! direction)}) end ================================================ FILE: ext/tk/sample/demos-en/menu.rb ================================================ # # menus widget demo (called by 'widget') # # toplevel widget if defined?($menu_demo) && $menu_demo $menu_demo.destroy $menu_demo = nil end # demo toplevel widget $menu_demo = TkToplevel.new {|w| title("File Selection Dialogs") iconname("menu") positionWindow(w) } base_frame = TkFrame.new($menu_demo).pack(:fill=>:both, :expand=>true) # menu frame $menu_frame = TkFrame.new(base_frame, 'relief'=>'raised', 'bd'=>2) $menu_frame.pack('side'=>'top', 'fill'=>'x') begin windowingsystem = Tk.windowingsystem() rescue windowingsystem = "" end # label TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left') { if $tk_platform['platform'] == 'macintosh' || windowingsystem == "classic" || windowingsystem == "aqua" text("This window contains a menubar with cascaded menus. You can invoke entries with an accelerator by typing Command+x, where \"x\" is the character next to the command key symbol. The rightmost menu can be torn off into a palette by dragging outside of its bounds and releasing the mouse.") else text("This window contains a menubar with cascaded menus. You can post a menu from the keyboard by typing Alt+x, where \"x\" is the character underlined on the menu. You can then traverse among the menus using the arrow keys. When a menu is posted, you can invoke the current entry by typing space, or you can invoke any entry by typing its underlined character. If a menu entry has an accelerator, you can invoke the entry without posting the menu just by typing the accelerator. The rightmost menu can be torn off into a palette by selecting the first item in the menu.") end }.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $menu_demo $menu_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'menu'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # menu TkMenubutton.new($menu_frame, 'text'=>'File', 'underline'=>0) {|m| pack('side'=>'left') TkMenu.new(m, 'tearoff'=>false) {|file_menu| m.configure('menu'=>file_menu) add('command', 'label'=>'Open...', 'command'=>proc{fail 'this is just a demo: no action has been defined for the "Open..." entry'}) add('command', 'label'=>'New', 'command'=>proc{fail 'this is just a demo: no action has been defined for the "New" entry'}) add('command', 'label'=>'Save', 'command'=>proc{fail 'this is just a demo: no action has been defined for the "Save" entry'}) add('command', 'label'=>'Save As...', 'command'=>proc{fail 'this is just a demo: no action has been defined for the "Save As..." entry'}) add('separator') add('command', 'label'=>'Print Setup...', 'command'=>proc{fail 'this is just a demo: no action has been defined for the "Print Setup..." entry'}) add('command', 'label'=>'Print...', 'command'=>proc{fail 'this is just a demo: no action has been defined for the "Print..." entry'}) add('separator') add('command', 'label'=>'Dismiss Menus Demo', 'command'=>proc{$menu_demo.destroy}) } } if $tk_platform['platform'] == 'macintosh' || windowingsystem == "classic" || windowingsystem == "aqua" modifier = 'Command' elsif $tk_platform['platform'] == 'windows' modifier = 'Control' else modifier = 'Meta' end TkMenubutton.new($menu_frame, 'text'=>'Basic', 'underline'=>0) {|m| pack('side'=>'left') TkMenu.new(m, 'tearoff'=>false) {|basic_menu| m.configure('menu'=>basic_menu) add('command', 'label'=>'Long entry that does nothing') ['A','B','C','D','E','F','G'].each{|c| add('command', 'label'=>"Print letter \"#{c}\"", 'underline'=>14, 'accelerator'=>"Meta+#{c}", 'command'=>proc{print c,"\n"}, 'accelerator'=>"#{modifier}+#{c}") $menu_demo.bind("#{modifier}-#{c.downcase}", proc{print c,"\n"}) } } } TkMenubutton.new($menu_frame, 'text'=>'Cascades', 'underline'=>0) {|m| pack('side'=>'left') TkMenu.new(m, 'tearoff'=>false) {|cascade_menu| m.configure('menu'=>cascade_menu) add('command', 'label'=>'Print hello', 'command'=>proc{print "Hello\n"}, 'accelerator'=>"#{modifier}+H", 'underline'=>6) $menu_demo.bind("#{modifier}-h", proc{print "Hello\n"}) add('command', 'label'=>'Print goodbye', 'command'=>proc{print "Goodbye\n"}, 'accelerator'=>"#{modifier}+G", 'underline'=>6) $menu_demo.bind("#{modifier}-g", proc{print "Goodbye\n"}) TkMenu.new(cascade_menu, 'tearoff'=>false) {|cascade_check| cascade_menu.add('cascade', 'label'=>'Check buttons', 'menu'=>cascade_check, 'underline'=>0) oil = TkVariable.new(0) add('check', 'label'=>'Oil checked', 'variable'=>oil) trans = TkVariable.new(0) add('check', 'label'=>'Transmission checked', 'variable'=>trans) brakes = TkVariable.new(0) add('check', 'label'=>'Brakes checked', 'variable'=>brakes) lights = TkVariable.new(0) add('check', 'label'=>'Lights checked', 'variable'=>lights) add('separator') add('command', 'label'=>'Show current values', 'command'=>proc{showVars($menu_demo, ['oil', oil], ['trans', trans], ['brakes', brakes], ['lights', lights])} ) invoke 1 invoke 3 } TkMenu.new(cascade_menu, 'tearoff'=>false) {|cascade_radio| cascade_menu.add('cascade', 'label'=>'Radio buttons', 'menu'=>cascade_radio, 'underline'=>0) pointSize = TkVariable.new add('radio', 'label'=>'10 point', 'variable'=>pointSize, 'value'=>10) add('radio', 'label'=>'14 point', 'variable'=>pointSize, 'value'=>14) add('radio', 'label'=>'18 point', 'variable'=>pointSize, 'value'=>18) add('radio', 'label'=>'24 point', 'variable'=>pointSize, 'value'=>24) add('radio', 'label'=>'32 point', 'variable'=>pointSize, 'value'=>32) add('separator') style = TkVariable.new add('radio', 'label'=>'Roman', 'variable'=>style, 'value'=>'roman') add('radio', 'label'=>'Bold', 'variable'=>style, 'value'=>'bold') add('radio', 'label'=>'Italic', 'variable'=>style, 'value'=>'italic') add('separator') add('command', 'label'=>'Show current values', 'command'=>proc{showVars($menu_demo, ['pointSize', pointSize], ['style', style])} ) invoke 1 invoke 7 } } } TkMenubutton.new($menu_frame, 'text'=>'Icons', 'underline'=>0) {|m| pack('side'=>'left') TkMenu.new(m, 'tearoff'=>false) {|icon_menu| m.configure('menu'=>icon_menu) add('command', 'bitmap'=>'@'+[$demo_dir,'..', 'images','pattern.xbm'].join(File::Separator), 'command'=>proc{TkDialog.new('title'=>'Bitmap Menu Entry', 'text'=>'The menu entry you invoked displays a bitmap rather than a text string. Other than this, it is just like any other menu entry.', 'bitmap'=>'', 'default'=>0, 'buttons'=>'Dismiss')} ) ['info', 'questhead', 'error'].each{|icon| add('command', 'bitmap'=>icon, 'command'=>proc{print "You invoked the #{icon} bitmap\n"}) } } } TkMenubutton.new($menu_frame, 'text'=>'More', 'underline'=>0) {|m| pack('side'=>'left') TkMenu.new(m, 'tearoff'=>false) {|more_menu| m.configure('menu'=>more_menu) [ 'An entry','Another entry','Does nothing','Does almost nothing', 'Make life meaningful' ].each{|i| add('command', 'label'=>i, 'command'=>proc{print "You invoked \"#{i}\"\n"}) } } } TkMenubutton.new($menu_frame, 'text'=>'Colors', 'underline'=>0) {|m| pack('side'=>'left') TkMenu.new(m) {|colors_menu| m.configure('menu'=>colors_menu) ['red', 'orange', 'yellow', 'green', 'blue'].each{|c| add('command', 'label'=>c, 'background'=>c, 'command'=>proc{print "You invoked \"#{c}\"\n"}) } } } ================================================ FILE: ext/tk/sample/demos-en/menu84.rb ================================================ # # menus widget demo (called by 'widget') # # toplevel widget if defined?($menu84_demo) && $menu84_demo $menu84_demo.destroy $menu84_demo = nil end # demo toplevel widget $menu84_demo = TkToplevel.new {|w| title("File Selection Dialogs") iconname("menu84") positionWindow(w) } base_frame = TkFrame.new($menu84_demo).pack(:fill=>:both, :expand=>true) begin windowingsystem = Tk.windowingsystem() rescue windowingsystem = "" end # label TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left') { if $tk_platform['platform'] == 'macintosh' || windowingsystem == "classic" || windowingsystem == "aqua" text("This window contains a menubar with cascaded menus. You can invoke entries with an accelerator by typing Command+x, where \"x\" is the character next to the command key symbol. The rightmost menu can be torn off into a palette by dragging outside of its bounds and releasing the mouse.") else text("This window contains a menubar with cascaded menus. You can post a menu from the keyboard by typing Alt+x, where \"x\" is the character underlined on the menu. You can then traverse among the menus using the arrow keys. When a menu is posted, you can invoke the current entry by typing space, or you can invoke any entry by typing its underlined character. If a menu entry has an accelerator, you can invoke the entry without posting the menu just by typing the accelerator. The rightmost menu can be torn off into a palette by selecting the first item in the menu.") end }.pack('side'=>'top') menustatus = TkVariable.new(" ") TkFrame.new(base_frame) {|frame| TkLabel.new(frame, 'textvariable'=>menustatus, 'relief'=>'sunken', 'bd'=>1, 'font'=>['Helvetica', '10'], 'anchor'=>'w').pack('side'=>'left', 'padx'=>2, 'expand'=>true, 'fill'=>'both') pack('side'=>'bottom', 'fill'=>'x', 'pady'=>2) } # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $menu84_demo $menu84_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'menu84'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # create menu frame $menu84_frame = TkMenu.new($menu84_demo, 'tearoff'=>false) # menu TkMenu.new($menu84_frame, 'tearoff'=>false) {|m| $menu84_frame.add('cascade', 'label'=>'File', 'menu'=>m, 'underline'=>0) add('command', 'label'=>'Open...', 'command'=>proc{fail 'this is just a demo: no action has been defined for the "Open..." entry'}) add('command', 'label'=>'New', 'command'=>proc{fail 'this is just a demo: no action has been defined for the "New" entry'}) add('command', 'label'=>'Save', 'command'=>proc{fail 'this is just a demo: no action has been defined for the "Save" entry'}) add('command', 'label'=>'Save As...', 'command'=>proc{fail 'this is just a demo: no action has been defined for the "Save As..." entry'}) add('separator') add('command', 'label'=>'Print Setup...', 'command'=>proc{fail 'this is just a demo: no action has been defined for the "Print Setup..." entry'}) add('command', 'label'=>'Print...', 'command'=>proc{fail 'this is just a demo: no action has been defined for the "Print..." entry'}) add('separator') add('command', 'label'=>'Dismiss Menus Demo', 'command'=>proc{$menu84_demo.destroy}) } if $tk_platform['platform'] == 'macintosh' || windowingsystem = "classic" || windowingsystem = "aqua" modifier = 'Command' elsif $tk_platform['platform'] == 'windows' modifier = 'Control' else modifier = 'Meta' end TkMenu.new($menu84_frame, 'tearoff'=>false) {|m| $menu84_frame.add('cascade', 'label'=>'Basic', 'menu'=>m, 'underline'=>0) add('command', 'label'=>'Long entry that does nothing') ['A','B','C','D','E','F','G'].each{|c| add('command', 'label'=>"Print letter \"#{c}\"", 'underline'=>14, 'accelerator'=>"Meta+#{c}", 'command'=>proc{print c,"\n"}, 'accelerator'=>"#{modifier}+#{c}") $menu84_demo.bind("#{modifier}-#{c.downcase}", proc{print c,"\n"}) } } TkMenu.new($menu84_frame, 'tearoff'=>false) {|m| $menu84_frame.add('cascade', 'label'=>'Cascades', 'menu'=>m, 'underline'=>0) add('command', 'label'=>'Print hello', 'command'=>proc{print "Hello\n"}, 'accelerator'=>"#{modifier}+H", 'underline'=>6) $menu84_demo.bind("#{modifier}-h", proc{print "Hello\n"}) add('command', 'label'=>'Print goodbye', 'command'=>proc{print "Goodbye\n"}, 'accelerator'=>"#{modifier}+G", 'underline'=>6) $menu84_demo.bind("#{modifier}-g", proc{print "Goodbye\n"}) TkMenu.new(m, 'tearoff'=>false) {|cascade_check| m.add('cascade', 'label'=>'Check buttons', 'menu'=>cascade_check, 'underline'=>0) oil = TkVariable.new(0) add('check', 'label'=>'Oil checked', 'variable'=>oil) trans = TkVariable.new(0) add('check', 'label'=>'Transmission checked', 'variable'=>trans) brakes = TkVariable.new(0) add('check', 'label'=>'Brakes checked', 'variable'=>brakes) lights = TkVariable.new(0) add('check', 'label'=>'Lights checked', 'variable'=>lights) add('separator') add('command', 'label'=>'Show current values', 'command'=>proc{showVars($menu84_demo, ['oil', oil], ['trans', trans], ['brakes', brakes], ['lights', lights])} ) invoke 1 invoke 3 } TkMenu.new(m, 'tearoff'=>false) {|cascade_radio| m.add('cascade', 'label'=>'Radio buttons', 'menu'=>cascade_radio, 'underline'=>0) pointSize = TkVariable.new add('radio', 'label'=>'10 point', 'variable'=>pointSize, 'value'=>10) add('radio', 'label'=>'14 point', 'variable'=>pointSize, 'value'=>14) add('radio', 'label'=>'18 point', 'variable'=>pointSize, 'value'=>18) add('radio', 'label'=>'24 point', 'variable'=>pointSize, 'value'=>24) add('radio', 'label'=>'32 point', 'variable'=>pointSize, 'value'=>32) add('separator') style = TkVariable.new add('radio', 'label'=>'Roman', 'variable'=>style, 'value'=>'roman') add('radio', 'label'=>'Bold', 'variable'=>style, 'value'=>'bold') add('radio', 'label'=>'Italic', 'variable'=>style, 'value'=>'italic') add('separator') add('command', 'label'=>'Show current values', 'command'=>proc{showVars($menu84_demo, ['pointSize', pointSize], ['style', style])} ) invoke 1 invoke 7 } } TkMenu.new($menu84_frame, 'tearoff'=>false) {|m| $menu84_frame.add('cascade', 'label'=>'Icons', 'menu'=>m, 'underline'=>0) add('command', 'hidemargin'=>1, 'bitmap'=>'@'+[$demo_dir,'..', 'images','pattern.xbm'].join(File::Separator), 'command'=>proc{TkDialog.new('title'=>'Bitmap Menu Entry', 'text'=>'The menu entry you invoked displays a bitmap rather than a text string. Other than this, it is just like any other menu entry.', 'bitmap'=>'', 'default'=>0, 'buttons'=>'Dismiss')} ) ['info', 'questhead', 'error'].each{|icon| add('command', 'bitmap'=>icon, 'hidemargin'=>1, 'command'=>proc{print "You invoked the #{icon} bitmap\n"}) } entryconfigure(2, :columnbreak=>true) } TkMenu.new($menu84_frame, 'tearoff'=>false) {|m| $menu84_frame.add('cascade', 'label'=>'More', 'menu'=>m, 'underline'=>0) [ 'An entry','Another entry','Does nothing','Does almost nothing', 'Make life meaningful' ].each{|i| add('command', 'label'=>i, 'command'=>proc{print "You invoked \"#{i}\"\n"}) } m.entryconfigure('Does almost nothing', 'bitmap'=>'questhead', 'compound'=>'left', 'command'=>proc{ TkDialog.new('title'=>'Compound Menu Entry', 'message'=>'The menu entry you invoked'+ 'displays both a bitmap and '+ 'a text string. Other than '+ 'this, it isjust like any '+ 'other menu entry.', 'buttons'=>['OK'], 'bitmap'=>'') }) } TkMenu.new($menu84_frame) {|m| $menu84_frame.add('cascade', 'label'=>'Colors', 'menu'=>m, 'underline'=>0) ['red', 'orange', 'yellow', 'green', 'blue'].each{|c| add('command', 'label'=>c, 'background'=>c, 'command'=>proc{print "You invoked \"#{c}\"\n"}) } } $menu84_demo.menu($menu84_frame) TkMenu.bind('', proc{|w| begin label = w.entrycget('active', 'label') rescue label = " " end menustatus.value = label Tk.update(true) }, '%W') ================================================ FILE: ext/tk/sample/demos-en/menubu.rb ================================================ # menubutton.rb # # This demonstration script creates a window with a bunch of menus # and cascaded menus using menubuttons. require "tkcanvas" def optionMenu(menubutton, varName, firstValue, *rest) varName.value = firstValue configoptions = {'textvariable'=>varName,'indicatoron'=>'on', 'relief'=>'raised','borderwidth'=>2,'highlightthickness'=>2, 'anchor'=>'c','direction'=>'flush'} configoptions.each {|key, value| menubutton.configure(key, value) } menu = TkMenu.new(menubutton) { tearoff 'off' add 'radio', 'label'=>firstValue, 'variable'=>varName } menubutton.menu(menu) for i in rest menu.add 'radio', 'label'=>i, 'variable'=>varName end return menu end if defined?($menubu_demo) && $menubu_demo $menubu_demo.destroy $menubu_demo = nil end $menubu_demo = TkToplevel.new {|w| title("Menu Button Demonstration") iconname("menubutton") } positionWindow($menubu_demo) base_frame = TkFrame.new($menubu_demo).pack(:fill=>:both, :expand=>true) # version check if $tk_version.to_f < 8.0 # label TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left') { text("This is a demonstration of menubuttons. The \"Below\" menubutton pops its menu below the button; the \"Right\" button pops to the right, etc. There are two option menus directly below this text; one is just a standard menu and the other is a 16-color palette.") }.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $menubu_demo $menubu_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'menubu'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') else ; # Tk8.x body = TkFrame.new(base_frame) body.pack('expand'=>'yes', 'fill'=>'both') below = TkMenubutton.new(body) { text "Below" underline 0 direction 'below' relief 'raised' } belowMenu = TkMenu.new(below) { tearoff 0 add 'command', 'label'=>"Below menu: first item", 'command'=>proc {puts "\"You have selected the first item from the Below menu.\""} add 'command', 'label'=>"Below menu: second item", 'command'=>proc {puts "\"You have selected the second item from the Below menu.\""} } below.menu(belowMenu) below.grid('row'=>0, 'column'=>1, 'sticky'=>'n') below = TkMenubutton.new(body) { text "Below" underline 0 direction 'below' relief 'raised' } belowMenu = TkMenu.new(below) { tearoff 0 add 'command', 'label'=>"Below menu: first item", 'command'=>proc {puts "\"You have selected the first item from the Below menu.\""} add 'command', 'label'=>"Below menu: second item", 'command'=>proc {puts "\"You have selected the second item from the Below menu.\""} } below.menu(belowMenu) below.grid('row'=>0, 'column'=>1, 'sticky'=>'n') below = TkMenubutton.new(body) { text "Below" underline 0 direction 'below' relief 'raised' } belowMenu = TkMenu.new(below) { tearoff 0 add 'command', 'label'=>"Below menu: first item", 'command'=>proc {puts "\"You have selected the first item from the Below menu.\""} add 'command', 'label'=>"Below menu: second item", 'command'=>proc {puts "\"You have selected the second item from the Below menu.\""} } below.menu(belowMenu) below.grid('row'=>0, 'column'=>1, 'sticky'=>'n') right = TkMenubutton.new(body) { text "Right" underline 0 direction 'right' relief 'raised' } rightMenu = TkMenu.new(right) { tearoff 0 add 'command', 'label'=>"Right menu: first item", 'command'=>proc {puts "\"You have selected the first item from the Left menu.\""} add 'command', 'label'=>"Right menu: second item", 'command'=>proc {puts "\"You have selected the second item from the Right menu.\""} } right.menu(rightMenu) right.grid('row'=>1, 'column'=>0, 'sticky'=>'w') left = TkMenubutton.new(body) { text "Left" underline 0 direction 'left' relief 'raised' } leftMenu = TkMenu.new(left) { tearoff 0 add 'command', 'label'=>"Left menu: first item", 'command'=>proc {puts "\"You have selected the first item from the Left menu.\""} add 'command', 'label'=>"Left menu: second item", 'command'=>proc {puts "\"You have selected the second item from the Left menu.\""} } left.menu(leftMenu) left.grid('row'=>1, 'column'=>2, 'sticky'=>'e') center = TkFrame.new(body) { grid('row'=>1, 'column'=>1, 'sticky'=>'news') } above = TkMenubutton.new(body) { text "Above" underline 0 direction 'above' relief 'raised' } aboveMenu = TkMenu.new(above) { tearoff 0 add 'command', 'label'=>"Above menu: first item", 'command'=>proc {puts "\"You have selected the first item from the Above menu.\""} add 'command', 'label'=>"Above menu: second item", 'command'=>proc {puts "\"You have selected the second item from the Above menu.\""} } above.menu(aboveMenu) above.grid('row'=>2, 'column'=>1, 'sticky'=>'s') center = TkFrame.new(body) { grid('row'=>1, 'column'=>1, 'sticky'=>'news') } TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc { tmppath = $menubu_demo $menubu_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc { showCode 'menubu' } }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'expand'=>'yes', 'fill'=>'x', 'pady'=>'2m') msg = TkLabel.new(center) { # font $font wraplength '4i' justify 'left' text "This is a demonstration of menubuttons. The \"Below\" menubutton pops its menu below the button; the \"Right\" button pops to the right, etc. There are two option menus directly below this text; one is just a standard menu and the other is a 16-color palette." } msg.pack('side'=>'top', 'padx'=>25, 'pady'=>25) TkFrame.new(center) {|f| menubuttonoptions = TkVariable.new mbutton = TkMenubutton.new(f) options = optionMenu(mbutton, menubuttonoptions, 'one', 'two', 'three') mbutton.pack('side'=>'left', 'padx'=>25, 'pady'=>25) paletteColor = TkVariable.new colors = ['Black','red4','DarkGreen','NavyBlue', 'gray75', 'Red','Green','Blue','gray50','Yellow','Cyan','Magenta', 'White','Brown','DarkSeaGreen','DarkViolet'] colorMenuButton = TkMenubutton.new(f) m = optionMenu(colorMenuButton, paletteColor, *colors) begin windowingsystem = Tk.windowingsystem() rescue windowingsystem = "" end if windowingsystem == "classic" || windowingsystem == "aqua" topBorderColor = 'Black' bottomBorderColor = 'Black' else topBorderColor = 'gray50' bottomBorderColor = 'gray75' end for i in 0..15 image = TkPhotoImage.new('height'=>16, 'width'=>16) image.put(topBorderColor, 0, 0, 16, 1) image.put(topBorderColor, 0, 1, 1, 16) image.put(bottomBorderColor, 0, 15, 16, 16) image.put(bottomBorderColor, 15, 1, 16, 16) image.put(colors[i], 1, 1, 15, 15) selectimage = TkPhotoImage.new('height'=>16, 'width'=>16) selectimage.put('Black', 0, 0, 16, 2) selectimage.put('Black', 0, 2, 2, 16) selectimage.put('Black', 2, 14, 16, 16) selectimage.put('Black', 14, 2, 16, 14) selectimage.put(colors[i], 2, 2, 14, 14) m.entryconfigure(i, 'image'=>image, 'selectimage'=>selectimage, 'hidemargin'=>'on') end m.configure('tearoff', 'on') for c in ['Black', 'gray75', 'gray50', 'White'] m.entryconfigure(c, 'columnbreak'=>1) end colorMenuButton.pack('side'=>'left', 'padx'=>25, 'pady'=>25) pack 'padx'=>25, 'pady'=>25 } end ; # Tk8.x ================================================ FILE: ext/tk/sample/demos-en/msgbox.rb ================================================ # msgbox.rb # # This demonstration script creates message boxes of various type # # message boxes widget demo (called by 'widget') # # toplevel widget if defined?($msgbox_demo) && $msgbox_demo $msgbox_demo.destroy $msgbox_demo = nil end # demo toplevel widget $msgbox_demo = TkToplevel.new {|w| title("Message Box Demonstration") iconname("messagebox") positionWindow(w) } base_frame = TkFrame.new($msgbox_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'4i', 'justify'=>'left', 'text'=>"Choose the icon and type option of the message box. Then press the \"Message Box\" button to see the message box.").pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $msgbox_demo $msgbox_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'msgbox'} }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Message Box' command proc{showMessageBox $msgbox_demo} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame $msgbox_leftframe = TkFrame.new(base_frame) $msgbox_rightframe = TkFrame.new(base_frame) $msgbox_leftframe .pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y', 'pady'=>'.5c', 'padx'=>'.5c') $msgbox_rightframe.pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y', 'pady'=>'.5c', 'padx'=>'.5c') TkLabel.new($msgbox_leftframe, 'text'=>'Icon').pack('side'=>'top') TkFrame.new($msgbox_leftframe, 'relief'=>'ridge', 'bd'=>1, 'height'=>2)\ .pack('side'=>'top', 'fill'=>'x', 'expand'=>'no') $msgboxIcon = TkVariable.new('info') ['error', 'info', 'question', 'warning'].each {|icon| TkRadioButton.new($msgbox_leftframe, 'text'=>icon, 'variable'=>$msgboxIcon, 'relief'=>'flat', 'value'=>icon, 'width'=>16, 'anchor'=>'w').pack('side'=>'top', 'pady'=>2, 'anchor'=>'w', 'fill'=>'x') } TkLabel.new($msgbox_rightframe, 'text'=>'Type').pack('side'=>'top') TkFrame.new($msgbox_rightframe, 'relief'=>'ridge', 'bd'=>1, 'height'=>2)\ .pack('side'=>'top', 'fill'=>'x', 'expand'=>'no') $msgboxType = TkVariable.new('ok') ['abortretryignore', 'ok', 'okcancel', 'retrycancel', 'yesno', 'yesnocancel'].each {|type| TkRadioButton.new($msgbox_rightframe, 'text'=>type, 'variable'=>$msgboxType, 'relief'=>'flat', 'value'=>type, 'width'=>16, 'anchor'=>'w').pack('side'=>'top', 'pady'=>2, 'anchor'=>'w', 'fill'=>'x') } def showMessageBox(w) button = Tk.messageBox('icon'=>$msgboxIcon.value, 'type'=>$msgboxType.value, 'title'=>'Message', 'parent'=>w, 'message'=>"This is a \"#{$msgboxType.value}\" type messagebox with the \"#{$msgboxIcon.value}\" icon") Tk.messageBox('icon'=>'info', 'type'=>'ok', 'parent'=>w, 'message'=>"You have selected \"#{button}\"") end ================================================ FILE: ext/tk/sample/demos-en/msgbox2.rb ================================================ # msgbox2.rb # # This demonstration script creates message boxes of various type # # message boxes widget demo (called by 'widget') # # toplevel widget if defined?($msgbox2_demo) && $msgbox2_demo $msgbox2_demo.destroy $msgbox2_demo = nil end # demo toplevel widget $msgbox2_demo = TkToplevel.new {|w| title("Message Box Demonstration") iconname("messagebox") positionWindow(w) } base_frame = TkFrame.new($msgbox2_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'4i', 'justify'=>'left', 'text'=>"Choose the icon and type option of the message box. Then press the \"Message Box\" button to see the message box with both of a message and a detail.").pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $msgbox2_demo $msgbox2_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'msgbox2'} }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Message Box' command proc{showMessageBox $msgbox2_demo} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame $msgbox_leftframe = TkFrame.new(base_frame) $msgbox_rightframe = TkFrame.new(base_frame) $msgbox_leftframe .pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y', 'pady'=>'.5c', 'padx'=>'.5c') $msgbox_rightframe.pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y', 'pady'=>'.5c', 'padx'=>'.5c') TkLabel.new($msgbox_leftframe, 'text'=>'Icon').pack('side'=>'top') TkFrame.new($msgbox_leftframe, 'relief'=>'ridge', 'bd'=>1, 'height'=>2)\ .pack('side'=>'top', 'fill'=>'x', 'expand'=>'no') $msgboxIcon = TkVariable.new('info') ['error', 'info', 'question', 'warning'].each {|icon| TkRadioButton.new($msgbox_leftframe, 'text'=>icon, 'variable'=>$msgboxIcon, 'relief'=>'flat', 'value'=>icon, 'width'=>16, 'anchor'=>'w').pack('side'=>'top', 'pady'=>2, 'anchor'=>'w', 'fill'=>'x') } TkLabel.new($msgbox_rightframe, 'text'=>'Type').pack('side'=>'top') TkFrame.new($msgbox_rightframe, 'relief'=>'ridge', 'bd'=>1, 'height'=>2)\ .pack('side'=>'top', 'fill'=>'x', 'expand'=>'no') $msgboxType = TkVariable.new('ok') ['abortretryignore', 'ok', 'okcancel', 'retrycancel', 'yesno', 'yesnocancel'].each {|type| TkRadioButton.new($msgbox_rightframe, 'text'=>type, 'variable'=>$msgboxType, 'relief'=>'flat', 'value'=>type, 'width'=>16, 'anchor'=>'w').pack('side'=>'top', 'pady'=>2, 'anchor'=>'w', 'fill'=>'x') } def showMessageBox(w) button = Tk.messageBox('icon'=>$msgboxIcon.value, 'type'=>$msgboxType.value, 'title'=>'Message', 'parent'=>w, 'message'=>"\"#{$msgboxType.value}\" Type MessageBox", 'detail'=>"This is a \"#{$msgboxType.value}\" type messagebox with the \"#{$msgboxIcon.value}\" icon. Please click one of the following button.") Tk.messageBox('icon'=>'info', 'type'=>'ok', 'parent'=>w, 'message'=>"You have selected \"#{button}\"") end ================================================ FILE: ext/tk/sample/demos-en/paned1.rb ================================================ # paned1.rb # # This demonstration script creates a toplevel window containing # a paned window that separates two windows horizontally. # # based on "Id: paned1.tcl,v 1.1 2002/02/22 14:07:01 dkf Exp" if defined?($paned1_demo) && $paned1_demo $paned1_demo.destroy $paned1_demo = nil end $paned1_demo = TkToplevel.new {|w| title("Horizontal Paned Window Demonstration") iconname("paned1") positionWindow(w) } base_frame = TkFrame.new($paned1_demo).pack(:fill=>:both, :expand=>true) TkLabel.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left, :text=><:top) The sash between the two coloured windows below can be used to divide the area between them. Use the left mouse button to resize without redrawing by just moving the sash, and use the middle mouse button to resize opaquely (always redrawing the windows in each position.) If your Tk library linked to Ruby doesn't include a 'panedwindow', this demo doesn't work. Please use later version of Tk which supports a 'panedwindow'. EOL # The bottom buttons TkFrame.new(base_frame){|f| pack(:side=>:bottom, :fill=>:x, :pady=>'2m') TkButton.new(f, :text=>'Dismiss', :width=>15, :command=>proc{ $paned1_demo.destroy $paned1_demo = nil }).pack(:side=>:left, :expand=>true) TkButton.new(f, :text=>'See Code', :width=>15, :command=>proc{ showCode 'paned1' }).pack(:side=>:left, :expand=>true) } TkPanedwindow.new(base_frame, :orient=>:horizontal){|f| add(Tk::Label.new(f, :text=>"This is the\nleft side", :bg=>'yellow'), Tk::Label.new(f, :text=>"This is the\nright side", :bg=>'cyan')) pack(:side=>:top, :expand=>true, :fill=>:both, :pady=>2, :padx=>'2m') } ================================================ FILE: ext/tk/sample/demos-en/paned2.rb ================================================ # paned2.rb -- # # This demonstration script creates a toplevel window containing # a paned window that separates two windows vertically. # # based on "Id: paned2.tcl,v 1.1 2002/02/22 14:07:01 dkf Exp" if defined?($paned2_demo) && $paned2_demo $paned2_demo.destroy $paned2_demo = nil end $paned2_demo = TkToplevel.new {|w| title("Vertical Paned Window Demonstration") iconname("paned2") positionWindow(w) } base_frame = TkFrame.new($paned2_demo).pack(:fill=>:both, :expand=>true) TkLabel.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left, :text=><:top) The sash between the two scrolled windows below can be used to divide the area between them. Use the left mouse button to resize without redrawing by just moving the sash, and use the middle mouse button to resize opaquely (always redrawing the windows in each position.) If your Tk library linked to Ruby doesn't include a 'panedwindow', this demo doesn't work. Please use later version of Tk which supports a 'panedwindow'. EOL # The bottom buttons TkFrame.new(base_frame){|f| pack(:side=>:bottom, :fill=>:x, :pady=>'2m') TkButton.new(f, :text=>'Dismiss', :width=>15, :command=>proc{ $paned2_demo.destroy $paned2_demo = nil }).pack(:side=>:left, :expand=>true) TkButton.new(f, :text=>'See Code', :width=>15, :command=>proc{ showCode 'paned2' }).pack(:side=>:left, :expand=>true) } paneList = TkVariable.new # define as normal variable (not array) paneList.value = [ # ruby's array --> tcl's list 'List of Ruby/Tk Widgets', 'TkButton', 'TkCanvas', 'TkCheckbutton', 'TkEntry', 'TkFrame', 'TkLabel', 'TkLabelframe', 'TkListbox', 'TkMenu', 'TkMenubutton', 'TkMessage', 'TkPanedwindow', 'TkRadiobutton', 'TkScale', 'TkScrollbar', 'TkSpinbox', 'TkText', 'TkToplevel' ] # Create the pane itself TkPanedwindow.new(base_frame, :orient=>:vertical){|f| pack(:side=>:top, :expand=>true, :fill=>:both, :pady=>2, :padx=>'2m') add(TkFrame.new(f){|paned2_top| TkListbox.new(paned2_top, :listvariable=>paneList) { # Invert the first item to highlight it itemconfigure(0, :background=>self.cget(:foreground), :foreground=>self.cget(:background) ) yscrollbar(TkScrollbar.new(paned2_top).pack(:side=>:right, :fill=>:y)) pack(:fill=>:both, :expand=>true) } }, TkFrame.new(f, :height=>120) {|paned2_bottom| # The bottom window is a text widget with scrollbar paned2_xscr = TkScrollbar.new(paned2_bottom) paned2_yscr = TkScrollbar.new(paned2_bottom) paned2_text = TkText.new(paned2_bottom, :width=>30, :wrap=>:non) { insert('1.0', "This is just a normal text widget") xscrollbar(paned2_xscr) yscrollbar(paned2_yscr) } Tk.grid(paned2_text, paned2_yscr, :sticky=>'nsew') Tk.grid(paned2_xscr, :sticky=>'nsew') TkGrid.columnconfigure(paned2_bottom, 0, :weight=>1) TkGrid.rowconfigure(paned2_bottom, 0, :weight=>1) } ) } ================================================ FILE: ext/tk/sample/demos-en/pendulum.rb ================================================ # # This demonstration illustrates how Tcl/Tk can be used to construct # simulations of physical systems. # (called by 'widget') # # based on Tcl/Tk8.5a2 widget demos # destroy toplevel widget for this demo script if defined?($pendulum_demo) && $pendulum_demo $pendulum_demo.destroy $pendulum_demo = nil end # create toplevel widget $pendulum_demo = TkToplevel.new {|w| title("Pendulum Animation Demonstration") iconname("pendulum") positionWindow(w) } base_frame = TkFrame.new($pendulum_demo).pack(:fill=>:both, :expand=>true) # create label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text 'This demonstration shows how Ruby/Tk can be used to carry out animations that are linked to simulations of physical systems. In the left canvas is a graphical representation of the physical system itself, a simple pendulum, and in the right canvas is a graph of the phase space of the system, which is a plot of the angle (relative to the vertical) against the angular velocity. The pendulum bob may be repositioned by clicking and dragging anywhere on the left canvas.' } msg.pack('side'=>'top') # create frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $pendulum_demo $pendulum_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'See Code' command proc{showCode 'pendulum'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # animated wave class PendulumAnimationDemo def initialize(frame) # Create some structural widgets @pane = TkPanedWindow.new(frame, :orient=>:horizontal).pack(:fill=>:both, :expand=>true) # @pane.add(@lf1 = TkLabelFrame.new(@pane, :text=>'Pendulum Simulation')) # @pane.add(@lf2 = TkLabelFrame.new(@pane, :text=>'Phase Space')) @lf1 = TkLabelFrame.new(@pane, :text=>'Pendulum Simulation') @lf2 = TkLabelFrame.new(@pane, :text=>'Phase Space') # Create the canvas containing the graphical representation of the # simulated system. @c = TkCanvas.new(@lf1, :width=>320, :height=>200, :background=>'white', :borderwidth=>2, :relief=>:sunken) TkcText.new(@c, 5, 5, :anchor=>:nw, :text=>'Click to Adjust Bob Start Position') # Coordinates of these items don't matter; they will be set properly below @plate = TkcLine.new(@c, 0, 25, 320, 25, :width=>2, :fill=>'grey50') @rod = TkcLine.new(@c, 1, 1, 1, 1, :width=>3, :fill=>'black') @bob = TkcOval.new(@c, 1, 1, 2, 2, :width=>3, :fill=>'yellow', :outline=>'black') TkcOval.new(@c, 155, 20, 165, 30, :fill=>'grey50', :outline=>'') # pack @c.pack(:fill=>:both, :expand=>true) # Create the canvas containing the phase space graph; this consists of # a line that gets gradually paler as it ages, which is an extremely # effective visual trick. @k = TkCanvas.new(@lf2, :width=>320, :height=>200, :background=>'white', :borderwidth=>2, :relief=>:sunken) @y_axis = TkcLine.new(@k, 160, 200, 160, 0, :fill=>'grey75', :arrow=>:last) @x_axis = TkcLine.new(@k, 0, 100, 320, 100, :fill=>'grey75', :arrow=>:last) @graph = {} 90.step(0, -10){|i| # Coordinates of these items don't matter; # they will be set properly below @graph[i] = TkcLine.new(@k, 0, 0, 1, 1, :smooth=>true, :fill=>"grey#{i}") } # labels @label_theta = TkcText.new(@k, 0, 0, :anchor=>:ne, :text=>'q', :font=>'Symbol 8') @label_dtheta = TkcText.new(@k, 0, 0, :anchor=>:ne, :text=>'dq', :font=>'Symbol 8') # pack @k.pack(:fill=>:both, :expand=>true) # Initialize some variables @points = [] @theta = 45.0 @dTheta = 0.0 @length = 150 # animation loop @timer = TkTimer.new(15){ repeat } # binding @c.bindtags_unshift(btag = TkBindTag.new) btag.bind('Destroy'){ @timer.stop } btag.bind('1', proc{|x, y| @timer.stop; showPendulum(x.to_i, y.to_i)}, '%x %y') btag.bind('B1-Motion', proc{|x, y| showPendulum(x.to_i, y.to_i)}, '%x %y') btag.bind('ButtonRelease-1', proc{|x, y| showPendulum(x.to_i, y.to_i); @timer.start }, '%x %y') btag.bind('Configure', proc{|w| @plate.coords(0, 25, w.to_i, 25)}, '%w') @k.bind('Configure', proc{|h, w| h = h.to_i w = w.to_i @psh = h/2; @psw = w/2 @x_axis.coords(2, @psh, w-2, @psh) @y_axis.coords(@psw, h-2, @psw, 2) @label_theta.coords(@psw-4, 6) @label_dtheta.coords(w-6, @psh+4) }, '%h %w') # add Tk.update @pane.add(@lf1) @pane.add(@lf2) # init display showPendulum # animation start @timer.start(500) end # This procedure makes the pendulum appear at the correct place on the # canvas. If the additional arguments x, y are passed instead of computing # the position of the pendulum from the length of the pendulum rod and its # angle, the length and angle are computed in reverse from the given # location (which is taken to be the centre of the pendulum bob.) def showPendulum(x=nil, y=nil) if x && y && (x != 160 || y != 25) @dTheta = 0.0 x2 = x - 160 y2 = y - 25 @length = Math.hypot(x2, y2) @theta = Math.atan2(x2,y2)*180/Math::PI else angle = @theta*Math::PI/180 x = 160 + @length*Math.sin(angle) y = 25 + @length*Math.cos(angle) end @rod.coords(160, 25, x, y) @bob.coords(x-15, y-15, x+15, y+15) end # Update the phase-space graph according to the current angle and the # rate at which the angle is changing (the first derivative with # respect to time.) def showPhase unless @psw && @psh @psw = @k.width/2 @psh = @k.height/2 end @points << @theta + @psw << -20*@dTheta + @psh if @points.length > 100 @points = @points[-100..-1] end (0...100).step(10){|i| first = - i last = 11 - i last = -1 if last >= 0 next if first > last lst = @points[first..last] @graph[i].coords(lst) if lst && lst.length >= 4 } end # This procedure is the "business" part of the simulation that does # simple numerical integration of the formula for a simple rotational # pendulum. def recomputeAngle scaling = 3000.0/@length/@length # To estimate the integration accurately, we really need to # compute the end-point of our time-step. But to do *that*, we # need to estimate the integration accurately! So we try this # technique, which is inaccurate, but better than doing it in a # single step. What we really want is bound up in the # differential equation: # .. - sin theta # theta + theta = ----------- # length # But my math skills are not good enough to solve this! # first estimate firstDDTheta = -Math.sin(@theta * Math::PI/180) * scaling midDTheta = @dTheta + firstDDTheta midTheta = @theta + (@dTheta + midDTheta)/2 # second estimate midDDTheta = -Math.sin(midTheta * Math::PI/180) * scaling midDTheta = @dTheta + (firstDDTheta + midDDTheta)/2 midTheta = @theta + (@dTheta + midDTheta)/2 # Now we do a double-estimate approach for getting the final value # first estimate midDDTheta = -Math.sin(midTheta * Math::PI/180) * scaling lastDTheta = midDTheta + midDDTheta lastTheta = midTheta + (midDTheta+ lastDTheta)/2 # second estimate lastDDTheta = -Math.sin(lastTheta * Math::PI/180) * scaling lastDTheta = midDTheta + (midDDTheta + lastDDTheta)/2 lastTheta = midTheta + (midDTheta + lastDTheta)/2 # Now put the values back in our globals @dTheta = lastDTheta @theta = lastTheta end # This method ties together the simulation engine and the graphical # display code that visualizes it. def repeat # Simulate recomputeAngle # Update the display showPendulum showPhase end end # Start the animation processing PendulumAnimationDemo.new(base_frame) ================================================ FILE: ext/tk/sample/demos-en/plot.rb ================================================ # plot.rb # # This demonstration script creates a canvas widget showing a 2-D # plot with data points that can be dragged with the mouse. # # 2-D plot widget demo (called by 'widget') # # toplevel widget if defined?($plot_demo) && $plot_demo $plot_demo.destroy $plot_demo = nil end # demo toplevel widget $plot_demo = TkToplevel.new {|w| title("Plot Demonstration") iconname("Plot") positionWindow(w) } base_frame = TkFrame.new($plot_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'4i', 'justify'=>'left', 'text'=>"This window displays a canvas widget containing a simple 2-dimensional plot. You can doctor the data by dragging any of the points with mouse button 1."){ pack('side'=>'top') } # frame $plot_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $plot_demo $plot_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'plot'} }.pack('side'=>'left', 'expand'=>'yes') } $plot_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # font plotFont = '-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*' # canvas $plot_canvas = TkCanvas.new(base_frame,'relief'=>'raised','width'=>450,'height'=>300) $plot_canvas.pack('side'=>'top', 'fill'=>'x') # plot TkcLine.new($plot_canvas, 100, 250, 400, 250, 'width'=>2) TkcLine.new($plot_canvas, 100, 250, 100, 50, 'width'=>2) TkcText.new($plot_canvas, 225, 20, 'text'=>"A Simple Plot", 'font'=>plotFont, 'fill'=>'brown') (0..10).each {|i| x = 100 + (i * 30) TkcLine.new($plot_canvas, x, 250, x, 245, 'width'=>2) TkcText.new($plot_canvas, x, 254, 'text'=>10*i, 'font'=>plotFont, 'anchor'=>'n') } (0..5).each {|i| y = 250 - (i * 40) TkcLine.new($plot_canvas, 100, y, 105, y, 'width'=>2) TkcText.new($plot_canvas, 96, y, 'text'=>"#{i*50}.0", 'font'=>plotFont, 'anchor'=>'e') } for xx, yy in [[12,56],[20,94],[33,98],[32,120],[61,180],[75,160],[98,223]] x = 100 + (3*xx) y = 250 - (4*yy)/5 item = TkcOval.new($plot_canvas, x-6, y-6, x+6, y+6, 'width'=>1, 'outline'=>'black', 'fill'=>'SkyBlue2') item.addtag 'point' end $plot_canvas.itembind('point', 'Any-Enter', proc{$plot_canvas.itemconfigure 'current','fill','red'}) $plot_canvas.itembind('point', 'Any-Leave', proc{$plot_canvas.itemconfigure 'current','fill','SkyBlue2'}) $plot_canvas.itembind('point', '1', proc{|x,y| plotDown $plot_canvas,x,y}, "%x %y") $plot_canvas.itembind('point', 'ButtonRelease-1', proc{$plot_canvas.dtag 'selected'}) $plot_canvas.bind('B1-Motion', proc{|x,y| plotMove $plot_canvas,x,y}, "%x %y") $plot = {'lastX'=>0, 'lastY'=>0} # plotDown -- # This method is invoked when the mouse is pressed over one of the # data points. It sets up state to allow the point to be dragged. # # Arguments: # w - The canvas window. # x, y - The coordinates of the mouse press. def plotDown (w, x, y) w.dtag 'selected' w.addtag_withtag 'selected', 'current' w.raise 'current' $plot['lastX'] = x $plot['lastY'] = y end # plotMove -- # This method is invoked during mouse motion events. It drags the # current item. # # Arguments: # w - The canvas window. # x, y - The coordinates of the mouse. def plotMove (w, x, y) w.move 'selected', x - $plot['lastX'], y - $plot['lastY'] $plot['lastX'] = x $plot['lastY'] = y end ================================================ FILE: ext/tk/sample/demos-en/puzzle.rb ================================================ # puzzle.rb # # This demonstration script creates a 15-puzzle game using a collection # of buttons. # # widet demo 'puzzle' (called by 'widget') # # toplevel widget if defined?($puzzle_demo) && $puzzle_demo $puzzle_demo.destroy $puzzle_demo = nil end # demo toplevel widget $puzzle_demo = TkToplevel.new {|w| title("15-Puzzle Demonstration") iconname("15-Puzzle") positionWindow(w) } base_frame = TkFrame.new($puzzle_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "A 15-puzzle appears below as a collection of buttons. Click on any of the pieces next to the space, and that piece will slide over the space. Continue this until the pieces are arranged in numerical order from upper-left to lower-right." } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $puzzle_demo $puzzle_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'puzzle'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame # Special trick: select a darker color for the space by creating a # scrollbar widget and using its trough color. begin if Tk.windowingsystem() == 'aqua' frameWidth = 168 frameHeight = 168 elsif Tk.default_widget_set == :Ttk frameWidth = 148 frameHeight = 124 else frameWidth = 120 frameHeight = 120 end rescue frameWidth = 120 frameHeight = 120 end # depend_on_button_width = true depend_on_button_width = false s = TkScrollbar.new(base_frame) base = TkFrame.new(base_frame) { width frameWidth height frameHeight borderwidth 2 relief 'sunken' bg s['troughcolor'] } s.destroy base.pack('side'=>'top', 'padx'=>'1c', 'pady'=>'1c') def def_puzzleswitch_proc(w, num) proc{puzzleSwitch w, num} end $xpos = {} $ypos = {} order = [3,1,6,2,5,7,15,13,4,11,8,9,14,10,12] (0..14).each{|i| num = order[i] $xpos[num] = (i % 4) * 0.25 $ypos[num] = (i / 4) * 0.25 TkButton.new(base) {|w| relief 'raised' text num highlightthickness 0 command def_puzzleswitch_proc(w, num) if depend_on_button_width && (w.winfo_reqwidth * 4 > base.width) base.width = w.winfo_reqwidth * 4 end }.place('relx'=>$xpos[num], 'rely'=>$ypos[num], 'relwidth'=>0.25, 'relheight'=>0.25) } $xpos['space'] = 0.75 $ypos['space'] = 0.75 # puzzleSwitch -- # This procedure is invoked when the user clicks on a particular button; # if the button is next to the empty space, it moves the button into the # empty space. def puzzleSwitch(w, num) if ( ($ypos[num] >= ($ypos['space'] - 0.01)) \ && ($ypos[num] <= ($ypos['space'] + 0.01)) \ && ($xpos[num] >= ($xpos['space'] - 0.26)) \ && ($xpos[num] <= ($xpos['space'] + 0.26))) \ || (($xpos[num] >= ($xpos['space'] - 0.01)) \ && ($xpos[num] <= ($xpos['space'] + 0.01)) \ && ($ypos[num] >= ($ypos['space'] - 0.26)) \ && ($ypos[num] <= ($ypos['space'] + 0.26))) tmp = $xpos['space'] $xpos['space'] = $xpos[num] $xpos[num] = tmp tmp = $ypos['space'] $ypos['space'] = $ypos[num] $ypos[num] = tmp w.place('relx'=>$xpos[num], 'rely'=>$ypos[num]) end end ================================================ FILE: ext/tk/sample/demos-en/radio.rb ================================================ # radio.rb # # This demonstration script creates a toplevel window containing # several radiobutton widgets. # # radiobutton widget demo (called by 'widget') # # toplevel widget if defined?($radio_demo) && $radio_demo $radio_demo.destroy $radio_demo = nil end # demo toplevel widget $radio_demo = TkToplevel.new {|w| title("Radiobutton Demonstration") iconname("radio") positionWindow(w) } base_frame = TkFrame.new($radio_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "Two groups of radiobuttons are displayed below. If you click on a button then the button will become selected exclusively among all the buttons in its group. A Tcl variable is associated with each group to indicate which of the group's buttons is selected. Click the \"See Variables\" button to see the current values of the variables." } msg.pack('side'=>'top') # size = TkVariable.new color = TkVariable.new # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $radio_demo $radio_demo = nil $showVarsWin[tmppath.path] = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'radio'} }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'See Variables' command proc{ showVars(base_frame, ['size', size], ['color', color]) } }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame f_left = TkFrame.new(base_frame) f_right = TkFrame.new(base_frame) f_left.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c') f_right.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c') # radiobutton [10, 12, 18, 24].each {|sz| TkRadioButton.new(f_left) { text "Point Size #{sz}" variable size relief 'flat' value sz }.pack('side'=>'top', 'pady'=>2, 'anchor'=>'w') } ['Red', 'Green', 'Blue', 'Yellow', 'Orange', 'Purple'].each {|col| TkRadioButton.new(f_right) { text col variable color relief 'flat' value col.downcase }.pack('side'=>'top', 'pady'=>2, 'anchor'=>'w') } ================================================ FILE: ext/tk/sample/demos-en/radio2.rb ================================================ # radio2.rb # # This demonstration script creates a toplevel window containing # several radiobutton widgets. # # radiobutton widget demo (called by 'widget') # # toplevel widget if defined?($radio2_demo) && $radio2_demo $radio2_demo.destroy $radio2_demo = nil end # demo toplevel widget $radio2_demo = TkToplevel.new {|w| title("Radiobutton Demonstration 2") iconname("radio2") positionWindow(w) } base_frame = TkFrame.new($radio2_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '5i' justify 'left' text "Three groups of radiobuttons are displayed below. If you click on a button then the button will become selected exclusively among all the buttons in its group. A Tcl variable is associated with each group to indicate which of the group's buttons is selected. Click the \"See Variables\" button to see the current values of the variables." } msg.pack('side'=>'top') # size = TkVariable.new color = TkVariable.new align = TkVariable.new # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $radio2_demo $radio2_demo = nil $showVarsWin[tmppath.path] = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'radio2'} }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'See Variables' command proc{ showVars(base_frame, ['size', size], ['color', color], ['compound', align]) } }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame f_left = TkLabelFrame.new(base_frame, 'text'=>'Point Size', 'pady'=>2, 'padx'=>2) f_mid = TkLabelFrame.new(base_frame, 'text'=>'Color', 'pady'=>2, 'padx'=>2) f_right = TkLabelFrame.new(base_frame, 'text'=>'Alignment', 'pady'=>2, 'padx'=>2) f_left.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c') f_mid.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c') f_right.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c') # radiobutton [10, 12, 18, 24].each {|sz| TkRadioButton.new(f_left) { text "Point Size #{sz}" variable size relief 'flat' value sz }.pack('side'=>'top', 'pady'=>2, 'anchor'=>'w', 'fill'=>'x') } ['Red', 'Green', 'Blue', 'Yellow', 'Orange', 'Purple'].each {|col| TkRadioButton.new(f_mid) { text col variable color relief 'flat' value col.downcase anchor 'w' }.pack('side'=>'top', 'pady'=>2, 'fill'=>'x') } # label = TkLabel.new(f_right, 'text'=>'Label', 'bitmap'=>'questhead', label = Tk::Label.new(f_right, 'text'=>'Label', 'bitmap'=>'questhead', 'compound'=>'left') label.configure('width'=>TkWinfo.reqwidth(label), 'compound'=>'top') label.height(TkWinfo.reqheight(label)) abtn = ['Top', 'Left', 'Right', 'Bottom'].collect{|a| lower = a.downcase TkRadioButton.new(f_right, 'text'=>a, 'variable'=>align, 'relief'=>'flat', 'value'=>lower, 'indicatoron'=>0, 'width'=>7, 'command'=>proc{label.compound(align.value)}) } Tk.grid('x', abtn[0]) Tk.grid(abtn[1], label, abtn[2]) Tk.grid('x', abtn[3]) ================================================ FILE: ext/tk/sample/demos-en/radio3.rb ================================================ # radio3.rb # # This demonstration script creates a toplevel window containing # several radiobutton widgets. # # radiobutton widget demo (called by 'widget') # # toplevel widget if defined?($radio3_demo) && $radio3_demo $radio3_demo.destroy $radio3_demo = nil end # demo toplevel widget $radio3_demo = TkToplevel.new {|w| title("Radiobutton Demonstration 3") iconname("radio3") positionWindow(w) } base_frame = TkFrame.new($radio3_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '5i' justify 'left' text "Three groups of radiobuttons are displayed below. If you click on a button then the button will become selected exclusively among all the buttons in its group. A Tcl variable is associated with each group to indicate which of the group's buttons is selected. When the 'Tristate' button is pressed, the radio buttons will display the tri-state mode. Selecting any radio button will return the buttons to their respective on/off state. Click the \"See Variables\" button to see the current values of the variables." } msg.grid(:row=>0, :column=>0, :columnspan=>3, :sticky=>'nsew') # variable size = TkVariable.new color = TkVariable.new align = TkVariable.new # frame TkFrame.new(base_frame) {|frame| TkGrid(TkFrame.new(frame, :height=>2, :relief=>:sunken, :bd=>2), :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', TkButton.new(frame, :text=>'See Variables', :image=>$image['view'], :compound=>:left, :command=>proc{ showVars(base_frame, ['size', size], ['color', color], ['compound', align]) }), TkButton.new(frame, :text=>'See Code', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'radio3'}), TkButton.new(frame, :text=>'Dismiss', :image=>$image['delete'], :compound=>:left, :command=>proc{ tmppath = $radio3_demo $radio3_demo = nil $showVarsWin[tmppath.path] = nil tmppath.destroy }), :padx=>4, :pady=>4) frame.grid_columnconfigure(0, :weight=>1) TkGrid(frame, :row=>3, :column=>0, :columnspan=>3, :sticky=>'nsew') } # frame f_left = TkLabelFrame.new(base_frame, 'text'=>'Point Size', 'pady'=>2, 'padx'=>2) f_mid = TkLabelFrame.new(base_frame, 'text'=>'Color', 'pady'=>2, 'padx'=>2) f_right = TkLabelFrame.new(base_frame, 'text'=>'Alignment', 'pady'=>2, 'padx'=>2) f_left .grid('column'=>0, 'row'=>1, 'pady'=>'.5c', 'padx'=>'.5c', 'rowspan'=>2) f_mid .grid('column'=>1, 'row'=>1, 'pady'=>'.5c', 'padx'=>'.5c', 'rowspan'=>2) f_right.grid('column'=>2, 'row'=>1, 'pady'=>'.5c', 'padx'=>'.5c') TkButton.new(base_frame, 'text'=>'Tristate', 'command'=>proc{size.value = 'multi'; color.value = 'multi'}){ grid('column'=>2, 'row'=>2, 'pady'=>'.5c', 'padx'=>'.5c') } # radiobutton [10, 12, 14, 18, 24].each {|sz| TkRadioButton.new(f_left) { text "Point Size #{sz}" variable size relief 'flat' value sz tristatevalue 'multi' }.pack('side'=>'top', 'pady'=>2, 'anchor'=>'w', 'fill'=>'x') } ['Red', 'Green', 'Blue', 'Yellow', 'Orange', 'Purple'].each {|col| TkRadioButton.new(f_mid) { text col variable color relief 'flat' value col.downcase anchor 'w' tristatevalue 'multi' command proc{f_mid.fg(color.value)} }.pack('side'=>'top', 'pady'=>2, 'fill'=>'x') } # label = TkLabel.new(f_right, 'text'=>'Label', 'bitmap'=>'questhead', label = Tk::Label.new(f_right, 'text'=>'Label', 'bitmap'=>'questhead', 'compound'=>'left') label.configure('width'=>TkWinfo.reqwidth(label), 'compound'=>'top') label.height(TkWinfo.reqheight(label)) a_btn = ['Top', 'Left', 'Right', 'Bottom'].collect{|a| TkRadioButton.new(f_right, 'text'=>a, 'variable'=>align, 'relief'=>'flat', 'value'=>a.downcase, 'indicatoron'=>0, 'width'=>7, 'command'=>proc{label.compound(align.value)}) } Tk.grid('x', a_btn[0]) Tk.grid(a_btn[1], label, a_btn[2]) Tk.grid('x', a_btn[3]) ================================================ FILE: ext/tk/sample/demos-en/rmt ================================================ #!/usr/bin/env ruby # rmt -- # This script implements a simple remote-control mechanism for # Tk applications. It allows you to select an application and # then type commands to that application. require 'tk' class Rmt def initialize(parent=nil) win = self unless parent parent = TkRoot.new end root = TkWinfo.toplevel(parent) root.minsize(1,1) # The instance variable below keeps track of the remote application # that we're sending to. If it's an empty string then we execute # the commands locally. @app = 'local' @mode = 'Ruby' # The instance variable below keeps track of whether we're in the # middle of executing a command entered via the text. @executing = 0 # The instance variable below keeps track of the last command executed, # so it can be re-executed in response to !! commands. @lastCommand = "" # Create menu bar. Arrange to recreate all the information in the # applications sub-menu whenever it is cascaded to. TkFrame.new(root, 'relief'=>'raised', 'bd'=>2) {|f| pack('side'=>'top', 'fill'=>'x') TkMenubutton.new(f, 'text'=>'File', 'underline'=>0) {|mb| TkMenu.new(mb) {|mf| mb.menu(mf) TkMenu.new(mf) {|ma| postcommand proc{win.fillAppsMenu ma} mf.add('cascade', 'label'=>'Select Application', 'menu'=>ma, 'underline'=>0) } add('command', 'label'=>'Quit', 'command'=>proc{root.destroy}, 'underline'=>0) } pack('side'=>'left') } } # Create text window and scrollbar. @txt = TkText.new(root, 'relief'=>'sunken', 'bd'=>2, 'setgrid'=>true) { yscrollbar(TkScrollbar.new(root){pack('side'=>'right', 'fill'=>'y')}) pack('side'=>'left') } @promptEnd = TkTextMark.new(@txt, 'insert') # Create a binding to forward commands to the target application, # plus modify many of the built-in bindings so that only information # in the current command can be deleted (can still set the cursor # earlier in the text and select and insert; just can't delete). @txt.bindtags([@txt, TkText, root, 'all']) @txt.bind('Return', proc{ @txt.set_insert('end - 1c') @txt.insert('insert', "\n") win.invoke Tk.callback_break }) @txt.bind('Delete', proc{ begin @txt.tag_remove('sel', 'sel.first', @promptEnd) rescue end if @txt.tag_nextrange('sel', '1.0', 'end') == [] if @txt.compare('insert', '<', @promptEnd) Tk.callback_break end end }) @txt.bind('BackSpace', proc{ begin @txt.tag_remove('sel', 'sel.first', @promptEnd) rescue end if @txt.tag_nextrange('sel', '1.0', 'end') == [] if @txt.compare('insert', '<', @promptEnd) Tk.callback_break end end }) @txt.bind('Control-d', proc{ if @txt.compare('insert', '<', @promptEnd) Tk.callback_break end }) @txt.bind('Control-k', proc{ if @txt.compare('insert', '<', @promptEnd) @txt.set_insert(@promptEnd) end }) @txt.bind('Control-t', proc{ if @txt.compare('insert', '<', @promptEnd) Tk.callback_break end }) @txt.bind('Meta-d', proc{ if @txt.compare('insert', '<', @promptEnd) Tk.callback_break end }) @txt.bind('Meta-BackSpace', proc{ if @txt.compare('insert', '<=', @promptEnd) Tk.callback_break end }) @txt.bind('Control-h', proc{ if @txt.compare('insert', '<=', @promptEnd) Tk.callback_break end }) @txt.tag_configure('bold', 'font'=>['Courier', 12, 'bold']) @app = Tk.appname('rmt') if (@app =~ /^rmt(.*)$/) root.title("Tk Remote Controller#{$1}") root.iconname("Tk Remote#{$1}") end prompt @txt.focus #@app = TkWinfo.appname(TkRoot.new) end def tkTextInsert(w,s) return if s == "" begin if w.compare('sel.first','<=','insert') \ && w.compare('sel.last','>=','insert') w.tag_remove('sel', 'sel.first', @promptEnd) w.delete('sel.first', 'sel.last') end rescue end w.insert('insert', s) w.see('insert') end # The method below is used to print out a prompt at the # insertion point (which should be at the beginning of a line # right now). def prompt @txt.insert('insert', "#{@app}: ") @promptEnd.set('insert') @promptEnd.gravity = 'left' @txt.tag_add('bold', "#{@promptEnd.path} linestart", @promptEnd) end # The method below executes a command (it takes everything on the # current line after the prompt and either sends it to the remote # application or executes it locally, depending on "app". def invoke cmd = @txt.get(@promptEnd, 'insert') @executing += 1 case (@mode) when 'Tcl' if Tk.info('complete', cmd) if (cmd == "!!\n") cmd = @lastCommand else @lastCommand = cmd end begin msg = Tk.appsend(@app, false, cmd) rescue msg = "Error: #{$!}" end @txt.insert('insert', msg + "\n") if msg != "" prompt @promptEnd.set('insert') end when 'Ruby' if (cmd == "!!\n") cmd = @lastCommand end complete = true begin eval("proc{#{cmd}}") rescue complete = false end if complete @lastCommand = cmd begin # msg = Tk.appsend(@app, false, # 'ruby', # '"(' + cmd.gsub(/[][$"]/, '\\\\\&') + ').to_s"') msg = Tk.rb_appsend(@app, false, cmd) rescue msg = "Error: #{$!}" end @txt.insert('insert', msg + "\n") if msg != "" prompt @promptEnd.set('insert') end end @executing -= 1 @txt.yview_pickplace('insert') end # The following method is invoked to change the application that # we're talking to. It also updates the prompt for the current # command, unless we're in the middle of executing a command from # the text item (in which case a new prompt is about to be output # so there's no need to change the old one). def newApp(appName, mode) @app = appName @mode = mode if @executing == 0 @promptEnd.gravity = 'right' @txt.delete("#{@promptEnd.path} linestart", @promptEnd) @txt.insert(@promptEnd, "#{appName}: ") @txt.tag_add('bold', "#{@promptEnd.path} linestart", @promptEnd) @promptEnd.gravity = 'left' end end # The method below will fill in the applications sub-menu with a list # of all the applications that currently exist. def fillAppsMenu(menu) win = self begin menu.delete(0,'last') rescue end TkWinfo.interps.sort.each{|ip| begin if Tk.appsend(ip, false, 'info commands ruby') == "" mode = 'Tcl' else mode = 'Ruby' end menu.add('command', 'label'=>format("%s (#{mode}/Tk)", ip), 'command'=>proc{win.newApp ip, mode}) rescue menu.add('command', 'label'=>format("%s (unknown Tk)", ip), 'command'=>proc{win.newApp ip, mode}, 'state'=>'disabled') end } menu.add('command', 'label'=>format("local (Ruby/Tk)"), 'command'=>proc{win.newApp 'local', 'Ruby'}) end end Rmt.new Tk.mainloop ================================================ FILE: ext/tk/sample/demos-en/rolodex ================================================ #!/usr/bin/env ruby # # rolodex -- # This script is a part of Tom LaStrange's rolodex # # Copyright (C) 1998 by Takaaki Tateishi # Time-stamp: "03/08/02 06:23:06 nagai" # require "tk" def show_help(topic,x=0,y=0) if( topic.is_a?(TkWindow) ) w = TkWinfo.containing(x,y) if( TkWinfo.exist?(w) ) topic = w end end if( $helpTopics.include?(topic) ) msg = $helpTopics[topic] else msg = "Sorry, but no help is available for this topic" end TkDialog.new("title"=>"Rolodex Help", "message"=>"Information on #{topic}:\n\n#{msg}", "default_button"=>0, "buttons"=>["OK"]) end def fillCard clearAction $root.frame.entry[1].insert(0,"Takaaki Tateishi") $root.frame.entry[2].insert(0,"Japan Advanced Institute of Science and Techonology") $root.frame.entry[3].insert(0,"1-1 Asahidai, Tatsunokuchi") $root.frame.entry[4].insert(0,"Ishikawa 923-1292, Japan") $root.frame.entry[5].insert(0,"private") $root.frame.entry[6].insert(0,"***-***-****") $root.frame.entry[7].insert(0,"***-***-****") end def addAction for i in 1..7 STDERR.print format("%-12s %s\n", RolodexFrame::LABEL[i], $root.frame.entry[i].value) end end def clearAction for i in 1..7 $root.frame.entry[i].delete(0,"end") end end def fileAction TkDialog.new("title"=>"File Selection", "message"=>"This is a dummy file selection dialog box.\n", "default_button"=>0, "buttons"=>["OK"]) STDERR.print "dummy file name\n" end def deleteAction result = TkDialog.new("title"=>"Confirm Action", "message"=>"Are you sure?", "default_button"=>0, "buttons"=>["Cancel"]) if( result.value == 0 ) clearAction end end class RolodexFrame < TkFrame attr_reader :entry, :label LABEL = ["","Name:","Address:","","","Home Phone:","Work Phone:","Fax:"] def initialize(parent=nil,keys=nil) super(parent,keys) self["relief"] = "flat" @i = [] @label = [] @entry = [] for i in 1..7 @i[i] = TkFrame.new(self) @i[i].pack("side"=>"top", "pady"=>2, "anchor"=>"e") @label[i] = TkLabel.new(@i[i], "text"=>LABEL[i], "anchor"=>"e") @entry[i] = TkEntry.new(@i[i], "width"=>30, "relief"=>"sunken") @entry[i].pack("side"=>"right") @label[i].pack("side"=>"right") end end end class RolodexButtons < TkFrame attr_reader :clear, :add, :search, :delete def initialize(parent,keys=nil) super(parent,keys) @clear = TkButton.new(self, "text" => "Clear") @add = TkButton.new(self, "text" => "Add") @search = TkButton.new(self, "text" => "Search") @delete = TkButton.new(self, "text" => "Delete") for w in [@clear,@add,@search,@delete] w.pack("side"=>"left", "padx"=>2) end end end class RolodexMenuFrame < TkFrame attr_reader :file_menu, :help_menu, :file, :help def initialize(parent,keys=nil) super(parent,keys) configure("relief"=>"raised", "borderwidth"=>1) @file = TkMenubutton.new(self, "text"=>"File", "underline"=>0) @file_menu = TkMenu.new(@file) @file_menu.add("command", "label" => "Load ...", "command" => proc{fileAction}, "underline" => 0) @file_menu.add("command", "label" => "Exit", "command" => proc{$root.destroy}, "underline" => 0) @file.menu(@file_menu) @file.pack("side"=>"left") @help = TkMenubutton.new(self, "text"=>"Help", "underline"=>0) @help_menu = TkMenu.new(@help) @help_menu.add("command", "label"=>"On Context...", "command"=>proc{show_help("context")}, "underline"=>3) @help_menu.add("command", "label"=>"On Help...", "command"=>proc{show_help("help")}, "underline"=>3) @help_menu.add("command", "label"=>"On Window...", "command"=>proc{show_help("window")}, "underline"=>3) @help_menu.add("command", "label"=>"On Keys...", "command"=>proc{show_help("keys")}, "underline"=>3) @help_menu.add("command", "label"=>"On version...", "command"=>proc{show_help("version")}, "underline"=>3) @help.menu(@help_menu) @help.pack("side"=>"right") end end class Rolodex < TkRoot attr_reader :frame, :buttons, :menu def initialize(*args) super(*args) @frame = RolodexFrame.new(self) @frame.pack("side"=>"top", "fill"=>"y", "anchor"=>"center") @buttons = RolodexButtons.new(self) @buttons.pack("side"=>"bottom", "pady"=>2, "anchor"=>"center") @menu = RolodexMenuFrame.new(self) @menu.pack("before"=>@frame, "side"=>"top", "fill"=>"x") end end $root = Rolodex.new $root.buttons.delete.configure("command"=>proc{deleteAction}) $root.buttons.add.configure("command"=>proc{addAction}) $root.buttons.clear.configure("command"=>proc{clearAction}) $root.buttons.search.configure("command"=>proc{addAction; fillCard}) $root.buttons.clear.configure("text"=>"Clear Ctrl+C") $root.bind("Control-c",proc{clearAction}) $root.buttons.add.configure("text"=>"Add Ctrl+A") $root.bind("Control-a",proc{addAction}) $root.buttons.search.configure("text"=>"Search Ctrl+S") $root.bind("Control-s",proc{addAction; fillCard}) $root.buttons.delete.configure("text"=>"Delete... Ctrl+D") $root.bind("Control-d",proc{deleteAction}) $root.menu.file_menu.entryconfigure(1, "accel"=>"Ctrl+F") $root.bind("Control-f",proc{fileAction}) $root.menu.file_menu.entryconfigure(2, "accel"=>"Ctrl+Q") $root.bind("Control-q",proc{$root.destroy}) $root.frame.entry[1].focus $root.bind("Any-F1", proc{|event| show_help(event.widget, event.x_root, event.y_root)}) $root.bind("Any-Help", proc{|event| show_help(event.widget, event.x_root, event.y_root)}) $helpTopics = {} $helpTopics[$root.menu.file] = <:both, :expand=>true) # label TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left', 'text'=>"This canvas widget shows a mock-up of a ruler. You can create tab stops by dragging them out of the well to the right of the ruler. You can also drag existing tab stops. If you drag a tab stop far enough up or down so that it turns dim, it will be deleted when you release the mouse button."){ pack('side'=>'top') } # frame $ruler_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $ruler_demo $ruler_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'ruler'} }.pack('side'=>'left', 'expand'=>'yes') } $ruler_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # canvas $ruler_canvas = TkCanvas.new(base_frame, 'width'=>'14.8c', 'height'=>'2.5c') $ruler_canvas.pack('side'=>'top', 'fill'=>'x') # unless Struct.const_defined?("RulerInfo") $demo_rulerInfo = Struct.new("RulerInfo", :grid, :left, :right, :x, :y, :top, :bottom, :size, :normalStyle, :activeStyle, :deleteStyle).new end $demo_rulerInfo.grid = '.25c' $demo_rulerInfo.left = TkWinfo.fpixels($ruler_canvas, '1c') $demo_rulerInfo.right = TkWinfo.fpixels($ruler_canvas, '13c') $demo_rulerInfo.top = TkWinfo.fpixels($ruler_canvas, '1c') $demo_rulerInfo.bottom = TkWinfo.fpixels($ruler_canvas, '1.5c') $demo_rulerInfo.size = TkWinfo.fpixels($ruler_canvas, '.2c') $demo_rulerInfo.normalStyle = {'fill'=>'black'} if TkWinfo.depth($ruler_canvas) > 1 $demo_rulerInfo.activeStyle = {'fill'=>'red', 'stipple'=>''} $demo_rulerInfo.deleteStyle = {'fill'=>'red', 'stipple'=>'@'+[$demo_dir, '..', 'images', 'gray25.xbm'].join(File::Separator)} else $demo_rulerInfo.activeStyle = {'fill'=>'black', 'stipple'=>''} $demo_rulerInfo.deleteStyle = {'fill'=>'black', 'stipple'=>'@'+[$demo_dir, '..', 'images', 'gray25.xbm'].join(File::Separator)} end TkcLine.new($ruler_canvas, '1c', '0.5c', '1c', '1c', '13c', '1c', '13c', '0.5c', 'width'=>1) (0..11).each{|i| x = i+1 TkcLine.new($ruler_canvas, "#{x}c", '1c', "#{x}c", '0.6c', 'width'=>1) TkcLine.new($ruler_canvas, "#{x}.25c", '1c', "#{x}.25c", '0.8c', 'width'=>1) TkcLine.new($ruler_canvas, "#{x}.5c", '1c', "#{x}.5c", '0.7c', 'width'=>1) TkcLine.new($ruler_canvas, "#{x}.75c", '1c', "#{x}.75c", '0.8c', 'width'=>1) TkcText.new($ruler_canvas, "#{x}.15c", '0.75c', 'text'=>i, 'anchor'=>'sw') } $rulerTag_well = TkcTag.new($ruler_canvas) $ruler_canvas\ .addtag_withtag($rulerTag_well, TkcRectangle.new($ruler_canvas, '13.2c', '1c', '13.8c', '0.5c', 'outline'=>'black', 'fill'=>($ruler_canvas\ .configinfo('background'))[4]) ) $ruler_canvas\ .addtag_withtag($rulerTag_well, rulerMkTab($ruler_canvas, TkWinfo.pixels($ruler_canvas, '13.5c'), TkWinfo.pixels($ruler_canvas, '.65c') ) ) $rulerTag_well.bind('1', proc{|x,y| rulerNewTab($ruler_canvas,x,y)}, '%x %y') $ruler_canvas.itembind('tab', '1', proc{|x,y| rulerSelectTab($ruler_canvas,x,y)}, '%x %y') $ruler_canvas.bind('B1-Motion', proc{|x,y| rulerMoveTab($ruler_canvas,x,y)}, '%x %y') $ruler_canvas.bind('Any-ButtonRelease-1', proc{rulerReleaseTab($ruler_canvas)}) # rulerNewTab -- # Does all the work of creating a tab stop, including creating the # triangle object and adding tags to it to give it tab behavior. # # Arguments: # c - The canvas window. # x, y - The coordinates of the tab stop. def rulerNewTab(c,x,y) v = $demo_rulerInfo c.addtag_withtag('active', rulerMkTab(c,x,y)) c.addtag_withtag('tab', 'active') v.x = x v.y = y rulerMoveTab(c,x,y) end # rulerSelectTab -- # This method is invoked when mouse button 1 is pressed over # a tab. It remembers information about the tab so that it can # be dragged interactively. # # Arguments: # c - The canvas widget. # x, y - The coordinates of the mouse (identifies the point by # which the tab was picked up for dragging). def rulerSelectTab(c,x,y) v = $demo_rulerInfo v.x = c.canvasx(x, v.grid) v.y = v.top+2 c.addtag_withtag('active', 'current') c.itemconfigure('active', v.activeStyle) c.raise('active') end # rulerMoveTab -- # This method is invoked during mouse motion events to drag a tab. # It adjusts the position of the tab, and changes its appearance if # it is about to be dragged out of the ruler. # # Arguments: # c - The canvas widget. # x, y - The coordinates of the mouse. def rulerMoveTab(c,x,y) v = $demo_rulerInfo return if c.find_withtag('active') == [] cx = c.canvasx(x,v.grid) cy = c.canvasy(y) cx = v.left if cx < v.left cx = v.right if cx > v.right if (cy >= v.top && cy <= v.bottom) cy = v.top+2 c.itemconfigure('active', v.activeStyle) else cy = cy-v.size-2 c.itemconfigure('active', v.deleteStyle) end c.move('active', cx-v.x, cy-v.y) v.x = cx v.y = cy end # rulerReleaseTab -- # This method is invoked during button release events that end # a tab drag operation. It deselects the tab and deletes the tab if # it was dragged out of the ruler. # # Arguments: # c - The canvas widget. # x, y - The coordinates of the mouse. def rulerReleaseTab(c) v = $demo_rulerInfo return if c.find_withtag('active') == [] if v.y != v.top+2 c.delete('active') else c.itemconfigure('active', v.normalStyle) c.dtag('active') end end ================================================ FILE: ext/tk/sample/demos-en/sayings.rb ================================================ # sayings.rb # # This demonstration script creates a listbox that can be scrolled # both horizontally and vertically. It displays a collection of # well-known sayings. # # listbox widget demo 'sayings' (called by 'widget') # # toplevel widget if defined?($sayings_demo) && $sayings_demo $sayings_demo.destroy $sayings_demo = nil end # demo toplevel widget $sayings_demo = TkToplevel.new {|w| title("Listbox Demonstration (well-known sayings)") iconname("sayings") positionWindow(w) } base_frame = TkFrame.new($sayings_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "The listbox below contains a collection of well-known sayings. You can scan the list using either of the scrollbars or by dragging in the listbox window with button 2 pressed." } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $sayings_demo $sayings_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'sayings'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame sayings_lbox = nil TkFrame.new(base_frame, 'borderwidth'=>10) {|w| sv = TkScrollbar.new(w) sh = TkScrollbar.new(w, 'orient'=>'horizontal') sayings_lbox = TkListbox.new(w) { setgrid 1 width 20 height 10 yscrollcommand proc{|first,last| sv.set first,last} xscrollcommand proc{|first,last| sh.set first,last} } sv.command(proc{|*args| sayings_lbox.yview(*args)}) sh.command(proc{|*args| sayings_lbox.xview(*args)}) if $tk_version =~ /^4\.[01]/ sv.pack('side'=>'right', 'fill'=>'y') sh.pack('side'=>'bottom', 'fill'=>'x') sayings_lbox.pack('expand'=>'yes', 'fill'=>'y') else sayings_lbox.grid('row'=>0, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') sv.grid('row'=>0, 'column'=>1, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') sh.grid('row'=>1, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') TkGrid.rowconfigure(w, 0, 'weight'=>1, 'minsize'=>0) TkGrid.columnconfigure(w, 0, 'weight'=>1, 'minsize'=>0) end }.pack('side'=>'top', 'expand'=>'yes', 'fill'=>'y') sayings_lbox.insert(0, "Waste not, want not", "Early to bed and early to rise makes a man healthy, wealthy, and wise", "Ask not what your country can do for you, ask what you can do for your country", "I shall return", "NOT", "A picture is worth a thousand words", "User interfaces are hard to build", "Thou shalt not steal", "A penny for your thoughts", "Fool me once, shame on you; fool me twice, shame on me", "Every cloud has a silver lining", "Where there's smoke there's fire", "It takes one to know one", "Curiosity killed the cat; but satisfaction brought it back", "Take this job and shove it", "Up a creek without a paddle", "I'm mad as hell and I'm not going to take it any more", "An apple a day keeps the doctor away", "Don't look a gift horse in the mouth" ) ================================================ FILE: ext/tk/sample/demos-en/search.rb ================================================ # search.rb # # This demonstration script creates a collection of widgets that # allow you to load a file into a text widget, then perform searches # on that file. # # Text Search widget demo (called by 'widget') # # textLoadFile -- # This method below loads a file into a text widget, discarding # the previous contents of the widget. Tags for the old widget are # not affected, however. # # Arguments: # w - The window into which to load the file. Must be a # text widget. # file - The name of the file to load. Must be readable. def textLoadFile(w,file) w.delete('1.0', 'end') f = open(file, 'r') while(!f.eof?) w.insert('end', f.read(1000)) end f.close end # textSearch -- # Search for all instances of a given string in a text widget and # apply a given tag to each instance found. # # Arguments: # w - The window in which to search. Must be a text widget. # string - The string to search for. The search is done using # exact matching only; no special characters. # tag - Tag to apply to each instance of a matching string. def textSearch(w, string, tag) tag.remove('0.0', 'end') return if string == "" cur = '1.0' loop { cur, len = w.search_with_length(string, cur, 'end') break if cur == "" tag.add(cur, "#{cur} + #{len} char") cur = w.index("#{cur} + #{len} char") } end # textToggle -- # This method is invoked repeatedly to invoke two commands at # periodic intervals. It normally reschedules itself after each # execution but if an error occurs (e.g. because the window was # deleted) then it doesn't reschedule itself. # # Arguments: # cmd1 - Command to execute when method is called. # sleep1 - Ms to sleep after executing cmd1 before executing cmd2. # cmd2 - Command to execute in the *next* invocation of this method. # sleep2 - Ms to sleep after executing cmd2 before executing cmd1 again. def textToggle(cmd1,sleep1,cmd2,sleep2) sleep_list = [sleep2, sleep1] TkAfter.new(proc{sleep = sleep_list.shift; sleep_list.push(sleep); sleep}, -1, cmd1, cmd2).start(sleep1) end # toplevel widget if defined?($search_demo) && $search_demo $search_demo.destroy $search_demo = nil end # demo toplevel widget $search_demo = TkToplevel.new {|w| title("Text Demonstration - Search and Highlight") iconname("search") positionWindow(w) } base_frame = TkFrame.new($search_demo).pack(:fill=>:both, :expand=>true) # frame $search_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $search_demo $search_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'search'} }.pack('side'=>'left', 'expand'=>'yes') } $search_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame TkFrame.new(base_frame) {|f| TkLabel.new(f, 'text'=>'File name:', 'width'=>13, 'anchor'=>'w').pack('side'=>'left') $search_fileName = TkVariable.new TkEntry.new(f, 'width'=>40, 'textvariable'=>$search_fileName) { pack('side'=>'left') bind('Return', proc{textLoadFile($search_text, $search_fileName.value) $search_string_entry.focus}) focus } TkButton.new(f, 'text'=>'Load File', 'command'=>proc{textLoadFile($search_text, $search_fileName.value)})\ .pack('side'=>'left', 'pady'=>5, 'padx'=>10) }.pack('side'=>'top', 'fill'=>'x') TkFrame.new(base_frame) {|f| TkLabel.new(f, 'text'=>'Search string:', 'width'=>13, 'anchor'=>'w').pack('side'=>'left') $search_searchString = TkVariable.new $search_string_entry = TkEntry.new(f, 'width'=>40, 'textvariable'=>$search_searchString) { pack('side'=>'left') bind('Return', proc{textSearch($search_text, $search_searchString.value, $search_Tag)}) } TkButton.new(f, 'text'=>'Highlight', 'command'=>proc{textSearch($search_text, $search_searchString.value, $search_Tag)}) { pack('side'=>'left', 'pady'=>5, 'padx'=>10) } }.pack('side'=>'top', 'fill'=>'x') $search_text = TkText.new(base_frame, 'setgrid'=>true, 'wrap'=>'word') {|t| $search_Tag = TkTextTag.new(t) TkScrollbar.new(base_frame, 'command'=>proc{|*args| t.yview(*args)}) {|sc| t.yscrollcommand(proc{|first,last| sc.set first,last}) pack('side'=>'right', 'fill'=>'y') } pack('expand'=>'yes', 'fill'=>'both') } # Set up display styles for text highlighting. if TkWinfo.depth($search_demo) > 1 textToggle(proc{ $search_Tag.configure('background'=>'#ce5555', 'foreground'=>'white') }, 800, proc{ $search_Tag.configure('background'=>'', 'foreground'=>'') }, 200 ) else textToggle(proc{ $search_Tag.configure('background'=>'black', 'foreground'=>'white') }, 800, proc{ $search_Tag.configure('background'=>'', 'foreground'=>'') }, 200 ) end $search_text.insert('1.0', "\ This window demonstrates how to use the tagging facilities in text \ widgets to implement a searching mechanism. First, type a file name \ in the top entry, then type or click on \"Load File\". Then \ type a string in the lower entry and type or click on \ \"Load File\". This will cause all of the instances of the string to \ be tagged with the tag \"search\", and it will arrange for the tag\'s \ display attributes to change to make all of the strings blink.") $search_text.insert('end', "\ The current directory to load a file is \"#{Dir.pwd}\".\ ") $search_text.set_insert '0.0' $search_fileName.value = '' $search_searchString.value = '' $search_text.width = 60 $search_text.height = 20 ================================================ FILE: ext/tk/sample/demos-en/spin.rb ================================================ # spin.rb -- # # This demonstration script creates several spinbox widgets. # # based on Tcl/Tk8.4.4 widget demos if defined?($spin_demo) && $spin_demo $spin_demo.destroy $spin_demo = nil end $spin_demo = TkToplevel.new {|w| title("Spinbox Demonstration") iconname("spin") positionWindow(w) } base_frame = TkFrame.new($spin_demo).pack(:fill=>:both, :expand=>true) TkLabel.new(base_frame, :font=>$font, :wraplength=>'5i', :justify=>:left, :text=><:top) Three different spin-boxes are displayed below. \ You can add characters by pointing, clicking and typing. \ The normal Motif editing characters are supported, along with \ many Emacs bindings. For example, Backspace and Control-h \ delete the character to the left of the insertion cursor and \ Delete and Control-d delete the chararacter to the right of the \ insertion cursor. For values that are too large to fit in the \ window all at once, you can scan through the value by dragging \ with mouse button2 pressed. Note that the first spin-box will \ only permit you to type in integers, and the third selects from \ a list of Australian cities. If your Tk library linked to Ruby doesn't include a 'spinbox' widget, \ this demo doesn't work. Please use later version of Tk \ which supports a 'spinbox' widget. EOL TkFrame.new(base_frame){|f| pack(:side=>:bottom, :fill=>:x, :pady=>'2m') TkButton.new(f, :text=>'Dismiss', :width=>15, :command=>proc{ $spin_demo.destroy $spin_demo = nil }).pack(:side=>:left, :expand=>true) TkButton.new(f, :text=>'See Code', :width=>15, :command=>proc{ showCode 'spin' }).pack(:side=>:left, :expand=>true) } australianCities = [ 'Canberra', 'Sydney', 'Melbourne', 'Perth', 'Adelaide', 'Brisbane', 'Hobart', 'Darwin', 'Alice Springs' ] [ TkSpinbox.new(base_frame, :from=>1, :to=>10, :width=>10, :validate=>:key, :validatecommand=>[ proc{|s| s == '' || /^[+-]?\d+$/ =~ s }, '%P' ]), TkSpinbox.new(base_frame, :from=>0, :to=>3, :increment=>0.5, :format=>'%05.2f', :width=>10), TkSpinbox.new(base_frame, :values=>australianCities, :width=>10) ].each{|sbox| sbox.pack(:side=>:top, :pady=>5, :padx=>10)} ================================================ FILE: ext/tk/sample/demos-en/square ================================================ #!/usr/bin/env ruby # square -- # This script generates a demo application containing only # a "square" widget. It's only usable if Tk has been compiled # with tkSquare.c and with the -DSQUARE_DEMO compiler switch. # This demo arranges the following bindings for the widget: # # Button-1 press/drag: moves square to mouse # "a": toggle size animation on/off # require 'tk' require 'tkafter' class TkSquare'yes', 'fill'=>'both') bind('1', proc{|x,y| center(x,y)}, '%s %y') bind('B1-Motion', proc{|x,y| center(x,y)}, '%s %y') bind('a', proc{animate}) focus } TkRoot.new.minsize(1,1) # The procedure below centers the square on a given position. def center(x,y) a = $s.size $s.position(x-(a/2), y-(a/2)) end # The procedures below provide a simple form of animation where # the box changes size in a pulsing pattern: larger, smaller, larger, # and so on. $inc = 0 def timer_proc a = $s.size return if $inc == 0 $inc = -3 if a >= 40 $inc = 3 if a <= 10 $s.size(a+$inc) end $timer = TkAfter.new(30, -1, proc{timer_proc}) def animate if $inc == 0 $inc = 3 $timer.start else $inc = 0 $timer.stop end end Tk.mainloop ================================================ FILE: ext/tk/sample/demos-en/states.rb ================================================ # states.rb # # This demonstration script creates a listbox widget that displays # the names of the 50 states in the United States of America. # # listbox widget demo 'states' (called by 'widget') # # toplevel widget if defined?($states_demo) && $states_demo $states_demo.destroy $states_demo = nil end # demo toplevel widget $states_demo = TkToplevel.new {|w| title("Listbox Demonstration (states)") iconname("states") positionWindow(w) } base_frame = TkFrame.new($states_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "A listbox containing the 50 states is displayed below, along with a scrollbar. You can scan the list either using the scrollbar or by scanning. To scan, press button 2 in the widget and drag up or down." } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $states_demo $states_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'states'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame states_lbox = nil TkFrame.new(base_frame, 'borderwidth'=>'.5c') {|w| s = TkScrollbar.new(w) states_lbox = TkListbox.new(w) { setgrid 1 height 12 yscrollcommand proc{|first,last| s.set first,last} } s.command(proc{|*args| states_lbox.yview(*args)}) s.pack('side'=>'right', 'fill'=>'y') states_lbox.pack('side'=>'left', 'expand'=>1, 'fill'=>'both') }.pack('side'=>'top', 'expand'=>'yes', 'fill'=>'y') ins_data = [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New_Hampshire', 'New_Jersey', 'New_Mexico', 'New_York', 'North_Carolina', 'North_Dakota', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode_Island', 'South_Carolina', 'South_Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West_Virginia', 'Wisconsin', 'Wyoming' ] states_lbox.insert(0, *ins_data) ================================================ FILE: ext/tk/sample/demos-en/style.rb ================================================ # style.rb # # This demonstration script creates a text widget that illustrates the # various display styles that may be set for tags. # # text (display styles) widget demo (called by 'widget') # # toplevel widget if defined?($style_demo) && $style_demo $style_demo.destroy $style_demo = nil end # demo toplevel widget $style_demo = TkToplevel.new {|w| title("Text Demonstration - Display Styles") iconname("style") positionWindow(w) } base_frame = TkFrame.new($style_demo).pack(:fill=>:both, :expand=>true) # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $style_demo $style_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'style'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # text txt = TkText.new(base_frame){|t| # setgrid 'true' #width 70 #height 32 wrap 'word' font $font TkScrollbar.new(base_frame) {|s| pack('side'=>'right', 'fill'=>'y') command proc{|*args| t.yview(*args)} t.yscrollcommand proc{|first,last| s.set first,last} } pack('expand'=>'yes', 'fill'=>'both') # family = 'Courier' if $tk_version =~ /^4.*/ style_tag_bold = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-O-Normal--*-120-*-*-*-*-*-*') style_tag_big = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-R-Normal--*-140-*-*-*-*-*-*', 'kanjifont'=>$msg_kanji_font) style_tag_verybig = TkTextTag.new(t, 'font'=>'-*-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*') # style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*', 'kanjifont'=>$kanji_font) style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*') else style_tag_bold = TkTextTag.new(t, 'font'=>[family, 12, :bold, :italic]) style_tag_big = TkTextTag.new(t, 'font'=>[family, 14, :bold]) style_tag_verybig = TkTextTag.new(t, 'font'=>['Helvetica', 24, :bold]) style_tag_small = TkTextTag.new(t, 'font'=>'Times 8 bold') end ### # case($tk_version) # when /^4.*/ # style_tag_big = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-R-Normal--*-140-*-*-*-*-*-*', 'kanjifont'=>$msg_kanji_font) # style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*', 'kanjifont'=>$kanji_font) # when /^8.*/ # unless $style_demo_do_first # $style_demo_do_first = true # Tk.tk_call('font', 'create', '@bigascii', # '-copy', '-*-Courier-Bold-R-Normal--*-140-*-*-*-*-*-*') # Tk.tk_call('font', 'create', '@smallascii', # '-copy', '-Adobe-Helvetica-Bold-R-Normal-*-100-*') # Tk.tk_call('font', 'create', '@cBigFont', # '-compound', '@bigascii @msg_knj') # Tk.tk_call('font', 'create', '@cSmallFont', # '-compound', '@smallascii @kanji') # end # style_tag_big = TkTextTag.new(t, 'font'=>'@cBigFont') # style_tag_small = TkTextTag.new(t, 'font'=>'@cSmallFont') # end # if TkWinfo.depth($root).to_i > 1 style_tag_color1 = TkTextTag.new(t, 'background'=>'#a0b7ce') style_tag_color2 = TkTextTag.new(t, 'foreground'=>'red') style_tag_raised = TkTextTag.new(t, 'relief'=>'raised', 'borderwidth'=>1) style_tag_sunken = TkTextTag.new(t, 'relief'=>'sunken', 'borderwidth'=>1) else style_tag_color1 = TkTextTag.new(t, 'background'=>'black', 'foreground'=>'white') style_tag_color2 = TkTextTag.new(t, 'background'=>'black', 'foreground'=>'white') style_tag_raised = TkTextTag.new(t, 'background'=>'white', 'relief'=>'raised', 'borderwidth'=>1) style_tag_sunken = TkTextTag.new(t, 'background'=>'white', 'relief'=>'sunken', 'borderwidth'=>1) end # if $tk_version =~ /^4\.[01]/ style_tag_bgstipple = TkTextTag.new(t, 'background'=>'black', 'borderwidth'=>0, 'bgstipple'=>'gray25') else style_tag_bgstipple = TkTextTag.new(t, 'background'=>'black', 'borderwidth'=>0, 'bgstipple'=>'gray12') end style_tag_fgstipple = TkTextTag.new(t, 'fgstipple'=>'gray50') style_tag_underline = TkTextTag.new(t, 'underline'=>'on') style_tag_overstrike = TkTextTag.new(t, 'overstrike'=>'on') style_tag_right = TkTextTag.new(t, 'justify'=>'right') style_tag_center = TkTextTag.new(t, 'justify'=>'center') if $tk_version =~ /^4.*/ style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') else style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>[family, 10]) style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>[family, 10]) end style_tag_margins = TkTextTag.new(t, 'lmargin1'=>'12m', 'lmargin2'=>'6m', 'rmargin'=>'10m') style_tag_spacing = TkTextTag.new(t, 'spacing1'=>'10p', 'spacing2'=>'2p', 'lmargin1'=>'12m', 'lmargin2'=>'6m', 'rmargin'=>'10m') # insert('end', 'Text widgets like this one allow you to display information in a variety of styles. Display styles are controlled using a mechanism called ') insert('end', 'tags', style_tag_big) insert('end', '. Tags are just textual names that you can apply to one or more ranges of characters within a text widget. You can configure tags with various display styles. If you do this, then the tagged characters will be displayed with the styles you chose. The available display styles are: ') insert('end', "\n1. Font.", style_tag_big) insert('end', " You can choose any X font, ") insert('end', "large", style_tag_verybig) insert('end', " or ") insert('end', "small", style_tag_small) insert('end', ".\n") insert('end', "\n2. Color.", style_tag_big) insert('end', " You can change either the ") insert('end', "background", style_tag_color1) insert('end', " or ") insert('end', "foreground", style_tag_color2) insert('end', "\ncolor, or ") insert('end', "both", style_tag_color1, style_tag_color2) insert('end', ".\n") insert('end', "\n3. Stippling.", style_tag_big) insert('end', " You can cause either the ") insert('end', "background", style_tag_bgstipple) insert('end', " or ") insert('end', "foreground", style_tag_fgstipple) insert('end', "\ninformation to be drawn with a stipple fill instead of a solid fill.\n") insert('end', "\n4. Underlining.", style_tag_big) insert('end', " You can ") insert('end', "underline", style_tag_underline) insert('end', " ranges of text.\n") insert('end', "\n5. Overstrikes.", style_tag_big) insert('end', " You can ") insert('end', "draw lines through", style_tag_overstrike) insert('end', " ranges of text.\n") insert('end', "\n6. 3-D effects.", style_tag_big) insert('end', " You can arrange for the background to be drawn\nwith a border that makes characters appear either\n") insert('end', "raised", style_tag_raised) insert('end', " or ") insert('end', "sunken", style_tag_sunken) insert('end', ".\n") insert('end', "\n7. Justification.", style_tag_big) insert('end', " You can arrange for lines to be displayed\n") insert('end', "left-justified,\n") insert('end', "right-justified, or\n", style_tag_right) insert('end', "centered.\n", style_tag_center) insert('end', "\n8. Superscripts and subscripts.", style_tag_big) insert('end', " You can control the vertical\n") insert('end', "position of text to generate superscript effects like 10") insert('end', "n", style_tag_super) insert('end', " or\nsubscript effects like X") insert('end', "i", style_tag_sub) insert('end', ".\n") insert('end', "\n9. Margins.", style_tag_big) insert('end', " You can control the amount of extra space left") insert('end', " on\neach side of the text:\n") insert('end', "This paragraph is an example of the use of ", style_tag_margins) insert('end', "margins. It consists of a single line of text ", style_tag_margins) insert('end', "that wraps around on the screen. There are two ", style_tag_margins) insert('end', "separate left margin values, one for the first ", style_tag_margins) insert('end', "display line associated with the text line, ", style_tag_margins) insert('end', "and one for the subsequent display lines, which ", style_tag_margins) insert('end', "occur because of wrapping. There is also a ", style_tag_margins) insert('end', "separate specification for the right margin, ", style_tag_margins) insert('end', "which is used to choose wrap points for lines.\n", style_tag_margins) insert('end', "\n10. Spacing.", style_tag_big) insert('end', " You can control the spacing of lines with three\n") insert('end', "separate parameters. \"Spacing1\" tells how much ") insert('end', "extra space to leave\nabove a line, \"spacing3\" ") insert('end', "tells how much space to leave below a line,\nand ") insert('end', "if a text line wraps, \"spacing2\" tells how much ") insert('end', "space to leave\nbetween the display lines that ") insert('end', "make up the text line.\n") insert('end', "These indented paragraphs illustrate how spacing ", style_tag_spacing) insert('end', "can be used. Each paragraph is actually a ", style_tag_spacing) insert('end', "single line in the text widget, which is ", style_tag_spacing) insert('end', "word-wrapped by the widget.\n", style_tag_spacing) insert('end', "Spacing1 is set to 10 points for this text, ", style_tag_spacing) insert('end', "which results in relatively large gaps between ", style_tag_spacing) insert('end', "the paragraphs. Spacing2 is set to 2 points, ", style_tag_spacing) insert('end', "which results in just a bit of extra space ", style_tag_spacing) insert('end', "within a pararaph. Spacing3 isn't used ", style_tag_spacing) insert('end', "in this example.\n", style_tag_spacing) insert('end', "To see where the space is, select ranges of ", style_tag_spacing) insert('end', "text within these paragraphs. The selection ", style_tag_spacing) insert('end', "highlight will cover the extra space.", style_tag_spacing) } txt.width 70 txt.height 32 ================================================ FILE: ext/tk/sample/demos-en/tcolor ================================================ #!/usr/bin/env ruby # # tcolor -- # simple color editor which supports RGB, HSB and CYM color space # # Copyright (C) 1998 Takaaki Tateishi(ttate@jaist.ac.jp) # last update: Thu Jun 18 06:32:35 JST 1998 # require "tk" # use TkVariable instance for the variable which is changed by Tk interpreter $colorSpace = TkVariable.new(:rgb) $master = nil $red = 65535 $green = 0 $blue = 0 $color = "#ffff00000000" $updating = TkVariable.new(0) $autoUpdate = TkVariable.new(1) $name = TkVariable.new($color) $command = TkVariable.new("print(%%,\"\n\")") # $command = TkVariable.new("") $label1 = TkVariable.new("label1") $label2 = TkVariable.new("label2") $label3 = TkVariable.new("label3") # setup the entry of the resourc database if (TkVarAccess.new('tcl_platform')['platform'] == 'unix') TkOptionDB.add('*Entry.background', 'white') end # methods for events def rgbToHsv(red,green,blue) if ( red > green ) max = red min = green else max = green min = red end if ( blue > max ) max = blue else if ( blue < min ) min = blue end end range = max - min if ( max == 0 ) sat = 0.0 else sat = (max-min)/max end if ( sat == 0 ) hue = 0.0 else rc = (max-red)/range gc = (max-green)/range bc = (max-blue)/range if ( red == max ) hue = 0.166667 * (bc - gc) else if ( green == max ) hue = 0.166667 * (2.0 + rc - bc) else hue = 0.166667 * (4.0 + gc - rc) end end if ( hue < 0.0 ) hue = hue + 1.0 end end [hue,sat,max/65535] end def hsbToRgb(hue,sat,value) v = 65535.0 * value if( sat == 0 ) ans = [v,v,v] else hue = hue*6.0 if ( hue >= 6 ) hue = 0.0 end i = hue.to_i f = hue - i p = 65535.0 * value * (1.0 - sat) q = 65535.0 * value * (1.0 - (sat * f)) t = 65535.0 * value * (1.0 - (sat * (1.0 - f))) case i when 0 ans = [v,t,p] when 1 ans = [q,v,p] when 2 ans = [p,v,t] when 3 ans = [p,q,v] when 4 ans = [t,p,v] when 5 ans = [v,p,q] else raise(eException,"i value #{i} is out of range") end end return ans end def _null_binding Module.new.instance_eval{binding} end private :_null_binding def doUpdate newCmd = $command.to_s.gsub("%%","\"#{$color}\"") eval(newCmd, _null_binding) end def tc_scaleChanged if( $updating.to_i == 1 ) return end $master = :scale if $master == nil scale1 = $root.middle.middle.scale1 scale2 = $root.middle.middle.scale2 scale3 = $root.middle.middle.scale3 case $colorSpace.value.intern when :rgb $red = (scale1.get * 65.535).to_i $green = (scale2.get * 65.535).to_i $blue = (scale3.get * 65.535).to_i when :cmy $red = (65535 - scale1.get * 65.535).to_i $green = (65535 - scale2.get * 65.535).to_i $blue = (65535 - scale3.get * 65.535).to_i when :hsb list = hsbToRgb(scale1.get / 1000.0, scale2.get / 1000.0, scale3.get / 1000.0) $red = list[0] $green = list[1] $blue = list[2] else raise(Exception,"unknown colorSpace") end $color = format("#%04x%04x%04x",$red.to_i,$green.to_i,$blue.to_i) $name.value = $color if $master == :scale $root.middle.right.set_color($color) if( $autoUpdate.to_i == 1 ) doUpdate end Tk.update(true) $master = nil if $master == :scale end def tc_setScales $updating.value = 1 scale1 = $root.middle.middle.scale1 scale2 = $root.middle.middle.scale2 scale3 = $root.middle.middle.scale3 case $colorSpace.value.intern when :rgb scale1.set($red / 65.535) scale2.set($green / 65.535) scale3.set($blue / 65.535) when :cmy scale1.set((65535 - $red) / 65.535) scale2.set((65535 - $green) / 65.535) scale3.set((65535 - $blue) / 65.535) when :hsb list = rgbToHsv($red,$green,$blue) scale1.set( list[0] * 1000.0 ) scale2.set( list[1] * 1000.0 ) scale3.set( list[2] * 1000.0 ) else raise(Exception,"unknown colorSpace") end $updating.value = 0 end def tc_loadNamedColor(name) $name.value = name $master = :name if $master == nil if name[0,1] != "#" list = TkWinfo.rgb($root.middle.right.swatch,name) $red = list[0] $green = list[1] $blue = list[2] else case name.length when 4 fmt = /#(.{1})(.{1})(.{1})/ shift = 12 when 7 fmt = /#(.{2})(.{2})(.{2})/ shift = 8 when 10 fmt = /#(.{3})(.{3})(.{3})/ shift = 4 when 13 fmt = /#(.{4})(.{4})(.{4})/ shift = 0 else raise(eException,"syntax error in color name \"#{name}\"") end name.scan(fmt){|strlist| if strlist.length != 3 raise(eException,"syntax error in color name \"#{name}\"") end $red = strlist[0].hex $green = strlist[1].hex $blue = strlist[2].hex } $red = $red << shift $green = $green << shift $blue = $blue << shift end tc_setScales $color = format("#%04x%04x%04x",$red,$green,$blue) $root.middle.right.set_color($color) if $autoUpdate.to_i == 1 doUpdate end Tk.update(true) $master = nil if $master == :name end def changeColorSpace(space) case space when :rgb $label1.value = "Red" $label2.value = "Green" $label3.value = "Blue" when :cmy $label1.value = "Cyan" $label2.value = "Magenta" $label3.value = "Yellow" when :hsb $label1.value = "Hue" $label2.value = "Saturation" $label3.value = "Brightness" end tc_setScales end # menu class TkColorMenuFrame"raised", "borderwidth"=>"2") # File menubutton @file = TkMenubutton.new(self){|button| # File menu @file_menu = TkMenu.new(button){ add "radio", "label" => "RGB color space", "variable" => $colorSpace, "value" => :rgb, "underline" => "0", "command" => proc{changeColorSpace(:rgb)} add "radio", "label" => "CMY color space", "variable" => $colorSpace, "value" => :cmy, "underline" => "0", "command" => proc{changeColorSpace(:cmy)} add "radio", "label" => "HSB color space", "variable" => $colorSpace, "value" => :hsb, "underline" => "0", "command" => proc{changeColorSpace(:hsb)} add "separator" add "radio", "label" => "Automatic updates", "variable" => $autoUpdate, "value" => "1", "underline" => "0" add "radio", "label" => "Manual updates", "variable" => $autoUpdate, "value" => "0", "underline" => "0" add "separator" add "command", "label" => "Exit program", "underline" => "0", "command" => proc{exit} } # assign File menu to File button menu @file_menu text "File" underline "0" }.pack("side"=>"left") self end end # bottom frame class TkColorBotFrame "raised", "borderwidth"=> 2) @commandLabel = TkLabel.new(self, "text"=> "Command:") @command = TkEntry.new(self, "relief"=> "sunken", "borderwidth"=> "2", "textvariable"=> $command, "font"=> "-Adobe-Courier-Medium-R-Normal--*-120-*-*-*-*-*-*") @update = TkButton.new(self, "text"=> "Update", "command"=> proc{doUpdate}) @commandLabel.pack("side"=>"left") @update.pack("side"=>"right","pady"=>".1c","padx"=>".25c") @command.pack("expand"=>"yes","fill"=>"x","ipadx"=>".25c") self end end # left side frame of middle level class TkColorMiddleLeftFrame"vertical", "relief"=>"sunken", "borderwidth"=>"2") @scroll.pack("side"=>"right","fill"=>"y") @names = TkListbox.new(self, "width"=>"20", "height"=>"12", "yscrollcommand"=> proc{|first,last| @scroll.set first,last}, "relief"=>"sunken", "borderwidth"=>"2", "exportselection"=>"false") @scroll.command(proc{|*args| @names.yview(*args)}) @names.bind("Double-1",proc{ tc_loadNamedColor(@names.get(@names.curselection))}) @names.pack("side"=>"left") while (line = f.gets) line.chop! linelist = line.split(/[ \t]+/) if linelist.length == 4 @names.insert("end",linelist[3]) end end f.close break end self end end # middle frame of middle level class TkColorMiddleMiddleFrame"top","expand"=>"yes") end @f4.pack("side"=>"top","expand"=>"yes","fill"=>"x") @label1 = TkLabel.new(self,"textvariable"=>$label1) @scale1 = TkScale.new(self,"from"=>"0","to"=>"1000","length"=>"6c", "orient"=>"horizontal", "command"=>proc{tc_scaleChanged}) @scale1.pack("side"=>"top","anchor"=>"w") @label1.pack("side"=>"top","anchor"=>"w") @label2 = TkLabel.new(self,"textvariable"=>$label2) @scale2 = TkScale.new(self,"from"=>"0","to"=>"1000","length"=>"6c", "orient"=>"horizontal", "command"=>proc{tc_scaleChanged}) @scale2.pack("side"=>"top","anchor"=>"w") @label2.pack("side"=>"top","anchor"=>"w") @label3 = TkLabel.new(self,"textvariable"=>$label3) @scale3 = TkScale.new(self,"from"=>"0","to"=>"1000","length"=>"6c", "orient"=>"horizontal", "command"=>proc{tc_scaleChanged}) @scale3.pack("side"=>"top","anchor"=>"w") @label3.pack("side"=>"top","anchor"=>"w") @nameLabel = TkLabel.new(self,"text"=>"Name:") @name = TkEntry.new(self,"relief"=>"sunken","borderwidth"=>"2", "textvariable"=>$name,"width"=>"10", "font"=>"-Adobe-Courier-Medium-R-Normal--*-120-*-*-*-*-*-*") @nameLabel.pack("side"=>"left") @name.pack("side"=>"right", "expand"=>"1", "fill"=>"x") @name.bind("Return",proc{tc_loadNamedColor $name.to_s}) self end end class TkColorMiddleRightFrame"2c", "height"=>"5c", "background"=>$color) @value = TkLabel.new(self, "text"=>$color, "width"=>"13", "font"=>"-Adobe-Courier-Medium-R-Normal--*-120-*-*-*-*-*-*") @swatch.pack("side"=>"top","expand"=>"yes","fill"=>"both") @value.pack("side"=>"bottom","pady"=>".25c") self end def set_color(color) @swatch["background"] = color @value["text"] = color end end # middle level frame class TkColorMiddleFrame "raised", "borderwidth"=> "2") @left = TkColorMiddleLeftFrame.new(self) @left.pack("side"=>"left","padx"=>".25c","pady"=>".25c") @middle = TkColorMiddleMiddleFrame.new(self) @middle.pack("side"=>"left","expand"=>"yes","fill"=>"y") @right = TkColorMiddleRightFrame.new(self) @right.pack("side"=>"left","padx"=>".25c","pady"=>".25c","anchor"=>"s") self end end class TkColor"top", "fill"=>"x") @bottom = TkColorBotFrame.new(self) @bottom.pack("side"=>"bottom","fill"=>"x") @middle = TkColorMiddleFrame.new(self) @middle.pack("side"=>"top","fill"=>"both") self end end $root = TkColor.new changeColorSpace :rgb # start eventloop Tk.mainloop ================================================ FILE: ext/tk/sample/demos-en/text.rb ================================================ # text.rb # # This demonstration script creates a text widget that describes # the basic editing functions. # # text (basic facilities) widget demo (called by 'widget') # # toplevel widget if defined?($text_demo) && $text_demo $text_demo.destroy $text_demo = nil end # demo toplevel widget $text_demo = TkToplevel.new {|w| title("Text Demonstration - Basic Facilities") iconname("text") positionWindow(w) } base_frame = TkFrame.new($text_demo).pack(:fill=>:both, :expand=>true) # version check if ((Tk::TK_VERSION.split('.').collect{|n| n.to_i} <=> [8,4]) < 0) undo_support = false else undo_support = true end # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $text_demo $text_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'text'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # text TkText.new(base_frame){|t| relief 'sunken' bd 2 setgrid 1 height 30 if undo_support undo true autoseparators true end TkScrollbar.new(base_frame) {|s| pack('side'=>'right', 'fill'=>'y') command proc{|*args| t.yview(*args)} t.yscrollcommand proc{|first,last| s.set first,last} } pack('expand'=>'yes', 'fill'=>'both') # insert('0.0', <:both, :expand=>true) count = [0] ## Define a widget that we peer from; it won't ever actually be shown though first = TkText.new(base_frame, :widgetname=>"text#{count[0] += 1}") first.insert :end,"This is a coupled pair of text widgets; they are peers to " first.insert :end,"each other. They have the same underlying data model, but " first.insert :end,"can show different locations, have different current edit " first.insert :end,"locations, and have different selections. You can also " first.insert :end,"create additional peers of any of these text widgets using " first.insert :end,"the Make Peer button beside the text widget to clone, and " first.insert :end,"delete a particular peer widget using the Delete Peer " first.insert :end,"button." Tk.update_idletasks ## for 'first' widget ## Procedures to make and kill clones; most of this is just so that the demo ## looks nice... def makeClone(count, win, txt) cnt = (count[0] += 1) peer = TkText::Peer.new(txt, win, :widgetname=>"text#{cnt}") sbar = TkScrollbar.new(win, :widgetname=>"sb#{cnt}") peer.yscrollbar sbar b1 = TkButton.new(win, :widgetname=>"clone#{cnt}", :text=>'Make Peer', :command=>proc{makeClone(count, win, peer)}) b2 = TkButton.new(win, :widgetname=>"kill#{cnt}", :text=>'Delete Peer', :command=>proc{killClone(win, cnt)}) row = cnt * 2 TkGrid.configure(peer, sbar, b1, :sticky=>'nsew', :row=>row) TkGrid.configure('^', '^', b2, :sticky=>'nsew', :row=>(row+=1)) TkGrid.configure(b1, b2, :sticky=>'new') TkGrid.rowconfigure(win, b2, :weight=>1) end def killClone(win, cnt) Tk.destroy("#{win.path}.text#{cnt}", "#{win.path}.sb#{cnt}", "#{win.path}.clone#{cnt}", "#{win.path}.kill#{cnt}") end ## Now set up the GUI makeClone(count, base_frame, first) makeClone(count, base_frame, first) first.destroy ## See Code / Dismiss buttons TkFrame.new(base_frame){|f| TkButton.new(f, :text=>'Dismiss', :width=>15, :command=>proc{ $textpeer_demo.destroy $textpeer_demo = nil }).pack(:side=>:left, :expand=>true) TkButton.new(f, :text=>'See Code', :width=>15, :command=>proc{ showCode 'textpeer' }).pack(:side=>:left, :expand=>true) TkGrid.configure(f, '-', '-', :sticky=>'ew', :row=>5000) } TkGrid.columnconfigure(base_frame, 0, :weight=>1) ================================================ FILE: ext/tk/sample/demos-en/timer ================================================ #!/usr/bin/env ruby # # timer -- # This script generates a counter with start,stop and reset buttons. # # Copyright (C) 1998 Takaaki Tateishi (ttate@jaist.ac.jp) # last update: Sat Jun 27 12:24:14 JST 1998 # require "tk" require "thread" require "tkafter" $time = "0.00" $m = Mutex.new $loop = false def timer_stop $loop = false $m.lock end def timer_start $loop = true $m.unlock end def timer_reset $time = "0.00" $root.countframe.counter['text'] = $time end def timer_loop if $loop $time = $time.succ $root.countframe.counter['text'] = $time end Tk.after(10,proc{timer_loop}) end # # thread version # def timer_loop2 while true $m.lock $time = $time.succ $root.countframe.counter['text'] = $time sleep(0.01) $m.unlock end end # # TkAfter # def timer_loop3 if $loop $time = $time.succ $root.countframe.counter['text'] = $time end end class CountFrame < TkFrame attr_reader :counter def initialize(parent=nil,keys=nil) super(parent,keys) @counter = TkLabel.new(self, 'text'=>$time, 'relief'=>'raised') @counter.pack('fill'=>'both') self end end class ButtonFrame < TkFrame def initialize(parent=nil,keys=nil) super(parent,keys) =begin @stop = TkButton.new(self, 'text'=>'Stop', 'command'=>proc{timer_stop}) @start = TkButton.new(self, 'text'=>'Start', 'command'=>proc{timer_start}) =end @stop = TkButton.new(self, :text=>'Stop', :state=>:disabled) @start = TkButton.new(self, :text=>'Start', :state=>:normal) @stop.command proc{ timer_stop @start.state(:normal) @stop.state(:disabled) } @start.command proc{ timer_start @stop.state(:normal) @start.state(:disabled) } @reset = TkButton.new(self, 'text'=>'Reset', 'command'=>proc{timer_reset}) for b in [@stop,@start,@reset] b.pack('side'=>'left', 'fill'=>'both', 'expand'=>'yes') end end end class Timer < TkRoot attr_reader :countframe def initialize(*args) super(*args) @countframe = CountFrame.new(self) @buttonframe = ButtonFrame.new(self) for f in [@buttonframe,@countframe] f.pack('side'=>'top', 'fill'=>'both') end self end end $root = Timer.new #$thread = Thread.start{timer_loop2} #timer_loop TkAfter.new(10,-1,proc{timer_loop3}).start Tk.mainloop ================================================ FILE: ext/tk/sample/demos-en/tkencoding.rb ================================================ # -*- ruby -*- # # tkencoding.rb # written by ttate@jaist.ac.jp class TclTkIp alias __eval _eval alias __invoke _invoke private :__eval private :__invoke attr_accessor :encoding def _eval(cmd) if( @encoding ) _fromUTF8(__eval(_toUTF8(cmd,@encoding)),@encoding) else __eval(cmd) end end def _invoke(*cmds) if( @encoding ) cmds = cmds.collect{|cmd| _toUTF8(cmd,@encoding)} _fromUTF8(__invoke(*cmds),@encoding) else __invoke(*cmds) end end end module Tk INTERP = TkCore::INTERP def encoding=(name) INTERP.encoding = name end def encoding INTERP.encoding end end ================================================ FILE: ext/tk/sample/demos-en/toolbar.rb ================================================ # toolbar.rb -- # # This demonstration script creates a toolbar that can be torn off. # # based on "Id: toolbar.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp" if defined?($toolbar_demo) && $toolbar_demo $toolbar_demo.destroy $toolbar_demo = nil end $toolbar_demo = TkToplevel.new {|w| title("Ttk Menu Buttons") iconname("toolbar") positionWindow(w) } base_frame = Ttk::Frame.new($toolbar_demo).pack(:fill=>:both, :expand=>true) if Tk.windowingsystem != 'aqua' msg = Ttk::Label.new(base_frame, :wraplength=>'4i', :text=>Tk::UTF8_String.new(<'4i', :text=>Tk::UTF8_String.new(<'toolbar') # for window title sep = Ttk::Separator.new(base_frame) to_base = Ttk::Frame.new(tbar_base, :cursor=>'fleur') if Tk.windowingsystem != 'aqua' to = Ttk::Separator.new(to_base, :orient=>:vertical) to2 = Ttk::Separator.new(to_base, :orient=>:vertical) to.pack(:fill=>:y, :expand=>true, :padx=>2, :side=>:left) to2.pack(:fill=>:y, :expand=>true, :side=>:left) end contents = Ttk::Frame.new(tbar_base) Tk.grid(to_base, contents, :sticky=>'nsew') tbar_base.grid_columnconfigure(contents, :weight=>1) contents.grid_columnconfigure(1000, :weight=>1) if Tk.windowingsystem != 'aqua' ## Bindings so that the toolbar can be torn off and reattached to_base.bind('B1-Motion', '%X %Y'){|x, y| tbar_base.tearoff(to_base, x, y)} to. bind('B1-Motion', '%X %Y'){|x, y| tbar_base.tearoff(to_base, x, y)} to2. bind('B1-Motion', '%X %Y'){|x, y| tbar_base.tearoff(to_base, x, y)} def tbar_base.tearoff(w, x, y) on_win = TkWinfo.containing(x, y) return unless (on_win && on_win.path =~ /^#{@path}(\.|$)/) self.grid_remove w.grid_remove self.wm_manage # self.wm_title('Toolbar') # if you don't want to use its widget name as a window title. self.wm_protocol('WM_DELETE_WINDOW'){ self.untearoff(self) } end def tbar_base.untearoff(w) self.wm_forget w.grid self.grid end end ## Some content for the rest of the toplevel text = TkText.new(base_frame, :width=>40, :height=>10) ## Toolbar contents tb_btn = Ttk::Button.new(tbar_base, :text=>'Button', :style=>'Toolbutton', :command=>proc{text.insert(:end, "Button Pressed\n")}) tb_chk = Ttk::Checkbutton.new(tbar_base, :text=>'Check', :style=>'Toolbutton', :variable=>(check = TkVariable.new), :command=>proc{ text.insert(:end, "Check is #{check.value}\n") }) tb_mbtn = Ttk::Menubutton.new(tbar_base, :text=>'Menu') tb_combo = Ttk::Combobox.new(tbar_base, :value=>TkFont.families, :state=>:readonly) tb_mbtn.menu(menu = Tk::Menu.new(tb_mbtn)) menu.add(:command, :label=>'Just', :command=>proc{text.insert(:end, "Just\n")}) menu.add(:command, :label=>'An', :command=>proc{text.insert(:end, "An\n")}) menu.add(:command, :label=>'Example', :command=>proc{text.insert(:end, "Example\n")}) tb_combo.bind(''){ text.font.family = tb_combo.get } ## Arrange contents Tk.grid(tb_btn, tb_chk, tb_mbtn, tb_combo, :in=>contents, :padx=>2, :sticky=>'ns') Tk.grid(tbar_base, :sticky=>'ew') Tk.grid(sep, :sticky=>'ew') Tk.grid(msg, :sticky=>'ew') Tk.grid(text, :sticky=>'nsew') base_frame.grid_rowconfigure(text, :weight=>1) base_frame.grid_columnconfigure(text, :weight=>1) ## See Code / Dismiss buttons Ttk::Frame.new(base_frame) {|frame| sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'See Code', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'toolbar'}), Ttk::Button.new(frame, :text=>'Dismiss', :image=>$image['delete'], :compound=>:left, :command=>proc{ $toolbar_demo.destroy $toolbar_demo = nil }), :padx=>4, :pady=>4) grid_columnconfigure(0, :weight=>1) Tk.grid(frame, :sticky=>'ew') } ================================================ FILE: ext/tk/sample/demos-en/tree.rb ================================================ # tree.rb -- # # This demonstration script creates a toplevel window containing a Ttk # tree widget. # # based on "Id: tree.tcl,v 1.4 2007/12/13 15:27:07 dgp Exp" if defined?($tree_demo) && $tree_demo $tree_demo.destroy $tree_demo = nil end $tree_demo = TkToplevel.new {|w| title("Directory Browser") iconname("tree") positionWindow(w) } base_frame = TkFrame.new($tree_demo).pack(:fill=>:both, :expand=>true) ## Explanatory text Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left, :anchor=>'n', :padding=>[10, 2, 10, 6], :text=><:x) Ttk is the new Tk themed widget set. \ One of the widgets it includes is a tree widget, \ which allows the user to browse a hierarchical data-set such as a filesystem. \ The tree widget not only allows for the tree part itself, \ but it also supports an arbitrary number of additional columns \ which can show additional data (in this case, the size of the files \ found in your filesystem). \ You can also change the width of the columns \ by dragging the boundary between them. EOL ## See Code / Dismiss Ttk::Frame.new(base_frame) {|frame| sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'See Code', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'tree'}), Ttk::Button.new(frame, :text=>'Dismiss', :image=>$image['delete'], :compound=>:left, :command=>proc{ $tree_demo.destroy $tree_demo = nil }), :padx=>4, :pady=>4) grid_columnconfigure(0, :weight=>1) pack(:side=>:bottom, :fill=>:x) } ## Code to populate the roots of the tree (can be more than one on Windows) def populate_roots(tree) TkComm.simplelist(Tk.tk_call('file', 'volumes')).sort.each{|dir| populate_tree(tree, tree.insert(nil, :end, :text=>dir, :values=>[dir, 'directory'])) } end ## Code to populate a node of the tree def populate_tree(tree, node) return if tree.get(node, :type) != 'directory' path = tree.get(node, :fullpath) tree.delete(tree.children(node)) Dir.glob("#{path}/*").sort.each{|f| type = File.ftype(f) id = tree.insert(node, :end, :text=>File.basename(f), :values=>[f, type]).id if type == 'directory' ## Make it so that this node is openable tree.insert(id, 0, :text=>'dummy') tree.itemconfigure(id, :text=>File.basename(f)) elsif type == 'file' size = File.size(f) if size >= 1024*1024*1024 size = '%.1f GB' % (size.to_f/1024/1024/1024) elsif size >= 1024*1024 size = '%.1f MB' % (size.to_f/1024/1024) elsif size >= 1024 size = '%.1f KB' % (size.to_f/1024) else size = '%.1f bytes' % (size.to_f/1024) end tree.set(id, :size, size) end } # Stop this code from rerunning on the current node tree.set(node, :type, 'processed_directory') end ## Create the tree and set it up tree = Ttk::Treeview.new(base_frame, :columns=>%w(fullpath type size), :displaycolumns=>['size']) if Tk.windowingsystem != 'aqua' vsb = tree.yscrollbar(Ttk::Scrollbar.new(base_frame)) hsb = tree.xscrollbar(Ttk::Scrollbar.new(base_frame)) else vsb = tree.yscrollbar(Tk::Scrollbar.new(base_frame)) hsb = tree.xscrollbar(Tk::Scrollbar.new(base_frame)) end tree.heading_configure('#0', :text=>'Directory Structure') tree.heading_configure('size', :text=>'File Size') tree.column_configure('size', :stretch=>0, :width=>70) populate_roots(tree) tree.bind('', '%W'){|w| populate_tree(w, w.focus_item)} ## Arrange the tree and its scrollbars in the toplevel container = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true) container.lower Tk.grid(tree, vsb, :in=>container, :sticky=>'nsew') Tk.grid(hsb, :in=>container, :sticky=>'nsew') container.grid_columnconfigure(0, :weight=>1) container.grid_rowconfigure(0, :weight=>1) ================================================ FILE: ext/tk/sample/demos-en/ttkbut.rb ================================================ # ttkbut.rb # # This demonstration script creates a toplevel window containing several # simple Ttk widgets, such as labels, labelframes, buttons, checkbuttons and # radiobuttons. # # based on "Id: ttkbut.tcl,v 1.4 2007/12/13 15:27:07 dgp Exp" if defined?($ttkbut_demo) && $ttkbut_demo $ttkbut_demo.destroy $ttkbut_demo = nil end $ttkbut_demo = TkToplevel.new {|w| title("Simple Ttk Widgets") iconname("ttkbut") positionWindow(w) } base_frame = TkFrame.new($ttkbut_demo).pack(:fill=>:both, :expand=>true) Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left, :text=><:top, :fill=>:x) Ttk is the new Tk themed widget set. This is a Ttk themed label, \ and below are three groups of Ttk widgets in Ttk labelframes. \ The first group are all buttons that set the current application theme \ when pressed. The second group contains three sets of checkbuttons, \ with a separator widget between the sets. Note that the "Enabled" \ button controls whether all the other themed widgets in this toplevel are \ in the disabled state. The third group has a collection of linked \ radiobuttons. EOL ## Add buttons for setting the theme buttons = Ttk::Labelframe.new(base_frame, :text=>'Buttons') # Ttk::Style.theme_names.each{|theme| # Ttk::Button.new(buttons, :text=>theme, # :command=>proc{Ttk::Style.theme_use theme}).pack(:pady=>2) # } Ttk.themes.each{|theme| Ttk::Button.new(buttons, :text=>theme, :command=>proc{Ttk.set_theme theme}).pack(:pady=>2) } ## Helper procedure for the top checkbutton def setState(root, value, *excepts) return if excepts.member?(root) ## Non-Ttk widgets (e.g. the toplevel) will fail, so make it silent begin root.state = value rescue end ## Recursively invoke on all children of this root that are in the same ## toplevel widget root.winfo_children.each{|w| setState(w, value, *excepts) if w.winfo_toplevel == root.winfo_toplevel } end ## Set up the checkbutton group checks = Ttk::Labelframe.new(base_frame, :text=>'Checkbuttons') enabled = TkVariable.new(true) e = Ttk::Checkbutton.new(checks, :text=>'Enabled', :variable=>enabled, :command=>proc{ setState($ttkbut_demo, ((enabled.bool)? "!disabled" : "disabled"), e) }) ## See ttk_widget(n) for other possible state flags sep1 = Ttk::Separator.new(checks) sep2 = Ttk::Separator.new(checks) cheese = TkVariable.new tomato = TkVariable.new basil = TkVariable.new oregano = TkVariable.new c1 = Ttk::Checkbutton.new(checks, :text=>'Cheese', :variable=>cheese) c2 = Ttk::Checkbutton.new(checks, :text=>'Tomato', :variable=>tomato) c3 = Ttk::Checkbutton.new(checks, :text=>'Basil', :variable=>basil) c4 = Ttk::Checkbutton.new(checks, :text=>'Oregano', :variable=>oregano) Tk.pack(e, sep1, c1, c2, sep2, c3, c4, :fill=>:x, :pady=>2) ## Set up the radiobutton group radios = Ttk::Labelframe.new(base_frame, :text=>'Radiobuttons') happyness = TkVariable.new r1 = Ttk::Radiobutton.new(radios, :variable=>happyness, :text=>'Great', :value=>'great') r2 = Ttk::Radiobutton.new(radios, :variable=>happyness, :text=>'Good', :value=>'good') r3 = Ttk::Radiobutton.new(radios, :variable=>happyness, :text=>'Ok', :value=>'ok') r4 = Ttk::Radiobutton.new(radios, :variable=>happyness, :text=>'Poor', :value=>'poor') r5 = Ttk::Radiobutton.new(radios, :variable=>happyness, :text=>'Awful', :value=>'awful') Tk.pack(r1, r2, r3, r4, r5, :fill=>:x, :padx=>3, :pady=>2) ## See Code / Dismiss Ttk::Frame.new(base_frame) {|frame| sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'See Variables', :image=>$image['view'], :compound=>:left, :command=>proc{ showVars(base_frame, ['enabled', enabled], ['cheese', cheese], ['tomato', tomato], ['basil', basil], ['oregano', oregano], ['happyness', happyness]) }), Ttk::Button.new(frame, :text=>'See Code', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'ttkbut'}), Ttk::Button.new(frame, :text=>'Dismiss', :image=>$image['delete'], :compound=>:left, :command=>proc{ tmppath = $ttkbut_demo $ttkbut_demo = nil $showVarsWin[tmppath.path] = nil tmppath.destroy }), :padx=>4, :pady=>4) grid_columnconfigure(0, :weight=>1) pack(:side=>:bottom, :fill=>:x, :expand=>true) } ## Arrange things neatly f = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true) f.lower Tk.grid(buttons, checks, radios, :in=>f, :sticky=>'nwe', :pady=>2, :padx=>3) f.grid_columnconfigure([0, 1, 2], :weight=>1, :uniform=>:yes) ================================================ FILE: ext/tk/sample/demos-en/ttkmenu.rb ================================================ # ttkmenu.rb -- # # This demonstration script creates a toplevel window containing several Ttk # menubutton widgets. # # based on "Id: ttkmenu.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp" if defined?($ttkmenu_demo) && $ttkmenu_demo $ttkmenu_demo.destroy $ttkmenu_demo = nil end $ttkmenu_demo = TkToplevel.new {|w| title("Ttk Menu Buttons") iconname("ttkmenu") positionWindow(w) } base_frame = Ttk::Frame.new($ttkmenu_demo).pack(:fill=>:both, :expand=>true) Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left, :text=><:top, :fill=>:x) Ttk is the new Tk themed widget set, \ and one widget that is available in themed form is the menubutton. \ Below are some themed menu buttons \ that allow you to pick the current theme in use. \ Notice how picking a theme changes the way \ that the menu buttons themselves look, \ and that the central menu button is styled differently \ (in a way that is normally suitable for toolbars). \ However, there are no themed menus; the standard Tk menus were judged \ to have a sufficiently good look-and-feel on all platforms, \ especially as they are implemented as native controls in many places. EOL Ttk::Separator.new(base_frame).pack(:side=>:top, :fill=>:x) ## See Code / Dismiss Ttk::Frame.new($ttkmenu_demo) {|frame| sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'See Code', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'ttkmenu'}), Ttk::Button.new(frame, :text=>'Dismiss', :image=>$image['delete'], :compound=>:left, :command=>proc{ $ttkmenu_demo.destroy $ttkmenu_demo = nil }), :padx=>4, :pady=>4) grid_columnconfigure(0, :weight=>1) pack(:side=>:bottom, :fill=>:x) } b1 = Ttk::Menubutton.new(base_frame,:text=>'Select a theme',:direction=>:above) b2 = Ttk::Menubutton.new(base_frame,:text=>'Select a theme',:direction=>:left) b3 = Ttk::Menubutton.new(base_frame,:text=>'Select a theme',:direction=>:right) b4 = Ttk::Menubutton.new(base_frame,:text=>'Select a theme',:direction=>:flush, :style=>Ttk::Menubutton.style('Toolbutton')) b5 = Ttk::Menubutton.new(base_frame,:text=>'Select a theme',:direction=>:below) b1.menu(m1 = Tk::Menu.new(b1, :tearoff=>false)) b2.menu(m2 = Tk::Menu.new(b2, :tearoff=>false)) b3.menu(m3 = Tk::Menu.new(b3, :tearoff=>false)) b4.menu(m4 = Tk::Menu.new(b4, :tearoff=>false)) b5.menu(m5 = Tk::Menu.new(b5, :tearoff=>false)) Ttk.themes.each{|theme| m1.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme}) m2.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme}) m3.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme}) m4.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme}) m5.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme}) } f = Ttk::Frame.new(base_frame).pack(:fill=>:x) f1 = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true) f.lower f.grid_anchor(:center) TkGrid('x', b1, 'x', :in=>f, :padx=>3, :pady=>2) TkGrid(b2, b4, b3, :in=>f, :padx=>3, :pady=>2) TkGrid('x', b5, 'x', :in=>f, :padx=>3, :pady=>2) ================================================ FILE: ext/tk/sample/demos-en/ttknote.rb ================================================ # ttknote.rb -- # # This demonstration script creates a toplevel window containing a Ttk # notebook widget. # # based on "Id: ttknote.tcl,v 1.5 2007/12/13 15:27:07 dgp Exp" if defined?($ttknote_demo) && $ttknote_demo $ttknote_demo.destroy $ttknote_demo = nil end $ttknote_demo = TkToplevel.new {|w| title("Ttk Notebook Widget") iconname("ttknote") positionWindow(w) } ## See Code / Dismiss Ttk::Frame.new($ttknote_demo) {|frame| sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'See Code', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'ttknote'}), Ttk::Button.new(frame, :text=>'Dismiss', :image=>$image['delete'], :compound=>:left, :command=>proc{ $ttknote_demo.destroy $ttknote_demo = nil }), :padx=>4, :pady=>4) grid_columnconfigure(0, :weight=>1) pack(:side=>:bottom, :fill=>:x) } base_frame = Ttk::Frame.new($ttknote_demo).pack(:fill=>:both, :expand=>true) ## Make the notebook and set up Ctrl+Tab traversal notebook = Ttk::Notebook.new(base_frame).pack(:fill=>:both, :expand=>true, :padx=>2, :pady=>3) notebook.enable_traversal ## Popuplate the first pane f_msg = Ttk::Frame.new(notebook) msg_m = Ttk::Label.new(f_msg, :font=>$font, :wraplength=>'4i', :justify=>:left, :anchor=>'n', :text=><'Neat!', :underline=>0, :command=>proc{ neat.value = 'Yeah, I know...' Tk.after_cancel(after_id) if after_id after_id = Tk.after(500){neat.value = ''} }) msg_b.winfo_toplevel.bind('Alt-n'){ msg_b.focus; msg_b.invoke } msg_l = Ttk::Label.new(f_msg, :textvariable=>neat) notebook.add(f_msg, :text=>'Description', :underline=>0, :padding=>2) Tk.grid(msg_m, '-', :sticky=>'new', :pady=>2) Tk.grid(msg_b, msg_l, :pady=>[2, 4]) f_msg.grid_rowconfigure(1, :weight=>1) f_msg.grid_columnconfigure([0, 1], :weight=>1, :uniform=>1) ## Populate the second pane. Note that the content doesn't really matter f_disabled = Ttk::Frame.new(notebook) notebook.add(f_disabled, :text=>'Disabled', :state=>:disabled) ## Popuplate the third pane f_editor = Ttk::Frame.new(notebook) notebook.add(f_editor, :text=>'Text Editor', :underline=>0) editor_t = Tk::Text.new(f_editor, :width=>40, :height=>10, :wrap=>:char) if Tk.windowingsystem != 'aqua' editor_s = editor_t.yscrollbar(Ttk::Scrollbar.new(f_editor)) else editor_s = editor_t.yscrollbar(Tk::Scrollbar.new(f_editor)) end editor_s.pack(:side=>:right, :fill=>:y, :padx=>[0,2], :pady=>2) editor_t.pack(:fill=>:both, :expand=>true, :padx=>[2,0], :pady=>2) ================================================ FILE: ext/tk/sample/demos-en/ttkpane.rb ================================================ # ttkpane.rb -- # # This demonstration script creates a Ttk pane with some content. # # based on "Id: ttkpane.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp" if defined?($ttkpane_demo) && $ttkpane_demo $ttkpane_demo.destroy $ttkpane_demo = nil end $ttkpane_demo = TkToplevel.new {|w| title("Themed Nested Panes") iconname("ttkpane") positionWindow(w) } base_frame = TkFrame.new($ttkpane_demo).pack(:fill=>:both, :expand=>true) Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left, :text=><:top, :fill=>:x) This demonstration shows off a nested set of themed paned windows. \ Their sizes can be changed by grabbing the area \ between each contained pane and dragging the divider. EOL Ttk::Separator.new(base_frame).pack(:side=>:top, :fill=>:x) ## See Code / Dismiss Ttk::Frame.new(base_frame) {|frame| sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'See Code', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'ttkpane'}), Ttk::Button.new(frame, :text=>'Dismiss', :image=>$image['delete'], :compound=>:left, :command=>proc{ $ttkpane_demo.destroy $ttkpane_demo = nil }), :padx=>4, :pady=>4) grid_columnconfigure(0, :weight=>1) pack(:side=>:bottom, :fill=>:x) } frame = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true) outer = Ttk::Panedwindow.new(frame, :orient=>:horizontal) outer.add(in_left = Ttk::Panedwindow.new(outer, :orient=>:vertical)) outer.add(in_right = Ttk::Panedwindow.new(outer, :orient=>:vertical)) in_left.add(left_top = Ttk::Labelframe.new(in_left, :text=>'Button')) in_left.add(left_bot = Ttk::Labelframe.new(in_left, :text=>'Clocks')) in_right.add(right_top = Ttk::Labelframe.new(in_right, :text=>'Progress')) in_right.add(right_bot = Ttk::Labelframe.new(in_right, :text=>'Text')) if Tk.windowingsystem == 'aqua' [left_top, left_bot, right_top, right_bot].each{|w| w.padding(3) } end # Fill the button pane Ttk::Button.new(left_top, :text=>'Press Me', :command=>proc{ Tk.messageBox(:type=>'ok', :icon=>'info', :message=>'Ouch!', :detail=>'That hurt...', :parent=>base_frame, :title=>'Button Pressed') }).pack(:padx=>2, :pady=>5) zones_list = [ [':Europe/Berlin'], [':America/Argentina/Buenos_Aires', ':America/Buenos_Aires'], [':Africa/Johannesburg'], [':Europe/London'], [':America/Los_Angeles'], [':Europe/Moscow'], [':America/New_York'], [':Asia/Singapore'], [':Australia/Sydney'], [':Asia/Tokyo'], ] zones = [] # Check tzinfo support if $tk_major_ver > 8 || ($tk_major_ver == 8 && $tk_minor_ver >= 5) tzinfo = :tcl # Force a pre-load of all the timezones needed; otherwise can end up # poor-looking synch problems! zones_list.each{|list| list.each{|zone| begin Tk.tk_call('clock', 'format', '0', '-timezone', zone) rescue RuntimeError # ignore else zones << [zone, zone[%r<[^/:]+$>].tr('_', ' ')] break end } } else begin require 'tzinfo' tzinfo = :tzinfo rescue Exception begin require 'tzfile' tzinfo = :tzfile rescue Exception tzinfo = nil end end case tzinfo when :tzinfo zones_list.each{|list| list.each{|zone| begin tz = TZInfo::Timezone.get(zone[%r<[^:]+$>]) rescue Exception # ignore else zones << [tz, zone[%r<[^/:]+$>].tr('_', ' ')] break end } } when :tzfile zones_list.each{|list| list.each{|zone| begin tz = TZFile.create(zone[%r<[^:]+$>]) rescue Exception # ignore else zones << [tz, zone[%r<[^/:]+$>].tr('_', ' ')] break end } } else [ -7, -4, -2, -1, 0, +1, +3, +8, +9, +10 ].each{|zone| zones << [zone, 'UTC%+03d00' % zone] } end end time = TkVariable.new_hash case tzinfo when :tcl update_proc = proc{|now, tz, label| time[label] = Tk.tk_call('clock', 'format', now.tv_sec, '-timezone', tz, '-format', '%T') } when :tzinfo update_proc = proc{|now, tz, label| time[label] = tz.utc_to_local(now).strftime('%H:%M:%S') } when :tzfile update_proc = proc{|now, tz, label| time[label] = tz.at(now.tv_sec).strftime('%H:%M:%S') } else update_proc = proc{|now, tz, label| time[label] = (now + (tz * 3600)).strftime('%H:%M:%S') } end # Fill the clocks pane zones.each_with_index{|(zone, label), idx| Ttk::Separator.new(left_bot).pack(:fill=>:x) if idx > 0 Ttk::Label.new(left_bot, :text=>label, :anchor=>'w').pack(:fill=>:x) Ttk::Label.new(left_bot, :textvariable=>time.ref(label), :anchor=>'w').pack(:fill=>:x) } # Timer start every = proc{ now = Time.now.utc zones.each{|zone, label| update_proc.call(now, zone, label) } } TkRTTimer.new(1000, -1, every).start(0, every) # Fill the progress pane Ttk::Progressbar.new(right_top, :mode=>:indeterminate).pack(:fill=>:both, :expand=>true).start # Fill the text pane if Tk.windowingsystem != 'aqua' # The trick with the ttk::frame makes the text widget look like it fits with # the current Ttk theme despite not being a themed widget itself. It is done # by styling the frame like an entry, turning off the border in the text # widget, and putting the text widget in the frame with enough space to allow # the surrounding border to show through (2 pixels seems to be enough). f = Ttk::Frame.new(right_bot, :style=>Ttk::Entry) txt = TkText.new(frame, :wrap=>:word, :width=>30, :borderwidth=>0) txt.pack(:fill=>:both, :expand=>true, :in=>f, :pady=>2, :padx=>2) scr = txt.yscrollbar(Ttk::Scrollbar.new(frame)) scr.pack(:side=>:right, :fill=>:y, :in=>right_bot) f.pack(:fill=>:both, :expand=>true) outer.pack(:fill=>:both, :expand=>true) else txt = TkText.new(frame, :wrap=>:word, :width=>30, :borderwidth=>0) scr = txt.yscrollbar(TkScrollbar.new(frame)) scr.pack(:side=>:right, :fill=>:y, :in=>right_bot) txt.pack(:fill=>:both, :expand=>true, :in=>right_bot) outer.pack(:fill=>:both, :expand=>true, :padx=>10, :pady=>[6, 10]) end ================================================ FILE: ext/tk/sample/demos-en/ttkprogress.rb ================================================ # ttkprogress.rb -- # # This demonstration script creates several progress bar widgets. # # based on "Id: ttkprogress.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp" if defined?($ttkprogress_demo) && $ttkprogress_demo $ttkprogress_demo.destroy $ttkprogress_demo = nil end $ttkprogress_demo = TkToplevel.new {|w| title("Progress Bar Demonstration") iconname("ttkprogress") positionWindow(w) } base_frame = TkFrame.new($ttkprogress_demo).pack(:fill=>:both, :expand=>true) Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left, :text=>Tk::UTF8_String.new(<:top, :fill=>:x) Below are two progress bars. \ The top one is a \\u201Cdeterminate\\u201D progress bar, \ which is used for showing how far through a defined task the program has got. \ The bottom one is an \\u201Cindeterminate\\u201D progress bar, \ which is used to show that the program is busy \ but does not know how long for. Both are run here in self-animated mode, \ which can be turned on and off using the buttons underneath. EOL ## See Code / Dismiss buttons Ttk::Frame.new(base_frame) {|frame| sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'See Code', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'ttkprogress'}), Ttk::Button.new(frame, :text=>'Dismiss', :image=>$image['delete'], :compound=>:left, :command=>proc{ $ttkprogress_demo.destroy $ttkprogress_demo = nil }), :padx=>4, :pady=>4) grid_columnconfigure(0, :weight=>1) pack(:side=>:bottom, :fill=>:x) } frame = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true) p1 = Ttk::Progressbar.new(frame, :mode=>:determinate) p2 = Ttk::Progressbar.new(frame, :mode=>:indeterminate) start = Ttk::Button.new(frame, :text=>'Start Progress', :command=>proc{ p1.start; p2.start }) stop = Ttk::Button.new(frame, :text=>'Stop Progress', :command=>proc{ p1.stop; p2.stop }) Tk.grid(p1, '-', :pady=>5, :padx=>10) Tk.grid(p2, '-', :pady=>5, :padx=>10) Tk.grid(start, stop, :padx=>10, :pady=>5) start.grid_configure(:sticky=>'e') stop.grid_configure(:sticky=>'w') frame.grid_columnconfigure(:all, :weight=>1) ================================================ FILE: ext/tk/sample/demos-en/twind.rb ================================================ # twind.rb # # This demonstration script creates a text widget with a bunch of # embedded windows. # # text (embedded windows) widget demo (called by 'widget') # # toplevel widget if defined?($twind_demo) && $twind_demo $twind_demo.destroy $twind_demo = nil end # demo toplevel widget $twind_demo = TkToplevel.new {|w| title("Text Demonstration - Embedded Windows") iconname("Embedded Windows") positionWindow(w) } base_frame = TkFrame.new($twind_demo).pack(:fill=>:both, :expand=>true) # frame $twind_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc{ tmppath = $twind_demo $twind_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc{showCode 'twind'} }.pack('side'=>'left', 'expand'=>'yes') } $twind_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame $twind_text = nil TkFrame.new(base_frame, 'highlightthickness'=>2, 'borderwidth'=>2, 'relief'=>'sunken') {|f| $twind_text = TkText.new(f, 'setgrid'=>'true', 'font'=>$font, 'width'=>'70', 'height'=>35, 'wrap'=>'word', 'highlightthickness'=>0, 'borderwidth'=>0 ){|t| TkScrollbar.new(f) {|s| command proc{|*args| t.yview(*args)} t.yscrollcommand proc{|first,last| s.set first,last} }.pack('side'=>'right', 'fill'=>'y') }.pack('expand'=>'yes', 'fill'=>'both') }.pack('expand'=>'yes', 'fill'=>'both') # $tag_center = TkTextTag.new($twind_text, 'justify' =>'center', 'spacing1'=>'5m', 'spacing3'=>'5m' ) $tag_buttons = TkTextTag.new($twind_text, 'lmargin1'=>'1c', 'lmargin2'=>'1c', 'rmargin' =>'1c', 'spacing1'=>'3m', 'spacing2'=>0, 'spacing3'=>0 ) $twind_text.insert('end', "A text widget can contain other widgets embedded ") $twind_text.insert('end', "it. These are called \"embedded windows\", ") $twind_text.insert('end', "and they can consist of arbitrary widgets. ") $twind_text.insert('end', "For example, here are two embedded button ") $twind_text.insert('end', "widgets. You can click on the first button to ") TkTextWindow.new($twind_text, 'end', 'window'=>TkButton.new($twind_text) { #text 'ON' text 'Turn On' command proc{textWindOn $twind_text,$twind_buttons} cursor 'top_left_arrow' }) $twind_text.insert('end', " horizontal scrolling, which also turns off ") $twind_text.insert('end', "word wrapping. Or, you can click on the second ") $twind_text.insert('end', "button to\n") TkTextWindow.new($twind_text, 'end', 'window'=>TkButton.new($twind_text) { #text 'OFF' text 'Turn Off' command proc{textWindOff $twind_text} cursor 'top_left_arrow' }) $twind_text.insert('end', " horizontal scrolling and turn back on word wrapping.\n\n") $twind_text.insert('end', "Or, here is another example. If you ") TkTextWindow.new($twind_text, 'end', 'window'=>TkButton.new($twind_text) { text 'Click Here' command proc{textWindPlot $twind_text} cursor 'top_left_arrow' }) $twind_text.insert('end', " a canvas displaying an x-y plot will appear right here.") $mark_plot = TkTextMark.new($twind_text, 'insert') $mark_plot.gravity='left' $twind_text.insert('end', " You can drag the data points around with the mouse, ") $twind_text.insert('end', "or you can click here to ") TkTextWindow.new($twind_text, 'end', 'window'=>TkButton.new($twind_text) { text 'Delete' command proc{textWindDel $twind_text} cursor 'top_left_arrow' }) $twind_text.insert('end', " the plot again.\n\n") $twind_text.insert('end', "You may also find it useful to put embedded windows in ") $twind_text.insert('end', "a text without any actual text. In this case the ") $twind_text.insert('end', "text widget acts like a geometry manager. For ") $twind_text.insert('end', "example, here is a collection of buttons laid out ") $twind_text.insert('end', "neatly into rows by the text widget. These buttons ") $twind_text.insert('end', "can be used to change the background color of the ") $twind_text.insert('end', "text widget (\"Default\" restores the color to ") $twind_text.insert('end', "its default). If you click on the button labeled ") $twind_text.insert('end', "\"Short\", it changes to a longer string so that ") $twind_text.insert('end', "you can see how the text widget automatically ") $twind_text.insert('end', "changes the layout. Click on the button again ") $twind_text.insert('end', "to restore the short string.\n") TkTextWindow.new($twind_text, 'end', 'window'=>TkButton.new($twind_text) {|b| text 'Default' command proc{embDefBg $twind_text} cursor 'top_left_arrow' $tag_buttons.add('end') }, 'padx'=>3 ) embToggle = TkVariable.new('Short') TkTextWindow.new($twind_text, 'end', 'window'=>TkCheckButton.new($twind_text) { textvariable embToggle indicatoron 0 variable embToggle onvalue 'A much longer string' offvalue 'Short' cursor 'top_left_arrow' pady 5 padx 2 }, 'padx'=>3, 'pady'=>2 ) [ 'AntiqueWhite3', 'Bisque1', 'Bisque2', 'Bisque3', 'Bisque4', 'SlateBlue3', 'RoyalBlue1', 'SteelBlue2', 'DeepSkyBlue3', 'LightBlue1', 'DarkSlateGray1', 'Aquamarine2', 'DarkSeaGreen2', 'SeaGreen1', 'Yellow1', 'IndianRed1', 'IndianRed2', 'Tan1', 'Tan4' ].each{|twind_color| TkTextWindow.new($twind_text, 'end', 'window'=>TkButton.new($twind_text) { text twind_color cursor 'top_left_arrow' command proc{$twind_text.bg twind_color} }, 'padx'=>3, 'pady'=>2 ) } # def textWindOn (w,f) if defined? $twind_scroll begin $twind_scroll.destroy rescue end $twind_scroll = nil end base = TkWinfo.parent( TkWinfo.parent(w) ) $twind_scroll = TkScrollbar.new(base) {|s| orient 'horizontal' command proc{|*args| w.xview(*args)} w.xscrollcommand proc{|first,last| s.set first,last} w.wrap 'none' pack('after'=>f, 'side'=>'bottom', 'fill'=>'x') } return nil end def textWindOff (w) if defined? $twind_scroll begin $twind_scroll.destroy rescue end $twind_scroll = nil end w.xscrollcommand '' w.wrap 'word' end def textWindPlot (t) if (defined? $twind_plot) && TkWinfo.exist?($twind_plot) return end $twind_plot = TkCanvas.new(t) { relief 'sunken' width 450 height 300 cursor 'top_left_arrow' } if $tk_version =~ /^4.*/ font = '-Adobe-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*' else font = 'Helvetica 18' end TkcLine.new($twind_plot, 100, 250, 400, 250, 'width'=>2) TkcLine.new($twind_plot, 100, 250, 100, 50, 'width'=>2) TkcText.new($twind_plot, 225, 20, 'text'=>"A Simple Plot", 'font'=>font, 'fill'=>'brown') (0..10).each {|i| x = 100 + (i * 30) TkcLine.new($twind_plot, x, 250, x, 245, 'width'=>2) TkcText.new($twind_plot, x, 254, 'text'=>10*i, 'font'=>font, 'anchor'=>'n') } (0..5).each {|i| y = 250 - (i * 40) TkcLine.new($twind_plot, 100, y, 105, y, 'width'=>2) TkcText.new($twind_plot, 96, y, 'text'=>"#{i*50}.0", 'font'=>font, 'anchor'=>'e') } for xx, yy in [[12,56],[20,94],[33,98],[32,120],[61,180],[75,160],[98,223]] x = 100 + (3*xx) y = 250 - (4*yy)/5 item = TkcOval.new($twind_plot, x-6, y-6, x+6, y+6, 'width'=>1, 'outline'=>'black', 'fill'=>'SkyBlue2') item.addtag 'point' end $twind_plot.itembind('point', 'Any-Enter', proc{$twind_plot.itemconfigure 'current', 'fill', 'red'}) $twind_plot.itembind('point', 'Any-Leave', proc{$twind_plot.itemconfigure 'current', 'fill', 'SkyBlue2'}) $twind_plot.itembind('point', '1', proc{|x,y| embPlotDown $twind_plot,x,y}, "%x %y") $twind_plot.itembind('point', 'ButtonRelease-1', proc{$twind_plot.dtag 'selected'}) $twind_plot.bind('B1-Motion', proc{|x,y| embPlotMove $twind_plot,x,y}, "%x %y") while ($twind_text.get($mark_plot) =~ /[ \t\n]/) $twind_text.delete $mark_plot end $twind_text.insert $mark_plot,"\n" TkTextWindow.new($twind_text, $mark_plot, 'window'=>$twind_plot) $tag_center.add $mark_plot $twind_text.insert $mark_plot,"\n" end $embPlot = {'lastX'=>0, 'lastY'=>0} def embPlotDown (w, x, y) w.dtag 'selected' w.addtag_withtag 'selected', 'current' w.raise 'current' $embPlot['lastX'] = x $embPlot['lastY'] = y end def embPlotMove (w, x, y) w.move 'selected', x - $embPlot['lastX'], y - $embPlot['lastY'] $embPlot['lastX'] = x $embPlot['lastY'] = y end def textWindDel (w) if (defined? $twind_text) && TkWinfo.exist?($twind_plot) $twind_text.delete $twind_plot $twind_plot = nil while ($twind_text.get($mark_plot) =~ /[ \t\n]/) $twind_text.delete $mark_plot end $twind_text.insert $mark_plot," " end end def embDefBg (w) w['background'] = w.configinfo('background')[3] end ================================================ FILE: ext/tk/sample/demos-en/twind2.rb ================================================ # # text (embedded windows) widget demo 2 (called by 'widget') # # delete toplevel widget if defined?($twind2_demo) && $twind2_demo $twind2_demo.destroy $twind2_demo = nil end # demo toplevel widget $twind2_demo = TkToplevel.new {|w| title("Text Demonstration - Embedded Windows 2") iconname("Embedded Windows") positionWindow(w) } base_frame = TkFrame.new($twind2_demo).pack(:fill=>:both, :expand=>true) # frame $twind2_buttons = TkFrame.new(base_frame) {|frame| TkGrid(TkFrame.new(frame, :height=>2, :relief=>:sunken, :bd=>2), :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', TkButton.new(frame, :text=>'See Code', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'twind2'}), TkButton.new(frame, :text=>'Dismiss', :image=>$image['delete'], :compound=>:left, :command=>proc{ tmppath = $twind2_demo $twind2_demo = nil $showVarsWin[tmppath.path] = nil tmppath.destroy }), :padx=>4, :pady=>4) frame.grid_columnconfigure(0, :weight=>1) } $twind2_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame $twind2_text = nil TkFrame.new(base_frame, 'highlightthickness'=>2, 'borderwidth'=>2, 'relief'=>'sunken') {|f| $twind2_text = TkText.new(f, 'setgrid'=>true, 'font'=>$font, # 'width'=>'70', 'height'=>35, 'wrap'=>'word', 'width'=>'70', 'height'=>35, 'wrap'=>'char', 'highlightthickness'=>0, 'borderwidth'=>0 ){|t| TkScrollbar.new(f) {|s| command proc{|*args| t.yview(*args)} t.yscrollcommand proc{|first,last| s.set first,last} }.pack('side'=>'right', 'fill'=>'y') }.pack('expand'=>'yes', 'fill'=>'both') }.pack('expand'=>'yes', 'fill'=>'both') # text tags $tag2_center = TkTextTag.new($twind2_text, 'justify' =>'center', 'spacing1'=>'5m', 'spacing3'=>'5m' ) $tag2_buttons = TkTextTag.new($twind2_text, 'lmargin1'=>'1c', 'lmargin2'=>'1c', 'rmargin' =>'1c', 'spacing1'=>'3m', 'spacing2'=>0, 'spacing3'=>0 ) # insert text $twind2_text.insert('end', 'A text widget can contain many different kinds of items, ') $twind2_text.insert('end', "both active and passive. It can lay these out in various ") $twind2_text.insert('end', "ways, with wrapping, tabs, centering, etc. In addition, ") $twind2_text.insert('end', "when the contents are too big for the window, smooth ") $twind2_text.insert('end', "scrolling in all directions is provided.\n\n") $twind2_text.insert('end', "A text widget can contain other widgets embedded ") $twind2_text.insert('end', "it. These are called \"embedded windows\", ") $twind2_text.insert('end', "and they can consist of arbitrary widgets. ") $twind2_text.insert('end', "For example, here are two embedded button ") $twind2_text.insert('end', "widgets. You can click on the first button to ") TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text) { text 'ON' command proc{textWindOn2 $twind2_text,$twind2_buttons} cursor 'top_left_arrow' }) $twind2_text.insert('end', " horizontal scrolling, which also turns off ") $twind2_text.insert('end', "word wrapping. Or, you can click on the second ") $twind2_text.insert('end', "button to\n") TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text) { text 'OFF' command proc{textWindOff2 $twind2_text} cursor 'top_left_arrow' }) $twind2_text.insert('end', " horizontal scrolling and turn back on word wrapping.\n\n") $twind2_text.insert('end', "Or, here is another example. If you ") TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text) { text 'Click Here' command proc{textWindPlot2 $twind2_text} cursor 'top_left_arrow' }) $twind2_text.insert('end', " a canvas displaying an x-y plot will appear right here.") $mark2_plot = TkTextMark.new($twind2_text, 'insert') $mark2_plot.gravity='left' $twind2_text.insert('end', " You can drag the data points around with the mouse, ") $twind2_text.insert('end', "or you can click here to ") TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text) { text 'Delete' command proc{textWindDel2 $twind2_text} cursor 'top_left_arrow' }) $twind2_text.insert('end', " the plot again.\n\n") $twind2_text.insert('end', "You may also find it useful to put embedded windows in ") $twind2_text.insert('end', "a text without any actual text. In this case the ") $twind2_text.insert('end', "text widget acts like a geometry manager. For ") $twind2_text.insert('end', "example, here is a collection of buttons laid out ") $twind2_text.insert('end', "neatly into rows by the text widget. These buttons ") $twind2_text.insert('end', "can be used to change the background color of the ") $twind2_text.insert('end', "text widget (\"Default\" restores the color to ") $twind2_text.insert('end', "its default). If you click on the button labeled ") $twind2_text.insert('end', "\"Short\", it changes to a longer string so that ") $twind2_text.insert('end', "you can see how the text widget automatically ") $twind2_text.insert('end', "changes the layout. Click on the button again ") $twind2_text.insert('end', "to restore the short string.\n") btn_default = TkButton.new($twind2_text) {|b| text 'Default' command proc{embDefBg2 $twind2_text} cursor 'top_left_arrow' } TkTextWindow.new($twind2_text, 'end', 'window'=>btn_default, 'padx'=>3) embToggle = TkVariable.new('Short') TkTextWindow.new($twind2_text, 'end', 'window'=>TkCheckButton.new($twind2_text) { textvariable embToggle indicatoron 0 variable embToggle onvalue 'A much longer string' offvalue 'Short' cursor 'top_left_arrow' pady 5 padx 2 }, 'padx'=>3, 'pady'=>2 ) [ 'AntiqueWhite3', 'Bisque1', 'Bisque2', 'Bisque3', 'Bisque4', 'SlateBlue3', 'RoyalBlue1', 'SteelBlue2', 'DeepSkyBlue3', 'LightBlue1', 'DarkSlateGray1', 'Aquamarine2', 'DarkSeaGreen2', 'SeaGreen1', 'Yellow1', 'IndianRed1', 'IndianRed2', 'Tan1', 'Tan4' ].each{|twind_color| TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text) { text twind_color cursor 'top_left_arrow' command proc{$twind2_text.bg twind_color} }, 'padx'=>3, 'pady'=>2 ) } $tag2_buttons.add(btn_default, 'end') $text_normal2 = {} $text_normal2['border'] = $twind2_text.cget('borderwidth') $text_normal2['highlight'] = $twind2_text.cget('highlightthickness') $text_normal2['pad'] = $twind2_text.cget('padx') $twind2_text.insert('end', "\nYou can also change the usual border width and ") $twind2_text.insert('end', "highlightthickness and padding.\n") TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text, :text=>"Big borders", :cursor=>'top_left_arrow', 'command'=>proc{ textWinBigB2 $twind2_text })) TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text, :text=>"Small borders", :cursor=>'top_left_arrow', 'command'=>proc{ textWinSmallB2 $twind2_text })) TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text, :text=>"Big highlight", :cursor=>'top_left_arrow', 'command'=>proc{ textWinBigH2 $twind2_text })) TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text, :text=>"Small highlight", :cursor=>'top_left_arrow', 'command'=>proc{ textWinSmallH2 $twind2_text })) TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text, :text=>"Big pad", :cursor=>'top_left_arrow', 'command'=>proc{ textWinBigP2 $twind2_text })) TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text, :text=>"Small pad", :cursor=>'top_left_arrow', 'command'=>proc{ textWinSmallP2 $twind2_text })) $twind2_text.insert('end', "\n\nFinally, images fit comfortably in text widgets too:") TkTextImage.new($twind2_text, 'end', 'image'=>TkBitmapImage.new(:file=>[ $demo_dir, '..', 'images', 'face.xbm' ].join(File::Separator))) # methods def textWinBigB2(w) w.borderwidth 15 end def textWinSmallB2(w) w.borderwidth $text_normal2['border'] end def textWinBigH2(w) w.highlightthickness 15 end def textWinSmallH2(w) w.highlightthickness $text_normal2['highlight'] end def textWinBigP2(w) w.configure(:padx=>15, :pady=>15) end def textWinSmallP2(w) w.configure(:padx=>$text_normal2['pad'], :pady=>$text_normal2['pad']) end def textWindOn2 (w,f) if defined? $twind2_scroll begin $twind2_scroll.destroy rescue end $twind2_scroll = nil end base = TkWinfo.parent( TkWinfo.parent(w) ) $twind2_scroll = TkScrollbar.new(base) {|s| orient 'horizontal' command proc{|*args| w.xview(*args)} w.xscrollcommand proc{|first,last| s.set first,last} w.wrap 'none' pack('after'=>f, 'side'=>'bottom', 'fill'=>'x') } return nil end def textWindOff2 (w) if defined? $twind2_scroll begin $twind2_scroll.destroy rescue end $twind2_scroll = nil end w.xscrollcommand '' #w.wrap 'word' w.wrap 'char' end def textWindPlot2 (t) if (defined? $twind2_plot) && (TkWinfo.exist?($twind2_plot)) return end $twind2_plot = TkCanvas.new(t) { relief 'sunken' width 450 height 300 cursor 'top_left_arrow' } #font = '-Adobe-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*' font = 'Helvetica 18' TkcLine.new($twind2_plot, 100, 250, 400, 250, 'width'=>2) TkcLine.new($twind2_plot, 100, 250, 100, 50, 'width'=>2) TkcText.new($twind2_plot, 225, 20, 'text'=>"A Simple Plot", 'font'=>font, 'fill'=>'brown') (0..10).each {|i| x = 100 + (i * 30) TkcLine.new($twind2_plot, x, 250, x, 245, 'width'=>2) TkcText.new($twind2_plot, x, 254, 'text'=>10*i, 'font'=>font, 'anchor'=>'n') } (0..5).each {|i| y = 250 - (i * 40) TkcLine.new($twind2_plot, 100, y, 105, y, 'width'=>2) TkcText.new($twind2_plot, 96, y, 'text'=>"#{i*50}.0", 'font'=>font, 'anchor'=>'e') } for xx, yy in [[12,56],[20,94],[33,98],[32,120],[61,180],[75,160],[98,223]] x = 100 + (3*xx) y = 250 - (4*yy)/5 item = TkcOval.new($twind2_plot, x-6, y-6, x+6, y+6, 'width'=>1, 'outline'=>'black', 'fill'=>'SkyBlue2') item.addtag 'point' end $twind2_plot.itembind('point', 'Any-Enter', proc{$twind2_plot.itemconfigure 'current', 'fill', 'red'}) $twind2_plot.itembind('point', 'Any-Leave', proc{$twind2_plot.itemconfigure 'current', 'fill', 'SkyBlue2'}) $twind2_plot.itembind('point', '1', proc{|x,y| embPlotDown2 $twind2_plot,x,y}, "%x %y") $twind2_plot.itembind('point', 'ButtonRelease-1', proc{$twind2_plot.dtag 'selected'}) $twind2_plot.bind('B1-Motion', proc{|x,y| embPlotMove2 $twind2_plot,x,y}, "%x %y") while ($twind2_text.get($mark2_plot) =~ /[ \t\n]/) $twind2_text.delete $mark2_plot end $twind2_text.insert $mark2_plot,"\n" TkTextWindow.new($twind2_text, $mark2_plot, 'window'=>$twind2_plot) $tag2_center.add $mark2_plot $twind2_text.insert $mark2_plot,"\n" end $embPlot2 = {'lastX'=>0, 'lastY'=>0} def embPlotDown2 (w, x, y) w.dtag 'selected' w.addtag_withtag 'selected', 'current' w.raise 'current' $embPlot2['lastX'] = x $embPlot2['lastY'] = y end def embPlotMove2 (w, x, y) w.move 'selected', x - $embPlot2['lastX'], y - $embPlot2['lastY'] $embPlot2['lastX'] = x $embPlot2['lastY'] = y end def textWindDel2 (w) if (defined? $twind2_text) && TkWinfo.exist?($twind2_plot) $twind2_text.delete $twind2_plot $twind2_plot = nil while ($twind2_text.get($mark2_plot) =~ /[ \t\n]/) $twind2_text.delete $mark2_plot end $twind2_text.insert $mark2_plot," " end end def embDefBg2 (w) w['background'] = w.configinfo('background')[3] end ================================================ FILE: ext/tk/sample/demos-en/unicodeout.rb ================================================ # unicodeout.rb -- # # This demonstration script shows how you can produce output (in label # widgets) using many different alphabets. # # based on Tcl/Tk8.4.4 widget demos if defined?($unicodeout_demo) && $unicodeout_demo $unicodeout_demo.destroy $unicodeout_demo = nil end $unicodeout_demo = TkToplevel.new {|w| title("Unicode Label Demonstration") iconname("unicodeout") positionWindow(w) } base_frame = TkFrame.new($unicodeout_demo).pack(:fill=>:both, :expand=>true) TkLabel.new(base_frame, :font=>$font, :wraplength=>'5.4i', :justify=>:left, :text=><:top) This is a sample of Tk's support for languages that use non-Western \ character sets. However, what you will actually see below depends \ largely on what character sets you have installed, and what you see \ for characters that are not present varies greatly between platforms as well. \ Please try to click the 'See Code' button, \ and click the 'Rerun Demo' button after editing \ (the source file is not changed) \ the definition of @@font on the Unicodeout_SampleFrame class. The strings are written in Tcl using UNICODE characters \ using the \\uXXXX escape so as to do so in a portable fashion. ATTENTION: The strings are converted to the encoded string objects \ (completed to rewrite Tcl's escapes) by Tk::UTF8_String method. \ And the Tk::UTF8_String objects are passed to the label widgets. EOL TkFrame.new(base_frame){|f| pack(:side=>:bottom, :fill=>:x, :pady=>'2m') TkButton.new(f, :text=>'Dismiss', :width=>15, :command=>proc{ $unicodeout_demo.destroy $unicodeout_demo = nil }).pack(:side=>:left, :expand=>true) TkButton.new(f, :text=>'See Code', :width=>15, :command=>proc{ showCode 'unicodeout' }).pack(:side=>:left, :expand=>true) } wait_msg = TkLabel.new(base_frame, :text=>"Please wait while loading fonts...", :font=>"Helvetica 12 italic").pack class Unicodeout_SampleFrame < TkFrame @@font = $font # @@font = 'Helvetica 14' # @@font = 'Courier 12' # @@font = 'clearlyu 16' # @@font = 'fixed 12' # @@font = 'Times 12' # @@font = 'Newspaper 12' # @@font = '{New century schoolbook} 12' def initialize(base) super(base) grid_columnconfig(1, :weight=>1) end def add_sample(lang, *args) sample_txt = Tk::UTF8_String(args.join('')) l = TkLabel.new(self, :font=>@@font, :text=>lang+':', :anchor=>:nw, :pady=>0) #s = TkLabel.new(self, :font=>@@font, :text=>sample_txt, s = TkLabel.new(self, :font=>TkFont.new(@@font), :text=>sample_txt, :anchor=>:nw, :width=>30, :pady=>0) Tk.grid(l, s, :sticky=>:ew, :pady=>0) l.grid_config(:padx, '1m') end end f = Unicodeout_SampleFrame.new(base_frame) f.pack(:expand=>true, :fill=>:both, :padx=>'2m', :pady=>'1m') # Processing when some characters are missing might take a while, so make # sure we're displaying something in the meantime... oldCursor = $unicodeout_demo.cursor $unicodeout_demo.cursor('watch') Tk.update f.add_sample('Arabic', '\uFE94\uFEF4\uFE91\uFEAE\uFECC\uFEDF\uFE8D\uFE94', '\uFEE4\uFEE0\uFEDC\uFEDF\uFE8D') f.add_sample('Trad. Chinese', '\u4E2D\u570B\u7684\u6F22\u5B57') f.add_sample('Simpl. Chinese', '\u6C49\u8BED') f.add_sample('Greek', '\u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AE ', '\u03B3\u03BB\u03CE\u03C3\u03C3\u03B1') f.add_sample('Hebrew', '\u05DD\u05D9\u05DC\u05E9\u05D5\u05E8\u05D9 ', '\u05DC\u05D9\u05D0\u05E8\u05E9\u05D9') f.add_sample('Japanese', '\u65E5\u672C\u8A9E\u306E\u3072\u3089\u304C\u306A, ', '\u6F22\u5B57\u3068\u30AB\u30BF\u30AB\u30CA') f.add_sample('Korean', '\uB300\uD55C\uBBFC\uAD6D\uC758 \uD55C\uAE00') f.add_sample('Russian', '\u0420\u0443\u0441\u0441\u043A\u0438\u0439 ', '\u044F\u0437\u044B\u043A') wait_msg.destroy $unicodeout_demo.cursor(oldCursor) ================================================ FILE: ext/tk/sample/demos-en/vscale.rb ================================================ # vscale.rb # # This demonstration script shows an example with a vertical scale. require "tkcanvas" if defined?($vscale_demo) && $vscale_demo $vscale_demo.destroy $vscale_demo = nil end $vscale_demo = TkToplevel.new {|w| title("Vertical Scale Demonstration") iconname("vscale") } positionWindow($vscale_demo) base_frame = TkFrame.new($vscale_demo).pack(:fill=>:both, :expand=>true) msg = TkLabel.new(base_frame) { font $font wraplength '3.5i' justify 'left' text "An arrow and a vertical scale are displayed below. If you click or drag mouse button 1 in the scale, you can change the size of the arrow." } msg.pack('side'=>'top', 'padx'=>'.5c') TkFrame.new(base_frame) {|frame| TkButton.new(frame) { text 'Dismiss' command proc { tmppath = $vscale_demo $vscale_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'Show Code' command proc { showCode 'vscale' } }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') def setHeight(w, height) height = height + 21 y2 = height - 30 if y2 < 21 y2 = 21 end w.coords 'poly',15,20,35,20,35,y2,45,y2,25,height,5,y2,15,y2,15,20 w.coords 'line',15,20,35,20,35,y2,45,y2,25,height,5,y2,15,y2,15,20 end TkFrame.new(base_frame) {|frame| borderwidth 10 canvas = TkCanvas.new(frame) {|c| width 50 height 50 bd 0 highlightthickness 0 TkcPolygon.new(c, 0, 0, 1, 1, 2, 2) { fill 'SeaGreen3' tags 'poly' } TkcLine.new(c, 0, 0, 1, 1, 2, 2, 0, 0) { fill 'black' tags 'line' } }.pack('side'=>'left', 'anchor'=>'nw', 'fill'=>'y') scale = TkScale.new(frame) { orient 'vertical' length 284 from 0 to 250 command proc{|value| setHeight(canvas, value)} tickinterval 50 }.pack('side'=>'left', 'anchor'=>'ne') scale.set 75 }.pack ================================================ FILE: ext/tk/sample/demos-en/widget ================================================ #!/usr/bin/env ruby # widget -- # This script demonstrates the various widgets provided by Tk, # along with many of the features of the Tk toolkit. This file # only contains code to generate the main window for the # application, which invokes individual demonstrations. The # code for the actual demonstrations is contained in separate # ".rb" files is this directory, which are sourced by this script # as needed. require 'tk' # require 'tkafter' ### $DEBUG=1 ########## $RubyTk_WidgetDemo = true #---------------------------------------------------------------- # The code below create the main window, consisting of a menu bar # and a text widget that explains how to use the program, plus lists # all of the demos as hypertext items. #---------------------------------------------------------------- # widget demo directory # $demo_dir = File.dirname($0) $demo_dir = File.dirname(__FILE__) # root $root = TkRoot.new{title "Ruby/Tk Widget Demonstration"} # tk $tk_version = Tk::TK_VERSION $tk_major_ver, $tk_minor_ver = $tk_version.split('.').map{|n| n.to_i} $tk_patchlevel = Tk::TK_PATCHLEVEL # tcl_platform $tk_platform = TkVarAccess.new('tcl_platform') # case($tk_version) when /^4.*/ $font = TkFont.new('-*-Helvetica-Medium-R-Normal--*-140-*-*-*-*-*-*', nil) else $font = TkFont.new('Helvetica -12') end # images $image = {} if $tk_major_ver >= 8 $image['refresh'] = TkPhotoImage.new(:height=>16, :format=>'GIF', :data=><= 8 $image['view'] = TkPhotoImage.new(:height=>16, :format=>'GIF', :data=><= 8 $image['delete'] = TkPhotoImage.new(:height=>16, :format=>'GIF', :data=><= 8 $image['print'] = TkPhotoImage.new(:height=>19, :format=>'GIF', :data=><= 8 $root.add_menubar([[['File', 0], ['About ... ', proc{aboutBox}, 0, ''], '---', ['Quit', proc{exit}, 0, 'Ctrl-Q'] ]]) else TkMenubar.new($root, [[['File', 0], ['About ... ', proc{aboutBox}, 0, ''], '---', ['Quit', proc{exit}, 0, 'Ctrl-Q'] ]]).pack('side'=>'top', 'fill'=>'x') end $root.bind('F1', proc{aboutBox}) $root.bind('Control-q', proc{exit}) =begin TkFrame.new($root){|frame| TkMenubutton.new(frame){|button| m = TkMenu.new(button) { add 'command', 'label'=>'Quit', 'command'=>proc{exit}, 'underline'=>0 } menu m text 'File' underline 0 }.pack('side'=>'left') }.pack('side'=>'top', 'fill'=>'x') =end # if $tk_version =~ /^4\.[01]/ scr = TkScrollbar.new($root, 'orient'=>'vertical') txt = TkText.new($root) { wrap 'word' width 70 height 30 font $font setgrid 'yes' yscrollcommand proc{|first,last| scr.set first,last} } scr.command(proc{|*args| txt.yview(*args)}) scr.pack('side'=>'right', 'fill'=>'y') txt.pack('expand'=>'yes', 'fill'=>'both') else textFrame = TkFrame.new($root) scr = TkScrollbar.new($root, 'orient'=>'vertical', 'highlightthickness'=>0, 'takefocus'=>1) { pack('in'=>textFrame, 'side'=>'right', 'fill'=>'y', 'padx'=>1) } txt = TkText.new($root) { wrap 'word' width 70 height 30 font $font setgrid 'yes' highlightthickness 0 padx 4 pady 2 takefocus 0 bd 1 yscrollcommand proc{|first,last| scr.set first,last} } scr.command(proc{|*args| txt.yview(*args)}) # txt.pack('in'=>textFrame, 'expand'=>'yes', 'fill'=>'both', 'padx'=>1) txt.pack('in'=>textFrame, 'expand'=>'yes', 'fill'=>'both') # textFrame.pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>2) textFrame.pack('expand'=>'yes', 'fill'=>'both') statusBar = TkFrame.new($root) {|f| if $tk_version =~ /^4.*/ statusfont = '-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*' else statusfont = 'Helvetica 10' end $statusBarLabel = \ TkLabel.new(f, 'text'=>" ", 'relief'=>'sunken', 'bd'=>1, 'anchor'=>'w', 'font'=>statusfont) \ .pack('side'=>'left', 'padx'=>2, 'expand'=>'yes', 'fill'=>'both') TkLabel.new(f, 'width'=>8, 'relief'=>'sunken', 'bd'=>1, 'anchor'=>'w', 'font'=>statusfont) \ .pack('side'=>'left', 'padx'=>2) }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>2) end # Create a bunch of tags to use in the text widget, such as those for # section titles and demo descriptions. Also define the bindings for # tags. if $tk_version =~ /^4.*/ tag_title = TkTextTag.new(txt, 'font'=>'-*-Helvetica-Bold-R-Normal--*-180-*-*-*-*-*-*') else tag_title = TkTextTag.new(txt, 'font'=>'Helvetica 18 bold') end # We put some "space" characters to the left and right of each demo description # so that the descriptions are highlighted only when the mouse cursor # is right over them (but not when the cursor is to their left or right) tag_demospace = TkTextTag.new(txt, 'lmargin1'=>'1c', 'lmargin2'=>'1c') if TkWinfo.depth($root) == 1 tag_demo = TkTextTag.new(txt, 'lmargin1'=>'1c', 'lmargin2'=>'1c', 'underline'=>1) $tag_visited = TkTextTag.new(txt, 'lmargin1'=>'1c', 'lmargin2'=>'1c', 'underline'=>1) tag_hot = TkTextTag.new(txt, 'background'=>'black', 'foreground'=>'white') else tag_demo = TkTextTag.new(txt, 'lmargin1'=>'1c', 'lmargin2'=>'1c', 'foreground'=>'blue', 'underline'=>1) $tag_visited = TkTextTag.new(txt, 'lmargin1'=>'1c', 'lmargin2'=>'1c', 'foreground'=>'#303080', 'underline'=>1) # tag_hot = TkTextTag.new(txt, 'relief'=>'raised', 'borderwidth'=>1, # 'background'=>'SeaGreen3') tag_hot = TkTextTag.new(txt, 'borderwidth'=>1, 'foreground'=>'red') end #tag_demo.bind('Button-1', proc{invoke txt, txt.index('current')}) tag_demo.bind('ButtonRelease-1', proc{|x,y|invoke txt, txt.index("@#{x},#{y}")}, '%x %y') lastLine = TkVariable.new("") newLine = TkVariable.new("") tag_demo.bind('Enter', proc{|x,y| lastLine.value = txt.index("@#{x},#{y} linestart") tag_hot.add(lastLine.value, "#{lastLine.value} lineend") showStatus txt, txt.index("@#{x},#{y}") }, '%x %y') tag_demo.bind('Leave', proc{ tag_hot.remove('1.0','end') txt.configure('cursor','xterm') $statusBarLabel.configure('text'=>"") }) tag_demo.bind('Motion', proc{|x, y| newLine.value = txt.index("@#{x},#{y} linestart") if newLine.value != lastLine.value tag_hot.remove('1.0','end') lastLine.value = newLine.value if ( txt.tag_names("@#{x},#{y}").find{|t| t.kind_of?(String) && t =~ /^demo-/ } ) tag_hot.add(lastLine.value, "#{lastLine.value} lineend -1 chars") end end showStatus txt, txt.index("@#{x},#{y}") }, '%x %y') # Create the text for the text widget. txt.insert('end', "Ruby/Tk Widget Demonstrations\n\n", tag_title) txt.insert('end', <:both, :expand=>true) TkLabel.new(base) { text "Variable values:" width 20 anchor 'center' if $tk_version =~ /^4.*/ font '-Adobe-helvetica-medium-r-normal--*-180-*-*-*-*-*-*' else font 'Helvetica 14' end }.pack('side'=>'top', 'fill'=>'x') len = 1 args.each{|vnam,vbody| len = vnam.to_s.length if vnam.to_s.length > len } args.each{|vnam,vbody| TkFrame.new(w){|f| #TkLabel.new(f, 'text'=>"#{vnam}: ").pack('side'=>'left') TkLabel.new(f, 'text'=>"#{vnam}: ",'width'=>len+2).pack('side'=>'left') TkLabel.new(f, 'textvariable'=>vbody, 'anchor'=>'w')\ .pack('side'=>'left', 'expand'=>'yes', 'fill'=>'x') }.pack('side'=>'top', 'anchor'=>'w', 'fill'=>'x') } TkButton.new(base) { text "OK" command proc{w.destroy} }.pack('side'=>'bottom', 'pady'=>2) } $showVarsWin[parent.path] = w end def showVars2(parent, *args) if $showVarsWin[parent.path] begin $showVarsWin[parent.path].destroy rescue end end $showVarsWin[parent.path] = TkToplevel.new(parent) {|top| title "Variable values" base = TkFrame.new(top).pack(:fill=>:both, :expand=>true) TkLabelFrame.new(base, :text=>"Variable values:", :font=>{:family=>'Helvetica', :size=>14}){|f| args.each{|vnam,vbody| TkGrid(TkLabel.new(f, :text=>"#{vnam}: ", :anchor=>'w'), TkLabel.new(f, :textvariable=>vbody, :anchor=>'w'), :padx=>2, :pady=>2, :sticky=>'w') } f.grid(:sticky=>'news', :padx=>4) f.grid_columnconfig(1, :weight=>1) f.grid_rowconfig(100, :weight=>1) } TkButton.new(base, :text=>"OK", :width=>8, :default=>:active, :command=>proc{top.destroy}){|b| top.bind('Return', proc{b.invoke}) top.bind('Escape', proc{b.invoke}) b.grid(:sticky=>'e', :padx=>4, :pady=>[6, 4]) } base.grid_columnconfig(0, :weight=>1) base.grid_rowconfig(0, :weight=>1) } end if $tk_major_ver < 8 alias showVars showVars1 elsif $tk_major_ver == 8 && $tk_minor_ver < 4 alias showVars showVars1 else # ver >= 8.4 alias showVars showVars2 end # Pseudo-Toplevel support module PseudoToplevel_Evaluable def pseudo_toplevel_eval(body = Proc.new) Thread.current[:TOPLEVEL] = self begin body.call ensure Thread.current[:TOPLEVEL] = nil end end def pseudo_toplevel_evaluable? @pseudo_toplevel_evaluable end def pseudo_toplevel_evaluable=(mode) @pseudo_toplevel_evaluable = (mode)? true: false end def self.extended(mod) mod.__send__(:extend_object, mod) mod.instance_variable_set('@pseudo_toplevel_evaluable', true) end end class Object alias __method_missing__ method_missing private :__method_missing__ def method_missing(id, *args) begin has_top = (top = Thread.current[:TOPLEVEL]) && top.respond_to?(:pseudo_toplevel_evaluable?) && top.pseudo_toplevel_evaluable? && top.respond_to?(id) rescue Exception => e has_top = false end if has_top top.__send__(id, *args) else __method_missing__(id, *args) end end end class Proc def initialize(*args, &b) super @__pseudo_toplevel__ = Thread.current[:TOPLEVEL] end alias __call__ call def call(*args, &b) if top = @__pseudo_toplevel__ orig_top = Thread.current[:TOPLEVEL] Thread.current[:TOPLEVEL] = top begin __call__(*args, &b) ensure Thread.current[:TOPLEVEL] = orig_top end else __call__(*args, &b) end end end def proc(&b) Proc.new(&b) end def lambda(&b) Proc.new(&b) end def _null_binding Module.new.instance_eval{extend PseudoToplevel_Evaluable} # binding # Module.new.instance_eval{binding} end private :_null_binding def eval_samplecode(code, file=nil) #eval(code) #_null_binding.pseudo_toplevel_eval{ eval(code) } #Thread.new{ _null_binding.pseudo_toplevel_eval{ eval(code) } } Thread.new{ _null_binding.pseudo_toplevel_eval{ begin if file eval(code, binding, "(eval:#{file})") else eval(code) end rescue Exception=>e #p e TkBgError.show(e.class.inspect + ': ' + e.message + "\n" + "\n---< backtrace of Ruby side >-----\n" + e.backtrace.join("\n") + "\n---< backtrace of Tk side >-------") end } } Tk.update end # invoke -- # This procedure is called when the user clicks on a demo description. # It is responsible for invoking the demonstration. # # Arguments: # txt - Name of text widget # index - The index of the character that the user clicked on. def invoke(txt, idx) tag = txt.tag_names(idx).find{|t| t.kind_of?(String) && t =~ /^demo-/} return unless tag cursor = txt.cget('cursor') txt.cursor('watch') Tk.update # eval(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join, _null_binding) # Tk.update eval_samplecode(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join, tag[5..-1] + '.rb') txt.cursor(cursor) $tag_visited.add("#{idx} linestart +1 chars", "#{idx} lineend +1 chars") end =begin def invoke (txt, idx) tag = txt.tag_names(idx).find{|t| t.kind_of?(String) && t =~ /^demo-/} return unless tag current_cursor = txt.cget('cursor') txt.cursor('watch') Tk.update # eval `cat #{tag[5..-1]}.rb` # eval `cat #{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb` eval IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join Tk.update # txt.cursor('xterm') txt.cursor(current_cursor) $tag_visited.add("#{idx} linestart +1 chars", "#{idx} lineend +1 chars") end =end # showStatus -- # # Show the name of the demo program in the status bar. This procedure # is called when the user moves the cursor over a demo description. # def showStatus (txt, index) tag = txt.tag_names(index).find{|t| t.kind_of?(String) && t =~ /^demo-/} cursor = txt.cget('cursor') unless tag $statusBarLabel.configure('text', " ") newcursor = 'xterm' else demoname = tag[5..-1] $statusBarLabel.configure('text', "Run the \"#{demoname}\" sample program") newcursor = 'hand2' end txt.configure('cursor'=>newcursor) if cursor != newcursor end # showCode -- # This procedure creates a toplevel window that displays the code for # a demonstration and allows it to be edited and reinvoked. # # Arguments: # demo - The name of the demonstration's window, which can be # used to derive the name of the file containing its code. def showCode1(demo) file = "#{demo}.rb" $code_window = nil unless defined? $code_window if $code_window == nil || TkWinfo.exist?($code_window) == false $code_window = TkToplevel.new(nil) f = TkFrame.new($code_window) TkButton.new(f) { text "Dismiss" command proc{ $code_window.destroy $code_window = nil } }.pack('side'=>'right', 'expand'=>'false', 'pady'=>2, 'padx'=>25) TkButton.new(f) { text "Rerun Demo" # command proc{eval($code_text.get('1.0','end'), _null_binding)} command proc{eval_samplecode($code_text.get('1.0','end'), '')} }.pack('side'=>'right', 'expand'=>'false', 'pady'=>2) TkLabel.new(f,'text'=>'line:').pack('side'=>'left') linenum =TkLabel.new(f,'text'=>'').pack('side'=>'left') TkLabel.new(f,'text'=>' pos:').pack('side'=>'left') posnum =TkLabel.new(f,'text'=>'').pack('side'=>'left') $set_linenum = proc{|w| line, pos = w.index('insert').split('.') linenum.text = line posnum.text = pos } f.pack('side'=>'bottom', 'expand'=>'true', 'fill'=>'x') if $tk_version =~ /^4\.[01]/ s = TkScrollbar.new($code_window, 'orient'=>'vertical') $code_text = TkText.new($code_window) { height 40 setgrid 'yes' yscrollcommand proc{|first,last| s.set first,last} } s.command(proc{|*args| $code_text.yview(*args)}) s.pack('side'=>'right', 'fill'=>'y') $code_text.pack('side'=>'left', 'expand'=>'yes', 'fill'=>'both') else TkFrame.new($code_window) {|f| pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1) hs = TkScrollbar.new($code_window, 'highlightthickness'=>0, 'orient'=>'horizontal') vs = TkScrollbar.new($code_window, 'highlightthickness'=>0, 'orient'=>'vertical') $code_text = TkText.new($code_window) {|t| height 40 wrap 'word' xscrollcommand proc{|first,last| hs.set first,last} yscrollcommand proc{|first,last| vs.set first,last} setgrid 'yes' highlightthickness 0 pady 2 padx 3 hs.command(proc{|*args| $code_text.xview(*args)}) vs.command(proc{|*args| $code_text.yview(*args)}) } $code_text.grid('in'=>f, 'padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') vs.grid('in'=>f, 'padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>1, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') # xs.grid('in'=>f, 'padx'=>1, 'pady'=>1, 'row'=>1, 'column'=>0, # 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') # JKC 2001-07-26: segfaults under 1.7.1 (2001-06-19) [i686-linux] TkGrid.rowconfigure(f, 0, 'weight'=>1, 'minsize'=>0) TkGrid.columnconfigure(f, 0, 'weight'=>1, 'minsize'=>0) } end btag = TkBindTag.new btag.bind('Key', $set_linenum, '%W') btag.bind('Button', $set_linenum, '%W') btags = $code_text.bindtags btags.insert(btags.index($code_text.class) + 1, btag) $code_text.bindtags = btags else $code_window.deiconify $code_window.raise end $code_window.title("Demo code: #{file}") $code_window.iconname(file) # fid = open(file, 'r') fid = open([$demo_dir, file].join(File::Separator), 'r') $code_text.delete('1.0', 'end') #$code_text.insert('1.0', `cat #{file}`) $code_text.insert('1.0', fid.read) #$code_mark = TkTextMark.new($code_text, '1.0') #$code_text.set_insert('1.0') TkTextMarkInsert.new($code_text,'1.0') $set_linenum.call($code_text) fid.close end def showCode2(demo) file = "#{demo}.rb" $code_window = nil unless defined? $code_window if $code_window == nil || TkWinfo.exist?($code_window) == false $code_window = TkToplevel.new(nil) tf = TkFrame.new($code_window) $code_text = TkText.new(tf, :font=>'Courier 10', :height=>30, :wrap=>'word', :bd=>1, :setgrid=>true, :highlightthickness=>0, :pady=>2, :padx=>3) xscr = TkScrollbar.new(tf, :bd=>1){assign($code_text)} yscr = TkScrollbar.new(tf, :bd=>1){assign($code_text)} TkGrid($code_text, yscr, :sticky=>'news') #TkGrid(xscr) tf.grid_rowconfigure(0, :weight=>1) tf.grid_columnconfigure(0, :weight=>1) bf = TkFrame.new($code_window) lf = TkFrame.new(bf) TkLabel.new(lf, :text=>'line:').pack(:side=>:left) linenum =TkLabel.new(lf, :text=>'').pack(:side=>:left) TkLabel.new(lf, :text=>' pos:').pack(:side=>:left) posnum =TkLabel.new(lf, :text=>'').pack(:side=>:left) $set_linenum = proc{|w| line, pos = w.index('insert').split('.') linenum.text = line posnum.text = pos } b_dis = TkButton.new(bf, :text=>'Dismiss', :default=>:active, :command=>proc{ $code_window.destroy $code_window = nil }, :image=>$image['delete'], :compound=>:left) b_prn = TkButton.new(bf, :text=>'Print Code', :command=>proc{printCode($code_text, file)}, :image=>$image['print'], :compound=>:left) b_run = TkButton.new(bf, :text=>'Rerun Demo', :command=>proc{ # eval($code_text.get('1.0','end'), _null_binding) eval_samplecode($code_text.get('1.0','end'), '') }, :image=>$image['refresh'], :compound=>:left) TkGrid(lf, 'x', b_run, b_prn, b_dis, :padx=>4, :pady=>[6,4]) bf.grid_columnconfigure(1, :weight=>1) TkGrid(tf, :sticky=>'news') TkGrid(bf, :sticky=>'ew') $code_window.grid_columnconfigure(0, :weight=>1) $code_window.grid_rowconfigure(0, :weight=>1) $code_window.bind('Return', proc{|win| b_dis.invoke unless win.kind_of?(TkText) }, '%W') $code_window.bindinfo('Return').each{|cmd, arg| $code_window.bind_append('Escape', cmd, arg) } btag = TkBindTag.new btag.bind('Key', $set_linenum, '%W') btag.bind('Button', $set_linenum, '%W') btag.bind('Configure', $set_linenum, '%W') btags = $code_text.bindtags btags.insert(btags.index($code_text.class) + 1, btag) $code_text.bindtags = btags else $code_window.deiconify $code_window.raise end $code_window.title("Demo code: #{file}") $code_window.iconname(file) fid = open([$demo_dir, file].join(File::Separator), 'r') $code_text.delete('1.0', 'end') $code_text.insert('1.0', fid.read) TkTextMarkInsert.new($code_text,'1.0') $set_linenum.call($code_text) fid.close end if $tk_major_ver < 8 alias showCode showCode1 elsif $tk_major_ver == 8 && $tk_minor_ver < 4 alias showCode showCode1 else # ver >= 8.4 alias showCode showCode2 end # printCode -- # Prints the source code currently displayed in the See Code dialog. # Much thanks to Arjen Markus for this. # # Arguments: # txt - Name of text widget containing code to print # file - Name of the original file (implicitly for title) def printCode(txt, file) code = txt.get('1.0', 'end - 1c') dir = '.' dir = ENV['HOME'] if ENV['HOME'] dir = ENV['TMP'] if ENV['TMP'] dir = ENV['TEMP'] if ENV['TEMP'] fname = [dir, 'tkdemo-' + file].join(File::Separator) open(fname, 'w'){|fid| fid.print(code)} begin case Tk::TCL_PLATFORM('platform') when 'unix' msg = `lp -c #{fname}` unless $?.exitstatus == 0 Tk.messageBox(:title=>'Print spooling failure', :message=>'Print spooling probably failed: ' + msg) end when 'windows' begin printTextWin32(fname) rescue => e Tk.messageBox(:title=>'Print spooling failure', :message=>'Print spooling probably failed: ' + e.message) end when 'macintosh' Tk.messageBox(:title=>'Operation not Implemented', :message=>'Oops, sorry: not implemented yet!') else Tk.messageBox(:title=>'Operation not Implemented', :message=>'Wow! Unknown platform: ' + Tk::TCL_PLATFORM('platform')) end ensure File.delete(fname) end end # printTextWin32 -- # Print a file under Windows # # Arguments: # filename - Name of the file # def printTextWin32(fname) require 'win32/registry' begin app = Win32::Registry::HKEY_CLASSES_ROOT['.txt'] pcmd = nil Win32::Registry::HKEY_CLASSES_ROOT.open("#{app}\\shell\\print"){|reg| pcmd = reg['command'] } rescue app = Tk.tk_call('auto_execok', 'notepad.exe') pcmd = "#{app} /p %1" end pcmd.gsub!('%1', fname) puts pcmd cmd = Tk.tk_call('auto_execok', 'start') + ' /min ' + pcmd msg = `#{cmd}` unless $?.exitstatus == 0 fail RuntimeError, msg end end # aboutBox # # Pops up a message box with an "about" message # def aboutBox Tk.messageBox('icon'=>'info', 'type'=>'ok', 'title'=>'About Widget Demo', 'message'=>"Ruby/Tk widget demonstration Ver.1.7.0-en\n\n" + "based on demos of Tk8.1 -- 8.5 " + "( Copyright of Tcl/Tk demos:: " + "(c) 1996-1997 Sun Microsystems, Inc. / " + "(c) 1997-2000 Ajuba Solutions, Inc. / " + "(c) 2001-2007 Donal K. Fellows / " + "(c) 2002-2007 Daniel A. Steffen )\n\n" + "Your Ruby & Tk Version ::\n" + "Ruby#{RUBY_VERSION}(#{RUBY_RELEASE_DATE})[#{RUBY_PLATFORM}] / Tk#{$tk_patchlevel}#{(Tk::JAPANIZED_TK)? '-jp': ''}\n\n" + "Ruby/Tk release date :: tcltklib #{TclTkLib::RELEASE_DATE}; tk #{Tk::RELEASE_DATE}") end ######################################### # start demos if given at command line no_launcher = false if ARGV[0] == '-n' ARGV.shift no_launcher = true if ARGV.size > 0 else # show the root widget to make it lower then demo windows Tk.update end ARGV.each{|cmd| if cmd =~ /(.*).rb/ cmd = $1 end #eval(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join, # _null_binding) eval_samplecode(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join, cmd + '.rb') } if no_launcher $root.withdraw # hide root window Thread.start{ loop do count = 0 $root.winfo_children.each{|w| count += 1 if w.kind_of?(TkToplevel) } $root.destroy if count == 0 end } end ######################################### # start eventloop Tk.mainloop ================================================ FILE: ext/tk/sample/demos-jp/README ================================================ Ruby/Tk widget-demo version 1.2 ( 2000/04/08 ) ʰǽ幩 (nagai@ai.kyutech.ac.jp) ɸۤ Tcl/Tk ĥѥå Ruby (ʲ Ruby/Tk ȸƤӤޤ) ǤϡTk widget Ѥ GUI κԤȤǤޤºݤ GUI Ƥˤ͡ʼ㤬ץȤ¸ߤʤΤǤRuby/Tk ˤϤΤ褦Ŭʥץ륹ץȽ¸ߤޤǤФ ĥѥåθǤ Tcl/Tk ˤϡTk widget ѤƤɤΤ褦ʤȤ 뤫򼨤ΤȤ widget-demo ¸ߤꡤTcl/Tk Ѥ GUI κ ݤɽŪץȤʤäƤޤܥ֤ϡRuby/Tk ν ɽŪʥץ륹ץȤȤ٤Tcl/Tk widget-demo ܿ ΤǤ ΥС ruby-1.4.x бȤƤޤС٤ơ ۤȤѹϤޤruby-1.1c2 ʾʤưȻפޤruby-1.5.x ˤ ƤϥƥȤƤޤ󡥤ΤᡤߴαƶФ뤳Ȥ뤫⤷ޤ 󤬡ξǤ⾯νưȻפޤȤ߹ Tk ΥСϡ 4.2 Ǥ 8.0 Ǥ⽤ʤưϤǤܸǤǤΰܿȤʤä 뤿ᡤܸ첽줿 Tk ѤץȤΥƥȤϡС κݤ Tk4.2jp Tk8.0jp ξǹԤäƤޤ (ˤǤϤʤǤ) ΥСǤ ruby-1.4.x + Tk8.0jp ǤδñʥƥȤԤäƤޤ󤬡 ȤۤɤνϤƤޤΤϤʤȹͤƤޤ ܥ֤˴ޤޤ륹ץȤ¿ϡȤʤäƤ Tcl/Tk ǤŪ ץȵҤȤʤ褦ˤƤޤΤᡤRuby/Tk Υץȸ ϡޤ Ruby 餷ʤȤǤ礦ˤ⤫餺Τ褦ʵ äƤͳϡRuby/Tk Υɥ­ˤޤ Tcl/Tk ˤŬʻͽ񤬲¸ߤƤޤ顤Ruby/Tk ץȤ ݤϡΤ褦 Tcl/Tk λͽǾ䤤ʤ뤳ȤˤʤȻ ޤ widget λȤơTcl/Tk widget-demo 򻲾Ȥ뤳Ȥ⤢ Ǥ礦Ruby/Tk ǤεҤ widget-demo Tcl/Tk ǤεҤ˶ᤤΤˤ СˤäơRuby/Tk 뤳ȤǤȹͤޤ ö Ruby/Tk Ǥ widget λˡƤޤСRuby 餷 ץȤ뤳Ȥ񤷤ʤǤ礦ܥ֤ΥץȤϡRuby/Tk ǽ˽ޤǤƧȤѤƤйǤ widget-demo ΰܿˤäƤϡˤܿץȤ󶡤Ƥ ޤ˴դΰդɽޤ ΩСJAIST (ttate@jaist.ac.jp) ʿͻ (hiramatu@cdrom.co.jp) ʿˤ Ruby/Tk Web page (http://www.cdrom.co.jp/~hiramatu/) Ruby/Tk νͭѤȻפޤΤǡҤȤ ޤ (maebashi@iij.ad.jp) ϤȤơwidget-demo ΰܿ˺ݤ ɬפȤʤä Ruby Tk Ϣ饤֥꽤ˤĤơХλŦ Ƥˤⴶפޤ ƺǸ˺δդ Ruby ߷׼Ԥ ޤĤ 椭Ҥ (matz@netlab.co.jp) Ȼפޤ ================================================ FILE: ext/tk/sample/demos-jp/README.1st ================================================ Υǥ쥯ȥˤ Ruby/Tk Υǥ⥹ץȤƤޤ '.rb' ȤĥҤäƤեϡ㨡ץȤ 'widget' ƤӽФ륵֥ץȤǤ줾Ω ưޤ'widget' ץȤƤӽФƤ ⤷㨡ץ 'widget' εưƱˤĤΥ֥ ץȤưСΥ֥ץȤ̾ȤͿ Ƥ ( : /usr/local/bin/ruby widget button.rb entry1.rb text.rb ) ֥ץȤγĥ '.rb' Ͼά뤳ȤǤޤ ( : /usr/local/bin/ruby widget button entry1 text ) ⤷㨡ץȤΥɥɬפʤˤϡ'-n' ץͿƤ ( : /usr/local/bin/ruby widget -n button.rb entry1.rb text.rb ) ¾Υե (browse1 hello ʤ) ñȤưȤǽǤ 2004/04/14 Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) ================================================ FILE: ext/tk/sample/demos-jp/anilabel.rb ================================================ # -*- coding: euc-jp -*- # # animated label widget demo (called by 'widget') # # based on Tcl/Tk8.5a2 widget demos # toplevel widget ¸ߤк if defined?($anilabel_demo) && $anilabel_demo $anilabel_demo.destroy $anilabel_demo = nil end # demo Ѥ toplevel widget $anilabel_demo = TkToplevel.new {|w| title("Animated Label Demonstration") iconname("anilabel") positionWindow(w) } base_frame = TkFrame.new($anilabel_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "ˤ4ĤΥ˥᡼٥뤬ɽƤޤ¦ˤ٥ϡΥƥȥå򥹥뤷褦˸뤳ȤưդƤޤ¦Υ٥ϡɽ륤᡼Ѳ뤳ȤưͿƤޤ" } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $anilabel_demo $anilabel_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'anilabel'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # label demo ѥե졼 f_left = TkLabelFrame.new(base_frame, :text=>'Scrolling Texts') f_right = TkLabelFrame.new(base_frame, :text=>'GIF Image') Tk.pack(f_left, f_right, 'side'=>'left', 'expand'=>'yes', 'fill'=>'both', 'padx'=>10, 'pady'=>10) # animated label class AnimatedTextLabel < TkLabel def initialize(*args) super(*args) @timer = TkTimer.new{ _animation_callback } @timer.loop_exec = -1 # bind('Destroy'){ @timer.stop } @btag = TkBindTag.new('Destroy'){ @timer.stop } self.bindtags_unshift(@btag) end def _animation_callback() txt = self.text self.text = (txt[1..-1] << txt[0]) end private :_animation_callback def start(interval) @timer.set_interval(interval) @timer.start end def stop @timer.stop end end # animated image class AnimatedImageLabel < AnimatedTextLabel def initialize(*args) super(*args) @destroy_image = false @btag.bind_append('Destroy'){ if @destroy_image begin self.image.delete rescue end end } end attr_accessor :destroy_image def _animation_callback() img = self.image fmt = img.format if fmt.kind_of?(Array) if fmt[1].kind_of?(Hash) # fmt == ['GIF', {'index'=>idx}] idx = fmt[1]['index'] else # fmt == ['GIF', '-index', idx] :: Ruby1.8.2 returns this. idx = fmt[2] end elsif fmt.kind_of?(String) && fmt =~ /GIF -index (\d+)/ idx = $1.to_i else idx = -1 end begin img.format("GIF -index #{idx + 1}") rescue => e img.format("GIF -index 0") end end private :_animation_callback end # label l1 = AnimatedTextLabel.new(f_left, :borderwidth=>4, :relief=>:ridge, :font=>{:family=>'Courier', :size=>10}) l2 = AnimatedTextLabel.new(f_left, :borderwidth=>4, :relief=>:groove, :font=>{:family=>'Courier', :size=>10}) l3 = AnimatedTextLabel.new(f_left, :borderwidth=>4, :relief=>:flat, :font=>{:family=>'Courier', :size=>10}, :width=>18) Tk.pack(l1, l2, l3, :side=>:top, :expand=>true, :anchor=>:w, :padx=>10, :pady=>10) limg = AnimatedImageLabel.new(f_right, :borderwidth=>0) limg.pack(:side=>:top, :expand=>true, :padx=>10, :pady=>10) # base64-encoded animated GIF file tclPowerdData = <'GIF', :data=>tclPowerdData)).start(100) ================================================ FILE: ext/tk/sample/demos-jp/aniwave.rb ================================================ # -*- coding: euc-jp -*- # # animated wave demo (called by 'widget') # # based on Tcl/Tk8.5a2 widget demos # destroy toplevel widget for this demo script if defined?($aniwave_demo) && $aniwave_demo $aniwave_demo.destroy $aniwave_demo = nil end # create toplevel widget $aniwave_demo = TkToplevel.new {|w| title("Animated Wave Demonstration") iconname("aniwave") positionWindow(w) } base_frame = TkFrame.new($aniwave_demo).pack(:fill=>:both, :expand=>true) # create label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text 'ΥǥǤϡ饤󥢥ƥबĤ줿ХåȤɽƤޤ˥᡼ϡΥ饤󥢥ƥκɸͤѹ뤳ȤǼ¸Ƥޤ' } msg.pack('side'=>'top') # create frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $aniwave_demo $aniwave_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'aniwave'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # animated wave class AnimatedWaveDemo def initialize(frame, dir=:left) @direction = dir # create canvas widget @c = TkCanvas.new(frame, :width=>300, :height=>200, :background=>'black') @c.pack(:padx=>10, :pady=>10, :expand=>true) # Creates a coordinates list of a wave. @waveCoords = [] @backupCoords = [] n = 0 (-10..300).step(5){|n| @waveCoords << [n, 100]; @backupCoords << [n, 100] } n = 305 @waveCoords << [n, 0]; @backupCoords << [n, 0] @waveCoords << [n+5, 200]; @backupCoords << [n+5, 200] @coordsLen = @waveCoords.length # Create a smoothed line and arrange for its coordinates to be the # contents of the variable waveCoords. @line = TkcLine.new(@c, @waveCoords, :width=>1, :fill=>'green', :smooth=>true) # Main animation "loop". # Theoretically 100 frames-per-second (==10ms between frames) @timer = TkTimer.new(10){ basicMotion; reverser } # Arrange for the animation loop to stop when the canvas is deleted @c.bindtags_unshift(TkBindTag.new('Destroy'){ @timer.stop }) end # Basic motion handler. Given what direction the wave is travelling # in, it advances the y coordinates in the coordinate-list one step in # that direction. def basicMotion @backupCoords, @waveCoords = @waveCoords, @backupCoords (0...@coordsLen).each{|idx| if @direction == :left @waveCoords[idx][1] = @backupCoords[(idx+1 == @coordsLen)? 0: idx+1][1] else @waveCoords[idx][1] = @backupCoords[(idx == 0)? -1: idx-1][1] end } @line.coords(@waveCoords) end # Oscillation handler. This detects whether to reverse the direction # of the wave by checking to see if the peak of the wave has moved off # the screen (whose size we know already.) def reverser if @waveCoords[0][1] < 10 @direction = :right elsif @waveCoords[-1][1] < 10 @direction = :left end end # animation control def move @timer.start end def stop @timer.stop end end # Start the animation processing AnimatedWaveDemo.new(base_frame, :left).move ================================================ FILE: ext/tk/sample/demos-jp/arrow.rb ================================================ # -*- coding: euc-jp -*- # # arrowhead widget demo (called by 'widget') # # arrowSetup -- # This method regenerates all the text and graphics in the canvas # window. It's called when the canvas is initially created, and also # whenever any of the parameters of the arrow head are changed # interactively. # # Arguments: # c - Name of the canvas widget. def arrowSetup(c) v = $demo_arrowInfo # Remember the current box, if there is one. tags = c.gettags('current') if tags != [] cur = tags.find{|t| t.kind_of?(String) && t =~ /^box[1-3]$/ } else cur = nil end # Create the arrow and outline. c.delete('all') TkcLine.new(c, v.x1, v.y, v.x2, v.y, { 'width'=>10 * v.width, 'arrowshape'=>[10*v.a, 10*v.b, 10*v.c], 'arrow'=>'last' }.update(v.bigLineStyle) ) xtip = v.x2 - 10*v.b deltaY = 10*v.c + 5*v.width TkcLine.new(c, v.x2, v.y, xtip, v.y + deltaY, v.x2 - 10*v.a, v.y, xtip, v.y - deltaY, v.x2, v.y, 'width'=>2, 'capstyle'=>'round', 'joinstyle'=>'round') # Create the boxes for reshaping the line and arrowhead. TkcRectangle.new(c, v.x2-10*v.a-5, v.y-5, v.x2-10*v.a+5, v.y+5, {'tags'=>['box1', $arrowTag_box]}.update(v.boxStyle) ) TkcRectangle.new(c, xtip-5, v.y-deltaY-5, xtip+5, v.y-deltaY+5, {'tags'=>['box2', $arrowTag_box]}.update(v.boxStyle) ) TkcRectangle.new(c, v.x1-5, v.y-5*v.width-5, v.x1+5, v.y-5*v.width+5, {'tags'=>['box3', $arrowTag_box]}.update(v.boxStyle) ) c.itemconfigure cur, v.activeStyle if cur # Create three arrows in actual size with the same parameters TkcLine.new(c, v.x2+50, 0, v.x2+50, 1000, 'width'=>2) tmp = v.x2+100 TkcLine.new(c, tmp, v.y-125, tmp, v.y-75, 'width'=>v.width, 'arrow'=>'both', 'arrowshape'=>[v.a, v.b, v.c]) TkcLine.new(c, tmp-25, v.y, tmp+25, v.y, 'width'=>v.width, 'arrow'=>'both', 'arrowshape'=>[v.a, v.b, v.c]) TkcLine.new(c, tmp-25, v.y+75, tmp+25, v.y+125, 'width'=>v.width, 'arrow'=>'both', 'arrowshape'=>[v.a, v.b, v.c]) # Create a bunch of other arrows and text items showing the # current dimensions. tmp = v.x2+10 TkcLine.new(c, tmp, v.y-5*v.width, tmp, v.y-deltaY, 'arrow'=>'both', 'arrowshape'=>v.smallTips) TkcText.new(c, v.x2+15, v.y-deltaY+5*v.c, 'text'=>v.c, 'anchor'=>'w') tmp = v.x1-10 TkcLine.new(c, tmp, v.y-5*v.width, tmp, v.y+5*v.width, 'arrow'=>'both', 'arrowshape'=>v.smallTips) TkcText.new(c, v.x1-15, v.y, 'text'=>v.width, 'anchor'=>'e') tmp = v.y+5*v.width+10*v.c+10 TkcLine.new(c, v.x2-10*v.a, tmp, v.x2, tmp, 'arrow'=>'both', 'arrowshape'=>v.smallTips) TkcText.new(c, v.x2-5*v.a, tmp+5, 'text'=>v.a, 'anchor'=>'n') tmp = tmp+25 TkcLine.new(c, v.x2-10*v.b, tmp, v.x2, tmp, 'arrow'=>'both', 'arrowshape'=>v.smallTips) TkcText.new(c, v.x2-5*v.b, tmp+5, 'text'=>v.b, 'anchor'=>'n') if $tk_version =~ /^4.*/ TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w', 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') TkcText.new(c, v.x1, 330, 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]",'anchor'=>'w', 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') else TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w', 'font'=>'Helvetica 18') TkcText.new(c, v.x1, 330, 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]", 'anchor'=>'w', 'font'=>'Helvetica 18') end v.count += 1 end # toplevel widget ¸ߤк if defined?($arrow_demo) && $arrow_demo $arrow_demo.destroy $arrow_demo = nil end # demo Ѥ toplevel widget $arrow_demo = TkToplevel.new {|w| title("Arrowhead Editor Demonstration") iconname("arrow") positionWindow(w) } base_frame = TkFrame.new($arrow_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left', 'text'=>" widget ǡХǻȤ饤ˤĤ͡ƬηƤߤ뤳ȤǤޤηѤˤϡ礵줿ˤĤƤ 3ĤλͳѤɥåƤ¦̤礭ǤΥץ򼨤ƤޤΥƥȤϥ饤󥢥ƥФꥪץǤ"){ pack('side'=>'top') } # frame $arrow_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $arrow_demo $arrow_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'arrow'} }.pack('side'=>'left', 'expand'=>'yes') } $arrow_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # canvas $arrow_canvas = TkCanvas.new(base_frame, 'width'=>500, 'height'=>350, 'relief'=>'sunken', 'borderwidth'=>2) $arrow_canvas.pack('expand'=>'yes', 'fill'=>'both') # unless Struct.const_defined?("ArrowInfo") $demo_arrowInfo = Struct.new("ArrowInfo", :a, :b, :c, :width, :motionProc, :x1, :x2, :y, :smallTips, :count, :bigLineStyle, :boxStyle, :activeStyle).new end $demo_arrowInfo.a = 8 $demo_arrowInfo.b = 10 $demo_arrowInfo.c = 3 $demo_arrowInfo.width = 2 $demo_arrowInfo.motionProc = proc{} $demo_arrowInfo.x1 = 40 $demo_arrowInfo.x2 = 350 $demo_arrowInfo.y = 150 $demo_arrowInfo.smallTips = [5, 5, 2] $demo_arrowInfo.count = 0 if TkWinfo.depth($arrow_canvas) > 1 $demo_arrowInfo.bigLineStyle = {'fill'=>'SkyBlue1'} $demo_arrowInfo.boxStyle = {'fill'=>'', 'outline'=>'black', 'width'=>1} $demo_arrowInfo.activeStyle = {'fill'=>'red', 'outline'=>'black', 'width'=>1} else $demo_arrowInfo.bigLineStyle = {'fill'=>'black', 'stipple'=>'@'+[$demo_dir,'..','images','grey.25'].join(File::Separator)} $demo_arrowInfo.boxStyle = {'fill'=>'', 'outline'=>'black', 'width'=>1} $demo_arrowInfo.activeStyle = {'fill'=>'black','outline'=>'black','width'=>1} end $arrowTag_box = TkcTag.new($arrow_canvas) arrowSetup $arrow_canvas $arrowTag_box.bind('Enter', proc{$arrow_canvas.itemconfigure('current', $demo_arrowInfo.activeStyle)}) $arrowTag_box.bind('Leave', proc{$arrow_canvas.itemconfigure('current', $demo_arrowInfo.boxStyle)}) $arrowTag_box.bind('B1-Enter', proc{}) $arrowTag_box.bind('B1-Leave', proc{}) $arrow_canvas.itembind('box1', '1', proc{$demo_arrowInfo.motionProc \ = proc{|x,y| arrowMove1 $arrow_canvas, x, y}}) $arrow_canvas.itembind('box2', '1', proc{$demo_arrowInfo.motionProc \ = proc{|x,y| arrowMove2 $arrow_canvas, x, y}}) $arrow_canvas.itembind('box3', '1', proc{$demo_arrowInfo.motionProc \ = proc{|x,y| arrowMove3 $arrow_canvas, x, y}}) $arrowTag_box.bind('B1-Motion', proc{|x,y| $demo_arrowInfo.motionProc.call(x,y)}, "%x %y") $arrow_canvas.bind('Any-ButtonRelease-1', proc{arrowSetup $arrow_canvas}) # arrowMove1 -- # This method is called for each mouse motion event on box1 (the # one at the vertex of the arrow). It updates the controlling parameters # for the line and arrowhead. # # Arguments: # c - The name of the canvas window. # x, y - The coordinates of the mouse. def arrowMove1(c,x,y) v = $demo_arrowInfo newA = (v.x2+5-c.canvasx(x).round)/10 newA = 0 if newA < 0 newA = 25 if newA > 25 if newA != v.a c.move('box1', 10*(v.a-newA), 0) v.a = newA end end # arrowMove2 -- # This method is called for each mouse motion event on box2 (the # one at the trailing tip of the arrowhead). It updates the controlling # parameters for the line and arrowhead. # # Arguments: # c - The name of the canvas window. # x, y - The coordinates of the mouse. def arrowMove2(c,x,y) v = $demo_arrowInfo newB = (v.x2+5-c.canvasx(x).round)/10 newB = 0 if newB < 0 newB = 25 if newB > 25 newC = (v.y+5-c.canvasy(y).round-5*v.width)/10 newC = 0 if newC < 0 newC = 20 if newC > 20 if newB != v.b || newC != v.c c.move('box2', 10*(v.b-newB), 10*(v.c-newC)) v.b = newB v.c = newC end end # arrowMove3 -- # This method is called for each mouse motion event on box3 (the # one that controls the thickness of the line). It updates the # controlling parameters for the line and arrowhead. # # Arguments: # c - The name of the canvas window. # x, y - The coordinates of the mouse. def arrowMove3(c,x,y) v = $demo_arrowInfo newWidth = (v.y+2-c.canvasy(y).round)/5 newWidth = 0 if newWidth < 0 newWidth = 20 if newWidth > 20 if newWidth != v.width c.move('box3', 0, 5*(v.width-newWidth)) v.width = newWidth end end ================================================ FILE: ext/tk/sample/demos-jp/bind.rb ================================================ # -*- coding: euc-jp -*- # # text (tag bindings) widget demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($bind_demo) && $bind_demo $bind_demo.destroy $bind_demo = nil end # demo Ѥ toplevel widget $bind_demo = TkToplevel.new {|w| title("Text Demonstration - Tag Bindings") iconname("bind") positionWindow(w) } base_frame = TkFrame.new($bind_demo).pack(:fill=>:both, :expand=>true) # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $bind_demo $bind_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'bind'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # bind ѥ᥽å def tag_binding_for_bind_demo(tag, enter_style, leave_style) tag.bind('Any-Enter', proc{tag.configure enter_style}) tag.bind('Any-Leave', proc{tag.configure leave_style}) end # text txt = TkText.new(base_frame){|t| # setgrid 'true' #width 60 #height 24 font $font wrap 'word' TkScrollbar.new(base_frame) {|s| pack('side'=>'right', 'fill'=>'y') command proc{|*args| t.yview(*args)} t.yscrollcommand proc{|first,last| s.set first,last} } pack('expand'=>'yes', 'fill'=>'both') # if TkWinfo.depth($root).to_i > 1 tagstyle_bold = {'background'=>'#43ce80', 'relief'=>'raised', 'borderwidth'=>1} tagstyle_normal = {'background'=>'', 'relief'=>'flat'} else tagstyle_bold = {'foreground'=>'white', 'background'=>'black'} tagstyle_normal = {'foreground'=>'', 'background'=>''} end # ƥ insert 'insert', "ƥwidgetɽ椹ΤƱΥᥫ˥ȤäơƥȤTclΥޥɤƤ뤳ȤǤޤˤꡢޥ䥭ܡɤΥTclΥޥɤ¹Ԥ褦ˤʤޤ㤨СΥХΥǥץˤĤƤʸˤϤΤ褦ʥĤƤޤޥʸξ˻äƤʸꡢܥ1򲡤ȤΥǥ⤬Ϥޤޤ " insert('end', '1. Х widget ˺뤳ȤΤǤ륢ƥμƤ˴ؤ륵ץ롣', (d1 = TkTextTag.new(t)) ) insert('end', "\n\n") insert('end', '2. ñ 2ΥץåȡǡɽưȤǤ롣', (d2 = TkTextTag.new(t)) ) insert('end', "\n\n") insert('end', '3. ƥȥƥΥ󥫡ȹ·', (d3 = TkTextTag.new(t)) ) insert('end', "\n\n") insert('end', '4. 饤󥢥ƥΤƬηΥǥ', (d4 = TkTextTag.new(t)) ) insert('end', "\n\n") insert('end', '5. ֥ȥåפѹ뤿εǽĤΥ롼顼', (d5 = TkTextTag.new(t)) ) insert('end', "\n\n") insert('end', '6. Хɤäƥ뤹Τ򼨤åɡ', (d6 = TkTextTag.new(t)) ) # binding [d1, d2, d3, d4, d5, d6].each{|tag| tag_binding_for_bind_demo(tag, tagstyle_bold, tagstyle_normal) } d1.bind('1', proc{ eval_samplecode(`cat #{[$demo_dir,'items.rb'].join(File::Separator)}`, 'items.rb') }) d2.bind('1', proc{ eval_samplecode(`cat #{[$demo_dir,'plot.rb'].join(File::Separator)}`, 'plot.rb') }) d3.bind('1', proc{ eval_samplecode(`cat #{[$demo_dir,'ctext.rb'].join(File::Separator)}`, 'ctext.rb') }) d4.bind('1', proc{ eval_samplecode(`cat #{[$demo_dir,'arrow.rb'].join(File::Separator)}`, 'arrow.rb') }) d5.bind('1', proc{ eval_samplecode(`cat #{[$demo_dir,'ruler.rb'].join(File::Separator)}`, 'ruler.rb') }) d6.bind('1', proc{ eval_samplecode(`cat #{[$demo_dir,'cscroll.rb'].join(File::Separator)}`, 'cscroll.rb') }) TkTextMarkInsert.new(t, '0.0') configure('state','disabled') } txt.width 60 txt.height 24 ================================================ FILE: ext/tk/sample/demos-jp/bitmap.rb ================================================ # -*- coding: euc-jp -*- # # bitmap widget demo (called by 'widget') # # bitmapRow -- # Create a row of bitmap items in a window. # # Arguments: # w - The parent window that is to contain the row. # args - The names of one or more bitmaps, which will be displayed # in a new row across the bottom of w along with their # names. def bitmapRow(w,*args) TkFrame.new(w){|row| pack('side'=>'top', 'fill'=>'both') for bitmap in args TkFrame.new(row){|base| pack('side'=>'left', 'fill'=>'both', 'pady'=>'.25c', 'padx'=>'.25c') TkLabel.new(base, 'text'=>bitmap, 'width'=>9).pack('side'=>'bottom') Tk::Label.new(base, 'bitmap'=>bitmap).pack('side'=>'bottom') } end } end # toplevel widget ¸ߤк if defined?($bitmap_demo) && $bitmap_demo $bitmap_demo.destroy $bitmap_demo = nil end # demo Ѥ toplevel widget $bitmap_demo = TkToplevel.new {|w| title("Bitmap Demonstration") iconname("bitmap") positionWindow(w) } base_frame = TkFrame.new($bitmap_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left', 'text'=>"ΥɥˤϡTk Ȥ߹ޤ줿٤ƤΥӥåȥޥåפ̾ȶɽƤޤTcl ΥץǤϡ줾̾ѤƻȤޤ"){ pack('side'=>'top') } # frame $bitmap_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $bitmap_demo $bitmap_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'bitmap'} }.pack('side'=>'left', 'expand'=>'yes') } $bitmap_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame TkFrame.new(base_frame){|f| bitmapRow(f,'error','gray25','gray50','hourglass') bitmapRow(f,'info','question','questhead','warning') pack('side'=>'top', 'expand'=>'yes', 'fill'=>'both') } ================================================ FILE: ext/tk/sample/demos-jp/browse1 ================================================ #!/usr/bin/env ruby # browse -- # This script generates a directory browser, which lists the working # directory and allow you to open files or subdirectories by # double-clicking. require 'tk' # Create a scrollbar on the right side of the main window and a listbox # on the left side. listbox = TkListbox.new(nil, 'relief'=>'sunken', 'width'=>20, 'height'=>20, 'setgrid'=>'yes') {|l| TkScrollbar.new(nil, 'command'=>proc{|*args| l.yview *args}) {|s| pack('side'=>'right', 'fill'=>'y') l.yscrollcommand(proc{|first,last| s.set(first,last)}) } pack('side'=>'left', 'fill'=>'both', 'expand'=>'yes') } root = TkRoot.new root.minsize(1,1) # The procedure below is invoked to open a browser on a given file; if the # file is a directory then another instance of this program is invoked; if # the file is a regular file then the Mx editor is invoked to display # the file. def browse (dir, file) file = dir + File::Separator + file if dir != '.' type = File.ftype(file) if type == 'directory' system($0 + ' ' + file + ' &') else if type == 'file' if ENV['EDITOR'] system(ENV['EDITOR'] + ' ' + file + ' &') else system('xedit ' + file + ' &') end else STDOUT.print "\"#{file}\" isn't a directory or regular file" end end end # Fill the listbox with a list of all the files in the directory (run # the "ls" command to get that information). dir = ARGV[0] ? ARGV[0] : '.' open("|ls -a #{dir}", 'r'){|fid| fid.readlines}.each{|fname| listbox.insert('end', fname.chomp) } # Set up bindings for the browser. Tk.bind_all('Control-c', proc{root.destroy}) listbox.bind('Double-Button-1', proc{TkSelection.get.each{|f| browse dir, f}}) Tk.mainloop ================================================ FILE: ext/tk/sample/demos-jp/browse2 ================================================ #!/usr/bin/env ruby # browse -- # This script generates a directory browser, which lists the working # directory and allow you to open files or subdirectories by # double-clicking. require 'tk' class Browse BROWSE_WIN_COUNTER = TkVariable.new(0) def initialize(dir) BROWSE_WIN_COUNTER.value = BROWSE_WIN_COUNTER.to_i + 1 # create base frame base = TkToplevel.new { minsize(1,1) title('Browse : ' + dir) } # Create a scrollbar on the right side of the main window and a listbox # on the left side. list = TkListbox.new(base, 'relief'=>'sunken', 'width'=>20, 'height'=>20, 'setgrid'=>'yes') {|l| TkScrollbar.new(base, 'command'=>proc{|*args| l.yview *args}) {|s| pack('side'=>'right', 'fill'=>'y') l.yscrollcommand(proc{|first,last| s.set(first,last)}) } pack('side'=>'left', 'fill'=>'both', 'expand'=>'yes') # Fill the listbox with a list of all the files in the directory (run # the "ls" command to get that information). open("|ls -a #{dir}", 'r'){|fid| fid.readlines}.each{|fname| l.insert('end', fname.chomp) } } # Set up bindings for the browser. base.bind('Destroy', proc{ Browse::BROWSE_WIN_COUNTER.value = \ Browse::BROWSE_WIN_COUNTER.to_i - 1 }) base.bind('Control-c', proc{base.destroy}) list.bind('Double-Button-1', proc{TkSelection.get.each{|f| self.browse dir, f}}) end # The method below is invoked to open a browser on a given file; if the # file is a directory then another instance of this program is invoked; if # the file is a regular file then the Mx editor is invoked to display # the file. def browse (dir, file) file = dir + File::Separator + file if dir != '.' type = File.ftype(file) if type == 'directory' Browse.new(file) else if type == 'file' if ENV['EDITOR'] system(ENV['EDITOR'] + ' ' + file + ' &') else system('xedit ' + file + ' &') end else STDOUT.print "\"#{file}\" isn't a directory or regular file" end end end end Browse.new(ARGV[0] ? ARGV[0] : '.') TkRoot.new { withdraw Browse::BROWSE_WIN_COUNTER.trace('w', proc{exit if Browse::BROWSE_WIN_COUNTER.to_i == 0}) } Tk.mainloop ================================================ FILE: ext/tk/sample/demos-jp/button.rb ================================================ # -*- coding: euc-jp -*- # # button widget demo (called by 'widget') # # # toplevel widget ¸ߤк if defined?($button_demo) && $button_demo $button_demo.destroy $button_demo = nil end # demo Ѥ toplevel widget $button_demo = TkToplevel.new {|w| title("Button Demonstration") iconname("button") positionWindow(w) } # label msg = TkLabel.new($button_demo) { font $kanji_font wraplength '4i' justify 'left' text "ܥ򥯥åȡܥطʿΥܥ˽񤫤Ƥ뿧ˤʤޤܥ󤫤ܥؤΰưϥ֤򲡤ȤǤǽǤޤڡǼ¹Ԥ뤳ȤǤޤ" } msg.pack('side'=>'top') # frame $button_buttons = Tk::Frame.new($button_demo) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $button_demo $button_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'button'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # button TkButton.new($button_demo){ text "Peach Puff" width 10 command proc{ $button_demo.configure('bg','PeachPuff1') $button_buttons.configure('bg','PeachPuff1') } }.pack('side'=>'top', 'expand'=>'yes', 'pady'=>2) TkButton.new($button_demo){ text "Light Blue" width 10 command proc{ $button_demo.configure('bg','LightBlue1') $button_buttons.configure('bg','LightBlue1') } }.pack('side'=>'top', 'expand'=>'yes', 'pady'=>2) TkButton.new($button_demo){ text "Sea Green" width 10 command proc{ $button_demo.configure('bg','SeaGreen2') $button_buttons.configure('bg','SeaGreen2') } }.pack('side'=>'top', 'expand'=>'yes', 'pady'=>2) TkButton.new($button_demo){ text "Yellow" width 10 command proc{ $button_demo.configure('bg','Yellow1') $button_buttons.configure('bg','Yellow1') } }.pack('side'=>'top', 'expand'=>'yes', 'pady'=>2) ================================================ FILE: ext/tk/sample/demos-jp/check.rb ================================================ # -*- coding: euc-jp -*- # # checkbutton widget demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($check_demo) && $check_demo $check_demo.destroy $check_demo = nil end # demo Ѥ toplevel widget $check_demo = TkToplevel.new {|w| title("Checkbutton Demonstration") iconname("check") positionWindow(w) } base_frame = TkFrame.new($check_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "ˤ 3 ĤΥåܥɽƤޤåȥܥ֤ѤꡢTcl ѿ ( TkVariable ֥ȤǥǤޤ ) ˤΥܥξ֤򼨤ͤꤷޤߤѿͤ򸫤ˤϡѿȡץܥ򥯥åƤ" } msg.pack('side'=>'top') # ѿ wipers = TkVariable.new(0) brakes = TkVariable.new(0) sober = TkVariable.new(0) # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $check_demo $check_demo = nil $showVarsWin[tmppath.path] = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'check'} }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ѿ' command proc{ showVars(base_frame, ['wipers', wipers], ['brakes', brakes], ['sober', sober]) } }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # checkbutton [ TkCheckButton.new(base_frame, 'text'=>'磻ѡ OK', 'variable'=>wipers), TkCheckButton.new(base_frame, 'text'=>'֥졼 OK', 'variable'=>brakes), TkCheckButton.new(base_frame, 'text'=>'ž ', 'variable'=>sober) ].each{|w| w.relief('flat'); w.pack('side'=>'top', 'pady'=>2, 'anchor'=>'w')} ================================================ FILE: ext/tk/sample/demos-jp/check2.rb ================================================ # -*- coding: euc-jp -*- # # checkbutton widget demo2 (called by 'widget') # # toplevel widget ¸ߤк if defined?($check2_demo) && $check2_demo $check2_demo.destroy $check2_demo = nil end # demo Ѥ toplevel widget $check2_demo = TkToplevel.new {|w| title("Checkbutton Demonstration 2") iconname("check2") positionWindow(w) } base_frame = TkFrame.new($check2_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "ˤϣĤΥåܥɽƤޤåȥܥ֤ѤꡢTclѿTkVariable֥ȤǥǤޤˤˤΥܥξ֤򼨤ͤꤷޤǽΥܥξ֤¾ΣĤΥܥξ֤ˤ¸Ѳޤ⤷ĤΥܥΰ˥åդƤ硢ǽΥܥϥȥ饤ơȡʣ֡˥⡼ɤǤɽԤޤߤѿͤ򸫤ˤϡѿȡץܥ򥯥åƤ" } msg.pack('side'=>'top') # ѿ safety = TkVariable.new(0) wipers = TkVariable.new(0) brakes = TkVariable.new(0) sober = TkVariable.new(0) # frame TkFrame.new(base_frame) {|frame| TkGrid(TkFrame.new(frame, :height=>2, :relief=>:sunken, :bd=>2), :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', TkButton.new(frame, :text=>'ѿ', :image=>$image['view'], :compound=>:left, :command=>proc{ showVars($check2_demo, ['safety', safety], ['wipers', wipers], ['brakes', brakes], ['sober', sober]) }), TkButton.new(frame, :text=>'ɻ', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'check2'}), TkButton.new(frame, :text=>'Ĥ', :image=>$image['delete'], :compound=>:left, :command=>proc{ tmppath = $check2_demo $check2_demo = nil $showVarsWin[tmppath.path] = nil tmppath.destroy }), :padx=>4, :pady=>4) frame.grid_columnconfigure(0, :weight=>1) }.pack('side'=>'bottom', 'fill'=>'x') # checkbutton TkCheckButton.new(base_frame, :text=>'', :variable=>safety, :relief=>:flat, :onvalue=>'all', :offvalue=>'none', :tristatevalue=>'partial'){ pack('side'=>'top', 'pady'=>2, 'anchor'=>'w') } [ TkCheckButton.new(base_frame, 'text'=>'磻ѡ OK', 'variable'=>wipers), TkCheckButton.new(base_frame, 'text'=>'֥졼 OK', 'variable'=>brakes), TkCheckButton.new(base_frame, 'text'=>'ž ', 'variable'=>sober) ].each{|w| w.relief('flat') w.pack('side'=>'top', 'padx'=>15, 'pady'=>2, 'anchor'=>'w') } # tristate check in_check = false tristate_check = proc{|n1,n2,op| unless in_check in_check = true begin if n1 == safety if safety == 'none' wipers.value = 0 brakes.value = 0 sober.value = 0 elsif safety == 'all' wipers.value = 1 brakes.value = 1 sober.value = 1 end else if wipers == 1 && brakes == 1 && sober == 1 safety.value = 'all' elsif wipers == 1 || brakes == 1 || sober == 1 safety.value = 'partial' else safety.value = 'none' end end ensure in_check = false end end } [wipers, brakes, sober, safety].each{|v| v.trace('w', tristate_check)} ================================================ FILE: ext/tk/sample/demos-jp/clrpick.rb ================================================ # -*- coding: euc-jp -*- # # widget demo prompts the user to select a color (called by 'widget') # # Note: don't support ttk_wrapper. work with standard widgets only. # # toplevel widget ¸ߤк if defined?($clrpick_demo) && $clrpick_demo $clrpick_demo.destroy $clrpick_demo = nil end # demo Ѥ toplevel widget $clrpick_demo = TkToplevel.new {|w| title("Color Selection Dialogs") iconname("colors") positionWindow(w) } # label #TkLabel.new($clrpick_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left', Tk::Label.new($clrpick_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left', 'text'=>"ʲΥܥ򲡤ơΥɥˤ륦åȤʿطʿ򤷤Ʋ").pack('side'=>'top') # frame # TkFrame.new($clrpick_demo) {|frame| Tk::Frame.new($clrpick_demo) {|frame| # TkButton.new(frame) { Tk::Button.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $clrpick_demo $clrpick_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') # TkButton.new(frame) { Tk::Button.new(frame) { text 'ɻ' command proc{showCode 'clrpick'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # button # TkButton.new($clrpick_demo, 'text'=>'طʿ ...') {|b| Tk::Button.new($clrpick_demo, 'text'=>'طʿ ...') {|b| command(proc{setColor $clrpick_demo, b, 'background', ['background', 'highlightbackground']}) pack('side'=>'top', 'anchor'=>'c', 'pady'=>'2m') } # TkButton.new($clrpick_demo, 'text'=>'ʿ ...') {|b| Tk::Button.new($clrpick_demo, 'text'=>'ʿ ...') {|b| command(proc{setColor $clrpick_demo, b, 'foreground', ['foreground']}) pack('side'=>'top', 'anchor'=>'c', 'pady'=>'2m') } def setColor(w,button,name,options) w.grab initialColor = button[name] color = Tk.chooseColor('title'=>"Choose a #{name} color", 'parent'=>w, 'initialcolor'=>initialColor) if color != "" setColor_helper(w,options,color) end w.grab('release') end def setColor_helper(w, options, color) options.each{|opt| begin w[opt] = color rescue end } TkWinfo.children(w).each{|child| setColor_helper child, options, color } end ================================================ FILE: ext/tk/sample/demos-jp/colors.rb ================================================ # -*- coding: euc-jp -*- # # listbox widget demo 'colors' (called by 'widget') # # toplevel widget ¸ߤк if defined?($colors_demo) && $colors_demo $colors_demo.destroy $colors_demo = nil end # demo Ѥ toplevel widget $colors_demo = TkToplevel.new {|w| title("Listbox Demonstration (colors)") iconname("colors") positionWindow(w) } base_frame = TkFrame.new($colors_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "ˤϿ̾äСդΥꥹȥܥåɽƤޤꥹȤ򥹥뤵ΤϥСǤǤޤꥹȥܥåǥޥΥܥ2(ܥ)򲡤ޤޥɥåƤǤޤ뿧ܥ1(ܥ)ǥ֥륯åȥץꥱΤοˤʤޤ" } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $colors_demo $colors_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'colors'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame colors_lbox = nil TkFrame.new(base_frame, 'borderwidth'=>10) {|w| s = TkScrollbar.new(w) colors_lbox = TkListbox.new(w) { setgrid 1 width 10 height 12 yscrollcommand proc{|first,last| s.set first,last} } s.command(proc{|*args| colors_lbox.yview(*args)}) s.pack('side'=>'right', 'fill'=>'y') colors_lbox.pack('side'=>'left', 'expand'=>1, 'fill'=>'both') }.pack('side'=>'top', 'expand'=>'yes', 'fill'=>'y') #colors_lbox.bind('Double-1', proc{TkPalette.setPalette TkSelection.get}) colors_lbox.bind('Double-1', proc{ begin TkPalette.setPalette TkSelection.get rescue => e p e Tk.tk_call_without_enc('destroy', '.___tk_set_palette') end }) ins_data = [ 'gray60','gray70','gray80','gray85','gray90','gray95', 'snow1','snow2','snow3','snow4','seashell1','seashell2', 'seashell3','seashell4','AntiqueWhite1','AntiqueWhite2', 'AntiqueWhite3','AntiqueWhite4','bisque1','bisque2', 'bisque3','bisque4','PeachPuff1','PeachPuff2', 'PeachPuff3','PeachPuff4','NavajoWhite1','NavajoWhite2', 'NavajoWhite3','NavajoWhite4','LemonChiffon1', 'LemonChiffon2','LemonChiffon3','LemonChiffon4', 'cornsilk1','cornsilk2','cornsilk3','cornsilk4', 'ivory1','ivory2','ivory3','ivory4','honeydew1', 'honeydew2','honeydew3','honeydew4','LavenderBlush1', 'LavenderBlush2','LavenderBlush3','LavenderBlush4', 'MistyRose1','MistyRose2','MistyRose3','MistyRose4', 'azure1','azure2','azure3','azure4','SlateBlue1', 'SlateBlue2','SlateBlue3','SlateBlue4','RoyalBlue1', 'RoyalBlue2','RoyalBlue3','RoyalBlue4','blue1','blue2', 'blue3','blue4','DodgerBlue1','DodgerBlue2', 'DodgerBlue3','DodgerBlue4','SteelBlue1','SteelBlue2', 'SteelBlue3','SteelBlue4','DeepSkyBlue1','DeepSkyBlue2', 'DeepSkyBlue3','DeepSkyBlue4','SkyBlue1','SkyBlue2', 'SkyBlue3','SkyBlue4','LightSkyBlue1','LightSkyBlue2', 'LightSkyBlue3','LightSkyBlue4','SlateGray1', 'SlateGray2','SlateGray3','SlateGray4', 'LightSteelBlue1','LightSteelBlue2','LightSteelBlue3', 'LightSteelBlue4','LightBlue1','LightBlue2', 'LightBlue3','LightBlue4','LightCyan1','LightCyan2', 'LightCyan3','LightCyan4','PaleTurquoise1', 'PaleTurquoise2','PaleTurquoise3','PaleTurquoise4', 'CadetBlue1','CadetBlue2','CadetBlue3','CadetBlue4', 'turquoise1','turquoise2','turquoise3','turquoise4', 'cyan1','cyan2','cyan3','cyan4','DarkSlateGray1', 'DarkSlateGray2','DarkSlateGray3','DarkSlateGray4', 'aquamarine1','aquamarine2','aquamarine3','aquamarine4', 'DarkSeaGreen1','DarkSeaGreen2','DarkSeaGreen3', 'DarkSeaGreen4','SeaGreen1','SeaGreen2','SeaGreen3', 'SeaGreen4','PaleGreen1','PaleGreen2','PaleGreen3', 'PaleGreen4','SpringGreen1','SpringGreen2', 'SpringGreen3','SpringGreen4','green1','green2', 'green3','green4','chartreuse1','chartreuse2', 'chartreuse3','chartreuse4','OliveDrab1','OliveDrab2', 'OliveDrab3','OliveDrab4','DarkOliveGreen1', 'DarkOliveGreen2','DarkOliveGreen3','DarkOliveGreen4', 'khaki1','khaki2','khaki3','khaki4','LightGoldenrod1', 'LightGoldenrod2','LightGoldenrod3','LightGoldenrod4', 'LightYellow1','LightYellow2','LightYellow3', 'LightYellow4','yellow1','yellow2','yellow3','yellow4', 'gold1','gold2','gold3','gold4','goldenrod1', 'goldenrod2','goldenrod3','goldenrod4','DarkGoldenrod1', 'DarkGoldenrod2','DarkGoldenrod3','DarkGoldenrod4', 'RosyBrown1','RosyBrown2','RosyBrown3','RosyBrown4', 'IndianRed1','IndianRed2','IndianRed3','IndianRed4', 'sienna1','sienna2','sienna3','sienna4','burlywood1', 'burlywood2','burlywood3','burlywood4','wheat1', 'wheat2','wheat3','wheat4','tan1','tan2','tan3','tan4', 'chocolate1','chocolate2','chocolate3','chocolate4', 'firebrick1','firebrick2','firebrick3','firebrick4', 'brown1','brown2','brown3','brown4','salmon1','salmon2', 'salmon3','salmon4','LightSalmon1','LightSalmon2', 'LightSalmon3','LightSalmon4','orange1','orange2', 'orange3','orange4','DarkOrange1','DarkOrange2', 'DarkOrange3','DarkOrange4','coral1','coral2','coral3', 'coral4','tomato1','tomato2','tomato3','tomato4', 'OrangeRed1','OrangeRed2','OrangeRed3','OrangeRed4', 'red1','red2','red3','red4','DeepPink1','DeepPink2', 'DeepPink3','DeepPink4','HotPink1','HotPink2', 'HotPink3','HotPink4','pink1','pink2','pink3','pink4', 'LightPink1','LightPink2','LightPink3','LightPink4', 'PaleVioletRed1','PaleVioletRed2','PaleVioletRed3', 'PaleVioletRed4','maroon1','maroon2','maroon3', 'maroon4','VioletRed1','VioletRed2','VioletRed3', 'VioletRed4','magenta1','magenta2','magenta3', 'magenta4','orchid1','orchid2','orchid3','orchid4', 'plum1','plum2','plum3','plum4','MediumOrchid1', 'MediumOrchid2','MediumOrchid3','MediumOrchid4', 'DarkOrchid1','DarkOrchid2','DarkOrchid3', 'DarkOrchid4','purple1','purple2','purple3','purple4', 'MediumPurple1','MediumPurple2','MediumPurple3', 'MediumPurple4','thistle1','thistle2','thistle3', 'thistle4' ] colors_lbox.insert(0, *ins_data) ================================================ FILE: ext/tk/sample/demos-jp/combo.rb ================================================ # -*- coding: euc-jp -*- # # combo.rb -- # # This demonstration script creates several combobox widgets. # # based on "Id: combo.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp" if defined?($combo_demo) && $combo_demo $combo_demo.destroy $combo_demo = nil end $combo_demo = TkToplevel.new {|w| title("Combobox Demonstration") iconname("combo") positionWindow(w) } base_frame = TkFrame.new($combo_demo).pack(:fill=>:both, :expand=>true) Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'5i', :justify=>:left, :text=><:top, :fill=>:x) ʲǤ3ΥܥܥåɽƤޤ\ ǽΤΤϡȥꥦåȤƱͤˡ\ ݥȤꡤåꡤפꤹ뤳ȤǤޤ\ ޤReturnϤиߤͤꥹȤɲä졤\ ɥåץꥹȤ򤹤뤳ȤǤ褦ˤʤޤ\ ()򲡤ɽ줿ꥹȤ\ ¾θReturn򲡤СͤǤޤ\ 2ܤΥܥܥåͤ˸ꤵƤꡤѹǤޤ\ 3ܤΤΤϥȥꥢԻԤΥɥåץꥹȤ\ 򤹤뤳ȤǽȤʤäƤޤ EOL ## variables firstValue = TkVariable.new secondValue = TkVariable.new ozCity = TkVariable.new ## See Code / Dismiss buttons Ttk::Frame.new(base_frame) {|frame| sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'ѿ', :image=>$image['view'], :compound=>:left, :command=>proc{ showVars(base_frame, ['firstVariable', firstValue], ['secondVariable', secondValue], ['ozCity', ozCity]) }), Ttk::Button.new(frame, :text=>'ɻ', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'combo'}), Ttk::Button.new(frame, :text=>'Ĥ', :image=>$image['delete'], :compound=>:left, :command=>proc{ $combo_demo.destroy $combo_demo = nil }), :padx=>4, :pady=>4) grid_columnconfigure(0, :weight=>1) pack(:side=>:bottom, :fill=>:x) } frame = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true) australianCities = [ '٥', 'ɥˡ', 'ܥ', 'ѡ', 'ǥ졼', '֥ꥹ١', 'ۥС', '', 'ꥹ ץ󥰥' ] secondValue.value = 'ѹԲ' ozCity.value = 'ɥˡ' Tk.pack(Ttk::Labelframe.new(frame, :text=>'Fully Editable'){|f| Ttk::Combobox.new(f, :textvariable=>firstValue){|b| b.bind('Return', '%W'){|w| w.values <<= w.value unless w.values.include?(w.value) } }.pack(:pady=>5, :padx=>10) }, Ttk::LabelFrame.new(frame, :text=>'Disabled'){|f| Ttk::Combobox.new(f, :textvariable=>secondValue, :state=>:disabled) . pack(:pady=>5, :padx=>10) }, Ttk::LabelFrame.new(frame, :text=>'Defined List Only'){|f| Ttk::Combobox.new(f, :textvariable=>ozCity, :state=>:readonly, :values=>australianCities) . pack(:pady=>5, :padx=>10) }, :side=>:top, :pady=>5, :padx=>10) ================================================ FILE: ext/tk/sample/demos-jp/cscroll.rb ================================================ # -*- coding: euc-jp -*- # # simple scrollable canvas widget demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($cscroll_demo) && $cscroll_demo $cscroll_demo.destroy $cscroll_demo = nil end # demo Ѥ toplevel widget $cscroll_demo = TkToplevel.new {|w| title("Scrollable Canvas Demonstration") iconname("cscroll") positionWindow(w) } base_frame = TkFrame.new($cscroll_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'4i', 'justify'=>'left', 'text'=>"ΥɥˤϥСޥΥܥ2 ǥǤ륭Х widget ɽƤޤͳѤξǥܥ1 򥯥åȡΥǥåɸϤ˽Ϥޤ"){ pack('side'=>'top') } # frame $cscroll_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $cscroll_demo $cscroll_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'cscroll'} }.pack('side'=>'left', 'expand'=>'yes') } $cscroll_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame unless $tk_version =~ /^4\.[01]/ $cscroll_grid = TkFrame.new(base_frame) { pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1) } TkGrid.rowconfigure($cscroll_grid, 0, 'weight'=>1, 'minsize'=>0) TkGrid.columnconfigure($cscroll_grid, 0, 'weight'=>1, 'minsize'=>0) end # canvas $cscroll_canvas = TkCanvas.new(base_frame, 'relief'=>'sunken', 'borderwidth'=>2, 'scrollregion'=>['-11c', '-11c', '50c', '20c'] ) {|c| if $tk_version =~ /^4\.[01]/ pack('expand'=>'yes', 'fill'=>'both') else grid('in'=>$cscroll_grid, 'padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') end TkScrollbar.new(base_frame, 'command'=>proc{|*args| c.yview(*args)}) {|vs| c.yscrollcommand(proc{|first,last| vs.set first,last}) if $tk_version =~ /^4\.[01]/ pack('side'=>'right', 'fill'=>'y') else grid('in'=>$cscroll_grid, 'padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>1, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') end } TkScrollbar.new(base_frame, 'orient'=>'horiz', 'command'=>proc{|*args| c.xview(*args)}) {|hs| c.xscrollcommand(proc{|first,last| hs.set first,last}) if $tk_version =~ /^4\.[01]/ pack('side'=>'bottom', 'fill'=>'x') else grid('in'=>$cscroll_grid, 'padx'=>1, 'pady'=>1, 'row'=>1, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') end } } bg = $cscroll_canvas.configinfo('bg')[4] (0..19).each{|i| x = -10+3*i y = -10 (0..9).each{|j| TkcRectangle.new($cscroll_canvas, "#{x}c", "#{y}c", "#{x+2}c", "#{y+2}c", 'outline'=>'black', 'fill'=>bg, 'tags'=>'rect') TkcText.new($cscroll_canvas, "#{x+1}c", "#{y+1}c", 'text'=>"#{i},#{j}", 'anchor'=>'center', 'tags'=>'text') y += 3 } } $cscroll_canvas.itembind('all', 'Any-Enter', proc{scrollEnter $cscroll_canvas}) $cscroll_canvas.itembind('all', 'Any-Leave', proc{scrollLeave $cscroll_canvas}) $cscroll_canvas.itembind('all', '1', proc{scrollButton $cscroll_canvas}) $cscroll_canvas.itembind('all', 'Any-Enter', proc{scrollEnter $cscroll_canvas}) $cscroll_canvas.bind('2', proc{|x,y| $cscroll_canvas.scan_mark(x,y)}, '%x %y') $cscroll_canvas.bind('B2-Motion', proc{|x,y| $cscroll_canvas.scan_dragto(x,y)}, '%x %y') def scrollEnter(c) id = c.find_withtag('current')[0].id id -= 1 if c.gettags('current').include?('text') $oldFill = c.itemconfiginfo(id, 'fill')[4] if TkWinfo.depth(c) > 1 c.itemconfigure(id, 'fill'=>'SeaGreen1') else c.itemconfigure(id, 'fill'=>'black') c.itemconfigure(id+1, 'fill'=>'white') end end def scrollLeave(c) id = c.find_withtag('current')[0].id id -= 1 if c.gettags('current').include?('text') c.itemconfigure(id, 'fill'=>$oldFill) c.itemconfigure(id+1, 'fill'=>'black') end def scrollButton(c) id = c.find_withtag('current')[0].id id += 1 unless c.gettags('current').include?('text') print "You buttoned at #{c.itemconfiginfo(id,'text')[4]}\n" end ================================================ FILE: ext/tk/sample/demos-jp/ctext.rb ================================================ # -*- coding: euc-jp -*- # # Canvas Text widget demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($ctext_demo) && $ctext_demo $ctext_demo.destroy $ctext_demo = nil end # demo Ѥ toplevel widget $ctext_demo = TkToplevel.new {|w| title("Canvas Text Demonstration") iconname("Text") positionWindow(w) } base_frame = TkFrame.new($ctext_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left', 'text'=>"ΥɥˤϥХwidgetΥƥȵǽǥ⤹뤿ΥƥʸɽƤޤޥͳѤ˻äƤåȰ֤Ѥа֤Ѥꡢ·Ѥꤹ뤳ȤǤޤޤʲΤ褦ԽΤδñʥХǥ󥰤򥵥ݡȤƤޤ 1. ޥäƤåϤǤޤ 2. ܥ1Ǥޤ 3. ޥΰ֤˥ܥ2򤷤ƥȤ򥳥ԡǤޤ 4.Хåڡ򥳥ȥ-Hľʸޤ 5. Deleteľʸޤ"){ pack('side'=>'top') } # frame $ctext_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $ctext_demo $ctext_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'ctext'} }.pack('side'=>'left', 'expand'=>'yes') } $ctext_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # canvas $ctext_canvas = TkCanvas.new(base_frame, 'relief'=>'flat', 'borderwidth'=>0, 'width'=>500, 'height'=>350) $ctext_canvas.pack('side'=>'top', 'expand'=>'yes', 'fill'=>'both') # font if $tk_version =~ /^4.*/ textFont = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*' else textFont = 'Helvetica 24' end # canvas TkcRectangle.new($ctext_canvas, 245, 195, 255, 205, 'outline'=>'black', 'fill'=>'red') ctag_text_param = { 'text'=>"ϥХwidgetΥƥȵǽǥ⤹뤿ʸǤ\nǽҤ٤褦ԽǽȤ뤿ΥХǥ󥰤ܤƤޤ", 'width'=>440, 'anchor'=>'n', 'justify'=>'left' } if $tk_version =~ /^4.*/ ctag_text_param['font'] = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*' ctag_text_param['kanjifont'] = '-*-r-*--24-*-jisx0208.1983-0' else ctag_text_param['font'] = 'Helvetica 24' end $ctag_text = TkcTag.new($ctext_canvas) $ctag_text.withtag(TkcText.new($ctext_canvas, 250, 200, ctag_text_param)) $ctag_text.bind('1', proc{|x,y| textB1Press $ctext_canvas,x,y}, "%x %y") $ctag_text.bind('B1-Motion', proc{|x,y| textB1Move $ctext_canvas,x,y}, "%x %y") $ctag_text.bind('Shift-1', proc{|x,y| $ctext_canvas.seleect_adjust 'current', "@#{x},#{y}"}, "%x %y") $ctag_text.bind('Shift-B1-Motion', proc{|x,y| textB1Move $ctext_canvas,x,y}, "%x %y") $ctag_text.bind('KeyPress', proc{|a| textInsert $ctext_canvas,a}, "%A") $ctag_text.bind('Return', proc{textInsert $ctext_canvas,"\n"}) $ctag_text.bind('Control-h', proc{textBs $ctext_canvas}) $ctag_text.bind('BackSpace', proc{textBs $ctext_canvas}) $ctag_text.bind('Delete', proc{textDel $ctext_canvas}) $ctag_text.bind('2', proc{|x,y| textPaste $ctext_canvas, "@#{x},#{y}"}, "%x %y") # Next, create some items that allow the text's anchor position # to be edited. def mkTextConfig(w,x,y,option,value,color) item = TkcRectangle.new(w, x, y, x+30, y+30, 'outline'=>'black', 'fill'=>color, 'width'=>1) item.bind('1', proc{$ctag_text.configure option, value}) w.addtag_withtag('config', item) end x = 50 y = 50 color = 'LightSkyBlue1' mkTextConfig $ctext_canvas, x, y, 'anchor', 'se', color mkTextConfig $ctext_canvas, x+30, y, 'anchor', 's', color mkTextConfig $ctext_canvas, x+60, y, 'anchor', 'sw', color mkTextConfig $ctext_canvas, x, y+30, 'anchor', 'e', color mkTextConfig $ctext_canvas, x+30, y+30, 'anchor', 'center', color mkTextConfig $ctext_canvas, x+60, y+30, 'anchor', 'w', color mkTextConfig $ctext_canvas, x, y+60, 'anchor', 'ne', color mkTextConfig $ctext_canvas, x+30, y+60, 'anchor', 'n', color mkTextConfig $ctext_canvas, x+60, y+60, 'anchor', 'nw', color item = TkcRectangle.new($ctext_canvas, x+40, y+40, x+50, y+50, 'outline'=>'black', 'fill'=>'red') item.bind('1', proc{$ctag_text.configure 'anchor', 'center'}) if $tk_version =~ /^4.*/ TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position', 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', 'anchor'=>'s', 'fill'=>'brown') else TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position', 'font'=>'Times 24', 'anchor'=>'s', 'fill'=>'brown') end # Lastly, create some items that allow the text's justification to be # changed. x = 350 y = 50 color = 'SeaGreen2' mkTextConfig $ctext_canvas, x, y, 'justify', 'left', color mkTextConfig $ctext_canvas, x+30, y, 'justify', 'center', color mkTextConfig $ctext_canvas, x+60, y, 'justify', 'right', color if $tk_version =~ /^4.*/ TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification', 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', 'anchor'=>'s', 'fill'=>'brown') else TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification', 'font'=>'Times 24', 'anchor'=>'s', 'fill'=>'brown') end $ctext_canvas.itembind('config', 'Enter', proc{textEnter $ctext_canvas}) $ctext_canvas.itembind('config', 'Leave', proc{$ctext_canvas\ .itemconfigure('current', 'fill'=>$textConfigFill)}) $textConfigFill = '' def textEnter(w) $textConfigFill = (w.itemconfiginfo 'current', 'fill')[4] w.itemconfigure 'current', 'fill', 'black' end def textInsert(w, string) return if string == "" begin $ctag_text.dchars 'sel.first', 'sel.last' rescue end $ctag_text.insert 'insert', string end def textPaste(w, pos) begin $ctag_text.insert pos, TkSelection.get rescue end end def textB1Press(w,x,y) w.icursor 'current', "@#{x},#{y}" w.itemfocus 'current' w.focus w.select_from 'current', "@#{x},#{y}" end def textB1Move(w,x,y) w.select_to 'current', "@#{x},#{y}" end def textBs(w) begin $ctag_text.dchars 'sel.first', 'sel.last' rescue char = $ctag_text.index('insert').to_i - 1 $ctag_text.dchars(char) if char >= 0 end end def textDel(w) begin $ctag_text.dchars 'sel.first', 'sel.last' rescue $ctag_text.dchars 'insert' end end ================================================ FILE: ext/tk/sample/demos-jp/dialog1.rb ================================================ # -*- coding: euc-jp -*- # # a dialog box with a local grab (called by 'widget') # class TkDialog_Demo1 < TkDialog ############### private ############### def title "Dialog with local grab" end def message '⡼ܥåǤTk "grab" ޥɤѤƥܥåǡ֥륰֡פƤޤΤ줫Υܥ¹Ԥ뤳ȤˤäơΥޤǡΥ֤ˤäƥץꥱ¾ΥɥǤϡݥ󥿴طΥ٥Ȥ뤳ȤǤʤʤäƤޤ' end def bitmap 'info' end def default_button 0 end def buttons # "λ 󥻥 ɻ" ["λ", "󥻥", "ɻ"] end end ret = TkDialog_Demo1.new('message_config'=>{'wraplength'=>'4i'}).value case ret when 0 print "ʤϡλפ򲡤ޤ͡\n" when 1 print "ʤϡ֥󥻥פ򲡤ޤ͡\n" when 2 showCode 'dialog1' end ================================================ FILE: ext/tk/sample/demos-jp/dialog2.rb ================================================ # -*- coding: euc-jp -*- # # a dialog box with a global grab (called by 'widget') # class TkDialog_Demo2 < TkDialog ############### private ############### def title "Dialog with global grab" end def message 'ΥܥåϥХ륰֤ѤƤޤΥܥ¹Ԥޤǡǥץ쥤ΤʤΤȤäǤޤ󡣥Х륰֤Ѥ뤳ȤϡޤɤͤǤϤޤ󡣤ɤƤɬפˤʤޤǻȤȻפʤDz' end def bitmap 'info' end def default_button 0 end def buttons # "λ 󥻥 ɻ" ["λ", "󥻥", "ɻ"] end end ret = TkDialog_Demo2.new('message_config'=>{'wraplength'=>'4i'}, 'prev_command'=>proc{|dialog| Tk.after 100, proc{dialog.grab('global')} }).value case ret when 0 print "ʤϡλפ򲡤ޤ͡\n" when 1 print "ʤϡ֥󥻥פ򲡤ޤ͡\n" when 2 showCode 'dialog2' end ================================================ FILE: ext/tk/sample/demos-jp/doc.org/README ================================================ This directory contains a collection of demonstration programs that are translated into Japanese. You need to use a Japanized "wish" to see these Japanese-translated demonstration programs. You also need to put this directory ("demos.jp") at the next to "demos" since some of the programs refer to the image files at "demos". Please refer to the README file at "demos" for more detail. ================================================ FILE: ext/tk/sample/demos-jp/doc.org/README.JP ================================================ This directory contains "widget" demo for the Japanized Tcl7.6/Tk4.2. Most of the messages in the original are translated to Japanese. But other tools in this directory are not translated. Following 2 kanji fonts are defined at the beginning of the file "widget." -*--24-*-jisx0208.1983-0 -*--16-*-jisx0208.1983-0 These fonts are all part of the core distribution of X11R5, so if you are running X11R5, you don't have to modify the file. But if you don't have these fonts, replace them with appropriate ones. "-*--14-*-jisx0208.1983-0" will be a good choice. ================================================ FILE: ext/tk/sample/demos-jp/doc.org/README.tk80 ================================================ This directory contains a collection of programs to demonstrate the features of the Tk toolkit. The programs are all scripts for "wish", a windowing shell. If wish has been installed in /usr/local then you can invoke any of the programs in this directory just by typing its file name to your command shell. Otherwise invoke wish with the file as its first argument, e.g., "wish hello". The rest of this file contains a brief description of each program. Files with names ending in ".tcl" are procedure packages used by one or more of the demo programs; they can't be used as programs by themselves so they aren't described below. hello - Creates a single button; if you click on it, a message is typed and the application terminates. widget - Contains a collection of demonstrations of the widgets currently available in the Tk library. Most of the .tcl files are scripts for individual demos available through the "widget" program. ixset - A simple Tk-based wrapper for the "xset" program, which allows you to interactively query and set various X options such as mouse acceleration and bell volume. Thanks to Pierre David for contributing this example. rolodex - A mock-up of a simple rolodex application. It has much of the user interface for such an application but no back-end database. This program was written in response to Tom LaStrange's toolkit benchmark challenge. tcolor - A color editor. Allows you to edit colors in several different ways, and will also perform automatic updates using "send". rmt - Allows you to "hook-up" remotely to any Tk application on the display. Select an application with the menu, then just type commands: they'll go to that application. timer - Displays a seconds timer with start and stop buttons. Control-c and control-q cause it to exit. browse - A simple directory browser. Invoke it with and argument giving the name of the directory you'd like to browse. Double-click on files or subdirectories to browse them. Control-c and control-q cause the program to exit. sccs id = SCCS: @(#) README 1.3 96/02/16 10:49:14 ================================================ FILE: ext/tk/sample/demos-jp/doc.org/license.terms ================================================ This software is copyrighted by the Regents of the University of California, Sun Microsystems, Inc., and other parties. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. ================================================ FILE: ext/tk/sample/demos-jp/doc.org/license.terms.tk80 ================================================ This software is copyrighted by the Regents of the University of California, Sun Microsystems, Inc., and other parties. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. ================================================ FILE: ext/tk/sample/demos-jp/entry1.rb ================================================ # -*- coding: euc-jp -*- # # entry (no scrollbars) widget demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($entry1_demo) && $entry1_demo $entry1_demo.destroy $entry1_demo = nil end # demo Ѥ toplevel widget $entry1_demo = TkToplevel.new {|w| title("Entry Demonstration (no scrollbars)") iconname("entry1") positionWindow(w) } base_frame = TkFrame.new($entry1_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '5i' justify 'left' text "3ΰۤʤ륨ȥ꤬ɽƤޤʸϤˤϥݥ󥿤äƹԤåƤ饿פƤɸŪMotifԽǽEmacsΥХɤȤȤˡݡȤƤޤ㤨СХåڡȥȥ-Hϥκʸǥ꡼ȥȥȥ-Dϥα¦ʸޤĹ᤮ƥɥڤʤΤϡޥΥܥ2򲡤ޤޥɥå뤳Ȥǥ뤵뤳ȤǤޤܸϤΤϥȥ-ХååǤkinput2ưƤϤ뤳ȤǤޤ" } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $entry1_demo $entry1_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'entry1'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # entry e1 = TkEntry.new(base_frame, 'relief'=>'sunken') e2 = TkEntry.new(base_frame, 'relief'=>'sunken') e3 = TkEntry.new(base_frame, 'relief'=>'sunken') [e1,e2,e3].each{|w| w.pack('side'=>'top', 'padx'=>10, 'pady'=>5, 'fill'=>'x')} # e1.insert(0, '') e2.insert('end', "ΥȥˤĹʸäƤơ") e2.insert('end', "ĹƥɥˤڤʤΤǡ") e2.insert('end', "ºݤν꽪ޤǸˤϥ뤵ʤ") e2.insert('end', "ʤʤǤ礦") ================================================ FILE: ext/tk/sample/demos-jp/entry2.rb ================================================ # -*- coding: euc-jp -*- # # entry (with scrollbars) widget demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($entry2_demo) && $entry2_demo $entry2_demo.destroy $entry2_demo = nil end # demo Ѥ toplevel widget $entry2_demo = TkToplevel.new {|w| title("Entry Demonstration (with scrollbars)") iconname("entry2") positionWindow(w) } base_frame = TkFrame.new($entry2_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '5i' justify 'left' text "3ΰۤʤ륨ȥ꤬ơСդɽƤޤʸϤˤϥݥ󥿤äƹԤåƤ饿פƤɸŪMotifԽǽEmacsΥХɤȤȤˡݡȤƤޤ㤨СХåڡȥȥ-Hϥκʸǥ꡼ȥȥȥ-Dϥα¦ʸޤĹ᤮ƥɥڤʤΤϡޥΥܥ2򲡤ޤޥɥå뤳Ȥǥ뤵뤳ȤǤޤܸϤΤϥȥ-ХååǤkinput2ưƤϤ뤳ȤǤޤ" } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $entry2_demo $entry2_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'entry2'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame TkFrame.new(base_frame, 'borderwidth'=>10) {|w| # entry 1 s1 = TkScrollbar.new(w, 'relief'=>'sunken', 'orient'=>'horiz') e1 = TkEntry.new(w, 'relief'=>'sunken') { xscrollcommand proc{|first,last| s1.set first,last} } s1.command(proc{|*args| e1.xview(*args)}) e1.pack('side'=>'top', 'fill'=>'x') s1.pack('side'=>'top', 'fill'=>'x') # spacer TkFrame.new(w, 'width'=>20, 'height'=>10).pack('side'=>'top', 'fill'=>'x') # entry 2 s2 = TkScrollbar.new(w, 'relief'=>'sunken', 'orient'=>'horiz') e2 = TkEntry.new(w, 'relief'=>'sunken') { xscrollcommand proc{|first,last| s2.set first,last} } s2.command(proc{|*args| e2.xview(*args)}) e2.pack('side'=>'top', 'fill'=>'x') s2.pack('side'=>'top', 'fill'=>'x') # spacer TkFrame.new(w, 'width'=>20, 'height'=>10).pack('side'=>'top', 'fill'=>'x') # entry 3 s3 = TkScrollbar.new(w, 'relief'=>'sunken', 'orient'=>'horiz') e3 = TkEntry.new(w, 'relief'=>'sunken') { xscrollcommand proc{|first,last| s3.set first,last} } s3.command(proc{|*args| e3.xview(*args)}) e3.pack('side'=>'top', 'fill'=>'x') s3.pack('side'=>'top', 'fill'=>'x') # e1.insert(0, '') e2.insert('end', "ΥȥˤĹʸäƤơ") e2.insert('end', "ĹƥɥˤڤʤΤǡ") e2.insert('end', "ºݤν꽪ޤǸˤϥ뤵ʤ") e2.insert('end', "ʤʤǤ礦") }.pack('side'=>'top', 'fill'=>'x', 'expand'=>'yes') ================================================ FILE: ext/tk/sample/demos-jp/entry3.rb ================================================ # -*- coding: euc-jp -*- # entry3.rb -- # # This demonstration script creates several entry widgets whose # permitted input is constrained in some way. It also shows off a # password entry. # # based on Tcl/Tk8.4.4 widget demos if defined?($entry3_demo) && $entry3_demo $entry3_demo.destroy $entry3_demo = nil end $entry3_demo = TkToplevel.new {|w| title("Constrained Entry Demonstration") iconname("entry3") positionWindow(w) } base_frame = TkFrame.new($entry3_demo).pack(:fill=>:both, :expand=>true) TkLabel.new(base_frame, :font=>$font, :wraplength=>'5i', :justify=>:left, :text=><:top) ʲˤϣΥȥܥåɽƤޤƥȥܥåϡ\ ޥåʸǤळȤǽǤ줾줬ɤΤ褦\ Ϥդ뤳ȤǤ뤫ˤߤƤޤ\ ĤΥȥܥåȸʤʸʸʤξ֤\ ξդ꤬ϥȥܥåǤޤ\ ʥե˥åޤˡ\ ĤΥȥܥåϡϤ줿ʸĹ\ ʸ̤ξդ¤ۤƽ񤭹⤦ȤȤˤ\ ٥Ĥ餷Τ餻ޤ\ Ĥƹֹդ륨ȥܥåǤ\ ե٥åȤϡõΥбŤƤѴޤ\ ŬڤʸϤ줿ʳʸΰ֤˿Ϥ褦Ȥ\ ˤϷٹΥ٥뤬Ĥޤ\ ͤĤΥȥܥåϡʸޤǤϤդ\ ѥɥեɤǤʣʸʾä˷ٹФȤʤ̵뤵ޤˡ\ Ϥ줿ʸϥꥹ֤ɽޤ EOL TkFrame.new(base_frame){|f| pack(:side=>:bottom, :fill=>:x, :pady=>'2m') TkButton.new(f, :text=>'Ĥ', :width=>15, :command=>proc{ $entry3_demo.destroy $entry3_demo = nil }).pack(:side=>:left, :expand=>true) TkButton.new(f, :text=>'ɻ', :width=>15, :command=>proc{ showCode 'entry3' }).pack(:side=>:left, :expand=>true) } # focusAndFlash -- # Error handler for entry widgets that forces the focus onto the # widget and makes the widget flash by exchanging the foreground and # background colours at intervals of 200ms (i.e. at approximately # 2.5Hz). # # Arguments: # widget - entry widget to flash # fg - Initial foreground colour # bg - Initial background colour # count - Counter to control the number of times flashed def focusAndFlash(widget, fg, bg, count=5) return if count <= 0 if fg && !fg.empty? && bg && !bg.empty? TkTimer.new(200, count, proc{widget.configure(:foreground=>bg, :background=>fg)}, proc{widget.configure(:foreground=>fg, :background=>bg)} ).start else # TkTimer.new(150, 3){Tk.bell}.start Tk.bell TkTimer.new(200, count, proc{widget.configure(:foreground=>'white', :background=>'black')}, proc{widget.configure(:foreground=>'black', :background=>'white')} ).at_end{begin widget.configure(:foreground=>fg, :background=>bg) rescue # ignore end}.start end widget.focus(true) end l1 = TkLabelFrame.new(base_frame, :text=>"ȥ") TkEntry.new(l1, :validate=>:focus, :vcmd=>[ proc{|s| s == '' || /^[+-]?\d+$/ =~ s }, '%P' ]) {|e| fg = e.foreground bg = e.background invalidcommand [proc{|w| focusAndFlash(w, fg, bg)}, '%W'] pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m') } l2 = TkLabelFrame.new(base_frame, :text=>"Ĺդȥ") TkEntry.new(l2, :validate=>:key, :invcmd=>proc{Tk.bell}, :vcmd=>[proc{|s| s.length < 10}, '%P'] ).pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m') ### PHONE NUMBER ENTRY ### # Note that the source to this is quite a bit longer as the behaviour # demonstrated is a lot more ambitious than with the others. # Initial content for the third entry widget entry3content = TkVariable.new("1-(000)-000-0000") # Mapping from alphabetic characters to numbers. $phoneNumberMap = {} Hash[*(%w(abc 2 def 3 ghi 4 jkl 5 mno 6 pqrs 7 tuv 8 wxyz 9))].each{|chars, n| chars.split('').each{|c| $phoneNumberMap[c] = n $phoneNumberMap[c.upcase] = n } } # phoneSkipLeft -- # Skip over fixed characters in a phone-number string when moving left. # # Arguments: # widget - The entry widget containing the phone-number. def phoneSkipLeft(widget) idx = widget.index('insert') if idx == 8 # Skip back two extra characters widget.cursor = idx - 2 elsif idx == 7 || idx == 12 # Skip back one extra character widget.cursor = idx - 1 elsif idx <= 3 # Can't move any further Tk.bell Tk.callback_break end end # phoneSkipRight -- # Skip over fixed characters in a phone-number string when moving right. # # Arguments: # widget - The entry widget containing the phone-number. # add - Offset to add to index before calculation (used by validation.) def phoneSkipRight(widget, add = 0) idx = widget.index('insert') if (idx + add == 5) # Skip forward two extra characters widget.cursor = idx + 2 elsif (idx + add == 6 || idx + add == 10) # Skip forward one extra character widget.cursor = idx + 1 elsif (idx + add == 15 && add == 0) # Can't move any further Tk.bell Tk.callback_break end end # validatePhoneChange -- # Checks that the replacement (mapped to a digit) of the given # character in an entry widget at the given position will leave a # valid phone number in the widget. # # widget - entry widget to validate # vmode - The widget's validation mode # idx - The index where replacement is to occur # char - The character (or string, though that will always be # refused) to be overwritten at that point. def validatePhoneChange(widget, vmode, idx, char) return true if idx == nil Tk.after_idle(proc{widget.configure(:validate=>vmode, :invcmd=>proc{Tk.bell})}) if !(idx<3 || idx==6 || idx==7 || idx==11 || idx>15) && char =~ /[0-9A-Za-z]/ widget.delete(idx) widget.insert(idx, $phoneNumberMap[char] || char) Tk.after_idle(proc{phoneSkipRight(widget, -1)}) # Tk.update(true) # <- Don't work 'update' inter validation callback. # It depends on Tcl/Tk side (tested on Tcl/Tk8.5a1). return true end return false end l3 = TkLabelFrame.new(base_frame, :text=>"ƹֹ楨ȥ") TkEntry.new(l3, :validate=>:key, :invcmd=>proc{Tk.bell}, :textvariable=>entry3content, :vcmd=>[ proc{|w,v,i,s| validatePhoneChange(w,v,i,s)}, "%W %v %i %S" ]){|e| # Click to focus goes to the first editable character... bind('FocusIn', proc{|d,w| if d != "NotifyAncestor" w.cursor = 3 Tk.after_idle(proc{w.selection_clear}) end }, '%d %W') bind('Left', proc{|w| phoneSkipLeft(w)}, '%W') bind('Right', proc{|w| phoneSkipRight(w)}, '%W') pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m') } l4 = TkLabelFrame.new(base_frame, :text=>"ѥɥȥ") TkEntry.new(l4, :validate=>:key, :show=>'*', :vcmd=>[ proc{|s| s.length <= 8}, '%P' ]).pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m') TkFrame.new(base_frame){|f| lower TkGrid.configure(l1, l2, :in=>f, :padx=>'3m', :pady=>'1m', :sticky=>:ew) TkGrid.configure(l3, l4, :in=>f, :padx=>'3m', :pady=>'1m', :sticky=>:ew) TkGrid.columnconfigure(f, [0,1], :uniform=>1) pack(:fill=>:both, :expand=>true) } ================================================ FILE: ext/tk/sample/demos-jp/filebox.rb ================================================ # -*- coding: euc-jp -*- # # widget demo prompts the user to select a file (called by 'widget') # # toplevel widget ¸ߤк if defined?($filebox_demo) && $entry2_demo $filebox_demo.destroy $filebox_demo = nil end # demo Ѥ toplevel widget $filebox_demo = TkToplevel.new {|w| title("File Selection Dialogs") iconname("filebox") positionWindow(w) } base_frame = TkFrame.new($filebox_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left', 'text'=>"ȥ˥ե̾ľϤ뤫\"Browse\" ܥ򲡤ƥեե̾Dz").pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $filebox_demo $filebox_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'filebox'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame ['', '¸'].each{|type| TkFrame.new(base_frame) {|f| TkLabel.new(f, 'text'=>"ե#{type}: ", 'anchor'=>'e')\ .pack('side'=>'left') TkEntry.new(f, 'width'=>20) {|e| pack('side'=>'left', 'expand'=>'yes', 'fill'=>'x') TkButton.new(f, 'text'=>'Browse ...', 'command'=>proc{fileDialog base_frame,e,type})\ .pack('side'=>'left') } pack('fill'=>'x', 'padx'=>'1c', 'pady'=>3) } } $tk_strictMotif = TkVarAccess.new('tk_strictMotif') if ($tk_platform['platform'] == 'unix') TkCheckButton.new(base_frame, 'text'=>'MotifΥѤ', 'variable'=>$tk_strictMotif, 'onvalue'=>1, 'offvalue'=>0 ).pack('anchor'=>'c') end def fileDialog(w,ent,operation) # Type names Extension(s) Mac File Type(s) # #-------------------------------------------------------- types = [ ['Text files', ['.txt','.doc'] ], ['Text files', [], 'TEXT' ], ['Ruby Scripts', ['.rb'], 'TEXT' ], ['Tcl Scripts', ['.tcl'], 'TEXT' ], ['C Source Files', ['.c','.h'] ], ['All Source Files', ['.rb','.tcl','.c','.h'] ], ['Image Files', ['.gif'] ], ['Image Files', ['.jpeg','.jpg'] ], ['Image Files', [], ['GIFF','JPEG']], ['All files', '*' ] ] if operation == '' file = Tk.getOpenFile('filetypes'=>types, 'parent'=>w) else file = Tk.getSaveFile('filetypes'=>types, 'parent'=>w, 'initialfile'=>'Untitled', 'defaultextension'=>'.txt') end if file != "" ent.delete 0, 'end' ent.insert 0, file # ent.xview 'end' Tk.update_idletasks # need this for Tk::Tile::Entry # (to find right position of 'xview'). ent.xview(ent.index('end')) end end ================================================ FILE: ext/tk/sample/demos-jp/floor.rb ================================================ # -*- coding: euc-jp -*- # # floorDisplay widget demo (called by 'widget') # # floorDisplay -- # Recreate the floorplan display in the canvas given by "w". The # floor given by "active" is displayed on top with its office structure # visible. # # Arguments: # w - Name of the canvas window. # active - Number of active floor (1, 2, or 3). def floorDisplay(w,active) return if $activeFloor == active w.delete('all') $activeFloor = active # First go through the three floors, displaying the backgrounds for # each floor. floor_bg1(w,$floor_colors['bg1'],$floor_colors['outline1']) floor_bg2(w,$floor_colors['bg2'],$floor_colors['outline2']) floor_bg3(w,$floor_colors['bg3'],$floor_colors['outline3']) # Raise the background for the active floor so that it's on top. w.raise("floor#{active}") # Create a dummy item just to mark this point in the display list, # so we can insert highlights here. TkcRectangle.new(w,0,100,1,101, 'fill'=>'', 'outline'=>'', 'tags'=>'marker') # Add the walls and labels for the active floor, along with # transparent polygons that define the rooms on the floor. # Make sure that the room polygons are on top. $floorLabels.clear $floorItems.clear send("floor_fg#{active}", w, $floor_colors['offices']) w.raise('room') # Offset the floors diagonally from each other. w.move('floor1', '2c', '2c') w.move('floor2', '1c', '1c') # Create items for the room entry and its label. TkcWindow.new(w, 600, 100, 'anchor'=>'w', 'window'=>$floor_entry) TkcText.new(w, 600, 100, 'anchor'=>'e', 'text'=>"ֹ: ") w['scrollregion'] = w.bbox('all') end # newRoom -- # This method is invoked whenever the mouse enters a room # in the floorplan. It changes tags so that the current room is # highlighted. # # Arguments: # w - The name of the canvas window. def newRoom(w) id = w.find_withtag('current')[0] $currentRoom.value = $floorLabels[id.id] if id != "" Tk.update(true) end # roomChanged -- # This method is invoked whenever the currentRoom variable changes. # It highlights the current room and unhighlights any previous room. # # Arguments: # w - The canvas window displaying the floorplan. # args - Not used. def roomChanged(w,*args) w.delete('highlight') item = $floorItems[$currentRoom.value] return if item == nil new = TkcPolygon.new(w, *(w.coords(item))) new.configure('fill'=>$floor_colors['active'], 'tags'=>'highlight') w.raise(new, 'marker') end # floor_bg1 -- # This method represents part of the floorplan database. When # invoked, it instantiates the background information for the first # floor. # # Arguments: # w - The canvas window. # fill - Fill color to use for the floor's background. # outline - Color to use for the floor's outline. def floor_bg1(w,fill,outline) TkcPolygon.new(w,347,80,349,82,351,84,353,85,363,92,375,99,386,104, 386,129,398,129,398,162,484,162,484,129,559,129,559,133,725, 133,725,129,802,129,802,389,644,389,644,391,559,391,559,327, 508,327,508,311,484,311,484,278,395,278,395,288,400,288,404, 288,409,290,413,292,418,297,421,302,422,309,421,318,417,325, 411,330,405,332,397,333,344,333,340,334,336,336,335,338,332, 342,331,347,332,351,334,354,336,357,341,359,340,360,335,363, 331,365,326,366,304,366,304,355,258,355,258,387,60,387,60,391, 0,391,0,337,3,337,3,114,8,114,8,25,30,25,30,5,93,5,98,5,104,7, 110,10,116,16,119,20,122,28,123,32,123,68,220,68,220,34,221, 22,223,17,227,13,231,8,236,4,242,2,246,0,260,0,283,1,300,5, 321,14,335,22,348,25,365,29,363,39,358,48,352,56,337,70, 344,76,347,80, 'tags'=>['floor1','bg'], 'fill'=>fill) TkcLine.new(w,386,129,398,129, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,258,355,258,387, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,60,387,60,391, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,0,337,0,391, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,60,391,0,391, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,3,114,3,337, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,258,387,60,387, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,484,162,398,162, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,398,162,398,129, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,484,278,484,311, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,484,311,508,311, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,508,327,508,311, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,559,327,508,327, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,644,391,559,391, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,644,389,644,391, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,559,129,484,129, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,484,162,484,129, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,725,133,559,133, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,559,129,559,133, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,725,129,802,129, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,802,389,802,129, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,3,337,0,337, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,559,391,559,327, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,802,389,644,389, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,725,133,725,129, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,8,25,8,114, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,8,114,3,114, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,30,25,8,25, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,484,278,395,278, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,30,25,30,5, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,93,5,30,5, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,98,5,93,5, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,104,7,98,5, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,110,10,104,7, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,116,16,110,10, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,119,20,116,16, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,122,28,119,20, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,123,32,122,28, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,123,68,123,32, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,220,68,123,68, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,386,129,386,104, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,386,104,375,99, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,375,99,363,92, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,353,85,363,92, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,220,68,220,34, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,337,70,352,56, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,352,56,358,48, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,358,48,363,39, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,363,39,365,29, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,365,29,348,25, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,348,25,335,22, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,335,22,321,14, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,321,14,300,5, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,300,5,283,1, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,283,1,260,0, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,260,0,246,0, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,246,0,242,2, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,242,2,236,4, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,236,4,231,8, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,231,8,227,13, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,223,17,227,13, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,221,22,223,17, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,220,34,221,22, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,340,360,335,363, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,335,363,331,365, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,331,365,326,366, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,326,366,304,366, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,304,355,304,366, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,395,288,400,288, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,404,288,400,288, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,409,290,404,288, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,413,292,409,290, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,418,297,413,292, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,421,302,418,297, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,422,309,421,302, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,421,318,422,309, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,421,318,417,325, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,417,325,411,330, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,411,330,405,332, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,405,332,397,333, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,397,333,344,333, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,344,333,340,334, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,340,334,336,336, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,336,336,335,338, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,335,338,332,342, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,331,347,332,342, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,332,351,331,347, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,334,354,332,351, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,336,357,334,354, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,341,359,336,357, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,341,359,340,360, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,395,288,395,278, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,304,355,258,355, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,347,80,344,76, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,344,76,337,70, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,349,82,347,80, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,351,84,349,82, 'fill'=>outline, 'tags'=>['floor1','bg']) TkcLine.new(w,353,85,351,84, 'fill'=>outline, 'tags'=>['floor1','bg']) end # floor_bg2 -- # This method represents part of the floorplan database. When # invoked, it instantiates the background information for the first # floor. # # Arguments: # w - The canvas window. # fill - Fill color to use for the floor's background. # outline - Color to use for the floor's outline. def floor_bg2(w,fill,outline) TkcPolygon.new(w,559,129,484,129,484,162,398,162,398,129,315,129, 315,133,176,133,176,129,96,129,96,133,3,133,3,339,0,339,0,391, 60,391,60,387,258,387,258,329,350,329,350,311,395,311,395,280, 484,280,484,311,508,311,508,327,558,327,558,391,644,391,644, 367,802,367,802,129,725,129,725,133,559,133,559,129, 'tags'=>['floor2','bg'], 'fill'=>fill) TkcLine.new(w,350,311,350,329, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,398,129,398,162, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,802,367,802,129, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,802,129,725,129, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,725,133,725,129, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,559,129,559,133, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,559,133,725,133, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,484,162,484,129, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,559,129,484,129, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,802,367,644,367, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,644,367,644,391, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,644,391,558,391, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,558,327,558,391, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,558,327,508,327, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,508,327,508,311, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,484,311,508,311, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,484,280,484,311, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,398,162,484,162, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,484,280,395,280, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,395,280,395,311, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,258,387,60,387, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,3,133,3,339, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,3,339,0,339, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,60,391,0,391, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,0,339,0,391, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,60,387,60,391, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,258,329,258,387, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,350,329,258,329, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,395,311,350,311, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,398,129,315,129, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,176,133,315,133, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,176,129,96,129, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,3,133,96,133, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,315,133,315,129, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,176,133,176,129, 'fill'=>outline, 'tags'=>['floor2','bg']) TkcLine.new(w,96,133,96,129, 'fill'=>outline, 'tags'=>['floor2','bg']) end # floor_bg3 -- # This method represents part of the floorplan database. When # invoked, it instantiates the background information for the first # floor. # # Arguments: # w - The canvas window. # fill - Fill color to use for the floor's background. # outline - Color to use for the floor's outline. def floor_bg3(w,fill,outline) TkcPolygon.new(w,159,300,107,300,107,248,159,248,159,129,96,129,96, 133,21,133,21,331,0,331,0,391,60,391,60,370,159,370,159,300, 'tags'=>['floor3','bg'], 'fill'=>fill) TkcPolygon.new(w,258,370,258,329,350,329,350,311,399,311,399,129, 315,129,315,133,176,133,176,129,159,129,159,370,258,370, 'tags'=>['floor3','bg'], 'fill'=>fill) TkcLine.new(w,96,133,96,129, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,176,129,96,129, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,176,129,176,133, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,315,133,176,133, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,315,133,315,129, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,399,129,315,129, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,399,311,399,129, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,399,311,350,311, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,350,329,350,311, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,350,329,258,329, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,258,370,258,329, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,60,370,258,370, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,60,370,60,391, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,60,391,0,391, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,0,391,0,331, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,21,331,0,331, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,21,331,21,133, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,96,133,21,133, 'fill'=>outline, 'tags'=>['floor3','bg']) TkcLine.new(w,107,300,159,300,159,248,107,248,107,300, 'fill'=>outline, 'tags'=>['floor3','bg']) end # floor_fg1 -- # This method represents part of the floorplan database. When # invoked, it instantiates the foreground information for the first # floor (office outlines and numbers). # # Arguments: # w - The canvas window. # color - Color to use for drawing foreground information. def floor_fg1(w,color) i = TkcPolygon.new(w,375,246,375,172,341,172,341,246, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '101' $floorItems['101'] = i TkcText.new(w,358,209, 'text'=>'101', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,307,240,339,240,339,206,307,206, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'Pub Lift1' $floorItems['Pub Lift1'] = i TkcText.new(w,323,223, 'text'=>'Pub Lift1', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,339,205,307,205,307,171,339,171, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'Priv Lift1' $floorItems['Priv Lift1'] = i TkcText.new(w,323,188, 'text'=>'Priv Lift1', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,42,389,42,337,1,337,1,389, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '110' $floorItems['110'] = i TkcText.new(w,21.5,363, 'text'=>'110', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,59,389,59,385,90,385,90,337,44,337,44,389, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '109' $floorItems['109'] = i TkcText.new(w,67,363, 'text'=>'109', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,51,300,51,253,6,253,6,300, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '111' $floorItems['111'] = i TkcText.new(w,28.5,276.5, 'text'=>'111', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,98,248,98,309,79,309,79,248, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '117B' $floorItems['117B'] = i TkcText.new(w,88.5,278.5, 'text'=>'117B', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,51,251,51,204,6,204,6,251, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '112' $floorItems['112'] = i TkcText.new(w,28.5,227.5, 'text'=>'112', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,6,156,51,156,51,203,6,203, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '113' $floorItems['113'] = i TkcText.new(w,28.5,179.5, 'text'=>'113', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,85,169,79,169,79,192,85,192, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '117A' $floorItems['117A'] = i TkcText.new(w,82,180.5, 'text'=>'117A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,77,302,77,168,53,168,53,302, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '117' $floorItems['117'] = i TkcText.new(w,65,235, 'text'=>'117', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,51,155,51,115,6,115,6,155, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '114' $floorItems['114'] = i TkcText.new(w,28.5,135, 'text'=>'114', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,95,115,53,115,53,168,95,168, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '115' $floorItems['115'] = i TkcText.new(w,74,141.5, 'text'=>'115', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,87,113,87,27,10,27,10,113, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '116' $floorItems['116'] = i TkcText.new(w,48.5,70, 'text'=>'116', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,89,91,128,91,128,113,89,131, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '118' $floorItems['118'] = i TkcText.new(w,108.5,102, 'text'=>'118', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,178,128,178,132,216,132,216,91, 163,91,163,112,149,112,149,128, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '120' $floorItems['120'] = i TkcText.new(w,189.5,111.5, 'text'=>'120', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,79,193,87,193,87,169,136,169,136,192, 156,192,156,169,175,169,175,246,79,246, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '122' $floorItems['122'] = i TkcText.new(w,131,207.5, 'text'=>'122', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,138,169,154,169,154,191,138,191, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '121' $floorItems['121'] = i TkcText.new(w,146,180, 'text'=>'121', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,99,300,126,300,126,309,99,309, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '106A' $floorItems['106A'] = i TkcText.new(w,112.5,304.5, 'text'=>'106A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,128,299,128,309,150,309,150,248,99,248,99,299, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '105' $floorItems['105'] = i TkcText.new(w,124.5,278.5, 'text'=>'105', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,174,309,174,300,152,300,152,309, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '106B' $floorItems['106B'] = i TkcText.new(w,163,304.5, 'text'=>'106B', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,176,299,176,309,216,309,216,248,152,248,152,299, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '104' $floorItems['104'] = i TkcText.new(w,184,278.5, 'text'=>'104', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,138,385,138,337,91,337,91,385, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '108' $floorItems['108'] = i TkcText.new(w,114.5,361, 'text'=>'108', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,256,337,140,337,140,385,256,385, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '107' $floorItems['107'] = i TkcText.new(w,198,361, 'text'=>'107', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,300,353,300,329,260,329,260,353, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'Smoking' $floorItems['Smoking'] = i TkcText.new(w,280,341, 'text'=>'Smoking', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,314,135,314,170,306,170,306,246,177,246,177,135, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '123' $floorItems['123'] = i TkcText.new(w,245.5,190.5, 'text'=>'123', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,217,248,301,248,301,326,257,326,257,310,217,310, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '103' $floorItems['103'] = i TkcText.new(w,259,287, 'text'=>'103', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,396,188,377,188,377,169,316,169,316,131,396,131, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '124' $floorItems['124'] = i TkcText.new(w,356,150, 'text'=>'124', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,397,226,407,226,407,189,377,189,377,246,397,246, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '125' $floorItems['125'] = i TkcText.new(w,392,217.5, 'text'=>'125', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,399,187,409,187,409,207,474,207,474,164,399,164, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '126' $floorItems['126'] = i TkcText.new(w,436.5,185.5, 'text'=>'126', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,409,209,409,229,399,229,399,253, 486,253,486,239,474,239,474,209, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '127' $floorItems['127'] = i TkcText.new(w,436.5,'231', 'text'=>'127', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,501,164,501,174,495,174,495,188, 490,188,490,204,476,204,476,164, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'MShower' $floorItems['MShower'] = i TkcText.new(w,488.5,'184', 'text'=>'MShower', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,497,176,513,176,513,204,492,204,492,190,497,190, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'Closet' $floorItems['Closet'] = i TkcText.new(w,502.5,190, 'text'=>'Closet', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,476,237,476,206,513,206,513,254,488,254,488,237, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'WShower' $floorItems['WShower'] = i TkcText.new(w,494.5,230, 'text'=>'WShower', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,486,131,558,131,558,135,724,135,724,166, 697,166,697,275,553,275,531,254,515,254, 515,174,503,174,503,161,486,161, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '130' $floorItems['130'] = i TkcText.new(w,638.5,205, 'text'=>'130', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,308,242,339,242,339,248,342,248, 342,246,397,246,397,276,393,276, 393,309,300,309,300,248,308,248, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '102' $floorItems['102'] = i TkcText.new(w,367.5,278.5, 'text'=>'102', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,397,255,486,255,486,276,397,276, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '128' $floorItems['128'] = i TkcText.new(w,441.5,265.5, 'text'=>'128', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,510,309,486,309,486,255,530,255, 552,277,561,277,561,325,510,325, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '129' $floorItems['129'] = i TkcText.new(w,535.5,293, 'text'=>'129', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,696,281,740,281,740,387,642,387, 642,389,561,389,561,277,696,277, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '133' $floorItems['133'] = i TkcText.new(w,628.5,335, 'text'=>'133', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,742,387,742,281,800,281,800,387, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '132' $floorItems['132'] = i TkcText.new(w,771,334, 'text'=>'132', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,800,168,800,280,699,280,699,168, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '134' $floorItems['134'] = i TkcText.new(w,749.5,224, 'text'=>'134', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,726,131,726,166,800,166,800,131, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '135' $floorItems['135'] = i TkcText.new(w,763,148.5, 'text'=>'135', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,340,360,335,363,331,365,326,366,304,366, 304,312,396,312,396,288,400,288,404,288, 409,290,413,292,418,297,421,302,422,309, 421,318,417,325,411,330,405,332,397,333, 344,333,340,334,336,336,335,338,332,342, 331,347,332,351,334,354,336,357,341,359, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'Ramona Stair' $floorItems['Ramona Stair'] = i TkcText.new(w,368,323, 'text'=>'Ramona Stair', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,30,23,30,5,93,5,98,5,104,7,110,10,116,16,119,20, 122,28,123,32,123,68,220,68,220,87,90,87,90,23, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'University Stair' $floorItems['University Stair'] = i TkcText.new(w,155,77.5, 'text'=>'University Stair', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,282,37,295,40,312,49,323,56,337,70,352,56, 358,48,363,39,365,29,348,25,335,22,321,14, 300,5,283,1,260,0,246,0,242,2,236,4,231,8, 227,13,223,17,221,22,220,34,260,34, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'Plaza Stair' $floorItems['Plaza Stair'] = i TkcText.new(w,317.5,28.5, 'text'=>'Plaza Stair', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,220,34,260,34,282,37,295,40,312,49, 323,56,337,70,350,83,365,94,377,100, 386,104,386,128,220,128, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = 'Plaza Deck' $floorItems['Plaza Deck'] = i TkcText.new(w,303,81, 'text'=>'Plaza Deck', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,257,336,77,336,6,336,6,301,77,301,77,310,257,310, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '106' $floorItems['106'] = i TkcText.new(w,131.5,318.5, 'text'=>'106', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,146,110,162,110,162,91,130,91,130,115,95,115, 95,128,114,128,114,151,157,151,157,153,112,153, 112,130,97,130,97,168,175,168,175,131,146,131, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels[i.id] = '119' $floorItems['119'] = i TkcText.new(w,143.5,133, 'text'=>'119', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) TkcLine.new(w,155,191,155,189, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,155,177,155,169, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,96,129,96,169, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,78,169,176,169, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,176,247,176,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,340,206,307,206, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,340,187,340,170, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,340,210,340,201, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,340,247,340,224, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,340,241,307,241, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,376,246,376,170, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,307,247,307,170, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,376,170,307,170, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,315,129,315,170, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,147,129,176,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,202,133,176,133, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,398,129,315,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,258,352,258,387, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,60,387,60,391, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,0,337,0,391, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,60,391,0,391, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,3,114,3,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,258,387,60,387, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,52,237,52,273, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,52,189,52,225, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,52,140,52,177, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,395,306,395,311, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,531,254,398,254, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,475,178,475,238, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,502,162,398,162, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,398,129,398,188, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,383,188,376,188, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,408,188,408,194, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,398,227,398,254, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,408,227,398,227, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,408,222,408,227, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,408,206,408,210, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,408,208,475,208, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,484,278,484,311, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,484,311,508,311, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,508,327,508,311, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,559,327,508,327, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,644,391,559,391, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,644,389,644,391, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,514,205,475,205, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,496,189,496,187, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,559,129,484,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,484,162,484,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,725,133,559,133, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,559,129,559,133, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,725,149,725,167, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,725,129,802,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,802,389,802,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,739,167,802,167, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,396,188,408,188, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,0,337,9,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,58,337,21,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,43,391,43,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,105,337,75,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,91,387,91,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,154,337,117,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,139,387,139,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,227,337,166,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,258,337,251,337, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,258,328,302,328, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,302,355,302,311, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,395,311,302,311, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,484,278,395,278, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,395,294,395,278, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,473,278,473,275, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,473,256,473,254, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,533,257,531,254, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,553,276,551,274, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,698,276,553,276, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,559,391,559,327, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,802,389,644,389, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,741,314,741,389, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,698,280,698,167, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,707,280,698,280, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,802,280,731,280, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,741,280,741,302, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,698,167,727,167, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,725,137,725,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,514,254,514,175, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,496,175,514,175, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,502,175,502,162, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,475,166,475,162, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,496,176,496,175, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,491,189,496,189, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,491,205,491,189, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,487,238,475,238, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,487,240,487,238, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,487,252,487,254, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,315,133,304,133, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,256,133,280,133, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,78,247,270,247, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,307,247,294,247, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,214,133,232,133, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,217,247,217,266, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,217,309,217,291, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,217,309,172,309, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,154,309,148,309, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,175,300,175,309, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,151,300,175,300, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,151,247,151,309, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,78,237,78,265, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,78,286,78,309, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,106,309,78,309, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,130,309,125,309, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,99,309,99,247, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,127,299,99,299, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,127,309,127,299, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,155,191,137,191, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,137,169,137,191, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,78,171,78,169, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,78,190,78,218, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,86,192,86,169, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,86,192,78,192, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,52,301,3,301, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,52,286,52,301, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,52,252,3,252, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,52,203,3,203, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,3,156,52,156, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,8,25,8,114, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,63,114,3,114, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,75,114,97,114, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,108,114,129,114, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,129,114,129,89, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,52,114,52,128, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,132,89,88,89, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,88,25,88,89, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,88,114,88,89, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,218,89,144,89, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,147,111,147,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,162,111,147,111, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,162,109,162,111, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,162,96,162,89, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,218,89,218,94, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,218,89,218,119, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,8,25,88,25, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,258,337,258,328, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,113,129,96,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,302,355,258,355, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,386,104,386,129, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,377,100,386,104, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,365,94,377,100, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,350,83,365,94, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,337,70,350,83, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,337,70,323,56, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,312,49,323,56, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,295,40,312,49, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,282,37,295,40, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,260,34,282,37, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,253,34,260,34, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,386,128,386,104, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,113,152,156,152, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,113,152,156,152, 'fill'=>color, 'tags'=>['floor1','wall']) TkcLine.new(w,113,152,113,129, 'fill'=>color, 'tags'=>['floor1','wall']) end # floor_fg2 -- # This method represents part of the floorplan database. When # invoked, it instantiates the foreground information for the second # floor (office outlines and numbers). # # Arguments: # w - The canvas window. # color - Color to use for drawing foreground information. def floor_fg2(w,color) i = TkcPolygon.new(w,748,188,755,188,755,205,758,205,758,222, 800,222,800,168,748,168, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '238' $floorItems['238'] = i TkcText.new(w,774,195, 'text'=>'238', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,726,188,746,188,746,166,800,166,800,131,726,131, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '237' $floorItems['237'] = i TkcText.new(w,763,148.5, 'text'=>'237', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,497,187,497,204,559,204,559,324,641,324, 643,324,643,291,641,291,641,205,696,205, 696,291,694,291,694,314,715,314,715,291, 715,205,755,205,755,190,724,190,724,187, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '246' $floorItems['246'] = i TkcText.new(w,600,264, 'text'=>'246', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,694,279,643,279,643,314,694,314, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '247' $floorItems['247'] = i TkcText.new(w,668.5,296.5, 'text'=>'247', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,232,250,308,250,308,242,339,242,339,246, 397,246,397,255,476,255,476,250,482,250,559,250, 559,274,482,274,482,278,396,278,396,274,232,274, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '202' $floorItems['202'] = i TkcText.new(w,285.5,260, 'text'=>'202', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,53,228,53,338,176,338,233,338,233,196, 306,196,306,180,175,180,175,169,156,169, 156,196,176,196,176,228, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '206' $floorItems['206'] = i TkcText.new(w,143,267, 'text'=>'206', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,51,277,6,277,6,338,51,338, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '212' $floorItems['212'] = i TkcText.new(w,28.5,307.5, 'text'=>'212', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,557,276,486,276,486,309,510,309,510,325,557,325, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '245' $floorItems['245'] = i TkcText.new(w,521.5,300.5, 'text'=>'245', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,560,389,599,389,599,326,560,326, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '244' $floorItems['244'] = i TkcText.new(w,579.5,357.5, 'text'=>'244', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,601,389,601,326,643,326,643,389, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '243' $floorItems['243'] = i TkcText.new(w,622,357.5, 'text'=>'243', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,688,316,645,316,645,365,688,365, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '242' $floorItems['242'] = i TkcText.new(w,666.5,340.5, 'text'=>'242', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,802,367,759,367,759,226,802,226, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = 'Barbecue Deck' $floorItems['Barbecue Deck'] = i TkcText.new(w,780.5,296.5, 'text'=>'Barbecue Deck', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,755,262,755,314,717,314,717,262, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '240' $floorItems['240'] = i TkcText.new(w,736,288, 'text'=>'240', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,755,316,689,316,689,365,755,365, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '241' $floorItems['241'] = i TkcText.new(w,722,340.5, 'text'=>'241', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,755,206,717,206,717,261,755,261, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '239' $floorItems['239'] = i TkcText.new(w,736,233.5, 'text'=>'239', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,695,277,643,277,643,206,695,206, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '248' $floorItems['248'] = i TkcText.new(w,669,241.5, 'text'=>'248', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,676,135,676,185,724,185,724,135, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '236' $floorItems['236'] = i TkcText.new(w,700,160, 'text'=>'236', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,675,135,635,135,635,145,628,145,628,185,675,185, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '235' $floorItems['235'] = i TkcText.new(w,651.5,160, 'text'=>'235', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,626,143,633,143,633,135,572,135, 572,143,579,143,579,185,626,185, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '234' $floorItems['234'] = i TkcText.new(w,606,160, 'text'=>'234', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,557,135,571,135,571,145,578,145, 578,185,527,185,527,131,557,131, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '233' $floorItems['233'] = i TkcText.new(w,552.5,158, 'text'=>'233', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,476,249,557,249,557,205,476,205, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '230' $floorItems['230'] = i TkcText.new(w,516.5,227, 'text'=>'230', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,476,164,486,164,486,131,525,131,525,185,476,185, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '232' $floorItems['232'] = i TkcText.new(w,500.5,158, 'text'=>'232', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,476,186,495,186,495,204,476,204, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '229' $floorItems['229'] = i TkcText.new(w,485.5,195, 'text'=>'229', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,474,207,409,207,409,187,399,187,399,164,474,164, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '227' $floorItems['227'] = i TkcText.new(w,436.5,185.5, 'text'=>'227', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,399,228,399,253,474,253,474,209,409,209,409,228, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '228' $floorItems['228'] = i TkcText.new(w,436.5,231, 'text'=>'228', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,397,246,397,226,407,226,407,189,377,189,377,246, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '226' $floorItems['226'] = i TkcText.new(w,392,217.5, 'text'=>'226', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,377,169,316,169,316,131,397,131,397,188,377,188, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '225' $floorItems['225'] = i TkcText.new(w,356.5,150, 'text'=>'225', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,234,198,306,198,306,249,234,249, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '224' $floorItems['224'] = i TkcText.new(w,270,223.5, 'text'=>'224', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,270,179,306,179,306,170,314,170,314,135,270,135, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '223' $floorItems['223'] = i TkcText.new(w,292,157, 'text'=>'223', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,268,179,221,179,221,135,268,135, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '222' $floorItems['222'] = i TkcText.new(w,244.5,157, 'text'=>'222', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,177,179,219,179,219,135,177,135, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '221' $floorItems['221'] = i TkcText.new(w,198,157, 'text'=>'221', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,299,327,349,327,349,284,341,284,341,276,299,276, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '204' $floorItems['204'] = i TkcText.new(w,324,301.5, 'text'=>'204', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,234,276,297,276,297,327,257,327,257,338,234,338, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '205' $floorItems['205'] = i TkcText.new(w,265.5,307, 'text'=>'205', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,256,385,256,340,212,340,212,385, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '207' $floorItems['207'] = i TkcText.new(w,234,362.5, 'text'=>'207', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,210,340,164,340,164,385,210,385, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '208' $floorItems['208'] = i TkcText.new(w,187,362.5, 'text'=>'208', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,115,340,162,340,162,385,115,385, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '209' $floorItems['209'] = i TkcText.new(w,138.5,362.5, 'text'=>'209', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,89,228,89,156,53,156,53,228, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '217' $floorItems['217'] = i TkcText.new(w,71,192, 'text'=>'217', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,89,169,97,169,97,190,89,190, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '217A' $floorItems['217A'] = i TkcText.new(w,93,179.5, 'text'=>'217A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,89,156,89,168,95,168,95,135,53,135,53,156, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '216' $floorItems['216'] = i TkcText.new(w,71,145.5, 'text'=>'216', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,51,179,51,135,6,135,6,179, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '215' $floorItems['215'] = i TkcText.new(w,28.5,157, 'text'=>'215', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,51,227,6,227,6,180,51,180, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '214' $floorItems['214'] = i TkcText.new(w,28.5,203.5, 'text'=>'214', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,51,275,6,275,6,229,51,229, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '213' $floorItems['213'] = i TkcText.new(w,28.5,252, 'text'=>'213', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,114,340,67,340,67,385,114,385, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '210' $floorItems['210'] = i TkcText.new(w,90.5,362.5, 'text'=>'210', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,59,389,59,385,65,385,65,340,1,340,1,389, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '211' $floorItems['211'] = i TkcText.new(w,33,364.5, 'text'=>'211', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,393,309,350,309,350,282,342,282,342,276,393,276, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '203' $floorItems['203'] = i TkcText.new(w,367.5,292.5, 'text'=>'203', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,99,191,91,191,91,226,174,226,174,198, 154,198,154,192,109,192,109,169,99,169, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '220' $floorItems['220'] = i TkcText.new(w,132.5,208.5, 'text'=>'220', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,339,205,307,205,307,171,339,171, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = 'Priv Lift2' $floorItems['Priv Lift2'] = i TkcText.new(w,323,188, 'text'=>'Priv Lift2', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,307,240,339,240,339,206,307,206, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = 'Pub Lift 2' $floorItems['Pub Lift 2'] = i TkcText.new(w,323,223, 'text'=>'Pub Lift 2', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,175,168,97,168,97,131,175,131, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '218' $floorItems['218'] = i TkcText.new(w,136,149.5, 'text'=>'218', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,154,191,111,191,111,169,154,169, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '219' $floorItems['219'] = i TkcText.new(w,132.5,180, 'text'=>'219', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,375,246,375,172,341,172,341,246, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels[i.id] = '201' $floorItems['201'] = i TkcText.new(w,358,209, 'text'=>'201', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) TkcLine.new(w,641,186,678,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,757,350,757,367, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,634,133,634,144, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,634,144,627,144, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,572,133,572,144, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,572,144,579,144, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,398,129,398,162, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,174,197,175,197, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,175,197,175,227, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,757,206,757,221, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,396,188,408,188, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,727,189,725,189, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,747,167,802,167, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,747,167,747,189, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,755,189,739,189, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,769,224,757,224, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,802,224,802,129, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,802,129,725,129, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,725,189,725,129, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,725,186,690,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,676,133,676,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,627,144,627,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,629,186,593,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,579,144,579,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,559,129,559,133, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,725,133,559,133, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,484,162,484,129, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,559,129,484,129, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,526,129,526,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,540,186,581,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,528,186,523,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,511,186,475,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,496,190,496,186, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,496,205,496,202, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,475,205,527,205, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,558,205,539,205, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,558,205,558,249, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,558,249,475,249, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,662,206,642,206, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,695,206,675,206, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,695,278,642,278, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,642,291,642,206, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,695,291,695,206, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,716,208,716,206, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,757,206,716,206, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,757,221,757,224, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,793,224,802,224, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,757,262,716,262, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,716,220,716,264, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,716,315,716,276, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,757,315,703,315, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,757,325,757,224, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,757,367,644,367, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,689,367,689,315, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,647,315,644,315, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,659,315,691,315, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,600,325,600,391, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,627,325,644,325, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,644,391,644,315, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,615,325,575,325, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,644,391,558,391, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,563,325,558,325, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,558,391,558,314, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,558,327,508,327, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,558,275,484,275, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,558,302,558,275, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,508,327,508,311, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,484,311,508,311, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,484,275,484,311, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,475,208,408,208, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,408,206,408,210, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,408,222,408,227, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,408,227,398,227, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,398,227,398,254, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,408,188,408,194, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,383,188,376,188, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,398,188,398,162, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,398,162,484,162, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,475,162,475,254, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,398,254,475,254, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,484,280,395,280, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,395,311,395,275, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,307,197,293,197, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,278,197,233,197, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,233,197,233,249, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,307,179,284,179, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,233,249,278,249, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,269,179,269,133, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,220,179,220,133, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,155,191,110,191, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,90,190,98,190, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,98,169,98,190, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,52,133,52,165, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,52,214,52,177, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,52,226,52,262, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,52,274,52,276, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,234,275,234,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,226,339,258,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,211,387,211,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,214,339,177,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,258,387,60,387, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,3,133,3,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,165,339,129,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,117,339,80,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,68,339,59,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,0,339,46,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,60,391,0,391, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,0,339,0,391, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,60,387,60,391, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,258,329,258,387, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,350,329,258,329, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,395,311,350,311, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,398,129,315,129, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,176,133,315,133, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,176,129,96,129, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,3,133,96,133, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,66,387,66,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,115,387,115,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,163,387,163,339, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,234,275,276,275, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,288,275,309,275, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,298,275,298,329, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,341,283,350,283, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,321,275,341,275, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,375,275,395,275, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,315,129,315,170, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,376,170,307,170, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,307,250,307,170, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,376,245,376,170, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,340,241,307,241, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,340,245,340,224, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,340,210,340,201, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,340,187,340,170, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,340,206,307,206, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,293,250,307,250, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,271,179,238,179, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,226,179,195,179, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,176,129,176,179, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,182,179,176,179, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,174,169,176,169, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,162,169,90,169, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,96,169,96,129, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,175,227,90,227, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,90,190,90,227, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,52,179,3,179, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,52,228,3,228, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,52,276,3,276, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,155,177,155,169, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,110,191,110,169, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,155,189,155,197, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,350,283,350,329, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,162,197,155,197, 'fill'=>color, 'tags'=>['floor2','wall']) TkcLine.new(w,341,275,341,283, 'fill'=>color, 'tags'=>['floor2','wall']) end # floor_fg3 -- # This method represents part of the floorplan database. When # invoked, it instantiates the foreground information for the third # floor (office outlines and numbers). # # Arguments: # w - The canvas window. # color - Color to use for drawing foreground information. def floor_fg3(w,color) i = TkcPolygon.new(w,89,228,89,180,70,180,70,228, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '316' $floorItems['316'] = i TkcText.new(w,79.5,204, 'text'=>'316', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,115,368,162,368,162,323,115,323, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '309' $floorItems['309'] = i TkcText.new(w,138.5,345.5, 'text'=>'309', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,164,323,164,368,211,368,211,323, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '308' $floorItems['308'] = i TkcText.new(w,187.5,345.5, 'text'=>'308', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,256,368,212,368,212,323,256,323, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '307' $floorItems['307'] = i TkcText.new(w,234,345.5, 'text'=>'307', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,244,276,297,276,297,327,260,327,260,321,244,321, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '305' $floorItems['305'] = i TkcText.new(w,270.5,301.5, 'text'=>'305', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,251,219,251,203,244,203,244,219, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '324B' $floorItems['324B'] = i TkcText.new(w,247.5,211, 'text'=>'324B', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,251,249,244,249,244,232,251,232, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '324A' $floorItems['324A'] = i TkcText.new(w,247.5,240.5, 'text'=>'324A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,223,135,223,179,177,179,177,135, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '320' $floorItems['320'] = i TkcText.new(w,200,157, 'text'=>'320', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,114,368,114,323,67,323,67,368, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '310' $floorItems['310'] = i TkcText.new(w,90.5,345.5, 'text'=>'310', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,23,277,23,321,68,321,68,277, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '312' $floorItems['312'] = i TkcText.new(w,45.5,299, 'text'=>'312', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,23,229,68,229,68,275,23,275, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '313' $floorItems['313'] = i TkcText.new(w,45.5,252, 'text'=>'313', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,68,227,23,227,23,180,68,180, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '314' $floorItems['314'] = i TkcText.new(w,40.5,203.5, 'text'=>'314', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,95,179,95,135,23,135,23,179, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '315' $floorItems['315'] = i TkcText.new(w,59,157, 'text'=>'315', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,99,226,99,204,91,204,91,226, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '316B' $floorItems['316B'] = i TkcText.new(w,95,215, 'text'=>'316B', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,91,202,99,202,99,180,91,180, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '316A' $floorItems['316A'] = i TkcText.new(w,95,191, 'text'=>'316A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,97,169,109,169,109,192,154,192,154,198, 174,198,174,226,101,226,101,179,97,179, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '319' $floorItems['319'] = i TkcText.new(w,141.5,209, 'text'=>'319', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,65,368,58,368,58,389,1,389,1,333,23,333,23,323,65,323, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '311' $floorItems['311'] = i TkcText.new(w,29.5,361, 'text'=>'311', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,154,191,111,191,111,169,154,169, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '318' $floorItems['318'] = i TkcText.new(w,132.5,180, 'text'=>'318', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,175,168,97,168,97,131,175,131, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '317' $floorItems['317'] = i TkcText.new(w,136,149.5, 'text'=>'317', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,274,194,274,221,306,221,306,194, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '323' $floorItems['323'] = i TkcText.new(w,290,207.5, 'text'=>'323', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,306,222,274,222,274,249,306,249, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '325' $floorItems['325'] = i TkcText.new(w,290,235.5, 'text'=>'325', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,263,179,224,179,224,135,263,135, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '321' $floorItems['321'] = i TkcText.new(w,243.5,157, 'text'=>'321', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,314,169,306,169,306,192,273,192, 264,181,264,135,314,135, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '322' $floorItems['322'] = i TkcText.new(w,293.5,163.5, 'text'=>'322', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,307,240,339,240,339,206,307,206, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = 'Pub Lift3' $floorItems['Pub Lift3'] = i TkcText.new(w,323,223, 'text'=>'Pub Lift3', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,339,205,307,205,307,171,339,171, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = 'Priv Lift3' $floorItems['Priv Lift3'] = i TkcText.new(w,323,188, 'text'=>'Priv Lift3', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,350,284,376,284,376,276,397,276,397,309,350,309, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '303' $floorItems['303'] = i TkcText.new(w,373.5,292.5, 'text'=>'303', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,272,203,272,249,252,249,252,230, 244,230,244,221,252,221,252,203, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '324' $floorItems['324'] = i TkcText.new(w,262,226, 'text'=>'324', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,299,276,299,327,349,327,349,284,341,284,341,276, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '304' $floorItems['304'] = i TkcText.new(w,324,301.5, 'text'=>'304', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,375,246,375,172,341,172,341,246, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '301' $floorItems['301'] = i TkcText.new(w,358,209, 'text'=>'301', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,397,246,377,246,377,185,397,185, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '327' $floorItems['327'] = i TkcText.new(w,387,215.5, 'text'=>'327', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,316,131,316,169,377,169,377,185,397,185,397,131, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '326' $floorItems['326'] = i TkcText.new(w,365.5,150, 'text'=>'326', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,308,251,242,251,242,274,342,274,342,282,375, 282, 375,274,397,274,397,248,339,248,339,242,308,242, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '302' $floorItems['302'] = i TkcText.new(w,319.5,261, 'text'=>'302', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,70,321,242,321,242,200,259,200,259,203,272,203, 272,193,263,180,242,180,175,180,175,169,156,169, 156,196,177,196,177,228,107,228,70,228,70,275,107,275, 107,248,160,248,160,301,107,301,107,275,70,275, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels[i.id] = '306' $floorItems['306'] = i TkcText.new(w,200.5,284.5, 'text'=>'306', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) TkcLine.new(w,341,275,341,283, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,162,197,155,197, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,396,247,399,247, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,399,129,399,311, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,258,202,243,202, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,350,283,350,329, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,251,231,243,231, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,243,220,251,220, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,243,250,243,202, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,155,197,155,190, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,110,192,110,169, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,155,192,110,192, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,155,177,155,169, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,176,197,176,227, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,69,280,69,274, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,21,276,69,276, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,69,262,69,226, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,21,228,69,228, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,21,179,75,179, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,69,179,69,214, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,90,220,90,227, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,90,204,90,202, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,90,203,100,203, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,90,187,90,179, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,90,227,176,227, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,100,179,100,227, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,100,179,87,179, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,96,179,96,129, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,162,169,96,169, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,173,169,176,169, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,182,179,176,179, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,176,129,176,179, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,195,179,226,179, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,224,133,224,179, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,264,179,264,133, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,238,179,264,179, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,273,207,273,193, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,273,235,273,250, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,273,224,273,219, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,273,193,307,193, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,273,222,307,222, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,273,250,307,250, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,384,247,376,247, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,340,206,307,206, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,340,187,340,170, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,340,210,340,201, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,340,247,340,224, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,340,241,307,241, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,376,247,376,170, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,307,250,307,170, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,376,170,307,170, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,315,129,315,170, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,376,283,366,283, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,376,283,376,275, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,399,275,376,275, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,341,275,320,275, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,341,283,350,283, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,298,275,298,329, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,308,275,298,275, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,243,322,243,275, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,243,275,284,275, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,258,322,226,322, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,212,370,212,322, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,214,322,177,322, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,163,370,163,322, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,165,322,129,322, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,84,322,117,322, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,71,322,64,322, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,115,322,115,370, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,66,322,66,370, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,52,322,21,322, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,21,331,0,331, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,21,331,21,133, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,96,133,21,133, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,176,129,96,129, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,315,133,176,133, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,315,129,399,129, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,399,311,350,311, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,350,329,258,329, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,258,322,258,370, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,60,370,258,370, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,60,370,60,391, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,0,391,0,331, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,60,391,0,391, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,307,250,307,242, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,273,250,307,250, 'fill'=>color, 'tags'=>['floor3','wall']) TkcLine.new(w,258,250,243,250, 'fill'=>color, 'tags'=>['floor3','wall']) end # Below is the "main program" that creates the floorplan demonstration. # toplevel widget ¸ߤк if defined?($floor_demo) && $floor_demo $floor_demo.destroy $floor_demo = nil end # demo Ѥ toplevel widget $floor_demo = TkToplevel.new {|w| title("Floorplan Canvas Demonstration") iconname("Floorplan") positionWindow(w) geometry('+20+20') minsize(100,100) } base_frame = TkFrame.new($floor_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'8i', 'justify'=>'left', 'text'=>"Υɥˤϥǥ륨åץȼҤΥꥵܥȥ (DECWRL) δּ꤬񤫤줿Х widget äƤޤ 3ƤǡˤΤ1ʬ򡢤Ĥޤꤽδּ꤬ɽ褦ˤʤäƤޤ볬򤹤ˤϡξǥޥκܥ򥯥åƤޥ򤵤Ƥ볬ξưȡβˤοѤꡢֹ椬ֹ:ץȥɽޤޤȥֹ񤯤ȤοѤޤ"){ pack('side'=>'top') } # frame $floor_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $floor_demo $floor_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'floor'} }.pack('side'=>'left', 'expand'=>'yes') } $floor_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # ѿ $floorLabels = {} $floorItems = {} # canvas if $tk_version =~ /^4\.[01]/ $floor_canvas_frame = TkFrame.new(base_frame,'bd'=>2,'relief'=>'sunken', 'highlightthickness'=>2) $floor_canvas = TkCanvas.new($floor_canvas_frame, 'width'=>900, 'height'=>500, 'borderwidth'=>0, 'highlightthickness'=>0) {|c| TkScrollbar.new(base_frame, 'orient'=>'horiz', 'command'=>proc{|*args| c.xview(*args)}){|hs| c.xscrollcommand(proc{|first,last| hs.set first,last}) pack('side'=>'bottom', 'fill'=>'x') } TkScrollbar.new(base_frame, 'command'=>proc{|*args| c.yview(*args)}){|vs| c.yscrollcommand(proc{|first,last| vs.set first,last}) pack('side'=>'right', 'fill'=>'y') } } $floor_canvas_frame.pack('side'=>'top','fill'=>'both', 'expand'=>'yes') $floor_canvas.pack('expand'=>'yes', 'fill'=>'both') else TkFrame.new(base_frame) {|f| pack('side'=>'top', 'fill'=>'both', 'expand'=>'yes') h = TkScrollbar.new(f, 'highlightthickness'=>0, 'orient'=>'horizontal') v = TkScrollbar.new(f, 'highlightthickness'=>0, 'orient'=>'vertical') TkFrame.new(f, 'bd'=>2, 'relief'=>'sunken') {|f1| $floor_canvas = TkCanvas.new(f1, 'width'=>900, 'height'=>500, 'borderwidth'=>0, 'highlightthickness'=>0) { xscrollcommand(proc{|first,last| h.set first,last}) yscrollcommand(proc{|first,last| v.set first,last}) pack('expand'=>'yes', 'fill'=>'both') } grid('padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') } v.grid('padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>1, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') h.grid('padx'=>1, 'pady'=>1, 'row'=>1, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') TkGrid.rowconfigure(f, 0, 'weight'=>1, 'minsize'=>0) TkGrid.columnconfigure(f, 0, 'weight'=>1, 'minsize'=>0) pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1) v.command(proc{|*args| $floor_canvas.yview(*args)}) h.command(proc{|*args| $floor_canvas.xview(*args)}) } end # Create an entry for displaying and typing in current room. $currentRoom = TkVariable.new $floor_entry = TkEntry.new($floor_canvas, 'width'=>10, 'relief'=>'sunken', 'bd'=>2, 'textvariable'=>$currentRoom) # Choose colors, then fill in the floorplan. $floor_colors = {} if TkWinfo.depth($floor_canvas) > 1 $floor_colors['bg1'] = '#a9c1da' $floor_colors['outline1'] = '#77889a' $floor_colors['bg2'] = '#9ab0c6' $floor_colors['outline2'] = '#687786' $floor_colors['bg3'] = '#8ba0b3' $floor_colors['outline3'] = '#596673' $floor_colors['offices'] = 'Black' $floor_colors['active'] = '#c4d1df' else $floor_colors['bg1'] = 'white' $floor_colors['outline1'] = 'black' $floor_colors['bg2'] = 'white' $floor_colors['outline2'] = 'black' $floor_colors['bg3'] = 'white' $floor_colors['outline3'] = 'black' $floor_colors['offices'] = 'Black' $floor_colors['active'] = 'black' end $activeFloor = '' floorDisplay $floor_canvas,3 # Set up event bindings for canvas: $floor_canvas.itembind('floor1', '1', proc{floorDisplay $floor_canvas,1}) $floor_canvas.itembind('floor2', '1', proc{floorDisplay $floor_canvas,2}) $floor_canvas.itembind('floor3', '1', proc{floorDisplay $floor_canvas,3}) $floor_canvas.itembind('room', 'Enter', proc{newRoom $floor_canvas}) $floor_canvas.itembind('room', 'Leave', proc{$currentRoom.value = ''}) $floor_canvas.bind('2', proc{|x,y| $floor_canvas.scan_mark x,y}, '%x %y') $floor_canvas.bind('B2-Motion', proc{|x,y| $floor_canvas.scan_dragto x,y}, '%x %y') $floor_canvas.bind('Destroy', proc{$currentRoom.unset}) $currentRoom.value = '' $currentRoom.trace('w',proc{roomChanged $floor_canvas}) ================================================ FILE: ext/tk/sample/demos-jp/floor2.rb ================================================ # -*- coding: euc-jp -*- # # floorDisplay widget demo 2 (called by 'widget') # # floorDisplay2 -- # Recreate the floorplan display in the canvas given by "w". The # floor given by "active" is displayed on top with its office structure # visible. # # Arguments: # w - Name of the canvas window. # active - Number of active floor (1, 2, or 3). def floorDisplay2(w,active) return if $activeFloor2 == active w.delete('all') $activeFloor2 = active # First go through the three floors, displaying the backgrounds for # each floor. floor2_bg1(w,$floor2_colors['bg1'],$floor2_colors['outline1']) floor2_bg2(w,$floor2_colors['bg2'],$floor2_colors['outline2']) floor2_bg3(w,$floor2_colors['bg3'],$floor2_colors['outline3']) # Raise the background for the active floor so that it's on top. w.raise("floor#{active}") # Create a dummy item just to mark this point in the display list, # so we can insert highlights here. w.create(TkcRectangle,0,100,1,101,'fill'=>'','outline'=>'','tags'=>'marker') # Add the walls and labels for the active floor, along with # transparent polygons that define the rooms on the floor. # Make sure that the room polygons are on top. $floorLabels2.clear $floorItems2.clear send("floor2_fg#{active}", w, $floor2_colors['offices']) w.raise('room') # Offset the floors diagonally from each other. w.move('floor1', '2c', '2c') w.move('floor2', '1c', '1c') # Create items for the room entry and its label. w.create(TkcWindow, 600, 100, 'anchor'=>'w', 'window'=>$floor2_entry) w.create(TkcText, 600, 100, 'anchor'=>'e', 'text'=>"ֹ: ") w['scrollregion'] = w.bbox('all') end # newRoom2 -- # This method is invoked whenever the mouse enters a room # in the floorplan. It changes tags so that the current room is # highlighted. # # Arguments: # w - The name of the canvas window. def newRoom2(w) id = w.find_withtag('current')[0] $currentRoom2.value = $floorLabels2[id.id] if id != "" Tk.update(true) end # roomChanged2 -- # This method is invoked whenever the currentRoom variable changes. # It highlights the current room and unhighlights any previous room. # # Arguments: # w - The canvas window displaying the floorplan. # args - Not used. def roomChanged2(w,*args) w.delete('highlight') item = $floorItems2[$currentRoom2.value] return if item == nil new = TkcPolygon.new(w, *(w.coords(item))) new.configure('fill'=>$floor2_colors['active'], 'tags'=>'highlight') w.raise(new, 'marker') end # floor2_bg1 -- # This method represents part of the floorplan database. When # invoked, it instantiates the background information for the first # floor. # # Arguments: # w - The canvas window. # fill - Fill color to use for the floor's background. # outline - Color to use for the floor's outline. def floor2_bg1(w,fill,outline) w.create(TkcPolygon,347,80,349,82,351,84,353,85,363,92,375,99,386,104, 386,129,398,129,398,162,484,162,484,129,559,129,559,133,725, 133,725,129,802,129,802,389,644,389,644,391,559,391,559,327, 508,327,508,311,484,311,484,278,395,278,395,288,400,288,404, 288,409,290,413,292,418,297,421,302,422,309,421,318,417,325, 411,330,405,332,397,333,344,333,340,334,336,336,335,338,332, 342,331,347,332,351,334,354,336,357,341,359,340,360,335,363, 331,365,326,366,304,366,304,355,258,355,258,387,60,387,60,391, 0,391,0,337,3,337,3,114,8,114,8,25,30,25,30,5,93,5,98,5,104,7, 110,10,116,16,119,20,122,28,123,32,123,68,220,68,220,34,221, 22,223,17,227,13,231,8,236,4,242,2,246,0,260,0,283,1,300,5, 321,14,335,22,348,25,365,29,363,39,358,48,352,56,337,70, 344,76,347,80, 'tags'=>['floor1','bg'], 'fill'=>fill) w.create(TkcLine,386,129,398,129, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,258,355,258,387, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,60,387,60,391, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,0,337,0,391, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,60,391,0,391, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,3,114,3,337, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,258,387,60,387, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,484,162,398,162, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,398,162,398,129, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,484,278,484,311, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,484,311,508,311, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,508,327,508,311, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,559,327,508,327, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,644,391,559,391, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,644,389,644,391, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,559,129,484,129, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,484,162,484,129, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,725,133,559,133, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,559,129,559,133, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,725,129,802,129, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,802,389,802,129, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,3,337,0,337, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,559,391,559,327, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,802,389,644,389, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,725,133,725,129, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,8,25,8,114, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,8,114,3,114, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,30,25,8,25, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,484,278,395,278, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,30,25,30,5, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,93,5,30,5, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,98,5,93,5, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,104,7,98,5, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,110,10,104,7, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,116,16,110,10, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,119,20,116,16, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,122,28,119,20, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,123,32,122,28, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,123,68,123,32, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,220,68,123,68, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,386,129,386,104, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,386,104,375,99, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,375,99,363,92, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,353,85,363,92, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,220,68,220,34, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,337,70,352,56, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,352,56,358,48, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,358,48,363,39, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,363,39,365,29, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,365,29,348,25, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,348,25,335,22, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,335,22,321,14, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,321,14,300,5, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,300,5,283,1, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,283,1,260,0, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,260,0,246,0, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,246,0,242,2, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,242,2,236,4, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,236,4,231,8, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,231,8,227,13, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,223,17,227,13, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,221,22,223,17, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,220,34,221,22, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,340,360,335,363, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,335,363,331,365, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,331,365,326,366, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,326,366,304,366, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,304,355,304,366, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,395,288,400,288, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,404,288,400,288, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,409,290,404,288, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,413,292,409,290, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,418,297,413,292, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,421,302,418,297, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,422,309,421,302, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,421,318,422,309, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,421,318,417,325, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,417,325,411,330, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,411,330,405,332, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,405,332,397,333, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,397,333,344,333, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,344,333,340,334, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,340,334,336,336, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,336,336,335,338, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,335,338,332,342, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,331,347,332,342, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,332,351,331,347, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,334,354,332,351, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,336,357,334,354, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,341,359,336,357, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,341,359,340,360, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,395,288,395,278, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,304,355,258,355, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,347,80,344,76, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,344,76,337,70, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,349,82,347,80, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,351,84,349,82, 'fill'=>outline, 'tags'=>['floor1','bg']) w.create(TkcLine,353,85,351,84, 'fill'=>outline, 'tags'=>['floor1','bg']) end # floor2_bg2 -- # This method represents part of the floorplan database. When # invoked, it instantiates the background information for the first # floor. # # Arguments: # w - The canvas window. # fill - Fill color to use for the floor's background. # outline - Color to use for the floor's outline. def floor2_bg2(w,fill,outline) w.create(TkcPolygon,559,129,484,129,484,162,398,162,398,129,315,129, 315,133,176,133,176,129,96,129,96,133,3,133,3,339,0,339,0,391, 60,391,60,387,258,387,258,329,350,329,350,311,395,311,395,280, 484,280,484,311,508,311,508,327,558,327,558,391,644,391,644, 367,802,367,802,129,725,129,725,133,559,133,559,129, 'tags'=>['floor2','bg'], 'fill'=>fill) w.create(TkcLine,350,311,350,329, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,398,129,398,162, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,802,367,802,129, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,802,129,725,129, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,725,133,725,129, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,559,129,559,133, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,559,133,725,133, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,484,162,484,129, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,559,129,484,129, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,802,367,644,367, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,644,367,644,391, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,644,391,558,391, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,558,327,558,391, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,558,327,508,327, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,508,327,508,311, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,484,311,508,311, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,484,280,484,311, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,398,162,484,162, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,484,280,395,280, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,395,280,395,311, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,258,387,60,387, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,3,133,3,339, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,3,339,0,339, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,60,391,0,391, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,0,339,0,391, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,60,387,60,391, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,258,329,258,387, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,350,329,258,329, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,395,311,350,311, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,398,129,315,129, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,176,133,315,133, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,176,129,96,129, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,3,133,96,133, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,315,133,315,129, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,176,133,176,129, 'fill'=>outline, 'tags'=>['floor2','bg']) w.create(TkcLine,96,133,96,129, 'fill'=>outline, 'tags'=>['floor2','bg']) end # floor2_bg3 -- # This method represents part of the floorplan database. When # invoked, it instantiates the background information for the first # floor. # # Arguments: # w - The canvas window. # fill - Fill color to use for the floor's background. # outline - Color to use for the floor's outline. def floor2_bg3(w,fill,outline) w.create(TkcPolygon,159,300,107,300,107,248,159,248,159,129,96,129,96, 133,21,133,21,331,0,331,0,391,60,391,60,370,159,370,159,300, 'tags'=>['floor3','bg'], 'fill'=>fill) w.create(TkcPolygon,258,370,258,329,350,329,350,311,399,311,399,129, 315,129,315,133,176,133,176,129,159,129,159,370,258,370, 'tags'=>['floor3','bg'], 'fill'=>fill) w.create(TkcLine,96,133,96,129, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,176,129,96,129, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,176,129,176,133, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,315,133,176,133, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,315,133,315,129, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,399,129,315,129, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,399,311,399,129, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,399,311,350,311, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,350,329,350,311, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,350,329,258,329, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,258,370,258,329, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,60,370,258,370, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,60,370,60,391, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,60,391,0,391, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,0,391,0,331, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,21,331,0,331, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,21,331,21,133, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,96,133,21,133, 'fill'=>outline, 'tags'=>['floor3','bg']) w.create(TkcLine,107,300,159,300,159,248,107,248,107,300, 'fill'=>outline, 'tags'=>['floor3','bg']) end # floor2_fg1 -- # This method represents part of the floorplan database. When # invoked, it instantiates the foreground information for the first # floor (office outlines and numbers). # # Arguments: # w - The canvas window. # color - Color to use for drawing foreground information. def floor2_fg1(w,color) i = TkcPolygon.new(w,375,246,375,172,341,172,341,246, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '101' $floorItems2['101'] = i w.create(TkcText,358,209, 'text'=>'101', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,307,240,339,240,339,206,307,206, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'Pub Lift1' $floorItems2['Pub Lift1'] = i w.create(TkcText,323,223, 'text'=>'Pub Lift1', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,339,205,307,205,307,171,339,171, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'Priv Lift1' $floorItems2['Priv Lift1'] = i w.create(TkcText,323,188, 'text'=>'Priv Lift1', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,42,389,42,337,1,337,1,389, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '110' $floorItems2['110'] = i w.create(TkcText,21.5,363, 'text'=>'110', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,59,389,59,385,90,385,90,337,44,337,44,389, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '109' $floorItems2['109'] = i w.create(TkcText,67,363, 'text'=>'109', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,51,300,51,253,6,253,6,300, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '111' $floorItems2['111'] = i w.create(TkcText,28.5,276.5, 'text'=>'111', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,98,248,98,309,79,309,79,248, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '117B' $floorItems2['117B'] = i w.create(TkcText,88.5,278.5, 'text'=>'117B', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,51,251,51,204,6,204,6,251, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '112' $floorItems2['112'] = i w.create(TkcText,28.5,227.5, 'text'=>'112', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,6,156,51,156,51,203,6,203, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '113' $floorItems2['113'] = i w.create(TkcText,28.5,179.5, 'text'=>'113', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,85,169,79,169,79,192,85,192, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '117A' $floorItems2['117A'] = i w.create(TkcText,82,180.5, 'text'=>'117A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,77,302,77,168,53,168,53,302, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '117' $floorItems2['117'] = i w.create(TkcText,65,235, 'text'=>'117', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,51,155,51,115,6,115,6,155, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '114' $floorItems2['114'] = i w.create(TkcText,28.5,135, 'text'=>'114', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,95,115,53,115,53,168,95,168, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '115' $floorItems2['115'] = i w.create(TkcText,74,141.5, 'text'=>'115', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,87,113,87,27,10,27,10,113, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '116' $floorItems2['116'] = i w.create(TkcText,48.5,70, 'text'=>'116', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,89,91,128,91,128,113,89,131, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '118' $floorItems2['118'] = i w.create(TkcText,108.5,102, 'text'=>'118', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,178,128,178,132,216,132,216,91, 163,91,163,112,149,112,149,128, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '120' $floorItems2['120'] = i w.create(TkcText,189.5,111.5, 'text'=>'120', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,79,193,87,193,87,169,136,169,136,192, 156,192,156,169,175,169,175,246,79,246, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '122' $floorItems2['122'] = i w.create(TkcText,131,207.5, 'text'=>'122', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,138,169,154,169,154,191,138,191, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '121' $floorItems2['121'] = i w.create(TkcText,146,180, 'text'=>'121', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,99,300,126,300,126,309,99,309, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '106A' $floorItems2['106A'] = i w.create(TkcText,112.5,304.5, 'text'=>'106A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,128,299,128,309,150,309,150,248,99,248,99,299, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '105' $floorItems2['105'] = i w.create(TkcText,124.5,278.5, 'text'=>'105', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,174,309,174,300,152,300,152,309, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '106B' $floorItems2['106B'] = i w.create(TkcText,163,304.5, 'text'=>'106B', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,176,299,176,309,216,309,216,248,152,248,152,299, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '104' $floorItems2['104'] = i w.create(TkcText,184,278.5, 'text'=>'104', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,138,385,138,337,91,337,91,385, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '108' $floorItems2['108'] = i w.create(TkcText,114.5,361, 'text'=>'108', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,256,337,140,337,140,385,256,385, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '107' $floorItems2['107'] = i w.create(TkcText,198,361, 'text'=>'107', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,300,353,300,329,260,329,260,353, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'Smoking' $floorItems2['Smoking'] = i w.create(TkcText,280,341, 'text'=>'Smoking', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,314,135,314,170,306,170,306,246,177,246,177,135, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '123' $floorItems2['123'] = i w.create(TkcText,245.5,190.5, 'text'=>'123', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,217,248,301,248,301,326,257,326,257,310,217,310, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '103' $floorItems2['103'] = i w.create(TkcText,259,287, 'text'=>'103', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,396,188,377,188,377,169,316,169,316,131,396,131, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '124' $floorItems2['124'] = i w.create(TkcText,356,150, 'text'=>'124', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,397,226,407,226,407,189,377,189,377,246,397,246, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '125' $floorItems2['125'] = i w.create(TkcText,392,217.5, 'text'=>'125', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,399,187,409,187,409,207,474,207,474,164,399,164, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '126' $floorItems2['126'] = i w.create(TkcText,436.5,185.5, 'text'=>'126', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,409,209,409,229,399,229,399,253, 486,253,486,239,474,239,474,209, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '127' $floorItems2['127'] = i w.create(TkcText,436.5,'231', 'text'=>'127', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,501,164,501,174,495,174,495,188, 490,188,490,204,476,204,476,164, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'MShower' $floorItems2['MShower'] = i w.create(TkcText,488.5,'184', 'text'=>'MShower', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,497,176,513,176,513,204,492,204,492,190,497,190, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'Closet' $floorItems2['Closet'] = i w.create(TkcText,502.5,190, 'text'=>'Closet', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,476,237,476,206,513,206,513,254,488,254,488,237, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'WShower' $floorItems2['WShower'] = i w.create(TkcText,494.5,230, 'text'=>'WShower', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,486,131,558,131,558,135,724,135,724,166, 697,166,697,275,553,275,531,254,515,254, 515,174,503,174,503,161,486,161, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '130' $floorItems2['130'] = i w.create(TkcText,638.5,205, 'text'=>'130', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,308,242,339,242,339,248,342,248, 342,246,397,246,397,276,393,276, 393,309,300,309,300,248,308,248, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '102' $floorItems2['102'] = i w.create(TkcText,367.5,278.5, 'text'=>'102', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,397,255,486,255,486,276,397,276, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '128' $floorItems2['128'] = i w.create(TkcText,441.5,265.5, 'text'=>'128', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,510,309,486,309,486,255,530,255, 552,277,561,277,561,325,510,325, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '129' $floorItems2['129'] = i w.create(TkcText,535.5,293, 'text'=>'129', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,696,281,740,281,740,387,642,387, 642,389,561,389,561,277,696,277, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '133' $floorItems2['133'] = i w.create(TkcText,628.5,335, 'text'=>'133', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,742,387,742,281,800,281,800,387, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '132' $floorItems2['132'] = i w.create(TkcText,771,334, 'text'=>'132', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,800,168,800,280,699,280,699,168, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '134' $floorItems2['134'] = i w.create(TkcText,749.5,224, 'text'=>'134', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,726,131,726,166,800,166,800,131, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '135' $floorItems2['135'] = i w.create(TkcText,763,148.5, 'text'=>'135', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,340,360,335,363,331,365,326,366,304,366, 304,312,396,312,396,288,400,288,404,288, 409,290,413,292,418,297,421,302,422,309, 421,318,417,325,411,330,405,332,397,333, 344,333,340,334,336,336,335,338,332,342, 331,347,332,351,334,354,336,357,341,359, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'Ramona Stair' $floorItems2['Ramona Stair'] = i w.create(TkcText,368,323, 'text'=>'Ramona Stair', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,30,23,30,5,93,5,98,5,104,7,110,10,116,16,119,20, 122,28,123,32,123,68,220,68,220,87,90,87,90,23, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'University Stair' $floorItems2['University Stair'] = i w.create(TkcText,155,77.5, 'text'=>'University Stair', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,282,37,295,40,312,49,323,56,337,70,352,56, 358,48,363,39,365,29,348,25,335,22,321,14, 300,5,283,1,260,0,246,0,242,2,236,4,231,8, 227,13,223,17,221,22,220,34,260,34, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'Plaza Stair' $floorItems2['Plaza Stair'] = i w.create(TkcText,317.5,28.5, 'text'=>'Plaza Stair', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,220,34,260,34,282,37,295,40,312,49, 323,56,337,70,350,83,365,94,377,100, 386,104,386,128,220,128, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = 'Plaza Deck' $floorItems2['Plaza Deck'] = i w.create(TkcText,303,81, 'text'=>'Plaza Deck', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,257,336,77,336,6,336,6,301,77,301,77,310,257,310, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '106' $floorItems2['106'] = i w.create(TkcText,131.5,318.5, 'text'=>'106', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) i = TkcPolygon.new(w,146,110,162,110,162,91,130,91,130,115,95,115, 95,128,114,128,114,151,157,151,157,153,112,153, 112,130,97,130,97,168,175,168,175,131,146,131, 'fill'=>'', 'tags'=>['floor1','room']) $floorLabels2[i.id] = '119' $floorItems2['119'] = i w.create(TkcText,143.5,133, 'text'=>'119', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor1','label']) w.create(TkcLine,155,191,155,189, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,155,177,155,169, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,96,129,96,169, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,78,169,176,169, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,176,247,176,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,340,206,307,206, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,340,187,340,170, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,340,210,340,201, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,340,247,340,224, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,340,241,307,241, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,376,246,376,170, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,307,247,307,170, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,376,170,307,170, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,315,129,315,170, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,147,129,176,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,202,133,176,133, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,398,129,315,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,258,352,258,387, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,60,387,60,391, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,0,337,0,391, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,60,391,0,391, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,3,114,3,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,258,387,60,387, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,52,237,52,273, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,52,189,52,225, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,52,140,52,177, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,395,306,395,311, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,531,254,398,254, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,475,178,475,238, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,502,162,398,162, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,398,129,398,188, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,383,188,376,188, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,408,188,408,194, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,398,227,398,254, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,408,227,398,227, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,408,222,408,227, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,408,206,408,210, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,408,208,475,208, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,484,278,484,311, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,484,311,508,311, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,508,327,508,311, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,559,327,508,327, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,644,391,559,391, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,644,389,644,391, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,514,205,475,205, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,496,189,496,187, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,559,129,484,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,484,162,484,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,725,133,559,133, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,559,129,559,133, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,725,149,725,167, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,725,129,802,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,802,389,802,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,739,167,802,167, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,396,188,408,188, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,0,337,9,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,58,337,21,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,43,391,43,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,105,337,75,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,91,387,91,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,154,337,117,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,139,387,139,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,227,337,166,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,258,337,251,337, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,258,328,302,328, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,302,355,302,311, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,395,311,302,311, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,484,278,395,278, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,395,294,395,278, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,473,278,473,275, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,473,256,473,254, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,533,257,531,254, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,553,276,551,274, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,698,276,553,276, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,559,391,559,327, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,802,389,644,389, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,741,314,741,389, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,698,280,698,167, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,707,280,698,280, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,802,280,731,280, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,741,280,741,302, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,698,167,727,167, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,725,137,725,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,514,254,514,175, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,496,175,514,175, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,502,175,502,162, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,475,166,475,162, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,496,176,496,175, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,491,189,496,189, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,491,205,491,189, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,487,238,475,238, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,487,240,487,238, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,487,252,487,254, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,315,133,304,133, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,256,133,280,133, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,78,247,270,247, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,307,247,294,247, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,214,133,232,133, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,217,247,217,266, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,217,309,217,291, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,217,309,172,309, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,154,309,148,309, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,175,300,175,309, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,151,300,175,300, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,151,247,151,309, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,78,237,78,265, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,78,286,78,309, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,106,309,78,309, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,130,309,125,309, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,99,309,99,247, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,127,299,99,299, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,127,309,127,299, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,155,191,137,191, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,137,169,137,191, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,78,171,78,169, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,78,190,78,218, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,86,192,86,169, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,86,192,78,192, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,52,301,3,301, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,52,286,52,301, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,52,252,3,252, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,52,203,3,203, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,3,156,52,156, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,8,25,8,114, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,63,114,3,114, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,75,114,97,114, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,108,114,129,114, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,129,114,129,89, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,52,114,52,128, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,132,89,88,89, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,88,25,88,89, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,88,114,88,89, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,218,89,144,89, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,147,111,147,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,162,111,147,111, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,162,109,162,111, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,162,96,162,89, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,218,89,218,94, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,218,89,218,119, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,8,25,88,25, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,258,337,258,328, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,113,129,96,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,302,355,258,355, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,386,104,386,129, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,377,100,386,104, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,365,94,377,100, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,350,83,365,94, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,337,70,350,83, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,337,70,323,56, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,312,49,323,56, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,295,40,312,49, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,282,37,295,40, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,260,34,282,37, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,253,34,260,34, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,386,128,386,104, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,113,152,156,152, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,113,152,156,152, 'fill'=>color, 'tags'=>['floor1','wall']) w.create(TkcLine,113,152,113,129, 'fill'=>color, 'tags'=>['floor1','wall']) end # floor2_fg2 -- # This method represents part of the floorplan database. When # invoked, it instantiates the foreground information for the second # floor (office outlines and numbers). # # Arguments: # w - The canvas window. # color - Color to use for drawing foreground information. def floor2_fg2(w,color) i = TkcPolygon.new(w,748,188,755,188,755,205,758,205,758,222, 800,222,800,168,748,168, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '238' $floorItems2['238'] = i w.create(TkcText,774,195, 'text'=>'238', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,726,188,746,188,746,166,800,166,800,131,726,131, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '237' $floorItems2['237'] = i w.create(TkcText,763,148.5, 'text'=>'237', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,497,187,497,204,559,204,559,324,641,324, 643,324,643,291,641,291,641,205,696,205, 696,291,694,291,694,314,715,314,715,291, 715,205,755,205,755,190,724,190,724,187, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '246' $floorItems2['246'] = i w.create(TkcText,600,264, 'text'=>'246', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,694,279,643,279,643,314,694,314, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '247' $floorItems2['247'] = i w.create(TkcText,668.5,296.5, 'text'=>'247', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,232,250,308,250,308,242,339,242,339,246, 397,246,397,255,476,255,476,250,482,250,559,250, 559,274,482,274,482,278,396,278,396,274,232,274, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '202' $floorItems2['202'] = i w.create(TkcText,285.5,260, 'text'=>'202', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,53,228,53,338,176,338,233,338,233,196, 306,196,306,180,175,180,175,169,156,169, 156,196,176,196,176,228, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '206' $floorItems2['206'] = i w.create(TkcText,143,267, 'text'=>'206', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,51,277,6,277,6,338,51,338, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '212' $floorItems2['212'] = i w.create(TkcText,28.5,307.5, 'text'=>'212', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,557,276,486,276,486,309,510,309,510,325,557,325, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '245' $floorItems2['245'] = i w.create(TkcText,521.5,300.5, 'text'=>'245', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,560,389,599,389,599,326,560,326, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '244' $floorItems2['244'] = i w.create(TkcText,579.5,357.5, 'text'=>'244', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,601,389,601,326,643,326,643,389, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '243' $floorItems2['243'] = i w.create(TkcText,622,357.5, 'text'=>'243', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,688,316,645,316,645,365,688,365, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '242' $floorItems2['242'] = i w.create(TkcText,666.5,340.5, 'text'=>'242', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,802,367,759,367,759,226,802,226, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = 'Barbecue Deck' $floorItems2['Barbecue Deck'] = i w.create(TkcText,780.5,296.5, 'text'=>'Barbecue Deck', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,755,262,755,314,717,314,717,262, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '240' $floorItems2['240'] = i w.create(TkcText,736,288, 'text'=>'240', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,755,316,689,316,689,365,755,365, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '241' $floorItems2['241'] = i w.create(TkcText,722,340.5, 'text'=>'241', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,755,206,717,206,717,261,755,261, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '239' $floorItems2['239'] = i w.create(TkcText,736,233.5, 'text'=>'239', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,695,277,643,277,643,206,695,206, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '248' $floorItems2['248'] = i w.create(TkcText,669,241.5, 'text'=>'248', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,676,135,676,185,724,185,724,135, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '236' $floorItems2['236'] = i w.create(TkcText,700,160, 'text'=>'236', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,675,135,635,135,635,145,628,145,628,185,675,185, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '235' $floorItems2['235'] = i w.create(TkcText,651.5,160, 'text'=>'235', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,626,143,633,143,633,135,572,135, 572,143,579,143,579,185,626,185, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '234' $floorItems2['234'] = i w.create(TkcText,606,160, 'text'=>'234', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,557,135,571,135,571,145,578,145, 578,185,527,185,527,131,557,131, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '233' $floorItems2['233'] = i w.create(TkcText,552.5,158, 'text'=>'233', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,476,249,557,249,557,205,476,205, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '230' $floorItems2['230'] = i w.create(TkcText,516.5,227, 'text'=>'230', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,476,164,486,164,486,131,525,131,525,185,476,185, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '232' $floorItems2['232'] = i w.create(TkcText,500.5,158, 'text'=>'232', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,476,186,495,186,495,204,476,204, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '229' $floorItems2['229'] = i w.create(TkcText,485.5,195, 'text'=>'229', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,474,207,409,207,409,187,399,187,399,164,474,164, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '227' $floorItems2['227'] = i w.create(TkcText,436.5,185.5, 'text'=>'227', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,399,228,399,253,474,253,474,209,409,209,409,228, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '228' $floorItems2['228'] = i w.create(TkcText,436.5,231, 'text'=>'228', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,397,246,397,226,407,226,407,189,377,189,377,246, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '226' $floorItems2['226'] = i w.create(TkcText,392,217.5, 'text'=>'226', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,377,169,316,169,316,131,397,131,397,188,377,188, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '225' $floorItems2['225'] = i w.create(TkcText,356.5,150, 'text'=>'225', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,234,198,306,198,306,249,234,249, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '224' $floorItems2['224'] = i w.create(TkcText,270,223.5, 'text'=>'224', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,270,179,306,179,306,170,314,170,314,135,270,135, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '223' $floorItems2['223'] = i w.create(TkcText,292,157, 'text'=>'223', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,268,179,221,179,221,135,268,135, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '222' $floorItems2['222'] = i w.create(TkcText,244.5,157, 'text'=>'222', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,177,179,219,179,219,135,177,135, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '221' $floorItems2['221'] = i w.create(TkcText,198,157, 'text'=>'221', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,299,327,349,327,349,284,341,284,341,276,299,276, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '204' $floorItems2['204'] = i w.create(TkcText,324,301.5, 'text'=>'204', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,234,276,297,276,297,327,257,327,257,338,234,338, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '205' $floorItems2['205'] = i w.create(TkcText,265.5,307, 'text'=>'205', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,256,385,256,340,212,340,212,385, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '207' $floorItems2['207'] = i w.create(TkcText,234,362.5, 'text'=>'207', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,210,340,164,340,164,385,210,385, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '208' $floorItems2['208'] = i w.create(TkcText,187,362.5, 'text'=>'208', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,115,340,162,340,162,385,115,385, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '209' $floorItems2['209'] = i w.create(TkcText,138.5,362.5, 'text'=>'209', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,89,228,89,156,53,156,53,228, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '217' $floorItems2['217'] = i w.create(TkcText,71,192, 'text'=>'217', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,89,169,97,169,97,190,89,190, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '217A' $floorItems2['217A'] = i w.create(TkcText,93,179.5, 'text'=>'217A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,89,156,89,168,95,168,95,135,53,135,53,156, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '216' $floorItems2['216'] = i w.create(TkcText,71,145.5, 'text'=>'216', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,51,179,51,135,6,135,6,179, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '215' $floorItems2['215'] = i w.create(TkcText,28.5,157, 'text'=>'215', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,51,227,6,227,6,180,51,180, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '214' $floorItems2['214'] = i w.create(TkcText,28.5,203.5, 'text'=>'214', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,51,275,6,275,6,229,51,229, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '213' $floorItems2['213'] = i w.create(TkcText,28.5,252, 'text'=>'213', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,114,340,67,340,67,385,114,385, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '210' $floorItems2['210'] = i w.create(TkcText,90.5,362.5, 'text'=>'210', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,59,389,59,385,65,385,65,340,1,340,1,389, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '211' $floorItems2['211'] = i w.create(TkcText,33,364.5, 'text'=>'211', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,393,309,350,309,350,282,342,282,342,276,393,276, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '203' $floorItems2['203'] = i w.create(TkcText,367.5,292.5, 'text'=>'203', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,99,191,91,191,91,226,174,226,174,198, 154,198,154,192,109,192,109,169,99,169, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '220' $floorItems2['220'] = i w.create(TkcText,132.5,208.5, 'text'=>'220', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,339,205,307,205,307,171,339,171, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = 'Priv Lift2' $floorItems2['Priv Lift2'] = i w.create(TkcText,323,188, 'text'=>'Priv Lift2', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,307,240,339,240,339,206,307,206, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = 'Pub Lift 2' $floorItems2['Pub Lift 2'] = i w.create(TkcText,323,223, 'text'=>'Pub Lift 2', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,175,168,97,168,97,131,175,131, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '218' $floorItems2['218'] = i w.create(TkcText,136,149.5, 'text'=>'218', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,154,191,111,191,111,169,154,169, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '219' $floorItems2['219'] = i w.create(TkcText,132.5,180, 'text'=>'219', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) i = TkcPolygon.new(w,375,246,375,172,341,172,341,246, 'fill'=>'', 'tags'=>['floor2','room']) $floorLabels2[i.id] = '201' $floorItems2['201'] = i w.create(TkcText,358,209, 'text'=>'201', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor2','label']) w.create(TkcLine,641,186,678,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,757,350,757,367, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,634,133,634,144, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,634,144,627,144, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,572,133,572,144, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,572,144,579,144, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,398,129,398,162, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,174,197,175,197, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,175,197,175,227, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,757,206,757,221, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,396,188,408,188, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,727,189,725,189, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,747,167,802,167, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,747,167,747,189, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,755,189,739,189, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,769,224,757,224, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,802,224,802,129, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,802,129,725,129, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,725,189,725,129, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,725,186,690,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,676,133,676,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,627,144,627,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,629,186,593,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,579,144,579,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,559,129,559,133, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,725,133,559,133, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,484,162,484,129, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,559,129,484,129, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,526,129,526,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,540,186,581,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,528,186,523,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,511,186,475,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,496,190,496,186, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,496,205,496,202, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,475,205,527,205, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,558,205,539,205, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,558,205,558,249, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,558,249,475,249, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,662,206,642,206, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,695,206,675,206, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,695,278,642,278, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,642,291,642,206, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,695,291,695,206, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,716,208,716,206, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,757,206,716,206, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,757,221,757,224, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,793,224,802,224, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,757,262,716,262, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,716,220,716,264, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,716,315,716,276, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,757,315,703,315, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,757,325,757,224, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,757,367,644,367, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,689,367,689,315, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,647,315,644,315, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,659,315,691,315, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,600,325,600,391, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,627,325,644,325, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,644,391,644,315, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,615,325,575,325, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,644,391,558,391, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,563,325,558,325, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,558,391,558,314, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,558,327,508,327, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,558,275,484,275, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,558,302,558,275, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,508,327,508,311, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,484,311,508,311, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,484,275,484,311, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,475,208,408,208, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,408,206,408,210, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,408,222,408,227, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,408,227,398,227, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,398,227,398,254, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,408,188,408,194, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,383,188,376,188, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,398,188,398,162, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,398,162,484,162, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,475,162,475,254, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,398,254,475,254, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,484,280,395,280, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,395,311,395,275, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,307,197,293,197, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,278,197,233,197, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,233,197,233,249, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,307,179,284,179, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,233,249,278,249, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,269,179,269,133, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,220,179,220,133, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,155,191,110,191, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,90,190,98,190, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,98,169,98,190, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,52,133,52,165, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,52,214,52,177, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,52,226,52,262, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,52,274,52,276, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,234,275,234,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,226,339,258,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,211,387,211,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,214,339,177,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,258,387,60,387, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,3,133,3,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,165,339,129,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,117,339,80,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,68,339,59,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,0,339,46,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,60,391,0,391, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,0,339,0,391, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,60,387,60,391, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,258,329,258,387, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,350,329,258,329, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,395,311,350,311, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,398,129,315,129, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,176,133,315,133, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,176,129,96,129, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,3,133,96,133, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,66,387,66,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,115,387,115,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,163,387,163,339, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,234,275,276,275, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,288,275,309,275, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,298,275,298,329, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,341,283,350,283, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,321,275,341,275, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,375,275,395,275, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,315,129,315,170, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,376,170,307,170, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,307,250,307,170, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,376,245,376,170, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,340,241,307,241, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,340,245,340,224, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,340,210,340,201, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,340,187,340,170, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,340,206,307,206, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,293,250,307,250, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,271,179,238,179, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,226,179,195,179, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,176,129,176,179, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,182,179,176,179, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,174,169,176,169, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,162,169,90,169, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,96,169,96,129, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,175,227,90,227, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,90,190,90,227, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,52,179,3,179, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,52,228,3,228, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,52,276,3,276, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,155,177,155,169, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,110,191,110,169, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,155,189,155,197, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,350,283,350,329, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,162,197,155,197, 'fill'=>color, 'tags'=>['floor2','wall']) w.create(TkcLine,341,275,341,283, 'fill'=>color, 'tags'=>['floor2','wall']) end # floor2_fg3 -- # This method represents part of the floorplan database. When # invoked, it instantiates the foreground information for the third # floor (office outlines and numbers). # # Arguments: # w - The canvas window. # color - Color to use for drawing foreground information. def floor2_fg3(w,color) i = TkcPolygon.new(w,89,228,89,180,70,180,70,228, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '316' $floorItems2['316'] = i w.create(TkcText,79.5,204, 'text'=>'316', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,115,368,162,368,162,323,115,323, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '309' $floorItems2['309'] = i w.create(TkcText,138.5,345.5, 'text'=>'309', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,164,323,164,368,211,368,211,323, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '308' $floorItems2['308'] = i w.create(TkcText,187.5,345.5, 'text'=>'308', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,256,368,212,368,212,323,256,323, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '307' $floorItems2['307'] = i w.create(TkcText,234,345.5, 'text'=>'307', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,244,276,297,276,297,327,260,327,260,321,244,321, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '305' $floorItems2['305'] = i w.create(TkcText,270.5,301.5, 'text'=>'305', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,251,219,251,203,244,203,244,219, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '324B' $floorItems2['324B'] = i w.create(TkcText,247.5,211, 'text'=>'324B', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,251,249,244,249,244,232,251,232, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '324A' $floorItems2['324A'] = i w.create(TkcText,247.5,240.5, 'text'=>'324A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,223,135,223,179,177,179,177,135, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '320' $floorItems2['320'] = i w.create(TkcText,200,157, 'text'=>'320', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,114,368,114,323,67,323,67,368, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '310' $floorItems2['310'] = i w.create(TkcText,90.5,345.5, 'text'=>'310', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,23,277,23,321,68,321,68,277, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '312' $floorItems2['312'] = i w.create(TkcText,45.5,299, 'text'=>'312', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,23,229,68,229,68,275,23,275, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '313' $floorItems2['313'] = i w.create(TkcText,45.5,252, 'text'=>'313', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,68,227,23,227,23,180,68,180, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '314' $floorItems2['314'] = i w.create(TkcText,40.5,203.5, 'text'=>'314', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,95,179,95,135,23,135,23,179, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '315' $floorItems2['315'] = i w.create(TkcText,59,157, 'text'=>'315', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,99,226,99,204,91,204,91,226, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '316B' $floorItems2['316B'] = i w.create(TkcText,95,215, 'text'=>'316B', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,91,202,99,202,99,180,91,180, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '316A' $floorItems2['316A'] = i w.create(TkcText,95,191, 'text'=>'316A', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,97,169,109,169,109,192,154,192,154,198, 174,198,174,226,101,226,101,179,97,179, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '319' $floorItems2['319'] = i w.create(TkcText,141.5,209, 'text'=>'319', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,65,368,58,368,58,389,1,389,1,333,23,333,23,323,65,323, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '311' $floorItems2['311'] = i w.create(TkcText,29.5,361, 'text'=>'311', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,154,191,111,191,111,169,154,169, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '318' $floorItems2['318'] = i w.create(TkcText,132.5,180, 'text'=>'318', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,175,168,97,168,97,131,175,131, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '317' $floorItems2['317'] = i w.create(TkcText,136,149.5, 'text'=>'317', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,274,194,274,221,306,221,306,194, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '323' $floorItems2['323'] = i w.create(TkcText,290,207.5, 'text'=>'323', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,306,222,274,222,274,249,306,249, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '325' $floorItems2['325'] = i w.create(TkcText,290,235.5, 'text'=>'325', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,263,179,224,179,224,135,263,135, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '321' $floorItems2['321'] = i w.create(TkcText,243.5,157, 'text'=>'321', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,314,169,306,169,306,192,273,192, 264,181,264,135,314,135, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '322' $floorItems2['322'] = i w.create(TkcText,293.5,163.5, 'text'=>'322', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,307,240,339,240,339,206,307,206, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = 'Pub Lift3' $floorItems2['Pub Lift3'] = i w.create(TkcText,323,223, 'text'=>'Pub Lift3', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,339,205,307,205,307,171,339,171, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = 'Priv Lift3' $floorItems2['Priv Lift3'] = i w.create(TkcText,323,188, 'text'=>'Priv Lift3', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,350,284,376,284,376,276,397,276,397,309,350,309, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '303' $floorItems2['303'] = i w.create(TkcText,373.5,292.5, 'text'=>'303', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,272,203,272,249,252,249,252,230, 244,230,244,221,252,221,252,203, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '324' $floorItems2['324'] = i w.create(TkcText,262,226, 'text'=>'324', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,299,276,299,327,349,327,349,284,341,284,341,276, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '304' $floorItems2['304'] = i w.create(TkcText,324,301.5, 'text'=>'304', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,375,246,375,172,341,172,341,246, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '301' $floorItems2['301'] = i w.create(TkcText,358,209, 'text'=>'301', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,397,246,377,246,377,185,397,185, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '327' $floorItems2['327'] = i w.create(TkcText,387,215.5, 'text'=>'327', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,316,131,316,169,377,169,377,185,397,185,397,131, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '326' $floorItems2['326'] = i w.create(TkcText,365.5,150, 'text'=>'326', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,308,251,242,251,242,274,342,274,342,282,375, 282, 375,274,397,274,397,248,339,248,339,242,308,242, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '302' $floorItems2['302'] = i w.create(TkcText,319.5,261, 'text'=>'302', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) i = TkcPolygon.new(w,70,321,242,321,242,200,259,200,259,203,272,203, 272,193,263,180,242,180,175,180,175,169,156,169, 156,196,177,196,177,228,107,228,70,228,70,275,107,275, 107,248,160,248,160,301,107,301,107,275,70,275, 'fill'=>'', 'tags'=>['floor3','room']) $floorLabels2[i.id] = '306' $floorItems2['306'] = i w.create(TkcText,200.5,284.5, 'text'=>'306', 'fill'=>color, 'anchor'=>'c', 'tags'=>['floor3','label']) w.create(TkcLine,341,275,341,283, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,162,197,155,197, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,396,247,399,247, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,399,129,399,311, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,258,202,243,202, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,350,283,350,329, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,251,231,243,231, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,243,220,251,220, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,243,250,243,202, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,155,197,155,190, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,110,192,110,169, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,155,192,110,192, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,155,177,155,169, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,176,197,176,227, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,69,280,69,274, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,21,276,69,276, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,69,262,69,226, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,21,228,69,228, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,21,179,75,179, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,69,179,69,214, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,90,220,90,227, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,90,204,90,202, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,90,203,100,203, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,90,187,90,179, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,90,227,176,227, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,100,179,100,227, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,100,179,87,179, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,96,179,96,129, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,162,169,96,169, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,173,169,176,169, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,182,179,176,179, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,176,129,176,179, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,195,179,226,179, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,224,133,224,179, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,264,179,264,133, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,238,179,264,179, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,273,207,273,193, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,273,235,273,250, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,273,224,273,219, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,273,193,307,193, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,273,222,307,222, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,273,250,307,250, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,384,247,376,247, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,340,206,307,206, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,340,187,340,170, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,340,210,340,201, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,340,247,340,224, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,340,241,307,241, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,376,247,376,170, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,307,250,307,170, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,376,170,307,170, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,315,129,315,170, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,376,283,366,283, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,376,283,376,275, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,399,275,376,275, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,341,275,320,275, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,341,283,350,283, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,298,275,298,329, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,308,275,298,275, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,243,322,243,275, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,243,275,284,275, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,258,322,226,322, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,212,370,212,322, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,214,322,177,322, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,163,370,163,322, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,165,322,129,322, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,84,322,117,322, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,71,322,64,322, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,115,322,115,370, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,66,322,66,370, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,52,322,21,322, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,21,331,0,331, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,21,331,21,133, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,96,133,21,133, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,176,129,96,129, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,315,133,176,133, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,315,129,399,129, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,399,311,350,311, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,350,329,258,329, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,258,322,258,370, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,60,370,258,370, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,60,370,60,391, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,0,391,0,331, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,60,391,0,391, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,307,250,307,242, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,273,250,307,250, 'fill'=>color, 'tags'=>['floor3','wall']) w.create(TkcLine,258,250,243,250, 'fill'=>color, 'tags'=>['floor3','wall']) end # Below is the "main program" that creates the floorplan demonstration. # toplevel widget ¸ߤк if defined?($floor2_demo) && $floor2_demo $floor2_demo.destroy $floor2_demo = nil end # demo Ѥ toplevel widget $floor2_demo = TkToplevel.new {|w| title("Floorplan Canvas Demonstration 2") iconname("Floorplan2") positionWindow(w) geometry('+20+20') minsize(100,100) } base_frame = TkFrame.new($floor2_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'8i', 'justify'=>'left', 'text'=>"Υɥˤϥǥ륨åץȼҤΥꥵܥȥ (DECWRL) δּ꤬񤫤줿Х widget äƤޤ 3ƤǡˤΤ1ʬ򡢤Ĥޤꤽδּ꤬ɽ褦ˤʤäƤޤ볬򤹤ˤϡξǥޥκܥ򥯥åƤޥ򤵤Ƥ볬ξưȡβˤοѤꡢֹ椬ֹ:ץȥɽޤޤȥֹ񤯤ȤοѤޤ"){ pack('side'=>'top') } # frame $floor2_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $floor2_demo $floor2_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'floor2'} }.pack('side'=>'left', 'expand'=>'yes') } $floor2_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # ѿ $floorLabels2 = {} $floorItems2 = {} # canvas if $tk_version =~ /^4\.[01]/ $floor2_canvas_frame = TkFrame.new(base_frame,'bd'=>2,'relief'=>'sunken', 'highlightthickness'=>2) $floor2_canvas = TkCanvas.new($floor2_canvas_frame, 'width'=>900, 'height'=>500, 'borderwidth'=>0, 'highlightthickness'=>0) {|c| TkScrollbar.new(base_frame, 'orient'=>'horiz', 'command'=>proc{|*args| c.xview(*args)}){|hs| c.xscrollcommand(proc{|first,last| hs.set first,last}) pack('side'=>'bottom', 'fill'=>'x') } TkScrollbar.new(base_frame, 'command'=>proc{|*args| c.yview(*args)}){|vs| c.yscrollcommand(proc{|first,last| vs.set first,last}) pack('side'=>'right', 'fill'=>'y') } } $floor2_canvas_frame.pack('side'=>'top','fill'=>'both', 'expand'=>'yes') $floor2_canvas.pack('expand'=>'yes', 'fill'=>'both') else TkFrame.new(base_frame) {|f| pack('side'=>'top', 'fill'=>'both', 'expand'=>'yes') h = TkScrollbar.new(f, 'highlightthickness'=>0, 'orient'=>'horizontal') v = TkScrollbar.new(f, 'highlightthickness'=>0, 'orient'=>'vertical') TkFrame.new(f, 'bd'=>2, 'relief'=>'sunken') {|f1| $floor2_canvas = TkCanvas.new(f1, 'width'=>900, 'height'=>500, 'borderwidth'=>0, 'highlightthickness'=>0) { xscrollcommand(proc{|first,last| h.set first,last}) yscrollcommand(proc{|first,last| v.set first,last}) pack('expand'=>'yes', 'fill'=>'both') } grid('padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') } v.grid('padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>1, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') h.grid('padx'=>1, 'pady'=>1, 'row'=>1, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') TkGrid.rowconfigure(f, 0, 'weight'=>1, 'minsize'=>0) TkGrid.columnconfigure(f, 0, 'weight'=>1, 'minsize'=>0) pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1) v.command(proc{|*args| $floor2_canvas.yview(*args)}) h.command(proc{|*args| $floor2_canvas.xview(*args)}) } end # Create an entry for displaying and typing in current room. $currentRoom2 = TkVariable.new $floor2_entry = TkEntry.new($floor2_canvas, 'width'=>10, 'relief'=>'sunken', 'bd'=>2, 'textvariable'=>$currentRoom2) # Choose colors, then fill in the floorplan. $floor2_colors = {} if TkWinfo.depth($floor2_canvas) > 1 $floor2_colors['bg1'] = '#a9c1da' $floor2_colors['outline1'] = '#77889a' $floor2_colors['bg2'] = '#9ab0c6' $floor2_colors['outline2'] = '#687786' $floor2_colors['bg3'] = '#8ba0b3' $floor2_colors['outline3'] = '#596673' $floor2_colors['offices'] = 'Black' $floor2_colors['active'] = '#c4d1df' else $floor2_colors['bg1'] = 'white' $floor2_colors['outline1'] = 'black' $floor2_colors['bg2'] = 'white' $floor2_colors['outline2'] = 'black' $floor2_colors['bg3'] = 'white' $floor2_colors['outline3'] = 'black' $floor2_colors['offices'] = 'Black' $floor2_colors['active'] = 'black' end $activeFloor2 = '' floorDisplay2 $floor2_canvas,3 # Set up event bindings for canvas: $floor2_canvas.itembind('floor1', '1', proc{floorDisplay2 $floor2_canvas,1}) $floor2_canvas.itembind('floor2', '1', proc{floorDisplay2 $floor2_canvas,2}) $floor2_canvas.itembind('floor3', '1', proc{floorDisplay2 $floor2_canvas,3}) $floor2_canvas.itembind('room', 'Enter', proc{newRoom2 $floor2_canvas}) $floor2_canvas.itembind('room', 'Leave', proc{$currentRoom2.value = ''}) $floor2_canvas.bind('2', proc{|x,y| $floor2_canvas.scan_mark x,y}, '%x %y') $floor2_canvas.bind('B2-Motion', proc{|x,y| $floor2_canvas.scan_dragto x,y}, '%x %y') $floor2_canvas.bind('Destroy', proc{$currentRoom2.unset}) $currentRoom2.value = '' $currentRoom2.trace('w',proc{roomChanged2 $floor2_canvas}) ================================================ FILE: ext/tk/sample/demos-jp/form.rb ================================================ # -*- coding: euc-jp -*- # # form widget demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($form_demo) && $form_demo $form_demo.destroy $form_demo = nil end # demo Ѥ toplevel widget $form_demo = TkToplevel.new {|w| title("Form Demonstration") iconname("form") positionWindow(w) } base_frame = TkFrame.new($form_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "ΥɥϴñʥեѤˤʤäƤơޤޤʥȥϤǤޤ֤ǥȥؤǤޤ" } msg.pack('side'=>'top', 'fill'=>'x') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $form_demo $form_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'form'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # entry form_data = [] (1..5).each{|i| f = TkFrame.new(base_frame, 'bd'=>2) e = TkEntry.new(f, 'relief'=>'sunken', 'width'=>40) l = TkLabel.new(f) e.pack('side'=>'right') l.pack('side'=>'left') form_data[i] = {'frame'=>f, 'entry'=>e, 'label'=>l} } # ʸ form_data[1]['label'].text('̾:') form_data[2]['label'].text(':') form_data[5]['label'].text(':') # pack (1..5).each{|i| form_data[i]['frame'].pack('side'=>'top', 'fill'=>'x')} ================================================ FILE: ext/tk/sample/demos-jp/goldberg.rb ================================================ # -*- coding: euc-jp -*- # # Ruby/Tk Goldverg demo (called by 'widget') # # Based on Tcl/Tk8.5a2 widget demos. # The following is the original comment of TkGoldberg.tcl. # #>>##+################################################################# #>># #>># TkGoldberg.tcl #>># by Keith Vetter, March 13, 2003 #>># #>># "Man will always find a difficult means to perform a simple task" #>># Rube Goldberg #>># #>># Reproduced here with permission. #>># #>>##+################################################################# #>># #>># Keith Vetter 2003-03-21: this started out as a simple little program #>># but was so much fun that it grew and grew. So I apologize about the #>># size but I just couldn't resist sharing it. #>># #>># This is a whizzlet that does a Rube Goldberg type animation, the #>># design of which comes from an New Years e-card from IncrediMail. #>># That version had nice sound effects which I eschewed. On the other #>># hand, that version was in black and white (actually dark blue and #>># light blue) and this one is fully colorized. #>># #>># One thing I learned from this project is that drawing filled complex #>># objects on a canvas is really hard. More often than not I had to #>># draw each item twice--once with the desired fill color but no #>># outline, and once with no fill but with the outline. Another trick #>># is erasing by drawing with the background color. Having a flood fill #>># command would have been extremely helpful. #>># #>># Two wiki pages were extremely helpful: Drawing rounded rectangles #>># which I generalized into Drawing rounded polygons, and regular #>># polygons which allowed me to convert ovals and arcs into polygons #>># which could then be rotated (see Canvas Rotation). I also wrote #>># Named Colors to aid in the color selection. #>># #>># I could comment on the code, but it's just 26 state machines with #>># lots of canvas create and move calls. if defined?($goldberg_demo) && $goldberg_demo $goldberg_demo.destroy $goldberg_demo = nil end # demo toplevel widget $goldberg_demo = TkToplevel.new {|w| title("Tk Goldberg (demonstration)") iconname("goldberg") # positionWindow(w) } base_frame = TkFrame.new($goldberg_demo).pack(:fill=>:both, :expand=>true) =begin # label msg = TkLabel.new($goldberg_demo) { font 'Arial 10' wraplength '4i' justify 'left' text "ϡʤʬΥ˥᡼򤤤ȤΤˤǤ뤫򼨤ȤΤΥǥǤܡ򥯥åʪưϤޤ\n\n\"Man will always find a difficult means to perform a simple task\"\n - Rube Goldberg" } msg.pack('side'=>'top') =end =begin # frame TkFrame.new($goldberg_demo) {|frame| TkButton.new(frame) { text 'Ĥ' command proc{ tmppath = $goldberg_demo $goldberg_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'goldberg'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') =end ######################################### class TkGoldberg_Demo def initialize(parent) @parent = parent @S = {} @S['title'] = 'Tk Goldberg' @S['speed'] = TkVariable.new(5) @S['cnt'] = TkVariable.new(0) # @S['message'] = TkVariable.new("\\nWelcome\\nto\\nRuby/Tk") @S['message'] = TkVariable.new("\\n 褦\\nRuby/Tk\\n\\n") @S['pause'] = TkVariable.new @S['details'] = TkVariable.new(true) @S['mode'] = TkVariable.new(:MSTART, :symbol) # :MSTART, :MGO, :MPAUSE, :MSSTEP, :MBSTEP, :MDONE, :MDEBUG # 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 @speed = [1, 10, 20, 50, 80, 100, 150, 200, 300, 400, 500] # colors @C = {} @C['fg'] = 'black' # @C['bg'] = 'gray75' @C['bg'] = 'cornflowerblue' @C['0'] = 'white'; @C['1a'] = 'darkgreen'; @C['1b'] = 'yellow' @C['2'] = 'red'; @C['3a'] = 'green'; @C['3b'] = 'darkblue' @C['4'] = @C['fg']; @C['5a'] = 'brown'; @C['5b'] = 'white' @C['6'] = 'magenta'; @C['7'] = 'green'; @C['8'] = @C['fg'] @C['9'] = 'blue4'; @C['10a'] = 'white'; @C['10b'] = 'cyan' @C['11a'] = 'yellow'; @C['11b'] = 'mediumblue'; @C['12'] = 'tan2' @C['13a'] = 'yellow'; @C['13b'] = 'red'; @C['14'] = 'white' @C['15a'] = 'green'; @C['15b'] = 'yellow'; @C['16'] = 'gray65' @C['17'] = '#A65353'; @C['18'] = @C['fg']; @C['19'] = 'gray50' @C['20'] = 'cyan'; @C['21'] = 'gray65'; @C['22'] = @C['20'] @C['23a'] = 'blue'; @C['23b'] = 'red'; @C['23c'] = 'yellow' @C['24a'] = 'red'; @C['24b'] = 'white'; @STEP = TkVariable.new_hash @STEP.default_value_type = :numeric @XY = {} @XY6 = { '-1'=>[366, 207], '-2'=>[349, 204], '-3'=>[359, 193], '-4'=>[375, 192], '-5'=>[340, 190], '-6'=>[349, 177], '-7'=>[366, 177], '-8'=>[380, 176], '-9'=>[332, 172], '-10'=>[342, 161], '-11'=>[357, 164], '-12'=>[372, 163], '-13'=>[381, 149], '-14'=>[364, 151], '-15'=>[349, 146], '-16'=>[333, 148], '0'=>[357, 219], '1'=>[359, 261], '2'=>[359, 291], '3'=>[359, 318], '4'=>[361, 324], '5'=>[365, 329], '6'=>[367, 334], '7'=>[367, 340], '8'=>[366, 346], '9'=>[364, 350], '10'=>[361, 355], '11'=>[359, 370], '12'=>[359, 391], '13,0'=>[360, 456], '13,1'=>[376, 456], '13,2'=>[346, 456], '13,3'=>[330, 456], '13,4'=>[353, 444], '13,5'=>[368, 443], '13,6'=>[339, 442], '13,7'=>[359, 431], '13,8'=>[380, 437], '13,9'=>[345, 428], '13,10'=>[328, 434], '13,11'=>[373, 424], '13,12'=>[331, 420], '13,13'=>[360, 417], '13,14'=>[345, 412], '13,15'=>[376, 410], '13,16'=>[360, 403] } @timer = TkTimer.new(@speed[@S['speed'].numeric]){|timer| timer.set_interval(go) } do_display reset # Start everything going @timer.start end def do_display() @ctrl = TkFrame.new(@parent, :relief=>:ridge, :bd=>2, :padx=>5, :pady=>5) @screen = TkFrame.new(@parent, :bd=>2, :relief=>:raised).pack(:side=>:left, :fill=>:both, :expand=>true) @canvas = TkCanvas.new(@parent, :width=>850, :height=>700, :bg=>@C['bg'], :highlightthickness=>0){ scrollregion([0, 0, 1000, 1000]) # Kludge to move everything up yview_moveto(0.05) }.pack(:in=>@screen, :side=>:top, :fill=>:both, :expand=>true) @canvas.bind('3'){ @pause.invoke } @canvas.bind('Destroy'){ @timer.stop } do_ctrl_frame do_detail_frame # msg = TkLabel.new(@parent, :bg=>@C['bg'], :fg=>'white') { msg = Tk::Label.new(@parent, :bg=>@C['bg'], :fg=>'white') { font 'Arial 10' wraplength 600 justify 'left' text "ϡʤʬΥ˥᡼򤤤ȤΤˤǤ뤫򼨤ȤΤΥǥǤܡ򥯥åʪưϤޤ\n\"Man will always find a difficult means to perform a simple task\" - Rube Goldberg" } msg.place(:in=>@canvas, :relx=>0, :rely=>0, :anchor=>:nw) frame = TkFrame.new(@parent, :bg=>@C['bg']) # TkButton.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) { Tk::Button.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) { text 'Ĥ' command proc{ tmppath = $goldberg_demo $goldberg_demo = nil tmppath.destroy } }.pack('side'=>'left') # TkButton.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) { Tk::Button.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) { text 'ɻ' command proc{showCode 'goldberg'} }.pack('side'=>'left', 'padx'=>5) # @show = TkButton.new(frame, :text=>'>>', :command=>proc{show_ctrl}, @show = Tk::Button.new(frame, :text=>'>>', :command=>proc{show_ctrl}, :bg=>@C['bg'], :activebackground=>@C['bg']) @show.pack('side'=>'left') frame.place(:in=>@canvas, :relx=>1, :rely=>0, :anchor=>:ne) Tk.update end def do_ctrl_frame @start = Tk::Button.new(@parent, :text=>'Start', :bd=>6, :command=>proc{do_button(0)}) if font = @start['font'] @start.font(font.weight('bold')) end @pause = TkCheckbutton.new(@parent, :text=>'Pause', :font=>font, :command=>proc{do_button(1)}, :relief=>:raised, :variable=>@S['pause']) @step = TkButton.new(@parent, :text=>'Single Step', :font=>font, :command=>proc{do_button(2)}) @bstep = TkButton.new(@parent, :text=>'Big Step', :font=>font, :command=>proc{do_button(4)}) @reset = TkButton.new(@parent, :text=>'Reset', :font=>font, :command=>proc{do_button(3)}) @details = TkFrame.new(@parent, :bd=>2, :relief=>:ridge) @detail = TkCheckbutton.new(@parent, :text=>'Details', :font=>font, :relief=>:raised, :variable=>@S['details']) @msg_entry = TkEntry.new(@parent, :textvariable=>@S['message'], :justify=>:center) @speed_scale = TkScale.new(@parent, :orient=>:horizontal, :from=>1, :to=>10, :font=>font, :variable=>@S['speed'], :bd=>2, :relief=>:ridge, :showvalue=>false) @about = TkButton.new(@parent, :text=>'About', :command=>proc{about}, :font=>font) Tk.grid(@start, :in=>@ctrl, :row=>0, :sticky=>:ew) @ctrl.grid_rowconfigure(1, :minsize=>10) Tk.grid(@pause, :in=>@ctrl, :row=>2, :sticky=>:ew) Tk.grid(@step, :in=>@ctrl, :sticky=>:ew) Tk.grid(@bstep, :in=>@ctrl, :sticky=>:ew) Tk.grid(@reset, :in=>@ctrl, :sticky=>:ew) @ctrl.grid_rowconfigure(10, :minsize=>20) Tk.grid(@details, :in=>@ctrl, :row=>11, :sticky=>:ew) Tk.grid(@detail, :in=>@details, :row=>0, :sticky=>:ew) @ctrl.grid_rowconfigure(50, :weight=>1) @S['mode'].trace('w', proc{|*args| active_GUI(*args)}) @S['details'].trace('w', proc{|*args| active_GUI(*args)}) @S['speed'].trace('w', proc{|*args| active_GUI(*args)}) Tk.grid(@msg_entry, :in=>@ctrl, :row=>98, :sticky=>:ew, :pady=>5) Tk.grid(@speed_scale, :in=>@ctrl, :row=>99, :sticky=>:ew) Tk.grid(@about, :in=>@ctrl, :row=>100, :sticky=>:ew) @reset.bind('3'){@S['mode'].value = -1} # Debugging end def do_detail_frame @f_details = TkFrame.new(@details) @label = TkLabel.new(@f_details, :textvariable=>@S['cnt'], :bd=>1, :relief=>:solid, :bg=>'white') Tk.grid(@label, '-', '-', '-', :sticky=>:ew, :row=>0) idx = 1 loop { break unless respond_to?("move#{idx}") l = TkLabel.new(@f_details, :text=>idx, :anchor=>:e, :width=>2, :bd=>1, :relief=>:solid, :bg=>'white') @STEP[idx] = 0 ll = TkLabel.new(@f_details, :textvariable=>@STEP.ref(idx), :width=>5, :bd=>1, :relief=>:solid, :bg=>'white') row = (idx + 1)/2 col = ((idx + 1) & 1) * 2 Tk.grid(l, :sticky=>:ew, :row=>row, :column=>col) Tk.grid(ll, :sticky=>:ew, :row=>row, :column=>(col + 1)) idx += 1 } @f_details.grid_columnconfigure(1, :weight=>1) end def show_ctrl if @ctrl.winfo_mapped? @ctrl.pack_forget @show.text('>>') else @ctrl.pack(:side=>:right, :fill=>:both, :ipady=>5) @show.text('<<') end end def draw_all reset_step @canvas.delete(:all) idx = 0 loop{ m = "draw#{idx}" break unless respond_to?(m) send(m) idx += 1 } end def active_GUI(var1, var2, op) st = {false=>:disabled, true=>:normal} m = @S['mode'].to_sym @S['pause'].value = (m == :MPAUSE) @start.state(st[m != :MGO]) @pause.state(st[m != :MSTART && m != :MDONE]) @step.state(st[m != :MGO && m != :MDONE]) @bstep.state(st[m != :MGO && m != :MDONE]) @reset.state(st[m != :MSTART]) if @S['details'].bool Tk.grid(@f_details, :in=>@details, :row=>2, :sticky=>:ew) else Tk.grid_forget(@f_details) end @speed_scale.label("Speed: #{@S['speed'].value}") end def start @S['mode'].value = :MGO end def do_button(what) case what when 0 # Start reset if @S['mode'].to_sym == :MDONE @S['mode'].value = :MGO when 1 # Pause @S['mode'].value = ((@S['pause'].bool)? :MPAUSE: :MGO) when 2 # Step @S['mode'].value = :MSSTEP when 3 # Reset reset when 4 # Big step @S['mode'].value = :MBSTEP end end def go(who = nil) now = Tk::Clock.clicks(:miliseconds) if who # Start here for debugging @S['active'] = [who] @S['mode'].value = :MGO end return if @S['mode'].to_sym == :MDEBUG # Debugging # If not paused, do the next move n = next_step if @S['mode'].to_sym != :MPAUSE @S['mode'].value = :MPAUSE if @S['mode'].to_sym == :MSSTEP # Single step @S['mode'].value = :MSSTEP if @S['mode'].to_sym == :MBSTEP && n # big step elapsed = Tk::Clock.clicks(:miliseconds) - now delay = @speed[@S['speed'].to_i] - elapsed delay = 1 if delay <= 0 return delay end def next_step retval = false # Return value if @S['mode'].to_sym != :MSTART && @S['mode'].to_sym != :MDONE @S['cnt'].numeric += 1 end alive = [] @S['active'].each{|who| who = who.to_i n = send("move#{who}") if (n & 1).nonzero? # This guy still alive alive << who end if (n & 2).nonzero? # Next guy is active alive << (who + 1) retval = true end if (n & 4).nonzero? # End of puzzle flag @S['mode'].value = :MDONE # Done mode @S['active'] = [] # No more animation return true end } @S['active'] = alive return retval end def about msg = "Ruby/Tk Version ::\nby Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)\n\n" msg += "Original Version ::\n" msg += "#{@S['title']}\nby Keith Vetter, March 2003\n(Reproduced by kind permission of the author)\n\n" msg += "Man will always find a difficult means to perform a simple task" msg += "\nRube Goldberg" Tk.messageBox(:message=>msg, :title=>'About') end ################################################################ # # All the drawing and moving routines # # START HERE! banner def draw0 color = @C['0'] TkcText.new(@canvas, # [579, 119], :text=>'START HERE!', [558, 119], :text=>'饹ȡ', :fill=>color, :anchor=>:w, :tag=>'I0', :font=>['Times Roman', 12, :italic, :bold]) TkcLine.new(@canvas, [719, 119, 763, 119], :tag=>'I0', :fill=>color, :width=>5, :arrow=>:last, :arrowshape=>[18, 18, 5]) @canvas.itembind('I0', '1'){ start } end def move0(step = nil) step = get_step(0, step) if @S['mode'].to_sym != :MSTART # Start the ball rolling move_abs('I0', [-100, -100]) # Hide the banner return 2 end pos = [ [673, 119], [678, 119], [683, 119], [688, 119], [693, 119], [688, 119], [683, 119], [678, 119] ] step = step % pos.length move_abs('I0', pos[step]) return 1 end # Dropping ball def draw1 color = @C['1a'] color2 = @C['1b'] TkcPolygon.new(@canvas, [ 844, 133, 800, 133, 800, 346, 820, 346, 820, 168, 844, 168, 844, 133 ], :width=>3, :fill=>color, :outline=>'') TkcPolygon.new(@canvas, [ 771, 133, 685, 133, 685, 168, 751, 168, 751, 346, 771, 346, 771, 133 ], :width=>3, :fill=>color, :outline=>'') TkcOval.new(@canvas, box(812, 122, 9), :tag=>'I1', :fill=>color2, :outline=>'') @canvas.itembind('I1', '1'){ start } end def move1(step = nil) step = get_step(1, step) pos = [ [807, 122], [802, 122], [797, 123], [793, 124], [789, 129], [785, 153], [785, 203], [785, 278, :x], [785, 367], [810, 392], [816, 438], [821, 503], [824, 585, :y], [838, 587], [848, 593], [857, 601], [-100, -100] ] return 0 if step >= pos.length where = pos[step] move_abs('I1', where) move15a if where[2] == :y return 3 if where[2] == :x return 1 end # Lighting the match def draw2 color = @C['2'] # Fulcrum TkcPolygon.new(@canvas, [750, 369, 740, 392, 760, 392], :fill=>@C['fg'], :outline=>@C['fg']) # Strike box TkcRectangle.new(@canvas, [628, 335, 660, 383], :fill=>'', :outline=>@C['fg']) (0..2).each{|y| yy = 335 + y*16 TkcBitmap.new(@canvas, [628, yy], :bitmap=>'gray25', :anchor=>:nw, :foreground=>@C['fg']) TkcBitmap.new(@canvas, [644, yy], :bitmap=>'gray25', :anchor=>:nw, :foreground=>@C['fg']) } # Lever TkcLine.new(@canvas, [702, 366, 798, 366], :fill=>@C['fg'], :width=>6, :tag=>'I2_0') # R strap TkcLine.new(@canvas, [712, 363, 712, 355], :fill=>@C['fg'], :width=>3, :tag=>'I2_1') # L strap TkcLine.new(@canvas, [705, 363, 705, 355], :fill=>@C['fg'], :width=>3, :tag=>'I2_2') # Match stick TkcLine.new(@canvas, [679, 356, 679, 360, 717, 360, 717, 356, 679, 356], :fill=>@C['fg'], :width=>3, :tag=>'I2_3') # Match head TkcPolygon.new(@canvas, [ 671, 352, 677.4, 353.9, 680, 358.5, 677.4, 363.1, 671, 365, 664.6, 363.1, 662, 358.5, 664.6, 353.9 ], :fill=>color, :outline=>color, :tag=>'I2_4') end def move2(step = nil) step = get_step(2, step) stages = [0, 0, 1, 2, 0, 2, 1, 0, 1, 2, 0, 2, 1] xy = [] xy[0] = [ 686, 333, 692, 323, 682, 316, 674, 309, 671, 295, 668, 307, 662, 318, 662, 328, 671, 336 ] xy[1] = [ 687, 331, 698, 322, 703, 295, 680, 320, 668, 297, 663, 311, 661, 327, 671, 335 ] xy[2] = [ 686, 331, 704, 322, 688, 300, 678, 283, 678, 283, 674, 298, 666, 309, 660, 324, 672, 336 ] if step >= stages.length @canvas.delete('I2') return 0 end if step == 0 # Rotate the match beta = 20 ox, oy = anchor('I2_0', :s) # Where to pivot i = 0 until @canvas.find_withtag("I2_#{i}").empty? rotate_item("I2_#{i}", ox, oy, beta) i += 1 end # For the flame TkcPolygon.new(@canvas, [], :tag=>'I2', :smooth=>true, :fill=>@C['2']) return 1 end @canvas.coords('I2', xy[stages[step]]) return ((step == 7)? 3: 1) end # Weight and pulleys def draw3 color = @C['3a'] color2 = @C['3b'] xy = [ [602, 296], [577, 174], [518, 174] ] xy.each{|x, y| # 3 Pulleys TkcOval.new(@canvas, box(x, y, 13), :fill=>color, :outline=>@C['fg'], :width=>3) TkcOval.new(@canvas, box(x, y, 2), :fill=>@C['fg'], :outline=>@C['fg']) } # Wall to flame TkcLine.new(@canvas, [750, 309, 670, 309], :tag=>'I3_s', :width=>3, :fill=>@C['fg'], :smooth=>true) # Flame to pulley 1 TkcLine.new(@canvas, [670, 309, 650, 309], :tag=>'I3_0', :width=>3, :fill=>@C['fg'], :smooth=>true) TkcLine.new(@canvas, [650, 309, 600, 309], :tag=>'I3_1', :width=>3, :fill=>@C['fg'], :smooth=>true) # Pulley 1 half way to 2 TkcLine.new(@canvas, [589, 296, 589, 235], :tag=>'I3_2', :width=>3, :fill=>@C['fg']) # Pulley 1 other half to 2 TkcLine.new(@canvas, [589, 235, 589, 174], :width=>3, :fill=>@C['fg']) # Across the top TkcLine.new(@canvas, [577, 161, 518, 161], :width=>3, :fill=>@C['fg']) # Down to weight TkcLine.new(@canvas, [505, 174, 505, 205], :tag=>'I3_w', :width=>3, :fill=>@C['fg']) # Draw the weight as 2 circles, two rectangles and 1 rounded rectangle x1, y1, x2, y2 = [515, 207, 495, 207] TkcOval.new(@canvas, box(x1, y1, 6), :tag=>'I3_', :fill=>color2, :outline=>color2) TkcOval.new(@canvas, box(x2, y2, 6), :tag=>'I3_', :fill=>color2, :outline=>color2) TkcRectangle.new(@canvas, x1, y1 - 6, x2, y2 + 6, :tag=>'I3_', :fill=>color2, :outline=>color2) TkcPolygon.new(@canvas, round_rect([492, 220, 518, 263], 15), :smooth=>true, :tag=>'I3_', :fill=>color2, :outline=>color2) TkcLine.new(@canvas, [500, 217, 511, 217], :tag=>'I3_', :fill=>color2, :width=>10) # Bottom weight target TkcLine.new(@canvas, [502, 393, 522, 393, 522, 465], :tag=>'I3__', :fill=>@C['fg'], :joinstyle=>:miter, :width=>10) end def move3(step = nil) step = get_step(3, step) pos = [ [505, 247], [505, 297], [505, 386.5], [505, 386.5] ] rope = [] rope[0] = [750, 309, 729, 301, 711, 324, 690, 300] rope[1] = [750, 309, 737, 292, 736, 335, 717, 315, 712, 320] rope[2] = [750, 309, 737, 309, 740, 343, 736, 351, 725, 340] rope[3] = [750, 309, 738, 321, 746, 345, 742, 356] return 0 if step >= pos.length @canvas.delete("I3_#{step}") # Delete part of the rope move_abs('I3_', pos[step]) # Move weight down @canvas.coords('I3_s', rope[step]) # Flapping rope end @canvas.coords('I3_w', [505, 174].concat(pos[step])) if step == 2 @canvas.move('I3__', 0, 30) return 2 end return 1 end # Cage and door def draw4 color = @C['4'] x0, y0, x1, y1 = [527, 356, 611, 464] # Horizontal bars y0.step(y1, 12){|y| TkcLine.new(@canvas, [x0, y, x1, y], :fill=>color, :width=>1) } # Vertical bars x0.step(x1, 12){|x| TkcLine.new(@canvas, [x, y0, x, y1], :fill=>color, :width=>1) } # Swing gate TkcLine.new(@canvas, [518, 464, 518, 428], :tag=>'I4', :fill=>color, :width=>1) end def move4(step = nil) step = get_step(4, step) angles = [-10, -20, -30, -30] return 0 if step >= angles.length rotate_item('I4', 518, 464, angles[step]) @canvas.raise('I4') return((step == 3)? 3: 1) end # Mouse def draw5 color = @C['5a'] color2 = @C['5b'] xy = [377, 248, 410, 248, 410, 465, 518, 465] # Mouse course xy.concat [518, 428, 451, 428, 451, 212, 377, 212] TkcPolygon.new(@canvas, xy, :fill=>color2, :outline=>@C['fg'], :width=>3) xy = [ 534.5, 445.5, 541, 440, 552, 436, 560, 436, 569, 440, 574, 446, 575, 452, 574, 454, 566, 456, 554, 456, 545, 456, 537, 454, 530, 452 ] TkcPolygon.new(@canvas, xy, :tag=>['I5', 'I5_0'], :fill=>color) TkcLine.new(@canvas, [573, 452, 592, 458, 601, 460, 613, 456], # Tail :tag=>['I5', 'I5_1'], :fill=>color, :smooth=>true, :width=>3) xy = box(540, 446, 2) # Eye xy = [540, 444, 541, 445, 541, 447, 540, 448, 538, 447, 538, 445] TkcPolygon.new(@canvas, xy, :tag=>['I5', 'I5_2'], :fill=>@C['bg'], :outline=>'', :smooth=>true) xy = [538, 454, 535, 461] # Front leg TkcLine.new(@canvas, xy, :tag=>['I5', 'I5_3'], :fill=>color, :width=>2) xy = [566, 455, 569, 462] # Back leg TkcLine.new(@canvas, xy, :tag=>['I5', 'I5_4'], :fill=>color, :width=>2) xy = [544, 455, 545, 460] # 2nd front leg TkcLine.new(@canvas, xy, :tag=>['I5', 'I5_5'], :fill=>color, :width=>2) xy = [560, 455, 558, 460] # 2nd back leg TkcLine.new(@canvas, xy, :tag=>['I5', 'I5_6'], :fill=>color, :width=>2) end def move5(step = nil) step = get_step(5, step) pos = [ [553, 452], [533, 452], [513, 452], [493, 452], [473, 452], [463, 442, 30], [445.5, 441.5, 30], [425.5, 434.5, 30], [422, 414], [422, 394], [422, 374], [422, 354], [422, 334], [422, 314], [422, 294], [422, 274, -30], [422, 260.5, -30, :x], [422.5, 248.5, -28], [425, 237] ] return 0 if step >= pos.length x, y, beta, nxt = pos[step] move_abs('I5', [x, y]) if beta ox, oy = centroid('I5_0') (0..6).each{|id| rotate_item("I5_#{id}", ox, oy, beta) } end return 3 if nxt == :x return 1 end # Dropping gumballs def draw6 color = @C['6'] xy = [324, 130, 391, 204] # Ball holder xy = round_rect(xy, 10) TkcPolygon.new(@canvas, xy, :smooth=>true, :outline=>@C['fg'], :width=>3, :fill=>color) xy = [339, 204, 376, 253] # Below the ball holder TkcRectangle.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :fill=>color, :tag=>'I6c') xy = box(346, 339, 28) TkcOval.new(@canvas, xy, :fill=>color, :outline=>'') # Roter TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>2, :style=>:arc, :start=>80, :extent=>205) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>2, :style=>:arc, :start=>-41, :extent=>85) xy = box(346, 339, 15) # Center of rotor TkcOval.new(@canvas, xy, :outline=>@C['fg'], :fill=>@C['fg'], :tag=>'I6m') xy = [352, 312, 352, 254, 368, 254, 368, 322] # Top drop to rotor TkcPolygon.new(@canvas, xy, :fill=>color, :outline=>'') TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2) xy = [353, 240, 367, 300] # Poke bottom hole TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>'') xy = [341, 190, 375, 210] # Poke another hole TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>'') xy = [ 368, 356, 368, 403, 389, 403, 389, 464, 320, 464, 320, 403, 352, 403, 352, 366 ] TkcPolygon.new(@canvas, xy, :fill=>color, :outline=>'', :width=>2) # Below rotor TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2) xy = box(275, 342, 7) # On/off rotor TkcOval.new(@canvas, xy, :outline=>@C['fg'], :fill=>@C['fg']) xy = [276, 334, 342, 325] # Fan belt top TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) xy = [276, 349, 342, 353] # Fan belt bottom TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) xy = [337, 212, 337, 247] # What the mouse pushes TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I6_') xy = [392, 212, 392, 247] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I6_') xy = [337, 230, 392, 230] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>7, :tag=>'I6_') who = -1 # All the balls colors = %w(red cyan orange green blue darkblue) colors *= 3 (0..16).each{|i| loc = -i color = colors[i] x, y = @XY6["#{loc}"] TkcOval.new(@canvas, box(x, y, 5), :fill=>color, :outline=>color, :tag=>"I6_b#{i}") } draw6a(12) # The wheel end def draw6a(beta) @canvas.delete('I6_0') ox, oy = [346, 339] (0..3).each{|i| b = beta + i * 45 x, y = rotate_c(28, 0, 0, 0, b) xy = [ox + x, oy + y, ox - x, oy - y] TkcLine.new(@canvas, xy, :tag=>'I6_0', :fill=>@C['fg'], :width=>2) } end def move6(step = nil) step = get_step(6, step) return 0 if step > 62 if step < 2 # Open gate for balls to drop @canvas.move('I6_', -7, 0) if step == 1 # Poke a hole xy = [348, 226, 365, 240] TkcRectangle.new(@canvas, xy, :fill=>@canvas.itemcget('I6c', :fill), :outline=>'') end return 1 end s = step - 1 # Do the gumball drop dance (0..(((s - 1)/3).to_i)).each{|i| tag = "I6_b#{i}" break if @canvas.find_withtag(tag).empty? loc = s - 3*i if @XY6["#{loc},#{i}"] move_abs(tag, @XY6["#{loc},#{i}"]) elsif @XY6["#{loc}"] move_abs(tag, @XY6["#{loc}"]) end } if s % 3 == 1 first = (s + 2)/3 i = first loop { tag = "I6_b#{i}" break if @canvas.find_withtag(tag).empty? loc = first - i move_abs(tag, @XY6["#{loc}"]) i += 1 } end if s >= 3 # Rotate the motor idx = s % 3 draw6a(12 + s * 15) end return((s == 3)? 3 : 1) end # On/off switch def draw7 color = @C['7'] xy = [198, 306, 277, 374] # Box TkcRectangle.new(@canvas, xy, :outline=>@C['fg'], :width=>2, :fill=>color, :tag=>'I7z') @canvas.lower('I7z') xy = [275, 343, 230, 349] TkcLine.new(@canvas, xy, :tag=>'I7', :fill=>@C['fg'], :arrow=>:last, :arrowshape=>[23, 23, 8], :width=>6) xy = [225, 324] # On button x, y = xy TkcOval.new(@canvas, box(x, y, 3), :fill=>@C['fg'], :outline=>@C['fg']) xy = [218, 323] # On text font = ['Times Roman', 8] TkcText.new(@canvas, xy, :text=>'on', :anchor=>:e, :fill=>@C['fg'], :font=>font) xy = [225, 350] # Off button x, y = xy TkcOval.new(@canvas, box(x, y, 3), :fill=>@C['fg'], :outline=>@C['fg']) xy = [218, 349] # Off text TkcText.new(@canvas, xy, :text=>'off', :anchor=>:e, :fill=>@C['fg'], :font=>font) end def move7(step = nil) step = get_step(7, step) numsteps = 30 return 0 if step > numsteps beta = 30.0 / numsteps rotate_item('I7', 275, 343, beta) return((step == numsteps)? 3: 1) end # Electricity to the fan def draw8 sine([271, 248, 271, 306], 5, 8, :tag=>'I8_s', :fill=>@C['8'], :width=>3) end def move8(step = nil) step = get_step(8, step) return 0 if step > 3 if step == 0 sparkle(anchor('I8_s', :s), 'I8') return 1 elsif step == 1 move_abs('I8', anchor('I8_s', :c)) elsif step == 2 move_abs('I8', anchor('I8_s', :n)) else @canvas.delete('I8') end return((step == 2)? 3: 1) end # Fan def draw9 color = @C['9'] xy = [266, 194, 310, 220] TkcOval.new(@canvas, xy, :outline=>color, :fill=>color) xy = [280, 209, 296, 248] TkcOval.new(@canvas, xy, :outline=>color, :fill=>color) xy = [ 288, 249, 252, 249, 260, 240, 280, 234, 296, 234, 316, 240, 324, 249, 288, 249 ] TkcPolygon.new(@canvas, xy, :fill=>color, :smooth=>true) xy = [248, 205, 265, 214, 264, 205, 265, 196] # Spinner TkcPolygon.new(@canvas, xy, :fill=>color) xy = [255, 206, 265, 234] # Fan blades TkcOval.new(@canvas, xy, :fill=>'', :outline=>@C['fg'], :width=>3, :tag=>'I9_0') xy = [255, 176, 265, 204] TkcOval.new(@canvas, xy, :fill=>'', :outline=>@C['fg'], :width=>3, :tag=>'I9_0') xy = [255, 206, 265, 220] TkcOval.new(@canvas, xy, :fill=>'', :outline=>@C['fg'], :width=>1, :tag=>'I9_1') xy = [255, 190, 265, 204] TkcOval.new(@canvas, xy, :fill=>'', :outline=>@C['fg'], :width=>1, :tag=>'I9_1') end def move9(step = nil) step = get_step(9, step) if (step & 1).nonzero? @canvas.itemconfigure('I9_0', :width=>4) @canvas.itemconfigure('I9_1', :width=>1) @canvas.lower('I9_1', 'I9_0') else @canvas.itemconfigure('I9_0', :width=>1) @canvas.itemconfigure('I9_1', :width=>4) @canvas.lower('I9_0', 'I9_1') end return 3 if step == 0 return 1 end # Boat def draw10 color = @C['10a'] color2 = @C['10b'] xy = [191, 230, 233, 230, 233, 178, 191, 178] # Sail TkcPolygon.new(@canvas, xy, :fill=>color, :width=>3, :outline=>@C['fg'], :tag=>'I10') xy = box(209, 204, 31) # Front TkcArc.new(@canvas, xy, :outline=>'', :fill=>color, :style=>:pie, :start=>120, :extent=>120, :tag=>'I10') TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, :start=>120, :extent=>120, :tag=>'I10') xy = box(249, 204, 31) # Back TkcArc.new(@canvas, xy, :outline=>'', :fill=>@C['bg'], :width=>3, :style=>:pie, :start=>120, :extent=>120, :tag=>'I10') TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, :start=>120, :extent=>120, :tag=>'I10') xy = [200, 171, 200, 249] # Mast TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I10') xy = [159, 234, 182, 234] # Bow sprit TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I10') xy = [180, 234, 180, 251, 220, 251] # Hull TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>6, :tag=>'I10') xy = [92, 255, 221, 255] # Waves sine(xy, 2, 25, :fill=>color2, :width=>1, :tag=>'I10w') xy = @canvas.coords('I10w')[4..-5] # Water xy.concat([222, 266, 222, 277, 99, 277]) TkcPolygon.new(@canvas, xy, :fill=>color2, :outline=>color2) xy = [222, 266, 222, 277, 97, 277, 97, 266] # Water bottom TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) xy = box(239, 262, 17) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, :start=>95, :extent=>103) xy = box(76, 266, 21) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, :extent=>190) end def move10(step = nil) step = get_step(10, step) pos = [ [195, 212], [193, 212], [190, 212], [186, 212], [181, 212], [176, 212], [171, 212], [166, 212], [161, 212], [156, 212], [151, 212], [147, 212], [142, 212], [137, 212], [132, 212, :x], [127, 212], [121, 212], [116, 212], [111, 212] ] return 0 if step >= pos.length where = pos[step] move_abs('I10', where) return 3 if where[2] == :x return 1 end # 2nd ball drop def draw11 color = @C['11a'] color2 = @C['11b'] xy = [23, 264, 55, 591] # Color the down tube TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>'') xy = box(71, 460, 48) # Color the outer loop TkcOval.new(@canvas, xy, :fill=>color, :outline=>'') xy = [55, 264, 55, 458] # Top right side TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) xy = [55, 504, 55, 591] # Bottom right side TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) xy = box(71, 460, 48) # Outer loop TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, :start=>110, :extent=>-290, :tag=>'I11i') xy = box(71, 460, 16) # Inner loop TkcOval.new(@canvas, xy, :outline=>@C['fg'], :fill=>'', :width=>3, :tag=>'I11i') TkcOval.new(@canvas, xy, :outline=>@C['fg'], :fill=>@C['bg'], :width=>3) xy = [23, 264, 23, 591] # Left side TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) xy = box(1, 266, 23) # Top left curve TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, :extent=>90) xy = box(75, 235, 9) # The ball TkcOval.new(@canvas, xy, :fill=>color2, :outline=>'', :width=>3, :tag=>'I11') end def move11(step = nil) step = get_step(11, step) pos = [ [75, 235], [70, 235], [65, 237], [56, 240], [46, 247], [38, 266], [38, 296], [38, 333], [38, 399], [38, 475], [74, 496], [105, 472], [100, 437], [65, 423], [-100, -100], [38, 505], [38, 527, :x], [38, 591] ] return 0 if step >= pos.length where = pos[step] move_abs('I11', where) return 3 if where[2] == :x return 1 end # Hand def draw12 xy = [ 20, 637, 20, 617, 20, 610, 20, 590, 40, 590, 40, 590, 60, 590, 60, 610, 60, 610 ] xy.concat([60, 610, 65, 620, 60, 631]) # Thumb xy.concat([60, 631, 60, 637, 60, 662, 60, 669, 52, 669, 56, 669, 50, 669, 50, 662, 50, 637]) y0 = 637 # Bumps for fingers y1 = 645 50.step(21, -10){|x| x1 = x - 5 x2 = x - 10 xy << x << y0 << x1 << y1 << x2 << y0 } TkcPolygon.new(@canvas, xy, :fill=>@C['12'], :outline=>@C['fg'], :smooth=>true, :tag=>'I12', :width=>3) end def move12(step = nil) step = get_step(12, step) pos = [[42.5, 641, :x]] return 0 if step >= pos.length where = pos[step] move_abs('I12', where) return 3 if where[2] == :x return 1 end # Fax def draw13 color = @C['13a'] xy = [86, 663, 149, 663, 149, 704, 50, 704, 50, 681, 64, 681, 86, 671] xy2 = [ 784, 663, 721, 663, 721, 704, 820, 704, 820, 681, 806, 681, 784, 671 ] radii = [2, 9, 9, 8, 5, 5, 2] round_poly(@canvas, xy, radii, :width=>3, :outline=>@C['fg'], :fill=>color) round_poly(@canvas, xy2, radii, :width=>3, :outline=>@C['fg'], :fill=>color) xy = [56, 677] x, y = xy TkcRectangle.new(@canvas, box(x, y, 4), :fill=>'', :outline=>@C['fg'], :width=>3, :tag=>'I13') xy = [809, 677] x, y = xy TkcRectangle.new(@canvas, box(x, y, 4), :fill=>'', :outline=>@C['fg'], :width=>3, :tag=>'I13R') xy = [112, 687] # Label TkcText.new(@canvas, xy, :text=>'FAX', :fill=>@C['fg'], :font=>['Times Roman', 12, :bold]) xy = [762, 687] TkcText.new(@canvas, xy, :text=>'FAX', :fill=>@C['fg'], :font=>['Times Roman', 12, :bold]) xy = [138, 663, 148, 636, 178, 636] # Paper guide TkcLine.new(@canvas, xy, :smooth=>true, :fill=>@C['fg'], :width=>3) xy = [732, 663, 722, 636, 692, 636] TkcLine.new(@canvas, xy, :smooth=>true, :fill=>@C['fg'], :width=>3) sine([149, 688, 720, 688], 5, 15, :tag=>'I13_s', :fill=>@C['fg'], :width=>3) end def move13(step = nil) step = get_step(13, step) numsteps = 7 if step == numsteps + 2 move_abs('I13_star', [-100, -100]) @canvas.itemconfigure('I13R', :fill=>@C['13b'], :width=>2) return 2 end if step == 0 # Button down @canvas.delete('I13') sparkle([-100, -100], 'I13_star') # Create off screen return 1 end x0, y0 = anchor('I13_s', :w) x1, y1 = anchor('I13_s', :e) x = x0 + (x1 - x0) * (step - 1) / numsteps.to_f move_abs('I13_star', [x, y0]) return 1 end # Paper in fax def draw14 color = @C['14'] xy = [102, 661, 113, 632, 130, 618] # Left paper edge TkcLine.new(@canvas, xy, :smooth=>true, :fill=>color, :width=>3, :tag=>'I14L_0') xy = [148, 629, 125, 640, 124, 662] # Right paper edge TkcLine.new(@canvas, xy, :smooth=>true, :fill=>color, :width=>3, :tag=>'I14L_1') draw14a('L') xy = [ 768.0, 662.5, 767.991316225, 662.433786215, 767.926187912, 662.396880171 ] TkcLine.new(@canvas, xy, :smooth=>true, :fill=>color, :width=>3, :tag=>'I14R_0') @canvas.lower('I14R_0') # NB. these numbers are VERY sensitive, you must start with final size # and shrink down to get the values xy = [ 745.947897349, 662.428358855, 745.997829056, 662.452239237, 746.0, 662.5 ] TkcLine.new(@canvas, xy, :smooth=>true, :fill=>color, :width=>3, :tag=>'I14R_1') @canvas.lower('I14R_1') end def draw14a(side) color = @C['14'] xy = @canvas.coords("I14#{side}_0") xy2 = @canvas.coords("I14#{side}_1") x0, y0, x1, y1, x2, y2 = xy x3, y3, x4, y4, x5, y5 = xy2 zz = [ x0, y0, x0, y0, xy, x2, y2, x2, y2, x3, y3, x3, y3, xy2, x5, y5, x5, y5 ].flatten @canvas.delete("I14#{side}") TkcPolygon.new(@canvas, zz, :tag=>"I14#{side}", :smooth=>true, :fill=>color, :outline=>color, :width=>3) @canvas.lower("I14#{side}") end def move14(step = nil) step = get_step(14, step) # Paper going down sc = 0.9 - 0.05*step if sc < 0.3 @canvas.delete('I14L') return 0 end ox, oy = @canvas.coords('I14L_0') @canvas.scale('I14L_0', ox, oy, sc, sc) ox, oy = @canvas.coords('I14L_1')[-2..-1] @canvas.scale('I14L_1', ox, oy, sc, sc) draw14a('L') # Paper going up sc = 0.35 + 0.05*step sc = 1/sc ox, oy = @canvas.coords('I14R_0') @canvas.scale('I14R_0', ox, oy, sc, sc) ox, oy = @canvas.coords('I14R_1')[-2..-1] @canvas.scale('I14R_1', ox, oy, sc, sc) draw14a('R') return((step == 10)? 3: 1) end # Light beam def draw15 color = @C['15a'] xy = [824, 599, 824, 585, 820, 585, 829, 585] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I15a') xy = [789, 599, 836, 643] TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>3) xy = [778, 610, 788, 632] TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>3) xy = [766, 617, 776, 625] TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>3) xy = [633, 600, 681, 640] TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>3) xy = [635, 567, 657, 599] TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>2) xy = [765, 557, 784, 583] TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>2) sine([658, 580, 765, 580], 3, 15, :tag=>'I15_s', :fill=>@C['fg'], :width=>3) end def move15a color = @C['15b'] @canvas.scale('I15a', 824, 599, 1, 0.3) # Button down xy = [765, 621, 681, 621] TkcLine.new(@canvas, xy, :dash=>'-', :width=>3, :fill=>color, :tag=>'I15') end def move15(step = nil) step = get_step(15, step) numsteps = 6 if step == numsteps + 2 move_abs('I15_star', [-100, -100]) return 2 end if step == 0 # Break the light beam sparkle([-100, -100], 'I15_star') xy = [765, 621, 745, 621] @canvas.coords('I15', xy) return 1 end x0, y0 = anchor('I15_s', :w) x1, y1 = anchor('I15_s', :e) x = x0 + (x1 - x0) * (step - 1) / numsteps.to_f move_abs('I15_star', [x, y0]) return 1 end # Bell def draw16 color = @C['16'] xy = [722, 485, 791, 556] TkcRectangle.new(@canvas, xy, :fill=>'', :outline=>@C['fg'], :width=>3) xy = box(752, 515, 25) # Bell TkcOval.new(@canvas, xy, :fill=>color, :outline=>'black', :tag=>'I16b', :width=>2) xy = box(752, 515, 5) # Bell button TkcOval.new(@canvas, xy, :fill=>'black', :outline=>'black', :tag=>'I16b') xy = [784, 523, 764, 549] # Clapper TkcLine.new(@canvas, xy, :width=>3, :tag=>'I16c', :fill=>@C['fg']) xy = box(784, 523, 4) TkcOval.new(@canvas, xy, :fill=>@C['fg'], :outline=>@C['fg'], :tag=>'I16d') end def move16(step = nil) step = get_step(16, step) # Note: we never stop ox, oy = [760, 553] if (step & 1).nonzero? beta = 12 @canvas.move('I16b', 3, 0) else beta = -12 @canvas.move('I16b', -3, 0) end rotate_item('I16c', ox, oy, beta) rotate_item('I16d', ox, oy, beta) return ((step == 1)? 3: 1) end # Cat def draw17 color = @C['17'] xy = [584, 556, 722, 556] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) xy = [584, 485, 722, 485] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) xy = [664, 523, 717, 549] # Body TkcArc.new(@canvas, xy, :outline=>@C['fg'], :fill=>color, :width=>3, :style=>:chord, :start=>128, :extent=>260, :tag=>'I17') xy = [709, 554, 690, 543] # Paw TkcOval.new(@canvas, xy, :outline=>@C['fg'], :fill=>color, :width=>3, :tag=>'I17') xy = [657, 544, 676, 555] TkcOval.new(@canvas, xy, :outline=>@C['fg'], :fill=>color, :width=>3, :tag=>'I17') xy = box(660, 535, 15) # Lower face TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, :start=>150, :extent=>240, :tag=>'I17_') TkcArc.new(@canvas, xy, :outline=>'', :fill=>color, :width=>1, :style=>:chord, :start=>150, :extent=>240, :tag=>'I17_') xy = [674, 529, 670, 513, 662, 521, 658, 521, 650, 513, 647, 529] # Ears TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') TkcPolygon.new(@canvas, xy, :fill=>color, :outline=>'', :width=>1, :tag=>['I17_', 'I17_c']) xy = [652, 542, 628, 539] # Whiskers TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') xy = [652, 543, 632, 545] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') xy = [652, 546, 632, 552] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') xy = [668, 543, 687, 538] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>['I17_', 'I17_w']) xy = [668, 544, 688, 546] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>['I17_', 'I17_w']) xy = [668, 547, 688, 553] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>['I17_', 'I17_w']) xy = [649, 530, 654, 538, 659, 530] # Left eye TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2, :smooth=>true, :tag=>'I17') xy = [671, 530, 666, 538, 661, 530] # Right eye TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2, :smooth=>true, :tag=>'I17') xy = [655, 543, 660, 551, 665, 543] # Mouth TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2, :smooth=>true, :tag=>'I17') end def move17(step = nil) step = get_step(17, step) if step == 0 @canvas.delete('I17') # Delete most of the cat xy = [655, 543, 660, 535, 665, 543] # Mouth TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :smooth=>true, :tag=>'I17_') xy = box(654, 530, 4) # Left eye TkcOval.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :fill=>'', :tag=>'I17_') xy = box(666, 530, 4) # Right eye TkcOval.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :fill=>'', :tag=>'I17_') @canvas.move('I17_', 0, -20) # Move face up xy = [652, 528, 652, 554] # Front leg TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') xy = [670, 528, 670, 554] # 2nd front leg TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') xy = [ # Body 675, 506, 694, 489, 715, 513, 715, 513, 715, 513, 716, 525, 716, 525, 716, 525, 706, 530, 695, 530, 679, 535, 668, 527, 668, 527, 668, 527, 675, 522, 676, 517, 677, 512 ] TkcPolygon.new(@canvas, xy, :fill=>@canvas.itemcget('I17_c', :fill), :outline=>@C['fg'], :width=>3, :smooth=>true, :tag=>'I17_') xy = [716, 514, 716, 554] # Back leg TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') xy = [694, 532, 694, 554] # 2nd back leg TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') xy = [715, 514, 718, 506, 719, 495, 716, 488] # Tail TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :smooth=>true, :tag=>'I17_') @canvas.raise('I17w') # Make whiskers visible @canvas.move('I17_', -5, 0) # Move away from the wall a bit return 2 end return 0 end # Sling shot def draw18 color = @C['18'] xy = [721, 506, 627, 506] # Sling hold TkcLine.new(@canvas, xy, :width=>4, :fill=>@C['fg'], :tag=>'I18') xy = [607, 500, 628, 513] # Sling rock TkcOval.new(@canvas, xy, :fill=>color, :outline=>'', :tag=>'I18a') xy = [526, 513, 606, 507, 494, 502] # Sling band TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>4, :tag=>'I18b') xy = [485, 490, 510, 540, 510, 575, 510, 540, 535, 491] # Sling TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>6) end def move18(step = nil) step = get_step(18, step) pos = [ [587, 506], [537, 506], [466, 506], [376, 506], [266, 506, :x], [136, 506], [16, 506], [-100, -100] ] b = [] b[0] = [490, 502, 719, 507, 524, 512] # Band collapsing b[1] = [ 491, 503, 524, 557, 563, 505, 559, 496, 546, 506, 551, 525, 553, 536, 538, 534, 532, 519, 529, 499 ] b[2] = [ 491, 503, 508, 563, 542, 533, 551, 526, 561, 539, 549, 550, 530, 500 ] b[3] = [ 491, 503, 508, 563, 530, 554, 541, 562, 525, 568, 519, 544, 530, 501 ] return 0 if step >= pos.length if step == 0 @canvas.delete('I18') @canvas.itemconfigure('I18b', :smooth=>true) end if b[step] @canvas.coords('I18b', b[step]) end where = pos[step] move_abs('I18a', where) return 3 if where[2] == :x return 1 end # Water pipe def draw19 color = @C['19'] xx = [[249, 181], [155, 118], [86, 55], [22, 0]] xx.each{|x1, x2| TkcRectangle.new(@canvas, x1, 453, x2, 467, :fill=>color, :outline=>'', :tag=>'I19') TkcLine.new(@canvas, x1, 453, x2, 453, :fill=>@C['fg'], :width=>1) # Pipe top TkcLine.new(@canvas, x1, 467, x2, 467, :fill=>@C['fg'], :width=>1) # Pipe bottom } @canvas.raise('I11i') xy = box(168, 460, 16) # Bulge by the joint TkcOval.new(@canvas, xy, :fill=>color, :outline=>'') TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>21, :extent=>136) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>-21, :extent=>-130) xy = [249, 447, 255, 473] # First joint 26x6 TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>1) xy = box(257, 433, 34) # Bend up TkcArc.new(@canvas, xy, :outline=>'', :fill=>color, :width=>1, :style=>:pie, :start=>0, :extent=>-91) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>0, :extent=>-90) xy = box(257, 433, 20) TkcArc.new(@canvas, xy, :outline=>'', :fill=>@C['bg'], :width=>1, :style=>:pie, :start=>0, :extent=>-92) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>0, :extent=>-90) xy = box(257, 421, 34) # Bend left TkcArc.new(@canvas, xy, :outline=>'', :fill=>color, :width=>1, :style=>:pie, :start=>0, :extent=>91) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>0, :extent=>90) xy = box(257, 421, 20) TkcArc.new(@canvas, xy, :outline=>'', :fill=>@C['bg'], :width=>1, :style=>:pie, :start=>0, :extent=>90) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>0, :extent=>90) xy = box(243, 421, 34) # Bend down TkcArc.new(@canvas, xy, :outline=>'', :fill=>color, :width=>1, :style=>:pie, :start=>90, :extent=>90) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>90, :extent=>90) xy = box(243, 421, 20) TkcArc.new(@canvas, xy, :outline=>'', :fill=>@C['bg'], :width=>1, :style=>:pie, :start=>90, :extent=>90) TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>90, :extent=>90) xy = [270, 427, 296, 433] # 2nd joint bottom TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>1) xy = [270, 421, 296, 427] # 2nd joint top TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>1) xy = [249, 382, 255, 408] # Third joint right TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>1) xy = [243, 382, 249, 408] # Third joint left TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>1) xy = [203, 420, 229, 426] # Last joint TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>1) xy = box(168, 460, 6) # Handle joint TkcOval.new(@canvas, xy, :fill=>@C['fg'], :outline=>'', :tag=>'I19a') xy = [168, 460, 168, 512] # Handle bar TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>5, :tag=>'I19b') end def move19(step = nil) step = get_step(19, step) angles = [30, 30, 30] return 2 if step == angles.length ox, oy = centroid('I19a') rotate_item('I19b', ox, oy, angles[step]) return 1 end # Water pouring def draw20 # do nothing end def move20(step = nil) step = get_step(20, step) pos = [451, 462, 473, 484, 496, 504, 513, 523, 532] freq = [20, 40, 40, 40, 40, 40, 40, 40, 40] pos = [ [451, 20], [462, 40], [473, 40], [484, 40], [496, 40], [504, 40], [513, 40], [523, 40], [532, 40, :x] ] return 0 if step >= pos.length @canvas.delete('I20') where = pos[step] y, f = where h20(y, f) return 3 if where[2] == :x return 1 end def h20(y, f) color = @C['20'] @canvas.delete('I20') sine([208, 428, 208, y], 4, f, :tag=>['I20', 'I20s'], :width=>3, :fill=>color, :smooth=>true) TkcLine.new(@canvas, @canvas.coords('I20s'), :width=>3, :fill=>color, :smooth=>1, :tag=>['I20', 'I20a']) TkcLine.new(@canvas, @canvas.coords('I20s'), :width=>3, :fill=>color, :smooth=>1, :tag=>['I20', 'I20b']) @canvas.move('I20a', 8, 0) @canvas.move('I20b', 16, 0) end # Bucket def draw21 color = @C['21'] xy = [217, 451, 244, 490] # Right handle TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2, :tag=>'I21_a') xy = [201, 467, 182, 490] # Left handle TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2, :tag=>'I21_a') xy = [245, 490, 237, 535] # Right side xy2 = [189, 535, 181, 490] # Left side TkcPolygon.new(@canvas, xy + xy2, :fill=>color, :outline=>'', :tag=>['I21', 'I21f']) TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2, :tag=>'I21') TkcLine.new(@canvas, xy2, :fill=>@C['fg'], :width=>2, :tag=>'I21') xy = [182, 486, 244, 498] # Top TkcOval.new(@canvas, xy, :fill=>color, :outline=>'', :width=>2, :tag=>['I21', 'I21f']) TkcOval.new(@canvas, xy, :fill=>'', :outline=>@C['fg'], :width=>2, :tag=>['I21', 'I21t']) xy = [189, 532, 237, 540] # Bottom TkcOval.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>2, :tag=>['I21', 'I21b']) end def move21(step = nil) step = get_step(21, step) numsteps = 30 return 0 if step >= numsteps x1, y1, x2, y2 = @canvas.coords('I21b') # lx1, ly1, lx2, ly2 = @canvas.coords('I21t') lx1, ly1, lx2, ly2 = [183, 492, 243, 504] f = step / numsteps.to_f y2 = y2 - 3 xx1 = x1 + (lx1 - x1) * f yy1 = y1 + (ly1 - y1) * f xx2 = x2 + (lx2 - x2) * f yy2 = y2 + (ly2 - y2) * f @canvas.itemconfigure('I21b', :fill=>@C['20']) @canvas.delete('I21w') TkcPolygon.new(@canvas, x2, y2, x1, y1, xx1, yy1, xx2, yy1, :tag=>['I21', 'I21w'], :outline=>'', :fill=>@C['20']) @canvas.lower('I21w', 'I21') @canvas.raise('I21b') @canvas.lower('I21f') return((step == numsteps - 1)? 3: 1) end # Bucket drop def draw22 # do nothing end def move22(step = nil) step = get_step(22, step) pos = [[213, 513], [213, 523], [213, 543, :x], [213, 583], [213, 593]] @canvas.itemconfigure('I21f', :fill=>@C['22']) if step == 0 return 0 if step >= pos.length where = pos[step] move_abs('I21', where) h20(where[1], 40) @canvas.delete('I21_a') # Delete handles return 3 if where[2] == :x return 1 end # Blow dart def draw23 color = @C['23a'] color2 = @C['23b'] color3 = @C['23c'] xy = [185, 623, 253, 650] # Block TkcRectangle.new(@canvas, xy, :fill=>'black', :outline=>@C['fg'], :width=>2, :tag=>'I23a') xy = [187, 592, 241, 623] # Balloon TkcOval.new(@canvas, xy, :outline=>'', :fill=>color, :tag=>'I23b') TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :tag=>'I23b', :style=>:arc, :start=>12, :extent=>336) xy = [239, 604, 258, 589, 258, 625, 239, 610] # Balloon nozzle TkcPolygon.new(@canvas, xy, :outline=>'', :fill=>color, :tag=>'I23b') TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I23b') xy = [285, 611, 250, 603] # Dart body TkcOval.new(@canvas, xy, :fill=>color2, :outline=>@C['fg'], :width=>3, :tag=>'I23d') xy = [249, 596, 249, 618, 264, 607, 249, 596] # Dart tail TkcPolygon.new(@canvas, xy, :fill=>color3, :outline=>@C['fg'], :width=>3, :tag=>'I23d') xy = [249, 607, 268, 607] # Dart detail TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I23d') xy = [285, 607, 305, 607] # Dart needle TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I23d') end def move23(step = nil) step = get_step(23, step) pos = [ [277, 607], [287, 607], [307, 607, :x], [347, 607], [407, 607], [487, 607], [587, 607], [687, 607], [787, 607], [-100, -100] ] return 0 if step >= pos.length if step <= 1 ox, oy = anchor('I23a', :n) @canvas.scale('I23b', ox, oy, 0.9, 0.5) end where = pos[step] move_abs('I23d', where) return 3 if where[2] == :x return 1 end # Balloon def draw24 color = @C['24a'] xy = [366, 518, 462, 665] # Balloon TkcOval.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>3, :tag=>'I24') xy = [414, 666, 414, 729] # String TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I24') xy = [410, 666, 404, 673, 422, 673, 418, 666] # Nozzle TkcPolygon.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>3, :tag=>'I24') xy = [387, 567, 390, 549, 404, 542] # Reflections TkcLine.new(@canvas, xy, :fill=>@C['fg'], :smooth=>true, :width=>2, :tag=>'I24') xy = [395, 568, 399, 554, 413, 547] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :smooth=>true, :width=>2, :tag=>'I24') xy = [403, 570, 396, 555, 381, 553] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :smooth=>true, :width=>2, :tag=>'I24') xy = [408, 564, 402, 547, 386, 545] TkcLine.new(@canvas, xy, :fill=>@C['fg'], :smooth=>true, :width=>2, :tag=>'I24') end def move24(step = nil) step = get_step(24, step) return 0 if step > 4 return 2 if step == 4 if step == 0 @canvas.delete('I24') # Exploding balloon xy = [ 347, 465, 361, 557, 271, 503, 272, 503, 342, 574, 259, 594, 259, 593, 362, 626, 320, 737, 320, 740, 398, 691, 436, 738, 436, 739, 476, 679, 528, 701, 527, 702, 494, 627, 548, 613, 548, 613, 480, 574, 577, 473, 577, 473, 474, 538, 445, 508, 431, 441, 431, 440, 400, 502, 347, 465, 347, 465 ] TkcPolygon.new(@canvas, xy, :tag=>'I24', :fill=>@C['24b'], :outline=>@C['24a'], :width=>10, :smooth=>true) msg = Tk.subst(@S['message'].value) TkcText.new(@canvas, centroid('I24'), :text=>msg, :tag=>['I24', 'I24t'], :justify=>:center, :font=>['Times Roman', 18, :bold]) return 1 end @canvas.itemconfigure('I24t', :font=>['Times Roman', 18 + 6*step, :bold]) @canvas.move('I24', 0, -60) ox, oy = centroid('I24') @canvas.scale('I24', ox, oy, 1.25, 1.25) return 1 end # Displaying the message def move25(step = nil) step = get_step(25, step) if step == 0 @XY['25'] = Tk::Clock.clicks(:miliseconds) return 1 end elapsed = Tk::Clock.clicks(:miliseconds) - @XY['25'] return 1 if elapsed < 5000 return 2 end # Collapsing balloon def move26(step = nil) step = get_step(26, step) if step >= 3 @canvas.delete('I24', 'I26') TkcText.new(@canvas, 430, 735, :anchor=>:s, :tag=>'I26', #:text=>'click to continue', :text=>'åǥꥻåȤޤ', :font=>['Times Roman', 20, :bold]) @canvas.bind('1', proc{reset}) return 4 end ox, oy = centroid('I24') @canvas.scale('I24', ox, oy, 0.8, 0.8) @canvas.move('I24', 0, 60) @canvas.itemconfigure('I24t', :font=>['Times Roman', 30 - 6*step, :bold]) return 1 end ################################################################ # # Helper functions # def box(x, y, r) [x - r, y - r, x + r, y + r] end def move_abs(item, xy) x, y = xy ox, oy = centroid(item) dx = x - ox dy = y - oy @canvas.move(item, dx, dy) end def rotate_item(item, ox, oy, beta) xy = @canvas.coords(item) xy2 = [] 0.step(xy.length - 1, 2){|idx| x, y = xy[idx, 2] xy2.concat(rotate_c(x, y, ox, oy, beta)) } @canvas.coords(item, xy2) end def rotate_c(x, y, ox, oy, beta) # rotates vector (ox,oy)->(x,y) by beta degrees clockwise x -= ox # Shift to origin y -= oy beta = beta * Math.atan(1) * 4 / 180.0 # Radians xx = x * Math.cos(beta) - y * Math.sin(beta) # Rotate yy = x * Math.sin(beta) + y * Math.cos(beta) xx += ox # Shift back yy += oy [xx, yy] end def reset draw_all @canvas.bind_remove('1') @S['mode'].value = :MSTART @S['active'] = [0] end # Each Move## keeps its state info in STEP, this retrieves and increments it def get_step(who, step) if step @STEP[who] = step else if !@STEP.exist?(who) || @STEP[who] == "" @STEP[who] = 0 else @STEP[who] += 1 end end @STEP[who] end def reset_step @S['cnt'].value = 0 @STEP.keys.each{|k| @STEP[k] = ''} end def sine(xy0, amp, freq, opts = {}) x0, y0, x1, y1 = xy0 step = 2 xy = [] if y0 == y1 # Horizontal x0.step(x1, step){|x| beta = (x - x0) * 2 * Math::PI / freq y = y0 + amp * Math.sin(beta) xy << x << y } else y0.step(y1, step){|y| beta = (y - y0) * 2 * Math::PI / freq x = x0 + amp * Math.sin(beta) xy << x << y } end TkcLine.new(@canvas, xy, opts) end def round_rect(xy, radius, opts={}) x0, y0, x3, y3 = xy r = @canvas.winfo_pixels(radius) d = 2 * r # Make sure that the radius of the curve is less than 3/8 size of the box! maxr = 0.75 if d > maxr * (x3 - x0) d = maxr * (x3 - x0) end if d > maxr * (y3 - y0) d = maxr * (y3 - y0) end x1 = x0 + d x2 = x3 - d y1 = y0 + d y2 = y3 - d xy = [x0, y0, x1, y0, x2, y0, x3, y0, x3, y1, x3, y2] xy.concat([x3, y3, x2, y3, x1, y3, x0, y3, x0, y2, x0, y1]) return xy end def round_poly(canv, xy, radii, opts) lenXY = xy.length lenR = radii.length if lenXY != 2*lenR raise "wrong number of vertices and radii" end knots = [] x0 = xy[-2]; y0 = xy[-1] x1 = xy[0]; y1 = xy[1] xy << xy[0] << xy[1] 0.step(lenXY - 1, 2){|i| radius = radii[i/2] r = canv.winfo_pixels(radius) x2 = xy[i+2]; y2 = xy[i+3] z = _round_poly2(x0, y0, x1, y1, x2, y2, r) knots.concat(z) x0 = x1; y0 = y1 x1 = x2; y1 = y2 } TkcPolygon.new(canv, knots, {:smooth=>true}.update(opts)) end def _round_poly2(x0, y0, x1, y1, x2, y2, radius) d = 2 * radius maxr = 0.75 v1x = x0 - x1 v1y = y0 - y1 v2x = x2 - x1 v2y = y2 - y1 vlen1 = Math.sqrt(v1x*v1x + v1y*v1y) vlen2 = Math.sqrt(v2x*v2x + v2y*v2y) if d > maxr * vlen1 d = maxr * vlen1 end if d > maxr * vlen2 d = maxr * vlen2 end xy = [] xy << (x1 + d * v1x / vlen1) << (y1 + d * v1y / vlen1) xy << x1 << y1 xy << (x1 + d * v2x / vlen2) << (y1 + d * v2y / vlen2) return xy end def sparkle(oxy, tag) xy = [ [299, 283], [298, 302], [295, 314], [271, 331], [239, 310], [242, 292], [256, 274], [281, 273] ] xy.each{|x, y| TkcLine.new(@canvas, 271, 304, x, y, :fill=>'white', :width=>3, :tag=>tag) } move_abs(tag, oxy) end def centroid(item) anchor(item, :c) end def anchor(item, where) x1, y1, x2, y2 = @canvas.bbox(item) case(where) when :n y = y1 when :s y = y2 else y = (y1 + y2) / 2.0 end case(where) when :w x = x1 when :e x = x2 else x = (x1 + x2) / 2.0 end return [x, y] end end TkGoldberg_Demo.new(base_frame) ================================================ FILE: ext/tk/sample/demos-jp/hello ================================================ #!/usr/bin/env ruby # -*- coding: euc-jp -*- require 'tk' TkButton.new(nil, 'text'=>"ˤϡ", 'command'=>proc{print "ˤϡ\n"; exit} ).pack Tk.mainloop ================================================ FILE: ext/tk/sample/demos-jp/hscale.rb ================================================ # -*- coding: euc-jp -*- require "tkcanvas" if defined?($hscale_demo) && $hscale_deom $hscale_demo.destroy $hscale_demo = nil end $hscale_demo = TkToplevel.new {|w| title("Horizontal Scale Demonstration") iconname("hscale") } positionWindow($hscale_demo) base_frame = TkFrame.new($hscale_demo).pack(:fill=>:both, :expand=>true) msg = TkLabel.new(base_frame) { font $font wraplength '3.5i' justify 'left' text "ˤ1Ĥȿʿʥ뤬ɽƤޤ\ ǥޥܥ1򥯥åޤϥɥå\ ĹѤ뤳ȤǤޤ" } msg.pack('side'=>'top') TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc { tmppath = $hscale_demo $hscale_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc { showCode 'hscale' } }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') def setWidth(w, width) width = width + 21 x2 = width - 30 if x2 < 21 x2 = 21 end w.coords 'poly',20,15,20,35,x2,35,x2,45,width,25,x2,5,x2,15,20,15 w.coords 'line',20,15,20,35,x2,35,x2,45,width,25,x2,5,x2,15,20,15 end TkFrame.new(base_frame) {|frame| canvas = TkCanvas.new(frame) {|c| width 50 height 50 bd 0 highlightthickness 0 TkcPolygon.new(c, '0', '0', '1', '1', '2', '2') { fill 'DeepSkyBlue' tags 'poly' } TkcLine.new(c, '0', '0', '1', '1', '2', '2', '0', '0') { fill 'black' tags 'line' } }.pack('side'=>'top', 'expand'=>'yes', 'anchor'=>'s', 'fill'=>'x', 'padx'=>'15') scale = TkScale.new(frame) { orient 'horizontal' length 284 from 0 to 250 command proc{|value| setWidth(canvas, value)} tickinterval 50 }.pack('side'=>'bottom', 'expand'=>'yes', 'anchor'=>'n') scale.set 75 }.pack('side'=>'top', 'fill'=>'x') ================================================ FILE: ext/tk/sample/demos-jp/icon.rb ================================================ # -*- coding: euc-jp -*- # # iconic button widget demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($icon_demo) && $icon_demo $icon_demo.destroy $icon_demo = nil end # demo Ѥ toplevel widget $icon_demo = TkToplevel.new {|w| title("Iconic Button Demonstration") iconname("icon") positionWindow(w) } base_frame = TkFrame.new($icon_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '5i' justify 'left' text "Υɥˤϥ饸ܥȥåܥ˥ӥåȥޥåפɽ 3 Ĥˡ򼨤ƤޤˤΤ2ĤΥ饸ܥǡ줾줬ӥåȥޥåפ򼨤󥸥ǤǤƤޤˤΤϡѤߤɤˤäưۤʤɽåܥǤ¦ˤΤѤߤɤˤäطʿѤӥåȥޥåפɽåܥǤ" } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $icon_demo $icon_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'icon'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # image flagup = \ TkBitmapImage.new('file'=>[$demo_dir,'..', 'images','flagup.xbm'].join(File::Separator), 'maskfile'=>\ [$demo_dir,'..','images','flagup.xbm'].join(File::Separator)) flagdown = \ TkBitmapImage.new('file'=>[$demo_dir,'..', 'images','flagdown.xbm'].join(File::Separator), 'maskfile'=>\ [$demo_dir,'..', 'images','flagdown.xbm'].join(File::Separator)) # ѿ letters = TkVariable.new # frame TkFrame.new(base_frame, 'borderwidth'=>10){|w| TkFrame.new(w) {|f| # TkRadioButton.new(f){ Tk::RadioButton.new(f){ bitmap '@' + [$demo_dir,'..', 'images','letters.xbm'].join(File::Separator) variable letters value 'full' }.pack('side'=>'top', 'expand'=>'yes') # TkRadioButton.new(f){ Tk::RadioButton.new(f){ bitmap '@' + [$demo_dir,'..', 'images','noletter.xbm'].join(File::Separator) variable letters value 'empty' }.pack('side'=>'top', 'expand'=>'yes') }.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'5m') # TkCheckButton.new(w) { Tk::CheckButton.new(w) { image flagdown selectimage flagup indicatoron 0 selectcolor self['background'] }.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'5m') # TkCheckButton.new(w) { Tk::CheckButton.new(w) { bitmap '@' + [$demo_dir,'..', 'images','letters.xbm'].join(File::Separator) indicatoron 0 selectcolor 'SeaGreen1' }.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'5m') }.pack('side'=>'top') ================================================ FILE: ext/tk/sample/demos-jp/image1.rb ================================================ # -*- coding: euc-jp -*- # # two image widgets demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($image1_demo) && $image1_demo $image1_demo.destroy $image1_demo = nil end # demo Ѥ toplevel widget $image1_demo = TkToplevel.new {|w| title('Image Demonstration #1') iconname("Image1") positionWindow(w) } base_frame = TkFrame.new($image1_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "ΥǥǤ2ĤΥ٥˲򤽤줾ɽƤޤ" } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $image1_demo $image1_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'image1'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # image image1a = \ TkPhotoImage.new('file'=>[$demo_dir,'..', 'images','earth.gif'].join(File::Separator)) image1b = \ TkPhotoImage.new('file'=>[$demo_dir,'..', 'images','earthris.gif'].join(File::Separator)) # label #[ TkLabel.new(base_frame, 'image'=>image1a, 'bd'=>1, 'relief'=>'sunken'), # TkLabel.new(base_frame, 'image'=>image1b, 'bd'=>1, 'relief'=>'sunken') #].each{|w| w.pack('side'=>'top', 'padx'=>'.5m', 'pady'=>'.5m')} [ Tk::Label.new(base_frame, 'image'=>image1a, 'bd'=>1, 'relief'=>'sunken'), Tk::Label.new(base_frame, 'image'=>image1b, 'bd'=>1, 'relief'=>'sunken') ].each{|w| w.pack('side'=>'top', 'padx'=>'.5m', 'pady'=>'.5m')} ================================================ FILE: ext/tk/sample/demos-jp/image2.rb ================================================ # -*- coding: euc-jp -*- # # widget demo 'load image' (called by 'widget') # # toplevel widget ¸ߤк if defined?($image2_demo) && $image2_demo $image2_demo.destroy $image2_demo = nil end # demo Ѥ toplevel widget $image2_demo = TkToplevel.new {|w| title('Image Demonstration #2') iconname("Image2") positionWindow(w) } base_frame = TkFrame.new($image2_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "ΥǥǤTk photo image ѤƲ򸫤뤳ȤǤޤǽ˥ȥˤ˥ǥ쥯ȥ̾Ʋ˲ΥꥹȥܥåˤΥǥ쥯ȥɤ뤿ᡢ꥿򲡤Ƥθ塢򤹤뤿˥ꥹȥܥåΥե֥̾륯åƲ" } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $image2_demo $image2_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'image2'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # ѿ $dirName = TkVariable.new([$demo_dir,'..','images'].join(File::Separator)) # image $image2a = TkPhotoImage.new # ե̾ TkLabel.new(base_frame, 'text'=>'ǥ쥯ȥ:')\ .pack('side'=>'top', 'anchor'=>'w') image2_e = TkEntry.new(base_frame) { width 30 textvariable $dirName }.pack('side'=>'top', 'anchor'=>'w') TkFrame.new(base_frame, 'height'=>'3m', 'width'=>20)\ .pack('side'=>'top', 'anchor'=>'w') TkLabel.new(base_frame, 'text'=>'ե:')\ .pack('side'=>'top', 'anchor'=>'w') TkFrame.new(base_frame){|w| s = TkScrollbar.new(w) l = TkListbox.new(w) { width 20 height 10 yscrollcommand proc{|first,last| s.set first,last} } s.command(proc{|*args| l.yview(*args)}) l.pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y') s.pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y') #l.insert(0,'earth.gif', 'earthris.gif', 'mickey.gif', 'teapot.ppm') l.insert(0,'earth.gif', 'earthris.gif', 'teapot.ppm') l.bind('Double-1', proc{|x,y| loadImage $image2a,l,x,y}, '%x %y') image2_e.bind 'Return', proc{loadDir l} }.pack('side'=>'top', 'anchor'=>'w') # image [ TkFrame.new(base_frame, 'height'=>'3m', 'width'=>20), TkLabel.new(base_frame, 'text'=>':'), # TkLabel.new(base_frame, 'image'=>$image2a) Tk::Label.new(base_frame, 'image'=>$image2a) ].each{|w| w.pack('side'=>'top', 'anchor'=>'w')} # ᥽å def loadDir(w) w.delete(0,'end') Dir.glob([$dirName,'*'].join(File::Separator)).sort.each{|f| w.insert('end',File.basename(f)) } end def loadImage(img,w,x,y) img.file([$dirName, w.get("@#{x},#{y}")].join(File::Separator)) end ================================================ FILE: ext/tk/sample/demos-jp/image3.rb ================================================ # -*- coding: euc-jp -*- # image3.rb # # This demonstration script creates a simple collection of widgets # that allow you to select and view images in a Tk label. # # widget demo 'load image' (called by 'widget') # # toplevel widget if defined?($image3_demo) && $image3_demo $image3_demo.destroy $image3_demo = nil end # demo toplevel widget $image3_demo = TkToplevel.new {|w| title('Image Demonstration #3') iconname("Image3") positionWindow(w) } base_frame = TkFrame.new($image3_demo).pack(:fill=>:both, :expand=>true) # def loadDir3(w) w.delete(0,'end') Dir.glob([$dirName,'*'].join(File::Separator)).sort.each{|f| w.insert('end',File.basename(f)) } end # selectAndLoadDir3 -- # This procedure pops up a dialog to ask for a directory to load into # the listobx and (if the user presses OK) reloads the directory # listbox from the directory named in the demo's entry. # # Arguments: # w - Name of the toplevel window of the demo. def selectAndLoadDir3(w, lbox) dir = Tk.chooseDirectory(:initialdir=>$dirName.value, :parent=>w, :mustexist=>true) if dir.length > 0 $dirName.value = dir loadDir3(lbox) end end def loadImage3(w,x,y) $image3a.file([$dirName, w.get("@#{x},#{y}")].join(File::Separator)) end # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "ΥǥǤTk photo image ѤƲ 뤳ȤǤޤǽ˥ȥˤ˥ǥ쥯ȥ̾Ʋ˲ΥꥹȥܥåˤΥǥ쥯ȥɤ뤿ᡢ꥿򲡤Ƥθ塢򤹤뤿˥ꥹȥܥåΥե֥̾륯åƲ" } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $image3_demo $image3_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'image3'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # variable $dirName = TkVariable.new([$demo_dir,'..','images'].join(File::Separator)) # image begin $image3a.delete rescue end $image3a = TkPhotoImage.new # image3_f = TkFrame.new(base_frame).pack(:fill=>:both, :expand=>true) image3_df = TkLabelFrame.new(base_frame, :text=>'ǥ쥯ȥ:') image3_ff = TkLabelFrame.new(base_frame, :text=>'ե:', :padx=>'2m', :pady=>'2m') image3_lbx = TkListbox.new(image3_ff, :width=>20, :height=>10) { pack(:side=>:left, :fill=>:y, :expand=>true) yscrollbar(TkScrollbar.new(image3_ff).pack(:side=>:left, :fill=>:y, :expand=>true)) insert(0, *(%w(earth.gif earthris.gif teapot.ppm))) bind('Double-1', proc{|x,y| loadImage3(self, x, y)}, '%x %y') } image3_ent = TkEntry.new(image3_df, :width=>30, :textvariable=>$dirName){ pack(:side=>:left, :fill=>:both, :padx=>'2m', :pady=>'2m', :expand=>true) bind('Return', proc{loadDir3(image3_lbx)}) } TkButton.new(image3_df, :pady=>0, :padx=>'2m', :text=>"ǥ쥯ȥ", :command=>proc{selectAndLoadDir3(image3_ent, image3_lbx)}) { pack(:side=>:left, :fill=>:y, :padx=>[0, '2m'], :pady=>'2m') } image3_if = TkLabelFrame.new(base_frame, :text=>'᡼:') {|f| # TkLabel.new(f, :image=>$image3a).pack(:padx=>'2m', :pady=>'2m') Tk::Label.new(f, :image=>$image3a).pack(:padx=>'2m', :pady=>'2m') } Tk.grid(image3_df, '-', :sticky=>:ew, :padx=>'1m', :pady=>'1m', :in=>image3_f) Tk.grid(image3_ff, image3_if, :sticky=>:nw, :padx=>'1m', :pady=>'1m', :in=>image3_f) TkGrid.columnconfigure(image3_f, 1, :weight=>1) ================================================ FILE: ext/tk/sample/demos-jp/items.rb ================================================ # -*- coding: euc-jp -*- # # canvas item types widget demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($items_demo) && $items_demo $items_demo.destroy $items_demo = nil end # demo Ѥ toplevel widget $items_demo = TkToplevel.new {|w| title("Canvas Item Demonstration") iconname("Items") positionWindow(w) } base_frame = TkFrame.new($items_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame) { font $font wraplength '5i' justify 'left' text "ΥɥˤϥХ widget äƤꡢˤϥХ widget ݡȤ͡ʥפΥƥ㤬äƤޤΤ褦Ǥޤ\n ܥ-1 ɥå:\tƥư\n ܥ-2 ɥå:\tƤʬ򤺤餹\n ܥ-3 ɥå:\tΰϤ\n ȥ-F:\tΰβΥƥɽ롣" }.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $items_demo $items_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'items'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame cvs = nil TkFrame.new(base_frame) {|cf| # canvas cvs = TkCanvas.new(cf) {|c| focus scrollregion '0c 0c 30c 24c' width '15c' height '10c' relief 'sunken' borderwidth 2 hs = TkScrollbar.new(cf) {|s| orient 'horizontal' command proc{|*args| c.xview(*args)} c.xscrollcommand proc{|first,last| s.set first,last} } vs = TkScrollbar.new(cf) {|s| command proc{|*args| c.yview(*args)} c.yscrollcommand proc{|first,last| s.set first,last} } if $tk_version =~ /^4\.[01]/ hs.pack('side'=>'bottom', 'fill'=>'x') vs.pack('side'=>'right', 'fill'=>'y') c.pack('in'=>cf, 'expand'=>'yes', 'fill'=>'both') else c.grid('in'=>cf, 'row'=>0, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') vs.grid('row'=>0, 'column'=>1, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') hs.grid('row'=>1, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') TkGrid.rowconfigure(cf, 0, 'weight'=>1, 'minsize'=>0) TkGrid.columnconfigure(cf, 0, 'weight'=>1, 'minsize'=>0) end } }.pack('side'=>'top', 'fill'=>'both', 'expand'=>'yes') # Display a 3x3 rectangular grid TkcRectangle.new(cvs, '0c', '0c', '30c', '24c', 'width'=>2) TkcLine.new(cvs, '0c', '8c', '30c', '8c', 'width'=>2) TkcLine.new(cvs, '0c', '16c', '30c', '16c', 'width'=>2) TkcLine.new(cvs, '10c', '0c', '10c', '24c', 'width'=>2) TkcLine.new(cvs, '20c', '0c', '20c', '24c', 'width'=>2) if $tk_version =~ /^4.*/ font1 = '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*' font2 = '-Adobe-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*' else font1 = 'Helvetica 12' font2 = 'Helvetica 24 bold' end if TkWinfo.depth($root).to_i > 1 blue = 'DeepSkyBlue3' red = 'red' bisque = 'bisque3' green = 'SeaGreen3' else blue = 'black' red = 'black' bisque = 'black' green = 'black' end # tag ֥Ȥ $tag_item = TkcGroup.new(cvs) # Set up demos within each of the areas of the grid. TkcText.new(cvs, '5c', '.2c', 'text'=>'饤', 'anchor'=>'n') TkcLine.new(cvs, '1c', '1c', '3c', '1c', '1c', '4c', '3c', '4c', 'width'=>2, 'fill'=>blue, 'capstyle'=>'butt', 'join'=>'miter', 'tags'=>$tag_item ) TkcLine.new(cvs, '4.67c','1c','4.67c','4c', 'arrow'=>'last', 'tags'=>$tag_item) TkcLine.new(cvs, '6.33c','1c','6.33c','4c', 'arrow'=>'both', 'tags'=>$tag_item) TkcLine.new(cvs, '5c','6c','9c','6c','9c','1c','8c','1c','8c','4.8c','8.8c', '4.8c','8.8c','1.2c','8.2c','1.2c','8.2c','4.6c','8.6c','4.6c', '8.6c','1.4c','8.4c','1.4c','8.4c','4.4c', 'width'=>3, 'fill'=>red, 'tags'=>$tag_item ) TkcLine.new(cvs, '1c','5c','7c','5c','7c','7c','9c','7c', 'width'=>'.5c', 'stipple'=>'@'+[$demo_dir,'..', 'images','gray25.xbm'].join(File::Separator), 'arrow'=>'both', 'arrowshape'=>'15 15 7', 'tags'=>$tag_item ) TkcLine.new(cvs, '1c','7c','1.75c','5.8c','2.5c','7c','3.25c','5.8c','4c','7c', 'width'=>'.5c', 'capstyle'=>'round', 'join'=>'round', 'tags'=>$tag_item ) TkcText.new(cvs, '15c', '.2c', 'text'=>' (餫ˤĤʤľ)', 'anchor'=>'n') TkcLine.new(cvs, '11c','4c','11.5c','1c','13.5c','1c','14c','4c', 'smooth'=>'on', 'fill'=>blue, 'tags'=>$tag_item ) TkcLine.new(cvs, '15.5c','1c','19.5c','1.5c','15.5c','4.5c','19.5c','4c', 'smooth'=>'on', 'arrow'=>'both', 'width'=>3, 'tags'=>$tag_item ) TkcLine.new(cvs, '12c','6c','13.5c','4.5c','16.5c','7.5c','18c','6c', '16.5c','4.5c','13.5c','7.5c','12c','6c', 'smooth'=>'on', 'width'=>'3m', 'capstyle'=>'round', 'stipple'=>'@'+[$demo_dir, '..', 'images', 'gray25.xbm'].join(File::Separator), 'fill'=>red, 'tags'=>$tag_item ) TkcText.new(cvs, '25c', '.2c', 'text'=>'¿ѷ', 'anchor'=>'n') TkcPolygon.new(cvs, '21c','1.0c','22.5c','1.75c','24c','1.0c','23.25c','2.5c', '24c','4.0c','22.5c','3.25c','21c','4.0c','21.75c','2.5c', 'fill'=>'green', 'outline'=>'black', 'width'=>4, 'tags'=>$tag_item ) TkcPolygon.new(cvs, '25c','4c','25c','4c','25c','1c','26c','1c','27c','4c', '28c','1c','29c','1c','29c','4c','29c','4c', 'fill'=>red, 'smooth'=>'on', 'tags'=> $tag_item) TkcPolygon.new(cvs, '22c','4.5c','25c','4.5c','25c','6.75c','28c','6.75c', '28c','5.25c','24c','5.25c','24c','6.0c','26c','6c','26c', '7.5c','22c','7.5c', 'stipple'=>'@' + [$demo_dir, '..', 'images', 'gray25.xbm'].join(File::Separator), 'outline'=>'black', 'tags'=>$tag_item ) TkcText.new(cvs, '5c', '8.2c', 'text'=>'', 'anchor'=>'n') TkcRectangle.new(cvs, '1c','9.5c','4c','12.5c', 'outline'=>red, 'width'=>'3m', 'tags'=>$tag_item) TkcRectangle.new(cvs, '0.5c','13.5c','4.5c','15.5c', 'fill'=>green, 'tags'=>$tag_item ) TkcRectangle.new(cvs, '6c','10c','9c','15c', 'outline'=>'', 'stipple'=>'@'+[$demo_dir,'..', 'images','gray25.xbm'].join(File::Separator), 'fill'=>blue, 'tags'=>$tag_item ) TkcText.new(cvs, '15c', '8.2c', 'text'=>'ʱ', 'anchor'=>'n') TkcOval.new(cvs, '11c','9.5c','14c','12.5c', 'outline'=>red, 'width'=>'3m', 'tags'=>$tag_item) TkcOval.new(cvs, '10.5c','13.5c','14.5c','15.5c', 'fill'=>green, 'tags'=>$tag_item ) TkcOval.new(cvs, '16c','10c','19c','15c', 'outline'=>'', 'stipple'=>'@'+[$demo_dir,'..', 'images','gray25.xbm'].join(File::Separator), 'fill'=>blue, 'tags'=>$tag_item ) TkcText.new(cvs, '25c', '8.2c', 'text'=>'ƥ', 'anchor'=>'n') TkcRectangle.new(cvs, '22.4c','8.9c','22.6c','9.1c') TkcText.new(cvs, '22.5c', '9c', 'anchor'=>'n', 'font'=>font1, 'width'=>'4c', 'text'=>'ûƥȡɥåס·󥫡()ϳƥƥȤΥ󥫡ݥȤ򼨤', 'tags'=>$tag_item ) TkcRectangle.new(cvs, '25.4c','10.9c','25.6c','11.1c') TkcText.new(cvs, '25.5c', '11c', 'anchor'=>'w', 'font'=>font1, 'fill'=>blue, 'text'=>"Ĥιԡ\n줾Ω\n·\nƺü󥫡Ƥ롣", 'justify'=>'center', 'tags'=>$tag_item ) TkcRectangle.new(cvs, '24.9c','13.9c','25.1c','14.1c') if $tk_version =~ /^4\.[01]/ TkcText.new(cvs, '25c', '14c', 'anchor'=>'c', 'font'=>font2, 'fill'=>red, 'stipple'=>'@' + [$demo_dir, '..', 'images', 'grey.5'].join(File::Separator), 'text'=>'Stippled characters', 'tags'=>$tag_item ) else TkcText.new(cvs, '25c', '14c', 'anchor'=>'c', 'font'=>font2, 'fill'=>red, 'stipple'=>'gray50', 'text'=>'Stippled characters', 'tags'=>$tag_item ) end TkcText.new(cvs, '5c', '16.2c', 'text'=>'', 'anchor'=>'n') TkcArc.new(cvs, '0.5c','17c','7c','20c', 'fill'=>green, 'outline'=>'black', 'start'=>45, 'extent'=>270, 'style'=>'pieslice', 'tags'=>$tag_item) #TkcArc.new(cvs, '6.5c','17c','9.5c','20c', 'width'=>'4m', 'style'=>'arc', # 'outline'=>blue, 'start'=>135, 'extent'=>270, # 'outlinestipple'=>'@' + ['images', 'grey.25'].join(File::Separator), # 'tags'=>$tag_item) TkcArc.new(cvs, '6.5c','17c','9.5c','20c', 'width'=>'4m', 'style'=>'arc', 'outline'=>blue, 'start'=>135, 'extent'=>270, 'outlinestipple'=>'@'+[$demo_dir, '..', 'images','gray25.xbm'].join(File::Separator), 'tags'=>$tag_item) TkcArc.new(cvs, '0.5c','20c','9.5c','24c', 'width'=>'4m', 'style'=>'pieslice', 'fill'=>'', 'outline'=>red, 'start'=>225, 'extent'=>90, 'tags'=>$tag_item) TkcArc.new(cvs, '5.5c','20.5c','9.5c','23.5c', 'width'=>'4m', 'style'=>'chord', 'fill'=>blue, 'outline'=>'', 'start'=>45, 'extent'=>270, 'tags'=>$tag_item) TkcText.new(cvs, '15c', '16.2c', 'text'=>'ӥåȥޥå', 'anchor'=>'n') #TkcBitmap.new(cvs, '13c','20c', # 'bitmap'=>'@' + ['images', 'face'].join(File::Separator), # 'tags'=>$tag_item) TkcBitmap.new(cvs, '13c','20c', 'bitmap'=>'@' + [$demo_dir, '..', 'images', 'face.xbm'].join(File::Separator), 'tags'=>$tag_item) #TkcBitmap.new(cvs, '17c','18.5c', # 'bitmap'=>'@' + ['images', 'noletters'].join(File::Separator), # 'tags'=>$tag_item) TkcBitmap.new(cvs, '17c','18.5c', 'bitmap'=>'@' + [$demo_dir, '..', 'images', 'noletter.xbm'].join(File::Separator), 'tags'=>$tag_item) #TkcBitmap.new(cvs, '17c','21.5c', # 'bitmap'=>'@' + ['images', 'letters'].join(File::Separator), # 'tags'=>$tag_item) # ηǤǽ TkcBitmap.new(cvs, '17c','21.5c') { bitmap '@' + [$demo_dir, '..', 'images', 'letters.xbm'].join(File::Separator) tags $tag_item } #TkcBitmap.new(cvs, '17c','21.5c') { # bitmap '@' + ['images', 'letters'].join(File::Separator) # tags $tag_item #} TkcText.new(cvs, '25c', '16.2c', 'text'=>'ɥ', 'anchor'=>'n') TkButton.new(cvs) {|b| text 'Ƥ' command proc{butPress cvs, red} TkcWindow.new(cvs, '21c','18c', 'window'=>b, 'anchor'=>'nw', 'tags'=>$tag_item) } TkEntry.new(cvs, 'width'=>20, 'relief'=>'sunken') {|e| insert 'end', 'ԽƤ' TkcWindow.new(cvs, '21c','21c', 'window'=>e, 'anchor'=>'nw', 'tags'=>$tag_item) } TkScale.new(cvs, 'from'=>0, 'to'=>100, 'length'=>'6c', 'sliderlength'=>'.4c', 'width'=>'.5c', 'tickinterval'=>0 ) {|scl| TkcWindow.new(cvs, '28.5c','17.5c', 'window'=>scl, 'anchor'=>'n', 'tags'=>$tag_item) } TkcText.new(cvs, '21c', '17.9c', 'text'=>'ܥ:', 'anchor'=>'sw') TkcText.new(cvs, '21c', '20.9c', 'text'=>'ȥ:', 'anchor'=>'sw') TkcText.new(cvs, '28.5c', '17.4c', 'text'=>':', 'anchor'=>'s') # Set up event bindings for canvas: cvs.itembind($tag_item, 'Any-Enter', proc{itemEnter cvs}) cvs.itembind($tag_item, 'Any-Leave', proc{itemLeave cvs}) cvs.bind('2', proc{|x,y| cvs.scan_mark x,y}, '%x %y') cvs.bind('B2-Motion', proc{|x,y| cvs.scan_dragto x,y}, '%x %y') cvs.bind('3', proc{|x,y| itemMark cvs,x,y}, '%x %y') cvs.bind('B3-Motion', proc{|x,y| itemStroke cvs,x,y}, '%x %y') cvs.bind('Control-f', proc{itemsUnderArea cvs}) cvs.bind('1', proc{|x,y| itemStartDrag cvs,x,y}, '%x %y') cvs.bind('B1-Motion', proc{|x,y| itemDrag cvs,x,y}, '%x %y') # Utility methods for highlighting the item under the pointer $restoreCmd = nil def itemEnter (c) if TkWinfo.depth(c).to_i == 1 $restoreCmd = nil return end type = c.itemtype('current') if type == TkcWindow $restoreCmd = nil return end if type == TkcBitmap bg = (c.itemconfiginfo('current', 'background'))[4] $restoreCmd = proc{c.itemconfigure 'current', 'background', bg} c.itemconfigure 'current', 'background', 'SteelBlue2' return end fill = (c.itemconfiginfo('current', 'fill'))[4] if (type == TkcRectangle || type == TkcOval || type == TkcArc) && fill == [] outline = (c.itemconfiginfo('current', 'outline'))[4] $restoreCmd = proc{c.itemconfigure 'current', 'outline', outline} c.itemconfigure 'current', 'outline', 'SteelBlue2' else $restoreCmd = proc{c.itemconfigure 'current', 'fill', fill} c.itemconfigure 'current', 'fill', 'SteelBlue2' end end def itemLeave(c) $restoreCmd.call if $restoreCmd end # Utility methods for stroking out a rectangle and printing what's # underneath the rectangle's area. def itemMark(c,x,y) $areaX1 = c.canvasx(x) $areaY1 = c.canvasy(y) c.delete 'area' end def itemStroke(c,x,y) x = c.canvasx(x) y = c.canvasy(y) if $areaX1 != x && $areaY1 != y c.delete 'area' c.addtag_withtag 'area', TkcRectangle.new(c, $areaX1, $areaY1, x, y, '-outline', 'black') $areaX2 = x $areaY2 = y end end def itemsUnderArea(c) area = c.find_withtag('area') items = [] c.find_enclosed($areaX1,$areaY1,$areaX2,$areaY2).each{|i| items.push(i) if i.gettags.include?($tag_item) } print "Items enclosed by area: #{items.inspect}\n"; STDOUT.flush items.clear c.find_overlapping($areaX1,$areaY1,$areaX2,$areaY2).each{|i| items.push(i) if i.gettags.include?($tag_item) } print "Items overlapping area: #{items.inspect}\n"; STDOUT.flush end $areaX1 = 0 $areaY1 = 0 $areaX2 = 0 $areaY2 = 0 # Utility methods to support dragging of items. def itemStartDrag(c,x,y) $lastX = c.canvasx(x) $lastY = c.canvasy(y) end def itemDrag(c,x,y) x = c.canvasx(x) y = c.canvasy(y) c.move('current', x - $lastX, y - $lastY) $lastX = x $lastY = y end # Method that's invoked when the button embedded in the canvas # is invoked. def butPress(w,color) i = TkcText.new(w, '25c', '18.1c', 'text'=>'Ƥ!!', 'fill'=>color, 'anchor'=>'n') Tk.after(500, proc{w.delete i}) end ================================================ FILE: ext/tk/sample/demos-jp/ixset ================================================ #!/usr/bin/env ruby # ixset -- # A nice interface to "xset" to change X server settings # require 'tk' class Xsettings # # Button actions # def quit @root.destroy end def ok writesettings quit end def cancel readsettings dispsettings end # apply is just "writesettings" # # Read current settings # def readsettings xfd = open("|xset q", 'r') xfd.readlines.each{|line| fields = line.chomp.strip.split(/\s+/) case fields[0] when "auto" if fields[1] == 'repeat:' @kbdrep = fields[2] @w_kbdrep.set(@kbdrep) @kbdcli = fields[6] end when "bell" @bellvol = fields[2] @bellpit = fields[5] @belldur = fields[8] when "acceleration:" @mouseacc = fields[1] @mousethr = fields[3] when "prefer" if fields[2] == 'yes' @screenbla = 'blank' else @screenbla = 'noblank' end @w_screenbla.set(@screenbla) when "timeout:" @screentim = fields[1] @screencyc = fields[3] end } xfd.close end # # Write settings into the X server # def writesettings @bellvol = @w_bellvol.get @bellpit = @w_bellpit.get @belldur = @w_belldur.get @kbdrep = @w_kbdrep.get if @kbdrep == 'on' @kbdcli = @w_kbdcli.get else @kbdcli = 'off' end @mouseacc = @w_mouseacc.get @mousethr = @w_mousethr.get @screentim = @w_screentim.get @screencyc = @w_screencyc.get @screenbla = @w_screenbla.get system("xset \ b #{@bellvol} #{@bellpit} #{@belldur} \ c #{@kbdcli} \ r #{@kbdrep} \ m #{@mouseacc} #{@mousethr} \ s #{@screentim} #{@screencyc} \ s #{@screenbla}") end # # Sends all settings to the window # def dispsettings @w_bellvol.set(@bellvol) @w_bellpit.set(@bellpit) @w_belldur.set(@belldur) @w_kbdonoff.set(@w_kbdrep.get) @w_kbdcli.set(@kbdcli) @w_mouseacc.set(@mouseacc) @w_mousethr.set(@mousethr) @w_screenblank.set(@w_screenbla.get) @w_screenpat.set(@w_screenbla.get) @w_screentim.set(@screentim) @w_screencyc.set(@screencyc) end # # Create all windows, and pack them # class LabelEntry def initialize(parent, text, length) @frame = TkFrame.new(parent) TkLabel.new(@frame, 'text'=>text).pack('side'=>'left','expand'=>'y') @entry = TkEntry.new(@frame, 'width'=>length, 'relief'=>'sunken') { pack('side'=>'left','expand'=>'y') } end def pack(keys) @frame.pack(keys) end def get @entry.value end def set(value) @entry.delete(0,'end') @entry.insert(0, value) end end def createwindows win = self # # Buttons # buttons = TkFrame.new(@root) {|f| [ TkButton.new(f, 'command'=>proc{win.ok}, 'text'=>'Ok'), TkButton.new(f, 'command'=>proc{win.writesettings}, 'text'=>'Apply'), TkButton.new(f, 'command'=>proc{win.cancel}, 'text'=>'Cancel'), TkButton.new(f, 'command'=>proc{win.quit}, 'text'=>'Quit') ].each{|b| b.pack('side'=>'left', 'expand'=>'yes', 'pady'=>5) } } # # Bell settings # bell = TkFrame.new(@root, 'relief'=>'raised', 'borderwidth'=>2) l = TkLabel.new(bell, 'text'=>'Bell Settings') @w_bellvol = TkScale.new(bell, 'from'=>0, 'to'=>100, 'length'=>200, 'tickinterval'=>20, 'orient'=>'horizontal', 'label'=>"Volume (%)") f = TkFrame.new(bell) @w_bellpit = LabelEntry.new(f, "Pitch (Hz)", 6) @w_bellpit.pack('side'=>'left', 'padx'=>5) @w_belldur = LabelEntry.new(f, "Duration (ms)", 6) @w_belldur.pack('side'=>'right', 'padx'=>5) l.pack('side'=>'top', 'expand'=>'yes') @w_bellvol.pack('side'=>'top', 'expand'=>'yes') f.pack('side'=>'top', 'expand'=>'yes') # # Keyboard settings # kbdonoff = nil kbdcli = nil kbd = TkFrame.new(@root, 'relief'=>'raised', 'borderwidth'=>2) l = TkLabel.new(kbd, 'text'=>'Keyboard Repeat Settings') f = TkFrame.new(kbd) @w_kbdonoff = TkCheckButton.new(f, 'text'=>'On', 'relief'=>'flat', 'onvalue'=>'on', 'offvalue'=>'off', 'variable'=>@w_kbdrep ) { def self.set(value) if value == 'on' self.select else self.deselect end end pack('side'=>'left', 'expand'=>'yes', 'fill'=>'both') } @w_kbdcli = TkScale.new(f, 'from'=>0, 'to'=>100, 'length'=>200, 'tickinterval'=>20, 'orient'=>'horizontal', 'label'=>'Click Volume (%)') @w_kbdcli.pack('side'=>'left', 'expand'=>'yes') l.pack('side'=>'top', 'expand'=>'yes') f.pack('side'=>'top', 'expand'=>'yes', 'pady'=>2, 'fill'=>'x') # # Mouse settings # mouse = TkFrame.new(@root, 'relief'=>'raised', 'borderwidth'=>2) l = TkLabel.new(mouse, 'text'=>'Mouse Settings') f = TkFrame.new(mouse) @w_mouseacc = LabelEntry.new(f, 'Acceleration', 3) @w_mouseacc.pack('side'=>'left') @w_mousethr = LabelEntry.new(f, 'Threshold (pixels)', 3) @w_mousethr.pack('side'=>'right') l.pack('side'=>'top') f.pack('side'=>'top', 'expand'=>'yes') # # Screen Saver settings # screen = TkFrame.new(@root, 'relief'=>'raised', 'borderwidth'=>2) l = TkLabel.new(screen, 'text'=>'Screen-saver Settings') f = TkFrame.new(screen) ff1 = TkFrame.new(f) [ @w_screenblank = TkRadioButton.new(ff1, 'text'=>'Blank', 'relief'=>'flat', 'variable'=>@w_screenbla, 'value'=>'blank') { def self.set(value) if value == 'blank' self.select else self.deselect end end }, @w_screenpat = TkRadioButton.new(ff1, 'text'=>'Pattern', 'relief'=>'flat', 'variable'=>@w_screenbla, 'value'=>'noblank') { def self.set(value) if value != 'blank' self.select else self.deselect end end } ].each {|w| w.pack('side'=>'top', 'pady'=>2, 'anchor'=>'w') } ff2 = TkFrame.new(f) [ @w_screentim = LabelEntry.new(ff2, 'Timeout (s)', 5), @w_screencyc = LabelEntry.new(ff2, 'Cycle (s)', 5) ].each{|w| w.pack('side'=>'top', 'pady'=>2, 'anchor'=>'e') } ff1.pack('side'=>'left') ff2.pack('side'=>'left') l.pack('side'=>'top') f.pack('side'=>'top', 'expand'=>'yes') # # Main window # buttons.pack('side'=>'top', 'fill'=>'both') bell.pack('side'=>'top', 'fill'=>'both', 'ipady'=>5, 'expand'=>'yes') kbd.pack('side'=>'top', 'fill'=>'both', 'ipady'=>5, 'expand'=>'yes') mouse.pack('side'=>'top', 'fill'=>'both', 'ipady'=>5, 'expand'=>'yes') screen.pack('side'=>'top', 'fill'=>'both', 'ipady'=>5, 'expand'=>'yes') # # Let the user resize our window # @root.minsize(10,10) end def initialize @root = TkRoot.new @kbdrep = 'on' @w_kbdrep = TkVariable.new(@kbdrep) def @w_kbdrep.get self.value end def @w_kbdrep.set(val) self.value=val end @kbdcli = 0 @bellvol = 100 @bellpit = 440 @belldur = 100 @mouseacc = "3/1" @mousethr = 4 @screenbla = "blank" @w_screenbla = TkVariable.new(@screenbla) def @w_screenbla.get self.value end def @w_screenbla.set(val) self.value=val end @screentim = 600 @screencyc = 600 # # Listen what "xset" tells us... # readsettings # # Create all windows # createwindows # # Write xset parameters # dispsettings end end Xsettings.new Tk.mainloop ================================================ FILE: ext/tk/sample/demos-jp/ixset2 ================================================ #!/usr/bin/env ruby # -*- coding: euc-jp -*- # # ixset -- # A nice interface to "xset" to change X server settings # require 'tk' class Xsettings # # Button actions # def quit @root.destroy end def ok writesettings quit end def cancel readsettings dispsettings @btn_APPLY.state(:disabled) @btn_CANCEL.state(:disabled) end # apply is just "writesettings" def apply writesettings @btn_APPLY.state(:disabled) @btn_CANCEL.state(:disabled) end # # Read current settings # def readsettings xfd = open("|xset q", 'r') xfd.readlines.each{|line| fields = line.chomp.strip.split(/\s+/) case fields[0] when "auto" if fields[1] == 'repeat:' @kbdrep = fields[2] @w_kbdrep.set(@kbdrep) @kbdcli = fields[6] end when "bell" @bellvol = fields[2] @bellpit = fields[5] @belldur = fields[8] when "acceleration:" @mouseacc = fields[1] @mousethr = fields[3] when "prefer" if fields[2] == 'yes' @screenbla = 'blank' else @screenbla = 'noblank' end @w_screenbla.set(@screenbla) when "timeout:" @screentim = fields[1] @screencyc = fields[3] end } xfd.close end # # Write settings into the X server # def writesettings @bellvol = @w_bellvol.get @bellpit = @w_bellpit.get @belldur = @w_belldur.get @kbdrep = @w_kbdrep.get if @kbdrep == 'on' @kbdcli = @w_kbdcli.get else @kbdcli = 'off' end @mouseacc = @w_mouseacc.get @mousethr = @w_mousethr.get @screentim = @w_screentim.get @screencyc = @w_screencyc.get @screenbla = @w_screenbla.get system("xset \ b #{@bellvol} #{@bellpit} #{@belldur} \ c #{@kbdcli} \ r #{@kbdrep} \ m #{@mouseacc} #{@mousethr} \ s #{@screentim} #{@screencyc} \ s #{@screenbla}") end # # Sends all settings to the window # def dispsettings @w_bellvol.set(@bellvol) @w_bellpit.set(@bellpit) @w_belldur.set(@belldur) @w_kbdonoff.set(@w_kbdrep.get) @w_kbdcli.set(@kbdcli) @w_mouseacc.set(@mouseacc) @w_mousethr.set(@mousethr) @w_screenblank.set(@w_screenbla.get) @w_screenpat.set(@w_screenbla.get) @w_screentim.set(@screentim) @w_screencyc.set(@screencyc) end # # Create all windows, and pack them # class LabelEntry def initialize(parent, text, length, range=[]) @frame = TkFrame.new(parent) TkLabel.new(@frame, 'text'=>text).pack('side'=>'left') if range.size > 0 @entry = TkSpinbox.new(@frame, 'width'=>length, 'relief'=>'sunken', 'from'=>range[0], 'to'=>range[1]) else @entry = TkEntry.new(@frame, 'width'=>length, 'relief'=>'sunken') end @entry.pack('side'=>'right','expand'=>'y', 'fill'=>'x') end def epath @frame end def pack(keys) @frame.pack(keys) end def get @entry.value end def set(value) @entry.delete(0,'end') @entry.insert(0, value) end end def createwindows win = self # # Buttons # btn_frame = TkFrame.new(@root) buttons = [ @btn_OK = TkButton.new(btn_frame, 'command'=>proc{win.ok}, 'default'=>'active', 'text'=>'λ'), @btn_APPLY = TkButton.new(btn_frame, 'command'=>proc{win.writesettings}, 'default'=>'normal', 'text'=>'Ŭ', 'state'=>'disabled'), @btn_CANCEL = TkButton.new(btn_frame, 'command'=>proc{win.cancel}, 'default'=>'normal', 'text'=>'', 'state'=>'disabled'), @btn_QUIT = TkButton.new(btn_frame, 'command'=>proc{win.quit}, 'default'=>'normal', 'text'=>'') ] buttons.each{|b| b.pack('side'=>'left', 'expand'=>'yes', 'pady'=>5) } @root.bind('Return', proc{@btn_OK.flash; @btn_OK.invoke}) @root.bind('Escape', proc{@btn_QUIT.flash; @btn_QUIT.invoke}) @root.bind('1', proc{|w| unless buttons.index(w) @btn_APPLY.state(:normal) @btn_CANCEL.state(:normal) end }, '%W') @root.bind('Key', proc{|w, k| unless buttons.index(w) case k when 'Return', 'Escape', 'Tab', /.*Shift.*/ # do nothing else @btn_APPLY.state(:normal) @btn_CANCEL.state(:normal) end end }, '%W %K') # # Bell settings # bell = TkLabelframe.new(@root, 'text'=>'٥', 'padx'=>'1.5m', 'pady'=>'1.5m') @w_bellvol = TkScale.new(bell, 'from'=>0, 'to'=>100, 'length'=>200, 'tickinterval'=>20, 'orient'=>'horizontal', 'label'=>" (%)") f = TkFrame.new(bell) @w_bellpit = LabelEntry.new(f, " (Hz)", 6, [25, 20000]) @w_bellpit.pack('side'=>'left', 'padx'=>5) @w_belldur = LabelEntry.new(f, "³ (ms)", 6, [1, 10000]) @w_belldur.pack('side'=>'right', 'padx'=>5) @w_bellvol.pack('side'=>'top', 'expand'=>'yes') f.pack('side'=>'top', 'expand'=>'yes') # # Keyboard settings # kbdonoff = nil kbdcli = nil kbd = TkLabelframe.new(@root, 'text'=>'ܡɥԡ', 'padx'=>'1.5m', 'pady'=>'1.5m') f = TkFrame.new(kbd) @w_kbdonoff = TkCheckButton.new(f, 'text'=>'å', 'relief'=>'flat', 'onvalue'=>'on', 'offvalue'=>'off', 'variable'=>@w_kbdrep ) { def self.set(value) if value == 'on' self.select else self.deselect end end pack('side'=>'left', 'expand'=>'yes', 'fill'=>'x', 'padx'=>[0, '1m']) } @w_kbdcli = TkScale.new(f, 'from'=>0, 'to'=>100, 'length'=>200, 'tickinterval'=>20, 'orient'=>'horizontal', 'label'=>'å (%)') @w_kbdcli.pack('side'=>'left', 'expand'=>'yes', 'fill'=>'x', 'padx'=>['1m', 0]) f.pack('side'=>'top', 'expand'=>'yes', 'pady'=>2, 'fill'=>'x') # # Mouse settings # mouse = TkLabelframe.new(@root, 'text'=>'ޥ', 'padx'=>'1.5m', 'pady'=>'1.5m') f = TkFrame.new(mouse) @w_mouseacc = LabelEntry.new(f, '®', 5) @w_mouseacc.pack('side'=>'left', 'padx'=>[0, '1m']) @w_mousethr = LabelEntry.new(f, ' (pixels)', 3, [1, 2000]) @w_mousethr.pack('side'=>'right', 'padx'=>['1m', 0]) f.pack('side'=>'top', 'expand'=>'yes') # # Screen Saver settings # screen = TkLabelframe.new(@root, 'text'=>'꡼󥻡', 'padx'=>'1.5m', 'pady'=>'1.5m') @w_screenblank = TkRadioButton.new(screen, 'text'=>'֥ɽ', 'relief'=>'flat', 'anchor'=>'w', 'variable'=>@w_screenbla, 'value'=>'blank') { def self.set(value) if value == 'blank' self.select else self.deselect end end } @w_screenpat = TkRadioButton.new(screen, 'text'=>'ѥɽ', 'relief'=>'flat', 'anchor'=>'w', 'variable'=>@w_screenbla, 'value'=>'noblank') { def self.set(value) if value != 'blank' self.select else self.deselect end end } @w_screentim = LabelEntry.new(screen, 'ॢ (s)', 5, [1, 100000]) @w_screencyc = LabelEntry.new(screen, ' (s)', 5, [1, 100000]) Tk.grid(@w_screenblank, @w_screentim, 'sticky'=>'e') Tk.grid(@w_screenpat, @w_screencyc, 'sticky'=>'e') TkGrid.configure(@w_screenblank, @w_screenpat, 'sticky'=>'ew') # # Main window # param = { 'side'=>'top', 'fill'=>'both', 'expand'=>'yes', 'padx'=>'1m', 'pady'=>'1m' } btn_frame.pack('side'=>'top', 'fill'=>'both') bell.pack(param) kbd.pack(param) mouse.pack(param) screen.pack(param) # # Let the user resize our window # @root.minsize(10,10) end def initialize(title) @root = TkRoot.new('title'=>title) @kbdrep = 'on' @w_kbdrep = TkVariable.new(@kbdrep) def @w_kbdrep.get self.value end def @w_kbdrep.set(val) self.value=val end @kbdcli = 0 @bellvol = 100 @bellpit = 440 @belldur = 100 @mouseacc = "3/1" @mousethr = 4 @screenbla = "blank" @w_screenbla = TkVariable.new(@screenbla) def @w_screenbla.get self.value end def @w_screenbla.set(val) self.value=val end @screentim = 600 @screencyc = 600 # # Listen what "xset" tells us... # readsettings # # Create all windows # createwindows # # Write xset parameters # dispsettings end end Xsettings.new(File.basename($0,'.rb')) Tk.mainloop ================================================ FILE: ext/tk/sample/demos-jp/knightstour.rb ================================================ # -*- coding: euc-jp -*- # # Based on the widget demo of Tcl/Tk8.5.2 # The following is the original copyright text. #---------------------------------------------------------------------------- # Copyright (C) 2008 Pat Thoyts # # Calculate a Knight's tour of a chessboard. # # This uses Warnsdorff's rule to calculate the next square each # time. This specifies that the next square should be the one that # has the least number of available moves. # # Using this rule it is possible to get to a position where # there are no squares available to move into. In this implementation # this occurs when the starting square is d6. # # To solve this fault an enhancement to the rule is that if we # have a choice of squares with an equal score, we should choose # the one nearest the edge of the board. # # If the call to the Edgemost function is commented out you can see # this occur. # # You can drag the knight to a specific square to start if you wish. # If you let it repeat then it will choose random start positions # for each new tour. #---------------------------------------------------------------------------- require 'tk' class Knights_Tour # Return a list of accessible squares from a given square def valid_moves(square) moves = [] [ [-1,-2], [-2,-1], [-2,1], [-1,2], [1,2], [2,1], [2,-1], [1,-2] ].each{|col_delta, row_delta| col = (square % 8) + col_delta row = (square.div(8)) + row_delta moves << (row * 8 + col) if row > -1 && row < 8 && col > -1 && col < 8 } moves end # Return the number of available moves for this square def check_square(square) valid_moves(square).find_all{|pos| ! @visited.include?(pos)}.length end # Select the next square to move to. Returns -1 if there are no available # squares remaining that we can move to. def next_square(square) minimum = 9 nxt = -1 valid_moves(square).each{|pos| unless @visited.include?(pos) cnt = check_square(pos) if cnt < minimum minimum = cnt nxt = pos elsif cnt == minimum nxt = edgemost(nxt, pos) end end } nxt end # Select the square nearest the edge of the board def edgemost(nxt, pos) col_A = 3 - ((3.5 - nxt % 8).abs.to_i) col_B = 3 - ((3.5 - pos % 8).abs.to_i) row_A = 3 - ((3.5 - nxt.div(8)).abs.to_i) row_B = 3 - ((3.5 - pos.div(8)).abs.to_i) (col_A * row_A < col_B * row_B)? nxt : pos end # Display a square number as a standard chess square notation. def _N(square) '%c%d' % [(97 + square % 8), (square.div(8) + 1)] end # Perform a Knight's move and schedule the next move. def move_piece(last, square) @log.insert(:end, "#{@visited.length}. #{_N last} -> #{_N square}\n", '') @log.see(:end) @board.itemconfigure(1+last, :state=>:normal, :outline=>'black') @board.itemconfigure(1+square, :state=>:normal, :outline=>'red') @knight.coords(@board.coords(1+square)[0..1]) @visited << square if (nxt = next_square(square)) != -1 @after_id = Tk.after(@delay.numeric){move_piece(square, nxt) rescue nil} else @start_btn.state :normal if @visited.length == 64 if @initial == square @log.insert :end, 'ͷ(closed tour)' else @log.insert :end, "\n", {} Tk.after(@delay.numeric * 2){tour(rand(64))} if @continuous.bool end else @log.insert :end, "ԡ\n", {} end end end # Begin a new tour of the board given a random start position def tour(square = nil) @visited.clear @log.clear @start_btn.state :disabled 1.upto(64){|n| @board.itemconfigure(n, :state=>:disabled, :outline=>'black') } unless square square = @board.find_closest(*(@knight.coords << 0 << 65))[0].to_i - 1 end @initial = square Tk.after_idle{ move_piece(@initial, @initial) rescue nil } end def _stop Tk.after_cancel(@after_id) rescue nil end def _exit _stop $knightstour.destroy end def set_delay(new) @delay.numeric = new.to_i end def drag_start(w, x, y) w.dtag('selected') w.addtag('selected', :withtag, 'current') @dragging = [x, y] end def drag_motion(w, x, y) return unless @dragging w.move('selected', x - @dragging[0], y - @dragging[1]) @dragging = [x, y] end def drag_end(w, x, y) square = w.find_closest(x, y, 0, 65) w.coords('selected', w.coords(square)[0..1]) w.dtag('selected') @dragging = nil end def make_SeeDismiss ## See Code / Dismiss frame = Ttk::Frame.new($knightstour) sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'ɻ', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'knightstour'}), Ttk::Button.new(frame, :text=>'Ĥ', :image=>$image['delete'], :compound=>:left, :command=>proc{ $knightstour.destroy $knightstour = nil }), :padx=>4, :pady=>4) frame.grid_columnconfigure(0, :weight=>1) frame end def create_gui(parent = nil) $knightstour.destroy rescue nil $knightstour = Tk::Toplevel.new(parent, :title=>"Knight's tour") $knightstour.withdraw base_f = Ttk::Frame.new($knightstour) @board = Tk::Canvas.new(base_f, :width=>240, :height=>240) @log = Tk::Text.new(base_f, :width=>12, :height=>1, :font=>'Arial 8', :background=>'white') scr = @log.yscrollbar(Ttk::Scrollbar.new(base_f)) @visited = [] @delay = TkVariable.new(600) @continuous = TkVariable.new(false) tool_f = Ttk::Frame.new($knightstour) label = Ttk::Label.new(tool_f, :text=>'¹®') scale = Ttk::Scale.new(tool_f, :from=>8, :to=>2000, :variable=>@delay, :command=>proc{|n| set_delay(n)}) check = Ttk::Checkbutton.new(tool_f, :text=>'ȿ', :variable=>@continuous) @start_btn = Ttk::Button.new(tool_f, :text=>'', :command=>proc{tour()}) @exit_btn = Ttk::Button.new(tool_f, :text=>'λ', :command=>proc{_exit()}) 7.downto(0){|row| 0.upto(7){|col| if ((col & 1) ^ (row & 1)).zero? fill = 'bisque' dfill = 'bisque3' else fill = 'tan3' dfill = 'tan4' end coords = [col * 30 + 4, row * 30 + 4, col * 30 + 30, row * 30 + 30] @board.create(TkcRectangle, coords, :fill=>fill, :disabledfill=>dfill, :width=>2, :state=>:disabled) } } @knight_font = TkFont.new(:size=>-24) @knight = TkcText.new(@board, 0, 0, :font=>@knight_font, :text=>Tk::UTF8_String.new('\u265e'), :anchor=>'nw', # :tags=>'knight', :fill=>'black', :activefill=>'#600000') @knight.coords(@board.coords(rand(64)+1)[0..1]) @knight.bind('ButtonPress-1', '%W %x %y'){|w,x,y| drag_start(w,x,y)} @knight.bind('Motion', '%W %x %y'){|w,x,y| drag_motion(w,x,y)} @knight.bind('ButtonRelease-1', '%W %x %y'){|w,x,y| drag_end(w,x,y)} Tk.grid(@board, @log, scr, :sticky=>'news') base_f.grid_rowconfigure(0, :weight=>1) base_f.grid_columnconfigure(0, :weight=>1) Tk.grid(base_f, '-', '-', '-', '-', '-', :sticky=>'news') widgets = [label, scale, check, @start_btn] sg = nil unless $RubyTk_WidgetDemo widgets << @exit_btn if Tk.windowingsystem != 'aqua' #widgets.unshift(Ttk::SizeGrip.new(tool_f)) Ttk::SizeGrip.new(tool_f).pack(:side=>:right, :anchor=>'se') end end Tk.pack(widgets, :side=>:right) if Tk.windowingsystem == 'aqua' TkPack.configure(widgets, :padx=>[4, 4], :pady=>[12, 12]) TkPack.configure(widgets[0], :padx=>[4, 24]) TkPack.configure(widgets[-1], :padx=>[16, 4]) end Tk.grid(tool_f, '-', '-', '-', '-', '-', :sticky=>'ew') if $RubyTk_WidgetDemo Tk.grid(make_SeeDismiss(), '-', '-', '-', '-', '-', :sticky=>'ew') end $knightstour.grid_rowconfigure(0, :weight=>1) $knightstour.grid_columnconfigure(0, :weight=>1) $knightstour.bind('Control-F2'){TkConsole.show} $knightstour.bind('Return'){@start_btn.invoke} $knightstour.bind('Escape'){@exit_btn.invoke} $knightstour.bind('Destroy'){ _stop } $knightstour.protocol('WM_DELETE_WINDOW'){ _exit } $knightstour.deiconify $knightstour.tkwait_destroy end def initialize(parent = nil) create_gui(parent) end end Tk.root.withdraw unless $RubyTk_WidgetDemo Thread.new{Tk.mainloop} if __FILE__ == $0 Knights_Tour.new ================================================ FILE: ext/tk/sample/demos-jp/label.rb ================================================ # -*- coding: euc-jp -*- # # label widget demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($label_demo) && $label_demo $label_demo.destroy $label_demo = nil end # demo Ѥ toplevel widget $label_demo = TkToplevel.new {|w| title("Label Demonstration") iconname("label") positionWindow(w) } base_frame = TkFrame.new($label_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "ˤ5ĤΥ٥뤬ɽƤޤ¦ˤϥƥȥ٥뤬3Ĥꡢ¦ˤϥӥåȥޥåץ٥ȥƥȥ٥뤬ޤ٥ȤΤϤޤ򤤤ΤǤϤޤ󡣤ʤʤįʳǤʤǤ" } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $label_demo $label_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'label'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # label demo ѥե졼 f_left = TkFrame.new(base_frame) f_right = TkFrame.new(base_frame) [f_left, f_right].each{|w| w.pack('side'=>'left', 'expand'=>'yes', 'padx'=>10, 'pady'=>10, 'fill'=>'both')} # label [ TkLabel.new(f_left, 'text'=>'ǽΥ٥'), TkLabel.new(f_left, 'text'=>'2 ܡä⤭夬餻Ƥߤޤ', 'relief'=>'raised'), TkLabel.new(f_left, 'text'=>'3 ܡǤޤ ', 'relief'=>'sunken') ].each{|w| w.pack('side'=>'top', 'expand'=>'yes', 'pady'=>2, 'anchor'=>'w')} # TkLabel.new(f_right) { Tk::Label.new(f_right) { bitmap('@' + [$demo_dir,'..','images','face.xbm'].join(File::Separator)) borderwidth 2 relief 'sunken' }.pack('side'=>'top') TkLabel.new(f_right) { text 'Tcl/Tk ͭ' }.pack('side'=>'top') ================================================ FILE: ext/tk/sample/demos-jp/labelframe.rb ================================================ # -*- coding: euc-jp -*- # # labelframe.rb # # This demonstration script creates a toplevel window containing # several labelframe widgets. # # based on "Id: labelframe.tcl,v 1.2 2001/10/30 11:21:50 dkf Exp" if defined?($labelframe_demo) && $labelframe_demo $labelframe_demo.destroy $labelframe_demo = nil end $labelframe_demo = TkToplevel.new {|w| title("Labelframe Demonstration") iconname("labelframe") positionWindow(w) } base_frame = TkFrame.new($labelframe_demo).pack(:fill=>:both, :expand=>true) # Some information TkLabel.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left, :text=><:top) TkLabelFrame åȤϴϢ widget ޤȤƼ갷Ѥޤ ٥̾ʸǤⲿ餫Υå Ǥ⤫ޤޤ󡣤⤷ʤȤäƤ Ruby ˥󥯤Ƥ Tk 饤֥꤬ labelframe åȤƤʤ 硢ΥǥϤޤưʤϤǤ ξˤ labelframe åȤ Ƥ褦ʤ꿷С Tk Ȥ߹碌ƻ褦ˤƤ EOL # The bottom buttons TkFrame.new(base_frame){|f| pack(:side=>:bottom, :fill=>:x, :pady=>'2m') TkButton.new(f, :text=>'Ĥ', :width=>15, :command=>proc{ $labelframe_demo.destroy $labelframe_demo = nil }).pack(:side=>:left, :expand=>true) TkButton.new(f, :text=>'ɻ', :width=>15, :command=>proc{ showCode 'labelframe' }).pack(:side=>:left, :expand=>true) } # Demo area w = TkFrame.new(base_frame).pack(:side=>:bottom, :fill=>:both, :expand=>true) # A group of radiobuttons in a labelframe TkLabelFrame.new(w, :text=>'', :padx=>2, :pady=>2) {|f| grid(:row=>0, :column=>0, :pady=>'2m', :padx=>'2m') v = TkVariable.new (1..4).each{|i| TkRadiobutton.new(f, :text=>"This is value #{i}", :variable=>v, :value=>i) { pack(:side=>:top, :fill=>:x, :pady=>2) } } } # Using a label window to control a group of options. $lfdummy = TkVariable.new(0) def lfEnableButtons(w) TkWinfo.children(w).each{|child| next if child.path =~ /\.cb$/ if $lfdummy == 1 child.state(:normal) else child.state(:disabled) end } end TkLabelFrame.new(w, :pady=>2, :padx=>2){|f| TkCheckButton.new(f, :widgetname=>'cb', :variable=>$lfdummy, :text=>"ץ", :padx=>0) {|cb| command proc{lfEnableButtons(f)} f.labelwidget(cb) } grid(:row=>0, :column=>1, :pady=>'2m', :padx=>'2m') %w(ץ1 ץ2 ץ3).each{|str| TkCheckbutton.new(f, :text=>str).pack(:side=>:top, :fill=>:x, :pady=>2) } lfEnableButtons(f) } TkGrid.columnconfigure(w, [0,1], :weight=>1) ================================================ FILE: ext/tk/sample/demos-jp/mclist.rb ================================================ # -*- coding: euc-jp -*- # # mclist.rb -- # # This demonstration script creates a toplevel window containing a Ttk # tree widget configured as a multi-column listbox. # # based on "Id: mclist.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp" if defined?($mclist_demo) && $mclist_demo $mclist_demo.destroy $mclist_demo = nil end $mclist_demo = TkToplevel.new {|w| title("Multi-Column List") iconname("mclist") positionWindow(w) } base_frame = TkFrame.new($mclist_demo).pack(:fill=>:both, :expand=>true) ## Explanatory text Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left, :anchor=>'n', :padding=>[10, 2, 10, 6], :text=><:x) TtkȤϡơ޻ǽʿåȽǤ\ Ttk::TreeviewåȤ\ TtkåȥåȤ˴ޤޤ륦åȤΰĤǡ\ 줬ݻڹ¤ΥǡΤΤޤǤɽ뤳Ȥʤ\ ޥɽ뤳ȤǤޤ ΥץϡʣΥäꥹȥܥåñǤ ƥΥȥ(heading)򥯥åС\ Υξ˴ŤƥꥹȤ¤ؤʤϤǤ\ ޤΥȥ֤ζڤʬɥå뤳Ȥǡ\ ѹ뤳ȤǽǤ EOL ## See Code / Dismiss Ttk::Frame.new(base_frame) {|frame| sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'ɻ', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'mclist'}), Ttk::Button.new(frame, :text=>'Ĥ', :image=>$image['delete'], :compound=>:left, :command=>proc{ $mclist_demo.destroy $mclist_demo = nil }), :padx=>4, :pady=>4) grid_columnconfigure(0, :weight=>1) pack(:side=>:bottom, :fill=>:x) } container = Ttk::Frame.new(base_frame) tree = Ttk::Treeview.new(base_frame, :columns=>%w(country capital currency), :show=>:headings) if Tk.windowingsystem != 'aquq' vsb = tree.yscrollbar(Ttk::Scrollbar.new(base_frame)) hsb = tree.xscrollbar(Ttk::Scrollbar.new(base_frame)) else vsb = tree.yscrollbar(Tk::Scrollbar.new(base_frame)) hsb = tree.xscrollbar(Tk::Scrollbar.new(base_frame)) end container.pack(:fill=>:both, :expand=>true) Tk.grid(tree, vsb, :in=>container, :sticky=>'nsew') Tk.grid(hsb, :in=>container, :sticky=>'nsew') container.grid_columnconfigure(0, :weight=>1) container.grid_rowconfigure(0, :weight=>1) ## The data we're going to insert data = [ ['를', '֥Υ쥹', 'ARS'], ['ȥꥢ', '٥', 'AUD'], ['֥饸', '֥饸ꥢ', 'BRL'], ['ʥ', '', 'CAD'], ['', '̵', 'CNY'], ['ե', 'ѥ', 'EUR'], ['ɥ', '٥', 'EUR'], ['', '˥塼ǥ꡼', 'INR'], ['ꥢ', '', 'EUR'], ['', '', 'JPY'], ['ᥭ', 'ᥭƥ', 'MXN'], ['', '⥹', 'RUB'], ['եꥫ', 'ץȥꥢ', 'ZAR'], ['ѹ', 'ɥ', 'GBP'], ['ꥫ', '亮ȥ D.C.', 'USD'], ] ## Code to insert the data nicely font = Ttk::Style.lookup(tree[:style], :font) cols = %w(country capital currency) cols.zip(%w(̾ ̲)).each{|col, name| tree.heading_configure(col, :text=>name, :command=>proc{sort_by(tree, col, false)}) tree.column_configure(col, :width=>TkFont.measure(font, name)) } data.each{|country, capital, currency| #tree.insert('', :end, :values=>[country, capital, currency]) tree.insert(nil, :end, :values=>[country, capital, currency]) cols.zip([country, capital, currency]).each{|col, val| len = TkFont.measure(font, "#{val} ") if tree.column_cget(col, :width) < len tree.column_configure(col, :width=>len) end } } ## Code to do the sorting of the tree contents when clicked on def sort_by(tree, col, direction) tree.children(nil).map!{|row| [tree.get(row, col), row.id]} . sort(&((direction)? proc{|x, y| y <=> x}: proc{|x, y| x <=> y})) . each_with_index{|info, idx| tree.move(info[1], nil, idx)} tree.heading_configure(col, :command=>proc{sort_by(tree, col, ! direction)}) end ================================================ FILE: ext/tk/sample/demos-jp/menu.rb ================================================ # -*- coding: euc-jp -*- # # menus widget demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($menu_demo) && $menu_demo $menu_demo.destroy $menu_demo = nil end # demo Ѥ toplevel widget $menu_demo = TkToplevel.new {|w| title("File Selection Dialogs") iconname("menu") positionWindow(w) } base_frame = TkFrame.new($menu_demo).pack(:fill=>:both, :expand=>true) # menu frame $menu_frame = TkFrame.new(base_frame, 'relief'=>'raised', 'bd'=>2) $menu_frame.pack('side'=>'top', 'fill'=>'x') begin windowingsystem = Tk.windowingsystem() rescue windowingsystem = "" end # label TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left') { if $tk_platform['platform'] == 'macintosh' || windowingsystem == "classic" || windowingsystem == "aqua" text("Υɥ͡ʥ˥塼ȥɥ˥塼鹽ƤޤCommand-X ϤȡXޥɥ³ɽƤʸʤС졼ȤäܵưԤȤǤޤ˥塼桢ǸΤΤϡΥ˥塼κǽιܤ򤹤뤳ȤΩ뤳ȤǤޤ") else text("Υɥ͡ʥ˥塼ȥɥ˥塼鹽ƤޤAlt-X ϤȡX˥塼˥饤դɽƤʸʤСܡɤλ꤬Ǥޤǥ˥塼ΥȥСǽǤ˥塼ꤵ줿ݤˤϡڡǼ¹Ԥ뤳ȤǤޤ뤤ϡ饤դʸϤ뤳ȤǤ¹ԤǤޤ˥塼Υȥ꤬졼äƤϡΥ졼Ϥ뤳Ȥǥ˥塼ꤹ뤳Ȥʤ˼¹Ԥ뤳ȤǤޤ˥塼桢ǸΤΤϡΥ˥塼κǽιܤ򤹤뤳ȤΩ뤳ȤǤޤ") end }.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $menu_demo $menu_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'menu'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # menu TkMenubutton.new($menu_frame, 'text'=>'File', 'underline'=>0) {|m| pack('side'=>'left') TkMenu.new(m, 'tearoff'=>false) {|file_menu| m.configure('menu'=>file_menu) add('command', 'label'=>' ...', 'command'=>proc{fail 'ϡǥǤΤ" ..."Ф륢Ƥޤ'}) add('command', 'label'=>'', 'command'=>proc{fail 'ϡǥǤΤ""Ф륢Ƥޤ'}) add('command', 'label'=>'¸', 'command'=>proc{fail 'ϡǥǤΤ"¸"Ф륢Ƥޤ'}) add('command', 'label'=>'¸() ...', 'command'=>proc{fail 'ϡǥǤΤ"¸() ..."Ф륢Ƥޤ'}) add('separator') add('command', 'label'=>'ץ ...', 'command'=>proc{fail 'ϡǥǤΤ"ץ ..."Ф륢Ƥޤ'}) add('command', 'label'=>'ץ ...', 'command'=>proc{fail 'ϡǥǤΤ"ץ ..."Ф륢Ƥޤ'}) add('separator') add('command', 'label'=>'λ', 'command'=>proc{$menu_demo.destroy}) } } if $tk_platform['platform'] == 'macintosh' || windowingsystem == "classic" || windowingsystem == "aqua" modifier = 'Command' elsif $tk_platform['platform'] == 'windows' modifier = 'Control' else modifier = 'Meta' end TkMenubutton.new($menu_frame, 'text'=>'Basic', 'underline'=>0) {|m| pack('side'=>'left') TkMenu.new(m, 'tearoff'=>false) {|basic_menu| m.configure('menu'=>basic_menu) add('command', 'label'=>'⤷ʤĹȥ') ['A','B','C','D','E','F','G'].each{|c| # add('command', 'label'=>"ʸ \"#{c}\" ", 'underline'=>4, add('command', 'label'=>"Print letter \"#{c}\" (ʸ \"#{c}\" )", 'underline'=>14, 'accelerator'=>"Meta+#{c}", 'command'=>proc{print c,"\n"}, 'accelerator'=>"#{modifier}+#{c}") $menu_demo.bind("#{modifier}-#{c.downcase}", proc{print c,"\n"}) } } } TkMenubutton.new($menu_frame, 'text'=>'Cascades', 'underline'=>0) {|m| pack('side'=>'left') TkMenu.new(m, 'tearoff'=>false) {|cascade_menu| m.configure('menu'=>cascade_menu) add('command', 'label'=>'Print hello(ˤ)', 'command'=>proc{print "Hello(ˤ)\n"}, 'accelerator'=>"#{modifier}+H", 'underline'=>6) $menu_demo.bind("#{modifier}-h", proc{print "Hello(ˤ)\n"}) add('command', 'label'=>'Print goodbye(褦ʤ)', 'command'=>proc{print "Goodbye(褦ʤ)\n"}, 'accelerator'=>"#{modifier}+G", 'underline'=>6) $menu_demo.bind("#{modifier}-g", proc{print "Goodbye(褦ʤ)\n"}) # TkMenu.new(m, 'tearoff'=>false) {|cascade_check| TkMenu.new(cascade_menu, 'tearoff'=>false) {|cascade_check| cascade_menu.add('cascade', 'label'=>'Check buttons(åܥ)', 'menu'=>cascade_check, 'underline'=>0) oil = TkVariable.new(0) add('check', 'label'=>'', 'variable'=>oil) trans = TkVariable.new(0) add('check', 'label'=>'ȥ󥹥ߥå', 'variable'=>trans) brakes = TkVariable.new(0) add('check', 'label'=>'֥졼', 'variable'=>brakes) lights = TkVariable.new(0) add('check', 'label'=>'饤', 'variable'=>lights) add('separator') add('command', 'label'=>'ߤͤɽ', 'command'=>proc{showVars($menu_demo, ['', oil], ['ȥ󥹥ߥå', trans], ['֥졼', brakes], ['饤', lights])} ) invoke 1 invoke 3 } #TkMenu.new(m, 'tearoff'=>false) {|cascade_radio| TkMenu.new(cascade_menu, 'tearoff'=>false) {|cascade_radio| cascade_menu.add('cascade', 'label'=>'Radio buttons(饸ܥ)', 'menu'=>cascade_radio, 'underline'=>0) pointSize = TkVariable.new add('radio', 'label'=>'10 ݥ', 'variable'=>pointSize, 'value'=>10) add('radio', 'label'=>'14 ݥ', 'variable'=>pointSize, 'value'=>14) add('radio', 'label'=>'18 ݥ', 'variable'=>pointSize, 'value'=>18) add('radio', 'label'=>'24 ݥ', 'variable'=>pointSize, 'value'=>24) add('radio', 'label'=>'32 ݥ', 'variable'=>pointSize, 'value'=>32) add('separator') style = TkVariable.new add('radio', 'label'=>'ޥ', 'variable'=>style, 'value'=>'roman') add('radio', 'label'=>'ܡ', 'variable'=>style, 'value'=>'bold') add('radio', 'label'=>'å', 'variable'=>style, 'value'=>'italic') add('separator') add('command', 'label'=>'ߤͤɽ', 'command'=>proc{showVars($menu_demo, ['ݥȥ', pointSize], ['', style])} ) invoke 1 invoke 7 } } } TkMenubutton.new($menu_frame, 'text'=>'Icons', 'underline'=>0) {|m| pack('side'=>'left') TkMenu.new(m, 'tearoff'=>false) {|icon_menu| m.configure('menu'=>icon_menu) add('command', 'bitmap'=>'@'+[$demo_dir,'..', 'images','pattern.xbm'].join(File::Separator), 'command'=>proc{TkDialog.new('title'=>'Bitmap Menu Entry', 'text'=>'ʤ򤷤˥塼ιܤϥƥȤǤϤʤӥåȥޥåפɽƤޤʳǤ¾Υ˥塼ܤѤޤ', 'bitmap'=>'', 'default'=>0, 'buttons'=>'λ')} ) ['info', 'questhead', 'error'].each{|icon| add('command', 'bitmap'=>icon, 'command'=>proc{print "You invoked the #{icon} bitmap\n"}) } } } TkMenubutton.new($menu_frame, 'text'=>'More', 'underline'=>0) {|m| pack('side'=>'left') TkMenu.new(m, 'tearoff'=>false) {|more_menu| m.configure('menu'=>more_menu) [ 'ȥ','̤Υȥ','⤷ʤ','ۤȤɲ⤷ʤ', 'յΤ' ].each{|i| add('command', 'label'=>i, 'command'=>proc{print "You invoked \"#{i}\"\n"}) } } } TkMenubutton.new($menu_frame, 'text'=>'Colors', 'underline'=>0) {|m| pack('side'=>'left') TkMenu.new(m) {|colors_menu| m.configure('menu'=>colors_menu) ['red', 'orange', 'yellow', 'green', 'blue'].each{|c| add('command', 'label'=>c, 'background'=>c, 'command'=>proc{print "You invoked \"#{c}\"\n"}) } } } ================================================ FILE: ext/tk/sample/demos-jp/menu84.rb ================================================ # -*- coding: euc-jp -*- # # menus widget demo (called by 'widget') # # toplevel widget if defined?($menu84_demo) && $menu84_demo $menu84_demo.destroy $menu84_demo = nil end # demo toplevel widget $menu84_demo = TkToplevel.new {|w| title("File Selection Dialogs") iconname("menu84") positionWindow(w) } base_frame = TkFrame.new($menu84_demo).pack(:fill=>:both, :expand=>true) begin windowingsystem = Tk.windowingsystem() rescue windowingsystem = "" end # label TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left') { if $tk_platform['platform'] == 'macintosh' || windowingsystem == "classic" || windowingsystem == "aqua" text("Υɥˤϥɥ˥塼ĥ˥塼СդƤޤCommand+x ('x'ϥޥɥܥ³ɽƤʸǤ) ȥפ뤳ȤˤäƤܤεǽƤӽФȤǤޤǸΥ˥塼ϡޥǥɥγ˥ɥå뤳ȤˤäơΩѥåȤȤʤ褦ڤȤǽǤ") else text("Υɥˤϥɥ˥塼ĥ˥塼СդƤޤAlt+x ('x'ϥ˥塼Dz줿ʸǤ) ȥפ뤳ȤˤäƤ˥塼ƤӽФȤǤޤȤäơ˥塼֤ư뤳ȤǽǤ˥塼ɽƤˤϡ֤߰ιܤ򥹥ڡ򤷤ꡢ줿ʸϤ뤳ȤǤιܤ򤷤ꤹ뤳ȤǤޤ⤷ܤ˥졼λ꤬ʤƤʤСλꤵ줿ϤԤȤǡ˥塼ɽ뤳ȤʤľܤιܤεǽƤӽФޤǸΥ˥塼ϡ˥塼κǽιܤ򤹤뤳ȤˤäơΩѥåȤȤʤ褦ڤȤǽǤ") end }.pack('side'=>'top') menustatus = TkVariable.new(" ") TkFrame.new(base_frame) {|frame| TkLabel.new(frame, 'textvariable'=>menustatus, 'relief'=>'sunken', 'bd'=>1, 'font'=>['Helvetica', '10'], 'anchor'=>'w').pack('side'=>'left', 'padx'=>2, 'expand'=>true, 'fill'=>'both') pack('side'=>'bottom', 'fill'=>'x', 'pady'=>2) } # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $menu84_demo $menu84_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'menu84'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # create menu frame $menu84_frame = TkMenu.new($menu84_demo, 'tearoff'=>false) # menu TkMenu.new($menu84_frame, 'tearoff'=>false) {|m| $menu84_frame.add('cascade', 'label'=>'File', 'menu'=>m, 'underline'=>0) add('command', 'label'=>'Open...', 'command'=>proc{fail 'ñʤǥǤ顢"Open..." ܤεǽäƤϤޤ'}) add('command', 'label'=>'New', 'command'=>proc{fail 'ñʤǥǤ顢"New" ܤεǽäƤϤޤ'}) add('command', 'label'=>'Save', 'command'=>proc{fail 'ñʤǥǤ顢"Save" ܤεǽäƤϤޤ'}) add('command', 'label'=>'Save As...', 'command'=>proc{fail 'ñʤǥǤ顢"Save As..." ܤεǽäƤϤޤ'}) add('separator') add('command', 'label'=>'Print Setup...', 'command'=>proc{fail 'ñʤǥǤ顢"Print Setup..." ܤεǽäƤϤޤ'}) add('command', 'label'=>'Print...', 'command'=>proc{fail 'ñʤǥǤ顢"Print..." ܤεǽäƤϤޤ'}) add('separator') add('command', 'label'=>'Dismiss Menus Demo', 'command'=>proc{$menu84_demo.destroy}) } if $tk_platform['platform'] == 'macintosh' || windowingsystem = "classic" || windowingsystem = "aqua" modifier = 'Command' elsif $tk_platform['platform'] == 'windows' modifier = 'Control' else modifier = 'Meta' end TkMenu.new($menu84_frame, 'tearoff'=>false) {|m| $menu84_frame.add('cascade', 'label'=>'Basic', 'menu'=>m, 'underline'=>0) add('command', 'label'=>'Long entry that does nothing') ['A','B','C','D','E','F','G'].each{|c| add('command', 'label'=>"Print letter \"#{c}\"", 'underline'=>14, 'accelerator'=>"Meta+#{c}", 'command'=>proc{print c,"\n"}, 'accelerator'=>"#{modifier}+#{c}") $menu84_demo.bind("#{modifier}-#{c.downcase}", proc{print c,"\n"}) } } TkMenu.new($menu84_frame, 'tearoff'=>false) {|m| $menu84_frame.add('cascade', 'label'=>'Cascades', 'menu'=>m, 'underline'=>0) add('command', 'label'=>'Print hello', 'command'=>proc{print "Hello\n"}, 'accelerator'=>"#{modifier}+H", 'underline'=>6) $menu84_demo.bind("#{modifier}-h", proc{print "Hello\n"}) add('command', 'label'=>'Print goodbye', 'command'=>proc{print "Goodbye\n"}, 'accelerator'=>"#{modifier}+G", 'underline'=>6) $menu84_demo.bind("#{modifier}-g", proc{print "Goodbye\n"}) TkMenu.new(m, 'tearoff'=>false) {|cascade_check| m.add('cascade', 'label'=>'Check button', 'menu'=>cascade_check, 'underline'=>0) oil = TkVariable.new(0) add('check', 'label'=>'븡', 'variable'=>oil) trans = TkVariable.new(0) add('check', 'label'=>'ȥ󥹥ߥå󸡺', 'variable'=>trans) brakes = TkVariable.new(0) add('check', 'label'=>'֥졼', 'variable'=>brakes) lights = TkVariable.new(0) add('check', 'label'=>'饤ȸ', 'variable'=>lights) add('separator') add('command', 'label'=>'Show current values', 'command'=>proc{showVars($menu84_demo, ['', oil], ['ȥ󥹥ߥå', trans], ['֥졼', brakes], ['饤', lights])} ) invoke 1 invoke 3 } TkMenu.new(m, 'tearoff'=>false) {|cascade_radio| m.add('cascade', 'label'=>'Radio buttons', 'menu'=>cascade_radio, 'underline'=>0) pointSize = TkVariable.new add('radio', 'label'=>'10 point', 'variable'=>pointSize, 'value'=>10) add('radio', 'label'=>'14 point', 'variable'=>pointSize, 'value'=>14) add('radio', 'label'=>'18 point', 'variable'=>pointSize, 'value'=>18) add('radio', 'label'=>'24 point', 'variable'=>pointSize, 'value'=>24) add('radio', 'label'=>'32 point', 'variable'=>pointSize, 'value'=>32) add('separator') style = TkVariable.new add('radio', 'label'=>'Roman', 'variable'=>style, 'value'=>'roman') add('radio', 'label'=>'Bold', 'variable'=>style, 'value'=>'bold') add('radio', 'label'=>'Italic', 'variable'=>style, 'value'=>'italic') add('separator') add('command', 'label'=>'ͤɽ', 'command'=>proc{showVars($menu84_demo, ['pointSize', pointSize], ['style', style])} ) invoke 1 invoke 7 } } TkMenu.new($menu84_frame, 'tearoff'=>false) {|m| $menu84_frame.add('cascade', 'label'=>'Icons', 'menu'=>m, 'underline'=>0) add('command', 'hidemargin'=>1, 'bitmap'=>'@'+[$demo_dir,'..', 'images','pattern.xbm'].join(File::Separator), 'command'=>proc{TkDialog.new('title'=>'Bitmap Menu Entry', 'text'=>'ʤ򤷤˥塼ܤϡʸ˥ӥåȥޥåץ᡼ǹܤɽΤǤʳǤϡۤΥ˥塼ܤȤδ֤ä˰㤤櫓ǤϤޤ', 'bitmap'=>'', 'default'=>0, 'buttons'=>'Ĥ')} ) ['info', 'questhead', 'error'].each{|icon| add('command', 'bitmap'=>icon, 'hidemargin'=>1, 'command'=>proc{print "You invoked the #{icon} bitmap\n"}) } entryconfigure(2, :columnbreak=>true) } TkMenu.new($menu84_frame, 'tearoff'=>false) {|m| $menu84_frame.add('cascade', 'label'=>'More', 'menu'=>m, 'underline'=>0) [ 'An entry','Another entry','Does nothing','Does almost nothing', 'Make life meaningful' ].each{|i| add('command', 'label'=>i, 'command'=>proc{print "You invoked \"#{i}\"\n"}) } m.entryconfigure('Does almost nothing', 'bitmap'=>'questhead', 'compound'=>'left', 'command'=>proc{ TkDialog.new('title'=>'Compound Menu Entry', 'message'=>'ʤ򤷤˥塼ܤϡӥåȥޥåץ᡼ʸȤƱ˰Ĥιܤɽ褦ˤΤǤʳǤϡۤΥ˥塼ܤȤδ֤ä˰㤤櫓ǤϤޤ', 'buttons'=>['λ'], 'bitmap'=>'') }) } TkMenu.new($menu84_frame) {|m| $menu84_frame.add('cascade', 'label'=>'Colors', 'menu'=>m, 'underline'=>0) ['red', 'orange', 'yellow', 'green', 'blue'].each{|c| add('command', 'label'=>c, 'background'=>c, 'command'=>proc{print "You invoked \"#{c}\"\n"}) } } $menu84_demo.menu($menu84_frame) TkMenu.bind('', proc{|w| begin label = w.entrycget('active', 'label') rescue label = " " end menustatus.value = label Tk.update(true) }, '%W') ================================================ FILE: ext/tk/sample/demos-jp/menu8x.rb ================================================ # -*- coding: euc-jp -*- # # menus widget demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($menu8x_demo) && $menu8x_demo $menu8x_demo.destroy $menu8x_demo = nil end # demo Ѥ toplevel widget $menu8x_demo = TkToplevel.new {|w| title("Menu Demonstration (Tk8.x)") iconname("menu") positionWindow(w) } base_frame = TkFrame.new($menu8x_demo).pack(:fill=>:both, :expand=>true) # version check if $tk_version.to_f < 8.0 # label TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left') { text("¹Ԥ褦ȤץȤ Tk8.0 ʾѤǤ뵡ǽѤƤ뤿ᡢʤ Ruby#{VERSION}/Tk#{$tk_version}#{(Tk::JAPANIZED_TK)? 'jp': ''} Ǥ˼¹ԤǤޤ󡣤äƥǥμ¹ԤߤޤΥɻȥܥ򲡤Ȥǡ¹Ԥߤ줿ץȤΥ򻲾Ȥ뤳ȤϲǽǤ") }.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $menu8x_demo $menu8x_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'menu8x'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') else ; # Tk8.x begin windowingsystem = Tk.windowingsystem() rescue windowingsystem = "" end # label TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left') { if $tk_platform['platform'] == 'macintosh' || windowingsystem == "classic" || windowingsystem == "aqua" text("Υɥ͡ʥ˥塼ȥɥ˥塼鹽ƤޤCommand-X ϤȡXޥɥ³ɽƤʸʤС졼ȤäܵưԤȤǤޤ˥塼桢ǸΤΤϡΥ˥塼κǽιܤ򤹤뤳ȤΩ뤳ȤǤޤ") else text("Υɥ͡ʥ˥塼ȥɥ˥塼鹽ƤޤAlt-X ϤȡX˥塼˥饤դɽƤʸʤСܡɤλ꤬Ǥޤǥ˥塼ΥȥСǽǤ˥塼ꤵ줿ݤˤϡڡǼ¹Ԥ뤳ȤǤޤ뤤ϡ饤դʸϤ뤳ȤǤ¹ԤǤޤ˥塼Υȥ꤬졼äƤϡΥ졼Ϥ뤳Ȥǥ˥塼ꤹ뤳Ȥʤ˼¹Ԥ뤳ȤǤޤ˥塼桢ǸΤΤϡΥ˥塼κǽιܤ򤹤뤳ȤΩ뤳ȤǤޤ") end }.pack('side'=>'top') # ɽ $menu8xstatus = TkVariable.new(" ") TkFrame.new(base_frame) {|frame| TkLabel.new(frame, 'textvariable'=>$menu8xstatus, 'relief'=>'sunken', 'bd'=>1, 'font'=>['Helvetica', '10'], 'anchor'=>'w')\ .pack('side'=>'left', 'padx'=>2, 'expand'=>'yes', 'fill'=>'both') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>2) # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $menu8x_demo $menu8x_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'menu8x'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # menu TkMenu.new($menu8x_demo, 'tearoff'=>false) {|m| TkMenu.new(m, 'tearoff'=>false) {|file_menu| m.add('cascade', 'label'=>'File', 'menu'=>file_menu, 'underline'=>0) add('command', 'label'=>' ...', 'command'=>proc{fail 'ϡǥǤΤ" ..."Ф륢Ƥޤ'}) add('command', 'label'=>'', 'command'=>proc{fail 'ϡǥǤΤ""Ф륢Ƥޤ'}) add('command', 'label'=>'¸', 'command'=>proc{fail 'ϡǥǤΤ"¸"Ф륢Ƥޤ'}) add('command', 'label'=>'¸() ...', 'command'=>proc{fail 'ϡǥǤΤ"¸() ..."Ф륢Ƥޤ'}) add('separator') add('command', 'label'=>'ץ ...', 'command'=>proc{fail 'ϡǥǤΤ"ץ ..."Ф륢Ƥޤ'}) add('command', 'label'=>'ץ ...', 'command'=>proc{fail 'ϡǥǤΤ"ץ ..."Ф륢Ƥޤ'}) add('separator') add('command', 'label'=>'λ', 'command'=>proc{$menu8x_demo.destroy}) } if $tk_platform['platform'] == 'macintosh' || windowingsystem == "classic" || windowingsystem == "aqua" modifier = 'Command' elsif $tk_platform['platform'] == 'windows' modifier = 'Control' else modifier = 'Meta' end TkMenu.new(m, 'tearoff'=>false) {|basic_menu| m.add('cascade', 'label'=>'Basic', 'menu'=>basic_menu, 'underline'=>0) add('command', 'label'=>'⤷ʤĹȥ') ['A','B','C','D','E','F','G'].each{|c| # add('command', 'label'=>"ʸ \"#{c}\" ", 'underline'=>4, add('command', 'label'=>"Print letter \"#{c}\" (ʸ \"#{c}\" )", 'underline'=>14, 'accelerator'=>"Meta+#{c}", 'command'=>proc{print c,"\n"}, 'accelerator'=>"#{modifier}+#{c}") $menu8x_demo.bind("#{modifier}-#{c.downcase}", proc{print c,"\n"}) } } TkMenu.new(m, 'tearoff'=>false) {|cascade_menu| m.add('cascade', 'label'=>'Cascades', 'menu'=>cascade_menu, 'underline'=>0) add('command', 'label'=>'Print hello(ˤ)', 'command'=>proc{print "Hello(ˤ)\n"}, 'accelerator'=>"#{modifier}+H", 'underline'=>6) $menu8x_demo.bind("#{modifier}-h", proc{print "Hello(ˤ)\n"}) add('command', 'label'=>'Print goodbye(褦ʤ)', 'command'=>proc{print "Goodbye(褦ʤ)\n"}, 'accelerator'=>"#{modifier}+G", 'underline'=>6) $menu8x_demo.bind("#{modifier}-g", proc{print "Goodbye(褦ʤ)\n"}) TkMenu.new(m, 'tearoff'=>false) {|cascade_check| cascade_menu.add('cascade', 'label'=>'Check buttons(åܥ)', 'menu'=>cascade_check, 'underline'=>0) oil = TkVariable.new(0) add('check', 'label'=>'', 'variable'=>oil) trans = TkVariable.new(0) add('check', 'label'=>'ȥ󥹥ߥå', 'variable'=>trans) brakes = TkVariable.new(0) add('check', 'label'=>'֥졼', 'variable'=>brakes) lights = TkVariable.new(0) add('check', 'label'=>'饤', 'variable'=>lights) add('separator') add('command', 'label'=>'ߤͤɽ', 'command'=>proc{showVars($menu8x_demo, ['', oil], ['ȥ󥹥ߥå', trans], ['֥졼', brakes], ['饤', lights])} ) invoke 1 invoke 3 } TkMenu.new(m, 'tearoff'=>false) {|cascade_radio| cascade_menu.add('cascade', 'label'=>'Radio buttons(饸ܥ)', 'menu'=>cascade_radio, 'underline'=>0) pointSize = TkVariable.new add('radio', 'label'=>'10 ݥ', 'variable'=>pointSize, 'value'=>10) add('radio', 'label'=>'14 ݥ', 'variable'=>pointSize, 'value'=>14) add('radio', 'label'=>'18 ݥ', 'variable'=>pointSize, 'value'=>18) add('radio', 'label'=>'24 ݥ', 'variable'=>pointSize, 'value'=>24) add('radio', 'label'=>'32 ݥ', 'variable'=>pointSize, 'value'=>32) add('separator') style = TkVariable.new add('radio', 'label'=>'ޥ', 'variable'=>style, 'value'=>'roman') add('radio', 'label'=>'ܡ', 'variable'=>style, 'value'=>'bold') add('radio', 'label'=>'å', 'variable'=>style, 'value'=>'italic') add('separator') add('command', 'label'=>'ߤͤɽ', 'command'=>proc{showVars($menu8x_demo, ['ݥȥ', pointSize], ['', style])} ) invoke 1 invoke 7 } } TkMenu.new(m, 'tearoff'=>false) {|icon_menu| m.add('cascade', 'label'=>'Icons', 'menu'=>icon_menu, 'underline'=>0) add('command', 'bitmap'=>'@'+[$demo_dir,'..', 'images','pattern.xbm'].join(File::Separator), 'hidemargin'=>1, 'command'=>proc{TkDialog.new('title'=>'Bitmap Menu Entry', 'text'=>'ʤ򤷤˥塼ιܤϥƥȤǤϤʤӥåȥޥåפɽƤޤʳǤ¾Υ˥塼ܤѤޤ', 'bitmap'=>'', 'default'=>0, 'buttons'=>'λ')} ) ['info', 'questhead', 'error'].each{|icon| add('command', 'bitmap'=>icon, 'hidemargin'=>1, 'command'=>proc{print "You invoked the #{icon} bitmap\n"}) } entryconfigure(2, 'columnbreak'=>1) } TkMenu.new(m, 'tearoff'=>false) {|more_menu| m.add('cascade', 'label'=>'More', 'menu'=>more_menu, 'underline'=>0) [ 'ȥ','̤Υȥ','⤷ʤ','ۤȤɲ⤷ʤ', 'յΤ' ].each{|i| add('command', 'label'=>i, 'command'=>proc{print "You invoked \"#{i}\"\n"}) } } TkMenu.new(m) {|colors_menu| m.add('cascade', 'label'=>'Colors', 'menu'=>colors_menu, 'underline'=>1) ['red', 'orange', 'yellow', 'green', 'blue'].each{|c| add('command', 'label'=>c, 'background'=>c, 'command'=>proc{print "You invoked \"#{c}\"\n"}) } } $menu8x_demo.configure('menu'=>m) } TkMenu.bind('', proc{|w| begin label = w.entrycget('active', 'label') rescue label = ' ' end $menu8xstatus.value = label Tk.update('idletasks') }, '%W') end ; # Tk 8.x ================================================ FILE: ext/tk/sample/demos-jp/menubu.rb ================================================ # -*- coding: euc-jp -*- require "tkcanvas" def optionMenu(menubutton, varName, firstValue, *rest) varName.value = firstValue configoptions = {'textvariable'=>varName,'indicatoron'=>'on', 'relief'=>'raised','borderwidth'=>2,'highlightthickness'=>2, 'anchor'=>'c','direction'=>'flush'} configoptions.each {|key, value| menubutton.configure(key, value) } menu = TkMenu.new(menubutton) { tearoff 'off' add 'radio', 'label'=>firstValue, 'variable'=>varName } menubutton.menu(menu) for i in rest menu.add 'radio', 'label'=>i, 'variable'=>varName end return menu end if defined?($menubu_demo) && $menubu_demo $menubu_demo.destroy $menubu_demo = nil end $menubu_demo = TkToplevel.new {|w| title("Menu Button Demonstration") iconname("menubutton") } positionWindow($menubu_demo) base_frame = TkFrame.new($menubu_demo).pack(:fill=>:both, :expand=>true) # version check if $tk_version.to_f < 8.0 # label TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left') { text("¹Ԥ褦ȤץȤ Tk8.0 ʾѤǤ뵡ǽѤƤ뤿ᡢʤ Ruby#{VERSION}/Tk#{$tk_version}#{(Tk::JAPANIZED_TK)? 'jp': ''} Ǥ˼¹ԤǤޤ󡣤äƥǥμ¹ԤߤޤΥɻȥܥ򲡤Ȥǡ¹Ԥߤ줿ץȤΥ򻲾Ȥ뤳ȤϲǽǤ") }.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $menubu_demo $menubu_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'menubu'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') else ; # Tk8.x body = TkFrame.new(base_frame) body.pack('expand'=>'yes', 'fill'=>'both') below = TkMenubutton.new(body) { text "Below" underline 0 direction 'below' relief 'raised' } belowMenu = TkMenu.new(below) { tearoff 0 add 'command', 'label'=>"Below menu: first item", 'command'=>proc {puts "\"You have selected the first item from the Below menu.\""} add 'command', 'label'=>"Below menu: second item", 'command'=>proc {puts "\"You have selected the second item from the Below menu.\""} } below.menu(belowMenu) below.grid('row'=>0, 'column'=>1, 'sticky'=>'n') below = TkMenubutton.new(body) { text "Below" underline 0 direction 'below' relief 'raised' } belowMenu = TkMenu.new(below) { tearoff 0 add 'command', 'label'=>"Below menu: first item", 'command'=>proc {puts "\"You have selected the first item from the Below menu.\""} add 'command', 'label'=>"Below menu: second item", 'command'=>proc {puts "\"You have selected the second item from the Below menu.\""} } below.menu(belowMenu) below.grid('row'=>0, 'column'=>1, 'sticky'=>'n') below = TkMenubutton.new(body) { text "Below" underline 0 direction 'below' relief 'raised' } belowMenu = TkMenu.new(below) { tearoff 0 add 'command', 'label'=>"Below menu: first item", 'command'=>proc {puts "\"You have selected the first item from the Below menu.\""} add 'command', 'label'=>"Below menu: second item", 'command'=>proc {puts "\"You have selected the second item from the Below menu.\""} } below.menu(belowMenu) below.grid('row'=>0, 'column'=>1, 'sticky'=>'n') right = TkMenubutton.new(body) { text "Right" underline 0 direction 'right' relief 'raised' } rightMenu = TkMenu.new(right) { tearoff 0 add 'command', 'label'=>"Right menu: first item", 'command'=>proc {puts "\"You have selected the first item from the Left menu.\""} add 'command', 'label'=>"Right menu: second item", 'command'=>proc {puts "\"You have selected the second item from the Right menu.\""} } right.menu(rightMenu) right.grid('row'=>1, 'column'=>0, 'sticky'=>'w') left = TkMenubutton.new(body) { text "Left" underline 0 direction 'left' relief 'raised' } leftMenu = TkMenu.new(left) { tearoff 0 add 'command', 'label'=>"Left menu: first item", 'command'=>proc {puts "\"You have selected the first item from the Left menu.\""} add 'command', 'label'=>"Left menu: second item", 'command'=>proc {puts "\"You have selected the second item from the Left menu.\""} } left.menu(leftMenu) left.grid('row'=>1, 'column'=>2, 'sticky'=>'e') center = TkFrame.new(body) { grid('row'=>1, 'column'=>1, 'sticky'=>'news') } above = TkMenubutton.new(body) { text "Above" underline 0 direction 'above' relief 'raised' } aboveMenu = TkMenu.new(above) { tearoff 0 add 'command', 'label'=>"Above menu: first item", 'command'=>proc {puts "\"You have selected the first item from the Above menu.\""} add 'command', 'label'=>"Above menu: second item", 'command'=>proc {puts "\"You have selected the second item from the Above menu.\""} } above.menu(aboveMenu) above.grid('row'=>2, 'column'=>1, 'sticky'=>'s') center = TkFrame.new(body) { grid('row'=>1, 'column'=>1, 'sticky'=>'news') } TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc { tmppath = $menubu_demo $menubu_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc { showCode 'menubu' } }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'expand'=>'yes', 'fill'=>'x', 'pady'=>'2m') msg = TkLabel.new(center) { # font $font wraplength '4i' justify 'left' text "ϥ˥塼ܥΥǥǤ\"Below\"Υܥ\ ˥˥塼Ф\"Right\"Υܥϱ˥˥塼Фơ\ ġĤȤʤޤʸϤβˤ2ĤΥץ˥塼ޤ\ 1Ĥ̤Υ˥塼ǡ⤦1Ĥ16ΥѥåȤǤ" } msg.pack('side'=>'top', 'padx'=>25, 'pady'=>25) TkFrame.new(center) {|f| menubuttonoptions = TkVariable.new mbutton = TkMenubutton.new(f) options = optionMenu(mbutton, menubuttonoptions, 'one', 'two', 'three') mbutton.pack('side'=>'left', 'padx'=>25, 'pady'=>25) paletteColor = TkVariable.new colors = ['Black','red4','DarkGreen','NavyBlue', 'gray75', 'Red','Green','Blue','gray50','Yellow','Cyan','Magenta', 'White','Brown','DarkSeaGreen','DarkViolet'] colorMenuButton = TkMenubutton.new(f) m = optionMenu(colorMenuButton, paletteColor, *colors) begin windowingsystem = Tk.windowingsystem() rescue windowingsystem = "" end if windowingsystem == "classic" || windowingsystem == "aqua" topBorderColor = 'Black' bottomBorderColor = 'Black' else topBorderColor = 'gray50' bottomBorderColor = 'gray75' end for i in 0..15 image = TkPhotoImage.new('height'=>16, 'width'=>16) image.put(topBorderColor, 0, 0, 16, 1) image.put(topBorderColor, 0, 1, 1, 16) image.put(bottomBorderColor, 0, 15, 16, 16) image.put(bottomBorderColor, 15, 1, 16, 16) image.put(colors[i], 1, 1, 15, 15) selectimage = TkPhotoImage.new('height'=>16, 'width'=>16) selectimage.put('Black', 0, 0, 16, 2) selectimage.put('Black', 0, 2, 2, 16) selectimage.put('Black', 2, 14, 16, 16) selectimage.put('Black', 14, 2, 16, 14) selectimage.put(colors[i], 2, 2, 14, 14) m.entryconfigure(i, 'image'=>image, 'selectimage'=>selectimage, 'hidemargin'=>'on') end m.configure('tearoff', 'on') for c in ['Black', 'gray75', 'gray50', 'White'] m.entryconfigure(c, 'columnbreak'=>1) end colorMenuButton.pack('side'=>'left', 'padx'=>25, 'pady'=>25) pack 'padx'=>25, 'pady'=>25 } end ; # Tk8.x ================================================ FILE: ext/tk/sample/demos-jp/msgbox.rb ================================================ # -*- coding: euc-jp -*- # # message boxes widget demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($msgbox_demo) && $msgbox_demo $msgbox_demo.destroy $msgbox_demo = nil end # demo Ѥ toplevel widget $msgbox_demo = TkToplevel.new {|w| title("Message Box Demonstration") iconname("messagebox") positionWindow(w) } base_frame = TkFrame.new($msgbox_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'4i', 'justify'=>'left', 'text'=>"ޤɽ륢ȥåܥåμDzθ\"åܥå\"ܥ򲡤ȡꤷåܥåɽޤ").pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $msgbox_demo $msgbox_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'msgbox'} }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'åܥå' command proc{showMessageBox $msgbox_demo} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame $msgbox_leftframe = TkFrame.new(base_frame) $msgbox_rightframe = TkFrame.new(base_frame) $msgbox_leftframe .pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y', 'pady'=>'.5c', 'padx'=>'.5c') $msgbox_rightframe.pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y', 'pady'=>'.5c', 'padx'=>'.5c') TkLabel.new($msgbox_leftframe, 'text'=>'').pack('side'=>'top') TkFrame.new($msgbox_leftframe, 'relief'=>'ridge', 'bd'=>1, 'height'=>2)\ .pack('side'=>'top', 'fill'=>'x', 'expand'=>'no') $msgboxIcon = TkVariable.new('info') ['error', 'info', 'question', 'warning'].each {|icon| TkRadioButton.new($msgbox_leftframe, 'text'=>icon, 'variable'=>$msgboxIcon, 'relief'=>'flat', 'value'=>icon, 'width'=>16, 'anchor'=>'w').pack('side'=>'top', 'pady'=>2, 'anchor'=>'w', 'fill'=>'x') } TkLabel.new($msgbox_rightframe, 'text'=>'').pack('side'=>'top') TkFrame.new($msgbox_rightframe, 'relief'=>'ridge', 'bd'=>1, 'height'=>2)\ .pack('side'=>'top', 'fill'=>'x', 'expand'=>'no') $msgboxType = TkVariable.new('ok') ['abortretryignore', 'ok', 'okcancel', 'retrycancel', 'yesno', 'yesnocancel'].each {|type| TkRadioButton.new($msgbox_rightframe, 'text'=>type, 'variable'=>$msgboxType, 'relief'=>'flat', 'value'=>type, 'width'=>16, 'anchor'=>'w').pack('side'=>'top', 'pady'=>2, 'anchor'=>'w', 'fill'=>'x') } def showMessageBox(w) button = Tk.messageBox('icon'=>$msgboxIcon.value, 'type'=>$msgboxType.value, 'title'=>'Message', 'parent'=>w, 'message'=>"\"#{$msgboxType.value}\"ȤΥåܥåǡ\"#{$msgboxIcon.value}\"ΥɽƤޤ") Tk.messageBox('icon'=>'info', 'type'=>'ok', 'parent'=>w, 'message'=>"ʤ \"#{button}\" 򲡤ޤ͡") end ================================================ FILE: ext/tk/sample/demos-jp/msgbox2.rb ================================================ # -*- coding: euc-jp -*- # # message boxes widget demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($msgbox2_demo) && $msgbox2_demo $msgbox2_demo.destroy $msgbox2_demo = nil end # demo Ѥ toplevel widget $msgbox2_demo = TkToplevel.new {|w| title("Message Box Demonstration") iconname("messagebox") positionWindow(w) } base_frame = TkFrame.new($msgbox2_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'4i', 'justify'=>'left', 'text'=>"ޤɽ륢ȥåܥåμDzθ\"åܥå\"ܥ򲡤ȡꤵ줿ǡåȾܺ٥ƥȤȤäåܥåɽޤ").pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $msgbox2_demo $msgbox2_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'msgbox2'} }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'åܥå' command proc{showMessageBox $msgbox2_demo} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame $msgbox_leftframe = TkFrame.new(base_frame) $msgbox_rightframe = TkFrame.new(base_frame) $msgbox_leftframe .pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y', 'pady'=>'.5c', 'padx'=>'.5c') $msgbox_rightframe.pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y', 'pady'=>'.5c', 'padx'=>'.5c') TkLabel.new($msgbox_leftframe, 'text'=>'').pack('side'=>'top') TkFrame.new($msgbox_leftframe, 'relief'=>'ridge', 'bd'=>1, 'height'=>2)\ .pack('side'=>'top', 'fill'=>'x', 'expand'=>'no') $msgboxIcon = TkVariable.new('info') ['error', 'info', 'question', 'warning'].each {|icon| TkRadioButton.new($msgbox_leftframe, 'text'=>icon, 'variable'=>$msgboxIcon, 'relief'=>'flat', 'value'=>icon, 'width'=>16, 'anchor'=>'w').pack('side'=>'top', 'pady'=>2, 'anchor'=>'w', 'fill'=>'x') } TkLabel.new($msgbox_rightframe, 'text'=>'').pack('side'=>'top') TkFrame.new($msgbox_rightframe, 'relief'=>'ridge', 'bd'=>1, 'height'=>2)\ .pack('side'=>'top', 'fill'=>'x', 'expand'=>'no') $msgboxType = TkVariable.new('ok') ['abortretryignore', 'ok', 'okcancel', 'retrycancel', 'yesno', 'yesnocancel'].each {|type| TkRadioButton.new($msgbox_rightframe, 'text'=>type, 'variable'=>$msgboxType, 'relief'=>'flat', 'value'=>type, 'width'=>16, 'anchor'=>'w').pack('side'=>'top', 'pady'=>2, 'anchor'=>'w', 'fill'=>'x') } def showMessageBox(w) button = Tk.messageBox('icon'=>$msgboxIcon.value, 'type'=>$msgboxType.value, 'title'=>'Message', 'parent'=>w, 'message'=>"\"#{$msgboxType.value}\"פΥåܥå", 'detail'=>"\"#{$msgboxType.value}\"ȤΥåܥåǡ\"#{$msgboxIcon.value}\"ΥɽƤޤΥܥΤ줫򤷤ƥåƤ") Tk.messageBox('icon'=>'info', 'type'=>'ok', 'parent'=>w, 'message'=>"ʤ \"#{button}\" 򲡤ޤ͡") end ================================================ FILE: ext/tk/sample/demos-jp/paned1.rb ================================================ # -*- coding: euc-jp -*- # # paned1.rb # # This demonstration script creates a toplevel window containing # a paned window that separates two windows horizontally. # # based on "Id: paned1.tcl,v 1.1 2002/02/22 14:07:01 dkf Exp" if defined?($paned1_demo) && $paned1_demo $paned1_demo.destroy $paned1_demo = nil end $paned1_demo = TkToplevel.new {|w| title("Horizontal Paned Window Demonstration") iconname("paned1") positionWindow(w) } base_frame = TkFrame.new($paned1_demo).pack(:fill=>:both, :expand=>true) TkLabel.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left, :text=><:top) οդ줿ĤΥɥδ֤λڤȤϡĤΰ򤽤줾ΥɥΤʬ䤹뤿ΤΤǤܥǻڤȡʬ䥵ѹǤϺɽϤʤ줺ꤵȤɽޤޥˤڤɿ路ƥѹɽʤ褦ˤϡޥܥȤäƤ ⤷ʤȤäƤ Ruby ˥󥯤Ƥ Tk 饤֥꤬ panedwindow Ƥʤ 硢ΥǥϤޤưʤϤǤξˤ panedwindow Ƥ褦 꿷С Tk Ȥ߹碌ƻ 褦ˤƤ EOL # The bottom buttons TkFrame.new(base_frame){|f| pack(:side=>:bottom, :fill=>:x, :pady=>'2m') TkButton.new(f, :text=>'Ĥ', :width=>15, :command=>proc{ $paned1_demo.destroy $paned1_demo = nil }).pack(:side=>:left, :expand=>true) TkButton.new(f, :text=>'ɻ', :width=>15, :command=>proc{ showCode 'paned1' }).pack(:side=>:left, :expand=>true) } TkPanedwindow.new(base_frame, :orient=>:horizontal){|f| add(Tk::Label.new(f, :text=>"This is the\nleft side", :bg=>'yellow'), Tk::Label.new(f, :text=>"This is the\nright side", :bg=>'cyan')) pack(:side=>:top, :expand=>true, :fill=>:both, :pady=>2, :padx=>'2m') } ================================================ FILE: ext/tk/sample/demos-jp/paned2.rb ================================================ # -*- coding: euc-jp -*- # # paned2.rb -- # # This demonstration script creates a toplevel window containing # a paned window that separates two windows vertically. # # based on "Id: paned2.tcl,v 1.1 2002/02/22 14:07:01 dkf Exp" if defined?($paned2_demo) && $paned2_demo $paned2_demo.destroy $paned2_demo = nil end $paned2_demo = TkToplevel.new {|w| title("Vertical Paned Window Demonstration") iconname("paned2") positionWindow(w) } base_frame = TkFrame.new($paned2_demo).pack(:fill=>:both, :expand=>true) TkLabel.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left, :text=><:top) ΥСդΥåȤ֤줿ĤΥɥδ֤λڤȤϡĤΰ򤽤줾ΥɥΤʬ䤹뤿ΤΤǤܥǻڤȡʬ䥵ѹǤϺɽϤʤ줺ꤵȤɽޤޥˤڤɿ路ƥѹɽʤ褦ˤϡޥܥȤäƤ ⤷ʤȤäƤ Ruby ˥󥯤Ƥ Tk 饤֥꤬ panedwindow Ƥʤ 硢ΥǥϤޤưʤϤǤξˤ panedwindow Ƥ褦 꿷С Tk Ȥ߹碌ƻ 褦ˤƤ EOL # The bottom buttons TkFrame.new(base_frame){|f| pack(:side=>:bottom, :fill=>:x, :pady=>'2m') TkButton.new(f, :text=>'Ĥ', :width=>15, :command=>proc{ $paned2_demo.destroy $paned2_demo = nil }).pack(:side=>:left, :expand=>true) TkButton.new(f, :text=>'ɻ', :width=>15, :command=>proc{ showCode 'paned2' }).pack(:side=>:left, :expand=>true) } paneList = TkVariable.new # define as normal variable (not array) paneList.value = [ # ruby's array --> tcl's list 'Ruby/Tk ΥåȰ', 'TkButton', 'TkCanvas', 'TkCheckbutton', 'TkEntry', 'TkFrame', 'TkLabel', 'TkLabelframe', 'TkListbox', 'TkMenu', 'TkMenubutton', 'TkMessage', 'TkPanedwindow', 'TkRadiobutton', 'TkScale', 'TkScrollbar', 'TkSpinbox', 'TkText', 'TkToplevel' ] # Create the pane itself TkPanedwindow.new(base_frame, :orient=>:vertical){|f| pack(:side=>:top, :expand=>true, :fill=>:both, :pady=>2, :padx=>'2m') add(TkFrame.new(f){|paned2_top| TkListbox.new(paned2_top, :listvariable=>paneList) { # Invert the first item to highlight it itemconfigure(0, :background=>self.cget(:foreground), :foreground=>self.cget(:background) ) yscrollbar(TkScrollbar.new(paned2_top).pack(:side=>:right, :fill=>:y)) pack(:fill=>:both, :expand=>true) } }, TkFrame.new(f, :height=>120) {|paned2_bottom| # The bottom window is a text widget with scrollbar paned2_xscr = TkScrollbar.new(paned2_bottom) paned2_yscr = TkScrollbar.new(paned2_bottom) paned2_text = TkText.new(paned2_bottom, :width=>30, :wrap=>:non) { insert('1.0', '֤ƤΤϡ' + '̤ΥƥȥåȤǤ') xscrollbar(paned2_xscr) yscrollbar(paned2_yscr) } Tk.grid(paned2_text, paned2_yscr, :sticky=>'nsew') Tk.grid(paned2_xscr, :sticky=>'nsew') TkGrid.columnconfigure(paned2_bottom, 0, :weight=>1) TkGrid.rowconfigure(paned2_bottom, 0, :weight=>1) } ) } ================================================ FILE: ext/tk/sample/demos-jp/pendulum.rb ================================================ # -*- coding: euc-jp -*- # # This demonstration illustrates how Tcl/Tk can be used to construct # simulations of physical systems. # (called by 'widget') # # based on Tcl/Tk8.5a2 widget demos # destroy toplevel widget for this demo script if defined?($pendulum_demo) && $pendulum_demo $pendulum_demo.destroy $pendulum_demo = nil end # create toplevel widget $pendulum_demo = TkToplevel.new {|w| title("Pendulum Animation Demonstration") iconname("pendulum") positionWindow(w) } base_frame = TkFrame.new($pendulum_demo).pack(:fill=>:both, :expand=>true) # create label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text 'ΥǥϡʪϤΥߥ졼˴ؤ褦ʥ˥᡼¹Ԥ뤿 Ruby/Tk ɤΤ褦Ѥ뤳ȤǤ뤫򼨤Ƥޤ¦ΥХñʿҤǤʪϼΤΥեɽǤΤФ¦ΥХϷϤΰ֤Υաʳ®٤ȳ٤ȤץåȤΡˤˤʤäƤޤ¦ΥХǥåӥɥåԤäƿҤνŤΰ֤ѤƤߤƤ' } msg.pack('side'=>'top') # create frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $pendulum_demo $pendulum_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'pendulum'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # animated wave class PendulumAnimationDemo def initialize(frame) # Create some structural widgets @pane = TkPanedWindow.new(frame, :orient=>:horizontal).pack(:fill=>:both, :expand=>true) # @pane.add(@lf1 = TkLabelFrame.new(@pane, :text=>'Pendulum Simulation')) # @pane.add(@lf2 = TkLabelFrame.new(@pane, :text=>'Phase Space')) @lf1 = TkLabelFrame.new(@pane, :text=>'Pendulum Simulation') @lf2 = TkLabelFrame.new(@pane, :text=>'Phase Space') # Create the canvas containing the graphical representation of the # simulated system. @c = TkCanvas.new(@lf1, :width=>320, :height=>200, :background=>'white', :borderwidth=>2, :relief=>:sunken) TkcText.new(@c, 5, 5, :anchor=>:nw, :text=>'Click to Adjust Bob Start Position') # Coordinates of these items don't matter; they will be set properly below @plate = TkcLine.new(@c, 0, 25, 320, 25, :width=>2, :fill=>'grey50') @rod = TkcLine.new(@c, 1, 1, 1, 1, :width=>3, :fill=>'black') @bob = TkcOval.new(@c, 1, 1, 2, 2, :width=>3, :fill=>'yellow', :outline=>'black') TkcOval.new(@c, 155, 20, 165, 30, :fill=>'grey50', :outline=>'') # pack @c.pack(:fill=>:both, :expand=>true) # Create the canvas containing the phase space graph; this consists of # a line that gets gradually paler as it ages, which is an extremely # effective visual trick. @k = TkCanvas.new(@lf2, :width=>320, :height=>200, :background=>'white', :borderwidth=>2, :relief=>:sunken) @y_axis = TkcLine.new(@k, 160, 200, 160, 0, :fill=>'grey75', :arrow=>:last) @x_axis = TkcLine.new(@k, 0, 100, 320, 100, :fill=>'grey75', :arrow=>:last) @graph = {} 90.step(0, -10){|i| # Coordinates of these items don't matter; # they will be set properly below @graph[i] = TkcLine.new(@k, 0, 0, 1, 1, :smooth=>true, :fill=>"grey#{i}") } # labels @label_theta = TkcText.new(@k, 0, 0, :anchor=>:ne, :text=>'q', :font=>'Symbol 8') @label_dtheta = TkcText.new(@k, 0, 0, :anchor=>:ne, :text=>'dq', :font=>'Symbol 8') # pack @k.pack(:fill=>:both, :expand=>true) # Initialize some variables @points = [] @theta = 45.0 @dTheta = 0.0 @length = 150 # animation loop @timer = TkTimer.new(15){ repeat } # binding @c.bindtags_unshift(btag = TkBindTag.new) btag.bind('Destroy'){ @timer.stop } btag.bind('1', proc{|x, y| @timer.stop; showPendulum(x.to_i, y.to_i)}, '%x %y') btag.bind('B1-Motion', proc{|x, y| showPendulum(x.to_i, y.to_i)}, '%x %y') btag.bind('ButtonRelease-1', proc{|x, y| showPendulum(x.to_i, y.to_i); @timer.start }, '%x %y') btag.bind('Configure', proc{|w| @plate.coords(0, 25, w.to_i, 25)}, '%w') @k.bind('Configure', proc{|h, w| h = h.to_i w = w.to_i @psh = h/2; @psw = w/2 @x_axis.coords(2, @psh, w-2, @psh) @y_axis.coords(@psw, h-2, @psw, 2) @label_theta.coords(@psw-4, 6) @label_dtheta.coords(w-6, @psh+4) }, '%h %w') # add Tk.update @pane.add(@lf1) @pane.add(@lf2) # init display showPendulum # animation start @timer.start(500) end # This procedure makes the pendulum appear at the correct place on the # canvas. If the additional arguments x, y are passed instead of computing # the position of the pendulum from the length of the pendulum rod and its # angle, the length and angle are computed in reverse from the given # location (which is taken to be the centre of the pendulum bob.) def showPendulum(x=nil, y=nil) if x && y && (x != 160 || y != 25) @dTheta = 0.0 x2 = x - 160 y2 = y - 25 @length = Math.hypot(x2, y2) @theta = Math.atan2(x2,y2)*180/Math::PI else angle = @theta*Math::PI/180 x = 160 + @length*Math.sin(angle) y = 25 + @length*Math.cos(angle) end @rod.coords(160, 25, x, y) @bob.coords(x-15, y-15, x+15, y+15) end # Update the phase-space graph according to the current angle and the # rate at which the angle is changing (the first derivative with # respect to time.) def showPhase unless @psw && @psh @psw = @k.width/2 @psh = @k.height/2 end @points << @theta + @psw << -20*@dTheta + @psh if @points.length > 100 @points = @points[-100..-1] end (0...100).step(10){|i| first = - i last = 11 - i last = -1 if last >= 0 next if first > last lst = @points[first..last] @graph[i].coords(lst) if lst && lst.length >= 4 } end # This procedure is the "business" part of the simulation that does # simple numerical integration of the formula for a simple rotational # pendulum. def recomputeAngle scaling = 3000.0/@length/@length # To estimate the integration accurately, we really need to # compute the end-point of our time-step. But to do *that*, we # need to estimate the integration accurately! So we try this # technique, which is inaccurate, but better than doing it in a # single step. What we really want is bound up in the # differential equation: # .. - sin theta # theta + theta = ----------- # length # But my math skills are not good enough to solve this! # first estimate firstDDTheta = -Math.sin(@theta * Math::PI/180) * scaling midDTheta = @dTheta + firstDDTheta midTheta = @theta + (@dTheta + midDTheta)/2 # second estimate midDDTheta = -Math.sin(midTheta * Math::PI/180) * scaling midDTheta = @dTheta + (firstDDTheta + midDDTheta)/2 midTheta = @theta + (@dTheta + midDTheta)/2 # Now we do a double-estimate approach for getting the final value # first estimate midDDTheta = -Math.sin(midTheta * Math::PI/180) * scaling lastDTheta = midDTheta + midDDTheta lastTheta = midTheta + (midDTheta+ lastDTheta)/2 # second estimate lastDDTheta = -Math.sin(lastTheta * Math::PI/180) * scaling lastDTheta = midDTheta + (midDDTheta + lastDDTheta)/2 lastTheta = midTheta + (midDTheta + lastDTheta)/2 # Now put the values back in our globals @dTheta = lastDTheta @theta = lastTheta end # This method ties together the simulation engine and the graphical # display code that visualizes it. def repeat # Simulate recomputeAngle # Update the display showPendulum showPhase end end # Start the animation processing PendulumAnimationDemo.new(base_frame) ================================================ FILE: ext/tk/sample/demos-jp/plot.rb ================================================ # -*- coding: euc-jp -*- # # 2-D plot widget demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($plot_demo) && $plot_demo $plot_demo.destroy $plot_demo = nil end # demo Ѥ toplevel widget $plot_demo = TkToplevel.new {|w| title("Plot Demonstration") iconname("Plot") positionWindow(w) } base_frame = TkFrame.new($plot_demo).pack(:fill=>:both, :expand=>true) # label TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'4i', 'justify'=>'left', 'text'=>"Υɥϴñ2ΥץåȤޤХ widgetǤɽ줿ޥܥ1ǥɥåƥǡ򤤤뤳ȤǤޤ"){ pack('side'=>'top') } # frame $plot_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $plot_demo $plot_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'plot'} }.pack('side'=>'left', 'expand'=>'yes') } $plot_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # font if $tk_version =~ /^4.*/ plotFont = '-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*' else font = 'Helvetica 18' end # canvas $plot_canvas = TkCanvas.new(base_frame,'relief'=>'raised','width'=>450,'height'=>300) $plot_canvas.pack('side'=>'top', 'fill'=>'x') # plot TkcLine.new($plot_canvas, 100, 250, 400, 250, 'width'=>2) TkcLine.new($plot_canvas, 100, 250, 100, 50, 'width'=>2) TkcText.new($plot_canvas, 225, 20, 'text'=>"ñʥץå", 'font'=>plotFont, 'fill'=>'brown') (0..10).each {|i| x = 100 + (i * 30) TkcLine.new($plot_canvas, x, 250, x, 245, 'width'=>2) TkcText.new($plot_canvas, x, 254, 'text'=>10*i, 'font'=>plotFont, 'anchor'=>'n') } (0..5).each {|i| y = 250 - (i * 40) TkcLine.new($plot_canvas, 100, y, 105, y, 'width'=>2) TkcText.new($plot_canvas, 96, y, 'text'=>"#{i*50}.0", 'font'=>plotFont, 'anchor'=>'e') } for xx, yy in [[12,56],[20,94],[33,98],[32,120],[61,180],[75,160],[98,223]] x = 100 + (3*xx) y = 250 - (4*yy)/5 item = TkcOval.new($plot_canvas, x-6, y-6, x+6, y+6, 'width'=>1, 'outline'=>'black', 'fill'=>'SkyBlue2') item.addtag 'point' end $plot_canvas.itembind('point', 'Any-Enter', proc{$plot_canvas.itemconfigure 'current','fill','red'}) $plot_canvas.itembind('point', 'Any-Leave', proc{$plot_canvas.itemconfigure 'current','fill','SkyBlue2'}) $plot_canvas.itembind('point', '1', proc{|x,y| plotDown $plot_canvas,x,y}, "%x %y") $plot_canvas.itembind('point', 'ButtonRelease-1', proc{$plot_canvas.dtag 'selected'}) $plot_canvas.bind('B1-Motion', proc{|x,y| plotMove $plot_canvas,x,y}, "%x %y") $plot = {'lastX'=>0, 'lastY'=>0} # plotDown -- # This method is invoked when the mouse is pressed over one of the # data points. It sets up state to allow the point to be dragged. # # Arguments: # w - The canvas window. # x, y - The coordinates of the mouse press. def plotDown (w, x, y) w.dtag 'selected' w.addtag_withtag 'selected', 'current' w.raise 'current' $plot['lastX'] = x $plot['lastY'] = y end # plotMove -- # This method is invoked during mouse motion events. It drags the # current item. # # Arguments: # w - The canvas window. # x, y - The coordinates of the mouse. def plotMove (w, x, y) w.move 'selected', x - $plot['lastX'], y - $plot['lastY'] $plot['lastX'] = x $plot['lastY'] = y end ================================================ FILE: ext/tk/sample/demos-jp/puzzle.rb ================================================ # -*- coding: euc-jp -*- # # widet demo 'puzzle' (called by 'widget') # # toplevel widget ¸ߤк if defined?($puzzle_demo) && $puzzle_demo $puzzle_demo.destroy $puzzle_demo = nil end # demo Ѥ toplevel widget $puzzle_demo = TkToplevel.new {|w| title("15-Puzzle Demonstration") iconname("15-Puzzle") positionWindow(w) } base_frame = TkFrame.new($puzzle_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "15-ѥϥܥ򽸤ƤǤƤޤƤ٤Υԡ򥯥åȡΥԡζƤ˥饤ɤޤ³ԡον˾夫鲼鱦¤֤褦ˤƤ" } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $puzzle_demo $puzzle_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'puzzle'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame # # Special trick: scrollbar widget Ƥ trough color Ѥ뤳Ȥ # ʬΤΰſ򤷡ꤹ # begin if Tk.windowingsystem() == 'aqua' frameWidth = 168 frameHeight = 168 elsif Tk.default_widget_set == :Ttk frameWidth = 148 frameHeight = 124 else frameWidth = 120 frameHeight = 120 end rescue frameWidth = 120 frameHeight = 120 end # depend_on_button_width = true depend_on_button_width = false s = TkScrollbar.new(base_frame) base = TkFrame.new(base_frame) { width frameWidth height frameHeight borderwidth 2 relief 'sunken' bg s['troughcolor'] } s.destroy base.pack('side'=>'top', 'padx'=>'1c', 'pady'=>'1c') # proc ΥפĤ뤿ᡤproc ᥽åɤѰ # ƤͤС롼ͤѲ num αƶ # puzzleSwitch 2 ѲƤޤ̤ˤϤʤʤ def def_puzzleswitch_proc(w, num) proc{puzzleSwitch w, num} end $xpos = {} $ypos = {} order = [3,1,6,2,5,7,15,13,4,11,8,9,14,10,12] (0..14).each{|i| num = order[i] $xpos[num] = (i % 4) * 0.25 $ypos[num] = (i / 4) * 0.25 TkButton.new(base) {|w| relief 'raised' text num highlightthickness 0 command def_puzzleswitch_proc(w, num) if depend_on_button_width && (w.winfo_reqwidth * 4 > base.width) base.width = w.winfo_reqwidth * 4 end }.place('relx'=>$xpos[num], 'rely'=>$ypos[num], 'relwidth'=>0.25, 'relheight'=>0.25) } $xpos['space'] = 0.75 $ypos['space'] = 0.75 ############ def puzzleSwitch(w, num) if ( ($ypos[num] >= ($ypos['space'] - 0.01)) \ && ($ypos[num] <= ($ypos['space'] + 0.01)) \ && ($xpos[num] >= ($xpos['space'] - 0.26)) \ && ($xpos[num] <= ($xpos['space'] + 0.26))) \ || (($xpos[num] >= ($xpos['space'] - 0.01)) \ && ($xpos[num] <= ($xpos['space'] + 0.01)) \ && ($ypos[num] >= ($ypos['space'] - 0.26)) \ && ($ypos[num] <= ($ypos['space'] + 0.26))) tmp = $xpos['space'] $xpos['space'] = $xpos[num] $xpos[num] = tmp tmp = $ypos['space'] $ypos['space'] = $ypos[num] $ypos[num] = tmp w.place('relx'=>$xpos[num], 'rely'=>$ypos[num]) end end ================================================ FILE: ext/tk/sample/demos-jp/radio.rb ================================================ # -*- coding: euc-jp -*- # # radiobutton widget demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($radio_demo) && $radio_demo $radio_demo.destroy $radio_demo = nil end # demo Ѥ toplevel widget $radio_demo = TkToplevel.new {|w| title("Radiobutton Demonstration") iconname("radio") positionWindow(w) } base_frame = TkFrame.new($radio_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "ˤ2ĤΥ饸ܥ󥰥롼פɽƤޤܥ򥯥åȡΥܥΥ롼פ򤵤ޤƥ롼פФƤΥ롼פΤɤΥܥ򤵤Ƥ뤫򼨤ѿƤƤޤߤѿͤ򸫤ˤϡѿȡץܥ򥯥åƤ" } msg.pack('side'=>'top') # ѿ size = TkVariable.new color = TkVariable.new # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $radio_demo $radio_demo = nil $showVarsWin[tmppath.path] = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'radio'} }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ѿ' command proc{ showVars(base_frame, ['size', size], ['color', color]) } }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame f_left = TkFrame.new(base_frame) f_right = TkFrame.new(base_frame) f_left.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c') f_right.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c') # radiobutton [10, 12, 18, 24].each {|sz| TkRadioButton.new(f_left) { text "ݥȥ #{sz}" variable size relief 'flat' value sz }.pack('side'=>'top', 'pady'=>2, 'anchor'=>'w') } ['', '', '', '', '', ''].each {|col| TkRadioButton.new(f_right) { text col variable color relief 'flat' value col.downcase }.pack('side'=>'top', 'pady'=>2, 'anchor'=>'w') } ================================================ FILE: ext/tk/sample/demos-jp/radio2.rb ================================================ # -*- coding: euc-jp -*- # # radio2.rb # # This demonstration script creates a toplevel window containing # several radiobutton widgets. # # radiobutton widget demo (called by 'widget') # # toplevel widget if defined?($radio2_demo) && $radio2_demo $radio2_demo.destroy $radio2_demo = nil end # demo toplevel widget $radio2_demo = TkToplevel.new {|w| title("Radiobutton Demonstration 2") iconname("radio2") positionWindow(w) } base_frame = TkFrame.new($radio2_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '5i' justify 'left' text "ˤ3ĤΥ饸ܥ󥰥롼פɽƤޤܥ򥯥åȡΥܥΥ롼פ򤵤ޤƥ롼פФƤΥ롼פΤɤΥܥ򤵤Ƥ뤫򼨤ѿƤƤޤߤѿͤ򸫤ˤϡѿȡץܥ򥯥åƤ" } msg.pack('side'=>'top') # size = TkVariable.new color = TkVariable.new align = TkVariable.new # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $radio2_demo $radio2_demo = nil $showVarsWin[tmppath.path] = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'radio2'} }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ѿ' command proc{ showVars(base_frame, ['size', size], ['color', color], ['compound', align]) } }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame f_left = TkLabelFrame.new(base_frame, 'text'=>'ʸ', 'pady'=>2, 'padx'=>2) f_mid = TkLabelFrame.new(base_frame, 'text'=>'', 'pady'=>2, 'padx'=>2) f_right = TkLabelFrame.new(base_frame, 'text'=>'ӥåȥޥå', 'pady'=>2, 'padx'=>2) f_left.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c') f_mid.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c') f_right.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c') # radiobutton [10, 12, 18, 24].each {|sz| TkRadioButton.new(f_left) { text "ݥȥ #{sz}" variable size relief 'flat' value sz }.pack('side'=>'top', 'pady'=>2, 'anchor'=>'w', 'fill'=>'x') } ['', '', '', '', '', ''].each {|col| TkRadioButton.new(f_mid) { text col variable color relief 'flat' value col.downcase anchor 'w' }.pack('side'=>'top', 'pady'=>2, 'fill'=>'x') } # label = TkLabel.new(f_right, 'text'=>'٥', 'bitmap'=>'questhead', label = Tk::Label.new(f_right, 'text'=>'٥', 'bitmap'=>'questhead', 'compound'=>'left') label.configure('width'=>TkWinfo.reqwidth(label), 'compound'=>'top') label.height(TkWinfo.reqheight(label)) abtn = ['Top', 'Left', 'Right', 'Bottom'].collect{|a| lower = a.downcase TkRadioButton.new(f_right, 'text'=>a, 'variable'=>align, 'relief'=>'flat', 'value'=>lower, 'indicatoron'=>0, 'width'=>7, 'command'=>proc{label.compound(align.value)}) } Tk.grid('x', abtn[0]) Tk.grid(abtn[1], label, abtn[2]) Tk.grid('x', abtn[3]) ================================================ FILE: ext/tk/sample/demos-jp/radio3.rb ================================================ # -*- coding: euc-jp -*- # # radio3.rb # # This demonstration script creates a toplevel window containing # several radiobutton widgets. # # radiobutton widget demo (called by 'widget') # # toplevel widget if defined?($radio3_demo) && $radio3_demo $radio3_demo.destroy $radio3_demo = nil end # demo toplevel widget $radio3_demo = TkToplevel.new {|w| title("Radiobutton Demonstration 3") iconname("radio3") positionWindow(w) } base_frame = TkFrame.new($radio3_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '5i' justify 'left' text 'ˤ3ĤΥ饸ܥ󥰥롼פɽƤޤܥ򥯥åȡΥ롼פ°뤹٤ƤΥܥǥåܥ򤵤줿֤ˤʤޤƥ롼פˤϡΥ롼פΤɤΥܥ򤵤Ƥ뤫򼨤ѿƤƤޤ֥ȥ饤ơȡץܥ󤬲줿Ȥˤϡ饸ܥɽȥ饤ơȥ⡼ɤˤʤޤ줫Υܥ򤹤Сܥξ֤ϸΤ褦˸ġΥܥon/off֤򼨤褦ˤʤޤߤѿͤ򸫤ˤϡѿȡץܥ򥯥åƤ' } msg.grid(:row=>0, :column=>0, :columnspan=>3, :sticky=>'nsew') # variable size = TkVariable.new color = TkVariable.new align = TkVariable.new # frame TkFrame.new(base_frame) {|frame| TkGrid(TkFrame.new(frame, :height=>2, :relief=>:sunken, :bd=>2), :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', TkButton.new(frame, :text=>'ѿ', :image=>$image['view'], :compound=>:left, :command=>proc{ showVars(base_frame, ['size', size], ['color', color], ['compound', align]) }), TkButton.new(frame, :text=>'ɻ', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'radio3'}), TkButton.new(frame, :text=>'Ĥ', :image=>$image['delete'], :compound=>:left, :command=>proc{ tmppath = $radio3_demo $radio3_demo = nil $showVarsWin[tmppath.path] = nil tmppath.destroy }), :padx=>4, :pady=>4) frame.grid_columnconfigure(0, :weight=>1) TkGrid(frame, :row=>3, :column=>0, :columnspan=>3, :sticky=>'nsew') } # frame f_left = TkLabelFrame.new(base_frame, 'text'=>'ʸ', 'pady'=>2, 'padx'=>2) f_mid = TkLabelFrame.new(base_frame, 'text'=>'', 'pady'=>2, 'padx'=>2) f_right = TkLabelFrame.new(base_frame, 'text'=>'ӥåȥޥå', 'pady'=>2, 'padx'=>2) f_left .grid('column'=>0, 'row'=>1, 'pady'=>'.5c', 'padx'=>'.5c', 'rowspan'=>2) f_mid .grid('column'=>1, 'row'=>1, 'pady'=>'.5c', 'padx'=>'.5c', 'rowspan'=>2) f_right.grid('column'=>2, 'row'=>1, 'pady'=>'.5c', 'padx'=>'.5c') TkButton.new(base_frame, 'text'=>'ȥ饤ơ', 'command'=>proc{size.value = 'multi'; color.value = 'multi'}){ grid('column'=>2, 'row'=>2, 'pady'=>'.5c', 'padx'=>'.5c') } # radiobutton [10, 12, 14, 18, 24].each {|sz| TkRadioButton.new(f_left) { text "ݥȥ #{sz}" variable size relief 'flat' value sz tristatevalue 'multi' }.pack('side'=>'top', 'pady'=>2, 'anchor'=>'w', 'fill'=>'x') } ['Red', 'Green', 'Blue', 'Yellow', 'Orange', 'Purple'].each {|col| TkRadioButton.new(f_mid) { text col variable color relief 'flat' value col.downcase anchor 'w' tristatevalue 'multi' command proc{f_mid.fg(color.value)} }.pack('side'=>'top', 'pady'=>2, 'fill'=>'x') } # label = TkLabel.new(f_right, 'text'=>'٥', 'bitmap'=>'questhead', label = Tk::Label.new(f_right, 'text'=>'٥', 'bitmap'=>'questhead', 'compound'=>'left') label.configure('width'=>TkWinfo.reqwidth(label), 'compound'=>'top') label.height(TkWinfo.reqheight(label)) a_btn = ['Top', 'Left', 'Right', 'Bottom'].collect{|a| TkRadioButton.new(f_right, 'text'=>a, 'variable'=>align, 'relief'=>'flat', 'value'=>a.downcase, 'indicatoron'=>0, 'width'=>7, 'command'=>proc{label.compound(align.value)}) } Tk.grid('x', a_btn[0]) Tk.grid(a_btn[1], label, a_btn[2]) Tk.grid('x', a_btn[3]) ================================================ FILE: ext/tk/sample/demos-jp/rmt ================================================ #!/usr/bin/env ruby # rmt -- # This script implements a simple remote-control mechanism for # Tk applications. It allows you to select an application and # then type commands to that application. require 'tk' class Rmt def initialize(parent=nil) win = self unless parent parent = TkRoot.new end root = TkWinfo.toplevel(parent) root.minsize(1,1) # The instance variable below keeps track of the remote application # that we're sending to. If it's an empty string then we execute # the commands locally. @app = 'local' @mode = 'Ruby' # The instance variable below keeps track of whether we're in the # middle of executing a command entered via the text. @executing = 0 # The instance variable below keeps track of the last command executed, # so it can be re-executed in response to !! commands. @lastCommand = "" # Create menu bar. Arrange to recreate all the information in the # applications sub-menu whenever it is cascaded to. TkFrame.new(root, 'relief'=>'raised', 'bd'=>2) {|f| pack('side'=>'top', 'fill'=>'x') TkMenubutton.new(f, 'text'=>'File', 'underline'=>0) {|mb| TkMenu.new(mb) {|mf| mb.menu(mf) TkMenu.new(mf) {|ma| postcommand proc{win.fillAppsMenu ma} mf.add('cascade', 'label'=>'Select Application', 'menu'=>ma, 'underline'=>0) } add('command', 'label'=>'Quit', 'command'=>proc{root.destroy}, 'underline'=>0) } pack('side'=>'left') } } # Create text window and scrollbar. @txt = TkText.new(root, 'relief'=>'sunken', 'bd'=>2, 'setgrid'=>true) { yscrollbar(TkScrollbar.new(root){pack('side'=>'right', 'fill'=>'y')}) pack('side'=>'left') } @promptEnd = TkTextMark.new(@txt, 'insert') # Create a binding to forward commands to the target application, # plus modify many of the built-in bindings so that only information # in the current command can be deleted (can still set the cursor # earlier in the text and select and insert; just can't delete). @txt.bindtags([@txt, TkText, root, 'all']) @txt.bind('Return', proc{ @txt.set_insert('end - 1c') @txt.insert('insert', "\n") win.invoke Tk.callback_break }) @txt.bind('Delete', proc{ begin @txt.tag_remove('sel', 'sel.first', @promptEnd) rescue end if @txt.tag_nextrange('sel', '1.0', 'end') == [] if @txt.compare('insert', '<', @promptEnd) Tk.callback_break end end }) @txt.bind('BackSpace', proc{ begin @txt.tag_remove('sel', 'sel.first', @promptEnd) rescue end if @txt.tag_nextrange('sel', '1.0', 'end') == [] if @txt.compare('insert', '<', @promptEnd) Tk.callback_break end end }) @txt.bind('Control-d', proc{ if @txt.compare('insert', '<', @promptEnd) Tk.callback_break end }) @txt.bind('Control-k', proc{ if @txt.compare('insert', '<', @promptEnd) @txt.set_insert(@promptEnd) end }) @txt.bind('Control-t', proc{ if @txt.compare('insert', '<', @promptEnd) Tk.callback_break end }) @txt.bind('Meta-d', proc{ if @txt.compare('insert', '<', @promptEnd) Tk.callback_break end }) @txt.bind('Meta-BackSpace', proc{ if @txt.compare('insert', '<=', @promptEnd) Tk.callback_break end }) @txt.bind('Control-h', proc{ if @txt.compare('insert', '<=', @promptEnd) Tk.callback_break end }) @txt.tag_configure('bold', 'font'=>['Courier', 12, 'bold']) @app = Tk.appname('rmt') if (@app =~ /^rmt(.*)$/) root.title("Tk Remote Controller#{$1}") root.iconname("Tk Remote#{$1}") end prompt @txt.focus #@app = TkWinfo.appname(TkRoot.new) end def tkTextInsert(w,s) return if s == "" begin if w.compare('sel.first','<=','insert') \ && w.compare('sel.last','>=','insert') w.tag_remove('sel', 'sel.first', @promptEnd) w.delete('sel.first', 'sel.last') end rescue end w.insert('insert', s) w.see('insert') end # The method below is used to print out a prompt at the # insertion point (which should be at the beginning of a line # right now). def prompt @txt.insert('insert', "#{@app}: ") @promptEnd.set('insert') @promptEnd.gravity = 'left' @txt.tag_add('bold', "#{@promptEnd.path} linestart", @promptEnd) end # The method below executes a command (it takes everything on the # current line after the prompt and either sends it to the remote # application or executes it locally, depending on "app". def invoke cmd = @txt.get(@promptEnd, 'insert') @executing += 1 case (@mode) when 'Tcl' if Tk.info('complete', cmd) if (cmd == "!!\n") cmd = @lastCommand else @lastCommand = cmd end begin msg = Tk.appsend(@app, false, cmd) rescue msg = "Error: #{$!}" end @txt.insert('insert', msg + "\n") if msg != "" prompt @promptEnd.set('insert') end when 'Ruby' if (cmd == "!!\n") cmd = @lastCommand end complete = true begin eval("proc{#{cmd}}") rescue complete = false end if complete @lastCommand = cmd begin # msg = Tk.appsend(@app, false, # 'ruby', # '"(' + cmd.gsub(/[][$"]/, '\\\\\&') + ').to_s"') msg = Tk.rb_appsend(@app, false, cmd) rescue msg = "Error: #{$!}" end @txt.insert('insert', msg + "\n") if msg != "" prompt @promptEnd.set('insert') end end @executing -= 1 @txt.yview_pickplace('insert') end # The following method is invoked to change the application that # we're talking to. It also updates the prompt for the current # command, unless we're in the middle of executing a command from # the text item (in which case a new prompt is about to be output # so there's no need to change the old one). def newApp(appName, mode) @app = appName @mode = mode if @executing == 0 @promptEnd.gravity = 'right' @txt.delete("#{@promptEnd.path} linestart", @promptEnd) @txt.insert(@promptEnd, "#{appName}: ") @txt.tag_add('bold', "#{@promptEnd.path} linestart", @promptEnd) @promptEnd.gravity = 'left' end end # The method below will fill in the applications sub-menu with a list # of all the applications that currently exist. def fillAppsMenu(menu) win = self begin menu.delete(0,'last') rescue end TkWinfo.interps.sort.each{|ip| begin if Tk.appsend(ip, false, 'info commands ruby') == "" mode = 'Tcl' else mode = 'Ruby' end menu.add('command', 'label'=>format("%s (#{mode}/Tk)", ip), 'command'=>proc{win.newApp ip, mode}) rescue menu.add('command', 'label'=>format("%s (unknown Tk)", ip), 'command'=>proc{win.newApp ip, mode}, 'state'=>'disabled') end } menu.add('command', 'label'=>format("local (Ruby/Tk)"), 'command'=>proc{win.newApp 'local', 'Ruby'}) end end Rmt.new Tk.mainloop ================================================ FILE: ext/tk/sample/demos-jp/rolodex ================================================ #!/usr/bin/env ruby # # rolodex -- # This script is a part of Tom LaStrange's rolodex # # Copyright (C) 1998 by Takaaki Tateishi # Time-stamp: "03/08/02 12:45:21 nagai" # require "tk" def show_help(topic,x=0,y=0) if( topic.is_a?(TkWindow) ) w = TkWinfo.containing(x,y) if( TkWinfo.exist?(w) ) topic = w end end if( $helpTopics.include?(topic) ) msg = $helpTopics[topic] else msg = "Sorry, but no help is available for this topic" end TkDialog.new("title"=>"Rolodex Help", "message"=>"Information on #{topic}:\n\n#{msg}", "default_button"=>0, "buttons"=>["OK"]) end def fillCard clearAction $root.frame.entry[1].insert(0,"Takaaki Tateishi") $root.frame.entry[2].insert(0,"Japan Advanced Institute of Science and Techonology") $root.frame.entry[3].insert(0,"1-1 Asahidai, Tatsunokuchi") $root.frame.entry[4].insert(0,"Ishikawa 923-1292, Japan") $root.frame.entry[5].insert(0,"private") $root.frame.entry[6].insert(0,"***-***-****") $root.frame.entry[7].insert(0,"***-***-****") end def addAction for i in 1..7 STDERR.print format("%-12s %s\n", RolodexFrame::LABEL[i], $root.frame.entry[i].value) end end def clearAction for i in 1..7 $root.frame.entry[i].delete(0,"end") end end def fileAction TkDialog.new("title"=>"File Selection", "message"=>"This is a dummy file selection dialog box.\n", "default_button"=>0, "buttons"=>["OK"]) STDERR.print "dummy file name\n" end def deleteAction result = TkDialog.new("title"=>"Confirm Action", "message"=>"Are you sure?", "default_button"=>0, "buttons"=>["Cancel"]) if( result.value == 0 ) clearAction end end class RolodexFrame < TkFrame attr_reader :entry, :label LABEL = ["","Name:","Address:","","","Home Phone:","Work Phone:","Fax:"] def initialize(parent=nil,keys=nil) super(parent,keys) self["relief"] = "flat" @i = [] @label = [] @entry = [] for i in 1..7 @i[i] = TkFrame.new(self) @i[i].pack("side"=>"top", "pady"=>2, "anchor"=>"e") @label[i] = TkLabel.new(@i[i], "text"=>LABEL[i], "anchor"=>"e") @entry[i] = TkEntry.new(@i[i], "width"=>30, "relief"=>"sunken") @entry[i].pack("side"=>"right") @label[i].pack("side"=>"right") end end end class RolodexButtons < TkFrame attr_reader :clear, :add, :search, :delete def initialize(parent,keys=nil) super(parent,keys) @clear = TkButton.new(self, "text" => "Clear") @add = TkButton.new(self, "text" => "Add") @search = TkButton.new(self, "text" => "Search") @delete = TkButton.new(self, "text" => "Delete") for w in [@clear,@add,@search,@delete] w.pack("side"=>"left", "padx"=>2) end end end class RolodexMenuFrame < TkFrame attr_reader :file_menu, :help_menu, :file, :help def initialize(parent,keys=nil) super(parent,keys) configure("relief"=>"raised", "borderwidth"=>1) @file = TkMenubutton.new(self, "text"=>"File", "underline"=>0) @file_menu = TkMenu.new(@file) @file_menu.add("command", "label" => "Load ...", "command" => proc{fileAction}, "underline" => 0) @file_menu.add("command", "label" => "Exit", "command" => proc{$root.destroy}, "underline" => 0) @file.menu(@file_menu) @file.pack("side"=>"left") @help = TkMenubutton.new(self, "text"=>"Help", "underline"=>0) @help_menu = TkMenu.new(@help) @help_menu.add("command", "label"=>"On Context...", "command"=>proc{show_help("context")}, "underline"=>3) @help_menu.add("command", "label"=>"On Help...", "command"=>proc{show_help("help")}, "underline"=>3) @help_menu.add("command", "label"=>"On Window...", "command"=>proc{show_help("window")}, "underline"=>3) @help_menu.add("command", "label"=>"On Keys...", "command"=>proc{show_help("keys")}, "underline"=>3) @help_menu.add("command", "label"=>"On version...", "command"=>proc{show_help("version")}, "underline"=>3) @help.menu(@help_menu) @help.pack("side"=>"right") end end class Rolodex < TkRoot attr_reader :frame, :buttons, :menu def initialize(*args) super(*args) @frame = RolodexFrame.new(self) @frame.pack("side"=>"top", "fill"=>"y", "anchor"=>"center") @buttons = RolodexButtons.new(self) @buttons.pack("side"=>"bottom", "pady"=>2, "anchor"=>"center") @menu = RolodexMenuFrame.new(self) @menu.pack("before"=>@frame, "side"=>"top", "fill"=>"x") end end $root = Rolodex.new $root.buttons.delete.configure("command"=>proc{deleteAction}) $root.buttons.add.configure("command"=>proc{addAction}) $root.buttons.clear.configure("command"=>proc{clearAction}) $root.buttons.search.configure("command"=>proc{addAction; fillCard}) $root.buttons.clear.configure("text"=>"Clear Ctrl+C") $root.bind("Control-c",proc{clearAction}) $root.buttons.add.configure("text"=>"Add Ctrl+A") $root.bind("Control-a",proc{addAction}) $root.buttons.search.configure("text"=>"Search Ctrl+S") $root.bind("Control-s",proc{addAction; fillCard}) $root.buttons.delete.configure("text"=>"Delete... Ctrl+D") $root.bind("Control-d",proc{deleteAction}) $root.menu.file_menu.entryconfigure(1, "accel"=>"Ctrl+F") $root.bind("Control-f",proc{fileAction}) $root.menu.file_menu.entryconfigure(2, "accel"=>"Ctrl+Q") $root.bind("Control-q",proc{$root.destroy}) $root.frame.entry[1].focus $root.bind("Any-F1", proc{|event| show_help(event.widget, event.x_root, event.y_root)}) $root.bind("Any-Help", proc{|event| show_help(event.widget, event.x_root, event.y_root)}) $helpTopics = {} $helpTopics[$root.menu.file] = < # Time-stamp: "04/04/09 00:32:12 nagai" # require "tk" Tk.encoding = "euc-jp" def show_help(topic,x=0,y=0) if( topic.is_a?(TkWindow) ) w = TkWinfo.containing(x,y) if( w.is_a?(TkWindow) ) if( TkWinfo.exist?(w) ) topic = w end end end if( $helpTopics.include?(topic) ) msg = $helpTopics[topic] else msg = "ΥȥԥåˤĤƤΥإפϤޤѤǤޤ" end TkDialog.new("title"=>"Rolodex Help", "message"=>"#{topic}\n\n#{msg}", "default_button"=>0, "buttons"=>["OK"]) end def fillCard clearAction $root.frame.entry[1].insert(0, "Ω ") $root.frame.entry[2].insert(0, "923-1292 ") $root.frame.entry[3].insert(0, "äĮ 1-1") $root.frame.entry[4].insert(0, "Φüʳصر") $root.frame.entry[5].insert(0,"private") $root.frame.entry[6].insert(0,"***-***-****") $root.frame.entry[7].insert(0,"***-***-****") end def addAction for i in 1..7 STDERR.print format("%-12s %s\n", RolodexFrame::LABEL[i], $root.frame.entry[i].value) end end def clearAction for i in 1..7 $root.frame.entry[i].delete(0,"end") end end def fileAction TkDialog.new("title"=>"File Selection", "message"=>"ϥեΥߡǤ\n", "default_button"=>0, "buttons"=>["OK"]) STDERR.print "dummy file name\n" end def deleteAction result = TkDialog.new("title"=>"Confirm Action", "message"=>"Ǥ", "default_button"=>0, "buttons"=>["󥻥"]) if( result.value == 0 ) clearAction end end class RolodexFrame < TkFrame attr_reader :entry, :label LABEL = ["","̾:","","","","():","():","Fax:"] def initialize(parent=nil,keys=nil) super(parent,keys) self["relief"] = "flat" @i = [] @label = [] @entry = [] for i in 1..7 @i[i] = TkFrame.new(self) @i[i].pack("side"=>"top", "pady"=>2, "anchor"=>"e") @label[i] = TkLabel.new(@i[i], "text"=>LABEL[i], "anchor"=>"e") @entry[i] = TkEntry.new(@i[i], "width"=>30, "relief"=>"sunken") @entry[i].pack("side"=>"right") @label[i].pack("side"=>"right") end end end class RolodexButtons < TkFrame attr_reader :clear, :add, :search, :delete def initialize(parent,keys=nil) super(parent,keys) @clear = TkButton.new(self,"text" => "ꥢ") @add = TkButton.new(self, "text" => "ɲ") @search = TkButton.new(self, "text" => "") @delete = TkButton.new(self, "text" => "õ") for w in [@clear,@add,@search,@delete] w.pack("side"=>"left", "padx"=>2) end end end class RolodexMenuFrame < TkFrame attr_reader :file_menu, :help_menu, :file, :help def initialize(parent,keys=nil) super(parent,keys) configure("relief"=>"raised", "borderwidth"=>1) @file = TkMenubutton.new(self, "text"=> "ե", "underline"=>0) @file_menu = TkMenu.new(@file) @file_menu.add("command", "label" => "ɤ߹ ...", "command" => proc{fileAction}, "underline" => 0) @file_menu.add("command", "label" => "λ", "command" => proc{$root.destroy}, "underline" => 0) @file.menu(@file_menu) @file.pack("side"=>"left") @help = TkMenubutton.new(self, "text"=> "إ", "underline"=>0) @help_menu = TkMenu.new(@help) @help_menu.add("command", "label"=> "ƥȤˤĤ", "command"=>proc{show_help("ƥ")}, "underline"=>3) @help_menu.add("command", "label"=> "إפˤĤ", "command"=>proc{show_help("إ")}, "underline"=>3) @help_menu.add("command", "label"=> "ɥˤĤ", "command"=>proc{show_help("ɥ")}, "underline"=>3) @help_menu.add("command", "label"=> "ˤĤ", "command"=>proc{show_help("")}, "underline"=>3) @help_menu.add("command", "label"=> "С", "command"=>proc{show_help("С")}, "underline"=>3) @help.menu(@help_menu) @help.pack("side"=>"right") end end class Rolodex < TkRoot attr_reader :frame, :buttons, :menu def initialize(*args) super(*args) @frame = RolodexFrame.new(self) @frame.pack("side"=>"top", "fill"=>"y", "anchor"=>"center") @buttons = RolodexButtons.new(self) @buttons.pack("side"=>"bottom", "pady"=>2, "anchor"=>"center") @menu = RolodexMenuFrame.new(self) @menu.pack("before"=>@frame, "side"=>"top", "fill"=>"x") end end $root = Rolodex.new $root.buttons.delete.configure("command"=>proc{deleteAction}) $root.buttons.add.configure("command"=>proc{addAction}) $root.buttons.clear.configure("command"=>proc{clearAction}) $root.buttons.search.configure("command"=>proc{addAction; fillCard}) $root.buttons.clear.configure("text"=> "ꥢ Ctrl+C") $root.bind("Control-c",proc{clearAction}) $root.buttons.add.configure("text"=> "ɲ Ctrl+A") $root.bind("Control-a",proc{addAction}) $root.buttons.search.configure("text"=> " Ctrl+S") $root.bind("Control-s",proc{addAction; fillCard}) $root.buttons.delete.configure("text"=> "õ Ctrl+D") $root.bind("Control-d",proc{deleteAction}) $root.menu.file_menu.entryconfigure(1, "accel"=>"Ctrl+F") $root.bind("Control-f",proc{fileAction}) $root.menu.file_menu.entryconfigure(2, "accel"=>"Ctrl+Q") $root.bind("Control-q",proc{$root.destroy}) $root.frame.entry[1].focus $root.bind("Any-F1", proc{|event| show_help(event.widget, event.x_root, event.y_root)}) $root.bind("Any-Help", proc{|event| show_help(event.widget, event.x_root, event.y_root)}) $helpTopics = {} $helpTopics[$root.menu.file] = <:both, :expand=>true) # label TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left', 'text'=>"ΥХwidgetϥ롼顼ϷǤ롼顼αˤΤϥ֥ȥåפΰͤǡĥäƤ뤳Ȥˤäƥ֥ȥåפ뤳ȤǤޤޤǤˤ륿֥ȥåפưȤǤޤ֥ȥåפޤϲˤɽޤǥɥåȡޥܥΥˤΥ֥ȥåפϾäޤ"){ pack('side'=>'top') } # frame $ruler_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $ruler_demo $ruler_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'ruler'} }.pack('side'=>'left', 'expand'=>'yes') } $ruler_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # canvas $ruler_canvas = TkCanvas.new(base_frame, 'width'=>'14.8c', 'height'=>'2.5c') $ruler_canvas.pack('side'=>'top', 'fill'=>'x') # unless Struct.const_defined?("RulerInfo") $demo_rulerInfo = Struct.new("RulerInfo", :grid, :left, :right, :x, :y, :top, :bottom, :size, :normalStyle, :activeStyle, :deleteStyle).new end $demo_rulerInfo.grid = '.25c' $demo_rulerInfo.left = TkWinfo.fpixels($ruler_canvas, '1c') $demo_rulerInfo.right = TkWinfo.fpixels($ruler_canvas, '13c') $demo_rulerInfo.top = TkWinfo.fpixels($ruler_canvas, '1c') $demo_rulerInfo.bottom = TkWinfo.fpixels($ruler_canvas, '1.5c') $demo_rulerInfo.size = TkWinfo.fpixels($ruler_canvas, '.2c') $demo_rulerInfo.normalStyle = {'fill'=>'black'} if TkWinfo.depth($ruler_canvas) > 1 $demo_rulerInfo.activeStyle = {'fill'=>'red', 'stipple'=>''} $demo_rulerInfo.deleteStyle = {'fill'=>'red', 'stipple'=>'@'+[$demo_dir, '..', 'images', 'gray25.xbm'].join(File::Separator)} else $demo_rulerInfo.activeStyle = {'fill'=>'black', 'stipple'=>''} $demo_rulerInfo.deleteStyle = {'fill'=>'black', 'stipple'=>'@'+[$demo_dir, '..', 'images', 'gray25.xbm'].join(File::Separator)} end TkcLine.new($ruler_canvas, '1c', '0.5c', '1c', '1c', '13c', '1c', '13c', '0.5c', 'width'=>1) (0..11).each{|i| x = i+1 TkcLine.new($ruler_canvas, "#{x}c", '1c', "#{x}c", '0.6c', 'width'=>1) TkcLine.new($ruler_canvas, "#{x}.25c", '1c', "#{x}.25c", '0.8c', 'width'=>1) TkcLine.new($ruler_canvas, "#{x}.5c", '1c', "#{x}.5c", '0.7c', 'width'=>1) TkcLine.new($ruler_canvas, "#{x}.75c", '1c', "#{x}.75c", '0.8c', 'width'=>1) TkcText.new($ruler_canvas, "#{x}.15c", '0.75c', 'text'=>i, 'anchor'=>'sw') } $rulerTag_well = TkcTag.new($ruler_canvas) $ruler_canvas\ .addtag_withtag($rulerTag_well, TkcRectangle.new($ruler_canvas, '13.2c', '1c', '13.8c', '0.5c', 'outline'=>'black', 'fill'=>($ruler_canvas\ .configinfo('background'))[4]) ) $ruler_canvas\ .addtag_withtag($rulerTag_well, rulerMkTab($ruler_canvas, TkWinfo.pixels($ruler_canvas, '13.5c'), TkWinfo.pixels($ruler_canvas, '.65c') ) ) $rulerTag_well.bind('1', proc{|x,y| rulerNewTab($ruler_canvas,x,y)}, '%x %y') $ruler_canvas.itembind('tab', '1', proc{|x,y| rulerSelectTab($ruler_canvas,x,y)}, '%x %y') $ruler_canvas.bind('B1-Motion', proc{|x,y| rulerMoveTab($ruler_canvas,x,y)}, '%x %y') $ruler_canvas.bind('Any-ButtonRelease-1', proc{rulerReleaseTab($ruler_canvas)}) # rulerNewTab -- # Does all the work of creating a tab stop, including creating the # triangle object and adding tags to it to give it tab behavior. # # Arguments: # c - The canvas window. # x, y - The coordinates of the tab stop. def rulerNewTab(c,x,y) v = $demo_rulerInfo c.addtag_withtag('active', rulerMkTab(c,x,y)) c.addtag_withtag('tab', 'active') v.x = x v.y = y rulerMoveTab(c,x,y) end # rulerSelectTab -- # This method is invoked when mouse button 1 is pressed over # a tab. It remembers information about the tab so that it can # be dragged interactively. # # Arguments: # c - The canvas widget. # x, y - The coordinates of the mouse (identifies the point by # which the tab was picked up for dragging). def rulerSelectTab(c,x,y) v = $demo_rulerInfo v.x = c.canvasx(x, v.grid) v.y = v.top+2 c.addtag_withtag('active', 'current') c.itemconfigure('active', v.activeStyle) c.raise('active') end # rulerMoveTab -- # This method is invoked during mouse motion events to drag a tab. # It adjusts the position of the tab, and changes its appearance if # it is about to be dragged out of the ruler. # # Arguments: # c - The canvas widget. # x, y - The coordinates of the mouse. def rulerMoveTab(c,x,y) v = $demo_rulerInfo return if c.find_withtag('active') == [] cx = c.canvasx(x,v.grid) cy = c.canvasy(y) cx = v.left if cx < v.left cx = v.right if cx > v.right if (cy >= v.top && cy <= v.bottom) cy = v.top+2 c.itemconfigure('active', v.activeStyle) else cy = cy-v.size-2 c.itemconfigure('active', v.deleteStyle) end c.move('active', cx-v.x, cy-v.y) v.x = cx v.y = cy end # rulerReleaseTab -- # This method is invoked during button release events that end # a tab drag operation. It deselects the tab and deletes the tab if # it was dragged out of the ruler. # # Arguments: # c - The canvas widget. # x, y - The coordinates of the mouse. def rulerReleaseTab(c) v = $demo_rulerInfo return if c.find_withtag('active') == [] if v.y != v.top+2 c.delete('active') else c.itemconfigure('active', v.normalStyle) c.dtag('active') end end ================================================ FILE: ext/tk/sample/demos-jp/sayings.rb ================================================ # -*- coding: euc-jp -*- # # listbox widget demo 'sayings' (called by 'widget') # # toplevel widget ¸ߤк if defined?($sayings_demo) && $sayings_demo $sayings_demo.destroy $sayings_demo = nil end # demo Ѥ toplevel widget $sayings_demo = TkToplevel.new {|w| title("Listbox Demonstration (well-known sayings)") iconname("sayings") positionWindow(w) } base_frame = TkFrame.new($sayings_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "ΥꥹȥܥåˤϤʳʸäƤޤꥹȤ򥹥뤵ΤϥСǤǤޤꥹȥܥåǥޥΥܥ2(ܥ)򲡤ޤޥɥåƤǤޤ" } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $sayings_demo $sayings_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'sayings'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame sayings_lbox = nil TkFrame.new(base_frame, 'borderwidth'=>10) {|w| sv = TkScrollbar.new(w) sh = TkScrollbar.new(w, 'orient'=>'horizontal') sayings_lbox = TkListbox.new(w) { setgrid 1 width 20 height 10 yscrollcommand proc{|first,last| sv.set first,last} xscrollcommand proc{|first,last| sh.set first,last} } sv.command(proc{|*args| sayings_lbox.yview(*args)}) sh.command(proc{|*args| sayings_lbox.xview(*args)}) if $tk_version =~ /^4\.[01]/ sv.pack('side'=>'right', 'fill'=>'y') sh.pack('side'=>'bottom', 'fill'=>'x') sayings_lbox.pack('expand'=>'yes', 'fill'=>'y') else sayings_lbox.grid('row'=>0, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') sv.grid('row'=>0, 'column'=>1, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') sh.grid('row'=>1, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') TkGrid.rowconfigure(w, 0, 'weight'=>1, 'minsize'=>0) TkGrid.columnconfigure(w, 0, 'weight'=>1, 'minsize'=>0) end }.pack('side'=>'top', 'expand'=>'yes', 'fill'=>'y') sayings_lbox.insert(0, "Waste not, want not", "Early to bed and early to rise makes a man healthy, wealthy, and wise", "Ask not what your country can do for you, ask what you can do for your country", "I shall return", "NOT", "A picture is worth a thousand words", "User interfaces are hard to build", "Thou shalt not steal", "A penny for your thoughts", "Fool me once, shame on you; fool me twice, shame on me", "Every cloud has a silver lining", "Where there's smoke there's fire", "It takes one to know one", "Curiosity killed the cat", "Take this job and shove it", "Up a creek without a paddle", "I'm mad as hell and I'm not going to take it any more", "An apple a day keeps the doctor away", "Don't look a gift horse in the mouth" ) ================================================ FILE: ext/tk/sample/demos-jp/search.rb ================================================ # -*- coding: euc-jp -*- # # Text Search widget demo (called by 'widget') # # textLoadFile -- # This method below loads a file into a text widget, discarding # the previous contents of the widget. Tags for the old widget are # not affected, however. # # Arguments: # w - The window into which to load the file. Must be a # text widget. # file - The name of the file to load. Must be readable. def textLoadFile(w,file) w.delete('1.0', 'end') f = open(file, 'r') while(!f.eof?) w.insert('end', f.read(1000)) end f.close end # textSearch -- # Search for all instances of a given string in a text widget and # apply a given tag to each instance found. # # Arguments: # w - The window in which to search. Must be a text widget. # string - The string to search for. The search is done using # exact matching only; no special characters. # tag - Tag to apply to each instance of a matching string. def textSearch(w, string, tag) tag.remove('0.0', 'end') return if string == "" cur = '1.0' loop { cur, len = w.search_with_length(string, cur, 'end') break if cur == "" tag.add(cur, "#{cur} + #{len} char") cur = w.index("#{cur} + #{len} char") } end # textToggle -- # This method is invoked repeatedly to invoke two commands at # periodic intervals. It normally reschedules itself after each # execution but if an error occurs (e.g. because the window was # deleted) then it doesn't reschedule itself. # # Arguments: # cmd1 - Command to execute when method is called. # sleep1 - Ms to sleep after executing cmd1 before executing cmd2. # cmd2 - Command to execute in the *next* invocation of this method. # sleep2 - Ms to sleep after executing cmd2 before executing cmd1 again. def textToggle(cmd1,sleep1,cmd2,sleep2) sleep_list = [sleep2, sleep1] TkAfter.new(proc{sleep = sleep_list.shift; sleep_list.push(sleep); sleep}, -1, cmd1, cmd2).start(sleep1) end # toplevel widget ¸ߤк if defined?($search_demo) && $search_demo $search_demo.destroy $search_demo = nil end # demo Ѥ toplevel widget $search_demo = TkToplevel.new {|w| title("Text Demonstration - Search and Highlight") iconname("search") positionWindow(w) } base_frame = TkFrame.new($search_demo).pack(:fill=>:both, :expand=>true) # frame $search_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $search_demo $search_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'search'} }.pack('side'=>'left', 'expand'=>'yes') } $search_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame TkFrame.new(base_frame) {|f| TkLabel.new(f, 'text'=>'ե̾:', 'width'=>13, 'anchor'=>'w').pack('side'=>'left') $search_fileName = TkVariable.new TkEntry.new(f, 'width'=>40, 'textvariable'=>$search_fileName) { pack('side'=>'left') bind('Return', proc{textLoadFile($search_text, $search_fileName.value) $search_string_entry.focus}) focus } TkButton.new(f, 'text'=>'ɤ߹', 'command'=>proc{textLoadFile($search_text, $search_fileName.value)})\ .pack('side'=>'left', 'pady'=>5, 'padx'=>10) }.pack('side'=>'top', 'fill'=>'x') TkFrame.new(base_frame) {|f| TkLabel.new(f, 'text'=>'ʸ:', 'width'=>13, 'anchor'=>'w').pack('side'=>'left') $search_searchString = TkVariable.new $search_string_entry = TkEntry.new(f, 'width'=>40, 'textvariable'=>$search_searchString) { pack('side'=>'left') bind('Return', proc{textSearch($search_text, $search_searchString.value, $search_Tag)}) } TkButton.new(f, 'text'=>'ȿž', 'command'=>proc{textSearch($search_text, $search_searchString.value, $search_Tag)}) { pack('side'=>'left', 'pady'=>5, 'padx'=>10) } }.pack('side'=>'top', 'fill'=>'x') $search_text = TkText.new(base_frame, 'setgrid'=>true) {|t| $search_Tag = TkTextTag.new(t) TkScrollbar.new(base_frame, 'command'=>proc{|*args| t.yview(*args)}) {|sc| t.yscrollcommand(proc{|first,last| sc.set first,last}) pack('side'=>'right', 'fill'=>'y') } pack('expand'=>'yes', 'fill'=>'both') } # Set up display styles for text highlighting. if TkWinfo.depth($search_demo) > 1 textToggle(proc{ $search_Tag.configure('background'=>'#ce5555', 'foreground'=>'white') }, 800, proc{ $search_Tag.configure('background'=>'', 'foreground'=>'') }, 200 ) else textToggle(proc{ $search_Tag.configure('background'=>'black', 'foreground'=>'white') }, 800, proc{ $search_Tag.configure('background'=>'', 'foreground'=>'') }, 200 ) end $search_text.insert('1.0', "\ Υɥϸ¸Τ˥ƥ widget Υǽɤ \ 褦˻ȤΤǥ⤹ΤǤޤΥȥ˥ե̾ \ 졢<꥿> 򲡤֥ɡץܥ򲡤Ƥˤβ \ ȥʸϤ<꥿> 򲡤ȿžץܥ򲡤Ƥ \ ȥեΡʸȰפʬ \"search_Tag\" \ ȤĤ졢ɽ°ȤƤʸǤ褦 \ ꤵޤ\n") $search_text.insert('end', "\ եɤ߹ߤΥȥǥ쥯ȥ \"#{Dir.pwd}\" Ǥ\ ") $search_text.set_insert '0.0' $search_fileName.value = '' $search_searchString.value = '' $search_text.width = 60 $search_text.height = 20 ================================================ FILE: ext/tk/sample/demos-jp/spin.rb ================================================ # -*- coding: euc-jp -*- # # spin.rb -- # # This demonstration script creates several spinbox widgets. # # based on Tcl/Tk8.4.4 widget demos if defined?($spin_demo) && $spin_demo $spin_demo.destroy $spin_demo = nil end $spin_demo = TkToplevel.new {|w| title("Spinbox Demonstration") iconname("spin") positionWindow(w) } base_frame = TkFrame.new($spin_demo).pack(:fill=>:both, :expand=>true) TkLabel.new(base_frame, :font=>$font, :wraplength=>'5i', :justify=>:left, :text=><:top) ˤϣΥԥܥåɽƤޤ 줾졢ޥ򤷤ʸϤ뤳ȤǤޤ ԽȤƤϡEmacs ¿˲äơŪ Motif ΥݡȤƤޤȤС Backspace Control-h Ȥϥκ¦ʸ Delete Control-d Ȥϱ¦ʸޤ ȤĹۤ褦ĹʸϤˤϡ ޥΥܥ󣲤򲡤ƥɥå뤳Ȥǡʸ 򥹥󤹤뤳ȤǽǤ ʤǽΥԥܥåϡͤȤߤʤ褦 ʸ󤷤ϤʤȤդƤޤ ܤΥԥܥå˸Τϥȥ ꥢԻ̾ΥꥹȤȤʤäƤޤ ⤷ʤȤäƤ Ruby ˥󥯤Ƥ Tk 饤 ֥꤬ spinbox åȤƤʤ硢 ǥϤޤưʤϤǤξˤ spinbox åȤƤ褦ʤ꿷С Tk Ȥ߹碌ƻ褦ˤƤ EOL TkFrame.new(base_frame){|f| pack(:side=>:bottom, :fill=>:x, :pady=>'2m') TkButton.new(f, :text=>'Ĥ', :width=>15, :command=>proc{ $spin_demo.destroy $spin_demo = nil }).pack(:side=>:left, :expand=>true) TkButton.new(f, :text=>'ɻ', :width=>15, :command=>proc{ showCode 'spin' }).pack(:side=>:left, :expand=>true) } australianCities = [ 'Canberra', 'Sydney', 'Melbourne', 'Perth', 'Adelaide', 'Brisbane', 'Hobart', 'Darwin', 'Alice Springs' ] [ TkSpinbox.new(base_frame, :from=>1, :to=>10, :width=>10, :validate=>:key, :validatecommand=>[ proc{|s| s == '' || /^[+-]?\d+$/ =~ s }, '%P' ]), TkSpinbox.new(base_frame, :from=>0, :to=>3, :increment=>0.5, :format=>'%05.2f', :width=>10), TkSpinbox.new(base_frame, :values=>australianCities, :width=>10) ].each{|sbox| sbox.pack(:side=>:top, :pady=>5, :padx=>10)} ================================================ FILE: ext/tk/sample/demos-jp/square ================================================ #!/usr/bin/env ruby # square -- # This script generates a demo application containing only # a "square" widget. It's only usable if Tk has been compiled # with tkSquare.c and with the -DSQUARE_DEMO compiler switch. # This demo arranges the following bindings for the widget: # # Button-1 press/drag: moves square to mouse # "a": toggle size animation on/off # require 'tk' require 'tkafter' class TkSquare'yes', 'fill'=>'both') bind('1', proc{|x,y| center(x,y)}, '%s %y') bind('B1-Motion', proc{|x,y| center(x,y)}, '%s %y') bind('a', proc{animate}) focus } TkRoot.new.minsize(1,1) # The procedure below centers the square on a given position. def center(x,y) a = $s.size $s.position(x-(a/2), y-(a/2)) end # The procedures below provide a simple form of animation where # the box changes size in a pulsing pattern: larger, smaller, larger, # and so on. $inc = 0 def timer_proc a = $s.size return if $inc == 0 $inc = -3 if a >= 40 $inc = 3 if a <= 10 $s.size(a+$inc) end $timer = TkAfter.new(30, -1, proc{timer_proc}) def animate if $inc == 0 $inc = 3 $timer.start else $inc = 0 $timer.stop end end Tk.mainloop ================================================ FILE: ext/tk/sample/demos-jp/states.rb ================================================ # -*- coding: euc-jp -*- # # listbox widget demo 'states' (called by 'widget') # # toplevel widget ¸ߤк if defined?($states_demo) && $states_demo $states_demo.destroy $states_demo = nil end # demo Ѥ toplevel widget $states_demo = TkToplevel.new {|w| title("Listbox Demonstration (states)") iconname("states") positionWindow(w) } base_frame = TkFrame.new($states_demo).pack(:fill=>:both, :expand=>true) # label msg = TkLabel.new(base_frame) { font $font wraplength '4i' justify 'left' text "ˤΤƻܸ̾äСդΥꥹȥܥåǤꥹȤ򥹥뤵ΤϥСǤǤޤꥹȥܥåǥޥΥܥ2(ܥ)򲡤ޤޥɥåƤǤޤ" } msg.pack('side'=>'top') # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $states_demo $states_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'states'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame states_lbox = nil TkFrame.new(base_frame, 'borderwidth'=>'.5c') {|w| s = TkScrollbar.new(w) states_lbox = TkListbox.new(w) { setgrid 1 height 12 yscrollcommand proc{|first,last| s.set first,last} } s.command(proc{|*args| states_lbox.yview(*args)}) s.pack('side'=>'right', 'fill'=>'y') states_lbox.pack('side'=>'left', 'expand'=>1, 'fill'=>'both') }.pack('side'=>'top', 'expand'=>'yes', 'fill'=>'y') ins_data = [ '','Ŀ','','','','','ɲ', 'ʬ','','','','','','', '','','','','','','', '','Ų','纬','','','','', 'Ļ','ٻ','Ĺ','Ĺ','','','ʼ', '','ʡ','ʡ','ʡ','̳ƻ','','ܾ', 'ܺ','','','','²λ' ] states_lbox.insert(0, *ins_data) ================================================ FILE: ext/tk/sample/demos-jp/style.rb ================================================ # -*- coding: euc-jp -*- # # text (display styles) widget demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($style_demo) && $style_demo $style_demo.destroy $style_demo = nil end # demo Ѥ toplevel widget $style_demo = TkToplevel.new {|w| title("Text Demonstration - Display Styles") iconname("style") positionWindow(w) } base_frame = TkFrame.new($style_demo).pack(:fill=>:both, :expand=>true) # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $style_demo $style_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'style'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # text txt = TkText.new(base_frame){|t| # setgrid 'true' #width 70 #height 32 wrap 'word' font $font TkScrollbar.new(base_frame) {|s| pack('side'=>'right', 'fill'=>'y') command proc{|*args| t.yview(*args)} t.yscrollcommand proc{|first,last| s.set first,last} } pack('expand'=>'yes', 'fill'=>'both') # ƥȥ (եȴϢ) family = 'Courier' if $tk_version =~ /^4.*/ style_tag_bold = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-O-Normal--*-120-*-*-*-*-*-*') style_tag_big = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-R-Normal--*-140-*-*-*-*-*-*', 'kanjifont'=>$msg_kanji_font) style_tag_verybig = TkTextTag.new(t, 'font'=>'-*-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*') # style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*', 'kanjifont'=>$kanji_font) style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*') else style_tag_bold = TkTextTag.new(t, 'font'=>[family, 12, :bold, :italic]) style_tag_big = TkTextTag.new(t, 'font'=>[family, 14, :bold]) style_tag_verybig = TkTextTag.new(t, 'font'=>['Helvetica', 24, :bold]) style_tag_small = TkTextTag.new(t, 'font'=>'Times 8 bold') end ### # case($tk_version) # when /^4.*/ # style_tag_big = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-R-Normal--*-140-*-*-*-*-*-*', 'kanjifont'=>$msg_kanji_font) # style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*', 'kanjifont'=>$kanji_font) # when /^8.*/ # unless $style_demo_do_first # $style_demo_do_first = true # Tk.tk_call('font', 'create', '@bigascii', # '-copy', '-*-Courier-Bold-R-Normal--*-140-*-*-*-*-*-*') # Tk.tk_call('font', 'create', '@smallascii', # '-copy', '-Adobe-Helvetica-Bold-R-Normal-*-100-*') # Tk.tk_call('font', 'create', '@cBigFont', # '-compound', '@bigascii @msg_knj') # Tk.tk_call('font', 'create', '@cSmallFont', # '-compound', '@smallascii @kanji') # end # style_tag_big = TkTextTag.new(t, 'font'=>'@cBigFont') # style_tag_small = TkTextTag.new(t, 'font'=>'@cSmallFont') # end # ƥȥ (꡼մϢ) if TkWinfo.depth($root).to_i > 1 style_tag_color1 = TkTextTag.new(t, 'background'=>'#a0b7ce') style_tag_color2 = TkTextTag.new(t, 'foreground'=>'red') style_tag_raised = TkTextTag.new(t, 'relief'=>'raised', 'borderwidth'=>1) style_tag_sunken = TkTextTag.new(t, 'relief'=>'sunken', 'borderwidth'=>1) else style_tag_color1 = TkTextTag.new(t, 'background'=>'black', 'foreground'=>'white') style_tag_color2 = TkTextTag.new(t, 'background'=>'black', 'foreground'=>'white') style_tag_raised = TkTextTag.new(t, 'background'=>'white', 'relief'=>'raised', 'borderwidth'=>1) style_tag_sunken = TkTextTag.new(t, 'background'=>'white', 'relief'=>'sunken', 'borderwidth'=>1) end # ƥȥ (¾) if $tk_version =~ /^4\.[01]/ style_tag_bgstipple = TkTextTag.new(t, 'background'=>'black', 'borderwidth'=>0, 'bgstipple'=>'gray25') else style_tag_bgstipple = TkTextTag.new(t, 'background'=>'black', 'borderwidth'=>0, 'bgstipple'=>'gray12') end style_tag_fgstipple = TkTextTag.new(t, 'fgstipple'=>'gray50') style_tag_underline = TkTextTag.new(t, 'underline'=>'on') style_tag_overstrike = TkTextTag.new(t, 'overstrike'=>'on') style_tag_right = TkTextTag.new(t, 'justify'=>'right') style_tag_center = TkTextTag.new(t, 'justify'=>'center') if $tk_version =~ /^4.*/ style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') else style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>[family, 10]) style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>[family, 10]) end style_tag_margins = TkTextTag.new(t, 'lmargin1'=>'12m', 'lmargin2'=>'6m', 'rmargin'=>'10m') style_tag_spacing = TkTextTag.new(t, 'spacing1'=>'10p', 'spacing2'=>'2p', 'lmargin1'=>'12m', 'lmargin2'=>'6m', 'rmargin'=>'10m') # ƥ insert('end', 'Τ褦˥ƥ widget Ͼ͡ʥɽ뤳 Ǥޤ') insert('end', '', style_tag_big) insert('end', 'Ȥᥫ˥ǥȥ뤵ޤ Ȥϥƥ widget Τʸ (ϰ)ФŬѤǤ ñʤ̾ΤȤǤ͡ɽǤޤ ꤹȡΥΤĤʸϻꤷɽ 褦ˤʤޤѤǤɽϼ̤Ǥ ') insert('end', ' 1. ե', style_tag_big) insert('end', ' ɤ X ΥեȤǤȤޤ') insert('end', 'large', style_tag_verybig) insert('end', ' Ȥ') # insert('end', '', style_tag_small) insert('end', 'small', style_tag_small) insert('end', 'Ȥ ') insert('end', ' 2. ', style_tag_big) insert('end', ' ') insert('end', 'طʿ', style_tag_color1) insert('end', '') insert('end', 'ʿ', style_tag_color2) insert('end', '') insert('end', 'ξ', style_tag_color1, style_tag_color2) insert('end', 'ȤѤ뤳ȤǤޤ ') insert('end', ' 3. ֤', style_tag_big) insert('end', ' Τ褦κݤ') insert('end', 'طʤ', style_tag_bgstipple) insert('end', 'ʸ', style_tag_fgstipple) insert('end', 'ñʤɤĤ֤ Ǥʤ֤ȤȤǤޤ ') insert('end', ' 4. ', style_tag_big) insert('end', ' Τ褦') insert('end', 'ʸ˲', style_tag_underline) insert('end', 'ȤǤޤ ') insert('end', ' 5. Ǥä', style_tag_big) insert('end', ' Τ褦') insert('end', 'ʸ˽Ťͤ', style_tag_overstrike) insert('end', 'ȤǤޤ ') insert('end', ' 6. 3D ', style_tag_big) insert('end', ' طʤȤĤơʸ') insert('end', 'ӽФ', style_tag_raised) insert('end', '褦ˤ') insert('end', '', style_tag_sunken) insert('end', ' 褦ˤǤޤ ') insert('end', ' 7. ·', style_tag_big) insert('end', ' Τ褦˹Ԥ ') insert('end', '· ') insert('end', '· ', style_tag_right) insert('end', '·Ǥޤ ', style_tag_center) insert('end', ' 8. դʸź', style_tag_big) insert('end', ' 10') insert('end', 'n', style_tag_super) insert('end', ' Τ褦˸դʸθ̤䡢') insert('end', ' X') insert('end', 'i', style_tag_sub) insert('end', 'Τ褦źθ̤ФȤǤޤ ') insert('end', ' 9. ޡ', style_tag_big) insert('end', 'ƥȤκ¦;ʬʶ֤ȤǤޤ: ') insert('end', 'ϥޡλǤ꡼', style_tag_margins) insert('end', 'ޤ֤ɽƤ1ԤΥƥȤǤ', style_tag_margins) insert('end', '¦ˤ2Υޡޤ', style_tag_margins) insert('end', '1ܤФΤȡ', style_tag_margins) insert('end', '2ܰʹߤϢ³ޡ', style_tag_margins) insert('end', 'Ǥޤ¦ˤޡ󤬤ޤ', style_tag_margins) insert('end', 'Ԥޤ֤֤뤿˻Ѥ뤳ȤǤޤ ', style_tag_margins) insert('end', ' 10. ڡ', style_tag_big) insert('end', '3ĤΥѥ᡼ǹԤΥڡ󥰤') insert('end', '椹 뤳ȤǤޤSpacing1ǡԤ') insert('end', 'ˤɤΤ餤ζ֤֤ spacing3') insert('end', 'ǹԤβˤɤΤ餤ζ֤֤') insert('end', 'Ԥޤ֤Ƥʤ Сspacing2ǡ') insert('end', 'ƥȹԤƤԤδ֤ˤɤΤ餤') insert('end', 'ζ֤ 򼨤ޤ ') insert('end', 'ΥǥȤ줿ϤɤΤ褦', style_tag_spacing) insert('end', 'ڡ󥰤ԤΤ򼨤ޤ', style_tag_spacing) insert('end', 'ϼºݤϥƥwidget', style_tag_spacing) insert('end', '1ԤǡwidgetˤäޤޤƤޤ ', style_tag_spacing) insert('end', 'Spacing1ϤΥƥȤǤ10point', style_tag_spacing) insert('end', 'ꤵƤޤ', style_tag_spacing) insert('end', 'ˤꡢδ֤礭ʴֳ֤', style_tag_spacing) insert('end', '¸ߤƤޤ', style_tag_spacing) insert('end', 'Spacing22pointꤵƤޤ', style_tag_spacing) insert('end', 'ˤۤξֳ֤¸ߤƤޤ', style_tag_spacing) insert('end', 'Spacing3ϤǤϻѤƤޤ ', style_tag_spacing) insert('end', 'ֳ֤ɤˤ뤫򸫤С', style_tag_spacing) insert('end', 'ʤǥƥȤ򤷤Ƥ', style_tag_spacing) insert('end', 'ȿžʬˤ;ʬˤȤ줿ֳ֤', style_tag_spacing) insert('end', 'ޤޤƤޤ ', style_tag_spacing) } txt.width 70 txt.height 32 ================================================ FILE: ext/tk/sample/demos-jp/tcolor ================================================ #!/usr/bin/env ruby # -*- coding: euc-jp -*- # # tcolor -- # ΥץȤRGB,HSB,CYM򥵥ݡȤ # ʰץ顼ǥǤ # # Copyright (C) 1998 Takaaki Tateishi(ttate@jaist.ac.jp) # last update: Thu Jun 18 06:32:35 JST 1998 # # ޤtk.rbɤ߹ࡣ require "tk" # TkˤäѹѿTkVariableΥ󥹥󥹤Ȥ $colorSpace = TkVariable.new(:rgb) $master = nil $red = 65535 $green = 0 $blue = 0 $color = "#ffff00000000" $updating = TkVariable.new(0) $autoUpdate = TkVariable.new(1) $name = TkVariable.new($color) $command = TkVariable.new("print(%%,\"\n\")") # $command = TkVariable.new("") $label1 = TkVariable.new("label1") $label2 = TkVariable.new("label2") $label3 = TkVariable.new("label3") # ꥽ǡ١ if (TkVarAccess.new('tcl_platform')['platform'] == 'unix') TkOptionDB.add('*Entry.background', 'white') end # ƥ٥ѤΥ᥽å def rgbToHsv(red,green,blue) if ( red > green ) max = red min = green else max = green min = red end if ( blue > max ) max = blue else if ( blue < min ) min = blue end end range = max - min if ( max == 0 ) sat = 0.0 else sat = (max-min)/max end if ( sat == 0 ) hue = 0.0 else rc = (max-red)/range gc = (max-green)/range bc = (max-blue)/range if ( red == max ) hue = 0.166667 * (bc - gc) else if ( green == max ) hue = 0.166667 * (2.0 + rc - bc) else hue = 0.166667 * (4.0 + gc - rc) end end if ( hue < 0.0 ) hue = hue + 1.0 end end [hue,sat,max/65535] end def hsbToRgb(hue,sat,value) v = 65535.0 * value if( sat == 0 ) ans = [v,v,v] else hue = hue*6.0 if ( hue >= 6 ) hue = 0.0 end i = hue.to_i f = hue - i p = 65535.0 * value * (1.0 - sat) q = 65535.0 * value * (1.0 - (sat * f)) t = 65535.0 * value * (1.0 - (sat * (1.0 - f))) case i when 0 ans = [v,t,p] when 1 ans = [q,v,p] when 2 ans = [p,v,t] when 3 ans = [p,q,v] when 4 ans = [t,p,v] when 5 ans = [v,p,q] else raise(eException,"i value #{i} is out of range") end end return ans end def _null_binding Module.new.instance_eval{binding} end private :_null_binding def doUpdate newCmd = $command.to_s.gsub("%%","\"#{$color}\"") eval(newCmd, _null_binding) end def tc_scaleChanged if( $updating.to_i == 1 ) return end $master = :scale if $master == nil scale1 = $root.middle.middle.scale1 scale2 = $root.middle.middle.scale2 scale3 = $root.middle.middle.scale3 case $colorSpace.value.intern when :rgb $red = (scale1.get * 65.535).to_i $green = (scale2.get * 65.535).to_i $blue = (scale3.get * 65.535).to_i when :cmy $red = (65535 - scale1.get * 65.535).to_i $green = (65535 - scale2.get * 65.535).to_i $blue = (65535 - scale3.get * 65.535).to_i when :hsb list = hsbToRgb(scale1.get / 1000.0, scale2.get / 1000.0, scale3.get / 1000.0) $red = list[0] $green = list[1] $blue = list[2] else raise(Exception,"unknown colorSpace") end $color = format("#%04x%04x%04x",$red.to_i,$green.to_i,$blue.to_i) $name.value = $color if $master == :scale $root.middle.right.set_color($color) if( $autoUpdate.to_i == 1 ) doUpdate end Tk.update(true) $master = nil if $master == :scale end def tc_setScales $updating.value = 1 scale1 = $root.middle.middle.scale1 scale2 = $root.middle.middle.scale2 scale3 = $root.middle.middle.scale3 case $colorSpace.value.intern when :rgb scale1.set($red / 65.535) scale2.set($green / 65.535) scale3.set($blue / 65.535) when :cmy scale1.set((65535 - $red) / 65.535) scale2.set((65535 - $green) / 65.535) scale3.set((65535 - $blue) / 65.535) when :hsb list = rgbToHsv($red,$green,$blue) scale1.set( list[0] * 1000.0 ) scale2.set( list[1] * 1000.0 ) scale3.set( list[2] * 1000.0 ) else raise(Exception,"unknown colorSpace") end $updating.value = 0 end def tc_loadNamedColor(name) $name.value = name $master = :name if $master == nil if name[0,1] != "#" list = TkWinfo.rgb($root.middle.right.swatch,name) $red = list[0] $green = list[1] $blue = list[2] else case name.length when 4 fmt = /#(.{1})(.{1})(.{1})/ shift = 12 when 7 fmt = /#(.{2})(.{2})(.{2})/ shift = 8 when 10 fmt = /#(.{3})(.{3})(.{3})/ shift = 4 when 13 fmt = /#(.{4})(.{4})(.{4})/ shift = 0 else raise(eException,"syntax error in color name \"#{name}\"") end name.scan(fmt){|strlist| if strlist.length != 3 raise(eException,"syntax error in color name \"#{name}\"") end $red = strlist[0].hex $green = strlist[1].hex $blue = strlist[2].hex } $red = $red << shift $green = $green << shift $blue = $blue << shift end tc_setScales $color = format("#%04x%04x%04x",$red,$green,$blue) $root.middle.right.set_color($color) if $autoUpdate.to_i == 1 doUpdate end Tk.update(true) $master = nil if $master == :name end def changeColorSpace(space) case space when :rgb $label1.value = "Red" $label2.value = "Green" $label3.value = "Blue" when :cmy $label1.value = "Cyan" $label2.value = "Magenta" $label3.value = "Yellow" when :hsb $label1.value = "Hue" $label2.value = "Saturation" $label3.value = "Brightness" end tc_setScales end # tcolorѤΥ˥塼 class TkColorMenuFrame"raised", "borderwidth"=>"2") # File˥塼ܥ @file = TkMenubutton.new(self){|button| # File˥塼κ @file_menu = TkMenu.new(button){ add "radio", "label" => "RGB color space", "variable" => $colorSpace, "value" => :rgb, "underline" => "0", "command" => proc{changeColorSpace(:rgb)} add "radio", "label" => "CMY color space", "variable" => $colorSpace, "value" => :cmy, "underline" => "0", "command" => proc{changeColorSpace(:cmy)} add "radio", "label" => "HSB color space", "variable" => $colorSpace, "value" => :hsb, "underline" => "0", "command" => proc{changeColorSpace(:hsb)} add "separator" add "radio", "label" => "Automatic updates", "variable" => $autoUpdate, "value" => "1", "underline" => "0" add "radio", "label" => "Manual updates", "variable" => $autoUpdate, "value" => "0", "underline" => "0" add "separator" add "command", "label" => "Exit program", "underline" => "0", "command" => proc{exit} } # File˥塼FileܥϢդ menu @file_menu text "File" underline "0" }.pack("side"=>"left") self end end # Υե졼ΤΥ饹 class TkColorBotFrame "raised", "borderwidth"=> 2) @commandLabel = TkLabel.new(self, "text"=> "Command:") @command = TkEntry.new(self, "relief"=> "sunken", "borderwidth"=> "2", "textvariable"=> $command, "font"=> "-Adobe-Courier-Medium-R-Normal--*-120-*-*-*-*-*-*") @update = TkButton.new(self, "text"=> "Update", "command"=> proc{doUpdate}) @commandLabel.pack("side"=>"left") @update.pack("side"=>"right","pady"=>".1c","padx"=>".25c") @command.pack("expand"=>"yes","fill"=>"x","ipadx"=>".25c") self end end # ʺΥե졼 class TkColorMiddleLeftFrame"vertical", "relief"=>"sunken", "borderwidth"=>"2") @scroll.pack("side"=>"right","fill"=>"y") @names = TkListbox.new(self, "width"=>"20", "height"=>"12", "yscrollcommand"=> proc{|first,last| @scroll.set first,last}, "relief"=>"sunken", "borderwidth"=>"2", "exportselection"=>"false") @scroll.command(proc{|*args| @names.yview(*args)}) @names.bind("Double-1",proc{ tc_loadNamedColor(@names.get(@names.curselection))}) @names.pack("side"=>"left") while (line = f.gets) line.chop! linelist = line.split(/[ \t]+/) if linelist.length == 4 @names.insert("end",linelist[3]) end end f.close break end self end end # Υե졼 class TkColorMiddleMiddleFrame"top","expand"=>"yes") end @f4.pack("side"=>"top","expand"=>"yes","fill"=>"x") @label1 = TkLabel.new(self,"textvariable"=>$label1) @scale1 = TkScale.new(self,"from"=>"0","to"=>"1000","length"=>"6c", "orient"=>"horizontal", "command"=>proc{tc_scaleChanged}) @scale1.pack("side"=>"top","anchor"=>"w") @label1.pack("side"=>"top","anchor"=>"w") @label2 = TkLabel.new(self,"textvariable"=>$label2) @scale2 = TkScale.new(self,"from"=>"0","to"=>"1000","length"=>"6c", "orient"=>"horizontal", "command"=>proc{tc_scaleChanged}) @scale2.pack("side"=>"top","anchor"=>"w") @label2.pack("side"=>"top","anchor"=>"w") @label3 = TkLabel.new(self,"textvariable"=>$label3) @scale3 = TkScale.new(self,"from"=>"0","to"=>"1000","length"=>"6c", "orient"=>"horizontal", "command"=>proc{tc_scaleChanged}) @scale3.pack("side"=>"top","anchor"=>"w") @label3.pack("side"=>"top","anchor"=>"w") @nameLabel = TkLabel.new(self,"text"=>"Name:") @name = TkEntry.new(self,"relief"=>"sunken","borderwidth"=>"2", "textvariable"=>$name,"width"=>"10", "font"=>"-Adobe-Courier-Medium-R-Normal--*-120-*-*-*-*-*-*") @nameLabel.pack("side"=>"left") @name.pack("side"=>"right", "expand"=>"1", "fill"=>"x") @name.bind("Return",proc{tc_loadNamedColor $name.to_s}) self end end class TkColorMiddleRightFrame"2c", "height"=>"5c", "background"=>$color) @value = TkLabel.new(self, "text"=>$color, "width"=>"13", "font"=>"-Adobe-Courier-Medium-R-Normal--*-120-*-*-*-*-*-*") @swatch.pack("side"=>"top","expand"=>"yes","fill"=>"both") @value.pack("side"=>"bottom","pady"=>".25c") self end def set_color(color) @swatch["background"] = color @value["text"] = color end end # ʤΥե졼 class TkColorMiddleFrame "raised", "borderwidth"=> "2") @left = TkColorMiddleLeftFrame.new(self) @left.pack("side"=>"left","padx"=>".25c","pady"=>".25c") @middle = TkColorMiddleMiddleFrame.new(self) @middle.pack("side"=>"left","expand"=>"yes","fill"=>"y") @right = TkColorMiddleRightFrame.new(self) @right.pack("side"=>"left","padx"=>".25c","pady"=>".25c","anchor"=>"s") self end end class TkColor"top", "fill"=>"x") @bottom = TkColorBotFrame.new(self) @bottom.pack("side"=>"bottom","fill"=>"x") @middle = TkColorMiddleFrame.new(self) @middle.pack("side"=>"top","fill"=>"both") self end end $root = TkColor.new # ٥ȤԤİ٤˥롼פ롣 changeColorSpace :rgb Tk.mainloop ================================================ FILE: ext/tk/sample/demos-jp/text.rb ================================================ # -*- coding: euc-jp -*- # # text (basic facilities) widget demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($text_demo) && $text_demo $text_demo.destroy $text_demo = nil end # demo Ѥ toplevel widget $text_demo = TkToplevel.new {|w| title("Text Demonstration - Basic Facilities") iconname("text") positionWindow(w) } base_frame = TkFrame.new($text_demo).pack(:fill=>:both, :expand=>true) # version check if ((Tk::TK_VERSION.split('.').collect{|n| n.to_i} <=> [8,4]) < 0) undo_support = false else undo_support = true end # frame TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $text_demo $text_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'text'} }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # text TkText.new(base_frame){|t| # relief 'sunken' bd 2 setgrid 1 height 30 TkScrollbar.new(base_frame) {|s| pack('side'=>'right', 'fill'=>'y') command proc{|*args| t.yview(*args)} t.yscrollcommand proc{|first,last| s.set first,last} } pack('expand'=>'yes', 'fill'=>'both') # ƥ insert('0.0', <:both, :expand=>true) count = [0] ## Define a widget that we peer from; it won't ever actually be shown though first = TkText.new(base_frame, :widgetname=>"text#{count[0] += 1}") first.insert :end,"ΥǥϰĤȤƥȥåȤ򼨤ޤ" first.insert :end,"ΥƥȥåȤ(ԥ;peer)δط" first.insert :end,"ʤäƤޤ" first.insert :end,"ϡפȤʤǡǥ϶̤ΤΤޤ" first.insert :end,"ɽ֡Խ֡ϰ(selection)ˤĤƤ" first.insert :end,"Ω˻ĤȤǤޤ" first.insert :end,"ƥƥȥåȤƤˤ" first.insert :end,"֥ԥ(peer)κץܥȤС" first.insert :end,"ʥԥɲä뤳ȤǽǤ" first.insert :end,"ޤ֥ԥ(peer)ξõץܥȤС" first.insert :end,"ΥԥåȤõ뤳ȤǤޤ" Tk.update_idletasks ## for 'first' widget ## Procedures to make and kill clones; most of this is just so that the demo ## looks nice... def makeClone(count, win, txt) cnt = (count[0] += 1) peer = TkText::Peer.new(txt, win, :widgetname=>"text#{cnt}") sbar = TkScrollbar.new(win, :widgetname=>"sb#{cnt}") peer.yscrollbar sbar b1 = TkButton.new(win, :widgetname=>"clone#{cnt}", :text=>'ԥ(peer)κ', :command=>proc{makeClone(count, win, peer)}) b2 = TkButton.new(win, :widgetname=>"kill#{cnt}", :text=>'ԥ(peer)ξõ', :command=>proc{killClone(win, cnt)}) row = cnt * 2 TkGrid.configure(peer, sbar, b1, :sticky=>'nsew', :row=>row) TkGrid.configure('^', '^', b2, :sticky=>'nsew', :row=>(row+=1)) TkGrid.configure(b1, b2, :sticky=>'new') TkGrid.rowconfigure(win, b2, :weight=>1) end def killClone(win, cnt) Tk.destroy("#{win.path}.text#{cnt}", "#{win.path}.sb#{cnt}", "#{win.path}.clone#{cnt}", "#{win.path}.kill#{cnt}") end ## Now set up the GUI makeClone(count, base_frame, first) makeClone(count, base_frame, first) first.destroy ## See Code / Dismiss buttons TkFrame.new(base_frame){|f| TkButton.new(f, :text=>'Ĥ', :width=>15, :command=>proc{ $textpeer_demo.destroy $textpeer_demo = nil }).pack(:side=>:left, :expand=>true) TkButton.new(f, :text=>'ɻ', :width=>15, :command=>proc{ showCode 'textpeer' }).pack(:side=>:left, :expand=>true) TkGrid.configure(f, '-', '-', :sticky=>'ew', :row=>5000) } TkGrid.columnconfigure(base_frame, 0, :weight=>1) ================================================ FILE: ext/tk/sample/demos-jp/timer ================================================ #!/usr/bin/env ruby # # timer -- # This script generates a counter with start,stop and reset buttons. # # Copyright (C) 1998 Takaaki Tateishi (ttate@jaist.ac.jp) # last update: Sat Jun 27 12:24:14 JST 1998 # require "tk" require "thread" require "tkafter" $time = "0.00" $m = Mutex.new $loop = false def timer_stop $loop = false $m.lock end def timer_start $loop = true $m.unlock end def timer_reset $time = "0.00" $root.countframe.counter['text'] = $time end def timer_loop if $loop $time = $time.succ $root.countframe.counter['text'] = $time end Tk.after(10,proc{timer_loop}) end # # thread version # def timer_loop2 while true $m.lock $time = $time.succ $root.countframe.counter['text'] = $time sleep(0.01) $m.unlock end end # # TkAfter # def timer_loop3 if $loop $time = $time.succ $root.countframe.counter['text'] = $time end end class CountFrame < TkFrame attr_reader :counter def initialize(parent=nil,keys=nil) super(parent,keys) @counter = TkLabel.new(self, 'text'=>$time, 'relief'=>'raised') @counter.pack('fill'=>'both') self end end class ButtonFrame < TkFrame def initialize(parent=nil,keys=nil) super(parent,keys) =begin @stop = TkButton.new(self, 'text'=>'Stop', 'command'=>proc{timer_stop}) @start = TkButton.new(self, 'text'=>'Start', 'command'=>proc{timer_start}) =end @stop = TkButton.new(self, :text=>'Stop', :state=>:disabled) @start = TkButton.new(self, :text=>'Start', :state=>:normal) @stop.command proc{ timer_stop @start.state(:normal) @stop.state(:disabled) } @start.command proc{ timer_start @stop.state(:normal) @start.state(:disabled) } @reset = TkButton.new(self, 'text'=>'Reset', 'command'=>proc{timer_reset}) for b in [@stop,@start,@reset] b.pack('side'=>'left', 'fill'=>'both', 'expand'=>'yes') end end end class Timer < TkRoot attr_reader :countframe def initialize(*args) super(*args) @countframe = CountFrame.new(self) @buttonframe = ButtonFrame.new(self) for f in [@buttonframe,@countframe] f.pack('side'=>'top', 'fill'=>'both') end self end end $root = Timer.new #$thread = Thread.start{timer_loop2} #timer_loop TkAfter.new(10,-1,proc{timer_loop3}).start Tk.mainloop ================================================ FILE: ext/tk/sample/demos-jp/toolbar.rb ================================================ # -*- coding: euc-jp -*- # # toolbar.rb -- # # This demonstration script creates a toolbar that can be torn off. # # based on "Id: toolbar.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp" if defined?($toolbar_demo) && $toolbar_demo $toolbar_demo.destroy $toolbar_demo = nil end $toolbar_demo = TkToplevel.new {|w| title("Ttk Menu Buttons") iconname("toolbar") positionWindow(w) } base_frame = Ttk::Frame.new($toolbar_demo).pack(:fill=>:both, :expand=>true) if Tk.windowingsystem != 'aqua' msg = Ttk::Label.new(base_frame, :wraplength=>'4i', :text=><'4i', :text=><'toolbar') # ɥȥʸȤ뤿ˡå̾Ƥޤ sep = Ttk::Separator.new(base_frame) to_base = Ttk::Frame.new(tbar_base, :cursor=>'fleur') if Tk.windowingsystem != 'aqua' to = Ttk::Separator.new(to_base, :orient=>:vertical) to2 = Ttk::Separator.new(to_base, :orient=>:vertical) to.pack(:fill=>:y, :expand=>true, :padx=>2, :side=>:left) to2.pack(:fill=>:y, :expand=>true, :side=>:left) end contents = Ttk::Frame.new(tbar_base) Tk.grid(to_base, contents, :sticky=>'nsew') tbar_base.grid_columnconfigure(contents, :weight=>1) contents.grid_columnconfigure(1000, :weight=>1) if Tk.windowingsystem != 'aqua' ## Bindings so that the toolbar can be torn off and reattached to_base.bind('B1-Motion', '%X %Y'){|x, y| tbar_base.tearoff(to_base, x, y)} to. bind('B1-Motion', '%X %Y'){|x, y| tbar_base.tearoff(to_base, x, y)} to2. bind('B1-Motion', '%X %Y'){|x, y| tbar_base.tearoff(to_base, x, y)} def tbar_base.tearoff(w, x, y) on_win = TkWinfo.containing(x, y) return unless (on_win && on_win.path =~ /^#{@path}(\.|$)/) self.grid_remove w.grid_remove self.wm_manage # self.wm_title('Toolbar') # ⤷å̾򥦥ɥȥˤʤʤ顤ꤷƤ self.wm_protocol('WM_DELETE_WINDOW'){ self.untearoff(self) } end def tbar_base.untearoff(w) self.wm_forget w.grid self.grid end end ## Some content for the rest of the toplevel text = TkText.new(base_frame, :width=>40, :height=>10) ## Toolbar contents tb_btn = Ttk::Button.new(tbar_base, :text=>'ܥ', :style=>'Toolbutton', :command=>proc{ text.insert(:end, "ܥ󤬲ޤ\n") }) tb_chk = Ttk::Checkbutton.new(tbar_base, :text=>'åܥ', :style=>'Toolbutton', :variable=>(check = TkVariable.new), :command=>proc{ text.insert(:end, "åܥͤ#{check.value}Ǥ\n") }) tb_mbtn = Ttk::Menubutton.new(tbar_base, :text=>'˥塼') tb_combo = Ttk::Combobox.new(tbar_base, :value=>TkFont.families, :state=>:readonly) tb_mbtn.menu(menu = Tk::Menu.new(tb_mbtn)) menu.add(:command, :label=>'Just', :command=>proc{text.insert(:end, "Just\n")}) menu.add(:command, :label=>'An', :command=>proc{text.insert(:end, "An\n")}) menu.add(:command, :label=>'Example', :command=>proc{text.insert(:end, "Example\n")}) tb_combo.bind(''){ text.font.family = tb_combo.get } ## Arrange contents Tk.grid(tb_btn, tb_chk, tb_mbtn, tb_combo, :in=>contents, :padx=>2, :sticky=>'ns') Tk.grid(tbar_base, :sticky=>'ew') Tk.grid(sep, :sticky=>'ew') Tk.grid(msg, :sticky=>'ew') Tk.grid(text, :sticky=>'nsew') base_frame.grid_rowconfigure(text, :weight=>1) base_frame.grid_columnconfigure(text, :weight=>1) ## See Code / Dismiss buttons Ttk::Frame.new(base_frame) {|frame| sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'ɻ', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'toolbar'}), Ttk::Button.new(frame, :text=>'Ĥ', :image=>$image['delete'], :compound=>:left, :command=>proc{ $toolbar_demo.destroy $toolbar_demo = nil }), :padx=>4, :pady=>4) grid_columnconfigure(0, :weight=>1) Tk.grid(frame, :sticky=>'ew') } ================================================ FILE: ext/tk/sample/demos-jp/tree.rb ================================================ # -*- coding: euc-jp -*- # # tree.rb -- # # This demonstration script creates a toplevel window containing a Ttk # tree widget. # # based on "Id: tree.tcl,v 1.4 2007/12/13 15:27:07 dgp Exp" if defined?($tree_demo) && $tree_demo $tree_demo.destroy $tree_demo = nil end $tree_demo = TkToplevel.new {|w| title("Directory Browser") iconname("tree") positionWindow(w) } base_frame = TkFrame.new($tree_demo).pack(:fill=>:both, :expand=>true) ## Explanatory text Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left, :anchor=>'n', :padding=>[10, 2, 10, 6], :text=><:x) TtkȤϡơ޻ǽʿåȽǤ\ Υץϡե륷ƥΤ褦ʳŪʥǡ\ ȤǤ褦ˤTtk::TreeviewåȤޤǤޤ\ Ttk::TreeviewåȤϡڹ¤ΤɽǽˤǤʤ\ ɲþ(Υץξϥե륵)ɽ뤿\ ǤդθĿɲåⰷȤǤޤ\ ޤΥȥ֤ζڤʬɥå뤳Ȥǡ\ ѹ뤳ȤǽǤ EOL ## See Code / Dismiss Ttk::Frame.new(base_frame) {|frame| sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'ɻ', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'tree'}), Ttk::Button.new(frame, :text=>'Ĥ', :image=>$image['delete'], :compound=>:left, :command=>proc{ $tree_demo.destroy $tree_demo = nil }), :padx=>4, :pady=>4) grid_columnconfigure(0, :weight=>1) pack(:side=>:bottom, :fill=>:x) } ## Code to populate the roots of the tree (can be more than one on Windows) def populate_roots(tree) TkComm.simplelist(Tk.tk_call('file', 'volumes')).sort.each{|dir| populate_tree(tree, tree.insert(nil, :end, :text=>dir, :values=>[dir, 'directory'])) } end ## Code to populate a node of the tree def populate_tree(tree, node) return if tree.get(node, :type) != 'directory' path = tree.get(node, :fullpath) tree.delete(tree.children(node)) Dir.glob("#{path}/*").sort.each{|f| type = File.ftype(f) id = tree.insert(node, :end, :text=>File.basename(f), :values=>[f, type]).id if type == 'directory' ## Make it so that this node is openable tree.insert(id, 0, :text=>'dummy') tree.itemconfigure(id, :text=>File.basename(f)) elsif type == 'file' size = File.size(f) if size >= 1024*1024*1024 size = '%.1f GB' % (size.to_f/1024/1024/1024) elsif size >= 1024*1024 size = '%.1f MB' % (size.to_f/1024/1024) elsif size >= 1024 size = '%.1f KB' % (size.to_f/1024) else size = '%.1f bytes' % (size.to_f/1024) end tree.set(id, :size, size) end } # Stop this code from rerunning on the current node tree.set(node, :type, 'processed_directory') end ## Create the tree and set it up tree = Ttk::Treeview.new(base_frame, :columns=>%w(fullpath type size), :displaycolumns=>['size']) if Tk.windowingsystem != 'aqua' vsb = tree.yscrollbar(Ttk::Scrollbar.new(base_frame)) hsb = tree.xscrollbar(Ttk::Scrollbar.new(base_frame)) else vsb = tree.yscrollbar(Tk::Scrollbar.new(base_frame)) hsb = tree.xscrollbar(Tk::Scrollbar.new(base_frame)) end tree.heading_configure('#0', :text=>'Directory Structure') tree.heading_configure('size', :text=>'File Size') tree.column_configure('size', :stretch=>0, :width=>70) populate_roots(tree) tree.bind('', '%W'){|w| populate_tree(w, w.focus_item)} ## Arrange the tree and its scrollbars in the toplevel container = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true) container.lower Tk.grid(tree, vsb, :in=>container, :sticky=>'nsew') Tk.grid(hsb, :in=>container, :sticky=>'nsew') container.grid_columnconfigure(0, :weight=>1) container.grid_rowconfigure(0, :weight=>1) ================================================ FILE: ext/tk/sample/demos-jp/ttkbut.rb ================================================ # -*- coding: euc-jp -*- # # ttkbut.rb # # This demonstration script creates a toplevel window containing several # simple Ttk widgets, such as labels, labelframes, buttons, checkbuttons and # radiobuttons. # # based on "Id: ttkbut.tcl,v 1.4 2007/12/13 15:27:07 dgp Exp" if defined?($ttkbut_demo) && $ttkbut_demo $ttkbut_demo.destroy $ttkbut_demo = nil end $ttkbut_demo = TkToplevel.new {|w| title("Simple Ttk Widgets") iconname("ttkbut") positionWindow(w) } base_frame = TkFrame.new($ttkbut_demo).pack(:fill=>:both, :expand=>true) Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left, :text=><:top, :fill=>:x) TtkȤϡơ޻ǽʿåȽǤ\ ʤܤˤƤΤTtkΥơ޲٥ǡ\ ˤTtkΥ٥ե졼˻ĤΥ롼פTtkåȤ\ ɽƤޤ ǽΥ롼פƥܥǤꡤ\ 줾쥯åиߤΥץꥱΥơޤꤵޤ ܤΥ롼פϻĤΥåܥ󽸹Ǥ\ ƽδ֤ˤϡѥ졼åȤ֤Ƥޤ\ ʤͭץܥϡΥȥåץ٥륦å\ ¾Τ٤ƤΥơ޲åȤξ(state)"disabled"ɤ\ ȥ뤹뤳ȤդƤ ܤΥ롼פϴϢդ줿饸ܥ󽸹ȤʤäƤޤ EOL ## Add buttons for setting the theme buttons = Ttk::Labelframe.new(base_frame, :text=>'ܥ') # Ttk::Style.theme_names.each{|theme| # Ttk::Button.new(buttons, :text=>theme, # :command=>proc{Ttk::Style.theme_use theme}).pack(:pady=>2) # } Ttk.themes.each{|theme| Ttk::Button.new(buttons, :text=>theme, :command=>proc{Ttk.set_theme theme}).pack(:pady=>2) } ## Helper procedure for the top checkbutton def setState(root, value, *excepts) return if excepts.member?(root) ## Non-Ttk widgets (e.g. the toplevel) will fail, so make it silent begin root.state = value rescue end ## Recursively invoke on all children of this root that are in the same ## toplevel widget root.winfo_children.each{|w| setState(w, value, *excepts) if w.winfo_toplevel == root.winfo_toplevel } end ## Set up the checkbutton group checks = Ttk::Labelframe.new(base_frame, :text=>'åܥ') enabled = TkVariable.new(true) e = Ttk::Checkbutton.new(checks, :text=>'ͭ', :variable=>enabled, :command=>proc{ setState($ttkbut_demo, ((enabled.bool)? "!disabled" : "disabled"), e) }) ## See ttk_widget(n) for other possible state flags sep1 = Ttk::Separator.new(checks) sep2 = Ttk::Separator.new(checks) cheese = TkVariable.new tomato = TkVariable.new basil = TkVariable.new oregano = TkVariable.new c1 = Ttk::Checkbutton.new(checks, :text=>'', :variable=>cheese) c2 = Ttk::Checkbutton.new(checks, :text=>'ȥޥ', :variable=>tomato) c3 = Ttk::Checkbutton.new(checks, :text=>'Х', :variable=>basil) c4 = Ttk::Checkbutton.new(checks, :text=>'쥬', :variable=>oregano) Tk.pack(e, sep1, c1, c2, sep2, c3, c4, :fill=>:x, :pady=>2) ## Set up the radiobutton group radios = Ttk::Labelframe.new(base_frame, :text=>'饸ܥ') happyness = TkVariable.new r1 = Ttk::Radiobutton.new(radios, :variable=>happyness, :text=>'Great', :value=>'great') r2 = Ttk::Radiobutton.new(radios, :variable=>happyness, :text=>'Good', :value=>'good') r3 = Ttk::Radiobutton.new(radios, :variable=>happyness, :text=>'Ok', :value=>'ok') r4 = Ttk::Radiobutton.new(radios, :variable=>happyness, :text=>'Poor', :value=>'poor') r5 = Ttk::Radiobutton.new(radios, :variable=>happyness, :text=>'Awful', :value=>'awful') Tk.pack(r1, r2, r3, r4, r5, :fill=>:x, :padx=>3, :pady=>2) ## See Code / Dismiss Ttk::Frame.new(base_frame) {|frame| sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'ѿ', :image=>$image['view'], :compound=>:left, :command=>proc{ showVars(base_frame, ['ͭ', enabled], ['', cheese], ['ȥޥ', tomato], ['Х', basil], ['쥬', oregano], ['ʡ', happyness]) }), Ttk::Button.new(frame, :text=>'ɻ', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'ttkbut'}), Ttk::Button.new(frame, :text=>'Ĥ', :image=>$image['delete'], :compound=>:left, :command=>proc{ tmppath = $ttkbut_demo $ttkbut_demo = nil $showVarsWin[tmppath.path] = nil tmppath.destroy }), :padx=>4, :pady=>4) grid_columnconfigure(0, :weight=>1) pack(:side=>:bottom, :fill=>:x, :expand=>true) } ## Arrange things neatly f = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true) f.lower Tk.grid(buttons, checks, radios, :in=>f, :sticky=>'nwe', :pady=>2, :padx=>3) f.grid_columnconfigure([0, 1, 2], :weight=>1, :uniform=>:yes) ================================================ FILE: ext/tk/sample/demos-jp/ttkmenu.rb ================================================ # -*- coding: euc-jp -*- # # ttkmenu.rb -- # # This demonstration script creates a toplevel window containing several Ttk # menubutton widgets. # # based on "Id: ttkmenu.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp" if defined?($ttkmenu_demo) && $ttkmenu_demo $ttkmenu_demo.destroy $ttkmenu_demo = nil end $ttkmenu_demo = TkToplevel.new {|w| title("Ttk Menu Buttons") iconname("ttkmenu") positionWindow(w) } base_frame = Ttk::Frame.new($ttkmenu_demo).pack(:fill=>:both, :expand=>true) Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left, :text=><:top, :fill=>:x) TtkȤϡơ޻ǽʿåȽǤ\ ˤơޤб뤳ȤǤ褦ˤʤäåȤΤҤȤĤ\ ˥塼ܥ󤬤ޤ\ ʲǤϡơޤб˥塼ܥ󤬤ĤɽƤޤ\ Ȥäơ߻Υơޤѹ뤳ȤǽǤ\ ơޤ򤬥˥塼ܥ󼫿ȤθݤѲͻҤ䡤\ Υ˥塼ܥۤʤ륹\ (ġСǤΰŪɽŬ)ɽƤͻҤ\ ܤƤ\ ʤ˥塼ܥˤĤƤϥơޤбåȤޤ\ ˥塼ˤĤƤϥơޤбåȤϴޤޤƤޤ\ ͳϡɸTkΥ˥塼åȤ\ ٤ƤΥץåȥۡǽʬɹʸݤäƤ롤\ äˡ¿δĶǤδĶηϤȤʤ褦˼Ƥ\ ȽǤ줿Ȥˤޤ EOL Ttk::Separator.new(base_frame).pack(:side=>:top, :fill=>:x) ## See Code / Dismiss Ttk::Frame.new($ttkmenu_demo) {|frame| sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'ɻ', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'ttkmenu'}), Ttk::Button.new(frame, :text=>'Ĥ', :image=>$image['delete'], :compound=>:left, :command=>proc{ $ttkmenu_demo.destroy $ttkmenu_demo = nil }), :padx=>4, :pady=>4) grid_columnconfigure(0, :weight=>1) pack(:side=>:bottom, :fill=>:x) } b1 = Ttk::Menubutton.new(base_frame,:text=>'ơޤ',:direction=>:above) b2 = Ttk::Menubutton.new(base_frame,:text=>'ơޤ',:direction=>:left) b3 = Ttk::Menubutton.new(base_frame,:text=>'ơޤ',:direction=>:right) b4 = Ttk::Menubutton.new(base_frame,:text=>'ơޤ',:direction=>:flush, :style=>Ttk::Menubutton.style('Toolbutton')) b5 = Ttk::Menubutton.new(base_frame,:text=>'ơޤ',:direction=>:below) b1.menu(m1 = Tk::Menu.new(b1, :tearoff=>false)) b2.menu(m2 = Tk::Menu.new(b2, :tearoff=>false)) b3.menu(m3 = Tk::Menu.new(b3, :tearoff=>false)) b4.menu(m4 = Tk::Menu.new(b4, :tearoff=>false)) b5.menu(m5 = Tk::Menu.new(b5, :tearoff=>false)) Ttk.themes.each{|theme| m1.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme}) m2.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme}) m3.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme}) m4.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme}) m5.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme}) } f = Ttk::Frame.new(base_frame).pack(:fill=>:x) f1 = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true) f.lower f.grid_anchor(:center) TkGrid('x', b1, 'x', :in=>f, :padx=>3, :pady=>2) TkGrid(b2, b4, b3, :in=>f, :padx=>3, :pady=>2) TkGrid('x', b5, 'x', :in=>f, :padx=>3, :pady=>2) ================================================ FILE: ext/tk/sample/demos-jp/ttknote.rb ================================================ # -*- coding: euc-jp -*- # # ttknote.rb -- # # This demonstration script creates a toplevel window containing a Ttk # notebook widget. # # based on "Id: ttknote.tcl,v 1.5 2007/12/13 15:27:07 dgp Exp" if defined?($ttknote_demo) && $ttknote_demo $ttknote_demo.destroy $ttknote_demo = nil end $ttknote_demo = TkToplevel.new {|w| title("Ttk Notebook Widget") iconname("ttknote") positionWindow(w) } ## See Code / Dismiss Ttk::Frame.new($ttknote_demo) {|frame| sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'ɻ', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'ttknote'}), Ttk::Button.new(frame, :text=>'Ĥ', :image=>$image['delete'], :compound=>:left, :command=>proc{ $ttknote_demo.destroy $ttknote_demo = nil }), :padx=>4, :pady=>4) grid_columnconfigure(0, :weight=>1) pack(:side=>:bottom, :fill=>:x) } base_frame = Ttk::Frame.new($ttknote_demo).pack(:fill=>:both, :expand=>true) ## Make the notebook and set up Ctrl+Tab traversal notebook = Ttk::Notebook.new(base_frame).pack(:fill=>:both, :expand=>true, :padx=>2, :pady=>3) notebook.enable_traversal ## Popuplate the first pane f_msg = Ttk::Frame.new(notebook) msg_m = Ttk::Label.new(f_msg, :font=>$font, :wraplength=>'5i', :justify=>:left, :anchor=>'n', :text=><'Ƥ(Neat!)', :underline=>6, :command=>proc{ neat.value = 'ΤȤꤵ' Tk.after_cancel(after_id) if after_id after_id = Tk.after(500){neat.value = ''} }) msg_b.winfo_toplevel.bind('Alt-n'){ msg_b.focus; msg_b.invoke } msg_l = Ttk::Label.new(f_msg, :textvariable=>neat) notebook.add(f_msg, :text=>'(Description)', :underline=>3, :padding=>2) Tk.grid(msg_m, '-', :sticky=>'new', :pady=>2) Tk.grid(msg_b, msg_l, :pady=>[2, 4], :padx=>20) msg_b.grid_configure(:sticky=>'e') msg_l.grid_configure(:sticky=>'w') f_msg.grid_rowconfigure(1, :weight=>1) f_msg.grid_columnconfigure([0, 1], :weight=>1, :uniform=>1) ## Populate the second pane. Note that the content doesn't really matter f_disabled = Ttk::Frame.new(notebook) notebook.add(f_disabled, :text=>'̵줿', :state=>:disabled) ## Popuplate the third pane f_editor = Ttk::Frame.new(notebook) notebook.add(f_editor, :text=>'ƥȥǥ(Text Editor)', :underline=>9) editor_t = Tk::Text.new(f_editor, :width=>40, :height=>10, :wrap=>:char) if Tk.windowingsystem != 'aqua' editor_s = editor_t.yscrollbar(Ttk::Scrollbar.new(f_editor)) else editor_s = editor_t.yscrollbar(Tk::Scrollbar.new(f_editor)) end editor_s.pack(:side=>:right, :fill=>:y, :padx=>[0,2], :pady=>2) editor_t.pack(:fill=>:both, :expand=>true, :padx=>[2,0], :pady=>2) ================================================ FILE: ext/tk/sample/demos-jp/ttkpane.rb ================================================ # -*- coding: euc-jp -*- # # ttkpane.rb -- # # This demonstration script creates a Ttk pane with some content. # # based on "Id: ttkpane.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp" if defined?($ttkpane_demo) && $ttkpane_demo $ttkpane_demo.destroy $ttkpane_demo = nil end $ttkpane_demo = TkToplevel.new {|w| title("Themed Nested Panes") iconname("ttkpane") positionWindow(w) } base_frame = TkFrame.new($ttkpane_demo).pack(:fill=>:both, :expand=>true) Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left, :text=><:top, :fill=>:x) Υǥϡߴطˤơդڥɥɥ򼨤Ƥޤ\ 줾礭ϡޤޤƤڥδ֤ˤ륨ꥢĤ\ ɥå뤳ȤѹǤޤ EOL Ttk::Separator.new(base_frame).pack(:side=>:top, :fill=>:x) ## See Code / Dismiss Ttk::Frame.new(base_frame) {|frame| sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'ɻ', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'ttkpane'}), Ttk::Button.new(frame, :text=>'Ĥ', :image=>$image['delete'], :compound=>:left, :command=>proc{ $ttkpane_demo.destroy $ttkpane_demo = nil }), :padx=>4, :pady=>4) grid_columnconfigure(0, :weight=>1) pack(:side=>:bottom, :fill=>:x) } frame = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true) outer = Ttk::Panedwindow.new(frame, :orient=>:horizontal) outer.add(in_left = Ttk::Panedwindow.new(outer, :orient=>:vertical)) outer.add(in_right = Ttk::Panedwindow.new(outer, :orient=>:vertical)) in_left.add(left_top = Ttk::Labelframe.new(in_left, :text=>'ܥ')) in_left.add(left_bot = Ttk::Labelframe.new(in_left, :text=>'')) in_right.add(right_top = Ttk::Labelframe.new(in_right, :text=>'ץ쥹')) in_right.add(right_bot = Ttk::Labelframe.new(in_right, :text=>'ƥ')) if Tk.windowingsystem == 'aqua' [left_top, left_bot, right_top, right_bot].each{|w| w.padding(3) } end # Fill the button pane Ttk::Button.new(left_top, :text=>'Ƥ', :command=>proc{ Tk.messageBox(:type=>'ok', :icon=>'info', :message=>'Ƥơ', :detail=>'That hurt...', :parent=>base_frame, :title=>'Button Pressed') }).pack(:padx=>2, :pady=>5) zones_list = [ [':Europe/Berlin'], [':America/Argentina/Buenos_Aires', ':America/Buenos_Aires'], [':Africa/Johannesburg'], [':Europe/London'], [':America/Los_Angeles'], [':Europe/Moscow'], [':America/New_York'], [':Asia/Singapore'], [':Australia/Sydney'], [':Asia/Tokyo'], ] zones = [] # Check tzinfo support if $tk_major_ver > 8 || ($tk_major_ver == 8 && $tk_minor_ver >= 5) tzinfo = :tcl zones_list.each{|list| list.each{|zone| begin # Force a pre-load of all the timezones needed; otherwise can end up # poor-looking synch problems! Tk.tk_call('clock', 'format', '0', '-timezone', zone) rescue RuntimeError # ignore else zones << [zone, zone[%r<[^/:]+$>].tr('_', ' ')] break end } } else begin require 'tzinfo' tzinfo = :tzinfo rescue Exception begin require 'tzfile' tzinfo = :tzfile rescue Exception tzinfo = nil end end case tzinfo when :tzinfo zones_list.each{|list| list.each{|zone| begin tz = TZInfo::Timezone.get(zone[%r<[^:]+$>]) rescue Exception # ignore else zones << [tz, zone[%r<[^/:]+$>].tr('_', ' ')] break end } } when :tzfile zones_list.each{|list| list.each{|zone| begin tz = TZFile.create(zone[%r<[^:]+$>]) rescue Exception # ignore else zones << [tz, zone[%r<[^/:]+$>].tr('_', ' ')] break end } } else [ -7, -4, -2, -1, 0, +1, +3, +8, +9, +10 ].each{|zone| zones << [zone, 'UTC%+03d00' % zone] } end end time = TkVariable.new_hash case tzinfo when :tcl update_proc = proc{|now, tz, label| time[label] = Tk.tk_call('clock', 'format', now.tv_sec, '-timezone', tz, '-format', '%T') } when :tzinfo update_proc = proc{|now, tz, label| time[label] = tz.utc_to_local(now).strftime('%H:%M:%S') } when :tzfile update_proc = proc{|now, tz, label| time[label] = tz.at(now.tv_sec).strftime('%H:%M:%S') } else update_proc = proc{|now, tz, label| time[label] = (now + (tz * 3600)).strftime('%H:%M:%S') } end # Fill the clocks pane zones.each_with_index{|(zone, label), idx| Ttk::Separator.new(left_bot).pack(:fill=>:x) if idx > 0 Ttk::Label.new(left_bot, :text=>label, :anchor=>'w').pack(:fill=>:x) Ttk::Label.new(left_bot, :textvariable=>time.ref(label), :anchor=>'w').pack(:fill=>:x) } # Timer start every = proc{ now = Time.now.utc zones.each{|zone, label| update_proc.call(now, zone, label) } } TkRTTimer.new(1000, -1, every).start(0, every) # Fill the progress pane Ttk::Progressbar.new(right_top, :mode=>:indeterminate).pack(:fill=>:both, :expand=>true).start # Fill the text pane if Tk.windowingsystem != 'aqua' # The trick with the ttk::frame makes the text widget look like it fits with # the current Ttk theme despite not being a themed widget itself. It is done # by styling the frame like an entry, turning off the border in the text # widget, and putting the text widget in the frame with enough space to allow # the surrounding border to show through (2 pixels seems to be enough). f = Ttk::Frame.new(right_bot, :style=>Ttk::Entry) txt = TkText.new(frame, :wrap=>:word, :width=>30, :borderwidth=>0) txt.pack(:fill=>:both, :expand=>true, :in=>f, :pady=>2, :padx=>2) scr = txt.yscrollbar(Ttk::Scrollbar.new(frame)) scr.pack(:side=>:right, :fill=>:y, :in=>right_bot) f.pack(:fill=>:both, :expand=>true) outer.pack(:fill=>:both, :expand=>true) else txt = TkText.new(frame, :wrap=>:word, :width=>30, :borderwidth=>0) scr = txt.yscrollbar(TkScrollbar.new(frame)) scr.pack(:side=>:right, :fill=>:y, :in=>right_bot) txt.pack(:fill=>:both, :expand=>true, :in=>right_bot) outer.pack(:fill=>:both, :expand=>true, :padx=>10, :pady=>[6, 10]) end ================================================ FILE: ext/tk/sample/demos-jp/ttkprogress.rb ================================================ # -*- coding: euc-jp -*- # # ttkprogress.rb -- # # This demonstration script creates several progress bar widgets. # # based on "Id: ttkprogress.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp" if defined?($ttkprogress_demo) && $ttkprogress_demo $ttkprogress_demo.destroy $ttkprogress_demo = nil end $ttkprogress_demo = TkToplevel.new {|w| title("Progress Bar Demonstration") iconname("ttkprogress") positionWindow(w) } base_frame = TkFrame.new($ttkprogress_demo).pack(:fill=>:both, :expand=>true) Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left, :text=><:top, :fill=>:x) ˤΤĤΥץ쥹СǤ\ ΤΤ"determinate"פΥץ쥹Сǡ\ 㤨ХץबͿ줿λޤǤˤɤΤ餤뤫\ ȤʤɤѤޤ\ ΤΤ"indeterminate"פΥץ쥹Сǡ\ 㤨Хץब¹(busy)ǤΤ\ λޤǤˤɤ줯餤뤫ʬʤȤ֤\ ȤʤɤѤޤ\ Υץ쥹С⡤ˤܥȤȤ\ ư˥᡼⡼ɤON/OFFؤ뤳ȤǤޤ EOL ## See Code / Dismiss buttons Ttk::Frame.new(base_frame) {|frame| sep = Ttk::Separator.new(frame) Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', Ttk::Button.new(frame, :text=>'ɻ', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'ttkprogress'}), Ttk::Button.new(frame, :text=>'Ĥ', :image=>$image['delete'], :compound=>:left, :command=>proc{ $ttkprogress_demo.destroy $ttkprogress_demo = nil }), :padx=>4, :pady=>4) grid_columnconfigure(0, :weight=>1) pack(:side=>:bottom, :fill=>:x) } frame = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true) p1 = Ttk::Progressbar.new(frame, :mode=>:determinate) p2 = Ttk::Progressbar.new(frame, :mode=>:indeterminate) start = Ttk::Button.new(frame, :text=>'Start Progress', :command=>proc{ p1.start; p2.start }) stop = Ttk::Button.new(frame, :text=>'Stop Progress', :command=>proc{ p1.stop; p2.stop }) Tk.grid(p1, '-', :pady=>5, :padx=>10) Tk.grid(p2, '-', :pady=>5, :padx=>10) Tk.grid(start, stop, :padx=>10, :pady=>5) start.grid_configure(:sticky=>'e') stop.grid_configure(:sticky=>'w') frame.grid_columnconfigure(:all, :weight=>1) ================================================ FILE: ext/tk/sample/demos-jp/twind.rb ================================================ # -*- coding: euc-jp -*- # # text (embedded windows) widget demo (called by 'widget') # # toplevel widget ¸ߤк if defined?($twind_demo) && $twind_demo $twind_demo.destroy $twind_demo = nil end # demo Ѥ toplevel widget $twind_demo = TkToplevel.new {|w| title("Text Demonstration - Embedded Windows") iconname("Embedded Windows") positionWindow(w) } base_frame = TkFrame.new($twind_demo).pack(:fill=>:both, :expand=>true) # frame $twind_buttons = TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc{ tmppath = $twind_demo $twind_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc{showCode 'twind'} }.pack('side'=>'left', 'expand'=>'yes') } $twind_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame $twind_text = nil TkFrame.new(base_frame, 'highlightthickness'=>2, 'borderwidth'=>2, 'relief'=>'sunken') {|f| $twind_text = TkText.new(f, 'setgrid'=>'true', 'font'=>$font, 'width'=>'70', 'height'=>35, 'wrap'=>'word', 'highlightthickness'=>0, 'borderwidth'=>0 ){|t| TkScrollbar.new(f) {|s| command proc{|*args| t.yview(*args)} t.yscrollcommand proc{|first,last| s.set first,last} }.pack('side'=>'right', 'fill'=>'y') }.pack('expand'=>'yes', 'fill'=>'both') }.pack('expand'=>'yes', 'fill'=>'both') # $tag_center = TkTextTag.new($twind_text, 'justify' =>'center', 'spacing1'=>'5m', 'spacing3'=>'5m' ) $tag_buttons = TkTextTag.new($twind_text, 'lmargin1'=>'1c', 'lmargin2'=>'1c', 'rmargin' =>'1c', 'spacing1'=>'3m', 'spacing2'=>0, 'spacing3'=>0 ) # ƥȤ $twind_text.insert('end', 'ƥwidget¾widgetȤ߹ळȤǤޤ') $twind_text.insert('end', 'Ȥ߹ߥɥȸƤФ졢ǤդwidgetǽǤ') $twind_text.insert('end', '㤨С2ĤΥܥwidgetȤ߹ޤƤޤ') $twind_text.insert('end', 'ǽΥܥ򥯥åȿʿΥ') TkTextWindow.new($twind_text, 'end', 'window'=>TkButton.new($twind_text) { #text 'ON' text '' command proc{textWindOn $twind_text,$twind_buttons} cursor 'top_left_arrow' }) $twind_text.insert('end', "ˤޤޤ2ĤΥܥ򥯥å\n") $twind_text.insert('end', 'ʿΥ') TkTextWindow.new($twind_text, 'end', 'window'=>TkButton.new($twind_text) { #text 'OFF' text '' command proc{textWindOff $twind_text} cursor 'top_left_arrow' }) $twind_text.insert('end', 'ˤޤ') $twind_text.insert('end', '⤦ҤȤĤǤ') TkTextWindow.new($twind_text, 'end', 'window'=>TkButton.new($twind_text) { text '򥯥å' command proc{textWindPlot $twind_text} cursor 'top_left_arrow' }) $twind_text.insert('end', 'ȡx-yץåȤ˸ޤ') $mark_plot = TkTextMark.new($twind_text, 'insert') $mark_plot.gravity='left' $twind_text.insert('end', 'ޥǥǡ褹뤳ȤǤޤ') TkTextWindow.new($twind_text, 'end', 'window'=>TkButton.new($twind_text) { text 'õ' command proc{textWindDel $twind_text} cursor 'top_left_arrow' }) $twind_text.insert('end', '򥯥åȸޤ ') $twind_text.insert('end', 'Ȥ߹ߥɥƥwidgetˡºݤ') $twind_text.insert('end', 'ƥȤϤʤȤ߹ळȤǤ') $twind_text.insert('end', 'ξϡƥwidgetϥɥޥ͡') $twind_text.insert('end', '褦ưޤ㤨Сˤϥƥwidget') $twind_text.insert('end', 'äƥܥ󤬤줤¤٤Ƥޤ') $twind_text.insert('end', 'ΥܥطʿѤ뤳ȤǤޤ') $twind_text.insert('end', '("Default"Ǹο᤹ȤǤޤ)') $twind_text.insert('end', '"Short"Ȥܥ򥯥åʸĹ') $twind_text.insert('end', 'ѤޤȼưŪ˥ƥwidget') $twind_text.insert('end', '쥤ȤƤޤ') $twind_text.insert('end', '⤦Ʊܥ򲡤ȸޤ ') TkTextWindow.new($twind_text, 'end', 'window'=>TkButton.new($twind_text) {|b| text 'ǥե' command proc{embDefBg $twind_text} cursor 'top_left_arrow' $tag_buttons.add('end') }, 'padx'=>3 ) embToggle = TkVariable.new('Short') TkTextWindow.new($twind_text, 'end', 'window'=>TkCheckButton.new($twind_text) { textvariable embToggle indicatoron 0 variable embToggle onvalue 'A much longer string' offvalue 'Short' cursor 'top_left_arrow' pady 5 padx 2 }, 'padx'=>3, 'pady'=>2 ) [ 'AntiqueWhite3', 'Bisque1', 'Bisque2', 'Bisque3', 'Bisque4', 'SlateBlue3', 'RoyalBlue1', 'SteelBlue2', 'DeepSkyBlue3', 'LightBlue1', 'DarkSlateGray1', 'Aquamarine2', 'DarkSeaGreen2', 'SeaGreen1', 'Yellow1', 'IndianRed1', 'IndianRed2', 'Tan1', 'Tan4' ].each{|twind_color| TkTextWindow.new($twind_text, 'end', 'window'=>TkButton.new($twind_text) { text twind_color cursor 'top_left_arrow' command proc{$twind_text.bg twind_color} }, 'padx'=>3, 'pady'=>2 ) } # ᥽å def textWindOn (w,f) if defined? $twind_scroll begin $twind_scroll.destroy rescue end $twind_scroll = nil end base = TkWinfo.parent( TkWinfo.parent(w) ) $twind_scroll = TkScrollbar.new(base) {|s| orient 'horizontal' command proc{|*args| w.xview(*args)} w.xscrollcommand proc{|first,last| s.set first,last} w.wrap 'none' pack('after'=>f, 'side'=>'bottom', 'fill'=>'x') } return nil end def textWindOff (w) if defined? $twind_scroll begin $twind_scroll.destroy rescue end $twind_scroll = nil end w.xscrollcommand '' w.wrap 'word' end def textWindPlot (t) if (defined? $twind_plot) && (TkWinfo.exist?($twind_plot)) return end $twind_plot = TkCanvas.new(t) { relief 'sunken' width 450 height 300 cursor 'top_left_arrow' } if $tk_version =~ /^4.*/ font = '-Adobe-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*' else font = 'Helvetica 18' end TkcLine.new($twind_plot, 100, 250, 400, 250, 'width'=>2) TkcLine.new($twind_plot, 100, 250, 100, 50, 'width'=>2) TkcText.new($twind_plot, 225, 20, 'text'=>"A Simple Plot", 'font'=>font, 'fill'=>'brown') (0..10).each {|i| x = 100 + (i * 30) TkcLine.new($twind_plot, x, 250, x, 245, 'width'=>2) TkcText.new($twind_plot, x, 254, 'text'=>10*i, 'font'=>font, 'anchor'=>'n') } (0..5).each {|i| y = 250 - (i * 40) TkcLine.new($twind_plot, 100, y, 105, y, 'width'=>2) TkcText.new($twind_plot, 96, y, 'text'=>"#{i*50}.0", 'font'=>font, 'anchor'=>'e') } for xx, yy in [[12,56],[20,94],[33,98],[32,120],[61,180],[75,160],[98,223]] x = 100 + (3*xx) y = 250 - (4*yy)/5 item = TkcOval.new($twind_plot, x-6, y-6, x+6, y+6, 'width'=>1, 'outline'=>'black', 'fill'=>'SkyBlue2') item.addtag 'point' end $twind_plot.itembind('point', 'Any-Enter', proc{$twind_plot.itemconfigure 'current', 'fill', 'red'}) $twind_plot.itembind('point', 'Any-Leave', proc{$twind_plot.itemconfigure 'current', 'fill', 'SkyBlue2'}) $twind_plot.itembind('point', '1', proc{|x,y| embPlotDown $twind_plot,x,y}, "%x %y") $twind_plot.itembind('point', 'ButtonRelease-1', proc{$twind_plot.dtag 'selected'}) $twind_plot.bind('B1-Motion', proc{|x,y| embPlotMove $twind_plot,x,y}, "%x %y") while ($twind_text.get($mark_plot) =~ /[ \t\n]/) $twind_text.delete $mark_plot end $twind_text.insert $mark_plot,"\n" TkTextWindow.new($twind_text, $mark_plot, 'window'=>$twind_plot) $tag_center.add $mark_plot $twind_text.insert $mark_plot,"\n" end $embPlot = {'lastX'=>0, 'lastY'=>0} def embPlotDown (w, x, y) w.dtag 'selected' w.addtag_withtag 'selected', 'current' w.raise 'current' $embPlot['lastX'] = x $embPlot['lastY'] = y end def embPlotMove (w, x, y) w.move 'selected', x - $embPlot['lastX'], y - $embPlot['lastY'] $embPlot['lastX'] = x $embPlot['lastY'] = y end def textWindDel (w) if (defined? $twind_text) && TkWinfo.exist?($twind_plot) $twind_text.delete $twind_plot $twind_plot = nil while ($twind_text.get($mark_plot) =~ /[ \t\n]/) $twind_text.delete $mark_plot end $twind_text.insert $mark_plot," " end end def embDefBg (w) w['background'] = w.configinfo('background')[3] end ================================================ FILE: ext/tk/sample/demos-jp/twind2.rb ================================================ # -*- coding: euc-jp -*- # # text (embedded windows) widget demo 2 (called by 'widget') # # toplevel widget ¸ߤк if defined?($twind2_demo) && $twind2_demo $twind2_demo.destroy $twind2_demo = nil end # demo Ѥ toplevel widget $twind2_demo = TkToplevel.new {|w| title("Text Demonstration - Embedded Windows 2") iconname("Embedded Windows") positionWindow(w) } base_frame = TkFrame.new($twind2_demo).pack(:fill=>:both, :expand=>true) # frame $twind2_buttons = TkFrame.new(base_frame) {|frame| TkGrid(TkFrame.new(frame, :height=>2, :relief=>:sunken, :bd=>2), :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2) TkGrid('x', TkButton.new(frame, :text=>'ɻ', :image=>$image['view'], :compound=>:left, :command=>proc{showCode 'twind2'}), TkButton.new(frame, :text=>'Ĥ', :image=>$image['delete'], :compound=>:left, :command=>proc{ tmppath = $twind2_demo $twind2_demo = nil $showVarsWin[tmppath.path] = nil tmppath.destroy }), :padx=>4, :pady=>4) frame.grid_columnconfigure(0, :weight=>1) } $twind2_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # frame $twind2_text = nil TkFrame.new(base_frame, 'highlightthickness'=>2, 'borderwidth'=>2, 'relief'=>'sunken') {|f| $twind2_text = TkText.new(f, 'setgrid'=>true, 'font'=>$font, # 'width'=>'70', 'height'=>35, 'wrap'=>'word', 'width'=>'70', 'height'=>35, 'wrap'=>'char', 'highlightthickness'=>0, 'borderwidth'=>0 ){|t| TkScrollbar.new(f) {|s| command proc{|*args| t.yview(*args)} t.yscrollcommand proc{|first,last| s.set first,last} }.pack('side'=>'right', 'fill'=>'y') }.pack('expand'=>'yes', 'fill'=>'both') }.pack('expand'=>'yes', 'fill'=>'both') # $tag2_center = TkTextTag.new($twind2_text, 'justify' =>'center', 'spacing1'=>'5m', 'spacing3'=>'5m' ) $tag2_buttons = TkTextTag.new($twind2_text, 'lmargin1'=>'1c', 'lmargin2'=>'1c', 'rmargin' =>'1c', 'spacing1'=>'3m', 'spacing2'=>0, 'spacing3'=>0 ) # ƥȤ $twind2_text.insert('end', 'ƥȥåȤˤϿʼΥƥ') $twind2_text.insert('end', 'ưŪʤΤŪʤΤξޤˤ') $twind2_text.insert('end', '¿ޤ뤳ȤǤޤƥ') $twind2_text.insert('end', 'ؤ֡·ʤɤ͡ˡ') $twind2_text.insert('end', '֤뤳ȤǤޤ') $twind2_text.insert('end', 'äơƥȥåȤʪ') $twind2_text.insert('end', 'ɥ٤礭Ǥ') $twind2_text.insert('end', '٤Ƥ˥ࡼ˥뤵') $twind2_text.insert('end', 'ǧ뤳ȤǽǤ') $twind2_text.insert('end', "\n\n") $twind2_text.insert('end', 'ƥȥåȾˤ¾ΥåȤ') $twind2_text.insert('end', 'ޤ뤳ȤǤޤΤ') $twind2_text.insert('end', 'ߥɥפȸƤФ졢') $twind2_text.insert('end', 'ʤ륦åȤǤͤळȤǤޤ') $twind2_text.insert('end', '㤨СˤϣĤ') $twind2_text.insert('end', 'ܥ󥦥åȤޤƤޤ') $twind2_text.insert('end', 'ǽΥܥ򥯥åȡ') $twind2_text.insert('end', 'ʿΥ ') TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text) { #text 'ON' text '' command proc{textWindOn2 $twind2_text,$twind2_buttons} cursor 'top_left_arrow' }) $twind2_text.insert('end', "ˤޤޤĤΥܥ򥯥å\n") $twind2_text.insert('end', 'ʿΥ') TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text) { #text 'OFF' text '' command proc{textWindOff2 $twind2_text} cursor 'top_left_arrow' }) $twind2_text.insert('end', "ˤޤ\n\n") $twind2_text.insert('end', 'Ϥ⤦ҤȤĤǤ') TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text) { text '򥯥å' command proc{textWindPlot2 $twind2_text} cursor 'top_left_arrow' }) $twind2_text.insert('end', 'ȡx-yץåȤ˸ޤ') $mark2_plot = TkTextMark.new($twind2_text, 'insert') $mark2_plot.gravity='left' $twind2_text.insert('end', 'ޥǥɥå뤳Ȥǡ') $twind2_text.insert('end', 'ץåȾΥǡư뤳ȤǤޤ') TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text) { text 'õ' command proc{textWindDel2 $twind2_text} cursor 'top_left_arrow' }) $twind2_text.insert('end', '򥯥åȸޤ') $twind2_text.insert('end', "\n\n") $twind2_text.insert('end', 'ɽƥȤʤߥɥ') $twind2_text.insert('end', 'ƥȥåȤ˴ޤ뤳ȤͭѤǤ礦') $twind2_text.insert('end', 'ξ硢ƥȥåȤ') $twind2_text.insert('end', 'ȥޥ͡Τ褦Ưޤ') $twind2_text.insert('end', '㤨СˤϥƥȥåȤ') $twind2_text.insert('end', 'äƥܥ󤬤줤󤷤֤Ƥޤ') $twind2_text.insert('end', 'Υܥ򥯥å뤳Ȥǡ') $twind2_text.insert('end', 'ΥƥȥåȤطʿ') $twind2_text.insert('end', 'Ѥ뤳ȤǤޤ("ǥե"ܥ') $twind2_text.insert('end', 'ο᤹ȤǤޤ)') $twind2_text.insert('end', '"Short"Ȥܥ򥯥åʸĹ') $twind2_text.insert('end', 'ѤꡢƥȥåȤưŪ') $twind2_text.insert('end', '쥤ȤͻҤ򸫤뤳ȤǤޤ') $twind2_text.insert('end', '⤦Ʊܥ򲡤ȸޤ') $twind2_text.insert('end', "\n") btn_default = TkButton.new($twind2_text) {|b| text 'ǥե' command proc{embDefBg2 $twind2_text} cursor 'top_left_arrow' } TkTextWindow.new($twind2_text, 'end', 'window'=>btn_default, 'padx'=>3) embToggle = TkVariable.new('Short') TkTextWindow.new($twind2_text, 'end', 'window'=>TkCheckButton.new($twind2_text) { textvariable embToggle indicatoron 0 variable embToggle onvalue 'A much longer string' offvalue 'Short' cursor 'top_left_arrow' pady 5 padx 2 }, 'padx'=>3, 'pady'=>2 ) [ 'AntiqueWhite3', 'Bisque1', 'Bisque2', 'Bisque3', 'Bisque4', 'SlateBlue3', 'RoyalBlue1', 'SteelBlue2', 'DeepSkyBlue3', 'LightBlue1', 'DarkSlateGray1', 'Aquamarine2', 'DarkSeaGreen2', 'SeaGreen1', 'Yellow1', 'IndianRed1', 'IndianRed2', 'Tan1', 'Tan4' ].each{|twind_color| TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text) { text twind_color cursor 'top_left_arrow' command proc{$twind2_text.bg twind_color} }, 'padx'=>3, 'pady'=>2 ) } $tag2_buttons.add(btn_default, 'end') $text_normal2 = {} $text_normal2['border'] = $twind2_text.cget('borderwidth') $text_normal2['highlight'] = $twind2_text.cget('highlightthickness') $text_normal2['pad'] = $twind2_text.cget('padx') $twind2_text.insert('end', "\nborder width highlightthickness, ") $twind2_text.insert('end', "padding ̾ͤѹ뤳ȤǽǤ\n") TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text, :text=>"Big borders", :cursor=>'top_left_arrow', 'command'=>proc{ textWinBigB2 $twind2_text })) TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text, :text=>"Small borders", :cursor=>'top_left_arrow', 'command'=>proc{ textWinSmallB2 $twind2_text })) TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text, :text=>"Big highlight", :cursor=>'top_left_arrow', 'command'=>proc{ textWinBigH2 $twind2_text })) TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text, :text=>"Small highlight", :cursor=>'top_left_arrow', 'command'=>proc{ textWinSmallH2 $twind2_text })) TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text, :text=>"Big pad", :cursor=>'top_left_arrow', 'command'=>proc{ textWinBigP2 $twind2_text })) TkTextWindow.new($twind2_text, 'end', 'window'=>TkButton.new($twind2_text, :text=>"Small pad", :cursor=>'top_left_arrow', 'command'=>proc{ textWinSmallP2 $twind2_text })) $twind2_text.insert('end', "\n\n˥᡼ƥȥåȤ") $twind2_text.insert('end', "ޤ֤Ǥޤ") TkTextImage.new($twind2_text, 'end', 'image'=>TkBitmapImage.new(:file=>[ $demo_dir, '..', 'images', 'face.xbm' ].join(File::Separator))) # ᥽å def textWinBigB2(w) w.borderwidth 15 end def textWinSmallB2(w) w.borderwidth $text_normal2['border'] end def textWinBigH2(w) w.highlightthickness 15 end def textWinSmallH2(w) w.highlightthickness $text_normal2['highlight'] end def textWinBigP2(w) w.configure(:padx=>15, :pady=>15) end def textWinSmallP2(w) w.configure(:padx=>$text_normal2['pad'], :pady=>$text_normal2['pad']) end def textWindOn2 (w,f) if defined? $twind2_scroll begin $twind2_scroll.destroy rescue end $twind2_scroll = nil end base = TkWinfo.parent( TkWinfo.parent(w) ) $twind2_scroll = TkScrollbar.new(base) {|s| orient 'horizontal' command proc{|*args| w.xview(*args)} w.xscrollcommand proc{|first,last| s.set first,last} w.wrap 'none' pack('after'=>f, 'side'=>'bottom', 'fill'=>'x') } return nil end def textWindOff2 (w) if defined? $twind2_scroll begin $twind2_scroll.destroy rescue end $twind2_scroll = nil end w.xscrollcommand '' #w.wrap 'word' w.wrap 'char' end def textWindPlot2 (t) if (defined? $twind2_plot) && (TkWinfo.exist?($twind2_plot)) return end $twind2_plot = TkCanvas.new(t) { relief 'sunken' width 450 height 300 cursor 'top_left_arrow' } #font = '-Adobe-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*' font = 'Helvetica 18' TkcLine.new($twind2_plot, 100, 250, 400, 250, 'width'=>2) TkcLine.new($twind2_plot, 100, 250, 100, 50, 'width'=>2) TkcText.new($twind2_plot, 225, 20, 'text'=>"A Simple Plot", 'font'=>font, 'fill'=>'brown') (0..10).each {|i| x = 100 + (i * 30) TkcLine.new($twind2_plot, x, 250, x, 245, 'width'=>2) TkcText.new($twind2_plot, x, 254, 'text'=>10*i, 'font'=>font, 'anchor'=>'n') } (0..5).each {|i| y = 250 - (i * 40) TkcLine.new($twind2_plot, 100, y, 105, y, 'width'=>2) TkcText.new($twind2_plot, 96, y, 'text'=>"#{i*50}.0", 'font'=>font, 'anchor'=>'e') } for xx, yy in [[12,56],[20,94],[33,98],[32,120],[61,180],[75,160],[98,223]] x = 100 + (3*xx) y = 250 - (4*yy)/5 item = TkcOval.new($twind2_plot, x-6, y-6, x+6, y+6, 'width'=>1, 'outline'=>'black', 'fill'=>'SkyBlue2') item.addtag 'point' end $twind2_plot.itembind('point', 'Any-Enter', proc{$twind2_plot.itemconfigure 'current', 'fill', 'red'}) $twind2_plot.itembind('point', 'Any-Leave', proc{$twind2_plot.itemconfigure 'current', 'fill', 'SkyBlue2'}) $twind2_plot.itembind('point', '1', proc{|x,y| embPlotDown2 $twind2_plot,x,y}, "%x %y") $twind2_plot.itembind('point', 'ButtonRelease-1', proc{$twind2_plot.dtag 'selected'}) $twind2_plot.bind('B1-Motion', proc{|x,y| embPlotMove2 $twind2_plot,x,y}, "%x %y") while ($twind2_text.get($mark2_plot) =~ /[ \t\n]/) $twind2_text.delete $mark2_plot end $twind2_text.insert $mark2_plot,"\n" TkTextWindow.new($twind2_text, $mark2_plot, 'window'=>$twind2_plot) $tag2_center.add $mark2_plot $twind2_text.insert $mark2_plot,"\n" end $embPlot2 = {'lastX'=>0, 'lastY'=>0} def embPlotDown2 (w, x, y) w.dtag 'selected' w.addtag_withtag 'selected', 'current' w.raise 'current' $embPlot2['lastX'] = x $embPlot2['lastY'] = y end def embPlotMove2 (w, x, y) w.move 'selected', x - $embPlot2['lastX'], y - $embPlot2['lastY'] $embPlot2['lastX'] = x $embPlot2['lastY'] = y end def textWindDel2 (w) if (defined? $twind2_text) && TkWinfo.exist?($twind2_plot) $twind2_text.delete $twind2_plot $twind2_plot = nil while ($twind2_text.get($mark2_plot) =~ /[ \t\n]/) $twind2_text.delete $mark2_plot end $twind2_text.insert $mark2_plot," " end end def embDefBg2 (w) w['background'] = w.configinfo('background')[3] end ================================================ FILE: ext/tk/sample/demos-jp/unicodeout.rb ================================================ # -*- coding: euc-jp -*- # # unicodeout.rb -- # # This demonstration script shows how you can produce output (in label # widgets) using many different alphabets. # # based on Tcl/Tk8.4.4 widget demos if defined?($unicodeout_demo) && $unicodeout_demo $unicodeout_demo.destroy $unicodeout_demo = nil end $unicodeout_demo = TkToplevel.new {|w| title("Unicode Label Demonstration") iconname("unicodeout") positionWindow(w) } base_frame = TkFrame.new($unicodeout_demo).pack(:fill=>:both, :expand=>true) TkLabel.new(base_frame, :font=>$font, :wraplength=>'5.4i', :justify=>:left, :text=><:top) ϡTkˤʸѤФ륵ݡȤˤĤƤ\ ץǤɽˤƤʤºݤˤɤΤ褦ɽ\ ܤˤ뤫ϡʤδĶˤɤΤ褦ʸ礬󥹥ȡ뤵Ƥ뤫\ 礭¸ޤޤоݤȤʤʸ礬󥹥ȡ뤵Ƥʤ\ ɤΤ褦ɽʤ뤫⤢ʤδĶǤ\ ֥ɻȡץܥ򲡤ƥɽ\ Unicodeout_SampleFrame饹@@font񤭴\ (եƤѹޤ)\ ֺƼ¹ԡץܥΥåƤߤƤ ץȤĤ褦ˡʸ\\uXXXXȤ\ TclΥɽѤUNICODEʸǽ񤫤Ƥޤ\ ʸϡTk::UTF8_String᥽åɤˤäơ\ UTF8ʸǤפȤ\ 󥳡ɾդʸ󥪥֥\ (TclΥɽѴѤ)Ѵ\ ٥륦åȤϤƤդƤ EOL #' TkFrame.new(base_frame){|f| pack(:side=>:bottom, :fill=>:x, :pady=>'2m') TkButton.new(f, :text=>'Ĥ', :width=>15, :command=>proc{ $unicodeout_demo.destroy $unicodeout_demo = nil }).pack(:side=>:left, :expand=>true) TkButton.new(f, :text=>'ɻ', :width=>15, :command=>proc{ showCode 'unicodeout' }).pack(:side=>:left, :expand=>true) } wait_msg = TkLabel.new(base_frame, :text=>"եɤ߹ߤδλޤ" + "Ф餯Ԥ", :font=>"Helvetica 12 italic").pack class Unicodeout_SampleFrame < TkFrame @@font = $font # @@font = 'Helvetica 14' # @@font = 'Courier 12' # @@font = 'clearlyu 16' # @@font = 'fixed 12' # @@font = 'Times 12' # @@font = 'Newspaper 12' # @@font = '{New century schoolbook} 12' def initialize(base) super(base) grid_columnconfig(1, :weight=>1) end def add_sample(lang, *args) sample_txt = Tk::UTF8_String(args.join('')) l = TkLabel.new(self, :font=>@@font, :text=>lang+':', :anchor=>:nw, :pady=>0) #s = TkLabel.new(self, :font=>@@font, :text=>sample_txt, s = TkLabel.new(self, :font=>TkFont.new(@@font), :text=>sample_txt, :anchor=>:nw, :width=>30, :pady=>0) Tk.grid(l, s, :sticky=>:ew, :pady=>0) l.grid_config(:padx, '1m') end end f = Unicodeout_SampleFrame.new(base_frame) f.pack(:expand=>true, :fill=>:both, :padx=>'2m', :pady=>'1m') # Processing when some characters are missing might take a while, so make # sure we're displaying something in the meantime... oldCursor = $unicodeout_demo.cursor $unicodeout_demo.cursor('watch') Tk.update f.add_sample('Arabic', '\uFE94\uFEF4\uFE91\uFEAE\uFECC\uFEDF\uFE8D\uFE94', '\uFEE4\uFEE0\uFEDC\uFEDF\uFE8D') f.add_sample('Trad. Chinese', '\u4E2D\u570B\u7684\u6F22\u5B57') f.add_sample('Simpl. Chinese', '\u6C49\u8BED') f.add_sample('Greek', '\u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AE ', '\u03B3\u03BB\u03CE\u03C3\u03C3\u03B1') f.add_sample('Hebrew', '\u05DD\u05D9\u05DC\u05E9\u05D5\u05E8\u05D9 ', '\u05DC\u05D9\u05D0\u05E8\u05E9\u05D9') f.add_sample('Japanese', '\u65E5\u672C\u8A9E\u306E\u3072\u3089\u304C\u306A, ', '\u6F22\u5B57\u3068\u30AB\u30BF\u30AB\u30CA') f.add_sample('Korean', '\uB300\uD55C\uBBFC\uAD6D\uC758 \uD55C\uAE00') f.add_sample('Russian', '\u0420\u0443\u0441\u0441\u043A\u0438\u0439 ', '\u044F\u0437\u044B\u043A') wait_msg.destroy $unicodeout_demo.cursor(oldCursor) ================================================ FILE: ext/tk/sample/demos-jp/vscale.rb ================================================ # -*- coding: euc-jp -*- require "tkcanvas" if defined?($vscale_demo) && $vscale_demo $vscale_demo.destroy $vscale_demo = nil end $vscale_demo = TkToplevel.new {|w| title("Vertical Scale Demonstration") iconname("vscale") } positionWindow($vscale_demo) base_frame = TkFrame.new($vscale_demo).pack(:fill=>:both, :expand=>true) msg = TkLabel.new(base_frame) { font $font wraplength '3.5i' justify 'left' # text "ˤ1ĤȾľʥ뤬ɽƤޤ\ #ǥޥܥ1򥯥åޤϥɥå\ #ĹѤ뤳ȤǤޤ" text "ˤϥСȽķΥ뤬ɽƤޤǥޥΥܥ1 򥯥å뤫ɥåƥСι⤵Ѥ뤳ȤǤޤäλץܥ򲡤Ƥ" } msg.pack('side'=>'top', 'padx'=>'.5c') TkFrame.new(base_frame) {|frame| TkButton.new(frame) { #text 'λ' text 'Ĥ' command proc { tmppath = $vscale_demo $vscale_demo = nil tmppath.destroy } }.pack('side'=>'left', 'expand'=>'yes') TkButton.new(frame) { text 'ɻ' command proc { showCode 'vscale' } }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') def setHeight(w, height) height = height + 21 y2 = height - 30 if y2 < 21 y2 = 21 end w.coords 'poly',15,20,35,20,35,y2,45,y2,25,height,5,y2,15,y2,15,20 w.coords 'line',15,20,35,20,35,y2,45,y2,25,height,5,y2,15,y2,15,20 end TkFrame.new(base_frame) {|frame| borderwidth 10 canvas = TkCanvas.new(frame) {|c| width 50 height 50 bd 0 highlightthickness 0 TkcPolygon.new(c, 0, 0, 1, 1, 2, 2) { fill 'SeaGreen3' tags 'poly' } TkcLine.new(c, 0, 0, 1, 1, 2, 2, 0, 0) { fill 'black' tags 'line' } }.pack('side'=>'left', 'anchor'=>'nw', 'fill'=>'y') scale = TkScale.new(frame) { orient 'vertical' length 284 from 0 to 250 command proc{|value| setHeight(canvas, value)} tickinterval 50 }.pack('side'=>'left', 'anchor'=>'ne') scale.set 75 }.pack ================================================ FILE: ext/tk/sample/demos-jp/widget ================================================ #!/usr/bin/env ruby # -*- coding: euc-jp -*- # ( tk.rb Υɻ encoding /˻Ȥ ) if RUBY_VERSION < '1.9.0' ### !!!!!!!!!!!!!! $KCODE = 'euc' else DEFAULT_TK_ENCODING = 'EUC-JP' end # tk ط饤֥ɤ߹ require 'tk' # require 'tkafter' $RubyTk_WidgetDemo = true # widget demo directory ֤γ # $demo_dir = File.dirname($0) $demo_dir = File.dirname(__FILE__) # root $root = TkRoot.new{title "Ruby/Tk Widget Demonstration"} # tk Сμ $tk_version = Tk::TK_VERSION $tk_major_ver, $tk_minor_ver = $tk_version.split('.').map{|n| n.to_i} $tk_patchlevel = Tk::TK_PATCHLEVEL # tcl_platform ؤΥ֥ $tk_platform = TkVarAccess.new('tcl_platform') # ե ####### case($tk_version) when /^4.*/ $font = TkFont.new('-*-Helvetica-Medium-R-Normal--*-140-*-*-*-*-*-*', nil) knjfont = '-*--16-*-jisx0208.1983-0' $kanji_font = TkFont.new('-*-Helvetica-Medium-R-Normal--*-140-*-*-*-*-*-*', knjfont) TkOption.add('*kanjiFont', knjfont, 'startupFile') $msg_kanji_font=TkFont.new('-*-Helvetica-Medium-R-Normal--*-140-*-*-*-*-*-*', '-*--24-*-jisx0208.1983-0') #when '8.0' # $font = TkFont.new('Helvetica -12') # $kanji_font = TkFont.new('Helvetica -12', 'Mincho -12') # TkOption.add('*kanjiFont', knjfont, 'startupFile') # $msg_kanji_font=TkFont.new('Helvetica 16', 'Gothic 16 bold') when /^8.*/ $font = TkFont.new('Helvetica -12') $kanji_font = TkFont.new('Helvetica -12', 'Mincho -12') TkOption.add('*kanjiFont', knjfont, 'startupFile') $msg_kanji_font=TkFont.new('Helvetica 14 bold', 'Gothic 14 bold') else $font = TkFont.new('Helvetica 14', nil) knjfont = '-*--16-*-jisx0208.1983-0' $kanji_font = TkFont.new('Helvetic 14', knjfont) TkOption.add('*kanjiFont', knjfont, 'startupFile') $msg_kanji_font=TkFont.new('Helvetica 14', '-*--24-*-jisx0208.1983-0') end ####### # ᡼ $image = {} if $tk_major_ver >= 8 $image['refresh'] = TkPhotoImage.new(:height=>16, :format=>'GIF', :data=><= 8 $image['view'] = TkPhotoImage.new(:height=>16, :format=>'GIF', :data=><= 8 $image['delete'] = TkPhotoImage.new(:height=>16, :format=>'GIF', :data=><= 8 $image['print'] = TkPhotoImage.new(:height=>19, :format=>'GIF', :data=><= 8 $root.add_menubar([[['File', 0], ['About ... ', proc{aboutBox}, 0, ''], '---', ['Quit', proc{exit}, 0, 'Ctrl-Q'] ]]) else TkMenubar.new($root, [[['File', 0], ['About ... ', proc{aboutBox}, 0, ''], '---', ['Quit', proc{exit}, 0, 'Ctrl-Q'] ]]).pack('side'=>'top', 'fill'=>'x') end $root.bind('F1', proc{aboutBox}) $root.bind('Control-q', proc{exit}) =begin TkFrame.new($root){|frame| TkMenubutton.new(frame){|button| m = TkMenu.new(button) { add 'command', 'label'=>'Quit', 'command'=>proc{exit}, 'underline'=>0 } menu m text 'File' underline 0 }.pack('side'=>'left') }.pack('side'=>'top', 'fill'=>'x') =end # ƥȥܥå if $tk_version =~ /^4\.[01]/ scr = TkScrollbar.new($root, 'orient'=>'vertical') txt = TkText.new($root) { #wrap 'word' wrap 'char' width 70 height 30 font $font setgrid 'yes' yscrollcommand proc{|first,last| scr.set first,last} } scr.command(proc{|*args| txt.yview(*args)}) scr.pack('side'=>'right', 'fill'=>'y') txt.pack('expand'=>'yes', 'fill'=>'both') else textFrame = TkFrame.new($root) scr = TkScrollbar.new($root, 'orient'=>'vertical', 'highlightthickness'=>0, 'takefocus'=>1) { pack('in'=>textFrame, 'side'=>'right', 'fill'=>'y', 'padx'=>1) } txt = TkText.new($root) { #wrap 'word' wrap 'char' width 70 height 30 font $font setgrid 'yes' highlightthickness 0 padx 4 pady 2 takefocus 0 bd 1 yscrollcommand proc{|first,last| scr.set first,last} } scr.command(proc{|*args| txt.yview(*args)}) # txt.pack('in'=>textFrame, 'expand'=>'yes', 'fill'=>'both', 'padx'=>1) txt.pack('in'=>textFrame, 'expand'=>'yes', 'fill'=>'both') # textFrame.pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>2) textFrame.pack('expand'=>'yes', 'fill'=>'both') statusBar = TkFrame.new($root) {|f| if $tk_version =~ /^4.*/ statusfont = '-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*' else statusfont = 'Helvetica 10' end $statusBarLabel = \ TkLabel.new(f, 'text'=>" ", 'relief'=>'sunken', 'bd'=>1, 'anchor'=>'w', 'font'=>statusfont) \ .pack('side'=>'left', 'padx'=>2, 'expand'=>'yes', 'fill'=>'both') TkLabel.new(f, 'width'=>8, 'relief'=>'sunken', 'bd'=>1, 'anchor'=>'w', 'font'=>statusfont) \ .pack('side'=>'left', 'padx'=>2) }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>2) end # ƥȥ if $tk_version =~ /^4.*/ tag_title = TkTextTag.new(txt, 'font'=>'-*-Helvetica-Bold-R-Normal--*-180-*-*-*-*-*-*') else tag_title = TkTextTag.new(txt, 'font'=>'Helvetica 18 bold') end #tag_kanji_title = TkTextTag.new(txt, 'kanjifont'=>$msg_kanji_font) #tag_middle = TkTextTag.new(txt, 'kanjifont'=>$kanji_font) tag_kanji_title = TkTextTag.new(txt, 'font'=>$msg_kanji_font) tag_middle = TkTextTag.new(txt, 'font'=>$kanji_font) tag_demospace = TkTextTag.new(txt, 'lmargin1'=>'1c', 'lmargin2'=>'1c') if TkWinfo.depth($root) == 1 tag_demo = TkTextTag.new(txt, 'lmargin1'=>'1c', 'lmargin2'=>'1c', 'underline'=>1) $tag_visited = TkTextTag.new(txt, 'lmargin1'=>'1c', 'lmargin2'=>'1c', 'underline'=>1) tag_hot = TkTextTag.new(txt, 'background'=>'black', 'foreground'=>'white') else tag_demo = TkTextTag.new(txt, 'lmargin1'=>'1c', 'lmargin2'=>'1c', 'foreground'=>'blue', 'underline'=>1) $tag_visited = TkTextTag.new(txt, 'lmargin1'=>'1c', 'lmargin2'=>'1c', 'foreground'=>'#303080', 'underline'=>1) # tag_hot = TkTextTag.new(txt, 'relief'=>'raised', 'borderwidth'=>1, # 'background'=>'SeaGreen3') tag_hot = TkTextTag.new(txt, 'borderwidth'=>1, 'foreground'=>'red') end #tag_demo.bind('Button-1', proc{invoke txt, txt.index('current')}) tag_demo.bind('ButtonRelease-1', proc{|x,y|invoke txt, txt.index("@#{x},#{y}")}, '%x %y') lastLine = TkVariable.new("") newLine = TkVariable.new("") tag_demo.bind('Enter', proc{|x,y| lastLine.value = txt.index("@#{x},#{y} linestart") tag_hot.add(lastLine.value, "#{lastLine.value} lineend") showStatus txt, txt.index("@#{x},#{y}") }, '%x %y') tag_demo.bind('Leave', proc{ tag_hot.remove('1.0','end') txt.configure('cursor','xterm') $statusBarLabel.configure('text'=>"") }) tag_demo.bind('Motion', proc{|x, y| newLine.value = txt.index("@#{x},#{y} linestart") if newLine.value != lastLine.value tag_hot.remove('1.0','end') lastLine.value = newLine.value if ( txt.tag_names("@#{x},#{y}").find{|t| t.kind_of?(String) && t =~ /^demo-/ } ) tag_hot.add(lastLine.value, "#{lastLine.value} lineend -1 chars") end end showStatus txt, txt.index("@#{x},#{y}") }, '%x %y') # ƥ txt.insert('end', 'Ruby/Tk : Widget', tag_title) #txt.insert('end', " ǥ󥹥ȥ졼\n", tag_middle) txt.insert('end', " ǥ󥹥ȥ졼\n", tag_kanji_title) txt.insert('end', <<"EOT") ΥץꥱϡTk Widget ѤƤɤΤ褦ʤȤǤ뤫\ 򼨤ΡĤξʥץȤФեȥɤ\ Ƥޤʲ˽֤˵󤲤Ƥǥ󥹥ȥ졼¹\ ˤϥޥǥåƤǥ󥹥ȥ졼Υ\ ɥȡǥ󥹥ȥ졼 Ruby/Tk Υɤ\ 뤿ˡ"ɻ"ܥ򥯥å뤳ȤǤޤʤ\ ˾ʤ顢Υɤ뤳ȤǤޤɤǥǥ\ 󥹥ȥ졼Ƽ¹Ԥ뤿ˤϡɤ񤫤줿ɥ\ "ǥƼ¹" ܥ򥯥åƤ\ ɤƤ⥪ꥸʥΥե뤬񤭴뤳Ȥ\ ޤ󤫤顢ۤ˿ѹƤߤƤ ΥǥǤϡŪǶΥС Tk ǤʤХݡȤ\ ʤǽȤäƼƤޤ(㤨 Tk8.4 ʾʤ)Τᡢ\ ǽʤ Tk 饤֥ȤäƤˤϡ\ ǥưޤ󡣤Τ褦ʵǽɬפǤС򥵥ݡ\ Ƥ Tk 饤֥Ȥ褦 tcltklib 򥳥ѥ뤷ʤ\ ⤷ʤ Tk (ǽ餫ޤफ󥹥ȡ뤷ˤ) \ Ttk (Tile) ĥѤǤ֤Ǥʤ顢\ Ttk ĥΥǥ (sample/tkextlib/tile/demo.rb) ⤼һƤߤƤ ( ¿ʬߤΤʤδĶˤ Ttk ĥ\ #{ begin require 'tkextlib/tile' "ǤƳƤޤ" rescue "ޤ󥹥ȡ뤵Ƥޤ" end }\ ) Ttk ĥϡTk8.5 ʾǤɸεǽȤȤ߹ޤƤޤ EOT #txt.insert('end',"٥, ܥ, åܥ, 饸ܥ\n",tag_middle) txt.insert('end', "٥, ܥ, åܥ, 饸ܥ\n", tag_kanji_title) txt.insert('end', " \n ", tag_demospace) txt.insert('end', "1. ٥ (ƥ, ӥåȥޥå)\n", tag_demo, "demo-label") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "2. ٥UNICODEƥ (ǽбСTkɬ)\n", tag_demo, "demo-unicodeout") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "3. ܥ \n", tag_demo, "demo-button") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "4. åܥ (ʣǽ)\n", tag_demo, "demo-check") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "5. ֥åܥ (ǽбСTkɬ)\n", tag_demo, "demo-check2") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "6. 饸ܥ (ǤդΰĤǽ)\n", tag_demo, "demo-radio") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "7. 饸ܥ (ǽбСTkɬ)\n", tag_demo, "demo-radio2") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "8. ֥饸ܥ (ǽбСTkɬ)\n", tag_demo, "demo-radio3") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "9. ܥǺ줿15-ѥ륲\n", tag_demo, "demo-puzzle") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "10. ӥåȥޥåפѤܥ\n", tag_demo, "demo-icon") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "11. ɽĤΥ٥\n", tag_demo, "demo-image1") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "12. 򸫤뤿δñʥ桼󥿡ե\n", tag_demo, "demo-image2") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "13. 򸫤뤿δñʥ桼󥿡ե (ǽбСTkɬ)\n", tag_demo, "demo-image3") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "14. ٥դե졼 (ǽбСTkɬ)\n", tag_demo, "demo-labelframe") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "15. ơޤбåȤδñ (Tile/Ttkĥؤбɬ)\n", tag_demo, "demo-ttkbut") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "\n") #txt.insert('end', "ꥹȥܥå\n", tag_middle) txt.insert('end', "ꥹȥܥå\n", tag_kanji_title) txt.insert('end', " \n ", tag_demospace) txt.insert('end', "1. ƻܸ.\n", tag_demo, "demo-states") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "2. : ץꥱΤۿѤ\n", "#{tag_demo.id} demo-colors") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "3. ʸ\n", tag_demo, "demo-sayings") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "4. ˤĤƤΥޥꥹ (Tile/Ttkĥؤбɬ)\n", tag_demo, "demo-mclist") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "5. ǥ쥯ȥ֥饦 (Tile/Ttkĥؤбɬ)\n", tag_demo, "demo-tree") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "\n") #txt.insert('end', "ȥȥԥܥå\n", tag_middle) txt.insert('end', "ȥ\n", tag_kanji_title) txt.insert('end', " \n ", tag_demospace) txt.insert('end', "1. Сʤ\n", tag_demo, "demo-entry1") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "2. С\n", tag_demo, "demo-entry2") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "3. ǧڽդΥȥܥåȥѥɥե (ǽбСTkɬ)\n", tag_demo, "demo-entry3") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "4. ԥܥå (ǽбСTkɬ)\n", tag_demo, "demo-spin") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "5. ܥܥå (Tile/Ttkĥؤбɬ)\n", tag_demo, "demo-combo") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "6. ñʥե\n", tag_demo, "demo-form") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "\n") #txt.insert('end', "ƥ\n", tag_middle) txt.insert('end', "ƥ\n", tag_kanji_title) txt.insert('end', " \n ", tag_demospace) txt.insert('end', "1. Ūʥƥ\n", tag_demo, "demo-text") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "2. ɽ.\n", tag_demo, "demo-style") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "3. ϥѡƥ(Х).\n", tag_demo, "demo-bind") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "4. ɥƥ\n", tag_demo, "demo-twind") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "5. ɥƥ (ǽбСTkɬ)\n", tag_demo, "demo-twind2") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "6. \n", tag_demo, "demo-search") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "7. ƥȥåȤ(peering) (ǽбСTkɬ)\n", tag_demo, "demo-textpeer") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "\n") #txt.insert('end', "Х\n", tag_middle) txt.insert('end', "Х\n", tag_kanji_title) txt.insert('end', " \n ", tag_demospace) txt.insert('end', "1. ƥη\n", tag_demo, "demo-items") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "2. 2 Υץå\n", tag_demo, "demo-plot") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "3. ƥ\n", tag_demo, "demo-ctext") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "4. η\n", tag_demo, "demo-arrow") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "5. 롼顼\n", tag_demo, "demo-ruler") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "6. եץ\n", tag_demo, "demo-floor") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "7. եץ (ۤʤ륭Хƥˡ)\n", tag_demo, "demo-floor2") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "8. ǽʥХ\n", tag_demo, "demo-cscroll") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "9. ܡɾεΤν (Tile/Ttkĥؤбɬ)\n", tag_demo, "demo-knightstour") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "\n") #txt.insert('end', "ȥץ쥹С\n", tag_middle) txt.insert('end', "ȥץ쥹С\n", tag_kanji_title) txt.insert('end', " \n ", tag_demospace) txt.insert('end', "1. ľ\n", tag_demo.id, "demo-vscale") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "2. ʿ\n", tag_demo.id, "demo-hscale") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "3. ץ쥹С (Tile/Ttkĥؤбɬ)\n", tag_demo.id, "demo-ttkprogress") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "\n") txt.insert('end', "ڥɥɥȥΡȥ֥å\n", tag_kanji_title) txt.insert('end', " \n ", tag_demospace) txt.insert('end', "1. ʿ (ǽбСTkɬ)\n", tag_demo.id, "demo-paned1") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "2. ľ (ǽбСTkɬ)\n", tag_demo.id, "demo-paned2") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "3. ơޤбߥڥ (Tile/Ttkĥؤбɬ)\n", tag_demo.id, "demo-ttkpane") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "4. Ρȥ֥åå (Tile/Ttkĥؤбɬ)\n", tag_demo.id, "demo-ttknote") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "\n") #txt.insert('end', "˥塼ȥġС\n", tag_middle) txt.insert('end', "˥塼ȥġС\n", tag_kanji_title) txt.insert('end', " \n ", tag_demospace) txt.insert('end', "1. ˥塼ȥɤޤɥ\n", tag_demo, "demo-menu") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "2. ˥塼ȥɤޤɥ (Tk8.x )\n", tag_demo, "demo-menu8x") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "3. (ǽбСTkɬ)\n", tag_demo, "demo-menu84") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "4. ˥塼ܥ (Tk8.x )\n", tag_demo, "demo-menubu") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "5. ơޤб˥塼ܥ (Tile/Ttkĥؤбɬ)\n", tag_demo.id, "demo-ttkmenu") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "6. ơޤбġС (Tile/Ttkĥؤбɬ)\n", tag_demo.id, "demo-toolbar") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "\n") #txt.insert('end', "ɥ\n", tag_middle) txt.insert('end', "ɥ\n", tag_kanji_title) txt.insert('end', " \n ", tag_demospace) txt.insert('end', "1. åܥå\n", tag_demo, "demo-msgbox") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "2. ܺ٥ƥդΥåܥå (ǽбСTkɬ)\n", tag_demo, "demo-msgbox2") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "3. ե\n", tag_demo, "demo-filebox") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "4. \n", tag_demo, "demo-clrpick") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "\n") #txt.insert('end', "˥᡼\n", tag_middle) txt.insert('end', "˥᡼\n", tag_kanji_title) txt.insert('end', " \n ", tag_demospace) txt.insert('end', "1. ˥᡼٥ (ǽбСTkɬ)\n", tag_demo, "demo-anilabel") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "2. ȷΥ˥᡼ (ǽбСTkɬ)\n", tag_demo, "demo-aniwave") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "3. ҤΥߥ졼 (ǽбСTkɬ)\n", tag_demo, "demo-pendulum") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "4. A celebration of Rube Goldberg (ǽбСTkɬ)\n", tag_demo, "demo-goldberg") txt.insert('end', "\n") #txt.insert('end', "¾\n", tag_middle) txt.insert('end', "¾\n", tag_kanji_title) txt.insert('end', " \n ", tag_demospace) txt.insert('end', "1. Ȥ߹ߤΥӥåȥޥå\n", tag_demo, "demo-bitmap") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "2. ⡼(륰)\n", tag_demo, "demo-dialog1") txt.insert('end', " \n ", tag_demospace) txt.insert('end', "3. ⡼(Х륰)\n", tag_demo, "demo-dialog2") txt.insert('end', " \n ", tag_demospace) txt.state('disabled') scr.focus ################################ # method ################################ def positionWindow(w) w.geometry('+300+300') end # ƥåȤȡѿ̾ TkVariable Ȥ()¤ӤϤ $showVarsWin = {} def showVars1(parent, *args) if $showVarsWin[parent.path] begin $showVarsWin[parent.path].destroy rescue end end top = TkToplevel.new(parent) {|w| title "Variable values" base = TkFrame.new(w).pack(:fill=>:both, :expand=>true) TkLabel.new(base) { text "ѿ:" width 20 anchor 'center' if $tk_version =~ /^4.*/ font '-Adobe-helvetica-medium-r-normal--*-180-*-*-*-*-*-*' else font 'Helvetica 14' end }.pack('side'=>'top', 'fill'=>'x') len = 1 args.each{|vnam,vbody| len = vnam.to_s.length if vnam.to_s.length > len } args.each{|vnam,vbody| TkFrame.new(base){|f| #TkLabel.new(f, 'text'=>"#{vnam}: ").pack('side'=>'left') TkLabel.new(f, 'text'=>"#{vnam}: ",'width'=>len+2).pack('side'=>'left') TkLabel.new(f, 'textvariable'=>vbody, 'anchor'=>'w')\ .pack('side'=>'left', 'expand'=>'yes', 'fill'=>'x') }.pack('side'=>'top', 'anchor'=>'w', 'fill'=>'x') } TkButton.new(base) { text "λ" command proc{w.destroy} }.pack('side'=>'bottom', 'pady'=>2) } $showVarsWin[parent.path] = top end def showVars2(parent, *args) if $showVarsWin[parent.path] begin $showVarsWin[parent.path].destroy rescue end end $showVarsWin[parent.path] = TkToplevel.new(parent) {|top| title "Variable values" base = TkFrame.new(top).pack(:fill=>:both, :expand=>true) TkLabelFrame.new(base, :text=>"ѿ:", :font=>{:family=>'Helvetica', :size=>14}){|f| args.each{|vnam,vbody| TkGrid(TkLabel.new(f, :text=>"#{vnam}: ", :anchor=>'w'), TkLabel.new(f, :textvariable=>vbody, :anchor=>'w'), :padx=>2, :pady=>2, :sticky=>'w') } f.grid(:sticky=>'news', :padx=>4) f.grid_columnconfig(1, :weight=>1) f.grid_rowconfig(100, :weight=>1) } TkButton.new(base, :text=>"λ", :width=>8, :default=>:active, :command=>proc{top.destroy}){|b| top.bind('Return', proc{b.invoke}) top.bind('Escape', proc{b.invoke}) b.grid(:sticky=>'e', :padx=>4, :pady=>[6, 4]) } base.grid_columnconfig(0, :weight=>1) base.grid_rowconfig(0, :weight=>1) } end if $tk_major_ver < 8 alias showVars showVars1 elsif $tk_major_ver == 8 && $tk_minor_ver < 4 alias showVars showVars1 else # ver >= 8.4 alias showVars showVars2 end # ȥåץ٥륵ݡ module PseudoToplevel_Evaluable def pseudo_toplevel_eval(body = Proc.new) Thread.current[:TOPLEVEL] = self begin body.call ensure Thread.current[:TOPLEVEL] = nil end end def pseudo_toplevel_evaluable? @pseudo_toplevel_evaluable end def pseudo_toplevel_evaluable=(mode) @pseudo_toplevel_evaluable = (mode)? true: false end def self.extended(mod) mod.__send__(:extend_object, mod) mod.instance_variable_set('@pseudo_toplevel_evaluable', true) end end class Object alias __method_missing__ method_missing private :__method_missing__ def method_missing(id, *args) begin has_top = (top = Thread.current[:TOPLEVEL]) && top.respond_to?(:pseudo_toplevel_evaluable?) && top.pseudo_toplevel_evaluable? && top.respond_to?(id) rescue Exception => e has_top = false end if has_top top.__send__(id, *args) else __method_missing__(id, *args) end end end class Proc def initialize(*args, &b) super @__pseudo_toplevel__ = Thread.current[:TOPLEVEL] end alias __call__ call def call(*args, &b) if top = @__pseudo_toplevel__ orig_top = Thread.current[:TOPLEVEL] Thread.current[:TOPLEVEL] = top begin __call__(*args, &b) ensure Thread.current[:TOPLEVEL] = orig_top end else __call__(*args, &b) end end end def proc(&b) Proc.new(&b) end def lambda(&b) Proc.new(&b) end def _null_binding Module.new.instance_eval{extend PseudoToplevel_Evaluable} # binding # Module.new.instance_eval{binding} end private :_null_binding def eval_samplecode(code, file=nil) #eval(code) #_null_binding.pseudo_toplevel_eval{ eval(code) } #Thread.new{ _null_binding.pseudo_toplevel_eval{ eval(code) } } Thread.new{ _null_binding.pseudo_toplevel_eval{ begin if file eval(code, binding, "(eval:#{file})") else eval(code) end rescue Exception=>e #p e TkBgError.show(e.message + "\n" + "\n---< backtrace of Ruby side >-----\n" + e.backtrace.join("\n") + "\n---< backtrace of Tk side >-------") end } } Tk.update end # ƥȾǤ click Фư def invoke(txt, idx) tag = txt.tag_names(idx).find{|t| t.kind_of?(String) && t =~ /^demo-/} return unless tag cursor = txt.cget('cursor') txt.cursor('watch') Tk.update # eval(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join, _null_binding) # Tk.update eval_samplecode(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join, tag[5..-1] + '.rb') txt.cursor(cursor) $tag_visited.add("#{idx} linestart +1 chars", "#{idx} lineend +1 chars") end =begin def invoke (txt, idx) tag = txt.tag_names(idx).find{|t| t.kind_of?(String) && t =~ /^demo-/} return unless tag current_cursor = txt.cget('cursor') txt.cursor('watch') Tk.update # eval `cat #{tag[5..-1]}.rb` # eval `cat #{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb` eval IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join Tk.update # txt.cursor('xterm') txt.cursor(current_cursor) $tag_visited.add("#{idx} linestart +1 chars", "#{idx} lineend +1 chars") end =end # ɽ def showStatus (txt, index) tag = txt.tag_names(index).find{|t| t.kind_of?(String) && t =~ /^demo-/} cursor = txt.cget('cursor') unless tag $statusBarLabel.configure('text', " ") newcursor = 'xterm' else demoname = tag[5..-1] $statusBarLabel.configure('text', "ץץ \"#{demoname}\" μ¹ ") newcursor = 'hand2' end txt.configure('cursor'=>newcursor) if cursor != newcursor end # ɤɽ def showCode1(demo) file = "#{demo}.rb" $code_window = nil unless defined? $code_window if $code_window == nil || TkWinfo.exist?($code_window) == false $code_window = TkToplevel.new(nil) f = TkFrame.new($code_window) TkButton.new(f) { #text "λ" text "Ĥ" command proc{ $code_window.destroy $code_window = nil } }.pack('side'=>'right', 'expand'=>'false', 'pady'=>2) TkButton.new(f) { text "Ƽ¹" # command proc{eval($code_text.get('1.0','end'), _null_binding)} command proc{eval_samplecode($code_text.get('1.0','end'), '')} }.pack('side'=>'right', 'expand'=>'false', 'pady'=>2) TkLabel.new(f,'text'=>'line:').pack('side'=>'left') linenum =TkLabel.new(f,'text'=>'').pack('side'=>'left') TkLabel.new(f,'text'=>' pos:').pack('side'=>'left') posnum =TkLabel.new(f,'text'=>'').pack('side'=>'left') $set_linenum = proc{|w| line, pos = w.index('insert').split('.') linenum.text = line posnum.text = pos } f.pack('side'=>'bottom', 'expand'=>'true', 'fill'=>'x') if $tk_version =~ /^4\.[01]/ s = TkScrollbar.new($code_window, 'orient'=>'vertical') $code_text = TkText.new($code_window) { height 40 setgrid 'yes' yscrollcommand proc{|first,last| s.set first,last} } s.command(proc{|*args| $code_text.yview(*args)}) s.pack('side'=>'right', 'fill'=>'y') $code_text.pack('side'=>'left', 'expand'=>'yes', 'fill'=>'both') else TkFrame.new($code_window) {|f| pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1) hs = TkScrollbar.new($code_window, 'highlightthickness'=>0, 'orient'=>'horizontal') vs = TkScrollbar.new($code_window, 'highlightthickness'=>0, 'orient'=>'vertical') $code_text = TkText.new($code_window) {|t| height 40 #wrap 'word' wrap 'char' xscrollcommand proc{|first,last| hs.set first,last} yscrollcommand proc{|first,last| vs.set first,last} setgrid 'yes' highlightthickness 0 pady 2 padx 3 hs.command(proc{|*args| $code_text.xview(*args)}) vs.command(proc{|*args| $code_text.yview(*args)}) } $code_text.grid('in'=>f, 'padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') vs.grid('in'=>f, 'padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>1, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') # xs.grid('in'=>f, 'padx'=>1, 'pady'=>1, 'row'=>1, 'column'=>0, # 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') TkGrid.rowconfigure(f, 0, 'weight'=>1, 'minsize'=>0) TkGrid.columnconfigure(f, 0, 'weight'=>1, 'minsize'=>0) } end btag = TkBindTag.new btag.bind('Key', $set_linenum, '%W') btag.bind('Button', $set_linenum, '%W') btags = $code_text.bindtags btags.insert(btags.index($code_text.class) + 1, btag) $code_text.bindtags = btags else $code_window.deiconify $code_window.raise end $code_window.title("Demo code: #{file}") $code_window.iconname(file) # fid = open(file, 'r') fid = open([$demo_dir, file].join(File::Separator), 'r') $code_text.delete('1.0', 'end') #$code_text.insert('1.0', `cat #{file}`) $code_text.insert('1.0', fid.read) #$code_mark = TkTextMark.new($code_text, '1.0') #$code_text.set_insert('1.0') TkTextMarkInsert.new($code_text,'1.0') $set_linenum.call($code_text) fid.close end def showCode2(demo) file = "#{demo}.rb" $code_window = nil unless defined? $code_window if $code_window == nil || TkWinfo.exist?($code_window) == false $code_window = TkToplevel.new(nil) tf = TkFrame.new($code_window) $code_text = TkText.new(tf, :font=>'Courier 10', :height=>30, :wrap=>'word', :bd=>1, :setgrid=>true, :highlightthickness=>0, :pady=>2, :padx=>3) xscr = TkScrollbar.new(tf, :bd=>1){assign($code_text)} yscr = TkScrollbar.new(tf, :bd=>1){assign($code_text)} TkGrid($code_text, yscr, :sticky=>'news') #TkGrid(xscr) tf.grid_rowconfigure(0, :weight=>1) tf.grid_columnconfigure(0, :weight=>1) bf = TkFrame.new($code_window) lf = TkFrame.new(bf) TkLabel.new(lf, :text=>'line:').pack(:side=>:left) linenum =TkLabel.new(lf, :text=>'').pack(:side=>:left) TkLabel.new(lf, :text=>' pos:').pack(:side=>:left) posnum =TkLabel.new(lf, :text=>'').pack(:side=>:left) $set_linenum = proc{|w| line, pos = w.index('insert').split('.') linenum.text = line posnum.text = pos } #b_dis = TkButton.new(bf, :text=>'λ', :default=>:active, b_dis = TkButton.new(bf, :text=>'Ĥ', :default=>:active, :command=>proc{ $code_window.destroy $code_window = nil }, :image=>$image['delete'], :compound=>:left) b_prn = TkButton.new(bf, :text=>'', :command=>proc{printCode($code_text, file)}, :image=>$image['print'], :compound=>:left) b_run = TkButton.new(bf, :text=>'Ƽ¹', :command=>proc{ # eval($code_text.get('1.0','end'), _null_binding) eval_samplecode($code_text.get('1.0','end'), '') }, :image=>$image['refresh'], :compound=>:left) TkGrid(lf, 'x', b_run, b_prn, b_dis, :padx=>4, :pady=>[6,4]) bf.grid_columnconfigure(1, :weight=>1) TkGrid(tf, :sticky=>'news') TkGrid(bf, :sticky=>'ew') $code_window.grid_columnconfigure(0, :weight=>1) $code_window.grid_rowconfigure(0, :weight=>1) $code_window.bind('Return', proc{|win| b_dis.invoke unless win.kind_of?(TkText) }, '%W') $code_window.bindinfo('Return').each{|cmd, arg| $code_window.bind_append('Escape', cmd, arg) } btag = TkBindTag.new btag.bind('Key', $set_linenum, '%W') btag.bind('Button', $set_linenum, '%W') btags = $code_text.bindtags btags.insert(btags.index($code_text.class) + 1, btag) $code_text.bindtags = btags else $code_window.deiconify $code_window.raise end $code_window.title("Demo code: #{file}") $code_window.iconname(file) fid = open([$demo_dir, file].join(File::Separator), 'r') $code_text.delete('1.0', 'end') $code_text.insert('1.0', fid.read) TkTextMarkInsert.new($code_text,'1.0') $set_linenum.call($code_text) fid.close end if $tk_major_ver < 8 alias showCode showCode1 elsif $tk_major_ver == 8 && $tk_minor_ver < 4 alias showCode showCode1 else # ver >= 8.4 alias showCode showCode2 end # printCode -- # Prints the source code currently displayed in the See Code dialog. # Much thanks to Arjen Markus for this. # # Arguments: # txt - Name of text widget containing code to print # file - Name of the original file (implicitly for title) def printCode(txt, file) code = txt.get('1.0', 'end - 1c') dir = '.' dir = ENV['HOME'] if ENV['HOME'] dir = ENV['TMP'] if ENV['TMP'] dir = ENV['TEMP'] if ENV['TEMP'] fname = [dir, 'tkdemo-' + file].join(File::Separator) open(fname, 'w'){|fid| fid.print(code)} begin case Tk::TCL_PLATFORM('platform') when 'unix' msg = `lp -c #{fname}` unless $?.exitstatus == 0 Tk.messageBox(:title=>'Print spooling failure', :message=>'顼ȯޤ' + '˼ԤΤȻפޤ : ' + msg) end when 'windows' begin printTextWin32(fname) rescue => e Tk.messageBox(:title=>'Print spooling failure', :message=>'顼ȯޤ' + '˼ԤΤȻפޤ : ' + e.message) end when 'macintosh' Tk.messageBox(:title=>'Operation not Implemented', :message=>'ǽϤޤƤޤ') else Tk.messageBox(:title=>'Operation not Implemented', :message=>'Ф줿Ķ ' + Tk::TCL_PLATFORM('platform') + ' ̤ΤδĶǤ뤿ᡤ' + 'ǽϼƤޤ: ') end ensure File.delete(fname) end end # printTextWin32 -- # Print a file under Windows # # Arguments: # filename - Name of the file # def printTextWin32(fname) require 'win32/registry' begin app = Win32::Registry::HKEY_CLASSES_ROOT['.txt'] pcmd = nil Win32::Registry::HKEY_CLASSES_ROOT.open("#{app}\\shell\\print"){|reg| pcmd = reg['command'] } rescue app = Tk.tk_call('auto_execok', 'notepad.exe') pcmd = "#{app} /p %1" end pcmd.gsub!('%1', fname) puts pcmd cmd = Tk.tk_call('auto_execok', 'start') + ' /min ' + pcmd msg = `#{cmd}` unless $?.exitstatus == 0 fail RuntimeError, msg end end # aboutBox # # Pops up a message box with an "about" message # def aboutBox Tk.messageBox('icon'=>'info', 'type'=>'ok', 'title'=>'About Widget Demo', 'message'=>"Ruby/Tk åȥǥ Ver.1.7.0-jp\n\n" + "based on demos of Tk8.1 -- 8.5 " + "( Copyright of Tcl/Tk demos:: " + "(c) 1996-1997 Sun Microsystems, Inc. / " + "(c) 1997-2000 Ajuba Solutions, Inc. / " + "(c) 2001-2007 Donal K. Fellows / " + "(c) 2002-2007 Daniel A. Steffen )\n\n" + "Your Ruby & Tk Version ::\n" + "Ruby#{RUBY_VERSION}(#{RUBY_RELEASE_DATE})[#{RUBY_PLATFORM}] / Tk#{$tk_patchlevel}#{(Tk::JAPANIZED_TK)? '-jp': ''}\n\n" + "Ruby/Tk release date :: tcltklib #{TclTkLib::RELEASE_DATE}; tk #{Tk::RELEASE_DATE}") end #################################### # ǻꤵ줿ǥư no_launcher = false if ARGV[0] == '-n' ARGV.shift no_launcher = true if ARGV.size > 0 else # show the root widget to make it lower then demo windows Tk.update end ARGV.each{|cmd| if cmd =~ /(.*).rb/ cmd = $1 end #eval(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join, # _null_binding) eval_samplecode(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join, cmd + '.rb') } if no_launcher $root.withdraw # hide root window Thread.start{ loop do count = 0 $root.winfo_children.each{|w| count += 1 if w.kind_of?(TkToplevel) } $root.destroy if count == 0 end } end ################################ # ٥Ԥ Tk.mainloop ================================================ FILE: ext/tk/sample/editable_listbox.rb ================================================ # # Editable_TkListbox class # # When "DoubleClick-1" on a listbox item, the entry box is opend on the # item. And when hit "Return" key on the entry box after modifying the # text, the entry box is closed and the item is changed. Or when hit # "Escape" key, the entry box is closed without modification. # # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' class Editable_TkListbox < TkListbox def _ebox_placer(coord_y) idx = self.nearest(coord_y) x, y, w, h = self.bbox(idx) @ebox.place(:x => 0, :relwidth => 1.0, :y => y - self.selectborderwidth, :height => h + 2 * self.selectborderwidth) @ebox.pos = idx @ebox.value = self.listvariable.list[idx] @ebox.focus end private :_ebox_placer def create_self(keys) super(keys) unless self.listvariable self.listvariable = TkVariable.new(self.get(0, :end)) end @ebox = TkEntry.new(self){ @pos = -1 def self.pos; @pos; end def self.pos=(idx); @pos = idx; end } @ebox.bind('Return'){ list = self.listvariable.list list[@ebox.pos] = @ebox.value self.listvariable.value = list @ebox.place_forget @ebox.pos = -1 } @ebox.bind('Escape'){ @ebox.place_forget @ebox.pos = -1 } self.bind('Double-1', '%y'){|y| _ebox_placer(y) } end end if $0 == __FILE__ scr = TkScrollbar.new.pack(:side=>:right, :fill=>:y) lbox1 = Editable_TkListbox.new.pack(:side=>:left) lbox2 = Editable_TkListbox.new.pack(:side=>:left) scr.assign(lbox1, lbox2) lbox1.insert(:end, *%w(a b c d e f g h i j k l m n)) lbox2.insert(:end, 0,1,2,3,4,5,6,7,8,9,0,1,2,3) Tk.mainloop end ================================================ FILE: ext/tk/sample/encstr_usage.rb ================================================ require 'tk' TkMessage.new(:width=>400, :text=><5).pack t2 = TkText.new(:height=>5).pack t3 = TkText.new(:height=>5).pack src_str = IO.readlines(File.join(File.dirname(__FILE__),'iso2022-kr.txt')).join t1.insert('end', "use neither Tk::EncodedString class nor Tk.encoding= method\n\n") t1.insert('end', src_str) enc_str = Tk::EncodedString(src_str, 'iso2022-kr') t2.insert('end', "use Tk::EncodedString class (Tk.encoding => '#{Tk.encoding}')\n\n") t2.insert('end', enc_str) Tk.encoding = 'iso2022-kr' t3.insert('end', "use Tk.encoding = 'iso2022-kr' (Tk.force_default_encoding? == #{Tk.force_default_encoding?})\n\n") t3.insert('end', src_str) Tk.mainloop ================================================ FILE: ext/tk/sample/figmemo_sample.rb ================================================ #!/usr/bin/env ruby require 'tk' begin # try to use Img extension require 'tkextlib/tkimg' rescue Exception # cannot use Img extention --> ignore end ############################ # scrolled_canvas class TkScrolledCanvas < TkCanvas include TkComposite def initialize_composite(keys={}) @h_scr = TkScrollbar.new(@frame) @v_scr = TkScrollbar.new(@frame) @canvas = TkCanvas.new(@frame) @path = @canvas.path @canvas.xscrollbar(@h_scr) @canvas.yscrollbar(@v_scr) TkGrid.rowconfigure(@frame, 0, :weight=>1, :minsize=>0) TkGrid.columnconfigure(@frame, 0, :weight=>1, :minsize=>0) @canvas.grid(:row=>0, :column=>0, :sticky=>'news') @h_scr.grid(:row=>1, :column=>0, :sticky=>'ew') @v_scr.grid(:row=>0, :column=>1, :sticky=>'ns') delegate('DEFAULT', @canvas) delegate('background', @canvas, @h_scr, @v_scr) delegate('activebackground', @h_scr, @v_scr) delegate('troughcolor', @h_scr, @v_scr) delegate('repeatdelay', @h_scr, @v_scr) delegate('repeatinterval', @h_scr, @v_scr) delegate('borderwidth', @frame) delegate('relief', @frame) delegate_alias('canvasborderwidth', 'borderwidth', @canvas) delegate_alias('canvasrelief', 'relief', @canvas) delegate_alias('scrollbarborderwidth', 'borderwidth', @h_scr, @v_scr) delegate_alias('scrollbarrelief', 'relief', @h_scr, @v_scr) configure(keys) unless keys.empty? end end ############################ class PhotoCanvas < TkScrolledCanvas USAGE = <@photo) width = self.width height = self.height @scr_region = [-width, -height, width, height] self.scrollregion(@scr_region) self.xview_moveto(0.25) self.yview_moveto(0.25) @col = 'red' @font = 'Helvetica -12' @memo_id_num = -1 @memo_id_head = 'memo_' @memo_id_tag = nil @overlap_d = 2 @state = TkVariable.new @border = 2 @selectborder = 1 @delta = @border + @selectborder @entry = TkEntry.new(self, :relief=>:ridge, :borderwidth=>@border, :selectborderwidth=>@selectborder, :highlightthickness=>0) @entry.bind('Return'){@state.value = 0} @mode = old_mode = 0 _state0() bind('2', :x, :y){|x,y| scan_mark(x,y)} bind('B2-Motion', :x, :y){|x,y| scan_dragto(x,y)} bind('3'){ next if (old_mode = @mode) == 0 @items.each{|item| item.delete } _state0() } bind('Double-3', :widget, :x, :y){|w, x, y| next if old_mode != 0 x = w.canvasx(x) y = w.canvasy(y) tag = nil w.find_overlapping(x - @overlap_d, y - @overlap_d, x + @overlap_d, y + @overlap_d).find{|item| ! (item.tags.find{|name| if name =~ /^(#{@memo_id_head}\d+)$/ tag = $1 end }.empty?) } w.delete(tag) if tag } end #----------------------------------- private def _state0() # init @mode = 0 @memo_id_num += 1 @memo_id_tag = @memo_id_head + @memo_id_num.to_s @target = nil @items = [] @mark = [0, 0] bind_remove('Motion') bind('ButtonRelease-1', proc{|x,y| _state1(x,y)}, '%x', '%y') end def _state1(x,y) # set center @mode = 1 @target = TkcOval.new(self, [canvasx(x), canvasy(y)], [canvasx(x), canvasy(y)], :outline=>@col, :width=>3, :tags=>[@memo_id_tag]) @items << @target @mark = [x,y] bind('Motion', proc{|x,y| _state2(x,y)}, '%x', '%y') bind('ButtonRelease-1', proc{|x,y| _state3(x,y)}, '%x', '%y') end def _state2(x,y) # create circle @mode = 2 r = Integer(Math.sqrt((x-@mark[0])**2 + (y-@mark[1])**2)) @target.coords([canvasx(@mark[0] - r), canvasy(@mark[1] - r)], [canvasx(@mark[0] + r), canvasy(@mark[1] + r)]) end def _state3(x,y) # set line start @mode = 3 @target = TkcLine.new(self, [canvasx(x), canvasy(y)], [canvasx(x), canvasy(y)], :arrow=>:first, :arrowshape=>[10, 14, 5], :fill=>@col, :tags=>[@memo_id_tag]) @items << @target @mark = [x, y] bind('Motion', proc{|x,y| _state4(x,y)}, '%x', '%y') bind('ButtonRelease-1', proc{|x,y| _state5(x,y)}, '%x', '%y') end def _state4(x,y) # create line @mode = 4 @target.coords([canvasx(@mark[0]), canvasy(@mark[1])], [canvasx(x), canvasy(y)]) end def _state5(x,y) # set text @mode = 5 if x - @mark[0] >= 0 justify = 'left' dx = - @delta if y - @mark[1] >= 0 anchor = 'nw' dy = - @delta else anchor = 'sw' dy = @delta end else justify = 'right' dx = @delta if y - @mark[1] >= 0 anchor = 'ne' dy = - @delta else anchor = 'se' dy = @delta end end bind_remove('Motion') @entry.value = '' @entry.configure(:justify=>justify, :font=>@font, :foreground=>@col) ewin = TkcWindow.new(self, [canvasx(x)+dx, canvasy(y)+dy], :window=>@entry, :state=>:normal, :anchor=>anchor, :tags=>[@memo_id_tag]) @entry.focus @entry.grab @state.wait @entry.grab_release ewin.delete @target = TkcText.new(self, [canvasx(x), canvasy(y)], :anchor=>anchor, :justify=>justify, :fill=>@col, :font=>@font, :text=>@entry.value, :tags=>[@memo_id_tag]) _state0() end #----------------------------------- public def load_photo(filename) @photo.configure(:file=>filename) end def modified? ! ((find_withtag('all') - [@img]).empty?) end def fig_erase (find_withtag('all') - [@img]).each{|item| item.delete} end def reset_region width = @photo.width height = @photo.height if width > @scr_region[2] @scr_region[0] = -width @scr_region[2] = width end if height > @scr_region[3] @scr_region[1] = -height @scr_region[3] = height end self.scrollregion(@scr_region) self.xview_moveto(0.25) self.yview_moveto(0.25) end def get_texts ret = [] find_withtag('all').each{|item| if item.kind_of?(TkcText) ret << item[:text] end } ret end end ############################ # define methods for menu def open_file(canvas, fname) if canvas.modified? ret = Tk.messageBox(:icon=>'warning',:type=>'okcancel',:default=>'cancel', :message=>'Canvas may be modified. Realy erase? ') return if ret == 'cancel' end filetypes = [ ['GIF Files', '.gif'], ['GIF Files', [], 'GIFF'], ['PPM Files', '.ppm'], ['PGM Files', '.pgm'] ] begin if Tk::Img::package_version != '' filetypes << ['JPEG Files', ['.jpg', '.jpeg']] filetypes << ['PNG Files', '.png'] filetypes << ['PostScript Files', '.ps'] filetypes << ['PDF Files', '.pdf'] filetypes << ['Windows Bitmap Files', '.bmp'] filetypes << ['Windows Icon Files', '.ico'] filetypes << ['PCX Files', '.pcx'] filetypes << ['Pixmap Files', '.pixmap'] filetypes << ['SGI Files', '.sgi'] filetypes << ['Sun Raster Files', '.sun'] filetypes << ['TGA Files', '.tga'] filetypes << ['TIFF Files', '.tiff'] filetypes << ['XBM Files', '.xbm'] filetypes << ['XPM Files', '.xpm'] end rescue end filetypes << ['ALL Files', '*'] fpath = Tk.getOpenFile(:filetypes=>filetypes) return if fpath.empty? begin canvas.load_photo(fpath) rescue => e Tk.messageBox(:icon=>'error', :type=>'ok', :message=>"Fail to read '#{fpath}'.\n#{e.message}") end canvas.fig_erase canvas.reset_region fname.value = fpath end # -------------------------------- def save_memo(canvas, fname) initname = fname.value if initname != '-' initname = File.basename(initname, File.extname(initname)) fpath = Tk.getSaveFile(:filetypes=>[ ['Text Files', '.txt'], ['ALL Files', '*'] ], :initialfile=>initname) else fpath = Tk.getSaveFile(:filetypes=>[ ['Text Files', '.txt'], ['ALL Files', '*'] ]) end return if fpath.empty? begin fid = open(fpath, 'w') rescue => e Tk.messageBox(:icon=>'error', :type=>'ok', :message=>"Fail to open '#{fname.value}'.\n#{e.message}") end begin canvas.get_texts.each{|txt| fid.print(txt, "\n") } ensure fid.close end end # -------------------------------- def ps_print(canvas, fname) initname = fname.value if initname != '-' initname = File.basename(initname, File.extname(initname)) fpath = Tk.getSaveFile(:filetypes=>[ ['Postscript Files', '.ps'], ['ALL Files', '*'] ], :initialfile=>initname) else fpath = Tk.getSaveFile(:filetypes=>[ ['Postscript Files', '.ps'], ['ALL Files', '*'] ]) end return if fpath.empty? bbox = canvas.bbox('all') canvas.postscript(:file=>fpath, :x=>bbox[0], :y=>bbox[1], :width=>bbox[2] - bbox[0], :height=>bbox[3] - bbox[1]) end # -------------------------------- def quit(canvas) ret = Tk.messageBox(:icon=>'warning', :type=>'okcancel', :default=>'cancel', :message=>'Realy quit? ') exit if ret == 'ok' end # -------------------------------- # setup root root = TkRoot.new(:title=>'Fig Memo') # create canvas frame canvas = PhotoCanvas.new(root).pack(:fill=>:both, :expand=>true) usage_frame = TkFrame.new(root, :relief=>:ridge, :borderwidth=>2) hide_btn = TkButton.new(usage_frame, :text=>'hide usage', :font=>{:size=>8}, :pady=>1, :command=>proc{usage_frame.unpack}) hide_btn.pack(:anchor=>'e', :padx=>5) usage = TkLabel.new(usage_frame, :text=>PhotoCanvas::USAGE, :font=>'Helvetica 8', :justify=>:left).pack show_usage = proc{ usage_frame.pack(:before=>canvas, :fill=>:x, :expand=>true) } fname = TkVariable.new('-') f = TkFrame.new(root, :relief=>:sunken, :borderwidth=>1).pack(:fill=>:x) label = TkLabel.new(f, :textvariable=>fname, :font=>{:size=>-12, :weight=>:bold}, :anchor=>'w').pack(:side=>:left, :fill=>:x, :padx=>10) # create menu mspec = [ [ ['File', 0], ['Show Usage', proc{show_usage.call}, 5], '---', ['Open Image File', proc{open_file(canvas, fname)}, 0], ['Save Memo Texts', proc{save_memo(canvas, fname)}, 0], '---', ['Save Postscript', proc{ps_print(canvas, fname)}, 5], '---', ['Quit', proc{quit(canvas)}, 0] ] ] root.add_menubar(mspec) # manage wm_protocol root.protocol(:WM_DELETE_WINDOW){quit(canvas)} # show usage show_usage.call # -------------------------------- # start eventloop Tk.mainloop ================================================ FILE: ext/tk/sample/images/face.xbm ================================================ #define face_width 108 #define face_height 144 #define face_x_hot 48 #define face_y_hot 80 static char face_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x20, 0x80, 0x24, 0x05, 0x00, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x88, 0x24, 0x20, 0x80, 0x24, 0x00, 0x00, 0x00, 0x10, 0x80, 0x04, 0x00, 0x01, 0x00, 0x01, 0x40, 0x0a, 0x09, 0x00, 0x92, 0x04, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x12, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x84, 0x24, 0x40, 0x22, 0xa8, 0x02, 0x14, 0x84, 0x92, 0x40, 0x42, 0x12, 0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x52, 0x11, 0x00, 0x12, 0x00, 0x40, 0x02, 0x00, 0x20, 0x00, 0x08, 0x00, 0xaa, 0x02, 0x54, 0x85, 0x24, 0x00, 0x10, 0x12, 0x00, 0x00, 0x81, 0x44, 0x00, 0x90, 0x5a, 0x00, 0xea, 0x1b, 0x00, 0x80, 0x40, 0x40, 0x02, 0x00, 0x08, 0x00, 0x20, 0xa2, 0x05, 0x8a, 0xb4, 0x6e, 0x45, 0x12, 0x04, 0x08, 0x00, 0x00, 0x00, 0x10, 0x02, 0xa8, 0x92, 0x00, 0xda, 0x5f, 0x10, 0x00, 0x10, 0xa1, 0x04, 0x20, 0x41, 0x02, 0x00, 0x5a, 0x25, 0xa0, 0xff, 0xfb, 0x05, 0x41, 0x02, 0x04, 0x00, 0x00, 0x08, 0x40, 0x80, 0xec, 0x9b, 0xec, 0xfe, 0x7f, 0x01, 0x04, 0x20, 0x90, 0x02, 0x04, 0x00, 0x08, 0x20, 0xfb, 0x2e, 0xf5, 0xff, 0xff, 0x57, 0x00, 0x04, 0x02, 0x00, 0x00, 0x20, 0x01, 0xc1, 0x6e, 0xab, 0xfa, 0xff, 0xff, 0x05, 0x90, 0x20, 0x48, 0x02, 0x00, 0x04, 0x20, 0xa8, 0xdf, 0xb5, 0xfe, 0xff, 0xff, 0x0b, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x04, 0xe0, 0xbb, 0xef, 0xff, 0xff, 0x7f, 0x01, 0x00, 0x04, 0x48, 0x02, 0x00, 0x20, 0x80, 0xf4, 0x6f, 0xfb, 0xff, 0xff, 0xff, 0x20, 0x90, 0x40, 0x02, 0x00, 0x00, 0x04, 0x08, 0xb8, 0xf6, 0xff, 0xff, 0xdf, 0xbe, 0x12, 0x45, 0x10, 0x90, 0x04, 0x90, 0x00, 0x22, 0xfa, 0xff, 0xff, 0xff, 0xbb, 0xd7, 0xe9, 0x3a, 0x02, 0x02, 0x00, 0x04, 0x90, 0x80, 0xfe, 0xdf, 0xf6, 0xb7, 0xef, 0xbe, 0x56, 0x57, 0x40, 0x48, 0x09, 0x00, 0x04, 0x00, 0xfa, 0xf5, 0xdf, 0xed, 0x5a, 0xd5, 0xea, 0xbd, 0x09, 0x00, 0x00, 0x40, 0x00, 0x92, 0xfe, 0xbf, 0x7d, 0xb7, 0x6a, 0x55, 0xbf, 0xf7, 0x02, 0x11, 0x01, 0x00, 0x91, 0x00, 0xff, 0xff, 0xaf, 0x55, 0x55, 0x5b, 0xeb, 0xef, 0x22, 0x04, 0x04, 0x04, 0x00, 0xa4, 0xff, 0xf7, 0xad, 0xaa, 0xaa, 0xaa, 0xbe, 0xfe, 0x03, 0x20, 0x00, 0x10, 0x44, 0x80, 0xff, 0x7f, 0x55, 0x12, 0x91, 0x2a, 0xeb, 0xbf, 0x0b, 0x82, 0x02, 0x00, 0x00, 0xd1, 0x7f, 0xdf, 0xa2, 0xa4, 0x54, 0x55, 0xfd, 0xfd, 0x47, 0x08, 0x08, 0x00, 0x21, 0xe4, 0xff, 0x37, 0x11, 0x09, 0xa5, 0xaa, 0xb6, 0xff, 0x0d, 0x80, 0x00, 0x00, 0x04, 0xd0, 0xff, 0x4f, 0x44, 0x20, 0x48, 0x55, 0xfb, 0xff, 0x27, 0x11, 0x02, 0x40, 0x40, 0xe2, 0xfb, 0x15, 0x11, 0x4a, 0x55, 0x4a, 0x7d, 0xf7, 0x0f, 0x00, 0x00, 0x04, 0x08, 0xf8, 0xdf, 0x52, 0x44, 0x01, 0x52, 0xb5, 0xfa, 0xff, 0x0f, 0x49, 0x02, 0x00, 0x02, 0xe9, 0xf6, 0x0a, 0x11, 0xa4, 0x88, 0x4a, 0x6d, 0xff, 0x5f, 0x00, 0x00, 0x10, 0x20, 0xf0, 0x2f, 0x21, 0x44, 0x10, 0x52, 0xb5, 0xfa, 0xff, 0x0f, 0x44, 0x04, 0x80, 0x08, 0xf8, 0xab, 0x8a, 0x00, 0x81, 0xa4, 0xd4, 0xd6, 0xfe, 0x2f, 0x00, 0x00, 0x04, 0x40, 0xb5, 0x2d, 0x21, 0x08, 0x04, 0x90, 0xaa, 0xfa, 0xff, 0x1f, 0x11, 0x01, 0x00, 0x04, 0xf0, 0x57, 0x0a, 0x22, 0x40, 0x4a, 0xda, 0x5e, 0xfb, 0x1f, 0x40, 0x00, 0x40, 0x20, 0xba, 0x95, 0x90, 0x00, 0x01, 0xa0, 0xaa, 0xea, 0xff, 0x5f, 0x02, 0x02, 0x00, 0x01, 0xe8, 0x57, 0x05, 0x00, 0x00, 0x12, 0xd5, 0xfe, 0xfd, 0x1f, 0x48, 0x00, 0x04, 0x48, 0x7a, 0x95, 0x08, 0x02, 0x10, 0x40, 0xaa, 0x55, 0xf7, 0x1f, 0x00, 0x09, 0x20, 0x00, 0xf8, 0x57, 0x22, 0x10, 0x00, 0x28, 0xa9, 0xfa, 0xff, 0x5f, 0x02, 0x00, 0x00, 0x49, 0xdd, 0x29, 0x01, 0x00, 0x80, 0x80, 0xaa, 0xd7, 0xff, 0x0f, 0x10, 0x00, 0x08, 0x00, 0xf8, 0x96, 0x08, 0x00, 0x00, 0x20, 0x54, 0xfa, 0xee, 0x3f, 0x81, 0x04, 0x40, 0x24, 0xfe, 0x55, 0x82, 0x00, 0x00, 0x82, 0xd2, 0xad, 0xff, 0x0f, 0x08, 0x00, 0x04, 0x80, 0x6c, 0x97, 0x00, 0x00, 0x02, 0x20, 0xa9, 0xf6, 0xdf, 0x5f, 0x00, 0x02, 0x20, 0x09, 0xfa, 0x49, 0x12, 0x00, 0x20, 0x84, 0x54, 0xdb, 0xfe, 0x1f, 0x91, 0x00, 0x00, 0x00, 0xf8, 0x2b, 0x00, 0x20, 0x00, 0x40, 0xa4, 0xf6, 0xbb, 0x1f, 0x04, 0x00, 0x44, 0x92, 0x7e, 0x95, 0x02, 0x00, 0x00, 0x89, 0xaa, 0xdd, 0xff, 0x1f, 0x20, 0x09, 0x10, 0x00, 0xf4, 0x57, 0x20, 0x01, 0x08, 0x20, 0xa9, 0x76, 0xff, 0x5f, 0x02, 0x00, 0x00, 0x21, 0xfc, 0x4a, 0x05, 0x00, 0x01, 0x80, 0x54, 0xdb, 0xff, 0x1e, 0x08, 0x02, 0x04, 0x08, 0xf9, 0x2b, 0x00, 0x00, 0x40, 0x28, 0xd2, 0xf6, 0xff, 0xbf, 0x80, 0x00, 0x90, 0x00, 0xbc, 0x92, 0x08, 0x10, 0x00, 0x82, 0x54, 0xdb, 0xff, 0x1f, 0x20, 0x00, 0x00, 0x44, 0xf9, 0x55, 0x02, 0x01, 0x00, 0x20, 0xaa, 0xbd, 0xfd, 0x3f, 0x08, 0x04, 0x04, 0x10, 0xf4, 0x2a, 0x01, 0x00, 0x22, 0x80, 0xd4, 0xf6, 0xff, 0x5f, 0x82, 0x00, 0x40, 0x02, 0xf8, 0x55, 0x20, 0x00, 0x00, 0x50, 0x6a, 0xdf, 0xfe, 0x3f, 0x00, 0x00, 0x00, 0x48, 0xe9, 0x4a, 0x05, 0x08, 0x00, 0xa5, 0xd5, 0xf5, 0xff, 0x3f, 0x10, 0x01, 0x10, 0x01, 0xb0, 0xab, 0x92, 0x02, 0x40, 0xf8, 0xbf, 0xde, 0xfe, 0x5f, 0x02, 0x04, 0x04, 0x48, 0xfa, 0xd4, 0x6f, 0x20, 0x84, 0xef, 0xff, 0xfb, 0xff, 0x1f, 0x20, 0x00, 0x00, 0x00, 0xe0, 0xed, 0xbf, 0x0b, 0xa1, 0x7e, 0xff, 0xbf, 0xfd, 0x5f, 0x04, 0x01, 0x20, 0x49, 0xd2, 0xfb, 0xfe, 0x55, 0xd4, 0xff, 0xff, 0xf6, 0xff, 0x07, 0x00, 0x04, 0x00, 0x00, 0xc0, 0xaa, 0xfb, 0x2b, 0xa2, 0xfe, 0xff, 0xdf, 0xee, 0x1f, 0x91, 0x00, 0x82, 0xa4, 0xa4, 0xf5, 0xff, 0x57, 0xd5, 0xff, 0xbf, 0xfd, 0xff, 0x4d, 0x00, 0x00, 0x20, 0x00, 0x88, 0x5b, 0xff, 0x2f, 0x69, 0xff, 0xff, 0xdb, 0xfe, 0x1f, 0x24, 0x02, 0x00, 0x49, 0xa2, 0xd6, 0xff, 0x5f, 0xea, 0xff, 0x7f, 0x7f, 0x7f, 0x0d, 0x00, 0x00, 0x10, 0x00, 0x40, 0xab, 0xf7, 0xbb, 0xf0, 0xdf, 0xff, 0xd5, 0xff, 0xbf, 0x82, 0x04, 0x42, 0x24, 0x91, 0xd5, 0xaa, 0xae, 0xd4, 0xaa, 0x52, 0x7b, 0xff, 0x15, 0x08, 0x00, 0x00, 0x01, 0x04, 0x55, 0xd5, 0x55, 0x70, 0x5b, 0x75, 0xdd, 0xdf, 0x1f, 0x40, 0x00, 0x08, 0x48, 0xa0, 0x4a, 0xa9, 0x56, 0xea, 0x56, 0xad, 0x6a, 0x7d, 0x9b, 0x04, 0x01, 0x00, 0x02, 0x42, 0x2a, 0xd5, 0xaa, 0xa8, 0xaa, 0xaa, 0xfa, 0xdf, 0x2f, 0x10, 0x04, 0x22, 0x48, 0x08, 0x45, 0x2a, 0x15, 0x68, 0x55, 0x55, 0xd7, 0x76, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x40, 0x2a, 0x80, 0xa0, 0xb2, 0x09, 0x48, 0xb9, 0xdf, 0x17, 0x22, 0x01, 0x00, 0x24, 0x45, 0x8a, 0x24, 0x4a, 0x54, 0x51, 0x91, 0xf6, 0x6e, 0x4b, 0x00, 0x04, 0x90, 0x00, 0x80, 0x52, 0x00, 0x20, 0x69, 0x05, 0xa4, 0xaa, 0xff, 0x1e, 0x48, 0x00, 0x02, 0x92, 0x08, 0x05, 0x81, 0x94, 0xd4, 0x92, 0x40, 0xfd, 0xb6, 0x8b, 0x00, 0x01, 0x40, 0x00, 0x82, 0x54, 0x00, 0x48, 0x68, 0x05, 0x90, 0xa4, 0xef, 0x06, 0x24, 0x00, 0x08, 0x12, 0x10, 0x05, 0x00, 0x10, 0xb5, 0x01, 0x42, 0xfb, 0xbf, 0x43, 0x00, 0x09, 0x00, 0x40, 0x81, 0xa8, 0x08, 0x4a, 0xaa, 0x96, 0x90, 0xac, 0x6d, 0x15, 0x22, 0x00, 0x20, 0x09, 0x04, 0x15, 0x80, 0x28, 0xdc, 0x01, 0x24, 0xfb, 0xbf, 0x01, 0x80, 0x04, 0x09, 0x00, 0x40, 0x48, 0x02, 0x45, 0xb2, 0x2e, 0x41, 0x6d, 0xef, 0x05, 0x11, 0x00, 0x40, 0x52, 0x02, 0x15, 0x29, 0x2a, 0xac, 0x42, 0x54, 0xfb, 0x3b, 0x51, 0x84, 0x00, 0x08, 0x00, 0x20, 0x54, 0x80, 0x05, 0xb5, 0x3d, 0xa2, 0xb6, 0xdf, 0x00, 0x20, 0x04, 0x20, 0x49, 0x89, 0xa8, 0x6a, 0x29, 0xac, 0xd6, 0x54, 0xff, 0x3f, 0x84, 0x00, 0x01, 0x04, 0x10, 0x00, 0x94, 0xa8, 0x56, 0xda, 0x5f, 0xab, 0xd5, 0x1e, 0x10, 0x48, 0x00, 0x90, 0x82, 0x48, 0xa8, 0xb2, 0xac, 0xfd, 0x55, 0xd5, 0xfe, 0x9f, 0x80, 0x00, 0x0a, 0x02, 0x08, 0x02, 0x55, 0x5a, 0x75, 0xff, 0xaf, 0xb6, 0xf7, 0x2d, 0x12, 0x92, 0x00, 0x10, 0x20, 0x10, 0xa8, 0x54, 0xd5, 0xbf, 0x5d, 0xad, 0xdd, 0x0f, 0x00, 0x00, 0x04, 0x40, 0x09, 0x84, 0xa8, 0xaa, 0x5a, 0xed, 0xeb, 0x6a, 0xff, 0x9f, 0xa4, 0x24, 0x01, 0x02, 0xa0, 0x20, 0x50, 0x55, 0xd5, 0xbe, 0xae, 0xad, 0xfd, 0x16, 0x00, 0x10, 0x04, 0x20, 0x0a, 0x08, 0xb4, 0xaa, 0x95, 0xaa, 0x7b, 0xb7, 0xdb, 0x5f, 0x92, 0x04, 0x01, 0x84, 0x20, 0x21, 0x51, 0xd5, 0x2a, 0xa9, 0xee, 0xd5, 0xfe, 0x0d, 0x00, 0x20, 0x04, 0x10, 0x00, 0x08, 0x50, 0xe9, 0xd7, 0xd4, 0xfb, 0xb5, 0xff, 0x9f, 0x24, 0x09, 0x01, 0x42, 0x4a, 0xa2, 0x64, 0xd5, 0x55, 0x7b, 0x7f, 0xda, 0x7d, 0x4f, 0x00, 0x20, 0x04, 0x00, 0x80, 0x00, 0xa0, 0x2a, 0x13, 0x84, 0x6a, 0x55, 0xff, 0x1d, 0x48, 0x8a, 0x00, 0x94, 0x24, 0x8a, 0xc8, 0xaa, 0x42, 0x20, 0x5d, 0xf5, 0xff, 0x5f, 0x01, 0x00, 0x02, 0x01, 0x00, 0x20, 0xa2, 0x4a, 0x1a, 0x82, 0x56, 0xda, 0xbd, 0x3f, 0x92, 0x92, 0x00, 0x90, 0x92, 0x00, 0x40, 0x95, 0x6a, 0xf4, 0x55, 0x6d, 0xff, 0xd6, 0x00, 0x00, 0x0a, 0x04, 0x20, 0x14, 0x49, 0x4b, 0xaa, 0xaa, 0x56, 0xf5, 0xff, 0xbf, 0xab, 0xa4, 0x00, 0x20, 0x89, 0x40, 0x80, 0xaa, 0xaa, 0xaa, 0xaa, 0xde, 0xbf, 0xeb, 0x03, 0x00, 0x02, 0x04, 0x02, 0x0a, 0x10, 0x2b, 0x2a, 0x55, 0x5b, 0xf5, 0xff, 0xd7, 0x2f, 0x92, 0x00, 0x10, 0x28, 0x21, 0x01, 0x56, 0x95, 0xa0, 0x56, 0xdf, 0xef, 0xea, 0x87, 0x40, 0x0a, 0x42, 0x41, 0x00, 0x90, 0xaa, 0x52, 0xb6, 0xad, 0xfa, 0xff, 0xd5, 0x2f, 0x14, 0x00, 0x00, 0x04, 0x95, 0x04, 0xaa, 0xac, 0x55, 0x6b, 0xff, 0xb7, 0xea, 0x9f, 0x40, 0x02, 0x28, 0x51, 0x00, 0x40, 0x58, 0xd5, 0xda, 0xd6, 0x6e, 0x7f, 0xf9, 0x3f, 0x12, 0x04, 0x02, 0x04, 0x49, 0x25, 0x55, 0xaa, 0x77, 0xab, 0xff, 0x2b, 0xfd, 0x3f, 0x48, 0x01, 0x20, 0x41, 0x00, 0x00, 0x58, 0xa9, 0xda, 0xea, 0xfd, 0xaf, 0xfa, 0xff, 0x02, 0x04, 0x08, 0x14, 0x29, 0x49, 0x52, 0x55, 0x55, 0x55, 0xff, 0x8d, 0xfe, 0x3f, 0xa8, 0x00, 0x02, 0x41, 0x00, 0x02, 0xa0, 0xa2, 0xaa, 0xea, 0xff, 0x53, 0xfd, 0xff, 0x02, 0x04, 0x50, 0x04, 0x25, 0xa8, 0x54, 0x49, 0x52, 0xb5, 0xbf, 0x8a, 0xfe, 0xff, 0xa9, 0x08, 0x04, 0x50, 0x80, 0x02, 0xa1, 0x2a, 0x95, 0xea, 0xff, 0xa1, 0xff, 0xff, 0x03, 0x02, 0x90, 0x02, 0x09, 0x08, 0x44, 0x49, 0x52, 0xbd, 0x7f, 0xca, 0xff, 0xff, 0x2b, 0x09, 0x04, 0x48, 0x40, 0x82, 0x90, 0x56, 0xa9, 0xf6, 0xbf, 0xd0, 0xff, 0xff, 0x47, 0x00, 0x50, 0x02, 0x15, 0x11, 0x40, 0x95, 0xaa, 0xfd, 0x2f, 0xe9, 0xff, 0xff, 0x8f, 0x0a, 0x84, 0x50, 0x40, 0x84, 0x14, 0xaa, 0x6a, 0xff, 0x5f, 0xf2, 0xff, 0xff, 0x7f, 0x00, 0x10, 0x02, 0x09, 0x10, 0x40, 0x7d, 0xf7, 0xff, 0x0b, 0xfc, 0xff, 0xff, 0xaf, 0x02, 0x84, 0x50, 0x42, 0x85, 0x12, 0xd0, 0xdd, 0xff, 0xa7, 0xf2, 0xff, 0xff, 0xff, 0x04, 0x00, 0x0a, 0x08, 0x10, 0x48, 0xf8, 0xff, 0xff, 0x0a, 0xfe, 0xff, 0xff, 0x7f, 0x03, 0xa4, 0x80, 0xa2, 0x8a, 0x02, 0x68, 0xff, 0xff, 0x52, 0xfd, 0xff, 0xff, 0xff, 0x07, 0x00, 0x2a, 0x08, 0x20, 0x28, 0xdc, 0xff, 0x5f, 0x05, 0xff, 0xff, 0xff, 0xff, 0x0d, 0x92, 0x40, 0x22, 0x09, 0x02, 0xea, 0xfb, 0xaf, 0x48, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x12, 0x81, 0xa0, 0x48, 0x9c, 0x6e, 0x93, 0xa2, 0xff, 0xff, 0xff, 0xff, 0x07, 0xa8, 0x40, 0x28, 0x0a, 0x02, 0x74, 0xb5, 0x45, 0x81, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x02, 0x0a, 0x81, 0x20, 0x08, 0xae, 0xaa, 0x90, 0xe8, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x90, 0x40, 0x28, 0x88, 0x12, 0x58, 0x15, 0x50, 0xd0, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x44, 0x0a, 0x41, 0x21, 0x08, 0xae, 0x04, 0x14, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x10, 0x40, 0x14, 0x88, 0x04, 0xba, 0x02, 0x28, 0xe8, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x42, 0x15, 0x41, 0x21, 0x05, 0xad, 0x00, 0x05, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x10, 0x40, 0x24, 0x8a, 0x0e, 0x36, 0x00, 0x0a, 0xf4, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x42, 0x25, 0x90, 0xd0, 0x8b, 0xc2, 0x41, 0x05, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x10, 0x08, 0x05, 0xe8, 0x8e, 0x58, 0x80, 0x02, 0xfa, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x4a, 0x20, 0xa8, 0xba, 0x0b, 0x2b, 0x51, 0x01, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x8a, 0x02, 0xe8, 0xaf, 0x84, 0x90, 0x04, 0xfd, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x52, 0x21, 0x54, 0xbf, 0x1f, 0x15, 0xa5, 0x02, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x08, 0x01, 0xfa, 0xb6, 0xa4, 0x52, 0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x4a, 0xa2, 0x54, 0xef, 0x5f, 0x4b, 0xa4, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x80, 0x10, 0x82, 0xfe, 0xbf, 0x92, 0x52, 0x42, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x12, 0x42, 0xa8, 0xbf, 0x1f, 0x24, 0x80, 0xa0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x84, 0x28, 0x8a, 0xf7, 0x37, 0x80, 0x52, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x10, 0x82, 0xe0, 0xff, 0x1f, 0x00, 0x20, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x84, 0x28, 0xca, 0xff, 0x1f, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x10, 0x42, 0xf0, 0xfd, 0x1b, 0x00, 0x50, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xa4, 0x10, 0xc5, 0xff, 0x1f, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x22, 0xf8, 0xff, 0x0e, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xaa, 0x88, 0xe2, 0xff, 0x0f, 0x10, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x25, 0xfa, 0xff, 0x0f, 0x01, 0x11, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xfb, 0xfb, 0xff, 0x7f, 0x5d, 0xd5, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f}; ================================================ FILE: ext/tk/sample/images/flagdown.xbm ================================================ #define flagdown_width 48 #define flagdown_height 48 static char flagdown_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x70, 0x80, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x04, 0x00, 0x00, 0x03, 0x00, 0x06, 0x06, 0x00, 0x80, 0x01, 0x00, 0x06, 0x07, 0x00, 0xc0, 0x1f, 0x00, 0x87, 0x07, 0x00, 0xe0, 0x7f, 0x80, 0xc7, 0x07, 0x00, 0x70, 0xe0, 0xc0, 0xe5, 0x07, 0x00, 0x38, 0x80, 0xe1, 0x74, 0x07, 0x00, 0x18, 0x80, 0x71, 0x3c, 0x07, 0x00, 0x0c, 0x00, 0x3b, 0x1e, 0x03, 0x00, 0x0c, 0x00, 0x1f, 0x0f, 0x00, 0x00, 0x86, 0x1f, 0x8e, 0x07, 0x00, 0x00, 0x06, 0x06, 0xc6, 0x05, 0x00, 0x00, 0x06, 0x00, 0xc6, 0x05, 0x00, 0x00, 0x06, 0x00, 0xc6, 0x04, 0x00, 0x00, 0x06, 0x00, 0x06, 0x04, 0x00, 0x7f, 0x06, 0x00, 0x06, 0xe4, 0xff, 0x00, 0x06, 0x00, 0x06, 0x04, 0x00, 0x00, 0x06, 0x00, 0x06, 0x04, 0x00, 0x00, 0x06, 0x00, 0x06, 0x06, 0x00, 0x00, 0x06, 0x00, 0x06, 0x03, 0x00, 0x00, 0x06, 0x00, 0x86, 0x01, 0x00, 0x00, 0x06, 0x00, 0xc6, 0x00, 0x00, 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x00, 0x06, 0x00, 0x36, 0x00, 0x00, 0x00, 0x06, 0x00, 0x3e, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x2f, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x27, 0x00, 0x00, 0x00, 0x00, 0x88, 0x20, 0x00, 0x00, 0x00, 0x00, 0x88, 0x20, 0x00, 0x00, 0x00, 0x00, 0x88, 0x20, 0x00, 0x00, 0x00, 0x00, 0x88, 0x20, 0x00, 0x00, 0x00, 0x00, 0x88, 0x20, 0x00, 0x00, 0x00, 0x00, 0x88, 0x20, 0x00, 0x00, 0x00, 0x00, 0x88, 0x20, 0x00, 0x00, 0x00, 0x00, 0x88, 0x20, 0x00, 0x00, 0xf7, 0xbf, 0x8e, 0xfc, 0xdf, 0xf8, 0x9d, 0xeb, 0x9b, 0x76, 0xd2, 0x7a, 0x46, 0x30, 0xe2, 0x0f, 0xe1, 0x47, 0x55, 0x84, 0x48, 0x11, 0x84, 0x19}; ================================================ FILE: ext/tk/sample/images/flagup.xbm ================================================ #define flagup_width 48 #define flagup_height 48 static char flagup_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xef, 0x6a, 0x00, 0x00, 0x00, 0xc0, 0x7b, 0x75, 0x00, 0x00, 0x00, 0xe0, 0xe0, 0x6a, 0x00, 0x00, 0x00, 0x30, 0x60, 0x75, 0x00, 0x00, 0x00, 0x18, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x0c, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x06, 0xe0, 0x04, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x04, 0x00, 0x00, 0x80, 0x01, 0xe0, 0x06, 0x00, 0x00, 0xc0, 0x1f, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x7f, 0xe0, 0x07, 0x00, 0x00, 0x70, 0xe0, 0xe0, 0x05, 0x00, 0x00, 0x38, 0x80, 0xe1, 0x04, 0x00, 0x00, 0x18, 0x80, 0xf1, 0x04, 0x00, 0x00, 0x0c, 0x00, 0xfb, 0x04, 0x00, 0x00, 0x0c, 0x00, 0xff, 0x04, 0x00, 0x00, 0x86, 0x1f, 0xee, 0x04, 0x00, 0x00, 0x06, 0x06, 0xe6, 0x04, 0x00, 0x00, 0x06, 0x00, 0xe6, 0x04, 0x00, 0x00, 0x06, 0x00, 0xe6, 0x04, 0x00, 0x00, 0x06, 0x00, 0x66, 0x04, 0x00, 0x7f, 0x56, 0x52, 0x06, 0xe4, 0xff, 0x00, 0x76, 0x55, 0x06, 0x04, 0x00, 0x00, 0x56, 0x57, 0x06, 0x04, 0x00, 0x00, 0x56, 0x55, 0x06, 0x06, 0x00, 0x00, 0x56, 0xd5, 0x06, 0x03, 0x00, 0x00, 0x06, 0x00, 0x86, 0x01, 0x00, 0x54, 0x06, 0x00, 0xc6, 0x54, 0x55, 0xaa, 0x06, 0x00, 0x66, 0xaa, 0x2a, 0x54, 0x06, 0x00, 0x36, 0x55, 0x55, 0xaa, 0x06, 0x00, 0xbe, 0xaa, 0x2a, 0x54, 0xfe, 0xff, 0x6f, 0x55, 0x55, 0xaa, 0xfc, 0xff, 0xa7, 0xaa, 0x2a, 0x54, 0x01, 0x88, 0x60, 0x55, 0x55, 0xaa, 0xaa, 0x8a, 0xa0, 0xaa, 0x2a, 0x54, 0x55, 0x8d, 0x60, 0x55, 0x55, 0xaa, 0xaa, 0x8a, 0xa0, 0xaa, 0x2a, 0x54, 0x55, 0x8d, 0x60, 0x55, 0x55, 0xaa, 0xaa, 0x8a, 0xa0, 0xaa, 0x2a, 0x54, 0x55, 0x8d, 0x50, 0x55, 0x55, 0xaa, 0xaa, 0x8a, 0xa8, 0xaa, 0x2a, 0x54, 0x55, 0x95, 0x54, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x54, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ================================================ FILE: ext/tk/sample/images/gray25.xbm ================================================ #define grey_width 16 #define grey_height 16 static char grey_bits[] = { 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44}; ================================================ FILE: ext/tk/sample/images/grey.25 ================================================ #define grey_width 16 #define grey_height 16 static char grey_bits[] = { 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44}; ================================================ FILE: ext/tk/sample/images/grey.5 ================================================ #define grey_width 16 #define grey_height 16 static char grey_bits[] = { 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa}; ================================================ FILE: ext/tk/sample/images/letters.xbm ================================================ #define letters_width 48 #define letters_height 48 static char letters_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2e, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x21, 0x20, 0x00, 0x00, 0x00, 0x00, 0x21, 0xa0, 0x03, 0x00, 0x00, 0x70, 0x21, 0x20, 0x00, 0x00, 0x00, 0x50, 0x21, 0xa0, 0x1f, 0x00, 0x00, 0x50, 0x21, 0x20, 0x00, 0x00, 0x00, 0x70, 0x21, 0xfe, 0xff, 0xff, 0xff, 0x0f, 0x21, 0x02, 0x00, 0x00, 0x00, 0x08, 0x21, 0xfa, 0x01, 0x00, 0x80, 0x0b, 0x21, 0x02, 0x00, 0x00, 0x80, 0x0a, 0x21, 0xba, 0x01, 0x00, 0x80, 0x0a, 0x21, 0x02, 0x00, 0x00, 0x80, 0x0b, 0x21, 0x3a, 0x00, 0x00, 0x00, 0x08, 0x21, 0x02, 0x00, 0x00, 0x00, 0x08, 0x21, 0x02, 0xc0, 0xfb, 0x03, 0x08, 0x21, 0x02, 0x00, 0x00, 0x00, 0x08, 0x3f, 0x02, 0xc0, 0xbd, 0x0f, 0x08, 0x01, 0x02, 0x00, 0x00, 0x00, 0x08, 0x01, 0x02, 0xc0, 0x7f, 0x7b, 0x08, 0x01, 0x02, 0x00, 0x00, 0x00, 0x08, 0x01, 0x02, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ================================================ FILE: ext/tk/sample/images/noletter.xbm ================================================ #define noletters_width 48 #define noletters_height 48 static char noletters_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x07, 0x00, 0x00, 0xf0, 0x0f, 0xe0, 0x1f, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x7f, 0x00, 0x00, 0x3e, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x1f, 0x00, 0x00, 0xf0, 0x01, 0x80, 0x07, 0x00, 0x00, 0xc0, 0x03, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x78, 0x0e, 0xf0, 0x00, 0x00, 0x00, 0x3c, 0x1e, 0x70, 0x00, 0x00, 0x00, 0x1e, 0x1c, 0x38, 0x00, 0x00, 0x00, 0x0f, 0x38, 0x38, 0x00, 0x00, 0x80, 0x07, 0x38, 0x3c, 0xfc, 0xff, 0xff, 0x7f, 0x78, 0x1c, 0x04, 0x00, 0xe0, 0x41, 0x70, 0x1c, 0x04, 0x00, 0xf0, 0x40, 0x70, 0x1c, 0x74, 0x00, 0x78, 0x4e, 0x70, 0x0e, 0x04, 0x00, 0x3c, 0x4a, 0xe0, 0x0e, 0x74, 0x03, 0x1e, 0x4a, 0xe0, 0x0e, 0x04, 0x00, 0x0f, 0x4e, 0xe0, 0x0e, 0x04, 0x80, 0x07, 0x40, 0xe0, 0x0e, 0x04, 0xf8, 0x0f, 0x40, 0xe0, 0x0e, 0x04, 0xe0, 0x01, 0x40, 0xe0, 0x0e, 0x04, 0xf8, 0x00, 0x40, 0xe0, 0x0e, 0x04, 0x78, 0x00, 0x40, 0xe0, 0x0e, 0x04, 0xfc, 0xf3, 0x40, 0xe0, 0x1c, 0x04, 0x1e, 0x00, 0x40, 0x70, 0x1c, 0x04, 0x0f, 0x00, 0x40, 0x70, 0x1c, 0x84, 0x07, 0x00, 0x40, 0x70, 0x3c, 0xfc, 0xff, 0xff, 0x7f, 0x78, 0x38, 0xe0, 0x01, 0x00, 0x00, 0x38, 0x38, 0xf0, 0x00, 0x00, 0x00, 0x38, 0x70, 0x78, 0x00, 0x00, 0x00, 0x1c, 0xf0, 0x3c, 0x00, 0x00, 0x00, 0x1e, 0xe0, 0x1e, 0x00, 0x00, 0x00, 0x0e, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x07, 0x00, 0x00, 0x80, 0x07, 0x80, 0x07, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x1f, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x3e, 0x00, 0x00, 0xf8, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x7f, 0x00, 0x00, 0xf0, 0x0f, 0xe0, 0x1f, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00}; ================================================ FILE: ext/tk/sample/images/pattern.xbm ================================================ #define foo_width 16 #define foo_height 16 static char foo_bits[] = { 0x60, 0x06, 0x90, 0x09, 0x90, 0x09, 0xb0, 0x0d, 0x4e, 0x72, 0x49, 0x92, 0x71, 0x8e, 0x8e, 0x71, 0x8e, 0x71, 0x71, 0x8e, 0x49, 0x92, 0x4e, 0x72, 0xb0, 0x0d, 0x90, 0x09, 0x90, 0x09, 0x60, 0x06}; ================================================ FILE: ext/tk/sample/images/teapot.ppm ================================================ P6 256 256 255 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[7 eOLjQLmSMoTMnSMlRMhPL_9 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\nSMtVMzYN~[N~[N\N\O\O]O]O]O]O\O\O}[NyYNtVM\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\G-wXN}[N]O^O_O`O`O`O`OaOaOaOaOaOaOaOaO`O_O^O\N \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\aMLyYN_OaPbPcPcPdPdPdPdPdPdPdPdPdPePePePePePdPcP_OpUM\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\wXN_OdPfPgQhQhQiQiQiQiQiQjQjQjQjQjQjQjQjQjQjQiQfP`O\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\NCJiQLbPhQkQmRnRoRoRoRoRoRoRoRoRpRpSqSqSrSrSrSqSoRjQ]O\KK\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\fOLrUMcPlRqStSuTwTxTxTyTyTzTzUzUzUzUzUyTxTwTtSmRaOhPL\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\a0 cNLqUM\OfQpSwVzV|V}VVVǀVɂW̅[ՏewꪅĈgqTfQ{ZNYIK9\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\O1{G#JkRMqUMtVNiSv\dbzZvUuTsSqSnRjQeP^OrUMHh>!T4\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\G-V5wE"~I#M%U+e7l:g2b*a(`(^(])^-]1S,qC$`9 R3G-\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\@)J/i>!pA"tD"wF$yH&xH&tE$wE#yG%}M+T4S5mE*Z7!K/B*;'\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\aOoR{UǀVυX<(F-a: e!j@#k@$h>"df-^(Z'W&T&N>)F-J/b; g>#nD(jB&c y< u: r9 o7 l6 j5 h4 g3 5$D,K/b; h>"wM1tK.e="a<#cA,U8&E-<(9&.!a0 b1 c1      +3#@)46G<:HMCIXHK\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\U*vT~X{Yk+W&N$|> u: p8 k5 f3 a0 _/ ]. [- I\*_(LkRMmSMmSMnSMnSMD,R3W5mA"|O0|P1j?"c!a: X/K%&4$+2F=;HPEJL&\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\lRxTsTd)O$w; m6 g3 a0 Z- \/ T*Q(Hm8kRMmSMnTMoTMpTMpUM15G15G05G04G04GpUMpTM5^9 d!Y0W+]. s=M$dPlR\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\oTMoRdPvE"V+K%A 99F['qUMtVM99H:9H:9H:9H:9H:9H:9H:9H:9H:9H99H99H99H99H99H99H:9H;:H>;HB=HPDJ\JKmSMwXN|ZNy[ᦆ֘u{WyU]btUnRhQaO{ZNvWNtVMvXNwXNyYNzYN{ZN|ZN}[N}[N~[N~[N~[N~[N~[N~[N~[N}[N}[N{ZNzYNxXNL$f3 I$L&P(U*\. J#\OjQ\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\kRaOo9 L&C!:4f3 X&pUMuWMwXNxXN<:H<:H<:H<:H<;H<;H<;H<;H=;H=;H=;H=;H>;H>;H?HG@ILBIREJ[JKcNLjQLpRuTzU~VȁW˂X֎csҎe{VvTpSkRgQbP_O^O]O\O\O\O\O]O]O]O]O]O]O]O]O]O]O]O\O\O~\N}[N|ZNxXNT%H$G#K%Q(W+zG#nTMiQ\\\\\\\\\\\\dOLrUMuWNwXNyYN{ZN}[N{ZNwXNsVM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\`OcPnA"M&@ 8F#m6 W&rVMvWNyYNzYN|ZN}[N}[N>HE?IG@IIAIKBIODJSFJWHKhQlRpRb(i*n+|7|6r,q+p-l+g)b(sSpSlRiQgQePcPaPaO`O`O_O_O_O_O_O_O_O_O_O_O^O^O^O^O]O]O\O~[N{ZNT%F#B!Y,L&U*~I#^O`O\\\\cNLrUMzYN\O^O`ObPcPdPePfPfPfQfQfQePcPaP~[N\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\fPsVM^/ C!7 Q%tVMwXNzYN|ZN}[N\N\O\O]O]O]O]OA=HB=HB=HB>HC>HC>ID?IE?IF@IG@IIAIKBIcPdPePgQiQlRnR\'d)i*m+s/s/o+n+l*i*g)c(_(qSoRmRkQiQgQfPePdPcPbPbPbPaPaPaOaOaO`O`O`O`O`O`O_O_O^O^O]O\O}[NQD"?D"K%_/ kRLfPODJSFJ_ObPcPePfQgQiQjQkRlRmRnRnRoRoRoRnRmRlRiQeP_O\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\B+ePI#L&90y< PxXN{ZN}[N\N\O]O]O^O^O^O_O_O_O_O`O`O`O`OaOaPbPbPcPdPePfPgQhQiQkRmRZ'_(e)h)k*n,n,m*l*j*f)e)c(_(]'pRnRmRkRjQiQgQgQfPePdPdPdPcPcPcPbPbPbPbPbPaPaPaOaO`O`O_O_O^O]O_(@ B!I$B!N'w=eP`LKbNLeOLkRmRnRoRpSqSrSsStStStSuSuStStSsSrSpSmRjQbPjQL\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\bPpTME"5M$tVM{ZN}[N\O]O^O^O_O_O_O`O`O`O`OaOaPaPbPbPbPcPcPdPdPePfPgQhQiQjQkRlRmRZ'`(d)g)gj*j*i*i*g)d)c(a(_(\'pRoRnRmRkRjQiQiQhQgQgQfPePePePdPdPdPcPcPcPcPcPbPbPbPbPaPaO`O_O^O\NQ@ <G#_LKcPlSMnTMpUMsVMtSuTvTwTwTxTxTwTwTvTuTtSsSqSpSoRnRkRhQbPeOL\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\wXN\NJ%01JvWN}[N\O]O^O_O_O`O`O`OaOaPaPbPbPbPbPcPcPdPdPdPePePfQgQgQhQiQjQkQlRmRY&]'`(c(e)c\\\]]^a(`(^'['['oRnRmRlRkRkQjQiQiQhQgQgQgQfQfPePePePePdPdPdPdPdPcPcPcPbPbPaPaO`O]OOG#7F#uWM^OwXNxXNzYN{ZN|ZNyTyTxTwTuTsSpSmRjQgQdPbPaPaPbPcPePcP|ZN\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[JKbP^/ 1 01|> wXN}[N]O^O_O`O`OaOaPaPbPbPbPcPcPcPcPdPdPdPePePfPfQgQgQhQhQiQjQkQkRlRmRY&]'`(b([gihfdecU_(]'['Z'nRnRmRmRlRkRkQjQjQiQiQhQhQgQgQgQfQfQfPfPePePePePePdPdPdPcPcPbPbP`O^OD 4M&dPnSM|[N|[O|[OzZOxXNrSnRhQcP^OvXNiQL^KKRFJMCJJAIKBISFJ\JKnSMxYN_O\OaMK\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\B!qUMaPC!/00a0 uWN}[N]O_O`O`OaPaPbPbPcPcPcPcPdPdPdPePePePfPfQfQgQgQhQhQiQiQjQjQkRlRlRX&['^'`(Zdfigdcca_T\'['Z'Y&nRmRmRlRlRkRkQjQjQjQiQiQhQhQhQhQgQgQgQgQfQfQfQfPfPePePePdPdPcPbPaO^Ox< :aP]Oj8sVMmSMfOL^KKUGJIAIQEJ?IeZY638*  B\\\\\,  4 .G1!\TUrsVM{ZN`MK\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[JKyYNbP/0N$]O_O`ObPbPcPcPdPdPdPePePePfPfPfQfQgQgQgQgQhQhQhQiQiQiQjQjQkQkRkRlROZ'\'^'Vabei!fba`_]\Z['Z'Y&QmRmRmRlRlRlRkRkRkQkQjQjQjQjQiQiQiQiQiQhQhQhQhQhQhQgQgQgQgQfQfPdPcPW&dPaPrUM  B\\\\\\\\\\%7!!C*F#P) {dYzep\OgPL\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\SFJ`LKvWNaPm6 X,uWM]O`ObPcPdPdPdPePePfPfPfQfQgQgQgQgQgQhQhQhQiQiQiQiQjQjQjQkQkQkRlRlRZ'\']'_`abei"ea`__]\\YZ'Z'Z'mRmRmRlRlRlRlRlRkRkRkRkQkQjQjQjQjQjQjQiQiQiQiQiQiQiQhQhQhQgQgQfQdP_Oq8 gQ`OuWMT%\\\\\\\\\\ B B!!T,c5FT3ț~Ɠq^OfOL\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\XHK_LKsVM`OcP S%]ObPcPdPePePfPfQfQgQgQgQgQgQhQhQhQhQiQiQiQiQiQjQjQjQjQkQkRkRlRlRlR\']'^'V`abfi"ea`__]\\RZ'Z'['mRmRmRmRmRlRlRlRlRlRlRkRkRkRkRkQkQjQjQjQjQjQjQjQjQjQjQiQiQiQhQgQePSq8 aOgQ`OtVMX&\\\\\\\\\\ B B B l@!{AL$Y'afPaO]KK\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ODJ[JKaMKqUM\OcP^OvE"]OaPdPePfPfQgQgQgQhQhQhQhQhQiQiQiQiQiQjQjQjQjQjQkQkQkRkRkRlRlRlRlR^'^'_(Waacg i"ea`__^\\R['[']'mRmRmRmRmRmRmRlRlRlRlRlRlRlRlRlRlRkRkRkRkRkRkRkRkRkQkQkQjQjQiQhQePW&M&oTMiQeP_OtVMmSMdOL\\\\\\\\\ B B B JZ'_(kQiQ`OSFJ\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\TFJ\JKcNLlRMzYN`OePzZN \N`OdPfQgQgQhQhQhQiQiQiQiQiQiQjQjQjQjQjQjQkQkQkRkRkRlRlRlRlRlRlRmRa(`(`([abdh!i"da`__^]]S\']'_(nRmRmRmRmRmRmRmRmRmRmRmRmRmRmRmRlRlRlRlRlRlRlRlRlRlRlRlRlRkRkQiQePt: kQhQcP]OtVMlSMa2 \\\\\\\\\ B B $5 `(e)nRjQ^OJAI\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\XIK^KKdNLhPLuWM]ObPfQeP m6 `OcPfQhQhQiQiQjQjQjQjQjQjQjQkQkQkQkRkRkRkRlRlRlRlRlRlRlRmRmRmRmRg)c(c(b(Vcei!i!db``__^Q]'_(`(f)nRnRnRnRnRnRnRnRnRnRnRnRnRmRmRmRmRmRmRmRmRmRnRmRmRnRmRmRmRmRkRhQGa0 bPmRjQfQaP}[NrUMmSML$\\\\\\\\ B B #C, 8&H.Z7 pRjQ{ZN\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\QEJ[JK`LKdNLhQLqUM{ZN_OcPgQhQ bPePhQiQjQjQkQkQkRkRkRlRlRlRlRlRlRlRlRlRlRmRmRmRmRmRmRmRmRmRnRnRj*g)e)d)dXghecbbbU`(a(a(c(i*oRoRnRnRnRnRnRnRnRnRnRnRnRnRnRnRnRoRoRoRoRoRoRoRoRoRoRoRoRnRmRjQQ%Z- jQnRlRhQdP_OuWMpTMnSMkRLa: \\\\\\\ B B&D2 @*S6#G@IPDJhQmSM\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\VGJ]KKbMLeOLiQLlRMvWN\OaOePhQjQgQoTMgQiQkQlRlRlRmRmRmRmRmRmRmRmRmRmRmRmRmRmRnRnRnRnRnRnRnRnRnRnRnRnRl*l+j+g)f)e)d)e)e)e)e)f)i*s0s.oRoRoRoRoRoRoRoRoRoRoRoRoRoRoRoRpRpRpRpRpRpSpSpSqSqSqSqSpSqSpSnRlRIhQpRoRmRiQePaP\OsVMpTMnTMlRMX)\\\\\\\ B%C)D$;J/[8"LBITGJYIKWHK\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\NCJYIK_LKcNLgPLjQLlRMpUMzYN^ObPePhQkQlRfQ- hQjQlRmRnRnRnRnRnRnRnRnRnRnRoRoRoRoRoRoRoRoRoRoRoRoRoRoRoRoRoRoRpRpRpRpy-w-w-y.{-upSpSpSpSpSpSpSpSpSpSpSpSpSpSpSqSqSqSqSqSqSqSqSqSrSrSrSrSrSrSrSsSrSqSoRiQiQqSqSpRmRjQgQcP_O{ZNtVMpUMoTMmSMjQL_9 \\\\\ B "C(D#*A$[<)dI\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\SFJ[JKaMKeOLhPLkRLmSMoTMuWM}[N_ObPePhQkRmRnRkR!-EkRmRnRoRpRpRpSpSpSpSpSpSpSpRpSpSpSpSpSpSpSpSpSpSpSpSpSpSpSpSpSpSqSqSqSqSqSqSqSqSqSqSqSqSqSqSqSqSqSqSrSrSrSrSrSrSrSrSrSrSsSsSsSsStStStStStSuStSsSrSnRoRsSsSrSpRmRjQgQdPaO\OyYNuWMqUMoTMnSMkRLo8 \\\\\ B'D+E$(1 J/jH1NCJUGJYIKUGJ\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\XHK]KKbNLfOLiQLkRMmSMoTMqUMxXN\N_ObPfPhQkQmRoRpSpRhQmRoRpSqSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSsSsSsSsSsSsSsSsSsSsSsSsStStStSuSuSuTuTuTuTuTvTwTvTvTuTtSmRtSuTuStSrSpRmRkQhQePaP^O\N{ZNvXNqUMpTMnSMlRMP%\\\\ B#C*E$.E- .!G$Y:%d<"SFJYIKZIKNCJ\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\PDJZIK_LKdNLgPLjQLlRMnSMpTMqUMuWMyYN\O`OcPfPhQjQmRoRqSrSrSrSmRrSsStStStStStStStStStStStStStStStSsSsSsSsSsSsSsSsSsStStStStStStStStStStStStStStStStSuSuSuTuTvTvTvTvTvTwTwTwTwTxTxTxTyTyUxU\'qSvTwTwTvTuTtTrSoRmRkQhQePbP`O^O\O|ZNxXNtVMpTMoTMmSMjQLh7\\\ B(D"-E*1F, 4#K)pL5PEJWHK[JKXHK:9H\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\UGJ\JKaMLeOLhPLkRLmSMoTMpUMrVMvWNyYN|ZN]O`OcPePhQjQlRnRpSqSsStSuStSsSmR^/ vTvTvTwTwTwTvTvTvTvTvTvTvTvTvTvTvTvTvTvTvTvTvTvTvTvTvTvTvTvTvTvTwTwTwTwTwTwTwTxTxTxTxTxTxTxTyTyTzUzU{U{V|VgQrSwTxTyUyUzVyVxVvUtTqSoSmRjQhQePcPbP`O_O]O}[NyYNuWMpUMoTMmSMkRL}H#\\ &D -E(1F/!2#8 W7"iA&UGJ[JK\JKREJ\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\MCIXIK^KKcNLfOLiQLkRMmSMoTMqUMsVMwXNzYN}[N\O^O`ObPePgQjQkRmRoRqSrStSuSvTvTwTwTuTsSlR_(yTyTyTyTyTyTyTyTyTyTxTxTxTxTxTxTyTyTyTyTyTyTyTyTyTyTyTyTyTyTyTzTzTzU{U{U{U|U|U}V~VWÀYiQrSwTyTzU|V}XZ]]]~[zYwWtUqSnSlRjQgQfPePcPbP`O_O]O~\NzZNvXNqUMoTMnSMlRMiQLg=!\ !C+E'0F.4F7%8%U/lG.SFJZIK]KKZIKB=H\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\REJZJK`LKdNLgPLjQLlRMnSMpTMqUMtWMxXN{ZN~[N]O^O`OaObPdPgQiQkQlRnRpSrSsStTuTvTwTxTyTyTyTyTyTxTvTrSnRhQ|U|U|U|U|U|U|U|U|U|U|U|U|U|U}U}U}U}U}U}U}U~U~U~V~VVŀWƁXa(lRrSvTyTzU|U~VXƂ[Ɇ_΋dӑjԓmԓnБlʌhĆd_{[vWsUpSnRkRiQhQgQfQePdPbPaO_O^O\O|ZNxXNsVMpTMnTMmSMjQLC B)D&/F-3F47G6%>" Y7 kA$YIK]KK^KKSFJ\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\VGJ\KKbMLeOLhPLkRLmSMnTMpTMrUMuWNyYN|ZN\N]O_O`OaPbPcPePfPhQjQlRnRoSqTsTuUvUwVxVyVyUzUzU{U{U{U|U|U|U|U|U{U{U{UzUzTyTyTxTwTvTvTvTvTwTwTwTxTyTzTzU{U{U|U|U}UVŀWǂYɄ\͈_ьdٔlu|쩂ſt명榁ޟ{՗sˎl†d^yZuWqUoSlRkRjQiQhQgQfQePdPcPaP`O^O]O}[NyYNuWMpTMoTMmSMkRLgPL&D#.E,3F46G;'<(D"iB(VGJ]KK`LK[JKB>H\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\NCJYIK^LKcNLfOLiQLkRMmSMoTMqUMsVMvXNzYN}[N\O^O_O`OaPcPdPePfQgQhQiQkRmSoTrUtWwYzZ}\]^^^‚^\ZYX~W~W~V~V~V~V~U~U~U~UUUVVVVVƀVƀVǀWǁWȂXɃZ˅[͇^ЊaӍdؒiܗntz驅~֘vˏmÇf`z[vXrUpToSnSlRkRkRjQiQhQfQePdPcPbP`O_O]O~[NzYNvWNpTMoTMnSMkRMhQLo7 ,2F36G99HC+@ ]8 nA"\JK`ML_LKSFJ\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\SFJ[JK`LKdNLgPLjQLlRMnSMpTMqUMtVMwXNzZN}[N]O^O_OaObPcPdPePfQgQhQiQjRlRmSoUrWvZ{]afŊjˏnГqӕsՖsՖrՖqՔoӒmяjύg͊cˈaɆ^Ȅ\ǂ[ƁYŀXŀWWWVVWŀWƀWǁXȂYɃ[ʅ\͇_ϊaҍeՑhٕmݙqvz}꧀멃몄騃奀ߠ|ٛwӕȑmƉhc~^yZvXtWsVqUpToSnSmRlRkRjQiQhQgQfPePcPbPaO_O^O\N{ZNwXNsVMoTMnSMlRMiQL~I#26G99G?IQ2P+XHK_LLfQOcNLXIK\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\qSyT~VΈ`遲ޜv]qSLG|> g3 S)?*%.hQhQeP`OuWM\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\SFJ[JK`LKdNLgPLjQLlRMnSMoTMqUMsVMwXNzYN}[N\O^O_O`OaPbPdPePfPgQhQiQjRkRlSnTpVsXvZz^bgËmʒsјz؟ޤ㩊譍ꯏ및ꯎ謋娇ं۞|֙wѓq̎lljgÅb_\}Z{XzWyVyUxUxUxTxTxUxUxUyVyVyWzW{X{Y|Z}[}[}\~\~]~]}]|\{\z[yZwYvXtWsVrUpToSnSmRlRkRjQiQhQgQfQePdPcPbP`O_O]O~[NzZNvWNrUMoTMmSMlRMiQLeOLJAIJ(h>!]KKfQOgQN_LKD>I\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\iQtSyT{UYΌeרּ՗u|\Z'LD |> ePoRqSoRmRjQeP^OhPL\\\\\\\\\\\\\\\\\\\\\\\\\\\\\WHJ\KKaMLeOLhPLjQLlRMnSMpTMqUMtVMwXNzZN}[N]O^O_O`ObPcPdPePfQgQhQiQjRkRmSnTqVsXw[{_chČn˒tҙz؟ޥ㩉筍ꯎꯎꮍ竊䧆ߣ۞|՘vГpˎkljfÅb_\}Y{XzWyVxUxUxTxTxTxUxUxUxUyVyVzWzX{Y|Y|Z}[}[}\}\}\}\|\{[zZyZwYvXtWsVrUpToSnSmRlRkRjQiQhQgQfQePdPcPbP`O_O^O\N{ZNwXNsVMoTMnSMlRMiQLfOLJ(V.]KKePNkUQcNLQEJ\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\]OmRqSrStSvTwTxU{WĆbғqךxʏo KrSvTwTvTuTsSqSnRkQgQ`OuWNY,\\\\\\\\\\\\\\\\\\\\\\\\\\NCJYIK^KKbNLfOLhQLkRLmSMoTMpUMrUMuWMxXN{ZN~[N]O^O_OaObPcPdPePfQgQhQiQjRkRmSoTqVtXw[|_diČn˓tҙz؟ޥ㩉笌鮎ꮎ魌檉㧅ߢڝ{՗uϒpˍjƈf…b^\|Y{XzVyVxUxUxTxTxTxUxUxUxUyVyVyWzW{X{Y|Z|Z|[}[}\}\|\|[{[zZxYwXvXtWsVrUpToSnSmRlRkRjQjQiQhQgQfPdPcPbPaO_O^O\O|ZNxXNtVMoTMnSMlRMjQLgPLzG#\JKcOMoXUgPMZIK\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\fPgQgQhQiQkQlRnRpRqSsStS:"r<zYNsSyT|U~WƄ^ˊeˋgƈeaz[tVpSmRkQgQbPzYNkRL\\\\\\\\\\\\\\\\\\\\\\\\\RFJZJK`LKcNLfPLiQLkRMmSMoTMqUMrVMvWNyYN|ZN\N]O^O`OaObPcPdPePfQgQhQiQjRlRmSoUqVtYx\|`diōo˓uҙ{ٟޥ㩉笌鮍鮍謋婈⦄ޡٜzԗtϑoʌjƈe„a^~[|Y{XzVyVxUxUxTxTxTxTxUxUxUxVyVyWzWzX{Y{Y|Z|Z|[|[|[|[{[z[yZxYwXvWtWsVrUpToSnSmRlRkRkRjQiQhQgQfPePdPbPaP`O^O]O}[NyYNuWNqUMnSMlSMkRLhPLcNLbNLpYVlUP`LK>;H\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\jQ`O{ZN^'^'`(e)h)k*o+b(nRyT~UǁXҍdw詅ݟ}Ԙvȍme}_x[y\x[tWqTmRjQgQbP}[NlRM\\\\\\\\\\\\\\\\\\\\\\\\VGJ\JKaMKdNLgPLjQLlRMnSMpTMqUMsVMvXNzYN|[N\O]O_O`OaPbPcPdPePfQgQhQiQjRlSmSoUrWuYx\|`djōo̓uҚ{٠ޥ㩉欋譍譌竊婇᥃ݠ~؛yӖtΑoʌjňe„a^~[|Y{WzVyVxUxUxTxTxTxTxUxUxUxUxVyVyWzXzX{Y{Z{Z|Z|[|[{[{[zZyZxYwXuWtVsVrUpToSnSmRlRkRkRjQiQhQgQfQePdPcPaP`O^O]O~[NzYNvWNrUMnSMmSMkRLiQLeOLoXUu]XdOLKBI\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\:9H\NhQ}\uUsTtTtSqSnRnRnRlRjQiQhQhQgQfQePePhQkRmSpUtXuYsWqUmSjQgQBS%jQL\\\\\\\\\\\\\\\\\\\\\\LBIXHK^KKbMLeOLhPLjRLlSMnSMpTMqUMtVMwXNzYN}[N\O^O_O`OaPbPcPePfPfQgQhQiRkRlSnTpUrWuYy]}`ejŎp̔vӚ{٠ޤ⨉櫋笌笋櫊䨆ंܟ~ךxҕsΐnɌiŇea^~[|Y{WyVyVxUxUxTwTwTwTxTxUxUxUxVyVyWzWzXzY{Y{Z{Z{Z{Z{ZzZyZyYxYvXuWtVsUrUpToSnSmRlRlRkRjQiQhQgQfQePdPcPaP`O_O]O\N{ZNwXNsVMnSMmSMkRMiQLfOL_LKhQMUGJ\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ (6BFP>=DKHMqjktrwf`~kcndqesete{w`v[\N_OcPfPiQjRlSoTqVqVoTlRiQ^`OQ%hPL\\\\\\\\\\\\\\\\\\\\\QEJZIK_LKcNLfOLiQLkRLmSMoTMpUMrUMuWMxXN{ZN~[N]O^O_O`OaPcPdPePfPgQhQiQjRkRlSnTpUrWuZy]}aekƎp̔vӚ{ٟޤ⨈媊櫋櫊婈⦅ߣ۞}֚xѕr͐mȋićda]~[|YzWyVyUxUxUwTwTwTwTwTxUxUxUxUxVyVyWzXzXzYzY{Y{Z{ZzZzZyYxYwXvXuWtVsUrUpToSnSmSmRlRkRjQiQhQgQfQePdPcPbP`O_O]O\O|ZNxXNtVMoTMmSMlRMjQLgPLbML[JK\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\%5 (6$/79CEEKjgkrc_{uf{w_q]O`OcPfQhQjRlRnToTnTkRhQdP]'Q%\\\\\\\\\\\\\\\\\\\\\UGJ[JK`MKdNLgPLiQLkRMmSMoTMqUMrUMuWNxXN{ZN~[N]O^O_O`ObPcPdP['d)gQhQiQjRkRlSnTpUrWvZy]~afkƎp̔vӚ{؟ݤᧇ䩉媊媉䨇᥄ޡڝ|՘wДȑmȊhĆd`]}[|YzWyVxUxUxUwTwTwTwTwTwUwUxUxUxVxVyWyWyXzXzYzYzYzYzYyYyYxYwXvWuWtVsUqUpToSnSmSmRlRkRjQiQhQgQfQePdPcPbPaO_O^O\O|[NxYNtWMpUMmSMlRMjQLgPLcNLA;=\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\#*6+.8;:AHEJmgjd\]pe}xcw^p^OaPePgQiQlRmSnTmSjRgQh*X&M$\\\\\\\\\\\\\\\\\\\C+WHJ]KKaMLdOLgPLjQLlRMnSMoTMqUMrVMvWNyYN|ZN\N]O^O_OaObPcPY&_(c(gQhQiQjRkRlSnTpVsXvZz^~bfkƎp̔vҚ{؟ݣই㩉䩉䩈⧆ःܠ؜{ԗvϓqˎlljgÆc`]}Z{YzWyVxUxUwUwTwTwTwTwTwTwUwUxUxVxVxVyWyWyXyXyYzYyYyYyYxYwXwXvWuVtVrUqUpToSnSmSmRlRkRjQiQhQgQfQePdPcPbPaO_O^O\O}[NyYNuWNqUMmSMlRMjQLhPLdNL\1\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\+.775;ICFphhztre}yavZ]OaPePgQiQkRlSnTlSiQq.b*S%zG#\\\\\\\\\\\\\\\\\\MCJXHK^KKbMLeOLhPLjRLlSMnSMpTMqUMsVMvWNyYN|ZN\N]O^O`OaObPU&\'a(g)r/hQiQjRkRmSnTpVsXv[z^~bfkƎp̔vҙ{מܣআ⨈㨈㨇ᦅޣ۟~כyӖuΒpʍkƉg…c_]}Z{XzWyVxUxUwTwTwTwTwTwTwTwUwUwUxUxVxVxWyWyWyXyXyXyYyYxXxXwXvWuWtVsVrUqTpToSnSmRmRlRkRjQiQhQgQfQePdPcPbPaO`O^O]O}[NzYNvWNrUMmSMlRMjQLhQLeOL_LK\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\,)/ZTVXONuqod}ybs]OaPePgQiQkRlRlSkRhQg*\(Q%`LK\\\\\\\\\\\\\\\\\ B B_LKcNLfOLiQLkRLmSMoTMpTMrUMtVMwXNzYN}[N\O]O_O`OaOQ%Y&^'b(i*{8hQiQjRkRmSnTqVsXv[z^~bfkƎp̔vҙ{מۢߥᧇ⧇ᦆऄݢڞ}֚xҕt͑oɌjňf…b_\}Z{XzWyVxUxUwTwTwTwTwTwTwTwTwUwUwUxVxVxVxWxWyWyXyXxXxXxXwXwWvWuWtVsUrUqTpToSnSmRmRlRkRjQiQhQgQgQfPdPcPbPaP`O^O]O~[N{ZNvXNrVMnSMlRMjRLhQLeOLaML+O+O\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\HFLXQRTJH~pmla}zcttTaPdPgQiQjRlRlSjR|:e*V&N$\\\\\\\\\\\\\\\\\ B B`LKdNLgPLiQLkRMmSMoTMpUMrUMtVMwXNzYN}[N\O]O_O`OaPW&['_(d)l,݃@t.iQjRkRmSoUqVsXw[z^bgkƎp̔uљz֝~ڡޤॆআॅޣܠ؝{ՙwєs̐nȌjňfb_~\|Z{XyWyVxUwUwTwTwTwTwTwTwTwTwUwUwUwUwVxVxVxWxWxWxWxXxXwXwWvWuWuVtVsUrUqTpToSnSmRlRlRkRjQiQhQhQgQfPdPcPbPaP`O^O]O~[N{ZNwXNsVMoTMlRMjRLiQLfOLbML+O+O+O+O\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\6./fZXeVRHAIZIKiQLuWMtUaOdPgQjQkRlRkRiQn/b,R%rC"\\\\\\\\\\\\"Fx"Fx!Fx!Fx B B BdNLgPLjQLlRMmSMoTMqUMrUMtWMwXNzZN}[N\O^O_O`OS%X&\'a(g+s2{9j*iQjRkSmSoUqVsXw[z^bgkƎp˓uИy՜}٠ܢޤߤޣݡڟ~כzӗvϓrˏmNjićea^~\|ZzXyWxVxUwUwTwTwTwTwTwTwTwTwTwUwUwUwUwVwVxVxWxWwWwWwWwWvWvWuVtVsUsUrTqTpToSnSmRlRlRkRjQiQhQgQgQfPePcPbPaP`O_O]O~\N{ZNxXNsVMoTMlRMjRLiQLfPLbNL +O+O+P+P+P\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\@89dWT@IIAI\JKlRMyYN^OcPgQiQkRlRkRiRt3d-S%I#\\\:^:^:^:^:^:^:^:^:^"Fx"Fx B B B BeOLhPLjRLlSMnSMpTMqUMrVMuWMxXN{ZN~[N]O^O_OS%W&['^(k2i+{:gQhQiQjRkSmToUqVtYw[{_bfkčoʒtϖxӚ|ם~٠ۡۡ۠ٞ~כ{ԘwДs̐oɌkʼng…c`]}[{YzXyVxVwUwUwTwTvTvTvTvTvTvTvTvTvUvUvUwUwUwVwVwVwVvVvVvVuVuVtVtUsUrUqTpTpSoSnSmRlRlRkRjQiQhQgQgQfPePdPbPaP`O_O]O\N|ZNxYNtWMpTMlRMjRLiQLgPLcNL_LK+P+P+P,P,P,P,P,PNr\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\]QNl\VG@IMCI_LKoTM|ZN`OdPgQjQkRlRkRhQh*^,P%X3:_:_:_:_:_:_:_:_:^:^:^:^"Fx B B B BfOLiQLkRLmSMnTMpTMqUMrVMuWNxYN{ZN~[N]O^OP%U&X&['`)n4n/j*gQhQiQjRkSmToUqWtYw[z^~bfjČoɑsΕwҙ{՜}؞ٟڟٞ~ל|՚yҗvϓrˏnNjjĈfc`]}[{YzWxVxUwUwTwTvTvTvTvTvTvTvTvTvTvTvUvUvUvUvUvVvVvVvVvVuVuVuVtUsUrUrTqTpToSoSnSmRlRkRkRjQiQhQgQgQfPePdPbPaP`O_O]O\N|ZNyYNuWMpUMlRMjQLiQLgPLdNL_LK,P,P,P,P,PNrNrNrNrNrNr\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\aSOD>IJAIQEJbNLrUM~[NaOePhQjQkRlRjRs0e,T&K$;_;_;_;_;_;_;_:_:_:_:_:_:_ B B B BgPLiQLkRLmSMoTMpTMqUMsVMuWNxYN{ZN~[N]OM$S%V&Y&\'e-j/z:fQgQhQiRjRkSmToUqWtYw[z^~bfjÌnȐr͔vјyԛ|֝~מ~؞~ם}՛{ӘxЕt͒qʎmƊiÇeb_~\|Z{YyWxVxUwUwTvTvTvTvTvTvTvTvTvTvTvTvTvUvUvUvUvUvUvVvVuVuVuVtUsUsUrUqTqTpSoSnSnRmRlRkRkRjQiQhQgQgQfPePdPbPaP`O_O]O\O|ZNyYNuWMqUMlSMjQLhQLfPLdNL_LK,P,PNrNrNrNrNrNrNrNsNsNsNs\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\dUOG@IMCITFJeOLtWM]ObPfPiQkRlRkRiQj,c/P%[JK;_;_;_;_;_;_;_;_;_;_;_;_ B B B BgPLiQLkRMmSMoTMpTMqUMsVMvWNyYN{ZN~[N|H#Q%T%W&Z']'m5f*v5fQgQhQiRjRkSmToUqWsYv[z^~bei‹nǏq˓uϖxҙzԛ|֜}֜|՛{ԙyіvϓs̐oȍlʼnh†ea_~\|ZzXyWxVwUwUvTvTvTvTvTvTvTvTvTvTvTvTvTvTvUvUvUuUuUuUuUuUtUtUtUsUrUrTqTpTpSoSnSmRmRlRkRjRjQiQhQgQfQfPePcPbPaP`O_O^O\O|ZNyYNuWNqUMmSMjQLhQLfPLdNL`LKNrNrNrNrNrNsNsNsNsOsOsOsOsOsOs\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\2#TB3REJVGJ`LKpTM}[NaOePiQkRlRlRhQe)^.P%^8 #Gy#Gy#Gy#Gy#Gy#Gy#Gy#Gy * B B B B BjQLlRMnSMoTMpUMrUMsVMxF#M$Q%S%U&W&Y&['a+s;g+dPePfQgQhQiQjRkSlSnUpVrXuZx]{_~beikÌnƎpȐrʑs˒sˑrʐqɏoǍmŋkÈheb`~^|[{ZyXxWwVvUvUvTuTuTuTuTuTuTuTuTuTuTtTtTtTtTtTtTtTtTsTsTsTsTrTrTrTqTqSpSpSoSnSnRmRlRlRkRjQjQiQhQgQgQfPePdPcPbPaO`O^O]O\N|ZNxXNuWMqUMmSMhPLgPLeOLcNL`LKZIK,P,P,QOsOsOtOtOtOtPtPtPtPtPt-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\vvvvvvvww=a=a=a#Gy#Gy#Gy#Gy#Gy#Gy#Gy#GymYPODJUGJXIKeOLtWM]OcPgQjQlRmRkRp.g0T&N$]8 #Gy#Gy#Gy#Gy#Gy#Gy#Gy * B B B B BjQLlRMnSMoTMpUMrUMv>L$P%R%T%V&X&Z'\'f0m5q3dPePfQgQgQhQjRkSlSnTpVrXtZw\z_}adgjlČnƎpǏqȏqȏpǎoƍmŋkÉigda_}]|[zYyXxWwVvUvUuTuTuTuTuTuTuSuStStStStStTtTtTtTtTsTsTsTsTsTrTrTrTqTqSpSpSoSoSnSmRmRlRlRkRjQjQiQhQgQfQfPePdPcPbPaO`O^O]O~\N{ZNxXNuWMqUMiQLgPLfOLeOLbNL_LKZIK,Q,Q,Q,Q,QOtPtPtPtPtPt-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\vvvvwwwwwwww=a=a=a=a=a#Gz#Gz#Gz#Gz#Gz#Gz#GzgUOS=2RFJWHJ[JKlRMzYN`OePiQkRmRlRiQh*h4R%N$^9 [JK#Gy#Gy#Gy#Gy#Gy * B B B B BjQLlRMnSMoTMpUMI#L$O$Q%S%U&W&X&Z'](l5f,t5dPePfPfQgQhQiRkRlSmToVqWtYv[y^|acfhklÌnōnōoōnŌmċk‰igec`~^|\{ZyYxWwVvUvUuTuTuTuTuTtStStStStStStStStStStSsSsTsTsTsTrTrTrTrSqSqSpSpSoSoSnSnRmRmRlRkRkRjQiQiQhQgQfQePePdPcPbP`O_O^O]O~[N{ZNxXNtVMqUMhPLgPLfOLdNLbML_LKbE6,Q,Q,Q,Q-Q-Q-QPt-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\@dwwwwwwwwwwwwww=a=a=a=a=a=a=a#Hz#Gz#Gz#Gz#Gz#Gz#GzmYPPDJUGJYIKbMLqUM\NbPfQjQlRmRlRp,e+\+R%N$b; ]8 [7 XHKO+N1L/L/L/K/K/ eb>b>b>b>b>b>b>b=b=b=b=b=b=b=b=bYEUGJYIK_LKnSM|ZN`OePiQlRmRmRiQg*j4W'R%Q%h>!g=!f=!db>b>b>b>b>b>b$Hz$Hz$Hz$Hz$Hz>b>b>b>b>bgVOS=2RFJWHK[JKeOLsVM]ObPgQjQlRmRlRr/g*h2U&S%R%Q%Q%P%[']'`(b(d)f)g)i*j*I#Z'Z'Z'Z'Z'['['\']'_)d,d)q3bPcPdPePfQfQgQhQiRkSlSmUoVqWsYu[x]z^|`~bdeffffedba~_}^{\zZyYwXwWvVuUuUtTtTtTtStStSsSsSsSsSsSsSsSsSsSsSrSrSrSrSrSqSqSqSpSpSpSoSoSoRnRnRmRmRlRkRkRjQjQiQhQhQgQfQePdPcPcPbP`O_O^O]O\N|ZNyYNuWNrUMnSMjQLdNLcNLaMK_LK[JK`D6PtPtPtPtPtPuPuPuPuQuQuQuQuQuQu-Q-Q-Q-R-R-R-R-R-R-R-R-R.R.RRvRvRv~~~~\\\\\\\\\\\\\\\\\\\\\\\\\\\@e@e@e@eAeAeAeAeAeAeAeAeAeAeAexxxxxxxyy>b>b>b$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz>b>b>b>b>bYDb>b>b>bQ@:R<2fL@WHJZJKaMKoTM|ZN`OePiQlRmRmRjRo-i-h0`)]']'`(b(d)f)h)j*k*m*n+p+q+r,]']']'^'_(_(`(`(b)c)i.`OaPbPcPdPePfQgQhQiRjRkSlTnUoVqWsYuZw\y]{_|`}a~bbbba~`}_|^{]z[yZxYwXvWuVuUtUtTtTsTsSsSsSsSsSsSsSsSsSrSrSrSrSrSrSrSqSqSqSqSpSpSpSoSoRoRnRnRmRmRlRlRkRkRjQjQiQhQhQgQfQePdPdPcPbPaO`O_O]O\O}[NzYNwXNtVMpTMlRMhPLcNLaMK_LK]KKbR]C5PuPuPuQuQuQuQuQuQuQuQuQuQuQuQuQuQvQvQv-R-R.R.R.RRvRvRvRvRvRvRv\\\\\\\\\\\\\\\\\\\\\\AeAeAeAeAeAeAeAeAeAeAeAeAeAeAeAeAeyyyAfAfAf$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz>b>b>b>bWD3TFJXHK[JKfOLsVM]ObPgQjQlRmRmRkRm,i,j/d+c)c(e)f)h*j*l*n+o+q+r+s,t,K$^(_(_(`(a(a)b)d*f+m1`OaPbPcPdPePfQfQgQhRiRkSlTmToVpWrXtYv[w\y]z^{_|`}`}`}`}_|^{^{\z[yZxYwXvWuVtUtUtTsTsTsSsSsSsSsSrSrSrSrSrSrSrSrSrSrSqSqSqSqSqSpSpSpSoSoRoRnRnRmRmRmRlRlRkRjQjQiQiQhQgQfQfPePdPcPbPaP`O_O^O]O\N|ZNyYNvWNsVMoTMkRLgPLbML`LK^KK\JK~aR[B5PuQuQuQuQuQuQuQuQuQuQuQuQuQuQvQvQvRvRvRvRvRvRvRvRvRvRvRvRvRv\\\\\\\\\\\\\\\\\\\\AeAeAeAeAeAeAeAeAeAeAeAeAeAfAfAfyAfAfAfAfAfBf$H{$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz>c>c>b>bO?:[E|aRZA5-QQuQuQuQuQuQuQuQuQuQuQvQvQvQvRvRvRvRv.R.R.R.RRvRvRvRvRvRw\\\\\\\\\\\\\\\\\\AeAeAeAeAeAeAeAfAfAfAfAfyyyzzzBfBfBfBfBf$H{$H{$H{$H{$H{$H{$H{$H{$H{$Hz$Hz$Hz$Hz$Hz$Hz$Hz$Hz>c>c>c>cVC^C6W@5-Q-QQuQuQuQuQuQuQvQvQvQvRvRvRvRv.R.R.R.R.R.R.R.R.RRvRwRwRwրրրրրրրրրրր\\\\\\\\\\\\\\\\AfAfAfAfAfAfAfAfzzzzzzzzzzzBfBfBfBf$I{$I{$I{$H{$H{$H{$H{$H{$H{$H{$H{$H{$H{$H{$H{$H{$Hz$Hz$Hz$Hz$Hz YE\C6T>4-Q-Q-Q-RQuQuQvQvQvQvRvRvRv.R.R.R.R.R.R.R.R.R.R.R.R.RRwSwրրրրրրրրրրրրրրրրրEiEiEi\\\\\\\\\\\\\\AfAfBfBfBfzzzzzzzzzzzzzzzBfBfBf$I{$I{$I{$I{$I{$I{$I{$I{$I{$I{$I{$H{$H{$H{$H{?c?c?c?c$H{$H{$H{SB;R<2zbVUGJXIK[JK[JKuWN\OaPfPiQlRmRnSnSpT99w2w0v/v.x/z0z0|1~235688m4o7q8u;s9s8j0]O^O_O`OaPbPcPdPePfQfQgQhRiRjSkSlTnUoVpVqWrXsYtYuYuZuZvZvYuYuXuXtWtVsVsUsUrTrTrTrSqSqSqSqSqSqSqSqSqSqSqSqSqSqSpSpSpSpRpRoRoRoRoRnRnRnRmRmRmRlRlRkRkRjQjQiQiQhQgQgQfQePePdPcPbPaP`O_O^O]O\O}[NzYNwXNtVMqUMnSMiQLeOL`LK]KKmP?kN?|aSZA5P<4-R-R-R-R-R-RQvRvRvRvRv.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R׀׀׀׀׀׀׀׀׀׀׀׀׀׀׀EiEiEiEiEiEiEi\\\\\\\\\\\\Bfzzzzzzzzzzzzz{{{{{{BfBfBf%I{$I{$I{$I{$I{$I{$I{$I{$I{$I{$I{?c?c?c?c?c?c?c?c?c$H{$H{$H{jXP^H=}dXUGJXHKZIKkRLwXN]ObPfQiQkRmRnSpTqUrU;>?<9;==>ADHKEr:t;t;t`KA-R-R-R.R.R.R.RRvRvRvRv.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.REiEiEiEiEiEiׁׁׁׁׁׁEiEiEiEiEiEiEiEiEiEiEiEiEiEiEiEi\\\\\\\\zz{{{{{{{{{{{{{{{{{{{|CgCg%I{%I{%I{@d@d@d@d@d@d@d@d@d@d@d@d?d?d?d?d?d?d$I{$I{dUPYEXG@-R.R.R.RRvRvRvRvRvRvRvRv.R.R.R.R.R.R.R.R.R.R.R.R.R.R.SEiEiEiEjEjEjEjEjׁׁEjEjEjEjEjEjEjEjEjEjEjEjEjEjEjEjEjEiEiEi\\\\\\{{{{{{{{{{{{{{|||||||||Cg@d@d@d@d@d@d@d@d@d@d@d@d@d@d@d@d@d@d@d@d@d?d$I{$I{RA;P<3zcXnVIuh~pdNLpUMwzZvSePgQjQlRmRoSpTuVvWxY|\_ÆdƉgȊhʌi̎kΏlRFk4g1d-b+_(Z'}[N\O]O^O_O`OaPbPcPcPdPeQfQgQgQhRiRjRkSkSlTmTnTnUoUoUpUpUpUpUpUpTpTpTpTpSpSoSoSoSoSoSoSoRoRoRoRoRoRoRoRoRoRoRoRoRnRnRnRnRnRmRmRmRlRlRlRkRkRkQjQjQiQiQhQhQgQgQfPePePdPcPbPbPaO`O_O^O]O~\N|[NzYNwXNtVMpUMpYoXzWBuUBgVlP@jO@|bUx`TcMB3!.RRvRvRvRvRvRvRvRvRvRvRwRwRw.R.R.R.R.R.R.R.R.R.S.S.SEjEjEjEjEjEjEjEjEj؁EjEjEjEjEjEjEjEjEjEjEjEjEjEjEjEjEjEjEjEjEjEjEj\\\\Bg{{{{{{{||||||||||||CgCgCgCg|@d@d@d@d@d@d@d@d@d@d@d@d@d@d@d@d@d@d@d@d@d@d%I{;0/SB;R=4fODpXLxkrvbzx{[ÏldPgQiQjQlRnRpSqTrTtUwW{Z}\|\}\~]]}+~6d.a+_)^(\'zYN|ZN~\N]O^O_O_O`OaPbPcPdPdPeQfQgQgQhRiRjRjSkSlSlTmTmTnTnTnToToToToToToSoSoSoSoSoSoSoRoRoRoRoRoRoRoRoRoRoRoRnRnRnRnRnRnRmRmRmRmRlRlRlRlRkRkQjQjQjQiQiQhQhQgQgQfQePePdPcPbPbPaO`O_O^O]O\N}[NzZNxXNuWMrUMrZpY|XCxVCsTBmQAkOA~cVzaU`I>\IARvRvRvRvRvRvRvRvRvRvRwRwRwSwSwSwSw.R.R.R.R.R.S.S.S.SFjFjFjFjFjFjFjFj؂؂؂؂؂FjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFj\\Bg{||||||||||||||CgCgCgCgCgCgCgCg}@e@e@e@e@e@e@d@d@d@d@d@d@d@d@d@d@d@d@d@d@d@d@d%I{<1/J82^I@gQFqYNxlsvc{dy{\wUčiePgQhQkQmRmRnRoSpSrTtUtUtUtUtUtUt.L&](['Z'Y&xYN{ZN}[N\N]O^O_O`OaOaPbPcPdPePeQfQgQgQhRiRiRjRkSkSlSlSmSmSmSnSnSnSnSnSnSnSnSnSnRnRnRnRnRnRnRnRnRnRnRnRnRnRnRnRnRnRmRmRmRmRmRlRlRlRlRkRkRkQjQjQiQiQiQhQhQgQfQfPePePdPcPbPbPaO`O_O^O]O\O}[N{ZNxYNvWNsVMs[rZ~ZDnYkYqSBkPAiOA|cVbK?\G>NB?RvRvRvRvRvRvRvRvRwRwRwSwSwSwSwSwSwSwSw.S.S.S.S.S.SFjFjFjFjFjFj؂؂؂؂؂؂؂؂؂؂FjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjCgCg|||||||||||CgCgCgCgCgCgCgCgCgCgCgCg}AeAeAe@e@e@e@e@e@e@e@e@d@d@d@d@d@d@d@d@d@d%I{@d@d<1/H72\I@ePGpYNxmtvc{ezu‘pwUuQePgQiQjQjQlRmRnRnRoRoRoRoRoRgb; Z'Y&W&S%vXNyYN{ZN~[N\O]O^O_O`OaOaPbPcPdPdPeQfQgQgQhQiRiRjRjRkSkSlSlSlSlSmSmSmSmSmSmRmRmRmRmRmRnRnRnRnRnRnRnRnRnRnRmRmRmRmRmRmRmRmRlRlRlRlRkRkRkQjQjQjQiQiQhQhQgQgQfQfPePdPdPcPbPbPaO`O_O^O]O\O}[N{ZNyYNvXNtVMu\]E[EoZmZkYnRBjOB}cVdL@`I?XGARvRvRvRvRvRvRwRwRwRwSwSwSwSwSwSwSwSwSwSwSw.S.S.S.S/SFjFjFjFjققققققققققققققFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjقCgCg|||||||CgCgCgCgCgCgCgCgCgCgCgCgChChChChCh}AeAeAeAeAeAeAeAeAe@e@e@e@e@e@e@e@d%I{%I{%I{%I{%I{@d@d<10F61o]Vye]oexmuud{e}d|atpÏluQdPePfQgQiQjQjQjQjQjQkQkQkQ_9 X&V&T%rUMuWMwXNzYN|ZN~[N\O]O^O_O`OaObPbPcPdPdPeQfQfQgQhQhRiRiRjRjRkRkRkRlRlRlRlRlRlRlRmRmRmRmRmRmRmRmRmRmRmRmRmRmRmRmRmRmRmRlRlRlRlRlRkRkRkRkQjQjQjQiQiQiQhQhQgQgQfQfPePdPdPcPbPbPaO`O_O^O]O\O~[N{ZNyYNwXNtVMrUM^F]Fq\o[lZqTDfX}dWeMAbK@O=6NB@RvRvRvRvRwRwRwRwSwSwSwSwSwSwSwSwSwSwSwSwSxSxSx/S/SFjFjFjككككككككككككككككككFjFjFjFjFjFjFjFjFjFjFjFjFjFjFjكككCgCgCg}}}CgCgCgCgCgCgCgCgChChChChChChChChChChDhDhDh~AeAeAeAeAeAeAeAeAeAeAeAeAe%I{%I{%I{%I{%I{%I{%I{%I{%I{@d@dE:9D61m\Vwe]lXOuaXk_z||e|c|`z]yXnÏlĎkĎidPePfPfPfPfPfPfPfP[7 U&T%P%pTMsVMuWMxXNzYN|ZN~[N\O]O^O_O`OaObPbPcPdPdPePeQfQgQgQhQhQiRiRjRjRjRkRkRkRkRkRlRlRlRlRlRlRlRlRlRlRlRlRlRlRlRlRlRlRlRlRlRlRlRkRkRkRkQkQjQjQjQiQiQiQhQhQgQgQfQfPePePdPdPcPbPbPaO`O_O^O]O\O~[N|ZNyYNwXNuWMrUM`G^Gr]|ZFxXFtVEgY~eY{cXbLA[H?REA.R.RRvRwRwRwSwSwSwSwSwSwSwSwSwSwSwSwSxSxSxSxTxTxTxككككككككككككككككككككككككFjFjFjFjFjFjFjFjFjFjFjكككككCgCg}}CgCgCgCgChChChChChChChChChDhDhDhDhDhDhDhDhDhDh~AeAeAeAeAeAeAeAeAe%I|%I|%I|%I{%I{%I{%I{%I{%I{%I{%I{%I{%I{%I{@e@eB99B51k[Vud]iWPr_Wye]y|}|e|cw{^z\yZpxWwUwUwUwUÎlÎlŽlŽlkD(S%P%nSMoTMqUMsVMvWNxXNzYN|ZN~[N\O]O^O_O`OaOaPbPcPcPdPePeQfQfQgQgQhQhQiQiRiRjRjRjRjRkRkRkRkRkRkRkRlRlRlRlRlRlRlRlRlRlRlRlRkRkRkRkRkQkQkQjQjQjQjQiQiQiQhQhQgQgQgQfQfPePePdPcPcPbPaPaO`O_O^O]O\O~[N|ZNyYNwXNuWMrUMw_v_t^~\GzYGvWFj[fZ|dYybX\I@VGB5/2.R.R.R.RSwSwSwSwSwSwSwSwSwSwSwSwSxSxSxSxTxTxTxTxFkFkFkFkڃڃڃڃڃڃڃڃڃڃڃڃڃڃڃڃڃڃڃڃڃڃFkFkFkFkFkFkFkFkڃڃڃڃڃڃڃ}}}}ChChChChChChChDhDhDhDhDhDhDhDhDhDhDhDhDhDhDhDhDh~AeAeAeAeAe%J|%I|%I|%I|%I|%I|%I|%I|%I|%I|%I|%I|%I{%I{%I{%I{%I{%I{@e@e<68?31gYVpa\bRMjYTq`Zj`z}}|{zxwz^tsssrrrrh2O$L$mSMnSMnTMoTMtVMvWNxXNzYN|ZN~[N\O]O^O_O`OaOaPbPcPcPdPdPePeQfQfQgQgQhQhQhQiQiQiQiQjQjQjQjQjQkQkQkQkRkRkRkRkRkRkRkRkRkQkQkQkQjQjQjQjQjQjQiQiQiQhQhQhQgQgQgQfQfPePePdPdPcPbPbPaP`O`O_O^O]O\O~[N|ZNyYNwXNtWMz`y`w`u_]I|[HwXGl\i[}eZycYr_WjZU;23.R.R.R.R.R.R.RSwSwSwSwSwSwSwSwSxSxSxTxTxTxTx/S/SGkGkGkGkGkGkGkڃڃڃڃڃڃڃڃڃڃڃڃڃڃڃڃڃڃڃڃڃڃGkGkGkڃڃڃڃڃڃڃڃڃڃ}}}}~DhDhDhDhDhDhDhDhDhDhDhDhDhDhDhDhDhDhDhDhDhDhDhDhAf%J|%J|%J|%J|%J|%J|%J|%J|%J|%I|%I|%I|%I|%I|%I|%I|%I|%I|%I|%I|%I{%I{AeAeAe?89H=:?YUY`QGfVLudXjeitlm{po|qp}rp~rpsqsqtqr_=1+xJ)o[~[F\G^H_I`IkRLlRMnSMpTMrVMuWMwXNyYN{ZN}[N~\N\O]O^O_O_O`O`OaPbPbPcPcPcPdPdPePePePfPfQfQfQgQgQgQgQgQgQgQhQhQhQhQhQhQhQhQhQgQgQgQgQgQgQfQfQfQfPePePePdPdPdPcPcPbPbPaPaO`O_O_O^O]O\O~\N}[N{ZNyYNwXNuWMiOhOgOeOzeydwdtcrbtYKjTIaOG[KFj]Y^UU?;@.R.R.S.S.S.S.S.S/S/S/S/S/S/S/S/S/S/S/S/S/S/S/SGkGkGkGkGkGkGkGkGkGkGkGkGkGkGkGkGkGkۅۅۅۅۅۅۅۅۅۅGlGlGlGlGlGlGlGlGlGlGlGlGlۅۅۅۅۅDhDhDhDhDiDiDiDiDiրրրրրրրրրրրEiEi&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|%J|%J|%J|%J|%J|%J|AfAeAe%J|%J|%J|%I|%I|%I|%I|#-#%.()1MEAQIEUMI]SL]TM=4.1+(=.#6,&5( 1%"lYn[p\r]]H_I`JwaybkRLmSMpTMrUMtVMvWNxXNzYN|ZN}[N\N]O]O^O_O_O`OaOaPaPbPbPcPcPdPdPdPePePePePfPfPfQfQfQfQfQgQgQgQgQgQgQgQgQfQfQfQfQfQfPfPePePePePdPdPdPcPcPcPbPbPaPaO`O_O_O^O]O]O\O}[N|ZNzYNxXNvWNggghPfP|fzfxevdscsYLiTK_NHYKFh\Z]UV=;@.R.S.S.S.S.S.S/S/S/S/S/S/S/STxTxTxTxTx/S/S/S/SGlGlGlGlGlGlGlGlGlGlGlGlGlGlGlGlGlGlGlGlۅۅۅۅۅۅGlGlGlGlGlGlGlGlGlGlGlGlGlGlGlGlGlGlۅۅۅDiDiDiDiDiDiրրրրրրրրրրրրրրր׀׀׀Ei&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|BfBfAfAfAfAfAf%J|%J|%J|%J|%J|%J|%I|%I|%I|, +,!.! "`E6iYlZo\q]s^^Jvawbyczd{e}foTMqUMsVMuWNwXNyYN{ZN|ZN~[N\O]O]O^O_O_O`O`OaOaPbPbPcPcPcPdPdPdPdPePePePePePePePePfPfPfPfPfPfPfPePePePePePePePdPdPdPdPcPcPcPbPbPaPaO`O`O_O_O^O]O]O\O~[N|[N{ZNyYNwXNiiiihhRfQdQbPwfx]Opdkbtd_m`]OEDG?A;:@.S.S.S.S.S/S/S/S/S/S/S/S/STxTxTxTxTxTxTxTxTy/SGlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHl܅܅HlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHl܅Eiրրրրրրրրրրրր׀׀׀׀׀׀BgBgBgBgBg&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|BfBfBfBfBfBfBfBfBfAfAf%J|%J|%J|%J|%J|%J|%J|%J|%J|%J|%I|%I|%I|%I|%I|%I| +,YA5jPBpSDl[o]q^t`_Kwbycze{f}ghilSrVMtWMvWNxXNyYN{ZN|[N~[N\O]O]O^O_O_O`O`O`OaPaPbPbPbPcPcPcPcPdPdPdPdPdPdPdPdPePePePePePdPdPdPdPdPdPdPcPcPcPcPbPbPbPaPaO`O`O`O_O^O^O]O]O\O~[N|[N{ZNyYNxXNjjjjjjhSgSeRcR|`Qsfoe}jcrd`k_]LCDC=@,,3(4F(4F.S.S/S/S/S/S/S/S/STxTxTxTxTxTxTxTxTxTyTyTyHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlChChրրրրEiEiEiրրրրրր׀׀׀CgCgCgCgCgCgCgCgCgCgCgCgBgBg&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|BfBfBfBfBfBfBfBfBfBfBfBfBfBfBf&J|%J|%J|%J|%J|%J|%J|%J|%J|%J|%J|%J|%I|%I|%I|%I|%I|#5H71O;3V?4iOBoSDsVFo]{[I^K`LbNdO{f}g~hjkTmUoVqWrWwXNxXNzYN{ZN}[N~[N\O]O]O^O^O_O_O`O`O`OaOaPaPbPbPbPbPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPbPbPbPbPaPaPaO`O`O_O_O_O^O^O]O\O\N~[N|ZN{ZNyYNoToToTnTllljUiThTfTcSvirgnfyidqdah^^HBD?<@)+3OZkMYk(5F(5F(5F/S/S/S/S/STxTxTxTxTxTxTxTxTyTyTyTyUy܆܆܆HlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHl܆܆܆܆HlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlDhDhDhCh&K}&K}&K}&K}&K}&K}ChChCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCg&J|&J|&J|&J|&J|&J|BgBgBgBfBfBfBfBfBfBfBfBfBfBfBfBfBfBfBf&J|&J|&J|&J|%J|%J|%J|%J|%J|%J|%J|%J|%J|%J|%J|%I|%I|A99N?;L:2T>4gNBlRDk\n^z[J~^LaNcOdPfQgRhTjUlVnWpXrXsYqqrrrsz[z[z[{[{[{ZœrŒqŒqŒpŒpőoyVxVxUwTwTaPbPbPbPbPbPbPbPbPbPbPbPbPbPaPaPaPaPaOaO`O`O`O_O_O^O^O^O]O]O\O~\N}[N|ZNzYNpTpUpUpUoVoVnVmVlVkVjVhVfU~cUujqh~mfugdkaad\^E@D98?$(2minffm^blV^lMYk(5F(5F/STxTxTxTxTxTxTxTxTxTyTyTyUyUy܆܆܆܆܆܆܆HlHlHlHlHlHlHlHlHlHlHlHlHlHlHl݆݆݆݆݆݆݆݆݆HlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHl'K}'K}'K}'K}'K}'K}'K}'K}'K}&K}&K}ChChChChChChChCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCg&J|CgCgCgCgCgBgBgBgBgBgBgBfBfBfBfBfBfBfBfBfBfBfBfBf&J|&J|&J|&J|&J|&J|&J|%J|%J|%J|%J|%J|%J|%J|AeAe;GY<68I=:I82Q=4XA6~fZj\m^p`|]L`NcPeQgSjlmnoXqYrZt[rsstttz]{]{]{\{\{\{[ēsērĒrĒqĒpđpyWĐoÐnÏmÏlŽlŽkkaOaOaOaOaOaOaO`O`O`O`O`O`O_O_O_O_O^O^O]O]O]O\O~\N}[N|ZNllmqVqVqVpWpWoWnnnnn~neWxltkpiykfodcf_`JDG@>C*,5$1MYktr~tstmolinadmX_lNZkMZkTxTxTxTxTxTxTxTyTyTyUyUyUy݆݆݆݆݆݆݆݆݆HlHlHmHmHmHmHmHmHmHmHmHm݆݆݇݇݇݇݇݇݇݇݇݇HmHmHmHmHmHmHmHmHmHmHmHmHmHmHmHmHmHmHmHm'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}DhDhDhDhChChChChChChChCgCgCgCgCgCgCgCgCgCgCg&J}&J}&J}CgCgCgCgCgCgCgCgCgCgBgBgBgBgBgBgBfBfBfBfBfBfBfBfBf&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|AfAfAfAf;GY;GY;GY1'!D:9N?;N;3]I?zdYh[l^oascuebQdRfTlmnopqrsv]w]uuuuv{^{^|^|]|]{\{\{[{[zZzZyYyXxXonnmmuTuStStStRsRsQ_O_O_O^O^O^O^O^O]O]O]OrSrSrSkllmmmnnqWqXqXooppppp}o{cXv`Vp]U}nishfhaba\_DAF::B$)4MYkMYkMYktctq\QPPIKFDI;>H/8GMZkTxTxTxTxTyTyTyUyUyUy݆݆݇݇݇݇݇݇݇݇݇݇݇HmHmHmImImImImIm݇݇݇݇݇݇݇݇݇݇݇݇݇݇݇݇ImImImImImImImImImImImImImImImImImIm'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}DhDhDhDhDhDhDhDhDhChChChChChChChChCgCg&K}&K}&K}&K}&J}&J}CgCgCgCgCgCgCgCgCgCgCgCgCgCgBgBgBgBgBgBgBfBfBfBfBfBf&J|&J|&J|&J|&J|&J|BfBfBfBfBfBf;HY;HY;GY;GY;GY;GY;,#I=:H82YF?^JA|e[j]n`qctewgyi|k~lnopqssu]v^w^x_y_z_z_{_wwvvv“u“u“t{\{\z[zZyZyYxXpowWvVvVuUuUuTtTlkkkkkksTrTrTrTrTrUrUrVnnnoooppqYqqrrrrqgZ{dYvaXp^WiYU`TRVNOb]aEBH<+[NL^SQWNNKFJ?AI2:HTxTyTyTyUyUyUyUyUy݇݇݇݇݇݇݇݇݇݇݇݇݇݇݇݇ImImImIm݇݇݇݇އއއއއއއއއއއއއއއއImImImImImImImImImImImImImImImIm'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}DhDhDhDhDhDhDhDhDhDhDhDhDhDhCh&K}&K}&K}&K}&K}&K}&K}&K}&K}&K}CgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgBgBgBgBgBgBgBfBfBf&J|&J|BfBfBfBfBfBfBfBfBf;HY;HY;HY;HY;HY;HY;GY3("D::B41RB=YG@wcZ}g\k_nbrdug}aRdTgViXkYqrstp^q^w`x`y`z`za{axxwwwvvvuutssrrqqppoovWnnnnnnmtVsVsVsVsVsWsWsXsXpppsYsYrZr[r\q\p]ttssh\{e[vbYo^XhZV`USXPQNJMECJRS[47A+((MYkMYkMYkMZk(5F(5F(5FOHJT=+YML_SRZQQMGJABI2:H/TUyUyUyUyUyUy݇݇݇݇݇އއއއއއއއއއއއއއއއއއއއއއއއއއއއއއއއވވވވވވވImImImImImImImImImImImImވ'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}DhDhDhDhDhDhDhDhDhDhDhDh'K}'K}'K}'K}'K}'K}&K}&K}&K}&K}&K}&K}&K}&K}CgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgBgBgBgBg&J|&J|BfBfBfBfBfBfBfBfBf;HY;HY;HY;HY;HY;HY>DM>DM;HY89<:+#9&B52I94ZHAxd[}g^k`ncrey_R}bTeVgXiYk[l\n]o^vvvawaxaybzb{b{axx|a|a|`{`{_{_{^z^uttssrrwZwZvYvYvYuXuXuXuXpppppppqqtZt[s\s\s]r]r^q^p^o^n^l^j^h]{f\ub[n^YgZW_UTWPQOKOEEKST]JNY>=?JJIMYkMYk(5F(5F(5F(5F(5F)5G)5GK=4S<*XMLbWVYPPLGJ@AI/T/TUyUyUyއއއއއއއއއއއވވވވވވވImImImImވވވވވވވވވވވވވވވވވވވވވވވވވImImImImImImImImވވވ'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}DhDhDhDhDhDhDhDh'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}&K}&K}&K}&K}ChChCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCgCg&J|&J|&J|&J|&J|BgBgBgBfBfBfBfBfBf;HY;HY;HY;HY;HY;HYCIR>DMCIR;HYCIR.$0"8&?*G/V=+w[F{g^kanXMs\Px_S{bU~dWfYhZj\l]m^vwxyyzzzzz{b{b{b{b{a{a{`{`z_z_z^uy]y]x]x\w\w[w[v[v[v[v[rrrsssstuut^s_s_r_r`q`p`wvvu~twd]sb[l^ZeYW]TUUORLJOYYaRU^JOZ>>@!$)RXaMYk39B-3<-3<(5F)5G)5G)5G)5G)5GFDJK9*^K=YONg\\TLMIFJ:>I0T0TImވވވވވވވވވވވވވވވވވImImInInInInInInވވވވވވވވވ߈߈߈߈߈߈߈߈߈߈߈߈߈߈߈InInInInIn߈߈߈߈߈'K~'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}DiDiDh'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}&K}ChChChChChCgCgCgCgCgCgCgCgCgCgCg&J}&J}&J}&J}&J|&J|&J|&J|&J|BgBgBgBgBgBfBfEM>EMCIR;HY;HYCIRCIR)6&8&@*H0I1!\B0}_JhTKjM8q[Pt]Sw`U{cW~eYg[i\k^m_vwxyzz{{{{{zdzdzczczcyyyxxxwwwww_w_w_vvvvwwwwwwxxxxxxxxwv~v|tysvrh\YcXX[TUSNRIHOUXaNS^JFE>>A')+"%(4:C(5F(5F3:B3:B-3<-3<)5G)5G)5G)5G)5G)5GE:4O:*TKLbXWcZZPIKDCJImImImImވވވވވވވވވވވ߈߈߈InInInInInInJnJnJnJnJn߈߈߈߈߈߈߈߈߈߈߈߈߈߈߈߈߈߈߈߈߉߉߉߉߉Jn߉߉߉߈߈߈߈'K~'K~'K~'K~'K~'K~'K~'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}DhDhDhChChChChChChCgCgCgCg&K}&K}&J}&J}&J}&J}&J}&J}&J}&J}&J|&J|&J|CgCgCgBgBgBgEMCIRCIRCIR888DGNCJRCIRBBB(0 8&<)G0M5"X@0z^KbFkUlXPp[Rs^TvaVzcX}fZg\i]uvwxyzz{{vevewewe||{{{{{{zzzzzyvbvbvbububuctctcsbscrcqcyyyxxww|uytvs~sqyooslmVQTOLR[\dQU`KHHAAD:<@68; &Z`i-4<%');AJ4:C4:C4:C-4<)5G)5G)5G)5G)6G)6G@84H8-N?5YPQmccoghd`dInInInInInIn߈߈߈߈߈߈߈߈߈JnJnJnJnJnJnJnJnJnJnJnJnJnJnJnJn߉߉߉߉߉߉߉߉߉߉߉߉߉߉߉߉߉߉߉߉߉߉JnJnJn߉߉߉߉߉߉'K~'K~'K~'K~'K~'K~'K~'K~'K~'K~'K~'K~EiEiEiEi'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}DhDhDhDhDhDhChChCh&K}&K}&K}&K}&K}&K}&K}&K}&J}&J}&J}&J}&J}&J}&J}&J}&J}CgCgCgCgB9;>68;Z`iZ`iMZk)5G4:C-4<4:C4:C-4<;BJ)5G)6G)6G)6G)6G)6GC6-L;.leg{{ypqhbeVYcJnJnJnJnJnJnJn߉߉߉߉߉JnJnJnJnJnJnJnJnJnJnJnJnJnJnJnJnJnJnJnJn߉߉߉߉߉߉JnJnJnJnJnJnJn'L~'L~'L~'L~'L~'L~'K~'K~'K~EiEiEiEiEiEiEiEi'K~'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}DhDhDhDhDh'K}'K}'K}'K}&K}&K}&K}&K}&K}&K}&K}&K}&K}&K}&K}&J}&J}&J}&J}&J}&J}CgCgCg<535=AG=?D?AD==1(B3)B2&F4'E4)gTGlXJs^OzcTzaPqfethgvjhbVTcWUdXVeYWfZXg[Yh\Zi]Zi][j^\usususts~tt~tt}tt|st{stut~tt|sszrsyqrwpquoqsmpqloXTXTQWPOULLSSJEA<:=99757335./2113)+.'),)+.8:="(3@QJMPV\eT[cNZlNZlZ`iZ`iZ`iZ`iSYbY`h4;C.4=)6GCPaCPaCPaCPaCPaEQbZOGa_emhknfgeaeJnJnJnJnJnJnJoJoJoJoJoJoJoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoኮኮኮኮኮኮKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoڃڃڃڃڃڃڃڄڄڄڄڄڄEjEiEiEiEi'L~'L~'K~'K~'K~'K~'K~'K~'K~'K~'K~'K~'K~'K}'K}'K}'K}'K}'K}'K}DiDiDiDiDhDh'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}&K}&K}&K}&K}&K}&K}&K}&K}&K}$.>=I[=I[2)>0&A2'C3(I8-^OFbRHfUJjXMq^RwcVzfYfRDfQCdN@zdTqijrjksklrklrklrklqjmpjmpjmojmojmnimmimkhliflscYm`Xg\VbYT^VRE>;A<:>98:77645:873220/0,-/)+.*,/#%( &15;5BSKKKJMP]dlU[dNZlNZlZ`iTZcZaiZaiZ`iZ`iSZbLS[V]eDPbDPbDPbDPbDPbDPbWMF^^dieirkeaeJoJoJoJoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoኯኯኯKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoڃڄڄڄڄڄڄڄڄڄڄڄڄڄڄڄڄۄGk'L~'L~'L~'L~'L~'L~'K~'K~'K~'K~'K~'K~'K~'K~'K~'K~EiEiEiEiEiDiDiDiDiDi'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}&K}&K}&K}&K}&K}%/> ,>=I[=I[ ,> ,>#)2(.7#)2(.7#)2#)2#)2#)2(.7(.7(.767@D>A214$+3#%("$'###""""""&&&888888cB*}\I@!%+%!5*$:/(;0)<1*>3+@4+>1(bUKN@6OA6L=3QB8M?4_RKaTLbUMcVNcVNcVObVOaVOaUO`UO_UO^UO^TO\SOYRNWPNUOMWPKYSOWRN;63953:76755333,/2'),%(+"%(!' "&,KXi04:JMP]_b^emU[dNZlNZlT[cU[dU[dU[d[ajW]fDPbDPbDPbDPbDPbDPbnSw|mqjKoKoKoኮኮኮኮኮኯኯኯKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKpKpKpKpKpKpKpKpKpKpKpKpKpKpKpKpKpKpKpKpKpKpڄڄڄڄڄڄڄڄڄڄڄۄۄۄۄۄۄۄۄGkGkGkGkGkGk'L~'L~'L~'L~'K~'K~'K~EiEiEiEiEiEiEiEiEiEiEiEiDiDi'K}'K}'K}'K}HlHlHlHlHlHlHlHl'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}&K}*2? ->=I[=I[ ,> ,> ,>#)2#)2#)2(.7(.7#)2#)2(.7(.7(.7(.7/28:79G@A<89',4#%(#%(######""""""8888888887'vS:jW;)  &3#.$-% .% .& /&!,#,#@70A71XNHXNHWNHWNHZRLYQLYQLXQLWQLWPLUOLSNLQMKOLJMJJ0//.-.,,-&(+"(!' 15;6CT37=MMMKMP^ad_enY`hNZlNZlU\dV\eDQbDQbDQbDQbDQbMUcyl|oiKoኯኯኯኯኯኯዯዯዯዯዯዯዯዯዯKoKoKoKoKoKoKoKpKpKpKpKpKpKpKpKpKpKpKpKpKpKpKp⋯⋯⋯LpLpLpLpLpLpLpLpLpLpLpLpLpLpLpLpLpLpLpLpLpڄڄڄڄڄۄۄۄۄۄۄۄۄۄۅۅۅۅۅۅGkGkGkGkGkGkGkGkGkۅ܅܅܅܅܅܅܅܅܅܅܅܆܆܆܆܆HlHlHlHlHlHlHlHlHlHlHlHlHl'K}'K}'K}'K}'K}'K}'K}'K}'K}HO\=J[=J[=J[ -> ,> ,>(.7#)2#)2(.7(.7(.7#)2(.7(.7(/7(/7)/8/28114H7,99@.05&,5$&)$$$######"""(((8888888888888884"nO9gXjZE/ (-"  %' %$#" ! !$ 48>7CU:GX JJJLLLKMPagp_enNZlLPVDQbDQbDQbDQbNVcuorjѼዯዯዯዯዯዯዯዯዯዯዯዯዯዯዯዯዯKpKpKpKpKpLpLpLpLpLpLpLpLpLpLpLpLpLpLpLp⋰⋰⋰⌰⌰⌰LpLpLpLpLpLpLpLpLpLpLpLpLpLpLpLpLpLpLpLpۄۄۄۄۄۄۄۄۅۅۅۅۅۅۅۅۅۅۅۅGkGkGkGlGlGl܅܅܅܅܅܅܅܅܆܆܆܆܆܆܆܆܆܆܆܆HlHlHlHlHlHlHlHlHlHlHlHlHlHlHl'K}'K}'K}'K}DhDhDhIP\=J[=J[=J[=J[ -> ->(.7#)2#)2(.7(.7(.7#)2(.7(/7(/7)/8)/8)/803966:E?AC>A856,07%'*%')$$$######(((DDDBBB8888888880 cF1w]OcS{`QS;+57'   *      ;?E7CU;HY=I[ JJJMMMKMPacfbhqEQcHScNVdȵዯዯዯዯዯዯዯ⋯⋯⋯⋯⋯⋰⋰⋰⋰⋰⋰⋰LpLpLpLpLpLpLpLpLpLpLpLpLpLpLpLp⌰⌰⌰⌰⌰⌰⌰⌰⌰⌰LpLpLpLpLpLpLpLpLpLpLpLpLpLpLpLpLpLpۄۄۅۅۅۅۅۅۅۅۅۅۅۅۅۅۅۅۅ܅܅GlGl܅܅܅܅܅܆܆܆܆܆܆܆܆܆܆܆܆܆܆܆܆܆܆܆HlHlHlHlHlHlHlHlHlHlHlHlHlHlHl݇DhDhDhDh=J[=J[=J[=J[=J[=J[ ->(/7#)2#)2(.7(.7(.7#*2(/7)/8)/8)/8)/8)08*0903:56:88@KBB=;@348*08&(+'(*%%%$$$(((EEE(((&&&">-"bF3oXMs[Ow]Py^PqbpXMdH5R<,Q;, &%%#'-"'-&3DS_qP\nR_p>J\?K]AG@B::@66:-29'),)'%BBBFFFEEE)))))))))&&& @@@FFFACFZ\_[ajagpEQcGRcKTdPWd⌰⌰⌰⌰⌰⌰⌰⌰⌰⌰⌰⌰⌰⌰⌰⌰⌰⌰⌰⌰㌰㌰㌰㌰LpLpLqLqLqLqLqLqLq㌱㌱㌱㌱㌱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱MqMqMqMqMqMqMqMqMqMqMqMqMqMqMqۅۅۅۅۅۅ܅܅܅܅܅܅܅܅܅܅܆HlHlHlHlHl܆܆܆܆܆܆܆܆܆܆܆݆݆݆݆݆݆݆݆݆݆݆݇݇݇݇݇HlHlHlHlHlHlHl݇݇݇݇݇݇݇݇އއއށ>J\>J\=J[=J[=J[=J[FLU39B#*2(/7)/7)/8$*3$*3$*3)/8)08*09*09*19',5(-5*.6.17338@<=G@BH@BXW]UUXLPWFHKDFHKKKHHH+++%%%%%%$$$###!!!!!!777777777777777777777AAAFFFACFACF\^aeltbhqDQbDQbDQbERcERcERcERcHScLUdRXd|nj⌰⌰⌰⌰⌰⌰⌰⌰⌰⌰㌰㌰㌰㌰㌱㌱㌱㌱㌱㌱㌱㌱㍱㍱㍱㍱MqMqMqMqMqMq㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱MqMqMqMqMqMqMqMqMqMqMqMqMq܅܅܅܅܅܅܅܅܅܅܆܆܆܆HlHlHlHlHlHlHlHlHl܆܆܆݆݆݆݆݆݆݆݆݆݆݆݇݇݇݇݇݇݇݇݇݇݇݇HlHlHlHlHl݇݇݇އއއއއއއއއއށ>J\=J[=J[FLUFLU(/7(/7*08*08%+3$*3$+3$+3*09*09*19&,5&,5'-6).6*/7-18NPURRVXUVc]^f^_[X]\XYTUZLQYKMPFHJ)))(((&&&%%%%%%$$$$$$###!!!!!!!!!777777777BBBEEEACGADGFIL\ckZ`iTZcDQbDQbDQbagpbiqcircirY`hY_hERcERcERcGSdJTdNVdTYeLpLp㌰㌰㌰㌱㌱㌱㌱㌱㌱㌱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱MqMq㍱㍱㍱䍱䍱䍱䍱䍱䍱䍱䍱䍱䍲䍲䍲䍲䍲䍲䍲䍲䍲䍲䍲䍲䍲MqMqMqMqMqMqMqMqMqMqMq܅܅܅܆܆܆܆܆܆܆܆HlHlHlHlHlHlHlHlHlHlHlHl݆݆݆݆݆݆݆݆݇݇݇݇݇݇݇݇݇݇݇݇݇݇݇݇݇݇݇HmއއއއއއއއއއއވވވވވށFLUFLUFLU)/8+08+08&+3&+3%+4%+4%+4*19+1:&,5'-5'-6(.6FLTHMTINUKOVOQWSTXYWX`[^lbac]_f_\a_aY\aRX_,.1*,.*+-***((('''&&&%%%%%%$$$$$$$$$###!!!!!!!!!!!!!!!%%%%%%%%%%%%"""""""""KKKJJJFFFGIL]_b^dm\bkV]eDQbEQcEQcEQccirdjsdksektdjsdjscir[ajZ`iOU^ERcERcFRdFRdITdLUdPWeVZeLpLqLqLq㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱㍱䍱䍱䍱䍱䍱䍲䍲䍲Mq䍲䍲䍲䍲䍲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲MrMrMrMrMrMrMrMrMrMr܆܆܆܆܆܆܆܆HlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHl݇݇݇݇݇݇݇݇݇݇݇݇݇݇݇݇݇݇݇݇އއއއHmHmHmއއއއވވވވވވވވވވވވށ-18,18',3',4',4&,4%,4+1:,2:'-5DJSEKSEKTFLTFLUHMUINVKOWLPWQSYTUZWWZpjje^`offb\_h`]eaaCCG8;A27?-/2+-/.+)******)))((('''&&&&&&%%%%%%$$$$$$$$$$$$$$$$$$######???EEEEEEEEE((((((###&&&%%%HJMHJMHJMHJM_en]dlZ`i_enEQcEQcEQcEQcbhqektflufluflufluektektdksdjscjr\ckQW`[ajZaiOU^FRdFRdFRdHSdKUdNVeRXeX\fLqMqMqMqMq㍱㍱㍱㍱㍱䍱䍱䍱䍱䍲䍲䍲䍲䍲䍲䍲䍲䎲䎲䎲䎲䎲MrMrMrMrMr䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲厲厲厲厲厲厲厲厲NrNrNrNrNrNrNrNr܆܆܆܆܆HlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHl݇݇݇݇݇݇݇݇݇݇݇݇އއއއއއއއHmHmHmHmImImImވވވވވވވވވވވވވވވނPT[KOVJOV(-4(-4'-5'-5JOXEKSEKSEKTFLTFLTGMUGMUHNVIOWKPWLQXMRYPTZTV[\]a_^asljd^azporjkE@CLEBIEFEDG29A28A17@135,.1+-0+,/./1..0'),)))++++++++++++***FFFFFFACFACFEEEACFACFJLOJLOKQZ_en]clY_hU[dEQcEQcEQcEQcEQcagp[aj\bk\bkgnvgnvgmvgmvfluflueltektdksdjscjrcirTZcSYbRYaRXaQW`[bj[ajZ`iFSdFSdGSdJTdLVePXeTZfZ]fMqMqMqMqMqMqMq䍲䍲䍲䍲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲䎲NrNrNrNrNrNrNrNrNr厲厲厲厳厳厳厳厳厳厳厳厳厳厳厳厳厳厳厳右右右右右右右NrNrNrNrNr右冪܆܆HlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHlHl݇݇݇݇݇އއއއއއއއއއއއImImImImImImImImImImވވވވވވވވވ߈߈߈߈߈߈߂LPVLPWKPWFLTFLTFLUGMUGMUHMVHNVINWIOWKPXLQYMRYNSZTX`X[a[]b]^c__ccacib`JDGi__aYYPJLD@C=;AKEDTQR@?A>>A;/5>.4=-4'IRB console') top.protocol(:WM_DELETE_WINDOW){ Tk.exit } case (Tk.windowingsystem) when 'win32' fnt = ['MS Gothic', '-12'] else fnt = ['courier', '-12'] end console = TkTextIO.new(top, :mode=>:console, :width=>80).pack(:side=>:left, :expand=>true, :fill=>:both) console.yscrollbar(TkScrollbar.new(top, :width=>10).pack(:before=>console, :side=>:right, :expand=>false, :fill=>:y)) irb_thread = nil ev_loop = Thread.new{ Tk.mainloop irb_thread.kill if irb_thread } # window position control root = Tk.root r_x = root.winfo_rootx r_y = root.winfo_rooty r_w = root.winfo_width t_x = top.winfo_rootx t_y = top.winfo_rooty t_w = top.winfo_width delta = 10 ratio = 0.8 s_w = (ratio * root.winfo_screenwidth).to_i if r_x < t_x r_x, t_x = t_x, r_x end if t_x + t_w + r_w + delta < s_w r_x = t_x + t_w + delta elsif t_w + r_w + delta < s_w r_x = s_w - r_w t_x = r_x - t_w else r_x = s_w - r_w t_x = 0 end root.geometry("+#{r_x}+#{r_y}") top.geometry("+#{t_x}+#{t_y}") root.raise console.focus # I/O setup $stdin = console $stdout = console $stderr = console # dummy for rubyw.exe on Windows def STDIN.tty? true end # IRB setup IRB.init_config(nil) IRB.conf[:USE_READLINE] = false IRB.init_error irb = IRB::Irb.new IRB.conf[:MAIN_CONTEXT] = irb.context class IRB::StdioInputMethod def gets prompt = "\n" << @prompt $stdin.instance_eval{ flush @prompt = prompt _set_console_line @prompt = nil _see_pos } @line[@line_no += 1] = $stdin.gets end end # IRB start $stdout.print("*** IRB console on Ruby/Tk (#{release}) ") irb_thread = Thread.new{ catch(:IRB_EXIT){ loop { begin irb.eval_input rescue Exception end } } } console.bind('Control-c'){ console.insert('end', "^C\n") irb_thread.raise RubyLex::TerminateLineInput } irb_thread.join # exit ev_thread.kill Tk.exit ================================================ FILE: ext/tk/sample/iso2022-kr.txt ================================================ Sample text: $)C Hangul (GQ1[) >H3gGO<H3gGO=J4O1n ================================================ FILE: ext/tk/sample/menubar1.rb ================================================ # # menubar sample 1 : use frame and menubuttons # require 'tk' radio_var = TkVariable.new('y') menu_spec = [ [['File', 0], {:label=>'Open', :command=>proc{puts('Open clicked')}, :underline=>0}, '---', ['Check_A', TkVariable.new(true), 6], {:type=>'checkbutton', :label=>'Check_B', :variable=>TkVariable.new, :underline=>6}, '---', ['Radio_X', [radio_var, 'x'], 6, '', {:foreground=>'black'}], ['Radio_Y', [radio_var, 'y'], 6], ['Radio_Z', [radio_var, 'z'], 6], '---', ['cascade', [ ['sss', proc{p 'sss'}, 0], ['ttt', proc{p 'ttt'}, 0], ['uuu', proc{p 'uuu'}, 0], ['vvv', proc{p 'vvv'}, 0], ], 0, '', {:font=>'Courier 16 italic', :menu_config=>{:font=>'Times -18 bold', :foreground=>'black'}}], '---', ['Quit', proc{exit}, 0]], [['Edit', 0], ['Cut', proc{puts('Cut clicked')}, 2], ['Copy', proc{puts('Copy clicked')}, 0], ['Paste', proc{puts('Paste clicked')}, 0]], [['Help', 0, {:menu_name=>'help'}], ['About This', proc{puts('Ruby/Tk menubar sample 1')}, 6]] ] menubar = TkMenubar.new(nil, menu_spec, 'tearoff'=>false, 'foreground'=>'grey40', 'activeforeground'=>'red', 'font'=>'Helvetia 12 bold') menubar.pack('side'=>'top', 'fill'=>'x') TkText.new(:wrap=>'word').pack.insert('1.0', 'Please read the sample source, and check how to override default configure options of menu entries on a menu_spec. Maybe, on windows, this menubar does not work properly about keyboard shortcuts. Then, please use "menu" option of root/toplevel widget (see sample/menubar2.rb).') Tk.mainloop ================================================ FILE: ext/tk/sample/menubar2.rb ================================================ # # menubar sample 2 : use 'menu' option of root/toplevel widget # require 'tk' radio_var = TkVariable.new('y') menu_spec = [ [['File', 0], {:label=>'Open', :command=>proc{puts('Open clicked')}, :underline=>0}, '---', ['Check_A', TkVariable.new(true), 6], {:type=>'checkbutton', :label=>'Check_B', :variable=>TkVariable.new, :underline=>6}, '---', ['Radio_X', [radio_var, 'x'], 6, '', {:foreground=>'black'}], ['Radio_Y', [radio_var, 'y'], 6], ['Radio_Z', [radio_var, 'z'], 6], '---', ['cascade', [ ['sss', proc{p 'sss'}, 0], ['ttt', proc{p 'ttt'}, 0], ['uuu', proc{p 'uuu'}, 0], ['vvv', proc{p 'vvv'}, 0], ], 0, '', {:font=>'Courier 16 italic', :menu_config=>{:font=>'Times -18 bold', :foreground=>'black'}}], '---', ['Quit', proc{exit}, 0]], [['Edit', 0], ['Cut', proc{puts('Cut clicked')}, 2], ['Copy', proc{puts('Copy clicked')}, 0], ['Paste', proc{puts('Paste clicked')}, 0]], [['Help', 0, {:menu_name=>'help'}], ['About This', proc{puts('Ruby/Tk menubar sample 2')}, 6]] ] mbar = Tk.root.add_menubar(menu_spec, # followings are default configure options 'tearoff'=>'false', 'foreground'=>'grey40', 'activeforeground'=>'red', 'font'=>'Helvetia 12 bold') # This (default configure options) is NOT same the following. # # mbar = Tk.root.add_menubar(menu_spec) # mbar.configure('foreground'=>'grey40', 'activeforeground'=>'red', # 'font'=>'Helvetia 12 bold') TkText.new(:wrap=>'word').pack.insert('1.0', 'Please read the sample source, and check how to override default configure options of menu entries on a menu_spec.') Tk.mainloop ================================================ FILE: ext/tk/sample/msgs_rb/README ================================================ Message catalogs in this directory depend on Tcl/Tk's message catalogs. Texts of each locale are copied from Tcl/Tk8.5a1 widget demos. Please refer '../msgs_tk/README'. ================================================ FILE: ext/tk/sample/msgs_rb/cs.msg ================================================ TkMsgCatalog.new('::tkmsgcat_demo') { cs "Application Error", "Chyba programu" cs "Blue", "Modr\341" cs "Color", "Barva" cs "Delete", "Smazat" cs "Error", "Chyba" cs "Exit", "Konec" cs "Green", "Zelen\341" cs "Red", "\\u010cerven\341" cs "blue", "modr\341" cs "green", "zelen\341" cs "red", "\\u010derven\341" } TkMsgCatalog.new('::tk') { cs "&Abort", "&P\\u0159eru\\u0161it" cs "About...", "O programu..." cs "All Files", "V\\u0161echny soubory" cs "Application Error", "Chyba programu" cs "&Blue", "&Modr\341" cs "&Cancel", "&Zru\\u0161it" cs "Cannot change to the directory \"%1\$s\".\nPermission denied.", "Nemohu zm\\u011bnit atku\341ln\355 adres\341\\u0159 na \"%1\$s\".\nP\\u0159\355stup odm\355tnut." cs "Choose Directory", "V\375b\\u011br adres\341\\u0159e" cs "Clear", "Smazat" cs "Color", "Barva" cs "Console", "Konzole" cs "Copy", "Kop\355rovat" cs "Cut", "Vy\\u0159\355znout" cs "Delete", "Smazat" cs "Details >>", "Detaily >>" cs "Directory \"%1\$s\" does not exist.", "Adres\341\\u0159 \"%1\$s\" neexistuje." cs "&Directory:", "&Adres\341\\u0159:" cs "Error: %1\$s", "Chyba: %1\$s" cs "Exit", "Konec" cs "File \"%1\$s\" already exists.\n\n", "Soubor \"%1\$s\" ji\\u017e existuje.\n\n" cs "File \"%1\$s\" already exists.\nDo you want to overwrite it?", "Soubor \"%1\$s\" ji\\u017e existuje.\nChcete jej p\\u0159epsat?" cs "File \"%1\$s\" does not exist.", "Soubor \"%1\$s\" neexistuje." cs "File &name:", "&Jm\351no souboru:" cs "File &names:", "&Jm\351na soubor\\u016f:" cs "Files of &type:", "&Typy soubor\\u016f:" cs "Fi&les:", "Sou&bory:" cs "&Filter", "&Filtr" cs "Fil&ter:", "Fil&tr:" cs "&Green", "Ze&len\341" cs "Hi" cs "Hide Console", "Skr\375t konsolu" cs "&Ignore", "&Ignorovat" cs "Invalid file name \"%1\$s\".", "\\u0160patn\351 jm\351no souboru \"%1\$s\"." cs "Log Files", "Log soubory" cs "&No", "&Ne" cs "&OK" cs "Ok" cs "Open", "Otev\\u0159\355t" cs "&Open", "&Otev\\u0159\355t" cs "Open Multiple Files", "Otev\\u0159\355t v\355ce soubor\\u016f" cs "Paste", "Vlo\\u017eit" cs "Quit", "Skon\\u010dit" cs "&Red", " \\u010ce&rven\341" cs "Replace existing file?", "Nahradit st\341vaj\355c\355 soubor?" cs "&Retry", "Z&novu" cs "&Save", "&Ulo\\u017eit" cs "Save As", "Ulo\\u017eit jako" cs "Save To Log", "Ulo\\u017eit do logu" cs "Select Log File", "Vybrat log soubor" cs "Select a file to source", "Vybrat soubor k nahr\341n\355" cs "&Selection:", "&V\375b\\u011br:" cs "Skip Messages", "P\\u0159esko\\u010dit zpr\341vy" cs "Source...", "Nahr\341t..." cs "Tcl Scripts", "Tcl skripty" cs "Tcl for Windows", "Tcl pro Windows" cs "Text Files", "Textov\351 soubory" cs "&Yes", "&Ano" cs "abort", "p\\u0159eru\\u0161it" cs "blue", "modr\341" cs "cancel", "zru\\u0161it" cs "extension", "p\\u0159\355pona" cs "extensions", "p\\u0159\355pony" cs "green", "zelen\341" cs "ignore", "ignorovat" cs "ok" cs "red", "\\u010derven\341" cs "retry", "znovu" cs "yes", "ano" } ================================================ FILE: ext/tk/sample/msgs_rb/de.msg ================================================ TkMsgCatalog.new('::tkmsgcat_demo') { de "Application Error", "Applikationsfehler" de "Blue", "Blau" de "Color", "Farbe" de "Delete", "L\\u00f6schen" de "Error", "Fehler" de "Exit", "Ende" de "Green", "Gr\\u00fcn" de "Red", "Rot" de "blue", "blau" de "green", "gr\\u00fcn" de "red", "rot" } TkMsgCatalog.new('::tk') { de "&Abort", "&Abbruch" de "&About...", "&\\u00dcber..." de "All Files", "Alle Dateien" de "Application Error", "Applikationsfehler" de "&Blue", "&Blau" de "&Cancel", "&Abbruch" de "Cannot change to the directory \"%1\$s\".\nPermission denied.", "Kann nicht in das Verzeichnis \"%1\$s\" wechseln.\nKeine Rechte vorhanden." de "Choose Directory", "W\\u00e4hle Verzeichnis" de "&Clear", "&R\\u00fccksetzen" de "&Clear Console", "&Konsole l\\u00f6schen" de "Color", "Farbe" de "Console", "Konsole" de "&Copy", "&Kopieren" de "Cu&t", "Aus&schneiden" de "&Delete", "&L\\u00f6schen" de "Details >>" de "Directory \"%1\$s\" does not exist.", "Das Verzeichnis \"%1\$s\" existiert nicht." de "&Directory:", "&Verzeichnis:" de "&Edit", "&Bearbieten" de "Error: %1\$s", "Fehler: %1\$s" de "E&xit", "&Ende" de "&File", "&Datei" de "File \"%1\$s\" already exists.\nDo you want to overwrite it?", "Die Datei \"%1\$s\" ist bereits vorhanden.\nWollen sie diese Datei \\u00fcberschreiben ?" de "File \"%1\$s\" already exists.\n\n", "Die Datei \"%1\$s\" ist bereits vorhanden.\n\n" de "File \"%1\$s\" does not exist.", "Die Datei \"%1\$s\" existiert nicht." de "File &name:", "Datei&name:" de "File &names:", "Datei&namen:" de "Files of &type:", "Dateien des &Typs:" de "Fi&les:", "Dat&eien:" de "&Filter" de "Fil&ter:" de "&Green", "&Gr\\u00fcn" de "&Help", "&Hilfe" de "Hi", "Hallo" de "&Hide Console", "&Konsole unsichtbar machen" de "&Ignore", "&Ignorieren" de "Invalid file name \"%1\$s\".", "Ung\\u00fcltiger Dateiname \"%1\$s\"." de "Log Files", "Protokolldatei" de "&No", "&Nein" de "OK" de "Ok" de "Open", "\\u00d6ffnen" de "&Open", "\\u00d6&ffnen" de "Open Multiple Files" de "P&aste", "E&inf\\u00fcgen" de "&Quit", "&Beenden" de "&Red", "&Rot" de "Replace existing file?", "Existierende Datei ersetzen?" de "&Retry", "&Wiederholen" de "&Save", "&Speichern" de "Save As", "Speichern unter" de "Save To Log", "In Protokoll speichern" de "Select Log File", "Protokolldatei ausw\\u00e4hlen" de "Select a file to source", "Auszuf\\u00fchrende Datei ausw\\u00e4hlen" de "&Selection:", "Auswah&l:" de "Skip Messages", "Weitere Nachrichten \\u00fcberspringen" de "&Source...", "&Ausf\\u00fchren..." de "Tcl Scripts", "Tcl-Skripte" de "Tcl for Windows", "Tcl f\\u00fcr Windows" de "Text Files", "Textdateien" de "&Yes", "&Ja" de "abort", "abbrechen" de "blue", "blau" de "cancel", "abbrechen" de "extension", "Erweiterung" de "extensions", "Erweiterungen" de "green", "gr\\u00fcn" de "ignore", "ignorieren" de "ok" de "red", "rot" de "retry", "wiederholen" de "yes", "ja" } ================================================ FILE: ext/tk/sample/msgs_rb/el.msg ================================================ TkMsgCatalog.new('::tkmsgcat_demo') { el 'Application Error', '\u039b\u03ac\u03b8\u03bf\u03c2 \u0395\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae\u03c2' el 'Blue', '\u039c\u03c0\u03bb\u03b5' el 'Color', '\u03a7\u03c1\u03ce\u03bc\u03b1' el 'Delete', '\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae' el 'Error', '\u039b\u03ac\u03b8\u03bf\u03c2' el 'Exit', '\u0388\u03be\u03bf\u03b4\u03bf\u03c2' el 'Green', '\u03a0\u03c1\u03ac\u03c3\u03b9\u03bd\u03bf' el 'Red', '\u039a\u03cc\u03ba\u03ba\u03b9\u03bd\u03bf' el 'blue', '\u03bc\u03c0\u03bb\u03b5' el 'green', '\u03c0\u03c1\u03ac\u03c3\u03b9\u03bd\u03bf' el 'red', '\u03ba\u03cc\u03ba\u03ba\u03b9\u03bd\u03bf' } TkMsgCatalog.new('::tk') { el '&Abort', '\u03a4\u03b5\u03c1\u03bc\u03b1\u03c4\u03b9\u03c3\u03bc\u03cc\u03c2' el 'About...', '\u03a3\u03c7\u03b5\u03c4\u03b9\u03ba\u03ac...' el 'All Files', '\u038c\u03bb\u03b1 \u03c4\u03b1 \u0391\u03c1\u03c7\u03b5\u03af\u03b1' el 'Application Error', '\u039b\u03ac\u03b8\u03bf\u03c2 \u0395\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae\u03c2' el '&Blue', '\u039c\u03c0\u03bb\u03b5' el '&Cancel', '\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7' el 'Cannot change to the directory "%1\$s".' "\n" 'Permission denied.', \ '\u0394\u03b5\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b4\u03c5\u03bd\u03b1\u03c4\u03ae \u03b7 \u03b1\u03bb\u03bb\u03b1\u03b3\u03ae \u03ba\u03b1\u03c4\u03b1\u03bb\u03cc\u03b3\u03bf\u03c5 \u03c3\u03b5 "%1\$s".' \ "\n" \ '\u0397 \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03b4\u03b5\u03bd \u03b5\u03c0\u03b9\u03c4\u03c1\u03ad\u03c0\u03b5\u03c4\u03b1\u03b9.' el 'Choose Directory', '\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u039a\u03b1\u03c4\u03b1\u03bb\u03cc\u03b3\u03bf\u03c5' el 'Clear', '\u039a\u03b1\u03b8\u03b1\u03c1\u03b9\u03c3\u03bc\u03cc\u03c2' el 'Color', '\u03a7\u03c1\u03ce\u03bc\u03b1' el 'Console', '\u039a\u03bf\u03bd\u03c3\u03cc\u03bb\u03b1' el 'Copy', '\u0391\u03bd\u03c4\u03b9\u03b3\u03c1\u03b1\u03c6\u03ae' el 'Cut', '\u0391\u03c0\u03bf\u03ba\u03bf\u03c0\u03ae' el 'Delete', '\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae' el 'Details >>', '\u039b\u03b5\u03c0\u03c4\u03bf\u03bc\u03ad\u03c1\u03b5\u03b9\u03b5\u03c2 >>' el 'Directory "%1\$s", does not exist.', \ '\u039f \u03ba\u03b1\u03c4\u03ac\u03bb\u03bf\u03b3\u03bf\u03c2 \'%1\$s\' \u03b4\u03b5\u03bd \u03c5\u03c0\u03ac\u03c1\u03c7\u03b5\u03b9.' el '&Directory:', '&\u039a\u03b1\u03c4\u03ac\u03bb\u03bf\u03b3\u03bf\u03c2:' el 'Error: %1\$s', '\u039b\u03ac\u03b8\u03bf\u03c2: %1\$s' el 'Exit', '\u0388\u03be\u03bf\u03b4\u03bf\u03c2' el 'File "%1\$s" already exists.' "\n" 'Do you want to overwrite it?', \ '\u03a4\u03bf \u03b1\u03c1\u03c7\u03b5\u03af\u03bf "%1\$s" \u03ae\u03b4\u03b7 \u03c5\u03c0\u03ac\u03c1\u03c7\u03b5\u03b9.' \ "\n" \ '\u0398\u03ad\u03bb\u03b5\u03c4\u03b5 \u03bd\u03b1 \u03b5\u03c0\u03b9\u03ba\u03b1\u03bb\u03c5\u03c6\u03b8\u03b5\u03af;' el 'File "%1\$s" already exists.' "\n\n", \ '\u03a4\u03bf \u03b1\u03c1\u03c7\u03b5\u03af\u03bf "%1\$s" \u03ae\u03b4\u03b7 \u03c5\u03c0\u03ac\u03c1\u03c7\u03b5\u03b9.' "\n\n" el 'File "%1\$s" does not exist.', \ '\u03a4\u03bf \u03b1\u03c1\u03c7\u03b5\u03af\u03bf "%1\$s" \u03b4\u03b5\u03bd \u03c5\u03c0\u03ac\u03c1\u03c7\u03b5\u03b9.' el 'File &name:', '\u038c&\u03bd\u03bf\u03bc\u03b1 \u03b1\u03c1\u03c7\u03b5\u03af\u03bf\u03c5:' el 'File &names:', '\u038c&\u03bd\u03bf\u03bc\u03b1 \u03b1\u03c1\u03c7\u03b5\u03af\u03c9\u03bd:' el 'Files of &type:', '\u0391\u03c1\u03c7\u03b5\u03af\u03b1 \u03c4\u03bf\u03c5 &\u03c4\u03cd\u03c0\u03bf\u03c5:' el 'Fi&les:', '\u0391\u03c1\u03c7\u03b5\u03af\u03b1:' el '&Filter', '\u03a6\u03af\u03bb\u03c4\u03c1\u03bf' el 'Fil&ter:', '\u03a6\u03af\u03bb\u03c4\u03c1\u03bf:' el '&Green', '\u03a0\u03c1\u03ac\u03c3\u03b9\u03bd\u03bf' el 'Hi', '\u0393\u03b5\u03b9\u03b1' el 'Hide Console', '\u0391\u03c0\u03cc\u03ba\u03c1\u03c5\u03c8\u03b7 \u03ba\u03bf\u03bd\u03c3\u03cc\u03bb\u03b1\u03c2' el '&Ignore', '\u0391\u03b3\u03bd\u03cc\u03b7\u03c3\u03b7' el 'Invalid file name "%1\$s".', \ '\u0386\u03ba\u03c5\u03c1\u03bf \u03cc\u03bd\u03bf\u03bc\u03b1 \u03b1\u03c1\u03c7\u03b5\u03af\u03bf\u03c5 "%1\$s".' el 'Log Files', '\u0391\u03c1\u03c7\u03b5\u03af\u03b1 \u039a\u03b1\u03c4\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2' el '&No', '\u038c\u03c7\u03b9' el '&OK', '\u0395\u03bd\u03c4\u03ac\u03be\u03b5\u03b9' el '&Ok', '\u0395\u03bd\u03c4\u03ac\u03be\u03b5\u03b9' el 'Open', '\u0386\u03bd\u03bf\u03b9\u03b3\u03bc\u03b1' el '&Open', '\u0386\u03bd\u03bf\u03b9\u03b3\u03bc\u03b1' el 'Open Multiple Files', \ '\u0386\u03bd\u03bf\u03b9\u03b3\u03bc\u03b1 \u03c0\u03bf\u03bb\u03bb\u03b1\u03c0\u03bb\u03ce\u03bd \u03b1\u03c1\u03c7\u03b5\u03af\u03c9\u03bd' el 'Paste', '\u0395\u03c0\u03b9\u03ba\u03cc\u03bb\u03bb\u03b7\u03c3\u03b7' el 'Quit', '\u0388\u03be\u03bf\u03b4\u03bf\u03c2' el '&Red', '\u039a\u03cc\u03ba\u03ba\u03b9\u03bd\u03bf' el 'Replace existing file?', \ '\u0395\u03c0\u03b9\u03ba\u03ac\u03bb\u03c5\u03c8\u03b7 \u03c5\u03c0\u03ac\u03c1\u03c7\u03bf\u03bd\u03c4\u03bf\u03c2 \u03b1\u03c1\u03c7\u03b5\u03af\u03bf\u03c5;' el '&Retry', '\u03a0\u03c1\u03bf\u03c3\u03c0\u03ac\u03b8\u03b7\u03c3\u03b5 \u03be\u03b1\u03bd\u03ac' el '&Save', '\u0391\u03c0\u03bf\u03b8\u03ae\u03ba\u03b5\u03c5\u03c3\u03b7' el 'Save As', '\u0391\u03c0\u03bf\u03b8\u03ae\u03ba\u03b5\u03c5\u03c3\u03b7 \u03c3\u03b1\u03bd' el 'Save To Log', '\u0391\u03c0\u03bf\u03b8\u03ae\u03ba\u03b5\u03c5\u03c3\u03b7 \u03c3\u03c4\u03bf \u03b1\u03c1\u03c7\u03b5\u03af\u03bf \u03ba\u03b1\u03c4\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2' el 'Select Log File', '\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u03b1\u03c1\u03c7\u03b5\u03af\u03bf\u03c5 \u03ba\u03b1\u03c4\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2' el 'Select a file to source', \ '\u0395\u03c0\u03b9\u03bb\u03ad\u03be\u03c4\u03b5 \u03b1\u03c1\u03c7\u03b5\u03af\u03bf \u03b3\u03b9\u03b1 \u03b5\u03ba\u03c4\u03ad\u03bb\u03b5\u03c3\u03b7' el '&Selection:', '\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae:' el 'Skip Messages', '\u0391\u03c0\u03bf\u03c6\u03c5\u03b3\u03ae \u03bc\u03c5\u03bd\u03b7\u03bc\u03ac\u03c4\u03c9\u03bd' el 'Source...', '\u0395\u03ba\u03c4\u03ad\u03bb\u03b5\u03c3\u03b7...' el 'Tcl Scripts', 'Tcl Scripts' el 'Tcl for Windows', 'Tcl \u03b3\u03b9\u03b1 Windows' el 'Text Files', '\u0391\u03c1\u03c7\u03b5\u03af\u03b1 \u039a\u03b5\u03b9\u03bc\u03ad\u03bd\u03bf\u03c5' el '&Yes', '\u039d\u03b1\u03b9' el 'abort', '\u03c4\u03b5\u03c1\u03bc\u03b1\u03c4\u03b9\u03c3\u03bc\u03cc\u03c2' el 'blue', '\u03bc\u03c0\u03bb\u03b5' el 'cancel', '\u03b1\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7' el 'extension', '\u03b5\u03c0\u03ad\u03ba\u03c4\u03b1\u03c3\u03b7' el 'extensions', '\u03b5\u03c0\u03b5\u03ba\u03c4\u03ac\u03c3\u03b5\u03b9\u03c2' el 'green', '\u03c0\u03c1\u03ac\u03c3\u03b9\u03bd\u03bf' el 'ignore', '\u03b1\u03b3\u03bd\u03cc\u03b7\u03c3\u03b7' el 'ok', '\u03b5\u03bd\u03c4\u03ac\u03be\u03b5\u03b9' el 'red', '\u03ba\u03cc\u03ba\u03ba\u03b9\u03bd\u03bf' el 'retry', '\u03c0\u03c1\u03bf\u03c3\u03c0\u03ac\u03b8\u03b7\u03c3\u03b5 \u03be\u03b1\u03bd\u03ac' el 'yes', '\u03bd\u03b1\u03b9' } ================================================ FILE: ext/tk/sample/msgs_rb/en.msg ================================================ TkMsgCatalog.new('::tkmsgcat_demo') { en "Application Error" en "Blue" en "Color" en "Delete" en "Error" en "Green" en "Red" en "blue" en "green" en "red" } TkMsgCatalog.new('::tk') { en "&Abort" en "About..." en "All Files" en "Application Error" en "&Blue" en "&Cancel" en "Cannot change to the directory \"%1\$s\".\nPermission denied." en "Choose Directory" en "Clear" en "Color" en "Console" en "Copy" en "Cut" en "Delete" en "Details >>" en "Directory \"%1\$s\" does not exist." en "&Directory:" en "Error: %1\$s" en "Exit" en "File \"%1\$s\" already exists.\nDo you want to overwrite it?" en "File \"%1\$s\" already exists.\n\n" en "File \"%1\$s\" does not exist." en "File &name:" en "File &names:" en "Files of &type:" en "Fi&les:" en "&Filter" en "Fil&ter:" en "&Green" en "Hi" en "Hide Console" en "&Ignore" en "Invalid file name \"%1\$s\"." en "Log Files" en "&No" en "&OK" en "Ok" en "Open" en "&Open" en "Open Multiple Files" en "Paste" en "Quit" en "&Red" en "Replace existing file?" en "&Retry" en "&Save" en "Save As" en "Save To Log" en "Select Log File" en "Select a file to source" en "&Selection:" en "Skip Messages" en "Source..." en "Tcl Scripts" en "Tcl for Windows" en "Text Files" en "&Yes" en "abort" en "blue" en "cancel" en "extension" en "extensions" en "green" en "ignore" en "ok" en "red" en "retry" en "yes" } ================================================ FILE: ext/tk/sample/msgs_rb/en_gb.msg ================================================ TkMsgCatalog.new('::tkmsgcat_demo') { en_gb 'Color', 'Colour' } TkMsgCatalog.new('::tk') { en_gb 'Color', 'Colour' } ================================================ FILE: ext/tk/sample/msgs_rb/eo.msg ================================================ TkMsgCatalog.new('::tkmsgcat_demo') { eo 'Application Error', 'Aplikoerraro' eo 'Blue', 'Blua' eo 'Color', 'Farbo' eo 'Delete', 'Forprenu' eo 'Error', 'Eraro' eo 'Exit', 'Eliru' eo 'Green', 'Verda' eo 'Red', 'Rosa' eo 'blue', 'blua' eo 'green', 'verda' eo 'red', 'ru\u011da' } TkMsgCatalog.new('::tk') { eo '&Abort', '&\u0108esigo' eo '&About...', 'Pri...' eo 'All Files', '\u0108ioj dosieroj' eo 'Application Error', 'Aplikoerraro' eo '&Blue', '&Blua' eo '&Cancel', '&Rezignu' eo 'Cannot change to the directory "%1\$s".' "\n" 'Permission denied.', 'Neeble \u0109angi al dosierulon "%1\$s".' "\n" 'Vi ne rajtas tion.' eo 'Choose Directory', 'Elektu Dosierujo' eo '&Clear', '&Klaru' eo '&Clear Console', '&Klaru konzolon' eo 'Color', 'Farbo' eo 'Console', 'Konzolo' eo '&Copy', '&Kopiu' eo 'Cu&t', '&Enpo\u015digu' eo '&Delete', '&Forprenu' eo 'Details >>', 'Detaloj >>' eo 'Directory "%1\$s" does not exist.', 'La dosierujo "%1\$s" ne ekzistas.' eo '&Directory:', '&Dosierujo:' eo '&Edit', '&Redaktu' eo 'Error: %1\$s', 'Eraro: %1\$s' eo 'E&xit', '&Eliru' eo '&File', '&Dosiero' eo 'File "%1\$s" already exists.' "\n" 'Do you want to overwrite it?', 'La dosiero "%1\$s" jam ekzistas.' "\n" '\u0108u vi volas anstata\u00fbigi la dosieron?' eo 'File "%1\$s" already exists.' "\n\n", 'La dosiero "%1\$s" jam egzistas.' "\n\n" eo 'File "%1\$s" does not exist.', 'La dosierp "%1\$s" ne estas.' eo 'File &name:', 'Dosiero&nomo:' eo 'File &names:', 'Dosiero&nomoj:' eo 'Files of &type:', 'Dosieroj de &Typo:' eo 'Fi&les:', 'Do&sieroj:' eo '&Filter', '&Filtrilo' eo 'Fil&ter:', '&Filtrilo:' eo '&Green', '&Verda' eo '&Help', '&Helpu' eo 'Hi', 'Saluton' eo '&Hide Console', '&Ka\u015du konzolon' eo '&Ignore', '&Ignoru' eo 'Invalid file name "%1\$s".', 'Malvalida dosieronomo "%1\$s".' eo 'Log Files', 'Protokolo' eo '&No', '&Ne' eo 'OK' eo 'Ok' eo 'Open', 'Malfermu' eo '&Open', '&Malfermu' eo 'Open Multiple Files', 'Melfermu multan dosierojn' eo 'P&aste', '&Elpo\u015digi' eo '&Quit', '&Finigu' eo '&Red', '&Rosa' eo 'Replace existing file?', '\u0108u anstata\u00fbu ekzistantan dosieron?' eo '&Retry', '&Ripetu' eo '&Save', '&Savu' eo 'Save As', 'Savu kiel' eo 'Save To Log', 'Savu en protokolon' eo 'Select Log File', 'Elektu prokolodosieron' eo 'Select a file to source', 'Elektu dosieron por interpreti' eo '&Selection:', '&Elekto:' eo 'Skip Messages', 'transsaltu pluajn mesa\u011dojn' eo '&Source...', '&Fontoprogramo...' eo 'Tcl Scripts', 'Tcl-skriptoj' eo 'Tcl for Windows', 'Tcl por vindoso' eo 'Text Files', 'Tekstodosierojn' eo '&Yes', '&Jes' eo 'abort', '\u0109esigo' eo 'blue', 'blua' eo 'cancel', 'rezignu' eo 'extension', 'ekspansio' eo 'extensions', 'ekspansioj' eo 'green', 'verda' eo 'ignore', 'ignorieren' eo 'red', 'ru\u011da' eo 'retry', 'ripetu' eo 'yes', 'jes' } ================================================ FILE: ext/tk/sample/msgs_rb/es.msg ================================================ TkMsgCatalog.new('::tkmsgcat_demo') { es "Application Error", "Error de la aplicaci\\u00f3n" es "Blue", "Azul" es "Color", "Color" es "Delete", "Borrar" es "Error", "Error" es "Exit", "Salir" es "Green", "Verde" es "Red", "Rojo" es "blue", "azul" es "green", "verde" es "red", "rojo" } TkMsgCatalog.new('::tk') { es "&Abort", "&Abortar" es "About...", "Acerca de ..." es "All Files", "Todos los archivos" es "Application Error", "Error de la aplicaci\\u00f3n" es "&Blue", "&Azul" es "&Cancel", "&Cancelar" es "Cannot change to the directory \"%1\$s\".\nPermission denied.", "No es posible acceder al directorio \"%1\$s\".\nPermiso denegado." es "Choose Directory", "Elegir directorio" es "Clear", "Borrar" es "Color", "Color" es "Console", "Consola" es "Copy", "Copiar" es "Cut", "Cortar" es "Delete", "Borrar" es "Details >>", "Detalles >>" es "Directory \"%1\$s\" does not exist.", "El directorio \"%1\$s\" no existe." es "&Directory:", "&Directorio:" es "Error: %1\$s", "Error: %1\$s" es "Exit", "Salir" es "File \"%1\$s\" already exists.\nDo you want to overwrite it?", "El archivo \"%1\$s\" ya existe.\nDesea sobreescribirlo?" es "File \"%1\$s\" already exists.\n\n", "El archivo \"%1\$s\" ya existe.\n\n" es "File \"%1\$s\" does not exist.", "El archivo \"%1\$s\" no existe." es "File &name:", "&Nombre de archivo:" es "File &names:", "&Nombres de archivo:" es "Files of &type:", "Archivos de &tipo:" es "Fi&les:", "&Archivos:" es "&Filter", "&Filtro" es "Fil&ter:", "Fil&tro:" es "&Green", "&Verde" es "Hi", "Hola" es "Hide Console", "Esconder la consola" es "&Ignore", "&Ignorar" es "Invalid file name \"%1\$s\".", "Nombre de archivo inv\\u00e1lido \"%1\$s\"." es "Log Files", "Ficheros de traza" es "&No", "&No" es "&OK", "&OK" es "Ok", "Ok" es "Open", "Abrir" es "&Open", "&Abrir" es "Open Multiple Files", "Abrir m\\u00faltiples archivos" es "Paste", "Pegar" es "Quit", "Abandonar" es "&Red", "&Rojo" es "Replace existing file?", "Reemplazar el archivo existente?" es "&Retry", "&Reintentar" es "&Save", "&Salvar" es "Save As", "Salvar como" es "Save To Log", "Salvar al archivo de traza" es "Select Log File", "Elegir un archivo de traza" es "Select a file to source", "Seleccionar un archivo a evaluar" es "&Selection:", "&Selecci\\u00f3n:" es "Skip Messages", "Omitir los mensajes" es "Source...", "Evaluar..." es "Tcl Scripts", "Scripts Tcl" es "Tcl for Windows", "Tcl para Windows" es "Text Files", "Archivos de texto" es "&Yes", "&S\\u00ed" es "abort", "abortar" es "blue", "azul" es "cancel", "cancelar" es "extension", "extensi\\u00f3n" es "extensions", "extensiones" es "green", "verde" es "ignore", "ignorar" es "ok", "ok" es "red", "rojo" es "retry", "reintentar" es "yes", "s\\u00ed" } ================================================ FILE: ext/tk/sample/msgs_rb/fr.msg ================================================ TkMsgCatalog.new('::tkmsgcat_demo') { fr 'Application Error', "Erreur d'application" fr 'Blue', 'Bleu' fr 'Color', 'Couleur' fr 'Delete', 'Effacer' fr 'Error', 'Erreur' fr 'Exit', 'Quitter' fr 'Green', 'Vert' fr 'Red', 'Rouge' fr 'blue', 'bleu' fr 'green', 'vert' fr 'red', 'rouge' } TkMsgCatalog.new('::tk') { fr '&Abort', '&Annuler' fr 'About...', '\u00c0 propos...' fr 'All Files', 'Tous les fichiers' fr 'Application Error', "Erreur d'application" fr '&Blue', '&Bleu' fr '&Cancel', '&Annuler' fr 'Cannot change to the directory "%1\$s".' "\n" 'Permission denied.', 'Impossible d\'acc\u00e9der au r\u00e9pertoire "%1\$s".' "\n" 'Permission refus\u00e9e.' fr 'Choose Directory', 'Choisir r\u00e9pertoire' fr 'Clear', 'Effacer' fr 'Color', 'Couleur' fr 'Console' fr 'Copy', 'Copier' fr 'Cut', 'Couper' fr 'Delete', 'Effacer' fr 'Details >>', 'D\u00e9tails >>' fr 'Directory "%1\$s" does not exist.', 'Le r\u00e9pertoire "%1\$s" n\'existe pas.' fr '&Directory:', '&R\u00e9pertoire:' fr 'Error: %1\$s', 'Erreur: %1\$s' fr 'Exit', 'Quitter' fr 'File "%1\$s" already exists.' "\n" 'Do you want to overwrite it?', 'Le fichier "%1\$s" existe d\u00e9j\u00e0.' "\n" 'Voulez-vous l\'\u00e9craser?' fr 'File "%1\$s" already exists.' "\n\n", 'Le fichier "%1\$s" existe d\u00e9j\u00e0.' "\n\n" fr 'File "%1\$s" does not exist.', 'Le fichier "%1\$s" n\'existe pas.' fr 'File &name:', '&Nom de fichier:' fr 'File &names:', '&Noms de fichiers:' fr 'Files of &type:', '&Type de fichiers:' fr 'Fi&les:', 'Fich&iers:' fr '&Filter', '&Filtre' fr 'Fil&ter:', 'Fil&tre:' fr '&Green', '&Vert' fr 'Hi', 'Salut' fr 'Hide Console', 'Cacher la Console' fr '&Ignore', '&Ignorer' fr 'Invalid file name "%1\$s".', 'Nom de fichier invalide "%1\$s".' fr 'Log Files', 'Fichiers de trace' fr '&No', '&Non' fr '&OK' fr 'Ok' fr 'Open', 'Ouvrir' fr '&Open', '&Ouvrir' fr 'Open Multiple Files', 'Ouvrir plusieurs fichiers' fr 'Paste', 'Coller' fr 'Quit', 'Quitter' fr '&Red', '&Rouge' fr 'Replace existing file?', 'Remplacer le fichier existant?' fr '&Retry', '&R\u00e9-essayer' fr '&Save', '&Sauvegarder' fr 'Save As', 'Sauvegarder sous' fr 'Save To Log', 'Sauvegarde au fichier de trace' fr 'Select Log File', 'Choisir un fichier de trace' fr 'Select a file to source', 'Choisir un fichier \u00e0 \u00e9valuer' fr '&Selection:', '&S\u00e9lection:' fr 'Skip Messages', 'Omettre les messages' fr 'Source...', '\u00c9valuer...' fr 'Tcl Scripts', 'Scripts Tcl' fr 'Tcl for Windows', 'Tcl pour Windows' fr 'Text Files', 'Fichiers texte' fr '&Yes', '&Oui' fr 'abort', 'abandonner' fr 'blue', 'bleu' fr 'cancel', 'annuler' fr 'extension' fr 'extensions' fr 'green', 'vert' fr 'ignore', 'ignorer' fr 'ok' fr 'red', 'rouge' fr 'retry', 'r\u00e9essayer' fr 'yes', 'oui' } ================================================ FILE: ext/tk/sample/msgs_rb/it.msg ================================================ TkMsgCatalog.new('::tkmsgcat_demo') { it "Application Error", "Errore dell' applicazione" it "Blue", "Blu" it "Color", "Colore" it "Delete", "Incolla" it "Error", "Errore" it "Exit", "Esci" it "Green", "Verde" it "Red", "Rosso" it "blue", "blu" it "green", "verde" it "red", "rosso" } TkMsgCatalog.new('::tk') { it "&Abort", "&Interrompi" it "About...", "Informazioni ..." it "All Files", "Tutti i file" it "Application Error", "Errore dell' applicazione" it "&Blue", "&Blu" it "&Cancel", "&Annulla" it "Cannot change to the directory \"%1\$s\".\nPermission denied.", "Impossibile accedere alla directory \"%1\$s\".\nPermesso negato." it "Choose Directory", "Scegli directory" it "Clear", "Azzera" it "Color", "Colore" it "Console" it "Copy", "Copia" it "Cut", "Taglia" it "Delete", "Incolla" it "Details >>", "Dettagli >>" it "Directory \"%1\$s\" does not exist.", "La directory \"%1\$s\" non esiste." it "&Directory:" it "Error: %1\$s", "Errore: %1\$s" it "Exit", "Esci" it "File \"%1\$s\" already exists.\nDo you want to overwrite it?", "Il file \"%1\$s\" esiste gi\\u00e0.\nVuoi sovrascriverlo?" it "File \"%1\$s\" already exists.\n\n", "Il file \"%1\$s\" esiste gi\\u00e0.\n\n" it "File \"%1\$s\" does not exist.", "Il file \"%1\$s\" non esiste." it "File &name:", "&Nome del file:" it "File &names:", "&Nomi dei file:" it "Files of &type:", "File di &tipo:" it "Fi&les:", "Fi&le:" it "&Filter", "&Filtro" it "Fil&ter:", "Fil&tro:" it "&Green", "&Verde" it "Hi", "Salve" it "Hide Console", "Nascondi la console" it "&Ignore", "&Ignora" it "Invalid file name \"%1\$s\".", "Nome di file non valido \"%1\$s\"." it "Log Files", "File di log" it "&No" it "&OK" it "Ok" it "&Open", "A&pri" it "Open", "Apri" it "Open Multiple Files", "Apri file multipli" it "Paste", "Incolla" it "Quit", "Esci" it "&Red", "&Rosso" it "Replace existing file?", "Sostituisci il file esistente?" it "&Retry", "&Riprova" it "&Save", "&Salva" it "Save As", "Salva come" it "Save To Log", "Salva il log" it "Select Log File", "Scegli un file di log" it "Select a file to source", "Scegli un file da eseguire" it "&Selection:", "&Selezione:" it "Skip Messages", "Salta i messaggi" it "Source...", "Esegui..." it "Tcl Scripts", "Scripts Tcl" it "Tcl for Windows", "Tcl per Windows" it "Text Files", "File di testo" it "&Yes", "&Si" it "abort", "interrompi" it "blue", "blu" it "cancel", "annulla" it "extension", "estensione" it "extensions", "estensioni" it "green", "verde" it "ignore", "ignora" it "ok" it "red", "rosso" it "retry", "riprova" it "yes", "si" } ================================================ FILE: ext/tk/sample/msgs_rb/ja.msg ================================================ TkMsgCatalog.new('::tkmsgcat_demo') { ja 'Application Error', '\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u30A8\u30E9\u30FC' ja 'Blue', '\u9752' ja 'Color', '\u80CC\u666F\u8272' ja 'Delete', '\u6D88\u53BB' ja 'Error', '\u30A8\u30E9\u30FC' ja 'Exit', '\u7D42\u4E86' ja 'Green', '\u7DD1' ja 'Red', '\u8D64' ja 'blue', '\u9752' ja 'green', '\u7DD1' ja 'red', '\u8D64' } ================================================ FILE: ext/tk/sample/msgs_rb/nl.msg ================================================ TkMsgCatalog.new('::tkmsgcat_demo') { nl "Application Error", "Toepassingsfout" nl "Blue", "Blauw" nl "Color", "Kleur" nl "Delete", "Wissen" nl "Error", "Fout" nl "Exit", "Be\\u00ebindigen" nl "Green", "Groen" nl "Red", "Rood" nl "blue", "blauw" nl "green", "groen" nl "red", "rood" } TkMsgCatalog.new('::tk') { nl "\"%1\$s\" must be an absolute pathname", "\"%1\$s\" moet een absolute pad-naam zijn" nl "%1\$s is not a toplevel window", "%1\$s is geen toplevel window" nl ", or", ", of" nl "-default, -icon, -message, -parent, -title, or -type", "-default, -icon, -message, -parent, -title, of -type" nl "-initialdir, -mustexist, -parent, or -title", "-initialdir, -mustexist, -parent, of -title" nl "&Abort", "&Afbreken" nl "About...", "Over..." nl "All Files", "Alle Bestanden" nl "Application Error", "Toepassingsfout" nl "&Blue", "&Blauw" nl "&Cancel", "&Annuleren" nl "Cannot change to the directory \"%1\$s\".\nPermission denied.", "Kan niet naar map \"%1\$s\" gaan.\nU heeft hiervoor geen toestemming." nl "Choose Directory", "Kies map" nl "Clear", "Wissen" nl "Clear entry, Press OK; Enter %1\$s, press OK", "Wis veld, Druk op OK; typ %1\$s in, druk op OK" nl "&Clear Console", "&Wis Console" nl "Color", "Kleur" nl "Console" nl "Copy", "Kopi\\u00ebren" nl "Cut", "Knippen" nl "Delete", "Wissen" nl "Details" nl "Details >>" nl "Directory \"%1\$s\" does not exist.", "Map \"%1\$s\" bestaat niet." nl "&Directory:", "&Map:" nl "Edit", "Bewerken" nl "Enter \"%1\$s\", press OK", "Typ \"%1\$s\", druk op OK" nl "Enter \"%1\$s\", press OK, enter \"%2\$s\", press OK", "Typ \"%1\$s\", druk op OK, typ \"%2\$s\", druk op OK" nl "Error: %1\$s", "Fout: %1\$s" nl "Exit", "Be\\u00ebindigen" nl "File", "Bestand" nl "File \"%1\$s\" already exists.\n\n", "Bestand \"%1\$s\" bestaat al.\n\n" nl "File \"%1\$s\" already exists.\nDo you want to overwrite it?", "Bestand \"%1\$s\" bestaat al.\nWilt u het overschrijven?" nl "File \"%1\$s\" does not exist.", "Bestand \"%1\$s\" bestaat niet." nl "File &name:", "Bestands&naam:" nl "File &names:", "Bestands&namen:" nl "Files of &type:", "Bestanden van het &type:" nl "Fi&les:", "&Bestanden:" nl "&Filter" nl "Fil&ter:" nl "&Green", "&Groen" nl "Hi", "H\\u00e9" nl "Hide Console", "Verberg Console" nl "&Ignore", "&Negeren" nl "Invalid file name \"%1\$s\".", "Ongeldige bestandsnaam \"%1\$s\"." nl "Log Files", "Log Bestanden" nl "&No", "&Nee" nl "&OK" nl "Ok" nl "&Open", "&Openen" nl "Open", "Openen" nl "Open Multiple Files", "Open meerdere bestanden" nl "Paste", "Plakken" nl "Please press %1\$s", "Druk op %1\$s, A.U.B." nl "Please press ok", "Druk op ok, A.U.B." nl "Press Cancel", "Druk op Annuleren" nl "Press Ok", "Druk op Ok" nl "Quit", "Stoppen" nl "&Red", "&Rood" nl "Replace existing file?", "Vervang bestaand bestand?" nl "&Retry", "&Herhalen" nl "&Save", "Op&slaan" nl "Save As", "Opslaan als" nl "Save To Log", "Opslaan naar Log" nl "Select Log File", "Selecteer Log bestand" nl "Select a file to source", "Selecteer bronbestand" nl "&Selection:", "&Selectie:" nl "Skip Messages", "Berichten overslaan" nl "Source...", "Bron..." nl "Tcl Scripts" nl "Tcl for Windows", "Tcl voor Windows" nl "Text Files", "Tekstbestanden" nl "&Yes", "&Ja" nl "abort", "afbreken" nl "abort, retry, ignore, ok, cancel, no, or yes", "afbreken, opnieuw, negeren, ok, annuleren, nee, of ja" nl "abortretryignore, ok, okcancel, retrycancel, yesno, or yesnocancel", "abortretryignore, ok, okcancel, retrycancel, yesno, of yesnocancel" nl "bad %1\$s value \"%2\$s\": must be %3\$s", "verkeerde %1\$s waarde \"%2\$s\": moet zijn %3\$s" nl "bad file type \"%1\$s\", should be", "verkeerd bestandstype \"%1\$s\", moet zijn" nl "bad option \"%1\$s\": should be %2\$s", "verkeerde optie \"%1\$s\": moet zijn %2\$s" nl "bad window path name \"%1\$s\"", "verkeerde window-padnaam \"%1\$s\"" nl "blue", "blauw" nl "can't post %1\$s: it isn't a descendant of %2\$s (this is a new requirement in Tk versions 3.0 and later)", "kan %1\$s niet verzenden: het is geen afstammeling van %2\$s (dit is een nieuwe eis in Tk versies 3.0 en later)" nl "cancel", "annuleren" nl "default button index greater than number of buttons specified for tk_dialog", "default knop index is groter dan het aantal knoppen beschikbaar voor tk_dialog" nl "display name to use (current one otherwise)", "te gebruiken schermnaam (anders huidige scherm)" nl "error, info, question, or warning", "error, info, question, of warning" nl "extension" nl "extensions" nl "focus group \"%1\$s\" doesn't exist", "focusgroep \"%1\$s\" bestaat niet" nl "green", "groen" nl "history event %1\$s" nl "ignore", "negeren" nl "invalid default button \"%1\$s\"", "ongeldige default knop \"%1\$s\"" nl "macType" nl "macTypes" nl "must specify a background color", "een achtergrondkleur is verplicht" nl "name of the slave interpreter", "naam van de slaaf-interpreter" nl "no winfo screen . nor env(DISPLAY)", "geen winfo scherm . noch env(DISPLAY)" nl "ok" nl "red", "rood" nl "retry", "opnieuw" nl "should contain 5 or 4 elements", "moet 4 of 5 elementen bevatten" nl "spec" nl "tk_chooseDirectory command", "tk_chooseDirectory opdracht" nl "tk_chooseDirectory command, cancel gives null", "tk_chooseDirectory opdracht, annuleren geeft lege waarde" nl "tk_chooseDirectory command, initialdir", "tk_chooseDirectory opdracht, initi\\u00eble map" nl "yes", "ja" } ================================================ FILE: ext/tk/sample/msgs_rb/pl.msg ================================================ TkMsgCatalog.new('::tkmsgcat_demo') { pl 'Application Error', 'Bl\u0105d w Programie' pl 'Blue', 'Niebieski' pl 'Color', 'Kolor' pl 'Delete', 'Usu\u0144' pl 'Error', 'B\u0142\u0105d' pl 'Exit', 'Zako\u0144cz' pl 'Green', 'Zielony' pl 'Red', 'Czerwonz' pl 'blue', 'niebieski' pl 'green', 'zielony' pl 'red', 'czerwony' } TkMsgCatalog.new('::tk') { pl '&Abort', '&Anuluj' pl '&About...', 'O Programie...' pl 'All Files', 'Wszystkie pliki' pl 'Application Error', 'Bl\u0105d w Programie' pl '&Blue', '&Niebieski' pl '&Cancel', '&Anuluj' pl 'Cannot change to the directory "%1\$s".' "\n" 'Permission denied.', 'Katalog "%1\$s" nie mo\u017ce zosta\u0107 odczytany lub nie istnieje.' pl 'Choose Directory', 'Wybierz katalog' pl '&Clear', '&Wyczy\u015b\u0107' pl '&Clear Console', '&Wyczy\u015b\u0107 konsol\u0119' pl 'Color', 'Kolor' pl 'Console', 'Konsola' pl '&Copy', '&Kopiuj' pl 'Cu&t', '&Wytnij' pl '&Delete', '&Usu\u0144' pl 'Details >>', 'Detale >>' pl 'Directory "%1\$s" does not exist.', 'Katalog "%1\$s" nie istniej.' pl '&Directory:', '&Katalog:' pl '&Edit', '&Edytuj' pl 'Error: %1\$s', 'B\u0142\u0105d: %1\$s' pl 'E&xit', '&Zako\u0144cz' pl '&File', '&Plik' pl 'File "%1\$s" already exists.' "\n" 'Do you want to overwrite it?', 'Plik "%1\$s" ju\u017c istnieje.' "\n" 'Czy chcesz go zast\u0105pi\u0107?' pl 'File "%1\$s" already exists.' "\n\n", 'Plik "%1\$s" ju\u017c istnieje. ' "\n\n" pl 'File "%1\$s" does not exist.', 'Plik "%1\$s" nie istnieje.' pl 'File &name:', 'Nazwa &pliku:' pl 'File &names:', 'Nazwy &plik\u00f3w:' pl 'Files of &type:', 'Pliki &typu:' pl 'Fi&les:', 'Pli&ki:' pl '&Filter', '&Filter' pl 'Fil&ter:', '&Filter:' pl '&Green', '&Zielony' pl '&Help', '&Pomoc' pl 'Hi', 'Witaj' pl '&Hide Console', '&Schowaj konsol\u0119' pl '&Ignore', '&Ignoruj' pl 'Invalid file name "%1\$s".', 'Niew\u0142a\u015bciwa nazwa pliku "%1\$s".' pl 'Log Files', 'Protoko\u0142uj' pl '&No', '&Nie' pl 'OK' pl 'Ok' pl 'Open', 'Wczytaj' pl '&Open', '&Wczytaj' pl 'Open Multiple Files', 'Wczytuj wiele plik\u00f3w' pl 'P&aste', '&Wklej' pl '&Quit', '&Zako\u0144cz' pl '&Red', '&Czerwonz' pl 'Replace existing file?', 'Czy zost\u0105pi\u0107 instniej\u0105cy plik?' pl '&Retry', '&Powt\u00f3rz' pl '&Save', '&Zapisz' pl 'Save As', 'Zapisz jako' pl 'Save To Log', 'Wpisz do protoko\u0142u' pl 'Select Log File', 'Wybierz plik proko\u0142u' pl 'Select a file to source', 'Wybierz plik do wykonania' pl '&Selection:', '&Wyb\u00f3r:' pl 'Skip Messages', 'Omi\u0144 pozosta\u0142e komunikaty' pl '&Source...', '&Kod \u017ar\u00f3d\u0142owy...' pl 'Tcl Scripts', 'Tcl-skrypty' pl 'Tcl for Windows', 'Tcl dla Okienek (Windows)' pl 'Text Files', 'Pliki Tekstowe' pl '&Yes', '&Tak' pl 'abort', 'zako\u0144cz' pl 'blue', 'niebieski' pl 'cancel', 'anuluj' pl 'extension', 'rozszerzenie' pl 'extensions', 'rozszerzenia' pl 'green', 'zielony' pl 'ignore', 'ignoruj' pl 'red', 'czerwony' pl 'retry', 'potw\u00f3rz' pl 'yes', 'tak' } ================================================ FILE: ext/tk/sample/msgs_rb/ru.msg ================================================ TkMsgCatalog.new('::tkmsgcat_demo') { ru 'Application Error', '\u041e\u0448\u0438\u0431\u043a\u0430 \u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0435' ru 'Blue', ' \u0413\u043e\u043b\u0443\u0431\u043e\u0439' ru 'Color', '\u0426\u0432\u0435\u0442' ru 'Delete', '\u0423\u0434\u0430\u043b\u0438\u0442\u044c' ru 'Error', '\u041e\u0448\u0438\u0431\u043a\u0430' ru 'Exit', '\u0412\u044b\u0445\u043e\u0434' ru 'Green', '\u0417\u0435\u043b\u0435\u043d\u044b\u0439' ru 'Red', '\u041a\u0440\u0430\u0441\u043d\u044b\u0439' ru 'blue', ' \u0433\u043e\u043b\u0443\u0431\u043e\u0439' ru 'green', ' \u0437\u0435\u043b\u0435\u043d\u044b\u0439' ru 'red', ' \u043a\u0440\u0430\u0441\u043d\u044b\u0439' } TkMsgCatalog.new('::tk') { ru '&Abort', '&\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c' ru 'About...', '\u041f\u0440\u043e...' ru 'All Files', '\u0412\u0441\u0435 \u0444\u0430\u0439\u043b\u044b' ru 'Application Error', '\u041e\u0448\u0438\u0431\u043a\u0430 \u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0435' ru '&Blue', ' &\u0413\u043e\u043b\u0443\u0431\u043e\u0439' ru '&Cancel', '\u041e\u0442&\u043c\u0435\u043d\u0430' ru 'Cannot change to the directory "%1\$s".' "\n" 'Permission denied.' \ '\u041d\u0435 \u043c\u043e\u0433\u0443 \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 "%1\$s".' "\n" '\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u0430\u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0430' ru 'Choose Directory', '\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433' ru 'Clear', '\u041e\u0447\u0438\u0441\u0442\u0438\u0442\u044c' ru 'Color', '\u0426\u0432\u0435\u0442' ru 'Console', '\u041a\u043e\u043d\u0441\u043e\u043b\u044c' ru 'Copy', '\u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c' ru 'Cut', '\u0412\u044b\u0440\u0435\u0437\u0430\u0442\u044c' ru 'Delete', '\u0423\u0434\u0430\u043b\u0438\u0442\u044c' ru 'Details >>', '\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 >>' ru 'Directory "%1\$s" does not exist.', '\u041a\u0430\u0442\u0430\u043b\u043e\u0433\u0430 "%1\$s" \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442.' ru '&Directory:', '&\u041a\u0430\u0442\u0430\u043b\u043e\u0433:' ru 'Error: %1\$s', '\u041e\u0448\u0438\u0431\u043a\u0430: %1\$s' ru 'Exit', '\u0412\u044b\u0445\u043e\u0434' ru 'File "%1\$s" already exists.' "\n" 'Do you want to overwrite it?' \ '\u0424\u0430\u0439\u043b "%1\$s" \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442.' "\n" '\u0417\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0435\u0433\u043e?' ru 'File "%1\$s" already exists.' "\n\n", '\u0424\u0430\u0439\u043b "%1\$s" \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442.' "\n\n" ru 'File "%1\$s" does not exist.', '\u0424\u0430\u0439\u043b "%1\$s" \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d.' ru 'File &name:', '&\u0418\u043c\u044f \u0444\u0430\u0439\u043b\u0430:' ru 'File &names:', '&\u0418\u043c\u0435\u043d\u0430 \u0444\u0430\u0439\u043b\u043e\u0432:' ru 'Files of &type:', '&\u0422\u0438\u043f \u0444\u0430\u0439\u043b\u043e\u0432:' ru 'Fi&les:', '\u0424\u0430\u0439&\u043b\u044b:' ru '&Filter', '&\u0424\u0438\u043b\u044c\u0442\u0440' ru 'Fil&ter:', '\u0424\u0438\u043b\u044c&\u0442\u0440:' ru '&Green', ' &\u0417\u0435\u043b\u0435\u043d\u044b\u0439' ru 'Hi', '\u041f\u0440\u0438\u0432\u0435\u0442' ru 'Hide Console', '\u0421\u043f\u0440\u044f\u0442\u0430\u0442\u044c \u043a\u043e\u043d\u0441\u043e\u043b\u044c' ru '&Ignore', '&\u0418\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c' ru 'Invalid file name "%1\$s".', '\u041d\u0435\u0432\u0435\u0440\u043d\u043e\u0435 \u0438\u043c\u044f \u0444\u0430\u0439\u043b\u0430 "%1\$s".' ru 'Log Files', '\u0424\u0430\u0439\u043b\u044b \u0436\u0443\u0440\u043d\u0430\u043b\u0430' ru '&No', '&\u041d\u0435\u0442' ru '&OK', '&\u041e\u041a' ru 'Ok', '\u0414\u0430' ru 'Open', '\u041e\u0442\u043a\u0440\u044b\u0442\u044c' ru '&Open', '&\u041e\u0442\u043a\u0440\u044b\u0442\u044c' ru 'Open Multiple Files', '\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0444\u0430\u0439\u043b\u043e\u0432' ru 'Paste', '\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c' ru 'Quit', '\u0412\u044b\u0445\u043e\u0434' ru '&Red', ' &\u041a\u0440\u0430\u0441\u043d\u044b\u0439' ru 'Replace existing file?', '\u0417\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0444\u0430\u0439\u043b?' ru '&Retry', '&\u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c' ru '&Save', '&\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c' ru 'Save As', '\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u0430\u043a' ru 'Save To Log', '\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u0436\u0443\u0440\u043d\u0430\u043b' ru 'Select Log File', '\u0412\u044b\u0431\u0440\u0430\u0442\u044c \u0436\u0443\u0440\u043d\u0430\u043b' ru 'Select a file to source', '\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0444\u0430\u0439\u043b \u0434\u043b\u044f \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0446\u0438\u0438' ru '&Selection:', '&Selection:' ru 'Skip Messages', '\u041f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f' ru 'Source...', '\u0418\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b...' ru 'Tcl Scripts', '\u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u043d\u0430 \u044f\u0437\u044b\u043a\u0435 TCL' ru 'Tcl for Windows', 'TCL \u0434\u043b\u044f Windows' ru 'Text Files', '\u0422\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u0444\u0430\u0439\u043b\u044b' ru '&Yes', '&\u0414\u0430' ru 'abort', '\u043e\u0442\u043c\u0435\u043d\u0430' ru 'blue', ' \u0433\u043e\u043b\u0443\u0431\u043e\u0439' ru 'cancel', '\u043e\u0442\u043c\u0435\u043d\u0430' ru 'extension', '\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435' ru 'extensions', '\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f' ru 'green', ' \u0437\u0435\u043b\u0435\u043d\u044b\u0439' ru 'ignore', '\u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c' ru 'ok', '\u043e\u043a' ru 'red', ' \u043a\u0440\u0430\u0441\u043d\u044b\u0439' ru 'retry', '\u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c' ru 'yes', '\u0434\u0430' } ================================================ FILE: ext/tk/sample/msgs_rb2/README ================================================ Message catalogs in this directory are written in encodings except UTF-8. As if you have a trouble to edit UTF-8 text, you can write message catalogs in your familier encoding. Please see '../msgs_rb/README' too. ================================================ FILE: ext/tk/sample/msgs_rb2/de.msg ================================================ TkMsgCatalog.new('::tkmsgcat_demo') { de 'Application Error', 'Applikationsfehler' de 'Blue', 'Blau' de 'Color', 'Farbe' de 'Delete', 'Lschen', 'iso8859-1' de 'Error', 'Fehler' de 'Exit', 'Ende' de 'Green', 'Grn', 'iso8859-1' de 'Red', 'Rot' de 'blue', 'blau' de 'green', 'grn', 'iso8859-1' de 'red', 'rot' } TkMsgCatalog.new('::tk') { de "&Abort", "&Abbruch" de "&About...", "&ber...", 'iso8859-1' de "All Files", "Alle Dateien" de "Application Error", "Applikationsfehler" de "&Blue", "&Blau" de "&Cancel", "&Abbruch" de "Cannot change to the directory \"%1\$s\".\nPermission denied.", "Kann nicht in das Verzeichnis \"%1\$s\" wechseln.\nKeine Rechte vorhanden." de "Choose Directory", "Whle Verzeichnis", 'iso8859-1' de "&Clear", "&Rcksetzen", 'iso8859-1' de "&Clear Console", "&Konsole lschen", 'iso8859-1' de "Color", "Farbe" de "Console", "Konsole" de "&Copy", "&Kopieren" de "Cu&t", "Aus&schneiden" de '&Delete', '&Lschen', 'iso8859-1' de "Details >>" de "Directory \"%1\$s\" does not exist.", "Das Verzeichnis \"%1\$s\" existiert nicht." de "&Directory:", "&Verzeichnis:" de "&Edit", "&Bearbieten" de "Error: %1\$s", "Fehler: %1\$s" de "E&xit", "&Ende" de "&File", "&Datei" de "File \"%1\$s\" already exists.\nDo you want to overwrite it?", "Die Datei \"%1\$s\" ist bereits vorhanden.\nWollen sie diese Datei berschreiben ?", 'iso8859-1' de "File \"%1\$s\" already exists.\n\n", "Die Datei \"%1\$s\" ist bereits vorhanden.\n\n" de "File \"%1\$s\" does not exist.", "Die Datei \"%1\$s\" existiert nicht." de "File &name:", "Datei&name:" de "File &names:", "Datei&namen:" de "Files of &type:", "Dateien des &Typs:" de "Fi&les:", "Dat&eien:" de "&Filter" de "Fil&ter:" de '&Green', '&Grn', 'iso8859-1' de "&Help", "&Hilfe" de "Hi", "Hallo" de "&Hide Console", "&Konsole unsichtbar machen" de "&Ignore", "&Ignorieren" de "Invalid file name \"%1\$s\".", "Ungltiger Dateiname \"%1\$s\".", 'iso8859-1' de "Log Files", "Protokolldatei" de "&No", "&Nein" de "OK" de "Ok" de "Open", "ffnen", 'iso8859-1' de "&Open", "&ffnen", 'iso8859-1' de "Open Multiple Files" de "P&aste", "E&infgen", 'iso8859-1' de "&Quit", "&Beenden" de "&Red", "&Rot" de "Replace existing file?", "Existierende Datei ersetzen?" de "&Retry", "&Wiederholen" de "&Save", "&Speichern" de "Save As", "Speichern unter" de "Save To Log", "In Protokoll speichern" de "Select Log File", "Protokolldatei auswhlen", 'iso8859-1' de "Select a file to source", "Auszufhrende Datei auswhlen", 'iso8859-1' de "&Selection:", "Auswah&l:" de "Skip Messages", "Weitere Nachrichten berspringen", 'iso8859-1' de "&Source...", "&Ausfhren...", 'iso8859-1' de "Tcl Scripts", "Tcl-Skripte" de "Tcl for Windows", "Tcl fr Windows", 'iso8859-1' de "Text Files", "Textdateien" de "&Yes", "&Ja" de "abort", "abbrechen" de "blue", "blau" de "cancel", "abbrechen" de "extension", "Erweiterung" de "extensions", "Erweiterungen" de 'green', 'grn', 'iso8859-1' de "ignore", "ignorieren" de "ok" de "red", "rot" de "retry", "wiederholen" de "yes", "ja" } ================================================ FILE: ext/tk/sample/msgs_rb2/ja.msg ================================================ TkMsgCatalog.new('::tkmsgcat_demo') { ja 'Application Error', 'ץꥱ󥨥顼', 'euc-jp' ja 'Blue', '', 'euc-jp' ja 'Color', '', 'euc-jp' ja 'Delete', 'õ', 'euc-jp' ja 'Error', '顼', 'euc-jp' ja 'Exit', 'λ', 'euc-jp' ja 'Green', '', 'euc-jp' ja 'Red', '', 'euc-jp' ja 'blue', '', 'euc-jp' ja 'green', '', 'euc-jp' ja 'red', '', 'euc-jp' } TkMsgCatalog.new('::tk') { ja "&Abort", '', 'euc-jp' ja "About..." ja "All Files", '٤ƤΥե', 'euc-jp' ja "Application Error", 'ץꥱ󥨥顼', 'euc-jp' ja "&Blue", '', 'euc-jp' ja "&Cancel", 'ä', 'euc-jp' ja "Cannot change to the directory \"%1\$s\".\nPermission denied.", "ǥ쥯ȥ \"%1\$s\" ѹǤޤ\nĤޤ", 'euc-jp' ja "Choose Directory", 'ǥ쥯ȥ', 'euc-jp' ja "Clear", 'õ', 'euc-jp' ja "Color", '', 'euc-jp' ja "Console", '󥽡', 'euc-jp' ja "Copy", 'ԡ', 'euc-jp' ja "Cut", 'ڤ', 'euc-jp' ja "Delete", 'õ', 'euc-jp' ja "Details >>", 'ܺ >>', 'euc-jp' ja "Directory \"%1\$s\" does not exist.", '"%1$s" Ȥǥ쥯ȥ¸ߤޤ', 'euc-jp' ja "&Directory:", 'ǥ쥯ȥ', 'euc-jp' ja "Error: %1\$s" ja "Exit", 'λ', 'euc-jp' ja "File \"%1\$s\" already exists.\nDo you want to overwrite it?", "\"%1\$s\" Ȥեϴ¸ߤƤޤ\n񤭴ޤ", 'euc-jp' ja "File \"%1\$s\" already exists.\n\n", "\"%1\$s\" Ȥեϴ¸ߤƤޤ\n\n", 'euc-jp' ja "File \"%1\$s\" does not exist.", '"%1$s" Ȥե¸ߤޤ', 'euc-jp' ja "File &name:", 'ե̾', 'euc-jp' ja "File &names:", 'ե̾', 'euc-jp' ja "Files of &type:", 'ե', 'euc-jp' ja "Fi&les:", 'ե', 'euc-jp' ja "&Filter", 'ե륿', 'euc-jp' ja "Fil&ter:", 'ե륿', 'euc-jp' ja "&Green", '', 'euc-jp' ja "Hi", 'ˤ', 'euc-jp' ja "Hide Console", '󥽡򱣤', 'euc-jp' ja "&Ignore", '̵', 'euc-jp' ja "Invalid file name \"%1\$s\".", '"%1$s" ʥե̾Ǥ', 'euc-jp' ja "Log Files", 'ե', 'euc-jp' ja "&No", '', 'euc-jp' ja "&OK", 'λ', 'euc-jp' ja "OK", 'λ', 'euc-jp' ja "Ok", 'λ', 'euc-jp' ja "Open", '', 'euc-jp' ja "&Open", '', 'euc-jp' ja "Open Multiple Files", 'ʣΥե򳫤', 'euc-jp' ja "Paste", 'Žդ', 'euc-jp' ja "Quit", 'λ', 'euc-jp' ja "&Red", '', 'euc-jp' ja "Replace existing file?", '¸Υե֤ޤ', 'euc-jp' ja "&Retry", 'Ƽ¹', 'euc-jp' ja "&Save", '¸', 'euc-jp' ja "Save As", '̾դ¸', 'euc-jp' ja "Save To Log", '¸', 'euc-jp' ja "Select Log File", 'ե', 'euc-jp' ja "Select a file to source", 'ե', 'euc-jp' ja "&Selection:", '', 'euc-jp' ja "Skip Messages", 'åȤФ', 'euc-jp' ja "Source...", '...', 'euc-jp' ja "Tcl Scripts", 'Tcl ץ', 'euc-jp' ja "Tcl for Windows" ja "Text Files", 'ƥȥե', 'euc-jp' ja "&Yes", 'Ϥ', 'euc-jp' ja "abort", '', 'euc-jp' ja "blue", '', 'euc-jp' ja "cancel", 'ä', 'euc-jp' ja "extension", 'ĥ', 'euc-jp' ja "extensions", 'ĥ', 'euc-jp' ja "green", '', 'euc-jp' ja "ignore", '̵', 'euc-jp' ja "ok", 'λ', 'euc-jp' ja "red", '', 'euc-jp' ja "retry", 'Ƽ¹', 'euc-jp' ja "yes", 'Ϥ', 'euc-jp' } ================================================ FILE: ext/tk/sample/msgs_tk/README ================================================ Almost all of Message-Catalog files in this directory are quoted from Tcl/Tk8.5a1 source archive (only a little are modified for 'tkmsgcat-load_tk.rb'). Please read the file 'license.terms' in this directry (That was included in demo directory of Tcl/Tk8.5a1). ================================================ FILE: ext/tk/sample/msgs_tk/cs.msg ================================================ namespace eval ::tkmsgcat_demo { ::msgcat::mcset cs "Application Error" "Chyba programu" ::msgcat::mcset cs "Blue" "Modr\341" ::msgcat::mcset cs "Color" "Barva" ::msgcat::mcset cs "Delete" "Smazat" ::msgcat::mcset cs "Error" "Chyba" ::msgcat::mcset cs "Exit" "Konec" ::msgcat::mcset cs "Green" "Zelen\341" ::msgcat::mcset cs "Red" "\u010cerven\341" ::msgcat::mcset cs "blue" "modr\341" ::msgcat::mcset cs "green" "zelen\341" ::msgcat::mcset cs "red" "\u010derven\341" } namespace eval ::tk { ::msgcat::mcset cs "&Abort" "&P\u0159eru\u0161it" ::msgcat::mcset cs "About..." "O programu..." ::msgcat::mcset cs "All Files" "V\u0161echny soubory" ::msgcat::mcset cs "Application Error" "Chyba programu" ::msgcat::mcset cs "&Blue" "&Modr\341" ::msgcat::mcset cs "&Cancel" "&Zru\u0161it" ::msgcat::mcset cs "Cannot change to the directory \"%1\$s\".\nPermission denied." "Nemohu zm\u011bnit atku\341ln\355 adres\341\u0159 na \"%1\$s\".\nP\u0159\355stup odm\355tnut." ::msgcat::mcset cs "Choose Directory" "V\375b\u011br adres\341\u0159e" ::msgcat::mcset cs "Clear" "Smazat" ::msgcat::mcset cs "Color" "Barva" ::msgcat::mcset cs "Console" "Konzole" ::msgcat::mcset cs "Copy" "Kop\355rovat" ::msgcat::mcset cs "Cut" "Vy\u0159\355znout" ::msgcat::mcset cs "Delete" "Smazat" ::msgcat::mcset cs "Details >>" "Detaily >>" ::msgcat::mcset cs "Directory \"%1\$s\" does not exist." "Adres\341\u0159 \"%1\$s\" neexistuje." ::msgcat::mcset cs "&Directory:" "&Adres\341\u0159:" ::msgcat::mcset cs "Error: %1\$s" "Chyba: %1\$s" ::msgcat::mcset cs "Exit" "Konec" ::msgcat::mcset cs "File \"%1\$s\" already exists.\n\n" "Soubor \"%1\$s\" ji\u017e existuje.\n\n" ::msgcat::mcset cs "File \"%1\$s\" already exists.\nDo you want to overwrite it?" "Soubor \"%1\$s\" ji\u017e existuje.\nChcete jej p\u0159epsat?" ::msgcat::mcset cs "File \"%1\$s\" does not exist." "Soubor \"%1\$s\" neexistuje." ::msgcat::mcset cs "File &name:" "&Jm\351no souboru:" ::msgcat::mcset cs "File &names:" "&Jm\351na soubor\u016f:" ::msgcat::mcset cs "Files of &type:" "&Typy soubor\u016f:" ::msgcat::mcset cs "Fi&les:" "Sou&bory:" ::msgcat::mcset cs "&Filter" "&Filtr" ::msgcat::mcset cs "Fil&ter:" "Fil&tr:" ::msgcat::mcset cs "&Green" "Ze&len\341" ::msgcat::mcset cs "Hi" ::msgcat::mcset cs "Hide Console" "Skr\375t konsolu" ::msgcat::mcset cs "&Ignore" "&Ignorovat" ::msgcat::mcset cs "Invalid file name \"%1\$s\"." "\u0160patn\351 jm\351no souboru \"%1\$s\"." ::msgcat::mcset cs "Log Files" "Log soubory" ::msgcat::mcset cs "&No" "&Ne" ::msgcat::mcset cs "&OK" ::msgcat::mcset cs "Ok" ::msgcat::mcset cs "Open" "Otev\u0159\355t" ::msgcat::mcset cs "&Open" "&Otev\u0159\355t" ::msgcat::mcset cs "Open Multiple Files" "Otev\u0159\355t v\355ce soubor\u016f" ::msgcat::mcset cs "Paste" "Vlo\u017eit" ::msgcat::mcset cs "Quit" "Skon\u010dit" ::msgcat::mcset cs "&Red" " \u010ce&rven\341" ::msgcat::mcset cs "Replace existing file?" "Nahradit st\341vaj\355c\355 soubor?" ::msgcat::mcset cs "&Retry" "Z&novu" ::msgcat::mcset cs "&Save" "&Ulo\u017eit" ::msgcat::mcset cs "Save As" "Ulo\u017eit jako" ::msgcat::mcset cs "Save To Log" "Ulo\u017eit do logu" ::msgcat::mcset cs "Select Log File" "Vybrat log soubor" ::msgcat::mcset cs "Select a file to source" "Vybrat soubor k nahr\341n\355" ::msgcat::mcset cs "&Selection:" "&V\375b\u011br:" ::msgcat::mcset cs "Skip Messages" "P\u0159esko\u010dit zpr\341vy" ::msgcat::mcset cs "Source..." "Nahr\341t..." ::msgcat::mcset cs "Tcl Scripts" "Tcl skripty" ::msgcat::mcset cs "Tcl for Windows" "Tcl pro Windows" ::msgcat::mcset cs "Text Files" "Textov\351 soubory" ::msgcat::mcset cs "&Yes" "&Ano" ::msgcat::mcset cs "abort" "p\u0159eru\u0161it" ::msgcat::mcset cs "blue" "modr\341" ::msgcat::mcset cs "cancel" "zru\u0161it" ::msgcat::mcset cs "extension" "p\u0159\355pona" ::msgcat::mcset cs "extensions" "p\u0159\355pony" ::msgcat::mcset cs "green" "zelen\341" ::msgcat::mcset cs "ignore" "ignorovat" ::msgcat::mcset cs "ok" ::msgcat::mcset cs "red" "\u010derven\341" ::msgcat::mcset cs "retry" "znovu" ::msgcat::mcset cs "yes" "ano" } ================================================ FILE: ext/tk/sample/msgs_tk/de.msg ================================================ namespace eval ::tkmsgcat_demo { ::msgcat::mcset de "Application Error" "Applikationsfehler" ::msgcat::mcset de "Blue" "Blau" ::msgcat::mcset de "Color" "Farbe" ::msgcat::mcset de "Delete" "L\u00f6schen" ::msgcat::mcset de "Error" "Fehler" ::msgcat::mcset de "Exit" "Ende" ::msgcat::mcset de "Green" "Gr\u00fcn" ::msgcat::mcset de "Red" "Rot" ::msgcat::mcset de "blue" "blau" ::msgcat::mcset de "green" "gr\u00fcn" ::msgcat::mcset de "red" "rot" } namespace eval ::tk { ::msgcat::mcset de "&Abort" "&Abbruch" ::msgcat::mcset de "&About..." "&\u00dcber..." ::msgcat::mcset de "All Files" "Alle Dateien" ::msgcat::mcset de "Application Error" "Applikationsfehler" ::msgcat::mcset de "&Blue" "&Blau" ::msgcat::mcset de "&Cancel" "&Abbruch" ::msgcat::mcset de "Cannot change to the directory \"%1\$s\".\nPermission denied." "Kann nicht in das Verzeichnis \"%1\$s\" wechseln.\nKeine Rechte vorhanden." ::msgcat::mcset de "Choose Directory" "W\u00e4hle Verzeichnis" ::msgcat::mcset de "&Clear" "&R\u00fccksetzen" ::msgcat::mcset de "&Clear Console" "&Konsole l\u00f6schen" ::msgcat::mcset de "Color" "Farbe" ::msgcat::mcset de "Console" "Konsole" ::msgcat::mcset de "&Copy" "&Kopieren" ::msgcat::mcset de "Cu&t" "Aus&schneiden" ::msgcat::mcset de "&Delete" "&L\u00f6schen" ::msgcat::mcset de "Details >>" ::msgcat::mcset de "Directory \"%1\$s\" does not exist." "Das Verzeichnis \"%1\$s\" existiert nicht." ::msgcat::mcset de "&Directory:" "&Verzeichnis:" ::msgcat::mcset de "&Edit" "&Bearbieten" ::msgcat::mcset de "Error: %1\$s" "Fehler: %1\$s" ::msgcat::mcset de "E&xit" "&Ende" ::msgcat::mcset de "&File" "&Datei" ::msgcat::mcset de "File \"%1\$s\" already exists.\nDo you want to overwrite it?" "Die Datei \"%1\$s\" ist bereits vorhanden.\nWollen sie diese Datei \u00fcberschreiben ?" ::msgcat::mcset de "File \"%1\$s\" already exists.\n\n" "Die Datei \"%1\$s\" ist bereits vorhanden.\n\n" ::msgcat::mcset de "File \"%1\$s\" does not exist." "Die Datei \"%1\$s\" existiert nicht." ::msgcat::mcset de "File &name:" "Datei&name:" ::msgcat::mcset de "File &names:" "Datei&namen:" ::msgcat::mcset de "Files of &type:" "Dateien des &Typs:" ::msgcat::mcset de "Fi&les:" "Dat&eien:" ::msgcat::mcset de "&Filter" ::msgcat::mcset de "Fil&ter:" ::msgcat::mcset de "&Green" "&Gr\u00fcn" ::msgcat::mcset de "&Help" "&Hilfe" ::msgcat::mcset de "Hi" "Hallo" ::msgcat::mcset de "&Hide Console" "&Konsole unsichtbar machen" ::msgcat::mcset de "&Ignore" "&Ignorieren" ::msgcat::mcset de "Invalid file name \"%1\$s\"." "Ung\u00fcltiger Dateiname \"%1\$s\"." ::msgcat::mcset de "Log Files" "Protokolldatei" ::msgcat::mcset de "&No" "&Nein" ::msgcat::mcset de "OK" ::msgcat::mcset de "Ok" ::msgcat::mcset de "Open" "\u00d6ffnen" ::msgcat::mcset de "&Open" "\u00d6&ffnen" ::msgcat::mcset de "Open Multiple Files" ::msgcat::mcset de "P&aste" "E&inf\u00fcgen" ::msgcat::mcset de "&Quit" "&Beenden" ::msgcat::mcset de "&Red" "&Rot" ::msgcat::mcset de "Replace existing file?" "Existierende Datei ersetzen?" ::msgcat::mcset de "&Retry" "&Wiederholen" ::msgcat::mcset de "&Save" "&Speichern" ::msgcat::mcset de "Save As" "Speichern unter" ::msgcat::mcset de "Save To Log" "In Protokoll speichern" ::msgcat::mcset de "Select Log File" "Protokolldatei ausw\u00e4hlen" ::msgcat::mcset de "Select a file to source" "Auszuf\u00fchrende Datei ausw\u00e4hlen" ::msgcat::mcset de "&Selection:" "Auswah&l:" ::msgcat::mcset de "Skip Messages" "Weitere Nachrichten \u00fcberspringen" ::msgcat::mcset de "&Source..." "&Ausf\u00fchren..." ::msgcat::mcset de "Tcl Scripts" "Tcl-Skripte" ::msgcat::mcset de "Tcl for Windows" "Tcl f\u00fcr Windows" ::msgcat::mcset de "Text Files" "Textdateien" ::msgcat::mcset de "&Yes" "&Ja" ::msgcat::mcset de "abort" "abbrechen" ::msgcat::mcset de "blue" "blau" ::msgcat::mcset de "cancel" "abbrechen" ::msgcat::mcset de "extension" "Erweiterung" ::msgcat::mcset de "extensions" "Erweiterungen" ::msgcat::mcset de "green" "gr\u00fcn" ::msgcat::mcset de "ignore" "ignorieren" ::msgcat::mcset de "ok" ::msgcat::mcset de "red" "rot" ::msgcat::mcset de "retry" "wiederholen" ::msgcat::mcset de "yes" "ja" } ================================================ FILE: ext/tk/sample/msgs_tk/el.msg ================================================ namespace eval ::tkmsgcat_demo { ::msgcat::mcset el "Application Error" "\u039b\u03ac\u03b8\u03bf\u03c2 \u0395\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae\u03c2" ::msgcat::mcset el "Blue" "\u039c\u03c0\u03bb\u03b5" ::msgcat::mcset el "Color" "\u03a7\u03c1\u03ce\u03bc\u03b1" ::msgcat::mcset el "Delete" "\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae" ::msgcat::mcset el "Error" "\u039b\u03ac\u03b8\u03bf\u03c2" ::msgcat::mcset el "Exit" "\u0388\u03be\u03bf\u03b4\u03bf\u03c2" ::msgcat::mcset el "Green" "\u03a0\u03c1\u03ac\u03c3\u03b9\u03bd\u03bf" ::msgcat::mcset el "Red" "\u039a\u03cc\u03ba\u03ba\u03b9\u03bd\u03bf" ::msgcat::mcset el "blue" "\u03bc\u03c0\u03bb\u03b5" ::msgcat::mcset el "green" "\u03c0\u03c1\u03ac\u03c3\u03b9\u03bd\u03bf" ::msgcat::mcset el "red" "\u03ba\u03cc\u03ba\u03ba\u03b9\u03bd\u03bf" } # followings are same to original file included into Tk8.5a1's widget demos. ## Messages for the Greek (Hellenic - "el") language. ## Please report any changes/suggestions to: ## petasis@iit.demokritos.gr namespace eval ::tk { ::msgcat::mcset el "&Abort" "\u03a4\u03b5\u03c1\u03bc\u03b1\u03c4\u03b9\u03c3\u03bc\u03cc\u03c2" ::msgcat::mcset el "About..." "\u03a3\u03c7\u03b5\u03c4\u03b9\u03ba\u03ac..." ::msgcat::mcset el "All Files" "\u038c\u03bb\u03b1 \u03c4\u03b1 \u0391\u03c1\u03c7\u03b5\u03af\u03b1" ::msgcat::mcset el "Application Error" "\u039b\u03ac\u03b8\u03bf\u03c2 \u0395\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae\u03c2" ::msgcat::mcset el "&Blue" "\u039c\u03c0\u03bb\u03b5" ::msgcat::mcset el "&Cancel" "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7" ::msgcat::mcset el \ "Cannot change to the directory \"%1\$s\".\nPermission denied." \ "\u0394\u03b5\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b4\u03c5\u03bd\u03b1\u03c4\u03ae \u03b7 \u03b1\u03bb\u03bb\u03b1\u03b3\u03ae \u03ba\u03b1\u03c4\u03b1\u03bb\u03cc\u03b3\u03bf\u03c5 \u03c3\u03b5 \"%1\$s\".\n\u0397 \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03b4\u03b5\u03bd \u03b5\u03c0\u03b9\u03c4\u03c1\u03ad\u03c0\u03b5\u03c4\u03b1\u03b9." ::msgcat::mcset el "Choose Directory" "\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u039a\u03b1\u03c4\u03b1\u03bb\u03cc\u03b3\u03bf\u03c5" ::msgcat::mcset el "Clear" "\u039a\u03b1\u03b8\u03b1\u03c1\u03b9\u03c3\u03bc\u03cc\u03c2" ::msgcat::mcset el "Color" "\u03a7\u03c1\u03ce\u03bc\u03b1" ::msgcat::mcset el "Console" "\u039a\u03bf\u03bd\u03c3\u03cc\u03bb\u03b1" ::msgcat::mcset el "Copy" "\u0391\u03bd\u03c4\u03b9\u03b3\u03c1\u03b1\u03c6\u03ae" ::msgcat::mcset el "Cut" "\u0391\u03c0\u03bf\u03ba\u03bf\u03c0\u03ae" ::msgcat::mcset el "Delete" "\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae" ::msgcat::mcset el "Details >>" "\u039b\u03b5\u03c0\u03c4\u03bf\u03bc\u03ad\u03c1\u03b5\u03b9\u03b5\u03c2 >>" ::msgcat::mcset el "Directory \"%1\$s\" does not exist." \ "\u039f \u03ba\u03b1\u03c4\u03ac\u03bb\u03bf\u03b3\u03bf\u03c2 \"%1\$s\" \u03b4\u03b5\u03bd \u03c5\u03c0\u03ac\u03c1\u03c7\u03b5\u03b9." ::msgcat::mcset el "&Directory:" "&\u039a\u03b1\u03c4\u03ac\u03bb\u03bf\u03b3\u03bf\u03c2:" ::msgcat::mcset el "Error: %1\$s" "\u039b\u03ac\u03b8\u03bf\u03c2: %1\$s" ::msgcat::mcset el "Exit" "\u0388\u03be\u03bf\u03b4\u03bf\u03c2" ::msgcat::mcset el \ "File \"%1\$s\" already exists.\nDo you want to overwrite it?" \ "\u03a4\u03bf \u03b1\u03c1\u03c7\u03b5\u03af\u03bf \"%1\$s\" \u03ae\u03b4\u03b7 \u03c5\u03c0\u03ac\u03c1\u03c7\u03b5\u03b9.\n\u0398\u03ad\u03bb\u03b5\u03c4\u03b5 \u03bd\u03b1 \u03b5\u03c0\u03b9\u03ba\u03b1\u03bb\u03c5\u03c6\u03b8\u03b5\u03af;" ::msgcat::mcset el "File \"%1\$s\" already exists.\n\n" \ "\u03a4\u03bf \u03b1\u03c1\u03c7\u03b5\u03af\u03bf \"%1\$s\" \u03ae\u03b4\u03b7 \u03c5\u03c0\u03ac\u03c1\u03c7\u03b5\u03b9.\n\n" ::msgcat::mcset el "File \"%1\$s\" does not exist." \ "\u03a4\u03bf \u03b1\u03c1\u03c7\u03b5\u03af\u03bf \"%1\$s\" \u03b4\u03b5\u03bd \u03c5\u03c0\u03ac\u03c1\u03c7\u03b5\u03b9." ::msgcat::mcset el "File &name:" "\u038c&\u03bd\u03bf\u03bc\u03b1 \u03b1\u03c1\u03c7\u03b5\u03af\u03bf\u03c5:" ::msgcat::mcset el "File &names:" "\u038c&\u03bd\u03bf\u03bc\u03b1 \u03b1\u03c1\u03c7\u03b5\u03af\u03c9\u03bd:" ::msgcat::mcset el "Files of &type:" "\u0391\u03c1\u03c7\u03b5\u03af\u03b1 \u03c4\u03bf\u03c5 &\u03c4\u03cd\u03c0\u03bf\u03c5:" ::msgcat::mcset el "Fi&les:" "\u0391\u03c1\u03c7\u03b5\u03af\u03b1:" ::msgcat::mcset el "&Filter" "\u03a6\u03af\u03bb\u03c4\u03c1\u03bf" ::msgcat::mcset el "Fil&ter:" "\u03a6\u03af\u03bb\u03c4\u03c1\u03bf:" ::msgcat::mcset el "&Green" "\u03a0\u03c1\u03ac\u03c3\u03b9\u03bd\u03bf" ::msgcat::mcset el "Hi" "\u0393\u03b5\u03b9\u03b1" ::msgcat::mcset el "Hide Console" "\u0391\u03c0\u03cc\u03ba\u03c1\u03c5\u03c8\u03b7 \u03ba\u03bf\u03bd\u03c3\u03cc\u03bb\u03b1\u03c2" ::msgcat::mcset el "&Ignore" "\u0391\u03b3\u03bd\u03cc\u03b7\u03c3\u03b7" ::msgcat::mcset el "Invalid file name \"%1\$s\"." \ "\u0386\u03ba\u03c5\u03c1\u03bf \u03cc\u03bd\u03bf\u03bc\u03b1 \u03b1\u03c1\u03c7\u03b5\u03af\u03bf\u03c5 \"%1\$s\"." ::msgcat::mcset el "Log Files" "\u0391\u03c1\u03c7\u03b5\u03af\u03b1 \u039a\u03b1\u03c4\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2" ::msgcat::mcset el "&No" "\u038c\u03c7\u03b9" ::msgcat::mcset el "&OK" "\u0395\u03bd\u03c4\u03ac\u03be\u03b5\u03b9" ::msgcat::mcset el "&Ok" "\u0395\u03bd\u03c4\u03ac\u03be\u03b5\u03b9" ::msgcat::mcset el "Open" "\u0386\u03bd\u03bf\u03b9\u03b3\u03bc\u03b1" ::msgcat::mcset el "&Open" "\u0386\u03bd\u03bf\u03b9\u03b3\u03bc\u03b1" ::msgcat::mcset el "Open Multiple Files" \ "\u0386\u03bd\u03bf\u03b9\u03b3\u03bc\u03b1 \u03c0\u03bf\u03bb\u03bb\u03b1\u03c0\u03bb\u03ce\u03bd \u03b1\u03c1\u03c7\u03b5\u03af\u03c9\u03bd" ::msgcat::mcset el "Paste" "\u0395\u03c0\u03b9\u03ba\u03cc\u03bb\u03bb\u03b7\u03c3\u03b7" ::msgcat::mcset el "Quit" "\u0388\u03be\u03bf\u03b4\u03bf\u03c2" ::msgcat::mcset el "&Red" "\u039a\u03cc\u03ba\u03ba\u03b9\u03bd\u03bf" ::msgcat::mcset el "Replace existing file?" \ "\u0395\u03c0\u03b9\u03ba\u03ac\u03bb\u03c5\u03c8\u03b7 \u03c5\u03c0\u03ac\u03c1\u03c7\u03bf\u03bd\u03c4\u03bf\u03c2 \u03b1\u03c1\u03c7\u03b5\u03af\u03bf\u03c5;" ::msgcat::mcset el "&Retry" "\u03a0\u03c1\u03bf\u03c3\u03c0\u03ac\u03b8\u03b7\u03c3\u03b5 \u03be\u03b1\u03bd\u03ac" ::msgcat::mcset el "&Save" "\u0391\u03c0\u03bf\u03b8\u03ae\u03ba\u03b5\u03c5\u03c3\u03b7" ::msgcat::mcset el "Save As" "\u0391\u03c0\u03bf\u03b8\u03ae\u03ba\u03b5\u03c5\u03c3\u03b7 \u03c3\u03b1\u03bd" ::msgcat::mcset el "Save To Log" "\u0391\u03c0\u03bf\u03b8\u03ae\u03ba\u03b5\u03c5\u03c3\u03b7 \u03c3\u03c4\u03bf \u03b1\u03c1\u03c7\u03b5\u03af\u03bf \u03ba\u03b1\u03c4\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2" ::msgcat::mcset el "Select Log File" "\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u03b1\u03c1\u03c7\u03b5\u03af\u03bf\u03c5 \u03ba\u03b1\u03c4\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2" ::msgcat::mcset el "Select a file to source" \ "\u0395\u03c0\u03b9\u03bb\u03ad\u03be\u03c4\u03b5 \u03b1\u03c1\u03c7\u03b5\u03af\u03bf \u03b3\u03b9\u03b1 \u03b5\u03ba\u03c4\u03ad\u03bb\u03b5\u03c3\u03b7" ::msgcat::mcset el "&Selection:" "\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae:" ::msgcat::mcset el "Skip Messages" "\u0391\u03c0\u03bf\u03c6\u03c5\u03b3\u03ae \u03bc\u03c5\u03bd\u03b7\u03bc\u03ac\u03c4\u03c9\u03bd" ::msgcat::mcset el "Source..." "\u0395\u03ba\u03c4\u03ad\u03bb\u03b5\u03c3\u03b7..." ::msgcat::mcset el "Tcl Scripts" "Tcl Scripts" ::msgcat::mcset el "Tcl for Windows" "Tcl \u03b3\u03b9\u03b1 Windows" ::msgcat::mcset el "Text Files" "\u0391\u03c1\u03c7\u03b5\u03af\u03b1 \u039a\u03b5\u03b9\u03bc\u03ad\u03bd\u03bf\u03c5" ::msgcat::mcset el "&Yes" "\u039d\u03b1\u03b9" ::msgcat::mcset el "abort" "\u03c4\u03b5\u03c1\u03bc\u03b1\u03c4\u03b9\u03c3\u03bc\u03cc\u03c2" ::msgcat::mcset el "blue" "\u03bc\u03c0\u03bb\u03b5" ::msgcat::mcset el "cancel" "\u03b1\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7" ::msgcat::mcset el "extension" "\u03b5\u03c0\u03ad\u03ba\u03c4\u03b1\u03c3\u03b7" ::msgcat::mcset el "extensions" "\u03b5\u03c0\u03b5\u03ba\u03c4\u03ac\u03c3\u03b5\u03b9\u03c2" ::msgcat::mcset el "green" "\u03c0\u03c1\u03ac\u03c3\u03b9\u03bd\u03bf" ::msgcat::mcset el "ignore" "\u03b1\u03b3\u03bd\u03cc\u03b7\u03c3\u03b7" ::msgcat::mcset el "ok" "\u03b5\u03bd\u03c4\u03ac\u03be\u03b5\u03b9" ::msgcat::mcset el "red" "\u03ba\u03cc\u03ba\u03ba\u03b9\u03bd\u03bf" ::msgcat::mcset el "retry" "\u03c0\u03c1\u03bf\u03c3\u03c0\u03ac\u03b8\u03b7\u03c3\u03b5 \u03be\u03b1\u03bd\u03ac" ::msgcat::mcset el "yes" "\u03bd\u03b1\u03b9" } ================================================ FILE: ext/tk/sample/msgs_tk/en.msg ================================================ namespace eval ::tkmsgcat_demo { ::msgcat::mcset en "Application Error" ::msgcat::mcset en "Blue" ::msgcat::mcset en "Color" ::msgcat::mcset en "Delete" ::msgcat::mcset en "Error" ::msgcat::mcset en "Green" ::msgcat::mcset en "Red" ::msgcat::mcset en "blue" ::msgcat::mcset en "green" ::msgcat::mcset en "red" } namespace eval ::tk { ::msgcat::mcset en "&Abort" ::msgcat::mcset en "About..." ::msgcat::mcset en "All Files" ::msgcat::mcset en "Application Error" ::msgcat::mcset en "&Blue" ::msgcat::mcset en "&Cancel" ::msgcat::mcset en "Cannot change to the directory \"%1\$s\".\nPermission denied." ::msgcat::mcset en "Choose Directory" ::msgcat::mcset en "Clear" ::msgcat::mcset en "Color" ::msgcat::mcset en "Console" ::msgcat::mcset en "Copy" ::msgcat::mcset en "Cut" ::msgcat::mcset en "Delete" ::msgcat::mcset en "Details >>" ::msgcat::mcset en "Directory \"%1\$s\" does not exist." ::msgcat::mcset en "&Directory:" ::msgcat::mcset en "Error: %1\$s" ::msgcat::mcset en "Exit" ::msgcat::mcset en "File \"%1\$s\" already exists.\nDo you want to overwrite it?" ::msgcat::mcset en "File \"%1\$s\" already exists.\n\n" ::msgcat::mcset en "File \"%1\$s\" does not exist." ::msgcat::mcset en "File &name:" ::msgcat::mcset en "File &names:" ::msgcat::mcset en "Files of &type:" ::msgcat::mcset en "Fi&les:" ::msgcat::mcset en "&Filter" ::msgcat::mcset en "Fil&ter:" ::msgcat::mcset en "&Green" ::msgcat::mcset en "Hi" ::msgcat::mcset en "Hide Console" ::msgcat::mcset en "&Ignore" ::msgcat::mcset en "Invalid file name \"%1\$s\"." ::msgcat::mcset en "Log Files" ::msgcat::mcset en "&No" ::msgcat::mcset en "&OK" ::msgcat::mcset en "Ok" ::msgcat::mcset en "Open" ::msgcat::mcset en "&Open" ::msgcat::mcset en "Open Multiple Files" ::msgcat::mcset en "Paste" ::msgcat::mcset en "Quit" ::msgcat::mcset en "&Red" ::msgcat::mcset en "Replace existing file?" ::msgcat::mcset en "&Retry" ::msgcat::mcset en "&Save" ::msgcat::mcset en "Save As" ::msgcat::mcset en "Save To Log" ::msgcat::mcset en "Select Log File" ::msgcat::mcset en "Select a file to source" ::msgcat::mcset en "&Selection:" ::msgcat::mcset en "Skip Messages" ::msgcat::mcset en "Source..." ::msgcat::mcset en "Tcl Scripts" ::msgcat::mcset en "Tcl for Windows" ::msgcat::mcset en "Text Files" ::msgcat::mcset en "&Yes" ::msgcat::mcset en "abort" ::msgcat::mcset en "blue" ::msgcat::mcset en "cancel" ::msgcat::mcset en "extension" ::msgcat::mcset en "extensions" ::msgcat::mcset en "green" ::msgcat::mcset en "ignore" ::msgcat::mcset en "ok" ::msgcat::mcset en "red" ::msgcat::mcset en "retry" ::msgcat::mcset en "yes" } ================================================ FILE: ext/tk/sample/msgs_tk/en_gb.msg ================================================ namespace eval ::tkmsgcat_demo { ::msgcat::mcset en_gb Color Colour } namespace eval ::tk { ::msgcat::mcset en_gb Color Colour } ================================================ FILE: ext/tk/sample/msgs_tk/eo.msg ================================================ namespace eval ::tkmsgcat_demo { ::msgcat::mcset eo "Application Error" "Aplikoerraro" ::msgcat::mcset eo "Blue" "Blua" ::msgcat::mcset eo "Color" "Farbo" ::msgcat::mcset eo "Delete" "Forprenu" ::msgcat::mcset eo "Error" "Eraro" ::msgcat::mcset eo "Exit" "Eliru" ::msgcat::mcset eo "Green" "Verda" ::msgcat::mcset eo "Red" "Rosa" ::msgcat::mcset eo "blue" "blua" ::msgcat::mcset eo "green" "verda" ::msgcat::mcset eo "red" "ru\u011da" } namespace eval ::tk { ::msgcat::mcset eo "&Abort" "&\u0108esigo" ::msgcat::mcset eo "&About..." "Pri..." ::msgcat::mcset eo "All Files" "\u0108ioj dosieroj" ::msgcat::mcset eo "Application Error" "Aplikoerraro" ::msgcat::mcset eo "&Blue" "&Blua" ::msgcat::mcset eo "&Cancel" "&Rezignu" ::msgcat::mcset eo "Cannot change to the directory \"%1\$s\".\nPermission denied." "Neeble \u0109angi al dosierulon \"%1\$s\".\nVi ne rajtas tion." ::msgcat::mcset eo "Choose Directory" "Elektu Dosierujo" ::msgcat::mcset eo "&Clear" "&Klaru" ::msgcat::mcset eo "&Clear Console" "&Klaru konzolon" ::msgcat::mcset eo "Color" "Farbo" ::msgcat::mcset eo "Console" "Konzolo" ::msgcat::mcset eo "&Copy" "&Kopiu" ::msgcat::mcset eo "Cu&t" "&Enpo\u015digu" ::msgcat::mcset eo "&Delete" "&Forprenu" ::msgcat::mcset eo "Details >>" "Detaloj >>" ::msgcat::mcset eo "Directory \"%1\$s\" does not exist." "La dosierujo \"%1\$s\" ne ekzistas." ::msgcat::mcset eo "&Directory:" "&Dosierujo:" ::msgcat::mcset eo "&Edit" "&Redaktu" ::msgcat::mcset eo "Error: %1\$s" "Eraro: %1\$s" ::msgcat::mcset eo "E&xit" "&Eliru" ::msgcat::mcset eo "&File" "&Dosiero" ::msgcat::mcset eo "File \"%1\$s\" already exists.\nDo you want to overwrite it?" "La dosiero \"%1\$s\" jam ekzistas.\n\u0108u vi volas anstata\u00fbigi la dosieron?" ::msgcat::mcset eo "File \"%1\$s\" already exists.\n\n" "La dosiero \"%1\$s\" jam egzistas. \n\n" ::msgcat::mcset eo "File \"%1\$s\" does not exist." "La dosierp \"%1\$s\" ne estas." ::msgcat::mcset eo "File &name:" "Dosiero&nomo:" ::msgcat::mcset eo "File &names:" "Dosiero&nomoj:" ::msgcat::mcset eo "Files of &type:" "Dosieroj de &Typo:" ::msgcat::mcset eo "Fi&les:" "Do&sieroj:" ::msgcat::mcset eo "&Filter" "&Filtrilo" ::msgcat::mcset eo "Fil&ter:" "&Filtrilo:" ::msgcat::mcset eo "&Green" "&Verda" ::msgcat::mcset eo "&Help" "&Helpu" ::msgcat::mcset eo "Hi" "Saluton" ::msgcat::mcset eo "&Hide Console" "&Ka\u015du konzolon" ::msgcat::mcset eo "&Ignore" "&Ignoru" ::msgcat::mcset eo "Invalid file name \"%1\$s\"." "Malvalida dosieronomo \"%1\$s\"." ::msgcat::mcset eo "Log Files" "Protokolo" ::msgcat::mcset eo "&No" "&Ne" ::msgcat::mcset eo "OK" ::msgcat::mcset eo "Ok" ::msgcat::mcset eo "Open" "Malfermu" ::msgcat::mcset eo "&Open" "&Malfermu" ::msgcat::mcset eo "Open Multiple Files" "Melfermu multan dosierojn" ::msgcat::mcset eo "P&aste" "&Elpo\u015digi" ::msgcat::mcset eo "&Quit" "&Finigu" ::msgcat::mcset eo "&Red" "&Rosa" ::msgcat::mcset eo "Replace existing file?" "\u0108u anstata\u00fbu ekzistantan dosieron?" ::msgcat::mcset eo "&Retry" "&Ripetu" ::msgcat::mcset eo "&Save" "&Savu" ::msgcat::mcset eo "Save As" "Savu kiel" ::msgcat::mcset eo "Save To Log" "Savu en protokolon" ::msgcat::mcset eo "Select Log File" "Elektu prokolodosieron" ::msgcat::mcset eo "Select a file to source" "Elektu dosieron por interpreti" ::msgcat::mcset eo "&Selection:" "&Elekto:" ::msgcat::mcset eo "Skip Messages" "transsaltu pluajn mesa\u011dojn" ::msgcat::mcset eo "&Source..." "&Fontoprogramo..." ::msgcat::mcset eo "Tcl Scripts" "Tcl-skriptoj" ::msgcat::mcset eo "Tcl for Windows" "Tcl por vindoso" ::msgcat::mcset eo "Text Files" "Tekstodosierojn" ::msgcat::mcset eo "&Yes" "&Jes" ::msgcat::mcset eo "abort" "\u0109esigo" ::msgcat::mcset eo "blue" "blua" ::msgcat::mcset eo "cancel" "rezignu" ::msgcat::mcset eo "extension" "ekspansio" ::msgcat::mcset eo "extensions" "ekspansioj" ::msgcat::mcset eo "green" "verda" ::msgcat::mcset eo "ignore" "ignorieren" ::msgcat::mcset eo "red" "ru\u011da" ::msgcat::mcset eo "retry" "ripetu" ::msgcat::mcset eo "yes" "jes" } ================================================ FILE: ext/tk/sample/msgs_tk/es.msg ================================================ namespace eval ::tkmsgcat_demo { ::msgcat::mcset es "Application Error" "Error de la aplicaci\u00f3n" ::msgcat::mcset es "Blue" "Azul" ::msgcat::mcset es "Color" "Color" ::msgcat::mcset es "Delete" "Borrar" ::msgcat::mcset es "Error" "Error" ::msgcat::mcset es "Exit" "Salir" ::msgcat::mcset es "Green" "Verde" ::msgcat::mcset es "Red" "Rojo" ::msgcat::mcset es "blue" "azul" ::msgcat::mcset es "green" "verde" ::msgcat::mcset es "red" "rojo" } namespace eval ::tk { ::msgcat::mcset es "&Abort" "&Abortar" ::msgcat::mcset es "About..." "Acerca de ..." ::msgcat::mcset es "All Files" "Todos los archivos" ::msgcat::mcset es "Application Error" "Error de la aplicaci\u00f3n" ::msgcat::mcset es "&Blue" "&Azul" ::msgcat::mcset es "&Cancel" "&Cancelar" ::msgcat::mcset es "Cannot change to the directory \"%1\$s\".\nPermission denied." "No es posible acceder al directorio \"%1\$s\".\nPermiso denegado." ::msgcat::mcset es "Choose Directory" "Elegir directorio" ::msgcat::mcset es "Clear" "Borrar" ::msgcat::mcset es "Color" "Color" ::msgcat::mcset es "Console" "Consola" ::msgcat::mcset es "Copy" "Copiar" ::msgcat::mcset es "Cut" "Cortar" ::msgcat::mcset es "Delete" "Borrar" ::msgcat::mcset es "Details >>" "Detalles >>" ::msgcat::mcset es "Directory \"%1\$s\" does not exist." "El directorio \"%1\$s\" no existe." ::msgcat::mcset es "&Directory:" "&Directorio:" ::msgcat::mcset es "Error: %1\$s" "Error: %1\$s" ::msgcat::mcset es "Exit" "Salir" ::msgcat::mcset es "File \"%1\$s\" already exists.\nDo you want to overwrite it?" "El archivo \"%1\$s\" ya existe.\nDesea sobreescribirlo?" ::msgcat::mcset es "File \"%1\$s\" already exists.\n\n" "El archivo \"%1\$s\" ya existe.\n\n" ::msgcat::mcset es "File \"%1\$s\" does not exist." "El archivo \"%1\$s\" no existe." ::msgcat::mcset es "File &name:" "&Nombre de archivo:" ::msgcat::mcset es "File &names:" "&Nombres de archivo:" ::msgcat::mcset es "Files of &type:" "Archivos de &tipo:" ::msgcat::mcset es "Fi&les:" "&Archivos:" ::msgcat::mcset es "&Filter" "&Filtro" ::msgcat::mcset es "Fil&ter:" "Fil&tro:" ::msgcat::mcset es "&Green" "&Verde" ::msgcat::mcset es "Hi" "Hola" ::msgcat::mcset es "Hide Console" "Esconder la consola" ::msgcat::mcset es "&Ignore" "&Ignorar" ::msgcat::mcset es "Invalid file name \"%1\$s\"." "Nombre de archivo inv\u00e1lido \"%1\$s\"." ::msgcat::mcset es "Log Files" "Ficheros de traza" ::msgcat::mcset es "&No" "&No" ::msgcat::mcset es "&OK" "&OK" ::msgcat::mcset es "Ok" "Ok" ::msgcat::mcset es "Open" "Abrir" ::msgcat::mcset es "&Open" "&Abrir" ::msgcat::mcset es "Open Multiple Files" "Abrir m\u00faltiples archivos" ::msgcat::mcset es "Paste" "Pegar" ::msgcat::mcset es "Quit" "Abandonar" ::msgcat::mcset es "&Red" "&Rojo" ::msgcat::mcset es "Replace existing file?" "Reemplazar el archivo existente?" ::msgcat::mcset es "&Retry" "&Reintentar" ::msgcat::mcset es "&Save" "&Salvar" ::msgcat::mcset es "Save As" "Salvar como" ::msgcat::mcset es "Save To Log" "Salvar al archivo de traza" ::msgcat::mcset es "Select Log File" "Elegir un archivo de traza" ::msgcat::mcset es "Select a file to source" "Seleccionar un archivo a evaluar" ::msgcat::mcset es "&Selection:" "&Selecci\u00f3n:" ::msgcat::mcset es "Skip Messages" "Omitir los mensajes" ::msgcat::mcset es "Source..." "Evaluar..." ::msgcat::mcset es "Tcl Scripts" "Scripts Tcl" ::msgcat::mcset es "Tcl for Windows" "Tcl para Windows" ::msgcat::mcset es "Text Files" "Archivos de texto" ::msgcat::mcset es "&Yes" "&S\u00ed" ::msgcat::mcset es "abort" "abortar" ::msgcat::mcset es "blue" "azul" ::msgcat::mcset es "cancel" "cancelar" ::msgcat::mcset es "extension" "extensi\u00f3n" ::msgcat::mcset es "extensions" "extensiones" ::msgcat::mcset es "green" "verde" ::msgcat::mcset es "ignore" "ignorar" ::msgcat::mcset es "ok" "ok" ::msgcat::mcset es "red" "rojo" ::msgcat::mcset es "retry" "reintentar" ::msgcat::mcset es "yes" "s\u00ed" } ================================================ FILE: ext/tk/sample/msgs_tk/fr.msg ================================================ namespace eval ::tkmsgcat_demo { ::msgcat::mcset fr "Application Error" "Erreur d'application" ::msgcat::mcset fr "Blue" "Bleu" ::msgcat::mcset fr "Color" "Couleur" ::msgcat::mcset fr "Delete" "Effacer" ::msgcat::mcset fr "Error" "Erreur" ::msgcat::mcset fr "Exit" "Quitter" ::msgcat::mcset fr "Green" "Vert" ::msgcat::mcset fr "Red" "Rouge" ::msgcat::mcset fr "blue" "bleu" ::msgcat::mcset fr "green" "vert" ::msgcat::mcset fr "red" "rouge" } namespace eval ::tk { ::msgcat::mcset fr "&Abort" "&Annuler" ::msgcat::mcset fr "About..." "\u00c0 propos..." ::msgcat::mcset fr "All Files" "Tous les fichiers" ::msgcat::mcset fr "Application Error" "Erreur d'application" ::msgcat::mcset fr "&Blue" "&Bleu" ::msgcat::mcset fr "&Cancel" "&Annuler" ::msgcat::mcset fr "Cannot change to the directory \"%1\$s\".\nPermission denied." "Impossible d'acc\u00e9der au r\u00e9pertoire \"%1\$s\".\nPermission refus\u00e9e." ::msgcat::mcset fr "Choose Directory" "Choisir r\u00e9pertoire" ::msgcat::mcset fr "Clear" "Effacer" ::msgcat::mcset fr "Color" "Couleur" ::msgcat::mcset fr "Console" ::msgcat::mcset fr "Copy" "Copier" ::msgcat::mcset fr "Cut" "Couper" ::msgcat::mcset fr "Delete" "Effacer" ::msgcat::mcset fr "Details >>" "D\u00e9tails >>" ::msgcat::mcset fr "Directory \"%1\$s\" does not exist." "Le r\u00e9pertoire \"%1\$s\" n'existe pas." ::msgcat::mcset fr "&Directory:" "&R\u00e9pertoire:" ::msgcat::mcset fr "Error: %1\$s" "Erreur: %1\$s" ::msgcat::mcset fr "Exit" "Quitter" ::msgcat::mcset fr "File \"%1\$s\" already exists.\nDo you want to overwrite it?" "Le fichier \"%1\$s\" existe d\u00e9j\u00e0.\nVoulez-vous l'\u00e9craser?" ::msgcat::mcset fr "File \"%1\$s\" already exists.\n\n" "Le fichier \"%1\$s\" existe d\u00e9j\u00e0.\n\n" ::msgcat::mcset fr "File \"%1\$s\" does not exist." "Le fichier \"%1\$s\" n'existe pas." ::msgcat::mcset fr "File &name:" "&Nom de fichier:" ::msgcat::mcset fr "File &names:" "&Noms de fichiers:" ::msgcat::mcset fr "Files of &type:" "&Type de fichiers:" ::msgcat::mcset fr "Fi&les:" "Fich&iers:" ::msgcat::mcset fr "&Filter" "&Filtre" ::msgcat::mcset fr "Fil&ter:" "Fil&tre:" ::msgcat::mcset fr "&Green" "&Vert" ::msgcat::mcset fr "Hi" "Salut" ::msgcat::mcset fr "Hide Console" "Cacher la Console" ::msgcat::mcset fr "&Ignore" "&Ignorer" ::msgcat::mcset fr "Invalid file name \"%1\$s\"." "Nom de fichier invalide \"%1\$s\"." ::msgcat::mcset fr "Log Files" "Fichiers de trace" ::msgcat::mcset fr "&No" "&Non" ::msgcat::mcset fr "&OK" ::msgcat::mcset fr "Ok" ::msgcat::mcset fr "Open" "Ouvrir" ::msgcat::mcset fr "&Open" "&Ouvrir" ::msgcat::mcset fr "Open Multiple Files" "Ouvrir plusieurs fichiers" ::msgcat::mcset fr "Paste" "Coller" ::msgcat::mcset fr "Quit" "Quitter" ::msgcat::mcset fr "&Red" "&Rouge" ::msgcat::mcset fr "Replace existing file?" "Remplacer le fichier existant?" ::msgcat::mcset fr "&Retry" "&R\u00e9-essayer" ::msgcat::mcset fr "&Save" "&Sauvegarder" ::msgcat::mcset fr "Save As" "Sauvegarder sous" ::msgcat::mcset fr "Save To Log" "Sauvegarde au fichier de trace" ::msgcat::mcset fr "Select Log File" "Choisir un fichier de trace" ::msgcat::mcset fr "Select a file to source" "Choisir un fichier \u00e0 \u00e9valuer" ::msgcat::mcset fr "&Selection:" "&S\u00e9lection:" ::msgcat::mcset fr "Skip Messages" "Omettre les messages" ::msgcat::mcset fr "Source..." "\u00c9valuer..." ::msgcat::mcset fr "Tcl Scripts" "Scripts Tcl" ::msgcat::mcset fr "Tcl for Windows" "Tcl pour Windows" ::msgcat::mcset fr "Text Files" "Fichiers texte" ::msgcat::mcset fr "&Yes" "&Oui" ::msgcat::mcset fr "abort" "abandonner" ::msgcat::mcset fr "blue" "bleu" ::msgcat::mcset fr "cancel" "annuler" ::msgcat::mcset fr "extension" ::msgcat::mcset fr "extensions" ::msgcat::mcset fr "green" "vert" ::msgcat::mcset fr "ignore" "ignorer" ::msgcat::mcset fr "ok" ::msgcat::mcset fr "red" "rouge" ::msgcat::mcset fr "retry" "r\u00e9essayer" ::msgcat::mcset fr "yes" "oui" } ================================================ FILE: ext/tk/sample/msgs_tk/it.msg ================================================ namespace eval ::tkmsgcat_demo { ::msgcat::mcset it "Application Error" "Errore dell' applicazione" ::msgcat::mcset it "Blue" "Blu" ::msgcat::mcset it "Color" "Colore" ::msgcat::mcset it "Delete" "Incolla" ::msgcat::mcset it "Error" "Errore" ::msgcat::mcset it "Exit" "Esci" ::msgcat::mcset it "Green" "Verde" ::msgcat::mcset it "Red" "Rosso" ::msgcat::mcset it "blue" "blu" ::msgcat::mcset it "green" "verde" ::msgcat::mcset it "red" "rosso" } namespace eval ::tk { ::msgcat::mcset it "&Abort" "&Interrompi" ::msgcat::mcset it "About..." "Informazioni ..." ::msgcat::mcset it "All Files" "Tutti i file" ::msgcat::mcset it "Application Error" "Errore dell' applicazione" ::msgcat::mcset it "&Blue" "&Blu" ::msgcat::mcset it "&Cancel" "&Annulla" ::msgcat::mcset it "Cannot change to the directory \"%1\$s\".\nPermission denied." "Impossibile accedere alla directory \"%1\$s\".\nPermesso negato." ::msgcat::mcset it "Choose Directory" "Scegli directory" ::msgcat::mcset it "Clear" "Azzera" ::msgcat::mcset it "Color" "Colore" ::msgcat::mcset it "Console" ::msgcat::mcset it "Copy" "Copia" ::msgcat::mcset it "Cut" "Taglia" ::msgcat::mcset it "Delete" "Incolla" ::msgcat::mcset it "Details >>" "Dettagli >>" ::msgcat::mcset it "Directory \"%1\$s\" does not exist." "La directory \"%1\$s\" non esiste." ::msgcat::mcset it "&Directory:" ::msgcat::mcset it "Error: %1\$s" "Errore: %1\$s" ::msgcat::mcset it "Exit" "Esci" ::msgcat::mcset it "File \"%1\$s\" already exists.\nDo you want to overwrite it?" "Il file \"%1\$s\" esiste gi\u00e0.\nVuoi sovrascriverlo?" ::msgcat::mcset it "File \"%1\$s\" already exists.\n\n" "Il file \"%1\$s\" esiste gi\u00e0.\n\n" ::msgcat::mcset it "File \"%1\$s\" does not exist." "Il file \"%1\$s\" non esiste." ::msgcat::mcset it "File &name:" "&Nome del file:" ::msgcat::mcset it "File &names:" "&Nomi dei file:" ::msgcat::mcset it "Files of &type:" "File di &tipo:" ::msgcat::mcset it "Fi&les:" "Fi&le:" ::msgcat::mcset it "&Filter" "&Filtro" ::msgcat::mcset it "Fil&ter:" "Fil&tro:" ::msgcat::mcset it "&Green" "&Verde" ::msgcat::mcset it "Hi" "Salve" ::msgcat::mcset it "Hide Console" "Nascondi la console" ::msgcat::mcset it "&Ignore" "&Ignora" ::msgcat::mcset it "Invalid file name \"%1\$s\"." "Nome di file non valido \"%1\$s\"." ::msgcat::mcset it "Log Files" "File di log" ::msgcat::mcset it "&No" ::msgcat::mcset it "&OK" ::msgcat::mcset it "Ok" ::msgcat::mcset it "&Open" "A&pri" ::msgcat::mcset it "Open" "Apri" ::msgcat::mcset it "Open Multiple Files" "Apri file multipli" ::msgcat::mcset it "Paste" "Incolla" ::msgcat::mcset it "Quit" "Esci" ::msgcat::mcset it "&Red" "&Rosso" ::msgcat::mcset it "Replace existing file?" "Sostituisci il file esistente?" ::msgcat::mcset it "&Retry" "&Riprova" ::msgcat::mcset it "&Save" "&Salva" ::msgcat::mcset it "Save As" "Salva come" ::msgcat::mcset it "Save To Log" "Salva il log" ::msgcat::mcset it "Select Log File" "Scegli un file di log" ::msgcat::mcset it "Select a file to source" "Scegli un file da eseguire" ::msgcat::mcset it "&Selection:" "&Selezione:" ::msgcat::mcset it "Skip Messages" "Salta i messaggi" ::msgcat::mcset it "Source..." "Esegui..." ::msgcat::mcset it "Tcl Scripts" "Scripts Tcl" ::msgcat::mcset it "Tcl for Windows" "Tcl per Windows" ::msgcat::mcset it "Text Files" "File di testo" ::msgcat::mcset it "&Yes" "&Si" ::msgcat::mcset it "abort" "interrompi" ::msgcat::mcset it "blue" "blu" ::msgcat::mcset it "cancel" "annulla" ::msgcat::mcset it "extension" "estensione" ::msgcat::mcset it "extensions" "estensioni" ::msgcat::mcset it "green" "verde" ::msgcat::mcset it "ignore" "ignora" ::msgcat::mcset it "ok" ::msgcat::mcset it "red" "rosso" ::msgcat::mcset it "retry" "riprova" ::msgcat::mcset it "yes" "si" } ================================================ FILE: ext/tk/sample/msgs_tk/ja.msg ================================================ namespace eval ::tkmsgcat_demo { ::msgcat::mcset ja "Application Error" "\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u30A8\u30E9\u30FC" ::msgcat::mcset ja "Blue" "\u9752" ::msgcat::mcset ja "Color" "\u80CC\u666F\u8272" ::msgcat::mcset ja "Delete" "\u6D88\u53BB" ::msgcat::mcset ja "Error" "\u30A8\u30E9\u30FC" ::msgcat::mcset ja "Exit" "\u7D42\u4E86" ::msgcat::mcset ja "Green" "\u7DD1" ::msgcat::mcset ja "Red" "\u8D64" ::msgcat::mcset ja "blue" "\u9752" ::msgcat::mcset ja "green" "\u7DD1" ::msgcat::mcset ja "red" "\u8D64" } ================================================ FILE: ext/tk/sample/msgs_tk/license.terms ================================================ This software is copyrighted by the Regents of the University of California, Sun Microsystems, Inc., and other parties. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. ================================================ FILE: ext/tk/sample/msgs_tk/nl.msg ================================================ namespace eval ::tkmsgcat_demo { ::msgcat::mcset nl "Application Error" "Toepassingsfout" ::msgcat::mcset nl "Blue" "Blauw" ::msgcat::mcset nl "Color" "Kleur" ::msgcat::mcset nl "Delete" "Wissen" ::msgcat::mcset nl "Error" "Fout" ::msgcat::mcset nl "Exit" "Be\u00ebindigen" ::msgcat::mcset nl "Green" "Groen" ::msgcat::mcset nl "Red" "Rood" ::msgcat::mcset nl "blue" "blauw" ::msgcat::mcset nl "green" "groen" ::msgcat::mcset nl "red" "rood" } namespace eval ::tk { ::msgcat::mcset nl "\"%1\$s\" must be an absolute pathname" "\"%1\$s\" moet een absolute pad-naam zijn" ::msgcat::mcset nl "%1\$s is not a toplevel window" "%1\$s is geen toplevel window" ::msgcat::mcset nl ", or" ", of" ::msgcat::mcset nl "-default, -icon, -message, -parent, -title, or -type" "-default, -icon, -message, -parent, -title, of -type" ::msgcat::mcset nl "-initialdir, -mustexist, -parent, or -title" "-initialdir, -mustexist, -parent, of -title" ::msgcat::mcset nl "&Abort" "&Afbreken" ::msgcat::mcset nl "About..." "Over..." ::msgcat::mcset nl "All Files" "Alle Bestanden" ::msgcat::mcset nl "Application Error" "Toepassingsfout" ::msgcat::mcset nl "&Blue" "&Blauw" ::msgcat::mcset nl "&Cancel" "&Annuleren" ::msgcat::mcset nl "Cannot change to the directory \"%1\$s\".\nPermission denied." "Kan niet naar map \"%1\$s\" gaan.\nU heeft hiervoor geen toestemming." ::msgcat::mcset nl "Choose Directory" "Kies map" ::msgcat::mcset nl "Clear" "Wissen" ::msgcat::mcset nl "Clear entry, Press OK; Enter %1\$s, press OK" "Wis veld, Druk op OK; typ %1\$s in, druk op OK" ::msgcat::mcset nl "&Clear Console" "&Wis Console" ::msgcat::mcset nl "Color" "Kleur" ::msgcat::mcset nl "Console" ::msgcat::mcset nl "Copy" "Kopi\u00ebren" ::msgcat::mcset nl "Cut" "Knippen" ::msgcat::mcset nl "Delete" "Wissen" ::msgcat::mcset nl "Details" ::msgcat::mcset nl "Details >>" ::msgcat::mcset nl "Directory \"%1\$s\" does not exist." "Map \"%1\$s\" bestaat niet." ::msgcat::mcset nl "&Directory:" "&Map:" ::msgcat::mcset nl "Edit" "Bewerken" ::msgcat::mcset nl "Enter \"%1\$s\", press OK" "Typ \"%1\$s\", druk op OK" ::msgcat::mcset nl "Enter \"%1\$s\", press OK, enter \"%2\$s\", press OK" "Typ \"%1\$s\", druk op OK, typ \"%2\$s\", druk op OK" ::msgcat::mcset nl "Error: %1\$s" "Fout: %1\$s" ::msgcat::mcset nl "Exit" "Be\u00ebindigen" ::msgcat::mcset nl "File" "Bestand" ::msgcat::mcset nl "File \"%1\$s\" already exists.\n\n" "Bestand \"%1\$s\" bestaat al.\n\n" ::msgcat::mcset nl "File \"%1\$s\" already exists.\nDo you want to overwrite it?" "Bestand \"%1\$s\" bestaat al.\nWilt u het overschrijven?" ::msgcat::mcset nl "File \"%1\$s\" does not exist." "Bestand \"%1\$s\" bestaat niet." ::msgcat::mcset nl "File &name:" "Bestands&naam:" ::msgcat::mcset nl "File &names:" "Bestands&namen:" ::msgcat::mcset nl "Files of &type:" "Bestanden van het &type:" ::msgcat::mcset nl "Fi&les:" "&Bestanden:" ::msgcat::mcset nl "&Filter" ::msgcat::mcset nl "Fil&ter:" ::msgcat::mcset nl "&Green" "&Groen" ::msgcat::mcset nl "Hi" "H\u00e9" ::msgcat::mcset nl "Hide Console" "Verberg Console" ::msgcat::mcset nl "&Ignore" "&Negeren" ::msgcat::mcset nl "Invalid file name \"%1\$s\"." "Ongeldige bestandsnaam \"%1\$s\"." ::msgcat::mcset nl "Log Files" "Log Bestanden" ::msgcat::mcset nl "&No" "&Nee" ::msgcat::mcset nl "&OK" ::msgcat::mcset nl "Ok" ::msgcat::mcset nl "&Open" "&Openen" ::msgcat::mcset nl "Open" "Openen" ::msgcat::mcset nl "Open Multiple Files" "Open meerdere bestanden" ::msgcat::mcset nl "Paste" "Plakken" ::msgcat::mcset nl "Please press %1\$s" "Druk op %1\$s, A.U.B." ::msgcat::mcset nl "Please press ok" "Druk op ok, A.U.B." ::msgcat::mcset nl "Press Cancel" "Druk op Annuleren" ::msgcat::mcset nl "Press Ok" "Druk op Ok" ::msgcat::mcset nl "Quit" "Stoppen" ::msgcat::mcset nl "&Red" "&Rood" ::msgcat::mcset nl "Replace existing file?" "Vervang bestaand bestand?" ::msgcat::mcset nl "&Retry" "&Herhalen" ::msgcat::mcset nl "&Save" "Op&slaan" ::msgcat::mcset nl "Save As" "Opslaan als" ::msgcat::mcset nl "Save To Log" "Opslaan naar Log" ::msgcat::mcset nl "Select Log File" "Selecteer Log bestand" ::msgcat::mcset nl "Select a file to source" "Selecteer bronbestand" ::msgcat::mcset nl "&Selection:" "&Selectie:" ::msgcat::mcset nl "Skip Messages" "Berichten overslaan" ::msgcat::mcset nl "Source..." "Bron..." ::msgcat::mcset nl "Tcl Scripts" ::msgcat::mcset nl "Tcl for Windows" "Tcl voor Windows" ::msgcat::mcset nl "Text Files" "Tekstbestanden" ::msgcat::mcset nl "&Yes" "&Ja" ::msgcat::mcset nl "abort" "afbreken" ::msgcat::mcset nl "abort, retry, ignore, ok, cancel, no, or yes" "afbreken, opnieuw, negeren, ok, annuleren, nee, of ja" ::msgcat::mcset nl "abortretryignore, ok, okcancel, retrycancel, yesno, or yesnocancel" "abortretryignore, ok, okcancel, retrycancel, yesno, of yesnocancel" ::msgcat::mcset nl "bad %1\$s value \"%2\$s\": must be %3\$s" "verkeerde %1\$s waarde \"%2\$s\": moet zijn %3\$s" ::msgcat::mcset nl "bad file type \"%1\$s\", should be" "verkeerd bestandstype \"%1\$s\", moet zijn" ::msgcat::mcset nl "bad option \"%1\$s\": should be %2\$s" "verkeerde optie \"%1\$s\": moet zijn %2\$s" ::msgcat::mcset nl "bad window path name \"%1\$s\"" "verkeerde window-padnaam \"%1\$s\"" ::msgcat::mcset nl "blue" "blauw" ::msgcat::mcset nl "can't post %1\$s: it isn't a descendant of %2\$s (this is a new requirement in Tk versions 3.0 and later)" "kan %1\$s niet verzenden: het is geen afstammeling van %2\$s (dit is een nieuwe eis in Tk versies 3.0 en later)" ::msgcat::mcset nl "cancel" "annuleren" ::msgcat::mcset nl "default button index greater than number of buttons specified for tk_dialog" "default knop index is groter dan het aantal knoppen beschikbaar voor tk_dialog" ::msgcat::mcset nl "display name to use (current one otherwise)" "te gebruiken schermnaam (anders huidige scherm)" ::msgcat::mcset nl "error, info, question, or warning" "error, info, question, of warning" ::msgcat::mcset nl "extension" ::msgcat::mcset nl "extensions" ::msgcat::mcset nl "focus group \"%1\$s\" doesn't exist" "focusgroep \"%1\$s\" bestaat niet" ::msgcat::mcset nl "green" "groen" ::msgcat::mcset nl "history event %1\$s" ::msgcat::mcset nl "ignore" "negeren" ::msgcat::mcset nl "invalid default button \"%1\$s\"" "ongeldige default knop \"%1\$s\"" ::msgcat::mcset nl "macType" ::msgcat::mcset nl "macTypes" ::msgcat::mcset nl "must specify a background color" "een achtergrondkleur is verplicht" ::msgcat::mcset nl "name of the slave interpreter" "naam van de slaaf-interpreter" ::msgcat::mcset nl "no winfo screen . nor env(DISPLAY)" "geen winfo scherm . noch env(DISPLAY)" ::msgcat::mcset nl "ok" ::msgcat::mcset nl "red" "rood" ::msgcat::mcset nl "retry" "opnieuw" ::msgcat::mcset nl "should contain 5 or 4 elements" "moet 4 of 5 elementen bevatten" ::msgcat::mcset nl "spec" ::msgcat::mcset nl "tk_chooseDirectory command" "tk_chooseDirectory opdracht" ::msgcat::mcset nl "tk_chooseDirectory command, cancel gives null" "tk_chooseDirectory opdracht, annuleren geeft lege waarde" ::msgcat::mcset nl "tk_chooseDirectory command, initialdir" "tk_chooseDirectory opdracht, initi\u00eble map" ::msgcat::mcset nl "yes" "ja" } ================================================ FILE: ext/tk/sample/msgs_tk/pl.msg ================================================ namespace eval ::tkmsgcat_demo { ::msgcat::mcset pl "Application Error" "Bl\u0105d w Programie" ::msgcat::mcset pl "Blue" "Niebieski" ::msgcat::mcset pl "Color" "Kolor" ::msgcat::mcset pl "Delete" "Usu\u0144" ::msgcat::mcset pl "Error" "B\u0142\u0105d" ::msgcat::mcset pl "Exit" "Zako\u0144cz" ::msgcat::mcset pl "Green" "Zielony" ::msgcat::mcset pl "Red" "Czerwonz" ::msgcat::mcset pl "blue" "niebieski" ::msgcat::mcset pl "green" "zielony" ::msgcat::mcset pl "red" "czerwony" } namespace eval ::tk { ::msgcat::mcset pl "&Abort" "&Anuluj" ::msgcat::mcset pl "&About..." "O Programie..." ::msgcat::mcset pl "All Files" "Wszystkie pliki" ::msgcat::mcset pl "Application Error" "Bl\u0105d w Programie" ::msgcat::mcset pl "&Blue" "&Niebieski" ::msgcat::mcset pl "&Cancel" "&Anuluj" ::msgcat::mcset pl "Cannot change to the directory \"%1\$s\".\nPermission denied." "Katalog \"%1\$s\" nie mo\u017ce zosta\u0107 odczytany lub nie istnieje." ::msgcat::mcset pl "Choose Directory" "Wybierz katalog" ::msgcat::mcset pl "&Clear" "&Wyczy\u015b\u0107" ::msgcat::mcset pl "&Clear Console" "&Wyczy\u015b\u0107 konsol\u0119" ::msgcat::mcset pl "Color" "Kolor" ::msgcat::mcset pl "Console" "Konsola" ::msgcat::mcset pl "&Copy" "&Kopiuj" ::msgcat::mcset pl "Cu&t" "&Wytnij" ::msgcat::mcset pl "&Delete" "&Usu\u0144" ::msgcat::mcset pl "Details >>" "Detale >>" ::msgcat::mcset pl "Directory \"%1\$s\" does not exist." "Katalog \"%1\$s\" nie istniej." ::msgcat::mcset pl "&Directory:" "&Katalog:" ::msgcat::mcset pl "&Edit" "&Edytuj" ::msgcat::mcset pl "Error: %1\$s" "B\u0142\u0105d: %1\$s" ::msgcat::mcset pl "E&xit" "&Zako\u0144cz" ::msgcat::mcset pl "&File" "&Plik" ::msgcat::mcset pl "File \"%1\$s\" already exists.\nDo you want to overwrite it?" "Plik \"%1\$s\" ju\u017c istnieje.\nCzy chcesz go zast\u0105pi\u0107?" ::msgcat::mcset pl "File \"%1\$s\" already exists.\n\n" "Plik \"%1\$s\" ju\u017c istnieje. \n\n" ::msgcat::mcset pl "File \"%1\$s\" does not exist." "Plik \"%1\$s\" nie istnieje." ::msgcat::mcset pl "File &name:" "Nazwa &pliku:" ::msgcat::mcset pl "File &names:" "Nazwy &plik\u00f3w:" ::msgcat::mcset pl "Files of &type:" "Pliki &typu:" ::msgcat::mcset pl "Fi&les:" "Pli&ki:" ::msgcat::mcset pl "&Filter" "&Filter" ::msgcat::mcset pl "Fil&ter:" "&Filter:" ::msgcat::mcset pl "&Green" "&Zielony" ::msgcat::mcset pl "&Help" "&Pomoc" ::msgcat::mcset pl "Hi" "Witaj" ::msgcat::mcset pl "&Hide Console" "&Schowaj konsol\u0119" ::msgcat::mcset pl "&Ignore" "&Ignoruj" ::msgcat::mcset pl "Invalid file name \"%1\$s\"." "Niew\u0142a\u015bciwa nazwa pliku \"%1\$s\"." ::msgcat::mcset pl "Log Files" "Protoko\u0142uj" ::msgcat::mcset pl "&No" "&Nie" ::msgcat::mcset pl "OK" ::msgcat::mcset pl "Ok" ::msgcat::mcset pl "Open" "Wczytaj" ::msgcat::mcset pl "&Open" "&Wczytaj" ::msgcat::mcset pl "Open Multiple Files" "Wczytuj wiele plik\u00f3w" ::msgcat::mcset pl "P&aste" "&Wklej" ::msgcat::mcset pl "&Quit" "&Zako\u0144cz" ::msgcat::mcset pl "&Red" "&Czerwonz" ::msgcat::mcset pl "Replace existing file?" "Czy zost\u0105pi\u0107 instniej\u0105cy plik?" ::msgcat::mcset pl "&Retry" "&Powt\u00f3rz" ::msgcat::mcset pl "&Save" "&Zapisz" ::msgcat::mcset pl "Save As" "Zapisz jako" ::msgcat::mcset pl "Save To Log" "Wpisz do protoko\u0142u" ::msgcat::mcset pl "Select Log File" "Wybierz plik proko\u0142u" ::msgcat::mcset pl "Select a file to source" "Wybierz plik do wykonania" ::msgcat::mcset pl "&Selection:" "&Wyb\u00f3r:" ::msgcat::mcset pl "Skip Messages" "Omi\u0144 pozosta\u0142e komunikaty" ::msgcat::mcset pl "&Source..." "&Kod \u017ar\u00f3d\u0142owy..." ::msgcat::mcset pl "Tcl Scripts" "Tcl-skrypty" ::msgcat::mcset pl "Tcl for Windows" "Tcl dla Okienek (Windows)" ::msgcat::mcset pl "Text Files" "Pliki Tekstowe" ::msgcat::mcset pl "&Yes" "&Tak" ::msgcat::mcset pl "abort" "zako\u0144cz" ::msgcat::mcset pl "blue" "niebieski" ::msgcat::mcset pl "cancel" "anuluj" ::msgcat::mcset pl "extension" "rozszerzenie" ::msgcat::mcset pl "extensions" "rozszerzenia" ::msgcat::mcset pl "green" "zielony" ::msgcat::mcset pl "ignore" "ignoruj" ::msgcat::mcset pl "red" "czerwony" ::msgcat::mcset pl "retry" "potw\u00f3rz" ::msgcat::mcset pl "yes" "tak" } ================================================ FILE: ext/tk/sample/msgs_tk/ru.msg ================================================ namespace eval ::tkmsgcat_demo { ::msgcat::mcset ru "Application Error" "\u041e\u0448\u0438\u0431\u043a\u0430 \u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0435" ::msgcat::mcset ru "Blue" " \u0413\u043e\u043b\u0443\u0431\u043e\u0439" ::msgcat::mcset ru "Color" "\u0426\u0432\u0435\u0442" ::msgcat::mcset ru "Delete" "\u0423\u0434\u0430\u043b\u0438\u0442\u044c" ::msgcat::mcset ru "Error" "\u041e\u0448\u0438\u0431\u043a\u0430" ::msgcat::mcset ru "Exit" "\u0412\u044b\u0445\u043e\u0434" ::msgcat::mcset ru "Green" "\u0417\u0435\u043b\u0435\u043d\u044b\u0439" ::msgcat::mcset ru "Red" "\u041a\u0440\u0430\u0441\u043d\u044b\u0439" ::msgcat::mcset ru "blue" " \u0433\u043e\u043b\u0443\u0431\u043e\u0439" ::msgcat::mcset ru "green" " \u0437\u0435\u043b\u0435\u043d\u044b\u0439" ::msgcat::mcset ru "red" " \u043a\u0440\u0430\u0441\u043d\u044b\u0439" } namespace eval ::tk { ::msgcat::mcset ru "&Abort" "&\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c" ::msgcat::mcset ru "About..." "\u041f\u0440\u043e..." ::msgcat::mcset ru "All Files" "\u0412\u0441\u0435 \u0444\u0430\u0439\u043b\u044b" ::msgcat::mcset ru "Application Error" "\u041e\u0448\u0438\u0431\u043a\u0430 \u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0435" ::msgcat::mcset ru "&Blue" " &\u0413\u043e\u043b\u0443\u0431\u043e\u0439" ::msgcat::mcset ru "&Cancel" "\u041e\u0442&\u043c\u0435\u043d\u0430" ::msgcat::mcset ru "Cannot change to the directory \"%1\$s\".\nPermission denied." \ "\u041d\u0435 \u043c\u043e\u0433\u0443 \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \"%1\$s\".\n\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u0430\u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0430" ::msgcat::mcset ru "Choose Directory" "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433" ::msgcat::mcset ru "Clear" "\u041e\u0447\u0438\u0441\u0442\u0438\u0442\u044c" ::msgcat::mcset ru "Color" "\u0426\u0432\u0435\u0442" ::msgcat::mcset ru "Console" "\u041a\u043e\u043d\u0441\u043e\u043b\u044c" ::msgcat::mcset ru "Copy" "\u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c" ::msgcat::mcset ru "Cut" "\u0412\u044b\u0440\u0435\u0437\u0430\u0442\u044c" ::msgcat::mcset ru "Delete" "\u0423\u0434\u0430\u043b\u0438\u0442\u044c" ::msgcat::mcset ru "Details >>" "\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 >>" ::msgcat::mcset ru "Directory \"%1\$s\" does not exist." "\u041a\u0430\u0442\u0430\u043b\u043e\u0433\u0430 \"%1\$s\" \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442." ::msgcat::mcset ru "&Directory:" "&\u041a\u0430\u0442\u0430\u043b\u043e\u0433:" ::msgcat::mcset ru "Error: %1\$s" "\u041e\u0448\u0438\u0431\u043a\u0430: %1\$s" ::msgcat::mcset ru "Exit" "\u0412\u044b\u0445\u043e\u0434" ::msgcat::mcset ru "File \"%1\$s\" already exists.\nDo you want to overwrite it?" \ "\u0424\u0430\u0439\u043b \"%1\$s\" \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442.\n\u0417\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0435\u0433\u043e?" ::msgcat::mcset ru "File \"%1\$s\" already exists.\n\n" "\u0424\u0430\u0439\u043b \"%1\$s\" \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442.\n\n" ::msgcat::mcset ru "File \"%1\$s\" does not exist." "\u0424\u0430\u0439\u043b \"%1\$s\" \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d." ::msgcat::mcset ru "File &name:" "&\u0418\u043c\u044f \u0444\u0430\u0439\u043b\u0430:" ::msgcat::mcset ru "File &names:" "&\u0418\u043c\u0435\u043d\u0430 \u0444\u0430\u0439\u043b\u043e\u0432:" ::msgcat::mcset ru "Files of &type:" "&\u0422\u0438\u043f \u0444\u0430\u0439\u043b\u043e\u0432:" ::msgcat::mcset ru "Fi&les:" "\u0424\u0430\u0439&\u043b\u044b:" ::msgcat::mcset ru "&Filter" "&\u0424\u0438\u043b\u044c\u0442\u0440" ::msgcat::mcset ru "Fil&ter:" "\u0424\u0438\u043b\u044c&\u0442\u0440:" ::msgcat::mcset ru "&Green" " &\u0417\u0435\u043b\u0435\u043d\u044b\u0439" ::msgcat::mcset ru "Hi" "\u041f\u0440\u0438\u0432\u0435\u0442" ::msgcat::mcset ru "Hide Console" "\u0421\u043f\u0440\u044f\u0442\u0430\u0442\u044c \u043a\u043e\u043d\u0441\u043e\u043b\u044c" ::msgcat::mcset ru "&Ignore" "&\u0418\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c" ::msgcat::mcset ru "Invalid file name \"%1\$s\"." "\u041d\u0435\u0432\u0435\u0440\u043d\u043e\u0435 \u0438\u043c\u044f \u0444\u0430\u0439\u043b\u0430 \"%1\$s\"." ::msgcat::mcset ru "Log Files" "\u0424\u0430\u0439\u043b\u044b \u0436\u0443\u0440\u043d\u0430\u043b\u0430" ::msgcat::mcset ru "&No" "&\u041d\u0435\u0442" ::msgcat::mcset ru "&OK" "&\u041e\u041a" ::msgcat::mcset ru "Ok" "\u0414\u0430" ::msgcat::mcset ru "Open" "\u041e\u0442\u043a\u0440\u044b\u0442\u044c" ::msgcat::mcset ru "&Open" "&\u041e\u0442\u043a\u0440\u044b\u0442\u044c" ::msgcat::mcset ru "Open Multiple Files" "\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0444\u0430\u0439\u043b\u043e\u0432" ::msgcat::mcset ru "Paste" "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c" ::msgcat::mcset ru "Quit" "\u0412\u044b\u0445\u043e\u0434" ::msgcat::mcset ru "&Red" " &\u041a\u0440\u0430\u0441\u043d\u044b\u0439" ::msgcat::mcset ru "Replace existing file?" "\u0417\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0444\u0430\u0439\u043b?" ::msgcat::mcset ru "&Retry" "&\u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c" ::msgcat::mcset ru "&Save" "&\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c" ::msgcat::mcset ru "Save As" "\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u0430\u043a" ::msgcat::mcset ru "Save To Log" "\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u0436\u0443\u0440\u043d\u0430\u043b" ::msgcat::mcset ru "Select Log File" "\u0412\u044b\u0431\u0440\u0430\u0442\u044c \u0436\u0443\u0440\u043d\u0430\u043b" ::msgcat::mcset ru "Select a file to source" "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0444\u0430\u0439\u043b \u0434\u043b\u044f \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0446\u0438\u0438" ::msgcat::mcset ru "&Selection:" "&Selection:" ::msgcat::mcset ru "Skip Messages" "\u041f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f" ::msgcat::mcset ru "Source..." "\u0418\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b..." ::msgcat::mcset ru "Tcl Scripts" "\u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u043d\u0430 \u044f\u0437\u044b\u043a\u0435 TCL" ::msgcat::mcset ru "Tcl for Windows" "TCL \u0434\u043b\u044f Windows" ::msgcat::mcset ru "Text Files" "\u0422\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u0444\u0430\u0439\u043b\u044b" ::msgcat::mcset ru "&Yes" "&\u0414\u0430" ::msgcat::mcset ru "abort" "\u043e\u0442\u043c\u0435\u043d\u0430" ::msgcat::mcset ru "blue" " \u0433\u043e\u043b\u0443\u0431\u043e\u0439" ::msgcat::mcset ru "cancel" "\u043e\u0442\u043c\u0435\u043d\u0430" ::msgcat::mcset ru "extension" "\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435" ::msgcat::mcset ru "extensions" "\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f" ::msgcat::mcset ru "green" " \u0437\u0435\u043b\u0435\u043d\u044b\u0439" ::msgcat::mcset ru "ignore" "\u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c" ::msgcat::mcset ru "ok" "\u043e\u043a" ::msgcat::mcset ru "red" " \u043a\u0440\u0430\u0441\u043d\u044b\u0439" ::msgcat::mcset ru "retry" "\u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c" ::msgcat::mcset ru "yes" "\u0434\u0430" } ================================================ FILE: ext/tk/sample/multi-ip_sample.rb ================================================ #!/usr/bin/env ruby # This script is a sample of MultiTkIp class require "multi-tk" # create slave interpreters trusted_slave = MultiTkIp.new_slave safe_slave1 = MultiTkIp.new_safeTk safe_slave2 = MultiTkIp.new_safeTk('fill'=>:none, 'expand'=>false) #safe_slave2 = MultiTkIp.new_safeTk('fill'=>:none) #safe_slave2 = MultiTkIp.new_safeTk('expand'=>false) cmd = Proc.new{|txt| ##################### ## from TkTimer2.rb if TkCore::INTERP.safe? # safeTk doesn't have permission to call 'wm' command else root = TkRoot.new(:title=>'timer sample') end label = TkLabel.new(:parent=>root, :relief=>:raised, :width=>10) \ .pack(:side=>:bottom, :fill=>:both) tick = proc{|aobj| cnt = aobj.return_value + 5 label.text format("%d.%02d", *(cnt.divmod(100))) cnt } timer = TkTimer.new(50, -1, tick).start(0, proc{ label.text('0.00'); 0 }) =begin TkButton.new(:text=>'Start') { command proc{ timer.continue unless timer.running? } pack(:side=>:left, :fill=>:both, :expand=>true) } TkButton.new(:text=>'Restart') { command proc{ timer.restart(0, proc{ label.text('0.00'); 0 }) } pack('side'=>'right','fill'=>'both','expand'=>'yes') } TkButton.new(:text=>'Stop') { command proc{ timer.stop if timer.running? } pack('side'=>'right','fill'=>'both','expand'=>'yes') } =end b_start = TkButton.new(:text=>'Start', :state=>:disabled) { pack(:side=>:left, :fill=>:both, :expand=>true) } b_stop = TkButton.new(:text=>'Stop', :state=>:normal) { pack('side'=>'left', 'fill'=>'both', 'expand'=>'yes') } b_start.command { timer.continue b_stop.state(:normal) b_start.state(:disabled) } b_stop.command { timer.stop b_start.state(:normal) b_stop.state(:disabled) } TkButton.new(:text=>'Reset', :state=>:normal) { command { timer.reset } pack('side'=>'right', 'fill'=>'both', 'expand'=>'yes') } ev_quit = TkVirtualEvent.new('Control-c', 'Control-q') Tk.root.bind(ev_quit, proc{Tk.exit}).focus } # call on the default master interpreter trusted_slave.eval_proc(cmd, 'trusted') # label -> .w00012 safe_slave1.eval_proc(cmd, 'safe1') # label -> .w00016 safe_slave2.eval_proc(cmd, 'safe2') # label -> .w00020 cmd.call('master') # label -> .w00024 #second_master = MultiTkIp.new(&cmd) TkTimer.new(2000, -1, proc{p ['safe1', safe_slave1.deleted?]}).start TkTimer.new(2000, -1, proc{p ['safe2', safe_slave2.deleted?]}).start TkTimer.new(2000, -1, proc{p ['trusted', trusted_slave.deleted?]}).start TkTimer.new(5000, 1, proc{ safe_slave1.eval_proc{Tk.root.destroy} safe_slave1.delete print "*** The safe_slave1 is deleted by the timer.\n" }).start TkTimer.new(10000, 1, proc{ trusted_slave.eval_proc{Tk.root.destroy} trusted_slave.delete print "*** The trusted_slave is deleted by the timer.\n" }).start Tk.mainloop ================================================ FILE: ext/tk/sample/multi-ip_sample2.rb ================================================ require 'multi-tk.rb' th = Thread.new{Tk.mainloop} TkLabel.new(:text=>'this is a primary master').pack ip1 = MultiTkIp.new_slave(:safe=>1) ip2 = MultiTkIp.new_slave(:safe=>2) cmd = proc{|s| require 'tk' TkButton.new(:text=>'b1: p self', :command=>proc{p self}).pack(:fill=>:x) sleep s TkButton.new(:text=>'b2: p $SAFE', :command=>proc{p $SAFE}).pack(:fill=>:x) sleep s TkButton.new(:text=>'b3: p MultiTkIp.ip_name', :command=>proc{p MultiTkIp.ip_name}).pack(:fill=>:x) sleep s TkButton.new(:text=>'EXIT', :command=>proc{exit}).pack(:fill=>:x) Tk.mainloop } Thread.new{ip1.eval_proc(cmd, 1.1)} Thread.new{ip2.eval_proc(cmd, 0.3)} cmd.call(0.7) th.join ================================================ FILE: ext/tk/sample/optobj_sample.rb ================================================ #!/usr/bin/env ruby # # sample script of Tk::OptionObj # require "tk" optobj = Tk::OptionObj.new('foreground'=>'red', 'background'=>'black') f = TkFrame.new.pack(:side=>:left, :anchor=>:n, :padx=>5, :pady=>30) b1 = TkButton.new(f, :text=>'AAA').pack(:fill=>:x) b2 = TkButton.new(f, :text=>'BBB').pack(:fill=>:x) b3 = TkButton.new(f, :text=>'CCC').pack(:fill=>:x) optobj.assign( b1, [ b2, 'configure', { 'foreground'=>'background', 'background'=>'foreground' } ], [ b3, nil, { 'foreground'=>'background', 'activeforeground'=>nil, 'background'=>['foreground', 'activeforeground'] } ] ) optobj.update('activeforeground'=>'yellow') TkButton.new(f){ configure( optobj.assign(self) + {:text=>'DDD'} ) pack(:fill=>:x) } TkButton.new(f){ configure( optobj.assign([self, nil, {'foreground'=>'activeforeground', 'background'=>'foreground', 'activeforeground'=>'background'}]) \ + {:text=>'EEE', :relief=>:groove, :borderwidth=>5} ) pack(:fill=>:x) } optobj.notify # To apply the convert_key ( 3rd element of widget info # (that is, {'foreground'=>'activeforeground', ,,, } ) # of the 'EEE' button TkButton.new(f, :text=>'toggle', :command=>proc{ fg = optobj['foreground'] bg = optobj['background'] optobj.configure('foreground'=>bg, 'background'=>fg) }).pack(:fill=>:x, :pady=>10) TkButton.new(f, :text=>'exit', :command=>proc{exit}).pack(:fill=>:x, :pady=>10) TkFrame.new{|f| pack(:side=>:right, :expand=>true, :fill=>:both) TkLabel.new(f, :text=>'source::').pack(:anchor=>:w) TkFrame.new(f){|ff| TkText.new(ff){ yscrollbar(TkScrollbar.new(ff){pack(:fill=>:y, :side=>:right)}) insert('end', File.read(__FILE__)) pack(:side=>:left, :expand=>true, :fill=>:both) } pack(:expand=>true, :fill=>:both) } } Tk.mainloop ================================================ FILE: ext/tk/sample/propagate.rb ================================================ #!/usr/bin/env ruby require 'tk' TkLabel.new(:text=>"Please click the bottom frame").pack f = TkFrame.new(:width=>400, :height=>100, :background=>'yellow', :relief=>'ridge', :borderwidth=>5).pack # TkPack.propagate(f, false) # <== important!! f.pack_propagate(false) # <== important!! list = (1..3).collect{|n| TkButton.new(f, :text=>"button#{'-X'*n}"){ command proc{ puts "button#{'-X'*n}" self.unpack } } } list.unshift(nil) f.bind('1', proc{ w = list.shift w.unpack if w list.push(w) list[0].pack(:expand=>true, :anchor=>:center) if list[0] }) Tk.mainloop ================================================ FILE: ext/tk/sample/remote-ip_sample.rb ================================================ #!/usr/bin/env ruby require 'remote-tk' puts <proc{puts 'This procesure is on the controller-ip (Ruby/Tk)'}, :text=>'print on Ruby/Tk (controller-ip)').pack(:fill=>:x)} ip.eval_proc{TkButton.new(:command=>'puts {This procesure is on the remote-ip (wish)}', :text=>'print on wish (remote-ip)').pack(:fill=>:x)} # If your remote-ip is Ruby/Tk, you can control the remote Ruby by # 'ruby' or 'ruby_eval' or 'ruby_cmd' on the Tk interpreter. if ip.is_rubytk? ip.eval_proc{TkButton.new(:command=>'ruby {p 111; p Array.new(3,"ruby")}', :text=>'ruby cmd on the remote-ip').pack(:fill=>:x)} end ip.eval_proc{TkButton.new(:command=>'exit', :text=>'QUIT').pack(:fill=>:x)} TkButton.new(:command=>proc{exit}, :text=>'QUIT', :padx=>10, :pady=>7).pack(:padx=>10, :pady=>7) Tk.mainloop ================================================ FILE: ext/tk/sample/remote-ip_sample2.rb ================================================ #!/usr/bin/env ruby require 'remote-tk' # start sub-process ip_name = 'remote_ip' ip_list = TkWinfo.interps fork{ exec "/usr/bin/env ruby -r tk -e \"Tk.appname('#{ip_name}');Tk.mainloop\"" } sleep 1 until (app = (TkWinfo.interps - ip_list)[0]) && app =~ /^#{ip_name}/ p TkWinfo.interps # create RemoteTkIp object ip = RemoteTkIp.new(app) # setup remote-ip window btns = [] ip.eval_proc{ btns << TkButton.new(:command=>proc{ puts 'This procesure is on the controller-ip (Ruby-side)' }, :text=>'print on controller-ip (Ruby-side)').pack(:fill=>:x) btns << TkButton.new(:command=> 'puts {This procesure is on the remote-ip (Tk-side)}', :text=>'print on remote-ip (Tk-side)').pack(:fill=>:x) btns << TkButton.new(:command=> 'ruby { puts "This procedure is on the remote-ip (Ruby-side)" p Array.new(3,"ruby") }', :text=>'ruby cmd on the remote-ip').pack(:fill=>:x) TkButton.new(:command=>'exit', :text=>'QUIT').pack(:fill=>:x) } # setup controller-ip window btns.each_with_index{|btn, idx| # The scope of the eval-block of 'eval_proc' method is different from # the enternal. If you want to pass local values to the eval-block, # use arguments of eval_proc method. They are passed to block-arguments. TkButton.new(:command=>proc{ip.eval_proc(btn){|b| b.flash}}, :text=>"flash button-#{idx}", :padx=>10).pack(:padx=>10, :pady=>2) } TkButton.new(:command=>proc{exit}, :text=>'QUIT', :padx=>10, :pady=>7).pack(:padx=>10, :pady=>7) # start eventloop Tk.mainloop ================================================ FILE: ext/tk/sample/resource.en ================================================ ! ! see Tcl/Tk's "options" manual for "Database Name" and "Database Class" ! *BtnFrame.borderWidth: 5 *BtnFrame.relief: ridge *BtnFrame.Button.background: wheat *BtnFrame.Button.foreground: red *hello.text: HELLO *quit.text: QUIT *BTN_CMD.show_msg: {|arg| print "($SAFE=#{$SAFE}) ";\ print "Hello!! This is a sample of #{arg}.";\ print "(<<< $SAFE=#{$SAFE})\n"} *BTN_CMD.bye_msg: {print "($SAFE=#{$SAFE} >>>) Good-bye(<<< $SAFE=#{$SAFE})\n"} ================================================ FILE: ext/tk/sample/resource.ja ================================================ ! ! see Tcl/Tk's "options" manual for "Database Name" and "Database Class" ! *BtnFrame.borderWidth: 5 *BtnFrame.relief: ridge *BtnFrame.Button.background: wheat *BtnFrame.Button.foreground: red *hello.text: ˤ *quit.text: λ *BTN_CMD.show_msg: {|arg| print "($SAFE=#{$SAFE} >>>) ";\ print "ˤϡ #{arg} ΥץǤ";\ print "(<<< $SAFE=#{$SAFE})\n"} *BTN_CMD.bye_msg: {print "($SAFE=#{$SAFE} >>>) 褦ʤ顥(<<< $SAFE=#{$SAFE})\n"} ================================================ FILE: ext/tk/sample/safe-tk.rb ================================================ #!/usr/bin/env ruby # This script is a sample of MultiTkIp class require "multi-tk" ############################### TkLabel.new(:text=>'This is the Default Master Ipnterpreter').pack(:padx=>5, :pady=>3) TkButton.new(:text=>'QUIT', :command=>proc{exit}).pack(:pady=>3) TkFrame.new(:borderwidth=>2, :height=>3, :relief=>:sunken).pack(:fill=>:x, :expand=>true, :padx=>10, :pady=>7) ############################### puts "---- create a safe slave IP with Ruby's safe-level == 1 ----------" ip = MultiTkIp.new_safe_slave(1) puts "\n---- create procs ----------" puts 'x = proc{p [\'proc x\', "$SAFE==#{$SAFE}"]; exit}' x = proc{p ['proc x', "$SAFE==#{$SAFE}"]; exit} TkLabel.new(:text=>'x = proc{p [\'proc x\', "$SAFE==#{$SAFE}"]; exit}', :anchor=>:w).pack(:fill=>:x) puts 'y = proc{|label| p [\'proc y\', "$SAFE==#{$SAFE}", label]; label.text($SAFE)}' y = proc{|label| p ['proc y', "$SAFE==#{$SAFE}", label]; label.text($SAFE)} TkLabel.new(:text=>'y = proc{|label| p [\'proc y\', "$SAFE==#{$SAFE}", label]; label.text($SAFE)}', :anchor=>:w).pack(:fill=>:x) puts 'z = proc{p [\'proc z\', "$SAFE==#{$SAFE}"]; exit}' z = proc{p ['proc z', "$SAFE==#{$SAFE}"]; exit} TkLabel.new(:text=>'z = proc{p [\'proc z\', "$SAFE==#{$SAFE}"]; exit}', :anchor=>:w).pack(:fill=>:x) puts "\n---- call 1st eval_proc ----------" print 'lbl = ' p lbl = ip.eval_proc{ TkLabel.new(:text=>"1st eval_proc : $SAFE == #{$SAFE}").pack f = TkFrame.new.pack TkLabel.new(f, :text=>"$SAFE == ").pack(:side=>:left) # TkLabel.new(f, :text=>" (<-- 'lbl' widget is here)").pack(:side=>:right) l = TkLabel.new(f).pack(:side=>:right) TkButton.new(:text=>':command=>proc{l.text($SAFE)}', :command=>proc{l.text($SAFE)}).pack(:fill=>:x, :padx=>5) TkButton.new(:text=>':command=>x', :command=>x).pack(:fill=>:x, :padx=>5) TkButton.new(:text=>':command=>proc{exit}', :command=>proc{exit}).pack(:fill=>:x, :padx=>5) TkFrame.new(:borderwidth=>2, :height=>3, :relief=>:sunken).pack(:fill=>:x, :expand=>true, :padx=>10, :pady=>7) l # return the label widget } puts "\n---- change the safe slave IP's safe-level ==> 3 ----------" ip.safe_level = 3 puts "\n---- call 2nd eval_proc ----------" p ip.eval_proc(proc{ TkLabel.new(:text=>"2nd eval_proc : $SAFE == #{$SAFE}").pack f = TkFrame.new.pack TkLabel.new(f, :text=>"$SAFE == ").pack(:side=>:left) l = TkLabel.new(f, :text=>$SAFE).pack(:side=>:right) TkButton.new(:text=>':command=>proc{l.text($SAFE)}', :command=>proc{l.text($SAFE)}).pack(:fill=>:x, :padx=>5) TkButton.new(:text=>':command=>proc{y.call(l)}', :command=>proc{y.call(l)}).pack(:fill=>:x, :padx=>5) TkButton.new(:text=>':command=>proc{Thread.new(l, &y).value}', :command=>proc{ Thread.new(l, &y).value }).pack(:fill=>:x, :padx=>5) TkButton.new(:text=>':command=>proc{z.call}', :command=>proc{z.call}).pack(:fill=>:x, :padx=>5) TkFrame.new(:borderwidth=>2, :height=>3, :relief=>:sunken).pack(:fill=>:x, :expand=>true, :padx=>10, :pady=>7) }) puts "\n---- call 1st and 2nd eval_str ----------" p bind = ip.eval_str(' TkLabel.new(:text=>"1st and 2nd eval_str : $SAFE == #{$SAFE}").pack f = TkFrame.new.pack TkLabel.new(f, :text=>"$SAFE == ").pack(:side=>:left) l = TkLabel.new(f, :text=>$SAFE).pack(:side=>:right) TkButton.new(:text=>":command=>proc{y.call(l)}", :command=>proc{y.call(l)}).pack(:fill=>:x, :padx=>5) binding ', binding) p ip.eval_str(" TkButton.new(:text=>':command=>proc{ l.text = $SAFE }', :command=>proc{ l.text = $SAFE }).pack(:fill=>:x, :padx=>5) TkFrame.new(:borderwidth=>2, :height=>3, :relief=>:sunken).pack(:fill=>:x, :expand=>true, :padx=>10, :pady=>7) ", bind) puts "\n---- change the safe slave IP's safe-level ==> 4 ----------" ip.safe_level = 4 puts "\n---- call 3rd and 4th eval_proc ----------" p ip.eval_proc{ TkLabel.new(:text=>"3rd and 4th eval_proc : $SAFE == #{$SAFE}").pack } p ip.eval_proc{ TkButton.new(:text=>':command=>proc{ lbl.text = $SAFE }', :command=>proc{ lbl.text = $SAFE }).pack(:fill=>:x, :padx=>5) } puts "\n---- start event-loop ( current $SAFE == #{$SAFE} ) ----------" Tk.mainloop ================================================ FILE: ext/tk/sample/scrollframe.rb ================================================ # # Tk::ScrollFrame class # # This widget class is a frame widget with scrollbars. # The ScrollFrame doesn't propagate the size of embedded widgets. # When it is configured, scrollregion of the container is changed. # # Scrollbars can be toggled by Tk::ScrollFrame#vscroll & hscroll. # If horizontal or virtical scrollbar is turned off, the horizontal # or virtical size of embedded widgets is propagated. # # Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' class Tk::ScrollFrame < TkFrame include TkComposite DEFAULT_WIDTH = 200 DEFAULT_HEIGHT = 200 def initialize_composite(keys={}) @frame.configure(:width=>DEFAULT_WIDTH, :height=>DEFAULT_HEIGHT) # create scrollbars @h_scroll = TkScrollbar.new(@frame, 'orient'=>'horizontal') @v_scroll = TkScrollbar.new(@frame, 'orient'=>'vertical') # create a canvas widget @canvas = TkCanvas.new(@frame, :borderwidth=>0, :selectborderwidth=>0, :highlightthickness=>0) # allignment TkGrid.rowconfigure(@frame, 0, 'weight'=>1, 'minsize'=>0) TkGrid.columnconfigure(@frame, 0, 'weight'=>1, 'minsize'=>0) @canvas.grid('row'=>0, 'column'=>0, 'sticky'=>'news') @frame.grid_propagate(false) # assign scrollbars @canvas.xscrollbar(@h_scroll) @canvas.yscrollbar(@v_scroll) # convert hash keys keys = _symbolkey2str(keys) # check options for the frame framekeys = {} if keys.key?('classname') keys['class'] = keys.delete('classname') end if @classname = keys.delete('class') framekeys['class'] = @classname end if @colormap = keys.delete('colormap') framekeys['colormap'] = @colormap end if @container = keys.delete('container') framekeys['container'] = @container end if @visual = keys.delete('visual') framekeys['visual'] = @visual end if @classname.kind_of? TkBindTag @db_class = @classname @classname = @classname.id elsif @classname @db_class = TkDatabaseClass.new(@classname) else @db_class = self.class @classname = @db_class::WidgetClassName end # create base frame @base = TkFrame.new(@canvas, framekeys) # embed base frame @cwin = TkcWindow.new(@canvas, [0, 0], :window=>@base, :anchor=>'nw') @canvas.scrollregion(@cwin.bbox) # binding to reset scrollregion @base.bind('Configure'){ _reset_scrollregion(nil, nil) } # set default receiver of method calls @path = @base.path # scrollbars ON vscroll(keys.delete('vscroll'){true}) hscroll(keys.delete('hscroll'){true}) # please check the differences of the following definitions option_methods( :scrollbarwidth ) # set receiver widgets for configure methods (with alias) delegate_alias('scrollbarrelief', 'relief', @h_scroll, @v_scroll) # set receiver widgets for configure methods delegate('DEFAULT', @base) delegate('background', @frame, @base, @canvas, @h_scroll, @v_scroll) delegate('width', @frame) delegate('height', @frame) delegate('activebackground', @h_scroll, @v_scroll) delegate('troughcolor', @h_scroll, @v_scroll) delegate('repeatdelay', @h_scroll, @v_scroll) delegate('repeatinterval', @h_scroll, @v_scroll) delegate('borderwidth', @frame) delegate('relief', @frame) # do configure configure keys unless keys.empty? end # callback for Configure event def _reset_scrollregion(h_mod=nil, v_mod=nil) cx1, cy1, cx2, cy2 = @canvas.scrollregion x1, y1, x2, y2 = @cwin.bbox @canvas.scrollregion([x1, y1, x2, y2]) if h_mod.nil? && v_mod.nil? if x2 != cx2 && TkGrid.info(@h_scroll).size == 0 @frame.grid_propagate(true) @canvas.width = x2 Tk.update_idletasks @frame.grid_propagate(false) end if y2 != cy2 && TkGrid.info(@v_scroll).size == 0 @frame.grid_propagate(true) @canvas.height = y2 Tk.update_idletasks @frame.grid_propagate(false) end else @h_scroll.ungrid if h_mod == false @v_scroll.ungrid if v_mod == false h_flag = (TkGrid.info(@h_scroll).size == 0) v_flag = (TkGrid.info(@v_scroll).size == 0) @frame.grid_propagate(true) @canvas.width = (h_flag)? x2: @canvas.winfo_width @canvas.height = (v_flag)? y2: @canvas.winfo_height @h_scroll.grid('row'=>1, 'column'=>0, 'sticky'=>'ew') if h_mod @v_scroll.grid('row'=>0, 'column'=>1, 'sticky'=>'ns') if v_mod Tk.update_idletasks @frame.grid_propagate(false) end end private :_reset_scrollregion # forbid to change binding of @base frame def bind(*args) @frame.bind(*args) end def bind_append(*args) @frame.bind_append(*args) end def bind_remove(*args) @frame.bind_remove(*args) end def bindinfo(*args) @frame.bindinfo(*args) end # set width of scrollbar def scrollbarwidth(width = nil) if width @h_scroll.width(width) @v_scroll.width(width) else @h_scroll.width end end # vertical scrollbar : ON/OFF def vscroll(mode) Tk.update_idletasks st = TkGrid.info(@v_scroll) if mode && st.size == 0 then @v_scroll.grid('row'=>0, 'column'=>1, 'sticky'=>'ns') _reset_scrollregion(nil, true) elsif !mode && st.size != 0 then _reset_scrollregion(nil, false) else _reset_scrollregion(nil, nil) end self end # horizontal scrollbar : ON/OFF def hscroll(mode) Tk.update_idletasks st = TkGrid.info(@h_scroll) if mode && st.size == 0 then _reset_scrollregion(true, nil) elsif !mode && st.size != 0 then _reset_scrollregion(false, nil) else _reset_scrollregion(nil, nil) end self end end # test if __FILE__ == $0 f = Tk::ScrollFrame.new(:scrollbarwidth=>10, :width=>300, :height=>200) f.pack(:expand=>true, :fill=>:both) TkButton.new(f, :text=>'foo button', :command=>proc{puts 'foo'}).pack TkButton.new(f, :text=>'baaar button', :command=>proc{puts 'baaar'}).pack TkButton.new(f, :text=>'baz button', :command=>proc{puts 'baz'}).pack TkButton.new(f, :text=>'hoge hoge button', :command=>proc{puts 'hoge hoge'}).pack(:side=>:bottom) # f.hscroll(false) Tk.after(3000){ t = TkText.new(f).pack(:expand=>true, :fill=>:both) t.insert(:end, 'Here is a text widget') } Tk.after(6000){ f.vscroll(false) } Tk.after(9000){ f.vscroll(true) } Tk.after(12000){ f.hscroll(false) } Tk.after(15000){ f.hscroll(true) } Tk.mainloop end ================================================ FILE: ext/tk/sample/tcltklib/lines0.tcl ================================================ #! /usr/local/bin/wish proc drawlines {} { puts [clock format [clock seconds]] for {set j 0} {$j < 100} {incr j} { puts -nonewline "*" flush stdout if {$j & 1} { set c "blue" } { set c "red" } for {set i 0} {$i < 100} {incr i} { # .a create line $i 0 0 [expr 500 - $i] -fill $c } } puts [clock format [clock seconds]] for {set j 0} {$j < 100} {incr j} { puts -nonewline "*" flush stdout if {$j & 1} { set c "blue" } { set c "red" } for {set i 0} {$i < 100} {incr i} { .a create line $i 0 0 [expr 500 - $i] -fill $c } } puts [clock format [clock seconds]] # destroy . } canvas .a -height 500 -width 500 button .b -text draw -command drawlines pack .a .b -side left # eof ================================================ FILE: ext/tk/sample/tcltklib/lines1.rb ================================================ #! /usr/local/bin/ruby require "tcltk" def drawlines() print Time.now, "\n" for j in 0 .. 99 print "*" $stdout.flush if (j & 1) != 0 col = "blue" else col = "red" end for i in 0 .. 99 # $a.e("create line", i, 0, 0, 500 - i, "-fill", col) end end print Time.now, "\n" for j in 0 .. 99 print "*" $stdout.flush if (j & 1) != 0 col = "blue" else col = "red" end for i in 0 .. 99 $a.e("create line", i, 0, 0, 500 - i, "-fill", col) end end print Time.now, "\n" # $ip.commands()["destroy"].e($root) end $ip = TclTkInterpreter.new() $root = $ip.rootwidget() $a = TclTkWidget.new($ip, $root, "canvas", "-height 500 -width 500") $c = TclTkCallback.new($ip, proc{drawlines()}) $b = TclTkWidget.new($ip, $root, "button", "-text draw -command", $c) $ip.commands()["pack"].e($a, $b, "-side left") TclTk.mainloop # eof ================================================ FILE: ext/tk/sample/tcltklib/lines2.rb ================================================ #! /usr/local/bin/ruby require "tk" def drawlines() print Time.now, "\n" for j in 0 .. 99 print "*" $stdout.flush if (j & 1) != 0 col = "blue" else col = "red" end for i in 0 .. 99 # TkcLine.new($a, i, 0, 0, 500 - i, "-fill", col) end end print Time.now, "\n" for j in 0 .. 99 print "*" $stdout.flush if (j & 1) != 0 col = "blue" else col = "red" end for i in 0 .. 99 TkcLine.new($a, i, 0, 0, 500 - i, "-fill", col) end end print Time.now, "\n" # Tk.root.destroy end $a = TkCanvas.new{ height(500) width(500) } $b = TkButton.new{ text("draw") command(proc{drawlines()}) } TkPack.configure($a, $b, {"side"=>"left"}) Tk.mainloop # eof ================================================ FILE: ext/tk/sample/tcltklib/lines3.rb ================================================ #! /usr/local/bin/ruby require "tk" def drawlines() print Time.now, "\n" for j in 0 .. 99 print "*" $stdout.flush if (j & 1) != 0 col = "blue" else col = "red" end for i in 0 .. 99 # $a.create(TkcLine, i, 0, 0, 500 - i, "fill"=>col) end end print Time.now, "\n" for j in 0 .. 99 print "*" $stdout.flush if (j & 1) != 0 col = "blue" else col = "red" end for i in 0 .. 99 $a.create(TkcLine, i, 0, 0, 500 - i, "fill"=>col) end end print Time.now, "\n" # Tk.root.destroy end $a = TkCanvas.new{ height(500) width(500) } $b = TkButton.new{ text("draw") command(proc{drawlines()}) } TkPack.configure($a, $b, {"side"=>"left"}) Tk.mainloop # eof ================================================ FILE: ext/tk/sample/tcltklib/lines4.rb ================================================ #! /usr/local/bin/ruby require "tk" def drawlines() print Time.now, "\n" for j in 0 .. 99 print "*" $stdout.flush if (j & 1) != 0 col = "blue" else col = "red" end for i in 0 .. 99 # TkCore::INTERP.__invoke($a.path, "create", "line", i.to_s, '0', '0', (500 - i).to_s, "-fill", col) end end print Time.now, "\n" for j in 0 .. 99 print "*" $stdout.flush if (j & 1) != 0 col = "blue" else col = "red" end for i in 0 .. 99 TkCore::INTERP.__invoke($a.path, "create", "line", i.to_s, '0', '0', (500 - i).to_s, "-fill", col) end end print Time.now, "\n" # Tk.root.destroy end $a = TkCanvas.new{ height(500) width(500) } $b = TkButton.new{ text("draw") command(proc{drawlines()}) } TkPack.configure($a, $b, {"side"=>"left"}) Tk.mainloop # eof ================================================ FILE: ext/tk/sample/tcltklib/safeTk.rb ================================================ #!/usr/bin/env ruby require 'tcltklib' master = TclTkIp.new slave_name = 'slave0' slave = master.create_slave(slave_name, true) master._eval("::safe::interpInit #{slave_name}") master._eval("::safe::loadTk #{slave_name}") master._invoke('label', '.l1', '-text', 'master') master._invoke('pack', '.l1', '-padx', '30', '-pady', '50') master._eval('label .l2 -text {root widget of master-ip}') master._eval('pack .l2 -padx 30 -pady 50') slave._invoke('label', '.l1', '-text', 'slave') slave._invoke('pack', '.l1', '-padx', '30', '-pady', '50') slave._eval('label .l2 -text {root widget of slave-ip}') slave._eval('pack .l2 -padx 30 -pady 20') slave._eval('label .l3 -text {( container frame widget of master-ip )}') slave._eval('pack .l3 -padx 30 -pady 20') TclTkLib.mainloop ================================================ FILE: ext/tk/sample/tcltklib/sample0.rb ================================================ #! /usr/local/bin/ruby -vd # tcltklib 饤֥Υƥ require "tcltklib" def test # 󥿥ץ꥿ ip1 = TclTkIp.new() # ɾƤߤ print ip1._return_value().inspect, "\n" print ip1._eval("puts {abc}").inspect, "\n" # ܥäƤߤ print ip1._return_value().inspect, "\n" print ip1._eval("button .lab -text exit -command \"destroy .\"").inspect, "\n" print ip1._return_value().inspect, "\n" print ip1._eval("pack .lab").inspect, "\n" print ip1._return_value().inspect, "\n" # 󥿥ץ꥿ ruby ޥɤɾƤߤ # print ip1._eval(%q/ruby {print "print by ruby\n"}/).inspect, "\n" print ip1._eval(%q+puts [ruby {print "print by ruby\n"; "puts by tcl/tk"}]+).inspect, "\n" print ip1._return_value().inspect, "\n" # ⤦ĥ󥿥ץ꥿Ƥߤ ip2 = TclTkIp.new() ip2._eval("button .lab -text test -command \"puts test ; destroy .\"") ip2._eval("pack .lab") TclTkLib.mainloop end test GC.start print "exit\n" ================================================ FILE: ext/tk/sample/tcltklib/sample1.rb ================================================ #! /usr/local/bin/ruby -d #! /usr/local/bin/ruby # -d ץդ, ǥХåɽ. # tcltk 饤֥Υץ # ޤ, 饤֥ require . require "tcltk" # ʲ, Test1 Υ󥹥󥹤 initialize() , # tcl/tk ˴ؤԤǤ. # ɬ⤽Τ褦ˤɬפ̵, # (⤷, ) class γ tcl/tk ˴ؤԤäƤɤ. class Test1 # (󥿥ץ꥿ƥåȤ). def initialize() #### ȤΤޤʤ # 󥿥ץ꥿. ip = TclTkInterpreter.new() # ޥɤб륪֥Ȥ c ꤷƤ. c = ip.commands() # Ѥ륳ޥɤб륪֥ȤѿƤ. append, bind, button, destroy, incr, info, label, place, set, wm = c.values_at( "append", "bind", "button", "destroy", "incr", "info", "label", "place", "set", "wm") #### tcl/tk Υޥɤб륪֥(TclTkCommand) # ¹Ԥ, e() ᥽åɤȤ. # (ʲ, tcl/tk ˤ info command r* ¹.) print info.e("command", "r*"), "\n" # , ޤȤ᤿ʸˤƤƱ. print info.e("command r*"), "\n" # ѿѤʤȤ¹ԤǤ뤬, ᤬. print c["info"].e("command", "r*"), "\n" # 󥿥ץ꥿Υ᥽åɤȤƤ¹ԤǤ뤬, Ψ. print ip.info("command", "r*"), "\n" #### # ʲ, ֥ȤѿƤʤ # GC оݤˤʤäƤޤ. #### tcl/tk ѿб륪֥(TclTkVariable) # Ʊͤꤹ. v1 = TclTkVariable.new(ip, "20") # ɤ߽Ф get ᥽åɤȤ. print v1.get(), "\n" # set ᥽åɤȤ. v1.set(40) print v1.get(), "\n" # set ޥɤȤäɤ߽Ф, ϲǽ᤬. # e() ᥽åΰľ TclTkObject ͤ񤤤Ƥɤ. set.e(v1, 30) print set.e(v1), "\n" # tcl/tk ΥޥɤѿǤ. incr.e(v1) print v1.get(), "\n" append.e(v1, 10) print v1.get(), "\n" #### tcl/tk ΥåȤб륪֥(TclTkWidget) # 롼ȥåȤФ. root = ip.rootwidget() # åȤ. root.e("configure -height 300 -width 300") # ȥդȤ wm Ȥ. wm.e("title", root, $0) # ƥåȤȥޥɤꤷ, åȤ. l1 = TclTkWidget.new(ip, root, label, "-text {type `x' to print}") # place ɽ. place.e(l1, "-x 0 -rely 0.0 -relwidth 1 -relheight 0.1") # ޥ̾ʸǻꤷƤɤ, ᤬. # (ޥ̾ΩǤʤФʤʤ.) l2 = TclTkWidget.new(ip, root, "label") # åȤ. l2.e("configure -text {type `q' to exit}") place.e(l2, "-x 0 -rely 0.1 -relwidth 1 -relheight 0.1") #### tcl/tk ΥХåб륪֥(TclTkCallback) # Хå. c1 = TclTkCallback.new(ip, proc{sample(ip, root)}) # ХåĥåȤ. b1 = TclTkWidget.new(ip, root, button, "-text sample -command", c1) place.e(b1, "-x 0 -rely 0.2 -relwidth 1 -relheight 0.1") # ٥ȥ롼פȴˤ destroy.e(root) . c2 = TclTkCallback.new(ip, proc{destroy.e(root)}) b2 = TclTkWidget.new(ip, root, button, "-text exit -command", c2) place.e(b2, "-x 0 -rely 0.3 -relwidth 1 -relheight 0.1") #### ٥ȤΥХ # script ɲ (bind tag sequence +script) ϺΤȤǤʤ. # (ƥ졼ѿ꤬ޤʤ.) # ŪˤϥåȤФ륳ХåƱ. c3 = TclTkCallback.new(ip, proc{print("q pressed\n"); destroy.e(root)}) bind.e(root, "q", c3) # bind ޥɤ % ִˤѥ᡼ꤿȤ, # proc{} θʸǻꤹ, # ִ̤򥤥ƥ졼ѿ̤Ƽ뤳ȤǤ. # proc{} θʸ, # bind ޥɤͿ륳ХåʳǻꤷƤϤʤ. c4 = TclTkCallback.new(ip, proc{|i| print("#{i} pressed\n")}, "%A") bind.e(root, "x", c4) # TclTkCallback GC оݤˤ, # dcb() (ޤ deletecallbackkeys()) ɬפ. cb = [c1, c2, c3, c4] c5 = TclTkCallback.new(ip, proc{|w| TclTk.dcb(cb, root, w)}, "%W") bind.e(root, "", c5) cb.push(c5) #### tcl/tk Υ᡼б륪֥(TclTkImage) # ǡꤷ. i1 = TclTkImage.new(ip, "photo", "-file maru.gif") # ٥ĥդƤߤ. l3 = TclTkWidget.new(ip, root, label, "-relief raised -image", i1) place.e(l3, "-x 0 -rely 0.4 -relwidth 0.2 -relheight 0.2") # Υ᡼Ƹ. i2 = TclTkImage.new(ip, "photo") # ᡼. i2.e("copy", i1) i2.e("configure -gamma 0.5") l4 = TclTkWidget.new(ip, root, label, "-relief raised -image", i2) place.e(l4, "-relx 0.2 -rely 0.4 -relwidth 0.2 -relheight 0.2") #### end # ץΤΥåȤ. def sample(ip, parent) bind, button, destroy, grid, toplevel, wm = ip.commands().values_at( "bind", "button", "destroy", "grid", "toplevel", "wm") ## toplevel # ɥ򳫤ˤ, toplevel Ȥ. t1 = TclTkWidget.new(ip, parent, toplevel) # ȥդƤ wm.e("title", t1, "sample") # åȤ˲줿Ȥ, Хå GC оݤˤʤ褦ˤ. cb = [] cb.push(c = TclTkCallback.new(ip, proc{|w| TclTk.dcb(cb, t1, w)}, "%W")) bind.e(t1, "", c) # ܥ. wid = [] # toplevel åȤ˲ˤ destroy . cb.push(c = TclTkCallback.new(ip, proc{destroy.e(t1)})) wid.push(TclTkWidget.new(ip, t1, button, "-text close -command", c)) cb.push(c = TclTkCallback.new(ip, proc{test_label(ip, t1)})) wid.push(TclTkWidget.new(ip, t1, button, "-text label -command", c)) cb.push(c = TclTkCallback.new(ip, proc{test_button(ip, t1)})) wid.push(TclTkWidget.new(ip, t1, button, "-text button -command", c)) cb.push(c = TclTkCallback.new(ip, proc{test_checkbutton(ip, t1)})) wid.push(TclTkWidget.new(ip, t1, button, "-text checkbutton -command", c)) cb.push(c = TclTkCallback.new(ip, proc{test_radiobutton(ip, t1)})) wid.push(TclTkWidget.new(ip, t1, button, "-text radiobutton -command", c)) cb.push(c = TclTkCallback.new(ip, proc{test_scale(ip, t1)})) wid.push(TclTkWidget.new(ip, t1, button, "-text scale -command", c)) cb.push(c = TclTkCallback.new(ip, proc{test_entry(ip, t1)})) wid.push(TclTkWidget.new(ip, t1, button, "-text entry -command", c)) cb.push(c = TclTkCallback.new(ip, proc{test_text(ip, t1)})) wid.push(TclTkWidget.new(ip, t1, button, "-text text -command", c)) cb.push(c = TclTkCallback.new(ip, proc{test_raise(ip, t1)})) wid.push(TclTkWidget.new(ip, t1, button, "-text raise/lower -command", c)) cb.push(c = TclTkCallback.new(ip, proc{test_modal(ip, t1)})) wid.push(TclTkWidget.new(ip, t1, button, "-text message/modal -command", c)) cb.push(c = TclTkCallback.new(ip, proc{test_menu(ip, t1)})) wid.push(TclTkWidget.new(ip, t1, button, "-text menu -command", c)) cb.push(c = TclTkCallback.new(ip, proc{test_listbox(ip, t1)})) wid.push(TclTkWidget.new(ip, t1, button, "-text listbox/scrollbar", "-command", c)) cb.push(c = TclTkCallback.new(ip, proc{test_canvas(ip, t1)})) wid.push(TclTkWidget.new(ip, t1, button, "-text canvas -command", c)) # grid ɽ. ro = co = 0 wid.each{|w| grid.e(w, "-row", ro, "-column", co, "-sticky news") ro += 1 if ro == 7 ro = 0 co += 1 end } end # inittoplevel(ip, parent, title) # ʲνޤȤƹԤ. # 1. toplevel åȤ. # 2. ХåϿѰդ, toplevel åȤ # ٥Ȥ˥Хå³Ͽ. # 3. ܥ. # toplevel å, ܥ, ХåϿѿ # ֤. # ip: 󥿥ץ꥿ # parent: ƥå # title: toplevel åȤΥɥΥȥ def inittoplevel(ip, parent, title) bind, button, destroy, toplevel, wm = ip.commands().values_at( "bind", "button", "destroy", "toplevel", "wm") # ɥ򳫤ˤ, toplevel Ȥ. t1 = TclTkWidget.new(ip, parent, toplevel) # ȥդƤ wm.e("title", t1, title) # åȤ˲줿Ȥ, Хå GC оݤˤʤ褦ˤ. cb = [] cb.push(c = TclTkCallback.new(ip, proc{|w| TclTk.dcb(cb, t1, w)}, "%W")) bind.e(t1, "", c) # close ܥäƤ. # toplevel åȤ˲ˤ destroy . cb.push(c = TclTkCallback.new(ip, proc{destroy.e(t1)})) b1 = TclTkWidget.new(ip, t1, button, "-text close -command", c) return t1, b1, cb end # label Υץ. def test_label(ip, parent) button, global, label, pack = ip.commands().values_at( "button", "global", "label", "pack") t1, b1, cb = inittoplevel(ip, parent, "label") ## label # ʷΥ٥. l1 = TclTkWidget.new(ip, t1, label, "-text {default(flat)}") l2 = TclTkWidget.new(ip, t1, label, "-text raised -relief raised") l3 = TclTkWidget.new(ip, t1, label, "-text sunken -relief sunken") l4 = TclTkWidget.new(ip, t1, label, "-text groove -relief groove") l5 = TclTkWidget.new(ip, t1, label, "-text ridge -relief ridge") l6 = TclTkWidget.new(ip, t1, label, "-bitmap error") l7 = TclTkWidget.new(ip, t1, label, "-bitmap questhead") # pack Ƥɽ. pack.e(b1, l1, l2, l3, l4, l5, l6, l7, "-pady 3") ## -textvariable # tcltk 饤֥μǤ, Хå tcl/tk ``³''̤ # ƤФ. ä, Хå()ѿ˥Ȥ, # global ɬפ. # global ѿͤꤷƤޤȥ顼ˤʤΤ, # tcl/tk ˤɽ, ºݤͤꤷʤ褦, # 2 ܤΰˤ nil Ϳ. v1 = TclTkVariable.new(ip, nil) global.e(v1) v1.set(100) # -textvariable ѿꤹ. l6 = TclTkWidget.new(ip, t1, label, "-textvariable", v1) # Хå椫ѿ. cb.push(c = TclTkCallback.new(ip, proc{ global.e(v1); v1.set(v1.get().to_i + 10)})) b2 = TclTkWidget.new(ip, t1, button, "-text +10 -command", c) cb.push(c = TclTkCallback.new(ip, proc{ global.e(v1); v1.set(v1.get().to_i - 10)})) b3 = TclTkWidget.new(ip, t1, button, "-text -10 -command", c) pack.e(l6, b2, b3) end # button Υץ. def test_button(ip, parent) button, pack = ip.commands().values_at("button", "pack") t1, b1, cb = inittoplevel(ip, parent, "button") ## button # ХåǻȤѿƤʤФʤʤ. b3 = b4 = nil cb.push(c = TclTkCallback.new(ip, proc{b3.e("flash"); b4.e("flash")})) b2 = TclTkWidget.new(ip, t1, button, "-text flash -command", c) cb.push(c = TclTkCallback.new(ip, proc{b2.e("configure -state normal")})) b3 = TclTkWidget.new(ip, t1, button, "-text normal -command", c) cb.push(c = TclTkCallback.new(ip, proc{b2.e("configure -state disabled")})) b4 = TclTkWidget.new(ip, t1, button, "-text disable -command", c) pack.e(b1, b2, b3, b4) end # checkbutton Υץ. def test_checkbutton(ip, parent) checkbutton, global, pack = ip.commands().values_at( "checkbutton", "global", "pack") t1, b1, cb = inittoplevel(ip, parent, "checkbutton") ## checkbutton v1 = TclTkVariable.new(ip, nil) global.e(v1) # -variable ѿꤹ. ch1 = TclTkWidget.new(ip, t1, checkbutton, "-onvalue on -offvalue off", "-textvariable", v1, "-variable", v1) pack.e(b1, ch1) end # radiobutton Υץ. def test_radiobutton(ip, parent) global, label, pack, radiobutton = ip.commands().values_at( "global", "label", "pack", "radiobutton") t1, b1, cb = inittoplevel(ip, parent, "radiobutton") ## radiobutton v1 = TclTkVariable.new(ip, nil) global.e(v1) # ̥륹ȥ󥰤 "{}" ǻꤹ. v1.set("{}") l1 = TclTkWidget.new(ip, t1, label, "-textvariable", v1) # -variable ƱѿꤹƱ롼פˤʤ. ra1 = TclTkWidget.new(ip, t1, radiobutton, "-text radio1 -value r1 -variable", v1) ra2 = TclTkWidget.new(ip, t1, radiobutton, "-text radio2 -value r2 -variable", v1) cb.push(c = TclTkCallback.new(ip, proc{global.e(v1); v1.set("{}")})) ra3 = TclTkWidget.new(ip, t1, radiobutton, "-text clear -value r3 -variable", v1, "-command", c) pack.e(b1, l1, ra1, ra2, ra3) end # scale Υץ. def test_scale(ip, parent) global, pack, scale = ip.commands().values_at( "global", "pack", "scale") t1, b1, cb = inittoplevel(ip, parent, "scale") ## scale v1 = TclTkVariable.new(ip, nil) global.e(v1) v1.set(219) # ХåǻȤѿƤʤФʤʤ. sca1 = nil cb.push(c = TclTkCallback.new(ip, proc{global.e(v1); v = v1.get(); sca1.e("configure -background", format("#%02x%02x%02x", v, v, v))})) sca1 = TclTkWidget.new(ip, t1, scale, "-label scale -orient h -from 0 -to 255 -variable", v1, "-command", c) pack.e(b1, sca1) end # entry Υץ. def test_entry(ip, parent) button, entry, global, pack = ip.commands().values_at( "button", "entry", "global", "pack") t1, b1, cb = inittoplevel(ip, parent, "entry") ## entry v1 = TclTkVariable.new(ip, nil) global.e(v1) # ̥륹ȥ󥰤 "{}" ǻꤹ. v1.set("{}") en1 = TclTkWidget.new(ip, t1, entry, "-textvariable", v1) cb.push(c = TclTkCallback.new(ip, proc{ global.e(v1); print(v1.get(), "\n"); v1.set("{}")})) b2 = TclTkWidget.new(ip, t1, button, "-text print -command", c) pack.e(b1, en1, b2) end # text Υץ. def test_text(ip, parent) button, pack, text = ip.commands().values_at( "button", "pack", "text") t1, b1, cb = inittoplevel(ip, parent, "text") ## text te1 = TclTkWidget.new(ip, t1, text) cb.push(c = TclTkCallback.new(ip, proc{ # 1 ܤ 0 ʸܤǸޤǤɽ, . print(te1.e("get 1.0 end")); te1.e("delete 1.0 end")})) b2 = TclTkWidget.new(ip, t1, button, "-text print -command", c) pack.e(b1, te1, b2) end # raise/lower Υץ. def test_raise(ip, parent) button, frame, lower, pack, raise = ip.commands().values_at( "button", "frame", "lower", "pack", "raise") t1, b1, cb = inittoplevel(ip, parent, "raise/lower") ## raise/lower # button 򱣤ƥȤΤ, frame Ȥ. f1 = TclTkWidget.new(ip, t1, frame) # ХåǻȤѿƤʤФʤʤ. b2 = nil cb.push(c = TclTkCallback.new(ip, proc{raise.e(f1, b2)})) b2 = TclTkWidget.new(ip, t1, button, "-text raise -command", c) cb.push(c = TclTkCallback.new(ip, proc{lower.e(f1, b2)})) b3 = TclTkWidget.new(ip, t1, button, "-text lower -command", c) lower.e(f1, b3) pack.e(b2, b3, "-in", f1) pack.e(b1, f1) end # modal ʥåȤΥץ. def test_modal(ip, parent) button, frame, message, pack, tk_chooseColor, tk_getOpenFile, tk_messageBox = ip.commands().values_at( "button", "frame", "message", "pack", "tk_chooseColor", "tk_getOpenFile", "tk_messageBox") # ǽ load Ƥʤ饤֥ ip.commands() ¸ߤʤΤ, # TclTkLibCommand ɬפ. tk_dialog = TclTkLibCommand.new(ip, "tk_dialog") t1, b1, cb = inittoplevel(ip, parent, "message/modal") ## message mes = " message åȤΥƥȤǤ." mes += "ʲ modal ʥåȤΥƥȤǤ." me1 = TclTkWidget.new(ip, t1, message, "-text {#{mes}}") ## modal # tk_messageBox cb.push(c = TclTkCallback.new(ip, proc{ print tk_messageBox.e("-type yesnocancel -message messageBox", "-icon error -default cancel -title messageBox"), "\n"})) b2 = TclTkWidget.new(ip, t1, button, "-text messageBox -command", c) # tk_dialog cb.push(c = TclTkCallback.new(ip, proc{ # å̾뤿˥ߡ frame . print tk_dialog.e(TclTkWidget.new(ip, t1, frame), "dialog dialog error 2 yes no cancel"), "\n"})) b3 = TclTkWidget.new(ip, t1, button, "-text dialog -command", c) # tk_chooseColor cb.push(c = TclTkCallback.new(ip, proc{ print tk_chooseColor.e("-title chooseColor"), "\n"})) b4 = TclTkWidget.new(ip, t1, button, "-text chooseColor -command", c) # tk_getOpenFile cb.push(c = TclTkCallback.new(ip, proc{ print tk_getOpenFile.e("-defaultextension .rb", "-filetypes {{{Ruby Script} {.rb}} {{All Files} {*}}}", "-title getOpenFile"), "\n"})) b5 = TclTkWidget.new(ip, t1, button, "-text getOpenFile -command", c) pack.e(b1, me1, b2, b3, b4, b5) end # menu Υץ. def test_menu(ip, parent) global, menu, menubutton, pack = ip.commands().values_at( "global", "menu", "menubutton", "pack") tk_optionMenu = TclTkLibCommand.new(ip, "tk_optionMenu") t1, b1, cb = inittoplevel(ip, parent, "menu") ## menu # menubutton . mb1 = TclTkWidget.new(ip, t1, menubutton, "-text menu") # menu . me1 = TclTkWidget.new(ip, mb1, menu) # mb1 me1 ư褦ˤ. mb1.e("configure -menu", me1) # cascade ǵư menu . me11 = TclTkWidget.new(ip, me1, menu) # radiobutton Υץ. v1 = TclTkVariable.new(ip, nil); global.e(v1); v1.set("r1") me11.e("add radiobutton -label radio1 -value r1 -variable", v1) me11.e("add radiobutton -label radio2 -value r2 -variable", v1) me11.e("add radiobutton -label radio3 -value r3 -variable", v1) # cascade ˤ mb11 ư褦ˤ. me1.e("add cascade -label cascade -menu", me11) # checkbutton Υץ. v2 = TclTkVariable.new(ip, nil); global.e(v2); v2.set("none") me1.e("add checkbutton -label check -variable", v2) # separator Υץ. me1.e("add separator") # command Υץ. v3 = nil cb.push(c = TclTkCallback.new(ip, proc{ global.e(v1, v2, v3); print "v1: ", v1.get(), ", v2: ", v2.get(), ", v3: ", v3.get(), "\n"})) me1.e("add command -label print -command", c) ## tk_optionMenu v3 = TclTkVariable.new(ip, nil); global.e(v3); v3.set("opt2") om1 = TclTkWidget.new(ip, t1, tk_optionMenu, v3, "opt1 opt2 opt3 opt4") pack.e(b1, mb1, om1, "-side left") end # listbox Υץ. def test_listbox(ip, parent) clipboard, frame, grid, listbox, lower, menu, menubutton, pack, scrollbar, selection = ip.commands().values_at( "clipboard", "frame", "grid", "listbox", "lower", "menu", "menubutton", "pack", "scrollbar", "selection") t1, b1, cb = inittoplevel(ip, parent, "listbox") ## listbox/scrollbar f1 = TclTkWidget.new(ip, t1, frame) # ХåǻȤѿƤʤФʤʤ. li1 = sc1 = sc2 = nil # ¹Ի, ˥ѥ᡼ĤХå, # ƥ졼ѿǤΥѥ᡼뤳ȤǤ. # (ʣΥѥ᡼ϤҤȤĤʸˤޤȤ.) cb.push(c1 = TclTkCallback.new(ip, proc{|i| li1.e("xview", i)})) cb.push(c2 = TclTkCallback.new(ip, proc{|i| li1.e("yview", i)})) cb.push(c3 = TclTkCallback.new(ip, proc{|i| sc1.e("set", i)})) cb.push(c4 = TclTkCallback.new(ip, proc{|i| sc2.e("set", i)})) # listbox li1 = TclTkWidget.new(ip, f1, listbox, "-xscrollcommand", c3, "-yscrollcommand", c4, "-selectmode extended -exportselection true") for i in 1..20 li1.e("insert end {line #{i} line #{i} line #{i} line #{i} line #{i}}") end # scrollbar sc1 = TclTkWidget.new(ip, f1, scrollbar, "-orient horizontal -command", c1) sc2 = TclTkWidget.new(ip, f1, scrollbar, "-orient vertical -command", c2) ## selection/clipboard mb1 = TclTkWidget.new(ip, t1, menubutton, "-text edit") me1 = TclTkWidget.new(ip, mb1, menu) mb1.e("configure -menu", me1) cb.push(c = TclTkCallback.new(ip, proc{ # clipboard 򥯥ꥢ. clipboard.e("clear") # selection ʸɤ߹ clipboard ɲä. clipboard.e("append {#{selection.e('get')}}")})) me1.e("add command -label {selection -> clipboard} -command",c) cb.push(c = TclTkCallback.new(ip, proc{ # li1 򥯥ꥢ. li1.e("delete 0 end") # clipboard ʸФ, 1 Ԥ selection.e("get -selection CLIPBOARD").split(/\n/).each{|line| # li1 . li1.e("insert end {#{line}}")}})) me1.e("add command -label {clipboard -> listbox} -command",c) grid.e(li1, "-row 0 -column 0 -sticky news") grid.e(sc1, "-row 1 -column 0 -sticky ew") grid.e(sc2, "-row 0 -column 1 -sticky ns") grid.e("rowconfigure", f1, "0 -weight 100") grid.e("columnconfigure", f1, "0 -weight 100") f2 = TclTkWidget.new(ip, t1, frame) lower.e(f2, b1) pack.e(b1, mb1, "-in", f2, "-side left") pack.e(f2, f1) end # canvas Υץ. def test_canvas(ip, parent) canvas, lower, pack = ip.commands().values_at("canvas", "lower", "pack") t1, b1, cb = inittoplevel(ip, parent, "canvas") ## canvas ca1 = TclTkWidget.new(ip, t1, canvas, "-width 400 -height 300") lower.e(ca1, b1) # rectangle . idr = ca1.e("create rectangle 10 10 20 20") # oval . ca1.e("create oval 60 10 100 50") # polygon . ca1.e("create polygon 110 10 110 30 140 10") # line . ca1.e("create line 150 10 150 30 190 10") # arc . ca1.e("create arc 200 10 250 50 -start 0 -extent 90 -style pieslice") # i1 , ɤ˲ʤФʤʤ, ݤʤΤäƤ. i1 = TclTkImage.new(ip, "photo", "-file maru.gif") # image . ca1.e("create image 100 100 -image", i1) # bitmap . ca1.e("create bitmap 260 50 -bitmap questhead") # text . ca1.e("create text 320 50 -text {drag rectangle}") # window (ܥ). ca1.e("create window 200 200 -window", b1) # bind ˤ rectangle drag Ǥ褦ˤ. cb.push(c = TclTkCallback.new(ip, proc{|i| # i x y Τ, Ф. x, y = i.split(/ /); x = x.to_f; y = y.to_f # ɸѹ. ca1.e("coords current #{x - 5} #{y - 5} #{x + 5} #{y + 5}")}, # x, y ɸǶڤäΤ򥤥ƥ졼ѿϤ褦˻. "%x %y")) # rectangle bind . ca1.e("bind", idr, "", c) pack.e(ca1) end end # test driver if ARGV.size == 0 print "#{$0} n , n ĤΥ󥿥ץ꥿ưޤ.\n" n = 1 else n = ARGV[0].to_i end print "start\n" ip = [] # 󥿥ץ꥿, å. for i in 1 .. n ip.push(Test1.new()) end # ѰդǤ饤٥ȥ롼פ. TclTk.mainloop() print "exit from mainloop\n" # 󥿥ץ꥿ GC 뤫Υƥ. ip = [] print "GC.start\n" if $DEBUG GC.start() if $DEBUG print "end\n" exit # end ================================================ FILE: ext/tk/sample/tcltklib/sample2.rb ================================================ #!/usr/local/bin/ruby #----------------------> pretty simple othello game <----------------------- # othello.rb # # version 0.3 # maeda shugo (shuto@po.aianet.ne.jp) #--------------------------------------------------------------------------- # Sep. 17, 1997 modified by Y. Shigehiro for tcltk library # maeda shugo (shugo@po.aianet.ne.jp) ˤ # (ruby/tk ǽ񤫤Ƥ) ruby Υץץ # http://www.aianet.or.jp/~shugo/ruby/othello.rb.gz # tcltk 饤֥Ȥ褦, ŪѹƤߤޤ. # # ʤ٤ꥸʥƱˤʤ褦ˤƤޤ. require "observer" require "tcltk" $ip = TclTkInterpreter.new() $root = $ip.rootwidget() $button, $canvas, $checkbutton, $frame, $label, $pack, $update, $wm = $ip.commands().values_at( "button", "canvas", "checkbutton", "frame", "label", "pack", "update", "wm") class Othello EMPTY = 0 BLACK = 1 WHITE = - BLACK attr :in_com_turn attr :game_over class Board include Observable DIRECTIONS = [ [-1, -1], [-1, 0], [-1, 1], [ 0, -1], [ 0, 1], [ 1, -1], [ 1, 0], [ 1, 1] ] attr_accessor :com_disk def initialize(othello) @othello = othello reset end def notify_observers(*arg) if @observer_peers != nil super(*arg) end end def reset @data = [ [EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY], [EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY], [EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY], [EMPTY, EMPTY, EMPTY, WHITE, BLACK, EMPTY, EMPTY, EMPTY], [EMPTY, EMPTY, EMPTY, BLACK, WHITE, EMPTY, EMPTY, EMPTY], [EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY], [EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY], [EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY] ] changed notify_observers end def man_disk return - @com_disk end def other_disk(disk) return - disk end def get_disk(row, col) return @data[row][col] end def reverse_to(row, col, my_disk, dir_y, dir_x) y = row x = col begin y += dir_y x += dir_x if y < 0 || x < 0 || y > 7 || x > 7 || @data[y][x] == EMPTY return end end until @data[y][x] == my_disk begin @data[y][x] = my_disk changed notify_observers(y, x) y -= dir_y x -= dir_x end until y == row && x == col end def put_disk(row, col, disk) @data[row][col] = disk changed notify_observers(row, col) DIRECTIONS.each do |dir| reverse_to(row, col, disk, *dir) end end def count_disk(disk) num = 0 @data.each do |rows| rows.each do |d| if d == disk num += 1 end end end return num end def count_point_to(row, col, my_disk, dir_y, dir_x) return 0 if @data[row][col] != EMPTY count = 0 loop do row += dir_y col += dir_x break if row < 0 || col < 0 || row > 7 || col > 7 case @data[row][col] when my_disk return count when other_disk(my_disk) count += 1 when EMPTY break end end return 0 end def count_point(row, col, my_disk) count = 0 DIRECTIONS.each do |dir| count += count_point_to(row, col, my_disk, *dir) end return count end def corner?(row, col) return (row == 0 && col == 0) || (row == 0 && col == 7) || (row == 7 && col == 0) || (row == 7 && col == 7) end def search(my_disk) max = 0 max_row = nil max_col = nil for row in 0 .. 7 for col in 0 .. 7 buf = count_point(row, col, my_disk) if (corner?(row, col) && buf > 0) || max < buf max = buf max_row = row max_col = col end end end return max_row, max_col end end #--------------------------> class Board ends here class BoardView < TclTkWidget BACK_GROUND_COLOR = "DarkGreen" HILIT_BG_COLOR = "green" BORDER_COLOR = "black" BLACK_COLOR = "black" WHITE_COLOR = "white" STOP_COLOR = "red" attr :left attr :top attr :right attr :bottom class Square attr :oval, TRUE attr :row attr :col def initialize(view, row, col) @view = view @id = @view.e("create rectangle", *(view.tk_rect(view.left + col, view.top + row, view.left + col + 1, view.top + row + 1) \ << "-fill #{BACK_GROUND_COLOR}") ) @row = row @col = col @view.e("itemconfigure", @id, "-width 0.5m -outline #{BORDER_COLOR}") @view.e("bind", @id, "", TclTkCallback.new($ip, proc{ if @oval == nil view.e("itemconfigure", @id, "-fill #{HILIT_BG_COLOR}") end })) @view.e("bind", @id, "", TclTkCallback.new($ip, proc{ view.e("itemconfigure", @id, "-fill #{BACK_GROUND_COLOR}") })) @view.e("bind", @id, "", TclTkCallback.new($ip, proc{ view.click_square(self) })) end def blink(color) @view.e("itemconfigure", @id, "-fill #{color}") $update.e() sleep(0.1) @view.e("itemconfigure", @id, "-fill #{BACK_GROUND_COLOR}") end end #-----------------------> class Square ends here def initialize(othello, board) super($ip, $root, $canvas) @othello = othello @board = board @board.add_observer(self) @squares = Array.new(8) for i in 0 .. 7 @squares[i] = Array.new(8) end @left = 1 @top = 0.5 @right = @left + 8 @bottom = @top + 8 i = self.e("create rectangle", *tk_rect(@left, @top, @right, @bottom)) self.e("itemconfigure", i, "-width 1m -outline #{BORDER_COLOR} -fill #{BACK_GROUND_COLOR}") for row in 0 .. 7 for col in 0 .. 7 @squares[row][col] = Square.new(self, row, col) end end update end def tk_rect(left, top, right, bottom) return left.to_s + "c", top.to_s + "c", right.to_s + "c", bottom.to_s + "c" end def clear each_square do |square| if square.oval != nil self.e("delete", square.oval) square.oval = nil end end end def draw_disk(row, col, disk) if disk == EMPTY if @squares[row][col].oval != nil self.e("delete", @squares[row][col].oval) @squares[row][col].oval = nil end return end $update.e() sleep(0.05) oval = @squares[row][col].oval if oval == nil oval = self.e("create oval", *tk_rect(@left + col + 0.2, @top + row + 0.2, @left + col + 0.8, @top + row + 0.8)) @squares[row][col].oval = oval end case disk when BLACK color = BLACK_COLOR when WHITE color = WHITE_COLOR else fail format("Unknown disk type: %d", disk) end self.e("itemconfigure", oval, "-outline #{color} -fill #{color}") end def update(row = nil, col = nil) if row && col draw_disk(row, col, @board.get_disk(row, col)) else each_square do |square| draw_disk(square.row, square.col, @board.get_disk(square.row, square.col)) end end @othello.show_point end def each_square @squares.each do |rows| rows.each do |square| yield(square) end end end def click_square(square) if @othello.in_com_turn || @othello.game_over || @board.count_point(square.row, square.col, @board.man_disk) == 0 square.blink(STOP_COLOR) return end @board.put_disk(square.row, square.col, @board.man_disk) @othello.com_turn end private :draw_disk public :update end #----------------------> class BoardView ends here def initialize @msg_label = TclTkWidget.new($ip, $root, $label) $pack.e(@msg_label) @board = Board.new(self) @board_view = BoardView.new(self, @board) #### added by Y. Shigehiro ## board_view 礭ꤹ. x1, y1, x2, y2 = @board_view.e("bbox all").split(/ /).collect{|i| i.to_f} @board_view.e("configure -width", x2 - x1) @board_view.e("configure -height", y2 - y1) ## scrollregion ꤹ. @board_view.e("configure -scrollregion {", @board_view.e("bbox all"), "}") #### ޤ $pack.e(@board_view, "-fill both -expand true") panel = TclTkWidget.new($ip, $root, $frame) @play_black = TclTkWidget.new($ip, panel, $checkbutton, "-text {com is black} -command", TclTkCallback.new($ip, proc{ switch_side })) $pack.e(@play_black, "-side left") quit = TclTkWidget.new($ip, panel, $button, "-text Quit -command", TclTkCallback.new($ip, proc{ exit })) $pack.e(quit, "-side right -fill x") reset = TclTkWidget.new($ip, panel, $button, "-text Reset -command", TclTkCallback.new($ip, proc{ reset_game })) $pack.e(reset, "-side right -fill x") $pack.e(panel, "-side bottom -fill x") # root = Tk.root $wm.e("title", $root, "Othello") $wm.e("iconname", $root, "Othello") @board.com_disk = WHITE @game_over = FALSE TclTk.mainloop end def switch_side if @in_com_turn @play_black.e("toggle") else @board.com_disk = @board.man_disk com_turn unless @game_over end end def reset_game if @board.com_disk == BLACK @board.com_disk = WHITE @play_black.e("toggle") end @board_view.clear @board.reset $wm.e("title", $root, "Othello") @game_over = FALSE end def com_turn @in_com_turn = TRUE $update.e() sleep(0.5) begin com_disk = @board.count_disk(@board.com_disk) man_disk = @board.count_disk(@board.man_disk) if @board.count_disk(EMPTY) == 0 if man_disk == com_disk $wm.e("title", $root, "{Othello - Draw!}") elsif man_disk > com_disk $wm.e("title", $root, "{Othello - You Win!}") else $wm.e("title", $root, "{Othello - You Loose!}") end @game_over = TRUE break elsif com_disk == 0 $wm.e("title", $root, "{Othello - You Win!}") @game_over = TRUE break elsif man_disk == 0 $wm.e("title", $root, "{Othello - You Loose!}") @game_over = TRUE break end row, col = @board.search(@board.com_disk) break if row == nil || col == nil @board.put_disk(row, col, @board.com_disk) end while @board.search(@board.man_disk) == [nil, nil] @in_com_turn = FALSE end def show_point black = @board.count_disk(BLACK) white = @board.count_disk(WHITE) @msg_label.e("configure -text", %Q/{#{format("BLACK: %.2d WHITE: %.2d", black, white)}}/) end end #----------------------> class Othello ends here Othello.new #----------------------------------------------> othello.rb ends here ================================================ FILE: ext/tk/sample/tkalignbox.rb ================================================ # # tkalignbox.rb : align widgets with same width/height # # by Hidetoshi NAGAI # # The box size depends on 'reqheight' and 'reqwidth' of contained widgets. # If you want to give the box size when those requested sizes are 0, # please set box.propagate = false (See the test routine at the tail of # this file). require 'tk' class TkAlignBox < TkFrame def initialize(*args) if self.class == TkAlignBox fail RuntimeError, "TkAlignBox is an abstract class" end @padx = 0 @pady = 0 if args[-1].kind_of? Hash keys = _symbolkey2str(args.pop) @padx = keys.delete('padx') || 0 @pady = keys.delete('pady') || 0 args.push(keys) end super(*args) @max_width = 0 @max_height = 0 @propagate = true @widgets = [] end def _set_framesize fail RuntimeError, "TkAlignBox is an abstract class" end private :_set_framesize def _place_config(widget, idx, cnt) fail RuntimeError, "TkAlignBox is an abstract class" end private :_place_config def align widgets = [] @widgets.each{|w| widgets << w if w.winfo_exist?} @widgets = widgets cnt = @widgets.size.to_f @widgets.each_with_index{|w, idx| _place_config(w, idx, cnt)} @widgets = widgets _set_framesize if @propagate self end def add(*widgets) widgets.each{|w| unless w.kind_of? TkWindow fail RuntimeError, "#{w.inspect} is not a widget instance." end @widgets.delete(w) @widgets << w sz = w.winfo_reqwidth @max_width = sz if @max_width < sz sz = w.winfo_reqheight @max_height = sz if @max_height < sz } align end def <<(widget) add(widget) end def insert(idx, widget) unless widget.kind_of? TkWindow fail RuntimeError, "#{widget.inspect} is not a widget instance." end @widgets.delete(widget) @widgets[idx,0] = widget sz = widget.winfo_reqwidth @max_width = sz if @max_width < sz sz = widget.winfo_reqheight @max_height = sz if @max_height < sz align end def delete(idx) ret = @widgets.delete_at(idx) @req_size = 0 @widget.each{|w| sz = w.winfo_reqwidth @max_width = sz if @max_width < sz sz = w.winfo_reqheight @max_height = sz if @max_height < sz } align ret end def padx(size = nil) if size @padx = size align else @padx end end def pady(size = nil) if size @pady = size align else @pady end end attr_accessor :propagate end class TkHBox < TkAlignBox def _set_framesize bd = self.borderwidth self.width((@max_width + 2*@padx) * @widgets.size + 2*bd) self.height(@max_height + 2*@pady + 2*bd) end private :_set_framesize def _place_config(widget, idx, cnt) widget.place_in(self, 'relx'=>idx/cnt, 'x'=>@padx, 'rely'=>0, 'y'=>@pady, 'relwidth'=>1.0/cnt, 'width'=>-2*@padx, 'relheight'=>1.0, 'height'=>-2*@pady) end private :_place_config end TkHLBox = TkHBox class TkHRBox < TkHBox def _place_config(widget, idx, cnt) widget.place_in(self, 'relx'=>(cnt - idx - 1)/cnt, 'x'=>@padx, 'rely'=>0, 'y'=>@pady, 'relwidth'=>1.0/cnt, 'width'=>-2*@padx, 'relheight'=>1.0, 'height'=>-2*@pady) end private :_place_config end class TkVBox < TkAlignBox def _set_framesize bd = self.borderwidth self.width(@max_width + 2*@padx + 2*bd) self.height((@max_height + 2*@pady) * @widgets.size + 2*bd) end private :_set_framesize def _place_config(widget, idx, cnt) widget.place_in(self, 'relx'=>0, 'x'=>@padx, 'rely'=>idx/cnt, 'y'=>@pady, 'relwidth'=>1.0, 'width'=>-2*@padx, 'relheight'=>1.0/cnt, 'height'=>-2*@pady) end private :_place_config end TkVTBox = TkVBox class TkVBBox < TkVBox def _place_config(widget, idx, cnt) widget.place_in(self, 'relx'=>0, 'x'=>@padx, 'rely'=>(cnt - idx - 1)/cnt, 'y'=>@pady, 'relwidth'=>1.0, 'width'=>-2*@padx, 'relheight'=>1.0/cnt, 'height'=>-2*@pady) end private :_place_config end ################################################ # test ################################################ if __FILE__ == $0 f = TkHBox.new(:borderwidth=>3, :relief=>'ridge').pack f.add(TkButton.new(f, :text=>'a'), TkButton.new(f, :text=>'aa', :font=>'Helvetica 16'), TkButton.new(f, :text=>'aaa'), TkButton.new(f, :text=>'aaaa')) f = TkHBox.new(:borderwidth=>3, :relief=>'ridge', :padx=>7, :pady=>3, :background=>'yellow').pack f.add(TkButton.new(f, :text=>'a'), TkButton.new(f, :text=>'aa', :font=>'Helvetica 16'), TkButton.new(f, :text=>'aaa'), TkButton.new(f, :text=>'aaaa')) f = TkVBox.new(:borderwidth=>5, :relief=>'groove').pack f.add(TkButton.new(f, :text=>'a'), TkButton.new(f, :text=>'aa', :font=>'Helvetica 30'), TkButton.new(f, :text=>'aaa'), TkButton.new(f, :text=>'aaaa')) f = TkHRBox.new(:borderwidth=>3, :relief=>'raised').pack(:fill=>:x) f.add(TkButton.new(f, :text=>'a'), TkButton.new(f, :text=>'aa'), TkButton.new(f, :text=>'aaa')) f = TkVBBox.new(:borderwidth=>3, :relief=>'ridge').pack(:fill=>:x) f.propagate = false f.height 100 f.add(TkFrame.new(f){|ff| TkButton.new(ff, :text=>'a').pack(:pady=>4, :padx=>6, :fill=>:both, :expand=>true) }, TkFrame.new(f){|ff| TkButton.new(ff, :text=>'aa').pack(:pady=>4, :padx=>6, :fill=>:both, :expand=>true) }, TkFrame.new(f){|ff| TkButton.new(ff, :text=>'aaaa').pack(:pady=>4, :padx=>6, :fill=>:both, :expand=>true) }) Tk.mainloop end ================================================ FILE: ext/tk/sample/tkballoonhelp.rb ================================================ # # tkballoonhelp.rb : simple balloon help widget # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # # Add a balloon help to a widget. # This widget has only poor featureas. If you need more useful features, # please try to use the Tix extension of Tcl/Tk under Ruby/Tk. # # The interval time to display a balloon help is defined 'interval' option # (default is 1000ms). # require 'tk' class TkBalloonHelp'bisque').pack @label.configure(_symbolkey2str(keys)) unless keys.empty? @path = @label end def epath @epath end def interval(val) if val @timer.interval(val) else @interval end end def command(cmd = Proc.new) @command = cmd self end def show x = TkWinfo.pointerx(@parent) y = TkWinfo.pointery(@parent) @frame.geometry("+#{x+1}+#{y+1}") if @command case @command.arity when 0 @command.call when 2 @command.call(x - TkWinfo.rootx(@parent), y - TkWinfo.rooty(@parent)) when 3 @command.call(x - TkWinfo.rootx(@parent), y - TkWinfo.rooty(@parent), self) else @command.call(x - TkWinfo.rootx(@parent), y - TkWinfo.rooty(@parent), self, @parent) end end @frame.deiconify @frame.raise @org_cursor = @parent['cursor'] @parent.cursor('crosshair') end def erase @parent.cursor(@org_cursor) @frame.withdraw end def destroy @frame.destroy end end ################################################ # test ################################################ if __FILE__ == $0 TkButton.new('text'=>'This button has a balloon help') {|b| pack('fill'=>'x') TkBalloonHelp.new(b, 'text'=>' Message ') } TkButton.new('text'=>'This button has another balloon help') {|b| pack('fill'=>'x') TkBalloonHelp.new(b, 'text'=>'configured message', 'interval'=>200, 'font'=>'courier', 'background'=>'gray', 'foreground'=>'red') } sb = TkScrollbox.new.pack(:fill=>:x) sb.insert(:end, *%w(aaa bbb ccc ddd eee fff ggg hhh iii jjj kkk lll mmm)) =begin # CASE1 : command takes no arguemnt bh = TkBalloonHelp.new(sb, :interval=>500, :relief=>:ridge, :background=>'white', :command=>proc{ y = TkWinfo.pointery(sb) - TkWinfo.rooty(sb) bh.text "current index == #{sb.nearest(y)}" }) =end =begin # CASE2 : command takes 2 arguemnts bh = TkBalloonHelp.new(sb, :interval=>500, :relief=>:ridge, :background=>'white', :command=>proc{|x, y| bh.text "current index == #{sb.nearest(y)}" }) =end =begin # CASE3 : command takes 3 arguemnts TkBalloonHelp.new(sb, :interval=>500, :relief=>:ridge, :background=>'white', :command=>proc{|x, y, bhelp| bhelp.text "current index == #{sb.nearest(y)}" }) =end =begin # CASE4a : command is a Proc object and takes 4 arguemnts cmd = proc{|x, y, bhelp, parent| bhelp.text "current index == #{parent.nearest(y)}" } TkBalloonHelp.new(sb, :interval=>500, :relief=>:ridge, :background=>'white', :command=>cmd) sb2 = TkScrollbox.new.pack(:fill=>:x) sb2.insert(:end, *%w(AAA BBB CCC DDD EEE FFF GGG HHH III JJJ KKK LLL MMM)) TkBalloonHelp.new(sb2, :interval=>500, :padx=>5, :relief=>:raised, :background=>'gray25', :foreground=>'white', :command=>cmd) =end #=begin # CASE4b : command is a Method object and takes 4 arguemnts def set_msg(x, y, bhelp, parent) bhelp.text "current index == #{parent.nearest(y)}" end cmd = self.method(:set_msg) TkBalloonHelp.new(sb, :interval=>500, :relief=>:ridge, :background=>'white', :command=>cmd) sb2 = TkScrollbox.new.pack(:fill=>:x) sb2.insert(:end, *%w(AAA BBB CCC DDD EEE FFF GGG HHH III JJJ KKK LLL MMM)) TkBalloonHelp.new(sb2, :interval=>500, :padx=>5, :relief=>:raised, :background=>'gray25', :foreground=>'white', :command=>cmd) #=end Tk.mainloop end ================================================ FILE: ext/tk/sample/tkbiff.rb ================================================ #!/usr/bin/env ruby if ARGV[0] != '-d' unless $DEBUG exit if fork end else ARGV.shift end if ARGV.length == 0 if ENV['MAIL'] $spool = ENV['MAIL'] else $spool = '/var/spool/mail/' + ENV['USER'] end else $spool = ARGV[0] end require "parsedate" require "base64" include ParseDate class Mail def Mail.new(f) if !f.kind_of?(IO) f = open(f, "r") me = super f.close else me = super end return me end def initialize(f) @header = {} @body = [] while line = f.gets() line.chop! next if /^From / =~ line # skip From-line break if /^$/ =~ line # end of header if /^(\S+):\s*(.*)/ =~ line @header[attr = $1.capitalize] = $2 elsif attr sub(/^\s*/, '') @header[attr] += "\n" + $_ end end return unless $_ while line = f.gets() break if /^From / =~ line @body.push($_) end end def header return @header end def body return @body end end require "tkscrollbox" my_appname = Tk.appname('tkbiff') $top = TkRoot.new if ((TkWinfo.interps($top) - [my_appname]).find{|ip| ip =~ /^tkbiff/}) STDERR.print("Probably other 'tkbiff's are running. Bye.\n") exit end $top.withdraw $list = TkScrollbox.new($top) { relief 'raised' width 80 height 8 setgrid 'yes' pack } TkButton.new($top) { text 'Dismiss' command proc {$top.withdraw} pack('fill'=>'both','expand'=>'yes') } $top.bind "Control-c", proc{exit} $top.bind "Control-q", proc{exit} $top.bind "space", proc{exit} $spool_size = 0 $check_time = Time.now def check $check_time = Time.now size = File.size($spool) if size and size != $spool_size $spool_size = size pop_up if size > 0 end Tk.after 5000, proc{check} end if defined? Thread Thread.start do loop do sleep 600 if Time.now - $check_time > 200 Tk.after 5000, proc{check} end end end end def pop_up outcount = 0; $list.delete 0, 'end' f = open($spool, "r") while !f.eof? mail = Mail.new(f) date, from, subj = mail.header['Date'], mail.header['From'], mail.header['Subject'] next if !date y = m = d = 0 y, m, d = parsedate(date) if date from = "sombody@somewhere" if ! from subj = "(nil)" if ! subj from = decode_b(from) subj = decode_b(subj) $list.insert 'end', format('%-02d/%02d/%02d [%-28.28s] %s',y,m,d,from,subj) outcount += 1 end f.close if outcount == 0 $list.insert 'end', "You have no mail." else $list.see 'end' end $top.deiconify Tk.after 2000, proc{$top.iconify} end $list.insert 'end', "You have no mail." check Tk.after 2000, proc{$top.iconify} begin Tk.mainloop rescue `echo #$! > /tmp/tkbiff` end ================================================ FILE: ext/tk/sample/tkbrowse.rb ================================================ #!/usr/bin/env ruby # # This script generates a directory browser, which lists the working # directory and allows you to open files or subdirectories by # double-clicking. # Create a scrollbar on the right side of the main window and a listbox # on the left side. require "tkscrollbox" # The procedure below is invoked to open a browser on a given file; if the # file is a directory then another instance of this program is invoked; if # the file is a regular file then the Mx editor is invoked to display # the file. $dirlist = {} def browsedir (dir) if $dirlist.key? dir $dirlist[dir] else top = if $dirlist.size > 0 then TkToplevel.new else nil end list = TkScrollbox.new(top) { relief 'raised' width 20 height 20 setgrid 'yes' pack } list.insert 'end', *`ls #{dir}`.split # Set up bindings for the browser. list.focus list.bind "Control-q", proc{exit} list.bind "Control-c", proc{exit} list.bind "Control-p", proc{ print "selection <", TkSelection.get, ">\n" } list.bind "Double-Button-1", proc{ for i in TkSelection.get.split print "clicked ", i, "\n" browse dir, i end } $dirlist[dir] = list end end def browse (dir, file) file="#{dir}/#{file}" if File.directory? file browsedir(file) else if File.file? file if ENV['EDITOR'] system format("%s %s&", ENV['EDITOR'], file) else system "xedit #{file}&" end else STDERR.print "\"#{file}\" isn't a directory or regular file" end end end # Fill the listbox with a list of all the files in the directory (run # the "ls" command to get that information). if ARGV.length>0 dir = ARGV[0] else dir="." end browsedir(dir) Tk.mainloop ================================================ FILE: ext/tk/sample/tkcombobox.rb ================================================ # # tkcombobox.rb : TkAutoScrollbox & TkCombobox # # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # require 'tk' class TkAutoScrollbox < TkListbox include TkComposite @@up_bmp = TkBitmapImage.new(:data=><<0) @path = @lbox.path TkPack.propagate(@lbox, false) @scr = TkScrollbar.new(@frame, :width=>10) @lbox.yscrollcommand(proc{|*args| @scr.set(*args); _config_proc}) @scr.command(proc{|*args| @lbox.yview(*args); _config_proc}) @up_arrow = TkLabel.new(@lbox, :image=>@@up_bmp, :relief=>:raised, :borderwidth=>1) @down_arrow = TkLabel.new(@lbox, :image=>@@down_bmp, :relief=>:raised, :borderwidth=>1) _init_binding @lbox.pack(:side=>:left, :fill=>:both, :expand=>:true) delegate('DEFAULT', @lbox) delegate('background', @frame, @scr) delegate('activebackground', @scr) delegate('troughcolor', @scr) delegate('repeatdelay', @scr) delegate('repeatinterval', @scr) delegate('relief', @frame) delegate('borderwidth', @frame) delegate_alias('arrowrelief', 'relief', @up_arrow, @down_arrow) delegate_alias('arrowborderwidth', 'borderwidth', @up_arrow, @down_arrow) scrollbar(keys.delete('scrollbar')){false} configure keys unless keys.empty? end def _show_up_arrow unless @up_arrow.winfo_mapped? @up_arrow.pack(:side=>:top, :fill=>:x) end end def _show_down_arrow unless @down_arrow.winfo_mapped? @down_arrow.pack(:side=>:bottom, :fill=>:x) end end def _set_sel(idx) @lbox.activate(idx) @lbox.selection_clear(0, 'end') @lbox.selection_set(idx) end def _check_sel(cidx, tidx = nil, bidx = nil) _set_sel(cidx) unless tidx tidx = @lbox.nearest(0) tidx += 1 if tidx > 0 end unless bidx bidx = @lbox.nearest(10000) bidx -= 1 if bidx < @lbox.index('end') - 1 end if cidx > bidx _set_sel(bidx) end if cidx < tidx _set_sel(tidx) end end def _up_proc cidx = @lbox.curselection[0] idx = @lbox.nearest(0) if idx >= 0 @lbox.see(idx - 1) _set_sel(idx) @up_arrow.pack_forget if idx == 1 @up_timer.stop if idx == 0 _show_down_arrow if @lbox.bbox('end') == [] end if cidx && cidx > 0 && (idx == 0 || cidx == @lbox.nearest(10000)) _set_sel(cidx - 1) end end def _down_proc cidx = @lbox.curselection[0] eidx = @lbox.index('end') - 1 idx = @lbox.nearest(10000) if idx <= eidx @lbox.see(idx + 1) _set_sel(cidx + 1) if cidx < eidx @down_arrow.pack_forget if idx + 1 == eidx @down_timer.stop if idx == eidx _show_up_arrow if @lbox.bbox(0) == [] end if cidx && cidx < eidx && (eidx == idx || cidx == @lbox.nearest(0)) _set_sel(cidx + 1) end end def _key_UP_proc cidx = @lbox.curselection[0] _set_sel(cidx = @lbox.index('activate')) unless cidx cidx -= 1 if cidx == 0 @up_arrow.pack_forget elsif cidx == @lbox.nearest(0) @lbox.see(cidx - 1) end end def _key_DOWN_proc cidx = @lbox.curselection[0] _set_sel(cidx = @lbox.index('activate')) unless cidx cidx += 1 if cidx == @lbox.index('end') - 1 @down_arrow.pack_forget elsif cidx == @lbox.nearest(10000) @lbox.see(cidx + 1) end end def _config_proc if @lbox.size == 0 @up_arrow.pack_forget @down_arrow.pack_forget return end tidx = @lbox.nearest(0) bidx = @lbox.nearest(10000) if tidx > 0 _show_up_arrow tidx += 1 else @up_arrow.pack_forget unless @up_timer.running? end if bidx < @lbox.index('end') - 1 _show_down_arrow bidx -= 1 else @down_arrow.pack_forget unless @down_timer.running? end cidx = @lbox.curselection[0] _check_sel(cidx, tidx, bidx) if cidx end def _init_binding @up_timer = TkAfter.new(@interval, -1, proc{_up_proc}) @down_timer = TkAfter.new(@interval, -1, proc{_down_proc}) @up_timer.set_start_proc(@initwait, proc{}) @down_timer.set_start_proc(@initwait, proc{}) @up_arrow.bind('Enter', proc{@up_timer.start}) @up_arrow.bind('Leave', proc{@up_timer.stop if @up_arrow.winfo_mapped?}) @down_arrow.bind('Enter', proc{@down_timer.start}) @down_arrow.bind('Leave', proc{@down_timer.stop if @down_arrow.winfo_mapped?}) @lbox.bind('Configure', proc{_config_proc}) @lbox.bind('Enter', proc{|y| _set_sel(@lbox.nearest(y))}, '%y') @lbox.bind('Motion', proc{|y| @up_timer.stop if @up_timer.running? @down_timer.stop if @down_timer.running? _check_sel(@lbox.nearest(y)) }, '%y') @lbox.bind('Up', proc{_key_UP_proc}) @lbox.bind('Down', proc{_key_DOWN_proc}) end ############################ public ############################ def scrollbar(mode) if mode @scr.pack(:side=>:right, :fill=>:y) else @scr.pack_forget end end end ################################################ class TkCombobox < TkEntry include TkComposite @@down_btn_bmp = TkBitmapImage.new(:data=><< 0 @lst.see(0) @lst.activate(0) @lst.selection_set(0) end @top.grab begin @var.tkwait if (idx = @var.to_i) >= 0 @ent.value = @lst.get(idx) end @top.withdraw @btn.relief(:raised) @btn.image(@@down_btn_bmp) rescue ensure begin @top.grab(:release) @ent.focus rescue end end end private :_button_proc def _init_bindings @btn.bind('1', proc{_button_proc(true)}) @btn.bind('3', proc{_button_proc(false)}) @lst.bind('1', proc{|y| @var.value = @lst.nearest(y)}, '%y') @lst.bind('Return', proc{@var.value = @lst.curselection[0]}) cancel = TkVirtualEvent.new('2', '3', 'Escape') @lst.bind(cancel, proc{@var.value = -1}) end private :_init_bindings def initialize_composite(keys={}) keys = _symbolkey2str(keys) @btn = TkLabel.new(@frame, :relief=>:raised, :borderwidth=>3, :image=>@@down_btn_bmp).pack(:side=>:right, :ipadx=>2, :fill=>:y) @ent = TkEntry.new(@frame).pack(:side=>:left) @path = @ent.path @top = TkToplevel.new(@btn, :borderwidth=>1, :relief=>:raised) { withdraw transient overrideredirect(true) } startwait = keys.delete('startwait'){300} interval = keys.delete('interval'){150} @lst = TkAutoScrollbox.new(@top, :startwait=>startwait, :interval=>interval).pack(:fill=>:both, :expand=>true) @ent_list = [] @var = TkVariable.new _init_bindings delegate('DEFAULT', @ent) delegate('height', @lst) delegate('relief', @frame) delegate('borderwidth', @frame) delegate('arrowrelief', @lst) delegate('arrowborderwidth', @lst) if mode = keys.delete('scrollbar') scrollbar(mode) end configure keys unless keys.empty? end private :initialize_composite def scrollbar(mode) @lst.scrollbar(mode) end def _reset_width len = @ent.width @lst.get(0, 'end').each{|l| len = l.length if l.length > len} @lst.width(len + 1) end private :_reset_width def add(ent) ent = ent.to_s unless @ent_list.index(ent) @ent_list << ent @lst.insert('end', ent) end _reset_width self end def remove(ent) ent = ent.to_s @ent_list.delete(ent) if idx = @lst.get(0, 'end').index(ent) @lst.delete(idx) end _reset_width self end def values(ary = nil) if ary @lst.delete(0, 'end') @ent_list.clear ary.each{|ent| add(ent)} _reset_width self else @lst.get(0, 'end') end end def see(idx) @lst.see(@lst.index(idx) - 1) end def list_index(idx) @lst.index(idx) end end ################################################ # test ################################################ if __FILE__ == $0 v = TkVariable.new e = TkCombobox.new(:height=>7, :scrollbar=>true, :textvariable=>v, :arrowrelief=>:flat, :arrowborderwidth=>0, :startwait=>400, :interval=>200).pack e.values(%w(aa bb cc dd ee ff gg hh ii jj kk ll mm nn oo pp qq rr ss tt uu)) #e.see(e.list_index('end') - 2) e.value = 'cc' TkFrame.new{|f| fnt = TkFont.new('Helvetica 10') TkLabel.new(f, :font=>fnt, :text=>'TkCombobox value :').pack(:side=>:left) TkLabel.new(f, :font=>fnt, :textvariable=>v).pack(:side=>:left) }.pack TkFrame.new(:relief=>:raised, :borderwidth=>2, :height=>3).pack(:fill=>:x, :expand=>true, :padx=>5, :pady=>3) l = TkAutoScrollbox.new(nil, :relief=>:groove, :borderwidth=>4, :width=>20).pack(:fill=>:both, :expand=>true) (0..20).each{|i| l.insert('end', "line #{i}")} TkFrame.new(:relief=>:ridge, :borderwidth=>3){ TkButton.new(self, :text=>'ON', :command=>proc{l.scrollbar(true)}).pack(:side=>:left) TkButton.new(self, :text=>'OFF', :command=>proc{l.scrollbar(false)}).pack(:side=>:right) pack(:fill=>:x) } Tk.mainloop end ================================================ FILE: ext/tk/sample/tkdialog.rb ================================================ #!/usr/bin/env ruby require "tk" root = TkFrame.new top = TkFrame.new(root) { relief 'raised' border 1 } msg = TkMessage.new(top) { text "File main.c hasn't been saved to disk since \ it was last modified. What should I do?" justify 'center' aspect 200 font '-Adobe-helvetica-medium-r-normal--*-240*' pack('padx'=>5, 'pady'=>5, 'expand'=>'yes') } top.pack('fill'=>'both') root.pack bot = TkFrame.new(root) { relief 'raised' border 1 } TkFrame.new(bot) { |left| relief 'sunken' border 1 pack('side'=>'left', 'expand'=>'yes', 'padx'=>10, 'pady'=> 10) TkButton.new(left) { text "Save File" command "quit 'save'" pack('expand'=>'yes','padx'=>6,'pady'=> 6) top.bind "Enter", proc{state 'active'} msg.bind "Enter", proc{state 'active'} bot.bind "Enter", proc{state 'active'} top.bind "Leave", proc{state 'normal'} msg.bind "Leave", proc{state 'normal'} bot.bind "Leave", proc{state 'normal'} Tk.root.bind "ButtonRelease-1", proc{quit 'save'} Tk.root.bind "Return", proc{quit 'save'} } } TkButton.new(bot) { text "Quit Anyway" command "quit 'quit'" pack('side'=>'left', 'expand'=>'yes', 'padx'=>10) } TkButton.new(bot) { text "Return To Editor" command "quit 'return'" pack('side'=>'left', 'expand'=>'yes', 'padx'=>10) } bot.pack root.pack('side'=>'top', 'fill'=>'both', 'expand'=>'yes') def quit(button) print "You pressed the \"#{button}\" button; bye-bye!\n" exit end Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/ICONS/Orig_LICENSE.txt ================================================ ######################################################################### ### The following text is the original file of the Tcl/Tk extension. ### ### Icon data files ( those are 'tkIcons', 'tkIcons-sample.kde', and ### ### 'tkIcons.kde' ) are quoted from the source archive of ICONS ### ### extension. As the following document describes, those icon images ### ### are not applied the license. ### ######################################################################### IMPORTANT LICENSE INFORMATION ============================= The following terms (based on the standard TCL/TK license) apply to all files contained in this package, except the icon images. The icon images can be freely distributed. If you require clarification of copyright/license details for the images, please contact the appropriate creator/maintainer. ICONS: LICENSE TERMS ==================== This software (ICONS) is Copyright 2002 by Adrian Davis (adrian@satisoft.com). The following terms apply to all files associated with the software except where noted above. The author hereby grants permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. ================================================ FILE: ext/tk/sample/tkextlib/ICONS/tkIcons ================================================ actattach16:act act16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBPz+/AQCBAAAACH5BAEAAAAALAAAAAAQABAAAAI2hAOCxg2h0nJHyEshi9HpxU1GOCLdZoKpQ15nibUoprKp9lh2oucUxsBRXsJh4Hjs/QTMpr8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actbookmark16:act act16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBCwqLLSytLy+vERGRFRWVDQ2NKSmpAQCBKyurMTGxISChJyanHR2dIyKjGxubHRydGRmZIyOjFxeXHx6fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVbICACwWieY1CibCCsrBkMb0zchSEcNYskCtqBBzshFkOGQFk0IRqOxqPBODRHCMhCQKteRc9FI/KQWGOIyFYgkDC+gPR4snCcfRGKOIKIgSMQE31+f4OEYCZ+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 actbookmarknew16:act act16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBCwqLLSytLy6vERGRFRWVDQyNKSipAQCBMTGxKyurISChJSSlJyanHR2dIyKjPz+xISGhPz+BGxubMTCBHx+fPz+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVfICACwWieY1CibCCsrBkMb0zchTEcNYsIiYHiwIOdEAvigdFQGE0Ix4NBbSAgsWjk+jBIAlcUYrJASChnSXZSoUDelKfoKpFALJA61ueGI2IAZmhogGFmCGGAgXsifiEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== actcheck16:act act16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBMT+xATCBASCBARCBAQCBEQCBAAAACH5BAEAAAAALAAAAAAQABAAAAM2CLrc/itAF8RkdVyVye4FpzUgJwijORCGUhDDOZbLG6Nd2xjwibIQ2y80sRGIl4IBuWk6Af4EACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actcross16:act act16 16:photo:16 16:R0lGODlhEAAQAIIAAASC/PwCBMQCBEQCBIQCBAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMuCLrc/hCGFyYLQjQsquLDQ2ScEEJjZkYfyQKlJa2j7AQnMM7NfucLze1FLD78CQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 actexit16:act act16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBDQyNHR2dCH5BAEAAAAALAAAAAAQABAAAAI4hI+pFrHb3nEg1iWiDiINCwYDko0V9XUTda6I1TIsUMpGinyzbB6ZeGuoEr+GUDL4CXqSphPhLwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== acthelp16:act act16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQ6XAQCBCyCvARSjAQ+ZGSm1ARCbEyWzESOxIy63ARalAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAQ/EEgQqhUz00GEJx2WFUY3BZw5HYh4cu6mSkEy06B72LHkiYFST0NRLIaa4I0oQyZhTKInSq2eAlaaMAuYEv0RACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actitemadd16:act act16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBARCZPz+/Mzq9BTC3ITC1HSyzGSivAw+XBSStIS6zHy2zAQCDFyatAQOHFSStEyOtAQSJBSq1DR2nCxunCRmlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVbICCOQTmeaCAMRIC+AVu47xkTBl2Ld16XQNYBQTQBVIOkMHFQJBeMI4tAbSSu2IRDSnhAvFfI97sFRM6RwOMacbjLKckVvgvIJ5EdSU7J648VgXQ7Dmd/hyJ+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 actitemdelete16:act act16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBARCZPz+/Mzq9BTC3AQCDAQOHFSStAQSJAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAQwEMhJq704681n+GAISoEwnGg6EAUQrEQsz4ThEkeu77kNIAagMEj0dY7IpHI58UcAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actlock16:act act16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaVAQCBKSipDQyNMTCxISChFxaLFxSJEQ+FExGHCQiDBwaDGxiLHxyNHRuPIR+TIyGZJSSfFxaRFxWJGRiLJyaXNzWpNTOnMzGnLy2hJSKTGReLKyqjPTu1NzarMS+jLSyfKyibJySXIyGVCQeDLSytPT29Ozu7OTi5NTS1KyurJSSjGxqVFxaXLS2tKSebOzuzLSufJSOXExGLGRiTExONAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaTQIBwGCgGhkhkQDBoEpLKQoBACAyOUID1qTVwoQGvMPxNFgVjAxp6QCQUicSCwVgkG44HJCKRRCYUCAxIFRYXhxgZGhYbHINEHR4fGCAhIiMkFSVKJicoKSoFKwMsLZtDLison6GjLA92qCueoAUvpC2xQhWqrLYDErmEMDEXlDIwMxAHukI0NS01EzY2NAmPAH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actredo16:act act16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBBxOHBxSHBRGHKzCtNzu3MTSzBQ2FLzSxIzCjCSKFCyeHDzCLAxGHAwuFDSCNBxKLES+NHSmfBQ6FBxWJAQaDAQWFAw+HDSyLJzOnISyjMTexAQOBAwmDAw+FMzizAQODDymNKzWrAQKDAwaDEy6TFTGTFSyXDyKTAQCBAwiFBQyHAwSFAwmHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ2QIBwSCwaj0hAICBICgcDQsEgaB4PiIRiW0AEiE3sdsFgcK2CBsCheEAcjgYjoigwJRM2pUK0XDAKGRobDRwKHUcegAsfExUdIEcVCgshImojfEUkCiUmJygHACkqHEQpqKkpogAgK5FOQywtprFDKRwptrZ+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 actreload16:act act16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBCRaJBxWJBxOHBRGBCxeLLTatCSKFCymJBQ6BAwmBNzu3AQCBAQOBCRSJKzWrGy+ZDy+NBxSHFSmTBxWHLTWtCyaHCSSFCx6PETKNBQ+FBwaHCRKJMTixLy6vExOTKyqrFxaXDQyNDw+PBQSFHx6fCwuLJyenDQ2NISChLSytJSSlFxeXAwODCQmJBweHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaBQIBQGBAMBALCcCksGA4IQkJBUDIDC6gVwGhshY5HlMn9DiCRL1MyYE8iiapaSKlALBdMRiPckDkdeXt9HgxkGhWDXB4fH4ZMGnxcICEiI45kQiQkDCUmJZskmUIiJyiPQgyoQwwpH35LqqgMKiEjq5obqh8rLCMtowAkLqovuH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actrun16:act act16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+/ISChKSipMTCxLS2tLy+vMzOzMTGxNTS1AAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARlEMgJQqDYyiDGrR8oWJxnCcQXDMU4GEYqFN4UEHB+FEhtv7EBIYEohkjBkwJBqggEMB+ncHhaBsDUZmbAXq67EecQ02x2CMWzkAs504gCO3qcDZjkl11FMJVIN0cqHSpuGYYSfhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== actstop16:act act16 16:photo:16 16:R0lGODlhEAAQAIUAAASC/Gw6NGQuLHQ6NGQmJFweHFQaFPTm5PTa3PTW1Oy+vOS6tNSinKReVDQWFPz+/Nx6fNyCfNyGhNR+dMxybMRiXLxGRIwWFNx2dNx+fNx2bMxuZLQWFBwWFPTu7Pzy9NRqZNRuZMRSVLwmJGwWFNR2dMQiHPTKxMxmXMQyLMxmZNx6dMxiXMRSRMRaVKxybMxaVEQWFMQuJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaaQIAQEBAMCAWDYcgkHhAJxYLRcDQBggckIplQKpaLdRh4YDIaSWa94Vw6woAHgv6AMKGPaMQhwQMJJRkfhHmEJhdvRCcgGSCEkCgpbnAECiorGYYfLCItlAAFCygQj5AfbYlwBQwVE5AukG6KBi8tMC0fLi0pHxyzcAAxFxwmMny/wEwOxMm/qlcdJCSJ1H5XQh3a28HY3kx+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 actundo16:act act16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBBxSHBxOHMTSzNzu3KzCtBRGHCSKFIzCjLzSxBQ2FAxGHDzCLCyeHBQ+FHSmfAwuFBxKLDSCNMzizISyjJzOnDSyLAw+FAQSDAQeDBxWJAwmDAQOBKzWrDymNAQaDAQODAwaDDyKTFSyXFTGTEy6TAQCBAQKDAwiFBQyHAwSFAwmHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ1QIBwSCwaj0hiQCBICpcDQsFgGAaIguhhi0gohIsrQEDYMhiNrRfgeAQC5fMCAolIDhD2hFI5WC4YRBkaBxsOE2l/RxsHHA4dHmkfRyAbIQ4iIyQlB5NFGCAACiakpSZEJyinTgAcKSesACorgU4mJ6uxR35BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actunlock16:act act16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaVAQCBKSipDQyNMTCxISChFxaLFxSJExGHEQ+FCQiDBwaDBweDGxiLHxyNHRuPIR+RIyGZJSSfFxaRGxmLJyaXNzWpNTOnMzGnMS+jJSKTGReLKyqjPTu1NzarLSufKyibJySXIyGVGxiNFxaXLSytPT29Ozu7OTi5NTS1KyurGxqVCQeDJSSjLS2tNTW1KSmpGRiLKSebOzuzJSOXExONExGLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaVQIBwOAwYA8SkMCAYOAnKYiFAIAQGyOgVCggYuEovVxztMpdnwAGRSCgUCwOjIeQ6HpCIZDKRUNYMRBUWF4UYGRoWGxyBRR0eHxgaICEiIyR0QyUmJygpKgUrAxMsLUQlKyieoKIuEAunK52fBS8DLiywQySpnjC1Mbi6QjIzNBeSIBY1EQfDQgosLAEUNjY3Co1DfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== appbook16:app app16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBAQCBDyKhDSChGSinFSWlEySjCx+fHSqrGSipESOjCR6dKTGxISytIy6vFSalBxydAQeHHyurAxubARmZCR+fBx2dDyKjPz+/MzKzLTS1IyOjAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVkICCOZGmKQXCWqTCoa0oUxnDAZIrsSaEMCxwgwGggHI3E47eA4AKRogQxcy0mFFhgEW3MCoOKBZsdUrhFxSUMyT7P3bAlhcnk4BoHvb4RBuABGHwpJn+BGX1CLAGJKzmKjpF+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 appbookopen16:app app16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBExCNGSenHRmVCwqJPTq1GxeTHRqXPz+/DwyJPTq3Ny+lOzexPzy5HRuVFSWlNzClPTexIR2ZOzevPz29AxqbPz6/IR+ZDyKjPTy5IyCZPz27ESOjJySfDSGhPTm1PTizJSKdDSChNzWxMS2nIR6ZKyijNzOrOzWtIx+bLSifNTGrMy6lIx+ZCRWRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaeQEAAQCwWBYJiYEAoGAFIw0E5QCScAIVikUgQqNargtFwdB9KSDhxiEjMiUlgHlB3E48IpdKdLCxzEAQJFxUTblwJGH9zGQgVGhUbbhxdG4wBHQQaCwaTb10emB8EBiAhInp8CSKYIw8kDRSfDiUmJ4xCIxMoKSoRJRMrJyy5uhMtLisTLCQkC8bHGBMj1daARgEjLyN03kPZc09FfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== appboxes16:app app16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBMT+xAT+BASCBATCBMT+/AT+/ASChATCxPz+xPz+BISCBMTCBAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARaEEgZwrwYBCFqvhs3DNYXjChRlWBRjIRqGN4UuEUczMZxsDeXykdEsDQVVSLhQxhBCkVlmXA+KVHFYhFYOoHbMGN6pTQaW8YYiQmcG+q16a0+Zipw+4e9B/gjACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= appbox16:app app16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+xISCBMTCBAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANECKoR6ys2IVqokF08yMTA1gwkYX5WQK5ma4VceTYPxXnBWdtY6+0834/Bowgzm6APWRQcH4TiMhPK2WYRiZWW7XK7/gQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== appbrowser16:app app16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxONCROfCRKfKx6LNy+bNTOpGSS1DRupAwyXBRSnPTSjPTqvOzqzMzSvHSSlKy6ZDxutAxCpBQ2XBxepLTKvPzqzPzy5OTShLS2dLSqRFR2jBRerBQ+jOTixOzetNS2XHx6XDR2tCRexBwyTDyKzOTavPzq1OzKdCx23BRKtCQ6VCQmHFSa7IyirOzSnGSGpIR+bFSO1DyK7DR+5CRixBw2VDQuHFye7IS27NzGXISuhEyS5DR25BRWxBQ+lBQyXCQqPCxSfGyu7GyerKy2ZFR+rERqfCRmxBROtBQ+fBwuTBwmNDSW9JyabLyqRIx+TExSXBQ6bAQCBBQ6ZBxapDR+zBxq3LyaLJySRHxqPGxeNBxGbCRmrHRyRERONDRKNDQ2JCQuLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAeygACCg4SFhgABAQIDh4MBBAUGBwgDCYcKCwwNDg8QERIThRQVFhcNGBkaGxwdoYMDHhcXHxggISIjEiSvJSYXJwsoISkpIyorLIIDLS4WLzAxMjM0NSo2N8o4OS46OzwzPSk+P0BBgkI8Q0NERUZHCEhJSktMgwk4Qy1NTk9QUVJLphCiUsWKlStYsmjZQiJgIS4KuijQ4iXAFxYCDVFJwGUFmDBhMjYSw0KMyEYoBfkJBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 appcalc16:app app16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBISChPz+/AQCBCH5BAEAAAAALAAAAAAQABAAAAI4hI9pwe0Ogpi00hHF2LzzzFlTsIHD45SSx6oCeW4wjK2tl83y7t64pIsJaxrfh2bEAJIlhRPhLwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== appclock16:app app16 16:photo:16 16:R0lGODlhEAAQAIIAALy+vAQCBPwCBMQCBIQCBISChPz+/MTCxCH5BAAAAAAALAAAAAAQABAAAANbCLHcrSLKOZcYmDSCsR1aUABAsXDDJwJGa5SBFwgaWxbCG3CWaBwG3C8Y67FawpYiNQscg65fsVkYuoAmJs1pBR522lQB6ILJLqHRwQQOZzYdZnw+dzruDIA/AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 appdate16:app app16 16:photo:16 16:R0lGODlhEAAQAIQAAASC/AQCBPzerPyqXMRaBIQCBISChPz+/KSipMTCxPz+BMTCBPwCBPz+xPzCxMQCBISCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVxICCOQGCeJjkGwkC8RFEEavkax2G8dB0QuRyhhzoBg8MSYsncJXKJZIDZHCoWP1ogGIwGrtnSgUFmHLyNRHhrdpjRamnO/SYkromHdnxwnwkKVxByZW8DgQsQM2JcfwZXO0MBCZSVBgMuLzJaRZ0pfiEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== apppencil16:app app16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/IQCBMQCBPzCxAQCBPz+/MTCxISChDQyNKSipEQCBAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARDEMhJZRBD1H2z3lMnjKCFjUJQimOgcmcbELCXzjXq0hV785WCQYcDFQjDXeloMByKG6YTAdwIDAlqSZJSVFeKLcUfAQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 appsheet16:app app16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBAT+/Pz+/KSipPz+BAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANFCBDc7iqIKUW98WkWpx1DAIphR41ouWya+YVpoBAaCKtMoRfsyue8WGC3YxBii5+RtiEWmASFdDVs6GRTKfCa7UK6AH8CACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= apptool16:app app16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBISChGRmZMTCxKSipLS2tHx6fPz+/OTm5FxaXOzu7DQyNMzOzAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAReEMhAq7wYBDECKVSGBcbRfcEYauSZXgFCrEEXgDCSeIEyzKSXZoBYVCoJVIqBGByKu0Cy8QHxmgNngWCkGgqsGWFseu6oMApoXHAWhWnKrv0UqeYDe0YO10/6fhJ+EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 apptools16:app app16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBExKTERCRAQCBOzu7Nze3MzKzLy+vCxqZBQ2NJyanKyqrGRiZDRydKza3FRWVPT29LSytDw6PMTm5EySjCxaXGRaJFSanCRSVGxqbPTmvMSqVJTW1GSurHS6vOzq7KSipISChFRKHJSGNPz23GxKFBQ6PKyurCwqLMyufJx2RAQGBJSWlEwyDIRiLNy+lLSKVDwmDJRuNOTOrLyabGRCFDx2dKSCVOzWtHzCxOTGnNSyhAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAahQIBwCAgIBAOiUiggFAyHASKxDAwUC8Zg0HAglA9IZPGQABoTSqJCFTIOEIsFgHBcEhhHUpKJFCwaGxYYHB0VEx4IEh8gIQwiIyQbJRMcHokmEicfDygAkCkqJQgIGG0rLElCLS4vMCWqQwMCQg0UMTIzNDVLQjaIGDE3ODQlS785CEkxKjowvEOHybG4O6JDCdNKuDUxRAmxRDHeveUAfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== appuser16:app app16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+/MTCxISChMT+/ATCxASChFxaXAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARaEMg5gw00yyDGIAR1YUDggeFWFIZhnSBZrsZxdIOFEGTA2oeBAHeyuGwvzxBlYdUOLROMFzDQntJPrNoqAKUBaqnV+k57ZORruykHDj2LqIzUVKp1u0iuB/gjACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= appusers16:app app16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBMTCxISChAT+BMRaBPyqXARCBPz+/FxaXAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARLEIRJa5Ui673nsGAgeKE1Bl9AUEXbiqTlFlZaGUZoszm4BzhDAVf5BYbAXI+TAR6CS2ZGSZSEiIIqYIsSIEaJ7GRrlY7J1lKA7I8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= appwp16:app app16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBKSinJyOfPz27Pzy7AwKDExOTJyWlERCRKSelPz69LyyrKymnPz+/MS2fDQyJAQCBOTazLSiXOzivMS2jKSSVOzmxPz25NzSpPTu5KyebOzixNTGjOTWpMSydMSybCwqFGReVKyaXNzSnGxeNJSCVMS2nPz23MSuZIR+bJyShLyqnOTOtGxiXIR6XOTSvIx6RMSubIyCdKSalMS6pOTWxMzKvKSabJyKTOzezHxuPGRmZKyurMTCvPTq3AAAACH5BAEAAAAALAAAAAAQABAAAAajQIBwCAgIiEhiYEA4FgwHRDKhIBAWz4OhgGQ0FAPHA7qFEBONb0Qy0ULeQ2+aUrFcMI+3GYBOZzQbHB0eHyAhIQByDREiEwMjFRIkJQImAgJ+jScjHigkKSorLC0AKg2NFSMoki4qCy+IQgITKDAxkjIzNDWkQxQoJaskMgk2Eb1DNzgoOCoHDDY5yEIwJToAOzw9ET7TQiREAhkZ3kmy5QB+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 cal1day16:cal cal16 16:photo:16 16:R0lGODlhEAAQAIIAAAQCBPwCBAQC/AQCjPz+/MTCxKSipAAAACH5BAEAAAEALAAAAAAQABAAAANOCLrMEUDIOUS9AFLLhx8LIRZjKYZmMRCkaChFLHty/AIiS3y6q+QtT49wq8VotRtQJGwRf6Zmrlj7DJLQXsupTJmeEIN4TB5nII20wp8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= cal5days16:cal cal16 16:photo:16 16:R0lGODlhEAAQAIIAAAQCBPwCBAQC/AQCjPz+/MTCxKSipAAAACH5BAEAAAEALAAAAAAQABAAAANMCLrMEUDIOUS9AFLLhx8LIRZjKYbj55GioRRwoQ5x4QIiIdMmcec7jy53q81qP9OO5VMAj8RXTFWzOZW95HDLdEEM4LA4nIE0zgp/AgAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 cal7days16:cal cal16 16:photo:16 16:R0lGODlhEAAQAIIAAAQCBPwCBAQC/AQCjPz+/MTCxKSipAAAACH5BAEAAAEALAAAAAAQABAAAANPCLrMEUDIOUS9AFLLhx8LIRZjKYbj55GioRRwoQ5x4QIiwcp0fucsj873qvGMv5Jw2FIACUsW4WakGW1O046I05qmGYBhTC6TM5CGWuFPAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 calappointment16:cal cal16 16:photo:16 16:R0lGODlhEAAQAIMAAAQCBPwCBAQC/AQCjPz+/MTCxPz+BISCBISChKSipAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAARbEMhJaQhA6D1E/wDGeeRgDhOhFoTBEi+REgdrIHScSEVvAD9Xr7cDqGSGpFEnQSqTv2NxCFQOiU1VEAiTZmstHFg1vQKuw+LxxfYaV/AuOQRI2O/4ewhT6Uv8EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 calbell16:cal cal16 16:photo:16 16:R0lGODlhDwAOAIIAAPwCBISCBPz+BIQCBMTCxISChPz+/AQCBCH5BAEAAAAALAAAAAAPAA4AAAM+CLrR+zCIAWsgLVRGRBhOVQiG94WPVAbHaZHYAWqRYLbge88RsbInGuBCEhRYrZYm4xk4nYdoKzKIbiKHawIAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== callist16:cal cal16 16:photo:16 16:R0lGODlhEAAQAIMAAAQCBPwCBAQC/AQCjPz+/KSipPzerMRaBEQCBAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAARDEMhJaQhA6D1E/wDGeeRgDhOhruyatjBRSIRxxOsMEAdC0BUZDcfSEYvDo3Bn++2Cxt7RqFxWhZiCdsvdhjCVsMQfAQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 calmonth16:cal cal16 16:photo:16 16:R0lGODlhEAAQAIIAAAQCBPwCBAQC/AQCjPz+/MTCxKSipAAAACH5BAEAAAEALAAAAAAQABAAAANSCLrMEUDIOUS9AFLLhx8LIRZjKYbiRxLFIBpK0Q6z7MkwkJIe8b0KEeuWchFysuStVsjtfMbeMQitWpG25YfmNK1WU53XNIUYzug0OgNpuBX+BAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 caltoday16:cal cal16 16:photo:16 16:R0lGODlhEAAQAIMAAAQCBPwCBAQC/AQCjPz+/MTCxKSipPyCBMRaBPyqXAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAARTEMhJaQhA6D1E/wDGeeRgDhOhFmurpi5LyIQhFfiBIAfuFzaAioBIJBCummRYPCaDPh3vhwsOZdihNfa8Ub/AJXemFZPPNBvGwG672yFMZS7xRwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== caltodo16:cal cal16 16:photo:16 16:R0lGODlhEAAQAIMAAAQCBAT+BAQC/AQCjPz+/MTCxPzCxKSipPwCBMQCBIQCBAAAAAAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAARaEMhJaQhA6D1E/wDGeeRgDhOhFmurpi5LyMYhFXiuFwZiA6qZYbbqJX5BIw2RAPxwAAWCyWMCCsiXFGEEErKz6LQZfOqiTR1YJiGq1rFyyHmo2+/1EKbCl/gjACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= connecting16:connect connect16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBPz+BMTCBISCBAQCBPz+/MTCxMTGxISChFxaXMzGzKSipAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARaEMhJZbihUiz60FPnfaA0iBpBVGdHEYWxToEoSHBRHHM9AgSEQRcj+AYkYAJxIPKQFUJiOdTJQFIDU6dYzKKFhTCM+E5g4mXaDAyrlogEG+DGTecA7wsP8EcAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= connectno16:connect connect16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBPz+BMTCBAQCBERCBPz+/MTCxMTGxISChFxaXMzGzKSipAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARPEMhJq704axBEHoPUEdhQGMNYFuwxkKInDYjBniEnwMCQIIebSzXx/WwsFK+YMABZikWuYlrUCtZpEYv4WRPaHhb064YB41kCfJFSQBh/BAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 connectyes16:connect connect16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+/KSipDQyNMTCxMTGxISChFxaXMzGzAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARaEMhJZxCjgsAtDtUlCOA1gJQ4kl/IDatAoF7xxkS6GgEBr6jAobCyBX42SQBxMOx6A8MhiGASR8YDgrYsNEeJ0zaEGZY7uoH2oB6nOUwtbdLaVOeTUwo/8UcAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= devcdmount16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXISChNTS1MzKzMTGxMy+vNSytAQCBOzq7OTi5Nza3Oy6vPy2tOTStPz6/Ozu7Nze3MTKxOS2tOzOvNTqvLT2tDw+BPTy9MzOzLS2tPy+tLz+tLz2tLSynLzqvLzavLTOtNTW1KSipPz+/LzKvMTCxDQyNASCBARCBDTSJIT+bAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAa0QIBQGBAYA8Ok0DggFAwHBEIJECQUi8GT0XBMh9YHJDKQTBqUiuUCVmAeiYzmsKlwOt/AAKFIFAIIFx4WHyAhUwIDIgsZFyMkFxchJSYmiBkSBBoIJJwIGgOhiCYFJSEnFyQjFwNZewABISAfFiYnCAEmCREIrwAIFhwVGwcaBAkPGApsQsAVFA0GBQMRbxBTKM0ODQwTEq192ClDgROkBHvYKuNJUu5CKCorX1RDKCkpUn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= devcdunmount16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXISChNTS1MzKzMTGxMy+vNSytAQCBOzq7OTi5Nza3Oy6vPy2tOTStPz6/Ozu7Nze3MTKxOS2tNzmvLT2tDw+BPTy9MzOzLS2tPy+tLz+tLz2tLSynLzqvLzavLTOtNTW1KSipPz+/MTCxLy6vDQyNOTm5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAapQIBQGBAYA8Ok0DggFAwHBEIJECQUi8GT0XBMh9YHJDKQTLqUigWsuDwSmMxBQ9lwvoEBQpEoBBAWHRseHyBTAgMhCxgWIiMWFiASJCSHEgQSGQgjmwglGKCHBQUSICYWIyIWAwshIVMBIB8eFSQmCAEFCREIekIIFRsUGgcZEgkPFydrvxUUDg0GBSEREGJfv9AMEySsJxDYQ4DcEhh64UpS6lTs7QB+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 devdiskmount16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBDQyNIRuVKyCXMSKROzSrOzKpOTGnLSafLySZKxuLMSOVPTWvPzixLSehNyibOzOrGxaVJx+XOzGnFw2FJRuPKx+TPTSrHRWPKyKZPTOpHxOJKyKXFw+HKSipISChMTCxFxaXIRiPNSWXExOTOS2hLR+PLRyLPTWtMyOTASCBARCBPz+/DTSJIyKjIT+bAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaTQIBwCAgYA8SkMCAYDARI5ZJQMBwQiWgyoFgwrA3HQ7scQAqFAcEQOUi0zAkFUSFYLghMBloUCDQNGxwdHhwHekcfICEhICIfIxkLJBABJUYCICABIhAOBiYnKJaXmH4CGSkYCCqkSAEfTKenrkOwsrQll0IrS7G5uwArLLaxLbXCLsTFLyDBKy4wZEVHvCwsRn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= devdiskunmount16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBDQyNIRuVKyCXMSKRPTWtOzKpOTGnLSafLySZKxuLMSOVOzOrPzm1LSehNyibGxaVJx+XOzGnFw2FJRuPKx+TPTSrHRWPKyKZPTWvHxOJKyKXFw+HPTOpKSipISChMTCxFxaXIRiPHxaNLRyLNSWXExOTPzixOS2hLR+PMyOTPz+/IyKjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaIQIBwCAgYA8SkMCAYDARI5ZJQMBwQiWgyoFgwGgiD46FdDiCFwoDQAEe0TMkEQSFULIcLBloUCDIaDRscHRsNHhhHHyAhISAiHyMkJSYQASdGAiAgASIQKA0pKguXmJl+AiQGFwgrpUgBH0yoqK9DsbO1J5hbsrq8SrgstlJFHy0gwMVFR1J+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 devfloppymount16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBAQCBMTCxARmZPz+/FSWlLSytKSipERCRIyOjISChOTm5HRydNza3GRiZFRSVASCBARCBDTSJIT+bAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVrICCOQBCQKBkIw5mqLFG47zoQ+FwbN57TosDhgPD5dMEEIqE04kwlBWKBUEiNVYFpyqAyGEUCgqEtERiNNMLhQKzLQYJg7n7Y4aMAwbCUPvAQeWNgfzQQETAIhSMQEogwgBITQEGGEREmfiEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== devfloppyunmount16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBMTCxARmZPz+/FSWlLSytKSipERCRIyOjISChOTm5HRydNza3GRiZFRSVCH5BAEAAAAALAAAAAAQABAAAARcEMgJQqCYBjFu1hxReN82EOhYGieaklJwHIjrqnGCJLqNWhUFYoFQCG1FgWXIIDIYNQKCoawQGI0swuFAbKsxgmDsfZjBkwDBsNM90Jot9A3DbBD0Dwiur9QnfhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== devnetwork16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBAQCBISChPz+/Nza3ARaZESanCyKlARudARGTLy+vNzq7ARmbMTCxARufAROVMzOzKSipARyfOzq7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVmICAGZFmKQiACweCSBImq41AYB5IodLq2hwWO0ejRWDac48Gb/QKNqNRoqspmrVcAUuIJBANS8sBIFCORUgooPEh4J8B67NgdsVBp9C5XWfl9LRMTCyReX19hARNojWlWLH+AAH4hACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= devpc16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBISChHx+fPz+/AQCBAQC/AT+/AQCxAQChAT+BLy+vAR+BAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARYEIAgqK1YzsG754QUDERpmkEpkkXrtoK6EcVgHIibhnNx564Yb0TDvQq7FQ34EiqPOhnREqhWSUPsyZSQAbbg7GcMEgwUiYVivTa1R+y4XEGoWO/4AMAfAQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 devscanner16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+/MT+/ASChARCRATCxMTCxFxaXKSipDQyNAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARTEMgJgqWBVivEldkUdKSXhVjZfenommglDERh3Tc4E4ZRHAGgkEPr9X6H5AHBERSMRyWzkug8jQXFEhWoOo8dRYxqLXSmGjIJnVaz29Q3fAP3RwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== devscreen16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXFRSVPz+/PT29OTm5OTi5DQyNDw+PERGRExKTHx+fISChIyKjHRydFxeXDQ2NCQmJBQSFAQCBERCRMTGxHR2dGRiZExOTDw6PCQiJAwODCwuLFRWVOzu7BweHAwKDCwqLHx6fBQWFGxqbGRmZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAanQIBwSCwKAwKkMslEAgSDqDRKqBYKhkNgcDggEorkMrDQchkNhuOhgEQkk0l5S2lUGpYLJqPZTAwMHB0DCmhqAW0Rfh5zAxgOkBcCFAcfIBMECxwBBAEPFw8dChkhcBMDDAcdnQqtFKSWcQMimx4dGRkQBxGxsg6bBQEawx8jl3GnJFoFHRNXVVNRJYIFDAsL1tgiDiQXFx0HABwcXeQH5OjkRutEfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== devspeaker16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBFxaXAT+/DQyNATCxMTCxPz+/AQCBKSipASChAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARWEMgJQqCXziDG2JoUEENhZBkmHIWJVptAmqcIW/Js1MiF56TBzkckAAcHoa9nMRKeA4TyJk0knsHhTeK5khBaH2VwLYVh40TJhQ6RzeIQV32Quz8hfwQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== editcopy16:edit edit16 16:photo:16 16:R0lGODlhEAAQAIUAAFxaXPwCBNze3GxubERCRPz+/Pz29Pzy5OTe3LS2tAQCBPTq3PTizLyulKyqrOzexLymhLy+vPTy9OzWvLyifMTCxHRydOzSrLyihPz6/OTKpLyabOzu7OTm5MS2nMSqjKSipDQyNJyenLSytOTi5NTS1JyanNTW1JSWlLy6vKyurAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAAaUQIBwCAgYj0eAYLkcEJBIZWFaGBie0ICUOnBiowKq4YBIKIbJcGG8YDQUDoHTKGU/HhBFpHrVIiQHbQ8TFAoVBRZeSoEIgxcYhhkSAmZKghcXGht6EhwdDmcRHh4NHxgbmwkcCwIgZwqwsbAhCR0CCiIKWQAOCQkjJAolJrpQShK2wicoxVEJKSMqDiAizLuysiF+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 editcut16:edit edit16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBPz+/ISChCH5BAEAAAAALAAAAAAQABAAAAIwhI9pwaHrGFRBNDdPlYB3bWHQ1YXPtYln+iCpmqCDp6El7Ylsp6ssR1uYSKuW0V8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= editdelete16:edit edit16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbPT29GxubMzOzDQyNIyKjHRydERCROTi3IyKhPz29Ox6bPzCxPzy7PTm3NS6rIQCBMxCNPTq3PTi1PTezMyynPTm1PTaxOzWvMyulOzGrMymhPTq5OzOtNTKxNTOzNTCtNS+rMSehAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaKQAAgQCwahcihYMkcBAiBpLJApRoOBWgyIKhSEQkFgrBAcr1URiPhKAsDD3QB8RhA3FM0IlLHnyUTVBMSFBUWfl0XGBMTGBcZGodmcQWKjpAbHIgIBY2LHRoempOdjooTGx8giIOPFYofISJ+DyMXI6AfFySyfiUmJSUnKBYcICIpfgELzM3OZX5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= edit16:edit edit16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxaVMR+RPzKjNze3AQCBMR6RPzGjPyODPz+/MzOzPyKDPyKBPz29OTWzPyGDPyGBOx6BOza1OR2BKROBNSOXKRKBBwOBOzu7PTWxPzizOySZPyCDFxaXOy2lNRyRMxmJCQOBPTm1OzStPTKrMR+XIRWLFxGNCQSBDQyNIRSNDQuJERGRLyqlNzSvIx6ZKRuVEw6LLSyrLymhKSShBwaFFROTJyWjMS+vNzW1OTazNzKrHRqXOzezOTOpPTq3OzWvOTStLyedMS+rLy2pMSynMSulAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAewgAAAAYSFhoQCA4IBBI2OjgUGBwiLBAmXlpcKkgsMlZcJBA0JDpIPEBGVjwkSBgOnExSfmBIVBxAMExYXswkYGRobHLq8gh2PHhoeHyAWIYKzIiMkJSYnKCnQg5YNHtQqKywtK9qMBC4vMDEBMjIz2dCMDTQ1Njc4OToz5PEEOzw3ZPToMcLHO23HfogQ0QMIkCA+hPBbhAPHECJFjMyYIUQIvEUpUqwQOXKkSEF+AgEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== editpaste16:edit edit16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBCQiFHRqNIx+LFxSBDw6PKSaRPz+/NTOjKyiZDw+POTe3AQCBIR2HPT23Ly2dIR2FMTCxLS2tCQmJKSipExGLHx+fHR2dJyenJyanJSSlERCRGRmZNTW1ERGRNze3GxubBweHMzOzJSWlIyOjHRydPz29MzKzIyKjPTq3Ly2rLy+vISGhPzy5LymhISChPTizOzWvKyurPTexOzSrDQyNHx6fCwuLGxqbOzKpMSabAQGBMS2nLyulMSidAAAACH5BAEAAAAALAAAAAAQABAAAAa7QIBQGBAMCMMkoMAsGA6IBKFZECoWDEbDgXgYIIRIRDJZMigUMKHCrlgul7KCgcloNJu8fsMpFzoZgRoeHx0fHwsgGyEACiIjIxokhAeVByUmG0snkpIbC5YHF4obBREkJCgon5YmKQsqDAUrqiwsrAcmLSkpLrISLC/CrCYOKTAxvgUywhYvGx+6xzM0vjUSNhdvn7zIMdUMNxw4IByKH8fINDk6DABZWTsbYzw9Li4+7UoAHvD+4X6CAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 editshred16:edit edit16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbGxubMzOzPz69DQyNIyKjERCRPz29PT29OTi3IyKhPz27PTu5PTy5Pz6/Pzy7PTq3OzexLyqlPTm1PTizOzavLyqjOzWvOzaxLyifOzizOTOpAQCBOzezAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaEQAAgQCwahcihYMkcBAiBpLJApRoOBWgyIKhWEQkFYYHkeqkMxKFBFpq9jgdkEGlPqwrJhCIY2N8FFRYUFxcYGX9dgRKEGhiHiYEOhBcbGBwdiQEOARcBGwEeAZllAgEUnQEfoQEgmp4hrCKtrwEYsrRlTiMBJAG8syN/IyMAxMXHSH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= edittrash16:edit edit16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBKSipFxaXPz+/MTCxISChDQyNCH5BAEAAAAALAAAAAAQABAAAANQCKrRsZA5EYZ7K5BdugkdlQVCsRHdoGLMRwqw8UWvIKvGwTICQdmGgY7W+92GEJKPdNwBlMYgMlNkSp3QgOxKXAKFWE0UHHlObI3yyFH2JwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== fileclose16:file file16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBCQiJBwaHAQCBDQyNDw6PFxaXFRSVERGRCwqLAwODGRiZHx6fPz+/GxqbAwKDCQmJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVaICCOZGmeqBgEwjCkRGEcSKK4JrEcBrMgAdeLVDg0GguGsYEbBQyGYyN6FDoPDIf0+LCKBIgetQERDgGDBGIpNY8GioAU0m6KXFw883w3+/l9f4AkfimGIn4hACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= filedocument16:file file16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJSWjPz+/Ozq7GxqbJyanPT29HRydMzOzDQyNIyKjERCROTi3Pz69PTy7Pzy7PTu5Ozm3LyqlJyWlJSSjJSOhOzi1LyulPz27PTq3PTm1OzezLyqjIyKhJSKfOzaxPz29OzizLyidIyGdIyCdOTOpLymhOzavOTStMTCtMS+rMS6pMSynMSulLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaQQIAQECgajcNkQMBkDgKEQFK4LFgLhkMBIVUKroWEYlEgMLxbBKLQUBwc52HgAQ4LBo049atWQyIPA3pEdFcQEhMUFYNVagQWFxgZGoxfYRsTHB0eH5UJCJAYICEinUoPIxIcHCQkIiIllQYEGCEhJicoKYwPmiQeKisrKLFKLCwtLi8wHyUlMYwM0tPUDH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= filefind16:file file16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBCQmJDw+PBQSFAQCBMza3NTm5MTW1HyChOT29Ozq7MTq7Kze5Kzm7Oz6/NTy9Iza5GzGzKzS1Nzy9Nz29Kzq9HTGzHTK1Lza3AwKDLzu9JTi7HTW5GTCzITO1Mzq7Hza5FTK1ESyvHzKzKzW3DQyNDyqtDw6PIzW5HzGzAT+/Dw+RKyurNTOzMTGxMS+tJSGdATCxHRydLSqpLymnLSijBweHERCRNze3Pz69PTy9Oze1OTSxOTGrMSqlLy+vPTu5OzSvMymjNTGvNS+tMy2pMyunMSefAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAe4gACCAAECA4OIiAIEBQYHBAKJgwIICQoLDA0IkZIECQ4PCxARCwSSAxITFA8VEBYXGBmJAQYLGhUbHB0eH7KIGRIMEBAgISIjJKaIJQQLFxERIialkieUGigpKRoIBCqJKyyLBwvJAioEyoICLS4v6QQwMQQyLuqLli8zNDU2BCf1lN3AkUPHDh49fAQAAEnGD1MCCALZEaSHkIUMBQS8wWMIkSJGhBzBmFEGgRsBUqpMiSgdAD+BAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 filenew16:file file16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbPz6/GxubNTKxDQyNIyKhHRydERCROTi3PT29Pz29Pzy7PTq3My2pPzu5PTi1NS+rPTq5PTezMyynPTm1Pz69OzWvMyqjPTu5PTm3OzOtOzGrMSehNTCtNS+tAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ/QAAgQCwWhUhhQMBkDgKEQFIpKFgLhgMiOl1eC4iEYrtIer+MxsFRRgYe3wLkMWC0qXE5/T6sfiMSExR8Z1YRFRMWF4RwYIcYFhkahH6AGBuRk2YCCBwSFZgdHR6UgB8gkR0hpJsSGCAZoiEiI4QKtyQlFBQeHrVmC8HCw21+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 fileopen16:file file16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBOSmZPzSnPzChPzGhPyuZEwyHExOTFROTFxaVFRSTMSGTPT29Ozu7Nze3NTS1MzKzMTGxLy6vLS2tLSytDQyNOTm5OTi5Ly+vKyqrKSmpIyOjLR+RNTW1MzOzJyenGxqZBweHKSinJSWlExKTMTCxKyurGxubBQSFAwKDJyanERCRERGRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaRQIBwGCgGhkhkEWA8HpNPojFJFU6ryitTiw0IBgRBkxsYFAiGtDodDZwPCERCEV8sEk0CI9FoOB4BEBESExQVFgEEBw8PFxcYEBIZGhscCEwdCxAPGA8eHxkUGyAhIkwHEREQqxEZExUjJCVWCBAZJhEmGRUnoygpQioZGxsnxsQrHByzQiJxz3EsLSwWpkJ+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 fileprint16:file file16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFRKNAQCBPz+/MTCxExKLPTq5Pz29Pz6/OzezPT29PTu7PTy7NzClOzm1PTu5LSabJyanPTm3FxaXOzCjOTKrOzi1OzaxOTSvJyenGRmZLyyTKSipDQyNERCROTi5Hx+fMzKzJSSlIyOjISChLS2tAT+BDw6PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaYQIBwKAwIBMTkMDAYEApIpVBgOCAOg4RRGlAoEAuGIdGITgWOq4LxcCQgZkEkIHksHgYJOR6ZQCgVFhYJFxgTBVMZihoCfxUYDWUbUBGKGREcjBoQEB2TAB4CAx+Vl5WMhyACHiEhH6IfIiMktCQgE0cZJQStr6O2t6EARxO6vK6iEx4dZsMCxbsmBB4nzUTEutVSSUdmfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== filesave16:file file16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBFRSVMTCxKyurPz+/JSWlFRWVJyenKSipJSSlOzu7ISChISGhIyOjHR2dJyanIyKjHx6fMzOzGRiZAQGBFxeXGRmZHRydGxqbAwODOTm5ExOTERGRExKTHx+fGxubNza3Dw+PDQ2NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaAQIAQECgOj0jBgFAoBpBHpaFAbRqRh0F1a30ClAhuNZHwZhViqgFhJizSjIZXQCAoHOKHYw5xRBiAElQTFAoVQgINFBYXGBkZFxYHGRqIDBQbmRwdHgKeH2YgHpmkIR0HAhFeTqSZIhwCFIdIrBsjAgcPXlBERZ4Gu7xCRZVDfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== folder16:folder folder16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBwWHMzKzOzq7ERCRExGTCwqLARqnAQ+ZHR2dKyqrNTOzHx2fCQiJMTi9NTu9HzC3AxmnAQ+XPTm7Dy67DymzITC3IzG5AxypHRydKymrMzOzOzu7BweHByy9AyGtFyy1IzG3NTu/ARupFRSVByazBR6rAyGvFyuzJTK3MTm9BR+tAxWhHS61MTi7Pz+/IymvCxulBRelAx2rHS63Pz6/PTy9PTu9Nza3ISitBRupFSixNTS1CxqnDQyNMzGzOTi5MTCxMTGxGxubGxqbLy2vLSutGRiZLy6vLSytKyurDQuNFxaXKSipDw6PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfDgACCAAECg4eIAAMEBQYHCImDBgkKCwwNBQIBBw4Bhw8QERITFJYEFQUFnoIPFhcYoRkaFBscHR4Ggh8gIRciEiMQJBkltCa6JyUoKSkXKhIrLCQYuQAPLS4TEyUhKb0qLzDVAjEFMjMuNBMoNcw21QY3ODkFOjs82RM1PfDzFRU3fOggcM7Fj2pAgggRokOHDx9DhhAZUqQaISBGhjwMEvEIkiIHEgUAkgSJkiNLmFSMJChAEydPGBSBwvJQgAc0/QQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= folderhtml16:folder folder16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBERGRBQWFMzKzOzq7CwqLDw6NARqnAQ+XHR2dKyqrOTm5ExKTERCRHRydMTi7NTu9HS+1KSmpBweHDy67DyixHS61ITG3AxypByu7DxinBw+ZERmdIySjITC3ARypExOTDRurIR2RPTSdJyulEyGvBw+bFSyzJTK3LzKvPzivOTixNTChLSybGyCfCRSnBQqRASGtFyuzDw+PCRShPzy5OzerOTShKyaTEx6pCxerGRufBR+rOTezPTShNy6bER+1BxCfBQuRAxelFSixBw2VISq3GySrPTWlHyanIyitFSO3IymtCRujAxWhCRqlCQ6XGyWvNS2bFyGvDxuvCRSpLy+vMS+vGxqbFyO1GSi3EyO1FRaVCQuPLS2tDxyzKyWNFxaNCQyPGxubCxajERSVExKNJyenAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfZgACCAAECg4eIAAMEBQICBomDBwgJCgsEDA0BDg8BhwYQERKUDxOYDAyeghQVFhehGBmVlwwOqxobHB0eH6EfIAkPIYIiIyQlJhsnKBcpvrYiKissLS4vMDEyFjOvNAA1LDY3ODk6Oyc8PTIyFzQ1Jj42P0A6QTtCQ0REIEUORkdIkihZwsSekBhNnDyBciCKiSNSplDRUcWKkRhXCGDJYgiGli1cpuTocsILjytfFmRpACAGRTBhRogZgzHlAjKGWnIoY+bMgRgBDHRBo/LAIZoxuhwKatRPIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 folderlocked16:folder folder16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBQSFMzKzOTm5CwuLERCRARqnAQ+XHR2dKSmpOzm5GxqbCQiJMTi7NTu9HS+1HRydOTm1Ozq7Dy67DyixHS61ITC3AxypERGRBweHByu7ASGtFyy1DSOtDRmfExOTBSazBR+rCwqLAxWhAxelByGtDSaxAwODHy+1Dw+PPT29IyqvCxujOzu7NTW1Nza3ExGJJyebKyqfMTCpFRSPOTi5DQqHOTezDw2NMTGxKyqhMTGrGxmXDQ2NMTCxMTGpHx6bHx2bBQWFIyOXDQuDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfDgACCAAECg4eIAAMEBQICBomDBwgJCgsEDAKFDQGHDg8QEZQSlxMUDJ2CDhUWF6AYGZWXFBqCGxwdFh4XGK8fIAohtiIIIx25EZwBDREHgiQjJSYmGScoKSoRKQ8rggIsDC0uJS4oGygoAyjdAAcsLxQUMDEyMzQ1EzapBy8MDDc36tFwgONFjlQ6dgCEEZBHDx8+ctRIRehHAyAwZASZIGRIEBoUBwUwIGMCiwFEaBQJichIjo9FZLBsacRIAB0A/AQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= foldernew16:folder folder16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBPz+hPz+BOSmZPzSnPzChFxaXMTCBPyuZPz+xPzGhEwyHExOTPz+/MSGTFROTPT29OTm5KyurDQyNNza3Ozq5Nze3LR+RLy+vJyenMzKzNTS1Ly6vJSWlFRSTMzOzMTGxLS2tKSmpGxubBQSFAwKDKSinJyanIyOjCQiJERCRERGRBweHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaNQIBwSCwaj8ikcokMCIqBaEDoBAQG1meAUDAQpIcBQoy1dg2JdBqhECgQ1IWB0WgcBIOBwIHXBwwPEBEREhIBbG4IExR/DBUVFhIXV2NjDVYYDY8SFU4ZVxpVAQwbGxynGxkdTh6XVh8gGSGzGSITIxokJUImGSMTwLcnKCkprgAqDSt1zCssKxQtQ35BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= folderopen16:folder folder16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBQWFOzi1Ozq7ERCRCwqLPz+/PT29Ozu7OTm5FRSVHRydIR+fISCfMTCvAQ6XARqnJSKfIx6XPz6/MzKxJTa9Mzq9JzO5PTy7OzizJSOhIyCdOTi5Dy65FTC7HS2zMzm7OTSvNTCnIRyVNza3Dw+PASq5BSGrFyqzMyyjMzOzAR+zBRejBxqnBx+rHRmTPTy9IyqvDRylFxaXNze3DRujAQ2VLSyrDQ2NNTW1NTS1AQ6VJyenGxqbMTGxLy6vGRiZKyurKyqrKSmpDw6PDw6NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfCgACCAAECg4eIAAMEBQYCB4mHAQgJCgsLDAEGDQGIkw4PBQkJBYwQnRESEREIoRMUE6IVChYGERcYGaoRGhsbHBQdHgu2HyAhGSK6qxsjJCUmJwARKCkpKsjKqislLNIRLS4vLykw2MkRMRAGhDIJMzTiLzDXETUQ0gAGCgU2HjM35N3AkYMdAB0EbCjcwcPCDBguevjIR0jHDwgWLACBECRIBB8GJekQMiRIjhxEIlBMFOBADR9FIhiJ5OnAEQB+AgEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mailforward16:mail mail16 16:photo:16 16:R0lGODlhEAAQAIYAAIx+fIRydHxubHxmZGxiXHRmZFxOTFxGPFxKTPwCBLymlMy+pOze3PTq3PTu5Pzy7LSmnOTaxOzm5LyqlNzOtPz69Pz27MzCtLyqrPT27IRubPzuzNTGvNTCxLSelPz25Bw+ZFxKPPzy1Pz65LyupBxKdCxWfPTm1Pz23LyinBxGbGzO5DRafBxWfBxajCymxHTS5BxSdBxKbFTK3EzG1CSGvCyKvCSSxCSavGTO5GRaVPzqzFzK5EzG3BSCtAwiPGxaVPTivPzy3NzKpBxObCRefBxqlPTmzJR2bKyahAwyRPzmvOTOpKyObNS+nPz21AQOFKyOfPzuxAQCBGRORLSadPzyzLymjMy2lOzetDwuJFRCPEw6NEQ6LEQyLEQ6NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAkALAAAAAAQABAAAAfhgAABAgIDBAQFBgcIBwmOCQIKCwwNDg8OEBESjY8CDBMUFRYVFxgZDJyOGhsPChwVHR4fFSAhjwkaIiMOJBQQDRUVJSa3GicoHw4pEA8SGSorLI8tLtQu19gqLzDECTEyMzQ14zY1Njc3ODkqCTo7MjIxNCs5PD03PjctPwlAQUIihhBpQbCIihtG+CUocASFkAhIkogQ8kFJwkcFlogIkoRJEydPnkBR6GiAxiQLgiiIIkXElFQJqESoMsRKkAhXqkhhApNKFSxZggTJ4nHIEJhaDhzYwoVLFy1avHyB6ScQACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= mailget16:mail mail16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAxKdBRSfCyGvFSm1BxKfCSWzCyWzBRCXCRKfBwuRAQGDDw6PHy23Cym1CSSxByCxBxunBQSFKyurMTCxExihNza3NTW1JSSlMzKzFxaXLS2tNze3KSipCQmJGxmbNTS1KSepLy2vISGhJSWlHx+fERGRPz6/IyKjDw+POzq7JyenMzOzKSmpCwuLDQyNIyOjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaeQIBwGBAIAsOkUjAgFJRQQMHgjC4PBIEVgAh4D4aEYrGAMhINxwPyiCgYSsmEUmk82grLRZJkYCgXaAEKFxYZcEISGhsZFxwFeY0WHR5CDB8dGCAXG5shGxQicBIMpSMUGxgTGSQlpQwSJicnEwwdI7gdKAwTsykpKiobr8QMKxeHDBcsGRvOzxsT0i0uL9HSHdkT2ZkoMJXF4a8AfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mail16:mail mail16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBGxaVOTe1Oze3OTWxOTWvNzStNzKpEQ6LOTezPz+/Pzy7Pz69Pz27Pz25Pz21PzuzPzuxEQyLLyinLSmnPz67Pz23LSafKyObDwuJMzCtLSelPzy1My6nLymjNTCxLyqnPzq1LyihKyOfOzavOzetEQ6NPTq3NzOtLymnNTGxJR2bOTOpPTivNTGvLymlKSShKyahEw+NOTe3PTm1Pzu1Pzy3FRCPPz65LSadFxGPOzm3PzqzPTmzPzmvEw6NCH5BAEAAAAALAAAAAAQABAAAAaqQIBwSCwaj8ikMhloOp/QpmAgqAoIhELBUDgcEIGEYrFgNBoLx+IBiRwkgQnFoWAwKhWLhX3BZAILGhsCDXgODhwdGB5vgAofICBlDiEiIx4kJSYBJ2UoEykqHSMrLC0nLWAnFS4UCycvMAcEMR0RLTIBMwaSahw0NTYtFwclNwEdLws4eoc2DxwQOR06ASk7PBAhIRE9Pj0tLSUY1T8I5gjn6Qgy7D8SfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mailreplyall16:mail mail16 16:photo:16 16:R0lGODlhEAAQAIYAAIx+fIRubHxubHxqbHxmZGxeXHRmZGROTFRCPFxKTFxGPPwCBLymlMy6pOTa1PTq3PTu5Pz27Dw+POzi3PTm1OTWvPz25FRSVERCRLympPzuzPTu7NTGvFxaXKSmpPzu1Pz65Hx6fHxqZPzq1Pz23HR2dBw+ZHx+fISChJSWlDQmJHRydCxWfBxGbJyenExKTHRiXPzqzPzy3CQmJDRafGTO5ExOTERKTGxWVCRSfHTS5CymxBxajBxWfPTmvPzy1CyixCSaxCySxDSaxDSWxDSSvDyaxGS21PTmzPz21AwiPBRejCSavByGtCSezEzG3FzK5FzG3GzO5FTK3CQ2bPTixBxqlCRefBxSdBxSfBx2nCQ+dHxmXPzmvLSafAwmRAwyRPzyzDw6POzavNzKpAQOFPzuxBwWTBw2ZGRORLyWdMy2lOzetPTivAQCBKyObOTOpAweNBwWVEQyLEw2LEQ2LDwuJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAsALAAAAAAQABAAAAf4gAABAgMEBQUGBwgJCguOCwEMDQ4PEBESDA4TjY8DFAwVERYXGBkRm4+QGhsMHB0eGB8bDpyOARogEBceIRgXv8COIiMkGB4lJSYnIcwoKb/DGyoXKywtKS4pHinMLzAxJDIzNDUtNjcv6B0hLzgfMh85OjstPDw99zwd7T4/LTVAgggZQqSIECNHevSAgSSJkiVMmjh5AiWKlClAiFARUeVHFSVWmLS40gNLlh5agGzh0kWDlwZfrIDREKaCAjEqrFA5MMYLmTAxlJTxYoZMozNozqRRs4ZNmy5s3LwhA0dBnDNn5MxBoAABnTp17IitowDrmQV+AgEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mailreply16:mail mail16 16:photo:16 16:R0lGODlhEAAQAIYAAIx+fIRubHxubHxqbHxmZGxeXHRmZGROTEw+NFxKTFxGPPwCBLymnMy6pOTa1PTm1Pzy7LymlOzi3HxqZOTWvPz69Pz25My+tLympFRGRHxuZPzu1LymjNTGvNTCxBw+ZPz23PzuzPz65PTu5NzOtCxWfBxKbPzq1DRafGTO5BxGbPzy9HTS5CymxBxajHRiXPzqzCyixCSaxCySxDSaxDSSvGS21GxWVAwmRBRejCSavByGtCSezEzG3FzK5FzG3CQ2bPzuxAwiPBxqlBxKdCRefBxWfBxSdBxSfBx2nCQ+dPzy1CRqlAwyRDQmJPTmvPTixLSafOTOpAQOFPz21BwWTBw2ZPzmvNS6nPTivAQCBAweNBwWVNzKpPzyzLyihGRORLyWdMy2lOzetKyObEQyLEw6NEw2LDwuJEQ2LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAsALAAAAAAQABAAAAfqgAABAgMEBQUGBwgJCguOCwEMDQ4PEJYRDhKNjxMPDBQVFhAXGBUSGY8LGhsQHB0VHh8gFQ6bjgEhIiMMJCUmFbS2CwMnG6IoKSorI7WpEycWFiUsLSou1yXXji8wFiopMTIzNDUz4zbZNxsbODk6Ozw9Pj8pPzEzQDdB60JDOkRFjBw5giRJDCWdlmxwIIRJExAWKDRyMgTIiydLoESRImQKlSUSF1SxUoXAlSBRsGSJoCVICIlbqlThcoBClC5eYFD4EiVIFwUyqywAE0ZMlqNjpJDpIkUBl0dlFChAYOZMmTJoyqQR5icQACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= mailsend16:mail mail16 16:photo:16 16:R0lGODlhEAAQAIYAAIx+fIRubHxubHxqbHxmZGxeXHRmZGROTFRCPFxKTFxGPPwCBHxqZLyqlMy6pOze3PTq3PTu5Pz27Pzy7LyinOTaxOzi3Ozq3LymlOTOtPz69Pzy5My+tLympPzqzNTGvLSelPzy3BxGbBQ6VPzuzPz65LyupNzOtPz+/GzO5BRejPzq1Pz23LymjHTS5CyixCSavBxqlPz25LymnGTO5CymxCSaxByGtHRiXPzy1CySxCSezGxWVPzuxKyOhMy6nDSaxEzG3PTivNzKpKyOfPzu1FzK5PTmzJR2ZLyihLSWfKyObOzmzPzmvDyaxOzavLSafGRORMy2lOzetDwuJEw6NEw2LEQyLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAsALAAAAAAQABAAAAfUgAABAgMEBQUGBwgJCguOCwwNDg8QERITFBUWjY8DFxgZGhsaHB0aD5yODB4TGB+kICEaIiOPCwEkJRcmJyYPKCIpKrWqKywTmC0SIi4vMDHEDCsyMg8zEyI0NTY3z7U4Hhs5Mx+0IyI6OyPrIzw9Gys+PxIy2EBBxAs8Qjk5Q0RFWFxAZySfgSMsilRAkiRECHQ08hHgJ0TJkCU/mECU2ISEkowUlpAQ4QTfowNPoAzJIeRJCyjm8kVRIkWIzSkXhwxJtYAKgp9VrFi5QoWKFZ5+AgEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== nav1downarrow16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIYhI+py+0PUZi0zmTtypflV0VdRJbm6fgFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= nav1leftarrow16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIAAAP///wAAACH5BAEAAAAALAAAAAAQABAAAAIdhI+pyxqdwoNGTmgvy9px/IEWBWRkKZ2oWrKu4hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== nav1rightarrow16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIdhI+pyxCtwoNHTmpvy3rxnnwQh1mUI52o6rCu6hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== nav1uparrow16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIYhI+py+0PWwhxzmetzFpxnnxfRJbmufgFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= nav2downarrow16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIfhI+pq+EPXYpxUckoO3AjbF3dJwahllXe6AFgC8d+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 nav2leftarrow16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAImhI+pyxf5VohmSlsxmpjTzAHeN5ak6UHpqKRi2GpwvH3Q3eT64RcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== nav2rightarrow16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAImhI+pq5HOAjQyVnqfhHue7oAaKH5kiW0AmnLqaHomkj02g+e6XwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== nav2uparrow16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIghI+pyxfR0HsRzNnuXVqn3mVQZWFRyIDjp65Ga5Ly4hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== navback16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBBRSdBRObCQ2TBxObISevAQCBNzu/BRGZPz6/FzC3Pz+/HTS5ByyzJze7Mzq9ITC3AQWLAyWvBSavFyuxAwaLAwSHBRafBSOrDzW5AyixCS61ETW3CzG1AQeLAweLAxefBSStEze7CSWtCyatBSCnBRWfAwmPBRWdByixAQSHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZiQIBwSCwah4HjUTBQFgkFg3MoKBykU0QhoUAIAuAksbpgNByPxQMSGVsVDYlkIqdUiJYLJqORbDgcHRseRR8gISIaEyMkGCVYRBEmeyAnlgaQkSgpmU4RAZ1OKqFOpFNGfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== navdown16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBBRObCRKZBxCXAwyTKTK3Ozy/NTm9GSivAQWHNzu/FzC3IzO5CySrAQOHAyuzETS3CSWtAyOtETa5Aw2VLze7ByWtBy61BSavAxWdBRCXAwqPAQCBDR+nKTe7FS+1Eze7ByixBRmjPz+/AyexAyixAQKFBRqjAQGDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZeQIBwSCwaj0hAYCkYEJLKguGASEADigWj4bgaHpBINykwSCYRa5HCFFQsF0xGo9lwhpSOwfORYC4gISJ3RAQdIyQYJSAlImNrh4uNJkl5CoKUUBQnjlB4KJ6hokN+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 navforward16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAwyTBRObAw2VDR+nCRKZOzy/KTe7Pz+/KTK3Nzu/Lze7FS+1AyexAyuzBSavAyOtBSmzOTy/BRqjNTm9IzO5ETS3ETa5By61AyixByixBRmjAQGDBxCXGSivCySrCSWtBTC3AQOHAQWHAxWdEze7AQKFBRCXAwqPAQCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZjQIBwSCwahYGjUjBQGgWEpHNYMBCaT4G2UDggos+EwmBYMBpf6VBgYDgeEMgjIpmoAQVKxXLBPDIXGhscRB0eHyAgDSGBGyJFASMiIiMkJYImUwAnmJqbjp4AKCmhAKSlTn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= navhome16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBDw6PBQWFCQiJAQCBFxeXMTCxJyanDwyLDQqLFRSVLSytJSSlISChCQmJERGRFRWVGxubKSmpJyenGRmZLy+vOzq7OTi5Ly6vGRiZPTy9Pz6/OTm5ExOTPT29BwaHNza3NS6tJRqRGQqBNy6pIyKjDwGBPTe1JSWlDQyNOTGrNRiBGwmBIRaLNymdLxWBHxGFNySXCwqLKyqrNR6LKxGBNTS1NTW1Jw+BEweDDQ2NAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaoQIBwCAgIiEjAgAAoGA6I5DBBUBgWjIZDqnwYGgVIoTGQQgyRiGRCgZCR1nTFcsFkHm9hBp2paDYbHAsZHW9eERkYGh4eGx4ag3gfSgMTIBshIiMkGyAlCCZTEpciJyQjGxcoKUQBEhcbIiorLB4XEltDrhcaLS4vtbcJra8bMDHAGrcyrTMXHjA0NSypEsO6EzY3IzU4OdoTzK0BCAkDMgkIOjJlAH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= navup16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBBRObAwSHBRSdISevBRWfAweLNzu/BSOrAQWLPz6/FzC3DzW5BxObHTS5ByyzAyixEze7BSStBRWdAyWvByixAQSHCQ2TAQCBBRGZJze7CS61BSavAxefMzq9ETW3CSWtAwmPPz+/CzG1ITC3FyuxBSCnAQeLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZfQIBwSCwaj8hhQJAkDggFQxMQIBwQhUSyqlgwsFpjg6BwPCARySSstC4eFAqEURlYhoMLBpPRUDYcHXt7RgUeFB8gIU0BIoiKjAcUIwiLSQUkJRsmGIwJJwmEU6OkfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== playeject16:play play16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIbhI+py+0R3IFQUtruXVqn3kkWyIARR4rqKvoFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= playend16:play play16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIjhI+py8Eb3ENRggrxjRnrVIWcIoYd91FaenysMU6wTNeLXwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== playpause16:play play16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIfhI+py+1vgoxzyUCxrZd18ClfmIyVyJ1lqkHuC0N+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 playstart16:play play16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIjhI+pyxudwlNyguqkqRZh3h0gl43hpoElqlHt9UKw7NG27BcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== playstop16:play play16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIahI+py+1vgpySUWpvXXqrHmSaeJEYhKYq6hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textblock16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIahI+py40Bo5SOzRvrwlgrfnkJOIkPaaaJXwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textbold16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIihI+py70BowPQ1HZpwNv212Vg9IGHmIjoWa4ey5DSRNd+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 textbottom16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIVhI+py+0Po5y0hYtzrkB7zH0fN/kFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= textcenter16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIbhI+pm+EPIZsnRkqtDnhu1zHfFSpjaY4PavgFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= textitalic16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIahI+py+0BgztwUmmjBXX3jE0auHHhM5Yq4xcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textleft16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIbhI+pm+EPIZsgRoqr3Vnt102fFSJjUC6nlPoFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= textmiddle16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIXhI+py+0PT5i01pisphjt3UmfFZYm5hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textmove16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIbhI+pm+EPIZsg2kfZvblXbwTg10WlA4rjyvgFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= textright16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIahI+pm+EPIZstSrqsDhhv1ylfFE5jiYwX6hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textsortdec16:text text16 16:photo:16 16:R0lGODlhEAAQAIIAAAT+BPwCBAQCBAQC/FxaXAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM5CBDM+uKp8KiMsmaAs82dtnGeCHnNp4TjNQ4jq8CbDNOroIe3ROyEx2A4vOgkOBzgFxQ6Xa0owJ8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= textsortinc16:text text16 16:photo:16 16:R0lGODlhEAAQAIIAAAT+BAQC/AQCBPwCBFxaXAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM4CAqxLm61CGBs81FMrQxgpnhKJlaXFJHUGg0w7DrDUmvtPQo8qyuEHoHW6hEVv+DQFvuhWtCFPwEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== text16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIlhI8Jwe2/AmpTynqPTXSqrnBM+I0kdmpmGmUp+K4nPMvhYx9+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 texttop16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIWhI9pwe2uYnq0yQtqxbz7D4biSIZ+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 textunder16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIjhI+pu+FxXoOIKpds1oBH7hlYxYxRCaIZ01lhJbHy9tTv7BcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== viewchoose16:view view16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBDQyNAQCBPz+/PzerAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMzCLrcGlAs6UAYgwLdLtEcI4ygQo7VVp2oupGpG4vmaUVTemX523qlFcw0a4RqNlkx5k8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= viewdetailed16:view view16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBDQyNAQCBPz+/PzerAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMmCLrc/i1IAVkYg1Z1iRYUKCqitp1oikqBWV3ZOnhkWNagqu+qnwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== viewicon16:view view16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBDQyNAQCBPz+/PzerAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMwCLrcG1AwGOQbw6qANeCEB3pCSZpO6pgowJZqLKuUGE0dnuEhf8IL1kz1shSHDX8CACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= viewmag-16:view view16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBCQmJDw+PAwODAQCBMza3NTm5MTW1HyChOTy9Mzq7Kze5Kzm7OT29Oz6/Nzy9Lzu7JTW3GTCzLza3NTy9Nz29Ize7HTGzHzK1AwKDMTq7Kzq9JTi7HTW5HzGzMzu9KzS1IzW5Iza5FTK1ESyvLTa3HTK1GzGzGzG1DyqtIzK1AT+/AQGBATCxHRydMTCxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ+QIAQEBAMhkikgFAwHAiC5FCASCQUCwYiKiU0HA9IRAIhSAcTSuXBsFwwk0wyYNBANpyOxPMxIzMgCyEiHSMkGCV+SAQQJicoJCllUgBUECEeKhAIBCuUSxMKIFArBIpJBCxmLQQuL6eUAFCusJSzr7Kmpl0CtLGLvbW2Zn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= viewmag16:view view16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBCQmJDw+PAwODAQCBMza3NTm5MTW1HyChOTy9Mzq7Kze5Kzm7OT29Oz6/Nzy9Lzu7JTW3GTCzLza3NTy9Nz29Ize7HTGzHzK1AwKDMTq7Kzq9JTi7HTW5HzGzMzu9KzS1IzW5Iza5FTK1ESyvLTa3HTK1GzGzGzG1DyqtIzK1AT+/AQGBATCxHRydMTCxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ8QIAQEBAMhkikgFAwHAiC5FCASCQUCwYiKiU0HA9IRAIhSAcTSuXBsFwwk0wyYNBANpyOxPMxIzMgCyEiHSMkGCV+SAQQJicoJCllUgBUECEeKhAIBCuUSxMKIFArBIpJBCxmLQQuL6eUAFCusJSzr7GLArS5Q7O1tmZ+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 viewmag+16:view view16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBCQmJDw+PAwODAQCBMza3NTm5MTW1HyChOTy9Mzq7Kze5Kzm7OT29Oz6/Nzy9Lzu7JTW3GTCzLza3NTy9Nz29Ize7HTGzHzK1AwKDMTq7Kzq9JTi7HTW5HzGzMzu9KzS1IzW5Iza5FTK1ESyvLTa3HTK1GzGzGzG1DyqtIzK1AT+/AQGBATCxHRydMTCxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaBQIAQEBAMhkikgFAwHAiC5FCASCQUCwYiKiU0HA9IRAIhSAcTSuXBsFwwk0wyYNBANpyOxPMxIzMgCyEiHSMkGCV+SAQQJicoJCllUgBUECEeKhAIBCuUSxMKIFArBIpJBCxmLQQuL6cAsLECrqeys7WxpqZdtK9Ct8C0fsHAZn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= viewmulticolumn16:view view16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBDQyNAQCBPz+/PzerAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMwCLrc/ixI0WSgKoyBl+beQFACpo1AqXbKCr1wLAMWS08hGG3dSZqin4sxnBmPD38CACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= viewtext16:view view16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIchI+py40BTQSwuovp3DXkv1ia1IHmIXLiyWJ+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 viewtree16:view view16 16:photo:16 16:R0lGODlhEAAQAIIAAAQCBPwCBDQyNPz+/PzerAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAAMuCLHcri4yGISlj4kxcANgNRBQCIbL6U1Su7bB62rXvGydG25kqpwfIGxILBr9CQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 actattach22:act act22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBMTCxPz+/DQyNKSipAQCBISChFxaXDw6PAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARrEMgJgqA4zzus/gLhFd5HCcZAXqsphYPUdhcYFNRcZnvdtpnDqPTbUWgAJKBYwzBlw+bRo3xmkNWoBgm0OrVLn3GC9RgCk8DhUw7c0rHPr4CDu5SYQNyEt7uSY3p/UAKFhYKDSQOLiwgFdhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== actbookmark22:act act22 22:photo:22 22:R0lGODlhFgAWAIQAAPwCBCQmJCwqLMTGxAQCBBwaHMTCxLSytERGRFRWVLy+vKyqrKSmpHR2dJSSlJyanISGhGxubIyOjKyurGxqbFxeXGRmZHx+fKSipLy6vGRiZLS2tFRSVHRydJSWlHx6fCH5BAEAAAAALAAAAAAWABYAAAWWICCOZGmewamaQrq+wUC8azHINGocOI38iIRAceDNaISFYklkGHOEhoNBfUAOhuOLEJE8HoPiRKFdESiQBqViuTDIUAsEcyAeGJmyiqC5RCwJGg0YcEh9D0V3Dxt6JwQVDRYVHBUdi40mjw0PTgwQHgeYJQQJfxUXFxAOoTkFpQ0fsRSimQkWEQ0VtI62HLt7vjl7JQYhACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actbookmarknew22:act act22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBCwqLCQiJCQmJMTGxAQCBLy+vLSytERGRFRWVKyurKyqrLS2tKSmpHR2dJSWlKSipISGhGxubIyOjGxqbIyKjFxaXGRmZHx+fPz+NGRiZPz+ZPz+HMTCBKSiHPz+jFxeXPz+XPz+tPz+zPz+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAamQIBwSCwaj4Gj0hgQLJ+AAaEAVQoI06pRYDhkoYgwIhEgKBTfZ2FhaBsYDS8VWnA8Go0FJIKeqyUTDw8EDHBpSwUUFQ4UFhcYDQYFfkoFFxEQDG8KEAUZlEeWGBIakw4FG1STiBoYBRwdBR4fHgUdHKBEBSCnIR8iIyIfIblFu6ceIyQjtcXGCbLKzAUKzrq+wMLEVa+xs7W31kOTk6nkWuOf6Ea5QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 actexit22:act act22 22:photo:22 22:R0lGODlhFgAWAIEAAPwCBAQCBHR2dDQyNCH5BAEAAAAALAAAAAAWABYAAAJOhI+py90RnIMyRUOxhDfzJkACdoXBuEDDkQFDi5go0MrKx16kns80b7qdELCgBYaEGWwL5nG1ePFiKp9A6kuYRNuho8vxVrrZivmMRtMLACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= acthelp22:act act22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBCQuNBwiJAwiLAwaJAwSHAwSFIy+3ERynCw2PCQuPAwmPCxOZCxWdJzG3FSazBwmNAQKDAQGBDRmhBQyTDxujDR2rIy21AwWJDyGxCxmjAwmNDRihAQOFDxmhCxunBQWFAwaLCRahDR6rESGvDQ2PCRWdDRunDSGvCRSdAwWHCwuLDSOzHSmxDyKxBxCZBwqNHSu1DyOzAQSHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAahQIBwCAgIBAPCoGAgOoeBAyKhWCwYDUf0CX1AIhLiJEGpBLiAAaRxdgYsl7Ybk8igBZoN5xmAdDxoanp8HyANISF8EBsiXBMjJBolBEQmGHFoRScbKHIKDykqK5lFAZRCnyknTaROLA8tq61OChgtKqyzQgEYEJi6UC4vI3LAASkbMBPARAEBdszR0sACEaPSMTIQM8W6KzNl3bo0NOJDdEEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== actlock22:act act22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBHRudFxaXExGTERCRAwGDGxubPz+/Pz2/Ozm7Nza3NTS1KympFRSVHR2dNTO1JSSlKyqrKSipDQyNMTGxDw+PLSutKymrMTCxAQCBHRqLBQODJyanDQuFFxSJFRSJFRGJERCHExCHISChHxyLEQ6HGRaJExKHLSmbLy2fOzitPz23KSiZHxuNHxyNJSOTNTOnMTCjLSudKSaXJSKRJyOTOTetNzWpHxuPOTi5MzKzLS2tFxWXOzq7Ly6vOTe5Ix+RLSqdNzSpLyydKyqbKyiZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4IBAgMEBQKEjI0GBwgJCgsMDY2XjwkOAgQBDxCLl4QNCaGCBBGWooINCAqqrBKgqwATFKaDFRYVtBMXsIMNGBm0GRADjQIJxKIaGxwdHh8gISIhGyMZzIwkGholJiYfJiAfJyEZISDbg90oKCkqKwcHKyooLC0f7IIuLzD2YMSQgW8GDRri+AFoUMOGvRsxUhSsQQPHvmQSchyQtEAHhh0WJHDQcJERjwsKDvRI0BGDjwgicXhQyCOjSgUKPO6AObIkIQESfmxk6REDT4s0bfaYpDNkT4VAha5s+TLmzEYtatwIOHAiDZIKNQAJYk9IjCFEisyoocFEB4UACtBpm0t3LiF4gQAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== actredo22:act act22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBCReDJzGjMzivOTu3Pz+/JTWbHy+VHTCTMTivPT69BxGDESuJDyiHESiHEymJIzKZAQCBFS2LFzKNGzWPDRqHCxqDFSqLHy2XESCHAwaBAQOBBQqBDyWJHyqZDyKFGSiVESeJBQ6BAwSBGTGPFyWPFSSLEyOLESGJBQiDAwiBBQmDCRGFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAaoQIBwSCwaj8hkMcBkKpcBwYAwEDif0YLhwEUkFItFMkAwMBoOR+PxgHwjRDggamhIJpQ8ZbKGKOQLcgEFdhUWEYgRF3sNfhELBHALAhgZFhobRBwREhQdEAIEHpIKHwsaSJwUDQgQIJINARxKESESDQ0dgCIjSpAkDAwPco+ZSJAlJicnKHIAIrNHidOIQxunT0kpCyrZSCss0d5Fj6jjRonn6uvs2QZBACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actreload22:act act22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBCRSFCRSHBw+DBxCFCQ6FBwyDBQWBBxGFCxyLGTChMzqzLzmvHzKjDyOTER+RERyNDSqXNzy3LzivFS+fCyCPBQmBCQiBBxKFBQqDOTy3LTitES2dDR+PCxuJOT25KTarCx+PESSTCxKHDSeVCyKRNT21ESWVDSGPBQyDAQCBBQSFDRuLDSyZDySTGzChCRiJKSmpExKTDS2ZGzGhLy+vGxqbISChDSKRMzKzGxubDQ2NIyOjCQiJCwqLBQWFCwuLKSipERCRERGRHR2dAwKDDw6PFRWVIyKjCQmJFRSVBwaHKyurAQGBExOTBweHFxeXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf9gACCg4IBAgMEBQYHhI2ECAkKCwwNDg8QBAOOhAQREhMUFQgWBxcHGBmbggkaGxwPB4yDB6SbBJIKHQaqtY0eHyAhsqrDgx4aCiKpqoQHAyMjJBMKJaSxzAAHIRsmJgonKA0LHSmDKiuOBywRLSQuLyEwwyoxMuiN6iUzNBXy5jU2bsgoJugABBz95uXQsUMGD3vpPPgTpKIGwx4+HMr4kW4YkCA2hAzxAQSIECI+imBTwVIFESNHerRUgc0cEiFHkjiiyYzeDiVLdvLcySSkkKGEWiZVweSGkIHMmvQosoQlkaZOjvhosvKJjIAxoOAsgpRZkQNLnvSoqspAIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 actrun22:act act22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBAwKDAwKBCQiHNze3AQCBBwWFDw6NPTy9PTy/Dw2NKyytOTi3LS2tMTKzMzOxLy+tLy+vBQODNze5NTS1JyalIyCbIx6VIRyVISGfJyelOTq7EQ+NMTGxKyurGxeRLyKPOSmROSuVOy2XOSiTLzCzNTOzDw+NCwqLHxuVOy6bPzGfOSuXNTW1LSyrMSWRNymTOSmTKSCTPTGjPzSnPzWnMyaVBQSDMTCxPz+/KyahNSeRHxeLJRyTPzmtPzarOy6fJyajNza1Ly6vLyulFRCJPzirPTOlMS2pNTSzMTCvJyenBQWFNzKtPz6vPzyvPzqtOzGlOTe1AwGBFxWTLy6tPTm1PzSpPzutPz2xPTSnOTSxOy2dPzapPzerOzm5IR+dPzu5Pzu1PzqxPzy5Pz+9GRiXGxuZKympHR2bOTm5Pz6/MzSzBwaFJSSjCQmHPz2/AwODAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4SFhoeEAQKIjIIDBAQDjYMFBoMHCAkKgwYFhwULDAUKCg0ODxCkBQgRnoUSExMUDxUWFxgZGpAbFIuGHB0eHyAhIiMkIB8lJieIKCUpJCTGIyorLCktKIUDpC4YLzAxIjIyMzQ1NhgdpJI3ODktJTowOyM8Ejc9Pj9AQUIEclAocCMIBQhDiOwgoaKIoCI+jBxBkkSJkCWemIyq0GSHCBVHihRx8gRKFCmpKhGaQqWKFYZXsGR5kkXLFgRUXBUqkCGCFS5AjnTx0sXKlyA6CRVgAAHMAilhxIwhU6ZFkBY5kgKYUoXBAzMKzixZ4AJNGgVm1KxhM0WpmQpUMtooaOPGxAM3Nw60oYLGjNYCbzYJOgAnRzNBJ95oPYQCgpJtkwzFoULlRuRPiy9fNhAIACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actstop22:act act22 22:photo:22 22:R0lGODlhFgAWAIUAAASC/CQKDBwKDCwODNyKjPzq7My+vIxiXAQCBOSOjPz6/OSelNySjNyGhMR+fLRaTGQ2LPz+/Nx+dNR2bNRybMxuZMxeXMxiZLQSFJQaHFwqJNyKhOSCfNyCfNR6dMxmXMxWVMRORLQODOR+fOSSjNR2dMQ2LJQWFMRWTLwWDNSCfMxeVLwaFKQODNR+fNx+fMxiXKQSDOSWlMRSTMxaVMQ6NMxORMQyJOTS1MxqXLwWFLRORMxKPMQaHMxKTLQWFCH5BAEAAAAALAAAAAAWABYAAAb2QIBwSCwajwGBcikIHIsDQmFKNRwQT2EgoVgsGOCG4wHBIgmRhWRCqVQsF0xGYyYGNgoGh9PpeCQfICEic3UAAWgLIxwRJBsbHSUREyYYJ3RDAQULexGejhueESgpl3WaCxsqJKKsChEUKywtmFoFDC4vCayikzCyMbWHt38NCTKiHhUfMyzBdQIFKsodob0VNDWzwppuKxMRrx6iNjcitNA4bh+iEzkwojc66JkOOxcf7G35PBE9KS1MEUGgIQOIFfk++KjRw9wJgUUIZvhRoyLDFCliQDQisUWLGCJOeNx4hKCGkyhPGnqCoKVLl1liypyZxUAQACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actundo22:act act22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBCReDJzGjMzivOTu3PT69MTivHy+VJTWbIzKZEymJESmFESiHDyiHESqLAQCBFzKNGzWPFS2LNTmzCxqDDRqHPz+/KTGnBQqBAQOBAwaBESCHHy2XBxGDOzy7HTCTEyyJDSqFHzWTAwSBBQ6BIy+dESKJFySPFSSNAwiBCRGFBQmDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAalQIBwSCwaj8ikMsBkKotMwYAwEDiXgYLhwD0gCFZiQKxNKBYMRqPh+D6G16y5AYnYIxBJAyF4AwITTAUJdBESD4gPFBV6Fn6ABBcJDIYPGEQZGhQbHAIdfx4JHw2VSBodGwWfAR4LDSALfkgYAQurBiAhICKfSSMkvQElGyYnGyi9Rxkdj4nOskUYyU9FpxnURikdGtjRKivdRKfQ2Inh5+jpRwZBACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actunlock22:act act22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBGxqbFxaXExOTEQ+RAQCBPz+/PTy9Ozq7Nza3NTS1KSipFRSVOTi5Hx2fJSSlKyqrJyenJyWnDw6PMzKzKyurDQyNFxWXMTCxJyanHRuLHxuLGReJFxSLFROJFxWJExCHERCHBQODISChHxyLHRqNIRyNHRmLLSqbKyiZLy6fOTarPz67Pzy3OzitKymZFxSJJySTNTSnPTy3NzSpMTChLSydKyqbKSaXJySVIyGRGReLPz23NTOnMzCjHxuPLy2vKSmpOTe5LS2tLSutHxuNHRuPMS+xFxWLIR+RDw2HFRKJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4SDAQIDBAUChY2EAQYHCAkKCwyOjZANDgIEAQoPjJiDAg2iggQQp5gMBwmrDBESl6MTFKuoFQSjABYRF40CGAW8BRm7hQwNxBobHB0eHx4gISIjBdiEAhYFJBslHOHSHh4hBSHlxIUmJygpKissBiwtLi8pGjDqhBoxMjMuaNSwcSMFjhw6dnjYRyrGCh4ueviw4Q5HDB0/PjAUJCBCAwMIGiiggAEIBFk/FgYLIgRkggQkhxAJkqGExkYMFnxsIGRkSQgLHhRRWUjAggQgG8AsSWRBBiP6VrYMOfKIyaBDNwLo+HHSUplOSyDRqiEHjRkretRQkcLgxayNF0wksQGQxsSKMTIq0QpgCba/gAE7IhMIACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= appbook22:app app22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBDyGhCyCfFSWlESOjDyKjDSGhCx+fGSinGSenFyanEySjHSqpHSqrGympEySlBx2dISytHyyrCR6dKTGxHyurHSurHyytGSipCR6fARmZFSalEyWlBRubAxubBRydDyKhDSChLSytPz+/MzKzIyOjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAbFQIBwSCwaj8ikMhBQIpmCQdM5ZBIKhgNiugwkFAsCI7pNMhuOxkNBgBgEiAi3GkBLJpJHYgEpaClyREwVFhcSEhgOGQoMfgMaERtcARQBFRMYExZ6HB0FUYAekkIBHxqWFmlrC1haESAfG6MBGx+VFRgKYH0hInGRklO0ppYXCwwMWQiQHkwjgrWnFRdYZHIBJCTP0LaWGAcDW9jZ2nMAw9IWTOQkJSZMRsOV49nu8E+19PbmR7TY+1TovONH5V7Ag0QMBAEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== appbookopen22:app app22 22:photo:22 22:R0lGODlhFgAWAIYAAAQCBAQ2NPwCBHSurIS2tBx2dBweHPz+/Ozm1GxiTGyqpPz6/Pz69GSqpOzaxPzy5HxuVLSmlOTazPz27PT29NzClPTexHxuXLSmjAxqbFSinPTy9KyehNy+lPTy5Pz29HxyXNzWxKSahOzexPzy7IR2ZOTWtESenPTy7KSWfIyCbKyijAQGBDyalPTu3KSSdDSOjJyOdCSGhPzu3OzizJSGdPTq1PTq3JySdMy6lAyKhOzWtOzi1OTOrJyKbMS2nJySfMS+rAwCBNzOrNTCpNzKpJSGZKyafLSifLyylIx+ZHx6ZDSChAQuLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAIALAAAAAAWABYAAAf/gAABAoSFhoeHAAMAiI2IAAQFjI6EAAaJkQeTjwAICYkKBQcLm5WdBwyfhgChB66bp64HCQC1lQ2irqQCAA4PowsLEBESE4wAuLIHFAAVFr+uDBcYxRm1GrmuGxwdFh4Mrh8gGCET1gDYyhsiFSMkDAsMDCUYJhvnJ9kHKCnODwwfPlBQsULCPRYAWogK9sHFiwoOPEyQh0JFPXO1YBSYwBEFghjdHkwQOYGgwQwIZRR44GHGDBogabhAsYEEihrUMAIoUMCEDRs3HODIYQHFA6MPcJA7KICFjgw7eIzo4cOfiwc/gKwIUm2SkKdDdlDt4AABDaU/iIRwwbTSUyJFOow4S3Hkx9oNDDZgXPU0h1wcSIgEGUw4ibVET5WoWMKksePHpdxmyKADAEIWly9HJtQkQJMmlAgZCAQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== apppencil22:app app22 22:photo:22 22:R0lGODlhFgAWAIMAAASC/IQCBPwCBPyChMQCBPzCxAQCBPz+/MzKzISChKyqrDQyNEQCBAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARYEMhJ6wxiEMtpIAWxddwXiqRlikSQeiAbuC+wirNR322gv7zcLobzDU+9XypoBBKTR1lz+RTWDgip8nUwZK1XLyIx5XoVicX2RUAo1DVKi7GOBxjxfNwQAQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 apptool22:app app22 22:photo:22 22:R0lGODlhFgAWAIQAAPwCBAQCBISChFxaXNze3NTS1Ly6vKSipNTO1Ly2vNza3Pz+/MzOzOTe5DQyNOzu7MTCxGRmZMTGxPTy9Ozm7Hx6fPTu9MzGzGxmbAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAW1ICCOZGmeaEoGbBsI6joMRGEcbQwESDIrtVtAF1gwDLNaAmfKiVgLBJKgwB1KxQZrBHU0FAXmavFoQLYiB6TxFXMj5AZBwnJI2I3wcNWALyYEcgoKXxRhOHs7XxEVCwsWFgoUDRYUFwwQB25ZCxiNjo6GkwUXN2NsCxEYqhUHoQ0MEglYRQQXErcHrI55FycuB2YSmoyOBTEtB2sXuhU6XAENC2a6z9AKCwq+1tAN3E2J3ySkIQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 connecting22:connect connect22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBPz+BMTCBISCBAQCBPz+/MTCxOTi5AQGBNze3Ly6vISChNza3FxaXKSipAAAACH5BAEAAAAALAAAAAAWABYAAAR4EMhJqwzY6omD+MNGdR8YilNZnug0qGzrqrL1lnV1fyJBVB6VQEMoGH4ADGwQkxQPBwMiKGA2J8VEAnq0tgiKg5aL/C7C2gTjKCM0zowDQ8tuNQznNL7cKzjOUQsNfER+gguIg19+Pm6ChBZFDmWNi5M5FIyYFHQRACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= connectno22:connect connect22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBPz+BMTCBERCBAQCBPz+/MTCxOTi5Nze3OTm5Ly6vNza3ISChFxaXKSipAAAACH5BAEAAAAALAAAAAAWABYAAARiEMhJq7046827/+AVCKE0Dh9BAGdaGISAToFGFMcBU+11I4hDYseSZQiKwwKoI/QwBIYiuFDCZseGdIlYEjUNg1SpY6w2N4cUIW6cjwW1lsFwo+MqgtZuw0/ydw5vH34lBhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== connectyes22:connect connect22 22:photo:22 22:R0lGODlhFgAWAIQAAPwCBAQCBKyirPz+/KymrOTi5KSipMzCzNza3OTe5Ozi7MzGzPTq9OTm5ISChMS+xFxaXNze3GReZIyCjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAWLICCOZGmeaBkAQpoGg7C6JizTQT7CxPwOwFWgYPChYIXkIHC4uQKGAiKRKCyNpxxUUVViVYNFLkqtLo+DAkMMLXQPXwAy2WCTF4544FGtKuwPDhB6DnxuUmyCcXIQhV1uYoMuEAcOBxEKCHg6TzGFCJUSizuejROKOAM9OY2SnUU7nD89NCcDsLUnIQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 devscreen22:dev dev22 22:photo:22 22:R0lGODlhFgAWAIcAAPwCBAQCBPTy9PTu9Ozq7OTi5Nze3OTe5Nza3NzW3NTS1MzOzMzKzMzGzMTCxMTGxOzm7AwGDBQOFBQSFCQeHCwmLCwuLDQyNDw6PERCRFROVEQ+RDQ2NLy+vKSipISChGxqbExKTOzu7OTm5Pz+/GRiZMS+xLy6vBQWFLy2vCwiHFQ+NMSmfNSyhIxmTDwuLJx+bLS2tCwmHMyyhMyqfPTqpPzyvLSWbLSWfPzitIx+ZDw2PAwKDCQiJGxWRPTmrPTerMyuhPzqtPz63PTWnPz6zNy+nIRiVDQuLKyWbOTanPz21NS2jNS6lDQqJHRaTPzmrPTSnPzyxOTClPz2xNSuhPTqxPzuvOzSpAQGDOTKnMy2jOzSrPTu1NzKnOzOnBwWHJRuXLSWdPTatPzqvNzClCwmJOzSnOTOnPTuxOzKlOzerOzarOzitJR6ZNTO1IxmXPTWrNSyjPzOjPTSpLSehHRqZOzirOTCjPS+fPzGhOy6bOzKhGROPMy2lPz+1PzmtKRyRHRiNNTCdPz+zNzCjEQ2NKySdDQmJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAj/AAEIHEiwoMGBARIqXMhQIUIBAwYQIFCggIEDCBIoULBgAYMGDgIIDEBAwMSKBRBk3NjxAciQIwdACBBBwgQKFSxcwJBBwwYMHBx0EAmA5EwPH0CEsCChoYgOQ0cSGCHhA4kSS5syJGDiBNEAFVGUKKEBAwWFFM6SNJHi64gDFEKE4FBBggoKK1i0cPECxokYXw0gsECYggQZM2jAqGHjBo4cOtqOxLhDAg8ePXz8ABJEyBAWRIoYOfJipEoMCZEkuaFkSAslS5jUGJKkSRAnRREo0JDwCZQoTKQAmUKlihQrVa5gKZ1lI+oAK7QM2cJlSZMuU4Z4+TJEx0iNOwKAggkjZkyOFmS8kClzpcUQLRRGbjRD4MgZNEzSqKG+ZgobI2248dUbDDDwABzcxSEHEFpgEcUcdMRRhx1fFejAAx0cgcYdSxiBRx566LEHH0d8QFRRNC3Uhx985CHEH0MAEkhCBxWkgiCDFEFIEYUYUmONMhyCRxVH/PgjBYioYJAdAQEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== editcopy22:edit edit22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBBQSFPz+/DQyNISChDw6PMzKzMTGxERGRIyKjFxaXMTCvKSmpHR2dPz6/Pz29PTq3MS2rPz69MTCxFxWVHx6dJyWjNzSzPz27Pzy7Pzu5PTm3NTKvIR+fJyGfHxuZHxqXNTCtPTq5PTi1PTezNS+rExOTFRORMyylPTaxOzWxOzSvNze3NTOxMy2nMyulMyqjAQCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAbYQIBwSCwahYGkUnk0BgTQ6IAQaBKfUWhBYKhaAU+CgXAQIAyChLeJzSIQhcH6GFaM0QtGY5kstqEODw8QEQELAhJTc08KBBMEFBUWDRcBE1pca20SGBkaEBscAY5maFRIAgoLHRQRHh8gIQFlZnByqA8ZGSIQIyQjJQEmYgJ5p2ACrK4gJx4gKIZZAgdeAQ4ZI9kjKSor0AwEjeAs1S0cHAslLi4vMDDRWeRIfEsxMeET4ATyVoYLC5fizXEiAR84BeMG+pEm8EsAFhAjSlR4hR6fLxiF0AkCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= editcut22:edit edit22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBAQCBAwCBPz+/OTi5JyanOzq7DQyNGxqbAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARbEMhJq704gxBE0Bf3cZo4kRJqBQNRfBucyudgvJS6VaxLzyMa6/bLiWA9HOg4VIIkL5vzuRkcpkvRIIAorphJLzBW84WEuRZWp6uaT7J2Sh1Hit3OY/ZO7WvsEQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 editdelete22:edit edit22 22:photo:22 22:R0lGODlhFgAWAIYAAASC/FRSVExKTERCRDw6PDQyNCwuLBweHBwaHAwODAwKDAQCBExOTNze3NTW1MTGxLS2tJyanPz+/Ozu7BQSFCwqLDw+POTi5PTu7MzKxIR+fCQmJPz6/Oze1NTGvPz69Pzy7Pz29LyyrPy+vPyupPTm1BQWFIQCBPwCBMS6rPzSzNTOxPTi1NS+rPTezNzOxPTizOzWxMy2pOzaxMy2nPTaxOzOtMyynOzSvMyqjPx+fOzGpMSihPTq3OzKrOTCpNzKxNTCtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf8gACCAQIDBAUGBwgJCgsLgpCRAAwNlZYODxALEY+SkAMNEqKjEw0UD5yegqCjrRMVEqidkgWhraMWF7GptLa3EgEWFRSOnhW+vxgZEBqzkBvItxwdHryRCNGjHyAhHSLOgtgSI60c2yQjJd+eJqEnKK0hJCgnJSngAO0SF+8qEvL0VrBogW+BLX4oVKgIyMIFQU8KfDV4R+8FDBcxZBREthAFiRIsOsygsVEUh4Un3pGoUcPGjZInK65QicPlxg8oX5RwqNJGjo0hdJwQ6EIkjRM6dvDYCKIHSBc1Ztjw4eOH0oIrsgIJEqSFDBo0cuTgsdSTo7No0xYTZCcQACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= edit22:edit edit22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBISGhISChHx+fHx6fHR2dGxqbGxubGRmZGRiZFxeXFxaXFRSVIxSLPyuXMzKzMzKxMTCtExOTPzqrPz+/NTS1MS+tOSaVPyWNPz6/IxeNPzavPyKBNTW1PyCBPyGBJxmNPzOpLx6PNRqBMSCRNySTPyCDPSGBMxiBKROBHRydPSylOyydMxmBJxKBAwODPS2lPTq3OyabJxGBPTy5PTGrOyOXPR+DPz69PzmzPzevNxuPORqLMReFPzy7MyCXKxiNIRKHBQWFNTOxPzixJRaPFxONHRqVPz27PTy7PzStCwqJDQyLJSGdIx6ZPz29PTu5HRmTLSKbMSGZHROPFxKPJSKfJyShKyehMyuhDQmHEQuJJyOfLSijMSynMS6pLSefDQyNHx2bKSahLyqhLymhOzi1FRGNIR+bNzKtOTOtOTKrOTKpLyedAQCBFRWVPTq5NzOvLyunLSmlNTCrOTOrNzGrLyidMS+rLyynKyijLymjLyqjAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gAAAAQECAwQFBQYHBggJCgsLDAwADQ6CAQ8QD5ydEJ+gERKWE4ICDxSpqhWqqhYNFxMYphCtqaytGRoXGxgcggSoth25u70eH8APFR0VzMzNziAXIRjIvwAFwq3EqSLUGB/iI4LathS4JCXVJh8nKCmCKrXDFCss1eIfLS4v8ssdmgWsAGNDDBnt3s3wJ+jAtlUhaNSwccNEi4WCBBl4SAHHihw6ZOzg0QNjRgAG6KXK4CNEjBU/gDQI8kLISQAIADobAoMIzCINjLw4YvNkAno4kCRRUuNHESNLmDRxUjSjAlRPfECJImUKlSpMrFzBIqWqoKtJaWSJomULAy5XXrp4+QKGYcYFoCBEWRImi5gmY7CQyVLGriAGD2jEMHMmCxc0Xb6kUbOGTRs3N988gLM4jpw5Y+iwqcOGjZ07mE8yiGABz5c8c/Ts4cOnDJkybS7fdMO7t+/fvDMaCAQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== editpaste22:edit edit22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBBQWFDw6FHRuFGRaBFxSBAQCBAQKBCQiBIx6HPz6/NTOfKyiXDQuFOTm5Pz+/Ozu7PTq5Pz63PTyxNTOjKSeRExGLMTGxMzKzNTS1NTW1Dw2NKSmpKyqrKSipJyanNzWlLy6ZLSuVIx6FISChIyKhJSSlCQiJLS2tDw6NDQyNCQiFCQmHBQSDGRiZHRydGxubHx6dGxqbFxeXGRmZFxaXCwuLOzq7KyurHx+fDwmFEQuFCweFCQWDBQODBwaHBweHKSinJSWlOTi5JyepHR2dDw6PBQSFNze3ERGRIyKjIyOjISGhPz29Pzy7MS2rMzOzFRWVHx2dHxybDQiFPz27Pzu5PTq3PTm1NTCtJyGdHxuZHxqXPzq3PTaxNS6pFxWVFRKRNS2nPTi1PTStNSulNzOxNSynMymhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCgwABAgMEBYSLggaOjgcICQoLDA2Pj4MGDg8QEZ4FDxITFBUWFxcYGRobjQ8cHR4fCQ8gCyEiFSMWJCUkJieNEB4dKB4pKissK8wrLS4vMDHBAAYQHx8dFx0fJDIzNDU0M+IyHzaNNyg43Ng5Ojs7Ojw9Pj9AMkCNDiZB/h9CSOx4QLCgihItqBkYgqIDESElitAYWJCgkQcXjjRCgi1Ihw4BB5LAQOLCgyQYHihpUU3DBw5ElpAgAYNixSRJjKjQaECDCRPZPDB5IbIGSQwKLnh4wbInLA4kmJB4oaPiAwVNnER40hRK1BIAaVatUZJEFCkmpmjgCeWDCalFe4q4oFKwSRUrEa5gycLzwq8lUnPQ4PEgSpYcUZ5o2cIlS1O/JHLEDdfjQZMIVrpgweLFy5e+M6WSmBGlxYMYYBRzCaOFi5imHWBIfOEiShLTVjaP6eyFTBmN1TA5OvLDjJksWb58OVMGDRqWjAYdmU79SIvpjqJr104nEAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 editshred22:edit edit22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBFRSVExKTERCRDw6PDQyNCwuLBweHBwaHAwODAwKDAQCBExOTNze3NTW1MTGxLS2tJyanOze1Pz+/Ozu7BQSFCwqLDw+POTi5MzKxPTu7LyyrIR+fCQmJPz6/Pz69Pzy7Pz29OzaxPTu5PTq3PTm3My6pPzu5PTq5NS+rPTm1PTi1PTezOzWxPz27MyynOzSvMyulOzOtOzKrMymhOzGpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAbpQIAwIBgMCAXDAZFQLBbCqJTRqFobjgdkEYFKowPJZEyeUBqVR/crHDTKZYplovZKCW84+YKZZNZSBXl6EwEEBhVPXxZihGMaGRscdkIdg4QeEnVfCH2OHyAhIhuUAAiXZSEhIyQlJqWnjiEnKCWupRWoYyEgJK0SKaUKjam0JCorLMFfC6iqx8giLa/MGAsT1wsuCyULKwssC9RSzdkfCyALKuALLQsvpeXYIQso3gsiCzALMfENC+dGcMNHUAY/f+jq3ctncMYCGggFrsvHcEGNh/EyPFmg8cmrJxAVkVO0EUDJklHoBAEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== edittrash22:edit edit22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBERGRExOTDQyNISChBQSFCQiJCwuLPT29Nze3GxqbDw6PGxubHR2dJyanLSytJSWlJSSlOzq7Pz6/Nza3Ly6vFRWVBQWFIyKjMTCxHx6fIyOjLS2tOTi5PTy9OTm5Hx+fNTW1KyurKSmpJyenExKTMzKzKSipFxeXCwqLMzOzKyqrMTGxLy+vHRydBwaHNTS1DQ2NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAb8QIBwSCwaj8KAMoA8LgUDQsFwQByay4RiwWg4GA9IRGk0SCYJSsUCsVwwGQ1EsmESD5xOp+L5gDwhBRIZDhcDdkMGDgEiIxAkJQ8Ok5MmAohDAQ1xJxUlKCUlEg0pKpiZJRoLCxmtCw1eURhOcR4rbQ8cGRwLAwgGtBYTDywtGRKjvQTARgEZLhMcKC0OrQMvAirMRc7CHCTU1g2+20TO0NIn1RwDCya/wdHT1Rnt5LToKOq79trx0tR02YPX7Jm8fRxMOIhSLhOJE/LCJSTlr5kFEBQsWDiR4UGGBgsuHDg1BEYAfTE6oEBR4AIBAiS5yWBAAAGBAyaPGAgCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= fileclose22:file file22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBERGRERCRDw6PCwqLExOTFRWVHRydGxqbGRiZCQiJISChIyKjHx6fDQyNBwaHJSWlKSipBQWFJyanPz+/JSSlCQmJAwKDCwuLBweHBQSFGxubExKTISGhDQ2NFxeXFRSVDw+PAwODAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAbZQIBwSCwaj8jkMSAYDAgEJbFgOBwQCUOAoJAaFgvGonHIBhyP5BcSgUAYDWxggD4WFmx3e3HQngkSRgYMEBMUFG4MCId0BGlEAQeEhocVDYcUdBYKF0QCB3gRlJgUAQEYBBkaRAMbDZMMpAYcT46rQwMJrgsdC6QcfwoPnUMOBgkIV6SHHg6bw0QEAQYfBpggBZjPGsRD0gEchxwCIR6HChnQRQ8DIU4DTR4Em+ncRw8O+fmoXPXdRg+gQLFgIYM/KRIkoDP4QMKFf0o0aBAh4qGUixgzCrETBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 filefind22:file file22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBBQSFJyanLS6vLzCxISChNTe3OTu9Oz6/Nzy9Nzy/NTy/OT2/Nzi5Mzu9Lzq9KTe7LTq9PT+/Pz+/Nz2/Mzu/Kzm9Jza5HzK1LTi9PTu9IzW5ITO3FxaXNT2/KTi7Iza7GzC1LzW3FRSVMzO1MTq7HTS3Fy6zFS2vKzm7Lze5MTGzHzS5FTG1Ey2xEyyvJze7JzW3ITa5FTK3EymrGS+zFxWXKymrMzi7ESirEyqvLSyrKze7MzOzMTCxKSepAz+/NzW3MzKzBwWHLzS3ERCRAzi3KyurNze3MzGzLy2vLSutCQiJAyytHRydOTe5MTGxLy6tLyqpKyelJSCdOze3NS+tLyupLSmnKSOhCwuLPzy9Pzu7Oze1OzazOTOvMyihOTi5PTm3Pzi1PTazPTWxOzOtNSunDQyNPzy7Pzu5OzKrNzSzNzGvNS6rMyynMymjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCgwGFhYOIiYQBAgMEAwKHiokBBQYHCAkKCwwFAZOEBQ0IDAsODxARCZ6gAAEGEhMSFBUWFxgZCJ+TjBoMEpkRERscGBGRih0BBAgeFBQOER8gISEfIruIIwEkCCUVwhcgJicoKSrZg9srCRkRGdMsLS4vMNiK2wIKMRsbMiwzXtCocSydIBs3AuCIwIFDiBMucugAoWvSiB2VNPDg0ELHwA0MkCXr4aNSggg8NoDIQOFHgBtAkgURMiDAEAFEVBCJFKCIkSMGOyDRkETJEkOFmABoUsRJQkQdnkzQACWKlBtTplBR6qopxkFRJ0ytYuWKFCxZtBBq+hRA2AlbRrh08fLlCxi1a51g+dQhDFwuYsaQKWPmDBpKXgNETaNGjJgyhNfcVdTTiWI2XpK0cePmzRk4YA5T5otGixY0qFOXbgXAQCAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== filenew22:file file22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBExOTERCRDw6PCwuLBwaHAwODAQCBOze1NTW1OTi5Nze3MTGxLS2tJyanPz+/Ozu7OTi3BQSFCwqLDw+PDQyNFRSVPTu7MzKxLyyrIR+fCQmJPz6/NTOxPz69Pzy7PTu5Pz29Pzu5PTq5PTm1My6pBQWFPTq3PTm3NS+rAwKDPTi1PTezOzWxMy2pPz27PTazOzSvMyynOzaxOzOtPTaxOzKrMyqjOzGpMymhPTizOTCpNzSzNTGvMymjMSihCH5BAEAAAAALAAAAAAWABYAAAboQIBwSCwaiYGAYEAgFAqGg/Q4DCASCsTiymgcHAcqQLB4mM+QiIQBppLPcMjkwQ4bB2X4maKgt4sVCHpnFhQTElNFE3mDDxcYGRp2RBuMgxwIHX9EBZZwHh8gCBmTQ52NISEiIyQlpUImng8hHyInKAgprwAqgnC0IKwrLLpGB4wctLYkwy0uuwd9Z8AnJywsLcVFx2YcL7UnJCwwLTEy0GXJoSgrCCwzNDTnxgjeH9UrKzXwNDY36LRGhEOwLx4NHDmgJbh3QoeOgv127EhojEeHDj16pEhRQoZHHzl+QJNCsqTJSXaCAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 fileopen22:file file22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBAQCBCQWDCwaDDwmFPSubPzGhPzCfPy2dOSmZPzKlPzSnPzOlPzKjBQODPzChPzWnPy2bPSmXPyuZOyeXIRSLEQuFEwyHEQqFDQiFCweDKRuPFRSTPT29PTy9Ozq7OTi3Nze3NTW1MzOzMTGxMTCxLy6tLSytKyurDQyNMzKxOTm5OTi5Nza1NTS1MTCvLS2tLSyrKSmpJyenJSWlIyKjHx+fFxeXBwaHKxuPMzKzLy6vIyOjHx6fDw6NPy6dGxubLy+vISChCQmJNza3KyqrBQSFLR2RKSinJyanGxqZAwGBJSSlCwqLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4SFhoeDAYqKiIeLj4wBjQCMhY+NkoiLk5qbhQIDoJyGBAUGBwgEo4MECQoLDA2pDrS1tKQPEAwHERITE77AvxKqhAQNDA8UFRYXFs8YBAQZGqGPxw0RGxwdHR4eHyAhIiMkJSYnKCgpBAYPEhcqHyssLS4kLzAxMjM0NTY3cBA4UCAHBw8gVnhgEcKFjhc7UPDj0cMHAAI/KFgY4YLFio/jRpTYsW8GDyCSCEQw2DChOHIqgsCQSEPIEEEEJFhAoUNECCJEyOk4d6KIyRtGcB7hIJKjixEjHu4oimSGEIs4d8IIUoKECnNB0ElMwkNJJgBLlJBAcQKGiR07KGAURVGViY0mhIwwSTKjr99+THjUoIg0r48hTRIrRtxkiOMhDgrZCQQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== fileprint22:file file22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBFxaXDQyNFxSTPTizOzi1FxORDw2NExKLPTi1Pzy9Pz6/FRWVPz29Pz2/PTy7PTu9OzezPzu5OzavAQCBPzy7PTm3OzazOzKrPTu5FxSRERCRGReXPTq5Pzu7ExGTMS+xKSmpOTKpPTq3JSCDNzSfHRydLyadOzCjOzOtOzSvLyyTMTCxKSipGRiZFROLPz+/KyurJyenJyWnGxmbLSabOzClOzm7LSutJSWlJSSlJyanGxqbNze3OTm5IyGjNTO1Nza3NzW3OTe5IyKjHx6fMzGzMTGxMzOzNTW1IR+hISGhKymrLy6vLSytERGRGxubKyqrLy2vLS2tDQ2NEQ+RASKBAT+BFxeXHRudAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4QBAgOEiYqEAgQFBgcGi5MICQoLmAQDh5OEDA2YCw4ODxARApKUCaGYEAsSCRMUnQysCwoVEhYXGLOLCBCgDqK5GQUXGooCAhscBB0euBUZEAUJvQgIgx8gIR8iCSPiHuIFEREDJCXaANwhJhsnKCnWERcRKiopFCvsBywhQrRwQWGAPAz5EhpQ9wIABRgKYsiYMTEEDQocatiwkUIEP18fbkCAAcMBjhwzdOyQwYNCgBMfKJSgMItBjxs+btwgCSGGjhw/ZoRgQKGZCRMUPgABEgSIkCE3SZok8qNqkR85NtDUEcPIkaVAkCR5SrJBDCVKlmzQ6pCCiRlMTJo4YUH3K5AeMBYYWctW0BOaUH60cBJFypQmII6wyEpFQBVFMSm4UAI3hJUrOGh8oOJrklYKWIromJGDR99Ogz5j4ZGlM+pEnwmBCwQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== filesave22:file file22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBGxqbAQCBLy+vERCRExKTHRydIyKjMTCxFxaXGRiZFRSVFRWVPz6/Nze3Nzm5Pz+/JyanDw+PExOTHR2dMTGxBQWFLSytHx+fISChOzy9Ly6vAQGBJSWlMzKzAwODJSSlHx6fIyOjOTi5DQ2NISGhGxubCwuLOzq7ERGRFxeXNTW1CwqLPT29Dw6PGRmZKSmpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAb/QIBQGBAMj8ikUDAgFAzKKCBwQCQUCcICKh0SEAhGw5EIZAmBrgCxeDQgcDJWyz0GIggJfL+XGwQJRxNgC3yGDwwUFUZDFhdthnwMGAZNQwEZFwQakXANBBQbHIIdERIBnRAOiR4ERx8gsSEMBBmGCyEGG3YGBwcgIr8UCwQHECOgG4xCtRkEJAvBJRklJgkSFBQeJ68hJiEoESkFKiEZIbkGARsLlwEGExENGhorGSkpFAYm66NDLAECpGiBYsUIFA8wLHBBQMWLVkdUCFCwaYVFBOymkVCgYEMgOykEpICBccMBAhhELFigTEqAAgIIwCiQ4eRKDyS6EAlJIAI0EpaudF4iIKDAAn9CkRT5eMROEAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 foldernew22:folder folder22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBNzaTPT2FISCBCQaDPz+BExKBDwmFPSubPzChPzCfPy2dPz6BMzOTAQCBOSmZPzKlPzSnPzOlPzKjBQODPz+rPz+3PzWnPyuZPSmXNyaXPTyhISCLIRSLEQuFEwyHPy2bKRuPFRSTPT29PTy9Ozq7Pz+xJyanDQyNPzGhMzKzOTi3Nza3OTiVBQWFDwqFKxuPOTi5JSSjISChHR2dGRmZFxeXPS2dNTSzNTS1OTm5KSipLS2tLSytKyqpIyKhGRiZNze3NTW1MTGxMTCvLy6tIyKjCQmJMTCxMzOzMzKxJyenHx6fLR2RLy6vJSSlHx+fDw6NLy+vIyOjAwGBGxqZKyurCwuLBQSFJSWlCwqLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4SFhoeIiYqLjI2MAY6HAgOHBJYEhJCDBQaDmgcICQoLB4MGDA0OAQUBDg2cAAcPEBESE6QUuQasFRYVq5SxCRcSCggYGRjIGgYbFs8bHIMHExIJGR0eHx7cB83PFhsDDuTUEyAhIiMjJCQluwEmvsAnKAcp1x4qKyUrLLupWrByxcnFiwQIYIggEaNEiRgBZMyYQaNADRs2REA6cCODBxw5+OnQgWMHjx4+BND4MQOIg1gI0gUREkTHiplDhhApEoCGkRlHBL3I8MEHEhz+WAhJogTJySVMfthwIehAExE5jubAkYQpESc8fOx4AiXKNA8+ekhBgqSpzh5hPHcsmVLjpSAqVZBY6VGkiJMiPQKLnTvjCiEsWU4o3nGC8YksMmT8YCmC6iAXKLRc2cz5yGYtR0JjKWQgEAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 mailforward22:mail mail22 22:photo:22 22:R0lGODlhFgAWAIcAAJR6fIxydIxubIRqbIRmZHxeXHRaXHRWVGxSVGROTFxGRFxCRFQ+PEw6PEw2NEQuLPwCBJR2dLyijPTixPz69Pzq3Pzy3Pzu5PTu7Ozi1LyelOzavPz+/DwqLLyafPTmvPz67Pz29Pzy7LSWlPzmzPz6/LyajPTitOTSzMyurPz25PTatPTi3KyOjPzuxAwqVDQiJHxiZPTetKySlPzqvPz27BQ6bAwmTPTexLyinNzGxDRunPzy5KySjCQ+ZNzq9KTO7JzC3Nzq/Ozu/LzW7FSm1BR6vGSWvFyq1AyGxAxytAx6vBSKxAxSjMyujLSunES+5BSi1ByGvAQCBNzCrOTaxNTOvMS6rKyelCx6rBx6tBQKDOTWvPzu1PTq1OzezAQOHAxGdBROhAQGFPzy1NzOvIRqXLyynOzarPz21Jx2XPTWrLSShAw2XKSCbPzuzAwePAQCDPzyzPzqzPTmxOzWtAwGBKyObOTSrNzGrKyGbOzatEQyNKyCZOzWrOTGpNS2lCweHCQaHCQWFBwSFBQODAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABAALAAAAAAWABYAAAj/AAEEEDCAQAEDBxAkULCAQQMHDyBInBhBwgQKFSpY0HgBQwYNGzh0mDhRAAUPHziACEGBpYgRJDiUGEkSwoCQJk6opNASRQoOFETQJDkggwoOJlYApcCihQuVL2DUhBDjhIqjJmRwwDCDhswaNm5MjYHjKggOOU7o0CGTA9gdYknG2KCCBw8VJVL0uBgihAUfP+CSNGCjsI/DiBPbAMJBsEQbQYQM+UG5smUiRYw0jlvYxhEkSYyIHm1EyRLTTH40EZvAyZPOR4pAmU07ipIkUKQ0mQIhAZUqVq5gKXzkSBYtyLVEyd1ki8QFXLp4+WJFQowbYLJnD5NbzJiJCjaQnhnvpYwZM0/OPFlvQ/f3iQvQpBlvQc0aCWy4VKnCpY0Y5yQxgEYXZFjghgwZUOHGCW90YQEccUwloBwGyjAHHXUoSAMZb0xhx1QOoMHDHSfIwSEOdTjhAQ1d4MFbTQ6Q4MYacrzxhhx04JCHHhvQsMeLJPHRBxpr+LHCGnusgccfgKixQR1ATtTBlDDAEIggggxCCCGFbLGFHVFKZEdAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= mailget22:mail mail22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBBQ6bCQ+ZAwePKTC5Ozu/NTi9GSWvAwSJGSu3JS+5CR+rAQOHPTy/AyKzES23AwOHCw+bOTq/BR6xES+5AwmTBw6ZMTW9Ax6tByi1BRGdAw2XAQCBDQuNDRupKzS9FSm1BR2vBym3EzC7CSGxBROhNTW1Pz+/OTm5NTO1AQGFNzW3Ozq7Ozm7IyKjJyWnMzOzNzq9Nze3OTa5Ly6vCQiJGReZISChKyqrAwqVBRWlOTi5MS6xJSWlNza3OTe5Ly2vGxmbKymrIyGjMzGzISGhKSepCQmJDw6PHR2dJSOlPTy9MTGxLy+vLS2tMzKzLSutMTCxLSytKSipJyenKyurJyanCwqLCwmLCwuLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4IBhgIBA4SLjAABBAUGBwiNlY4FCQoLDJaNAQ0ODwsQnYwREhMUE5ylFYYRFhcYGRgaGxsDHJUdFR4SHyAhEyIjJCUcuo0cJr0nExihxgwoyYscKSnMHicOIw4lKissLdWDHC4vMCu9McYqMjMyNOUANTY3OPEoOTolDCszdrSgwaMcBxs9TMxYOCMHBx8zfPj48QNINQ5BbMBIIUShDIUoTAhR94PHPEEHbQwZckOGjBQviMxYUWQIDCMmdXE4gqRnkiFETAxR8iKFjJU2evZEdmLJkgJIbqS4wXJIUapImj5FtuSEVyRVV1IVi4RIChhEkLVAgcJHEqVwVJUmYdKkiRNkALMRecKECRG/ff8CEQJFCA5kMKJEoUHDCQ/HkB9LmWKECpUeyKoIMSLEyosen0OD7iH2xg1dV7BkqXGlBpbWNTq4Zn2khu0aAAwEAgAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 mail22:mail mail22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBDQyNCwqLCQiJBwaHBQSFAwKDAQCBDw6PPz+/Pz69Pz27PTy7PTy5PTu5PTu3PTu1PTq1PTqzOzmzPzuvOzitPTmvOzivAQGBDw+POzevPz67Pz25Pz23Pzy1PzyzPzqvOTavERCRKSilPz21OTevIR+ZExKTOTi3JyanLS2tPz6/Pz65KyihJSKbMS6lExOTNTW1JSWlJSKZMSylNTOrNTKpFRSVPz29MTCxPTmzKymjIyCdOTWxOzexOTWrBQWFFRWVOzu7MzKxJyalOzatLSulMzKtOzmxOTarFxaXKyqnPTmtIyGdIR+bOzetOzixBweHGRiZOzm3NzWzNzSrOTetGRmZOzizOTexOzm1JSKdGxqbHRydJySdHR2dOzapHx6fKyijOTixCwuLHx+fFxeXERGRDQ2NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4SFhoeIiYqLAQECjwORAwSUBZYFBpkHmwgJCgsMDA0OD6UQERITFBMVFhcVGBkangq1ChsLGxwcHQ0dHR4fICEGIiMSCbS3uLq8wCQUJSYGJygpKhQJKyvLLM4Nwi0uLwUwDQsxMtmeuQveHR8UMzQ1NgU3Dgo41jk6ns0cKOzgYaOHjx9AgjTAUUvIECLZNmxoUISHkSM9KiBJQkCJA4kKEoBQoWJJAiYtmjh5AmVCsCJRpHzckKCCySlUUvBYUqUHDysSPnxIEuXKA5pPRiRwxwFLFhRaIEDYUoEChCcDuECoOWKFuwW7nHkg4WELkw8/BHRRwESpt10dU8SSHevlRxIBX6C0WBE27q8GZMkKbTADjIAwYlb4GLMYShYoPTRo6FGiSJEKPyzMIFMmzJcvXbhwkSLFjJkbQW6cOHNGhAgEAdAsmk27tm0ABgIBACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= mailreplyall22:mail mail22 22:photo:22 22:R0lGODlhFgAWAIcAAJR6fIxydIxubIRqbIRmZHxeXHRaXHRWVGxSVGROTFxGRFxCRFQ+PEw6PEw2NEQuLPwCBLyejPTixPz29PTu3Pzu5Pzy7Ozi1LyelPTavPz+/DwqLPz67PTetPz69ERCRLSWlPTmzPz6/OzexLyajPzqvDw+PDQ2NMyurDQiJPz23PTatJyenAQCBPTevPz25LSajOzq7HxiZPTexPz65JyanBQ6bKSmpBwuTOTi5OzaxBRCdHySvGRiZHx6fBQSFERGRNzq9IyOjHx+fGxqbPzu3BwaHFSq3Aw6XAxKfPzy3Gy63ByWzJzO7Mzi9OzavBRytAx6vCSazGRKTPzy1AQKHBRGdBRyrDy63ES+3Cym1CR6rBwWVAQSLAx+xCyCtBRmnPzuzAQWLAwePPzyzKSCbAQOJByGvOTWvPTmxBQODFQ6PPTWrPzqzOzatAwGBKyObLSWfPTivKyCZEQyNKyGZOzWrOzWtOTSrOTGpNS2lJx2XDQmJCweHCQaHCQWFBwSFBQKDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABAALAAAAAAWABYAAAj/AAEEEDCAQAEDBxAkULCAQQMHDyBInBgggoQJFCpkzGjhAoYMGjZMpMghQgcNFjh4mODhA4gQGkSIHAmBwAgNJEpo8KDSxAkUGjhMSEGz5gUVIiKs2PmBRQudHiwQpUnAxYsXImB0aBqjBcuoU0fKmPGChgUNH2qIqGHjg9u3bicWIFs2rYgbNnDkyGFhb8cccQ3ouJqWQo0dPFr0WMy4h48LFj4gsKriB5AeNngEaSGks+chPnwQOXFAh4oXRYxk9nAEyY7XO2wksWHDx5ATCDIoUXEBsYclTJo4cWJhuIjhSXacSPBEiZLMQY4wgRKluvXqUpyIsDElAxUqVaxcwcGCPQuWLOixaNHCZAsXBU+oqKDSxQqULF6ifNmyn/8VMOtxwcAK36kQRhdJQIFFEmKM4eCDYGyhhYAEkqFEGSuYYcUZLaDxXRpqSNRCEu6twYaFZXTQhgRd2NCCG9918AYELTjoXgNuKAFHB2RQEUYHVbQQRwlUpPHGGFwkyQUEDsgxx4lh9BhCBy2U8UQJcrSg5JIQ0FEHG3bc0QGYK+CRhx57PEGlkhM9sAEffKTQhx9+/AEIIIGoEUgLLRRFR0AAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mailreply22:mail mail22 22:photo:22 22:R0lGODlhFgAWAIcAAJR6fIxydIxubIRqbIRmZHxeXHRaXHRWVGxSVGROTFxGRFxCRFQ+PEw6PEw2NEQuLPwCBMSihPTixPz69PTq5Pzy1Pzu5PTq1Pzy7Pzu7Ozi1LyelPTavPz+/DwqLLSajPTetPz27LSWlPzmzPz6/PTexPz67Pz29OTSzMyurPz25LyajBRCdPzuvDQmJOzexPTevOzq5BQ6bBwuTDQiJHxiZPz23Pz65LyinPzmvBxCbHySvAQCBOTi3OTq9CweHOzaxFSq3Aw6XGy63ByWzJzO7Mzi9OzavNzq9BRytAx6vBR6tPzy3AwOHDy63Ax+xCSazCym1CR6rBwWVOzizAQSLES+3CyCtBRyrBRmnGRKTPzu1MzGtAxKfAQWLAwePPTizMy6nByGvNzWxOzWrNzOtBQKDJR2ZNS2lPTmvBQODPTatKSCbOTaxLyqlAQKHFQ6PPzyzPzqzPTu1PTivOzWtKyObPzuzOTOtLSWfPzqvAwGBKyCZPTWrPTmxNzKrEQyNOzatOTGpJx2XCQaHCQWFBwSFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABAALAAAAAAWABYAAAj/AAEEEDCAQAEDBxAkULCAQQMHDyBInBgggoQJFCpYuIDBQgYNGzh08DCR4oQPIDqEmDBhJQYRIzqQIFkSAoESJCKkDGFiwgkUKTpMwECz5IASKjqsSMlSA4sWQjG4qGnzhYoQSmF0iCFjBgmWGWhQrVHCxg2sOHLo2MGjB0sLYmsWQHq1p4wdPtqemGDhB1UDQFSouKHi7oQgQmSwUMyYxcQDZQWz2EFiCJEiRoyQyLzZyGIIB47YKLwDSRAiSZSoXq1kCRHNLBK8YGKjCYskTp4ogeKkt+8oUaBImZKAAxMmVKrctqL7ihTnz7FkAT5FC4cKFbZwadIFdxcvX8KLss8iJcoUBUcq2KgAJoxyMTy4jCFTxoxEHl2GLyCDncmWM2hUIQMPY2CXhhoTfTEcA2tgVwEba7Thxhs88FdBD/ZB8MUUHMJBRhw2sAGCHBKU4UaFc1RAhxnhcdhhHUzYAUIcFdxRAh4R5KGHinu4OIVEDqTBRx81xhGHHzD8wQYQetDRI4cTAcIHGWT0EQgZa1ApCBqDcBAID1Q94IEHLtBAAyGEFGKIIWqYYQYPYNZkQEAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mailsend22:mail mail22 22:photo:22 22:R0lGODlhFgAWAIcAAIR6fIRydHxubHRqbHRmZGxeXGxaXGRWVFxSVFxOTFRGRExCREw+PEQ6PDw2NDwuLPwCBLSijOzixPz69PTq3PTu5PTu3PTu7OTi1KyelOzavPz+/DQqLPz67LSafOzetPz27Pz29KyajPTmzPz6/NzSzLyurCwiJPz25Ozi3JyOjPzuxBRGbAwSHOzexPz23KSSlPzqvBROdISavBxSdAwaLHRiZLSinNTGxMy+vBxGZNzu9BSGrAwWJMSyrKSSjFy61ETO3BRWfPz65PTqzHTK3ByqzBSWxEzW5AQWJOTWxBRCXOTu9BSOvDzO3ByavBRKbOzaxOzizKSWlCQ2TAQCBJza7BRWdNzSxJSCbMzq9BSOtCSKrAwiPOTavPzy3LymlCySrAwmPFRKTPzy1NTGrPzu1JR+bOzatPzyzCy61ByGpOzWtJyCbPTmvPzuzIS+3FymxCSuzBR6nJyCZOTWvKSObMSujOzivAwKDOTSrNzKrJyGbDwyNOzWrMy2lIx2XBwWFBQSFBQODAwGBAQGBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABAALAAAAAAWABYAAAj/AAEEEDCAQAEDBxAkULCAQQMHDyBInBgggoQJFCpYqMDxAoYMGjZwmEixg4cPGzqA6BBiAggRIzaQGEkSwgAMJCKgnNBhQogSJlKGOFHTpgYUG0TsnJBCxQoSE1i0KErAxYsOJJRuuAAjhkwZM2jUqGnDBQoUHTbciIEjx4YNOmbs4CGjB8kCZlGAALHBx4+YcTcACcJDyFSJBo6iGNIhhQkiG8BOKGLkCBK6SSQisHoWhZIbG5bMYALECI8mTZw8gTL1QJQXZ6VMiUylSpUlVpoYaXLFtm0EGmCjwJLlA2O9MrRsccKlC8kEXr7AdgEmwtkhX2SQ2BIkjBiSYzSQr/nyhUKZLIrJJOcexvlEBV7IvCBjRkmAMzHOaufhxDvJBWiQISAFxUUQQRovJNeEGmu4JxEDbKQhXxsfuFDGGW68IQMcccgxRxUkNRDhC3R8QMQIdZwXQ11JJGFbiB+QYccHaaTxhgt13OFBDGTgkUdRDrhAhx5k2JjGCB/swYcXMXwAYk190OGHHx/4wUaVepTxByAaoPEkSQ5wwMEJZAZipiCDDJIHIYV8OZEdAQEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== nav1downarrow22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBBQSFAQGBDQyNExKTHx6fGxqbFxeXGRiZFRWVDw+PAwKDJSWlOzu7LSytJyenJSSlISGhISChIyOjFxaXDw6PPz+/MTCxLS2tIyKjKSmpKSipJyanAwODDQ2NHRydERCRFRSVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAZzQIBwSCwaj8ikcslsOp/OgHRKlQoCgymRUDAcEIkwYgxWFBYERpHQcDwgEclEQmk8DhWL2kiIXDBwExMNGRoJaUkEEH8bEQ0cGgcWAksEHX8QHBKSHk1sfxMHH5ROBBsOICGkT2wiq1CIULKztLW2t0h2QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 nav1leftarrow22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNAQCBExKTJSSlHx6fAQGBOzu7GxqbJyenPz+/LSytFxaXMTCxGRiZKSmpISGhFxeXISChAwKDFRWVHRydJSWlBQSFERCRIyKjDQ2NIyOjLS2tDw6PBwaHFRSVDw+PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAZ5QIBwSCwaj8ikchgQLJGBgfNZDBAKBirRekBMtYGEYsHIgsWNhOO7tCrShDU18Hg/CJAIG0o4wCUQcksTFBUSCRYSEnpUFxgIGQkJGYyNGggbHBaVjR2QCxEeWkITHQ4IH3tPFwEMA2ajAKUgqlQTTbFEE7W5vUgGQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 nav1rightarrow22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNGReZAQCBMTCxGRiZMzGzOTm5LSytPTy9Pz+/CwqLOTi5Ly6vCwmLMzKzJyanJSSlBQWFKymrIyGjCQeJJyWnISChISGhHx2fKyurDw6PAwODHx6fHRydDw2PERCRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAZ2QIBwSCwaj8hkMRBQKgOCgRMZIBSk06XhEM0SA4iE4uoVLhCMhqLrdSAekMgYO5VM4BQ521mxIC4UFxBWdEkSERYYFxETGQGFSBKCGBEaGRuQSBwdeZaPXpsQCB6YZQMdEI6ZSgMepKusHh+wrCC0rLdlursGQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 nav1uparrow22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBFxeXDw+PMTGxHRudPz+/JSSlLSytIyKjHR2dISChIyGjIyOjLSutLy6vKSepJyanISGhJSOlOzm7Ozu7MzGzKyurJyenDQyNGReZKSmpIR+hCwuLCQiJBwaHBQSFAwKDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAZtQIBwSCwaj8ikcslsOp9QYyAQFQYEAyr0Sihkn1fDAeHVLsOJNELxVaITC0bDUU6GH5AIQ8KYrNtFVxQVFBYWFxgRCREYdUQZGhYEDwgIGxAHCQocCgWOQhmhGR0epR8gqCFTq1Wtrq+wsUt0QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 nav2downarrow22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBAQGBBwaHDQyNExKTHx6fGxqbFxeXGRiZFRSVDw+PAwKDJSWlOzu7LSytJyenJSSlISGhISChIyOjFRWVDw6PPz+/MTCxLS2tGRmZDQ2NAwODJyanKSmpKSipIyKjHRydBQSFERCRExOTFxaXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAasQIBwSCwah4FkQKBsDpoBIqFgOCASCYRWm1AUFgRGkdBwPCARiWRCaTwOFYvYSIhcMOiJpJGZaDYcR0IEHXceEQ0fICEWIoJDhHcQHxIHgI9SEHeVG46YUh8OISOen1INCqWmUnOYTUxQAU9NUlRWWFtbCiRgrYNlZ2lriG8lYUd1khETE24gCZeCkRgeFBAQIAeNn9OTlXKrBJoYnKrcoaPmpmSpq3S+7u50QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 nav2leftarrow22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNAQCBExKTJSSlHx6fAQGBOzu7GxqbJyenPz+/LSytFxaXMTCxGRiZKSmpISGhFxeXISChAwKDFRWVHRydJSWlBQSFERCRIyKjDQ2NIyOjLS2tDw6PBwaHFRSVDw+PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAavQIBwSCwaj8gkMiBYNpeDZzEQXRIKBmPgmtUSDgipcAsWjxOKBaN7Tq+n6EbCIQ3E5+KtQk6gjwl7CX11D3sPBBARTQGFDYeJT2R8EhB0koKUfgATFBUSCRYSEoqcnqCiikMXGAgZCQkZqautr7FiFxoIGxwWqQC4ury+qh2tCxEexMbIRhMdDggfYs7Q0kcXAQwDbELY2txEziBmmx3jSRNMR+nk4e2b70ry80QGQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 nav2rightarrow22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNFxeXAQCBMTGxOzm7CwqLLy2vPTy9Pz+/Ly6vCQiJLSytLS2tLSutOTi5MzGzKSepIyKjJSOlKSmpMzKzJyanIyOjBwaHIyGjISGhJSSlISChBQSFJyenIR+hGxubDw+PHRydHR2dEQ+RHx6fERCRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAa6QIBwSCwaj8hkIIBcJgEBweAYnTYJUmMAa9USClniFtwlGg6IRFhoUKTXwwWj0FB3F46Hwl6UQyISfAB+EROCQgsUFRYSF3yJEIyBaxgWDBkaGRtclQwSHBIbEGEdGx4fGhcOICEDGBsWHBmqIq1CHRIWGRMMIyRTHRy6Er22tyONq8YdJRe0xkIDwr2/QwMfliMmZQADIxasZd4e4UYDIr7c59rc0eVFA+/m0EQD9PDt0flP/P3+BkEAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= nav2uparrow22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBGReZDQyNMTCxHx6fPz+/JyWnKyurHx2fDw6PJSSlISGhIyKjIyGjISChLy6vJyanOTm5PTy9OTi5MzKzLSytKSepMTGxMzGzLS2tLSutKymrHRydCQiJCwmLBwWHAwODLy2vHx+fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAajQIBwSCwaj8RAAMkUBgSDZdP4JBSi06TAcEAkFNLp07BgLLzY5njRcDzO3zB1C4lEGI83Wj58SiYUFRUWdg0XEXFFAwIYGRoWGxwRZQUFHZdgRAObmx4fHiChISFKpVlKWUdPaalOAlasp1sHG4myZGZ7Yltsbgu1mUhjdRF5egmxfQJ/gYOFdrZDi40iFgiSCw8jBQmYcpydn6Ego6WorUwGQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 navback22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAw2VCRGZAxCZGyavExmjHyatOTy9CxihISevPz+/KzO3BRylAw+XAQCBDRWbPz6/FzC3CSuzDyexJzO5Mzq9CxSdAQOFISmxNzu9HTS5BSmxAyexDSuzJTa7Mzu9Kzi7GS21CRmjAQOHHSWtLze7AyWvHzG3BRihAQKFCTO3BS+1AyixBSWvBSOtBSStAQWJBSixDzW5BTC3BSqzBS21CTC1ETW3AQSHEze7BRqlBRmjAQCDBR+pBRefBRSdCH5BAEAAAAALAAAAAAWABYAAAalQIBwSCwaj8ikMqBcMpvHgGAANQYIhWdVGDAcENQtIJBQLBgNx0MQaDuQXcghIplQDhBIxXKJYiAZGhscHR4VHyAhIiNWJBklGhIbJoQnFCcTKIxFKSgbKissJi0mJi4vLiYoMEcXKDEyMzQ1Nje2NisoOEg4KDU5K6g6OwwoKAN9SCOeMmgwz884PEq9PT4NYkPLP9jZQikN3d4AKVrjKePp3gZBACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= navdown22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAw2VCRKZDRSbBxCXJTC1Mzi7Nzq9NTm9Bx2nAQCBNzu9JzG3Hy+1HzG3IzO5BRmjPz6/LTe7Dy61AyStCTC1FzC1AyGrETS3ETC1ETa5BRulAyuzBRylAw+XMTe7Gy+3CSqzAyexBTC3DR+nIS21KTW5Nzu/KzO3FzC3Pz+/ByixEze7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAaRQIBwSCwaj8ikcnkMBAQDgjPAFAYKhsMBkVBUAYEFo+F4QLzVQEQyoVTOX/XBcsHA0+vMRbNBMwkRDhxuHX5GTlIeHh8gISIjFAEeiVRECiQlDAUmgxQjIhwiJHdFlycoKSIUFCEjGiGkRpcqCxYijxorsUezcxYsuoZJsxLAu0qXB7DCTJfHVQrMX9PU1Uh0QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 navforward22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAw2VAQCBBxCXDR+nIS21Aw+XJTC1Nzu/KzO3Pz+/Nzq9Pz6/MTe7KTW5FzC1Nzu9CRKZMzi7IzK3Lzi7LTe7HzG3Gy+3AyuzAyexFzC3DRSbHy+1Dy61CSqzAySvAyStLze7IzO5AyGrETa5ByixBRmjCTC1ETS3BTC3Bx2nAyWvEze7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAaYQIBwSCwaj8hkMqBsBgTN5IAAjRoDBaq1aDggtMuAWDzoJhTgY+CwYLgZDccDwkgXI5IJZVGxXDAZGnR2QxsLHB0PHRgeHyAZDyFfVUQDCyIgIyCPIB+QJCUmlEMBEiInKCQnKSkeKSQeomoqJrUmKiArKSwZsmoCwMEBGCyxo1EGHr3HUQEEvltCBtDRAAbMW0zV29xDBkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== navhome22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBAQCBCQiJNze3ERCROTi5MzGzLy6vDw6PKyqrKyurBQSFGRiZGxqbGRmZISChEQ+RExKTExOTHRydDQyNOTe5FROVLSurCwqLMTCxPT29Pz6/LSutFxeXLyytLSytPz+/JSWlKympPTq7KSipNzW3BwaHHx6fKx2VJRWNHQmBFweDOzq7Ly+vNTW1JxWNLSajPTe1Ny6pKxWJNTS1IyOjJRmbPTi3OzKrNSSXMSGVHQiBHx+fJSSlPzy9IxOVOzWxOSyjNSCPLxeDJyWnIRGTOTGtMxmDLRWBHwqBIxGTLRSDDQuNNSunKxKBGwyNMSafMxqHMReDKRGDPTu9LxuPLxaDJQ+DIR+hGQqNIQyBGQiBNTO1EQKBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4QBAYSIiYQCAwQCiokEhwACBQYHBAiQhAiHlQYJCgkEC5uCkp8MDQ4NDwylmwgQlgQRERIEBBOkmxQVBgQWFwUFFxEEDLyJGAUZtQoFGhsFHLYdyoOVHsEf0SAbIAUex8mwlAUhtSIFG+3uIyTWvAIGJMEkJe76GyXbEeWUBJg4USKaBhQpVKzYoIFFiwYUBBJa8MAFCw0vYMSQMWOhBhoTKCQSUKMEiw02buDIoWOHBg0GeIhEFKAHDR8afgAJImSIioYliMws1MPkhiJGchxBkmTDCBo1hg4KQMTiBiUyhBxZ8pNFiR5MEtU0WqSJVidJNDyNKraHC5xPNKBEkTLlJ5WvUgWNvfikyhArV34+7ZEXQAAsB2iUyHLlihYtW0pwOYAFgyJDmDNr7jIIWiAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== navup22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAw2VAQCBHSWtBRmjAQOHISmxNzu9BSmxBRihHyatPz6/Lze7CTO3BSixHTS5BTC3DzW5ByyzPz+/OTy9AyexEze7ByixGyavKzO3FzC3AyWvBS+1BR+pAQKFCRGZExmjCxihBRylCSuzBSWvBS21BSOtBRSdAw+XAxCZDyexDSyzCTC1JzO5JTa7DSuzETW3BRqlAQWJDRWbOT2/Mzq9HzG3JzS5Kzi7BSStGS21CxSdCRmjAQOFAQSHAAAACH5BAEAAAAALAAAAAAWABYAAAaeQIBwSCwaj8ikcqkMCJjHwIBQgBIDhgMiUbUGFAtGw0GFfheHByQi4S6/E8pDUoFYLm5kAEPJaBAVGxIcER0JHlEfICEiIxUkGyUmIgknKIhXASkonCorgSwmKQGcKE9IAi0uLxUwMTJWMzQ1NiYwBLBQHws1N7avXgs4NjkcCblMATU6KhvGyG87PAnUKV1MAj0+2zIFp1bg4eJJdkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== playeject22:play play22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNAwKDJSWlFRSVBQSFKymrOzq7HRydERCRPz+/MzGzISGhJyenKSmpGxqbJyWnJSOlKSepLy2vIyOjGRiZPTu9IyGjLSutFxaXExOTHx2fGReZAQCBAQGBBwaHCQiJLSytKyurJSSlFxeXNze3LS2tIyKjFxWXHRudAwGDBQOFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAa1QIBwSCwaj8ikcqkMCJjHwIBQgBIDhgMiUbVKFQsGItBdBhpgh4PxIJvRC8cA4oiMy8bvQhJhMAYTFBVOURAWEw0QFxcMERAYCBluVxobDxkVHJocmBwEGgmEQx0dHh0CpKmkH6odVlanBR8FtAIFtiCkSB0LISEiGCIGIxAPDySuRwIOBwrOzwoHJRHJRh0jJgMj2gMnERQUCNVFHQQoCBvo6CkICATjRB0qp7b1K6qv+foyQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 playend22:play play22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNFxeXAQCBMTCxGReZBQSFOzm7AwKDKymrJSSlFRSVCwqLLy6vPTy9OTe5Ozq7CQiJLSytOTi5BwaHPz+/HRydMzKzKSepJSOlKSipJyanIyGjIyKjKyurISGhMzGzJyWnHR2dISChIyOjLSutDw+PERCRHx6fJSWlIR+hJyenGRmZHx2fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAa6QIBwSCwaj8ikMBBQKgOCgRMZIBSkxYHWoDVWD9EigpBQLLBERsPxCA8NDUhjgTBGJJNGG02RVBQWdUV3FxgZe0IGfoAGdhoXGxwdiAYef4FGFBoeHB8dGSBRihUhIo1FBhkbIyMkJRYmAwYal4JEBh2RChIWJ1IIGxUZFqdECCgkHR6wWAYpFR2YWSobvL5vFgfDaEMDIivMRBEsD9HcQgMWvecDLB0tZ0btsfJa9vLXU/X6/P3+b0EAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= playpause22:play play22 22:photo:22 22:R0lGODlhFgAWAIQAAPwCBAQCBAwODMTCxKSmpJSWlFRSVAQGBBwaHLSutOzq7Ly6vCQeJPz+/Hx2fBQWFGxubLSytJSOlBQOFAwKDJSSlJyWnIyOjHRydNze3GRiZAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAWBICCOZGmeaKqubOumQSDEgRjPMSoMRGEcol3vh0IkFAtDDWBEKlGMRKPgEIii0yrqIS1ArADu9KuLNCSOSdCMVp8ohEZFC4DL6SaBpXGh6/l4JX8XZACDhXkYCn1LAoqMUBAZEhBLDJKUSyYBGmhPAJyemiU0NDaloy+qq6ytI8whACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= playstart22:play play22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNAQCBExOTAwKDAQGBJSSlHx+fBQSFMTCxKymrFRSVOzu7GxqbLSytLy6vJyanPz+/GReZBwaHHRydKSepKSipGRiZJyWnAwODLSutKSmpISChPTu9ISGhFxaXJSWlIyGjJSOlERCRIyKjDw2PIyOjLy2vOzm7Dw6PLS2tCQmJOTe5GxmbDQ2NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAa7QIBwSCwaj8ik0hgQLJGBgbMoqBIKU2LAcMgOEQmFYeEFbBmNMgDhYDwWBC0k4pCoJ46IgRIXBioRCRYXamwRGBQIfgaBFhiERhkaenxmCoEbBhyQRYaIGVsdghgem4UWegcEBB8UHhsgIaZGBBgRIpUIIxQhChginEQIIBEklWslFyYnBsFfFCi4WQgpFBwqFxNGKxcsxl4IAS0NZEYCF3vlwgEfUuZV8JEuI2pPAARN9kcE9fr+SwaCAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 playstop22:play play22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBAwKDBQSFBwaHCQmJJSSlISChJSOlJSWlGxqbGRiZNTS1PTy9Pz+/Ozm7OTi5FRSVIyKjOTe5MTCxIR+hExOTHR2dLy6vLSytLy2vHRydFxWXIyGjIyOjPz2/FRWVHx6fExKTMzOzJyanKSmpKyqrKSipAQGBLSutHx2fDw6PAwODAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAa1QIBwSCwaj8ikcslsAgKCAWEQjQ4KgSwyYDAcugZEQqFYYJECA6PhaLcfEEUkgJZAGJB8fkKpWOhHAxcOGBQZGBoaGQgbHIBGAhUOGR0SBxISBh4Xf0iCHxQSlRIIXhsgj0UCIaCXmJgHGyKpRJ+hmB5dHQqOaCENIx0epBIkBhdzngoPGCQlJifQJBvJRygRKRcKGxcXGypys1srEREc5SLnICLiR1koLFVUWfRO9vf4+UwyQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 textblock22:text text22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAImhI+py30Bo5zBWUWzvNzo33GfFl5jVlonlTrr1DbvFi9vjeeNUQAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textbold22:text text22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAIxhI+py+0Powm0VnknjVkH2AEhE45LZ55Wqn6e65TsMc5eYosbksswubJIhsSiccgvAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 textcenter22:text text22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAImhI+py30Bo5zBWUbz3Sh7yIWfFHKjVl4nmFrr1Lpr7LwkjeeIUQAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textitalic22:text text22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAImhI+py+0P4wqUSlQvttrkDnyaOHIdeaGRupplAIauVM3xjeeOUQAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textleft22:text text22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAImhI+pyw0Bo5zB2UXz3Sp7yG2fFJajVjonmIor2TJvfL0wjecIXQAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textright22:text text22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAImhI+py30Bo5zBWUfz3SZ7yIXdF4kWqZkbCqoMO7kXLC+wVOe6YRQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== text22:text text22 22:photo:22 22:R0lGODlhFgAWAIQAAPwCBAQCBBwaHAwKDBQSFLy+vLS2tJSWlBQWFKyqrFRSVCwqLDQyNNTS1GxqbFxaXJyanIyOjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAVcICCOZGmKQSoMaZsShBsQBdAapHvgaIDUqUPJlRjSbAoT0fRDKgODRbF0PLUYjZO2F2Bst9evNix+dsvDlGKK5jraudQb7qbX6a2HEJ+ycyF+LRE8ZTI+fX5oGCEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textunder22:text text22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAIvhI+py+0PowmUnhpeVVnb1DkbCI1I2JhX+Z0sOr2cTHpwK7a4rUr+hAnufsTirwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== viewchoose22:view view22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBAQCBFRSVExKTDQyNPz69PTq5Pz+/OzaxOTKpAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARTEMhJq70466Cl+AMxBVwnFIVRAmQHCIeBrC1L3tQgJ/SaEbeeC1PLBHE2ybFI9A1HzstHEIK6YCmhDTmBybQaHYJn7QC5zKeytIQe1+pKNE6P2yMAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== viewdetailed22:view view22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBFRSVExKTDQyNPz+/Pz69PTq5AQCBOzaxOTKpAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAQ+EMhJq7046817+MLQUQFRGMc4lQaSAkcMx3QltMmrDrSu/sCgEPgJhIiFk89DaL1qPRnlhsgBebWhdstVESIAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== viewicon22:view view22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBFRSVExKTDQyNPz69PTq5AQCBPz+/OzaxOTKpAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARWEMhJq7046z2DF0PlBeAVEERhiKhqHgWyUgEsX0KczFOO7JeBYciTCImc5ITIXDKHyqhU9AnRqq9UEVDTvmLbGhin2/qAliOUot5OLc81IO5+2+8WewQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== viewmag-22:view view22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBBQSFJyanKy2tLzCxHyChNTa3Nzq7Nz29Nzy9Mzy9MTu9OTy9Nzi5Oz6/OT29MTi5Kzi7NTy9KTm7JzW3ITO1Lzq7IzW5HzK1LS+vMTq7Jze7ITW3GTCzGS+zLTS1MzOzLzq9Kzm7Jze5ITW5HTS3FS2vLze5EzCzEyyvEyutJTa5NTu9ITa5FTK1ESirLTm7Mzi5FS6xEy2vESerESmtFSutESmrKyqrAz+/Dw+RAzi3ASutHRydAQCBAAAACH5BAEAAAAALAAAAAAWABYAAAbKQIBQGCgWh8jksCgYEAaCozIZKBgOiIRiwSgEpstCw/HYQiKRhBcMCBgQDodkMaFU0t9pQHCIyy0TFxgYEVF6GQ4LCQkaERscHR4RH3lUIAkWCyEiIyQlHiYjEJVIAQQJJ2gjJSUoKSorlHoCLBQcHC0lLikvHjCGejEiHBgeMjM0NRwPpFQFDBHFNjceHAjAYFWoI7cnCVE4OWxtex8QH1EBOjs4zUpGUjw6Pe3j2fP19u/47vrq9P3s/avno2BBf/MCClSob4iBIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 viewmag22:view view22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBBQSFJyanKy2tLzCxHyChNTa3Nzq7Nz29Nzy9Mzy9MTu9OTy9Nzi5Oz6/OT29MTi5Kzi7NTy9KTm7JzW3ITO1Lzq7IzW5HzK1LS+vMTq7Jze7ITW3GTCzGS+zLTS1MzOzLzq9Kzm7Jze5ITW5HTS3FS2vLze5EzCzEyyvEyutJTa5NTu9ITa5FTK1ESirLTm7Mzi5FS6xEy2vESerESmtFSutESmrKyqrAz+/Dw+RAzi3ASutHRydAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAbIQIBQGCgWh8jksCgYEAaCozIZKBgOiIRiwSgEpstCw/HYQiKRhBcMCBgQDodkMaFU0t9pQHCIyy0TFxgYEVF6GQ4LCQkaERscHR4RH3lUIAkWCyEiIyQlHiYjEJVIAQQJJ2gjJSUoKSorlHoCLBQcHC0lLikvHjCGejEiHBgeMjM0NRwPpFQFDBHFNjceHAjAYFWoI7cnCVE4OWxtex8QH1EBOjs4zUpGUjw6Pe3j2fP19u/47vrq9P3s/cunr9S8gAIRFhTCLAgAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== viewmag+22:view view22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBBQSFJyanKy2tLzCxHyChNTa3Nzq7Nz29Nzy9Mzy9MTu9OTy9Nzi5Oz6/OT29MTi5Kzi7NTy9KTm7JzW3ITO1Lzq7IzW5HzK1LS+vMTq7Jze7ITW3GTCzGS+zLTS1MzOzLzq9Kzm7Jze5ITW5HTS3FS2vLze5EzCzEyyvEyutJTa5NTu9ITa5FTK1ESirLTm7Mzi5FS6xEy2vESerESmtFSutESmrKyqrAz+/Dw+RAzi3ASutHRydAQCBAAAACH5BAEAAAAALAAAAAAWABYAAAbQQIBQGCgWh8jksCgYEAaCozIZKBgOiIRiwSgEpstCw/HYQiKRhBcMCBgQDodkMaFU0t9pQHCIyy0TFxgYEVF6GQ4LCQkaERscHR4RH3lUIAkWCyEiIyQlHiYjEJVIAQQJJ2gjJSUoKSorlHoCLBQcHC0lLikvHjCGejEiHBgeMjM0NRwPpFQFDBHFNjceHAjAYFWoI7cnCVE4OWxtex8QH1EBOjs4zUpGUjw6Pe3j2fP19u/4zT766vRI+fvHD4CPgwcJ9qg0UB85JA0dDjEQBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 viewmulticolumn22:view view22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBFRSVExKTDQyNPz+/Pz69PTq5AQCBOzaxOTKpAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARTEMhJq7046813+MJQfUF4BURhHGO6noSBsEcNoDJtS4KcsJQe4ncZ1HYT47HDbDqfUAnJRJmKLIGCCjjJbmE5wBI3EyOFxKCPS1EiJW52dE6vZyIAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== viewtext22:view view22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAIkhI+py+0Po2ShBlOxzbP7n2yaJoLm+ZTcxqHuC6hXzML2HVEFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= viewtree22:view view22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBAQCBFRSVExKTDQyNPz+/Pz69Pzu5PTq5OzaxBQOFOzKpFRWVFxWXOzexPTexCH5BAEAAAAALAAAAAAWABYAAARPEMhJq704g6A779kHCORAgNskFMYhakE8FkjyBcoWv+JwJItXaELYCTFHlCSpZKKcoB5jYHpOGgUadLKbIRw3jhEzQDyCSuI4zW673yhDBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 ================================================ FILE: ext/tk/sample/tkextlib/ICONS/tkIcons-sample.kde ================================================ 1downarrow-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIYhI+py+0PUZi0zmTtypflV0VdRJbm6fgFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= 1leftarrow-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAP///wAAACH5BAEAAAAALAAAAAAQABAAAAIdhI+pyxqdwoNGTmgvy9px/IEWBWRkKZ2oWrKu4hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== 1rightarrow-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIdhI+pyxCtwoNHTmpvy3rxnnwQh1mUI52o6rCu6hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== 1uparrow-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIYhI+py+0PWwhxzmetzFpxnnxfRJbmufgFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= 2downarrow-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIfhI+pq+EPXYpxUckoO3AjbF3dJwahllXe6AFgC8d+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 2leftarrow-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAImhI+pyxf5VohmSlsxmpjTzAHeN5ak6UHpqKRi2GpwvH3Q3eT64RcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== 2rightarrow-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAImhI+pq5HOAjQyVnqfhHue7oAaKH5kiW0AmnLqaHomkj02g+e6XwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== 2uparrow-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIghI+pyxfR0HsRzNnuXVqn3mVQZWFRyIDjp65Ga5Ly4hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== abs-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBIQChAQCBBQSFCH5BAEAAAAALAAAAAAQABAAAAIwhI95ocn2GlySTiME1iC+DIKdNWxANl4HaqWr055cy6Bs6dahmJsyXVFFJJ7gyF8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= airbrush-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/AQCBPzCxMQCBIQCBPz+/MTCxKSipFxaXDQyNISChAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARUEMhJZxCjanBH3hY2EFJgVt0YcEW7liLxBoVxzPHL2msqUzSeT2c5HBC5jQmROKgAhCgKEVBQo6YAqVQIHBQ93ZbmBWt+nDJRgiYMvmuoThWXT/wRACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= attach-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBPz+/AQCBAAAACH5BAEAAAAALAAAAAAQABAAAAI2hAOCxg2h0nJHyEshi9HpxU1GOCLdZoKpQ15nibUoprKp9lh2oucUxsBRXsJh4Hjs/QTMpr8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= back-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBBRSdBRObCQ2TBxObISevAQCBNzu/BRGZPz6/FzC3Pz+/HTS5ByyzJze7Mzq9ITC3AQWLAyWvBSavFyuxAwaLAwSHBRafBSOrDzW5AyixCS61ETW3CzG1AQeLAweLAxefBSStEze7CSWtCyatBSCnBRWfAwmPBRWdByixAQSHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZiQIBwSCwah4HjUTBQFgkFg3MoKBykU0QhoUAIAuAksbpgNByPxQMSGVsVDYlkIqdUiJYLJqORbDgcHRseRR8gISIaEyMkGCVYRBEmeyAnlgaQkSgpmU4RAZ1OKqFOpFNGfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== blend-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBARCRAQCBASChATCxATCBASCBAAAACH5BAEAAAAALAAAAAAQABAAAANHCLrc/izISauYI5NduvlXMIjEQBSnUYCYxnmsSJrouhqh6J4wLo0mWuqWy5heN58seBrGdEdeMgQsNW0ggXbL7Qog4HDDnwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== bookmark_add-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBCwqLLSytLy6vERGRFRWVDQyNKSipAQCBMTGxKyurISChJSSlJyanHR2dIyKjPz+xISGhPz+BGxubMTCBHx+fPz+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVfICACwWieY1CibCCsrBkMb0zchTEcNYsIiYHiwIOdEAvigdFQGE0Ix4NBbSAgsWjk+jBIAlcUYrJASChnSXZSoUDelKfoKpFALJA61ueGI2IAZmhogGFmCGGAgXsifiEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== bookmark_folder-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBExKTBQWFOTi5OTm5CwqLPz+/PTy9Ozu7FRSVNza3PT29KSmpAQ6XARqnNTS1JyenGRiZJTa9Mzq9JzO5MTGxIyOjKSipFxeXMzOzDw+PDy65FTC7HS2zMzm7MzKzKSenASq5Bx+rBSGrFyqzLSytDw6NAR+zBRejBxqnLSyrERCRIyqvDRujKyurMTCvOzq7AQ2VDQ2NNze3KyqrGxqbLS2tLy6vCwuLDw6PAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAawQIAQEBAMh4GjcEAoCAQGYSCpDBwQiQJBEVhQj1YGo1DoNqZTx8PhODAWZUik0ZAkHRNKZe0IWC4RGBkBGhsOHB0eFR97bBdcICEbAA4iIyQlioxrGhEmJ5QoKSoqJCOZiw4rGixEYi0uo6WYDi8wkwAsCTFksLIuMi+tADMLNAsLEBAgLSMpMjW4RCc2MCAgFjA3MA4R0kgzGS84Ny8vDqBKSDkKETUOOurqAQagfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== bookmark-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBCwqLLSytLy+vERGRFRWVDQ2NKSmpAQCBKyurMTGxISChJyanHR2dIyKjGxubHRydGRmZIyOjFxeXHx6fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVbICACwWieY1CibCCsrBkMb0zchSEcNYskCtqBBzshFkOGQFk0IRqOxqPBODRHCMhCQKteRc9FI/KQWGOIyFYgkDC+gPR4snCcfRGKOIKIgSMQE31+f4OEYCZ+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 bookmark_toolbar-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBCwqLLSytLy6vERGRFRWVDQ2NKSipAQCBKyqrMTCxKyurISGhJSSlJyanHR2dIyKjGxubIyOjISChHx+fPz+/MTGxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVpICACwWieY1CibCCsrBkMb0zchTEcNYskCsXiwIOdEAzioeFIGE2IB6RBbT5HiAhEIpk6Y9kJBMJoHK6iLIU8kZxFlXhlIp/XJ4BKUIGoWIJ9f3x5e32FeoB5goGAfokTCJEIFJKTlX4hACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= bottom-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBBRObCRKZBxCXAwyTKTK3Ozy/NTm9GSivAQWHNzu/FzC3IzO5CySrAQOHAyuzETS3CSWtAyOtETa5Aw2VLze7ByWtBy61BSavAxWdBRCXAwqPAQCBDR+nKTe7FS+1Eze7ByixBRmjPz+/AyexAyixAQKFBRqjAQGDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZhQIBwSCwaj0hAYCkYEJLKguGASEADigWj4bgaHpBINykwSCYRa5HCFFQsF0xGo9lwhpSOwfORYC4gISJ3RAQdIyQYJSAlImNrh4uNJkl5CoKUUBQnjlB4KFAcoqOknkh+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 brace-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBIQChAQCBBQSFCH5BAEAAAAALAAAAAAQABAAAAI2hI9pEXq8mnsNzggsEMJwbHGimFXS4HUfpKUIq3QJ036vuakyWvbjCJLYbL2WgyW5WIw3g78AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= brackets-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBIQChAQCBBQSFCH5BAEAAAAALAAAAAAQABAAAAIzhI8JwXocllMxTlSREGY/2W2iJ1nAEAJklpCfeXAJG8sY6JGowY7jW0sBL0NiqTGBAPwFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= charset-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAInhI+pqxH8kFsvsgtm1vvEaoBZSH6j5FSaRY4me4pyq1ochuf6fvgFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= colorize-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIQAAPz+BAQCBPz+/MTCxISC/AQChMTC/ERCBPyqXMRaBATCxASChPzerKSipMT+/MQCBATCBASCBARCRISChMT+xDQyNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVnICAGgWieZyCQKGuqZPkGgwyv60gONRDvNlqt9Pv5BgRCYVj8IQ3L4qE4KFiZzRiP90MgEj+FYtGLIRiJQaMxUDjIxFoi8YBAIo3FQjIJ7iAUERNqDTI6PBGJfT0oFVpsMSgzkSh+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 colorpicker-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBARCBDQyNMT+xATCBASCBPz+/FxaXISChAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAQ/EMhJZRCjahBIMdlmeV8gBl3xCabWGarBihwBz+eB2O0WHIFEp1f5BU1EilFI4wCZtGWy+JwWj00OynrNTvwRACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= completion-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+/Ly+vHx+fAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM/CLrcGjBKCYK4+NoMs+jWIBIdZ50QuWGgMASD+oGnO5beR+x7UE3AyGKV0wxnpeSxyDoGN74Hszl8QhxYhj8BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= configure-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBISChGRmZMTCxKSipLS2tHx6fPz+/OTm5FxaXOzu7DQyNMzOzAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAReEMhAq7wYBDECKVSGBcbRfcEYauSZXgFCrEEXgDCSeIEyzKSXZoBYVCoJVIqBGByKu0Cy8QHxmgNngWCkGgqsGWFseu6oMApoXHAWhWnKrv0UqeYDe0YO10/6fhJ+EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 connect_creating-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBPz+BMTCBISCBAQCBPz+/MTCxMTGxISChFxaXMzGzKSipAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARaEMhJZbihUiz60FPnfaA0iBpBVGdHEYWxToEoSHBRHHM9AgSEQRcj+AYkYAJxIPKQFUJiOdTJQFIDU6dYzKKFhTCM+E5g4mXaDAyrlogEG+DGTecA7wsP8EcAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= connect_established-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+/KSipDQyNMTCxMTGxISChFxaXMzGzAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARaEMhJZxCjgsAtDtUlCOA1gJQ4kl/IDatAoF7xxkS6GgEBr6jAobCyBX42SQBxMOx6A8MhiGASR8YDgrYsNEeJ0zaEGZY7uoH2oB6nOUwtbdLaVOeTUwo/8UcAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= connect_no-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBPz+BMTCBAQCBERCBPz+/MTCxMTGxISChFxaXMzGzKSipAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARPEMhJq704axBEHoPUEdhQGMNYFuwxkKInDYjBniEnwMCQIIebSzXx/WwsFK+YMABZikWuYlrUCtZpEYv4WRPaHhb064YB41kCfJFSQBh/BAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 contents2-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBAQCBDyKhDSChGSinFSWlEySjCx+fHSqrGSipESOjCR6dKTGxISytIy6vFSalBxydAQeHHyurAxubARmZCR+fBx2dDyKjPz+/MzKzLTS1IyOjAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVkICCOZGmKQXCWqTCoa0oUxnDAZIrsSaEMCxwgwGggHI3E47eA4AKRogQxcy0mFFhgEW3MCoOKBZsdUrhFxSUMyT7P3bAlhcnk4BoHvb4RBuABGHwpJn+BGX1CLAGJKzmKjpF+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 contents-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBExCNGSenHRmVCwqJPTq1GxeTHRqXPz+/DwyJPTq3Ny+lOzexPzy5HRuVFSWlNzClPTexIR2ZOzevPz29AxqbPz6/IR+ZDyKjPTy5IyCZPz27ESOjJySfDSGhPTm1PTizJSKdDSChNzWxMS2nIR6ZKyijNzOrOzWtIx+bLSifNTGrMy6lIx+ZCRWRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaeQEAAQCwWBYJiYEAoGAFIw0E5QCScAIVikUgQqNargtFwdB9KSDhxiEjMiUlgHlB3E48IpdKdLCxzEAQJFxUTblwJGH9zGQgVGhUbbhxdG4wBHQQaCwaTb10emB8EBiAhInp8CSKYIw8kDRSfDiUmJ4xCIxMoKSoRJRMrJyy5uhMtLisTLCQkC8bHGBMj1daARgEjLyN03kPZc09FfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== contexthelp-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQChAQCBAAAACH5BAEAAAAALAAAAAAQABAAAAIzhH+hIeiwVmtOUcjENaxqjVjhByaBSZZVl24Y1V6iEVMzkD4bqD700bshgh1fzwd0IfwFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= crop-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBMT+xATCBASCBISChPz+/AAAACH5BAEAAAAALAAAAAAQABAAAAM0CLrc/iG+FsQgYapKbp7c4IFCZ2FQOQQE6oSl9Koxabrz/eVDDXat3atAlEEMSKFmyfAnAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 decrypted-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaVAQCBKSipDQyNMTCxISChFxaLFxSJExGHEQ+FCQiDBwaDBweDGxiLHxyNHRuPIR+RIyGZJSSfFxaRGxmLJyaXNzWpNTOnMzGnMS+jJSKTGReLKyqjPTu1NzarLSufKyibJySXIyGVGxiNFxaXLSytPT29Ozu7OTi5NTS1KyurGxqVCQeDJSSjLS2tNTW1KSmpGRiLKSebOzuzJSOXExONExGLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaVQIBwOAwYA8SkMCAYOAnKYiFAIAQGyOgVCggYuEovVxztMpdnwAGRSCgUCwOjIeQ6HpCIZDKRUNYMRBUWF4UYGRoWGxyBRR0eHxgaICEiIyR0QyUmJygpKgUrAxMsLUQlKyieoKIuEAunK52fBS8DLiywQySpnjC1Mbi6QjIzNBeSIBY1EQfDQgosLAEUNjY3Co1DfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== down-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBBRObCRKZBxCXAwyTKTK3Ozy/NTm9GSivAQWHNzu/FzC3IzO5CySrAQOHAyuzETS3CSWtAyOtETa5Aw2VLze7ByWtBy61BSavAxWdBRCXAwqPAQCBDR+nKTe7FS+1Eze7ByixBRmjPz+/AyexAyixAQKFBRqjAQGDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZeQIBwSCwaj0hAYCkYEJLKguGASEADigWj4bgaHpBINykwSCYRa5HCFFQsF0xGo9lwhpSOwfORYC4gISJ3RAQdIyQYJSAlImNrh4uNJkl5CoKUUBQnjlB4KJ6hokN+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 editclear-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBPz+/ISChCH5BAEAAAAALAAAAAAQABAAAAIuhI+pm+EPnwmi2msDoLgLzQWDV4HlSJof6qki+W0n7LKdCpdyrm/Rr2EIhwp/AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 editcopy-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAFxaXPwCBNze3GxubERCRPz+/Pz29Pzy5OTe3LS2tAQCBPTq3PTizLyulKyqrOzexLymhLy+vPTy9OzWvLyifMTCxHRydOzSrLyihPz6/OTKpLyabOzu7OTm5MS2nMSqjKSipDQyNJyenLSytOTi5NTS1JyanNTW1JSWlLy6vKyurAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAAaUQIBwCAgYj0eAYLkcEJBIZWFaGBie0ICUOnBiowKq4YBIKIbJcGG8YDQUDoHTKGU/HhBFpHrVIiQHbQ8TFAoVBRZeSoEIgxcYhhkSAmZKghcXGht6EhwdDmcRHh4NHxgbmwkcCwIgZwqwsbAhCR0CCiIKWQAOCQkjJAolJrpQShK2wicoxVEJKSMqDiAizLuysiF+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 editcut-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBPz+/ISChCH5BAEAAAAALAAAAAAQABAAAAIwhI9pwaHrGFRBNDdPlYB3bWHQ1YXPtYln+iCpmqCDp6El7Ylsp6ssR1uYSKuW0V8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= editdelete-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbPT29GxubMzOzDQyNIyKjHRydERCROTi3IyKhPz29Ox6bPzCxPzy7PTm3NS6rIQCBMxCNPTq3PTi1PTezMyynPTm1PTaxOzWvMyulOzGrMymhPTq5OzOtNTKxNTOzNTCtNS+rMSehAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaKQAAgQCwahcihYMkcBAiBpLJApRoOBWgyIKhSEQkFgrBAcr1URiPhKAsDD3QB8RhA3FM0IlLHnyUTVBMSFBUWfl0XGBMTGBcZGodmcQWKjpAbHIgIBY2LHRoempOdjooTGx8giIOPFYofISJ+DyMXI6AfFySyfiUmJSUnKBYcICIpfgELzM3OZX5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= edit-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxaVMR+RPzKjNze3AQCBMR6RPzGjPyODPz+/MzOzPyKDPyKBPz29OTWzPyGDPyGBOx6BOza1OR2BKROBNSOXKRKBBwOBOzu7PTWxPzizOySZPyCDFxaXOy2lNRyRMxmJCQOBPTm1OzStPTKrMR+XIRWLFxGNCQSBDQyNIRSNDQuJERGRLyqlNzSvIx6ZKRuVEw6LLSyrLymhKSShBwaFFROTJyWjMS+vNzW1OTazNzKrHRqXOzezOTOpPTq3OzWvOTStLyedMS+rLy2pMSynMSulAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAewgAAAAYSFhoQCA4IBBI2OjgUGBwiLBAmXlpcKkgsMlZcJBA0JDpIPEBGVjwkSBgOnExSfmBIVBxAMExYXswkYGRobHLq8gh2PHhoeHyAWIYKzIiMkJSYnKCnQg5YNHtQqKywtK9qMBC4vMDEBMjIz2dCMDTQ1Njc4OToz5PEEOzw3ZPToMcLHO23HfogQ0QMIkCA+hPBbhAPHECJFjMyYIUQIvEUpUqwQOXKkSEF+AgEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== editpaste-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBCQiFHRqNIx+LFxSBDw6PKSaRPz+/NTOjKyiZDw+POTe3AQCBIR2HPT23Ly2dIR2FMTCxLS2tCQmJKSipExGLHx+fHR2dJyenJyanJSSlERCRGRmZNTW1ERGRNze3GxubBweHMzOzJSWlIyOjHRydPz29MzKzIyKjPTq3Ly2rLy+vISGhPzy5LymhISChPTizOzWvKyurPTexOzSrDQyNHx6fCwuLGxqbOzKpMSabAQGBMS2nLyulMSidAAAACH5BAEAAAAALAAAAAAQABAAAAa7QIBQGBAMCMMkoMAsGA6IBKFZECoWDEbDgXgYIIRIRDJZMigUMKHCrlgul7KCgcloNJu8fsMpFzoZgRoeHx0fHwsgGyEACiIjIxokhAeVByUmG0snkpIbC5YHF4obBREkJCgon5YmKQsqDAUrqiwsrAcmLSkpLrISLC/CrCYOKTAxvgUywhYvGx+6xzM0vjUSNhdvn7zIMdUMNxw4IByKH8fINDk6DABZWTsbYzw9Li4+7UoAHvD+4X6CAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 editshred-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbGxubMzOzPz69DQyNIyKjERCRPz29PT29OTi3IyKhPz27PTu5PTy5Pz6/Pzy7PTq3OzexLyqlPTm1PTizOzavLyqjOzWvOzaxLyifOzizOTOpAQCBOzezAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaEQAAgQCwahcihYMkcBAiBpLJApRoOBWgyIKhWEQkFYYHkeqkMxKFBFpq9jgdkEGlPqwrJhCIY2N8FFRYUFxcYGX9dgRKEGhiHiYEOhBcbGBwdiQEOARcBGwEeAZllAgEUnQEfoQEgmp4hrCKtrwEYsrRlTiMBJAG8syN/IyMAxMXHSH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= edittrash-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBKSipFxaXPz+/MTCxISChDQyNCH5BAEAAAAALAAAAAAQABAAAANQCKrRsZA5EYZ7K5BdugkdlQVCsRHdoGLMRwqw8UWvIKvGwTICQdmGgY7W+92GEJKPdNwBlMYgMlNkSp3QgOxKXAKFWE0UHHlObI3yyFH2JwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== encrypted-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaVAQCBKSipDQyNMTCxISChFxaLFxSJEQ+FExGHCQiDBwaDGxiLHxyNHRuPIR+TIyGZJSSfFxaRFxWJGRiLJyaXNzWpNTOnMzGnLy2hJSKTGReLKyqjPTu1NzarMS+jLSyfKyibJySXIyGVCQeDLSytPT29Ozu7OTi5NTS1KyurJSSjGxqVFxaXLS2tKSebOzuzLSufJSOXExGLGRiTExONAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaTQIBwGCgGhkhkQDBoEpLKQoBACAyOUID1qTVwoQGvMPxNFgVjAxp6QCQUicSCwVgkG44HJCKRRCYUCAxIFRYXhxgZGhYbHINEHR4fGCAhIiMkFSVKJicoKSoFKwMsLZtDLison6GjLA92qCueoAUvpC2xQhWqrLYDErmEMDEXlDIwMxAHukI0NS01EzY2NAmPAH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= eraser-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAAT+BMTC/AQCBISC/AQChPzCxPz+/MQCBIQCBAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAQ/EMhJZRA120GwnsEgdh8QiqKXnSi5oqNKsbFWGEYrT8Vx4JydpOf7uSrEIkIISPqWtkIS+pH2qCUptgTYavwRACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= exec-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBEQ+PBwaHLy+vMzOzGxqZHx+dKyqnKymnIR+dNTW1MTCxJyOfLySVMSaVMSeVMSebJyWhOSmTOSuVNyubPS+dKSWhHR2dDw+PIyKhNymTNSaTEw+JOy+fPzSnLSyrISChDQyNDw6NMzKzLy2rMyiXGxWLAQCBHRqTPzerNy+lMzGvCwuLAwKDDQyLJyWlNy6jPTGhGxaRGxiRPz2vOTStLy2tFRSTMS+tOzGlPzmtPTixGRiXCwqJLy6tOTWxPTq1MzKxMzOxISCfHRybLS2tHR2bCQmJExORMTCvMTGxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAeogACCg4SFhoIBAYeDAogDA4oAjYQCBAEFBgcICQUBCpODAQsMDQ4PEBGWhgUMDxITFBUUFheDGAYZCA0aGxwcHR4QHwwgISILIyQlGiYnJygpKisEIywALS4vMBoxMjM0KTU2LC2ENzg5wDo6Owo8hT0+Lx8/OztAQR9C1oInQz4FMBAp8sEIhgIEMpwYdASJCwAYkihR5OLGkUUAMmTACK8Hx4+C/AQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= exit-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBDQyNHR2dCH5BAEAAAAALAAAAAAQABAAAAI4hI+pFrHb3nEg1iWiDiINCwYDko0V9XUTda6I1TIsUMpGinyzbB6ZeGuoEr+GUDL4CXqSphPhLwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== fileclose-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBCQiJBwaHAQCBDQyNDw6PFxaXFRSVERGRCwqLAwODGRiZHx6fPz+/GxqbAwKDCQmJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVaICCOZGmeqBgEwjCkRGEcSKK4JrEcBrMgAdeLVDg0GguGsYEbBQyGYyN6FDoPDIf0+LCKBIgetQERDgGDBGIpNY8GioAU0m6KXFw883w3+/l9f4AkfimGIn4hACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= filefind-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBCQmJDw+PBQSFAQCBMza3NTm5MTW1HyChOT29Ozq7MTq7Kze5Kzm7Oz6/NTy9Iza5GzGzKzS1Nzy9Nz29Kzq9HTGzHTK1Lza3AwKDLzu9JTi7HTW5GTCzITO1Mzq7Hza5FTK1ESyvHzKzKzW3DQyNDyqtDw6PIzW5HzGzAT+/Dw+RKyurNTOzMTGxMS+tJSGdATCxHRydLSqpLymnLSijBweHERCRNze3Pz69PTy9Oze1OTSxOTGrMSqlLy+vPTu5OzSvMymjNTGvNS+tMy2pMyunMSefAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAe4gACCAAECA4OIiAIEBQYHBAKJgwIICQoLDA0IkZIECQ4PCxARCwSSAxITFA8VEBYXGBmJAQYLGhUbHB0eH7KIGRIMEBAgISIjJKaIJQQLFxERIialkieUGigpKRoIBCqJKyyLBwvJAioEyoICLS4v6QQwMQQyLuqLli8zNDU2BCf1lN3AkUPHDh49fAQAAEnGD1MCCALZEaSHkIUMBQS8wWMIkSJGhBzBmFEGgRsBUqpMiSgdAD+BAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 filenew-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbPz6/GxubNTKxDQyNIyKhHRydERCROTi3PT29Pz29Pzy7PTq3My2pPzu5PTi1NS+rPTq5PTezMyynPTm1Pz69OzWvMyqjPTu5PTm3OzOtOzGrMSehNTCtNS+tAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ/QAAgQCwWhUhhQMBkDgKEQFIpKFgLhgMiOl1eC4iEYrtIer+MxsFRRgYe3wLkMWC0qXE5/T6sfiMSExR8Z1YRFRMWF4RwYIcYFhkahH6AGBuRk2YCCBwSFZgdHR6UgB8gkR0hpJsSGCAZoiEiI4QKtyQlFBQeHrVmC8HCw21+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 fileopen-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBOSmZPzSnPzChPzGhPyuZEwyHExOTFROTFxaVFRSTMSGTPT29Ozu7Nze3NTS1MzKzMTGxLy6vLS2tLSytDQyNOTm5OTi5Ly+vKyqrKSmpIyOjLR+RNTW1MzOzJyenGxqZBweHKSinJSWlExKTMTCxKyurGxubBQSFAwKDJyanERCRERGRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaRQIBwGCgGhkhkEWA8HpNPojFJFU6ryitTiw0IBgRBkxsYFAiGtDodDZwPCERCEV8sEk0CI9FoOB4BEBESExQVFgEEBw8PFxcYEBIZGhscCEwdCxAPGA8eHxkUGyAhIkwHEREQqxEZExUjJCVWCBAZJhEmGRUnoygpQioZGxsnxsQrHByzQiJxz3EsLSwWpkJ+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 fileprint-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFRKNAQCBPz+/MTCxExKLPTq5Pz29Pz6/OzezPT29PTu7PTy7NzClOzm1PTu5LSabJyanPTm3FxaXOzCjOTKrOzi1OzaxOTSvJyenGRmZLyyTKSipDQyNERCROTi5Hx+fMzKzJSSlIyOjISChLS2tAT+BDw6PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaYQIBwKAwIBMTkMDAYEApIpVBgOCAOg4RRGlAoEAuGIdGITgWOq4LxcCQgZkEkIHksHgYJOR6ZQCgVFhYJFxgTBVMZihoCfxUYDWUbUBGKGREcjBoQEB2TAB4CAx+Vl5WMhyACHiEhH6IfIiMktCQgE0cZJQStr6O2t6EARxO6vK6iEx4dZsMCxbsmBB4nzUTEutVSSUdmfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== filequickprint-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/AQCBPz+/ISChERCBDQyNPz+xPz+BFxaXPwCBMTCxAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARWEMhAq5UYBME7D9kkBMNGjqHmeWBoDhwsEIS7coVx1NhbCrmdzROk9SyU4GEJ2twECISOUNokEopsVrobKCgCrZa73IHFYy4VyZ5WNIO4vBhvse8gfwQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== filesave-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBFRSVMTCxKyurPz+/JSWlFRWVJyenKSipJSSlOzu7ISChISGhIyOjHR2dJyanIyKjHx6fMzOzGRiZAQGBFxeXGRmZHRydGxqbAwODOTm5ExOTERGRExKTHx+fGxubNza3Dw+PDQ2NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaAQIAQECgOj0jBgFAoBpBHpaFAbRqRh0F1a30ClAhuNZHwZhViqgFhJizSjIZXQCAoHOKHYw5xRBiAElQTFAoVQgINFBYXGBkZFxYHGRqIDBQbmRwdHgKeH2YgHpmkIR0HAhFeTqSZIhwCFIdIrBsjAgcPXlBERZ4Gu7xCRZVDfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== fill-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/AQCBMT+xASCBMQCBATCBPwCBIQCBISCBAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARSEMhJq50hXBvE0JsUEMXwhYFBmOeVDsVqgpS6luRc32RR6hLCTSCQ/VqEwwDhK5Z+Ao3wEPAViL6BR6PSZKyCa6uLAbcAZEznLDHQ1BZDiOKPAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 filter-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBKSipMTCxISChMTGxAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM3CLrcDiGGt6IQQ7pI8PjSVHUeqFVBNxRfFjXSZYqwENoUNFx4rve+wI6WEwKLQ5/CSCw2lQ9/AgAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 find-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBCQmJDw+PAwODAQCBMza3NTm5MTW1ISChOTy9Mzq7Kze5Kzm7HyChOT29Oz6/Nzy9Lzu7JTW3GTCzERCRLza3NTy9Nz29Mzu9Kzq9Ize7HTGzHzK1AwKDMTq7JTi7HTW5HzGzKzS1IzW5Hza5FTK1ESyvLTa3HTK1GzG1DyqtLzu9IzK1AT+/Dw+RAQGBATCxHRydMTCxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaSQIAQEBAMhkjBUEAoGA4EJXKJSCQUC0ZDCmg0hATHAxKRTCIEYYMiMFYsF0xGs+FUOl0BJRAweCIRHyATIRhpRAEAHSILIyQgJSYhJ4dIBBEoISkmKiuVSQgRIyEsEQgELVNCLgQVCiJRLQSfli9pMAQxMrRcQ1G6tAC9AL+7al+qxALACG1Kw8oxBGt7yWBpfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== finish-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAwyTBRObAw2VDR+nAQCBCRKZOzy/KTe7Pz+/KTK3Nzu/Lze7FS+1AyexAyuzBSavAyOtBSmzOTy/BRqjNTm9IzO5ETS3ETa5By61AyixByixBRmjAQGDBxCXGSivCySrCSWtBTC3AQOHAQWHAxWdEze7AQKFBRCXAwqPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZtQIBwSCwahYGjUjBQGgWE5LCgNBwITSFVKOgKDAZEIqodChSLw4HRcIyTW4Dg0HhAIhGIZEIJxA0VFhcYGRAaGBscHXEeHyAhIQ4iiBwjAHEBJCMjJCUmiSdlRyigU0oolURxRSmrTpevsUN+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 flag-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAASC/AQCBMTCxPz+/MQCBPzCxPwCBAAAACH5BAEAAAAALAAAAAAQABAAAAM5CLrcruG9QCULokqKR44NJQykQGgXSRaEcYJLsLLu6wSFoRMvCuk1kO9ni8GMt6MForQMl89NxJ8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= folder_new-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBPz+hPz+BOSmZPzSnPzChFxaXMTCBPyuZPz+xPzGhEwyHExOTPz+/MSGTFROTPT29OTm5KyurDQyNNza3Ozq5Nze3LR+RLy+vJyenMzKzNTS1Ly6vJSWlFRSTMzOzMTGxLS2tKSmpGxubBQSFAwKDKSinJyanIyOjCQiJERCRERGRBweHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaNQIBwSCwaj8ikcokMCIqBaEDoBAQG1meAUDAQpIcBQoy1dg2JdBqhECgQ1IWB0WgcBIOBwIHXBwwPEBEREhIBbG4IExR/DBUVFhIXV2NjDVYYDY8SFU4ZVxpVAQwbGxynGxkdTh6XVh8gGSGzGSITIxokJUImGSMTwLcnKCkprgAqDSt1zCssKxQtQ35BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= forward-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAwyTBRObAw2VDR+nCRKZOzy/KTe7Pz+/KTK3Nzu/Lze7FS+1AyexAyuzBSavAyOtBSmzOTy/BRqjNTm9IzO5ETS3ETa5By61AyixByixBRmjAQGDBxCXGSivCySrCSWtBTC3AQOHAQWHAxWdEze7AQKFBRCXAwqPAQCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZjQIBwSCwahYGjUjBQGgWEpHNYMBCaT4G2UDggos+EwmBYMBpf6VBgYDgeEMgjIpmoAQVKxXLBPDIXGhscRB0eHyAgDSGBGyJFASMiIiMkJYImUwAnmJqbjp4AKCmhAKSlTn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= frac-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBAQGBIQChCH5BAEAAAAALAAAAAAQABAAAAInhA9hig0SAmQOxeouPrFTzHzbCAzmiZ4k2S1ryHKsoo3tptXg3fgFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= frameprint-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFRKNAQCBPz+/MTCxExKLPTq5Pz29Pz6/OzezPTy7PT29NzClPTu7PTu5PTm3LSabJyanOzi1FxaXOzCjOTKrOTSvJyenGRmZLyyTKSipDQyNERCROTi5MzKzIyOjLS2tAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaPQIBwKAwIBMTkMDAYEApIpVBgOCAOg4RRGlAsEAqFIcGITqnWRcPxSEDMgkhAonA4DO3yMD6BUCoSCYIWEwVTF4gYAhAMFRUMZRlQEYgXERqKGBAQG5IAHAIDHYiUEUcDpwIcHh4doR0fH02zqAIXIASsrqi0TQBHE7e5HqG0Zr8CwSC9qFJHxbRSU7W1fkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== gear-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBISChMTCxDQyNFxaXKSipPz+/CH5BAEAAAAALAAAAAAQABAAAANdCLobwbAFMciLwBFSihBEFHSG8QnmpQQEBX6loI5G5QTlcMgrZSmEmsGxKqRWNV3hMrFlBtDoA1eTEaKHJdMYhR6+gxkF++UMGbiDzvDVioyHAJSHcchuGLQq4k8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= gohome-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBDw6PBQWFCQiJAQCBFxeXMTCxJyanDwyLDQqLFRSVLSytJSSlISChCQmJERGRFRWVGxubKSmpJyenGRmZLy+vOzq7OTi5Ly6vGRiZPTy9Pz6/OTm5ExOTPT29BwaHNza3NS6tJRqRGQqBNy6pIyKjDwGBPTe1JSWlDQyNOTGrNRiBGwmBIRaLNymdLxWBHxGFNySXCwqLKyqrNR6LKxGBNTS1NTW1Jw+BEweDDQ2NAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaoQIBwCAgIiEjAgAAoGA6I5DBBUBgWjIZDqnwYGgVIoTGQQgyRiGRCgZCR1nTFcsFkHm9hBp2paDYbHAsZHW9eERkYGh4eGx4ag3gfSgMTIBshIiMkGyAlCCZTEpciJyQjGxcoKUQBEhcbIiorLB4XEltDrhcaLS4vtbcJra8bMDHAGrcyrTMXHjA0NSypEsO6EzY3IzU4OdoTzK0BCAkDMgkIOjJlAH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= goto-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBEQCBAAAACH5BAEAAAAALAAAAAAQABAAAAIohI8RyKciVnMwTlrlDfkm5QFgaHBWMo0lp22dZ57wO8vpGrLk2iJ+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 help-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQ6XAQCBCyCvARSjAQ+ZGSm1ARCbEyWzESOxIy63ARalAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAQ/EEgQqhUz00GEJx2WFUY3BZw5HYh4cu6mSkEy06B72LHkiYFST0NRLIaa4I0oQyZhTKInSq2eAlaaMAuYEv0RACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= history-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBEQ2LEw6POTSrOzWtNS2lAQCBOzatPTm3PTq3MyyjEw+NOzm1Pz29Pz+/Pz6/Pz27FRGPFxKRPTu3Pzy7Pz69Pz67KSGbPzy3Pzu3PTizPzu1Pzq1PTmzOzaxPTixPTmxOzWvOTOtKyWdOTGpOTStNS+nIRmVLymhNzCnOzavLyefAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaHQIBwGCgOj0jBgFAwGJDJAyJBUDihwgWj4XhAqhEJNDKhVLwUSUDyPJIrlgYlLSG0hYELhgLJTBJOd1kaGxgYHB0egkQfHBwgHyEigkUBIwMkBwcEJSZ3ARYWJCcnKCYpJJ5HAQUqFhSjJysoKItOCgehJBISI4tCtyERa79HTrx2WEiBUH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= idea-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+BPzerPz+xPyqXPz+/ISChFxaXKSipDQyNAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARMEEgZap14BjG6CJkmEMVQCF+4mQPBpthWtuYJxkJJGK6dbQRCgMBB3XCDzQamMhpDGlvuCFUyoQDLBUsJHBDUKuKQCKsUCIVZtc34IwAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 int-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBIQChAQCBAwODAQGBAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMwCKqx/iw0CNukzuJ8d1yCAAziIyliCKjck1ZuaV4igZ1r+raongE4j8YT6QiJC38CACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= locationbar_erase-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBPz+/AAAACH5BAEAAAAALAAAAAAQABAAAAIshI+py40Bo1SywgSFiDq+oG3hZHDhVpUmagFrl7pgN3oqPNuqpe+8Awwi/AUAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== lock-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaVAQCBKSipDQyNMTCxISChFxaLFxSJEQ+FExGHCQiDBwaDGxiLHxyNHRuPIR+TIyGZJSSfFxaRFxWJGRiLJyaXNzWpNTOnMzGnLy2hJSKTGReLKyqjPTu1NzarMS+jLSyfKyibJySXIyGVCQeDLSytPT29Ozu7OTi5NTS1KyurJSSjGxqVFxaXLS2tKSebOzuzLSufJSOXExGLGRiTExONAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaTQIBwGCgGhkhkQDBoEpLKQoBACAyOUID1qTVwoQGvMPxNFgVjAxp6QCQUicSCwVgkG44HJCKRRCYUCAxIFRYXhxgZGhYbHINEHR4fGCAhIiMkFSVKJicoKSoFKwMsLZtDLison6GjLA92qCueoAUvpC2xQhWqrLYDErmEMDEXlDIwMxAHukI0NS01EzY2NAmPAH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= lsub-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBIQChAAAACH5BAEAAAAALAAAAAAQABAAAAImhI+pFu2+QpxKVppsxkh3fnhh9DyGcC6IwLbqir4HK58tLcfx6xcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== lsup-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBIQChAQCBAAAACH5BAEAAAAALAAAAAAQABAAAAIlhI95YawYonwp0uoukFO7rCXCSJKPcKYKuqqii7BvS892XJZ+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 mail_forward-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIYAAIx+fIRydHxubHxmZGxiXHRmZFxOTFxGPFxKTPwCBLymlMy+pOze3PTq3PTu5Pzy7LSmnOTaxOzm5LyqlNzOtPz69Pz27MzCtLyqrPT27IRubPzuzNTGvNTCxLSelPz25Bw+ZFxKPPzy1Pz65LyupBxKdCxWfPTm1Pz23LyinBxGbGzO5DRafBxWfBxajCymxHTS5BxSdBxKbFTK3EzG1CSGvCyKvCSSxCSavGTO5GRaVPzqzFzK5EzG3BSCtAwiPGxaVPTivPzy3NzKpBxObCRefBxqlPTmzJR2bKyahAwyRPzmvOTOpKyObNS+nPz21AQOFKyOfPzuxAQCBGRORLSadPzyzLymjMy2lOzetDwuJFRCPEw6NEQ6LEQyLEQ6NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAkALAAAAAAQABAAAAfhgAABAgIDBAQFBgcIBwmOCQIKCwwNDg8OEBESjY8CDBMUFRYVFxgZDJyOGhsPChwVHR4fFSAhjwkaIiMOJBQQDRUVJSa3GicoHw4pEA8SGSorLI8tLtQu19gqLzDECTEyMzQ14zY1Njc3ODkqCTo7MjIxNCs5PD03PjctPwlAQUIihhBpQbCIihtG+CUocASFkAhIkogQ8kFJwkcFlogIkoRJEydPnkBR6GiAxiQLgiiIIkXElFQJqESoMsRKkAhXqkhhApNKFSxZggTJ4nHIEJhaDhzYwoVLFy1avHyB6ScQACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= mail_generic-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBGxaVOTe1Oze3OTWxOTWvNzStNzKpEQ6LOTezPz+/Pzy7Pz69Pz27Pz25Pz21PzuzPzuxEQyLLyinLSmnPz67Pz23LSafKyObDwuJMzCtLSelPzy1My6nLymjNTCxLyqnPzq1LyihKyOfOzavOzetEQ6NPTq3NzOtLymnNTGxJR2bOTOpPTivNTGvLymlKSShKyahEw+NOTe3PTm1Pzu1Pzy3FRCPPz65LSadFxGPOzm3PzqzPTmzPzmvEw6NCH5BAEAAAAALAAAAAAQABAAAAaqQIBwSCwaj8ikMhloOp/QpmAgqAoIhELBUDgcEIGEYrFgNBoLx+IBiRwkgQnFoWAwKhWLhX3BZAILGhsCDXgODhwdGB5vgAofICBlDiEiIx4kJSYBJ2UoEykqHSMrLC0nLWAnFS4UCycvMAcEMR0RLTIBMwaSahw0NTYtFwclNwEdLws4eoc2DxwQOR06ASk7PBAhIRE9Pj0tLSUY1T8I5gjn6Qgy7D8SfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mail_get-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAxKdBRSfCyGvFSm1BxKfCSWzCyWzBRCXCRKfBwuRAQGDDw6PHy23Cym1CSSxByCxBxunBQSFKyurMTCxExihNza3NTW1JSSlMzKzFxaXLS2tNze3KSipCQmJGxmbNTS1KSepLy2vISGhJSWlHx+fERGRPz6/IyKjDw+POzq7JyenMzOzKSmpCwuLDQyNIyOjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaeQIBwGBAIAsOkUjAgFJRQQMHgjC4PBIEVgAh4D4aEYrGAMhINxwPyiCgYSsmEUmk82grLRZJkYCgXaAEKFxYZcEISGhsZFxwFeY0WHR5CDB8dGCAXG5shGxQicBIMpSMUGxgTGSQlpQwSJicnEwwdI7gdKAwTsykpKiobr8QMKxeHDBcsGRvOzxsT0i0uL9HSHdkT2ZkoMJXF4a8AfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mail_replyall-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIYAAIx+fIRubHxubHxqbHxmZGxeXHRmZGROTFRCPFxKTFxGPPwCBLymlMy6pOTa1PTq3PTu5Pz27Dw+POzi3PTm1OTWvPz25FRSVERCRLympPzuzPTu7NTGvFxaXKSmpPzu1Pz65Hx6fHxqZPzq1Pz23HR2dBw+ZHx+fISChJSWlDQmJHRydCxWfBxGbJyenExKTHRiXPzqzPzy3CQmJDRafGTO5ExOTERKTGxWVCRSfHTS5CymxBxajBxWfPTmvPzy1CyixCSaxCySxDSaxDSWxDSSvDyaxGS21PTmzPz21AwiPBRejCSavByGtCSezEzG3FzK5FzG3GzO5FTK3CQ2bPTixBxqlCRefBxSdBxSfBx2nCQ+dHxmXPzmvLSafAwmRAwyRPzyzDw6POzavNzKpAQOFPzuxBwWTBw2ZGRORLyWdMy2lOzetPTivAQCBKyObOTOpAweNBwWVEQyLEw2LEQ2LDwuJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAsALAAAAAAQABAAAAf4gAABAgMEBQUGBwgJCguOCwEMDQ4PEBESDA4TjY8DFAwVERYXGBkRm4+QGhsMHB0eGB8bDpyOARogEBceIRgXv8COIiMkGB4lJSYnIcwoKb/DGyoXKywtKS4pHinMLzAxJDIzNDUtNjcv6B0hLzgfMh85OjstPDw99zwd7T4/LTVAgggZQqSIECNHevSAgSSJkiVMmjh5AiWKlClAiFARUeVHFSVWmLS40gNLlh5agGzh0kWDlwZfrIDREKaCAjEqrFA5MMYLmTAxlJTxYoZMozNozqRRs4ZNmy5s3LwhA0dBnDNn5MxBoAABnTp17IitowDrmQV+AgEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mail_reply-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIYAAIx+fIRubHxubHxqbHxmZGxeXHRmZGROTEw+NFxKTFxGPPwCBLymnMy6pOTa1PTm1Pzy7LymlOzi3HxqZOTWvPz69Pz25My+tLympFRGRHxuZPzu1LymjNTGvNTCxBw+ZPz23PzuzPz65PTu5NzOtCxWfBxKbPzq1DRafGTO5BxGbPzy9HTS5CymxBxajHRiXPzqzCyixCSaxCySxDSaxDSSvGS21GxWVAwmRBRejCSavByGtCSezEzG3FzK5FzG3CQ2bPzuxAwiPBxqlBxKdCRefBxWfBxSdBxSfBx2nCQ+dPzy1CRqlAwyRDQmJPTmvPTixLSafOTOpAQOFPz21BwWTBw2ZPzmvNS6nPTivAQCBAweNBwWVNzKpPzyzLyihGRORLyWdMy2lOzetKyObEQyLEw6NEw2LDwuJEQ2LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAsALAAAAAAQABAAAAfqgAABAgMEBQUGBwgJCguOCwEMDQ4PEJYRDhKNjxMPDBQVFhAXGBUSGY8LGhsQHB0VHh8gFQ6bjgEhIiMMJCUmFbS2CwMnG6IoKSorI7WpEycWFiUsLSou1yXXji8wFiopMTIzNDUz4zbZNxsbODk6Ozw9Pj8pPzEzQDdB60JDOkRFjBw5giRJDCWdlmxwIIRJExAWKDRyMgTIiydLoESRImQKlSUSF1SxUoXAlSBRsGSJoCVICIlbqlThcoBClC5eYFD4EiVIFwUyqywAE0ZMlqNjpJDpIkUBl0dlFChAYOZMmTJoyqQR5icQACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= mail_send-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIYAAIx+fIRubHxubHxqbHxmZGxeXHRmZGROTFRCPFxKTFxGPPwCBHxqZLyqlMy6pOze3PTq3PTu5Pz27Pzy7LyinOTaxOzi3Ozq3LymlOTOtPz69Pzy5My+tLympPzqzNTGvLSelPzy3BxGbBQ6VPzuzPz65LyupNzOtPz+/GzO5BRejPzq1Pz23LymjHTS5CyixCSavBxqlPz25LymnGTO5CymxCSaxByGtHRiXPzy1CySxCSezGxWVPzuxKyOhMy6nDSaxEzG3PTivNzKpKyOfPzu1FzK5PTmzJR2ZLyihLSWfKyObOzmzPzmvDyaxOzavLSafGRORMy2lOzetDwuJEw6NEw2LEQyLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAsALAAAAAAQABAAAAfUgAABAgMEBQUGBwgJCguOCwwNDg8QERITFBUWjY8DFxgZGhsaHB0aD5yODB4TGB+kICEaIiOPCwEkJRcmJyYPKCIpKrWqKywTmC0SIi4vMDHEDCsyMg8zEyI0NTY3z7U4Hhs5Mx+0IyI6OyPrIzw9Gys+PxIy2EBBxAs8Qjk5Q0RFWFxAZySfgSMsilRAkiRECHQ08hHgJ0TJkCU/mECU2ISEkowUlpAQ4QTfowNPoAzJIeRJCyjm8kVRIkWIzSkXhwxJtYAKgp9VrFi5QoWKFZ5+AgEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== matrix-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBIQChCH5BAEAAAAALAAAAAAQABAAAAIrhI9pwQHt4Jru2Vsjna919lXKeEimh6UZp1lrCEvkfILyirOby3q1OEv4CwAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 misc-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBISChMTCxDQyNFxaXKSipPz+/CH5BAEAAAAALAAAAAAQABAAAANdCLobwbAFMciLwBFSihBEFHSG8QnmpQQEBX6loI5G5QTlcMgrZSmEmsGxKqRWNV3hMrFlBtDoA1eTEaKHJdMYhR6+gxkF++UMGbiDzvDVioyHAJSHcchuGLQq4k8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= move-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAImhA8RyKja2HtRrmrxNfDszm3JMpXmiULg6Hyto4kYO49Tfdc04xcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== news_subscribe-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/ERCBDQyNAQCBPz+/FxaXIQCBMQCBKSipMTCxATCBMT+xISChASCBAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARsEEgZxLxYDlJsvsJGDN0nFQRhpKR3DSJxrGMphYQgpDI9WLhdTtjjAFApXZI30m2UQwICVigcEzzolKAYIAIFBAKbQjQX3YGGISZvFtzFQr1uDxT4PH0yYE8FCg0/Jn0MAwsNOiY3IQMBEn4RACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= news_unsubscribe-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/ERCBDQyNAQCBPz+/FxaXIQCBMQCBMTCxPzCxKSipAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARiEEgZxLxYDlJsvsJGDN0nFQRhpKR3DSJxrGMphYQgpDI9WLhdTtjjAFApXZI30m2UwxjsiOApB4kNLFtQKKopxeCQxR4GAJIXPCInzmhN9zvCljNq8ZvswmzhZHEfOhpofhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== next-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBFwyXAQCBOze9BwCHNx21LQCvPSi5NRi7AAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAQ3EMhJqwUhAMG7DQOxdVwFFuI1nYZIethwIK0aFwjtwrfh15cAYUjcvWyvkm1Z4TGfkyN0avFHAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 ok-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBMT+xATCBASCBARCBAQCBEQCBAAAACH5BAEAAAAALAAAAAAQABAAAAM2CLrc/itAF8RkdVyVye4FpzUgJwijORCGUhDDOZbLG6Nd2xjwibIQ2y80sRGIl4IBuWk6Af4EACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= openterm-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXFRSVPz+/PT29OTm5OTi5DQyNDw+PERGRExKTHx+fISChIyKjHRydFxeXDQ2NCQmJBQSFAQCBERCRMTGxHR2dGRiZExOTDw6PCQiJAwODCwuLFRWVOzu7BweHAwKDCwqLHx6fBQWFGxqbGRmZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAanQIBwSCwKAwKkMslEAgSDqDRKqBYKhkNgcDggEorkMrDQchkNhuOhgEQkk0l5S2lUGpYLJqPZTAwMHB0DCmhqAW0Rfh5zAxgOkBcCFAcfIBMECxwBBAEPFw8dChkhcBMDDAcdnQqtFKSWcQMimx4dGRkQBxGxsg6bBQEawx8jl3GnJFoFHRNXVVNRJYIFDAsL1tgiDiQXFx0HABwcXeQH5OjkRutEfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== paintbrush-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBMTC/AQChPz+/MTCxKSipDQyNCH5BAEAAAAALAAAAAAQABAAAAM7CLrMIS2qN2Sj1U4xugaYZxFE1wUaURQnKpFBYQTuFRiyXDsCd8y7RYhmCQ2IkiHywmkFN84ibfrxJwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== paren-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBIQChAQCBBQSFCH5BAEAAAAALAAAAAAQABAAAAI3hI+JEQq8mnvyzSOhEWJ3CgLcOILV4IlfUx1cwirfYiEvXL83arANSer5UipM5tIzXjRCh8ZfAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 pencil-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/IQCBMQCBPzCxAQCBPz+/MTCxISChDQyNKSipEQCBAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARDEMhJZRBD1H2z3lMnjKCFjUJQimOgcmcbELCXzjXq0hV785WCQYcDFQjDXeloMByKG6YTAdwIDAlqSZJSVFeKLcUfAQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 player_eject-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIbhI+py+0R3IFQUtruXVqn3kkWyIARR4rqKvoFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= player_end-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIjhI+py8Eb3ENRggrxjRnrVIWcIoYd91FaenysMU6wTNeLXwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== player_pause-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIfhI+py+1vgoxzyUCxrZd18ClfmIyVyJ1lqkHuC0N+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 player_start-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIjhI+pyxudwlNyguqkqRZh3h0gl43hpoElqlHt9UKw7NG27BcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== player_stop-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIahI+py+1vgpySUWpvXXqrHmSaeJEYhKYq6hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== previous-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBFwyXOzC7PTq9OTK7IQyhBwCHNRi7LQCzPSi5IQ6jLwKzORy7AAAAAAAACH5BAEAAAAALAAAAAAQABAAAAQ8EMhJKwg4W5o1EGAIbt8wEERhHJ0mIEmiLAH5IYxi1JcnvTOeTdDYcVo1gfHY+hxs0IkvSpV2qtgswB8BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= prod-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBIQChCH5BAEAAAAALAAAAAAQABAAAAIihI+py50Bo4SKHlsDwk9fn21gJzIcV37miKpuZ0nOTBt+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 queue-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBMTC/Pz+/CH5BAEAAAAALAAAAAAQABAAAAI5hI+pFrEahGgPtCinS2GMlknU0Xkflm2l6YEiw8aRGssTXLe3lZsznvuRViwholEcLZCfynGT8BcAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= redo-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBBxOHBxSHBRGHKzCtNzu3MTSzBQ2FLzSxIzCjCSKFCyeHDzCLAxGHAwuFDSCNBxKLES+NHSmfBQ6FBxWJAQaDAQWFAw+HDSyLJzOnISyjMTexAQOBAwmDAw+FMzizAQODDymNKzWrAQKDAwaDEy6TFTGTFSyXDyKTAQCBAwiFBQyHAwSFAwmHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ2QIBwSCwaj0hAICBICgcDQsEgaB4PiIRiW0AEiE3sdsFgcK2CBsCheEAcjgYjoigwJRM2pUK0XDAKGRobDRwKHUcegAsfExUdIEcVCgshImojfEUkCiUmJygHACkqHEQpqKkpogAgK5FOQywtprFDKRwptrZ+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 reload-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBCRaJBxWJBxOHBRGBCxeLLTatCSKFCymJBQ6BAwmBNzu3AQCBAQOBCRSJKzWrGy+ZDy+NBxSHFSmTBxWHLTWtCyaHCSSFCx6PETKNBQ+FBwaHCRKJMTixLy6vExOTKyqrFxaXDQyNDw+PBQSFHx6fCwuLJyenDQ2NISChLSytJSSlFxeXAwODCQmJBweHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaBQIBQGBAMBALCcCksGA4IQkJBUDIDC6gVwGhshY5HlMn9DiCRL1MyYE8iiapaSKlALBdMRiPckDkdeXt9HgxkGhWDXB4fH4ZMGnxcICEiI45kQiQkDCUmJZskmUIiJyiPQgyoQwwpH35LqqgMKiEjq5obqh8rLCMtowAkLqovuH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= remove-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAASC/PwCBMQCBEQCBIQCBAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMuCLrc/hCGFyYLQjQsquLDQ2ScEEJjZkYfyQKlJa2j7AQnMM7NfucLze1FLD78CQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 revert-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIQAAAQCBPwCBPz+/PTizCQeHDQyNBweHAQGBAwKBDQ2NPzu5PTi3ERGRCQiJHR2dPTi1CwqLPz6/Mya/Mxm/GQCzFRWVGRmZAwODFxeXExOTExKTERCRBQWFMTCxKSipMzKzCH5BAEAAAEALAAAAAAQABAAAAV9ICCOQWkGIiqsQloCKCqy7UC8MC4URSsMhsDBNWOJEK4TYJfoGU8vmmJBGI5SyyYj0XDQjMvVQwBxRCQTilowFGwrjG5kTo+0x4OdpcLvV0YXIhcGGH0ZFRobOSccfB2PHR4FiyYAGQwdAI8eEAdQKBsZmR+RBpSVVyMHfiEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== rotate_ccw-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBFxaXIQChEQCBAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM0CLrcHjA6JcK4ET68MrNDoIgjOYbdJ4IXagIa3IqVFAMEOqpfn067ErBxG0qGsCJyyQT4EwAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 rotate_cw-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBIQChFxaXEQCBAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMzCLrcHjA6FaG4YbS6At5BR31UKI4mADGhd31rpbmCuZ6qQLA8XvqT2+QhHLKKxqSy4U8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= rotate-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBFxaXIQChEQCBAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM0CLrcHjA6JcK4ET68MrNDoIgjOYbdJ4IXagIa3IqVFAMEOqpfn067ErBxG0qGsCJyyQT4EwAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 rsub-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBIQChAAAACH5BAEAAAAALAAAAAAQABAAAAInhI8Jwd26YJBUTVvT1Rlt3x2f6DjQeQiGigLCC7crK7+yC9sty/oFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= rsup-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBIQChAQCBAAAACH5BAEAAAAALAAAAAAQABAAAAImhI+pGtZ7gpwQyWofnnQ7I4SiuAjlqZgpmqgti7gxfMh1OY6LXwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== run-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+/ISChKSipMTCxLS2tLy+vMzOzMTGxNTS1AAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARlEMgJQqDYyiDGrR8oWJxnCcQXDMU4GEYqFN4UEHB+FEhtv7EBIYEohkjBkwJBqggEMB+ncHhaBsDUZmbAXq67EecQ02x2CMWzkAs504gCO3qcDZjkl11FMJVIN0cqHSpuGYYSfhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== signature-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAFxaXPwCBAQCBDQyNPz+/KSipERCBAQChISCBMTCBPz+xMTC/AQC/MTCxPzerAAAACH5BAEAAAEALAAAAAAQABAAAARwEMhJZwgCiM17DoMkEGRpAmGhmSxhAOrakim6DgeLJApRhCPCgJRT8AhGEVFIQigAxgSQsBgwms8oIrDKDZNGxJY7GuYQULHhQj4shAmAuNAQsFc9xY4uUNgvMiQOBIMOfncjeUhICocXAx6RfwF+EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 spellcheck-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAASC/AQCBPzCxPwCBMQCBIQCBAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM7CLrcGuHBNZ+NIOJ9O4MTaH2e1nDoiFYZJjgwIAzwy8yEgy84RhWDQa4HCwAHxJgxSPApC83YyQnwJwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== sqrt-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBIQChAQCBAwODAQGBAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMyCLrcDiHK6eIL9WmsmwWCAAyiwkGKGILihzLq8p1s9onE9a48Iy28ko/WgRCLyGTDnwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== stamp-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+xMTCBISCBAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANCCLrR+zAIMQKMguh6GR2g1QEBCBLiGGjo+DSpS3IqXNqxNAnwzisSk3BowRltM8IAZVMqi84lLNoqUVfLrOhoVPgTACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= start-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBBRSdBRObCQ2TAQCBBxObISevNzu/BRGZPz6/FzC3Pz+/HTS5ByyzJze7Mzq9ITC3AQWLAyWvBSavFyuxAwaLAQSHBRWfBSOrDzW5AyixCS61ETW3CzG1AQeLAweLAxefBSStEze7CSWtCyatBSCnAwmPBRWdByixAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZrQIBwSCwah4HjUTBQEogFw/M4BQgMh2pxijAkFAhBYJwUPq8LRsPxWDwgkSHhelA0JJIJnlKRWy4YGRoSGxwcHRsecgAfICEiGhMjJBglVVMRgBkgJp0El0MRJyhaRFqipUoAFqmqrapHfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== stop-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAASC/Gw6NGQuLHQ6NGQmJFweHFQaFPTm5PTa3PTW1Oy+vOS6tNSinKReVDQWFPz+/Nx6fNyCfNyGhNR+dMxybMRiXLxGRIwWFNx2dNx+fNx2bMxuZLQWFBwWFPTu7Pzy9NRqZNRuZMRSVLwmJGwWFNR2dMQiHPTKxMxmXMQyLMxmZNx6dMxiXMRSRMRaVKxybMxaVEQWFMQuJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaaQIAQEBAMCAWDYcgkHhAJxYLRcDQBggckIplQKpaLdRh4YDIaSWa94Vw6woAHgv6AMKGPaMQhwQMJJRkfhHmEJhdvRCcgGSCEkCgpbnAECiorGYYfLCItlAAFCygQj5AfbYlwBQwVE5AukG6KBi8tMC0fLi0pHxyzcAAxFxwmMny/wEwOxMm/qlcdJCSJ1H5XQh3a28HY3kx+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 sum-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBIQChCH5BAEAAAAALAAAAAAQABAAAAIdhI+py60BowyPJriwQ3qb7oGNyJCZtZHixHpu4xcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== text_block-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIahI+py40Bo5SOzRvrwlgrfnkJOIkPaaaJXwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== text_bold-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIihI+py70BowPQ1HZpwNv212Vg9IGHmIjoWa4ey5DSRNd+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 text-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIlhI8Jwe2/AmpTynqPTXSqrnBM+I0kdmpmGmUp+K4nPMvhYx9+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 text_italic-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIahI+py+0BgztwUmmjBXX3jE0auHHhM5Yq4xcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== text_under-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIjhI+pu+FxXoOIKpds1oBH7hlYxYxRCaIZ01lhJbHy9tTv7BcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== toggle_log-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBATCxMTCBPz+xPz+/ERCBASChISCBARCRAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARaEIQJqpXBBjFI1oGncYU4EUXxSWQZlum6DXDQpeo0tR6KqqgdLXiLBWepHgyYIxF/TKHv9XvtDDfb0So5YHuTgThYCXgH4Q6hqvEGEIm4PLGSyHX4OkZv8UcAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= top-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBBRObAQSHBRSdISevBRWfAweLNzu/BSOrAQWLPz6/FzC3DzW5BxObHTS5ByyzAyixEze7BSStBRWdAyWvByixCQ2TBRGZJze7CS61BSavAxefMzq9ETW3CSWtAwmPPz+/CzG1ITC3FyuxBSCnAQeLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZjQIBwSCwSA8ik0kgUDJhGQsFwgA4FBUTCoLBiF4zGtmt0FBYPSEQyoZCvWQakUok0LISnkHBBYjIVGhscS0UGHRUeHyBWAAIhiYuNAggVIgmMVgYjJBolAZMKJgpIjaanRH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= transform-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBMTCBPz+/Pz+xFxaXAQChAAAACH5BAEAAAAALAAAAAAQABAAAANOCLrcEDAGt4K4F46wmcVCQIzE4F1DukksehVkiUlDYcdfCAyEGI+D2aP3G+UmPF/MAJpwnpuNgMmcKHKgabWSvRi+ums3a32wzmWKw58AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= undo-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBBxSHBxOHMTSzNzu3KzCtBRGHCSKFIzCjLzSxBQ2FAxGHDzCLCyeHBQ+FHSmfAwuFBxKLDSCNMzizISyjJzOnDSyLAw+FAQSDAQeDBxWJAwmDAQOBKzWrDymNAQaDAQODAwaDDyKTFSyXFTGTEy6TAQCBAQKDAwiFBQyHAwSFAwmHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ1QIBwSCwaj0hiQCBICpcDQsFgGAaIguhhi0gohIsrQEDYMhiNrRfgeAQC5fMCAolIDhD2hFI5WC4YRBkaBxsOE2l/RxsHHA4dHmkfRyAbIQ4iIyQlB5NFGCAACiakpSZEJyinTgAcKSesACorgU4mJ6uxR35BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= unlock-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaVAQCBKSipDQyNMTCxISChFxaLFxSJExGHEQ+FCQiDBwaDBweDGxiLHxyNHRuPIR+RIyGZJSSfFxaRGxmLJyaXNzWpNTOnMzGnMS+jJSKTGReLKyqjPTu1NzarLSufKyibJySXIyGVGxiNFxaXLSytPT29Ozu7OTi5NTS1KyurGxqVCQeDJSSjLS2tNTW1KSmpGRiLKSebOzuzJSOXExONExGLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaVQIBwOAwYA8SkMCAYOAnKYiFAIAQGyOgVCggYuEovVxztMpdnwAGRSCgUCwOjIeQ6HpCIZDKRUNYMRBUWF4UYGRoWGxyBRR0eHxgaICEiIyR0QyUmJygpKgUrAxMsLUQlKyieoKIuEAunK52fBS8DLiywQySpnjC1Mbi6QjIzNBeSIBY1EQfDQgosLAEUNjY3Co1DfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== up-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBBRObAwSHBRSdISevBRWfAweLNzu/BSOrAQWLPz6/FzC3DzW5BxObHTS5ByyzAyixEze7BSStBRWdAyWvByixAQSHCQ2TAQCBBRGZJze7CS61BSavAxefMzq9ETW3CSWtAwmPPz+/CzG1ITC3FyuxBSCnAQeLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZfQIBwSCwaj8hhQJAkDggFQxMQIBwQhUSyqlgwsFpjg6BwPCARySSstC4eFAqEURlYhoMLBpPRUDYcHXt7RgUeFB8gIU0BIoiKjAcUIwiLSQUkJRsmGIwJJwmEU6OkfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== view_choose-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBDQyNAQCBPz+/PzerAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMzCLrcGlAs6UAYgwLdLtEcI4ygQo7VVp2oupGpG4vmaUVTemX523qlFcw0a4RqNlkx5k8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= view_detailed-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBDQyNAQCBPz+/PzerAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMmCLrc/i1IAVkYg1Z1iRYUKCqitp1oikqBWV3ZOnhkWNagqu+qnwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== view_icon-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBDQyNAQCBPz+/PzerAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMwCLrcG1AwGOQbw6qANeCEB3pCSZpO6pgowJZqLKuUGE0dnuEhf8IL1kz1shSHDX8CACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= viewmag--16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBCQmJDw+PAwODAQCBMza3NTm5MTW1HyChOTy9Mzq7Kze5Kzm7OT29Oz6/Nzy9Lzu7JTW3GTCzLza3NTy9Nz29Ize7HTGzHzK1AwKDMTq7Kzq9JTi7HTW5HzGzMzu9KzS1IzW5Iza5FTK1ESyvLTa3HTK1GzGzGzG1DyqtIzK1AT+/AQGBATCxHRydMTCxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ+QIAQEBAMhkikgFAwHAiC5FCASCQUCwYiKiU0HA9IRAIhSAcTSuXBsFwwk0wyYNBANpyOxPMxIzMgCyEiHSMkGCV+SAQQJicoJCllUgBUECEeKhAIBCuUSxMKIFArBIpJBCxmLQQuL6eUAFCusJSzr7Kmpl0CtLGLvbW2Zn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= viewmag-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBCQmJDw+PAwODAQCBMza3NTm5MTW1HyChOTy9Mzq7Kze5Kzm7OT29Oz6/Nzy9Lzu7JTW3GTCzLza3NTy9Nz29Ize7HTGzHzK1AwKDMTq7Kzq9JTi7HTW5HzGzMzu9KzS1IzW5Iza5FTK1ESyvLTa3HTK1GzGzGzG1DyqtIzK1AT+/AQGBATCxHRydMTCxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ8QIAQEBAMhkikgFAwHAiC5FCASCQUCwYiKiU0HA9IRAIhSAcTSuXBsFwwk0wyYNBANpyOxPMxIzMgCyEiHSMkGCV+SAQQJicoJCllUgBUECEeKhAIBCuUSxMKIFArBIpJBCxmLQQuL6eUAFCusJSzr7GLArS5Q7O1tmZ+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 viewmag+-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBCQmJDw+PAwODAQCBMza3NTm5MTW1HyChOTy9Mzq7Kze5Kzm7OT29Oz6/Nzy9Lzu7JTW3GTCzLza3NTy9Nz29Ize7HTGzHzK1AwKDMTq7Kzq9JTi7HTW5HzGzMzu9KzS1IzW5Iza5FTK1ESyvLTa3HTK1GzGzGzG1DyqtIzK1AT+/AQGBATCxHRydMTCxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaBQIAQEBAMhkikgFAwHAiC5FCASCQUCwYiKiU0HA9IRAIhSAcTSuXBsFwwk0wyYNBANpyOxPMxIzMgCyEiHSMkGCV+SAQQJicoJCllUgBUECEeKhAIBCuUSxMKIFArBIpJBCxmLQQuL6cAsLECrqeys7WxpqZdtK9Ct8C0fsHAZn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= view_multicolumn-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBDQyNAQCBPz+/PzerAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMwCLrc/ixI0WSgKoyBl+beQFACpo1AqXbKCr1wLAMWS08hGG3dSZqin4sxnBmPD38CACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= view_text-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIchI+py40BTQSwuovp3DXkv1ia1IHmIXLiyWJ+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 view_tree-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIIAAAQCBPwCBDQyNPz+/PzerAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAAMuCLHcri4yGISlj4kxcANgNRBQCIbL6U1Su7bB62rXvGydG25kqpwfIGxILBr9CQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 window_fullscreen-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIQAAASC/AQCBNTW1MzOzMTGxLy6vKyurJyenHR2dOTm5Pz+/IQCBOTm1Pz+9Pz+7Pz+5OTmzOTmxOTm3Pz+3OTmvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVuICCOZAkEaKquqzAQRWEYR32gSK7vO5oowKAQmPAtjkPFccEwLoaNhuPYDCSeT2B0+lhAfMHF1kF+PL5W7ZhrjqAk4gW53J0s3AG4nP6Y2BcUKAxLZn1+S4EBDAwQEIsUDBQRFJSJLJcoJpojfiEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== window_new-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIUAAFxaXGRmZFRWVGQmhFwmfFxeXOTm5MTCxLyWzLySzKyCvKSCvJxyrJRmrIxipIxWpNze3AQCBMTGxJRWtJRatIxOrIRCpHw+pHw6nHQ2lGwulOzu7Pz+/Pz+9Ozu5Pz+7NzexPz+5Pz+hPz+3NzevPz+BMTCBNzetMTCDPz+xNze1NzezPwCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACwALAAAAAAQABAAAAaVQEBAMCAUj0aCYFkwHBAJhWLBYDQcD8ghIjhIJhRKxXLBZDQaiYQLABDe8PiSu+HY7/dOh+PhQvB4eh8fIH6Adh2DHyGFAn+BiQAiISMkhnmSIQAlI5KXHIkfAiUmpCUnhoKLISgpIikmAlwqtCArkiUlIhwiuSKyEcHCESausMEsycrJEaaly9ARIizN1NPQ0dfJfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== window_nofullscreen-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIQAAASC/AQCBNTW1MzOzMTGxLy6vKyurJyenHR2dIQCBPz+/OTm5Pz+9OTm1Pz+7OTmzPz+5OTmxPz+3OTmvOTm3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVsICCOZAkEaKquqzAQRWEYR32gSK7vO5oowKAQmEAtfr9hgpFoGBWJpDDqcAaOUSHDEU08nkOG2AGBfK/aMYQMiRi7Ywe5674yE3I2JCqZoChLeGwSEgmFfgFNDQ8NjQ0TEROSRSyVKSaYI34hACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= wizard-16:actions actions16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+xPz+BMTCBPz+/MTCxISChDQyNAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAREEMhJg6BYWhAGv5k2EKMXToSgEqc1DEIhvGAWpOvJFSXZyoXOxxY0BDahQDGg4xgOxmbgiWDqpoeqlGrVcZuSbLfpjwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== abbrowser-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBKSipMTCxISChPyqXPzerPz+xPz+/FxaXAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARhEMgJQqC4Xms1tkIgDEMYXpMYEEJRCIT6Ea5R2DHFtQZBG6dNoHQrsAyH14DDWiENBsQhBtskEs4Dohe4oiqE5So2zElECEKCrCYgQmcRVnRKnFIdC0L4/az7GXiBg4N+EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 access-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBGRufLzi7PT6/NTq9OTy9MTm7LTW5LTS5LTO5KzC1FyGrExSXHzG3Gy+3FSStPz+/ESGpFSmxEySvEyKrER6nERylExqjFSSrKze7EyCrDxulKzG3GSuzGSitEyWvER2nEx6pKzO5DxmhLze7DxqjExihERadLS6xERulEyOrLTC1KzK3ERWbERujFRefGR+nKTO3LS6zLS+zFRmbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAAQABAAAAa1QEBgSCwWhYIBocA0CA6IhEKwYAQKDccDAolIJpSK5aKwFhyYDGSQoWgqm4uFYyV0PAeIIPIeayZlVw4OFV19FxoSGoFnH1tcayASIRciVgYfEWoQIxcLk4gHlxQCnJBcJBUSdAEHhQediSV5ExWBBxYQGSZelLkHJyhWsHmSISkHKpsrViwWJ1xPXCAtesIBCiUaGHm6LiYvLybXMAQCMQosBwcoMjIzMTQMAC0M9vf49wB+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 acroread-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIEAAASC/PwCBPz+/AAAACH5BAEAAAAALAAAAAAQABAAAAIlhI+pELshmkOhzmTvyZrFDglRxVEiGUoUualtx7gOC36gDGt+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 agent-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBKSipISChPz+BMTCBISCBERCBCH5BAEAAAAALAAAAAAQABAAAANLCLrcHkFBt4IY8EYKYCAT9xVBYRhbM5KFeaRVy56oSsgQ/TLrB567ym10ChiCnRIRaJx8lDdd86UkEWjHaURZwlKRHpM0xPOYGf4EACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= aktion-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBPz+/AAAACH5BAEAAAAALAAAAAAQABAAAAI5hG+hIuigAmMvLTlfnJiePQndt4SMFFioeaagaEbvySlQF6I2BLPRwYntDLlaylH8VXLDpaiJ8BcAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= alevt-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAASC/Pz+/AQCBAT+BPwCBAT+/Pz+BMTCxCH5BAEAAAAALAAAAAAQABAAAANFCLrc/i3ISadQYQhSehFecAGiYJ6oiJmaZrymSrKCJhinXLYmHo+l2skn0KGOPwyBUHPhOrqKVIWsmhqHyqhhPUG+Cn8CACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= applixware-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBKSipAAAACH5BAEAAAAALAAAAAAQABAAAAIyhI+pGbsBHYtHCGARbMhms1HVB0TieJhcl23liXkinAmhy7732UL9GnsZeixczChB+AsAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== ark-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAASC/PwCBAQCBPyCBPzerAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANCCLoQwTBK6dy8WNQgptAbB33DQGzlx3xE65RpBwgtCw9sR7e1gO8EGYs3DMoUH5rPqFylSrzaygcjHqdQVUYL8ScAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= arts-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAAQCBPz+/KSipPwCBISChAT+BARCBMTCxDQyNAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAMALAAAAAAQABAAAARTEIQ5xbgYAwJksFhhaFTVdeLpURYwAOL7cp6gpmcZHEQPGyIOLRAkiI4GTqmIDG5QwGihuRIBU8boasLzZbEd082QK7VkrvTwo2pvP5m4GxHP+CMAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== background-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIYAAAQCBJx6NJR2LIxyNJR6NKSORKyaTJyGRJyORKSWTJyKRKSWRKyOPKSKPHRKLEwiFDwSDEQeDGxGJLSeTKSSRKyaVLyaPLyaTGQqFFwyHGwyFEQWFDQKDDQKFEwmFMSiTMyiVJRuNLx+LOS2VOy2ZNSKTFQeFGRGJLyqXMymVOSiVOy6ZOymZKxyTEQODDQOFLymVKxuNMRyJOSeNMx2FLxiJLRiHFQaDDwOFDQODFw+HLSiVHxSLFQiFIQ+HKxmNJxOLJRSLIxGHDwODGw+HNSSPOSWNNRyFOyyVOSOPARihNSORKRSFLR6TPz+/MTCxKTi9JTW7GSy1Lx2THw+FNSOXJRWNISChASq3ASWxARynEQaFMx+JJRSJFRWVARafARSdHxeLFw6HPz+7Pz+5GxKJDwSFIRSNHxGNPz+3MSCPNSWTMyGNPz+9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAAQABAAAAfXgACCg4SFggECAgMEBQYHBwgJCAoLggsMDA0ODxAREg0TCxQVghYWFxgZGhscHR4LE7GCHyAhIiMkJSatJyi+giApGCokKywtLhwvBzAwgiMxGDIzNDU2Nzg5OjsTghc8PT4/QEFC2EMeCZUARKpFRkdISUr09YIYET0qS0wqTUpOnkCJIkWQhxsbpsigUsWKkidXsGTRIkjHgy0YuMjoYkKJFy9KvoARFEZMBAg3UkIA6MTJGDKCBpQ5aebMGTQsx4xJU/FBBIxq1rAB4KTNS56Gkg7yEwgAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== bell-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBEwuFLR6PLRqJHQ6DNyuhLx6LKxiHDwiDMSOXLx2NKxaHAQCBHxSLGw+FKRyLFRSHLR6NIRKFExGHNTStOzm1KyqfIRmNHx6PIyGRFxeJNzavOzq1MTGpKymfKyqhKSmdGxqNDw+FPTy7KyuhNzevISGTJSSXLy6jOzq3Ly+lJyabHRyNCQmDKSifAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ6QIBwGCgOj8iAYEAIIJ+BguGAeCYTigXDegw0DI4tl/gQj4WB8hkAgUQeEsaEC6FULBdMRjN/QjYcHR4fICEiVn8jFCAkHxiHfiUjHRYfHyZmR4kdICAeJ5lCECgVKSorJysrLC1IEBgVFSgunSAaoWwTIi28DL5HfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== blender-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBDwiDPSyNOyKLDweBFQuDFQyDPSeNEQmDIxSHFQ2DEQqDARWjARGdASO5AR6xAQiPOymNAQ2XARqtAQKHOSmNEQiDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVqICCOQBCQKBkIA5G+63C+RW3UrIsSQt8fA+CMREAQgIkaUEdSsBK6hZBUeJ4YjRLQIKoOBgVAw/GAAAqRk+EJBkgmDQrAUDGxTAMBAgCR89oFOgF5YQAWdy8EeTeILyV5jY5nBAGFkpJ+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 clock-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAASC/AQCBPzerPyqXMRaBIQCBISChPz+/KSipMTCxPz+BMTCBPwCBPz+xPzCxMQCBISCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVxICCOQGCeJjkGwkC8RFEEavkax2G8dB0QuRyhhzoBg8MSYsncJXKJZIDZHCoWP1ogGIwGrtnSgUFmHLyNRHhrdpjRamnO/SYkromHdnxwnwkKVxByZW8DgQsQM2JcfwZXO0MBCZSVBgMuLzJaRZ0pfiEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== colors-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPz+BAQCBAQC/MQCxATCxATCBPyqXPwCBPzerAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARWEMgZ6rwYBCFsvtXWeWA1DBU3ggRhomJQBm14dlJYFFXrbjKNwVDZ9Vw4TWWoKyCDgcNhyXQClVLpMmANIRAhLdGa+36j07GrfM4GiKTAGfsOlmYZfwQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== cookie-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBNzeDJR+BOzmVNSqPOSmBNSCBKRCJFwuBOSOjMRSTLRaXFQODMxiXOS6vIwiJGwKDHx6fKyqrMSOjNRWVLRaVFwCBJyanJSKhHRydPTy9PT29OyytIQSFPz+/JSSlOTGxIQyLMTGxNTW1Nze3Ozq7OTe3FxSTGxqZNza3Ozu7OTm5MzKzLy6vLS2tNTS1FRKPGxWRMSypJyOhKSOfPTu7LyupFQ6HMzOzEw+NJR2XKyOdFxGNHRSNJx6XGRCLHRCDMy+tGxONDwaBHRiVDwyLEQuHJRyVJyCZLSilIxiPIRePHxOJIRWJFwyFEwqDCwWBBQOBDweBKSCbHRKLHRKHIROHGQyBFwyDDQaBIxqTHxOLGQ2DDwiDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAe4gACCgwABAoSIiAMEiY0ABQaHjoQHCJOECQoLDJeCDQ4PEJMRERITFBUWFxgZhKQaGhsKHB0WHrcfEQARGxu3HiAKIRgiIyQlJicoGym+KissLRIuIi8jJTAwJjEyGzIYKxszNDU2Nzg5MDY6OyQ8PT4jP0BBQkNERUZHOkhJSktMZDQBcsTJEyhRpOybcuSIEipVrFxBgEVKFigATkiRgkSLki1UgFzh8kRKFEQbN3aR0qULIT+BAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 date-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAASC/AQCBPzerPyqXMRaBIQCBISChPz+/KSipMTCxPz+BMTCBPwCBPz+xPzCxMQCBISCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVxICCOQGCeJjkGwkC8RFEEavkax2G8dB0QuRyhhzoBg8MSYsncJXKJZIDZHCoWP1ogGIwGrtnSgUFmHLyNRHhrdpjRamnO/SYkromHdnxwnwkKVxByZW8DgQsQM2JcfwZXO0MBCZSVBgMuLzJaRZ0pfiEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== dlgedit-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBMTCxFxaXKSipPz+/AQChAAAACH5BAEAAAAALAAAAAAQABAAAANLCLHcrSLKOVccAuvMLf2Rlw0bYRKFGBGZWQioRc4kPKfB+qFFL9ODF+EmKxh6vZOreETCbLiMESkcxnIgATXK2XgFqmxI4SgvAP4EACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= emacs-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBDQyNKSipPz+/FxaXISChMTCxCH5BAEAAAAALAAAAAAQABAAAANJCBASoXCFoVi8VdL6HHQeB4YjSAxnYQygSLzoSTjbEs9vMF86cbyH34NX+AELQ4zO+Nopm6cBC1PBEQwG6gd3SGo7Xa1STIb4EwAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 email-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBGRWVAQCBOTWvKSShDwyLOTazOTaxPTuzLSilOzi1OzezPzy7Pzu1NTKtKySfPzy5Ozm3Pzy3PTq1NTCrMS2rNzWvNzOvMy+rLSmlPz69LSejIx2bPz29ISChPz6/Oze1HR2dOTi5Pz+/EQyLJyanKSipOTm5MTCxHx+fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaGQIBwSAQEAoJi8RgYEApK49FgOCAS0CFTsVAwEA2CIysMJB6QCEQyoVQsZOMFk3loJoeNAk4MGBQOFAQcDw8IfFoLDB0cEBMICIRxAV6NEB4aHwICk4wLIBYhIiObSxwLBSQkJaOlfQUFpCYnIyMoSVGbtQK3UQCbKCYprkq8m8S+uL4AfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== energy-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBBQSFASiBHS2/JzK/KzW/JzO/ASWBATCBASKBHy+/Hy6/ByuHASCBAR+BATOBARyBIzC/MS+BASeBASOBARaBFym/Pz6BASuBEyW5AR2BJS+7Gyq7PT2BARKBDyC1FSS3IR+BJyaBLy2BPz+BCxuxAQ+BDw+BOzmBARiBCxyxBxetPTyBAQCPAxOpAQ6BAQ6jAQ2fAQ2hLy6BAQubAQydAQmXAQmVAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAahQIBwSCwaj0hAYBkQBJDLAaFgOBCWxcAAkVAsGIyG4/EUBh4ICCIicUAgkwTZjKBULISL3oHJzAMaDhscHYEODhMeExEfSyAhGxsgICIYHiMWJCUYSyYYJw8kIigoKSomKxgmSywYfC0YGCJ8rSwuS7EYJBYYLi+xE5tkARMoMCoYEzEiJDIzMjQiSzExMxGkNTY2NTc4NTNPTOLjWElHfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== enhanced_browsing-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBOTWzIyCrFRSTMy+tCQmVOzi3ExKhAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARFEMhJq6UhyHy3GNmnAeNEFAZwpuRRBiIMkkOBjKuKTsHtgbISybTLYX6hGc+lSxk3tVtMVOkFck9MMNjB7jqkEQdMlvgjACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= filetypes-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBMT+/ISChKSipPz+/PyqXMTCxFxaXPzerPz+xAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARfEEgZqg0zV8EHF5XWEUMxkBwGBB9REIZLfBgrkEaen+l6F4cYgpA4vEC+ASIYSxQRnlrncEgoFFQP0laCHpSmnk+AEJQ8ZeRkw0mDVJT3JZQZw+trC77Ouu8pfn8AfhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== fonts-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAASC/AQCBPz+/KSipMTCxPwCBFxaXMQCBCH5BAEAAAAALAAAAAAQABAAAANBCLoQ/C+I4GAMY1ZGN80UJ2jA0BFbUxhjF6BWsQroawEyWhN37vKxQo0ChPhOPaGDIhhADr5FinE4TG5PrBbiTwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== gimp-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBISChPz+/FxaXMTCxAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM6CLrc/izAJVWoD4MgtL2R0F2k6HFiOgjDSRBq0FLUKxYDTmKBnf6gGqz3egWFhEvSQ9kxJ9CotOFPAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 go-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBERGRFRSVDw6PDQ2NDw+PPz+/ERCROTi5Pz6/AQCBKyurERGPOzq7ISGhNTS1DQyNLSytExKTLy+vKx+RGRiZPTipEQ6LOzu7PT29JSOjOzWlEw+LIyKjIx+dLy6vOy6ZEwuFHQ+DCwqLGQ6HNSWPMymfIxmPMyqjKSipCwuLMzKzHx+fBweHOTm5GxubJSSlAQGBHR2dAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAadQIBwGAgIiMXhgAAoGAwH4QCRKAgVCwSB8AwwCo2n9ZpwMMSFhyEBGQoLEa5BMnkO3G/Kef2sMIdfCxYXT2oGGAIHCk0ZCBobHE8dHk8MFR+LgSAhXSIRdmNCBxScBiObCAYZI25wJE8SJSYECVVDCg8dERchJygPKSqsQgQNKwQFCw8fLC0KLi+LxH9YMDFX0ngAzzLZ2m4K3kN+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 gv-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBPz+/AAAACH5BAEAAAAALAAAAAAQABAAAAIxhI+pwaHZ2jNMWMFmvXk1GznHF4DhWF4cJlKpynpwB73ms3Etiq00EAr+hJGJ0eAvAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 gvim-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBAT+BPz+/ASCBMTCxISChAQChCH5BAEAAAAALAAAAAAQABAAAANUCBDMEqupNWoNJNgBV/mfwYCFqASgmA1h57VaO71lXLtPytZEBggZ0E7Vy2BQJEaRcDghP6iGb/IsNKBWKghZzb5EUau4g1KFz1QId+ydRRZwiD8BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= help_index-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPz+BAQCBPwCBAQC/IQCBATCxMT+/Pz+/ISChAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARTEIRJJZ1ACjF3GGAYaKNFDNfXldLJqmQWcKhcW6tkl1NhFJhdRmIwHIq8m8R3LAIlykCxiZQNl8XsU3eVZg0Y2LD3CyAQlassbEaz1N32Gz5m+SMAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== hwinfo-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBBQ+XBRCZAw+XAw6XBRCXCRObCxihCxqjCRijBRSfAwyVCxehDx6nER+pPz+/BxKZAwmPFyWtGyevCRSbBxWfAxGbHSqxGSatCxulBxahBRKbAQiNEyKrBRKdAw6ZAwiNESSLCyCDBxWBDRulBwyRHS6ZDSWHCyKFDQyNCxqlAQmRAwiPMzalPyCBMQCBCx+DAwuRBQqPITCdFxaXCyOFAQeNAwmRAxKdPz6/GyyVMTCxKSirAQCBGzKZAwqTAweNFyuRDyeJFzCTITOdAQiPAQaNHzCbES6NEy6PESyNDyqLDymJPz+xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfBgACCAAECAwSDiYMFBgcICQoLC4qCBQwNDg8PEJERlAYNEhOaFBUWnokBBw4SFxgOGRobCxyJBQkNHZoPpR4fICEiIiMBCSSYmgoKFgslJicoKQQKCSoZmgW+KywtLi8pMDEbFRqaAcwyMyc0NSkiNjc4ObsrKyU6Ozw97j4lNhGSfsgAEkQIDxr7YAwh0qKIDSM2jgRpgbDHPhFIMiZRsoTJkhMgobUDMKKkySYjUKockYJSypcrWypKQbOmTT+BAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 icons-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAASC/AQCBPz+/ISChIQChFxaXKSipPzCxPzC/MQCBISCBPyqXMT+/MTCxPwCBMQCxMT+xPz+xMTCBPzerPz+BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAV+IBCMZBkAqCgMa8uyJxoMRFHUtz3Eqk0MBhxBwJsRaqTcLhUQ3AyHAMI0EtEI0pGrpU38SANFQazYGY+LqUChYDQUxCbB8YjOFJAIpGEePOpZAhITIxJxAg8JDwQPMxISERESfXSVTRIQAZKHLyuOFI8US1RNnTApqCJUAH4hACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= iconthemes-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAASC/AQCBPz+xISCBPz+/ISChPz+BIQChFxaXMRaBPyqXIQCBPzC/MT+/MTCxMQCxPzCxMT+xMTCBPzerMQCBPwCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAWLIBCMwhgMJqCKRBEIpWAMBRGsQXG8sIAiLpwNZpAFEAcbjlc0OI9BVcAWSDgHT9MtF1AsZrmamNpNBAyjwgCxpo0U5h1jOhg0HAMbPHB4QNIDEQIRDi5xfgFzBBITIxJUBQ8UD305EhIwEi45FQ+dFVMSES+PIy2nLgUSBpcGQVomqKc3K7WwIwB+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 input_devices_settings-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+/MTCxHx+fISChKSipKSirATCxAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARQEMgQpL03iEEx1gOxdR5YbCJXZUbqjusUhGitZkFri0VFUodXoTfjWCi6oY8Skxl6k4FhxZRRRxMC1TBdWn0CAbcZQFAH4WnGjDPiPICYPwIAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kab-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBISChFxaXKSipDQyNAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANICLocHiyqIMQYUE5Ses8S1V0FGInFIJTalKpsS5FxKDxB/EzV4GUBQsXR87BQnRtNtxphfJ9FAAqbRqUXVfPaMH5MDRx44U8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kappfinder-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBExOTDw+PExKTPz+/ISChAQCBPz6/FRSVIyKjJSSlIyOjGRmZNTS1Ozq7Ozu7AxyzPTy9ERCRBQWFIyqxPT29AQ2vOTi5IzG7DR2zNze3Nza3BQSFISy5CRyvBQenISmvBQitMzOzAQGBAw6rDR61Hx6fMzKzAz+/IzW7ASyvCwuLMTGxMTCxBwWFDQyNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAahQAAgEBAYj0ahckAoEJ5QgkE5fBYO0SeCOigkFE2DeEFgUAUNBwGBeBAcCMHirF4gnhBCBCE5PydqBBQVFhdTSgJPBk8YGRQaG4dCiQQcDh0eHyAhIiN+BHYXJCUNIggmfhUOAQgbJ6YCKGcVKSUaChwGHCYqCyuIDhkhGyIsLcccCL6TFxsNJ8fRLS7KvyNi2GIrAQwK1AsvVOJULi4AfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== karm-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPz+BAQCBPz+/ISChMTC/MTCxPzCxMQCBPwCBAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARTEIRJa5Ui66H3FETHdcTwdcIofkVbUIJbmAEoZl95aoXxUrNdpnAIDFomgRA3yxxhIdxAlaKhAgUNYshyYVGxnMZInS6VzVSQPG0bkWaJZT4B+CMAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kcalc-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPz+BAQCBATCxARCRASChAT+BMTCxFxaXEQCBPzCxPwCBAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARPEIBAq5U4iM17wJMwjORIfJkYFCs7nKA2rJQLp0Su66ikGcAg8OYTGA6BA/KAIIYsFudPGJQal8uAFVqxUg2JxBYbUGh7k5J6BppwKyB/BAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 kcharselect-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBISChPz+/MTCxAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANBCLrR+zCIGWCcI1cLpNCa5YHZsCmj2QTlxrZmmRFVSs4E7X13TqMTXsl36gSHuSIQQ+QYP0kncPCTokzWh3LhTwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kchart-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/AQCBPz+/ATCBAS6BPyqXPzerPz6/Pz+BPwC/MQCBAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARcEMgJQqB4WiFulhvXfaEwiJ4mEgExFCMVcENgBEXepdVhG7dcABGr/IJCQ8ICAt4IUIuSKAW2XMOD0qC42AIHV4277YIqKHKCy5txbIoyDy2Nr80yjyVwn5OYfhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kcmdevices-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPyCBPyqXPzerPz+xPz+/AAAACH5BAEAAAAALAAAAAAQABAAAANMCLrcHjA6BcW4Q8AWLL7EFSwdOIRoOAKBiZ5EPJYvBMeDba5BQfg52ik4KPgKOVYqZiwYjLzb7/c0JCnSo3VFasFEXE5kMymbzwp/AgAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 kcmdf-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBMT+xAT+BASCBATCBMT+/AT+/ASChATCxPz+xPz+BISCBMTCBAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARaEEgZwrwYBCFqvhs3DNYXjChRlWBRjIRqGN4UuEUczMZxsDeXykdEsDQVVSLhQxhBCkVlmXA+KVHFYhFYOoHbMGN6pTQaW8YYiQmcG+q16a0+Zipw+4e9B/gjACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kcmdrkonqi-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPzerPz+/PyqXMTCxPz+xAAAACH5BAEAAAAALAAAAAAQABAAAANKCAoRy+6pIESkVuLaKl8b53lOaA3EyIXBUBjpWHKDYNhxNrWv/aaRiWBwKwoIDZCH2EN+TMQjyzR0yhgqiyo4vT4wl48E8g0C/AkAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kcmkicker-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBFxaXPz+/ISChMTCxPzerPyqXDQyNAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARaEEgQqr11AjG6/4FGDEVZBOapWSXbToFhoKkZUjJGEEJvyUDDYQaKATElBOJklB0OgY5SWgnmpFJm4PkMjDxLFYXFGSCyN8mocDaD0xsSO6wUS6K1FBzDD/gjACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kcmkwm-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBCRiXCRaVPz+/CRmZFRWVISGhMTCxESSjPT29DR6dDyOhDyCfPTy9CxqZOzu7Ozq7ERubOTm5ARehAxefPz6/ByaxBSOvBSGrAxynAxqlBR6nBRylAxmhARWdFxaXCH5BAEAAAAALAAAAAAQABAAAAWHICCKQTCeqCgMhJCihXEYSPuKRWIoC6PYsEZikHA4FA4CEJdoJh4QgXRwiOAeQudDIpEZIpPwhCImhyGGAmBSOVgumExG055w1ZPZhpPpUDwzExBqAAUDhxUVTQ0QEgWOOIcDiU1QjoSFFYiKDZYFmAWJlE9bkCM5iouWpiIfBa6frrKYAH4hACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kcmmemory-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBISChAQCBMTCxCH5BAEAAAAALAAAAAAQABAAAAI6hA+Bu+HCmgiiRuNoHZBRXQlc84TmcHzm2WVryE1YvMaZIdbVd2zw7lj4bDKGbxK8hHgX3K2JUDD8BQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 kcmmidi-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBFxaXKSipMTCxPz+/AAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM7CLEL/pDJAONs1V2W1ebWJ46kKJxomi5D2QZEwRSyVMNyngf7Eg8FYHAIZMRoyCSNMSA0n85oszTxJwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kcmpartitions-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBMT+xAT+BASCBATCBMT+/AT+/ASChATCxPz+xPz+BISCBMTCBAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARaEEgZwrwYBCFqvhs3DNYXjChRlWBRjIRqGN4UuEUczMZxsDeXykdEsDQVVSLhQxhBCkVlmXA+KVHFYhFYOoHbMGN6pTQaW8YYiQmcG+q16a0+Zipw+4e9B/gjACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kcmpci-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAADQyNATCBASCBKSipFxaXAQCBMTC/ISChAQC/IQCBPyCBPz+xPwCBMTCxPz+/AAAACH5BAEAAAwALAAAAAAQABAAAARVEMhJqww4a33F+EL4jUI3EEXoEWzaFbAKzyUQeLihDqrpHQhBQkHyqY49iWCxbDKfJQbASYUCpJbslcHter+NQ3gsLo8bBYd6zWYf0u24GjWr22f+CAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 kcmprocessor-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBKSipMTCxISChFxaXDQyNAAAACH5BAEAAAAALAAAAAAQABAAAAM7CLrc/jDGQCWgIleH88jCdgXgB4JVQJxsVgQXIQvrWdwwJc/0jcOG0Y7gqwQVQR3R+EgyJcGjZUoF+BMAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kcmscsi-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+/MTCxKSipISChAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANCCLoQwZAFIV6UYgxi79Qa52WDE3bKV6YOpFpO3L5pJcckLBB8/wQEDezWAQpZqIWxFNAUkqkg6HmJOqGuArUqwfoTACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kcmsound-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQC/AQCxFxaXAQChAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM7CLrcDiE+F4SQU4UBLH6VoHjT1okQR6mnuTYuJMWaGlkXW2u4QOipRYDws82AjJsHKez9MgrigAkF+BMAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kcmsystem-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBGxqFAQCBPz+/PTqtOTOfMSyPNze3Ozi5KyeLMTCxMzGzKSipOTe5MTGxAAAACH5BAEAAAAALAAAAAAQABAAAARfEMhJQah4ihFunsFAEIVXCVJACIJhoBK6CerawsA8HAhbuAnYZrBDKBYMWpCy4S2QSRazyBIwrrjcoNFQzK4KR1bQcHhZjGM2BgWLMYJ2enForHPJtNj+kfHvcB8AfhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kcmx-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIAAAASC/PwCBCH5BAEAAAAALAAAAAAQABAAAAIlhI+pm+HB4HkS1flszOCq7C2Qw0wdJ2Lk16BGeK5dSZX2jS9+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 kcontrol-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAASC/CRyBBxSBExOTNzipOTijOz67NT21LzutJTmlGzaXPz+/OTi5AQCBLy+JKSiJES2NES2LESyLDQyNLy+vLzWhLzWjLS2tGRiZDymJASChIQCBDyuLLzShDyiJMQ2LATCxMQKDDSaHDSWFCQ6tMT+/PzCxLzuvCyKDDSSFKyqrMTCxGzabDw+PISChASSBAT+BDzOPNTW3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAacQEBgSAwIBsikkFAwHBAJhWBBpTIaAccDAolEJIKJWEzBMiuWCyYjaLjd5exDIsE02A1NY9OIMzkcHRkebW99WFoVahkfbSANIYdCBh52IiOFb2VCByIWIh0kbSUNJpIBJ6CgKJlwDUIJKSooswIUt7crrwEsKC2+rC7CLzAuuzEoycmtbgAAAtDR0DLGztYALbm426/Wht9vzn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kcron-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAADxePARCBAQuBNTS1OTi3LSytAQeBMTC/Pz+/AQCBOTi5MTCtISCZAQiBISCfKSipFRWZGRiZERCRHRyZMTOxDxOPMTCxIyCjCQiJAQOBLS2tAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAAQABAAAAWFIBCMpCCQpDgQLFusLVEYAXEgOJIQOXIkNF5v19MFWQrCgsFYxIC1InEYvOWmuF9QKrw2aoSkYtksOBwEaBeXeEAiiIdD8rUNJw8EBUGobIcQFggXLglgCohLGA95CQMOGVFDEQ4YGhERdAEWCZ2dDwsSEHMOEA0ABqmqGRkGDQ2pDRV+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 kdevelop-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBGSKXEx6RFR+RFSORISidJzCjJS+hISydHSqZDxuNIyuhKzOpLTSrKTGlHyybGyqVDx2LHyedKzKpLzWtMzexLzavIS2fFyWTDyCLCxiHNTmzPT29PT69NTm1GSWVESKNCRmFOz27Pz69PT27MTKxJymnIS6dESGNDR6HFyCTIy2fNzm1Ozy5JyenISKhISOhMTKvESGLBxaFOzy7JSWlIySjCx2FBxGDIyOjOTu5BQ+DFSGRDR+JCx6FBxODDx2NGyaXCRyFCx2HCRqFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAexgACCg4SFhgABAgMEh4MFBQYHCAkCCocLDA0MDgcPEAQRhRITFBUWDAcXEBgZGoQIFBscHRweBgkfICGDAQcUIiMdJCUmJxgoKbsAKissLSQuLzAxFgQyKTOCKgk0NS/fNiQtBBk3OIIEEC0cMDkvJiQ6ICk3O4M8FCQcNjAcJBM9fPwgBCQICxI0XtBgQeCGEHuEFGCYwILFBAJCHh7SEGJIRiI/IDaagSNko5OF/AQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kdisknav-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBERCBBQWFPz+xPz+BISCBERCRPz+/OTm5HRydAQ+XHR2dKSmpNTS1Hy+1AxypNTu9ITC3ARypExOTFSyzHS61JTK3MTi7CwqLBR+rASGtDyixFyuzDw+PAxWhAxmnBRypISitCRujAxelAxmlFSixMzKzCRqlMzOzMTGxMS+vGxubLy+vLy6vKyurCwuLGRiZLSytFxaXJyenGxqbDw6PDw6NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAafQIAQEBAYh0jkQEAoFAxJ5EGAaAoSh8BBEUBSrQtGw5EodwHfgsBgeEAWijGW2XTaDRHJJExBrwl1AhUWFxgRDwdCGWkCGhsbHB0WGB5CjB8fICGOGxaJaWwGIiMfJCUTJh50dk4ODiejHyiff2oGDikqK7osiUIGai0pJyouxi+9v2pEMDEyLTIyDckCy0gBMDM0DTU2flFDARk3AH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kdmconfig-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+/MTCxISChMT+/ATCxASChFxaXAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARaEMg5gw00yyDGIAR1YUDggeFWFIZhnSBZrsZxdIOFEGTA2oeBAHeyuGwvzxBlYdUOLROMFzDQntJPrNoqAKUBaqnV+k57ZORruykHDj2LqIzUVKp1u0iuB/gjACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kdvi-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBPz+/MTCxCH5BAEAAAAALAAAAAAQABAAAAJCRI4ZwCYPo1gsiIHHxY86KXmWdiGkCA1Wp6Htc07NOsEv2oVyldLHbuBgEhORJhOxGEkkiLJybCZ3iqrD08hmF/4CACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= keditbookmarks-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBCwqLLSytLy+vERGRFRWVDQ2NKSmpAQCBKyurMTGxISChJyanHR2dIyKjGxubHRydGRmZIyOjFxeXHx6fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVbICACwWieY1CibCCsrBkMb0zchSEcNYskCtqBBzshFkOGQFk0IRqOxqPBODRHCMhCQKteRc9FI/KQWGOIyFYgkDC+gPR4snCcfRGKOIKIgSMQE31+f4OEYCZ+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 kedit-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBASCBPz+xPyqXERCBARCBISChMTCxPz+/FxaXAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARXEMgpQ6B4WnGzDgJHWWMYdkAwEF1QFKe2oqDZztr7GpfKjrvAAeFDpQq8ISIRYBotSoTUkiC2ostqYps49BSKIVfaBbcC4MMWcTAbU+iw21NBk+gjuj8CACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= key_bindings-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBISChPz+/MTCxAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANMCAoRy2IEuYIQDsrBld0NN4XaJF5iCppWxBGtCscEAbkDfH2wh+ogiudD5AhvoZWoJEFtckBTE1dzKKfQjMtUjfQUzizjeBN7HgB/AgAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 keyboard-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBISChPz+/MTCxAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANBCLrR+zCIGWCcI1cLpNCa5YHZsCmj2QTlxrZmmRFVSs4E7X13TqMTXsl36gSHuSIQQ+QYP0kncPCTokzWh3LhTwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== keyboard_layout-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPz+BAQCBPwCBMT+/AQC/Pz+/PzCxKSipISChAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARSEEgZqr1hUjFIEQXBZVogDt/XYWxgoEVFzEUt3MGNm7SND4aarPfBFQYCQmtpiTErh+ahMK1SqVHoYcvtUptX67SWDXTPXWltva5q0WfEs+WPAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 keystone-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBMTCxISChPz+/MT+/AAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM/CBDcHkoFQasVUIrBe8fRNDwMAWpjUThmtmxk0IYwOaPx/V6XG3hAjmsRa0Qkg6NSOVo6F0nG88g4TUNDpT8BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kfax-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/AQCBPz+/MTCxISChERCBFxaXPwCBAT+BARCRAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARVEMhJQ6C4imEzDkLIXR4ADqFAThYRoFu4ti6YbhfdFm+aEzWgAWhB5QyGAMEwWA4PlpyFCWwOkAhCgla1EqxXKbD7vSJnyuUXyV5JuOxtqZV0z+3+CAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 kfind-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBExOTDw+PExKTPz+/ISChAQCBPz6/FRSVIyKjJSSlIyOjGRmZNTS1Ozq7Ozu7AxyzPTy9ERCRBQWFIyqxPT29AQ2vOTi5IzG7DR2zNze3Nza3BQSFISy5CRyvBQenISmvBQitMzOzAQGBAw6rDR61Hx6fMzKzAz+/IzW7ASyvCwuLMTGxMTCxBwWFDQyNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAahQAAgEBAYj0ahckAoEJ5QgkE5fBYO0SeCOigkFE2DeEFgUAUNBwGBeBAcCMHirF4gnhBCBCE5PydqBBQVFhdTSgJPBk8YGRQaG4dCiQQcDh0eHyAhIiN+BHYXJCUNIggmfhUOAQgbJ6YCKGcVKSUaChwGHCYqCyuIDhkhGyIsLcccCL6TFxsNJ8fRLS7KvyNi2GIrAQwK1AsvVOJULi4AfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kfloppy-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPz+BAQCBISChKSipFxaXPyCBAQChMQCBPz+/AQC/MTCxATCxAQCxAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARWEMgZgggz5zAIBp9GFV8oSqRkikFanapBVgccGAiJBDWL74jd4UUxGBI/IcJQMigSimPSsMDcEFCFVkptKhCDgSBB7m4sA2y5eqqMF2YYKMBgys8nfwQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kfm-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBGRiZERGRPz+/MTCxAQCBMTGxPzerLy+vLy6vPyqXLS2tLSytKyurKyqrKSmpKSipJyenISChJyanJSWlJSSlIyOjIyKjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAV+IBCMZCAIQKoGw0C8MFEUqmgYrTwXL50GhtegcCgedr4AIpEYHhQKopEWSCwYw1fUeBQxGo3hiBCIUR2OxyAwG8OoD0hkICFABMiZKBKZ0GNkPiIUFBUuEoiIMisVFRZ/MWwqAheVfxICdZIpmZZ1kYIAMxcuJWWhKXl5Kn4hACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kfm_home-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBDw6PBQWFCQiJAQCBFxeXMTCxJyanDwyLDQqLFRSVLSytJSSlISChCQmJERGRFRWVGxubKSmpJyenGRmZLy+vOzq7OTi5Ly6vGRiZPTy9Pz6/OTm5ExOTPT29BwaHNza3NS6tJRqRGQqBNy6pIyKjDwGBPTe1JSWlDQyNOTGrNRiBGwmBIRaLNymdLxWBHxGFNySXCwqLKyqrNR6LKxGBNTS1NTW1Jw+BEweDDQ2NAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaoQIBwCAgIiEjAgAAoGA6I5DBBUBgWjIZDqnwYGgVIoTGQQgyRiGRCgZCR1nTFcsFkHm9hBp2paDYbHAsZHW9eERkYGh4eGx4ag3gfSgMTIBshIiMkGyAlCCZTEpciJyQjGxcoKUQBEhcbIiorLB4XEltDrhcaLS4vtbcJra8bMDHAGrcyrTMXHjA0NSypEsO6EzY3IzU4OdoTzK0BCAkDMgkIOjJlAH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kfract-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBAQCxAAAACH5BAEAAAAALAAAAAAQABAAAAInhI+pyxudwoNACiFbuBzHt3XeEYbiBF5mN5HpyayqVrY0hdj4vvgFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kghostview-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBPz+/MTCxCH5BAEAAAAALAAAAAAQABAAAAJCRI4ZwCYPo1gsiIHHxY86KXmWdiGkCA1Wp6Htc07NOsEv2oVyldLHbuBgEhORJhOxGEkkiLJybCZ3iqrD08hmF/4CACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= khelpcenter-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAASC/FRWVExOTKwCBJQCBIwaHFRSVPz6/LxSVOSqrNyanIQKDHwKDHwCBPz+/OTm5Ozu7JwCBMRKTMxubLxCRNTW1IyOjDQyNEwCBGQCBJyanMRaXNyOjKQODIRydKQqLOzCxEQCBNze3Ly6vJQKDDQ2NIQCBCwCBGwCBFwCBDw6PNyipDwCBKSipEQ6PDw+PJR2dMRiZHwSFPz29BQSFIwODJwuLMTGxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAabQIBwSCwaAQHBgFA4Cg2BwwGRUCwYxobD8YBEBpLJoEGMUA4VywWTaUQOmstww+l45MKM5/DAf0AIDSFFBiIHI3IEHCSDRgEOFSUAJhQNJ0coYikAKpB4RQwrJiycWy0uRQ2AKKQAL3wwKEMCMDEdGEMvWxIKDTICIzMQKZdDKQ0dMSAxBzMPGjRGGCkoNTYaNzTRThgnJ9pFfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== khexedit-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBMTC/Pz+/MTCxFxaXPz+xPyCBKSipAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARZEEgZ6rw4CB3wrJUggt03nANIoCUQoDDcvqJAaHXqunBxywFDZWArDHy4lOEwTBEKgYJRyeQJEIEnYrQsvU63abBKIYq2m+4s5mTeTLVRSFdmyy6kvGXijwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kicker-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+/FxaXMTCxDQyNAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANECLrcEDDKGYQV4+qbie9eGIJEVxTe+QmjUFgnXLLr615oF8x2v0I8DWpF2GV6slkLKSMdYT4nS0WgSkXYAWUbcXgX/gQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kiconedit-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAPwC/AQCBMRaBPyqXPzerPyCBPzCxPwCBPz+xMTCBPz+BISCBMT+xATCBAT+BASCBMTC/AQCxAQC/AQChAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVkICCOpBicZQoEwjAE6hgQQwvH81AU8OnfuR3QYDgcgAKhjGj8+UgzQkHHw+2mQlQpgEAkFInEYnGDhr/h8VPGYDQcjcZj/iiv4u84vQ6FQCISERETgxN2AX6AgoQThlBOkCR+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 killustrator-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBAT+/Pz+/KSipPzerPyqXAAAACH5BAEAAAAALAAAAAAQABAAAANHCLrcGzBK+YK4OAcAx4AXIURj4J2fJYhWh35pOHKoG8+mFxS5HimmXU8HBH4MQyJD+FI+kM3Ug9eENALQk9VhDW4c1y/YnwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kit-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCxCH5BAEAAAAALAAAAAAQABAAAAIghI+pFrHbXmpRMmoBxXB75IWcKIKk022ZunJtdlSw5BcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kjots-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPzerISChPz+/MTCxMTC/AAAACH5BAEAAAAALAAAAAAQABAAAAM8CAHc7kGsR1mc9d1Md/icIgXDB1YXMZQnZBJEIbdKABPGTbSfnuc8mw8W1OlotYER2fgod5iMKRqiNvwJACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= klaptopdaemon-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+/KSipAT+BISChFxaXPz+BMRaBPyCBMTCBDQyNAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARtEIBAq5w1TBGEGIM2ESTlVUNhaAFJUAcXgAXCZkFyJEoiIArWYQjj+Xi2yfBA0SU6CuAts4MCk4EdcxbznFhOCsjrWUxRhbRBBk48Z6kCZ2GeuN9xucF8FqcEBnt1OW4saSp7IoRPEjgiGBV+EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 klipper-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFQyDEwuFEQuDISGhFRSVEQqFEQuFPz+/PTy7Nze3PT29Ozu7DQyNJx6VIxuRIRiLEwuDIxSFHxSHKSipLSytGRiZGRCHDwmFOzm3HxOHIRWHOTazHRCFHxOFEwyFNTKvHROHFxeXJRqLIxWFFw6DFQ2DNTCrIRaJJxuPMSynHRKHIxqRMSqjGRGHMSifJxeFKyGXHxKFLyaXKyObGxGFEwyDKyOXIxeHKSOdFQ6FIx2THRKFFw+FKx6NKRmFKxuFLyCPLyOTLyabLSefLyijFw6FJRmJIxWHHRGFFQ2FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfFgAAAAQIDBAWIiAMGA4IABwgJCgUICwwKDQ4PEBGCEQsSEwUUFQQWDRepGJ4ZEggIDbENrxobAZ4cHa+7uxAeH4IGICEIIsbGFggjJCWCJicovLwpIcAAGCorCBbc3AoILB2rgy2u0q8OLrcAJS8wr8nJrzEy6yUz79sivDQ1jQA2buB4tU8eghw6xgnYwePcqxcdbAjq4eMHECA+ggiZMYRIESPjShyBgQPJBB48OsiokaTDOoACItgwYULJhw8BbIzzEwgAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kljettool-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+/MTCxKSipISChFxaXATCBDQyNATCxASChAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAReEMg5Q6CYBiFsxhvXXZklimRlDWenBQNRzKJRXCsxHPFcIDGcILYbGHqzAY41NCQSiuNgMLPAmNTElFoFWKecqe8mCRAIq6nt5imb0TC2wZByny3zdslMr3+8fgB+EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 klpq-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBMTCxFxaXISChPz+/ISCBPz+BKSipAT+BAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARaEMhJqwUh3xqEz8EWDKT3aVNAFAVBDqYQYitbjARhGDJt34Nc4SBAZAomoDAhKAwyTZZp5XE+O0lp9QVFeLNWUpflJXheTww2ijiLKSBPW/C+xOmzjQRU8UcAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kmail-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPyqXPz+/PzerMTCxFxaXIQCBPyCBAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAReEMgJgrWU4iAGIUFWFYMldF+okUPJeeAUDEY7FFzXqnNdkIGDgHAKzWgsDuJAFBhbtd1peTAWDFjpaZg6skonYfOZzC3HlduuMj1UZUDZ6RMblTTDokylQYsyFwB+EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 kmenuedit-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBMTCxAT+/ATCxASChPyqXPz+xMRaBISChAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARLEMhAq5UY2B3yFGDIYcFgnuNErGwQCl1VzHSJBsbBUSxBIbnEC0YrxICHhFKZCiATlldn8gSlNE7YEurRQHdd19Aa3m6nmV0F448AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kmid-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/AQCBKSipISChMTCxPz+BAT+BFxaXPwCBATCxARCRAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARUEMgJgqVYWsFv3lwoeFMwEIQYkkFhouoQlIFhHvCgz9oxjoeDblc6+Q4B4ZBXCSBQx+GIZhNAOURaACsYypq0kNeSSLC2uxm5fGZqAgqFO0OjT/wRACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kmidi-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBPz+/Lz+/CH5BAEAAAAALAAAAAAQABAAAAIzhI+By7oBo5RH2GvDRRhre0xiVHXZVpqfEI5iKkQxalzQIIPGhI+pSAN4cjqA68VIHvwFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kmix-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBFxaXAT+/DQyNATCxMTCxPz+/AQCBKSipASChAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARWEMgJQqCXziDG2JoUEENhZBkmHIWJVptAmqcIW/Js1MiF56TBzkckAAcHoa9nMRKeA4TyJk0knsHhTeK5khBaH2VwLYVh40TJhQ6RzeIQV32Quz8hfwQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== knewsticker-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAAQCBPwCBMTCBPz+xPzCxISCBKSipISChCH5BAEAAAEALAAAAAAQABAAAANTCBCsysEpseQDI08KSPdYNmwUYSraUDRC64iAMbIuLGtOS423BhKFmgj2C+5EhsOoWEsOnB0FsKl0jnLUp3IG0O2sMNpRVHBAJpjyA8KOmNsMfwIAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== knode-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIYAABwaDAQCBPwCBDw6NERCFJSWJAwGBLy+rPz+7IyOJJyeLBQWDIRqZIxydPzCxDQuHPTWzOSypBweDKyqLJyWJKySjPTOxKSCfOyCfOyKhJSSJJSSLFRWTDw+NOSqnOR+dOyWjOzGvNza1ERGFJSWLLy+ZPTGvOTOxOSSjOy6rLSypJSWjKSinAwODHR2HISCJOTWtPTe1Pz+9Ozu5IyKfNzazPy6tExCHMzKfPTy7KyupKSmnEQ2HHx+HKSiLKSiJPz65OzuzOTmrKSmLIyKJLS2TPTyxOzuvNTSlLy6fHx6RLy+RJyaNLS2NNTSnLy6lLy6dMzKpGxqXCQiDKyuNMS+PLy6VMTGPMzKrOzq1CwmDLy+PMzGTNTWxMzOxERCPKSiNCQmJERCRERCHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAIALAAAAAAQABAAAAffgAABAoQBhoOEAgOGBAUEAocBBoOLBwgBBAkKBAsMAQ0ODwOWEBEBEhMUFAQVFhejCBYYGRCGGhsKFBwdlh4fICEIIoMjBRQkJSYnKCkWCCorLIMtLgUvCjAxMjIzNCw1KoY2NxovFDjbMjk6OjuHNjw9Pj8lMggIQEFCATaDBD4JhhApgsDIESFIkigxJGDEkiJFmDQB4uQJFBxPokgRMIVKkypFrFxBgCVjlnuXtARQUGTLFS4yunipgRLBF0I3moChgsQeAg5hxDBMNCUAlyAcOCBKxJTQmKVNBfgJBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 knotes-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/AQCBISChMTCxPz+xPwCBPz+/ISCBPz+BMTCBIQCBAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARIEMhJZQg1z6vzxR0VCKE4gCE2lhcRnF1LuAInBjNRfDMn64WCQRCcHS6IRE6nyB0Sx0ACkcwloFiflKp8Pm2bbRblkYJZHX8EACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= knotify-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+/Pz+BPyqXMRaBAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMyCLoQznAFIUKE09krZ+VS9XBaMBBbZKIBUaSYa40kTIPNhyvazje+G2gFI8l8jaLCnwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== konqueror-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxONCROfCRKfKx6LNy+bNTOpGSS1DRupAwyXBRSnPTSjPTqvOzqzMzSvHSSlKy6ZDxutAxCpBQ2XBxepLTKvPzqzPzy5OTShLS2dLSqRFR2jBRerBQ+jOTixOzetNS2XHx6XDR2tCRexBwyTDyKzOTavPzq1OzKdCx23BRKtCQ6VCQmHFSa7IyirOzSnGSGpIR+bFSO1DyK7DR+5CRixBw2VDQuHFye7IS27NzGXISuhEyS5DR25BRWxBQ+lBQyXCQqPCxSfGyu7GyerKy2ZFR+rERqfCRmxBROtBQ+fBwuTBwmNDSW9JyabLyqRIx+TExSXBQ6bAQCBBQ6ZBxapDR+zBxq3LyaLJySRHxqPGxeNBxGbCRmrHRyRERONDRKNDQ2JCQuLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAeygACCg4SFhgABAQIDh4MBBAUGBwgDCYcKCwwNDg8QERIThRQVFhcNGBkaGxwdoYMDHhcXHxggISIjEiSvJSYXJwsoISkpIyorLIIDLS4WLzAxMjM0NSo2N8o4OS46OzwzPSk+P0BBgkI8Q0NERUZHCEhJSktMgwk4Qy1NTk9QUVJLphCiUsWKlStYsmjZQiJgIS4KuijQ4iXAFxYCDVFJwGUFmDBhMjYSw0KMyEYoBfkJBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 konsole-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXFRSVPz+/PT29OTm5OTi5DQyNDw+PERGRExKTHx+fISChIyKjHRydFxeXDQ2NCQmJBQSFAQCBERCRMTGxHR2dGRiZExOTDw6PCQiJAwODCwuLFRWVOzu7BweHAwKDCwqLHx6fBQWFGxqbGRmZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAanQIBwSCwKAwKkMslEAgSDqDRKqBYKhkNgcDggEorkMrDQchkNhuOhgEQkk0l5S2lUGpYLJqPZTAwMHB0DCmhqAW0Rfh5zAxgOkBcCFAcfIBMECxwBBAEPFw8dChkhcBMDDAcdnQqtFKSWcQMimx4dGRkQBxGxsg6bBQEawx8jl3GnJFoFHRNXVVNRJYIFDAsL1tgiDiQXFx0HABwcXeQH5OjkRutEfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== korganizer-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBASCBISChFxaXPz+/Pz+vKSipLy+/MTCxPz+BPyqXLxaBAQ+BPy+vAAAACH5BAEAAAAALAAAAAAQABAAAARmEIRJqw1ikM37FsFQjMZ4lAVKBESBjCYsFiuBkkk5KG1dJL+CZjBYMES+l2x3RCBqtxHBOFD6DkHmAQj0yXgzmFdIhY2erBJBwTiczDSWq0Eg1gvYrvyHxcMdUEojYWIYHocbDX4RACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= korn-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/AQCBMTCxPz+/PwCBMQCBFxaXISChKSipAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARSEMgQpL03CEExDkO4dR6ghSFBkJa2CSlRcNX0voNQ5Ebn3pvdAWHo/W6IHUJwGFCAm+SrSTm+ZgcY6XnDhlim3wwxKNYymiX17HmCSxO4/OKPAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 kpackage-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+xERCBMTCBISCBDQyNAAAACH5BAEAAAAALAAAAAAQABAAAANPCLoR+7AJ0SALYkxd79za12FgOTlAQBDhRxUFqrKEG8PyOqwEfMeKwGDI8zVGul0vFsAFdaxB43ecKZfUKm1lZD6ERZgBZWn0OpYvGeJPAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 kpager-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAAQCBPwCBFxaXISChASChATCxKSipMTCxDQyNERCBPz+/MTC/AAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAARWEMhJZ7hADFI4+RpwBYBxFJ1HmMiYJUgiJPI8Bwmp7HyvyBOfMCHR+QwzhAAhMvZKSFgRIOwtJczqboFoBasGGVNUKVNGaEyTlEYL1sX2pYXOyO8XfwQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kpaint-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAPz+BAQCBMTCxPz+/PwCBPzCxPz+xPyqXASCBMQCxAQC/AQChPyCBATCBMT+/ATCxASChIQCBKSipISChAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAV1ICCOYxCI5kmigTCYBKGW7WAH8QyYrn3LNFesYDgEjCVXIRYzGgWqgA2BICQUx9pMSkUssgsbFOWighW+7c24KDAKDccjCjVCHAEGo/GYl+wPLwwRfF8oT2mDAwuGWVJiARERAxITJkhaJhMSlJY7NDQpAH4hACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kpixmap2bitmap-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAPwC/AQCBMRaBPyqXPzerPyCBPzCxPwCBPz+xMTCBPz+BISCBMT+xATCBAT+BASCBMTC/AQCxAQC/AQChAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVkICCOpBicZQoEwjAE6hgQQwvH81AU8OnfuR3QYDgcgAKhjGj8+UgzQkHHw+2mQlQpgEAkFInEYnGDhr/h8VPGYDQcjcZj/iiv4u84vQ6FQCISERETgxN2AX6AgoQThlBOkCR+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 kpm-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBMTCxKSipPz+/ISChAQChMTCBATCBPyqXAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARbEIBAa5BYUsHF+FQ2EUTHfUOoFQVpeuAVGAbrnmg603U7FD8UxXDgGQgoYMyAIBoSyI9Sx2seoj/lRlDFTmUBDs0L0gg2CGwFs93oWJdMOwCPiybhguout2f8EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 kppp-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIYAAAT+BGSOhERadDxKbDRKZExWXKzG/KzO9KS+tER+lBQyNERaVOTu5PT6/OTy9Lza5LTatISylHSilCQ6LNzq9MTa/LzevKzKzIS6dBwuZISi9MzizLTW3Iyy1IymjHyGbCwuLDRGXHya3HSe9Jy+/MTe5Pz+nPzmhOTSbGyGXGx+XCwyLHyinISe/NzifFRKTFRqXCQmJExSVFyafFyC9MTCvAQCBMTCxExKTDw+PMTGxLy+vNTS1Ly6vMzOzNza3MzKzHRybERCPDQyNPzCxPQODHR6dAwODAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAengACCggECAwQBg4qDBQIGBwgJCouDCwwNDg8QERITlIUUDhUWFxgBC4mKGRoGFQcbHB0eHyCLISIjJCUmJygpKiuLEywjLRYuLy8pMDGLATIzNMk1Nck2lCDJN9TcLziKOTg63DvcPD0ygjk+P9zcQDVBQekAQkMgPjzcPfLy1wAgiBQBAYIHkH5BbPwTBGKIQBBBjAQBsXCRDYJGZFSkJOhIM45+AgEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kpresenter-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwC/AQCBMQCxPwCBAT+/MTCBASChATCxPz+BPz+/ASCBAT+BKSipAQC/AQChARCBCH5BAEAAAAALAAAAAAQABAAAARhEMhJq70YhM2D5UIYDARHBUWxEcRgHKgncWyLuPEc1MOAJLfBRsNSEBYbH8kw3BEUyABjZHzJdsiGI6AYLBQG5qykDSy+jwdLpimj1aVhe7tIr00a6Q4uP02dfRVygRZ+EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 kruler-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBFRGDPTijPzmnKSGDOzWdPTahOTGXOzOZOTKXNzCTNy6RNS2NMyqHNSuJCH5BAEAAAAALAAAAAAQABAAAARkEMhJKwg4643FEIQHimHRfaiYmoFxvMLhwi5r3IaA37rBIomgABhEDBM/hHLJVCBYCwFjYVxQBdYFi8GQertSLqshaJgFZbK5wXI4BO63W/Bwt+HzON7BKvj/gIAcgxoWhhN+EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 kscd-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/AQCBKSipFxaXARCRPyqXPwCBAT+BMTCxMT+/AT+/PzCxASCBAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARbEIRJa5Ui672nsNYgegFhFoRhCuJAEgcsE+wYfHIc0y3JbT2QsOJCGG+/zyShMCICregEsUgEnNCe6/rsPkPTY2LxZLEOh4DEqbBmRQyGen0kjgB4ySSPp+D9EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 kscreensaver-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXAQCBOzu7Ozq7OTi5Pz+7Pz+xISChHx+fMTCBARWlARepOTm5ISCBNze3ARalARanKSmpARSlHzC9ARGfLy+vKSipARKhAROhARKfJyenNTW1AROjARSjMTCxJyanNTS1JSWlMzOzNza3MzKzJSSlMTGxLy6vLSytKyqrAT+BIyOjPz+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAalQEBgOBQYj0fhYEAoCAyHqPRgDAyIggPikOAeFFVCYMHImqnfaiPAKH8VcLij+ghAGJFFlnuUCAJ1ExR5AnACFRUWF39/CxETXQoYGRoaFht/HAEdE2AeGRgVFBUfIH8hmx4doBihGokifyMPAiQcISEjJR+7HyZ/JScfFigpKSoSFxsiKywCAEjR0QDU1AIJFi0tFgnP1dYJ4QgJ4+Xe1tLTAH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= ksirc-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAAT+BMROTPz+/KQGBFxaXAQCBDQyNGSGzDRivAw6lAQmbCRGlAw2jHSS1BxGpAwiVGyO1CRWvBRKtJSq3AxCrEx2xAxGtAw+pAw6nDRmxAQmZAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVYICCOQBCQKCoMaRsMbCvPNE3cRA0QRWEciIQigQLyfAtGqtFwPI6GFgQReex60WJEYr36UpOtQgQlUQAVieUyLoskY8Bhi3liEZJ6MaOmWCgJGjYGhCl+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 ksnapshot-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/AQCBATCBFxaXISChAT+BASCBAT+/PwCBPzCxAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARLEMhJKw3YViw6HkRgBUVnCkG4GUV5otthsO6A3KJEHm6R3AOYTtAy2QqzHCDwMpiSk8DsxIFGpc6T9YJ9GpSb7laDSYI1yzNa448AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kspreadcalc-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPz+BAQCBATCxARCRASChAT+BMTCxFxaXEQCBPzCxPwCBAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARPEIBAq5U4iM17wJMwjORIfJkYFCs7nKA2rJQLp0Su66ikGcAg8OYTGA6BA/KAIIYsFudPGJQal8uAFVqxUg2JxBYbUGh7k5J6BppwKyB/BAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 kspread-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBAT+/Pz+/KSipPz+BAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANFCBDc7iqIKUW98WkWpx1DAIphR41ouWya+YVpoBAaCKtMoRfsyue8WGC3YxBii5+RtiEWmASFdDVs6GRTKfCa7UK6AH8CACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= ksysctrl-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBISChHx+fPz+/AQCBAQC/AT+/AQCxAQChAT+BLy+vAR+BAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARYEIAgqK1YzsG754QUDERpmkEpkkXrtoK6EcVgHIibhnNx564Yb0TDvQq7FQ34EiqPOhnREqhWSUPsyZSQAbbg7GcMEgwUiYVivTa1R+y4XEGoWO/4AMAfAQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 ksysguard-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBExKTERCRERGRAQCBFxeXKSinIyOjJSWlKyurKyqrKSqxPTy9LSmxNzS1Nzm7JyitJyipMzOzLS2tOz6/OzW1Ozy9Oy6vNyCjNRydMR+lNza3LSurFReZMTG3Pz29OSmrMx6hDw6PKS2zMTCvOyytOSWnMzi5MTa3NTS1LzCvNTe5Pzm7PTK1PS6vOSapMyKjNTy9KzCzMzS1GxqbISKxOzq7Ozm5Oza3MyytLzS1Nz29OTy9LTS5GyGtOTe3MzKzOT29OTm5KS2vKSurNzy9LTW5OTi5Mza7NTm5KS61KyytOT2/HyChHSChHx6fNTy/LzKzMTCxLS+vMze5KSmpLzS3Ky61JSSlLTGzLTa5FRSVJyanKSipJSWnJyWlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfagACCggECAQEDBIOLAAEFBgcHCAgJAYqLAQoICwwNDg8QERKXjQYTFBUWFxgZGhsJHJcdHB4fHxUgrCEiIyQCjRwWthUlJiG7IycoKQQBKisfLC0uLzACJzExMjMBNBI1Njc4FTkBOjs8PT4/3UBBQjc8FkNEQTtFRUZHhyQySEkHOAyxgOCcEhkSLC1ZwSRGEx1OnBx4EgNKFCmKAkyh0uNADBpDOpyQ0YNEAEJVIFjBZg/bFRIRSAXAwiFLDyNaesiYEJMRgS1cupDg4OXLFlI+DwkQgBSAn0AAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== ksysv-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+/MTCxISChIQCBAT+BAAAACH5BAEAAAAALAAAAAAQABAAAANWCLoQzlA5IVyIK1S9L7PDsFHBIJXDFFaViYYEUQpy6orEqq12Aw+FmkjQQxEKwQCBSCz5BrGYkuc06nKU4s8gW4q0UAN3+q3CZJfJRhJ6fDwZOGbhTwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== ktalkd-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBKSipMTCxARCRFxaXASChDQyNATCxISChAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARYEMgZqqXU6gCuDIJQDQTBBQX3hUFpmN2hFaxhIPCJDrRo46dPglf7BTvDXsB2OwaSCd8tZ0kWgZ3Uk+hDvHRV5bfyybACPNmkY2EVZKpM5UBPre8fD94fAQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 kthememgr-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBASCBATCBAQCBDQyNPz+/MTCBPz+xISCBAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAReEMhJaw1V6Bs0HgIWYFMnhSERkiU6ekM1FO9IGMcxIFK3jgGDzRADhAypQipI7A0OId1IaGhKntHDjWogTLCB3JbpvULD2ir5i0SPDYjy9ZgWDuQUwqBLLFq+ehZ+EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 ktimemon-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPz+BHSG5PxSVDRW9PwuLPQKDFze1AQi7CH5BAEAAAAALAAAAAAQABAAAANDCLrc/lCFGeKi1YktAH5c92mcR4HloA4P4RLAyjovLLdvvD5FX+gqgGFoUPh+N2IRcAQcngch0ehzQqVDas/6xBb9CQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 ktip-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBGxubFxeXAQCBOzu7OTi5NTS1PT29Pz6/Ozq7Nza3PTy9Pz+/Nze3MzKzMzOzOTm5MTCxLS2tKSipNTW1Ly+vKyqrMTGxJyenISChAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVwICCOQRkIY0oORFEYqCoGw4EcSaHEarAgDESu4RioBIMfA1doPIwpZGJBhTQMEWh04GoqDBLtCKkYNL5hGUAwoZQfFYs46lBQLnK1SICJUCR5egMZGBgZcyoDGAwTh3oiAxMMhogpioyOjwADnIh+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 kuser-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBMTCxISChAT+BMRaBPyqXARCBPz+/FxaXAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARLEIRJa5Ui673nsGAgeKE1Bl9AUEXbiqTlFlZaGUZoszm4BzhDAVf5BYbAXI+TAR6CS2ZGSZSEiIIqYIsSIEaJ7GRrlY7J1lKA7I8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kview-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAPz+BAQCBPz+/PzCxFxaXPwCBPyCBPzerPz+xASCBMTC/PyqXATCxMT+/ATCBASChIQCBAQChISChMTCxKSipARCRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAV0ICCOYxCQaBkIwpmKJsu6qDkIREDMZFwUAYNwRVuxgLfDAUGEsRIJo2LRapUE0ABDsa1aAcZoo+stsnIMwcDQcDQUV9MjF4Q4GJFiQJJuGSYOFHkwezJ+ExUUEicmYDITARATAoomLiuQJhKTlTRgepYBfiEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kwin-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAAQCBPwCBFxaXISChASChATCxKSipMTCxDQyNERCBPz+/MTC/AAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAARWEMhJZ7hADFI4+RpwBYBxFJ1HmMiYJUgiJPI8Bwmp7HyvyBOfMCHR+QwzhAAhMvZKSFgRIOwtJczqboFoBasGGVNUKVNGaEyTlEYL1sX2pYXOyO8XfwQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kword-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPz+BAQCBPz+/FxaXISChPwCBEQCBIQCBMQCBMTC/ASChARCRAQC/AQChMTCxAAAACH5BAEAAAAALAAAAAAQABAAAARiEMgpQ6B4WnGzDkLIeVs4DAIBWFcpnKJVzCUcz8ZxVOKN/AWNKRQo5HQYELHwQxQSHR7HqDuwMIRisxBQLBbRFdUaYCwYjUZHywIxGI53K0jolRkJdLkhtKwaeWpJYW0AfhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== kwrite-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBKSinJyOfPz27Pzy7AwKDExOTJyWlERCRKSelPz69LyyrKymnPz+/MS2fDQyJAQCBOTazLSiXOzivMS2jKSSVOzmxPz25NzSpPTu5KyebOzixNTGjOTWpMSydMSybCwqFGReVKyaXNzSnGxeNJSCVMS2nPz23MSuZIR+bJyShLyqnOTOtGxiXIR6XOTSvIx6RMSubIyCdKSalMS6pOTWxMzKvKSabJyKTOzezHxuPGRmZKyurMTCvPTq3AAAACH5BAEAAAAALAAAAAAQABAAAAajQIBwCAgIiEhiYEA4FgwHRDKhIBAWz4OhgGQ0FAPHA7qFEBONb0Qy0ULeQ2+aUrFcMI+3GYBOZzQbHB0eHyAhIQByDREiEwMjFRIkJQImAgJ+jScjHigkKSorLC0AKg2NFSMoki4qCy+IQgITKDAxkjIzNDWkQxQoJaskMgk2Eb1DNzgoOCoHDDY5yEIwJToAOzw9ET7TQiREAhkZ3kmy5QB+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 laptop_battery-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+/KSipAT+BISChFxaXPz+BMRaBPyCBMTCBDQyNAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARtEIBAq5w1TBGEGIM2ESTlVUNhaAFJUAcXgAXCZkFyJEoiIArWYQjj+Xi2yfBA0SU6CuAts4MCk4EdcxbznFhOCsjrWUxRhbRBBk48Z6kCZ2GeuN9xucF8FqcEBnt1OW4saSp7IoRPEjgiGBV+EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 laptop_pcmcia-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwC/AQCBMRaBMTCxPyqXKSipFxaXASChISChMTCBPz+BPz+/PwCBAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARfEMhJaw3Y2iDGyJoUEIVRfIHGEcaBHCc4jcWbGG2cAuuhKIZE4mX68EgI3M/wORgQGAHr4HICD4NCKoBIJqsv7w6DKDgNi0VuN+O+GIxFl00hlxjakIhbo4cwfnoWfhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== locale-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAASC/AQCBPz+/MTCxISChMxKTKSipFxaXERGRGxqbCQiJDQ2NJQaHMwmJDQyNFRSVOR6fGwSFNxSVKQqLFQODJwaHOyGhOySlNRCRMSuBPz65PzupPyCBJyOLMxyJOTKRLSiNIR6JExCFGxaHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaPQEBgGAAYhcWjUMAUEAMDQtIIZRauBaZhKhwIsFjBgFu9HgKHrHNI9QYQCQQarWB313D5Ik68BxgIDQwOCgcJD2wBWwENEBANEQwMEBITFEIOQhWNkhENFhcYl0l/GRobHB0MGBAeo1QdHxsaICEfpyAiQlQhICMiHyMgs8FKASMjRiK/yLrGStDRXNFGfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== looknfeel-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAASC/ERGRExKTLy+vKSmpAQCBPTy9Pz+/IwKFLQWNPT29GwOFExOTIyKPHx2NPz2pIQSHLwWNMzGXFxaLLSytERCHCQmJNze3GxubLS2tHR2dAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAWNICCKgVCWYwoEwUAMhXEQhhocRuHCMpIgiJVBptC9DojDIrFYwRS4wgGJZAIYuwL00Ej6FjOGEXZwPByQCNjAyrnKj4NkAqYUBIIoXC5pVGYUFgIXU2Z8fgdGFhgZiRqHf1EDFgCJGAcafX9aUSIFlxoFBX8vMYmemKJSY6Ijn6oHF26tKbAEGCaUKX4hACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= lyx-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBAQChARCRKSipASChFxaXISChPyCBATCxPyqXMT+/Pz+xPzerPz+/AAAACH5BAEAAAAALAAAAAAQABAAAARZEMg5Q6C4BnGzHsRgeVZRGIbYaekxuAFijUGRBOqMKPxlJQsLQxjoVWyWBsMxNEp+iRuj2VvVCklHLCZjiRrawGFmNQUajQ129RwYyCMSau2pcNh1AB7jjwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mathematica-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBISChPwC/FxaXIQCBAQCxAQC/KSipAQChPyqXPyCBEQCBARCBASCBDQyNCH5BAEAAAAALAAAAAAQABAAAARlEMhJ6wxChiFFCBUhENtQGIcBUghWDsHxWck7wMpKfXz/ZYBAYeCpKRQLWwkjMCpQJQ3TE8gdUgxPUMDlflINhzfocJB6BNEDqLnKpgRLTJZjBuIUAf1TExR0EyRASWmAFocAfhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mouse-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAAQCBPwCBDQyNKSipPz+/MTCxISChPzCxATCBISC/MTC/AAAAAAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAARSEIRJqw0Sg32rAANBFNwlhIQhGkNGAaSaouW0iYUBEIdYgzsUIqHAuWAoQlGEE9gMJKaU8IPupqLWy3qVkioAFqkLc9nCg3G5oxFr2ecavOOPAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 mozilla-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAASC/JxqBHRKBGw6BHwuBHQuBKwmBKQmBIRWBGRGBMQeBKwaBHxSBFQ6BDwaBEwqBEQuBGQuBFQOBGwSBGxGBHQ+BOQiBPQmBLQaBKQaBCQGBIwWBLQeBDwKBHQSBGQ+BIRaBHweBIQWBNQiBKQeBJw6BPxGBNQuBLwiBPwmBKweBIQiBJQmBHwyBIxeBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZzQIBwSCwahYHA8SgYLI2EwpMoMBwQU2FCsRAYGQ3HwwGJSCYPCNnRoAgrlgsmo8hkLJpNpEjhbBYdHhYZEh9HICEiGRMjJAxPJSYmJxkoSocjKSorExYNSwMXLAwgDhYVSwUtRAMORwGfRR8uRpdGWEJ+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 multimedia-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBAQCBIR+hKSipPz+/MTCxMRaBMTGxOTe5MzGzNyytPyqrPyurLz+tKzqrPTy9LSytNTS1Pz6/Nze3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAWAICCKQWmOKFAKQ9uWacAOJcEWQjDKrxHYJZxONRAQaL+c76DjyY4D4A+RC9B8xkPiQKCySsjAQZAojHMva9pk8iGrCsWC0Wg4HCvT4wApyO0FEAcRJhKGhzUEioolDw8TgYQBEYITCIQqE4IRCnQOEXyYJAFxCwt1dzAxbCcjfiEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== nedit-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAAQChPwCBAQCBPz+/MTCxKSipFxaXAAAACH5BAEAAAEALAAAAAAQABAAAANDCBoK8TAC8Vy8QUyGr9BaFwmDZonZp66sIhBwLBMFlRl4rhv1IxiDoHDYuw1yw2Dxl0wugTqnjdkUPmezJWv7QXX8CQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 netscape-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIYAAEyStPwCBNTKrHRqPAxSfLR6VNzWvAQCBEyOrFxGPMSWdKx6XPz69Ozm1PTy7NTOtOTOxKRqRGxCJPz6/MzGnMS6jDwmHEyGpPz+/Hx2bGxiPOTexFxWNLSmhMy6jLyGXNSqjHxSLLyuhMSyhLSqhDQeDJyWdJyOVNTKtPTu5KSONMS+rLyqdMy+lFxSNOTezKySPEw+FEQ6JKSOPDw6LNSylHxSNKyWPLSeXExGLDQuFIRiRCRCVEwyJAwODLyyjIx+TNzaxMy+jBwaHNzGvMS2hMS2jKSWXGw+JFw6LKR2XCQ6TDw2HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAAfVgAABg4QCA4SIBAQFiAYHiIQICQoLAQwNDg0PgxARg4oSChMOBg0UAgYVBRaDFxcIGA4ZGhscHB0eHISKoxkfARsHICEiI7oBrg0kGiUfpCEBJiIngygbKQ0bG5kjKisbFSwtAi4HLx0cBwYiMDEyJh4zMjSKKBQuNTY3Mb8vODk6kLky0GEHjxUyeiigMMPHJ0UCKvw4sQFIECEqhgQUSCSChRFFWhg5MkMjkk9JlJRY4uIEixk5fOhAsuOkqyFLXF1oQYOJTiQIAigaqohCD6JD/QQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= noatun-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBCQ2PARehAwODASCtASi5ASq7JTK5PT29MzS1JyipISGjAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARlEMgJgrg3zDHkCEQoEhrnVYXBDUVRdmagHjT7AnExHPtg3LldzYXr4FA6juHnMXZkqaiGMpEtOdOmETpAIEy473fV9Xphq7P6DEgMFIpFWm1sJ+4JBec8SFAnd3pveH+AeHcSfhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== package_applications-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAFxaXGRmZFRWVARehAxehFxeXOTm5MTGxKze7JzO3ITC1HSyzGSmvFSWtESKpCx6nBxulNze3MTCxAQCBByezByWxBSOtBSGrAx2nAxqlARijARafARWdARSdARKbARGZARCXOzu7Pz+/Pz+9Ozu5Nza3Pz+7NzexPz+5NzivGxqbGxubNze1NS+vPTCvMzKzLz6vLzevPwCBNzevAwOBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAADIALAAAAAAQABAAAAamQEBAMCAMikfjQMAsGA6IhGLBaDgeEEJEMhFIJBRKxXLBYDKajeTQBQAGG05n7vl8QABBNyTq+/8iIyRdJSJrgCMjJiYnhCIHEn+JiygpXQaGB32JKgErKiuNAoV+iQIGLBItLhOOgYkrmAYvLikwl6+Lo5gTtjFdLMHCKy8vEyITxV2tzBMFMTCWIgYlEzLX2NcwMy4vstngAS4tLyUGNODprdl+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 package_development-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAASC/GxKFAQCBNSyhFQ2FOTGnJRuNOzWtPz23FRWVERGRJSGNMyyZHRydOzu7PTy9Ly6vOzq7Nza3JyanMTCxHQCBLxWVKQaHOTm5NyOjMxqbJQSFHwGBDw+POTi5LQiJJwWFPz+/Pz6/PT29NyWlMReXNyenLQqLIwSFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ9QIBwSCQGBMWkMDAgKIuBgsH5FBIO0+oSka0mFAsGtdpwLMbPxONBgCDJEQkEMnkn1RLKRGF3+CtCDRJ7AoUSEgAWFw+AChB8hYUYGRobHIwAHZGbHh8gayEhIqGiIw9+GBgSJBoliiGUrhcOJq0WJyAbKBUhnrocDr4ofkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== package_editors-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBLS2tHx6fOTm5Ozq7OTi5Hx+fPTy9Ozu7PT29Ly+vMTCxPz6/IRuPHROLPz+/LyOdLSCTNSmnOS6vPzmzISGhExOTJSCZPTSxPTKtPS6jPSujNyKZGxqbDQyNDw+PHRaTKRqVLRqRLxqTMxmPOR6NKyurDQqLExCRFxKLKRSFNza3KyqrKSmpDQ6PGwyBNze3NTS1LSytAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaWQIBwSCwahwFA8kgMOAVLpjMgGBCixamgECAYsELtoUAuXJtPRCCRMBu44ecBoVC0F2aC8qkIKBAICQx5X3INh3UMbQMOD05/AQ0QDQoMERITFBUVThZ1Cg0XFxgZGhobHB1KHp4NCR8gISIjJCQlJmGsCAULAicoKSoqDytIrAkGBCwMLS4vKTBNrAUJCzEBMjMuM35BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= package_favourite-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/AQCBPz+xISCBMTCBPyCBMQCBIQCBPwCBPzCxAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARYEEgZwrQzVyFq6Bj1gQOxgcBYDSzhnl7Azm7tpWT7VhdHmoFXzweqmYZE4I5C5AQKhkMAYbCMfM9EIWBAIKzNLNRbTRHCBUT6ewn6TOlyJuX2sOftS8YfAQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 package_games-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/AQCBPz+xISCBMTCBPwCBMTCxMQCBPz+/KSipISChAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARaEEgZwrQzVyFq6Bj1gQMxgsBYDSxhqunKtu5bpSQdFDfFkS9DgHD5cTwBIdFnFLiSw2IzGGX+AocDNHQ6GhCJQCJsGRqThm/CoMBUCNc1W9HWmD2Jdsh+CfkjACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= package-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+xISCBMTCBAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANECKoR6ys2IVqokF08yMTA1gwkYX5WQK5ma4VceTYPxXnBWdtY6+0834/Bowgzm6APWRQcH4TiMhPK2WYRiZWW7XK7/gQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== package_graphics-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIYAAASC/MQmJPz+/LwuLLw2NLQiJNTKVNTOZOyydNRaXMxGRJQmJFQuXFRypFySdHS+VLTOfNzWhJQeHFwCBGyGtHyqlIzKdPTapAQCBGRCbKTSjOzqxLzG3MzmxJyanBQSFJSSlBwaHCQmJGxqbFxaXNzmxPzmzOSenExKTLSytAwKDAQGBMTS5LzerOSaTFRWVHR2dJzOhLTKdNyiNDw6PFxeXDw+PLSmvKS2zIyynLzSjNTKXNSGNIx2lIx6tISavNzSbLwmJHRWfNzWfIRurIyexOSmPJweHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAejgACCg4SFAYWIgwECAQMEA4mCBYwGBwgICQoFhowLDA0ODxARCAQSkp0TgwwUFRYHFxeLARITGIUZFBobEgUBC7aRHB0eBcC3iRgfGAIgISKRGCMeIhgkJSYniBkoKSgqKywtES6bgy8iMCgYyhwxMjOb7Bg0NTYr7Dc4OTo7PPIrQoRgJ6iHjx8xgMwIEgmAkIMxhsw4lYgBkSI5LEQwcsRPIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 package_multimedia-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxaXHx+fHR2dGxubISChNTS1MzKzLS2tLSmpNSytAQCBOzu7Ozm1Nza3MTGxNS+vOy6vPy2tOTStOzq7Pz6/Nze3MTCxOzOvNTqvLT2tDw+BOTm5MzOzPy+tLz+tLz2tOTi5LSynLz6tPz+/NTW1KSipMy6THx6fMTKxKyOLNTGVPTmbLTOtBQOBBQSBKySLHReFLzKvLzavAQGBCQiDNzKVOTSXLSWLNzGVLyiPNTCTOTaZLymPMSqROzebOzeZMSuPBwaDMyyRFRKHAwKBOzibMSmPMy6RLSaNLyaNDwyFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfKgACCgwECAwQBg4qCBQUGBwgJCgsLiwAFDA0OBg8QERITlYMFFBUMFgYXEBIYGRoboxwMFRQdCAoeGR8glAABBgshFA8BCxsiI5QklY4lJQYbJiQbypQnACgpB5ALy92UKissAAQXDyktlBUuLzALMeG+MjPKNDU2LDc47yqC1Qs5dODYwYJHj3f/Yrxb4QPHiR9Aqr0I4kNFDCExdgxRQaSItyA8jJw4YvFFjBdCGtCotECFjhssVgRR8W8QkgVJlOBb8k3UID+BAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 package_network-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBPz+/CRKfERCRAQCBFxONKx6LDw+PDR2rAwyXMzOzOzq7AwKDHSSlKy2ZDxutAxCpExOTBRavBQ+fBQ2XOTi5OzWhFRSVBw2VGRmZDw6POzKdCQ6ZBRKrCQmHAwODIyirGSGpIR+bCRixBRKtCQ6VDQ2JBw2XIS27DRKNISuhESK5DR+5BQ+jCQqPCxSfFSa5Gyu7GyerOzetBw+XBwuTBwmNFSa7Eye7DSW9JyabLyqRBQ+dBRerDR+zDx+3Bxq3LyaLJySRHxqPGxeNBRSnCRmrHRyRERONDw+NCQuLCwqHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAeygACCg4SFhoeEAQGJigIChQEDBIIFBgEHBAgCCYMBCgQBCwyhDA0ODxCcAAqRihGXiooSExSCsYoVDBYEFwEEEBiCrBmgGgUbigMcHRgeth8gAR8hIgQECyMkJSaCAicoICkqASssvi0YLoIvMDExMg4zrjQTNTaDCTcxODk6OwQYJmCYNIhHDx8/gAQRMoRIDRcEBwkoYqTIkSMFkNiISCjBCR40UiQxwdGQEg9LSvoJBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 package_settings-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBISChGRmZMTCxKSipLS2tHx6fPz+/OTm5FxaXOzu7DQyNMzOzAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAReEMhAq7wYBDECKVSGBcbRfcEYauSZXgFCrEEXgDCSeIEyzKSXZoBYVCoJVIqBGByKu0Cy8QHxmgNngWCkGgqsGWFseu6oMApoXHAWhWnKrv0UqeYDe0YO10/6fhJ+EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 package_system-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBGxqFAQCBPz+/PTqtOTOfMSyPNze3Ozi5KyeLMTCxMzGzKSipOTe5MTGxAAAACH5BAEAAAAALAAAAAAQABAAAARfEMhJQah4ihFunsFAEIVXCVJACIJhoBK6CerawsA8HAhbuAnYZrBDKBYMWpCy4S2QSRazyBIwrrjcoNFQzK4KR1bQcHhZjGM2BgWLMYJ2enForHPJtNj+kfHvcB8AfhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== package_toys-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBJxyLJRqJGxKFIReHKR6NJx2NMSmbEwyFKyGTMSibFw6FMSqdCQWDIxeHNS6hAQCBDQiDNS+jOzexCwiDCQiHLyeXFxGHLSWXJwuJGweFHQiFMx2bLRGNGQeFNTClOzSrLxKPLQ+LLxOPGxOHIxmLEwWDOzatNS+lKyKTIRiJJx2PIRmPJRuNKyGRIReJJxuLKyKRMSqbKSCPEw6HNzKnAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAauQIAQEBAMhITCcTg0CA6IhGJwICyYwgWjEQg4HIgHBCuMBCCSM6FBHiIOk4cg0hYiKAFFxUJBtC8YGQgBFhAaBVdMAw8bHB0eHh0cGh9LAAMgAxAhHiKPIxAkH1cXEiVjJiQnKCljECoWCAgEFGUrKBYsYwARKnQIRxG0Ky0QtAAIvwcuAwQpLxDCGDAIMTKyMSczs7sQATQz2mMIMyAXu0IQNDUu6AgQ6EPwu35BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= package_utilities-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBExKTERCRAQCBOzu7Nze3MzKzLy+vCxqZBQ2NJyanKyqrGRiZDRydKza3FRWVPT29LSytDw6PMTm5EySjCxaXGRaJFSanCRSVGxqbPTmvMSqVJTW1GSurHS6vOzq7KSipISChFRKHJSGNPz23GxKFBQ6PKyurCwqLMyufJx2RAQGBJSWlEwyDIRiLNy+lLSKVDwmDJRuNOTOrLyabGRCFDx2dKSCVOzWtHzCxOTGnNSyhAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAahQIBwCAgIBAOiUiggFAyHASKxDAwUC8Zg0HAglA9IZPGQABoTSqJCFTIOEIsFgHBcEhhHUpKJFCwaGxYYHB0VEx4IEh8gIQwiIyQbJRMcHokmEicfDygAkCkqJQgIGG0rLElCLS4vMCWqQwMCQg0UMTIzNDVLQjaIGDE3ODQlS785CEkxKjowvEOHybG4O6JDCdNKuDUxRAmxRDHeveUAfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== package_wordprocessing-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBHx6fPT29FxaXPTy9AQCBHRydPT25Pz6/ERGRIR6PJyORHR2LDQyNLy+vNTW1Ozq7Ozu7LSiVKSiTIyKJJyenMTCxMTGxNTGlNTSjLyyRExGTExKTBwaHOzivMy+XBQWFExOTNzOhIyKjFxeXDQuNMSyjNzOnBQSFNTGjDQuLCQiJAwODCwqLGRmZHR2dAwKDCwmJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAafQIAwQCwWhcihYMkUDJLIAKG5fEILhoOAgGAmCgXFgsEoNByOxwMCiTTAEsmEAq5ULJbLxQEuYCQZGn0JGwkcCR1gCUIeHyCJfX2JIUIHIiANCQMGIwYkCSUgi0KPHSYdJyAnKCkdHQ1IrhgdGCC1s7UqSCsdKLi0wL2xHY/FxMcssS0JIS4vIy8uIQktHUkgKygsMNwwKCAxUOLjAH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= panel-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+/FxaXMTCxDQyNAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANECLrcEDDKGYQV4+qbie9eGIJEVxTe+QmjUFgnXLLr615oF8x2v0I8DWpF2GV6slkLKSMdYT4nS0WgSkXYAWUbcXgX/gQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== panel_settings-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBMTCxPz+/PzerISChPyqXAAAACH5BAEAAAAALAAAAAAQABAAAANKCLobwRAG4SJw7w5BswoEkQXbRn0h5ggF14FhbIhb68SiOgnbLRsPEovjwwVLRIdhCfwMiR/VZ1A7WS4tntWyynquq+01+h1//AkAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== password-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+/MTCBPz+BISCBPz+xAAAACH5BAEAAAAALAAAAAAQABAAAANECLrcGi6CIAKUKwxSb/ZasXWPMFwBQRQiZwlqAVnEGbRwKz/ndMep3QNUqKV6kpQh6HFoCIaBMDmQTpOsJsaC6XoZ/gQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== penguin-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+/ISChPz+BMTCBISCBAAAACH5BAEAAAAALAAAAAAQABAAAANHCLrRsTC6F6UId1TYiNtMQRQNqARDOlAgJrzlhr7vqlUufbHMoMO8k+8XY4yGtc9pREIORKRTYVoYDgxUVmBqmGCLJzDYnwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== pixie-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBFxaXPz+/DQyNAQCBKSipPz+xPzerPyqXPyCBERCBISCBMTCBAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARdEMg5Q6C4BjEGyZIlCEFHfJQonEERnB8sE6RxIMkAnGtPBzacjqBQLBiMxS+Y2xmRx+WtSTgmkwQLcwhNKqRCz3VRBOeGvh5wqpPMzO3JQFBguWAYxeiNwnRAEn4RACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= plan-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBMTCxPz+/Pz+xMTCBISChASCBMRaBAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARaEIRJKwU4iD23FwEmDeAwBGYaZiehWutEFK6JqtlM7KZhHhOJbuizIUKBHVGFOOaUPgPlGEsSDNjbKWBgcT0oX5CV2qakIg24OTGA0sxjeSWpUC2ivESf90cAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= proxy-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+/KSipFxaXAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANGCAHcziuIuFy44045WxhZpkxCB4GEKA1lpIAiVG7XB1bjPMHxqds3y++S6nGOL1ikpYlkbBSZM/oYfXBVaS8LuXCr2IY/AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 pybliographic-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBMTG5OTi7Nze/NTS5LSuxOTm/MTCxGxaFIRmFJR6JLy+zOzq9IRqJJR2HLSaNKSirNTOxKySLIR6VLS2vOzu/LSqhNzOXHxqNMzK1KSGJHxmFKSabLy2pIx2JJyCJIRyNNS+VAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZhQIBwSCwaj8WAEplULpkAZ0AQgEaVA4K0alQWDAdEQrHgNguMRsHxgJiJgcEg0pA4Jk84ZVCoWC4TGG9CAQkZGnUIG3lDAQocCh0eFB+MjRsgIAsLIYNwASKCnk2WVkR+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 realplayer-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIYAAAwWVBwC7BwC9BQC3BQOvBQCtBQCrBQCvBQO1AwKPAwOVBwC/AwGnAwCXAQGNAQCJAQCHAQGLAQGTAwKjBwG7AQCNAQKRAQGDAQCBAQGJAQGPAQGFAQKVAQGBGRiZBweHFxaXDw+PExKRBQSFERGPFxeXCQqJLy+vAwCjJSanFRSVLzCxJSSjIyGhGxubNTW1KyurAQGHAwODKyqrHR2dBwO7AwSZCwqRDQyLCwuLAQKFAwSjAQCLAQCFAQCDAwSbAwGbBQKvBQCzBQC1AQSNBQKtAwOdBQKnBQCxAQabCwOLDQSNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAAQABAAAAe/gAABAgGFAwQFBgcIgwEJCguRDA0ODxCXERITFBUWCwMNDxcYpKUYGRobFQEcFx0dGLCxrx6kFQcYHyAhIiIhIyQlJiekESgYHikqKywtLi0vIDCkMQQbLiQyMzQgLDQzJSCkMjU2NzIYOCYyOSYmH+gYOjUBOzw9PT6mGD4P/AORahj4IaECBFI9gAQhJSSSw0g2fGggsEAIw4eRhhBhEGBBgCKkjAgZSRLFESFIRibZx5KlkpYtlbyEuW+Jn0AAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== remote-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBDQyNISChJyGPGReLAQCBMy+hERCHKSipAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARFEEgZqp0Y1KxD9twEapg1kqhwBgKFvqIIjgMRdy4wFIaNbiiCYXDIAUcH328EQsxiIBXAqWn9MtTSTZLNybizEweY8UcAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= samba-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIUAAAQCBDQyNFRWVASC/Pz+/PTW1OyytNTW9LSy7PTGxOSenNx2dMTG9Jye5OSKjNxiZMw6PIyK5GRi3AwODMwmJLQCBCQmzPS+DPTejPTaJLR+DPT21OzqtNT21MTCxPTyxOTmnNzedMTyxPz6/ISChOTijNzaZMzOPIzijMzKJLS2BPT29Nza3PTmxKSipOzu7LyGJPTKRNSeDFxaXERCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAMALAAAAAAQABAAAAacQIBwCAgIBsjkAEAoGJgHxFC5TCgWAEajyFUCHA8IICJhTggAr4NSGVsAF8wlnSQWBYLMRUNHMjccTB0AGh5dfh8gIQAiAAJCIyRCfiUmJwEokARok0slKSqPApukAZNDRpqbkZMjSROOI5srLAGwS34tGgEuBCMvAjCBA64ALRgxuyzAMnItQmgaMRcypjMByNR9QjQ0adzeaX5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= scsi-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+/MTCxKSipISChAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANCCLoQwZAFIV6UYgxi79Qa52WDE3bKV6YOpFpO3L5pJcckLBB8/wQEDezWAQpZqIWxFNAUkqkg6HmJOqGuArUqwfoTACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= style-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBAQCBOzqBLS2BPz+HPz+rPz+BPz+lPz+zPz+9Pz+1Pz+nPz+hNyuhPz+pIQCBMTCBIQyBPz+/MTCxFwmfCQiJIxOrHw6nJRWtJxmvJxuvJxyvAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVvICACwWieYiCUwVCiKVEEhjHA6YEcxooHBURCsXihaAYGglEzngKBhsMmMDhH0YcBAu16SY2IKiApm81RMXTCblPelDCrXJlI6hSL5SJOSewVdRMUGHtGZICChHsmZHeAgxkaG41/bWxnjV6bUH4hACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= terminal-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBMTCxISChPz+/MT+/AAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM/CBDcHkoFQasVUIrBe8fRNDwMAWpjUThmtmxk0IYwOaPx/V6XG3hAjmsRa0Qkg6NSOVo6F0nG88g4TUNDpT8BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= wabi-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+/ISChPz+xAQC/AQCxPz+BFxaXAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARUEMhJgw20XsHxvIEwcKQHBESaDkShmqhKsMb7tW1RHPwOH4ZdYcBDGH+8A2JgLH2MzZHAJgmRBAgZAabNqg7cJMGb5BKSZF4Yfb5Uzmp3piqfS/wRACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= window_list-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBCRiXCRaVPz+/CRmZFRWVISGhMTCxESSjPT29DR6dDyOhDyCfPTy9CxqZOzu7Ozq7ERubOTm5ARehAxefPz6/ByaxBSOvBSGrAxynAxqlBR6nBRylAxmhARWdFxaXCH5BAEAAAAALAAAAAAQABAAAAWHICCKQTCeqCgMhJCihXEYSPuKRWIoC6PYsEZikHA4FA4CEJdoJh4QgXRwiOAeQudDIpEZIpPwhCImhyGGAmBSOVgumExG055w1ZPZhpPpUDwzExBqAAUDhxUVTQ0QEgWOOIcDiU1QjoSFFYiKDZYFmAWJlE9bkCM5iouWpiIfBa6frrKYAH4hACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= winprops-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAAQCBPz+/ASChATCxISChFxaXKSipPz+xMTCxMTCBPwCBAAAAAAAAAAAAAAAAAAAACH5BAEAAAoALAAAAAAQABAAAARXEMhJqwxAjM23wBMhjGQJEFKhriwrGUcsE3JsvPWBFAAiT7BaIYAA/HAxWk9CO9wAwd0SkJA9g8NiomnDoYqnHDAGroqRyVy3F2i7326LnKKo2+94hT8CACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= wp-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBAQCBAQCxAQChKSipPz+xPz+/ARCRFxaXEQCBMTCxPyqXDQyNPzerISChISCBASCBERCBMTC/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAV1ICCOZDkGgSgMg0AUZWAExyHc7YCQclLYtxtieAoUEApFUIBgnRYMhUHRCDYcDoUIRUhOlYLkYwcIDLvSpAsBiYx0CPQUgXNv4V0ZWEByDBgRcTMGDislTX+CMgISJk1+AQ4zWiYiCCiRDmRbmJ2eKZWhAH4hACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= xapp-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBISChAQCBAAAACH5BAEAAAAALAAAAAAQABAAAAIyhI9pIa0nYAtPUGlTRszJ10UA8xiNRZZmJKoA25boqW7npeHvlKRHyIn9aKYaz6XwFwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== xcalc-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBISChPz+/AQCBCH5BAEAAAAALAAAAAAQABAAAAI4hI9pwe0Ogpi00hHF2LzzzFlTsIHD45SSx6oCeW4wjK2tl83y7t64pIsJaxrfh2bEAJIlhRPhLwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== xclipboard-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+/MTCxPz+xPzerMRaBISChCH5BAEAAAAALAAAAAAQABAAAANICLoQwdBJIaRjgYbBR66Lo1nfowTER61aWGRd1y5GyrLm+QrxMJ81FQ4T2MV+jUPwBgpVdrdcQ6AUIj8Ha/N06Hq/UpLY5E8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= xclock-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAALy+vAQCBPwCBMQCBIQCBISChPz+/MTCxCH5BAAAAAAALAAAAAAQABAAAANbCLHcrSLKOZcYmDSCsR1aUABAsXDDJwJGa5SBFwgaWxbCG3CWaBwG3C8Y67FawpYiNQscg65fsVkYuoAmJs1pBR522lQB6ILJLqHRwQQOZzYdZnw+dzruDIA/AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 xconsole-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+/ISChMTCxAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM7CLrcGjBKCYK4OGcohv/gxw2aRgyjYJXCmVpr5loke82dfaO03vI5Ha5mwxGOyOSRF2qKKpMoxEFl+BMAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== xedit-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/AQCBMRaBPyCBMQCBMTCxPz+BPz+/KSipFxaXPzerPyqXIQCBARCRDQyNISChCH5BAEAAAAALAAAAAAQABAAAARnEMg5gw00yyDGIJi2FUHhDWEWeEXrgaphHEOBJF8KBLKyLINEIAHbyA6/hbDACDSMBt9PIBA6n4HfIElFXTeKg2LbtTSeu7BiPegIvuA1mwrfOB5r4PusCjimZmgUF4F8IhJnhiJ+EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 xemacs-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBDQyNKSipPz+/FxaXISChMTCxCH5BAEAAAAALAAAAAAQABAAAANJCBASoXCFoVi8VdL6HHQeB4YjSAxnYQygSLzoSTjbEs9vMF86cbyH34NX+AELQ4zO+Nopm6cBC1PBEQwG6gd3SGo7Xa1STIb4EwAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 xeyes-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBPz+/ISChCH5BAEAAAAALAAAAAAQABAAAAI4hI+py50Bw4lyBiEggFjvi2VcqIFhdnaDSabZKrbjS3W1OHz2CkJD/vHlKD/Er2g4Ah3MptPgLwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== xfig-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+BMTCBISCBARCBATCBASCBCH5BAEAAAAALAAAAAAQABAAAANQCLocwbAJ8SIMYgwHHO9Opk2V5xGEplZK0alaui0eDLOB8QTykOKGQ6mnKQWFPILDN8sdng7l69c5CjuKAHNnZb2KnUOhcG3MsmMv7aK2+BMAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== xfmail-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPyqXMRaBPz+/AAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANACLHcAVCJSWcYLwaxSPAXBj2bswyiIlUWSr5muGhbdaZjTd1ZzvKMFaOFcbCIpiOnGGs2FM5gLkLrTalQLMCfAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 xload-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAImhI+py+3hEoxnUmBpyBjNzWXfJnkGKJ4dBlbjS7Jni9Zsjec66hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== xmag-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBKSipMTCxPz+/IQCBPyCBMRaBCH5BAEAAAAALAAAAAAQABAAAANICKrR+6+JIRxkc4RBww1TQBBNB21io2rRRKpltaDvis4hvJmzBmuslo+zkZ0yu0rBcwJ1AgXD8gJQMaJTaqRwyGqvzO9M4U8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= xosview-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIMAAPwC/AQCBPz+/MTCxAQChPyCBAT+BPz+BAT+/PwCBAQC/AAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARFEIRJa5Ui663HFEQojqEXCAVhrCxLmGB4kCJM03aIHEdC5rfaJ6UotlavT3AEIxaNLuAyd2wlT0thYMDter0BiWU8AfgjACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= xpaint-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBAQCBPzerMQCBPz+/AQCxPz+BMTCBASCBPyCBPzC/PyqXMQCxIQChKSipMRaBDQyNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVtICCOYmCaZGoKLBuMbykMA1EURFwCgWAQwKBAxxMQDocgAjEkrYAsoS6QGEYJCgWhWVq4tgJGY+iAVbcBB5jLq/aMbzJsYXK0Arky7JFY+BcJDyckDgEPh4d1aUSFJ2l6ARApDpSUKkQpmSJ+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 xv-16:apps apps16 16:photo:16 16:R0lGODlhEAAQAIIAAASC/AQCBPyqXPz+xPyCBPwCBAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM8CLrc/jC+oIK9Lgg7RuietWhCSWkkVZUbEBBnWxXFSVP1eLt7kPM3X86nEhJrtx/P0tuNilCVZEqtNvwJACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= 3floppy_mount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBAQCBMTCxARmZPz+/FSWlLSytKSipERCRIyOjISChOTm5HRydNza3GRiZFRSVASCBARCBDTSJIT+bAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVrICCOQBCQKBkIw5mqLFG47zoQ+FwbN57TosDhgPD5dMEEIqE04kwlBWKBUEiNVYFpyqAyGEUCgqEtERiNNMLhQKzLQYJg7n7Y4aMAwbCUPvAQeWNgfzQQETAIhSMQEogwgBITQEGGEREmfiEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== 3floppy_unmount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBMTCxARmZPz+/FSWlLSytKSipERCRIyOjISChOTm5HRydNza3GRiZFRSVCH5BAEAAAAALAAAAAAQABAAAARcEMgJQqCYBjFu1hxReN82EOhYGieaklJwHIjrqnGCJLqNWhUFYoFQCG1FgWXIIDIYNQKCoawQGI0swuFAbKsxgmDsfZjBkwDBsNM90Jot9A3DbBD0Dwiur9QnfhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== 5floppy_mount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBFxaXPz+/DQyNISChASCBARCBMT+xAT+BAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARMEMgJQqCYBiFu1sIwdJ+0hSKZnZw4ehPLoW88c0Q7X7JABLlbp+eT/UyzgpADqwgKxKYpeIMZQNWJ4YBhWRHcrgpgQCSkJu3hYPFHAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 5floppy_unmount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBFxaXPz+/DQyNISChAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM+CLoQwZAFIV6UYox61cwaF32UtlkLSYFnulJEuT6qQATxW9W2enurgo6CaggKvKIn91K6mh0gMepydqwAfwIAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== cdaudio_mount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXISChNTS1MzKzMTGxMy+vNSytAQCBOzq7OTi5Nza3Oy6vPy2tOTStPz6/Ozu7Nze3MTKxOS2tOzOvNTqvLT2tDw+BPTy9MzOzLS2tPy+tLz+tLz2tLSynLzqvLzavLTOtNTW1KSipPz+/LzKvMTCxDQyNASCBARCBDTSJIT+bAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAa0QIBQGBAYA8Ok0DggFAwHBEIJECQUi8GT0XBMh9YHJDKQTBqUiuUCVmAeiYzmsKlwOt/AAKFIFAIIFx4WHyAhUwIDIgsZFyMkFxchJSYmiBkSBBoIJJwIGgOhiCYFJSEnFyQjFwNZewABISAfFiYnCAEmCREIrwAIFhwVGwcaBAkPGApsQsAVFA0GBQMRbxBTKM0ODQwTEq192ClDgROkBHvYKuNJUu5CKCorX1RDKCkpUn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= cdaudio_unmount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXISChNTS1MzKzMTGxMy+vNSytAQCBOzq7OTi5Nza3Oy6vPy2tOTStPz6/Ozu7Nze3MTKxOS2tNzmvLT2tDw+BPTy9MzOzLS2tPy+tLz+tLz2tLSynLzqvLzavLTOtNTW1KSipPz+/MTCxLy6vDQyNOTm5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAapQIBQGBAYA8Ok0DggFAwHBEIJECQUi8GT0XBMh9YHJDKQTLqUigWsuDwSmMxBQ9lwvoEBQpEoBBAWHRseHyBTAgMhCxgWIiMWFiASJCSHEgQSGQgjmwglGKCHBQUSICYWIyIWAwshIVMBIB8eFSQmCAEFCREIekIIFRsUGgcZEgkPFydrvxUUDg0GBSEREGJfv9AMEySsJxDYQ4DcEhh64UpS6lTs7QB+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 cdrom_mount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXISChNTS1MzKzMTGxMy+vNSytAQCBOzq7OTi5Nza3Oy6vPy2tOTStPz6/Ozu7Nze3MTKxOS2tOzOvNTqvLT2tDw+BPTy9MzOzLS2tPy+tLz+tLz2tLSynLzqvLzavLTOtNTW1KSipPz+/LzKvMTCxDQyNASCBARCBDTSJIT+bAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAa0QIBQGBAYA8Ok0DggFAwHBEIJECQUi8GT0XBMh9YHJDKQTBqUiuUCVmAeiYzmsKlwOt/AAKFIFAIIFx4WHyAhUwIDIgsZFyMkFxchJSYmiBkSBBoIJJwIGgOhiCYFJSEnFyQjFwNZewABISAfFiYnCAEmCREIrwAIFhwVGwcaBAkPGApsQsAVFA0GBQMRbxBTKM0ODQwTEq192ClDgROkBHvYKuNJUu5CKCorX1RDKCkpUn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= cdrom_unmount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXISChNTS1MzKzMTGxMy+vNSytAQCBOzq7OTi5Nza3Oy6vPy2tOTStPz6/Ozu7Nze3MTKxOS2tNzmvLT2tDw+BPTy9MzOzLS2tPy+tLz+tLz2tLSynLzqvLzavLTOtNTW1KSipPz+/MTCxLy6vDQyNOTm5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAapQIBQGBAYA8Ok0DggFAwHBEIJECQUi8GT0XBMh9YHJDKQTLqUigWsuDwSmMxBQ9lwvoEBQpEoBBAWHRseHyBTAgMhCxgWIiMWFiASJCSHEgQSGQgjmwglGKCHBQUSICYWIyIWAwshIVMBIB8eFSQmCAEFCREIekIIFRsUGgcZEgkPFydrvxUUDg0GBSEREGJfv9AMEySsJxDYQ4DcEhh64UpS6lTs7QB+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 cdwriter_mount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBFxaXISChERCBMTCxKSipAQCBMTCBPzCxPz+xPzerMT+xDQyNMTC/ASCBPyqXPz+BARCBAT+BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAWIICCKgWAGYyoKA+EWhGGogOAaB6Lr8ygUCYWCkEMoEovBSHZUFI8LGYloODJkhWijMbMdiAwBQEbYxmpExFlkgN3QrliXAcvNAuVt4coYKtQ9BlwLCQQFMAlVSmwEUX8IB1UJiQAObEE6BA9VEDMOEUsDDzoHkZ4LoCkyqyIOCxI9NCOfETJ+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 cdwriter_unmount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBFxaXISChERCBMTCxKSipAQCBMTCBPzCxPz+xPzerMT+xDQyNMTC/PyqXPz+BCH5BAEAAAAALAAAAAAQABAAAAR3EEgZhA0zSzGIL4RhaIDgGQeiquMkFImiECmiJMswibdS3wsRhWa4MUSFYKMxMh1oDAFARFiGSjTEVWIAnbCeUJMBSo0C1WXhyJgptC0Dc5EgFECJoo5LCL4RB0UJeRkGMSoEDkUPLYUDDioHgY0kIpYkmJkAfhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== dvd_mount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXISChNTS1MzKzMTGxMy+vNSytAQCBOzq7OTi5Nza3Oy6vPy2tOTStPz6/Ozu7Nze3MTKxOS2tOzOvNTqvLT2tDw+BPTy9MzOzLS2tPy+tLz+tLz2tLSynLzqvLzavLTOtNTW1KSipPz+/LzKvMTCxDQyNASCBARCBDTSJIT+bAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAa0QIBQGBAYA8Ok0DggFAwHBEIJECQUi8GT0XBMh9YHJDKQTBqUiuUCVmAeiYzmsKlwOt/AAKFIFAIIFx4WHyAhUwIDIgsZFyMkFxchJSYmiBkSBBoIJJwIGgOhiCYFJSEnFyQjFwNZewABISAfFiYnCAEmCREIrwAIFhwVGwcaBAkPGApsQsAVFA0GBQMRbxBTKM0ODQwTEq192ClDgROkBHvYKuNJUu5CKCorX1RDKCkpUn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= dvd_unmount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXISChNTS1MzKzMTGxMy+vNSytAQCBOzq7OTi5Nza3Oy6vPy2tOTStPz6/Ozu7Nze3MTKxOS2tNzmvLT2tDw+BPTy9MzOzLS2tPy+tLz+tLz2tLSynLzqvLzavLTOtNTW1KSipPz+/MTCxLy6vDQyNOTm5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAapQIBQGBAYA8Ok0DggFAwHBEIJECQUi8GT0XBMh9YHJDKQTLqUigWsuDwSmMxBQ9lwvoEBQpEoBBAWHRseHyBTAgMhCxgWIiMWFiASJCSHEgQSGQgjmwglGKCHBQUSICYWIyIWAwshIVMBIB8eFSQmCAEFCREIekIIFRsUGgcZEgkPFydrvxUUDg0GBSEREGJfv9AMEySsJxDYQ4DcEhh64UpS6lTs7QB+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 hdd_mount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBDQyNIRuVKyCXMSKROzSrOzKpOTGnLSafLySZKxuLMSOVPTWvPzixLSehNyibOzOrGxaVJx+XOzGnFw2FJRuPKx+TPTSrHRWPKyKZPTOpHxOJKyKXFw+HKSipISChMTCxFxaXIRiPNSWXExOTOS2hLR+PLRyLPTWtMyOTASCBARCBPz+/DTSJIyKjIT+bAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaTQIBwCAgYA8SkMCAYDARI5ZJQMBwQiWgyoFgwrA3HQ7scQAqFAcEQOUi0zAkFUSFYLghMBloUCDQNGxwdHhwHekcfICEhICIfIxkLJBABJUYCICABIhAOBiYnKJaXmH4CGSkYCCqkSAEfTKenrkOwsrQll0IrS7G5uwArLLaxLbXCLsTFLyDBKy4wZEVHvCwsRn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= hdd_unmount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBDQyNIRuVKyCXMSKRPTWtOzKpOTGnLSafLySZKxuLMSOVOzOrPzm1LSehNyibGxaVJx+XOzGnFw2FJRuPKx+TPTSrHRWPKyKZPTWvHxOJKyKXFw+HPTOpKSipISChMTCxFxaXIRiPHxaNLRyLNSWXExOTPzixOS2hLR+PMyOTPz+/IyKjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaIQIBwCAgYA8SkMCAYDARI5ZJQMBwQiWgyoFgwGgiD46FdDiCFwoDQAEe0TMkEQSFULIcLBloUCDIaDRscHRsNHhhHHyAhISAiHyMkJSYQASdGAiAgASIQKA0pKguXmJl+AiQGFwgrpUgBH0yoqK9DsbO1J5hbsrq8SrgstlJFHy0gwMVFR1J+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 memory-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBISChAQCBMTCxCH5BAEAAAAALAAAAAAQABAAAAI6hA+Bu+HCmgiiRuNoHZBRXQlc84TmcHzm2WVryE1YvMaZIdbVd2zw7lj4bDKGbxK8hHgX3K2JUDD8BQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 mo_mount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBKSipDQyNPz+/MTC/PzC/ISChASCBARCBMT+xAT+BAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARTEMgJQqCYBjFu1hxBeN82iCIJDgWaYhtntC4ZCzItdhWOD7mdwHLrAAczoKViIh6Vto5lcDjglppp9UpCTALULRaASGS5E4TCnB2rFyqJO5Gw+CMAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mo_unmount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBKSipDQyNPz+/MTC/PzC/ISChCH5BAEAAAAALAAAAAAQABAAAANHCLoQwZAFMV6UlBB759Aahw0FGEITZZQmlwoqq1UNDA/xLDhvhQ8rnKPh4f2EropjcDjAhpJl8ylaBJhTaCelvRC7XqLXnwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== nfs_mount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBExKTGRmZPz+/ExOTMTCxAQCBDw6PCwqLIyCRHxyNCQiJOzmxMSybFxSHHRmLIx+NFROHERCRFxaXASCBARCBDTSJIT+bAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVWICCOZGmeaEoGKiCwwUAI5zsUBnAUQ0CLNhxLFEDwDAnFzTAsBRYJRsORSwUeDUiEWYtJIhFj7+eKCUdPHmxyNj0nFABXRam0RBSLvZW/VFN1FQYGfiEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== nfs_unmount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBExKTGRmZPz+/ExOTMTCxAQCBDw6PCwqLIyCRHxyNCQiJOzmxMSybFxSHHRmLIx+NFROHERCRFxaXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVLICCOZGmeaEoGKiCwwUAI5zsUBnAUQ0CLNhxLFEDwDAnFzTAsBRYJRsORSwUeDUiEWYtJIhFj7+eKCUdPHmxyNj0nOa6q2qrbW/4QACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= printer1-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBFRWVPz+/Ly+vISChMTCxFxaXPT29DQyNJSSlHR2dERCRFRSVERGRBSmnExOTExKTAT+/NTW1MzOzMzKzMTGxLy6vLS2tGRiZFxeXOTm5IyKjISGhLSytKyqrGRmZNTS1Nze3Nza3Hx6fKSmpKSipAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaUQIBwSCwaA0ikkRgQDJCE5LFgOAicUKUwUCAgBuDE9RkFcL3ggbgQUCwYyIIA8VU32ASDwoEcIAoHCQkHbA8EBBARSX0DXQEPEgQCDYpJExQVAWCHBwcNDUkKChQWBBcYARkanaABExsbHB0FGB4fIKoHAWYhpCIBIyQLJSAJGbtbULUTISa4yEVJJSbO0EtmUkR+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 printer2-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBKSipAQCBPz+xPz+/MTCBISCBISChMTCxFxaXAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARaEMggqrwYVDGGzRLXEZ0HhgMpFIXxZZzRBsHxXquAUHqCCBgB6YcoFhNAXMWISCQOv6Dt6DMmQwQntHjwXTVL6mH83Ry31qBO8CSQSmVg2GM74aAVij2UTPojACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= scanner-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+/MT+/ASChARCRATCxMTCxFxaXKSipDQyNAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARTEMgJgqWBVivEldkUdKSXhVjZfenommglDERh3Tc4E4ZRHAGgkEPr9X6H5AHBERSMRyWzkug8jQXFEhWoOo8dRYxqLXSmGjIJnVaz29Q3fAP3RwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== tablet-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBMTC/Pz+/MTCxFxaXKSipAAAACH5BAEAAAAALAAAAAAQABAAAANECLrc/iosCUEQlEYdRp6dZ4lgKBBEp1kmmpLRMBQu6qWLEdYBn+81F0wnC8oCK+LAQDgGDIaG0vOMPnRIaEUBtW6//gQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== zip_mount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIMAAPz+BAQCBFxaXMTCxPz+/ASChPwCBKSipASCBARCBMT+xAT+BAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARTEMgJQqCYBiFs1lwwdF8VEsR4YVuXoirYFcWbkmY31wPqma2ZwReqBEODQutwEY04oeWqMniGOEzW4HAVZAEImVSCSLDGYIX5/EMoFtNSOWHxRwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== zip_unmount-16:devices devices16 16:photo:16 16:R0lGODlhEAAQAIIAAPz+BAQCBFxaXMTCxPz+/ASChPwCBKSipCH5BAEAAAAALAAAAAAQABAAAANICLoQwZAFIVyUNIx6WybE9kBTFYIiVhXFGXJetbYDaHnlathZk2eDQunw0GwomeGoMThmKETS4PAURCMlZccHXXYct60Y4E8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= blockdevice-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBMT+xAT+BASCBMT+/ATCBAT+/ARCRPz+xARCBPz+BATCxISCBDQyNMTCBCH5BAEAAAAALAAAAAAQABAAAARhEMgZwrwYBCFsvhs3eF8wDMJAVBVmnupazKRmGDFxzMVBBjcDQXfYHRA/QmKpKBYRSMoysVgwGEeoJ1ClLhpXhlbiqJobjcA1Sn48qug06+JwP+I1UMCNzmcqaR8lghN+EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 chardevice-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIIAAASC/AQCBMTCxISChPz+/MQCBPwCBAAAACH5BAEAAAAALAAAAAAQABAAAANCCBDcHkoFQasVUIrBe8fRNDwMAWojMTZmtmzByp6v7LQhTOLadbkxj3AUWZAcxcUgyYwQm8wYoOCCLgoGK5Nq9ScAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= desktop-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBExKTDQyNHRydFRWVKyqpGxubExOTERCRLy6vFxaXBweHFRKPFxeXAQCBIyKjCwqLMS+tKyurDw+PNze3ERGPPTu5Pz+/Pz6/Nza3MzOzKSipISChOzq7NTW1Ly+vHx2ZOzm3Ix2XJx2XIyOjKyqrJSSlPTexPTixKR2VKxyPCQiJPTy9JSWlHRmTOzSrMzKzJyCbKR+XCwuLOTi5CQmJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaeQIBwKAwIiEjkgJBsAgoGwcE5RCQUgAWj0WwcHA8FRLhAcIcKhyIiMSwcwglc2ABTDA2Eo9KQoy0PFxgYGRobDxwBDHRgF44YHQ4bHgkfHBUMHQ8gFp2dISIjEQwfBwIkJR0mICcoJycpKgweCisAEAcPGSwtLi8vsQkNtkMrBxswCQ8uMTINY0kzBCQwNB/DVAArBC0NNdlDM9BDfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== file_broken-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBFxaXDQyNAQCBMTCxPz+/KSipPz+xPzerAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARWEEgQahVijMmD/oRAbBw1FCgaFFrppeo5didsZTSMDoRBSi/dgfUz6Va7HPIQGB6KnpW0EEB4Oshp5ZlTFRBfFs3ZLDihtTAYwZ14nGbzoS3JfO4ffwQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== file_important-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBExGTKQqLPz+/KQqNAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM7CLoQwZAFIV6Es15Jqd2ZtzXUMIhXZqJYaZ5aK7zwp6h0zc05i+c6Eg8oCnWOR0eHQGEKnEWHdDoF+BMAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== file_locked-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBFxaXDQyNAQCBMTCxPz+/KSipPz+xISCBERCBAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARTEEgQahVijMmD/oRAbBw1FCgaFFrppeo5didsZTSMDoRBSi/dgfUz6Sq7XGp1CByKQZUUWjsgrtcENYXNUodWhAahVRa65G9hmGgnnpzMZ/7xRwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== folder_blue-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBwWHMzKzOzq7ERCRExGTCwqLARqnAQ+ZHR2dKyqrNTOzHx2fCQiJMTi9NTu9HzC3AxmnAQ+XPTm7Dy67DymzITC3IzG5AxypHRydKymrMzOzOzu7BweHByy9AyGtFyy1IzG3NTu/ARupFRSVByazBR6rAyGvFyuzJTK3MTm9BR+tAxWhHS61MTi7Pz+/IymvCxulBRelAx2rHS63Pz6/PTy9PTu9Nza3ISitBRupFSixNTS1CxqnDQyNMzGzOTi5MTCxMTGxGxubGxqbLy2vLSutGRiZLy6vLSytKyurDQuNFxaXKSipDw6PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfDgACCAAECg4eIAAMEBQYHCImDBgkKCwwNBQIBBw4Bhw8QERITFJYEFQUFnoIPFhcYoRkaFBscHR4Ggh8gIRciEiMQJBkltCa6JyUoKSkXKhIrLCQYuQAPLS4TEyUhKb0qLzDVAjEFMjMuNBMoNcw21QY3ODkFOjs82RM1PfDzFRU3fOggcM7Fj2pAgggRokOHDx9DhhAZUqQaISBGhjwMEvEIkiIHEgUAkgSJkiNLmFSMJChAEydPGBSBwvJQgAc0/QQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= folder_blue_open-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBQWFOzi1Ozq7ERCRCwqLPz+/PT29Ozu7OTm5FRSVHRydIR+fISCfMTCvAQ6XARqnJSKfIx6XPz6/MzKxJTa9Mzq9JzO5PTy7OzizJSOhIyCdOTi5Dy65FTC7HS2zMzm7OTSvNTCnIRyVNza3Dw+PASq5BSGrFyqzMyyjMzOzAR+zBRejBxqnBx+rHRmTPTy9IyqvDRylFxaXNze3DRujAQ2VLSyrDQ2NNTW1NTS1AQ6VJyenGxqbMTGxLy6vGRiZKyurKyqrKSmpDw6PDw6NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfCgACCAAECg4eIAAMEBQYCB4mHAQgJCgsLDAEGDQGIkw4PBQkJBYwQnRESEREIoRMUE6IVChYGERcYGaoRGhsbHBQdHgu2HyAhGSK6qxsjJCUmJwARKCkpKsjKqislLNIRLS4vLykw2MkRMRAGhDIJMzTiLzDXETUQ0gAGCgU2HjM35N3AkYMdAB0EbCjcwcPCDBguevjIR0jHDwgWLACBECRIBB8GJekQMiRIjhxEIlBMFOBADR9FIhiJ5OnAEQB+AgEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== folder_cyan-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBwWHNTKzOzq7ExGTCwqLERCRBSKjBRSVGxubKymrNTS1Hx2fCQiJMzq7NTy7IzKxHR2dFTW1Ey2rITKzNzy9JTSzBySlHRydKSipDTW1ByelGzCvIzOzByOjFRSVCy2rCSalGS+tJzSzBxudCR6hCSCjITGxMTm5Pz+/JSutDyChBxydCyOlITKxPz6/PTy9Nza3ISqrGSyrOzm7MzKzDQyNMzGzNze3OTi5MTCxNTO1Ly6vLSutGRiZKyurHRudDw6PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAe2gACCAAECg4eIAAMEBQYGB4mDCAkKCwwNjYUOAYcPEBESlBMMjAUFnIIPFBUWEBcYGQoaG5gGggMcHRUeFh+fGCCVIakiICMduiQWJa4fCKkdJicoCcjJKSrPAAIrBSwtLtMv1jDaCDEyMgUzNC3SKCA12gYFMjY2KzMzN98uLdo4cujYoa9BAx4IeSywJSgAjgU8evTIgdDHj4WJHAL54cPiDyAMIzkMsSGIkCGREAU4gAOAn0AAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== folder_cyan_open-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBQWFNze3Ozq7ERCRCwqLPz+/PT29Ozu7OTm5FRSVHRydIR+fIyCdMzGxAxOTBSGhIx6XJSKfMzKzERGRAxOVKTq5Mzy7KTW1Ozi1OzizEzSxGTWzHzCvNTq5OTSvNTCnIRyVNTS1BzKvCSalGy6tAQ6XMyyjMzOzDw+PByqtCR6fCyGjHRmTMS+vJSytDyChCyWlGReVOTi5AxGRKyurDQ2NNza3NTW1AxKTJyenGxqbMTCxMTGxLy6vLS2tLSurKyqrCwuLFxaXKSmpDw6PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfEgACCAAECg4eIAAMEBQYCB4mHAQgJCgsLDAEGDQGIkw4PBQkJBZcQnRESEREIDwoPExSipBUWFxgZGhIXFwkbHBQToQQGFx0eHxoguhEXHCEiIyQGABclJiYnycsSKCkjKisAESwtLi7Y2soXLzDUAaMxMuYuM9kXNDDiAAYFBTU15NGTYeMGNQA4ahAgkEMHiQoxZrTYwWMfIRw9fKio8MMHECAReByUhIPGDSBBhAyJYDFRACJFeBi5cCSSpwM4APgJBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 folder-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBwWHMzKzOzq7ERCRExGTCwqLARqnAQ+ZHR2dKyqrNTOzHx2fCQiJMTi9NTu9HzC3AxmnAQ+XPTm7Dy67DymzITC3IzG5AxypHRydKymrMzOzOzu7BweHByy9AyGtFyy1IzG3NTu/ARupFRSVByazBR6rAyGvFyuzJTK3MTm9BR+tAxWhHS61MTi7Pz+/IymvCxulBRelAx2rHS63Pz6/PTy9PTu9Nza3ISitBRupFSixNTS1CxqnDQyNMzGzOTi5MTCxMTGxGxubGxqbLy2vLSutGRiZLy6vLSytKyurDQuNFxaXKSipDw6PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfDgACCAAECg4eIAAMEBQYHCImDBgkKCwwNBQIBBw4Bhw8QERITFJYEFQUFnoIPFhcYoRkaFBscHR4Ggh8gIRciEiMQJBkltCa6JyUoKSkXKhIrLCQYuQAPLS4TEyUhKb0qLzDVAjEFMjMuNBMoNcw21QY3ODkFOjs82RM1PfDzFRU3fOggcM7Fj2pAgggRokOHDx9DhhAZUqQaISBGhjwMEvEIkiIHEgUAkgSJkiNLmFSMJChAEydPGBSBwvJQgAc0/QQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= folder_green-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBwWHNTK1Ozq7ExGTCwqLERCRByGRBROLGxubKymrNTS1Hx2fCQiJMzm1NTy3ITGnKSipFzShFSydIzKnMzq1Nzy5JzSrByKTBweHDzOdCSaTGy+jJTOrFRSVDSuZCySVMzq3IzKpBxuRCR+TCSCVGy6hPz+/JSunDyCXCSOTCyWVCyeVPz6/PTy9IyqlCSCTGSuhPTu9Ozm7Nza3Dx+VBxyRDQyNMzGzNze3OTi5MTGxMTCxLy6vLSutGRiZLSytDQuNKyqrHRudDw6PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAe+gACCAAECg4eIAAMEBQYGB4mDCAkKCwwNjYUOAYcPEBESlA4TjAUFnIIPFBUWFxgZGpWXjYIbHB0VHhKtER+UCyC1ISIdxbkSGSMYJAiCByIlJicaxbgoEhDNAAYpBSorJScnLC0uHRLaCC8wMAUNMeAnMgkz2gY0NDUFKTYNBDE3cKzQlkPHDh42djRo0KNhjwUGBgXIscAHgQY6fPz4AQRioolBhGwUIiRIxEiEhoCYQKSIEZSHAhzIAcBPIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 folder_green_open-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBQWFNze3Ozq7ERCRCwqLPz+/PTy9PT29FRSVHRydIR+fISCfOzu7OTm5OTi5MzGxAxOLByCRJSKfIRyVERGRKTmvNTu3KTWvOzi1OzizIx6XIyCdFTOfGzSjITClAxGJOTSvNTCnNTW1Dw+PAxKJCTCVCyWVGy2jAQ6XMyyjMzKzByuZCR+TCyGVNTm3HRmTLy6vJSypESCXGReVLSurDQ2NNTS1MzOzKSipGRiZMTGxMTCxJyanDQyNLSytKyqrCwuLDw6PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfCgACCAAECg4eIAAMEBQYCB4mHAQgJCowLAQYMAYiTDQ4FCgoPEBESnBMUExMIoBUWFaEKBRIXExgZGqoTChscFR0epQYTHyAhGrkUIhMcIyQWJSYAJygpKSrIyissFi0GABMuLzAv19kaMRMyM+ABojQ15ObYEzYz0wAGBQUbBPHkYNQQcQMcABwEEhLIkUMHjRQvTuzIRwgHjx45evTwMWPGiR8GJQGxcWNGkBtCTlBMFGDIgh9CJhCJ1OkADgB+AgEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== folder_grey-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBExKTBwWHMzKzOzq7ERCRExGTCwqLHx2fKyqrNTS1PTy9CQiJNza3OTi5GxubJSSlISChLSytFxWXDQuNKSipBweHISGhFxaXIR+hLSutFROVHR2dFRSVGReZKymrLy6vFxeXNTW1Pz+/KSepERGRPz6/PTu9Ozm7DQyNMzGzMTCxMTGxGxqbNTO1Ly2vHRydKyurHRudDw6PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAawQIAQEBAMj0jAgFAwHBDJoUGASCgWDEMxETg2HA8FFaJgFgpdYSMiUYAnlErCsmgKL5iMJqJwPzYcCB0eahAZH4gSESAhYAoGQggiBh4eFB8iehEWI5AABiQFFpMeHCIiiCWeJicMDAUOEZMcHBkSngYMKCkpJA4OBCWTk0IqKw8PvwsLLCwtLBCeRCouLC8vK80wGzEHSQEqHxMhMBMyLtLfKh4WCjM0UUgBCCoAfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== folder_grey_open-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBExOTBQWFNze3Ozq7ERGRCwqLPz+/PTy9Ozu7OTi5HRydIR+fISCfPT29Pz6/PTy7MTCxCwuLJSKfIx6XMzKzDQyNOzizJSOhIyCdOTm5Dw+PJSSlKSipLy+vOzi1OTSvNTCnIRyVNTW1GRiZFxaXAQ6XMyyjNTS1GRmZFxeXHRmTFRWVKSmpKyurMzOzGxqbMTGxLS2tJyenKyqrDw6PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAauQIAQEBAMj0jAgFAwCA7JYwCRUCwWgoCBEUBOG47CAxJhSrqT5wERplQoC8ijYDEcJASJ4HKIYDAZFRoFGxwXHR4eH3lqICEiIyQcAAcMJSaIeHonKCMpkxMqAismKyuIixMsH5MBDw8eJS0mJpcdByYSkwAcEQUEBC4lo7UHL7sXwMAkKTAeogceu0QXMRIwFjISMxITNNNDARcmLx8zNTUH4F64NDUTNlHsk35BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= folder_home-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBDw6PBQWFCQiJAQCBFxeXMTCxJyanDwyLDQqLFRSVLSytJSSlISChCQmJERGRFRWVGxubKSmpJyenGRmZLy+vOzq7OTi5Ly6vGRiZPTy9Pz6/OTm5ExOTPT29BwaHNza3NS6tKx6XGQqBNy6pIyKjDwGBOzOvJSWlDQyNIRaLNRiBGwmBNyidLxWBHxGFNySXCwqLKyqrNR6LKxGBNTS1NTW1Jw+BEweDDQ2NAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaoQIBwCAgIiEjAgAAoGA6I5DBBUBgWjIZDqnwYGgVIoTGQQgyRiGRCgZCR1nTFcsFkHm9hBp2paDYbHAsZHW9eERkYGh4eGx4ag3gfSgMTIBshIiMkGyAlCCZTEpciJyQjGxcoKUQBEhcbKiQrLB4XEltDrhcaKi0utbcJra8bLzDAGrcxrTIXHi8zNCypEsO6EzU2IzQ3ONoTzK0BCAkDMQkIOTFlAH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= folder_html-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBERGRBQWFMzKzOzq7CwqLDw6NARqnAQ+XHR2dKyqrOTm5ExKTERCRHRydMTi7NTu9HS+1KSmpBweHDy67DyixHS61ITG3AxypByu7DxinBw+ZERmdIySjITC3ARypExOTDRurIR2RPTSdJyulEyGvBw+bFSyzJTK3LzKvPzivOTixNTChLSybGyCfCRSnBQqRASGtFyuzDw+PCRShPzy5OzerOTShKyaTEx6pCxerGRufBR+rOTezPTShNy6bER+1BxCfBQuRAxelFSixBw2VISq3GySrPTWlHyanIyitFSO3IymtCRujAxWhCRqlCQ6XGyWvNS2bFyGvDxuvCRSpLy+vMS+vGxqbFyO1GSi3EyO1FRaVCQuPLS2tDxyzKyWNFxaNCQyPGxubCxajERSVExKNJyenAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfZgACCAAECg4eIAAMEBQICBomDBwgJCgsEDA0BDg8BhwYQERKUDxOYDAyeghQVFhehGBmVlwwOqxobHB0eH6EfIAkPIYIiIyQlJhsnKBcpvrYiKissLS4vMDEyFjOvNAA1LDY3ODk6Oyc8PTIyFzQ1Jj42P0A6QTtCQ0REIEUORkdIkihZwsSekBhNnDyBciCKiSNSplDRUcWKkRhXCGDJYgiGli1cpuTocsILjytfFmRpACAGRTBhRogZgzHlAjKGWnIoY+bMgRgBDHRBo/LAIZoxuhwKatRPIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 folder_image-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPz+BAQCBExKTBQWFMzKzOTm5CwuLERCRARqnAQ+XHR2dKSmpHRydCQiJMTi7NTu9HS+1Dy67DyixITC3BR2pBweHByu7ASGtFSyzHS61AxypExOTBSazBRupJQOFBSCtDxKfKTa9AxelNz61MTaxDw+PPzGpLweHJTO3ESu3DRilFymXCxKRBRypBR+rDwCBNxmVORiRKQWFCyKvJTWhDSOPCRONFSixDQaHNROPNQ2JLRubHTC5DR6rHx6fFSqRCRyLGRmXGxqbIymtCRujAxWhMySjMQ2JMyqrKTW5ERijJSenFSGXGRmZLy+vMTGxMTCvERGRMxCNOzq7NTe5LSurISKhHR2fLy6vLS2tKyurGxubCwqLOSKfOzy9Nza3KSmrIyGjGxmZKyqrIRqZIyKjFxaXJyenDw6PDw6NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAffgACCAAECg4eIAAMEBQICBomDBwgJCguMAoUMAYcNDg8QlAyXBaWcgg0REhCfExSVpIYAFRYXEhgZE60aCQwbghUcHRQXtri6DxMHgh4fICEiIyTFtxkOJQAeJicoKSojKywtLsUZJS8wMTIpMyA0NTYKIiIaNwc4OTo7PD0+P0BBhAwhUkTFAQNGjiBJomQJExsMmjh5AkVIFANQpEyhsqSKlStXmmDJomVLFC5Gunj5QiALmDAKxGSpMsYiAC5kqjhZUOaKmUdmzoAJgkaQgQYCmogJEmRQAC5pAPgJBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 folder_important-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBExGTKQqLPz+/KQqNAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM7CLoQwZAFIV6Es15Jqd2ZtzXUMIhXZqJYaZ5aK7zwp6h0zc05i+c6Eg8oCnWOR0eHQGEKnEWHdDoF+BMAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== folder_locked-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBQSFMzKzOTm5CwuLERCRARqnAQ+XHR2dKSmpOzm5GxqbCQiJMTi7NTu9HS+1HRydOTm1Ozq7Dy67DyixHS61ITC3AxypERGRBweHByu7ASGtFyy1DSOtDRmfExOTBSazBR+rCwqLAxWhAxelByGtDSaxAwODHy+1Dw+PPT29IyqvCxujOzu7NTW1Nza3ExGJJyebKyqfMTCpFRSPOTi5DQqHOTezDw2NMTGxKyqhMTGrGxmXDQ2NMTCxMTGpHx6bHx2bBQWFIyOXDQuDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfDgACCAAECg4eIAAMEBQICBomDBwgJCgsEDAKFDQGHDg8QEZQSlxMUDJ2CDhUWF6AYGZWXFBqCGxwdFh4XGK8fIAohtiIIIx25EZwBDREHgiQjJSYmGScoKSoRKQ8rggIsDC0uJS4oGygoAyjdAAcsLxQUMDEyMzQ1EzapBy8MDDc36tFwgONFjlQ6dgCEEZBHDx8+ctRIRehHAyAwZASZIGRIEBoUBwUwIGMCiwFEaBQJichIjo9FZLBsacRIAB0A/AQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= folder_man-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBQWFMzKzOzq5ERCRCwqLARqnAQ+XHR2dKSmpHRydCQiJMTi7NTu9HS+1KyqrMzOzOTi5Ozu5Dy67DyixHS61ITC3ARypOzq7ERGRFRWVJyanByu7ASGtFyy1Hy+1FRSVOzu7BSazBR+rFSyzJTK3Dw+PFxaXPTy7LSyrAxWhAxelLy6vMTGxNTS1Ly6tFyuzMS+vPz69NTW1MTCvIyOjPT29OTm5HRybFSixLy+tLS2tISGhGxubIymtCRujCRqlHx6fNza1GRiZMTCxGxqZLy+vFxeXLSytKyurGxqbISChFxeZDw6PDw6NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAffgACCAAECg4eIAAMEBQYCB4mDBggJCguMBgEGDAGHDQ4PEJQKERITFBOdgg0VFhegGBmVlxobABwdHh8WIBchsLIKIiIjCyQZJR+7JhcnoBAoKSoqKywtLi8wMbsyrwYpGhowHTMqNCqkyR8XKBwTNTY3KjgFOTopLS0ZO98wPD0+JhR490MAkCAshHyTsCLCEAlEYEgoIsCIjRlHDNzy0UFBDBtIbBzZ4KJHBB0aAQhIoqCHESQ9dAjooWQJE1uCBBRpkoSDExEcUnRYwOTJIQECNmwQwEFQgANQAPgJBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 folder_open-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBQWFOzi1Ozq7ERCRCwqLPz+/PT29Ozu7OTm5FRSVHRydIR+fISCfMTCvAQ6XARqnJSKfIx6XPz6/MzKxJTa9Mzq9JzO5PTy7OzizJSOhIyCdOTi5Dy65FTC7HS2zMzm7OTSvNTCnIRyVNza3Dw+PASq5BSGrFyqzMyyjMzOzAR+zBRejBxqnBx+rHRmTPTy9IyqvDRylFxaXNze3DRujAQ2VLSyrDQ2NNTW1NTS1AQ6VJyenGxqbMTGxLy6vGRiZKyurKyqrKSmpDw6PDw6NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfCgACCAAECg4eIAAMEBQYCB4mHAQgJCgsLDAEGDQGIkw4PBQkJBYwQnRESEREIoRMUE6IVChYGERcYGaoRGhsbHBQdHgu2HyAhGSK6qxsjJCUmJwARKCkpKsjKqislLNIRLS4vLykw2MkRMRAGhDIJMzTiLzDXETUQ0gAGCgU2HjM35N3AkYMdAB0EbCjcwcPCDBguevjIR0jHDwgWLACBECRIBB8GJekQMiRIjhxEIlBMFOBADR9FIhiJ5OnAEQB+AgEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== folder_orange-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBwWHNTO1Ozq7ExGTDQuNERCRJxmDFw6DGxubKymrMzOzOzu7Hx2fCwqLOzaxPTm1NSyfKSipBweHOSmRMSKRNy2jJxuFFw+DKyqrOSeJKxqFMyaXNSyhNSufFRSVMSCJKRyHLRuFMSORNy6nPTezHxaFIxmFJxqDJxyHPz+/LyqjJR2NPz6/NTS1KyehIxqNJRmDLyWXPTu9PTy9Ozm7Nza3MzKzMzK1OTi5MTCxMTGxDQ2NMzGzLy+vLy2vKyurGRiZLSytLy6vFxaXHRudDw6PDQyNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAe/gACCAAECg4eIAAMEBQYGB4mDCAkKCwwNDgYBBg8BhxAREhOUDxSMBQWeghUWFxOhGBkaCxuMBqscHRceHyCwCbMhqyIZIx0kJR4gJicSIAiCECMoKSorKyS6yhHQAAYsBS0uKSkZHSsdHc+CCC8vqDAxMtQzJDTdBjU2NwUsODg5Wsxz0e2ADhw7/sEgwKOHwwW3BAXwsYAHARg/eAAJIgRiogAHhhApEoSIkCERI4E0QmHDESSREAWAkASAn0AAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== folder_orange_open-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBQWFOTm5ERCRCwqLPz+/PTy9PTy7OTi5FRSVHRydISCfIR+fPT29Ozu7MTCxFw+BJxqBFQ+BJSOhIRyVMTGxPzSlPzmxOTGnOzizIx6XIyCdOyeLPSuTNSubOTSvNTCnNza3Dw+POSGBLRyDMyeXAQ6XMyyjMzKzMyWBKx6FJx2FHRmTLy+xDw6PLyqjJR2LJRyDFxaXOzq7JRuLEw2BKyurDQyNNze3NTW1NTS1MzOzJyenDQ2NGxqbLy6vJyanGRiZLS2tKyqrCwuLKSmpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfEgACCAAECg4eIAAMEBAUCBomHAQcICQoECwEFDAGIkw0OBA8PEIwRnRITFBIHDRAVFhWipBcFEhgZGhMSEg8bGxUcHQQKth4fIBoburwbISIWIyQAEiUmJicnyrooKRYqBdQrEywt1yfJGxQuLzCEozEyM+XnEjQv4QAFEDUKCjE2JrRoYeMGjmkAchAYoWPEDh49YrBQ5SMfoR9AXvRQcSFCkBcUhFgcFCDHEBxBiOAoQgFhpABGaPg4IiFHJE8GbPoJBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 folder_red-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBExKTBwWHMzKzOzm7ERCRExGTCwqLIw6FFQiDHx2fKyqrOzu7CQiJOzOxPTe1MySfKymrOzq7Nx2TLxmTNSelJQ+FMzOzNxiNKw+HMR6ZMyWhNSajHRydFRSVLxSLJRKJKRKJKQ+HNSWhNSmnHQ6FIRGHJRCHPz6/LSajIRONPTu9Nza3KyShLR6ZPz+/DQyNOTi5NTS1MTCxGxubGxqbMzGzLy6vLSytGRiZHRudDw6PAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAanQIAQEBAMj0jAgFAwHBDJoSGhWDAIDUHgsAgcHQ9IhLqQMAsTr9BBqUTClktVgmkYhIOMprLhdOBUHh9rICEiIyN8JCVwdwAOIiYnJyiHiRtvjgYpBSorJgknIpYRmikpLAUtLp+hIy+aLKkFMC0tGJ4mK44xBDKqLTMEBDTFNY5EMTY0MzM3NDg4OR7IQwExOjnROTk6B1FC1x8SEjs84EcBCDEAfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== folder_red_open-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBQWFOTi5OTm5CwqLPz+/PTy9Ozu7Nze3Ozq7HRydISCfPT29PTy7MTGxFQiDIw6FJSKfIx6XPz6/MzKzERGRNyypPTWzOzi1OzizIyCdDw+PNRuTNyCZMSSfOzW1OTSvNTCnIRyVNTS1ERCRMxGFJxGJIRKJLyCbAQ6XMyyjLRWFHRmTLy+xLSelIxWPEQeBGReVIxOJIRSPKyurDQyNNTW1JxOLEwiDKSipGRiZMTCxLy6vJyenLS2tCwuLFxaXKSmpDQ2NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAe+gACCAAECg4eIAAMEBQICBomHAQcICQoLAoUMAYiTDQ0LDg4PCgQQnBESEREHoBMUEwUVDgsWFxEYGRiqEQ8aG68cBQQdER4fIBghu6saIiMkJSYAEScoKSrJyxIrLNEd1C0p1ygo2coRLi/gAaIwMSnx5SoyM+uCHQ8LChrv8TQ1ZNiYBuCGgoMKcJSwACNHCh07wAkK0IFHj4UQevjwEeGHREk3ZtjwAcSGjQgfEwUIIuTHEJSROhkgAsBPIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 folder_sound-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBQWFMzOzOTm5ERCRCwqLARqnAQ+XHR2dKyqrMzKzHRydCQiJMTi7NTu9HS61KSmpDy67DyexExSVITC3AxypBweHByu7FRiZDRiZHy+1ARypExaXBy2xGRqZFSyzJTK3AQ+RByqtASCtASGtFyuzDw+PATC1ByGlFxeXISGhJSWlFRWVAxmlBR2pBR+rAQ2PAS2xHS2vMTCxJyenLS2tCRujAxWhAxelFSixAQaHARibARudAR2hEySnPTy9Nza3GRiZNTS1IymtCRqlARWXDyCjPz6/MTGxLy+vMS+vGxqbAQiJARaZEx+hLy6vKyurERGRBQuNCw6PISanFxaXDw6PCQ2NDRGRDw6NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfYgACCAAECg4eIAAMEBQYCB4mDBggJCgsMBQIBBg0Bhw4PEBGUDRKMBQWegg4TFBUVEBYXlZeNghgZGhsCFRyhFh0JDRWCAx4fGg0gCiERIqEcBoIjHyQeDcMlJhQnEQ8oANQpKissLS4vMDEmJhEoMjPxNDU2Ny44OTo6FzsGPD0+fgABEUTIECIMiuAzIk3GkR5IbgRJMoSAkiVKmDSRBsDJEyg1hBQYUqNGlBtSGkwZRGUDEyILWCxYcmPBgiYrB1WxEsBTgANXbCwYggVRFi2Ifm4B4CcQACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= folder_tar-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBQWFMzKzOTm5ERCRCwqLARqnAQ+XHR2dKSmpHRydCQiJMTi7NTu9Hy+1ARypDy67DyixHS61ITC3Ozq7BweHJySbJyWbAxypExOTPz21KyqjPz67OzmxFSyzJTK3LSujASGtDw+PKSehPz69Pz23OzitPTqvOzerKSaZBR2pBR+rKSefMy+dKyeTIR2NAxWhAxelFSixJyadOzirLyubLyqVJySPHRmJIymtCRujCRqlPTqzOzW5OzSzNzSrLyqXLSeTJSGNMTGxMS+vLy6vGxqbJSKZOzOxNzGtNzOhKSSRIR+LGReHLy+vKyurOTWlHxyJFxSFLS2tKyqrERGRHRuRNzKfNTGdGxeJGxiNFxaXJyenDw6PDw6NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfcgACCAAECg4eIAAMEBQYCB4mDBggJCguMAgEGDAGHDQ4PEBEJDJcFp52CDRITFKAVo6UEFgaCFxgZGRgUFa8apBsAuhwdHh+5IBQhrwYZIh3PHdAdGSMTyQ4kJR4mJycdKCkqKywtIyMUJC4cKR7EKC8wMTIzMxE0BjUmJjY2NzgwcuggsIOHjB7NfPwAEkTIkBxEdBQxUuQIEgNJgihZwgRGEyJOnhyBciTKxSRSpDBh0iRGjClUjlSJYgXJFQBYbmTREmOLDi4BDnTxsgDJl0E5uXBBFBQMAD+BAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 folder_txt-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAMR6RPwCBAQCBExKTPzGjBQWFMzOzOTm5ERCRCwqLPyGBPzKjARqnAQ+XHR2dKSmpMzKzHRydPyGDNTu9Hy+1OR2BNSOXHS+1MTi7ITC3AxypOzq7KRKBPyCDOySZPzizPTWxFSyzHS61ITG3FROTCQSBMxmJNRyROy2lOy2nASGtDyixJTK3FxGNIRWLMR+XPzStPTKrBRupBR+tFyuzDw+PDQuJIRSNAxWhAxmnBR2pBR+rPT29FxaVEw6LKRuVIx6ZISitCRujAxelAxmlFSixOzu7JyWjBwaFKSShNTW1MTGxDQ2NMTCxNze3Nza3HRqXMS+vGxubGRiZLSytCwuLERGRJyenGxqbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAAfLgAABgwIDg4eIAQSCBQYHCAMJiYMKCwAMDQ4PEAcDAggRApQSlhMUmJqOBweiFQoKBBYXGBMZGpkPBhsIHBUdHh8gISIjtCOoJCUcJicoHykqK8MstBQIASUtLi8wMTIzKtE0Ihg1gwg2Ny8xKDg5OjvhItcBCDw9Pj9AQUI4Q0QMipirZ2TDERJIkihZwg+HEHpMmjg58OQIFANLomSUQi+AACZTohiAkDEKFSocJwmoMoWKSSoPpFiZdEhAgh5XHmBhQjORTZ5+AgEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== folder_video-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExOTBQWFMzKzOTm5ERCRCwqLARqnAQ+XHR2dKSmpHRydCQiJMTi7NTu9Hy+1Hx6dJyenLy6vIyOjDy67DyixHS61ITC3ARypOzq7ERGRFxaPKyqrBweHByu7ASGtFSyzITG3KSOPKyurBSazBR+rJTK3HS+1Hx6ZNzObAxWhAxelAxmlBRupBR+tFyuzDw+POzibNzOZIyqvCRujLyiPJyCPJSWlNTS1ISitFSixHxiFGxeJFxWLExKNCRqlDw2BFROHHxqPMSqVISChMzOzGxqZISCbLSaRKSWTFxWPNzGZNTCZLy+vLSytGxubJSSfGRiTMyyVLymTLyiRMSqTEQ+JGxqbNS+XNzKZOTWbLy2ZFxaXDw6PIyGbOzidOzifMy6XCwmFGxmXDw6LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfigACCAAECg4eIAAMEBQYCB4mDBggJCguMAgEGDAGHDQ4PEJQREowFBZ0TFA0VFhegGBkJEZcaGxwdHh8gFiEXGKAiowIjHCQlCCYgvL4noCgGKSoGCyssLS4vyxYwrzEyM9MSNDUrK9jKIBcGNiMjNwY4Gjk65dcIOwY8PT0+PwYUAuTIQaDeCiAGgggZMoQDEQNFchghMIHiEQNIkihZwoRJkx8RCDhxMuEJFAMGokiZQoRKFStXjpQk0QHLBgDRrEzJomULlwFHukhYgMWLIANfwIAJw+WKmDFkAjQoA8BPIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 folder_violet-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBExKTBwWHMzKzOzq7ERCRExGTCwqLHQWhEQOVHR2dKyqrNTS1PTy9Hx2fCQiJOTK7OzW9LyKzGxubLRW1JxOtLyCzMSS1HwijKSipLQ61HwinKxuvHQajFRSVJQytIQqlKRqvMSe1GQebHQihLSCxNzG5Pz+/KyStHQ6hPz6/PTu9Nza3KSGrJxmrOzm7MzOzDw6PDQyNOTi5MzGzMTCxGxqbLy6vLSytHRudGRiZLy2vDQuNFxaXDQ6NCH5BAEAAAAALAAAAAAQABAAAAaoQIAQEBAMj0jAgFAwHBDJoSGhWDAaDkPxEThCIpIJlcJgFgpdIaRiuYAxGcVD02gKBxuOpXPBvD1VH2ogISEceiIXI2ATBmohJAklGYaIJieOAAIoBSkqJCUlHJUmmQYrDiwFLS6foRwvpqkwMCstDTGtJCoyQjMELTQttw01Nsc3B0MBMxQ2DSfGNjg5OplHzDs5ODw5DMlRQgE9PhoMOjPh2BA/AH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= folder_violet_open-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBQWFOTi5OTm5CwqLPz+/PTy7Ozu7HRydISCfPT29Ozq7Nze3MTGxEQOTGwahDwKRJSKfIx6XOzi1Pz6/MTKxNSi5OTS7Mym1OzizJSOhIyCdDw+PKxSzLRq1LSCxOTSvNTCnIRyVNTW1JwixHwqlKRutOTS5AQ6XMyyjNTS1JwerHQmfIQylHRmTLzCvKyWtHRChHwuhFxaXERCRHQ+fLSytDQ2NKSmpGxqbLy6vDwOTJyenDQyNKyqrCwuLDw6PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfDgACCAAECg4eIAAMEBQICBomHAQcICYwChQoBiJMLCwUMBw0NDg+bEBESEAcLDRMUExUMFggXAhAYGRoREBAIGxscFB0EBB4QHyAhGrq8EBsiIyQlHgAQJicnKMspuyorJCzVEi0uLy7Z2xopEDAx1QEMDDIzLjTZ2hI174I2CQ0EHMi4ge7EDQk4qgHI4aChAxYsLsg4J0GHQkI5dsSIeCFGDB49fFwcFOBHDRw8cOAAAmEkpyA1fOjoISQSJwPV/AQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= folder_wordprocessing-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExOTBQSFMzKzOTm5ERCRDQuLARqnAQ+XHRydKSmpExKTCQiHMTi7NTu9HS+1HR2dCQiJDy67DyixHS61ITC3AxypKyqrBweHGxqbGRmZFxaXFRSVERGRPz+/ITG3JyalOze1PTm3Ozi1PTm1Hx2bJTK3IyOjPTy9CQqJFyuzDw+PNTGnDQyNPTq3Ozq7MS2hASGtKyaXCwqHBwaHFxWTKyahLSijKyehHRmXHRqNFSixHxyNAwKDERCPAQGBCwqLIymtCRujAxWhCRqlMS+vMTGxIyCVJSSfLy6vLS2tLSytGxubCwqJExGJEQ+JBQWFJyanDw6NDQ2NBQaFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfUgACCAAECg4eIAAMEBQIGB4mDBggJCguMDAEGCgGHDQ4PEJQRlwWmnYISExQVoBYXCREYjAaCGREaGxwdHh8PIJQKhgAhIiMkJSQkJhUnrrUGKCkf1B8pGyoUK60sLSouIS8vMCUhBw0xMjIVBjM0NTY3ODk5Og0NOwgXPCw9AD4BBvwwMABIgCBChhApUqtBhgw1INaIWMPIESMaGiIRsbFjkhpKlmDQYKgGx5MdDyxhgqFJLSdPoMiU+YRGFA5SRk4RRCWDix9TnFRxISiAE6J+AgEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== folder_yellow-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBwWHMzKzOzq7ExGTCwqLERCRJSSDFxWDGxubKyqrNTS1Hx2fCQiJOzqzPTy1NTKfHRydOTWTMSyTNTKjNzOjJyWFHR2dKymrOTaLKyaFLyyRMS6ZFRSVLy2JKSeHNTOnNTKhHR2FISGHIyKHKyeFOzmxPz+/LS2lIyCNJSWJMzKfPz6/PTy9Nze3KyqhLS2XPTu9Ozm7Nza3MzK1LSyjIyONDQyNOTi5NTO1MTGxMTCxMzGzLy6vLSutGRiZLy2vKyurKSipAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAe0gACCAAECg4eIAAMEBQYGB4mDCAkKCwwNjYUOAYcPEBESlBMMjAUFnIIPFBUWnxcYChkajAaCAxscHR4SrREWlBkfqSAYIRy5uyKfIwipISQlJhgnx7oSKM0ABikFKivQCSwn1C3ZCC4vLwUwMd/RGDLZBjPqNCk1NTY33zjZOQQ1dOBrsIMHjx49FtQSFCDHgh47GvhA+AOIwkQNgwARUnHIxUiEcnwgwmBBDpCHAjw46ScQACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= folder_yellow_open-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBQWFNze3Ozq7ERCRCwqLPz+/PTy9PT29FRSVHRydIR+fISCfOzu7OTm5MTCxFRWBIyOFFRSBJSKfIRyVOzqnPTuzNzapOzi1OzizIx6XIyCdNzORNzSZMTCfOzqzOTSvNTCnNTW1NTGFKSaHLy6ZAQ6XMyyjMzKzDw+PLS+DHyGHIySJHRmTLy+xLS2lIyKPISGJGReVOTi5ISGNExKBKyqrDQyNNza3NTS1JyeJKSipGxqbMzOzLS2tJyanKyurLy6vKyutCwuLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfDgACCAAECg4eIAAMEBQYCB4mHAQgJCowLAQYMAYiTDQ4FCgoPEBARnBITFBIIoBUWFaEKBREGFBcYGaoUChobFRwdBRAGEh4fIBkhuqsbIiMWJAYAFCUmJifJG7ooKRYqK9QsLS4T19kZGxIvMNMBojEyMy4u5xQ0EeEABgUFBDUxbJBzYeMGjmkAchBYqGPHjggxeMy40UMfoRw+IvxQoSICEBgUgiCUlIOGkCFAiOCgYDFRgCILgqxsGYnQgRwA/AQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= ftp-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxaXNze3LSyrJyanPz+/Ozq7GxqbDxinBw+ZERmdIySjHRydMzOzPT29CwuNDRurIR2RPTSdJyulEyGvBw+bLzCxIyKhGxubERCRLzKvPzivPTmxNTChLSybGyCfCRSnBQqPLy6vLy2rCRShOTixPzy5OzerOTShLyaVEx6nCxerGRyhOTi3OzaxPTShNy6bEx6rER6zDRitBxCfPTq3LyulBw2VISq3GySrPTWlHyanIyitFSO3PTm1Ozi1LyqjDQyNCQ6XHSq3GyWvDxuvCRSpLSqpOzezAQCBCxGZCRKZExGLDQuHAwaLBQWHKymnOzexARCBJzOnGy2bDyePCxKJOzWvLymhAx6DAyGDDROLOTOpHRmVLyidLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfRgACCAAGFhoaDiQECjIwDAQQBiYKLBZYFBgcFkZMICQoLlwwNDgQPghAREhMUCBUWBRcMGBmnEBobHB0eHyAhIg4CIxenJCUmJygpKisVLAIGLSMPJBQuJi8wMTIzNCEWJjU2Dzc4OTo7PD0yK94DPj9AQUIUQ0QwFDFFRjchRz5IbARJEkLJkiVMmDRx8uQBlCgbgDyQMmUKlYpTqlSsYsXFFSwTK2bRMmWkyCxbuICkmKVlySwvpXTh4mWilJs4c3bB8uXLqUEBHggdSvSBn0AAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== link-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBFxaXPz+/AQCBKSipAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMgCLrc/jDKSau9OL/AuwxCKAzfOIwlcZIRKLJQMMyz5CcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== network-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBAQCBISChPz+/Nza3ARaZESanCyKlARudARGTLy+vNzq7ARmbMTCxARufAROVMzOzKSipARyfOzq7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVmICAGZFmKQiACweCSBImq41AYB5IodLq2hwWO0ejRWDac48Gb/QKNqNRoqspmrVcAUuIJBANS8sBIFCORUgooPEh4J8B67NgdsVBp9C5XWfl9LRMTCyReX19hARNojWlWLH+AAH4hACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= pipe-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBISChMTCxPz+/ARCBFxaXASChCH5BAEAAAAALAAAAAAQABAAAAM2CLoazpAFIV6UYZB6Yd5BtwRbEYqkYIqAQRir6KpnN8cdCddXivcbAy+S2qEOAuPx8MtZRP4EACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= shredder-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBERCBAQCBMTCBPz+xFxaXPz+/AQChISCBISC/DQyNPz+BARCRAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARcEMgZhBUzgzuIH4G2FYThnZUlCab5Ed0hC6nZ3Yh8JIKyLjCYboeZKIK6BDHTGwyViopEoWAkdwfqoKhIKLFUwXY79coUtLG4CFAcOOstWyNWyEXMO57p2/vxfhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== socket-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+xMTCBFxaXKSipDQyNPz+/MTCxISChAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARKEMgZpr1SjFqx1QHoTaA4AuV2EmmHEUUxsKoHB7FMGPbhI7gCgnchII6+AyJBtBhjx0KC2TsIp9QXcpm1HafNEQF8mhAOCdfEHwEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== trashcan_empty-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBKSipERCBARCRPz+/MTCxISChFxaXAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARREEgZapiYWjGIvVNQjEZ5BKUAApVgjEWJzCtAnIGgC8eZ5bre7ICosQQFVY9Y/CGVwiYmlwwsac7qVRp6WqNGKpQZ9m7DojH2t+lVMtMP3B8BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= trashcan_full-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+/Pz+xATCxMTCxMTCBKSipPyqXISCBFxaXISChAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARbEIAQJJU4BzEoIdSFbcNQnIVhBJ02GAeFIGxZjUl8KoHRagfeYqgo3kaxQOEwXPAyk4Mgtgg6jxYp1foETgPEKzSgBXOx0W9VIfZu2d3R5t3WhA5BEdQSQgP8EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 www-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxaXNze3LSyrJyanPz+/Ozq7GxqbDxinBw+ZERmdIySjHRydMzOzPT29CwuNDRurIR2RPTSdJyulEyGvBw+bLzCxIyKhGxubERCPLzKvPzivOTixNTChLSybGyCfCRSnBQqPLy6vOTi3Ly2rCRShPzy5OzerLyaVEx6nCxerGRyhOTezPTShNy6bEx6rER6zDRitBxCfPTu5PTq3LyqjBw2VISq3GySrPTWlHyanIyitFSO3LSqpPTm1DQyNCQ6XHSq3GyWvDxuvCRSpKyurOzizAQCBCxGZCRKZExGLDQuHAwaLBQWHKymnPTmxOzaxHx+fMTCvOzWvLymhHRmVExGPOTOpExOTERCRLyedBwaHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfWgACCAAGFhoaDiQECjIwDAQQBiYKLBZYFBgcFkZMICQoLlwwNDgQPghAREhMUCBUWBRcMGBmnEBobHB0eHyAhIg4jJBenJRwmJxIoKSoVKwIGwg8lFCwmLS4vMDEyIRYzNDUPNjc4OTo7PDAq3T0+Pj0/QBRBQi4UL0NENiFFPkbijoRAkiSJEiVLmDR54OQJFHEPREQRIWWihYlRMkCZQuXBgyIBihSpIjLAowBWroj7gaUIlpYvXWLJUuWKlgdbHvz44XHnzgdVami5qUinR50/efoJBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 zip-16:filesystems filesystems16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBIQChPzC/AQCBMQCxAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMeCBCh/i+IAesShNo4+v5gKI5kaZ7oxzCilLVvq/kJACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= cal1day-16:korganizer korganizer16 16:photo:16 16:R0lGODlhEAAQAIIAAAQCBPwCBAQC/AQCjPz+/MTCxKSipAAAACH5BAEAAAEALAAAAAAQABAAAANOCLrMEUDIOUS9AFLLhx8LIRZjKYZmMRCkaChFLHty/AIiS3y6q+QtT49wq8VotRtQJGwRf6Zmrlj7DJLQXsupTJmeEIN4TB5nII20wp8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= cal5days-16:korganizer korganizer16 16:photo:16 16:R0lGODlhEAAQAIIAAAQCBPwCBAQC/AQCjPz+/MTCxKSipAAAACH5BAEAAAEALAAAAAAQABAAAANMCLrMEUDIOUS9AFLLhx8LIRZjKYbj55GioRRwoQ5x4QIiIdMmcec7jy53q81qP9OO5VMAj8RXTFWzOZW95HDLdEEM4LA4nIE0zgp/AgAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 cal7days-16:korganizer korganizer16 16:photo:16 16:R0lGODlhEAAQAIIAAAQCBPwCBAQC/AQCjPz+/MTCxKSipAAAACH5BAEAAAEALAAAAAAQABAAAANPCLrMEUDIOUS9AFLLhx8LIRZjKYbj55GioRRwoQ5x4QIiwcp0fucsj873qvGMv5Jw2FIACUsW4WakGW1O046I05qmGYBhTC6TM5CGWuFPAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 calappointment-16:korganizer korganizer16 16:photo:16 16:R0lGODlhEAAQAIMAAAQCBPwCBAQC/AQCjPz+/MTCxPz+BISCBISChKSipAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAARbEMhJaQhA6D1E/wDGeeRgDhOhFoTBEi+REgdrIHScSEVvAD9Xr7cDqGSGpFEnQSqTv2NxCFQOiU1VEAiTZmstHFg1vQKuw+LxxfYaV/AuOQRI2O/4ewhT6Uv8EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 calbell-16:korganizer korganizer16 16:photo:16 16:R0lGODlhDwAOAIIAAPwCBISCBPz+BIQCBMTCxISChPz+/AQCBCH5BAEAAAAALAAAAAAPAA4AAAM+CLrR+zCIAWsgLVRGRBhOVQiG94WPVAbHaZHYAWqRYLbge88RsbInGuBCEhRYrZYm4xk4nYdoKzKIbiKHawIAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== callist-16:korganizer korganizer16 16:photo:16 16:R0lGODlhEAAQAIMAAAQCBPwCBAQC/AQCjPz+/KSipPzerMRaBEQCBAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAARDEMhJaQhA6D1E/wDGeeRgDhOhruyatjBRSIRxxOsMEAdC0BUZDcfSEYvDo3Bn++2Cxt7RqFxWhZiCdsvdhjCVsMQfAQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 calmonth-16:korganizer korganizer16 16:photo:16 16:R0lGODlhEAAQAIIAAAQCBPwCBAQC/AQCjPz+/MTCxKSipAAAACH5BAEAAAEALAAAAAAQABAAAANSCLrMEUDIOUS9AFLLhx8LIRZjKYbiRxLFIBpK0Q6z7MkwkJIe8b0KEeuWchFysuStVsjtfMbeMQitWpG25YfmNK1WU53XNIUYzug0OgNpuBX+BAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 caltoday-16:korganizer korganizer16 16:photo:16 16:R0lGODlhEAAQAIMAAAQCBPwCBAQC/AQCjPz+/MTCxKSipPyCBMRaBPyqXAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAARTEMhJaQhA6D1E/wDGeeRgDhOhFmurpi5LyIQhFfiBIAfuFzaAioBIJBCummRYPCaDPh3vhwsOZdihNfa8Ub/AJXemFZPPNBvGwG672yFMZS7xRwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== caltodo-16:korganizer korganizer16 16:photo:16 16:R0lGODlhEAAQAIMAAAQCBAT+BAQC/AQCjPz+/MTCxPzCxKSipPwCBMQCBIQCBAAAAAAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAARaEMhJaQhA6D1E/wDGeeRgDhOhFmurpi5LyMYhFXiuFwZiA6qZYbbqJX5BIw2RAPxwAAWCyWMCCsiXFGEEErKz6LQZfOqiTR1YJiGq1rFyyHmo2+/1EKbCl/gjACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= adjustcol-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBGRiZAQCBPz+/CH5BAEAAAAALAAAAAAQABAAAAI7hI8JAWL+IgvwUSSY2Lz7VTXXkS2NdJ6TwiSaB3PNQNdCbc/4cO9OjwPmhDQiTxfcHY1MpE35g0IB/gIAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== adjustrow-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBGRiZAQCBPz+/CH5BAEAAAAALAAAAAAQABAAAAI5hI8JEcItooxG1oEzBoJ7oWlHd4VbNZpbx3LqUFGuajTPhI8kSLfsO0rRUCXT5wPkyHhGhsOJs/gLACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= black_sum-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIdhI+py60BY2QwhVYdytpw/WFXF1LjcW6S1LVu6xcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== border_all-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAAQCBPwCBCH5BAEAAAEALAAAAAAQABAAAAIjhI+pq+FuHjwyRInqfRkDTXkgQ5YLOH6it00pyqqcPJk26RcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== border_bottom-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAAQCBPwCBCH5BAEAAAEALAAAAAAQABAAAAInRIynGe0PFTQz2kdxzHf72iSiRDpc2F1niaafBroYQNe2fdx6HfgFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= border_fall-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAAQCBPwCBCH5BAEAAAEALAAAAAAQABAAAAIrRIyneRYP4wPUKWmr3E5b+DVh9GkYuFALiqnsJp6nObYZB5ow2a3Jvwv6CwAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 border_horizontal-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAAQCBPwCBCH5BAEAAAEALAAAAAAQABAAAAImRIynGe0PFTQz2kdxzHf7CoTiSB7kKUpa1Vlc86rtSjvxnOSL4hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== border_inside-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAAQCBPwCBCH5BAEAAAEALAAAAAAQABAAAAIrRIygxxYPF4zzyenqxfVk2m0g9lnKiabqqoYl43YwGcqiFWv22zRnD/AXAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 border_left-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAAQCBPwCBCH5BAEAAAEALAAAAAAQABAAAAInBHKJmxYPY3TyVCozsjMbrk3gM27KyZDlioVQS3qwO7Nl6KC6q/kFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= border_outline-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAAQCBPwCBCH5BAEAAAEALAAAAAAQABAAAAIrhI8ZybgQYoTy2YqtwVTunVVfN3HQsaTnc5Kp2Ibw5Zm0PHJ2w7O8I5P5CwAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 border_remove-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAAQCBPwCBCH5BAEAAAEALAAAAAAQABAAAAIjRIynGe0PFTQz2kdxzHf72iSiRDpc2F1niaafBrraSMuQXwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== border_right-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAAQCBPwCBCH5BAEAAAEALAAAAAAQABAAAAInRIynaOEPH5hRRVrzbJBLn32g1TXJuWBdpYYiy47hBl+yRqH6HfoFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= border_top-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAAQCBPwCBCH5BAEAAAEALAAAAAAQABAAAAImhI8ZyRgPo3xgVnmnprbvnUEhx1XmgpLRmH7e+rowFssleuaBXwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== border_up-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAAQCBPwCBCH5BAEAAAEALAAAAAAQABAAAAItRIynwOEPH0vRuGkjnFKjpmgX2FVkuBwNhapZKZ3VyMKcGJPv5eJmAkz5RP4CACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= border_vertical-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAAQCBPwCBCH5BAEAAAEALAAAAAAQABAAAAIrRIygxxYPF4zzyenqxfVk2m0g9llmsiCmVjJh65Jh59GtGMuzqqQNDQz4CwAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 cell_edit-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBPz+/ISChCH5BAEAAAAALAAAAAAQABAAAAIshI+pm+EPnwmi2msDoLgLzQWDV4HlSJof6qki+W0nrMKlbN9bxGvMDwwG/QUAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== cell_layout-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+/PzerMTCxPyqXHx+fAAAACH5BAEAAAAALAAAAAAQABAAAANCCLrc/i3ISacKIuutA8ACxWUeJg0DqBHhd6ZiRpQBag9F2n13FRis0q1QUAmCvFuKRTAYWhIi0bhz+SqQrHbL9ScAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= chart-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBAQCxAQC/AT+/MTC/Pz+BAAAACH5BAEAAAAALAAAAAAQABAAAANMCLocHiyuIASU6lE7Xx7DdgEBQVwBKE4mqlZjeT4vl7VFkYZUjOuGkMFiuJ1yKUNAWTQGkEKDknUESpdXkkYjnWIWzOVX0SyPJwx/AgAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 comment-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+BPz+/Hx+BAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM5CLrc/i3ISacKYuStuwhAMBATKRHkAGJeu60qagqmuHK4B6Pn3N0u147Ha8FyOVCowlRCntAo1J8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= deletecell-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIIAAASC/AQCBPz+/PwCBMQCBISChAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANICLrc/i3ISacKIuutA8BcKAwfNwwmQYDZoJ6tWrBZoRKuXIb2XRS7UG4wC25yOIGHFvu9PJ8KcRbQOVzAheoxbRCyDOKj4E8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= delete_table-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIIAAASC/AQCBPz+/PwCBMQCBISChAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANPCLHcDDCIOSUVAaqLeY5O+G2XRQVDdA0DNxCEwrwEu9AFORVw3ee6Cu8HFKFgA2AQQ6uNTJNXYZgCNZKFBay4IhQuMBUFW/LKZlkHoOBPAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 dissociatecell-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIEAAASC/AQCBPz+/PwCBCH5BAEAAAAALAAAAAAQABAAAAI0hI+pm+EPoQlC0GqxnfV2HUzR6HDWgA5Bqppr+qIhcMUqO5Oki+M87KN1ejCRTsJIKhP+AgAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 first_letter_upper-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIohI+py72RIJOHRmBt3QaGz2GVBGJfKW4aiXhX2sHxbKKneDv6zht+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 fontsizedown-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAInhI+pELHqmIkQNZrwfXYvzE1fBUrWoZniOjWdp0agjLL2i7rhDvgFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= fontsizeup-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAImhI+pEeoNIFyIzXStw3q/T4VVhJHHlDGjgZ6n1bLyCrqPyuJe4hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== funct-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAImhI+py60R3IkRVHQzo9BwD1qhqGneRU4gSqlVJ8Zy0mKPhOe6XwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== insertcell-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIIAAAQCBPwCBPz+/Pz+BATCBAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAAM7CLoa/k7IKQCEdNobc+UOMCijCD5jGjAMOowrIc/Wm77ATIe2leuETcrEYpSOJ88HpNxwmqdi40Tl+BMAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== inserttable-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBPz+/AAAACH5BAEAAAAALAAAAAAQABAAAAIuRI6JwCH/HBSBmUlxbarvO0nQJ0aa5XWodjZsiKbJGrbgaMuzW8M87jPoDgx/AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 lower-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIqhI+pELHqmIkQNZrwfXYvzE0QKGniQWmNhbYSeqXn6zJOBJLTuuuh4i8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= mergecell-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBPz+/ATCBCH5BAEAAAAALAAAAAAQABAAAAIyhI+pm+EPoQlC0GqxnfV2HUzR6HDWgKZpCFyBCrMurMoPvZovPsgd39MBbaQI44hU+AsAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== money-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIIAAASC/AQCBPz+BPwCBASCBATCBAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM+CLrcHMHJIEaUD16sqIUcQAne5pQaBglkZS6lxb6dRoIAQTzuphcFXWeW0xl/utIPGDQOSUdnA7IUhoocfwIAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== oscilloscope-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBOTm5Hx+fLy+vAQCfAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANKCLrcGjDK+IS9494AgrbEJ3CeUBRWpp2daaHhhZKuq75jh8pxTRaEQbAgFAIHv1VvR/vsdrnSCmdpagYnjfXS27Q+N29nQuYA/AkAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== percent-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIkhI+py70RUHxxQmosu6BOdWkNR35PVm1etqEsaKXnwTn2DfgFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= precminus-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBPz+/AAAACH5BAEAAAAALAAAAAAQABAAAAIthH8RiJvrmHogVoXNtFRDpjUf6JWkeUoXlpGBAMfC+cowbd+uwL54/rMFZf4CACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= precplus-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBPz+/AAAACH5BAEAAAAALAAAAAAQABAAAAI2hG8Rp4y9IGgszqhyspLueYHih43hiX7Iui5XprGTQNeCPNNBje86L9vBdr2a7xY0AllHm78AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= removecell-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIEAAAQCBASC/Pz+/PwCBCH5BAEAAAEALAAAAAAQABAAAAI5hG+hq+IvAGPwydlqxAohvnjHMChkR6YDcKaougZqCMdyGYqSG+jXKQtoNkGTUHPBDJMTH+jJ8RcAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= removecomment-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIIAAASC/AQCBPz+BPz+/Hx+BPwCBMQCBISChCH5BAEAAAAALAAAAAAQABAAAANVCLrc/i3ISacKYuStuwhAMBATKRHkUIScUBSeahhigBbzK+HGgXmHmYHXC41MqKDwcGDFMryCz4gi3YQwkKiFY+ZAoYrUF5g1HV3G7DFuFBvSx8GfAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 resizecol-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBFxaXAQCBDQyNPz+/AAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMyCLrcG0A4CZ90saohuv+XEgxYxkDhQp2lyIBwKhB0bct2TuB6zfe7F5D26xV1x9zFnwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== resizerow-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBFxaXAQCBPz+/CH5BAEAAAAALAAAAAAQABAAAAIyhI+pmxHinph0GnqH3hoIDwocd3zZ2F0lmoInWq5s/I60xw5hmF8WPnNAhJUK44hM+AsAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== series-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBGRiZAAAACH5BAEAAAAALAAAAAAQABAAAAIjhI+py+0fUGRhGrswVtr1FgiGsGlhZVWAuarr9byyB8f24hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== sort_decrease-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIIAAAT+BPwCBAQCBAQC/FxaXAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM5CBDM+uKp8KiMsmaAs82dtnGeCHnNp4TjNQ4jq8CbDNOroIe3ROyEx2A4vOgkOBzgFxQ6Xa0owJ8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= sort_incr-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIIAAAT+BAQC/AQCBPwCBFxaXAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM4CAqxLm61CGBs81FMrQxgpnhKJlaXFJHUGg0w7DrDUmvtPQo8qyuEHoHW6hEVv+DQFvuhWtCFPwEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== special_paste-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+xPz+BNTS1MzGLMRaBMzOzPz+rPyqXPz+/MzGNDQyNKSipAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARoEMgJQhBySGx7IEQwFKMWGKgRHNZRIAJSVAm6usIwCEo+BDWVJ/CKzYAplWJZItGSgSVPZBEgU9EFQyGyWoK25XJ4DTO2iob6CxVLe2ys4rw9e8HKd8ybVJ7ndgEVQz09e1YUEmQefhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== strike_out-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBGRiZAAAACH5BAEAAAAALAAAAAAQABAAAAIghI+py+0BgwOS1gXnuS/b6ClCpCUcclJMmKIGWcby5BcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== text_bottom-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIVhI+py+0Po5y0hYtzrkB7zH0fN/kFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= text_center-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIbhI+pm+EPIZsnRkqtDnhu1zHfFSpjaY4PavgFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= text_left-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIbhI+pm+EPIZsgRoqr3Vnt102fFSJjUC6nlPoFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= text_middle-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIXhI+py+0PT5i01pisphjt3UmfFZYm5hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== text_multirow-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIbhI+pm+EPIZsg2kfZvblXbwTg10WlA4rjyvgFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= text_right-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIahI+pm+EPIZstSrqsDhhv1ylfFE5jiYwX6hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== text_top-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIWhI9pwe2uYnq0yQtqxbz7D4biSIZ+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 upper-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAImhI+pEeoNIFyIzXStw3q/dR2hhEVcJqamuq6Z9brlNtKMeHuKXwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== vertical_text-16:kspread kspread16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIihI+pFrHqQHynTRrvyxQ12YWQWJGMpC0f2E1psr4eaj5+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 applix-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFRSVFxaXFxeXNze3Ly2rJyanOTi3Pz+/Ozq7HRydFxaVISGhGxubMzOzDQuLExKTCwqLIyKjGxqbERCRCwuLJSSlOTi5BQSFPT29IyKhDQyNISChDw6PBweHMS6pPz69Pz29PTq3Ozm3MSynMTGxAwKDPTu5Ozi1LyulExOTCQiJPTm1OzezLyqlLSyrDw2NOTazOzizOzaxLyqjKSipBwaHOTStLymhLymfGRmXNzKtOTOpLyidMTCtMS+rCH5BAEAAAAALAAAAAAQABAAAAa9QIAQEBAMikfjcCkgOJ2FgCGwFAYOiCwioUAYFtUrgtFFNBzeB5OAgESyEsWEUjFYAJYJ4hLBoDMHBRobAAaGehwdHnoZCQcfEUKHCBQBAxsgISIjJIRCeSUmHAYmJSInKCmRkgYqGw4ZKxMiLC0unoUvFBQQMBQRMTIzNBVDFjUrGwO9Nh8zNzi4BhM2LyIvGhgLNzc5akM6DsEyMjsfPDw9uAALPj4/HyQ0ND31q0ICFRv6FTAb/xE2+AkCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= binary2-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFRSVFxaXFxeXFRWVNze3Ly2tJyalHR2dISCfLSyrPTy9Pz+/Ozq7GxubJyanKSmpMTCxMzKzLy6vNTS1JSSlCwuLLy6tMzGxOTi3KSipKyurHx6fOTi5IyKjGxqbERGRDQyNMzOzOzu7GxmZIyKhHRydLS2tNTW1ERCROzm5MS6pIyOjDw+PPTu5PTq3LSqnOTazOzi1GRmZJSWlCQeHPTm1OzizLyqjISGhExOTGxqZDw6PNzSxOzaxGRiZExKTCQiHEQ+NLyulOzavOzWvLymhHRybLyypNTGtOTOpOzexLyidMTCtMS+rMSynLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfqgACCAAECAwQCiIiDjAIFj48GAgcBjIIICQoLDAwNDgwPA4MIBhAREgkTmw4UDBUWAxcYFAUZGggbHB0eDh8gIQkiHSMeFRoUDyQRIxkGJRYmFScTKCcHCCkgJyoNGSsWHCwKCCgIASAgLQoZLi8wISUbEyQUJAEDKQEKMS8yMBYeZmCgMcEcghog9tm4gSNEjgEPdEDYEQJEDR4aetzwgcPCjw8VfiAAwqNFECFDehApYiSEoCMQBVjQkQBJkpVKjFhgNGBGzSRLVhZRwsTloAFNmjhZ8WQIDiZQoOwcFMCCVQshrmYN4ScQACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= binary-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbPz69HRydMzOzDQyNIyKhERCRPT29GxubPTy7Pzy7PTu5Ozm3LyulPTq3Ozi1OzezLyqjPz27OzaxLymhPz29OTStLyifPTm1OzavOTOpLyedMS+rMS6pMSynAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaJQIAQECgajcNkQMBkDgKEQFK4LFgLhgMiOq0WDgVEQrFdKAXfhJWRODTMQ6+64BAMGHAq+pB4hCF2eURoVwgREhMUgl5/EBUWimdWB4cVDxcYiwJiGQcVfBobmhwPEgkWFg8dmWcQEgcWFw99HpoVFR8XGiAhISKLI8EkJRgYGyK/SgvLzM0LfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== colorscm-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIcAAPz+BFxaXNze3Ly2rJyanPz+/Ozq7GxqbJxaLLxOFLQ+HLQ6NMSOnOzi5GxubMzOzDQyNMx6JOSSXOSedNx+ZMxaXLQ6ZKRalNzW3IyKjERCRNSWPPTKnNReNMRGVLxalJRGpHRanNTS3PTy9OTi3ISGfLySNOzCfPTatOy2dNxuFMw6DJxGrHROvEROnHyKrMSmTOzanNzShOSqRNyCFMxCHJxGnFxavDxqxCRmrCxijPTq3Ozm3LyulLyyZOTenNTGZMS6VISKbCyCzASGxAR6rBxmhKyqpOzi1JyuXLTShJzKdHS+XES2XCy6pDSy3Bym3AySxAR2pBxadKyinPTm1OzezLyqjGSWTHS6ZFy+ZCyyVCS2dDy61Dyq1CSOtBRqjExqZKyilOzaxLymhDyeTCSuVByyZCS6hDS2vDSatCx2lCxabIR+dBSKTByeZCSmhCymnCyanCR6hNTCrOTOpLyedCxmVCR+bCR2bCRmZExqbMy+pOTStKSelKyejMSynLyqlLymfLyifAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAjqAAEIBBCgoEGDAxMGEMCQ4YAABAIkFLiwgMUCBg4UiJgQQQIFCxg0sOjgwUYIAiNImEChgoULGApkcHBAA8oNHDhI6ODhA4gQIkaQGFACgokTKFKoWGGBRQsXLwQIHQABRgwZM2jUsHEDRw4dA3bw6AHBxw8ZQIIIGUKESBEjR3YgIZtEyRImTZw8gRJFyhQqVaxcgYAli5YtXJx08fIFTBgxVsaQQVnGzBk0TtKoWcOmzZExklECcPMGThw5czqLoYOijh3RAO7gyaNnTxsxfOr0cQ2boBg/f44AChRI0KDXCiEoX84cgp+AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= core-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAASC/PzuBFxaVNza3Ly2tJyanPyuBPQCBPz+/Ozq7GxqbFRSVHx6dKSmpHRybMzOzDQyNGRiZHRydHx2fExKRCwqLPTy9ISGhERCRCwuLERGTIyOjBQSFGReXJSSlFRSTDQ2NAwKDNze3OTi3Ly2rFxaXAQCBFxeXMzKxOzm3LyqlDw6NCQiJFROTLy2pDw+PGRiXMS2pOzi1CwqJBwaHAwODAQGDJSOhOzWvLymhKSajNTGrJyWhOTOpLSyrKymlKSelMS+rLyidMTCtMS6tMS6pMSynLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfVgAAAAQAChoeHgoqCAgOOjgQCBQKCBoMABwMImwgJCggFC4sGDAQNDZoIDg+gEAcABhESEwoUFQsWFw4KGBmCGhsFGwoLEBwYCRYEFxCEHRceFwofIBwhDSIjJBCCCxISDiUaGRwmJygpKr4AGAIl4issISYtLuncgi8YLxAs5SYwYshQgQ8AixksaNSwYYLDDRc4chS0USMEQxMhHOjYEbEggBUWTQhwwANiD4mLBPj4AYTHjyA9cPQQsq7bkCFEihhRkSPHkSMeBUDIAGFo0aMZ/AQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= deb-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIUAAASC/FxaXNza3Nze3Ly2rJyanPz+/Ozu7GxqbPz6/JwCBMw+PMQCBLQCBNx6fPT29GxubMzOzIyKhDQyNLwqLLRWVLxaXNyurERCRMzKxOzq5Ozq7MQ2NMRmZLwCDOTi3Ly2tMReXOS2tMTCvPTu5Ozm3LyulMSSlNTOxPTq3Ozi1OSytPTm1OzezLyqjNyqpLxaVNzSxOzaxPTy9Ozm1OzexOzavLymhOzWvOTOpOTStLyidMyShMSulLyifLyedCH5BAEAAAAALAAAAAAQABAAAAa0QIAQECgajcNkQDAYCASEQCGQFC4NWMMBkZhWFQtGw/EwQCIGyWSoaFAqFgblIkEgMGthQ5HRbAQcFAcaBGp6DQEJCx0XFx4ZGx8geQ1ECyECByIMIyQlJnkMRBwnBwYODSgpKqB6RCIcK6gEKiwtLpQKiS8WMAQxKi0yuEOICTM0LSo0NTY2N3kAbhoHBzQ0zjg50EkKHC80LCo2ODo5O9FEBCE8Pe49Pj8/6QET9vf4E35BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= document2-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJSWjPz+/Ozq7GxqbJyanPT29HRydMzOzDQyNIyKjERCROTi3Pz69PTy7Pzy7PTu5Ozm3LyqlJyWlJSSjJSOhOzi1LyulPz27PTq3PTm1OzezLyqjIyKhJSKfOzaxPz29OzizLyidIyGdIyCdOTOpLymhOzavOTStMTCtMS+rMS6pMSynMSulLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaQQIAQECgajcNkQMBkDgKEQFK4LFgLhkMBIVUKroWEYlEgMLxbBKLQUBwc52HgAQ4LBo049atWQyIPA3pEdFcQEhMUFYNVagQWFxgZGoxfYRsTHB0eH5UJCJAYICEinUoPIxIcHCQkIiIllQYEGCEhJicoKYwPmiQeKisrKLFKLCwtLi8wHyUlMYwM0tPUDH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= document-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbPz69HRydMzOzDQyNIyKhERCRFQ6LJSKfNTOxJSOhPT29PTy7PTu5Ozm3LyulOzi1PTq3OzezLyqjOzavPz29Pzy7OzWvLymhOTOpOzaxOTStLyedMS+rMTCtMS6pMSynAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaLQIAQECgajcNkQMBkDgKEQFK4LFgLhgMiOq0WCAREQrFdKAVXKyNxaJgBjgck4khLBAPGm4r+ghETeHtEfVaAFBUWg15gjReKZ4YTFBgYGRpvcQoPDggRnwwMG5hnHB2UFxcbHh+LAh0YDA+zDyCtZ5UXIRsiIiAjiyQlJCYnGhofI8BKC83Ozwt+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 dvi-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAASC/FxaXNze3Ly2pJyanKyijPz+/Ozq7GxubIx+RIRyLHRyVGxqbMzOzDQyNHxyTHRqNGxiJHRiLJySVIyKhERCRGQmLMy6ZNS+TMSuPLSePIRaNGReLHRuTPT29FxOFKymdIRmLHRiHGxKLDQuDPTy7Ly2tHQqLLwyPIxqVGw6LIx2LGRSHDwyDDwyFNTOxOzm3LyqlIQuNLy+zKSGdKSSfJRSRKSSNExKJLSmnOzi1LyulIyCZIxiPJyGLExGFOTSvOzezLyqjLyyXAQCBNzGRLyeREw+DFRONNzSvOzaxGxqVKSelJSCNEQ6DFRKFKSajMS2pNzOtOTStLyidEQ+FLSunOTOpIyKdMSulLymhLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfVgACCAAGFhoaDiQECjIwDAQQBiYIBBQUGmAcIBpGTCQqgC5gMDZwOgw8KEBESEwkGFAgMFacAFhcYGRobEBwdHgIDFKcWHwYgBiEhIiMkAyUCJg4nKCgp1SorLC0uBC8wMQ4yMzQnNTM2Nx84LTkNOjunNjY88z0+Hz8kOUBBQqdDiHQoYiREhBZHkORIouSfIAghjCiI8IHEEiYDgAApUAtAEwgfnDzBASWKFCBTqHQE8ONIFRwErFxRcuWKSkU8sBTIkSWLFi1btqwM4KCo0aMO/AQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= font_bitmap-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAASC/FRWVFxaXNze3Ly2tJyanPz+/Ozq7GxubGxqbNTS1DQyNPS+vPw2NNQeHFw6PPTy9IyKjERCRPzi5PyGhHRWVOTi5PT29OTi3IyKhPza3LySlLQGBGQCBNza3Pz69PTy7MS6pKRubPy6vGQ2NKRSVIxmZPTq3LyqjLQqLHRydPxydHwCBNTSzPTu5Ozi1MSynKQCBOQ+PKwCBIReXJwCBExOTMzGtOzezOzWvEQeHLSytOR+fIxaTOzexLymhEwCBDweHNTOzPTm1LRORIQ6PJyOfOTOpOTe1OTSvLyedMTCtMS+rLyulLyifAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAe6gACCAAEChYeGg4oCA42NBAEFAYqCAQMGmAYHCAaSlJaZmAkKnQuKAQwNDg8QBhEJCRKmgwITFA4VFgYXGAQZs5UaGxwdHgYfIAMhwAAiIyQlHCYgECcnKMwpKSoKKywtLicvMMwcHDEyMjM0L+3YgzUsNgH0HCw3ODnvgjU6OwMvBvCQ0cNHjh+zOgAJIqTaECJFOhg5gvAUEmsvksBAAeOIEmYBbixhEgJGExROlHw8taCly5cL/AQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= font_truetype-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFRSTFxaXFxeXNze3Ly6vJyanPz+/Ozq7GxubHx6fCwuLDQyNIyKjKSmpPTy9PT29HRydMzOzCQmJAQCBKyqrFRSVLy+vGRiZNTS1GxqbERCRMzKzJyenOTm5JSWlLy2rIyKhMzK9KSm1Kyq3OTi3OTi5JyezBQSJExOTLy6/CwuXLy+5LyulMTC3LSytHx+7Ly2pLSyxLyqlNza3Gxq1OTWxMS6pLyqjPzy7OzexPTq3LyynOzWvLymhPTy7DQ2bOTOpGRmhERCfNzGpLyedMTCtMy+rAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfIgACCAAECA4WHhoOLAgSOjgUBBgGLggEEB5kHCAkHBgKCCgsKBgwNDg8HEBESngwAExQVBhYXGBmZDREaGwuDHB0CHh+4qgQgIa+CBMEiIyQiJNAlIMoAJgYDJygpKisWLAMtvoIe2S4pLzArMTIBM9YHBRUeNAQ1KwU2NzjWFAwDDEDIgS+GDh39Fl3ykGMHPh46evggJ2gAgR87HAKZYSOID2uECGQUMkRIAiJBioAUYMTIkRs8cODwUUSlQgY4GSzQuVOnn0AAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== font_type1-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAASC/FxaXNze3Ly2rJyanExKRPz+/Ozq7GRmZPz6/HRydMzOzDQyNJRmZPSmpIQuLGwWFKxeXPTy7IyKhNxSVGxCRLy6vPQ+PPT29GQ2LPTCxOROTPz69KQ2NPSGhPTq3Ozm5LyqlGwODPxiZOzi1LyulLwKDORydBQSDOx+fNw+PNS2tOzi3PTm1OzezLyqjNQaHPRubJx+fMS6rOzizOzaxMwuLKQWFHRaXOQuLJSShNzOvOzavOzWvLymfCwiHHx6dOzexOTOpOTStLyedMTCtMS+rMS6pMSulLymhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfFgACCAAGFhoaDiQECjIwDAQQBiYIFAgaXBgcIBgQFk4uYBgkKC5wMiQ0ODxAOERITCggFp4MUFRYCFxUCGAIDE7QAFBkWCRobChIcEr60HR0IHAYeHQQYEh8gIbQbIgjGIw8WEtgkJacmJyjfKSoFKywfLS4vpzAxEAgnHSYyJjMkaNSoB0CEChs3cMjIYULHDho8evig9aPiAQFAHAap0UPIREXYPpAIEnGIECLBABQoYmTGESRIfCQhglIRg5s4czLwEwgAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== gf-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIMAAPz+BFxaXDQyNAQCBMTCxPz+/ISChKSipERCBMTC/Pz+xPzerMQCBAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARwEEgQahVijMmD/oRAbBw1FCgaFFrppeo5UtILWxlAGNWZHocA4bAxGAnDg9GA8LQCxGTQoHwVNYYEMEHtKYrEA0tctVIOo0Fl2Ct8AQLlKMnzLFg1KIHBCGoUbiR5VSd3C28TThpubgqIEhkfkh9+EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 html-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFRaVNze3Ly2tJyanPz+/Ozq7GxqbDxinBw+ZERmdIySjMzOzPT29DQyNDRurIR2RPTSdJyulFSGxLzCxIyKjHRydERCRLzKvPzivPTmxNTChLSybGyCfCRSpBQqRLy6vPTy7OTi3IyKhCRShOTixPzy5OzerOTShLyaVEx6nCxerGRyhOzi1LSyrEyGvOzaxPTShNy6bEx6rDxyzDRitCRCfPTq3LyulBw2VISq3GySrPTWlHyanIyitEyO1ER6zBxCfLSqnCQ6XHSq3GyWvFyGvDxuvLSqpPTm1OzezLyqjCxajFyO1GSi3NS2bKyaTCQuPGRufOzexLSmlER2vKyWNFxaNHx6dLyunOzWvLymfERSVExKNDRCNKyilMy+pOTOpLyifFxaVLyidMSynMSulLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfYgACCAAGFhoaDiQECjIwDAQQBiYKLBZYFBgcFkZMICQoLlwcMDQQOgg8QERITnhQFFRYHF6cPGBkaGxwdHh8gISIDI6ckJSYnKCkqKwksAiEtLg4kLzAhMTIzNDU2HxQ3NzgOOTo7PD0+P0A1QR8uNy1CDkMvREUyRjNHHjkfSElKlpxi0sTJjydQAiSIIkXIFBhUTn14UIWGFQhXHHzAkgWGli2nAHxIwIRLFy8bv4DREkZMSEEfYo4hQAVMGJZkXhIaIERImTJmlogRc0ZnAAdIkyp14CcQACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= image-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPz+BFxaXNze3Nza3Nza1LS2tJyanPz+/PTu5GRqZOTi3HRydMzOzDQyNJQOFDxKfKTW5OTy/OT23MTaxISKhGxmZERCRCwuLJQSFPzGpLweHJTO3ESu3DRilNz61FymXCxKRMTCxPTy7Ly2rIyKhDwCBORiRKQWFEy23CyKvJTWhDSOPCRONDQaHNROPNQ2JLRubHTC5DR6rHR+jFSqRCRyLGxqbOzm3LyulCwqLMySjMQ2JMyqrERijJSenFSGXGRmXMS6tPTq3Ozi1MS+vMxCNKyqrHR2dPTm1OzezOSKfNTe5KSmpIyGjLy2pOzWvLyqjIRqZIyKjHR2fExKTHx2bLyynOzexLymhERGRGRmZKSWhMS6pOTOpLyedMTCtMS6rMSulLymfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfcgACCAAGFhoaDiQECAwICBAUBBgGJggEEB5kHCAkHk5UBCpqZCwyeDYIOAA8QERITmRQLFRYXABgZGhscHR4fICEiAiMkDSUmJicoKQ8qKywLAwgKIxctLi8wMTIzNDUJNiEINzgNOTo7PBA9Pj/QQEFCQzg5F0RFEQQ+RhRHswVIkpS7oEMJgiUhCjBpcqSCkyFPoNjKEYVJCCNSpgSgUsXKlSdYUAG4kCOLlgpAgFTZwuVJFyy2Bi0gEsSJzZYuvYi09OULGC44wmAR48VLDkU5zClt0OACUz+BAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 info-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxaXNze3Ly2rJyanDROXHSSpISetPz+/Nzm7GxqbGyGnMTS3MzW3JyuvERujLzG1HRydMzOzPT29DQyNMze5Iy2zLTS3Cx+pCRijLS+zIyKhGxubERCRFR6lGSivFyavISuxAxajBRejAxGdDxihJyyvCR6pBRqnAxelAxOfPTu5OTi3IyqvFSOtJy+1IyyzFxyhOzm3LyqlGySrAxejAQ6ZFxqfMzKxPTq3Ozi1LyulCxulAQuVISKjMzGvPTm1OzezLyqjBwmLBROdExOTKSinNTOvOzexBQeLAw2XAQmTCwyPLy2pOzaxOTWxLyedCQmJAQKFAQWJKSalOzavOzWvOTOpLymhKyqpMS+rOTStMSulLymfLyidAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfVgACCAAGFhoaDiQECjIwDAQQBiYIFBgcImAkKCJGJCwwNDg8QmBESEwQUgg4VFhcYGBkaCBsRHB2qHgwfIAghIiMkAhMCAxsUJSYhJygiKc4qCysrLAPILS4oLwgwKcExEisyMxQFNBg1Nb7ONjc4OTo7yAU8IiIIDiIqPT4/QEFCVA0hooJBAg0eehQxciQIEnKCktiYqGQJEwJNnCB5AkWVoChSpkwpQmXAkypWrmDxKAhSlixaTlrZcqWjIi0/BmjhsgNLFy82BwWgQDQK0aNE/QQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= kmultiple-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBFxaXPz+/AQCBISChPz+xMTCxPzerKSipAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARWEIRJgb04iLEJwaAmjMTwgVbAjeaESmNcGMGrxmOhDqE8HAOVJ7MSFH4qhOmiOQIPNIGB4JJwnIaDaFaTUL4iYxc0MJidQVvROc4Yfz+a+g3V2sAVfwQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== log-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxaXNze3Ly2rJyanPz+/OTm5GxqbMTCxARiTARSPARCNAQ6LAQyJGx+fGxubMzOzDQyNCxGPARyVARqTARaRLSyBCRGHFRuZIyKhERCRDRuXAx+ZPz+BIyOBFRybOTi3AyGbAx2XExaDBROLOzm3PTy7DRORDyeXBx2VEymVHyuJGRyDPTu5LyqlFyGTBxaNAxqVDR6PARKNPTq3Ozi1LyulCRuTCxeNBSCZDxmJEx6bOzWvPTm1OzezLyqjCSSdCSmhBySdBR+ZARqVEx+bNzSxOzizESCdAQCBNzOvOzexLymhOTStOTOpMS6pLyedMS+rAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfIgACCAAGFhoaDiQECjIwDAQQBiYKLBZYFBgcFkYIICQkKCgsLDA0ODxCbEQASExQJFRYXpBgZDwcaqxscrgkdHqMfBiADGasIIRwiHSMdJB0YJSYCA6snKCkqFgorHSwdIC0lLqsvvx0wMTIWMxgCNDU2xzcdOBw5EzoKOzw9Pj/WgAQRIiTEkAlEihg5wgMgACRBkpwQIpGDRCVLeDCJACGJx48gAzRxspHQoZNPRkJZNSjAkygDntiwwYQJlJWKIujcyTOCn0AAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== make-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxWVFxaVOTi3Nza3LS2tJyalGRmZMTCxPTy9Pz69Pz+/Ozq7GxubJyWnFRWVHx6fHRydMzKzDQyNHx2bHx+dIyKjERCRGRiZKyilLSifMTCtLy+tISGhOS2bPzerPzuvOzetJSSjFxaXOzu7PTy7MS6pGxqbKSWdPS+dMSidOTerPzqtISCfKyurOzq5LSqnMzKxPS6ZEw6HJSKbOTStHR2dMzGvPTq3OzizLyulFRSTOyyVNymXOy+dKyqpPTm1OzezLyqjJyCTOSqTOSmRLSupNzSxOzaxOzexOzWvOTOpKyinMS6rNTGrLyedMSynAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfagACCAAEChoeGg4oCAwQEjQUCBgGKggcICQoKCwwNCg4CiwQPCBAFmRESCwYTghQCEgYHDBUSChYNDRetGAQZGhscHAIFDAoDHB2tAQYeHyAhIiMIJAolBCYTAicoKSorLBItGC4DLy8wExExKjIzNB81CBI2Nzg5Oq07KDw9Ph4mdgj4IQFIECGtHrgYQqRIjQoPjBzJkQMJQgANkrngYGFAhB8UkyjR0EpQAAkUKkQQkCGHEiVLLg6y8IDJhiZOXsJ8UtLkhpsmoAgRouIJT0UPJihdynSCn0AAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== man-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxaXFRWVNze3OTi3Ly2tJyanNza1Pz+/Ozq7GxubMzOzDQyNOzq5KSmpNTS1IyKjGxqbERCRPTy7PT29LSytOTi5MTCvMTCxLy6vMS6rISChLy+vPz69HR2dLSyrLy2rNTW1IyOjOzu7OTm5HRybHx2ZNTOxLyulLS2tIyKhHRuVMS+tHx6fGRmZLyqjISGhJyenMTCtGxqZGxmVMS2pFxeZGxiTMSynLymhHx6dGRiZFxeXFRSVLyifGxmTKSSfLyidMS+rLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfDgACCAAEChYeGg4oBAwMEjQUCBgGKggEHCJkICQoIBgKKkgSamQoLngyWDQ4PpAgQChESqQACExQVFgkXGA8ZBBobtAENDQsGHB0dEx4fBCC0AhYhGCIjFA0kJSYnKMMPHCkqFg0DIQorLN6WCx8OLQsHIQsuKxovtIQwMR4ZHDIYZtCogU+RjQAeUmDAkELBDRw58hHSsWMDjx4XV6DwIZGYCRc/aNz4AeRFkI4sZAipgePFCx9BhkgUwKCmzZsM/AQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= metafont-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxaXNze3Ly2rJSWlPz+/Ozq7GxqbKSajPT29GxubNTS1DQyNIyKjERCROzi5Ly+vKyqrKSipKSmpKyurISChKyinHRybISGhGRiXJyanIyOjFxeXJyenJSSjMzGxMzOzMTGxLS2tISGjExOTLyulMTCxISWpGx6jExifFxufJyepJymrFRSVLSupLyqjERKROza1OTKzNS6vGRmZLy6vPz29Hx6dMTCvHRydJSKfOTStLymhNTCxLSOjKx6fMS6pLyifLSytHx+fOzWvOTOpLyedMSulLyidAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfDgACCAAGFhoaDiQECjIwDAQQBiYKLBZYFBgcFCJKKApcFCQoLBQQMnqAFDQoHDqeDAQ8QERITBhQVFhWnF4IVsxgKGRobHB0DrxUeHyAhIiMeGCQVFCWvACYCJygWKSoTFxcD1oMJGissJiwjFC0ZLi+nMBoLMTIPFDMzDS00FvEAYlyQUMNGiBs4OuQgoWMHj2sDe/j44aNCBh1AdgS5BoCGBhNChlxAQGRHESMcYXCI5sHCkRdIkKBUxKCmzZsM/AQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= midi-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Nza3Ly2tJyanPz69Pz+/ISChOzm3GxqbKSipAQCBHRydMzOzDQyNIyKhERCRPT29OTi3PTu5PTy7LyqjOzi1OzezOzWvLyidOzaxOTOpMS6pMSynLymhLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaOQIAQECgajcOjUTAYEAKFgDBgOFQNiMHhkFAYosQFg2HNbg0Nx/dB3W7NW0hDEWEjxm+BWzIhINhVbnBUFH12eAeDFRQUFoBuiVoGRRQXjgGQiQQLCwELBZaHZJGMARgLGZeZCARRUKgaom8DCAEZGwscqm5YrZyfHLFKRQQdHhYWHxogD0NED9DR0g9+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 mime_empty-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbPz69HRydMzOzDQyNIyKhERCRPT29PTy7Pzy7PTu5Ozm3LyulPTq3Ozi1PTm1OzezLyqjOzexOzavPz29OzWvLymhOzizOTOpOTStLyedMS+rMTCtMSynLymfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaBQIAQECgajcNkQMBkDgKEQFK4LFgLhgMiOq1eEQnFdqEUXK2MxKFBHnqvDsGA0aaaz4iHvE68WxEQERITfG+ADxQVhGV/DxEWFBcYhQIIgBEUFBkak2UbgYkZHBwdlIgUHh4aHB+lZZkVF6sgHyGFIiMiAyQYGCUhtkoLw8TFC35BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= misc_doc-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFRSVFxaXFxeXFRWVOTi3NzW1Nze3Ly2rJyanPz+/Ozq7GxqbMzOzDQyNHRydExKRERGRExKTERCRCQiJIyKjCwuLGxubDw+PDw6PDQ2NBweHAQCBPT29IyKhNz+3HzmfDTCNASaBBxaHCQmJPz69PTu5JTqlGTOZCSmJAR+BBxSHOzm3LyqlFTKVASCBARmBBxGHNTSzPTq3Ozi1MSynAyeDAROBCQ+JBQSFNTOxPTm1OzezLyqjCwuNAQyBCQ2JMzGtOzexAwODOzaxOzWvLymhMzCrOTOpNTKvMS+rLyifMTCtLyulLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfcgACCAAECAwQCiIiDjAMFBgeRCAMJAYyCAQUKmwoLDAoJA5eZnJsMDaAOAA8BEBESExETFAsVDwwTFgAXAhgOGBkaGhscHQUIHqoDAR8gISIjJBQGJSbHugMSJygpKisU0x0mLC2qAhEuKS8wMRsbMiYzNDW6ARM26zc4ORQ6Mzs8evgAACGDChg3fgDhF6SAECE9VEXQYKGiDwtDKAQRQqSIEV25KGzIQZIDhSNFiiAxomoQAwM6kgRRgiQlkiW6BgVIwkQJghpNeixx4qQlJiAWHCh1kFSpBT+BAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 netscape_doc-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxaXNTW1Nze3Ly2rJyanPz+/Ozq7GxubPz6/OTi1Ozq3GxiTMzOzCwuLMSijGROLLSqjGRiZOze1LSOdIyKjEw+NHxGJNSqjMTGxPTy7Ozm1NzWxLSSfFw+LMzKvHRuVKyeZHxybOTazOTi3Ly2tDQyNOzm3MS6jFxaRPTu5LyulOzi1KSehMTCxKSOdHxuRMzCpJSGXOTStLyqlHRqRIR2TFRKLLyedLyqdGxWLIR6XOzezJyCZJySbEQqHKyKdFRONJSKfOzaxNTCpKSWbJSSjExKNHxuNOzWvLymhIyKhOTOpHRydHx6bIR+dOTOrLyidAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfVgACCAAGFhoaDiQECA40CBAEFAYmCAQMGmAYHCAmSlAEKCwyZCA2dDoIPEIsREgkTFBUICBaoABcYGRobHAodHhkDBBW2AB8fIBwMESEiIxokJSaDJxAUKAwQESkaKicrqBssLS4vBzAfMTIRMwo00zU2LTc4OToQOzU3DDwr04Ixeljw8QNIiCBCYgyJUIxIESMfjuxAwoDDkCRK/j244CNHjhBIPDxYMoPJA1sXIDRxkuOIkycXHsyAEqUYoRk7GDAh8uJFDhw4/lUy4aCo0aJE/QQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= news-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/AQCBERCBPz+/FxaXIQCBMQCBMTCxISChKSipDQyNAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARXEEgZwrxYikFsvtUwBN0nEWIhkh4YiIOhjiX1hqIsHlb4jr8VwoJa/XCCBG4ZZA2bRxEi0QkgeLAloUZKYGEDhLgG6H5JBEFrYg4ItmsMCaGomFyEiz8CACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= pdf-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAASC/FxaXNze3Nza3LyypJSSlPz+/Pz69Pzq5Ozq7GxqbJyanNyGhNx6dGxubMzOzDQyNERCRPz6/My+vLxaVJxeXKSmpNTGxIyKjNTS1OTi5OzCxLRSVMTCxKyWjOTi3Ly2tIyKhLxmZLSWlOTe3MzKzOza3MyytNyOjAQCBKyqrOzm3LyulPSajMRWXOSGhOyGhKxiXOzi1OxyXKRORIxSTNTKzMy6vLyenLRubLwqLMxiZNSurJRybOzezLyqjJxCRGxSTLy6vGQiJMw+LJR+dMzCrOzaxIyOjKyurHxydNxWPNTCrOTStLymhIR2dKyKhIxuZIR+dJyShOTOpHRmZKSKhJyCdKyilMSulNTCpLyedMS+rMS6pLyidAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfQgACCAAGFhoaDiQECAwKMBAEFAYmCAQMGBwgHCQoGC5OKAgYMDZcODwYFEIkREhMUFRYXGA4OEauCGRkaGxwZHR4ZHyAhuAAdCQgiFR8aHSMkHwS4JRomIicoJykqHh0rLKstLhQcFC8wMR0FHgQy4TM0HDU2Nzg5Ojs8PQQ+P6tAggjRVaLEjiFEihg58k+QBSQdQCTpoITIkhBMmjgxVsBCxydQokiZYoTKxkRVrFy5EgJLFi1NqGwxRohLBy5dsmT54cXLTEUQggodCsFPIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 pk-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/IQChFxaXDQyNAQCBPzC/MTCxMQCxPz+/ISChKSipERCBMTC/Pz+xPzerMQCBCH5BAEAAAAALAAAAAAQABAAAAR6EIAQhLVjECJlKISwjcZgcFNxhATiugKyTaP4wu0JiOyNXBqAIWFpvRQKgUHBSTgNS4UzseBxBMxoMiG1NTcJBpLBLTaaTIVM3fXuFKeQMmk7AwbSU5QocsgkFnAPD0kbFBQdO1hELQ4fK4lWLQ0IASsoEhojIwEjfhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== postscript-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxWVFRWVFxaXOTi3Nze3LS2tKSajPT29Pz+/Ozq7GxqbJyanISChPz6/HRydNTS1CwqLMTCxISGhOzu7ERCRDQyNERGRLy2rIyKhExOTAQCBKyqrOTm5KSmpHR2dNza3AQGBNzSxOzm3LyulBweHBQSFKSilOzaxAwKDOzezDw6PJSSlDw+PKSelNzOvLymhAwODNzGrOTStLyqjExKRHRqZLymfMTCvMS+tMS6rLyynMS6pOTOpLyifMTCtMS+rMS2pMSynLyidLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfPgACCAAECA4aIA4OLAgSOBQQGAgcBi4KNCAmaCgsJDAKWjQkNCA4JDxCeEYwSDQ4TFKMPCxUWAA0BEQ0GDggQDxcIBBgZthobExwICB0eFRsSHcOrER8QCwYIIA8bIRwiIyS2JSYVHgsQzhsbJygEJKsl6ykeH9zrJyIq4gAp6xsrWLT45+IFChi2YqwLwcLEvxgHZMygsarBOgsCBGioUcNGxBk3bA0SgCOHjh0oeczo4WPVoAA/fgAJIoQGjSFEiIgUNCCCBZ8Wggq14CcQACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= readme-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxaXNze3Ly2rJyanDROXHSSpISetPz+/Nzm7GxqbGyGnMTS3MzW3JyuvERujLzG1HRydMzOzPT29DQyNMze5Iy2zLTS3Cx+pCRijLS+zIyKhGxubERCRFR6lGSivFyavISuxAxajBRejAxGdDxihJyyvCR6pBRqnAxelAxOfPTu5OTi3IyqvFSOtJy+1IyyzFxyhOzm3LyqlGySrAxejAQ6ZFxqfMzKxPTq3Ozi1LyulCxulAQuVISKjMzGvPTm1OzezLyqjBwmLBROdExOTKSinNTOvOzexBQeLAw2XAQmTCwyPLy2pOzaxOTWxLyedCQmJAQKFAQWJKSalOzavOzWvOTOpLymhKyqpMS+rOTStMSulLymfLyidAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfVgACCAAGFhoaDiQECjIwDAQQBiYIFBgcImAkKCJGJCwwNDg8QmBESEwQUgg4VFhcYGBkaCBsRHB2qHgwfIAghIiMkAhMCAxsUJSYhJygiKc4qCysrLAPILS4oLwgwKcExEisyMxQFNBg1Nb7ONjc4OTo7yAU8IiIIDiIqPT4/QEFCVA0hooJBAg0eehQxciQIEnKCktiYqGQJEwJNnCB5AkWVoChSpkwpQmXAkypWrmDxKAhSlixaTlrZcqWjIi0/BmjhsgNLFy82BwWgQDQK0aNE/QQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= recycled-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxaXNze3Ly2rJyanGRmZKyqrMTGxPz+/Ozq7KSinOTi3LzatLTGpJSSlMzKzGxubMzWzPT29DQyNMS+rOTy5KzWlEymLDSSDKTClIyKjGxqbERCRGx+bNzu1Hy+ZESeHDSWDCyKDCyGFMTKxHx6fOTi5ISCfFRuVKzGnJzKjDSOFJy2lNTSzJSSjPTy7Ozm3FR6RJzChGSqRFSePHyqdMzOzLSytNTOvLyulExyREyWPESSJMS+vKyurMzKxPTq3Ozi1BxeDDSCHNTS1Ly+vHx+dIyOfPTm1OzezLyqjBw6FBxmDFSKRMzGxERONOzavBQ6DBROBHSOdCxeLDRCJKSelOzexOzWvLymfCw6LBxGHFRiTOTOpERGRKyqpMy+rLyedMTCtLy2pMSynMSulAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfWgACCAAGFhoaDiQECjIwDAQQBiYIFBgcImAkFCJGJCgsMDQ4PmBAREgQTghQVFhcYGZYIGhAbHKodHh8gISIjJCUCEiYDJxMoKSogGCsjLC0GLgkvMAMTMTIzIjQ1LDYHNxo4CTA5Ezo7PDstEQ8HPT4nP0BB5jpCQxFE7kU3RkcHkCRRomoJkyYHnBQZ0OEJARxJoBAUFEWKjilUolSxMiDJFSxZVAnSEmVLFC4EBnzE0iVkIi8EvnwBs5JlGJGCAogRQ2EMmTJZsoS5qWiC0aNIJ/gJBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 resource-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFRSVFxaXFxeXFRWVOTi3NzW1Nze3Ly2rJyanPz+/Ozq7GxqbMzOzDQyNHRydExKRERGRExKTERCRCQiJIyKjCwuLGxubDw+PDw6PDQ2NBweHAQCBPT29IyKhNz+3HzmfDTCNASaBBxaHCQmJPz69PTu5JTqlGTOZCSmJAR+BBxSHOzm3LyqlFTKVASCBARmBBxGHNTSzPTq3Ozi1MSynAyeDAROBCQ+JBQSFNTOxPTm1OzezLyqjCwuNAQyBCQ2JMzGtOzexAwODOzaxOzWvLymhMzCrOTOpNTKvMS+rLyifMTCtLyulLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfcgACCAAECAwQCiIiDjAMFBgeRCAMJAYyCAQUKmwoLDAoJA5eZnJsMDaAOAA8BEBESExETFAsVDwwTFgAXAhgOGBkaGhscHQUIHqoDAR8gISIjJBQGJSbHugMSJygpKisU0x0mLC2qAhEuKS8wMRsbMiYzNDW6ARM26zc4ORQ6Mzs8evgAACGDChg3fgDhF6SAECE9VEXQYKGiDwtDKAQRQqSIEV25KGzIQZIDhSNFiiAxomoQAwM6kgRRgiQlkiW6BgVIwkQJghpNeixx4qQlJiAWHCh1kFSpBT+BAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 rpm-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIUAAASC/FRaVNze3Ly2tJyanFRSVOTi3PT29Pz+/Ozq7GxqbFxaXHRydNzazDQyNIyKjERCRGRmZExOTLyipOSytLy6vIyCfBweHMzOzNS+vMRqZMRSTNzGxAQCBLxCPMzGvLyulCQmJPz69IxKRIwWFLSGfLyynAwODERGRMTGxGRiXLyqjHR6dIyOjBQWFLSqnNTCpNTKtLyidPTm1OzezOzavOzWvOTOpMTCtMy+rMSynLymfLyedAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAazQIAQECgajcNkQMBkDgKEQFJYMBwQ2ITiEJ0uDFjsgdHgOpIFQRj7UCggZyEksIgoJBPKwVCxnBUXEgwYBgkGGRobHAYDDgUdFx1fawceHh8gDiEdnEthIgcjJCUmDh0nKJwdCCmcKh0WJiumQh0sFR0tFyYuLycwK5u1nBYsFwMuJicTs0MdEhUpDRkxMRkwMDJxQl8zBjM0NTY3N9poKTg5JjorKzsyPNtEDvT19CH0fkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== shellscript2-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxaXNze3LyypJyanPz+/Ozq7GxqbPT29HRydMzOzPz69DQyNHRaJKyONJR2LJyCJKyCHKSCHMSqZNTOvIyKjGxubERCRGxSFIxyRKR+HMyeHOTCLMSOHLyWFMzGtIyKhHx2bKSGZNyiFHxeDOTi3Ly2rMyudOTCpOTKxLyqjJR2VJxuDLSGHLSunPTu5Ozm3LyulJx6NNSyXOTCjOzWvPzi3MyqhGxSLFQ2DLSKLNSqTPTWtPzq7NS2nIxyVIx6ZOzezFxCFOy2POSyROTGlPTazPTWxLSiZLSSVMy+rOzaxKyCJMyeNOSyTNy+dLymXLyePNyqPKSWfOTStLymfKR6HMyaPMyaNJR6TMy6pFxKLHxWFKR2FIxiDOTOpLyedMTCtIyCbMSulAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfQgACCAAGFhoaDiQECjIwDAQQBiYKLBZYFBgcFkZOVlwgJCgsEDIINDg8QERITFAUVFgcXpYIYGRobHB0eHwgCAyC0giEiIg8bIyQCCCUmtCInKCkpKissLS4vMDGlMjM0NQsINjc4OQ0U26U6OzQ8CAg9Pj8uQBRBKgxCQ0QzRUY2jiDRkURJkCX5ADBp4uQJjRNQokhpMSUIlSqlcFjpQOQKESlYWmTRQuUirS1cumy04qWBlhpUvoARRihMGDFaBoxRUQXMTEUMggodysBPIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 shellscript-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFRWVFxaXNza3OTi3Nze3Ly2tJyanPz+/Ozq7GxubNzSxMzOzMTGxHRybDQyNLy+vHRydHx6fKSipISChIyKjGxqbERCRCwuLLy6vGRiZExKTCQiJAwKDLSytLy2rJSSlHx+fDw6PKyqrBQWFPTu5Ozm3LyulLS2tCQmJAQCBPTq3Ozi1MSynCwqLAQGBOTazOzizOzezLyqjBweHNzSvOzaxKyurHRuZNzOtLymhDw+PIyCdOzWvOTOpLyidNzKtOTStLyifMTCtMS+rLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfZgACCAAEChYeGg4oCAwQFjgYBBwGKggEECJkICQoIkwADCwwNDY2mDA4Lng8QDhESsLARExQVDhYXGBkWExIaGw8cHR4SCQQfFQ8eFgUgIQEiwiMSBMYfGB4atwEXDyQd0wQlJicPKAHoFyIpJCoeDgMrLC0YKBsX6i4kL+4OMDEyZijr5oLGNxUqUCioEcPGDAwjPNyI6MEDChQjcOSwsUDHgw07RIgI4KCkAgs8cvTw8eOBogAxQtXIASTISiEuBwUYMoRIixYnZggpUgTDywdIkWJIitRPIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 sound-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxaXFRWVExSVNze3Ozi1Ly2rJSWlPz+/Gx6dNTS1Ozq7GxubGxqbDRmbDQyNFRiXBy6xFRmZLy6vIyKjERCRAQ+RBy2xByqtHRydIyOjPT29PTy9OTi3ISGhAQ2PATC1ByGlPz6/MS2pAS2xHS2vMTCxJyenLS2tPTq3Ozm3LSmnAQaHARibARudAR2hEySnOTm5MzGvLyulARKTARWXDyCjOzaxAQiJEx+hNza3MzCtOzexOzavLymhBQuNCxqdLy+vKSelOzWvLymfDxOVISipAQCBNzOtOTOpFRybKSejMS6pOTStLyedMS+rAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfLgACCAAEChYeGg4oDBAUEjwYBBwGKggEICQkKCAsMCJOVAw0OA4wIDZsHD4oQERINDRMIFA0MFauCFhcYARkJGhscHRMeuB8RICEQHgcaBCIcBSOrHyTWJSYnKB4KHCkqK6ssLS4vMA0LMRoyKe0zuDQ1LTYoHBwU7Ck374M4NTkmdHDIsKMAjx4+cAn6ASSIAhRCdvDgMYSIQkJFjBzJsALJjSFJLCoSUKCIkiVMegxpksTJxQATnjwZMWMGER9OXI58wLOnzwd+AgEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== source_c-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbIyKjMTCtPT29GxubMzOzPz69DQyNHRydERCROTi3IyKhIyOjPzy7PTu5Ozm3LyqjPz29PTq3Ozi1LyqlPTm1OzizOzWvLymhGxudGRmdFxedFRWdERKdDQ+dHR2dFxidAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaHQIAQECgajcNkQMBkDgKEQFK4LFgLhkMhOl0iElbFgtEgOJQC8BXxOEDOw0DkGhYMJHCq4FuYJBQUEQN5RGlWYBQVFheEVWEYFRkaG40RXw2JGX6MaIiRHGCccQKAkRodHh4fjQ+tICEiIyQkJY0mJg8FJwWzJbVKD7gnI7K+v3EOycrLDn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= source_cpp-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbIyKjMTCtPT29GxubMzOzPz69DQyNHR2bERCROTi3IyKhIyOjPTy7Pz29PTq3Ozm3LyqlPTu5Ozi1LyulPzy7LyqjPTm1OzizOzWvLymhHRydHR2ZHR2XHRyTHRyRHRyPHR2dAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaHQIAQECgajcNkQMBkDgKEQFK4LFgLhkMhOl0iElbFgtEgOJQC8BXxOEDOw0DkGhYMJHCq4FuYJBQUEQN5RGlWYBUWFxiEVWEVGRYaG40RXw0ckV8djYaZFh5gnGgKnx4fICAhjSIPrSMkJCUmJ6woBQ8FJAUlJ7VKDygPD7G9vo0OycrLDn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= source_f-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbIyKjMTCtPT29GxubMzOzPz69DQyNGR2ZERCROTi3IyKhIyOjPTy7PTm1LyqlPzy7PTq3LyulLyqjPTu5OzexOzWvLymhHRydHR2bFx2XFx2VFR2TEx2RHR2dFR2VAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaHQIAQECgajcNkQMBkDgKEQFK4LFgLhkMhOl0iElbFgtEgOJQC8BXxOEDOw0DkGo4MJHCq4FuYJBQUdnlEaVZgCgYVFoNVYRcYGBEZjBFfDRePEgkajIUXGxgVYJxoCp+hHBwdHowfIK4PDyEiIyStJSUFDwUmJiS2Sq8PILG+v4wOycrLDn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= source-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbIyKjMS+rPT29GxubMzOzPz69DQyNMTCtHRydERCROTi3IyKhIyOjPzy7PTu5Ozm3LyqjPz29PTq3Ozi1MSynPz27PTm1OzizOzaxOzWvLymhLyifOzexLyedLymfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaJQIAQECgajcNkQMBkDgKEQFK4LFgLhkMhOl0iElbFgtEgOJSCx7WAgBwi52FAsi4oBINJnCpAqCkPChUSA3tEEmoFahUWFxiGSwphGRYaGxyQEn4NHZVfj2iLlR5qoHICGYyWHyAhIpB9Dxp+IYAjsGokaiFqJZAJDwkDHBwYJiW+Sg7LzM0OfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== source_h-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxubPT29IyKjMTCtMzOzDQyNHRydERCROTi3IyChIyOjPzy7Pz27PTu5Ozm3LyulPz29PTq3Ozi1Pz69LymhOzizLyqjPTm1OzWvIyGhIR6dIRubIRmZHxaVHxSTHxCPIRydIReXHxWVHxKRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaIQIAQECgajcNkQMBkDgKEQFK4LFgLhgMiOl0mFFbEYVEgMJQC8DXRODjOw8DjGhYMIHCq4FuIKBASDwN5RGlWYBMUFRaEVWEXFBgZjEoPXxoSkX4bjYaZGBxgHZ2AkR4cHx+cSiAJCRAhIiMkJSaNCREgBScFKCkqtkq4sLK0JsFxDMrLzAx+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 source_java-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFRWVFxaXNza3OTi3Nze3Ly2tJyanPz+/Ozq7GxubFRWXHRydMzOzDQyLIyKjGxqbERCRCwuLHx6dKSinKymnLyyrNza1PTy9Ly2rIyKhDQyNGReXKyejKSWhIx+bJSCdIRuZCQiJISCfGxaPJSKdHxuVHReRHxiVHxeVGRGPKSajMS+tMSynAQCBFxeXGROLFxCLFxCNFw6LGxiXFxiZMTCtOzi1ERGRLSytJSWlERKTNzSxOzaxKymlOTi5JSSjISChBwaFNzGrLyqjKSmpDw+PMS+rOTStLyqlLyifGRmZKyqpLyidAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfWgACCAAEChYeGg4oCAwQFjgYBBwGKggEECJkICQoIk5ULmJoIDA2eDoqXowgPDBAREoIRExQVFhYEBA0XGBkaGwAcHR4dHx4gIRMGDBcEFg4iIyQlJicoISkqISssBC0OLi8lMDAxMiozNDUUNjctEjg5OjklDCEcOy4OFDw9Pg4QfuQAEgTCDglCHAQYMaQHEVRFBhRhIACHAyMLIHg4guShIAg6KDwYMYHBhBVJhiBRgmrQkhxMKlBo0ULlkCYtLbGwYYNmCyJNguYk5KBoUQlGi/oJBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 source_l-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbIyKjMTCtPT29GxubMzOzPz69DQyNHRydERCROTi3IyKhIyOjPzy7PTu5Ozm3LyqjPz29PTq3Ozi1LyqlPTm1OzizOzWvLymhGxudGRmdFxedFRWdERKdDQ+dHR2dFxidAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaHQIAQECgajcNkQMBkDgKEQFK4LFgLhkMhOl0iElbFgtEgOJQC8BXxOEDOw0DkGhYMJHCq4FuYJBQUEQN5RGlWYBQVFheEVWEYFRkaG40RXw2JGX6MaIiRHGCccQKAkRodHh4fjQ+tICEiIyQkJY0mJg8FJwWzJbVKD7gnI7K+v3EOycrLDn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= source_moc-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIQAAPz+BKSipISChERCBPz+/AQCBMTC/MTCxISC/FxaXDQyNASChARCRPzCxAQC/PzerMRaBPyCBPyqXISCBPwC/MQCxIQChATCxMT+xATCBASCBIQCBARCBPwCBMQCBMTCBCH5BAEAAAAALAAAAAAQABAAAAWOICACQRkI6DCuJOG+JysGL1wIMm0YNHEUBNwqsDMgEL5AIqEYIhZPxqtwUI0CzwRDSih4E6KGeLl1vB4FMAASkTC1icmjmxZBKBXL4YLJaAoPgWoQEBsbGX4JHHR1Ih0eChkTGoqADQ9qMwR+GhwcXlSZAAJzDQNogZeiAUBeaAcNHw2iAygocQkCuQN+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 source_o-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbIyKjMTCtPT29GxubMzOzPz69DQyNGR2ZERCROTi3IyKhIyOjPTy7PTm1LyqlPzy7PTq3LyulLyqjPTu5OzexOzWvLymhHRydHR2bFx2XFx2VFR2TEx2RHR2dFR2VAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaHQIAQECgajcNkQMBkDgKEQFK4LFgLhkMhOl0iElbFgtEgOJQC8BXxOEDOw0DkGo4MJHCq4FuYJBQUdnlEaVZgCgYVFoNVYRcYGBEZjBFfDRePEgkajIUXGxgVYJxoCp+hHBwdHowfIK4PDyEiIyStJSUFDwUmJiS2Sq8PILG+v4wOycrLDn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= source_p-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBMTCxDQyNPz+/FxaXKSipPz+xPzerISChATCBARCBASCBAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARVEEgQqrUz3yqGCJlUESRZEFVooWZAfJpbEkU9gNMqo4KBi7vSAfWjyFxIUnEkJAwPy9EugEDFSE+nMzojVKvLREGsKCgWjMVybDaj0eH2OZ2Objb+CAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 source_pl-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbIyKjMS+rPT29GxubMzOzPz69DQyNMTCtHRydERCROTi3IyKhIyOjPzy7PTu5Ozm3LyqjPz29PTq3Ozi1MSynPz27PTm1OzizOzaxOzWvLymhLyifOzexLyedLymfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaJQIAQECgajcNkQMBkDgKEQFK4LFgLhkMhOl0iElbFgtEgOJSCx7WAgBwi52FAsi4oBINJnCpAqCkPChUSA3tEEmoFahUWFxiGSwphGRYaGxyQEn4NHZVfj2iLlR5qoHICGYyWHyAhIpB9Dxp+IYAjsGokaiFqJZAJDwkDHBwYJiW+Sg7LzM0OfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== source_py-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxaXNza1Nze3Ly2rJyanPz+/Ozq7GxqbPz6/NTSzDQyNKSujIyKhHRydERCRGR2PHyaLLzObIyqNKzCZIymRKy6jPTy7OTi3ISChFx+HISaNKyuPJyaBKTCRKS+VISiVGyKJHSGPLzWdKS+TMzefISCJHRiBGySJJSyNLTGbKzKRHSaHJSWhLyulHSKNJy6RKzCXISWRLTOZJSuVIyuJGyOHHyWLOzaxJSqTGyGJJSmXHySPJS+JHSOHIy2JHR2XLyqlERaHGSGHFRqJHSOJGR+JFxmPNTOxIySbHyORHSWJPTm1ISiHHyiJFRuHMSqjPTu5OzexFx6LMTCtMS+rJyidISqJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfKgACCAAGFhoaDiQECAwMCAgQBBQGJggEDBpkGBwgJk5WXmgYJCAqeC4kFAwysCQYNDggPqIMQERITFBUWFxgEGagaGhsVHB0eH8ggvQQLISIjJCUmJygpKissLRcuCy8wMSMqMhszMzQ1Njc43QA5Njo0Ozw9Pig/LCxAQbRCOkM2iBQxgsLGjyJH+CXKoEABkiRKWCxhQYQBLUsYLhxgwkRJEydPoFwkhCEKRylKbNSYIlIRASpVCFj5UeMKhJaDAizYybPnAj+BAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 source_s-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbIyKjMTCtPT29GxubMzOzPz69DQyNHRydERCROTi3IyKhIyOjPzy7PTu5Ozm3LyqjPz29PTq3Ozi1LyqlPTm1OzizOzWvLymhGxudGRmdFxedFRWdERKdDQ+dHR2dFxidAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaHQIAQECgajcNkQMBkDgKEQFK4LFgLhkMhOl0iElbFgtEgOJQC8BXxOEDOw0DkGhYMJHCq4FuYJBQUEQN5RGlWYBQVFheEVWEYFRkaG40RXw2JGX6MaIiRHGCccQKAkRodHh4fjQ+tICEiIyQkJY0mJg8FJwWzJbVKD7gnI7K+v3EOycrLDn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= source_y-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxubPT29IyKjMTCtMzOzDQyNHRydERCROTi3IyChIyOjPzy7Pz27PTu5Ozm3LyulPz29PTq3Ozi1Pz69LymhOzizLyqjPTm1OzWvIyGhIR6dIRubIRmZHxaVHxSTHxCPIRydIReXHxWVHxKRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaIQIAQECgajcNkQMBkDgKEQFK4LFgLhgMiOl0mFFbEYVEgMJQC8DXRODjOw8DjGhYMIHCq4FuIKBASDwN5RGlWYBMUFRaEVWEXFBgZjEoPXxoSkX4bjYaZGBxgHZ2AkR4cHx+cSiAJCRAhIiMkJSaNCREgBScFKCkqtkq4sLK0JsFxDMrLzAx+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 tar-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxaXNze3Ly2tJyanPz+/Ozq7GxqbJySbJyadPT29Pz69GxubMzOzDQyNPz21LSujPz25OzmxNTS1IyKhERCRKyqjLy2rKSehPz67Pz23OzerKSaZMzGxPTy7PTqvOzirMy+dKyeTIR2NPTq3LyubLyqVJySPHxyJOzi1LyunPTqzOzW5OzSzNzOrJSGNGxiNLy2pPTm1OzezLyqjJSKZOTStOzOxNzGtOTSjKSSRIR+LGReHLyynOzexLymhOTWlNzOhFxSFHRuRNzKfNTGdHxuLGxeJIyCbMy6pLyifLyqlNS+pOTOpLyedHRydJySfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfLgACCAAGFhoaDiQECjIwDAQQBiYKLBZYFBgcFkZMICAkICgULDA0LBA6Cnw8QERKgExQHDBWpCBAQFrm4EAkKAhcUqRgRGRqsGxIbHB0eAgOpCRofCw8WICEiIwMkJBDRCwsgICUmIico3CkqtissLS7mJy8wMTIzNKk1Njc4OSI6Xuzg0WOGjx/6gOQIEkTHiB0ohKjwYQOhoCEliBQxcuQIDCRJbNhQkmoQRhgflzAR2cRJSUFPekDpQbMHjR9OXCpywLOnTwd+AgEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== tex-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBMTCxDQyNPz+/FxaXAQChKSipPz+xPzerAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARgEEgQqrUz3yqGCJlUESRZEFU4lkQREJ/2skU9BEaezzmRCwccwDCc+XwIFGhI0ZEMxiURxzIQkghp0+qjJlDDHdRnQPSyGu4oEfguRTrs9fqmWAjfPHpSkWMReyIbg34RACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= tgz-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBIQChFxaXMQCxNze3Ly2tJyanPzC/Pz+/OTi3GxubJySbJyWbPT29MzOzPz69DQyNPz21LSujPz67OzmxJyadNTS1IyKjGxqbERCRKyqjLymhLy2rIyKhKSehPz23Pz+9OTevOzmtKSaZMzGxPTu5PTqzMy+dKyeTIR2NPTq3LyulOzirLyubLyqVJySPHxyJOzi1OzW5OzOxNzOrJSGNHRmJOzezJSKZOTSjGReHLyunOzaxOTWlNzOhKSSRIR+LFxSFLyynOzWvHRuRNzKfNTGdGxeJGxiNIyCbMy6pNS+pNzSrAQCBHRydLSunMSynAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfYgACCAQKFhoaCiQOEBI2NBQIGAooHjAiXCAkKCJIAAZ8BCwsMCw2XCg4PBhCCohESExQVCxYXChgZrAsSvBIaGxIbDA0JHB2sHh8gHx8SISIiIyQlBBysFR8mzBIiJygpBSUqK9cPEywiLS4oLzAFKjHkAAwmMjM06y81NgUmNxuscNCYQSIHuxopdOy4wQMgABw9cvjw8SMFEBhBhPAY4hAAkRZFjKQ4cgRJEiWgAiTy2AKJSSFLmAQ4MKDJSidPFggRAmXFhgADNthMJACC0aMQAjRZ6icQACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= txt-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxaVPzKjMR6RNze3Ly2tJyanPyODPz+/Ozq7GxqbPyKBPyGDPzGjPT29HRydMzOzDQuJOx6BPyGBPyKDOTWzIyKjERGRDQyNKROBOR2BOzezIyKhBwOBKRKBNSOXOza1CQOBPyCDOySZPzizPTWxPTy7Pz69Pz29PTq3LyqlMxmJNRyROy2lPTu5OTi3MSulFxGNIRWLMR+XPTKrOzStPTm3IRSNOzizOzavLymhLSyrEw6LKRuVIx6ZNzSvOzexNzWxNzW1FROTBwaFKSShOzWvOTOpOTazJyWjHRqXNzKrOTStLyifMS+vMS+rMS6pLymfLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfOgACCAAGFhoaDAgOCAQSOjgUBBgGCB4qEBAiaCAkKCJMACwwNA42bCA4PEA4GERITFKQVpwgWDwoXGBkaE6MDG6cOBAUcGB0eGgsTDR8gmw4OGwURACHIIiMkJSYIJygpKSoYgtYrLC0kLdAuKS8w1IIdMTIzNDUbLjYpG+KDABcRbtRrYWMDjhw6xg0KsCMAjx4+fmwAEiShvwBCChgYQqSIkRpHdMBjZCIFkh1JlCxhcqSJQkZOnjyBAgOGjihSpLwkhAFDBJ9Ae0bwEwgAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== unknown-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXIyKjNTW1Nze3LS2tJyanER2RGS+VPz+/PTu5GxqbPz69BQ6BCxeLFSqRPT29HRydMzOzDQyNERmPKSypCRWHIyKhERCRDyGPKz2nESiLBxGHCyCHGxubPz6/PTy7Ozi1Ly2rKSipOzm3LyqlKSWhCRyFOzizLymhNTKtNzOvOzaxOTStPz27OzWvOTOpLSupLyedMS+rMS6pMSulLyqjLymfLyifAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAamQIAQECgajcOkYEBoDgoBQyAJOCCuiENCsWBIh9aGw9F4HCARiXciRDQoBUnlYRlcIgsMG5CxXAgMGhscBRAEBRd7AB0eBBoIgxUfICEiikSPgyMMIAokJZcBkBybJgomIaBJAZoMpyCmqkMBFCcVCrgKKAwpoSorKqchKCwtvasIFBIhLiYvLzDHsxQNMcMKLDAwMqEz3jQ1NTY3ONyrE+jp6hN+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 vcalendar-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBFxaXDQyNAQCBMTCxPz+/ISChAQChKSipAQC/Pz+xPzerPyqXMRaBAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARyEEgQahVijMmD/oRAbBw1FCgaFFrpEbB6jt1g3OpFAscxwATUiIAgBRKJXiqIYJEMBQNSWSAYgptrMDo9FJqKrHArTR4WLGisSkbebE12gXFFGRBFyd3eaFSvbx1xCDBXC2E1e1EECo07ABkaBh4fGn4RACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= vcard-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBFxaXDQyNAQCBMTCxPz+/ISChKSipISC/ERCBMTC/Pz+xPzerAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARvEEgQahVijMmD/oRAbBw1FCgaFFrppeo5drKhXqQUEIfREyweqWIoHo4GDYtkGxwQ0CjitEkUrCyfYjtdbJoFW/agmLJWWZSY3B0EbGJ4uAwcHlK2HpTg7YgHBgQjDH0THoGBCwULjDkAGR+RH34RACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= video-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxaTFxaXIxuHJyCLHx6ZLy6vJSSlNze3Ly2rMy2RNS+TKyqrMzKzPz+/Ozq7GxubJyanLSePKySNKSSPNTS1JSWlDQyNMSqPLSmVNzKZJyenIyKjHRydGxqbERCROTWXNS6XOzidNzOZPT29MS6rISChLSulMy2TLyeNKSOPJyCPOTi3JSSfHxiFGxaJFxWLFROLPTu5Ozm3ISCdDw2BFRKHHxqPFxWPLymTMzCvPTq3OzezKSWTMzCbNzGZExKNHx6dLyqjMy6XMSqTMSmTEQ+JHRybMSynISCbMyyVOTWbLy2ZBQWFGxqZOzifDw6LCwiDISCZJR6LIRqJBwWDExKRHRuXHxmJGxeJFxSHCQiFFRGFGRSHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfhgACCAAECAoWHhoMDBAUGBwiRkQkCBwGCCgsLBQwNDp8ODxAOEQIAChITFJwVoA4QnhYXEhgZBRoFG62fHB0eHxcgIQUiIyO5uyQIJSYXJwUoKSoUKwEWniQkLCUXHy0DLi8vMDEfBw0kMjMnFwAfNDU2Nzc4OTgmOjs87ILvEj04NPj4ASRICR5C2vVrEWAIEQwSihg5giThIHdJiCgJMWIJkyZOLA4K8CHJkycimEAJEcWJQkECEHyQEqIHFAJTqFSxcjGAjhIfrlzAkkWLDS1bel5Y+mELly5YCEyQ4CcQACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= wordprocessing-16:mimetypes mimetypes16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFRSVFxaXFxWTNze3Ly2rJyanPz+/Ozq7GxqbHR2dHRydGRmZERGRMzOzCwqLJyWjOzi1Oze1PTm1PTm3IyKjDQyNERCPPTy7HRmXCwqJPT29DQ2NNTGnOzm3PTq3CQqJMS2hDQuLKyaXCQmHBwaHKyahLSijKyehBQaFCQiHHRqNPTu5LyulCwuLHxyNAQGBBQSFERCRBweHOzezIyCVJSSfOzavLyqjOzexOzWvLymhExGJEQ+JExCJExGLCwqHOTOpDw6POTStLyifMTCtMSynMSulLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfWgACCAAECAwIChYeDjAIEj48FAgYBjIIBBAeaBwgJBwYDjAoLDIkNmgsOnw+CEBESExQSEgsHFQsJDRYAFxWbmhgZGhsEBRUcHQ8cEB4fzhAWICEYxSIjJCUDJicnKBkpKissFC0uLwAwMDEyFzHpDxgfES27DyozMyX6+TMTEzQtWJWoIYGgQRsl/t3AsStFQRoGIYrIkUPHDhcANPDo0cMHxx9AUtzQEWQHKwAcSDy4IAQbh5FDghDZNShAkZsFjBzBgaQnh0YcHojgIMIFBwtBXfgJBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 1downarrow-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBBQSFAQGBDQyNExKTHx6fGxqbFxeXGRiZFRWVDw+PAwKDJSWlOzu7LSytJyenJSSlISGhISChIyOjFxaXDw6PPz+/MTCxLS2tIyKjKSmpKSipJyanAwODDQ2NHRydERCRFRSVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAZzQIBwSCwaj8ikcslsOp/OgHRKlQoCgymRUDAcEIkwYgxWFBYERpHQcDwgEclEQmk8DhWL2kiIXDBwExMNGRoJaUkEEH8bEQ0cGgcWAksEHX8QHBKSHk1sfxMHH5ROBBsOICGkT2wiq1CIULKztLW2t0h2QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 1leftarrow-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNAQCBExKTJSSlHx6fAQGBOzu7GxqbJyenPz+/LSytFxaXMTCxGRiZKSmpISGhFxeXISChAwKDFRWVHRydJSWlBQSFERCRIyKjDQ2NIyOjLS2tDw6PBwaHFRSVDw+PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAZ5QIBwSCwaj8ikchgQLJGBgfNZDBAKBirRekBMtYGEYsHIgsWNhOO7tCrShDU18Hg/CJAIG0o4wCUQcksTFBUSCRYSEnpUFxgIGQkJGYyNGggbHBaVjR2QCxEeWkITHQ4IH3tPFwEMA2ajAKUgqlQTTbFEE7W5vUgGQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 1rightarrow-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNGReZAQCBMTCxGRiZMzGzOTm5LSytPTy9Pz+/CwqLOTi5Ly6vCwmLMzKzJyanJSSlBQWFKymrIyGjCQeJJyWnISChISGhHx2fKyurDw6PAwODHx6fHRydDw2PERCRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAZ2QIBwSCwaj8hkMRBQKgOCgRMZIBSk06XhEM0SA4iE4uoVLhCMhqLrdSAekMgYO5VM4BQ521mxIC4UFxBWdEkSERYYFxETGQGFSBKCGBEaGRuQSBwdeZaPXpsQCB6YZQMdEI6ZSgMepKusHh+wrCC0rLdlursGQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 1uparrow-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBFxeXDw+PMTGxHRudPz+/JSSlLSytIyKjHR2dISChIyGjIyOjLSutLy6vKSepJyanISGhJSOlOzm7Ozu7MzGzKyurJyenDQyNGReZKSmpIR+hCwuLCQiJBwaHBQSFAwKDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAZtQIBwSCwaj8ikcslsOp9QYyAQFQYEAyr0Sihkn1fDAeHVLsOJNELxVaITC0bDUU6GH5AIQ8KYrNtFVxQVFBYWFxgRCREYdUQZGhYEDwgIGxAHCQocCgWOQhmhGR0epR8gqCFTq1Wtrq+wsUt0QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 2downarrow-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBAQGBBwaHDQyNExKTHx6fGxqbFxeXGRiZFRSVDw+PAwKDJSWlOzu7LSytJyenJSSlISGhISChIyOjFRWVDw6PPz+/MTCxLS2tGRmZDQ2NAwODJyanKSmpKSipIyKjHRydBQSFERCRExOTFxaXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAasQIBwSCwah4FkQKBsDpoBIqFgOCASCYRWm1AUFgRGkdBwPCARiWRCaTwOFYvYSIhcMOiJpJGZaDYcR0IEHXceEQ0fICEWIoJDhHcQHxIHgI9SEHeVG46YUh8OISOen1INCqWmUnOYTUxQAU9NUlRWWFtbCiRgrYNlZ2lriG8lYUd1khETE24gCZeCkRgeFBAQIAeNn9OTlXKrBJoYnKrcoaPmpmSpq3S+7u50QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 2leftarrow-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNAQCBExKTJSSlHx6fAQGBOzu7GxqbJyenPz+/LSytFxaXMTCxGRiZKSmpISGhFxeXISChAwKDFRWVHRydJSWlBQSFERCRIyKjDQ2NIyOjLS2tDw6PBwaHFRSVDw+PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAavQIBwSCwaj8gkMiBYNpeDZzEQXRIKBmPgmtUSDgipcAsWjxOKBaN7Tq+n6EbCIQ3E5+KtQk6gjwl7CX11D3sPBBARTQGFDYeJT2R8EhB0koKUfgATFBUSCRYSEoqcnqCiikMXGAgZCQkZqautr7FiFxoIGxwWqQC4ury+qh2tCxEexMbIRhMdDggfYs7Q0kcXAQwDbELY2txEziBmmx3jSRNMR+nk4e2b70ry80QGQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 2rightarrow-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNFxeXAQCBMTGxOzm7CwqLLy2vPTy9Pz+/Ly6vCQiJLSytLS2tLSutOTi5MzGzKSepIyKjJSOlKSmpMzKzJyanIyOjBwaHIyGjISGhJSSlISChBQSFJyenIR+hGxubDw+PHRydHR2dEQ+RHx6fERCRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAa6QIBwSCwaj8hkIIBcJgEBweAYnTYJUmMAa9USClniFtwlGg6IRFhoUKTXwwWj0FB3F46Hwl6UQyISfAB+EROCQgsUFRYSF3yJEIyBaxgWDBkaGRtclQwSHBIbEGEdGx4fGhcOICEDGBsWHBmqIq1CHRIWGRMMIyRTHRy6Er22tyONq8YdJRe0xkIDwr2/QwMfliMmZQADIxasZd4e4UYDIr7c59rc0eVFA+/m0EQD9PDt0flP/P3+BkEAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= 2uparrow-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBGReZDQyNMTCxHx6fPz+/JyWnKyurHx2fDw6PJSSlISGhIyKjIyGjISChLy6vJyanOTm5PTy9OTi5MzKzLSytKSepMTGxMzGzLS2tLSutKymrHRydCQiJCwmLBwWHAwODLy2vHx+fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAajQIBwSCwaj8RAAMkUBgSDZdP4JBSi06TAcEAkFNLp07BgLLzY5njRcDzO3zB1C4lEGI83Wj58SiYUFRUWdg0XEXFFAwIYGRoWGxwRZQUFHZdgRAObmx4fHiChISFKpVlKWUdPaalOAlasp1sHG4myZGZ7Yltsbgu1mUhjdRF5egmxfQJ/gYOFdrZDi40iFgiSCw8jBQmYcpydn6Ego6WorUwGQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 abs-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIEAAPwCBIQChAQCBBQSFCH5BAEAAAAALAAAAAAWABYAAAJLhI+pF+vW4HMR1InqxbJzBiLCeIxCaIkneQJk6rkl+2qlONzeNi+2YvKhEIOW4iczvJSoSDDIbCpbq2oGBXUtd59r7IPshsHdB70AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= airbrush-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIMAAASC/AQCBPyChMwCBIQCBPz+/MzKzKyqrISChDQyNPwCBAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAR8EMhJKw3BahvEyNvWDV+ojQMBAhgmeukaFHSxTqh6FYZx3CyYbtf7XYRAFs8nQ56WxiBpyOEdjLkkrnA9IAKGqXbnTYAP1NDMe0Z8JYR4nPP1seEqTHpWZMupVHx2by03Q4JXbxuBfYoaaVZ3i4YKbo4WaQAKBCxjcEAGEQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 appearance-22:actions actions22 22:photo:22 22:R0lGODlhFwAWAIYAAPz+BAQCBBweHPTy7Ozq5ExKRPTu5NzStLy2lCQmJAQGBOTezNTKrLyylNTKpOzm3NzWvOzm1MTCpNzaxISuvBSGvLy+pKSehOTexISutKTa7IzS7GSarJTW9HTK7CyazBRypMzGpDw2LOTaxEyKpCSSxARGbERCROTizMS6nDx2jARajIR+bOzi1OTi1MzCnLy6lOSupNx6dGS2rJS6pMy+pOS2pNxGTKwaLDSmpHTOzES2tIyuhLSmjPyqrMw6RLSOhLzSrGyqbFSmXJSyhNTOtGTCvLzm5CyOjEQ+NPRqbOxOVKyKfMzizKzepFyuZJSqlBR6fCRmZJSKdDw6NLxqZLQiNIwyNLSejDSCRJzWnEyiVHySbBRiZDQyJMSijGS6ZHSCZJyafDRmPISKbJyifDw6LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAXABYAAAf/gACCg4SFhoYBAgGHjIQBAwQEBYwBlYiQAwYGi4UBBwcInIIJA6WRBAqdCwcMDA2pggEEDpUODwSiAAEQnwwHnI8RwBIGsLoLExQVFg4XiwEPD6IKGBjAExkaGxUcocfSgwHV1uITFR0eHyAhIroRERLAC/PVIxMkJSUgJvHH1RAKTixAgQzZhAkpVKwwwYKWrgnzFrRY4IIgBoMTRryQAGPjs4zzYsgYQdIgsgMzaNRw0CCBLgn2bNzAceMgSZITcujYwaNGj2sjcPjw8QNIECFDiEgoYuSIDiQOkoSTMAGHkiU4mAhp4uQJDyhRjOSQMiUXFQdVrOC4giWLFidbRri8QBKlyxQviIp8udKjRhYwYLKEedFAjJgvucI5cFBEgoMxkMm82PjFmCERix1wLCNmcg8viRGZ6aHZcQ8zoRtVWp16UCAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== attach-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBMTCxPz+/DQyNKSipAQCBISChFxaXDw6PAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARrEMgJgqA4zzus/gLhFd5HCcZAXqsphYPUdhcYFNRcZnvdtpnDqPTbUWgAJKBYwzBlw+bRo3xmkNWoBgm0OrVLn3GC9RgCk8DhUw7c0rHPr4CDu5SYQNyEt7uSY3p/UAKFhYKDSQOLiwgFdhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== back-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAw2VCRGZAxCZGyavExmjHyatOTy9CxihISevPz+/KzO3BRylAw+XAQCBDRWbPz6/FzC3CSuzDyexJzO5Mzq9CxSdAQOFISmxNzu9HTS5BSmxAyexDSuzJTa7Mzu9Kzi7GS21CRmjAQOHHSWtLze7AyWvHzG3BRihAQKFCTO3BS+1AyixBSWvBSOtBSStAQWJBSixDzW5BTC3BSqzBS21CTC1ETW3AQSHEze7BRqlBRmjAQCDBR+pBRefBRSdCH5BAEAAAAALAAAAAAWABYAAAalQIBwSCwaj8ikMqBcMpvHgGAANQYIhWdVGDAcENQtIJBQLBgNx0MQaDuQXcghIplQDhBIxXKJYiAZGhscHR4VHyAhIiNWJBklGhIbJoQnFCcTKIxFKSgbKissJi0mJi4vLiYoMEcXKDEyMzQ1Nje2NisoOEg4KDU5K6g6OwwoKAN9SCOeMmgwz884PEq9PT4NYkPLP9jZQikN3d4AKVrjKePp3gZBACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= blend-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQmJAQyNAQ6PARGRARSVARmZARubARuXARmTARiPAReLARaHARKBAROBAQCBERydESChESOjESanESmpESytES+vETKzETKtETCpES+lES2fESybESqXESiRAQ+PARiZARybASGhASWlASmpAS6tASynASqhASiZASaTASSNASKHAR+BARiBARydAR+fAS2tARKTDRaXARaXASOjASKdASCZAR+TAR2PARuJARqFAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAa3QIBwSCwaj8ikcslcBp6CAaFQMBwOiIRiwWg4HA9hAAKJSCaUiuVywWQ0G07H4wkDxp8CKCQakUolJicoKSorLC12eHouL34lMIKEhoiKEFMgLn0kMIGDhSyVYhADjJuAkoWHiaMEMXuOnJ6Tq5alBpp+nSeflKx3l6a6s6CiwKWZm52pvpaue8rEzaPIubLMta2Mscu9ob8BMgIfBDPJNDQ1Njc4OTotDXYP8/T19vZN+fr7SXRBACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= bookmark_add-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBCwqLCQiJCQmJMTGxAQCBLy+vLSytERGRFRWVKyurKyqrLS2tKSmpHR2dJSWlKSipISGhGxubIyOjGxqbIyKjFxaXGRmZHx+fPz+NGRiZPz+ZPz+HMTCBKSiHPz+jFxeXPz+XPz+tPz+zPz+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAamQIBwSCwaj4Gj0hgQLJ+AAaEAVQoI06pRYDhkoYgwIhEgKBTfZ2FhaBsYDS8VWnA8Go0FJIKeqyUTDw8EDHBpSwUUFQ4UFhcYDQYFfkoFFxEQDG8KEAUZlEeWGBIakw4FG1STiBoYBRwdBR4fHgUdHKBEBSCnIR8iIyIfIblFu6ceIyQjtcXGCbLKzAUKzrq+wMLEVa+xs7W31kOTk6nkWuOf6Ea5QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 bookmark-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIQAAPwCBCQmJCwqLMTGxAQCBBwaHMTCxLSytERGRFRWVLy+vKyqrKSmpHR2dJSSlJyanISGhGxubIyOjKyurGxqbFxeXGRmZHx+fKSipLy6vGRiZLS2tFRSVHRydJSWlHx6fCH5BAEAAAAALAAAAAAWABYAAAWWICCOZGmewamaQrq+wUC8azHINGocOI38iIRAceDNaISFYklkGHOEhoNBfUAOhuOLEJE8HoPiRKFdESiQBqViuTDIUAsEcyAeGJmyiqC5RCwJGg0YcEh9D0V3Dxt6JwQVDRYVHBUdi40mjw0PTgwQHgeYJQQJfxUXFxAOoTkFpQ0fsRSimQkWEQ0VtI62HLt7vjl7JQYhACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= border_all-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAI+hI+pyw0Bo5wR0TttUJDv0yWhRopfaYzguaKt6aasrGFYbVPxM/O7Snv9WEAfTIgMKpNGWU63emYc1GrVUAAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== border_bottom-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAIyhI+pyw3xIpwyOgOv1dvl+2lhMzIlyZ1KQLUVm8Zch4ozbcq6l7L+D4QhgsTf7Xi0FwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== border_fall-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAI/hI+pyw3xIpwypgBRdg/v9h2eyBnZCIKYxX2oEsJruVKjHS8vk3duKZnpHKjeRSTU0HYpTcxWgRqB1KrVYC8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= border_horizontal-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAIyhI+pyw3xIpwyOgOv1dvl+2lhMzIlyZ1KwLbuyybw7KY216Einpv377FRhhUV78igFwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== border_inside-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAI7hI+pyw3xIgxTRvcg1oku3njbBx4liV3dqYbsSsXyLBr0Pad1iCovsmOwgjbdz9TrGHWWSeWZikoXhgIAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== border_left-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAI6hI+pyw0Rnox0ygNXdG9z43Xal30gUiYhk5LoenJQRVtti5FwE+Kx4+O9RrIda6gwDmvMi+kJjTIMBQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 border_outline-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAI8hI+pyw0Bo5ww0SttcKci/ymgMTZl+Yjbt3Jn26lautX0A+OizHJkjsrper7XbkZ0ATEYDZPii0qnU3sBACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= border_remove-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAIthI+pyw3xIpwyOgOv1dvl+2lhMzIlyZ1KQLUVm8Zch4ozbcq6F7s+fgsKb4YCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= border_right-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAI7hI+pyw3xIpzyQRdVuIZj+3nHhogOiZng+I1qoqIdRVfbWy5y1u5M7MFphB1dsDULGXO15goJjUoRhgIAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== border_top-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAIyhI+pyw0Bo5ww0SvdCdrw7oGfNnZlczIpKorc+8RwZbZgXOc2uevOqpjJhrCb8QgwFAAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== border_up-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAI/hI+pyw3xIpwyOgNRyPq+zTkcuIQKaV3T1pgHinmfm7AUedMa64Vw3bLJMr9TiZcSFUsnkw54q0Rl1KrVYSgAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= border_vertical-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAI6hI+pyw3xIgxTRvcg1oku3njbBx4liV3dqYbsalFeJTp1iCovcjNsb9iZhMFcJwXUxTJLYuoJjR7sBQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 bottom-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAw2VCRKZDRSbBxCXJTC1Mzi7Nzq9NTm9Bx2nAQCBNzu9JzG3Hy+1HzG3IzO5BRmjPz6/LTe7Dy61AyStCTC1FzC1AyGrETS3ETC1ETa5BRulAyuzBRylAw+XMTe7Gy+3CSqzAyexBTC3DR+nIS21KTW5Nzu/KzO3FzC3Pz+/ByixEze7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAaXQIBwSCwaj8ikcnkMBAQDgjPAFAYKhsMBkVBUAYEFo+F4QLzVQEQyoVTOX/XBcsHA0+vMRbNBMwkRDhxuHX5GTlIeHh8gISIjFAEeiVRECiQlDAUmgxQjIhwiJHdFlycoKSIUFCEjGiGkRpcqCxYijxorsUezcxYsuoZJsxLAu0qXB7DCTJfHvArR0tPSSNTX1V/a20J2QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 brace-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIEAAPwCBIQChAQCBBQSFCH5BAEAAAAALAAAAAAWABYAAAJRhI+pGbHYVHzQnUnrtXn7/gEYIJRHKRgYZraGuXLp28LcNL/Dqd4cYmJYRqegsKcY5DRIUhHYFDlQJGMuVn1ljdhqjhoiZrogKbMjFh/LHUMBACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= brackets-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIEAAPwCBIQChAQCBBQSFCH5BAEAAAAALAAAAAAWABYAAAJRhI+pyw0Bg3vxwImu0Zha2XkbaAjmYQrjh6qnCpwcB8evTGp1PKDrnzglZqTWDsg5DI5IUE1Yatpc0BrRFr2xfiljJlecXEPjDjG5iIRDCHsBACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= centrejust-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAIhhI+py+1vgpy0TogztlT7j3CiBJbZWJlqg4rry7jw/BoFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= charset-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIIAAPwCBAQCBAQGBFxaXAwKDBQWFAAAAAAAACH5BAEAAAAALAAAAAAWABYAAANLCLrc/jDKuQK1zmKo3/YVJSpBSZYmKaTkAAwYoQwFELjvpisyaTM7H6AH+3lQMZQwExrOOiBh7/cJGokaXHGpQVaUo7B4TC6bw4AEACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= colorize-22:actions actions22 22:photo:22 22:R0lGODlhFwAWAIYAAPz+BAQCBBweHPTy7Ozq5ExKRPTu5NzStLy2lCQmJAQGBOTezNTKrLyylNTKpOzm3NzWvOzm1MTCpNzaxISuvBSGvLy+pKSehOTexISutKTa7IzS7GSarJTW9HTK7CyazBRypMzGpDw2LOTaxEyKpCSSxARGbERCROTizMS6nDx2jARajIR+bOzi1OTi1MzCnLy6lOSupNx6dGS2rJS6pMy+pOS2pNxGTKwaLDSmpHTOzES2tIyuhLSmjPyqrMw6RLSOhLzSrGyqbFSmXJSyhNTOtGTCvLzm5CyOjEQ+NPRqbOxOVKyKfMzizKzepFyuZJSqlBR6fCRmZJSKdDw6NLxqZLQiNIwyNLSejDSCRJzWnEyiVHySbBRiZDQyJMSijGS6ZHSCZJyafDRmPISKbJyifDw6LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAXABYAAAf/gACCg4SFhoYBAgGHjIQBAwQEBYwBlYiQAwYGi4UBBwcInIIJA6WRBAqdCwcMDA2pggEEDpUODwSiAAEQnwwHnI8RwBIGsLoLExQVFg4XiwEPD6IKGBjAExkaGxUcocfSgwHV1uITFR0eHyAhIroRERLAC/PVIxMkJSUgJvHH1RAKTixAgQzZhAkpVKwwwYKWrgnzFrRY4IIgBoMTRryQAGPjs4zzYsgYQdIgsgMzaNRw0CCBLgn2bNzAceMgSZITcujYwaNGj2sjcPjw8QNIECFDiEgoYuSIDiQOkoSTMAGHkiU4mAhp4uQJDyhRjOSQMiUXFQdVrOC4giWLFidbRri8QBKlyxQviIp8udKjRhYwYLKEedFAjJgvucI5cFBEgoMxkMm82PjFmCERix1wLCNmcg8viRGZ6aHZcQ8zoRtVWp16UCAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== colorpicker-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBAQCBMT+xASaBASyBASCBARCBPz+/KyqrISChAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARZEMhJ6wzBahvEyNvWEcMXcgJBFuApjavRhlgaz6J9u5dQDAUZ73VA+FhDQOAQQCQEQt6ymcjgREznlZatJpXdLZYq1ky137M3qS5zwl8lOR5IIDBx5TpviAAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== configure-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIQAAPwCBAQCBISChFxaXNze3NTS1Ly6vKSipNTO1Ly2vNza3Pz+/MzOzOTe5DQyNOzu7MTCxGRmZMTGxPTy9Ozm7Hx6fPTu9MzGzGxmbAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAW1ICCOZGmeaEoGbBsI6joMRGEcbQwESDIrtVtAF1gwDLNaAmfKiVgLBJKgwB1KxQZrBHU0FAXmavFoQLYiB6TxFXMj5AZBwnJI2I3wcNWALyYEcgoKXxRhOHs7XxEVCwsWFgoUDRYUFwwQB25ZCxiNjo6GkwUXN2NsCxEYqhUHoQ0MEglYRQQXErcHrI55FycuB2YSmoyOBTEtB2sXuhU6XAENC2a6z9AKCwq+1tAN3E2J3ySkIQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 connect_creating-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBPz+BMTCBISCBAQCBPz+/MTCxOTi5AQGBNze3Ly6vISChNza3FxaXKSipAAAACH5BAEAAAAALAAAAAAWABYAAAR4EMhJqwzY6omD+MNGdR8YilNZnug0qGzrqrL1lnV1fyJBVB6VQEMoGH4ADGwQkxQPBwMiKGA2J8VEAnq0tgiKg5aL/C7C2gTjKCM0zowDQ8tuNQznNL7cKzjOUQsNfER+gguIg19+Pm6ChBZFDmWNi5M5FIyYFHQRACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= connect_established-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIQAAPwCBAQCBKyirPz+/KymrOTi5KSipMzCzNza3OTe5Ozi7MzGzPTq9OTm5ISChMS+xFxaXNze3GReZIyCjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAWLICCOZGmeaBkAQpoGg7C6JizTQT7CxPwOwFWgYPChYIXkIHC4uQKGAiKRKCyNpxxUUVViVYNFLkqtLo+DAkMMLXQPXwAy2WCTF4544FGtKuwPDhB6DnxuUmyCcXIQhV1uYoMuEAcOBxEKCHg6TzGFCJUSizuejROKOAM9OY2SnUU7nD89NCcDsLUnIQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 connect_no-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBPz+BMTCBERCBAQCBPz+/MTCxOTi5Nze3OTm5Ly6vNza3ISChFxaXKSipAAAACH5BAEAAAAALAAAAAAWABYAAARiEMhJq7046827/+AVCKE0Dh9BAGdaGISAToFGFMcBU+11I4hDYseSZQiKwwKoI/QwBIYiuFDCZseGdIlYEjUNg1SpY6w2N4cUIW6cjwW1lsFwo+MqgtZuw0/ydw5vH34lBhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== contents2-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBDyGhCyCfFSWlESOjDyKjDSGhCx+fGSinGSenFyanEySjHSqpHSqrGympEySlBx2dISytHyyrCR6dKTGxHyurHSurHyytGSipCR6fARmZFSalEyWlBRubAxubBRydDyKhDSChLSytPz+/MzKzIyOjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAbFQIBwSCwaj8ikMhBQIpmCQdM5ZBIKhgNiugwkFAsCI7pNMhuOxkNBgBgEiAi3GkBLJpJHYgEpaClyREwVFhcSEhgOGQoMfgMaERtcARQBFRMYExZ6HB0FUYAekkIBHxqWFmlrC1haESAfG6MBGx+VFRgKYH0hInGRklO0ppYXCwwMWQiQHkwjgrWnFRdYZHIBJCTP0LaWGAcDW9jZ2nMAw9IWTOQkJSZMRsOV49nu8E+19PbmR7TY+1TovONH5V7Ag0QMBAEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== contents-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAAQCBAQ2NPwCBHSurIS2tBx2dBweHPz+/Ozm1GxiTGyqpPz6/Pz69GSqpOzaxPzy5HxuVLSmlOTazPz27PT29NzClPTexHxuXLSmjAxqbFSinPTy9KyehNy+lPTy5Pz29HxyXNzWxKSahOzexPzy7IR2ZOTWtESenPTy7KSWfIyCbKyijAQGBDyalPTu3KSSdDSOjJyOdCSGhPzu3OzizJSGdPTq1PTq3JySdMy6lAyKhOzWtOzi1OTOrJyKbMS2nJySfMS+rAwCBNzOrNTCpNzKpJSGZKyafLSifLyylIx+ZHx6ZDSChAQuLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAIALAAAAAAWABYAAAf/gAABAoSFhoeHAAMAiI2IAAQFjI6EAAaJkQeTjwAICYkKBQcLm5WdBwyfhgChB66bp64HCQC1lQ2irqQCAA4PowsLEBESE4wAuLIHFAAVFr+uDBcYxRm1GrmuGxwdFh4Mrh8gGCET1gDYyhsiFSMkDAsMDCUYJhvnJ9kHKCnODwwfPlBQsULCPRYAWogK9sHFiwoOPEyQh0JFPXO1YBSYwBEFghjdHkwQOYGgwQwIZRR44GHGDBogabhAsYEEihrUMAIoUMCEDRs3HODIYQHFA6MPcJA7KICFjgw7eIzo4cOfiwc/gKwIUm2SkKdDdlDt4AABDaU/iIRwwbTSUyJFOow4S3Hkx9oNDDZgXPU0h1wcSIgEGUw4ibVET5WoWMKksePHpdxmyKADAEIWly9HJtQkQJMmlAgZCAQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== contexthelp-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIEAAPwCBAQCBAQChAAAACH5BAEAAAAALAAAAAAWABYAAAJQhI8Qy5F/ghBsLuOgpHHy+0hZ94HINiqWwoQrtjYpNqJ0A8Hcjbs73yPNZEHVDygTJohJWqiZe0JPM5ajtXxFMkXnklqNgsPiWzmHPatzhgIAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== crop-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBAQCBMT+xASyBASCBASaBISChMTCxPz+/AAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARUEMhJq704681r+EFHBcIwEKFImmfKkURhoh1cyO0rxEWZa7bezIUJ7gg04O62A22MyeeyF1XymrUSs5pZmbA61u+FLBOBhrThozq4D2cgYo6IawwRACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= decrypted-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBGxqbFxaXExOTEQ+RAQCBPz+/PTy9Ozq7Nza3NTS1KSipFRSVOTi5Hx2fJSSlKyqrJyenJyWnDw6PMzKzKyurDQyNFxWXMTCxJyanHRuLHxuLGReJFxSLFROJFxWJExCHERCHBQODISChHxyLHRqNIRyNHRmLLSqbKyiZLy6fOTarPz67Pzy3OzitKymZFxSJJySTNTSnPTy3NzSpMTChLSydKyqbKSaXJySVIyGRGReLPz23NTOnMzCjHxuPLy2vKSmpOTe5LS2tLSutHxuNHRuPMS+xFxWLIR+RDw2HFRKJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4SDAQIDBAUChY2EAQYHCAkKCwyOjZANDgIEAQoPjJiDAg2iggQQp5gMBwmrDBESl6MTFKuoFQSjABYRF40CGAW8BRm7hQwNxBobHB0eHx4gISIjBdiEAhYFJBslHOHSHh4hBSHlxIUmJygpKissBiwtLi8pGjDqhBoxMjMuaNSwcSMFjhw6dnjYRyrGCh4ueviw4Q5HDB0/PjAUJCBCAwMIGiiggAEIBFk/FgYLIgRkggQkhxAJkqGExkYMFnxsIGRkSQgLHhRRWUjAggQgG8AsSWRBBiP6VrYMOfKIyaBDNwLo+HHSUplOSyDRqiEHjRkretRQkcLgxayNF0wksQGQxsSKMTIq0QpgCba/gAE7whEIACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= down-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAw2VCRKZDRSbBxCXJTC1Mzi7Nzq9NTm9Bx2nAQCBNzu9JzG3Hy+1HzG3IzO5BRmjPz6/LTe7Dy61AyStCTC1FzC1AyGrETS3ETC1ETa5BRulAyuzBRylAw+XMTe7Gy+3CSqzAyexBTC3DR+nIS21KTW5Nzu/KzO3FzC3Pz+/ByixEze7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAaRQIBwSCwaj8ikcnkMBAQDgjPAFAYKhsMBkVBUAYEFo+F4QLzVQEQyoVTOX/XBcsHA0+vMRbNBMwkRDhxuHX5GTlIeHh8gISIjFAEeiVRECiQlDAUmgxQjIhwiJHdFlycoKSIUFCEjGiGkRpcqCxYijxorsUezcxYsuoZJsxLAu0qXB7DCTJfHVQrMX9PU1Uh0QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 editclear-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIEAAPwCBAQCBPz+/ISChCH5BAEAAAAALAAAAAAWABYAAAJBhI+py+0PYZi0WnqC2Lx7HhjaR3YhMArBUHpnuramCLLy9tY3TuP2nfPtVD3VTxY0DpNDHqo5E12mlYj1is1e7QUAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== editcopy-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBBQSFPz+/DQyNISChDw6PMzKzMTGxERGRIyKjFxaXMTCvKSmpHR2dPz6/Pz29PTq3MS2rPz69MTCxFxWVHx6dJyWjNzSzPz27Pzy7Pzu5PTm3NTKvIR+fJyGfHxuZHxqXNTCtPTq5PTi1PTezNS+rExOTFRORMyylPTaxOzWxOzSvNze3NTOxMy2nMyulMyqjAQCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAbYQIBwSCwahYGkUnk0BgTQ6IAQaBKfUWhBYKhaAU+CgXAQIAyChLeJzSIQhcH6GFaM0QtGY5kstqEODw8QEQELAhJTc08KBBMEFBUWDRcBE1pca20SGBkaEBscAY5maFRIAgoLHRQRHh8gIQFlZnByqA8ZGSIQIyQjJQEmYgJ5p2ACrK4gJx4gKIZZAgdeAQ4ZI9kjKSor0AwEjeAs1S0cHAslLi4vMDDRWeRIfEsxMeET4ATyVoYLC5fizXEiAR84BeMG+pEm8EsAFhAjSlR4hR6fLxiF0AkCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= editcut-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBAQCBAwCBPz+/OTi5JyanOzq7DQyNGxqbAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARbEMhJq704gxBE0Bf3cZo4kRJqBQNRfBucyudgvJS6VaxLzyMa6/bLiWA9HOg4VIIkL5vzuRkcpkvRIIAorphJLzBW84WEuRZWp6uaT7J2Sh1Hit3OY/ZO7WvsEQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 editdelete-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAASC/FRSVExKTERCRDw6PDQyNCwuLBweHBwaHAwODAwKDAQCBExOTNze3NTW1MTGxLS2tJyanPz+/Ozu7BQSFCwqLDw+POTi5PTu7MzKxIR+fCQmJPz6/Oze1NTGvPz69Pzy7Pz29LyyrPy+vPyupPTm1BQWFIQCBPwCBMS6rPzSzNTOxPTi1NS+rPTezNzOxPTizOzWxMy2pOzaxMy2nPTaxOzOtMyynOzSvMyqjPx+fOzGpMSihPTq3OzKrOTCpNzKxNTCtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf8gACCAQIDBAUGBwgJCgsLgpCRAAwNlZYODxALEY+SkAMNEqKjEw0UD5yegqCjrRMVEqidkgWhraMWF7GptLa3EgEWFRSOnhW+vxgZEBqzkBvItxwdHryRCNGjHyAhHSLOgtgSI60c2yQjJd+eJqEnKK0hJCgnJSngAO0SF+8qEvL0VrBogW+BLX4oVKgIyMIFQU8KfDV4R+8FDBcxZBREthAFiRIsOsygsVEUh4Un3pGoUcPGjZInK65QicPlxg8oX5RwqNJGjo0hdJwQ6EIkjRM6dvDYCKIHSBc1Ztjw4eOH0oIrsgIJEqSFDBo0cuTgsdSTo7No0xYTZCcQACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= edit-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBISGhISChHx+fHx6fHR2dGxqbGxubGRmZGRiZFxeXFxaXFRSVIxSLPyuXMzKzMzKxMTCtExOTPzqrPz+/NTS1MS+tOSaVPyWNPz6/IxeNPzavPyKBNTW1PyCBPyGBJxmNPzOpLx6PNRqBMSCRNySTPyCDPSGBMxiBKROBHRydPSylOyydMxmBJxKBAwODPS2lPTq3OyabJxGBPTy5PTGrOyOXPR+DPz69PzmzPzevNxuPORqLMReFPzy7MyCXKxiNIRKHBQWFNTOxPzixJRaPFxONHRqVPz27PTy7PzStCwqJDQyLJSGdIx6ZPz29PTu5HRmTLSKbMSGZHROPFxKPJSKfJyShKyehMyuhDQmHEQuJJyOfLSijMSynMS6pLSefDQyNHx2bKSahLyqhLymhOzi1FRGNIR+bNzKtOTOtOTKrOTKpLyedAQCBFRWVPTq5NzOvLyunLSmlNTCrOTOrNzGrLyidMS+rLyynKyijLymjLyqjAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gAAAAQECAwQFBQYHBggJCgsLDAwADQ6CAQ8QD5ydEJ+gERKWE4ICDxSpqhWqqhYNFxMYphCtqaytGRoXGxgcggSoth25u70eH8APFR0VzMzNziAXIRjIvwAFwq3EqSLUGB/iI4LathS4JCXVJh8nKCmCKrXDFCss1eIfLS4v8ssdmgWsAGNDDBnt3s3wJ+jAtlUhaNSwccNEi4WCBBl4SAHHihw6ZOzg0QNjRgAG6KXK4CNEjBU/gDQI8kLISQAIADobAoMIzCINjLw4YvNkAno4kCRRUuNHESNLmDRxUjSjAlRPfECJImUKlSpMrFzBIqWqoKtJaWSJomULAy5XXrp4+QKGYcYFoCBEWRImi5gmY7CQyVLGriAGD2jEMHMmCxc0Xb6kUbOGTRs3N988gLM4jpw5Y+iwqcOGjZ07mE8yiGABz5c8c/Ts4cOnDJkybS7fdMO7t+/fvDMaCAQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== editpaste-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBBQWFDw6FHRuFGRaBFxSBAQCBAQKBCQiBIx6HPz6/NTOfKyiXDQuFOTm5Pz+/Ozu7PTq5Pz63PTyxNTOjKSeRExGLMTGxMzKzNTS1NTW1Dw2NKSmpKyqrKSipJyanNzWlLy6ZLSuVIx6FISChIyKhJSSlCQiJLS2tDw6NDQyNCQiFCQmHBQSDGRiZHRydGxubHx6dGxqbFxeXGRmZFxaXCwuLOzq7KyurHx+fDwmFEQuFCweFCQWDBQODBwaHBweHKSinJSWlOTi5JyepHR2dDw6PBQSFNze3ERGRIyKjIyOjISGhPz29Pzy7MS2rMzOzFRWVHx2dHxybDQiFPz27Pzu5PTq3PTm1NTCtJyGdHxuZHxqXPzq3PTaxNS6pFxWVFRKRNS2nPTi1PTStNSulNzOxNSynMymhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCgwABAgMEBYSLggaOjgcICQoLDA2Pj4MGDg8QEZ4FDxITFBUWFxcYGRobjQ8cHR4fCQ8gCyEiFSMWJCUkJieNEB4dKB4pKissK8wrLS4vMDHBAAYQHx8dFx0fJDIzNDU0M+IyHzaNNyg43Ng5Ojs7Ojw9Pj9AMkCNDiZB/h9CSOx4QLCgihItqBkYgqIDESElitAYWJCgkQcXjjRCgi1Ihw4BB5LAQOLCgyQYHihpUU3DBw5ElpAgAYNixSRJjKjQaECDCRPZPDB5IbIGSQwKLnh4wbInLA4kmJB4oaPiAwVNnER40hRK1BIAaVatUZJEFCkmpmjgCeWDCalFe4q4oFKwSRUrEa5gycLzwq8lUnPQ4PEgSpYcUZ5o2cIlS1O/JHLEDdfjQZMIVrpgweLFy5e+M6WSmBGlxYMYYBRzCaOFi5imHWBIfOEiShLTVjaP6eyFTBmN1TA5OvLDjJksWb58OVMGDRqWjAYdmU79SIvpjqJr104nEAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 editshred-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBFRSVExKTERCRDw6PDQyNCwuLBweHBwaHAwODAwKDAQCBExOTNze3NTW1MTGxLS2tJyanOze1Pz+/Ozu7BQSFCwqLDw+POTi5MzKxPTu7LyyrIR+fCQmJPz6/Pz69Pzy7Pz29OzaxPTu5PTq3PTm3My6pPzu5PTq5NS+rPTm1PTi1PTezOzWxPz27MyynOzSvMyulOzOtOzKrMymhOzGpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAbpQIAwIBgMCAXDAZFQLBbCqJTRqFobjgdkEYFKowPJZEyeUBqVR/crHDTKZYplovZKCW84+YKZZNZSBXl6EwEEBhVPXxZihGMaGRscdkIdg4QeEnVfCH2OHyAhIhuUAAiXZSEhIyQlJqWnjiEnKCWupRWoYyEgJK0SKaUKjam0JCorLMFfC6iqx8giLa/MGAsT1wsuCyULKwssC9RSzdkfCyALKuALLQsvpeXYIQso3gsiCzALMfENC+dGcMNHUAY/f+jq3ctncMYCGggFrsvHcEGNh/EyPFmg8cmrJxAVkVO0EUDJklHoBAEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== edittrash-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBERGRExOTDQyNISChBQSFCQiJCwuLPT29Nze3GxqbDw6PGxubHR2dJyanLSytJSWlJSSlOzq7Pz6/Nza3Ly6vFRWVBQWFIyKjMTCxHx6fIyOjLS2tOTi5PTy9OTm5Hx+fNTW1KyurKSmpJyenExKTMzKzKSipFxeXCwqLMzOzKyqrMTGxLy+vHRydBwaHNTS1DQ2NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAb8QIBwSCwaj8KAMoA8LgUDQsFwQByay4RiwWg4GA9IRGk0SCYJSsUCsVwwGQ1EsmESD5xOp+L5gDwhBRIZDhcDdkMGDgEiIxAkJQ8Ok5MmAohDAQ1xJxUlKCUlEg0pKpiZJRoLCxmtCw1eURhOcR4rbQ8cGRwLAwgGtBYTDywtGRKjvQTARgEZLhMcKC0OrQMvAirMRc7CHCTU1g2+20TO0NIn1RwDCya/wdHT1Rnt5LToKOq79trx0tR02YPX7Jm8fRxMOIhSLhOJE/LCJSTlr5kFEBQsWDiR4UGGBgsuHDg1BEYAfTE6oEBR4AIBAiS5yWBAAAGBAyaPGAgCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= encrypted-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBHRudFxaXExGTERCRAwGDGxubPz+/Pz2/Ozm7Nza3NTS1KympFRSVHR2dNTO1JSSlKyqrKSipDQyNMTGxDw+PLSutKymrMTCxAQCBHRqLBQODJyanDQuFFxSJFRSJFRGJERCHExCHISChHxyLEQ6HGRaJExKHLSmbLy2fOzitPz23KSiZHxuNHxyNJSOTNTOnMTCjLSudKSaXJSKRJyOTOTetNzWpHxuPOTi5MzKzLS2tFxWXOzq7Ly6vOTe5Ix+RLSqdNzSpLyydKyqbKyiZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4IBAgMEBQKEjI0GBwgJCgsMDY2XjwkOAgQBDxCLl4QNCaGCBBGWooINCAqqrBKgqwATFKaDFRYVtBMXsIMNGBm0GRADjQIJxKIaGxwdHh8gISIhGyMZzIwkGholJiYfJiAfJyEZISDbg90oKCkqKwcHKyooLC0f7IIuLzD2YMSQgW8GDRri+AFoUMOGvRsxUhSsQQPHvmQSchyQtEAHhh0WJHDQcJERjwsKDvRI0BGDjwgicXhQyCOjSgUKPO6AObIkIQESfmxk6REDT4s0bfaYpDNkT4VAha5s+TLmzEYtatwIOHAiDZIKNQAJYk9IjCFEisyoocFEB4UACtBpm0t3LiEsgQAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== eraser-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBMTC/AQChAQCBISC/PzCxPz+/MQCBIQCBAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARfEMhJKwhi2F0DIRnHeR+oiRRZmqikrmD7wgI6r+EI4+d2l7lNwWDYsTiFw4FI61mSymXxE3xGo8xqBXpVGrQUbveAcG7H0bKowEar12wx2SyMp+lI+7s1ie/5fX8tBhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== exec-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBAwKDAwKBCQiHNze3AQCBBwWFDw6NPTy9PTy/Dw2NKyytOTi3LS2tMTKzMzOxLy+tLy+vBQODNze5NTS1JyalIyCbIx6VIRyVISGfJyelOTq7EQ+NMTGxKyurGxeRLyKPOSmROSuVOy2XOSiTLzCzNTOzDw+NCwqLHxuVOy6bPzGfOSuXNTW1LSyrMSWRNymTOSmTKSCTPTGjPzSnPzWnMyaVBQSDMTCxPz+/KyahNSeRHxeLJRyTPzmtPzarOy6fJyajNza1Ly6vLyulFRCJPzirPTOlMS2pNTSzMTCvJyenBQWFNzKtPz6vPzyvPzqtOzGlOTe1AwGBFxWTLy6tPTm1PzSpPzutPz2xPTSnOTSxOy2dPzapPzerOzm5IR+dPzu5Pzu1PzqxPzy5Pz+9GRiXGxuZKympHR2bOTm5Pz6/MzSzBwaFJSSjCQmHPz2/AwODAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4SFhoeEAQKIjIIDBAQDjYMFBoMHCAkKgwYFhwULDAUKCg0ODxCkBQgRnoUSExMUDxUWFxgZGpAbFIuGHB0eHyAhIiMkIB8lJieIKCUpJCTGIyorLCktKIUDpC4YLzAxIjIyMzQ1NhgdpJI3ODktJTowOyM8Ejc9Pj9AQUIEclAocCMIBQhDiOwgoaKIoCI+jBxBkkSJkCWemIyq0GSHCBVHihRx8gRKFCmpKhGaQqWKFYZXsGR5kkXLFgRUXBUqkCGCFS5AjnTx0sXKlyA6CRVgAAHMAilhxIwhU6ZFkBY5kgKYUoXBAzMKzixZ4AJNGgVm1KxhM0WpmQpUMtooaOPGxAM3Nw60oYLGjNYCbzYJOgAnRzNBJ95oPYQCgpJtkwzFoULlRuRPiy9fNhAIACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= exit-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIEAAPwCBAQCBHR2dDQyNCH5BAEAAAAALAAAAAAWABYAAAJOhI+py90RnIMyRUOxhDfzJkACdoXBuEDDkQFDi5go0MrKx16kns80b7qdELCgBYaEGWwL5nG1ePFiKp9A6kuYRNuho8vxVrrZivmMRtMLACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= fileclose-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBERGRERCRDw6PCwqLExOTFRWVHRydGxqbGRiZCQiJISChIyKjHx6fDQyNBwaHJSWlKSipBQWFJyanPz+/JSSlCQmJAwKDCwuLBweHBQSFGxubExKTISGhDQ2NFxeXFRSVDw+PAwODAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAbZQIBwSCwaj8jkMSAYDAgEJbFgOBwQCUOAoJAaFgvGonHIBhyP5BcSgUAYDWxggD4WFmx3e3HQngkSRgYMEBMUFG4MCId0BGlEAQeEhocVDYcUdBYKF0QCB3gRlJgUAQEYBBkaRAMbDZMMpAYcT46rQwMJrgsdC6QcfwoPnUMOBgkIV6SHHg6bw0QEAQYfBpggBZjPGsRD0gEchxwCIR6HChnQRQ8DIU4DTR4Em+ncRw8O+fmoXPXdRg+gQLFgIYM/KRIkoDP4QMKFf0o0aBAh4qGUixgzCrETBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 filefind-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBBQSFJyanLS6vLzCxISChNTe3OTu9Oz6/Nzy9Nzy/NTy/OT2/Nzi5Mzu9Lzq9KTe7LTq9PT+/Pz+/Nz2/Mzu/Kzm9Jza5HzK1LTi9PTu9IzW5ITO3FxaXNT2/KTi7Iza7GzC1LzW3FRSVMzO1MTq7HTS3Fy6zFS2vKzm7Lze5MTGzHzS5FTG1Ey2xEyyvJze7JzW3ITa5FTK3EymrGS+zFxWXKymrMzi7ESirEyqvLSyrKze7MzOzMTCxKSepAz+/NzW3MzKzBwWHLzS3ERCRAzi3KyurNze3MzGzLy2vLSutCQiJAyytHRydOTe5MTGxLy6tLyqpKyelJSCdOze3NS+tLyupLSmnKSOhCwuLPzy9Pzu7Oze1OzazOTOvMyihOTi5PTm3Pzi1PTazPTWxOzOtNSunDQyNPzy7Pzu5OzKrNzSzNzGvNS6rMyynMymjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCgwGFhYOIiYQBAgMEAwKHiokBBQYHCAkKCwwFAZOEBQ0IDAsODxARCZ6gAAEGEhMSFBUWFxgZCJ+TjBoMEpkRERscGBGRih0BBAgeFBQOER8gISEfIruIIwEkCCUVwhcgJicoKSrZg9srCRkRGdMsLS4vMNiK2wIKMRsbMiwzXtCocSydIBs3AuCIwIFDiBMucugAoWvSiB2VNPDg0ELHwA0MkCXr4aNSggg8NoDIQOFHgBtAkgURMiDAEAFEVBCJFKCIkSMGOyDRkETJEkOFmABoUsRJQkQdnkzQACWKlBtTplBR6qopxkFRJ0ytYuWKFCxZtBBq+hRA2AlbRrh08fLlCxi1a51g+dQhDFwuYsaQKWPmDBpKXgNETaNGjJgyhNfcVdTTiWI2XpK0cePmzRk4YA5T5otGixY0qFOXbgXAQCAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== filenew-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBExOTERCRDw6PCwuLBwaHAwODAQCBOze1NTW1OTi5Nze3MTGxLS2tJyanPz+/Ozu7OTi3BQSFCwqLDw+PDQyNFRSVPTu7MzKxLyyrIR+fCQmJPz6/NTOxPz69Pzy7PTu5Pz29Pzu5PTq5PTm1My6pBQWFPTq3PTm3NS+rAwKDPTi1PTezOzWxMy2pPz27PTazOzSvMyynOzaxOzOtPTaxOzKrMyqjOzGpMymhPTizOTCpNzSzNTGvMymjMSihCH5BAEAAAAALAAAAAAWABYAAAboQIBwSCwaiYGAYEAgFAqGg/Q4DCASCsTiymgcHAcqQLB4mM+QiIQBppLPcMjkwQ4bB2X4maKgt4sVCHpnFhQTElNFE3mDDxcYGRp2RBuMgxwIHX9EBZZwHh8gCBmTQ52NISEiIyQlpUImng8hHyInKAgprwAqgnC0IKwrLLpGB4wctLYkwy0uuwd9Z8AnJywsLcVFx2YcL7UnJCwwLTEy0GXJoSgrCCwzNDTnxgjeH9UrKzXwNDY36LRGhEOwLx4NHDmgJbh3QoeOgv127EhojEeHDj16pEhRQoZHHzl+QJNCsqTJSXaCAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 fileopen-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBAQCBCQWDCwaDDwmFPSubPzGhPzCfPy2dOSmZPzKlPzSnPzOlPzKjBQODPzChPzWnPy2bPSmXPyuZOyeXIRSLEQuFEwyHEQqFDQiFCweDKRuPFRSTPT29PTy9Ozq7OTi3Nze3NTW1MzOzMTGxMTCxLy6tLSytKyurDQyNMzKxOTm5OTi5Nza1NTS1MTCvLS2tLSyrKSmpJyenJSWlIyKjHx+fFxeXBwaHKxuPMzKzLy6vIyOjHx6fDw6NPy6dGxubLy+vISChCQmJNza3KyqrBQSFLR2RKSinJyanGxqZAwGBJSSlCwqLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4SFhoeDAYqKiIeLj4wBjQCMhY+NkoiLk5qbhQIDoJyGBAUGBwgEo4MECQoLDA2pDrS1tKQPEAwHERITE77AvxKqhAQNDA8UFRYXFs8YBAQZGqGPxw0RGxwdHR4eHyAhIiMkJSYnKCgpBAYPEhcqHyssLS4kLzAxMjM0NTY3cBA4UCAHBw8gVnhgEcKFjhc7UPDj0cMHAAI/KFgY4YLFio/jRpTYsW8GDyCSCEQw2DChOHIqgsCQSEPIEEEEJFhAoUNECCJEyOk4d6KIyRtGcB7hIJKjixEjHu4oimSGEIs4d8IIUoKECnNB0ElMwkNJJgBLlJBAcQKGiR07KGAURVGViY0mhIwwSTKjr99+THjUoIg0r48hTRIrRtxkiOMhDgrZCQQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== fileprint-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBFxaXDQyNFxSTPTizOzi1FxORDw2NExKLPTi1Pzy9Pz6/FRWVPz29Pz2/PTy7PTu9OzezPzu5OzavAQCBPzy7PTm3OzazOzKrPTu5FxSRERCRGReXPTq5Pzu7ExGTMS+xKSmpOTKpPTq3JSCDNzSfHRydLyadOzCjOzOtOzSvLyyTMTCxKSipGRiZFROLPz+/KyurJyenJyWnGxmbLSabOzClOzm7LSutJSWlJSSlJyanGxqbNze3OTm5IyGjNTO1Nza3NzW3OTe5IyKjHx6fMzGzMTGxMzOzNTW1IR+hISGhKymrLy6vLSytERGRGxubKyqrLy2vLS2tDQ2NEQ+RASKBAT+BFxeXHRudAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4QBAgOEiYqEAgQFBgcGi5MICQoLmAQDh5OEDA2YCw4ODxARApKUCaGYEAsSCRMUnQysCwoVEhYXGLOLCBCgDqK5GQUXGooCAhscBB0euBUZEAUJvQgIgx8gIR8iCSPiHuIFEREDJCXaANwhJhsnKCnWERcRKiopFCvsBywhQrRwQWGAPAz5EhpQ9wIABRgKYsiYMTEEDQocatiwkUIEP18fbkCAAcMBjhwzdOyQwYNCgBMfKJSgMItBjxs+btwgCSGGjhw/ZoRgQKGZCRMUPgABEgSIkCE3SZok8qNqkR85NtDUEcPIkaVAkCR5SrJBDCVKlmzQ6pCCiRlMTJo4YUH3K5AeMBYYWctW0BOaUH60cBJFypQmII6wyEpFQBVFMSm4UAI3hJUrOGh8oOJrklYKWIromJGDR99Ogz5j4ZGlM+pEnwmBCwQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== filesave-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBGxqbAQCBLy+vERCRExKTHRydIyKjMTCxFxaXGRiZFRSVFRWVPz6/Nze3Nzm5Pz+/JyanDw+PExOTHR2dMTGxBQWFLSytHx+fISChOzy9Ly6vAQGBJSWlMzKzAwODJSSlHx6fIyOjOTi5DQ2NISGhGxubCwuLOzq7ERGRFxeXNTW1CwqLPT29Dw6PGRmZKSmpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAb/QIBQGBAMj8ikUDAgFAzKKCBwQCQUCcICKh0SEAhGw5EIZAmBrgCxeDQgcDJWyz0GIggJfL+XGwQJRxNgC3yGDwwUFUZDFhdthnwMGAZNQwEZFwQakXANBBQbHIIdERIBnRAOiR4ERx8gsSEMBBmGCyEGG3YGBwcgIr8UCwQHECOgG4xCtRkEJAvBJRklJgkSFBQeJ68hJiEoESkFKiEZIbkGARsLlwEGExENGhorGSkpFAYm66NDLAECpGiBYsUIFA8wLHBBQMWLVkdUCFCwaYVFBOymkVCgYEMgOykEpICBccMBAhhELFigTEqAAgIIwCiQ4eRKDyS6EAlJIAI0EpaudF4iIKDAAn9CkRT5eMROEAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 fill-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIMAAASC/AQCBMT+xASCBMQCBASaBPyChASyBATCBPwCBARmBAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAASCEMhJq704axB2DkLnVeAwiCNHDMWZcsbaul5ZyCaKBcZwFDcgDRNbHX7AmW4SMx2MSOFQQlitEAhosrVcDQQE7NMXzVGqA6xAgCUckabQpJoIYBFsxBspUKBiHQEHaoNvBQJTgBIBdnh5B4hLihONeJBTc0uMaphMS4uRGQYfny9EEQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 filter-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIQAAPwCBAQCBAwKDMzKzMTGxNTS1MzOzAQGBLS2tLy+vKyqrLSytLy6vMTCxBQWFKyurCQmJBweHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAV7ICCOZGmeaHoGbKuOAjsQhVG764EgyT7YhaCBVQogFMhFImEABoUBknFxRDAazac2Kg00djystkA0sQ4BgzgYK6+Ch/bBseOmAmMD4gF5ifBCDwoRfiOABgyEhYYFCA6LUo19kH+Nj5QAaQh2kHibmJkFBJydpKCnfnYhACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= find-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBBQSFJSWlFxaXJyanKy2tLzCxDw+PHyChNTa3Nzq7Nz29NTy9Mzu9OT29Nzi5Oz6/Mzy9Kzi7Jze5Lze5Nzy9JyenIyKjHR2dMTu9Kzm7JzW3ITW3ISChGxubERGROz+/Lzq9IzW5HzK1LTm7FRSVHTS3GS+zLTS1DQ2NMzOzMTq7Lzq7ITW5FS2vMTi5ExOTKTm7EzCzEy2vEyutJTa5FTK1ESirGy+zMzi5ESerESmtITa5OTy9KTe5KyqrAz+/Azi3ASutERCRExKTFRWVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCggGFhYOIAAIDiYUEBQYFAoeJAweKhAgJCgsLDA0OCAGJg4wBCA8QDhENEhMUFaKDFhcYgwEJCxAQDBkaGxwSFaMAFh0eAx8AAQIKECAODCEaIiMjJJMAtQMlygEGEBkVva4mJycTKKMYJd0pyyoOKyssGhMtIycuGi/EMB/vlhmoQEFDjHsmZMygUUMdqWUCGgCbYMKEjRk3cEjI9jBADg3Wzs3QsYOHA2IdO1SQkI/GjRMtFhBA2RFBDwk+OASrMPMHkIe3AhBA8QLFzAAHgvyg2dEQMSEHPCwltQgooSFSmVpSxKjjh6wPtwINgHVqsVpWESEFeywZ17RkED2s40YEgFirlIq4SwvUQCAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== finish-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAw2VAQCBBxCXDR+nIS21Aw+XJTC1Nzu/KzO3Pz+/Nzq9Pz6/MTe7KTW5FzC1Nzu9CRKZMzi7IzK3Lzi7LTe7HzG3Gy+3AyuzAyexFzC3DRSbHy+1Dy61CSqzAySvAyStLze7IzO5AyGrEze7BRmjCTC1ETS3ETa5BTC3Bx2nAyWvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAakQIBwSCwaj8hkMqBsBgTN5IAAJQqqykCBasUmDQcEV3gtBs7oATihGJeJgcOCQWc0HA8Ig/seRiQTFAsVFhcYGRp6VH1CGwscHQ8dGB4fIBkPIWKMAAMLIiAjIJcgH5gkGSWcARIiJicoJikpHikoHqqrKiW8JSogKymoqgCrV8cCARgkuFWcRwYeqVjPRgEExEPVRQbZ2l5IBuBRQ0zk5+hRBkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== folder_new-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBNzaTPT2FISCBCQaDPz+BExKBDwmFPSubPzChPzCfPy2dPz6BMzOTAQCBOSmZPzKlPzSnPzOlPzKjBQODPz+rPz+3PzWnPyuZPSmXNyaXPTyhISCLIRSLEQuFEwyHPy2bKRuPFRSTPT29PTy9Ozq7Pz+xJyanDQyNPzGhMzKzOTi3Nza3OTiVBQWFDwqFKxuPOTi5JSSjISChHR2dGRmZFxeXPS2dNTSzNTS1OTm5KSipLS2tLSytKyqpIyKhGRiZNze3NTW1MTGxMTCvLy6tIyKjCQmJMTCxMzOzMzKxJyenHx6fLR2RLy6vJSSlHx+fDw6NLy+vIyOjAwGBGxqZKyurCwuLBQSFJSWlCwqLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4SFhoeIiYqLjI2MAY6HAgOHBJYEhJCDBQaDmgcICQoLB4MGDA0OAQUBDg2cAAcPEBESE6QUuQasFRYVq5SxCRcSCggYGRjIGgYbFs8bHIMHExIJGR0eHx7cB83PFhsDDuTUEyAhIiMjJCQluwEmvsAnKAcp1x4qKyUrLLupWrByxcnFiwQIYIggEaNEiRgBZMyYQaNADRs2REA6cCODBxw5+OnQgWMHjx4+BND4MQOIg1gI0gUREkTHiplDhhApEoCGkRlHBL3I8MEHEhz+WAhJogTJySVMfthwIehAExE5jubAkYQpESc8fOx4AiXKNA8+ekhBgqSpzh5hPHcsmVLjpSAqVZBY6VGkiJMiPQKLnTvjCiEsWU4o3nGC8YksMmT8YCmC6iAXKLRc2cz5yGYtR0JjKWQgEAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 forward-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAw2VAQCBBxCXDR+nIS21Aw+XJTC1Nzu/KzO3Pz+/Nzq9Pz6/MTe7KTW5FzC1Nzu9CRKZMzi7IzK3Lzi7LTe7HzG3Gy+3AyuzAyexFzC3DRSbHy+1Dy61CSqzAySvAyStLze7IzO5AyGrETa5ByixBRmjCTC1ETS3BTC3Bx2nAyWvEze7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAaYQIBwSCwaj8hkMqBsBgTN5IAAjRoDBaq1aDggtMuAWDzoJhTgY+CwYLgZDccDwkgXI5IJZVGxXDAZGnR2QxsLHB0PHRgeHyAZDyFfVUQDCyIgIyCPIB+QJCUmlEMBEiInKCQnKSkeKSQeomoqJrUmKiArKSwZsmoCwMEBGCyxo1EGHr3HUQEEvltCBtDRAAbMW0zV29xDBkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== frac-22:actions actions22 22:photo:22 22:R0lGODlhFwAWAIIAAPwCBAQCBAwODAwKDAQGBIQChAAAAAAAACH5BAEAAAAALAAAAAAXABYAAANICLrc/iwEJSEUQA45LcOKMHWeU5XWiUYZsZClOIjj+naqrS9F7/9A326YCYBypREOpMPBVifjkBRw7SpIG+eJIg2IWC5UikoAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= frameprint-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBFxaXDQyNFxSTPTizOzi1FxORDw2NExKLPTi1Pzy9Pz6/FRWVPz29Pz2/PTu9PTu5OzezPzu5OzavAQCBPzy7PTm3OzazOzOtPTu7ERCRGReXPzu7PTq5OzKrExGTMS+xKSmpOTKpPTq3JSCDNzSfHRydLyadOzCjOzSvLyyTMTCxKSipGxmbOzClFROLPz+/LSutJSWlJyWnOzm7JSSlJyenOTe5OTi5MzKzASKBAT+BNzW3OTm5KyurMzGzMTGxMzOzNTW1KyqrLy2vERGRGxubIyGjLSytGRiZISChAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4QBAgOEiYqEAgQFBgcGi5MICQoLmAQDh5OEDA2YCw4LDxARApKUCaGYDwsSCRMUnQysCxUKEhYXGLOLCBCgow4VEhkFF6mMAhobBRAcChUVGR0FCR4UCAiDHyAhHyIJCRAjHOUJEREDJCXcAN4hJhonKBjXESn5Kdkq7wcrQoRg0YLCgBMuRFxIwTCFgXYvAFCA0SCGjBkYQxQMUE8EBhEUVPj6QOMBDBgLLM6oYYMFhYkvYcSkwOAGDho3TyqIUaPGyZ9AKXzIoWMHDx44bvQ4+WAi0KA1fPwAEiTIjyBCkDp9KlMiBRMzhhAhsqLsD64/fQEo8tLIERZIH8Ru5arow8skSmTMDdpJQ0y0XTsJ2gtU8GCZMBMbCAQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== funct-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAI+hI+py+0PIwhUohpMXfl6103h1nTUNproEU6am62v1pLsPX/siO9Jiou9TD2XyHfMGUs65aVmiUqn1CrCUAAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== gear-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBBQSFCQiJERGRBwaHFxeXHx+fDw+PGRmZExOTGxubKSipDQyNHx6fIyKjJSSlJyanISGhISChLS2tIyOjHR2dAwKDAQGBJyenAQCBCwqLLy+vKyqrAwODMTGxKyurFRWVLSytLy6vMTCxMzOzGRiZNTW1CwuLMzKzFxaXJSWlOTm5Nze3Ozu7OTi5Ozq7GxqbDw6PHRydAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAb/QIBwSBwGBMVkMjAgFAwHBFJpPB4SiQJCsWAQqEJB4prdNhQNx7QYIFwLD0ikQZdMHgelOPGYULQVDg4QEAVfRAEBBwUTEE0WFwcYhAuNF0QDBQULDwwZGUIaEAuVGxgBRAIFEhwHHUQMCxwTHAVrAAwFFRwKFkQZsxseDqBDGXMSHwfFQiAhIiMeJApEBwcOcahDJcLSJCYcGkQKcRAnQhkF0SgmEykHXkObox8q1iEjKN8rENqYD7MmeBCmzwSLFS1I3AqzYIPDESS+sWCxgQMLEgOSJKjozeAKFyskCDigQFwSBhJMjDDhAlyLFyVA+dIzAUUKEi0eaNhAIg8YGiEMenkwASNDDBkLqRQAEEAkup9KDkEFgC4IACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= gohome-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBAQCBCQiJNze3ERCROTi5MzGzLy6vDw6PKyqrKyurBQSFGRiZGxqbGRmZISChEQ+RExKTExOTHRydDQyNOTe5FROVLSurCwqLMTCxPT29Pz6/LSutFxeXLyytLSytPz+/JSWlKympPTq7KSipNzW3BwaHHx6fKx2VJRWNHQmBFweDOzq7Ly+vNTW1JxWNLSajPTe1Ny6pKxWJNTS1IyOjJRmbPTi3OzKrNSSXMSGVHQiBHx+fJSSlPzy9IxOVOzWxOSyjNSCPLxeDJyWnIRGTOTGtMxmDLRWBHwqBIxGTLRSDDQuNNSunKxKBGwyNMSafMxqHMReDKRGDPTu9LxuPLxaDJQ+DIR+hGQqNIQyBGQiBNTO1EQKBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4QBAYSIiYQCAwQCiokEhwACBQYHBAiQhAiHlQYJCgkEC5uCkp8MDQ4NDwylmwgQlgQRERIEBBOkmxQVBgQWFwUFFxEEDLyJGAUZtQoFGhsFHLYdyoOVHsEf0SAbIAUex8mwlAUhtSIFG+3uIyTWvAIGJMEkJe76GyXbEeWUBJg4USKaBhQpVKzYoIFFiwYUBBJa8MAFCw0vYMSQMWOhBhoTKCQSUKMEiw02buDIoWOHBg0GeIhEFKAHDR8afgAJImSIioYliMws1MPkhiJGchxBkmTDCBo1hg4KQMTiBiUyhBxZ8pNFiR5MEtU0WqSJVidJNDyNKraHC5xPNKBEkTLlJ5WvUgWNvfikyhArV34+7ZEXQAAsB2iUyHLlihYtW0pwOYAFgyJDmDNr7jIIWiAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== goto-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIQAAPwCBBQSDAwODAQCBCwiHDQuJExCNFRCNAwGBDwuJEw+NFxKPBQODEQ6LFxOPEw6NCwmHDQmJBwaFCQaFEQ2LCQeFDwyJBwWFDwyLDQqJAwKBAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAWSICCOJBkEQqmWA1EYR4Gsq5Aoy2EYKU0yDcPCkSP4SgShw2FoDI6jQeNxYD6MUBFCEXxAelkRgxCRhEWQiW/wXE2CataAUmiXKo+Fwg6YWxQWfCQEAxckUgoYDRSCR4gKB4ZnFVwUCgUMZ30KCRQUhJpzBRQQjUcSnmyaM32mPgQNmZpRBwmSsxAZBBqzUa4iBiEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== help-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBCQuNBwiJAwiLAwaJAwSHAwSFIy+3ERynCw2PCQuPAwmPCxOZCxWdJzG3FSazBwmNAQKDAQGBDRmhBQyTDxujDR2rIy21AwWJDyGxCxmjAwmNDRihAQOFDxmhCxunBQWFAwaLCRahDR6rESGvDQ2PCRWdDRunDSGvCRSdAwWHCwuLDSOzHSmxDyKxBxCZBwqNHSu1DyOzAQSHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAahQIBwCAgIBAPCoGAgOoeBAyKhWCwYDUf0CX1AIhLiJEGpBLiAAaRxdgYsl7Ybk8igBZoN5xmAdDxoanp8HyANISF8EBsiXBMjJBolBEQmGHFoRScbKHIKDykqK5lFAZRCnyknTaROLA8tq61OChgtKqyzQgEYEJi6UC4vI3LAASkbMBPARAEBdszR0sACEaPSMTIQM8W6KzNl3bo0NOJDdEEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== int-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIIAAPwCBIQChAQCBBwaHAQGBAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAANJCLrc/iDAuYKlU0r8NHfXB24iEyrCIAjAynakQLQuDS+vrTcnI1M9HyaIykFOKwUhZ6zEWC5oU9GrRY+kkqdUiXCdWW74SzYkAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 leftjust-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAIihI+py+1vgpy0Tohzs1T7z3CiBJbQWJnqg4rre7jwTBtGAQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 locationbar_erase-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIEAAPwCBAQCBPz+/AAAACH5BAEAAAAALAAAAAAWABYAAAJChI+py+0PX5i0VmbzVboHPgmCJVoJJY5haR5VGsCa+6ZqZ2Sy95E2n0OVdi2A8EacIIS+YpC3WUIpi6kygs1qsYYCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= lock-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBHRudFxaXExGTERCRAwGDGxubPz+/Pz2/Ozm7Nza3NTS1KympFRSVHR2dNTO1JSSlKyqrKSipDQyNMTGxDw+PLSutKymrMTCxAQCBHRqLBQODJyanDQuFFxSJFRSJFRGJERCHExCHISChHxyLEQ6HGRaJExKHLSmbLy2fOzitPz23KSiZHxuNHxyNJSOTNTOnMTCjLSudKSaXJSKRJyOTOTetNzWpHxuPOTi5MzKzLS2tFxWXOzq7Ly6vOTe5Ix+RLSqdNzSpLyydKyqbKyiZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4IBAgMEBQKEjI0GBwgJCgsMDY2XjwkOAgQBDxCLl4QNCaGCBBGWooINCAqqrBKgqwATFKaDFRYVtBMXsIMNGBm0GRADjQIJxKIaGxwdHh8gISIhGyMZzIwkGholJiYfJiAfJyEZISDbg90oKCkqKwcHKyooLC0f7IIuLzD2YMSQgW8GDRri+AFoUMOGvRsxUhSsQQPHvmQSchyQtEAHhh0WJHDQcJERjwsKDvRI0BGDjwgicXhQyCOjSgUKPO6AObIkIQESfmxk6REDT4s0bfaYpDNkT4VAha5s+TLmzEYtatwIOHAiDZIKNQAJYk9IjCFEisyoocFEB4UACtBpm0t3LiF4gQAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== lsub-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIEAAPwCBAQCBIQChAAAACH5BAEAAAAALAAAAAAWABYAAAI9hI+pe+EPHTNhgjox04srn4CI2FgkZaaZurGd+5nRfAiCYVuJzfN6jbvdfrshEZE7ApNGXa+nZDaVVIOhAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 lsup-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIEAAPwCBIQChAQCBAAAACH5BAEAAAAALAAAAAAWABYAAAI5hI+pF2G9YpszKgcgtgtyuX2I44UcRYkM5qmWAMcyzAn1/eKRnfe7vuD9fEGgQlgkHo2JmRPpStgLACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= mail_forward-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIcAAJR6fIxydIxubIRqbIRmZHxeXHRaXHRWVGxSVGROTFxGRFxCRFQ+PEw6PEw2NEQuLPwCBJR2dLyijPTixPz69Pzq3Pzy3Pzu5PTu7Ozi1LyelOzavPz+/DwqLLyafPTmvPz67Pz29Pzy7LSWlPzmzPz6/LyajPTitOTSzMyurPz25PTatPTi3KyOjPzuxAwqVDQiJHxiZPTetKySlPzqvPz27BQ6bAwmTPTexLyinNzGxDRunPzy5KySjCQ+ZNzq9KTO7JzC3Nzq/Ozu/LzW7FSm1BR6vGSWvFyq1AyGxAxytAx6vBSKxAxSjMyujLSunES+5BSi1ByGvAQCBNzCrOTaxNTOvMS6rKyelCx6rBx6tBQKDOTWvPzu1PTq1OzezAQOHAxGdBROhAQGFPzy1NzOvIRqXLyynOzarPz21Jx2XPTWrLSShAw2XKSCbPzuzAwePAQCDPzyzPzqzPTmxOzWtAwGBKyObOTSrNzGrKyGbOzatEQyNKyCZOzWrOTGpNS2lCweHCQaHCQWFBwSFBQODAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABAALAAAAAAWABYAAAj/AAEEEDCAQAEDBxAkULCAQQMHDyBInBhBwgQKFSpY0HgBQwYNGzh0mDhRAAUPHziACEGBpYgRJDiUGEkSwoCQJk6opNASRQoOFETQJDkggwoOJlYApcCihQuVL2DUhBDjhIqjJmRwwDCDhswaNm5MjYHjKggOOU7o0CGTA9gdYknG2KCCBw8VJVL0uBgihAUfP+CSNGCjsI/DiBPbAMJBsEQbQYQM+UG5smUiRYw0jlvYxhEkSYyIHm1EyRLTTH40EZvAyZPOR4pAmU07ipIkUKQ0mQIhAZUqVq5gKXzkSBYtyLVEyd1ki8QFXLp4+WJFQowbYLJnD5NbzJiJCjaQnhnvpYwZM0/OPFlvQ/f3iQvQpBlvQc0aCWy4VKnCpY0Y5yQxgEYXZFjghgwZUOHGCW90YQEccUwloBwGyjAHHXUoSAMZb0xhx1QOoMHDHSfIwSEOdTjhAQ1d4MFbTQ6Q4MYacrzxhhx04JCHHhvQsMeLJPHRBxpr+LHCGnusgccfgKixQR1ATtTBlDDAEIggggxCCCGFbLGFHVFKZEdAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= mail_generic-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBDQyNCwqLCQiJBwaHBQSFAwKDAQCBDw6PPz+/Pz69Pz27PTy7PTy5PTu5PTu3PTu1PTq1PTqzOzmzPzuvOzitPTmvOzivAQGBDw+POzevPz67Pz25Pz23Pzy1PzyzPzqvOTavERCRKSilPz21OTevIR+ZExKTOTi3JyanLS2tPz6/Pz65KyihJSKbMS6lExOTNTW1JSWlJSKZMSylNTOrNTKpFRSVPz29MTCxPTmzKymjIyCdOTWxOzexOTWrBQWFFRWVOzu7MzKxJyalOzatLSulMzKtOzmxOTarFxaXKyqnPTmtIyGdIR+bOzetOzixBweHGRiZOzm3NzWzNzSrOTetGRmZOzizOTexOzm1JSKdGxqbHRydJySdHR2dOzapHx6fKyijOTixCwuLHx+fFxeXERGRDQ2NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4SFhoeIiYqLAQECjwORAwSUBZYFBpkHmwgJCgsMDA0OD6UQERITFBMVFhcVGBkangq1ChsLGxwcHQ0dHR4fICEGIiMSCbS3uLq8wCQUJSYGJygpKhQJKyvLLM4Nwi0uLwUwDQsxMtmeuQveHR8UMzQ1NgU3Dgo41jk6ns0cKOzgYaOHjx9AgjTAUUvIECLZNmxoUISHkSM9KiBJQkCJA4kKEoBQoWJJAiYtmjh5AmVCsCJRpHzckKCCySlUUvBYUqUHDysSPnxIEuXKA5pPRiRwxwFLFhRaIEDYUoEChCcDuECoOWKFuwW7nHkg4WELkw8/BHRRwESpt10dU8SSHevlRxIBX6C0WBE27q8GZMkKbTADjIAwYlb4GLMYShYoPTRo6FGiSJEKPyzMIFMmzJcvXbhwkSLFjJkbQW6cOHNGhAgEAdAsmk27tm0ABgIBACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= mail_get-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBBQ6bCQ+ZAwePKTC5Ozu/NTi9GSWvAwSJGSu3JS+5CR+rAQOHPTy/AyKzES23AwOHCw+bOTq/BR6xES+5AwmTBw6ZMTW9Ax6tByi1BRGdAw2XAQCBDQuNDRupKzS9FSm1BR2vBym3EzC7CSGxBROhNTW1Pz+/OTm5NTO1AQGFNzW3Ozq7Ozm7IyKjJyWnMzOzNzq9Nze3OTa5Ly6vCQiJGReZISChKyqrAwqVBRWlOTi5MS6xJSWlNza3OTe5Ly2vGxmbKymrIyGjMzGzISGhKSepCQmJDw6PHR2dJSOlPTy9MTGxLy+vLS2tMzKzLSutMTCxLSytKSipJyenKyurJyanCwqLCwmLCwuLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4IBhgIBA4SLjAABBAUGBwiNlY4FCQoLDJaNAQ0ODwsQnYwREhMUE5ylFYYRFhcYGRgaGxsDHJUdFR4SHyAhEyIjJCUcuo0cJr0nExihxgwoyYscKSnMHicOIw4lKissLdWDHC4vMCu9McYqMjMyNOUANTY3OPEoOTolDCszdrSgwaMcBxs9TMxYOCMHBx8zfPj48QNINQ5BbMBIIUShDIUoTAhR94PHPEEHbQwZckOGjBQviMxYUWQIDCMmdXE4gqRnkiFETAxR8iKFjJU2evZEdmLJkgJIbqS4wXJIUapImj5FtuSEVyRVV1IVi4RIChhEkLVAgcJHEqVwVJUmYdKkiRNkALMRecKECRG/ff8CEQJFCA5kMKJEoUHDCQ/HkB9LmWKECpUeyKoIMSLEyosen0OD7iH2xg1dV7BkqXGlBpbWNTq4Zn2khu0aAAwEAgAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 mail_replyall-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIcAAJR6fIxydIxubIRqbIRmZHxeXHRaXHRWVGxSVGROTFxGRFxCRFQ+PEw6PEw2NEQuLPwCBLyejPTixPz29PTu3Pzu5Pzy7Ozi1LyelPTavPz+/DwqLPz67PTetPz69ERCRLSWlPTmzPz6/OzexLyajPzqvDw+PDQ2NMyurDQiJPz23PTatJyenAQCBPTevPz25LSajOzq7HxiZPTexPz65JyanBQ6bKSmpBwuTOTi5OzaxBRCdHySvGRiZHx6fBQSFERGRNzq9IyOjHx+fGxqbPzu3BwaHFSq3Aw6XAxKfPzy3Gy63ByWzJzO7Mzi9OzavBRytAx6vCSazGRKTPzy1AQKHBRGdBRyrDy63ES+3Cym1CR6rBwWVAQSLAx+xCyCtBRmnPzuzAQWLAwePPzyzKSCbAQOJByGvOTWvPTmxBQODFQ6PPTWrPzqzOzatAwGBKyObLSWfPTivKyCZEQyNKyGZOzWrOzWtOTSrOTGpNS2lJx2XDQmJCweHCQaHCQWFBwSFBQKDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABAALAAAAAAWABYAAAj/AAEEEDCAQAEDBxAkULCAQQMHDyBInBgggoQJFCpkzGjhAoYMGjZMpMghQgcNFjh4mODhA4gQGkSIHAmBwAgNJEpo8KDSxAkUGjhMSEGz5gUVIiKs2PmBRQudHiwQpUnAxYsXImB0aBqjBcuoU0fKmPGChgUNH2qIqGHjg9u3bicWIFs2rYgbNnDkyGFhb8cccQ3ouJqWQo0dPFr0WMy4h48LFj4gsKriB5AeNngEaSGks+chPnwQOXFAh4oXRYxk9nAEyY7XO2wksWHDx5ATCDIoUXEBsYclTJo4cWJhuIjhSXacSPBEiZLMQY4wgRKluvXqUpyIsDElAxUqVaxcwcGCPQuWLOixaNHCZAsXBU+oqKDSxQqULF6ifNmyn/8VMOtxwcAK36kQRhdJQIFFEmKM4eCDYGyhhYAEkqFEGSuYYcUZLaDxXRpqSNRCEu6twYaFZXTQhgRd2NCCG9918AYELTjoXgNuKAFHB2RQEUYHVbQQRwlUpPHGGFwkyQUEDsgxx4lh9BhCBy2U8UQJcrSg5JIQ0FEHG3bc0QGYK+CRhx57PEGlkhM9sAEffKTQhx9+/AEIIIGoEUgLLRRFR0AAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mail_reply-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIcAAJR6fIxydIxubIRqbIRmZHxeXHRaXHRWVGxSVGROTFxGRFxCRFQ+PEw6PEw2NEQuLPwCBMSihPTixPz69PTq5Pzy1Pzu5PTq1Pzy7Pzu7Ozi1LyelPTavPz+/DwqLLSajPTetPz27LSWlPzmzPz6/PTexPz67Pz29OTSzMyurPz25LyajBRCdPzuvDQmJOzexPTevOzq5BQ6bBwuTDQiJHxiZPz23Pz65LyinPzmvBxCbHySvAQCBOTi3OTq9CweHOzaxFSq3Aw6XGy63ByWzJzO7Mzi9OzavNzq9BRytAx6vBR6tPzy3AwOHDy63Ax+xCSazCym1CR6rBwWVOzizAQSLES+3CyCtBRyrBRmnGRKTPzu1MzGtAxKfAQWLAwePPTizMy6nByGvNzWxOzWrNzOtBQKDJR2ZNS2lPTmvBQODPTatKSCbOTaxLyqlAQKHFQ6PPzyzPzqzPTu1PTivOzWtKyObPzuzOTOtLSWfPzqvAwGBKyCZPTWrPTmxNzKrEQyNOzatOTGpJx2XCQaHCQWFBwSFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABAALAAAAAAWABYAAAj/AAEEEDCAQAEDBxAkULCAQQMHDyBInBgggoQJFCpYuIDBQgYNGzh08DCR4oQPIDqEmDBhJQYRIzqQIFkSAoESJCKkDGFiwgkUKTpMwECz5IASKjqsSMlSA4sWQjG4qGnzhYoQSmF0iCFjBgmWGWhQrVHCxg2sOHLo2MGjB0sLYmsWQHq1p4wdPtqemGDhB1UDQFSouKHi7oQgQmSwUMyYxcQDZQWz2EFiCJEiRoyQyLzZyGIIB47YKLwDSRAiSZSoXq1kCRHNLBK8YGKjCYskTp4ogeKkt+8oUaBImZKAAxMmVKrctqL7ihTnz7FkAT5FC4cKFbZwadIFdxcvX8KLss8iJcoUBUcq2KgAJoxyMTy4jCFTxoxEHl2GLyCDncmWM2hUIQMPY2CXhhoTfTEcA2tgVwEba7Thxhs88FdBD/ZB8MUUHMJBRhw2sAGCHBKU4UaFc1RAhxnhcdhhHUzYAUIcFdxRAh4R5KGHinu4OIVEDqTBRx81xhGHHzD8wQYQetDRI4cTAcIHGWT0EQgZa1ApCBqDcBAID1Q94IEHLtBAAyGEFGKIIWqYYQYPYNZkQEAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mail_send-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIcAAIR6fIRydHxubHRqbHRmZGxeXGxaXGRWVFxSVFxOTFRGRExCREw+PEQ6PDw2NDwuLPwCBLSijOzixPz69PTq3PTu5PTu3PTu7OTi1KyelOzavPz+/DQqLPz67LSafOzetPz27Pz29KyajPTmzPz6/NzSzLyurCwiJPz25Ozi3JyOjPzuxBRGbAwSHOzexPz23KSSlPzqvBROdISavBxSdAwaLHRiZLSinNTGxMy+vBxGZNzu9BSGrAwWJMSyrKSSjFy61ETO3BRWfPz65PTqzHTK3ByqzBSWxEzW5AQWJOTWxBRCXOTu9BSOvDzO3ByavBRKbOzaxOzizKSWlCQ2TAQCBJza7BRWdNzSxJSCbMzq9BSOtCSKrAwiPOTavPzy3LymlCySrAwmPFRKTPzy1NTGrPzu1JR+bOzatPzyzCy61ByGpOzWtJyCbPTmvPzuzIS+3FymxCSuzBR6nJyCZOTWvKSObMSujOzivAwKDOTSrNzKrJyGbDwyNOzWrMy2lIx2XBwWFBQSFBQODAwGBAQGBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABAALAAAAAAWABYAAAj/AAEEEDCAQAEDBxAkULCAQQMHDyBInBgggoQJFCpYqMDxAoYMGjZwmEixg4cPGzqA6BBiAggRIzaQGEkSwgAMJCKgnNBhQogSJlKGOFHTpgYUG0TsnJBCxQoSE1i0KErAxYsOJJRuuAAjhkwZM2jUqGnDBQoUHTbciIEjx4YNOmbs4CGjB8kCZlGAALHBx4+YcTcACcJDyFSJBo6iGNIhhQkiG8BOKGLkCBK6SSQisHoWhZIbG5bMYALECI8mTZw8gTL1QJQXZ6VMiUylSpUlVpoYaXLFtm0EGmCjwJLlA2O9MrRsccKlC8kEXr7AdgEmwtkhX2SQ2BIkjBiSYzSQr/nyhUKZLIrJJOcexvlEBV7IvCBjRkmAMzHOaufhxDvJBWiQISAFxUUQQRovJNeEGmu4JxEDbKQhXxsfuFDGGW68IQMcccgxRxUkNRDhC3R8QMQIdZwXQ11JJGFbiB+QYccHaaTxhgt13OFBDGTgkUdRDrhAhx5k2JjGCB/swYcXMXwAYk190OGHHx/4wUaVepTxByAaoPEkSQ5wwMEJZAZipiCDDJIHIYV8OZEdAQEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== matrix-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBIQChCH5BAEAAAAALAAAAAAWABYAAAJHhI+pyw0Bw4sTVmmw1C/3/20ex2VUtJ2Uwx7oBb9eR45ziNfgy6tW2+pZhJicjXbTiZA7X2q4AjqIsajSuDsuty5n9SddGAoAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== message_get-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBFxatHx+/Hx69GRixFRWtHR29FxaxHx6/Gxq9ExKxGRm/FRW9Dw+xFxavFxazFRS1ExO9ERC/DQy5CQmzBwaxBQSpCwqLMS+xBwatExK/DQy9CQm/BQW3AQCjJyavAQCBMzGzAwOtDQ21DQy/Cwq/BQW9AwK5JSStOTi5AwKDKyurMTGxLS2xISGpNTS1IyKjJyanMTCxAQC1MzKzNza3MzOzCQiJGxqbHx6fKyqrLy61NTO1JSSlNTW1NzW3Nze3HRydKSipISChDw6PLy+vFxaXPTy9ISGhPz+/Ly6vLSytJSWlHx+fCQmJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4IBAgIDBISLjIWHiY2RggWHBgeSkYYICQqYjQUICwwNnoMFDg8QDBESExQVFpgXGBkQERoSGxwdHh8gkiAhGCIjJCUmJx4oKb+NKissIS0iHcgeLi8pzI0gMDEyLzIiM9c0NTU2zYQ3ODk6L/A7yvDnPBjqgiA5PTYvPvU+fvh4AeQFDXwgggTBwEIIOB8sakB0iO7gIH05hvToIeQFBo4eNwoJEaIZiAtEUgbhWGQjRxk9hhhJSeQXiCM4jxBxyXMjEiI5bR5JQnRnT5dDiNCgIcNmCiBAfAShSZVmECVKltgc+MIGCxlgw4pdskKHEJtMZRTJuqStW7dCImLEYGLTrJC4PeYy0asXxpAhTZpdGHzBSWHDiBPfWCzIQCAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== misc-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBBQSFCQiJERGRBwaHFxeXHx+fDw+PGRmZExOTGxubKSipDQyNHx6fIyKjJSSlJyanISGhISChLS2tIyOjHR2dAwKDAQGBJyenAQCBCwqLLy+vKyqrAwODMTGxKyurFRWVLSytLy6vMTCxMzOzGRiZNTW1CwuLMzKzFxaXJSWlOTm5Nze3Ozu7OTi5Ozq7GxqbDw6PHRydAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAb/QIBwSBwGBMVkMjAgFAwHBFJpPB4SiQJCsWAQqEJB4prdNhQNx7QYIFwLD0ikQZdMHgelOPGYULQVDg4QEAVfRAEBBwUTEE0WFwcYhAuNF0QDBQULDwwZGUIaEAuVGxgBRAIFEhwHHUQMCxwTHAVrAAwFFRwKFkQZsxseDqBDGXMSHwfFQiAhIiMeJApEBwcOcahDJcLSJCYcGkQKcRAnQhkF0SgmEykHXkObox8q1iEjKN8rENqYD7MmeBCmzwSLFS1I3AqzYIPDESS+sWCxgQMLEgOSJKjozeAKFyskCDigQFwSBhJMjDDhAlyLFyVA+dIzAUUKEi0eaNhAIg8YGiEMenkwASNDDBkLqRQAEEAkup9KDkEFACUIACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= move-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAI6hI8RyJ26nAQQzlbrdWrP7nHRNh5gwpxmaZxWylJdRtf2fcux2rr7n8LsQrxQzyhE9mhIplKjPE5wBQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 news_subscribe-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAASC/Dw6PAQCBHRydPT29GxqbCQiJPz+9PTy9JwCBKwqLPz6/GRiZERCRPz+/FRSVDQyNBQSFBwaHDQ2NKSipJyanHx+fMzOzNza3FTCFGRmZCwqLAwODLzqpCwuLExOTLzqrFTGFAQGBES+BETCBEzCDDSqBBQ+BLTqnBRCBFRWVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAb0QIBwCAgIiMgkckAoHJVQgEFAOCCc0WThcEgoDgvGMztFJLiJ83Ws3C4ODIY1jUCIlQ0Bd+FwMLZmCXV3Qw8CCAICfW9wBQhddVgAEIcCCwuJDlxWBQx1AhFPjlyJlwISj1ZWBJQTAImIerGqVwgEiAwUR46ysAeJcKoEoYkTVLGPvrWVDBUWEwEXF1aziMGfAhhiAhAVFdKPyMux2YkAEc3fF3WcdQTAGYkQQxAF3uAIGggbCBwCHfEEeEBiIB0+BB8cgHAQogMIKPXurRMxgkQJExjZELT3jUGDEyhMpDhxIouUOB8qqAhZ0iS9CJMStTQQBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 next-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBAQCBOze9ORy7Pzy/PSi5LQCvNSG1JQ2nNx21LQCzMRGzNRy3KQCpLwKzAAAACH5BAEAAAAALAAAAAAWABYAAARTEMhJq704axC671WAfR8VCOKUbudApCBHksVgHO+5agFiHwVBAuYZ+RQLBmLHatgMS8mMyREsDI7oRipEeLWsKVG8Fce26EspzeaR2vDQNE7PGCIAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== openterm-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIcAAPwCBAQCBPTy9PTu9Ozq7OTi5Nze3OTe5Nza3NzW3NTS1MzOzMzKzMzGzMTCxMTGxOzm7AwGDBQOFBQSFCQeHCwmLCwuLDQyNDw6PERCRFROVEQ+RDQ2NLy+vKSipISChGxqbExKTOzu7OTm5Pz+/GRiZMS+xLy6vBQWFLy2vCwiHFQ+NMSmfNSyhIxmTDwuLJx+bLS2tCwmHMyyhMyqfPTqpPzyvLSWbLSWfPzitIx+ZDw2PAwKDCQiJGxWRPTmrPTerMyuhPzqtPz63PTWnPz6zNy+nIRiVDQuLKyWbOTanPz21NS2jNS6lDQqJHRaTPzmrPTSnPzyxOTClPz2xNSuhPTqxPzuvOzSpAQGDOTKnMy2jOzSrPTu1NzKnOzOnBwWHJRuXLSWdPTatPzqvNzClCwmJOzSnOTOnPTuxOzKlOzerOzarOzitJR6ZNTO1IxmXPTWrNSyjPzOjPTSpLSehHRqZOzirOTCjPS+fPzGhOy6bOzKhGROPMy2lPz+1PzmtKRyRHRiNNTCdPz+zNzCjEQ2NKySdDQmJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAj/AAEIHEiwoMGBARIqXMhQIUIBAwYQIFCggIEDCBIoULBgAYMGDgIIDEBAwMSKBRBk3NjxAciQIwdACBBBwgQKFSxcwJBBwwYMHBx0EAmA5EwPH0CEsCChoYgOQ0cSGCHhA4kSS5syJGDiBNEAFVGUKKEBAwWFFM6SNJHi64gDFEKE4FBBggoKK1i0cPECxokYXw0gsECYggQZM2jAqGHjBo4cOtqOxLhDAg8ePXz8ABJEyBAWRIoYOfJipEoMCZEkuaFkSAslS5jUGJKkSRAnRREo0JDwCZQoTKQAmUKlihQrVa5gKZ1lI+oAK7QM2cJlSZMuU4Z4+TJEx0iNOwKAggkjZkyOFmS8kClzpcUQLRRGbjRD4MgZNEzSqKG+ZgobI2248dUbDDDwABzcxSEHEFpgEcUcdMRRhx1fFejAAx0cgcYdSxiBRx566LEHH0d8QFRRNC3Uhx985CHEH0MAEkhCBxWkgiCDFEFIEYUYUmONMhyCRxVH/PgjBYioYJAdAQEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== paintbrush-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBAQCBMTC/AQCtAQCdPz+/MzKzOzu7KyqrCwuLAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARZEMhJ6wxiDMsp1lvHfRohWuRAmOeVlUTQSukqz3U8A/nd9rtCAWTbAQoGg0q3OyANCOYPA0UgfCdMJnHFimre72sZ7pBWiTLqRUirK5hV7A0P2O3GvD5PjwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== paren-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIEAAPwCBIQChAQCBBQSFCH5BAEAAAAALAAAAAAWABYAAAJThI+pGou9oDuS1hlqnkxu/niVQB6kYHzAiJYoUK7paLrxpr6GMJjWeqlFGirEaQhcDHQJnEQX2/1kMBv08Yu1ttNkFRr1ikHjIiYYjDjSWLIbUAAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== pencil-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIMAAASC/IQCBPwCBPyChMQCBPzCxAQCBPz+/MzKzISChKyqrDQyNEQCBAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARYEMhJ6wxiEMtpIAWxddwXiqRlikSQeiAbuC+wirNR322gv7zcLobzDU+9XypoBBKTR1lz+RTWDgip8nUwZK1XLyIx5XoVicX2RUAo1DVKi7GOBxjxfNwQAQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 percent-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAIzhI+py+0P4wkU1XfDhBdo/zndF4qh1pkGKYFk2XpTqoJr9G5YfmOz3hixfBZa7IhMJg0FACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= player_eject-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNAwKDJSWlFRSVBQSFKymrOzq7HRydERCRPz+/MzGzISGhJyenKSmpGxqbJyWnJSOlKSepLy2vIyOjGRiZPTu9IyGjLSutFxaXExOTHx2fGReZAQCBAQGBBwaHCQiJLSytKyurJSSlFxeXNze3LS2tIyKjFxWXHRudAwGDBQOFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAa1QIBwSCwaj8ikcqkMCJjHwIBQgBIDhgMiUbVKFQsGItBdBhpgh4PxIJvRC8cA4oiMy8bvQhJhMAYTFBVOURAWEw0QFxcMERAYCBluVxobDxkVHJocmBwEGgmEQx0dHh0CpKmkH6odVlanBR8FtAIFtiCkSB0LISEiGCIGIxAPDySuRwIOBwrOzwoHJRHJRh0jJgMj2gMnERQUCNVFHQQoCBvo6CkICATjRB0qp7b1K6qv+foyQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 player_end-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNFxeXAQCBMTCxGReZBQSFOzm7AwKDKymrJSSlFRSVCwqLLy6vPTy9OTe5Ozq7CQiJLSytOTi5BwaHPz+/HRydMzKzKSepJSOlKSipJyanIyGjIyKjKyurISGhMzGzJyWnHR2dISChIyOjLSutDw+PERCRHx6fJSWlIR+hJyenGRmZHx2fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAa6QIBwSCwaj8ikMBBQKgOCgRMZIBSkxYHWoDVWD9EigpBQLLBERsPxCA8NDUhjgTBGJJNGG02RVBQWdUV3FxgZe0IGfoAGdhoXGxwdiAYef4FGFBoeHB8dGSBRihUhIo1FBhkbIyMkJRYmAwYal4JEBh2RChIWJ1IIGxUZFqdECCgkHR6wWAYpFR2YWSobvL5vFgfDaEMDIivMRBEsD9HcQgMWvecDLB0tZ0btsfJa9vLXU/X6/P3+b0EAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= player_pause-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIQAAPwCBAQCBAwODMTCxKSmpJSWlFRSVAQGBBwaHLSutOzq7Ly6vCQeJPz+/Hx2fBQWFGxubLSytJSOlBQOFAwKDJSSlJyWnIyOjHRydNze3GRiZAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAWBICCOZGmeaKqubOumQSDEgRjPMSoMRGEcol3vh0IkFAtDDWBEKlGMRKPgEIii0yrqIS1ArADu9KuLNCSOSdCMVp8ohEZFC4DL6SaBpXGh6/l4JX8XZACDhXkYCn1LAoqMUBAZEhBLDJKUSyYBGmhPAJyemiU0NDaloy+qq6ytI8whACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= player_start-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNAQCBExOTAwKDAQGBJSSlHx+fBQSFMTCxKymrFRSVOzu7GxqbLSytLy6vJyanPz+/GReZBwaHHRydKSepKSipGRiZJyWnAwODLSutKSmpISChPTu9ISGhFxaXJSWlIyGjJSOlERCRIyKjDw2PIyOjLy2vOzm7Dw6PLS2tCQmJOTe5GxmbDQ2NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAa7QIBwSCwaj8ik0hgQLJGBgbMoqBIKU2LAcMgOEQmFYeEFbBmNMgDhYDwWBC0k4pCoJ46IgRIXBioRCRYXamwRGBQIfgaBFhiERhkaenxmCoEbBhyQRYaIGVsdghgem4UWegcEBB8UHhsgIaZGBBgRIpUIIxQhChginEQIIBEklWslFyYnBsFfFCi4WQgpFBwqFxNGKxcsxl4IAS0NZEYCF3vlwgEfUuZV8JEuI2pPAARN9kcE9fr+SwaCAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 player_stop-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBAwKDBQSFBwaHCQmJJSSlISChJSOlJSWlGxqbGRiZNTS1PTy9Pz+/Ozm7OTi5FRSVIyKjOTe5MTCxIR+hExOTHR2dLy6vLSytLy2vHRydFxWXIyGjIyOjPz2/FRWVHx6fExKTMzOzJyanKSmpKyqrKSipAQGBLSutHx2fDw6PAwODAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAa1QIBwSCwaj8ikcslsAgKCAWEQjQ4KgSwyYDAcugZEQqFYYJECA6PhaLcfEEUkgJZAGJB8fkKpWOhHAxcOGBQZGBoaGQgbHIBGAhUOGR0SBxISBh4Xf0iCHxQSlRIIXhsgj0UCIaCXmJgHGyKpRJ+hmB5dHQqOaCENIx0epBIkBhdzngoPGCQlJifQJBvJRygRKRcKGxcXGypys1srEREc5SLnICLiR1koLFVUWfRO9vf4+UwyQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 prec_minus-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIEAAPwCBAQCBKSipPz+/CH5BAEAAAAALAAAAAAWABYAAAJAhI+py62RgnRnGguZ3BlTYIHdl13jh3goFpIleggvTK8ctw76Pswav/MtAkCd8NHj9HLFY6S4JEGdqdumtjAUAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 prec_plus-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIEAAPwCBAQCBKSipPz+/CH5BAEAAAAALAAAAAAWABYAAAJHhI+py22hgjwSonktxBZU7GnhkyXc6JmmeDpnG2lg1YCOInT3zrvfxwsMhsSBrkYUDo8MpTEZNH6M0SV058xWi1Tsj9ZjGAoAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== previous-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBAQCBOzC7PTq9NSG1MxW3LQCzNRi7MRGzLQCvPz2/NRq3ORy7HQCdJwClAAAACH5BAEAAAAALAAAAAAWABYAAARUEMhJq70Yh813rl1HheInBYIwrEJwktxJFEbRmuOBJIXivp5LQLcj+HCnBaPBMBhdMBBjw0w8ccEA0/EzdQHaHywmnIyDyDSIrG4LQ+64OSqvx+kRACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= prod-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBIQChCH5BAEAAAAALAAAAAAWABYAAAI7hI+py+1/gpy0hlVRZlP19mmSE0YjeIoXuqpkarYYbJQeDdiJrrs77gvOZDVg7Eb8JXtFSpMJiUoB9AIAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== queue-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIIAAPwCBAQCBKSipMTC/Pz+/AAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAANfCLrc/jDKEGQMQlDLKM5aZQXDQIHZ9nhleaLqEhAE1bofKCozXZO3l0bmK9qCQ2LRCDQlAb3lkoTZQaVS6jOKpWmt3O5X2fU6wWXfuBM2mmINCpbKkavho56VI9s7DAkAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== redo-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBCReDJzGjMzivOTu3Pz+/JTWbHy+VHTCTMTivPT69BxGDESuJDyiHESiHEymJIzKZAQCBFS2LFzKNGzWPDRqHCxqDFSqLHy2XESCHAwaBAQOBBQqBDyWJHyqZDyKFGSiVESeJBQ6BAwSBGTGPFyWPFSSLEyOLESGJBQiDAwiBBQmDCRGFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAaoQIBwSCwaj8hkMcBkKpcBwYAwEDif0YLhwEUkFItFMkAwMBoOR+PxgHwjRDggamhIJpQ8ZbKGKOQLcgEFdhUWEYgRF3sNfhELBHALAhgZFhobRBwREhQdEAIEHpIKHwsaSJwUDQgQIJINARxKESESDQ0dgCIjSpAkDAwPco+ZSJAlJicnKHIAIrNHidOIQxunT0kpCyrZSCss0d5Fj6jjRonn6uvs2QZBACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= reload-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBCRSFCRSHBw+DBxCFCQ6FBwyDBQWBBxGFCxyLGTChMzqzLzmvHzKjDyOTER+RERyNDSqXNzy3LzivFS+fCyCPBQmBCQiBBxKFBQqDOTy3LTitES2dDR+PCxuJOT25KTarCx+PESSTCxKHDSeVCyKRNT21ESWVDSGPBQyDAQCBBQSFDRuLDSyZDySTGzChCRiJKSmpExKTDS2ZGzGhLy+vGxqbISChDSKRMzKzGxubDQ2NIyOjCQiJCwqLBQWFCwuLKSipERCRERGRHR2dAwKDDw6PFRWVIyKjCQmJFRSVBwaHKyurAQGBExOTBweHFxeXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf9gACCg4IBAgMEBQYHhI2ECAkKCwwNDg8QBAOOhAQREhMUFQgWBxcHGBmbggkaGxwPB4yDB6SbBJIKHQaqtY0eHyAhsqrDgx4aCiKpqoQHAyMjJBMKJaSxzAAHIRsmJgonKA0LHSmDKiuOBywRLSQuLyEwwyoxMuiN6iUzNBXy5jU2bsgoJugABBz95uXQsUMGD3vpPPgTpKIGwx4+HMr4kW4YkCA2hAzxAQSIECI+imBTwVIFESNHerRUgc0cEiFHkjiiyYzeDiVLdvLcySSkkKGEWiZVweSGkIHMmvQosoQlkaZOjvhosvKJjIAxoOAsgpRZkQNLnvSoqspAIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 revert-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAAQCBPwCBPz+/BQSFPTy9CQiJNTW1ERCRLSytAQGBISChMzKzFRWVDQyNCwqLMTCxFxeXOTm1KSipPz69BweHHR2dJSWlMya/Mxm/GQCzOzWxGRmZPzOzMzOzMzOnExOTDw6PNze3Ozq7OTi5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAWABYAAAbrQIBwSAwYAwDjUCloOgUDQlJJFCKfzoLAMF0ih9jmASGQfq3IBECgYC8YCsah4Rgc7+Bw2fCY4pNrCg8QboIIEX5HXXoEjWZ3eAIMgxITcRRVmVdOE50TBRV6TkJsD3EWDBUOoRcXGBmwsAJqT44aoKJNtAoVDAwWFRUFGwKxxhkCQhMEyxEcGrfEuWoGBgsdDwseHhQQvt++Hx8HmUQU4OHiICAJkHcDDB8hBCIj1QYfDomQAOIiHwxCPBiYr507JeNGAOQz8IC+g0YKrAtxAMQDBBgPFDB4EACIAwIHDkQAAhNEKuUStDMQBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 rightjust-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAIhhI+py+1vgpy0Toizjvbur3WiBJbhSJnqgorri7nwDBoFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= rsub-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIEAAPwCBAQCBIQChAAAACH5BAEAAAAALAAAAAAWABYAAAI+hI+pFu3f1gmSVUBrlnt19SUhMk5XaWnnqrYc+2rQfNWHIBi4feP+zssBdkJez5gAIodDYbH2+yGBymXCUAAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== rsup-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIEAAPwCBIQChAQCBAAAACH5BAEAAAAALAAAAAAWABYAAAI6hI+pyxBhXlOv1omggxon6VFdGG1laFmkyQLCC8fvJNB2U+M3k/P70gP+FEHiMFFEHhFJJk0GXUkNBQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 run-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBOzq5MzOzPTy9KyurNze3PTy7IyOjOTi5MTGxNza3MTCxMzKzHx+fOTm5NTSzNTS1NTW1FxaXAQGBLy+vJSWlGxqbGRmZIyKhDw6PAQGDJyenAwKDLy6vLSytBQSFLy6tKyqrHR2dLS2tJyanJSSlISGhKSmpCQiJISGjCwqLBwaHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAbcQIBwSCwaj8RAAMkUBgSDZdMpBQQIharyGDAclsoDYhtIKKrDwMEgUBMWiwSj3HCg0w+DfgGJQAYSDRMUTAELBhJ8fw0KFXdJBwkLEhYXGAUNDBUZj0pXkxYaARsIDRUMHJ5pAgQHkxEYUh0JFR4fHAVZTgMFCAt+sUIgBB4hIggOI1pKCQO8CB0gAgYkJGNbRQEKEYwNCa7VIhOPaRAKCpoV1QUl5E5mDJrFJAW4JuRlCuMnKB+94yVQ2DGi7QSYABcQgACTDF+VFChULJsiZIUCiRS5sMjIsQidIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 showmenu-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBAQCBBwaHERCRIyKjBQi/ERO7HR+1Ly+1Pz+/Ozq7MTCxOzu7NTS1AAAAAAAACH5BAEAAAAALAAAAAAWABYAAARkEMhJq7046z2D/2AoDAQVFGiqqsaBmGH8jWWX3Hiu3+YdKglPMIDrDXc+Is92zAmFi5pECWIkjySj0EkUZplb3JP4nV65WCmAqhR3yeo2Emmc0zsyGc3U6Pv/gAAKHISFhoQGEQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 signature-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAISGhISChHx+fHx6fHR2dHRydGxubGxqbGRmZGRiZFxeXFxaXFRWVFRSVExOTPwCBAQCBMzKzMzOzMTCtMS2dJSCTCwqLPz+/PTu1MzCtERCRMSydPTqxPz+9Pz6/MS+rNzKlKSSVOTarPz69ISCtGxurJyaxPT29MS6pOzmvNzSnHRyrPz29OTi5LyqXOzavMy6fFxanHR2rOzq5JyKTOzizPTqzKyWVGxqpPTy7LymZGRipLSy1PTu5KSSZFRKLExKTGRaNPz27PTq3LSiXPTq1GRWNDQ2NMTC3FxSNLymXGxqrPzy7IRyPDQyNCQmJGRinJSCdHxuVBQSDPTy5PTm1IR2RJyOfKSSfBweHGRenFxepNzGrKyejNS+pNTCnNzCpLyedBwaFBQWFNzOrOTOtOTOrBQSFOzStOTKpAwKBMS+tMS6rMS2nMSylMSulLymhLymfAQGBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAA8ALAAAAAAWABYAAAf/gAAAAQIDBAUGBwgJCgsMDQ4OD5MPEAEREpmYmJqaE5IPFBUWAxEXp6ipqJ+TFRgVBaaqsxcZGhUVGxwdBrK0qB4fFSAhIiMYCLIkJSa0JygVKSIhKSoJvhcrqh4sLRUuKR4vITAL2DGpMiMzNBs1FzYiKjcMER6oOKglLDkVOinwRMCAAcKBrx33eMTwkKPHPx8/RGxwEaICkIMXcOBgMaJfCgw/fMCgWCGIhoMlSOQQkmMIkSJGUoysGOTBEVlIZMTg16NHhSJJZCqhOenmqSU5cDDB0JJIzJlNak5yYoqHDBY7hmgN8aPGhhslKU16EgHJDiY9oGz9EcJFkChSaKaIfUC2I5UhMarU+GElyJUrWHzIFZslAtqWVbRs4dIFi5cvYMKImTsmQs8qVVrUePGCDJcyZkCEGUzpTAQMmGts5ozGTJo0XEbPVTNhDRsUbdy82Q0HTpwwwNXMlQOhuPHjyIWLNRAIACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= spellcheck-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIQAAASC/AQCBFxaXBQWFAwKDPzCxPwaHPwiJNQGBOxKTPQ6PNQCBGwCBPQ+POwCBPwqLMwCBHwCBBwCBFQCBLQCBPwCBBQCBCQCBPQCBOQCBDQCBFwCBJQCBAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAWGICCOZGmeaAoErMi+4xuQgQAI8yoKw2rfOZ1LRIgJh0hhDncsyXKypNMIKAKbNGpwFjxukcza7jt8xmCAgkpVMKxRhQOCnTAVFAtGqtBwLEgFDxAREigBExQVFRAibYNdJhaIigmODBdvF4gYDwoZDBpvIhKIGYOFoi4bHBGQogESqKlvBiEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== sqrt-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIIAAPwCBIQChAQCBBwaHAQGBAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAANPCLrc/jDCQKutkcqQJeCP5k3g6IjCIAjAynYt0brzUn7gW++i0i8CGcNiuyl0NlyysYKhXgQdUvmcNZtDTo/mmvo+ptMvjDOSzWey+mFIAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 start-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAw2VAQCBCRGZAxCZGyavExmjHyatOTy9CxihISevPz+/KzO3BRylAw+XDRWbPz6/FzC3CSuzDyexJzO5Mzq9CxSdAQOFISmxNzu9HTS5BSmxAyexDSuzJTa7Mzu9Kzi7GS21CRmjAQOHHSWtLze7AyWvHzG3BRihCTO3BS+1AyixBSWvBSOtBSStAQWJDzW5BTC3BSqzBS21CTC1ETW3AQSHEze7BRqlBRmjAQCDBR+pBRefBRSdAQKFAAAACH5BAEAAAAALAAAAAAWABYAAAa0QIBwSCwaj8ikMqBcMpsCQTEwIDQBUWKgYHgqs8LAAZGwQqWAgGLBaDgEj0Fgjh5mxRBERDKhICAQFRYXRVEBGBAZGhscHR4VHyAhIiOFAiQZJRoSGyaNJxQnEyiVRFEoGykqKyYsJiYtLi0mKC+WFygrMDEyMzQ1wDQqKDaWADYoMzcqsjg5DSgoBISmaCOoMG4v29s2OsZCyDs8DldgQtc95WdFPg7rV0Y+XvHt9ff4SXRBACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= stop-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAASC/CQKDBwKDCwODNyKjPzq7My+vIxiXAQCBOSOjPz6/OSelNySjNyGhMR+fLRaTGQ2LPz+/Nx+dNR2bNRybMxuZMxeXMxiZLQSFJQaHFwqJNyKhOSCfNyCfNR6dMxmXMxWVMRORLQODOR+fOSSjNR2dMQ2LJQWFMRWTLwWDNSCfMxeVLwaFKQODNR+fNx+fMxiXKQSDOSWlMRSTMxaVMQ6NMxORMQyJOTS1MxqXLwWFLRORMxKPMQaHMxKTLQWFCH5BAEAAAAALAAAAAAWABYAAAb2QIBwSCwajwGBcikIHIsDQmFKNRwQT2EgoVgsGOCG4wHBIgmRhWRCqVQsF0xGYyYGNgoGh9PpeCQfICEic3UAAWgLIxwRJBsbHSUREyYYJ3RDAQULexGejhueESgpl3WaCxsqJKKsChEUKywtmFoFDC4vCayikzCyMbWHt38NCTKiHhUfMyzBdQIFKsodob0VNDWzwppuKxMRrx6iNjcitNA4bh+iEzkwojc66JkOOxcf7G35PBE9KS1MEUGgIQOIFfk++KjRw9wJgUUIZvhRoyLDFCliQDQisUWLGCJOeNx4hKCGkyhPGnqCoKVLl1liypyZxUAQACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= sum-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBIQChCH5BAEAAAAALAAAAAAWABYAAAIyhI+py+1/gpyUMrvm1bdhFTgfhIykYZ4pyZ2o5EZwDLSurc7ZFnqZDgLKKsQe7QihFwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== text_block-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAImhI+py30Bo5zBWUWzvNzo33GfFl5jVlonlTrr1DbvFi9vjeeNUQAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== text_bold-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAIxhI+py+0Powm0VnknjVkH2AEhE45LZ55Wqn6e65TsMc5eYosbksswubJIhsSiccgvAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 text_center-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAImhI+py30Bo5zBWUbz3Sh7yIWfFHKjVl4nmFrr1Lpr7LwkjeeIUQAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== text-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIQAAPwCBAQCBBwaHAwKDBQSFLy+vLS2tJSWlBQWFKyqrFRSVCwqLDQyNNTS1GxqbFxaXJyanIyOjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAVcICCOZGmKQSoMaZsShBsQBdAapHvgaIDUqUPJlRjSbAoT0fRDKgODRbF0PLUYjZO2F2Bst9evNix+dsvDlGKK5jraudQb7qbX6a2HEJ+ycyF+LRE8ZTI+fX5oGCEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== text_italic-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAImhI+py+0P4wqUSlQvttrkDnyaOHIdeaGRupplAIauVM3xjeeOUQAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== text_left-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAImhI+pyw0Bo5zB2UXz3Sp7yG2fFJajVjonmIor2TJvfL0wjecIXQAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== text_right-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAImhI+py30Bo5zBWUfz3SZ7yIXdF4kWqZkbCqoMO7kXLC+wVOe6YRQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== text_under-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAIvhI+py+0PowmUnhpeVVnb1DkbCI1I2JhX+Z0sOr2cTHpwK7a4rUr+hAnufsTirwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== toggle_log-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIYAAAQCBAQ2NPwCBATW1KSWfBweHATS1Pz+/Ozm1GxiTATOzPz6/Pz69ATGxKSahOzaxPzy5HxuVLSmlOTazPz27AS+vPT29NzClPTexHxuXLSmjAyKhPTy9KyehNy+lPTy5Pz29HxyXNzWxAS2tOzexPzy7IR6ZASytPTy7ASurPTu3KSSdIx+bASqrJyOdIyCbASmpJySfPzu3OzizJyKbKyijASipJSGdOTWtPTq1PTq3NS+lJySdOzWtOzi1My6lMS+rOTOrMS2nNTGrNTCpNzKpJSGZKyafLSifIx+ZHx6ZFR6bFR+dAQyNAQuLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAIALAAAAAAWABYAAAf/gAABAoSFhoeHAAMAiI2IigSMjoQABYkGBAeSjwAICYkKmQublJ0HDJ+GAA0OB66bpq4HCQC1lA2ZrqMCAA8QBwvBERITFIwAFa2yFgAXGL+uDBkaxRu1FQQLshwdHhgfDK4gIRoiFNYAI8quHA4XJCUMCwwMJhLm6Ce5rigEzhAMQICwYKLcuVopWgUDoWLFhQcfKNCjwOLeQQAtCFDYiAKBC28QKITk8MIgOhgxIHyQIWOGi4cfIHAogYJGjWq1bNzAkSOHjgc0dmBAgQKCUR43S1jjVeFGDx8PcNAAKePDjxg1gOCThOxFEBxBgpJQMQGpkCETEIBYSqkpkSJGOYTyOCJkgg4OIDaybXvjh5ELLpAMUYEAgQ7COPbyTWJEiY3HkCOTaruESYVamDPbQtTESedJhOgEAgAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 top-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBAw2VHSWtBRihAQOHISmxNzu9BSmxHyatPz6/Lze7CTO3AyixAQSHHTS5BTC3DzW5ByyzPz+/OTy9AyexEze7GyavKzO3FzC3AyWvBSqzBR+pAQKFCRGZExmjCxihBRylCSuzBSWvBS21BSStBRSdAw+XAxCZDyexDSuzCTC1BSOtJzO5JTa7ETW3BRqlAQWJDRWbOT2/Mzq9HzG3BRmjJzS5Kzi7GS21BS+1CxSdCRmjAQOFAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAaoQIBwSCwaj8jkMMBsOp3Ip7SpHAoGhELVKDAcENmtNaFYMBoEh1hAPjwgEUlYyZ5QHpIKxALWIgUXFBgZCBUaG3AcBB1HAh4fICEiFRUjJCUhBCYnjEQCAignoikqhissKAKiJwFJAS0uKhovMDFiADIzNDUsLza2Yh4KNDcsEbW3Ago4NSUrBMBbAjQ5KRo60Mk7PATdKH5bAT0xDg4xPa236uvsShRBACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= undo-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBCReDJzGjMzivOTu3PT69MTivHy+VJTWbIzKZEymJESmFESiHDyiHESqLAQCBFzKNGzWPFS2LNTmzCxqDDRqHPz+/KTGnBQqBAQOBAwaBESCHHy2XBxGDOzy7HTCTEyyJDSqFHzWTAwSBBQ6BIy+dESKJFySPFSSNAwiBCRGFBQmDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAalQIBwSCwaj8ikMsBkKotMwYAwEDiXgYLhwD0gCFZiQKxNKBYMRqPh+D6G16y5AYnYIxBJAyF4AwITTAUJdBESD4gPFBV6Fn6ABBcJDIYPGEQZGhQbHAIdfx4JHw2VSBodGwWfAR4LDSALfkgYAQurBiAhICKfSSMkvQElGyYnGyi9Rxkdj4nOskUYyU9FpxnURikdGtjRKivdRKfQ2Inh5+jpRwZBACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= up-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAw2VAQCBHSWtBRmjAQOHISmxNzu9BSmxBRihHyatPz6/Lze7CTO3BSixHTS5BTC3DzW5ByyzPz+/OTy9AyexEze7ByixGyavKzO3FzC3AyWvBS+1BR+pAQKFCRGZExmjCxihBRylCSuzBSWvBS21BSOtBRSdAw+XAxCZDyexDSyzCTC1JzO5JTa7DSuzETW3BRqlAQWJDRWbOT2/Mzq9HzG3JzS5Kzi7BSStGS21CxSdCRmjAQOFAQSHAAAACH5BAEAAAAALAAAAAAWABYAAAaeQIBwSCwaj8ikcqkMCJjHwIBQgBIDhgMiUbUGFAtGw0GFfheHByQi4S6/E8pDUoFYLm5kAEPJaBAVGxIcER0JHlEfICEiIxUkGyUmIgknKIhXASkonCorgSwmKQGcKE9IAi0uLxUwMTJWMzQ1NiYwBLBQHws1N7avXgs4NjkcCblMATU6KhvGyG87PAnUKV1MAj0+2zIFp1bg4eJJdkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== view_choose-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBAQCBFRSVExKTDQyNPz69PTq5Pz+/OzaxOTKpAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARTEMhJq70466Cl+AMxBVwnFIVRAmQHCIeBrC1L3tQgJ/SaEbeeC1PLBHE2ybFI9A1HzstHEIK6YCmhDTmBybQaHYJn7QC5zKeytIQe1+pKNE6P2yMAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== view_detailed-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBFRSVExKTDQyNPz+/Pz69PTq5AQCBOzaxOTKpAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAQ+EMhJq7046817+MLQUQFRGMc4lQaSAkcMx3QltMmrDrSu/sCgEPgJhIiFk89DaL1qPRnlhsgBebWhdstVESIAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== view_icon-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBFRSVExKTDQyNPz69PTq5AQCBPz+/OzaxOTKpAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARWEMhJq7046z2DF0PlBeAVEERhiKhqHgWyUgEsX0KczFOO7JeBYciTCImc5ITIXDKHyqhU9AnRqq9UEVDTvmLbGhin2/qAliOUot5OLc81IO5+2+8WewQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== viewmag--22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBBQSFJyanKy2tLzCxHyChNTa3Nzq7Nz29Nzy9Mzy9MTu9OTy9Nzi5Oz6/OT29MTi5Kzi7NTy9KTm7JzW3ITO1Lzq7IzW5HzK1LS+vMTq7Jze7ITW3GTCzGS+zLTS1MzOzLzq9Kzm7Jze5ITW5HTS3FS2vLze5EzCzEyyvEyutJTa5NTu9ITa5FTK1ESirLTm7Mzi5FS6xEy2vESerESmtFSutESmrKyqrAz+/Dw+RAzi3ASutHRydAQCBAAAACH5BAEAAAAALAAAAAAWABYAAAbKQIBQGCgWh8jksCgYEAaCozIZKBgOiIRiwSgEpstCw/HYQiKRhBcMCBgQDodkMaFU0t9pQHCIyy0TFxgYEVF6GQ4LCQkaERscHR4RH3lUIAkWCyEiIyQlHiYjEJVIAQQJJ2gjJSUoKSorlHoCLBQcHC0lLikvHjCGejEiHBgeMjM0NRwPpFQFDBHFNjceHAjAYFWoI7cnCVE4OWxtex8QH1EBOjs4zUpGUjw6Pe3j2fP19u/47vrq9P3s/avno2BBf/MCClSob4iBIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 viewmag-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBBQSFJyanKy2tLzCxHyChNTa3Nzq7Nz29Nzy9Mzy9MTu9OTy9Nzi5Oz6/OT29MTi5Kzi7NTy9KTm7JzW3ITO1Lzq7IzW5HzK1LS+vMTq7Jze7ITW3GTCzGS+zLTS1MzOzLzq9Kzm7Jze5ITW5HTS3FS2vLze5EzCzEyyvEyutJTa5NTu9ITa5FTK1ESirLTm7Mzi5FS6xEy2vESerESmtFSutESmrKyqrAz+/Dw+RAzi3ASutHRydAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAbIQIBQGCgWh8jksCgYEAaCozIZKBgOiIRiwSgEpstCw/HYQiKRhBcMCBgQDodkMaFU0t9pQHCIyy0TFxgYEVF6GQ4LCQkaERscHR4RH3lUIAkWCyEiIyQlHiYjEJVIAQQJJ2gjJSUoKSorlHoCLBQcHC0lLikvHjCGejEiHBgeMjM0NRwPpFQFDBHFNjceHAjAYFWoI7cnCVE4OWxtex8QH1EBOjs4zUpGUjw6Pe3j2fP19u/47vrq9P3s/cunr9S8gAIRFhTCLAgAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== viewmag+-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBBQSFJyanKy2tLzCxHyChNTa3Nzq7Nz29Nzy9Mzy9MTu9OTy9Nzi5Oz6/OT29MTi5Kzi7NTy9KTm7JzW3ITO1Lzq7IzW5HzK1LS+vMTq7Jze7ITW3GTCzGS+zLTS1MzOzLzq9Kzm7Jze5ITW5HTS3FS2vLze5EzCzEyyvEyutJTa5NTu9ITa5FTK1ESirLTm7Mzi5FS6xEy2vESerESmtFSutESmrKyqrAz+/Dw+RAzi3ASutHRydAQCBAAAACH5BAEAAAAALAAAAAAWABYAAAbQQIBQGCgWh8jksCgYEAaCozIZKBgOiIRiwSgEpstCw/HYQiKRhBcMCBgQDodkMaFU0t9pQHCIyy0TFxgYEVF6GQ4LCQkaERscHR4RH3lUIAkWCyEiIyQlHiYjEJVIAQQJJ2gjJSUoKSorlHoCLBQcHC0lLikvHjCGejEiHBgeMjM0NRwPpFQFDBHFNjceHAjAYFWoI7cnCVE4OWxtex8QH1EBOjs4zUpGUjw6Pe3j2fP19u/4zT766vRI+fvHD4CPgwcJ9qg0UB85JA0dDjEQBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 view_multicolumn-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBFRSVExKTDQyNPz+/Pz69PTq5AQCBOzaxOTKpAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARTEMhJq7046813+MJQfUF4BURhHGO6noSBsEcNoDJtS4KcsJQe4ncZ1HYT47HDbDqfUAnJRJmKLIGCCjjJbmE5wBI3EyOFxKCPS1EiJW52dE6vZyIAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== view_sidetree-22:actions actions22 22:photo:22 22:R0lGODlhFgAVAIUAAPwCBFRWVFxWXFxaXExKTNTO1NTS1Nze3Hx6fLSutMzGzLy6vMTCxDQyNMzOzPT29Pz6/Pz+/PTu9Ozq7OTi5Pz2/Ozm7MzKzGxmbIyKjAQCBPTy9FROVFRSVPTq5OzOpMS+xPzu5OTKpExOTJSOlOzu7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABUAAAb/QIBwSCwaAQFBcqlsLgcBAnFQqBqqhwIiUVB4F4wGMeB4QMyPSCFQkEwmlMlCPKRC7pCKmjpxTyxzUwVmEBF6FxiDbxZyUnUFdxERhQUZbX4TDBlEAgUVkQ8DogEDAqYBTwEaAw54eQNusRMPs319Gp0PFZ8PAhMRGpLCwxOrFw/IFRuwwMICHAIEkhK4lxK0A7/Bkh0RHtvFAwp9D27MGugRAh4f29TithIW2c2SBOjgqwxv/AIS9cOEvQPBiBEFetsidOhAQFqEcCDgWLBAwR9AARFCuMPFAMwCEAsQpuMQQkS+EQ1SNkBAwuKwe+kiUDuSzU0JPyUm5HSj4Qi+Bp9A8QEIAgAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 view_text-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAIkhI+py+0Po2ShBlOxzbP7n2yaJoLm+ZTcxqHuC6hXzML2HVEFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= view_tree-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBAQCBFRSVExKTDQyNPz+/Pz69Pzu5PTq5OzaxBQOFOzKpFRWVFxWXOzexPTexCH5BAEAAAAALAAAAAAWABYAAARPEMhJq704g6A779kHCORAgNskFMYhakE8FkjyBcoWv+JwJItXaELYCTFHlCSpZKKcoB5jYHpOGgUadLKbIRw3jhEzQDyCSuI4zW673yhDBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 window_fullscreen-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIQAAPwCBAQCBNTW1NTS1MzOzMTGxLy+vLy6vLS2tKyurKyqrKSmpKSipJyenMzKzMTCxLSytFxaXPz+/Pz+9Pz+7IQCBMzOvMzOtPz+1MzOrPz+5Pz+3MzOpMzOnMzOxAAAACH5BAEAAAAALAAAAAAWABYAAAWxICCOZGmeKBqsbOu+rjAQRFEYxoEkibIwjUZMRnAUHjkEpPcLriLQqHQ6XRUk2Kw2O+lSKIUVoUKubLflikVcPnO75cvKkXZL4HG2pK31lilqc1lmfRNfgBQYGBlidl5fGhobGxqMAQNnXYaQkZOLjVgVmpsUkRoVnpZje2SkphtlGBUcbH+br5NptAF0rYe4G4plHSseaaW4irLDcxYOFtDRFhnU1B3X1zDa2indIwYhACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= window_nofullscreen-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBNTW1NTS1MzOzMTGxLy+vLy6vLS2tKyurKyqrKSmpKSipJyenMzKzMTCxLSytFxaXPz+/Pz+9Pz+7IQCBMzOvMzOtPz+5Pz+3MzOrPz+1Pz+zMzOpPz+xMzOxMzOnAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAbKQIBwSCwaj0hkYMlsOp9OwYBAKBQMhgMikVAsGI1GVEpwFB5ZBKT7DS8j8Lh8Pl8WJPiJfr/PTygUBUsEEhV4h4h+ExUUFoMVkIWJhxWLkBeDhZCGiXqbFRiYAYSanId7mxihSwOlphJ6gJ8ZGksOiqd/gKoYGRmipIh7gBSqvhkbtaOuw7sYn8mseJuxxcabGxwdmZ/EvL6f2o+Qz869yBUem9sBH4sYf7znG/Qb6h4gSx8fDh8W/wA1CBTYoSCIfFASQknCcIiBIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 wizard-22:actions actions22 22:photo:22 22:R0lGODlhFgAWAIQAAPwCBNzaTPz6BAQCBPz+BExKBMzOTPz+rPz+3ISCBPTyhISCLISChPz+xOTiVPz+/MTCxKSipKyqrExOTDw+PDQyNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAV+ICCOZAkEZqoKqoqKAzHAb1sIxhAQwWAQhRaJd0AcdgkhqaBAOBUL5WjAaD6TUqog0DAildqcg+cDtgaPACTCiM0AOhV6sG4DWOAHnf2uyfV1b1lsgVIwEgwTFHaGA2yKFYJgiJCSQo6JFJGGcJSalkKPn5wimZukAJWoIgYhACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= ================================================ FILE: ext/tk/sample/tkextlib/ICONS/tkIcons.kde ================================================ actattach16:act act16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBPz+/AQCBAAAACH5BAEAAAAALAAAAAAQABAAAAI2hAOCxg2h0nJHyEshi9HpxU1GOCLdZoKpQ15nibUoprKp9lh2oucUxsBRXsJh4Hjs/QTMpr8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actbookmark16:act act16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBCwqLLSytLy+vERGRFRWVDQ2NKSmpAQCBKyurMTGxISChJyanHR2dIyKjGxubHRydGRmZIyOjFxeXHx6fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVbICACwWieY1CibCCsrBkMb0zchSEcNYskCtqBBzshFkOGQFk0IRqOxqPBODRHCMhCQKteRc9FI/KQWGOIyFYgkDC+gPR4snCcfRGKOIKIgSMQE31+f4OEYCZ+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 actbookmarknew16:act act16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBCwqLLSytLy6vERGRFRWVDQyNKSipAQCBMTGxKyurISChJSSlJyanHR2dIyKjPz+xISGhPz+BGxubMTCBHx+fPz+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVfICACwWieY1CibCCsrBkMb0zchTEcNYsIiYHiwIOdEAvigdFQGE0Ix4NBbSAgsWjk+jBIAlcUYrJASChnSXZSoUDelKfoKpFALJA61ueGI2IAZmhogGFmCGGAgXsifiEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== actcheck16:act act16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBMT+xATCBASCBARCBAQCBEQCBAAAACH5BAEAAAAALAAAAAAQABAAAAM2CLrc/itAF8RkdVyVye4FpzUgJwijORCGUhDDOZbLG6Nd2xjwibIQ2y80sRGIl4IBuWk6Af4EACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actcross16:act act16 16:photo:16 16:R0lGODlhEAAQAIIAAASC/PwCBMQCBEQCBIQCBAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMuCLrc/hCGFyYLQjQsquLDQ2ScEEJjZkYfyQKlJa2j7AQnMM7NfucLze1FLD78CQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 actexit16:act act16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBDQyNHR2dCH5BAEAAAAALAAAAAAQABAAAAI4hI+pFrHb3nEg1iWiDiINCwYDko0V9XUTda6I1TIsUMpGinyzbB6ZeGuoEr+GUDL4CXqSphPhLwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== acthelp16:act act16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQ6XAQCBCyCvARSjAQ+ZGSm1ARCbEyWzESOxIy63ARalAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAQ/EEgQqhUz00GEJx2WFUY3BZw5HYh4cu6mSkEy06B72LHkiYFST0NRLIaa4I0oQyZhTKInSq2eAlaaMAuYEv0RACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actitemadd16:act act16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBARCZPz+/Mzq9BTC3ITC1HSyzGSivAw+XBSStIS6zHy2zAQCDFyatAQOHFSStEyOtAQSJBSq1DR2nCxunCRmlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVbICCOQTmeaCAMRIC+AVu47xkTBl2Ld16XQNYBQTQBVIOkMHFQJBeMI4tAbSSu2IRDSnhAvFfI97sFRM6RwOMacbjLKckVvgvIJ5EdSU7J648VgXQ7Dmd/hyJ+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 actitemdelete16:act act16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBARCZPz+/Mzq9BTC3AQCDAQOHFSStAQSJAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAQwEMhJq704681n+GAISoEwnGg6EAUQrEQsz4ThEkeu77kNIAagMEj0dY7IpHI58UcAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actlock16:act act16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaVAQCBKSipDQyNMTCxISChFxaLFxSJEQ+FExGHCQiDBwaDGxiLHxyNHRuPIR+TIyGZJSSfFxaRFxWJGRiLJyaXNzWpNTOnMzGnLy2hJSKTGReLKyqjPTu1NzarMS+jLSyfKyibJySXIyGVCQeDLSytPT29Ozu7OTi5NTS1KyurJSSjGxqVFxaXLS2tKSebOzuzLSufJSOXExGLGRiTExONAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaTQIBwGCgGhkhkQDBoEpLKQoBACAyOUID1qTVwoQGvMPxNFgVjAxp6QCQUicSCwVgkG44HJCKRRCYUCAxIFRYXhxgZGhYbHINEHR4fGCAhIiMkFSVKJicoKSoFKwMsLZtDLison6GjLA92qCueoAUvpC2xQhWqrLYDErmEMDEXlDIwMxAHukI0NS01EzY2NAmPAH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actredo16:act act16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBBxOHBxSHBRGHKzCtNzu3MTSzBQ2FLzSxIzCjCSKFCyeHDzCLAxGHAwuFDSCNBxKLES+NHSmfBQ6FBxWJAQaDAQWFAw+HDSyLJzOnISyjMTexAQOBAwmDAw+FMzizAQODDymNKzWrAQKDAwaDEy6TFTGTFSyXDyKTAQCBAwiFBQyHAwSFAwmHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ2QIBwSCwaj0hAICBICgcDQsEgaB4PiIRiW0AEiE3sdsFgcK2CBsCheEAcjgYjoigwJRM2pUK0XDAKGRobDRwKHUcegAsfExUdIEcVCgshImojfEUkCiUmJygHACkqHEQpqKkpogAgK5FOQywtprFDKRwptrZ+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 actreload16:act act16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBCRaJBxWJBxOHBRGBCxeLLTatCSKFCymJBQ6BAwmBNzu3AQCBAQOBCRSJKzWrGy+ZDy+NBxSHFSmTBxWHLTWtCyaHCSSFCx6PETKNBQ+FBwaHCRKJMTixLy6vExOTKyqrFxaXDQyNDw+PBQSFHx6fCwuLJyenDQ2NISChLSytJSSlFxeXAwODCQmJBweHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaBQIBQGBAMBALCcCksGA4IQkJBUDIDC6gVwGhshY5HlMn9DiCRL1MyYE8iiapaSKlALBdMRiPckDkdeXt9HgxkGhWDXB4fH4ZMGnxcICEiI45kQiQkDCUmJZskmUIiJyiPQgyoQwwpH35LqqgMKiEjq5obqh8rLCMtowAkLqovuH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actrun16:act act16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+/ISChKSipMTCxLS2tLy+vMzOzMTGxNTS1AAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARlEMgJQqDYyiDGrR8oWJxnCcQXDMU4GEYqFN4UEHB+FEhtv7EBIYEohkjBkwJBqggEMB+ncHhaBsDUZmbAXq67EecQ02x2CMWzkAs504gCO3qcDZjkl11FMJVIN0cqHSpuGYYSfhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== actstop16:act act16 16:photo:16 16:R0lGODlhEAAQAIUAAASC/Gw6NGQuLHQ6NGQmJFweHFQaFPTm5PTa3PTW1Oy+vOS6tNSinKReVDQWFPz+/Nx6fNyCfNyGhNR+dMxybMRiXLxGRIwWFNx2dNx+fNx2bMxuZLQWFBwWFPTu7Pzy9NRqZNRuZMRSVLwmJGwWFNR2dMQiHPTKxMxmXMQyLMxmZNx6dMxiXMRSRMRaVKxybMxaVEQWFMQuJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaaQIAQEBAMCAWDYcgkHhAJxYLRcDQBggckIplQKpaLdRh4YDIaSWa94Vw6woAHgv6AMKGPaMQhwQMJJRkfhHmEJhdvRCcgGSCEkCgpbnAECiorGYYfLCItlAAFCygQj5AfbYlwBQwVE5AukG6KBi8tMC0fLi0pHxyzcAAxFxwmMny/wEwOxMm/qlcdJCSJ1H5XQh3a28HY3kx+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 actundo16:act act16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBBxSHBxOHMTSzNzu3KzCtBRGHCSKFIzCjLzSxBQ2FAxGHDzCLCyeHBQ+FHSmfAwuFBxKLDSCNMzizISyjJzOnDSyLAw+FAQSDAQeDBxWJAwmDAQOBKzWrDymNAQaDAQODAwaDDyKTFSyXFTGTEy6TAQCBAQKDAwiFBQyHAwSFAwmHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ1QIBwSCwaj0hiQCBICpcDQsFgGAaIguhhi0gohIsrQEDYMhiNrRfgeAQC5fMCAolIDhD2hFI5WC4YRBkaBxsOE2l/RxsHHA4dHmkfRyAbIQ4iIyQlB5NFGCAACiakpSZEJyinTgAcKSesACorgU4mJ6uxR35BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actunlock16:act act16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaVAQCBKSipDQyNMTCxISChFxaLFxSJExGHEQ+FCQiDBwaDBweDGxiLHxyNHRuPIR+RIyGZJSSfFxaRGxmLJyaXNzWpNTOnMzGnMS+jJSKTGReLKyqjPTu1NzarLSufKyibJySXIyGVGxiNFxaXLSytPT29Ozu7OTi5NTS1KyurGxqVCQeDJSSjLS2tNTW1KSmpGRiLKSebOzuzJSOXExONExGLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaVQIBwOAwYA8SkMCAYOAnKYiFAIAQGyOgVCggYuEovVxztMpdnwAGRSCgUCwOjIeQ6HpCIZDKRUNYMRBUWF4UYGRoWGxyBRR0eHxgaICEiIyR0QyUmJygpKgUrAxMsLUQlKyieoKIuEAunK52fBS8DLiywQySpnjC1Mbi6QjIzNBeSIBY1EQfDQgosLAEUNjY3Co1DfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== appbook16:app app16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBAQCBDyKhDSChGSinFSWlEySjCx+fHSqrGSipESOjCR6dKTGxISytIy6vFSalBxydAQeHHyurAxubARmZCR+fBx2dDyKjPz+/MzKzLTS1IyOjAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVkICCOZGmKQXCWqTCoa0oUxnDAZIrsSaEMCxwgwGggHI3E47eA4AKRogQxcy0mFFhgEW3MCoOKBZsdUrhFxSUMyT7P3bAlhcnk4BoHvb4RBuABGHwpJn+BGX1CLAGJKzmKjpF+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 appbookopen16:app app16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBExCNGSenHRmVCwqJPTq1GxeTHRqXPz+/DwyJPTq3Ny+lOzexPzy5HRuVFSWlNzClPTexIR2ZOzevPz29AxqbPz6/IR+ZDyKjPTy5IyCZPz27ESOjJySfDSGhPTm1PTizJSKdDSChNzWxMS2nIR6ZKyijNzOrOzWtIx+bLSifNTGrMy6lIx+ZCRWRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaeQEAAQCwWBYJiYEAoGAFIw0E5QCScAIVikUgQqNargtFwdB9KSDhxiEjMiUlgHlB3E48IpdKdLCxzEAQJFxUTblwJGH9zGQgVGhUbbhxdG4wBHQQaCwaTb10emB8EBiAhInp8CSKYIw8kDRSfDiUmJ4xCIxMoKSoRJRMrJyy5uhMtLisTLCQkC8bHGBMj1daARgEjLyN03kPZc09FfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== appboxes16:app app16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBMT+xAT+BASCBATCBMT+/AT+/ASChATCxPz+xPz+BISCBMTCBAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARaEEgZwrwYBCFqvhs3DNYXjChRlWBRjIRqGN4UuEUczMZxsDeXykdEsDQVVSLhQxhBCkVlmXA+KVHFYhFYOoHbMGN6pTQaW8YYiQmcG+q16a0+Zipw+4e9B/gjACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= appbox16:app app16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBPz+xISCBMTCBAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANECKoR6ys2IVqokF08yMTA1gwkYX5WQK5ma4VceTYPxXnBWdtY6+0834/Bowgzm6APWRQcH4TiMhPK2WYRiZWW7XK7/gQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== appbrowser16:app app16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxONCROfCRKfKx6LNy+bNTOpGSS1DRupAwyXBRSnPTSjPTqvOzqzMzSvHSSlKy6ZDxutAxCpBQ2XBxepLTKvPzqzPzy5OTShLS2dLSqRFR2jBRerBQ+jOTixOzetNS2XHx6XDR2tCRexBwyTDyKzOTavPzq1OzKdCx23BRKtCQ6VCQmHFSa7IyirOzSnGSGpIR+bFSO1DyK7DR+5CRixBw2VDQuHFye7IS27NzGXISuhEyS5DR25BRWxBQ+lBQyXCQqPCxSfGyu7GyerKy2ZFR+rERqfCRmxBROtBQ+fBwuTBwmNDSW9JyabLyqRIx+TExSXBQ6bAQCBBQ6ZBxapDR+zBxq3LyaLJySRHxqPGxeNBxGbCRmrHRyRERONDRKNDQ2JCQuLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAeygACCg4SFhgABAQIDh4MBBAUGBwgDCYcKCwwNDg8QERIThRQVFhcNGBkaGxwdoYMDHhcXHxggISIjEiSvJSYXJwsoISkpIyorLIIDLS4WLzAxMjM0NSo2N8o4OS46OzwzPSk+P0BBgkI8Q0NERUZHCEhJSktMgwk4Qy1NTk9QUVJLphCiUsWKlStYsmjZQiJgIS4KuijQ4iXAFxYCDVFJwGUFmDBhMjYSw0KMyEYoBfkJBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 appcalc16:app app16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBISChPz+/AQCBCH5BAEAAAAALAAAAAAQABAAAAI4hI9pwe0Ogpi00hHF2LzzzFlTsIHD45SSx6oCeW4wjK2tl83y7t64pIsJaxrfh2bEAJIlhRPhLwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== appclock16:app app16 16:photo:16 16:R0lGODlhEAAQAIIAALy+vAQCBPwCBMQCBIQCBISChPz+/MTCxCH5BAAAAAAALAAAAAAQABAAAANbCLHcrSLKOZcYmDSCsR1aUABAsXDDJwJGa5SBFwgaWxbCG3CWaBwG3C8Y67FawpYiNQscg65fsVkYuoAmJs1pBR522lQB6ILJLqHRwQQOZzYdZnw+dzruDIA/AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 appdate16:app app16 16:photo:16 16:R0lGODlhEAAQAIQAAASC/AQCBPzerPyqXMRaBIQCBISChPz+/KSipMTCxPz+BMTCBPwCBPz+xPzCxMQCBISCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVxICCOQGCeJjkGwkC8RFEEavkax2G8dB0QuRyhhzoBg8MSYsncJXKJZIDZHCoWP1ogGIwGrtnSgUFmHLyNRHhrdpjRamnO/SYkromHdnxwnwkKVxByZW8DgQsQM2JcfwZXO0MBCZSVBgMuLzJaRZ0pfiEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== apppencil16:app app16 16:photo:16 16:R0lGODlhEAAQAIMAAASC/IQCBMQCBPzCxAQCBPz+/MTCxISChDQyNKSipEQCBAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARDEMhJZRBD1H2z3lMnjKCFjUJQimOgcmcbELCXzjXq0hV785WCQYcDFQjDXeloMByKG6YTAdwIDAlqSZJSVFeKLcUfAQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 appsheet16:app app16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBAT+/Pz+/KSipPz+BAAAAAAAACH5BAEAAAAALAAAAAAQABAAAANFCBDc7iqIKUW98WkWpx1DAIphR41ouWya+YVpoBAaCKtMoRfsyue8WGC3YxBii5+RtiEWmASFdDVs6GRTKfCa7UK6AH8CACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= apptool16:app app16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBISChGRmZMTCxKSipLS2tHx6fPz+/OTm5FxaXOzu7DQyNMzOzAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAReEMhAq7wYBDECKVSGBcbRfcEYauSZXgFCrEEXgDCSeIEyzKSXZoBYVCoJVIqBGByKu0Cy8QHxmgNngWCkGgqsGWFseu6oMApoXHAWhWnKrv0UqeYDe0YO10/6fhJ+EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 apptools16:app app16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBExKTERCRAQCBOzu7Nze3MzKzLy+vCxqZBQ2NJyanKyqrGRiZDRydKza3FRWVPT29LSytDw6PMTm5EySjCxaXGRaJFSanCRSVGxqbPTmvMSqVJTW1GSurHS6vOzq7KSipISChFRKHJSGNPz23GxKFBQ6PKyurCwqLMyufJx2RAQGBJSWlEwyDIRiLNy+lLSKVDwmDJRuNOTOrLyabGRCFDx2dKSCVOzWtHzCxOTGnNSyhAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAahQIBwCAgIBAOiUiggFAyHASKxDAwUC8Zg0HAglA9IZPGQABoTSqJCFTIOEIsFgHBcEhhHUpKJFCwaGxYYHB0VEx4IEh8gIQwiIyQbJRMcHokmEicfDygAkCkqJQgIGG0rLElCLS4vMCWqQwMCQg0UMTIzNDVLQjaIGDE3ODQlS785CEkxKjowvEOHybG4O6JDCdNKuDUxRAmxRDHeveUAfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== appuser16:app app16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+/MTCxISChMT+/ATCxASChFxaXAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARaEMg5gw00yyDGIAR1YUDggeFWFIZhnSBZrsZxdIOFEGTA2oeBAHeyuGwvzxBlYdUOLROMFzDQntJPrNoqAKUBaqnV+k57ZORruykHDj2LqIzUVKp1u0iuB/gjACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= appusers16:app app16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBMTCxISChAT+BMRaBPyqXARCBPz+/FxaXAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARLEIRJa5Ui673nsGAgeKE1Bl9AUEXbiqTlFlZaGUZoszm4BzhDAVf5BYbAXI+TAR6CS2ZGSZSEiIIqYIsSIEaJ7GRrlY7J1lKA7I8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= appwp16:app app16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBKSinJyOfPz27Pzy7AwKDExOTJyWlERCRKSelPz69LyyrKymnPz+/MS2fDQyJAQCBOTazLSiXOzivMS2jKSSVOzmxPz25NzSpPTu5KyebOzixNTGjOTWpMSydMSybCwqFGReVKyaXNzSnGxeNJSCVMS2nPz23MSuZIR+bJyShLyqnOTOtGxiXIR6XOTSvIx6RMSubIyCdKSalMS6pOTWxMzKvKSabJyKTOzezHxuPGRmZKyurMTCvPTq3AAAACH5BAEAAAAALAAAAAAQABAAAAajQIBwCAgIiEhiYEA4FgwHRDKhIBAWz4OhgGQ0FAPHA7qFEBONb0Qy0ULeQ2+aUrFcMI+3GYBOZzQbHB0eHyAhIQByDREiEwMjFRIkJQImAgJ+jScjHigkKSorLC0AKg2NFSMoki4qCy+IQgITKDAxkjIzNDWkQxQoJaskMgk2Eb1DNzgoOCoHDDY5yEIwJToAOzw9ET7TQiREAhkZ3kmy5QB+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 cal1day16:cal cal16 16:photo:16 16:R0lGODlhEAAQAIIAAAQCBPwCBAQC/AQCjPz+/MTCxKSipAAAACH5BAEAAAEALAAAAAAQABAAAANOCLrMEUDIOUS9AFLLhx8LIRZjKYZmMRCkaChFLHty/AIiS3y6q+QtT49wq8VotRtQJGwRf6Zmrlj7DJLQXsupTJmeEIN4TB5nII20wp8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= cal5days16:cal cal16 16:photo:16 16:R0lGODlhEAAQAIIAAAQCBPwCBAQC/AQCjPz+/MTCxKSipAAAACH5BAEAAAEALAAAAAAQABAAAANMCLrMEUDIOUS9AFLLhx8LIRZjKYbj55GioRRwoQ5x4QIiIdMmcec7jy53q81qP9OO5VMAj8RXTFWzOZW95HDLdEEM4LA4nIE0zgp/AgAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 cal7days16:cal cal16 16:photo:16 16:R0lGODlhEAAQAIIAAAQCBPwCBAQC/AQCjPz+/MTCxKSipAAAACH5BAEAAAEALAAAAAAQABAAAANPCLrMEUDIOUS9AFLLhx8LIRZjKYbj55GioRRwoQ5x4QIiwcp0fucsj873qvGMv5Jw2FIACUsW4WakGW1O046I05qmGYBhTC6TM5CGWuFPAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 calappointment16:cal cal16 16:photo:16 16:R0lGODlhEAAQAIMAAAQCBPwCBAQC/AQCjPz+/MTCxPz+BISCBISChKSipAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAARbEMhJaQhA6D1E/wDGeeRgDhOhFoTBEi+REgdrIHScSEVvAD9Xr7cDqGSGpFEnQSqTv2NxCFQOiU1VEAiTZmstHFg1vQKuw+LxxfYaV/AuOQRI2O/4ewhT6Uv8EQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 calbell16:cal cal16 16:photo:16 16:R0lGODlhDwAOAIIAAPwCBISCBPz+BIQCBMTCxISChPz+/AQCBCH5BAEAAAAALAAAAAAPAA4AAAM+CLrR+zCIAWsgLVRGRBhOVQiG94WPVAbHaZHYAWqRYLbge88RsbInGuBCEhRYrZYm4xk4nYdoKzKIbiKHawIAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== callist16:cal cal16 16:photo:16 16:R0lGODlhEAAQAIMAAAQCBPwCBAQC/AQCjPz+/KSipPzerMRaBEQCBAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAARDEMhJaQhA6D1E/wDGeeRgDhOhruyatjBRSIRxxOsMEAdC0BUZDcfSEYvDo3Bn++2Cxt7RqFxWhZiCdsvdhjCVsMQfAQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 calmonth16:cal cal16 16:photo:16 16:R0lGODlhEAAQAIIAAAQCBPwCBAQC/AQCjPz+/MTCxKSipAAAACH5BAEAAAEALAAAAAAQABAAAANSCLrMEUDIOUS9AFLLhx8LIRZjKYbiRxLFIBpK0Q6z7MkwkJIe8b0KEeuWchFysuStVsjtfMbeMQitWpG25YfmNK1WU53XNIUYzug0OgNpuBX+BAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 caltoday16:cal cal16 16:photo:16 16:R0lGODlhEAAQAIMAAAQCBPwCBAQC/AQCjPz+/MTCxKSipPyCBMRaBPyqXAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAARTEMhJaQhA6D1E/wDGeeRgDhOhFmurpi5LyIQhFfiBIAfuFzaAioBIJBCummRYPCaDPh3vhwsOZdihNfa8Ub/AJXemFZPPNBvGwG672yFMZS7xRwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== caltodo16:cal cal16 16:photo:16 16:R0lGODlhEAAQAIMAAAQCBAT+BAQC/AQCjPz+/MTCxPzCxKSipPwCBMQCBIQCBAAAAAAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAARaEMhJaQhA6D1E/wDGeeRgDhOhFmurpi5LyMYhFXiuFwZiA6qZYbbqJX5BIw2RAPxwAAWCyWMCCsiXFGEEErKz6LQZfOqiTR1YJiGq1rFyyHmo2+/1EKbCl/gjACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= connecting16:connect connect16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBPz+BMTCBISCBAQCBPz+/MTCxMTGxISChFxaXMzGzKSipAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARaEMhJZbihUiz60FPnfaA0iBpBVGdHEYWxToEoSHBRHHM9AgSEQRcj+AYkYAJxIPKQFUJiOdTJQFIDU6dYzKKFhTCM+E5g4mXaDAyrlogEG+DGTecA7wsP8EcAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= connectno16:connect connect16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBPz+BMTCBAQCBERCBPz+/MTCxMTGxISChFxaXMzGzKSipAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARPEMhJq704axBEHoPUEdhQGMNYFuwxkKInDYjBniEnwMCQIIebSzXx/WwsFK+YMABZikWuYlrUCtZpEYv4WRPaHhb064YB41kCfJFSQBh/BAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 connectyes16:connect connect16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+/KSipDQyNMTCxMTGxISChFxaXMzGzAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARaEMhJZxCjgsAtDtUlCOA1gJQ4kl/IDatAoF7xxkS6GgEBr6jAobCyBX42SQBxMOx6A8MhiGASR8YDgrYsNEeJ0zaEGZY7uoH2oB6nOUwtbdLaVOeTUwo/8UcAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= devcdmount16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXISChNTS1MzKzMTGxMy+vNSytAQCBOzq7OTi5Nza3Oy6vPy2tOTStPz6/Ozu7Nze3MTKxOS2tOzOvNTqvLT2tDw+BPTy9MzOzLS2tPy+tLz+tLz2tLSynLzqvLzavLTOtNTW1KSipPz+/LzKvMTCxDQyNASCBARCBDTSJIT+bAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAa0QIBQGBAYA8Ok0DggFAwHBEIJECQUi8GT0XBMh9YHJDKQTBqUiuUCVmAeiYzmsKlwOt/AAKFIFAIIFx4WHyAhUwIDIgsZFyMkFxchJSYmiBkSBBoIJJwIGgOhiCYFJSEnFyQjFwNZewABISAfFiYnCAEmCREIrwAIFhwVGwcaBAkPGApsQsAVFA0GBQMRbxBTKM0ODQwTEq192ClDgROkBHvYKuNJUu5CKCorX1RDKCkpUn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= devcdunmount16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXISChNTS1MzKzMTGxMy+vNSytAQCBOzq7OTi5Nza3Oy6vPy2tOTStPz6/Ozu7Nze3MTKxOS2tNzmvLT2tDw+BPTy9MzOzLS2tPy+tLz+tLz2tLSynLzqvLzavLTOtNTW1KSipPz+/MTCxLy6vDQyNOTm5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAapQIBQGBAYA8Ok0DggFAwHBEIJECQUi8GT0XBMh9YHJDKQTLqUigWsuDwSmMxBQ9lwvoEBQpEoBBAWHRseHyBTAgMhCxgWIiMWFiASJCSHEgQSGQgjmwglGKCHBQUSICYWIyIWAwshIVMBIB8eFSQmCAEFCREIekIIFRsUGgcZEgkPFydrvxUUDg0GBSEREGJfv9AMEySsJxDYQ4DcEhh64UpS6lTs7QB+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 devdiskmount16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBDQyNIRuVKyCXMSKROzSrOzKpOTGnLSafLySZKxuLMSOVPTWvPzixLSehNyibOzOrGxaVJx+XOzGnFw2FJRuPKx+TPTSrHRWPKyKZPTOpHxOJKyKXFw+HKSipISChMTCxFxaXIRiPNSWXExOTOS2hLR+PLRyLPTWtMyOTASCBARCBPz+/DTSJIyKjIT+bAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaTQIBwCAgYA8SkMCAYDARI5ZJQMBwQiWgyoFgwrA3HQ7scQAqFAcEQOUi0zAkFUSFYLghMBloUCDQNGxwdHhwHekcfICEhICIfIxkLJBABJUYCICABIhAOBiYnKJaXmH4CGSkYCCqkSAEfTKenrkOwsrQll0IrS7G5uwArLLaxLbXCLsTFLyDBKy4wZEVHvCwsRn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= devdiskunmount16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBDQyNIRuVKyCXMSKRPTWtOzKpOTGnLSafLySZKxuLMSOVOzOrPzm1LSehNyibGxaVJx+XOzGnFw2FJRuPKx+TPTSrHRWPKyKZPTWvHxOJKyKXFw+HPTOpKSipISChMTCxFxaXIRiPHxaNLRyLNSWXExOTPzixOS2hLR+PMyOTPz+/IyKjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaIQIBwCAgYA8SkMCAYDARI5ZJQMBwQiWgyoFgwGgiD46FdDiCFwoDQAEe0TMkEQSFULIcLBloUCDIaDRscHRsNHhhHHyAhISAiHyMkJSYQASdGAiAgASIQKA0pKguXmJl+AiQGFwgrpUgBH0yoqK9DsbO1J5hbsrq8SrgstlJFHy0gwMVFR1J+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 devfloppymount16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBAQCBMTCxARmZPz+/FSWlLSytKSipERCRIyOjISChOTm5HRydNza3GRiZFRSVASCBARCBDTSJIT+bAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVrICCOQBCQKBkIw5mqLFG47zoQ+FwbN57TosDhgPD5dMEEIqE04kwlBWKBUEiNVYFpyqAyGEUCgqEtERiNNMLhQKzLQYJg7n7Y4aMAwbCUPvAQeWNgfzQQETAIhSMQEogwgBITQEGGEREmfiEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== devfloppyunmount16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBMTCxARmZPz+/FSWlLSytKSipERCRIyOjISChOTm5HRydNza3GRiZFRSVCH5BAEAAAAALAAAAAAQABAAAARcEMgJQqCYBjFu1hxReN82EOhYGieaklJwHIjrqnGCJLqNWhUFYoFQCG1FgWXIIDIYNQKCoawQGI0swuFAbKsxgmDsfZjBkwDBsNM90Jot9A3DbBD0Dwiur9QnfhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== devnetwork16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBAQCBISChPz+/Nza3ARaZESanCyKlARudARGTLy+vNzq7ARmbMTCxARufAROVMzOzKSipARyfOzq7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVmICAGZFmKQiACweCSBImq41AYB5IodLq2hwWO0ejRWDac48Gb/QKNqNRoqspmrVcAUuIJBANS8sBIFCORUgooPEh4J8B67NgdsVBp9C5XWfl9LRMTCyReX19hARNojWlWLH+AAH4hACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= devpc16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBISChHx+fPz+/AQCBAQC/AT+/AQCxAQChAT+BLy+vAR+BAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARYEIAgqK1YzsG754QUDERpmkEpkkXrtoK6EcVgHIibhnNx564Yb0TDvQq7FQ34EiqPOhnREqhWSUPsyZSQAbbg7GcMEgwUiYVivTa1R+y4XEGoWO/4AMAfAQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 devscanner16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBAQCBPz+/MT+/ASChARCRATCxMTCxFxaXKSipDQyNAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARTEMgJgqWBVivEldkUdKSXhVjZfenommglDERh3Tc4E4ZRHAGgkEPr9X6H5AHBERSMRyWzkug8jQXFEhWoOo8dRYxqLXSmGjIJnVaz29Q3fAP3RwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== devscreen16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXFRSVPz+/PT29OTm5OTi5DQyNDw+PERGRExKTHx+fISChIyKjHRydFxeXDQ2NCQmJBQSFAQCBERCRMTGxHR2dGRiZExOTDw6PCQiJAwODCwuLFRWVOzu7BweHAwKDCwqLHx6fBQWFGxqbGRmZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAanQIBwSCwKAwKkMslEAgSDqDRKqBYKhkNgcDggEorkMrDQchkNhuOhgEQkk0l5S2lUGpYLJqPZTAwMHB0DCmhqAW0Rfh5zAxgOkBcCFAcfIBMECxwBBAEPFw8dChkhcBMDDAcdnQqtFKSWcQMimx4dGRkQBxGxsg6bBQEawx8jl3GnJFoFHRNXVVNRJYIFDAsL1tgiDiQXFx0HABwcXeQH5OjkRutEfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== devspeaker16:dev dev16 16:photo:16 16:R0lGODlhEAAQAIMAAPwCBFxaXAT+/DQyNATCxMTCxPz+/AQCBKSipASChAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAARWEMgJQqCXziDG2JoUEENhZBkmHIWJVptAmqcIW/Js1MiF56TBzkckAAcHoa9nMRKeA4TyJk0knsHhTeK5khBaH2VwLYVh40TJhQ6RzeIQV32Quz8hfwQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== editcopy16:edit edit16 16:photo:16 16:R0lGODlhEAAQAIUAAFxaXPwCBNze3GxubERCRPz+/Pz29Pzy5OTe3LS2tAQCBPTq3PTizLyulKyqrOzexLymhLy+vPTy9OzWvLyifMTCxHRydOzSrLyihPz6/OTKpLyabOzu7OTm5MS2nMSqjKSipDQyNJyenLSytOTi5NTS1JyanNTW1JSWlLy6vKyurAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAAaUQIBwCAgYj0eAYLkcEJBIZWFaGBie0ICUOnBiowKq4YBIKIbJcGG8YDQUDoHTKGU/HhBFpHrVIiQHbQ8TFAoVBRZeSoEIgxcYhhkSAmZKghcXGht6EhwdDmcRHh4NHxgbmwkcCwIgZwqwsbAhCR0CCiIKWQAOCQkjJAolJrpQShK2wicoxVEJKSMqDiAizLuysiF+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 editcut16:edit edit16 16:photo:16 16:R0lGODlhEAAQAIEAAPwCBAQCBPz+/ISChCH5BAEAAAAALAAAAAAQABAAAAIwhI9pwaHrGFRBNDdPlYB3bWHQ1YXPtYln+iCpmqCDp6El7Ylsp6ssR1uYSKuW0V8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= editdelete16:edit edit16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbPT29GxubMzOzDQyNIyKjHRydERCROTi3IyKhPz29Ox6bPzCxPzy7PTm3NS6rIQCBMxCNPTq3PTi1PTezMyynPTm1PTaxOzWvMyulOzGrMymhPTq5OzOtNTKxNTOzNTCtNS+rMSehAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaKQAAgQCwahcihYMkcBAiBpLJApRoOBWgyIKhSEQkFgrBAcr1URiPhKAsDD3QB8RhA3FM0IlLHnyUTVBMSFBUWfl0XGBMTGBcZGodmcQWKjpAbHIgIBY2LHRoempOdjooTGx8giIOPFYofISJ+DyMXI6AfFySyfiUmJSUnKBYcICIpfgELzM3OZX5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= edit16:edit edit16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBFxaVMR+RPzKjNze3AQCBMR6RPzGjPyODPz+/MzOzPyKDPyKBPz29OTWzPyGDPyGBOx6BOza1OR2BKROBNSOXKRKBBwOBOzu7PTWxPzizOySZPyCDFxaXOy2lNRyRMxmJCQOBPTm1OzStPTKrMR+XIRWLFxGNCQSBDQyNIRSNDQuJERGRLyqlNzSvIx6ZKRuVEw6LLSyrLymhKSShBwaFFROTJyWjMS+vNzW1OTazNzKrHRqXOzezOTOpPTq3OzWvOTStLyedMS+rLy2pMSynMSulAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAewgAAAAYSFhoQCA4IBBI2OjgUGBwiLBAmXlpcKkgsMlZcJBA0JDpIPEBGVjwkSBgOnExSfmBIVBxAMExYXswkYGRobHLq8gh2PHhoeHyAWIYKzIiMkJSYnKCnQg5YNHtQqKywtK9qMBC4vMDEBMjIz2dCMDTQ1Njc4OToz5PEEOzw3ZPToMcLHO23HfogQ0QMIkCA+hPBbhAPHECJFjMyYIUQIvEUpUqwQOXKkSEF+AgEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== editpaste16:edit edit16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBCQiFHRqNIx+LFxSBDw6PKSaRPz+/NTOjKyiZDw+POTe3AQCBIR2HPT23Ly2dIR2FMTCxLS2tCQmJKSipExGLHx+fHR2dJyenJyanJSSlERCRGRmZNTW1ERGRNze3GxubBweHMzOzJSWlIyOjHRydPz29MzKzIyKjPTq3Ly2rLy+vISGhPzy5LymhISChPTizOzWvKyurPTexOzSrDQyNHx6fCwuLGxqbOzKpMSabAQGBMS2nLyulMSidAAAACH5BAEAAAAALAAAAAAQABAAAAa7QIBQGBAMCMMkoMAsGA6IBKFZECoWDEbDgXgYIIRIRDJZMigUMKHCrlgul7KCgcloNJu8fsMpFzoZgRoeHx0fHwsgGyEACiIjIxokhAeVByUmG0snkpIbC5YHF4obBREkJCgon5YmKQsqDAUrqiwsrAcmLSkpLrISLC/CrCYOKTAxvgUywhYvGx+6xzM0vjUSNhdvn7zIMdUMNxw4IByKH8fINDk6DABZWTsbYzw9Li4+7UoAHvD+4X6CAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 editshred16:edit edit16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbGxubMzOzPz69DQyNIyKjERCRPz29PT29OTi3IyKhPz27PTu5PTy5Pz6/Pzy7PTq3OzexLyqlPTm1PTizOzavLyqjOzWvOzaxLyifOzizOTOpAQCBOzezAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaEQAAgQCwahcihYMkcBAiBpLJApRoOBWgyIKhWEQkFYYHkeqkMxKFBFpq9jgdkEGlPqwrJhCIY2N8FFRYUFxcYGX9dgRKEGhiHiYEOhBcbGBwdiQEOARcBGwEeAZllAgEUnQEfoQEgmp4hrCKtrwEYsrRlTiMBJAG8syN/IyMAxMXHSH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= edittrash16:edit edit16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBAQCBKSipFxaXPz+/MTCxISChDQyNCH5BAEAAAAALAAAAAAQABAAAANQCKrRsZA5EYZ7K5BdugkdlQVCsRHdoGLMRwqw8UWvIKvGwTICQdmGgY7W+92GEJKPdNwBlMYgMlNkSp3QgOxKXAKFWE0UHHlObI3yyFH2JwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== fileclose16:file file16 16:photo:16 16:R0lGODlhEAAQAIQAAPwCBCQiJBwaHAQCBDQyNDw6PFxaXFRSVERGRCwqLAwODGRiZHx6fPz+/GxqbAwKDCQmJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVaICCOZGmeqBgEwjCkRGEcSKK4JrEcBrMgAdeLVDg0GguGsYEbBQyGYyN6FDoPDIf0+LCKBIgetQERDgGDBGIpNY8GioAU0m6KXFw883w3+/l9f4AkfimGIn4hACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= filedocument16:file file16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJSWjPz+/Ozq7GxqbJyanPT29HRydMzOzDQyNIyKjERCROTi3Pz69PTy7Pzy7PTu5Ozm3LyqlJyWlJSSjJSOhOzi1LyulPz27PTq3PTm1OzezLyqjIyKhJSKfOzaxPz29OzizLyidIyGdIyCdOTOpLymhOzavOTStMTCtMS+rMS6pMSynMSulLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaQQIAQECgajcNkQMBkDgKEQFK4LFgLhkMBIVUKroWEYlEgMLxbBKLQUBwc52HgAQ4LBo049atWQyIPA3pEdFcQEhMUFYNVagQWFxgZGoxfYRsTHB0eH5UJCJAYICEinUoPIxIcHCQkIiIllQYEGCEhJicoKYwPmiQeKisrKLFKLCwtLi8wHyUlMYwM0tPUDH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= filefind16:file file16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBCQmJDw+PBQSFAQCBMza3NTm5MTW1HyChOT29Ozq7MTq7Kze5Kzm7Oz6/NTy9Iza5GzGzKzS1Nzy9Nz29Kzq9HTGzHTK1Lza3AwKDLzu9JTi7HTW5GTCzITO1Mzq7Hza5FTK1ESyvHzKzKzW3DQyNDyqtDw6PIzW5HzGzAT+/Dw+RKyurNTOzMTGxMS+tJSGdATCxHRydLSqpLymnLSijBweHERCRNze3Pz69PTy9Oze1OTSxOTGrMSqlLy+vPTu5OzSvMymjNTGvNS+tMy2pMyunMSefAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAe4gACCAAECA4OIiAIEBQYHBAKJgwIICQoLDA0IkZIECQ4PCxARCwSSAxITFA8VEBYXGBmJAQYLGhUbHB0eH7KIGRIMEBAgISIjJKaIJQQLFxERIialkieUGigpKRoIBCqJKyyLBwvJAioEyoICLS4v6QQwMQQyLuqLli8zNDU2BCf1lN3AkUPHDh49fAQAAEnGD1MCCALZEaSHkIUMBQS8wWMIkSJGhBzBmFEGgRsBUqpMiSgdAD+BAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 filenew16:file file16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJyanPz+/Ozq7GxqbPz6/GxubNTKxDQyNIyKhHRydERCROTi3PT29Pz29Pzy7PTq3My2pPzu5PTi1NS+rPTq5PTezMyynPTm1Pz69OzWvMyqjPTu5PTm3OzOtOzGrMSehNTCtNS+tAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ/QAAgQCwWhUhhQMBkDgKEQFIpKFgLhgMiOl1eC4iEYrtIer+MxsFRRgYe3wLkMWC0qXE5/T6sfiMSExR8Z1YRFRMWF4RwYIcYFhkahH6AGBuRk2YCCBwSFZgdHR6UgB8gkR0hpJsSGCAZoiEiI4QKtyQlFBQeHrVmC8HCw21+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 fileopen16:file file16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBOSmZPzSnPzChPzGhPyuZEwyHExOTFROTFxaVFRSTMSGTPT29Ozu7Nze3NTS1MzKzMTGxLy6vLS2tLSytDQyNOTm5OTi5Ly+vKyqrKSmpIyOjLR+RNTW1MzOzJyenGxqZBweHKSinJSWlExKTMTCxKyurGxubBQSFAwKDJyanERCRERGRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaRQIBwGCgGhkhkEWA8HpNPojFJFU6ryitTiw0IBgRBkxsYFAiGtDodDZwPCERCEV8sEk0CI9FoOB4BEBESExQVFgEEBw8PFxcYEBIZGhscCEwdCxAPGA8eHxkUGyAhIkwHEREQqxEZExUjJCVWCBAZJhEmGRUnoygpQioZGxsnxsQrHByzQiJxz3EsLSwWpkJ+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 fileprint16:file file16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBFRKNAQCBPz+/MTCxExKLPTq5Pz29Pz6/OzezPT29PTu7PTy7NzClOzm1PTu5LSabJyanPTm3FxaXOzCjOTKrOzi1OzaxOTSvJyenGRmZLyyTKSipDQyNERCROTi5Hx+fMzKzJSSlIyOjISChLS2tAT+BDw6PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaYQIBwKAwIBMTkMDAYEApIpVBgOCAOg4RRGlAoEAuGIdGITgWOq4LxcCQgZkEkIHksHgYJOR6ZQCgVFhYJFxgTBVMZihoCfxUYDWUbUBGKGREcjBoQEB2TAB4CAx+Vl5WMhyACHiEhH6IfIiMktCQgE0cZJQStr6O2t6EARxO6vK6iEx4dZsMCxbsmBB4nzUTEutVSSUdmfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== filesave16:file file16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBFRSVMTCxKyurPz+/JSWlFRWVJyenKSipJSSlOzu7ISChISGhIyOjHR2dJyanIyKjHx6fMzOzGRiZAQGBFxeXGRmZHRydGxqbAwODOTm5ExOTERGRExKTHx+fGxubNza3Dw+PDQ2NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaAQIAQECgOj0jBgFAoBpBHpaFAbRqRh0F1a30ClAhuNZHwZhViqgFhJizSjIZXQCAoHOKHYw5xRBiAElQTFAoVQgINFBYXGBkZFxYHGRqIDBQbmRwdHgKeH2YgHpmkIR0HAhFeTqSZIhwCFIdIrBsjAgcPXlBERZ4Gu7xCRZVDfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== folder16:folder folder16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBwWHMzKzOzq7ERCRExGTCwqLARqnAQ+ZHR2dKyqrNTOzHx2fCQiJMTi9NTu9HzC3AxmnAQ+XPTm7Dy67DymzITC3IzG5AxypHRydKymrMzOzOzu7BweHByy9AyGtFyy1IzG3NTu/ARupFRSVByazBR6rAyGvFyuzJTK3MTm9BR+tAxWhHS61MTi7Pz+/IymvCxulBRelAx2rHS63Pz6/PTy9PTu9Nza3ISitBRupFSixNTS1CxqnDQyNMzGzOTi5MTCxMTGxGxubGxqbLy2vLSutGRiZLy6vLSytKyurDQuNFxaXKSipDw6PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfDgACCAAECg4eIAAMEBQYHCImDBgkKCwwNBQIBBw4Bhw8QERITFJYEFQUFnoIPFhcYoRkaFBscHR4Ggh8gIRciEiMQJBkltCa6JyUoKSkXKhIrLCQYuQAPLS4TEyUhKb0qLzDVAjEFMjMuNBMoNcw21QY3ODkFOjs82RM1PfDzFRU3fOggcM7Fj2pAgggRokOHDx9DhhAZUqQaISBGhjwMEvEIkiIHEgUAkgSJkiNLmFSMJChAEydPGBSBwvJQgAc0/QQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= folderhtml16:folder folder16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBERGRBQWFMzKzOzq7CwqLDw6NARqnAQ+XHR2dKyqrOTm5ExKTERCRHRydMTi7NTu9HS+1KSmpBweHDy67DyixHS61ITG3AxypByu7DxinBw+ZERmdIySjITC3ARypExOTDRurIR2RPTSdJyulEyGvBw+bFSyzJTK3LzKvPzivOTixNTChLSybGyCfCRSnBQqRASGtFyuzDw+PCRShPzy5OzerOTShKyaTEx6pCxerGRufBR+rOTezPTShNy6bER+1BxCfBQuRAxelFSixBw2VISq3GySrPTWlHyanIyitFSO3IymtCRujAxWhCRqlCQ6XGyWvNS2bFyGvDxuvCRSpLy+vMS+vGxqbFyO1GSi3EyO1FRaVCQuPLS2tDxyzKyWNFxaNCQyPGxubCxajERSVExKNJyenAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfZgACCAAECg4eIAAMEBQICBomDBwgJCgsEDA0BDg8BhwYQERKUDxOYDAyeghQVFhehGBmVlwwOqxobHB0eH6EfIAkPIYIiIyQlJhsnKBcpvrYiKissLS4vMDEyFjOvNAA1LDY3ODk6Oyc8PTIyFzQ1Jj42P0A6QTtCQ0REIEUORkdIkihZwsSekBhNnDyBciCKiSNSplDRUcWKkRhXCGDJYgiGli1cpuTocsILjytfFmRpACAGRTBhRogZgzHlAjKGWnIoY+bMgRgBDHRBo/LAIZoxuhwKatRPIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 folderlocked16:folder folder16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBQSFMzKzOTm5CwuLERCRARqnAQ+XHR2dKSmpOzm5GxqbCQiJMTi7NTu9HS+1HRydOTm1Ozq7Dy67DyixHS61ITC3AxypERGRBweHByu7ASGtFyy1DSOtDRmfExOTBSazBR+rCwqLAxWhAxelByGtDSaxAwODHy+1Dw+PPT29IyqvCxujOzu7NTW1Nza3ExGJJyebKyqfMTCpFRSPOTi5DQqHOTezDw2NMTGxKyqhMTGrGxmXDQ2NMTCxMTGpHx6bHx2bBQWFIyOXDQuDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfDgACCAAECg4eIAAMEBQICBomDBwgJCgsEDAKFDQGHDg8QEZQSlxMUDJ2CDhUWF6AYGZWXFBqCGxwdFh4XGK8fIAohtiIIIx25EZwBDREHgiQjJSYmGScoKSoRKQ8rggIsDC0uJS4oGygoAyjdAAcsLxQUMDEyMzQ1EzapBy8MDDc36tFwgONFjlQ6dgCEEZBHDx8+ctRIRehHAyAwZASZIGRIEBoUBwUwIGMCiwFEaBQJichIjo9FZLBsacRIAB0A/AQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= foldernew16:folder folder16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAQCBPz+hPz+BOSmZPzSnPzChFxaXMTCBPyuZPz+xPzGhEwyHExOTPz+/MSGTFROTPT29OTm5KyurDQyNNza3Ozq5Nze3LR+RLy+vJyenMzKzNTS1Ly6vJSWlFRSTMzOzMTGxLS2tKSmpGxubBQSFAwKDKSinJyanIyOjCQiJERCRERGRBweHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaNQIBwSCwaj8ikcokMCIqBaEDoBAQG1meAUDAQpIcBQoy1dg2JdBqhECgQ1IWB0WgcBIOBwIHXBwwPEBEREhIBbG4IExR/DBUVFhIXV2NjDVYYDY8SFU4ZVxpVAQwbGxynGxkdTh6XVh8gGSGzGSITIxokJUImGSMTwLcnKCkprgAqDSt1zCssKxQtQ35BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= folderopen16:folder folder16 16:photo:16 16:R0lGODlhEAAQAIYAAPwCBAQCBExKTBQWFOzi1Ozq7ERCRCwqLPz+/PT29Ozu7OTm5FRSVHRydIR+fISCfMTCvAQ6XARqnJSKfIx6XPz6/MzKxJTa9Mzq9JzO5PTy7OzizJSOhIyCdOTi5Dy65FTC7HS2zMzm7OTSvNTCnIRyVNza3Dw+PASq5BSGrFyqzMyyjMzOzAR+zBRejBxqnBx+rHRmTPTy9IyqvDRylFxaXNze3DRujAQ2VLSyrDQ2NNTW1NTS1AQ6VJyenGxqbMTGxLy6vGRiZKyurKyqrKSmpDw6PDw6NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfCgACCAAECg4eIAAMEBQYCB4mHAQgJCgsLDAEGDQGIkw4PBQkJBYwQnRESEREIoRMUE6IVChYGERcYGaoRGhsbHBQdHgu2HyAhGSK6qxsjJCUmJwARKCkpKsjKqislLNIRLS4vLykw2MkRMRAGhDIJMzTiLzDXETUQ0gAGCgU2HjM35N3AkYMdAB0EbCjcwcPCDBguevjIR0jHDwgWLACBECRIBB8GJekQMiRIjhxEIlBMFOBADR9FIhiJ5OnAEQB+AgEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mailforward16:mail mail16 16:photo:16 16:R0lGODlhEAAQAIYAAIx+fIRydHxubHxmZGxiXHRmZFxOTFxGPFxKTPwCBLymlMy+pOze3PTq3PTu5Pzy7LSmnOTaxOzm5LyqlNzOtPz69Pz27MzCtLyqrPT27IRubPzuzNTGvNTCxLSelPz25Bw+ZFxKPPzy1Pz65LyupBxKdCxWfPTm1Pz23LyinBxGbGzO5DRafBxWfBxajCymxHTS5BxSdBxKbFTK3EzG1CSGvCyKvCSSxCSavGTO5GRaVPzqzFzK5EzG3BSCtAwiPGxaVPTivPzy3NzKpBxObCRefBxqlPTmzJR2bKyahAwyRPzmvOTOpKyObNS+nPz21AQOFKyOfPzuxAQCBGRORLSadPzyzLymjMy2lOzetDwuJFRCPEw6NEQ6LEQyLEQ6NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAkALAAAAAAQABAAAAfhgAABAgIDBAQFBgcIBwmOCQIKCwwNDg8OEBESjY8CDBMUFRYVFxgZDJyOGhsPChwVHR4fFSAhjwkaIiMOJBQQDRUVJSa3GicoHw4pEA8SGSorLI8tLtQu19gqLzDECTEyMzQ14zY1Njc3ODkqCTo7MjIxNCs5PD03PjctPwlAQUIihhBpQbCIihtG+CUocASFkAhIkogQ8kFJwkcFlogIkoRJEydPnkBR6GiAxiQLgiiIIkXElFQJqESoMsRKkAhXqkhhApNKFSxZggTJ4nHIEJhaDhzYwoVLFy1avHyB6ScQACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= mailget16:mail mail16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAxKdBRSfCyGvFSm1BxKfCSWzCyWzBRCXCRKfBwuRAQGDDw6PHy23Cym1CSSxByCxBxunBQSFKyurMTCxExihNza3NTW1JSSlMzKzFxaXLS2tNze3KSipCQmJGxmbNTS1KSepLy2vISGhJSWlHx+fERGRPz6/IyKjDw+POzq7JyenMzOzKSmpCwuLDQyNIyOjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaeQIBwGBAIAsOkUjAgFJRQQMHgjC4PBIEVgAh4D4aEYrGAMhINxwPyiCgYSsmEUmk82grLRZJkYCgXaAEKFxYZcEISGhsZFxwFeY0WHR5CDB8dGCAXG5shGxQicBIMpSMUGxgTGSQlpQwSJicnEwwdI7gdKAwTsykpKiobr8QMKxeHDBcsGRvOzxsT0i0uL9HSHdkT2ZkoMJXF4a8AfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mail16:mail mail16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBGxaVOTe1Oze3OTWxOTWvNzStNzKpEQ6LOTezPz+/Pzy7Pz69Pz27Pz25Pz21PzuzPzuxEQyLLyinLSmnPz67Pz23LSafKyObDwuJMzCtLSelPzy1My6nLymjNTCxLyqnPzq1LyihKyOfOzavOzetEQ6NPTq3NzOtLymnNTGxJR2bOTOpPTivNTGvLymlKSShKyahEw+NOTe3PTm1Pzu1Pzy3FRCPPz65LSadFxGPOzm3PzqzPTmzPzmvEw6NCH5BAEAAAAALAAAAAAQABAAAAaqQIBwSCwaj8ikMhloOp/QpmAgqAoIhELBUDgcEIGEYrFgNBoLx+IBiRwkgQnFoWAwKhWLhX3BZAILGhsCDXgODhwdGB5vgAofICBlDiEiIx4kJSYBJ2UoEykqHSMrLC0nLWAnFS4UCycvMAcEMR0RLTIBMwaSahw0NTYtFwclNwEdLws4eoc2DxwQOR06ASk7PBAhIRE9Pj0tLSUY1T8I5gjn6Qgy7D8SfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mailreplyall16:mail mail16 16:photo:16 16:R0lGODlhEAAQAIYAAIx+fIRubHxubHxqbHxmZGxeXHRmZGROTFRCPFxKTFxGPPwCBLymlMy6pOTa1PTq3PTu5Pz27Dw+POzi3PTm1OTWvPz25FRSVERCRLympPzuzPTu7NTGvFxaXKSmpPzu1Pz65Hx6fHxqZPzq1Pz23HR2dBw+ZHx+fISChJSWlDQmJHRydCxWfBxGbJyenExKTHRiXPzqzPzy3CQmJDRafGTO5ExOTERKTGxWVCRSfHTS5CymxBxajBxWfPTmvPzy1CyixCSaxCySxDSaxDSWxDSSvDyaxGS21PTmzPz21AwiPBRejCSavByGtCSezEzG3FzK5FzG3GzO5FTK3CQ2bPTixBxqlCRefBxSdBxSfBx2nCQ+dHxmXPzmvLSafAwmRAwyRPzyzDw6POzavNzKpAQOFPzuxBwWTBw2ZGRORLyWdMy2lOzetPTivAQCBKyObOTOpAweNBwWVEQyLEw2LEQ2LDwuJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAsALAAAAAAQABAAAAf4gAABAgMEBQUGBwgJCguOCwEMDQ4PEBESDA4TjY8DFAwVERYXGBkRm4+QGhsMHB0eGB8bDpyOARogEBceIRgXv8COIiMkGB4lJSYnIcwoKb/DGyoXKywtKS4pHinMLzAxJDIzNDUtNjcv6B0hLzgfMh85OjstPDw99zwd7T4/LTVAgggZQqSIECNHevSAgSSJkiVMmjh5AiWKlClAiFARUeVHFSVWmLS40gNLlh5agGzh0kWDlwZfrIDREKaCAjEqrFA5MMYLmTAxlJTxYoZMozNozqRRs4ZNmy5s3LwhA0dBnDNn5MxBoAABnTp17IitowDrmQV+AgEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mailreply16:mail mail16 16:photo:16 16:R0lGODlhEAAQAIYAAIx+fIRubHxubHxqbHxmZGxeXHRmZGROTEw+NFxKTFxGPPwCBLymnMy6pOTa1PTm1Pzy7LymlOzi3HxqZOTWvPz69Pz25My+tLympFRGRHxuZPzu1LymjNTGvNTCxBw+ZPz23PzuzPz65PTu5NzOtCxWfBxKbPzq1DRafGTO5BxGbPzy9HTS5CymxBxajHRiXPzqzCyixCSaxCySxDSaxDSSvGS21GxWVAwmRBRejCSavByGtCSezEzG3FzK5FzG3CQ2bPzuxAwiPBxqlBxKdCRefBxWfBxSdBxSfBx2nCQ+dPzy1CRqlAwyRDQmJPTmvPTixLSafOTOpAQOFPz21BwWTBw2ZPzmvNS6nPTivAQCBAweNBwWVNzKpPzyzLyihGRORLyWdMy2lOzetKyObEQyLEw6NEw2LDwuJEQ2LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAsALAAAAAAQABAAAAfqgAABAgMEBQUGBwgJCguOCwEMDQ4PEJYRDhKNjxMPDBQVFhAXGBUSGY8LGhsQHB0VHh8gFQ6bjgEhIiMMJCUmFbS2CwMnG6IoKSorI7WpEycWFiUsLSou1yXXji8wFiopMTIzNDUz4zbZNxsbODk6Ozw9Pj8pPzEzQDdB60JDOkRFjBw5giRJDCWdlmxwIIRJExAWKDRyMgTIiydLoESRImQKlSUSF1SxUoXAlSBRsGSJoCVICIlbqlThcoBClC5eYFD4EiVIFwUyqywAE0ZMlqNjpJDpIkUBl0dlFChAYOZMmTJoyqQR5icQACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= mailsend16:mail mail16 16:photo:16 16:R0lGODlhEAAQAIYAAIx+fIRubHxubHxqbHxmZGxeXHRmZGROTFRCPFxKTFxGPPwCBHxqZLyqlMy6pOze3PTq3PTu5Pz27Pzy7LyinOTaxOzi3Ozq3LymlOTOtPz69Pzy5My+tLympPzqzNTGvLSelPzy3BxGbBQ6VPzuzPz65LyupNzOtPz+/GzO5BRejPzq1Pz23LymjHTS5CyixCSavBxqlPz25LymnGTO5CymxCSaxByGtHRiXPzy1CySxCSezGxWVPzuxKyOhMy6nDSaxEzG3PTivNzKpKyOfPzu1FzK5PTmzJR2ZLyihLSWfKyObOzmzPzmvDyaxOzavLSafGRORMy2lOzetDwuJEw6NEw2LEQyLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAsALAAAAAAQABAAAAfUgAABAgMEBQUGBwgJCguOCwwNDg8QERITFBUWjY8DFxgZGhsaHB0aD5yODB4TGB+kICEaIiOPCwEkJRcmJyYPKCIpKrWqKywTmC0SIi4vMDHEDCsyMg8zEyI0NTY3z7U4Hhs5Mx+0IyI6OyPrIzw9Gys+PxIy2EBBxAs8Qjk5Q0RFWFxAZySfgSMsilRAkiRECHQ08hHgJ0TJkCU/mECU2ISEkowUlpAQ4QTfowNPoAzJIeRJCyjm8kVRIkWIzSkXhwxJtYAKgp9VrFi5QoWKFZ5+AgEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== nav1downarrow16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIYhI+py+0PUZi0zmTtypflV0VdRJbm6fgFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= nav1leftarrow16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIAAAP///wAAACH5BAEAAAAALAAAAAAQABAAAAIdhI+pyxqdwoNGTmgvy9px/IEWBWRkKZ2oWrKu4hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== nav1rightarrow16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIdhI+pyxCtwoNHTmpvy3rxnnwQh1mUI52o6rCu6hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== nav1uparrow16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIYhI+py+0PWwhxzmetzFpxnnxfRJbmufgFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= nav2downarrow16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIfhI+pq+EPXYpxUckoO3AjbF3dJwahllXe6AFgC8d+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 nav2leftarrow16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAImhI+pyxf5VohmSlsxmpjTzAHeN5ak6UHpqKRi2GpwvH3Q3eT64RcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== nav2rightarrow16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAImhI+pq5HOAjQyVnqfhHue7oAaKH5kiW0AmnLqaHomkj02g+e6XwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== nav2uparrow16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIghI+pyxfR0HsRzNnuXVqn3mVQZWFRyIDjp65Ga5Ly4hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== navback16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBBRSdBRObCQ2TBxObISevAQCBNzu/BRGZPz6/FzC3Pz+/HTS5ByyzJze7Mzq9ITC3AQWLAyWvBSavFyuxAwaLAwSHBRafBSOrDzW5AyixCS61ETW3CzG1AQeLAweLAxefBSStEze7CSWtCyatBSCnBRWfAwmPBRWdByixAQSHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZiQIBwSCwah4HjUTBQFgkFg3MoKBykU0QhoUAIAuAksbpgNByPxQMSGVsVDYlkIqdUiJYLJqORbDgcHRseRR8gISIaEyMkGCVYRBEmeyAnlgaQkSgpmU4RAZ1OKqFOpFNGfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== navdown16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBBRObCRKZBxCXAwyTKTK3Ozy/NTm9GSivAQWHNzu/FzC3IzO5CySrAQOHAyuzETS3CSWtAyOtETa5Aw2VLze7ByWtBy61BSavAxWdBRCXAwqPAQCBDR+nKTe7FS+1Eze7ByixBRmjPz+/AyexAyixAQKFBRqjAQGDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZeQIBwSCwaj0hAYCkYEJLKguGASEADigWj4bgaHpBINykwSCYRa5HCFFQsF0xGo9lwhpSOwfORYC4gISJ3RAQdIyQYJSAlImNrh4uNJkl5CoKUUBQnjlB4KJ6hokN+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 navforward16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBAwyTBRObAw2VDR+nCRKZOzy/KTe7Pz+/KTK3Nzu/Lze7FS+1AyexAyuzBSavAyOtBSmzOTy/BRqjNTm9IzO5ETS3ETa5By61AyixByixBRmjAQGDBxCXGSivCySrCSWtBTC3AQOHAQWHAxWdEze7AQKFBRCXAwqPAQCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZjQIBwSCwahYGjUjBQGgWEpHNYMBCaT4G2UDggos+EwmBYMBpf6VBgYDgeEMgjIpmoAQVKxXLBPDIXGhscRB0eHyAgDSGBGyJFASMiIiMkJYImUwAnmJqbjp4AKCmhAKSlTn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= navhome16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBDw6PBQWFCQiJAQCBFxeXMTCxJyanDwyLDQqLFRSVLSytJSSlISChCQmJERGRFRWVGxubKSmpJyenGRmZLy+vOzq7OTi5Ly6vGRiZPTy9Pz6/OTm5ExOTPT29BwaHNza3NS6tJRqRGQqBNy6pIyKjDwGBPTe1JSWlDQyNOTGrNRiBGwmBIRaLNymdLxWBHxGFNySXCwqLKyqrNR6LKxGBNTS1NTW1Jw+BEweDDQ2NAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaoQIBwCAgIiEjAgAAoGA6I5DBBUBgWjIZDqnwYGgVIoTGQQgyRiGRCgZCR1nTFcsFkHm9hBp2paDYbHAsZHW9eERkYGh4eGx4ag3gfSgMTIBshIiMkGyAlCCZTEpciJyQjGxcoKUQBEhcbIiorLB4XEltDrhcaLS4vtbcJra8bMDHAGrcyrTMXHjA0NSypEsO6EzY3IzU4OdoTzK0BCAkDMgkIOjJlAH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= navup16:nav nav16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBBRObAwSHBRSdISevBRWfAweLNzu/BSOrAQWLPz6/FzC3DzW5BxObHTS5ByyzAyixEze7BSStBRWdAyWvByixAQSHCQ2TAQCBBRGZJze7CS61BSavAxefMzq9ETW3CSWtAwmPPz+/CzG1ITC3FyuxBSCnAQeLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZfQIBwSCwaj8hhQJAkDggFQxMQIBwQhUSyqlgwsFpjg6BwPCARySSstC4eFAqEURlYhoMLBpPRUDYcHXt7RgUeFB8gIU0BIoiKjAcUIwiLSQUkJRsmGIwJJwmEU6OkfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== playeject16:play play16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIbhI+py+0R3IFQUtruXVqn3kkWyIARR4rqKvoFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= playend16:play play16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIjhI+py8Eb3ENRggrxjRnrVIWcIoYd91FaenysMU6wTNeLXwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== playpause16:play play16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIfhI+py+1vgoxzyUCxrZd18ClfmIyVyJ1lqkHuC0N+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 playstart16:play play16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIjhI+pyxudwlNyguqkqRZh3h0gl43hpoElqlHt9UKw7NG27BcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== playstop16:play play16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIahI+py+1vgpySUWpvXXqrHmSaeJEYhKYq6hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textblock16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIahI+py40Bo5SOzRvrwlgrfnkJOIkPaaaJXwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textbold16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIihI+py70BowPQ1HZpwNv212Vg9IGHmIjoWa4ey5DSRNd+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 textbottom16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIVhI+py+0Po5y0hYtzrkB7zH0fN/kFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= textcenter16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIbhI+pm+EPIZsnRkqtDnhu1zHfFSpjaY4PavgFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= textitalic16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIahI+py+0BgztwUmmjBXX3jE0auHHhM5Yq4xcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textleft16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIbhI+pm+EPIZsgRoqr3Vnt102fFSJjUC6nlPoFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= textmiddle16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIXhI+py+0PT5i01pisphjt3UmfFZYm5hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textmove16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIbhI+pm+EPIZsg2kfZvblXbwTg10WlA4rjyvgFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= textright16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIahI+pm+EPIZstSrqsDhhv1ylfFE5jiYwX6hcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textsortdec16:text text16 16:photo:16 16:R0lGODlhEAAQAIIAAAT+BPwCBAQCBAQC/FxaXAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM5CBDM+uKp8KiMsmaAs82dtnGeCHnNp4TjNQ4jq8CbDNOroIe3ROyEx2A4vOgkOBzgFxQ6Xa0owJ8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= textsortinc16:text text16 16:photo:16 16:R0lGODlhEAAQAIIAAAT+BAQC/AQCBPwCBFxaXAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAM4CAqxLm61CGBs81FMrQxgpnhKJlaXFJHUGg0w7DrDUmvtPQo8qyuEHoHW6hEVv+DQFvuhWtCFPwEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== text16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIlhI8Jwe2/AmpTynqPTXSqrnBM+I0kdmpmGmUp+K4nPMvhYx9+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 texttop16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIWhI9pwe2uYnq0yQtqxbz7D4biSIZ+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 textunder16:text text16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIjhI+pu+FxXoOIKpds1oBH7hlYxYxRCaIZ01lhJbHy9tTv7BcAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== viewchoose16:view view16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBDQyNAQCBPz+/PzerAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMzCLrcGlAs6UAYgwLdLtEcI4ygQo7VVp2oupGpG4vmaUVTemX523qlFcw0a4RqNlkx5k8AACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= viewdetailed16:view view16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBDQyNAQCBPz+/PzerAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMmCLrc/i1IAVkYg1Z1iRYUKCqitp1oikqBWV3ZOnhkWNagqu+qnwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== viewicon16:view view16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBDQyNAQCBPz+/PzerAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMwCLrcG1AwGOQbw6qANeCEB3pCSZpO6pgowJZqLKuUGE0dnuEhf8IL1kz1shSHDX8CACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= viewmag-16:view view16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBCQmJDw+PAwODAQCBMza3NTm5MTW1HyChOTy9Mzq7Kze5Kzm7OT29Oz6/Nzy9Lzu7JTW3GTCzLza3NTy9Nz29Ize7HTGzHzK1AwKDMTq7Kzq9JTi7HTW5HzGzMzu9KzS1IzW5Iza5FTK1ESyvLTa3HTK1GzGzGzG1DyqtIzK1AT+/AQGBATCxHRydMTCxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ+QIAQEBAMhkikgFAwHAiC5FCASCQUCwYiKiU0HA9IRAIhSAcTSuXBsFwwk0wyYNBANpyOxPMxIzMgCyEiHSMkGCV+SAQQJicoJCllUgBUECEeKhAIBCuUSxMKIFArBIpJBCxmLQQuL6eUAFCusJSzr7Kmpl0CtLGLvbW2Zn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= viewmag16:view view16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBCQmJDw+PAwODAQCBMza3NTm5MTW1HyChOTy9Mzq7Kze5Kzm7OT29Oz6/Nzy9Lzu7JTW3GTCzLza3NTy9Nz29Ize7HTGzHzK1AwKDMTq7Kzq9JTi7HTW5HzGzMzu9KzS1IzW5Iza5FTK1ESyvLTa3HTK1GzGzGzG1DyqtIzK1AT+/AQGBATCxHRydMTCxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ8QIAQEBAMhkikgFAwHAiC5FCASCQUCwYiKiU0HA9IRAIhSAcTSuXBsFwwk0wyYNBANpyOxPMxIzMgCyEiHSMkGCV+SAQQJicoJCllUgBUECEeKhAIBCuUSxMKIFArBIpJBCxmLQQuL6eUAFCusJSzr7GLArS5Q7O1tmZ+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 viewmag+16:view view16 16:photo:16 16:R0lGODlhEAAQAIUAAPwCBCQmJDw+PAwODAQCBMza3NTm5MTW1HyChOTy9Mzq7Kze5Kzm7OT29Oz6/Nzy9Lzu7JTW3GTCzLza3NTy9Nz29Ize7HTGzHzK1AwKDMTq7Kzq9JTi7HTW5HzGzMzu9KzS1IzW5Iza5FTK1ESyvLTa3HTK1GzGzGzG1DyqtIzK1AT+/AQGBATCxHRydMTCxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaBQIAQEBAMhkikgFAwHAiC5FCASCQUCwYiKiU0HA9IRAIhSAcTSuXBsFwwk0wyYNBANpyOxPMxIzMgCyEiHSMkGCV+SAQQJicoJCllUgBUECEeKhAIBCuUSxMKIFArBIpJBCxmLQQuL6cAsLECrqeys7WxpqZdtK9Ct8C0fsHAZn5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= viewmulticolumn16:view view16 16:photo:16 16:R0lGODlhEAAQAIIAAPwCBDQyNAQCBPz+/PzerAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAMwCLrc/ixI0WSgKoyBl+beQFACpo1AqXbKCr1wLAMWS08hGG3dSZqin4sxnBmPD38CACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= viewtext16:view view16 16:photo:16 16:R0lGODlhEAAQAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAQABAAAAIchI+py40BTQSwuovp3DXkv1ia1IHmIXLiyWJ+AQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 viewtree16:view view16 16:photo:16 16:R0lGODlhEAAQAIIAAAQCBPwCBDQyNPz+/PzerAAAAAAAAAAAACH5BAEAAAEALAAAAAAQABAAAAMuCLHcri4yGISlj4kxcANgNRBQCIbL6U1Su7bB62rXvGydG25kqpwfIGxILBr9CQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 actattach22:act act22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBMTCxPz+/DQyNKSipAQCBISChFxaXDw6PAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARrEMgJgqA4zzus/gLhFd5HCcZAXqsphYPUdhcYFNRcZnvdtpnDqPTbUWgAJKBYwzBlw+bRo3xmkNWoBgm0OrVLn3GC9RgCk8DhUw7c0rHPr4CDu5SYQNyEt7uSY3p/UAKFhYKDSQOLiwgFdhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== actbookmark22:act act22 22:photo:22 22:R0lGODlhFgAWAIQAAPwCBCQmJCwqLMTGxAQCBBwaHMTCxLSytERGRFRWVLy+vKyqrKSmpHR2dJSSlJyanISGhGxubIyOjKyurGxqbFxeXGRmZHx+fKSipLy6vGRiZLS2tFRSVHRydJSWlHx6fCH5BAEAAAAALAAAAAAWABYAAAWWICCOZGmewamaQrq+wUC8azHINGocOI38iIRAceDNaISFYklkGHOEhoNBfUAOhuOLEJE8HoPiRKFdESiQBqViuTDIUAsEcyAeGJmyiqC5RCwJGg0YcEh9D0V3Dxt6JwQVDRYVHBUdi40mjw0PTgwQHgeYJQQJfxUXFxAOoTkFpQ0fsRSimQkWEQ0VtI62HLt7vjl7JQYhACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actbookmarknew22:act act22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBCwqLCQiJCQmJMTGxAQCBLy+vLSytERGRFRWVKyurKyqrLS2tKSmpHR2dJSWlKSipISGhGxubIyOjGxqbIyKjFxaXGRmZHx+fPz+NGRiZPz+ZPz+HMTCBKSiHPz+jFxeXPz+XPz+tPz+zPz+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAamQIBwSCwaj4Gj0hgQLJ+AAaEAVQoI06pRYDhkoYgwIhEgKBTfZ2FhaBsYDS8VWnA8Go0FJIKeqyUTDw8EDHBpSwUUFQ4UFhcYDQYFfkoFFxEQDG8KEAUZlEeWGBIakw4FG1STiBoYBRwdBR4fHgUdHKBEBSCnIR8iIyIfIblFu6ceIyQjtcXGCbLKzAUKzrq+wMLEVa+xs7W31kOTk6nkWuOf6Ea5QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 actexit22:act act22 22:photo:22 22:R0lGODlhFgAWAIEAAPwCBAQCBHR2dDQyNCH5BAEAAAAALAAAAAAWABYAAAJOhI+py90RnIMyRUOxhDfzJkACdoXBuEDDkQFDi5go0MrKx16kns80b7qdELCgBYaEGWwL5nG1ePFiKp9A6kuYRNuho8vxVrrZivmMRtMLACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= acthelp22:act act22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBCQuNBwiJAwiLAwaJAwSHAwSFIy+3ERynCw2PCQuPAwmPCxOZCxWdJzG3FSazBwmNAQKDAQGBDRmhBQyTDxujDR2rIy21AwWJDyGxCxmjAwmNDRihAQOFDxmhCxunBQWFAwaLCRahDR6rESGvDQ2PCRWdDRunDSGvCRSdAwWHCwuLDSOzHSmxDyKxBxCZBwqNHSu1DyOzAQSHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAahQIBwCAgIBAPCoGAgOoeBAyKhWCwYDUf0CX1AIhLiJEGpBLiAAaRxdgYsl7Ybk8igBZoN5xmAdDxoanp8HyANISF8EBsiXBMjJBolBEQmGHFoRScbKHIKDykqK5lFAZRCnyknTaROLA8tq61OChgtKqyzQgEYEJi6UC4vI3LAASkbMBPARAEBdszR0sACEaPSMTIQM8W6KzNl3bo0NOJDdEEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== actlock22:act act22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBHRudFxaXExGTERCRAwGDGxubPz+/Pz2/Ozm7Nza3NTS1KympFRSVHR2dNTO1JSSlKyqrKSipDQyNMTGxDw+PLSutKymrMTCxAQCBHRqLBQODJyanDQuFFxSJFRSJFRGJERCHExCHISChHxyLEQ6HGRaJExKHLSmbLy2fOzitPz23KSiZHxuNHxyNJSOTNTOnMTCjLSudKSaXJSKRJyOTOTetNzWpHxuPOTi5MzKzLS2tFxWXOzq7Ly6vOTe5Ix+RLSqdNzSpLyydKyqbKyiZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4IBAgMEBQKEjI0GBwgJCgsMDY2XjwkOAgQBDxCLl4QNCaGCBBGWooINCAqqrBKgqwATFKaDFRYVtBMXsIMNGBm0GRADjQIJxKIaGxwdHh8gISIhGyMZzIwkGholJiYfJiAfJyEZISDbg90oKCkqKwcHKyooLC0f7IIuLzD2YMSQgW8GDRri+AFoUMOGvRsxUhSsQQPHvmQSchyQtEAHhh0WJHDQcJERjwsKDvRI0BGDjwgicXhQyCOjSgUKPO6AObIkIQESfmxk6REDT4s0bfaYpDNkT4VAha5s+TLmzEYtatwIOHAiDZIKNQAJYk9IjCFEisyoocFEB4UACtBpm0t3LiF4gQAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== actredo22:act act22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBCReDJzGjMzivOTu3Pz+/JTWbHy+VHTCTMTivPT69BxGDESuJDyiHESiHEymJIzKZAQCBFS2LFzKNGzWPDRqHCxqDFSqLHy2XESCHAwaBAQOBBQqBDyWJHyqZDyKFGSiVESeJBQ6BAwSBGTGPFyWPFSSLEyOLESGJBQiDAwiBBQmDCRGFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAaoQIBwSCwaj8hkMcBkKpcBwYAwEDif0YLhwEUkFItFMkAwMBoOR+PxgHwjRDggamhIJpQ8ZbKGKOQLcgEFdhUWEYgRF3sNfhELBHALAhgZFhobRBwREhQdEAIEHpIKHwsaSJwUDQgQIJINARxKESESDQ0dgCIjSpAkDAwPco+ZSJAlJicnKHIAIrNHidOIQxunT0kpCyrZSCss0d5Fj6jjRonn6uvs2QZBACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actreload22:act act22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBCRSFCRSHBw+DBxCFCQ6FBwyDBQWBBxGFCxyLGTChMzqzLzmvHzKjDyOTER+RERyNDSqXNzy3LzivFS+fCyCPBQmBCQiBBxKFBQqDOTy3LTitES2dDR+PCxuJOT25KTarCx+PESSTCxKHDSeVCyKRNT21ESWVDSGPBQyDAQCBBQSFDRuLDSyZDySTGzChCRiJKSmpExKTDS2ZGzGhLy+vGxqbISChDSKRMzKzGxubDQ2NIyOjCQiJCwqLBQWFCwuLKSipERCRERGRHR2dAwKDDw6PFRWVIyKjCQmJFRSVBwaHKyurAQGBExOTBweHFxeXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf9gACCg4IBAgMEBQYHhI2ECAkKCwwNDg8QBAOOhAQREhMUFQgWBxcHGBmbggkaGxwPB4yDB6SbBJIKHQaqtY0eHyAhsqrDgx4aCiKpqoQHAyMjJBMKJaSxzAAHIRsmJgonKA0LHSmDKiuOBywRLSQuLyEwwyoxMuiN6iUzNBXy5jU2bsgoJugABBz95uXQsUMGD3vpPPgTpKIGwx4+HMr4kW4YkCA2hAzxAQSIECI+imBTwVIFESNHerRUgc0cEiFHkjiiyYzeDiVLdvLcySSkkKGEWiZVweSGkIHMmvQosoQlkaZOjvhosvKJjIAxoOAsgpRZkQNLnvSoqspAIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 actrun22:act act22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBAwKDAwKBCQiHNze3AQCBBwWFDw6NPTy9PTy/Dw2NKyytOTi3LS2tMTKzMzOxLy+tLy+vBQODNze5NTS1JyalIyCbIx6VIRyVISGfJyelOTq7EQ+NMTGxKyurGxeRLyKPOSmROSuVOy2XOSiTLzCzNTOzDw+NCwqLHxuVOy6bPzGfOSuXNTW1LSyrMSWRNymTOSmTKSCTPTGjPzSnPzWnMyaVBQSDMTCxPz+/KyahNSeRHxeLJRyTPzmtPzarOy6fJyajNza1Ly6vLyulFRCJPzirPTOlMS2pNTSzMTCvJyenBQWFNzKtPz6vPzyvPzqtOzGlOTe1AwGBFxWTLy6tPTm1PzSpPzutPz2xPTSnOTSxOy2dPzapPzerOzm5IR+dPzu5Pzu1PzqxPzy5Pz+9GRiXGxuZKympHR2bOTm5Pz6/MzSzBwaFJSSjCQmHPz2/AwODAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4SFhoeEAQKIjIIDBAQDjYMFBoMHCAkKgwYFhwULDAUKCg0ODxCkBQgRnoUSExMUDxUWFxgZGpAbFIuGHB0eHyAhIiMkIB8lJieIKCUpJCTGIyorLCktKIUDpC4YLzAxIjIyMzQ1NhgdpJI3ODktJTowOyM8Ejc9Pj9AQUIEclAocCMIBQhDiOwgoaKIoCI+jBxBkkSJkCWemIyq0GSHCBVHihRx8gRKFCmpKhGaQqWKFYZXsGR5kkXLFgRUXBUqkCGCFS5AjnTx0sXKlyA6CRVgAAHMAilhxIwhU6ZFkBY5kgKYUoXBAzMKzixZ4AJNGgVm1KxhM0WpmQpUMtooaOPGxAM3Nw60oYLGjNYCbzYJOgAnRzNBJ95oPYQCgpJtkwzFoULlRuRPiy9fNhAIACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actstop22:act act22 22:photo:22 22:R0lGODlhFgAWAIUAAASC/CQKDBwKDCwODNyKjPzq7My+vIxiXAQCBOSOjPz6/OSelNySjNyGhMR+fLRaTGQ2LPz+/Nx+dNR2bNRybMxuZMxeXMxiZLQSFJQaHFwqJNyKhOSCfNyCfNR6dMxmXMxWVMRORLQODOR+fOSSjNR2dMQ2LJQWFMRWTLwWDNSCfMxeVLwaFKQODNR+fNx+fMxiXKQSDOSWlMRSTMxaVMQ6NMxORMQyJOTS1MxqXLwWFLRORMxKPMQaHMxKTLQWFCH5BAEAAAAALAAAAAAWABYAAAb2QIBwSCwajwGBcikIHIsDQmFKNRwQT2EgoVgsGOCG4wHBIgmRhWRCqVQsF0xGYyYGNgoGh9PpeCQfICEic3UAAWgLIxwRJBsbHSUREyYYJ3RDAQULexGejhueESgpl3WaCxsqJKKsChEUKywtmFoFDC4vCayikzCyMbWHt38NCTKiHhUfMyzBdQIFKsodob0VNDWzwppuKxMRrx6iNjcitNA4bh+iEzkwojc66JkOOxcf7G35PBE9KS1MEUGgIQOIFfk++KjRw9wJgUUIZvhRoyLDFCliQDQisUWLGCJOeNx4hKCGkyhPGnqCoKVLl1liypyZxUAQACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actundo22:act act22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBCReDJzGjMzivOTu3PT69MTivHy+VJTWbIzKZEymJESmFESiHDyiHESqLAQCBFzKNGzWPFS2LNTmzCxqDDRqHPz+/KTGnBQqBAQOBAwaBESCHHy2XBxGDOzy7HTCTEyyJDSqFHzWTAwSBBQ6BIy+dESKJFySPFSSNAwiBCRGFBQmDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAalQIBwSCwaj8ikMsBkKotMwYAwEDiXgYLhwD0gCFZiQKxNKBYMRqPh+D6G16y5AYnYIxBJAyF4AwITTAUJdBESD4gPFBV6Fn6ABBcJDIYPGEQZGhQbHAIdfx4JHw2VSBodGwWfAR4LDSALfkgYAQurBiAhICKfSSMkvQElGyYnGyi9Rxkdj4nOskUYyU9FpxnURikdGtjRKivdRKfQ2Inh5+jpRwZBACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= actunlock22:act act22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBGxqbFxaXExOTEQ+RAQCBPz+/PTy9Ozq7Nza3NTS1KSipFRSVOTi5Hx2fJSSlKyqrJyenJyWnDw6PMzKzKyurDQyNFxWXMTCxJyanHRuLHxuLGReJFxSLFROJFxWJExCHERCHBQODISChHxyLHRqNIRyNHRmLLSqbKyiZLy6fOTarPz67Pzy3OzitKymZFxSJJySTNTSnPTy3NzSpMTChLSydKyqbKSaXJySVIyGRGReLPz23NTOnMzCjHxuPLy2vKSmpOTe5LS2tLSutHxuNHRuPMS+xFxWLIR+RDw2HFRKJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4SDAQIDBAUChY2EAQYHCAkKCwyOjZANDgIEAQoPjJiDAg2iggQQp5gMBwmrDBESl6MTFKuoFQSjABYRF40CGAW8BRm7hQwNxBobHB0eHx4gISIjBdiEAhYFJBslHOHSHh4hBSHlxIUmJygpKissBiwtLi8pGjDqhBoxMjMuaNSwcSMFjhw6dnjYRyrGCh4ueviw4Q5HDB0/PjAUJCBCAwMIGiiggAEIBFk/FgYLIgRkggQkhxAJkqGExkYMFnxsIGRkSQgLHhRRWUjAggQgG8AsSWRBBiP6VrYMOfKIyaBDNwLo+HHSUplOSyDRqiEHjRkretRQkcLgxayNF0wksQGQxsSKMTIq0QpgCba/gAE7IhMIACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= appbook22:app app22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBDyGhCyCfFSWlESOjDyKjDSGhCx+fGSinGSenFyanEySjHSqpHSqrGympEySlBx2dISytHyyrCR6dKTGxHyurHSurHyytGSipCR6fARmZFSalEyWlBRubAxubBRydDyKhDSChLSytPz+/MzKzIyOjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAbFQIBwSCwaj8ikMhBQIpmCQdM5ZBIKhgNiugwkFAsCI7pNMhuOxkNBgBgEiAi3GkBLJpJHYgEpaClyREwVFhcSEhgOGQoMfgMaERtcARQBFRMYExZ6HB0FUYAekkIBHxqWFmlrC1haESAfG6MBGx+VFRgKYH0hInGRklO0ppYXCwwMWQiQHkwjgrWnFRdYZHIBJCTP0LaWGAcDW9jZ2nMAw9IWTOQkJSZMRsOV49nu8E+19PbmR7TY+1TovONH5V7Ag0QMBAEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== appbookopen22:app app22 22:photo:22 22:R0lGODlhFgAWAIYAAAQCBAQ2NPwCBHSurIS2tBx2dBweHPz+/Ozm1GxiTGyqpPz6/Pz69GSqpOzaxPzy5HxuVLSmlOTazPz27PT29NzClPTexHxuXLSmjAxqbFSinPTy9KyehNy+lPTy5Pz29HxyXNzWxKSahOzexPzy7IR2ZOTWtESenPTy7KSWfIyCbKyijAQGBDyalPTu3KSSdDSOjJyOdCSGhPzu3OzizJSGdPTq1PTq3JySdMy6lAyKhOzWtOzi1OTOrJyKbMS2nJySfMS+rAwCBNzOrNTCpNzKpJSGZKyafLSifLyylIx+ZHx6ZDSChAQuLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAIALAAAAAAWABYAAAf/gAABAoSFhoeHAAMAiI2IAAQFjI6EAAaJkQeTjwAICYkKBQcLm5WdBwyfhgChB66bp64HCQC1lQ2irqQCAA4PowsLEBESE4wAuLIHFAAVFr+uDBcYxRm1GrmuGxwdFh4Mrh8gGCET1gDYyhsiFSMkDAsMDCUYJhvnJ9kHKCnODwwfPlBQsULCPRYAWogK9sHFiwoOPEyQh0JFPXO1YBSYwBEFghjdHkwQOYGgwQwIZRR44GHGDBogabhAsYEEihrUMAIoUMCEDRs3HODIYQHFA6MPcJA7KICFjgw7eIzo4cOfiwc/gKwIUm2SkKdDdlDt4AABDaU/iIRwwbTSUyJFOow4S3Hkx9oNDDZgXPU0h1wcSIgEGUw4ibVET5WoWMKksePHpdxmyKADAEIWly9HJtQkQJMmlAgZCAQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== apppencil22:app app22 22:photo:22 22:R0lGODlhFgAWAIMAAASC/IQCBPwCBPyChMQCBPzCxAQCBPz+/MzKzISChKyqrDQyNEQCBAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARYEMhJ6wxiEMtpIAWxddwXiqRlikSQeiAbuC+wirNR322gv7zcLobzDU+9XypoBBKTR1lz+RTWDgip8nUwZK1XLyIx5XoVicX2RUAo1DVKi7GOBxjxfNwQAQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 apptool22:app app22 22:photo:22 22:R0lGODlhFgAWAIQAAPwCBAQCBISChFxaXNze3NTS1Ly6vKSipNTO1Ly2vNza3Pz+/MzOzOTe5DQyNOzu7MTCxGRmZMTGxPTy9Ozm7Hx6fPTu9MzGzGxmbAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAW1ICCOZGmeaEoGbBsI6joMRGEcbQwESDIrtVtAF1gwDLNaAmfKiVgLBJKgwB1KxQZrBHU0FAXmavFoQLYiB6TxFXMj5AZBwnJI2I3wcNWALyYEcgoKXxRhOHs7XxEVCwsWFgoUDRYUFwwQB25ZCxiNjo6GkwUXN2NsCxEYqhUHoQ0MEglYRQQXErcHrI55FycuB2YSmoyOBTEtB2sXuhU6XAENC2a6z9AKCwq+1tAN3E2J3ySkIQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 connecting22:connect connect22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBPz+BMTCBISCBAQCBPz+/MTCxOTi5AQGBNze3Ly6vISChNza3FxaXKSipAAAACH5BAEAAAAALAAAAAAWABYAAAR4EMhJqwzY6omD+MNGdR8YilNZnug0qGzrqrL1lnV1fyJBVB6VQEMoGH4ADGwQkxQPBwMiKGA2J8VEAnq0tgiKg5aL/C7C2gTjKCM0zowDQ8tuNQznNL7cKzjOUQsNfER+gguIg19+Pm6ChBZFDmWNi5M5FIyYFHQRACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= connectno22:connect connect22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBPz+BMTCBERCBAQCBPz+/MTCxOTi5Nze3OTm5Ly6vNza3ISChFxaXKSipAAAACH5BAEAAAAALAAAAAAWABYAAARiEMhJq7046827/+AVCKE0Dh9BAGdaGISAToFGFMcBU+11I4hDYseSZQiKwwKoI/QwBIYiuFDCZseGdIlYEjUNg1SpY6w2N4cUIW6cjwW1lsFwo+MqgtZuw0/ydw5vH34lBhEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== connectyes22:connect connect22 22:photo:22 22:R0lGODlhFgAWAIQAAPwCBAQCBKyirPz+/KymrOTi5KSipMzCzNza3OTe5Ozi7MzGzPTq9OTm5ISChMS+xFxaXNze3GReZIyCjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAWLICCOZGmeaBkAQpoGg7C6JizTQT7CxPwOwFWgYPChYIXkIHC4uQKGAiKRKCyNpxxUUVViVYNFLkqtLo+DAkMMLXQPXwAy2WCTF4544FGtKuwPDhB6DnxuUmyCcXIQhV1uYoMuEAcOBxEKCHg6TzGFCJUSizuejROKOAM9OY2SnUU7nD89NCcDsLUnIQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 devscreen22:dev dev22 22:photo:22 22:R0lGODlhFgAWAIcAAPwCBAQCBPTy9PTu9Ozq7OTi5Nze3OTe5Nza3NzW3NTS1MzOzMzKzMzGzMTCxMTGxOzm7AwGDBQOFBQSFCQeHCwmLCwuLDQyNDw6PERCRFROVEQ+RDQ2NLy+vKSipISChGxqbExKTOzu7OTm5Pz+/GRiZMS+xLy6vBQWFLy2vCwiHFQ+NMSmfNSyhIxmTDwuLJx+bLS2tCwmHMyyhMyqfPTqpPzyvLSWbLSWfPzitIx+ZDw2PAwKDCQiJGxWRPTmrPTerMyuhPzqtPz63PTWnPz6zNy+nIRiVDQuLKyWbOTanPz21NS2jNS6lDQqJHRaTPzmrPTSnPzyxOTClPz2xNSuhPTqxPzuvOzSpAQGDOTKnMy2jOzSrPTu1NzKnOzOnBwWHJRuXLSWdPTatPzqvNzClCwmJOzSnOTOnPTuxOzKlOzerOzarOzitJR6ZNTO1IxmXPTWrNSyjPzOjPTSpLSehHRqZOzirOTCjPS+fPzGhOy6bOzKhGROPMy2lPz+1PzmtKRyRHRiNNTCdPz+zNzCjEQ2NKySdDQmJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAj/AAEIHEiwoMGBARIqXMhQIUIBAwYQIFCggIEDCBIoULBgAYMGDgIIDEBAwMSKBRBk3NjxAciQIwdACBBBwgQKFSxcwJBBwwYMHBx0EAmA5EwPH0CEsCChoYgOQ0cSGCHhA4kSS5syJGDiBNEAFVGUKKEBAwWFFM6SNJHi64gDFEKE4FBBggoKK1i0cPECxokYXw0gsECYggQZM2jAqGHjBo4cOtqOxLhDAg8ePXz8ABJEyBAWRIoYOfJipEoMCZEkuaFkSAslS5jUGJKkSRAnRREo0JDwCZQoTKQAmUKlihQrVa5gKZ1lI+oAK7QM2cJlSZMuU4Z4+TJEx0iNOwKAggkjZkyOFmS8kClzpcUQLRRGbjRD4MgZNEzSqKG+ZgobI2248dUbDDDwABzcxSEHEFpgEcUcdMRRhx1fFejAAx0cgcYdSxiBRx566LEHH0d8QFRRNC3Uhx985CHEH0MAEkhCBxWkgiCDFEFIEYUYUmONMhyCRxVH/PgjBYioYJAdAQEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== editcopy22:edit edit22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBBQSFPz+/DQyNISChDw6PMzKzMTGxERGRIyKjFxaXMTCvKSmpHR2dPz6/Pz29PTq3MS2rPz69MTCxFxWVHx6dJyWjNzSzPz27Pzy7Pzu5PTm3NTKvIR+fJyGfHxuZHxqXNTCtPTq5PTi1PTezNS+rExOTFRORMyylPTaxOzWxOzSvNze3NTOxMy2nMyulMyqjAQCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAbYQIBwSCwahYGkUnk0BgTQ6IAQaBKfUWhBYKhaAU+CgXAQIAyChLeJzSIQhcH6GFaM0QtGY5kstqEODw8QEQELAhJTc08KBBMEFBUWDRcBE1pca20SGBkaEBscAY5maFRIAgoLHRQRHh8gIQFlZnByqA8ZGSIQIyQjJQEmYgJ5p2ACrK4gJx4gKIZZAgdeAQ4ZI9kjKSor0AwEjeAs1S0cHAslLi4vMDDRWeRIfEsxMeET4ATyVoYLC5fizXEiAR84BeMG+pEm8EsAFhAjSlR4hR6fLxiF0AkCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= editcut22:edit edit22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBAQCBAwCBPz+/OTi5JyanOzq7DQyNGxqbAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARbEMhJq704gxBE0Bf3cZo4kRJqBQNRfBucyudgvJS6VaxLzyMa6/bLiWA9HOg4VIIkL5vzuRkcpkvRIIAorphJLzBW84WEuRZWp6uaT7J2Sh1Hit3OY/ZO7WvsEQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 editdelete22:edit edit22 22:photo:22 22:R0lGODlhFgAWAIYAAASC/FRSVExKTERCRDw6PDQyNCwuLBweHBwaHAwODAwKDAQCBExOTNze3NTW1MTGxLS2tJyanPz+/Ozu7BQSFCwqLDw+POTi5PTu7MzKxIR+fCQmJPz6/Oze1NTGvPz69Pzy7Pz29LyyrPy+vPyupPTm1BQWFIQCBPwCBMS6rPzSzNTOxPTi1NS+rPTezNzOxPTizOzWxMy2pOzaxMy2nPTaxOzOtMyynOzSvMyqjPx+fOzGpMSihPTq3OzKrOTCpNzKxNTCtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf8gACCAQIDBAUGBwgJCgsLgpCRAAwNlZYODxALEY+SkAMNEqKjEw0UD5yegqCjrRMVEqidkgWhraMWF7GptLa3EgEWFRSOnhW+vxgZEBqzkBvItxwdHryRCNGjHyAhHSLOgtgSI60c2yQjJd+eJqEnKK0hJCgnJSngAO0SF+8qEvL0VrBogW+BLX4oVKgIyMIFQU8KfDV4R+8FDBcxZBREthAFiRIsOsygsVEUh4Un3pGoUcPGjZInK65QicPlxg8oX5RwqNJGjo0hdJwQ6EIkjRM6dvDYCKIHSBc1Ztjw4eOH0oIrsgIJEqSFDBo0cuTgsdSTo7No0xYTZCcQACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= edit22:edit edit22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBISGhISChHx+fHx6fHR2dGxqbGxubGRmZGRiZFxeXFxaXFRSVIxSLPyuXMzKzMzKxMTCtExOTPzqrPz+/NTS1MS+tOSaVPyWNPz6/IxeNPzavPyKBNTW1PyCBPyGBJxmNPzOpLx6PNRqBMSCRNySTPyCDPSGBMxiBKROBHRydPSylOyydMxmBJxKBAwODPS2lPTq3OyabJxGBPTy5PTGrOyOXPR+DPz69PzmzPzevNxuPORqLMReFPzy7MyCXKxiNIRKHBQWFNTOxPzixJRaPFxONHRqVPz27PTy7PzStCwqJDQyLJSGdIx6ZPz29PTu5HRmTLSKbMSGZHROPFxKPJSKfJyShKyehMyuhDQmHEQuJJyOfLSijMSynMS6pLSefDQyNHx2bKSahLyqhLymhOzi1FRGNIR+bNzKtOTOtOTKrOTKpLyedAQCBFRWVPTq5NzOvLyunLSmlNTCrOTOrNzGrLyidMS+rLyynKyijLymjLyqjAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gAAAAQECAwQFBQYHBggJCgsLDAwADQ6CAQ8QD5ydEJ+gERKWE4ICDxSpqhWqqhYNFxMYphCtqaytGRoXGxgcggSoth25u70eH8APFR0VzMzNziAXIRjIvwAFwq3EqSLUGB/iI4LathS4JCXVJh8nKCmCKrXDFCss1eIfLS4v8ssdmgWsAGNDDBnt3s3wJ+jAtlUhaNSwccNEi4WCBBl4SAHHihw6ZOzg0QNjRgAG6KXK4CNEjBU/gDQI8kLISQAIADobAoMIzCINjLw4YvNkAno4kCRRUuNHESNLmDRxUjSjAlRPfECJImUKlSpMrFzBIqWqoKtJaWSJomULAy5XXrp4+QKGYcYFoCBEWRImi5gmY7CQyVLGriAGD2jEMHMmCxc0Xb6kUbOGTRs3N988gLM4jpw5Y+iwqcOGjZ07mE8yiGABz5c8c/Ts4cOnDJkybS7fdMO7t+/fvDMaCAQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== editpaste22:edit edit22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBBQWFDw6FHRuFGRaBFxSBAQCBAQKBCQiBIx6HPz6/NTOfKyiXDQuFOTm5Pz+/Ozu7PTq5Pz63PTyxNTOjKSeRExGLMTGxMzKzNTS1NTW1Dw2NKSmpKyqrKSipJyanNzWlLy6ZLSuVIx6FISChIyKhJSSlCQiJLS2tDw6NDQyNCQiFCQmHBQSDGRiZHRydGxubHx6dGxqbFxeXGRmZFxaXCwuLOzq7KyurHx+fDwmFEQuFCweFCQWDBQODBwaHBweHKSinJSWlOTi5JyepHR2dDw6PBQSFNze3ERGRIyKjIyOjISGhPz29Pzy7MS2rMzOzFRWVHx2dHxybDQiFPz27Pzu5PTq3PTm1NTCtJyGdHxuZHxqXPzq3PTaxNS6pFxWVFRKRNS2nPTi1PTStNSulNzOxNSynMymhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCgwABAgMEBYSLggaOjgcICQoLDA2Pj4MGDg8QEZ4FDxITFBUWFxcYGRobjQ8cHR4fCQ8gCyEiFSMWJCUkJieNEB4dKB4pKissK8wrLS4vMDHBAAYQHx8dFx0fJDIzNDU0M+IyHzaNNyg43Ng5Ojs7Ojw9Pj9AMkCNDiZB/h9CSOx4QLCgihItqBkYgqIDESElitAYWJCgkQcXjjRCgi1Ihw4BB5LAQOLCgyQYHihpUU3DBw5ElpAgAYNixSRJjKjQaECDCRPZPDB5IbIGSQwKLnh4wbInLA4kmJB4oaPiAwVNnER40hRK1BIAaVatUZJEFCkmpmjgCeWDCalFe4q4oFKwSRUrEa5gycLzwq8lUnPQ4PEgSpYcUZ5o2cIlS1O/JHLEDdfjQZMIVrpgweLFy5e+M6WSmBGlxYMYYBRzCaOFi5imHWBIfOEiShLTVjaP6eyFTBmN1TA5OvLDjJksWb58OVMGDRqWjAYdmU79SIvpjqJr104nEAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 editshred22:edit edit22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBFRSVExKTERCRDw6PDQyNCwuLBweHBwaHAwODAwKDAQCBExOTNze3NTW1MTGxLS2tJyanOze1Pz+/Ozu7BQSFCwqLDw+POTi5MzKxPTu7LyyrIR+fCQmJPz6/Pz69Pzy7Pz29OzaxPTu5PTq3PTm3My6pPzu5PTq5NS+rPTm1PTi1PTezOzWxPz27MyynOzSvMyulOzOtOzKrMymhOzGpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAbpQIAwIBgMCAXDAZFQLBbCqJTRqFobjgdkEYFKowPJZEyeUBqVR/crHDTKZYplovZKCW84+YKZZNZSBXl6EwEEBhVPXxZihGMaGRscdkIdg4QeEnVfCH2OHyAhIhuUAAiXZSEhIyQlJqWnjiEnKCWupRWoYyEgJK0SKaUKjam0JCorLMFfC6iqx8giLa/MGAsT1wsuCyULKwssC9RSzdkfCyALKuALLQsvpeXYIQso3gsiCzALMfENC+dGcMNHUAY/f+jq3ctncMYCGggFrsvHcEGNh/EyPFmg8cmrJxAVkVO0EUDJklHoBAEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== edittrash22:edit edit22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBERGRExOTDQyNISChBQSFCQiJCwuLPT29Nze3GxqbDw6PGxubHR2dJyanLSytJSWlJSSlOzq7Pz6/Nza3Ly6vFRWVBQWFIyKjMTCxHx6fIyOjLS2tOTi5PTy9OTm5Hx+fNTW1KyurKSmpJyenExKTMzKzKSipFxeXCwqLMzOzKyqrMTGxLy+vHRydBwaHNTS1DQ2NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAb8QIBwSCwaj8KAMoA8LgUDQsFwQByay4RiwWg4GA9IRGk0SCYJSsUCsVwwGQ1EsmESD5xOp+L5gDwhBRIZDhcDdkMGDgEiIxAkJQ8Ok5MmAohDAQ1xJxUlKCUlEg0pKpiZJRoLCxmtCw1eURhOcR4rbQ8cGRwLAwgGtBYTDywtGRKjvQTARgEZLhMcKC0OrQMvAirMRc7CHCTU1g2+20TO0NIn1RwDCya/wdHT1Rnt5LToKOq79trx0tR02YPX7Jm8fRxMOIhSLhOJE/LCJSTlr5kFEBQsWDiR4UGGBgsuHDg1BEYAfTE6oEBR4AIBAiS5yWBAAAGBAyaPGAgCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= fileclose22:file file22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBERGRERCRDw6PCwqLExOTFRWVHRydGxqbGRiZCQiJISChIyKjHx6fDQyNBwaHJSWlKSipBQWFJyanPz+/JSSlCQmJAwKDCwuLBweHBQSFGxubExKTISGhDQ2NFxeXFRSVDw+PAwODAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAbZQIBwSCwaj8jkMSAYDAgEJbFgOBwQCUOAoJAaFgvGonHIBhyP5BcSgUAYDWxggD4WFmx3e3HQngkSRgYMEBMUFG4MCId0BGlEAQeEhocVDYcUdBYKF0QCB3gRlJgUAQEYBBkaRAMbDZMMpAYcT46rQwMJrgsdC6QcfwoPnUMOBgkIV6SHHg6bw0QEAQYfBpggBZjPGsRD0gEchxwCIR6HChnQRQ8DIU4DTR4Em+ncRw8O+fmoXPXdRg+gQLFgIYM/KRIkoDP4QMKFf0o0aBAh4qGUixgzCrETBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 filefind22:file file22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBBQSFJyanLS6vLzCxISChNTe3OTu9Oz6/Nzy9Nzy/NTy/OT2/Nzi5Mzu9Lzq9KTe7LTq9PT+/Pz+/Nz2/Mzu/Kzm9Jza5HzK1LTi9PTu9IzW5ITO3FxaXNT2/KTi7Iza7GzC1LzW3FRSVMzO1MTq7HTS3Fy6zFS2vKzm7Lze5MTGzHzS5FTG1Ey2xEyyvJze7JzW3ITa5FTK3EymrGS+zFxWXKymrMzi7ESirEyqvLSyrKze7MzOzMTCxKSepAz+/NzW3MzKzBwWHLzS3ERCRAzi3KyurNze3MzGzLy2vLSutCQiJAyytHRydOTe5MTGxLy6tLyqpKyelJSCdOze3NS+tLyupLSmnKSOhCwuLPzy9Pzu7Oze1OzazOTOvMyihOTi5PTm3Pzi1PTazPTWxOzOtNSunDQyNPzy7Pzu5OzKrNzSzNzGvNS6rMyynMymjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCgwGFhYOIiYQBAgMEAwKHiokBBQYHCAkKCwwFAZOEBQ0IDAsODxARCZ6gAAEGEhMSFBUWFxgZCJ+TjBoMEpkRERscGBGRih0BBAgeFBQOER8gISEfIruIIwEkCCUVwhcgJicoKSrZg9srCRkRGdMsLS4vMNiK2wIKMRsbMiwzXtCocSydIBs3AuCIwIFDiBMucugAoWvSiB2VNPDg0ELHwA0MkCXr4aNSggg8NoDIQOFHgBtAkgURMiDAEAFEVBCJFKCIkSMGOyDRkETJEkOFmABoUsRJQkQdnkzQACWKlBtTplBR6qopxkFRJ0ytYuWKFCxZtBBq+hRA2AlbRrh08fLlCxi1a51g+dQhDFwuYsaQKWPmDBpKXgNETaNGjJgyhNfcVdTTiWI2XpK0cePmzRk4YA5T5otGixY0qFOXbgXAQCAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== filenew22:file file22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBExOTERCRDw6PCwuLBwaHAwODAQCBOze1NTW1OTi5Nze3MTGxLS2tJyanPz+/Ozu7OTi3BQSFCwqLDw+PDQyNFRSVPTu7MzKxLyyrIR+fCQmJPz6/NTOxPz69Pzy7PTu5Pz29Pzu5PTq5PTm1My6pBQWFPTq3PTm3NS+rAwKDPTi1PTezOzWxMy2pPz27PTazOzSvMyynOzaxOzOtPTaxOzKrMyqjOzGpMymhPTizOTCpNzSzNTGvMymjMSihCH5BAEAAAAALAAAAAAWABYAAAboQIBwSCwaiYGAYEAgFAqGg/Q4DCASCsTiymgcHAcqQLB4mM+QiIQBppLPcMjkwQ4bB2X4maKgt4sVCHpnFhQTElNFE3mDDxcYGRp2RBuMgxwIHX9EBZZwHh8gCBmTQ52NISEiIyQlpUImng8hHyInKAgprwAqgnC0IKwrLLpGB4wctLYkwy0uuwd9Z8AnJywsLcVFx2YcL7UnJCwwLTEy0GXJoSgrCCwzNDTnxgjeH9UrKzXwNDY36LRGhEOwLx4NHDmgJbh3QoeOgv127EhojEeHDj16pEhRQoZHHzl+QJNCsqTJSXaCAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 fileopen22:file file22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBAQCBCQWDCwaDDwmFPSubPzGhPzCfPy2dOSmZPzKlPzSnPzOlPzKjBQODPzChPzWnPy2bPSmXPyuZOyeXIRSLEQuFEwyHEQqFDQiFCweDKRuPFRSTPT29PTy9Ozq7OTi3Nze3NTW1MzOzMTGxMTCxLy6tLSytKyurDQyNMzKxOTm5OTi5Nza1NTS1MTCvLS2tLSyrKSmpJyenJSWlIyKjHx+fFxeXBwaHKxuPMzKzLy6vIyOjHx6fDw6NPy6dGxubLy+vISChCQmJNza3KyqrBQSFLR2RKSinJyanGxqZAwGBJSSlCwqLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4SFhoeDAYqKiIeLj4wBjQCMhY+NkoiLk5qbhQIDoJyGBAUGBwgEo4MECQoLDA2pDrS1tKQPEAwHERITE77AvxKqhAQNDA8UFRYXFs8YBAQZGqGPxw0RGxwdHR4eHyAhIiMkJSYnKCgpBAYPEhcqHyssLS4kLzAxMjM0NTY3cBA4UCAHBw8gVnhgEcKFjhc7UPDj0cMHAAI/KFgY4YLFio/jRpTYsW8GDyCSCEQw2DChOHIqgsCQSEPIEEEEJFhAoUNECCJEyOk4d6KIyRtGcB7hIJKjixEjHu4oimSGEIs4d8IIUoKECnNB0ElMwkNJJgBLlJBAcQKGiR07KGAURVGViY0mhIwwSTKjr99+THjUoIg0r48hTRIrRtxkiOMhDgrZCQQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== fileprint22:file file22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBFxaXDQyNFxSTPTizOzi1FxORDw2NExKLPTi1Pzy9Pz6/FRWVPz29Pz2/PTy7PTu9OzezPzu5OzavAQCBPzy7PTm3OzazOzKrPTu5FxSRERCRGReXPTq5Pzu7ExGTMS+xKSmpOTKpPTq3JSCDNzSfHRydLyadOzCjOzOtOzSvLyyTMTCxKSipGRiZFROLPz+/KyurJyenJyWnGxmbLSabOzClOzm7LSutJSWlJSSlJyanGxqbNze3OTm5IyGjNTO1Nza3NzW3OTe5IyKjHx6fMzGzMTGxMzOzNTW1IR+hISGhKymrLy6vLSytERGRGxubKyqrLy2vLS2tDQ2NEQ+RASKBAT+BFxeXHRudAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4QBAgOEiYqEAgQFBgcGi5MICQoLmAQDh5OEDA2YCw4ODxARApKUCaGYEAsSCRMUnQysCwoVEhYXGLOLCBCgDqK5GQUXGooCAhscBB0euBUZEAUJvQgIgx8gIR8iCSPiHuIFEREDJCXaANwhJhsnKCnWERcRKiopFCvsBywhQrRwQWGAPAz5EhpQ9wIABRgKYsiYMTEEDQocatiwkUIEP18fbkCAAcMBjhwzdOyQwYNCgBMfKJSgMItBjxs+btwgCSGGjhw/ZoRgQKGZCRMUPgABEgSIkCE3SZok8qNqkR85NtDUEcPIkaVAkCR5SrJBDCVKlmzQ6pCCiRlMTJo4YUH3K5AeMBYYWctW0BOaUH60cBJFypQmII6wyEpFQBVFMSm4UAI3hJUrOGh8oOJrklYKWIromJGDR99Ogz5j4ZGlM+pEnwmBCwQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== filesave22:file file22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBGxqbAQCBLy+vERCRExKTHRydIyKjMTCxFxaXGRiZFRSVFRWVPz6/Nze3Nzm5Pz+/JyanDw+PExOTHR2dMTGxBQWFLSytHx+fISChOzy9Ly6vAQGBJSWlMzKzAwODJSSlHx6fIyOjOTi5DQ2NISGhGxubCwuLOzq7ERGRFxeXNTW1CwqLPT29Dw6PGRmZKSmpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAb/QIBQGBAMj8ikUDAgFAzKKCBwQCQUCcICKh0SEAhGw5EIZAmBrgCxeDQgcDJWyz0GIggJfL+XGwQJRxNgC3yGDwwUFUZDFhdthnwMGAZNQwEZFwQakXANBBQbHIIdERIBnRAOiR4ERx8gsSEMBBmGCyEGG3YGBwcgIr8UCwQHECOgG4xCtRkEJAvBJRklJgkSFBQeJ68hJiEoESkFKiEZIbkGARsLlwEGExENGhorGSkpFAYm66NDLAECpGiBYsUIFA8wLHBBQMWLVkdUCFCwaYVFBOymkVCgYEMgOykEpICBccMBAhhELFigTEqAAgIIwCiQ4eRKDyS6EAlJIAI0EpaudF4iIKDAAn9CkRT5eMROEAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 foldernew22:folder folder22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBNzaTPT2FISCBCQaDPz+BExKBDwmFPSubPzChPzCfPy2dPz6BMzOTAQCBOSmZPzKlPzSnPzOlPzKjBQODPz+rPz+3PzWnPyuZPSmXNyaXPTyhISCLIRSLEQuFEwyHPy2bKRuPFRSTPT29PTy9Ozq7Pz+xJyanDQyNPzGhMzKzOTi3Nza3OTiVBQWFDwqFKxuPOTi5JSSjISChHR2dGRmZFxeXPS2dNTSzNTS1OTm5KSipLS2tLSytKyqpIyKhGRiZNze3NTW1MTGxMTCvLy6tIyKjCQmJMTCxMzOzMzKxJyenHx6fLR2RLy6vJSSlHx+fDw6NLy+vIyOjAwGBGxqZKyurCwuLBQSFJSWlCwqLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4SFhoeIiYqLjI2MAY6HAgOHBJYEhJCDBQaDmgcICQoLB4MGDA0OAQUBDg2cAAcPEBESE6QUuQasFRYVq5SxCRcSCggYGRjIGgYbFs8bHIMHExIJGR0eHx7cB83PFhsDDuTUEyAhIiMjJCQluwEmvsAnKAcp1x4qKyUrLLupWrByxcnFiwQIYIggEaNEiRgBZMyYQaNADRs2REA6cCODBxw5+OnQgWMHjx4+BND4MQOIg1gI0gUREkTHiplDhhApEoCGkRlHBL3I8MEHEhz+WAhJogTJySVMfthwIehAExE5jubAkYQpESc8fOx4AiXKNA8+ekhBgqSpzh5hPHcsmVLjpSAqVZBY6VGkiJMiPQKLnTvjCiEsWU4o3nGC8YksMmT8YCmC6iAXKLRc2cz5yGYtR0JjKWQgEAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 mailforward22:mail mail22 22:photo:22 22:R0lGODlhFgAWAIcAAJR6fIxydIxubIRqbIRmZHxeXHRaXHRWVGxSVGROTFxGRFxCRFQ+PEw6PEw2NEQuLPwCBJR2dLyijPTixPz69Pzq3Pzy3Pzu5PTu7Ozi1LyelOzavPz+/DwqLLyafPTmvPz67Pz29Pzy7LSWlPzmzPz6/LyajPTitOTSzMyurPz25PTatPTi3KyOjPzuxAwqVDQiJHxiZPTetKySlPzqvPz27BQ6bAwmTPTexLyinNzGxDRunPzy5KySjCQ+ZNzq9KTO7JzC3Nzq/Ozu/LzW7FSm1BR6vGSWvFyq1AyGxAxytAx6vBSKxAxSjMyujLSunES+5BSi1ByGvAQCBNzCrOTaxNTOvMS6rKyelCx6rBx6tBQKDOTWvPzu1PTq1OzezAQOHAxGdBROhAQGFPzy1NzOvIRqXLyynOzarPz21Jx2XPTWrLSShAw2XKSCbPzuzAwePAQCDPzyzPzqzPTmxOzWtAwGBKyObOTSrNzGrKyGbOzatEQyNKyCZOzWrOTGpNS2lCweHCQaHCQWFBwSFBQODAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABAALAAAAAAWABYAAAj/AAEEEDCAQAEDBxAkULCAQQMHDyBInBhBwgQKFSpY0HgBQwYNGzh0mDhRAAUPHziACEGBpYgRJDiUGEkSwoCQJk6opNASRQoOFETQJDkggwoOJlYApcCihQuVL2DUhBDjhIqjJmRwwDCDhswaNm5MjYHjKggOOU7o0CGTA9gdYknG2KCCBw8VJVL0uBgihAUfP+CSNGCjsI/DiBPbAMJBsEQbQYQM+UG5smUiRYw0jlvYxhEkSYyIHm1EyRLTTH40EZvAyZPOR4pAmU07ipIkUKQ0mQIhAZUqVq5gKXzkSBYtyLVEyd1ki8QFXLp4+WJFQowbYLJnD5NbzJiJCjaQnhnvpYwZM0/OPFlvQ/f3iQvQpBlvQc0aCWy4VKnCpY0Y5yQxgEYXZFjghgwZUOHGCW90YQEccUwloBwGyjAHHXUoSAMZb0xhx1QOoMHDHSfIwSEOdTjhAQ1d4MFbTQ6Q4MYacrzxhhx04JCHHhvQsMeLJPHRBxpr+LHCGnusgccfgKixQR1ATtTBlDDAEIggggxCCCGFbLGFHVFKZEdAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= mailget22:mail mail22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBBQ6bCQ+ZAwePKTC5Ozu/NTi9GSWvAwSJGSu3JS+5CR+rAQOHPTy/AyKzES23AwOHCw+bOTq/BR6xES+5AwmTBw6ZMTW9Ax6tByi1BRGdAw2XAQCBDQuNDRupKzS9FSm1BR2vBym3EzC7CSGxBROhNTW1Pz+/OTm5NTO1AQGFNzW3Ozq7Ozm7IyKjJyWnMzOzNzq9Nze3OTa5Ly6vCQiJGReZISChKyqrAwqVBRWlOTi5MS6xJSWlNza3OTe5Ly2vGxmbKymrIyGjMzGzISGhKSepCQmJDw6PHR2dJSOlPTy9MTGxLy+vLS2tMzKzLSutMTCxLSytKSipJyenKyurJyanCwqLCwmLCwuLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4IBhgIBA4SLjAABBAUGBwiNlY4FCQoLDJaNAQ0ODwsQnYwREhMUE5ylFYYRFhcYGRgaGxsDHJUdFR4SHyAhEyIjJCUcuo0cJr0nExihxgwoyYscKSnMHicOIw4lKissLdWDHC4vMCu9McYqMjMyNOUANTY3OPEoOTolDCszdrSgwaMcBxs9TMxYOCMHBx8zfPj48QNINQ5BbMBIIUShDIUoTAhR94PHPEEHbQwZckOGjBQviMxYUWQIDCMmdXE4gqRnkiFETAxR8iKFjJU2evZEdmLJkgJIbqS4wXJIUapImj5FtuSEVyRVV1IVi4RIChhEkLVAgcJHEqVwVJUmYdKkiRNkALMRecKECRG/ff8CEQJFCA5kMKJEoUHDCQ/HkB9LmWKECpUeyKoIMSLEyosen0OD7iH2xg1dV7BkqXGlBpbWNTq4Zn2khu0aAAwEAgAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 mail22:mail mail22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBDQyNCwqLCQiJBwaHBQSFAwKDAQCBDw6PPz+/Pz69Pz27PTy7PTy5PTu5PTu3PTu1PTq1PTqzOzmzPzuvOzitPTmvOzivAQGBDw+POzevPz67Pz25Pz23Pzy1PzyzPzqvOTavERCRKSilPz21OTevIR+ZExKTOTi3JyanLS2tPz6/Pz65KyihJSKbMS6lExOTNTW1JSWlJSKZMSylNTOrNTKpFRSVPz29MTCxPTmzKymjIyCdOTWxOzexOTWrBQWFFRWVOzu7MzKxJyalOzatLSulMzKtOzmxOTarFxaXKyqnPTmtIyGdIR+bOzetOzixBweHGRiZOzm3NzWzNzSrOTetGRmZOzizOTexOzm1JSKdGxqbHRydJySdHR2dOzapHx6fKyijOTixCwuLHx+fFxeXERGRDQ2NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4SFhoeIiYqLAQECjwORAwSUBZYFBpkHmwgJCgsMDA0OD6UQERITFBMVFhcVGBkangq1ChsLGxwcHQ0dHR4fICEGIiMSCbS3uLq8wCQUJSYGJygpKhQJKyvLLM4Nwi0uLwUwDQsxMtmeuQveHR8UMzQ1NgU3Dgo41jk6ns0cKOzgYaOHjx9AgjTAUUvIECLZNmxoUISHkSM9KiBJQkCJA4kKEoBQoWJJAiYtmjh5AmVCsCJRpHzckKCCySlUUvBYUqUHDysSPnxIEuXKA5pPRiRwxwFLFhRaIEDYUoEChCcDuECoOWKFuwW7nHkg4WELkw8/BHRRwESpt10dU8SSHevlRxIBX6C0WBE27q8GZMkKbTADjIAwYlb4GLMYShYoPTRo6FGiSJEKPyzMIFMmzJcvXbhwkSLFjJkbQW6cOHNGhAgEAdAsmk27tm0ABgIBACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= mailreplyall22:mail mail22 22:photo:22 22:R0lGODlhFgAWAIcAAJR6fIxydIxubIRqbIRmZHxeXHRaXHRWVGxSVGROTFxGRFxCRFQ+PEw6PEw2NEQuLPwCBLyejPTixPz29PTu3Pzu5Pzy7Ozi1LyelPTavPz+/DwqLPz67PTetPz69ERCRLSWlPTmzPz6/OzexLyajPzqvDw+PDQ2NMyurDQiJPz23PTatJyenAQCBPTevPz25LSajOzq7HxiZPTexPz65JyanBQ6bKSmpBwuTOTi5OzaxBRCdHySvGRiZHx6fBQSFERGRNzq9IyOjHx+fGxqbPzu3BwaHFSq3Aw6XAxKfPzy3Gy63ByWzJzO7Mzi9OzavBRytAx6vCSazGRKTPzy1AQKHBRGdBRyrDy63ES+3Cym1CR6rBwWVAQSLAx+xCyCtBRmnPzuzAQWLAwePPzyzKSCbAQOJByGvOTWvPTmxBQODFQ6PPTWrPzqzOzatAwGBKyObLSWfPTivKyCZEQyNKyGZOzWrOzWtOTSrOTGpNS2lJx2XDQmJCweHCQaHCQWFBwSFBQKDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABAALAAAAAAWABYAAAj/AAEEEDCAQAEDBxAkULCAQQMHDyBInBgggoQJFCpkzGjhAoYMGjZMpMghQgcNFjh4mODhA4gQGkSIHAmBwAgNJEpo8KDSxAkUGjhMSEGz5gUVIiKs2PmBRQudHiwQpUnAxYsXImB0aBqjBcuoU0fKmPGChgUNH2qIqGHjg9u3bicWIFs2rYgbNnDkyGFhb8cccQ3ouJqWQo0dPFr0WMy4h48LFj4gsKriB5AeNngEaSGks+chPnwQOXFAh4oXRYxk9nAEyY7XO2wksWHDx5ATCDIoUXEBsYclTJo4cWJhuIjhSXacSPBEiZLMQY4wgRKluvXqUpyIsDElAxUqVaxcwcGCPQuWLOixaNHCZAsXBU+oqKDSxQqULF6ifNmyn/8VMOtxwcAK36kQRhdJQIFFEmKM4eCDYGyhhYAEkqFEGSuYYcUZLaDxXRpqSNRCEu6twYaFZXTQhgRd2NCCG9918AYELTjoXgNuKAFHB2RQEUYHVbQQRwlUpPHGGFwkyQUEDsgxx4lh9BhCBy2U8UQJcrSg5JIQ0FEHG3bc0QGYK+CRhx57PEGlkhM9sAEffKTQhx9+/AEIIIGoEUgLLRRFR0AAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mailreply22:mail mail22 22:photo:22 22:R0lGODlhFgAWAIcAAJR6fIxydIxubIRqbIRmZHxeXHRaXHRWVGxSVGROTFxGRFxCRFQ+PEw6PEw2NEQuLPwCBMSihPTixPz69PTq5Pzy1Pzu5PTq1Pzy7Pzu7Ozi1LyelPTavPz+/DwqLLSajPTetPz27LSWlPzmzPz6/PTexPz67Pz29OTSzMyurPz25LyajBRCdPzuvDQmJOzexPTevOzq5BQ6bBwuTDQiJHxiZPz23Pz65LyinPzmvBxCbHySvAQCBOTi3OTq9CweHOzaxFSq3Aw6XGy63ByWzJzO7Mzi9OzavNzq9BRytAx6vBR6tPzy3AwOHDy63Ax+xCSazCym1CR6rBwWVOzizAQSLES+3CyCtBRyrBRmnGRKTPzu1MzGtAxKfAQWLAwePPTizMy6nByGvNzWxOzWrNzOtBQKDJR2ZNS2lPTmvBQODPTatKSCbOTaxLyqlAQKHFQ6PPzyzPzqzPTu1PTivOzWtKyObPzuzOTOtLSWfPzqvAwGBKyCZPTWrPTmxNzKrEQyNOzatOTGpJx2XCQaHCQWFBwSFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABAALAAAAAAWABYAAAj/AAEEEDCAQAEDBxAkULCAQQMHDyBInBgggoQJFCpYuIDBQgYNGzh08DCR4oQPIDqEmDBhJQYRIzqQIFkSAoESJCKkDGFiwgkUKTpMwECz5IASKjqsSMlSA4sWQjG4qGnzhYoQSmF0iCFjBgmWGWhQrVHCxg2sOHLo2MGjB0sLYmsWQHq1p4wdPtqemGDhB1UDQFSouKHi7oQgQmSwUMyYxcQDZQWz2EFiCJEiRoyQyLzZyGIIB47YKLwDSRAiSZSoXq1kCRHNLBK8YGKjCYskTp4ogeKkt+8oUaBImZKAAxMmVKrctqL7ihTnz7FkAT5FC4cKFbZwadIFdxcvX8KLss8iJcoUBUcq2KgAJoxyMTy4jCFTxoxEHl2GLyCDncmWM2hUIQMPY2CXhhoTfTEcA2tgVwEba7Thxhs88FdBD/ZB8MUUHMJBRhw2sAGCHBKU4UaFc1RAhxnhcdhhHUzYAUIcFdxRAh4R5KGHinu4OIVEDqTBRx81xhGHHzD8wQYQetDRI4cTAcIHGWT0EQgZa1ApCBqDcBAID1Q94IEHLtBAAyGEFGKIIWqYYQYPYNZkQEAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== mailsend22:mail mail22 22:photo:22 22:R0lGODlhFgAWAIcAAIR6fIRydHxubHRqbHRmZGxeXGxaXGRWVFxSVFxOTFRGRExCREw+PEQ6PDw2NDwuLPwCBLSijOzixPz69PTq3PTu5PTu3PTu7OTi1KyelOzavPz+/DQqLPz67LSafOzetPz27Pz29KyajPTmzPz6/NzSzLyurCwiJPz25Ozi3JyOjPzuxBRGbAwSHOzexPz23KSSlPzqvBROdISavBxSdAwaLHRiZLSinNTGxMy+vBxGZNzu9BSGrAwWJMSyrKSSjFy61ETO3BRWfPz65PTqzHTK3ByqzBSWxEzW5AQWJOTWxBRCXOTu9BSOvDzO3ByavBRKbOzaxOzizKSWlCQ2TAQCBJza7BRWdNzSxJSCbMzq9BSOtCSKrAwiPOTavPzy3LymlCySrAwmPFRKTPzy1NTGrPzu1JR+bOzatPzyzCy61ByGpOzWtJyCbPTmvPzuzIS+3FymxCSuzBR6nJyCZOTWvKSObMSujOzivAwKDOTSrNzKrJyGbDwyNOzWrMy2lIx2XBwWFBQSFBQODAwGBAQGBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABAALAAAAAAWABYAAAj/AAEEEDCAQAEDBxAkULCAQQMHDyBInBgggoQJFCpYqMDxAoYMGjZwmEixg4cPGzqA6BBiAggRIzaQGEkSwgAMJCKgnNBhQogSJlKGOFHTpgYUG0TsnJBCxQoSE1i0KErAxYsOJJRuuAAjhkwZM2jUqGnDBQoUHTbciIEjx4YNOmbs4CGjB8kCZlGAALHBx4+YcTcACcJDyFSJBo6iGNIhhQkiG8BOKGLkCBK6SSQisHoWhZIbG5bMYALECI8mTZw8gTL1QJQXZ6VMiUylSpUlVpoYaXLFtm0EGmCjwJLlA2O9MrRsccKlC8kEXr7AdgEmwtkhX2SQ2BIkjBiSYzSQr/nyhUKZLIrJJOcexvlEBV7IvCBjRkmAMzHOaufhxDvJBWiQISAFxUUQQRovJNeEGmu4JxEDbKQhXxsfuFDGGW68IQMcccgxRxUkNRDhC3R8QMQIdZwXQ11JJGFbiB+QYccHaaTxhgt13OFBDGTgkUdRDrhAhx5k2JjGCB/swYcXMXwAYk190OGHHx/4wUaVepTxByAaoPEkSQ5wwMEJZAZipiCDDJIHIYV8OZEdAQEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== nav1downarrow22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBBQSFAQGBDQyNExKTHx6fGxqbFxeXGRiZFRWVDw+PAwKDJSWlOzu7LSytJyenJSSlISGhISChIyOjFxaXDw6PPz+/MTCxLS2tIyKjKSmpKSipJyanAwODDQ2NHRydERCRFRSVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAZzQIBwSCwaj8ikcslsOp/OgHRKlQoCgymRUDAcEIkwYgxWFBYERpHQcDwgEclEQmk8DhWL2kiIXDBwExMNGRoJaUkEEH8bEQ0cGgcWAksEHX8QHBKSHk1sfxMHH5ROBBsOICGkT2wiq1CIULKztLW2t0h2QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 nav1leftarrow22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNAQCBExKTJSSlHx6fAQGBOzu7GxqbJyenPz+/LSytFxaXMTCxGRiZKSmpISGhFxeXISChAwKDFRWVHRydJSWlBQSFERCRIyKjDQ2NIyOjLS2tDw6PBwaHFRSVDw+PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAZ5QIBwSCwaj8ikchgQLJGBgfNZDBAKBirRekBMtYGEYsHIgsWNhOO7tCrShDU18Hg/CJAIG0o4wCUQcksTFBUSCRYSEnpUFxgIGQkJGYyNGggbHBaVjR2QCxEeWkITHQ4IH3tPFwEMA2ajAKUgqlQTTbFEE7W5vUgGQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 nav1rightarrow22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNGReZAQCBMTCxGRiZMzGzOTm5LSytPTy9Pz+/CwqLOTi5Ly6vCwmLMzKzJyanJSSlBQWFKymrIyGjCQeJJyWnISChISGhHx2fKyurDw6PAwODHx6fHRydDw2PERCRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAZ2QIBwSCwaj8hkMRBQKgOCgRMZIBSk06XhEM0SA4iE4uoVLhCMhqLrdSAekMgYO5VM4BQ521mxIC4UFxBWdEkSERYYFxETGQGFSBKCGBEaGRuQSBwdeZaPXpsQCB6YZQMdEI6ZSgMepKusHh+wrCC0rLdlursGQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 nav1uparrow22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBFxeXDw+PMTGxHRudPz+/JSSlLSytIyKjHR2dISChIyGjIyOjLSutLy6vKSepJyanISGhJSOlOzm7Ozu7MzGzKyurJyenDQyNGReZKSmpIR+hCwuLCQiJBwaHBQSFAwKDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAZtQIBwSCwaj8ikcslsOp9QYyAQFQYEAyr0Sihkn1fDAeHVLsOJNELxVaITC0bDUU6GH5AIQ8KYrNtFVxQVFBYWFxgRCREYdUQZGhYEDwgIGxAHCQocCgWOQhmhGR0epR8gqCFTq1Wtrq+wsUt0QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 nav2downarrow22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBAQGBBwaHDQyNExKTHx6fGxqbFxeXGRiZFRSVDw+PAwKDJSWlOzu7LSytJyenJSSlISGhISChIyOjFRWVDw6PPz+/MTCxLS2tGRmZDQ2NAwODJyanKSmpKSipIyKjHRydBQSFERCRExOTFxaXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAasQIBwSCwah4FkQKBsDpoBIqFgOCASCYRWm1AUFgRGkdBwPCARiWRCaTwOFYvYSIhcMOiJpJGZaDYcR0IEHXceEQ0fICEWIoJDhHcQHxIHgI9SEHeVG46YUh8OISOen1INCqWmUnOYTUxQAU9NUlRWWFtbCiRgrYNlZ2lriG8lYUd1khETE24gCZeCkRgeFBAQIAeNn9OTlXKrBJoYnKrcoaPmpmSpq3S+7u50QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 nav2leftarrow22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNAQCBExKTJSSlHx6fAQGBOzu7GxqbJyenPz+/LSytFxaXMTCxGRiZKSmpISGhFxeXISChAwKDFRWVHRydJSWlBQSFERCRIyKjDQ2NIyOjLS2tDw6PBwaHFRSVDw+PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAavQIBwSCwaj8gkMiBYNpeDZzEQXRIKBmPgmtUSDgipcAsWjxOKBaN7Tq+n6EbCIQ3E5+KtQk6gjwl7CX11D3sPBBARTQGFDYeJT2R8EhB0koKUfgATFBUSCRYSEoqcnqCiikMXGAgZCQkZqautr7FiFxoIGxwWqQC4ury+qh2tCxEexMbIRhMdDggfYs7Q0kcXAQwDbELY2txEziBmmx3jSRNMR+nk4e2b70ry80QGQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 nav2rightarrow22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNFxeXAQCBMTGxOzm7CwqLLy2vPTy9Pz+/Ly6vCQiJLSytLS2tLSutOTi5MzGzKSepIyKjJSOlKSmpMzKzJyanIyOjBwaHIyGjISGhJSSlISChBQSFJyenIR+hGxubDw+PHRydHR2dEQ+RHx6fERCRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAa6QIBwSCwaj8hkIIBcJgEBweAYnTYJUmMAa9USClniFtwlGg6IRFhoUKTXwwWj0FB3F46Hwl6UQyISfAB+EROCQgsUFRYSF3yJEIyBaxgWDBkaGRtclQwSHBIbEGEdGx4fGhcOICEDGBsWHBmqIq1CHRIWGRMMIyRTHRy6Er22tyONq8YdJRe0xkIDwr2/QwMfliMmZQADIxasZd4e4UYDIr7c59rc0eVFA+/m0EQD9PDt0flP/P3+BkEAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= nav2uparrow22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBGReZDQyNMTCxHx6fPz+/JyWnKyurHx2fDw6PJSSlISGhIyKjIyGjISChLy6vJyanOTm5PTy9OTi5MzKzLSytKSepMTGxMzGzLS2tLSutKymrHRydCQiJCwmLBwWHAwODLy2vHx+fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAajQIBwSCwaj8RAAMkUBgSDZdP4JBSi06TAcEAkFNLp07BgLLzY5njRcDzO3zB1C4lEGI83Wj58SiYUFRUWdg0XEXFFAwIYGRoWGxwRZQUFHZdgRAObmx4fHiChISFKpVlKWUdPaalOAlasp1sHG4myZGZ7Yltsbgu1mUhjdRF5egmxfQJ/gYOFdrZDi40iFgiSCw8jBQmYcpydn6Ego6WorUwGQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 navback22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAw2VCRGZAxCZGyavExmjHyatOTy9CxihISevPz+/KzO3BRylAw+XAQCBDRWbPz6/FzC3CSuzDyexJzO5Mzq9CxSdAQOFISmxNzu9HTS5BSmxAyexDSuzJTa7Mzu9Kzi7GS21CRmjAQOHHSWtLze7AyWvHzG3BRihAQKFCTO3BS+1AyixBSWvBSOtBSStAQWJBSixDzW5BTC3BSqzBS21CTC1ETW3AQSHEze7BRqlBRmjAQCDBR+pBRefBRSdCH5BAEAAAAALAAAAAAWABYAAAalQIBwSCwaj8ikMqBcMpvHgGAANQYIhWdVGDAcENQtIJBQLBgNx0MQaDuQXcghIplQDhBIxXKJYiAZGhscHR4VHyAhIiNWJBklGhIbJoQnFCcTKIxFKSgbKissJi0mJi4vLiYoMEcXKDEyMzQ1Nje2NisoOEg4KDU5K6g6OwwoKAN9SCOeMmgwz884PEq9PT4NYkPLP9jZQikN3d4AKVrjKePp3gZBACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= navdown22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAw2VCRKZDRSbBxCXJTC1Mzi7Nzq9NTm9Bx2nAQCBNzu9JzG3Hy+1HzG3IzO5BRmjPz6/LTe7Dy61AyStCTC1FzC1AyGrETS3ETC1ETa5BRulAyuzBRylAw+XMTe7Gy+3CSqzAyexBTC3DR+nIS21KTW5Nzu/KzO3FzC3Pz+/ByixEze7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAaRQIBwSCwaj8ikcnkMBAQDgjPAFAYKhsMBkVBUAYEFo+F4QLzVQEQyoVTOX/XBcsHA0+vMRbNBMwkRDhxuHX5GTlIeHh8gISIjFAEeiVRECiQlDAUmgxQjIhwiJHdFlycoKSIUFCEjGiGkRpcqCxYijxorsUezcxYsuoZJsxLAu0qXB7DCTJfHVQrMX9PU1Uh0QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 navforward22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAw2VAQCBBxCXDR+nIS21Aw+XJTC1Nzu/KzO3Pz+/Nzq9Pz6/MTe7KTW5FzC1Nzu9CRKZMzi7IzK3Lzi7LTe7HzG3Gy+3AyuzAyexFzC3DRSbHy+1Dy61CSqzAySvAyStLze7IzO5AyGrETa5ByixBRmjCTC1ETS3BTC3Bx2nAyWvEze7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAaYQIBwSCwaj8hkMqBsBgTN5IAAjRoDBaq1aDggtMuAWDzoJhTgY+CwYLgZDccDwkgXI5IJZVGxXDAZGnR2QxsLHB0PHRgeHyAZDyFfVUQDCyIgIyCPIB+QJCUmlEMBEiInKCQnKSkeKSQeomoqJrUmKiArKSwZsmoCwMEBGCyxo1EGHr3HUQEEvltCBtDRAAbMW0zV29xDBkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== navhome22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIYAAPwCBAQCBCQiJNze3ERCROTi5MzGzLy6vDw6PKyqrKyurBQSFGRiZGxqbGRmZISChEQ+RExKTExOTHRydDQyNOTe5FROVLSurCwqLMTCxPT29Pz6/LSutFxeXLyytLSytPz+/JSWlKympPTq7KSipNzW3BwaHHx6fKx2VJRWNHQmBFweDOzq7Ly+vNTW1JxWNLSajPTe1Ny6pKxWJNTS1IyOjJRmbPTi3OzKrNSSXMSGVHQiBHx+fJSSlPzy9IxOVOzWxOSyjNSCPLxeDJyWnIRGTOTGtMxmDLRWBHwqBIxGTLRSDDQuNNSunKxKBGwyNMSafMxqHMReDKRGDPTu9LxuPLxaDJQ+DIR+hGQqNIQyBGQiBNTO1EQKBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAf/gACCg4QBAYSIiYQCAwQCiokEhwACBQYHBAiQhAiHlQYJCgkEC5uCkp8MDQ4NDwylmwgQlgQRERIEBBOkmxQVBgQWFwUFFxEEDLyJGAUZtQoFGhsFHLYdyoOVHsEf0SAbIAUex8mwlAUhtSIFG+3uIyTWvAIGJMEkJe76GyXbEeWUBJg4USKaBhQpVKzYoIFFiwYUBBJa8MAFCw0vYMSQMWOhBhoTKCQSUKMEiw02buDIoWOHBg0GeIhEFKAHDR8afgAJImSIioYliMws1MPkhiJGchxBkmTDCBo1hg4KQMTiBiUyhBxZ8pNFiR5MEtU0WqSJVidJNDyNKraHC5xPNKBEkTLlJ5WvUgWNvfikyhArV34+7ZEXQAAsB2iUyHLlihYtW0pwOYAFgyJDmDNr7jIIWiAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== navup22:nav nav22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAw2VAQCBHSWtBRmjAQOHISmxNzu9BSmxBRihHyatPz6/Lze7CTO3BSixHTS5BTC3DzW5ByyzPz+/OTy9AyexEze7ByixGyavKzO3FzC3AyWvBS+1BR+pAQKFCRGZExmjCxihBRylCSuzBSWvBS21BSOtBRSdAw+XAxCZDyexDSyzCTC1JzO5JTa7DSuzETW3BRqlAQWJDRWbOT2/Mzq9HzG3JzS5Kzi7BSStGS21CxSdCRmjAQOFAQSHAAAACH5BAEAAAAALAAAAAAWABYAAAaeQIBwSCwaj8ikcqkMCJjHwIBQgBIDhgMiUbUGFAtGw0GFfheHByQi4S6/E8pDUoFYLm5kAEPJaBAVGxIcER0JHlEfICEiIxUkGyUmIgknKIhXASkonCorgSwmKQGcKE9IAi0uLxUwMTJWMzQ1NiYwBLBQHws1N7avXgs4NjkcCblMATU6KhvGyG87PAnUKV1MAj0+2zIFp1bg4eJJdkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== playeject22:play play22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNAwKDJSWlFRSVBQSFKymrOzq7HRydERCRPz+/MzGzISGhJyenKSmpGxqbJyWnJSOlKSepLy2vIyOjGRiZPTu9IyGjLSutFxaXExOTHx2fGReZAQCBAQGBBwaHCQiJLSytKyurJSSlFxeXNze3LS2tIyKjFxWXHRudAwGDBQOFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAa1QIBwSCwaj8ikcqkMCJjHwIBQgBIDhgMiUbVKFQsGItBdBhpgh4PxIJvRC8cA4oiMy8bvQhJhMAYTFBVOURAWEw0QFxcMERAYCBluVxobDxkVHJocmBwEGgmEQx0dHh0CpKmkH6odVlanBR8FtAIFtiCkSB0LISEiGCIGIxAPDySuRwIOBwrOzwoHJRHJRh0jJgMj2gMnERQUCNVFHQQoCBvo6CkICATjRB0qp7b1K6qv+foyQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 playend22:play play22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNFxeXAQCBMTCxGReZBQSFOzm7AwKDKymrJSSlFRSVCwqLLy6vPTy9OTe5Ozq7CQiJLSytOTi5BwaHPz+/HRydMzKzKSepJSOlKSipJyanIyGjIyKjKyurISGhMzGzJyWnHR2dISChIyOjLSutDw+PERCRHx6fJSWlIR+hJyenGRmZHx2fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAa6QIBwSCwaj8ikMBBQKgOCgRMZIBSkxYHWoDVWD9EigpBQLLBERsPxCA8NDUhjgTBGJJNGG02RVBQWdUV3FxgZe0IGfoAGdhoXGxwdiAYef4FGFBoeHB8dGSBRihUhIo1FBhkbIyMkJRYmAwYal4JEBh2RChIWJ1IIGxUZFqdECCgkHR6wWAYpFR2YWSobvL5vFgfDaEMDIivMRBEsD9HcQgMWvecDLB0tZ0btsfJa9vLXU/X6/P3+b0EAACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= playpause22:play play22 22:photo:22 22:R0lGODlhFgAWAIQAAPwCBAQCBAwODMTCxKSmpJSWlFRSVAQGBBwaHLSutOzq7Ly6vCQeJPz+/Hx2fBQWFGxubLSytJSOlBQOFAwKDJSSlJyWnIyOjHRydNze3GRiZAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAWBICCOZGmeaKqubOumQSDEgRjPMSoMRGEcol3vh0IkFAtDDWBEKlGMRKPgEIii0yrqIS1ArADu9KuLNCSOSdCMVp8ohEZFC4DL6SaBpXGh6/l4JX8XZACDhXkYCn1LAoqMUBAZEhBLDJKUSyYBGmhPAJyemiU0NDaloy+qq6ytI8whACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= playstart22:play play22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBDQyNAQCBExOTAwKDAQGBJSSlHx+fBQSFMTCxKymrFRSVOzu7GxqbLSytLy6vJyanPz+/GReZBwaHHRydKSepKSipGRiZJyWnAwODLSutKSmpISChPTu9ISGhFxaXJSWlIyGjJSOlERCRIyKjDw2PIyOjLy2vOzm7Dw6PLS2tCQmJOTe5GxmbDQ2NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAa7QIBwSCwaj8ik0hgQLJGBgbMoqBIKU2LAcMgOEQmFYeEFbBmNMgDhYDwWBC0k4pCoJ46IgRIXBioRCRYXamwRGBQIfgaBFhiERhkaenxmCoEbBhyQRYaIGVsdghgem4UWegcEBB8UHhsgIaZGBBgRIpUIIxQhChginEQIIBEklWslFyYnBsFfFCi4WQgpFBwqFxNGKxcsxl4IAS0NZEYCF3vlwgEfUuZV8JEuI2pPAARN9kcE9fr+SwaCAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 playstop22:play play22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBAQCBAwKDBQSFBwaHCQmJJSSlISChJSOlJSWlGxqbGRiZNTS1PTy9Pz+/Ozm7OTi5FRSVIyKjOTe5MTCxIR+hExOTHR2dLy6vLSytLy2vHRydFxWXIyGjIyOjPz2/FRWVHx6fExKTMzOzJyanKSmpKyqrKSipAQGBLSutHx2fDw6PAwODAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAa1QIBwSCwaj8ikcslsAgKCAWEQjQ4KgSwyYDAcugZEQqFYYJECA6PhaLcfEEUkgJZAGJB8fkKpWOhHAxcOGBQZGBoaGQgbHIBGAhUOGR0SBxISBh4Xf0iCHxQSlRIIXhsgj0UCIaCXmJgHGyKpRJ+hmB5dHQqOaCENIx0epBIkBhdzngoPGCQlJifQJBvJRygRKRcKGxcXGypys1srEREc5SLnICLiR1koLFVUWfRO9vf4+UwyQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 textblock22:text text22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAImhI+py30Bo5zBWUWzvNzo33GfFl5jVlonlTrr1DbvFi9vjeeNUQAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textbold22:text text22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAIxhI+py+0Powm0VnknjVkH2AEhE45LZ55Wqn6e65TsMc5eYosbksswubJIhsSiccgvAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 textcenter22:text text22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAImhI+py30Bo5zBWUbz3Sh7yIWfFHKjVl4nmFrr1Lpr7LwkjeeIUQAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textitalic22:text text22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAImhI+py+0P4wqUSlQvttrkDnyaOHIdeaGRupplAIauVM3xjeeOUQAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textleft22:text text22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAImhI+pyw0Bo5zB2UXz3Sp7yG2fFJajVjonmIor2TJvfL0wjecIXQAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textright22:text text22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAImhI+py30Bo5zBWUfz3SZ7yIXdF4kWqZkbCqoMO7kXLC+wVOe6YRQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== text22:text text22 22:photo:22 22:R0lGODlhFgAWAIQAAPwCBAQCBBwaHAwKDBQSFLy+vLS2tJSWlBQWFKyqrFRSVCwqLDQyNNTS1GxqbFxaXJyanIyOjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAVcICCOZGmKQSoMaZsShBsQBdAapHvgaIDUqUPJlRjSbAoT0fRDKgODRbF0PLUYjZO2F2Bst9evNix+dsvDlGKK5jraudQb7qbX6a2HEJ+ycyF+LRE8ZTI+fX5oGCEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== textunder22:text text22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAIvhI+py+0PowmUnhpeVVnb1DkbCI1I2JhX+Z0sOr2cTHpwK7a4rUr+hAnufsTirwAAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== viewchoose22:view view22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBAQCBFRSVExKTDQyNPz69PTq5Pz+/OzaxOTKpAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARTEMhJq70466Cl+AMxBVwnFIVRAmQHCIeBrC1L3tQgJ/SaEbeeC1PLBHE2ybFI9A1HzstHEIK6YCmhDTmBybQaHYJn7QC5zKeytIQe1+pKNE6P2yMAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== viewdetailed22:view view22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBFRSVExKTDQyNPz+/Pz69PTq5AQCBOzaxOTKpAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAQ+EMhJq7046817+MLQUQFRGMc4lQaSAkcMx3QltMmrDrSu/sCgEPgJhIiFk89DaL1qPRnlhsgBebWhdstVESIAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== viewicon22:view view22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBFRSVExKTDQyNPz69PTq5AQCBPz+/OzaxOTKpAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARWEMhJq7046z2DF0PlBeAVEERhiKhqHgWyUgEsX0KczFOO7JeBYciTCImc5ITIXDKHyqhU9AnRqq9UEVDTvmLbGhin2/qAliOUot5OLc81IO5+2+8WewQAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== viewmag-22:view view22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBBQSFJyanKy2tLzCxHyChNTa3Nzq7Nz29Nzy9Mzy9MTu9OTy9Nzi5Oz6/OT29MTi5Kzi7NTy9KTm7JzW3ITO1Lzq7IzW5HzK1LS+vMTq7Jze7ITW3GTCzGS+zLTS1MzOzLzq9Kzm7Jze5ITW5HTS3FS2vLze5EzCzEyyvEyutJTa5NTu9ITa5FTK1ESirLTm7Mzi5FS6xEy2vESerESmtFSutESmrKyqrAz+/Dw+RAzi3ASutHRydAQCBAAAACH5BAEAAAAALAAAAAAWABYAAAbKQIBQGCgWh8jksCgYEAaCozIZKBgOiIRiwSgEpstCw/HYQiKRhBcMCBgQDodkMaFU0t9pQHCIyy0TFxgYEVF6GQ4LCQkaERscHR4RH3lUIAkWCyEiIyQlHiYjEJVIAQQJJ2gjJSUoKSorlHoCLBQcHC0lLikvHjCGejEiHBgeMjM0NRwPpFQFDBHFNjceHAjAYFWoI7cnCVE4OWxtex8QH1EBOjs4zUpGUjw6Pe3j2fP19u/47vrq9P3s/avno2BBf/MCClSob4iBIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 viewmag22:view view22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBBQSFJyanKy2tLzCxHyChNTa3Nzq7Nz29Nzy9Mzy9MTu9OTy9Nzi5Oz6/OT29MTi5Kzi7NTy9KTm7JzW3ITO1Lzq7IzW5HzK1LS+vMTq7Jze7ITW3GTCzGS+zLTS1MzOzLzq9Kzm7Jze5ITW5HTS3FS2vLze5EzCzEyyvEyutJTa5NTu9ITa5FTK1ESirLTm7Mzi5FS6xEy2vESerESmtFSutESmrKyqrAz+/Dw+RAzi3ASutHRydAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAbIQIBQGCgWh8jksCgYEAaCozIZKBgOiIRiwSgEpstCw/HYQiKRhBcMCBgQDodkMaFU0t9pQHCIyy0TFxgYEVF6GQ4LCQkaERscHR4RH3lUIAkWCyEiIyQlHiYjEJVIAQQJJ2gjJSUoKSorlHoCLBQcHC0lLikvHjCGejEiHBgeMjM0NRwPpFQFDBHFNjceHAjAYFWoI7cnCVE4OWxtex8QH1EBOjs4zUpGUjw6Pe3j2fP19u/47vrq9P3s/cunr9S8gAIRFhTCLAgAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== viewmag+22:view view22 22:photo:22 22:R0lGODlhFgAWAIUAAPwCBBQSFJyanKy2tLzCxHyChNTa3Nzq7Nz29Nzy9Mzy9MTu9OTy9Nzi5Oz6/OT29MTi5Kzi7NTy9KTm7JzW3ITO1Lzq7IzW5HzK1LS+vMTq7Jze7ITW3GTCzGS+zLTS1MzOzLzq9Kzm7Jze5ITW5HTS3FS2vLze5EzCzEyyvEyutJTa5NTu9ITa5FTK1ESirLTm7Mzi5FS6xEy2vESerESmtFSutESmrKyqrAz+/Dw+RAzi3ASutHRydAQCBAAAACH5BAEAAAAALAAAAAAWABYAAAbQQIBQGCgWh8jksCgYEAaCozIZKBgOiIRiwSgEpstCw/HYQiKRhBcMCBgQDodkMaFU0t9pQHCIyy0TFxgYEVF6GQ4LCQkaERscHR4RH3lUIAkWCyEiIyQlHiYjEJVIAQQJJ2gjJSUoKSorlHoCLBQcHC0lLikvHjCGejEiHBgeMjM0NRwPpFQFDBHFNjceHAjAYFWoI7cnCVE4OWxtex8QH1EBOjs4zUpGUjw6Pe3j2fP19u/4zT766vRI+fvHD4CPgwcJ9qg0UB85JA0dDjEQBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 viewmulticolumn22:view view22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBFRSVExKTDQyNPz+/Pz69PTq5AQCBOzaxOTKpAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARTEMhJq7046813+MJQfUF4BURhHGO6noSBsEcNoDJtS4KcsJQe4ncZ1HYT47HDbDqfUAnJRJmKLIGCCjjJbmE5wBI3EyOFxKCPS1EiJW52dE6vZyIAIf5oQ3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw== viewtext22:view view22 22:photo:22 22:R0lGODlhFgAWAIAAAPwCBAQCBCH5BAEAAAAALAAAAAAWABYAAAIkhI+py+0Po2ShBlOxzbP7n2yaJoLm+ZTcxqHuC6hXzML2HVEFACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= viewtree22:view view22 22:photo:22 22:R0lGODlhFgAWAIMAAPwCBAQCBFRSVExKTDQyNPz+/Pz69Pzu5PTq5OzaxBQOFOzKpFRWVFxWXOzexPTexCH5BAEAAAAALAAAAAAWABYAAARPEMhJq704g6A779kHCORAgNskFMYhakE8FkjyBcoWv+JwJItXaELYCTFHlCSpZKKcoB5jYHpOGgUadLKbIRw3jhEzQDyCSuI4zW673yhDBAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7 ================================================ FILE: ext/tk/sample/tkextlib/ICONS/viewIcons.rb ================================================ #!/usr/bin/env ruby # # viewIcons.rb # # -- Display icons from icon library. # # -- Copy the clicked icon data (command string of creating # a TkPhotoImage instance) to the clipboard. # require 'tk' require 'tkextlib/ICONS' class ViewIcons ##################################### private ##################################### def _create_controls @controls = base = TkFrame.new columns = TkFrame.new(base) line1 = TkFrame.new(base, :height=>2, :borderwidth=>1, :relief=>:sunken) line2 = TkFrame.new(base, :height=>2, :borderwidth=>1, :relief=>:sunken) lbl_library = TkLabel.new(base, :font=>@boldfont, :text=>'Library') lbl_groups = TkLabel.new(base, :font=>@boldfont, :text=>'Groups') lbl_columns = TkLabel.new(base, :font=>@boldfont, :text=>'Columns') ent_library = TkEntry.new(base, :width=>50, :textvariable=>@library) ent_groups = TkEntry.new(base, :width=>50, :textvariable=>@groups) btn_browse = TkButton.new(base, :text=>'Browse', :command=>method(:select_icons)) btn_view = TkButton.new(base, :text=>'View', :command=>method(:display_icons)) btn_exit = TkButton.new(base, :text=>'Exit', :command=>proc{exit}) @column_btns = {} 6.step(20, 2){|i| @column_btns[i] = TkButton.new(columns, :text=>i.to_s, :width=>2, :command=>proc{set_columns(i)} ).pack(:side=>:left) } @column_btns[@columns][:relief] = :sunken lbl_library.grid(:row=>0, :column=>0, :padx=>4) ent_library.grid(:row=>0, :column=>1) btn_browse.grid(:row=>0, :column=>2, :padx=>4, :pady=>2, :sticky=>:ew) line1.grid(:row=>1, :column=>0, :pady=>2, :columnspan=>3, :sticky=>:ew) lbl_groups.grid(:row=>2, :column=>0, :padx=>4) ent_groups.grid(:row=>2, :column=>1) btn_view.grid(:row=>2, :column=>2, :padx=>4, :pady=>2, :sticky=>:ew) line1.grid(:row=>3, :column=>0, :pady=>2, :columnspan=>3, :sticky=>:ew) lbl_columns.grid(:row=>4, :column=>0, :padx=>4) columns.grid(:row=>4, :column=>1, :padx=>2, :sticky=>:ew) btn_exit.grid(:row=>4, :column=>2, :padx=>4, :pady=>2, :sticky=>:ew) base.pack ent_library.bind('Return', method(:display_icons), '') ent_groups.bind('Return', method(:display_icons), '') end def _create_display base = TkFrame.new(:borderwidth=>2, :relief=>:sunken) @icons_window = icons = TkCanvas.new(base) xscr = icons.xscrollbar(TkScrollbar.new(base)) yscr = icons.yscrollbar(TkScrollbar.new(base)) icons.grid(:row=>0, :column=>0, :sticky=>:news) yscr.grid(:row=>0, :column=>1, :sticky=>:ns) xscr.grid(:row=>1, :column=>0, :sticky=>:ew) base.grid_columnconfigure(0, :weight=>1) base.grid_columnconfigure(1, :weight=>0) base.grid_rowconfigure(0, :weight=>1) base.grid_rowconfigure(1, :weight=>0) # yscr.pack(:side=>:right, :fill=>:y) # xscr.pack(:side=>:bottom, :fill=>:x) # icons.pack(:side=>:left, :fill=>:both, :expand=>true) @icons_layout = TkFrame.new(icons).pack TkcWindow.create(icons, 0, 0, :anchor=>:nw, :window=>@icons_layout) @icons_layout.bind('Configure', method(:layout_resize), '') base.pack(:expand=>true, :fill=>:both) end def _create_info_window @info_window = TkToplevel.new(:background=>'lightyellow', :borderwidth=>1, :relief=>:solid){|w| lbl_name = TkLabel.new(w, :text=>'Name', :background=>'lightyellow', :font=>@boldfont, :justify=>:left) lbl_grps = TkLabel.new(w, :text=>'Groups', :background=>'lightyellow', :font=>@boldfont, :justify=>:left) lbl_type = TkLabel.new(w, :text=>'Type', :background=>'lightyellow', :font=>@boldfont, :justify=>:left) lbl_size = TkLabel.new(w, :text=>'Size', :background=>'lightyellow', :font=>@boldfont, :justify=>:left) lbl_name.grid(:row=>0, :column=>0, :sticky=>:w) lbl_grps.grid(:row=>1, :column=>0, :sticky=>:w) lbl_type.grid(:row=>2, :column=>0, :sticky=>:w) lbl_size.grid(:row=>3, :column=>0, :sticky=>:w) @name = TkLabel.new(w, :background=>'lightyellow', :justify=>:left) @grps = TkLabel.new(w, :background=>'lightyellow', :justify=>:left) @type = TkLabel.new(w, :background=>'lightyellow', :justify=>:left) @size = TkLabel.new(w, :background=>'lightyellow', :justify=>:left) @name.grid(:row=>0, :column=>1, :sticky=>:w) @grps.grid(:row=>1, :column=>1, :sticky=>:w) @type.grid(:row=>2, :column=>1, :sticky=>:w) @size.grid(:row=>3, :column=>1, :sticky=>:w) def name(txt) @name['text'] = txt end def groups(txt) @grps['text'] = txt end def type(txt) @type['text'] = txt end def size(txt) @size['text'] = txt end overrideredirect(true) withdraw } end def initialize(init_path = Tk::LIBRARY) init_path = Tk::LIBRARY unless init_path init_path = File.expand_path(init_path) if File.directory?(init_path) @initial_dir = init_path @initial_file = 'tkIcons' else @initial_dir = File.dirname(init_path) @initial_file = File.basename(init_path) end if Tk::PLATFORM['platform'] == 'unix' TkOption.add('*HighlightThickness', 0) end @columns = 14 @command = "" @delay_timer = nil dummy = TkLabel.new @font = dummy.font @boldfont = TkFont.new(@font, :weight=>:bold) @icons = {} @icon_name = {} @icon_info = {} @library = TkVariable.new(File.join(@initial_dir, @initial_file)) @groups = TkVariable.new('*') _create_controls _create_display _create_info_window Tk.root.title('viewIcons') layout_resize Tk.root.resizable(false, true) display_icons end def init_info(item, name) @icon_name[item] = name item.bind('Button-1', method(:clip_info), '%W') item.bind('Enter', method(:delay_info), '%W') item.bind('Leave', method(:cancel_info), '') end def delay_info(item) cancel_info @delay_timer = TkTimer.new(200, 1, proc{ show_info(item) }).start end def cancel_info if @delay_timer @delay_timer.cancel @delay_timer = nil end @info_window.withdraw end def show_info(item) name, groups, type, size = @icon_info[@icon_name[item]] @info_window.name(name) @info_window.groups(groups) @info_window.type(type) @info_window.size(size) info_x = item.winfo_rootx + 10 info_y = item.winfo_rooty + item.winfo_height @info_window.geometry("+#{info_x}+#{info_y}") @info_window.deiconify @info_window.raise @delay_timer = nil end def primary_transfer(offset, max_chars) @command end def lost_selection @command = "" end def clip_info(item) name = @icon_name[item] data_width = 60 cmd = "#{name} = TkPhotoImage.new(:data=><<'EOD')\n" icon_data = Tk::ICONS.query(name, :file=>@library.value, :items=>'d')[0][0] icon_data.scan(/.{1,#{data_width}}/m){|s| cmd << ' ' << s << "\n"} cmd << "EOD\n" @command = cmd TkClipboard.clear TkClipboard.append(@command) if Tk::PLATFORM['platform'] == 'unix' TkSelection.handle(Tk.root, method(:primary_transfer), :selection=>'PRIMARY') TkSelection.set_owner(Tk.root, :selection=>'PRIMARY', :command=>method(:lost_selection)) end Tk.bell end def layout_resize Tk.update bbox = @icons_window.bbox('all') width = @controls.winfo_width - @icons_window.yscrollbar.winfo_width - 8 @icons_window.configure(:width=>width, :scrollregion=>bbox, :xscrollincrement=>'0.1i', :yscrollincrement=>'0.1i') end def select_icons new_lib = Tk.getOpenFile(:initialdir=>@initial_dir, :initialfile=>'tkIcons', :title=>'Select Icon Library', :filetypes=>[ ['Icon Libraries', ['tkIcons*']], ['All Files', ['*']] ]) @library.value = new_lib if new_lib.length != 0 display_icons end def display_icons column = 0 limit = @columns - 1 row = 0 unless File.exist?(@library.value) Tk.messageBox(:icon=>'warning', :message=>'File does not exist', :title=>'viewIcons') return end cursor = Tk.root[:cursor] Tk.root[:cursor] = 'watch' Tk::ICONS.delete(@icons) @icons_frame.destroy if @icons_frame @icons_frame = TkFrame.new(@icons_layout).pack @icons = Tk::ICONS.create(:file=>@library.value, :group=>@groups.value) Tk::ICONS.query(:file=>@library.value, :group=>@groups.value).each{|inf| name = inf[0] @icon_info[name] = inf lbl = TkLabel.new(@icons_frame, :image=>"::icon::#{name}") lbl.grid(:column=>column, :row=>row, :padx=>3, :pady=>3) # lbl.grid_columnconfigure column init_info(lbl, name) if column == limit column = 0 row += 1 else column += 1 end } Tk.root[:cursor] = cursor end def set_columns(columns) @columns = columns 6.step(20, 2){|i| @column_btns[i][:relief] = :raised } @column_btns[@columns][:relief] = :sunken display_icons end end ViewIcons.new(ARGV[0]) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/blt/barchart5.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/blt' load File.join(File.dirname(File.expand_path(__FILE__)), 'scripts', 'stipples.rb') TkOption.add('*graph.x.Title', 'X Axis Label') TkOption.add('*graph.y.Title', 'Y Axis Label') TkOption.add('*graph.title', 'A Simple Barchart') TkOption.add('*graph.x.Font', 'Times 10') TkOption.add('*graph.Element.Relief', :raised) visual = Tk.root.winfo_screenvisual if visual != 'staticgray' && visual != 'grayscale' TkOption.add('*graph.LineMarker.color', 'yellow') TkOption.add('*graph.Element.Background', 'white') TkOption.add('*graph.Legend.activeForeground', 'pink') TkOption.add('*print.background', 'yellow') TkOption.add('*quit.background', 'red') TkOption.add('*graph.background', 'palegreen') TkOption.add('*graph.plotBackground', 'lightblue') end htext = Tk::BLT::Htext.new(:widgetname=>'.htext', :text=><'print', :text=>'Print', :command=>proc{ $graph.postsript(:output=>'bar.ps') }) Tk::BLT::Htext::Htext_Widget.window.append(b) } %% button. %% ruby { $graph = Tk::BLT::Barchart.new(:widgetname=>'.htext.graph', :relief=>:raised, :borderwidth=>2) $graph.xaxis_configure(:rotate=>90, :stepsize=>0) Tk::BLT::Htext::Htext_Widget.window.append($graph, :fill=>:both, :padx=>4) } %% Hit the %% ruby { b = TkButton.new(Tk::BLT::Htext::Htext_Widget.window, :widgetname=>'quit', :text=>'Quit', :command=>proc{ exit }) Tk::BLT::Htext::Htext_Widget.window.append(b) } %% button when you've seen enough.%% ruby { l = TkLabel.new(Tk::BLT::Htext::Htext_Widget.window, :bitmap=>'BLT') Tk::BLT::Htext::Htext_Widget.window.append(l, :padx=>20) } %% EOD names = %w(One Two Three Four Five Six Seven Eight) if visual == 'staticgray' || visual == 'grayscale' fgcolors = %w(white white white white white white white white) bgcolors = %w(black black black black black black black black) else fgcolors = %w(yellow orange red magenta purple blue cyan green) bgcolors = %w(yellow4 orange4 red4 magenta4 purple4 blue4 cyan4 green4) end numColors = names.length Tk::TCL_PRECISION.value = 15 x = Tk::BLT::Vector.new y = Tk::BLT::Vector.new x.seq(-5.0, 5.0, 0.2) y.expr("sin(#{x})") barWidth = 0.19 $graph.element_create('sin', :relief=>:raised, :borderwidth=>1, :x=>x, :y=>y, :barwidth=>barWidth) Tk::BLT::Table.add(Tk.root, htext, :fill=>:both) Tk.root.minsize(0, 0) Tk::BLT.zoom_stack($graph) Tk::BLT.crosshairs($graph) Tk::BLT.active_legend($graph) Tk::BLT.closest_point($graph) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/blt/calendar.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/blt' require 'date' dir = File.join(File.dirname(File.expand_path(__FILE__)), 'images') file = File.join(dir, 'chalk.gif') active = File.join(dir, 'rain.gif') texture1 = TkPhotoImage.new(:file=>file) texture2 = TkPhotoImage.new(:file=>active) TkOption.add('*Tile', texture1) TkOption.add('*HighlightThickness', 0) TkOption.add('*calendar.weekframe*Tile', texture2) TkOption.add('*Calendar.Label.borderWidth', 0) TkOption.add('*Calendar.Label.relief', :sunken) TkOption.add('*Calendar.Frame.borderWidth', 2) TkOption.add('*Calendar.Frame.relief', :raised) TkOption.add('*Calendar.Label.font', 'Helvetica 11') TkOption.add('*Calendar.Label.foreground', 'navyblue') TkOption.add('*button.foreground', 'navyblue') TkOption.add('*background', 'grey85') TkOption.add('*Label.ipadX', 200) TkOption.add('*tile', texture2) class BLT_Calendar_sample @@monthInfo = [ nil, # dummy ['January', 31], ['February', 28], ['March', 31], ['April', 30], ['May', 31], ['June', 30], ['July', 31], ['August', 31], ['Septembar', 30], ['October', 31], ['November', 30], ['December', 31] ] @@abbrDays = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ] def initialize() today = Date.today if TkComm.bool(Tk.info(:commands, '.calendar')) Tk.destroy('.calendar') end cal = Tk::BLT::Tile::Frame.new(:widgetname=>'.calendar', :classname=>'Calendar', :width=>'3i', :height=>'3i') mon = Tk::BLT::Tile::Label.new(cal, :font=>'Courier 14 bold', :text=>"#{@@monthInfo[today.month][0]} " + "#{today.year}") Tk::BLT::Table.add(cal, mon, [1, 0], :cspan=>7, :pady=>10) week_f = Tk::BLT::Tile::Frame.new(cal, :widgetname=>'weekframe', :relief=>:sunken, :borderwidth=>1) Tk::BLT::Table.add(cal, week_f, [2, 0], :columnspan=>7, :fill=>:both) @@abbrDays.each_with_index{|dayName, idx| Tk::BLT::Table.add(cal, Tk::BLT::Tile::Label.new(cal, :text=>dayName, :font=>'Helvetica 12'), [2, idx], :pady=>2, :padx=>2) } Tk::BLT::Table.itemconfigure(cal, 'c*', 'r2', :pad=>4) numDays = @@monthInfo[today.month][1] week = 0 cnt = 1 wkday = today.wday - ((today.day - 1) % 7) wkday += 7 if wkday < 0 while cnt <= numDays Tk::BLT::Table.add(cal, Tk::BLT::Tile::Label.new(cal, :text=>cnt){ self.configure(:borderwidth=>1, :relief=>:sunken) if cnt == today.day }, [week+3, wkday], :fill=>:both, :ipadx=>10, :ipady=>4) cnt += 1 wkday += 1 if wkday == 7 week += 1 wkday = 0 end end Tk::BLT::Tile::Frame.new(cal, :borderwidth=>1, :relief=>:sunken){|f| Tk::BLT::Table.add(f, Tk::BLT::Tile::Button.new(f, :widgetname=>'button', :command=>proc{exit}, :borderwidth=>2, :text=>'Quit'), :padx=>4, :pady=>4) Tk::BLT::Table.add(cal, f, [week+4, 5], :cspan=>2, :pady=>4) } Tk::BLT::Table.add(Tk.root, cal, :fill=>:both) Tk::BLT::Table.itemconfigure(cal, 'r0', :resize=>:none) end end BLT_Calendar_sample.new Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/blt/graph6.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/blt' Tk::TCL_PRECISION.value = 15 [ ['*Graph.Width', '10i'], ['*Graph.leftMargin', '.75i'], ['*Graph.Height', '6i'], ['*Graph.plotBackground', 'black'], ['*LineMarker.color', 'white'], ['*LineMarker.Dashes', 5], ['*TextMarker.foreground', 'white'], ['*TextMarker.Background', ''], ['*Graph.x.hide', true], ['*Graph.x.title', ''], ['*Graph.y.rotate', 90], # ['*Graph.y.stepSize', 2.0], ['*Graph.title', ''], ['*graph.Title', 'Example s27'], ['*graph.x.hide', false], ['*graph.topMargin', 0], ['*graph.bottomMargin', 0], ['*x.Title', 'Time'], ['*y.Title', 'Signals'], ['*Pixels', 1], ['*Reduce', 0.5], ['*bufferElements', false], ['*Element.color', 'green4'], ['*Element.ScaleSymbols', true], ['*Element.Color', 'grey70'], ['*Element.Symbol', :none], ['*Element.LineWidth', 1], # ['*Element.Smooth', :natural], ['*Element.Smooth', :catrom], ['*activeLine.LineWidth', 2], ['*activeLine.Color', 'white'], ['*activeLine.Color', 'green1'], # ['*Legend.Hide', true], ['*Legend.Position', :right], ['*Legend.Relief', :flat], ['*Legend.activeRelief', :sunken], ['*Legend.borderWidth', 2], #['*Legend.Font', '-*-helvetica-medium-r-*-*-10-*-*-*-*-*-*-*'], ['*Legend.Font', 'Helvetica -10'], ['*Grid.hide', false], ['*Grid.dashes', [1, 5]], # ['*foreground', 'white'], ['*zoomOutline.outline', 'yellow'], ].each{|k, v| TkOption.add(k, v)} ############################## class BLT_Graph_Demo def initialize @graph = Tk::BLT::Graph.new(:widgetname=>'graph') @root = Tk.root @root.minsize(0, 0) _set_vectors() (1..39).each{|i| @graph.element_create("V#{i}", :x=>@x, :y=>@v[i])} @top = Tk::BLT::Tile::Toplevel.new =begin legend = Tk::BLT::Graph.new(@top, :widgetname=>'legend', :without_creating=>true) @graph.legend_configure(:position=>legend) =end # legend = @graph.legend_window_create(@top, :widgetname=>'legend') legend = @graph.legend_window_create(@top) legend.pack(:fill=>:both, :expand=>true) Tk::BLT::Table.add(@root, @graph, [0,0], :fill=>:both) @quit_btn = Tk::BLT::Tile::Button.new(:text=>' quit ', :background=>'red', :command=>proc{exit}) Tk::BLT::Table.add(@root, @quit_btn, [1,0], :anchor=>:e, :padx=>10) @graph.zoom_stack @graph.crosshairs @graph.closest_point @graph.print_key @graph.legend_bind(:all, 'ButtonRelease-1', proc{|w| highlightTrace(w)}, '%W') @graph.legend_bind(:all, 'ButtonRelease-3', proc{|w| w.legend_deactivate('*') active = w.element_activate w.element_deactivate(*active) }, '%W') end private def _set_vectors @x = Tk::BLT::Vector.new(:variable=>'') @v = [] (1..39).each{|i| @v[i] = Tk::BLT::Vector.new(:variable=>'')} @x.set(<<-'EOD') 0 1e-10 2e-10 3e-10 4e-10 5e-10 6e-10 7e-10 8e-10 9e-10 1e-09 1.1e-09 1.2e-09 1.3e-09 1.4e-09 1.5e-09 1.6e-09 1.7e-09 1.8e-09 1.9e-09 2e-09 2.1e-09 2.2e-09 2.3e-09 2.4e-09 2.5e-09 2.6e-09 2.7e-09 2.8e-09 2.9e-09 3e-09 3.1e-09 3.2e-09 3.3e-09 3.4e-09 3.5e-09 3.6e-09 3.7e-09 3.8e-09 3.9e-09 4e-09 4.1e-09 4.2e-09 4.3e-09 4.4e-09 4.5e-09 4.6e-09 4.7e-09 4.8e-09 4.9e-09 5e-09 5.1e-09 5.2e-09 5.3e-09 5.4e-09 5.5e-09 5.6e-09 5.7e-09 5.8e-09 5.9e-09 6e-09 6.1e-09 6.2e-09 6.3e-09 6.4e-09 6.5e-09 6.6e-09 6.7e-09 6.8e-09 6.9e-09 7e-09 7.1e-09 7.2e-09 7.3e-09 7.4e-09 7.5e-09 7.6e-09 7.7e-09 7.8e-09 7.9e-09 8e-09 8.1e-09 8.2e-09 8.3e-09 8.4e-09 8.5e-09 8.6e-09 8.7e-09 8.8e-09 8.9e-09 9e-09 9.1e-09 9.2e-09 9.3e-09 9.4e-09 9.5e-09 9.6e-09 9.7e-09 9.8e-09 9.9e-09 1e-08 1.01e-08 1.02e-08 1.03e-08 1.04e-08 1.05e-08 1.06e-08 1.07e-08 1.08e-08 1.09e-08 1.1e-08 1.11e-08 1.12e-08 1.13e-08 1.14e-08 1.15e-08 1.16e-08 1.17e-08 1.18e-08 1.19e-08 1.2e-08 1.21e-08 1.22e-08 1.23e-08 1.24e-08 1.25e-08 1.26e-08 1.27e-08 1.28e-08 1.29e-08 1.3e-08 1.31e-08 1.32e-08 1.33e-08 1.34e-08 1.35e-08 1.36e-08 1.37e-08 1.38e-08 1.39e-08 1.4e-08 1.41e-08 1.42e-08 1.43e-08 1.44e-08 1.45e-08 1.46e-08 1.47e-08 1.48e-08 1.49e-08 1.5e-08 1.51e-08 1.52e-08 1.53e-08 1.54e-08 1.55e-08 1.56e-08 1.57e-08 1.58e-08 1.59e-08 1.6e-08 1.61e-08 1.62e-08 1.63e-08 1.64e-08 1.65e-08 1.66e-08 1.67e-08 1.68e-08 1.69e-08 1.7e-08 1.71e-08 1.72e-08 1.73e-08 1.74e-08 1.75e-08 1.76e-08 1.77e-08 1.78e-08 1.79e-08 1.8e-08 1.81e-08 1.82e-08 1.83e-08 1.84e-08 1.85e-08 1.86e-08 1.87e-08 1.88e-08 1.89e-08 1.9e-08 1.91e-08 1.92e-08 1.93e-08 1.94e-08 1.95e-08 1.96e-08 1.97e-08 1.98e-08 1.99e-08 2e-08 2.01e-08 2.02e-08 2.03e-08 2.04e-08 2.05e-08 2.06e-08 2.07e-08 2.08e-08 2.09e-08 2.1e-08 2.11e-08 2.12e-08 2.13e-08 2.14e-08 2.15e-08 2.16e-08 2.17e-08 2.18e-08 2.19e-08 2.2e-08 2.21e-08 2.22e-08 2.23e-08 2.24e-08 2.25e-08 2.26e-08 2.27e-08 2.28e-08 2.29e-08 2.3e-08 2.31e-08 2.32e-08 2.33e-08 2.34e-08 2.35e-08 2.36e-08 2.37e-08 2.38e-08 2.39e-08 2.4e-08 2.41e-08 2.42e-08 2.43e-08 2.44e-08 2.45e-08 2.46e-08 2.47e-08 2.48e-08 2.49e-08 2.5e-08 2.51e-08 2.52e-08 2.53e-08 2.54e-08 2.55e-08 2.56e-08 2.57e-08 2.58e-08 2.59e-08 2.6e-08 2.61e-08 2.62e-08 2.63e-08 2.64e-08 2.65e-08 2.66e-08 2.67e-08 2.68e-08 2.69e-08 2.7e-08 2.71e-08 2.72e-08 2.73e-08 2.74e-08 2.75e-08 2.76e-08 2.77e-08 2.78e-08 2.79e-08 2.8e-08 2.81e-08 2.82e-08 2.83e-08 2.84e-08 2.85e-08 2.86e-08 2.87e-08 2.88e-08 2.89e-08 2.9e-08 2.91e-08 2.92e-08 2.93e-08 2.94e-08 2.95e-08 2.96e-08 2.97e-08 2.98e-08 2.99e-08 3e-08 3.01e-08 3.02e-08 3.03e-08 3.04e-08 3.05e-08 3.06e-08 3.07e-08 3.08e-08 3.09e-08 3.1e-08 3.11e-08 3.12e-08 3.13e-08 3.14e-08 3.15e-08 3.16e-08 3.17e-08 3.18e-08 3.19e-08 3.2e-08 3.21e-08 3.22e-08 3.23e-08 3.24e-08 3.25e-08 3.26e-08 3.27e-08 3.28e-08 3.29e-08 3.3e-08 3.31e-08 3.32e-08 3.33e-08 3.34e-08 3.35e-08 3.36e-08 3.37e-08 3.38e-08 3.39e-08 3.4e-08 3.41e-08 3.42e-08 3.43e-08 3.44e-08 3.45e-08 3.46e-08 3.47e-08 3.48e-08 3.49e-08 3.5e-08 3.51e-08 3.52e-08 3.53e-08 3.54e-08 3.55e-08 3.56e-08 3.57e-08 3.58e-08 3.59e-08 3.6e-08 EOD @v[1].set(<<-'EOD') 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 EOD @v[2].set(<<-'EOD') 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 5.32907e-15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 EOD @v[3].set(<<-'EOD') 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 8.88178e-16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 2.13718e-14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 EOD @v[4].set(<<-'EOD') 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 EOD @v[5].set(<<-'EOD') 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 EOD @v[6].set(<<-'EOD') 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 8.88178e-16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4 3 2 1 2.13718e-14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 EOD @v[7].set(<<-'EOD') 5 5.16904 4.84159 3.34542 0.317102 0.103304 0.0275721 0.0221534 0.017689 0.0142639 0.0113974 0.00918238 0.00742541 0.00616602 0.00481195 0.00397049 -0.0659889 -0.025671 0.165495 0.986891 3.05229 4.55511 4.91611 4.98192 4.99428 4.99833 4.99095 4.97295 4.95493 4.93428 4.90723 4.94799 4.98584 4.99566 4.99813 4.99907 4.99947 4.99965 4.99976 4.99984 4.99989 4.99992 4.99994 4.99996 4.99998 5.00002 5.00006 5.00002 4.99996 4.99994 4.99999 5.00003 5.00002 5 4.99997 4.99997 4.99997 4.99997 4.99997 4.99996 4.99997 4.99997 4.99998 4.99998 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5.16575 4.69986 2.43862 0.0230224 0.035229 -0.0210607 -0.0292766 -0.0172693 -0.00271479 -0.000912251 -0.000349106 -0.000116866 -4.24733e-05 -1.39536e-05 -3.01179e-05 -0.0657192 -0.0204835 0.183378 1.07181 3.118 4.46472 4.84158 4.94795 4.98173 4.99236 4.99762 5.01939 5.0433 5.05332 5.04959 5.03955 5.02851 5.02052 5.01422 5.00965 5.00631 5.00405 5.00248 5.00083 5.00012 5.00209 5.00387 5.00347 4.99917 4.99213 4.98411 4.97521 4.96332 4.94601 4.9304 4.94633 4.97936 4.99264 4.99685 4.99857 4.99925 4.99954 4.9997 4.99973 4.9997 4.99973 4.99979 4.99983 4.99986 4.99988 4.9999 4.9999 4.99992 4.99993 4.99994 4.99995 4.99996 4.99996 4.99997 4.99997 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5.14242 4.76101 3.16003 0.299374 0.0645506 -0.000498424 -2.45108e-05 -2.27986e-05 -5.24401e-05 -4.9884e-05 -4.92491e-05 -2.93354e-05 -3.21402e-05 -2.11851e-05 -3.37925e-05 -0.0657892 -0.020563 0.182582 1.06058 3.12484 4.46552 4.84146 4.95102 4.98556 4.99472 4.99806 4.99909 4.99955 4.99976 4.99994 4.99992 5.00029 4.99967 4.99849 4.99736 4.99884 5.00099 5.00377 5.00215 4.99994 4.99893 4.99788 4.99862 5.00055 5.00134 5.00127 5.00073 5.00039 5.00018 5.00006 5.00001 4.99985 5.00026 5.00018 5.00003 4.99981 4.99985 4.99987 4.99985 4.99982 4.99982 4.99982 4.99983 4.99985 4.99987 4.99989 4.99991 4.99992 4.99994 4.99995 4.99995 4.99994 4.99994 4.99996 4.99999 5.00002 5.00008 5.00009 5.00006 5.00001 5 4.99999 4.99998 4.99997 4.99996 4.99997 4.99997 4.99998 4.99998 4.99999 4.99999 4.99999 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 EOD @v[8].set(<<-'EOD') 5 5.03758 5.04711 4.96911 4.20882 3.96295 4.01117 4.15521 4.2967 4.42274 4.5295 4.6176 4.69014 4.74831 4.7966 4.83537 4.80526 4.787 4.79295 4.88588 5.08978 5.15615 5.10778 5.07718 5.06652 5.08225 4.9744 4.52977 3.77452 2.69426 1.15294 0.245509 0.0981544 0.0567527 0.0367487 0.0252578 0.0180599 0.0133837 0.0101497 0.0078616 0.00620186 0.00499056 0.0041027 0.00344223 0.00295808 0.00260089 0.00229887 0.00200817 0.00176397 0.00160116 0.00147381 0.00134645 0.00125029 0.00116043 0.00107371 0.00101981 0.000965921 0.000912028 0.000858135 0.000804242 0.000761669 0.00072672 0.000691771 0.000656823 0.000621874 0.000588722 0.00057041 0.000552098 0.000533785 0.000515473 0.000497162 0.00047885 0.000460537 0.000442226 0.000423914 0.000405601 0.000388399 0.000378694 0.000368989 0.000359284 0.00034958 0.000339875 0.00033017 0.000320465 0.00031076 0.000301055 0.00029135 0.000282207 0.000276247 0.000270287 0.000264327 0.000258367 0.000252407 0.000246447 0.000240487 0.000234527 0.000228567 0.000222607 0.000217086 0.000213696 0.000210307 0.000206918 0.000203528 0.000200139 0.00019675 0.00019336 0.000189971 0.000186582 0.000183192 0.000179803 0.000176414 0.000173025 0.000169635 0.000166246 0.000162857 0.000159467 0.000156078 0.000152689 0.000149299 0.00014591 0.00014255 0.0316021 0.163272 0.348732 0.603651 0.35745 0.135965 0.0707354 0.0314595 0.0201047 0.00994945 0.00389601 0.00138839 0.00060778 0.000329648 0.000492396 -0.0732035 -0.0844077 -0.0789062 -0.0390837 0.0197559 0.0183094 -0.00180099 -0.0189565 -0.0424144 -0.0735904 -0.0892423 0.285039 1.13702 2.10809 2.95826 3.60164 4.0435 4.35771 4.57254 4.71769 4.81329 4.87534 4.91487 4.94264 4.97375 5.01526 5.06517 5.10154 5.06259 4.89005 4.5787 4.12226 3.46151 2.49023 1.2586 0.32725 0.116753 0.0701865 0.0455509 0.0286914 0.0178176 0.0117599 0.00902715 0.00760583 0.00637745 0.00543811 0.00439377 0.00352448 0.0030151 0.00285771 0.002465 0.00203114 0.00173004 0.0014839 0.00125177 0.00105327 0.000894905 0.000766372 0.000658894 0.000569105 0.000492114 0.000427938 0.000370217 0.000314758 0.000266569 0.000233726 0.000209048 0.000191957 0.000177169 0.000166604 0.000161 0.000157314 0.000143828 0.000130342 0.000116857 0.000103371 8.98855e-05 7.63998e-05 6.29141e-05 5.76583e-05 5.30027e-05 4.8347e-05 4.36913e-05 3.90357e-05 3.438e-05 2.97243e-05 2.72507e-05 2.59083e-05 2.45659e-05 2.32235e-05 2.18811e-05 2.05387e-05 1.91963e-05 1.78539e-05 1.65115e-05 1.51691e-05 1.38267e-05 1.24843e-05 1.11419e-05 9.79954e-06 8.51574e-06 7.69807e-06 6.8804e-06 6.06273e-06 5.24506e-06 0.0287318 0.0317111 -0.0320087 -0.103609 0.0369639 0.0121128 0.00961197 0.00934971 0.00820853 0.00699769 0.00607002 0.00535541 0.00476552 0.00427601 0.00376357 -0.073012 -0.0866964 -0.0809538 -0.038005 0.0277001 0.0188906 0.00614597 0.00373629 0.00489787 0.0146573 0.0191052 0.0151708 0.0124224 0.0105859 0.00879272 0.00729464 0.0070047 0.00449575 -0.00626652 -0.0252417 -0.0147287 0.022538 0.0822905 0.0947372 0.0657516 0.0445506 0.0316753 0.0220971 0.0158101 0.0140971 0.0161498 0.0139876 0.0122447 0.0106994 0.009397 0.00822236 0.00686509 0.00797431 0.00751269 0.00671173 0.00595243 0.00524633 0.00459528 0.00401688 0.00350109 0.00303954 0.00260569 0.00222792 0.00191033 0.00163917 0.00140949 0.00121464 0.0010471 0.000900638 0.000768847 0.000645236 0.000524807 0.000460275 0.000442237 0.000446775 0.000397026 0.000301585 0.000228994 0.000190894 0.000166569 0.000152261 0.000137953 0.000123644 0.000109336 9.50281e-05 8.56557e-05 7.78437e-05 7.00318e-05 6.22198e-05 5.44079e-05 4.87539e-05 4.57761e-05 4.27982e-05 3.98203e-05 3.68425e-05 3.38646e-05 3.08868e-05 2.79089e-05 2.4931e-05 2.19532e-05 1.89753e-05 1.75244e-05 1.64095e-05 1.52946e-05 1.41797e-05 1.30648e-05 1.19499e-05 1.0835e-05 9.72011e-06 8.60521e-06 7.4903e-06 6.5117e-06 6.10334e-06 5.69497e-06 5.2866e-06 4.87824e-06 4.46987e-06 4.06151e-06 3.65314e-06 3.24477e-06 EOD @v[9].set(<<-'EOD') 1.86175 1.99708 2.07867 2.01211 2.43309 3.27194 3.63896 3.90426 4.11074 4.27932 4.41496 4.52543 4.61491 4.68862 4.7479 4.79666 4.72895 4.68886 4.70354 4.81353 5.01568 5.14184 5.10482 5.07362 5.05143 5.03638 5.02323 5.01465 5.00853 5.00383 4.99985 5.00454 5.00652 5.00546 5.00411 5.003 5.00214 5.00151 5.00106 5.00073 5.0005 5.00034 5.00023 5.00015 5.0001 5.00005 5 5.00001 5.00005 5.00005 5.00003 5 4.99998 4.99996 4.99994 4.99995 4.99997 4.99998 5 5.00001 5.00002 5.00002 5.00003 5.00003 5.00003 5.00003 5.00003 5.00003 5.00002 5.00002 5.00001 5.00001 5.00001 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.17392 4.94828 3.78491 1.52079 0.608874 0.244031 0.127087 0.0552995 0.0361032 0.0169025 0.006364 0.00217624 0.000921391 0.000457305 0.000786754 -0.120016 -0.148054 -0.15898 -0.0801463 0.16463 0.174017 0.0799249 0.0318788 0.0129696 0.00483397 0.0025677 0.0042079 0.00350003 0.00178404 -8.72902e-05 -0.00128497 -0.00142213 -0.00130018 -0.00106874 -0.000789207 -0.000824335 -0.00104518 -0.00136799 -0.004366 -0.0102621 -0.0109254 -0.00649259 -0.00194842 0.00029793 0.00148673 0.00221085 0.00228291 0.00185261 0.00139687 0.00148183 0.00562266 0.00844119 0.00754627 0.00657396 0.00591212 0.00539269 0.0049282 0.00448417 0.0040572 0.00363719 0.00320392 0.00279607 0.00243938 0.00211505 0.00182302 0.00156254 0.0013341 0.00113834 0.000971865 0.00082776 0.000706193 0.000602499 0.000515059 0.000441401 0.00037897 0.000325459 0.00028083 0.000242096 0.000207274 0.000176444 0.000150372 0.000126407 0.000103373 9.05522e-05 8.53555e-05 8.63685e-05 9.02593e-05 8.37346e-05 7.72099e-05 7.06852e-05 6.41605e-05 5.76358e-05 5.11112e-05 4.45865e-05 4.08176e-05 3.72497e-05 3.36818e-05 3.01138e-05 2.65459e-05 2.2978e-05 1.94101e-05 1.76154e-05 1.67399e-05 1.58645e-05 1.4989e-05 1.41136e-05 1.32381e-05 1.23626e-05 1.14872e-05 1.06117e-05 9.73629e-06 8.86083e-06 7.98538e-06 7.10993e-06 6.23447e-06 5.44363e-06 5.32578e-06 5.20792e-06 5.09007e-06 4.97222e-06 0.0784323 0.0474527 -0.0764232 -0.151146 0.0615785 0.0144489 0.00974161 0.00947176 0.00849005 0.00728201 0.00630581 0.00554032 0.00487809 0.00441504 0.00384139 -0.118943 -0.149894 -0.161173 -0.0825299 0.171686 0.176912 0.0816085 0.0335236 0.013791 0.0056976 0.00238833 0.00105348 0.000526199 0.00025969 0.000396026 0.000837835 0.00170131 0.00196699 -0.000553314 -0.0061621 -0.0111895 -0.0142698 -0.0124608 -0.00795847 -0.00467822 -0.0043058 -0.00874449 -0.0118584 -0.00871386 -0.00377892 1.95244e-05 0.00218952 0.00325486 0.00386497 0.00422837 0.00446883 0.00447065 0.00486647 0.00547838 0.00565398 0.00559092 0.00538752 0.00507015 0.00466305 0.00420756 0.00373465 0.00328404 0.00287059 0.00250057 0.00216124 0.00184861 0.00156815 0.00134624 0.00117857 0.00103412 0.0008948 0.000761012 0.000619853 0.000462614 0.000319965 0.000287666 0.000356415 0.000379946 0.000339183 0.00027972 0.000252982 0.000226244 0.000199507 0.000172769 0.000146031 0.000130097 0.000117578 0.000105059 9.25401e-05 8.00213e-05 7.11204e-05 6.67061e-05 6.22918e-05 5.78775e-05 5.34632e-05 4.90489e-05 4.46346e-05 4.02203e-05 3.5806e-05 3.13916e-05 2.69773e-05 2.4827e-05 2.31747e-05 2.15225e-05 1.98702e-05 1.8218e-05 1.65658e-05 1.49135e-05 1.32613e-05 1.1609e-05 9.95678e-06 8.50108e-06 7.86765e-06 7.23422e-06 6.60079e-06 5.96736e-06 5.33393e-06 4.7005e-06 4.06707e-06 3.43363e-06 EOD @v[10].set(<<-'EOD') 1.86175 1.99308 2.16619 2.46661 3.09359 3.76864 4.31299 4.65564 4.83425 4.92153 4.96157 4.98063 4.98649 4.99039 4.9945 4.9972 4.96206 4.89882 4.83865 4.83202 4.91016 5.04479 5.06078 5.04827 5.03474 5.0246 5.01639 5.00996 5.00569 5.00239 5.00043 5.00296 5.00437 5.00382 5.00287 5.00208 5.00148 5.00104 5.00073 5.0005 5.00034 5.00023 5.00016 5.00011 5.00008 5.00007 5.00007 5.00004 5 4.99998 4.99998 4.99997 4.99998 4.99999 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 5.10081 5.10949 4.98359 5.00733 5.15145 4.37298 2.36126 0.470759 0.0577238 0.0115884 0.00262611 0.000671499 0.000389038 0.000291291 0.000317347 -0.0167823 -0.0158344 -0.0140559 0.0104849 0.0865874 0.107813 0.0524688 0.0214369 0.00876443 0.00341595 0.00170778 0.00259042 0.0022241 0.00118519 1.10217e-06 -0.000784506 -0.000948169 -0.000856256 -0.000696719 -0.000485987 -0.000724787 -0.000981491 -0.001454 -0.00552498 -0.0114992 -0.0105266 -0.00543527 -0.000982798 0.00127356 0.00224212 0.00275439 0.00281098 0.0025471 0.00230368 0.00222576 0.00485522 0.00729453 0.00691796 0.0062615 0.00573987 0.0052688 0.00481185 0.00436934 0.00394326 0.00352712 0.00309978 0.00270038 0.00235335 0.00203742 0.00175256 0.00150067 0.00128126 0.00109323 0.000933619 0.000795113 0.000678182 0.00057843 0.000494345 0.000423609 0.000363821 0.000312766 0.000269856 0.000232389 0.000198382 0.000168126 0.00014267 0.000119293 9.69034e-05 8.5669e-05 8.26828e-05 8.64066e-05 9.26665e-05 8.5454e-05 7.82416e-05 7.10291e-05 6.38167e-05 5.66043e-05 4.93918e-05 4.21794e-05 3.86073e-05 3.53007e-05 3.19941e-05 2.86876e-05 2.5381e-05 2.20744e-05 1.87678e-05 1.70933e-05 1.62648e-05 1.54363e-05 1.46079e-05 1.37794e-05 1.2951e-05 1.21225e-05 1.12941e-05 1.04656e-05 9.63716e-06 8.80871e-06 7.98026e-06 7.1518e-06 6.32335e-06 5.5374e-06 5.08959e-06 4.64178e-06 4.19397e-06 3.74616e-06 0.0438026 0.0242078 -0.0602019 -0.0840866 0.00148461 -0.00292489 0.000442098 0.00219489 0.00281478 0.00290756 0.00277945 0.00263896 0.00240099 0.00223283 0.001947 -0.0153629 -0.0148815 -0.0128673 0.0126017 0.0905161 0.11051 0.0538958 0.022562 0.00935726 0.00397422 0.00172534 0.000790207 0.000416322 0.000191632 0.000469721 0.0009779 0.00192566 0.00200688 -0.0016502 -0.00733932 -0.0128113 -0.0147608 -0.0115456 -0.00668995 -0.00401368 -0.00463908 -0.0101197 -0.0118993 -0.0076276 -0.00262656 0.000813059 0.00264455 0.00350796 0.00399494 0.0043049 0.00451658 0.00444739 0.00503842 0.00559516 0.00568213 0.00556459 0.0053176 0.00496654 0.00454337 0.00408592 0.00362171 0.00317793 0.00277001 0.00240394 0.00207009 0.00176575 0.00149725 0.00129045 0.00114257 0.00101135 0.000871672 0.000723764 0.000580438 0.000427507 0.000296956 0.000281834 0.000376628 0.000412266 0.000367547 0.000295305 0.000264513 0.000233721 0.000202929 0.000172137 0.000141345 0.000124721 0.000112577 0.000100433 8.82893e-05 7.61453e-05 6.75517e-05 6.33609e-05 5.91701e-05 5.49792e-05 5.07884e-05 4.65976e-05 4.24067e-05 3.82159e-05 3.40251e-05 2.98342e-05 2.56434e-05 2.36401e-05 2.21181e-05 2.05961e-05 1.90741e-05 1.75521e-05 1.60301e-05 1.45081e-05 1.29861e-05 1.14641e-05 9.94208e-06 8.59252e-06 7.96439e-06 7.33626e-06 6.70813e-06 6.07999e-06 5.45186e-06 4.82373e-06 4.1956e-06 3.56747e-06 EOD @v[11].set(<<-'EOD') 1.86175 1.73419 1.42874 1.04055 0.943004 0.268275 0.0826455 0.0388346 0.0214104 0.0135431 0.00961322 0.00712846 0.00588262 0.00432397 0.00377774 0.00270134 -0.00393731 -0.00542187 -0.00126596 0.0113777 0.0134522 0.00477056 -0.00211067 -0.00229253 -0.00173355 -0.00122404 -0.00113426 -0.000744931 -0.000520112 -0.000410048 -0.000220439 0.000508104 5.15856e-05 -0.000112593 -0.000118917 -9.57394e-05 -7.15727e-05 -5.11847e-05 -3.58275e-05 -2.47166e-05 -1.68866e-05 -1.14082e-05 -7.66646e-06 -5.12139e-06 -3.63426e-06 -3.01815e-06 -2.64862e-06 -1.4947e-06 -1.91403e-07 -2.5763e-08 -7.73699e-07 -1.52164e-06 -1.07268e-06 -3.81696e-07 2.6727e-07 4.75489e-07 6.83708e-07 8.91926e-07 1.10014e-06 1.30836e-06 1.2482e-06 1.00726e-06 7.66311e-07 5.25364e-07 2.84417e-07 6.27857e-08 7.43904e-10 -6.12979e-08 -1.2334e-07 -1.85382e-07 -2.47423e-07 -3.09465e-07 -3.71507e-07 -4.33549e-07 -4.95591e-07 -5.57633e-07 -6.04571e-07 -5.4944e-07 -4.9431e-07 -4.3918e-07 -3.84049e-07 -3.28919e-07 -2.73789e-07 -2.18659e-07 -1.63528e-07 -1.08398e-07 -5.32678e-08 1.062e-09 5.08502e-08 1.00638e-07 1.50427e-07 2.00215e-07 2.50003e-07 2.99791e-07 3.4958e-07 3.99368e-07 4.49156e-07 4.98944e-07 5.34512e-07 5.01032e-07 4.67553e-07 4.34073e-07 4.00593e-07 3.67113e-07 3.33633e-07 3.00153e-07 2.66674e-07 2.33194e-07 1.99714e-07 1.66234e-07 1.32754e-07 9.92744e-08 6.57945e-08 3.23147e-08 -1.16513e-09 -3.4645e-08 -6.81248e-08 -1.01605e-07 -1.35084e-07 -1.68564e-07 -2.18729e-07 0.0114926 -0.0245378 -0.111828 0.0964775 1.61491 3.22668 4.22041 4.54492 4.82845 4.94868 4.98588 4.99609 4.9981 4.99908 4.99788 4.98395 4.99294 4.99724 5.01939 5.0471 5.00902 4.98194 4.98496 4.99188 4.99623 4.99862 5.00025 4.99974 4.99953 4.99946 4.99958 5.00012 4.99997 4.99992 4.99988 4.99985 4.9998 4.9997 4.9988 4.99806 4.99982 5.00143 5.00159 5.00098 5.00053 5.00028 5.00007 4.99977 4.99992 5.00005 5.00133 5.0009 4.99993 4.99972 4.99975 4.9998 4.99982 4.99983 4.99983 4.99983 4.99983 4.99984 4.99986 4.99987 4.99989 4.9999 4.99991 4.99992 4.99994 4.99995 4.99995 4.99996 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5.01457 4.99482 4.96561 4.99326 5.03452 5.00424 5.00101 5.00045 5.00004 4.99965 4.99997 4.99994 4.99958 4.99999 4.99936 4.9839 4.99248 4.99717 5.01976 5.04869 5.0087 4.98143 4.98488 4.99199 4.99622 4.9983 4.99928 4.99971 4.99986 5.00031 5.00022 5.00035 5.0001 4.99884 4.99811 4.99803 4.99887 5.00078 5.00151 5.00116 5.00007 4.99843 4.99915 5.00107 5.00168 5.00141 5.00092 5.00055 5.0003 5.00016 5.0001 5.00001 5.00016 5.0002 5.00009 4.99993 4.99975 4.99984 4.99991 4.99991 4.99982 4.99974 4.99974 4.99985 4.99995 4.99999 4.99998 5.00004 5.00013 5.00015 5.00007 4.99988 4.99982 4.99985 4.99995 5.00006 5.0002 5.00025 5.0002 5.00009 5.00006 5.00004 5.00002 5 4.99998 4.99997 4.99998 4.99998 4.99999 4.99999 4.99999 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 EOD @v[12].set(<<-'EOD') 5 5.16975 4.78685 2.94241 0.126698 0.0487004 -0.00422591 -0.00130689 -0.000486756 -0.000195875 -0.000108988 -6.66736e-05 -7.26005e-05 -5.63608e-05 -3.81859e-05 -2.123e-05 -0.0646846 -0.0184474 0.182248 1.06731 3.10988 4.46133 4.84133 4.95113 4.98364 4.99455 4.99694 4.99727 4.9994 4.99975 5.0001 5.00132 5.00089 5.00039 5.00019 5.00011 5.00006 5.00005 5.00004 5.00001 4.99992 4.99992 5.00002 5.00013 5.00017 5.00009 4.99992 4.99991 4.99994 4.99996 4.99998 4.99999 5.00001 5.00004 5.00006 5.00005 5.00004 5.00003 5.00002 5.00001 5 4.99999 4.99999 4.99998 4.99998 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5.14699 4.78074 3.19424 0.305663 0.0611255 -0.00179951 -0.0012032 0.000405978 0.000989399 0.000445194 0.000191447 8.30476e-05 3.96236e-05 1.91866e-05 1.70665e-05 -0.0655239 -0.0210234 0.1827 1.06848 3.11554 4.46518 4.84212 4.94853 4.98244 4.99434 4.9997 5.00081 5.00009 4.99972 4.99985 4.99974 4.9995 4.99949 4.99958 4.99973 4.99948 4.99914 4.99874 4.99946 5.00309 5.0091 5.01576 5.01835 5.01852 5.0176 5.01625 5.01479 5.01345 5.01264 5.011 5.01092 5.01344 5.01363 5.01289 5.01184 5.01071 5.00956 5.00848 5.00751 5.00663 5.00577 5.00497 5.00427 5.00365 5.0031 5.00264 5.00224 5.00191 5.00163 5.00138 5.00117 5.00099 5.00083 5.00071 5.00061 5.00053 5.00045 5.00037 5.00029 5.00022 5.00019 5.0002 5.00023 5.00024 5.00023 5.00023 5.00022 5.0002 5.00018 5.00016 5.00014 5.00011 5.00009 5.00007 5.00006 5.00005 5.00005 5.00004 5.00003 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.14298 4.79809 3.32704 0.498385 0.105773 0.0160646 0.0319912 0.0299434 0.0240102 0.0185844 0.0130411 0.0106532 0.00864871 0.00744519 0.00660887 -0.0612913 -0.0203719 0.174998 0.991787 3.06292 4.60005 4.93058 4.98917 5.00033 4.9999 4.99909 4.9966 4.9955 4.99488 4.99374 4.9943 5.00131 5.00506 4.99311 4.96288 4.93567 4.92439 4.94236 4.9732 4.98864 4.99458 5.00031 5.00694 5.01525 5.01945 5.01998 5.01953 5.01874 5.01766 5.0164 5.01509 5.01326 5.01423 5.01455 5.01361 5.01245 5.01122 5.01002 5.00888 5.00783 5.00687 5.00596 5.00514 5.00442 5.00379 5.00325 5.00279 5.0024 5.00208 5.0018 5.00153 5.00126 5.00107 5.00094 5.00085 5.00078 5.00072 5.00063 5.00053 5.00042 5.00038 5.00034 5.0003 5.00027 5.00023 5.00021 5.00019 5.00017 5.00015 5.00013 5.00012 5.00011 5.0001 5.0001 5.00009 5.00008 5.00007 5.00007 5.00006 5.00005 5.00005 5.00004 5.00004 5.00003 5.00003 5.00002 5.00002 5.00002 5.00001 5.00001 5 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 EOD @v[13].set(<<-'EOD') 9.73784e-10 0.0189926 0.0926769 0.206309 0.111533 0.0953491 0.0426966 0.0214177 0.0117943 0.00741442 0.00528816 0.00398417 0.0032967 0.00266499 0.00206647 0.00158788 -0.0371391 -0.0439528 -0.0408653 -0.0188706 0.0150241 0.0126852 0.00209817 -0.000239206 -5.31488e-05 0.000876324 -0.00451221 -0.0165223 -0.0284127 -0.0427584 -0.0502453 -0.0257366 -0.00903938 -0.00376456 -0.00233385 -0.00169922 -0.00130397 -0.00102542 -0.000811435 -0.000648115 -0.000529266 -0.00043795 -0.00036574 -0.00030716 -0.00026221 -0.000229662 -0.000205112 -0.000181038 -0.000162045 -0.000148988 -0.000137633 -0.000126278 -0.000115562 -0.000104976 -9.49324e-05 -9.0585e-05 -8.62375e-05 -8.18901e-05 -7.75426e-05 -7.31952e-05 -6.93752e-05 -6.59106e-05 -6.24461e-05 -5.89815e-05 -5.55169e-05 -5.22412e-05 -5.05263e-05 -4.88114e-05 -4.70966e-05 -4.53817e-05 -4.36668e-05 -4.19519e-05 -4.0237e-05 -3.85222e-05 -3.68073e-05 -3.50924e-05 -3.34782e-05 -3.25442e-05 -3.16102e-05 -3.06763e-05 -2.97423e-05 -2.88083e-05 -2.78744e-05 -2.69404e-05 -2.60064e-05 -2.50725e-05 -2.41385e-05 -2.32635e-05 -2.27232e-05 -2.21829e-05 -2.16426e-05 -2.11023e-05 -2.0562e-05 -2.00217e-05 -1.94814e-05 -1.89411e-05 -1.84007e-05 -1.78604e-05 -1.73647e-05 -1.70853e-05 -1.68059e-05 -1.65265e-05 -1.62471e-05 -1.59677e-05 -1.56883e-05 -1.54089e-05 -1.51295e-05 -1.48501e-05 -1.45707e-05 -1.42913e-05 -1.40119e-05 -1.37325e-05 -1.34531e-05 -1.31737e-05 -1.28943e-05 -1.26149e-05 -1.23355e-05 -1.20561e-05 -1.17767e-05 -1.14973e-05 -1.10954e-05 0.0152675 0.0228237 -0.00460678 -0.0341525 0.0232109 -0.0138039 -0.0416538 -0.0458764 -0.0201967 -0.00878316 -0.00379173 -0.00164621 -0.000785131 -0.00037575 -0.000352375 -0.0545586 -0.0746881 -0.0771865 -0.05386 -0.0022199 0.0136703 0.00633526 0.00138826 -0.00108934 0.0038886 0.0298077 0.0475776 0.0481003 0.0464167 0.047818 0.042789 0.035207 0.0264423 0.0193959 0.0151614 0.00624257 -0.00913057 -0.0310696 -0.0430238 0.016426 0.189762 0.49025 0.820116 1.13919 1.43549 1.70658 1.95183 2.17414 2.38506 2.5657 2.73958 2.97905 3.21403 3.43025 3.62645 3.8028 3.96002 4.09996 4.22443 4.33427 4.42886 4.51097 4.5817 4.64326 4.6957 4.74132 4.7797 4.81298 4.84102 4.86512 4.88523 4.90224 4.91649 4.92846 4.93868 4.94755 4.95483 4.96114 4.96682 4.97161 4.97502 4.9776 4.97944 4.98141 4.98319 4.98467 4.98585 4.9869 4.98796 4.98902 4.99008 4.99114 4.9922 4.99326 4.9938 4.99429 4.99479 4.99528 4.99578 4.99628 4.99677 4.99704 4.99718 4.99733 4.99747 4.99762 4.99777 4.99791 4.99806 4.9982 4.99835 4.9985 4.99864 4.99879 4.99893 4.99907 4.99916 4.99925 4.99934 4.99943 5.01473 4.92293 4.61974 4.0316 3.7835 3.74195 3.78344 3.87272 3.97386 4.07319 4.16686 4.25256 4.33126 4.40264 4.46697 4.49249 4.51807 4.55803 4.64055 4.78574 4.86074 4.88334 4.8999 4.91455 4.92814 4.93926 4.94761 4.95433 4.95907 4.9654 4.98317 5.0208 5.05134 4.85852 4.16041 3.00077 1.68376 0.672707 0.240838 0.0794725 -0.0106347 -0.00879443 0.107196 0.368163 0.701424 1.03581 1.3601 1.6678 1.95731 2.22701 2.47544 2.69099 2.92327 3.16648 3.3877 3.59067 3.77344 3.93584 4.08066 4.20863 4.32065 4.41791 4.50211 4.57423 4.63614 4.68888 4.73377 4.7721 4.80519 4.83338 4.85732 4.87815 4.89514 4.90927 4.92108 4.93122 4.94014 4.94845 4.95601 4.96251 4.96576 4.969 4.97225 4.9755 4.97874 4.98087 4.98265 4.98442 4.9862 4.98797 4.98924 4.9899 4.99055 4.9912 4.99186 4.99251 4.99316 4.99381 4.99447 4.99512 4.99577 4.99609 4.99634 4.99659 4.99683 4.99708 4.99732 4.99757 4.99782 4.99806 4.99831 4.99853 4.99863 4.99873 4.99883 4.99893 4.99903 4.99913 4.99923 4.99933 EOD @v[14].set(<<-'EOD') 1.86175 2.00147 1.85141 1.0654 0.275481 0.205547 0.0712627 0.0313387 0.0151431 0.00864531 0.00593861 0.00438111 0.0037479 0.00305857 0.00221221 0.0017081 -0.0896128 -0.109079 -0.121356 -0.0542001 0.175821 0.177442 0.0814591 0.0333042 0.0134909 0.00625777 0.00100092 -0.00552776 -0.00411139 -0.00150395 -0.000564784 3.48169e-05 -0.000287014 -0.000538515 -0.000456537 -0.000325677 -0.000275468 -0.000166452 -8.27481e-05 -8.28704e-05 -7.47644e-05 -4.60552e-05 -2.61481e-06 2.26359e-05 2.53852e-05 -1.39853e-06 -4.23456e-05 -4.0907e-05 -2.8501e-05 -1.5945e-05 -9.01122e-06 -2.07747e-06 1.49328e-06 4.38398e-06 6.84248e-06 4.76711e-06 2.69173e-06 6.16362e-07 -1.45901e-06 -3.53438e-06 -4.14256e-06 -3.76238e-06 -3.3822e-06 -3.00202e-06 -2.62184e-06 -2.24878e-06 -1.93456e-06 -1.62033e-06 -1.3061e-06 -9.91867e-07 -6.77638e-07 -3.63409e-07 -4.91792e-08 2.6505e-07 5.7928e-07 8.93509e-07 1.16076e-06 1.11055e-06 1.06034e-06 1.01014e-06 9.59927e-07 9.09719e-07 8.59511e-07 8.09302e-07 7.59094e-07 7.08886e-07 6.58678e-07 5.99251e-07 4.87523e-07 3.75795e-07 2.64068e-07 1.5234e-07 4.06119e-08 -7.1116e-08 -1.82844e-07 -2.94572e-07 -4.063e-07 -5.18027e-07 -6.08517e-07 -5.95879e-07 -5.83241e-07 -5.70604e-07 -5.57966e-07 -5.45328e-07 -5.3269e-07 -5.20053e-07 -5.07415e-07 -4.94777e-07 -4.8214e-07 -4.69502e-07 -4.56864e-07 -4.44226e-07 -4.31589e-07 -4.18951e-07 -4.06313e-07 -3.93676e-07 -3.81038e-07 -3.684e-07 -3.55762e-07 -3.43125e-07 1.06736e-05 0.0797407 0.0437947 -0.0645098 -0.0877312 0.0653203 -0.00621184 -0.0353188 -0.0491378 -0.0251957 -0.0110996 -0.00481123 -0.0020941 -0.000998038 -0.000478747 -0.000445332 -0.102046 -0.135753 -0.154351 -0.0827509 0.163348 0.174012 0.0794822 0.0310624 0.0112213 0.00249061 0.00130764 0.00181315 0.00163875 0.00101454 0.000497435 0.000195258 5.31901e-05 2.4607e-05 6.62736e-05 7.90718e-05 4.0372e-05 -0.000141184 -0.000280623 5.5608e-05 0.000799565 0.000920189 0.000931616 0.000494527 0.000162303 -8.24884e-05 -0.000183938 -0.000203899 -0.000144788 -9.87063e-05 -0.000227929 2.93932e-05 0.000208563 1.88958e-06 -7.6335e-05 -0.000172472 -0.000165656 -0.000145889 -0.000177311 -0.000191058 -0.000168287 -0.00015755 -0.00013142 -8.10488e-05 -6.36115e-05 -7.8699e-05 -8.11282e-05 -7.98625e-05 -5.98807e-05 -3.40879e-05 -1.95464e-05 -1.79247e-05 -4.45514e-05 -7.47995e-05 -8.7682e-05 -7.50806e-05 -3.25561e-05 -4.34114e-05 -7.69099e-05 -0.000141101 -0.00018743 -0.000148471 -5.06546e-05 0.000120195 0.000177635 0.000177052 0.000146344 9.75126e-05 8.31233e-05 6.8734e-05 5.43447e-05 3.99554e-05 2.55661e-05 1.11768e-05 -3.21253e-06 -3.88937e-06 -3.56628e-06 -3.24318e-06 -2.92008e-06 -2.59699e-06 -2.27389e-06 -1.9508e-06 -1.73227e-06 -1.56796e-06 -1.40365e-06 -1.23934e-06 -1.07503e-06 -9.10722e-07 -7.46412e-07 -5.82101e-07 -4.1779e-07 -2.5348e-07 -8.91694e-08 7.51412e-08 2.39452e-07 4.03762e-07 5.95733e-07 1.00771e-06 1.41969e-06 1.83167e-06 2.24365e-06 0.0828257 0.231038 0.465438 1.54516 2.8461 3.19221 3.40395 3.6382 3.80758 3.93848 4.04882 4.15428 4.247 4.32917 4.40235 4.36941 4.397 4.48862 4.64552 4.86595 5.03475 5.0348 5.02627 5.01967 5.01542 5.00925 4.98613 4.9519 4.91581 4.87357 4.82302 4.80403 4.82565 4.86102 4.89483 4.92253 4.94428 4.96257 4.97608 4.98373 4.98823 4.99182 4.99437 4.99635 4.99745 4.99802 4.99843 4.99873 4.99895 4.99912 4.99925 4.99931 4.99962 4.99973 4.99972 4.99971 4.9997 4.99969 4.9997 4.99971 4.99973 4.99974 4.99976 4.99978 4.9998 4.99982 4.99985 4.99987 4.99989 4.9999 4.99991 4.99991 4.99993 4.99994 4.99997 5.00001 5.00006 5.00008 5.00006 5.00002 5 4.99999 4.99998 4.99997 4.99995 4.99995 4.99995 4.99995 4.99995 4.99995 4.99995 4.99996 4.99997 4.99997 4.99998 4.99999 5 5 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 4.99999 4.99999 4.99999 EOD @v[15].set(<<-'EOD') 1.86175 2.00199 2.08919 1.84314 1.08254 0.214737 0.0377351 0.00952455 0.00232763 0.000563614 0.000263477 0.000148642 0.000285086 0.000242592 7.34699e-05 -1.53467e-05 -0.0161874 -0.0157876 -0.0141194 0.0132576 0.0903272 0.109938 0.0535295 0.0224216 0.00940945 0.00466825 -0.000649972 -0.00654752 -0.00333248 -0.00103671 -0.000508276 -5.8896e-05 -0.00043938 -0.000544704 -0.00044444 -0.000307093 -0.00024517 -0.000154538 -8.78602e-05 -7.10461e-05 -6.06485e-05 -3.91039e-05 -8.45988e-06 9.43442e-06 1.28351e-05 -2.16734e-06 -2.6142e-05 -2.54768e-05 -1.88997e-05 -1.17906e-05 -7.3808e-06 -2.97101e-06 1.19146e-07 2.94246e-06 5.38942e-06 3.88851e-06 2.38761e-06 8.86704e-07 -6.14201e-07 -2.11511e-06 -2.59565e-06 -2.38885e-06 -2.18205e-06 -1.97525e-06 -1.76845e-06 -1.56241e-06 -1.36258e-06 -1.16276e-06 -9.62939e-07 -7.63116e-07 -5.63293e-07 -3.6347e-07 -1.63647e-07 3.61756e-08 2.35999e-07 4.35822e-07 6.07653e-07 5.90323e-07 5.72994e-07 5.55665e-07 5.38336e-07 5.21007e-07 5.03678e-07 4.86349e-07 4.6902e-07 4.51691e-07 4.34361e-07 4.11899e-07 3.60315e-07 3.08731e-07 2.57146e-07 2.05562e-07 1.53977e-07 1.02393e-07 5.08082e-08 -7.76222e-10 -5.23607e-08 -1.03945e-07 -1.47815e-07 -1.54225e-07 -1.60635e-07 -1.67045e-07 -1.73455e-07 -1.79864e-07 -1.86274e-07 -1.92684e-07 -1.99094e-07 -2.05504e-07 -2.11914e-07 -2.18324e-07 -2.24734e-07 -2.31144e-07 -2.37554e-07 -2.43964e-07 -2.50373e-07 -2.56783e-07 -2.63193e-07 -2.69603e-07 -2.76013e-07 -2.82423e-07 2.92534e-06 0.0446777 0.024278 -0.0518987 -0.0636547 0.00983929 -0.000518204 -0.000265194 0.000154772 0.000299538 3.12715e-05 -3.18225e-05 -2.48268e-05 -1.16701e-05 -6.05117e-06 7.61116e-06 -0.0163668 -0.0158244 -0.0141177 0.0100085 0.0857144 0.107784 0.051862 0.0204448 0.00629858 0.000967736 0.00121674 0.00190276 0.00154009 0.000860922 0.000410386 0.000164585 3.99493e-05 1.93797e-05 5.67594e-05 0.000110126 2.49925e-05 -7.17815e-05 -0.000142299 -1.63109e-05 0.000439529 0.000562489 0.000594599 0.000326164 0.000126423 -4.26063e-05 -0.000122927 -0.000114152 -6.72706e-05 -6.41242e-05 -0.000135588 2.61507e-05 0.000134036 6.43734e-06 -4.6223e-05 -0.000112047 -0.000101388 -8.67847e-05 -0.000117664 -0.000133957 -0.000116558 -0.000100873 -7.65448e-05 -4.44964e-05 -3.6677e-05 -5.26632e-05 -5.45172e-05 -5.13545e-05 -3.73869e-05 -1.99732e-05 -1.0907e-05 -1.10081e-05 -3.02609e-05 -5.18517e-05 -6.13597e-05 -5.30706e-05 -2.39572e-05 -3.24146e-05 -5.70062e-05 -0.000103448 -0.000135376 -0.0001024 -2.39007e-05 0.000110929 0.000151226 0.000142044 0.000105922 5.62834e-05 4.78476e-05 3.94117e-05 3.09759e-05 2.25401e-05 1.41042e-05 5.66837e-06 -2.76747e-06 -3.08639e-06 -2.81341e-06 -2.54043e-06 -2.26745e-06 -1.99447e-06 -1.72149e-06 -1.44851e-06 -1.26226e-06 -1.12096e-06 -9.79661e-07 -8.38363e-07 -6.97065e-07 -5.55768e-07 -4.1447e-07 -2.73173e-07 -1.31875e-07 9.42259e-09 1.5072e-07 2.92018e-07 4.33315e-07 5.74613e-07 7.10363e-07 8.01984e-07 8.93604e-07 9.85225e-07 1.07685e-06 0.04474 0.0928765 0.141327 0.0176048 -0.071675 -0.0124613 0.989022 2.28104 3.40619 4.21417 4.67173 4.87438 4.96044 4.98996 4.99858 4.96672 4.89502 4.79391 4.76433 4.8387 4.98612 5.0161 5.01722 5.01437 5.01256 4.99827 4.95807 4.9209 4.88217 4.83006 4.78461 4.80759 4.85548 4.89604 4.9254 4.94617 4.96126 4.97374 4.98255 4.98792 4.99126 4.99361 4.99554 4.99699 4.99792 4.99846 4.99881 4.99905 4.99924 4.99938 4.99949 4.99955 4.9997 4.9998 4.99982 4.99982 4.99982 4.99982 4.99982 4.99983 4.99984 4.99985 4.99986 4.99987 4.99988 4.99989 4.9999 4.99992 4.99993 4.99994 4.99995 4.99995 4.99996 4.99996 4.99998 4.99999 5.00001 5.00002 5.00002 5.00001 5.00001 5 4.99999 4.99999 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 EOD @v[16].set(<<-'EOD') 1.86175 1.73073 1.50572 1.89001 3.39004 4.36034 4.79012 4.93798 4.98305 4.99539 4.9979 4.99904 4.99772 4.9983 4.99935 4.99975 4.98837 4.99456 4.99728 5.01838 5.04568 5.00759 4.98112 4.98479 4.99197 4.99641 4.99747 4.99775 5.00043 5.0007 5.00035 5.00023 4.99976 5.00002 5.00007 5.0002 4.99993 5.00003 5.00021 5.00006 4.99993 4.99992 5.00002 5.00013 5.00017 5.00009 4.99992 4.99991 4.99993 4.99996 4.99998 4.99999 5.00001 5.00003 5.00005 5.00004 5.00004 5.00003 5.00002 5.00001 5 4.99999 4.99999 4.99998 4.99998 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5.01498 4.99342 4.96899 5.00301 5.02627 4.9977 4.99548 4.99757 5.00277 5.00245 5.0014 5.00069 5.00032 5.00014 5.00009 4.9867 4.99262 4.99607 5.01805 5.04713 5.00927 4.98184 4.98483 4.9914 4.99616 4.99902 4.9999 4.99987 4.99979 4.99981 4.99989 4.99994 4.99998 5.0002 5.00001 5.00008 5.00008 5.0001 5.00021 5.00032 5.00025 5.00019 5.00006 5.00007 4.99994 4.99997 4.99999 5.00023 5.00008 4.99993 4.99998 4.99986 4.99982 5.00003 4.99985 4.99996 5.00014 5 4.99984 4.99979 4.99982 4.99993 5.00008 5.00011 5.00002 4.99996 4.9999 4.99994 5.00001 5.00007 5.00009 4.99995 4.99978 4.99971 4.99976 4.99997 4.99996 4.99989 4.99972 4.99955 4.99953 4.99959 4.99976 4.9999 5.00005 5.00023 5.00039 5.00034 5.00029 5.00024 5.00019 5.00014 5.00009 5.00004 5.00003 5.00002 5.00001 5 5 4.99999 4.99998 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5.00001 5.00002 5.00003 5.00004 5.01564 5.03395 5.04932 5.11868 3.92502 1.31888 0.163888 0.0946876 0.0789578 0.0565084 0.0260333 0.0156986 0.00907667 0.00613629 0.00468417 -0.00174008 -0.0021422 0.000586962 0.0124937 0.0147977 0.00838454 0.00039383 -0.000522021 -0.000426598 -0.000290214 -0.00173713 -0.00384132 -0.00382945 -0.00429219 -0.00580193 -0.00393246 0.0017543 0.00423045 0.00408931 0.0031976 0.00245457 0.00187293 0.00159068 0.00105697 0.000609902 0.000358825 0.000334125 0.000212708 0.000168116 8.97349e-05 5.21578e-05 3.84527e-05 2.93033e-05 2.10067e-05 1.59954e-05 1.13917e-05 5.49738e-06 2.77217e-05 6.51259e-06 -6.65468e-06 2.09837e-06 -6.617e-06 -4.80187e-06 1.55031e-06 4.26536e-06 7.69457e-07 -1.46213e-06 -7.25202e-07 3.26501e-06 6.55807e-06 7.524e-06 6.07209e-06 6.00701e-06 5.41166e-06 3.86573e-06 1.10651e-06 -2.74603e-06 -2.18566e-06 2.3658e-06 8.59956e-06 8.35046e-06 2.90621e-06 -8.75982e-07 -1.87189e-06 -2.1528e-06 -1.94875e-06 -1.74471e-06 -1.54067e-06 -1.33662e-06 -1.13258e-06 -8.40567e-07 -5.20743e-07 -2.00918e-07 1.18906e-07 4.38731e-07 6.11382e-07 6.01529e-07 5.91675e-07 5.81822e-07 5.71968e-07 5.62115e-07 5.52261e-07 5.42407e-07 5.32554e-07 5.227e-07 5.12847e-07 4.72812e-07 4.26137e-07 3.79462e-07 3.32786e-07 2.86111e-07 2.39436e-07 1.92761e-07 1.46086e-07 9.94107e-08 5.27356e-08 -2.77779e-10 -7.98079e-08 -1.59338e-07 -2.38868e-07 -3.18398e-07 -3.97928e-07 -4.77458e-07 -5.56988e-07 -6.36519e-07 EOD @v[17].set(<<-'EOD') 5 5.16963 4.84136 3.33754 0.316206 0.103113 0.0273341 0.0221102 0.0177008 0.0143758 0.0115203 0.00929231 0.00752716 0.00625439 0.00489872 0.00403656 -0.0657317 -0.0256467 0.165394 0.985963 3.05067 4.55799 4.89728 4.92464 4.8882 4.90592 4.97315 4.99241 4.99694 4.99845 4.99905 4.99939 4.99959 4.99971 4.9998 4.99986 4.9999 4.99993 4.99995 4.99996 4.99997 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 5 5.00001 5.00003 5.00005 5.00004 5.00002 5 4.99999 4.99999 4.99998 4.99998 4.99997 4.99997 4.99998 4.99998 4.99999 4.99999 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00025 5.1657 4.69981 2.43895 0.0229743 0.0351406 -0.0211974 -0.0312063 -0.0160331 -0.0021718 -0.000766597 -0.000251052 -5.49363e-05 -3.36364e-06 -2.01983e-06 -9.70575e-06 -0.0657007 -0.0205247 0.183332 1.07163 3.11839 4.46213 4.84163 4.95195 4.99159 5.02084 5.04029 5.04138 5.0271 5.00445 4.97957 4.95702 4.95231 4.97819 4.99191 4.9963 4.99822 4.99878 4.99903 4.99925 4.99942 4.9995 4.99954 4.99957 4.99961 4.99966 4.9997 4.99974 4.99977 4.99981 4.99983 4.99986 4.99988 4.9999 4.99991 4.99992 4.99994 4.99995 4.99995 4.99996 4.99997 4.99997 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 4.99999 4.99998 4.99997 4.99996 5.14239 4.76219 3.16574 0.299969 0.0631609 -0.00118611 -0.00026052 -5.96333e-05 -1.44904e-05 -4.3859e-06 -2.99454e-06 1.10547e-06 4.84662e-06 1.30971e-05 2.23082e-05 -0.0655844 -0.0204818 0.182507 1.05954 3.12277 4.46735 4.83915 4.94512 4.97679 4.98654 4.9966 5.00833 5.00776 5.00432 5.00199 5.00086 5.00033 5.00008 5 5.00001 5 5.00005 5.00002 4.99981 4.99991 4.99998 4.99979 4.99979 4.99984 4.9998 4.9998 5.00006 5.00002 5.00001 5 5 4.99992 4.99998 4.99999 5.00002 5.00014 4.99999 4.99987 4.99993 5.00003 5.00011 5.00005 4.99996 4.99987 4.99985 4.99994 5.00009 5.0001 5 4.99993 4.99997 5.00008 5.00015 5.00021 5.00021 5.00007 4.99978 4.99965 4.99973 4.9999 4.99992 4.99995 4.99997 4.99999 5.00001 5.00002 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 EOD @v[18].set(<<-'EOD') 5 5.0333 5.02472 4.92559 4.18383 3.93923 3.9961 4.14293 4.28591 4.41336 4.52157 4.61101 4.68472 4.7439 4.79294 4.83239 4.80697 4.78808 4.79322 4.8838 5.08529 5.21863 4.88852 3.90198 2.14586 0.383977 0.101103 0.0525711 0.0318287 0.020895 0.0146908 0.010831 0.00830272 0.00656377 0.00532066 0.00440078 0.00369956 0.00315713 0.00272614 0.00237965 0.00209659 0.00186339 0.00167014 0.0015081 0.00137172 0.00125607 0.00115393 0.00106076 0.000980166 0.000918015 0.000862837 0.00080766 0.000763488 0.000721541 0.000680825 0.000653026 0.000625226 0.000597426 0.000569627 0.000541827 0.000519087 0.000499756 0.000480424 0.000461093 0.000441761 0.000423291 0.000411941 0.00040059 0.00038924 0.000377889 0.000366539 0.000355188 0.000343838 0.000332487 0.000321137 0.000309786 0.000299055 0.000292509 0.000285963 0.000279417 0.000272871 0.000266325 0.000259779 0.000253233 0.000246686 0.00024014 0.000233594 0.000227387 0.0002231 0.000218813 0.000214526 0.00021024 0.000205953 0.000201666 0.000197379 0.000193092 0.000188805 0.000184519 0.000180526 0.000177963 0.0001754 0.000172837 0.000170274 0.000167711 0.000165148 0.000162585 0.000160022 0.000157459 0.000154895 0.000152332 0.000149769 0.000147206 0.000144643 0.00014208 0.000139517 0.000136954 0.000134391 0.000131828 0.000129265 0.000126702 0.000132838 0.0311184 0.163151 0.34986 0.604501 0.357125 0.136137 0.0711304 0.0346959 0.0212674 0.00872193 0.00252206 0.000455269 7.59332e-05 2.91532e-05 0.000320562 -0.0720911 -0.0840491 -0.0791345 -0.0404143 0.0182035 -0.0235871 -0.0426072 -0.0597501 0.00824773 0.481404 1.32496 2.11949 2.57317 2.58202 2.15054 1.33786 0.45702 0.153772 0.0913584 0.0604989 0.0421591 0.0271456 0.0170021 0.0115815 0.00907886 0.00742466 0.00626096 0.00531127 0.00450501 0.00381927 0.00323718 0.00274374 0.00232494 0.00196885 0.00166686 0.00141134 0.00119437 0.0010109 0.000855534 0.000723378 0.000611408 0.000516704 0.000436769 0.000369523 0.000313026 0.00026526 0.000223976 0.000188972 0.000159042 0.000134148 0.000112688 9.49738e-05 7.97877e-05 6.721e-05 5.65115e-05 4.77194e-05 4.03591e-05 3.42848e-05 2.92627e-05 2.50435e-05 2.1412e-05 1.84532e-05 1.58624e-05 1.34673e-05 1.14461e-05 1.00935e-05 9.12375e-06 8.50202e-06 7.81431e-06 7.20729e-06 6.73936e-06 6.3702e-06 5.90049e-06 5.43077e-06 4.96105e-06 4.49133e-06 4.02162e-06 3.5519e-06 3.08218e-06 2.79099e-06 2.51281e-06 2.23463e-06 1.95645e-06 1.67827e-06 1.40009e-06 1.12191e-06 1.01376e-06 9.9375e-07 9.73741e-07 9.53733e-07 9.33724e-07 9.13715e-07 8.93707e-07 8.73698e-07 8.5369e-07 8.33681e-07 8.13673e-07 7.93664e-07 7.73655e-07 7.53647e-07 7.21781e-07 5.956e-07 4.69419e-07 3.43239e-07 2.17058e-07 0.0284032 0.0374438 -0.0157543 -0.0680497 0.0504768 0.0100294 0.00222261 0.000528697 0.000132929 3.99489e-05 2.46066e-05 4.56327e-06 -6.54853e-06 1.33783e-05 -3.68221e-05 -0.0724498 -0.0843663 -0.0792935 -0.0406426 0.0200019 0.0426259 0.0220753 0.00668555 -0.000968483 0.024662 0.0383437 0.0911513 0.087848 0.0602076 0.0390559 0.0260573 0.0180444 0.012974 0.00985409 0.00788132 0.0064228 0.005545 0.00453571 0.00364245 0.00310278 0.00270523 0.00236439 0.0020945 0.00186808 0.00167493 0.00151731 0.00138594 0.00126945 0.00116695 0.0010762 0.000996366 0.000928387 0.000864414 0.000808258 0.000759574 0.000713865 0.000666712 0.000632716 0.000601262 0.000572163 0.000543986 0.000515253 0.0004897 0.000468112 0.000449313 0.000432981 0.000417911 0.000401307 0.000382712 0.000366678 0.000355736 0.000349171 0.000335727 0.000317091 0.000296086 0.000283543 0.000277366 0.000272233 0.000267001 0.000263147 0.000256699 0.000250251 0.000243803 0.000237355 0.000230907 0.000225424 0.000220247 0.000215069 0.000209892 0.000204714 0.000200213 0.000196548 0.000192884 0.00018922 0.000185556 0.000181892 0.000178228 0.000174564 0.0001709 0.000167236 0.000163572 0.000160824 0.000158279 0.000155733 0.000153187 0.000150641 0.000148095 0.000145549 0.000143003 0.000140457 0.000137911 0.000135457 0.000133386 0.000131315 0.000129245 0.000127174 0.000125103 0.000123032 0.000120961 0.000118891 EOD @v[19].set(<<-'EOD') 1.86175 1.99994 2.0833 2.01627 2.42503 3.25769 3.62134 3.88827 4.09688 4.26773 4.40529 4.51734 4.60827 4.68313 4.74346 4.79302 4.72815 4.68959 4.70421 4.81316 5.01375 5.14493 5.10305 5.0699 5.04484 5.03751 5.03348 5.02504 5.01799 5.01271 5.00895 5.00628 5.0044 5.00309 5.00216 5.00151 5.00105 5.00073 5.00051 5.00034 5.00023 5.00015 5.0001 5.00007 5.00003 4.99998 4.99993 4.99993 4.99995 4.99999 5.00001 5.00003 5.00002 5.00001 5 5 5 5 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5.00017 5.17398 4.94779 3.78508 1.52302 0.608808 0.244311 0.126053 0.0597175 0.038422 0.0158174 0.00481338 0.00107847 0.000301256 0.000114861 0.00059489 -0.118904 -0.147478 -0.158986 -0.080544 0.165361 0.171378 0.0776087 0.0435738 0.0428235 0.0423755 0.0347695 0.0225061 0.0155539 0.0121357 0.0107997 0.0103976 0.0124406 0.016814 0.0167556 0.0149852 0.01459 0.0141182 0.0131934 0.0120286 0.0108692 0.0097184 0.00855881 0.00744912 0.00643877 0.00554044 0.00475165 0.00406535 0.00347158 0.00295981 0.00251995 0.00214318 0.00182101 0.00154613 0.00131196 0.0011119 0.000941587 0.000796999 0.000674582 0.000571283 0.000484276 0.000410649 0.000347005 0.000292984 0.000246715 0.000208143 0.00017489 0.000147412 0.000123854 0.000104332 8.77229e-05 7.40686e-05 6.2637e-05 5.32e-05 4.53946e-05 3.88343e-05 3.31864e-05 2.85905e-05 2.45725e-05 2.08671e-05 1.77301e-05 1.55911e-05 1.40153e-05 1.29421e-05 1.18693e-05 1.09815e-05 1.03484e-05 9.87664e-06 9.14446e-06 8.41228e-06 7.68011e-06 6.94793e-06 6.21575e-06 5.48357e-06 4.7514e-06 4.38454e-06 4.04432e-06 3.7041e-06 3.36388e-06 3.02366e-06 2.68344e-06 2.34322e-06 2.15196e-06 2.03791e-06 1.92386e-06 1.80982e-06 1.69577e-06 1.58173e-06 1.46768e-06 1.35363e-06 1.23959e-06 1.12554e-06 1.0115e-06 8.9745e-07 7.83404e-07 6.69358e-07 4.76113e-07 -3.47071e-07 -1.17025e-06 -1.99344e-06 -2.81662e-06 0.0783754 0.0500262 -0.0659563 -0.120914 0.0815957 0.0154255 0.00347177 0.000840357 0.000214582 6.54655e-05 3.91709e-05 8.07396e-06 -4.44265e-07 1.74384e-05 -4.52725e-05 -0.119379 -0.147984 -0.159247 -0.0824604 0.169014 0.177628 0.0758742 0.010558 -0.0346506 -0.0710288 -0.0838952 -0.0599521 -0.034568 -0.0181615 -0.00968034 -0.00547115 -0.00333511 -0.00232468 -0.00181159 -0.00143841 -0.00116601 -0.000839755 -0.000569764 -0.000578683 -0.000490551 -0.000411712 -0.000437859 -0.000408185 -0.000356644 -0.000311332 -0.000269006 -0.000221396 -0.000210054 -0.0001923 -0.000175122 -0.000161039 -0.0001428 -0.000126123 -0.000127893 -8.14516e-05 -0.000120166 -0.000154909 -0.000112733 -8.40377e-05 -7.11342e-05 -8.09538e-05 -9.77789e-05 -9.82402e-05 -7.73531e-05 -5.28255e-05 -3.1096e-05 -1.87967e-05 -1.96552e-05 -4.16655e-05 -5.77185e-05 -5.24142e-05 -2.83153e-05 -1.90012e-05 -1.54415e-05 -2.52569e-05 -6.23747e-05 -0.000130543 -0.000149394 -0.000110886 -4.35517e-05 -4.17084e-05 -3.98651e-05 -3.80218e-05 -3.61785e-05 -3.43352e-05 -3.36249e-05 -3.32729e-05 -3.29208e-05 -3.25687e-05 -3.22166e-05 -3.17143e-05 -3.10258e-05 -3.03372e-05 -2.96486e-05 -2.89601e-05 -2.82715e-05 -2.75829e-05 -2.68944e-05 -2.62058e-05 -2.55173e-05 -2.48287e-05 -2.43043e-05 -2.38159e-05 -2.33276e-05 -2.28393e-05 -2.2351e-05 -2.18626e-05 -2.13743e-05 -2.0886e-05 -2.03977e-05 -1.99093e-05 -1.945e-05 -1.91122e-05 -1.87744e-05 -1.84366e-05 -1.80987e-05 -1.77609e-05 -1.74231e-05 -1.70853e-05 -1.67474e-05 EOD @v[20].set(<<-'EOD') 1.86175 1.99724 2.17266 2.48439 3.15933 3.85231 4.38091 4.69033 4.85034 4.92851 4.96453 4.98188 4.98736 4.991 4.99482 4.9973 4.96422 4.89989 4.83907 4.83151 4.90868 5.04854 5.06104 5.04571 5.03219 5.03025 5.02273 5.01707 5.0123 5.0087 5.00611 5.00429 5.00301 5.00211 5.00148 5.00103 5.00072 5.0005 5.00035 5.00024 5.00016 5.00011 5.00007 5.00005 5.00003 5.00001 4.99999 4.99998 4.99998 4.99998 4.99998 4.99998 4.99999 5 5 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 4.99981 5.10081 5.10903 4.98404 5.00999 5.14946 4.36501 2.23938 0.325144 0.00660272 -0.0102186 -0.0082401 -0.00556785 -0.00374178 -0.00264763 -0.00202823 -0.0182241 -0.0169551 -0.0150395 0.0103736 0.0877592 0.104382 0.0515938 0.0373818 0.0411547 0.0397009 0.0308946 0.0205793 0.0154037 0.0129191 0.0119327 0.011527 0.0124295 0.0161152 0.0161076 0.0145391 0.0144541 0.0139287 0.0129215 0.0117239 0.0105795 0.00942983 0.00827423 0.00718354 0.00619954 0.00532868 0.00456631 0.00390448 0.00333254 0.00284003 0.00241714 0.00205524 0.0017458 0.00148202 0.00125739 0.0010655 0.000902213 0.000763611 0.000646279 0.000547291 0.000463934 0.000393401 0.000332424 0.000280655 0.000236328 0.000199386 0.000167536 0.000141218 0.000118654 9.99559e-05 8.40479e-05 7.09694e-05 6.00188e-05 5.09786e-05 4.3502e-05 3.72191e-05 3.18114e-05 2.74071e-05 2.35539e-05 1.99967e-05 1.69871e-05 1.49449e-05 1.3451e-05 1.24492e-05 1.14256e-05 1.05669e-05 9.94487e-06 9.47514e-06 8.77318e-06 8.07123e-06 7.36927e-06 6.66731e-06 5.96536e-06 5.2634e-06 4.56144e-06 4.23044e-06 3.92649e-06 3.62254e-06 3.31858e-06 3.01463e-06 2.71068e-06 2.40673e-06 2.23063e-06 2.12082e-06 2.01102e-06 1.90121e-06 1.7914e-06 1.68159e-06 1.57178e-06 1.46197e-06 1.35216e-06 1.24235e-06 1.13255e-06 1.02274e-06 9.12929e-07 8.0312e-07 6.33171e-07 -1.51288e-08 -6.63428e-07 -1.31173e-06 -1.96003e-06 0.0437517 0.0265689 -0.0515377 -0.0658688 0.010727 -0.000511921 -8.36924e-05 2.13278e-05 1.45207e-05 4.54862e-06 -6.14726e-06 2.0062e-06 1.02709e-06 1.4152e-05 -3.08225e-05 -0.0166501 -0.0157139 -0.013957 0.0107537 0.0873717 0.111302 0.0454129 -0.00530142 -0.0468336 -0.0790063 -0.0826944 -0.0534753 -0.0288705 -0.0149009 -0.00801592 -0.0046342 -0.00291835 -0.00213019 -0.00170055 -0.001352 -0.00110593 -0.000742655 -0.000532042 -0.000544742 -0.000479206 -0.000407307 -0.000403575 -0.000366209 -0.000324161 -0.000286183 -0.000247579 -0.000214281 -0.000203435 -0.000186896 -0.000171033 -0.00015779 -0.000145259 -0.000128069 -0.000122647 -9.89398e-05 -0.000114926 -0.000132195 -0.000107872 -8.91015e-05 -7.87996e-05 -8.14061e-05 -8.9098e-05 -8.83368e-05 -7.6122e-05 -6.14668e-05 -4.75402e-05 -3.81855e-05 -3.69696e-05 -4.78656e-05 -5.61346e-05 -5.35007e-05 -4.1459e-05 -3.35411e-05 -2.52374e-05 -2.37479e-05 -4.6406e-05 -9.41884e-05 -0.000109222 -8.52676e-05 -4.25166e-05 -4.10125e-05 -3.95085e-05 -3.80045e-05 -3.65004e-05 -3.49964e-05 -3.41627e-05 -3.3541e-05 -3.29193e-05 -3.22976e-05 -3.16758e-05 -3.10334e-05 -3.03653e-05 -2.96971e-05 -2.9029e-05 -2.83609e-05 -2.76928e-05 -2.70246e-05 -2.63565e-05 -2.56884e-05 -2.50203e-05 -2.43521e-05 -2.38716e-05 -2.34324e-05 -2.29932e-05 -2.25539e-05 -2.21147e-05 -2.16755e-05 -2.12362e-05 -2.0797e-05 -2.03578e-05 -1.99186e-05 -1.95079e-05 -1.9217e-05 -1.8926e-05 -1.8635e-05 -1.8344e-05 -1.8053e-05 -1.7762e-05 -1.74711e-05 -1.71801e-05 EOD @v[21].set(<<-'EOD') 1.86175 1.73273 1.42016 1.02483 0.944013 0.274107 0.0823742 0.0379366 0.020816 0.0132952 0.00955525 0.00717008 0.00592286 0.00437379 0.00383557 0.00273694 -0.0037467 -0.0054191 -0.00131454 0.0112179 0.0133918 0.00519747 -0.00260113 -0.00252847 -0.00181292 0.000183398 -0.000667607 -0.000750747 -0.000594314 -0.000433904 -0.000308985 -0.000217858 -0.000152926 -0.000107454 -7.54076e-05 -5.2675e-05 -3.66299e-05 -2.54341e-05 -1.75095e-05 -1.18848e-05 -7.97289e-06 -5.30239e-06 -3.53615e-06 -2.38504e-06 -2.40158e-06 -3.84485e-06 -5.29435e-06 -2.57099e-06 1.95189e-06 3.55083e-06 2.06179e-06 5.72753e-07 3.30469e-07 3.40296e-07 3.60221e-07 4.86081e-07 6.1194e-07 7.37799e-07 8.63659e-07 9.89518e-07 9.21274e-07 7.22275e-07 5.23276e-07 3.24277e-07 1.25278e-07 -5.59467e-08 -9.03265e-08 -1.24706e-07 -1.59086e-07 -1.93466e-07 -2.27846e-07 -2.62226e-07 -2.96605e-07 -3.30985e-07 -3.65365e-07 -3.99745e-07 -4.24266e-07 -3.82163e-07 -3.40061e-07 -2.97959e-07 -2.55857e-07 -2.13755e-07 -1.71652e-07 -1.2955e-07 -8.7448e-08 -4.53457e-08 -3.24353e-09 3.76901e-08 7.19937e-08 1.06297e-07 1.40601e-07 1.74904e-07 2.09208e-07 2.43512e-07 2.77815e-07 3.12119e-07 3.46422e-07 3.80726e-07 4.04507e-07 3.77191e-07 3.49876e-07 3.22561e-07 2.95246e-07 2.67931e-07 2.40616e-07 2.13301e-07 1.85986e-07 1.58671e-07 1.31356e-07 1.04041e-07 7.67256e-08 4.94105e-08 2.20955e-08 -5.21962e-09 -3.25347e-08 -5.98498e-08 -8.71649e-08 -1.1448e-07 -1.41795e-07 -1.6911e-07 7.87893e-06 0.0114592 -0.0245712 -0.111637 0.0961324 1.61168 3.22343 4.20442 4.53535 4.83834 4.95464 4.98874 4.99746 4.99883 4.99948 4.99815 4.98431 4.99298 4.99718 5.01948 5.04749 5.008 4.98243 4.98985 4.99781 4.99887 4.99679 4.99616 4.99743 4.99859 4.99936 4.99972 5.00058 5.00123 5.0002 4.99945 4.99983 4.9998 4.99966 4.99958 4.99956 4.99956 4.99956 4.99958 4.99961 4.99965 4.99969 4.99973 4.99977 4.9998 4.99983 4.99985 4.99987 4.99989 4.99991 4.99992 4.99993 4.99994 4.99995 4.99996 4.99997 4.99997 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 4.99999 4.99998 4.99997 4.99996 5.01454 4.99566 4.96796 4.99819 5.03232 5.00034 4.99867 4.99937 4.99977 4.99992 4.99997 4.99999 5.00001 5.00021 4.99974 4.98462 4.99301 4.99723 5.01936 5.04807 5.00929 4.9789 4.97876 4.98244 4.9863 4.99575 5.0069 5.00863 5.00624 5.00357 5.0019 5.00098 5.00048 5.00025 5.00016 5.00011 5.00013 5.00009 4.99982 4.99994 5.00005 4.99994 4.99988 4.99989 4.99997 5.00003 5.00005 5.00002 5.00001 5.00001 5.00001 4.99993 4.99999 5 5.00021 4.99997 4.99981 5 5.00009 5.0001 5.00001 4.99991 4.9999 5 5.00011 5.00017 5.00018 5.00018 5.00014 5.00007 4.99999 4.9999 4.9999 5.00001 5.00016 5.00014 4.99999 4.99993 4.99999 5.00009 5.00007 5.00006 5.00004 5.00003 5.00001 5.00001 5 4.99999 4.99998 4.99997 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 EOD @v[22].set(<<-'EOD') 7.10441e-10 0.00107105 0.000637109 -0.00236346 -0.018079 -0.0120077 -0.00217059 0.00266679 0.00403383 0.00403836 0.00356705 0.00303303 0.00244716 0.00198586 0.0016855 0.00136497 -3.96022e-05 -0.000367409 -3.77079e-05 0.00194085 0.00506964 -0.0400214 -0.0402572 0.0524434 0.286234 0.803011 1.44795 2.02473 2.54768 3.02748 3.4415 3.78287 4.09667 4.35152 4.53987 4.67614 4.77407 4.84319 4.89227 4.92702 4.95119 4.96764 4.97846 4.98557 4.98982 4.99209 4.99371 4.99569 4.99727 4.99802 4.99834 4.99867 4.99892 4.99915 4.99936 4.99939 4.99943 4.99946 4.9995 4.99953 4.99957 4.9996 4.99963 4.99967 4.9997 4.99973 4.99974 4.99975 4.99976 4.99977 4.99978 4.9998 4.99981 4.99982 4.99983 4.99984 4.99985 4.99986 4.99986 4.99986 4.99987 4.99987 4.99988 4.99988 4.99989 4.99989 4.9999 4.9999 4.9999 4.9999 4.99991 4.99991 4.99991 4.99991 4.99992 4.99992 4.99992 4.99992 4.99993 4.99993 4.99993 4.99993 4.99993 4.99993 4.99993 4.99993 4.99994 4.99994 4.99994 4.99994 4.99994 4.99994 4.99994 4.99994 4.99995 4.99995 4.99995 4.99995 4.99995 4.99995 4.99995 5.00145 5.00659 5.01209 5.01931 5.00279 4.99273 4.99217 4.99295 4.99471 4.99594 4.99696 4.9978 4.99844 4.99891 4.99924 4.99635 4.99699 4.99813 5.00068 5.00307 5.0588 4.96365 4.54012 3.6307 2.35176 1.0322 0.354379 0.115986 0.0435668 0.0245112 0.020786 0.0164656 0.0118409 0.00849698 0.00597078 0.0040105 0.0026076 0.0016597 0.00118185 0.00121067 0.00153587 0.00174836 0.00136519 -0.000189116 -0.00315555 -0.00646603 -0.00898042 -0.010203 -0.0110896 -0.0123764 -0.00953841 -0.00225795 0.000818314 0.00152252 0.00150269 0.00119025 0.000767068 0.000308852 -3.79272e-05 -0.00019691 -0.000186642 -9.73653e-05 -8.49784e-06 2.04147e-05 -9.91086e-06 -1.55959e-05 -1.80499e-05 -1.77097e-05 -1.51548e-05 -1.1978e-05 -9.84916e-06 -1.29728e-05 -1.67235e-05 -1.74153e-05 -1.39958e-05 -5.92272e-06 -8.08216e-06 -1.53077e-05 -2.92531e-05 -3.91049e-05 -2.98935e-05 -7.32122e-06 3.18534e-05 4.39134e-05 4.18753e-05 3.22759e-05 1.86766e-05 1.58432e-05 1.30098e-05 1.01765e-05 7.34312e-06 4.50975e-06 1.67639e-06 -1.15697e-06 -1.23877e-06 -1.11991e-06 -1.00106e-06 -8.82208e-07 -7.63355e-07 -6.44502e-07 -5.2565e-07 -4.29318e-07 -3.44661e-07 -2.60004e-07 -1.75347e-07 -9.06904e-08 -6.03349e-09 7.86234e-08 1.6328e-07 2.47937e-07 3.32594e-07 4.17251e-07 5.01908e-07 5.86565e-07 6.71222e-07 7.36123e-07 6.43886e-07 5.5165e-07 4.59414e-07 3.67178e-07 0.000334759 -4.60833e-05 -0.00106139 -0.00166624 0.000859563 0.00102606 0.00410037 0.00419931 0.00518997 0.00459791 0.00503125 0.00523877 0.00452158 0.00339924 0.00233399 0.000876915 0.000546439 0.000444299 0.000983968 0.00119304 -0.0429422 -0.0403983 0.0534896 0.288013 0.807345 1.44247 2.03448 2.57021 3.05049 3.47332 3.8131 4.1009 4.34677 4.53512 4.67127 4.76531 4.82526 4.86593 4.89586 4.91904 4.93806 4.95348 4.96597 4.97629 4.9843 4.98983 4.99335 4.9957 4.99741 4.99864 4.99946 4.99994 5.00047 5.00073 5.00086 5.00092 5.00094 5.00091 5.00087 5.00081 5.00074 5.00067 5.00059 5.00052 5.00046 5.0004 5.00034 5.0003 5.00026 5.00022 5.00019 5.00016 5.00014 5.00012 5.0001 5.00009 5.00007 5.00006 5.00006 5.00005 5.00004 5.00004 5.00004 5.00003 5.00003 5.00003 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 EOD @v[23].set(<<-'EOD') 5 5.00284 5.01266 5.01895 4.98936 4.99575 4.99217 4.99545 4.99775 4.99894 4.99946 4.99968 4.99975 4.99977 4.99986 4.9999 4.99528 4.99808 5.00039 5.00392 5.00512 4.99985 4.99863 4.99942 4.99992 5.00017 4.99897 4.99803 4.99784 4.99739 4.99883 5.00365 5.00298 5.00133 5.00048 5.00019 5.00008 5.00005 5.00004 5.00003 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 4.99999 4.99997 4.99995 4.99996 4.99998 5 5.00001 5.00001 5.00002 5.00002 5.00003 5.00003 5.00002 5.00002 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5.00217 5.00108 4.99547 4.99658 5.00667 4.99641 4.99532 4.99938 5.00328 5.00222 5.00114 5.00052 5.00024 5.00011 5.00009 4.99285 4.99591 4.99897 5.00403 5.00786 5.00318 4.99942 4.9992 4.99949 5.001 5.00408 5.00319 5.00063 4.99995 5.00014 4.99982 4.99832 4.99838 4.99865 4.99912 4.99836 4.99735 4.99606 4.99814 5.00958 5.02973 5.05293 5.06103 4.99342 4.80726 4.50744 4.07509 3.41358 2.37924 1.03194 0.261552 0.142392 0.0904482 0.0555071 0.0322869 0.018289 0.0113802 0.00875182 0.00757055 0.00629906 0.00523 0.00403349 0.0031953 0.00280864 0.00286119 0.00250389 0.00202815 0.001723 0.00147312 0.0012411 0.00104401 0.000886204 0.000758277 0.000651915 0.00056348 0.000487966 0.000424048 0.000365613 0.000308178 0.000258725 0.000228061 0.000207976 0.000198491 0.00018518 0.000172716 0.000163197 0.000155007 0.000141734 0.000128461 0.000115188 0.000101915 8.86417e-05 7.53686e-05 6.20956e-05 5.69164e-05 5.23275e-05 4.77385e-05 4.31495e-05 3.85605e-05 3.39716e-05 2.93826e-05 2.69449e-05 2.56224e-05 2.42999e-05 2.29774e-05 2.16549e-05 2.03324e-05 1.90099e-05 1.76873e-05 1.63648e-05 1.50423e-05 1.37198e-05 1.23973e-05 1.10748e-05 9.75232e-06 8.48447e-06 7.65129e-06 6.81811e-06 5.98494e-06 5.15176e-06 0.00056893 -0.00787906 -0.0217381 -0.0370066 -0.00770505 0.00659312 0.00975477 0.00949456 0.00777552 0.00655645 0.00568776 0.00508782 0.00458121 0.00410187 0.00365665 0.0015121 0.00160863 0.00263181 0.00638941 0.00772607 0.00225583 0.0010843 0.000882939 0.000801563 0.00075632 0.000554992 0.000435131 0.0003474 0.000217667 0.000491602 0.0012267 0.00250446 0.000212058 -0.0174972 -0.0527527 -0.0479071 0.194908 1.45838 3.40677 4.49242 4.86894 4.97215 5.01218 5.04342 5.06228 5.03069 4.87169 4.57056 4.11523 3.38264 2.19691 0.715839 0.172818 0.102162 0.0627162 0.0363388 0.020289 0.0119414 0.00826608 0.0066417 0.00549092 0.00492505 0.00439443 0.0037156 0.00306471 0.00247451 0.00195965 0.0014822 0.0010815 0.000904464 0.0010514 0.00152308 0.00120752 0.000228447 -0.00102833 -0.00116644 -0.00042067 4.78758e-05 5.09599e-05 -4.45756e-05 -3.22966e-06 3.81163e-05 7.94622e-05 0.000120808 0.000162154 0.000161895 0.000148481 0.000135068 0.000121654 0.000108241 9.81453e-05 9.2164e-05 8.61827e-05 8.02014e-05 7.42201e-05 6.82388e-05 6.22576e-05 5.62763e-05 5.0295e-05 4.43137e-05 3.83324e-05 3.54323e-05 3.321e-05 3.09877e-05 2.87654e-05 2.65431e-05 2.43209e-05 2.20986e-05 1.98763e-05 1.7654e-05 1.54317e-05 1.34612e-05 1.25441e-05 1.1627e-05 1.07099e-05 9.79276e-06 8.87564e-06 7.95851e-06 7.04139e-06 6.12427e-06 EOD @v[24].set(<<-'EOD') 5 5.01099 5.00866 4.97845 4.92369 4.9273 4.97413 4.9929 4.99826 4.99958 4.99978 5.00005 4.99968 4.99959 5.00014 4.99979 4.99914 4.99982 5.00023 5.00295 5.00664 4.99854 4.99647 5.00438 5.01722 5.03681 5.04766 5.04799 5.04867 5.04873 5.04685 5.04413 5.0367 5.02505 5.01726 5.01183 5.00806 5.00549 5.00371 5.00246 5.00162 5.00105 5.00069 5.00045 5.00031 5.00024 5.00019 5.00012 5.00007 5.00004 5.00001 4.99998 4.99999 4.99999 5 5.00001 5.00001 5.00002 5.00002 5.00003 5.00003 5.00003 5.00002 5.00002 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5.00418 4.99953 4.99152 4.99807 5.00497 5.00112 5.00055 5.00038 5.00018 5.00006 5.00006 5.00007 5.00006 5.00004 5.00004 4.99853 4.99945 4.99998 5.00304 5.00935 5.00742 4.99181 4.97421 4.93603 4.8853 4.8927 4.93984 4.97458 4.99039 4.99614 4.99801 4.99851 4.99869 4.99924 5.00108 5.00181 5.00119 5.00059 5.00031 5.00022 5.00018 5.00011 5.00001 5.00006 4.99981 4.99977 4.99982 5.00012 4.99993 5.00008 5.00043 5.00048 5.00024 5.00008 4.99984 4.99993 5.00011 4.99996 4.9998 4.99977 4.9998 4.99993 5.00008 5.00011 5.00002 4.99995 4.99989 4.99993 5 5.00007 5.00009 4.99994 4.99977 4.9997 4.99975 4.99996 4.99996 4.99988 4.9997 4.99952 4.9995 4.99956 4.99973 4.99988 5.00005 5.00025 5.00042 5.00036 5.00031 5.00025 5.0002 5.00014 5.00009 5.00003 5.00002 5.00001 5.00001 5 4.99999 4.99998 4.99998 4.99997 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5.00284 5.00442 5.00381 4.98997 4.99092 5.00733 5.07791 4.98237 4.86434 4.76835 4.74067 4.79278 4.85094 4.90068 4.93603 4.95698 4.96984 4.97856 4.98869 4.99904 5.0005 4.99524 5.00181 5.01878 5.05177 5.07986 4.98917 4.56217 3.68 2.3539 1.18541 0.505772 0.221044 0.115287 0.0760938 0.0589194 0.0476784 0.0457213 0.0412911 0.033889 0.0259741 0.0191452 0.0139018 0.0100235 0.00711788 0.00497657 0.00349368 0.00250021 0.00176179 0.00121843 0.000838368 0.000582711 0.000423458 0.000294608 0.000201251 0.000133748 8.6227e-05 5.44252e-05 3.30514e-05 1.93926e-05 1.09814e-05 5.29857e-06 1.92247e-06 3.08708e-07 -3.74311e-07 -6.11121e-07 -7.27807e-07 -4.87604e-07 -4.80493e-07 -9.15925e-07 -2.03774e-06 -4.01128e-06 -2.46644e-06 2.10626e-06 8.22422e-06 1.04922e-05 9.83047e-06 7.27106e-06 3.29654e-06 -2.06736e-06 -2.18019e-06 -2.29303e-06 -2.40586e-06 -2.51869e-06 -2.63153e-06 -2.24615e-06 -1.70325e-06 -1.16036e-06 -6.17468e-07 -7.45754e-08 2.45198e-07 2.88285e-07 3.31373e-07 3.7446e-07 4.17548e-07 4.60635e-07 5.03723e-07 5.4681e-07 5.89898e-07 6.32985e-07 6.76073e-07 6.19054e-07 5.4001e-07 4.60967e-07 3.81923e-07 3.02879e-07 2.23836e-07 1.44792e-07 6.57488e-08 -1.32948e-08 -9.23383e-08 -1.6698e-07 -2.23206e-07 -2.79432e-07 -3.35658e-07 -3.91884e-07 -4.48109e-07 -5.04335e-07 -5.60561e-07 -6.16787e-07 EOD @v[25].set(<<-'EOD') 1.34824 1.35838 1.36465 1.34675 1.29167 1.23161 1.2201 1.2185 1.2181 1.21798 1.21793 1.21788 1.21785 1.21782 1.21779 1.21776 1.21655 1.21656 1.21669 1.21871 1.22421 1.22247 1.21858 1.2228 1.23803 1.27737 1.10647 0.395248 0.0600669 0.027687 0.0192374 0.015425 0.0130881 0.00977445 0.00696598 0.00491122 0.00341952 0.00237078 0.00162339 0.00109178 0.000726647 0.000478886 0.00031568 0.000207902 0.000143494 0.000109768 8.62987e-05 5.69775e-05 3.36547e-05 2.30356e-05 1.86108e-05 1.41861e-05 1.08293e-05 7.68835e-06 4.79593e-06 4.51019e-06 4.22444e-06 3.9387e-06 3.65295e-06 3.36721e-06 3.04559e-06 2.69981e-06 2.35403e-06 2.00825e-06 1.66247e-06 1.34508e-06 1.26225e-06 1.17941e-06 1.09657e-06 1.01373e-06 9.30893e-07 8.48054e-07 7.65216e-07 6.82378e-07 5.9954e-07 5.16702e-07 4.37489e-07 3.82774e-07 3.2806e-07 2.73346e-07 2.18632e-07 1.63917e-07 1.09203e-07 5.4489e-08 -2.2523e-10 -5.49395e-08 -1.09654e-07 -1.52862e-07 -1.3079e-07 -1.08718e-07 -8.6646e-08 -6.45739e-08 -4.25019e-08 -2.04298e-08 1.64229e-09 2.37144e-08 4.57864e-08 6.78585e-08 8.71693e-08 9.30725e-08 9.89758e-08 1.04879e-07 1.10782e-07 1.16685e-07 1.22589e-07 1.28492e-07 1.34395e-07 1.40298e-07 1.46201e-07 1.52105e-07 1.58008e-07 1.63911e-07 1.69814e-07 1.75718e-07 1.81621e-07 1.87524e-07 1.93427e-07 1.9933e-07 2.05234e-07 2.11137e-07 2.19788e-07 0.000393944 -0.000218983 -0.00105784 0.00172403 -0.00027134 -0.000204147 8.79968e-06 5.93762e-05 5.83554e-05 4.13815e-05 3.71369e-05 3.03372e-05 2.25336e-05 1.5986e-05 1.07284e-05 -7.5239e-05 5.60593e-05 6.97571e-05 0.000667617 0.000960856 0.00131749 -0.00759564 -0.0217897 -0.0450321 -0.076646 -0.128569 -0.186391 -0.202175 -0.206953 -0.2082 -0.208416 -0.208669 -0.208934 -0.209111 -0.209234 -0.209329 -0.209389 -0.209416 -0.2094 -0.209329 -0.20926 -0.209204 -0.209208 -0.209285 -0.209454 -0.209641 -0.20977 -0.209811 -0.209833 -0.209887 -0.209653 -0.209127 -0.208893 -0.208811 -0.208777 -0.208758 -0.208747 -0.20874 -0.208726 -0.208697 -0.208657 -0.208611 -0.208565 -0.208524 -0.208488 -0.208451 -0.208412 -0.208373 -0.208333 -0.208294 -0.208256 -0.208219 -0.208183 -0.208145 -0.208107 -0.208066 -0.208029 -0.207993 -0.207959 -0.207923 -0.207883 -0.207838 -0.207789 -0.207747 -0.20771 -0.207675 -0.207642 -0.207605 -0.207568 -0.207531 -0.207494 -0.207457 -0.20742 -0.207383 -0.207346 -0.207308 -0.207271 -0.207233 -0.207196 -0.207158 -0.207121 -0.207084 -0.207046 -0.207009 -0.206972 -0.206935 -0.206898 -0.206861 -0.206823 -0.206786 -0.206749 -0.206712 -0.206675 -0.206638 -0.2066 -0.206563 -0.206526 -0.206489 -0.206452 -0.206415 -0.203384 -0.20015 -0.196872 -0.205024 -0.210727 -0.206779 -0.0685263 0.586138 1.4665 2.22945 2.77554 3.076 3.24926 3.34515 3.40164 3.43006 3.43713 3.43075 3.42886 3.4384 3.46567 3.49025 3.51287 3.53821 3.57841 3.39846 2.80753 2.22947 1.7549 1.30429 0.707786 0.303206 0.131352 0.0671706 0.0429955 0.032461 0.0257161 0.0239521 0.0217397 0.0179705 0.0138745 0.0102813 0.00749643 0.0054328 0.00386817 0.0027004 0.00189442 0.00135552 0.000954715 0.000659981 0.000453435 0.000313993 0.000231347 0.000159665 0.000108122 7.10528e-05 4.50233e-05 2.77892e-05 1.62765e-05 8.9893e-06 4.5471e-06 1.54614e-06 -1.6542e-07 -8.68508e-07 -1.04369e-06 -9.63086e-07 -8.44294e-07 -6.57339e-07 -7.35885e-07 -9.80056e-07 -1.39772e-06 -2.10199e-06 -1.37474e-06 6.13269e-07 3.3028e-06 4.60941e-06 4.91053e-06 4.14186e-06 2.45258e-06 -8.7388e-09 -3.59647e-07 -7.10554e-07 -1.06146e-06 -1.41237e-06 -1.76328e-06 -1.63073e-06 -1.34534e-06 -1.05995e-06 -7.74561e-07 -4.8917e-07 -2.95733e-07 -2.16326e-07 -1.3692e-07 -5.75135e-08 2.18929e-08 1.01299e-07 1.80706e-07 2.60112e-07 3.39519e-07 4.18925e-07 4.98332e-07 4.83984e-07 4.4901e-07 4.14035e-07 3.79061e-07 3.44087e-07 3.09112e-07 2.74138e-07 2.39163e-07 2.04189e-07 1.69215e-07 1.26002e-07 4.83213e-08 -2.9359e-08 -1.07039e-07 -1.8472e-07 -2.624e-07 -3.4008e-07 -4.1776e-07 -4.95441e-07 EOD @v[26].set(<<-'EOD') 7.10441e-10 0.000309731 -0.000308186 -0.001694 -0.00360784 8.40909e-05 0.00203175 0.0012896 0.000596548 0.000277191 0.000161134 0.000120439 8.4915e-05 9.49929e-05 6.18812e-05 1.65433e-05 1.89682e-05 3.97578e-05 4.95446e-05 0.000225325 0.000214579 -0.00230134 -0.000451102 0.00997237 0.0341443 0.0449314 0.0424411 0.0341996 0.0315315 0.0308892 0.0291614 0.024365 0.0190282 0.0188976 0.017238 0.0138526 0.0105645 0.00778548 0.00561753 0.0039871 0.00279554 0.00194075 0.0013468 0.000934775 0.000664723 0.000498911 0.000377384 0.000254183 0.000163421 0.000120773 9.65058e-05 7.22384e-05 5.60316e-05 4.14549e-05 2.79516e-05 2.57096e-05 2.34677e-05 2.12257e-05 1.89837e-05 1.67417e-05 1.46737e-05 1.27228e-05 1.07719e-05 8.82099e-06 6.87009e-06 5.0896e-06 4.71705e-06 4.34451e-06 3.97196e-06 3.59941e-06 3.22686e-06 2.85431e-06 2.48176e-06 2.10921e-06 1.73666e-06 1.36411e-06 1.02855e-06 9.42931e-07 8.57316e-07 7.71701e-07 6.86086e-07 6.00471e-07 5.14856e-07 4.29241e-07 3.43626e-07 2.58011e-07 1.72396e-07 9.85409e-08 9.14091e-08 8.42773e-08 7.71456e-08 7.00138e-08 6.2882e-08 5.57503e-08 4.86185e-08 4.14867e-08 3.4355e-08 2.72232e-08 2.05821e-08 1.63235e-08 1.2065e-08 7.80643e-09 3.54786e-09 -7.10696e-10 -4.96926e-09 -9.22782e-09 -1.34864e-08 -1.77449e-08 -2.20035e-08 -2.62621e-08 -3.05206e-08 -3.47792e-08 -3.90378e-08 -4.32963e-08 -4.75549e-08 -5.18134e-08 -5.6072e-08 -6.03306e-08 -6.45891e-08 -6.88477e-08 -8.76373e-06 0.000131607 -0.00021685 -0.000433027 0.00047234 0.000211593 -0.000189601 3.2492e-05 0.000575955 7.72235e-05 -0.000285172 -0.000242061 -0.000135112 -3.50117e-05 -2.75868e-05 5.48974e-05 1.80604e-07 5.48911e-05 3.97478e-05 0.000192909 0.000297932 0.00402253 -0.0122366 -0.047853 -0.0963082 -0.108071 -0.0567275 -0.0239271 -0.0178628 -0.0233027 -0.031853 -0.0400843 -0.0482725 -0.0576154 -0.0627218 -0.0511236 -0.0279524 -0.0150986 -0.00931091 -0.00652876 -0.00479286 -0.00344346 -0.00249578 -0.0019532 -0.00157977 -0.00131848 -0.00111251 -0.000939229 -0.000797445 -0.000708384 -0.000630452 -0.000539722 -0.000508862 -0.000480596 -0.000439484 -0.000407217 -0.000363866 -0.000329506 -0.000318642 -0.000307362 -0.000286511 -0.000266253 -0.000242943 -0.000218107 -0.000204661 -0.00020241 -0.000194435 -0.000185062 -0.000173042 -0.000160549 -0.000151407 -0.000145626 -0.000145976 -0.000147342 -0.000145288 -0.000137979 -0.000124481 -0.000123218 -0.000127453 -0.000139006 -0.000145486 -0.000129764 -9.82749e-05 -4.72596e-05 -3.08671e-05 -3.28834e-05 -4.52254e-05 -6.25389e-05 -6.32516e-05 -6.39643e-05 -6.4677e-05 -6.53897e-05 -6.61023e-05 -6.6815e-05 -6.75277e-05 -6.61005e-05 -6.45173e-05 -6.29341e-05 -6.13509e-05 -5.97676e-05 -5.81844e-05 -5.66012e-05 -5.54231e-05 -5.4455e-05 -5.3487e-05 -5.25189e-05 -5.15508e-05 -5.05828e-05 -4.96147e-05 -4.86466e-05 -4.76785e-05 -4.67105e-05 -4.57424e-05 -4.47743e-05 -4.38063e-05 -4.28382e-05 -4.18821e-05 -4.10211e-05 -4.016e-05 -3.9299e-05 -3.8438e-05 4.29885e-05 5.14113e-05 -0.000127986 -0.000611463 -0.000149428 0.000882394 0.00297059 -0.00405825 -0.00591067 -0.00546997 -0.00158744 0.00190677 0.00298403 0.00268595 0.00196161 0.00130289 0.000783347 0.000520683 0.000565306 0.00053419 -0.00224696 -0.000920818 0.0132755 0.0322504 0.0442808 0.0638615 0.0701007 0.0539356 0.0247771 0.056244 0.294266 0.831368 1.45424 2.02898 2.54559 2.9937 3.35333 3.72609 4.06363 4.32789 4.52413 4.66504 4.7652 4.83637 4.88631 4.92109 4.94464 4.96046 4.97218 4.98079 4.98679 4.99076 4.99361 4.99555 4.99686 4.99783 4.99853 4.99902 4.99936 4.99959 4.99973 4.99983 4.9999 4.99993 4.99996 4.99998 5 5.00001 5 4.99999 4.99997 4.99994 4.99993 4.99994 4.99996 4.99999 5.00004 5.00006 5.00005 5.00003 5.00002 5.00001 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 EOD @v[27].set(<<-'EOD') 5 4.99984 4.99796 4.99478 4.9889 4.98738 4.98896 4.99087 4.99262 4.99419 4.99552 4.99659 4.99743 4.99807 4.99855 4.9989 4.99894 4.99908 4.99935 5.00001 5.0007 5.00132 5.00032 4.99976 5.00134 5.00339 5.00315 5.00157 5.00091 5.00058 5.00012 4.99944 4.99886 4.9994 4.99934 4.99899 4.99876 4.99868 4.99872 4.99883 4.99898 4.99914 4.9993 4.99944 4.99956 4.99967 4.99976 4.99982 4.99986 4.9999 4.99993 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5.00009 5.00028 5.00015 4.99983 5.00036 4.99996 4.99834 4.99783 5.00383 5.00734 5.00387 5.00058 4.99893 4.99836 4.99832 4.99854 4.99873 4.99905 4.99927 4.99952 4.99969 4.99834 4.99536 4.99163 4.99073 5.0053 5.03631 5.03103 4.9008 4.62503 4.21887 3.70902 3.09967 2.35791 1.41912 0.519675 0.210458 0.131362 0.0980819 0.0708209 0.0471701 0.0323272 0.0253535 0.0199144 0.0152615 0.0117228 0.00917696 0.00738117 0.00609292 0.00512664 0.00436184 0.0037961 0.00331639 0.00289006 0.0025477 0.00226529 0.00202925 0.00182793 0.00165474 0.00150531 0.00137529 0.00125983 0.00115603 0.00106455 0.000982977 0.000911255 0.000846819 0.000790092 0.000738698 0.000692816 0.00065107 0.000613595 0.000579642 0.000548935 0.00052106 0.000495598 0.000472174 0.000450849 0.000431118 0.000412667 0.000395868 0.000381319 0.000368487 0.000357327 0.000344212 0.000330334 0.00031622 0.000303298 0.000295809 0.00028832 0.000280831 0.000273342 0.000265853 0.000258364 0.000250875 0.000245118 0.000239488 0.000233857 0.000228227 0.000222596 0.000216966 0.000211336 0.000207047 0.000203455 0.000199863 0.00019627 0.000192678 0.000189085 0.000185493 0.0001819 0.000178308 0.000174716 0.000171123 0.000167531 0.000163938 0.000160346 0.000156835 0.000153973 0.00015111 0.000148248 0.000145385 0.000296579 -3.96718e-05 -0.000449085 0.000323433 0.000750086 0.000268264 0.000149028 -0.000100249 7.00956e-05 0.00012605 0.00022592 0.000193036 0.000120453 8.07865e-05 7.65771e-05 -3.27828e-05 0.000116759 0.000169498 0.000409804 0.000414965 0.00092323 -0.00590633 -0.0175477 -0.032433 -0.0559842 -0.0820373 0.0688484 0.626629 1.32929 2.01657 2.60925 3.12329 3.38952 3.14128 2.38463 1.23802 0.316019 0.107832 0.0694707 0.051837 0.035247 0.0209999 0.0116618 0.00967674 0.00789182 0.00574566 0.00386872 0.00258612 0.00167126 0.00104169 0.000641093 0.000401246 0.000277928 0.000171775 0.000102266 5.89376e-05 3.29258e-05 1.80463e-05 1.0057e-05 6.4571e-06 5.10093e-06 4.06791e-06 3.62716e-06 3.63321e-06 3.99625e-06 4.64368e-06 5.20886e-06 4.77728e-06 3.23919e-06 1.14113e-06 -1.29416e-06 -4.15607e-06 -1.88532e-06 5.24411e-06 1.38678e-05 1.28823e-05 3.6758e-06 -2.52285e-06 -3.97133e-06 -4.03071e-06 -3.37154e-06 -2.71238e-06 -2.05321e-06 -1.39404e-06 -7.34872e-07 -3.73325e-07 -1.05873e-07 1.61578e-07 4.2903e-07 6.96482e-07 8.18468e-07 7.60065e-07 7.01662e-07 6.43258e-07 5.84855e-07 5.26452e-07 4.68049e-07 4.09646e-07 3.51243e-07 2.9284e-07 2.34437e-07 1.71213e-07 1.06928e-07 4.2644e-08 -2.16403e-08 -8.59247e-08 -1.50209e-07 -2.14493e-07 -2.78778e-07 -3.43062e-07 -4.07346e-07 -4.55065e-07 -4.3348e-07 -4.11896e-07 -3.90311e-07 -3.68726e-07 -3.47141e-07 -3.25556e-07 -3.03971e-07 -2.82386e-07 EOD @v[28].set(<<-'EOD') 0.368163 0.361756 0.327463 0.269513 0.149476 0.0805716 0.0501146 0.03403 0.0230886 0.0160474 0.0116071 0.00870013 0.00679614 0.00542384 0.00432512 0.00340653 -0.00129719 -0.00399429 -0.00318719 0.00443085 0.0150156 0.0334147 0.0132288 -0.0189751 -0.0508377 -0.0252174 -0.0142489 -0.00675908 -0.0038653 -0.00243423 -0.00168891 -0.00120901 -0.000900426 -0.000685575 -0.000557595 -0.000457268 -0.000377427 -0.000315269 -0.000266613 -0.000228397 -0.000198283 -0.000174248 -0.000154886 -0.00013892 -0.000125864 -0.000115189 -0.000105841 -9.66611e-05 -8.84262e-05 -8.23872e-05 -7.74668e-05 -7.25463e-05 -6.79992e-05 -6.35276e-05 -5.92413e-05 -5.68994e-05 -5.45574e-05 -5.22154e-05 -4.98735e-05 -4.75315e-05 -4.54981e-05 -4.36726e-05 -4.18471e-05 -4.00216e-05 -3.81961e-05 -3.64559e-05 -3.54209e-05 -3.43858e-05 -3.33508e-05 -3.23157e-05 -3.12807e-05 -3.02456e-05 -2.92105e-05 -2.81755e-05 -2.71404e-05 -2.61054e-05 -2.51232e-05 -2.44984e-05 -2.38736e-05 -2.32487e-05 -2.26239e-05 -2.19991e-05 -2.13742e-05 -2.07494e-05 -2.01246e-05 -1.94998e-05 -1.88749e-05 -1.82865e-05 -1.79044e-05 -1.75224e-05 -1.71403e-05 -1.67582e-05 -1.63762e-05 -1.59941e-05 -1.56121e-05 -1.523e-05 -1.4848e-05 -1.44659e-05 -1.41138e-05 -1.39075e-05 -1.37011e-05 -1.34947e-05 -1.32883e-05 -1.30819e-05 -1.28755e-05 -1.26691e-05 -1.24627e-05 -1.22563e-05 -1.205e-05 -1.18436e-05 -1.16372e-05 -1.14308e-05 -1.12244e-05 -1.1018e-05 -1.08116e-05 -1.06052e-05 -1.03988e-05 -1.01924e-05 -9.98605e-06 -9.77966e-06 -2.85319e-05 0.00281092 0.00180106 -0.000981083 0.00551926 -0.00119763 -0.0295069 -0.0367677 0.064749 0.119022 0.0882007 0.0552062 0.03418 0.0223243 0.015545 0.011949 0.00757134 0.00667655 0.00583243 0.00644443 0.00650959 -0.0302575 -0.0437806 -0.0355466 0.0381776 0.282109 0.674178 1.07582 1.45189 1.789 2.08649 2.34663 2.57245 2.81211 3.04778 3.2523 3.45877 3.65593 3.83396 3.9923 4.13368 4.25864 4.36719 4.46064 4.54086 4.60962 4.66835 4.71838 4.76094 4.79716 4.82796 4.85413 4.87634 4.89518 4.91116 4.92476 4.93631 4.94608 4.95434 4.9613 4.96715 4.97211 4.97638 4.98001 4.98312 4.98571 4.98795 4.98979 4.99138 4.99269 4.99381 4.99474 4.99551 4.99615 4.99668 4.99713 4.99752 4.99783 4.99811 4.99836 4.99858 4.99873 4.99884 4.99892 4.999 4.99907 4.99912 4.99916 4.99921 4.99926 4.99932 4.99937 4.99942 4.99948 4.99953 4.99956 4.99958 4.99961 4.99963 4.99966 4.99968 4.99971 4.99972 4.99973 4.99974 4.99975 4.99976 4.99977 4.99978 4.99979 4.9998 4.9998 4.99981 4.99982 4.99983 4.99984 4.99985 4.99986 4.99986 4.99987 4.99987 5.00498 5.00354 4.99359 4.98981 5.00498 5.00099 5.00041 5.00022 5.00015 5.00012 5.0001 5.00008 5.00005 5.00003 5 4.99431 4.99459 4.99591 5.00087 5.01029 5.03935 4.92784 4.51643 3.78356 2.68745 1.43417 0.583128 0.205094 0.0777337 0.0391566 0.02723 0.023883 0.018808 0.010165 0.00254623 -0.00377463 -0.0038097 0.00144145 0.00267231 0.00193045 0.00144538 0.00121758 0.00112893 0.00109424 0.0010226 0.000948072 0.000882573 0.000826996 0.000776391 0.000729719 0.000686499 0.000647333 0.000610108 0.000575631 0.000545069 0.000515485 0.000488514 0.000465316 0.000443215 0.000422454 0.00040292 0.00038488 0.000368472 0.000353628 0.000339643 0.000326197 0.000313483 0.000302884 0.000294038 0.000284003 0.000270941 0.000254925 0.000246511 0.000244089 0.000245538 0.000242099 0.000235728 0.000227482 0.000218001 0.000207257 0.000202127 0.000196997 0.000191868 0.000186738 0.000181608 0.00017758 0.000173899 0.000170219 0.000166538 0.000162857 0.000159576 0.00015679 0.000154005 0.000151219 0.000148433 0.000145647 0.000142861 0.000140076 0.00013729 0.000134504 0.000131718 0.000129603 0.000127635 0.000125668 0.0001237 0.000121732 0.000119765 0.000117797 0.000115829 0.000113862 0.000111894 0.000109993 0.000108372 0.000106751 0.00010513 0.000103509 0.000101887 0.000100266 9.86449e-05 9.70237e-05 EOD @v[29].set(<<-'EOD') 5 4.99899 4.99654 4.99327 4.9863 4.98954 4.99212 4.99378 4.9951 4.99624 4.99715 4.99786 4.99839 4.99879 4.99909 4.99931 4.99922 4.99933 4.99971 5.00064 5.00084 5.00123 4.99865 4.99853 4.99983 5.00457 5.00242 5.00105 5.00062 5.00042 4.99971 4.9994 4.9992 4.9996 4.99955 4.99932 4.99918 4.99915 4.99919 4.99927 4.99937 4.99948 4.99957 4.99966 4.99974 4.9998 4.99985 4.99989 4.99992 4.99993 4.99994 4.99994 4.99996 4.99998 5 5 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 4.9997 4.99998 4.99954 4.99963 5.00059 4.99945 4.99732 4.99957 5.00919 5.00558 5.00033 4.99851 4.9983 4.99854 4.99871 4.99928 4.99914 4.99939 4.99952 4.9998 4.99976 4.99744 4.99598 4.99478 4.99806 5.01911 5.04602 5.05469 5.01317 4.89484 4.69655 4.42036 4.06069 3.60793 3.12531 2.72975 2.45187 2.25081 2.09841 1.98509 1.90211 1.84084 1.79411 1.7574 1.72763 1.70283 1.68188 1.66389 1.64823 1.63438 1.62201 1.61088 1.60081 1.59163 1.58323 1.57549 1.56835 1.56173 1.55558 1.54985 1.54451 1.53951 1.53479 1.53035 1.52615 1.5222 1.51845 1.5149 1.51153 1.50834 1.50529 1.5024 1.49964 1.497 1.49449 1.49208 1.48977 1.48755 1.48542 1.48336 1.48138 1.47948 1.47765 1.4759 1.47419 1.47255 1.47096 1.46949 1.46823 1.46696 1.4657 1.46444 1.46317 1.46191 1.46065 1.45956 1.4585 1.45743 1.45636 1.45529 1.45422 1.45315 1.45226 1.45145 1.45064 1.44983 1.44902 1.44821 1.4474 1.44659 1.44579 1.44498 1.44417 1.44336 1.44255 1.44174 1.44094 1.44019 1.43944 1.43868 1.43793 1.43765 1.43679 1.43515 1.43405 1.43478 1.43387 1.43345 1.43184 1.43086 1.43021 1.43003 1.42988 1.42944 1.42883 1.42818 1.42702 1.42642 1.42595 1.42586 1.42616 1.42783 1.41733 1.38106 1.30738 1.3877 2.09819 3.05285 3.58059 3.77601 3.87609 4.02557 4.24887 4.4608 4.60411 4.72109 4.8255 4.90465 4.97379 5.01253 5.01532 5.01239 5.0092 5.00665 5.00474 5.00333 5.00232 5.00163 5.00117 5.00082 5.00057 5.00039 5.00027 5.00019 5.00013 5.00009 5.00006 5.00004 5.00003 5.00002 5.00001 5.00001 5 5 5 4.99998 4.99995 4.99992 4.99996 5.00005 5.00012 5.00008 4.99996 4.9999 4.99985 4.99986 4.99997 5.00021 5.0003 5.00024 5.00009 5.00007 5.00005 5.00003 5.00001 4.99998 4.99998 4.99998 4.99999 4.99999 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 EOD @v[30].set(<<-'EOD') 7.10441e-10 5.70385e-05 0.000226143 0.000131916 -0.000887764 -8.01837e-05 -3.49653e-05 9.40039e-05 0.000118663 0.000108025 8.6059e-05 6.33268e-05 4.99295e-05 3.16843e-05 3.60692e-05 2.07572e-05 -8.6375e-05 3.44583e-05 8.07397e-05 0.000196296 0.000115615 -7.12768e-05 -0.000129812 -4.18679e-05 7.94364e-05 0.000182034 -5.41226e-05 -0.000451819 -0.000713937 -0.00129863 -0.00262186 -0.00213417 -0.00133767 0.000775698 0.000969902 0.000549281 0.000280946 0.000140321 8.6919e-05 7.22446e-05 6.5631e-05 6.45263e-05 6.63087e-05 7.17391e-05 7.59042e-05 7.59172e-05 7.03353e-05 6.33558e-05 5.31136e-05 4.64278e-05 4.40594e-05 4.16909e-05 4.05674e-05 3.96957e-05 3.87875e-05 3.74977e-05 3.62079e-05 3.49181e-05 3.36283e-05 3.23385e-05 3.12427e-05 3.02775e-05 2.93124e-05 2.83472e-05 2.7382e-05 2.64613e-05 2.59077e-05 2.5354e-05 2.48004e-05 2.42468e-05 2.36931e-05 2.31395e-05 2.25859e-05 2.20322e-05 2.14786e-05 2.0925e-05 2.03916e-05 1.9995e-05 1.95984e-05 1.92019e-05 1.88053e-05 1.84087e-05 1.80122e-05 1.76156e-05 1.7219e-05 1.68225e-05 1.64259e-05 1.6051e-05 1.57991e-05 1.55471e-05 1.52952e-05 1.50433e-05 1.47913e-05 1.45394e-05 1.42875e-05 1.40356e-05 1.37836e-05 1.35317e-05 1.32978e-05 1.31513e-05 1.30048e-05 1.28583e-05 1.27118e-05 1.25653e-05 1.24188e-05 1.22724e-05 1.21259e-05 1.19794e-05 1.18329e-05 1.16864e-05 1.15399e-05 1.13934e-05 1.12469e-05 1.11005e-05 1.0954e-05 1.08075e-05 1.0661e-05 1.05145e-05 1.0368e-05 1.02215e-05 1.76447e-05 7.21516e-05 -3.59786e-05 -0.000159618 0.000156236 0.000135106 -0.000336402 -0.000302283 0.000699323 0.000473866 -0.000156146 -0.000225625 -0.000123592 -3.78116e-05 8.47472e-06 2.43387e-06 -7.44762e-05 7.80111e-05 9.43608e-05 0.000170159 8.83919e-05 -0.00018802 -0.000373512 -0.000390597 0.000156875 0.0032343 0.00776304 -0.000566905 -0.00760695 -0.0159226 -0.0245989 -0.0331402 -0.0100902 0.067837 0.266702 0.910818 1.82282 2.69714 3.43247 3.98325 4.32893 4.51529 4.67087 4.79288 4.87574 4.92797 4.95902 4.97655 4.98622 4.99195 4.99526 4.99735 4.9991 4.99974 4.99982 4.99974 4.99961 4.9995 4.99943 4.9994 4.9994 4.99942 4.99944 4.99948 4.99952 4.99956 4.99961 4.99965 4.9997 4.99974 4.99977 4.99981 4.99983 4.99986 4.99988 4.9999 4.99991 4.99992 4.99993 4.99994 4.99995 4.99995 4.99996 4.99997 4.99997 4.99998 4.99998 4.99999 4.99999 4.99999 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5.00019 4.99888 4.99663 4.99457 4.99902 5.00229 5.00323 5.00302 5.0023 5.0015 5.00085 5.00041 5.00013 4.99993 4.99979 4.99948 4.99954 4.99983 5.00055 5.00109 5.00009 4.9987 4.998 4.99755 4.99676 4.99618 5.01091 5.05272 5.04156 4.80112 4.27692 3.42343 2.23953 0.967179 0.429813 0.540757 1.32991 2.32147 3.14903 3.78143 4.22325 4.47978 4.59448 4.69875 4.79798 4.87419 4.92339 4.95249 4.97174 4.98408 4.99124 4.99478 4.99729 4.99868 4.9992 4.99941 4.99947 4.99946 4.99943 4.9994 4.99939 4.9994 4.99942 4.99946 4.99951 4.99956 4.99961 4.99967 4.99973 4.99977 4.9998 4.99981 4.99983 4.99984 4.99987 4.99992 5.00001 5.00005 5.00001 4.99994 4.99995 4.99995 4.99996 4.99996 4.99996 4.99997 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 EOD @v[31].set(<<-'EOD') 1.8179e-09 -5.28841e-06 -1.44913e-05 -3.62932e-05 -9.75719e-05 0.000141781 3.73396e-05 -1.65603e-05 -1.5271e-05 -6.73884e-06 4.40157e-06 -4.85345e-06 -1.02964e-05 2.03126e-05 -1.89457e-05 -8.75564e-06 7.67422e-06 4.71103e-06 1.29798e-05 6.13469e-06 -1.14363e-05 -0.0394563 -0.0477298 -0.0622012 -0.0519225 0.262499 0.943611 1.67052 2.31017 2.84028 3.28467 3.61582 3.85887 4.13011 4.36511 4.54063 4.67013 4.76408 4.83263 4.8825 4.91837 4.94373 4.96117 4.97318 4.98093 4.98562 4.98906 4.99267 4.99539 4.99666 4.99731 4.99797 4.99844 4.99887 4.99927 4.99933 4.99938 4.99944 4.99949 4.99955 4.9996 4.99965 4.9997 4.99975 4.9998 4.99985 4.99986 4.99987 4.99989 4.9999 4.99991 4.99992 4.99993 4.99995 4.99996 4.99997 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5.00001 5.00001 5.00001 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99997 5.00002 5.00004 5.0001 5.0001 4.99987 5.00009 5.00021 5.00002 5.00004 4.99988 5.00013 4.99993 5.00026 4.99973 5 5.00006 5.00009 5.00004 5.00004 5.04854 4.82711 4.04208 2.64155 0.838902 0.19014 0.0982549 0.0723197 0.0576863 0.0427644 0.0301979 0.020146 0.0135728 0.00980358 0.00774482 0.00586604 0.0036687 0.00211511 0.00121906 0.000647581 0.000828436 0.00190938 0.00224254 0.00199956 0.00165488 0.00135612 0.00113715 0.000984181 0.000877175 0.000789973 0.000741139 0.000689338 0.000625676 0.000586082 0.000550152 0.000529573 0.000505606 0.000482117 0.000460574 0.000441649 0.000424674 0.000408398 0.000391914 0.000376272 0.000361487 0.000348181 0.000336045 0.000324466 0.000313545 0.000303046 0.000293056 0.00028356 0.000274586 0.000266155 0.000258279 0.000250938 0.000243789 0.000236912 0.000230244 0.000224186 0.000219291 0.000215346 0.000212468 0.000207291 0.000200862 0.00019368 0.000186767 0.000183515 0.000180263 0.00017701 0.000173758 0.000170506 0.000167253 0.000164001 0.000161164 0.000158357 0.00015555 0.000152743 0.000149936 0.000147129 0.000144322 0.000142066 0.000140096 0.000138127 0.000136157 0.000134187 0.000132218 0.000130248 0.000128278 0.000126308 0.000124339 0.000122369 0.000120399 0.000118429 0.00011646 0.000114527 0.000112892 0.000111258 0.000109623 0.000107988 0.000103598 6.86052e-05 3.337e-05 7.00783e-05 0.000218764 0.000221318 0.000118593 -0.000113962 5.78552e-05 9.42068e-05 0.000237037 0.000171302 0.0001033 6.16066e-05 5.52908e-05 6.30233e-05 7.01897e-05 8.48573e-05 0.000106859 8.37213e-05 -0.0391541 -0.047722 -0.0618454 -0.0169804 0.345725 1.03426 1.74825 2.37152 2.88737 3.32173 3.66761 3.9707 4.17762 3.98832 3.30483 2.09737 0.710892 0.148159 0.0707463 0.0555808 0.045618 0.0319116 0.0199589 0.0133357 0.00898528 0.00586075 0.00375478 0.00245443 0.00156038 0.000962344 0.000590953 0.000375107 0.000250243 0.00015882 0.000100203 6.18122e-05 3.7372e-05 2.23009e-05 1.32569e-05 8.29437e-06 5.72457e-06 3.96832e-06 2.98935e-06 2.59699e-06 2.75024e-06 3.38689e-06 4.0453e-06 3.50095e-06 1.64988e-06 -3.84371e-07 -2.03828e-06 -3.46401e-06 -1.24301e-06 4.63458e-06 1.14104e-05 1.02619e-05 2.15487e-06 -2.98487e-06 -3.67221e-06 -2.94279e-06 -2.58649e-06 -2.23019e-06 -1.87389e-06 -1.5176e-06 -1.1613e-06 -7.92127e-07 -4.18889e-07 -4.56502e-08 3.27588e-07 7.00827e-07 8.79539e-07 8.17025e-07 7.5451e-07 6.91996e-07 6.29481e-07 5.66966e-07 5.04452e-07 4.41937e-07 3.79422e-07 3.16908e-07 2.54393e-07 1.90078e-07 1.25366e-07 6.0654e-08 -4.05776e-09 -6.87696e-08 -1.33481e-07 -1.98193e-07 -2.62905e-07 -3.27617e-07 -3.92329e-07 -4.40392e-07 -4.18802e-07 -3.97213e-07 -3.75624e-07 -3.54035e-07 -3.32446e-07 -3.10856e-07 -2.89267e-07 -2.67678e-07 EOD @v[32].set(<<-'EOD') 1.10294 1.10297 1.10291 1.10277 1.10259 1.10294 1.10313 1.10306 1.10299 1.10296 1.10295 1.10295 1.10294 1.10294 1.10294 1.10294 1.10294 1.10294 1.10294 1.10296 1.10296 1.00547 0.998599 1.5201 2.49297 3.31258 3.73162 3.84757 3.92505 4.02965 4.16599 4.30294 4.41541 4.52886 4.64414 4.73865 4.81065 4.86391 4.90315 4.93188 4.95258 4.96726 4.97738 4.98436 4.98888 4.99162 4.99363 4.99573 4.99731 4.99804 4.99843 4.99881 4.99909 4.99934 4.99957 4.9996 4.99964 4.99967 4.9997 4.99973 4.99977 4.9998 4.99983 4.99986 4.99988 4.99991 4.99992 4.99992 4.99993 4.99994 4.99994 4.99995 4.99996 4.99996 4.99997 4.99997 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5.00028 4.99988 4.99968 5.00019 4.99987 5.00021 4.99973 4.99977 4.99996 4.99997 5.0002 4.99957 5.00026 4.99947 5.00074 5.00003 4.99987 4.99979 5.00008 4.99997 5.08794 5.05993 4.76875 3.99197 3.10174 2.5197 2.21771 2.04 1.92235 1.83874 1.77592 1.72665 1.686 1.65276 1.6286 1.61299 1.60039 1.58934 1.57954 1.57083 1.56306 1.55604 1.54963 1.54375 1.53832 1.53331 1.52865 1.52432 1.52026 1.51645 1.51287 1.50949 1.50629 1.50327 1.50039 1.49766 1.49505 1.49257 1.49019 1.48792 1.48574 1.48365 1.48164 1.47971 1.47784 1.47604 1.47431 1.47264 1.47102 1.46945 1.46794 1.46647 1.46505 1.46367 1.46233 1.46103 1.45976 1.45853 1.45733 1.45616 1.45502 1.45392 1.45284 1.45179 1.45076 1.44975 1.4488 1.44795 1.44711 1.44626 1.44541 1.44457 1.44372 1.44287 1.44212 1.44138 1.44063 1.43989 1.43914 1.4384 1.43766 1.43701 1.43641 1.43581 1.43522 1.43462 1.43402 1.43342 1.43282 1.43223 1.43163 1.43103 1.43043 1.42984 1.42924 1.42865 1.42808 1.42752 1.42695 1.42639 1.42584 1.42529 1.42472 1.42412 1.42365 1.42326 1.42304 1.42162 1.42082 1.42032 1.42029 1.42026 1.41995 1.41947 1.41894 1.41841 1.4179 1.41742 1.41699 1.41656 1.32097 1.30963 1.78765 2.64656 3.35764 3.747 3.86589 3.94217 4.04185 4.18453 4.3561 4.53439 4.68621 4.74905 4.77848 4.84629 4.91261 4.97541 5.01284 5.01548 5.01248 5.00924 5.00666 5.00475 5.00334 5.00234 5.00164 5.00118 5.00083 5.00058 5.0004 5.00028 5.00019 5.00013 5.00009 5.00007 5.00004 5.00003 5.00002 5.00001 5.00001 5.00001 5 5 4.99999 4.99995 4.99992 4.99996 5.00006 5.00012 5.00009 4.99997 4.9999 4.99985 4.99986 4.99997 5.00021 5.00031 5.00024 5.0001 5.00007 5.00005 5.00003 5.00001 4.99998 4.99998 4.99999 4.99999 4.99999 5 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 EOD @v[33].set(<<-'EOD') 5 5.00012 5.00023 5.0003 4.99972 4.99988 4.99984 4.99991 4.99996 4.99999 5.00008 5.00009 4.99986 5.00003 5.00007 4.99995 4.9999 4.99997 5.00013 5.00014 5.00013 4.99701 4.99763 4.99742 4.99998 5.02836 5.07262 4.96856 4.57267 3.85637 2.79544 1.45942 0.408016 0.084885 0.0271375 0.0119294 0.00707546 0.0051087 0.00373035 0.00264737 0.00186477 0.00130379 0.000915857 0.000653121 0.000483893 0.000380852 0.000302362 0.000219498 0.000154435 0.000121928 0.000104026 8.61242e-05 7.48526e-05 6.49216e-05 5.56238e-05 5.29689e-05 5.03139e-05 4.7659e-05 4.5004e-05 4.23491e-05 4.00356e-05 3.79522e-05 3.58687e-05 3.37852e-05 3.17018e-05 2.97592e-05 2.89804e-05 2.82016e-05 2.74228e-05 2.66441e-05 2.58653e-05 2.50865e-05 2.43077e-05 2.35289e-05 2.27501e-05 2.19714e-05 2.12346e-05 2.07821e-05 2.03295e-05 1.98769e-05 1.94244e-05 1.89718e-05 1.85192e-05 1.80667e-05 1.76141e-05 1.71615e-05 1.6709e-05 1.62828e-05 1.60061e-05 1.57294e-05 1.54527e-05 1.5176e-05 1.48993e-05 1.46226e-05 1.43459e-05 1.40692e-05 1.37925e-05 1.35158e-05 1.3262e-05 1.31191e-05 1.29761e-05 1.28332e-05 1.26903e-05 1.25474e-05 1.24045e-05 1.22615e-05 1.21186e-05 1.19757e-05 1.18328e-05 1.16898e-05 1.15469e-05 1.1404e-05 1.12611e-05 1.11182e-05 1.09752e-05 1.08323e-05 1.06894e-05 1.05465e-05 1.04036e-05 1.02606e-05 1.00185e-05 3.8343e-05 -3.06781e-05 -0.000111758 0.000111673 0.000130815 -0.000210491 -0.000231304 0.000310226 0.000265303 3.0878e-05 -4.48405e-05 -1.2852e-05 -7.84469e-06 3.29986e-05 -1.23286e-05 -6.07871e-05 5.35082e-05 7.69194e-05 0.000126221 6.57178e-05 0.00223349 -0.0148854 -0.0476636 -0.0491447 0.220125 1.11174 2.03988 2.90209 3.61069 4.13554 4.50679 4.71501 4.83916 4.91027 4.95284 4.98086 4.99151 4.98651 4.97113 4.95075 4.93102 4.93683 4.95457 4.97071 4.98212 4.98948 4.99386 4.99636 4.99785 4.9987 4.99927 4.99989 5.00014 5.00007 4.99988 4.99982 4.99976 4.99973 4.99972 4.99972 4.99973 4.99974 4.99975 4.99977 4.99979 4.99981 4.99984 4.99986 4.99988 4.99989 4.99991 4.99992 4.99993 4.99994 4.99995 4.99996 4.99996 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5.00001 5.00001 5.00001 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5.00012 4.99946 4.99839 4.99733 4.99948 5.00114 5.00158 5.00147 5.00113 5.00073 5.00043 5.0002 5.00006 4.99995 4.99986 4.99973 4.99976 4.9999 5.00029 5.00055 4.99704 4.99734 4.9972 5.00278 5.03354 5.07184 4.94057 4.51936 3.75638 2.60982 1.23803 0.315016 0.0796102 0.0252894 0.0165723 0.0827785 0.491298 1.40686 2.33436 3.1251 3.7691 4.22201 4.49976 4.68115 4.80513 4.88509 4.93208 4.95861 4.97579 4.98655 4.99268 4.99571 4.99771 4.99881 4.99929 4.99954 4.99965 4.9997 4.99971 4.99971 4.99971 4.99971 4.99972 4.99974 4.99976 4.99978 4.99981 4.99984 4.99987 4.99989 4.99991 4.99991 4.99992 4.99992 4.99993 4.99997 5.00003 5.00006 5.00004 5.00001 5 4.99999 4.99998 4.99998 4.99997 4.99997 4.99997 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 5 5 4.99999 4.99999 4.99999 4.99999 4.99998 4.99998 EOD @v[34].set(<<-'EOD') 5 5.00207 5.00813 5.01486 5.00156 5.0018 4.99861 4.99844 4.99888 4.9993 4.99956 4.99971 4.99979 4.99983 4.99987 4.99989 4.99671 4.9974 4.99864 5.00131 5.00377 5.0021 5.00039 4.99993 5.00004 5.0009 5.00109 4.99636 4.98617 4.96778 4.92047 4.89528 4.91112 4.9559 4.98286 4.99369 4.99812 4.99951 4.99994 5.00014 5.00008 4.99994 4.99984 4.99989 4.99998 5.00004 5.00004 5.00006 5.00005 5.00001 4.99997 4.99992 4.99993 4.99994 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99996 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99997 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 5.00131 5.00072 4.9977 4.99811 5.00325 4.99647 4.98948 4.99459 5.00262 5.00276 5.00156 5.00072 5.0003 5.00013 4.99995 4.99668 4.99775 4.99917 5.00173 5.00386 5.00188 4.99888 4.99757 4.99951 5.01712 5.0557 5.07088 5.07704 5.07758 5.06958 5.04223 5.03331 5.0279 5.03408 5.07611 5.01911 4.68594 3.99152 2.92195 1.69878 0.809 0.344091 0.154663 0.0788717 0.0467212 0.0336168 0.0280514 0.0254947 0.024173 0.0223567 0.0220555 0.0271514 0.0295872 0.0296052 0.0283971 0.0264726 0.0241813 0.0218244 0.0195349 0.017368 0.0152495 0.013295 0.0115444 0.00996982 0.00857091 0.00733891 0.00627261 0.0053494 0.00456316 0.00388373 0.00331073 0.00282181 0.00240991 0.00206389 0.00177187 0.00152283 0.00131167 0.00112558 0.000954373 0.000805726 0.00069326 0.000600991 0.000525743 0.00047355 0.00044359 0.000434815 0.000436053 0.000402511 0.000368969 0.000335427 0.000301886 0.000268344 0.000234802 0.00020126 0.000184967 0.000169932 0.000154896 0.000139861 0.000124825 0.00010979 9.47546e-05 8.67896e-05 8.24901e-05 7.81906e-05 7.38911e-05 6.95915e-05 6.5292e-05 6.09925e-05 5.66929e-05 5.23934e-05 4.80939e-05 4.37943e-05 3.94948e-05 3.51953e-05 3.08957e-05 2.67968e-05 2.42936e-05 2.17904e-05 1.92872e-05 1.6784e-05 0.00125927 -0.00794344 -0.0305499 -0.0621697 -0.0463796 -0.0224608 -0.00538381 0.00546086 0.0108675 0.012883 0.0131787 0.0127271 0.0119702 0.0110398 0.0100635 0.00649617 0.00489388 0.00545863 0.0098351 0.0167428 0.0126563 0.00697542 0.00427027 0.00330002 0.00390774 0.00408999 -0.00259143 -0.0160578 -0.0451849 -0.0409651 0.1301 0.597429 1.3848 2.63426 3.81272 4.51373 4.8412 4.98731 4.88165 4.37165 3.40034 2.17681 1.12217 0.505129 0.219703 0.104992 0.0622333 0.0448317 0.0355782 0.0311867 0.0293529 0.0274615 0.0288739 0.0307845 0.0304909 0.029245 0.0273602 0.0251006 0.022697 0.0202765 0.0179357 0.0157106 0.0136562 0.0117951 0.0101273 0.00865784 0.00739394 0.00634364 0.00551356 0.00480538 0.00415747 0.00356084 0.00297585 0.00236711 0.00181853 0.00160713 0.00169822 0.00166542 0.00145504 0.00120252 0.00109259 0.000982658 0.00087273 0.000762802 0.000652874 0.000584068 0.000528263 0.000472458 0.000416653 0.000360848 0.000321155 0.000301442 0.000281729 0.000262016 0.000242303 0.00022259 0.000202877 0.000183164 0.000163451 0.000143738 0.000124025 0.000114582 0.000107399 0.000100216 9.30332e-05 8.58502e-05 7.86672e-05 7.14841e-05 6.43011e-05 5.7118e-05 4.9935e-05 4.35378e-05 4.04281e-05 3.73184e-05 3.42088e-05 3.10991e-05 2.79894e-05 2.48798e-05 2.17701e-05 1.86604e-05 EOD @v[35].set(<<-'EOD') 7.24585e-12 2.21843e-05 3.20014e-05 1.25076e-05 -2.44947e-05 1.8425e-05 5.50546e-06 3.53025e-05 -1.07551e-05 -3.94383e-06 -2.27848e-06 -9.04789e-05 7.44215e-05 -2.7662e-05 0.000200038 -2.11998e-05 -2.09011e-05 2.37098e-05 2.18751e-05 -2.28422e-05 -6.23659e-05 3.58241e-05 1.76386e-05 -4.28311e-05 0.000355626 0.00156903 0.00100999 -0.0085304 -0.02067 -0.0389485 -0.0651568 -0.128475 -0.314362 -0.406837 -0.421558 -0.421277 -0.418176 -0.414481 -0.410845 -0.407348 -0.403971 -0.400716 -0.397582 -0.394563 -0.391658 -0.388866 -0.386178 -0.383585 -0.381094 -0.378789 -0.376569 -0.37435 -0.372256 -0.370188 -0.36815 -0.366422 -0.364694 -0.362967 -0.361239 -0.359511 -0.357888 -0.356334 -0.354781 -0.353227 -0.351674 -0.350152 -0.348888 -0.347625 -0.346361 -0.345098 -0.343834 -0.342571 -0.341307 -0.340044 -0.33878 -0.337517 -0.336279 -0.335215 -0.334152 -0.333088 -0.332024 -0.330961 -0.329897 -0.328833 -0.32777 -0.326706 -0.325642 -0.324601 -0.323683 -0.322766 -0.321849 -0.320932 -0.320014 -0.319097 -0.31818 -0.317263 -0.316345 -0.315428 -0.314545 -0.313825 -0.313106 -0.312387 -0.311667 -0.310948 -0.310228 -0.309509 -0.308789 -0.30807 -0.307351 -0.306631 -0.305912 -0.305192 -0.304473 -0.303754 -0.303034 -0.302315 -0.301595 -0.300876 -0.300157 -0.299437 -0.298716 -0.29798 -0.297329 -0.296691 -0.295837 -0.29516 -0.294725 -0.294044 -0.292917 -0.292351 -0.291965 -0.291365 -0.290687 -0.290027 -0.289376 -0.288772 -0.288193 -0.287505 -0.286892 -0.28626 -0.285714 -0.284545 -0.289246 -0.298717 -0.298492 -0.214163 0.181451 0.0749974 0.0454707 0.0292987 0.0196837 0.0124119 0.00884715 0.00527181 0.00585821 0.0296361 0.169856 0.361207 0.538856 0.67469 0.685933 0.392802 0.17772 0.0813085 0.0424601 0.0246654 0.0175258 0.0144256 0.0129859 0.012205 0.0112846 0.010933 0.0134813 0.0147254 0.0147981 0.0142156 0.0132732 0.0121355 0.0109587 0.00981238 0.00872731 0.00767007 0.00669346 0.00581341 0.00502167 0.00431819 0.00369842 0.00316168 0.00269663 0.00230035 0.00195801 0.00166928 0.00142286 0.00121522 0.00104072 0.000893384 0.000767675 0.000661268 0.000567659 0.000481766 0.000407101 0.000350044 0.000302721 0.000263424 0.000236813 0.00022199 0.000218182 0.000219548 0.0002027 0.000185853 0.000169006 0.000152158 0.000135311 0.000118463 0.000101616 9.33782e-05 8.57685e-05 7.81588e-05 7.0549e-05 6.29393e-05 5.53296e-05 4.77199e-05 4.36954e-05 4.15296e-05 3.93637e-05 3.71978e-05 3.50319e-05 3.28661e-05 3.07002e-05 2.85343e-05 2.63685e-05 2.42026e-05 2.20367e-05 1.98709e-05 1.7705e-05 1.55391e-05 1.34772e-05 1.22416e-05 1.10061e-05 9.77055e-06 8.535e-06 0.000631271 -0.00362586 -0.0146235 -0.0308486 -0.0237466 -0.0117522 -0.00304171 0.00251033 0.00531986 0.0063897 0.00657351 0.00636494 0.00599705 0.00553442 0.00505994 0.00330925 0.00246671 0.0027006 0.00473161 0.00830333 0.00649147 0.00356815 0.00217448 0.00187579 0.00270447 0.00219543 -0.00546118 -0.0179576 -0.0445306 -0.0649309 0.0197935 0.473629 0.87268 0.269542 0.0086094 0.0844602 0.606456 1.04929 0.906014 0.916205 0.919425 0.872867 0.556244 0.262457 0.11838 0.0571226 0.0333451 0.0237133 0.0185096 0.0159617 0.0148663 0.0138683 0.0144081 0.0153797 0.0152551 0.0146487 0.0137192 0.0125973 0.0113996 0.0101903 0.00901851 0.00790495 0.00687502 0.00593994 0.00510092 0.00436111 0.00372439 0.0031945 0.00277537 0.00241888 0.002095 0.00179943 0.00150419 0.00119264 0.00090934 0.000802394 0.000852816 0.000838368 0.000730842 0.000601028 0.000546616 0.000492205 0.000437793 0.000383381 0.000328969 0.00029454 0.000266428 0.000238317 0.000210205 0.000182093 0.000162091 0.000152145 0.000142198 0.000132252 0.000122306 0.000112359 0.000102413 9.24665e-05 8.25201e-05 7.25738e-05 6.26274e-05 5.78553e-05 5.42216e-05 5.05878e-05 4.69541e-05 4.33204e-05 3.96867e-05 3.60529e-05 3.24192e-05 2.87855e-05 2.51518e-05 2.19153e-05 2.03406e-05 1.8766e-05 1.71913e-05 1.56167e-05 1.4042e-05 1.24674e-05 1.08927e-05 9.31806e-06 EOD @v[36].set(<<-'EOD') 5 5.01426 5.02852 5.01923 4.77685 4.56471 4.52338 4.56813 4.63122 4.693 4.74776 4.79385 4.83258 4.86358 4.88918 4.91021 4.90553 4.89733 4.89554 4.91953 5.00757 5.07101 5.06318 5.05241 5.05535 5.08042 5.07251 4.90973 4.56136 3.98637 3.237 2.67216 2.33678 2.13529 2.00544 1.91429 1.84638 1.79461 1.75338 1.71958 1.69175 1.6686 1.64918 1.63258 1.61836 1.60607 1.59506 1.58483 1.57575 1.56847 1.56193 1.55538 1.54968 1.54416 1.5388 1.53523 1.53165 1.52807 1.52449 1.52091 1.51771 1.51477 1.51182 1.50888 1.50593 1.50309 1.50113 1.49917 1.4972 1.49524 1.49328 1.49132 1.48935 1.48739 1.48543 1.48346 1.48157 1.48012 1.47868 1.47724 1.47579 1.47435 1.47291 1.47146 1.47002 1.46857 1.46713 1.46574 1.46462 1.4635 1.46238 1.46126 1.46014 1.45902 1.4579 1.45678 1.45567 1.45455 1.45349 1.45275 1.45201 1.45127 1.45053 1.44979 1.44905 1.44831 1.44757 1.44683 1.44609 1.44535 1.44461 1.44387 1.44313 1.44239 1.44165 1.44091 1.44017 1.43943 1.43869 1.43795 1.43721 1.43874 1.43976 1.43619 1.43182 1.43726 1.43084 1.42587 1.42383 1.42642 1.42728 1.42736 1.4271 1.42669 1.42621 1.42569 1.41703 1.41244 1.41019 1.41199 1.41833 1.42502 1.41504 1.37535 1.28381 1.44779 2.33713 3.25835 3.67554 3.84975 4.01125 4.2253 4.45433 4.62215 4.74478 4.82998 4.8868 4.92396 4.94768 4.96498 4.98537 5.0128 5.04467 5.06722 5.06535 5.01475 4.91956 4.80647 4.7242 4.7059 4.73552 4.76379 4.81684 4.87376 4.92276 4.96112 4.9884 5.0045 5.00999 5.00933 5.00619 5.00384 5.00342 5.00373 5.00362 5.00309 5.00272 5.00239 5.00204 5.00172 5.00146 5.00124 5.00105 5.00089 5.00076 5.00065 5.00057 5.00048 5.00041 5.00034 5.00028 5.00023 5.00019 5.00015 5.00015 5.00016 5.0002 5.00023 5.00021 5.00019 5.00017 5.00015 5.00012 5.0001 5.00008 5.00007 5.00006 5.00005 5.00004 5.00003 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.00062 4.99506 4.9835 4.96726 4.9728 4.97877 4.98675 4.9966 5.00406 5.00679 5.00629 5.00561 5.00487 5.00429 5.00384 5.002 5.00164 5.00229 5.00484 5.00769 5.00019 5.00242 5.01319 5.0335 5.07265 5.10129 5.11485 5.12551 5.13953 5.16048 5.18862 5.22811 5.25656 5.25627 5.19975 4.9139 4.24745 3.43732 2.8202 2.43224 2.17409 2.01333 1.93951 1.94622 1.98861 2.02217 2.05383 2.08376 2.11184 2.13793 2.16191 2.18267 2.20502 2.22837 2.24958 2.26901 2.28648 2.302 2.31582 2.32802 2.33869 2.34795 2.35596 2.36282 2.3687 2.37371 2.37797 2.38161 2.38476 2.38743 2.3897 2.39168 2.39329 2.39463 2.39575 2.39671 2.39756 2.39835 2.39907 2.39968 2.39999 2.4003 2.40061 2.40091 2.40122 2.40142 2.40159 2.40176 2.40193 2.4021 2.40222 2.40228 2.40234 2.4024 2.40247 2.40253 2.40259 2.40265 2.40271 2.40277 2.40284 2.40287 2.40289 2.40291 2.40294 2.40296 2.40298 2.40301 2.40303 2.40305 2.40308 2.4031 2.40311 2.40312 2.40313 2.40314 2.40315 2.40316 2.40317 2.40318 EOD @v[37].set(<<-'EOD') 5 5.01732 5.03181 5.05944 5.12686 5.20725 5.28103 5.31254 5.32901 5.33709 5.3408 5.34257 5.34311 5.34347 5.34386 5.34411 5.3406 5.33484 5.32942 5.32904 5.33644 5.34869 5.35001 5.34882 5.34758 5.34672 5.34599 5.34496 5.34364 5.34165 5.33712 5.33502 5.3366 5.34067 5.34306 5.34398 5.34434 5.34442 5.34443 5.34443 5.34441 5.34439 5.34437 5.34437 5.34438 5.34438 5.34438 5.34438 5.34438 5.34437 5.34437 5.34436 5.34436 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.34437 5.35377 5.35451 5.34265 5.34488 5.35861 5.28622 4.90033 4.75027 4.89731 4.97098 4.99293 4.99832 4.99909 4.99956 4.99858 4.99829 4.9998 5.00035 5.0038 5.00989 5.00251 4.99438 4.9953 4.99761 4.99985 5.00152 5.0011 5.00046 4.99996 4.99925 4.99862 4.99919 4.99961 5.00048 5.00234 4.99654 4.98235 4.95936 4.83738 4.53021 4.21004 4.00593 3.91207 3.88059 3.87822 3.89117 3.91278 3.94044 3.97376 4.01152 4.05052 4.10679 4.17908 4.25673 4.33414 4.40875 4.47879 4.54342 4.60258 4.65595 4.70291 4.74414 4.78018 4.81185 4.83915 4.86291 4.88301 4.90048 4.91528 4.92802 4.9387 4.94777 4.95539 4.9618 4.96725 4.97195 4.97588 4.97932 4.98247 4.98512 4.98697 4.98831 4.98919 4.99015 4.99101 4.99169 4.99222 4.99282 4.99341 4.994 4.9946 4.99519 4.99578 4.99638 4.99667 4.99693 4.9972 4.99747 4.99773 4.998 4.99827 4.99841 4.99849 4.99856 4.99864 4.99872 4.9988 4.99888 4.99896 4.99904 4.99911 4.99919 4.99927 4.99935 4.99943 4.9995 4.99955 4.9996 4.99965 4.9997 5.00736 4.98252 4.87516 4.66727 4.49142 4.43103 4.4301 4.4571 4.49729 4.5407 4.5835 4.62363 4.66114 4.69577 4.72738 4.74632 4.75971 4.77576 4.80671 4.87073 4.91665 4.93252 4.94418 4.95331 4.96094 4.96727 4.97148 4.97471 4.97612 4.98276 5.00247 5.04086 5.08628 5.10673 5.08887 5.0564 5.02767 5.01336 4.99685 4.97422 4.90866 4.67035 4.33117 4.07888 3.94432 3.89105 3.88174 3.89292 3.91442 3.94564 3.98708 4.0355 4.09134 4.16315 4.24088 4.31918 4.39527 4.46693 4.53337 4.59405 4.6486 4.69693 4.73938 4.77617 4.80809 4.83551 4.85895 4.87894 4.89596 4.91081 4.92417 4.93651 4.94552 4.95198 4.9565 4.96096 4.96523 4.96972 4.97428 4.97868 4.98064 4.9826 4.98455 4.98651 4.98847 4.98967 4.99064 4.9916 4.99257 4.99353 4.99422 4.99457 4.99493 4.99528 4.99563 4.99598 4.99633 4.99668 4.99703 4.99738 4.99773 4.9979 4.99804 4.99817 4.9983 4.99843 4.99856 4.99869 4.99883 4.99896 4.99909 4.99921 4.99926 4.99931 4.99937 4.99942 4.99948 4.99953 4.99959 4.99964 EOD @v[38].set(<<-'EOD') 4.49849 4.53282 4.58329 4.66625 4.83345 4.97823 5.0207 5.01816 5.01116 5.00595 5.00296 5.00148 5.00073 5.00062 5.00033 5.0003 4.99864 4.99661 4.99652 4.99928 5.00361 5.12573 5.17251 5.22612 5.33479 5.44503 5.44432 5.44379 5.44334 5.443 5.44276 5.44258 5.44246 5.44238 5.44232 5.44228 5.44225 5.44223 5.44221 5.4422 5.44219 5.44219 5.44218 5.44218 5.44218 5.44218 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44217 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44216 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44215 5.44214 5.44214 5.44214 5.44214 5.44214 5.44214 5.44214 5.44214 5.44214 5.44214 5.44214 5.44212 5.45159 5.45236 5.44064 5.44307 5.45616 5.38122 4.77163 3.53297 2.74466 2.34448 2.11802 1.9783 1.88656 1.82001 1.77389 1.72955 1.69632 1.66971 1.6526 1.65236 1.56034 1.53764 1.97139 2.75096 3.39212 3.74042 3.82345 3.85696 3.88547 3.91862 3.9585 4.00467 4.05903 4.1254 4.19533 4.26791 4.34517 4.42112 4.49238 4.55807 4.6179 4.6713 4.71815 4.75889 4.79418 4.82456 4.85062 4.87291 4.89196 4.90823 4.92209 4.93388 4.9439 4.95242 4.95968 4.96585 4.97108 4.9755 4.97923 4.98237 4.98503 4.98732 4.98927 4.99094 4.99233 4.99353 4.99452 4.99538 4.99608 4.99668 4.99718 4.9976 4.99794 4.99822 4.99847 4.99867 4.99884 4.99899 4.99913 4.99924 4.99932 4.99938 4.99943 4.99947 4.99951 4.99953 4.99955 4.99958 4.99961 4.99964 4.99967 4.99969 4.99972 4.99975 4.99977 4.99978 4.99979 4.99981 4.99982 4.99983 4.99985 4.99986 4.99986 4.99987 4.99987 4.99988 4.99988 4.99988 4.99989 4.99989 4.9999 4.9999 4.99991 4.99991 4.99992 4.99992 4.99993 4.99993 4.99993 4.99994 5.00381 5.00064 4.99246 4.99823 5.00349 5.00076 5.00033 5.00015 5.00009 5.00007 5.00005 5.00004 5.00003 5.00002 4.99988 4.99732 4.99728 4.9978 5.00187 5.00927 5.08712 5.07654 4.92855 4.4863 3.76162 3.00049 2.49834 2.20883 2.03492 1.92384 1.84676 1.79021 1.74716 1.7132 1.68576 1.66309 1.64406 1.62785 1.61383 1.60162 1.59081 1.58117 1.57253 1.56473 1.55765 1.55117 1.54527 1.53988 1.53485 1.53012 1.5257 1.5216 1.51773 1.51411 1.51071 1.50746 1.50438 1.50146 1.49868 1.49603 1.4935 1.49109 1.48878 1.48657 1.48445 1.48242 1.48046 1.47858 1.47677 1.47502 1.47333 1.4717 1.47012 1.46859 1.46711 1.46568 1.46428 1.46292 1.4616 1.46034 1.45923 1.45812 1.45701 1.4559 1.45479 1.45378 1.45279 1.45181 1.45082 1.44983 1.44893 1.44813 1.44732 1.44652 1.44571 1.44491 1.4441 1.4433 1.44249 1.44169 1.44089 1.44019 1.43951 1.43883 1.43815 1.43747 1.4368 1.43612 1.43544 1.43476 1.43408 1.43342 1.43283 1.43223 1.43163 1.43104 1.43044 1.42984 1.42924 1.42865 EOD @v[39].set(<<-'EOD') 5 5.01048 5.01221 4.98887 4.76261 4.54943 4.51564 4.56249 4.62621 4.68843 4.74374 4.79044 4.82972 4.86127 4.88724 4.90862 4.90791 4.89858 4.89589 4.91767 5.00405 5.16956 5.12391 4.7557 3.87953 3.01124 2.48482 2.20424 2.03812 1.92679 1.84956 1.79256 1.74907 1.71487 1.68724 1.6644 1.64513 1.6287 1.61446 1.60197 1.59095 1.58117 1.57245 1.5646 1.55752 1.55109 1.54516 1.53958 1.53444 1.53008 1.52606 1.52205 1.51843 1.5149 1.51146 1.50893 1.50639 1.50387 1.50133 1.4988 1.49651 1.49436 1.49222 1.49007 1.48793 1.48585 1.48433 1.4828 1.48128 1.47975 1.47823 1.4767 1.47518 1.47365 1.47213 1.4706 1.46912 1.46795 1.46678 1.46561 1.46444 1.46327 1.4621 1.46093 1.45976 1.45859 1.45741 1.45628 1.45534 1.45441 1.45347 1.45254 1.4516 1.45067 1.44973 1.4488 1.44786 1.44693 1.44604 1.44539 1.44475 1.4441 1.44345 1.44281 1.44216 1.44151 1.44086 1.44022 1.43957 1.43892 1.43828 1.43763 1.43698 1.43633 1.43569 1.43504 1.43439 1.43375 1.4331 1.43245 1.4318 1.43157 1.43089 1.43001 1.43042 1.42899 1.42439 1.42216 1.43447 1.44048 1.43705 1.43314 1.43039 1.42861 1.42739 1.42651 1.42548 1.42488 1.4243 1.42392 1.4235 1.32443 1.31149 1.78169 2.64844 3.43211 3.95252 4.20231 4.3746 4.49948 4.58929 4.65742 4.71183 4.77057 4.83196 4.88354 4.92894 4.96625 4.99235 5.00651 5.00941 5.00813 5.00689 5.00588 5.00504 5.00431 5.00368 5.00314 5.00268 5.00228 5.00194 5.00165 5.0014 5.00118 5.001 5.00085 5.00072 5.00061 5.00052 5.00044 5.00037 5.00031 5.00027 5.00022 5.00019 5.00016 5.00013 5.00011 5.00009 5.00008 5.00007 5.00006 5.00005 5.00004 5.00003 5.00003 5.00003 5.00002 5.00002 5.00002 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5.00001 5 5 5 5 5 4.99999 4.99999 4.99999 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99998 4.99999 4.99999 4.99999 4.99999 4.99999 4.99999 5 5 5 5 5.00001 5.00002 5.00003 5.00004 5.00022 4.99974 4.99942 4.99997 5.00063 5.00002 5.00003 4.99994 4.99998 4.99999 5 5 5 5 5 4.99981 4.99998 5.00004 5.00036 5.00049 5.12012 5.16315 5.19712 5.21835 4.87874 4.10151 3.31555 2.74207 2.38075 2.15872 2.01614 1.91886 1.84852 1.79401 1.75052 1.71508 1.68672 1.66467 1.64602 1.62985 1.61576 1.60343 1.59256 1.58287 1.57418 1.56632 1.55922 1.55282 1.54687 1.54132 1.53618 1.53143 1.52698 1.52282 1.51895 1.51527 1.5118 1.50851 1.5054 1.50244 1.49963 1.49695 1.4944 1.49196 1.48963 1.4874 1.48527 1.48322 1.48124 1.47934 1.47751 1.47574 1.47403 1.47239 1.4708 1.46926 1.46777 1.46632 1.46491 1.46355 1.46237 1.4612 1.46002 1.45884 1.45766 1.45659 1.45555 1.45451 1.45346 1.45242 1.45147 1.45062 1.44978 1.44894 1.44809 1.44725 1.4464 1.44556 1.44472 1.44387 1.44303 1.4423 1.44159 1.44088 1.44017 1.43947 1.43876 1.43805 1.43734 1.43664 1.43593 1.43524 1.43462 1.434 1.43338 1.43276 1.43213 1.43151 1.43089 1.43027 EOD end def highlightTrace(graph) entry = graph.legend_get(:current) active_list = graph.legend_activate if active_list.include?(entry) graph.legend_deactivate(entry) graph.element_deactivate(entry) else graph.legend_activate(entry) graph.element_activate(entry) end end end BLT_Graph_Demo.new Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/blt/graph7.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/blt' length = 250000 graph = Tk::BLT::Graph.new(:title=>"Scatter Plot\n#{length} points") graph.xaxis_configure(:loose=>false, :title=>'X Axis Label') graph.yaxis_configure(:title=>'Y Axis Label') graph.legend_configure(:activerelief=>:sunken, :background=>'') Tk::BLT::Table.add(Tk.root, graph, [0,0], :fill=>:both) v_x = Tk::BLT::Vector.new(length) v_y = Tk::BLT::Vector.new(length) v_x.expr("random(#{v_x})") v_y.expr("random(#{v_y})") v_x.sort(v_y) plot = Tk::BLT::PlotComponent::Element.new(graph, :symbol=>:square, :color=>'green4', :fill=>'green2', :linewidth=>0, :outlinewidth=>1, :pixels=>4, :label=>'plot', :xdata=>v_x, :ydata=>v_y) Tk.root.minsize(0, 0) #graph.zoom_stack #graph.crosshairs #graph.active_legend #graph.closest_point Tk::BLT.zoom_stack(graph) Tk::BLT.crosshairs(graph) Tk::BLT.active_legend(graph) Tk::BLT.closest_point(graph) Tk::BLT::Busy.hold(graph) Tk.update Tk::BLT::Busy.release(graph) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/blt/graph7a.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/blt' file = File.join(File.dirname(File.expand_path(__FILE__)), 'images', 'buckskin.gif') bgTexture = TkPhotoImage.new(:file=>file) TkOption.add('*Graph.Tile', bgTexture) TkOption.add('*Label.Tile', bgTexture) TkOption.add('*Frame.Tile', bgTexture) TkOption.add('*Htext.Tile', bgTexture) TkOption.add('*TileOffset', 0) TkOption.add('*HighlightThickness', 0) TkOption.add('*Element.ScaleSybols', false) TkOption.add('*Element.Smooth', :linear) TkOption.add('*activeLine.Color', 'yellow4') TkOption.add('*activeLine.Fill', 'yellow') TkOption.add('*activeLine.LineWidth', 0) TkOption.add('*Element.Pixels', 3) TkOption.add('*Graph.halo', '7i') if Tk.root.winfo_screenvisual != 'staticgray' TkOption.add('*print.background', 'yellow') TkOption.add('*quit.background', 'red') end length = 250000 graph = Tk::BLT::Graph.new(:title=>"Scatter Plot\n#{length} points") graph.xaxis_configure(:loose=>false, :title=>'X Axis Label') graph.yaxis_configure(:title=>'Y Axis Label') graph.legend_configure(:activerelief=>:sunken, :background=>'') Tk::BLT::Table.add(Tk.root, graph, [0,0], :fill=>:both) v_x = Tk::BLT::Vector.new(length) v_y = Tk::BLT::Vector.new(length) v_x.expr("random(#{v_x})") v_y.expr("random(#{v_y})") v_x.sort(v_y) plot = Tk::BLT::PlotComponent::Element.new(graph, :symbol=>:square, :color=>'green4', :fill=>'green2', :linewidth=>0, :outlinewidth=>1, :pixels=>4, :label=>'plot', :xdata=>v_x, :ydata=>v_y) Tk.root.minsize(0, 0) #graph.zoom_stack #graph.crosshairs #graph.active_legend #graph.closest_point Tk::BLT.zoom_stack(graph) Tk::BLT.crosshairs(graph) Tk::BLT.active_legend(graph) Tk::BLT.closest_point(graph) Tk::BLT::Busy.hold(graph) Tk.update Tk::BLT::Busy.release(graph) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/blt/graph7b.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/blt' length = 250000 graph = Tk::BLT::Graph.new(:title=>"Scatter Plot\n#{length} points") graph.xaxis_configure(:loose=>false, :title=>'X Axis Label') graph.yaxis_configure(:title=>'Y Axis Label') graph.legend_configure(:activerelief=>:sunken, :background=>'') Tk::BLT::Table.add(Tk.root, graph, [0,0], :fill=>:both) x = Array.new(length) y = Array.new(length) (0...length).each{|i| x[i] = rand y[i] = rand } plot = Tk::BLT::PlotComponent::Element.new(graph, :symbol=>:square, :color=>'green4', :fill=>'green2', :linewidth=>0, :outlinewidth=>1, :pixels=>4, :label=>'plot', :xdata=>x, :ydata=>y) Tk.root.minsize(0, 0) #graph.zoom_stack #graph.crosshairs #graph.active_legend #graph.closest_point Tk::BLT.zoom_stack(graph) Tk::BLT.crosshairs(graph) Tk::BLT.active_legend(graph) Tk::BLT.closest_point(graph) Tk::BLT::Busy.hold(graph) Tk.update Tk::BLT::Busy.release(graph) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/blt/graph7c.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/blt' length = 250000 graph = Tk::BLT::Graph.new(:title=>"Scatter Plot\n#{length} points") graph.xaxis_configure(:loose=>false, :title=>'X Axis Label') graph.yaxis_configure(:title=>'Y Axis Label') graph.legend_configure(:activerelief=>:sunken, :background=>'') Tk::BLT::Table.add(Tk.root, graph, [0,0], :fill=>:both) v_x = Tk::BLT::Vector.new(length) v_y = Tk::BLT::Vector.new(length) x = Array.new(length) y = Array.new(length) (0...length).each{|i| x[i] = rand y[i] = rand } v_x.set(x) v_y.set(y) plot = Tk::BLT::PlotComponent::Element.new(graph, :symbol=>:square, :color=>'green4', :fill=>'green2', :linewidth=>0, :outlinewidth=>1, :pixels=>4, :label=>'plot', :xdata=>v_x, :ydata=>v_y) Tk.root.minsize(0, 0) #graph.zoom_stack #graph.crosshairs #graph.active_legend #graph.closest_point Tk::BLT.zoom_stack(graph) Tk::BLT.crosshairs(graph) Tk::BLT.active_legend(graph) Tk::BLT.closest_point(graph) Tk::BLT::Busy.hold(graph) Tk.update Tk::BLT::Busy.release(graph) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/blt/pareto.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/blt' # Example of a pareto chart. # # The pareto chart mixes line and bar elements in the same graph. # Each processing operating is represented by a bar element. The # total accumulated defects is displayed with a single line element. b = Tk::BLT::Barchart.new(:title=>'Defects Found During Inspection', :font=>'Helvetica 12', :plotpady=>[12, 4], :width=>'6i', :height=>'5i') Tk::BLT::Table.add(Tk.root, b, :fill=>:both) data = [ ["Spot Weld", 82, 'yellow'], ["Lathe", 49, 'orange'], ["Gear Cut", 38, 'green'], ["Drill", 24, 'blue'], ["Grind", 17, 'red'], ["Lapping", 12, 'brown'], ["Press", 8, 'purple'], ["De-burr", 4, 'pink'], ["Packaging", 3, 'cyan'], ["Other", 12, 'magenta'] ] # Create an X-Y graph line element to trace the accumulated defects. b.line_create('accum', :label=>'', :symbol=>:none, :color=>'red') # Define a bitmap to be used to stipple the background of each bar. pattern1 = Tk::BLT::Bitmap.define([ [4, 4], [1, 2, 4, 8] ]) # For each process, create a bar element to display the magnitude. count = 0 sum = 0 ydata = [0] xdata = [0] labels = [] data.each{|label, value, color| count += 1 b.element_create(label, :xdata=>count, :ydata=>value, :foreground=>color, :relief=>:solid, :borderwidth=>1, :stipple=>pattern1, :background=>'lightblue') labels[count] = label # Get the total number of defects. sum += value ydata << sum xdata << count } # Configure the coordinates of the accumulated defects, # now that we know what they are. b.element_configure('accum', :xdata=>xdata, :ydata=>ydata) # Add text markers to label the percentage of total at each point. xdata.zip(ydata){|x, y| percent = (y * 100.0) / sum if x == 0 text = ' 0%' else text = '%.1f' % percent end b.marker_create(:text, :coords=>[x, y], :text=>text, :font=>'Helvetica 10', :foreground=>'red4', :anchor=>:center, :yoffset=>-5) } # Display an auxillary y-axis for percentages. b.axis_configure('y2', :hide=>false, :min=>0.0, :max=>100.0, :title=>'Percentage') # Title the y-axis b.axis_configure('y', :title=>'Defects') # Configure the x-axis to display the process names, instead of numbers. b.axis_configure('x', :title=>'Process', :rotate=>90, :subdivisions=>0, :command=>proc{|w, val| val = val.round labels[val]? labels[val]: val }) # No legend needed. b.legend_configure(:hide=>true) # Configure the grid lines. b.gridline_configure(:mapx=>:x, :color=>'lightblue') Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/blt/plot1.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/blt' graph = Tk::BLT::Graph.new.pack plot = Tk::BLT::PlotComponent::Element.new(graph, :linewidth=>0, :label=>'foo') plot.data([[1.0, 3.4], [1.1, 2.8], [1.2, 3.1], [1.4, 2.9]].flatten) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/blt/plot1b.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/blt' graph = Tk::BLT::Graph.new.pack plot = graph.element_create plot.configure(:linewidth=>0, :label=>'foo', :data=>[[1.0, 3.4], [1.1, 2.8], [1.2, 3.1], [1.4, 2.9]].flatten) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/blt/readme.txt ================================================ The scripts and image files in this directory are based on demo files of Tcl/Tk's BLT extention. ================================================ FILE: ext/tk/sample/tkextlib/blt/scripts/stipples.rb ================================================ $stipples = {} unless $stipples $stipples['bdiagonal1'] = Tk::BLT::Bitmap.new(<file) else fail RuntimeError, 'no image file' end width = src.width height = src.height TkOption.add('*Label.font', '*helvetica*10*') TkOption.add('*Label.background', 'white') l_img0 = TkLabel.new(:image=>src) l_hdr0 = TkLabel.new(:text=>"#{width} x #{height}") l_ftr0 = TkLabel.new(:text=>'100%') Tk.root.background('white') (2..10).each{|i| iw = width/i ih = height/i r = '%6g'%(100.0/i) dst = TkPhotoImage.new(:width=>iw, :height=>ih) Tk::BLT::Winop.image_resample(src, dst, :sinc) l_hdr = TkLabel.new(:text=>"#{iw} x #{ih}") l_ftr = TkLabel.new(:text=>"#{r}%") l_img = TkLabel.new(:image=>dst) Tk::BLT::Table.add(Tk.root, [0,i], l_hdr, [1,i], l_img, [2,i], l_ftr) Tk.update } Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/blt/winop2.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/blt' file = File.join(File.dirname(File.expand_path(__FILE__)), 'images', 'qv100.t.gif') if File.exist?(file) src = TkPhotoImage.new(:file=>file) else fail RuntimeError, 'no image file' end width = src.width height = src.height TkOption.add('*Label.font', '*helvetica*10*') TkOption.add('*Label.background', 'white') [0, 90, 180, 270, 360, 45].each_with_index{|r, i| dest = TkPhotoImage.new Tk::BLT::Winop.image_rotate(src, dest, r) l_txt = TkLabel.new(:text=>"#{r} degrees") l_img = TkLabel.new(:image=>dest) Tk::BLT::Table.add(Tk.root, [0,i], l_img, [1,i], l_txt) Tk.update } Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/bwidget/Orig_LICENSE.txt ================================================ ###################################################################### ### The following text is the original 'LICENSE.txt' of BWidget ### ### extension. ### ### Original Tcl source files are not include in this directry, ### ### because of all of them are rewrited to Ruby files. ### ### However, the bitmap data files ('bwidgtet.xbm' and 'x1.xbm') ### ### included in this directory are quoted from BWidget source ### ### archive. So, those bitmaps are under the following license. ### ###################################################################### BWidget ToolKit Copyright (c) 1998-1999 UNIFIX. Copyright (c) 2001-2002 ActiveState Corp. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. ================================================ FILE: ext/tk/sample/tkextlib/bwidget/basic.rb ================================================ # # basic demo --- called from demo.rb # unless Object.const_defined?('DemoVar') fail RuntimeError, "This is NOT a stand alone script. This script is called from 'demo.rb'. " end module DemoBasic @@var = TkVariable.new_hash @@after = nil @@count = 0 def self.create(nb) frame = nb.insert('end', 'demoBasic', :text=>'Basic') topf = TkFrame.new(frame) titf1 = Tk::BWidget::TitleFrame.new(topf, :text=>'Label') titf2 = Tk::BWidget::TitleFrame.new(topf, :text=>'Entry') titf3 = Tk::BWidget::TitleFrame.new(frame, :text=>'Button and ArrowButton') _label(titf1.get_frame) _entry(titf2.get_frame) _button(titf3.get_frame) Tk.pack(titf1, titf2, :side=>:left, :fill=>:both, :padx=>4, :expand=>true) topf.pack(:pady=>2, :fill=>:x) titf3.pack(:pady=>2, :padx=>4, :fill=>:x) end def self._label(parent) lab = Tk::BWidget::Label.new(parent, :text=>'This is a Label widget', :helptext=>'Label widget') chk = TkCheckbutton.new(parent, :text=>'Disabled', :variable=>@@var.ref(lab, 'state'), :onvalue=>'disabled', :offvalue=>'normal', :command=>proc{lab[:state] = @@var[lab, 'state']}) lab.pack(:anchor=>:w, :pady=>4) chk.pack(:anchor=>:w) end def self._entry(parent) ent = Tk::BWidget::Entry.new(parent, :text=>'Press enter', :helptext=>'Entry widtet', :command=>proc{ @@var['entcmd'] = 'command called' Tk.after(500, proc{@@var['entcmd'] = ''}) }) chk1 = TkCheckbutton.new(parent, :text=>'Disabled', :variable=>@@var.ref(ent, 'state'), :onvalue=>'disabled', :offvalue=>'normal', :command=>proc{ent.state = @@var[ent, 'state']}) chk2 = TkCheckbutton.new(parent, :text=>'Non editable', :variable=>@@var.ref(ent, 'editable'), :onvalue=>false, :offvalue=>true, :command=>proc{ ent.editable = @@var[ent, 'editable'] }) lab = TkLabel.new(parent, :textvariable=>@@var.ref('entcmd'), :foreground=>'red') ent.pack(:pady=>4, :anchor=>:w) Tk.pack(chk1, chk2, :anchor=>:w) lab.pack(:pady=>4) end def self._button(parent) frame = TkFrame.new(parent) but = Tk::BWidget::Button.new(frame, :text=>'Press me!', :repeatdelay=>300, :command=>proc{_butcmd('command')}, :helptext=>'This is a Button widget') sep1 = Tk::BWidget::Separator.new(frame, :orient=>:vertical) arr1 = Tk::BWidget::ArrowButton.new(frame, :type=>:button, :width=>25, :height=>25, :repeatdelay=>300, :command=>proc{_butcmd('command')}, :helptext=>"This is an ArrowButton widget\nof type button") sep2 = Tk::BWidget::Separator.new(frame, :orient=>:vertical) arr2 = Tk::BWidget::ArrowButton.new(frame, :type=>:arrow, :width=>25, :height=>25, :relief=>:sunken, :ipadx=>0, :ipady=>0, :repeatdelay=>300, :command=>proc{_butcmd('command')}, :helptext=>"This is an ArrowButton widget\nof type arrow") but.pack(:side=>:left, :padx=>4) sep1.pack(:side=>:left, :padx=>4, :fill=>:y) arr1.pack(:side=>:left, :padx=>4) sep2.pack(:side=>:left, :padx=>4, :fill=>:y) arr2.pack(:side=>:left, :padx=>4) frame.pack Tk::BWidget::Separator.new(parent, :orient=>:horizontal).pack(:fill=>:x, :pady=>10) labf1 = Tk::BWidget::LabelFrame.new(parent, :text=>'Command', :side=>:top, :anchor=>:w, :relief=>:sunken, :borderwidth=>1) subf = labf1.get_frame chk1 = TkCheckbutton.new(subf, :text=>'Disabled', :variable=>@@var.ref('bstate'), :onvalue=>'disabled', :offvalue=>'normal', :command=>proc{_bstate(@@var['bstate'], but, arr1, arr2)}) chk2 = TkCheckbutton.new(subf, :text=>"Use armcommand/\ndisarmcommand", :variable=>@@var.ref('barmcmd'), :command=>proc{_barmcmd(@@var['barmcmd'], but, arr1, arr2)}) Tk.pack(chk1, chk2, :anchor=>:w) label = TkLabel.new(parent, :textvariable=>@@var.ref('butcmd'), :foreground=>'red').pack(:side=>:bottom, :pady=>4) labf2 = Tk::BWidget::LabelFrame.new(parent, :text=>'Direction', :side=>:top, :anchor=>:w, :relief=>:sunken, :borderwidth=>1) subf = labf2.get_frame @@var['bside'] = :top [:top, :left, :bottom, :right].each{|dir| TkRadiobutton.new(subf, :text=>"#{dir} arrow", :variable=>@@var.ref('bside'), :value=>dir, :command=>proc{_bside(@@var['bside'], arr1, arr2)} ).pack(:anchor=>:w) } labf3 = Tk::BWidget::LabelFrame.new(parent, :text=>'Relief', :side=>:top, :anchor=>:w, :relief=>:sunken, :borderwidth=>1) subf = labf3.get_frame @@var['brelief'] = :raised [ %w(raised sunken ridge groove), %w(flat solid link)].each{|lrelief| f = TkFrame.new(subf) lrelief.each{|relief| TkRadiobutton.new(f, :text=>relief, :variable=>@@var.ref('brelief'), :value=>relief, :command=>proc{ _brelief(@@var['brelief'], but, arr1, arr2) }).pack(:anchor=>:w) } f.pack(:side=>:left, :padx=>2, :anchor=>:n) } Tk.pack(labf1, labf2, labf3, :side=>:left, :fill=>:y, :padx=>4) end def self._bstate(state, but, arr1, arr2) [but, arr1, arr2].each{|b| b[:state] = state} end def self._brelief(relief, but, arr1, arr2) but[:relief] = relief if relief.to_s != 'link' [arr1, arr2].each{|arr| arr[:relief] = relief} end end def self._bside(side, *args) args.each{|arr| arr[:dir] = side} end def self._barmcmd(value, but, arr1, arr2) if TkComm.bool(value) but.configure(:armcommand=>proc{_butcmd('arm')}, :disarmcommand=>proc{_butcmd('disarm')}, :command=>'') [arr1, arr2].each{|arr| arr.configure(:armcommand=>proc{_butcmd('arm')}, :disarmcommand=>proc{_butcmd('disarm')}, :command=>'') } else but.configure(:armcommand=>'', :disarmcommand=>'', :command=>proc{_butcmd('command')}) [arr1, arr2].each{|arr| arr.configure(:armcommand=>'', :disarmcommand=>'', :command=>proc{_butcmd('command')}) } end end def self._butcmd(reason) unless @@after @@after = TkTimer.new(500, 1, proc{@@var['butcmd'] = ''}) end @@after.stop if (reason == 'arm') @@count += 1 @@var['butcmd'] = "#{reason} command called (#{@@count})" else @@count = 0 @@var['butcmd'] = "#{reason} command called" end @@after.start end end ================================================ FILE: ext/tk/sample/tkextlib/bwidget/bwidget.xbm ================================================ #define bwidget_width 76 #define bwidget_height 64 static char bwidget_bits[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xf0,0x00,0xb6,0x6d,0xdb,0x16,0x00,0x00,0x00,0x00,0xf0, 0x00,0xdb,0xb6,0x6d,0xab,0x00,0x00,0x00,0x00,0xf0,0x00,0x55,0x55,0x55,0x75, 0x01,0x00,0x00,0x00,0xf0,0x00,0x6d,0xdb,0xb6,0xad,0x02,0x00,0x00,0x00,0xf0, 0x00,0xb6,0x6d,0xdb,0xb6,0x05,0x00,0x00,0x00,0xf0,0x00,0x55,0x55,0x55,0x55, 0x05,0x00,0x00,0x00,0xf0,0x00,0xda,0xb6,0xad,0x6d,0x0b,0x00,0x00,0x00,0xf0, 0x00,0x6b,0x03,0xc0,0xb6,0x05,0x00,0x00,0x00,0xf0,0x00,0x56,0x05,0x00,0x55, 0x0d,0x00,0x00,0x00,0xf0,0x00,0xbb,0x05,0x80,0xdb,0x06,0x00,0x00,0x00,0xf0, 0x00,0xca,0x06,0x00,0x6c,0x0b,0x00,0x00,0x00,0xf0,0x00,0xb6,0x02,0x00,0xaa, 0x0a,0x00,0x00,0x00,0xf0,0x00,0xab,0x05,0x00,0x6c,0x0b,0x00,0x00,0x00,0xf0, 0x00,0xdd,0x06,0x00,0xb6,0x05,0x00,0x00,0x00,0xf0,0x00,0xaa,0x02,0x00,0x55, 0x05,0x00,0x00,0x00,0xf0,0x00,0xb7,0x05,0xc0,0xda,0x02,0x00,0x00,0x00,0xf0, 0x00,0xd9,0x06,0x50,0x6b,0x01,0x00,0x00,0x00,0xf0,0x00,0x56,0xb5,0xad,0xad, 0x00,0x00,0x00,0x00,0xf0,0x00,0xdb,0xd6,0x76,0x15,0x00,0x00,0x00,0x00,0xf0, 0x00,0x6a,0xab,0xaa,0x2d,0x00,0x00,0x00,0x00,0xf0,0x00,0x56,0x75,0xad,0xb6, 0x02,0x00,0x00,0x00,0xf0,0x00,0xbb,0xad,0xd6,0xaa,0x05,0x00,0x00,0x00,0xf0, 0x00,0xca,0xb6,0x6b,0xdb,0x2a,0x00,0x00,0x00,0xf0,0x00,0x77,0xd5,0x5c,0x6d, 0x2d,0x00,0x00,0x00,0xf0,0x00,0x99,0x05,0x00,0xaa,0x56,0x00,0x00,0x00,0xf0, 0x00,0xee,0x06,0x00,0x6c,0xbb,0x00,0x00,0x00,0xf0,0x00,0xaa,0x02,0x00,0xb0, 0x55,0x00,0x00,0x00,0xf0,0x00,0x55,0x05,0x00,0xa8,0xd6,0x00,0x00,0x00,0xf0, 0x00,0xee,0x06,0x00,0xd0,0x6a,0x00,0x00,0x00,0xf0,0x00,0x55,0x03,0x00,0x68, 0xb7,0xfc,0x00,0x7e,0xf0,0x00,0x6d,0x05,0x00,0xa8,0xaa,0xfc,0x80,0x7e,0xf0, 0x00,0xb6,0x05,0x00,0x50,0xbb,0xfe,0x01,0x7e,0xf0,0x00,0x55,0x05,0x00,0x78, 0xad,0xfe,0x81,0x1f,0xf0,0x00,0xb6,0x05,0x00,0xa4,0xb5,0xfe,0x81,0x1f,0xf0, 0x00,0x5b,0x05,0x80,0xba,0x56,0xfe,0x83,0x1f,0xf0,0x00,0xaa,0x6b,0x5b,0xd5, 0x5a,0xff,0x85,0x1f,0xf0,0x00,0xdb,0x5a,0xad,0x57,0x2b,0xff,0xc7,0x0f,0xf0, 0x00,0x6d,0xad,0xd5,0x6a,0x0d,0xff,0xc7,0x0f,0xf0,0x00,0xaa,0xd6,0xb6,0xba, 0x05,0xdf,0xc7,0x0f,0xf0,0x00,0xb7,0xb5,0x5a,0xab,0x8a,0xdf,0xcf,0x0f,0xf0, 0x00,0xd9,0x5a,0xab,0x6d,0x8f,0xcf,0xef,0x07,0xf0,0x00,0x56,0xad,0x75,0xb5, 0xaf,0x8f,0xef,0x07,0xf0,0x00,0xb5,0xeb,0x5a,0x00,0x9f,0xcf,0xef,0x07,0xf0, 0x00,0x00,0x00,0x00,0x00,0xff,0x8f,0xff,0x07,0xf0,0x00,0x00,0x00,0x00,0x00, 0xfe,0x87,0xff,0x03,0xf0,0x00,0x00,0x00,0x00,0x00,0xff,0x03,0xff,0x03,0xf0, 0x00,0x00,0x00,0x00,0x00,0xfe,0x03,0xff,0x03,0xf0,0x00,0x00,0x00,0x00,0x00, 0xfe,0x03,0xff,0x01,0xf0,0x00,0x00,0x00,0x00,0x00,0xfc,0x01,0xff,0x03,0xf0, 0x00,0x00,0x00,0x00,0x00,0xfe,0x01,0xfe,0x01,0xf0,0x00,0x00,0x00,0x00,0x00, 0xfc,0x01,0xfe,0x01,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0}; ================================================ FILE: ext/tk/sample/tkextlib/bwidget/demo.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/bwidget' module DemoVar @_wfont = nil @notebook = nil @mainframe = nil @status = TkVariable.new @prgtext = TkVariable.new @prgindic = TkVariable.new @font = nil @font_name = nil @toolbar1 = TkVariable.new(true) @toolbar2 = TkVariable.new(true) end class << DemoVar attr_accessor :_wfont, :notebook, :mainframe, :font, :font_name attr_reader :status, :prgtext, :prgindic, :toolbar1, :toolbar2 end class BWidget_Demo DEMODIR = File.dirname(File.expand_path(__FILE__)) %w(manager basic select dnd tree tmpldlg).each{|f| require File.join(DEMODIR, f << '.rb') } def initialize TkOption.add('*TitleFrame.l.font', 'helvetica 11 bold italic') root = TkRoot.new(:title=>'BWidget demo') root.withdraw _create Tk::BWidget.place(root, 0, 0, :center) root.deiconify root.raise root.focus(true) root.geometry(root.geometry) end def _create DemoVar.prgtext.value = 'Please wait while loading font...' DemoVar.prgindic.value = -1 intro = _create_intro Tk.update Tk::BWidget::SelectFont.load_font descmenu = [ '&File', 'all', 'file', 0, [ ['command', 'E&xit', [], 'Exit BWidget demo', [], {:command=>proc{exit}}] ], '&Options', 'all', 'options', 0, [ ['checkbutton', 'Toolbar &1', ['all', 'option'], 'Show/hide toolbar 1', [], { :variable=>DemoVar.toolbar1, :command=>proc{ DemoVar.mainframe.show_toolbar(0, DemoVar.toolbar1.value) } } ], ['checkbutton', 'Toolbar &2', ['all', 'option'], 'Show/hide toolbar 2', [], { :variable=>DemoVar.toolbar2, :command=>proc{ DemoVar.mainframe.show_toolbar(1, DemoVar.toolbar2.value) } } ] ] ] DemoVar.prgtext.value = 'Creating MainFrame...' DemoVar.prgindic.value = 0 DemoVar.mainframe = Tk::BWidget::MainFrame.new( :menu=>descmenu, :textvariable=>DemoVar.status, :progressvar=>DemoVar.prgindic ) # toobar 1 creation DemoVar.prgindic.numeric += 1 DemoVar.mainframe.add_toolbar{|tb1| Tk::BWidget::ButtonBox.new(tb1, :spacing=>0, :padx=>1, :pady=>1){|bbox| add(:image=>Tk::BWidget::Bitmap.new('new'), :highlightthickness=>0, :takefocus=>0, :relief=>:link, :borderwidth=>1, :padx=>1, :pady=>1, :command=>proc{puts 'select "Create a new file" icon'}, :helptext=>"Create a new file") add(:image=>Tk::BWidget::Bitmap.new('open'), :highlightthickness=>0, :takefocus=>0, :relief=>:link, :borderwidth=>1, :padx=>1, :pady=>1, :command=>proc{puts 'select "Open an existing file" icon'}, :helptext=>"Open an existing file") add(:image=>Tk::BWidget::Bitmap.new('save'), :highlightthickness=>0, :takefocus=>0, :relief=>:link, :borderwidth=>1, :padx=>1, :pady=>1, :command=>proc{puts 'select "Save file" icon'}, :helptext=>"Save file") pack(:side=>:left, :anchor=>:w) } Tk::BWidget::Separator.new(tb1, :orient=>:vertical){ pack(:side=>:left, :fill=>:y, :padx=>4, :anchor=>:w) } DemoVar.prgindic.numeric += 1 Tk::BWidget::ButtonBox.new(tb1, :spacing=>0, :padx=>1, :pady=>1){|bbox| add(:image=>Tk::BWidget::Bitmap.new('cut'), :highlightthickness=>0, :takefocus=>0, :relief=>:link, :borderwidth=>1, :padx=>1, :pady=>1, :command=>proc{puts 'select "Cut selection" icon'}, :helptext=>"Cut selection") add(:image=>Tk::BWidget::Bitmap.new('copy'), :highlightthickness=>0, :takefocus=>0, :relief=>:link, :borderwidth=>1, :padx=>1, :pady=>1, :command=>proc{puts 'select "Copy selection" icon'}, :helptext=>"Copy selection") add(:image=>Tk::BWidget::Bitmap.new('paste'), :highlightthickness=>0, :takefocus=>0, :relief=>:link, :borderwidth=>1, :padx=>1, :pady=>1, :command=>proc{puts 'select "Paste selection" icon'}, :helptext=>"Paste selection") pack(:side=>:left, :anchor=>:w) } } # toolbar 2 creation DemoVar.prgindic.numeric += 1 tb2 = DemoVar.mainframe.add_toolbar DemoVar._wfont = Tk::BWidget::SelectFont::Toolbar.new(tb2, :command=>proc{update_font(DemoVar._wfont[:font])} ) DemoVar.font = DemoVar._wfont[:font] DemoVar._wfont.pack(:side=>:left, :anchor=>:w) DemoVar.mainframe.add_indicator( :text=>"BWidget #{Tk::BWidget.package_version}" ) DemoVar.mainframe.add_indicator(:textvariable=>'tk_patchLevel') # NoteBook creation DemoVar.notebook = Tk::BWidget::NoteBook.new(DemoVar.mainframe.get_frame) DemoVar.prgtext.value = "Creating Manager..." DemoVar.prgindic.numeric += 1 DemoManager.create(DemoVar.notebook) DemoVar.prgtext.value = "Creating Basic..." DemoVar.prgindic.numeric += 1 DemoBasic.create(DemoVar.notebook) DemoVar.prgtext.value = "Creating Select..." DemoVar.prgindic.numeric += 1 DemoSelect.create(DemoVar.notebook) DemoVar.prgtext.value = "Creating Dialog..." DemoVar.prgindic.numeric += 1 DemoDialog.create(DemoVar.notebook) DemoVar.prgtext.value = "Creating Drag and Drop..." DemoVar.prgindic.numeric += 1 DemoDnD.create(DemoVar.notebook) DemoVar.prgtext.value = "Creating Tree..." DemoVar.prgindic.numeric += 1 DemoTree.create(DemoVar.notebook) DemoVar.prgtext.value = "Done" DemoVar.prgindic.numeric += 1 DemoVar.notebook.compute_size DemoVar.notebook.pack(:fill=>:both, :expand=>true, :padx=>4, :pady=>4) DemoVar.notebook.raise(DemoVar.notebook.get_page(0)) DemoVar.mainframe.pack(:fill=>:both, :expand=>true) Tk.update_idletasks intro.destroy end def update_font(newfont) root = Tk.root root[:cursor] = 'watch' if newfont != '' && DemoVar.font != newfont DemoVar._wfont[:font] = newfont DemoVar.notebook[:font] = newfont DemoVar.font = newfont end root[:cursor] = '' end def _create_intro top = TkToplevel.new(:relief=>:raised, :borderwidth=>2) top.withdraw top.overrideredirect(true) ximg = TkLabel.new(top, :bitmap=>"@#{File.join(DEMODIR,'x1.xbm')}", :foreground=>'grey90', :background=>'white') bwimg = TkLabel.new(ximg, :bitmap=>"@#{File.join(DEMODIR,'bwidget.xbm')}", :foreground=>'grey90', :background=>'white') frame = TkFrame.new(ximg, :background=>'white') TkLabel.new(frame, :text=>'Loading demo', :background=>'white', :font=>'times 8').pack TkLabel.new(frame, :textvariable=>DemoVar.prgtext, :background=>'white', :font=>'times 8', :width=>35).pack Tk::BWidget::ProgressBar.new(frame, :width=>50, :height=>10, :background=>'white', :variable=>DemoVar.prgindic, :maximum=>10).pack frame.place(:x=>0, :y=>0, :anchor=>:nw) bwimg.place(:relx=>1, :rely=>1, :anchor=>:se) ximg.pack Tk::BWidget.place(top, 0, 0, :center) top.deiconify top end end module DemoVar Demo = BWidget_Demo.new end Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/bwidget/dnd.rb ================================================ # # dnd demo --- called from demo.rb # unless Object.const_defined?('DemoVar') fail RuntimeError, "This is NOT a stand alone script. This script is called from 'demo.rb'. " end module DemoDnD def self.create(nb) frame = nb.insert('end', 'demoDnD', :text=>'Drag and Drop') titf1 = Tk::BWidget::TitleFrame.new(frame, :text=>'Drag source') subf = titf1.get_frame ent1 = Tk::BWidget::LabelEntry.new(subf, :label=>'Entry', :labelwidth=>14, :dragenabled=>true, :dragevent=>3) labf1 = Tk::BWidget::LabelFrame.new(subf, :text=>'Label (text)', :width=>14) f = labf1.get_frame lab = Tk::BWidget::Label.new(f, :text=>'Drag this text', :dragenabled=>true, :dragevent=>3).pack labf2 = Tk::BWidget::LabelFrame.new(subf, :text=>'Label (bitmap)', :width=>14) f = labf2.get_frame lab = Tk::BWidget::Label.new(f, :bitmap=>'info', :dragenabled=>true, :dragevent=>3).pack Tk.pack(ent1, labf1, labf2, :side=>:top, :fill=>:x, :pady=>4) titf2 = Tk::BWidget::TitleFrame.new(frame, :text=>'Drop targets') subf = titf2.get_frame ent1 = Tk::BWidget::LabelEntry.new(subf, :label=>'Entry', :labelwidth=>14, :dropenabled=>true) labf1 = Tk::BWidget::LabelFrame.new(subf, :text=>'Label', :width=>14) f = labf1.get_frame lab = Tk::BWidget::Label.new(f, :dropenabled=>true, :highlightthickness=>1).pack(:fill=>:x) Tk.pack(ent1, labf1, :side=>:top, :fill=>:x, :pady=>4) Tk.pack(titf1, titf2, :pady=>4) frame end end ================================================ FILE: ext/tk/sample/tkextlib/bwidget/manager.rb ================================================ # # manager demo --- called from demo.rb # unless Object.const_defined?('DemoVar') fail RuntimeError, "This is NOT a stand alone script. This script is called from 'demo.rb'. " end module DemoManager @@progress = TkVariable.new(false) @@status = TkVariable.new('Compute in progress...') @@homogeneous = TkVariable.new(false) @@constw = TkVariable.new @@afterobj = nil def self.create(nb) frame = nb.insert('end', 'demoManager', :text=>'Manager') topf = TkFrame.new(frame) titf1 = Tk::BWidget::TitleFrame.new(topf, :text=>"MainFrame") titf2 = Tk::BWidget::TitleFrame.new(topf, :text=>"NoteBook") titf3 = Tk::BWidget::TitleFrame.new(frame, :text=>"Paned & ScrolledWindow") _mainframe(titf1.get_frame) _notebook(titf2.get_frame) _paned(titf3.get_frame) Tk.pack(titf1, titf2, :padx=>4, :side=>:left, :fill=>:both, :expand=>true) Tk.pack(topf, :fill=>:x, :pady=>2) Tk.pack(titf3, :pady=>2, :padx=>4, :fill=>:both, :expand=>true) frame end def self._mainframe(parent) labf1 = Tk::BWidget::LabelFrame.new(parent, :text=>'Toolbar', :side=>:top, :anchor=>:w, :relief=>:sunken, :borderwidth=>2) subf = labf1.get_frame chk1 = TkCheckbutton.new(subf, :text=>'View toolbar 1', :variable=>DemoVar.toolbar1, :command=>proc{ DemoVar.mainframe.show_toolbar( 0, DemoVar.toolbar1.value ) }) chk2 = TkCheckbutton.new(subf, :text=>'View toolbar 2', :variable=>DemoVar.toolbar2, :command=>proc{ DemoVar.mainframe.show_toolbar( 1, DemoVar.toolbar2.value ) }) Tk.pack(chk1, chk2, :anchor=>:w, :fill=>:x) labf1.pack(:fill=>:both) labf2 = Tk::BWidget::LabelFrame.new(parent, :text=>'Status bar', :side=>:top, :anchor=>:w, :relief=>:sunken, :borderwidth=>2) subf = labf2.get_frame chk1 = TkCheckbutton.new(subf, :text=>"Show Progress\nindicator", :justify=>:left, :variable=>@@progress, :command=>proc{ _show_progress }) chk1.pack(:anchor=>:w, :fill=>:x) Tk.pack(labf1, labf2, :side=>:left, :padx=>4, :fill=>:both) end def self._notebook(parent) TkCheckbutton.new(parent, :text=>'Homogeneous label', :variable=>@@homogeneous, :command=>proc{ DemoVar.notebook[:homogeneous] = @@homogeneous.value }).pack(:side=>:left, :anchor=>:n, :fill=>:x) end def self._paned(parent) pw1 = Tk::BWidget::PanedWindow.new(parent, :side=>:top) pane = pw1.add(:minsize=>100) pw2 = Tk::BWidget::PanedWindow.new(pane, :side=>:left) pane1 = pw2.add(:minsize=>100) pane2 = pw2.add(:minsize=>100) pane3 = pw1.add(:minsize=>100) [pane1, pane2].each{|pane| sw = Tk::BWidget::ScrolledWindow.new(pane) lb = TkListbox.new(sw, :height=>8, :width=>20, :highlightthickness=>0) (1..8).each{|i| lb.insert('end', "Valur #{i}") } sw.set_widget(lb) sw.pack(:fill=>:both, :expand=>true) } sw = Tk::BWidget::ScrolledWindow.new(pane3, :relief=>:sunken, :borderwidth=>2) sf = Tk::BWidget::ScrollableFrame.new(sw) sw.set_widget(sf) subf = sf.get_frame lab = TkLabel.new(subf, :text=>'This is a ScrollableFrame') chk = TkCheckbutton.new(subf, :text=>'Constrained with', :variable=>@@constw, :command=>proc{ sf['constrainedwidth'] = @@constw.value }) lab.pack chk.pack(:anchor=>:w) chk.bind('FocusIn', proc{sf.see(chk)}) (0..20).each{|i| ent = TkEntry.new(subf, :width=>50).pack(:fill=>:x, :pady=>4) ent.bind('FocusIn', proc{sf.see(ent)}) ent.insert('end', "Text field #{i}") } Tk.pack(sw, pw2, pw1, :fill=>:both, :expand=>true) end def self._show_progress unless @@afterobj @@afterobj = TkTimer.new(30, -1, proc{_update_progress}) end if @@progress.bool DemoVar.status.value = 'Compute in progress...' DemoVar.prgindic.value = 0 DemoVar.mainframe.show_statusbar(:progression) @@afterobj.start unless @@afterobj.running? else DemoVar.status.value = '' DemoVar.mainframe.show_statusbar(:status) @@afterobj.stop end end def self._update_progress if @@progress.bool if DemoVar.prgindic.numeric < 100 DemoVar.prgindic.numeric += 5 else @@progress.value = false DemoVar.mainframe.show_statusbar(:status) DemoVar.status.value = 'Done' @@afterobj.stop Tk.after(500, proc{ DemoVar.status.value = '' }) end else @@afterobj.stop end end end ================================================ FILE: ext/tk/sample/tkextlib/bwidget/select.rb ================================================ # # select demo --- called from demo.rb # unless Object.const_defined?('DemoVar') fail RuntimeError, "This is NOT a stand alone script. This script is called from 'demo.rb'. " end module DemoSelect @@var = TkVariable.new_hash def self.create(nb) frame = nb.insert('end', 'demoSelect', :text=>'Spin & Combo') titf1 = Tk::BWidget::TitleFrame.new(frame, :text=>'SpinBox') subf = titf1.get_frame spin = Tk::BWidget::SpinBox.new(subf, :range=>[1, 100, 1], :textvariable=>@@var.ref('spin', 'var'), :helptext=>'This is the SpinBox') ent = Tk::BWidget::LabelEntry.new(subf, :label=>'Linked var', :labelwidth=>10, :labelanchor=>:w, :textvariable=>@@var.ref('spin', 'var'), :editable=>0, :helptext=>"This is an Entry reflecting\nthe linked var of SpinBox") labf = Tk::BWidget::LabelFrame.new(subf, :text=>'Options', :side=>:top, :anchor=>:w, :relief=>:sunken, :borderwidth=>1, :helptext=>'Modify some options of SpinBox') subf = labf.get_frame chk1 = TkCheckbutton.new(subf, :text=>'Non editable', :variable=>@@var.ref('spin', 'editable'), :onvalue=>false, :offvalue=>true, :command=>proc{ spin.editable(@@var['spin', 'editable']) }) chk2 = TkCheckbutton.new(subf, :text=>'Disabled', :variable=>@@var.ref('spin', 'state'), :onvalue=>'disabled', :offvalue=>'normal', :command=>proc{ spin.state(@@var['spin', 'state']) }) Tk.pack(chk1, chk2, :side=>:left, :anchor=>:w) Tk.pack(spin, ent, labf, :pady=>4, :fill=>:x) titf1.pack titf2 = Tk::BWidget::TitleFrame.new(frame, :text=>'ComboBox') subf = titf2.get_frame combo = Tk::BWidget::ComboBox.new(subf, :textvariable=>@@var.ref('combo', 'var'), :values=>[ 'first value', 'second value', 'third value', 'fourth value', 'fifth value' ], :helptext=>'This is the ComboBox') ent = Tk::BWidget::LabelEntry.new(subf, :label=>'Linked var', :labelwidth=>10, :labelanchor=>:w, :textvariable=>@@var.ref('combo', 'var'), :editable=>0, :helptext=>"This is an Entry reflecting\nthe linked var of ComboBox") labf = Tk::BWidget::LabelFrame.new(subf, :text=>'Options', :side=>:top, :anchor=>:w, :relief=>:sunken, :borderwidth=>1, :helptext=>'Modify some options of ComboBox') subf = labf.get_frame chk1 = TkCheckbutton.new(subf, :text=>'Non editable', :variable=>@@var.ref('combo', 'editable'), :onvalue=>false, :offvalue=>true, :command=>proc{ combo.editable(@@var['combo', 'editable']) }) chk2 = TkCheckbutton.new(subf, :text=>'Disabled', :variable=>@@var.ref('combo', 'state'), :onvalue=>'disabled', :offvalue=>'normal', :command=>proc{ combo.state(@@var['combo', 'state']) }) Tk.pack(chk1, chk2, :side=>:left, :anchor=>:w) Tk.pack(combo, ent, labf, :pady=>4, :fill=>:x) Tk.pack(titf1, titf2, :pady=>4) frame end end ================================================ FILE: ext/tk/sample/tkextlib/bwidget/tmpldlg.rb ================================================ # # templdlg demo --- called from demo.rb # unless Object.const_defined?('DemoVar') fail RuntimeError, "This is NOT a stand alone script. This script is called from 'demo.rb'. " end module DemoDialog @@tmpl = TkVariable.new_hash @@msg = TkVariable.new_hash @@msgdlg = nil @@progmsg = TkVariable.new @@progval = TkVariable.new @@progdlg = nil @@resources = TkVariable.new('en') def self.create(nb) frame = nb.insert('end', 'demoDlg', :text=>'Dialog') titf1 = Tk::BWidget::TitleFrame.new(frame, :text=>'Resources') titf2 = Tk::BWidget::TitleFrame.new(frame, :text=>'Template Dialog') titf3 = Tk::BWidget::TitleFrame.new(frame, :text=>'Message Dialog') titf4 = Tk::BWidget::TitleFrame.new(frame, :text=>'Other dialog') subf = titf1.get_frame cmd = proc{ TkOption.read_file(File.join(Tk::BWidget::LIBRARY, 'lang', @@resources.value + '.rc')) } Tk.pack(TkRadiobutton.new(subf, :text=>'English', :value=>'en', :variable=>@@resources, :command=>cmd), TkRadiobutton.new(subf, :text=>'French', :value=>'fr', :variable=>@@resources, :command=>cmd), TkRadiobutton.new(subf, :text=>'German', :value=>'de', :variable=>@@resources, :command=>cmd), :side=>:left) _tmpldlg(titf2.get_frame) _msgdlg(titf3.get_frame) _stddlg(titf4.get_frame) titf1.pack(:fill=>:x, :pady=>2, :padx=>2) titf4.pack(:side=>:bottom, :fill=>:x, :pady=>2, :padx=>2) Tk.pack(titf2, titf3, :side=>:left, :padx=>2, :fill=>:both, :expand=>true) end def self._tmpldlg(parent) @@tmpl['side'] = :bottom @@tmpl['anchor'] = :c labf1 = Tk::BWidget::LabelFrame.new(parent, :text=>'Button side', :side=>:top, :anchor=>:w, :relief=>:sunken, :borderwidth=>1) subf = labf1.get_frame Tk.pack(TkRadiobutton.new(subf, :text=>'Bottom', :value=>:bottom, :variable=>@@tmpl.ref('side'), :anchor=>:w), TkRadiobutton.new(subf, :text=>'Left', :value=>:left, :variable=>@@tmpl.ref('side'), :anchor=>:w), TkRadiobutton.new(subf, :text=>'Right', :value=>:right, :variable=>@@tmpl.ref('side'), :anchor=>:w), TkRadiobutton.new(subf, :text=>'Top', :value=>:top, :variable=>@@tmpl.ref('side'), :anchor=>:w), :fill=>:x, :anchor=>:w) labf2 = Tk::BWidget::LabelFrame.new(parent, :text=>'Button anchor', :side=>:top, :anchor=>:w, :relief=>:sunken, :borderwidth=>1) subf = labf2.get_frame Tk.pack(TkRadiobutton.new(subf, :text=>'North', :value=>:n, :variable=>@@tmpl.ref('anchor'), :anchor=>:w), TkRadiobutton.new(subf, :text=>'West', :value=>:w, :variable=>@@tmpl.ref('anchor'), :anchor=>:w), TkRadiobutton.new(subf, :text=>'East', :value=>:e, :variable=>@@tmpl.ref('anchor'), :anchor=>:w), TkRadiobutton.new(subf, :text=>'South', :value=>:s, :variable=>@@tmpl.ref('anchor'), :anchor=>:w), TkRadiobutton.new(subf, :text=>'Center', :value=>:c, :variable=>@@tmpl.ref('anchor'), :anchor=>:w), :fill=>:x, :anchor=>:w) sep = Tk::BWidget::Separator.new(parent, :orient=>:horizontal) button = TkButton.new(parent, :text=>'Show', :command=>proc{_show_tmpldlg}) button.pack(:side=>:bottom) sep.pack(:side=>:bottom, :fill=>:x, :pady=>10) Tk.pack(labf1, labf2, :side=>:left, :padx=>4, :anchor=>:n) end def self._msgdlg(parent) @@msg['type'] = 'ok' @@msg['icon'] = 'info' labf1 = Tk::BWidget::LabelFrame.new(parent, :text=>'Type', :side=>:top, :anchor=>:w, :relief=>:sunken, :borderwidth=>1) subf = labf1.get_frame Tk.pack(TkRadiobutton.new(subf, :text=>'Ok', :value=>'ok', :variable=>@@msg.ref('type'), :anchor=>:w), TkRadiobutton.new(subf, :text=>'Ok, Cancel', :value=>'okcancel', :variable=>@@msg.ref('type'), :anchor=>:w), TkRadiobutton.new(subf, :text=>'Retry, Cancel', :value=>'retrycancel', :variable=>@@msg.ref('type'), :anchor=>:w), TkRadiobutton.new(subf, :text=>'Yes, No', :value=>'yesno', :variable=>@@msg.ref('type'), :anchor=>:w), TkRadiobutton.new(subf, :text=>'Yes, No, Cancel', :value=>'yesnocancel', :variable=>@@msg.ref('type'), :anchor=>:w), TkRadiobutton.new(subf, :text=>'Abort, Retry, Ignore', :value=>'abortretryignore', :variable=>@@msg.ref('type'), :anchor=>:w), :fill=>:x, :anchor=>:w) Tk.pack(TkRadiobutton.new(subf, :text=>'User', :value=>'user', :variable=>@@msg.ref('type'), :anchor=>:w), Tk::BWidget::Entry.new(subf, :textvariable=>@@msg.ref('buttons')), :side=>:left) labf2 = Tk::BWidget::LabelFrame.new(parent, :text=>'Icon', :side=>:top, :anchor=>:w, :relief=>:sunken, :borderwidth=>1) subf = labf2.get_frame Tk.pack(TkRadiobutton.new(subf, :text=>'Information', :value=>'info', :variable=>@@msg.ref('icon'), :anchor=>:w), TkRadiobutton.new(subf, :text=>'Question', :value=>'question', :variable=>@@msg.ref('icon'), :anchor=>:w), TkRadiobutton.new(subf, :text=>'Warning', :value=>'warning', :variable=>@@msg.ref('icon'), :anchor=>:w), TkRadiobutton.new(subf, :text=>'Error', :value=>'error', :variable=>@@msg.ref('icon'), :anchor=>:w), :fill=>:x, :anchor=>:w) sep = Tk::BWidget::Separator.new(parent, :orient=>:horizontal) button = TkButton.new(parent, :text=>'Show', :command=>proc{_show_msgdlg}) button.pack(:side=>:bottom) sep.pack(:side=>:bottom, :fill=>:x, :pady=>10) Tk.pack(labf1, labf2, :side=>:left, :padx=>4, :anchor=>:n) end def self._stddlg(parent) Tk.pack(TkButton.new(parent, :text=>'Select a color '){|w| command(proc{DemoDialog._show_color(w)}) }, TkButton.new(parent, :text=>'Font selector dialog', :command=>proc{_show_fontdlg}), TkButton.new(parent, :text=>'Progression dialog', :command=>proc{_show_progdlg}), TkButton.new(parent, :text=>'Password dialog', :command=>proc{_show_passdlg}), :side=>:left, :padx=>5, :anchor=>:w) end def self._show_color(w) dlg = Tk::BWidget::SelectColor.new(w, :color=>w.background) color = dlg.menu([:below, w]) unless color.empty? w.background(color) end end def self._show_tmpldlg dlg = Tk::BWidget::Dialog.new(:relative=>Tk.root, :modal=>:local, :separator=>true, :title=>'Template dialog', :side=>@@tmpl['side'], :anchor=>@@tmpl['anchor'], :default=>0, :cancel=>1) dlg.add('name'=>'ok') dlg.add('name'=>'cancel') TkMessage.new(dlg.get_frame, :text=>"Template\nDialog", :justify=>:center, :anchor=>:c, :width=>80).pack(:fill=>:both, :expand=>true, :padx=>100, :pady=>100) dlg.draw dlg.destroy end def self._show_msgdlg @@msgdlg.destroy if @@msgdlg @@msgdlg = Tk::BWidget::MessageDlg.new(:relative=>Tk.root, :message=>'Message for MessageBox', :type=>@@msg['type'], :icon=>@@msg['icon'], :buttons=>@@msg['buttons']) @@msgdlg.create end def self._show_fontdlg font = Tk::BWidget::SelectFont.new(:relative=>Tk.root, :font=>DemoVar.font).create DemoVar::Demo.update_font(font) end def self._show_progdlg @@progmsg.value = "Compute in progress..." @@progval.value = 0 @@progdlg = Tk::BWidget::ProgressDlg.new(:relative=>Tk.root, :title=>'Wait...', :type=>'infinite', :width=>20, :textvariable=>@@progmsg, :variable=>@@progval, :stop=>'Stop') { command(proc{self.destroy}) create } _update_progdlg end def self._update_progdlg TkTimer.new(20, -1, proc{ if @@progdlg && @@progdlg.winfo_exist? @@progval.value = 2 else stop end }).start end def self._show_passdlg Tk::BWidget::PasswdDlg.new(:relative=>Tk.root).create end end ================================================ FILE: ext/tk/sample/tkextlib/bwidget/tree.rb ================================================ # # templdlg demo --- called from demo.rb # unless Object.const_defined?('DemoVar') fail RuntimeError, "This is NOT a stand alone script. This script is called from 'demo.rb'. " end module DemoTree @@count = 0 @@dblclick = false @@top = nil def self.create(nb) frame = nb.insert('end', 'demoTree', :text=>'Tree') pw = Tk::BWidget::PanedWindow.new(frame, :side=>:top) pane = pw.add(:weight=>1) title = Tk::BWidget::TitleFrame.new(pane, :text=>'Directory tree') sw = Tk::BWidget::ScrolledWindow.new(title.get_frame, :relief=>:sunken, :borderwidth=>2) tree = Tk::BWidget::Tree.new(sw, :relief=>:flat, :borderwidth=>0, :width=>15, :highlightthickness=>0, :redraw=>false, :dropenabled=>true, :dragenabled=>true, :dragevent=>3, :droptypes=>[ 'TREE_NODE', [ :copy, [], :move, [], :link, [] ], 'LISTBOX_ITEM', [ :copy, [], :move, [], :link, [] ] ], :opencmd=>proc{|node| moddir(1, tree, node) }, :closecmd=>proc{|node| moddir(0, tree, node) }) sw.set_widget(tree) sw.pack(:side=>:top, :expand=>true, :fill=>:both) title.pack(:fill=>:both, :expand=>true) pane = pw.add(:weight=>2) lf = Tk::BWidget::TitleFrame.new(pane, :text=>'Content') sw = Tk::BWidget::ScrolledWindow.new(lf.get_frame, :scrollbar=>:horizontal, :auto=>:none, :relief=>:sunken, :borderwidth=>2) list = Tk::BWidget::ListBox.new(sw, :relief=>:flat, :borderwidth=>0, :highlightthickness=>0, :width=>20, :multicolumn=>true, :redraw=>false, :dragevent=>3, :dropenabled=>true, :dragenabled=>true, :droptypes=>[ 'TREE_NODE', [ :copy, [], :move, [], :link, [] ], 'LISTBOX_ITEM', [ :copy, [], :move, [], :link, [] ] ]) sw.set_widget(list) Tk.pack(sw, lf, :fill=>:both, :expand=>true) pw.pack(:fill=>:both, :expand=>true) tree.textbind('ButtonPress-1', proc{|node, ev| select('tree', 1, tree, list, node)}) tree.textbind('Double-ButtonPress-1', proc{|node, ev| select('tree', 2, tree, list, node)}) list.textbind('ButtonPress-1', proc{|node, ev| select('list', 1, tree, list, node)}) list.textbind('Double-ButtonPress-1', proc{|node, ev| select('list', 2, tree, list, node)}) list.imagebind('Double-ButtonPress-1', proc{|node, ev| select('list', 2, tree, list, node)}) nb.itemconfigure('demoTree', :createcmd=>proc{|*args| init(tree, list, *args)}, :raisecmd=>proc{ Tk.root.geometry =~ /\d+x\d+([+-]{1,2}\d+)([+-]{1,2}\d+)/ global_w = ($1 || 0).to_i global_h = ($2 || 0).to_i if @@top Tk::BWidget.place(@@top, 0, 0, :at, global_w - Tk.root.winfo_screenwidth, global_h) @@top.deiconify Tk.root.bind('Unmap', proc{@@top.withdraw}) Tk.root.bind('Map', proc{@@top.deiconify}) Tk.root.bind('Configure', proc{|w| if w == Tk.root Tk.root.geometry =~ /\d+x\d+([+-]{1,2}\d+)([+-]{1,2}\d+)/ global_w = ($1 || 0).to_i global_h = ($2 || 0).to_i Tk::BWidget.place(@@top, 0, 0, :at, global_w - Tk.root.winfo_screenwidth, global_h) end }, '%W') end }, :leavecmd=>proc{ @@top.withdraw if @@top Tk.root.bind_remove('Unmap') Tk.root.bind_remove('Map') Tk.root.bind_remove('Configure') true }) end def self.init(tree, list, *args) @@count = 0 if Tk::PLATFORM['platform'] == 'unix' rootdir = File.expand_path('~') else rootdir = 'c:' end tree.insert('end', 'root', 'home', :text=>rootdir, :data=>rootdir, :open=>true, :image=>Tk::BWidget::Bitmap.new('openfold')) getdir(tree, 'home', rootdir) select('tree', 1, tree, list, 'home') tree.redraw(true) list.redraw(true) @@top = TkToplevel.new @@top.withdraw @@top.protocol('WM_DELETE_WINDOW'){ # don't kill me } @@top.resizable(false, false) @@top.title('Drag rectangle to scroll directory tree') @@top.transient(Tk.root) Tk::BWidget::ScrollView.new(@@top, :window=>tree, :fill=>'white', :width=>300, :height=>300, :relief=>:sunken, :bd=>1).pack(:fill=>:both, :expand=>true) end def self.getdir(tree, node, path) lentries = Dir.glob(File.join(path, '*')).sort lfiles = [] lentries.each{|f| basename = File.basename(f) if File.directory?(f) Tk::BWidget::Tree::Node.new(tree, node, :index=>'end', :text=>basename, :image=>Tk::BWidget::Bitmap.new('folder'), :drawcross=>:allways, :data=>f) @@count += 1 else lfiles << basename end } tree.itemconfigure(node, :drawcross=>:auto, :data=>lfiles) end def self.moddir(idx, tree, node) if (idx != 0 && tree.itemcget(node, :drawcross).to_s == 'allways') getdir(tree, node, tree.itemcget(node, :data)) if tree.nodes(node).empty? tree.itemconfigure(node, :image=>Tk::BWidget::Bitmap.new('folder')) else tree.itemconfigure(node, :image=>Tk::BWidget::Bitmap.new('openfold')) end else img = %w(folder openfold)[idx] || 'openfold' tree.itemconfigure(node, :image=>Tk::BWidget::Bitmap.new(img)) end end def self.select(where, num, tree, list, node) @@dblclick = true if num == 1 if (where == 'tree' && tree.selection_get.find{|x| TkUtil._get_eval_string(x) == TkUtil._get_eval_string(node) }) @@dblclick = false Tk.after(500, proc{edit('tree', tree, list, node)}) return end if (where == 'list' && list.selection_get.find{|x| TkUtil._get_eval_string(x) == TkUtil._get_eval_string(node) }) @@dblclick = false Tk.after(500, proc{edit('list', tree, list, node)}) return end if where == 'tree' select_node(tree, list, node) else list.selection_set(node) end elsif (where == 'list' && tree.exist?(node)) parent = tree.parent(node) while TkUtil._get_eval_string(parent) != 'root' tree.itemconfigure(parent, :open=>true) parent = tree.parent(parent) end select_node(tree, list, node) end end def self.select_node(tree, list, node) tree.selection_set(node) Tk.update list.delete(*(list.items(0, 'end'))) dir = tree.itemcget(node, :data) if tree.itemcget(node, :drawcross).to_s == 'allways' getdir(tree, node, dir) dir = tree.itemcget(node, :data) end tree.nodes(node).each{|subnode| list.insert('end', subnode, :text=>tree.itemcget(subnode, :text), :image=>Tk::BWidget::Bitmap.new('folder')) } TkComm.simplelist(dir).each{|f| Tk::BWidget::ListBox::Item.new(list, 'end', :text=>f, :image=>Tk::BWidget::Bitmap.new('file')) } end def self.edit(where, tree, list, node) return if @@dblclick if (where == 'tree' && tree.selection_get.find{|x| TkUtil._get_eval_string(x) == TkUtil._get_eval_string(node) }) res = tree.edit(node, tree.itemcget(node, :text)) if res != '' tree.itemconfigure(node, :text=>res) if list.exist?(node) list.itemconfigure(node, :text=>res) end tree.selection_set(node) end return end if (where == 'list') res = list.edit(node, list.igemcget(node, :text)) if res != '' list.itemconfigure(node, :text=>res) if tree.exist?(node) tree.itemconfigure(node, :text=>res) else cursel = tree.selection_get[0] index = list.index(node) - tree.nodes(cursel).size data = TkComm.simplelist(tree.itemcget(cursel, :data)) data[index] = res tree.itemconfigure(cursel, :date=>data) end list.selection_set(node) end end end def self.expand(tree, but) unless (cur = tree.selection_get).empty? if TkComm.bool(but) tree.opentree(cur) else tree.closetree(cur) end end end end ================================================ FILE: ext/tk/sample/tkextlib/bwidget/x1.xbm ================================================ #define x1_width 626 #define x1_height 428 static char x1_bits[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0x03,0x80,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0xe0,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00, 0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00, 0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x80,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00, 0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00, 0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0x0f, 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff, 0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00, 0x80,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff, 0xff,0x03,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff, 0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00, 0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00, 0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff, 0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00, 0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x03,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff, 0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0xfc,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00, 0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff, 0xff,0x3f,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff, 0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xfc, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01, 0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x03,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0xfc,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xe0,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00, 0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x1f,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0xfc,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xc0,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00, 0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x1f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x0f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfe,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0xfc,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x80,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03, 0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0x03,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x07,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0x01,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0xfc,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0xfc, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x1f,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0x7f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0x3f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0xfc,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xf0,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00, 0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0x0f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0x07, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0xfc,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xe0,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03, 0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x03,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0x03,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0xfc,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff, 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0xfc,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x80,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x0f,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x0f,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0x7f,0x00,0x00,0x00, 0x00,0xf8,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0xfc,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff, 0x7f,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0xfc, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfe,0xff,0xff,0x3f,0x00,0x00,0x00,0xc0,0xff,0xff,0x03,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x3f,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0xe0,0xff,0xff, 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0x1f,0x00,0x00, 0x00,0xf0,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0xfc,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff, 0xff,0x1f,0x00,0x00,0x00,0xfc,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00, 0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xf0,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0xfe,0xff,0xff,0x3f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0xfe,0xff, 0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0x0f,0x00, 0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0xfc,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff, 0xff,0xff,0x07,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x01,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xc0,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0x01, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x03,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0xe0,0xff, 0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00, 0xf8,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0xfc,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0x03, 0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01, 0x00,0x00,0x00,0x00,0xfe,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0xfc,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff, 0xff,0xff,0xff,0x01,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x80,0xff,0x07,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x07,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0xf0,0xff,0xff,0xff,0xff, 0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xc0,0xff,0x07,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x07,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0xf8, 0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00, 0xe0,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xfc,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0x3f, 0x00,0x00,0x00,0x00,0xf8,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xfc, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff, 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0x3f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff, 0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0xfc,0xff,0x0f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x0f,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xfc,0xff,0xff,0xff, 0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x80,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0xfe,0xff,0x0f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00, 0xfe,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00, 0x00,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0xfc,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff, 0x7f,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff, 0x07,0x00,0x00,0x00,0x80,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f, 0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff, 0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff, 0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0xc0,0xff,0xff,0x1f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x1f,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0xff,0xff,0xff, 0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0xe0,0xff,0xff, 0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xfc,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00, 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00, 0x00,0xf0,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xfc,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff, 0xff,0x3f,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff, 0xff,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x3f,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8, 0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff, 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0x1f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x7f,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x80,0xff,0xff, 0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0xfe,0xff, 0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xfc,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00, 0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0x3f,0x00,0x00, 0x00,0x00,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xfc,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff, 0xff,0xff,0x1f,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff, 0xff,0x1f,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x7f,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff, 0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xf0,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0x1f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0xe0,0xff, 0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0xe0,0xff, 0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f, 0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0x07,0x00, 0x00,0x00,0xe0,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff, 0xff,0xff,0xff,0x0f,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff, 0xff,0xff,0x03,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0xe0,0xff,0xff,0xff,0xff, 0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xe0,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0x1f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0xf0, 0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xfc, 0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x07,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0x00, 0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xfd,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x07,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x1f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff, 0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xfd,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0xf0,0xff,0xff,0xff, 0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x80,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff, 0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00, 0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x80, 0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x07,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0x1f, 0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xfd,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff, 0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0x7f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0xf8,0xff,0xff, 0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0xf0,0xff,0xff,0xff, 0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00, 0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x07,0x00,0x00,0x00, 0xf8,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x03,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff, 0x03,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfe,0xff,0xff,0x01,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0xfc,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x01,0x00,0x00,0x00,0xfe,0xff,0xff, 0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03, 0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0x00,0x00,0x00, 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x03,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff, 0x7f,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0xfc,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfc,0xff,0x7f,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff, 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0xfc, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0x3f,0x00,0x00,0x00,0xc0,0xff,0xff, 0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x03,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0x1f,0x00,0x00, 0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x03,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0, 0xff,0x1f,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00, 0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0xfc,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xf0,0xff,0x0f,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff, 0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00, 0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0x07,0x00,0x00,0x00,0xf8,0xff, 0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x03,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0x07,0x00, 0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00, 0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xe0,0xff,0x03,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00, 0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0xfe,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xe0,0xff,0x01,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff, 0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00, 0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0x01,0x00,0x00,0x00,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x07,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0x00, 0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00, 0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x80,0x7f,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x03,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0xfe,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x80,0x7f,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07, 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0xe0, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x80,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x0f,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f, 0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00, 0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x80,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x07,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x80,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0xf8,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x1f,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x00, 0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x3f,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x06,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0xf0,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00, 0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0xfc, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00, 0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00, 0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00, 0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x00,0x00,0x00,0x00, 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd, 0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xfd,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x00,0x00,0x00,0x00,0x00,0xc0,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x00,0x00,0x00, 0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xfd,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0xf8, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x00,0x00, 0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xfc,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xfc,0x00, 0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x7f,0xfc,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x7f,0xfc,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xfc,0x00,0x00,0x00,0x00, 0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xfc, 0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x3f,0xfc,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xfc,0x00,0x00,0x00,0x00,0xf8,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xfc,0x00,0x00,0x00, 0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f, 0xfc,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x1f,0xfc,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0xfc,0x00,0x00,0x00,0x00,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xfc,0x00,0x00, 0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x0f,0xfc,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x0f,0xfc,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0xfc,0x00,0x00,0x00,0xe0,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0xfc,0x00, 0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x07,0xfc,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x07,0xfc,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0xfc,0x00,0x00,0x00,0xf8, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0xfc, 0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x03,0xfc,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x01,0xfc,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0xfc,0x00,0x00,0x00, 0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00, 0xfc,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x00,0xfc,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xfc,0x00,0x00,0x80,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0xfc,0x00,0x00, 0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, 0x00,0xfc,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x3f,0x00,0xfc,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0xfc,0x00,0x00,0xe0,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0xfc,0x00, 0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x1f,0x00,0xfc,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x1f,0x00,0xfc,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0xfc,0x00,0x00,0xf8,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0xfc, 0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x0f,0x00,0xfc,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x07,0x00,0xfc,0x00,0x00,0xfe,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0xfc,0x00,0x00,0xfe, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00, 0xfc,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x03,0x00,0xfc,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0xfc,0x00,0x80,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0xfc,0x00,0x80, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00, 0x00,0xfc,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x00,0x00,0xfc,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0xfc,0x00,0xe0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0xfc,0x00, 0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f, 0x00,0x00,0xfc,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x3f,0x00,0x00,0xfc,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0xfc,0x00,0xf0,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0xfc, 0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x0f,0x00,0x00,0xfc,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x07,0x00,0x00,0xfc,0x00,0xf8,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0xfc,0x00,0xfc,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00, 0xfc,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x03,0x00,0x00,0xfc,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0xfc,0x00,0xfe,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0xfc,0x00,0xfe, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00, 0x00,0xfc,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x7f,0x00,0x00,0x00,0xfc,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0xfc,0x00,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0xfc,0x80, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00, 0x00,0x00,0xfc,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x1f,0x00,0x00,0x00,0xfc,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0xfc,0xc0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0xfc, 0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07, 0x00,0x00,0x00,0xfc,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x03,0x00,0x00,0x00,0xfc,0xc0,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0xfc,0xe0,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00, 0xfc,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x01,0x00,0x00,0x00,0xfc,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xfc,0xf0,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0xfc,0xf0,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00, 0x00,0xfc,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x3f,0x00,0x00,0x00,0x00,0xfc,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0xfc,0xf8,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0xfc,0xf8, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00, 0x00,0x00,0xfc,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x07,0x00,0x00,0x00,0x00,0xfc,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0xfc,0xf8,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0xfc, 0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00, 0x00,0x00,0x00,0xfc,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0xfc,0xfc,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0xfc,0xfc,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00, 0xfc,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00, 0x00,0x00,0x00,0x00,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0xfc,0xfe,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00, 0x00,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07, 0x00,0x00,0x00,0x00,0x00,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0xfc,0xfe,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0xfc,0xfe, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, 0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x7f,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0xfc,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x7f,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0xf8, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x03,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x0f,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0xe0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00, 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0xe0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x01,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00, 0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x03,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0xc0,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x07, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00, 0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00, 0x00,0x00,0x80,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0xc0,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x7f,0x00,0x00,0x00,0xc0,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01, 0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0xc0,0x0f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x01,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0xe0, 0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x80,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f, 0x00,0x00,0x00,0xf0,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x80,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0xf8,0x1f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0xfc,0x3f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00, 0xfc,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x80,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x01,0x00,0x00,0x00,0xfe,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x80, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0xff,0x7f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff, 0x7f,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x80,0xff,0x7f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff, 0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00, 0x80,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x80,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x3f,0x00,0x00,0x00,0xc0,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00, 0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0xe0,0xff,0xff,0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff, 0xff,0x7f,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0xf0,0xff,0xff, 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8, 0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00, 0x00,0xf8,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0xc0,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x07,0x00,0x00,0x00,0xf8,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0x3f,0x00, 0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0xfc,0xff,0xff,0x03,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff, 0xff,0xff,0x3f,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0xfe,0xff, 0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xf0,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00, 0x00,0x00,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0xc0,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff, 0xff,0x7f,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0x1f, 0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff, 0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0x0f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff, 0xff,0xff,0xff,0x1f,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0xc0,0xff, 0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0xe0,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00, 0x00,0x00,0xe0,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0xe0, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff, 0xff,0xff,0x0f,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff, 0x0f,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0, 0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0x1f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff, 0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xfe,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0xf8, 0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0xe0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x01, 0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0x07,0x00,0x00, 0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff, 0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0x3f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff, 0xff,0x07,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xf0,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, 0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xfc,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0xf0,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfc,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0x1f, 0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0x03,0x00, 0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfc,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff, 0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff, 0xff,0xff,0x03,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xfc,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0xe0,0xff,0xff,0xff, 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xe0,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff, 0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xfc, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00, 0xe0,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0xf8,0xff, 0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfc,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff, 0x03,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0x00, 0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff, 0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0x01, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff, 0xff,0xff,0xff,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xf8,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xfc,0xff,0xff, 0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff, 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00, 0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x3f,0x00,0x00,0x00,0xfc, 0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff, 0x3f,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0x3f, 0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xf0,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff, 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xf8,0xff,0xff,0x1f,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0x0f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xf0,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x80,0xff,0xff, 0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0x0f,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, 0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0x07,0x00,0x00, 0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0x07,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, 0xff,0x01,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff, 0x01,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xe0,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff, 0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfe,0x7f,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0x7f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xc0,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0xf8,0xff, 0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x1f,0x00,0x00,0x00,0x80,0xff,0xff,0xff, 0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfc,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x3f,0x00,0x00, 0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x80,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfc,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff, 0xff,0x1f,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x80,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x80,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff, 0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0x03, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x80, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff, 0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfc,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0x03,0x00, 0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff, 0xff,0xff,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xc0,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0x1f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0xf0, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff, 0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0x1f,0x00, 0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0xfe,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff, 0xff,0xff,0x07,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0xfc,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xe0,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0x7f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00, 0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0x7f,0x00, 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0xf8,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0x07,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0xf0, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xc0,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfc,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0x01,0x00,0x00,0x00,0x00, 0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x7f,0x00, 0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x80,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0xe0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfe,0x1f,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0x1f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00, 0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xf0,0x01,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff, 0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfc,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xc0,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x80,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0x7f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff, 0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xf8,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0xfe,0xff,0xff,0xff,0xff, 0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0xfc, 0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0x01,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff, 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0x1f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfe,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0xf0,0xff,0xff,0xff, 0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00, 0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0x07,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfc,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff, 0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff, 0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xc0,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0xc0,0xff,0xff, 0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00, 0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0x0f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfc,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8, 0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff, 0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xf8,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0xfe, 0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x7f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x1f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0xf0,0xff,0xff,0xff, 0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x80,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00, 0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x3f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff, 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xf0,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x80,0xff,0xff, 0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xf8,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00, 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfc,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff, 0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0xf8, 0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x80,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00, 0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0x7f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff, 0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00, 0x80,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff, 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0xf8,0xff, 0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00, 0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff, 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x80, 0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0x1f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff, 0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00, 0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00, 0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00, 0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00, 0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00, 0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff, 0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe, 0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x80,0x0f,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0xc0,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x80, 0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xfc}; ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/catalog_demo/Orig_LICENSE.txt ================================================ ####################################################################### ### The following text is the original 'license.terms' of iwidges ### ### extension. ### ### Original Tcl source files are not include in this directry, ### ### because of all of them are rewrited to Ruby files. ### ### However, the image data files in the 'images' directory are ### ### quoted from iwidgets source archive. ### ####################################################################### This software is copyrighted by DSC Technologies and private individual contributors. The copyright holder is specifically listed in the header of each file. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files by private contributors. Copyright 1997 DSC Technologies Corporation Permission to use, copy, modify, distribute and license this software and its documentation for any purpose, and without fee or written agreement with DSC, is hereby granted, provided that the above copyright notice appears in all copies and that both the copyright notice and warranty disclaimer below appear in supporting documentation, and that the names of DSC Technologies Corporation or DSC Communications Corporation not be used in advertising or publicity pertaining to the software without specific, written prior permission. DSC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. IN NO EVENT SHALL DSC BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. RESTRICTED RIGHTS: Use, duplication or disclosure by the government is subject to the restrictions as set forth in subparagraph (c) (1) (ii) of the Rights in Technical Data and Computer Software Clause as DFARS 252.227-7013 and FAR 52.227-19. ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/catalog_demo/images/box.xbm ================================================ #define Tool_32_box_width 32 #define Tool_32_box_height 32 static unsigned char Tool_32_box_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x0f, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0xe0, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/catalog_demo/images/line.xbm ================================================ #define lineOp_width 32 #define lineOp_height 32 static unsigned char lineOp_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/catalog_demo/images/oval.xbm ================================================ #define ovalOp_width 32 #define ovalOp_height 32 static unsigned char ovalOp_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x1c, 0x70, 0x00, 0x00, 0x03, 0x80, 0x01, 0x80, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x20, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x02, 0x00, 0x03, 0x80, 0x01, 0x00, 0x1c, 0x70, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/catalog_demo/images/points.xbm ================================================ #define dotPencilOp_width 32 #define dotPencilOp_height 32 static unsigned char dotPencilOp_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x24, 0x00, 0x18, 0x00, 0x24, 0x00, 0x18, 0x00, 0x12, 0x00, 0x00, 0x00, 0x12, 0x00, 0x30, 0x00, 0x0e, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x30, 0x00, 0x00, 0x0c, 0x30, 0x00, 0x30, 0xa0, 0x01, 0x00, 0x60, 0xb0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/catalog_demo/images/text.xbm ================================================ #define font_edit_width 32 #define font_edit_height 32 static unsigned char font_edit_bits[] = { 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x80, 0x7b, 0x00, 0x00, 0x80, 0x7e, 0x00, 0x00, 0xc0, 0xfd, 0x00, 0x00, 0x60, 0xfb, 0x00, 0x00, 0xb0, 0xf7, 0x00, 0x00, 0xd0, 0xef, 0x00, 0x00, 0xf8, 0xdf, 0x00, 0x00, 0xd4, 0x7f, 0x00, 0x00, 0xaa, 0x1f, 0x00, 0x00, 0x15, 0x0f, 0x00, 0x80, 0x82, 0x06, 0x03, 0x40, 0x01, 0x01, 0x07, 0xa0, 0x80, 0x00, 0x0f, 0x10, 0x40, 0x00, 0x1f, 0x08, 0x20, 0x00, 0x3b, 0xe4, 0x1f, 0x00, 0x73, 0x1a, 0x00, 0x00, 0xe3, 0x07, 0x00, 0x00, 0xc3, 0x01, 0x00, 0x00, 0xe3, 0x03, 0x00, 0x00, 0x7b, 0x07, 0x00, 0x00, 0x1f, 0x06, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/buttonbox.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' # sample 1 p bb1 = Tk::Iwidgets::Buttonbox.new p bb1.add('Yes', :text=>'Yes', :command=>proc{puts 'Yes'}) p bb1.add('No', :text=>'No', :command=>proc{puts 'No'}) p bb1.add('Maybe', :text=>'Maybe', :command=>proc{puts 'Maybe'}) bb1.default('Yes') bb1.pack(:expand=>true, :fill=>:both, :pady=>5) print "\n" # sample 2 p bb2 = Tk::Iwidgets::Buttonbox.new p btn1 = bb2.add(:text=>'Yes', :command=>proc{puts 'Yes'}) p btn2 = bb2.add(:text=>'No', :command=>proc{puts 'No'}) p btn3 = bb2.add(:text=>'Maybe', :command=>proc{puts 'Maybe'}) bb2.default(btn1) bb2.pack(:expand=>true, :fill=>:both, :pady=>5) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/calendar.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' Tk::Iwidgets::Calendar.new(:command=>proc{|arg| puts(arg.date)}, :weekendbackground=>'mistyrose', :weekdaybackground=>'ghostwhite', :outline=>'black', :startday=>'wednesday', :days=>%w(We Th Fr Sa Su Mo Tu)).pack Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/canvasprintbox.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' Tk::Iwidgets::Canvasprintbox.new(:orient=>:landscape, :stretch=>1) \ .pack(:padx=>10, :pady=>10, :fill=>:both, :expand=>true) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/canvasprintdialog.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' Tk::Iwidgets::Canvasprintdialog.new.activate Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/checkbox.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' cb = Tk::Iwidgets::Checkbox.new cb.add('bold', :text=>'Bold') cb.add('italic', :text=>'Italic') cb.add('underline', :text=>'Underline') cb.select('underline') cb.pack(:expand=>true, :fill=>:both, :padx=>10, :pady=>10) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/combobox.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' # # Non-editable Dropdown Combobox # cb1 = Tk::Iwidgets::Combobox.new(:labeltext=>'Month:', :selectioncommand=>proc{ puts(cb1.get_curselection) }, :editable=>false, :listheight=>185, :popupcursor=>'hand1') cb1.insert_list('end', *%w(Jan Feb Mar Apr May June Jul Aug Sept Oct Nov Dec)) # # Editable Dropdown Combobox # cb2 = Tk::Iwidgets::Combobox.new(:labeltext=>'Operating System:', :selectioncommand=>proc{ puts(cb2.get_curselection) }) cb2.insert_list('end', *%w(Linux HP-UX SunOS Solaris Irix)) cb2.insert_entry('end', 'L') cb1.pack(:padx=>10, :pady=>10, :fill=>:x) cb2.pack(:padx=>10, :pady=>10, :fill=>:x) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/dateentry.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' Tk::Iwidgets::Dateentry.new.pack Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/datefield.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' df = Tk::Iwidgets::Datefield.new(:command=>proc{puts(df.get)}) df.pack(:fill=>:x, :expand=>true, :padx=>10, :pady=>10) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/dialog.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' Thread.new{Tk.mainloop} d = Tk::Iwidgets::Dialog.new(:modality=>:application) d.buttonconfigure('OK', :command=>proc{puts 'OK'; d.deactivate true}) d.buttonconfigure('Apply', :command=>proc{puts 'Apply'}) d.buttonconfigure('Cancel', :command=>proc{puts 'Cancel'; d.deactivate false}) d.buttonconfigure('Help', :command=>proc{puts 'Help'}) TkListbox.new(d.child_site, :relief=>:sunken).pack(:expand=>true, :fill=>:both) if TkComm.bool(d.activate) puts "Exit via OK button" else puts "Exit via Cancel button" end ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/dialogshell.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' ds = Tk::Iwidgets::Dialogshell.new(:modality=>:none) ds.add('OK', :text=>'OK', :command=>proc{puts 'OK'; ds.deactivate}) ds.add('Cancel', :text=>'Cancel', :command=>proc{puts 'Cancel'; ds.deactivate}) ds.default('OK') TkButton.new(:text=>'ACTIVATE', :padx=>7, :pady=>7, :command=>proc{puts ds.activate}).pack(:padx=>10, :pady=>10) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/disjointlistbox.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' djl = Tk::Iwidgets::Disjointlistbox.new.pack(:fill=>:both, :expand=>true, :padx=>10, :pady=>10) djl.set_lhs(*[0,2,4,5]) djl.set_rhs(3,6) djl.insert_lhs(1,7,8) djl.insert_rhs(9) p djl.get_lhs p djl.get_rhs Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/entryfield-1.rb ================================================ #!/usr/bin/env ruby ######################################################### # # use Tk::UTF8_String() for a utf8 charecter # ######################################################### require 'tk' require 'tkextlib/iwidgets' TkOption.add('*textBackground', 'white') ef = Tk::Iwidgets::Entryfield.new(:command=>proc{puts "Return Pressed"}) fef = Tk::Iwidgets::Entryfield.new(:labeltext=>'Fixed:', :fixed=>10, :width=>12) nef = Tk::Iwidgets::Entryfield.new(:labeltext=>'Numeric:', :validate=>:numeric, :width=>12) aef = Tk::Iwidgets::Entryfield.new(:labeltext=>'Alphabetic:', :validate=>:alphabetic, :width=>12, :invalid=>proc{ puts "Alphabetic contents invalid" }) pef = Tk::Iwidgets::Entryfield.new(:labeltext=>'Password:', :width=>12, :show=>Tk::UTF8_String("\267"), ## <=== utf8 character :command=>proc{puts "Return Pressed"}) Tk::Iwidgets::Labeledwidget.alignlabels(ef, fef, nef, aef, pef) ef.pack(:fil=>:x, :expand=>true, :padx=>10, :pady=>5) fef.pack(:fil=>:x, :expand=>true, :padx=>10, :pady=>5) nef.pack(:fil=>:x, :expand=>true, :padx=>10, :pady=>5) aef.pack(:fil=>:x, :expand=>true, :padx=>10, :pady=>5) pef.pack(:fil=>:x, :expand=>true, :padx=>10, :pady=>5) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/entryfield-2.rb ================================================ #!/usr/bin/env ruby ######################################################### # # set $KCODE to 'utf' for a utf8 charecter # ######################################################### $KCODE='utf' require 'tk' require 'tkextlib/iwidgets' TkOption.add('*textBackground', 'white') ef = Tk::Iwidgets::Entryfield.new(:command=>proc{puts "Return Pressed"}) fef = Tk::Iwidgets::Entryfield.new(:labeltext=>'Fixed:', :fixed=>10, :width=>12) nef = Tk::Iwidgets::Entryfield.new(:labeltext=>'Numeric:', :validate=>:numeric, :width=>12) aef = Tk::Iwidgets::Entryfield.new(:labeltext=>'Alphabetic:', :validate=>:alphabetic, :width=>12, :invalid=>proc{ puts "Alphabetic contents invalid" }) pef = Tk::Iwidgets::Entryfield.new(:labeltext=>'Password:', :width=>12, :show=>"\267", ## <=== utf8 character :command=>proc{puts "Return Pressed"}) Tk::Iwidgets::Labeledwidget.alignlabels(ef, fef, nef, aef, pef) ef.pack(:fil=>:x, :expand=>true, :padx=>10, :pady=>5) fef.pack(:fil=>:x, :expand=>true, :padx=>10, :pady=>5) nef.pack(:fil=>:x, :expand=>true, :padx=>10, :pady=>5) aef.pack(:fil=>:x, :expand=>true, :padx=>10, :pady=>5) pef.pack(:fil=>:x, :expand=>true, :padx=>10, :pady=>5) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/entryfield-3.rb ================================================ #!/usr/bin/env ruby ######################################################### # # set Tk.encoding = 'utf-8' for a utf8 charecter # ######################################################### require 'tk' require 'tkextlib/iwidgets' Tk.encoding = 'utf-8' TkOption.add('*textBackground', 'white') ef = Tk::Iwidgets::Entryfield.new(:command=>proc{puts "Return Pressed"}) fef = Tk::Iwidgets::Entryfield.new(:labeltext=>'Fixed:', :fixed=>10, :width=>12) nef = Tk::Iwidgets::Entryfield.new(:labeltext=>'Numeric:', :validate=>:numeric, :width=>12) aef = Tk::Iwidgets::Entryfield.new(:labeltext=>'Alphabetic:', :validate=>:alphabetic, :width=>12, :invalid=>proc{ puts "Alphabetic contents invalid" }) pef = Tk::Iwidgets::Entryfield.new(:labeltext=>'Password:', :width=>12, :show=>"\267", ## <=== utf8 character :command=>proc{puts "Return Pressed"}) Tk::Iwidgets::Labeledwidget.alignlabels(ef, fef, nef, aef, pef) ef.pack(:fil=>:x, :expand=>true, :padx=>10, :pady=>5) fef.pack(:fil=>:x, :expand=>true, :padx=>10, :pady=>5) nef.pack(:fil=>:x, :expand=>true, :padx=>10, :pady=>5) aef.pack(:fil=>:x, :expand=>true, :padx=>10, :pady=>5) pef.pack(:fil=>:x, :expand=>true, :padx=>10, :pady=>5) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/extbutton.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' Tk::Iwidgets::Extbutton.new(:text=>'Bitmap example', :bitmap=>'info', :background=>'bisque', :activeforeground=>'red', :bitmapforeground=>'blue', :defaultring=>true, :command=>proc{ puts "Bisque is beautiful" }).pack(:expand=>true) #img = TkPhotoImage.new(:file=>File.join(File.dirname(File.expand_path(__FILE__)), '../../../images/earthris.gif')) img = TkPhotoImage.new(:file=>File.join(File.dirname(File.expand_path(__FILE__)), '../catalog_demo/images/clear.gif')) Tk::Iwidgets::Extbutton.new(:text=>'Image example', :relief=>:ridge, :image=>img, :imagepos=>:e, :font=>'9x15bold', :activebackground=>'lightyellow', :background=>'lightgreen').pack(:expand=>true) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/extfileselectionbox.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' Tk::Iwidgets::Extfileselectionbox.new.pack(:padx=>10, :pady=>10, :fill=>:both, :expand=>true) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/extfileselectiondialog.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' mainloop = Thread.new{Tk.mainloop} # # Non-modal example # nmfsd = Tk::Iwidgets::Extfileselectiondialog.new(:title=>'Non-Modal') nmfsd.buttonconfigure('OK', :command=>proc{ puts "You selected #{nmfsd.get}" nmfsd.deactivate }) nmfsd.activate # # Modal example # mfsd = Tk::Iwidgets::Extfileselectiondialog.new(:modality=>:application) mfsd.center if TkComm.bool(mfsd.activate) puts "You selected #{mfsd.get}" else puts "You cancelled the dialog" end mainloop.join ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/feedback.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' Tk::Iwidgets::Feedback.new(:labeltext=>'Status', :steps=>20){|fb| pack(:padx=>10, :pady=>10, :fill=>:both, :expand=>true) TkTimer.new(500, 20, proc{fb.step}).start(2500) } Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/fileselectionbox.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' Tk::Iwidgets::Fileselectionbox.new.pack(:padx=>10, :pady=>10, :fill=>:both, :expand=>true) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/fileselectiondialog.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' mainloop = Thread.new{Tk.mainloop} # # Non-modal example # nmfsd = Tk::Iwidgets::Fileselectiondialog.new(:title=>'Non-Modal') nmfsd.buttonconfigure('OK', :command=>proc{ puts "You selected #{nmfsd.get}" nmfsd.deactivate }) nmfsd.activate # # Modal example # mfsd = Tk::Iwidgets::Fileselectiondialog.new(:modality=>:application) mfsd.center if TkComm.bool(mfsd.activate) puts "You selected #{mfsd.get}" else puts "You cancelled the dialog" end mainloop.join ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/finddialog.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' mainloop = Thread.new{Tk.mainloop} st = Tk::Iwidgets::Scrolledtext.new.pack st.insert('end', "Now is the time for all good men\n") st.insert('end', "to come to the aid of their country") fd = Tk::Iwidgets::Finddialog.new(:textwidget=>st) fd.center(st) fd.activate mainloop.join ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/hierarchy.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' def get_files(file) dir = (file.empty?)? ENV['HOME'] : TkComm._fromUTF8(file) Dir.chdir(dir) rescue return '' Dir['*'].sort.collect{|f| [TkComm._toUTF8(File.join(dir, f)), TkComm._toUTF8(f)] } end Tk::Iwidgets::Hierarchy.new(:querycommand=>proc{|arg| get_files(arg.node)}, :visibleitems=>'30x15', :labeltext=>ENV['HOME']).pack(:side=>:left, :expand=>true, :fill=>:both) # Tk::Iwidgets::Hierarchy.new(:querycommand=>[proc{|n| get_files(n)}, '%n'], # :visibleitems=>'30x15', # :labeltext=>ENV['HOME']).pack(:side=>:left, # :expand=>true, # :fill=>:both) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/hyperhelp.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' mainloop = Thread.new{Tk.mainloop} dir = '/usr/local/ActiveTcl/demos/IWidgets/html/' href = [ 'hyperhelp.n', 'buttonbox.n', 'calendar.n' ] hh = Tk::Iwidgets::Hyperhelp.new(:topics=>href, :helpdir=>dir) hh.show_topic('hyperhelp.n') hh.activate mainloop.join ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/labeledframe.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' lf = Tk::Iwidgets::Labeledframe.new(:labeltext=>'Entry Frame', :labelpos=>:n) lf.pack(:fill=>:both, :expand=>true, :padx=>10, :pady=>10) cs = lf.child_site Tk::Iwidgets::Entryfield.new(cs, :labeltext=>'Name:').pack(:side=>:top, :fill=>:x) Tk::Iwidgets::Spinint.new(cs, :labeltext=>'Number:').pack(:side=>:top, :fill=>:x) Tk::Iwidgets::Pushbutton.new(cs, :text=>'Details:').pack(:side=>:top, :fill=>:x) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/labeledwidget.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' lw = Tk::Iwidgets::Labeledwidget.new(:labeltext=>'Canvas Widget', :labelpos=>:s) lw.pack(:fill=>:both, :expand=>true, :padx=>10, :pady=>10) cw = TkCanvas.new(lw.child_site, :relief=>:raised, :width=>200, :height=>200, :borderwidth=>3, :background=>:white) cw.pack(:padx=>10, :pady=>10) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/mainwindow.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' mw = Tk::Iwidgets::Mainwindow.new mw.menubar.add(:menubutton, 'file', :text=>'File', :underline=>0, :padx=>8, :pady=>2, :menu=>[ [:options, {:tearoff=>false}], [:command, 'new', { :label=>'New', :underline=>0, :helpstr=>'Create a new file' } ], [:command, 'open', { :label=>'Open ...', :underline=>0, :helpstr=>'Open an existing file' } ], [:command, 'save', { :label=>'Save', :underline=>0, :helpstr=>'Save the current file' } ], [:command, 'saveas', { :label=>'Save As', :underline=>5, :helpstr=>'Save the file as a different name' } ], [:command, 'print', { :label=>'Print', :underline=>0, :helpstr=>'Print the file' } ], [:separator, 'sep1'], [:command, 'close', { :label=>'Close', :underline=>0, :helpstr=>'Close the file' } ], [:separator, 'sep2'], [:command, 'exit', { :label=>'Exit', :underline=>1, :helpstr=>'Exit this application' } ], nil ]) Tk::Iwidgets::Scrolledtext.new(mw.child_site).pack(:fill=>:both, :expand=>true) mw.activate Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/menubar.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' helpvar = TkVariable.new viewmode = TkVariable.new menu_spec = [ [:menubutton, 'file', { :text=>'File', :menu=>[ [:options, {:tearoff=>false}], [:command, 'new', { :label=>'New', :helpstr=>'Open new document', :command=>proc{puts 'NEW'} } ], [:command, 'close', { :label=>'Close', :helpstr=>'Close current document', :command=>proc{puts 'CLOSE'} } ], [:separator, 'sep1'], [:command, 'exit', { :label=>'Exit', :helpstr=>'Exit application', :command=>proc{exit} } ] ] } ], [:menubutton, 'edit', { :text=>'Edit', :menu=>[ [:options, {:tearoff=>false}], [:command, 'undo', { :label=>'Undo', :underline=>0, :helpstr=>'Undo last command', :command=>proc{puts 'UNDO'} } ], [:separator, 'sep2'], [:command, 'cut', { :label=>'Cut', :underline=>1, :helpstr=>'Cut selection to clipboard', :command=>proc{puts 'CUT'} } ], [:command, 'copy', { :label=>'Copy', :underline=>1, :helpstr=>'Copy selection to clipboard', :command=>proc{puts 'COPY'} } ], [:command, 'paste', { :label=>'Paste', :underline=>0, :helpstr=>'Paste clipboard contents', :command=>proc{puts 'PASTE'} } ] ] } ], [:menubutton, 'options', { :text=>'Options', :menu=>[ [:options, {:tearoff=>false, :selectcolor=>'blue'}], [:radiobutton, 'byName', { :variable=>viewmode, :value=>'NAME', :label=>'by Name', :helpstr=>'View files by name order', :command=>proc{puts 'NAME'} } ], [:radiobutton, 'byDate', { :variable=>viewmode, :value=>'DATE', :label=>'by Date', :helpstr=>'View files by date order', :command=>proc{puts 'DATE'} } ], [:cascade, 'prefs', { :label=>'Preferences', :menu=>[ [:command, 'colors', { :label=>'Colors...', :helpstr=>'Change text colors', :command=>proc{puts 'COLORS'} } ], [:command, 'fonts', { :label=>'Fonts...', :helpstr=>'Change text font', :command=>proc{puts 'COLORS'} } ] ] } ] ] } ] ] #mb = Tk::Iwidgets::Menubar.new(:helpvariable=>helpvar, # :menubuttons=>menu_spec) mb = Tk::Iwidgets::Menubar.new(:helpvariable=>helpvar) mb.configure(:menubuttons=>menu_spec) fr = TkFrame.new(:width=>300, :height=>300) ef = TkEntry.new(:textvariable=>helpvar) mb.pack(:anchor=>:nw, :fill=>:x, :expand=>true) fr.pack(:fill=>:both, :expand=>true) ef.pack(:anchor=>:sw, :fill=>:x, :expand=>true) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/menubar2.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' helpvar = TkVariable.new viewmode = TkVariable.new mb = Tk::Iwidgets::Menubar.new mb.menubuttons = [ [:menubutton, 'file', { :text=>'File', :menu=>[ [:command, 'new', {:label=>'New'}], [:command, 'close', {:label=>'Close'}], [:separator, 'sep1'], [:command, 'quit', {:label=>'Quit'}] ] } ], [:menubutton, 'edit', {:text=>'Edit'}] ] mb.add(:command, '.edit.undo', :label=>'Undo', :underline=>0) mb.add(:separator, '.edit.sep2') mb.add(:command, '.edit.cut', :label=>'Cut', :underline=>1) mb.add(:command, '.edit.copy', :label=>'Copy', :underline=>1) mb.add(:command, '.edit.paste', :label=>'Paste', :underline=>0) mb.add(:menubutton, '.options', :text=>'Options', :menu=>[ [:radiobutton, 'byName', { :variable=>viewmode, :value=>'NAME', :label=>'by Name'} ], [:radiobutton, 'byDate', { :variable=>viewmode, :value=>'DATE', :label=>'by Date'} ] ]) mb.add(:cascade, '.options.prefs', :label=>'Preferences', :menu=>[ [:command, 'colors', {:label=>'Colors...'}], [:command, 'fonts', {:label=>'Fonts...'}] ]) mb.pack(:side=>:left, :anchor=>:nw, :fill=>:x, :expand=>true) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/messagebox1.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' mb = Tk::Iwidgets::Messagebox.new(:hscrollmode=>:dynamic, :labeltext=>'Messages', :labelpos=>:n, :height=>120, :width=>550, :savedir=>'/tmp', :textbackground=>'#d9d9d9') mb.pack(:padx=>5, :pady=>5, :fill=>:both, :expand=>true) mb.type_add('ERROR', :background=>'red', :foreground=>'white', :bell=>true) mb.type_add('WARNING', :background=>'yellow', :foreground=>'black') mb.type_add('INFO', :background=>'white', :foreground=>'black') mb.issue('This is an error message in red with a beep', 'ERROR') mb.issue('This warning message in yellow', 'WARNING') mb.issue('This is an informational message', 'INFO') Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/messagebox2.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' mb = Tk::Iwidgets::Messagebox.new(:hscrollmode=>:dynamic, :labeltext=>'Messages', :labelpos=>:n, :height=>120, :width=>550, :savedir=>'/tmp', :textbackground=>'#d9d9d9') mb.pack(:padx=>5, :pady=>5, :fill=>:both, :expand=>true) error = mb.type_add(:background=>'red', :foreground=>'white', :bell=>true) warning = mb.type_add(:background=>'yellow', :foreground=>'black') info = mb.type_add(:background=>'white', :foreground=>'black') mb.issue('This is an error message in red with a beep', error) mb.issue('This warning message in yellow', warning) mb.issue('This is an informational message', info) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/messagedialog.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' mainloop = Thread.new{Tk.mainloop} # # Standard question message dialog used for confirmation. # md = Tk::Iwidgets::Messagedialog.new(:title=>'Message Dialog', :text=>'Are you sure ? ', :bitmap=>'questhead', :modality=>:global) md.buttonconfigure('OK', :text=>'Yes') md.buttonconfigure('Cancel', :text=>'No') if TkComm.bool(md.activate) md.text('Are you really sure ? ') if TkComm.bool(md.activate) puts 'Yes' else puts 'No' end else puts 'No' end md.destroy # # Copyright notice with automatic deactivation. # bmp = '@' + File.join(File.dirname(File.expand_path(__FILE__)), '../catalog_demo/images/text.xbm') cr = Tk::Iwidgets::Messagedialog.new(:title=>'Copyright', :bitmap=>bmp, :imagepos=>:n, :text=>"Copyright 200x XXX Corporation\nAll rights reserved") cr.hide('Cancel') cr.activate Tk.after(7000, proc{cr.deactivate; Tk.root.destroy}) mainloop.join ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/notebook.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' # Create the tabnotebook widget and pack it. nb = Tk::Iwidgets::Notebook.new(:width=>100, :height=>100) nb.pack(:anchor=>:nw, :fill=>:both, :expand=>true, :side=>:left, :padx=>10, :pady=>10) # Add two pages to the tabnotebook, # labelled "Page One" and "Page Two" nb.add(:label=>'Page One') nb.add(:label=>'Page Two') # Get the child site frames of these two pages. page1CS = nb.child_site(0) page2CS = nb.child_site('Page Two') # Create buttons on each page of the tabnotebook. TkButton.new(page1CS, :text=>'Button One').pack TkButton.new(page2CS, :text=>'Button Two').pack # Select the first page of the tabnotebook. nb.select(0) # Create the scrollbar and associate teh scrollbar # and the notebook together, then pack the scrollbar nb.scrollbar(TkScrollbar.new).pack(:fill=>:y, :expand=>true, :pady=>10) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/notebook2.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' # Create the tabnotebook widget and pack it. nb = Tk::Iwidgets::Notebook.new(:width=>100, :height=>100) nb.pack(:anchor=>:nw, :fill=>:both, :expand=>true, :side=>:top, :padx=>10, :pady=>0) # Add two pages to the tabnotebook, # labelled "Page One" and "Page Two" nb.add(:label=>'Page One') nb.add(:label=>'Page Two') # Get the child site frames of these two pages. page1CS = nb.child_site(0) page2CS = nb.child_site('Page Two') # Create buttons on each page of the tabnotebook. TkButton.new(page1CS, :text=>'Button One').pack TkButton.new(page2CS, :text=>'Button Two').pack # Select the first page of the tabnotebook. nb.select(0) # Create the scrollbar and associate teh scrollbar # and the notebook together, then pack the scrollbar nb.xscrollbar(TkScrollbar.new).pack(:fill=>:x, :expand=>true, :padx=>10) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/optionmenu.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' om = Tk::Iwidgets::Optionmenu.new(:labelmargin=>5, :labelpos=>:w, :labeltext=>"Operating System :") om.insert('end', 'Unix', 'VMS', 'Linux', 'OS/2', 'Windows NT', 'DOS') om.sort_ascending om.select('Linux') om.pack(:padx=>10, :pady=>10) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/panedwindow.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' pw = Tk::Iwidgets::Panedwindow.new(:width=>300, :height=>300) pw.add('top') pw.add('middle', :margin=>10) pw.add('bottom', :margin=>10, :minimum=>10) pw.pack(:fill=>:both, :expand=>true) pw.child_site_list.each{|pane| TkButton.new(pane, :text=>pane.path, :relief=>:raised, :borderwidth=>2).pack(:fill=>:both, :expand=>true) } pw.fraction(50,30,20) pw.paneconfigure(0, :minimum=>20) pw.paneconfigure('bottom', :margin=>15) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/panedwindow2.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' pw = Tk::Iwidgets::Panedwindow.new(:width=>300, :height=>300) top = pw.add middle = pw.add(:margin=>10) bottom = pw.add(:margin=>10, :minimum=>10) pw.pack(:fill=>:both, :expand=>true) pw.child_site_list.each{|pane| TkButton.new(pane, :text=>pane.path, :relief=>:raised, :borderwidth=>2).pack(:fill=>:both, :expand=>true) } pw.fraction(50,30,20) pw.paneconfigure(0, :minimum=>20) # 0 == pw.index(top) pw.paneconfigure(bottom, :margin=>15) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/promptdialog.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' mainloop = Thread.new{Tk.mainloop} TkOption.add('*textBackground', 'white') pd = Tk::Iwidgets::Promptdialog.new(:modality=>:global, :title=>'Password', :labeltext=>'Password:', :show=>'*') pd.hide('Apply') if TkComm.bool(pd.activate) puts "Password entered: #{pd.get}" else puts "Password prompt cancelled" end ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/pushbutton.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' Tk::Iwidgets::Pushbutton.new(:text=>'Hello', :command=>proc{puts 'Hello World'}, :defaultring=>true).pack(:padx=>10, :pady=>10) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/radiobox.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' rb = Tk::Iwidgets::Radiobox.new(:labeltext=>'Fonts') rb.add('times', :text=>'Times') rb.add('helvetica', :text=>'Helvetica') rb.add('courier', :text=>'Courier') rb.add('symbol', :text=>'Symbol') rb.select('courier') rb.pack(:expand=>true, :fill=>:both, :padx=>10, :pady=>10) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/scrolledcanvas.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' sc = Tk::Iwidgets::Scrolledcanvas.new sc.create(TkcRectangle, 100, 100, 400, 400, :fill=>'red') TkcRectangle.new(sc, 300, 300, 600, 600, :fill=>'green') TkcRectangle.new(sc, [[200, 200], [500, 500]], :fill=>'blue') sc.pack(:expand=>true, :fill=>:both, :padx=>10, :pady=>10) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/scrolledframe.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' sf = Tk::Iwidgets::Scrolledframe.new(:width=>150, :height=>180, :labeltext=>'scrolledframe') cs = sf.child_site TkButton.new(cs, :text=>'Hello').pack(:pady=>10) TkButton.new(cs, :text=>'World').pack(:pady=>10) TkButton.new(cs, :text=>'This is a test').pack(:pady=>10) TkButton.new(cs, :text=>'This is a really big button').pack(:pady=>10) TkButton.new(cs, :text=>'This is another really big button').pack(:pady=>10) TkButton.new(cs, :text=>'This is the last really big button').pack(:pady=>10) sf.pack(:expand=>true, :fill=>:both, :padx=>10, :pady=>10) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/scrolledhtml.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' TkOption.add('*textBackground', 'white') sh = Tk::Iwidgets::Scrolledhtml.new(:fontname=>'helvetica', :linkcommand=>proc{|href| sh.import_link(href) }) sh.pack(:expand=>true, :fill=>:both, :padx=>10, :pady=>10) sh.import(Tk.getOpenFile(:title=>'select HTML document')) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/scrolledlistbox.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' TkOption.add('*textBackground', 'white') slb = Tk::Iwidgets::Scrolledlistbox.new(:selectmode=>:single, :vscrollmode=>:static, :hscrollmode=>:dynamic, :labeltext=>'List', :selectioncommand=>proc{ puts(slb.get_curselection) }, :dblclickcommand=>proc{ puts('Double Click') puts(slb.get_curselection) }) slb.pack(:expand=>true, :fill=>:both, :padx=>10, :pady=>10) slb.insert('end', *['Hello', 'Out There', 'World']) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/scrolledtext.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' st = Tk::Iwidgets::Scrolledtext.new(:hscrollmode=>:dynamic, :wrap=>:none, :labeltext=>'Password File') st.pack(:expand=>true, :fill=>:both, :padx=>10, :pady=>10) st.import('/etc/passwd') Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/selectionbox.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' TkOption.add('*textBackground', 'white') sb = Tk::Iwidgets::Selectionbox.new.pack(:padx=>10, :pady=>10, :fill=>:both, :expand=>true) sb.insert_items('end', *['Hello', 'Out There', 'World']) TkLabel.new(sb.child_site, :text=>'Child Site is Here').pack(:fill=>:x, :padx=>10, :pady=>10) sb.insert_items(2, 'Cruel Cruel') sb.selection_set(1) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/selectiondialog.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' mainloop = Thread.new{Tk.mainloop} TkButton.new(:text=>'QUIT', :command=>proc{Tk.root.destroy}).pack(:padx=>10, :pady=>10) Tk::Iwidgets::Selectiondialog.new.activate mainloop.join ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/shell.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' sh = Tk::Iwidgets::Shell.new(:modality=>:application, :padx=>20, :pady=>20, :title=>'Shell') TkButton.new(:text=>'ACTIVATE', :padx=>7, :pady=>7, :command=>proc{puts sh.activate}).pack(:padx=>10, :pady=>10) TkLabel.new(sh.child_site, :text=>'SHELL').pack TkButton.new(sh.child_site, :text=>'YES', :command=>proc{sh.deactivate 'press YES'}).pack(:fill=>:x) TkButton.new(sh.child_site, :text=>'NO', :command=>proc{sh.deactivate 'press NO'}).pack(:fill=>:x) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/spindate.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' Tk::Iwidgets::Spindate.new.pack(:padx=>10, :pady=>10) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/spinint.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' TkOption.add('*textBackground', 'white') Tk::Iwidgets::Spinint.new(:labeltext=>'Temperature', :labelpos=>:w, :width=>5, :fixed=>true, :range=>[32, 212]).pack(:pady=>10) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/spinner.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' class Spinner_demo < TkWindow Months = %w(January February March April May June July August September October November December) def block_input(c) false end def spin_month(step) index = Months.index(@spinner.get) + step index = 11 if index < 0 index = 0 if index > 11 @spinner.value = Months[index] end def initialize(parent=nil) @spinner = Tk::Iwidgets::Spinner.new(parent, :labeltext=>'Month : ', :width=>10, :fixed=>10, :validate=>proc{|c| block_input}, :decrement=>proc{spin_month -1}, :increment=>proc{spin_month 1}) @path = @spinner @spinner.insert(0, Months[0]) end end Spinner_demo.new.pack(:padx=>10, :pady=>10) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/spintime.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' Tk::Iwidgets::Spintime.new.pack(:padx=>10, :pady=>10) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/tabnotebook.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' # Create the tabnotebook widget and pack it. tn = Tk::Iwidgets::Tabnotebook.new(:width=>300, :height=>100) tn.pack(:anchor=>:nw, :fill=>:both, :expand=>true, :side=>:left, :padx=>10, :pady=>10) # Add two pages to the tabnotebook, # labelled "Page One" and "Page Two" tn.add(:label=>'Page One') tn.add(:label=>'Page Two') # Get the child site frames of these two pages. page1CS = tn.child_site(0) page2CS = tn.child_site('Page Two') # Create buttons on each page of the tabnotebook. TkButton.new(page1CS, :text=>'Button One').pack TkButton.new(page2CS, :text=>'Button Two').pack # Select the first page of the tabnotebook. tn.select(0) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/tabnotebook2.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' # Create the tabnotebook widget and pack it. tn = Tk::Iwidgets::Tabnotebook.new(:width=>300, :height=>100) tn.pack(:anchor=>:nw, :fill=>:both, :expand=>true, :side=>:top, :padx=>10, :pady=>0) # Add two pages to the tabnotebook, # labelled "Page One" and "Page Two" tn.add(:label=>'Page One') tn.add(:label=>'Page Two') # Get the child site frames of these two pages. page1CS = tn.child_site(0) page2CS = tn.child_site('Page Two') # Create buttons on each page of the tabnotebook. TkButton.new(page1CS, :text=>'Button One').pack TkButton.new(page2CS, :text=>'Button Two').pack # Select the first page of the tabnotebook. tn.select(0) # Create the scrollbar # and the notebook together, then pack the scrollbar tn.xscrollbar(TkScrollbar.new).pack(:fill=>:x, :expand=>true, :padx=>10) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/tabset.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' # Create a listbox with two items (one and two) l = TkListbox.new(:selectmode=>:single, :exportselection=>false).pack l.insert('end', 'one') l.insert('end', 'two') l.selection_set(0) # Define a proc that knows how to select an item # from a list given an index from the tabset -command callback. selectItem = proc{|item| l.selection_clear(l.curselection) l.selection_set(item) l.see(item) } # Create a tabset, set its -command to call selectItem # Add two labels to the tabset (one and two). ts = Tk::Iwidgets::Tabset.new(:command=>selectItem) ts.add(:label=>1) ts.add(:label=>2) ts.select(0) ts.pack(:fill=>:x, :expand=>true) # Define a proc that knows how to select a tab # given a y pixel coordinate from the list.. selectTab = proc{|y| ts.select(l.nearest(y)) } # bind button 1 press to the selectTab procedure. l.bind('ButtonPress-1', proc{|y| selectTab.call(y) }, '%y') Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/timeentry.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' Tk::Iwidgets::Timeentry.new.pack Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/timefield.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' tf = Tk::Iwidgets::Timefield.new(:command=>proc{puts(tf.get)}) tf.pack(:fill=>:x, :expand=>true, :padx=>10, :pady=>10) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/toolbar.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' ########################################## # icon images editcopy22 = TkPhotoImage.new(:data=><<'EOD') R0lGODlhFgAWAIUAAPwCBBQSFPz+/DQyNISChDw6PMzKzMTGxERGRIyKjFxa XMTCvKSmpHR2dPz6/Pz29PTq3MS2rPz69MTCxFxWVHx6dJyWjNzSzPz27Pzy 7Pzu5PTm3NTKvIR+fJyGfHxuZHxqXNTCtPTq5PTi1PTezNS+rExOTFRORMyy lPTaxOzWxOzSvNze3NTOxMy2nMyulMyqjAQCBAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAbY QIBwSCwahYGkUnk0BgTQ6IAQaBKfUWhBYKhaAU+CgXAQIAyChLeJzSIQhcH6 GFaM0QtGY5kstqEODw8QEQELAhJTc08KBBMEFBUWDRcBE1pca20SGBkaEBsc AY5maFRIAgoLHRQRHh8gIQFlZnByqA8ZGSIQIyQjJQEmYgJ5p2ACrK4gJx4g KIZZAgdeAQ4ZI9kjKSor0AwEjeAs1S0cHAslLi4vMDDRWeRIfEsxMeET4ATy VoYLC5fizXEiAR84BeMG+pEm8EsAFhAjSlR4hR6fLxiF0AkCACH+aENyZWF0 ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5 OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2 ZWxjb3IuY29tADs= EOD editcut22 = TkPhotoImage.new(:data=><<'EOD') R0lGODlhFgAWAIMAAPwCBAQCBAwCBPz+/OTi5JyanOzq7DQyNGxqbAAAAAAA AAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAARbEMhJq704gxBE 0Bf3cZo4kRJqBQNRfBucyudgvJS6VaxLzyMa6/bLiWA9HOg4VIIkL5vzuRkc pkvRIIAorphJLzBW84WEuRZWp6uaT7J2Sh1Hit3OY/ZO7WvsEQAh/mhDcmVh dGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAx OTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRl dmVsY29yLmNvbQA7 EOD editpaste22 = TkPhotoImage.new(:data=><<'EOD') R0lGODlhFgAWAIYAAPwCBBQWFDw6FHRuFGRaBFxSBAQCBAQKBCQiBIx6HPz6 /NTOfKyiXDQuFOTm5Pz+/Ozu7PTq5Pz63PTyxNTOjKSeRExGLMTGxMzKzNTS 1NTW1Dw2NKSmpKyqrKSipJyanNzWlLy6ZLSuVIx6FISChIyKhJSSlCQiJLS2 tDw6NDQyNCQiFCQmHBQSDGRiZHRydGxubHx6dGxqbFxeXGRmZFxaXCwuLOzq 7KyurHx+fDwmFEQuFCweFCQWDBQODBwaHBweHKSinJSWlOTi5JyepHR2dDw6 PBQSFNze3ERGRIyKjIyOjISGhPz29Pzy7MS2rMzOzFRWVHx2dHxybDQiFPz2 7Pzu5PTq3PTm1NTCtJyGdHxuZHxqXPzq3PTaxNS6pFxWVFRKRNS2nPTi1PTS tNSulNzOxNSynMymhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAA LAAAAAAWABYAAAf/gACCgwABAgMEBYSLggaOjgcICQoLDA2Pj4MGDg8QEZ4F DxITFBUWFxcYGRobjQ8cHR4fCQ8gCyEiFSMWJCUkJieNEB4dKB4pKissK8wr LS4vMDHBAAYQHx8dFx0fJDIzNDU0M+IyHzaNNyg43Ng5Ojs7Ojw9Pj9AMkCN DiZB/h9CSOx4QLCgihItqBkYgqIDESElitAYWJCgkQcXjjRCgi1Ihw4BB5LA QOLCgyQYHihpUU3DBw5ElpAgAYNixSRJjKjQaECDCRPZPDB5IbIGSQwKLnh4 wbInLA4kmJB4oaPiAwVNnER40hRK1BIAaVatUZJEFCkmpmjgCeWDCalFe4q4 oFKwSRUrEa5gycLzwq8lUnPQ4PEgSpYcUZ5o2cIlS1O/JHLEDdfjQZMIVrpg weLFy5e+M6WSmBGlxYMYYBRzCaOFi5imHWBIfOEiShLTVjaP6eyFTBmN1TA5 OvLDjJksWb58OVMGDRqWjAYdmU79SIvpjqJr104nEAAh/mhDcmVhdGVkIGJ5 IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5 OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29y LmNvbQA7 EOD editdelete22 = TkPhotoImage.new(:data=><<'EOD') R0lGODlhFgAWAIYAAASC/FRSVExKTERCRDw6PDQyNCwuLBweHBwaHAwODAwK DAQCBExOTNze3NTW1MTGxLS2tJyanPz+/Ozu7BQSFCwqLDw+POTi5PTu7MzK xIR+fCQmJPz6/Oze1NTGvPz69Pzy7Pz29LyyrPy+vPyupPTm1BQWFIQCBPwC BMS6rPzSzNTOxPTi1NS+rPTezNzOxPTizOzWxMy2pOzaxMy2nPTaxOzOtMyy nOzSvMyqjPx+fOzGpMSihPTq3OzKrOTCpNzKxNTCtAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAA LAAAAAAWABYAAAf8gACCAQIDBAUGBwgJCgsLgpCRAAwNlZYODxALEY+SkAMN EqKjEw0UD5yegqCjrRMVEqidkgWhraMWF7GptLa3EgEWFRSOnhW+vxgZEBqz kBvItxwdHryRCNGjHyAhHSLOgtgSI60c2yQjJd+eJqEnKK0hJCgnJSngAO0S F+8qEvL0VrBogW+BLX4oVKgIyMIFQU8KfDV4R+8FDBcxZBREthAFiRIsOsyg sVEUh4Un3pGoUcPGjZInK65QicPlxg8oX5RwqNJGjo0hdJwQ6EIkjRM6dvDY CKIHSBc1Ztjw4eOH0oIrsgIJEqSFDBo0cuTgsdSTo7No0xYTZCcQACH+aENy ZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29y IDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cu ZGV2ZWxjb3IuY29tADs= EOD text22 = TkPhotoImage.new(:data=><<'EOD') R0lGODlhFgAWAIQAAPwCBAQCBBwaHAwKDBQSFLy+vLS2tJSWlBQWFKyqrFRS VCwqLDQyNNTS1GxqbFxaXJyanIyOjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAWABYAAAVcICCOZGmK QSoMaZsShBsQBdAapHvgaIDUqUPJlRjSbAoT0fRDKgODRbF0PLUYjZO2F2Bs t9evNix+dsvDlGKK5jraudQb7qbX6a2HEJ+ycyF+LRE8ZTI+fX5oGCEAIf5o Q3JlYXRlZCBieSBCTVBUb0dJRiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxD b3IgMTk5NywxOTk4LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3 dy5kZXZlbGNvci5jb20AOw== EOD ########################################## bmp_dir = File.join(File.dirname(File.expand_path(__FILE__)), '../catalog_demo/images') ########################################## status_var = TkVariable.new radio_var = TkVariable.new check_var1 = TkVariable.new check_var2 = TkVariable.new tb = Tk::Iwidgets::Toolbar.new(:helpvariable=>status_var) ########################################## tb.add(:button, :helpstr=>'Copy It', :image=>editcopy22, :balloonstr=>'Copy', :command=>proc{puts 'Copy It'}) tb.add(:button, :helpstr=>'Cut It', :image=>editcut22, :balloonstr=>'Cut', :command=>proc{puts 'Cut It'}) tb.add(:button, :helpstr=>'Paste It', :image=>editpaste22, :balloonstr=>'Paste', :command=>proc{puts 'Paste It'}) tb.add(:button, :helpstr=>'Delete It', :image=>editdelete22, :balloonstr=>'Delete', :command=>proc{puts 'Delete It'}) #-------------------------------- tb.add(:frame, :borderwidth=>1, :width=>10, :height=>10) #-------------------------------- tb.add(:radiobutton, :variable=>radio_var, :value=>'Box', :bitmap=>"@#{bmp_dir}/box.xbm", :helpstr=>'Radio Button #1', :balloonstr=>'Radio', :command=>proc{puts 'Radio Button "Box"'}) tb.add(:radiobutton, :variable=>radio_var, :value=>'Line', :bitmap=>"@#{bmp_dir}/line.xbm", :helpstr=>'Radio Button #2', :balloonstr=>'Radio', :command=>proc{puts 'Radio Button "Line"'}) tb.add(:radiobutton, :variable=>radio_var, :value=>'Oval', :bitmap=>"@#{bmp_dir}/oval.xbm", :helpstr=>'Radio Button #3', :balloonstr=>'Radio', :command=>proc{puts 'Radio Button "Oval"'}) #-------------------------------- tb.add(:frame, :borderwidth=>1, :width=>10, :height=>10) #-------------------------------- tb.add(:checkbutton, :variable=>check_var1, :onvalue=>'yes', :offvalue=>'no', :image=>text22, :command=>proc{puts 'Checkbutton 1'}) tb.add(:checkbutton, :variable=>check_var2, :onvalue=>'yes', :offvalue=>'no', :bitmap=>"@#{bmp_dir}/points.xbm", :command=>proc{puts 'Checkbutton 2'}) tb.pack(:side=>:top, :anchor=>:nw) Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/iwidgets/sample/watch.rb ================================================ #!/usr/bin/env ruby require 'tk' require 'tkextlib/iwidgets' Thread.new{ trap('INT') {puts 'catch SIGINT'} sleep 5 trap('INT', 'DEFAULT') } Tk::Iwidgets::Watch.new(:state=>:disabled, :showampm=>:no, :width=>155, :height=>155){|w| w.pack(:padx=>10, :pady=>10, :fill=>:both, :expand=>true) # TkTimer.new(1000, -1, proc{w.show; Tk.update}).start TkTimer.new(25, -1, proc{w.show; Tk.update}).start } Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/tcllib/Orig_LICENSE.txt ================================================ >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< >>> The following text is the original 'license.term' of tklib <<< >>> extension. <<< >>> Original Tcl files are not include in this directry, because <<< >>> of all of them are rewrited to Ruby files. <<< >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< This software is copyrighted by Ajuba Solutions and other parties. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. ================================================ FILE: ext/tk/sample/tkextlib/tcllib/datefield.rb ================================================ #!/usr/bin/ruby require 'tk' require 'tkextlib/tcllib/datefield' require 'parsedate' Tk.root.title('Datefield example') my_date1 = TkVariable.new my_date2 = TkVariable.new my_date1.trace('w'){ begin t = Time.local(*(ParseDate.parsedate(my_date1.value))) my_date2.value = t.strftime('%A') rescue # ignore error end } df = Tk::Tcllib::Datefield.new(:textvariable=>my_date1) Tk.grid(TkLabel.new(:text=>'Enter a date:', :anchor=>:e), df, :sticky=>:ew) Tk.grid(TkLabel.new(:text=>'That date ia a:', :anchor=>:e), TkLabel.new(:textvariable=>my_date2, :relief=>:sunken, :width=>12), :sticky=>:ew) df.set_focus Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/tcllib/plotdemos1.rb ================================================ #!/usr/bin/ruby require 'tk' require 'tkextlib/tcllib/plotchart' ############################### c1 = TkCanvas.new(:background=>'white', :width=>400, :height=>200) c2 = TkCanvas.new(:background=>'white', :width=>400, :height=>200) c3 = TkCanvas.new(:background=>'white', :width=>400, :height=>200) Tk.pack(c1,c2,c3, :fill=>:both, :side=>:top) h = TkToplevel.new(:title=>'h') hc1 = TkCanvas.new(h, :background=>'white', :width=>400, :height=>200) hc2 = TkCanvas.new(h, :background=>'white', :width=>400, :height=>200) Tk.pack(hc1,hc2, :fill=>:both, :side=>:top) v = TkToplevel.new(:title=>'v') vc1 = TkCanvas.new(v, :background=>'white', :width=>400, :height=>200) vc2 = TkCanvas.new(v, :background=>'white', :width=>400, :height=>200) vc3 = TkCanvas.new(v, :background=>'white', :width=>400, :height=>200) Tk.pack(vc1,vc2,vc3, :fill=>:both, :side=>:top) ############################### s = Tk::Tcllib::Plotchart::XYPlot.new(c1, [0.0, 100.0, 10.0], [0.0, 100.0, 20.0]) xd = 5.0 yd = 20.0 xold = 0.0 yold = 50.0 s.dataconfig('series1', :color=>'red') (0..19).each{|i| xnew = xold + xd ynew = yold + (rand() - 0.5) * yd ynew2 = yold + (rand() - 0.5) * 2.0 * yd s.plot('series1', xnew, ynew) s.plot('series2', xnew, ynew2) xold = xnew yold = ynew } s.xtext "X-coordinate" s.ytext "Y-data" s.title "Aha!" c1.wait_visibility s.save_plot "aha.ps" ############################### s = Tk::Tcllib::Plotchart::Piechart.new(c2) s.plot([ ["Long names", 10], ["Short names", 30], ["Average", 40], ["Ultra-short names", 5] ]) # # Note: title should be shifted up # - distinguish a separate title area # s.title "Okay - this works" ############################### s = Tk::Tcllib::Plotchart::PolarPlot.new(c3, [3.0, 1.0]) 0.step(359, 10){|angle| rad = 1.0+Math.cos(angle*Math::PI/180.0) s.plot('cardioid', rad, angle) } s.title "Cardioid" ############################### s = Tk::Tcllib::Plotchart::Barchart.new(hc1, %w(A B C D E), [0.0, 10.0, 2.0], 2) s.plot('series1', [1.0, 4.0, 6.0, 1.0, 7.0], 'red') s.plot('series2', [0.0, 3.0, 7.0, 9.3, 2.0], 'green') s.title "Arbitrary data" ############################### s = Tk::Tcllib::Plotchart::Barchart.new(hc2, %w(A B C D E), [0.0, 20.0, 5.0], :stacked) s.plot('series1', [1.0, 4.0, 6.0, 1.0, 7.0], 'red') s.plot('series2', [0.0, 3.0, 7.0, 9.3, 2.0], 'green') s.title "Stacked diagram" ############################### s = Tk::Tcllib::Plotchart::HorizontalBarchart.new(vc1, [0.0, 10.0, 2.0], %w(A B C D E), 2) s.plot('series1', [1.0, 4.0, 6.0, 1.0, 7.0], 'red') s.plot('series2', [0.0, 3.0, 7.0, 9.3, 2.0], 'green') s.title "Arbitrary data" ############################### s = Tk::Tcllib::Plotchart::HorizontalBarchart.new(vc2, [0.0, 20.0, 5.0], %w(A B C D E), :stacked) s.plot('series1', [1.0, 4.0, 6.0, 1.0, 7.0], 'red') s.plot('series2', [0.0, 3.0, 7.0, 9.3, 2.0], 'green') s.title "Stacked diagram" ############################### s = Tk::Tcllib::Plotchart::Timechart.new(vc3, "1 january 2004", "31 december 2004", 4) s.period("Spring", "1 march 2004", "1 june 2004", 'green') s.period("Summer", "1 june 2004", "1 september 2004", 'yellow') s.vertline("1 jan", "1 january 2004") s.vertline("1 apr", "1 april 2004") s.vertline("1 jul", "1 july 2004") s.vertline("1 oct", "1 october 2004") s.milestone("Longest day", "21 july 2004") s.title "Seasons (northern hemisphere)" ############################### z = TkToplevel.new(:title=>'3D') zc1 = TkCanvas.new(z, :background=>'white', :width=>400, :height=>300) zc2 = TkCanvas.new(z, :background=>'white', :width=>400, :height=>250) Tk.pack(zc1,zc2) s = Tk::Tcllib::Plotchart::Plot3D.new(zc1, [0, 10, 3], [-10, 10, 10], [0, 10, 2.5]) s.title "3D Plot" s.plot_function{|x, y| # cowboyhat x1 = x.to_f/9.0 y1 = y.to_f/9.0 3.0 * (1.0-(x1*x1+y1*y1))*(1.0-(x1*x1+y1*y1)) } s = Tk::Tcllib::Plotchart::Plot3D.new(zc2, [0, 10, 3], [-10, 10, 10], [0, 10, 2.5]) s.title "3D Plot - data " s.colour("green", "black") s.plot_data([ [1.0, 2.0, 1.0, 0.0], [1.1, 3.0, 1.1, -0.5], [3.0, 1.0, 4.0, 5.0] ]) ############################### Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/tcllib/plotdemos2.rb ================================================ #!/usr/bin/ruby require 'tk' require 'tkextlib/tcllib/plotchart' ############################### c1 = TkCanvas.new(:background=>'white', :width=>400, :height=>200) c2 = TkCanvas.new(:background=>'white', :width=>400, :height=>200) Tk.pack(c1,c2, :fill=>:both, :side=>:top) ############################### # Set up a strip chart ############################### slipchart = Tk::Tcllib::Plotchart::Stripchart.new(c1, [0.0, 100.0, 10.0], [0.0, 100.0, 20.0]) TkTimer.new(500, -1, proc{|obj| # obj --> TkTimer object slipchart, xold, xd, yold, yd = obj.return_value xnew = xold + xd ynew = yold + (rand() - 0.5) * yd ynew2 = yold + (rand() - 0.5) * 2.0 * yd slipchart.plot('series1', xnew, ynew) slipchart.plot('series2', xnew, ynew2) obj.stop if xnew >= 200 [slipchart, xnew, xd, ynew, yd] # return_value }).start(100, proc{ # init return_value [slipchart, 0.0, 15.0, 50.0, 30.0] }) slipchart.title "Aha!" ############################### # Set up an isometric plot ############################### s = Tk::Tcllib::Plotchart::IsometricPlot.new(c2, [0.0, 100.0], [0.0, 200.0], :noaxes) s.set_zoom_pan s.plot('rectangle', [10.0, 10.0, 50.0, 50.0], 'green') s.plot('filled-rectangle', [20.0, 20.0, 40.0, 40.0], 'red') s.plot('filled-circle', [70.0, 70.0, 40.0], 'yellow') s.plot('circle', [70.0, 70.0, 42.0]) ############################### # Check the symbols ############################### h = TkToplevel.new(:title=>'h') c = TkCanvas.new(h, :bg=>'white', :width=>400, :height=>200).pack(:fill=>:both) s = Tk::Tcllib::Plotchart::XYPlot.new(c, [0.0, 100.0, 10.0], [0.0, 100.0, 20.0]) s.dataconfig('series1', :colour=>'red', :type=>:symbol) s.dataconfig('series2', :colour=>'green', :type=>:both) s.yconfig(:format=>"%12.2e") x = 5.0 %w(plus cross circle up down dot upfilled downfilled).each{|sym| s.dataconfig('series1', :symbol=>sym) s.dataconfig('series2', :symbol=>sym) s.plot('series1', x, 50.0) s.plot('series2', x, 20) x += 10 } ############################## Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/tcllib/plotdemos3.rb ================================================ #!/usr/bin/ruby require 'tk' require 'tkextlib/tcllib/plotchart' ############################### # Set up a strip chart ############################### Tk::Tcllib::Plotchart::Stripchart.new([0.0, 100.0, 10.0], [0.0, 100.0, 20.0], :background=>'white', :width=>400, :height=>200){|chart| title "Aha!" pack(:fill=>:both, :side=>:top) series1 = Tk::Tcllib::Plotchart::PlotSeries.new(chart) series2 = Tk::Tcllib::Plotchart::PlotSeries.new(chart) xd = 15.0 yd = 30.0 TkTimer.new(500, -1, proc{|obj| # obj --> TkTimer object xold, yold = obj.return_value xnew = xold + xd ynew = yold + (rand() - 0.5) * yd ynew2 = yold + (rand() - 0.5) * 2.0 * yd series1.plot(xnew, ynew) series2.plot(xnew, ynew2) obj.stop if xnew >= 200 [xnew, ynew] # return_value }).start(100, proc{ [0.0, 50.0] }) # init return_value } ############################### # Set up an isometric plot ############################### Tk::Tcllib::Plotchart::IsometricPlot.new([0.0, 100.0], [0.0, 200.0], :noaxes, :background=>'white', :width=>400, :height=>200){|chart| pack(:fill=>:both, :side=>:top) set_zoom_pan chart.plot('rectangle', [10.0, 10.0, 50.0, 50.0], 'green') chart.plot('filled-rectangle', [20.0, 20.0, 40.0, 40.0], 'red') chart.plot('filled-circle', [70.0, 70.0, 40.0], 'yellow') chart.plot('circle', [70.0, 70.0, 42.0]) } ############################### # Check the symbols ############################### TkToplevel.new(:title=>'h'){|h| Tk::Tcllib::Plotchart::XYPlot.new(h, [0.0, 100.0, 10.0], [0.0, 100.0, 20.0], :bg=>'white', :width=>400, :height=>200){|chart| pack(:fill=>:both) yconfig(:format=>"%12.2e") series1 = Tk::Tcllib::Plotchart::PlotSeries.new(chart, :colour=>'red', :type=>:symbol) series2 = Tk::Tcllib::Plotchart::PlotSeries.new(chart, :colour=>'green', :type=>:both) x = 5.0 %w(plus cross circle up down dot upfilled downfilled).each{|sym| series1.dataconfig(:symbol=>sym) series2.dataconfig(:symbol=>sym) series1.plot(x, 50.0) series2.plot(x, 20) x += 10 } } } ############################## Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/tcllib/xyplot.rb ================================================ #!/usr/bin/ruby require 'tk' require 'tkextlib/tcllib/plotchart' TkCanvas.new(:background=>'white', :width=>400, :height=>200){|c| pack(:fill=>:both) Tk::Tcllib::Plotchart::XYPlot.new(c, [0.0, 100.0, 10.0], [0.0, 100.0, 20.0]){ [ [0.0, 32.0], [10.0, 50.0], [25.0, 60.0], [78.0, 11.0] ].each{|x, y| plot('series1', x, y) } title("Data series") } } Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/tile/Orig_LICENSE.txt ================================================ ###################################################################### ### The following text is the original 'license.terms' of tile ### ### extension. ### ###################################################################### LICENSE ("MIT-style") This software is Copyright (C) 2003 Joe English and other parties. The following terms apply to all files associated with this software unless explicitly disclaimed in individual files. The author(s) hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. 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. IN NO EVENT shall the AUTHORS of THIS SOFTWARE be LIABLE to ANY PARTY for DIRECT, INDIRECT, SPECIAL, INCIDENTAL, or CONSEQUENTIAL DAMAGES arising out of the USE of THIS SOFTWARE and its DOCUMENTATION. ================================================ FILE: ext/tk/sample/tkextlib/tile/demo.rb ================================================ #!/usr/bin/env ruby # # Demo for 'tile' package. # require 'tk' demodir = File.dirname($0) themesdir = File.join(demodir, 'themes') Tk::AUTO_PATH.lappend('.', demodir, themesdir) Dir.foreach(themesdir){|name| next if name == '.' || name == '..' dir = File.join(themesdir, name) Tk::AUTO_PATH.lappend(dir) if File.directory?(dir) } require 'tkextlib/tile' def version?(ver) TkPackage.vcompare(Tk::Tile.package_version, ver) >= 0 end # define Tcl/Tk procedures for compatibility Tk::Tile.__define_LoadImages_proc_for_compatibility__! Tk::Tile::Style.__define_wrapper_proc_for_compatibility__! unless Tk::Tile::Style.theme_names.include?('step') Tk::Tile::Style.theme_create('step') end Tk.load_tclscript(File.join(demodir, 'toolbutton.tcl')) Tk.load_tclscript(File.join(demodir, 'repeater.tcl')) # This forces an update of the available packages list. It's required # for package names to find the themes in demos/themes/*.tcl ## Tk.tk_call(TkPackage.unknown_proc, 'Tcl', TkPackage.provide('Tcl')) ## --> This doesn't work. ## Because, unknown_proc may be "command + some arguments". Tk.ip_eval("#{TkPackage.unknown_proc} Tcl #{TkPackage.provide('Tcl')}") TkRoot.new{ title 'Tile demo' iconname 'Tile demo' } # The descriptive names of the builtin themes. $THEMELIST = [ ['default', 'Default'], ['classic', 'Classic'], ['alt', 'Revitalized'], ['winnative', 'Windows native'], ['xpnative', 'XP Native'], ['aqua', 'Aqua'], ] $V = TkVariable.new_hash(:THEME => 'default', :COMPOUND => 'top', :CONSOLE => false, :MENURADIO1 => 'One', :MENUCHECK1 => true, :PBMODE => 'determinate', :SELECTED => true, :CHOICE => 2) # Add in any available loadable themes. TkPackage.names.find_all{|n| n =~ /^(tile|ttk)::theme::/}.each{|pkg| name = pkg.split('::')[-1] unless $THEMELIST.assoc(name) $THEMELIST << [name, Tk.tk_call('string', 'totitle', name)] end } # Add theme definition written by ruby $RUBY_THEMELIST = [] begin load(File.join(demodir, 'themes', 'kroc.rb'), true) rescue => e raise e $RUBY_THEMELIST << ['kroc-rb', 'Kroc (by Ruby)', false] else $RUBY_THEMELIST << ['kroc-rb', 'Kroc (by Ruby)', true] end def makeThemeControl(parent) c = Tk::Tile::Labelframe.new(parent, :text=>'Theme') $THEMELIST.each{|theme, name| b = Tk::Tile::Radiobutton.new(c, :text=>name, :value=>theme, :variable=>$V.ref(:THEME), :command=>proc{setTheme(theme)}) b.grid(:sticky=>:ew) unless (TkPackage.names.find{|n| n =~ /(tile|ttk)::theme::#{theme}/}) b.ttk_state(:disabled) end } $RUBY_THEMELIST.each{|theme, name, available| b = Tk::Tile::Radiobutton.new(c, :text=>name, :value=>theme, :variable=>$V.ref(:THEME), :command=>proc{setTheme(theme)}) b.grid(:sticky=>:ew) b.ttk_state(:disabled) unless available } c end def makeThemeMenu(parent) m = TkMenu.new(parent) $THEMELIST.each{|theme, name| m.add(:radiobutton, :label=>name, :variable=>$V.ref(:THEME), :value=>theme, :command=>proc{setTheme(theme)}) unless (TkPackage.names.find{|n| n =~ /(tile|ttk)::theme::#{theme}/}) m.entryconfigure(:end, :state=>:disabled) end } $RUBY_THEMELIST.each{|theme, name, available| m.add(:radiobutton, :label=>name, :variable=>$V.ref(:THEME), :value=>theme, :command=>proc{setTheme(theme)}) m.entryconfigure(:end, :state=>:disabled) unless available } m end def setTheme(theme) if (pkg = TkPackage.names.find{|n| n =~ /(tile|ttk)::theme::#{theme}/}) unless Tk::Tile::Style.theme_names.find{|n| n == theme} TkPackage.require(pkg) end end Tk::Tile::Style.theme_use(theme) end # # Load icons... # $BUTTONS = ['open', 'new', 'save'] $CHECKBOXES = ['bold', 'italic'] $ICON = {} def loadIcons(file) Tk.load_tclscript(file) img_data = TkVarAccess.new('ImgData') img_data.keys.each{|icon| $ICON[icon] = TkPhotoImage.new(:data=>img_data[icon]) } end loadIcons(File.join(demodir, 'iconlib.tcl')) # # Utilities: # def foreachWidget(wins, cmd) wins.each{|w| cmd.call(w) foreachWidget(w.winfo_children, cmd) } end # sbstub # Used as the :command option for a scrollbar, # updates the scrollbar's position. # def sbstub(sb, cmd, num, units = 'units') num = TkComm.number(num) case cmd.to_s when 'moveto' sb.set(num, num+0.5) when 'scroll' if units.to_s == 'pages' delta = 0.2 else delta = 0.05 end current = sb.get sb.set(current[0] + delta * num, current[1] + delta * num) end end # ... for debugging: TkBindTag::ALL.bind('ButtonPress-3', proc{|w| $W = w}, '%W') TkBindTag::ALL.bind('Control-ButtonPress-3', proc{|w| w.set_focus}, '%W') def showHelp() Tk.messageBox(:message=>'No help yet...') end # # See toolbutton.tcl. TkOption.add('*Toolbar.relief', :groove) TkOption.add('*Toolbar.borderWidth', 2) TkOption.add('*Toolbar.Button.Pad', 2) $ROOT = Tk.root $BASE = $ROOT Tk.destroy(*($ROOT.winfo_children)) $TOOLBARS = [] # # Toolbar button standard vs. tile comparison: # def makeToolbars # # Tile toolbar: # tb = Tk::Tile::Frame.new($BASE, :class=>'Toolbar') $TOOLBARS << tb i = 0 $BUTTONS.each{|icon| i += 1 Tk::Tile::Button.new(tb, :text=>icon, :image=>$ICON[icon], :compound=>$V[:COMPOUND], :style=>:Toolbutton).grid(:row=>0, :column=>i, :sticky=>:news) } $CHECKBOXES.each{|icon| i += 1 Tk::Tile::Checkbutton.new(tb, :text=>icon, :image=>$ICON[icon], :variable=>$V.ref(icon), :compound=>$V[:COMPOUND], :style=>:Toolbutton).grid(:row=>0, :column=>i, :sticky=>:news) } mb = Tk::Tile::Menubutton.new(tb, :text=>'toolbar', :image=>$ICON['file'], :compound=>$V[:COMPOUND]) mb.configure(:menu=>makeCompoundMenu(mb)) i += 1 mb.grid(:row=>0, :column=>i, :sticky=>:news) i += 1 tb.grid_columnconfigure(i, :weight=>1) # # Standard toolbar: # tb = TkFrame.new($BASE, :class=>'Toolbar') $TOOLBARS << tb i = 0 $BUTTONS.each{|icon| i += 1 TkButton.new(tb, :text=>icon, :image=>$ICON[icon], :compound=>$V[:COMPOUND], :relief=>:flat, :overrelief=>:raised).grid(:row=>0, :column=>i, :sticky=>:news) } $CHECKBOXES.each{|icon| i += 1 TkCheckbutton.new(tb, :text=>icon, :image=>$ICON[icon], :variable=>$V.ref(icon), :compound=>$V[:COMPOUND], :indicatoron=>false, :selectcolor=>'', :relief=>:flat, :overrelief=>:raised).grid(:row=>0, :column=>i, :sticky=>:news) } mb = TkMenubutton.new(tb, :text=>'toolbar', :image=>$ICON['file'], :compound=>$V[:COMPOUND]) mb.configure(:menu=>makeCompoundMenu(mb)) i += 1 mb.grid(:row=>0, :column=>i, :sticky=>:news) i += 1 tb.grid_columnconfigure(i, :weight=>1) end # # Toolbar :compound control: # def makeCompoundMenu(mb) menu = TkMenu.new(mb) %w(text image none top bottom left right center).each{|str| menu.add(:radiobutton, :label=>Tk.tk_call('string', 'totitle', str), :variable=>$V.ref(:COMPOUND), :value=>str, :command=>proc{ changeToolbars() }) } menu end makeToolbars() ## CONTROLS control = Tk::Tile::Frame.new($BASE) # # Overall theme control: # makeThemeControl(control).grid(:sticky=>:news, :padx=>6, :ipadx=>6) control.grid_rowconfigure(99, :weight=>1) def changeToolbars foreachWidget($TOOLBARS, proc{|w| begin w.compound($V[:COMPOUND]) rescue end }) end def scrolledWidget(parent, klass, themed, *args) if themed f = Tk::Tile::Frame.new(parent) t = klass.new(f, *args) vs = Tk::Tile::Scrollbar.new(f) hs = Tk::Tile::Scrollbar.new(f) else f = TkFrame.new(parent) t = klass.new(f, *args) vs = TkScrollbar.new(f) hs = TkScrollbar.new(f) end t.yscrollbar(vs) t.xscrollbar(hs) TkGrid.configure(t, vs, :sticky=>:news) TkGrid.configure(hs, 'x', :sticky=>:news) TkGrid.rowconfigure(f, 0, :weight=>1) TkGrid.columnconfigure(f, 0, :weight=>1) [f, t] end # # Notebook demonstration: # def makeNotebook nb = Tk::Tile::Notebook.new($BASE, :padding=>6) nb.enable_traversal client = Tk::Tile::Frame.new(nb) nb.add(client, :text=>'Demo', :underline=>0) nb.select(client) scales = Tk::Tile::Frame.new(nb) nb.add(scales, :text=>'Scales') combo = Tk::Tile::Frame.new(nb) nb.add(combo, :text=>'Combobox', :underline=>7) tree = Tk::Tile::Frame.new(nb) nb.add(tree, :text=>'Tree') others = Tk::Tile::Frame.new(nb) nb.add(others, :text=>'Others', :underline=>4) [nb, client, scales, combo, tree, others] end nb, client, scales, combo, tree, others = makeNotebook() # # Side-by side check, radio, and menu button comparison: # def fillMenu(menu) %w(above below left right flush).each{|dir| menu.add(:command, :label=>Tk.tk_call('string', 'totitle', dir), :command=>proc{ menu.winfo_parent.direction(dir) }) } menu.add(:cascade, :label=>'Submenu', :menu=>(submenu = TkMenu.new(menu))) submenu.add(:command, :label=>'Subcommand 1') submenu.add(:command, :label=>'Subcommand 2') submenu.add(:command, :label=>'Subcommand 3') menu.add(:separator) menu.add(:command, :label=>'Quit', :command=>proc{Tk.root.destroy}) end l = Tk::Tile::Labelframe.new(client, :text=>'Themed', :padding=>6) r = TkLabelframe.new(client, :text=>'Standard', :padx=>6, :pady=>6) ## Styled frame cb = Tk::Tile::Checkbutton.new(l, :text=>'Checkbutton', :variable=>$V.ref(:SELECTED), :underline=>2) rb1 = Tk::Tile::Radiobutton.new(l, :text=>'One', :variable=>$V.ref(:CHOICE), :value=>1, :underline=>0) rb2 = Tk::Tile::Radiobutton.new(l, :text=>'Two', :variable=>$V.ref(:CHOICE), :value=>2) rb3 = Tk::Tile::Radiobutton.new(l, :text=>'Three', :variable=>$V.ref(:CHOICE), :value=>3, :underline=>0) btn = Tk::Tile::Button.new(l, :text=>'Button', :underline=>0) mb = Tk::Tile::Menubutton.new(l, :text=>'Menubutton', :underline=>2) m = TkMenu.new(mb) mb.menu(m) fillMenu(m) $entryText = TkVariable.new('Entry widget') e = Tk::Tile::Entry.new(l, :textvariable=>$entryText) e.selection_range(6, :end) ltext_f, ltext = scrolledWidget(l, TkText, true, :width=>12, :height=>5, :wrap=>:none) # NOTE TO MAINTAINERS: # The checkbuttons are -sticky ew / -expand x on purpose: # it demonstrates one of the differences between TCheckbuttons # and standard checkbuttons. # Tk.grid(cb, :sticky=>:ew) Tk.grid(rb1, :sticky=>:ew) Tk.grid(rb2, :sticky=>:ew) Tk.grid(rb3, :sticky=>:ew) Tk.grid(btn, :sticky=>:ew, :padx=>2, :pady=>2) Tk.grid(mb, :sticky=>:ew, :padx=>2, :pady=>2) Tk.grid(e, :sticky=>:ew, :padx=>2, :pady=>2) Tk.grid(ltext_f, :sticky=>:news) TkGrid.columnconfigure(l, 0, :weight=>1) TkGrid.rowconfigure(l, 7, :weight=>1) # text widget (grid is a PITA) ## Orig frame cb = TkCheckbutton.new(r, :text=>'Checkbutton', :variable=>$V.ref(:SELECTED)) rb1 = TkRadiobutton.new(r, :text=>'One', :variable=>$V.ref(:CHOICE), :value=>1) rb2 = TkRadiobutton.new(r, :text=>'Two', :variable=>$V.ref(:CHOICE), :value=>2, :underline=>1) rb3 = TkRadiobutton.new(r, :text=>'Three', :variable=>$V.ref(:CHOICE), :value=>3) btn = TkButton.new(r, :text=>'Button') mb = TkMenubutton.new(r, :text=>'Menubutton', :underline=>3, :takefocus=>true) m = TkMenu.new(mb) mb.menu(m) $V[:rmbIndicatoron] = mb.indicatoron m.add(:checkbutton, :label=>'Indicator?', #' :variable=>$V.ref(:rmbIndicatoron), :command=>proc{mb.indicatoron($V[:rmbIndicatoron])}) m.add(:separator) fillMenu(m) e = TkEntry.new(r, :textvariable=>$entryText) rtext_f, rtext = scrolledWidget(r, TkText, false, :width=>12, :height=>5, :wrap=>:none) Tk.grid(cb, :sticky=>:ew) Tk.grid(rb1, :sticky=>:ew) Tk.grid(rb2, :sticky=>:ew) Tk.grid(rb3, :sticky=>:ew) Tk.grid(btn, :sticky=>:ew, :padx=>2, :pady=>2) Tk.grid(mb, :sticky=>:ew, :padx=>2, :pady=>2) Tk.grid(e, :sticky=>:ew, :padx=>2, :pady=>2) Tk.grid(rtext_f, :sticky=>:news) TkGrid.columnconfigure(l, 0, :weight=>1) TkGrid.rowconfigure(l, 7, :weight=>1) # text widget (grid is a PITA) Tk.grid(l, r, :sticky=>:news, :padx=>6, :pady=>6) TkGrid.rowconfigure(client, 0, :weight=>1) TkGrid.columnconfigure(client, [0, 1], :weight=>1) # # Add some text to the text boxes: # msgs = [ "The cat crept into the crypt, crapped and crept out again", "Peter Piper picked a peck of pickled peppers", "How much wood would a woodchuck chuck if a woodchuck could chuck wood", "He thrusts his fists against the posts and still insists he sees the ghosts", "Who put the bomb in the bom-b-bom-b-bom,", "Is this your sister's sixth zither, sir?", "Who put the ram in the ramalamadingdong?", "I am not the pheasant plucker, I'm the pheasant plucker's mate." ] nmsgs = msgs.size (0...50).each{|n| msg = msgs[n % nmsgs] ltext.insert(:end, "#{n}: #{msg}\n") rtext.insert(:end, "#{n}: #{msg}\n") } # # Scales and sliders pane: # l = Tk::Tile::Labelframe.new(scales, :text=>'Themed', :padding=>6) r = TkLabelframe.new(scales, :text=>'Standard', :padx=>6, :pady=>6) if version?('0.6') # thremed frame scale = Tk::Tile::Scale.new(l, :orient=>:horizontal, :from=>0, :to=>100, :variable=>$V.ref(:SCALE)) vscale = Tk::Tile::Scale.new(l, :orient=>:vertical, :from=>0, :to=>100, :variable=>$V.ref(:VSCALE)) progress = Tk::Tile::Progressbar.new(l, :orient=>:horizontal, :maximum=>100) vprogress = Tk::Tile::Progressbar.new(l, :orient=>:vertical, :maximum=>100) if true def progress.inverted(w, value) if w.mode == 'indeterminate' w.value(value) else w.value(w.maximum - value) end end scale.command {|value| progress.value(value)} vscale.command {|value| progress.inverted(vprogress, value) } else # This would also work, but the Tk scale widgets # in the right hand pane cause some interference when # in autoincrement/indeterminate mode. # progress.variable $V.ref(:SCALE) vprogress.variable $V.ref(:VSCALE) end scale.set(50) vscale.set(50) lmode = Tk::Tile::Label.new(l, :text=>'Progress bar mode') pbmode0 = Tk::Tile::Radiobutton.new(l, :variable=>$V.ref(:PBMODE), :text=>'determinate', :value=>'determinate', :command=>proc{pbMode(progress, vprogress)}) pbmode1 = Tk::Tile::Radiobutton.new(l, :variable=>$V.ref(:PBMODE), :text=>'indeterminate', :value=>'indeterminate', :command=>proc{pbMode(progress, vprogress)}) def pbMode(progress, vprogress) if vprogress.mode != $V[:PBMODE] vprogress.value(vprogress.maximum - vprogress.value) end progress.mode $V[:PBMODE] vprogress.mode $V[:PBMODE] end start = Tk::Tile::Button.new(l, :text=>"Start", :command=>proc{pbStart(progress, vprogress)}) def pbStart(progress, vprogress) # $V[:PBMODE] = 'indeterminate' pbMode(progress, vprogress) progress.start 10 vprogress.start end stop = Tk::Tile::Button.new(l, :text=>'Stop', :command=>proc{pbStop(progress, vprogress)}) def pbStop(progress, vprogress) progress.stop vprogress.stop end Tk.grid(scale, :columnspan=>2, :sticky=>'ew') Tk.grid(progress, :columnspan=>2, :sticky=>'ew') Tk.grid(vscale, vprogress, :sticky=>'nws') Tk.grid(lmode, :sticky=>'we', :columnspan=>2) Tk.grid(pbmode0, :sticky=>'we', :columnspan=>2) Tk.grid(pbmode1, :sticky=>'we', :columnspan=>2) Tk.grid(start, :sticky=>'we', :columnspan=>2) Tk.grid(stop, :sticky=>'we', :columnspan=>2) l.grid_columnconfigure(0, :weight=>1) l.grid_columnconfigure(1, :weight=>1) l.grid_rowconfigure(99, :weight=>1) # standard frame TkScale.new(r, :orient=>:horizontal, :from=>0, :to=>100, :variable=>$V.ref(:SCALE)).grid(:sticky=>'news') TkScale.new(r, :orient=>:vertical, :from=>0, :to=>100, :variable=>$V.ref(:VSCALE)).grid(:sticky=>'nws') r.grid_columnconfigure(0, :weight=>1) r.grid_columnconfigure(1, :weight=>1) r.grid_rowconfigure(99, :weight=>1) else # tile 0.5 or earlier # themed frame scale = Tk::Tile::Scale.new(l, :variable=>$V.ref(:SCALE), :orient=>:horizontal, :from=>0, :to=>100) vscale = Tk::Tile::Scale.new(l, :variable=>$V.ref(:VSCALE), :orient=>:vertical, :from=>-25, :to=>25) progress = Tk::Tile::Progress.new(l, :orient=>:horizontal, :from=>0, :to=>100) vprogress = Tk::Tile::Progress.new(l, :orient=>:vertical, :from=>-25, :to=>25) if true scale.command{|value| progress.set(value)} vscale.command{|value| vprogress.set(value)} else # this would also work. (via TkVariable#trace) v1 = scale.variable v2 = vscale.variable v1.trace('w', proc{ progress.set(v1.value) }) v2.trace('w', proc{ vprogress.set(v2.value) }) end Tk.grid(scale, :columnspan=>2, :sticky=>:ew) Tk.grid(progress, :columnspan=>2, :sticky=>:ew) Tk.grid(vscale, vprogress, :sticky=>:nws) TkGrid.columnconfigure(l, 0, :weight=>1) TkGrid.columnconfigure(l, 1, :weight=>1) # standard frame TkScale.new(r, :variable=>$V.ref(:SCALE), :orient=>:horizontal, :from=>0, :to=>100).grid(:sticky=>'news') TkScale.new(r, :variable=>$V.ref(:VSCALE), :orient=>:vertical, :from=>-25, :to=>25).grid(:sticky=>'nws') TkGrid.columnconfigure(r, 0, :weight=>1) TkGrid.columnconfigure(r, 1, :weight=>1) end # layout frames Tk.grid(l, r, :sticky=>'nwes', :padx=>6, :pady=>6) scales.grid_columnconfigure(0, :weight=>1) scales.grid_columnconfigure(1, :weight=>1) scales.grid_rowconfigure(0, :weight=>1) # # Command box: # cmd = Tk::Tile::Frame.new($BASE) b_close = Tk::Tile::Button.new(cmd, :text=>'Close', :underline=>0, :default=>:normal, :command=>proc{Tk.root.destroy}) b_help = Tk::Tile::Button.new(cmd, :text=>'Help', :underline=>0, :default=>:normal, :command=>proc{showHelp()}) Tk.grid('x', b_close, b_help, :pady=>[6, 4], :padx=>4) TkGrid.columnconfigure(cmd, 0, :weight=>1) # # Set up accelerators: # $ROOT.bind('KeyPress-Escape', proc{Tk.event_generate(b_close, '')}) $ROOT.bind('', proc{Tk.event_generate(b_help, '')}) Tk::Tile::KeyNav.enableMnemonics($ROOT) Tk::Tile::KeyNav.defaultButton(b_help) Tk.grid($TOOLBARS[0], '-', :sticky=>:ew) Tk.grid($TOOLBARS[1], '-', :sticky=>:ew) Tk.grid(control, nb, :sticky=>:news) Tk.grid(cmd, '-', :sticky=>:ew) TkGrid.columnconfigure($ROOT, 1, :weight=>1) TkGrid.rowconfigure($ROOT, 2, :weight=>1) # # Add a menu # menu = TkMenu.new($BASE) $ROOT.menu(menu) m_file = TkMenu.new(menu, :tearoff=>0) menu.add(:cascade, :label=>'File', :underline=>0, :menu=>m_file) m_file.add(:command, :label=>'Open', :underline=>0, :compound=>:left, :image=>$ICON['open']) m_file.add(:command, :label=>'Save', :underline=>0, :compound=>:left, :image=>$ICON['save']) m_file.add(:separator) m_f_test = TkMenu.new(menu, :tearoff=>0) m_file.add(:cascade, :label=>'Test submenu', :underline=>0, :menu=>m_f_test) m_file.add(:checkbutton, :label=>'Text check', :underline=>5, :variable=>$V.ref(:MENUCHECK1)) m_file.insert(:end, :separator) if Tk.windowingsystem != 'x11' TkConsole.create m_file.insert(:end, :checkbutton, :label=>'Console', :underline=>5, :variable=>$V.ref(:CONSOLE), :command=>proc{toggle_console()}) def toggle_console if TkComm.bool($V[:CONSOLE]) TkConsole.show else TkConsole.hide end end end m_file.add(:command, :label=>'Exit', :underline=>1, :command=>proc{Tk.event_generate(b_close, '')}) %w(One Two Three Four).each{|lbl| m_f_test.add(:radiobutton, :label=>lbl, :variable=>$V.ref(:MENURADIO1)) } # Add Theme menu. # menu.add(:cascade, :label=>'Theme', :underline=>3, :menu=>makeThemeMenu(menu)) setTheme($V[:THEME]) # # Combobox demo pane: # values = %w(list abc def ghi jkl mno pqr stu vwx yz) 2.times {|i| cb = Tk::Tile::Combobox.new( combo, :values=>values, :textvariable=>$V.ref(:COMBO)) cb.pack(:side=>:top, :padx=>2, :pady=>2, :expand=>false, :fill=>:x) if i == 1 cb.ttk_state :readonly begin cb.current = 3 # ignore if unsupported (tile0.4) rescue end end } # # Treeview widget demo pane: # if version?('0.5') treeview = nil # avoid 'undefined' error scrollbar = Tk::Tile::Scrollbar.new(tree, :command=>proc{|*args| treeview.yview(*args)}) treeview = Tk::Tile::Treeview.new(tree, :columns=>%w(Class), :padding=>4, :yscrollcommand=>proc{|*args| scrollbar.set(*args)}) Tk.grid(treeview, scrollbar, :sticky=>'news') tree.grid_columnconfigure(0, :weight=>1) tree.grid_rowconfigure(0, :weight=>1) tree.grid_propagate(0) # Add initial tree node: # Later nodes will be added in <> binding. treeview.insert('', 0, :id=>'.', :text=>'Main Window', :open=>false, :values=>[TkWinfo.classname('.')]) treeview.headingconfigure('#0', :text=>'Widget') treeview.headingconfigure('Class', :text=>'Class') treeview.bind('', proc{fillTree(treeview)}) def fillTree(treeview) id = treeview.focus_item unless TkWinfo.exist?(id) treeview.delete(id) end # Replace tree item children with current list of child windows. treeview.delete(treeview.children(id)) for child in TkWinfo.children(id) treeview.insert(id, :end, :id=>child, :text=>TkWinfo.appname(child), :open=>false, :values=>[TkWinfo.classname(child)]) unless TkWinfo.children(child).empty? # insert dummy child to show [+] indicator treeview.insert(child, :end) end end end else Tk::Tile::Label.new(tree, :text=>'Treeview is supported on tile 0.5 or later...').pack end # # Other demos: # $Timers = {:StateMonitor=>nil, :FocusMonitor=>nil} begin msg = Tk::Tile::Label.new(others, :justify=>:left, :wraplength=>300) rescue msg = TkMessage.new(others, :aspect=>200) end $Desc = {} showDescription = TkBindTag.new showDescription.bind('Enter', proc{|w| msg.text($Desc[w.path])}, '%W') showDescription.bind('Leave', proc{|w| msg.text('')}, '%W') [ [ :trackStates, "Widget states...", "Display/modify widget state bits" ], [ :scrollbarResizeDemo, "Scrollbar resize behavior...", "Shows how Tile and standard scrollbars differ when they're sized too large" ], [ :trackFocus, "Track keyboard focus..." , "Display the name of the widget that currently has focus" ], [ :repeatDemo, "Repeating buttons...", "Demonstrates custom classes (see demos/repeater.tcl)" ] ].each{|demo_cmd, label, description| b = Tk::Tile::Button.new(others, :text=>label, :command=>proc{ self.__send__(demo_cmd) }) $Desc[b.path] = description b.bindtags <<= showDescription b.pack(:side=>:top, :expand=>false, :fill=>:x, :padx=>6, :pady=>6) } msg.pack(:side=>:bottom, :expand=>true, :fill=>:both) # # Scrollbar resize demo: # $scrollbars = nil def scrollbarResizeDemo if $scrollbars begin $scrollbars.destroy rescue end end $scrollbars = TkToplevel.new(:title=>'Scrollbars', :geometry=>'200x200') f = TkFrame.new($scrollbars, :height=>200) tsb = Tk::Tile::Scrollbar.new(f, :command=>proc{|*args| sbstub(tsb, *args)}) sb = TkScrollbar.new(f, :command=>proc{|*args| sbstub(sb, *args)}) Tk.grid(tsb, sb, :sticky=>:news) sb.set(0, 0.5) # prevent backwards-compatibility mode for old SB f.grid_columnconfigure(0, :weight=>1) f.grid_columnconfigure(1, :weight=>1) f.grid_rowconfigure(0, :weight=>1) f.pack(:expand=>true, :fill=>:both) end # # Track focus demo: # $FocusInf = TkVariable.new_hash $focus = nil def trackFocus if $focus begin $focus.destroy rescue end end $focus = TkToplevel.new(:title=>'Keyboard focus') i = 0 [ ["Focus widget:", :Widget], ["Class:", :WidgetClass], ["Next:", :WidgetNext], ["Grab:", :Grab], ["Status:", :GrabStatus] ].each{|label, var_index| Tk.grid(Tk::Tile::Label.new($focus, :text=>label, :anchor=>:e), Tk::Tile::Label.new($focus, :textvariable=>$FocusInf.ref(var_index), :width=>40, :anchor=>:w, :relief=>:groove), :sticky=>:ew) i += 1 } $focus.grid_columnconfigure(1, :weight=>1) $focus.grid_rowconfigure(i, :weight=>1) $focus.bind('Destroy', proc{Tk.after_cancel($Timers[:FocusMonitor])}) focusMonitor end def focusMonitor $FocusInf[:Widget] = focus_win = Tk.focus if focus_win $FocusInf[:WidgetClass] = focus_win.winfo_classname $FocusInf[:WidgetNext] = Tk.focus_next(focus_win) else $FocusInf[:WidgetClass] = $FocusInf[:WidgetNext] = '' end $FocusInf[:Grab] = grab_wins = Tk.current_grabs unless grab_wins.empty? $FocusInf[:GrabStatus] = grab_wins[0].grab_status else $FocusInf[:GrabStatus] = '' end $Timers[:FocusMonitor] = Tk.after(200, proc{ focusMonitor() }) end # # Widget state demo: # $Widget = TkVariable.new TkBindTag::ALL.bind('Control-Shift-ButtonPress-1', proc{|w| $Widget.value = w updateStates() Tk.callback_break }, '%W') $states_list = %w(active disabled focus pressed selected background indeterminate invalid default) $states_btns = {} $states = nil $State = TkVariable.new_hash def trackStates if $states begin $state.destroy rescue end end $states = TkToplevel.new(:title=>'Widget states') l_inf = Tk::Tile::Label.new($states, :text=>"Press Control-Shift-Button-1 on any widget") l_lw = Tk::Tile::Label.new($states, :text=>'Widget:', :anchor=>:e, :relief=>:groove) l_w = Tk::Tile::Label.new($states, :textvariable=>$Widget, :anchor=>:w, :relief=>:groove) Tk.grid(l_inf, '-', :sticky=>:ew, :padx=>6, :pady=>6) Tk.grid(l_lw, l_w, :sticky=>:ew) $states_list.each{|st| cb = Tk::Tile::Checkbutton.new($states, :text=>st, :variable=>$State.ref(st), :command=>proc{ changeState(st) }) $states_btns[st] = cb Tk.grid('x', cb, :sticky=>:nsew) } $states.grid_columnconfigure(1, :weight=>1) f_cmd = Tk::Tile::Frame.new($states) Tk.grid('x', f_cmd, :sticky=>:nse) b_close = Tk::Tile::Button.new(f_cmd, :text=>'Close', :command=>proc{ $states.destroy }) Tk.grid('x', b_close, :padx=>4, :pady=>[6,4]) f_cmd.grid_columnconfigure(0, :weight=>1) $states.bind('KeyPress-Escape', proc{Tk.event_generate(b_close, '')}) $states.bind('Destroy', proc{Tk.after_cancel($Timers[:StateMonitor])}) stateMonitor() end def stateMonitor updateStates() if $Widget.value != '' $Timers[:StateMonitor] = Tk.after(200, proc{ stateMonitor() }) end def updateStates $states_list.each{|st| begin $State[st] = $Widget.window.ttk_instate(st) rescue $states_btns[st].ttk_state('disabled') else $states_btns[st].ttk_state('!disabled') end } end def changeState(st) if $Widget.value != '' if $State.bool_element(st) $Widget.window.ttk_state(st) else $Widget.window.ttk_state("!#{st}") end end end # # Repeating buttons demo: # def repeatDemo if defined?($repeatDemo) && $repeatDemo.exist? $repeatDemo.deiconify; return end $repeatDemo = TkToplevel.new(:title=>'Repeating button') f = Tk::Tile::Frame.new($repeatDemo) b = Tk::Tile::Button.new(f, :class=>'Repeater', :text=>'Press and hold') if version?('0.6') p = Tk::Tile::Progressbar.new(f, :orient=>:horizontal, :maximum=>10) else # progressbar is not supported p = Tk::Tile::Progress.new(f, :orient=>:horizontal, :from=>0, :to=>10) def p.step i = self.get + 1 i = self.from if i > self.to self.set(i) end end b.command {p.step} b.pack(:side=>:left, :expand=>false, :fill=>:none, :padx=>6, :pady=>6) p.pack(:side=>:right, :expand=>true, :fill=>:x, :padx=>6, :pady=>6) f.pack(:expand=>true, :fill=>:both) end Tk.mainloop ================================================ FILE: ext/tk/sample/tkextlib/tile/iconlib.tcl ================================================ array set ImgData { bold {R0lGODlhEAAQAJEAANnZ2QAAAP///////yH5BAEAAAAALAAAAAAQABAAAAI6hI+py60U3wj+ RYQFJYRvEWFBCeFbRFhQQvhG8YPgX0RYUEL4FhEWlBC+RYQFJYQPFN8IPqYut/8hBQA7} copy {R0lGODlhEAAQAJEAANnZ2QAAAP///wAAhCH5BAEAAAAALAAAAAAQABAAAAJUhI8JFJ/gY4iI UEL4FyIiFIXgW0iEUDgfACBI9pzMAAGRiIghWSMDECR7JEKGtkFIRFBG+TIQKDQxtgzcDcmX IfgwQrFlCD4MyZch+EDzj+Bj6mYBADs=} cut {R0lGODlhEAAQAJEAANnZ2QAAAAAAhP///yH5BAEAAAAALAAAAAAQABAAAAJFhI+pcUHwEeIi E0gACIKPEAFBIXy0gMg8EhM+YmQiKSL4eAIiJMI/EQEhQGYGYiQIQAg+iAkIATIzECMBIgT/ RBARERlSADs=} dragfile {R0lGODlhGAAYAKIAANnZ2TMzM////wAAAJmZmf///////////yH5BAEAAAAALAAAAAAYABgA AAPACBi63IqgC4GiyxwogaAbKLrMgSKBoBoousyBogEACIGiyxwoKgGAECI4uiyCExMTOACB osuNpDoAGCI4uiyCIkREOACBosutSDoAgSI4usyCIjQAGCi63Iw0ACEoOLrMgiI0ABgoutyM NAAhKDi6zIIiNAAYKLrcjDQAISg4usyCIjQAGCi63Iw0AIGiiqPLIyhCA4CBosvNSAMQKKo4 ujyCIjQAGCi63Iw0AIGiy81IAxCBpMu9GAMAgKPL3QgJADs=} dragicon {R0lGODlhGAAYALMAANnZ2TMzM/////8zM8zMzGYAAAAAAJmZmQCZMwAzZgCZzGZmZv////// /////////yH5BAEAAAAALAAAAAAYABgAAAT/EMAgJ60SAjlBgEJOSoMIEMgZoJCT0iADBFIG KOSkNMwAAABhwiHnIEKIIIQQAQIZhBBwyDmKEMIEE0yABoAghIBDzlGEENDIaQAIQgg45BwF CinPOccAECYcUiKEEBFCiHPgMQAEIcQYYyABBUGIQCHlMQCEScZAAhKEEApCECGOARAEIQQp BRGIpAyCJCGOASBAISdEcqJAVBLiGABggELOAJGUKyiVhDgGABigkJMEhNAKSqkEhTgGgCCl FCQEGIJSSiUhjgEgQCEnJVBJmYQ4BoAAhZyTQCVnEuIYAAIUckoCk5xSiGMACFDISSs9BoBg rRXQMQAEKOSklR4DEUAI8MhJ6wwGAACgkZNWCkAEADs=} error {R0lGODlhIAAgAKIAANnZ2YQAAP8AAISEhP///////////////yH5BAEAAAAALAAAAAAgACAA AAP/CLoMGLqKoMvtGIqiqxEYCLrcioGiyxwIusyBgaLLLRiBoMsQKLrcjYGgu4Giy+2CAkFX A0WX2wXFIOgGii7trkCEohsDCACBoktEKLpKhISiGwAIECiqSKooukiqKKoxgACBooukKiIo SKooujGDECi6iqQqsopEV2MQAkV3kXQZRXdjEAJFl5F0FUWXY3ACRZcFSRdFlyVwJlB0WZB0 UXRZAmcCRZeRdBVFl2NwAkV3kXQZRXdjcAJFV5FURVaR6GoMDgSKLpKqiKAgqaLoxgwOBIoq kiqKLpIqimrM4ECg6BIRiq4SIaHoxgyCBoou7a5AhKIbMzgAAIGiy+2CTWJmBhAAAkWX2wXF zCDoBooud2PMDIKuRqDocgtGzMwg6O4Eii5z4Kgi6DIMhqLoagQGjiqCLvPgYOgqji6CLrfi 6DIj6HI7jq4i6DIkADs=} file {R0lGODlhCwANAJEAANnZ2QAAAP///////yH5BAEAAAAALAAAAAALAA0AAAIyhI9G8Q0AguSH AMQdxQgxEyEFQfItICQokYgEBMm3gBCKLRIQJN8CQii2SECQfAug+FgAOw==} folder {R0lGODlhEAANAKIAANnZ2YSEhMbGxv//AP///wAAAP///////yH5BAEAAAAALAAAAAAQAA0A AANjCIqhiqDLITgyEgi6GoIjIyMYugCBpMsaWBA0giMjIzgyUYBBMjIoIyODEgVBODIygiMj E1gQJIMyMjIoI1GAQSMjODIyghMFQSgjI4MyMhJYEDSCIyMjODJRgKHLXAiApcucADs=} hourglass {R0lGODlhIAAgAKIAANnZ2YAAAAAAAP8AAP///8DAwICAgP///yH5BAEAAAAALAAAAAAgACAA AAPZCLrc/jDKSau9OGcUuqyCoMvNGENVhaMrCLrcjaLLgqDL7WhFVIVVZoKgy+1oRUSFVWaC oMvtaEVEhVVmgqDL7WhFRIVVZoKgy+1oVVaCJWaCoMvtgKxISrBMEHS5fZEVSRkKgi63NzIq EwRdbndkVCYIutzeyIqqDAVBl9sXWRFJYZkg6HI7ICsiKqwyEwRdbkcrIhKsMhMEXW5HKyIp lDITBF1uRysyEiwxEwRdbkcrIyuUEhMEXW5H0WVB0OVujKGqwtEVBF1uRtHlRdDl9odRTlrt xRmjBAA7} info {R0lGODlhIAAgAKIAANnZ2YSEhMbGxv///wAA/wAAAP///////yH5BAEAAAAALAAAAAAgACAA AAP/CLoMGLqKoMvtGCo4uhKBgaDLDRghOLqsghEIuryBgqPLPSiBoMsQOLojhEQkOLpTCLob OLqKpIujq4WgC4Gju0i6OLpbCKohOLorhEQkOLorhaAQOLrc3qgCIARHl9sbSQUEji4j6RKO Lk9hQODosiKp4ujyFIbi6LIiqeLo8hSG4uiyIqni6PIUhuLosiKp4ujyFIYKji4PkiqOLkth BASOLg+SKo4uV2AEhODoMpIqju5KYShA4Ogqku7i6E4FRgAAYOHocvugiohAUC0cXe7GiohA 0IUSHF3uQamICATdrULB0WUVrIqIQNBlCCwVHF2pwsJQRdDlDYyoKsHRPMLQDQRdbsDQqBmc wlBF0OV2jJqZwggEXW5vVDMVgaDL7Y5qKgJBl9sfVUUg6HL7AxSKoMvtr1AEgi5DAgA7} italic {R0lGODlhEAAQAJEAANnZ2QAAAP///////yH5BAEAAAAALAAAAAAQABAAAAIrhI+py+1A4hN8 hIjINBITPlpEZBqJCR8tIjKNxISPFhGZQOITfExdbv9FCgA7} new {R0lGODlhEAAQAJEAANnZ2QAAAP///////yH5BAEAAAAALAAAAAAQABAAAAJFhI95FN8IvgXJ jyD4ECQ/JAh+kPyICIIdJP+CYAfJvyDYQfIvCHaQ/AuCHST/gmAHyb8g2EHyLwh2kPwLgk3x MQg+pu4WADs=} open {R0lGODlhEAAQAKIAANnZ2QAAAP//AP///4SEAP///////////yH5BAEAAAAALAAAAAAQABAA AANZCLrczigUQZc1EDQgEHSZAwMgIhB0NQIDQkYwdANBNUZwZGQEJxBUQwZlZGRQAkE1RnAE Q5dVcCSQdDcAYySQdDcAISSQdDcAASKQdDcAAQBDlwNBl9sfApQAOw==} openfold {R0lGODlhEAANAKIAANnZ2YSEhP///8bGxv//AAAAAP///////yH5BAEAAAAALAAAAAAQAA0A AANgCIqhiqDLgaIaCLoagkNDIxi6AIFCQ0M4KKpRgCFDQzg0NIQThaHLSxgVKLochRMVMkhD Q4M0VBFYEDKEQ0NDOFFRgCE0NEhDQ4MVBRAoNDSEQ0NRWAAYuqyFBQBYurwJADs=} overstrike {R0lGODlhEAAQAJEAANnZ2QAAAP///////yH5BAEAAAAALAAAAAAQABAAAAI3hI+py80Uh+Aj RFhQCP8iMILgWwRGEHyLwAiCbxEYQfCB4iPBhwiMIPgXYREEHyEiguBj6nI7FQA7} palette {R0lGODlhEAAQAKIAANnZ2QAAAP//AP////8A/4QAhP8AAAD//yH5BAEAAAAALAAAAAAQABAA AANtCLrcjqGBoMsRKCMTgaALMSgDAYMSCKoxgAFBITgSAIAQEhUIARCAEgAQOBAwghMQEwga MoIjIxAIEgCAEBEyKBAgg4GgGxAIYTGCgaALcRgQIIGgCwEYICODgaALITgyEoGguxiqCLrc /lChBAA7} passwd {R0lGODlhIAAgAMQAANnZ2QAAAICAgICAAP///7CwsMDAwMjIAPjIAOjo6Pj4AODg4HBwcMj4 ANjY2JiYANDQ0MjIyPj4yKCgoMiYAMjImDAwAMjIMJiYmJCQkP////////////////////// /yH5BAEAAAAALAAAAAAgACAAAAX/ICCOIhiIIgiII1maZSCMQnCeJyAIQiAIAiAMwxCcJwkk EAQRCIUwGMSBDEEAAuJIlgKRJEEgGAMRBIGiDENQlqNAJAsYCEwgEEEgBAHSIEMAAuJIAgKR LEsgGEMgCEJgBMqhHENQlgJILMsSCMRABEFgGAESHMcRgIA4kgKxOIsTBAOhKAITKEGDHMhD kqIAEqAjisJAgIooBkpwNMcTgIA4jgLhOBAkEAOhKIoSKEGDIMcTkKQICgQEQQIxEIqiBEpw IMdxPAEIiCMJCEQUMUQ0EIqiHIfSIM3xBGUpCiABCUQyEMqhHMiBHMjxBCAgjuQoEAKxRANB HMqhHM1x/zxDUJajQIACsUTDQBAEIR3IcQRDAALiSIoCYQiEE03gII7HQR3BEICAOJICYRSC QDjRNE1CAAzVQR3WE5AkAAqEUQiFQEARBAUAAAzHQR3BEICAOI4CUQhFIBAREwXjUFUHdQRD QJJAABbCFAhEJBgBAADAMAwXdQRDAALiCAhEIRQCYRiCEZDjUFFHMAQkIBAFOAmTQBiFUAQg II7AUFXUEQwBCQjEJExBkBRCEZCjMIBD9RxDAALiGEzCFBBYIRTBOI7AQB1DMIoCMQkYGAjL JEwBCIgjOVDDEJCAQGACJiTTJEwBSY5BEJAiSCCwTAiCZBKmAATEkSzNQBCCYCDBJgELTNMk g0AMEgwTAhAQR7I0zYARgvM8TyAIznMMAQA7} paste {R0lGODlhEAAQAKIAANnZ2QAAAP//AISEAISEhP///wAAhP///yH5BAEAAAAALAAAAAAQABAA AANwCLrcjqGBoKsYqiKrCDSGBkMiJJCGAgCDKBB0gwYDIKYwdJUIAyBokIaGBmloAhBiaAgH TdcCEIKGBsmwVM0AIYaGcAxL1coQgoYGySoisMzMAoeGxrB01QJpaMiwMHTLAEPVsHTVEHTR dBlBlxswAQA7} print {R0lGODlhEAAQAKIAANnZ2QAAAP///4SEhP//AP///////////yH5BAEAAAAALAAAAAAQABAA AANZCLrcjqG7CLqBoquBoBuCoSqBoBsouhoIuiEYqrKBoIGiqwEYEIChyxAIEYGgywEYgKHL DAgRCLozgwABARgIukSEABEBGLq8gAEQCLobgAEAgKHLgaDLzZgAOw==} question {R0lGODlhIAAgAKIAANnZ2YSEhMbGxv///wAAAAAA/////////yH5BAEAAAAALAAAAAAgACAA AAP/CLoMGLqKoMvtGCo4uhKBgaDLDRghOLqsghEIuryBgqPLPSiBoMsQOLrcjYSgu4GjO4Kl Kzi6Qwi6EDi6I4UyU1VYgqM7hKAagqM7VTg6VYWFoztCCAqBo6tVWDVThVU4ukqBACE4ulqF VSNVWIWjq0IYEDi6K4UlU1VYOLpMgRA4uryCpTi6PIShOLq8hVU4uqyEoTi6vIUlOLqshKE4 uryFhaPLSxgqOLrc3kgoAgJHl0ewSnB0eQhDIQRHl6uwCkeXhTAUIHB0uQqrcHSZAiMAAJBw dFcKS3B0lwIjAkGVcHS5GykiAkEXSHB0uQeFIiIQdJcIBUeXVZAoIgJBT5chkFRwdIUICUMV QZc3MIKIBEcJQzcQdLkBQ4NmcAhDFUGX2zFoZggjEHS5vRHNUASCLrc7oqEIBF1uf0QUgaDL 7Q9QKIIut79CEQi6DAkAOw==} redo {R0lGODlhEAAQAJEAANnZ2QAAhP///////yH5BAEAAAAALAAAAAAQABAAAAIvhI+py+1vSByC jxAYQXDMwsyAggQAQBB8iwgMgg8REQgUwqbYBDsIPqYutz+MgBQAOw==} save {R0lGODlhEAAQAJEAANnZ2QAAAISEAP///yH5BAEAAAAALAAAAAAQABAAAAJWhI9pFB8RIIRC +BYQFqQQvkWEBSmEbyFhQQrhW0hYkEL4FhIWpBC+hYQFSYxvIgFAoXy0AAiSGP8kAIIkxgcI CSBEQvEBQgIIkVB8gJAAAhgfj+BjWgEAOw==} underline {R0lGODlhEAAQAJEAANnZ2QAAAP///////yH5BAEAAAAALAAAAAAQABAAAAI3hI+py60UBy4I vkVcBMG/iIsg+BdxEQT/Ii6C4F/ERRD8i7gIgn8RF0HwkWITfExFin8EH1OXCwA7} undo {R0lGODlhEAAQAJEAANnZ2QAAhP///////yH5BAEAAAAALAAAAAAQABAAAAIuhI+py+2vSByC HxdxQCHsCIg7oAAAEUHwLTAiKIQPgRSbYMfd3VEIH1OX2x8mUgA7} warning {R0lGODlhIAAgAKIAANnZ2YSEAP//AMbGxgAAAISEhP///////yH5BAEAAAAALAAAAAAgACAA AAP/CLq8gREIutz+KESGEHS5vVGIiAxSIehy+6JAUaUqBF1uBxQoukOFhaDL7RgoukKFhaDL 3RgoujqEVQi63IyBortUWAi63IuBostDWIWgy60YIjKERCMiSFUIutyAISKCpCoiOFSFoMsd KCpIqiKCQlUIusyBooqkKiIoQ1UIuryBooqkiqJKVQi6rIGii6SKojpUWAi6DIGiG0RIgaJL VQi6HCi6MoREg6I7VFgIuhsoukqEhKKrVFgIuhoouhuEgaKrQ1iFoAuBortDOCi6S4WFoBso uiyEostDWIWgGii63K6IqgAAIVB0WQaJBkV3h7AKAAJFl4WQiFB0mQoLRyBQdFkJiQhFl4ew CgJFl3WQaFB0WQirIFB0ud0RVVWg6HJ7o6GqAgwUXW5fNFRVhQCBpMvti0oVABCwdLndEehi 6XI7I4AEADs=} } ================================================ FILE: ext/tk/sample/tkextlib/tile/readme.txt ================================================ All of *.tcl and under themes/ directory (except kroc.rb) are quoted from Tcl/Tk's Tile extension. Please read Orig_LICENSE.txt. ================================================ FILE: ext/tk/sample/tkextlib/tile/repeater.tcl ================================================ # # $Id$ # # Demonstration of custom classes. # # The Tile button doesn't have built-in support for autorepeat. # Instead of adding -repeatdelay and -repeatinterval options, # and all the extra binding scripts required to deal with them, # we create a custom widget class for autorepeating buttons. # # Usage: # ttk::button .b -class Repeater [... other options ...] # # TODO: # Use system settings for repeat interval and initial delay. # # Notes: # Repeater buttons work more like scrollbar arrows than # Tk repeating buttons: they fire once immediately when # first pressed, and $State(delay) specifies the initial # interval before the button starts autorepeating. # namespace eval tile::Repeater { variable State set State(timer) {} ;# [after] id of repeat script set State(interval) 100 ;# interval between repetitions set State(delay) 300 ;# delay after initial invocation } ### Class bindings. # bind Repeater { %W state active } bind Repeater { %W state !active } bind Repeater { tile::Repeater::Activate %W } bind Repeater <> { tile::Repeater::Activate %W } bind Repeater { tile::Repeater::Press %W } bind Repeater { tile::Repeater::Release %W } bind Repeater { tile::Repeater::Pause %W } bind Repeater { tile::Repeater::Resume %W } ;# @@@ see below # @@@ Workaround for metacity-induced bug: bind Repeater \ { if {"%d" ne "NotifyUngrab"} { tile::Repeater::Resume %W } } ### Binding procedures. # ## Activate -- Keyboard activation binding. # Simulate clicking the button, and invoke the command once. # proc tile::Repeater::Activate {w} { $w instate disabled { return } set oldState [$w state pressed] update idletasks; after 100 $w state $oldState after idle [list $w invoke] } ## Press -- ButtonPress-1 binding. # Invoke the command once and start autorepeating after # $State(delay) milliseconds. # proc tile::Repeater::Press {w} { variable State $w instate disabled { return } $w state pressed $w invoke after cancel $State(timer) set State(timer) [after $State(delay) [list tile::Repeater::Repeat $w]] } ## Release -- ButtonRelease binding. # Stop repeating. # proc tile::Repeater::Release {w} { variable State $w state !pressed after cancel $State(timer) } ## Pause -- B1-Leave binding # Temporarily suspend autorepeat. # proc tile::Repeater::Pause {w} { variable State $w state !pressed after cancel $State(timer) } ## Resume -- B1-Enter binding # Resume autorepeat. # proc tile::Repeater::Resume {w} { variable State $w instate disabled { return } $w state pressed $w invoke after cancel $State(timer) set State(timer) [after $State(interval) [list tile::Repeater::Repeat $w]] } ## Repeat -- Timer script # Invoke the command and reschedule another repetition # after $State(interval) milliseconds. # proc tile::Repeater::Repeat {w} { variable State $w instate disabled { return } $w invoke set State(timer) [after $State(interval) [list tile::Repeater::Repeat $w]] } #*EOF* ================================================ FILE: ext/tk/sample/tkextlib/tile/themes/blue/blue.tcl ================================================ # blue.tcl - Copyright (C) 2004 Pat Thoyts # # blue.tcl,v 1.27 2005/10/08 14:56:57 jenglish Exp # # namespace eval tile::theme::blue { package provide tile::theme::blue 0.7 set imgdir [file join [file dirname [info script]] blue] array set I [tile::LoadImages $imgdir *.gif] array set colors { -frame "#6699cc" -lighter "#bcd2e8" -window "#e6f3ff" -selectbg "#ffff33" -selectfg "#000000" -disabledfg "#666666" } style theme create blue -settings { style default . \ -borderwidth 1 \ -background $colors(-frame) \ -fieldbackground $colors(-window) \ -troughcolor $colors(-lighter) \ -selectbackground $colors(-selectbg) \ -selectforeground $colors(-selectfg) \ ; style map . -foreground [list disabled $colors(-disabledfg)] ## Buttons. # style default TButton -padding "10 0" style layout TButton { Button.button -children { Button.focus -children { Button.padding -children { Button.label } } } } style element create button image $I(button-n) \ -map [list pressed $I(button-p) active $I(button-h)] \ -border 4 -sticky ew style element create Checkbutton.indicator image $I(check-nu) \ -width 24 -sticky w -map [list \ {!disabled active selected} $I(check-hc) \ {!disabled active} $I(check-hu) \ {!disabled selected} $I(check-nc) ] style element create Radiobutton.indicator image $I(radio-nu) \ -width 24 -sticky w -map [list \ {!disabled active selected} $I(radio-hc) \ {!disabled active} $I(radio-hu) \ selected $I(radio-nc) ] style default TMenubutton -relief raised -padding {10 2} ## Toolbar buttons. # style default Toolbutton \ -width 0 -relief flat -borderwidth 2 -padding 4 \ -background $colors(-frame) -foreground #000000 ; style map Toolbutton -background [list active $colors(-selectbg)] style map Toolbutton -foreground [list active $colors(-selectfg)] style map Toolbutton -relief { disabled flat selected sunken pressed sunken active raised } ## Entry widgets. # style default TEntry \ -selectborderwidth 1 -padding 2 -insertwidth 2 -font TkTextFont style default TCombobox \ -selectborderwidth 1 -padding 2 -insertwidth 2 -font TkTextFont ## Notebooks. # style default TNotebook.Tab -padding {4 2 4 2} style map TNotebook.Tab \ -background \ [list selected $colors(-frame) active $colors(-lighter)] \ -padding [list selected {4 4 4 2}] ## Labelframes. # style default TLabelframe -borderwidth 2 -relief groove ## Scrollbars. # style layout Vertical.TScrollbar { Scrollbar.trough -children { Scrollbar.uparrow -side top Scrollbar.downarrow -side bottom Scrollbar.uparrow -side bottom Vertical.Scrollbar.thumb -side top -expand true -sticky ns } } style layout Horizontal.TScrollbar { Scrollbar.trough -children { Scrollbar.leftarrow -side left Scrollbar.rightarrow -side right Scrollbar.leftarrow -side right Horizontal.Scrollbar.thumb -side left -expand true -sticky we } } style element create Horizontal.Scrollbar.thumb image $I(sb-thumb) \ -map [list {pressed !disabled} $I(sb-thumb-p)] -border 3 style element create Vertical.Scrollbar.thumb image $I(sb-vthumb) \ -map [list {pressed !disabled} $I(sb-vthumb-p)] -border 3 foreach dir {up down left right} { style element create ${dir}arrow image $I(arrow${dir}) \ -map [list \ disabled $I(arrow${dir}) \ pressed $I(arrow${dir}-p) \ active $I(arrow${dir}-h)] \ -border 1 -sticky {} } ## Scales. # style element create Scale.slider \ image $I(slider) -map [list {pressed !disabled} $I(slider-p)] style element create Vertical.Scale.slider \ image $I(vslider) -map [list {pressed !disabled} $I(vslider-p)] style element create Horizontal.Progress.bar \ image $I(sb-thumb) -border 2 style element create Vertical.Progress.bar \ image $I(sb-vthumb) -border 2 } } ================================================ FILE: ext/tk/sample/tkextlib/tile/themes/blue/pkgIndex.tcl ================================================ # Package index for tile demo pixmap themes. if {[file isdirectory [file join $dir blue]]} { package ifneeded tile::theme::blue 0.7 \ [list source [file join $dir blue.tcl]] } ================================================ FILE: ext/tk/sample/tkextlib/tile/themes/keramik/keramik.tcl ================================================ # keramik.tcl - # # A sample pixmap theme for the tile package. # # Copyright (c) 2004 Googie # Copyright (c) 2004 Pat Thoyts # # $Id$ package require Tk 8.4; # minimum version for Tile package require tile 0.5; # depends upon tile 0.5 namespace eval tile { namespace eval theme { namespace eval keramik { variable version 0.3.2 } } } namespace eval tile::theme::keramik { variable imgdir [file join [file dirname [info script]] keramik] variable I array set I [tile::LoadImages $imgdir *.gif] variable colors array set colors { -frame "#cccccc" -lighter "#cccccc" -window "#ffffff" -selectbg "#eeeeee" -selectfg "#000000" -disabledfg "#aaaaaa" } style theme create keramik -parent alt -settings { # ----------------------------------------------------------------- # Theme defaults # style default . \ -borderwidth 1 \ -background $colors(-frame) \ -troughcolor $colors(-lighter) \ -font TkDefaultFont \ ; style map . -foreground [list disabled $colors(-disabledfg)] # ----------------------------------------------------------------- # Button elements # - the button has a large rounded border and needs a bit of # horizontal padding. # - the checkbutton and radiobutton have the focus drawn around # the whole widget - hence the new layouts. # style layout TButton { Button.background Button.button -children { Button.focus -children { Button.label } } } style layout Toolbutton { Toolbutton.background Toolbutton.button -children { Toolbutton.focus -children { Toolbutton.label } } } style element create button image $I(button-n) \ -border {8 6 8 16} -padding {6 6} -sticky news \ -map [list {pressed !disabled} $I(button-p) \ {active !selected} $I(button-h) \ selected $I(button-s) \ disabled $I(button-d)] style default TButton -padding {10 6} style element create Toolbutton.button image $I(tbar-n) \ -border {2 8 2 16} -padding {2 2} -sticky news \ -map [list {pressed !disabled} $I(tbar-p) \ {active !selected} $I(tbar-a) \ selected $I(tbar-p)] style element create Checkbutton.indicator image $I(check-u) \ -width 20 -sticky w \ -map [list selected $I(check-c)] style element create Radiobutton.indicator image $I(radio-u) \ -width 20 -sticky w \ -map [list selected $I(radio-c)] # The layout for the menubutton is modified to have a button element # drawn on top of the background. This means we can have transparent # pixels in the button element. Also, the pixmap has a special # region on the right for the arrow. So we draw the indicator as a # sibling element to the button, and draw it after (ie on top of) the # button image. style layout TMenubutton { Menubutton.background Menubutton.button -children { Menubutton.focus -children { Menubutton.padding -children { Menubutton.label -side left -expand true } } } Menubutton.indicator -side right } style element create Menubutton.button image $I(mbut-n) \ -map [list {active !disabled} $I(mbut-a) \ {pressed !disabled} $I(mbut-a) \ {disabled} $I(mbut-d)] \ -border {7 10 29 15} -padding {7 4 29 4} -sticky news style element create Menubutton.indicator image $I(mbut-arrow-n) \ -width 11 -sticky w -padding {0 0 18 0} # ----------------------------------------------------------------- # Scrollbars, scale and progress elements # - the scrollbar has three arrow buttons, two at the bottom and # one at the top. # style layout Vertical.TScrollbar { Scrollbar.background Scrollbar.trough -children { Scrollbar.uparrow -side top Scrollbar.downarrow -side bottom Scrollbar.uparrow -side bottom Vertical.Scrollbar.thumb -side top -expand true -sticky ns } } style layout Horizontal.TScrollbar { Scrollbar.background Scrollbar.trough -children { Scrollbar.leftarrow -side left Scrollbar.rightarrow -side right Scrollbar.leftarrow -side right Horizontal.Scrollbar.thumb -side left -expand true -sticky we } } style default TScrollbar -width 16 style element create Horizontal.Scrollbar.thumb image $I(hsb-n) \ -border {6 4} -width 15 -height 16 -sticky news \ -map [list {pressed !disabled} $I(hsb-p)] style element create Vertical.Scrollbar.thumb image $I(vsb-n) \ -border {4 6} -width 16 -height 15 -sticky news \ -map [list {pressed !disabled} $I(vsb-p)] style element create Scale.slider image $I(hslider-n) \ -border 3 style element create Vertical.Scale.slider image $I(vslider-n) \ -border 3 style element create Horizontal.Progress.bar image $I(hsb-n) \ -border {6 4} style element create Vertical.Progress.bar image $I(vsb-n) \ -border {4 6} style element create uparrow image $I(arrowup-n) \ -map [list {pressed !disabled} $I(arrowup-p)] style element create downarrow image $I(arrowdown-n) \ -map [list {pressed !disabled} $I(arrowdown-p)] style element create rightarrow image $I(arrowright-n) \ -map [list {pressed !disabled} $I(arrowright-p)] style element create leftarrow image $I(arrowleft-n) \ -map [list {pressed !disabled} $I(arrowleft-p)] # ----------------------------------------------------------------- # Notebook elements # style element create tab image $I(tab-n) \ -map [list selected $I(tab-p) active $I(tab-p)] \ -border {6 6 6 2} -height 12 ## Labelframes. # style default TLabelframe -borderwidth 2 -relief groove } } package provide tile::theme::keramik $::tile::theme::keramik::version ================================================ FILE: ext/tk/sample/tkextlib/tile/themes/keramik/pkgIndex.tcl ================================================ # pkgIndex.tcl for additional tile pixmap themes. # # We don't provide the package is the image subdirectory isn't present, # or we don't have the right version of Tcl/Tk # # To use this automatically within tile, the tile-using application should # use tile::availableThemes and tile::setTheme # # $Id$ if {![file isdirectory [file join $dir keramik]]} { return } if {![package vsatisfies [package provide Tcl] 8.4]} { return } package ifneeded tile::theme::keramik 0.3.2 \ [list source [file join $dir keramik.tcl]] ================================================ FILE: ext/tk/sample/tkextlib/tile/themes/kroc/kroc.tcl ================================================ # kroc.tcl - Copyright (C) 2004 David Zolli # # A sample pixmap theme for the tile package. #package require tile::pixmap namespace eval tile { namespace eval kroc { variable version 0.0.1 } } namespace eval tile::kroc { set imgdir [file join [file dirname [info script]] kroc] array set Images [tile::LoadImages $imgdir *.gif] if {[package vsatisfies [package provide tile] 0.5]} { set TNoteBook_Tab TNotebook.Tab } else { set TNoteBook_Tab Tab.TNotebook } style theme create kroc -parent alt -settings { style default . -background #FCB64F -troughcolor #F8C278 -borderwidth 1 style default . -font TkDefaultFont -borderwidth 1 style map . -background [list active #694418] style map . -foreground [list disabled #B2B2B2 active #FFE7CB] style default TButton -padding "10 4" style default $TNoteBook_Tab -padding {10 3} -font TkDefaultFont style map $TNoteBook_Tab \ -background [list selected #FCB64F {} #FFE6BA] \ -foreground [list {} black] \ -padding [list selected {10 6 10 3}] style map TScrollbar \ -background { pressed #694418} \ -arrowcolor { pressed #FFE7CB } \ -relief { pressed sunken } \ ; style layout Vertical.TScrollbar { Scrollbar.trough -children { Scrollbar.uparrow -side top Scrollbar.downarrow -side bottom Scrollbar.uparrow -side bottom Scrollbar.thumb -side top -expand true } } style layout Horizontal.TScrollbar { Scrollbar.trough -children { Scrollbar.leftarrow -side left Scrollbar.rightarrow -side right Scrollbar.leftarrow -side right Scrollbar.thumb -side left -expand true } } # # Elements: # if {[package vsatisfies [package provide tile] 0.5]} { style element create Button.button image $Images(button-n) \ -map [list \ pressed $Images(button-p) \ active $Images(button-h) \ ] -border 3 -sticky ew style element create Checkbutton.indicator image $Images(check-nu) \ -map [list \ {pressed selected} $Images(check-nc) \ pressed $Images(check-nu) \ {active selected} $Images(check-hc) \ active $Images(check-hu) \ selected $Images(check-nc) \ ] -sticky w style element create Radiobutton.indicator image $Images(radio-nu) \ -map [list \ {pressed selected} $Images(radio-nc) \ pressed $Images(radio-nu) \ {active selected} $Images(radio-hc) \ active $Images(radio-hu) \ selected $Images(radio-nc) \ ] -sticky w } else { style element create Button.button pixmap -images [list \ pressed $Images(button-p) \ active $Images(button-h) \ {} $Images(button-n) \ ] -border 3 -tiling tile style element create Checkbutton.indicator pixmap -images [list \ {pressed selected} $Images(check-nc) \ pressed $Images(check-nu) \ {active selected} $Images(check-hc) \ active $Images(check-hu) \ selected $Images(check-nc) \ {} $Images(check-nu) \ ] -tiling fixed style element create Radiobutton.indicator pixmap -images [list \ {pressed selected} $Images(radio-nc) \ pressed $Images(radio-nu) \ {active selected} $Images(radio-hc) \ active $Images(radio-hu) \ selected $Images(radio-nc) \ {} $Images(radio-nu) \ ] -tiling fixed } # # Settings: (*button.background is not needed in tile 0.5 or above) # style layout TButton { Button.button -children { Button.focus -children { Button.padding -children { Button.label -expand true -sticky {} } } } } style layout TCheckbutton { Checkbutton.border -children { Checkbutton.background Checkbutton.padding -children { Checkbutton.indicator -side left Checkbutton.focus -side left -children { Checkbutton.label } } } } style layout TRadiobutton { Radiobutton.border -children { Radiobutton.background Radiobutton.padding -children { Radiobutton.indicator -side left Radiobutton.focus -expand true -sticky w -children { Radiobutton.label -side right -expand true } } } } } } # ------------------------------------------------------------------------- package provide tile::theme::kroc $::tile::kroc::version # ------------------------------------------------------------------------- ================================================ FILE: ext/tk/sample/tkextlib/tile/themes/kroc/pkgIndex.tcl ================================================ # pkgIndex.tcl for additional tile pixmap themes. # # We don't provide the package is the image subdirectory isn't present, # or we don't have the right version of Tcl/Tk # # To use this automatically within tile, the tile-using application should # use tile::availableThemes and tile::setTheme # # $Id$ if {![file isdirectory [file join $dir kroc]]} { return } if {![package vsatisfies [package provide Tcl] 8.4]} { return } package ifneeded tile::theme::kroc 0.0.1 \ [list source [file join $dir kroc.tcl]] ================================================ FILE: ext/tk/sample/tkextlib/tile/themes/kroc.rb ================================================ # # kroc.rb # # based on: # >> kroc.tcl - Copyright (C) 2004 David Zolli # imgdir = File.join(File.dirname(__FILE__), 'kroc', 'kroc') $images = Tk::Tile.load_images(imgdir, '*.gif') if TkPackage.vcompare(Tk::Tile.package_version, '0.5') >= 0 $TNotebook_Tab = Tk::Tile::TNotebook.style('Tab') else $TNotebook_Tab = 'Tab.TNotebook' end def kroc_rb_settings # Tk::Tile::Style.default(TkRoot, :background=>'#FCB64F', # :troughcolor=>'#F8C278', :borderwidth=>1) # or # Tk::Tile::Style.default(Tk.root, :background=>'#FCB64F', # :troughcolor=>'#F8C278', :borderwidth=>1) # or # Tk::Tile::Style.default('.', :background=>'#FCB64F', # :troughcolor=>'#F8C278', :borderwidth=>1) # or # Tk::Tile::Style.default(nil, :background=>'#FCB64F', # :troughcolor=>'#F8C278', :borderwidth=>1) # or Tk::Tile::Style.default(:background=>'#FCB64F', :troughcolor=>'#F8C278', :borderwidth=>1) # Tk::Tile::Style.default(TkRoot, :font=>Tk::Tile::Font::Default, # :borderwidth=>1) # or # Tk::Tile::Style.default(Tk.root, :font=>Tk::Tile::Font::Default, # :borderwidth=>1) # or # Tk::Tile::Style.default('.', :font=>Tk::Tile::Font::Default, # :borderwidth=>1) # or # Tk::Tile::Style.default(nil, :font=>Tk::Tile::Font::Default, # :borderwidth=>1) # or Tk::Tile::Style.default(:font=>Tk::Tile::Font::Default, :borderwidth=>1) # Tk::Tile::Style.map(TkRoot, :background=>[:active, '#694418']) # or # Tk::Tile::Style.map(Tk.root, :background=>[:active, '#694418']) # or # Tk::Tile::Style.map('.', :background=>[:active, '#694418']) # or # Tk::Tile::Style.map(nil, :background=>[:active, '#694418']) # or Tk::Tile::Style.map(:background=>[:active, '#694418']) Tk::Tile::Style.map(:foreground=>[:disabled, '#B2B2B2', :active, '#FFE7CB']) # Tk::Tile::Style.default('TButton', :padding=>[10,4]) Tk::Tile::Style.default(Tk::Tile::TButton, :padding=>[10,4]) # Tk::Tile::Style.default('TNotebook.Tab', Tk::Tile::Style.default($TNotebook_Tab, :padding=>[10, 3], :font=>Tk::Tile::Font::Default) # Tk::Tile::Style.map('TNotebook.Tab', Tk::Tile::Style.map($TNotebook_Tab, :background=>[:selected, '#FCB64F', '', '#FFE6BA'], :foreground=>['', 'black'], :padding=>[:selected, [10, 6, 10, 3]]) # Tk::Tile::Style.map('TScrollbar', Tk::Tile::Style.map(Tk::Tile::TScrollbar, :background=>[:pressed, '#694418'], :arrowcolor=>[:pressed, '#FEF7CB'], :relief=>[:pressed, :sunken]) # Tk::Tile::Style.layout('Vertical.TScrollbar', Tk::Tile::Style.layout(Tk::Tile.style('Vertical', Tk::Tile::TScrollbar), ['Scrollbar.trough', {:children=>[ 'Scrollbar.uparrow', {:side=>:top}, 'Scrollbar.downarrow', {:side=>:bottom}, 'Scrollbar.uparrow', {:side=>:bottom}, 'Scrollbar.thumb', {:side=>:top, :expand=>true} ]} ]) # Tk::Tile::Style.layout('Horizontal.TScrollbar', Tk::Tile::Style.layout(Tk::Tile.style('Horizontal', Tk::Tile::TScrollbar), ['Scrollbar.trough', {:children=>[ 'Scrollbar.leftarrow', {:side=>:left}, 'Scrollbar.rightarrow', {:side=>:right}, 'Scrollbar.leftarrow', {:side=>:right}, 'Scrollbar.thumb', {:side=>:left, :expand=>true} ]} ]) # # Elements: # if Tk::Tile::TILE_SPEC_VERSION_ID >= 8 Tk::Tile::Style.element_create('Button.button', :image, [ $images['button-n'], :pressed, $images['button-p'], :active, $images['button-h'], ], :border=>3, :sticky=>:ew) Tk::Tile::Style.element_create('Checkbutton.indicator', :image, [ $images['check-nu'], [:pressed, :selected],$images['check-nc'], :pressed, $images['check-nu'], [:active, :selected], $images['check-hc'], :active, $images['check-hu'], :selected, $images['check-nc'], ], :sticky=>:w) Tk::Tile::Style.element_create('Radiobutton.indicator', :image, [ $images['radio-nu'], [:pressed,:selected],$images['radio-nc'], :pressed, $images['radio-nu'], [:active,:selected], $images['radio-hc'], :active, $images['radio-hu'], :selected, $images['radio-nc'], ], :sticky=>:w) elsif TkPackage.vcompare(Tk::Tile.package_version, '0.5') >= 0 Tk::Tile::Style.element_create('Button.button', :image, $images['button-n'], :map=>[ :pressed, $images['button-p'], :active, $images['button-h'], ], :border=>3, :sticky=>:ew) Tk::Tile::Style.element_create('Checkbutton.indicator', :image, $images['check-nu'], :map=>[ [:pressed, :selected],$images['check-nc'], :pressed, $images['check-nu'], [:active, :selected], $images['check-hc'], :active, $images['check-hu'], :selected, $images['check-nc'], ], :sticky=>:w) Tk::Tile::Style.element_create('Radiobutton.indicator', :image, $images['radio-nu'], :map=>[ [:pressed, :selected],$images['radio-nc'], :pressed, $images['radio-nu'], [:active, :selected], $images['radio-hc'], :active, $images['radio-hu'], :selected, $images['radio-nc'], ], :sticky=>:w) else # tile 0.4 or earlier Tk::Tile::Style.element_create('Button.button', :pixmap, :images=>[ :pressed, $images['button-p'], :active, $images['button-h'], '', $images['button-n'] ], :border=>3, :tiling=>:tile) Tk::Tile::Style.element_create('Checkbutton.indicator', :pixmap, :images=>[ [:pressed, :selected],$images['check-nc'], :pressed, $images['check-nu'], [:active, :selected], $images['check-hc'], :active, $images['check-hu'], :selected, $images['check-nc'], '', $images['check-nu'], ], :tiling=>:fixed) Tk::Tile::Style.element_create('Radiobutton.indicator', :pixmap, :images=>[ [:pressed, :selected],$images['radio-nc'], :pressed, $images['radio-nu'], [:active, :selected], $images['radio-hc'], :active, $images['radio-hu'], :selected, $images['radio-nc'], '', $images['radio-nu'], ], :tiling=>:fixed) end # # Settings: # # Tk::Tile::Style.layout(Tk::Tile::TButton, Tk::Tile::Style.layout('TButton', [ 'Button.button', {:children=>[ 'Button.focus', {:children=>[ 'Button.padding', {:children=>[ 'Button.label', {:expand=>true, :sticky=>''} ]} ]} ]} ]) # Tk::Tile::Style.layout(Tk::Tile::TCheckbutton, Tk::Tile::Style.layout('TCheckbutton', [ 'Checkbutton.background', # this is not needed in tile 0.5 or later 'Checkbutton.border', {:children=>[ 'Checkbutton.padding', {:children=>[ 'Checkbutton.indicator', {:side=>:left}, 'Checkbutton.focus', {:side=>:left, :children=>[ 'Checkbutton.label' ]} ]} ]} ]) # Tk::Tile::Style.layout(Tk::Tile::TRadiobutton, Tk::Tile::Style.layout('TRadiobutton', [ 'Radiobutton.background', # this is not needed in tile 0.5 or later 'Radiobutton.border', {:children=>[ 'Radiobutton.padding', {:children=>[ 'Radiobutton.indicator', {:side=>:left}, 'Radiobutton.focus', {:expand=>true, :sticky=>:w, :children=>[ 'Radiobutton.label', {:side=>:right, :expand=>true} ]} ]} ]} ]) end Tk::Tile::Style.theme_create('kroc-rb', :parent=>'alt', :settings=>proc{ kroc_rb_settings() }) ================================================ FILE: ext/tk/sample/tkextlib/tile/themes/plastik/pkgIndex.tcl ================================================ # pkgIndex.tcl for additional tile pixmap themes. # # We don't provide the package is the image subdirectory isn't present, # or we don't have the right version of Tcl/Tk # # To use this automatically within tile, the tile-using application should # use tile::availableThemes and tile::setTheme # # $Id$ if {![file isdirectory [file join $dir plastik]]} { return } if {![package vsatisfies [package provide Tcl] 8.4]} { return } package ifneeded tile::theme::plastik 0.3.1 \ [list source [file join $dir plastik.tcl]] ================================================ FILE: ext/tk/sample/tkextlib/tile/themes/plastik/plastik.tcl ================================================ # plastik.tcl - Copyright (C) 2004 Googie # # A sample pixmap theme for the tile package. # # Copyright (c) 2004 Googie # Copyright (c) 2005 Pat Thoyts # # $Id$ package require Tk 8.4 package require tile 0.5 namespace eval tile::theme::plastik { variable version 0.3.1 package provide tile::theme::plastik $version variable imgdir [file join [file dirname [info script]] plastik] variable Images; array set Images [tile::LoadImages $imgdir *.gif] variable colors array set colors { -frame "#cccccc" -disabledfg "#aaaaaa" -selectbg "#657a9e" -selectfg "#ffffff" } style theme create plastik -parent default -settings { style default . \ -background $colors(-frame) \ -troughcolor $colors(-frame) \ -selectbackground $colors(-selectbg) \ -selectforeground $colors(-selectfg) \ -font TkDefaultFont \ -borderwidth 1 \ ; style map . -foreground [list disabled $colors(-disabledfg)] # # Layouts: # style layout Vertical.TScrollbar { Scrollbar.background Scrollbar.trough -children { Scrollbar.uparrow -side top Scrollbar.downarrow -side bottom Scrollbar.uparrow -side bottom Vertical.Scrollbar.thumb -side top -expand true -sticky ns } } style layout Horizontal.TScrollbar { Scrollbar.background Scrollbar.trough -children { Scrollbar.leftarrow -side left Scrollbar.rightarrow -side right Scrollbar.leftarrow -side right Horizontal.Scrollbar.thumb -side left -expand true -sticky we } } style layout TButton { Button.button -children { Button.focus -children { Button.padding -children { Button.label -side left -expand true } } } } # # Elements: # style element create Button.button image $Images(button-n) \ -border 4 -sticky ew \ -map [list pressed $Images(button-p) active $Images(button-h)] style element create Checkbutton.indicator image $Images(check-nu) \ -sticky {} -map [list \ {active selected} $Images(check-hc) \ {pressed selected} $Images(check-pc) \ active $Images(check-hu) \ selected $Images(check-nc) \ ] style element create Radiobutton.indicator image $Images(radio-nu) \ -sticky {} -map [list \ {active selected} $Images(radio-hc) \ {pressed selected} $Images(radio-pc) \ active $Images(radio-hu) \ selected $Images(radio-nc) \ ] style element create Horizontal.Scrollbar.thumb \ image $Images(hsb-n) -border 3 -sticky ew style element create Vertical.Scrollbar.thumb \ image $Images(vsb-n) -border 3 -sticky ns style element create Scale.slider \ image $Images(hslider-n) -sticky {} style element create Vertical.Scale.slider \ image $Images(vslider-n) -sticky {} style element create Scrollbar.uparrow image $Images(arrowup-n) \ -map [list pressed $Images(arrowup-p)] -sticky {} style element create Scrollbar.downarrow image $Images(arrowdown-n) \ -map [list pressed $Images(arrowdown-p)] -sticky {} style element create Scrollbar.leftarrow image $Images(arrowleft-n) \ -map [list pressed $Images(arrowleft-p)] -sticky {} style element create Scrollbar.rightarrow image $Images(arrowright-n) \ -map [list pressed $Images(arrowright-p)] -sticky {} # # Settings: # style default TButton -width -10 style default TNotebook.Tab -padding {6 2 6 2} style default TLabelframe -borderwidth 2 -relief groove } } ================================================ FILE: ext/tk/sample/tkextlib/tile/toolbutton.tcl ================================================ # # $Id$ # # Demonstration of custom widget styles. # # # ~ BACKGROUND # # Checkbuttons in toolbars have a very different appearance # than regular checkbuttons: there's no indicator, they # "pop up" when the mouse is over them, and they appear sunken # when selected. # # Tk added partial support for toolbar-style buttons in 8.4 # with the "-overrelief" option, and TIP #82 added further # support with the "-offrelief" option. So to get a toolbar-style # checkbutton, you can configure it with: # # checkbutton .cb \ # -indicatoron false -selectcolor {} -relief flat -overrelief raised # # Behind the scenes, Tk has a lot of rather complicated logic # to implement this checkbutton style; see library/button.tcl, # generic/tkButton.c, and the platform-specific files unix/tkUnixButton.c # et al. for the full details. # # The tile widget set has a better way: custom styles. # Since the appearance is completely controlled by the theme engine, # we can define a new "Toolbutton" style and just use: # # checkbutton .cb -style Toolbutton # # # ~ DEMONSTRATION # # The tile built-in themes (default, "alt", windows, and XP) # already include Toolbutton styles. This script will add # them to the "step" and "blue" themes as a demonstration. # # (Note: Pushbuttons and radiobuttons can also use the "Toolbutton" # style; see demo.tcl.) # style theme settings "step" { # # First, we use [style layout] to define what elements to # use and how they're arranged. Toolbuttons are pretty # simple, consisting of a border, some internal padding, # and a label. (See also the TScrollbar layout definition # in demos/blue.tcl for a more complicated layout spec.) # style layout Toolbutton { Toolbutton.background Toolbutton.border -children { Toolbutton.padding -children { Toolbutton.label } } } # (Actually the above isn't strictly necessary, since the same layout # is defined in the default theme; we could have inherited it # instead.) # # Next, specify default values for element options. # For many options (like -background), the defaults # inherited from the parent style are sufficient. # style default Toolbutton -width 0 -padding 1 -relief flat -borderwidth 2 # # Finally, use [style map] to specify state-specific # resource values. We want a flat relief if the widget is # disabled, sunken if it's selected (on) or pressed, # and raised when it's active (the mouse pointer is # over the widget). Each state-value pair is checked # in order, and the first matching state takes precedence. # style map Toolbutton -relief { disabled flat selected sunken pressed sunken active raised } } # # Now for the "blue" theme. (Since the purpose of this # theme is to show what *can* be done, not necessarily what # *should* be done, the following makes some questionable # design decisions from an aesthetic standpoint.) # if {![catch {package require tile::theme::blue}]} { style theme settings "blue" { # # Default values: # style default Toolbutton \ -width 0 -relief flat -borderwidth 2 \ -background #6699CC -foreground #000000 ; # # Configure state-specific values for -relief, as before: # style map Toolbutton -relief { disabled flat selected sunken pressed sunken active raised } # # Adjust the -padding at the same time, to enhance # the raised/sunken illusion: # style default Toolbutton -padding 4 style map Toolbutton -padding { disabled {4} selected {6 6 2 2} pressed {6 6 2 2} active {2 2 6 6} } # # ... and change the foreground and background colors # when the mouse cursor is over the widget: # style map Toolbutton -background { active #008800 } -foreground { active #FFFFFF } } } # # ~ A final note: # # TIP #82 also says: "When -indicatoron is off and the button itself # is on, the relief continues to be hard-coded to sunken. For symmetry, # we might consider adding another -onrelief option to cover this # case. But it is difficult to imagine ever wanting to change the # value of -onrelief so it has been omitted from this TIP. # If there as strong desire to have -onrelief, it can be added later." # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # # The Tile project aims to make sure that this never needs to happen. # ================================================ FILE: ext/tk/sample/tkextlib/tkHTML/Orig_COPYRIGHT.txt ================================================ The following text is the original 'COPYRIGHT' file of tkHTML. ----------------------------------------------------------------------- Most of the source code for the Tk Html widget has been place in the public domain. You can do with it whatever you want. However, some files have been copied from other sources and contain copyrights. A copyright notice appears separately at the top of each source file. ----------------------------------------------------------------------- In this sample, HTML documents are quoted in the 'tests' directory of tkHTML source tree. There were no copyright notice in the directory. ================================================ FILE: ext/tk/sample/tkextlib/tkHTML/README ================================================ [ TkHtml widget example ] The directory page1 -- page4 are referd from "test" directory of original TkHtml extension's source archive. ( see http://www.hwaci.com/sw/tkhtml/index.html ) You can see the HTML documents on the 'hv.rb' or 'ss.rb' sample script. e.g. LD_LIBRARY_PATH=/usr/local/ActiveTcl/lib:$LD_LIBRARY_PATH /usr/local/bin/ruby ./hv.rb page1/index.html ================================================ FILE: ext/tk/sample/tkextlib/tkHTML/hv.rb ================================================ #!/usr/bin/env ruby # # This script implements the "hv" application. Type "hv FILE" to # view FILE as HTML. # # This application is used for testing the HTML widget. It can # also server as an example of how to use the HTML widget. # require 'tk' require 'tkextlib/tkHTML' root = TkRoot.new(:title=>'HTML File Viewer', :iconname=>'HV') file = ARGV[0] # # These images are used in place of GIFs or of form elements # biggray = TkPhotoImage.new(:data=><<'EOD') R0lGODdhPAA+APAAALi4uAAAACwAAAAAPAA+AAACQISPqcvtD6OctNqLs968+w+G4kiW5omm 6sq27gvH8kzX9o3n+s73/g8MCofEovGITCqXzKbzCY1Kp9Sq9YrNFgsAO/// EOD smgray = TkPhotoImage.new(:data=><<'EOD') R0lGODdhOAAYAPAAALi4uAAAACwAAAAAOAAYAAACI4SPqcvtD6OctNqLs968+w+G4kiW5omm 6sq27gvH8kzX9m0VADv/ EOD nogifbig = TkPhotoImage.new(:data=><<'EOD') R0lGODdhJAAkAPEAAACQkADQ0PgAAAAAACwAAAAAJAAkAAACmISPqcsQD6OcdJqKM71PeK15 AsSJH0iZY1CqqKSurfsGsex08XuTuU7L9HywHWZILAaVJssvgoREk5PolFo1XrHZ29IZ8oo0 HKEYVDYbyc/jFhz2otvdcyZdF68qeKh2DZd3AtS0QWcDSDgWKJXY+MXS9qY4+JA2+Vho+YPp FzSjiTIEWslDQ1rDhPOY2sXVOgeb2kBbu1AAADv/ EOD nogifsm = TkPhotoImage.new(:data=><<'EOD') R0lGODdhEAAQAPEAAACQkADQ0PgAAAAAACwAAAAAEAAQAAACNISPacHtD4IQz80QJ60as25d 3idKZdR0IIOm2ta0Lhw/Lz2S1JqvK8ozbTKlEIVYceWSjwIAO/// EOD # # define variables # ul_hyper = TkVariable.new(0) show_tbl = TkVariable.new(0) show_img = TkVariable.new(1) # # A font chooser routine. # # html[:fontcommand] = pick_font pick_font = proc{|size, attrs| puts "FontCmd: #{size} #{attrs}" [ ((attrs =~ /fixed/)? 'courier': 'charter'), (12 * (1.2**(size.to_f - 4.0))).to_i, ((attrs =~ /italic/)? 'italic': 'roman'), ((attrs =~ /bold/)? 'bold': 'normal') ].join(' ') } # # This routine is called for each form element # form_cmd = proc{|n, cmd, style, *args| # puts "FormCmd: $n $cmd $args" case cmd when 'select', 'textarea', 'input' TkLabel.new(:widgetname=>args[0], :image=>nogifsm) end } # # This routine is called for every markup # images = {} old_imgs = {} big_imgs = {} hotkey = {} move_big_image = proc{|b| if big_imgs.key?(b) b.copy(big_imgs[b]) big_imgs[b].delete big_imgs.delete(b) Tk.update end } image_cmd = proc{|*args| if show_img.bool smgray else fn = args[0] if old_imgs.key?(fn) images[fn] = old_imgs[fn] old_imgs.delete(fn) images[fn] else begin img = TkPhotoImage.new(:file=>fn) rescue smgray else if img.width * img.height > 20000 b = TkPhotoImage.new(:width=>img.width, :height=>img.height) big_imgs[b] = img img = b Tk.after_idle(proc{ move_big_image.call(b) }) end images[fn] = img img end end end } # # This routine is called for every

Welcome to Slashdot Linux News United States Education Space
 faq
 code
 awards
 privacy
 slashNET
 older stuff
 rob's page
 preferences
 andover.net
 submit story
 advertising
 supporters
 past polls
 topics
 about
 jobs
 hof

Sections
1/23
apache
1/29 (3)
askslashdot
1/27
awards
1/29 (2)
books
1/27
bsd
1/28 (2)
features
1/28 (2)
interviews
1/19
radio
1/27 (2)
science
1/28 (3)
yro
Andover.Net
AndoverNews
Ask Reggie
DaveCentral
FreeCode
MediaBuilder

Who Bought Linux.Net?
Linux Posted by CmdrTaco on Saturday January 29, @10:52AM
from the this-game-again dept.
So Fred VanKampen (who has to hold the record for most money made by reselling two domain names) e-mailed us to say that the Domain Name for 'Linux.Net' has been sold. He won't say to whom, but it supposedly will be announced at LinuxWorld next week. Of course we have no idea what he got for the entry, but the rumors were that he made several million when he sold Linux.com to VA Linux. Hopefully he'll take me for a ride in his yacht. ;)

( Read More... | 58 of 62 comments )

Book Reviews: E-Mails from (Over?) The Edge
News Posted by Hemos on Saturday January 29, @10:43AM
from the touching-story dept.
I'd like to thank the author of this book for sending it to me. Nick's written a book that's touching and endearing, and one that's well worth reading for everyone who's ever had social struggles to deal with. As well, his involvement with the fine folks of TheVenue. I'll warn you - it's not a tech text. But it's still worth reading. Click below to read more.

( Read More... | 6197 bytes in body | 6 of 22 comments )

Linux Kernel 2.3.41
Linux Posted by CmdrTaco on Saturday January 29, @10:21AM
from the download-compile-reboot-repeat dept.
sdriver writes "For those of us who enjoy *panic*, *oops*, and suddenly seeing their video BIOS... the newest version is out! Be the first on your block to submit a new patch! ;) " If you don't know where to get it, you probably should stick to your warm and cuddly 2.2.x kernel *grin*. Now outta my way, I wanna crash my laptop!

( Read More... | 52 of 57 comments )

Congress Still Figuring Out E-Mail
United States Posted by Roblimo on Saturday January 29, @07:28AM
from the voice-of-the-people-can-get-awfully-loud dept.
Jett writes " Vote.com has an interesting article in their Webmag Fifth Estate about how congressmen have responded to the popularity of e-mail in their daily operations. Quote: 'Of the 440 voting and non-voting House of Representatives members, 22 have no e-mail at all. Even House Speaker Dennis Hastert is wired only halfway -- his office receives e-mail, but does not respond to it. And while all U.S. senators have e-mail, they, like their House counterparts, routinely shun non-constituent mail -- even though they chair committees whose decisions affect the entire country.'"

( Read More... | 66 of 66 comments )

Ask Slashdot: Sci Fi Literature 101?
Education Posted by Cliff on Saturday January 29, @06:56AM
from the recommendations-wanted dept.
ohlaadee asks: "My niece (she's 13) wants to start reading science fiction. I do too. I gave us both Asimov's _The Foundation_  for Christmas. We'll read it together. I suppose we could spend the rest of our lives just reading Asimov, but I'm wondering what books and movies you folks would come up with? What does the /. recommended Science Fiction 101 list include?"

( Read More... | 345 of 345 comments )

Could Distributed.Net Help the Mars Polar Lander?
Space Posted by Roblimo on Saturday January 29, @03:35AM
from the food-for-thought dept.
Anonymous Coward writes "This official JPL press release describes the current attempt to listen for faint signals from the Mars Lander. They get three windows a day, and it takes 18 hours to process data because the signal is so weak (if it's really there). Too bad they don't have a deal with distributed.net." Interesting thought. Is anyone at distributed.net or JPL interested in pursuing it?

( Read More... | 99 of 102 comments )

iCrave TV Loses Battle against U.S. Broadcasters
Television Posted by Roblimo on Saturday January 29, @12:21AM
from the shut-down-just-before-the-super-bowl dept.
Doran writes "C|Net has this story about how the Canadian company iCraveTV.com has lost its latest battle in U.S. courts over whether it can rebroadcast TV signals over the Web. The broadcasters say it's theft, while iCraveTV sez it's just doing what's legal for other cable TV companies in Canada (ie. rebroadcasting TV). Of course, by framing the streaming video iCraveTV is doing more than just rebroadcasting, they're also adding more commercial content, which the broadcasters feel dilutes their TV commercials. "

( Read More... | 152 of 170 comments )

Win2k Security holes found
Microsoft Posted by HeUnique on Friday January 28, @04:58PM
from the and-it's-not-even-out-yet dept.
According to a story posted by ZDNN, two security holes have been found on Windows 2000, and that's even before the official release of Windows 2000! Administrators who rush to incorporate the patch from MS beware - according to one of the talkback posts on ZDNN, the patch creates a new problem with Windows 2000 news server service.

( Read More... | 510 of 534 comments )

Encryption Debate at Mitnick Trial
Encryption Posted by Hemos on Friday January 28, @03:33PM
from the gimmie-the-data dept.
A number of people have written about the latest twist in the Mitnick case. Kevin wants to get his data back, but the government is refusing to do so until he gives them the key. Apparently, the government is unable to crack the encryption that he's got on it - you'd think after having the data for five years, they'd be able to brute-force the darn thing. It's a NYT article - free login required.

( Read More... | 504 of 521 comments )

Forum: Future Ports of Games to Linux
Games Posted by CmdrTaco on Friday January 28, @02:26PM
from the it's-been-awhile dept.
It's been a long time since I posted an open forum like this, but I'm curious what people think on this one. What games do you most want to see ported to Linux in the next few months? Of course, for me personally it's StarCraft and Diablo 2, but I'm curious what games have come out or are due soon that people would most like to see a port of (and note that WINE doesn't count. ;)

( Read More... | 648 of 652 comments )

Features
Voting has begun for the $100k Slashdot Beanie Awards. Talk amongst yourselves and choose who deserves the cash.

The latest installment of Geeks in Space is up at The Sync. Listen to CmdrTaco, Hemos, and Nate talk about the latest events to happen - or not happen in the computer world.

Perhaps you are seeking Jon Katz's series of articles related to recent events in Colorado. These articles include Voices from the Hellmouth, More Stories from the Hellmouth or The Price of Being Different,

For something different, try reading a little essay Thoughts from the Furnace about the internet, and flame.

And for a bit of an amusing take on the Open Source world, check out Open Source as an Ant Farm

Update: 01/03 03:10 by CowboyNeal:

Past Features

Ask Slashdot
  • Sci Fi Literature 101?
  • Linux and Satellite Internet Services
  • Open Defensive Patents?
  • Technologies That Shaped the Last Century?
  • Disk Repair Tools for Linux?
  • Why Can't the Command-Line be More Standardized?
  • Packet Radio Networking with PalmOS?
  • Cheap Rackmount Enclosures/Systems?
  • Open Source Software and Tax Breaks?
  • Building an Upgradable Dual Processor System

    if you have a question for Ask Slashdot, send it to askslashdot@slashdot.org

  • Slashdot Login
    Nickname:

    Password:

    Don't have an account yet? Go Create One. A user account will allow you to customize all these nutty little boxes, tailor the stories you see, as well as remember your comment viewing preferences.

    Slashdot Poll
    The Tech Advance I Most Want Is:
    Nanotechnology
    Cold Fusion
    Powerful Fuel Cells
    Hard Wiring my Body
    Universal Strong Crypto
    Interstellar Travel
    Cybernetic Body Armor
    ColecoVision
    [ Results | Polls ]
    Comments:656 | Votes:29121

    Older Stuff

    Friday January 28

  • Abstract Programming and GPL Enforcement (235)
  • Interview: FreeDOS Leader Jim Hall Answers (86)
  • Open Source's Achilles Heel (466)
  • The Virtue of Communal Instincts (237)
  • Gartner Group Debunking Open Source Myths (165)
  • DoubleClick Taken to Court (310)
  • Updated Slash & Server 51 (81)
  • XMMS 1.0.0 Released (128)
  • Linux and Satellite Internet Services (138)
  • UN Wants to Combat Online Racism (531)

    Thursday January 27

  • Crackdowns, Fools and the MPAA (351)
  • Heroes of Might and Magic III Demo Released (157)
  • Sandia Labs Venture Into Nanotechnology (117)
  • CA Announces Program Ports to Linux (195)
  • Interview: Larry Augustin Finally Answers (210)
  • Final Call for Voting in Slashdot's Beanie Awards (178)
  • Transmeta Code Morphing != Just In Time (449)
  • Intrusion Detection (65)
  • Using Enzymes to Help Fight CO2 Build-Up (165)
  • Jon Johansen on ABC World News Tonight (415)


    Older Articles
    Yesterday's Edition

  • Book Reviews

    Jon Katz, Resident Gasbag, has a new, very appropriate book coming out soon, Geeks. Preorder now and receive the book early.

    For probably the best fiction read around, check out Neal Stephenson's Cryptonomicon, an engaging read about WWII, cryptography and buried treasure. And data vaults.

    If you've been doing a lot of work in Perl, you've probably figured out you really need Perl in a Nutshell or The Perl Cookbook. If you're still learning, grab Programming Perl.

    And if you want to learn more about how to become a better coder, grab The Unified Software Development Process or The Practice of Programming Additionally, check out Refactoring: Improving the Design of Existing Code .

    Developing a large application? Grab Eric Greenberg's excellent Network Application Frameworks.

    Visit Our Book Reviews Section for more.
    Update: 11/12 05:19 by H:

    Quick Links
    Cool Sites:
  • Linux.com (What is Linux?)
  • Everything (Blow your Mind)
  • After Y2k (This is Post-Apocalyptic?)
  • User Friendly (Laugh)
  • Themes.org (Make X Perty)

    Support Slashdot:

  • ThinkGeek (Clothe Yourself in Slashdot)
  • CDnow (Support Rob's Who Habit)
  • Slashdot Advertiser Index
  • Freshmeat

    January

  • We should get this out of the door now
  • Is Linux for Crazies?
  • SQN Linux 1.6
  • Limo 0.3.2
  • Fusion GS 1.3
  • MMR 1.5.4
  • KUPS 0.3.4
  • 3DSE patch for XMMS 4
  • Linux 2.3.41
  • Free Code for Linux S/390
    Search Freshmeat:

    More Meat...

  •   Wasn't there something about a PASCAL programmer knowing the value of everything and the Wirth of nothing?  
    All trademarks and copyrights on this page are owned by their respective owners. Comments are owned by the Poster. The Rest 1997-2000 Andover.Net.

    [ home | awards | supporters | rob's homepage | contribute story | older articles | Andover.Net | advertising | past polls | about | faq ]
    ================================================ FILE: ext/tk/sample/tkextlib/tkHTML/page2/index.html ================================================ Tcl Resource Center
    Scriptics
    Tcl/Tk
    Scripting Solutions for eBusiness Integration
    Products Customers Partners Services Tcl Resources Company
    Software
    Tcl/Tk Core
    Applications
    Extensions
    Patches
    Tcl & Java
    Tcl/Tk Ports
    Tools
    Documentation
    Community
    What's New
    Add URL
    Keyword Search
    Index
    Resource
     

    Tcl Resource Center

    Top>Software Central>Extensions>Tk Widgets
    Viewed by name (By date)

    Tk is a toolkit for building graphical user interfaces with Tcl. Your Tcl/Tk scripts run on UNIX, Windows, and Macintosh.

      BLT 8.0 Unofficial zip and DLL
      This is a compiled version of BLT 8.0 "unofficial" for the Windows platform. Edit (September 24, 1999 06:31)
      BLT 8.0p2 Unofficial tar file
      This is a contributed patch to make BLT compatible with Tcl/Tk 8.0p2. While still "unofficial", it is widely used. Make sure you get the 8.0p2 version because the 8.0 version does not compile under windows. There is also a 2.3-8.1 version that has been patched to work with 8.1. README file. Edit (August 30, 1999 06:38)
      BLT Home Page
      Author George Howlett, Version 2.3, Works with Tk 4.1 through Tk 8.1
      Download, BLT2.3.tar.gz, BLT2.4h.tar.gz, BLT2.4i.tar.gz, blt2.4i-for-8.0.exe, blt2.4i-for-8.1.exe
      BLT is a set of widgets for Tk, including a graph widget, bar chart, drag&drop, a simple command tracer, and much more. The 2.4 release, which is still under development, works with 8.0 or higher. There are also an "unofficial" release for 8.0p2 and 8.1a2 that were not done by the author. Edit (October 26, 1999 09:43)
      BWidget
      A set of native Tk 8.x Widgets using Tcl8.x namespaces. The ToolKit is available under Unix/X11 and Windows. The BWidget(s) have a professional look&feel as in other well known Toolkits (Tix or Incr Widget) but the concept is radically different because everything is native so no platform compilation, no compiled extension library are needed. The code is 100 Pure Tcl/Tk. More 30 components : Notebook, PageManager, Tree, PanedWindow, ButtonBox, ScrollView, ComboBox, SpinBox, ListBox, SelectFont, SelectColor, ProgressBare ... Edit (September 06, 1999 09:58)
      Dash Patch for Tk
      This patch has many enhancements to the Tk and its canvas widget, including dashed lines, smoothed polygons, and performance enhancements. Edit (November 21, 1999 06:33)
      Embedded Tk (et)
      Author Richard Hipp, Version 8.0b5, Works with Tk 4.0, 4.1, 4.2, 8.0
      Download: et80b5.tar.gz
      Embedded Tk or ``ET'' is tool for making stand-alone executables out of a mixture of C or C++ and Tcl/Tk. Using ET you can invoke a short Tcl/Tk script in the middle of a C routine, or you can invoke a C routine in the middle of a Tcl/Tk script. ET also bundles external Tcl/Tk scripts (including the standard Tcl/Tk startup scripts) into the executable so that the executable can be run on another binary-compatible computer that doesn't have Tcl/Tk installed. Edit (August 19, 1999 15:35)
      Enhanced Tk Console (TkCon)
      Author Jeff Hobbs, Version 1.3, Works with Tk 4.1 through Tk 8.1
      Download: tkcon.tar.gz
      TkCon is a replacement for the standard console that comes with Tk (on Windows/Mac, but also works on Unix). The console itself provides many more features than the standard console. Edit (August 23, 1999 12:06)
      Frontier-Tk ScriptMeridian project
      This project seeks to integrate the Tk toolkit with the Frontier scripting language. Edit (August 19, 1999 15:36)
      Img image format extension
      This package enhances Tk, adding support for many other Image formats: BMP, XBM, XPM, GIF (with transparency), PNG, JPEG, TIFF and postscript. This is implemented as a shared library that can be dynamically loaded into Tcl/Tk. Edit (November 21, 1999 06:35)
      mclistbox - a multi-column listbox widget
      mclistbox is a multi-column listbox that is written in pure tcl and runs on all platforms that support tcl/tk 8.0 or higher. This widget requires no other extensions; it is completely standalone. Edit (August 19, 1999 15:37)
      MFC views C++ class for embedding Tk
      The idea of embedding Tk in MFC windows always seemed very enticing but information was sparse and contradictory - on a scale between "very easy" and "not yet possible". The only thing for it was to have a go and lo, it wasn't that hard after all. CTkView is a C++ class which can be used in MFC SDI or MDI applications. An instance of CTkView hosts an embedded Tk toplevel widget and performs some management chores for the widget so that it can size, update and react correctly to Windows events. Edit (August 19, 1999 15:38)
      Pad++
      Author Ben Bederson et al, Version 0.9p1, Works with 8.0
      Download: download.html
      Pad++ is a Tk widget that provides a Zoomable User Interface (ZUI) that supports real-time interactive zoomable graphics in a fashion similar to the Tk Canvas widget. Pad++ supports tens of thousands of objects which include text, images, graphics, portals, lenses, simple html (and more), including transparency and rotation. Edit (August 19, 1999 15:39)
      Progressbar
      Progressbar is a megawidget written in pure tcl (ie: no compiling required - runs on all platforms Macintosh, Unix, Windows). Its primary purpose is to show the progress of any action in percent. Edit (January 24, 2000 09:19)
      scwoop (Simple Composite Widget Object Oriented Package)
      Scwoop is a composite widget (also known as mega widget) extension to the great Tk widget library. Scwoop is entirely written in Tcl using the stooop (Simple Tcl Only Object Oriented Programming) extension. Edit (January 09, 2000 02:10)
      Supertext - tk text widget with unlimited undo
      Author Bryan Oakley, Version 1.0b1, Works with Tcl 8.0
      Download: supertext.tcl
      Supertext is a package that provides a tk text widget with full undo and the ability to execute procedures both before and after a text widget command has been processed. Supertext may be used as-is, or for the brave it may be used in place of the standard text widget. Edit (August 23, 1999 12:06)
      Tabbed Notebook Widget
      Author Richard Hipp, Version 1.0, Works with Tk 4.1 or later.
      Download: notebook.tcl
      This implements a tabbed notebook using a canvas widget and embedded frames. This is pure Tcl code - not a C extension. Edit (August 23, 1999 12:08)
      Tcl GD - graphics
      Author John Ellson and Spencer Thomas, Version 2.0, Works with 8.0 and higher
      Download: Gdtclft2.0.tar.gz
      Thomas Boutell's Gd package provides a convenient way to generate PNG images with a C program. If you prefer Tcl for CGI applications, you'll want the TCL GD extension. Edit (August 19, 1999 14:52)
      The Meta-GUI Tools
      The Meta-GUI tools provide a framework for quickly building full GUI applications. The GUI is rendered by a run-time engine based on a hierarchical set of definitions you provide. At the bottom of the hierarchy are abstract data types such as length, angle, string, etc., and these are used to progressively build up frames, dialogs, toolbars, menus, and operations. Edit (August 23, 1999 12:10)
      Tkpiechart Home Page
      Tkpiechart is a Tcl-only extension that allows the programmer to create and dynamically update 2D or 3D pie charts in a Tcl/Tk application. This uses the stooop package and builds pie charts on a Tk canvas. Edit (January 09, 2000 02:12)
      TkPrint
      TkPrint is an extension that allows you to print from a Tk widget. Edit (October 11, 1999 09:58)
      TkTable Home Page
      The TkTable widget. The table command creates a 2-dimensional grid of cells. The table can use a Tcl array variable or Tcl command for data storage and retrieval. Edit (November 18, 1999 09:25)
      TkTextMatrix (spreadsheet)
      Author John Arthur Tucker, Version 4.1, Works with Tk 4.1
      Download: download.htm, textmatrix4.1.tar.gz
      A Tcl/Tk spreadsheet widget, TkTextmatrix, which is implemented in C++ and is basically a Tk Canvas widget plus extra behavior for manipulating rows and columns of cell items many times faster than with a plain Tk Canvas. It actually inserts text nearly as fast as the Tk Text widget. If you work with or are interested in creating your own Tcl/Tk widgets in C++, you might want to take a look at the C++ widget library included with this distribution. Edit (August 23, 1999 12:14)
      ToGL - a Tk Open GL widget
      Togl is a Tk widget for OpenGL rendering. Togl is based on OGLTK, originally written by Benjamin Bederson at the University of New Mexico (who has since moved to the University of Maryland). Togl adds the new features:
      • color-index mode support including color allocation functions
      • support for requesting stencil, accumulation, alpha buffers, etc
      • multiple OpenGL drawing widgets
      • OpenGL extension testing from Tcl
      • simple, portable font support
      • overlay plane support
      Togl allows one to create and manage a special Tk/OpenGL widget with Tcl and render into it with a C program. That is, a typical Togl program will have Tcl code for managing the user interface and a C program for computations and OpenGL rendering. Edit (August 23, 1999 12:14)
      Tree Widget
      This implements a tree display in a canvas widget. It is similar in layout to that of the Windows explorer file viewer. This is pure Tcl code - not a C extension. Edit (September 29, 1999 14:37)
      Windows Extensions for Tcl/Tk (Michael Schwartz)
      This site has pointers to several extensions specific to the Windows platform. The extensions provide printing, a MAPI interface to send email, and an interface to manipulate .INI files, among other things. Edit (October 07, 1999 10:50)
      [incr Widgets] Home Page
      [incr Widgets] is a set of megawidgets (combo boxes, etc.) that are upon the [incr Tcl] object system and the [incr Tk] megawidget framework. This comes bundled with the [incr Tcl] distributions. Edit (September 05, 1999 16:08)
      combobox
      Author Bryan Oakley, Version 1.03, Works with 8.x
      Download: combobox.tcl
      combobox is a pure-tcl implementation of a combobox widget. It is entirely self contained and does not require any other OO or megawidget extension. It supports both editable and non-editable entries, and provides the ability to call a procedure anytime the value of the combobox changes. Edit (August 23, 1999 12:15)
      Rnotebook
      Author Daniel Roche, Version 1.0, Works with 8.0 or higher
      Download: index.html
      This implements a resizeable notebook widget in pure tcl/tk Edit (August 19, 1999 15:39)
      saMDI v1.0a1 Multi-Document Interface Extension
      A multi-document interface (MDI) extension for TCL/Tk 8.0. This is a common interface format in Microsoft Windows that lets a parent window contain multiple child windows. In effect you get a window manager inside a window! Uses and includes the STOOOP object-oriented extension by Jean-Luc Fontaine. saMDI v1.0a1 GPL Copyright 1998 Sam Tregar. Edit (August 23, 1999 12:07)
      Tix Support Site
      Author Ioi Lam, (adopted by Gregg Squires), Version 4.1, Works with Tcl 7.4 through Tcl 8.0
      Download, Tix4.1.0.006.tar.gz, Tix41p6.zip, win41p6bin.zip
      Tix has found a new home!
      Tix provides over 40 new Tk including the combo box, file selection dialogs, paned widget, notebook, hierarchical list, directory tree, and more. Edit (August 23, 1999 12:11)
      Tk Tree Widget (C++)
      Tk Tree widget for Tcl8.0.3. This version contains (optional) support for \[incr Tcl\] and \[incr Tk\] version 3.0.
      With the tree widget, you can display a tree in a Tk canvas. The nodes can be made up of any number of canvas items or even other Tk widgets. You create the objects that make up a node and the line that connects it to its parent and pass them to the tree widget. After this the tree widget manages the positions of the nodes and end points of the tree lines. Operations are available for inserting, moving and removing nodes and subtrees and for querrying the position of a node in the tree. The tree can be displayed horizontally or vertically. Edit (August 25, 1999 03:14)
      widget, simple megawidget package
      Author Jeffrey Hobbs, Version 0.9, Works with Tcl/Tk 8.0 or higher
      Download: widget-0.9.tar.gz
      This is a package of megawidgets (i.e., compound widgets) that work almost exactly like Tk widgets. You can also build your own new megawidgets. Includes: combobox, hierarchy, console, progressbar, tabnotebook, validating entry, pane geometry manager, baloon help. Edit (August 23, 1999 12:16)


      Top
      Home | Products | Customers | Partners | Services | Tcl Resources | Company
      Search | Site Map | Feedback | Contact Us | info@scriptics.com
      © 1998-2000 Scriptics Corporation. All rights reserved. Legal Notice | Privacy Statement
      ================================================ FILE: ext/tk/sample/tkextlib/tkHTML/page3/index.html ================================================

      Embedding Tcl in C/C++ Applications

      Presented At:
      The Tcl2K Conference
      Austin, Texas
      9:00am, February 15, 2000
        Instructor:
      D. Richard Hipp
      drh@hwaci.com
      http://www.hwaci.com/drh/
      704.948.4565

      Copies of these notes, example source code,
      and other resources related to this tutorial
      are available online at http://www.hwaci.com/tcl2k/

      $Id$



      Tutorial Outline

      • Introduction
      • Building It Yourself
        • "Hello, World!" using Tcl
        • Tcl scripts as C strings
        • Adding new Tcl commands
        • A tour of the Tcl API
        • Tcl initialization scripts
        • Adding Tk
      • Tools Survey
      • Mktclapp
        • "Hello World" using mktclapp
        • Adding C code
        • Other Features
        • Invoking Tcl from C
        • Running mktclapp directly
        • Real-world examples
      • Summary



      Embedding Tcl in C/C++ Applications

      • You know how to program in Tcl/Tk
      • You know how to program in C/C++
      • This tutorial is about how to do both at the same time.



      Why Mix C With Tcl/Tk?

      • Use C for the things C is good at and Tcl for the things Tcl is good at.
      • Generate standalone executables.
        • Eliminate the need to install Tcl/Tk.
        • Prevent problems when the wrong version of Tcl/Tk is installed.
      • Prevent end users from changing the source code.
        • Keeps users from creating new bugs.
        • Protects proprietary code.
      • Office politics
      • Use Tcl/Tk as a portability layer for a large C program
      • Use Tcl as a testing interface



      Why Mix C With Tcl/Tk?

      "Use C for the things C is good at and use Tcl/Tk for the things Tcl/Tk is good at."

      C is good at:
      • Speed
      • Complex data structures
      • Computation
      • Interacting with hardware
      • Byte-by-byte data analysis
        Tcl/Tk is good at:
      • Building a user interface
      • Manipulation of strings
      • Portability
      • Opening sockets
      • Handling events


      Programming Models

      Mainstream Tcl Programming Model:

       

      Embedded Tcl Programming Model:  

      • Add bits of C code to a large Tcl program
       
      • Add bits of Tcl code to a large C program
      • Main Tcl script loads extensions written in C
       
      • Main C procedure invokes the Tcl interpreter
      • Tcl/Tk is a programming language
       
      • Tcl/Tk is a C library

      Most of the Tcl2K conference is about
       

      This tutorial is about


      "Hello, World!" Using The Tcl Library

      #include <tcl.h>       Always include <tcl.h>
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();       Create a new Tcl interpreter
        Tcl_Eval(interp, "puts {Hello, World!}");       Execute a Tcl command.
        return 0;
      }


      Compiling "Hello, World!"

      Unix:

      $ gcc hello.c -ltcl -lm -ldl
      $ ./a.out
      Hello, World!

      Windows using Cygwin:

      C:> gcc hello.c -ltcl80 -lm
      C:> a.exe
      Hello, World!

      Windows using Mingw32:

      C:> gcc -mno-cygwin hello.c -ltcl82 -lm
      Also works with VC++



      Where Does -ltcl Come From On Unix?

      Build it yourself using these steps:

      • Get tcl8.2.2.tar.gz from Scriptics
      • zcat tcl8.2.2.tar.gz | tar vx
      • cd tcl8.2.2/unix
      • ./configure --disable-shared
      • make
      • Move libtcl8.2.a to your lib directory.
      • Copy ../generic/tcl.h into /usr/include.



      What Other Libraries Are Required For Unix?

      • The sequence of -l options after -ltcl varies from system to system
      • Observe what libraries the TCL makefile inserts when it is building tclsh
      • Examples in this talk are for RedHat Linux 6.0 for Intel



      How To Compile Under Unix Without Installing Tcl

      Specify the *.a file directly:

        $ gcc -I../tcl8.2.2/generic hello.c \ 
            ../tcl8.2.2/unix/libtcl8.2.a -lm -ldl
        $ strip a.out
        $ ./a.out
        Hello, World!

      Or, tell the C compiler where to look for *.a files:

        $ gcc -I../tcl8.2.2/generic hello.c \ 
            -L../tcl8.2.2/unix -ltcl -lm -ldl
        $ strip a.out
        $ ./a.out
        Hello, World!
      The -I../tcl8.2.2 argument tells the compiler where to find <tcl.h>.



      What's "Cygwin"?

      • An implementation of GCC/G++ and all development tools for Windows95/98/NT/2000
      • Available for free download at
        http://sourceware.cygnus.com/cygwin/
      • Also available shrink-wrapped at your local software retailer or online at
        http://www.cygnus.com/cygwin/index.html
      • Programs compiled using Cygwin require a special DLL (cygwin1.dll) that provides a POSIX system API
      • Cygwin1.dll cannot be shipped with proprietary programs without purchasing a license from Cygnus.
      • Mingw32 is the same compiler as Cygwin, but generates binaries that do not use cygwin1.dll



      Where Does -ltcl82 Come From On Windows?

      Build it like this:

      • Get tcl82.lib and tcl82.dll from Scriptics.
      • echo EXPORTS >tcl82.def
      • nm tcl82.lib | grep 'T _' | sed 's/.* T _//' >>tcl82.def
      • dlltool --def tcl82.def --dllname tcl82.dll --output-lib libtcl82.a
      • Move libtcl82.a to the lib directory and tcl82.dll to the bin directory.



      Where Does Your Code Go?

      #include <tcl.h>
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        /* Your application code goes here */       Insert C code here to do whatever it is your program is suppose to do
        return 0;
      }


      Building A Simple TCLSH

      #include <tcl.h>
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        char *z;
        char zLine[2000];
        interp = Tcl_CreateInterp();
        while( fgets(zLine,sizeof(zLine),stdin) ){       Get one line of input
          Tcl_Eval(interp, zLine);       Execute the input as Tcl.
          z = Tcl_GetStringResult(interp);
          if( z[0] ){
            printf("PX\n", z);
          }
            Print result if not empty
        }
        return 0;
      }

      What if user types more than 2000 characters?



      Building A Simple TCLSH

      Use TCL to handle input. Allows input lines of unlimited length.

      #include <tcl.h>
       
      /* Tcl code to implement the
      ** input loop */
      static char zLoop[] = 
        "while {![eof stdin]} {\n"
        "  set line [gets stdin]\n"       Get one line of input
        "  set result [eval $line]\n"       Execute input as Tcl
        "  if {$result!=\"\"} {puts $result}\n"       Print result
        "}\n"
      ;
       

      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        Tcl_Eval(interp, zLoop);       Run the Tcl input loop
        return 0;
      }

      But what about commands that span multiple lines of input?



      Better Handling Of Command-Line Input

      The file "input.tcl"

      set line {}
      while {![eof stdin]} {
        if {$line!=""} {
          puts -nonewline "> "
        } else {
          puts -nonewline "% "
        }
        flush stdout
            Prompt for user input. The prompt is normally "%" but changes to ">" if the current line is a continuation.
        append line [gets stdin]
        if {[info complete $line]} {
          if {[catch {uplevel #0 $line} result]} {       If the command is complete, execute it.
            puts stderr "Error: $result"
          } elseif {$result!=""} {
            puts $result
          }
          set line {}
        } else {
          append line \n
        }
            If the command is incomplete, append a newline and get another line of text.
      }


      Better Handling Of Command-Line Input

      The file "input.c"

      #include <tcl.h>
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        Tcl_Eval(interp, "source input.tcl");       Read and execute the input loop
        return 0;
      }

      But now the program is not standalone!



      Converting Scripts Into C Strings

      static char zInputLoop[] = 
        "set line {}\n"
        "while {![eof stdin]} {\n"
        "  if {$line!=\"\"} {\n"
        "    puts -nonewline \"> \"\n"
        "  } else {\n"
        "    puts -nonewline \"% \"\n"
        "  }\n"
        "  flush stdout\n"
        "  append line [gets stdin]\n"
        "  if {[info complete $line]} {\n"
        "    if {[catch {uplevel #0 $line} result]} {\n"
        "      puts stderr \"Error: $result\"\n"
        "    } elseif {$result!=\"\"} {\n"
        "      puts $result\n"
        "    }\n"
        "    set line {}\n"
        "  } else {\n"
        "    append line \\n\n"
        "  }\n"
        "}\n"
      ;


      Compile Tcl Scripts Into C Programs

      #include <tcl.h>

      static char zInputLoop[] = 
        /* Actual code omitted */
      ;
            Copy and paste the converted Tcl script here

      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        Tcl_Eval(interp, zInputLoop);       Execute the Tcl code
        return 0;
      }


      Converting Scripts To Strings
      Using SED Or TCLSH

      sed -e 's/\\/\\\\/g' \        Convert \ into \\
        -e 's/"/\\"/g' \        Convert " into \"
        -e 's/^/  "/' \        Add " to start of each line
        -e 's/$/\\n"/' input.tcl       Add \n" to end of each line

       

       

      while {![eof stdin]} {
        set line [gets stdin]
        regsub -all {\} $line {&&} line       Convert \ into \\
        regsub -all {"} $line {\"} line       Convert " into \"
        puts "\"$line\\n\""       Add " in front and \n" at the end
      }


      Converting Scripts Into C Strings

      You may want to save space by removing comments and extra whitespace from scripts.

      static char zInputLoop[] = 
        "set line {}\n"
        "while {![eof stdin]} {\n"
        "if {$line!=\"\"} {\n"
        "puts -nonewline \"> \"\n"
        "} else {\n"
        "puts -nonewline \"% \"\n"
        "}\n"
        "flush stdout\n"
        "append line [gets stdin]\n"
        "if {[info complete $line]} {\n"
        "if {[catch {uplevel #0 $line} result]} {\n"
        "puts stderr \"Error: $result\"\n"
        "} elseif {$result!=\"\"} {\n"
        "puts $result\n"
        "}\n"
        "set line {}\n"
        "} else {\n"
        "append line \\n\n"
        "}\n"
        "}\n"
      ;


      Converting Scripts To Strings

      sed -e 's/\\/\\\\/g' \ 
        -e 's/"/\\"/g' \ 
        -e '/^ *#/d' \        Delete lines that begin with #
        -e '/^ *$/d' \        Delete blank lines
        -e 's/^ */  "/' \        Delete leading spaces
        -e 's/$/\\n"/' input.tcl
       

       

       
      while {![eof stdin]} {
        set line [gets stdin]
        set line [string trimleft $line]       Remove leading space
        if {$line==""} continue       Delete blank lines
        if {[string index $line 0]=="#"} {
          continue
        }
            Delete lines starting with #
        regsub -all {\} $line {&&} line
        regsub -all {"} $line {\"} line
        puts "\"$line\\n\""
      }


      Removing Comments Or Leading Space
      Will Break Some Tcl Scripts!

      image create bitmap smiley -data {
      #define smile_width 15
      #define smile_height 15
            These lines begin with # but are not comment
      static unsigned char smile_bits[] = {
         0xc0, 0x01, 0x30, 0x06, 0x0c, 0x18,
         0x04, 0x10, 0x22, 0x22, 0x52, 0x25,
         0x01, 0x40, 0x01, 0x40, 0x01, 0x40,
         0x12, 0x24, 0xe2, 0x23, 0x04, 0x10,
         0x0c, 0x18, 0x30, 0x06, 0xc0, 0x01};
      }
       

       
      text .t
      pack .t
      .t insert end [string trim {
      She walks in beauty, like the night
           Of cloudless climes and starry skies;
      And all that's best of dark and bright
           Meet in her aspect and her eyes;
            Indentation is deleted on lines 2 and 4
      }] 
       

      Problems like these are rare



      Adding A "continue" Command

      set line {}
      while {![eof stdin]} {
        if {$line!=""} {
          puts -nonewline "> "
        } else {
          puts -nonewline "% "
        }
        flush stdout
        append line [gets stdin]
        if {[info complete $line]} {
          if {[lindex $line 0]=="continue"} {
            break;
            Break out of the loop if the command is "continue"
          } elseif {[catch {uplevel #0 $line} result]} {
            puts stderr "Error: $result"
          } elseif {$result!=""} {
            puts $result
          }
          set line {}
        } else {
          append line \n
        }
      }


      Stop For Tcl Input At Various Points
      In A C Program

      #include <tcl.h>
       
      static char zInputLoop[] = 
        /* Tcl Input loop as a C string */
      ;
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        /* Application C code */       Do some computation
        Tcl_Eval(interp, zInputLoop);       Stop for some Tcl input
        /* More application C code */       Do more computation
        Tcl_Eval(interp, zInputLoop);       Stop for more Tcl input
        /* Finish up the application */       Finish the computation
        return 0;
      }


      Using Tcl For Testing

      #include <tcl.h>
       
      static char zInputLoop[] = 
        /* Tcl Input loop as a C string */
      ;
       
      int main(int argc, char **argv){
      #ifdef TESTING
        Tcl_Interp *interp;
            Create interpreter only if TESTING is defined
        interp = Tcl_CreateInterp();
      #endif
        /* Application C code */
      #ifdef TESTING
        Tcl_Eval(interp, zInputLoop);
      #endif
            Accept command-line input only if TESTING is defined
        /* More application C code */
      #ifdef TESTING
        Tcl_Eval(interp, zInputLoop);
      #endif
        /* Finish up the application */
        return 0;
      }


      Creating A New Tcl Command In C

      #include <tcl.h>
       
      int NewCmd(
        void *clientData,
        Tcl_Interp *interp,
        int argc,
        char **argv
            The Tcl command is implemented as a C function with four arguments.
      ){
        printf("Hello, World!\n");
        return TCL_OK;       Returns TCL_OK or TCL_ERROR
      }
       
      static char zInputLoop[] = 
        /* Tcl code omitted... */
      ;
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        Tcl_CreateCommand(interp, "helloworld",
                          NewCmd, 0, 0);
            Tell the interpreter which C function to call when the "helloworld" Tcl command is executed
        Tcl_Eval(interp, zInputLoop);
        return 0;
      }


      Linkage From Tcl To C

      • 3rd parameter of Tcl_CreateCommand() is a pointer to the C subroutine that implements the command.
      • 4th parameter to Tcl_CreateCommand() becomes the 1st parameter to the C routine whenever the Tcl command is executed.
      • 1st parameter to Tcl_CreateCommand() must be a valid Tcl interpreter. The same pointer appears as the second parameter to the C routine whenever the Tcl command is executed.



      Linkage From Tcl To C

      • 5th parameter of Tcl_CreateCommand() is a pointer to the C subroutine that is called when the Tcl command is deleted.
      • 4th parameter to Tcl_CreateCommand() becomes the 1st parameter to the C routine.



      When To Use A Delete Proc

      Examples of where the delete proc is used in standard Tcl/Tk:

      button .b -text Hello
      pack .b
      rename .b {}       Deleting the .b command causes the button to be destroyed

       
      image create photo smiley \ 
          -file smiley.gif
      rename smiley {}       Deleting the smiley command destroys the image and reclaims the memory used to hold the image

      • Always use a delete proc if the clientData is a pointer to malloced memory or some other resource that needs freeing
      • Delete procs are never used in the Tcl core but are used extensively in Tk



      Linkage From Tcl To C

      The argc and argv parameters work just like in main()

      helloworld one {two three} four       argc = 4
      argv[0] = "helloworld"
      argv[1] = "one"
      argv[2] = "two three"
      argv[3] = "four"
      argv[4] = NULL


      A Short-Cut

      In a program with many new Tcl commands implemented in C, it becomes tedious to type the same four parameters over and over again. So we define a short-cut.

      #define TCLARGS \ 
          void *clientData, \ 
          Tcl_Interp *interp, \ 
          int argc, \ 
          char *argv
            Define TCLARGS once in a header file
       
       
       
      int NewCmd(TCLARGS){       Use the TCLARGS macro to define new C functions that implement Tcl commands.
         /* implementation... */
      }

      For brevity, we will use the TCLARGS macro during the rest of this talk.



      Returning A Value From C Back To Tcl

      int NewCmd(TCLARGS){       Note that the C function returns an "int"
        return TCL_OK;       Return value is TCL_OK or TCL_ERROR
      }

      • TCL_OK and TCL_ERROR are defined in <tcl.h>
      • Other valid return values TCL_RETURN, TCL_BREAK and TCL_CONTINUE are rarely used
      • Common mistake: forgetting to return TCL_OK



      Returning A Value From C Back To Tcl

      int NewCmd(TCLARGS){
        Tcl_SetResult(interp,"Hello!",TCL_STATIC);       Set the result to "Hello!"
        return TCL_OK;
      }

      • Result should be the text of an error message if you return TCL_ERROR.
      • 3rd argument to Tcl_SetResult() can be TCL_STATIC, TCL_DYNAMIC, TCL_VOLATILE, or a function pointer.
      • Also consider using Tcl_AppendResult().
      • Direct access to interp->result is deprecated.
      • See the man pages for details.



      The Tcl_Obj Interface

      • A new way to write Tcl commands in C code
      • First introduced in Tcl8.0
      • Can be much faster, especially for lists or numeric values.
      • Able to handle arbitrary binary data.
      • More difficult to program.



      The Tcl_Obj Interface

      int NewObjCmd(
        void *clientData,
        Tcl_Interp *interp,
        int objc,
        Tcl_Obj *const* objv       4th parameter is an array Tcl_Objs, not an array of strings
      ){
        /* Implementation... */
        return TCL_OK;
      }
       
      static char zInputLoop[] = 
        /* Tcl code omitted... */
      ;
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        Tcl_CreateObjCommand(interp, "newcmd",
                             NewObjCmd, 0, 0);
            Use a different function to register the command
        Tcl_Eval(interp, zInputLoop);
        return 0;
      }


      The Tcl_Obj Interface

      • There are countless access methods for reading information from and placing information in Tcl_Objs. Always use the access methods.
      • Details provided at Lee Bernhard's talk this afternoon.
      • Definitely use Tcl_Objs if you are writing a new Tcl extension.
      • Tcl_Objs address some of the weaknesses of Tcl relative to C/C++.
        • Tcl_Objs are faster
        • Tcl_Objs work with binary data
        But C/C++ is faster still and better for working with binary data.
      • When mixing C/C++ with Tcl/Tk the benefits of Tcl_Objs are less important. Using Tcl_Objs in this context may not be worth the extra trouble.
      • This talk will focus on the string interface.



      Nickel Tour Of The Tcl API

      Memory allocation functions

      Tcl_Alloc
      Tcl_Free
      Tcl_Realloc

      Functions useful in the implementation of new Tcl commands

      Tcl_AppendElement
      Tcl_AppendResult
      Tcl_GetBoolean
      Tcl_GetDouble
      Tcl_GetInt
      Tcl_GetStringResult
      Tcl_ResetResult
      Tcl_SetResult

      Functions for controlling the Tcl interpreter

      Tcl_CreateCommand
      Tcl_CreateInterp
      Tcl_CreateObjCommand
      Tcl_DeleteCommand
      Tcl_DeleteInterp
      Tcl_Exit



      Nickel Tour Of The Tcl API

      I/O functions

      Tcl_Close
      Tcl_Eof
      Tcl_Flush
      Tcl_GetChannel
      Tcl_GetChannelMode
      Tcl_GetChannelName
      Tcl_Gets
      Tcl_OpenCommandChannel
      Tcl_OpenFileChannel
      Tcl_OpenTcpClient
      Tcl_OpenTcpServer
      Tcl_Read
      Tcl_Seek
      Tcl_Tell
      Tcl_Ungets
      Tcl_Write
      Tcl_WriteChars

      Names and meanings of system error codes

      Tcl_ErrnoId
      Tcl_ErrnoMsg
      Tcl_GetErrno
      Tcl_SetErrno
      Tcl_SignalId
      Tcl_SignalMsg



      Nickel Tour Of The Tcl API

      General Operating System Calls

      Tcl_Access
      Tcl_Chdir
      Tcl_GetCwd
      Tcl_GetHostName
      Tcl_GetNameOfExecutable
      Tcl_Sleep
      Tcl_Stat

      String Manipulation And Comparison

      Tcl_Concat
      Tcl_Merge
      Tcl_SplitList
      Tcl_StringCaseMatch
      Tcl_StringMatch

      Dynamically Resizable Strings

      Tcl_DStringAppend
      Tcl_DStringAppendElement
      Tcl_DStringEndSublist
      Tcl_DStringInit
      Tcl_DStringLength
      Tcl_DStringResult
      Tcl_DStringSetLength
      Tcl_DStringStartSublist
      Tcl_DStringValue



      Nickel Tour Of The Tcl API

      Event Handlers

      Tcl_CancelIdleCall
      Tcl_CreateChannelHandler
      Tcl_CreateTimerHandler
      Tcl_DeleteChannelHandler
      Tcl_DeleteTimerHandler
      Tcl_DoOneEvent
      Tcl_DoWhenIdle

      Functions For Reading And Writing Tcl Variables

      Tcl_GetVar
      Tcl_GetVar2
      Tcl_LinkVar
      Tcl_SetVar
      Tcl_SetVar2
      Tcl_TraceVar
      Tcl_TraceVar2
      Tcl_UnlinkVar
      Tcl_UnsetVar
      Tcl_UnsetVar2
      Tcl_UntraceVar
      Tcl_UntraceVar2
      Tcl_UpdateLinkedVar

      Functions For Executing Tcl Code

      Tcl_Eval
      Tcl_EvalFile
      Tcl_EvalObj
      Tcl_GlobalEval
      Tcl_GlobalEvalObj
      Tcl_VarEval



      Nickel Tour Of The Tcl API

      Functions For Dealing With Unicode

      Tcl_NumUtfChars
      Tcl_UniCharAtIndex
      Tcl_UniCharIsAlnum
      Tcl_UniCharIsAlpha
      Tcl_UniCharIsControl
      Tcl_UniCharIsDigit
      Tcl_UniCharIsGraph
      Tcl_UniCharIsLower
      Tcl_UniCharIsPrint
      Tcl_UniCharIsPunct
      Tcl_UniCharIsSpace
      Tcl_UniCharIsUpper
      Tcl_UniCharIsWordChar
      Tcl_UniCharLen
      Tcl_UniCharNcmp
      Tcl_UniCharToLower
      Tcl_UniCharToTitle
      Tcl_UniCharToUpper
      Tcl_UniCharToUtf
      Tcl_UniCharToUtfDString
      Tcl_UtfAtIndex
      Tcl_UtfBackslash
      Tcl_UtfCharComplete
      Tcl_UtfFindFirst
      Tcl_UtfFindLast
      Tcl_UtfNcasecmp
      Tcl_UtfNcmp
      Tcl_UtfNext
      Tcl_UtfPrev
      Tcl_UtfToLower
      Tcl_UtfToTitle
      Tcl_UtfToUniChar
      Tcl_UtfToUniCharDString
      Tcl_UtfToUpper

      Functions For Dealing With Tcl_Objs

      Too numerous to list...



      Documentation Of The Tcl API

      • Tcl comes with excellent man pages
      • "Use the source, Luke"
      • See tclDecl.h for a list of API functions
      • The header comments on the implementation of API functions usually gives a good description of what the function does and how it should be used.
      • Most API functions are used within Tcl and Tk. Use grep to locate examples.



      Initialization Scripts

      • Run the mini TCLSH implemented above and execute the parray command
      • It doesn't work! What's wrong?

      • parray is really a Tcl proc that is read in when the interpreter is initialized.

      • parray (and several other commands) are stored in a handful of "Initialization Scripts"

      • All the initialization scripts are stored in the "Tcl Library" - a directory on the host computer.

      Invoke the Tcl_Init() function to locate and read the Tcl initialization scripts.



      The Tcl_Init() Function

      #include <tcl.h>
       
      static char zInputLoop[] = 
        /* Tcl code omitted... */
      ;
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        Tcl_Init(interp);       Locate and read the initialization scripts
        /* Call Tcl_CreateCommand()? */
        Tcl_Eval(interp, zInputLoop);
        return 0;
      }

      But Tcl_Init() can fail. We need to check its return value...



      The Tcl_Init() Function

      #include <tcl.h>
       
      static char zInputLoop[] = 
        /* Tcl code omitted... */
      ;
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        if( Tcl_Init(interp)!=TCL_OK ){
          fprintf(stderr,"Tcl_Init() failed: PX",
             Tcl_GetStringResult(interp));
        }
            Print error message if Tcl_Init() fails
        /* Call Tcl_CreateCommand()? */
        Tcl_Eval(interp, zInputLoop);
        return 0;
      }

      But now the program is not standalone.



      How Tcl_Init() Works

      • Computes the value of variable tcl_libPath.
      • Invokes the procedure named "tclInit"
      • A default tclInit procedure is built into Tcl. You can define an alternative tclInit procedure prior to calling Tcl_Init().



      The Default initTcl Procedure

      set errors {}
      set dirs {}
      if {[info exists tcl_library]} {
        lappend dirs $tcl_library
      } else {
        if {[info exists env(TCL_LIBRARY)]} {
          lappend dirs $env(TCL_LIBRARY)
        }
        lappend dirs $tclDefaultLibrary
        unset tclDefaultLibrary
        set dirs [concat $dirs $tcl_libPath]
      }
      foreach i $dirs {
        set tcl_library $i
        set tclfile [file join $i init.tcl]
        if {[file exists $tclfile]} {
          if {![catch {uplevel #0 [list source $tclfile]} msg]} {
            return
          } else {
            append errors "$tclfile: $msg\n$errorInfo\n"
          }
        }
      }
      error "Can't find a usable init.tcl ..."


      The Default Initialization Sequence

      • The tclInit procedure locates and sources the init.tcl script. The directory that contains init.tcl is stored in the tcl_library variable.
      • The init.tcl script creates an unknown procedure. The unknown procedure will run whenever Tcl encounters an unknown command.
      • The unknown procedure consults the file tclIndex in the tcl_library directory to see if the command is defined by one of the initialization scripts.
      • The unknown procedure sources any needed initialization scripts and retries the command.
      Commands defined in the initialization scripts are loaded on demand.



      Standalone Initialization Techniques

      Manually execute all initialization scripts

      • Convert all initialization scripts into C strings and put them in the executable.
      • Call Tcl_Eval() on each initialization script and omit the call to Tcl_Init()
      • Or, redefine tclInit so that it does not attempt to source init.tcl then call Tcl_Eval() on each initialization script after Tcl_Init() returns.
      This approach is not recommended



      Standalone Initialization Techniques

      Redefining the builtin source command

      • Convert all initialization scripts into C strings and put them in the executable.
      • Create a new source command that calls Tcl_Eval() on the appropriate built-in string instead of reading from the disk.
      • Read from disk if the named file is not one that is built in.



      Redefining source

      static char zInitTcl[] = "...";
      static char zParrayTcl[] = "...";
            Scripts init.tcl and parray.tcl

      int NewSourceCmd(TCLARGS){
        if( !strcmp(argv[1],"/builtin/init.tcl") )
          return Tcl_Eval(interp, zInitTcl);
        if( !strcmp(argv[1],"/builtin/parray.tcl") )
          return Tcl_Eval(interp, zParrayTcl);
            Call Tcl_Eval() on builtin strings if the names match
        return Tcl_EvalFile(interp, argv[1]);       Call Tcl_EvalFile() if no match
      }
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        setenv("TCL_LIBRARY","/builtin");       Causes tclInit to look for init.tcl in /builtin
        interp = Tcl_CreateInterp();
        Tcl_CreateCommand(interp, "source",
                          NewSourceCmd, 0, 0);
            Redefine source
        Tcl_Init(interp);
        Tcl_Eval(interp, zInputLoop);
        return 0;
      }


      Redefining source

      • This approach works for all versions of Tcl and Tk.
      • Also need to redefine the "file exists" Tcl command since it too is used by tclInit.
      • To verify that the program is really standalone, remove the call to Tcl_EvalFile().



      Standalone Initialization Techniques

      Use the Tcl*InsertProc() functions

      • Three routines that overload basic file I/O operations:
        • TclStatInsertProc()
        • TclAccessInsertProc()
        • TclOpenFileChannelInsertProc()
      • Allows us to implement a virtual filesystem that overlays the real filesystem.
      • The virtual filesystem contains all the initialization scripts as compiled-in strings. The initialization scripts look like they are resident on disk even though they are built in.
      • These functions first appeared in Tcl8.0.3. Presumably to support TclPro Wrapper.
      • The only documentation is comments on the code. See the Tcl source file generic/tclIOUtil.c



      The TclStatInsertProc() Function

      • Sole argument is a pointer to a function whose interface is the same as stat()
      • Functions are stacked. Tcl tries each stat function on the list, beginning with the most recently inserted, until one succeeds.



      The TclStatInsertProc() Function

      #include <tclInt.h>       Rather than <tcl.h>!

      static int
      BltinFileStat(char *path,struct stat *buf){
        char *zData;
        int nData;
        zData = FindBuiltinFile(path, 0, &nData);       Check if path is a builtin
        if( zData==0 ){
          return -1;
        }
            Fail if path is not a builtin
        memset(buf, 0, sizeof(*buf));
        buf->st_mode = 0400;
        buf->st_size = nData;
        return 0;       Success if it is builtin
      }
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        TclStatInsertProc(BltinFileStat);       Register new stat function
        interp = Tcl_CreateInterp();
        Tcl_Init(interp);
        Tcl_Eval(interp, zInputLoop);
        return 0;
      }


      The TclAccessInsertProc() Function

      #include <tclInt.h>       Rather than <tcl.h>!

      /* BltinFileStat() not shown... */
       
      static int
      BltinFileAccess(char *path, int mode){
        char *zData;
        if( mode & 3 ) return -1;       All builtins are read-only
        zData = FindBuiltinFile(path, 0, &nData);       Check if path is a builtin
        if( zData==0 ) return -1;       Fail if path is not a builtin
        return 0;       Success if it is builtin
      }
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        TclStatInsertProc(BltinFileStat);
        TclAccessInsertProc(BltinFileAccess);
            Register new stat and access functions
        interp = Tcl_CreateInterp();
        Tcl_Init(interp);
        Tcl_Eval(interp, zInputLoop);
        return 0;
      }


      The TclOpenFileChannelInsertProc() Function

      static Tcl_Channel BuiltinFileOpen(
        Tcl_Interp *interp,   /* The TCL interpreter doing the open */
        char *zFilename,      /* Name of the file to open */
        char *modeString,     /* Mode string for the open (ignored) */
        int permissions       /* Permissions for a newly created file (ignored) */
      ){
        char *zData;
        BuiltinFileStruct *p;
        int nData;
        char zName[50];
        Tcl_Channel chan;
        static int count = 1;
       
        zData = FindBuiltinFile(zFilename, 1, &nData);
        if( zData==0 ) return NULL;
        p = (BuiltinFileStruct*)Tcl_Alloc( sizeof(BuiltinFileStruct) );
        if( p==0 ) return NULL;
        p->zData = zData;
        p->nData = nData;
        p->cursor = 0;
        sprintf(zName,"etbi_bffffc7c_8049b04",((int)BuiltinFileOpen)>>12,count++);
        chan = Tcl_CreateChannel(&builtinChannelType, zName, 
                                 (ClientData)p, TCL_READABLE);
        return chan;
      }


      The TclOpenFileChannelInsertProc() Function

      static Tcl_ChannelType builtinChannelType = {
        "builtin",          /* Type name. */
        NULL,               /* Always non-blocking.*/
        BuiltinFileClose,   /* Close proc. */
        BuiltinFileInput,   /* Input proc. */
        BuiltinFileOutput,  /* Output proc. */
        BuiltinFileSeek,    /* Seek proc. */
        NULL,               /* Set option proc. */
        NULL,               /* Get option proc. */
        BuiltinFileWatch,   /* Watch for events on console. */
        BuiltinFileHandle,  /* Get a handle from the device. */
      };

      For additional information see:

      • The man page for Tcl_CreateChannel()
      • Tk source code file generic/tkConsole.c



      Initializing Tk

      • All the same initialization script issues as Tcl
      • Tk initialization scripts are in a different directory than the Tcl initialization scripts - the "Tk Library"
      • Call Tk_Init() after Tcl_Init()
      • Must have an event loop or Tk will not work!



      Implementing An Event Loop

      button .b -text Hello -command exit
      pack .b
            Create a Tk interface

      bind . <Destroy> {
        if {![winfo exists .]} exit
      }
            Close the application when the main window is destroyed

      while 1 {vwait forever}       The event loop


      "Hello, World!" Using Tk

      #include <tk.h>
       
      static char zHello[] =        The application code
        "button .b "
          "-text {Hello, World} "
          "-command exit\n"
        "pack .b\n";
       
      static char zEventLoop[] =       The event loop
        "bind . <Destroy> {\n"
        "  if {![winfo exists .]} exit\n"
        "}\n"
        "while 1 {vwait forever}\n";
       

      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        Tcl_Init(interp);
        Tk_Init(interp);
            We really should check the return values of the init functions...
        Tcl_Eval(interp, zHello);
        Tcl_Eval(interp, zEventLoop);       The event loop never returns
        /*NOTREACHED*/
      }


      Compiling "Hello, World!" For Tk

      Unix:

        $ gcc hello.c -ltk -L/usr/X11R6/lib \ 
              -lX11 -ltcl -lm -ldl
        $ ./a.out

      Windows using Cygwin:

        C:> gcc hello.c -mwindows -ltk80 -ltcl80 -lm
        C:> a.exe

      Windows using Mingw32:

        C:> gcc -mno-cygwin hello.c -mwindows \ 
                 -ltk82 -ltcl82 -lm
        C:> a.exe



      Making The Program Standalone

      To make a Tcl application standalone you have to convert the following initialization scripts to C strings and compile them into the executable:

        auto.tcl
        history.tcl
        init.tcl
        ldAout.tcl
        package.tcl
        parray.tcl
        safe.tcl
        tclIndex
        word.tcl

      To make a Tk application standalone requires these additional initialization scripts from the Tk Library:

        bgerror.tcl
        button.tcl
        clrpick.tcl
        comdlg.tcl
        console.tcl
        dialog.tcl
        entry.tcl
        focus.tcl
        listbox.tcl
        menu.tcl
        msgbox.tcl
        optMenu.tcl
        palette.tcl
        safetk.tcl
        scale.tcl
        scrlbar.tcl
        tclIndex
        tearoff.tcl
        text.tcl
        tk.tcl
        tkfbox.tcl
        xmfbox.tcl

      Total of about 13K lines and 400K bytes of text or 9K lines and 250K bytes if you strip comments and leading spaces



      A Review Of The Features We Want

      1. Combine C/C++ with Tcl/Tk into a single executable.
      1. The executable should be standalone. It must not depend on files not normally found on the system.
      1. It should be difficult for end users to alter the program (and introduce bugs).



      Available Programming Aids

      Several tools are available. The chart below shows which tools help achieve which objectives.

      Features The Tool Helps To Achieve
      Tool Name Mix C and Tcl Standalone Hide Source
      SWIG    
      TclPro Wrapper  
      FreeWrap  
      Wrap    
      mktclapp



      SWIG

      • Creates an interface between an existing C/C++ library and a high-level programming language. Support for:
        • Tcl/Tk
        • Perl
        • Python
        • Java
        • Eiffel
        • Guile
      • No changes required to C/C++ code. Can be used with legacy libraries.
      • Generates an extension, not a standalone binary
      • The tutorial on SWIG was yesterday afternoon.
      • http://www.swig.org/



      Wrapper Programs

      • Convert a pure Tcl/Tk program into a standalone binary
      • Several wrapper programs are available:
        • TclPro Wrapper - http://www.scriptics.com/
        • FreeWrap - http://www.albany.net/~dlabelle/freewrap/freewrap.html
        • Wrap - http://members1.chello.nl/~j.nijtmans/wrap.html
      • No C compiler required!
      • TclPro will convert Tcl script into bytecode so that it cannot be easily read by the end user. FreeWrap encrypts the scripts.
      • FreeWrap uses compression on its executable. Wrap uses compression on both the executable and on the bundled script files.
      • Usually include extensions like winico and/or BLT



      mktclapp

      • Mix C/C++ with Tcl/Tk into a standalone binary
      • mktclapp generates an application initialization file that contains Tcl scripts as strings and makes all necessary calls to Tcl_Init, Tcl_CreateCommand, Tcl*InsertProc, etc.
      • Features to make it easier to write new Tcl command in C
      • xmktclapp.tcl provides a GUI interface to mktclapp
      • http://www.hwaci.com/sw/mktclapp/



      "Hello, World!" Using Mktclapp

      • Download mktclapp.c and xmktclapp.tcl from http://www.hwaci.com/sw/mktclapp/
      • Compile mktclapp:
          cc -o mktclapp mktclapp.c
          
      • Create "Hello, World!" as a Tcl script in file hw.tcl:
          button .b -text {Hello, World!} -command exit
          pack .b
          
      • Launch xmktclapp:
          wish xmktclapp.tcl
          



      "Hello, World!" Using Mktclapp

      • Set "Command Line Input?" to "None"
      • Set "Standalone?" to "Yes"
      • Enter "hw.mta" for the Configuration File
      • Enter "hw.c" for the Output C File



      "Hello, World!" Using Mktclapp

      • Go to the "Tcl Scripts" page
      • Press "Insert" and add hw.tcl to the list of Tcl scripts
      • Change the "Startup Script" to be hw.tcl.
      • Select File/Build and File/Exit



      "Hello, World!" Using Mktclapp

      • Mktclapp generates hw.c. Compile it something like this:
          cc hw.c -ltk -L/usr/X11R6/lib -lX11 -ltcl -lm -ldl
          
      • Or, if using Cygwin:
          gcc hw.c -mwindows -ltk80 -ltcl80 -lm
          
      • Or, if using Mingw32:
          gcc -mno-cygwin hw.c -mwindows -ltk82 -ltcl82 -lm
          
      • And you're done!



      Adding C Code To Your Program

      Put the new C code in a new source file named "add.c"

      #include "hw.h"       Generated by mktclapp
      int ET_COMMAND_add(ET_TCLARGS){       ET_TCLARGS is a macro defined in hw.h
        int a, b;
        char zResult[30];
        a = atoi(argv[1]);
        b = atoi(argv[2]);
        sprintf(zResult, "-1073742724", a+b);
        Tcl_SetResult(interp, zResult, TCL_VOLATILE);
        return TCL_OK;
      }


      Adding C Code To Your Program

      • Go to the "C/C++ Modules" page of xmktclapp.tcl
      • Press "Insert" and add add.c to the list of C/C++ modules

      • Select File/Build and File/Exit



      Adding C Code To Your Program

      • Compile as follows:
          cc add.c hw.c -ltk -L/usr/X11R6/lib -ltcl -lm -ldl
          
      • Or construct a Makefile that compiles add.c into add.o and hw.c into hw.o and then links them.
      • Compile the same way for Windows except use the usual Windows libraries and options...
      Don't have to worry with Tcl_CreateCommand() - Mktclapp takes care of that automatically.



      Checking Parameters In The add Command

      Modify add.c to insure the add command is called with exactly two integer arguments

      #include "hw.h"
       
      int ET_COMMAND_add(ET_TCLARGS){
        int a, b;
        char zResult[30];
        if( argc!=3 ){
          Tcl_AppendResult(interp,
            "wrong # args: should be: \"",
            argv[0], " VALUE VALUE\"", 0);
          return TCL_ERROR;
        }
            Report an error if there are not exactly 2 arguments
        if( Tcl_GetInt(interp, argv[1], &a)!=TCL_OK ){
          return TCL_ERROR;
        }
            Report an error if the first argument is not an integer
        if( Tcl_GetInt(interp, argv[2], &b)!=TCL_OK ){
          return TCL_ERROR;
        }
            Do the same for the second argument
        sprintf(zResult, "-1073742724", a+b);
        Tcl_SetResult(interp, zResult, TCL_VOLATILE);
        return TCL_OK;
      }


      Using The Tcl_Obj Interface

      In the file objadd.c put this code:

      #include "hw.h"

      int ET_OBJCOMMAND_add2(ET_OBJARGS){
        int a, b;
            Use "ET_OBJCOMMAND" instead of "ET_COMMAND" and "ET_OBJARGS" instead of "ET_TCLARGS"
        if( objc!=3 ){
          Tcl_WrongNumArgs(interp, 1, objv,
            "number number");
          return TCL_ERROR;
        }
            A special routine for "wrong # args" error
        if( Tcl_GetIntFromObj(interp, objv[1], &a) ){       Instead of Tcl_GetInt
          return TCL_ERROR;
        }
        if( Tcl_GetIntFromObj(interp, objv[2], &b) ){
          return TCL_ERROR;
        }
        Tcl_SetIntObj(Tcl_GetObjResult(interp), a+b);       Result stored as integer, not a string
        return TCL_OK;
      }


      Speed Of Tcl_Obj Versus "char*" Interfaces

      • Compile both add and add2 into the same executable.
      • Compare their speeds:
           time {add 123456 654321} 10000
          26 microseconds per iteration
           time {add2 123456 654321} 10000
          4 microseconds per iteration
          
      • The Tcl_Obj version is 650 faster!
      • Replace the addition with a "real" computation that takes 10 milliseconds.
      • Now the Tcl_Obj version is only 0.2 faster!
      In many real-world problems, the Tcl_Obj interface has no noticeable speed advantage over the string interface.



      More About Built-in Tcl Scripts

      • Comments and leading white-space are removed from the script by default. Use the "Don't Strip Comments" button to change this.
      • The file name must exactly match the name that is used by the source command.



      Locations Of Libraries

      • Tells mktclapp where to look for script libraries.
      • All Tcl scripts in the indicated directories are compiled into the appinit.c file.
      • Comments and extra white-space are removed. There is no way to turn this off.



      Built-in Binary Data Files

      • Arbitrary files become part of the virtual filesystem
      • No comment or white-space removal is attempted
      • Useful for images or other binary data



      New Commands In Namespaces

      Two underscores (__) are replaced by two colons (::) in command names, thus giving the ability to define new commands in a namespace

      #include <hw.h>

      int ET_COMMAND_adder__add(ET_TCLARGS){
        int a, b;
            Creates the Tcl command called "adder::add"
        char *zResult[30];
        if( argc!=3 ){
          Tcl_AppendResult(interp,
            "wrong # args: should be: \"",
            argv[0], " VALUE VALUE\"", 0);
          return TCL_ERROR;
        }
        if( Tcl_GetInt(interp, argv[1], &a)!=TCL_OK ){
          return TCL_ERROR;
        }
        if( Tcl_GetInt(interp, argv[1], &b)!=TCL_OK ){
          return TCL_ERROR;
        }
        sprintf(zResult, "-1073742724", a+b);
        Tcl_SetResult(interp, zResult, TCL_VOLATILE);
        return TCL_OK;
      }


      Adding Your Own main()

      int main(int argc, char **argv){
        /* Application specific initialization */
        Et_Init(argc, argv);       Never returns!
        /*NOTREACHED*/
        return 0;
      }

      The "Autofork" feature is disabled if you supply your own main()



      Initializing The Tcl Interpreter

      #include <tcl.h>
       
      int counter = 0;
       
      int main(int argc, char **argv){
         Et_Init(argc, argv);
         /*NOTREACHED*/
         return 0;
      }
       
      int Et_AppInit(Tcl_Interp *interp){
        if( Blt_Init(Interp) ){
          return TCL_ERROR;
        }
            Example: Initialize an extension
        Tcl_LinkVar(interp, "counter", &counter,
                    TCL_LINK_INT);
            Or link a C variable to a Tcl variable
        return TCL_OK;       Return TCL_OK if successful
      }


      Writing Your Own Event Loop

      #include <tcl.h>
      void Et_CustomMainLoop(Tcl_Interp *interp){       Replaces the default event loop
        return;       Ex: Return without handling any events.
      }
       
      int main(int argc, char **argv){
        Et_Init(argc, argv);       This now returns after initializing Tcl
        /* Application code here */
        return 0;
      }


      Writing Your Own Event Loop

      #include <tcl.h>
       
      void Et_CustomMainLoop(Tcl_Interp *interp){
        for(;;){
          Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT);
          /* Other processing... */
        }
            Intermix processing and event handling
      }
       
      int main(int argc, char **argv){
        Et_Init(argc, argv);       Never returns
        /*NOTREACHED*/
        return 0;
      }


      Mktclapp Initialization Sequence

      • Initialization starts when the Et_Init() function is called either by client code or by the main() that mktclapp generates
      • Create the main Tcl interpreter
      • Construct the virtual filesystem overlay by redefining the source command and by using the Tcl*InsertProc() functions
      • Call Et_PreInit() if the client defines it
      • Call Tcl_Init() and Tk_Init()
      • Call Tcl_CreateCommand() and Tcl_CreateObjCommand() for every ET_COMMAND_* and ET_OBJCOMMAND_* function in the client code
      • Call Et_AppInit() if the client defines it
      • Run the main Tcl script if there is one
      • Call Et_CustomMainLoop() if defined by client code or else run the built-in event loop



      Invoking Tcl From C

      • Use one of the built-in evaluation functions:
        • Tcl_Eval()
        • Tcl_VarEval()
        • Tcl_EvalFile()
        • Tcl_GlobalEval()
        • Tcl_EvalObj()
        • Tcl_GlobalEvalObj()
      • Mktclapp provides evaluation functions with variable argument lists as in printf():
        • Et_EvalF()
        • Et_GlobalEvalF()
      • Mktclapp provides a global variable Et_Interp which is a pointer to the main interpreter



      Invoking Tcl From C

      Example: A C function that pops up an error message dialog box

      #include "appinit.h"
       
      void ErrMsg(char *zMsg){
        Tcl_SetVar(Et_Interp, "zMsg", zMsg, TCL_GLOBAL_ONLY);
        Tcl_GlobalEval(Et_Interp, 
          "tk_messageBox -icon error -msg $zMsg -type ok");
        Tcl_UnsetVar(Et_Interp, "zMsg", TCL_GLOBAL_ONLY);
      }


      Invoking Tcl From C

      The same C function implemented using Et_EvalF() instead of Tcl_GlobalEval()

      #include "appinit.h"
       
      void ErrMsg(char *zMsg){
        Et_EvalF(Et_Interp, 
          "tk_messageBox -icon error -msg {PX} -type ok",
          zMsg);
      }

      • Suppose the function is called as follows:
        ErrMsg("Syntax error near \"}\"");
      • The command that gets executed is:
            tk_messageBox -icon error -msg \ 
                {Syntax error near "}"} -type ok
          
      • But this is an ill-formed Tcl command!



      Invoking Tcl From C

      Use the "" format to generate a quoted string

      #include "appinit.h"
       
      void ErrMsg(char *zMsg){
        Et_EvalF(Et_Interp, 
          "tk_messageBox -icon error -msg \"%\" -type ok",
          zMsg);
      }

      • The puts a backslash before all characters that are special to Tcl
      • The Tcl command becomes:
            tk_messageBox -icon error -msg \ 
                "Syntax error near \"\}\"" -type ok
          



      Other Functions Provided By Mktclapp

      • void Et_ResultF(Tcl_Interp*, ...);
      • char *Et_DStringAppendF(Tcl_DString*, ...);
      • int Et_AppendObjF(Tcl_Obj*, ...);
      • char *mprintf(const char *format, ...);
        char *vmprintf(const char *format, va_list);
      • void Et_NewBuiltinFile(char *filename, char *data, int amt);



      Operating Mktclapp From The Command Line

      • Generate the appinit.h header file like this:
        mktclapp -header >appinit.h
      • Generate the appinit.c file like this:
        mktclapp -f appinit.mta >appinit.c
      • The *.mta file is just a list of command-line options
      • Enter
        mktclapp -help
        to get a list of available options
      • Look at MTA files generated by xmktclapp.tcl for examples



      Format Of An MTA File

      # Configuration file generated by xmktclapp
      # Hand editing is not recommended
      #
            Comments begin with one #
      ## Autofork No
      ## CFile:add.c 1
      ## CFile:objadd.c 1
      ## CmdLine Console
      ## ConfigFile hw.mta
      ## Data:check.gif 1
      ## MainScript hw.tcl
      ## Mode Tcl/Tk
      ## NoSource No
      ## OutputFile hw.c
      ## Shroud No
      ## Standalone Yes
      ## TclFile:hw.tcl 1
      ## TclLib /usr/lib/tcl8.0
      ## TkLib /usr/lib/tk8.0
            Lines beginning with two #s are used by xmktclapp.tcl and ignored by mktclapp
      -console
      -main-script "hw.tcl"
      -tcl-library "/usr/lib/tcl8.0"
      -tk-library "/usr/lib/tk8.0"
      "add.c"
      "objadd.c"
      -i "check.gif"
      -strip-tcl "hw.tcl"
            All other lines are read by mktclapp and ignored by xmktclapp.tcl


      Summary

      • Use Tcl for the things Tcl is good at and use C/C++ for the things that C/C++ is good at
      • Use wrapper programs to make pure Tcl programs standalone
      • Use mktclapp to combine Tcl/Tk with C/C++ into a standalone



      ================================================ FILE: ext/tk/sample/tkextlib/tkHTML/page4/index.html ================================================ [fm] welcome to freshmeat.net
      freshmeat.net
      find:
      linux.com partner
      news |
      appindex |
      editorials |
      lounge |
      contribute |
      feedback |
      about |
      awards |
      FAQ |

      sort by: [ date | name | urgency ]
       
      We should get this out of the door now
      scoop - January 29th 2000, 23:59 EST

      Everyone else is talking about it, so we should announce it ourselves before you start to think it's a government hoax. Server 51 is our new hosting service for Open Source projects, based on Super Cool Space Alien Technology(TM). We hadn't planned to announce it quite so soon, and it's still in the alpha stage as we work day and night at integrating SCSAT with our terrestrial systems, but feel free to take a look around and see what's going on. When we're out of the testing stage and ready to make room for your project, we'll send word via your implants. Be listening.

      [ comments (8) ]

       Category: freshmeat homepage  

      Is Linux for Crazies?
      jeff covey - January 29th 2000, 23:59 EST

      Ray Woodcock writes: "In terms relevant to Linux, this freshmeat editorial glances at the tendency of mainstream viewpoints to dismiss other viewpoints as 'fringe,' the propensity of dissident movements to splinter into factions before they can effectively counter their primary adversaries, and the difficulty of creating stability without squelching curiosity."

      [ comments (2), 2065 words in body ]

       Category: Editorial  

      RabbIT 2.0.2
      Ernimril - January 29th 2000, 18:29 EST

      RabbIt is the mutating, caching webproxy which is used to speed up surfing over slow links like modems. It does this by removing advertising and background images and scaling down images to low quality JPEGs. RabbIT is written in Java and should be able to run on any platform. It does depend upon an image converter if imagescaleing is on. The recommended image converter is "convert" from the ImageMagick package.

      Changes: Fixes have been made for a few bugs concerning keep alive and the HTTP response header, a bug with NT and cache directories, a bug concerning requests without a response body, a bug in GZIPHandler that caused it to not gzip already compressed (gzip or compress) streams, a bug in HTTPHeader regarding response phrases that are multiline, and a few bugs in ImageHandler and NCache. GZIPHandler has been built as an intermediate(*) to FilterHandler (this means that it is possible to gzip text/plain, etc., without filtering those streams) uuencoding has been added to the Coder, RabbIT now uses HTTP/1.1, HTMLParser now compiles cleanly with Jikes, and GeneralHeader has been created to allow for HTTPFooter (which is useful when sending chunked data).

      Urgency: low

      [ comments (0) ]

       License: freely distributable
       Category: Daemons/Proxy
      download homepage appindex record  

      nmpg 1.1.3
      Joel Lindau - January 29th 2000, 18:18 EST

      nmpg is a small command-driven frontend and network-jukebox for mpg123.

      Changes: Bugfixes, better memory managment, a new .nmpgrc parser, and new options.

      Urgency: low

      [ comments (0) ]

       License: OpenSource
       Category: Console/Sound
      download homepage changelog appindex record  

      mod_dtcl 0.7.3
      David Welton - January 29th 2000, 18:11 EST

      Mod_dtcl is a free/open source implementation of server-parsed Tcl under Apache. It allows you to tightly integrate HTML with Tcl, a widely-used scripting language with many years of development invested in it. There are also many external Tcl modules that you can load into mod_dtcl, to create images, access databases, etc.

      Changes: A major overhaul of header handling and internal buffering, and the addition of the ability to handle binary data.

      Urgency: low

      [ comments (0) ]

       License: GPL
       Category: Web/Development
      download homepage changelog appindex record  

      CoreLinux++ 0.4.6
      Frank V. Castellucci - January 29th 2000, 18:07 EST

      CoreLinux++ is an initiative to normalize methods and conventions for OOA/OOD/C++ development for Linux, materialized in a set of Open Source C++ class libraries (libcorelinux++ and libcoreframework++) to support common patterns and exploit the C++ standards.

      Changes: This release adds AbstractFactory and AssociativeIterator analysis, design, implementations, test code, a CVS daily tarball, a Patch Submission facility and updated FAQ, Web Pages, and defect reporting guidelines.

      Urgency: medium

      [ comments (0) ]

       License: LGPL
       Category: Development/Libraries
      download homepage changelog appindex record  

      scribe 0.2
      ChromeBob - January 29th 2000, 12:12 EST

      scribe writes functions prototypes for your C code, so you don't have to. It also compares unique functions between source code files and will 'extern' when appropriate. C++ methods support is also planned.

      Changes: A fix for an fflush() bug and better documentation.

      Urgency: low

      [ comments (0) ]

       License: GPL
       Category: Development/Tools
      download homepage appindex record  

      E theme updater 0.1
      Hallvar Helleseth - January 29th 2000, 12:04 EST

      E theme Updater is a bash script to automatically update all of your Enlightenment themes from e.themes.org.

      Changes: Initial release.

      [ comments (0) ]

       License: GPL
       Category: Console/Misc
      download homepage appindex record  

      Powertweak-Linux 0.1.7
      Dave Jones - January 29th 2000, 12:03 EST

      Powertweak-Linux is a port of the Microsoft Windows tool of the same name rewritten from the ground up. Its main function is to tune your system to its optimal performance settings. Currently, it tunes PCI chipsets and can set /proc/sys entries.

      Changes: A major GUI overhaul, the ability to generate configuration files, extended PCI information tabs, extra information support for the Matrox G200, and numerous other bugfixes & improvements.

      Urgency: low

      [ comments (2) ]

       License: GPL
       Category: Console/System
      download homepage changelog appindex record  

      Pexeso Beta
      Pavol Krigler - January 29th 2000, 11:55 EST

      pexeso is a simple graphic card game for one or two players.

      Changes: Initial public release.

      [ comments (0) ]

       License: Freeware
       Category: Console/Games
      download homepage appindex record  

      XZX 2.9.2
      E. Kunze - January 29th 2000, 11:54 EST

      XZX is a portable emulator of ZX Spectrum 48K/128K/+3 (8-bit home computers made by Sir Clive Sinclair) and Pentagon/Scorpion (Spectrum clones made in Russia) for machines running UNIX and the X Window system. XZX is completely written in C and emulates Spectrum 48K, 128K, +2 and +3, Pentagon and Scorpion, Interface I with up to 8 microdrives, Multiface 128 and Multiface 3, BetaDisk 128 interface by Technology Research Ltd with 4 disk drives, +D interface by Miles Gordon Technology with 2 disk drives, Kempston mouse, Kempston joystick and built-in machine code monitor.

      Changes: Lots of feature improvement and bug fixes. Most parts of the audio support has been rewritten for different UNICES.

      Urgency: low

      [ comments (0) ]

       License: Shareware
       Category: X11/Emulators
      download homepage changelog appindex record  

      DistroLib 0.4
      PhiR - January 29th 2000, 11:54 EST

      DistroLib is an abstraction library designed to make the development of distributed application easier. Its main target is currently compute-bound tasks based on a one server, many clients model (much like distributed.net), but it is quite generic and could be used for any client/server app. It is lightweight, easy-to-use, and relies heavily on threads.

      Changes: Important bug fixes and command history support.

      Urgency: low

      [ comments (0) ]

       License: GPL
       Category: Development/Libraries
      download homepage changelog appindex record  

      ToutDoux 1.1.7
      yeupou - January 29th 2000, 11:54 EST

      ToutDoux is a project manager which lets you design a plan of action using a tree structure, with translations in French and English.

      Changes: A new menu and XML standard for save files.

      Urgency: low

      [ comments (0) ]

       License: GPL
       Category: GNOME/Tools
      download homepage appindex record  

      goMP 1.0.3
      Gautier - January 29th 2000, 11:52 EST

      goMP is a set of CGI scripts that allows you to remotely control, via a Web browser, a computer acting as an MP3 jukebox. This program is very useful for someone who's got a dedicated computer with a lot of MP3 files but that doesn't have any output and input devices except network and sound card. It's main advantages are built-in cataloging, fast access to music, and no special software needed on the client side.

      Changes: Bugfixes, a password-protected config page, basic search function, easier installation thanks to an install script, and relocation of HTML docs and CGIs to a subdirectory.

      Urgency: medium

      [ comments (0) ]

       License: Artistic
       Category: Web/Tools
      download homepage changelog appindex record  

      APSEND 1.40
      M.K. - January 29th 2000, 11:50 EST

      APSEND is a TCP/IP packet sender to test firewalls and other network applications. It also includes a syn flood option, the land DoS attack, and a DoS attack against tcpdump running on a UNIX-based system. Future updates will include support for a scripting language to construct TCP packets and a few more options and protocols like UDP and ICMP. A port of APSEND from Perl to C is planned as well.

      Changes: The stream attack, bugfixes, and rewrites for parts of the code.

      Urgency: low

      [ comments (0) ]

       License: GPL
       Category: Console/Networking
      download homepage changelog appindex record  

      ecasound 1.6.12r10
      Kai Vehmanen - January 29th 2000, 11:48 EST

      Ecasound is a software package designed for multitrack audio processing. It can be used for simple tasks like audio playback, recording and format conversions, as well as for multitrack effect processing, mixing, recording and signal recycling. Ecasound supports a wide range of audio inputs, outputs and effect algorithms. Ecasound has a chain-based design that allows effects to be easily combined both in series and in parallel. Oscillators and MIDI-CCs can be used for controlling effect parameters. Includes a versatile console mode interface, a Qt-based X-interface and various command-line utils suitable for batch processing.

      Changes: Support for 24- and 32-bit audio formats and for ALSA 0.5, multichannel noisegate, a new 2nd order lowpass filter, some ia-mode commands, and various bugfixes and low-level improvements.

      Urgency: low

      [ comments (0) ]

       License: GPL
       Category: Console/Sound
      download homepage changelog appindex record  

      SCEZ 20000129
      endergone Zwiebeltuete - January 29th 2000, 11:46 EST

      SCEZ is a library that should make the handling of smart cards (not memory cards) and card readers as simple as possible and be at the same time small and easily portable. Currently supported are Dumb Mouse, CT-API and Towitoko readers and Schlumberger Cryptoflex, Gemplus GPK4000, GSM SIM and Telesec SigG cards. A PKCS#15 implementation is in the design phase. There are ports to PalmOS and MS-Windows available.

      Changes: More card and reader drivers, and an application to read out GSM SIM card (phone book and SMS) and write it to the card.

      Urgency: low

      [ comments (0) ]

       License: BSD type
       Category: Development/Libraries
      download homepage appindex record  

      Comicq 0.2.0
      Terminal6 - January 29th 2000, 11:45 EST

      COMICQ is a command line ICQ messaging tool that allows a user to connect to ICQ using your UIN and password, then sends a message to the destination UIN.

      Changes: Several bugfixes, icq99a compliance, and a new option --ip that allows you to get any user's IP by their UIN.

      Urgency: low

      [ comments (0) ]

       License: GPL
       Category: Console/Communication
      download homepage appindex record  

      senv 0.2
      Zbyszek Sobiecki - January 29th 2000, 11:44 EST

      Senv allows you to run programs with a specified environment. It can set uid, gid, root directory, working directory, limits, and environment variables. It is useful in init scripts and as a shell for users for setting resource limits and environment variables. You can create sets of configurations and specify the one to use from command line.

      Changes: Login shell limits and environment setting for users, permanent resource limits for specified groups of users and environment variables, and other minor bugfixes.

      Urgency: low

      [ comments (0) ]

       License: GPL
       Category: Console/Administration
      download changelog appindex record  

      XZX 2.9.2
      E. Kunze - January 29th 2000, 10:55 EST

      XZX is a portable emulator of ZX Spectrum 48K/128K/+3 (8-bit home computers made by Sir Clive Sinclair) and Pentagon/Scorpion (Spectrum clones made in Russia) for machines running UNIX and the X Window system. XZX is completely written in C and emulates Spectrum 48K, 128K, +2 and +3, Pentagon and Scorpion, Interface I with up to 8 microdrives, Multiface 128 and Multiface 3, BetaDisk 128 interface by Technology Research Ltd with 4 disk drives, +D interface by Miles Gordon Technology with 2 disk drives, Kempston mouse, Kempston joystick and built-in machine code monitor.

      Changes: Lots of feature improvement and bug fixes. Most parts of the audio support has been rewritten for different UNICES.

      Urgency: low

      [ comments (0) ]

       License: Shareware
       Category: X11/Emulators
      download homepage changelog appindex record  

      [ full page for today | yesterday's edition ]
      navigator
      - full page for today
      - yesterday's edition
      - new: fm news via NNTP
       

      eye catcher
      Free Shirts
      We give away a free freshmeat t-shirt every week for the best comment added to an application announcement or story posted on freshmeat.

      #freshmeat
      If you want to chat about what's new on freshmeat and hang out with other fm lounge lizards and the fm staff, head over to #freshmeat on irc.freshmeat.net, part of The Open Projects Network.  

      site notes
      - We should get this out of the door now (Jan 29th)
      - freshmeat Y2K report (Jan 01st)
      - Assorted freshmeat notes (Aug 16th)
       

      recent editorials
      - Is Linux for Crazies? (Jan 29th)
      - A New Business Plan for Free Software (Jan 22nd)
      - Is Linux Going to Reunite the UNIX Market? (Jan 15th)
       

      andover.net

      Mirror Logo

      - Animation Factory
      - DaveCentral
      - FreeCode
      - Internet Traffic Report
      - IT Manager's Journal
      - MediaBuilder
      - Slashdot
      - Slaughterhouse
      - TechMailings
      - TechSightings

      E-Commerce

      - ThinkGeek (Stuff for smart masses)
       

      supported sites
      - Userfriendly.org
      - SecurityFocus
      - copyleft
      - Filewatcher
      - Linux.com
      - LinuxTelephony
      - LinuxToday
      - Openprojects
      - 32bitsonline
      - The GNU Project
       

      saturday
      - We should get this out of the door now
      - Is Linux for Crazies?
      - RabbIT 2.0.2
      - nmpg 1.1.3
      - mod_dtcl 0.7.3
      - CoreLinux++ 0.4.6
      - scribe 0.2
      - E theme updater 0.1
      - Powertweak-Linux 0.1.7
      - Pexeso Beta
      - XZX 2.9.2
      - DistroLib 0.4
      - ToutDoux 1.1.7
      - goMP 1.0.3
      - APSEND 1.40
      - ecasound 1.6.12r10
      - SCEZ 20000129
      - Comicq 0.2.0
      - senv 0.2
      - XZX 2.9.2
      - log4j 0.7.5
      - SQN Linux 1.6
      - Limo 0.3.2
      - Fusion GS 1.3
      - MMR 1.5.4
      - KUPS 0.3.4
      - 3DSE patch for XMMS 4
      - Linux 2.3.41
      - Free Code for Linux S/390
      - CircleMUD 3.0 beta patchlevel 17
      - NiL Isn't Liero 000128
      - OpenSSH Unix Port 1.2.2
      - KBoxes! 1.3
      - phpLanParty 0.23
      - DGen/SDL 1.20
      - EdcomLib 1.0 alpha 5
      - Etherboot 4.4.2
      - BLADE 0.18.0
      - Sapphire 0.13.7
      - ippl 1.99.3
      - Saint 1.5patch1
      - Zircon 1.18.232
      - nmap 2.3BETA14
      - xterm patch #124
      - MyThreads-Links v0.5.2
      - sudo 1.6.2p1
      - MIT Photonic-Bands 0.10
      - Launcher 0.86
      - nano 0.8.1
      - Gtk-- 1.1.8
      - tkchooser 0.65
      - XShipWars 1.33a
      - Lamerpad 0.1
       

      friday
      - fsv 0.9
      - popsneaker 0.1.1
      - eyep-updater.sh 1.0
      - W3Mail 0.5.0
      - The Urgent Decision 0.9.9
      - LTSP 1.02
      - Production BASIC 0.2.12
      - Postfix 19991231-pl03
      - Mp3 Commander 0.7
      - iManager 1.0.1b
      - Eterm 0.9
      - dqd_dirindex 1.0
      - Tidings 1.0.4
      - localscan 2.1
      - WMKeyboard 0.3
      - fcmp 1.0.2
      - Akkord 0.3.1
      - HiM 0.1.1
      - cdrecord 1.8
      - eMixer 0.05.5
      - FreeVSD 1.4.0
      - Common C++ Libraries 0.0
      - Moonshine 1.0beta2
      - swim 0.3.5
      - Xmame/xmess 0.36b15.1
      - pcmcia-cs 3.1.9
      - gPS 0.5.2
      - Snort 1.5.1
      - Pygmy Linux 0.7 beta
      - Intro to Bash Programming HOWTO 0.3
      - GNU Pth 1.3b2
      - Laonux 0.1
      - x-wvdial 0.12
      - Intro to Bash Programming HOWTO 0.3
      - Catalog 1.02
      - harvest 1.5.20-kj-0.9
      - wmseti 0.3.0a
      - RIG 1.02
      - FreeAddr 0.2
      - GtkAda 1.2.5
      - dot.conf 0.6.0
      - dep.pl 1.28.0
      - Prae's Scripts 1.1
      - Project Clock 0.1
      - Xtheater 0.2.1
      - i-no Chart 0.1
      - spliff 0.8.1
      - Regexx 0.95
      - RBook 0.5.0
      - RIG 1.01
      - wchat 1.2.0
      - PCCS MySQLDatabase Admin Tool 1.2.2
       

      thursday
      - CADUBI 1.1b1
      - Angus' Chess Clock 0.8.1
      - MP3 Report Generator 1.0.0
      - 4DOM 0.9.2
      - 4XSLT 0.8.2
      - OpenNaken 1.10
      - iManager 1.0b
      - QuakeForge 0.1.0
      - pylice 0.7.0
      - Solfege 0.6.0
      - xinetd 2.1.8.7p1
      - jac 0.13
      - Xmms 1.0.0
      - KSrnd 0.97
      - getpg / UW-IMAP 0.54
      - getpg 0.53
      - setserial 2.17
      - Pan 0.7.3
      - jwhois 2.4.1
      - Kmp3 1.0
      - xPine 0.0.12
      - Avenger's News System 2.1 Alpha
      - RIG 1.0
      - scroller 1.0
      - Perl EyeP Client 0.1
      - sfront 0.54
      - XFrisk 1.2
      - Moffy 0.0.1
      - Solid POP3 0.14
      - php3guest 1.5
      - crUD 01.27.2000
      - crUD 01.27.2000
      - Free Pascal Compiler 0.99.14
      - gtk-font-hack 0.2-gtk-1.2.6
      - Linux 2.2.15pre5
      - krunseti 0.2.1
      - CompuPic 5.0.1036
      - gfontview 0.3.3
      - authlocal 1.0.2
      - bigwig 1.1
      - CAFire 0.0.11
      - ANVLOGIN 2.0
      - sawmill.el 1.9
      - Perlsh 20000127
      - sitescooper 2.1.2
      - MHDns 1.4
      - JChemPaint 0.5
      - Filesystems HOWTO 0.7.3
      - KSnes9x 1.2
      - Mozilla M13
      - edna 0.3
      - GMasqdialer 0.99.8
      - spliff 0.8
      - MultiSeti 0.3
      - rude 0.50
      - cgi-util++ 0.0
      - Cricket 0.72
      - nuni 0.04
      - Ksetiwatch 0.3.0
      - SiteMgrYAP 0.1.2
      - phpLanParty 0.21
      - Glitter Newsreader 0.1
      - Fastresolve 2.4
      - ColdSync 1.1.2
      - DDD 3.2
      - X Northern Captain 4.2.1
      - abcde 1.0.2
      - Gnapster 1.3.2
      - xmix 1.0 Alpha
      - gtktetcolor 0.3
      - muttzilla 0.40
      - muttzilla 0.40
      - asp2php 0.73.6
      - mod_ticket 1.0
      - MegaHAL for Eggdrop .01
      - Jetty 2.3.5
      - xlpotdb 1.0
      - Koala Complete MUD Server 0.1.1a
      - mcountd 0.4
      - cdbackup 0.5.0
      - The Java SSH/Telnet Application/Applet 2.0 RC1
       

      slashdot
      - Petition Apple for Linux QuickTime
      - GNUstep 0.6.5 freeze
      - YETI@Home
      - Documents Unsealed in Microsoft/Caldera Case
      - Who Bought Linux.Net?
      - E-Mails from (Over?) The Edge
      - Linux Kernel 2.3.41
      - Congress Still Figuring Out E-Mail
      - Sci Fi Literature 101?
      - Could Distributed.Net Help the Mars Polar Lander?
       

      securityfocus
      - Win2000 security hole a 'major threat'
      - Visa acknowledges cracker break-ins
      - What's Wrong With Microsoft Security?
      - Microsoft posts first Win2K security patch
      - Libnids 1.12
      - New hack attack is greater threat than imagined
      - Student charged with hacking
      - Building and Managing Virtual Private Networks (book)
      - Threats, Vulnerabilities and Real-Worl Responses: The Foundations of the TruSecure Process
      - The Hundredth Window : Protecting Your Privacy and Security in the Age of the Internet (boo
       

      bebits
      - Pe 3.0a3
      - Rarscript 1.5
      - CD Manager 0.66a beta
      - TraX 1.1
      - BeMath 1.2.2
      - simple blackjack 1
      - HtmlTree 0.5.3
      - Yacp 0.1
      - TicTacToe 1.5
      - Pe 3.0a2
       

      linuxtoday
      - Linux Journal: KDE--The Next Generation
      - Kernel Cousin gimp-devel #11 Is Out
      - Infoworld: Corel Linux OS ideal for the desktop
      - Technology Evaluation: IBM Jumps on the Linux Bandwagon with Both Feet, Sort Of
      - Tobias Hvekamp: European Union acknowledges
      - &
      - #34;Open Source Software
      - &
      - #34;
       

      linuxtelephony
      - Traverse Technologies releases NETspider-U in US
      - Quicknet releases new GPL'd Linux Drivers!
      - Natural Microsystems Delivers Carrier-Class Linux
      - Quicknet is hiring programmers of all kinds!
      - Babylon MLPPP Software Released under GPL
      - Linux Telephony Server Project?
      - Vovida Networks to Hire Telephony Software Engineers
      - SPIRO-Linux Introduces Web-Enabled Phone Administration
      - LinuxTelephony sponsors area at LinuxFest 2000
      - GSM-Mobile Switching Center (MSC) with Linux-PC
       

      32bitsonline
      - Game: Homeworld
      - DVD Lawsuit Spreads Its Own 'Trade Secrets'
      - Register.com Adds 'One-step' Domain Registration
      - WebEvent: Keeping you organized
      - Y2K Officers Defend $100 Bil Investment
      - DON'T BE FOOLED
      - Microsoft Scorns Think-Tank's Breakup Idea
      - Yahoo Accused Of Stalking Internet Users
      - eToys.com Settles Spat With Swiss Artist Group
      - [more articles/news]
       



      copyright 1997-2000 Andover.Net - icons courtesy of tigert@gimp.org - code revision 20000101 - our privacy policy
      ================================================ FILE: ext/tk/sample/tkextlib/tkHTML/ss.rb ================================================ #!/usr/bin/env ruby # # This script implements the "ss" application. "ss" implements # a presentation slide-show based on HTML slides. # require 'tk' require 'tkextlib/tkHTML' file = ARGV[0] class TkHTML_File_Viewer include TkComm # These are images to use with the actual image specified in a # "" markup can't be found. # @@biggray = TkPhotoImage.new(:data=><<'EOD') R0lGODdhPAA+APAAALi4uAAAACwAAAAAPAA+AAACQISPqcvtD6OctNqLs968+w+G4kiW5omm 6sq27gvH8kzX9o3n+s73/g8MCofEovGITCqXzKbzCY1Kp9Sq9YrNFgsAO/// EOD @@smgray = TkPhotoImage.new(:data=><<'EOD') R0lGODdhOAAYAPAAALi4uAAAACwAAAAAOAAYAAACI4SPqcvtD6OctNqLs968+w+G4kiW5omm 6sq27gvH8kzX9m0VADv/ EOD def initialize(file = nil) @root = TkRoot.new(:title=>'HTML File Viewer', :iconname=>'HV') @fswin = nil @html = nil @html_fs = nil @hotkey = {} @applet_arg = TkVarAccess.new_hash('AppletArg') @images = {} @old_imgs = {} @big_imgs = {} @last_dir = Dir.pwd @last_file = '' @key_block = false Tk::HTML_Widget::ClippingWindow.bind('1', proc{|w, ksym| key_press(w, ksym)}, '%W Down') Tk::HTML_Widget::ClippingWindow.bind('3', proc{|w, ksym| key_press(w, ksym)}, '%W Up') Tk::HTML_Widget::ClippingWindow.bind('2', proc{|w, ksym| key_press(w, ksym)}, '%W Down') Tk::HTML_Widget::ClippingWindow.bind('KeyPress', proc{|w, ksym| key_press(w, ksym)}, '%W %K') ############################################ # # Build the half-size view of the page # menu_spec = [ [['File', 0], ['Open', proc{sel_load()}, 0], ['Full Screen', proc{fullscreen()}, 0], ['Refresh', proc{refresh()}, 0], '---', ['Exit', proc{exit}, 1]] ] mbar = @root.add_menubar(menu_spec) @html = Tk::HTML_Widget.new(:width=>512, :height=>384, :padx=>5, :pady=>9, :formcommand=>proc{|*args| form_cmd(*args)}, :imagecommand=>proc{|*args| image_cmd(1, *args) }, :scriptcommand=>proc{|*args| script_cmd(*args) }, :appletcommand=>proc{|*args| applet_cmd(*args) }, :hyperlinkcommand=>proc{|*args| hyper_cmd(*args) }, :fontcommand=>proc{|*args| pick_font(*args) }, :appletcommand=>proc{|*args| run_applet('small', *args) }, :bg=>'white', :tablerelief=>:raised) @html.token_handler('meta', proc{|*args| meta(@html, *args)}) vscr = @html.yscrollbar(TkScrollbar.new) hscr = @html.xscrollbar(TkScrollbar.new) Tk.grid(@html, vscr, :sticky=>:news) Tk.grid(hscr, :sticky=>:ew) @root.grid_columnconfigure(0, :weight=>1) @root.grid_columnconfigure(1, :weight=>0) @root.grid_rowconfigure(0, :weight=>1) @root.grid_rowconfigure(1, :weight=>0) ############################################ @html.clipwin.focus # If an arguent was specified, read it into the HTML widget. # Tk.update if file && file != "" load_file(file) end end # # A font chooser routine. # # html[:fontcommand] = pick_font def pick_font(size, attrs) # puts "FontCmd: #{size} #{attrs}" [ ((attrs =~ /fixed/)? 'courier': 'charter'), (12 * (1.2**(size.to_f - 4.0))).to_i, ((attrs =~ /italic/)? 'italic': 'roman'), ((attrs =~ /bold/)? 'bold': 'normal') ].join(' ') end # This routine is called to pick fonts for the fullscreen view. # def pick_font_fs(size, attrs) baseFontSize = 24 # puts "FontCmd: #{size} #{attrs}" [ ((attrs =~ /fixed/)? 'courier': 'charter'), (baseFontSize * (1.2**(size.to_f - 4.0))).to_i, ((attrs =~ /italic/)? 'italic': 'roman'), ((attrs =~ /bold/)? 'bold': 'normal') ].join(' ') end # # def hyper_cmd(*args) puts "HyperlinkCommand: #{args.inspect}" end # This routine is called to run an applet # def run_applet(size, w, arglist) applet_arg.value = Hash[*simplelist(arglist)] return unless @applet_arg.key?('src') src = @html.remove(@applet_arg['src']) @applet_arg['window'] = w @applet_arg['fontsize'] = size begin Tk.load_tclscript(src) rescue => e puts "Applet error: #{e.message}" end end # # def form_cmd(n, cmd, *args) # p [n, cmd, *args] end # # def move_big_image(b) return unless @big_imgs.key?(b) b.copy(@big_imgs[b]) @big_imgs[b].delete @big_imgs.delete(b) end def image_cmd(hs, *args) fn = args[0] if @old_imgs.key?(fn) return (@images[fn] = @old_imgs.delete(fn)) end begin img = TkPhotoImage.new(:file=>fn) rescue return ((hs)? @@smallgray: @@biggray) end if hs img2 = TkPhotoImage.new img2.copy(img, :subsample=>[2,2]) img.delete img = img2 end if img.width * img.height > 20000 b = TkPhotoImage.new(:width=>img.width, :height=>img.height) @big_imgs[b] = img img = b Tk.after_idle(proc{ move_big_image(b) }) end @images[fn] = img img end # # This routine is called for every !INCLUDE! IF:diagram
      %diagram%
      ENDIF:diagram IF:description
      %description%
      ENDIF:description IF:requires
      Required files

      START:requires HREF:aref:name: END:requires ENDIF:requires
      IF:methods
      Subroutines and Functions

      START:methods HREF:aref:name:, END:methods
      ENDIF:methods IF:attributes
      Arguments

      START:attributes IF:rw ENDIF:rw IFNOT:rw ENDIF:rw END:attributes
       [%rw%] %name% %a_desc%
      ENDIF:attributes IF:classlist
      Modules

      %classlist%
      ENDIF:classlist !INCLUDE! } ############################################################################### FILE_PAGE = <<_FILE_PAGE_
      File
      %short_name%
      Path: %full_path% IF:cvsurl  (CVS) ENDIF:cvsurl
      Modified: %dtm_modified%

      _FILE_PAGE_ ################################################################### CLASS_PAGE = %{
      %classmod%
      %full_name%
      IF:parent ENDIF:parent
      In: START:infiles HREF:full_path_url:full_path: IF:cvsurl  (CVS) ENDIF:cvsurl END:infiles
      Parent: IF:par_url ENDIF:par_url %parent% IF:par_url ENDIF:par_url

      } ################################################################### METHOD_LIST = %{ IF:includes
      Uses

      START:includes HREF:aref:name: END:includes
      ENDIF:includes IF:method_list START:method_list IF:methods
      %type% %category% methods
      START:methods
      %name%%params% IF:codeurl src ENDIF:codeurl
      IF:m_desc
      %m_desc%
      ENDIF:m_desc END:methods ENDIF:methods END:method_list ENDIF:method_list } =begin =end ########################## Source code ########################## SRC_PAGE = %{ %title%
      %code%
      } ########################## Index ################################ FR_INDEX_BODY = %{ !INCLUDE! } FILE_INDEX = %{ START:entries %name%
      END:entries } CLASS_INDEX = FILE_INDEX METHOD_INDEX = FILE_INDEX INDEX = %{ %title% <body bgcolor="#BBBBBB"> Click <a href="html/index.html">here</a> for a non-frames version of this page. </body> } # and a blank page to use as a target BLANK = %{ } def write_extra_pages template = TemplatePage.new(BLANK) File.open("blank.html", "w") { |f| template.write_html_on(f, {}) } end end end ================================================ FILE: lib/rdoc/generators/template/html/html.rb ================================================ # # = CSS2 RDoc HTML template # # This is a template for RDoc that uses XHTML 1.0 Transitional and dictates a # bit more of the appearance of the output to cascading stylesheets than the # default. It was designed for clean inline code display, and uses DHTMl to # toggle the visbility of each method's source with each click on the '[source]' # link. # # == Authors # # * Michael Granger # # Copyright (c) 2002, 2003 The FaerieMUD Consortium. Some rights reserved. # # This work is licensed under the Creative Commons Attribution License. To view # a copy of this license, visit http://creativecommons.org/licenses/by/1.0/ or # send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California # 94305, USA. # module RDoc module Page FONTS = "Verdana,Arial,Helvetica,sans-serif" STYLE = %{ body { font-family: Verdana,Arial,Helvetica,sans-serif; font-size: 90%; margin: 0; margin-left: 40px; padding: 0; background: white; } h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; } h1 { font-size: 150%; } h2,h3,h4 { margin-top: 1em; } a { background: #eef; color: #039; text-decoration: none; } a:hover { background: #039; color: #eef; } /* Override the base stylesheet's Anchor inside a table cell */ td > a { background: transparent; color: #039; text-decoration: none; } /* and inside a section title */ .section-title > a { background: transparent; color: #eee; text-decoration: none; } /* === Structural elements =================================== */ div#index { margin: 0; margin-left: -40px; padding: 0; font-size: 90%; } div#index a { margin-left: 0.7em; } div#index .section-bar { margin-left: 0px; padding-left: 0.7em; background: #ccc; font-size: small; } div#classHeader, div#fileHeader { width: auto; color: white; padding: 0.5em 1.5em 0.5em 1.5em; margin: 0; margin-left: -40px; border-bottom: 3px solid #006; } div#classHeader a, div#fileHeader a { background: inherit; color: white; } div#classHeader td, div#fileHeader td { background: inherit; color: white; } div#fileHeader { background: #057; } div#classHeader { background: #048; } .class-name-in-header { font-size: 180%; font-weight: bold; } div#bodyContent { padding: 0 1.5em 0 1.5em; } div#description { padding: 0.5em 1.5em; background: #efefef; border: 1px dotted #999; } div#description h1,h2,h3,h4,h5,h6 { color: #125;; background: transparent; } div#validator-badges { text-align: center; } div#validator-badges img { border: 0; } div#copyright { color: #333; background: #efefef; font: 0.75em sans-serif; margin-top: 5em; margin-bottom: 0; padding: 0.5em 2em; } /* === Classes =================================== */ table.header-table { color: white; font-size: small; } .type-note { font-size: small; color: #DEDEDE; } .xxsection-bar { background: #eee; color: #333; padding: 3px; } .section-bar { color: #333; border-bottom: 1px solid #999; margin-left: -20px; } .section-title { background: #79a; color: #eee; padding: 3px; margin-top: 2em; margin-left: -30px; border: 1px solid #999; } .top-aligned-row { vertical-align: top } .bottom-aligned-row { vertical-align: bottom } /* --- Context section classes ----------------------- */ .context-row { } .context-item-name { font-family: monospace; font-weight: bold; color: black; } .context-item-value { font-size: small; color: #448; } .context-item-desc { color: #333; padding-left: 2em; } /* --- Method classes -------------------------- */ .method-detail { background: #efefef; padding: 0; margin-top: 0.5em; margin-bottom: 1em; border: 1px dotted #ccc; } .method-heading { color: black; background: #ccc; border-bottom: 1px solid #666; padding: 0.2em 0.5em 0 0.5em; } .method-signature { color: black; background: inherit; } .method-name { font-weight: bold; } .method-args { font-style: italic; } .method-description { padding: 0 0.5em 0 0.5em; } /* --- Source code sections -------------------- */ a.source-toggle { font-size: 90%; } div.method-source-code { background: #262626; color: #ffdead; margin: 1em; padding: 0.5em; border: 1px dashed #999; overflow: hidden; } div.method-source-code pre { color: #ffdead; overflow: hidden; } /* --- Ruby keyword styles --------------------- */ .standalone-code { background: #221111; color: #ffdead; overflow: hidden; } .ruby-constant { color: #7fffd4; background: transparent; } .ruby-keyword { color: #00ffff; background: transparent; } .ruby-ivar { color: #eedd82; background: transparent; } .ruby-operator { color: #00ffee; background: transparent; } .ruby-identifier { color: #ffdead; background: transparent; } .ruby-node { color: #ffa07a; background: transparent; } .ruby-comment { color: #b22222; font-weight: bold; background: transparent; } .ruby-regexp { color: #ffa07a; background: transparent; } .ruby-value { color: #7fffd4; background: transparent; } } ##################################################################### ### H E A D E R T E M P L A T E ##################################################################### XHTML_PREAMBLE = %{ } HEADER = XHTML_PREAMBLE + %{ %title% } ##################################################################### ### C O N T E X T C O N T E N T T E M P L A T E ##################################################################### CONTEXT_CONTENT = %{ } ##################################################################### ### F O O T E R T E M P L A T E ##################################################################### FOOTER = %{ } ##################################################################### ### F I L E P A G E H E A D E R T E M P L A T E ##################################################################### FILE_PAGE = %{

      %short_name%

      Path: %full_path% IF:cvsurl  (CVS) ENDIF:cvsurl
      Last Update: %dtm_modified%
      } ##################################################################### ### C L A S S P A G E H E A D E R T E M P L A T E ##################################################################### CLASS_PAGE = %{
      IF:parent ENDIF:parent
      %classmod% %full_name%
      In: START:infiles IF:full_path_url ENDIF:full_path_url %full_path% IF:full_path_url ENDIF:full_path_url IF:cvsurl  (CVS) ENDIF:cvsurl
      END:infiles
      Parent: IF:par_url ENDIF:par_url %parent% IF:par_url ENDIF:par_url
      } ##################################################################### ### M E T H O D L I S T T E M P L A T E ##################################################################### METHOD_LIST = %{
      IF:diagram
      %diagram%
      ENDIF:diagram IF:description
      %description%
      ENDIF:description IF:requires

      Required files

      START:requires HREF:aref:name:   END:requires
      ENDIF:requires IF:toc

      Contents

      ENDIF:toc
      IF:methods

      Methods

      START:methods HREF:aref:name:   END:methods
      ENDIF:methods
      IF:includes

      Included Modules

      START:includes HREF:aref:name: END:includes
      ENDIF:includes START:sections
      IF:sectitle

      %sectitle%

      IF:seccomment
      %seccomment%
      ENDIF:seccomment ENDIF:sectitle IF:classlist

      Classes and Modules

      %classlist%
      ENDIF:classlist IF:constants

      Constants

      START:constants IF:desc ENDIF:desc END:constants
      %name% = %value%  %desc%
      ENDIF:constants IF:aliases

      External Aliases

      START:aliases IF:desc ENDIF:desc END:aliases
      %old_name% -> %new_name%
        %desc%
      ENDIF:aliases IF:attributes

      Attributes

      START:attributes IF:rw ENDIF:rw IFNOT:rw ENDIF:rw END:attributes
      %name% [%rw%]   %a_desc%
      ENDIF:attributes IF:method_list
      START:method_list IF:methods

      %type% %category% methods

      START:methods
      IF:m_desc %m_desc% ENDIF:m_desc IF:sourcecode

      [Source]

      %sourcecode%
      
      ENDIF:sourcecode
      END:methods ENDIF:methods END:method_list
      ENDIF:method_list END:sections } ##################################################################### ### B O D Y T E M P L A T E ##################################################################### BODY = HEADER + %{ !INCLUDE!
      } + METHOD_LIST + %{
      } + FOOTER ##################################################################### ### S O U R C E C O D E T E M P L A T E ##################################################################### SRC_PAGE = XHTML_PREAMBLE + %{ %title%
      %code%
      } ##################################################################### ### I N D E X F I L E T E M P L A T E S ##################################################################### FR_INDEX_BODY = %{ !INCLUDE! } FILE_INDEX = XHTML_PREAMBLE + %{ %list_title%

      %list_title%

      START:entries %name%
      END:entries
      } CLASS_INDEX = FILE_INDEX METHOD_INDEX = FILE_INDEX INDEX = %{ %title% } end # module Page end # class RDoc require 'rdoc/generators/template/html/one_page_html' ================================================ FILE: lib/rdoc/generators/template/html/kilmer.rb ================================================ module RDoc module Page FONTS = "Verdana, Arial, Helvetica, sans-serif" STYLE = %{ body,td,p { font-family: %fonts%; color: #000040; } .attr-rw { font-size: xx-small; color: #444488 } .title-row { background-color: #CCCCFF; color: #000010; } .big-title-font { color: black; font-weight: bold; font-family: %fonts%; font-size: large; height: 60px; padding: 10px 3px 10px 3px; } .small-title-font { color: black; font-family: %fonts%; font-size:10; } .aqua { color: black } .method-name, .attr-name { font-family: font-family: %fonts%; font-weight: bold; font-size: small; margin-left: 20px; color: #000033; } .tablesubtitle, .tablesubsubtitle { width: 100%; margin-top: 1ex; margin-bottom: .5ex; padding: 5px 0px 5px 3px; font-size: large; color: black; background-color: #CCCCFF; border: thin; } .name-list { margin-left: 5px; margin-bottom: 2ex; line-height: 105%; } .description { margin-left: 5px; margin-bottom: 2ex; line-height: 105%; font-size: small; } .methodtitle { font-size: small; font-weight: bold; text-decoration: none; color: #000033; background-color: white; } .srclink { font-size: small; font-weight: bold; text-decoration: none; color: #0000DD; background-color: white; } .paramsig { font-size: small; } .srcbut { float: right } } ############################################################################ BODY = %{ %title% !INCLUDE! IF:diagram
      %diagram%
      ENDIF:diagram IF:description
      %description%
      ENDIF:description IF:requires
      Required files

      START:requires HREF:aref:name: END:requires ENDIF:requires
      IF:methods
      Methods

      START:methods HREF:aref:name:, END:methods
      ENDIF:methods START:sections
      IF:sectitle

      %sectitle%

      IF:seccomment
      %seccomment%
      ENDIF:seccomment ENDIF:sectitle IF:attributes
      Attributes

      START:attributes IF:rw ENDIF:rw IFNOT:rw ENDIF:rw END:attributes
       [%rw%] %name% %a_desc%
      ENDIF:attributes IF:classlist
      Classes and Modules

      %classlist%
      ENDIF:classlist !INCLUDE! END:sections } ############################################################################### FILE_PAGE = <<_FILE_PAGE_
      File
      %short_name%
      Path: %full_path% IF:cvsurl  (CVS) ENDIF:cvsurl
      Modified: %dtm_modified%

      _FILE_PAGE_ ################################################################### CLASS_PAGE = %{
      %classmod%
      %full_name%
      IF:parent ENDIF:parent
      In: START:infiles HREF:full_path_url:full_path: IF:cvsurl  (CVS) ENDIF:cvsurl END:infiles
      Parent: IF:par_url ENDIF:par_url %parent% IF:par_url ENDIF:par_url

      } ################################################################### METHOD_LIST = %{ IF:includes
      Included modules

      START:includes HREF:aref:name: END:includes
      ENDIF:includes IF:method_list START:method_list IF:methods
      %type% %category% methods
      START:methods
      IF:callseq %callseq% ENDIF:callseq IFNOT:callseq %name%%params% ENDIF:callseq IF:codeurl src ENDIF:codeurl
      IF:m_desc
      %m_desc%
      ENDIF:m_desc IF:aka
      This method is also aliased as START:aka %name% END:aka
      ENDIF:aka IF:sourcecode
      %sourcecode%
      
      ENDIF:sourcecode END:methods ENDIF:methods END:method_list ENDIF:method_list } =begin =end ########################## Source code ########################## SRC_PAGE = %{ %title%
      %code%
      } ########################## Index ################################ FR_INDEX_BODY = %{ !INCLUDE! } FILE_INDEX = %{ START:entries %name%
      END:entries } CLASS_INDEX = FILE_INDEX METHOD_INDEX = FILE_INDEX INDEX = %{ %title% IF:inline_source ENDIF:inline_source IFNOT:inline_source ENDIF:inline_source <body bgcolor="white"> Click <a href="html/index.html">here</a> for a non-frames version of this page. </body> } # and a blank page to use as a target BLANK = %{ } def write_extra_pages template = TemplatePage.new(BLANK) File.open("blank.html", "w") { |f| template.write_html_on(f, {}) } end end end ================================================ FILE: lib/rdoc/generators/template/html/old_html.rb ================================================ module RDoc # This is how you define the HTML that RDoc generates. Simply create # a file in rdoc/generators/html_templates that creates the # module RDoc::Page and populate it as described below. Then invoke # rdoc using the --template option, and # your template will be used. # # The constants defining pages use a simple templating system: # # * The templating system is passed a hash. Keys in the hash correspond # to tags on this page. The tag %abc% is looked up in the hash, # and is replaced by the corresponding hash value. # # * Some tags are optional. You can detect this using IF/ENDIF # # IF: title # The value of title is %title% # ENDIF: title # # * Some entries in the hash have values that are arrays, where each # entry in the array is itself a hash. These are used to generate # lists using the START: construct. For example, given a hash # containing # # { 'people' => [ { 'name' => 'Fred', 'age' => '12' }, # { 'name' => 'Mary', 'age' => '21' } ] # # You could generate a simple table using # # # START:people # # END:people #
      %name%%age%
      # # These lists can be nested to an arbitrary depth # # * the construct HREF:url:name: generates %name% # if +url+ is defined in the hash, or %name% otherwise. # # # Your file must contain the following constants # # [*FONTS*] a list of fonts to be used # [*STYLE*] a CSS section (without the START:entries %name%
      END:entries } CLASS_INDEX = FILE_INDEX METHOD_INDEX = FILE_INDEX INDEX = %{ %title% <body bgcolor="white"> Sorry, RDoc currently only generates HTML using frames. </body> } ###################################################################### # # The following is used for the -1 option # CONTENTS_XML = %{ IF:description %description% ENDIF:description IF:requires

      Requires:

        START:requires IF:aref
      • %name%
      • ENDIF:aref IFNOT:aref
      • %name%
      • ENDIF:aref END:requires
      ENDIF:requires IF:attributes

      Attributes

      START:attributes END:attributes
      %name%%rw%%a_desc%
      ENDIF:attributes IF:includes

      Includes

        START:includes IF:aref
      • %name%
      • ENDIF:aref IFNOT:aref
      • %name%
      • ENDIF:aref END:includes
      ENDIF:includes IF:method_list

      Methods

      START:method_list IF:methods START:methods

      %type% %category% method: %name%%params%

      IF:m_desc %m_desc% ENDIF:m_desc IF:sourcecode
      %sourcecode%
      
      ENDIF:sourcecode END:methods ENDIF:methods END:method_list ENDIF:method_list } end end require 'rdoc/generators/template/html/one_page_html' ================================================ FILE: lib/rdoc/generators/template/html/one_page_html.rb ================================================ module RDoc module Page ###################################################################### # # The following is used for the -1 option # CONTENTS_XML = %{ IF:description %description% ENDIF:description IF:requires

      Requires:

        START:requires IF:aref
      • %name%
      • ENDIF:aref IFNOT:aref
      • %name%
      • ENDIF:aref END:requires
      ENDIF:requires IF:attributes

      Attributes

      START:attributes END:attributes
      %name%%rw%%a_desc%
      ENDIF:attributes IF:includes

      Includes

        START:includes IF:aref
      • %name%
      • ENDIF:aref IFNOT:aref
      • %name%
      • ENDIF:aref END:includes
      ENDIF:includes IF:method_list

      Methods

      START:method_list IF:methods START:methods

      %type% %category% method: IF:callseq %callseq% ENDIF:callseq IFNOT:callseq %name%%params%

      ENDIF:callseq IF:m_desc %m_desc% ENDIF:m_desc IF:sourcecode
      %sourcecode%
      
      ENDIF:sourcecode END:methods ENDIF:methods END:method_list ENDIF:method_list } ######################################################################## ONE_PAGE = %{ %title% START:files

      File: %short_name%

      Path:%full_path%
      Modified:%dtm_modified%
      } + CONTENTS_XML + %{ END:files IF:classes

      Classes

      START:classes IF:parent

      %classmod% %full_name% < HREF:par_url:parent:

      ENDIF:parent IFNOT:parent

      %classmod% %full_name%

      ENDIF:parent IF:infiles (in files START:infiles HREF:full_path_url:full_path: END:infiles ) ENDIF:infiles } + CONTENTS_XML + %{ END:classes ENDIF:classes } end end ================================================ FILE: lib/rdoc/generators/template/xml/rdf.rb ================================================ module RDoc module Page CONTENTS_RDF = %{ IF:description %description% ENDIF:description IF:requires START:requires END:requires ENDIF:requires IF:attributes START:attributes IF:rw %rw% ENDIF:rw %a_desc% END:attributes ENDIF:attributes IF:includes START:includes END:includes ENDIF:includes IF:method_list START:method_list IF:methods START:methods %params% IF:m_desc %m_desc% ENDIF:m_desc IF:sourcecode %sourcecode% ENDIF:sourcecode END:methods ENDIF:methods END:method_list ENDIF:method_list } ######################################################################## ONE_PAGE = %{ START:files %full_path% %dtm_modified% } + CONTENTS_RDF + %{ END:files START:classes <%classmod% rd:name="%full_name%" rd:id="%full_name%"> IF:infiles START:infiles END:infiles ENDIF:infiles IF:parent HREF:par_url:parent: ENDIF:parent } + CONTENTS_RDF + %{ END:classes } end end ================================================ FILE: lib/rdoc/generators/template/xml/xml.rb ================================================ module RDoc module Page CONTENTS_XML = %{ IF:description %description% ENDIF:description IF:requires START:requires END:requires ENDIF:requires IF:attributes START:attributes IF:rw %rw% ENDIF:rw %a_desc% END:attributes ENDIF:attributes IF:includes START:includes END:includes ENDIF:includes IF:method_list START:method_list IF:methods START:methods %params% IF:m_desc %m_desc% ENDIF:m_desc IF:sourcecode %sourcecode% ENDIF:sourcecode END:methods ENDIF:methods END:method_list ENDIF:method_list } ######################################################################## ONE_PAGE = %{ START:files %full_path% %dtm_modified% } + CONTENTS_XML + %{ END:files START:classes <%classmod% name="%full_name%" id="%full_name%"> IF:infiles START:infiles HREF:full_path_url:full_path: END:infiles ENDIF:infiles IF:parent HREF:par_url:parent: ENDIF:parent } + CONTENTS_XML + %{ END:classes } end end ================================================ FILE: lib/rdoc/generators/xml_generator.rb ================================================ require 'ftools' require 'rdoc/options' require 'rdoc/markup/simple_markup' require 'rdoc/markup/simple_markup/to_html' require 'rdoc/generators/html_generator' module Generators # Generate XML output as one big file class XMLGenerator < HTMLGenerator # Standard generator factory def XMLGenerator.for(options) XMLGenerator.new(options) end def initialize(*args) super end ## # Build the initial indices and output objects # based on an array of TopLevel objects containing # the extracted information. def generate(info) @info = info @files = [] @classes = [] @hyperlinks = {} build_indices generate_xml end ## # Generate: # # * a list of HtmlFile objects for each TopLevel object. # * a list of HtmlClass objects for each first level # class or module in the TopLevel objects # * a complete list of all hyperlinkable terms (file, # class, module, and method names) def build_indices @info.each do |toplevel| @files << HtmlFile.new(toplevel, @options, FILE_DIR) end RDoc::TopLevel.all_classes_and_modules.each do |cls| build_class_list(cls, @files[0], CLASS_DIR) end end def build_class_list(from, html_file, class_dir) @classes << HtmlClass.new(from, html_file, class_dir, @options) from.each_classmodule do |mod| build_class_list(mod, html_file, class_dir) end end ## # Generate all the HTML. For the one-file case, we generate # all the information in to one big hash # def generate_xml values = { 'charset' => @options.charset, 'files' => gen_into(@files), 'classes' => gen_into(@classes) } # this method is defined in the template file write_extra_pages if defined? write_extra_pages template = TemplatePage.new(RDoc::Page::ONE_PAGE) if @options.op_name opfile = File.open(@options.op_name, "w") else opfile = $stdout end template.write_html_on(opfile, values) end def gen_into(list) res = [] list.each do |item| res << item.value_hash end res end def gen_file_index gen_an_index(@files, 'Files') end def gen_class_index gen_an_index(@classes, 'Classes') end def gen_method_index gen_an_index(HtmlMethod.all_methods, 'Methods') end def gen_an_index(collection, title) res = [] collection.sort.each do |f| if f.document_self res << { "href" => f.path, "name" => f.index_name } end end return { "entries" => res, 'list_title' => title, 'index_url' => main_url, } end end end ================================================ FILE: lib/rdoc/markup/.document ================================================ simple_markup simple_markup.rb ================================================ FILE: lib/rdoc/markup/sample/rdoc2latex.rb ================================================ #!/usr/local/bin/ruby # Illustration of a script to convert an RDoc-style file to a LaTeX # document require 'rdoc/markup/simple_markup' require 'rdoc/markup/simple_markup/to_latex' p = SM::SimpleMarkup.new h = SM::ToLaTeX.new #puts "\\documentclass{report}" #puts "\\usepackage{tabularx}" #puts "\\usepackage{parskip}" #puts "\\begin{document}" puts p.convert(ARGF.read, h) #puts "\\end{document}" ================================================ FILE: lib/rdoc/markup/sample/sample.rb ================================================ # This program illustrates the basic use of the SimpleMarkup # class. It extracts the first comment block from the # simple_markup.rb file and converts it into HTML on # standard output. Run it using # # % ruby sample.rb # # You should be in the sample/ directory when you do this, # as it hardwires the path to the files it needs to require. # This isn't necessary in the code you write once you've # installed the package. # # For a better way of formatting code comment blocks (and more) # see the rdoc package. # $:.unshift "../../.." require 'rdoc/markup/simple_markup' require 'rdoc/markup/simple_markup/to_html' # Extract the comment block from the source file input_string = "" File.foreach("../simple_markup.rb") do |line| break unless line.gsub!(/^\# ?/, '') input_string << line end # Create a markup object markup = SM::SimpleMarkup.new # Attach it to an HTML formatter h = SM::ToHtml.new # And convert out comment block to html. Wrap it a body # tag pair to let browsers view it puts "" puts markup.convert(input_string, h) puts "" ================================================ FILE: lib/rdoc/markup/simple_markup/fragments.rb ================================================ require 'rdoc/markup/simple_markup/lines.rb' #require 'rdoc/markup/simple_markup/to_flow.rb' module SM ## # A Fragment is a chunk of text, subclassed as a paragraph, a list # entry, or verbatim text class Fragment attr_reader :level, :param, :txt attr_accessor :type def initialize(level, param, type, txt) @level = level @param = param @type = type @txt = "" add_text(txt) if txt end def add_text(txt) @txt << " " if @txt.length > 0 @txt << txt.tr_s("\n ", " ").strip end def to_s "L#@level: #{self.class.name.split('::')[-1]}\n#@txt" end ###### # This is a simple factory system that lets us associate fragement # types (a string) with a subclass of fragment TYPE_MAP = {} def Fragment.type_name(name) TYPE_MAP[name] = self end def Fragment.for(line) klass = TYPE_MAP[line.type] || raise("Unknown line type: '#{line.type.inspect}:' '#{line.text}'") return klass.new(line.level, line.param, line.flag, line.text) end end ## # A paragraph is a fragment which gets wrapped to fit. We remove all # newlines when we're created, and have them put back on output class Paragraph < Fragment type_name Line::PARAGRAPH end class BlankLine < Paragraph type_name Line::BLANK end class Heading < Paragraph type_name Line::HEADING def head_level @param.to_i end end ## # A List is a fragment with some kind of label # class ListBase < Paragraph # List types BULLET = :BULLET NUMBER = :NUMBER UPPERALPHA = :UPPERALPHA LOWERALPHA = :LOWERALPHA LABELED = :LABELED NOTE = :NOTE end class ListItem < ListBase type_name Line::LIST # def label # am = AttributeManager.new(@param) # am.flow # end end class ListStart < ListBase def initialize(level, param, type) super(level, param, type, nil) end end class ListEnd < ListBase def initialize(level, type) super(level, "", type, nil) end end ## # Verbatim code contains lines that don't get wrapped. class Verbatim < Fragment type_name Line::VERBATIM def add_text(txt) @txt << txt.chomp << "\n" end end ## # A horizontal rule class Rule < Fragment type_name Line::RULE end # Collect groups of lines together. Each group # will end up containing a flow of text class LineCollection def initialize @fragments = [] end def add(fragment) @fragments << fragment end def each(&b) @fragments.each(&b) end # For testing def to_a @fragments.map {|fragment| fragment.to_s} end # Factory for different fragment types def fragment_for(*args) Fragment.for(*args) end # tidy up at the end def normalize change_verbatim_blank_lines add_list_start_and_ends add_list_breaks tidy_blank_lines end def to_s @fragments.join("\n----\n") end def accept(am, visitor) visitor.start_accepting @fragments.each do |fragment| case fragment when Verbatim visitor.accept_verbatim(am, fragment) when Rule visitor.accept_rule(am, fragment) when ListStart visitor.accept_list_start(am, fragment) when ListEnd visitor.accept_list_end(am, fragment) when ListItem visitor.accept_list_item(am, fragment) when BlankLine visitor.accept_blank_line(am, fragment) when Heading visitor.accept_heading(am, fragment) when Paragraph visitor.accept_paragraph(am, fragment) end end visitor.end_accepting end ####### private ####### # If you have: # # normal paragraph text. # # this is code # # and more code # # You'll end up with the fragments Paragraph, BlankLine, # Verbatim, BlankLine, Verbatim, BlankLine, etc # # The BlankLine in the middle of the verbatim chunk needs to # be changed to a real verbatim newline, and the two # verbatim blocks merged # # def change_verbatim_blank_lines frag_block = nil blank_count = 0 @fragments.each_with_index do |frag, i| if frag_block.nil? frag_block = frag if Verbatim === frag else case frag when Verbatim blank_count.times { frag_block.add_text("\n") } blank_count = 0 frag_block.add_text(frag.txt) @fragments[i] = nil # remove out current fragment when BlankLine if frag_block blank_count += 1 @fragments[i] = nil end else frag_block = nil blank_count = 0 end end end @fragments.compact! end # List nesting is implicit given the level of # Make it explicit, just to make life a tad # easier for the output processors def add_list_start_and_ends level = 0 res = [] type_stack = [] @fragments.each do |fragment| # $stderr.puts "#{level} : #{fragment.class.name} : #{fragment.level}" new_level = fragment.level while (level < new_level) level += 1 type = fragment.type res << ListStart.new(level, fragment.param, type) if type type_stack.push type # $stderr.puts "Start: #{level}" end while level > new_level type = type_stack.pop res << ListEnd.new(level, type) if type level -= 1 # $stderr.puts "End: #{level}, #{type}" end res << fragment level = fragment.level end level.downto(1) do |i| type = type_stack.pop res << ListEnd.new(i, type) if type end @fragments = res end # now insert start/ends between list entries at the # same level that have different element types def add_list_breaks res = @fragments @fragments = [] list_stack = [] res.each do |fragment| case fragment when ListStart list_stack.push fragment when ListEnd start = list_stack.pop fragment.type = start.type when ListItem l = list_stack.last if fragment.type != l.type @fragments << ListEnd.new(l.level, l.type) start = ListStart.new(l.level, fragment.param, fragment.type) @fragments << start list_stack.pop list_stack.push start end else ; end @fragments << fragment end end # Finally tidy up the blank lines: # * change Blank/ListEnd into ListEnd/Blank # * remove blank lines at the front def tidy_blank_lines (@fragments.size - 1).times do |i| if @fragments[i].kind_of?(BlankLine) and @fragments[i+1].kind_of?(ListEnd) @fragments[i], @fragments[i+1] = @fragments[i+1], @fragments[i] end end # remove leading blanks @fragments.each_with_index do |f, i| break unless f.kind_of? BlankLine @fragments[i] = nil end @fragments.compact! end end end ================================================ FILE: lib/rdoc/markup/simple_markup/inline.rb ================================================ module SM # We manage a set of attributes. Each attribute has a symbol name # and a bit value class Attribute SPECIAL = 1 @@name_to_bitmap = { :_SPECIAL_ => SPECIAL } @@next_bitmap = 2 def Attribute.bitmap_for(name) bitmap = @@name_to_bitmap[name] if !bitmap bitmap = @@next_bitmap @@next_bitmap <<= 1 @@name_to_bitmap[name] = bitmap end bitmap end def Attribute.as_string(bitmap) return "none" if bitmap.zero? res = [] @@name_to_bitmap.each do |name, bit| res << name if (bitmap & bit) != 0 end res.join(",") end def Attribute.each_name_of(bitmap) @@name_to_bitmap.each do |name, bit| next if bit == SPECIAL yield name.to_s if (bitmap & bit) != 0 end end end # An AttrChanger records a change in attributes. It contains # a bitmap of the attributes to turn on, and a bitmap of those to # turn off AttrChanger = Struct.new(:turn_on, :turn_off) class AttrChanger def to_s "Attr: +#{Attribute.as_string(@turn_on)}/-#{Attribute.as_string(@turn_on)}" end end # An array of attributes which parallels the characters in a string class AttrSpan def initialize(length) @attrs = Array.new(length, 0) end def set_attrs(start, length, bits) for i in start ... (start+length) @attrs[i] |= bits end end def [](n) @attrs[n] end end ## # Hold details of a special sequence class Special attr_reader :type attr_accessor :text def initialize(type, text) @type, @text = type, text end def ==(o) self.text == o.text && self.type == o.type end def to_s "Special: type=#{type}, text=#{text.dump}" end end class AttributeManager NULL = "\000".freeze ## # We work by substituting non-printing characters in to the # text. For now I'm assuming that I can substitute # a character in the range 0..8 for a 7 bit character # without damaging the encoded string, but this might # be optimistic # A_PROTECT = 004 PROTECT_ATTR = A_PROTECT.chr # This maps delimiters that occur around words (such as # *bold* or +tt+) where the start and end delimiters # and the same. This lets us optimize the regexp MATCHING_WORD_PAIRS = {} # And this is used when the delimiters aren't the same. In this # case the hash maps a pattern to the attribute character WORD_PAIR_MAP = {} # This maps HTML tags to the corresponding attribute char HTML_TAGS = {} # And this maps _special_ sequences to a name. A special sequence # is something like a WikiWord SPECIAL = {} # Return an attribute object with the given turn_on # and turn_off bits set def attribute(turn_on, turn_off) AttrChanger.new(turn_on, turn_off) end def change_attribute(current, new) diff = current ^ new attribute(new & diff, current & diff) end def changed_attribute_by_name(current_set, new_set) current = new = 0 current_set.each {|name| current |= Attribute.bitmap_for(name) } new_set.each {|name| new |= Attribute.bitmap_for(name) } change_attribute(current, new) end def copy_string(start_pos, end_pos) res = @str[start_pos...end_pos] res.gsub!(/\000/, '') res end # Map attributes like textto the sequence \001\002\001\003, # where is a per-attribute specific character def convert_attrs(str, attrs) # first do matching ones tags = MATCHING_WORD_PAIRS.keys.join("") re = "(^|\\W)([#{tags}])([A-Za-z_]+?)\\2(\\W|\$)" # re = "(^|\\W)([#{tags}])(\\S+?)\\2(\\W|\$)" 1 while str.gsub!(Regexp.new(re)) { attr = MATCHING_WORD_PAIRS[$2]; attrs.set_attrs($`.length + $1.length + $2.length, $3.length, attr) $1 + NULL*$2.length + $3 + NULL*$2.length + $4 } # then non-matching unless WORD_PAIR_MAP.empty? WORD_PAIR_MAP.each do |regexp, attr| str.gsub!(regexp) { attrs.set_attrs($`.length + $1.length, $2.length, attr) NULL*$1.length + $2 + NULL*$3.length } end end end def convert_html(str, attrs) tags = HTML_TAGS.keys.join("|") re = "<(#{tags})>(.*?)" 1 while str.gsub!(Regexp.new(re, Regexp::IGNORECASE)) { attr = HTML_TAGS[$1.downcase] html_length = $1.length + 2 seq = NULL * html_length attrs.set_attrs($`.length + html_length, $2.length, attr) seq + $2 + seq + NULL } end def convert_specials(str, attrs) unless SPECIAL.empty? SPECIAL.each do |regexp, attr| str.scan(regexp) do attrs.set_attrs($`.length, $&.length, attr | Attribute::SPECIAL) end end end end # A \ in front of a character that would normally be # processed turns off processing. We do this by turning # \< into <#{PROTECT} PROTECTABLE = [ "<" << "\\" ] #" def mask_protected_sequences protect_pattern = Regexp.new("\\\\([#{Regexp.escape(PROTECTABLE.join(''))}])") @str.gsub!(protect_pattern, "\\1#{PROTECT_ATTR}") end def unmask_protected_sequences @str.gsub!(/(.)#{PROTECT_ATTR}/, "\\1\000") end def initialize add_word_pair("*", "*", :BOLD) add_word_pair("_", "_", :EM) add_word_pair("+", "+", :TT) add_html("em", :EM) add_html("i", :EM) add_html("b", :BOLD) add_html("tt", :TT) add_html("code", :TT) add_special(//, :COMMENT) end def add_word_pair(start, stop, name) raise "Word flags may not start '<'" if start[0] == ?< bitmap = Attribute.bitmap_for(name) if start == stop MATCHING_WORD_PAIRS[start] = bitmap else pattern = Regexp.new("(" + Regexp.escape(start) + ")" + # "([A-Za-z]+)" + "(\\S+)" + "(" + Regexp.escape(stop) +")") WORD_PAIR_MAP[pattern] = bitmap end PROTECTABLE << start[0,1] PROTECTABLE.uniq! end def add_html(tag, name) HTML_TAGS[tag.downcase] = Attribute.bitmap_for(name) end def add_special(pattern, name) SPECIAL[pattern] = Attribute.bitmap_for(name) end def flow(str) @str = str puts("Before flow, str='#{@str.dump}'") if $DEBUG mask_protected_sequences @attrs = AttrSpan.new(@str.length) puts("After protecting, str='#{@str.dump}'") if $DEBUG convert_attrs(@str, @attrs) convert_html(@str, @attrs) convert_specials(str, @attrs) unmask_protected_sequences puts("After flow, str='#{@str.dump}'") if $DEBUG return split_into_flow end def display_attributes puts puts @str.tr(NULL, "!") bit = 1 16.times do |bno| line = "" @str.length.times do |i| if (@attrs[i] & bit) == 0 line << " " else if bno.zero? line << "S" else line << ("%d" % (bno+1)) end end end puts(line) unless line =~ /^ *$/ bit <<= 1 end end def split_into_flow display_attributes if $DEBUG res = [] current_attr = 0 str = "" str_len = @str.length # skip leading invisible text i = 0 i += 1 while i < str_len and @str[i].zero? start_pos = i # then scan the string, chunking it on attribute changes while i < str_len new_attr = @attrs[i] if new_attr != current_attr if i > start_pos res << copy_string(start_pos, i) start_pos = i end res << change_attribute(current_attr, new_attr) current_attr = new_attr if (current_attr & Attribute::SPECIAL) != 0 i += 1 while i < str_len and (@attrs[i] & Attribute::SPECIAL) != 0 res << Special.new(current_attr, copy_string(start_pos, i)) start_pos = i next end end # move on, skipping any invisible characters begin i += 1 end while i < str_len and @str[i].zero? end # tidy up trailing text if start_pos < str_len res << copy_string(start_pos, str_len) end # and reset to all attributes off res << change_attribute(current_attr, 0) if current_attr != 0 return res end end end ================================================ FILE: lib/rdoc/markup/simple_markup/lines.rb ================================================ ########################################################################## # # We store the lines we're working on as objects of class Line. # These contain the text of the line, along with a flag indicating the # line type, and an indentation level module SM class Line INFINITY = 9999 BLANK = :BLANK HEADING = :HEADING LIST = :LIST RULE = :RULE PARAGRAPH = :PARAGRAPH VERBATIM = :VERBATIM # line type attr_accessor :type # The indentation nesting level attr_accessor :level # The contents attr_accessor :text # A prefix or parameter. For LIST lines, this is # the text that introduced the list item (the label) attr_accessor :param # A flag. For list lines, this is the type of the list attr_accessor :flag # the number of leading spaces attr_accessor :leading_spaces # true if this line has been deleted from the list of lines attr_accessor :deleted def initialize(text) @text = text.dup @deleted = false # expand tabs 1 while @text.gsub!(/\t+/) { ' ' * (8*$&.length - $`.length % 8)} && $~ #` # Strip trailing whitespace @text.sub!(/\s+$/, '') # and look for leading whitespace if @text.length > 0 @text =~ /^(\s*)/ @leading_spaces = $1.length else @leading_spaces = INFINITY end end # Return true if this line is blank def isBlank? @text.length.zero? end # stamp a line with a type, a level, a prefix, and a flag def stamp(type, level, param="", flag=nil) @type, @level, @param, @flag = type, level, param, flag end ## # Strip off the leading margin # def strip_leading(size) if @text.size > size @text[0,size] = "" else @text = "" end end def to_s "#@type#@level: #@text" end end ############################################################################### # # A container for all the lines # class Lines include Enumerable attr_reader :lines # for debugging def initialize(lines) @lines = lines rewind end def empty? @lines.size.zero? end def each @lines.each do |line| yield line unless line.deleted end end # def [](index) # @lines[index] # end def rewind @nextline = 0 end def next begin res = @lines[@nextline] @nextline += 1 if @nextline < @lines.size end while res and res.deleted and @nextline < @lines.size res end def unget @nextline -= 1 end def delete(a_line) a_line.deleted = true end def normalize margin = @lines.collect{|l| l.leading_spaces}.min margin = 0 if margin == Line::INFINITY @lines.each {|line| line.strip_leading(margin) } if margin > 0 end def as_text @lines.map {|l| l.text}.join("\n") end def line_types @lines.map {|l| l.type } end end end ================================================ FILE: lib/rdoc/markup/simple_markup/preprocess.rb ================================================ module SM ## # Handle common directives that can occur in a block of text: # # : include : filename # class PreProcess def initialize(input_file_name, include_path) @input_file_name = input_file_name @include_path = include_path end # Look for common options in a chunk of text. Options that # we don't handle are passed back to our caller # as |directive, param| def handle(text) text.gsub!(/^([ \t#]*):(\w+):\s*(.+)?\n/) do prefix = $1 directive = $2.downcase param = $3 case directive when "include" filename = param.split[0] include_file(filename, prefix) else yield(directive, param) end end end ####### private ####### # Include a file, indenting it correctly def include_file(name, indent) if (full_name = find_include_file(name)) content = File.open(full_name) {|f| f.read} # strip leading '#'s, but only if all lines start with them if content =~ /^[^#]/ content.gsub(/^/, indent) else content.gsub(/^#?/, indent) end else $stderr.puts "Couldn't find file to include: '#{name}'" '' end end # Look for the given file in the directory containing the current # file, and then in each of the directories specified in the # RDOC_INCLUDE path def find_include_file(name) to_search = [ File.dirname(@input_file_name) ].concat @include_path to_search.each do |dir| full_name = File.join(dir, name) stat = File.stat(full_name) rescue next return full_name if stat.readable? end nil end end end ================================================ FILE: lib/rdoc/markup/simple_markup/to_flow.rb ================================================ require 'rdoc/markup/simple_markup/fragments' require 'rdoc/markup/simple_markup/inline' require 'cgi' module SM module Flow P = Struct.new(:body) VERB = Struct.new(:body) RULE = Struct.new(:width) class LIST attr_reader :type, :contents def initialize(type) @type = type @contents = [] end def <<(stuff) @contents << stuff end end LI = Struct.new(:label, :body) H = Struct.new(:level, :text) end class ToFlow LIST_TYPE_TO_HTML = { SM::ListBase::BULLET => [ "
        ", "
      " ], SM::ListBase::NUMBER => [ "
        ", "
      " ], SM::ListBase::UPPERALPHA => [ "
        ", "
      " ], SM::ListBase::LOWERALPHA => [ "
        ", "
      " ], SM::ListBase::LABELED => [ "
      ", "
      " ], SM::ListBase::NOTE => [ "", "
      " ], } InlineTag = Struct.new(:bit, :on, :off) def initialize init_tags end ## # Set up the standard mapping of attributes to HTML tags # def init_tags @attr_tags = [ InlineTag.new(SM::Attribute.bitmap_for(:BOLD), "", ""), InlineTag.new(SM::Attribute.bitmap_for(:TT), "", ""), InlineTag.new(SM::Attribute.bitmap_for(:EM), "", ""), ] end ## # Add a new set of HTML tags for an attribute. We allow # separate start and end tags for flexibility # def add_tag(name, start, stop) @attr_tags << InlineTag.new(SM::Attribute.bitmap_for(name), start, stop) end ## # Given an HTML tag, decorate it with class information # and the like if required. This is a no-op in the base # class, but is overridden in HTML output classes that # implement style sheets def annotate(tag) tag end ## # Here's the client side of the visitor pattern def start_accepting @res = [] @list_stack = [] end def end_accepting @res end def accept_paragraph(am, fragment) @res << Flow::P.new((convert_flow(am.flow(fragment.txt)))) end def accept_verbatim(am, fragment) @res << Flow::VERB.new((convert_flow(am.flow(fragment.txt)))) end def accept_rule(am, fragment) size = fragment.param size = 10 if size > 10 @res << Flow::RULE.new(size) end def accept_list_start(am, fragment) @list_stack.push(@res) list = Flow::LIST.new(fragment.type) @res << list @res = list end def accept_list_end(am, fragment) @res = @list_stack.pop end def accept_list_item(am, fragment) @res << Flow::LI.new(fragment.param, convert_flow(am.flow(fragment.txt))) end def accept_blank_line(am, fragment) # @res << annotate("

      ") << "\n" end def accept_heading(am, fragment) @res << Flow::H.new(fragment.head_level, convert_flow(am.flow(fragment.txt))) end ####################################################################### private ####################################################################### def on_tags(res, item) attr_mask = item.turn_on return if attr_mask.zero? @attr_tags.each do |tag| if attr_mask & tag.bit != 0 res << annotate(tag.on) end end end def off_tags(res, item) attr_mask = item.turn_off return if attr_mask.zero? @attr_tags.reverse_each do |tag| if attr_mask & tag.bit != 0 res << annotate(tag.off) end end end def convert_flow(flow) res = "" flow.each do |item| case item when String res << convert_string(item) when AttrChanger off_tags(res, item) on_tags(res, item) when Special res << convert_special(item) else raise "Unknown flow element: #{item.inspect}" end end res end # some of these patterns are taken from SmartyPants... def convert_string(item) CGI.escapeHTML(item) end def convert_special(special) handled = false Attribute.each_name_of(special.type) do |name| method_name = "handle_special_#{name}" if self.respond_to? method_name special.text = send(method_name, special) handled = true end end raise "Unhandled special: #{special}" unless handled special.text end end end ================================================ FILE: lib/rdoc/markup/simple_markup/to_html.rb ================================================ require 'rdoc/markup/simple_markup/fragments' require 'rdoc/markup/simple_markup/inline' require 'cgi' module SM class ToHtml LIST_TYPE_TO_HTML = { ListBase::BULLET => [ "

        ", "
      " ], ListBase::NUMBER => [ "
        ", "
      " ], ListBase::UPPERALPHA => [ "
        ", "
      " ], ListBase::LOWERALPHA => [ "
        ", "
      " ], ListBase::LABELED => [ "
      ", "
      " ], ListBase::NOTE => [ "", "
      " ], } InlineTag = Struct.new(:bit, :on, :off) def initialize init_tags end ## # Set up the standard mapping of attributes to HTML tags # def init_tags @attr_tags = [ InlineTag.new(SM::Attribute.bitmap_for(:BOLD), "", ""), InlineTag.new(SM::Attribute.bitmap_for(:TT), "", ""), InlineTag.new(SM::Attribute.bitmap_for(:EM), "", ""), ] end ## # Add a new set of HTML tags for an attribute. We allow # separate start and end tags for flexibility # def add_tag(name, start, stop) @attr_tags << InlineTag.new(SM::Attribute.bitmap_for(name), start, stop) end ## # Given an HTML tag, decorate it with class information # and the like if required. This is a no-op in the base # class, but is overridden in HTML output classes that # implement style sheets def annotate(tag) tag end ## # Here's the client side of the visitor pattern def start_accepting @res = "" @in_list_entry = [] end def end_accepting @res end def accept_paragraph(am, fragment) @res << annotate("

      ") + "\n" @res << wrap(convert_flow(am.flow(fragment.txt))) @res << annotate("

      ") + "\n" end def accept_verbatim(am, fragment) @res << annotate("
      ") + "\n"
            @res << CGI.escapeHTML(fragment.txt)
            @res << annotate("
      ") << "\n" end def accept_rule(am, fragment) size = fragment.param size = 10 if size > 10 @res << "
      " end def accept_list_start(am, fragment) @res << html_list_name(fragment.type, true) <<"\n" @in_list_entry.push false end def accept_list_end(am, fragment) if tag = @in_list_entry.pop @res << annotate(tag) << "\n" end @res << html_list_name(fragment.type, false) <<"\n" end def accept_list_item(am, fragment) if tag = @in_list_entry.last @res << annotate(tag) << "\n" end @res << list_item_start(am, fragment) @res << wrap(convert_flow(am.flow(fragment.txt))) << "\n" @in_list_entry[-1] = list_end_for(fragment.type) end def accept_blank_line(am, fragment) # @res << annotate("

      ") << "\n" end def accept_heading(am, fragment) @res << convert_heading(fragment.head_level, am.flow(fragment.txt)) end # This is a higher speed (if messier) version of wrap def wrap(txt, line_len = 76) res = "" sp = 0 ep = txt.length while sp < ep # scan back for a space p = sp + line_len - 1 if p >= ep p = ep else while p > sp and txt[p] != ?\s p -= 1 end if p <= sp p = sp + line_len while p < ep and txt[p] != ?\s p += 1 end end end res << txt[sp...p] << "\n" sp = p sp += 1 while sp < ep and txt[sp] == ?\s end res end ####################################################################### private ####################################################################### def on_tags(res, item) attr_mask = item.turn_on return if attr_mask.zero? @attr_tags.each do |tag| if attr_mask & tag.bit != 0 res << annotate(tag.on) end end end def off_tags(res, item) attr_mask = item.turn_off return if attr_mask.zero? @attr_tags.reverse_each do |tag| if attr_mask & tag.bit != 0 res << annotate(tag.off) end end end def convert_flow(flow) res = "" flow.each do |item| case item when String res << convert_string(item) when AttrChanger off_tags(res, item) on_tags(res, item) when Special res << convert_special(item) else raise "Unknown flow element: #{item.inspect}" end end res end # some of these patterns are taken from SmartyPants... def convert_string(item) CGI.escapeHTML(item). # convert -- to em-dash, (-- to en-dash) gsub(/---?/, '—'). #gsub(/--/, '–'). # convert ... to elipsis (and make sure .... becomes .) gsub(/\.\.\.\./, '.…').gsub(/\.\.\./, '…'). # convert single closing quote gsub(%r{([^ \t\r\n\[\{\(])\'}) { "#$1’" }. gsub(%r{\'(?=\W|s\b)}) { "’" }. # convert single opening quote gsub(/'/, '‘'). # convert double closing quote gsub(%r{([^ \t\r\n\[\{\(])\'(?=\W)}) { "#$1”" }. # convert double opening quote gsub(/'/, '“'). # convert copyright gsub(/\(c\)/, '©'). # convert and registered trademark gsub(/\(r\)/, '®') end def convert_special(special) handled = false Attribute.each_name_of(special.type) do |name| method_name = "handle_special_#{name}" if self.respond_to? method_name special.text = send(method_name, special) handled = true end end raise "Unhandled special: #{special}" unless handled special.text end def convert_heading(level, flow) res = annotate("") + convert_flow(flow) + annotate("\n") end def html_list_name(list_type, is_open_tag) tags = LIST_TYPE_TO_HTML[list_type] || raise("Invalid list type: #{list_type.inspect}") annotate(tags[ is_open_tag ? 0 : 1]) end def list_item_start(am, fragment) case fragment.type when ListBase::BULLET, ListBase::NUMBER annotate("

    • ") when ListBase::UPPERALPHA annotate("
    • ") when ListBase::LOWERALPHA annotate("
    • ") when ListBase::LABELED annotate("
      ") + convert_flow(am.flow(fragment.param)) + annotate("
      ") + annotate("
      ") when ListBase::NOTE annotate("") + annotate("") + convert_flow(am.flow(fragment.param)) + annotate("") + annotate("") else raise "Invalid list type" end end def list_end_for(fragment_type) case fragment_type when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA, ListBase::LOWERALPHA "
    • " when ListBase::LABELED "" when ListBase::NOTE "" else raise "Invalid list type" end end end end ================================================ FILE: lib/rdoc/markup/simple_markup/to_latex.rb ================================================ require 'rdoc/markup/simple_markup/fragments' require 'rdoc/markup/simple_markup/inline' require 'cgi' module SM # Convert SimpleMarkup to basic LaTeX report format class ToLaTeX BS = "\020" # \ OB = "\021" # { CB = "\022" # } DL = "\023" # Dollar BACKSLASH = "#{BS}symbol#{OB}92#{CB}" HAT = "#{BS}symbol#{OB}94#{CB}" BACKQUOTE = "#{BS}symbol#{OB}0#{CB}" TILDE = "#{DL}#{BS}sim#{DL}" LESSTHAN = "#{DL}<#{DL}" GREATERTHAN = "#{DL}>#{DL}" def self.l(str) str.tr('\\', BS).tr('{', OB).tr('}', CB).tr('$', DL) end def l(arg) SM::ToLaTeX.l(arg) end LIST_TYPE_TO_LATEX = { ListBase::BULLET => [ l("\\begin{itemize}"), l("\\end{itemize}") ], ListBase::NUMBER => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\arabic" ], ListBase::UPPERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\Alph" ], ListBase::LOWERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\alph" ], ListBase::LABELED => [ l("\\begin{description}"), l("\\end{description}") ], ListBase::NOTE => [ l("\\begin{tabularx}{\\linewidth}{@{} l X @{}}"), l("\\end{tabularx}") ], } InlineTag = Struct.new(:bit, :on, :off) def initialize init_tags @list_depth = 0 @prev_list_types = [] end ## # Set up the standard mapping of attributes to LaTeX # def init_tags @attr_tags = [ InlineTag.new(SM::Attribute.bitmap_for(:BOLD), l("\\textbf{"), l("}")), InlineTag.new(SM::Attribute.bitmap_for(:TT), l("\\texttt{"), l("}")), InlineTag.new(SM::Attribute.bitmap_for(:EM), l("\\emph{"), l("}")), ] end ## # Escape a LaTeX string def escape(str) # $stderr.print "FE: ", str s = str. # sub(/\s+$/, ''). gsub(/([_\${}&%#])/, "#{BS}\\1"). gsub(/\\/, BACKSLASH). gsub(/\^/, HAT). gsub(/~/, TILDE). gsub(//, GREATERTHAN). gsub(/,,/, ",{},"). gsub(/\`/, BACKQUOTE) # $stderr.print "-> ", s, "\n" s end ## # Add a new set of LaTeX tags for an attribute. We allow # separate start and end tags for flexibility # def add_tag(name, start, stop) @attr_tags << InlineTag.new(SM::Attribute.bitmap_for(name), start, stop) end ## # Here's the client side of the visitor pattern def start_accepting @res = "" @in_list_entry = [] end def end_accepting @res.tr(BS, '\\').tr(OB, '{').tr(CB, '}').tr(DL, '$') end def accept_paragraph(am, fragment) @res << wrap(convert_flow(am.flow(fragment.txt))) @res << "\n" end def accept_verbatim(am, fragment) @res << "\n\\begin{code}\n" @res << fragment.txt.sub(/[\n\s]+\Z/, '') @res << "\n\\end{code}\n\n" end def accept_rule(am, fragment) size = fragment.param size = 10 if size > 10 @res << "\n\n\\rule{\\linewidth}{#{size}pt}\n\n" end def accept_list_start(am, fragment) @res << list_name(fragment.type, true) <<"\n" @in_list_entry.push false end def accept_list_end(am, fragment) if tag = @in_list_entry.pop @res << tag << "\n" end @res << list_name(fragment.type, false) <<"\n" end def accept_list_item(am, fragment) if tag = @in_list_entry.last @res << tag << "\n" end @res << list_item_start(am, fragment) @res << wrap(convert_flow(am.flow(fragment.txt))) << "\n" @in_list_entry[-1] = list_end_for(fragment.type) end def accept_blank_line(am, fragment) # @res << "\n" end def accept_heading(am, fragment) @res << convert_heading(fragment.head_level, am.flow(fragment.txt)) end # This is a higher speed (if messier) version of wrap def wrap(txt, line_len = 76) res = "" sp = 0 ep = txt.length while sp < ep # scan back for a space p = sp + line_len - 1 if p >= ep p = ep else while p > sp and txt[p] != ?\s p -= 1 end if p <= sp p = sp + line_len while p < ep and txt[p] != ?\s p += 1 end end end res << txt[sp...p] << "\n" sp = p sp += 1 while sp < ep and txt[sp] == ?\s end res end ####################################################################### private ####################################################################### def on_tags(res, item) attr_mask = item.turn_on return if attr_mask.zero? @attr_tags.each do |tag| if attr_mask & tag.bit != 0 res << tag.on end end end def off_tags(res, item) attr_mask = item.turn_off return if attr_mask.zero? @attr_tags.reverse_each do |tag| if attr_mask & tag.bit != 0 res << tag.off end end end def convert_flow(flow) res = "" flow.each do |item| case item when String # $stderr.puts "Converting '#{item}'" res << convert_string(item) when AttrChanger off_tags(res, item) on_tags(res, item) when Special res << convert_special(item) else raise "Unknown flow element: #{item.inspect}" end end res end # some of these patterns are taken from SmartyPants... def convert_string(item) escape(item). # convert ... to elipsis (and make sure .... becomes .) gsub(/\.\.\.\./, '.\ldots{}').gsub(/\.\.\./, '\ldots{}'). # convert single closing quote gsub(%r{([^ \t\r\n\[\{\(])\'}) { "#$1'" }. gsub(%r{\'(?=\W|s\b)}) { "'" }. # convert single opening quote gsub(/'/, '`'). # convert double closing quote gsub(%r{([^ \t\r\n\[\{\(])\"(?=\W)}) { "#$1''" }. # convert double opening quote gsub(/"/, "``"). # convert copyright gsub(/\(c\)/, '\copyright{}') end def convert_special(special) handled = false Attribute.each_name_of(special.type) do |name| method_name = "handle_special_#{name}" if self.respond_to? method_name special.text = send(method_name, special) handled = true end end raise "Unhandled special: #{special}" unless handled special.text end def convert_heading(level, flow) res = case level when 1 then "\\chapter{" when 2 then "\\section{" when 3 then "\\subsection{" when 4 then "\\subsubsection{" else "\\paragraph{" end + convert_flow(flow) + "}\n" end def list_name(list_type, is_open_tag) tags = LIST_TYPE_TO_LATEX[list_type] || raise("Invalid list type: #{list_type.inspect}") if tags[2] # enumerate if is_open_tag @list_depth += 1 if @prev_list_types[@list_depth] != tags[2] case @list_depth when 1 roman = "i" when 2 roman = "ii" when 3 roman = "iii" when 4 roman = "iv" else raise("Too deep list: level #{@list_depth}") end @prev_list_types[@list_depth] = tags[2] return l("\\renewcommand{\\labelenum#{roman}}{#{tags[2]}{enum#{roman}}}") + "\n" + tags[0] end else @list_depth -= 1 end end tags[ is_open_tag ? 0 : 1] end def list_item_start(am, fragment) case fragment.type when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA, ListBase::LOWERALPHA "\\item " when ListBase::LABELED "\\item[" + convert_flow(am.flow(fragment.param)) + "] " when ListBase::NOTE convert_flow(am.flow(fragment.param)) + " & " else raise "Invalid list type" end end def list_end_for(fragment_type) case fragment_type when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA, ListBase::LOWERALPHA, ListBase::LABELED "" when ListBase::NOTE "\\\\\n" else raise "Invalid list type" end end end end ================================================ FILE: lib/rdoc/markup/simple_markup.rb ================================================ # = Introduction # # SimpleMarkup parses plain text documents and attempts to decompose # them into their constituent parts. Some of these parts are high-level: # paragraphs, chunks of verbatim text, list entries and the like. Other # parts happen at the character level: a piece of bold text, a word in # code font. This markup is similar in spirit to that used on WikiWiki # webs, where folks create web pages using a simple set of formatting # rules. # # SimpleMarkup itself does no output formatting: this is left to a # different set of classes. # # SimpleMarkup is extendable at runtime: you can add new markup # elements to be recognised in the documents that SimpleMarkup parses. # # SimpleMarkup is intended to be the basis for a family of tools which # share the common requirement that simple, plain-text should be # rendered in a variety of different output formats and media. It is # envisaged that SimpleMarkup could be the basis for formating RDoc # style comment blocks, Wiki entries, and online FAQs. # # = Basic Formatting # # * SimpleMarkup looks for a document's natural left margin. This is # used as the initial margin for the document. # # * Consecutive lines starting at this margin are considered to be a # paragraph. # # * If a paragraph starts with a "*", "-", or with ".", then it is # taken to be the start of a list. The margin in increased to be the # first non-space following the list start flag. Subsequent lines # should be indented to this new margin until the list ends. For # example: # # * this is a list with three paragraphs in # the first item. This is the first paragraph. # # And this is the second paragraph. # # 1. This is an indented, numbered list. # 2. This is the second item in that list # # This is the third conventional paragraph in the # first list item. # # * This is the second item in the original list # # * You can also construct labeled lists, sometimes called description # or definition lists. Do this by putting the label in square brackets # and indenting the list body: # # [cat] a small furry mammal # that seems to sleep a lot # # [ant] a little insect that is known # to enjoy picnics # # A minor variation on labeled lists uses two colons to separate the # label from the list body: # # cat:: a small furry mammal # that seems to sleep a lot # # ant:: a little insect that is known # to enjoy picnics # # This latter style guarantees that the list bodies' left margins are # aligned: think of them as a two column table. # # * Any line that starts to the right of the current margin is treated # as verbatim text. This is useful for code listings. The example of a # list above is also verbatim text. # # * A line starting with an equals sign (=) is treated as a # heading. Level one headings have one equals sign, level two headings # have two,and so on. # # * A line starting with three or more hyphens (at the current indent) # generates a horizontal rule. THe more hyphens, the thicker the rule # (within reason, and if supported by the output device) # # * You can use markup within text (except verbatim) to change the # appearance of parts of that text. Out of the box, SimpleMarkup # supports word-based and general markup. # # Word-based markup uses flag characters around individual words: # # [\*word*] displays word in a *bold* font # [\_word_] displays word in an _emphasized_ font # [\+word+] displays word in a +code+ font # # General markup affects text between a start delimiter and and end # delimiter. Not surprisingly, these delimiters look like HTML markup. # # [\text...] displays word in a *bold* font # [\text...] displays word in an _emphasized_ font # [\text...] displays word in an _emphasized_ font # [\text...] displays word in a +code+ font # # Unlike conventional Wiki markup, general markup can cross line # boundaries. You can turn off the interpretation of markup by # preceding the first character with a backslash, so \\\bold # text and \\\*bold* produce \bold text and \*bold # respectively. # # = Using SimpleMarkup # # For information on using SimpleMarkup programatically, # see SM::SimpleMarkup. # # Author:: Dave Thomas, dave@pragmaticprogrammer.com # Version:: 0.0 # License:: Ruby license require 'rdoc/markup/simple_markup/fragments' require 'rdoc/markup/simple_markup/lines.rb' module SM #:nodoc: # == Synopsis # # This code converts input_string, which is in the format # described in markup/simple_markup.rb, to HTML. The conversion # takes place in the +convert+ method, so you can use the same # SimpleMarkup object to convert multiple input strings. # # require 'rdoc/markup/simple_markup' # require 'rdoc/markup/simple_markup/to_html' # # p = SM::SimpleMarkup.new # h = SM::ToHtml.new # # puts p.convert(input_string, h) # # You can extend the SimpleMarkup parser to recognise new markup # sequences, and to add special processing for text that matches a # regular epxression. Here we make WikiWords significant to the parser, # and also make the sequences {word} and \text... signify # strike-through text. When then subclass the HTML output class to deal # with these: # # require 'rdoc/markup/simple_markup' # require 'rdoc/markup/simple_markup/to_html' # # class WikiHtml < SM::ToHtml # def handle_special_WIKIWORD(special) # "" + special.text + "" # end # end # # p = SM::SimpleMarkup.new # p.add_word_pair("{", "}", :STRIKE) # p.add_html("no", :STRIKE) # # p.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD) # # h = WikiHtml.new # h.add_tag(:STRIKE, "", "") # # puts "" + p.convert(ARGF.read, h) + "" # # == Output Formatters # # _missing_ # # class SimpleMarkup SPACE = ?\s # List entries look like: # * text # 1. text # [label] text # label:: text # # Flag it as a list entry, and # work out the indent for subsequent lines SIMPLE_LIST_RE = /^( ( \* (?# bullet) |- (?# bullet) |\d+\. (?# numbered ) |[A-Za-z]\. (?# alphabetically numbered ) ) \s+ )\S/x LABEL_LIST_RE = /^( ( \[.*?\] (?# labeled ) |\S.*:: (?# note ) )(?:\s+|$) )/x ## # take a block of text and use various heuristics to determine # it's structure (paragraphs, lists, and so on). Invoke an # event handler as we identify significant chunks. # def initialize @am = AttributeManager.new @output = nil end ## # Add to the sequences used to add formatting to an individual word # (such as *bold*). Matching entries will generate attibutes # that the output formatters can recognize by their +name+ def add_word_pair(start, stop, name) @am.add_word_pair(start, stop, name) end ## # Add to the sequences recognized as general markup # def add_html(tag, name) @am.add_html(tag, name) end ## # Add to other inline sequences. For example, we could add # WikiWords using something like: # # parser.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD) # # Each wiki word will be presented to the output formatter # via the accept_special method # def add_special(pattern, name) @am.add_special(pattern, name) end # We take a string, split it into lines, work out the type of # each line, and from there deduce groups of lines (for example # all lines in a paragraph). We then invoke the output formatter # using a Visitor to display the result def convert(str, op) @lines = Lines.new(str.split(/\r?\n/).collect { |aLine| Line.new(aLine) }) return "" if @lines.empty? @lines.normalize assign_types_to_lines group = group_lines # call the output formatter to handle the result # group.to_a.each {|i| p i} group.accept(@am, op) end ####### private ####### ## # Look through the text at line indentation. We flag each line as being # Blank, a paragraph, a list element, or verbatim text # def assign_types_to_lines(margin = 0, level = 0) while line = @lines.next if line.isBlank? line.stamp(Line::BLANK, level) next end # if a line contains non-blanks before the margin, then it must belong # to an outer level text = line.text for i in 0...margin if text[i] != SPACE @lines.unget return end end active_line = text[margin..-1] # Rules (horizontal lines) look like # # --- (three or more hyphens) # # The more hyphens, the thicker the rule # if /^(---+)\s*$/ =~ active_line line.stamp(Line::RULE, level, $1.length-2) next end # Then look for list entries. First the ones that have to have # text following them (* xxx, - xxx, and dd. xxx) if SIMPLE_LIST_RE =~ active_line offset = margin + $1.length prefix = $2 prefix_length = prefix.length flag = case prefix when "*","-" then ListBase::BULLET when /^\d/ then ListBase::NUMBER when /^[A-Z]/ then ListBase::UPPERALPHA when /^[a-z]/ then ListBase::LOWERALPHA else raise "Invalid List Type: #{self.inspect}" end line.stamp(Line::LIST, level+1, prefix, flag) text[margin, prefix_length] = " " * prefix_length assign_types_to_lines(offset, level + 1) next end if LABEL_LIST_RE =~ active_line offset = margin + $1.length prefix = $2 prefix_length = prefix.length next if handled_labeled_list(line, level, margin, offset, prefix) end # Headings look like # = Main heading # == Second level # === Third # # Headings reset the level to 0 if active_line[0] == ?= and active_line =~ /^(=+)\s*(.*)/ prefix_length = $1.length prefix_length = 6 if prefix_length > 6 line.stamp(Line::HEADING, 0, prefix_length) line.strip_leading(margin + prefix_length) next end # If the character's a space, then we have verbatim text, # otherwise if active_line[0] == SPACE line.strip_leading(margin) if margin > 0 line.stamp(Line::VERBATIM, level) else line.stamp(Line::PARAGRAPH, level) end end end # Handle labeled list entries, We have a special case # to deal with. Because the labels can be long, they force # the remaining block of text over the to right: # # this is a long label that I wrote:: and here is the # block of text with # a silly margin # # So we allow the special case. If the label is followed # by nothing, and if the following line is indented, then # we take the indent of that line as the new margin # # this is a long label that I wrote:: # here is a more reasonably indented block which # will ab attached to the label. # def handled_labeled_list(line, level, margin, offset, prefix) prefix_length = prefix.length text = line.text flag = nil case prefix when /^\[/ flag = ListBase::LABELED prefix = prefix[1, prefix.length-2] when /:$/ flag = ListBase::NOTE prefix.chop! else raise "Invalid List Type: #{self.inspect}" end # body is on the next line if text.length <= offset original_line = line line = @lines.next return(false) unless line text = line.text for i in 0..margin if text[i] != SPACE @lines.unget return false end end i = margin i += 1 while text[i] == SPACE if i >= text.length @lines.unget return false else offset = i prefix_length = 0 @lines.delete(original_line) end end line.stamp(Line::LIST, level+1, prefix, flag) text[margin, prefix_length] = " " * prefix_length assign_types_to_lines(offset, level + 1) return true end # Return a block consisting of fragments which are # paragraphs, list entries or verbatim text. We merge consecutive # lines of the same type and level together. We are also slightly # tricky with lists: the lines following a list introduction # look like paragraph lines at the next level, and we remap them # into list entries instead def group_lines @lines.rewind inList = false wantedType = wantedLevel = nil block = LineCollection.new group = nil while line = @lines.next if line.level == wantedLevel and line.type == wantedType group.add_text(line.text) else group = block.fragment_for(line) block.add(group) if line.type == Line::LIST wantedType = Line::PARAGRAPH else wantedType = line.type end wantedLevel = line.type == Line::HEADING ? line.param : line.level end end block.normalize block end ## for debugging, we allow access to our line contents as text def content @lines.as_text end public :content ## for debugging, return the list of line types def get_line_types @lines.line_types end public :get_line_types end end ================================================ FILE: lib/rdoc/markup/test/AllTests.rb ================================================ require 'TestParse.rb' require 'TestInline.rb' ================================================ FILE: lib/rdoc/markup/test/TestInline.rb ================================================ require "test/unit" $:.unshift "../../.." require "rdoc/markup/simple_markup/inline" class TestInline < Test::Unit::TestCase def setup @am = SM::AttributeManager.new @bold_on = @am.changed_attribute_by_name([], [:BOLD]) @bold_off = @am.changed_attribute_by_name([:BOLD], []) @tt_on = @am.changed_attribute_by_name([], [:TT]) @tt_off = @am.changed_attribute_by_name([:TT], []) @em_on = @am.changed_attribute_by_name([], [:EM]) @em_off = @am.changed_attribute_by_name([:EM], []) @bold_em_on = @am.changed_attribute_by_name([], [:BOLD] | [:EM]) @bold_em_off = @am.changed_attribute_by_name([:BOLD] | [:EM], []) @em_then_bold = @am.changed_attribute_by_name([:EM], [:EM] | [:BOLD]) @em_to_bold = @am.changed_attribute_by_name([:EM], [:BOLD]) @am.add_word_pair("{", "}", :WOMBAT) @wombat_on = @am.changed_attribute_by_name([], [:WOMBAT]) @wombat_off = @am.changed_attribute_by_name([:WOMBAT], []) end def crossref(text) [ @am.changed_attribute_by_name([], [:CROSSREF] | [:_SPECIAL_]), SM::Special.new(33, text), @am.changed_attribute_by_name([:CROSSREF] | [:_SPECIAL_], []) ] end def test_special # class names, variable names, file names, or instance variables @am.add_special(/( \b([A-Z]\w+(::\w+)*) | \#\w+[!?=]? | \b\w+([_\/\.]+\w+)+[!?=]? )/x, :CROSSREF) assert_equal(["cat"], @am.flow("cat")) assert_equal(["cat ", crossref("#fred"), " dog"].flatten, @am.flow("cat #fred dog")) assert_equal([crossref("#fred"), " dog"].flatten, @am.flow("#fred dog")) assert_equal(["cat ", crossref("#fred")].flatten, @am.flow("cat #fred")) end def test_basic assert_equal(["cat"], @am.flow("cat")) assert_equal(["cat ", @bold_on, "and", @bold_off, " dog"], @am.flow("cat *and* dog")) assert_equal(["cat ", @bold_on, "AND", @bold_off, " dog"], @am.flow("cat *AND* dog")) assert_equal(["cat ", @em_on, "And", @em_off, " dog"], @am.flow("cat _And_ dog")) assert_equal(["cat *and dog*"], @am.flow("cat *and dog*")) assert_equal(["*cat and* dog"], @am.flow("*cat and* dog")) assert_equal(["cat *and ", @bold_on, "dog", @bold_off], @am.flow("cat *and *dog*")) assert_equal(["cat ", @em_on, "and", @em_off, " dog"], @am.flow("cat _and_ dog")) assert_equal(["cat_and_dog"], @am.flow("cat_and_dog")) assert_equal(["cat ", @tt_on, "and", @tt_off, " dog"], @am.flow("cat +and+ dog")) assert_equal(["cat ", @bold_on, "a_b_c", @bold_off, " dog"], @am.flow("cat *a_b_c* dog")) assert_equal(["cat __ dog"], @am.flow("cat __ dog")) assert_equal(["cat ", @em_on, "_", @em_off, " dog"], @am.flow("cat ___ dog")) end def test_combined assert_equal(["cat ", @em_on, "and", @em_off, " ", @bold_on, "dog", @bold_off], @am.flow("cat _and_ *dog*")) assert_equal(["cat ", @em_on, "a__nd", @em_off, " ", @bold_on, "dog", @bold_off], @am.flow("cat _a__nd_ *dog*")) end def test_html_like assert_equal(["cat ", @tt_on, "dog", @tt_off], @am.flow("cat dog")) assert_equal(["cat ", @em_on, "and", @em_off, " ", @bold_on, "dog", @bold_off], @am.flow("cat and dog")) assert_equal(["cat ", @em_on, "and ", @em_then_bold, "dog", @bold_em_off], @am.flow("cat and dog")) assert_equal(["cat ", @em_on, "and ", @em_to_bold, "dog", @bold_off], @am.flow("cat and dog")) assert_equal(["cat ", @em_on, "and ", @em_to_bold, "dog", @bold_off], @am.flow("cat and dog")) assert_equal([@tt_on, "cat", @tt_off, " ", @em_on, "and ", @em_to_bold, "dog", @bold_off], @am.flow("cat and dog")) assert_equal(["cat ", @em_on, "and ", @em_then_bold, "dog", @bold_em_off], @am.flow("cat and dog")) assert_equal(["cat ", @bold_em_on, "and", @bold_em_off, " dog"], @am.flow("cat and dog")) end def test_protect assert_equal(['cat \\ dog'], @am.flow('cat \\ dog')) assert_equal(["cat dog"], @am.flow("cat \\dog")) assert_equal(["cat ", @em_on, "and", @em_off, " dog"], @am.flow("cat and \\dog")) assert_equal(["*word* or text"], @am.flow("\\*word* or \\text")) assert_equal(["_cat_", @em_on, "dog", @em_off], @am.flow("\\_cat_dog")) end def test_adding assert_equal(["cat ", @wombat_on, "and", @wombat_off, " dog" ], @am.flow("cat {and} dog")) # assert_equal(["cat {and} dog" ], @am.flow("cat \\{and} dog")) end end ================================================ FILE: lib/rdoc/markup/test/TestParse.rb ================================================ require 'test/unit' $:.unshift "../../.." require 'rdoc/markup/simple_markup' include SM class TestParse < Test::Unit::TestCase class MockOutput def start_accepting @res = [] end def end_accepting @res end def accept_paragraph(am, fragment) @res << fragment.to_s end def accept_verbatim(am, fragment) @res << fragment.to_s end def accept_list_start(am, fragment) @res << fragment.to_s end def accept_list_end(am, fragment) @res << fragment.to_s end def accept_list_item(am, fragment) @res << fragment.to_s end def accept_blank_line(am, fragment) @res << fragment.to_s end def accept_heading(am, fragment) @res << fragment.to_s end def accept_rule(am, fragment) @res << fragment.to_s end end def basic_conv(str) sm = SimpleMarkup.new mock = MockOutput.new sm.convert(str, mock) sm.content end def line_types(str, expected) p = SimpleMarkup.new mock = MockOutput.new p.convert(str, mock) assert_equal(expected, p.get_line_types.map{|type| type.to_s[0,1]}.join('')) end def line_groups(str, expected) p = SimpleMarkup.new mock = MockOutput.new block = p.convert(str, mock) if block != expected rows = (0...([expected.size, block.size].max)).collect{|i| [expected[i]||"nil", block[i]||"nil"] } printf "\n\n%35s %35s\n", "Expected", "Got" rows.each {|e,g| printf "%35s %35s\n", e.dump, g.dump } end assert_equal(expected, block) end def test_tabs str = "hello\n dave" assert_equal(str, basic_conv(str)) str = "hello\n\tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = ".\t\t." assert_equal(". .", basic_conv(str)) end def test_whitespace assert_equal("hello", basic_conv("hello")) assert_equal("hello", basic_conv(" hello ")) assert_equal("hello", basic_conv(" \t \t hello\t\t")) assert_equal("1\n 2\n 3", basic_conv("1\n 2\n 3")) assert_equal("1\n 2\n 3", basic_conv(" 1\n 2\n 3")) assert_equal("1\n 2\n 3\n1\n 2", basic_conv("1\n 2\n 3\n1\n 2")) assert_equal("1\n 2\n 3\n1\n 2", basic_conv(" 1\n 2\n 3\n 1\n 2")) assert_equal("1\n 2\n\n 3", basic_conv(" 1\n 2\n\n 3")) end def test_types str = "now is the time" line_types(str, 'P') str = "now is the time\nfor all good men" line_types(str, 'PP') str = "now is the time\n code\nfor all good men" line_types(str, 'PVP') str = "now is the time\n code\n more code\nfor all good men" line_types(str, 'PVVP') str = "now is\n---\nthe time" line_types(str, 'PRP') str = %{\ now is * l1 * l2 the time} line_types(str, 'PLLP') str = %{\ now is * l1 l1+ * l2 the time} line_types(str, 'PLPLP') str = %{\ now is * l1 * l1.1 * l2 the time} line_types(str, 'PLLLP') str = %{\ now is * l1 * l1.1 text code code text * l2 the time} line_types(str, 'PLLPVVBPLP') str = %{\ now is 1. l1 * l1.1 2. l2 the time} line_types(str, 'PLLLP') str = %{\ now is [cat] l1 * l1.1 [dog] l2 the time} line_types(str, 'PLLLP') str = %{\ now is [cat] l1 continuation [dog] l2 the time} line_types(str, 'PLPLP') end def test_groups str = "now is the time" line_groups(str, ["L0: Paragraph\nnow is the time"] ) str = "now is the time\nfor all good men" line_groups(str, ["L0: Paragraph\nnow is the time for all good men"] ) str = %{\ now is the time code _line_ here for all good men} line_groups(str, [ "L0: Paragraph\nnow is the time", "L0: Verbatim\n code _line_ here\n", "L0: Paragraph\nfor all good men" ] ) str = "now is the time\n code\n more code\nfor all good men" line_groups(str, [ "L0: Paragraph\nnow is the time", "L0: Verbatim\n code\n more code\n", "L0: Paragraph\nfor all good men" ] ) str = %{\ now is * l1 * l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) str = %{\ now is * l1 l1+ * l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1 l1+", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) str = %{\ now is * l1 * l1.1 * l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1", "L2: ListStart\n", "L2: ListItem\nl1.1", "L2: ListEnd\n", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) str = %{\ now is * l1 * l1.1 text code code text * l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1", "L2: ListStart\n", "L2: ListItem\nl1.1 text", "L2: Verbatim\n code\n code\n", "L2: Paragraph\ntext", "L2: ListEnd\n", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) str = %{\ now is 1. l1 * l1.1 2. l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1", "L2: ListStart\n", "L2: ListItem\nl1.1", "L2: ListEnd\n", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) str = %{\ now is [cat] l1 * l1.1 [dog] l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1", "L2: ListStart\n", "L2: ListItem\nl1.1", "L2: ListEnd\n", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) str = %{\ now is [cat] l1 continuation [dog] l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1 continuation", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) end def test_verbatim_merge str = %{\ now is code the time} line_groups(str, [ "L0: Paragraph\nnow is", "L0: Verbatim\n code\n", "L0: Paragraph\nthe time" ]) str = %{\ now is code code1 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L0: Verbatim\n code\n code1\n", "L0: Paragraph\nthe time" ]) str = %{\ now is code code1 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L0: Verbatim\n code\n\n code1\n", "L0: Paragraph\nthe time" ]) str = %{\ now is code code1 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L0: Verbatim\n code\n\n code1\n", "L0: Paragraph\nthe time" ]) str = %{\ now is code code1 code2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L0: Verbatim\n code\n\n code1\n\n code2\n", "L0: Paragraph\nthe time" ]) # Folds multiple blank lines str = %{\ now is code code1 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L0: Verbatim\n code\n\n code1\n", "L0: Paragraph\nthe time" ]) end def test_list_split str = %{\ now is * l1 1. n1 2. n2 * l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1", "L1: ListEnd\n", "L1: ListStart\n", "L1: ListItem\nn1", "L1: ListItem\nn2", "L1: ListEnd\n", "L1: ListStart\n", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) end def test_headings str = "= heading one" line_groups(str, [ "L0: Heading\nheading one" ]) str = "=== heading three" line_groups(str, [ "L0: Heading\nheading three" ]) str = "text\n === heading three" line_groups(str, [ "L0: Paragraph\ntext", "L0: Verbatim\n === heading three\n" ]) str = "text\n code\n === heading three" line_groups(str, [ "L0: Paragraph\ntext", "L0: Verbatim\n code\n === heading three\n" ]) str = "text\n code\n=== heading three" line_groups(str, [ "L0: Paragraph\ntext", "L0: Verbatim\n code\n", "L0: Heading\nheading three" ]) end end ================================================ FILE: lib/rdoc/options.rb ================================================ # We handle the parsing of options, and subsequently as a singleton # object to be queried for option values require "rdoc/ri/ri_paths" class Options require 'singleton' require 'getoptlong' include Singleton # files matching this pattern will be excluded attr_accessor :exclude # the name of the output directory attr_accessor :op_dir # the name to use for the output attr_reader :op_name # include private and protected methods in the # output attr_accessor :show_all # name of the file, class or module to display in # the initial index page (if not specified # the first file we encounter is used) attr_accessor :main_page # merge into classes of the name name when generating ri attr_reader :merge # Don't display progress as we process the files attr_reader :quiet # description of the output generator (set with the -fmt # option attr_accessor :generator # and the list of files to be processed attr_reader :files # array of directories to search for files to satisfy an :include: attr_reader :rdoc_include # title to be used out the output #attr_writer :title # template to be used when generating output attr_reader :template # should diagrams be drawn attr_reader :diagram # should we draw fileboxes in diagrams attr_reader :fileboxes # include the '#' at the front of hyperlinked instance method names attr_reader :show_hash # image format for diagrams attr_reader :image_format # character-set attr_reader :charset # should source code be included inline, or displayed in a popup attr_reader :inline_source # should the output be placed into a single file attr_reader :all_one_file # the number of columns in a tab attr_reader :tab_width # include line numbers in the source listings attr_reader :include_line_numbers # pattern for additional attr_... style methods attr_reader :extra_accessors attr_reader :extra_accessor_flags # URL of stylesheet attr_reader :css # URL of web cvs frontend attr_reader :webcvs # Are we promiscuous about showing module contents across # multiple files attr_reader :promiscuous # scan newer sources than the flag file if true. attr_reader :force_update module OptionList OPTION_LIST = [ [ "--accessor", "-A", "accessorname[,..]", "comma separated list of additional class methods\n" + "that should be treated like 'attr_reader' and\n" + "friends. Option may be repeated. Each accessorname\n" + "may have '=text' appended, in which case that text\n" + "appears where the r/w/rw appears for normal accessors."], [ "--all", "-a", nil, "include all methods (not just public)\nin the output" ], [ "--charset", "-c", "charset", "specifies HTML character-set" ], [ "--debug", "-D", nil, "displays lots on internal stuff" ], [ "--diagram", "-d", nil, "Generate diagrams showing modules and classes.\n" + "You need dot V1.8.6 or later to use the --diagram\n" + "option correctly. Dot is available from\n"+ "http://www.research.att.com/sw/tools/graphviz/" ], [ "--exclude", "-x", "pattern", "do not process files or directories matching\n" + "pattern. Files given explicitly on the command\n" + "line will never be excluded." ], [ "--extension", "-E", "new=old", "Treat files ending with .new as if they ended with\n" + ".old. Using '-E cgi=rb' will cause xxx.cgi to be\n" + "parsed as a Ruby file"], [ "--fileboxes", "-F", nil, "classes are put in boxes which represents\n" + "files, where these classes reside. Classes\n" + "shared between more than one file are\n" + "shown with list of files that sharing them.\n" + "Silently discarded if --diagram is not given\n" + "Experimental." ], [ "--force-update", "-U", nil, "forces to scan all sources even if newer than\n" + "the flag file." ], [ "--fmt", "-f", "format name", "set the output formatter (see below)" ], [ "--help", "-h", nil, "you're looking at it" ], [ "--help-output", "-O", nil, "explain the various output options" ], [ "--image-format", "-I", "gif/png/jpg/jpeg", "Sets output image format for diagrams. Can\n" + "be png, gif, jpeg, jpg. If this option is\n" + "omitted, png is used. Requires --diagram." ], [ "--include", "-i", "dir[,dir...]", "set (or add to) the list of directories\n" + "to be searched when satisfying :include:\n" + "requests. Can be used more than once." ], [ "--inline-source", "-S", nil, "Show method source code inline, rather\n" + "than via a popup link" ], [ "--line-numbers", "-N", nil, "Include line numbers in the source code" ], [ "--main", "-m", "name", "'name' will be the initial page displayed" ], [ "--merge", "-M", nil, "when creating ri output, merge processed classes\n" + "into previously documented classes of the name name"], [ "--one-file", "-1", nil, "put all the output into a single file" ], [ "--op", "-o", "dir", "set the output directory" ], [ "--opname", "-n", "name", "Set the 'name' of the output. Has no\n" + "effect for HTML." ], [ "--promiscuous", "-p", nil, "When documenting a file that contains a module\n" + "or class also defined in other files, show\n" + "all stuff for that module/class in each files\n" + "page. By default, only show stuff defined in\n" + "that particular file." ], [ "--quiet", "-q", nil, "don't show progress as we parse" ], [ "--ri", "-r", nil, "generate output for use by 'ri.' The files are\n" + "stored in the '.rdoc' directory under your home\n"+ "directory unless overridden by a subsequent\n" + "--op parameter, so no special privileges are needed." ], [ "--ri-site", "-R", nil, "generate output for use by 'ri.' The files are\n" + "stored in a site-wide directory, making them accessible\n"+ "to others, so special privileges are needed." ], [ "--ri-system", "-Y", nil, "generate output for use by 'ri.' The files are\n" + "stored in a system-level directory, making them accessible\n"+ "to others, so special privileges are needed. This option\n"+ "is intended to be used during Ruby installations" ], [ "--show-hash", "-H", nil, "A name of the form #name in a comment\n" + "is a possible hyperlink to an instance\n" + "method name. When displayed, the '#' is\n" + "removed unless this option is specified" ], [ "--style", "-s", "stylesheet url", "specifies the URL of a separate stylesheet." ], [ "--tab-width", "-w", "n", "Set the width of tab characters (default 8)"], [ "--template", "-T", "template name", "Set the template used when generating output" ], [ "--title", "-t", "text", "Set 'txt' as the title for the output" ], [ "--version", "-v", nil, "display RDoc's version" ], [ "--webcvs", "-W", "url", "Specify a URL for linking to a web frontend\n" + "to CVS. If the URL contains a '\%s', the\n" + "name of the current file will be substituted;\n" + "if the URL doesn't contain a '\%s', the\n" + "filename will be appended to it." ], ] def OptionList.options OPTION_LIST.map do |long, short, arg,| [ long, short, arg ? GetoptLong::REQUIRED_ARGUMENT : GetoptLong::NO_ARGUMENT ] end end def OptionList.strip_output(text) text =~ /^\s+/ leading_spaces = $& text.gsub!(/^#{leading_spaces}/, '') $stdout.puts text end # Show an error and exit def OptionList.error(msg) $stderr.puts $stderr.puts msg $stderr.puts "\nFor help on options, try 'rdoc --help'\n\n" exit 1 end # Show usage and exit def OptionList.usage(generator_names) puts puts(VERSION_STRING) puts name = File.basename($0) OptionList.strip_output(<<-EOT) Usage: #{name} [options] [names...] Files are parsed, and the information they contain collected, before any output is produced. This allows cross references between all files to be resolved. If a name is a directory, it is traversed. If no names are specified, all Ruby files in the current directory (and subdirectories) are processed. Options: EOT OPTION_LIST.each do |long, short, arg, desc| opt = sprintf("%20s", "#{long}, #{short}") oparg = sprintf("%-7s", arg) print "#{opt} #{oparg}" desc = desc.split("\n") if arg.nil? || arg.length < 7 puts desc.shift else puts end desc.each do |line| puts(" "*28 + line) end puts end puts "\nAvailable output formatters: " + generator_names.sort.join(', ') + "\n\n" puts "For information on where the output goes, use\n\n" puts " rdoc --help-output\n\n" exit 0 end def OptionList.help_output OptionList.strip_output(<<-EOT) How RDoc generates output depends on the output formatter being used, and on the options you give. - HTML output is normally produced into a number of separate files (one per class, module, and file, along with various indices). These files will appear in the directory given by the --op option (doc/ by default). - XML output by default is written to standard output. If a --opname option is given, the output will instead be written to a file with that name in the output directory. - .chm files (Windows help files) are written in the --op directory. If an --opname parameter is present, that name is used, otherwise the file will be called rdoc.chm. For information on other RDoc options, use "rdoc --help". EOT exit 0 end end # Parse command line options. We're passed a hash containing # output generators, keyed by the generator name def parse(argv, generators) old_argv = ARGV.dup begin ARGV.replace(argv) @op_dir = "doc" @op_name = nil @show_all = false @main_page = nil @marge = false @exclude = [] @quiet = false @generator_name = 'html' @generator = generators[@generator_name] @rdoc_include = [] @title = nil @template = nil @diagram = false @fileboxes = false @show_hash = false @image_format = 'png' @inline_source = false @all_one_file = false @tab_width = 8 @include_line_numbers = false @extra_accessor_flags = {} @promiscuous = false @force_update = false @css = nil @webcvs = nil @charset = case $KCODE when /^S/i 'Shift_JIS' when /^E/i 'EUC-JP' else 'iso-8859-1' end accessors = [] go = GetoptLong.new(*OptionList.options) go.quiet = true go.each do |opt, arg| case opt when "--all" then @show_all = true when "--charset" then @charset = arg when "--debug" then $DEBUG = true when "--exclude" then @exclude << Regexp.new(arg) when "--inline-source" then @inline_source = true when "--line-numbers" then @include_line_numbers = true when "--main" then @main_page = arg when "--merge" then @merge = true when "--one-file" then @all_one_file = @inline_source = true when "--op" then @op_dir = arg when "--opname" then @op_name = arg when "--promiscuous" then @promiscuous = true when "--quiet" then @quiet = true when "--show-hash" then @show_hash = true when "--style" then @css = arg when "--template" then @template = arg when "--title" then @title = arg when "--webcvs" then @webcvs = arg when "--accessor" arg.split(/,/).each do |accessor| if accessor =~ /^(\w+)(=(.*))?$/ accessors << $1 @extra_accessor_flags[$1] = $3 end end when "--diagram" check_diagram @diagram = true when "--fileboxes" @fileboxes = true if @diagram when "--fmt" @generator_name = arg.downcase setup_generator(generators) when "--help" OptionList.usage(generators.keys) when "--help-output" OptionList.help_output when "--image-format" if ['gif', 'png', 'jpeg', 'jpg'].include?(arg) @image_format = arg else raise GetoptLong::InvalidOption.new("unknown image format: #{arg}") end when "--include" @rdoc_include.concat arg.split(/\s*,\s*/) when "--ri", "--ri-site", "--ri-system" @generator_name = "ri" @op_dir = case opt when "--ri" then RI::Paths::HOMEDIR when "--ri-site" then RI::Paths::SITEDIR when "--ri-system" then RI::Paths::SYSDIR else fail opt end setup_generator(generators) when "--tab-width" begin @tab_width = Integer(arg) rescue $stderr.puts "Invalid tab width: '#{arg}'" exit 1 end when "--extension" new, old = arg.split(/=/, 2) OptionList.error("Invalid parameter to '-E'") unless new && old unless RDoc::ParserFactory.alias_extension(old, new) OptionList.error("Unknown extension .#{old} to -E") end when "--force-update" @force_update = true when "--version" puts VERSION_STRING exit end end @files = ARGV.dup @rdoc_include << "." if @rdoc_include.empty? if @exclude.empty? @exclude = nil else @exclude = Regexp.new(@exclude.join("|")) end check_files # If no template was specified, use the default # template for the output formatter @template ||= @generator_name # Generate a regexp from the accessors unless accessors.empty? re = '^(' + accessors.map{|a| Regexp.quote(a)}.join('|') + ')$' @extra_accessors = Regexp.new(re) end rescue GetoptLong::InvalidOption, GetoptLong::MissingArgument => error OptionList.error(error.message) ensure ARGV.replace(old_argv) end end def title @title ||= "RDoc Documentation" end # Set the title, but only if not already set. This means that a title set from # the command line trumps one set in a source file def title=(string) @title ||= string end private # Set up an output generator for the format in @generator_name def setup_generator(generators) @generator = generators[@generator_name] if !@generator OptionList.error("Invalid output formatter") end if @generator_name == "xml" @all_one_file = true @inline_source = true end end # Check that the right version of 'dot' is available. # Unfortuately this doesn't work correctly under Windows NT, # so we'll bypass the test under Windows def check_diagram return if RUBY_PLATFORM =~ /mswin|cygwin|mingw|bccwin/ ok = false ver = nil IO.popen("dot -V 2>&1") do |io| ver = io.read if ver =~ /dot.+version(?:\s+gviz)?\s+(\d+)\.(\d+)/ ok = ($1.to_i > 1) || ($1.to_i == 1 && $2.to_i >= 8) end end unless ok if ver =~ /^dot.+version/ $stderr.puts "Warning: You may need dot V1.8.6 or later to use\n", "the --diagram option correctly. You have:\n\n ", ver, "\nDiagrams might have strange background colors.\n\n" else $stderr.puts "You need the 'dot' program to produce diagrams.", "(see http://www.research.att.com/sw/tools/graphviz/)\n\n" exit end # exit end end # Check that the files on the command line exist def check_files @files.each do |f| stat = File.stat f rescue error("File not found: #{f}") error("File '#{f}' not readable") unless stat.readable? end end def error(str) $stderr.puts str exit(1) end end ================================================ FILE: lib/rdoc/parsers/parse_c.rb ================================================ # Classes and modules built in to the interpreter. We need # these to define superclasses of user objects require "rdoc/code_objects" require "rdoc/parsers/parserfactory" require "rdoc/options" require "rdoc/rdoc" module RDoc ## # Ruby's built-in classes. KNOWN_CLASSES = { "rb_cObject" => "Object", "rb_cArray" => "Array", "rb_cBignum" => "Bignum", "rb_cClass" => "Class", "rb_cDir" => "Dir", "rb_cData" => "Data", "rb_cFalseClass" => "FalseClass", "rb_cFile" => "File", "rb_cFixnum" => "Fixnum", "rb_cFloat" => "Float", "rb_cHash" => "Hash", "rb_cInteger" => "Integer", "rb_cIO" => "IO", "rb_cModule" => "Module", "rb_cNilClass" => "NilClass", "rb_cNumeric" => "Numeric", "rb_cProc" => "Proc", "rb_cRange" => "Range", "rb_cRegexp" => "Regexp", "rb_cString" => "String", "rb_cSymbol" => "Symbol", "rb_cThread" => "Thread", "rb_cTime" => "Time", "rb_cTrueClass" => "TrueClass", "rb_cStruct" => "Struct", "rb_eException" => "Exception", "rb_eStandardError" => "StandardError", "rb_eSystemExit" => "SystemExit", "rb_eInterrupt" => "Interrupt", "rb_eSignal" => "Signal", "rb_eFatal" => "Fatal", "rb_eArgError" => "ArgError", "rb_eEOFError" => "EOFError", "rb_eIndexError" => "IndexError", "rb_eRangeError" => "RangeError", "rb_eIOError" => "IOError", "rb_eRuntimeError" => "RuntimeError", "rb_eSecurityError" => "SecurityError", "rb_eSystemCallError" => "SystemCallError", "rb_eTypeError" => "TypeError", "rb_eZeroDivError" => "ZeroDivError", "rb_eNotImpError" => "NotImpError", "rb_eNoMemError" => "NoMemError", "rb_eFloatDomainError" => "FloatDomainError", "rb_eScriptError" => "ScriptError", "rb_eNameError" => "NameError", "rb_eSyntaxError" => "SyntaxError", "rb_eLoadError" => "LoadError", "rb_mKernel" => "Kernel", "rb_mComparable" => "Comparable", "rb_mEnumerable" => "Enumerable", "rb_mPrecision" => "Precision", "rb_mErrno" => "Errno", "rb_mFileTest" => "FileTest", "rb_mGC" => "GC", "rb_mMath" => "Math", "rb_mProcess" => "Process" } ## # We attempt to parse C extension files. Basically we look for # the standard patterns that you find in extensions: rb_define_class, # rb_define_method and so on. We also try to find the corresponding # C source for the methods and extract comments, but if we fail # we don't worry too much. # # The comments associated with a Ruby method are extracted from the C # comment block associated with the routine that _implements_ that # method, that is to say the method whose name is given in the # rb_define_method call. For example, you might write: # # /* # * Returns a new array that is a one-dimensional flattening of this # * array (recursively). That is, for every element that is an array, # * extract its elements into the new array. # * # * s = [ 1, 2, 3 ] #=> [1, 2, 3] # * t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]] # * a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10] # * a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # */ # static VALUE # rb_ary_flatten(ary) # VALUE ary; # { # ary = rb_obj_dup(ary); # rb_ary_flatten_bang(ary); # return ary; # } # # ... # # void # Init_Array() # { # ... # rb_define_method(rb_cArray, "flatten", rb_ary_flatten, 0); # # Here RDoc will determine from the rb_define_method line that there's a # method called "flatten" in class Array, and will look for the implementation # in the method rb_ary_flatten. It will then use the comment from that # method in the HTML output. This method must be in the same source file # as the rb_define_method. # # C classes can be diagrammed (see /tc/dl/ruby/ruby/error.c), and RDoc # integrates C and Ruby source into one tree # # The comment blocks may include special directives: # # [Document-class: name] # This comment block is documentation for the given class. Use this # when the Init_xxx method is not named after the class. # # [Document-method: name] # This comment documents the named method. Use when RDoc cannot # automatically find the method from it's declaration # # [call-seq: text up to an empty line] # Because C source doesn't give descriptive names to Ruby-level parameters, # you need to document the calling sequence explicitly # # In addition, RDoc assumes by default that the C method implementing a # Ruby function is in the same source file as the rb_define_method call. # If this isn't the case, add the comment # # rb_define_method(....); // in: filename # # As an example, we might have an extension that defines multiple classes # in its Init_xxx method. We could document them using # # # /* # * Document-class: MyClass # * # * Encapsulate the writing and reading of the configuration # * file. ... # */ # # /* # * Document-method: read_value # * # * call-seq: # * cfg.read_value(key) -> value # * cfg.read_value(key} { |key| } -> value # * # * Return the value corresponding to +key+ from the configuration. # * In the second form, if the key isn't found, invoke the # * block and return its value. # */ # class C_Parser attr_accessor :progress extend ParserFactory parse_files_matching(/\.(?:([CcHh])\1?|c([+xp])\2|y)\z/) @@known_bodies = {} # prepare to parse a C file def initialize(top_level, file_name, body, options, stats) @known_classes = KNOWN_CLASSES.dup @body = handle_tab_width(handle_ifdefs_in(body)) @options = options @stats = stats @top_level = top_level @classes = Hash.new @file_dir = File.dirname(file_name) @progress = $stderr unless options.quiet end # Extract the classes/modules and methods from a C file # and return the corresponding top-level object def scan remove_commented_out_lines do_classes do_constants do_methods do_includes do_aliases @top_level end ####### private ####### def progress(char) unless @options.quiet @progress.print(char) @progress.flush end end def warn(msg) $stderr.puts $stderr.puts msg $stderr.flush end def remove_private_comments(comment) comment.gsub!(/\/?\*--(.*?)\/?\*\+\+/m, '') comment.sub!(/\/?\*--.*/m, '') end ## # removes lines that are commented out that might otherwise get picked up # when scanning for classes and methods def remove_commented_out_lines @body.gsub!(%r{//.*rb_define_}, '//') end def handle_class_module(var_name, class_mod, class_name, parent, in_module) progress(class_mod[0, 1]) parent_name = @known_classes[parent] || parent if in_module enclosure = @classes[in_module] unless enclosure if enclosure = @known_classes[in_module] handle_class_module(in_module, (/^rb_m/ =~ in_module ? "module" : "class"), enclosure, nil, nil) enclosure = @classes[in_module] end end unless enclosure warn("Enclosing class/module '#{in_module}' for " + "#{class_mod} #{class_name} not known") return end else enclosure = @top_level end if class_mod == "class" cm = enclosure.add_class(NormalClass, class_name, parent_name) @stats.num_classes += 1 else cm = enclosure.add_module(NormalModule, class_name) @stats.num_modules += 1 end cm.record_location(enclosure.toplevel) find_class_comment(cm.full_name, cm) @classes[var_name] = cm @known_classes[var_name] = cm.full_name end ## # Look for class or module documentation above Init_+class_name+(void), # in a Document-class +class_name+ (or module) comment or above an # rb_define_class (or module). If a comment is supplied above a matching # Init_ and a rb_define_class the Init_ comment is used. # # /* # * This is a comment for Foo # */ # Init_Foo(void) { # VALUE cFoo = rb_define_class("Foo", rb_cObject); # } # # /* # * Document-class: Foo # * This is a comment for Foo # */ # Init_foo(void) { # VALUE cFoo = rb_define_class("Foo", rb_cObject); # } # # /* # * This is a comment for Foo # */ # VALUE cFoo = rb_define_class("Foo", rb_cObject); def find_class_comment(class_name, class_meth) comment = nil if @body =~ %r{((?>/\*.*?\*/\s+)) (static\s+)?void\s+Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)?\)}xmi comment = $1 elsif @body =~ %r{Document-(class|module):\s#{class_name}\s*?\n((?>.*?\*/))}m comment = $2 else if @body =~ /rb_define_(class|module)/m then class_name = class_name.split("::").last comments = [] @body.split(/(\/\*.*?\*\/)\s*?\n/m).each_with_index do |chunk, index| comments[index] = chunk if chunk =~ /rb_define_(class|module).*?"(#{class_name})"/m then comment = comments[index-1] break end end end end class_meth.comment = mangle_comment(comment) if comment end ############################################################ def do_classes @body.scan(/(\w+)\s* = \s*rb_define_module\s*\(\s*"(\w+)"\s*\)/mx) do |var_name, class_name| handle_class_module(var_name, "module", class_name, nil, nil) end # The '.' lets us handle SWIG-generated files @body.scan(/([\w\.]+)\s* = \s*rb_define_class\s* \( \s*"(\w+)", \s*(\w+)\s* \)/mx) do |var_name, class_name, parent| handle_class_module(var_name, "class", class_name, parent, nil) end @body.scan(/(\w+)\s*=\s*boot_defclass\s*\(\s*"(\w+?)",\s*(\w+?)\s*\)/) do |var_name, class_name, parent| parent = nil if parent == "0" handle_class_module(var_name, "class", class_name, parent, nil) end @body.scan(/(\w+)\s* = \s*rb_define_module_under\s* \( \s*(\w+), \s*"(\w+)" \s*\)/mx) do |var_name, in_module, class_name| handle_class_module(var_name, "module", class_name, nil, in_module) end @body.scan(/([\w\.]+)\s* = \s*rb_define_class_under\s* \( \s*(\w+), \s*"(\w+)", \s*(\w+)\s* \s*\)/mx) do |var_name, in_module, class_name, parent| handle_class_module(var_name, "class", class_name, parent, in_module) end end ########################################################### def do_constants @body.scan(%r{\Wrb_define_ ( variable | readonly_variable | const | global_const | ) \s*\( (?:\s*(\w+),)? \s*"(\w+)", \s*(.*?)\s*\)\s*; }xm) do |type, var_name, const_name, definition| var_name = "rb_cObject" if !var_name or var_name == "rb_mKernel" handle_constants(type, var_name, const_name, definition) end end ############################################################ def do_methods @body.scan(%r{rb_define_ ( singleton_method | method | module_function | private_method ) \s*\(\s*([\w\.]+), \s*"([^"]+)", \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?, \s*(-?\w+)\s*\) (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))? }xm) do |type, var_name, meth_name, meth_body, param_count, source_file| #" # Ignore top-object and weird struct.c dynamic stuff next if var_name == "ruby_top_self" next if var_name == "nstr" next if var_name == "envtbl" next if var_name == "argf" # it'd be nice to handle this one var_name = "rb_cObject" if var_name == "rb_mKernel" handle_method(type, var_name, meth_name, meth_body, param_count, source_file) end @body.scan(%r{rb_define_attr\( \s*([\w\.]+), \s*"([^"]+)", \s*(\d+), \s*(\d+)\s*\); }xm) do #" |var_name, attr_name, attr_reader, attr_writer| #var_name = "rb_cObject" if var_name == "rb_mKernel" handle_attr(var_name, attr_name, attr_reader.to_i != 0, attr_writer.to_i != 0) end @body.scan(%r{rb_define_global_function\s*\( \s*"([^"]+)", \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?, \s*(-?\w+)\s*\) (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))? }xm) do #" |meth_name, meth_body, param_count, source_file| handle_method("method", "rb_mKernel", meth_name, meth_body, param_count, source_file) end @body.scan(/define_filetest_function\s*\( \s*"([^"]+)", \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?, \s*(-?\w+)\s*\)/xm) do #" |meth_name, meth_body, param_count| handle_method("method", "rb_mFileTest", meth_name, meth_body, param_count) handle_method("singleton_method", "rb_cFile", meth_name, meth_body, param_count) end end ############################################################ def do_aliases @body.scan(%r{rb_define_alias\s*\(\s*(\w+),\s*"([^"]+)",\s*"([^"]+)"\s*\)}m) do |var_name, new_name, old_name| @stats.num_methods += 1 class_name = @known_classes[var_name] || var_name class_obj = find_class(var_name, class_name) class_obj.add_alias(Alias.new("", old_name, new_name, "")) end end ## # Adds constant comments. By providing some_value: at the start ofthe # comment you can override the C value of the comment to give a friendly # definition. # # /* 300: The perfect score in bowling */ # rb_define_const(cFoo, "PERFECT", INT2FIX(300); # # Will override +INT2FIX(300)+ with the value +300+ in the output RDoc. # Values may include quotes and escaped colons (\:). def handle_constants(type, var_name, const_name, definition) #@stats.num_constants += 1 class_name = @known_classes[var_name] return unless class_name class_obj = find_class(var_name, class_name) unless class_obj warn("Enclosing class/module '#{const_name}' for not known") return end comment = find_const_comment(type, const_name) # In the case of rb_define_const, the definition and comment are in # "/* definition: comment */" form. The literal ':' and '\' characters # can be escaped with a backslash. if type.downcase == 'const' then elements = mangle_comment(comment).split(':') if elements.nil? or elements.empty? then con = Constant.new(const_name, definition, mangle_comment(comment)) else new_definition = elements[0..-2].join(':') if new_definition.empty? then # Default to literal C definition new_definition = definition else new_definition.gsub!("\:", ":") new_definition.gsub!("\\", '\\') end new_definition.sub!(/\A(\s+)/, '') new_comment = $1.nil? ? elements.last : "#{$1}#{elements.last.lstrip}" con = Constant.new(const_name, new_definition, mangle_comment(new_comment)) end else con = Constant.new(const_name, definition, mangle_comment(comment)) end class_obj.add_constant(con) end ## # Finds a comment matching +type+ and +const_name+ either above the # comment or in the matching Document- section. def find_const_comment(type, const_name) if @body =~ %r{((?>^\s*/\*.*?\*/\s+)) rb_define_#{type}\((?:\s*(\w+),)?\s*"#{const_name}"\s*,.*?\)\s*;}xmi $1 elsif @body =~ %r{Document-(?:const|global|variable):\s#{const_name}\s*?\n((?>.*?\*/))}m $1 else '' end end ########################################################### def handle_attr(var_name, attr_name, reader, writer) rw = '' if reader #@stats.num_methods += 1 rw << 'R' end if writer #@stats.num_methods += 1 rw << 'W' end class_name = @known_classes[var_name] return unless class_name class_obj = find_class(var_name, class_name) if class_obj comment = find_attr_comment(attr_name) unless comment.empty? comment = mangle_comment(comment) end att = Attr.new('', attr_name, rw, comment) class_obj.add_attribute(att) end end ########################################################### def find_attr_comment(attr_name) if @body =~ %r{((?>/\*.*?\*/\s+)) rb_define_attr\((?:\s*(\w+),)?\s*"#{attr_name}"\s*,.*?\)\s*;}xmi $1 elsif @body =~ %r{Document-attr:\s#{attr_name}\s*?\n((?>.*?\*/))}m $1 else '' end end ########################################################### def handle_method(type, var_name, meth_name, meth_body, param_count, source_file = nil) progress(".") @stats.num_methods += 1 class_name = @known_classes[var_name] return unless class_name class_obj = find_class(var_name, class_name) if class_obj if meth_name == "initialize" meth_name = "new" type = "singleton_method" end meth_obj = AnyMethod.new("", meth_name) meth_obj.singleton = %w{singleton_method module_function}.include?(type) p_count = (Integer(param_count) rescue -1) if p_count < 0 meth_obj.params = "(...)" elsif p_count == 0 meth_obj.params = "()" else meth_obj.params = "(" + (1..p_count).map{|i| "p#{i}"}.join(", ") + ")" end if source_file file_name = File.join(@file_dir, source_file) body = (@@known_bodies[source_file] ||= File.read(file_name)) else body = @body end if find_body(meth_body, meth_obj, body) and meth_obj.document_self class_obj.add_method(meth_obj) end end end ############################################################ # Find the C code corresponding to a Ruby method def find_body(meth_name, meth_obj, body, quiet = false) case body when %r{((?>/\*.*?\*/\s*))(?:static\s+)?VALUE\s+#{meth_name} \s*(\(.*?\)).*?^}xm comment, params = $1, $2 body_text = $& remove_private_comments(comment) if comment # see if we can find the whole body re = Regexp.escape(body_text) + '[^(]*^\{.*?^\}' if Regexp.new(re, Regexp::MULTILINE).match(body) body_text = $& end # The comment block may have been overridden with a # 'Document-method' block. This happens in the interpreter # when multiple methods are vectored through to the same # C method but those methods are logically distinct (for # example Kernel.hash and Kernel.object_id share the same # implementation override_comment = find_override_comment(meth_obj.name) comment = override_comment if override_comment find_modifiers(comment, meth_obj) if comment # meth_obj.params = params meth_obj.start_collecting_tokens meth_obj.add_token(RubyToken::Token.new(1,1).set_text(body_text)) meth_obj.comment = mangle_comment(comment) when %r{((?>/\*.*?\*/\s*))^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m comment = $1 find_body($2, meth_obj, body, true) find_modifiers(comment, meth_obj) meth_obj.comment = mangle_comment(comment) + meth_obj.comment when %r{^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m unless find_body($1, meth_obj, body, true) warn "No definition for #{meth_name}" unless quiet return false end else # No body, but might still have an override comment comment = find_override_comment(meth_obj.name) if comment find_modifiers(comment, meth_obj) meth_obj.comment = mangle_comment(comment) else warn "No definition for #{meth_name}" unless quiet return false end end true end ## # If the comment block contains a section that looks like: # # call-seq: # Array.new # Array.new(10) # # use it for the parameters. def find_modifiers(comment, meth_obj) if comment.sub!(/:nodoc:\s*^\s*\*?\s*$/m, '') or comment.sub!(/\A\/\*\s*:nodoc:\s*\*\/\Z/, '') meth_obj.document_self = false end if comment.sub!(/call-seq:(.*?)^\s*\*?\s*$/m, '') or comment.sub!(/\A\/\*\s*call-seq:(.*?)\*\/\Z/, '') seq = $1 seq.gsub!(/^\s*\*\s*/, '') meth_obj.call_seq = seq end end ############################################################ def find_override_comment(meth_name) name = Regexp.escape(meth_name) if @body =~ %r{Document-method:\s#{name}\s*?\n((?>.*?\*/))}m $1 end end ## # Look for includes of the form: # # rb_include_module(rb_cArray, rb_mEnumerable); def do_includes @body.scan(/rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/) do |c,m| if cls = @classes[c] m = @known_classes[m] || m cls.add_include(Include.new(m, "")) end end end ## # Remove the /*'s and leading asterisks from C comments def mangle_comment(comment) comment.sub!(%r{/\*+}) { " " * $&.length } comment.sub!(%r{\*+/}) { " " * $&.length } comment.gsub!(/^[ \t]*\*/m) { " " * $&.length } comment end def find_class(raw_name, name) unless @classes[raw_name] if raw_name =~ /^rb_m/ @classes[raw_name] = @top_level.add_module(NormalModule, name) else @classes[raw_name] = @top_level.add_class(NormalClass, name, nil) end end @classes[raw_name] end def handle_tab_width(body) if /\t/ =~ body tab_width = Options.instance.tab_width body.split(/\n/).map do |line| 1 while line.gsub!(/\t+/) { ' ' * (tab_width*$&.length - $`.length % tab_width)} && $~ #` line end .join("\n") else body end end ## # Removes #ifdefs that would otherwise confuse us def handle_ifdefs_in(body) body.gsub(/^#ifdef HAVE_PROTOTYPES.*?#else.*?\n(.*?)#endif.*?\n/m) { $1 } end end end ================================================ FILE: lib/rdoc/parsers/parse_f95.rb ================================================ #= parse_f95.rb - Fortran95 Parser # #== Overview # #"parse_f95.rb" parses Fortran95 files with suffixes "f90", "F90", "f95" #and "F95". Fortran95 files are expected to be conformed to Fortran95 #standards. # #== Rules # #Fundamental rules are same as that of the Ruby parser. #But comment markers are '!' not '#'. # #=== Correspondence between RDoc documentation and Fortran95 programs # #"parse_f95.rb" parses main programs, modules, subroutines, functions, #derived-types, public variables, public constants, #defined operators and defined assignments. #These components are described in items of RDoc documentation, as follows. # #Files :: Files (same as Ruby) #Classes :: Modules #Methods :: Subroutines, functions, variables, constants, derived-types, defined operators, defined assignments #Required files :: Files in which imported modules, external subroutines and external functions are defined. #Included Modules :: List of imported modules #Attributes :: List of derived-types, List of imported modules all of whose components are published again # #Components listed in 'Methods' (subroutines, functions, ...) #defined in modules are described in the item of 'Classes'. #On the other hand, components defined in main programs or #as external procedures are described in the item of 'Files'. # #=== Components parsed by default # #By default, documentation on public components (subroutines, functions, #variables, constants, derived-types, defined operators, #defined assignments) are generated. #With "--all" option, documentation on all components #are generated (almost same as the Ruby parser). # #=== Information parsed automatically # #The following information is automatically parsed. # #* Types of arguments #* Types of variables and constants #* Types of variables in the derived types, and initial values #* NAMELISTs and types of variables in them, and initial values # #Aliases by interface statement are described in the item of 'Methods'. # #Components which are imported from other modules and published again #are described in the item of 'Methods'. # #=== Format of comment blocks # #Comment blocks should be written as follows. #Comment blocks are considered to be ended when the line without '!' #appears. #The indentation is not necessary. # # ! (Top of file) # ! # ! Comment blocks for the files. # ! # !-- # ! The comment described in the part enclosed by # ! "!--" and "!++" is ignored. # !++ # ! # module hogehoge # ! # ! Comment blocks for the modules (or the programs). # ! # # private # # logical :: a ! a private variable # real, public :: b ! a public variable # integer, parameter :: c = 0 ! a public constant # # public :: c # public :: MULTI_ARRAY # public :: hoge, foo # # type MULTI_ARRAY # ! # ! Comment blocks for the derived-types. # ! # real, pointer :: var(:) =>null() ! Comments block for the variables. # integer :: num = 0 # end type MULTI_ARRAY # # contains # # subroutine hoge( in, & ! Comment blocks between continuation lines are ignored. # & out ) # ! # ! Comment blocks for the subroutines or functions # ! # character(*),intent(in):: in ! Comment blocks for the arguments. # character(*),intent(out),allocatable,target :: in # ! Comment blocks can be # ! written under Fortran statements. # # character(32) :: file ! This comment parsed as a variable in below NAMELIST. # integer :: id # # namelist /varinfo_nml/ file, id # ! # ! Comment blocks for the NAMELISTs. # ! Information about variables are described above. # ! # # .... # # end subroutine hoge # # integer function foo( in ) # ! # ! This part is considered as comment block. # # ! Comment blocks under blank lines are ignored. # ! # integer, intent(in):: inA ! This part is considered as comment block. # # ! This part is ignored. # # end function foo # # subroutine hide( in, & # & out ) !:nodoc: # ! # ! If "!:nodoc:" is described at end-of-line in subroutine # ! statement as above, the subroutine is ignored. # ! This assignment can be used to modules, subroutines, # ! functions, variables, constants, derived-types, # ! defined operators, defined assignments, # ! list of imported modules ("use" statement). # ! # # .... # # end subroutine hide # # end module hogehoge # require "rdoc/code_objects" module RDoc class Token NO_TEXT = "??".freeze def initialize(line_no, char_no) @line_no = line_no @char_no = char_no @text = NO_TEXT end # Because we're used in contexts that expect to return a token, # we set the text string and then return ourselves def set_text(text) @text = text self end attr_reader :line_no, :char_no, :text end # See rdoc/parsers/parse_f95.rb class Fortran95parser extend ParserFactory parse_files_matching(/\.((f|F)9(0|5)|F)$/) @@external_aliases = [] @@public_methods = [] # "false":: Comments are below source code # "true" :: Comments are upper source code COMMENTS_ARE_UPPER = false # Internal alias message INTERNAL_ALIAS_MES = "Alias for" # External alias message EXTERNAL_ALIAS_MES = "The entity is" # prepare to parse a Fortran 95 file def initialize(top_level, file_name, body, options, stats) @body = body @stats = stats @file_name = file_name @options = options @top_level = top_level @progress = $stderr unless options.quiet end # define code constructs def scan # remove private comment remaining_code = remove_private_comments(@body) # continuation lines are united to one line remaining_code = united_to_one_line(remaining_code) # semicolons are replaced to line feed remaining_code = semicolon_to_linefeed(remaining_code) # collect comment for file entity whole_comment, remaining_code = collect_first_comment(remaining_code) @top_level.comment = whole_comment # String "remaining_code" is converted to Array "remaining_lines" remaining_lines = remaining_code.split("\n") # "module" or "program" parts are parsed (new) # level_depth = 0 block_searching_flag = nil block_searching_lines = [] pre_comment = [] module_program_trailing = "" module_program_name = "" other_block_level_depth = 0 other_block_searching_flag = nil remaining_lines.collect!{|line| if !block_searching_flag && !other_block_searching_flag if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i block_searching_flag = :module block_searching_lines << line module_program_name = $1 module_program_trailing = find_comments($2) next false elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i || line =~ /^\s*?\w/ && !block_start?(line) block_searching_flag = :program block_searching_lines << line module_program_name = $1 || "" module_program_trailing = find_comments($2) next false elsif block_start?(line) other_block_searching_flag = true next line elsif line =~ /^\s*?!\s?(.*)/ pre_comment << line next line else pre_comment = [] next line end elsif other_block_searching_flag other_block_level_depth += 1 if block_start?(line) other_block_level_depth -= 1 if block_end?(line) if other_block_level_depth < 0 other_block_level_depth = 0 other_block_searching_flag = nil end next line end block_searching_lines << line level_depth += 1 if block_start?(line) level_depth -= 1 if block_end?(line) if level_depth >= 0 next false end # "module_program_code" is formatted. # ":nodoc:" flag is checked. # module_program_code = block_searching_lines.join("\n") module_program_code = remove_empty_head_lines(module_program_code) if module_program_trailing =~ /^:nodoc:/ # next loop to search next block level_depth = 0 block_searching_flag = false block_searching_lines = [] pre_comment = [] next false end # NormalClass is created, and added to @top_level # if block_searching_flag == :module module_name = module_program_name module_code = module_program_code module_trailing = module_program_trailing progress "m" @stats.num_modules += 1 f9x_module = @top_level.add_module NormalClass, module_name f9x_module.record_location @top_level f9x_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) + "\n" + module_trailing : module_trailing + "\n" + find_comments(module_code.sub(/^.*$\n/i, '')) f9x_module.comment = f9x_comment parse_program_or_module(f9x_module, module_code) TopLevel.all_files.each do |name, toplevel| if toplevel.include_includes?(module_name, @options.ignore_case) if !toplevel.include_requires?(@file_name, @options.ignore_case) toplevel.add_require(Require.new(@file_name, "")) end end toplevel.each_classmodule{|m| if m.include_includes?(module_name, @options.ignore_case) if !m.include_requires?(@file_name, @options.ignore_case) m.add_require(Require.new(@file_name, "")) end end } end elsif block_searching_flag == :program program_name = module_program_name program_code = module_program_code program_trailing = module_program_trailing progress "p" program_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) + "\n" + program_trailing : program_trailing + "\n" + find_comments(program_code.sub(/^.*$\n/i, '')) program_comment = "\n\n= Program #{program_name}\n\n" \ + program_comment @top_level.comment << program_comment parse_program_or_module(@top_level, program_code, :private) end # next loop to search next block level_depth = 0 block_searching_flag = false block_searching_lines = [] pre_comment = [] next false } remaining_lines.delete_if{ |line| line == false } # External subprograms and functions are parsed # parse_program_or_module(@top_level, remaining_lines.join("\n"), :public, true) @top_level end # End of scan private def parse_program_or_module(container, code, visibility=:public, external=nil) return unless container return unless code remaining_lines = code.split("\n") remaining_code = "#{code}" # # Parse variables before "contains" in module # level_depth = 0 before_contains_lines = [] before_contains_code = nil before_contains_flag = nil remaining_lines.each{ |line| if !before_contains_flag if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i before_contains_flag = true end else break if line =~ /^\s*?contains\s*?(!.*?)?$/i level_depth += 1 if block_start?(line) level_depth -= 1 if block_end?(line) break if level_depth < 0 before_contains_lines << line end } before_contains_code = before_contains_lines.join("\n") if before_contains_code before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "") before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "") end # # Parse global "use" # use_check_code = "#{before_contains_code}" cascaded_modules_list = [] while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i use_check_code = $~.pre_match use_check_code << $~.post_match used_mod_name = $1.strip.chomp used_list = $2 || "" used_trailing = $3 || "" next if used_trailing =~ /!:nodoc:/ if !container.include_includes?(used_mod_name, @options.ignore_case) progress "." container.add_include Include.new(used_mod_name, "") end if ! (used_list =~ /\,\s*?only\s*?:/i ) cascaded_modules_list << "\#" + used_mod_name end end # # Parse public and private, and store information. # This information is used when "add_method" and # "set_visibility_for" are called. # visibility_default, visibility_info = parse_visibility(remaining_lines.join("\n"), visibility, container) @@public_methods.concat visibility_info if visibility_default == :public if !cascaded_modules_list.empty? cascaded_modules = Attr.new("Cascaded Modules", "Imported modules all of whose components are published again", "", cascaded_modules_list.join(", ")) container.add_attribute(cascaded_modules) end end # # Check rename elements # use_check_code = "#{before_contains_code}" while use_check_code =~ /^\s*?use\s+(\w+)\s*?\,(.+)$/i use_check_code = $~.pre_match use_check_code << $~.post_match used_mod_name = $1.strip.chomp used_elements = $2.sub(/\s*?only\s*?:\s*?/i, '') used_elements.split(",").each{ |used| if /\s*?(\w+)\s*?=>\s*?(\w+)\s*?/ =~ used local = $1 org = $2 @@public_methods.collect!{ |pub_meth| if local == pub_meth["name"] || local.upcase == pub_meth["name"].upcase && @options.ignore_case pub_meth["name"] = org pub_meth["local_name"] = local end pub_meth } end } end # # Parse private "use" # use_check_code = remaining_lines.join("\n") while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i use_check_code = $~.pre_match use_check_code << $~.post_match used_mod_name = $1.strip.chomp used_trailing = $3 || "" next if used_trailing =~ /!:nodoc:/ if !container.include_includes?(used_mod_name, @options.ignore_case) progress "." container.add_include Include.new(used_mod_name, "") end end container.each_includes{ |inc| TopLevel.all_files.each do |name, toplevel| indicated_mod = toplevel.find_symbol(inc.name, nil, @options.ignore_case) if indicated_mod indicated_name = indicated_mod.parent.file_relative_name if !container.include_requires?(indicated_name, @options.ignore_case) container.add_require(Require.new(indicated_name, "")) end break end end } # # Parse derived-types definitions # derived_types_comment = "" remaining_code = remaining_lines.join("\n") while remaining_code =~ /^\s*? type[\s\,]+(public|private)?\s*?(::)?\s*? (\w+)\s*?(!.*?)?$ (.*?) ^\s*?end\s+type.*?$ /imx remaining_code = $~.pre_match remaining_code << $~.post_match typename = $3.chomp.strip type_elements = $5 || "" type_code = remove_empty_head_lines($&) type_trailing = find_comments($4) next if type_trailing =~ /^:nodoc:/ type_visibility = $1 type_comment = COMMENTS_ARE_UPPER ? find_comments($~.pre_match) + "\n" + type_trailing : type_trailing + "\n" + find_comments(type_code.sub(/^.*$\n/i, '')) type_element_visibility_public = true type_code.split("\n").each{ |line| if /^\s*?private\s*?$/ =~ line type_element_visibility_public = nil break end } if type_code args_comment = "" type_args_info = nil if @options.show_all args_comment = find_arguments(nil, type_code, true) else type_public_args_list = [] type_args_info = definition_info(type_code) type_args_info.each{ |arg| arg_is_public = type_element_visibility_public arg_is_public = true if arg.include_attr?("public") arg_is_public = nil if arg.include_attr?("private") type_public_args_list << arg.varname if arg_is_public } args_comment = find_arguments(type_public_args_list, type_code) end type = AnyMethod.new("type #{typename}", typename) type.singleton = false type.params = "" type.comment = " Derived Type :: \n" type.comment << args_comment if args_comment type.comment << type_comment if type_comment progress "t" @stats.num_methods += 1 container.add_method type set_visibility(container, typename, visibility_default, @@public_methods) if type_visibility type_visibility.gsub!(/\s/,'') type_visibility.gsub!(/\,/,'') type_visibility.gsub!(/:/,'') type_visibility.downcase! if type_visibility == "public" container.set_visibility_for([typename], :public) elsif type_visibility == "private" container.set_visibility_for([typename], :private) end end check_public_methods(type, container.name) if @options.show_all derived_types_comment << ", " unless derived_types_comment.empty? derived_types_comment << typename else if type.visibility == :public derived_types_comment << ", " unless derived_types_comment.empty? derived_types_comment << typename end end end if !derived_types_comment.empty? derived_types_table = Attr.new("Derived Types", "Derived_Types", "", derived_types_comment) container.add_attribute(derived_types_table) end # # move interface scope # interface_code = "" while remaining_code =~ /^\s*? interface( \s+\w+ | \s+operator\s*?\(.*?\) | \s+assignment\s*?\(\s*?=\s*?\) )?\s*?$ (.*?) ^\s*?end\s+interface.*?$ /imx interface_code << remove_empty_head_lines($&) + "\n" remaining_code = $~.pre_match remaining_code << $~.post_match end # # Parse global constants or variables in modules # const_var_defs = definition_info(before_contains_code) const_var_defs.each{|defitem| next if defitem.nodoc const_or_var_type = "Variable" const_or_var_progress = "v" if defitem.include_attr?("parameter") const_or_var_type = "Constant" const_or_var_progress = "c" end const_or_var = AnyMethod.new(const_or_var_type, defitem.varname) const_or_var.singleton = false const_or_var.params = "" self_comment = find_arguments([defitem.varname], before_contains_code) const_or_var.comment = "" + const_or_var_type + " :: \n" const_or_var.comment << self_comment if self_comment progress const_or_var_progress @stats.num_methods += 1 container.add_method const_or_var set_visibility(container, defitem.varname, visibility_default, @@public_methods) if defitem.include_attr?("public") container.set_visibility_for([defitem.varname], :public) elsif defitem.include_attr?("private") container.set_visibility_for([defitem.varname], :private) end check_public_methods(const_or_var, container.name) } if const_var_defs remaining_lines = remaining_code.split("\n") # "subroutine" or "function" parts are parsed (new) # level_depth = 0 block_searching_flag = nil block_searching_lines = [] pre_comment = [] procedure_trailing = "" procedure_name = "" procedure_params = "" procedure_prefix = "" procedure_result_arg = "" procedure_type = "" contains_lines = [] contains_flag = nil remaining_lines.collect!{|line| if !block_searching_flag # subroutine if line =~ /^\s*? (recursive|pure|elemental)?\s*? subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ /ix block_searching_flag = :subroutine block_searching_lines << line procedure_name = $2.chomp.strip procedure_params = $3 || "" procedure_prefix = $1 || "" procedure_trailing = $4 || "!" next false # function elsif line =~ /^\s*? (recursive|pure|elemental)?\s*? ( character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | type\s*?\([\w\s]+?\)\s+ | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | double\s+precision\s+ | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ )? function\s+(\w+)\s*? (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ /ix block_searching_flag = :function block_searching_lines << line procedure_prefix = $1 || "" procedure_type = $2 ? $2.chomp.strip : nil procedure_name = $8.chomp.strip procedure_params = $9 || "" procedure_result_arg = $11 ? $11.chomp.strip : procedure_name procedure_trailing = $12 || "!" next false elsif line =~ /^\s*?!\s?(.*)/ pre_comment << line next line else pre_comment = [] next line end end contains_flag = true if line =~ /^\s*?contains\s*?(!.*?)?$/ block_searching_lines << line contains_lines << line if contains_flag level_depth += 1 if block_start?(line) level_depth -= 1 if block_end?(line) if level_depth >= 0 next false end # "procedure_code" is formatted. # ":nodoc:" flag is checked. # procedure_code = block_searching_lines.join("\n") procedure_code = remove_empty_head_lines(procedure_code) if procedure_trailing =~ /^!:nodoc:/ # next loop to search next block level_depth = 0 block_searching_flag = nil block_searching_lines = [] pre_comment = [] procedure_trailing = "" procedure_name = "" procedure_params = "" procedure_prefix = "" procedure_result_arg = "" procedure_type = "" contains_lines = [] contains_flag = nil next false end # AnyMethod is created, and added to container # subroutine_function = nil if block_searching_flag == :subroutine subroutine_prefix = procedure_prefix subroutine_name = procedure_name subroutine_params = procedure_params subroutine_trailing = procedure_trailing subroutine_code = procedure_code subroutine_comment = COMMENTS_ARE_UPPER ? pre_comment.join("\n") + "\n" + subroutine_trailing : subroutine_trailing + "\n" + subroutine_code.sub(/^.*$\n/i, '') subroutine = AnyMethod.new("subroutine", subroutine_name) parse_subprogram(subroutine, subroutine_params, subroutine_comment, subroutine_code, before_contains_code, nil, subroutine_prefix) progress "s" @stats.num_methods += 1 container.add_method subroutine subroutine_function = subroutine elsif block_searching_flag == :function function_prefix = procedure_prefix function_type = procedure_type function_name = procedure_name function_params_org = procedure_params function_result_arg = procedure_result_arg function_trailing = procedure_trailing function_code_org = procedure_code function_comment = COMMENTS_ARE_UPPER ? pre_comment.join("\n") + "\n" + function_trailing : function_trailing + "\n " + function_code_org.sub(/^.*$\n/i, '') function_code = "#{function_code_org}" if function_type function_code << "\n" + function_type + " :: " + function_result_arg end function_params = function_params_org.sub(/^\(/, "\(#{function_result_arg}, ") function = AnyMethod.new("function", function_name) parse_subprogram(function, function_params, function_comment, function_code, before_contains_code, true, function_prefix) # Specific modification due to function function.params.sub!(/\(\s*?#{function_result_arg}\s*?,\s*?/, "\( ") function.params << " result(" + function_result_arg + ")" function.start_collecting_tokens function.add_token Token.new(1,1).set_text(function_code_org) progress "f" @stats.num_methods += 1 container.add_method function subroutine_function = function end # The visibility of procedure is specified # set_visibility(container, procedure_name, visibility_default, @@public_methods) # The alias for this procedure from external modules # check_external_aliases(procedure_name, subroutine_function.params, subroutine_function.comment, subroutine_function) if external check_public_methods(subroutine_function, container.name) # contains_lines are parsed as private procedures if contains_flag parse_program_or_module(container, contains_lines.join("\n"), :private) end # next loop to search next block level_depth = 0 block_searching_flag = nil block_searching_lines = [] pre_comment = [] procedure_trailing = "" procedure_name = "" procedure_params = "" procedure_prefix = "" procedure_result_arg = "" contains_lines = [] contains_flag = nil next false } # End of remaining_lines.collect!{|line| # Array remains_lines is converted to String remains_code again # remaining_code = remaining_lines.join("\n") # # Parse interface # interface_scope = false generic_name = "" interface_code.split("\n").each{ |line| if /^\s*? interface( \s+\w+| \s+operator\s*?\(.*?\)| \s+assignment\s*?\(\s*?=\s*?\) )? \s*?(!.*?)?$ /ix =~ line generic_name = $1 ? $1.strip.chomp : nil interface_trailing = $2 || "!" interface_scope = true interface_scope = false if interface_trailing =~ /!:nodoc:/ # if generic_name =~ /operator\s*?\((.*?)\)/i # operator_name = $1 # if operator_name && !operator_name.empty? # generic_name = "#{operator_name}" # end # end # if generic_name =~ /assignment\s*?\((.*?)\)/i # assignment_name = $1 # if assignment_name && !assignment_name.empty? # generic_name = "#{assignment_name}" # end # end end if /^\s*?end\s+interface/i =~ line interface_scope = false generic_name = nil end # internal alias if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line procedures = $1.strip.chomp procedures_trailing = $2 || "!" next if procedures_trailing =~ /!:nodoc:/ procedures.split(",").each{ |proc| proc.strip! proc.chomp! next if generic_name == proc || !generic_name old_meth = container.find_symbol(proc, nil, @options.ignore_case) next if !old_meth nolink = old_meth.visibility == :private ? true : nil nolink = nil if @options.show_all new_meth = initialize_external_method(generic_name, proc, old_meth.params, nil, old_meth.comment, old_meth.clone.token_stream[0].text, true, nolink) new_meth.singleton = old_meth.singleton progress "i" @stats.num_methods += 1 container.add_method new_meth set_visibility(container, generic_name, visibility_default, @@public_methods) check_public_methods(new_meth, container.name) } end # external aliases if interface_scope # subroutine proc = nil params = nil procedures_trailing = nil if line =~ /^\s*? (recursive|pure|elemental)?\s*? subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ /ix proc = $2.chomp.strip generic_name = proc unless generic_name params = $3 || "" procedures_trailing = $4 || "!" # function elsif line =~ /^\s*? (recursive|pure|elemental)?\s*? ( character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | type\s*?\([\w\s]+?\)\s+ | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | double\s+precision\s+ | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ )? function\s+(\w+)\s*? (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ /ix proc = $8.chomp.strip generic_name = proc unless generic_name params = $9 || "" procedures_trailing = $12 || "!" else next end next if procedures_trailing =~ /!:nodoc:/ indicated_method = nil indicated_file = nil TopLevel.all_files.each do |name, toplevel| indicated_method = toplevel.find_local_symbol(proc, @options.ignore_case) indicated_file = name break if indicated_method end if indicated_method external_method = initialize_external_method(generic_name, proc, indicated_method.params, indicated_file, indicated_method.comment) progress "e" @stats.num_methods += 1 container.add_method external_method set_visibility(container, generic_name, visibility_default, @@public_methods) if !container.include_requires?(indicated_file, @options.ignore_case) container.add_require(Require.new(indicated_file, "")) end check_public_methods(external_method, container.name) else @@external_aliases << { "new_name" => generic_name, "old_name" => proc, "file_or_module" => container, "visibility" => find_visibility(container, generic_name, @@public_methods) || visibility_default } end end } if interface_code # End of interface_code.split("\n").each ... # # Already imported methods are removed from @@public_methods. # Remainders are assumed to be imported from other modules. # @@public_methods.delete_if{ |method| method["entity_is_discovered"]} @@public_methods.each{ |pub_meth| next unless pub_meth["file_or_module"].name == container.name pub_meth["used_modules"].each{ |used_mod| TopLevel.all_classes_and_modules.each{ |modules| if modules.name == used_mod || modules.name.upcase == used_mod.upcase && @options.ignore_case modules.method_list.each{ |meth| if meth.name == pub_meth["name"] || meth.name.upcase == pub_meth["name"].upcase && @options.ignore_case new_meth = initialize_public_method(meth, modules.name) if pub_meth["local_name"] new_meth.name = pub_meth["local_name"] end progress "e" @stats.num_methods += 1 container.add_method new_meth end } end } } } container end # End of parse_program_or_module # # Parse arguments, comment, code of subroutine and function. # Return AnyMethod object. # def parse_subprogram(subprogram, params, comment, code, before_contains=nil, function=nil, prefix=nil) subprogram.singleton = false prefix = "" if !prefix arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params args_comment, params_opt = find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""), nil, nil, true) params_opt = "( " + params_opt + " ) " if params_opt subprogram.params = params_opt || "" namelist_comment = find_namelists(code, before_contains) block_comment = find_comments comment if function subprogram.comment = " Function :: #{prefix}\n" else subprogram.comment = " Subroutine :: #{prefix}\n" end subprogram.comment << args_comment if args_comment subprogram.comment << block_comment if block_comment subprogram.comment << namelist_comment if namelist_comment # For output source code subprogram.start_collecting_tokens subprogram.add_token Token.new(1,1).set_text(code) subprogram end # # Collect comment for file entity # def collect_first_comment(body) comment = "" not_comment = "" comment_start = false comment_end = false body.split("\n").each{ |line| if comment_end not_comment << line not_comment << "\n" elsif /^\s*?!\s?(.*)$/i =~ line comment_start = true comment << $1 comment << "\n" elsif /^\s*?$/i =~ line comment_end = true if comment_start && COMMENTS_ARE_UPPER else comment_end = true not_comment << line not_comment << "\n" end } return comment, not_comment end # Return comments of definitions of arguments # # If "all" argument is true, information of all arguments are returned. # If "modified_params" is true, list of arguments are decorated, # for example, optional arguments are parenthetic as "[arg]". # def find_arguments(args, text, all=nil, indent=nil, modified_params=nil) return unless args || all indent = "" unless indent args = ["all"] if all params = "" if modified_params comma = "" return unless text args_rdocforms = "\n" remaining_lines = "#{text}" definitions = definition_info(remaining_lines) args.each{ |arg| arg.strip! arg.chomp! definitions.each { |defitem| if arg == defitem.varname.strip.chomp || all args_rdocforms << <<-"EOF" #{indent}#{defitem.varname.chomp.strip}#{defitem.arraysuffix} #{defitem.inivalue} :: #{indent} #{defitem.types.chomp.strip} EOF if !defitem.comment.chomp.strip.empty? comment = "" defitem.comment.split("\n").each{ |line| comment << " " + line + "\n" } args_rdocforms << <<-"EOF" #{indent} :: #{indent} #{indent} #{comment.chomp.strip} EOF end if modified_params if defitem.include_attr?("optional") params << "#{comma}[#{arg}]" else params << "#{comma}#{arg}" end comma = ", " end end } } if modified_params return args_rdocforms, params else return args_rdocforms end end # Return comments of definitions of namelists # def find_namelists(text, before_contains=nil) return nil if !text result = "" lines = "#{text}" before_contains = "" if !before_contains while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)$/i lines = $~.post_match nml_comment = COMMENTS_ARE_UPPER ? find_comments($~.pre_match) : find_comments($~.post_match) nml_name = $1 nml_args = $2.split(",") result << "\n\n=== NAMELIST " + nml_name + "\n\n" result << nml_comment + "\n" if nml_comment if lines.split("\n")[0] =~ /^\//i lines = "namelist " + lines end result << find_arguments(nml_args, "#{text}" + "\n" + before_contains) end return result end # # Comments just after module or subprogram, or arguments are # returned. If "COMMENTS_ARE_UPPER" is true, comments just before # modules or subprograms are returned # def find_comments text return "" unless text lines = text.split("\n") lines.reverse! if COMMENTS_ARE_UPPER comment_block = Array.new lines.each do |line| break if line =~ /^\s*?\w/ || line =~ /^\s*?$/ if COMMENTS_ARE_UPPER comment_block.unshift line.sub(/^\s*?!\s?/,"") else comment_block.push line.sub(/^\s*?!\s?/,"") end end nice_lines = comment_block.join("\n").split "\n\s*?\n" nice_lines[0] ||= "" nice_lines.shift end def progress(char) unless @options.quiet @progress.print(char) @progress.flush end end # # Create method for internal alias # def initialize_public_method(method, parent) return if !method || !parent new_meth = AnyMethod.new("External Alias for module", method.name) new_meth.singleton = method.singleton new_meth.params = method.params.clone new_meth.comment = remove_trailing_alias(method.comment.clone) new_meth.comment << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}" return new_meth end # # Create method for external alias # # If argument "internal" is true, file is ignored. # def initialize_external_method(new, old, params, file, comment, token=nil, internal=nil, nolink=nil) return nil unless new || old if internal external_alias_header = "#{INTERNAL_ALIAS_MES} " external_alias_text = external_alias_header + old elsif file external_alias_header = "#{EXTERNAL_ALIAS_MES} " external_alias_text = external_alias_header + file + "#" + old else return nil end external_meth = AnyMethod.new(external_alias_text, new) external_meth.singleton = false external_meth.params = params external_comment = remove_trailing_alias(comment) + "\n\n" if comment external_meth.comment = external_comment || "" if nolink && token external_meth.start_collecting_tokens external_meth.add_token Token.new(1,1).set_text(token) else external_meth.comment << external_alias_text end return external_meth end # # Parse visibility # def parse_visibility(code, default, container) result = [] visibility_default = default || :public used_modules = [] container.includes.each{|i| used_modules << i.name} if container remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "") remaining_code.split("\n").each{ |line| if /^\s*?private\s*?$/ =~ line visibility_default = :private break end } if remaining_code remaining_code.split("\n").each{ |line| if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line methods = $2.sub(/!.*$/, '') methods.split(",").each{ |meth| meth.sub!(/!.*$/, '') meth.gsub!(/:/, '') result << { "name" => meth.chomp.strip, "visibility" => :private, "used_modules" => used_modules.clone, "file_or_module" => container, "entity_is_discovered" => nil, "local_name" => nil } } elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line methods = $2.sub(/!.*$/, '') methods.split(",").each{ |meth| meth.sub!(/!.*$/, '') meth.gsub!(/:/, '') result << { "name" => meth.chomp.strip, "visibility" => :public, "used_modules" => used_modules.clone, "file_or_module" => container, "entity_is_discovered" => nil, "local_name" => nil } } end } if remaining_code if container result.each{ |vis_info| vis_info["parent"] = container.name } end return visibility_default, result end # # Set visibility # # "subname" element of "visibility_info" is deleted. # def set_visibility(container, subname, visibility_default, visibility_info) return unless container || subname || visibility_default || visibility_info not_found = true visibility_info.collect!{ |info| if info["name"] == subname || @options.ignore_case && info["name"].upcase == subname.upcase if info["file_or_module"].name == container.name container.set_visibility_for([subname], info["visibility"]) info["entity_is_discovered"] = true not_found = false end end info } if not_found return container.set_visibility_for([subname], visibility_default) else return container end end # # Find visibility # def find_visibility(container, subname, visibility_info) return nil if !subname || !visibility_info visibility_info.each{ |info| if info["name"] == subname || @options.ignore_case && info["name"].upcase == subname.upcase if info["parent"] == container.name return info["visibility"] end end } return nil end # # Check external aliases # def check_external_aliases(subname, params, comment, test=nil) @@external_aliases.each{ |alias_item| if subname == alias_item["old_name"] || subname.upcase == alias_item["old_name"].upcase && @options.ignore_case new_meth = initialize_external_method(alias_item["new_name"], subname, params, @file_name, comment) new_meth.visibility = alias_item["visibility"] progress "e" @stats.num_methods += 1 alias_item["file_or_module"].add_method(new_meth) if !alias_item["file_or_module"].include_requires?(@file_name, @options.ignore_case) alias_item["file_or_module"].add_require(Require.new(@file_name, "")) end end } end # # Check public_methods # def check_public_methods(method, parent) return if !method || !parent @@public_methods.each{ |alias_item| parent_is_used_module = nil alias_item["used_modules"].each{ |used_module| if used_module == parent || used_module.upcase == parent.upcase && @options.ignore_case parent_is_used_module = true end } next if !parent_is_used_module if method.name == alias_item["name"] || method.name.upcase == alias_item["name"].upcase && @options.ignore_case new_meth = initialize_public_method(method, parent) if alias_item["local_name"] new_meth.name = alias_item["local_name"] end progress "e" @stats.num_methods += 1 alias_item["file_or_module"].add_method new_meth end } end # # Continuous lines are united. # # Comments in continuous lines are removed. # def united_to_one_line(f90src) return "" unless f90src lines = f90src.split("\n") previous_continuing = false now_continuing = false body = "" lines.each{ |line| words = line.split("") next if words.empty? && previous_continuing commentout = false brank_flag = true ; brank_char = "" squote = false ; dquote = false ignore = false words.collect! { |char| if previous_continuing && brank_flag now_continuing = true ignore = true case char when "!" ; break when " " ; brank_char << char ; next "" when "&" brank_flag = false now_continuing = false next "" else brank_flag = false now_continuing = false ignore = false next brank_char + char end end ignore = false if now_continuing next "" elsif !(squote) && !(dquote) && !(commentout) case char when "!" ; commentout = true ; next char when "\""; dquote = true ; next char when "\'"; squote = true ; next char when "&" ; now_continuing = true ; next "" else next char end elsif commentout next char elsif squote case char when "\'"; squote = false ; next char else next char end elsif dquote case char when "\""; dquote = false ; next char else next char end end } if !ignore && !previous_continuing || !brank_flag if previous_continuing body << words.join("") else body << "\n" + words.join("") end end previous_continuing = now_continuing ? true : nil now_continuing = nil } return body end # # Continuous line checker # def continuous_line?(line) continuous = false if /&\s*?(!.*)?$/ =~ line continuous = true if comment_out?($~.pre_match) continuous = false end end return continuous end # # Comment out checker # def comment_out?(line) return nil unless line commentout = false squote = false ; dquote = false line.split("").each { |char| if !(squote) && !(dquote) case char when "!" ; commentout = true ; break when "\""; dquote = true when "\'"; squote = true else next end elsif squote case char when "\'"; squote = false else next end elsif dquote case char when "\""; dquote = false else next end end } return commentout end # # Semicolons are replaced to line feed. # def semicolon_to_linefeed(text) return "" unless text lines = text.split("\n") lines.collect!{ |line| words = line.split("") commentout = false squote = false ; dquote = false words.collect! { |char| if !(squote) && !(dquote) && !(commentout) case char when "!" ; commentout = true ; next char when "\""; dquote = true ; next char when "\'"; squote = true ; next char when ";" ; "\n" else next char end elsif commentout next char elsif squote case char when "\'"; squote = false ; next char else next char end elsif dquote case char when "\""; dquote = false ; next char else next char end end } words.join("") } return lines.join("\n") end # # Which "line" is start of block (module, program, block data, # subroutine, function) statement ? # def block_start?(line) return nil if !line if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i || line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i || line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i || line =~ \ /^\s*? (recursive|pure|elemental)?\s*? subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ /ix || line =~ \ /^\s*? (recursive|pure|elemental)?\s*? ( character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | type\s*?\([\w\s]+?\)\s+ | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | double\s+precision\s+ | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ )? function\s+(\w+)\s*? (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ /ix return true end return nil end # # Which "line" is end of block (module, program, block data, # subroutine, function) statement ? # def block_end?(line) return nil if !line if line =~ /^\s*?end\s*?(!.*?)?$/i || line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i || line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i || line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i || line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i || line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i return true end return nil end # # Remove "Alias for" in end of comments # def remove_trailing_alias(text) return "" if !text lines = text.split("\n").reverse comment_block = Array.new checked = false lines.each do |line| if !checked if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line || /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line checked = true next end end comment_block.unshift line end nice_lines = comment_block.join("\n") nice_lines ||= "" return nice_lines end # Empty lines in header are removed def remove_empty_head_lines(text) return "" unless text lines = text.split("\n") header = true lines.delete_if{ |line| header = false if /\S/ =~ line header && /^\s*?$/ =~ line } lines.join("\n") end # header marker "=", "==", ... are removed def remove_header_marker(text) return text.gsub(/^\s?(=+)/, '\1') end def remove_private_comments(body) body.gsub!(/^\s*!--\s*?$.*?^\s*!\+\+\s*?$/m, '') return body end # # Information of arguments of subroutines and functions in Fortran95 # class Fortran95Definition # Name of variable # attr_reader :varname # Types of variable # attr_reader :types # Initial Value # attr_reader :inivalue # Suffix of array # attr_reader :arraysuffix # Comments # attr_accessor :comment # Flag of non documentation # attr_accessor :nodoc def initialize(varname, types, inivalue, arraysuffix, comment, nodoc=false) @varname = varname @types = types @inivalue = inivalue @arraysuffix = arraysuffix @comment = comment @nodoc = nodoc end def to_s return <<-EOF EOF end # # If attr is included, true is returned # def include_attr?(attr) return if !attr @types.split(",").each{ |type| return true if type.strip.chomp.upcase == attr.strip.chomp.upcase } return nil end end # End of Fortran95Definition # # Parse string argument "text", and Return Array of # Fortran95Definition object # def definition_info(text) return nil unless text lines = "#{text}" defs = Array.new comment = "" trailing_comment = "" under_comment_valid = false lines.split("\n").each{ |line| if /^\s*?!\s?(.*)/ =~ line if COMMENTS_ARE_UPPER comment << remove_header_marker($1) comment << "\n" elsif defs[-1] && under_comment_valid defs[-1].comment << "\n" defs[-1].comment << remove_header_marker($1) end next elsif /^\s*?$/ =~ line comment = "" under_comment_valid = false next end type = "" characters = "" if line =~ /^\s*? ( character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* | type\s*?\([\w\s]+?\)[\s\,]* | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* | double\s+precision[\s\,]* | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* ) (.*?::)? (.+)$ /ix characters = $8 type = $1 type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7 else under_comment_valid = false next end squote = false ; dquote = false ; bracket = 0 iniflag = false; commentflag = false varname = "" ; arraysuffix = "" ; inivalue = "" start_pos = defs.size characters.split("").each { |char| if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag) case char when "!" ; commentflag = true when "(" ; bracket += 1 ; arraysuffix = char when "\""; dquote = true when "\'"; squote = true when "=" ; iniflag = true ; inivalue << char when "," defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) varname = "" ; arraysuffix = "" ; inivalue = "" under_comment_valid = true when " " ; next else ; varname << char end elsif commentflag comment << remove_header_marker(char) trailing_comment << remove_header_marker(char) elsif iniflag if dquote case char when "\"" ; dquote = false ; inivalue << char else ; inivalue << char end elsif squote case char when "\'" ; squote = false ; inivalue << char else ; inivalue << char end elsif bracket > 0 case char when "(" ; bracket += 1 ; inivalue << char when ")" ; bracket -= 1 ; inivalue << char else ; inivalue << char end else case char when "," defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) varname = "" ; arraysuffix = "" ; inivalue = "" iniflag = false under_comment_valid = true when "(" ; bracket += 1 ; inivalue << char when "\""; dquote = true ; inivalue << char when "\'"; squote = true ; inivalue << char when "!" ; commentflag = true else ; inivalue << char end end elsif !(squote) && !(dquote) && bracket > 0 case char when "(" ; bracket += 1 ; arraysuffix << char when ")" ; bracket -= 1 ; arraysuffix << char else ; arraysuffix << char end elsif squote case char when "\'"; squote = false ; inivalue << char else ; inivalue << char end elsif dquote case char when "\""; dquote = false ; inivalue << char else ; inivalue << char end end } defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) if trailing_comment =~ /^:nodoc:/ defs[start_pos..-1].collect!{ |defitem| defitem.nodoc = true } end varname = "" ; arraysuffix = "" ; inivalue = "" comment = "" under_comment_valid = true trailing_comment = "" } return defs end end # class Fortran95parser end # module RDoc ================================================ FILE: lib/rdoc/parsers/parse_rb.rb ================================================ #!/usr/local/bin/ruby # Parse a Ruby source file, building a set of objects # representing the modules, classes, methods, # requires, and includes we find (these classes # are defined in code_objects.rb). # This file contains stuff stolen outright from: # # rtags.rb - # ruby-lex.rb - ruby lexcal analizer # ruby-token.rb - ruby tokens # by Keiju ISHITSUKA (Nippon Rational Inc.) # require "e2mmap" require "irb/slex" require "rdoc/code_objects" require "rdoc/tokenstream" require "rdoc/markup/simple_markup/preprocess" require "rdoc/parsers/parserfactory" $TOKEN_DEBUG = $DEBUG # Definitions of all tokens involved in the lexical analysis module RubyToken EXPR_BEG = :EXPR_BEG EXPR_MID = :EXPR_MID EXPR_END = :EXPR_END EXPR_ARG = :EXPR_ARG EXPR_FNAME = :EXPR_FNAME EXPR_DOT = :EXPR_DOT EXPR_CLASS = :EXPR_CLASS class Token NO_TEXT = "??".freeze attr :text def initialize(line_no, char_no) @line_no = line_no @char_no = char_no @text = NO_TEXT end # Because we're used in contexts that expect to return a token, # we set the text string and then return ourselves def set_text(text) @text = text self end attr_reader :line_no, :char_no, :text end class TkNode < Token attr :node end class TkId < Token def initialize(line_no, char_no, name) super(line_no, char_no) @name = name end attr :name end class TkKW < TkId end class TkVal < Token def initialize(line_no, char_no, value = nil) super(line_no, char_no) set_text(value) end end class TkOp < Token def name self.class.op_name end end class TkOPASGN < TkOp def initialize(line_no, char_no, op) super(line_no, char_no) op = TkReading2Token[op] unless op.kind_of?(Symbol) @op = op end attr :op end class TkUnknownChar < Token def initialize(line_no, char_no, id) super(line_no, char_no) @name = char_no.chr end attr :name end class TkError < Token end def set_token_position(line, char) @prev_line_no = line @prev_char_no = char end def Token(token, value = nil) tk = nil case token when String, Symbol source = token.kind_of?(String) ? TkReading2Token : TkSymbol2Token if (tk = source[token]).nil? IRB.fail TkReading2TokenNoKey, token end tk = Token(tk[0], value) else tk = if (token.ancestors & [TkId, TkVal, TkOPASGN, TkUnknownChar]).empty? token.new(@prev_line_no, @prev_char_no) else token.new(@prev_line_no, @prev_char_no, value) end end tk end TokenDefinitions = [ [:TkCLASS, TkKW, "class", EXPR_CLASS], [:TkMODULE, TkKW, "module", EXPR_BEG], [:TkDEF, TkKW, "def", EXPR_FNAME], [:TkUNDEF, TkKW, "undef", EXPR_FNAME], [:TkBEGIN, TkKW, "begin", EXPR_BEG], [:TkRESCUE, TkKW, "rescue", EXPR_MID], [:TkENSURE, TkKW, "ensure", EXPR_BEG], [:TkEND, TkKW, "end", EXPR_END], [:TkIF, TkKW, "if", EXPR_BEG, :TkIF_MOD], [:TkUNLESS, TkKW, "unless", EXPR_BEG, :TkUNLESS_MOD], [:TkTHEN, TkKW, "then", EXPR_BEG], [:TkELSIF, TkKW, "elsif", EXPR_BEG], [:TkELSE, TkKW, "else", EXPR_BEG], [:TkCASE, TkKW, "case", EXPR_BEG], [:TkWHEN, TkKW, "when", EXPR_BEG], [:TkWHILE, TkKW, "while", EXPR_BEG, :TkWHILE_MOD], [:TkUNTIL, TkKW, "until", EXPR_BEG, :TkUNTIL_MOD], [:TkFOR, TkKW, "for", EXPR_BEG], [:TkBREAK, TkKW, "break", EXPR_END], [:TkNEXT, TkKW, "next", EXPR_END], [:TkREDO, TkKW, "redo", EXPR_END], [:TkRETRY, TkKW, "retry", EXPR_END], [:TkIN, TkKW, "in", EXPR_BEG], [:TkDO, TkKW, "do", EXPR_BEG], [:TkRETURN, TkKW, "return", EXPR_MID], [:TkYIELD, TkKW, "yield", EXPR_END], [:TkSUPER, TkKW, "super", EXPR_END], [:TkSELF, TkKW, "self", EXPR_END], [:TkNIL, TkKW, "nil", EXPR_END], [:TkTRUE, TkKW, "true", EXPR_END], [:TkFALSE, TkKW, "false", EXPR_END], [:TkAND, TkKW, "and", EXPR_BEG], [:TkOR, TkKW, "or", EXPR_BEG], [:TkNOT, TkKW, "not", EXPR_BEG], [:TkIF_MOD, TkKW], [:TkUNLESS_MOD, TkKW], [:TkWHILE_MOD, TkKW], [:TkUNTIL_MOD, TkKW], [:TkALIAS, TkKW, "alias", EXPR_FNAME], [:TkDEFINED, TkKW, "defined?", EXPR_END], [:TklBEGIN, TkKW, "BEGIN", EXPR_END], [:TklEND, TkKW, "END", EXPR_END], [:Tk__LINE__, TkKW, "__LINE__", EXPR_END], [:Tk__FILE__, TkKW, "__FILE__", EXPR_END], [:TkIDENTIFIER, TkId], [:TkFID, TkId], [:TkGVAR, TkId], [:TkIVAR, TkId], [:TkCONSTANT, TkId], [:TkINTEGER, TkVal], [:TkFLOAT, TkVal], [:TkSTRING, TkVal], [:TkXSTRING, TkVal], [:TkREGEXP, TkVal], [:TkCOMMENT, TkVal], [:TkDSTRING, TkNode], [:TkDXSTRING, TkNode], [:TkDREGEXP, TkNode], [:TkNTH_REF, TkId], [:TkBACK_REF, TkId], [:TkUPLUS, TkOp, "+@"], [:TkUMINUS, TkOp, "-@"], [:TkPOW, TkOp, "**"], [:TkCMP, TkOp, "<=>"], [:TkEQ, TkOp, "=="], [:TkEQQ, TkOp, "==="], [:TkNEQ, TkOp, "!="], [:TkGEQ, TkOp, ">="], [:TkLEQ, TkOp, "<="], [:TkANDOP, TkOp, "&&"], [:TkOROP, TkOp, "||"], [:TkMATCH, TkOp, "=~"], [:TkNMATCH, TkOp, "!~"], [:TkDOT2, TkOp, ".."], [:TkDOT3, TkOp, "..."], [:TkAREF, TkOp, "[]"], [:TkASET, TkOp, "[]="], [:TkLSHFT, TkOp, "<<"], [:TkRSHFT, TkOp, ">>"], [:TkCOLON2, TkOp], [:TkCOLON3, TkOp], # [:OPASGN, TkOp], # +=, -= etc. # [:TkASSOC, TkOp, "=>"], [:TkQUESTION, TkOp, "?"], #? [:TkCOLON, TkOp, ":"], #: [:TkfLPAREN], # func( # [:TkfLBRACK], # func[ # [:TkfLBRACE], # func{ # [:TkSTAR], # *arg [:TkAMPER], # &arg # [:TkSYMBOL, TkId], # :SYMBOL [:TkSYMBEG, TkId], [:TkGT, TkOp, ">"], [:TkLT, TkOp, "<"], [:TkPLUS, TkOp, "+"], [:TkMINUS, TkOp, "-"], [:TkMULT, TkOp, "*"], [:TkDIV, TkOp, "/"], [:TkMOD, TkOp, "%"], [:TkBITOR, TkOp, "|"], [:TkBITXOR, TkOp, "^"], [:TkBITAND, TkOp, "&"], [:TkBITNOT, TkOp, "~"], [:TkNOTOP, TkOp, "!"], [:TkBACKQUOTE, TkOp, "`"], [:TkASSIGN, Token, "="], [:TkDOT, Token, "."], [:TkLPAREN, Token, "("], #(exp) [:TkLBRACK, Token, "["], #[arry] [:TkLBRACE, Token, "{"], #{hash} [:TkRPAREN, Token, ")"], [:TkRBRACK, Token, "]"], [:TkRBRACE, Token, "}"], [:TkCOMMA, Token, ","], [:TkSEMICOLON, Token, ";"], [:TkRD_COMMENT], [:TkSPACE], [:TkNL], [:TkEND_OF_SCRIPT], [:TkBACKSLASH, TkUnknownChar, "\\"], [:TkAT, TkUnknownChar, "@"], [:TkDOLLAR, TkUnknownChar, "\$"], #" ] # {reading => token_class} # {reading => [token_class, *opt]} TkReading2Token = {} TkSymbol2Token = {} def RubyToken.def_token(token_n, super_token = Token, reading = nil, *opts) token_n = token_n.id2name unless token_n.kind_of?(String) if RubyToken.const_defined?(token_n) IRB.fail AlreadyDefinedToken, token_n end token_c = Class.new super_token RubyToken.const_set token_n, token_c # token_c.inspect if reading if TkReading2Token[reading] IRB.fail TkReading2TokenDuplicateError, token_n, reading end if opts.empty? TkReading2Token[reading] = [token_c] else TkReading2Token[reading] = [token_c].concat(opts) end end TkSymbol2Token[token_n.intern] = token_c if token_c <= TkOp token_c.class_eval %{ def self.op_name; "#{reading}"; end } end end for defs in TokenDefinitions def_token(*defs) end NEWLINE_TOKEN = TkNL.new(0,0) NEWLINE_TOKEN.set_text("\n") end # Lexical analyzer for Ruby source class RubyLex ###################################################################### # # Read an input stream character by character. We allow for unlimited # ungetting of characters just read. # # We simplify the implementation greatly by reading the entire input # into a buffer initially, and then simply traversing it using # pointers. # # We also have to allow for the here document diversion. This # little gem comes about when the lexer encounters a here # document. At this point we effectively need to split the input # stream into two parts: one to read the body of the here document, # the other to read the rest of the input line where the here # document was initially encountered. For example, we might have # # do_something(<<-A, <<-B) # stuff # for # A # stuff # for # B # # When the lexer encounters the <= @size ch = @content[@offset, 1] @offset += 1 @hwm = @offset if @hwm < @offset if @newline_pending @line_num += 1 @last_newline = @offset - 1 @newline_pending = false end if ch == "\n" @newline_pending = true end ch end def getc_already_read getc end def ungetc(ch) raise "unget past beginning of file" if @offset <= 0 @offset -= 1 if @content[@offset] == ?\n @newline_pending = false end end def get_read res = @content[@read_back_offset...@offset] @read_back_offset = @offset res end def peek(at) pos = @offset + at if pos >= @size nil else @content[pos, 1] end end def peek_equal(str) @content[@offset, str.length] == str end def divert_read_from(reserve) @content[@offset, 0] = reserve @size = @content.size end end # end of nested class BufferedReader extend Exception2MessageMapper def_exception(:AlreadyDefinedToken, "Already defined token(%s)") def_exception(:TkReading2TokenNoKey, "key nothing(key='%s')") def_exception(:TkSymbol2TokenNoKey, "key nothing(key='%s')") def_exception(:TkReading2TokenDuplicateError, "key duplicate(token_n='%s', key='%s')") def_exception(:SyntaxError, "%s") include RubyToken include IRB attr_reader :continue attr_reader :lex_state def RubyLex.debug? false end def initialize(content) lex_init @reader = BufferedReader.new(content) @exp_line_no = @line_no = 1 @base_char_no = 0 @indent = 0 @ltype = nil @quoted = nil @lex_state = EXPR_BEG @space_seen = false @continue = false @line = "" @skip_space = false @read_auto_clean_up = false @exception_on_syntax_error = true end attr :skip_space, true attr :read_auto_clean_up, true attr :exception_on_syntax_error, true attr :indent # io functions def line_no @reader.line_num end def char_no @reader.column end def get_read @reader.get_read end def getc @reader.getc end def getc_of_rests @reader.getc_already_read end def gets c = getc or return l = "" begin l.concat c unless c == "\r" break if c == "\n" end while c = getc l end def ungetc(c = nil) @reader.ungetc(c) end def peek_equal?(str) @reader.peek_equal(str) end def peek(i = 0) @reader.peek(i) end def lex until (((tk = token).kind_of?(TkNL) || tk.kind_of?(TkEND_OF_SCRIPT)) && !@continue or tk.nil?) end line = get_read if line == "" and tk.kind_of?(TkEND_OF_SCRIPT) || tk.nil? nil else line end end def token set_token_position(line_no, char_no) begin begin tk = @OP.match(self) @space_seen = tk.kind_of?(TkSPACE) rescue SyntaxError abort if @exception_on_syntax_error tk = TkError.new(line_no, char_no) end end while @skip_space and tk.kind_of?(TkSPACE) if @read_auto_clean_up get_read end # throw :eof unless tk p tk if $DEBUG tk end ENINDENT_CLAUSE = [ "case", "class", "def", "do", "for", "if", "module", "unless", "until", "while", "begin" #, "when" ] DEINDENT_CLAUSE = ["end" #, "when" ] PERCENT_LTYPE = { "q" => "\'", "Q" => "\"", "x" => "\`", "r" => "/", "w" => "]" } PERCENT_PAREN = { "{" => "}", "[" => "]", "<" => ">", "(" => ")" } Ltype2Token = { "\'" => TkSTRING, "\"" => TkSTRING, "\`" => TkXSTRING, "/" => TkREGEXP, "]" => TkDSTRING } Ltype2Token.default = TkSTRING DLtype2Token = { "\"" => TkDSTRING, "\`" => TkDXSTRING, "/" => TkDREGEXP, } def lex_init() @OP = SLex.new @OP.def_rules("\0", "\004", "\032") do |chars, io| Token(TkEND_OF_SCRIPT).set_text(chars) end @OP.def_rules(" ", "\t", "\f", "\r", "\13") do |chars, io| @space_seen = TRUE while (ch = getc) =~ /[ \t\f\r\13]/ chars << ch end ungetc Token(TkSPACE).set_text(chars) end @OP.def_rule("#") do |op, io| identify_comment end @OP.def_rule("=begin", proc{@prev_char_no == 0 && peek(0) =~ /\s/}) do |op, io| str = op @ltype = "=" begin line = "" begin ch = getc line << ch end until ch == "\n" str << line end until line =~ /^=end/ ungetc @ltype = nil if str =~ /\A=begin\s+rdoc/i str.sub!(/\A=begin.*\n/, '') str.sub!(/^=end.*/m, '') Token(TkCOMMENT).set_text(str) else Token(TkRD_COMMENT)#.set_text(str) end end @OP.def_rule("\n") do print "\\n\n" if RubyLex.debug? case @lex_state when EXPR_BEG, EXPR_FNAME, EXPR_DOT @continue = TRUE else @continue = FALSE @lex_state = EXPR_BEG end Token(TkNL).set_text("\n") end @OP.def_rules("*", "**", "!", "!=", "!~", "=", "==", "===", "=~", "<=>", "<", "<=", ">", ">=", ">>") do |op, io| @lex_state = EXPR_BEG Token(op).set_text(op) end @OP.def_rules("<<") do |op, io| tk = nil if @lex_state != EXPR_END && @lex_state != EXPR_CLASS && (@lex_state != EXPR_ARG || @space_seen) c = peek(0) if /[-\w_\"\'\`]/ =~ c tk = identify_here_document end end if !tk @lex_state = EXPR_BEG tk = Token(op).set_text(op) end tk end @OP.def_rules("'", '"') do |op, io| identify_string(op) end @OP.def_rules("`") do |op, io| if @lex_state == EXPR_FNAME Token(op).set_text(op) else identify_string(op) end end @OP.def_rules('?') do |op, io| if @lex_state == EXPR_END @lex_state = EXPR_BEG Token(TkQUESTION).set_text(op) else ch = getc if @lex_state == EXPR_ARG && ch !~ /\s/ ungetc @lex_state = EXPR_BEG; Token(TkQUESTION).set_text(op) else str = op str << ch if (ch == '\\') #' str << read_escape end @lex_state = EXPR_END Token(TkINTEGER).set_text(str) end end end @OP.def_rules("&", "&&", "|", "||") do |op, io| @lex_state = EXPR_BEG Token(op).set_text(op) end @OP.def_rules("+=", "-=", "*=", "**=", "&=", "|=", "^=", "<<=", ">>=", "||=", "&&=") do |op, io| @lex_state = EXPR_BEG op =~ /^(.*)=$/ Token(TkOPASGN, $1).set_text(op) end @OP.def_rule("+@", proc{@lex_state == EXPR_FNAME}) do |op, io| Token(TkUPLUS).set_text(op) end @OP.def_rule("-@", proc{@lex_state == EXPR_FNAME}) do |op, io| Token(TkUMINUS).set_text(op) end @OP.def_rules("+", "-") do |op, io| catch(:RET) do if @lex_state == EXPR_ARG if @space_seen and peek(0) =~ /[0-9]/ throw :RET, identify_number(op) else @lex_state = EXPR_BEG end elsif @lex_state != EXPR_END and peek(0) =~ /[0-9]/ throw :RET, identify_number(op) else @lex_state = EXPR_BEG end Token(op).set_text(op) end end @OP.def_rule(".") do @lex_state = EXPR_BEG if peek(0) =~ /[0-9]/ ungetc identify_number("") else # for obj.if @lex_state = EXPR_DOT Token(TkDOT).set_text(".") end end @OP.def_rules("..", "...") do |op, io| @lex_state = EXPR_BEG Token(op).set_text(op) end lex_int2 end def lex_int2 @OP.def_rules("]", "}", ")") do |op, io| @lex_state = EXPR_END @indent -= 1 Token(op).set_text(op) end @OP.def_rule(":") do if @lex_state == EXPR_END || peek(0) =~ /\s/ @lex_state = EXPR_BEG tk = Token(TkCOLON) else @lex_state = EXPR_FNAME; tk = Token(TkSYMBEG) end tk.set_text(":") end @OP.def_rule("::") do # p @lex_state.id2name, @space_seen if @lex_state == EXPR_BEG or @lex_state == EXPR_ARG && @space_seen @lex_state = EXPR_BEG tk = Token(TkCOLON3) else @lex_state = EXPR_DOT tk = Token(TkCOLON2) end tk.set_text("::") end @OP.def_rule("/") do |op, io| if @lex_state == EXPR_BEG || @lex_state == EXPR_MID identify_string(op) elsif peek(0) == '=' getc @lex_state = EXPR_BEG Token(TkOPASGN, :/).set_text("/=") #") elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/ identify_string(op) else @lex_state = EXPR_BEG Token("/").set_text(op) end end @OP.def_rules("^") do @lex_state = EXPR_BEG Token("^").set_text("^") end # @OP.def_rules("^=") do # @lex_state = EXPR_BEG # Token(TkOPASGN, :^) # end @OP.def_rules(",", ";") do |op, io| @lex_state = EXPR_BEG Token(op).set_text(op) end @OP.def_rule("~") do @lex_state = EXPR_BEG Token("~").set_text("~") end @OP.def_rule("~@", proc{@lex_state = EXPR_FNAME}) do @lex_state = EXPR_BEG Token("~").set_text("~@") end @OP.def_rule("(") do @indent += 1 if @lex_state == EXPR_BEG || @lex_state == EXPR_MID @lex_state = EXPR_BEG tk = Token(TkfLPAREN) else @lex_state = EXPR_BEG tk = Token(TkLPAREN) end tk.set_text("(") end @OP.def_rule("[]", proc{@lex_state == EXPR_FNAME}) do Token("[]").set_text("[]") end @OP.def_rule("[]=", proc{@lex_state == EXPR_FNAME}) do Token("[]=").set_text("[]=") end @OP.def_rule("[") do @indent += 1 if @lex_state == EXPR_FNAME t = Token(TkfLBRACK) else if @lex_state == EXPR_BEG || @lex_state == EXPR_MID t = Token(TkLBRACK) elsif @lex_state == EXPR_ARG && @space_seen t = Token(TkLBRACK) else t = Token(TkfLBRACK) end @lex_state = EXPR_BEG end t.set_text("[") end @OP.def_rule("{") do @indent += 1 if @lex_state != EXPR_END && @lex_state != EXPR_ARG t = Token(TkLBRACE) else t = Token(TkfLBRACE) end @lex_state = EXPR_BEG t.set_text("{") end @OP.def_rule('\\') do #' if getc == "\n" @space_seen = true @continue = true Token(TkSPACE).set_text("\\\n") else ungetc Token("\\").set_text("\\") #" end end @OP.def_rule('%') do |op, io| if @lex_state == EXPR_BEG || @lex_state == EXPR_MID identify_quotation('%') elsif peek(0) == '=' getc Token(TkOPASGN, "%").set_text("%=") elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/ identify_quotation('%') else @lex_state = EXPR_BEG Token("%").set_text("%") end end @OP.def_rule('$') do #' identify_gvar end @OP.def_rule('@') do if peek(0) =~ /[@\w_]/ ungetc identify_identifier else Token("@").set_text("@") end end # @OP.def_rule("def", proc{|op, io| /\s/ =~ io.peek(0)}) do # |op, io| # @indent += 1 # @lex_state = EXPR_FNAME # # @lex_state = EXPR_END # # until @rests[0] == "\n" or @rests[0] == ";" # # rests.shift # # end # end @OP.def_rule("__END__", proc{@prev_char_no == 0 && peek(0) =~ /[\r\n]/}) do throw :eof end @OP.def_rule("") do |op, io| printf "MATCH: start %s: %s\n", op, io.inspect if RubyLex.debug? if peek(0) =~ /[0-9]/ t = identify_number("") elsif peek(0) =~ /[\w_]/ t = identify_identifier end printf "MATCH: end %s: %s\n", op, io.inspect if RubyLex.debug? t end p @OP if RubyLex.debug? end def identify_gvar @lex_state = EXPR_END str = "$" tk = case ch = getc when /[~_*$?!@\/\\;,=:<>".]/ #" str << ch Token(TkGVAR, str) when "-" str << "-" << getc Token(TkGVAR, str) when "&", "`", "'", "+" str << ch Token(TkBACK_REF, str) when /[1-9]/ str << ch while (ch = getc) =~ /[0-9]/ str << ch end ungetc Token(TkNTH_REF) when /\w/ ungetc ungetc return identify_identifier else ungetc Token("$") end tk.set_text(str) end def identify_identifier token = "" token.concat getc if peek(0) =~ /[$@]/ token.concat getc if peek(0) == "@" while (ch = getc) =~ /\w|_/ print ":", ch, ":" if RubyLex.debug? token.concat ch end ungetc if ch == "!" or ch == "?" token.concat getc end # fix token # $stderr.puts "identifier - #{token}, state = #@lex_state" case token when /^\$/ return Token(TkGVAR, token).set_text(token) when /^\@/ @lex_state = EXPR_END return Token(TkIVAR, token).set_text(token) end if @lex_state != EXPR_DOT print token, "\n" if RubyLex.debug? token_c, *trans = TkReading2Token[token] if token_c # reserved word? if (@lex_state != EXPR_BEG && @lex_state != EXPR_FNAME && trans[1]) # modifiers token_c = TkSymbol2Token[trans[1]] @lex_state = trans[0] else if @lex_state != EXPR_FNAME if ENINDENT_CLAUSE.include?(token) @indent += 1 elsif DEINDENT_CLAUSE.include?(token) @indent -= 1 end @lex_state = trans[0] else @lex_state = EXPR_END end end return Token(token_c, token).set_text(token) end end if @lex_state == EXPR_FNAME @lex_state = EXPR_END if peek(0) == '=' token.concat getc end elsif @lex_state == EXPR_BEG || @lex_state == EXPR_DOT @lex_state = EXPR_ARG else @lex_state = EXPR_END end if token[0, 1] =~ /[A-Z]/ return Token(TkCONSTANT, token).set_text(token) elsif token[token.size - 1, 1] =~ /[!?]/ return Token(TkFID, token).set_text(token) else return Token(TkIDENTIFIER, token).set_text(token) end end def identify_here_document ch = getc if ch == "-" ch = getc indent = true end if /['"`]/ =~ ch # ' lt = ch quoted = "" while (c = getc) && c != lt quoted.concat c end else lt = '"' quoted = ch.dup while (c = getc) && c =~ /\w/ quoted.concat c end ungetc end ltback, @ltype = @ltype, lt reserve = "" while ch = getc reserve << ch if ch == "\\" #" ch = getc reserve << ch elsif ch == "\n" break end end str = "" while (l = gets) l.chomp! l.strip! if indent break if l == quoted str << l.chomp << "\n" end @reader.divert_read_from(reserve) @ltype = ltback @lex_state = EXPR_END Token(Ltype2Token[lt], str).set_text(str.dump) end def identify_quotation(initial_char) ch = getc if lt = PERCENT_LTYPE[ch] initial_char += ch ch = getc elsif ch =~ /\W/ lt = "\"" else RubyLex.fail SyntaxError, "unknown type of %string ('#{ch}')" end # if ch !~ /\W/ # ungetc # next # end #@ltype = lt @quoted = ch unless @quoted = PERCENT_PAREN[ch] identify_string(lt, @quoted, ch, initial_char) end def identify_number(start) str = start.dup if start == "+" or start == "-" or start == "" start = getc str << start end @lex_state = EXPR_END if start == "0" if peek(0) == "x" ch = getc str << ch match = /[0-9a-f_]/ else match = /[0-7_]/ end while ch = getc if ch !~ match ungetc break else str << ch end end return Token(TkINTEGER).set_text(str) end type = TkINTEGER allow_point = TRUE allow_e = TRUE while ch = getc case ch when /[0-9_]/ str << ch when allow_point && "." type = TkFLOAT if peek(0) !~ /[0-9]/ ungetc break end str << ch allow_point = false when allow_e && "e", allow_e && "E" str << ch type = TkFLOAT if peek(0) =~ /[+-]/ str << getc end allow_e = false allow_point = false else ungetc break end end Token(type).set_text(str) end def identify_string(ltype, quoted = ltype, opener=nil, initial_char = nil) @ltype = ltype @quoted = quoted subtype = nil str = "" str << initial_char if initial_char str << (opener||quoted) nest = 0 begin while ch = getc str << ch if @quoted == ch if nest == 0 break else nest -= 1 end elsif opener == ch nest += 1 elsif @ltype != "'" && @ltype != "]" and ch == "#" ch = getc if ch == "{" subtype = true str << ch << skip_inner_expression else ungetc(ch) end elsif ch == '\\' #' str << read_escape end end if @ltype == "/" if peek(0) =~ /i|o|n|e|s/ str << getc end end if subtype Token(DLtype2Token[ltype], str) else Token(Ltype2Token[ltype], str) end.set_text(str) ensure @ltype = nil @quoted = nil @lex_state = EXPR_END end end def skip_inner_expression res = "" nest = 0 while (ch = getc) res << ch if ch == '}' break if nest.zero? nest -= 1 elsif ch == '{' nest += 1 end end res end def identify_comment @ltype = "#" comment = "#" while ch = getc if ch == "\\" ch = getc if ch == "\n" ch = " " else comment << "\\" end else if ch == "\n" @ltype = nil ungetc break end end comment << ch end return Token(TkCOMMENT).set_text(comment) end def read_escape res = "" case ch = getc when /[0-7]/ ungetc ch 3.times do case ch = getc when /[0-7]/ when nil break else ungetc break end res << ch end when "x" res << ch 2.times do case ch = getc when /[0-9a-fA-F]/ when nil break else ungetc break end res << ch end when "M" res << ch if (ch = getc) != '-' ungetc else res << ch if (ch = getc) == "\\" #" res << ch res << read_escape else res << ch end end when "C", "c" #, "^" res << ch if ch == "C" and (ch = getc) != "-" ungetc else res << ch if (ch = getc) == "\\" #" res << ch res << read_escape else res << ch end end else res << ch end res end end # Extract code elements from a source file, returning a TopLevel # object containing the constituent file elements. # # This file is based on rtags module RDoc GENERAL_MODIFIERS = [ 'nodoc' ].freeze CLASS_MODIFIERS = GENERAL_MODIFIERS ATTR_MODIFIERS = GENERAL_MODIFIERS CONSTANT_MODIFIERS = GENERAL_MODIFIERS METHOD_MODIFIERS = GENERAL_MODIFIERS + [ 'arg', 'args', 'yield', 'yields', 'notnew', 'not-new', 'not_new', 'doc' ] class RubyParser include RubyToken include TokenStream extend ParserFactory parse_files_matching(/\.rbw?$/) def initialize(top_level, file_name, content, options, stats) @options = options @stats = stats @size = 0 @token_listeners = nil @input_file_name = file_name @scanner = RubyLex.new(content) @scanner.exception_on_syntax_error = false @top_level = top_level @progress = $stderr unless options.quiet end def scan @tokens = [] @unget_read = [] @read = [] catch(:eof) do catch(:enddoc) do begin parse_toplevel_statements(@top_level) rescue Exception => e $stderr.puts "\n\n" $stderr.puts "RDoc failure in #@input_file_name at or around " + "line #{@scanner.line_no} column #{@scanner.char_no}" $stderr.puts $stderr.puts "Before reporting this, could you check that the file" $stderr.puts "you're documenting compiles cleanly--RDoc is not a" $stderr.puts "full Ruby parser, and gets confused easily if fed" $stderr.puts "invalid programs." $stderr.puts $stderr.puts "The internal error was:\n\n" e.set_backtrace(e.backtrace[0,4]) raise end end end @top_level end private def make_message(msg) prefix = "\n" + @input_file_name + ":" if @scanner prefix << "#{@scanner.line_no}:#{@scanner.char_no}: " end return prefix + msg end def warn(msg) return if @options.quiet msg = make_message msg $stderr.puts msg end def error(msg) msg = make_message msg $stderr.puts msg exit(1) end def progress(char) unless @options.quiet @progress.print(char) @progress.flush end end def add_token_listener(obj) @token_listeners ||= [] @token_listeners << obj end def remove_token_listener(obj) @token_listeners.delete(obj) end def get_tk tk = nil if @tokens.empty? tk = @scanner.token @read.push @scanner.get_read puts "get_tk1 => #{tk.inspect}" if $TOKEN_DEBUG else @read.push @unget_read.shift tk = @tokens.shift puts "get_tk2 => #{tk.inspect}" if $TOKEN_DEBUG end if tk.kind_of?(TkSYMBEG) set_token_position(tk.line_no, tk.char_no) tk1 = get_tk if tk1.kind_of?(TkId) || tk1.kind_of?(TkOp) tk = Token(TkSYMBOL).set_text(":" + tk1.name) # remove the identifier we just read (we're about to # replace it with a symbol) @token_listeners.each do |obj| obj.pop_token end if @token_listeners else warn("':' not followed by identifier or operator") tk = tk1 end end # inform any listeners of our shiny new token @token_listeners.each do |obj| obj.add_token(tk) end if @token_listeners tk end def peek_tk unget_tk(tk = get_tk) tk end def unget_tk(tk) @tokens.unshift tk @unget_read.unshift @read.pop # Remove this token from any listeners @token_listeners.each do |obj| obj.pop_token end if @token_listeners end def skip_tkspace(skip_nl = true) tokens = [] while ((tk = get_tk).kind_of?(TkSPACE) || (skip_nl && tk.kind_of?(TkNL))) tokens.push tk end unget_tk(tk) tokens end def get_tkread read = @read.join("") @read = [] read end def peek_read @read.join('') end NORMAL = "::" SINGLE = "<<" # Look for the first comment in a file that isn't # a shebang line. def collect_first_comment skip_tkspace res = '' first_line = true tk = get_tk while tk.kind_of?(TkCOMMENT) if first_line && /\A#!/ =~ tk.text skip_tkspace tk = get_tk elsif first_line && /\A#\s*-\*-/ =~ tk.text first_line = false skip_tkspace tk = get_tk else first_line = false res << tk.text << "\n" tk = get_tk if tk.kind_of? TkNL skip_tkspace(false) tk = get_tk end end end unget_tk(tk) res end def parse_toplevel_statements(container) comment = collect_first_comment look_for_directives_in(container, comment) container.comment = comment unless comment.empty? parse_statements(container, NORMAL, nil, comment) end def parse_statements(container, single=NORMAL, current_method=nil, comment='') nest = 1 save_visibility = container.visibility # if container.kind_of?(TopLevel) # else # comment = '' # end non_comment_seen = true while tk = get_tk keep_comment = false non_comment_seen = true unless tk.kind_of?(TkCOMMENT) case tk when TkNL skip_tkspace(true) # Skip blanks and newlines tk = get_tk if tk.kind_of?(TkCOMMENT) if non_comment_seen comment = '' non_comment_seen = false end while tk.kind_of?(TkCOMMENT) comment << tk.text << "\n" tk = get_tk # this is the newline skip_tkspace(false) # leading spaces tk = get_tk end unless comment.empty? look_for_directives_in(container, comment) if container.done_documenting container.ongoing_visibility = save_visibility # return end end keep_comment = true else non_comment_seen = true end unget_tk(tk) keep_comment = true when TkCLASS if container.document_children parse_class(container, single, tk, comment) else nest += 1 end when TkMODULE if container.document_children parse_module(container, single, tk, comment) else nest += 1 end when TkDEF if container.document_self parse_method(container, single, tk, comment) else nest += 1 end when TkCONSTANT if container.document_self parse_constant(container, single, tk, comment) end when TkALIAS if container.document_self parse_alias(container, single, tk, comment) end when TkYIELD if current_method.nil? warn("Warning: yield outside of method") if container.document_self else parse_yield(container, single, tk, current_method) end # Until and While can have a 'do', which shouldn't increas # the nesting. We can't solve the general case, but we can # handle most occurrences by ignoring a do at the end of a line when TkUNTIL, TkWHILE nest += 1 puts "FOUND #{tk.class} in #{container.name}, nest = #{nest}, " + "line #{tk.line_no}" if $DEBUG skip_optional_do_after_expression # 'for' is trickier when TkFOR nest += 1 puts "FOUND #{tk.class} in #{container.name}, nest = #{nest}, " + "line #{tk.line_no}" if $DEBUG skip_for_variable skip_optional_do_after_expression when TkCASE, TkDO, TkIF, TkUNLESS, TkBEGIN nest += 1 puts "Found #{tk.class} in #{container.name}, nest = #{nest}, " + "line #{tk.line_no}" if $DEBUG when TkIDENTIFIER if nest == 1 and current_method.nil? case tk.name when "private", "protected", "public", "private_class_method", "public_class_method" parse_visibility(container, single, tk) keep_comment = true when "attr" parse_attr(container, single, tk, comment) when /^attr_(reader|writer|accessor)$/, @options.extra_accessors parse_attr_accessor(container, single, tk, comment) when "alias_method" if container.document_self parse_alias(container, single, tk, comment) end end end case tk.name when "require" parse_require(container, comment) when "include" parse_include(container, comment) end when TkEND nest -= 1 puts "Found 'end' in #{container.name}, nest = #{nest}, line #{tk.line_no}" if $DEBUG puts "Method = #{current_method.name}" if $DEBUG and current_method if nest == 0 read_documentation_modifiers(container, CLASS_MODIFIERS) container.ongoing_visibility = save_visibility return end end comment = '' unless keep_comment begin get_tkread skip_tkspace(false) end while peek_tk == TkNL end end def parse_class(container, single, tk, comment, &block) progress("c") @stats.num_classes += 1 container, name_t = get_class_or_module(container) case name_t when TkCONSTANT name = name_t.name superclass = "Object" if peek_tk.kind_of?(TkLT) get_tk skip_tkspace(true) superclass = get_class_specification superclass = "" if superclass.empty? end if single == SINGLE cls_type = SingleClass else cls_type = NormalClass end cls = container.add_class(cls_type, name, superclass) read_documentation_modifiers(cls, CLASS_MODIFIERS) cls.record_location(@top_level) parse_statements(cls) cls.comment = comment when TkLSHFT case name = get_class_specification when "self", container.name parse_statements(container, SINGLE, &block) else other = TopLevel.find_class_named(name) unless other # other = @top_level.add_class(NormalClass, name, nil) # other.record_location(@top_level) # other.comment = comment other = NormalClass.new("Dummy", nil) end read_documentation_modifiers(other, CLASS_MODIFIERS) parse_statements(other, SINGLE, &block) end else warn("Expected class name or '<<'. Got #{name_t.class}: #{name_t.text.inspect}") end end def parse_module(container, single, tk, comment) progress("m") @stats.num_modules += 1 container, name_t = get_class_or_module(container) # skip_tkspace name = name_t.name mod = container.add_module(NormalModule, name) mod.record_location(@top_level) read_documentation_modifiers(mod, CLASS_MODIFIERS) parse_statements(mod) mod.comment = comment end # Look for the name of a class of module (optionally with a leading :: or # with :: separated named) and return the ultimate name and container def get_class_or_module(container) skip_tkspace name_t = get_tk # class ::A -> A is in the top level if name_t.kind_of?(TkCOLON2) name_t = get_tk container = @top_level end skip_tkspace(false) while peek_tk.kind_of?(TkCOLON2) prev_container = container container = container.find_module_named(name_t.name) if !container # warn("Couldn't find module #{name_t.name}") container = prev_container.add_module(NormalModule, name_t.name) end get_tk name_t = get_tk end skip_tkspace(false) return [container, name_t] end def parse_constant(container, single, tk, comment) name = tk.name skip_tkspace(false) eq_tk = get_tk unless eq_tk.kind_of?(TkASSIGN) unget_tk(eq_tk) return end nest = 0 get_tkread tk = get_tk if tk.kind_of? TkGT unget_tk(tk) unget_tk(eq_tk) return end loop do puts("Param: #{tk}, #{@scanner.continue} " + "#{@scanner.lex_state} #{nest}") if $DEBUG case tk when TkSEMICOLON break when TkLPAREN, TkfLPAREN nest += 1 when TkRPAREN nest -= 1 when TkCOMMENT if nest <= 0 && @scanner.lex_state == EXPR_END unget_tk(tk) break end when TkNL if (@scanner.lex_state == EXPR_END and nest <= 0) || !@scanner.continue unget_tk(tk) break end end tk = get_tk end res = get_tkread.tr("\n", " ").strip res = "" if res == ";" con = Constant.new(name, res, comment) read_documentation_modifiers(con, CONSTANT_MODIFIERS) if con.document_self container.add_constant(con) end end def parse_method(container, single, tk, comment) progress(".") @stats.num_methods += 1 line_no = tk.line_no column = tk.char_no start_collecting_tokens add_token(tk) add_token_listener(self) @scanner.instance_eval{@lex_state = EXPR_FNAME} skip_tkspace(false) name_t = get_tk back_tk = skip_tkspace meth = nil added_container = false dot = get_tk if dot.kind_of?(TkDOT) or dot.kind_of?(TkCOLON2) @scanner.instance_eval{@lex_state = EXPR_FNAME} skip_tkspace name_t2 = get_tk case name_t when TkSELF name = name_t2.name when TkCONSTANT name = name_t2.name prev_container = container container = container.find_module_named(name_t.name) if !container added_container = true obj = name_t.name.split("::").inject(Object) do |state, item| state.const_get(item) end rescue nil type = obj.class == Class ? NormalClass : NormalModule if not [Class, Module].include?(obj.class) warn("Couldn't find #{name_t.name}. Assuming it's a module") end if type == NormalClass then container = prev_container.add_class(type, name_t.name, obj.superclass.name) else container = prev_container.add_module(type, name_t.name) end end else # warn("Unexpected token '#{name_t2.inspect}'") # break skip_method(container) return end meth = AnyMethod.new(get_tkread, name) meth.singleton = true else unget_tk dot back_tk.reverse_each do |tk| unget_tk tk end name = name_t.name meth = AnyMethod.new(get_tkread, name) meth.singleton = (single == SINGLE) end remove_token_listener(self) meth.start_collecting_tokens indent = TkSPACE.new(1,1) indent.set_text(" " * column) meth.add_tokens([TkCOMMENT.new(line_no, 1, "# File #{@top_level.file_absolute_name}, line #{line_no}"), NEWLINE_TOKEN, indent]) meth.add_tokens(@token_stream) add_token_listener(meth) @scanner.instance_eval{@continue = false} parse_method_parameters(meth) if meth.document_self container.add_method(meth) elsif added_container container.document_self = false end # Having now read the method parameters and documentation modifiers, we # now know whether we have to rename #initialize to ::new if name == "initialize" && !meth.singleton if meth.dont_rename_initialize meth.visibility = :protected else meth.singleton = true meth.name = "new" meth.visibility = :public end end parse_statements(container, single, meth) remove_token_listener(meth) # Look for a 'call-seq' in the comment, and override the # normal parameter stuff if comment.sub!(/:?call-seq:(.*?)^\s*\#?\s*$/m, '') seq = $1 seq.gsub!(/^\s*\#\s*/, '') meth.call_seq = seq end meth.comment = comment end def skip_method(container) meth = AnyMethod.new("", "anon") parse_method_parameters(meth) parse_statements(container, false, meth) end # Capture the method's parameters. Along the way, # look for a comment containing # # # yields: .... # # and add this as the block_params for the method def parse_method_parameters(method) res = parse_method_or_yield_parameters(method) res = "(" + res + ")" unless res[0] == ?( method.params = res unless method.params if method.block_params.nil? skip_tkspace(false) read_documentation_modifiers(method, METHOD_MODIFIERS) end end def parse_method_or_yield_parameters(method=nil, modifiers=METHOD_MODIFIERS) skip_tkspace(false) tk = get_tk # Little hack going on here. In the statement # f = 2*(1+yield) # We see the RPAREN as the next token, so we need # to exit early. This still won't catch all cases # (such as "a = yield + 1" end_token = case tk when TkLPAREN, TkfLPAREN TkRPAREN when TkRPAREN return "" else TkNL end nest = 0 loop do puts("Param: #{tk.inspect}, #{@scanner.continue} " + "#{@scanner.lex_state} #{nest}") if $DEBUG case tk when TkSEMICOLON break when TkLBRACE nest += 1 when TkRBRACE # we might have a.each {|i| yield i } unget_tk(tk) if nest.zero? nest -= 1 break if nest <= 0 when TkLPAREN, TkfLPAREN nest += 1 when end_token if end_token == TkRPAREN nest -= 1 break if @scanner.lex_state == EXPR_END and nest <= 0 else break unless @scanner.continue end when method && method.block_params.nil? && TkCOMMENT unget_tk(tk) read_documentation_modifiers(method, modifiers) end tk = get_tk end res = get_tkread.tr("\n", " ").strip res = "" if res == ";" res end # skip the var [in] part of a 'for' statement def skip_for_variable skip_tkspace(false) tk = get_tk skip_tkspace(false) tk = get_tk unget_tk(tk) unless tk.kind_of?(TkIN) end # while, until, and for have an optional def skip_optional_do_after_expression skip_tkspace(false) tk = get_tk case tk when TkLPAREN, TkfLPAREN end_token = TkRPAREN else end_token = TkNL end nest = 0 @scanner.instance_eval{@continue = false} loop do puts("\nWhile: #{tk}, #{@scanner.continue} " + "#{@scanner.lex_state} #{nest}") if $DEBUG case tk when TkSEMICOLON break when TkLPAREN, TkfLPAREN nest += 1 when TkDO break if nest.zero? when end_token if end_token == TkRPAREN nest -= 1 break if @scanner.lex_state == EXPR_END and nest.zero? else break unless @scanner.continue end end tk = get_tk end skip_tkspace(false) if peek_tk.kind_of? TkDO get_tk end end # Return a superclass, which can be either a constant # of an expression def get_class_specification tk = get_tk return "self" if tk.kind_of?(TkSELF) res = "" while tk.kind_of?(TkCOLON2) || tk.kind_of?(TkCOLON3) || tk.kind_of?(TkCONSTANT) res += tk.text tk = get_tk end unget_tk(tk) skip_tkspace(false) get_tkread # empty out read buffer tk = get_tk case tk when TkNL, TkCOMMENT, TkSEMICOLON unget_tk(tk) return res end res += parse_call_parameters(tk) res end def parse_call_parameters(tk) end_token = case tk when TkLPAREN, TkfLPAREN TkRPAREN when TkRPAREN return "" else TkNL end nest = 0 loop do puts("Call param: #{tk}, #{@scanner.continue} " + "#{@scanner.lex_state} #{nest}") if $DEBUG case tk when TkSEMICOLON break when TkLPAREN, TkfLPAREN nest += 1 when end_token if end_token == TkRPAREN nest -= 1 break if @scanner.lex_state == EXPR_END and nest <= 0 else break unless @scanner.continue end when TkCOMMENT unget_tk(tk) break end tk = get_tk end res = get_tkread.tr("\n", " ").strip res = "" if res == ";" res end # Parse a constant, which might be qualified by # one or more class or module names def get_constant res = "" skip_tkspace(false) tk = get_tk while tk.kind_of?(TkCOLON2) || tk.kind_of?(TkCOLON3) || tk.kind_of?(TkCONSTANT) res += tk.text tk = get_tk end # if res.empty? # warn("Unexpected token #{tk} in constant") # end unget_tk(tk) res end # Get a constant that may be surrounded by parens def get_constant_with_optional_parens skip_tkspace(false) nest = 0 while (tk = peek_tk).kind_of?(TkLPAREN) || tk.kind_of?(TkfLPAREN) get_tk skip_tkspace(true) nest += 1 end name = get_constant while nest > 0 skip_tkspace(true) tk = get_tk nest -= 1 if tk.kind_of?(TkRPAREN) end name end # Directives are modifier comments that can appear after class, module, # or method names. For example # # def fred # :yields: a, b # # or # # class SM # :nodoc: # # we return the directive name and any parameters as a two element array def read_directive(allowed) tk = get_tk puts "directive: #{tk.inspect}" if $DEBUG result = nil if tk.kind_of?(TkCOMMENT) if tk.text =~ /\s*:?(\w+):\s*(.*)/ directive = $1.downcase if allowed.include?(directive) result = [directive, $2] end end else unget_tk(tk) end result end def read_documentation_modifiers(context, allow) dir = read_directive(allow) case dir[0] when "notnew", "not_new", "not-new" context.dont_rename_initialize = true when "nodoc" context.document_self = false if dir[1].downcase == "all" context.document_children = false end when "doc" context.document_self = true context.force_documentation = true when "yield", "yields" unless context.params.nil? context.params.sub!(/(,|)\s*&\w+/,'') # remove parameter &proc end context.block_params = dir[1] when "arg", "args" context.params = dir[1] end if dir end # Look for directives in a normal comment block: # # #-- - don't display comment from this point forward # # # This routine modifies it's parameter def look_for_directives_in(context, comment) preprocess = SM::PreProcess.new(@input_file_name, @options.rdoc_include) preprocess.handle(comment) do |directive, param| case directive when "stopdoc" context.stop_doc "" when "startdoc" context.start_doc context.force_documentation = true "" when "enddoc" #context.done_documenting = true #"" throw :enddoc when "main" options = Options.instance options.main_page = param "" when "title" options = Options.instance options.title = param "" when "section" context.set_current_section(param, comment) comment.replace("") # 1.8 doesn't support #clear break else warn "Unrecognized directive '#{directive}'" break end end remove_private_comments(comment) end def remove_private_comments(comment) comment.gsub!(/^#--.*?^#\+\+/m, '') comment.sub!(/^#--.*/m, '') end def get_symbol_or_name tk = get_tk case tk when TkSYMBOL tk.text.sub(/^:/, '') when TkId, TkOp tk.name when TkSTRING tk.text else raise "Name or symbol expected (got #{tk})" end end def parse_alias(context, single, tk, comment) skip_tkspace if (peek_tk.kind_of? TkLPAREN) get_tk skip_tkspace end new_name = get_symbol_or_name @scanner.instance_eval{@lex_state = EXPR_FNAME} skip_tkspace if (peek_tk.kind_of? TkCOMMA) get_tk skip_tkspace end old_name = get_symbol_or_name al = Alias.new(get_tkread, old_name, new_name, comment) read_documentation_modifiers(al, ATTR_MODIFIERS) if al.document_self context.add_alias(al) end end def parse_yield_parameters parse_method_or_yield_parameters end def parse_yield(context, single, tk, method) if method.block_params.nil? get_tkread @scanner.instance_eval{@continue = false} method.block_params = parse_yield_parameters end end def parse_require(context, comment) skip_tkspace_comment tk = get_tk if tk.kind_of? TkLPAREN skip_tkspace_comment tk = get_tk end name = nil case tk when TkSTRING name = tk.text # when TkCONSTANT, TkIDENTIFIER, TkIVAR, TkGVAR # name = tk.name when TkDSTRING warn "Skipping require of dynamic string: #{tk.text}" # else # warn "'require' used as variable" end if name context.add_require(Require.new(name, comment)) else unget_tk(tk) end end def parse_include(context, comment) loop do skip_tkspace_comment name = get_constant_with_optional_parens unless name.empty? context.add_include(Include.new(name, comment)) end return unless peek_tk.kind_of?(TkCOMMA) get_tk end end def get_bool skip_tkspace tk = get_tk case tk when TkTRUE true when TkFALSE, TkNIL false else unget_tk tk true end end def parse_attr(context, single, tk, comment) args = parse_symbol_arg(1) if args.size > 0 name = args[0] rw = "R" skip_tkspace(false) tk = get_tk if tk.kind_of? TkCOMMA rw = "RW" if get_bool else unget_tk tk end att = Attr.new(get_tkread, name, rw, comment) read_documentation_modifiers(att, ATTR_MODIFIERS) if att.document_self context.add_attribute(att) end else warn("'attr' ignored - looks like a variable") end end def parse_visibility(container, single, tk) singleton = (single == SINGLE) vis = case tk.name when "private" then :private when "protected" then :protected when "public" then :public when "private_class_method" singleton = true :private when "public_class_method" singleton = true :public else raise "Invalid visibility: #{tk.name}" end skip_tkspace_comment(false) case peek_tk # Ryan Davis suggested the extension to ignore modifiers, because he # often writes # # protected unless $TESTING # when TkNL, TkUNLESS_MOD, TkIF_MOD # error("Missing argument") if singleton container.ongoing_visibility = vis else args = parse_symbol_arg container.set_visibility_for(args, vis, singleton) end end def parse_attr_accessor(context, single, tk, comment) args = parse_symbol_arg read = get_tkread rw = "?" # If nodoc is given, don't document any of them tmp = CodeObject.new read_documentation_modifiers(tmp, ATTR_MODIFIERS) return unless tmp.document_self case tk.name when "attr_reader" then rw = "R" when "attr_writer" then rw = "W" when "attr_accessor" then rw = "RW" else rw = @options.extra_accessor_flags[tk.name] end for name in args att = Attr.new(get_tkread, name, rw, comment) context.add_attribute(att) end end def skip_tkspace_comment(skip_nl = true) loop do skip_tkspace(skip_nl) return unless peek_tk.kind_of? TkCOMMENT get_tk end end def parse_symbol_arg(no = nil) args = [] skip_tkspace_comment case tk = get_tk when TkLPAREN loop do skip_tkspace_comment if tk1 = parse_symbol_in_arg args.push tk1 break if no and args.size >= no end skip_tkspace_comment case tk2 = get_tk when TkRPAREN break when TkCOMMA else warn("unexpected token: '#{tk2.inspect}'") if $DEBUG break end end else unget_tk tk if tk = parse_symbol_in_arg args.push tk return args if no and args.size >= no end loop do # skip_tkspace_comment(false) skip_tkspace(false) tk1 = get_tk unless tk1.kind_of?(TkCOMMA) unget_tk tk1 break end skip_tkspace_comment if tk = parse_symbol_in_arg args.push tk break if no and args.size >= no end end end args end def parse_symbol_in_arg case tk = get_tk when TkSYMBOL tk.text.sub(/^:/, '') when TkSTRING eval @read[-1] else warn("Expected symbol or string, got #{tk.inspect}") if $DEBUG nil end end end end ================================================ FILE: lib/rdoc/parsers/parse_simple.rb ================================================ # Parse a non-source file. We basically take the whole thing # as one big comment. If the first character in the file # is '#', we strip leading pound signs. require "rdoc/code_objects" require "rdoc/markup/simple_markup/preprocess" module RDoc # See rdoc/parsers/parse_c.rb class SimpleParser # prepare to parse a plain file def initialize(top_level, file_name, body, options, stats) preprocess = SM::PreProcess.new(file_name, options.rdoc_include) preprocess.handle(body) do |directive, param| $stderr.puts "Unrecognized directive '#{directive}' in #{file_name}" end @body = body @options = options @top_level = top_level end # Extract the file contents and attach them to the toplevel as a # comment def scan # @body.gsub(/^(\s\n)+/, '') @top_level.comment = remove_private_comments(@body) @top_level end def remove_private_comments(comment) comment.gsub(/^--.*?^\+\+/m, '').sub(/^--.*/m, '') end end end ================================================ FILE: lib/rdoc/parsers/parserfactory.rb ================================================ require "rdoc/parsers/parse_simple" module RDoc # A parser is simple a class that implements # # #initialize(file_name, body, options) # # and # # #scan # # The initialize method takes a file name to be used, the body of the # file, and an RDoc::Options object. The scan method is then called # to return an appropriately parsed TopLevel code object. # # The ParseFactory is used to redirect to the correct parser given a filename # extension. This magic works because individual parsers have to register # themselves with us as they are loaded in. The do this using the following # incantation # # # require "rdoc/parsers/parsefactory" # # module RDoc # # class XyzParser # extend ParseFactory <<<< # parse_files_matching /\.xyz$/ <<<< # # def initialize(file_name, body, options) # ... # end # # def scan # ... # end # end # end # # Just to make life interesting, if we suspect a plain text file, we # also look for a shebang line just in case it's a potential # shell script module ParserFactory @@parsers = [] Parsers = Struct.new(:regexp, :parser) # Record the fact that a particular class parses files that # match a given extension def parse_files_matching(regexp) @@parsers.unshift Parsers.new(regexp, self) end # Return a parser that can handle a particular extension def ParserFactory.can_parse(file_name) @@parsers.find {|p| p.regexp.match(file_name) } end # Alias an extension to another extension. After this call, # files ending "new_ext" will be parsed using the same parser # as "old_ext" def ParserFactory.alias_extension(old_ext, new_ext) parser = ParserFactory.can_parse("xxx.#{old_ext}") return false unless parser @@parsers.unshift Parsers.new(Regexp.new("\\.#{new_ext}$"), parser.parser) true end # Find the correct parser for a particular file name. Return a # SimpleParser for ones that we don't know def ParserFactory.parser_for(top_level, file_name, body, options, stats) # If no extension, look for shebang if file_name !~ /\.\w+$/ && body =~ %r{\A#!(.+)} shebang = $1 case shebang when %r{env\s+ruby}, %r{/ruby} file_name = "dummy.rb" end end parser_description = can_parse(file_name) if parser_description parser = parser_description.parser else parser = SimpleParser end parser.new(top_level, file_name, body, options, stats) end end end ================================================ FILE: lib/rdoc/rdoc.rb ================================================ # See README. # VERSION_STRING = %{RDoc V1.0.1 - 20041108} require 'rdoc/parsers/parse_rb.rb' require 'rdoc/parsers/parse_c.rb' require 'rdoc/parsers/parse_f95.rb' require 'rdoc/parsers/parse_simple.rb' require 'rdoc/options' require 'rdoc/diagram' require 'find' require 'ftools' require 'time' # We put rdoc stuff in the RDoc module to avoid namespace # clutter. # # ToDo: This isn't universally true. # # :include: README module RDoc # Name of the dotfile that contains the description of files to be # processed in the current directory DOT_DOC_FILENAME = ".document" # Simple stats collector class Stats attr_accessor :num_files, :num_classes, :num_modules, :num_methods def initialize @num_files = @num_classes = @num_modules = @num_methods = 0 @start = Time.now end def print puts "Files: #@num_files" puts "Classes: #@num_classes" puts "Modules: #@num_modules" puts "Methods: #@num_methods" puts "Elapsed: " + sprintf("%0.3fs", Time.now - @start) end end # Exception thrown by any rdoc error. Only the #message part is # of use externally. class RDocError < Exception end # Encapsulate the production of rdoc documentation. Basically # you can use this as you would invoke rdoc from the command # line: # # rdoc = RDoc::RDoc.new # rdoc.document(args) # # where _args_ is an array of strings, each corresponding to # an argument you'd give rdoc on the command line. See rdoc/rdoc.rb # for details. class RDoc ## # This is the list of output generators that we # support Generator = Struct.new(:file_name, :class_name, :key) GENERATORS = {} $:.collect {|d| File::expand_path(d) }.find_all {|d| File::directory?("#{d}/rdoc/generators") }.each {|dir| Dir::entries("#{dir}/rdoc/generators").each {|gen| next unless /(\w+)_generator.rb$/ =~ gen type = $1 unless GENERATORS.has_key? type GENERATORS[type] = Generator.new("rdoc/generators/#{gen}", "#{type.upcase}Generator".intern, type) end } } ####### private ####### ## # Report an error message and exit def error(msg) raise RDocError.new(msg) end ## # Create an output dir if it doesn't exist. If it does # exist, but doesn't contain the flag file created.rid # then we refuse to use it, as we may clobber some # manually generated documentation def setup_output_dir(op_dir, force) flag_file = output_flag_file(op_dir) if File.exist?(op_dir) unless File.directory?(op_dir) error "'#{op_dir}' exists, and is not a directory" end begin created = File.read(flag_file) rescue SystemCallError error "\nDirectory #{op_dir} already exists, but it looks like it\n" + "isn't an RDoc directory. Because RDoc doesn't want to risk\n" + "destroying any of your existing files, you'll need to\n" + "specify a different output directory name (using the\n" + "--op option).\n\n" else last = (Time.parse(created) unless force rescue nil) end else File.makedirs(op_dir) end last end # Update the flag file in an output directory. def update_output_dir(op_dir, time) File.open(output_flag_file(op_dir), "w") {|f| f.puts time.rfc2822 } end # Return the path name of the flag file in an output directory. def output_flag_file(op_dir) File.join(op_dir, "created.rid") end # The .document file contains a list of file and directory name # patterns, representing candidates for documentation. It may # also contain comments (starting with '#') def parse_dot_doc_file(in_dir, filename, options) # read and strip comments patterns = File.read(filename).gsub(/#.*/, '') result = [] patterns.split.each do |patt| candidates = Dir.glob(File.join(in_dir, patt)) result.concat(normalized_file_list(options, candidates)) end result end # Given a list of files and directories, create a list # of all the Ruby files they contain. # # If +force_doc+ is true, we always add the given files. # If false, only add files that we guarantee we can parse # It is true when looking at files given on the command line, # false when recursing through subdirectories. # # The effect of this is that if you want a file with a non- # standard extension parsed, you must name it explicity. # def normalized_file_list(options, relative_files, force_doc = false, exclude_pattern=nil) file_list = [] relative_files.each do |rel_file_name| next if exclude_pattern && exclude_pattern =~ rel_file_name stat = File.stat(rel_file_name) case type = stat.ftype when "file" next if @last_created and stat.mtime < @last_created file_list << rel_file_name.sub(/^\.\//, '') if force_doc || ParserFactory.can_parse(rel_file_name) when "directory" next if rel_file_name == "CVS" || rel_file_name == ".svn" dot_doc = File.join(rel_file_name, DOT_DOC_FILENAME) if File.file?(dot_doc) file_list.concat(parse_dot_doc_file(rel_file_name, dot_doc, options)) else file_list.concat(list_files_in_directory(rel_file_name, options)) end else raise RDocError.new("I can't deal with a #{type} #{rel_file_name}") end end file_list end # Return a list of the files to be processed in # a directory. We know that this directory doesn't have # a .document file, so we're looking for real files. However # we may well contain subdirectories which must # be tested for .document files def list_files_in_directory(dir, options) normalized_file_list(options, Dir.glob(File.join(dir, "*")), false, options.exclude) end # Parse each file on the command line, recursively entering # directories def parse_files(options) file_info = [] files = options.files files = ["."] if files.empty? file_list = normalized_file_list(options, files, true) file_list.each do |fn| $stderr.printf("\n%35s: ", File.basename(fn)) unless options.quiet content = File.open(fn, "r") {|f| f.read} top_level = TopLevel.new(fn) parser = ParserFactory.parser_for(top_level, fn, content, options, @stats) file_info << parser.scan @stats.num_files += 1 end file_info end public ################################################################### # # Format up one or more files according to the given arguments. # For simplicity, _argv_ is an array of strings, equivalent to the # strings that would be passed on the command line. (This isn't a # coincidence, as we _do_ pass in ARGV when running # interactively). For a list of options, see rdoc/rdoc.rb. By # default, output will be stored in a directory called +doc+ below # the current directory, so make sure you're somewhere writable # before invoking. # # Throws: RDocError on error def document(argv) TopLevel::reset @stats = Stats.new options = Options.instance options.parse(argv, GENERATORS) @last_created = nil unless options.all_one_file @last_created = setup_output_dir(options.op_dir, options.force_update) end start_time = Time.now file_info = parse_files(options) if file_info.empty? $stderr.puts "\nNo newer files." unless options.quiet else gen = options.generator $stderr.puts "\nGenerating #{gen.key.upcase}..." unless options.quiet require gen.file_name gen_class = Generators.const_get(gen.class_name) gen = gen_class.for(options) pwd = Dir.pwd Dir.chdir(options.op_dir) unless options.all_one_file begin Diagram.new(file_info, options).draw if options.diagram gen.generate(file_info) update_output_dir(".", start_time) ensure Dir.chdir(pwd) end end unless options.quiet puts @stats.print end end end end ================================================ FILE: lib/rdoc/ri/ri_cache.rb ================================================ module RI class ClassEntry attr_reader :name attr_reader :path_names def initialize(path_name, name, in_class) @path_names = [ path_name ] @name = name @in_class = in_class @class_methods = [] @instance_methods = [] @inferior_classes = [] end # We found this class in more tha one place, so add # in the name from there. def add_path(path) @path_names << path end # read in our methods and any classes # and modules in our namespace. Methods are # stored in files called name-c|i.yaml, # where the 'name' portion is the external # form of the method name and the c|i is a class|instance # flag def load_from(dir) Dir.foreach(dir) do |name| next if name =~ /^\./ # convert from external to internal form, and # extract the instance/class flag if name =~ /^(.*?)-(c|i).yaml$/ external_name = $1 is_class_method = $2 == "c" internal_name = RiWriter.external_to_internal(external_name) list = is_class_method ? @class_methods : @instance_methods path = File.join(dir, name) list << MethodEntry.new(path, internal_name, is_class_method, self) else full_name = File.join(dir, name) if File.directory?(full_name) inf_class = @inferior_classes.find {|c| c.name == name } if inf_class inf_class.add_path(full_name) else inf_class = ClassEntry.new(full_name, name, self) @inferior_classes << inf_class end inf_class.load_from(full_name) end end end end # Return a list of any classes or modules that we contain # that match a given string def contained_modules_matching(name) @inferior_classes.find_all {|c| c.name[name]} end def classes_and_modules @inferior_classes end # Return an exact match to a particular name def contained_class_named(name) @inferior_classes.find {|c| c.name == name} end # return the list of local methods matching name # We're split into two because we need distinct behavior # when called from the _toplevel_ def methods_matching(name, is_class_method) local_methods_matching(name, is_class_method) end # Find methods matching 'name' in ourselves and in # any classes we contain def recursively_find_methods_matching(name, is_class_method) res = local_methods_matching(name, is_class_method) @inferior_classes.each do |c| res.concat(c.recursively_find_methods_matching(name, is_class_method)) end res end # Return our full name def full_name res = @in_class.full_name res << "::" unless res.empty? res << @name end # Return a list of all out method names def all_method_names res = @class_methods.map {|m| m.full_name } @instance_methods.each {|m| res << m.full_name} res end private # Return a list of all our methods matching a given string. # Is +is_class_methods+ if 'nil', we don't care if the method # is a class method or not, otherwise we only return # those methods that match def local_methods_matching(name, is_class_method) list = case is_class_method when nil then @class_methods + @instance_methods when true then @class_methods when false then @instance_methods else fail "Unknown is_class_method: #{is_class_method.inspect}" end list.find_all {|m| m.name; m.name[name]} end end # A TopLevelEntry is like a class entry, but when asked to search # for methods searches all classes, not just itself class TopLevelEntry < ClassEntry def methods_matching(name, is_class_method) res = recursively_find_methods_matching(name, is_class_method) end def full_name "" end def module_named(name) end end class MethodEntry attr_reader :name attr_reader :path_name def initialize(path_name, name, is_class_method, in_class) @path_name = path_name @name = name @is_class_method = is_class_method @in_class = in_class end def full_name res = @in_class.full_name unless res.empty? if @is_class_method res << "::" else res << "#" end end res << @name end end # We represent everything know about all 'ri' files # accessible to this program class RiCache attr_reader :toplevel def initialize(dirs) # At the top level we have a dummy module holding the # overall namespace @toplevel = TopLevelEntry.new('', '::', nil) dirs.each do |dir| @toplevel.load_from(dir) end end end end ================================================ FILE: lib/rdoc/ri/ri_descriptions.rb ================================================ require 'yaml' require 'rdoc/markup/simple_markup/fragments' # Descriptions are created by RDoc (in ri_generator) and # written out in serialized form into the documentation # tree. ri then reads these to generate the documentation module RI class NamedThing attr_reader :name def initialize(name) @name = name end def <=>(other) @name <=> other.name end def hash @name.hash end def eql?(other) @name.eql?(other) end end # Alias = Struct.new(:old_name, :new_name) class AliasName < NamedThing end class Attribute < NamedThing attr_reader :rw, :comment def initialize(name, rw, comment) super(name) @rw = rw @comment = comment end end class Constant < NamedThing attr_reader :value, :comment def initialize(name, value, comment) super(name) @value = value @comment = comment end end class IncludedModule < NamedThing end class MethodSummary < NamedThing def initialize(name="") super end end class Description attr_accessor :name attr_accessor :full_name attr_accessor :comment def serialize self.to_yaml end def Description.deserialize(from) YAML.load(from) end def <=>(other) @name <=> other.name end end class ModuleDescription < Description attr_accessor :class_methods attr_accessor :instance_methods attr_accessor :attributes attr_accessor :constants attr_accessor :includes # merge in another class desscription into this one def merge_in(old) merge(@class_methods, old.class_methods) merge(@instance_methods, old.instance_methods) merge(@attributes, old.attributes) merge(@constants, old.constants) merge(@includes, old.includes) if @comment.nil? || @comment.empty? @comment = old.comment else unless old.comment.nil? or old.comment.empty? then @comment << SM::Flow::RULE.new @comment.concat old.comment end end end def display_name "Module" end # the 'ClassDescription' subclass overrides this # to format up the name of a parent def superclass_string nil end private def merge(into, from) names = {} into.each {|i| names[i.name] = i } from.each {|i| names[i.name] = i } into.replace(names.keys.sort.map {|n| names[n]}) end end class ClassDescription < ModuleDescription attr_accessor :superclass def display_name "Class" end def superclass_string if @superclass && @superclass != "Object" @superclass else nil end end end class MethodDescription < Description attr_accessor :is_class_method attr_accessor :visibility attr_accessor :block_params attr_accessor :is_singleton attr_accessor :aliases attr_accessor :is_alias_for attr_accessor :params end end ================================================ FILE: lib/rdoc/ri/ri_display.rb ================================================ require 'rdoc/ri/ri_util' require 'rdoc/ri/ri_formatter' require 'rdoc/ri/ri_options' # This is a kind of 'flag' module. If you want to write your # own 'ri' display module (perhaps because you'r writing # an IDE or somesuch beast), you simply write a class # which implements the various 'display' methods in 'DefaultDisplay', # and include the 'RiDisplay' module in that class. # # To access your class from the command line, you can do # # ruby -r ../ri .... # # If folks _really_ want to do this from the command line, # I'll build an option in module RiDisplay @@display_class = nil def RiDisplay.append_features(display_class) @@display_class = display_class end def RiDisplay.new(*args) @@display_class.new(*args) end end ###################################################################### # # A paging display module. Uses the ri_formatter class to do the # actual presentation # class DefaultDisplay include RiDisplay def initialize(options) @options = options @formatter = @options.formatter.new(@options, " ") end ###################################################################### def display_usage page do RI::Options::OptionList.usage(short_form=true) end end ###################################################################### def display_method_info(method) page do @formatter.draw_line(method.full_name) display_params(method) @formatter.draw_line display_flow(method.comment) if method.aliases && !method.aliases.empty? @formatter.blankline aka = "(also known as " aka << method.aliases.map {|a| a.name }.join(", ") aka << ")" @formatter.wrap(aka) end end end ###################################################################### def display_class_info(klass, ri_reader) page do superclass = klass.superclass_string if superclass superclass = " < " + superclass else superclass = "" end @formatter.draw_line(klass.display_name + ": " + klass.full_name + superclass) display_flow(klass.comment) @formatter.draw_line unless klass.includes.empty? @formatter.blankline @formatter.display_heading("Includes:", 2, "") incs = [] klass.includes.each do |inc| inc_desc = ri_reader.find_class_by_name(inc.name) if inc_desc str = inc.name + "(" str << inc_desc.instance_methods.map{|m| m.name}.join(", ") str << ")" incs << str else incs << inc.name end end @formatter.wrap(incs.sort.join(', ')) end unless klass.constants.empty? @formatter.blankline @formatter.display_heading("Constants:", 2, "") len = 0 klass.constants.each { |c| len = c.name.length if c.name.length > len } len += 2 klass.constants.each do |c| @formatter.wrap(c.value, @formatter.indent+((c.name+":").ljust(len))) end end unless klass.class_methods.empty? @formatter.blankline @formatter.display_heading("Class methods:", 2, "") @formatter.wrap(klass.class_methods.map{|m| m.name}.sort.join(', ')) end unless klass.instance_methods.empty? @formatter.blankline @formatter.display_heading("Instance methods:", 2, "") @formatter.wrap(klass.instance_methods.map{|m| m.name}.sort.join(', ')) end unless klass.attributes.empty? @formatter.blankline @formatter.wrap("Attributes:", "") @formatter.wrap(klass.attributes.map{|a| a.name}.sort.join(', ')) end end end ###################################################################### # Display a list of method names def display_method_list(methods) page do puts "More than one method matched your request. You can refine" puts "your search by asking for information on one of:\n\n" @formatter.wrap(methods.map {|m| m.full_name} .join(", ")) end end ###################################################################### def display_class_list(namespaces) page do puts "More than one class or module matched your request. You can refine" puts "your search by asking for information on one of:\n\n" @formatter.wrap(namespaces.map {|m| m.full_name}.join(", ")) end end ###################################################################### def list_known_classes(classes) if classes.empty? warn_no_database else page do @formatter.draw_line("Known classes and modules") @formatter.blankline @formatter.wrap(classes.sort.join(", ")) end end end ###################################################################### def list_known_names(names) if names.empty? warn_no_database else page do names.each {|n| @formatter.raw_print_line(n)} end end end ###################################################################### private ###################################################################### def page return yield unless pager = setup_pager begin save_stdout = STDOUT.clone STDOUT.reopen(pager) yield ensure STDOUT.reopen(save_stdout) save_stdout.close pager.close end end ###################################################################### def setup_pager unless @options.use_stdout for pager in [ ENV['PAGER'], "less", "more", 'pager' ].compact.uniq return IO.popen(pager, "w") rescue nil end @options.use_stdout = true nil end end ###################################################################### def display_params(method) params = method.params if params[0,1] == "(" if method.is_singleton params = method.full_name + params else params = method.name + params end end params.split(/\n/).each do |p| @formatter.wrap(p) @formatter.break_to_newline end end ###################################################################### def display_flow(flow) if !flow || flow.empty? @formatter.wrap("(no description...)") else @formatter.display_flow(flow) end end ###################################################################### def warn_no_database puts "Before using ri, you need to generate documentation" puts "using 'rdoc' with the --ri option" end end # class RiDisplay ================================================ FILE: lib/rdoc/ri/ri_driver.rb ================================================ require 'rdoc/ri/ri_paths' require 'rdoc/usage' require 'rdoc/ri/ri_cache' require 'rdoc/ri/ri_util' require 'rdoc/ri/ri_reader' require 'rdoc/ri/ri_formatter' require 'rdoc/ri/ri_options' ###################################################################### class RiDriver def initialize @options = RI::Options.instance args = ARGV if ENV["RI"] args = ENV["RI"].split.concat(ARGV) end @options.parse(args) path = @options.path report_missing_documentation @options.raw_path if path.empty? @ri_reader = RI::RiReader.new(RI::RiCache.new(path)) @display = @options.displayer end # Couldn't find documentation in +path+, so tell the user what to do def report_missing_documentation(path) STDERR.puts "No ri documentation found in:" path.each do |d| STDERR.puts " #{d}" end STDERR.puts "\nWas rdoc run to create documentation?\n\n" RDoc::usage("Installing Documentation") end ###################################################################### # If the list of matching methods contains exactly one entry, or # if it contains an entry that exactly matches the requested method, # then display that entry, otherwise display the list of # matching method names def report_method_stuff(requested_method_name, methods) if methods.size == 1 method = @ri_reader.get_method(methods[0]) @display.display_method_info(method) else entries = methods.find_all {|m| m.name == requested_method_name} if entries.size == 1 method = @ri_reader.get_method(entries[0]) @display.display_method_info(method) else @display.display_method_list(methods) end end end ###################################################################### def report_class_stuff(namespaces) if namespaces.size == 1 klass = @ri_reader.get_class(namespaces[0]) @display.display_class_info(klass, @ri_reader) else # entries = namespaces.find_all {|m| m.full_name == requested_class_name} # if entries.size == 1 # klass = @ri_reader.get_class(entries[0]) # @display.display_class_info(klass, @ri_reader) # else @display.display_class_list(namespaces) # end end end ###################################################################### def get_info_for(arg) desc = NameDescriptor.new(arg) namespaces = @ri_reader.top_level_namespace for class_name in desc.class_names namespaces = @ri_reader.lookup_namespace_in(class_name, namespaces) if namespaces.empty? raise RiError.new("Nothing known about #{arg}") end end # at this point, if we have multiple possible namespaces, but one # is an exact match for our requested class, prune down to just it full_class_name = desc.full_class_name entries = namespaces.find_all {|m| m.full_name == full_class_name} namespaces = entries if entries.size == 1 if desc.method_name.nil? report_class_stuff(namespaces) else methods = @ri_reader.find_methods(desc.method_name, desc.is_class_method, namespaces) if methods.empty? raise RiError.new("Nothing known about #{arg}") else report_method_stuff(desc.method_name, methods) end end end ###################################################################### def process_args if @options.list_classes classes = @ri_reader.full_class_names @display.list_known_classes(classes) elsif @options.list_names names = @ri_reader.all_names @display.list_known_names(names) else if ARGV.size.zero? @display.display_usage else begin ARGV.each do |arg| get_info_for(arg) end rescue RiError => e STDERR.puts(e.message) exit(1) end end end end end # class RiDriver ================================================ FILE: lib/rdoc/ri/ri_formatter.rb ================================================ module RI class TextFormatter attr_reader :indent def initialize(options, indent) @options = options @width = options.width @indent = indent end ###################################################################### def draw_line(label=nil) len = @width len -= (label.size+1) if label print "-"*len if label print(" ") bold_print(label) end puts end ###################################################################### def wrap(txt, prefix=@indent, linelen=@width) return unless txt && !txt.empty? work = conv_markup(txt) textLen = linelen - prefix.length patt = Regexp.new("^(.{0,#{textLen}})[ \n]") next_prefix = prefix.tr("^ ", " ") res = [] while work.length > textLen if work =~ patt res << $1 work.slice!(0, $&.length) else res << work.slice!(0, textLen) end end res << work if work.length.nonzero? puts(prefix + res.join("\n" + next_prefix)) end ###################################################################### def blankline puts end ###################################################################### # called when we want to ensure a nbew 'wrap' starts on a newline # Only needed for HtmlFormatter, because the rest do their # own line breaking def break_to_newline end ###################################################################### def bold_print(txt) print txt end ###################################################################### def raw_print_line(txt) puts txt end ###################################################################### # convert HTML entities back to ASCII def conv_html(txt) txt. gsub(/>/, '>'). gsub(/</, '<'). gsub(/"/, '"'). gsub(/&/, '&') end # convert markup into display form def conv_markup(txt) txt. gsub(%r{(.*?)}) { "+#$1+" } . gsub(%r{(.*?)}) { "+#$1+" } . gsub(%r{(.*?)}) { "*#$1*" } . gsub(%r{(.*?)}) { "_#$1_" } end ###################################################################### def display_list(list) case list.type when SM::ListBase::BULLET prefixer = proc { |ignored| @indent + "* " } when SM::ListBase::NUMBER, SM::ListBase::UPPERALPHA, SM::ListBase::LOWERALPHA start = case list.type when SM::ListBase::NUMBER then 1 when SM::ListBase::UPPERALPHA then 'A' when SM::ListBase::LOWERALPHA then 'a' end prefixer = proc do |ignored| res = @indent + "#{start}.".ljust(4) start = start.succ res end when SM::ListBase::LABELED prefixer = proc do |li| li.label end when SM::ListBase::NOTE longest = 0 list.contents.each do |item| if item.kind_of?(SM::Flow::LI) && item.label.length > longest longest = item.label.length end end prefixer = proc do |li| @indent + li.label.ljust(longest+1) end else fail "unknown list type" end list.contents.each do |item| if item.kind_of? SM::Flow::LI prefix = prefixer.call(item) display_flow_item(item, prefix) else display_flow_item(item) end end end ###################################################################### def display_flow_item(item, prefix=@indent) case item when SM::Flow::P, SM::Flow::LI wrap(conv_html(item.body), prefix) blankline when SM::Flow::LIST display_list(item) when SM::Flow::VERB display_verbatim_flow_item(item, @indent) when SM::Flow::H display_heading(conv_html(item.text), item.level, @indent) when SM::Flow::RULE draw_line else fail "Unknown flow element: #{item.class}" end end ###################################################################### def display_verbatim_flow_item(item, prefix=@indent) item.body.split(/\n/).each do |line| print @indent, conv_html(line), "\n" end blankline end ###################################################################### def display_heading(text, level, indent) text = strip_attributes(text) case level when 1 ul = "=" * text.length puts puts text.upcase puts ul # puts when 2 ul = "-" * text.length puts puts text puts ul # puts else print indent, text, "\n" end end def display_flow(flow) flow.each do |f| display_flow_item(f) end end def strip_attributes(txt) tokens = txt.split(%r{()}) text = [] attributes = 0 tokens.each do |tok| case tok when %r{^$}, %r{^<(\w+)>$} ; else text << tok end end text.join end end ###################################################################### # Handle text with attributes. We're a base class: there are # different presentation classes (one, for example, uses overstrikes # to handle bold and underlining, while another using ANSI escape # sequences class AttributeFormatter < TextFormatter BOLD = 1 ITALIC = 2 CODE = 4 ATTR_MAP = { "b" => BOLD, "code" => CODE, "em" => ITALIC, "i" => ITALIC, "tt" => CODE } # TODO: struct? class AttrChar attr_reader :char attr_reader :attr def initialize(char, attr) @char = char @attr = attr end end class AttributeString attr_reader :txt def initialize @txt = [] @optr = 0 end def <<(char) @txt << char end def empty? @optr >= @txt.length end # accept non space, then all following spaces def next_word start = @optr len = @txt.length while @optr < len && @txt[@optr].char != " " @optr += 1 end while @optr < len && @txt[@optr].char == " " @optr += 1 end @txt[start...@optr] end end ###################################################################### # overrides base class. Looks for ... etc sequences # and generates an array of AttrChars. This array is then used # as the basis for the split def wrap(txt, prefix=@indent, linelen=@width) return unless txt && !txt.empty? txt = add_attributes_to(txt) next_prefix = prefix.tr("^ ", " ") linelen -= prefix.size line = [] until txt.empty? word = txt.next_word if word.size + line.size > linelen write_attribute_text(prefix, line) prefix = next_prefix line = [] end line.concat(word) end write_attribute_text(prefix, line) if line.length > 0 end protected # overridden in specific formatters def write_attribute_text(prefix, line) print prefix line.each do |achar| print achar.char end puts end # again, overridden def bold_print(txt) print txt end private def add_attributes_to(txt) tokens = txt.split(%r{()}) text = AttributeString.new attributes = 0 tokens.each do |tok| case tok when %r{^$} then attributes &= ~(ATTR_MAP[$1]||0) when %r{^<(\w+)>$} then attributes |= (ATTR_MAP[$1]||0) else tok.split(//).each {|ch| text << AttrChar.new(ch, attributes)} end end text end end ################################################## # This formatter generates overstrike-style formatting, which # works with pagers such as man and less. class OverstrikeFormatter < AttributeFormatter BS = "\C-h" def write_attribute_text(prefix, line) print prefix line.each do |achar| attr = achar.attr if (attr & (ITALIC+CODE)) != 0 print "_", BS end if (attr & BOLD) != 0 print achar.char, BS end print achar.char end puts end # draw a string in bold def bold_print(text) text.split(//).each do |ch| print ch, BS, ch end end end ################################################## # This formatter uses ANSI escape sequences # to colorize stuff # works with pages such as man and less. class AnsiFormatter < AttributeFormatter def initialize(*args) print "\033[0m" super end def write_attribute_text(prefix, line) print prefix curr_attr = 0 line.each do |achar| attr = achar.attr if achar.attr != curr_attr update_attributes(achar.attr) curr_attr = achar.attr end print achar.char end update_attributes(0) unless curr_attr.zero? puts end def bold_print(txt) print "\033[1m#{txt}\033[m" end HEADINGS = { 1 => [ "\033[1;32m", "\033[m" ] , 2 => ["\033[4;32m", "\033[m" ], 3 => ["\033[32m", "\033[m" ] } def display_heading(text, level, indent) level = 3 if level > 3 heading = HEADINGS[level] print indent print heading[0] print strip_attributes(text) puts heading[1] end private ATTR_MAP = { BOLD => "1", ITALIC => "33", CODE => "36" } def update_attributes(attr) str = "\033[" for quality in [ BOLD, ITALIC, CODE] unless (attr & quality).zero? str << ATTR_MAP[quality] end end print str, "m" end end ################################################## # This formatter uses HTML. class HtmlFormatter < AttributeFormatter def initialize(*args) super end def write_attribute_text(prefix, line) curr_attr = 0 line.each do |achar| attr = achar.attr if achar.attr != curr_attr update_attributes(curr_attr, achar.attr) curr_attr = achar.attr end print(escape(achar.char)) end update_attributes(curr_attr, 0) unless curr_attr.zero? end def draw_line(label=nil) if label != nil bold_print(label) end puts("
      ") end def bold_print(txt) tag("b") { txt } end def blankline() puts("

      ") end def break_to_newline puts("
      ") end def display_heading(text, level, indent) level = 4 if level > 4 tag("h#{level}") { text } puts end ###################################################################### def display_list(list) case list.type when SM::ListBase::BULLET list_type = "ul" prefixer = proc { |ignored| "

    • " } when SM::ListBase::NUMBER, SM::ListBase::UPPERALPHA, SM::ListBase::LOWERALPHA list_type = "ol" prefixer = proc { |ignored| "
    • " } when SM::ListBase::LABELED list_type = "dl" prefixer = proc do |li| "
      " + escape(li.label) + "
      " end when SM::ListBase::NOTE list_type = "table" prefixer = proc do |li| %{#{li.label.gsub(/ /, ' ')}} end else fail "unknown list type" end print "<#{list_type}>" list.contents.each do |item| if item.kind_of? SM::Flow::LI prefix = prefixer.call(item) print prefix display_flow_item(item, prefix) else display_flow_item(item) end end print "" end def display_verbatim_flow_item(item, prefix=@indent) print("
      ")
              puts item.body
              puts("
      ") end private ATTR_MAP = { BOLD => "b>", ITALIC => "i>", CODE => "tt>" } def update_attributes(current, wanted) str = "" # first turn off unwanted ones off = current & ~wanted for quality in [ BOLD, ITALIC, CODE] if (off & quality) > 0 str << "") print(yield) print("") end def escape(str) str. gsub(/&/n, '&'). gsub(/\"/n, '"'). gsub(/>/n, '>'). gsub(/ AnsiFormatter, "bs" => OverstrikeFormatter, "html" => HtmlFormatter, "plain" => TextFormatter, "simple" => SimpleFormatter, } def TextFormatter.list FORMATTERS.keys.sort.join(", ") end def TextFormatter.for(name) FORMATTERS[name.downcase] end end end ================================================ FILE: lib/rdoc/ri/ri_options.rb ================================================ # We handle the parsing of options, and subsequently as a singleton # object to be queried for option values module RI require 'rdoc/ri/ri_paths' require 'rdoc/ri/ri_display' VERSION_STRING = "ri v1.0.1 - 20041108" class Options require 'singleton' require 'getoptlong' include Singleton # No not use a pager. Writable, because ri sets it if it # can't find a pager attr_accessor :use_stdout # should we just display a class list and exit attr_reader :list_classes # should we display a list of all names attr_reader :list_names # The width of the output line attr_reader :width # the formatting we apply to the output attr_reader :formatter # the directory we search for original documentation attr_reader :doc_dir module OptionList OPTION_LIST = [ [ "--help", "-h", nil, "you're looking at it" ], [ "--classes", "-c", nil, "Display the names of classes and modules we\n" + "know about"], [ "--doc-dir", "-d", "", "A directory to search for documentation. If not\n" + "specified, we search the standard rdoc/ri directories.\n" + "May be repeated."], [ "--system", nil, nil, "Include documentation from Ruby's standard library:\n " + RI::Paths::SYSDIR ], [ "--site", nil, nil, "Include documentation from libraries installed in site_lib:\n " + RI::Paths::SITEDIR ], [ "--home", nil, nil, "Include documentation stored in ~/.rdoc:\n " + (RI::Paths::HOMEDIR || "No ~/.rdoc found") ], [ "--gems", nil, nil, "Include documentation from RubyGems:\n" + (RI::Paths::GEMDIRS ? Gem.path.map { |dir| " #{dir}/doc/*/ri" }.join("\n") : "No Rubygems ri found.") ], [ "--format", "-f", "", "Format to use when displaying output:\n" + " " + RI::TextFormatter.list + "\n" + "Use 'bs' (backspace) with most pager programs.\n" + "To use ANSI, either also use the -T option, or\n" + "tell your pager to allow control characters\n" + "(for example using the -R option to less)"], [ "--list-names", "-l", nil, "List all the names known to RDoc, one per line" ], [ "--no-pager", "-T", nil, "Send output directly to stdout." ], [ "--width", "-w", "output width", "Set the width of the output" ], [ "--version", "-v", nil, "Display the version of ri" ], ] def OptionList.options OPTION_LIST.map do |long, short, arg,| option = [] option << long option << short unless short.nil? option << (arg ? GetoptLong::REQUIRED_ARGUMENT : GetoptLong::NO_ARGUMENT) option end end def OptionList.strip_output(text) text =~ /^\s+/ leading_spaces = $& text.gsub!(/^#{leading_spaces}/, '') $stdout.puts text end # Show an error and exit def OptionList.error(msg) $stderr.puts $stderr.puts msg name = File.basename $PROGRAM_NAME $stderr.puts "\nFor help on options, try '#{name} --help'\n\n" exit 1 end # Show usage and exit def OptionList.usage(short_form=false) puts puts(RI::VERSION_STRING) puts name = File.basename($0) directories = [ RI::Paths::SYSDIR, RI::Paths::SITEDIR, RI::Paths::HOMEDIR ] if RI::Paths::GEMDIRS then Gem.path.each do |dir| directories << "#{dir}/doc/*/ri" end end directories = directories.join("\n ") OptionList.strip_output(<<-EOT) Usage: #{name} [options] [names...] Display information on Ruby classes, modules, and methods. Give the names of classes or methods to see their documentation. Partial names may be given: if the names match more than one entity, a list will be shown, otherwise details on that entity will be displayed. Nested classes and modules can be specified using the normal Name::Name notation, and instance methods can be distinguished from class methods using "." (or "#") instead of "::". For example: #{name} File #{name} File.new #{name} F.n #{name} zip Note that shell quoting may be required for method names containing punctuation: #{name} 'Array.[]' #{name} compact\\! By default ri searches for documentation in the following directories: #{directories} Specifying the --system, --site, --home, --gems or --doc-dir options will limit ri to searching only the specified directories. EOT if short_form puts "For help on options, type '#{name} -h'" puts "For a list of classes I know about, type '#{name} -c'" else puts "Options:\n\n" OPTION_LIST.each do|long, short, arg, desc| opt = '' opt << (short ? sprintf("%15s", "#{long}, #{short}") : sprintf("%15s", long)) if arg opt << " " << arg end print opt desc = desc.split("\n") if opt.size < 17 print " "*(18-opt.size) puts desc.shift else puts end desc.each do |line| puts(" "*18 + line) end puts end puts "Options may also be passed in the 'RI' environment variable" exit 0 end end end # Show the version and exit def show_version puts VERSION_STRING exit(0) end def initialize @use_stdout = !STDOUT.tty? @width = 72 @formatter = RI::TextFormatter.for("plain") @list_classes = false @list_names = false # By default all paths are used. If any of these are true, only those # directories are used. @use_system = false @use_site = false @use_home = false @use_gems = false @doc_dirs = [] end # Parse command line options. def parse(args) old_argv = ARGV.dup ARGV.replace(args) begin go = GetoptLong.new(*OptionList.options) go.quiet = true go.each do |opt, arg| case opt when "--help" then OptionList.usage when "--version" then show_version when "--list-names" then @list_names = true when "--no-pager" then @use_stdout = true when "--classes" then @list_classes = true when "--system" then @use_system = true when "--site" then @use_site = true when "--home" then @use_home = true when "--gems" then @use_gems = true when "--doc-dir" if File.directory?(arg) @doc_dirs << arg else $stderr.puts "Invalid directory: #{arg}" exit 1 end when "--format" @formatter = RI::TextFormatter.for(arg) unless @formatter $stderr.print "Invalid formatter (should be one of " $stderr.puts RI::TextFormatter.list + ")" exit 1 end when "--width" begin @width = Integer(arg) rescue $stderr.puts "Invalid width: '#{arg}'" exit 1 end end end rescue GetoptLong::InvalidOption, GetoptLong::MissingArgument => error OptionList.error(error.message) end end # Return the selected documentation directories. def path RI::Paths.path(@use_system, @use_site, @use_home, @use_gems, *@doc_dirs) end def raw_path RI::Paths.raw_path(@use_system, @use_site, @use_home, @use_gems, *@doc_dirs) end # Return an instance of the displayer (the thing that actually writes # the information). This allows us to load in new displayer classes # at runtime (for example to help with IDE integration) def displayer ::RiDisplay.new(self) end end end ================================================ FILE: lib/rdoc/ri/ri_paths.rb ================================================ module RI # Encapsulate all the strangeness to do with finding out # where to find RDoc files # # We basically deal with three directories: # # 1. The 'system' documentation directory, which holds # the documentation distributed with Ruby, and which # is managed by the Ruby install process # 2. The 'site' directory, which contains site-wide # documentation added locally. # 3. The 'user' documentation directory, stored under the # user's own home directory. # # There's contention about all this, but for now: # # system:: $datadir/ri//system/... # site:: $datadir/ri//site/... # user:: ~/.rdoc module Paths #:stopdoc: require 'rbconfig' DOC_DIR = "doc/rdoc" version = Config::CONFIG['ruby_version'] base = File.join(Config::CONFIG['datadir'], "ri", version) SYSDIR = File.join(base, "system") SITEDIR = File.join(base, "site") homedir = ENV['HOME'] || ENV['USERPROFILE'] || ENV['HOMEPATH'] if homedir HOMEDIR = File.join(homedir, ".rdoc") else HOMEDIR = nil end # This is the search path for 'ri' PATH = [ SYSDIR, SITEDIR, HOMEDIR ].find_all {|p| p && File.directory?(p)} begin require 'rubygems' # HACK dup'd from Gem.latest_partials and friends all_paths = [] all_paths = Gem.path.map do |dir| Dir[File.join(dir, 'doc', '*', 'ri')] end.flatten ri_paths = {} all_paths.each do |dir| base = File.basename File.dirname(dir) if base =~ /(.*)-((\d+\.)*\d+)/ then name, version = $1, $2 ver = Gem::Version.new version if ri_paths[name].nil? or ver > ri_paths[name][0] then ri_paths[name] = [ver, dir] end end end GEMDIRS = ri_paths.map { |k,v| v.last }.sort GEMDIRS.each { |dir| RI::Paths::PATH << dir } rescue LoadError GEMDIRS = nil end # Returns the selected documentation directories as an Array, or PATH if no # overriding directories were given. def self.path(use_system, use_site, use_home, use_gems, *extra_dirs) path = raw_path(use_system, use_site, use_home, use_gems, *extra_dirs) return path.select { |directory| File.directory? directory } end # Returns the selected documentation directories including nonexistent # directories. Used to print out what paths were searched if no ri was # found. def self.raw_path(use_system, use_site, use_home, use_gems, *extra_dirs) return PATH unless use_system or use_site or use_home or use_gems or not extra_dirs.empty? path = [] path << extra_dirs unless extra_dirs.empty? path << RI::Paths::SYSDIR if use_system path << RI::Paths::SITEDIR if use_site path << RI::Paths::HOMEDIR if use_home path << RI::Paths::GEMDIRS if use_gems return path.flatten.compact end end end ================================================ FILE: lib/rdoc/ri/ri_reader.rb ================================================ require 'rdoc/ri/ri_descriptions' require 'rdoc/ri/ri_writer' require 'rdoc/markup/simple_markup/to_flow' module RI class RiReader def initialize(ri_cache) @cache = ri_cache end def top_level_namespace [ @cache.toplevel ] end def lookup_namespace_in(target, namespaces) result = [] for n in namespaces result.concat(n.contained_modules_matching(target)) end result end def find_class_by_name(full_name) names = full_name.split(/::/) ns = @cache.toplevel for name in names ns = ns.contained_class_named(name) return nil if ns.nil? end get_class(ns) end def find_methods(name, is_class_method, namespaces) result = [] namespaces.each do |ns| result.concat ns.methods_matching(name, is_class_method) end result end # return the MethodDescription for a given MethodEntry # by deserializing the YAML def get_method(method_entry) path = method_entry.path_name File.open(path) { |f| RI::Description.deserialize(f) } end # Return a class description def get_class(class_entry) result = nil for path in class_entry.path_names path = RiWriter.class_desc_path(path, class_entry) desc = File.open(path) {|f| RI::Description.deserialize(f) } if result result.merge_in(desc) else result = desc end end result end # return the names of all classes and modules def full_class_names res = [] find_classes_in(res, @cache.toplevel) end # return a list of all classes, modules, and methods def all_names res = [] find_names_in(res, @cache.toplevel) end # ---- private # ---- def find_classes_in(res, klass) classes = klass.classes_and_modules for c in classes res << c.full_name find_classes_in(res, c) end res end def find_names_in(res, klass) classes = klass.classes_and_modules for c in classes res << c.full_name res.concat c.all_method_names find_names_in(res, c) end res end end end ================================================ FILE: lib/rdoc/ri/ri_util.rb ================================================ ###################################################################### class RiError < Exception; end # # Break argument into its constituent class or module names, an # optional method type, and a method name class NameDescriptor attr_reader :class_names attr_reader :method_name # true and false have the obvious meaning. nil means we don't care attr_reader :is_class_method # arg may be # 1. a class or module name (optionally qualified with other class # or module names (Kernel, File::Stat etc) # 2. a method name # 3. a method name qualified by a optionally fully qualified class # or module name # # We're fairly casual about delimiters: folks can say Kernel::puts, # Kernel.puts, or Kernel\#puts for example. There's one exception: # if you say IO::read, we look for a class method, but if you # say IO.read, we look for an instance method def initialize(arg) @class_names = [] separator = nil tokens = arg.split(/(\.|::|#)/) # Skip leading '::', '#' or '.', but remember it might # be a method name qualifier separator = tokens.shift if tokens[0] =~ /^(\.|::|#)/ # Skip leading '::', but remember we potentially have an inst # leading stuff must be class names while tokens[0] =~ /^[A-Z]/ @class_names << tokens.shift unless tokens.empty? separator = tokens.shift break unless separator == "::" end end # Now must have a single token, the method name, or an empty # array unless tokens.empty? @method_name = tokens.shift # We may now have a trailing !, ?, or = to roll into # the method name if !tokens.empty? && tokens[0] =~ /^[!?=]$/ @method_name << tokens.shift end if @method_name =~ /::|\.|#/ or !tokens.empty? raise RiError.new("Bad argument: #{arg}") end if separator && separator != '.' @is_class_method = separator == "::" end end end # Return the full class name (with '::' between the components) # or "" if there's no class name def full_class_name @class_names.join("::") end end ================================================ FILE: lib/rdoc/ri/ri_writer.rb ================================================ require 'fileutils' module RI class RiWriter def RiWriter.class_desc_path(dir, class_desc) File.join(dir, "cdesc-" + class_desc.name + ".yaml") end # Convert a name from internal form (containing punctuation) # to an external form (where punctuation is replaced # by %xx) def RiWriter.internal_to_external(name) name.gsub(/\W/) { sprintf("%%%02x", $&[0]) } end # And the reverse operation def RiWriter.external_to_internal(name) name.gsub(/%([0-9a-f]{2,2})/) { $1.to_i(16).chr } end def initialize(base_dir) @base_dir = base_dir end def remove_class(class_desc) FileUtils.rm_rf(path_to_dir(class_desc.full_name)) end def add_class(class_desc) dir = path_to_dir(class_desc.full_name) FileUtils.mkdir_p(dir) class_file_name = RiWriter.class_desc_path(dir, class_desc) File.open(class_file_name, "w") do |f| f.write(class_desc.serialize) end end def add_method(class_desc, method_desc) dir = path_to_dir(class_desc.full_name) file_name = RiWriter.internal_to_external(method_desc.name) meth_file_name = File.join(dir, file_name) if method_desc.is_singleton meth_file_name += "-c.yaml" else meth_file_name += "-i.yaml" end File.open(meth_file_name, "w") do |f| f.write(method_desc.serialize) end end private def path_to_dir(class_name) File.join(@base_dir, *class_name.split('::')) end end end ================================================ FILE: lib/rdoc/template.rb ================================================ # Cheap-n-cheerful HTML page template system. You create a # template containing: # # * variable names between percent signs (%fred%) # * blocks of repeating stuff: # # START:key # ... stuff # END:key # # You feed the code a hash. For simple variables, the values # are resolved directly from the hash. For blocks, the hash entry # corresponding to +key+ will be an array of hashes. The block will # be generated once for each entry. Blocks can be nested arbitrarily # deeply. # # The template may also contain # # IF:key # ... stuff # ENDIF:key # # _stuff_ will only be included in the output if the corresponding # key is set in the value hash. # # Usage: Given a set of templates T1, T2, etc # # values = { "name" => "Dave", state => "TX" } # # t = TemplatePage.new(T1, T2, T3) # File.open(name, "w") {|f| t.write_html_on(f, values)} # or # res = '' # t.write_html_on(res, values) # # class TemplatePage ########## # A context holds a stack of key/value pairs (like a symbol # table). When asked to resolve a key, it first searches the top of # the stack, then the next level, and so on until it finds a match # (or runs out of entries) class Context def initialize @stack = [] end def push(hash) @stack.push(hash) end def pop @stack.pop end # Find a scalar value, throwing an exception if not found. This # method is used when substituting the %xxx% constructs def find_scalar(key) @stack.reverse_each do |level| if val = level[key] return val unless val.kind_of? Array end end raise "Template error: can't find variable '#{key}'" end # Lookup any key in the stack of hashes def lookup(key) @stack.reverse_each do |level| val = level[key] return val if val end nil end end ######### # Simple class to read lines out of a string class LineReader # we're initialized with an array of lines def initialize(lines) @lines = lines end # read the next line def read @lines.shift end # Return a list of lines up to the line that matches # a pattern. That last line is discarded. def read_up_to(pattern) res = [] while line = read if pattern.match(line) return LineReader.new(res) else res << line end end raise "Missing end tag in template: #{pattern.source}" end # Return a copy of ourselves that can be modified without # affecting us def dup LineReader.new(@lines.dup) end end # +templates+ is an array of strings containing the templates. # We start at the first, and substitute in subsequent ones # where the string !INCLUDE! occurs. For example, # we could have the overall page template containing # # #

      Master

      # !INCLUDE! # # # and substitute subpages in to it by passing [master, sub_page]. # This gives us a cheap way of framing pages def initialize(*templates) result = "!INCLUDE!" templates.each do |content| result.sub!(/!INCLUDE!/, content) end @lines = LineReader.new(result.split($/)) end # Render the templates into HTML, storing the result on +op+ # using the method <<. The value_hash contains # key/value pairs used to drive the substitution (as described above) def write_html_on(op, value_hash) @context = Context.new op << substitute_into(@lines, value_hash).tr("\000", '\\') end # Substitute a set of key/value pairs into the given template. # Keys with scalar values have them substituted directly into # the page. Those with array values invoke substitute_array # (below), which examples a block of the template once for each # row in the array. # # This routine also copes with the IF:_key_ directive, # removing chunks of the template if the corresponding key # does not appear in the hash, and the START: directive, which # loops its contents for each value in an array def substitute_into(lines, values) @context.push(values) skip_to = nil result = [] while line = lines.read case line when /^IF:(\w+)/ lines.read_up_to(/^ENDIF:#$1/) unless @context.lookup($1) when /^IFNOT:(\w+)/ lines.read_up_to(/^ENDIF:#$1/) if @context.lookup($1) when /^ENDIF:/ ; when /^START:(\w+)/ tag = $1 body = lines.read_up_to(/^END:#{tag}/) inner_values = @context.lookup(tag) raise "unknown tag: #{tag}" unless inner_values raise "not array: #{tag}" unless inner_values.kind_of?(Array) inner_values.each do |vals| result << substitute_into(body.dup, vals) end else result << expand_line(line.dup) end end @context.pop result.join("\n") end # Given an individual line, we look for %xxx% constructs and # HREF:ref:name: constructs, substituting for each. def expand_line(line) # Generate a cross reference if a reference is given, # otherwise just fill in the name part line.gsub!(/HREF:(\w+?):(\w+?):/) { ref = @context.lookup($1) name = @context.find_scalar($2) if ref and !ref.kind_of?(Array) "#{name}" else name end } # Substitute in values for %xxx% constructs. This is made complex # because the replacement string may contain characters that are # meaningful to the regexp (like \1) line = line.gsub(/%([a-zA-Z]\w*)%/) { val = @context.find_scalar($1) val.tr('\\', "\000") } line rescue Exception => e $stderr.puts "Error in template: #{e}" $stderr.puts "Original line: #{line}" exit end end ================================================ FILE: lib/rdoc/tokenstream.rb ================================================ # A TokenStream is a list of tokens, gathered during the parse # of some entity (say a method). Entities populate these streams # by being registered with the lexer. Any class can collect tokens # by including TokenStream. From the outside, you use such an object # by calling the start_collecting_tokens method, followed by calls # to add_token and pop_token module TokenStream def token_stream @token_stream end def start_collecting_tokens @token_stream = [] end def add_token(tk) @token_stream << tk end def add_tokens(tks) tks.each {|tk| add_token(tk)} end def pop_token @token_stream.pop end end ================================================ FILE: lib/rdoc/usage.rb ================================================ # = Synopsis # # This library allows command-line tools to encapsulate their usage # as a comment at the top of the main file. Calling RDoc::usage # then displays some or all of that comment, and optionally exits # the program with an exit status. We always look for the comment # in the main program file, so it is safe to call this method # from anywhere in the executing program. # # = Usage # # RDoc::usage( [ exit_status ], [ section, ...]) # RDoc::usage_no_exit( [ section, ...]) # # where: # # exit_status:: # the integer exit code (default zero). RDoc::usage will exit # the calling program with this status. # # section:: # an optional list of section names. If specified, only the # sections with the given names as headings will be output. # For example, this section is named 'Usage', and the next # section is named 'Examples'. The section names are case # insensitive. # # = Examples # # # Comment block describing usage # # with (optional) section headings # # . . . # # require 'rdoc/usage' # # # Display all usage and exit with a status of 0 # # RDoc::usage # # # Display all usage and exit with a status of 99 # # RDoc::usage(99) # # # Display usage in the 'Summary' section only, then # # exit with a status of 99 # # RDoc::usage(99, 'Summary') # # # Display information in the Author and Copyright # # sections, then exit 0. # # RDoc::usage('Author', 'Copyright') # # # Display information in the Author and Copyright # # sections, but don't exit # # RDoc::usage_no_exit('Author', 'Copyright') # # = Author # # Dave Thomas, The Pragmatic Programmers, LLC # # = Copyright # # Copyright (c) 2004 Dave Thomas. # Licensed under the same terms as Ruby # require 'rdoc/markup/simple_markup' require 'rdoc/markup/simple_markup/to_flow' require 'rdoc/ri/ri_formatter' require 'rdoc/ri/ri_options' module RDoc # Display usage information from the comment at the top of # the file. String arguments identify specific sections of the # comment to display. An optional integer first argument # specifies the exit status (defaults to 0) def RDoc.usage(*args) exit_code = 0 if args.size > 0 status = args[0] if status.respond_to?(:to_int) exit_code = status.to_int args.shift end end # display the usage and exit with the given code usage_no_exit(*args) exit(exit_code) end # Display usage def RDoc.usage_no_exit(*args) main_program_file = caller[-1].sub(/:\d+$/, '') comment = File.open(main_program_file) do |file| find_comment(file) end comment = comment.gsub(/^\s*#/, '') markup = SM::SimpleMarkup.new flow_convertor = SM::ToFlow.new flow = markup.convert(comment, flow_convertor) format = "plain" unless args.empty? flow = extract_sections(flow, args) end options = RI::Options.instance if args = ENV["RI"] options.parse(args.split) end formatter = options.formatter.new(options, "") formatter.display_flow(flow) end ###################################################################### private # Find the first comment in the file (that isn't a shebang line) # If the file doesn't start with a comment, report the fact # and return empty string def RDoc.gets(file) if (line = file.gets) && (line =~ /^#!/) # shebang throw :exit, find_comment(file) else line end end def RDoc.find_comment(file) catch(:exit) do # skip leading blank lines 0 while (line = gets(file)) && (line =~ /^\s*$/) comment = [] while line && line =~ /^\s*#/ comment << line line = gets(file) end 0 while line && (line = gets(file)) return no_comment if comment.empty? return comment.join end end ##### # Given an array of flow items and an array of section names, extract those # sections from the flow which have headings corresponding to # a section name in the list. Return them in the order # of names in the +sections+ array. def RDoc.extract_sections(flow, sections) result = [] sections.each do |name| name = name.downcase copy_upto_level = nil flow.each do |item| case item when SM::Flow::H if copy_upto_level && item.level >= copy_upto_level copy_upto_level = nil else if item.text.downcase == name result << item copy_upto_level = item.level end end else if copy_upto_level result << item end end end end if result.empty? puts "Note to developer: requested section(s) [#{sections.join(', ')}] " + "not found" result = flow end result end ##### # Report the fact that no doc comment count be found def RDoc.no_comment $stderr.puts "No usage information available for this program" "" end end if $0 == __FILE__ RDoc::usage(*ARGV) end ================================================ FILE: lib/readbytes.rb ================================================ # TruncatedDataError is raised when IO#readbytes fails to read enough data. class TruncatedDataError ['210.251.121.21'], # :search => ['ruby-lang.org'], # :ndots => 1) def initialize(config_info=nil) @mutex = Mutex.new @config = Config.new(config_info) @initialized = nil end def lazy_initialize # :nodoc: @mutex.synchronize { unless @initialized @config.lazy_initialize @initialized = true end } self end ## # Closes the DNS resolver. def close @mutex.synchronize { if @initialized @initialized = false end } end ## # Gets the IP address of +name+ from the DNS resolver. # # +name+ can be a Resolv::DNS::Name or a String. Retrieved address will # be a Resolv::IPv4 or Resolv::IPv6 def getaddress(name) each_address(name) {|address| return address} raise ResolvError.new("DNS result has no information for #{name}") end ## # Gets all IP addresses for +name+ from the DNS resolver. # # +name+ can be a Resolv::DNS::Name or a String. Retrieved addresses will # be a Resolv::IPv4 or Resolv::IPv6 def getaddresses(name) ret = [] each_address(name) {|address| ret << address} return ret end ## # Iterates over all IP addresses for +name+ retrieved from the DNS # resolver. # # +name+ can be a Resolv::DNS::Name or a String. Retrieved addresses will # be a Resolv::IPv4 or Resolv::IPv6 def each_address(name) each_resource(name, Resource::IN::A) {|resource| yield resource.address} each_resource(name, Resource::IN::AAAA) {|resource| yield resource.address} end ## # Gets the hostname for +address+ from the DNS resolver. # # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved # name will be a Resolv::DNS::Name. def getname(address) each_name(address) {|name| return name} raise ResolvError.new("DNS result has no information for #{address}") end ## # Gets all hostnames for +address+ from the DNS resolver. # # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved # names will be Resolv::DNS::Name instances. def getnames(address) ret = [] each_name(address) {|name| ret << name} return ret end ## # Iterates over all hostnames for +address+ retrieved from the DNS # resolver. # # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved # names will be Resolv::DNS::Name instances. def each_name(address) case address when Name ptr = address when IPv4::Regex ptr = IPv4.create(address).to_name when IPv6::Regex ptr = IPv6.create(address).to_name else raise ResolvError.new("cannot interpret as address: #{address}") end each_resource(ptr, Resource::IN::PTR) {|resource| yield resource.name} end ## # Look up the +typeclass+ DNS resource of +name+. # # +name+ must be a Resolv::DNS::Name or a String. # # +typeclass+ should be one of the following: # # * Resolv::DNS::Resource::IN::A # * Resolv::DNS::Resource::IN::AAAA # * Resolv::DNS::Resource::IN::ANY # * Resolv::DNS::Resource::IN::CNAME # * Resolv::DNS::Resource::IN::HINFO # * Resolv::DNS::Resource::IN::MINFO # * Resolv::DNS::Resource::IN::MX # * Resolv::DNS::Resource::IN::NS # * Resolv::DNS::Resource::IN::PTR # * Resolv::DNS::Resource::IN::SOA # * Resolv::DNS::Resource::IN::TXT # * Resolv::DNS::Resource::IN::WKS # # Returned resource is represented as a Resolv::DNS::Resource instance, # i.e. Resolv::DNS::Resource::IN::A. def getresource(name, typeclass) each_resource(name, typeclass) {|resource| return resource} raise ResolvError.new("DNS result has no information for #{name}") end ## # Looks up all +typeclass+ DNS resources for +name+. See #getresource for # argument details. def getresources(name, typeclass) ret = [] each_resource(name, typeclass) {|resource| ret << resource} return ret end ## # Iterates over all +typeclass+ DNS resources for +name+. See # #getresource for argument details. def each_resource(name, typeclass, &proc) lazy_initialize requester = make_requester senders = {} begin @config.resolv(name) {|candidate, tout, nameserver| msg = Message.new msg.rd = 1 msg.add_question(candidate, typeclass) unless sender = senders[[candidate, nameserver]] sender = senders[[candidate, nameserver]] = requester.sender(msg, candidate, nameserver) end reply, reply_name = requester.request(sender, tout) case reply.rcode when RCode::NoError extract_resources(reply, reply_name, typeclass, &proc) return when RCode::NXDomain raise Config::NXDomain.new(reply_name.to_s) else raise Config::OtherResolvError.new(reply_name.to_s) end } ensure requester.close end end def make_requester # :nodoc: if nameserver = @config.single? Requester::ConnectedUDP.new(nameserver) else Requester::UnconnectedUDP.new end end def extract_resources(msg, name, typeclass) # :nodoc: if typeclass < Resource::ANY n0 = Name.create(name) msg.each_answer {|n, ttl, data| yield data if n0 == n } end yielded = false n0 = Name.create(name) msg.each_answer {|n, ttl, data| if n0 == n case data when typeclass yield data yielded = true when Resource::CNAME n0 = data.name end end } return if yielded msg.each_answer {|n, ttl, data| if n0 == n case data when typeclass yield data end end } end if defined? SecureRandom def self.random(arg) # :nodoc: begin SecureRandom.random_number(arg) rescue NotImplementedError rand(arg) end end else def self.random(arg) # :nodoc: rand(arg) end end def self.rangerand(range) # :nodoc: base = range.begin len = range.end - range.begin if !range.exclude_end? len += 1 end base + random(len) end RequestID = {} RequestIDMutex = Mutex.new def self.allocate_request_id(host, port) # :nodoc: id = nil RequestIDMutex.synchronize { h = (RequestID[[host, port]] ||= {}) begin id = rangerand(0x0000..0xffff) end while h[id] h[id] = true } id end def self.free_request_id(host, port, id) # :nodoc: RequestIDMutex.synchronize { key = [host, port] if h = RequestID[key] h.delete id if h.empty? RequestID.delete key end end } end def self.bind_random_port(udpsock, is_ipv6=false) # :nodoc: begin port = rangerand(1024..65535) udpsock.bind(is_ipv6 ? "::" : "", port) rescue Errno::EADDRINUSE retry end end class Requester # :nodoc: def initialize @senders = {} @sock = nil end def request(sender, tout) timelimit = Time.now + tout sender.send while (now = Time.now) < timelimit timeout = timelimit - now if !IO.select([@sock], nil, nil, timeout) raise ResolvTimeout end reply, from = recv_reply begin msg = Message.decode(reply) rescue DecodeError next # broken DNS message ignored end if s = @senders[[from,msg.id]] break else # unexpected DNS message ignored end end return msg, s.data end def close sock = @sock @sock = nil sock.close if sock end class Sender # :nodoc: def initialize(msg, data, sock) @msg = msg @data = data @sock = sock end end class UnconnectedUDP < Requester # :nodoc: def initialize super() @sock = UDPSocket.new @sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD DNS.bind_random_port(@sock) end def recv_reply reply, from = @sock.recvfrom(UDPSize) return reply, [from[3],from[1]] end def sender(msg, data, host, port=Port) service = [host, port] id = DNS.allocate_request_id(host, port) request = msg.encode request[0,2] = [id].pack('n') return @senders[[service, id]] = Sender.new(request, data, @sock, host, port) end def close super @senders.each_key {|service, id| DNS.free_request_id(service[0], service[1], id) } end class Sender < Requester::Sender # :nodoc: def initialize(msg, data, sock, host, port) super(msg, data, sock) @host = host @port = port end attr_reader :data def send @sock.send(@msg, 0, @host, @port) end end end class ConnectedUDP < Requester # :nodoc: def initialize(host, port=Port) super() @host = host @port = port is_ipv6 = host.index(':') @sock = UDPSocket.new(is_ipv6 ? Socket::AF_INET6 : Socket::AF_INET) DNS.bind_random_port(@sock, is_ipv6) @sock.connect(host, port) @sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD end def recv_reply reply = @sock.recv(UDPSize) return reply, nil end def sender(msg, data, host=@host, port=@port) unless host == @host && port == @port raise RequestError.new("host/port don't match: #{host}:#{port}") end id = DNS.allocate_request_id(@host, @port) request = msg.encode request[0,2] = [id].pack('n') return @senders[[nil,id]] = Sender.new(request, data, @sock) end def close super @senders.each_key {|from, id| DNS.free_request_id(@host, @port, id) } end class Sender < Requester::Sender # :nodoc: def send @sock.send(@msg, 0) end attr_reader :data end end class TCP < Requester # :nodoc: def initialize(host, port=Port) super() @host = host @port = port @sock = TCPSocket.new(@host, @port) @sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD @senders = {} end def recv_reply len = @sock.read(2).unpack('n')[0] reply = @sock.read(len) return reply, nil end def sender(msg, data, host=@host, port=@port) unless host == @host && port == @port raise RequestError.new("host/port don't match: #{host}:#{port}") end id = DNS.allocate_request_id(@host, @port) request = msg.encode request[0,2] = [request.length, id].pack('nn') return @senders[[nil,id]] = Sender.new(request, data, @sock) end class Sender < Requester::Sender # :nodoc: def send @sock.print(@msg) @sock.flush end attr_reader :data end def close super @senders.each_key {|from,id| DNS.free_request_id(@host, @port, id) } end end ## # Indicates a problem with the DNS request. class RequestError < StandardError end end class Config # :nodoc: def initialize(config_info=nil) @mutex = Mutex.new @config_info = config_info @initialized = nil end def Config.parse_resolv_conf(filename) nameserver = [] search = nil ndots = 1 open(filename) {|f| f.each {|line| line.sub!(/[#;].*/, '') keyword, *args = line.split(/\s+/) args.each { |arg| arg.untaint } next unless keyword case keyword when 'nameserver' nameserver += args when 'domain' next if args.empty? search = [args[0]] when 'search' next if args.empty? search = args when 'options' args.each {|arg| case arg when /\Andots:(\d+)\z/ ndots = $1.to_i end } end } } return { :nameserver => nameserver, :search => search, :ndots => ndots } end def Config.default_config_hash(filename="/etc/resolv.conf") if File.exist? filename config_hash = Config.parse_resolv_conf(filename) else if /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM require 'win32/resolv' search, nameserver = Win32::Resolv.get_resolv_info config_hash = {} config_hash[:nameserver] = nameserver if nameserver config_hash[:search] = [search].flatten if search end end config_hash end def lazy_initialize @mutex.synchronize { unless @initialized @nameserver = [] @search = nil @ndots = 1 case @config_info when nil config_hash = Config.default_config_hash when String config_hash = Config.parse_resolv_conf(@config_info) when Hash config_hash = @config_info.dup if String === config_hash[:nameserver] config_hash[:nameserver] = [config_hash[:nameserver]] end if String === config_hash[:search] config_hash[:search] = [config_hash[:search]] end else raise ArgumentError.new("invalid resolv configuration: #{@config_info.inspect}") end @nameserver = config_hash[:nameserver] if config_hash.include? :nameserver @search = config_hash[:search] if config_hash.include? :search @ndots = config_hash[:ndots] if config_hash.include? :ndots @nameserver = ['0.0.0.0'] if @nameserver.empty? if @search @search = @search.map {|arg| Label.split(arg) } else hostname = Socket.gethostname if /\./ =~ hostname @search = [Label.split($')] else @search = [[]] end end if !@nameserver.kind_of?(Array) || !@nameserver.all? {|ns| String === ns } raise ArgumentError.new("invalid nameserver config: #{@nameserver.inspect}") end if !@search.kind_of?(Array) || !@search.all? {|ls| ls.all? {|l| Label::Str === l } } raise ArgumentError.new("invalid search config: #{@search.inspect}") end if !@ndots.kind_of?(Integer) raise ArgumentError.new("invalid ndots config: #{@ndots.inspect}") end @initialized = true end } self end def single? lazy_initialize if @nameserver.length == 1 return @nameserver[0] else return nil end end def generate_candidates(name) candidates = nil name = Name.create(name) if name.absolute? candidates = [name] else if @ndots <= name.length - 1 candidates = [Name.new(name.to_a)] else candidates = [] end candidates.concat(@search.map {|domain| Name.new(name.to_a + domain)}) end return candidates end InitialTimeout = 5 def generate_timeouts ts = [InitialTimeout] ts << ts[-1] * 2 / @nameserver.length ts << ts[-1] * 2 ts << ts[-1] * 2 return ts end def resolv(name) candidates = generate_candidates(name) timeouts = generate_timeouts begin candidates.each {|candidate| begin timeouts.each {|tout| @nameserver.each {|nameserver| begin yield candidate, tout, nameserver rescue ResolvTimeout end } } raise ResolvError.new("DNS resolv timeout: #{name}") rescue NXDomain end } rescue ResolvError end end ## # Indicates no such domain was found. class NXDomain < ResolvError end ## # Indicates some other unhandled resolver error was encountered. class OtherResolvError < ResolvError end end module OpCode # :nodoc: Query = 0 IQuery = 1 Status = 2 Notify = 4 Update = 5 end module RCode # :nodoc: NoError = 0 FormErr = 1 ServFail = 2 NXDomain = 3 NotImp = 4 Refused = 5 YXDomain = 6 YXRRSet = 7 NXRRSet = 8 NotAuth = 9 NotZone = 10 BADVERS = 16 BADSIG = 16 BADKEY = 17 BADTIME = 18 BADMODE = 19 BADNAME = 20 BADALG = 21 end ## # Indicates that the DNS response was unable to be decoded. class DecodeError < StandardError end ## # Indicates that the DNS request was unable to be encoded. class EncodeError < StandardError end module Label # :nodoc: def self.split(arg) labels = [] arg.scan(/[^\.]+/) {labels << Str.new($&)} return labels end class Str # :nodoc: def initialize(string) @string = string @downcase = string.downcase end attr_reader :string, :downcase def to_s return @string end def inspect return "#<#{self.class} #{self.to_s}>" end def ==(other) return @downcase == other.downcase end def eql?(other) return self == other end def hash return @downcase.hash end end end ## # A representation of a DNS name. class Name ## # Creates a new DNS name from +arg+. +arg+ can be: # # Name:: returns +arg+. # String:: Creates a new Name. def self.create(arg) case arg when Name return arg when String return Name.new(Label.split(arg), /\.\z/ =~ arg ? true : false) else raise ArgumentError.new("cannot interpret as DNS name: #{arg.inspect}") end end def initialize(labels, absolute=true) # :nodoc: @labels = labels @absolute = absolute end def inspect # :nodoc: "#<#{self.class}: #{self.to_s}#{@absolute ? '.' : ''}>" end ## # True if this name is absolute. def absolute? return @absolute end def ==(other) # :nodoc: return false unless Name === other return @labels.join == other.to_a.join && @absolute == other.absolute? end alias eql? == # :nodoc: ## # Returns true if +other+ is a subdomain. # # Example: # # domain = Resolv::DNS::Name.create("y.z") # p Resolv::DNS::Name.create("w.x.y.z").subdomain_of?(domain) #=> true # p Resolv::DNS::Name.create("x.y.z").subdomain_of?(domain) #=> true # p Resolv::DNS::Name.create("y.z").subdomain_of?(domain) #=> false # p Resolv::DNS::Name.create("z").subdomain_of?(domain) #=> false # p Resolv::DNS::Name.create("x.y.z.").subdomain_of?(domain) #=> false # p Resolv::DNS::Name.create("w.z").subdomain_of?(domain) #=> false # def subdomain_of?(other) raise ArgumentError, "not a domain name: #{other.inspect}" unless Name === other return false if @absolute != other.absolute? other_len = other.length return false if @labels.length <= other_len return @labels[-other_len, other_len] == other.to_a end def hash # :nodoc: return @labels.hash ^ @absolute.hash end def to_a # :nodoc: return @labels end def length # :nodoc: return @labels.length end def [](i) # :nodoc: return @labels[i] end ## # returns the domain name as a string. # # The domain name doesn't have a trailing dot even if the name object is # absolute. # # Example: # # p Resolv::DNS::Name.create("x.y.z.").to_s #=> "x.y.z" # p Resolv::DNS::Name.create("x.y.z").to_s #=> "x.y.z" def to_s return @labels.join('.') end end class Message # :nodoc: @@identifier = -1 def initialize(id = (@@identifier += 1) & 0xffff) @id = id @qr = 0 @opcode = 0 @aa = 0 @tc = 0 @rd = 0 # recursion desired @ra = 0 # recursion available @rcode = 0 @question = [] @answer = [] @authority = [] @additional = [] end attr_accessor :id, :qr, :opcode, :aa, :tc, :rd, :ra, :rcode attr_reader :question, :answer, :authority, :additional def ==(other) return @id == other.id && @qr == other.qr && @opcode == other.opcode && @aa == other.aa && @tc == other.tc && @rd == other.rd && @ra == other.ra && @rcode == other.rcode && @question == other.question && @answer == other.answer && @authority == other.authority && @additional == other.additional end def add_question(name, typeclass) @question << [Name.create(name), typeclass] end def each_question @question.each {|name, typeclass| yield name, typeclass } end def add_answer(name, ttl, data) @answer << [Name.create(name), ttl, data] end def each_answer @answer.each {|name, ttl, data| yield name, ttl, data } end def add_authority(name, ttl, data) @authority << [Name.create(name), ttl, data] end def each_authority @authority.each {|name, ttl, data| yield name, ttl, data } end def add_additional(name, ttl, data) @additional << [Name.create(name), ttl, data] end def each_additional @additional.each {|name, ttl, data| yield name, ttl, data } end def each_resource each_answer {|name, ttl, data| yield name, ttl, data} each_authority {|name, ttl, data| yield name, ttl, data} each_additional {|name, ttl, data| yield name, ttl, data} end def encode return MessageEncoder.new {|msg| msg.put_pack('nnnnnn', @id, (@qr & 1) << 15 | (@opcode & 15) << 11 | (@aa & 1) << 10 | (@tc & 1) << 9 | (@rd & 1) << 8 | (@ra & 1) << 7 | (@rcode & 15), @question.length, @answer.length, @authority.length, @additional.length) @question.each {|q| name, typeclass = q msg.put_name(name) msg.put_pack('nn', typeclass::TypeValue, typeclass::ClassValue) } [@answer, @authority, @additional].each {|rr| rr.each {|r| name, ttl, data = r msg.put_name(name) msg.put_pack('nnN', data.class::TypeValue, data.class::ClassValue, ttl) msg.put_length16 {data.encode_rdata(msg)} } } }.to_s end class MessageEncoder # :nodoc: def initialize @data = '' @names = {} yield self end def to_s return @data end def put_bytes(d) @data << d end def put_pack(template, *d) @data << d.pack(template) end def put_length16 length_index = @data.length @data << "\0\0" data_start = @data.length yield data_end = @data.length @data[length_index, 2] = [data_end - data_start].pack("n") end def put_string(d) self.put_pack("C", d.length) @data << d end def put_string_list(ds) ds.each {|d| self.put_string(d) } end def put_name(d) put_labels(d.to_a) end def put_labels(d) d.each_index {|i| domain = d[i..-1] if idx = @names[domain] self.put_pack("n", 0xc000 | idx) return else @names[domain] = @data.length self.put_label(d[i]) end } @data << "\0" end def put_label(d) self.put_string(d.to_s) end end def Message.decode(m) o = Message.new(0) MessageDecoder.new(m) {|msg| id, flag, qdcount, ancount, nscount, arcount = msg.get_unpack('nnnnnn') o.id = id o.qr = (flag >> 15) & 1 o.opcode = (flag >> 11) & 15 o.aa = (flag >> 10) & 1 o.tc = (flag >> 9) & 1 o.rd = (flag >> 8) & 1 o.ra = (flag >> 7) & 1 o.rcode = flag & 15 (1..qdcount).each { name, typeclass = msg.get_question o.add_question(name, typeclass) } (1..ancount).each { name, ttl, data = msg.get_rr o.add_answer(name, ttl, data) } (1..nscount).each { name, ttl, data = msg.get_rr o.add_authority(name, ttl, data) } (1..arcount).each { name, ttl, data = msg.get_rr o.add_additional(name, ttl, data) } } return o end class MessageDecoder # :nodoc: def initialize(data) @data = data @index = 0 @limit = data.length yield self end def get_length16 len, = self.get_unpack('n') save_limit = @limit @limit = @index + len d = yield(len) if @index < @limit raise DecodeError.new("junk exists") elsif @limit < @index raise DecodeError.new("limit exceeded") end @limit = save_limit return d end def get_bytes(len = @limit - @index) d = @data[@index, len] @index += len return d end def get_unpack(template) len = 0 template.each_byte {|byte| case byte when ?c, ?C len += 1 when ?n len += 2 when ?N len += 4 else raise StandardError.new("unsupported template: '#{byte.chr}' in '#{template}'") end } raise DecodeError.new("limit exceeded") if @limit < @index + len arr = @data.unpack("@#{@index}#{template}") @index += len return arr end def get_string len = @data[@index] raise DecodeError.new("limit exceeded") if @limit < @index + 1 + len d = @data[@index + 1, len] @index += 1 + len return d end def get_string_list strings = [] while @index < @limit strings << self.get_string end strings end def get_name return Name.new(self.get_labels) end def get_labels(limit=nil) limit = @index if !limit || @index < limit d = [] while true case @data[@index] when 0 @index += 1 return d when 192..255 idx = self.get_unpack('n')[0] & 0x3fff if limit <= idx raise DecodeError.new("non-backward name pointer") end save_index = @index @index = idx d += self.get_labels(limit) @index = save_index return d else d << self.get_label end end return d end def get_label return Label::Str.new(self.get_string) end def get_question name = self.get_name type, klass = self.get_unpack("nn") return name, Resource.get_class(type, klass) end def get_rr name = self.get_name type, klass, ttl = self.get_unpack('nnN') typeclass = Resource.get_class(type, klass) return name, ttl, self.get_length16 {typeclass.decode_rdata(self)} end end end ## # A DNS query abstract class. class Query def encode_rdata(msg) # :nodoc: raise EncodeError.new("#{self.class} is query.") end def self.decode_rdata(msg) # :nodoc: raise DecodeError.new("#{self.class} is query.") end end ## # A DNS resource abstract class. class Resource < Query ## # Remaining Time To Live for this Resource. attr_reader :ttl ClassHash = {} # :nodoc: def encode_rdata(msg) # :nodoc: raise NotImplementedError.new end def self.decode_rdata(msg) # :nodoc: raise NotImplementedError.new end def ==(other) # :nodoc: return self.class == other.class && self.instance_variables == other.instance_variables && self.instance_variables.collect {|name| self.instance_eval name} == other.instance_variables.collect {|name| other.instance_eval name} end def eql?(other) # :nodoc: return self == other end def hash # :nodoc: h = 0 self.instance_variables.each {|name| h ^= self.instance_eval("#{name}.hash") } return h end def self.get_class(type_value, class_value) # :nodoc: return ClassHash[[type_value, class_value]] || Generic.create(type_value, class_value) end ## # A generic resource abstract class. class Generic < Resource ## # Creates a new generic resource. def initialize(data) @data = data end ## # Data for this generic resource. attr_reader :data def encode_rdata(msg) # :nodoc: msg.put_bytes(data) end def self.decode_rdata(msg) # :nodoc: return self.new(msg.get_bytes) end def self.create(type_value, class_value) # :nodoc: c = Class.new(Generic) c.const_set(:TypeValue, type_value) c.const_set(:ClassValue, class_value) Generic.const_set("Type#{type_value}_Class#{class_value}", c) ClassHash[[type_value, class_value]] = c return c end end ## # Domain Name resource abstract class. class DomainName < Resource ## # Creates a new DomainName from +name+. def initialize(name) @name = name end ## # The name of this DomainName. attr_reader :name def encode_rdata(msg) # :nodoc: msg.put_name(@name) end def self.decode_rdata(msg) # :nodoc: return self.new(msg.get_name) end end # Standard (class generic) RRs ClassValue = nil # :nodoc: ## # An authoritative name server. class NS < DomainName TypeValue = 2 # :nodoc: end ## # The canonical name for an alias. class CNAME < DomainName TypeValue = 5 # :nodoc: end ## # Start Of Authority resource. class SOA < Resource TypeValue = 6 # :nodoc: ## # Creates a new SOA record. See the attr documentation for the # details of each argument. def initialize(mname, rname, serial, refresh, retry_, expire, minimum) @mname = mname @rname = rname @serial = serial @refresh = refresh @retry = retry_ @expire = expire @minimum = minimum end ## # Name of the host where the master zone file for this zone resides. attr_reader :mname ## # The person responsible for this domain name. attr_reader :rname ## # The version number of the zone file. attr_reader :serial ## # How often, in seconds, a secondary name server is to check for # updates from the primary name server. attr_reader :refresh ## # How often, in seconds, a secondary name server is to retry after a # failure to check for a refresh. attr_reader :retry ## # Time in seconds that a secondary name server is to use the data # before refreshing from the primary name server. attr_reader :expire ## # The minimum number of seconds to be used for TTL values in RRs. attr_reader :minimum def encode_rdata(msg) # :nodoc: msg.put_name(@mname) msg.put_name(@rname) msg.put_pack('NNNNN', @serial, @refresh, @retry, @expire, @minimum) end def self.decode_rdata(msg) # :nodoc: mname = msg.get_name rname = msg.get_name serial, refresh, retry_, expire, minimum = msg.get_unpack('NNNNN') return self.new( mname, rname, serial, refresh, retry_, expire, minimum) end end ## # A Pointer to another DNS name. class PTR < DomainName TypeValue = 12 # :nodoc: end ## # Host Information resource. class HINFO < Resource TypeValue = 13 # :nodoc: ## # Creates a new HINFO running +os+ on +cpu+. def initialize(cpu, os) @cpu = cpu @os = os end ## # CPU architecture for this resource. attr_reader :cpu ## # Operating system for this resource. attr_reader :os def encode_rdata(msg) # :nodoc: msg.put_string(@cpu) msg.put_string(@os) end def self.decode_rdata(msg) # :nodoc: cpu = msg.get_string os = msg.get_string return self.new(cpu, os) end end ## # Mailing list or mailbox information. class MINFO < Resource TypeValue = 14 # :nodoc: def initialize(rmailbx, emailbx) @rmailbx = rmailbx @emailbx = emailbx end ## # Domain name responsible for this mail list or mailbox. attr_reader :rmailbx ## # Mailbox to use for error messages related to the mail list or mailbox. attr_reader :emailbx def encode_rdata(msg) # :nodoc: msg.put_name(@rmailbx) msg.put_name(@emailbx) end def self.decode_rdata(msg) # :nodoc: rmailbx = msg.get_string emailbx = msg.get_string return self.new(rmailbx, emailbx) end end ## # Mail Exchanger resource. class MX < Resource TypeValue= 15 # :nodoc: ## # Creates a new MX record with +preference+, accepting mail at # +exchange+. def initialize(preference, exchange) @preference = preference @exchange = exchange end ## # The preference for this MX. attr_reader :preference ## # The host of this MX. attr_reader :exchange def encode_rdata(msg) # :nodoc: msg.put_pack('n', @preference) msg.put_name(@exchange) end def self.decode_rdata(msg) # :nodoc: preference, = msg.get_unpack('n') exchange = msg.get_name return self.new(preference, exchange) end end ## # Unstructured text resource. class TXT < Resource TypeValue = 16 # :nodoc: def initialize(first_string, *rest_strings) @strings = [first_string, *rest_strings] end ## # Returns an Array of Strings for this TXT record. attr_reader :strings ## # Returns the first string from +strings+. def data @strings[0] end def encode_rdata(msg) # :nodoc: msg.put_string_list(@strings) end def self.decode_rdata(msg) # :nodoc: strings = msg.get_string_list return self.new(*strings) end end ## # A Query type requesting any RR. class ANY < Query TypeValue = 255 # :nodoc: end ClassInsensitiveTypes = [ # :nodoc: NS, CNAME, SOA, PTR, HINFO, MINFO, MX, TXT, ANY ] ## # module IN contains ARPA Internet specific RRs. module IN ClassValue = 1 # :nodoc: ClassInsensitiveTypes.each {|s| c = Class.new(s) c.const_set(:TypeValue, s::TypeValue) c.const_set(:ClassValue, ClassValue) ClassHash[[s::TypeValue, ClassValue]] = c self.const_set(s.name.sub(/.*::/, ''), c) } ## # IPv4 Address resource class A < Resource TypeValue = 1 ClassValue = IN::ClassValue ClassHash[[TypeValue, ClassValue]] = self # :nodoc: ## # Creates a new A for +address+. def initialize(address) @address = IPv4.create(address) end ## # The Resolv::IPv4 address for this A. attr_reader :address def encode_rdata(msg) # :nodoc: msg.put_bytes(@address.address) end def self.decode_rdata(msg) # :nodoc: return self.new(IPv4.new(msg.get_bytes(4))) end end ## # Well Known Service resource. class WKS < Resource TypeValue = 11 ClassValue = IN::ClassValue ClassHash[[TypeValue, ClassValue]] = self # :nodoc: def initialize(address, protocol, bitmap) @address = IPv4.create(address) @protocol = protocol @bitmap = bitmap end ## # The host these services run on. attr_reader :address ## # IP protocol number for these services. attr_reader :protocol ## # A bit map of enabled services on this host. # # If protocol is 6 (TCP) then the 26th bit corresponds to the SMTP # service (port 25). If this bit is set, then an SMTP server should # be listening on TCP port 25; if zero, SMTP service is not # supported. attr_reader :bitmap def encode_rdata(msg) # :nodoc: msg.put_bytes(@address.address) msg.put_pack("n", @protocol) msg.put_bytes(@bitmap) end def self.decode_rdata(msg) # :nodoc: address = IPv4.new(msg.get_bytes(4)) protocol, = msg.get_unpack("n") bitmap = msg.get_bytes return self.new(address, protocol, bitmap) end end ## # An IPv6 address record. class AAAA < Resource TypeValue = 28 ClassValue = IN::ClassValue ClassHash[[TypeValue, ClassValue]] = self # :nodoc: ## # Creates a new AAAA for +address+. def initialize(address) @address = IPv6.create(address) end ## # The Resolv::IPv6 address for this AAAA. attr_reader :address def encode_rdata(msg) # :nodoc: msg.put_bytes(@address.address) end def self.decode_rdata(msg) # :nodoc: return self.new(IPv6.new(msg.get_bytes(16))) end end ## # SRV resource record defined in RFC 2782 # # These records identify the hostname and port that a service is # available at. class SRV < Resource TypeValue = 33 ClassValue = IN::ClassValue ClassHash[[TypeValue, ClassValue]] = self # :nodoc: # Create a SRV resource record. # # See the documentation for #priority, #weight, #port and #target # for +priority+, +weight+, +port and +target+ respectively. def initialize(priority, weight, port, target) @priority = priority.to_int @weight = weight.to_int @port = port.to_int @target = Name.create(target) end # The priority of this target host. # # A client MUST attempt to contact the target host with the # lowest-numbered priority it can reach; target hosts with the same # priority SHOULD be tried in an order defined by the weight field. # The range is 0-65535. Note that it is not widely implemented and # should be set to zero. attr_reader :priority # A server selection mechanism. # # The weight field specifies a relative weight for entries with the # same priority. Larger weights SHOULD be given a proportionately # higher probability of being selected. The range of this number is # 0-65535. Domain administrators SHOULD use Weight 0 when there # isn't any server selection to do, to make the RR easier to read # for humans (less noisy). Note that it is not widely implemented # and should be set to zero. attr_reader :weight # The port on this target host of this service. # # The range is 0-65535. attr_reader :port # The domain name of the target host. # # A target of "." means that the service is decidedly not available # at this domain. attr_reader :target def encode_rdata(msg) # :nodoc: msg.put_pack("n", @priority) msg.put_pack("n", @weight) msg.put_pack("n", @port) msg.put_name(@target) end def self.decode_rdata(msg) # :nodoc: priority, = msg.get_unpack("n") weight, = msg.get_unpack("n") port, = msg.get_unpack("n") target = msg.get_name return self.new(priority, weight, port, target) end end end end end ## # A Resolv::DNS IPv4 address. class IPv4 ## # Regular expression IPv4 addresses must match. Regex = /\A(\d+)\.(\d+)\.(\d+)\.(\d+)\z/ def self.create(arg) case arg when IPv4 return arg when Regex if (0..255) === (a = $1.to_i) && (0..255) === (b = $2.to_i) && (0..255) === (c = $3.to_i) && (0..255) === (d = $4.to_i) return self.new([a, b, c, d].pack("CCCC")) else raise ArgumentError.new("IPv4 address with invalid value: " + arg) end else raise ArgumentError.new("cannot interpret as IPv4 address: #{arg.inspect}") end end def initialize(address) # :nodoc: unless address.kind_of?(String) && address.length == 4 raise ArgumentError.new('IPv4 address must be 4 bytes') end @address = address end ## # A String representation of this IPv4 address. ## # The raw IPv4 address as a String. attr_reader :address def to_s # :nodoc: return sprintf("%d.%d.%d.%d", *@address.unpack("CCCC")) end def inspect # :nodoc: return "#<#{self.class} #{self.to_s}>" end ## # Turns this IPv4 address into a Resolv::DNS::Name. def to_name return DNS::Name.create( '%d.%d.%d.%d.in-addr.arpa.' % @address.unpack('CCCC').reverse) end def ==(other) # :nodoc: return @address == other.address end def eql?(other) # :nodoc: return self == other end def hash # :nodoc: return @address.hash end end ## # A Resolv::DNS IPv6 address. class IPv6 ## # IPv6 address format a:b:c:d:e:f:g:h Regex_8Hex = /\A (?:[0-9A-Fa-f]{1,4}:){7} [0-9A-Fa-f]{1,4} \z/x ## # Compressed IPv6 address format a::b Regex_CompressedHex = /\A ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) :: ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) \z/x ## # IPv4 mapped IPv6 address format a:b:c:d:e:f:w.x.y.z Regex_6Hex4Dec = /\A ((?:[0-9A-Fa-f]{1,4}:){6,6}) (\d+)\.(\d+)\.(\d+)\.(\d+) \z/x ## # Compressed IPv4 mapped IPv6 address format a::b:w.x.y.z Regex_CompressedHex4Dec = /\A ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) :: ((?:[0-9A-Fa-f]{1,4}:)*) (\d+)\.(\d+)\.(\d+)\.(\d+) \z/x ## # A composite IPv6 address Regexp. Regex = / (?:#{Regex_8Hex}) | (?:#{Regex_CompressedHex}) | (?:#{Regex_6Hex4Dec}) | (?:#{Regex_CompressedHex4Dec})/x ## # Creates a new IPv6 address from +arg+ which may be: # # IPv6:: returns +arg+. # String:: +arg+ must match one of the IPv6::Regex* constants def self.create(arg) case arg when IPv6 return arg when String address = '' if Regex_8Hex =~ arg arg.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')} elsif Regex_CompressedHex =~ arg prefix = $1 suffix = $2 a1 = '' a2 = '' prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')} suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')} omitlen = 16 - a1.length - a2.length address << a1 << "\0" * omitlen << a2 elsif Regex_6Hex4Dec =~ arg prefix, a, b, c, d = $1, $2.to_i, $3.to_i, $4.to_i, $5.to_i if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d prefix.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')} address << [a, b, c, d].pack('CCCC') else raise ArgumentError.new("not numeric IPv6 address: " + arg) end elsif Regex_CompressedHex4Dec =~ arg prefix, suffix, a, b, c, d = $1, $2, $3.to_i, $4.to_i, $5.to_i, $6.to_i if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d a1 = '' a2 = '' prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')} suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')} omitlen = 12 - a1.length - a2.length address << a1 << "\0" * omitlen << a2 << [a, b, c, d].pack('CCCC') else raise ArgumentError.new("not numeric IPv6 address: " + arg) end else raise ArgumentError.new("not numeric IPv6 address: " + arg) end return IPv6.new(address) else raise ArgumentError.new("cannot interpret as IPv6 address: #{arg.inspect}") end end def initialize(address) # :nodoc: unless address.kind_of?(String) && address.length == 16 raise ArgumentError.new('IPv6 address must be 16 bytes') end @address = address end ## # The raw IPv6 address as a String. attr_reader :address def to_s # :nodoc: address = sprintf("%X:%X:%X:%X:%X:%X:%X:%X", *@address.unpack("nnnnnnnn")) unless address.sub!(/(^|:)0(:0)+(:|$)/, '::') address.sub!(/(^|:)0(:|$)/, '::') end return address end def inspect # :nodoc: return "#<#{self.class} #{self.to_s}>" end ## # Turns this IPv6 address into a Resolv::DNS::Name. #-- # ip6.arpa should be searched too. [RFC3152] def to_name return DNS::Name.new( @address.unpack("H32")[0].split(//).reverse + ['ip6', 'arpa']) end def ==(other) # :nodoc: return @address == other.address end def eql?(other) # :nodoc: return self == other end def hash # :nodoc: return @address.hash end end ## # Default resolver to use for Resolv class methods. DefaultResolver = self.new ## # Address Regexp to use for matching IP addresses. AddressRegex = /(?:#{IPv4::Regex})|(?:#{IPv6::Regex})/ end ================================================ FILE: lib/rexml/attlistdecl.rb ================================================ #vim:ts=2 sw=2 noexpandtab: require 'rexml/child' require 'rexml/source' module REXML # This class needs: # * Documentation # * Work! Not all types of attlists are intelligently parsed, so we just # spew back out what we get in. This works, but it would be better if # we formatted the output ourselves. # # AttlistDecls provide *just* enough support to allow namespace # declarations. If you need some sort of generalized support, or have an # interesting idea about how to map the hideous, terrible design of DTD # AttlistDecls onto an intuitive Ruby interface, let me know. I'm desperate # for anything to make DTDs more palateable. class AttlistDecl < Child include Enumerable # What is this? Got me. attr_reader :element_name # Create an AttlistDecl, pulling the information from a Source. Notice # that this isn't very convenient; to create an AttlistDecl, you basically # have to format it yourself, and then have the initializer parse it. # Sorry, but for the forseeable future, DTD support in REXML is pretty # weak on convenience. Have I mentioned how much I hate DTDs? def initialize(source) super() if (source.kind_of? Array) @element_name, @pairs, @contents = *source end end # Access the attlist attribute/value pairs. # value = attlist_decl[ attribute_name ] def [](key) @pairs[key] end # Whether an attlist declaration includes the given attribute definition # if attlist_decl.include? "xmlns:foobar" def include?(key) @pairs.keys.include? key end # Iterate over the key/value pairs: # attlist_decl.each { |attribute_name, attribute_value| ... } def each(&block) @pairs.each(&block) end # Write out exactly what we got in. def write out, indent=-1 out << @contents end def node_type :attlistdecl end end end ================================================ FILE: lib/rexml/attribute.rb ================================================ require "rexml/namespace" require 'rexml/text' module REXML # Defines an Element Attribute; IE, a attribute=value pair, as in: # . Attributes can be in their own # namespaces. General users of REXML will not interact with the # Attribute class much. class Attribute include Node include Namespace # The element to which this attribute belongs attr_reader :element # The normalized value of this attribute. That is, the attribute with # entities intact. attr_writer :normalized PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\2/um # Constructor. # FIXME: The parser doesn't catch illegal characters in attributes # # first:: # Either: an Attribute, which this new attribute will become a # clone of; or a String, which is the name of this attribute # second:: # If +first+ is an Attribute, then this may be an Element, or nil. # If nil, then the Element parent of this attribute is the parent # of the +first+ Attribute. If the first argument is a String, # then this must also be a String, and is the content of the attribute. # If this is the content, it must be fully normalized (contain no # illegal characters). # parent:: # Ignored unless +first+ is a String; otherwise, may be the Element # parent of this attribute, or nil. # # # Attribute.new( attribute_to_clone ) # Attribute.new( attribute_to_clone, parent_element ) # Attribute.new( "attr", "attr_value" ) # Attribute.new( "attr", "attr_value", parent_element ) def initialize( first, second=nil, parent=nil ) @normalized = @unnormalized = @element = nil if first.kind_of? Attribute self.name = first.expanded_name @unnormalized = first.value if second.kind_of? Element @element = second else @element = first.element end elsif first.kind_of? String @element = parent self.name = first @normalized = second.to_s else raise "illegal argument #{first.class.name} to Attribute constructor" end end # Returns the namespace of the attribute. # # e = Element.new( "elns:myelement" ) # e.add_attribute( "nsa:a", "aval" ) # e.add_attribute( "b", "bval" ) # e.attributes.get_attribute( "a" ).prefix # -> "nsa" # e.attributes.get_attribute( "b" ).prefix # -> "elns" # a = Attribute.new( "x", "y" ) # a.prefix # -> "" def prefix pf = super if pf == "" pf = @element.prefix if @element end pf end # Returns the namespace URL, if defined, or nil otherwise # # e = Element.new("el") # e.add_attributes({"xmlns:ns", "http://url"}) # e.namespace( "ns" ) # -> "http://url" def namespace arg=nil arg = prefix if arg.nil? @element.namespace arg end # Returns true if other is an Attribute and has the same name and value, # false otherwise. def ==( other ) other.kind_of?(Attribute) and other.name==name and other.value==value end # Creates (and returns) a hash from both the name and value def hash name.hash + value.hash end # Returns this attribute out as XML source, expanding the name # # a = Attribute.new( "x", "y" ) # a.to_string # -> "x='y'" # b = Attribute.new( "ns:x", "y" ) # b.to_string # -> "ns:x='y'" def to_string if @element and @element.context and @element.context[:attribute_quote] == :quote %Q^#@expanded_name="#{to_s().gsub(/"/, '"e;')}"^ else "#@expanded_name='#{to_s().gsub(/'/, ''')}'" end end # Returns the attribute value, with entities replaced def to_s return @normalized if @normalized doctype = nil if @element doc = @element.document doctype = doc.doctype if doc end @normalized = Text::normalize( @unnormalized, doctype ) @unnormalized = nil @normalized end # Returns the UNNORMALIZED value of this attribute. That is, entities # have been expanded to their values def value return @unnormalized if @unnormalized doctype = nil if @element doc = @element.document doctype = doc.doctype if doc end @unnormalized = Text::unnormalize( @normalized, doctype ) @normalized = nil @unnormalized end # Returns a copy of this attribute def clone Attribute.new self end # Sets the element of which this object is an attribute. Normally, this # is not directly called. # # Returns this attribute def element=( element ) @element = element self end # Removes this Attribute from the tree, and returns true if successfull # # This method is usually not called directly. def remove @element.attributes.delete self.name unless @element.nil? end # Writes this attribute (EG, puts 'key="value"' to the output) def write( output, indent=-1 ) output << to_string end def node_type :attribute end def inspect rv = "" write( rv ) rv end def xpath path = @element.xpath path += "/@#{self.expanded_name}" return path end end end #vim:ts=2 sw=2 noexpandtab: ================================================ FILE: lib/rexml/cdata.rb ================================================ require "rexml/text" module REXML class CData < Text START = '' ILLEGAL = /(\]\]>)/ # Constructor. CData is data between # # _Examples_ # CData.new( source ) # CData.new( "Here is some CDATA" ) # CData.new( "Some unprocessed data", respect_whitespace_TF, parent_element ) def initialize( first, whitespace=true, parent=nil ) super( first, whitespace, parent, true, true, ILLEGAL ) end # Make a copy of this object # # _Examples_ # c = CData.new( "Some text" ) # d = c.clone # d.to_s # -> "Some text" def clone CData.new self end # Returns the content of this CData object # # _Examples_ # c = CData.new( "Some text" ) # c.to_s # -> "Some text" def to_s @string end def value @string end # == DEPRECATED # See the rexml/formatters package # # Generates XML output of this object # # output:: # Where to write the string. Defaults to $stdout # indent:: # The amount to indent this node by # transitive:: # Ignored # ie_hack:: # Ignored # # _Examples_ # c = CData.new( " Some text " ) # c.write( $stdout ) #-> def write( output=$stdout, indent=-1, transitive=false, ie_hack=false ) Kernel.warn( "#{self.class.name}.write is deprecated" ) indent( output, indent ) output << START output << @string output << STOP end end end ================================================ FILE: lib/rexml/child.rb ================================================ require "rexml/node" module REXML ## # A Child object is something contained by a parent, and this class # contains methods to support that. Most user code will not use this # class directly. class Child include Node attr_reader :parent # The Parent of this object # Constructor. Any inheritors of this class should call super to make # sure this method is called. # parent:: # if supplied, the parent of this child will be set to the # supplied value, and self will be added to the parent def initialize( parent = nil ) @parent = nil # Declare @parent, but don't define it. The next line sets the # parent. parent.add( self ) if parent end # Replaces this object with another object. Basically, calls # Parent.replace_child # # Returns:: self def replace_with( child ) @parent.replace_child( self, child ) self end # Removes this child from the parent. # # Returns:: self def remove unless @parent.nil? @parent.delete self end self end # Sets the parent of this child to the supplied argument. # # other:: # Must be a Parent object. If this object is the same object as the # existing parent of this child, no action is taken. Otherwise, this # child is removed from the current parent (if one exists), and is added # to the new parent. # Returns:: The parent added def parent=( other ) return @parent if @parent == other @parent.delete self if defined? @parent and @parent @parent = other end alias :next_sibling :next_sibling_node alias :previous_sibling :previous_sibling_node # Sets the next sibling of this child. This can be used to insert a child # after some other child. # a = Element.new("a") # b = a.add_element("b") # c = Element.new("c") # b.next_sibling = c # # => def next_sibling=( other ) parent.insert_after self, other end # Sets the previous sibling of this child. This can be used to insert a # child before some other child. # a = Element.new("a") # b = a.add_element("b") # c = Element.new("c") # b.previous_sibling = c # # => def previous_sibling=(other) parent.insert_before self, other end # Returns:: the document this child belongs to, or nil if this child # belongs to no document def document return parent.document unless parent.nil? nil end # This doesn't yet handle encodings def bytes encoding = document.encoding to_s end end end ================================================ FILE: lib/rexml/comment.rb ================================================ require "rexml/child" module REXML ## # Represents an XML comment; that is, text between \ class Comment < Child include Comparable START = "" # The content text attr_accessor :string ## # Constructor. The first argument can be one of three types: # @param first If String, the contents of this comment are set to the # argument. If Comment, the argument is duplicated. If # Source, the argument is scanned for a comment. # @param second If the first argument is a Source, this argument # should be nil, not supplied, or a Parent to be set as the parent # of this object def initialize( first, second = nil ) #puts "IN COMMENT CONSTRUCTOR; SECOND IS #{second.type}" super(second) if first.kind_of? String @string = first elsif first.kind_of? Comment @string = first.string end end def clone Comment.new self end # == DEPRECATED # See REXML::Formatters # # output:: # Where to write the string # indent:: # An integer. If -1, no indenting will be used; otherwise, the # indentation will be this number of spaces, and children will be # indented an additional amount. # transitive:: # Ignored by this class. The contents of comments are never modified. # ie_hack:: # Needed for conformity to the child API, but not used by this class. def write( output, indent=-1, transitive=false, ie_hack=false ) Kernel.warn("Comment.write is deprecated. See REXML::Formatters") indent( output, indent ) output << START output << @string output << STOP end alias :to_s :string ## # Compares this Comment to another; the contents of the comment are used # in the comparison. def <=>(other) other.to_s <=> @string end ## # Compares this Comment to another; the contents of the comment are used # in the comparison. def ==( other ) other.kind_of? Comment and (other <=> self) == 0 end def node_type :comment end end end #vim:ts=2 sw=2 noexpandtab: ================================================ FILE: lib/rexml/doctype.rb ================================================ require "rexml/parent" require "rexml/parseexception" require "rexml/namespace" require 'rexml/entity' require 'rexml/attlistdecl' require 'rexml/xmltokens' module REXML # Represents an XML DOCTYPE declaration; that is, the contents of . DOCTYPES can be used to declare the DTD of a document, as well as # being used to declare entities used in the document. class DocType < Parent include XMLTokens START = "" SYSTEM = "SYSTEM" PUBLIC = "PUBLIC" DEFAULT_ENTITIES = { 'gt'=>EntityConst::GT, 'lt'=>EntityConst::LT, 'quot'=>EntityConst::QUOT, "apos"=>EntityConst::APOS } # name is the name of the doctype # external_id is the referenced DTD, if given attr_reader :name, :external_id, :entities, :namespaces # Constructor # # dt = DocType.new( 'foo', '-//I/Hate/External/IDs' ) # # # dt = DocType.new( doctype_to_clone ) # # Incomplete. Shallow clone of doctype # # +Note+ that the constructor: # # Doctype.new( Source.new( "" ) ) # # is _deprecated_. Do not use it. It will probably disappear. def initialize( first, parent=nil ) @entities = DEFAULT_ENTITIES @long_name = @uri = nil if first.kind_of? String super() @name = first @external_id = parent elsif first.kind_of? DocType super( parent ) @name = first.name @external_id = first.external_id elsif first.kind_of? Array super( parent ) @name = first[0] @external_id = first[1] @long_name = first[2] @uri = first[3] elsif first.kind_of? Source super( parent ) parser = Parsers::BaseParser.new( first ) event = parser.pull if event[0] == :start_doctype @name, @external_id, @long_name, @uri, = event[1..-1] end else super() end end def node_type :doctype end def attributes_of element rv = [] each do |child| child.each do |key,val| rv << Attribute.new(key,val) end if child.kind_of? AttlistDecl and child.element_name == element end rv end def attribute_of element, attribute att_decl = find do |child| child.kind_of? AttlistDecl and child.element_name == element and child.include? attribute end return nil unless att_decl att_decl[attribute] end def clone DocType.new self end # output:: # Where to write the string # indent:: # An integer. If -1, no indentation will be used; otherwise, the # indentation will be this number of spaces, and children will be # indented an additional amount. # transitive:: # Ignored # ie_hack:: # Ignored def write( output, indent=0, transitive=false, ie_hack=false ) f = REXML::Formatters::Default.new indent( output, indent ) output << START output << ' ' output << @name output << " #@external_id" if @external_id output << " #{@long_name.inspect}" if @long_name output << " #{@uri.inspect}" if @uri unless @children.empty? next_indent = indent + 1 output << ' [' child = nil # speed @children.each { |child| output << "\n" f.write( child, output ) } output << "\n]" end output << STOP end def context @parent.context end def entity( name ) @entities[name].unnormalized if @entities[name] end def add child super(child) @entities = DEFAULT_ENTITIES.clone if @entities == DEFAULT_ENTITIES @entities[ child.name ] = child if child.kind_of? Entity end # This method retrieves the public identifier identifying the document's # DTD. # # Method contributed by Henrik Martensson def public case @external_id when "SYSTEM" nil when "PUBLIC" strip_quotes(@long_name) end end # This method retrieves the system identifier identifying the document's DTD # # Method contributed by Henrik Martensson def system case @external_id when "SYSTEM" strip_quotes(@long_name) when "PUBLIC" @uri.kind_of?(String) ? strip_quotes(@uri) : nil end end # This method returns a list of notations that have been declared in the # _internal_ DTD subset. Notations in the external DTD subset are not # listed. # # Method contributed by Henrik Martensson def notations children().select {|node| node.kind_of?(REXML::NotationDecl)} end # Retrieves a named notation. Only notations declared in the internal # DTD subset can be retrieved. # # Method contributed by Henrik Martensson def notation(name) notations.find { |notation_decl| notation_decl.name == name } end private # Method contributed by Henrik Martensson def strip_quotes(quoted_string) quoted_string =~ /^[\'\"].*[\´\"]$/ ? quoted_string[1, quoted_string.length-2] : quoted_string end end # We don't really handle any of these since we're not a validating # parser, so we can be pretty dumb about them. All we need to be able # to do is spew them back out on a write() # This is an abstract class. You never use this directly; it serves as a # parent class for the specific declarations. class Declaration < Child def initialize src super() @string = src end def to_s @string+'>' end # == DEPRECATED # See REXML::Formatters # def write( output, indent ) output << to_s end end public class ElementDecl < Declaration def initialize( src ) super end end class ExternalEntity < Child def initialize( src ) super() @entity = src end def to_s @entity end def write( output, indent ) output << @entity end end class NotationDecl < Child attr_accessor :public, :system def initialize name, middle, pub, sys super(nil) @name = name @middle = middle @public = pub @system = sys end def to_s "" end def write( output, indent=-1 ) output << to_s end # This method retrieves the name of the notation. # # Method contributed by Henrik Martensson def name @name end end end ================================================ FILE: lib/rexml/document.rb ================================================ require "rexml/element" require "rexml/xmldecl" require "rexml/source" require "rexml/comment" require "rexml/doctype" require "rexml/instruction" require "rexml/rexml" require "rexml/parseexception" require "rexml/output" require "rexml/parsers/baseparser" require "rexml/parsers/streamparser" require "rexml/parsers/treeparser" module REXML # Represents a full XML document, including PIs, a doctype, etc. A # Document has a single child that can be accessed by root(). # Note that if you want to have an XML declaration written for a document # you create, you must add one; REXML documents do not write a default # declaration for you. See |DECLARATION| and |write|. class Document < Element # A convenient default XML declaration. If you want an XML declaration, # the easiest way to add one is mydoc << Document::DECLARATION # +DEPRECATED+ # Use: mydoc << XMLDecl.default DECLARATION = XMLDecl.default # Constructor # @param source if supplied, must be a Document, String, or IO. # Documents have their context and Element attributes cloned. # Strings are expected to be valid XML documents. IOs are expected # to be sources of valid XML documents. # @param context if supplied, contains the context of the document; # this should be a Hash. def initialize( source = nil, context = {} ) @entity_expansion_count = 0 super() @context = context return if source.nil? if source.kind_of? Document @context = source.context super source else build( source ) end end def node_type :document end # Should be obvious def clone Document.new self end # According to the XML spec, a root node has no expanded name def expanded_name '' #d = doc_type #d ? d.name : "UNDEFINED" end alias :name :expanded_name # We override this, because XMLDecls and DocTypes must go at the start # of the document def add( child ) if child.kind_of? XMLDecl @children.unshift child child.parent = self elsif child.kind_of? DocType # Find first Element or DocType node and insert the decl right # before it. If there is no such node, just insert the child at the # end. If there is a child and it is an DocType, then replace it. insert_before_index = 0 @children.find { |x| insert_before_index += 1 x.kind_of?(Element) || x.kind_of?(DocType) } if @children[ insert_before_index ] # Not null = not end of list if @children[ insert_before_index ].kind_of DocType @children[ insert_before_index ] = child else @children[ index_before_index-1, 0 ] = child end else # Insert at end of list @children[insert_before_index] = child end child.parent = self else rv = super raise "attempted adding second root element to document" if @elements.size > 1 rv end end alias :<< :add def add_element(arg=nil, arg2=nil) rv = super raise "attempted adding second root element to document" if @elements.size > 1 rv end # @return the root Element of the document, or nil if this document # has no children. def root elements[1] #self #@children.find { |item| item.kind_of? Element } end # @return the DocType child of the document, if one exists, # and nil otherwise. def doctype @children.find { |item| item.kind_of? DocType } end # @return the XMLDecl of this document; if no XMLDecl has been # set, the default declaration is returned. def xml_decl rv = @children[0] return rv if rv.kind_of? XMLDecl rv = @children.unshift(XMLDecl.default)[0] end # @return the XMLDecl version of this document as a String. # If no XMLDecl has been set, returns the default version. def version xml_decl().version end # @return the XMLDecl encoding of this document as a String. # If no XMLDecl has been set, returns the default encoding. def encoding xml_decl().encoding end # @return the XMLDecl standalone value of this document as a String. # If no XMLDecl has been set, returns the default setting. def stand_alone? xml_decl().stand_alone? end # Write the XML tree out, optionally with indent. This writes out the # entire XML document, including XML declarations, doctype declarations, # and processing instructions (if any are given). # # A controversial point is whether Document should always write the XML # declaration () whether or not one is given by the # user (or source document). REXML does not write one if one was not # specified, because it adds unnecessary bandwidth to applications such # as XML-RPC. # # See also the classes in the rexml/formatters package for the proper way # to change the default formatting of XML output # # _Examples_ # Document.new("").serialize # # output_string = "" # tr = Transitive.new( output_string ) # Document.new("").serialize( tr ) # # output:: # output an object which supports '<< string'; this is where the # document will be written. # indent:: # An integer. If -1, no indenting will be used; otherwise, the # indentation will be twice this number of spaces, and children will be # indented an additional amount. For a value of 3, every item will be # indented 3 more levels, or 6 more spaces (2 * 3). Defaults to -1 # trans:: # If transitive is true and indent is >= 0, then the output will be # pretty-printed in such a way that the added whitespace does not affect # the absolute *value* of the document -- that is, it leaves the value # and number of Text nodes in the document unchanged. # ie_hack:: # Internet Explorer is the worst piece of crap to have ever been # written, with the possible exception of Windows itself. Since IE is # unable to parse proper XML, we have to provide a hack to generate XML # that IE's limited abilities can handle. This hack inserts a space # before the /> on empty tags. Defaults to false def write( output=$stdout, indent=-1, trans=false, ie_hack=false ) if xml_decl.encoding != "UTF-8" && !output.kind_of?(Output) output = Output.new( output, xml_decl.encoding ) end formatter = if indent > -1 if trans REXML::Formatters::Transitive.new( indent, ie_hack ) else REXML::Formatters::Pretty.new( indent, ie_hack ) end else REXML::Formatters::Default.new( ie_hack ) end formatter.write( self, output ) end def Document::parse_stream( source, listener ) Parsers::StreamParser.new( source, listener ).parse end @@entity_expansion_limit = 10_000 # Set the entity expansion limit. By default the limit is set to 10000. def Document::entity_expansion_limit=( val ) @@entity_expansion_limit = val end # Get the entity expansion limit. By default the limit is set to 10000. def Document::entity_expansion_limit return @@entity_expansion_limit end attr_reader :entity_expansion_count def record_entity_expansion @entity_expansion_count += 1 if @entity_expansion_count > @@entity_expansion_limit raise "number of entity expansions exceeded, processing aborted." end end private def build( source ) Parsers::TreeParser.new( source, self ).parse end end end ================================================ FILE: lib/rexml/dtd/attlistdecl.rb ================================================ require "rexml/child" module REXML module DTD class AttlistDecl < Child START = ")/um end end end ================================================ FILE: lib/rexml/dtd/dtd.rb ================================================ require "rexml/dtd/elementdecl" require "rexml/dtd/entitydecl" require "rexml/comment" require "rexml/dtd/notationdecl" require "rexml/dtd/attlistdecl" require "rexml/parent" module REXML module DTD class Parser def Parser.parse( input ) case input when String parse_helper input when File parse_helper input.read end end # Takes a String and parses it out def Parser.parse_helper( input ) contents = Parent.new while input.size > 0 case input when ElementDecl.PATTERN_RE match = $& source = $' contents << ElementDecl.new( match ) when AttlistDecl.PATTERN_RE matchdata = $~ source = $' contents << AttlistDecl.new( matchdata ) when EntityDecl.PATTERN_RE matchdata = $~ source = $' contents << EntityDecl.new( matchdata ) when Comment.PATTERN_RE matchdata = $~ source = $' contents << Comment.new( matchdata ) when NotationDecl.PATTERN_RE matchdata = $~ source = $' contents << NotationDecl.new( matchdata ) end end contents end end end end ================================================ FILE: lib/rexml/dtd/elementdecl.rb ================================================ require "rexml/child" module REXML module DTD class ElementDecl < Child START = "/um PATTERN_RE = /^\s*#{START}\s+((?:[:\w_][-\.\w_]*:)?[-!\*\.\w_]*)(.*?)>/ #\s*((((["']).*?\5)|[^\/'">]*)*?)(\/)?>/um, true) def initialize match @name = match[1] @rest = match[2] end end end end ================================================ FILE: lib/rexml/dtd/entitydecl.rb ================================================ require "rexml/child" module REXML module DTD class EntityDecl < Child START = "/um SYSTEM = /^\s*#{START}\s+(?:%\s+)?(\w+)\s+SYSTEM\s+((["']).*?\3)(?:\s+NDATA\s+\w+)?\s*>/um PLAIN = /^\s*#{START}\s+(\w+)\s+((["']).*?\3)\s*>/um PERCENT = /^\s*#{START}\s+%\s+(\w+)\s+((["']).*?\3)\s*>/um # # def initialize src super() md = nil if src.match( PUBLIC ) md = src.match( PUBLIC, true ) @middle = "PUBLIC" @content = "#{md[2]} #{md[4]}" elsif src.match( SYSTEM ) md = src.match( SYSTEM, true ) @middle = "SYSTEM" @content = md[2] elsif src.match( PLAIN ) md = src.match( PLAIN, true ) @middle = "" @content = md[2] elsif src.match( PERCENT ) md = src.match( PERCENT, true ) @middle = "" @content = md[2] end raise ParseException.new("failed Entity match", src) if md.nil? @name = md[1] end def to_s rv = " 0 rv << @content rv end def write( output, indent ) indent( output, indent ) output << to_s end def EntityDecl.parse_source source, listener md = source.match( PATTERN_RE, true ) thing = md[0].squeeze(" \t\n\r") listener.send inspect.downcase, thing end end end end ================================================ FILE: lib/rexml/dtd/notationdecl.rb ================================================ require "rexml/child" module REXML module DTD class NotationDecl < Child START = "/um SYSTEM = /^\s*#{START}\s+(\w[\w-]*)\s+(SYSTEM)\s+((["']).*?\4)\s*>/um def initialize src super() if src.match( PUBLIC ) md = src.match( PUBLIC, true ) elsif src.match( SYSTEM ) md = src.match( SYSTEM, true ) else raise ParseException.new( "error parsing notation: no matching pattern", src ) end @name = md[1] @middle = md[2] @rest = md[3] end def to_s "" end def write( output, indent ) indent( output, indent ) output << to_s end def NotationDecl.parse_source source, listener md = source.match( PATTERN_RE, true ) thing = md[0].squeeze(" \t\n\r") listener.send inspect.downcase, thing end end end end ================================================ FILE: lib/rexml/element.rb ================================================ require "rexml/parent" require "rexml/namespace" require "rexml/attribute" require "rexml/cdata" require "rexml/xpath" require "rexml/parseexception" module REXML # An implementation note about namespaces: # As we parse, when we find namespaces we put them in a hash and assign # them a unique ID. We then convert the namespace prefix for the node # to the unique ID. This makes namespace lookup much faster for the # cost of extra memory use. We save the namespace prefix for the # context node and convert it back when we write it. @@namespaces = {} # Represents a tagged XML element. Elements are characterized by # having children, attributes, and names, and can themselves be # children. class Element < Parent include Namespace UNDEFINED = "UNDEFINED"; # The default name # Mechanisms for accessing attributes and child elements of this # element. attr_reader :attributes, :elements # The context holds information about the processing environment, such as # whitespace handling. attr_accessor :context # Constructor # arg:: # if not supplied, will be set to the default value. # If a String, the name of this object will be set to the argument. # If an Element, the object will be shallowly cloned; name, # attributes, and namespaces will be copied. Children will +not+ be # copied. # parent:: # if supplied, must be a Parent, and will be used as # the parent of this object. # context:: # If supplied, must be a hash containing context items. Context items # include: # * :respect_whitespace the value of this is :+all+ or an array of # strings being the names of the elements to respect # whitespace for. Defaults to :+all+. # * :compress_whitespace the value can be :+all+ or an array of # strings being the names of the elements to ignore whitespace on. # Overrides :+respect_whitespace+. # * :ignore_whitespace_nodes the value can be :+all+ or an array # of strings being the names of the elements in which to ignore # whitespace-only nodes. If this is set, Text nodes which contain only # whitespace will not be added to the document tree. # * :raw can be :+all+, or an array of strings being the names of # the elements to process in raw mode. In raw mode, special # characters in text is not converted to or from entities. def initialize( arg = UNDEFINED, parent=nil, context=nil ) super(parent) @elements = Elements.new(self) @attributes = Attributes.new(self) @context = context if arg.kind_of? String self.name = arg elsif arg.kind_of? Element self.name = arg.expanded_name arg.attributes.each_attribute{ |attribute| @attributes << Attribute.new( attribute ) } @context = arg.context end end def inspect rv = "<#@expanded_name" @attributes.each_attribute do |attr| rv << " " attr.write( rv, 0 ) end if children.size > 0 rv << "> ... " else rv << "/>" end end # Creates a shallow copy of self. # d = Document.new "" # new_a = d.root.clone # puts new_a # => "" def clone self.class.new self end # Evaluates to the root node of the document that this element # belongs to. If this element doesn't belong to a document, but does # belong to another Element, the parent's root will be returned, until the # earliest ancestor is found. # # Note that this is not the same as the document element. # In the following example, is the document element, and the root # node is the parent node of the document element. You may ask yourself # why the root node is useful: consider the doctype and XML declaration, # and any processing instructions before the document element... they # are children of the root node, or siblings of the document element. # The only time this isn't true is when an Element is created that is # not part of any Document. In this case, the ancestor that has no # parent acts as the root node. # d = Document.new '' # a = d[1] ; c = a[1][1] # d.root_node == d # TRUE # a.root_node # namely, d # c.root_node # again, d def root_node parent.nil? ? self : parent.root_node end def root return elements[1] if self.kind_of? Document return self if parent.kind_of? Document or parent.nil? return parent.root end # Evaluates to the document to which this element belongs, or nil if this # element doesn't belong to a document. def document rt = root rt.parent if rt end # Evaluates to +true+ if whitespace is respected for this element. This # is the case if: # 1. Neither :+respect_whitespace+ nor :+compress_whitespace+ has any value # 2. The context has :+respect_whitespace+ set to :+all+ or # an array containing the name of this element, and # :+compress_whitespace+ isn't set to :+all+ or an array containing the # name of this element. # The evaluation is tested against +expanded_name+, and so is namespace # sensitive. def whitespace @whitespace = nil if @context if @context[:respect_whitespace] @whitespace = (@context[:respect_whitespace] == :all or @context[:respect_whitespace].include? expanded_name) end @whitespace = false if (@context[:compress_whitespace] and (@context[:compress_whitespace] == :all or @context[:compress_whitespace].include? expanded_name) ) end @whitespace = true unless @whitespace == false @whitespace end def ignore_whitespace_nodes @ignore_whitespace_nodes = false if @context if @context[:ignore_whitespace_nodes] @ignore_whitespace_nodes = (@context[:ignore_whitespace_nodes] == :all or @context[:ignore_whitespace_nodes].include? expanded_name) end end end # Evaluates to +true+ if raw mode is set for this element. This # is the case if the context has :+raw+ set to :+all+ or # an array containing the name of this element. # # The evaluation is tested against +expanded_name+, and so is namespace # sensitive. def raw @raw = (@context and @context[:raw] and (@context[:raw] == :all or @context[:raw].include? expanded_name)) @raw end #once :whitespace, :raw, :ignore_whitespace_nodes ################################################# # Namespaces # ################################################# # Evaluates to an +Array+ containing the prefixes (names) of all defined # namespaces at this context node. # doc = Document.new("") # doc.elements['//b'].prefixes # -> ['x', 'y'] def prefixes prefixes = [] prefixes = parent.prefixes if parent prefixes |= attributes.prefixes return prefixes end def namespaces namespaces = {} namespaces = parent.namespaces if parent namespaces = namespaces.merge( attributes.namespaces ) return namespaces end # Evalutas to the URI for a prefix, or the empty string if no such # namespace is declared for this element. Evaluates recursively for # ancestors. Returns the default namespace, if there is one. # prefix:: # the prefix to search for. If not supplied, returns the default # namespace if one exists # Returns:: # the namespace URI as a String, or nil if no such namespace # exists. If the namespace is undefined, returns an empty string # doc = Document.new("") # b = doc.elements['//b'] # b.namespace # -> '1' # b.namespace("y") # -> '2' def namespace(prefix=nil) if prefix.nil? prefix = prefix() end if prefix == '' prefix = "xmlns" else prefix = "xmlns:#{prefix}" unless prefix[0,5] == 'xmlns' end ns = attributes[ prefix ] ns = parent.namespace(prefix) if ns.nil? and parent ns = '' if ns.nil? and prefix == 'xmlns' return ns end # Adds a namespace to this element. # prefix:: # the prefix string, or the namespace URI if +uri+ is not # supplied # uri:: # the namespace URI. May be nil, in which +prefix+ is used as # the URI # Evaluates to: this Element # a = Element.new("a") # a.add_namespace("xmlns:foo", "bar" ) # a.add_namespace("foo", "bar") # shorthand for previous line # a.add_namespace("twiddle") # puts a #-> def add_namespace( prefix, uri=nil ) unless uri @attributes["xmlns"] = prefix else prefix = "xmlns:#{prefix}" unless prefix =~ /^xmlns:/ @attributes[ prefix ] = uri end self end # Removes a namespace from this node. This only works if the namespace is # actually declared in this node. If no argument is passed, deletes the # default namespace. # # Evaluates to: this element # doc = Document.new "" # doc.root.delete_namespace # puts doc # -> # doc.root.delete_namespace 'foo' # puts doc # -> def delete_namespace namespace="xmlns" namespace = "xmlns:#{namespace}" unless namespace == 'xmlns' attribute = attributes.get_attribute(namespace) attribute.remove unless attribute.nil? self end ################################################# # Elements # ################################################# # Adds a child to this element, optionally setting attributes in # the element. # element:: # optional. If Element, the element is added. # Otherwise, a new Element is constructed with the argument (see # Element.initialize). # attrs:: # If supplied, must be a Hash containing String name,value # pairs, which will be used to set the attributes of the new Element. # Returns:: the Element that was added # el = doc.add_element 'my-tag' # el = doc.add_element 'my-tag', {'attr1'=>'val1', 'attr2'=>'val2'} # el = Element.new 'my-tag' # doc.add_element el def add_element element, attrs=nil raise "First argument must be either an element name, or an Element object" if element.nil? el = @elements.add(element) attrs.each do |key, value| el.attributes[key]=Attribute.new(key,value,self) end if attrs.kind_of? Hash el end # Deletes a child element. # element:: # Must be an +Element+, +String+, or +Integer+. If Element, # the element is removed. If String, the element is found (via XPath) # and removed. This means that any parent can remove any # descendant. If Integer, the Element indexed by that number will be # removed. # Returns:: the element that was removed. # doc.delete_element "/a/b/c[@id='4']" # doc.delete_element doc.elements["//k"] # doc.delete_element 1 def delete_element element @elements.delete element end # Evaluates to +true+ if this element has at least one child Element # doc = Document.new "Text" # doc.root.has_elements # -> true # doc.elements["/a/b"].has_elements # -> false # doc.elements["/a/c"].has_elements # -> false def has_elements? !@elements.empty? end # Iterates through the child elements, yielding for each Element that # has a particular attribute set. # key:: # the name of the attribute to search for # value:: # the value of the attribute # max:: # (optional) causes this method to return after yielding # for this number of matching children # name:: # (optional) if supplied, this is an XPath that filters # the children to check. # # doc = Document.new "" # # Yields b, c, d # doc.root.each_element_with_attribute( 'id' ) {|e| p e} # # Yields b, d # doc.root.each_element_with_attribute( 'id', '1' ) {|e| p e} # # Yields b # doc.root.each_element_with_attribute( 'id', '1', 1 ) {|e| p e} # # Yields d # doc.root.each_element_with_attribute( 'id', '1', 0, 'd' ) {|e| p e} def each_element_with_attribute( key, value=nil, max=0, name=nil, &block ) # :yields: Element each_with_something( proc {|child| if value.nil? child.attributes[key] != nil else child.attributes[key]==value end }, max, name, &block ) end # Iterates through the children, yielding for each Element that # has a particular text set. # text:: # the text to search for. If nil, or not supplied, will iterate # over all +Element+ children that contain at least one +Text+ node. # max:: # (optional) causes this method to return after yielding # for this number of matching children # name:: # (optional) if supplied, this is an XPath that filters # the children to check. # # doc = Document.new 'bbd' # # Yields b, c, d # doc.each_element_with_text {|e|p e} # # Yields b, c # doc.each_element_with_text('b'){|e|p e} # # Yields b # doc.each_element_with_text('b', 1){|e|p e} # # Yields d # doc.each_element_with_text(nil, 0, 'd'){|e|p e} def each_element_with_text( text=nil, max=0, name=nil, &block ) # :yields: Element each_with_something( proc {|child| if text.nil? child.has_text? else child.text == text end }, max, name, &block ) end # Synonym for Element.elements.each def each_element( xpath=nil, &block ) # :yields: Element @elements.each( xpath, &block ) end # Synonym for Element.to_a # This is a little slower than calling elements.each directly. # xpath:: any XPath by which to search for elements in the tree # Returns:: an array of Elements that match the supplied path def get_elements( xpath ) @elements.to_a( xpath ) end # Returns the next sibling that is an element, or nil if there is # no Element sibling after this one # doc = Document.new 'text' # doc.root.elements['b'].next_element #-> # doc.root.elements['c'].next_element #-> nil def next_element element = next_sibling element = element.next_sibling until element.nil? or element.kind_of? Element return element end # Returns the previous sibling that is an element, or nil if there is # no Element sibling prior to this one # doc = Document.new 'text' # doc.root.elements['c'].previous_element #-> # doc.root.elements['b'].previous_element #-> nil def previous_element element = previous_sibling element = element.previous_sibling until element.nil? or element.kind_of? Element return element end ################################################# # Text # ################################################# # Evaluates to +true+ if this element has at least one Text child def has_text? not text().nil? end # A convenience method which returns the String value of the _first_ # child text element, if one exists, and +nil+ otherwise. # # Note that an element may have multiple Text elements, perhaps # separated by other children. Be aware that this method only returns # the first Text node. # # This method returns the +value+ of the first text child node, which # ignores the +raw+ setting, so always returns normalized text. See # the Text::value documentation. # # doc = Document.new "

      some text this is bold! more text

      " # # The element 'p' has two text elements, "some text " and " more text". # doc.root.text #-> "some text " def text( path = nil ) rv = get_text(path) return rv.value unless rv.nil? nil end # Returns the first child Text node, if any, or +nil+ otherwise. # This method returns the actual +Text+ node, rather than the String content. # doc = Document.new "

      some text this is bold! more text

      " # # The element 'p' has two text elements, "some text " and " more text". # doc.root.get_text.value #-> "some text " def get_text path = nil rv = nil if path element = @elements[ path ] rv = element.get_text unless element.nil? else rv = @children.find { |node| node.kind_of? Text } end return rv end # Sets the first Text child of this object. See text() for a # discussion about Text children. # # If a Text child already exists, the child is replaced by this # content. This means that Text content can be deleted by calling # this method with a nil argument. In this case, the next Text # child becomes the first Text child. In no case is the order of # any siblings disturbed. # text:: # If a String, a new Text child is created and added to # this Element as the first Text child. If Text, the text is set # as the first Child element. If nil, then any existing first Text # child is removed. # Returns:: this Element. # doc = Document.new '' # doc.root.text = 'Sean' #-> 'Sean' # doc.root.text = 'Elliott' #-> 'Elliott' # doc.root.add_element 'c' #-> 'Elliott' # doc.root.text = 'Russell' #-> 'Russell' # doc.root.text = nil #-> '' def text=( text ) if text.kind_of? String text = Text.new( text, whitespace(), nil, raw() ) elsif !text.nil? and !text.kind_of? Text text = Text.new( text.to_s, whitespace(), nil, raw() ) end old_text = get_text if text.nil? old_text.remove unless old_text.nil? else if old_text.nil? self << text else old_text.replace_with( text ) end end return self end # A helper method to add a Text child. Actual Text instances can # be added with regular Parent methods, such as add() and <<() # text:: # if a String, a new Text instance is created and added # to the parent. If Text, the object is added directly. # Returns:: this Element # e = Element.new('a') #-> # e.add_text 'foo' #-> foo # e.add_text Text.new(' bar') #-> foo bar # Note that at the end of this example, the branch has 3 nodes; the 'e' # element and 2 Text node children. def add_text( text ) if text.kind_of? String if @children[-1].kind_of? Text @children[-1] << text return end text = Text.new( text, whitespace(), nil, raw() ) end self << text unless text.nil? return self end def node_type :element end def xpath path_elements = [] cur = self path_elements << __to_xpath_helper( self ) while cur.parent cur = cur.parent path_elements << __to_xpath_helper( cur ) end return path_elements.reverse.join( "/" ) end ################################################# # Attributes # ################################################# def attribute( name, namespace=nil ) prefix = nil prefix = namespaces.index(namespace) if namespace prefix = nil if prefix == 'xmlns' attributes.get_attribute( "#{prefix ? prefix + ':' : ''}#{name}" ) end # Evaluates to +true+ if this element has any attributes set, false # otherwise. def has_attributes? return !@attributes.empty? end # Adds an attribute to this element, overwriting any existing attribute # by the same name. # key:: # can be either an Attribute or a String. If an Attribute, # the attribute is added to the list of Element attributes. If String, # the argument is used as the name of the new attribute, and the value # parameter must be supplied. # value:: # Required if +key+ is a String, and ignored if the first argument is # an Attribute. This is a String, and is used as the value # of the new Attribute. This should be the unnormalized value of the # attribute (without entities). # Returns:: the Attribute added # e = Element.new 'e' # e.add_attribute( 'a', 'b' ) #-> # e.add_attribute( 'x:a', 'c' ) #-> # e.add_attribute Attribute.new('b', 'd') #-> def add_attribute( key, value=nil ) if key.kind_of? Attribute @attributes << key else @attributes[key] = value end end # Add multiple attributes to this element. # hash:: is either a hash, or array of arrays # el.add_attributes( {"name1"=>"value1", "name2"=>"value2"} ) # el.add_attributes( [ ["name1","value1"], ["name2"=>"value2"] ] ) def add_attributes hash if hash.kind_of? Hash hash.each_pair {|key, value| @attributes[key] = value } elsif hash.kind_of? Array hash.each { |value| @attributes[ value[0] ] = value[1] } end end # Removes an attribute # key:: # either an Attribute or a String. In either case, the # attribute is found by matching the attribute name to the argument, # and then removed. If no attribute is found, no action is taken. # Returns:: # the attribute removed, or nil if this Element did not contain # a matching attribute # e = Element.new('E') # e.add_attribute( 'name', 'Sean' ) #-> # r = e.add_attribute( 'sur:name', 'Russell' ) #-> # e.delete_attribute( 'name' ) #-> # e.delete_attribute( r ) #-> def delete_attribute(key) attr = @attributes.get_attribute(key) attr.remove unless attr.nil? end ################################################# # Other Utilities # ################################################# # Get an array of all CData children. # IMMUTABLE def cdatas find_all { |child| child.kind_of? CData }.freeze end # Get an array of all Comment children. # IMMUTABLE def comments find_all { |child| child.kind_of? Comment }.freeze end # Get an array of all Instruction children. # IMMUTABLE def instructions find_all { |child| child.kind_of? Instruction }.freeze end # Get an array of all Text children. # IMMUTABLE def texts find_all { |child| child.kind_of? Text }.freeze end # == DEPRECATED # See REXML::Formatters # # Writes out this element, and recursively, all children. # output:: # output an object which supports '<< string'; this is where the # document will be written. # indent:: # An integer. If -1, no indenting will be used; otherwise, the # indentation will be this number of spaces, and children will be # indented an additional amount. Defaults to -1 # transitive:: # If transitive is true and indent is >= 0, then the output will be # pretty-printed in such a way that the added whitespace does not affect # the parse tree of the document # ie_hack:: # Internet Explorer is the worst piece of crap to have ever been # written, with the possible exception of Windows itself. Since IE is # unable to parse proper XML, we have to provide a hack to generate XML # that IE's limited abilities can handle. This hack inserts a space # before the /> on empty tags. Defaults to false # # out = '' # doc.write( out ) #-> doc is written to the string 'out' # doc.write( $stdout ) #-> doc written to the console def write(writer=$stdout, indent=-1, transitive=false, ie_hack=false) Kernel.warn("#{self.class.name}.write is deprecated. See REXML::Formatters") formatter = if indent > -1 if transitive REXML::Formatters::Transitive.new( indent, ie_hack ) else REXML::Formatters::Pretty.new( indent, ie_hack ) end else REXML::Formatters::Default.new( ie_hack ) end formatter.write( self, output ) end private def __to_xpath_helper node rv = node.expanded_name.clone if node.parent results = node.parent.find_all {|n| n.kind_of?(REXML::Element) and n.expanded_name == node.expanded_name } if results.length > 1 idx = results.index( node ) rv << "[#{idx+1}]" end end rv end # A private helper method def each_with_something( test, max=0, name=nil ) num = 0 child=nil @elements.each( name ){ |child| yield child if test.call(child) and num += 1 return if max>0 and num == max } end end ######################################################################## # ELEMENTS # ######################################################################## # A class which provides filtering of children for Elements, and # XPath search support. You are expected to only encounter this class as # the element.elements object. Therefore, you are # _not_ expected to instantiate this yourself. class Elements include Enumerable # Constructor # parent:: the parent Element def initialize parent @element = parent end # Fetches a child element. Filters only Element children, regardless of # the XPath match. # index:: # the search parameter. This is either an Integer, which # will be used to find the index'th child Element, or an XPath, # which will be used to search for the Element. Because # of the nature of XPath searches, any element in the connected XML # document can be fetched through any other element. The # Integer index is 1-based, not 0-based. This means that the first # child element is at index 1, not 0, and the +n+th element is at index # +n+, not n-1. This is because XPath indexes element children # starting from 1, not 0, and the indexes should be the same. # name:: # optional, and only used in the first argument is an # Integer. In that case, the index'th child Element that has the # supplied name will be returned. Note again that the indexes start at 1. # Returns:: the first matching Element, or nil if no child matched # doc = Document.new '' # doc.root.elements[1] #-> # doc.root.elements['c'] #-> # doc.root.elements[2,'c'] #-> def []( index, name=nil) if index.kind_of? Integer raise "index (#{index}) must be >= 1" if index < 1 name = literalize(name) if name num = 0 child = nil @element.find { |child| child.kind_of? Element and (name.nil? ? true : child.has_name?( name )) and (num += 1) == index } else return XPath::first( @element, index ) #{ |element| # return element if element.kind_of? Element #} #return nil end end # Sets an element, replacing any previous matching element. If no # existing element is found ,the element is added. # index:: Used to find a matching element to replace. See [](). # element:: # The element to replace the existing element with # the previous element # Returns:: nil if no previous element was found. # # doc = Document.new '' # doc.root.elements[10] = Element.new('b') #-> # doc.root.elements[1] #-> # doc.root.elements[1] = Element.new('c') #-> # doc.root.elements['c'] = Element.new('d') #-> def []=( index, element ) previous = self[index] if previous.nil? @element.add element else previous.replace_with element end return previous end # Returns +true+ if there are no +Element+ children, +false+ otherwise def empty? @element.find{ |child| child.kind_of? Element}.nil? end # Returns the index of the supplied child (starting at 1), or -1 if # the element is not a child # element:: an +Element+ child def index element rv = 0 found = @element.find do |child| child.kind_of? Element and (rv += 1) and child == element end return rv if found == element return -1 end # Deletes a child Element # element:: # Either an Element, which is removed directly; an # xpath, where the first matching child is removed; or an Integer, # where the n'th Element is removed. # Returns:: the removed child # doc = Document.new '' # b = doc.root.elements[1] # doc.root.elements.delete b #-> # doc.elements.delete("a/c[@id='1']") #-> # doc.root.elements.delete 1 #-> def delete element if element.kind_of? Element @element.delete element else el = self[element] el.remove if el end end # Removes multiple elements. Filters for Element children, regardless of # XPath matching. # xpath:: all elements matching this String path are removed. # Returns:: an Array of Elements that have been removed # doc = Document.new '' # deleted = doc.elements.delete_all 'a/c' #-> [, , , ] def delete_all( xpath ) rv = [] XPath::each( @element, xpath) {|element| rv << element if element.kind_of? Element } rv.each do |element| @element.delete element element.remove end return rv end # Adds an element # element:: # if supplied, is either an Element, String, or # Source (see Element.initialize). If not supplied or nil, a # new, default Element will be constructed # Returns:: the added Element # a = Element.new('a') # a.elements.add(Element.new('b')) #-> # a.elements.add('c') #-> def add element=nil rv = nil if element.nil? Element.new("", self, @element.context) elsif not element.kind_of?(Element) Element.new(element, self, @element.context) else @element << element element.context = @element.context element end end alias :<< :add # Iterates through all of the child Elements, optionally filtering # them by a given XPath # xpath:: # optional. If supplied, this is a String XPath, and is used to # filter the children, so that only matching children are yielded. Note # that XPaths are automatically filtered for Elements, so that # non-Element children will not be yielded # doc = Document.new 'sean' # doc.root.each {|e|p e} #-> Yields b, c, d, b, c, d elements # doc.root.each('b') {|e|p e} #-> Yields b, b elements # doc.root.each('child::node()') {|e|p e} # #-> Yields , , , , , # XPath.each(doc.root, 'child::node()', &block) # #-> Yields , , , sean, , , def each( xpath=nil, &block) XPath::each( @element, xpath ) {|e| yield e if e.kind_of? Element } end def collect( xpath=nil, &block ) collection = [] XPath::each( @element, xpath ) {|e| collection << yield(e) if e.kind_of?(Element) } collection end def inject( xpath=nil, initial=nil, &block ) first = true XPath::each( @element, xpath ) {|e| if (e.kind_of? Element) if (first and initial == nil) initial = e first = false else initial = yield( initial, e ) if e.kind_of? Element end end } initial end # Returns the number of +Element+ children of the parent object. # doc = Document.new 'seanelliottrussell' # doc.root.size #-> 6, 3 element and 3 text nodes # doc.root.elements.size #-> 3 def size count = 0 @element.each {|child| count+=1 if child.kind_of? Element } count end # Returns an Array of Element children. An XPath may be supplied to # filter the children. Only Element children are returned, even if the # supplied XPath matches non-Element children. # doc = Document.new 'seanelliott' # doc.root.elements.to_a #-> [ , ] # doc.root.elements.to_a("child::node()") #-> [ , ] # XPath.match(doc.root, "child::node()") #-> [ sean, , elliott, ] def to_a( xpath=nil ) rv = XPath.match( @element, xpath ) return rv.find_all{|e| e.kind_of? Element} if xpath rv end private # Private helper class. Removes quotes from quoted strings def literalize name name = name[1..-2] if name[0] == ?' or name[0] == ?" #' name end end ######################################################################## # ATTRIBUTES # ######################################################################## # A class that defines the set of Attributes of an Element and provides # operations for accessing elements in that set. class Attributes < Hash # Constructor # element:: the Element of which this is an Attribute def initialize element @element = element end # Fetches an attribute value. If you want to get the Attribute itself, # use get_attribute() # name:: an XPath attribute name. Namespaces are relevant here. # Returns:: # the String value of the matching attribute, or +nil+ if no # matching attribute was found. This is the unnormalized value # (with entities expanded). # # doc = Document.new "" # doc.root.attributes['att'] #-> '<' # doc.root.attributes['bar:att'] #-> '2' def [](name) attr = get_attribute(name) return attr.value unless attr.nil? return nil end def to_a values.flatten end # Returns the number of attributes the owning Element contains. # doc = Document "" # doc.root.attributes.length #-> 3 def length c = 0 each_attribute { c+=1 } c end alias :size :length # Iterates over the attributes of an Element. Yields actual Attribute # nodes, not String values. # # doc = Document.new '' # doc.root.attributes.each_attribute {|attr| # p attr.expanded_name+" => "+attr.value # } def each_attribute # :yields: attribute each_value do |val| if val.kind_of? Attribute yield val else val.each_value { |atr| yield atr } end end end # Iterates over each attribute of an Element, yielding the expanded name # and value as a pair of Strings. # # doc = Document.new '' # doc.root.attributes.each {|name, value| p name+" => "+value } def each each_attribute do |attr| yield attr.expanded_name, attr.value end end # Fetches an attribute # name:: # the name by which to search for the attribute. Can be a # prefix:name namespace name. # Returns:: The first matching attribute, or nil if there was none. This # value is an Attribute node, not the String value of the attribute. # doc = Document.new '' # doc.root.attributes.get_attribute("foo").value #-> "2" # doc.root.attributes.get_attribute("x:foo").value #-> "1" def get_attribute( name ) attr = fetch( name, nil ) if attr.nil? return nil if name.nil? # Look for prefix name =~ Namespace::NAMESPLIT prefix, n = $1, $2 if prefix attr = fetch( n, nil ) # check prefix if attr == nil elsif attr.kind_of? Attribute return attr if prefix == attr.prefix else attr = attr[ prefix ] return attr end end element_document = @element.document if element_document and element_document.doctype expn = @element.expanded_name expn = element_document.doctype.name if expn.size == 0 attr_val = element_document.doctype.attribute_of(expn, name) return Attribute.new( name, attr_val ) if attr_val end return nil end if attr.kind_of? Hash attr = attr[ @element.prefix ] end return attr end # Sets an attribute, overwriting any existing attribute value by the # same name. Namespace is significant. # name:: the name of the attribute # value:: # (optional) If supplied, the value of the attribute. If # nil, any existing matching attribute is deleted. # Returns:: # Owning element # doc = Document.new "" # doc.root.attributes['y:foo'] = '2' # doc.root.attributes['foo'] = '4' # doc.root.attributes['x:foo'] = nil def []=( name, value ) if value.nil? # Delete the named attribute attr = get_attribute(name) delete attr return end element_document = @element.document unless value.kind_of? Attribute if @element.document and @element.document.doctype value = Text::normalize( value, @element.document.doctype ) else value = Text::normalize( value, nil ) end value = Attribute.new(name, value) end value.element = @element old_attr = fetch(value.name, nil) if old_attr.nil? store(value.name, value) elsif old_attr.kind_of? Hash old_attr[value.prefix] = value elsif old_attr.prefix != value.prefix # Check for conflicting namespaces raise ParseException.new( "Namespace conflict in adding attribute \"#{value.name}\": "+ "Prefix \"#{old_attr.prefix}\" = "+ "\"#{@element.namespace(old_attr.prefix)}\" and prefix "+ "\"#{value.prefix}\" = \"#{@element.namespace(value.prefix)}\"") if value.prefix != "xmlns" and old_attr.prefix != "xmlns" and @element.namespace( old_attr.prefix ) == @element.namespace( value.prefix ) store value.name, { old_attr.prefix => old_attr, value.prefix => value } else store value.name, value end return @element end # Returns an array of Strings containing all of the prefixes declared # by this set of # attributes. The array does not include the default # namespace declaration, if one exists. # doc = Document.new("") # prefixes = doc.root.attributes.prefixes #-> ['x', 'y'] def prefixes ns = [] each_attribute do |attribute| ns << attribute.name if attribute.prefix == 'xmlns' end if @element.document and @element.document.doctype expn = @element.expanded_name expn = @element.document.doctype.name if expn.size == 0 @element.document.doctype.attributes_of(expn).each { |attribute| ns << attribute.name if attribute.prefix == 'xmlns' } end ns end def namespaces namespaces = {} each_attribute do |attribute| namespaces[attribute.name] = attribute.value if attribute.prefix == 'xmlns' or attribute.name == 'xmlns' end if @element.document and @element.document.doctype expn = @element.expanded_name expn = @element.document.doctype.name if expn.size == 0 @element.document.doctype.attributes_of(expn).each { |attribute| namespaces[attribute.name] = attribute.value if attribute.prefix == 'xmlns' or attribute.name == 'xmlns' } end namespaces end # Removes an attribute # attribute:: # either a String, which is the name of the attribute to remove -- # namespaces are significant here -- or the attribute to remove. # Returns:: the owning element # doc = Document.new "" # doc.root.attributes.delete 'foo' #-> " # doc.root.attributes.delete 'x:foo' #-> " # attr = doc.root.attributes.get_attribute('y:foo') # doc.root.attributes.delete attr #-> " def delete( attribute ) name = nil prefix = nil if attribute.kind_of? Attribute name = attribute.name prefix = attribute.prefix else attribute =~ Namespace::NAMESPLIT prefix, name = $1, $2 prefix = '' unless prefix end old = fetch(name, nil) attr = nil if old.kind_of? Hash # the supplied attribute is one of many attr = old.delete(prefix) if old.size == 1 repl = nil old.each_value{|v| repl = v} store name, repl end elsif old.nil? return @element else # the supplied attribute is a top-level one attr = old res = super(name) end @element end # Adds an attribute, overriding any existing attribute by the # same name. Namespaces are significant. # attribute:: An Attribute def add( attribute ) self[attribute.name] = attribute end alias :<< :add # Deletes all attributes matching a name. Namespaces are significant. # name:: # A String; all attributes that match this path will be removed # Returns:: an Array of the Attributes that were removed def delete_all( name ) rv = [] each_attribute { |attribute| rv << attribute if attribute.expanded_name == name } rv.each{ |attr| attr.remove } return rv end # The +get_attribute_ns+ method retrieves a method by its namespace # and name. Thus it is possible to reliably identify an attribute # even if an XML processor has changed the prefix. # # Method contributed by Henrik Martensson def get_attribute_ns(namespace, name) each_attribute() { |attribute| if name == attribute.name && namespace == attribute.namespace() return attribute end } nil end end end ================================================ FILE: lib/rexml/encoding.rb ================================================ # -*- mode: ruby; ruby-indent-level: 2; indent-tabs-mode: t; tab-width: 2 -*- vim: sw=2 ts=2 module REXML module Encoding @encoding_methods = {} def self.register(enc, &block) @encoding_methods[enc] = block end def self.apply(obj, enc) @encoding_methods[enc][obj] end def self.encoding_method(enc) @encoding_methods[enc] end # Native, default format is UTF-8, so it is declared here rather than in # an encodings/ definition. UTF_8 = 'UTF-8' UTF_16 = 'UTF-16' UNILE = 'UNILE' # ID ---> Encoding name attr_reader :encoding def encoding=( enc ) old_verbosity = $VERBOSE begin $VERBOSE = false enc = enc.nil? ? nil : enc.upcase return false if defined? @encoding and enc == @encoding if enc and enc != UTF_8 @encoding = enc raise ArgumentError, "Bad encoding name #@encoding" unless @encoding =~ /^[\w-]+$/ @encoding.untaint begin require 'rexml/encodings/ICONV.rb' Encoding.apply(self, "ICONV") rescue LoadError, Exception begin enc_file = File.join( "rexml", "encodings", "#@encoding.rb" ) require enc_file Encoding.apply(self, @encoding) rescue LoadError => err puts err.message raise ArgumentError, "No decoder found for encoding #@encoding. Please install iconv." end end else @encoding = UTF_8 require 'rexml/encodings/UTF-8.rb' Encoding.apply(self, @encoding) end ensure $VERBOSE = old_verbosity end true end def check_encoding str # We have to recognize UTF-16, LSB UTF-16, and UTF-8 if str[0] == 0xfe && str[1] == 0xff str[0,2] = "" return UTF_16 elsif str[0] == 0xff && str[1] == 0xfe str[0,2] = "" return UNILE end str =~ /^\s*<\?xml\s+version\s*=\s*(['"]).*?\1\s+encoding\s*=\s*(["'])(.*?)\2/um return $3.upcase if $3 return UTF_8 end end end ================================================ FILE: lib/rexml/encodings/CP-1252.rb ================================================ # # This class was contributed by Mikko Tiihonen mikko DOT tiihonen AT hut DOT fi # module REXML module Encoding register( "CP-1252" ) do |o| class << o alias encode encode_cp1252 alias decode decode_cp1252 end end # Convert from UTF-8 def encode_cp1252(content) array_utf8 = content.unpack('U*') array_enc = [] array_utf8.each do |num| case num # shortcut first bunch basic characters when 0..0xFF; array_enc << num # characters added compared to iso-8859-1 when 0x20AC; array_enc << 0x80 # 0xe2 0x82 0xac when 0x201A; array_enc << 0x82 # 0xe2 0x82 0x9a when 0x0192; array_enc << 0x83 # 0xc6 0x92 when 0x201E; array_enc << 0x84 # 0xe2 0x82 0x9e when 0x2026; array_enc << 0x85 # 0xe2 0x80 0xa6 when 0x2020; array_enc << 0x86 # 0xe2 0x80 0xa0 when 0x2021; array_enc << 0x87 # 0xe2 0x80 0xa1 when 0x02C6; array_enc << 0x88 # 0xcb 0x86 when 0x2030; array_enc << 0x89 # 0xe2 0x80 0xb0 when 0x0160; array_enc << 0x8A # 0xc5 0xa0 when 0x2039; array_enc << 0x8B # 0xe2 0x80 0xb9 when 0x0152; array_enc << 0x8C # 0xc5 0x92 when 0x017D; array_enc << 0x8E # 0xc5 0xbd when 0x2018; array_enc << 0x91 # 0xe2 0x80 0x98 when 0x2019; array_enc << 0x92 # 0xe2 0x80 0x99 when 0x201C; array_enc << 0x93 # 0xe2 0x80 0x9c when 0x201D; array_enc << 0x94 # 0xe2 0x80 0x9d when 0x2022; array_enc << 0x95 # 0xe2 0x80 0xa2 when 0x2013; array_enc << 0x96 # 0xe2 0x80 0x93 when 0x2014; array_enc << 0x97 # 0xe2 0x80 0x94 when 0x02DC; array_enc << 0x98 # 0xcb 0x9c when 0x2122; array_enc << 0x99 # 0xe2 0x84 0xa2 when 0x0161; array_enc << 0x9A # 0xc5 0xa1 when 0x203A; array_enc << 0x9B # 0xe2 0x80 0xba when 0x0152; array_enc << 0x9C # 0xc5 0x93 when 0x017E; array_enc << 0x9E # 0xc5 0xbe when 0x0178; array_enc << 0x9F # 0xc5 0xb8 else # all remaining basic characters can be used directly if num <= 0xFF array_enc << num else # Numeric entity (&#nnnn;); shard by Stefan Scholl array_enc.concat "&\##{num};".unpack('C*') end end end array_enc.pack('C*') end # Convert to UTF-8 def decode_cp1252(str) array_latin9 = str.unpack('C*') array_enc = [] array_latin9.each do |num| case num # characters that added compared to iso-8859-1 when 0x80; array_enc << 0x20AC # 0xe2 0x82 0xac when 0x82; array_enc << 0x201A # 0xe2 0x82 0x9a when 0x83; array_enc << 0x0192 # 0xc6 0x92 when 0x84; array_enc << 0x201E # 0xe2 0x82 0x9e when 0x85; array_enc << 0x2026 # 0xe2 0x80 0xa6 when 0x86; array_enc << 0x2020 # 0xe2 0x80 0xa0 when 0x87; array_enc << 0x2021 # 0xe2 0x80 0xa1 when 0x88; array_enc << 0x02C6 # 0xcb 0x86 when 0x89; array_enc << 0x2030 # 0xe2 0x80 0xb0 when 0x8A; array_enc << 0x0160 # 0xc5 0xa0 when 0x8B; array_enc << 0x2039 # 0xe2 0x80 0xb9 when 0x8C; array_enc << 0x0152 # 0xc5 0x92 when 0x8E; array_enc << 0x017D # 0xc5 0xbd when 0x91; array_enc << 0x2018 # 0xe2 0x80 0x98 when 0x92; array_enc << 0x2019 # 0xe2 0x80 0x99 when 0x93; array_enc << 0x201C # 0xe2 0x80 0x9c when 0x94; array_enc << 0x201D # 0xe2 0x80 0x9d when 0x95; array_enc << 0x2022 # 0xe2 0x80 0xa2 when 0x96; array_enc << 0x2013 # 0xe2 0x80 0x93 when 0x97; array_enc << 0x2014 # 0xe2 0x80 0x94 when 0x98; array_enc << 0x02DC # 0xcb 0x9c when 0x99; array_enc << 0x2122 # 0xe2 0x84 0xa2 when 0x9A; array_enc << 0x0161 # 0xc5 0xa1 when 0x9B; array_enc << 0x203A # 0xe2 0x80 0xba when 0x9C; array_enc << 0x0152 # 0xc5 0x93 when 0x9E; array_enc << 0x017E # 0xc5 0xbe when 0x9F; array_enc << 0x0178 # 0xc5 0xb8 else array_enc << num end end array_enc.pack('U*') end end end ================================================ FILE: lib/rexml/encodings/EUC-JP.rb ================================================ module REXML module Encoding begin require 'uconv' def decode_eucjp(str) Uconv::euctou8(str) end def encode_eucjp content Uconv::u8toeuc(content) end rescue LoadError require 'nkf' EUCTOU8 = '-Ewm0' U8TOEUC = '-Wem0' def decode_eucjp(str) NKF.nkf(EUCTOU8, str) end def encode_eucjp content NKF.nkf(U8TOEUC, content) end end register("EUC-JP") do |obj| class << obj alias decode decode_eucjp alias encode encode_eucjp end end end end ================================================ FILE: lib/rexml/encodings/ICONV.rb ================================================ require "iconv" raise LoadError unless defined? Iconv module REXML module Encoding def decode_iconv(str) Iconv.conv(UTF_8, @encoding, str) end def encode_iconv(content) Iconv.conv(@encoding, UTF_8, content) end register("ICONV") do |obj| Iconv.conv(UTF_8, obj.encoding, nil) class << obj alias decode decode_iconv alias encode encode_iconv end end end end ================================================ FILE: lib/rexml/encodings/ISO-8859-1.rb ================================================ require 'rexml/encodings/US-ASCII' module REXML module Encoding register("ISO-8859-1", &encoding_method("US-ASCII")) end end ================================================ FILE: lib/rexml/encodings/ISO-8859-15.rb ================================================ # # This class was contributed by Mikko Tiihonen mikko DOT tiihonen AT hut DOT fi # module REXML module Encoding register("ISO-8859-15") do |o| alias encode to_iso_8859_15 alias decode from_iso_8859_15 end # Convert from UTF-8 def to_iso_8859_15(content) array_utf8 = content.unpack('U*') array_enc = [] array_utf8.each do |num| case num # shortcut first bunch basic characters when 0..0xA3; array_enc << num # characters removed compared to iso-8859-1 when 0xA4; array_enc << '¤' when 0xA6; array_enc << '¦' when 0xA8; array_enc << '¨' when 0xB4; array_enc << '´' when 0xB8; array_enc << '¸' when 0xBC; array_enc << '¼' when 0xBD; array_enc << '½' when 0xBE; array_enc << '¾' # characters added compared to iso-8859-1 when 0x20AC; array_enc << 0xA4 # 0xe2 0x82 0xac when 0x0160; array_enc << 0xA6 # 0xc5 0xa0 when 0x0161; array_enc << 0xA8 # 0xc5 0xa1 when 0x017D; array_enc << 0xB4 # 0xc5 0xbd when 0x017E; array_enc << 0xB8 # 0xc5 0xbe when 0x0152; array_enc << 0xBC # 0xc5 0x92 when 0x0153; array_enc << 0xBD # 0xc5 0x93 when 0x0178; array_enc << 0xBE # 0xc5 0xb8 else # all remaining basic characters can be used directly if num <= 0xFF array_enc << num else # Numeric entity (&#nnnn;); shard by Stefan Scholl array_enc.concat "&\##{num};".unpack('C*') end end end array_enc.pack('C*') end # Convert to UTF-8 def from_iso_8859_15(str) array_latin9 = str.unpack('C*') array_enc = [] array_latin9.each do |num| case num # characters that differ compared to iso-8859-1 when 0xA4; array_enc << 0x20AC when 0xA6; array_enc << 0x0160 when 0xA8; array_enc << 0x0161 when 0xB4; array_enc << 0x017D when 0xB8; array_enc << 0x017E when 0xBC; array_enc << 0x0152 when 0xBD; array_enc << 0x0153 when 0xBE; array_enc << 0x0178 else array_enc << num end end array_enc.pack('U*') end end end ================================================ FILE: lib/rexml/encodings/SHIFT-JIS.rb ================================================ module REXML module Encoding begin require 'uconv' def decode_sjis content Uconv::sjistou8(content) end def encode_sjis(str) Uconv::u8tosjis(str) end rescue LoadError require 'nkf' SJISTOU8 = '-Swm0x' U8TOSJIS = '-Wsm0x' def decode_sjis(str) NKF.nkf(SJISTOU8, str) end def encode_sjis content NKF.nkf(U8TOSJIS, content) end end b = proc do |obj| class << obj alias decode decode_sjis alias encode encode_sjis end end register("SHIFT-JIS", &b) register("SHIFT_JIS", &b) end end ================================================ FILE: lib/rexml/encodings/SHIFT_JIS.rb ================================================ require 'rexml/encodings/SHIFT-JIS' ================================================ FILE: lib/rexml/encodings/UNILE.rb ================================================ module REXML module Encoding def encode_unile content array_utf8 = content.unpack("U*") array_enc = [] array_utf8.each do |num| if ((num>>16) > 0) array_enc << ?? array_enc << 0 else array_enc << (num & 0xFF) array_enc << (num >> 8) end end array_enc.pack('C*') end def decode_unile(str) array_enc=str.unpack('C*') array_utf8 = [] 0.step(array_enc.size-1, 2){|i| array_utf8 << (array_enc.at(i) + array_enc.at(i+1)*0x100) } array_utf8.pack('U*') end register(UNILE) do |obj| class << obj alias decode decode_unile alias encode encode_unile end end end end ================================================ FILE: lib/rexml/encodings/US-ASCII.rb ================================================ module REXML module Encoding # Convert from UTF-8 def encode_ascii content array_utf8 = content.unpack('U*') array_enc = [] array_utf8.each do |num| if num <= 0x7F array_enc << num else # Numeric entity (&#nnnn;); shard by Stefan Scholl array_enc.concat "&\##{num};".unpack('C*') end end array_enc.pack('C*') end # Convert to UTF-8 def decode_ascii(str) str.unpack('C*').pack('U*') end register("US-ASCII") do |obj| class << obj alias decode decode_ascii alias encode encode_ascii end end end end ================================================ FILE: lib/rexml/encodings/UTF-16.rb ================================================ module REXML module Encoding def encode_utf16 content array_utf8 = content.unpack("U*") array_enc = [] array_utf8.each do |num| if ((num>>16) > 0) array_enc << 0 array_enc << ?? else array_enc << (num >> 8) array_enc << (num & 0xFF) end end array_enc.pack('C*') end def decode_utf16(str) str = str[2..-1] if /^\376\377/n =~ str array_enc=str.unpack('C*') array_utf8 = [] 0.step(array_enc.size-1, 2){|i| array_utf8 << (array_enc.at(i+1) + array_enc.at(i)*0x100) } array_utf8.pack('U*') end register(UTF_16) do |obj| class << obj alias decode decode_utf16 alias encode encode_utf16 end end end end ================================================ FILE: lib/rexml/encodings/UTF-8.rb ================================================ module REXML module Encoding def encode_utf8 content content end def decode_utf8(str) str end register(UTF_8) do |obj| class << obj alias decode decode_utf8 alias encode encode_utf8 end end end end ================================================ FILE: lib/rexml/entity.rb ================================================ require 'rexml/child' require 'rexml/source' require 'rexml/xmltokens' module REXML # God, I hate DTDs. I really do. Why this idiot standard still # plagues us is beyond me. class Entity < Child include XMLTokens PUBIDCHAR = "\x20\x0D\x0Aa-zA-Z0-9\\-()+,./:=?;!*@$_%#" SYSTEMLITERAL = %Q{((?:"[^"]*")|(?:'[^']*'))} PUBIDLITERAL = %Q{("[#{PUBIDCHAR}']*"|'[#{PUBIDCHAR}]*')} EXTERNALID = "(?:(?:(SYSTEM)\\s+#{SYSTEMLITERAL})|(?:(PUBLIC)\\s+#{PUBIDLITERAL}\\s+#{SYSTEMLITERAL}))" NDATADECL = "\\s+NDATA\\s+#{NAME}" PEREFERENCE = "%#{NAME};" ENTITYVALUE = %Q{((?:"(?:[^%&"]|#{PEREFERENCE}|#{REFERENCE})*")|(?:'([^%&']|#{PEREFERENCE}|#{REFERENCE})*'))} PEDEF = "(?:#{ENTITYVALUE}|#{EXTERNALID})" ENTITYDEF = "(?:#{ENTITYVALUE}|(?:#{EXTERNALID}(#{NDATADECL})?))" PEDECL = "" GEDECL = "" ENTITYDECL = /\s*(?:#{GEDECL})|(?:#{PEDECL})/um attr_reader :name, :external, :ref, :ndata, :pubid # Create a new entity. Simple entities can be constructed by passing a # name, value to the constructor; this creates a generic, plain entity # reference. For anything more complicated, you have to pass a Source to # the constructor with the entity definiton, or use the accessor methods. # +WARNING+: There is no validation of entity state except when the entity # is read from a stream. If you start poking around with the accessors, # you can easily create a non-conformant Entity. The best thing to do is # dump the stupid DTDs and use XMLSchema instead. # # e = Entity.new( 'amp', '&' ) def initialize stream, value=nil, parent=nil, reference=false super(parent) @ndata = @pubid = @value = @external = nil if stream.kind_of? Array @name = stream[1] if stream[-1] == '%' @reference = true stream.pop else @reference = false end if stream[2] =~ /SYSTEM|PUBLIC/ @external = stream[2] if @external == 'SYSTEM' @ref = stream[3] @ndata = stream[4] if stream.size == 5 else @pubid = stream[3] @ref = stream[4] end else @value = stream[2] end else @reference = reference @external = nil @name = stream @value = value end end # Evaluates whether the given string matchs an entity definition, # returning true if so, and false otherwise. def Entity::matches? string (ENTITYDECL =~ string) == 0 end # Evaluates to the unnormalized value of this entity; that is, replacing # all entities -- both %ent; and &ent; entities. This differs from # +value()+ in that +value+ only replaces %ent; entities. def unnormalized document.record_entity_expansion unless document.nil? v = value() return nil if v.nil? @unnormalized = Text::unnormalize(v, parent) @unnormalized end #once :unnormalized # Returns the value of this entity unprocessed -- raw. This is the # normalized value; that is, with all %ent; and &ent; entities intact def normalized @value end # Write out a fully formed, correct entity definition (assuming the Entity # object itself is valid.) # # out:: # An object implementing << to which the entity will be # output # indent:: # *DEPRECATED* and ignored def write out, indent=-1 out << '' end # Returns this entity as a string. See write(). def to_s rv = '' write rv rv end PEREFERENCE_RE = /#{PEREFERENCE}/um # Returns the value of this entity. At the moment, only internal entities # are processed. If the value contains internal references (IE, # %blah;), those are replaced with their values. IE, if the doctype # contains: # # # then: # doctype.entity('yada').value #-> "nanoo bar nanoo" def value if @value matches = @value.scan(PEREFERENCE_RE) rv = @value.clone if @parent matches.each do |entity_reference| entity_value = @parent.entity( entity_reference[0] ) rv.gsub!( /%#{entity_reference};/um, entity_value ) end end return rv end nil end end # This is a set of entity constants -- the ones defined in the XML # specification. These are +gt+, +lt+, +amp+, +quot+ and +apos+. module EntityConst # +>+ GT = Entity.new( 'gt', '>' ) # +<+ LT = Entity.new( 'lt', '<' ) # +&+ AMP = Entity.new( 'amp', '&' ) # +"+ QUOT = Entity.new( 'quot', '"' ) # +'+ APOS = Entity.new( 'apos', "'" ) end end ================================================ FILE: lib/rexml/formatters/default.rb ================================================ module REXML module Formatters class Default # Prints out the XML document with no formatting -- except if id_hack is # set. # # ie_hack:: # If set to true, then inserts whitespace before the close of an empty # tag, so that IE's bad XML parser doesn't choke. def initialize( ie_hack=false ) @ie_hack = ie_hack end # Writes the node to some output. # # node:: # The node to write # output:: # A class implementing <<. Pass in an Output object to # change the output encoding. def write( node, output ) case node when Document if node.xml_decl.encoding != "UTF-8" && !output.kind_of?(Output) output = Output.new( output, node.xml_decl.encoding ) end write_document( node, output ) when Element write_element( node, output ) when Declaration, ElementDecl, NotationDecl, ExternalEntity, Entity, Attribute, AttlistDecl node.write( output,-1 ) when Instruction write_instruction( node, output ) when DocType, XMLDecl node.write( output ) when Comment write_comment( node, output ) when CData write_cdata( node, output ) when Text write_text( node, output ) else raise Exception.new("XML FORMATTING ERROR") end end protected def write_document( node, output ) node.children.each { |child| write( child, output ) } end def write_element( node, output ) output << "<#{node.expanded_name}" node.attributes.each_attribute do |attr| output << " " attr.write( output ) end unless node.attributes.empty? if node.children.empty? output << " " if @ie_hack output << "/" else output << ">" node.children.each { |child| write( child, output ) } output << "" end def write_text( node, output ) output << node.to_s() end def write_comment( node, output ) output << Comment::START output << node.to_s output << Comment::STOP end def write_cdata( node, output ) output << CData::START output << node.to_s output << CData::STOP end def write_instruction( node, output ) output << Instruction::START.sub(/\\/u, '') output << node.target output << ' ' output << node.content output << Instruction::STOP.sub(/\\/u, '') end end end end ================================================ FILE: lib/rexml/formatters/pretty.rb ================================================ require 'rexml/formatters/default' module REXML module Formatters # Pretty-prints an XML document. This destroys whitespace in text nodes # and will insert carriage returns and indentations. # # TODO: Add an option to print attributes on new lines class Pretty < Default # If compact is set to true, then the formatter will attempt to use as # little space as possible attr_accessor :compact # The width of a page. Used for formatting text attr_accessor :width # Create a new pretty printer. # # output:: # An object implementing '<<(String)', to which the output will be written. # indentation:: # An integer greater than 0. The indentation of each level will be # this number of spaces. If this is < 1, the behavior of this object # is undefined. Defaults to 2. # ie_hack:: # If true, the printer will insert whitespace before closing empty # tags, thereby allowing Internet Explorer's feeble XML parser to # function. Defaults to false. def initialize( indentation=2, ie_hack=false ) @indentation = indentation @level = 0 @ie_hack = ie_hack @width = 80 end protected def write_element(node, output) output << ' '*@level output << "<#{node.expanded_name}" node.attributes.each_attribute do |attr| output << " " attr.write( output ) end unless node.attributes.empty? if node.children.empty? if @ie_hack output << " " end output << "/" else output << ">" # If compact and all children are text, and if the formatted output # is less than the specified width, then try to print everything on # one line skip = false if compact if node.children.inject(true) {|s,c| s & c.kind_of?(Text)} string = "" old_level = @level @level = 0 node.children.each { |child| write( child, string ) } @level = old_level if string.length < @width output << string skip = true end end end unless skip output << "\n" @level += @indentation node.children.each { |child| next if child.kind_of?(Text) and child.to_s.strip.length == 0 write( child, output ) output << "\n" } @level -= @indentation output << ' '*@level end output << "" end def write_text( node, output ) s = node.to_s() s.gsub!(/\s/,' ') s.squeeze!(" ") s = wrap(s, 80-@level) s = indent_text(s, @level, " ", true) output << (' '*@level + s) end def write_comment( node, output) output << ' ' * @level super end def write_cdata( node, output) output << ' ' * @level super end def write_document( node, output ) # Ok, this is a bit odd. All XML documents have an XML declaration, # but it may not write itself if the user didn't specifically add it, # either through the API or in the input document. If it doesn't write # itself, then we don't need a carriage return... which makes this # logic more complex. node.children.each { |child| next if child == node.children[-1] and child.instance_of?(Text) unless child == node.children[0] or child.instance_of?(Text) or (child == node.children[1] and !node.children[0].writethis) output << "\n" end write( child, output ) } end private def indent_text(string, level=1, style="\t", indentfirstline=true) return string if level < 0 string.gsub(/\n/, "\n#{style*level}") end def wrap(string, width) # Recursively wrap string at width. return string if string.length <= width place = string.rindex(' ', width) # Position in string with last ' ' before cutoff return string if place.nil? return string[0,place] + "\n" + wrap(string[place+1..-1], width) end end end end ================================================ FILE: lib/rexml/formatters/transitive.rb ================================================ require 'rexml/formatters/pretty' module REXML module Formatters # The Transitive formatter writes an XML document that parses to an # identical document as the source document. This means that no extra # whitespace nodes are inserted, and whitespace within text nodes is # preserved. Within these constraints, the document is pretty-printed, # with whitespace inserted into the metadata to introduce formatting. # # Note that this is only useful if the original XML is not already # formatted. Since this formatter does not alter whitespace nodes, the # results of formatting already formatted XML will be odd. class Transitive < Default def initialize( indentation=2 ) @indentation = indentation @level = 0 end protected def write_element( node, output ) output << "<#{node.expanded_name}" node.attributes.each_attribute do |attr| output << " " attr.write( output ) end unless node.attributes.empty? output << "\n" output << ' '*@level if node.children.empty? output << "/" else output << ">" # If compact and all children are text, and if the formatted output # is less than the specified width, then try to print everything on # one line skip = false @level += @indentation node.children.each { |child| write( child, output ) } @level -= @indentation output << "" end def write_text( node, output ) output << node.to_s() end end end end ================================================ FILE: lib/rexml/functions.rb ================================================ module REXML # If you add a method, keep in mind two things: # (1) the first argument will always be a list of nodes from which to # filter. In the case of context methods (such as position), the function # should return an array with a value for each child in the array. # (2) all method calls from XML will have "-" replaced with "_". # Therefore, in XML, "local-name()" is identical (and actually becomes) # "local_name()" module Functions @@context = nil @@namespace_context = {} @@variables = {} def Functions::namespace_context=(x) ; @@namespace_context=x ; end def Functions::variables=(x) ; @@variables=x ; end def Functions::namespace_context ; @@namespace_context ; end def Functions::variables ; @@variables ; end def Functions::context=(value); @@context = value; end def Functions::text( ) if @@context[:node].node_type == :element return @@context[:node].find_all{|n| n.node_type == :text}.collect{|n| n.value} elsif @@context[:node].node_type == :text return @@context[:node].value else return false end end def Functions::last( ) @@context[:size] end def Functions::position( ) @@context[:index] end def Functions::count( node_set ) node_set.size end # Since REXML is non-validating, this method is not implemented as it # requires a DTD def Functions::id( object ) end # UNTESTED def Functions::local_name( node_set=nil ) get_namespace( node_set ) do |node| return node.local_name end end def Functions::namespace_uri( node_set=nil ) get_namespace( node_set ) {|node| node.namespace} end def Functions::name( node_set=nil ) get_namespace( node_set ) do |node| node.expanded_name end end # Helper method. def Functions::get_namespace( node_set = nil ) if node_set == nil yield @@context[:node] if defined? @@context[:node].namespace else if node_set.respond_to? :each node_set.each { |node| yield node if defined? node.namespace } elsif node_set.respond_to? :namespace yield node_set end end end # A node-set is converted to a string by returning the string-value of the # node in the node-set that is first in document order. If the node-set is # empty, an empty string is returned. # # A number is converted to a string as follows # # NaN is converted to the string NaN # # positive zero is converted to the string 0 # # negative zero is converted to the string 0 # # positive infinity is converted to the string Infinity # # negative infinity is converted to the string -Infinity # # if the number is an integer, the number is represented in decimal form # as a Number with no decimal point and no leading zeros, preceded by a # minus sign (-) if the number is negative # # otherwise, the number is represented in decimal form as a Number # including a decimal point with at least one digit before the decimal # point and at least one digit after the decimal point, preceded by a # minus sign (-) if the number is negative; there must be no leading zeros # before the decimal point apart possibly from the one required digit # immediately before the decimal point; beyond the one required digit # after the decimal point there must be as many, but only as many, more # digits as are needed to uniquely distinguish the number from all other # IEEE 754 numeric values. # # The boolean false value is converted to the string false. The boolean # true value is converted to the string true. # # An object of a type other than the four basic types is converted to a # string in a way that is dependent on that type. def Functions::string( object=nil ) #object = @context unless object if object.instance_of? Array string( object[0] ) elsif defined? object.node_type if object.node_type == :attribute object.value elsif object.node_type == :element || object.node_type == :document string_value(object) else object.to_s end elsif object.nil? return "" else object.to_s end end def Functions::string_value( o ) rv = "" o.children.each { |e| if e.node_type == :text rv << e.to_s elsif e.node_type == :element rv << string_value( e ) end } rv end # UNTESTED def Functions::concat( *objects ) objects.join end # Fixed by Mike Stok def Functions::starts_with( string, test ) string(string).index(string(test)) == 0 end # Fixed by Mike Stok def Functions::contains( string, test ) string(string).include?(string(test)) end # Kouhei fixed this def Functions::substring_before( string, test ) ruby_string = string(string) ruby_index = ruby_string.index(string(test)) if ruby_index.nil? "" else ruby_string[ 0...ruby_index ] end end # Kouhei fixed this too def Functions::substring_after( string, test ) ruby_string = string(string) test_string = string(test) return $1 if ruby_string =~ /#{test}(.*)/ "" end # Take equal portions of Mike Stok and Sean Russell; mix # vigorously, and pour into a tall, chilled glass. Serves 10,000. def Functions::substring( string, start, length=nil ) ruby_string = string(string) ruby_length = if length.nil? ruby_string.length.to_f else number(length) end ruby_start = number(start) # Handle the special cases return '' if ( ruby_length.nan? or ruby_start.nan? or ruby_start.infinite? ) infinite_length = ruby_length.infinite? == 1 ruby_length = ruby_string.length if infinite_length # Now, get the bounds. The XPath bounds are 1..length; the ruby bounds # are 0..length. Therefore, we have to offset the bounds by one. ruby_start = ruby_start.round - 1 ruby_length = ruby_length.round if ruby_start < 0 ruby_length += ruby_start unless infinite_length ruby_start = 0 end return '' if ruby_length <= 0 ruby_string[ruby_start,ruby_length] end # UNTESTED def Functions::string_length( string ) string(string).length end # UNTESTED def Functions::normalize_space( string=nil ) string = string(@@context[:node]) if string.nil? if string.kind_of? Array string.collect{|x| string.to_s.strip.gsub(/\s+/um, ' ') if string} else string.to_s.strip.gsub(/\s+/um, ' ') end end # This is entirely Mike Stok's beast def Functions::translate( string, tr1, tr2 ) from = string(tr1) to = string(tr2) # the map is our translation table. # # if a character occurs more than once in the # from string then we ignore the second & # subsequent mappings # # if a character maps to nil then we delete it # in the output. This happens if the from # string is longer than the to string # # there's nothing about - or ^ being special in # http://www.w3.org/TR/xpath#function-translate # so we don't build ranges or negated classes map = Hash.new 0.upto(from.length - 1) { |pos| from_char = from[pos] unless map.has_key? from_char map[from_char] = if pos < to.length to[pos] else nil end end } string(string).unpack('U*').collect { |c| if map.has_key? c then map[c] else c end }.compact.pack('U*') end # UNTESTED def Functions::boolean( object=nil ) if object.kind_of? String if object =~ /\d+/u return object.to_f != 0 else return object.size > 0 end elsif object.kind_of? Array object = object.find{|x| x and true} end return object ? true : false end # UNTESTED def Functions::not( object ) not boolean( object ) end # UNTESTED def Functions::true( ) true end # UNTESTED def Functions::false( ) false end # UNTESTED def Functions::lang( language ) lang = false node = @@context[:node] attr = nil until node.nil? if node.node_type == :element attr = node.attributes["xml:lang"] unless attr.nil? lang = compare_language(string(language), attr) break else end end node = node.parent end lang end def Functions::compare_language lang1, lang2 lang2.downcase.index(lang1.downcase) == 0 end # a string that consists of optional whitespace followed by an optional # minus sign followed by a Number followed by whitespace is converted to # the IEEE 754 number that is nearest (according to the IEEE 754 # round-to-nearest rule) to the mathematical value represented by the # string; any other string is converted to NaN # # boolean true is converted to 1; boolean false is converted to 0 # # a node-set is first converted to a string as if by a call to the string # function and then converted in the same way as a string argument # # an object of a type other than the four basic types is converted to a # number in a way that is dependent on that type def Functions::number( object=nil ) object = @@context[:node] unless object case object when true Float(1) when false Float(0) when Array number(string( object )) when Numeric object.to_f else str = string( object ) # If XPath ever gets scientific notation... #if str =~ /^\s*-?(\d*\.?\d+|\d+\.)([Ee]\d*)?\s*$/ if str =~ /^\s*-?(\d*\.?\d+|\d+\.)\s*$/ str.to_f else (0.0 / 0.0) end end end def Functions::sum( nodes ) nodes = [nodes] unless nodes.kind_of? Array nodes.inject(0) { |r,n| r += number(string(n)) } end def Functions::floor( number ) number(number).floor end def Functions::ceiling( number ) number(number).ceil end def Functions::round( number ) begin number(number).round rescue FloatDomainError number(number) end end def Functions::processing_instruction( node ) node.node_type == :processing_instruction end def Functions::method_missing( id ) puts "METHOD MISSING #{id.id2name}" XPath.match( @@context[:node], id.id2name ) end end end ================================================ FILE: lib/rexml/instruction.rb ================================================ require "rexml/child" require "rexml/source" module REXML # Represents an XML Instruction; IE, # TODO: Add parent arg (3rd arg) to constructor class Instruction < Child START = '<\?' STOP = '\?>' # target is the "name" of the Instruction; IE, the "tag" in # content is everything else. attr_accessor :target, :content # Constructs a new Instruction # @param target can be one of a number of things. If String, then # the target of this instruction is set to this. If an Instruction, # then the Instruction is shallowly cloned (target and content are # copied). If a Source, then the source is scanned and parsed for # an Instruction declaration. # @param content Must be either a String, or a Parent. Can only # be a Parent if the target argument is a Source. Otherwise, this # String is set as the content of this instruction. def initialize(target, content=nil) if target.kind_of? String super() @target = target @content = content elsif target.kind_of? Instruction super(content) @target = target.target @content = target.content end @content.strip! if @content end def clone Instruction.new self end # == DEPRECATED # See the rexml/formatters package # def write writer, indent=-1, transitive=false, ie_hack=false Kernel.warn( "#{self.class.name}.write is deprecated" ) indent(writer, indent) writer << START.sub(/\\/u, '') writer << @target writer << ' ' writer << @content writer << STOP.sub(/\\/u, '') end # @return true if other is an Instruction, and the content and target # of the other matches the target and content of this object. def ==( other ) other.kind_of? Instruction and other.target == @target and other.content == @content end def node_type :processing_instruction end def inspect "" end end end ================================================ FILE: lib/rexml/light/node.rb ================================================ require 'rexml/xmltokens' require 'rexml/light/node' # [ :element, parent, name, attributes, children* ] # a = Node.new # a << "B" # => B # a.b # => B # a.b[1] # => B # a.b[1]["x"] = "y" # => B # a.b[0].c # => B # a.b.c << "D" # => BD module REXML module Light # Represents a tagged XML element. Elements are characterized by # having children, attributes, and names, and can themselves be # children. class Node NAMESPLIT = /^(?:(#{XMLTokens::NCNAME_STR}):)?(#{XMLTokens::NCNAME_STR})/u PARENTS = [ :element, :document, :doctype ] # Create a new element. def initialize node=nil @node = node if node.kind_of? String node = [ :text, node ] elsif node.nil? node = [ :document, nil, nil ] elsif node[0] == :start_element node[0] = :element elsif node[0] == :start_doctype node[0] = :doctype elsif node[0] == :start_document node[0] = :document end end def size if PARENTS.include? @node[0] @node[-1].size else 0 end end def each( &block ) size.times { |x| yield( at(x+4) ) } end def name at(2) end def name=( name_str, ns=nil ) pfx = '' pfx = "#{prefix(ns)}:" if ns _old_put(2, "#{pfx}#{name_str}") end def parent=( node ) _old_put(1,node) end def local_name namesplit @name end def local_name=( name_str ) _old_put( 1, "#@prefix:#{name_str}" ) end def prefix( namespace=nil ) prefix_of( self, namespace ) end def namespace( prefix=prefix() ) namespace_of( self, prefix ) end def namespace=( namespace ) @prefix = prefix( namespace ) pfx = '' pfx = "#@prefix:" if @prefix.size > 0 _old_put(1, "#{pfx}#@name") end def []( reference, ns=nil ) if reference.kind_of? String pfx = '' pfx = "#{prefix(ns)}:" if ns at(3)["#{pfx}#{reference}"] elsif reference.kind_of? Range _old_get( Range.new(4+reference.begin, reference.end, reference.exclude_end?) ) else _old_get( 4+reference ) end end def =~( path ) XPath.match( self, path ) end # Doesn't handle namespaces yet def []=( reference, ns, value=nil ) if reference.kind_of? String value = ns unless value at( 3 )[reference] = value elsif reference.kind_of? Range _old_put( Range.new(3+reference.begin, reference.end, reference.exclude_end?), ns ) else if value _old_put( 4+reference, ns, value ) else _old_put( 4+reference, ns ) end end end # Append a child to this element, optionally under a provided namespace. # The namespace argument is ignored if the element argument is an Element # object. Otherwise, the element argument is a string, the namespace (if # provided) is the namespace the element is created in. def << element if node_type() == :text at(-1) << element else newnode = Node.new( element ) newnode.parent = self self.push( newnode ) end at(-1) end def node_type _old_get(0) end def text=( foo ) replace = at(4).kind_of?(String)? 1 : 0 self._old_put(4,replace, normalizefoo) end def root context = self context = context.at(1) while context.at(1) end def has_name?( name, namespace = '' ) at(3) == name and namespace() == namespace end def children self end def parent at(1) end def to_s end private def namesplit return if @name.defined? at(2) =~ NAMESPLIT @prefix = '' || $1 @name = $2 end def namespace_of( node, prefix=nil ) if not prefix name = at(2) name =~ NAMESPLIT prefix = $1 end to_find = 'xmlns' to_find = "xmlns:#{prefix}" if not prefix.nil? ns = at(3)[ to_find ] ns ? ns : namespace_of( @node[0], prefix ) end def prefix_of( node, namespace=nil ) if not namespace name = node.name name =~ NAMESPLIT $1 else ns = at(3).find { |k,v| v == namespace } ns ? ns : prefix_of( node.parent, namespace ) end end end end end ================================================ FILE: lib/rexml/namespace.rb ================================================ require 'rexml/xmltokens' module REXML # Adds named attributes to an object. module Namespace # The name of the object, valid if set attr_reader :name, :expanded_name # The expanded name of the object, valid if name is set attr_accessor :prefix include XMLTokens NAMESPLIT = /^(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})/u # Sets the name and the expanded name def name=( name ) @expanded_name = name name =~ NAMESPLIT if $1 @prefix = $1 else @prefix = "" @namespace = "" end @name = $2 end # Compares names optionally WITH namespaces def has_name?( other, ns=nil ) if ns return (namespace() == ns and name() == other) elsif other.include? ":" return fully_expanded_name == other else return name == other end end alias :local_name :name # Fully expand the name, even if the prefix wasn't specified in the # source file. def fully_expanded_name ns = prefix return "#{ns}:#@name" if ns.size > 0 return @name end end end ================================================ FILE: lib/rexml/node.rb ================================================ require "rexml/parseexception" require "rexml/formatters/pretty" require "rexml/formatters/default" module REXML # Represents a node in the tree. Nodes are never encountered except as # superclasses of other objects. Nodes have siblings. module Node # @return the next sibling (nil if unset) def next_sibling_node return nil if @parent.nil? @parent[ @parent.index(self) + 1 ] end # @return the previous sibling (nil if unset) def previous_sibling_node return nil if @parent.nil? ind = @parent.index(self) return nil if ind == 0 @parent[ ind - 1 ] end # indent:: # *DEPRECATED* This parameter is now ignored. See the formatters in the # REXML::Formatters package for changing the output style. def to_s indent=nil unless indent.nil? Kernel.warn( "#{self.class.name}.to_s(indent) parameter is deprecated" ) f = REXML::Formatters::Pretty.new( indent ) f.write( self, rv = "" ) else f = REXML::Formatters::Default.new f.write( self, rv = "" ) end return rv end def indent to, ind if @parent and @parent.context and not @parent.context[:indentstyle].nil? then indentstyle = @parent.context[:indentstyle] else indentstyle = ' ' end to << indentstyle*ind unless ind<1 end def parent? false; end # Visit all subnodes of +self+ recursively def each_recursive(&block) # :yields: node self.elements.each {|node| block.call(node) node.each_recursive(&block) } end # Find (and return) first subnode (recursively) for which the block # evaluates to true. Returns +nil+ if none was found. def find_first_recursive(&block) # :yields: node each_recursive {|node| return node if block.call(node) } return nil end # Returns the position that +self+ holds in its parent's array, indexed # from 1. def index_in_parent parent.index(self)+1 end end end ================================================ FILE: lib/rexml/output.rb ================================================ require 'rexml/encoding' module REXML class Output include Encoding attr_reader :encoding def initialize real_IO, encd="iso-8859-1" @output = real_IO self.encoding = encd @to_utf = encd == UTF_8 ? false : true end def <<( content ) @output << (@to_utf ? self.encode(content) : content) end def to_s "Output[#{encoding}]" end end end ================================================ FILE: lib/rexml/parent.rb ================================================ require "rexml/child" module REXML # A parent has children, and has methods for accessing them. The Parent # class is never encountered except as the superclass for some other # object. class Parent < Child include Enumerable # Constructor # @param parent if supplied, will be set as the parent of this object def initialize parent=nil super(parent) @children = [] end def add( object ) #puts "PARENT GOTS #{size} CHILDREN" object.parent = self @children << object #puts "PARENT NOW GOTS #{size} CHILDREN" object end alias :push :add alias :<< :push def unshift( object ) object.parent = self @children.unshift object end def delete( object ) found = false @children.delete_if {|c| c.equal?(object) and found = true } object.parent = nil if found end def each(&block) @children.each(&block) end def delete_if( &block ) @children.delete_if(&block) end def delete_at( index ) @children.delete_at index end def each_index( &block ) @children.each_index(&block) end # Fetches a child at a given index # @param index the Integer index of the child to fetch def []( index ) @children[index] end alias :each_child :each # Set an index entry. See Array.[]= # @param index the index of the element to set # @param opt either the object to set, or an Integer length # @param child if opt is an Integer, this is the child to set # @return the parent (self) def []=( *args ) args[-1].parent = self @children[*args[0..-2]] = args[-1] end # Inserts an child before another child # @param child1 this is either an xpath or an Element. If an Element, # child2 will be inserted before child1 in the child list of the parent. # If an xpath, child2 will be inserted before the first child to match # the xpath. # @param child2 the child to insert # @return the parent (self) def insert_before( child1, child2 ) if child1.kind_of? String child1 = XPath.first( self, child1 ) child1.parent.insert_before child1, child2 else ind = index(child1) child2.parent.delete(child2) if child2.parent @children[ind,0] = child2 child2.parent = self end self end # Inserts an child after another child # @param child1 this is either an xpath or an Element. If an Element, # child2 will be inserted after child1 in the child list of the parent. # If an xpath, child2 will be inserted after the first child to match # the xpath. # @param child2 the child to insert # @return the parent (self) def insert_after( child1, child2 ) if child1.kind_of? String child1 = XPath.first( self, child1 ) child1.parent.insert_after child1, child2 else ind = index(child1)+1 child2.parent.delete(child2) if child2.parent @children[ind,0] = child2 child2.parent = self end self end def to_a @children.dup end # Fetches the index of a given child # @param child the child to get the index of # @return the index of the child, or nil if the object is not a child # of this parent. def index( child ) count = -1 @children.find { |i| count += 1 ; i.hash == child.hash } count end # @return the number of children of this parent def size @children.size end alias :length :size # Replaces one child with another, making sure the nodelist is correct # @param to_replace the child to replace (must be a Child) # @param replacement the child to insert into the nodelist (must be a # Child) def replace_child( to_replace, replacement ) @children.map! {|c| c.equal?( to_replace ) ? replacement : c } to_replace.parent = nil replacement.parent = self end # Deeply clones this object. This creates a complete duplicate of this # Parent, including all descendants. def deep_clone cl = clone() each do |child| if child.kind_of? Parent cl << child.deep_clone else cl << child.clone end end cl end alias :children :to_a def parent? true end end end ================================================ FILE: lib/rexml/parseexception.rb ================================================ module REXML class ParseException < RuntimeError attr_accessor :source, :parser, :continued_exception def initialize( message, source=nil, parser=nil, exception=nil ) super(message) @source = source @parser = parser @continued_exception = exception end def to_s # Quote the original exception, if there was one if @continued_exception err = @continued_exception.inspect err << "\n" err << @continued_exception.backtrace.join("\n") err << "\n...\n" else err = "" end # Get the stack trace and error message err << super # Add contextual information if @source err << "\nLine: #{line}\n" err << "Position: #{position}\n" err << "Last 80 unconsumed characters:\n" err << @source.buffer[0..80].gsub(/\n/, ' ') end err end def position @source.current_line[0] if @source and defined? @source.current_line and @source.current_line end def line @source.current_line[2] if @source and defined? @source.current_line and @source.current_line end def context @source.current_line end end end ================================================ FILE: lib/rexml/parsers/baseparser.rb ================================================ require 'rexml/parseexception' require 'rexml/undefinednamespaceexception' require 'rexml/source' require 'set' module REXML module Parsers # = Using the Pull Parser # This API is experimental, and subject to change. # parser = PullParser.new( "texttxet" ) # while parser.has_next? # res = parser.next # puts res[1]['att'] if res.start_tag? and res[0] == 'b' # end # See the PullEvent class for information on the content of the results. # The data is identical to the arguments passed for the various events to # the StreamListener API. # # Notice that: # parser = PullParser.new( "BAD DOCUMENT" ) # while parser.has_next? # res = parser.next # raise res[1] if res.error? # end # # Nat Price gave me some good ideas for the API. class BaseParser NCNAME_STR= '[\w:][\-\w\d.]*' NAME_STR= "(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})" UNAME_STR= "(?:#{NCNAME_STR}:)?#{NCNAME_STR}" NAMECHAR = '[\-\w\d\.:]' NAME = "([\\w:]#{NAMECHAR}*)" NMTOKEN = "(?:#{NAMECHAR})+" NMTOKENS = "#{NMTOKEN}(\\s+#{NMTOKEN})*" REFERENCE = "(?:&#{NAME};|&#\\d+;|&#x[0-9a-fA-F]+;)" REFERENCE_RE = /#{REFERENCE}/ DOCTYPE_START = /\A\s*)/um ATTRIBUTE_PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\4/um COMMENT_START = /\A/um CDATA_START = /\A/um CDATA_PATTERN = //um XMLDECL_START = /\A<\?xml\s/u; XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>/um INSTRUCTION_START = /\A<\?/u INSTRUCTION_PATTERN = /<\?(.*?)(\s+.*?)?\?>/um TAG_MATCH = /^<((?>#{NAME_STR}))\s*((?>\s+#{UNAME_STR}\s*=\s*(["']).*?\5)*)\s*(\/)?>/um CLOSE_MATCH = /^\s*<\/(#{NAME_STR})\s*>/um VERSION = /\bversion\s*=\s*["'](.*?)['"]/um ENCODING = /\bencoding\s*=\s*["'](.*?)['"]/um STANDALONE = /\bstandalone\s*=\s["'](.*?)['"]/um ENTITY_START = /^\s*/um SYSTEMENTITY = /^\s*(%.*?;)\s*$/um ENUMERATION = "\\(\\s*#{NMTOKEN}(?:\\s*\\|\\s*#{NMTOKEN})*\\s*\\)" NOTATIONTYPE = "NOTATION\\s+\\(\\s*#{NAME}(?:\\s*\\|\\s*#{NAME})*\\s*\\)" ENUMERATEDTYPE = "(?:(?:#{NOTATIONTYPE})|(?:#{ENUMERATION}))" ATTTYPE = "(CDATA|ID|IDREF|IDREFS|ENTITY|ENTITIES|NMTOKEN|NMTOKENS|#{ENUMERATEDTYPE})" ATTVALUE = "(?:\"((?:[^<&\"]|#{REFERENCE})*)\")|(?:'((?:[^<&']|#{REFERENCE})*)')" DEFAULTDECL = "(#REQUIRED|#IMPLIED|(?:(#FIXED\\s+)?#{ATTVALUE}))" ATTDEF = "\\s+#{NAME}\\s+#{ATTTYPE}\\s+#{DEFAULTDECL}" ATTDEF_RE = /#{ATTDEF}/ ATTLISTDECL_START = /^\s*/um NOTATIONDECL_START = /^\s*/um SYSTEM = /^\s*/um TEXT_PATTERN = /\A([^<]*)/um # Entity constants PUBIDCHAR = "\x20\x0D\x0Aa-zA-Z0-9\\-()+,./:=?;!*@$_%#" SYSTEMLITERAL = %Q{((?:"[^"]*")|(?:'[^']*'))} PUBIDLITERAL = %Q{("[#{PUBIDCHAR}']*"|'[#{PUBIDCHAR}]*')} EXTERNALID = "(?:(?:(SYSTEM)\\s+#{SYSTEMLITERAL})|(?:(PUBLIC)\\s+#{PUBIDLITERAL}\\s+#{SYSTEMLITERAL}))" NDATADECL = "\\s+NDATA\\s+#{NAME}" PEREFERENCE = "%#{NAME};" ENTITYVALUE = %Q{((?:"(?:[^%&"]|#{PEREFERENCE}|#{REFERENCE})*")|(?:'([^%&']|#{PEREFERENCE}|#{REFERENCE})*'))} PEDEF = "(?:#{ENTITYVALUE}|#{EXTERNALID})" ENTITYDEF = "(?:#{ENTITYVALUE}|(?:#{EXTERNALID}(#{NDATADECL})?))" PEDECL = "" GEDECL = "" ENTITYDECL = /\s*(?:#{GEDECL})|(?:#{PEDECL})/um EREFERENCE = /&(?!#{NAME};)/ DEFAULT_ENTITIES = { 'gt' => [/>/, '>', '>', />/], 'lt' => [/</, '<', '<', / [/"/, '"', '"', /"/], "apos" => [/'/, "'", "'", /'/] } ###################################################################### # These are patterns to identify common markup errors, to make the # error messages more informative. ###################################################################### MISSING_ATTRIBUTE_QUOTES = /^<#{NAME_STR}\s+#{NAME_STR}\s*=\s*[^"']/um def initialize( source ) self.stream = source end def add_listener( listener ) if !defined?(@listeners) or !@listeners @listeners = [] instance_eval <<-EOL alias :_old_pull :pull def pull event = _old_pull @listeners.each do |listener| listener.receive event end event end EOL end @listeners << listener end attr_reader :source def stream=( source ) @source = SourceFactory.create_from( source ) @closed = nil @document_status = nil @tags = [] @stack = [] @entities = [] @nsstack = [] end def position if @source.respond_to? :position @source.position else # FIXME 0 end end # Returns true if there are no more events def empty? return (@source.empty? and @stack.empty?) end # Returns true if there are more events. Synonymous with !empty? def has_next? return !(@source.empty? and @stack.empty?) end # Push an event back on the head of the stream. This method # has (theoretically) infinite depth. def unshift token @stack.unshift(token) end # Peek at the +depth+ event in the stack. The first element on the stack # is at depth 0. If +depth+ is -1, will parse to the end of the input # stream and return the last event, which is always :end_document. # Be aware that this causes the stream to be parsed up to the +depth+ # event, so you can effectively pre-parse the entire document (pull the # entire thing into memory) using this method. def peek depth=0 raise %Q[Illegal argument "#{depth}"] if depth < -1 temp = [] if depth == -1 temp.push(pull()) until empty? else while @stack.size+temp.size < depth+1 temp.push(pull()) end end @stack += temp if temp.size > 0 @stack[depth] end # Returns the next event. This is a +PullEvent+ object. def pull if @closed x, @closed = @closed, nil return [ :end_element, x ] end return [ :end_document ] if empty? return @stack.shift if @stack.size > 0 #STDERR.puts @source.encoding @source.read if @source.buffer.size<2 #STDERR.puts "BUFFER = #{@source.buffer.inspect}" if @document_status == nil #@source.consume( /^\s*/um ) word = @source.match( /^((?:\s+)|(?:<[^>]*>))/um ) word = word[1] unless word.nil? #STDERR.puts "WORD = #{word.inspect}" case word when COMMENT_START return [ :comment, @source.match( COMMENT_PATTERN, true )[1] ] when XMLDECL_START #STDERR.puts "XMLDECL" results = @source.match( XMLDECL_PATTERN, true )[1] version = VERSION.match( results ) version = version[1] unless version.nil? encoding = ENCODING.match(results) encoding = encoding[1] unless encoding.nil? @source.encoding = encoding standalone = STANDALONE.match(results) standalone = standalone[1] unless standalone.nil? return [ :xmldecl, version, encoding, standalone ] when INSTRUCTION_START return [ :processing_instruction, *@source.match(INSTRUCTION_PATTERN, true)[1,2] ] when DOCTYPE_START md = @source.match( DOCTYPE_PATTERN, true ) @nsstack.unshift(curr_ns=Set.new) identity = md[1] close = md[2] identity =~ IDENTITY name = $1 raise REXML::ParseException.new("DOCTYPE is missing a name") if name.nil? pub_sys = $2.nil? ? nil : $2.strip long_name = $4.nil? ? nil : $4.strip uri = $6.nil? ? nil : $6.strip args = [ :start_doctype, name, pub_sys, long_name, uri ] if close == ">" @document_status = :after_doctype @source.read if @source.buffer.size<2 md = @source.match(/^\s*/um, true) @stack << [ :end_doctype ] else @document_status = :in_doctype end return args when /^\s+/ else @document_status = :after_doctype @source.read if @source.buffer.size<2 md = @source.match(/\s*/um, true) end end if @document_status == :in_doctype md = @source.match(/\s*(.*?>)/um) case md[1] when SYSTEMENTITY match = @source.match( SYSTEMENTITY, true )[1] return [ :externalentity, match ] when ELEMENTDECL_START return [ :elementdecl, @source.match( ELEMENTDECL_PATTERN, true )[1] ] when ENTITY_START match = @source.match( ENTITYDECL, true ).to_a.compact match[0] = :entitydecl ref = false if match[1] == '%' ref = true match.delete_at 1 end # Now we have to sort out what kind of entity reference this is if match[2] == 'SYSTEM' # External reference match[3] = match[3][1..-2] # PUBID match.delete_at(4) if match.size > 4 # Chop out NDATA decl # match is [ :entity, name, SYSTEM, pubid(, ndata)? ] elsif match[2] == 'PUBLIC' # External reference match[3] = match[3][1..-2] # PUBID match[4] = match[4][1..-2] # HREF # match is [ :entity, name, PUBLIC, pubid, href ] else match[2] = match[2][1..-2] match.pop if match.size == 4 # match is [ :entity, name, value ] end match << '%' if ref return match when ATTLISTDECL_START md = @source.match( ATTLISTDECL_PATTERN, true ) raise REXML::ParseException.new( "Bad ATTLIST declaration!", @source ) if md.nil? element = md[1] contents = md[0] pairs = {} values = md[0].scan( ATTDEF_RE ) values.each do |attdef| unless attdef[3] == "#IMPLIED" attdef.compact! val = attdef[3] val = attdef[4] if val == "#FIXED " pairs[attdef[0]] = val if attdef[0] =~ /^xmlns:(.*)/ @nsstack[0] << $1 end end end return [ :attlistdecl, element, pairs, contents ] when NOTATIONDECL_START md = nil if @source.match( PUBLIC ) md = @source.match( PUBLIC, true ) vals = [md[1],md[2],md[4],md[6]] elsif @source.match( SYSTEM ) md = @source.match( SYSTEM, true ) vals = [md[1],md[2],nil,md[4]] else raise REXML::ParseException.new( "error parsing notation: no matching pattern", @source ) end return [ :notationdecl, *vals ] when CDATA_END @document_status = :after_doctype @source.match( CDATA_END, true ) return [ :end_doctype ] end end begin if @source.buffer[0] == ?< if @source.buffer[1] == ?/ @nsstack.shift last_tag = @tags.pop #md = @source.match_to_consume( '>', CLOSE_MATCH) md = @source.match( CLOSE_MATCH, true ) raise REXML::ParseException.new( "Missing end tag for "+ "'#{last_tag}' (got \"#{md[1]}\")", @source) unless last_tag == md[1] return [ :end_element, last_tag ] elsif @source.buffer[1] == ?! md = @source.match(/\A(\s*[^>]*>)/um) #STDERR.puts "SOURCE BUFFER = #{source.buffer}, #{source.buffer.size}" raise REXML::ParseException.new("Malformed node", @source) unless md if md[0][2] == ?- md = @source.match( COMMENT_PATTERN, true ) return [ :comment, md[1] ] if md else md = @source.match( CDATA_PATTERN, true ) return [ :cdata, md[1] ] if md end raise REXML::ParseException.new( "Declarations can only occur "+ "in the doctype declaration.", @source) elsif @source.buffer[1] == ?? md = @source.match( INSTRUCTION_PATTERN, true ) return [ :processing_instruction, md[1], md[2] ] if md raise REXML::ParseException.new( "Bad instruction declaration", @source) else # Get the next tag md = @source.match(TAG_MATCH, true) unless md # Check for missing attribute quotes raise REXML::ParseException.new("missing attribute quote", @source) if @source.match(MISSING_ATTRIBUTE_QUOTES ) raise REXML::ParseException.new("malformed XML: missing tag start", @source) end attributes = {} prefixes = Set.new prefixes << md[2] if md[2] @nsstack.unshift(curr_ns=Set.new) if md[4].size > 0 attrs = md[4].scan( ATTRIBUTE_PATTERN ) raise REXML::ParseException.new( "error parsing attributes: [#{attrs.join ', '}], excess = \"#$'\"", @source) if $' and $'.strip.size > 0 attrs.each { |a,b,c,d,e| if b == "xmlns" if c == "xml" if d != "http://www.w3.org/XML/1998/namespace" msg = "The 'xml' prefix must not be bound to any other namespace "+ "(http://www.w3.org/TR/REC-xml-names/#ns-decl)" raise REXML::ParseException.new( msg, @source, self ) end elsif c == "xmlns" msg = "The 'xmlns' prefix must not be declared "+ "(http://www.w3.org/TR/REC-xml-names/#ns-decl)" raise REXML::ParseException.new( msg, @source, self) end curr_ns << c elsif b prefixes << b unless b == "xml" end attributes[a] = e } end # Verify that all of the prefixes have been defined for prefix in prefixes unless @nsstack.find{|k| k.member?(prefix)} raise UndefinedNamespaceException.new(prefix,@source,self) end end if md[6] @closed = md[1] @nsstack.shift else @tags.push( md[1] ) end return [ :start_element, md[1], attributes ] end else md = @source.match( TEXT_PATTERN, true ) if md[0].length == 0 @source.match( /(\s+)/, true ) end #STDERR.puts "GOT #{md[1].inspect}" unless md[0].length == 0 #return [ :text, "" ] if md[0].length == 0 # unnormalized = Text::unnormalize( md[1], self ) # return PullEvent.new( :text, md[1], unnormalized ) return [ :text, md[1] ] end rescue REXML::UndefinedNamespaceException raise rescue REXML::ParseException raise rescue Exception, NameError => error raise REXML::ParseException.new( "Exception parsing", @source, self, (error ? error : $!) ) end return [ :dummy ] end def entity( reference, entities ) value = nil value = entities[ reference ] if entities if not value value = DEFAULT_ENTITIES[ reference ] value = value[2] if value end unnormalize( value, entities ) if value end # Escapes all possible entities def normalize( input, entities=nil, entity_filter=nil ) copy = input.clone # Doing it like this rather than in a loop improves the speed copy.gsub!( EREFERENCE, '&' ) entities.each do |key, value| copy.gsub!( value, "&#{key};" ) unless entity_filter and entity_filter.include?(entity) end if entities copy.gsub!( EREFERENCE, '&' ) DEFAULT_ENTITIES.each do |key, value| copy.gsub!( value[3], value[1] ) end copy end # Unescapes all possible entities def unnormalize( string, entities=nil, filter=nil ) rv = string.clone rv.gsub!( /\r\n?/, "\n" ) matches = rv.scan( REFERENCE_RE ) return rv if matches.size == 0 rv.gsub!( /�*((?:\d+)|(?:x[a-fA-F0-9]+));/ ) {|m| m=$1 m = "0#{m}" if m[0] == ?x [Integer(m)].pack('U*') } matches.collect!{|x|x[0]}.compact! if matches.size > 0 matches.each do |entity_reference| unless filter and filter.include?(entity_reference) entity_value = entity( entity_reference, entities ) if entity_value re = /&#{entity_reference};/ rv.gsub!( re, entity_value ) end end end matches.each do |entity_reference| unless filter and filter.include?(entity_reference) er = DEFAULT_ENTITIES[entity_reference] rv.gsub!( er[0], er[2] ) if er end end rv.gsub!( /&/, '&' ) end rv end end end end =begin case event[0] when :start_element when :text when :end_element when :processing_instruction when :cdata when :comment when :xmldecl when :start_doctype when :end_doctype when :externalentity when :elementdecl when :entity when :attlistdecl when :notationdecl when :end_doctype end =end ================================================ FILE: lib/rexml/parsers/lightparser.rb ================================================ require 'rexml/parsers/streamparser' require 'rexml/parsers/baseparser' require 'rexml/light/node' module REXML module Parsers class LightParser def initialize stream @stream = stream @parser = REXML::Parsers::BaseParser.new( stream ) end def add_listener( listener ) @parser.add_listener( listener ) end def rewind @stream.rewind @parser.stream = @stream end def parse root = context = [ :document ] while true event = @parser.pull case event[0] when :end_document break when :end_doctype context = context[1] when :start_element, :start_doctype new_node = event context << new_node new_node[1,0] = [context] context = new_node when :end_element, :end_doctype context = context[1] else new_node = event context << new_node new_node[1,0] = [context] end end root end end # An element is an array. The array contains: # 0 The parent element # 1 The tag name # 2 A hash of attributes # 3..-1 The child elements # An element is an array of size > 3 # Text is a String # PIs are [ :processing_instruction, target, data ] # Comments are [ :comment, data ] # DocTypes are DocType structs # The root is an array with XMLDecls, Text, DocType, Array, Text end end ================================================ FILE: lib/rexml/parsers/pullparser.rb ================================================ require 'forwardable' require 'rexml/parseexception' require 'rexml/parsers/baseparser' require 'rexml/xmltokens' module REXML module Parsers # = Using the Pull Parser # This API is experimental, and subject to change. # parser = PullParser.new( "texttxet" ) # while parser.has_next? # res = parser.next # puts res[1]['att'] if res.start_tag? and res[0] == 'b' # end # See the PullEvent class for information on the content of the results. # The data is identical to the arguments passed for the various events to # the StreamListener API. # # Notice that: # parser = PullParser.new( "BAD DOCUMENT" ) # while parser.has_next? # res = parser.next # raise res[1] if res.error? # end # # Nat Price gave me some good ideas for the API. class PullParser include XMLTokens extend Forwardable def_delegators( :@parser, :has_next? ) def_delegators( :@parser, :entity ) def_delegators( :@parser, :empty? ) def_delegators( :@parser, :source ) def initialize stream @entities = {} @listeners = nil @parser = BaseParser.new( stream ) @my_stack = [] end def add_listener( listener ) @listeners = [] unless @listeners @listeners << listener end def each while has_next? yield self.pull end end def peek depth=0 if @my_stack.length <= depth (depth - @my_stack.length + 1).times { e = PullEvent.new(@parser.pull) @my_stack.push(e) } end @my_stack[depth] end def pull return @my_stack.shift if @my_stack.length > 0 event = @parser.pull case event[0] when :entitydecl @entities[ event[1] ] = event[2] unless event[2] =~ /PUBLIC|SYSTEM/ when :text unnormalized = @parser.unnormalize( event[1], @entities ) event << unnormalized end PullEvent.new( event ) end def unshift token @my_stack.unshift token end end # A parsing event. The contents of the event are accessed as an +Array?, # and the type is given either by the ...? methods, or by accessing the # +type+ accessor. The contents of this object vary from event to event, # but are identical to the arguments passed to +StreamListener+s for each # event. class PullEvent # The type of this event. Will be one of :tag_start, :tag_end, :text, # :processing_instruction, :comment, :doctype, :attlistdecl, :entitydecl, # :notationdecl, :entity, :cdata, :xmldecl, or :error. def initialize(arg) @contents = arg end def []( start, endd=nil) if start.kind_of? Range @contents.slice( start.begin+1 .. start.end ) elsif start.kind_of? Numeric if endd.nil? @contents.slice( start+1 ) else @contents.slice( start+1, endd ) end else raise "Illegal argument #{start.inspect} (#{start.class})" end end def event_type @contents[0] end # Content: [ String tag_name, Hash attributes ] def start_element? @contents[0] == :start_element end # Content: [ String tag_name ] def end_element? @contents[0] == :end_element end # Content: [ String raw_text, String unnormalized_text ] def text? @contents[0] == :text end # Content: [ String text ] def instruction? @contents[0] == :processing_instruction end # Content: [ String text ] def comment? @contents[0] == :comment end # Content: [ String name, String pub_sys, String long_name, String uri ] def doctype? @contents[0] == :start_doctype end # Content: [ String text ] def attlistdecl? @contents[0] == :attlistdecl end # Content: [ String text ] def elementdecl? @contents[0] == :elementdecl end # Due to the wonders of DTDs, an entity declaration can be just about # anything. There's no way to normalize it; you'll have to interpret the # content yourself. However, the following is true: # # * If the entity declaration is an internal entity: # [ String name, String value ] # Content: [ String text ] def entitydecl? @contents[0] == :entitydecl end # Content: [ String text ] def notationdecl? @contents[0] == :notationdecl end # Content: [ String text ] def entity? @contents[0] == :entity end # Content: [ String text ] def cdata? @contents[0] == :cdata end # Content: [ String version, String encoding, String standalone ] def xmldecl? @contents[0] == :xmldecl end def error? @contents[0] == :error end def inspect @contents[0].to_s + ": " + @contents[1..-1].inspect end end end end ================================================ FILE: lib/rexml/parsers/sax2parser.rb ================================================ require 'rexml/parsers/baseparser' require 'rexml/parseexception' require 'rexml/namespace' require 'rexml/text' module REXML module Parsers # SAX2Parser class SAX2Parser def initialize source @parser = BaseParser.new(source) @listeners = [] @procs = [] @namespace_stack = [] @has_listeners = false @tag_stack = [] @entities = {} end def source @parser.source end def add_listener( listener ) @parser.add_listener( listener ) end # Listen arguments: # # Symbol, Array, Block # Listen to Symbol events on Array elements # Symbol, Block # Listen to Symbol events # Array, Listener # Listen to all events on Array elements # Array, Block # Listen to :start_element events on Array elements # Listener # Listen to All events # # Symbol can be one of: :start_element, :end_element, # :start_prefix_mapping, :end_prefix_mapping, :characters, # :processing_instruction, :doctype, :attlistdecl, :elementdecl, # :entitydecl, :notationdecl, :cdata, :xmldecl, :comment # # There is an additional symbol that can be listened for: :progress. # This will be called for every event generated, passing in the current # stream position. # # Array contains regular expressions or strings which will be matched # against fully qualified element names. # # Listener must implement the methods in SAX2Listener # # Block will be passed the same arguments as a SAX2Listener method would # be, where the method name is the same as the matched Symbol. # See the SAX2Listener for more information. def listen( *args, &blok ) if args[0].kind_of? Symbol if args.size == 2 args[1].each { |match| @procs << [args[0], match, blok] } else add( [args[0], nil, blok] ) end elsif args[0].kind_of? Array if args.size == 2 args[0].each { |match| add( [nil, match, args[1]] ) } else args[0].each { |match| add( [ :start_element, match, blok ] ) } end else add([nil, nil, args[0]]) end end def deafen( listener=nil, &blok ) if listener @listeners.delete_if {|item| item[-1] == listener } @has_listeners = false if @listeners.size == 0 else @procs.delete_if {|item| item[-1] == blok } end end def parse @procs.each { |sym,match,block| block.call if sym == :start_document } @listeners.each { |sym,match,block| block.start_document if sym == :start_document or sym.nil? } root = context = [] while true event = @parser.pull case event[0] when :end_document handle( :end_document ) break when :start_doctype handle( :doctype, *event[1..-1]) when :end_doctype context = context[1] when :start_element @tag_stack.push(event[1]) # find the observers for namespaces procs = get_procs( :start_prefix_mapping, event[1] ) listeners = get_listeners( :start_prefix_mapping, event[1] ) if procs or listeners # break out the namespace declarations # The attributes live in event[2] event[2].each {|n, v| event[2][n] = @parser.normalize(v)} nsdecl = event[2].find_all { |n, value| n =~ /^xmlns(:|$)/ } nsdecl.collect! { |n, value| [ n[6..-1], value ] } @namespace_stack.push({}) nsdecl.each do |n,v| @namespace_stack[-1][n] = v # notify observers of namespaces procs.each { |ob| ob.call( n, v ) } if procs listeners.each { |ob| ob.start_prefix_mapping(n, v) } if listeners end end event[1] =~ Namespace::NAMESPLIT prefix = $1 local = $2 uri = get_namespace(prefix) # find the observers for start_element procs = get_procs( :start_element, event[1] ) listeners = get_listeners( :start_element, event[1] ) # notify observers procs.each { |ob| ob.call( uri, local, event[1], event[2] ) } if procs listeners.each { |ob| ob.start_element( uri, local, event[1], event[2] ) } if listeners when :end_element @tag_stack.pop event[1] =~ Namespace::NAMESPLIT prefix = $1 local = $2 uri = get_namespace(prefix) # find the observers for start_element procs = get_procs( :end_element, event[1] ) listeners = get_listeners( :end_element, event[1] ) # notify observers procs.each { |ob| ob.call( uri, local, event[1] ) } if procs listeners.each { |ob| ob.end_element( uri, local, event[1] ) } if listeners namespace_mapping = @namespace_stack.pop # find the observers for namespaces procs = get_procs( :end_prefix_mapping, event[1] ) listeners = get_listeners( :end_prefix_mapping, event[1] ) if procs or listeners namespace_mapping.each do |prefix, uri| # notify observers of namespaces procs.each { |ob| ob.call( prefix ) } if procs listeners.each { |ob| ob.end_prefix_mapping(prefix) } if listeners end end when :text #normalized = @parser.normalize( event[1] ) #handle( :characters, normalized ) copy = event[1].clone @entities.each { |key, value| copy = copy.gsub("&#{key};", value) } copy.gsub!( Text::NUMERICENTITY ) {|m| m=$1 m = "0#{m}" if m[0] == ?x [Integer(m)].pack('U*') } handle( :characters, copy ) when :entitydecl @entities[ event[1] ] = event[2] if event.size == 3 handle( *event ) when :processing_instruction, :comment, :attlistdecl, :elementdecl, :cdata, :notationdecl, :xmldecl handle( *event ) end handle( :progress, @parser.position ) end end private def handle( symbol, *arguments ) tag = @tag_stack[-1] procs = get_procs( symbol, tag ) listeners = get_listeners( symbol, tag ) # notify observers procs.each { |ob| ob.call( *arguments ) } if procs listeners.each { |l| l.send( symbol.to_s, *arguments ) } if listeners end # The following methods are duplicates, but it is faster than using # a helper def get_procs( symbol, name ) return nil if @procs.size == 0 @procs.find_all do |sym, match, block| #puts sym.inspect+"=="+symbol.inspect+ "\t"+match.inspect+"=="+name.inspect+ "\t"+( (sym.nil? or symbol == sym) and ((name.nil? and match.nil?) or match.nil? or ( (name == match) or (match.kind_of? Regexp and name =~ match)))).to_s ( (sym.nil? or symbol == sym) and ((name.nil? and match.nil?) or match.nil? or ( (name == match) or (match.kind_of? Regexp and name =~ match) ) ) ) end.collect{|x| x[-1]} end def get_listeners( symbol, name ) return nil if @listeners.size == 0 @listeners.find_all do |sym, match, block| ( (sym.nil? or symbol == sym) and ((name.nil? and match.nil?) or match.nil? or ( (name == match) or (match.kind_of? Regexp and name =~ match) ) ) ) end.collect{|x| x[-1]} end def add( pair ) if pair[-1].respond_to? :call @procs << pair unless @procs.include? pair else @listeners << pair unless @listeners.include? pair @has_listeners = true end end def get_namespace( prefix ) uris = (@namespace_stack.find_all { |ns| not ns[prefix].nil? }) || (@namespace_stack.find { |ns| not ns[nil].nil? }) uris[-1][prefix] unless uris.nil? or 0 == uris.size end end end end ================================================ FILE: lib/rexml/parsers/streamparser.rb ================================================ module REXML module Parsers class StreamParser def initialize source, listener @listener = listener @parser = BaseParser.new( source ) end def add_listener( listener ) @parser.add_listener( listener ) end def parse # entity string while true event = @parser.pull case event[0] when :end_document return when :start_element attrs = event[2].each do |n, v| event[2][n] = @parser.unnormalize( v ) end @listener.tag_start( event[1], attrs ) when :end_element @listener.tag_end( event[1] ) when :text normalized = @parser.unnormalize( event[1] ) @listener.text( normalized ) when :processing_instruction @listener.instruction( *event[1,2] ) when :start_doctype @listener.doctype( *event[1..-1] ) when :end_doctype # FIXME: remove this condition for milestone:3.2 @listener.doctype_end if @listener.respond_to? :doctype_end when :comment, :attlistdecl, :cdata, :xmldecl, :elementdecl @listener.send( event[0].to_s, *event[1..-1] ) when :entitydecl, :notationdecl @listener.send( event[0].to_s, event[1..-1] ) end end end end end end ================================================ FILE: lib/rexml/parsers/treeparser.rb ================================================ require 'rexml/validation/validationexception' require 'rexml/undefinednamespaceexception' module REXML module Parsers class TreeParser def initialize( source, build_context = Document.new ) @build_context = build_context @parser = Parsers::BaseParser.new( source ) end def add_listener( listener ) @parser.add_listener( listener ) end def parse tag_stack = [] in_doctype = false entities = nil begin while true event = @parser.pull #STDERR.puts "TREEPARSER GOT #{event.inspect}" case event[0] when :end_document unless tag_stack.empty? #raise ParseException.new("No close tag for #{tag_stack.inspect}") raise ParseException.new("No close tag for #{@build_context.xpath}") end return when :start_element tag_stack.push(event[1]) el = @build_context = @build_context.add_element( event[1], event[2] ) when :end_element tag_stack.pop @build_context = @build_context.parent when :text if not in_doctype if @build_context[-1].instance_of? Text @build_context[-1] << event[1] else @build_context.add( Text.new(event[1], @build_context.whitespace, nil, true) ) unless ( @build_context.ignore_whitespace_nodes and event[1].strip.size==0 ) end end when :comment c = Comment.new( event[1] ) @build_context.add( c ) when :cdata c = CData.new( event[1] ) @build_context.add( c ) when :processing_instruction @build_context.add( Instruction.new( event[1], event[2] ) ) when :end_doctype in_doctype = false entities.each { |k,v| entities[k] = @build_context.entities[k].value } @build_context = @build_context.parent when :start_doctype doctype = DocType.new( event[1..-1], @build_context ) @build_context = doctype entities = {} in_doctype = true when :attlistdecl n = AttlistDecl.new( event[1..-1] ) @build_context.add( n ) when :externalentity n = ExternalEntity.new( event[1] ) @build_context.add( n ) when :elementdecl n = ElementDecl.new( event[1] ) @build_context.add(n) when :entitydecl entities[ event[1] ] = event[2] unless event[2] =~ /PUBLIC|SYSTEM/ @build_context.add(Entity.new(event)) when :notationdecl n = NotationDecl.new( *event[1..-1] ) @build_context.add( n ) when :xmldecl x = XMLDecl.new( event[1], event[2], event[3] ) @build_context.add( x ) end end rescue REXML::Validation::ValidationException raise rescue REXML::UndefinedNamespaceException raise rescue raise ParseException.new( $!.message, @parser.source, @parser, $! ) end end end end end ================================================ FILE: lib/rexml/parsers/ultralightparser.rb ================================================ require 'rexml/parsers/streamparser' require 'rexml/parsers/baseparser' module REXML module Parsers class UltraLightParser def initialize stream @stream = stream @parser = REXML::Parsers::BaseParser.new( stream ) end def add_listener( listener ) @parser.add_listener( listener ) end def rewind @stream.rewind @parser.stream = @stream end def parse root = context = [] while true event = @parser.pull case event[0] when :end_document break when :end_doctype context = context[1] when :start_element, :doctype context << event event[1,0] = [context] context = event when :end_element context = context[1] else context << event end end root end end # An element is an array. The array contains: # 0 The parent element # 1 The tag name # 2 A hash of attributes # 3..-1 The child elements # An element is an array of size > 3 # Text is a String # PIs are [ :processing_instruction, target, data ] # Comments are [ :comment, data ] # DocTypes are DocType structs # The root is an array with XMLDecls, Text, DocType, Array, Text end end ================================================ FILE: lib/rexml/parsers/xpathparser.rb ================================================ require 'rexml/namespace' require 'rexml/xmltokens' module REXML module Parsers # You don't want to use this class. Really. Use XPath, which is a wrapper # for this class. Believe me. You don't want to poke around in here. # There is strange, dark magic at work in this code. Beware. Go back! Go # back while you still can! class XPathParser include XMLTokens LITERAL = /^'([^']*)'|^"([^"]*)"/u def namespaces=( namespaces ) Functions::namespace_context = namespaces @namespaces = namespaces end def parse path path.gsub!(/([\(\[])\s+/, '\1') # Strip ignorable spaces path.gsub!( /\s+([\]\)])/, '\1' ) parsed = [] path = OrExpr(path, parsed) parsed end def predicate path parsed = [] Predicate( "[#{path}]", parsed ) parsed end def abbreviate( path ) path = path.kind_of?(String) ? parse( path ) : path string = "" document = false while path.size > 0 op = path.shift case op when :node when :attribute string << "/" if string.size > 0 string << "@" when :child string << "/" if string.size > 0 when :descendant_or_self string << "/" when :self string << "." when :parent string << ".." when :any string << "*" when :text string << "text()" when :following, :following_sibling, :ancestor, :ancestor_or_self, :descendant, :namespace, :preceding, :preceding_sibling string << "/" unless string.size == 0 string << op.to_s.tr("_", "-") string << "::" when :qname prefix = path.shift name = path.shift string << prefix+":" if prefix.size > 0 string << name when :predicate string << '[' string << predicate_to_string( path.shift ) {|x| abbreviate( x ) } string << ']' when :document document = true when :function string << path.shift string << "( " string << predicate_to_string( path.shift[0] ) {|x| abbreviate( x )} string << " )" when :literal string << %Q{ "#{path.shift}" } else string << "/" unless string.size == 0 string << "UNKNOWN(" string << op.inspect string << ")" end end string = "/"+string if document return string end def expand( path ) path = path.kind_of?(String) ? parse( path ) : path string = "" document = false while path.size > 0 op = path.shift case op when :node string << "node()" when :attribute, :child, :following, :following_sibling, :ancestor, :ancestor_or_self, :descendant, :descendant_or_self, :namespace, :preceding, :preceding_sibling, :self, :parent string << "/" unless string.size == 0 string << op.to_s.tr("_", "-") string << "::" when :any string << "*" when :qname prefix = path.shift name = path.shift string << prefix+":" if prefix.size > 0 string << name when :predicate string << '[' string << predicate_to_string( path.shift ) { |x| expand(x) } string << ']' when :document document = true else string << "/" unless string.size == 0 string << "UNKNOWN(" string << op.inspect string << ")" end end string = "/"+string if document return string end def predicate_to_string( path, &block ) string = "" case path[0] when :and, :or, :mult, :plus, :minus, :neq, :eq, :lt, :gt, :lteq, :gteq, :div, :mod, :union op = path.shift case op when :eq op = "=" when :lt op = "<" when :gt op = ">" when :lteq op = "<=" when :gteq op = ">=" when :neq op = "!=" when :union op = "|" end left = predicate_to_string( path.shift, &block ) right = predicate_to_string( path.shift, &block ) string << " " string << left string << " " string << op.to_s string << " " string << right string << " " when :function path.shift name = path.shift string << name string << "( " string << predicate_to_string( path.shift, &block ) string << " )" when :literal path.shift string << " " string << path.shift.inspect string << " " else string << " " string << yield( path ) string << " " end return string.squeeze(" ") end private #LocationPath # | RelativeLocationPath # | '/' RelativeLocationPath? # | '//' RelativeLocationPath def LocationPath path, parsed #puts "LocationPath '#{path}'" path = path.strip if path[0] == ?/ parsed << :document if path[1] == ?/ parsed << :descendant_or_self parsed << :node path = path[2..-1] else path = path[1..-1] end end #puts parsed.inspect return RelativeLocationPath( path, parsed ) if path.size > 0 end #RelativeLocationPath # | Step # | (AXIS_NAME '::' | '@' | '') AxisSpecifier # NodeTest # Predicate # | '.' | '..' AbbreviatedStep # | RelativeLocationPath '/' Step # | RelativeLocationPath '//' Step AXIS = /^(ancestor|ancestor-or-self|attribute|child|descendant|descendant-or-self|following|following-sibling|namespace|parent|preceding|preceding-sibling|self)::/ def RelativeLocationPath path, parsed #puts "RelativeLocationPath #{path}" while path.size > 0 # (axis or @ or ) nodetest predicate > # OR > / Step # (. or ..) > if path[0] == ?. if path[1] == ?. parsed << :parent parsed << :node path = path[2..-1] else parsed << :self parsed << :node path = path[1..-1] end else if path[0] == ?@ #puts "ATTRIBUTE" parsed << :attribute path = path[1..-1] # Goto Nodetest elsif path =~ AXIS parsed << $1.tr('-','_').intern path = $' # Goto Nodetest else parsed << :child end #puts "NODETESTING '#{path}'" n = [] path = NodeTest( path, n) #puts "NODETEST RETURNED '#{path}'" if path[0] == ?[ path = Predicate( path, n ) end parsed.concat(n) end if path.size > 0 if path[0] == ?/ if path[1] == ?/ parsed << :descendant_or_self parsed << :node path = path[2..-1] else path = path[1..-1] end else return path end end end return path end # Returns a 1-1 map of the nodeset # The contents of the resulting array are either: # true/false, if a positive match # String, if a name match #NodeTest # | ('*' | NCNAME ':' '*' | QNAME) NameTest # | NODE_TYPE '(' ')' NodeType # | PI '(' LITERAL ')' PI # | '[' expr ']' Predicate NCNAMETEST= /^(#{NCNAME_STR}):\*/u QNAME = Namespace::NAMESPLIT NODE_TYPE = /^(comment|text|node)\(\s*\)/m PI = /^processing-instruction\(/ def NodeTest path, parsed #puts "NodeTest with #{path}" res = nil case path when /^\*/ path = $' parsed << :any when NODE_TYPE type = $1 path = $' parsed << type.tr('-', '_').intern when PI path = $' literal = nil if path !~ /^\s*\)/ path =~ LITERAL literal = $1 path = $' raise ParseException.new("Missing ')' after processing instruction") if path[0] != ?) path = path[1..-1] end parsed << :processing_instruction parsed << (literal || '') when NCNAMETEST #puts "NCNAMETEST" prefix = $1 path = $' parsed << :namespace parsed << prefix when QNAME #puts "QNAME" prefix = $1 name = $2 path = $' prefix = "" unless prefix parsed << :qname parsed << prefix parsed << name end return path end # Filters the supplied nodeset on the predicate(s) def Predicate path, parsed #puts "PREDICATE with #{path}" return nil unless path[0] == ?[ predicates = [] while path[0] == ?[ path, expr = get_group(path) predicates << expr[1..-2] if expr end #puts "PREDICATES = #{predicates.inspect}" predicates.each{ |expr| #puts "ORING #{expr}" preds = [] parsed << :predicate parsed << preds OrExpr(expr, preds) } #puts "PREDICATES = #{predicates.inspect}" path end # The following return arrays of true/false, a 1-1 mapping of the # supplied nodeset, except for axe(), which returns a filtered # nodeset #| OrExpr S 'or' S AndExpr #| AndExpr def OrExpr path, parsed #puts "OR >>> #{path}" n = [] rest = AndExpr( path, n ) #puts "OR <<< #{rest}" if rest != path while rest =~ /^\s*( or )/ n = [ :or, n, [] ] rest = AndExpr( $', n[-1] ) end end if parsed.size == 0 and n.size != 0 parsed.replace(n) elsif n.size > 0 parsed << n end rest end #| AndExpr S 'and' S EqualityExpr #| EqualityExpr def AndExpr path, parsed #puts "AND >>> #{path}" n = [] rest = EqualityExpr( path, n ) #puts "AND <<< #{rest}" if rest != path while rest =~ /^\s*( and )/ n = [ :and, n, [] ] #puts "AND >>> #{rest}" rest = EqualityExpr( $', n[-1] ) #puts "AND <<< #{rest}" end end if parsed.size == 0 and n.size != 0 parsed.replace(n) elsif n.size > 0 parsed << n end rest end #| EqualityExpr ('=' | '!=') RelationalExpr #| RelationalExpr def EqualityExpr path, parsed #puts "EQUALITY >>> #{path}" n = [] rest = RelationalExpr( path, n ) #puts "EQUALITY <<< #{rest}" if rest != path while rest =~ /^\s*(!?=)\s*/ if $1[0] == ?! n = [ :neq, n, [] ] else n = [ :eq, n, [] ] end rest = RelationalExpr( $', n[-1] ) end end if parsed.size == 0 and n.size != 0 parsed.replace(n) elsif n.size > 0 parsed << n end rest end #| RelationalExpr ('<' | '>' | '<=' | '>=') AdditiveExpr #| AdditiveExpr def RelationalExpr path, parsed #puts "RELATION >>> #{path}" n = [] rest = AdditiveExpr( path, n ) #puts "RELATION <<< #{rest}" if rest != path while rest =~ /^\s*([<>]=?)\s*/ if $1[0] == ?< sym = "lt" else sym = "gt" end sym << "eq" if $1[-1] == ?= n = [ sym.intern, n, [] ] rest = AdditiveExpr( $', n[-1] ) end end if parsed.size == 0 and n.size != 0 parsed.replace(n) elsif n.size > 0 parsed << n end rest end #| AdditiveExpr ('+' | S '-') MultiplicativeExpr #| MultiplicativeExpr def AdditiveExpr path, parsed #puts "ADDITIVE >>> #{path}" n = [] rest = MultiplicativeExpr( path, n ) #puts "ADDITIVE <<< #{rest}" if rest != path while rest =~ /^\s*(\+| -)\s*/ if $1[0] == ?+ n = [ :plus, n, [] ] else n = [ :minus, n, [] ] end rest = MultiplicativeExpr( $', n[-1] ) end end if parsed.size == 0 and n.size != 0 parsed.replace(n) elsif n.size > 0 parsed << n end rest end #| MultiplicativeExpr ('*' | S ('div' | 'mod') S) UnaryExpr #| UnaryExpr def MultiplicativeExpr path, parsed #puts "MULT >>> #{path}" n = [] rest = UnaryExpr( path, n ) #puts "MULT <<< #{rest}" if rest != path while rest =~ /^\s*(\*| div | mod )\s*/ if $1[0] == ?* n = [ :mult, n, [] ] elsif $1.include?( "div" ) n = [ :div, n, [] ] else n = [ :mod, n, [] ] end rest = UnaryExpr( $', n[-1] ) end end if parsed.size == 0 and n.size != 0 parsed.replace(n) elsif n.size > 0 parsed << n end rest end #| '-' UnaryExpr #| UnionExpr def UnaryExpr path, parsed path =~ /^(\-*)/ path = $' if $1 and (($1.size % 2) != 0) mult = -1 else mult = 1 end parsed << :neg if mult < 0 #puts "UNARY >>> #{path}" n = [] path = UnionExpr( path, n ) #puts "UNARY <<< #{path}" parsed.concat( n ) path end #| UnionExpr '|' PathExpr #| PathExpr def UnionExpr path, parsed #puts "UNION >>> #{path}" n = [] rest = PathExpr( path, n ) #puts "UNION <<< #{rest}" if rest != path while rest =~ /^\s*(\|)\s*/ n = [ :union, n, [] ] rest = PathExpr( $', n[-1] ) end end if parsed.size == 0 and n.size != 0 parsed.replace( n ) elsif n.size > 0 parsed << n end rest end #| LocationPath #| FilterExpr ('/' | '//') RelativeLocationPath def PathExpr path, parsed path =~ /^\s*/ path = $' #puts "PATH >>> #{path}" n = [] rest = FilterExpr( path, n ) #puts "PATH <<< '#{rest}'" if rest != path if rest and rest[0] == ?/ return RelativeLocationPath(rest, n) end end #puts "BEFORE WITH '#{rest}'" rest = LocationPath(rest, n) if rest =~ /\A[\/\.\@\[\w_*]/ parsed.concat(n) return rest end #| FilterExpr Predicate #| PrimaryExpr def FilterExpr path, parsed #puts "FILTER >>> #{path}" n = [] path = PrimaryExpr( path, n ) #puts "FILTER <<< #{path}" path = Predicate(path, n) if path and path[0] == ?[ #puts "FILTER <<< #{path}" parsed.concat(n) path end #| VARIABLE_REFERENCE #| '(' expr ')' #| LITERAL #| NUMBER #| FunctionCall VARIABLE_REFERENCE = /^\$(#{NAME_STR})/u NUMBER = /^(\d*\.?\d+)/ NT = /^comment|text|processing-instruction|node$/ def PrimaryExpr path, parsed arry = [] case path when VARIABLE_REFERENCE varname = $1 path = $' parsed << :variable parsed << varname #arry << @variables[ varname ] when /^(\w[-\w]*)(?:\()/ #puts "PrimaryExpr :: Function >>> #$1 -- '#$''" fname = $1 tmp = $' #puts "#{fname} =~ #{NT.inspect}" return path if fname =~ NT path = tmp parsed << :function parsed << fname path = FunctionCall(path, parsed) when NUMBER #puts "LITERAL or NUMBER: #$1" varname = $1.nil? ? $2 : $1 path = $' parsed << :literal parsed << (varname.include?('.') ? varname.to_f : varname.to_i) when LITERAL #puts "LITERAL or NUMBER: #$1" varname = $1.nil? ? $2 : $1 path = $' parsed << :literal parsed << varname when /^\(/ #/ path, contents = get_group(path) contents = contents[1..-2] n = [] OrExpr( contents, n ) parsed.concat(n) end path end #| FUNCTION_NAME '(' ( expr ( ',' expr )* )? ')' def FunctionCall rest, parsed path, arguments = parse_args(rest) argset = [] for argument in arguments args = [] OrExpr( argument, args ) argset << args end parsed << argset path end # get_group( '[foo]bar' ) -> ['bar', '[foo]'] def get_group string ind = 0 depth = 0 st = string[0,1] en = (st == "(" ? ")" : "]") begin case string[ind,1] when st depth += 1 when en depth -= 1 end ind += 1 end while depth > 0 and ind < string.length return nil unless depth==0 [string[ind..-1], string[0..ind-1]] end def parse_args( string ) arguments = [] ind = 0 inquot = false inapos = false depth = 1 begin case string[ind] when ?" inquot = !inquot unless inapos when ?' inapos = !inapos unless inquot else unless inquot or inapos case string[ind] when ?( depth += 1 if depth == 1 string = string[1..-1] ind -= 1 end when ?) depth -= 1 if depth == 0 s = string[0,ind].strip arguments << s unless s == "" string = string[ind+1..-1] end when ?, if depth == 1 s = string[0,ind].strip arguments << s unless s == "" string = string[ind+1..-1] ind = -1 end end end end ind += 1 end while depth > 0 and ind < string.length return nil unless depth==0 [string,arguments] end end end end ================================================ FILE: lib/rexml/quickpath.rb ================================================ require 'rexml/functions' require 'rexml/xmltokens' module REXML class QuickPath include Functions include XMLTokens EMPTY_HASH = {} def QuickPath::first element, path, namespaces=EMPTY_HASH match(element, path, namespaces)[0] end def QuickPath::each element, path, namespaces=EMPTY_HASH, &block path = "*" unless path match(element, path, namespaces).each( &block ) end def QuickPath::match element, path, namespaces=EMPTY_HASH raise "nil is not a valid xpath" unless path results = nil Functions::namespace_context = namespaces case path when /^\/([^\/]|$)/u # match on root path = path[1..-1] return [element.root.parent] if path == '' results = filter([element.root], path) when /^[-\w]*::/u results = filter([element], path) when /^\*/u results = filter(element.to_a, path) when /^[\[!\w:]/u # match on child matches = [] children = element.to_a results = filter(children, path) else results = filter([element], path) end return results end # Given an array of nodes it filters the array based on the path. The # result is that when this method returns, the array will contain elements # which match the path def QuickPath::filter elements, path return elements if path.nil? or path == '' or elements.size == 0 case path when /^\/\//u # Descendant return axe( elements, "descendant-or-self", $' ) when /^\/?\b(\w[-\w]*)\b::/u # Axe axe_name = $1 rest = $' return axe( elements, $1, $' ) when /^\/(?=\b([:!\w][-\.\w]*:)?[-!\*\.\w]*\b([^:(]|$)|\*)/u # Child rest = $' results = [] elements.each do |element| results |= filter( element.to_a, rest ) end return results when /^\/?(\w[-\w]*)\(/u # / Function return function( elements, $1, $' ) when Namespace::NAMESPLIT # Element name name = $2 ns = $1 rest = $' elements.delete_if do |element| !(element.kind_of? Element and (element.expanded_name == name or (element.name == name and element.namespace == Functions.namespace_context[ns]))) end return filter( elements, rest ) when /^\/\[/u matches = [] elements.each do |element| matches |= predicate( element.to_a, path[1..-1] ) if element.kind_of? Element end return matches when /^\[/u # Predicate return predicate( elements, path ) when /^\/?\.\.\./u # Ancestor return axe( elements, "ancestor", $' ) when /^\/?\.\./u # Parent return filter( elements.collect{|e|e.parent}, $' ) when /^\/?\./u # Self return filter( elements, $' ) when /^\*/u # Any results = [] elements.each do |element| results |= filter( [element], $' ) if element.kind_of? Element #if element.kind_of? Element # children = element.to_a # children.delete_if { |child| !child.kind_of?(Element) } # results |= filter( children, $' ) #end end return results end return [] end def QuickPath::axe( elements, axe_name, rest ) matches = [] matches = filter( elements.dup, rest ) if axe_name =~ /-or-self$/u case axe_name when /^descendant/u elements.each do |element| matches |= filter( element.to_a, "descendant-or-self::#{rest}" ) if element.kind_of? Element end when /^ancestor/u elements.each do |element| while element.parent matches << element.parent element = element.parent end end matches = filter( matches, rest ) when "self" matches = filter( elements, rest ) when "child" elements.each do |element| matches |= filter( element.to_a, rest ) if element.kind_of? Element end when "attribute" elements.each do |element| matches << element.attributes[ rest ] if element.kind_of? Element end when "parent" matches = filter(elements.collect{|element| element.parent}.uniq, rest) when "following-sibling" matches = filter(elements.collect{|element| element.next_sibling}.uniq, rest) when "previous-sibling" matches = filter(elements.collect{|element| element.previous_sibling}.uniq, rest ) end return matches.uniq end # A predicate filters a node-set with respect to an axis to produce a # new node-set. For each node in the node-set to be filtered, the # PredicateExpr is evaluated with that node as the context node, with # the number of nodes in the node-set as the context size, and with the # proximity position of the node in the node-set with respect to the # axis as the context position; if PredicateExpr evaluates to true for # that node, the node is included in the new node-set; otherwise, it is # not included. # # A PredicateExpr is evaluated by evaluating the Expr and converting # the result to a boolean. If the result is a number, the result will # be converted to true if the number is equal to the context position # and will be converted to false otherwise; if the result is not a # number, then the result will be converted as if by a call to the # boolean function. Thus a location path para[3] is equivalent to # para[position()=3]. def QuickPath::predicate( elements, path ) ind = 1 bcount = 1 while bcount > 0 bcount += 1 if path[ind] == ?[ bcount -= 1 if path[ind] == ?] ind += 1 end ind -= 1 predicate = path[1..ind-1] rest = path[ind+1..-1] # have to change 'a [=<>] b [=<>] c' into 'a [=<>] b and b [=<>] c' predicate.gsub!( /([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)/u ) { "#$1 #$2 #$3 and #$3 #$4 #$5" } # Let's do some Ruby trickery to avoid some work: predicate.gsub!( /&/u, "&&" ) predicate.gsub!( /=/u, "==" ) predicate.gsub!( /@(\w[-\w.]*)/u ) { "attribute(\"#$1\")" } predicate.gsub!( /\bmod\b/u, "%" ) predicate.gsub!( /\b(\w[-\w.]*\()/u ) { fname = $1 fname.gsub( /-/u, "_" ) } Functions.pair = [ 0, elements.size ] results = [] elements.each do |element| Functions.pair[0] += 1 Functions.node = element res = eval( predicate ) case res when true results << element when Fixnum results << element if Functions.pair[0] == res when String results << element end end return filter( results, rest ) end def QuickPath::attribute( name ) return Functions.node.attributes[name] if Functions.node.kind_of? Element end def QuickPath::name() return Functions.node.name if Functions.node.kind_of? Element end def QuickPath::method_missing( id, *args ) begin Functions.send( id.id2name, *args ) rescue Exception raise "METHOD: #{id.id2name}(#{args.join ', '})\n#{$!.message}" end end def QuickPath::function( elements, fname, rest ) args = parse_args( elements, rest ) Functions.pair = [0, elements.size] results = [] elements.each do |element| Functions.pair[0] += 1 Functions.node = element res = Functions.send( fname, *args ) case res when true results << element when Fixnum results << element if Functions.pair[0] == res end end return results end def QuickPath::parse_args( element, string ) # /.*?(?:\)|,)/ arguments = [] buffer = "" while string and string != "" c = string[0] string.sub!(/^./u, "") case c when ?, # if depth = 1, then we start a new argument arguments << evaluate( buffer ) #arguments << evaluate( string[0..count] ) when ?( # start a new method call function( element, buffer, string ) buffer = "" when ?) # close the method call and return arguments return arguments else buffer << c end end "" end end end ================================================ FILE: lib/rexml/rexml.rb ================================================ # -*- encoding: utf-8 -*- # REXML is an XML toolkit for Ruby[http://www.ruby-lang.org], in Ruby. # # REXML is a _pure_ Ruby, XML 1.0 conforming, # non-validating[http://www.w3.org/TR/2004/REC-xml-20040204/#sec-conformance] # toolkit with an intuitive API. REXML passes 100% of the non-validating Oasis # tests[http://www.oasis-open.org/committees/xml-conformance/xml-test-suite.shtml], # and provides tree, stream, SAX2, pull, and lightweight APIs. REXML also # includes a full XPath[http://www.w3c.org/tr/xpath] 1.0 implementation. Since # Ruby 1.8, REXML is included in the standard Ruby distribution. # # Main page:: http://www.germane-software.com/software/rexml # Author:: Sean Russell # Version:: 3.1.7.2 # Date:: 2007/275 # Revision:: $Revision$ # # This API documentation can be downloaded from the REXML home page, or can # be accessed online[http://www.germane-software.com/software/rexml_doc] # # A tutorial is available in the REXML distribution in docs/tutorial.html, # or can be accessed # online[http://www.germane-software.com/software/rexml/docs/tutorial.html] module REXML COPYRIGHT = "Copyright \xC2\xA9 2001-2006 Sean Russell " VERSION = "3.1.7.3" DATE = "2007/275" REVISION = "$Revision$".gsub(/\$Revision:|\$/,'').strip Copyright = COPYRIGHT Version = VERSION end ================================================ FILE: lib/rexml/sax2listener.rb ================================================ module REXML # A template for stream parser listeners. # Note that the declarations (attlistdecl, elementdecl, etc) are trivially # processed; REXML doesn't yet handle doctype entity declarations, so you # have to parse them out yourself. # === Missing methods from SAX2 # ignorable_whitespace # === Methods extending SAX2 # +WARNING+ # These methods are certainly going to change, until DTDs are fully # supported. Be aware of this. # start_document # end_document # doctype # elementdecl # attlistdecl # entitydecl # notationdecl # cdata # xmldecl # comment module SAX2Listener def start_document end def end_document end def start_prefix_mapping prefix, uri end def end_prefix_mapping prefix end def start_element uri, localname, qname, attributes end def end_element uri, localname, qname end def characters text end def processing_instruction target, data end # Handles a doctype declaration. Any attributes of the doctype which are # not supplied will be nil. # EG, # @p name the name of the doctype; EG, "me" # @p pub_sys "PUBLIC", "SYSTEM", or nil. EG, "PUBLIC" # @p long_name the supplied long name, or nil. EG, "foo" # @p uri the uri of the doctype, or nil. EG, "bar" def doctype name, pub_sys, long_name, uri end # If a doctype includes an ATTLIST declaration, it will cause this # method to be called. The content is the declaration itself, unparsed. # EG, will come to this method as "el # attr CDATA #REQUIRED". This is the same for all of the .*decl # methods. def attlistdecl(element, pairs, contents) end # def elementdecl content end # # The argument passed to this method is an array of the entity # declaration. It can be in a number of formats, but in general it # returns (example, result): # # ["%", "YN", "'\"Yes\"'", "\""] # # ["%", "YN", "'Yes'", "s"] # # ["WhatHeSaid", "\"He said %YN;\"", "YN"] # # ["open-hatch", "SYSTEM", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""] # # ["open-hatch", "PUBLIC", "\"-//Textuality//TEXT Standard open-hatch boilerplate//EN\"", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""] # # ["hatch-pic", "SYSTEM", "\"../grafix/OpenHatch.gif\"", "\n\t\t\t\t\t\t\tNDATA gif", "gif"] def entitydecl name, decl end # def notationdecl content end # Called when is encountered in a document. # @p content "..." def cdata content end # Called when an XML PI is encountered in the document. # EG: # @p version the version attribute value. EG, "1.0" # @p encoding the encoding attribute value, or nil. EG, "utf" # @p standalone the standalone attribute value, or nil. EG, nil # @p spaced the declaration is followed by a line break def xmldecl version, encoding, standalone end # Called when a comment is encountered. # @p comment The content of the comment def comment comment end def progress position end end end ================================================ FILE: lib/rexml/source.rb ================================================ require 'rexml/encoding' module REXML # Generates Source-s. USE THIS CLASS. class SourceFactory # Generates a Source object # @param arg Either a String, or an IO # @return a Source, or nil if a bad argument was given def SourceFactory::create_from(arg) if arg.kind_of? String Source.new(arg) elsif arg.respond_to? :read and arg.respond_to? :readline and arg.respond_to? :nil? and arg.respond_to? :eof? IOSource.new(arg) elsif arg.kind_of? Source arg else raise "#{arg.class} is not a valid input stream. It must walk \n"+ "like either a String, an IO, or a Source." end end end # A Source can be searched for patterns, and wraps buffers and other # objects and provides consumption of text class Source include Encoding # The current buffer (what we're going to read next) attr_reader :buffer # The line number of the last consumed text attr_reader :line attr_reader :encoding # Constructor # @param arg must be a String, and should be a valid XML document # @param encoding if non-null, sets the encoding of the source to this # value, overriding all encoding detection def initialize(arg, encoding=nil) @orig = @buffer = arg if encoding self.encoding = encoding else self.encoding = check_encoding( @buffer ) end @line = 0 end # Inherited from Encoding # Overridden to support optimized en/decoding def encoding=(enc) return unless super @line_break = encode( '>' ) if enc != UTF_8 @buffer = decode(@buffer) @to_utf = true else @to_utf = false end end # Scans the source for a given pattern. Note, that this is not your # usual scan() method. For one thing, the pattern argument has some # requirements; for another, the source can be consumed. You can easily # confuse this method. Originally, the patterns were easier # to construct and this method more robust, because this method # generated search regexes on the fly; however, this was # computationally expensive and slowed down the entire REXML package # considerably, since this is by far the most commonly called method. # @param pattern must be a Regexp, and must be in the form of # /^\s*(#{your pattern, with no groups})(.*)/. The first group # will be returned; the second group is used if the consume flag is # set. # @param consume if true, the pattern returned will be consumed, leaving # everything after it in the Source. # @return the pattern, if found, or nil if the Source is empty or the # pattern is not found. def scan(pattern, cons=false) return nil if @buffer.nil? rv = @buffer.scan(pattern) @buffer = $' if cons and rv.size>0 rv end def read end def consume( pattern ) @buffer = $' if pattern.match( @buffer ) end def match_to( char, pattern ) return pattern.match(@buffer) end def match_to_consume( char, pattern ) md = pattern.match(@buffer) @buffer = $' return md end def match(pattern, cons=false) md = pattern.match(@buffer) @buffer = $' if cons and md return md end # @return true if the Source is exhausted def empty? @buffer == "" end def position @orig.index( @buffer ) end # @return the current line in the source def current_line lines = @orig.split res = lines.grep @buffer[0..30] res = res[-1] if res.kind_of? Array lines.index( res ) if res end end # A Source that wraps an IO. See the Source class for method # documentation class IOSource < Source #attr_reader :block_size # block_size has been deprecated def initialize(arg, block_size=500, encoding=nil) @er_source = @source = arg @to_utf = false # Determining the encoding is a deceptively difficult issue to resolve. # First, we check the first two bytes for UTF-16. Then we # assume that the encoding is at least ASCII enough for the '>', and # we read until we get one of those. This gives us the XML declaration, # if there is one. If there isn't one, the file MUST be UTF-8, as per # the XML spec. If there is one, we can determine the encoding from # it. @buffer = "" str = @source.read( 2 ) if encoding self.encoding = encoding elsif 0xfe == str[0] && 0xff == str[1] @line_break = "\000>" elsif 0xff == str[0] && 0xfe == str[1] @line_break = ">\000" elsif 0xef == str[0] && 0xbb == str[1] str += @source.read(1) str = '' if (0xbf == str[2]) @line_break = ">" else @line_break = ">" end super str+@source.readline( @line_break ) end def scan(pattern, cons=false) rv = super # You'll notice that this next section is very similar to the same # section in match(), but just a liiittle different. This is # because it is a touch faster to do it this way with scan() # than the way match() does it; enough faster to warrent duplicating # some code if rv.size == 0 until @buffer =~ pattern or @source.nil? begin # READLINE OPT #str = @source.read(@block_size) str = @source.readline(@line_break) str = decode(str) if @to_utf and str @buffer << str rescue Iconv::IllegalSequence raise rescue @source = nil end end rv = super end rv.taint rv end def read begin str = @source.readline(@line_break) str = decode(str) if @to_utf and str @buffer << str rescue Exception, NameError @source = nil end end def consume( pattern ) match( pattern, true ) end def match( pattern, cons=false ) rv = pattern.match(@buffer) @buffer = $' if cons and rv while !rv and @source begin str = @source.readline(@line_break) str = decode(str) if @to_utf and str @buffer << str rv = pattern.match(@buffer) @buffer = $' if cons and rv rescue @source = nil end end rv.taint rv end def empty? super and ( @source.nil? || @source.eof? ) end def position @er_source.stat.pipe? ? 0 : @er_source.pos end # @return the current line in the source def current_line begin pos = @er_source.pos # The byte position in the source lineno = @er_source.lineno # The XML < position in the source @er_source.rewind line = 0 # The \r\n position in the source begin while @er_source.pos < pos @er_source.readline line += 1 end rescue end rescue IOError pos = -1 line = -1 end [pos, lineno, line] end end end ================================================ FILE: lib/rexml/streamlistener.rb ================================================ module REXML # A template for stream parser listeners. # Note that the declarations (attlistdecl, elementdecl, etc) are trivially # processed; REXML doesn't yet handle doctype entity declarations, so you # have to parse them out yourself. module StreamListener # Called when a tag is encountered. # @p name the tag name # @p attrs an array of arrays of attribute/value pairs, suitable for # use with assoc or rassoc. IE, # will result in # tag_start( "tag", # [["attr1","value1"],["attr2","value2"]]) def tag_start name, attrs end # Called when the end tag is reached. In the case of , tag_end # will be called immidiately after tag_start # @p the name of the tag def tag_end name end # Called when text is encountered in the document # @p text the text content. def text text end # Called when an instruction is encountered. EG: # @p name the instruction name; in the example, "xsl" # @p instruction the rest of the instruction. In the example, # "sheet='foo'" def instruction name, instruction end # Called when a comment is encountered. # @p comment The content of the comment def comment comment end # Handles a doctype declaration. Any attributes of the doctype which are # not supplied will be nil. # EG, # @p name the name of the doctype; EG, "me" # @p pub_sys "PUBLIC", "SYSTEM", or nil. EG, "PUBLIC" # @p long_name the supplied long name, or nil. EG, "foo" # @p uri the uri of the doctype, or nil. EG, "bar" def doctype name, pub_sys, long_name, uri end # Called when the doctype is done def doctype_end end # If a doctype includes an ATTLIST declaration, it will cause this # method to be called. The content is the declaration itself, unparsed. # EG, will come to this method as "el # attr CDATA #REQUIRED". This is the same for all of the .*decl # methods. def attlistdecl element_name, attributes, raw_content end # def elementdecl content end # # The argument passed to this method is an array of the entity # declaration. It can be in a number of formats, but in general it # returns (example, result): # # ["%", "YN", "'\"Yes\"'", "\""] # # ["%", "YN", "'Yes'", "s"] # # ["WhatHeSaid", "\"He said %YN;\"", "YN"] # # ["open-hatch", "SYSTEM", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""] # # ["open-hatch", "PUBLIC", "\"-//Textuality//TEXT Standard open-hatch boilerplate//EN\"", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""] # # ["hatch-pic", "SYSTEM", "\"../grafix/OpenHatch.gif\"", "\n\t\t\t\t\t\t\tNDATA gif", "gif"] def entitydecl content end # def notationdecl content end # Called when %foo; is encountered in a doctype declaration. # @p content "foo" def entity content end # Called when is encountered in a document. # @p content "..." def cdata content end # Called when an XML PI is encountered in the document. # EG: # @p version the version attribute value. EG, "1.0" # @p encoding the encoding attribute value, or nil. EG, "utf" # @p standalone the standalone attribute value, or nil. EG, nil def xmldecl version, encoding, standalone end end end ================================================ FILE: lib/rexml/syncenumerator.rb ================================================ module REXML class SyncEnumerator include Enumerable # Creates a new SyncEnumerator which enumerates rows of given # Enumerable objects. def initialize(*enums) @gens = enums @biggest = @gens[0] @gens.each {|x| @biggest = x if x.size > @biggest.size } end # Returns the number of enumerated Enumerable objects, i.e. the size # of each row. def size @gens.size end # Returns the number of enumerated Enumerable objects, i.e. the size # of each row. def length @gens.length end # Enumerates rows of the Enumerable objects. def each @biggest.zip( *@gens ) {|a| yield(*a[1..-1]) } self end end end ================================================ FILE: lib/rexml/text.rb ================================================ require 'rexml/entity' require 'rexml/doctype' require 'rexml/child' require 'rexml/doctype' require 'rexml/parseexception' module REXML # Represents text nodes in an XML document class Text < Child include Comparable # The order in which the substitutions occur SPECIALS = [ /&(?!#?[\w-]+;)/u, //u, /"/u, /'/u, /\r/u ] SUBSTITUTES = ['&', '<', '>', '"', ''', ' '] # Characters which are substituted in written strings SLAICEPS = [ '<', '>', '"', "'", '&' ] SETUTITSBUS = [ /</u, />/u, /"/u, /'/u, /&/u ] # If +raw+ is true, then REXML leaves the value alone attr_accessor :raw ILLEGAL = /(<|&(?!(#{Entity::NAME})|(#0*((?:\d+)|(?:x[a-fA-F0-9]+)));))/um NUMERICENTITY = /�*((?:\d+)|(?:x[a-fA-F0-9]+));/ # Constructor # +arg+ if a String, the content is set to the String. If a Text, # the object is shallowly cloned. # # +respect_whitespace+ (boolean, false) if true, whitespace is # respected # # +parent+ (nil) if this is a Parent object, the parent # will be set to this. # # +raw+ (nil) This argument can be given three values. # If true, then the value of used to construct this object is expected to # contain no unescaped XML markup, and REXML will not change the text. If # this value is false, the string may contain any characters, and REXML will # escape any and all defined entities whose values are contained in the # text. If this value is nil (the default), then the raw value of the # parent will be used as the raw value for this node. If there is no raw # value for the parent, and no value is supplied, the default is false. # Use this field if you have entities defined for some text, and you don't # want REXML to escape that text in output. # Text.new( "<&", false, nil, false ) #-> "<&" # Text.new( "<&", false, nil, false ) #-> "&lt;&amp;" # Text.new( "<&", false, nil, true ) #-> Parse exception # Text.new( "<&", false, nil, true ) #-> "<&" # # Assume that the entity "s" is defined to be "sean" # # and that the entity "r" is defined to be "russell" # Text.new( "sean russell" ) #-> "&s; &r;" # Text.new( "sean russell", false, nil, true ) #-> "sean russell" # # +entity_filter+ (nil) This can be an array of entities to match in the # supplied text. This argument is only useful if +raw+ is set to false. # Text.new( "sean russell", false, nil, false, ["s"] ) #-> "&s; russell" # Text.new( "sean russell", false, nil, true, ["s"] ) #-> "sean russell" # In the last example, the +entity_filter+ argument is ignored. # # +pattern+ INTERNAL USE ONLY def initialize(arg, respect_whitespace=false, parent=nil, raw=nil, entity_filter=nil, illegal=ILLEGAL ) @raw = false if parent super( parent ) @raw = parent.raw else @parent = nil end @raw = raw unless raw.nil? @entity_filter = entity_filter @normalized = @unnormalized = nil if arg.kind_of? String @string = arg.clone @string.squeeze!(" \n\t") unless respect_whitespace elsif arg.kind_of? Text @string = arg.to_s @raw = arg.raw elsif raise "Illegal argument of type #{arg.type} for Text constructor (#{arg})" end @string.gsub!( /\r\n?/, "\n" ) # check for illegal characters if @raw if @string =~ illegal raise "Illegal character '#{$1}' in raw string \"#{@string}\"" end end end def node_type :text end def empty? @string.size==0 end def clone return Text.new(self) end # Appends text to this text node. The text is appended in the +raw+ mode # of this text node. def <<( to_append ) @string << to_append.gsub( /\r\n?/, "\n" ) end # +other+ a String or a Text # +returns+ the result of (to_s <=> arg.to_s) def <=>( other ) to_s() <=> other.to_s end REFERENCE = /#{Entity::REFERENCE}/ # Returns the string value of this text node. This string is always # escaped, meaning that it is a valid XML text node string, and all # entities that can be escaped, have been inserted. This method respects # the entity filter set in the constructor. # # # Assume that the entity "s" is defined to be "sean", and that the # # entity "r" is defined to be "russell" # t = Text.new( "< & sean russell", false, nil, false, ['s'] ) # t.to_s #-> "< & &s; russell" # t = Text.new( "< & &s; russell", false, nil, false ) # t.to_s #-> "< & &s; russell" # u = Text.new( "sean russell", false, nil, true ) # u.to_s #-> "sean russell" def to_s return @string if @raw return @normalized if @normalized doctype = nil if @parent doc = @parent.document doctype = doc.doctype if doc end @normalized = Text::normalize( @string, doctype, @entity_filter ) end def inspect @string.inspect end # Returns the string value of this text. This is the text without # entities, as it might be used programmatically, or printed to the # console. This ignores the 'raw' attribute setting, and any # entity_filter. # # # Assume that the entity "s" is defined to be "sean", and that the # # entity "r" is defined to be "russell" # t = Text.new( "< & sean russell", false, nil, false, ['s'] ) # t.value #-> "< & sean russell" # t = Text.new( "< & &s; russell", false, nil, false ) # t.value #-> "< & sean russell" # u = Text.new( "sean russell", false, nil, true ) # u.value #-> "sean russell" def value return @unnormalized if @unnormalized doctype = nil if @parent doc = @parent.document doctype = doc.doctype if doc end @unnormalized = Text::unnormalize( @string, doctype ) end # Sets the contents of this text node. This expects the text to be # unnormalized. It returns self. # # e = Element.new( "a" ) # e.add_text( "foo" ) # foo # e[0].value = "bar" # bar # e[0].value = "" # <a> def value=( val ) @string = val.gsub( /\r\n?/, "\n" ) @unnormalized = nil @normalized = nil @raw = false end def wrap(string, width, addnewline=false) # Recursively wrap string at width. return string if string.length <= width place = string.rindex(' ', width) # Position in string with last ' ' before cutoff if addnewline then return "\n" + string[0,place] + "\n" + wrap(string[place+1..-1], width) else return string[0,place] + "\n" + wrap(string[place+1..-1], width) end end def indent_text(string, level=1, style="\t", indentfirstline=true) return string if level < 0 new_string = '' string.each { |line| indent_string = style * level new_line = (indent_string + line).sub(/[\s]+$/,'') new_string << new_line } new_string.strip! unless indentfirstline return new_string end # == DEPRECATED # See REXML::Formatters # def write( writer, indent=-1, transitive=false, ie_hack=false ) Kernel.warn("#{self.class.name}.write is deprecated. See REXML::Formatters") formatter = if indent > -1 REXML::Formatters::Pretty.new( indent ) else REXML::Formatters::Default.new end formatter.write( self, writer ) end # FIXME # This probably won't work properly def xpath path = @parent.xpath path += "/text()" return path end # Writes out text, substituting special characters beforehand. # +out+ A String, IO, or any other object supporting <<( String ) # +input+ the text to substitute and the write out # # z=utf8.unpack("U*") # ascOut="" # z.each{|r| # if r < 0x100 # ascOut.concat(r.chr) # else # ascOut.concat(sprintf("&#x%x;", r)) # end # } # puts ascOut def write_with_substitution out, input copy = input.clone # Doing it like this rather than in a loop improves the speed copy.gsub!( SPECIALS[0], SUBSTITUTES[0] ) copy.gsub!( SPECIALS[1], SUBSTITUTES[1] ) copy.gsub!( SPECIALS[2], SUBSTITUTES[2] ) copy.gsub!( SPECIALS[3], SUBSTITUTES[3] ) copy.gsub!( SPECIALS[4], SUBSTITUTES[4] ) copy.gsub!( SPECIALS[5], SUBSTITUTES[5] ) out << copy end # Reads text, substituting entities def Text::read_with_substitution( input, illegal=nil ) copy = input.clone if copy =~ illegal raise ParseException.new( "malformed text: Illegal character #$& in \"#{copy}\"" ) end if illegal copy.gsub!( /\r\n?/, "\n" ) if copy.include? ?& copy.gsub!( SETUTITSBUS[0], SLAICEPS[0] ) copy.gsub!( SETUTITSBUS[1], SLAICEPS[1] ) copy.gsub!( SETUTITSBUS[2], SLAICEPS[2] ) copy.gsub!( SETUTITSBUS[3], SLAICEPS[3] ) copy.gsub!( SETUTITSBUS[4], SLAICEPS[4] ) copy.gsub!( /�*((?:\d+)|(?:x[a-f0-9]+));/ ) {|m| m=$1 #m='0' if m=='' m = "0#{m}" if m[0] == ?x [Integer(m)].pack('U*') } end copy end EREFERENCE = /&(?!#{Entity::NAME};)/ # Escapes all possible entities def Text::normalize( input, doctype=nil, entity_filter=nil ) copy = input.to_s # Doing it like this rather than in a loop improves the speed #copy = copy.gsub( EREFERENCE, '&' ) copy = copy.gsub( "&", "&" ) if doctype # Replace all ampersands that aren't part of an entity doctype.entities.each_value do |entity| copy = copy.gsub( entity.value, "&#{entity.name};" ) if entity.value and not( entity_filter and entity_filter.include?(entity) ) end else # Replace all ampersands that aren't part of an entity DocType::DEFAULT_ENTITIES.each_value do |entity| copy = copy.gsub(entity.value, "&#{entity.name};" ) end end copy end # Unescapes all possible entities def Text::unnormalize( string, doctype=nil, filter=nil, illegal=nil ) rv = string.clone rv.gsub!( /\r\n?/, "\n" ) matches = rv.scan( REFERENCE ) return rv if matches.size == 0 rv.gsub!( NUMERICENTITY ) {|m| m=$1 m = "0#{m}" if m[0] == ?x [Integer(m)].pack('U*') } matches.collect!{|x|x[0]}.compact! if matches.size > 0 if doctype matches.each do |entity_reference| unless filter and filter.include?(entity_reference) entity_value = doctype.entity( entity_reference ) re = /&#{entity_reference};/ rv.gsub!( re, entity_value ) if entity_value end end else matches.each do |entity_reference| unless filter and filter.include?(entity_reference) entity_value = DocType::DEFAULT_ENTITIES[ entity_reference ] re = /&#{entity_reference};/ rv.gsub!( re, entity_value.value ) if entity_value end end end rv.gsub!( /&/, '&' ) end rv end end end ================================================ FILE: lib/rexml/undefinednamespaceexception.rb ================================================ require 'rexml/parseexception' module REXML class UndefinedNamespaceException < ParseException def initialize( prefix, source, parser ) super( "Undefined prefix #{prefix} found" ) end end end ================================================ FILE: lib/rexml/validation/relaxng.rb ================================================ require "rexml/validation/validation" require "rexml/parsers/baseparser" module REXML module Validation # Implemented: # * empty # * element # * attribute # * text # * optional # * choice # * oneOrMore # * zeroOrMore # * group # * value # * interleave # * mixed # * ref # * grammar # * start # * define # # Not implemented: # * data # * param # * include # * externalRef # * notAllowed # * anyName # * nsName # * except # * name class RelaxNG include Validator INFINITY = 1.0 / 0.0 EMPTY = Event.new( nil ) TEXT = [:start_element, "text"] attr_accessor :current attr_accessor :count attr_reader :references # FIXME: Namespaces def initialize source parser = REXML::Parsers::BaseParser.new( source ) @count = 0 @references = {} @root = @current = Sequence.new(self) @root.previous = true states = [ @current ] begin event = parser.pull case event[0] when :start_element case event[1] when "empty" when "element", "attribute", "text", "value" states[-1] << event when "optional" states << Optional.new( self ) states[-2] << states[-1] when "choice" states << Choice.new( self ) states[-2] << states[-1] when "oneOrMore" states << OneOrMore.new( self ) states[-2] << states[-1] when "zeroOrMore" states << ZeroOrMore.new( self ) states[-2] << states[-1] when "group" states << Sequence.new( self ) states[-2] << states[-1] when "interleave" states << Interleave.new( self ) states[-2] << states[-1] when "mixed" states << Interleave.new( self ) states[-2] << states[-1] states[-1] << TEXT when "define" states << [ event[2]["name"] ] when "ref" states[-1] << Ref.new( event[2]["name"] ) when "anyName" states << AnyName.new( self ) states[-2] << states[-1] when "nsName" when "except" when "name" when "data" when "param" when "include" when "grammar" when "start" when "externalRef" when "notAllowed" end when :end_element case event[1] when "element", "attribute" states[-1] << event when "zeroOrMore", "oneOrMore", "choice", "optional", "interleave", "group", "mixed" states.pop when "define" ref = states.pop @references[ ref.shift ] = ref #when "empty" end when :end_document states[-1] << event when :text states[-1] << event end end while event[0] != :end_document end def receive event validate( event ) end end class State def initialize( context ) @previous = [] @events = [] @current = 0 @count = context.count += 1 @references = context.references @value = false end def reset return if @current == 0 @current = 0 @events.each {|s| s.reset if s.kind_of? State } end def previous=( previous ) @previous << previous end def next( event ) #print "In next with #{event.inspect}. " #puts "Next (#@current) is #{@events[@current]}" #p @previous return @previous.pop.next( event ) if @events[@current].nil? expand_ref_in( @events, @current ) if @events[@current].class == Ref if ( @events[@current].kind_of? State ) @current += 1 @events[@current-1].previous = self return @events[@current-1].next( event ) end #puts "Current isn't a state" if ( @events[@current].matches?(event) ) @current += 1 if @events[@current].nil? #puts "#{inspect[0,5]} 1RETURNING #{@previous.inspect[0,5]}" return @previous.pop elsif @events[@current].kind_of? State @current += 1 #puts "#{inspect[0,5]} 2RETURNING (#{@current-1}) #{@events[@current-1].inspect[0,5]}; on return, next is #{@events[@current]}" @events[@current-1].previous = self return @events[@current-1] else #puts "#{inspect[0,5]} RETURNING self w/ next(#@current) = #{@events[@current]}" return self end else return nil end end def to_s # Abbreviated: self.class.name =~ /(?:::)(\w)\w+$/ # Full: #self.class.name =~ /(?:::)(\w+)$/ "#$1.#@count" end def inspect "< #{to_s} #{@events.collect{|e| pre = e == @events[@current] ? '#' : '' pre + e.inspect unless self == e }.join(', ')} >" end def expected return [@events[@current]] end def <<( event ) add_event_to_arry( @events, event ) end protected def expand_ref_in( arry, ind ) new_events = [] @references[ arry[ind].to_s ].each{ |evt| add_event_to_arry(new_events,evt) } arry[ind,1] = new_events end def add_event_to_arry( arry, evt ) evt = generate_event( evt ) if evt.kind_of? String arry[-1].event_arg = evt if arry[-1].kind_of? Event and @value @value = false else arry << evt end end def generate_event( event ) return event if event.kind_of? State or event.class == Ref evt = nil arg = nil case event[0] when :start_element case event[1] when "element" evt = :start_element arg = event[2]["name"] when "attribute" evt = :start_attribute arg = event[2]["name"] when "text" evt = :text when "value" evt = :text @value = true end when :text return event[1] when :end_document return Event.new( event[0] ) else # then :end_element case event[1] when "element" evt = :end_element when "attribute" evt = :end_attribute end end return Event.new( evt, arg ) end end class Sequence < State def matches?(event) @events[@current].matches?( event ) end end class Optional < State def next( event ) if @current == 0 rv = super return rv if rv @prior = @previous.pop return @prior.next( event ) end super end def matches?(event) @events[@current].matches?(event) || (@current == 0 and @previous[-1].matches?(event)) end def expected return [ @prior.expected, @events[0] ].flatten if @current == 0 return [@events[@current]] end end class ZeroOrMore < Optional def next( event ) expand_ref_in( @events, @current ) if @events[@current].class == Ref if ( @events[@current].matches?(event) ) @current += 1 if @events[@current].nil? @current = 0 return self elsif @events[@current].kind_of? State @current += 1 @events[@current-1].previous = self return @events[@current-1] else return self end else @prior = @previous.pop return @prior.next( event ) if @current == 0 return nil end end def expected return [ @prior.expected, @events[0] ].flatten if @current == 0 return [@events[@current]] end end class OneOrMore < State def initialize context super @ord = 0 end def reset super @ord = 0 end def next( event ) expand_ref_in( @events, @current ) if @events[@current].class == Ref if ( @events[@current].matches?(event) ) @current += 1 @ord += 1 if @events[@current].nil? @current = 0 return self elsif @events[@current].kind_of? State @current += 1 @events[@current-1].previous = self return @events[@current-1] else return self end else return @previous.pop.next( event ) if @current == 0 and @ord > 0 return nil end end def matches?( event ) @events[@current].matches?(event) || (@current == 0 and @ord > 0 and @previous[-1].matches?(event)) end def expected if @current == 0 and @ord > 0 return [@previous[-1].expected, @events[0]].flatten else return [@events[@current]] end end end class Choice < State def initialize context super @choices = [] end def reset super @events = [] @choices.each { |c| c.each { |s| s.reset if s.kind_of? State } } end def <<( event ) add_event_to_arry( @choices, event ) end def next( event ) # Make the choice if we haven't if @events.size == 0 c = 0 ; max = @choices.size while c < max if @choices[c][0].class == Ref expand_ref_in( @choices[c], 0 ) @choices += @choices[c] @choices.delete( @choices[c] ) max -= 1 else c += 1 end end @events = @choices.find { |evt| evt[0].matches? event } # Remove the references # Find the events end #puts "In next with #{event.inspect}." #puts "events is #{@events.inspect}" unless @events @events = [] return nil end #puts "current = #@current" super end def matches?( event ) return @events[@current].matches?( event ) if @events.size > 0 !@choices.find{|evt| evt[0].matches?(event)}.nil? end def expected #puts "IN CHOICE EXPECTED" #puts "EVENTS = #{@events.inspect}" return [@events[@current]] if @events.size > 0 return @choices.collect do |x| if x[0].kind_of? State x[0].expected else x[0] end end.flatten end def inspect "< #{to_s} #{@choices.collect{|e| e.collect{|f|f.to_s}.join(', ')}.join(' or ')} >" end protected def add_event_to_arry( arry, evt ) if evt.kind_of? State or evt.class == Ref arry << [evt] elsif evt[0] == :text if arry[-1] and arry[-1][-1].kind_of?( Event ) and arry[-1][-1].event_type == :text and @value arry[-1][-1].event_arg = evt[1] @value = false end else arry << [] if evt[0] == :start_element arry[-1] << generate_event( evt ) end end end class Interleave < Choice def initialize context super @choice = 0 end def reset @choice = 0 end def next_current( event ) # Expand references c = 0 ; max = @choices.size while c < max if @choices[c][0].class == Ref expand_ref_in( @choices[c], 0 ) @choices += @choices[c] @choices.delete( @choices[c] ) max -= 1 else c += 1 end end @events = @choices[@choice..-1].find { |evt| evt[0].matches? event } @current = 0 if @events # reorder the choices old = @choices[@choice] idx = @choices.index( @events ) @choices[@choice] = @events @choices[idx] = old @choice += 1 end #puts "In next with #{event.inspect}." #puts "events is #{@events.inspect}" @events = [] unless @events end def next( event ) # Find the next series next_current(event) unless @events[@current] return nil unless @events[@current] expand_ref_in( @events, @current ) if @events[@current].class == Ref #puts "In next with #{event.inspect}." #puts "Next (#@current) is #{@events[@current]}" if ( @events[@current].kind_of? State ) @current += 1 @events[@current-1].previous = self return @events[@current-1].next( event ) end #puts "Current isn't a state" return @previous.pop.next( event ) if @events[@current].nil? if ( @events[@current].matches?(event) ) @current += 1 if @events[@current].nil? #puts "#{inspect[0,5]} 1RETURNING self" unless @choices[@choice].nil? return self unless @choices[@choice].nil? #puts "#{inspect[0,5]} 1RETURNING #{@previous[-1].inspect[0,5]}" return @previous.pop elsif @events[@current].kind_of? State @current += 1 #puts "#{inspect[0,5]} 2RETURNING (#{@current-1}) #{@events[@current-1].inspect[0,5]}; on return, next is #{@events[@current]}" @events[@current-1].previous = self return @events[@current-1] else #puts "#{inspect[0,5]} RETURNING self w/ next(#@current) = #{@events[@current]}" return self end else return nil end end def matches?( event ) return @events[@current].matches?( event ) if @events[@current] !@choices[@choice..-1].find{|evt| evt[0].matches?(event)}.nil? end def expected #puts "IN CHOICE EXPECTED" #puts "EVENTS = #{@events.inspect}" return [@events[@current]] if @events[@current] return @choices[@choice..-1].collect do |x| if x[0].kind_of? State x[0].expected else x[0] end end.flatten end def inspect "< #{to_s} #{@choices.collect{|e| e.collect{|f|f.to_s}.join(', ')}.join(' and ')} >" end end class Ref def initialize value @value = value end def to_s @value end def inspect "{#{to_s}}" end end end end ================================================ FILE: lib/rexml/validation/validation.rb ================================================ require 'rexml/validation/validationexception' module REXML module Validation module Validator NILEVENT = [ nil ] def reset @current = @root @root.reset @root.previous = true @attr_stack = [] self end def dump puts @root.inspect end def validate( event ) #puts "Current: #@current" #puts "Event: #{event.inspect}" @attr_stack = [] unless defined? @attr_stack match = @current.next(event) raise ValidationException.new( "Validation error. Expected: "+ @current.expected.join( " or " )+" from #{@current.inspect} "+ " but got #{Event.new( event[0], event[1] ).inspect}" ) unless match @current = match # Check for attributes case event[0] when :start_element #puts "Checking attributes" @attr_stack << event[2] begin sattr = [:start_attribute, nil] eattr = [:end_attribute] text = [:text, nil] k,v = event[2].find { |k,v| sattr[1] = k #puts "Looking for #{sattr.inspect}" m = @current.next( sattr ) #puts "Got #{m.inspect}" if m # If the state has text children... #puts "Looking for #{eattr.inspect}" #puts "Expect #{m.expected}" if m.matches?( eattr ) #puts "Got end" @current = m else #puts "Didn't get end" text[1] = v #puts "Looking for #{text.inspect}" m = m.next( text ) #puts "Got #{m.inspect}" text[1] = nil return false unless m @current = m if m end m = @current.next( eattr ) if m @current = m true else false end else false end } event[2].delete(k) if k end while k when :end_element attrs = @attr_stack.pop raise ValidationException.new( "Validation error. Illegal "+ " attributes: #{attrs.inspect}") if attrs.length > 0 end end end class Event def initialize(event_type, event_arg=nil ) @event_type = event_type @event_arg = event_arg end attr_reader :event_type attr_accessor :event_arg def done? @done end def single? return (@event_type != :start_element and @event_type != :start_attribute) end def matches?( event ) #puts "#@event_type =? #{event[0]} && #@event_arg =? #{event[1]} " return false unless event[0] == @event_type case event[0] when nil return true when :start_element return true if event[1] == @event_arg when :end_element return true when :start_attribute return true if event[1] == @event_arg when :end_attribute return true when :end_document return true when :text return (@event_arg.nil? or @event_arg == event[1]) =begin when :processing_instruction false when :xmldecl false when :start_doctype false when :end_doctype false when :externalentity false when :elementdecl false when :entity false when :attlistdecl false when :notationdecl false when :end_doctype false =end else false end end def ==( other ) return false unless other.kind_of? Event @event_type == other.event_type and @event_arg == other.event_arg end def to_s inspect end def inspect "#{@event_type.inspect}( #@event_arg )" end end end end ================================================ FILE: lib/rexml/validation/validationexception.rb ================================================ module REXML module Validation class ValidationException < RuntimeError def initialize msg super end end end end ================================================ FILE: lib/rexml/xmldecl.rb ================================================ require 'rexml/encoding' require 'rexml/source' module REXML # NEEDS DOCUMENTATION class XMLDecl < Child include Encoding DEFAULT_VERSION = "1.0"; DEFAULT_ENCODING = "UTF-8"; DEFAULT_STANDALONE = "no"; START = '<\?xml'; STOP = '\?>'; attr_accessor :version, :standalone attr_reader :writeencoding, :writethis def initialize(version=DEFAULT_VERSION, encoding=nil, standalone=nil) @writethis = true @writeencoding = !encoding.nil? if version.kind_of? XMLDecl super() @version = version.version self.encoding = version.encoding @writeencoding = version.writeencoding @standalone = version.standalone else super() @version = version self.encoding = encoding @standalone = standalone end @version = DEFAULT_VERSION if @version.nil? end def clone XMLDecl.new(self) end # indent:: # Ignored. There must be no whitespace before an XML declaration # transitive:: # Ignored # ie_hack:: # Ignored def write(writer, indent=-1, transitive=false, ie_hack=false) return nil unless @writethis or writer.kind_of? Output writer << START.sub(/\\/u, '') if writer.kind_of? Output writer << " #{content writer.encoding}" else writer << " #{content encoding}" end writer << STOP.sub(/\\/u, '') end def ==( other ) other.kind_of?(XMLDecl) and other.version == @version and other.encoding == self.encoding and other.standalone == @standalone end def xmldecl version, encoding, standalone @version = version self.encoding = encoding @standalone = standalone end def node_type :xmldecl end alias :stand_alone? :standalone alias :old_enc= :encoding= def encoding=( enc ) if enc.nil? self.old_enc = "UTF-8" @writeencoding = false else self.old_enc = enc @writeencoding = true end self.dowrite end # Only use this if you do not want the XML declaration to be written; # this object is ignored by the XML writer. Otherwise, instantiate your # own XMLDecl and add it to the document. # # Note that XML 1.1 documents *must* include an XML declaration def XMLDecl.default rv = XMLDecl.new( "1.0" ) rv.nowrite rv end def nowrite @writethis = false end def dowrite @writethis = true end def inspect START.sub(/\\/u, '') + " ... " + STOP.sub(/\\/u, '') end private def content(enc) rv = "version='#@version'" rv << " encoding='#{enc}'" if @writeencoding || enc !~ /utf-8/i rv << " standalone='#@standalone'" if @standalone rv end end end ================================================ FILE: lib/rexml/xmltokens.rb ================================================ module REXML # Defines a number of tokens used for parsing XML. Not for general # consumption. module XMLTokens NCNAME_STR= '[\w:][\-\w\d.]*' NAME_STR= "(?:#{NCNAME_STR}:)?#{NCNAME_STR}" NAMECHAR = '[\-\w\d\.:]' NAME = "([\\w:]#{NAMECHAR}*)" NMTOKEN = "(?:#{NAMECHAR})+" NMTOKENS = "#{NMTOKEN}(\\s+#{NMTOKEN})*" REFERENCE = "(?:&#{NAME};|&#\\d+;|&#x[0-9a-fA-F]+;)" #REFERENCE = "(?:#{ENTITYREF}|#{CHARREF})" #ENTITYREF = "&#{NAME};" #CHARREF = "&#\\d+;|&#x[0-9a-fA-F]+;" end end ================================================ FILE: lib/rexml/xpath.rb ================================================ require 'rexml/functions' require 'rexml/xpath_parser' module REXML # Wrapper class. Use this class to access the XPath functions. class XPath include Functions EMPTY_HASH = {} # Finds and returns the first node that matches the supplied xpath. # element:: # The context element # path:: # The xpath to search for. If not supplied or nil, returns the first # node matching '*'. # namespaces:: # If supplied, a Hash which defines a namespace mapping. # # XPath.first( node ) # XPath.first( doc, "//b"} ) # XPath.first( node, "a/x:b", { "x"=>"http://doofus" } ) def XPath::first element, path=nil, namespaces=nil, variables={} raise "The namespaces argument, if supplied, must be a hash object." unless namespaces.nil? or namespaces.kind_of?(Hash) raise "The variables argument, if supplied, must be a hash object." unless variables.kind_of?(Hash) parser = XPathParser.new parser.namespaces = namespaces parser.variables = variables path = "*" unless path element = [element] unless element.kind_of? Array parser.parse(path, element).flatten[0] end # Iterates over nodes that match the given path, calling the supplied # block with the match. # element:: # The context element # path:: # The xpath to search for. If not supplied or nil, defaults to '*' # namespaces:: # If supplied, a Hash which defines a namespace mapping # # XPath.each( node ) { |el| ... } # XPath.each( node, '/*[@attr='v']' ) { |el| ... } # XPath.each( node, 'ancestor::x' ) { |el| ... } def XPath::each element, path=nil, namespaces=nil, variables={}, &block raise "The namespaces argument, if supplied, must be a hash object." unless namespaces.nil? or namespaces.kind_of?(Hash) raise "The variables argument, if supplied, must be a hash object." unless variables.kind_of?(Hash) parser = XPathParser.new parser.namespaces = namespaces parser.variables = variables path = "*" unless path element = [element] unless element.kind_of? Array parser.parse(path, element).each( &block ) end # Returns an array of nodes matching a given XPath. def XPath::match element, path=nil, namespaces=nil, variables={} parser = XPathParser.new parser.namespaces = namespaces parser.variables = variables path = "*" unless path element = [element] unless element.kind_of? Array parser.parse(path,element) end end end ================================================ FILE: lib/rexml/xpath_parser.rb ================================================ require 'rexml/namespace' require 'rexml/xmltokens' require 'rexml/attribute' require 'rexml/syncenumerator' require 'rexml/parsers/xpathparser' class Object def dclone clone end end class Symbol def dclone ; self ; end end class Fixnum def dclone ; self ; end end class Float def dclone ; self ; end end class Array def dclone klone = self.clone klone.clear self.each{|v| klone << v.dclone} klone end end module REXML # You don't want to use this class. Really. Use XPath, which is a wrapper # for this class. Believe me. You don't want to poke around in here. # There is strange, dark magic at work in this code. Beware. Go back! Go # back while you still can! class XPathParser include XMLTokens LITERAL = /^'([^']*)'|^"([^"]*)"/u def initialize( ) @parser = REXML::Parsers::XPathParser.new @namespaces = nil @variables = {} end def namespaces=( namespaces={} ) Functions::namespace_context = namespaces @namespaces = namespaces end def variables=( vars={} ) Functions::variables = vars @variables = vars end def parse path, nodeset #puts "#"*40 path_stack = @parser.parse( path ) #puts "PARSE: #{path} => #{path_stack.inspect}" #puts "PARSE: nodeset = #{nodeset.inspect}" match( path_stack, nodeset ) end def get_first path, nodeset #puts "#"*40 path_stack = @parser.parse( path ) #puts "PARSE: #{path} => #{path_stack.inspect}" #puts "PARSE: nodeset = #{nodeset.inspect}" first( path_stack, nodeset ) end def predicate path, nodeset path_stack = @parser.parse( path ) expr( path_stack, nodeset ) end def []=( variable_name, value ) @variables[ variable_name ] = value end # Performs a depth-first (document order) XPath search, and returns the # first match. This is the fastest, lightest way to return a single result. # # FIXME: This method is incomplete! def first( path_stack, node ) #puts "#{depth}) Entering match( #{path.inspect}, #{tree.inspect} )" return nil if path.size == 0 case path[0] when :document # do nothing return first( path[1..-1], node ) when :child for c in node.children #puts "#{depth}) CHILD checking #{name(c)}" r = first( path[1..-1], c ) #puts "#{depth}) RETURNING #{r.inspect}" if r return r if r end when :qname name = path[2] #puts "#{depth}) QNAME #{name(tree)} == #{name} (path => #{path.size})" if node.name == name #puts "#{depth}) RETURNING #{tree.inspect}" if path.size == 3 return node if path.size == 3 return first( path[3..-1], node ) else return nil end when :descendant_or_self r = first( path[1..-1], node ) return r if r for c in node.children r = first( path, c ) return r if r end when :node return first( path[1..-1], node ) when :any return first( path[1..-1], node ) end return nil end def match( path_stack, nodeset ) #puts "MATCH: path_stack = #{path_stack.inspect}" #puts "MATCH: nodeset = #{nodeset.inspect}" r = expr( path_stack, nodeset ) #puts "MAIN EXPR => #{r.inspect}" r end private # Returns a String namespace for a node, given a prefix # The rules are: # # 1. Use the supplied namespace mapping first. # 2. If no mapping was supplied, use the context node to look up the namespace def get_namespace( node, prefix ) if @namespaces return @namespaces[prefix] || '' else return node.namespace( prefix ) if node.node_type == :element return '' end end # Expr takes a stack of path elements and a set of nodes (either a Parent # or an Array and returns an Array of matching nodes ALL = [ :attribute, :element, :text, :processing_instruction, :comment ] ELEMENTS = [ :element ] def expr( path_stack, nodeset, context=nil ) #puts "#"*15 #puts "In expr with #{path_stack.inspect}" #puts "Returning" if path_stack.length == 0 || nodeset.length == 0 node_types = ELEMENTS return nodeset if path_stack.length == 0 || nodeset.length == 0 while path_stack.length > 0 #puts "#"*5 #puts "Path stack = #{path_stack.inspect}" #puts "Nodeset is #{nodeset.inspect}" if nodeset.length == 0 path_stack.clear return [] end case (op = path_stack.shift) when :document nodeset = [ nodeset[0].root_node ] #puts ":document, nodeset = #{nodeset.inspect}" when :qname #puts "IN QNAME" prefix = path_stack.shift name = path_stack.shift nodeset.delete_if do |node| # FIXME: This DOUBLES the time XPath searches take ns = get_namespace( node, prefix ) #puts "NS = #{ns.inspect}" #puts "node.node_type == :element => #{node.node_type == :element}" if node.node_type == :element #puts "node.name == #{name} => #{node.name == name}" if node.name == name #puts "node.namespace == #{ns.inspect} => #{node.namespace == ns}" end end !(node.node_type == :element and node.name == name and node.namespace == ns ) end node_types = ELEMENTS when :any #puts "ANY 1: nodeset = #{nodeset.inspect}" #puts "ANY 1: node_types = #{node_types.inspect}" nodeset.delete_if { |node| !node_types.include?(node.node_type) } #puts "ANY 2: nodeset = #{nodeset.inspect}" when :self # This space left intentionally blank when :processing_instruction target = path_stack.shift nodeset.delete_if do |node| (node.node_type != :processing_instruction) or ( target!='' and ( node.target != target ) ) end when :text nodeset.delete_if { |node| node.node_type != :text } when :comment nodeset.delete_if { |node| node.node_type != :comment } when :node # This space left intentionally blank node_types = ALL when :child new_nodeset = [] nt = nil for node in nodeset nt = node.node_type new_nodeset += node.children if nt == :element or nt == :document end nodeset = new_nodeset node_types = ELEMENTS when :literal return path_stack.shift when :attribute new_nodeset = [] case path_stack.shift when :qname prefix = path_stack.shift name = path_stack.shift for element in nodeset if element.node_type == :element #puts "Element name = #{element.name}" #puts "get_namespace( #{element.inspect}, #{prefix} ) = #{get_namespace(element, prefix)}" attrib = element.attribute( name, get_namespace(element, prefix) ) #puts "attrib = #{attrib.inspect}" new_nodeset << attrib if attrib end end when :any #puts "ANY" for element in nodeset if element.node_type == :element new_nodeset += element.attributes.to_a end end end nodeset = new_nodeset when :parent #puts "PARENT 1: nodeset = #{nodeset}" nodeset = nodeset.collect{|n| n.parent}.compact #nodeset = expr(path_stack.dclone, nodeset.collect{|n| n.parent}.compact) #puts "PARENT 2: nodeset = #{nodeset.inspect}" node_types = ELEMENTS when :ancestor new_nodeset = [] for node in nodeset while node.parent node = node.parent new_nodeset << node unless new_nodeset.include? node end end nodeset = new_nodeset node_types = ELEMENTS when :ancestor_or_self new_nodeset = [] for node in nodeset if node.node_type == :element new_nodeset << node while ( node.parent ) node = node.parent new_nodeset << node unless new_nodeset.include? node end end end nodeset = new_nodeset node_types = ELEMENTS when :predicate new_nodeset = [] subcontext = { :size => nodeset.size } pred = path_stack.shift nodeset.each_with_index { |node, index| subcontext[ :node ] = node #puts "PREDICATE SETTING CONTEXT INDEX TO #{index+1}" subcontext[ :index ] = index+1 pc = pred.dclone #puts "#{node.hash}) Recursing with #{pred.inspect} and [#{node.inspect}]" result = expr( pc, [node], subcontext ) result = result[0] if result.kind_of? Array and result.length == 1 #puts "#{node.hash}) Result = #{result.inspect} (#{result.class.name})" if result.kind_of? Numeric #puts "Adding node #{node.inspect}" if result == (index+1) new_nodeset << node if result == (index+1) elsif result.instance_of? Array if result.size > 0 and result.inject(false) {|k,s| s or k} #puts "Adding node #{node.inspect}" if result.size > 0 new_nodeset << node if result.size > 0 end else #puts "Adding node #{node.inspect}" if result new_nodeset << node if result end } #puts "New nodeset = #{new_nodeset.inspect}" #puts "Path_stack = #{path_stack.inspect}" nodeset = new_nodeset =begin predicate = path_stack.shift ns = nodeset.clone result = expr( predicate, ns ) #puts "Result = #{result.inspect} (#{result.class.name})" #puts "nodeset = #{nodeset.inspect}" if result.kind_of? Array nodeset = result.zip(ns).collect{|m,n| n if m}.compact else nodeset = result ? nodeset : [] end #puts "Outgoing NS = #{nodeset.inspect}" =end when :descendant_or_self rv = descendant_or_self( path_stack, nodeset ) path_stack.clear nodeset = rv node_types = ELEMENTS when :descendant results = [] nt = nil for node in nodeset nt = node.node_type results += expr( path_stack.dclone.unshift( :descendant_or_self ), node.children ) if nt == :element or nt == :document end nodeset = results node_types = ELEMENTS when :following_sibling #puts "FOLLOWING_SIBLING 1: nodeset = #{nodeset}" results = [] nodeset.each do |node| next if node.parent.nil? all_siblings = node.parent.children current_index = all_siblings.index( node ) following_siblings = all_siblings[ current_index+1 .. -1 ] results += expr( path_stack.dclone, following_siblings ) end #puts "FOLLOWING_SIBLING 2: nodeset = #{nodeset}" nodeset = results when :preceding_sibling results = [] nodeset.each do |node| next if node.parent.nil? all_siblings = node.parent.children current_index = all_siblings.index( node ) preceding_siblings = all_siblings[ 0, current_index ].reverse results += preceding_siblings end nodeset = results node_types = ELEMENTS when :preceding new_nodeset = [] for node in nodeset new_nodeset += preceding( node ) end #puts "NEW NODESET => #{new_nodeset.inspect}" nodeset = new_nodeset node_types = ELEMENTS when :following new_nodeset = [] for node in nodeset new_nodeset += following( node ) end nodeset = new_nodeset node_types = ELEMENTS when :namespace #puts "In :namespace" new_nodeset = [] prefix = path_stack.shift for node in nodeset if (node.node_type == :element or node.node_type == :attribute) if @namespaces namespaces = @namespaces elsif (node.node_type == :element) namespaces = node.namespaces else namespaces = node.element.namesapces end #puts "Namespaces = #{namespaces.inspect}" #puts "Prefix = #{prefix.inspect}" #puts "Node.namespace = #{node.namespace}" if (node.namespace == namespaces[prefix]) new_nodeset << node end end end nodeset = new_nodeset when :variable var_name = path_stack.shift return @variables[ var_name ] # :and, :or, :eq, :neq, :lt, :lteq, :gt, :gteq # TODO: Special case for :or and :and -- not evaluate the right # operand if the left alone determines result (i.e. is true for # :or and false for :and). when :eq, :neq, :lt, :lteq, :gt, :gteq, :and, :or left = expr( path_stack.shift, nodeset.dup, context ) #puts "LEFT => #{left.inspect} (#{left.class.name})" right = expr( path_stack.shift, nodeset.dup, context ) #puts "RIGHT => #{right.inspect} (#{right.class.name})" res = equality_relational_compare( left, op, right ) #puts "RES => #{res.inspect}" return res when :and left = expr( path_stack.shift, nodeset.dup, context ) #puts "LEFT => #{left.inspect} (#{left.class.name})" if left == false || left.nil? || !left.inject(false) {|a,b| a | b} return [] end right = expr( path_stack.shift, nodeset.dup, context ) #puts "RIGHT => #{right.inspect} (#{right.class.name})" res = equality_relational_compare( left, op, right ) #puts "RES => #{res.inspect}" return res when :div left = Functions::number(expr(path_stack.shift, nodeset, context)).to_f right = Functions::number(expr(path_stack.shift, nodeset, context)).to_f return (left / right) when :mod left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f return (left % right) when :mult left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f return (left * right) when :plus left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f return (left + right) when :minus left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f return (left - right) when :union left = expr( path_stack.shift, nodeset, context ) right = expr( path_stack.shift, nodeset, context ) return (left | right) when :neg res = expr( path_stack, nodeset, context ) return -(res.to_f) when :not when :function func_name = path_stack.shift.tr('-','_') arguments = path_stack.shift #puts "FUNCTION 0: #{func_name}(#{arguments.collect{|a|a.inspect}.join(', ')})" subcontext = context ? nil : { :size => nodeset.size } res = [] cont = context nodeset.each_with_index { |n, i| if subcontext subcontext[:node] = n subcontext[:index] = i cont = subcontext end arg_clone = arguments.dclone args = arg_clone.collect { |arg| #puts "FUNCTION 1: Calling expr( #{arg.inspect}, [#{n.inspect}] )" expr( arg, [n], cont ) } #puts "FUNCTION 2: #{func_name}(#{args.collect{|a|a.inspect}.join(', ')})" Functions.context = cont res << Functions.send( func_name, *args ) #puts "FUNCTION 3: #{res[-1].inspect}" } return res end end # while #puts "EXPR returning #{nodeset.inspect}" return nodeset end ########################################################## # FIXME # The next two methods are BAD MOJO! # This is my achilles heel. If anybody thinks of a better # way of doing this, be my guest. This really sucks, but # it is a wonder it works at all. # ######################################################## def descendant_or_self( path_stack, nodeset ) rs = [] #puts "#"*80 #puts "PATH_STACK = #{path_stack.inspect}" #puts "NODESET = #{nodeset.collect{|n|n.inspect}.inspect}" d_o_s( path_stack, nodeset, rs ) #puts "RS = #{rs.collect{|n|n.inspect}.inspect}" document_order(rs.flatten.compact) #rs.flatten.compact end def d_o_s( p, ns, r ) #puts "IN DOS with #{ns.inspect}; ALREADY HAVE #{r.inspect}" nt = nil ns.each_index do |i| n = ns[i] #puts "P => #{p.inspect}" x = expr( p.dclone, [ n ] ) nt = n.node_type d_o_s( p, n.children, x ) if nt == :element or nt == :document and n.children.size > 0 r.concat(x) if x.size > 0 end end # Reorders an array of nodes so that they are in document order # It tries to do this efficiently. # # FIXME: I need to get rid of this, but the issue is that most of the XPath # interpreter functions as a filter, which means that we lose context going # in and out of function calls. If I knew what the index of the nodes was, # I wouldn't have to do this. Maybe add a document IDX for each node? # Problems with mutable documents. Or, rewrite everything. def document_order( array_of_nodes ) new_arry = [] array_of_nodes.each { |node| node_idx = [] np = node.node_type == :attribute ? node.element : node while np.parent and np.parent.node_type == :element node_idx << np.parent.index( np ) np = np.parent end new_arry << [ node_idx.reverse, node ] } #puts "new_arry = #{new_arry.inspect}" new_arry.sort{ |s1, s2| s1[0] <=> s2[0] }.collect{ |s| s[1] } end def recurse( nodeset, &block ) for node in nodeset yield node recurse( node, &block ) if node.node_type == :element end end # Builds a nodeset of all of the preceding nodes of the supplied node, # in reverse document order # preceding:: includes every element in the document that precedes this node, # except for ancestors def preceding( node ) #puts "IN PRECEDING" ancestors = [] p = node.parent while p ancestors << p p = p.parent end acc = [] p = preceding_node_of( node ) #puts "P = #{p.inspect}" while p if ancestors.include? p ancestors.delete(p) else acc << p end p = preceding_node_of( p ) #puts "P = #{p.inspect}" end acc end def preceding_node_of( node ) #puts "NODE: #{node.inspect}" #puts "PREVIOUS NODE: #{node.previous_sibling_node.inspect}" #puts "PARENT NODE: #{node.parent}" psn = node.previous_sibling_node if psn.nil? if node.parent.nil? or node.parent.class == Document return nil end return node.parent #psn = preceding_node_of( node.parent ) end while psn and psn.kind_of? Element and psn.children.size > 0 psn = psn.children[-1] end psn end def following( node ) #puts "IN PRECEDING" acc = [] p = next_sibling_node( node ) #puts "P = #{p.inspect}" while p acc << p p = following_node_of( p ) #puts "P = #{p.inspect}" end acc end def following_node_of( node ) #puts "NODE: #{node.inspect}" #puts "PREVIOUS NODE: #{node.previous_sibling_node.inspect}" #puts "PARENT NODE: #{node.parent}" if node.kind_of? Element and node.children.size > 0 return node.children[0] end return next_sibling_node(node) end def next_sibling_node(node) psn = node.next_sibling_node while psn.nil? if node.parent.nil? or node.parent.class == Document return nil end node = node.parent psn = node.next_sibling_node #puts "psn = #{psn.inspect}" end return psn end def norm b case b when true, false return b when 'true', 'false' return Functions::boolean( b ) when /^\d+(\.\d+)?$/ return Functions::number( b ) else return Functions::string( b ) end end def equality_relational_compare( set1, op, set2 ) #puts "EQ_REL_COMP(#{set1.inspect} #{op.inspect} #{set2.inspect})" if set1.kind_of? Array and set2.kind_of? Array #puts "#{set1.size} & #{set2.size}" if set1.size == 1 and set2.size == 1 set1 = set1[0] set2 = set2[0] elsif set1.size == 0 or set2.size == 0 nd = set1.size==0 ? set2 : set1 rv = nd.collect { |il| compare( il, op, nil ) } #puts "RV = #{rv.inspect}" return rv else res = [] enum = SyncEnumerator.new( set1, set2 ).each { |i1, i2| #puts "i1 = #{i1.inspect} (#{i1.class.name})" #puts "i2 = #{i2.inspect} (#{i2.class.name})" i1 = norm( i1 ) i2 = norm( i2 ) res << compare( i1, op, i2 ) } return res end end #puts "EQ_REL_COMP: #{set1.inspect} (#{set1.class.name}), #{op}, #{set2.inspect} (#{set2.class.name})" #puts "COMPARING VALUES" # If one is nodeset and other is number, compare number to each item # in nodeset s.t. number op number(string(item)) # If one is nodeset and other is string, compare string to each item # in nodeset s.t. string op string(item) # If one is nodeset and other is boolean, compare boolean to each item # in nodeset s.t. boolean op boolean(item) if set1.kind_of? Array or set2.kind_of? Array #puts "ISA ARRAY" if set1.kind_of? Array a = set1 b = set2 else a = set2 b = set1 end case b when true, false return a.collect {|v| compare( Functions::boolean(v), op, b ) } when Numeric return a.collect {|v| compare( Functions::number(v), op, b )} when /^\d+(\.\d+)?$/ b = Functions::number( b ) #puts "B = #{b.inspect}" return a.collect {|v| compare( Functions::number(v), op, b )} else #puts "Functions::string( #{b}(#{b.class.name}) ) = #{Functions::string(b)}" b = Functions::string( b ) return a.collect { |v| compare( Functions::string(v), op, b ) } end else # If neither is nodeset, # If op is = or != # If either boolean, convert to boolean # If either number, convert to number # Else, convert to string # Else # Convert both to numbers and compare s1 = set1.to_s s2 = set2.to_s #puts "EQ_REL_COMP: #{set1}=>#{s1}, #{set2}=>#{s2}" if s1 == 'true' or s1 == 'false' or s2 == 'true' or s2 == 'false' #puts "Functions::boolean(#{set1})=>#{Functions::boolean(set1)}" #puts "Functions::boolean(#{set2})=>#{Functions::boolean(set2)}" set1 = Functions::boolean( set1 ) set2 = Functions::boolean( set2 ) else if op == :eq or op == :neq if s1 =~ /^\d+(\.\d+)?$/ or s2 =~ /^\d+(\.\d+)?$/ set1 = Functions::number( s1 ) set2 = Functions::number( s2 ) else set1 = Functions::string( set1 ) set2 = Functions::string( set2 ) end else set1 = Functions::number( set1 ) set2 = Functions::number( set2 ) end end #puts "EQ_REL_COMP: #{set1} #{op} #{set2}" #puts ">>> #{compare( set1, op, set2 )}" return compare( set1, op, set2 ) end return false end def compare a, op, b #puts "COMPARE #{a.inspect}(#{a.class.name}) #{op} #{b.inspect}(#{b.class.name})" case op when :eq a == b when :neq a != b when :lt a < b when :lteq a <= b when :gt a > b when :gteq a >= b when :and a and b when :or a or b else false end end end end ================================================ FILE: lib/rinda/rinda.rb ================================================ require 'drb/drb' require 'thread' ## # A module to implement the Linda distributed computing paradigm in Ruby. # # Rinda is part of DRb (dRuby). # # == Example(s) # # See the sample/drb/ directory in the Ruby distribution, from 1.8.2 onwards. # #-- # TODO # == Introduction to Linda/rinda? # # == Why is this library separate from DRb? module Rinda ## # Rinda error base class class RindaError < RuntimeError; end ## # Raised when a hash-based tuple has an invalid key. class InvalidHashTupleKey < RindaError; end ## # Raised when trying to use a canceled tuple. class RequestCanceledError < ThreadError; end ## # Raised when trying to use an expired tuple. class RequestExpiredError < ThreadError; end ## # A tuple is the elementary object in Rinda programming. # Tuples may be matched against templates if the tuple and # the template are the same size. class Tuple ## # Creates a new Tuple from +ary_or_hash+ which must be an Array or Hash. def initialize(ary_or_hash) if hash?(ary_or_hash) init_with_hash(ary_or_hash) else init_with_ary(ary_or_hash) end end ## # The number of elements in the tuple. def size @tuple.size end ## # Accessor method for elements of the tuple. def [](k) @tuple[k] end ## # Fetches item +k+ from the tuple. def fetch(k) @tuple.fetch(k) end ## # Iterate through the tuple, yielding the index or key, and the # value, thus ensuring arrays are iterated similarly to hashes. def each # FIXME if Hash === @tuple @tuple.each { |k, v| yield(k, v) } else @tuple.each_with_index { |v, k| yield(k, v) } end end ## # Return the tuple itself def value @tuple end private def hash?(ary_or_hash) ary_or_hash.respond_to?(:keys) end ## # Munges +ary+ into a valid Tuple. def init_with_ary(ary) @tuple = Array.new(ary.size) @tuple.size.times do |i| @tuple[i] = ary[i] end end ## # Ensures +hash+ is a valid Tuple. def init_with_hash(hash) @tuple = Hash.new hash.each do |k, v| raise InvalidHashTupleKey unless String === k @tuple[k] = v end end end ## # Templates are used to match tuples in Rinda. class Template < Tuple ## # Matches this template against +tuple+. The +tuple+ must be the same # size as the template. An element with a +nil+ value in a template acts # as a wildcard, matching any value in the corresponding position in the # tuple. Elements of the template match the +tuple+ if the are #== or # #===. # # Template.new([:foo, 5]).match Tuple.new([:foo, 5]) # => true # Template.new([:foo, nil]).match Tuple.new([:foo, 5]) # => true # Template.new([String]).match Tuple.new(['hello']) # => true # # Template.new([:foo]).match Tuple.new([:foo, 5]) # => false # Template.new([:foo, 6]).match Tuple.new([:foo, 5]) # => false # Template.new([:foo, nil]).match Tuple.new([:foo]) # => false # Template.new([:foo, 6]).match Tuple.new([:foo]) # => false def match(tuple) return false unless tuple.respond_to?(:size) return false unless tuple.respond_to?(:fetch) return false unless self.size == tuple.size each do |k, v| begin it = tuple.fetch(k) rescue return false end next if v.nil? next if v == it next if v === it return false end return true end ## # Alias for #match. def ===(tuple) match(tuple) end end ## # Documentation? class DRbObjectTemplate ## # Creates a new DRbObjectTemplate that will match against +uri+ and +ref+. def initialize(uri=nil, ref=nil) @drb_uri = uri @drb_ref = ref end ## # This DRbObjectTemplate matches +ro+ if the remote object's drburi and # drbref are the same. +nil+ is used as a wildcard. def ===(ro) return true if super(ro) unless @drb_uri.nil? return false unless (@drb_uri === ro.__drburi rescue false) end unless @drb_ref.nil? return false unless (@drb_ref === ro.__drbref rescue false) end true end end ## # TupleSpaceProxy allows a remote Tuplespace to appear as local. class TupleSpaceProxy ## # Creates a new TupleSpaceProxy to wrap +ts+. def initialize(ts) @ts = ts end ## # Adds +tuple+ to the proxied TupleSpace. See TupleSpace#write. def write(tuple, sec=nil) @ts.write(tuple, sec) end ## # Takes +tuple+ from the proxied TupleSpace. See TupleSpace#take. def take(tuple, sec=nil, &block) port = [] @ts.move(DRbObject.new(port), tuple, sec, &block) port[0] end ## # Reads +tuple+ from the proxied TupleSpace. See TupleSpace#read. def read(tuple, sec=nil, &block) @ts.read(tuple, sec, &block) end ## # Reads all tuples matching +tuple+ from the proxied TupleSpace. See # TupleSpace#read_all. def read_all(tuple) @ts.read_all(tuple) end ## # Registers for notifications of event +ev+ on the proxied TupleSpace. # See TupleSpace#notify def notify(ev, tuple, sec=nil) @ts.notify(ev, tuple, sec) end end ## # An SimpleRenewer allows a TupleSpace to check if a TupleEntry is still # alive. class SimpleRenewer include DRbUndumped ## # Creates a new SimpleRenewer that keeps an object alive for another +sec+ # seconds. def initialize(sec=180) @sec = sec end ## # Called by the TupleSpace to check if the object is still alive. def renew @sec end end end ================================================ FILE: lib/rinda/ring.rb ================================================ # # Note: Rinda::Ring API is unstable. # require 'drb/drb' require 'rinda/rinda' require 'thread' module Rinda ## # The default port Ring discovery will use. Ring_PORT = 7647 ## # A RingServer allows a Rinda::TupleSpace to be located via UDP broadcasts. # Service location uses the following steps: # # 1. A RingServer begins listening on the broadcast UDP address. # 2. A RingFinger sends a UDP packet containing the DRb URI where it will # listen for a reply. # 3. The RingServer receives the UDP packet and connects back to the # provided DRb URI with the DRb service. class RingServer include DRbUndumped ## # Advertises +ts+ on the UDP broadcast address at +port+. def initialize(ts, port=Ring_PORT) @ts = ts @soc = UDPSocket.open @soc.bind('', port) @w_service = write_service @r_service = reply_service end ## # Creates a thread that picks up UDP packets and passes them to do_write # for decoding. def write_service Thread.new do loop do msg = @soc.recv(1024) do_write(msg) end end end ## # Extracts the response URI from +msg+ and adds it to TupleSpace where it # will be picked up by +reply_service+ for notification. def do_write(msg) Thread.new do begin tuple, sec = Marshal.load(msg) @ts.write(tuple, sec) rescue end end end ## # Creates a thread that notifies waiting clients from the TupleSpace. def reply_service Thread.new do loop do do_reply end end end ## # Pulls lookup tuples out of the TupleSpace and sends their DRb object the # address of the local TupleSpace. def do_reply tuple = @ts.take([:lookup_ring, nil]) Thread.new { tuple[1].call(@ts) rescue nil} rescue end end ## # RingFinger is used by RingServer clients to discover the RingServer's # TupleSpace. Typically, all a client needs to do is call # RingFinger.primary to retrieve the remote TupleSpace, which it can then # begin using. class RingFinger @@broadcast_list = ['', 'localhost'] @@finger = nil ## # Creates a singleton RingFinger and looks for a RingServer. Returns the # created RingFinger. def self.finger unless @@finger @@finger = self.new @@finger.lookup_ring_any end @@finger end ## # Returns the first advertised TupleSpace. def self.primary finger.primary end ## # Contains all discovered TupleSpaces except for the primary. def self.to_a finger.to_a end ## # The list of addresses where RingFinger will send query packets. attr_accessor :broadcast_list ## # The port that RingFinger will send query packets to. attr_accessor :port ## # Contain the first advertised TupleSpace after lookup_ring_any is called. attr_accessor :primary ## # Creates a new RingFinger that will look for RingServers at +port+ on # the addresses in +broadcast_list+. def initialize(broadcast_list=@@broadcast_list, port=Ring_PORT) @broadcast_list = broadcast_list || ['localhost'] @port = port @primary = nil @rings = [] end ## # Contains all discovered TupleSpaces except for the primary. def to_a @rings end ## # Iterates over all discovered TupleSpaces starting with the primary. def each lookup_ring_any unless @primary return unless @primary yield(@primary) @rings.each { |x| yield(x) } end ## # Looks up RingServers waiting +timeout+ seconds. RingServers will be # given +block+ as a callback, which will be called with the remote # TupleSpace. def lookup_ring(timeout=5, &block) return lookup_ring_any(timeout) unless block_given? msg = Marshal.dump([[:lookup_ring, DRbObject.new(block)], timeout]) @broadcast_list.each do |it| soc = UDPSocket.open begin soc.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true) soc.send(msg, 0, it, @port) rescue nil ensure soc.close end end sleep(timeout) end ## # Returns the first found remote TupleSpace. Any further recovered # TupleSpaces can be found by calling +to_a+. def lookup_ring_any(timeout=5) queue = Queue.new th = Thread.new do self.lookup_ring(timeout) do |ts| queue.push(ts) end queue.push(nil) while it = queue.pop @rings.push(it) end end @primary = queue.pop raise('RingNotFound') if @primary.nil? @primary end end ## # RingProvider uses a RingServer advertised TupleSpace as a name service. # TupleSpace clients can register themselves with the remote TupleSpace and # look up other provided services via the remote TupleSpace. # # Services are registered with a tuple of the format [:name, klass, # DRbObject, description]. class RingProvider ## # Creates a RingProvider that will provide a +klass+ service running on # +front+, with a +description+. +renewer+ is optional. def initialize(klass, front, desc, renewer = nil) @tuple = [:name, klass, front, desc] @renewer = renewer || Rinda::SimpleRenewer.new end ## # Advertises this service on the primary remote TupleSpace. def provide ts = Rinda::RingFinger.primary ts.write(@tuple, @renewer) end end end if __FILE__ == $0 DRb.start_service case ARGV.shift when 's' require 'rinda/tuplespace' ts = Rinda::TupleSpace.new place = Rinda::RingServer.new(ts) $stdin.gets when 'w' finger = Rinda::RingFinger.new(nil) finger.lookup_ring do |ts| p ts ts.write([:hello, :world]) end when 'r' finger = Rinda::RingFinger.new(nil) finger.lookup_ring do |ts| p ts p ts.take([nil, nil]) end end end ================================================ FILE: lib/rinda/tuplespace.rb ================================================ require 'monitor' require 'thread' require 'drb/drb' require 'rinda/rinda' require 'enumerator' require 'forwardable' module Rinda ## # A TupleEntry is a Tuple (i.e. a possible entry in some Tuplespace) # together with expiry and cancellation data. class TupleEntry include DRbUndumped attr_accessor :expires ## # Creates a TupleEntry based on +ary+ with an optional renewer or expiry # time +sec+. # # A renewer must implement the +renew+ method which returns a Numeric, # nil, or true to indicate when the tuple has expired. def initialize(ary, sec=nil) @cancel = false @expires = nil @tuple = make_tuple(ary) @renewer = nil renew(sec) end ## # Marks this TupleEntry as canceled. def cancel @cancel = true end ## # A TupleEntry is dead when it is canceled or expired. def alive? !canceled? && !expired? end ## # Return the object which makes up the tuple itself: the Array # or Hash. def value; @tuple.value; end ## # Returns the canceled status. def canceled?; @cancel; end ## # Has this tuple expired? (true/false). # # A tuple has expired when its expiry timer based on the +sec+ argument to # #initialize runs out. def expired? return true unless @expires return false if @expires > Time.now return true if @renewer.nil? renew(@renewer) return true unless @expires return @expires < Time.now end ## # Reset the expiry time according to +sec_or_renewer+. # # +nil+:: it is set to expire in the far future. # +false+:: it has expired. # Numeric:: it will expire in that many seconds. # # Otherwise the argument refers to some kind of renewer object # which will reset its expiry time. def renew(sec_or_renewer) sec, @renewer = get_renewer(sec_or_renewer) @expires = make_expires(sec) end ## # Returns an expiry Time based on +sec+ which can be one of: # Numeric:: +sec+ seconds into the future # +true+:: the expiry time is the start of 1970 (i.e. expired) # +nil+:: it is Tue Jan 19 03:14:07 GMT Standard Time 2038 (i.e. when # UNIX clocks will die) def make_expires(sec=nil) case sec when Numeric Time.now + sec when true Time.at(1) when nil Time.at(2**31-1) end end ## # Retrieves +key+ from the tuple. def [](key) @tuple[key] end ## # Fetches +key+ from the tuple. def fetch(key) @tuple.fetch(key) end ## # The size of the tuple. def size @tuple.size end ## # Creates a Rinda::Tuple for +ary+. def make_tuple(ary) Rinda::Tuple.new(ary) end private ## # Returns a valid argument to make_expires and the renewer or nil. # # Given +true+, +nil+, or Numeric, returns that value and +nil+ (no actual # renewer). Otherwise it returns an expiry value from calling +it.renew+ # and the renewer. def get_renewer(it) case it when Numeric, true, nil return it, nil else begin return it.renew, it rescue Exception return it, nil end end end end ## # A TemplateEntry is a Template together with expiry and cancellation data. class TemplateEntry < TupleEntry ## # Matches this TemplateEntry against +tuple+. See Template#match for # details on how a Template matches a Tuple. def match(tuple) @tuple.match(tuple) end alias === match def make_tuple(ary) # :nodoc: Rinda::Template.new(ary) end end ## # Documentation? class WaitTemplateEntry < TemplateEntry attr_reader :found def initialize(place, ary, expires=nil) super(ary, expires) @place = place @cond = place.new_cond @found = nil end def cancel super signal end def wait @cond.wait end def read(tuple) @found = tuple signal end def signal @place.synchronize do @cond.signal end end end ## # A NotifyTemplateEntry is returned by TupleSpace#notify and is notified of # TupleSpace changes. You may receive either your subscribed event or the # 'close' event when iterating over notifications. # # See TupleSpace#notify_event for valid notification types. # # == Example # # ts = Rinda::TupleSpace.new # observer = ts.notify 'write', [nil] # # Thread.start do # observer.each { |t| p t } # end # # 3.times { |i| ts.write [i] } # # Outputs: # # ['write', [0]] # ['write', [1]] # ['write', [2]] class NotifyTemplateEntry < TemplateEntry ## # Creates a new NotifyTemplateEntry that watches +place+ for +event+s that # match +tuple+. def initialize(place, event, tuple, expires=nil) ary = [event, Rinda::Template.new(tuple)] super(ary, expires) @queue = Queue.new @done = false end ## # Called by TupleSpace to notify this NotifyTemplateEntry of a new event. def notify(ev) @queue.push(ev) end ## # Retrieves a notification. Raises RequestExpiredError when this # NotifyTemplateEntry expires. def pop raise RequestExpiredError if @done it = @queue.pop @done = true if it[0] == 'close' return it end ## # Yields event/tuple pairs until this NotifyTemplateEntry expires. def each # :yields: event, tuple while !@done it = pop yield(it) end rescue ensure cancel end end ## # TupleBag is an unordered collection of tuples. It is the basis # of Tuplespace. class TupleBag class TupleBin extend Forwardable def_delegators '@bin', :find_all, :delete_if, :each, :empty? def initialize @bin = [] end def add(tuple) @bin.push(tuple) end def delete(tuple) idx = @bin.rindex(tuple) @bin.delete_at(idx) if idx end def find(&blk) @bin.reverse_each do |x| return x if yield(x) end nil end end def initialize # :nodoc: @hash = {} @enum = Enumerable::Enumerator.new(self, :each_entry) end ## # +true+ if the TupleBag to see if it has any expired entries. def has_expires? @enum.find do |tuple| tuple.expires end end ## # Add +tuple+ to the TupleBag. def push(tuple) key = bin_key(tuple) @hash[key] ||= TupleBin.new @hash[key].add(tuple) end ## # Removes +tuple+ from the TupleBag. def delete(tuple) key = bin_key(tuple) bin = @hash[key] return nil unless bin bin.delete(tuple) @hash.delete(key) if bin.empty? tuple end ## # Finds all live tuples that match +template+. def find_all(template) bin_for_find(template).find_all do |tuple| tuple.alive? && template.match(tuple) end end ## # Finds a live tuple that matches +template+. def find(template) bin_for_find(template).find do |tuple| tuple.alive? && template.match(tuple) end end ## # Finds all tuples in the TupleBag which when treated as templates, match # +tuple+ and are alive. def find_all_template(tuple) @enum.find_all do |template| template.alive? && template.match(tuple) end end ## # Delete tuples which dead tuples from the TupleBag, returning the deleted # tuples. def delete_unless_alive deleted = [] @hash.each do |key, bin| bin.delete_if do |tuple| if tuple.alive? false else deleted.push(tuple) true end end end deleted end private def each_entry(&blk) @hash.each do |k, v| v.each(&blk) end end def bin_key(tuple) head = tuple[0] if head.class == Symbol return head else false end end def bin_for_find(template) key = bin_key(template) key ? @hash.fetch(key, []) : @enum end end ## # The Tuplespace manages access to the tuples it contains, # ensuring mutual exclusion requirements are met. # # The +sec+ option for the write, take, move, read and notify methods may # either be a number of seconds or a Renewer object. class TupleSpace include DRbUndumped include MonitorMixin ## # Creates a new TupleSpace. +period+ is used to control how often to look # for dead tuples after modifications to the TupleSpace. # # If no dead tuples are found +period+ seconds after the last # modification, the TupleSpace will stop looking for dead tuples. def initialize(period=60) super() @bag = TupleBag.new @read_waiter = TupleBag.new @take_waiter = TupleBag.new @notify_waiter = TupleBag.new @period = period @keeper = nil end ## # Adds +tuple+ def write(tuple, sec=nil) entry = create_entry(tuple, sec) synchronize do if entry.expired? @read_waiter.find_all_template(entry).each do |template| template.read(tuple) end notify_event('write', entry.value) notify_event('delete', entry.value) else @bag.push(entry) start_keeper if entry.expires @read_waiter.find_all_template(entry).each do |template| template.read(tuple) end @take_waiter.find_all_template(entry).each do |template| template.signal end notify_event('write', entry.value) end end entry end ## # Removes +tuple+ def take(tuple, sec=nil, &block) move(nil, tuple, sec, &block) end ## # Moves +tuple+ to +port+. def move(port, tuple, sec=nil) template = WaitTemplateEntry.new(self, tuple, sec) yield(template) if block_given? synchronize do entry = @bag.find(template) if entry port.push(entry.value) if port @bag.delete(entry) notify_event('take', entry.value) return entry.value end raise RequestExpiredError if template.expired? begin @take_waiter.push(template) start_keeper if template.expires while true raise RequestCanceledError if template.canceled? raise RequestExpiredError if template.expired? entry = @bag.find(template) if entry port.push(entry.value) if port @bag.delete(entry) notify_event('take', entry.value) return entry.value end template.wait end ensure @take_waiter.delete(template) end end end ## # Reads +tuple+, but does not remove it. def read(tuple, sec=nil) template = WaitTemplateEntry.new(self, tuple, sec) yield(template) if block_given? synchronize do entry = @bag.find(template) return entry.value if entry raise RequestExpiredError if template.expired? begin @read_waiter.push(template) start_keeper if template.expires template.wait raise RequestCanceledError if template.canceled? raise RequestExpiredError if template.expired? return template.found ensure @read_waiter.delete(template) end end end ## # Returns all tuples matching +tuple+. Does not remove the found tuples. def read_all(tuple) template = WaitTemplateEntry.new(self, tuple, nil) synchronize do entry = @bag.find_all(template) entry.collect do |e| e.value end end end ## # Registers for notifications of +event+. Returns a NotifyTemplateEntry. # See NotifyTemplateEntry for examples of how to listen for notifications. # # +event+ can be: # 'write':: A tuple was added # 'take':: A tuple was taken or moved # 'delete':: A tuple was lost after being overwritten or expiring # # The TupleSpace will also notify you of the 'close' event when the # NotifyTemplateEntry has expired. def notify(event, tuple, sec=nil) template = NotifyTemplateEntry.new(self, event, tuple, sec) synchronize do @notify_waiter.push(template) end template end private def create_entry(tuple, sec) TupleEntry.new(tuple, sec) end ## # Removes dead tuples. def keep_clean synchronize do @read_waiter.delete_unless_alive.each do |e| e.signal end @take_waiter.delete_unless_alive.each do |e| e.signal end @notify_waiter.delete_unless_alive.each do |e| e.notify(['close']) end @bag.delete_unless_alive.each do |e| notify_event('delete', e.value) end end end ## # Notifies all registered listeners for +event+ of a status change of # +tuple+. def notify_event(event, tuple) ev = [event, tuple] @notify_waiter.find_all_template(ev).each do |template| template.notify(ev) end end ## # Creates a thread that scans the tuplespace for expired tuples. def start_keeper return if @keeper && @keeper.alive? @keeper = Thread.new do while true sleep(@period) synchronize do break unless need_keeper? keep_clean end end end end ## # Checks the tuplespace to see if it needs cleaning. def need_keeper? return true if @bag.has_expires? return true if @read_waiter.has_expires? return true if @take_waiter.has_expires? return true if @notify_waiter.has_expires? end end end ================================================ FILE: lib/rss/0.9.rb ================================================ require "rss/parser" module RSS module RSS09 NSPOOL = {} ELEMENTS = [] def self.append_features(klass) super klass.install_must_call_validator('', "") end end class Rss < Element include RSS09 include RootElementMixin %w(channel).each do |name| install_have_child_element(name, "", nil) end attr_writer :feed_version alias_method(:rss_version, :feed_version) alias_method(:rss_version=, :feed_version=) def initialize(feed_version, version=nil, encoding=nil, standalone=nil) super @feed_type = "rss" end def items if @channel @channel.items else [] end end def image if @channel @channel.image else nil end end def textinput if @channel @channel.textInput else nil end end def setup_maker_elements(maker) super items.each do |item| item.setup_maker(maker.items) end image.setup_maker(maker) if image textinput.setup_maker(maker) if textinput end private def _attrs [ ["version", true, "feed_version"], ] end class Channel < Element include RSS09 [ ["title", nil, :text], ["link", nil, :text], ["description", nil, :text], ["language", nil, :text], ["copyright", "?", :text], ["managingEditor", "?", :text], ["webMaster", "?", :text], ["rating", "?", :text], ["pubDate", "?", :date, :rfc822], ["lastBuildDate", "?", :date, :rfc822], ["docs", "?", :text], ["cloud", "?", :have_attribute], ["skipDays", "?", :have_child], ["skipHours", "?", :have_child], ["image", nil, :have_child], ["item", "*", :have_children], ["textInput", "?", :have_child], ].each do |name, occurs, type, *args| __send__("install_#{type}_element", name, "", occurs, name, *args) end alias date pubDate alias date= pubDate= private def maker_target(maker) maker.channel end def setup_maker_elements(channel) super [ [skipDays, "day"], [skipHours, "hour"], ].each do |skip, key| if skip skip.__send__("#{key}s").each do |val| target_skips = channel.__send__("skip#{key.capitalize}s") new_target = target_skips.__send__("new_#{key}") new_target.content = val.content end end end end def not_need_to_call_setup_maker_variables %w(image textInput) end class SkipDays < Element include RSS09 [ ["day", "*"] ].each do |name, occurs| install_have_children_element(name, "", occurs) end class Day < Element include RSS09 content_setup def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.content = args[0] end end end end class SkipHours < Element include RSS09 [ ["hour", "*"] ].each do |name, occurs| install_have_children_element(name, "", occurs) end class Hour < Element include RSS09 content_setup(:integer) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.content = args[0] end end end end class Image < Element include RSS09 %w(url title link).each do |name| install_text_element(name, "", nil) end [ ["width", :integer], ["height", :integer], ["description"], ].each do |name, type| install_text_element(name, "", "?", name, type) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.url = args[0] self.title = args[1] self.link = args[2] self.width = args[3] self.height = args[4] self.description = args[5] end end private def maker_target(maker) maker.image end end class Cloud < Element include RSS09 [ ["domain", "", true], ["port", "", true, :integer], ["path", "", true], ["registerProcedure", "", true], ["protocol", "", true], ].each do |name, uri, required, type| install_get_attribute(name, uri, required, type) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.domain = args[0] self.port = args[1] self.path = args[2] self.registerProcedure = args[3] self.protocol = args[4] end end end class Item < Element include RSS09 [ ["title", '?', :text], ["link", '?', :text], ["description", '?', :text], ["category", '*', :have_children, "categories"], ["source", '?', :have_child], ["enclosure", '?', :have_child], ].each do |tag, occurs, type, *args| __send__("install_#{type}_element", tag, "", occurs, tag, *args) end private def maker_target(items) if items.respond_to?("items") # For backward compatibility items = items.items end items.new_item end def setup_maker_element(item) super @enclosure.setup_maker(item) if @enclosure @source.setup_maker(item) if @source end class Source < Element include RSS09 [ ["url", "", true] ].each do |name, uri, required| install_get_attribute(name, uri, required) end content_setup def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.url = args[0] self.content = args[1] end end private def maker_target(item) item.source end def setup_maker_attributes(source) source.url = url source.content = content end end class Enclosure < Element include RSS09 [ ["url", "", true], ["length", "", true, :integer], ["type", "", true], ].each do |name, uri, required, type| install_get_attribute(name, uri, required, type) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.url = args[0] self.length = args[1] self.type = args[2] end end private def maker_target(item) item.enclosure end def setup_maker_attributes(enclosure) enclosure.url = url enclosure.length = length enclosure.type = type end end class Category < Element include RSS09 [ ["domain", "", false] ].each do |name, uri, required| install_get_attribute(name, uri, required) end content_setup def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.domain = args[0] self.content = args[1] end end private def maker_target(item) item.new_category end def setup_maker_attributes(category) category.domain = domain category.content = content end end end class TextInput < Element include RSS09 %w(title description name link).each do |name| install_text_element(name, "", nil) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.title = args[0] self.description = args[1] self.name = args[2] self.link = args[3] end end private def maker_target(maker) maker.textinput end end end end RSS09::ELEMENTS.each do |name| BaseListener.install_get_text_element("", name, name) end module ListenerMixin private def initial_start_rss(tag_name, prefix, attrs, ns) check_ns(tag_name, prefix, ns, "") @rss = Rss.new(attrs['version'], @version, @encoding, @standalone) @rss.do_validate = @do_validate @rss.xml_stylesheets = @xml_stylesheets @last_element = @rss pr = Proc.new do |text, tags| @rss.validate_for_stream(tags, @ignore_unknown_element) if @do_validate end @proc_stack.push(pr) end end end ================================================ FILE: lib/rss/1.0.rb ================================================ require "rss/parser" module RSS module RSS10 NSPOOL = {} ELEMENTS = [] def self.append_features(klass) super klass.install_must_call_validator('', ::RSS::URI) end end class RDF < Element include RSS10 include RootElementMixin class << self def required_uri URI end end @tag_name = 'RDF' PREFIX = 'rdf' URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" install_ns('', ::RSS::URI) install_ns(PREFIX, URI) [ ["channel", nil], ["image", "?"], ["item", "+", :children], ["textinput", "?"], ].each do |tag, occurs, type| type ||= :child __send__("install_have_#{type}_element", tag, ::RSS::URI, occurs) end alias_method(:rss_version, :feed_version) def initialize(version=nil, encoding=nil, standalone=nil) super('1.0', version, encoding, standalone) @feed_type = "rss" end def full_name tag_name_with_prefix(PREFIX) end class Li < Element include RSS10 class << self def required_uri URI end end [ ["resource", [URI, ""], true] ].each do |name, uri, required| install_get_attribute(name, uri, required) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.resource = args[0] end end def full_name tag_name_with_prefix(PREFIX) end end class Seq < Element include RSS10 Li = ::RSS::RDF::Li class << self def required_uri URI end end @tag_name = 'Seq' install_have_children_element("li", URI, "*") install_must_call_validator('rdf', ::RSS::RDF::URI) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() @li = args[0] if args[0] end end def full_name tag_name_with_prefix(PREFIX) end def setup_maker(target) lis.each do |li| target << li.resource end end end class Bag < Element include RSS10 Li = ::RSS::RDF::Li class << self def required_uri URI end end @tag_name = 'Bag' install_have_children_element("li", URI, "*") install_must_call_validator('rdf', URI) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() @li = args[0] if args[0] end end def full_name tag_name_with_prefix(PREFIX) end def setup_maker(target) lis.each do |li| target << li.resource end end end class Channel < Element include RSS10 class << self def required_uri ::RSS::URI end end [ ["about", URI, true] ].each do |name, uri, required| install_get_attribute(name, uri, required, nil, nil, "#{PREFIX}:#{name}") end [ ['title', nil, :text], ['link', nil, :text], ['description', nil, :text], ['image', '?', :have_child], ['items', nil, :have_child], ['textinput', '?', :have_child], ].each do |tag, occurs, type| __send__("install_#{type}_element", tag, ::RSS::URI, occurs) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.about = args[0] end end private def maker_target(maker) maker.channel end def setup_maker_attributes(channel) channel.about = about end class Image < Element include RSS10 class << self def required_uri ::RSS::URI end end [ ["resource", URI, true] ].each do |name, uri, required| install_get_attribute(name, uri, required, nil, nil, "#{PREFIX}:#{name}") end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.resource = args[0] end end end class Textinput < Element include RSS10 class << self def required_uri ::RSS::URI end end [ ["resource", URI, true] ].each do |name, uri, required| install_get_attribute(name, uri, required, nil, nil, "#{PREFIX}:#{name}") end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.resource = args[0] end end end class Items < Element include RSS10 Seq = ::RSS::RDF::Seq class << self def required_uri ::RSS::URI end end install_have_child_element("Seq", URI, nil) install_must_call_validator('rdf', URI) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.Seq = args[0] end self.Seq ||= Seq.new end def resources if @Seq @Seq.lis.collect do |li| li.resource end else [] end end end end class Image < Element include RSS10 class << self def required_uri ::RSS::URI end end [ ["about", URI, true] ].each do |name, uri, required| install_get_attribute(name, uri, required, nil, nil, "#{PREFIX}:#{name}") end %w(title url link).each do |name| install_text_element(name, ::RSS::URI, nil) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.about = args[0] end end private def maker_target(maker) maker.image end end class Item < Element include RSS10 class << self def required_uri ::RSS::URI end end [ ["about", URI, true] ].each do |name, uri, required| install_get_attribute(name, uri, required, nil, nil, "#{PREFIX}:#{name}") end [ ["title", nil], ["link", nil], ["description", "?"], ].each do |tag, occurs| install_text_element(tag, ::RSS::URI, occurs) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.about = args[0] end end private def maker_target(items) if items.respond_to?("items") # For backward compatibility items = items.items end items.new_item end end class Textinput < Element include RSS10 class << self def required_uri ::RSS::URI end end [ ["about", URI, true] ].each do |name, uri, required| install_get_attribute(name, uri, required, nil, nil, "#{PREFIX}:#{name}") end %w(title description name link).each do |name| install_text_element(name, ::RSS::URI, nil) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.about = args[0] end end private def maker_target(maker) maker.textinput end end end RSS10::ELEMENTS.each do |name| BaseListener.install_get_text_element(URI, name, name) end module ListenerMixin private def initial_start_RDF(tag_name, prefix, attrs, ns) check_ns(tag_name, prefix, ns, RDF::URI) @rss = RDF.new(@version, @encoding, @standalone) @rss.do_validate = @do_validate @rss.xml_stylesheets = @xml_stylesheets @last_element = @rss pr = Proc.new do |text, tags| @rss.validate_for_stream(tags, @ignore_unknown_element) if @do_validate end @proc_stack.push(pr) end end end ================================================ FILE: lib/rss/2.0.rb ================================================ require "rss/0.9" module RSS class Rss class Channel [ ["generator"], ["ttl", :integer], ].each do |name, type| install_text_element(name, "", "?", name, type) end [ %w(category categories), ].each do |name, plural_name| install_have_children_element(name, "", "*", name, plural_name) end [ ["image", "?"], ["language", "?"], ].each do |name, occurs| install_model(name, "", occurs) end Category = Item::Category class Item [ ["comments", "?"], ["author", "?"], ].each do |name, occurs| install_text_element(name, "", occurs) end [ ["pubDate", '?'], ].each do |name, occurs| install_date_element(name, "", occurs, name, 'rfc822') end alias date pubDate alias date= pubDate= [ ["guid", '?'], ].each do |name, occurs| install_have_child_element(name, "", occurs) end private alias _setup_maker_element setup_maker_element def setup_maker_element(item) _setup_maker_element(item) @guid.setup_maker(item) if @guid end class Guid < Element include RSS09 [ ["isPermaLink", "", false, :boolean] ].each do |name, uri, required, type| install_get_attribute(name, uri, required, type) end content_setup def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.isPermaLink = args[0] self.content = args[1] end end alias_method :_PermaLink?, :PermaLink? private :_PermaLink? def PermaLink? perma = _PermaLink? perma or perma.nil? end private def maker_target(item) item.guid end def setup_maker_attributes(guid) guid.isPermaLink = isPermaLink guid.content = content end end end end end RSS09::ELEMENTS.each do |name| BaseListener.install_get_text_element("", name, name) end end ================================================ FILE: lib/rss/atom.rb ================================================ require 'base64' require 'rss/parser' module RSS module Atom URI = "http://www.w3.org/2005/Atom" XHTML_URI = "http://www.w3.org/1999/xhtml" module CommonModel NSPOOL = {} ELEMENTS = [] def self.append_features(klass) super klass.install_must_call_validator("atom", URI) [ ["lang", :xml], ["base", :xml], ].each do |name, uri, required| klass.install_get_attribute(name, uri, required, [nil, :inherit]) end klass.class_eval do class << self def required_uri URI end def need_parent? true end end end end end module ContentModel module ClassMethods def content_type @content_type ||= nil end end class << self def append_features(klass) super klass.extend(ClassMethods) klass.content_setup(klass.content_type, klass.tag_name) end end def maker_target(target) target end private def setup_maker_element_writer "#{self.class.name.split(/::/).last.downcase}=" end def setup_maker_element(target) target.__send__(setup_maker_element_writer, content) super end end module URIContentModel class << self def append_features(klass) super klass.class_eval do @content_type = [nil, :uri] include(ContentModel) end end end end module TextConstruct def self.append_features(klass) super klass.class_eval do [ ["type", ""], ].each do |name, uri, required| install_get_attribute(name, uri, required, :text_type) end content_setup add_need_initialize_variable("xhtml") class << self def xml_getter "xhtml" end def xml_setter "xhtml=" end end end end attr_writer :xhtml def xhtml return @xhtml if @xhtml.nil? if @xhtml.is_a?(XML::Element) and [@xhtml.name, @xhtml.uri] == ["div", XHTML_URI] return @xhtml end children = @xhtml children = [children] unless children.is_a?(Array) XML::Element.new("div", nil, XHTML_URI, {"xmlns" => XHTML_URI}, children) end def have_xml_content? @type == "xhtml" end def atom_validate(ignore_unknown_element, tags, uri) if have_xml_content? if @xhtml.nil? raise MissingTagError.new("div", tag_name) end unless [@xhtml.name, @xhtml.uri] == ["div", XHTML_URI] raise NotExpectedTagError.new(@xhtml.name, @xhtml.uri, tag_name) end end end private def maker_target(target) target.__send__(self.class.name.split(/::/).last.downcase) {|x| x} end def setup_maker_attributes(target) target.type = type target.content = content target.xml_content = @xhtml end end module PersonConstruct def self.append_features(klass) super klass.class_eval do [ ["name", nil], ["uri", "?"], ["email", "?"], ].each do |tag, occurs| install_have_attribute_element(tag, URI, occurs, nil, :content) end end end def maker_target(target) target.__send__("new_#{self.class.name.split(/::/).last.downcase}") end class Name < RSS::Element include CommonModel include ContentModel end class Uri < RSS::Element include CommonModel include URIContentModel end class Email < RSS::Element include CommonModel include ContentModel end end module DateConstruct def self.append_features(klass) super klass.class_eval do @content_type = :w3cdtf include(ContentModel) end end def atom_validate(ignore_unknown_element, tags, uri) raise NotAvailableValueError.new(tag_name, "") if content.nil? end end module DuplicateLinkChecker def validate_duplicate_links(links) link_infos = {} links.each do |link| rel = link.rel || "alternate" next unless rel == "alternate" key = [link.hreflang, link.type] if link_infos.has_key?(key) raise TooMuchTagError.new("link", tag_name) end link_infos[key] = true end end end class Feed < RSS::Element include RootElementMixin include CommonModel include DuplicateLinkChecker install_ns('', URI) [ ["author", "*", :children], ["category", "*", :children, "categories"], ["contributor", "*", :children], ["generator", "?"], ["icon", "?", nil, :content], ["id", nil, nil, :content], ["link", "*", :children], ["logo", "?"], ["rights", "?"], ["subtitle", "?", nil, :content], ["title", nil, nil, :content], ["updated", nil, nil, :content], ["entry", "*", :children, "entries"], ].each do |tag, occurs, type, *args| type ||= :child __send__("install_have_#{type}_element", tag, URI, occurs, tag, *args) end def initialize(version=nil, encoding=nil, standalone=nil) super("1.0", version, encoding, standalone) @feed_type = "atom" @feed_subtype = "feed" end alias_method :items, :entries def have_author? authors.any? {|author| !author.to_s.empty?} or entries.any? {|entry| entry.have_author?(false)} end private def atom_validate(ignore_unknown_element, tags, uri) unless have_author? raise MissingTagError.new("author", tag_name) end validate_duplicate_links(links) end def have_required_elements? super and have_author? end def maker_target(maker) maker.channel end def setup_maker_element(channel) prev_dc_dates = channel.dc_dates.to_a.dup super channel.about = id.content if id channel.dc_dates.replace(prev_dc_dates) end def setup_maker_elements(channel) super items = channel.maker.items entries.each do |entry| entry.setup_maker(items) end end class Author < RSS::Element include CommonModel include PersonConstruct end class Category < RSS::Element include CommonModel [ ["term", "", true], ["scheme", "", false, [nil, :uri]], ["label", ""], ].each do |name, uri, required, type| install_get_attribute(name, uri, required, type) end private def maker_target(target) target.new_category end end class Contributor < RSS::Element include CommonModel include PersonConstruct end class Generator < RSS::Element include CommonModel include ContentModel [ ["uri", "", false, [nil, :uri]], ["version", ""], ].each do |name, uri, required, type| install_get_attribute(name, uri, required, type) end private def setup_maker_attributes(target) target.generator do |generator| generator.uri = uri if uri generator.version = version if version end end end class Icon < RSS::Element include CommonModel include URIContentModel end class Id < RSS::Element include CommonModel include URIContentModel end class Link < RSS::Element include CommonModel [ ["href", "", true, [nil, :uri]], ["rel", ""], ["type", ""], ["hreflang", ""], ["title", ""], ["length", ""], ].each do |name, uri, required, type| install_get_attribute(name, uri, required, type) end private def maker_target(target) target.new_link end end class Logo < RSS::Element include CommonModel include URIContentModel def maker_target(target) target.maker.image end private def setup_maker_element_writer "url=" end end class Rights < RSS::Element include CommonModel include TextConstruct end class Subtitle < RSS::Element include CommonModel include TextConstruct end class Title < RSS::Element include CommonModel include TextConstruct end class Updated < RSS::Element include CommonModel include DateConstruct end class Entry < RSS::Element include CommonModel include DuplicateLinkChecker [ ["author", "*", :children], ["category", "*", :children, "categories"], ["content", "?", :child], ["contributor", "*", :children], ["id", nil, nil, :content], ["link", "*", :children], ["published", "?", :child, :content], ["rights", "?", :child], ["source", "?"], ["summary", "?", :child], ["title", nil], ["updated", nil, :child, :content], ].each do |tag, occurs, type, *args| type ||= :attribute __send__("install_have_#{type}_element", tag, URI, occurs, tag, *args) end def have_author?(check_parent=true) authors.any? {|author| !author.to_s.empty?} or (check_parent and @parent and @parent.have_author?) or (source and source.have_author?) end private def atom_validate(ignore_unknown_element, tags, uri) unless have_author? raise MissingTagError.new("author", tag_name) end validate_duplicate_links(links) end def have_required_elements? super and have_author? end def maker_target(items) if items.respond_to?("items") # For backward compatibility items = items.items end items.new_item end Author = Feed::Author Category = Feed::Category class Content < RSS::Element include CommonModel class << self def xml_setter "xml=" end def xml_getter "xml" end end [ ["type", ""], ["src", "", false, [nil, :uri]], ].each do |name, uri, required, type| install_get_attribute(name, uri, required, type) end content_setup add_need_initialize_variable("xml") attr_writer :xml def have_xml_content? inline_xhtml? or inline_other_xml? end def xml return @xml unless inline_xhtml? return @xml if @xml.nil? if @xml.is_a?(XML::Element) and [@xml.name, @xml.uri] == ["div", XHTML_URI] return @xml end children = @xml children = [children] unless children.is_a?(Array) XML::Element.new("div", nil, XHTML_URI, {"xmlns" => XHTML_URI}, children) end def xhtml if inline_xhtml? xml else nil end end def atom_validate(ignore_unknown_element, tags, uri) if out_of_line? raise MissingAttributeError.new(tag_name, "type") if @type.nil? unless (content.nil? or content.empty?) raise NotAvailableValueError.new(tag_name, content) end elsif inline_xhtml? if @xml.nil? raise MissingTagError.new("div", tag_name) end unless @xml.name == "div" and @xml.uri == XHTML_URI raise NotExpectedTagError.new(@xml.name, @xml.uri, tag_name) end end end def inline_text? !out_of_line? and [nil, "text", "html"].include?(@type) end def inline_html? return false if out_of_line? @type == "html" or mime_split == ["text", "html"] end def inline_xhtml? !out_of_line? and @type == "xhtml" end def inline_other? return false if out_of_line? media_type, subtype = mime_split return false if media_type.nil? or subtype.nil? true end def inline_other_text? return false unless inline_other? return false if inline_other_xml? media_type, subtype = mime_split return true if "text" == media_type.downcase false end def inline_other_xml? return false unless inline_other? media_type, subtype = mime_split normalized_mime_type = "#{media_type}/#{subtype}".downcase if /(?:\+xml|^xml)$/ =~ subtype or %w(text/xml-external-parsed-entity application/xml-external-parsed-entity application/xml-dtd).find {|x| x == normalized_mime_type} return true end false end def inline_other_base64? inline_other? and !inline_other_text? and !inline_other_xml? end def out_of_line? not @src.nil? end def mime_split media_type = subtype = nil if /\A\s*([a-z]+)\/([a-z\+]+)\s*(?:;.*)?\z/i =~ @type.to_s media_type = $1.downcase subtype = $2.downcase end [media_type, subtype] end def need_base64_encode? inline_other_base64? end private def empty_content? out_of_line? or super end end Contributor = Feed::Contributor Id = Feed::Id Link = Feed::Link class Published < RSS::Element include CommonModel include DateConstruct end Rights = Feed::Rights class Source < RSS::Element include CommonModel [ ["author", "*", :children], ["category", "*", :children, "categories"], ["contributor", "*", :children], ["generator", "?"], ["icon", "?"], ["id", "?", nil, :content], ["link", "*", :children], ["logo", "?"], ["rights", "?"], ["subtitle", "?"], ["title", "?"], ["updated", "?", nil, :content], ].each do |tag, occurs, type, *args| type ||= :attribute __send__("install_have_#{type}_element", tag, URI, occurs, tag, *args) end def have_author? !author.to_s.empty? end Author = Feed::Author Category = Feed::Category Contributor = Feed::Contributor Generator = Feed::Generator Icon = Feed::Icon Id = Feed::Id Link = Feed::Link Logo = Feed::Logo Rights = Feed::Rights Subtitle = Feed::Subtitle Title = Feed::Title Updated = Feed::Updated end class Summary < RSS::Element include CommonModel include TextConstruct end Title = Feed::Title Updated = Feed::Updated end end class Entry < RSS::Element include RootElementMixin include CommonModel include DuplicateLinkChecker [ ["author", "*", :children], ["category", "*", :children, "categories"], ["content", "?"], ["contributor", "*", :children], ["id", nil, nil, :content], ["link", "*", :children], ["published", "?", :child, :content], ["rights", "?"], ["source", "?"], ["summary", "?"], ["title", nil], ["updated", nil, nil, :content], ].each do |tag, occurs, type, *args| type ||= :attribute __send__("install_have_#{type}_element", tag, URI, occurs, tag, *args) end def initialize(version=nil, encoding=nil, standalone=nil) super("1.0", version, encoding, standalone) @feed_type = "atom" @feed_subtype = "entry" end def items [self] end def setup_maker(maker) maker = maker.maker if maker.respond_to?("maker") super(maker) end def have_author? authors.any? {|author| !author.to_s.empty?} or (source and source.have_author?) end private def atom_validate(ignore_unknown_element, tags, uri) unless have_author? raise MissingTagError.new("author", tag_name) end validate_duplicate_links(links) end def have_required_elements? super and have_author? end def maker_target(maker) maker.items.new_item end Author = Feed::Entry::Author Category = Feed::Entry::Category Content = Feed::Entry::Content Contributor = Feed::Entry::Contributor Id = Feed::Entry::Id Link = Feed::Entry::Link Published = Feed::Entry::Published Rights = Feed::Entry::Rights Source = Feed::Entry::Source Summary = Feed::Entry::Summary Title = Feed::Entry::Title Updated = Feed::Entry::Updated end end Atom::CommonModel::ELEMENTS.each do |name| BaseListener.install_get_text_element(Atom::URI, name, "#{name}=") end module ListenerMixin private def initial_start_feed(tag_name, prefix, attrs, ns) check_ns(tag_name, prefix, ns, Atom::URI) @rss = Atom::Feed.new(@version, @encoding, @standalone) @rss.do_validate = @do_validate @rss.xml_stylesheets = @xml_stylesheets @rss.lang = attrs["xml:lang"] @rss.base = attrs["xml:base"] @last_element = @rss pr = Proc.new do |text, tags| @rss.validate_for_stream(tags) if @do_validate end @proc_stack.push(pr) end def initial_start_entry(tag_name, prefix, attrs, ns) check_ns(tag_name, prefix, ns, Atom::URI) @rss = Atom::Entry.new(@version, @encoding, @standalone) @rss.do_validate = @do_validate @rss.xml_stylesheets = @xml_stylesheets @rss.lang = attrs["xml:lang"] @rss.base = attrs["xml:base"] @last_element = @rss pr = Proc.new do |text, tags| @rss.validate_for_stream(tags) if @do_validate end @proc_stack.push(pr) end end end ================================================ FILE: lib/rss/content/1.0.rb ================================================ require 'rss/1.0' require 'rss/content' module RSS RDF.install_ns(CONTENT_PREFIX, CONTENT_URI) class RDF class Item; include ContentModel; end end end ================================================ FILE: lib/rss/content/2.0.rb ================================================ require "rss/2.0" require "rss/content" module RSS Rss.install_ns(CONTENT_PREFIX, CONTENT_URI) class Rss class Channel class Item; include ContentModel; end end end end ================================================ FILE: lib/rss/content.rb ================================================ require "rss/rss" module RSS CONTENT_PREFIX = 'content' CONTENT_URI = "http://purl.org/rss/1.0/modules/content/" module ContentModel extend BaseModel ELEMENTS = ["#{CONTENT_PREFIX}_encoded"] def self.append_features(klass) super klass.install_must_call_validator(CONTENT_PREFIX, CONTENT_URI) ELEMENTS.each do |full_name| name = full_name[(CONTENT_PREFIX.size + 1)..-1] klass.install_text_element(name, CONTENT_URI, "?", full_name) end end end prefix_size = CONTENT_PREFIX.size + 1 ContentModel::ELEMENTS.each do |full_name| name = full_name[prefix_size..-1] BaseListener.install_get_text_element(CONTENT_URI, name, full_name) end end require 'rss/content/1.0' require 'rss/content/2.0' ================================================ FILE: lib/rss/converter.rb ================================================ require "rss/utils" module RSS class Converter include Utils def initialize(to_enc, from_enc=nil) normalized_to_enc = to_enc.downcase.gsub(/-/, '_') from_enc ||= 'utf-8' normalized_from_enc = from_enc.downcase.gsub(/-/, '_') if normalized_to_enc == normalized_from_enc def_same_enc() else def_diff_enc = "def_to_#{normalized_to_enc}_from_#{normalized_from_enc}" if respond_to?(def_diff_enc) __send__(def_diff_enc) else def_else_enc(to_enc, from_enc) end end end def convert(value) value end def def_convert(depth=0) instance_eval(<<-EOC, *get_file_and_line_from_caller(depth)) def convert(value) if value.kind_of?(String) #{yield('value')} else value end end EOC end def def_iconv_convert(to_enc, from_enc, depth=0) begin require "iconv" @iconv = Iconv.new(to_enc, from_enc) def_convert(depth+1) do |value| <<-EOC begin @iconv.iconv(#{value}) rescue Iconv::Failure raise ConversionError.new(#{value}, "#{to_enc}", "#{from_enc}") end EOC end rescue LoadError, ArgumentError, SystemCallError raise UnknownConversionMethodError.new(to_enc, from_enc) end end def def_else_enc(to_enc, from_enc) def_iconv_convert(to_enc, from_enc, 0) end def def_same_enc() def_convert do |value| value end end def def_uconv_convert_if_can(meth, to_enc, from_enc, nkf_arg) begin require "uconv" def_convert(1) do |value| <<-EOC begin Uconv.#{meth}(#{value}) rescue Uconv::Error raise ConversionError.new(#{value}, "#{to_enc}", "#{from_enc}") end EOC end rescue LoadError require 'nkf' if NKF.const_defined?(:UTF8) def_convert(1) do |value| "NKF.nkf(#{nkf_arg.dump}, #{value})" end else def_iconv_convert(to_enc, from_enc, 1) end end end def def_to_euc_jp_from_utf_8 def_uconv_convert_if_can('u8toeuc', 'EUC-JP', 'UTF-8', '-We') end def def_to_utf_8_from_euc_jp def_uconv_convert_if_can('euctou8', 'UTF-8', 'EUC-JP', '-Ew') end def def_to_shift_jis_from_utf_8 def_uconv_convert_if_can('u8tosjis', 'Shift_JIS', 'UTF-8', '-Ws') end def def_to_utf_8_from_shift_jis def_uconv_convert_if_can('sjistou8', 'UTF-8', 'Shift_JIS', '-Sw') end def def_to_euc_jp_from_shift_jis require "nkf" def_convert do |value| "NKF.nkf('-Se', #{value})" end end def def_to_shift_jis_from_euc_jp require "nkf" def_convert do |value| "NKF.nkf('-Es', #{value})" end end def def_to_euc_jp_from_iso_2022_jp require "nkf" def_convert do |value| "NKF.nkf('-Je', #{value})" end end def def_to_iso_2022_jp_from_euc_jp require "nkf" def_convert do |value| "NKF.nkf('-Ej', #{value})" end end def def_to_utf_8_from_iso_8859_1 def_convert do |value| "#{value}.unpack('C*').pack('U*')" end end def def_to_iso_8859_1_from_utf_8 def_convert do |value| <<-EOC array_utf8 = #{value}.unpack('U*') array_enc = [] array_utf8.each do |num| if num <= 0xFF array_enc << num else array_enc.concat "&\#\#{num};".unpack('C*') end end array_enc.pack('C*') EOC end end end end ================================================ FILE: lib/rss/dublincore/1.0.rb ================================================ require "rss/1.0" require "rss/dublincore" module RSS RDF.install_ns(DC_PREFIX, DC_URI) class RDF class Channel; include DublinCoreModel; end class Image; include DublinCoreModel; end class Item; include DublinCoreModel; end class Textinput; include DublinCoreModel; end end end ================================================ FILE: lib/rss/dublincore/2.0.rb ================================================ require "rss/2.0" require "rss/dublincore" module RSS Rss.install_ns(DC_PREFIX, DC_URI) class Rss class Channel include DublinCoreModel class Item; include DublinCoreModel; end end end end ================================================ FILE: lib/rss/dublincore/atom.rb ================================================ require "rss/atom" require "rss/dublincore" module RSS module Atom Feed.install_ns(DC_PREFIX, DC_URI) class Feed include DublinCoreModel class Entry; include DublinCoreModel; end end class Entry include DublinCoreModel end end end ================================================ FILE: lib/rss/dublincore.rb ================================================ require "rss/rss" module RSS DC_PREFIX = 'dc' DC_URI = "http://purl.org/dc/elements/1.1/" module BaseDublinCoreModel def append_features(klass) super return if klass.instance_of?(Module) DublinCoreModel::ELEMENT_NAME_INFOS.each do |name, plural_name| plural = plural_name || "#{name}s" full_name = "#{DC_PREFIX}_#{name}" full_plural_name = "#{DC_PREFIX}_#{plural}" klass_name = "DublinCore#{Utils.to_class_name(name)}" klass.install_must_call_validator(DC_PREFIX, DC_URI) klass.install_have_children_element(name, DC_URI, "*", full_name, full_plural_name) klass.module_eval(<<-EOC, *get_file_and_line_from_caller(0)) remove_method :#{full_name} remove_method :#{full_name}= remove_method :set_#{full_name} def #{full_name} @#{full_name}.first and @#{full_name}.first.value end def #{full_name}=(new_value) @#{full_name}[0] = Utils.new_with_value_if_need(#{klass_name}, new_value) end alias set_#{full_name} #{full_name}= EOC end klass.module_eval(<<-EOC, *get_file_and_line_from_caller(0)) if method_defined?(:date) alias date_without_#{DC_PREFIX}_date= date= def date=(value) self.date_without_#{DC_PREFIX}_date = value self.#{DC_PREFIX}_date = value end else alias date #{DC_PREFIX}_date alias date= #{DC_PREFIX}_date= end # For backward compatibility alias #{DC_PREFIX}_rightses #{DC_PREFIX}_rights_list EOC end end module DublinCoreModel extend BaseModel extend BaseDublinCoreModel TEXT_ELEMENTS = { "title" => nil, "description" => nil, "creator" => nil, "subject" => nil, "publisher" => nil, "contributor" => nil, "type" => nil, "format" => nil, "identifier" => nil, "source" => nil, "language" => nil, "relation" => nil, "coverage" => nil, "rights" => "rights_list" } DATE_ELEMENTS = { "date" => "w3cdtf", } ELEMENT_NAME_INFOS = DublinCoreModel::TEXT_ELEMENTS.to_a DublinCoreModel::DATE_ELEMENTS.each do |name, | ELEMENT_NAME_INFOS << [name, nil] end ELEMENTS = TEXT_ELEMENTS.keys + DATE_ELEMENTS.keys ELEMENTS.each do |name, plural_name| module_eval(<<-EOC, *get_file_and_line_from_caller(0)) class DublinCore#{Utils.to_class_name(name)} < Element include RSS10 content_setup class << self def required_prefix DC_PREFIX end def required_uri DC_URI end end @tag_name = #{name.dump} alias_method(:value, :content) alias_method(:value=, :content=) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.content = args[0] end end def full_name tag_name_with_prefix(DC_PREFIX) end def maker_target(target) target.new_#{name} end def setup_maker_attributes(#{name}) #{name}.content = content end end EOC end DATE_ELEMENTS.each do |name, type| tag_name = "#{DC_PREFIX}:#{name}" module_eval(<<-EOC, *get_file_and_line_from_caller(0)) class DublinCore#{Utils.to_class_name(name)} < Element remove_method(:content=) remove_method(:value=) date_writer("content", #{type.dump}, #{tag_name.dump}) alias_method(:value=, :content=) end EOC end end # For backward compatibility DublincoreModel = DublinCoreModel DublinCoreModel::ELEMENTS.each do |name| class_name = Utils.to_class_name(name) BaseListener.install_class_name(DC_URI, name, "DublinCore#{class_name}") end DublinCoreModel::ELEMENTS.collect! {|name| "#{DC_PREFIX}_#{name}"} end require 'rss/dublincore/1.0' require 'rss/dublincore/2.0' require 'rss/dublincore/atom' ================================================ FILE: lib/rss/image.rb ================================================ require 'rss/1.0' require 'rss/dublincore' module RSS IMAGE_PREFIX = 'image' IMAGE_URI = 'http://purl.org/rss/1.0/modules/image/' RDF.install_ns(IMAGE_PREFIX, IMAGE_URI) IMAGE_ELEMENTS = [] %w(item favicon).each do |name| class_name = Utils.to_class_name(name) BaseListener.install_class_name(IMAGE_URI, name, "Image#{class_name}") IMAGE_ELEMENTS << "#{IMAGE_PREFIX}_#{name}" end module ImageModelUtils def validate_one_tag_name(ignore_unknown_element, name, tags) if !ignore_unknown_element invalid = tags.find {|tag| tag != name} raise UnknownTagError.new(invalid, IMAGE_URI) if invalid end raise TooMuchTagError.new(name, tag_name) if tags.size > 1 end end module ImageItemModel include ImageModelUtils extend BaseModel def self.append_features(klass) super klass.install_have_child_element("item", IMAGE_URI, "?", "#{IMAGE_PREFIX}_item") klass.install_must_call_validator(IMAGE_PREFIX, IMAGE_URI) end class ImageItem < Element include RSS10 include DublinCoreModel @tag_name = "item" class << self def required_prefix IMAGE_PREFIX end def required_uri IMAGE_URI end end install_must_call_validator(IMAGE_PREFIX, IMAGE_URI) [ ["about", ::RSS::RDF::URI, true], ["resource", ::RSS::RDF::URI, false], ].each do |name, uri, required| install_get_attribute(name, uri, required, nil, nil, "#{::RSS::RDF::PREFIX}:#{name}") end %w(width height).each do |tag| full_name = "#{IMAGE_PREFIX}_#{tag}" disp_name = "#{IMAGE_PREFIX}:#{tag}" install_text_element(tag, IMAGE_URI, "?", full_name, :integer, disp_name) BaseListener.install_get_text_element(IMAGE_URI, tag, full_name) end alias width= image_width= alias width image_width alias height= image_height= alias height image_height def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.about = args[0] self.resource = args[1] end end def full_name tag_name_with_prefix(IMAGE_PREFIX) end private def maker_target(target) target.image_item end def setup_maker_attributes(item) item.about = self.about item.resource = self.resource end end end module ImageFaviconModel include ImageModelUtils extend BaseModel def self.append_features(klass) super unless klass.class == Module klass.install_have_child_element("favicon", IMAGE_URI, "?", "#{IMAGE_PREFIX}_favicon") klass.install_must_call_validator(IMAGE_PREFIX, IMAGE_URI) end end class ImageFavicon < Element include RSS10 include DublinCoreModel @tag_name = "favicon" class << self def required_prefix IMAGE_PREFIX end def required_uri IMAGE_URI end end [ ["about", ::RSS::RDF::URI, true, ::RSS::RDF::PREFIX], ["size", IMAGE_URI, true, IMAGE_PREFIX], ].each do |name, uri, required, prefix| install_get_attribute(name, uri, required, nil, nil, "#{prefix}:#{name}") end AVAILABLE_SIZES = %w(small medium large) alias_method :set_size, :size= private :set_size def size=(new_value) if @do_validate and !new_value.nil? new_value = new_value.strip unless AVAILABLE_SIZES.include?(new_value) attr_name = "#{IMAGE_PREFIX}:size" raise NotAvailableValueError.new(full_name, new_value, attr_name) end end set_size(new_value) end alias image_size= size= alias image_size size def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.about = args[0] self.size = args[1] end end def full_name tag_name_with_prefix(IMAGE_PREFIX) end private def maker_target(target) target.image_favicon end def setup_maker_attributes(favicon) favicon.about = self.about favicon.size = self.size end end end class RDF class Channel; include ImageFaviconModel; end class Item; include ImageItemModel; end end end ================================================ FILE: lib/rss/itunes.rb ================================================ require 'rss/2.0' module RSS ITUNES_PREFIX = 'itunes' ITUNES_URI = 'http://www.itunes.com/dtds/podcast-1.0.dtd' Rss.install_ns(ITUNES_PREFIX, ITUNES_URI) module ITunesModelUtils include Utils def def_class_accessor(klass, name, type, *args) normalized_name = name.gsub(/-/, "_") full_name = "#{ITUNES_PREFIX}_#{normalized_name}" klass_name = "ITunes#{Utils.to_class_name(normalized_name)}" case type when :element, :attribute klass::ELEMENTS << full_name def_element_class_accessor(klass, name, full_name, klass_name, *args) when :elements klass::ELEMENTS << full_name def_elements_class_accessor(klass, name, full_name, klass_name, *args) else klass.install_must_call_validator(ITUNES_PREFIX, ITUNES_URI) klass.install_text_element(normalized_name, ITUNES_URI, "?", full_name, type, name) end end def def_element_class_accessor(klass, name, full_name, klass_name, recommended_attribute_name=nil) klass.install_have_child_element(name, ITUNES_PREFIX, "?", full_name) end def def_elements_class_accessor(klass, name, full_name, klass_name, plural_name, recommended_attribute_name=nil) full_plural_name = "#{ITUNES_PREFIX}_#{plural_name}" klass.install_have_children_element(name, ITUNES_PREFIX, "*", full_name, full_plural_name) end end module ITunesBaseModel extend ITunesModelUtils ELEMENTS = [] ELEMENT_INFOS = [["author"], ["block", :yes_other], ["explicit", :yes_clean_other], ["keywords", :csv], ["subtitle"], ["summary"]] end module ITunesChannelModel extend BaseModel extend ITunesModelUtils include ITunesBaseModel ELEMENTS = [] class << self def append_features(klass) super return if klass.instance_of?(Module) ELEMENT_INFOS.each do |name, type, *additional_infos| def_class_accessor(klass, name, type, *additional_infos) end end end ELEMENT_INFOS = [ ["category", :elements, "categories", "text"], ["image", :attribute, "href"], ["owner", :element], ["new-feed-url"], ] + ITunesBaseModel::ELEMENT_INFOS class ITunesCategory < Element include RSS09 @tag_name = "category" class << self def required_prefix ITUNES_PREFIX end def required_uri ITUNES_URI end end [ ["text", "", true] ].each do |name, uri, required| install_get_attribute(name, uri, required) end ITunesCategory = self install_have_children_element("category", ITUNES_URI, "*", "#{ITUNES_PREFIX}_category", "#{ITUNES_PREFIX}_categories") def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.text = args[0] end end def full_name tag_name_with_prefix(ITUNES_PREFIX) end private def maker_target(categories) if text or !itunes_categories.empty? categories.new_category else nil end end def setup_maker_attributes(category) category.text = text if text end def setup_maker_elements(category) super(category) itunes_categories.each do |sub_category| sub_category.setup_maker(category) end end end class ITunesImage < Element include RSS09 @tag_name = "image" class << self def required_prefix ITUNES_PREFIX end def required_uri ITUNES_URI end end [ ["href", "", true] ].each do |name, uri, required| install_get_attribute(name, uri, required) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.href = args[0] end end def full_name tag_name_with_prefix(ITUNES_PREFIX) end private def maker_target(target) if href target.itunes_image {|image| image} else nil end end def setup_maker_attributes(image) image.href = href end end class ITunesOwner < Element include RSS09 @tag_name = "owner" class << self def required_prefix ITUNES_PREFIX end def required_uri ITUNES_URI end end install_must_call_validator(ITUNES_PREFIX, ITUNES_URI) [ ["name"], ["email"], ].each do |name,| ITunesBaseModel::ELEMENT_INFOS << name install_text_element(name, ITUNES_URI, nil, "#{ITUNES_PREFIX}_#{name}") end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.itunes_name = args[0] self.itunes_email = args[1] end end def full_name tag_name_with_prefix(ITUNES_PREFIX) end private def maker_target(target) target.itunes_owner end def setup_maker_element(owner) super(owner) owner.itunes_name = itunes_name owner.itunes_email = itunes_email end end end module ITunesItemModel extend BaseModel extend ITunesModelUtils include ITunesBaseModel class << self def append_features(klass) super return if klass.instance_of?(Module) ELEMENT_INFOS.each do |name, type| def_class_accessor(klass, name, type) end end end ELEMENT_INFOS = ITunesBaseModel::ELEMENT_INFOS + [["duration", :element, "content"]] class ITunesDuration < Element include RSS09 @tag_name = "duration" class << self def required_prefix ITUNES_PREFIX end def required_uri ITUNES_URI end def parse(duration, do_validate=true) if do_validate and /\A(?: \d?\d:[0-5]\d:[0-5]\d| [0-5]?\d:[0-5]\d )\z/x !~ duration raise ArgumentError, "must be one of HH:MM:SS, H:MM:SS, MM::SS, M:SS: " + duration.inspect end components = duration.split(':') components[3..-1] = nil if components.size > 3 components.unshift("00") until components.size == 3 components.collect do |component| component.to_i end end def construct(hour, minute, second) components = [minute, second] if components.include?(nil) nil else components.unshift(hour) if hour and hour > 0 components.collect do |component| "%02d" % component end.join(":") end end end content_setup alias_method(:value, :content) remove_method(:content=) attr_reader :hour, :minute, :second def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() args = args[0] if args.size == 1 and args[0].is_a?(Array) if args.size == 1 self.content = args[0] elsif args.size > 3 raise ArgumentError, "must be (do_validate, params), (content), " + "(minute, second), ([minute, second]), " + "(hour, minute, second) or ([hour, minute, second]): " + args.inspect else @second, @minute, @hour = args.reverse update_content end end end def content=(value) if value.nil? @content = nil elsif value.is_a?(self.class) self.content = value.content else begin @hour, @minute, @second = self.class.parse(value, @do_validate) rescue ArgumentError raise NotAvailableValueError.new(tag_name, value) end @content = value end end alias_method(:value=, :content=) def hour=(hour) @hour = @do_validate ? Integer(hour) : hour.to_i update_content hour end def minute=(minute) @minute = @do_validate ? Integer(minute) : minute.to_i update_content minute end def second=(second) @second = @do_validate ? Integer(second) : second.to_i update_content second end def full_name tag_name_with_prefix(ITUNES_PREFIX) end private def update_content @content = self.class.construct(hour, minute, second) end def maker_target(target) if @content target.itunes_duration {|duration| duration} else nil end end def setup_maker_element(duration) super(duration) duration.content = @content end end end class Rss class Channel include ITunesChannelModel class Item; include ITunesItemModel; end end end element_infos = ITunesChannelModel::ELEMENT_INFOS + ITunesItemModel::ELEMENT_INFOS element_infos.each do |name, type| case type when :element, :elements, :attribute class_name = Utils.to_class_name(name) BaseListener.install_class_name(ITUNES_URI, name, "ITunes#{class_name}") else accessor_base = "#{ITUNES_PREFIX}_#{name.gsub(/-/, '_')}" BaseListener.install_get_text_element(ITUNES_URI, name, accessor_base) end end end ================================================ FILE: lib/rss/maker/0.9.rb ================================================ require "rss/0.9" require "rss/maker/base" module RSS module Maker class RSS09 < RSSBase def initialize(feed_version="0.92") super @feed_type = "rss" end private def make_feed Rss.new(@feed_version, @version, @encoding, @standalone) end def setup_elements(rss) setup_channel(rss) end class Channel < ChannelBase def to_feed(rss) channel = Rss::Channel.new set = setup_values(channel) _not_set_required_variables = not_set_required_variables if _not_set_required_variables.empty? rss.channel = channel set_parent(channel, rss) setup_items(rss) setup_image(rss) setup_textinput(rss) setup_other_elements(rss, channel) rss else raise NotSetError.new("maker.channel", _not_set_required_variables) end end private def setup_items(rss) @maker.items.to_feed(rss) end def setup_image(rss) @maker.image.to_feed(rss) end def setup_textinput(rss) @maker.textinput.to_feed(rss) end def variables super + ["pubDate"] end def required_variable_names %w(link language) end def not_set_required_variables vars = super vars << "description" unless description {|d| d.have_required_values?} vars << "title" unless title {|t| t.have_required_values?} vars end class SkipDays < SkipDaysBase def to_feed(rss, channel) unless @days.empty? skipDays = Rss::Channel::SkipDays.new channel.skipDays = skipDays set_parent(skipDays, channel) @days.each do |day| day.to_feed(rss, skipDays.days) end end end class Day < DayBase def to_feed(rss, days) day = Rss::Channel::SkipDays::Day.new set = setup_values(day) if set days << day set_parent(day, days) setup_other_elements(rss, day) end end private def required_variable_names %w(content) end end end class SkipHours < SkipHoursBase def to_feed(rss, channel) unless @hours.empty? skipHours = Rss::Channel::SkipHours.new channel.skipHours = skipHours set_parent(skipHours, channel) @hours.each do |hour| hour.to_feed(rss, skipHours.hours) end end end class Hour < HourBase def to_feed(rss, hours) hour = Rss::Channel::SkipHours::Hour.new set = setup_values(hour) if set hours << hour set_parent(hour, hours) setup_other_elements(rss, hour) end end private def required_variable_names %w(content) end end end class Cloud < CloudBase def to_feed(*args) end end class Categories < CategoriesBase def to_feed(*args) end class Category < CategoryBase end end class Links < LinksBase def to_feed(rss, channel) return if @links.empty? @links.first.to_feed(rss, channel) end class Link < LinkBase def to_feed(rss, channel) if have_required_values? channel.link = href else raise NotSetError.new("maker.channel.link", not_set_required_variables) end end private def required_variable_names %w(href) end end end class Authors < AuthorsBase def to_feed(rss, channel) end class Author < AuthorBase def to_feed(rss, channel) end end end class Contributors < ContributorsBase def to_feed(rss, channel) end class Contributor < ContributorBase end end class Generator < GeneratorBase def to_feed(rss, channel) end end class Copyright < CopyrightBase def to_feed(rss, channel) channel.copyright = content if have_required_values? end private def required_variable_names %w(content) end end class Description < DescriptionBase def to_feed(rss, channel) channel.description = content if have_required_values? end private def required_variable_names %w(content) end end class Title < TitleBase def to_feed(rss, channel) channel.title = content if have_required_values? end private def required_variable_names %w(content) end end end class Image < ImageBase def to_feed(rss) image = Rss::Channel::Image.new set = setup_values(image) if set image.link = link rss.channel.image = image set_parent(image, rss.channel) setup_other_elements(rss, image) elsif required_element? raise NotSetError.new("maker.image", not_set_required_variables) end end private def required_variable_names %w(url title link) end def required_element? true end end class Items < ItemsBase def to_feed(rss) if rss.channel normalize.each do |item| item.to_feed(rss) end setup_other_elements(rss, rss.items) end end class Item < ItemBase def to_feed(rss) item = Rss::Channel::Item.new set = setup_values(item) _not_set_required_variables = not_set_required_variables if _not_set_required_variables.empty? rss.items << item set_parent(item, rss.channel) setup_other_elements(rss, item) elsif variable_is_set? raise NotSetError.new("maker.items", _not_set_required_variables) end end private def required_variable_names [] end def not_set_required_variables vars = super if @maker.feed_version == "0.91" vars << "title" unless title {|t| t.have_required_values?} vars << "link" unless link {|l| l.have_required_values?} end vars end class Guid < GuidBase def to_feed(*args) end end class Enclosure < EnclosureBase def to_feed(*args) end end class Source < SourceBase def to_feed(*args) end class Authors < AuthorsBase def to_feed(*args) end class Author < AuthorBase end end class Categories < CategoriesBase def to_feed(*args) end class Category < CategoryBase end end class Contributors < ContributorsBase def to_feed(*args) end class Contributor < ContributorBase end end class Generator < GeneratorBase def to_feed(*args) end end class Icon < IconBase def to_feed(*args) end end class Links < LinksBase def to_feed(*args) end class Link < LinkBase end end class Logo < LogoBase def to_feed(*args) end end class Rights < RightsBase def to_feed(*args) end end class Subtitle < SubtitleBase def to_feed(*args) end end class Title < TitleBase def to_feed(*args) end end end class Categories < CategoriesBase def to_feed(*args) end class Category < CategoryBase end end class Authors < AuthorsBase def to_feed(*args) end class Author < AuthorBase end end class Links < LinksBase def to_feed(rss, item) return if @links.empty? @links.first.to_feed(rss, item) end class Link < LinkBase def to_feed(rss, item) if have_required_values? item.link = href else raise NotSetError.new("maker.link", not_set_required_variables) end end private def required_variable_names %w(href) end end end class Contributors < ContributorsBase def to_feed(rss, item) end class Contributor < ContributorBase end end class Rights < RightsBase def to_feed(rss, item) end end class Description < DescriptionBase def to_feed(rss, item) item.description = content if have_required_values? end private def required_variable_names %w(content) end end class Content < ContentBase def to_feed(rss, item) end end class Title < TitleBase def to_feed(rss, item) item.title = content if have_required_values? end private def required_variable_names %w(content) end end end end class Textinput < TextinputBase def to_feed(rss) textInput = Rss::Channel::TextInput.new set = setup_values(textInput) if set rss.channel.textInput = textInput set_parent(textInput, rss.channel) setup_other_elements(rss, textInput) end end private def required_variable_names %w(title description name link) end end end add_maker("0.9", "0.92", RSS09) add_maker("0.91", "0.91", RSS09) add_maker("0.92", "0.92", RSS09) add_maker("rss0.91", "0.91", RSS09) add_maker("rss0.92", "0.92", RSS09) end end ================================================ FILE: lib/rss/maker/1.0.rb ================================================ require "rss/1.0" require "rss/maker/base" module RSS module Maker class RSS10 < RSSBase def initialize(feed_version="1.0") super @feed_type = "rss" end private def make_feed RDF.new(@version, @encoding, @standalone) end def setup_elements(rss) setup_channel(rss) setup_image(rss) setup_items(rss) setup_textinput(rss) end class Channel < ChannelBase def to_feed(rss) set_default_values do _not_set_required_variables = not_set_required_variables if _not_set_required_variables.empty? channel = RDF::Channel.new(@about) set = setup_values(channel) channel.dc_dates.clear rss.channel = channel set_parent(channel, rss) setup_items(rss) setup_image(rss) setup_textinput(rss) setup_other_elements(rss, channel) else raise NotSetError.new("maker.channel", _not_set_required_variables) end end end private def setup_items(rss) items = RDF::Channel::Items.new seq = items.Seq set_parent(items, seq) target_items = @maker.items.normalize raise NotSetError.new("maker", ["items"]) if target_items.empty? target_items.each do |item| li = RDF::Channel::Items::Seq::Li.new(item.link) seq.lis << li set_parent(li, seq) end rss.channel.items = items set_parent(rss.channel, items) end def setup_image(rss) if @maker.image.have_required_values? image = RDF::Channel::Image.new(@maker.image.url) rss.channel.image = image set_parent(image, rss.channel) end end def setup_textinput(rss) if @maker.textinput.have_required_values? textinput = RDF::Channel::Textinput.new(@maker.textinput.link) rss.channel.textinput = textinput set_parent(textinput, rss.channel) end end def required_variable_names %w(about link) end def not_set_required_variables vars = super vars << "description" unless description {|d| d.have_required_values?} vars << "title" unless title {|t| t.have_required_values?} vars end class SkipDays < SkipDaysBase def to_feed(*args) end class Day < DayBase end end class SkipHours < SkipHoursBase def to_feed(*args) end class Hour < HourBase end end class Cloud < CloudBase def to_feed(*args) end end class Categories < CategoriesBase def to_feed(*args) end class Category < CategoryBase end end class Links < LinksBase def to_feed(rss, channel) return if @links.empty? @links.first.to_feed(rss, channel) end class Link < LinkBase def to_feed(rss, channel) if have_required_values? channel.link = href else raise NotSetError.new("maker.channel.link", not_set_required_variables) end end private def required_variable_names %w(href) end end end class Authors < AuthorsBase def to_feed(rss, channel) end class Author < AuthorBase def to_feed(rss, channel) end end end class Contributors < ContributorsBase def to_feed(rss, channel) end class Contributor < ContributorBase end end class Generator < GeneratorBase def to_feed(rss, channel) end end class Copyright < CopyrightBase def to_feed(rss, channel) end end class Description < DescriptionBase def to_feed(rss, channel) channel.description = content if have_required_values? end private def required_variable_names %w(content) end end class Title < TitleBase def to_feed(rss, channel) channel.title = content if have_required_values? end private def required_variable_names %w(content) end end end class Image < ImageBase def to_feed(rss) if @url image = RDF::Image.new(@url) set = setup_values(image) if set rss.image = image set_parent(image, rss) setup_other_elements(rss, image) end end end def have_required_values? super and @maker.channel.have_required_values? end private def variables super + ["link"] end def required_variable_names %w(url title link) end end class Items < ItemsBase def to_feed(rss) if rss.channel normalize.each do |item| item.to_feed(rss) end setup_other_elements(rss, rss.items) end end class Item < ItemBase def to_feed(rss) set_default_values do item = RDF::Item.new(link) set = setup_values(item) if set item.dc_dates.clear rss.items << item set_parent(item, rss) setup_other_elements(rss, item) elsif !have_required_values? raise NotSetError.new("maker.item", not_set_required_variables) end end end private def required_variable_names %w(link) end def variables super + %w(link) end def not_set_required_variables set_default_values do vars = super vars << "title" unless title {|t| t.have_required_values?} vars end end class Guid < GuidBase def to_feed(*args) end end class Enclosure < EnclosureBase def to_feed(*args) end end class Source < SourceBase def to_feed(*args) end class Authors < AuthorsBase def to_feed(*args) end class Author < AuthorBase end end class Categories < CategoriesBase def to_feed(*args) end class Category < CategoryBase end end class Contributors < ContributorsBase def to_feed(*args) end class Contributor < ContributorBase end end class Generator < GeneratorBase def to_feed(*args) end end class Icon < IconBase def to_feed(*args) end end class Links < LinksBase def to_feed(*args) end class Link < LinkBase end end class Logo < LogoBase def to_feed(*args) end end class Rights < RightsBase def to_feed(*args) end end class Subtitle < SubtitleBase def to_feed(*args) end end class Title < TitleBase def to_feed(*args) end end end class Categories < CategoriesBase def to_feed(*args) end class Category < CategoryBase end end class Authors < AuthorsBase def to_feed(*args) end class Author < AuthorBase end end class Links < LinksBase def to_feed(*args) end class Link < LinkBase end end class Contributors < ContributorsBase def to_feed(rss, item) end class Contributor < ContributorBase end end class Rights < RightsBase def to_feed(rss, item) end end class Description < DescriptionBase def to_feed(rss, item) item.description = content if have_required_values? end private def required_variable_names %w(content) end end class Content < ContentBase def to_feed(rss, item) end end class Title < TitleBase def to_feed(rss, item) item.title = content if have_required_values? end private def required_variable_names %w(content) end end end end class Textinput < TextinputBase def to_feed(rss) if @link textinput = RDF::Textinput.new(@link) set = setup_values(textinput) if set rss.textinput = textinput set_parent(textinput, rss) setup_other_elements(rss, textinput) end end end def have_required_values? super and @maker.channel.have_required_values? end private def required_variable_names %w(title description name link) end end end add_maker("1.0", "1.0", RSS10) add_maker("rss1.0", "1.0", RSS10) end end ================================================ FILE: lib/rss/maker/2.0.rb ================================================ require "rss/2.0" require "rss/maker/0.9" module RSS module Maker class RSS20 < RSS09 def initialize(feed_version="2.0") super end class Channel < RSS09::Channel private def required_variable_names %w(link) end class SkipDays < RSS09::Channel::SkipDays class Day < RSS09::Channel::SkipDays::Day end end class SkipHours < RSS09::Channel::SkipHours class Hour < RSS09::Channel::SkipHours::Hour end end class Cloud < RSS09::Channel::Cloud def to_feed(rss, channel) cloud = Rss::Channel::Cloud.new set = setup_values(cloud) if set channel.cloud = cloud set_parent(cloud, channel) setup_other_elements(rss, cloud) end end private def required_variable_names %w(domain port path registerProcedure protocol) end end class Categories < RSS09::Channel::Categories def to_feed(rss, channel) @categories.each do |category| category.to_feed(rss, channel) end end class Category < RSS09::Channel::Categories::Category def to_feed(rss, channel) category = Rss::Channel::Category.new set = setup_values(category) if set channel.categories << category set_parent(category, channel) setup_other_elements(rss, category) end end private def required_variable_names %w(content) end end end class Generator < GeneratorBase def to_feed(rss, channel) channel.generator = content end private def required_variable_names %w(content) end end end class Image < RSS09::Image private def required_element? false end end class Items < RSS09::Items class Item < RSS09::Items::Item private def required_variable_names [] end def not_set_required_variables vars = super if !title {|t| t.have_required_values?} and !description {|d| d.have_required_values?} vars << "title or description" end vars end def variables super + ["pubDate"] end class Guid < RSS09::Items::Item::Guid def to_feed(rss, item) guid = Rss::Channel::Item::Guid.new set = setup_values(guid) if set item.guid = guid set_parent(guid, item) setup_other_elements(rss, guid) end end private def required_variable_names %w(content) end end class Enclosure < RSS09::Items::Item::Enclosure def to_feed(rss, item) enclosure = Rss::Channel::Item::Enclosure.new set = setup_values(enclosure) if set item.enclosure = enclosure set_parent(enclosure, item) setup_other_elements(rss, enclosure) end end private def required_variable_names %w(url length type) end end class Source < RSS09::Items::Item::Source def to_feed(rss, item) source = Rss::Channel::Item::Source.new set = setup_values(source) if set item.source = source set_parent(source, item) setup_other_elements(rss, source) end end private def required_variable_names %w(url content) end class Links < RSS09::Items::Item::Source::Links def to_feed(rss, source) return if @links.empty? @links.first.to_feed(rss, source) end class Link < RSS09::Items::Item::Source::Links::Link def to_feed(rss, source) source.url = href end end end end class Categories < RSS09::Items::Item::Categories def to_feed(rss, item) @categories.each do |category| category.to_feed(rss, item) end end class Category < RSS09::Items::Item::Categories::Category def to_feed(rss, item) category = Rss::Channel::Item::Category.new set = setup_values(category) if set item.categories << category set_parent(category, item) setup_other_elements(rss) end end private def required_variable_names %w(content) end end end class Authors < RSS09::Items::Item::Authors def to_feed(rss, item) return if @authors.empty? @authors.first.to_feed(rss, item) end class Author < RSS09::Items::Item::Authors::Author def to_feed(rss, item) item.author = name end end end end end class Textinput < RSS09::Textinput end end add_maker("2.0", "2.0", RSS20) add_maker("rss2.0", "2.0", RSS20) end end ================================================ FILE: lib/rss/maker/atom.rb ================================================ require "rss/atom" require "rss/maker/base" module RSS module Maker module AtomPersons module_function def def_atom_persons(klass, name, maker_name, plural=nil) plural ||= "#{name}s" klass_name = Utils.to_class_name(name) plural_klass_name = Utils.to_class_name(plural) klass.class_eval(<<-EOC, __FILE__, __LINE__ + 1) class #{plural_klass_name} < #{plural_klass_name}Base class #{klass_name} < #{klass_name}Base def to_feed(feed, current) #{name} = feed.class::#{klass_name}.new set = setup_values(#{name}) unless set raise NotSetError.new(#{maker_name.dump}, not_set_required_variables) end current.#{plural} << #{name} set_parent(#{name}, current) setup_other_elements(#{name}) end private def required_variable_names %w(name) end end end EOC end end module AtomTextConstruct class << self def def_atom_text_construct(klass, name, maker_name, klass_name=nil, atom_klass_name=nil) klass_name ||= Utils.to_class_name(name) atom_klass_name ||= Utils.to_class_name(name) klass.class_eval(<<-EOC, __FILE__, __LINE__ + 1) class #{klass_name} < #{klass_name}Base include #{self.name} def to_feed(feed, current) #{name} = current.class::#{atom_klass_name}.new if setup_values(#{name}) current.#{name} = #{name} set_parent(#{name}, current) setup_other_elements(feed) elsif variable_is_set? raise NotSetError.new(#{maker_name.dump}, not_set_required_variables) end end end EOC end end private def required_variable_names if type == "xhtml" %w(xml_content) else %w(content) end end def variables if type == "xhtml" super + %w(xhtml) else super end end end module AtomCategory def to_feed(feed, current) category = feed.class::Category.new set = setup_values(category) if set current.categories << category set_parent(category, current) setup_other_elements(feed) else raise NotSetError.new(self.class.not_set_name, not_set_required_variables) end end private def required_variable_names %w(term) end def variables super + ["term", "scheme"] end end module AtomLink def to_feed(feed, current) link = feed.class::Link.new set = setup_values(link) if set current.links << link set_parent(link, current) setup_other_elements(feed) else raise NotSetError.new(self.class.not_set_name, not_set_required_variables) end end private def required_variable_names %w(href) end end module AtomGenerator def to_feed(feed, current) generator = current.class::Generator.new if setup_values(generator) current.generator = generator set_parent(generator, current) setup_other_elements(feed) elsif variable_is_set? raise NotSetError.new(self.class.not_set_name, not_set_required_variables) end end private def required_variable_names %w(content) end end module AtomLogo def to_feed(feed, current) logo = current.class::Logo.new class << logo alias_method(:uri=, :content=) end set = setup_values(logo) class << logo remove_method(:uri=) end if set current.logo = logo set_parent(logo, current) setup_other_elements(feed) elsif variable_is_set? raise NotSetError.new(self.class.not_set_name, not_set_required_variables) end end private def required_variable_names %w(uri) end end end end ================================================ FILE: lib/rss/maker/base.rb ================================================ require 'forwardable' require 'rss/rss' module RSS module Maker class Base extend Utils::InheritedReader OTHER_ELEMENTS = [] NEED_INITIALIZE_VARIABLES = [] class << self def other_elements inherited_array_reader("OTHER_ELEMENTS") end def need_initialize_variables inherited_array_reader("NEED_INITIALIZE_VARIABLES") end def inherited_base ::RSS::Maker::Base end def inherited(subclass) subclass.const_set("OTHER_ELEMENTS", []) subclass.const_set("NEED_INITIALIZE_VARIABLES", []) end def add_other_element(variable_name) self::OTHER_ELEMENTS << variable_name end def add_need_initialize_variable(variable_name, init_value="nil") self::NEED_INITIALIZE_VARIABLES << [variable_name, init_value] end def def_array_element(name, plural=nil, klass_name=nil) include Enumerable extend Forwardable plural ||= "#{name}s" klass_name ||= Utils.to_class_name(name) def_delegators("@#{plural}", :<<, :[], :[]=, :first, :last) def_delegators("@#{plural}", :push, :pop, :shift, :unshift) def_delegators("@#{plural}", :each, :size, :empty?, :clear) add_need_initialize_variable(plural, "[]") module_eval(<<-EOC, __FILE__, __LINE__ + 1) def new_#{name} #{name} = self.class::#{klass_name}.new(@maker) @#{plural} << #{name} if block_given? yield #{name} else #{name} end end alias new_child new_#{name} def to_feed(*args) @#{plural}.each do |#{name}| #{name}.to_feed(*args) end end def replace(elements) @#{plural}.replace(elements.to_a) end EOC end def def_classed_element_without_accessor(name, class_name=nil) class_name ||= Utils.to_class_name(name) add_other_element(name) add_need_initialize_variable(name, "make_#{name}") module_eval(<<-EOC, __FILE__, __LINE__ + 1) private def setup_#{name}(feed, current) @#{name}.to_feed(feed, current) end def make_#{name} self.class::#{class_name}.new(@maker) end EOC end def def_classed_element(name, class_name=nil, attribute_name=nil) def_classed_element_without_accessor(name, class_name) if attribute_name module_eval(<<-EOC, __FILE__, __LINE__ + 1) def #{name} if block_given? yield(@#{name}) else @#{name}.#{attribute_name} end end def #{name}=(new_value) @#{name}.#{attribute_name} = new_value end EOC else attr_reader name end end def def_classed_elements(name, attribute, plural_class_name=nil, plural_name=nil, new_name=nil) plural_name ||= "#{name}s" new_name ||= name def_classed_element(plural_name, plural_class_name) local_variable_name = "_#{name}" new_value_variable_name = "new_value" additional_setup_code = nil if block_given? additional_setup_code = yield(local_variable_name, new_value_variable_name) end module_eval(<<-EOC, __FILE__, __LINE__ + 1) def #{name} #{local_variable_name} = #{plural_name}.first #{local_variable_name} ? #{local_variable_name}.#{attribute} : nil end def #{name}=(#{new_value_variable_name}) #{local_variable_name} = #{plural_name}.first || #{plural_name}.new_#{new_name} #{additional_setup_code} #{local_variable_name}.#{attribute} = #{new_value_variable_name} end EOC end def def_other_element(name) attr_accessor name def_other_element_without_accessor(name) end def def_other_element_without_accessor(name) add_need_initialize_variable(name) add_other_element(name) module_eval(<<-EOC, __FILE__, __LINE__ + 1) def setup_#{name}(feed, current) if !@#{name}.nil? and current.respond_to?(:#{name}=) current.#{name} = @#{name} end end EOC end def def_csv_element(name, type=nil) def_other_element_without_accessor(name) attr_reader(name) converter = "" if type == :integer converter = "{|v| Integer(v)}" end module_eval(<<-EOC, __FILE__, __LINE__ + 1) def #{name}=(value) @#{name} = Utils::CSV.parse(value)#{converter} end EOC end end attr_reader :maker def initialize(maker) @maker = maker @default_values_are_set = false initialize_variables end def have_required_values? not_set_required_variables.empty? end def variable_is_set? variables.any? {|var| not __send__(var).nil?} end private def initialize_variables self.class.need_initialize_variables.each do |variable_name, init_value| instance_eval("@#{variable_name} = #{init_value}", __FILE__, __LINE__) end end def setup_other_elements(feed, current=nil) current ||= current_element(feed) self.class.other_elements.each do |element| __send__("setup_#{element}", feed, current) end end def current_element(feed) feed end def set_default_values(&block) return yield if @default_values_are_set begin @default_values_are_set = true _set_default_values(&block) ensure @default_values_are_set = false end end def _set_default_values(&block) yield end def setup_values(target) set = false if have_required_values? variables.each do |var| setter = "#{var}=" if target.respond_to?(setter) value = __send__(var) if value target.__send__(setter, value) set = true end end end end set end def set_parent(target, parent) target.parent = parent if target.class.need_parent? end def variables self.class.need_initialize_variables.find_all do |name, init| "nil" == init end.collect do |name, init| name end end def not_set_required_variables required_variable_names.find_all do |var| __send__(var).nil? end end def required_variables_are_set? required_variable_names.each do |var| return false if __send__(var).nil? end true end end module AtomPersonConstructBase def self.append_features(klass) super klass.class_eval(<<-EOC, __FILE__, __LINE__ + 1) %w(name uri email).each do |element| attr_accessor element add_need_initialize_variable(element) end EOC end end module AtomTextConstructBase module EnsureXMLContent class << self def included(base) super base.class_eval do %w(type content xml_content).each do |element| attr_reader element attr_writer element if element != "xml_content" add_need_initialize_variable(element) end alias_method(:xhtml, :xml_content) end end end def ensure_xml_content(content) xhtml_uri = ::RSS::Atom::XHTML_URI unless content.is_a?(RSS::XML::Element) and ["div", xhtml_uri] == [content.name, content.uri] children = content children = [children] unless content.is_a?(Array) children = set_xhtml_uri_as_default_uri(children) content = RSS::XML::Element.new("div", nil, xhtml_uri, {"xmlns" => xhtml_uri}, children) end content end def xml_content=(content) @xml_content = ensure_xml_content(content) end def xhtml=(content) self.xml_content = content end private def set_xhtml_uri_as_default_uri(children) children.collect do |child| if child.is_a?(RSS::XML::Element) and child.prefix.nil? and child.uri.nil? RSS::XML::Element.new(child.name, nil, ::RSS::Atom::XHTML_URI, child.attributes.dup, set_xhtml_uri_as_default_uri(child.children)) else child end end end end def self.append_features(klass) super klass.class_eval do include EnsureXMLContent end end end module SetupDefaultDate private def _set_default_values(&block) keep = { :date => date, :dc_dates => dc_dates.to_a.dup, } _date = date if _date and !dc_dates.any? {|dc_date| dc_date.value == _date} dc_date = self.class::DublinCoreDates::DublinCoreDate.new(self) dc_date.value = _date.dup dc_dates.unshift(dc_date) end self.date ||= self.dc_date super(&block) ensure date = keep[:date] dc_dates.replace(keep[:dc_dates]) end end class RSSBase < Base class << self def make(version, &block) new(version).make(&block) end end %w(xml_stylesheets channel image items textinput).each do |element| attr_reader element add_need_initialize_variable(element, "make_#{element}") module_eval(<<-EOC, __FILE__, __LINE__) private def setup_#{element}(feed) @#{element}.to_feed(feed) end def make_#{element} self.class::#{Utils.to_class_name(element)}.new(self) end EOC end attr_reader :feed_version alias_method(:rss_version, :feed_version) attr_accessor :version, :encoding, :standalone def initialize(feed_version) super(self) @feed_type = nil @feed_subtype = nil @feed_version = feed_version @version = "1.0" @encoding = "UTF-8" @standalone = nil end def make if block_given? yield(self) to_feed else nil end end def to_feed feed = make_feed setup_xml_stylesheets(feed) setup_elements(feed) setup_other_elements(feed) if feed.valid? feed else nil end end private remove_method :make_xml_stylesheets def make_xml_stylesheets XMLStyleSheets.new(self) end end class XMLStyleSheets < Base def_array_element("xml_stylesheet", nil, "XMLStyleSheet") class XMLStyleSheet < Base ::RSS::XMLStyleSheet::ATTRIBUTES.each do |attribute| attr_accessor attribute add_need_initialize_variable(attribute) end def to_feed(feed) xss = ::RSS::XMLStyleSheet.new guess_type_if_need(xss) set = setup_values(xss) if set feed.xml_stylesheets << xss end end private def guess_type_if_need(xss) if @type.nil? xss.href = @href @type = xss.type end end def required_variable_names %w(href type) end end end class ChannelBase < Base include SetupDefaultDate %w(cloud categories skipDays skipHours).each do |name| def_classed_element(name) end %w(generator copyright description title).each do |name| def_classed_element(name, nil, "content") end [ ["link", "href", Proc.new {|target,| "#{target}.href = 'self'"}], ["author", "name"], ["contributor", "name"], ].each do |name, attribute, additional_setup_maker| def_classed_elements(name, attribute, &additional_setup_maker) end %w(id about language managingEditor webMaster rating docs date lastBuildDate ttl).each do |element| attr_accessor element add_need_initialize_variable(element) end def pubDate date end def pubDate=(date) self.date = date end def updated date end def updated=(date) self.date = date end alias_method(:rights, :copyright) alias_method(:rights=, :copyright=) alias_method(:subtitle, :description) alias_method(:subtitle=, :description=) def icon image_favicon.about end def icon=(url) image_favicon.about = url end def logo maker.image.url end def logo=(url) maker.image.url = url end class SkipDaysBase < Base def_array_element("day") class DayBase < Base %w(content).each do |element| attr_accessor element add_need_initialize_variable(element) end end end class SkipHoursBase < Base def_array_element("hour") class HourBase < Base %w(content).each do |element| attr_accessor element add_need_initialize_variable(element) end end end class CloudBase < Base %w(domain port path registerProcedure protocol).each do |element| attr_accessor element add_need_initialize_variable(element) end end class CategoriesBase < Base def_array_element("category", "categories") class CategoryBase < Base %w(domain content label).each do |element| attr_accessor element add_need_initialize_variable(element) end alias_method(:term, :domain) alias_method(:term=, :domain=) alias_method(:scheme, :content) alias_method(:scheme=, :content=) end end class LinksBase < Base def_array_element("link") class LinkBase < Base %w(href rel type hreflang title length).each do |element| attr_accessor element add_need_initialize_variable(element) end end end class AuthorsBase < Base def_array_element("author") class AuthorBase < Base include AtomPersonConstructBase end end class ContributorsBase < Base def_array_element("contributor") class ContributorBase < Base include AtomPersonConstructBase end end class GeneratorBase < Base %w(uri version content).each do |element| attr_accessor element add_need_initialize_variable(element) end end class CopyrightBase < Base include AtomTextConstructBase end class DescriptionBase < Base include AtomTextConstructBase end class TitleBase < Base include AtomTextConstructBase end end class ImageBase < Base %w(title url width height description).each do |element| attr_accessor element add_need_initialize_variable(element) end def link @maker.channel.link end end class ItemsBase < Base def_array_element("item") attr_accessor :do_sort, :max_size def initialize(maker) super @do_sort = false @max_size = -1 end def normalize if @max_size >= 0 sort_if_need[0...@max_size] else sort_if_need[0..@max_size] end end private def sort_if_need if @do_sort.respond_to?(:call) @items.sort do |x, y| @do_sort.call(x, y) end elsif @do_sort @items.sort do |x, y| y <=> x end else @items end end class ItemBase < Base include SetupDefaultDate %w(guid enclosure source categories content).each do |name| def_classed_element(name) end %w(rights description title).each do |name| def_classed_element(name, nil, "content") end [ ["author", "name"], ["link", "href", Proc.new {|target,| "#{target}.href = 'alternate'"}], ["contributor", "name"], ].each do |name, attribute| def_classed_elements(name, attribute) end %w(date comments id published).each do |element| attr_accessor element add_need_initialize_variable(element) end def pubDate date end def pubDate=(date) self.date = date end def updated date end def updated=(date) self.date = date end alias_method(:summary, :description) alias_method(:summary=, :description=) def <=>(other) _date = date || dc_date _other_date = other.date || other.dc_date if _date and _other_date _date <=> _other_date elsif _date 1 elsif _other_date -1 else 0 end end class GuidBase < Base %w(isPermaLink content).each do |element| attr_accessor element add_need_initialize_variable(element) end end class EnclosureBase < Base %w(url length type).each do |element| attr_accessor element add_need_initialize_variable(element) end end class SourceBase < Base %w(authors categories contributors generator icon logo rights subtitle title).each do |name| def_classed_element(name) end [ ["link", "href"], ].each do |name, attribute| def_classed_elements(name, attribute) end %w(id content date).each do |element| attr_accessor element add_need_initialize_variable(element) end alias_method(:url, :link) alias_method(:url=, :link=) def updated date end def updated=(date) self.date = date end private AuthorsBase = ChannelBase::AuthorsBase CategoriesBase = ChannelBase::CategoriesBase ContributorsBase = ChannelBase::ContributorsBase GeneratorBase = ChannelBase::GeneratorBase class IconBase < Base %w(url).each do |element| attr_accessor element add_need_initialize_variable(element) end end LinksBase = ChannelBase::LinksBase class LogoBase < Base %w(uri).each do |element| attr_accessor element add_need_initialize_variable(element) end end class RightsBase < Base include AtomTextConstructBase end class SubtitleBase < Base include AtomTextConstructBase end class TitleBase < Base include AtomTextConstructBase end end CategoriesBase = ChannelBase::CategoriesBase AuthorsBase = ChannelBase::AuthorsBase LinksBase = ChannelBase::LinksBase ContributorsBase = ChannelBase::ContributorsBase class RightsBase < Base include AtomTextConstructBase end class DescriptionBase < Base include AtomTextConstructBase end class ContentBase < Base include AtomTextConstructBase::EnsureXMLContent %w(src).each do |element| attr_accessor(element) add_need_initialize_variable(element) end def xml_content=(content) content = ensure_xml_content(content) if inline_xhtml? @xml_content = content end alias_method(:xml, :xml_content) alias_method(:xml=, :xml_content=) def inline_text? [nil, "text", "html"].include?(@type) end def inline_html? @type == "html" end def inline_xhtml? @type == "xhtml" end def inline_other? !out_of_line? and ![nil, "text", "html", "xhtml"].include?(@type) end def inline_other_text? return false if @type.nil? or out_of_line? /\Atext\//i.match(@type) ? true : false end def inline_other_xml? return false if @type.nil? or out_of_line? /[\+\/]xml\z/i.match(@type) ? true : false end def inline_other_base64? return false if @type.nil? or out_of_line? @type.include?("/") and !inline_other_text? and !inline_other_xml? end def out_of_line? not @src.nil? and @content.nil? end end class TitleBase < Base include AtomTextConstructBase end end end class TextinputBase < Base %w(title description name link).each do |element| attr_accessor element add_need_initialize_variable(element) end end end end ================================================ FILE: lib/rss/maker/content.rb ================================================ require 'rss/content' require 'rss/maker/1.0' require 'rss/maker/2.0' module RSS module Maker module ContentModel def self.append_features(klass) super ::RSS::ContentModel::ELEMENTS.each do |name| klass.def_other_element(name) end end end class ItemsBase class ItemBase; include ContentModel; end end end end ================================================ FILE: lib/rss/maker/dublincore.rb ================================================ require 'rss/dublincore' require 'rss/maker/1.0' module RSS module Maker module DublinCoreModel def self.append_features(klass) super ::RSS::DublinCoreModel::ELEMENT_NAME_INFOS.each do |name, plural_name| plural_name ||= "#{name}s" full_name = "#{RSS::DC_PREFIX}_#{name}" full_plural_name = "#{RSS::DC_PREFIX}_#{plural_name}" klass_name = Utils.to_class_name(name) plural_klass_name = "DublinCore#{Utils.to_class_name(plural_name)}" full_plural_klass_name = "self.class::#{plural_klass_name}" full_klass_name = "#{full_plural_klass_name}::#{klass_name}" klass.def_classed_elements(full_name, "value", plural_klass_name, full_plural_name, name) klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) def new_#{full_name}(value=nil) _#{full_name} = #{full_plural_name}.new_#{name} _#{full_name}.value = value if block_given? yield _#{full_name} else _#{full_name} end end EOC end klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) # For backward compatibility alias #{DC_PREFIX}_rightses #{DC_PREFIX}_rights_list EOC end ::RSS::DublinCoreModel::ELEMENT_NAME_INFOS.each do |name, plural_name| plural_name ||= "#{name}s" full_name ||= "#{DC_PREFIX}_#{name}" full_plural_name ||= "#{DC_PREFIX}_#{plural_name}" klass_name = Utils.to_class_name(name) full_klass_name = "DublinCore#{klass_name}" plural_klass_name = "DublinCore#{Utils.to_class_name(plural_name)}" module_eval(<<-EOC, __FILE__, __LINE__ + 1) class #{plural_klass_name}Base < Base def_array_element(#{name.dump}, #{full_plural_name.dump}, #{full_klass_name.dump}) class #{full_klass_name}Base < Base attr_accessor :value add_need_initialize_variable("value") alias_method(:content, :value) alias_method(:content=, :value=) def have_required_values? @value end def to_feed(feed, current) if value and current.respond_to?(:#{full_name}) new_item = current.class::#{full_klass_name}.new(value) current.#{full_plural_name} << new_item end end end #{klass_name}Base = #{full_klass_name}Base end EOC end def self.install_dublin_core(klass) ::RSS::DublinCoreModel::ELEMENT_NAME_INFOS.each do |name, plural_name| plural_name ||= "#{name}s" klass_name = Utils.to_class_name(name) full_klass_name = "DublinCore#{klass_name}" plural_klass_name = "DublinCore#{Utils.to_class_name(plural_name)}" klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) class #{plural_klass_name} < #{plural_klass_name}Base class #{full_klass_name} < #{full_klass_name}Base end #{klass_name} = #{full_klass_name} end EOC end end end class ChannelBase include DublinCoreModel end class ImageBase; include DublinCoreModel; end class ItemsBase class ItemBase include DublinCoreModel end end class TextinputBase; include DublinCoreModel; end makers.each do |maker| maker.module_eval(<<-EOC, __FILE__, __LINE__ + 1) class Channel DublinCoreModel.install_dublin_core(self) end class Image DublinCoreModel.install_dublin_core(self) end class Items class Item DublinCoreModel.install_dublin_core(self) end end class Textinput DublinCoreModel.install_dublin_core(self) end EOC end end end ================================================ FILE: lib/rss/maker/entry.rb ================================================ require "rss/maker/atom" require "rss/maker/feed" module RSS module Maker module Atom class Entry < RSSBase def initialize(feed_version="1.0") super @feed_type = "atom" @feed_subtype = "entry" end private def make_feed ::RSS::Atom::Entry.new(@version, @encoding, @standalone) end def setup_elements(entry) setup_items(entry) end class Channel < ChannelBase class SkipDays < SkipDaysBase class Day < DayBase end end class SkipHours < SkipHoursBase class Hour < HourBase end end class Cloud < CloudBase end Categories = Feed::Channel::Categories Links = Feed::Channel::Links Authors = Feed::Channel::Authors Contributors = Feed::Channel::Contributors class Generator < GeneratorBase include AtomGenerator def self.not_set_name "maker.channel.generator" end end Copyright = Feed::Channel::Copyright class Description < DescriptionBase end Title = Feed::Channel::Title end class Image < ImageBase end class Items < ItemsBase def to_feed(entry) (normalize.first || Item.new(@maker)).to_feed(entry) end class Item < ItemBase def to_feed(entry) set_default_values do setup_values(entry) entry.dc_dates.clear setup_other_elements(entry) unless have_required_values? raise NotSetError.new("maker.item", not_set_required_variables) end end end private def required_variable_names %w(id updated) end def variables super + ["updated"] end def variable_is_set? super or !authors.empty? end def not_set_required_variables set_default_values do vars = super if authors.all? {|author| !author.have_required_values?} vars << "author" end vars << "title" unless title {|t| t.have_required_values?} vars end end def _set_default_values(&block) keep = { :authors => authors.to_a.dup, :contributors => contributors.to_a.dup, :categories => categories.to_a.dup, :id => id, :links => links.to_a.dup, :rights => @rights, :title => @title, :updated => updated, } authors.replace(@maker.channel.authors) if keep[:authors].empty? if keep[:contributors].empty? contributors.replace(@maker.channel.contributors) end if keep[:categories].empty? categories.replace(@maker.channel.categories) end self.id ||= link || @maker.channel.id links.replace(@maker.channel.links) if keep[:links].empty? unless keep[:rights].variable_is_set? @maker.channel.rights {|r| @rights = r} end unless keep[:title].variable_is_set? @maker.channel.title {|t| @title = t} end self.updated ||= @maker.channel.updated super(&block) ensure authors.replace(keep[:authors]) contributors.replace(keep[:contributors]) categories.replace(keep[:categories]) links.replace(keep[:links]) self.id = keep[:id] @rights = keep[:rights] @title = keep[:title] self.updated = keep[:prev_updated] end Guid = Feed::Items::Item::Guid Enclosure = Feed::Items::Item::Enclosure Source = Feed::Items::Item::Source Categories = Feed::Items::Item::Categories Authors = Feed::Items::Item::Authors Contributors = Feed::Items::Item::Contributors Links = Feed::Items::Item::Links Rights = Feed::Items::Item::Rights Description = Feed::Items::Item::Description Title = Feed::Items::Item::Title Content = Feed::Items::Item::Content end end class Textinput < TextinputBase end end end add_maker("atom:entry", "1.0", Atom::Entry) add_maker("atom1.0:entry", "1.0", Atom::Entry) end end ================================================ FILE: lib/rss/maker/feed.rb ================================================ require "rss/maker/atom" module RSS module Maker module Atom class Feed < RSSBase def initialize(feed_version="1.0") super @feed_type = "atom" @feed_subtype = "feed" end private def make_feed ::RSS::Atom::Feed.new(@version, @encoding, @standalone) end def setup_elements(feed) setup_channel(feed) setup_image(feed) setup_items(feed) end class Channel < ChannelBase def to_feed(feed) set_default_values do setup_values(feed) feed.dc_dates.clear setup_other_elements(feed) if image_favicon.about icon = feed.class::Icon.new icon.content = image_favicon.about feed.icon = icon end unless have_required_values? raise NotSetError.new("maker.channel", not_set_required_variables) end end end def have_required_values? super and (!authors.empty? or @maker.items.any? {|item| !item.authors.empty?}) end private def required_variable_names %w(id updated) end def variables super + %w(id updated) end def variable_is_set? super or !authors.empty? end def not_set_required_variables vars = super if authors.empty? and @maker.items.all? {|item| item.author.to_s.empty?} vars << "author" end vars << "title" unless title {|t| t.have_required_values?} vars end def _set_default_values(&block) keep = { :id => id, :updated => updated, } self.id ||= about self.updated ||= dc_date super(&block) ensure self.id = keep[:id] self.updated = keep[:updated] end class SkipDays < SkipDaysBase def to_feed(*args) end class Day < DayBase end end class SkipHours < SkipHoursBase def to_feed(*args) end class Hour < HourBase end end class Cloud < CloudBase def to_feed(*args) end end class Categories < CategoriesBase class Category < CategoryBase include AtomCategory def self.not_set_name "maker.channel.category" end end end class Links < LinksBase class Link < LinkBase include AtomLink def self.not_set_name "maker.channel.link" end end end AtomPersons.def_atom_persons(self, "author", "maker.channel.author") AtomPersons.def_atom_persons(self, "contributor", "maker.channel.contributor") class Generator < GeneratorBase include AtomGenerator def self.not_set_name "maker.channel.generator" end end AtomTextConstruct.def_atom_text_construct(self, "rights", "maker.channel.copyright", "Copyright") AtomTextConstruct.def_atom_text_construct(self, "subtitle", "maker.channel.description", "Description") AtomTextConstruct.def_atom_text_construct(self, "title", "maker.channel.title") end class Image < ImageBase def to_feed(feed) logo = feed.class::Logo.new class << logo alias_method(:url=, :content=) end set = setup_values(logo) class << logo remove_method(:url=) end if set feed.logo = logo set_parent(logo, feed) setup_other_elements(feed, logo) elsif variable_is_set? raise NotSetError.new("maker.image", not_set_required_variables) end end private def required_variable_names %w(url) end end class Items < ItemsBase def to_feed(feed) normalize.each do |item| item.to_feed(feed) end setup_other_elements(feed, feed.entries) end class Item < ItemBase def to_feed(feed) set_default_values do entry = feed.class::Entry.new set = setup_values(entry) setup_other_elements(feed, entry) if set feed.entries << entry set_parent(entry, feed) elsif variable_is_set? raise NotSetError.new("maker.item", not_set_required_variables) end end end def have_required_values? set_default_values do super and title {|t| t.have_required_values?} end end private def required_variable_names %w(id updated) end def variables super + ["updated"] end def not_set_required_variables vars = super vars << "title" unless title {|t| t.have_required_values?} vars end def _set_default_values(&block) keep = { :id => id, :updated => updated, } self.id ||= link self.updated ||= dc_date super(&block) ensure self.id = keep[:id] self.updated = keep[:updated] end class Guid < GuidBase def to_feed(feed, current) end end class Enclosure < EnclosureBase def to_feed(feed, current) end end class Source < SourceBase def to_feed(feed, current) source = current.class::Source.new setup_values(source) current.source = source set_parent(source, current) setup_other_elements(feed, source) current.source = nil if source.to_s == "" end private def required_variable_names [] end def variables super + ["updated"] end AtomPersons.def_atom_persons(self, "author", "maker.item.source.author") AtomPersons.def_atom_persons(self, "contributor", "maker.item.source.contributor") class Categories < CategoriesBase class Category < CategoryBase include AtomCategory def self.not_set_name "maker.item.source.category" end end end class Generator < GeneratorBase include AtomGenerator def self.not_set_name "maker.item.source.generator" end end class Icon < IconBase def to_feed(feed, current) icon = current.class::Icon.new class << icon alias_method(:url=, :content=) end set = setup_values(icon) class << icon remove_method(:url=) end if set current.icon = icon set_parent(icon, current) setup_other_elements(feed, icon) elsif variable_is_set? raise NotSetError.new("maker.item.source.icon", not_set_required_variables) end end private def required_variable_names %w(url) end end class Links < LinksBase class Link < LinkBase include AtomLink def self.not_set_name "maker.item.source.link" end end end class Logo < LogoBase include AtomLogo def self.not_set_name "maker.item.source.logo" end end maker_name_base = "maker.item.source." maker_name = "#{maker_name_base}rights" AtomTextConstruct.def_atom_text_construct(self, "rights", maker_name) maker_name = "#{maker_name_base}subtitle" AtomTextConstruct.def_atom_text_construct(self, "subtitle", maker_name) maker_name = "#{maker_name_base}title" AtomTextConstruct.def_atom_text_construct(self, "title", maker_name) end class Categories < CategoriesBase class Category < CategoryBase include AtomCategory def self.not_set_name "maker.item.category" end end end AtomPersons.def_atom_persons(self, "author", "maker.item.author") AtomPersons.def_atom_persons(self, "contributor", "maker.item.contributor") class Links < LinksBase class Link < LinkBase include AtomLink def self.not_set_name "maker.item.link" end end end AtomTextConstruct.def_atom_text_construct(self, "rights", "maker.item.rights") AtomTextConstruct.def_atom_text_construct(self, "summary", "maker.item.description", "Description") AtomTextConstruct.def_atom_text_construct(self, "title", "maker.item.title") class Content < ContentBase def to_feed(feed, current) content = current.class::Content.new if setup_values(content) content.src = nil if content.src and content.content current.content = content set_parent(content, current) setup_other_elements(feed, content) elsif variable_is_set? raise NotSetError.new("maker.item.content", not_set_required_variables) end end alias_method(:xml, :xml_content) private def required_variable_names if out_of_line? %w(type) elsif xml_type? %w(xml_content) else %w(content) end end def variables if out_of_line? super elsif xml_type? super + %w(xml) else super end end def xml_type? _type = type return false if _type.nil? _type == "xhtml" or /(?:\+xml|\/xml)$/i =~ _type or %w(text/xml-external-parsed-entity application/xml-external-parsed-entity application/xml-dtd).include?(_type.downcase) end end end end class Textinput < TextinputBase end end end add_maker("atom", "1.0", Atom::Feed) add_maker("atom:feed", "1.0", Atom::Feed) add_maker("atom1.0", "1.0", Atom::Feed) add_maker("atom1.0:feed", "1.0", Atom::Feed) end end ================================================ FILE: lib/rss/maker/image.rb ================================================ require 'rss/image' require 'rss/maker/1.0' require 'rss/maker/dublincore' module RSS module Maker module ImageItemModel def self.append_features(klass) super name = "#{RSS::IMAGE_PREFIX}_item" klass.def_classed_element(name) end def self.install_image_item(klass) klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) class ImageItem < ImageItemBase DublinCoreModel.install_dublin_core(self) end EOC end class ImageItemBase < Base include Maker::DublinCoreModel attr_accessor :about, :resource, :image_width, :image_height add_need_initialize_variable("about") add_need_initialize_variable("resource") add_need_initialize_variable("image_width") add_need_initialize_variable("image_height") alias width= image_width= alias width image_width alias height= image_height= alias height image_height def have_required_values? @about end def to_feed(feed, current) if current.respond_to?(:image_item=) and have_required_values? item = current.class::ImageItem.new setup_values(item) setup_other_elements(item) current.image_item = item end end end end module ImageFaviconModel def self.append_features(klass) super name = "#{RSS::IMAGE_PREFIX}_favicon" klass.def_classed_element(name) end def self.install_image_favicon(klass) klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) class ImageFavicon < ImageFaviconBase DublinCoreModel.install_dublin_core(self) end EOC end class ImageFaviconBase < Base include Maker::DublinCoreModel attr_accessor :about, :image_size add_need_initialize_variable("about") add_need_initialize_variable("image_size") alias size image_size alias size= image_size= def have_required_values? @about and @image_size end def to_feed(feed, current) if current.respond_to?(:image_favicon=) and have_required_values? favicon = current.class::ImageFavicon.new setup_values(favicon) setup_other_elements(favicon) current.image_favicon = favicon end end end end class ChannelBase; include Maker::ImageFaviconModel; end class ItemsBase class ItemBase; include Maker::ImageItemModel; end end makers.each do |maker| maker.module_eval(<<-EOC, __FILE__, __LINE__ + 1) class Channel ImageFaviconModel.install_image_favicon(self) end class Items class Item ImageItemModel.install_image_item(self) end end EOC end end end ================================================ FILE: lib/rss/maker/itunes.rb ================================================ require 'rss/itunes' require 'rss/maker/2.0' module RSS module Maker module ITunesBaseModel def def_class_accessor(klass, name, type, *args) name = name.gsub(/-/, "_").gsub(/^itunes_/, '') full_name = "#{RSS::ITUNES_PREFIX}_#{name}" case type when nil klass.def_other_element(full_name) when :yes_other def_yes_other_accessor(klass, full_name) when :yes_clean_other def_yes_clean_other_accessor(klass, full_name) when :csv def_csv_accessor(klass, full_name) when :element, :attribute recommended_attribute_name, = *args klass_name = "ITunes#{Utils.to_class_name(name)}" klass.def_classed_element(full_name, klass_name, recommended_attribute_name) when :elements plural_name, recommended_attribute_name = args plural_name ||= "#{name}s" full_plural_name = "#{RSS::ITUNES_PREFIX}_#{plural_name}" klass_name = "ITunes#{Utils.to_class_name(name)}" plural_klass_name = "ITunes#{Utils.to_class_name(plural_name)}" def_elements_class_accessor(klass, name, full_name, full_plural_name, klass_name, plural_klass_name, recommended_attribute_name) end end def def_yes_other_accessor(klass, full_name) klass.def_other_element(full_name) klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) def #{full_name}? Utils::YesOther.parse(@#{full_name}) end EOC end def def_yes_clean_other_accessor(klass, full_name) klass.def_other_element(full_name) klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) def #{full_name}? Utils::YesCleanOther.parse(#{full_name}) end EOC end def def_csv_accessor(klass, full_name) klass.def_csv_element(full_name) end def def_elements_class_accessor(klass, name, full_name, full_plural_name, klass_name, plural_klass_name, recommended_attribute_name=nil) if recommended_attribute_name klass.def_classed_elements(full_name, recommended_attribute_name, plural_klass_name, full_plural_name) else klass.def_classed_element(full_plural_name, plural_klass_name) end klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) def new_#{full_name}(text=nil) #{full_name} = @#{full_plural_name}.new_#{name} #{full_name}.text = text if block_given? yield #{full_name} else #{full_name} end end EOC end end module ITunesChannelModel extend ITunesBaseModel class << self def append_features(klass) super ::RSS::ITunesChannelModel::ELEMENT_INFOS.each do |name, type, *args| def_class_accessor(klass, name, type, *args) end end end class ITunesCategoriesBase < Base def_array_element("category", "itunes_categories", "ITunesCategory") class ITunesCategoryBase < Base attr_accessor :text add_need_initialize_variable("text") def_array_element("category", "itunes_categories", "ITunesCategory") def have_required_values? text end alias_method :to_feed_for_categories, :to_feed def to_feed(feed, current) if text and current.respond_to?(:itunes_category) new_item = current.class::ITunesCategory.new(text) to_feed_for_categories(feed, new_item) current.itunes_categories << new_item end end end end class ITunesImageBase < Base add_need_initialize_variable("href") attr_accessor("href") def to_feed(feed, current) if @href and current.respond_to?(:itunes_image) current.itunes_image ||= current.class::ITunesImage.new current.itunes_image.href = @href end end end class ITunesOwnerBase < Base %w(itunes_name itunes_email).each do |name| add_need_initialize_variable(name) attr_accessor(name) end def to_feed(feed, current) if current.respond_to?(:itunes_owner=) _not_set_required_variables = not_set_required_variables if (required_variable_names - _not_set_required_variables).empty? return end unless have_required_values? raise NotSetError.new("maker.channel.itunes_owner", _not_set_required_variables) end current.itunes_owner ||= current.class::ITunesOwner.new current.itunes_owner.itunes_name = @itunes_name current.itunes_owner.itunes_email = @itunes_email end end private def required_variable_names %w(itunes_name itunes_email) end end end module ITunesItemModel extend ITunesBaseModel class << self def append_features(klass) super ::RSS::ITunesItemModel::ELEMENT_INFOS.each do |name, type, *args| def_class_accessor(klass, name, type, *args) end end end class ITunesDurationBase < Base attr_reader :content add_need_initialize_variable("content") %w(hour minute second).each do |name| attr_reader(name) add_need_initialize_variable(name, '0') end def content=(content) if content.nil? @hour, @minute, @second, @content = nil else @hour, @minute, @second = ::RSS::ITunesItemModel::ITunesDuration.parse(content) @content = content end end def hour=(hour) @hour = Integer(hour) update_content end def minute=(minute) @minute = Integer(minute) update_content end def second=(second) @second = Integer(second) update_content end def to_feed(feed, current) if @content and current.respond_to?(:itunes_duration=) current.itunes_duration ||= current.class::ITunesDuration.new current.itunes_duration.content = @content end end private def update_content components = [@hour, @minute, @second] @content = ::RSS::ITunesItemModel::ITunesDuration.construct(*components) end end end class ChannelBase include Maker::ITunesChannelModel class ITunesCategories < ITunesCategoriesBase class ITunesCategory < ITunesCategoryBase ITunesCategory = self end end class ITunesImage < ITunesImageBase; end class ITunesOwner < ITunesOwnerBase; end end class ItemsBase class ItemBase include Maker::ITunesItemModel class ITunesDuration < ITunesDurationBase; end end end end end ================================================ FILE: lib/rss/maker/slash.rb ================================================ require 'rss/slash' require 'rss/maker/1.0' module RSS module Maker module SlashModel def self.append_features(klass) super ::RSS::SlashModel::ELEMENT_INFOS.each do |name, type| full_name = "#{RSS::SLASH_PREFIX}_#{name}" case type when :csv_integer klass.def_csv_element(full_name, :integer) else klass.def_other_element(full_name) end end klass.module_eval do alias_method(:slash_hit_parades, :slash_hit_parade) alias_method(:slash_hit_parades=, :slash_hit_parade=) end end end class ItemsBase class ItemBase include SlashModel end end end end ================================================ FILE: lib/rss/maker/syndication.rb ================================================ require 'rss/syndication' require 'rss/maker/1.0' module RSS module Maker module SyndicationModel def self.append_features(klass) super ::RSS::SyndicationModel::ELEMENTS.each do |name| klass.def_other_element(name) end end end class ChannelBase; include SyndicationModel; end end end ================================================ FILE: lib/rss/maker/taxonomy.rb ================================================ require 'rss/taxonomy' require 'rss/maker/1.0' require 'rss/maker/dublincore' module RSS module Maker module TaxonomyTopicsModel def self.append_features(klass) super klass.def_classed_element("#{RSS::TAXO_PREFIX}_topics", "TaxonomyTopics") end def self.install_taxo_topics(klass) klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) class TaxonomyTopics < TaxonomyTopicsBase def to_feed(feed, current) if current.respond_to?(:taxo_topics) topics = current.class::TaxonomyTopics.new bag = topics.Bag @resources.each do |resource| bag.lis << RDF::Bag::Li.new(resource) end current.taxo_topics = topics end end end EOC end class TaxonomyTopicsBase < Base attr_reader :resources def_array_element("resource") remove_method :new_resource end end module TaxonomyTopicModel def self.append_features(klass) super class_name = "TaxonomyTopics" klass.def_classed_elements("#{TAXO_PREFIX}_topic", "value", class_name) end def self.install_taxo_topic(klass) klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) class TaxonomyTopics < TaxonomyTopicsBase class TaxonomyTopic < TaxonomyTopicBase DublinCoreModel.install_dublin_core(self) TaxonomyTopicsModel.install_taxo_topics(self) def to_feed(feed, current) if current.respond_to?(:taxo_topics) topic = current.class::TaxonomyTopic.new(value) topic.taxo_link = value taxo_topics.to_feed(feed, topic) if taxo_topics current.taxo_topics << topic setup_other_elements(feed, topic) end end end end EOC end class TaxonomyTopicsBase < Base def_array_element("topic", nil, "TaxonomyTopic") alias_method(:new_taxo_topic, :new_topic) # For backward compatibility class TaxonomyTopicBase < Base include DublinCoreModel include TaxonomyTopicsModel attr_accessor :value add_need_initialize_variable("value") alias_method(:taxo_link, :value) alias_method(:taxo_link=, :value=) def have_required_values? @value end end end end class RSSBase include TaxonomyTopicModel end class ChannelBase include TaxonomyTopicsModel end class ItemsBase class ItemBase include TaxonomyTopicsModel end end makers.each do |maker| maker.module_eval(<<-EOC, __FILE__, __LINE__ + 1) TaxonomyTopicModel.install_taxo_topic(self) class Channel TaxonomyTopicsModel.install_taxo_topics(self) end class Items class Item TaxonomyTopicsModel.install_taxo_topics(self) end end EOC end end end ================================================ FILE: lib/rss/maker/trackback.rb ================================================ require 'rss/trackback' require 'rss/maker/1.0' require 'rss/maker/2.0' module RSS module Maker module TrackBackModel def self.append_features(klass) super klass.def_other_element("#{RSS::TRACKBACK_PREFIX}_ping") klass.def_classed_elements("#{RSS::TRACKBACK_PREFIX}_about", "value", "TrackBackAbouts") end class TrackBackAboutsBase < Base def_array_element("about", nil, "TrackBackAbout") class TrackBackAboutBase < Base attr_accessor :value add_need_initialize_variable("value") alias_method(:resource, :value) alias_method(:resource=, :value=) alias_method(:content, :value) alias_method(:content=, :value=) def have_required_values? @value end def to_feed(feed, current) if current.respond_to?(:trackback_abouts) and have_required_values? about = current.class::TrackBackAbout.new setup_values(about) setup_other_elements(about) current.trackback_abouts << about end end end end end class ItemsBase class ItemBase; include TrackBackModel; end end makers.each do |maker| maker.module_eval(<<-EOC, __FILE__, __LINE__ + 1) class Items class Item class TrackBackAbouts < TrackBackAboutsBase class TrackBackAbout < TrackBackAboutBase end end end end EOC end end end ================================================ FILE: lib/rss/maker.rb ================================================ require "rss/rss" module RSS module Maker MAKERS = {} class << self def make(version, &block) m = maker(version) raise UnsupportedMakerVersionError.new(version) if m.nil? m[:maker].make(m[:version], &block) end def maker(version) MAKERS[version] end def add_maker(version, normalized_version, maker) MAKERS[version] = {:maker => maker, :version => normalized_version} end def versions MAKERS.keys.uniq.sort end def makers MAKERS.values.collect {|info| info[:maker]}.uniq end end end end require "rss/maker/1.0" require "rss/maker/2.0" require "rss/maker/feed" require "rss/maker/entry" require "rss/maker/content" require "rss/maker/dublincore" require "rss/maker/slash" require "rss/maker/syndication" require "rss/maker/taxonomy" require "rss/maker/trackback" require "rss/maker/image" require "rss/maker/itunes" ================================================ FILE: lib/rss/parser.rb ================================================ require "forwardable" require "open-uri" require "rss/rss" require "rss/xml" module RSS class NotWellFormedError < Error attr_reader :line, :element # Create a new NotWellFormedError for an error at +line+ # in +element+. If a block is given the return value of # the block ends up in the error message. def initialize(line=nil, element=nil) message = "This is not well formed XML" if element or line message << "\nerror occurred" message << " in #{element}" if element message << " at about #{line} line" if line end message << "\n#{yield}" if block_given? super(message) end end class XMLParserNotFound < Error def initialize super("available XML parser was not found in " << "#{AVAILABLE_PARSER_LIBRARIES.inspect}.") end end class NotValidXMLParser < Error def initialize(parser) super("#{parser} is not an available XML parser. " << "Available XML parser"<< (AVAILABLE_PARSERS.size > 1 ? "s are ": " is ") << "#{AVAILABLE_PARSERS.inspect}.") end end class NSError < InvalidRSSError attr_reader :tag, :prefix, :uri def initialize(tag, prefix, require_uri) @tag, @prefix, @uri = tag, prefix, require_uri super("prefix <#{prefix}> doesn't associate uri " << "<#{require_uri}> in tag <#{tag}>") end end class Parser extend Forwardable class << self @@default_parser = nil def default_parser @@default_parser || AVAILABLE_PARSERS.first end # Set @@default_parser to new_value if it is one of the # available parsers. Else raise NotValidXMLParser error. def default_parser=(new_value) if AVAILABLE_PARSERS.include?(new_value) @@default_parser = new_value else raise NotValidXMLParser.new(new_value) end end def parse(rss, do_validate=true, ignore_unknown_element=true, parser_class=default_parser) parser = new(rss, parser_class) parser.do_validate = do_validate parser.ignore_unknown_element = ignore_unknown_element parser.parse end end def_delegators(:@parser, :parse, :rss, :ignore_unknown_element, :ignore_unknown_element=, :do_validate, :do_validate=) def initialize(rss, parser_class=self.class.default_parser) @parser = parser_class.new(normalize_rss(rss)) end private # Try to get the XML associated with +rss+. # Return +rss+ if it already looks like XML, or treat it as a URI, # or a file to get the XML, def normalize_rss(rss) return rss if maybe_xml?(rss) uri = to_uri(rss) if uri.respond_to?(:read) uri.read elsif !rss.tainted? and File.readable?(rss) File.open(rss) {|f| f.read} else rss end end # maybe_xml? tests if source is a string that looks like XML. def maybe_xml?(source) source.is_a?(String) and / :xml}] @tag_stack = [[]] @text_stack = [''] @proc_stack = [] @last_element = nil @version = @encoding = @standalone = nil @xml_stylesheets = [] @xml_child_mode = false @xml_element = nil @last_xml_element = nil end # set instance vars for version, encoding, standalone def xmldecl(version, encoding, standalone) @version, @encoding, @standalone = version, encoding, standalone end def instruction(name, content) if name == "xml-stylesheet" params = parse_pi_content(content) if params.has_key?("href") @xml_stylesheets << XMLStyleSheet.new(params) end end end def tag_start(name, attributes) @text_stack.push('') ns = @ns_stack.last.dup attrs = {} attributes.each do |n, v| if /\Axmlns(?:\z|:)/ =~ n ns[$POSTMATCH] = v else attrs[n] = v end end @ns_stack.push(ns) prefix, local = split_name(name) @tag_stack.last.push([_ns(ns, prefix), local]) @tag_stack.push([]) if @xml_child_mode previous = @last_xml_element element_attrs = attributes.dup unless previous ns.each do |ns_prefix, value| next if ns_prefix == "xml" key = ns_prefix.empty? ? "xmlns" : "xmlns:#{ns_prefix}" element_attrs[key] ||= value end end next_element = XML::Element.new(local, prefix.empty? ? nil : prefix, _ns(ns, prefix), element_attrs) previous << next_element if previous @last_xml_element = next_element pr = Proc.new do |text, tags| if previous @last_xml_element = previous else @xml_element = @last_xml_element @last_xml_element = nil end end @proc_stack.push(pr) else if @rss.nil? and respond_to?("initial_start_#{local}", true) __send__("initial_start_#{local}", local, prefix, attrs, ns.dup) elsif respond_to?("start_#{local}", true) __send__("start_#{local}", local, prefix, attrs, ns.dup) else start_else_element(local, prefix, attrs, ns.dup) end end end def tag_end(name) if DEBUG p "end tag #{name}" p @tag_stack end text = @text_stack.pop tags = @tag_stack.pop pr = @proc_stack.pop pr.call(text, tags) unless pr.nil? @ns_stack.pop end def text(data) if @xml_child_mode @last_xml_element << data if @last_xml_element else @text_stack.last << data end end private def _ns(ns, prefix) ns.fetch(prefix, "") end CONTENT_PATTERN = /\s*([^=]+)=(["'])([^\2]+?)\2/ # Extract the first name="value" pair from content. # Works with single quotes according to the constant # CONTENT_PATTERN. Return a Hash. def parse_pi_content(content) params = {} content.scan(CONTENT_PATTERN) do |name, quote, value| params[name] = value end params end def start_else_element(local, prefix, attrs, ns) class_name = self.class.class_name(_ns(ns, prefix), local) current_class = @last_element.class if class_name and (current_class.const_defined?(class_name) or current_class.constants.include?(class_name)) next_class = current_class.const_get(class_name) start_have_something_element(local, prefix, attrs, ns, next_class) else if !@do_validate or @ignore_unknown_element @proc_stack.push(nil) else parent = "ROOT ELEMENT???" if current_class.tag_name parent = current_class.tag_name end raise NotExpectedTagError.new(local, _ns(ns, prefix), parent) end end end NAMESPLIT = /^(?:([\w:][-\w\d.]*):)?([\w:][-\w\d.]*)/ def split_name(name) name =~ NAMESPLIT [$1 || '', $2] end def check_ns(tag_name, prefix, ns, require_uri) unless _ns(ns, prefix) == require_uri if @do_validate raise NSError.new(tag_name, prefix, require_uri) else # Force bind required URI with prefix @ns_stack.last[prefix] = require_uri end end end def start_get_text_element(tag_name, prefix, ns, required_uri) pr = Proc.new do |text, tags| setter = self.class.setter(required_uri, tag_name) if @last_element.respond_to?(setter) if @do_validate getter = self.class.getter(required_uri, tag_name) if @last_element.__send__(getter) raise TooMuchTagError.new(tag_name, @last_element.tag_name) end end @last_element.__send__(setter, text.to_s) else if @do_validate and !@ignore_unknown_element raise NotExpectedTagError.new(tag_name, _ns(ns, prefix), @last_element.tag_name) end end end @proc_stack.push(pr) end def start_have_something_element(tag_name, prefix, attrs, ns, klass) check_ns(tag_name, prefix, ns, klass.required_uri) attributes = collect_attributes(tag_name, prefix, attrs, ns, klass) @proc_stack.push(setup_next_element(tag_name, klass, attributes)) end def collect_attributes(tag_name, prefix, attrs, ns, klass) attributes = {} klass.get_attributes.each do |a_name, a_uri, required, element_name| if a_uri.is_a?(String) or !a_uri.respond_to?(:include?) a_uri = [a_uri] end unless a_uri == [""] for prefix, uri in ns if a_uri.include?(uri) val = attrs["#{prefix}:#{a_name}"] break if val end end end if val.nil? and a_uri.include?("") val = attrs[a_name] end if @do_validate and required and val.nil? unless a_uri.include?("") for prefix, uri in ns if a_uri.include?(uri) a_name = "#{prefix}:#{a_name}" end end end raise MissingAttributeError.new(tag_name, a_name) end attributes[a_name] = val end attributes end def setup_next_element(tag_name, klass, attributes) previous = @last_element next_element = klass.new(@do_validate, attributes) previous.set_next_element(tag_name, next_element) @last_element = next_element @last_element.parent = previous if klass.need_parent? @xml_child_mode = @last_element.have_xml_content? Proc.new do |text, tags| p(@last_element.class) if DEBUG if @xml_child_mode @last_element.content = @xml_element.to_s xml_setter = @last_element.class.xml_setter @last_element.__send__(xml_setter, @xml_element) @xml_element = nil @xml_child_mode = false else if klass.have_content? if @last_element.need_base64_encode? text = Base64.decode64(text.lstrip) end @last_element.content = text end end if @do_validate @last_element.validate_for_stream(tags, @ignore_unknown_element) end @last_element = previous end end end unless const_defined? :AVAILABLE_PARSER_LIBRARIES AVAILABLE_PARSER_LIBRARIES = [ ["rss/xmlparser", :XMLParserParser], ["rss/xmlscanner", :XMLScanParser], ["rss/rexmlparser", :REXMLParser], ] end AVAILABLE_PARSERS = [] AVAILABLE_PARSER_LIBRARIES.each do |lib, parser| begin require lib AVAILABLE_PARSERS.push(const_get(parser)) rescue LoadError end end if AVAILABLE_PARSERS.empty? raise XMLParserNotFound end end ================================================ FILE: lib/rss/rexmlparser.rb ================================================ require "rexml/document" require "rexml/streamlistener" /\A(\d+)\.(\d+)(?:\.\d+)+\z/ =~ REXML::Version if ([$1.to_i, $2.to_i] <=> [2, 5]) < 0 raise LoadError, "needs REXML 2.5 or later (#{REXML::Version})" end module RSS class REXMLParser < BaseParser class << self def listener REXMLListener end end private def _parse begin REXML::Document.parse_stream(@rss, @listener) rescue RuntimeError => e raise NotWellFormedError.new{e.message} rescue REXML::ParseException => e context = e.context line = context[0] if context raise NotWellFormedError.new(line){e.message} end end end class REXMLListener < BaseListener include REXML::StreamListener include ListenerMixin class << self def raise_for_undefined_entity? false end end def xmldecl(version, encoding, standalone) super(version, encoding, standalone == "yes") # Encoding is converted to UTF-8 when REXML parse XML. @encoding = 'UTF-8' end alias_method(:cdata, :text) end end ================================================ FILE: lib/rss/rss.rb ================================================ require "time" class Time class << self unless respond_to?(:w3cdtf) def w3cdtf(date) if /\A\s* (-?\d+)-(\d\d)-(\d\d) (?:T (\d\d):(\d\d)(?::(\d\d))? (\.\d+)? (Z|[+-]\d\d:\d\d)?)? \s*\z/ix =~ date and (($5 and $8) or (!$5 and !$8)) datetime = [$1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i] usec = 0 usec = $7.to_f * 1000000 if $7 zone = $8 if zone off = zone_offset(zone, datetime[0]) datetime = apply_offset(*(datetime + [off])) datetime << usec time = Time.utc(*datetime) time.localtime unless zone_utc?(zone) time else datetime << usec Time.local(*datetime) end else raise ArgumentError.new("invalid date: #{date.inspect}") end end end end unless method_defined?(:w3cdtf) def w3cdtf if usec.zero? fraction_digits = 0 else fraction_digits = Math.log10(usec.to_s.sub(/0*$/, '').to_i).floor + 1 end xmlschema(fraction_digits) end end end require "English" require "rss/utils" require "rss/converter" require "rss/xml-stylesheet" module RSS VERSION = "0.2.4" URI = "http://purl.org/rss/1.0/" DEBUG = false class Error < StandardError; end class OverlappedPrefixError < Error attr_reader :prefix def initialize(prefix) @prefix = prefix end end class InvalidRSSError < Error; end class MissingTagError < InvalidRSSError attr_reader :tag, :parent def initialize(tag, parent) @tag, @parent = tag, parent super("tag <#{tag}> is missing in tag <#{parent}>") end end class TooMuchTagError < InvalidRSSError attr_reader :tag, :parent def initialize(tag, parent) @tag, @parent = tag, parent super("tag <#{tag}> is too much in tag <#{parent}>") end end class MissingAttributeError < InvalidRSSError attr_reader :tag, :attribute def initialize(tag, attribute) @tag, @attribute = tag, attribute super("attribute <#{attribute}> is missing in tag <#{tag}>") end end class UnknownTagError < InvalidRSSError attr_reader :tag, :uri def initialize(tag, uri) @tag, @uri = tag, uri super("tag <#{tag}> is unknown in namespace specified by uri <#{uri}>") end end class NotExpectedTagError < InvalidRSSError attr_reader :tag, :uri, :parent def initialize(tag, uri, parent) @tag, @uri, @parent = tag, uri, parent super("tag <{#{uri}}#{tag}> is not expected in tag <#{parent}>") end end # For backward compatibility :X NotExceptedTagError = NotExpectedTagError class NotAvailableValueError < InvalidRSSError attr_reader :tag, :value, :attribute def initialize(tag, value, attribute=nil) @tag, @value, @attribute = tag, value, attribute message = "value <#{value}> of " message << "attribute <#{attribute}> of " if attribute message << "tag <#{tag}> is not available." super(message) end end class UnknownConversionMethodError < Error attr_reader :to, :from def initialize(to, from) @to = to @from = from super("can't convert to #{to} from #{from}.") end end # for backward compatibility UnknownConvertMethod = UnknownConversionMethodError class ConversionError < Error attr_reader :string, :to, :from def initialize(string, to, from) @string = string @to = to @from = from super("can't convert #{@string} to #{to} from #{from}.") end end class NotSetError < Error attr_reader :name, :variables def initialize(name, variables) @name = name @variables = variables super("required variables of #{@name} are not set: #{@variables.join(', ')}") end end class UnsupportedMakerVersionError < Error attr_reader :version def initialize(version) @version = version super("Maker doesn't support version: #{@version}") end end module BaseModel include Utils def install_have_child_element(tag_name, uri, occurs, name=nil, type=nil) name ||= tag_name add_need_initialize_variable(name) install_model(tag_name, uri, occurs, name) writer_type, reader_type = type def_corresponded_attr_writer name, writer_type def_corresponded_attr_reader name, reader_type install_element(name) do |n, elem_name| <<-EOC if @#{n} "\#{@#{n}.to_s(need_convert, indent)}" else '' end EOC end end alias_method(:install_have_attribute_element, :install_have_child_element) def install_have_children_element(tag_name, uri, occurs, name=nil, plural_name=nil) name ||= tag_name plural_name ||= "#{name}s" add_have_children_element(name, plural_name) add_plural_form(name, plural_name) install_model(tag_name, uri, occurs, plural_name, true) def_children_accessor(name, plural_name) install_element(name, "s") do |n, elem_name| <<-EOC rv = [] @#{n}.each do |x| value = "\#{x.to_s(need_convert, indent)}" rv << value if /\\A\\s*\\z/ !~ value end rv.join("\n") EOC end end def install_text_element(tag_name, uri, occurs, name=nil, type=nil, disp_name=nil) name ||= tag_name disp_name ||= name self::ELEMENTS << name unless self::ELEMENTS.include?(name) add_need_initialize_variable(name) install_model(tag_name, uri, occurs, name) def_corresponded_attr_writer(name, type, disp_name) def_corresponded_attr_reader(name, type || :convert) install_element(name) do |n, elem_name| <<-EOC if respond_to?(:#{n}_content) content = #{n}_content else content = @#{n} end if content rv = "\#{indent}<#{elem_name}>" value = html_escape(content) if need_convert rv << convert(value) else rv << value end rv << "" rv else '' end EOC end end def install_date_element(tag_name, uri, occurs, name=nil, type=nil, disp_name=nil) name ||= tag_name type ||= :w3cdtf disp_name ||= name self::ELEMENTS << name add_need_initialize_variable(name) install_model(tag_name, uri, occurs, name) # accessor convert_attr_reader name date_writer(name, type, disp_name) install_element(name) do |n, elem_name| <<-EOC if @#{n} rv = "\#{indent}<#{elem_name}>" value = html_escape(@#{n}.#{type}) if need_convert rv << convert(value) else rv << value end rv << "" rv else '' end EOC end end private def install_element(name, postfix="") elem_name = name.sub('_', ':') method_name = "#{name}_element#{postfix}" add_to_element_method(method_name) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{method_name}(need_convert=true, indent='') #{yield(name, elem_name)} end private :#{method_name} EOC end def inherit_convert_attr_reader(*attrs) attrs.each do |attr| attr = attr.id2name if attr.kind_of?(Integer) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{attr}_without_inherit convert(@#{attr}) end def #{attr} if @#{attr} #{attr}_without_inherit elsif @parent @parent.#{attr} else nil end end EOC end end def uri_convert_attr_reader(*attrs) attrs.each do |attr| attr = attr.id2name if attr.kind_of?(Integer) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{attr}_without_base convert(@#{attr}) end def #{attr} value = #{attr}_without_base return nil if value.nil? if /\\A[a-z][a-z0-9+.\\-]*:/i =~ value value else "\#{base}\#{value}" end end EOC end end def convert_attr_reader(*attrs) attrs.each do |attr| attr = attr.id2name if attr.kind_of?(Integer) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{attr} convert(@#{attr}) end EOC end end def yes_clean_other_attr_reader(*attrs) attrs.each do |attr| attr = attr.id2name if attr.kind_of?(Integer) module_eval(<<-EOC, __FILE__, __LINE__ + 1) attr_reader(:#{attr}) def #{attr}? YesCleanOther.parse(@#{attr}) end EOC end end def yes_other_attr_reader(*attrs) attrs.each do |attr| attr = attr.id2name if attr.kind_of?(Integer) module_eval(<<-EOC, __FILE__, __LINE__ + 1) attr_reader(:#{attr}) def #{attr}? Utils::YesOther.parse(@#{attr}) end EOC end end def csv_attr_reader(*attrs) separator = nil if attrs.last.is_a?(Hash) options = attrs.pop separator = options[:separator] end separator ||= ", " attrs.each do |attr| attr = attr.id2name if attr.kind_of?(Integer) module_eval(<<-EOC, __FILE__, __LINE__ + 1) attr_reader(:#{attr}) def #{attr}_content if @#{attr}.nil? @#{attr} else @#{attr}.join(#{separator.dump}) end end EOC end end def date_writer(name, type, disp_name=name) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{name}=(new_value) if new_value.nil? @#{name} = new_value elsif new_value.kind_of?(Time) @#{name} = new_value.dup else if @do_validate begin @#{name} = Time.__send__('#{type}', new_value) rescue ArgumentError raise NotAvailableValueError.new('#{disp_name}', new_value) end else @#{name} = nil if /\\A\\s*\\z/ !~ new_value.to_s begin unless Date._parse(new_value, false).empty? @#{name} = Time.parse(new_value) end rescue ArgumentError end end end end # Is it need? if @#{name} class << @#{name} undef_method(:to_s) alias_method(:to_s, :#{type}) end end end EOC end def integer_writer(name, disp_name=name) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{name}=(new_value) if new_value.nil? @#{name} = new_value else if @do_validate begin @#{name} = Integer(new_value) rescue ArgumentError raise NotAvailableValueError.new('#{disp_name}', new_value) end else @#{name} = new_value.to_i end end end EOC end def positive_integer_writer(name, disp_name=name) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{name}=(new_value) if new_value.nil? @#{name} = new_value else if @do_validate begin tmp = Integer(new_value) raise ArgumentError if tmp <= 0 @#{name} = tmp rescue ArgumentError raise NotAvailableValueError.new('#{disp_name}', new_value) end else @#{name} = new_value.to_i end end end EOC end def boolean_writer(name, disp_name=name) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{name}=(new_value) if new_value.nil? @#{name} = new_value else if @do_validate and ![true, false, "true", "false"].include?(new_value) raise NotAvailableValueError.new('#{disp_name}', new_value) end if [true, false].include?(new_value) @#{name} = new_value else @#{name} = new_value == "true" end end end EOC end def text_type_writer(name, disp_name=name) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{name}=(new_value) if @do_validate and !["text", "html", "xhtml", nil].include?(new_value) raise NotAvailableValueError.new('#{disp_name}', new_value) end @#{name} = new_value end EOC end def content_writer(name, disp_name=name) klass_name = "self.class::#{Utils.to_class_name(name)}" module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{name}=(new_value) if new_value.is_a?(#{klass_name}) @#{name} = new_value else @#{name} = #{klass_name}.new @#{name}.content = new_value end end EOC end def yes_clean_other_writer(name, disp_name=name) module_eval(<<-EOC, __FILE__, __LINE__ + 1) def #{name}=(value) value = (value ? "yes" : "no") if [true, false].include?(value) @#{name} = value end EOC end def yes_other_writer(name, disp_name=name) module_eval(<<-EOC, __FILE__, __LINE__ + 1) def #{name}=(new_value) if [true, false].include?(new_value) new_value = new_value ? "yes" : "no" end @#{name} = new_value end EOC end def csv_writer(name, disp_name=name) module_eval(<<-EOC, __FILE__, __LINE__ + 1) def #{name}=(new_value) @#{name} = Utils::CSV.parse(new_value) end EOC end def csv_integer_writer(name, disp_name=name) module_eval(<<-EOC, __FILE__, __LINE__ + 1) def #{name}=(new_value) @#{name} = Utils::CSV.parse(new_value) {|v| Integer(v)} end EOC end def def_children_accessor(accessor_name, plural_name) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{plural_name} @#{accessor_name} end def #{accessor_name}(*args) if args.empty? @#{accessor_name}.first else @#{accessor_name}[*args] end end def #{accessor_name}=(*args) receiver = self.class.name warn("Warning:\#{caller.first.sub(/:in `.*'\z/, '')}: " \ "Don't use `\#{receiver}\##{accessor_name} = XXX'/" \ "`\#{receiver}\#set_#{accessor_name}(XXX)'. " \ "Those APIs are not sense of Ruby. " \ "Use `\#{receiver}\##{plural_name} << XXX' instead of them.") if args.size == 1 @#{accessor_name}.push(args[0]) else @#{accessor_name}.__send__("[]=", *args) end end alias_method(:set_#{accessor_name}, :#{accessor_name}=) EOC end end module SetupMaker def setup_maker(maker) target = maker_target(maker) unless target.nil? setup_maker_attributes(target) setup_maker_element(target) setup_maker_elements(target) end end private def maker_target(maker) nil end def setup_maker_attributes(target) end def setup_maker_element(target) self.class.need_initialize_variables.each do |var| value = __send__(var) next if value.nil? if value.respond_to?("setup_maker") and !not_need_to_call_setup_maker_variables.include?(var) value.setup_maker(target) else setter = "#{var}=" if target.respond_to?(setter) target.__send__(setter, value) end end end end def not_need_to_call_setup_maker_variables [] end def setup_maker_elements(parent) self.class.have_children_elements.each do |name, plural_name| if parent.respond_to?(plural_name) target = parent.__send__(plural_name) __send__(plural_name).each do |elem| elem.setup_maker(target) end end end end end class Element extend BaseModel include Utils extend Utils::InheritedReader include SetupMaker INDENT = " " MUST_CALL_VALIDATORS = {} MODELS = [] GET_ATTRIBUTES = [] HAVE_CHILDREN_ELEMENTS = [] TO_ELEMENT_METHODS = [] NEED_INITIALIZE_VARIABLES = [] PLURAL_FORMS = {} class << self def must_call_validators inherited_hash_reader("MUST_CALL_VALIDATORS") end def models inherited_array_reader("MODELS") end def get_attributes inherited_array_reader("GET_ATTRIBUTES") end def have_children_elements inherited_array_reader("HAVE_CHILDREN_ELEMENTS") end def to_element_methods inherited_array_reader("TO_ELEMENT_METHODS") end def need_initialize_variables inherited_array_reader("NEED_INITIALIZE_VARIABLES") end def plural_forms inherited_hash_reader("PLURAL_FORMS") end def inherited_base ::RSS::Element end def inherited(klass) klass.const_set("MUST_CALL_VALIDATORS", {}) klass.const_set("MODELS", []) klass.const_set("GET_ATTRIBUTES", []) klass.const_set("HAVE_CHILDREN_ELEMENTS", []) klass.const_set("TO_ELEMENT_METHODS", []) klass.const_set("NEED_INITIALIZE_VARIABLES", []) klass.const_set("PLURAL_FORMS", {}) tag_name = klass.name.split(/::/).last tag_name[0, 1] = tag_name[0, 1].downcase klass.instance_variable_set("@tag_name", tag_name) klass.instance_variable_set("@have_content", false) end def install_must_call_validator(prefix, uri) self::MUST_CALL_VALIDATORS[uri] = prefix end def install_model(tag, uri, occurs=nil, getter=nil, plural=false) getter ||= tag if m = self::MODELS.find {|t, u, o, g, p| t == tag and u == uri} m[2] = occurs else self::MODELS << [tag, uri, occurs, getter, plural] end end def install_get_attribute(name, uri, required=true, type=nil, disp_name=nil, element_name=nil) disp_name ||= name element_name ||= name writer_type, reader_type = type def_corresponded_attr_writer name, writer_type, disp_name def_corresponded_attr_reader name, reader_type if type == :boolean and /^is/ =~ name alias_method "#{$POSTMATCH}?", name end self::GET_ATTRIBUTES << [name, uri, required, element_name] add_need_initialize_variable(disp_name) end def def_corresponded_attr_writer(name, type=nil, disp_name=nil) disp_name ||= name case type when :integer integer_writer name, disp_name when :positive_integer positive_integer_writer name, disp_name when :boolean boolean_writer name, disp_name when :w3cdtf, :rfc822, :rfc2822 date_writer name, type, disp_name when :text_type text_type_writer name, disp_name when :content content_writer name, disp_name when :yes_clean_other yes_clean_other_writer name, disp_name when :yes_other yes_other_writer name, disp_name when :csv csv_writer name when :csv_integer csv_integer_writer name else attr_writer name end end def def_corresponded_attr_reader(name, type=nil) case type when :inherit inherit_convert_attr_reader name when :uri uri_convert_attr_reader name when :yes_clean_other yes_clean_other_attr_reader name when :yes_other yes_other_attr_reader name when :csv csv_attr_reader name when :csv_integer csv_attr_reader name, :separator => "," else convert_attr_reader name end end def content_setup(type=nil, disp_name=nil) writer_type, reader_type = type def_corresponded_attr_writer :content, writer_type, disp_name def_corresponded_attr_reader :content, reader_type @have_content = true end def have_content? @have_content end def add_have_children_element(variable_name, plural_name) self::HAVE_CHILDREN_ELEMENTS << [variable_name, plural_name] end def add_to_element_method(method_name) self::TO_ELEMENT_METHODS << method_name end def add_need_initialize_variable(variable_name) self::NEED_INITIALIZE_VARIABLES << variable_name end def add_plural_form(singular, plural) self::PLURAL_FORMS[singular] = plural end def required_prefix nil end def required_uri "" end def need_parent? false end def install_ns(prefix, uri) if self::NSPOOL.has_key?(prefix) raise OverlappedPrefixError.new(prefix) end self::NSPOOL[prefix] = uri end def tag_name @tag_name end end attr_accessor :parent, :do_validate def initialize(do_validate=true, attrs=nil) @parent = nil @converter = nil if attrs.nil? and (do_validate.is_a?(Hash) or do_validate.is_a?(Array)) do_validate, attrs = true, do_validate end @do_validate = do_validate initialize_variables(attrs || {}) end def tag_name self.class.tag_name end def full_name tag_name end def converter=(converter) @converter = converter targets = children.dup self.class.have_children_elements.each do |variable_name, plural_name| targets.concat(__send__(plural_name)) end targets.each do |target| target.converter = converter unless target.nil? end end def convert(value) if @converter @converter.convert(value) else value end end def valid?(ignore_unknown_element=true) validate(ignore_unknown_element) true rescue RSS::Error false end def validate(ignore_unknown_element=true) do_validate = @do_validate @do_validate = true validate_attribute __validate(ignore_unknown_element) ensure @do_validate = do_validate end def validate_for_stream(tags, ignore_unknown_element=true) validate_attribute __validate(ignore_unknown_element, tags, false) end def to_s(need_convert=true, indent='') if self.class.have_content? return "" if !empty_content? and !content_is_set? rv = tag(indent) do |next_indent| if empty_content? "" else xmled_content end end else rv = tag(indent) do |next_indent| self.class.to_element_methods.collect do |method_name| __send__(method_name, false, next_indent) end end end rv = convert(rv) if need_convert rv end def have_xml_content? false end def need_base64_encode? false end def set_next_element(tag_name, next_element) klass = next_element.class prefix = "" prefix << "#{klass.required_prefix}_" if klass.required_prefix key = "#{prefix}#{tag_name.gsub(/-/, '_')}" if self.class.plural_forms.has_key?(key) ary = __send__("#{self.class.plural_forms[key]}") ary << next_element else __send__("#{key}=", next_element) end end protected def have_required_elements? self.class::MODELS.all? do |tag, uri, occurs, getter| if occurs.nil? or occurs == "+" child = __send__(getter) if child.is_a?(Array) children = child children.any? {|c| c.have_required_elements?} else !child.to_s.empty? end else true end end end private def initialize_variables(attrs) normalized_attrs = {} attrs.each do |key, value| normalized_attrs[key.to_s] = value end self.class.need_initialize_variables.each do |variable_name| value = normalized_attrs[variable_name.to_s] if value __send__("#{variable_name}=", value) else instance_variable_set("@#{variable_name}", nil) end end initialize_have_children_elements @content = normalized_attrs["content"] if self.class.have_content? end def initialize_have_children_elements self.class.have_children_elements.each do |variable_name, plural_name| instance_variable_set("@#{variable_name}", []) end end def tag(indent, additional_attrs={}, &block) next_indent = indent + INDENT attrs = collect_attrs return "" if attrs.nil? return "" unless have_required_elements? attrs.update(additional_attrs) start_tag = make_start_tag(indent, next_indent, attrs.dup) if block content = block.call(next_indent) else content = [] end if content.is_a?(String) content = [content] start_tag << ">" end_tag = "" else content = content.reject{|x| x.empty?} if content.empty? return "" if attrs.empty? end_tag = "/>" else start_tag << ">\n" end_tag = "\n#{indent}" end end start_tag + content.join("\n") + end_tag end def make_start_tag(indent, next_indent, attrs) start_tag = ["#{indent}<#{full_name}"] unless attrs.empty? start_tag << attrs.collect do |key, value| %Q[#{h key}="#{h value}"] end.join("\n#{next_indent}") end start_tag.join(" ") end def collect_attrs attrs = {} _attrs.each do |name, required, alias_name| value = __send__(alias_name || name) return nil if required and value.nil? next if value.nil? return nil if attrs.has_key?(name) attrs[name] = value end attrs end def tag_name_with_prefix(prefix) "#{prefix}:#{tag_name}" end # For backward compatibility def calc_indent '' end def children rv = [] self.class.models.each do |name, uri, occurs, getter| value = __send__(getter) next if value.nil? value = [value] unless value.is_a?(Array) value.each do |v| rv << v if v.is_a?(Element) end end rv end def _tags rv = [] self.class.models.each do |name, uri, occurs, getter, plural| value = __send__(getter) next if value.nil? if plural and value.is_a?(Array) rv.concat([[uri, name]] * value.size) else rv << [uri, name] end end rv end def _attrs self.class.get_attributes.collect do |name, uri, required, element_name| [element_name, required, name] end end def __validate(ignore_unknown_element, tags=_tags, recursive=true) if recursive children.compact.each do |child| child.validate end end must_call_validators = self.class.must_call_validators tags = tag_filter(tags.dup) p tags if DEBUG must_call_validators.each do |uri, prefix| _validate(ignore_unknown_element, tags[uri], uri) meth = "#{prefix}_validate" if !prefix.empty? and respond_to?(meth, true) __send__(meth, ignore_unknown_element, tags[uri], uri) end end end def validate_attribute _attrs.each do |a_name, required, alias_name| value = instance_variable_get("@#{alias_name || a_name}") if required and value.nil? raise MissingAttributeError.new(tag_name, a_name) end __send__("#{alias_name || a_name}=", value) end end def _validate(ignore_unknown_element, tags, uri, models=self.class.models) count = 1 do_redo = false not_shift = false tag = nil models = models.find_all {|model| model[1] == uri} element_names = models.collect {|model| model[0]} if tags tags_size = tags.size tags = tags.sort_by {|x| element_names.index(x) || tags_size} end _tags = tags.dup if tags models.each_with_index do |model, i| name, model_uri, occurs, getter = model if DEBUG p "before" p tags p model end if not_shift not_shift = false elsif tags tag = tags.shift end if DEBUG p "mid" p count end case occurs when '?' if count > 2 raise TooMuchTagError.new(name, tag_name) else if name == tag do_redo = true else not_shift = true end end when '*' if name == tag do_redo = true else not_shift = true end when '+' if name == tag do_redo = true else if count > 1 not_shift = true else raise MissingTagError.new(name, tag_name) end end else if name == tag if models[i+1] and models[i+1][0] != name and tags and tags.first == name raise TooMuchTagError.new(name, tag_name) end else raise MissingTagError.new(name, tag_name) end end if DEBUG p "after" p not_shift p do_redo p tag end if do_redo do_redo = false count += 1 redo else count = 1 end end if !ignore_unknown_element and !tags.nil? and !tags.empty? raise NotExpectedTagError.new(tags.first, uri, tag_name) end end def tag_filter(tags) rv = {} tags.each do |tag| rv[tag[0]] = [] unless rv.has_key?(tag[0]) rv[tag[0]].push(tag[1]) end rv end def empty_content? false end def content_is_set? if have_xml_content? __send__(self.class.xml_getter) else content end end def xmled_content if have_xml_content? __send__(self.class.xml_getter).to_s else _content = content _content = Base64.encode64(_content) if need_base64_encode? h(_content) end end end module RootElementMixin include XMLStyleSheetMixin attr_reader :output_encoding attr_reader :feed_type, :feed_subtype, :feed_version attr_accessor :version, :encoding, :standalone def initialize(feed_version, version=nil, encoding=nil, standalone=nil) super() @feed_type = nil @feed_subtype = nil @feed_version = feed_version @version = version || '1.0' @encoding = encoding @standalone = standalone @output_encoding = nil end def feed_info [@feed_type, @feed_version, @feed_subtype] end def output_encoding=(enc) @output_encoding = enc self.converter = Converter.new(@output_encoding, @encoding) end def setup_maker(maker) maker.version = version maker.encoding = encoding maker.standalone = standalone xml_stylesheets.each do |xss| xss.setup_maker(maker) end super end def to_feed(type, &block) Maker.make(type) do |maker| setup_maker(maker) block.call(maker) if block end end def to_rss(type, &block) to_feed("rss#{type}", &block) end def to_atom(type, &block) to_feed("atom:#{type}", &block) end def to_xml(type=nil, &block) if type.nil? or same_feed_type?(type) to_s else to_feed(type, &block).to_s end end private def same_feed_type?(type) if /^(atom|rss)?(\d+\.\d+)?(?::(.+))?$/i =~ type feed_type = ($1 || @feed_type).downcase feed_version = $2 || @feed_version feed_subtype = $3 || @feed_subtype [feed_type, feed_version, feed_subtype] == feed_info else false end end def tag(indent, attrs={}, &block) rv = super(indent, ns_declarations.merge(attrs), &block) return rv if rv.empty? "#{xmldecl}#{xml_stylesheet_pi}#{rv}" end def xmldecl rv = %Q[\n" rv end def ns_declarations decls = {} self.class::NSPOOL.collect do |prefix, uri| prefix = ":#{prefix}" unless prefix.empty? decls["xmlns#{prefix}"] = uri end decls end def maker_target(target) target end end end ================================================ FILE: lib/rss/slash.rb ================================================ require 'rss/1.0' module RSS SLASH_PREFIX = 'slash' SLASH_URI = "http://purl.org/rss/1.0/modules/slash/" RDF.install_ns(SLASH_PREFIX, SLASH_URI) module SlashModel extend BaseModel ELEMENT_INFOS = \ [ ["section"], ["department"], ["comments", :positive_integer], ["hit_parade", :csv_integer], ] class << self def append_features(klass) super return if klass.instance_of?(Module) klass.install_must_call_validator(SLASH_PREFIX, SLASH_URI) ELEMENT_INFOS.each do |name, type, *additional_infos| full_name = "#{SLASH_PREFIX}_#{name}" klass.install_text_element(full_name, SLASH_URI, "?", full_name, type, name) end klass.module_eval do alias_method(:slash_hit_parades, :slash_hit_parade) undef_method(:slash_hit_parade) alias_method(:slash_hit_parade, :slash_hit_parade_content) end end end end class RDF class Item; include SlashModel; end end SlashModel::ELEMENT_INFOS.each do |name, type| accessor_base = "#{SLASH_PREFIX}_#{name}" BaseListener.install_get_text_element(SLASH_URI, name, accessor_base) end end ================================================ FILE: lib/rss/syndication.rb ================================================ require "rss/1.0" module RSS SY_PREFIX = 'sy' SY_URI = "http://purl.org/rss/1.0/modules/syndication/" RDF.install_ns(SY_PREFIX, SY_URI) module SyndicationModel extend BaseModel ELEMENTS = [] def self.append_features(klass) super klass.install_must_call_validator(SY_PREFIX, SY_URI) klass.module_eval do [ ["updatePeriod"], ["updateFrequency", :positive_integer] ].each do |name, type| install_text_element(name, SY_URI, "?", "#{SY_PREFIX}_#{name}", type, "#{SY_PREFIX}:#{name}") end %w(updateBase).each do |name| install_date_element(name, SY_URI, "?", "#{SY_PREFIX}_#{name}", 'w3cdtf', "#{SY_PREFIX}:#{name}") end end klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) alias_method(:_sy_updatePeriod=, :sy_updatePeriod=) def sy_updatePeriod=(new_value) new_value = new_value.strip validate_sy_updatePeriod(new_value) if @do_validate self._sy_updatePeriod = new_value end EOC end private SY_UPDATEPERIOD_AVAILABLE_VALUES = %w(hourly daily weekly monthly yearly) def validate_sy_updatePeriod(value) unless SY_UPDATEPERIOD_AVAILABLE_VALUES.include?(value) raise NotAvailableValueError.new("updatePeriod", value) end end end class RDF class Channel; include SyndicationModel; end end prefix_size = SY_PREFIX.size + 1 SyndicationModel::ELEMENTS.uniq! SyndicationModel::ELEMENTS.each do |full_name| name = full_name[prefix_size..-1] BaseListener.install_get_text_element(SY_URI, name, full_name) end end ================================================ FILE: lib/rss/taxonomy.rb ================================================ require "rss/1.0" require "rss/dublincore" module RSS TAXO_PREFIX = "taxo" TAXO_URI = "http://purl.org/rss/1.0/modules/taxonomy/" RDF.install_ns(TAXO_PREFIX, TAXO_URI) TAXO_ELEMENTS = [] %w(link).each do |name| full_name = "#{TAXO_PREFIX}_#{name}" BaseListener.install_get_text_element(TAXO_URI, name, full_name) TAXO_ELEMENTS << "#{TAXO_PREFIX}_#{name}" end %w(topic topics).each do |name| class_name = Utils.to_class_name(name) BaseListener.install_class_name(TAXO_URI, name, "Taxonomy#{class_name}") TAXO_ELEMENTS << "#{TAXO_PREFIX}_#{name}" end module TaxonomyTopicsModel extend BaseModel def self.append_features(klass) super klass.install_must_call_validator(TAXO_PREFIX, TAXO_URI) %w(topics).each do |name| klass.install_have_child_element(name, TAXO_URI, "?", "#{TAXO_PREFIX}_#{name}") end end class TaxonomyTopics < Element include RSS10 Bag = ::RSS::RDF::Bag class << self def required_prefix TAXO_PREFIX end def required_uri TAXO_URI end end @tag_name = "topics" install_have_child_element("Bag", RDF::URI, nil) install_must_call_validator('rdf', RDF::URI) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.Bag = args[0] end self.Bag ||= Bag.new end def full_name tag_name_with_prefix(TAXO_PREFIX) end def maker_target(target) target.taxo_topics end def resources if @Bag @Bag.lis.collect do |li| li.resource end else [] end end end end module TaxonomyTopicModel extend BaseModel def self.append_features(klass) super var_name = "#{TAXO_PREFIX}_topic" klass.install_have_children_element("topic", TAXO_URI, "*", var_name) end class TaxonomyTopic < Element include RSS10 include DublinCoreModel include TaxonomyTopicsModel class << self def required_prefix TAXO_PREFIX end def required_uri TAXO_URI end end @tag_name = "topic" install_get_attribute("about", ::RSS::RDF::URI, true, nil, nil, "#{RDF::PREFIX}:about") install_text_element("link", TAXO_URI, "?", "#{TAXO_PREFIX}_link") def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.about = args[0] end end def full_name tag_name_with_prefix(TAXO_PREFIX) end def maker_target(target) target.new_taxo_topic end end end class RDF include TaxonomyTopicModel class Channel include TaxonomyTopicsModel end class Item; include TaxonomyTopicsModel; end end end ================================================ FILE: lib/rss/trackback.rb ================================================ require 'rss/1.0' require 'rss/2.0' module RSS TRACKBACK_PREFIX = 'trackback' TRACKBACK_URI = 'http://madskills.com/public/xml/rss/module/trackback/' RDF.install_ns(TRACKBACK_PREFIX, TRACKBACK_URI) Rss.install_ns(TRACKBACK_PREFIX, TRACKBACK_URI) module TrackBackUtils private def trackback_validate(ignore_unknown_element, tags, uri) return if tags.nil? if tags.find {|tag| tag == "about"} and !tags.find {|tag| tag == "ping"} raise MissingTagError.new("#{TRACKBACK_PREFIX}:ping", tag_name) end end end module BaseTrackBackModel ELEMENTS = %w(ping about) def append_features(klass) super unless klass.class == Module klass.module_eval {include TrackBackUtils} klass.install_must_call_validator(TRACKBACK_PREFIX, TRACKBACK_URI) %w(ping).each do |name| var_name = "#{TRACKBACK_PREFIX}_#{name}" klass_name = "TrackBack#{Utils.to_class_name(name)}" klass.install_have_child_element(name, TRACKBACK_URI, "?", var_name) klass.module_eval(<<-EOC, __FILE__, __LINE__) remove_method :#{var_name} def #{var_name} @#{var_name} and @#{var_name}.value end remove_method :#{var_name}= def #{var_name}=(value) @#{var_name} = Utils.new_with_value_if_need(#{klass_name}, value) end EOC end [%w(about s)].each do |name, postfix| var_name = "#{TRACKBACK_PREFIX}_#{name}" klass_name = "TrackBack#{Utils.to_class_name(name)}" klass.install_have_children_element(name, TRACKBACK_URI, "*", var_name) klass.module_eval(<<-EOC, __FILE__, __LINE__) remove_method :#{var_name} def #{var_name}(*args) if args.empty? @#{var_name}.first and @#{var_name}.first.value else ret = @#{var_name}.__send__("[]", *args) if ret.is_a?(Array) ret.collect {|x| x.value} else ret.value end end end remove_method :#{var_name}= remove_method :set_#{var_name} def #{var_name}=(*args) if args.size == 1 item = Utils.new_with_value_if_need(#{klass_name}, args[0]) @#{var_name}.push(item) else new_val = args.last if new_val.is_a?(Array) new_val = new_value.collect do |val| Utils.new_with_value_if_need(#{klass_name}, val) end else new_val = Utils.new_with_value_if_need(#{klass_name}, new_val) end @#{var_name}.__send__("[]=", *(args[0..-2] + [new_val])) end end alias set_#{var_name} #{var_name}= EOC end end end end module TrackBackModel10 extend BaseModel extend BaseTrackBackModel class TrackBackPing < Element include RSS10 class << self def required_prefix TRACKBACK_PREFIX end def required_uri TRACKBACK_URI end end @tag_name = "ping" [ ["resource", ::RSS::RDF::URI, true] ].each do |name, uri, required| install_get_attribute(name, uri, required, nil, nil, "#{::RSS::RDF::PREFIX}:#{name}") end alias_method(:value, :resource) alias_method(:value=, :resource=) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.resource = args[0] end end def full_name tag_name_with_prefix(TRACKBACK_PREFIX) end end class TrackBackAbout < Element include RSS10 class << self def required_prefix TRACKBACK_PREFIX end def required_uri TRACKBACK_URI end end @tag_name = "about" [ ["resource", ::RSS::RDF::URI, true] ].each do |name, uri, required| install_get_attribute(name, uri, required, nil, nil, "#{::RSS::RDF::PREFIX}:#{name}") end alias_method(:value, :resource) alias_method(:value=, :resource=) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.resource = args[0] end end def full_name tag_name_with_prefix(TRACKBACK_PREFIX) end private def maker_target(abouts) abouts.new_about end def setup_maker_attributes(about) about.resource = self.resource end end end module TrackBackModel20 extend BaseModel extend BaseTrackBackModel class TrackBackPing < Element include RSS09 @tag_name = "ping" content_setup class << self def required_prefix TRACKBACK_PREFIX end def required_uri TRACKBACK_URI end end alias_method(:value, :content) alias_method(:value=, :content=) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.content = args[0] end end def full_name tag_name_with_prefix(TRACKBACK_PREFIX) end end class TrackBackAbout < Element include RSS09 @tag_name = "about" content_setup class << self def required_prefix TRACKBACK_PREFIX end def required_uri TRACKBACK_URI end end alias_method(:value, :content) alias_method(:value=, :content=) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.content = args[0] end end def full_name tag_name_with_prefix(TRACKBACK_PREFIX) end end end class RDF class Item; include TrackBackModel10; end end class Rss class Channel class Item; include TrackBackModel20; end end end BaseTrackBackModel::ELEMENTS.each do |name| class_name = Utils.to_class_name(name) BaseListener.install_class_name(TRACKBACK_URI, name, "TrackBack#{class_name}") end BaseTrackBackModel::ELEMENTS.collect! {|name| "#{TRACKBACK_PREFIX}_#{name}"} end ================================================ FILE: lib/rss/utils.rb ================================================ module RSS module Utils module_function # Convert a name_with_underscores to CamelCase. def to_class_name(name) name.split(/[_\-]/).collect do |part| "#{part[0, 1].upcase}#{part[1..-1]}" end.join("") end def get_file_and_line_from_caller(i=0) file, line, = caller[i].split(':') line = line.to_i line += 1 if i.zero? [file, line] end # escape '&', '"', '<' and '>' for use in HTML. def html_escape(s) s.to_s.gsub(/&/, "&").gsub(/\"/, """).gsub(/>/, ">").gsub(/ "text/xsl", "css" => "text/css", } attr_accessor(*ATTRIBUTES) attr_accessor(:do_validate) def initialize(*attrs) if attrs.size == 1 and (attrs.first.is_a?(Hash) or attrs.first.is_a?(Array)) attrs = attrs.first end @do_validate = true ATTRIBUTES.each do |attr| __send__("#{attr}=", nil) end vars = ATTRIBUTES.dup vars.unshift(:do_validate) attrs.each do |name, value| if vars.include?(name.to_s) __send__("#{name}=", value) end end end def to_s rv = "" if @href rv << %Q[] end rv end remove_method(:href=) def href=(value) @href = value if @href and @type.nil? @type = guess_type(@href) end @href end remove_method(:alternate=) def alternate=(value) if value.nil? or /\A(?:yes|no)\z/ =~ value @alternate = value else if @do_validate args = ["?xml-stylesheet?", %Q[alternate="#{value}"]] raise NotAvailableValueError.new(*args) end end @alternate end def setup_maker(maker) xss = maker.xml_stylesheets.new_xml_stylesheet ATTRIBUTES.each do |attr| xss.__send__("#{attr}=", __send__(attr)) end end private def guess_type(filename) /\.([^.]+)$/ =~ filename GUESS_TABLE[$1] end end end ================================================ FILE: lib/rss/xml.rb ================================================ require "rss/utils" module RSS module XML class Element include Enumerable attr_reader :name, :prefix, :uri, :attributes, :children def initialize(name, prefix=nil, uri=nil, attributes={}, children=[]) @name = name @prefix = prefix @uri = uri @attributes = attributes if children.is_a?(String) or !children.respond_to?(:each) @children = [children] else @children = children end end def [](name) @attributes[name] end def []=(name, value) @attributes[name] = value end def <<(child) @children << child end def each(&block) @children.each(&block) end def ==(other) other.kind_of?(self.class) and @name == other.name and @uri == other.uri and @attributes == other.attributes and @children == other.children end def to_s rv = "<#{full_name}" attributes.each do |key, value| rv << " #{Utils.html_escape(key)}=\"#{Utils.html_escape(value)}\"" end if children.empty? rv << "/>" else rv << ">" children.each do |child| rv << child.to_s end rv << "" end rv end def full_name if @prefix "#{@prefix}:#{@name}" else @name end end end end end ================================================ FILE: lib/rss/xmlparser.rb ================================================ begin require "xml/parser" rescue LoadError require "xmlparser" end begin require "xml/encoding-ja" rescue LoadError require "xmlencoding-ja" if defined?(Kconv) module XMLEncoding_ja class SJISHandler include Kconv end end end end module XML class Parser unless defined?(Error) Error = ::XMLParserError end end end module RSS class REXMLLikeXMLParser < ::XML::Parser include ::XML::Encoding_ja def listener=(listener) @listener = listener end def startElement(name, attrs) @listener.tag_start(name, attrs) end def endElement(name) @listener.tag_end(name) end def character(data) @listener.text(data) end def xmlDecl(version, encoding, standalone) @listener.xmldecl(version, encoding, standalone == 1) end def processingInstruction(target, content) @listener.instruction(target, content) end end class XMLParserParser < BaseParser class << self def listener XMLParserListener end end private def _parse begin parser = REXMLLikeXMLParser.new parser.listener = @listener parser.parse(@rss) rescue ::XML::Parser::Error => e raise NotWellFormedError.new(parser.line){e.message} end end end class XMLParserListener < BaseListener include ListenerMixin def xmldecl(version, encoding, standalone) super # Encoding is converted to UTF-8 when XMLParser parses XML. @encoding = 'UTF-8' end end end ================================================ FILE: lib/rss/xmlscanner.rb ================================================ require 'xmlscan/scanner' require 'stringio' module RSS class XMLScanParser < BaseParser class << self def listener XMLScanListener end end private def _parse begin if @rss.is_a?(String) input = StringIO.new(@rss) else input = @rss end scanner = XMLScan::XMLScanner.new(@listener) scanner.parse(input) rescue XMLScan::Error => e lineno = e.lineno || scanner.lineno || input.lineno raise NotWellFormedError.new(lineno){e.message} end end end class XMLScanListener < BaseListener include XMLScan::Visitor include ListenerMixin ENTITIES = { 'lt' => '<', 'gt' => '>', 'amp' => '&', 'quot' => '"', 'apos' => '\'' } def on_xmldecl_version(str) @version = str end def on_xmldecl_encoding(str) @encoding = str end def on_xmldecl_standalone(str) @standalone = str end def on_xmldecl_end xmldecl(@version, @encoding, @standalone == "yes") end alias_method(:on_pi, :instruction) alias_method(:on_chardata, :text) alias_method(:on_cdata, :text) def on_etag(name) tag_end(name) end def on_entityref(ref) text(entity(ref)) end def on_charref(code) text([code].pack('U')) end alias_method(:on_charref_hex, :on_charref) def on_stag(name) @attrs = {} end def on_attribute(name) @attrs[name] = @current_attr = '' end def on_attr_value(str) @current_attr << str end def on_attr_entityref(ref) @current_attr << entity(ref) end def on_attr_charref(code) @current_attr << [code].pack('U') end alias_method(:on_attr_charref_hex, :on_attr_charref) def on_stag_end(name) tag_start(name, @attrs) end def on_stag_end_empty(name) tag_start(name, @attrs) tag_end(name) end private def entity(ref) ent = ENTITIES[ref] if ent ent else wellformed_error("undefined entity: #{ref}") end end end end ================================================ FILE: lib/rss.rb ================================================ # Copyright (c) 2003-2007 Kouhei Sutou. You can redistribute it and/or # modify it under the same terms as Ruby. # # Author:: Kouhei Sutou # Tutorial:: http://www.cozmixng.org/~rwiki/?cmd=view;name=RSS+Parser%3A%3ATutorial.en require 'rss/1.0' require 'rss/2.0' require 'rss/atom' require 'rss/content' require 'rss/dublincore' require 'rss/image' require 'rss/itunes' require 'rss/slash' require 'rss/syndication' require 'rss/taxonomy' require 'rss/trackback' require "rss/maker" ================================================ FILE: lib/rubyunit.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'runit/testcase' require 'test/unit' ================================================ FILE: lib/runit/assert.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/assertions' require 'runit/error' module RUNIT module Assert include Test::Unit::Assertions def setup_assert end def assert_no_exception(*args, &block) assert_nothing_raised(*args, &block) end # To deal with the fact that RubyUnit does not check that the # regular expression is, indeed, a regular expression, if it is # not, we do our own assertion using the same semantics as # RubyUnit def assert_match(actual_string, expected_re, message="") _wrap_assertion { full_message = build_message(message, "Expected to match ", actual_string, expected_re) assert_block(full_message) { expected_re =~ actual_string } Regexp.last_match } end def assert_not_nil(actual, message="") assert(!actual.nil?, message) end def assert_not_match(actual_string, expected_re, message="") assert_no_match(expected_re, actual_string, message) end def assert_matches(*args) assert_match(*args) end def assert_fail(message="") flunk(message) end def assert_equal_float(expected, actual, delta, message="") assert_in_delta(expected, actual, delta, message) end def assert_send(object, method, *args) super([object, method, *args]) end def assert_exception(exception, message="", &block) assert_raises(exception, message, &block) end def assert_respond_to(method, object, message="") if (called_internally?) super else super(object, method, message) end end def called_internally? /assertions\.rb/.match(caller[1]) end end end ================================================ FILE: lib/runit/cui/testrunner.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/ui/console/testrunner' require 'runit/testresult' module RUNIT module CUI class TestRunner < Test::Unit::UI::Console::TestRunner @@quiet_mode = false def self.run(suite) self.new().run(suite) end def initialize super nil end def run(suite, quiet_mode=@@quiet_mode) @suite = suite def @suite.suite self end @output_level = (quiet_mode ? Test::Unit::UI::PROGRESS_ONLY : Test::Unit::UI::VERBOSE) start end def create_mediator(suite) mediator = Test::Unit::UI::TestRunnerMediator.new(suite) class << mediator attr_writer :result_delegate def create_result return @result_delegate.create_result end end mediator.result_delegate = self return mediator end def create_result return RUNIT::TestResult.new end def self.quiet_mode=(boolean) @@quiet_mode = boolean end end end end ================================================ FILE: lib/runit/error.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/assertionfailederror.rb' module RUNIT AssertionFailedError = Test::Unit::AssertionFailedError end ================================================ FILE: lib/runit/testcase.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'runit/testresult' require 'runit/testsuite' require 'runit/assert' require 'runit/error' require 'test/unit/testcase' module RUNIT class TestCase < Test::Unit::TestCase include RUNIT::Assert def self.suite method_names = instance_methods(true) tests = method_names.delete_if { |method_name| method_name !~ /^test/ } suite = TestSuite.new(name) tests.each { |test| catch(:invalid_test) { suite << new(test, name) } } return suite end def initialize(test_name, suite_name=self.class.name) super(test_name) end def assert_equals(*args) assert_equal(*args) end def name super.sub(/^(.*?)\((.*)\)$/, '\2#\1') end def run(result, &progress_block) progress_block = proc {} unless (block_given?) super(result, &progress_block) end end end ================================================ FILE: lib/runit/testresult.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/testresult' module RUNIT class TestResult < Test::Unit::TestResult attr_reader(:errors, :failures) def succeed? return passed? end def failure_size return failure_count end def run_asserts return assertion_count end def error_size return error_count end def run_tests return run_count end def add_failure(failure) def failure.at return location end def failure.err return message end super(failure) end def add_error(error) def error.at return location end def error.err return exception end super(error) end end end ================================================ FILE: lib/runit/testsuite.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/testsuite' module RUNIT class TestSuite < Test::Unit::TestSuite def add_test(*args) add(*args) end def add(*args) self.<<(*args) end def count_test_cases return size end def run(result, &progress_block) progress_block = proc {} unless (block_given?) super(result, &progress_block) end end end ================================================ FILE: lib/runit/topublic.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module RUNIT module ToPublic end end ================================================ FILE: lib/scanf.rb ================================================ # scanf for Ruby # # $Revision$ # $Id$ # $Author$ # $Date$ # # A product of the Austin Ruby Codefest (Austin, Texas, August 2002) =begin =scanf for Ruby ==Description scanf for Ruby is an implementation of the C function scanf(3), modified as necessary for Ruby compatibility. The methods provided are String#scanf, IO#scanf, and Kernel#scanf. Kernel#scanf is a wrapper around STDIN.scanf. IO#scanf can be used on any IO stream, including file handles and sockets. scanf can be called either with or without a block. scanf for Ruby scans an input string or stream according to a format, as described below ("Conversions"), and returns an array of matches between the format and the input. The format is defined in a string, and is similar (though not identical) to the formats used in Kernel#printf and Kernel#sprintf. The format may contain conversion specifiers, which tell scanf what form (type) each particular matched substring should be converted to (e.g., decimal integer, floating point number, literal string, etc.) The matches and conversions take place from left to right, and the conversions themselves are returned as an array. The format string may also contain characters other than those in the conversion specifiers. White space (blanks, tabs, or newlines) in the format string matches any amount of white space, including none, in the input. Everything else matches only itself. Scanning stops, and scanf returns, when any input character fails to match the specifications in the format string, or when input is exhausted, or when everything in the format string has been matched. All matches found up to the stopping point are returned in the return array (or yielded to the block, if a block was given). ==Basic usage require 'scanf.rb' # String#scanf and IO#scanf take a single argument (a format string) array = aString.scanf("%d%s") array = anIO.scanf("%d%s") # Kernel#scanf reads from STDIN array = scanf("%d%s") ==Block usage When called with a block, scanf keeps scanning the input, cycling back to the beginning of the format string, and yields a new array of conversions to the block every time the format string is matched (including partial matches, but not including complete failures). The actual return value of scanf when called with a block is an array containing the results of all the executions of the block. str = "123 abc 456 def 789 ghi" str.scanf("%d%s") { |num,str| [ num * 2, str.upcase ] } # => [[246, "ABC"], [912, "DEF"], [1578, "GHI"]] ==Conversions The single argument to scanf is a format string, which generally includes one or more conversion specifiers. Conversion specifiers begin with the percent character ('%') and include information about what scanf should next scan for (string, decimal number, single character, etc.). There may be an optional maximum field width, expressed as a decimal integer, between the % and the conversion. If no width is given, a default of `infinity' is used (with the exception of the %c specifier; see below). Otherwise, given a field width of n for a given conversion, at most n characters are scanned in processing that conversion. Before conversion begins, most conversions skip white space in the input string; this white space is not counted against the field width. The following conversions are available. (See the files EXAMPLES and tests/scanftests.rb for examples.) [%] Matches a literal `%'. That is, `%%' in the format string matches a single input `%' character. No conversion is done, and the resulting '%' is not included in the return array. [d] Matches an optionally signed decimal integer. [u] Same as d. [i] Matches an optionally signed integer. The integer is read in base 16 if it begins with `0x' or `0X', in base 8 if it begins with `0', and in base 10 other- wise. Only characters that correspond to the base are recognized. [o] Matches an optionally signed octal integer. [x,X] Matches an optionally signed hexadecimal integer, [f,g,e,E] Matches an optionally signed floating-point number. [s] Matches a sequence of non-white-space character. The input string stops at white space or at the maximum field width, whichever occurs first. [c] Matches a single character, or a sequence of n characters if a field width of n is specified. The usual skip of leading white space is suppressed. To skip white space first, use an explicit space in the format. [[] Matches a nonempty sequence of characters from the specified set of accepted characters. The usual skip of leading white space is suppressed. This bracketed sub-expression is interpreted exactly like a character class in a Ruby regular expression. (In fact, it is placed as-is in a regular expression.) The matching against the input string ends with the appearance of a character not in (or, with a circumflex, in) the set, or when the field width runs out, whichever comes first. ===Assignment suppression To require that a particular match occur, but without including the result in the return array, place the assignment suppression flag, which is the star character ('*'), immediately after the leading '%' of a format specifier (just before the field width, if any). ==Examples See the files EXAMPLES and tests/scanftests.rb. ==scanf for Ruby compared with scanf in C scanf for Ruby is based on the C function scanf(3), but with modifications, dictated mainly by the underlying differences between the languages. ===Unimplemented flags and specifiers * The only flag implemented in scanf for Ruby is '*' (ignore upcoming conversion). Many of the flags available in C versions of scanf(4) have to do with the type of upcoming pointer arguments, and are literally meaningless in Ruby. * The n specifier (store number of characters consumed so far in next pointer) is not implemented. * The p specifier (match a pointer value) is not implemented. ===Altered specifiers [o,u,x,X] In scanf for Ruby, all of these specifiers scan for an optionally signed integer, rather than for an unsigned integer like their C counterparts. ===Return values scanf for Ruby returns an array of successful conversions, whereas scanf(3) returns the number of conversions successfully completed. (See below for more details on scanf for Ruby's return values.) ==Return values Without a block, scanf returns an array containing all the conversions it has found. If none are found, scanf will return an empty array. An unsuccesful match is never ignored, but rather always signals the end of the scanning operation. If the first unsuccessful match takes place after one or more successful matches have already taken place, the returned array will contain the results of those successful matches. With a block scanf returns a 'map'-like array of transformations from the block -- that is, an array reflecting what the block did with each yielded result from the iterative scanf operation. (See "Block usage", above.) ==Test suite scanf for Ruby includes a suite of unit tests (requiring the TestUnit package), which can be run with the command ruby tests/scanftests.rb or the command make test. ==Current limitations and bugs When using IO#scanf under Windows, make sure you open your files in binary mode: File.open("filename", "rb") so that scanf can keep track of characters correctly. Support for character classes is reasonably complete (since it essentially piggy-backs on Ruby's regular expression handling of character classes), but users are advised that character class testing has not been exhaustive, and that they should exercise some caution in using any of the more complex and/or arcane character class idioms. ==Technical notes ===Rationale behind scanf for Ruby The impetus for a scanf implementation in Ruby comes chiefly from the fact that existing pattern matching operations, such as Regexp#match and String#scan, return all results as strings, which have to be converted to integers or floats explicitly in cases where what's ultimately wanted are integer or float values. ===Design of scanf for Ruby scanf for Ruby is essentially a -to- converter. When scanf is called, a FormatString object is generated from the format string ("%d%s...") argument. The FormatString object breaks the format string down into atoms ("%d", "%5f", "blah", etc.), and from each atom it creates a FormatSpecifier object, which it saves. Each FormatSpecifier has a regular expression fragment and a "handler" associated with it. For example, the regular expression fragment associated with the format "%d" is "([-+]?\d+)", and the handler associated with it is a wrapper around String#to_i. scanf itself calls FormatString#match, passing in the input string. FormatString#match iterates through its FormatSpecifiers; for each one, it matches the corresponding regular expression fragment against the string. If there's a match, it sends the matched string to the handler associated with the FormatSpecifier. Thus, to follow up the "%d" example: if "123" occurs in the input string when a FormatSpecifier consisting of "%d" is reached, the "123" will be matched against "([-+]?\d+)", and the matched string will be rendered into an integer by a call to to_i. The rendered match is then saved to an accumulator array, and the input string is reduced to the post-match substring. Thus the string is "eaten" from the left as the FormatSpecifiers are applied in sequence. (This is done to a duplicate string; the original string is not altered.) As soon as a regular expression fragment fails to match the string, or when the FormatString object runs out of FormatSpecifiers, scanning stops and results accumulated so far are returned in an array. ==License and copyright Copyright:: (c) 2002-2003 David Alan Black License:: Distributed on the same licensing terms as Ruby itself ==Warranty disclaimer This software is provided "as is" and without any express or implied warranties, including, without limitation, the implied warranties of merchantibility and fitness for a particular purpose. ==Credits and acknowledgements scanf for Ruby was developed as the major activity of the Austin Ruby Codefest (Austin, Texas, August 2002). Principal author:: David Alan Black (mailto:dblack@superlink.net) Co-author:: Hal Fulton (mailto:hal9000@hypermetrics.com) Project contributors:: Nolan Darilek, Jason Johnston Thanks to Hal Fulton for hosting the Codefest. Thanks to Matz for suggestions about the class design. Thanks to Gavin Sinclair for some feedback on the documentation. The text for parts of this document, especially the Description and Conversions sections, above, were adapted from the Linux Programmer's Manual manpage for scanf(3), dated 1995-11-01. ==Bugs and bug reports scanf for Ruby is based on something of an amalgam of C scanf implementations and documentation, rather than on a single canonical description. Suggestions for features and behaviors which appear in other scanfs, and would be meaningful in Ruby, are welcome, as are reports of suspicious behaviors and/or bugs. (Please see "Credits and acknowledgements", above, for email addresses.) =end module Scanf class FormatSpecifier attr_reader :re_string, :matched_string, :conversion, :matched private def skip; /^\s*%\*/.match(@spec_string); end def extract_float(s); s.to_f if s &&! skip; end def extract_decimal(s); s.to_i if s &&! skip; end def extract_hex(s); s.hex if s &&! skip; end def extract_octal(s); s.oct if s &&! skip; end def extract_integer(s); Integer(s) if s &&! skip; end def extract_plain(s); s unless skip; end def nil_proc(s); nil; end public def to_s @spec_string end def count_space? /(?:\A|\S)%\*?\d*c|\[/.match(@spec_string) end def initialize(str) @spec_string = str h = '[A-Fa-f0-9]' @re_string, @handler = case @spec_string # %[[:...:]] when /%\*?(\[\[:[a-z]+:\]\])/ [ "(#{$1}+)", :extract_plain ] # %5[[:...:]] when /%\*?(\d+)(\[\[:[a-z]+:\]\])/ [ "(#{$2}{1,#{$1}})", :extract_plain ] # %[...] when /%\*?\[([^\]]*)\]/ yes = $1 if /^\^/.match(yes) then no = yes[1..-1] else no = '^' + yes end [ "([#{yes}]+)(?=[#{no}]|\\z)", :extract_plain ] # %5[...] when /%\*?(\d+)\[([^\]]*)\]/ yes = $2 w = $1 [ "([#{yes}]{1,#{w}})", :extract_plain ] # %i when /%\*?i/ [ "([-+]?(?:(?:0[0-7]+)|(?:0[Xx]#{h}+)|(?:[1-9]\\d*)))", :extract_integer ] # %5i when /%\*?(\d+)i/ n = $1.to_i s = "(" if n > 1 then s += "[1-9]\\d{1,#{n-1}}|" end if n > 1 then s += "0[0-7]{1,#{n-1}}|" end if n > 2 then s += "[-+]0[0-7]{1,#{n-2}}|" end if n > 2 then s += "[-+][1-9]\\d{1,#{n-2}}|" end if n > 2 then s += "0[Xx]#{h}{1,#{n-2}}|" end if n > 3 then s += "[-+]0[Xx]#{h}{1,#{n-3}}|" end s += "\\d" s += ")" [ s, :extract_integer ] # %d, %u when /%\*?[du]/ [ '([-+]?\d+)', :extract_decimal ] # %5d, %5u when /%\*?(\d+)[du]/ n = $1.to_i s = "(" if n > 1 then s += "[-+]\\d{1,#{n-1}}|" end s += "\\d{1,#{$1}})" [ s, :extract_decimal ] # %x when /%\*?[Xx]/ [ "([-+]?(?:0[Xx])?#{h}+)", :extract_hex ] # %5x when /%\*?(\d+)[Xx]/ n = $1.to_i s = "(" if n > 3 then s += "[-+]0[Xx]#{h}{1,#{n-3}}|" end if n > 2 then s += "0[Xx]#{h}{1,#{n-2}}|" end if n > 1 then s += "[-+]#{h}{1,#{n-1}}|" end s += "#{h}{1,#{n}}" s += ")" [ s, :extract_hex ] # %o when /%\*?o/ [ '([-+]?[0-7]+)', :extract_octal ] # %5o when /%\*?(\d+)o/ [ "([-+][0-7]{1,#{$1.to_i-1}}|[0-7]{1,#{$1}})", :extract_octal ] # %f when /%\*?f/ [ '([-+]?((\d+(?>(?=[^\d.]|$)))|(\d*(\.(\d*([eE][-+]?\d+)?)))))', :extract_float ] # %5f when /%\*?(\d+)f/ [ "(\\S{1,#{$1}})", :extract_float ] # %5s when /%\*?(\d+)s/ [ "(\\S{1,#{$1}})", :extract_plain ] # %s when /%\*?s/ [ '(\S+)', :extract_plain ] # %c when /\s%\*?c/ [ "\\s*(.)", :extract_plain ] # %c when /%\*?c/ [ "(.)", :extract_plain ] # %5c (whitespace issues are handled by the count_*_space? methods) when /%\*?(\d+)c/ [ "(.{1,#{$1}})", :extract_plain ] # %% when /%%/ [ '(\s*%)', :nil_proc ] # literal characters else [ "(#{Regexp.escape(@spec_string)})", :nil_proc ] end @re_string = '\A' + @re_string end def to_re Regexp.new(@re_string,Regexp::MULTILINE) end def match(str) @matched = false s = str.dup s.sub!(/\A\s+/,'') unless count_space? res = to_re.match(s) if res @conversion = send(@handler, res[1]) @matched_string = @conversion.to_s @matched = true end res end def letter /%\*?\d*([a-z\[])/.match(@spec_string).to_a[1] end def width w = /%\*?(\d+)/.match(@spec_string).to_a[1] w && w.to_i end def mid_match? return false unless @matched cc_no_width = letter == '[' &&! width c_or_cc_width = (letter == 'c' || letter == '[') && width width_left = c_or_cc_width && (matched_string.size < width) return width_left || cc_no_width end end class FormatString attr_reader :string_left, :last_spec_tried, :last_match_tried, :matched_count, :space SPECIFIERS = 'diuXxofeEgsc' REGEX = / # possible space, followed by... (?:\s* # percent sign, followed by... % # another percent sign, or... (?:%| # optional assignment suppression flag \*? # optional maximum field width \d* # named character class, ... (?:\[\[:\w+:\]\]| # traditional character class, or... \[[^\]]*\]| # specifier letter. [#{SPECIFIERS}])))| # or miscellaneous characters [^%\s]+/ix def initialize(str) @specs = [] @i = 1 s = str.to_s return unless /\S/.match(s) @space = true if /\s\z/.match(s) @specs.replace s.scan(REGEX).map {|spec| FormatSpecifier.new(spec) } end def to_s @specs.join('') end def prune(n=matched_count) n.times { @specs.shift } end def spec_count @specs.size end def last_spec @i == spec_count - 1 end def match(str) accum = [] @string_left = str @matched_count = 0 @specs.each_with_index do |spec,@i| @last_spec_tried = spec @last_match_tried = spec.match(@string_left) break unless @last_match_tried @matched_count += 1 accum << spec.conversion @string_left = @last_match_tried.post_match break if @string_left.empty? end return accum.compact end end end class IO # The trick here is doing a match where you grab one *line* # of input at a time. The linebreak may or may not occur # at the boundary where the string matches a format specifier. # And if it does, some rule about whitespace may or may not # be in effect... # # That's why this is much more elaborate than the string # version. # # For each line: # Match succeeds (non-emptily) # and the last attempted spec/string sub-match succeeded: # # could the last spec keep matching? # yes: save interim results and continue (next line) # # The last attempted spec/string did not match: # # are we on the next-to-last spec in the string? # yes: # is fmt_string.string_left all spaces? # yes: does current spec care about input space? # yes: fatal failure # no: save interim results and continue # no: continue [this state could be analyzed further] # # def scanf(str,&b) return block_scanf(str,&b) if b return [] unless str.size > 0 start_position = pos rescue 0 matched_so_far = 0 source_buffer = "" result_buffer = [] final_result = [] fstr = Scanf::FormatString.new(str) loop do if eof || (tty? &&! fstr.match(source_buffer)) final_result.concat(result_buffer) break end source_buffer << gets current_match = fstr.match(source_buffer) spec = fstr.last_spec_tried if spec.matched if spec.mid_match? result_buffer.replace(current_match) next end elsif (fstr.matched_count == fstr.spec_count - 1) if /\A\s*\z/.match(fstr.string_left) break if spec.count_space? result_buffer.replace(current_match) next end end final_result.concat(current_match) matched_so_far += source_buffer.size source_buffer.replace(fstr.string_left) matched_so_far -= source_buffer.size break if fstr.last_spec fstr.prune end seek(start_position + matched_so_far, IO::SEEK_SET) rescue Errno::ESPIPE soak_up_spaces if fstr.last_spec && fstr.space return final_result end private def soak_up_spaces c = getc ungetc(c) if c until eof ||! c || /\S/.match(c.chr) c = getc end ungetc(c) if (c && /\S/.match(c.chr)) end def block_scanf(str) final = [] # Sub-ideal, since another FS gets created in scanf. # But used here to determine the number of specifiers. fstr = Scanf::FormatString.new(str) last_spec = fstr.last_spec begin current = scanf(str) break if current.empty? final.push(yield(current)) end until eof || fstr.last_spec_tried == last_spec return final end end class String def scanf(fstr,&b) if b block_scanf(fstr,&b) else fs = if fstr.is_a? Scanf::FormatString fstr else Scanf::FormatString.new(fstr) end fs.match(self) end end def block_scanf(fstr,&b) fs = Scanf::FormatString.new(fstr) str = self.dup final = [] begin current = str.scanf(fs) final.push(yield(current)) unless current.empty? str = fs.string_left end until current.empty? || str.empty? return final end end module Kernel private def scanf(fs,&b) STDIN.scanf(fs,&b) end end ================================================ FILE: lib/securerandom.rb ================================================ # = Secure random number generator interface. # # This library is an interface for secure random number generator which is # suitable for generating session key in HTTP cookies, etc. # # It supports following secure random number generators. # # * openssl # * /dev/urandom # # == Example # # # random hexadecimal string. # p SecureRandom.hex(10) #=> "52750b30ffbc7de3b362" # p SecureRandom.hex(10) #=> "92b15d6c8dc4beb5f559" # p SecureRandom.hex(11) #=> "6aca1b5c58e4863e6b81b8" # p SecureRandom.hex(12) #=> "94b2fff3e7fd9b9c391a2306" # p SecureRandom.hex(13) #=> "39b290146bea6ce975c37cfc23" # ... # # # random base64 string. # p SecureRandom.base64(10) #=> "EcmTPZwWRAozdA==" # p SecureRandom.base64(10) #=> "9b0nsevdwNuM/w==" # p SecureRandom.base64(10) #=> "KO1nIU+p9DKxGg==" # p SecureRandom.base64(11) #=> "l7XEiFja+8EKEtY=" # p SecureRandom.base64(12) #=> "7kJSM/MzBJI+75j8" # p SecureRandom.base64(13) #=> "vKLJ0tXBHqQOuIcSIg==" # ... # # # random binary string. # p SecureRandom.random_bytes(10) #=> "\016\t{\370g\310pbr\301" # p SecureRandom.random_bytes(10) #=> "\323U\030TO\234\357\020\a\337" # ... begin require 'openssl' rescue LoadError end module SecureRandom # SecureRandom.random_bytes generates a random binary string. # # The argument n specifies the length of the result string. # # If n is not specified, 16 is assumed. # It may be larger in future. # # If secure random number generator is not available, # NotImplementedError is raised. def self.random_bytes(n=nil) n ||= 16 if defined? OpenSSL::Random return OpenSSL::Random.random_bytes(n) end if !defined?(@has_urandom) || @has_urandom @has_urandom = false flags = File::RDONLY flags |= File::NONBLOCK if defined? File::NONBLOCK flags |= File::NOCTTY if defined? File::NOCTTY flags |= File::NOFOLLOW if defined? File::NOFOLLOW begin File.open("/dev/urandom", flags) {|f| unless f.stat.chardev? raise Errno::ENOENT end @has_urandom = true ret = f.readpartial(n) if ret.length != n raise NotImplementedError, "Unexpected partial read from random device" end return ret } rescue Errno::ENOENT raise NotImplementedError, "No random device" end end raise NotImplementedError, "No random device" end # SecureRandom.hex generates a random hex string. # # The argument n specifies the length of the random length. # The length of the result string is twice of n. # # If n is not specified, 16 is assumed. # It may be larger in future. # # If secure random number generator is not available, # NotImplementedError is raised. def self.hex(n=nil) random_bytes(n).unpack("H*")[0] end # SecureRandom.base64 generates a random base64 string. # # The argument n specifies the length of the random length. # The length of the result string is about 4/3 of n. # # If n is not specified, 16 is assumed. # It may be larger in future. # # If secure random number generator is not available, # NotImplementedError is raised. def self.base64(n=nil) [random_bytes(n)].pack("m*").delete("\n") end # SecureRandom.random_number generates a random number. # # If an positive integer is given as n, # SecureRandom.random_number returns an integer: # 0 <= SecureRandom.random_number(n) < n. # # If 0 is given or an argument is not given, # SecureRandom.random_number returns an float: # 0.0 <= SecureRandom.random_number() < 1.0. def self.random_number(n=0) if 0 < n hex = n.to_s(16) hex = '0' + hex if (hex.length & 1) == 1 bin = [hex].pack("H*") mask = bin[0] mask |= mask >> 1 mask |= mask >> 2 mask |= mask >> 4 begin rnd = SecureRandom.random_bytes(bin.length) rnd[0] = (rnd[0] & mask).chr end until rnd < bin rnd.unpack("H*")[0].hex else # assumption: Float::MANT_DIG <= 64 i64 = SecureRandom.random_bytes(8).unpack("Q")[0] Math.ldexp(i64 >> (64-Float::MANT_DIG), -Float::MANT_DIG) end end end ================================================ FILE: lib/set.rb ================================================ #!/usr/bin/env ruby #-- # set.rb - defines the Set class #++ # Copyright (c) 2002-2008 Akinori MUSHA # # Documentation by Akinori MUSHA and Gavin Sinclair. # # All rights reserved. You can redistribute and/or modify it under the same # terms as Ruby. # # $Id$ # # == Overview # # This library provides the Set class, which deals with a collection # of unordered values with no duplicates. It is a hybrid of Array's # intuitive inter-operation facilities and Hash's fast lookup. If you # need to keep values ordered, use the SortedSet class. # # The method +to_set+ is added to Enumerable for convenience. # # See the Set class for an example of usage. # # Set implements a collection of unordered values with no duplicates. # This is a hybrid of Array's intuitive inter-operation facilities and # Hash's fast lookup. # # Several methods accept any Enumerable object (implementing +each+) # for greater flexibility: new, replace, merge, subtract, |, &, -, ^. # # The equality of each couple of elements is determined according to # Object#eql? and Object#hash, since Set uses Hash as storage. # # Finally, if you are using class Set, you can also use Enumerable#to_set # for convenience. # # == Example # # require 'set' # s1 = Set.new [1, 2] # -> # # s2 = [1, 2].to_set # -> # # s1 == s2 # -> true # s1.add("foo") # -> # # s1.merge([2, 6]) # -> # # s1.subset? s2 # -> false # s2.subset? s1 # -> true # # == Contact # # - Akinori MUSHA (current maintainer) # class Set include Enumerable # Creates a new set containing the given objects. def self.[](*ary) new(ary) end # Creates a new set containing the elements of the given enumerable # object. # # If a block is given, the elements of enum are preprocessed by the # given block. def initialize(enum = nil, &block) # :yields: o @hash ||= Hash.new enum.nil? and return if block enum.each { |o| add(block[o]) } else merge(enum) end end # Copy internal hash. def initialize_copy(orig) @hash = orig.instance_eval{@hash}.dup end # Returns the number of elements. def size @hash.size end alias length size # Returns true if the set contains no elements. def empty? @hash.empty? end # Removes all elements and returns self. def clear @hash.clear self end # Replaces the contents of the set with the contents of the given # enumerable object and returns self. def replace(enum) if enum.class == self.class @hash.replace(enum.instance_eval { @hash }) else enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" clear enum.each { |o| add(o) } end self end # Converts the set to an array. The order of elements is uncertain. def to_a @hash.keys end def flatten_merge(set, seen = Set.new) set.each { |e| if e.is_a?(Set) if seen.include?(e_id = e.object_id) raise ArgumentError, "tried to flatten recursive Set" end seen.add(e_id) flatten_merge(e, seen) seen.delete(e_id) else add(e) end } self end protected :flatten_merge # Returns a new set that is a copy of the set, flattening each # containing set recursively. def flatten self.class.new.flatten_merge(self) end # Equivalent to Set#flatten, but replaces the receiver with the # result in place. Returns nil if no modifications were made. def flatten! if detect { |e| e.is_a?(Set) } replace(flatten()) else nil end end # Returns true if the set contains the given object. def include?(o) @hash.include?(o) end alias member? include? # Returns true if the set is a superset of the given set. def superset?(set) set.is_a?(Set) or raise ArgumentError, "value must be a set" return false if size < set.size set.all? { |o| include?(o) } end # Returns true if the set is a proper superset of the given set. def proper_superset?(set) set.is_a?(Set) or raise ArgumentError, "value must be a set" return false if size <= set.size set.all? { |o| include?(o) } end # Returns true if the set is a subset of the given set. def subset?(set) set.is_a?(Set) or raise ArgumentError, "value must be a set" return false if set.size < size all? { |o| set.include?(o) } end # Returns true if the set is a proper subset of the given set. def proper_subset?(set) set.is_a?(Set) or raise ArgumentError, "value must be a set" return false if set.size <= size all? { |o| set.include?(o) } end # Calls the given block once for each element in the set, passing # the element as parameter. Returns an enumerator if no block is # given. def each block_given? or return enum_for(__method__) @hash.each_key { |o| yield(o) } self end # Adds the given object to the set and returns self. Use +merge+ to # add several elements at once. def add(o) @hash[o] = true self end alias << add # Adds the given object to the set and returns self. If the # object is already in the set, returns nil. def add?(o) if include?(o) nil else add(o) end end # Deletes the given object from the set and returns self. Use +subtract+ to # delete several items at once. def delete(o) @hash.delete(o) self end # Deletes the given object from the set and returns self. If the # object is not in the set, returns nil. def delete?(o) if include?(o) delete(o) else nil end end # Deletes every element of the set for which block evaluates to # true, and returns self. def delete_if to_a.each { |o| @hash.delete(o) if yield(o) } self end # Do collect() destructively. def collect! set = self.class.new each { |o| set << yield(o) } replace(set) end alias map! collect! # Equivalent to Set#delete_if, but returns nil if no changes were # made. def reject! n = size delete_if { |o| yield(o) } size == n ? nil : self end # Merges the elements of the given enumerable object to the set and # returns self. def merge(enum) if enum.is_a?(Set) @hash.update(enum.instance_eval { @hash }) else enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" enum.each { |o| add(o) } end self end # Deletes every element that appears in the given enumerable object # and returns self. def subtract(enum) enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" enum.each { |o| delete(o) } self end # Returns a new set built by merging the set and the elements of the # given enumerable object. def |(enum) enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" dup.merge(enum) end alias + | ## alias union | ## # Returns a new set built by duplicating the set, removing every # element that appears in the given enumerable object. def -(enum) enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" dup.subtract(enum) end alias difference - ## # Returns a new set containing elements common to the set and the # given enumerable object. def &(enum) enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" n = self.class.new enum.each { |o| n.add(o) if include?(o) } n end alias intersection & ## # Returns a new set containing elements exclusive between the set # and the given enumerable object. (set ^ enum) is equivalent to # ((set | enum) - (set & enum)). def ^(enum) enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" n = Set.new(enum) each { |o| if n.include?(o) then n.delete(o) else n.add(o) end } n end # Returns true if two sets are equal. The equality of each couple # of elements is defined according to Object#eql?. def ==(set) equal?(set) and return true set.is_a?(Set) && size == set.size or return false hash = @hash.dup set.all? { |o| hash.include?(o) } end def hash # :nodoc: @hash.hash end def eql?(o) # :nodoc: return false unless o.is_a?(Set) @hash.eql?(o.instance_eval{@hash}) end # Classifies the set by the return value of the given block and # returns a hash of {value => set of elements} pairs. The block is # called once for each element of the set, passing the element as # parameter. # # e.g.: # # require 'set' # files = Set.new(Dir.glob("*.rb")) # hash = files.classify { |f| File.mtime(f).year } # p hash # => {2000=>#, # # 2001=>#, # # 2002=>#} def classify # :yields: o h = {} each { |i| x = yield(i) (h[x] ||= self.class.new).add(i) } h end # Divides the set into a set of subsets according to the commonality # defined by the given block. # # If the arity of the block is 2, elements o1 and o2 are in common # if block.call(o1, o2) is true. Otherwise, elements o1 and o2 are # in common if block.call(o1) == block.call(o2). # # e.g.: # # require 'set' # numbers = Set[1, 3, 4, 6, 9, 10, 11] # set = numbers.divide { |i,j| (i - j).abs == 1 } # p set # => #, # # #, # # #, # # #}> def divide(&func) if func.arity == 2 require 'tsort' class << dig = {} # :nodoc: include TSort alias tsort_each_node each_key def tsort_each_child(node, &block) fetch(node).each(&block) end end each { |u| dig[u] = a = [] each{ |v| func.call(u, v) and a << v } } set = Set.new() dig.each_strongly_connected_component { |css| set.add(self.class.new(css)) } set else Set.new(classify(&func).values) end end InspectKey = :__inspect_key__ # :nodoc: # Returns a string containing a human-readable representation of the # set. ("#") def inspect ids = (Thread.current[InspectKey] ||= []) if ids.include?(object_id) return sprintf('#<%s: {...}>', self.class.name) end begin ids << object_id return sprintf('#<%s: {%s}>', self.class, to_a.inspect[1..-2]) ensure ids.pop end end def pretty_print(pp) # :nodoc: pp.text sprintf('#<%s: {', self.class.name) pp.nest(1) { pp.seplist(self) { |o| pp.pp o } } pp.text "}>" end def pretty_print_cycle(pp) # :nodoc: pp.text sprintf('#<%s: {%s}>', self.class.name, empty? ? '' : '...') end end # SortedSet implements a set which elements are sorted in order. See Set. class SortedSet < Set @@setup = false class << self def [](*ary) # :nodoc: new(ary) end def setup # :nodoc: @@setup and return module_eval { # a hack to shut up warning alias old_init initialize remove_method :old_init } begin require 'rbtree' module_eval %{ def initialize(*args, &block) @hash = RBTree.new super end } rescue LoadError module_eval %{ def initialize(*args, &block) @keys = nil super end def clear @keys = nil super end def replace(enum) @keys = nil super end def add(o) @keys = nil @hash[o] = true self end alias << add def delete(o) @keys = nil @hash.delete(o) self end def delete_if n = @hash.size super @keys = nil if @hash.size != n self end def merge(enum) @keys = nil super end def each block_given? or return enum_for(__method__) to_a.each { |o| yield(o) } self end def to_a (@keys = @hash.keys).sort! unless @keys @keys end } end @@setup = true end end def initialize(*args, &block) # :nodoc: SortedSet.setup initialize(*args, &block) end end module Enumerable # Makes a set from the enumerable object with given arguments. # Needs to +require "set"+ to use this method. def to_set(klass = Set, *args, &block) klass.new(self, *args, &block) end end # =begin # == RestricedSet class # RestricedSet implements a set with restrictions defined by a given # block. # # === Super class # Set # # === Class Methods # --- RestricedSet::new(enum = nil) { |o| ... } # --- RestricedSet::new(enum = nil) { |rset, o| ... } # Creates a new restricted set containing the elements of the given # enumerable object. Restrictions are defined by the given block. # # If the block's arity is 2, it is called with the RestrictedSet # itself and an object to see if the object is allowed to be put in # the set. # # Otherwise, the block is called with an object to see if the object # is allowed to be put in the set. # # === Instance Methods # --- restriction_proc # Returns the restriction procedure of the set. # # =end # # class RestricedSet < Set # def initialize(*args, &block) # @proc = block or raise ArgumentError, "missing a block" # # if @proc.arity == 2 # instance_eval %{ # def add(o) # @hash[o] = true if @proc.call(self, o) # self # end # alias << add # # def add?(o) # if include?(o) || !@proc.call(self, o) # nil # else # @hash[o] = true # self # end # end # # def replace(enum) # enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" # clear # enum.each { |o| add(o) } # # self # end # # def merge(enum) # enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" # enum.each { |o| add(o) } # # self # end # } # else # instance_eval %{ # def add(o) # if @proc.call(o) # @hash[o] = true # end # self # end # alias << add # # def add?(o) # if include?(o) || !@proc.call(o) # nil # else # @hash[o] = true # self # end # end # } # end # # super(*args) # end # # def restriction_proc # @proc # end # end if $0 == __FILE__ eval DATA.read, nil, $0, __LINE__+4 end __END__ require 'test/unit' class TC_Set < Test::Unit::TestCase def test_aref assert_nothing_raised { Set[] Set[nil] Set[1,2,3] } assert_equal(0, Set[].size) assert_equal(1, Set[nil].size) assert_equal(1, Set[[]].size) assert_equal(1, Set[[nil]].size) set = Set[2,4,6,4] assert_equal(Set.new([2,4,6]), set) end def test_s_new assert_nothing_raised { Set.new() Set.new(nil) Set.new([]) Set.new([1,2]) Set.new('a'..'c') Set.new('XYZ') } assert_raises(ArgumentError) { Set.new(false) } assert_raises(ArgumentError) { Set.new(1) } assert_raises(ArgumentError) { Set.new(1,2) } assert_equal(0, Set.new().size) assert_equal(0, Set.new(nil).size) assert_equal(0, Set.new([]).size) assert_equal(1, Set.new([nil]).size) ary = [2,4,6,4] set = Set.new(ary) ary.clear assert_equal(false, set.empty?) assert_equal(3, set.size) ary = [1,2,3] s = Set.new(ary) { |o| o * 2 } assert_equal([2,4,6], s.sort) end def test_clone set1 = Set.new set2 = set1.clone set1 << 'abc' assert_equal(Set.new, set2) end def test_dup set1 = Set[1,2] set2 = set1.dup assert_not_same(set1, set2) assert_equal(set1, set2) set1.add(3) assert_not_equal(set1, set2) end def test_size assert_equal(0, Set[].size) assert_equal(2, Set[1,2].size) assert_equal(2, Set[1,2,1].size) end def test_empty? assert_equal(true, Set[].empty?) assert_equal(false, Set[1, 2].empty?) end def test_clear set = Set[1,2] ret = set.clear assert_same(set, ret) assert_equal(true, set.empty?) end def test_replace set = Set[1,2] ret = set.replace('a'..'c') assert_same(set, ret) assert_equal(Set['a','b','c'], set) end def test_to_a set = Set[1,2,3,2] ary = set.to_a assert_equal([1,2,3], ary.sort) end def test_flatten # test1 set1 = Set[ 1, Set[ 5, Set[7, Set[0] ], Set[6,2], 1 ], 3, Set[3,4] ] set2 = set1.flatten set3 = Set.new(0..7) assert_not_same(set2, set1) assert_equal(set3, set2) # test2; destructive orig_set1 = set1 set1.flatten! assert_same(orig_set1, set1) assert_equal(set3, set1) # test3; multiple occurrences of a set in an set set1 = Set[1, 2] set2 = Set[set1, Set[set1, 4], 3] assert_nothing_raised { set2.flatten! } assert_equal(Set.new(1..4), set2) # test4; recursion set2 = Set[] set1 = Set[1, set2] set2.add(set1) assert_raises(ArgumentError) { set1.flatten! } # test5; miscellaneous empty = Set[] set = Set[Set[empty, "a"],Set[empty, "b"]] assert_nothing_raised { set.flatten } set1 = empty.merge(Set["no_more", set]) assert_nil(Set.new(0..31).flatten!) x = Set[Set[],Set[1,2]].flatten! y = Set[1,2] assert_equal(x, y) end def test_include? set = Set[1,2,3] assert_equal(true, set.include?(1)) assert_equal(true, set.include?(2)) assert_equal(true, set.include?(3)) assert_equal(false, set.include?(0)) assert_equal(false, set.include?(nil)) set = Set["1",nil,"2",nil,"0","1",false] assert_equal(true, set.include?(nil)) assert_equal(true, set.include?(false)) assert_equal(true, set.include?("1")) assert_equal(false, set.include?(0)) assert_equal(false, set.include?(true)) end def test_superset? set = Set[1,2,3] assert_raises(ArgumentError) { set.superset?() } assert_raises(ArgumentError) { set.superset?(2) } assert_raises(ArgumentError) { set.superset?([2]) } assert_equal(true, set.superset?(Set[])) assert_equal(true, set.superset?(Set[1,2])) assert_equal(true, set.superset?(Set[1,2,3])) assert_equal(false, set.superset?(Set[1,2,3,4])) assert_equal(false, set.superset?(Set[1,4])) assert_equal(true, Set[].superset?(Set[])) end def test_proper_superset? set = Set[1,2,3] assert_raises(ArgumentError) { set.proper_superset?() } assert_raises(ArgumentError) { set.proper_superset?(2) } assert_raises(ArgumentError) { set.proper_superset?([2]) } assert_equal(true, set.proper_superset?(Set[])) assert_equal(true, set.proper_superset?(Set[1,2])) assert_equal(false, set.proper_superset?(Set[1,2,3])) assert_equal(false, set.proper_superset?(Set[1,2,3,4])) assert_equal(false, set.proper_superset?(Set[1,4])) assert_equal(false, Set[].proper_superset?(Set[])) end def test_subset? set = Set[1,2,3] assert_raises(ArgumentError) { set.subset?() } assert_raises(ArgumentError) { set.subset?(2) } assert_raises(ArgumentError) { set.subset?([2]) } assert_equal(true, set.subset?(Set[1,2,3,4])) assert_equal(true, set.subset?(Set[1,2,3])) assert_equal(false, set.subset?(Set[1,2])) assert_equal(false, set.subset?(Set[])) assert_equal(true, Set[].subset?(Set[1])) assert_equal(true, Set[].subset?(Set[])) end def test_proper_subset? set = Set[1,2,3] assert_raises(ArgumentError) { set.proper_subset?() } assert_raises(ArgumentError) { set.proper_subset?(2) } assert_raises(ArgumentError) { set.proper_subset?([2]) } assert_equal(true, set.proper_subset?(Set[1,2,3,4])) assert_equal(false, set.proper_subset?(Set[1,2,3])) assert_equal(false, set.proper_subset?(Set[1,2])) assert_equal(false, set.proper_subset?(Set[])) assert_equal(false, Set[].proper_subset?(Set[])) end def test_each ary = [1,3,5,7,10,20] set = Set.new(ary) ret = set.each { |o| } assert_same(set, ret) e = set.each assert_instance_of(Enumerable::Enumerator, e) assert_nothing_raised { set.each { |o| ary.delete(o) or raise "unexpected element: #{o}" } ary.empty? or raise "forgotten elements: #{ary.join(', ')}" } end def test_add set = Set[1,2,3] ret = set.add(2) assert_same(set, ret) assert_equal(Set[1,2,3], set) ret = set.add?(2) assert_nil(ret) assert_equal(Set[1,2,3], set) ret = set.add(4) assert_same(set, ret) assert_equal(Set[1,2,3,4], set) ret = set.add?(5) assert_same(set, ret) assert_equal(Set[1,2,3,4,5], set) end def test_delete set = Set[1,2,3] ret = set.delete(4) assert_same(set, ret) assert_equal(Set[1,2,3], set) ret = set.delete?(4) assert_nil(ret) assert_equal(Set[1,2,3], set) ret = set.delete(2) assert_equal(set, ret) assert_equal(Set[1,3], set) ret = set.delete?(1) assert_equal(set, ret) assert_equal(Set[3], set) end def test_delete_if set = Set.new(1..10) ret = set.delete_if { |i| i > 10 } assert_same(set, ret) assert_equal(Set.new(1..10), set) set = Set.new(1..10) ret = set.delete_if { |i| i % 3 == 0 } assert_same(set, ret) assert_equal(Set[1,2,4,5,7,8,10], set) end def test_collect! set = Set[1,2,3,'a','b','c',-1..1,2..4] ret = set.collect! { |i| case i when Numeric i * 2 when String i.upcase else nil end } assert_same(set, ret) assert_equal(Set[2,4,6,'A','B','C',nil], set) end def test_reject! set = Set.new(1..10) ret = set.reject! { |i| i > 10 } assert_nil(ret) assert_equal(Set.new(1..10), set) ret = set.reject! { |i| i % 3 == 0 } assert_same(set, ret) assert_equal(Set[1,2,4,5,7,8,10], set) end def test_merge set = Set[1,2,3] ret = set.merge([2,4,6]) assert_same(set, ret) assert_equal(Set[1,2,3,4,6], set) end def test_subtract set = Set[1,2,3] ret = set.subtract([2,4,6]) assert_same(set, ret) assert_equal(Set[1,3], set) end def test_plus set = Set[1,2,3] ret = set + [2,4,6] assert_not_same(set, ret) assert_equal(Set[1,2,3,4,6], ret) end def test_minus set = Set[1,2,3] ret = set - [2,4,6] assert_not_same(set, ret) assert_equal(Set[1,3], ret) end def test_and set = Set[1,2,3,4] ret = set & [2,4,6] assert_not_same(set, ret) assert_equal(Set[2,4], ret) end def test_xor set = Set[1,2,3,4] ret = set ^ [2,4,5,5] assert_not_same(set, ret) assert_equal(Set[1,3,5], ret) end def test_eq set1 = Set[2,3,1] set2 = Set[1,2,3] assert_equal(set1, set1) assert_equal(set1, set2) assert_not_equal(Set[1], [1]) set1 = Class.new(Set)["a", "b"] set2 = Set["a", "b", set1] set1 = set1.add(set1.clone) # assert_equal(set1, set2) # assert_equal(set2, set1) assert_equal(set2, set2.clone) assert_equal(set1.clone, set1) assert_not_equal(Set[Exception.new,nil], Set[Exception.new,Exception.new], "[ruby-dev:26127]") end # def test_hash # end # def test_eql? # end def test_classify set = Set.new(1..10) ret = set.classify { |i| i % 3 } assert_equal(3, ret.size) assert_instance_of(Hash, ret) ret.each_value { |value| assert_instance_of(Set, value) } assert_equal(Set[3,6,9], ret[0]) assert_equal(Set[1,4,7,10], ret[1]) assert_equal(Set[2,5,8], ret[2]) end def test_divide set = Set.new(1..10) ret = set.divide { |i| i % 3 } assert_equal(3, ret.size) n = 0 ret.each { |s| n += s.size } assert_equal(set.size, n) assert_equal(set, ret.flatten) set = Set[7,10,5,11,1,3,4,9,0] ret = set.divide { |a,b| (a - b).abs == 1 } assert_equal(4, ret.size) n = 0 ret.each { |s| n += s.size } assert_equal(set.size, n) assert_equal(set, ret.flatten) ret.each { |s| if s.include?(0) assert_equal(Set[0,1], s) elsif s.include?(3) assert_equal(Set[3,4,5], s) elsif s.include?(7) assert_equal(Set[7], s) elsif s.include?(9) assert_equal(Set[9,10,11], s) else raise "unexpected group: #{s.inspect}" end } end def test_inspect set1 = Set[1] assert_equal('#', set1.inspect) set2 = Set[Set[0], 1, 2, set1] assert_equal(false, set2.inspect.include?('#')) set1.add(set2) assert_equal(true, set1.inspect.include?('#')) end # def test_pretty_print # end # def test_pretty_print_cycle # end end class TC_SortedSet < Test::Unit::TestCase def test_sortedset s = SortedSet[4,5,3,1,2] assert_equal([1,2,3,4,5], s.to_a) prev = nil s.each { |o| assert(prev < o) if prev; prev = o } assert_not_nil(prev) s.map! { |o| -2 * o } assert_equal([-10,-8,-6,-4,-2], s.to_a) prev = nil ret = s.each { |o| assert(prev < o) if prev; prev = o } assert_not_nil(prev) assert_same(s, ret) s = SortedSet.new([2,1,3]) { |o| o * -2 } assert_equal([-6,-4,-2], s.to_a) s = SortedSet.new(['one', 'two', 'three', 'four']) a = [] ret = s.delete_if { |o| a << o; o.start_with?('t') } assert_same(s, ret) assert_equal(['four', 'one'], s.to_a) assert_equal(['four', 'one', 'three', 'two'], a) s = SortedSet.new(['one', 'two', 'three', 'four']) a = [] ret = s.reject! { |o| a << o; o.start_with?('t') } assert_same(s, ret) assert_equal(['four', 'one'], s.to_a) assert_equal(['four', 'one', 'three', 'two'], a) s = SortedSet.new(['one', 'two', 'three', 'four']) a = [] ret = s.reject! { |o| a << o; false } assert_same(nil, ret) assert_equal(['four', 'one', 'three', 'two'], s.to_a) assert_equal(['four', 'one', 'three', 'two'], a) end end class TC_Enumerable < Test::Unit::TestCase def test_to_set ary = [2,5,4,3,2,1,3] set = ary.to_set assert_instance_of(Set, set) assert_equal([1,2,3,4,5], set.sort) set = ary.to_set { |o| o * -2 } assert_instance_of(Set, set) assert_equal([-10,-8,-6,-4,-2], set.sort) set = ary.to_set(SortedSet) assert_instance_of(SortedSet, set) assert_equal([1,2,3,4,5], set.to_a) set = ary.to_set(SortedSet) { |o| o * -2 } assert_instance_of(SortedSet, set) assert_equal([-10,-8,-6,-4,-2], set.sort) end end # class TC_RestricedSet < Test::Unit::TestCase # def test_s_new # assert_raises(ArgumentError) { RestricedSet.new } # # s = RestricedSet.new([-1,2,3]) { |o| o > 0 } # assert_equal([2,3], s.sort) # end # # def test_restriction_proc # s = RestricedSet.new([-1,2,3]) { |o| o > 0 } # # f = s.restriction_proc # assert_instance_of(Proc, f) # assert(f[1]) # assert(!f[0]) # end # # def test_replace # s = RestricedSet.new(-3..3) { |o| o > 0 } # assert_equal([1,2,3], s.sort) # # s.replace([-2,0,3,4,5]) # assert_equal([3,4,5], s.sort) # end # # def test_merge # s = RestricedSet.new { |o| o > 0 } # s.merge(-5..5) # assert_equal([1,2,3,4,5], s.sort) # # s.merge([10,-10,-8,8]) # assert_equal([1,2,3,4,5,8,10], s.sort) # end # end ================================================ FILE: lib/shell/builtin-command.rb ================================================ # # shell/builtin-command.rb - # $Release Version: 0.6.0 $ # $Revision$ # $Date$ # by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) # # -- # # # require "shell/filter" class Shell class BuiltInCommand # def expand_path(path) @shell.expand_path(path) end # # File related commands # Shell#foreach # Shell#open # Shell#unlink # Shell#test # # - # # CommandProcessor#foreach(path, rs) # path: String # rs: String - record separator # iterator # Same as: # File#foreach (when path is file) # Dir#foreach (when path is directory) # path is relative to pwd # def foreach(path = nil, *rs) path = "." unless path path = expand_path(path) if File.directory?(path) Dir.foreach(path){|fn| yield fn} else IO.foreach(path, *rs){|l| yield l} end end # # CommandProcessor#open(path, mode) # path: String # mode: String # return: File or Dir # Same as: # File#open (when path is file) # Dir#open (when path is directory) # mode has an effect only when path is a file # def open(path, mode) path = expand_path(path) if File.directory?(path) Dir.open(path) else effect_umask do File.open(path, mode) end end end # public :open # # CommandProcessor#unlink(path) # same as: # Dir#unlink (when path is directory) # File#unlink (when path is file) # def unlink(path) path = expand_path(path) if File.directory?(path) Dir.unlink(path) else IO.unlink(path) end end # # CommandProcessor#test(command, file1, file2) # CommandProcessor#[command, file1, file2] # command: char or String or Symbol # file1: String # file2: String(optional) # return: Boolean # same as: # test() (when command is char or length 1 string or symbol) # FileTest.command (others) # example: # sh[?e, "foo"] # sh[:e, "foo"] # sh["e", "foo"] # sh[:exists?, "foo"] # sh["exists?", "foo"] # alias top_level_test test def test(command, file1, file2=nil) file1 = expand_path(file1) file2 = expand_path(file2) if file2 command = command.id2name if command.kind_of?(Symbol) case command when Integer if file2 top_level_test(command, file1, file2) else top_level_test(command, file1) end when String if command.size == 1 if file2 top_level_test(command, file1, file2) else top_level_test(command, file1) end else if file2 FileTest.send(command, file1, file2) else FileTest.send(command, file1) end end end end alias [] test # # Dir related methods # # Shell#mkdir # Shell#rmdir # #-- # # CommandProcessor#mkdir(*path) # path: String # same as Dir.mkdir() # def mkdir(*path) for dir in path Dir.mkdir(expand_path(dir)) end end # # CommandProcessor#rmdir(*path) # path: String # same as Dir.rmdir() # def rmdir(*path) for dir in path Dir.rmdir(expand_path(dir)) end end # # CommandProcessor#system(command, *opts) # command: String # opts: String # return: SystemCommand # Same as system() function # example: # print sh.system("ls", "-l") # sh.system("ls", "-l") | sh.head > STDOUT # def system(command, *opts) if opts.empty? if command =~ /\*|\?|\{|\}|\[|\]|<|>|\(|\)|~|&|\||\\|\$|;|'|`|"|\n/ return SystemCommand.new(@shell, find_system_command("sh"), "-c", command) else command, *opts = command.split(/\s+/) end end SystemCommand.new(@shell, find_system_command(command), *opts) end # # ProcessCommand#rehash # clear command hash table. # def rehash @system_commands = {} end # # ProcessCommand#transact # def check_point @shell.process_controller.wait_all_jobs_execution end alias finish_all_jobs check_point def transact(&block) begin @shell.instance_eval(&block) ensure check_point end end # # internal commands # def out(dev = STDOUT, &block) dev.print transact(&block) end def echo(*strings) Echo.new(@shell, *strings) end def cat(*filenames) Cat.new(@shell, *filenames) end # def sort(*filenames) # Sort.new(self, *filenames) # end def glob(pattern) Glob.new(@shell, pattern) end def append(to, filter) case to when String AppendFile.new(@shell, to, filter) when IO AppendIO.new(@shell, to, filter) else Shell.Fail Error::CantApplyMethod, "append", to.class end end def tee(file) Tee.new(@shell, file) end def concat(*jobs) Concat.new(@shell, *jobs) end # %pwd, %cwd -> @pwd def notify(*opts, &block) Thread.exclusive do Shell.notify(*opts) {|mes| yield mes if iterator? mes.gsub!("%pwd", "#{@cwd}") mes.gsub!("%cwd", "#{@cwd}") } end end # # private functions # def effect_umask if @shell.umask Thread.critical = true save = File.umask begin yield ensure File.umask save Thread.critical = false end else yield end end private :effect_umask def find_system_command(command) return command if /^\// =~ command case path = @system_commands[command] when String if exists?(path) return path else Shell.Fail Error::CommandNotFound, command end when false Shell.Fail Error::CommandNotFound, command end for p in @shell.system_path path = join(p, command) if FileTest.exists?(path) @system_commands[command] = path return path end end @system_commands[command] = false Shell.Fail Error::CommandNotFound, command end # # CommandProcessor.def_system_command(command, path) # command: String # path: String # define 'command()' method as method. # def self.def_system_command(command, path = command) begin eval((d = %Q[def #{command}(*opts) SystemCommand.new(@shell, '#{path}', *opts) end]), nil, __FILE__, __LINE__ - 1) rescue SyntaxError Shell.notify "warn: Can't define #{command} path: #{path}." end Shell.notify "Define #{command} path: #{path}.", Shell.debug? Shell.notify("Definition of #{command}: ", d, Shell.debug.kind_of?(Integer) && Shell.debug > 1) end def self.undef_system_command(command) command = command.id2name if command.kind_of?(Symbol) remove_method(command) Shell.module_eval{remove_method(command)} Filter.module_eval{remove_method(command)} self end # define command alias # ex) # def_alias_command("ls_c", "ls", "-C", "-F") # def_alias_command("ls_c", "ls"){|*opts| ["-C", "-F", *opts]} # @alias_map = {} def self.alias_map @alias_map end def self.alias_command(ali, command, *opts, &block) ali = ali.id2name if ali.kind_of?(Symbol) command = command.id2name if command.kind_of?(Symbol) begin if iterator? @alias_map[ali.intern] = proc eval((d = %Q[def #{ali}(*opts) @shell.__send__(:#{command}, *(CommandProcessor.alias_map[:#{ali}].call *opts)) end]), nil, __FILE__, __LINE__ - 1) else args = opts.collect{|opt| '"' + opt + '"'}.join(",") eval((d = %Q[def #{ali}(*opts) @shell.__send__(:#{command}, #{args}, *opts) end]), nil, __FILE__, __LINE__ - 1) end rescue SyntaxError Shell.notify "warn: Can't alias #{ali} command: #{command}." Shell.notify("Definition of #{ali}: ", d) raise end Shell.notify "Define #{ali} command: #{command}.", Shell.debug? Shell.notify("Definition of #{ali}: ", d, Shell.debug.kind_of?(Integer) && Shell.debug > 1) self end def self.unalias_command(ali) ali = ali.id2name if ali.kind_of?(Symbol) @alias_map.delete ali.intern undef_system_command(ali) end # # CommandProcessor.def_builtin_commands(delegation_class, command_specs) # delegation_class: Class or Module # command_specs: [[command_name, [argument,...]],...] # command_name: String # arguments: String # FILENAME?? -> expand_path(filename??) # *FILENAME?? -> filename??.collect{|f|expand_path(f)}.join(", ") # define command_name(argument,...) as # delegation_class.command_name(argument,...) # def self.def_builtin_commands(delegation_class, command_specs) for meth, args in command_specs arg_str = args.collect{|arg| arg.downcase}.join(", ") call_arg_str = args.collect{ |arg| case arg when /^(FILENAME.*)$/ format("expand_path(%s)", $1.downcase) when /^(\*FILENAME.*)$/ # \*FILENAME* -> filenames.collect{|fn| expand_path(fn)}.join(", ") $1.downcase + '.collect{|fn| expand_path(fn)}' else arg end }.join(", ") d = %Q[def #{meth}(#{arg_str}) #{delegation_class}.#{meth}(#{call_arg_str}) end] Shell.notify "Define #{meth}(#{arg_str})", Shell.debug? Shell.notify("Definition of #{meth}: ", d, Shell.debug.kind_of?(Integer) && Shell.debug > 1) eval d end end # # CommandProcessor.install_system_commands(pre) # pre: String - command name prefix # defines every command which belongs in default_system_path via # CommandProcessor.command(). It doesn't define already defined # methods twice. By default, "pre_" is prefixes to each method # name. Characters that may not be used in a method name are # all converted to '_'. Definition errors are just ignored. # def self.install_system_commands(pre = "sys_") defined_meth = {} for m in Shell.methods defined_meth[m] = true end sh = Shell.new for path in Shell.default_system_path next unless sh.directory? path sh.cd path sh.foreach do |cn| if !defined_meth[pre + cn] && sh.file?(cn) && sh.executable?(cn) command = (pre + cn).gsub(/\W/, "_").sub(/^([0-9])/, '_\1') begin def_system_command(command, sh.expand_path(cn)) rescue Shell.notify "warn: Can't define #{command} path: #{cn}" end defined_meth[command] = command end end end end #---------------------------------------------------------------------- # # class initializing methods - # #---------------------------------------------------------------------- def self.add_delegate_command_to_shell(id) id = id.intern if id.kind_of?(String) name = id.id2name if Shell.method_defined?(id) Shell.notify "warn: override definnition of Shell##{name}." Shell.notify "warn: alias Shell##{name} to Shell##{name}_org.\n" Shell.module_eval "alias #{name}_org #{name}" end Shell.notify "method added: Shell##{name}.", Shell.debug? Shell.module_eval(%Q[def #{name}(*args, &block) begin @command_processor.__send__(:#{name}, *args, &block) rescue Exception $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #` $@.delete_if{|s| /^\\(eval\\):/ =~ s} raise end end], __FILE__, __LINE__) if Shell::Filter.method_defined?(id) Shell.notify "warn: override definnition of Shell::Filter##{name}." Shell.notify "warn: alias Shell##{name} to Shell::Filter##{name}_org." Filter.module_eval "alias #{name}_org #{name}" end Shell.notify "method added: Shell::Filter##{name}.", Shell.debug? Filter.module_eval(%Q[def #{name}(*args, &block) begin self | @shell.__send__(:#{name}, *args, &block) rescue Exception $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #` $@.delete_if{|s| /^\\(eval\\):/ =~ s} raise end end], __FILE__, __LINE__) end # # define default builtin commands # def self.install_builtin_commands # method related File. # (exclude open/foreach/unlink) normal_delegation_file_methods = [ ["atime", ["FILENAME"]], ["basename", ["fn", "*opts"]], ["chmod", ["mode", "*FILENAMES"]], ["chown", ["owner", "group", "*FILENAME"]], ["ctime", ["FILENAMES"]], ["delete", ["*FILENAMES"]], ["dirname", ["FILENAME"]], ["ftype", ["FILENAME"]], ["join", ["*items"]], ["link", ["FILENAME_O", "FILENAME_N"]], ["lstat", ["FILENAME"]], ["mtime", ["FILENAME"]], ["readlink", ["FILENAME"]], ["rename", ["FILENAME_FROM", "FILENAME_TO"]], # ["size", ["FILENAME"]], ["split", ["pathname"]], ["stat", ["FILENAME"]], ["symlink", ["FILENAME_O", "FILENAME_N"]], ["truncate", ["FILENAME", "length"]], ["utime", ["atime", "mtime", "*FILENAMES"]]] def_builtin_commands(File, normal_delegation_file_methods) alias_method :rm, :delete # method related FileTest def_builtin_commands(FileTest, FileTest.singleton_methods(false).collect{|m| [m, ["FILENAME"]]}) # method related ftools normal_delegation_ftools_methods = [ ["syscopy", ["FILENAME_FROM", "FILENAME_TO"]], ["copy", ["FILENAME_FROM", "FILENAME_TO"]], ["move", ["FILENAME_FROM", "FILENAME_TO"]], ["compare", ["FILENAME_FROM", "FILENAME_TO"]], ["safe_unlink", ["*FILENAMES"]], ["makedirs", ["*FILENAMES"]], # ["chmod", ["mode", "*FILENAMES"]], ["install", ["FILENAME_FROM", "FILENAME_TO", "mode"]], ] def_builtin_commands(File, normal_delegation_ftools_methods) alias_method :cmp, :compare alias_method :mv, :move alias_method :cp, :copy alias_method :rm_f, :safe_unlink alias_method :mkpath, :makedirs end end end ================================================ FILE: lib/shell/error.rb ================================================ # # shell/error.rb - # $Release Version: 0.6.0 $ # $Revision$ # $Date$ # by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) # # -- # # # require "e2mmap" class Shell module Error extend Exception2MessageMapper def_e2message TypeError, "wrong argument type %s (expected %s)" def_exception :DirStackEmpty, "Directory stack empty." def_exception :CantDefine, "Can't define method(%s, %s)." def_exception :CantApplyMethod, "This method(%s) does not apply to this type(%s)." def_exception :CommandNotFound, "Command not found(%s)." end end ================================================ FILE: lib/shell/filter.rb ================================================ # # shell/filter.rb - # $Release Version: 0.6.0 $ # $Revision$ # $Date$ # by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) # # -- # # # class Shell # # Filter # A method to require # each() # class Filter include Enumerable def initialize(sh) @shell = sh # parent shell @input = nil # input filter end attr_reader :input def input=(filter) @input = filter end def each(rs = nil) rs = @shell.record_separator unless rs if @input @input.each(rs){|l| yield l} end end def < (src) case src when String cat = Cat.new(@shell, src) cat | self when IO self.input = src self else Shell.Fail Error::CantApplyMethod, "<", to.class end end def > (to) case to when String dst = @shell.open(to, "w") begin each(){|l| dst << l} ensure dst.close end when IO each(){|l| to << l} else Shell.Fail Error::CantApplyMethod, ">", to.class end self end def >> (to) begin Shell.cd(@shell.pwd).append(to, self) rescue CantApplyMethod Shell.Fail Error::CantApplyMethod, ">>", to.class end end def | (filter) filter.input = self if active? @shell.process_controller.start_job filter end filter end def + (filter) Join.new(@shell, self, filter) end def to_a ary = [] each(){|l| ary.push l} ary end def to_s str = "" each(){|l| str.concat l} str end def inspect if @shell.debug.kind_of?(Integer) && @shell.debug > 2 super else to_s end end end end ================================================ FILE: lib/shell/process-controller.rb ================================================ # # shell/process-controller.rb - # $Release Version: 0.6.0 $ # $Revision$ # $Date$ # by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) # # -- # # # require "mutex_m" require "monitor" require "sync" class Shell class ProcessController @ProcessControllers = {} @ProcessControllers.extend Mutex_m class< normal debug # debug: 1 -> eval definition debug # debug: 2 -> detail inspect debug @debug = false @verbose = true class << Shell attr :cascade, true attr :debug, true attr :verbose, true # alias cascade? cascade alias debug? debug alias verbose? verbose @verbose = true def debug=(val) @debug = val @verbose = val if val end def cd(path) sh = new sh.cd path sh end def default_system_path if @default_system_path @default_system_path else ENV["PATH"].split(":") end end def default_system_path=(path) @default_system_path = path end def default_record_separator if @default_record_separator @default_record_separator else $/ end end def default_record_separator=(rs) @default_record_separator = rs end end def initialize @cwd = Dir.pwd @dir_stack = [] @umask = nil @system_path = Shell.default_system_path @record_separator = Shell.default_record_separator @command_processor = CommandProcessor.new(self) @process_controller = ProcessController.new(self) @verbose = Shell.verbose @debug = Shell.debug end attr_reader :system_path def system_path=(path) @system_path = path rehash end attr :umask, true attr :record_separator, true attr :verbose, true attr :debug, true def debug=(val) @debug = val @verbose = val if val end alias verbose? verbose alias debug? debug attr_reader :command_processor attr_reader :process_controller def expand_path(path) File.expand_path(path, @cwd) end # Most Shell commands are defined via CommandProcessor # # Dir related methods # # Shell#cwd/dir/getwd/pwd # Shell#chdir/cd # Shell#pushdir/pushd # Shell#popdir/popd # Shell#mkdir # Shell#rmdir attr :cwd alias dir cwd alias getwd cwd alias pwd cwd attr :dir_stack alias dirs dir_stack # If called as iterator, it restores the current directory when the # block ends. def chdir(path = nil) if iterator? cwd_old = @cwd begin chdir(path) yield ensure chdir(cwd_old) end else path = "~" unless path @cwd = expand_path(path) notify "current dir: #{@cwd}" rehash self end end alias cd chdir def pushdir(path = nil) if iterator? pushdir(path) begin yield ensure popdir end elsif path @dir_stack.push @cwd chdir path notify "dir stack: [#{@dir_stack.join ', '}]" self else if pop = @dir_stack.pop @dir_stack.push @cwd chdir pop notify "dir stack: [#{@dir_stack.join ', '}]" self else Shell.Fail DirStackEmpty end end end alias pushd pushdir def popdir if pop = @dir_stack.pop chdir pop notify "dir stack: [#{@dir_stack.join ', '}]" self else Shell.Fail DirStackEmpty end end alias popd popdir # # process management # def jobs @process_controller.jobs end def kill(sig, command) @process_controller.kill_job(sig, command) end # # command definitions # def Shell.def_system_command(command, path = command) CommandProcessor.def_system_command(command, path) end def Shell.undef_system_command(command) CommandProcessor.undef_system_command(command) end def Shell.alias_command(ali, command, *opts, &block) CommandProcessor.alias_command(ali, command, *opts, &block) end def Shell.unalias_command(ali) CommandProcessor.unalias_command(ali) end def Shell.install_system_commands(pre = "sys_") CommandProcessor.install_system_commands(pre) end # def inspect if debug.kind_of?(Integer) && debug > 2 super else to_s end end def self.notify(*opts, &block) Thread.exclusive do if opts[-1].kind_of?(String) yorn = verbose? else yorn = opts.pop end return unless yorn _head = true print opts.collect{|mes| mes = mes.dup yield mes if iterator? if _head _head = false "shell: " + mes else " " + mes end }.join("\n")+"\n" end end CommandProcessor.initialize CommandProcessor.run_config end ================================================ FILE: lib/shellwords.rb ================================================ # # shellwords.rb: Manipulates strings a la UNIX Bourne shell # # # This module manipulates strings according to the word parsing rules # of the UNIX Bourne shell. # # The shellwords() function was originally a port of shellwords.pl, # but modified to conform to POSIX / SUSv3 (IEEE Std 1003.1-2001). # # Authors: # - Wakou Aoyama # - Akinori MUSHA # # Contact: # - Akinori MUSHA (current maintainer) # module Shellwords # # Splits a string into an array of tokens in the same way the UNIX # Bourne shell does. # # argv = Shellwords.split('here are "two words"') # argv #=> ["here", "are", "two words"] # # +String#shellsplit+ is a shorthand for this function. # # argv = 'here are "two words"'.shellsplit # argv #=> ["here", "are", "two words"] # def shellsplit(line) line = String.new(line) rescue raise(ArgumentError, "Argument must be a string") line.lstrip! words = [] until line.empty? field = '' loop do if line.sub!(/\A"(([^"\\]|\\.)*)"/, '') then snippet = $1.gsub(/\\(.)/, '\1') elsif line =~ /\A"/ then raise ArgumentError, "Unmatched double quote: #{line}" elsif line.sub!(/\A'([^']*)'/, '') then snippet = $1 elsif line =~ /\A'/ then raise ArgumentError, "Unmatched single quote: #{line}" elsif line.sub!(/\A\\(.)?/, '') then snippet = $1 || '\\' elsif line.sub!(/\A([^\s\\'"]+)/, '') then snippet = $1 else line.lstrip! break end field.concat(snippet) end words.push(field) end words end alias shellwords shellsplit module_function :shellsplit, :shellwords class << self alias split shellsplit end # # Escapes a string so that it can be safely used in a Bourne shell # command line. # # Note that a resulted string should be used unquoted and is not # intended for use in double quotes nor in single quotes. # # open("| grep #{Shellwords.escape(pattern)} file") { |pipe| # # ... # } # # +String#shellescape+ is a shorthand for this function. # # open("| grep #{pattern.shellescape} file") { |pipe| # # ... # } # def shellescape(str) # An empty argument will be skipped, so return empty quotes. return "''" if str.empty? str = str.dup # Process as a single byte sequence because not all shell # implementations are multibyte aware. str.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/n, "\\\\\\1") # A LF cannot be escaped with a backslash because a backslash + LF # combo is regarded as line continuation and simply ignored. str.gsub!(/\n/, "'\n'") return str end module_function :shellescape class << self alias escape shellescape end # # Builds a command line string from an argument list +array+ joining # all elements escaped for Bourne shell and separated by a space. # # open('|' + Shellwords.join(['grep', pattern, *files])) { |pipe| # # ... # } # # +Array#shelljoin+ is a shorthand for this function. # # open('|' + ['grep', pattern, *files].shelljoin) { |pipe| # # ... # } # def shelljoin(array) array.map { |arg| shellescape(arg) }.join(' ') end module_function :shelljoin class << self alias join shelljoin end end class String # # call-seq: # str.shellsplit => array # # Splits +str+ into an array of tokens in the same way the UNIX # Bourne shell does. See +Shellwords::shellsplit+ for details. # def shellsplit Shellwords.split(self) end # # call-seq: # str.shellescape => string # # Escapes +str+ so that it can be safely used in a Bourne shell # command line. See +Shellwords::shellescape+ for details. # def shellescape Shellwords.escape(self) end end class Array # # call-seq: # array.shelljoin => string # # Builds a command line string from an argument list +array+ joining # all elements escaped for Bourne shell and separated by a space. # See +Shellwords::shelljoin+ for details. # def shelljoin Shellwords.join(self) end end ================================================ FILE: lib/singleton.rb ================================================ # The Singleton module implements the Singleton pattern. # # Usage: # class Klass # include Singleton # # ... # end # # * this ensures that only one instance of Klass lets call it # ``the instance'' can be created. # # a,b = Klass.instance, Klass.instance # a == b # => true # a.new # NoMethodError - new is private ... # # * ``The instance'' is created at instantiation time, in other # words the first call of Klass.instance(), thus # # class OtherKlass # include Singleton # # ... # end # ObjectSpace.each_object(OtherKlass){} # => 0. # # * This behavior is preserved under inheritance and cloning. # # # # This is achieved by marking # * Klass.new and Klass.allocate - as private # # Providing (or modifying) the class methods # * Klass.inherited(sub_klass) and Klass.clone() - # to ensure that the Singleton pattern is properly # inherited and cloned. # # * Klass.instance() - returning ``the instance''. After a # successful self modifying (normally the first) call the # method body is a simple: # # def Klass.instance() # return @__instance__ # end # # * Klass._load(str) - calling Klass.instance() # # * Klass._instantiate?() - returning ``the instance'' or # nil. This hook method puts a second (or nth) thread calling # Klass.instance() on a waiting loop. The return value # signifies the successful completion or premature termination # of the first, or more generally, current "instantiation thread". # # # The instance method of Singleton are # * clone and dup - raising TypeErrors to prevent cloning or duping # # * _dump(depth) - returning the empty string. Marshalling strips # by default all state information, e.g. instance variables and # taint state, from ``the instance''. Providing custom _load(str) # and _dump(depth) hooks allows the (partially) resurrections of # a previous state of ``the instance''. module Singleton # disable build-in copying methods def clone raise TypeError, "can't clone instance of singleton #{self.class}" end def dup raise TypeError, "can't dup instance of singleton #{self.class}" end # default marshalling strategy def _dump(depth=-1) '' end end class << Singleton # Method body of first instance call. FirstInstanceCall = proc do # @__instance__ takes on one of the following values # * nil - before and after a failed creation # * false - during creation # * sub_class instance - after a successful creation # the form makes up for the lack of returns in progs Thread.critical = true if @__instance__.nil? @__instance__ = false Thread.critical = false begin @__instance__ = new ensure if @__instance__ class < mes puts mes end puts "\nThreaded example with exception and customized #_instantiate?() hook"; p Thread.abort_on_exception = false class Ups < SomeSingletonClass def initialize self.class.__sleep puts "initialize called by thread ##{Thread.current[:i]}" end end class << Ups def _instantiate? @enter.push Thread.current[:i] while false.equal?(@__instance__) Thread.critical = false sleep 0.08 Thread.critical = true end @leave.push Thread.current[:i] @__instance__ end def __sleep sleep(rand(0.08)) end def new begin __sleep raise "boom - thread ##{Thread.current[:i]} failed to create instance" ensure # simple flip-flop class << self remove_method :new end end end def instantiate_all @enter = [] @leave = [] 1.upto(9) {|i| Thread.new { begin Thread.current[:i] = i __sleep instance rescue RuntimeError => mes puts mes end } } puts "Before there were #{num_of_instances(self)}" sleep 3 puts "Now there is #{num_of_instances(self)}" puts "#{@enter.join '; '} was the order of threads entering the waiting loop" puts "#{@leave.join '; '} was the order of threads leaving the waiting loop" end end Ups.instantiate_all # results in message like # Before there were 0 Ups instance(s) # boom - thread #6 failed to create instance # initialize called by thread #3 # Now there is 1 Ups instance(s) # 3; 2; 1; 8; 4; 7; 5 was the order of threads entering the waiting loop # 3; 2; 1; 7; 4; 8; 5 was the order of threads leaving the waiting loop puts "\nLets see if class level cloning really works" Yup = Ups.clone def Yup.new begin __sleep raise "boom - thread ##{Thread.current[:i]} failed to create instance" ensure # simple flip-flop class << self remove_method :new end end end Yup.instantiate_all puts "\n\n","Customized marshalling" class A include Singleton attr_accessor :persist, :die def _dump(depth) # this strips the @die information from the instance Marshal.dump(@persist,depth) end end def A._load(str) instance.persist = Marshal.load(str) instance end a = A.instance a.persist = ["persist"] a.die = "die" a.taint stored_state = Marshal.dump(a) # change state a.persist = nil a.die = nil b = Marshal.load(stored_state) p a == b # => true p a.persist # => ["persist"] p a.die # => nil puts "\n\nSingleton with overridden default #inherited() hook" class Up end def Up.inherited(sub_klass) puts "#{sub_klass} subclasses #{self}" end class Middle < Up include Singleton end class Down < Middle; end puts "and basic \"Down test\" is #{Down.instance == Down.instance}\n Various exceptions" begin module AModule include Singleton end rescue TypeError => mes puts mes #=> Inclusion of the OO-Singleton module in module AModule end begin 'aString'.extend Singleton rescue NoMethodError => mes puts mes #=> undefined method `extend_object' for Singleton:Module end end ================================================ FILE: lib/soap/attachment.rb ================================================ # soap/attachment.rb: SOAP4R - SwA implementation. # Copyright (C) 2002, 2003 Jamie Herre and NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/baseData' require 'soap/mapping' module SOAP class SOAPAttachment < SOAPExternalReference attr_reader :data def initialize(value) super() @data = value end private def external_contentid @data.contentid end end class Attachment attr_reader :io attr_accessor :contenttype def initialize(string_or_readable = nil) @string_or_readable = string_or_readable @contenttype = "application/octet-stream" @contentid = nil end def contentid @contentid ||= Attachment.contentid(self) end def contentid=(contentid) @contentid = contentid end def mime_contentid '<' + contentid + '>' end def content if @content == nil and @string_or_readable != nil @content = @string_or_readable.respond_to?(:read) ? @string_or_readable.read : @string_or_readable end @content end def to_s content end def write(out) out.write(content) end def save(filename) File.open(filename, "wb") do |f| write(f) end end def self.contentid(obj) # this needs to be fixed [obj.__id__.to_s, Process.pid.to_s].join('.') end def self.mime_contentid(obj) '<' + contentid(obj) + '>' end end module Mapping class AttachmentFactory < SOAP::Mapping::Factory def obj2soap(soap_class, obj, info, map) soap_obj = soap_class.new(obj) mark_marshalled_obj(obj, soap_obj) soap_obj end def soap2obj(obj_class, node, info, map) obj = node.data mark_unmarshalled_obj(node, obj) return true, obj end end DefaultRegistry.add(::SOAP::Attachment, ::SOAP::SOAPAttachment, AttachmentFactory.new, nil) end end ================================================ FILE: lib/soap/baseData.rb ================================================ # soap/baseData.rb: SOAP4R - Base type library # Copyright (C) 2000, 2001, 2003-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/datatypes' require 'soap/soap' module SOAP ### ## Mix-in module for SOAP base type classes. # module SOAPModuleUtils include SOAP public def decode(elename) d = self.new d.elename = elename d end end ### ## for SOAP type(base and compound) # module SOAPType attr_accessor :encodingstyle attr_accessor :elename attr_accessor :id attr_reader :precedents attr_accessor :root attr_accessor :parent attr_accessor :position attr_reader :extraattr attr_accessor :definedtype def initialize(*arg) super @encodingstyle = nil @elename = XSD::QName::EMPTY @id = nil @precedents = [] @root = false @parent = nil @position = nil @definedtype = nil @extraattr = {} end def inspect if self.is_a?(XSD::NSDBase) sprintf("#<%s:0x%x %s %s>", self.class.name, __id__, self.elename, self.type) else sprintf("#<%s:0x%x %s>", self.class.name, __id__, self.elename) end end def rootnode node = self while node = node.parent break if SOAPEnvelope === node end node end end ### ## for SOAP base type # module SOAPBasetype include SOAPType include SOAP def initialize(*arg) super end end ### ## for SOAP compound type # module SOAPCompoundtype include SOAPType include SOAP def initialize(*arg) super end end ### ## Convenience datatypes. # class SOAPReference < XSD::NSDBase include SOAPBasetype extend SOAPModuleUtils public attr_accessor :refid # Override the definition in SOAPBasetype. def initialize(obj = nil) super() @type = XSD::QName::EMPTY @refid = nil @obj = nil __setobj__(obj) if obj end def __getobj__ @obj end def __setobj__(obj) @obj = obj @refid = @obj.id || SOAPReference.create_refid(@obj) @obj.id = @refid unless @obj.id @obj.precedents << self # Copies NSDBase information @obj.type = @type unless @obj.type end # Why don't I use delegate.rb? # -> delegate requires target object type at initialize time. # Why don't I use forwardable.rb? # -> forwardable requires a list of forwarding methods. # # ToDo: Maybe I should use forwardable.rb and give it a methods list like # delegate.rb... # def method_missing(msg_id, *params) if @obj @obj.send(msg_id, *params) else nil end end def refidstr '#' + @refid end def self.create_refid(obj) 'id' + obj.__id__.to_s end def self.decode(elename, refidstr) if /\A#(.*)\z/ =~ refidstr refid = $1 elsif /\Acid:(.*)\z/ =~ refidstr refid = $1 else raise ArgumentError.new("illegal refid #{refidstr}") end d = super(elename) d.refid = refid d end end class SOAPExternalReference < XSD::NSDBase include SOAPBasetype extend SOAPModuleUtils def initialize super() @type = XSD::QName::EMPTY end def referred rootnode.external_content[external_contentid] = self end def refidstr 'cid:' + external_contentid end private def external_contentid raise NotImplementedError.new end end class SOAPNil < XSD::XSDNil include SOAPBasetype extend SOAPModuleUtils end # SOAPRawString is for sending raw string. In contrast to SOAPString, # SOAP4R does not do XML encoding and does not convert its CES. The string it # holds is embedded to XML instance directly as a 'xsd:string'. class SOAPRawString < XSD::XSDString include SOAPBasetype extend SOAPModuleUtils end ### ## Basic datatypes. # class SOAPAnySimpleType < XSD::XSDAnySimpleType include SOAPBasetype extend SOAPModuleUtils end class SOAPString < XSD::XSDString include SOAPBasetype extend SOAPModuleUtils end class SOAPBoolean < XSD::XSDBoolean include SOAPBasetype extend SOAPModuleUtils end class SOAPDecimal < XSD::XSDDecimal include SOAPBasetype extend SOAPModuleUtils end class SOAPFloat < XSD::XSDFloat include SOAPBasetype extend SOAPModuleUtils end class SOAPDouble < XSD::XSDDouble include SOAPBasetype extend SOAPModuleUtils end class SOAPDuration < XSD::XSDDuration include SOAPBasetype extend SOAPModuleUtils end class SOAPDateTime < XSD::XSDDateTime include SOAPBasetype extend SOAPModuleUtils end class SOAPTime < XSD::XSDTime include SOAPBasetype extend SOAPModuleUtils end class SOAPDate < XSD::XSDDate include SOAPBasetype extend SOAPModuleUtils end class SOAPGYearMonth < XSD::XSDGYearMonth include SOAPBasetype extend SOAPModuleUtils end class SOAPGYear < XSD::XSDGYear include SOAPBasetype extend SOAPModuleUtils end class SOAPGMonthDay < XSD::XSDGMonthDay include SOAPBasetype extend SOAPModuleUtils end class SOAPGDay < XSD::XSDGDay include SOAPBasetype extend SOAPModuleUtils end class SOAPGMonth < XSD::XSDGMonth include SOAPBasetype extend SOAPModuleUtils end class SOAPHexBinary < XSD::XSDHexBinary include SOAPBasetype extend SOAPModuleUtils end class SOAPBase64 < XSD::XSDBase64Binary include SOAPBasetype extend SOAPModuleUtils Type = QName.new(EncodingNamespace, Base64Literal) public # Override the definition in SOAPBasetype. def initialize(value = nil) super(value) @type = Type end def as_xsd @type = XSD::XSDBase64Binary::Type end end class SOAPAnyURI < XSD::XSDAnyURI include SOAPBasetype extend SOAPModuleUtils end class SOAPQName < XSD::XSDQName include SOAPBasetype extend SOAPModuleUtils end class SOAPInteger < XSD::XSDInteger include SOAPBasetype extend SOAPModuleUtils end class SOAPNonPositiveInteger < XSD::XSDNonPositiveInteger include SOAPBasetype extend SOAPModuleUtils end class SOAPNegativeInteger < XSD::XSDNegativeInteger include SOAPBasetype extend SOAPModuleUtils end class SOAPLong < XSD::XSDLong include SOAPBasetype extend SOAPModuleUtils end class SOAPInt < XSD::XSDInt include SOAPBasetype extend SOAPModuleUtils end class SOAPShort < XSD::XSDShort include SOAPBasetype extend SOAPModuleUtils end class SOAPByte < XSD::XSDByte include SOAPBasetype extend SOAPModuleUtils end class SOAPNonNegativeInteger < XSD::XSDNonNegativeInteger include SOAPBasetype extend SOAPModuleUtils end class SOAPUnsignedLong < XSD::XSDUnsignedLong include SOAPBasetype extend SOAPModuleUtils end class SOAPUnsignedInt < XSD::XSDUnsignedInt include SOAPBasetype extend SOAPModuleUtils end class SOAPUnsignedShort < XSD::XSDUnsignedShort include SOAPBasetype extend SOAPModuleUtils end class SOAPUnsignedByte < XSD::XSDUnsignedByte include SOAPBasetype extend SOAPModuleUtils end class SOAPPositiveInteger < XSD::XSDPositiveInteger include SOAPBasetype extend SOAPModuleUtils end ### ## Compound datatypes. # class SOAPStruct < XSD::NSDBase include SOAPCompoundtype include Enumerable public def initialize(type = nil) super() @type = type || XSD::QName::EMPTY @array = [] @data = [] end def to_s() str = '' self.each do |key, data| str << "#{key}: #{data}\n" end str end def add(name, value) add_member(name, value) end def [](idx) if idx.is_a?(Range) @data[idx] elsif idx.is_a?(Integer) if (idx > @array.size) raise ArrayIndexOutOfBoundsError.new('In ' << @type.name) end @data[idx] else if @array.include?(idx) @data[@array.index(idx)] else nil end end end def []=(idx, data) if @array.include?(idx) data.parent = self if data.respond_to?(:parent=) @data[@array.index(idx)] = data else add(idx, data) end end def key?(name) @array.include?(name) end def members @array end def to_obj hash = {} proptype = {} each do |k, v| value = v.respond_to?(:to_obj) ? v.to_obj : v.to_s case proptype[k] when :single hash[k] = [hash[k], value] proptype[k] = :multi when :multi hash[k] << value else hash[k] = value proptype[k] = :single end end hash end def each idx = 0 while idx < @array.length yield(@array[idx], @data[idx]) idx += 1 end end def replace members.each do |member| self[member] = yield(self[member]) end end def self.decode(elename, type) s = SOAPStruct.new(type) s.elename = elename s end private def add_member(name, value = nil) value = SOAPNil.new() if value.nil? @array.push(name) value.elename = value.elename.dup_name(name) @data.push(value) value.parent = self if value.respond_to?(:parent=) value end end # SOAPElement is not typed so it is not derived from NSDBase. class SOAPElement include Enumerable attr_accessor :encodingstyle attr_accessor :elename attr_accessor :id attr_reader :precedents attr_accessor :root attr_accessor :parent attr_accessor :position attr_accessor :extraattr attr_accessor :qualified def initialize(elename, text = nil) if !elename.is_a?(XSD::QName) elename = XSD::QName.new(nil, elename) end @encodingstyle = LiteralNamespace @elename = elename @id = nil @precedents = [] @root = false @parent = nil @position = nil @extraattr = {} @qualified = nil @array = [] @data = [] @text = text end def inspect sprintf("#<%s:0x%x %s>", self.class.name, __id__, self.elename) end # Text interface. attr_accessor :text alias data text # Element interfaces. def add(value) add_member(value.elename.name, value) end def [](idx) if @array.include?(idx) @data[@array.index(idx)] else nil end end def []=(idx, data) if @array.include?(idx) data.parent = self if data.respond_to?(:parent=) @data[@array.index(idx)] = data else add(data) end end def key?(name) @array.include?(name) end def members @array end def to_obj if members.empty? @text else hash = {} proptype = {} each do |k, v| value = v.respond_to?(:to_obj) ? v.to_obj : v.to_s case proptype[k] when :single hash[k] = [hash[k], value] proptype[k] = :multi when :multi hash[k] << value else hash[k] = value proptype[k] = :single end end hash end end def each idx = 0 while idx < @array.length yield(@array[idx], @data[idx]) idx += 1 end end def self.decode(elename) o = SOAPElement.new(elename) o end def self.from_obj(obj, namespace = nil) o = SOAPElement.new(nil) case obj when nil o.text = nil when Hash obj.each do |elename, value| if value.is_a?(Array) value.each do |subvalue| child = from_obj(subvalue, namespace) child.elename = to_elename(elename, namespace) o.add(child) end else child = from_obj(value, namespace) child.elename = to_elename(elename, namespace) o.add(child) end end else o.text = obj.to_s end o end def self.to_elename(obj, namespace = nil) if obj.is_a?(XSD::QName) obj elsif /\A(.+):([^:]+)\z/ =~ obj.to_s XSD::QName.new($1, $2) else XSD::QName.new(namespace, obj.to_s) end end private def add_member(name, value) add_accessor(name) @array.push(name) @data.push(value) value.parent = self if value.respond_to?(:parent=) value end if RUBY_VERSION > "1.7.0" def add_accessor(name) methodname = name if self.respond_to?(methodname) methodname = safe_accessor_name(methodname) end Mapping.define_singleton_method(self, methodname) do @data[@array.index(name)] end Mapping.define_singleton_method(self, methodname + '=') do |value| @data[@array.index(name)] = value end end else def add_accessor(name) methodname = safe_accessor_name(name) instance_eval <<-EOS def #{methodname} @data[@array.index(#{name.dump})] end def #{methodname}=(value) @data[@array.index(#{name.dump})] = value end EOS end end def safe_accessor_name(name) "var_" << name.gsub(/[^a-zA-Z0-9_]/, '') end end class SOAPArray < XSD::NSDBase include SOAPCompoundtype include Enumerable public attr_accessor :sparse attr_reader :offset, :rank attr_accessor :size, :size_fixed attr_reader :arytype def initialize(type = nil, rank = 1, arytype = nil) super() @type = type || ValueArrayName @rank = rank @data = Array.new @sparse = false @offset = Array.new(rank, 0) @size = Array.new(rank, 0) @size_fixed = false @position = nil @arytype = arytype end def offset=(var) @offset = var @sparse = true end def add(value) self[*(@offset)] = value end def [](*idxary) if idxary.size != @rank raise ArgumentError.new("given #{idxary.size} params does not match rank: #{@rank}") end retrieve(idxary) end def []=(*idxary) value = idxary.slice!(-1) if idxary.size != @rank raise ArgumentError.new("given #{idxary.size} params(#{idxary})" + " does not match rank: #{@rank}") end idx = 0 while idx < idxary.size if idxary[idx] + 1 > @size[idx] @size[idx] = idxary[idx] + 1 end idx += 1 end data = retrieve(idxary[0, idxary.size - 1]) data[idxary.last] = value if value.is_a?(SOAPType) value.elename = ITEM_NAME # Sync type unless @type.name @type = XSD::QName.new(value.type.namespace, SOAPArray.create_arytype(value.type.name, @rank)) end value.type ||= @type end @offset = idxary value.parent = self if value.respond_to?(:parent=) offsetnext end def each @data.each do |data| yield(data) end end def to_a @data.dup end def replace @data = deep_map(@data) do |ele| yield(ele) end end def deep_map(ary, &block) ary.collect do |ele| if ele.is_a?(Array) deep_map(ele, &block) else new_obj = block.call(ele) new_obj.elename = ITEM_NAME new_obj end end end def include?(var) traverse_data(@data) do |v, *rank| if v.is_a?(SOAPBasetype) && v.data == var return true end end false end def traverse traverse_data(@data) do |v, *rank| unless @sparse yield(v) else yield(v, *rank) if v && !v.is_a?(SOAPNil) end end end def soap2array(ary) traverse_data(@data) do |v, *position| iteary = ary rank = 1 while rank < position.size idx = position[rank - 1] if iteary[idx].nil? iteary = iteary[idx] = Array.new else iteary = iteary[idx] end rank += 1 end if block_given? iteary[position.last] = yield(v) else iteary[position.last] = v end end end def position @position end private ITEM_NAME = XSD::QName.new(nil, 'item') def retrieve(idxary) data = @data rank = 1 while rank <= idxary.size idx = idxary[rank - 1] if data[idx].nil? data = data[idx] = Array.new else data = data[idx] end rank += 1 end data end def traverse_data(data, rank = 1) idx = 0 while idx < ranksize(rank) if rank < @rank traverse_data(data[idx], rank + 1) do |*v| v[1, 0] = idx yield(*v) end else yield(data[idx], idx) end idx += 1 end end def ranksize(rank) @size[rank - 1] end def offsetnext move = false idx = @offset.size - 1 while !move && idx >= 0 @offset[idx] += 1 if @size_fixed if @offset[idx] < @size[idx] move = true else @offset[idx] = 0 idx -= 1 end else move = true end end end # Module function public def self.decode(elename, type, arytype) typestr, nofary = parse_type(arytype.name) rank = nofary.count(',') + 1 plain_arytype = XSD::QName.new(arytype.namespace, typestr) o = SOAPArray.new(type, rank, plain_arytype) size = [] nofary.split(',').each do |s| if s.empty? size.clear break else size << s.to_i end end unless size.empty? o.size = size o.size_fixed = true end o.elename = elename o end private def self.create_arytype(typename, rank) "#{typename}[" << ',' * (rank - 1) << ']' end TypeParseRegexp = Regexp.new('^(.+)\[([\d,]*)\]$') def self.parse_type(string) TypeParseRegexp =~ string return $1, $2 end end require 'soap/mapping/typeMap' end ================================================ FILE: lib/soap/element.rb ================================================ # SOAP4R - SOAP elements library # Copyright (C) 2000, 2001, 2003-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' require 'soap/baseData' module SOAP ### ## SOAP elements # module SOAPEnvelopeElement; end class SOAPFault < SOAPStruct include SOAPEnvelopeElement include SOAPCompoundtype public def faultcode self['faultcode'] end def faultstring self['faultstring'] end def faultactor self['faultactor'] end def detail self['detail'] end def faultcode=(rhs) self['faultcode'] = rhs end def faultstring=(rhs) self['faultstring'] = rhs end def faultactor=(rhs) self['faultactor'] = rhs end def detail=(rhs) self['detail'] = rhs end def initialize(faultcode = nil, faultstring = nil, faultactor = nil, detail = nil) super(EleFaultName) @elename = EleFaultName @encodingstyle = EncodingNamespace if faultcode self.faultcode = faultcode self.faultstring = faultstring self.faultactor = faultactor self.detail = detail self.faultcode.elename = EleFaultCodeName if self.faultcode self.faultstring.elename = EleFaultStringName if self.faultstring self.faultactor.elename = EleFaultActorName if self.faultactor self.detail.elename = EleFaultDetailName if self.detail end faultcode.parent = self if faultcode faultstring.parent = self if faultstring faultactor.parent = self if faultactor detail.parent = self if detail end def encode(generator, ns, attrs = {}) SOAPGenerator.assign_ns(attrs, ns, EnvelopeNamespace) SOAPGenerator.assign_ns(attrs, ns, EncodingNamespace) attrs[ns.name(AttrEncodingStyleName)] = EncodingNamespace name = ns.name(@elename) generator.encode_tag(name, attrs) yield(self.faultcode) yield(self.faultstring) yield(self.faultactor) yield(self.detail) if self.detail generator.encode_tag_end(name, true) end end class SOAPBody < SOAPStruct include SOAPEnvelopeElement def initialize(data = nil, is_fault = false) super(nil) @elename = EleBodyName @encodingstyle = nil if data if data.respond_to?(:elename) add(data.elename.name, data) else data.to_a.each do |datum| add(datum.elename.name, datum) end end end @is_fault = is_fault end def encode(generator, ns, attrs = {}) name = ns.name(@elename) generator.encode_tag(name, attrs) if @is_fault yield(@data) else @data.each do |data| yield(data) end end generator.encode_tag_end(name, true) end def root_node @data.each do |node| if node.root == 1 return node end end # No specified root... @data.each do |node| if node.root != 0 return node end end raise Parser::FormatDecodeError.new('no root element') end end class SOAPHeaderItem < XSD::NSDBase include SOAPEnvelopeElement include SOAPCompoundtype public attr_accessor :element attr_accessor :mustunderstand attr_accessor :encodingstyle def initialize(element, mustunderstand = true, encodingstyle = nil) super() @type = nil @element = element @mustunderstand = mustunderstand @encodingstyle = encodingstyle element.parent = self if element end def encode(generator, ns, attrs = {}) attrs.each do |key, value| @element.extraattr[key] = value end @element.extraattr[ns.name(AttrMustUnderstandName)] = (@mustunderstand ? '1' : '0') if @encodingstyle @element.extraattr[ns.name(AttrEncodingStyleName)] = @encodingstyle end @element.encodingstyle = @encodingstyle if !@element.encodingstyle yield(@element) end end class SOAPHeader < SOAPStruct include SOAPEnvelopeElement def initialize super(nil) @elename = EleHeaderName @encodingstyle = nil end def encode(generator, ns, attrs = {}) name = ns.name(@elename) generator.encode_tag(name, attrs) @data.each do |data| yield(data) end generator.encode_tag_end(name, true) end def add(name, value) mu = (value.extraattr[AttrMustUnderstandName] == '1') encstyle = value.extraattr[AttrEncodingStyleName] item = SOAPHeaderItem.new(value, mu, encstyle) super(name, item) end def length @data.length end alias size length end class SOAPEnvelope < XSD::NSDBase include SOAPEnvelopeElement include SOAPCompoundtype attr_reader :header attr_reader :body attr_reader :external_content def initialize(header = nil, body = nil) super() @type = nil @elename = EleEnvelopeName @encodingstyle = nil @header = header @body = body @external_content = {} header.parent = self if header body.parent = self if body end def header=(header) header.parent = self @header = header end def body=(body) body.parent = self @body = body end def encode(generator, ns, attrs = {}) SOAPGenerator.assign_ns(attrs, ns, elename.namespace, SOAPNamespaceTag) name = ns.name(@elename) generator.encode_tag(name, attrs) yield(@header) if @header and @header.length > 0 yield(@body) generator.encode_tag_end(name, true) end def to_ary [header, body] end end end ================================================ FILE: lib/soap/encodingstyle/aspDotNetHandler.rb ================================================ # SOAP4R - ASP.NET EncodingStyle handler library # Copyright (C) 2001, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/encodingstyle/handler' module SOAP module EncodingStyle class ASPDotNetHandler < Handler Namespace = 'http://tempuri.org/ASP.NET' add_handler def initialize(charset = nil) super(charset) @textbuf = '' @decode_typemap = nil end ### ## encode interface. # def encode_data(generator, ns, data, parent) attrs = {} # ASPDotNetHandler is intended to be used for accessing an ASP.NET doc/lit # service as an rpc/encoded service. in the situation, local elements # should be qualified. propagate parent's namespace to children. if data.elename.namespace.nil? data.elename.namespace = parent.elename.namespace end name = generator.encode_name(ns, data, attrs) case data when SOAPRawString generator.encode_tag(name, attrs) generator.encode_rawstring(data.to_s) when XSD::XSDString generator.encode_tag(name, attrs) generator.encode_string(@charset ? XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s) when XSD::XSDAnySimpleType generator.encode_tag(name, attrs) generator.encode_string(data.to_s) when SOAPStruct generator.encode_tag(name, attrs) data.each do |key, value| generator.encode_child(ns, value, data) end when SOAPArray generator.encode_tag(name, attrs) data.traverse do |child, *rank| data.position = nil generator.encode_child(ns, child, data) end else raise EncodingStyleError.new( "unknown object:#{data} in this encodingStyle") end end def encode_data_end(generator, ns, data, parent) name = generator.encode_name_end(ns, data) cr = data.is_a?(SOAPCompoundtype) generator.encode_tag_end(name, cr) end ### ## decode interface. # class SOAPTemporalObject attr_accessor :parent def initialize @parent = nil end end class SOAPUnknown < SOAPTemporalObject def initialize(handler, elename) super() @handler = handler @elename = elename end def as_struct o = SOAPStruct.decode(@elename, XSD::AnyTypeName) o.parent = @parent o.type.name = @name @handler.decode_parent(@parent, o) o end def as_string o = SOAPString.decode(@elename) o.parent = @parent @handler.decode_parent(@parent, o) o end def as_nil o = SOAPNil.decode(@elename) o.parent = @parent @handler.decode_parent(@parent, o) o end end def decode_tag(ns, elename, attrs, parent) @textbuf = '' o = SOAPUnknown.new(self, elename) o.parent = parent o end def decode_tag_end(ns, node) o = node.node if o.is_a?(SOAPUnknown) newnode = o.as_string # if /\A\s*\z/ =~ @textbuf # o.as_struct # else # o.as_string # end node.replace_node(newnode) o = node.node end decode_textbuf(o) @textbuf = '' end def decode_text(ns, text) # @textbuf is set at decode_tag_end. @textbuf << text end def decode_prologue end def decode_epilogue end def decode_parent(parent, node) case parent.node when SOAPUnknown newparent = parent.node.as_struct node.parent = newparent parent.replace_node(newparent) decode_parent(parent, node) when SOAPStruct data = parent.node[node.elename.name] case data when nil parent.node.add(node.elename.name, node) when SOAPArray name, type_ns = node.elename.name, node.type.namespace data.add(node) node.elename, node.type.namespace = name, type_ns else parent.node[node.elename.name] = SOAPArray.new name, type_ns = data.elename.name, data.type.namespace parent.node[node.elename.name].add(data) data.elename.name, data.type.namespace = name, type_ns name, type_ns = node.elename.name, node.type.namespace parent.node[node.elename.name].add(node) node.elename.name, node.type.namespace = name, type_ns end when SOAPArray if node.position parent.node[*(decode_arypos(node.position))] = node parent.node.sparse = true else parent.node.add(node) end when SOAPBasetype raise EncodingStyleError.new("SOAP base type must not have a child") else # SOAPUnknown does not have parent. # raise EncodingStyleError.new("illegal parent: #{parent}") end end private def decode_textbuf(node) if node.is_a?(XSD::XSDString) if @charset node.set(XSD::Charset.encoding_from_xml(@textbuf, @charset)) else node.set(@textbuf) end else # Nothing to do... end end end ASPDotNetHandler.new end end ================================================ FILE: lib/soap/encodingstyle/handler.rb ================================================ # SOAP4R - EncodingStyle handler library # Copyright (C) 2001, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/soap' require 'soap/baseData' require 'soap/element' module SOAP module EncodingStyle class Handler @@handlers = {} class EncodingStyleError < Error; end class << self def uri self::Namespace end def handler(uri) @@handlers[uri] end def each @@handlers.each do |key, value| yield(value) end end private def add_handler @@handlers[self.uri] = self end end attr_reader :charset attr_accessor :generate_explicit_type def decode_typemap=(definedtypes) @decode_typemap = definedtypes end def initialize(charset) @charset = charset @generate_explicit_type = true @decode_typemap = nil end ### ## encode interface. # # Returns a XML instance as a string. def encode_data(generator, ns, data, parent) raise NotImplementError end def encode_data_end(generator, ns, data, parent) raise NotImplementError end def encode_prologue end def encode_epilogue end ### ## decode interface. # # Returns SOAP/OM data. def decode_tag(ns, name, attrs, parent) raise NotImplementError.new('Method decode_tag must be defined in derived class.') end def decode_tag_end(ns, name) raise NotImplementError.new('Method decode_tag_end must be defined in derived class.') end def decode_text(ns, text) raise NotImplementError.new('Method decode_text must be defined in derived class.') end def decode_prologue end def decode_epilogue end end end end ================================================ FILE: lib/soap/encodingstyle/literalHandler.rb ================================================ # SOAP4R - XML Literal EncodingStyle handler library # Copyright (C) 2001, 2003-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/encodingstyle/handler' module SOAP module EncodingStyle class LiteralHandler < Handler Namespace = SOAP::LiteralNamespace add_handler def initialize(charset = nil) super(charset) @textbuf = '' end ### ## encode interface. # def encode_data(generator, ns, data, parent) attrs = {} name = generator.encode_name(ns, data, attrs) data.extraattr.each do |k, v| # ToDo: check generator.attributeformdefault here if k.is_a?(XSD::QName) if k.namespace SOAPGenerator.assign_ns(attrs, ns, k.namespace) k = ns.name(k) else k = k.name end end attrs[k] = v end case data when SOAPRawString generator.encode_tag(name, attrs) generator.encode_rawstring(data.to_s) when XSD::XSDString generator.encode_tag(name, attrs) str = data.to_s str = XSD::Charset.encoding_to_xml(str, @charset) if @charset generator.encode_string(str) when XSD::XSDAnySimpleType generator.encode_tag(name, attrs) generator.encode_string(data.to_s) when SOAPStruct generator.encode_tag(name, attrs) data.each do |key, value| generator.encode_child(ns, value, data) end when SOAPArray generator.encode_tag(name, attrs) data.traverse do |child, *rank| data.position = nil generator.encode_child(ns, child, data) end when SOAPElement # passes 2 times for simplifying namespace definition data.each do |key, value| if value.elename.namespace SOAPGenerator.assign_ns(attrs, ns, value.elename.namespace) end end generator.encode_tag(name, attrs) generator.encode_rawstring(data.text) if data.text data.each do |key, value| generator.encode_child(ns, value, data) end else raise EncodingStyleError.new( "unknown object:#{data} in this encodingStyle") end end def encode_data_end(generator, ns, data, parent) name = generator.encode_name_end(ns, data) cr = (data.is_a?(SOAPCompoundtype) or (data.is_a?(SOAPElement) and !data.text)) generator.encode_tag_end(name, cr) end ### ## decode interface. # class SOAPTemporalObject attr_accessor :parent def initialize @parent = nil end end class SOAPUnknown < SOAPTemporalObject def initialize(handler, elename, extraattr) super() @handler = handler @elename = elename @extraattr = extraattr end def as_element o = SOAPElement.decode(@elename) o.parent = @parent o.extraattr.update(@extraattr) @handler.decode_parent(@parent, o) o end def as_string o = SOAPString.decode(@elename) o.parent = @parent o.extraattr.update(@extraattr) @handler.decode_parent(@parent, o) o end def as_nil o = SOAPNil.decode(@elename) o.parent = @parent o.extraattr.update(@extraattr) @handler.decode_parent(@parent, o) o end end def decode_tag(ns, elename, attrs, parent) @textbuf = '' o = SOAPUnknown.new(self, elename, decode_attrs(ns, attrs)) o.parent = parent o end def decode_tag_end(ns, node) o = node.node if o.is_a?(SOAPUnknown) newnode = if /\A\s*\z/ =~ @textbuf o.as_element else o.as_string end node.replace_node(newnode) o = node.node end decode_textbuf(o) @textbuf = '' end def decode_text(ns, text) # @textbuf is set at decode_tag_end. @textbuf << text end def decode_attrs(ns, attrs) extraattr = {} attrs.each do |key, value| qname = ns.parse_local(key) extraattr[qname] = value end extraattr end def decode_prologue end def decode_epilogue end def decode_parent(parent, node) return unless parent.node case parent.node when SOAPUnknown newparent = parent.node.as_element node.parent = newparent parent.replace_node(newparent) decode_parent(parent, node) when SOAPElement parent.node.add(node) node.parent = parent.node when SOAPStruct parent.node.add(node.elename.name, node) node.parent = parent.node when SOAPArray if node.position parent.node[*(decode_arypos(node.position))] = node parent.node.sparse = true else parent.node.add(node) end node.parent = parent.node else raise EncodingStyleError.new("illegal parent: #{parent.node}") end end private def decode_textbuf(node) if node.is_a?(XSD::XSDString) if @charset node.set(XSD::Charset.encoding_from_xml(@textbuf, @charset)) else node.set(@textbuf) end else # Nothing to do... end end end LiteralHandler.new end end ================================================ FILE: lib/soap/encodingstyle/soapHandler.rb ================================================ # SOAP4R - SOAP EncodingStyle handler library # Copyright (C) 2001, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/encodingstyle/handler' module SOAP module EncodingStyle class SOAPHandler < Handler Namespace = SOAP::EncodingNamespace add_handler def initialize(charset = nil) super(charset) @refpool = [] @idpool = [] @textbuf = '' @is_first_top_ele = true end ### ## encode interface. # def encode_data(generator, ns, data, parent) attrs = encode_attrs(generator, ns, data, parent) if parent && parent.is_a?(SOAPArray) && parent.position attrs[ns.name(AttrPositionName)] = "[#{parent.position.join(',')}]" end name = generator.encode_name(ns, data, attrs) case data when SOAPReference attrs['href'] = data.refidstr generator.encode_tag(name, attrs) when SOAPExternalReference data.referred attrs['href'] = data.refidstr generator.encode_tag(name, attrs) when SOAPRawString generator.encode_tag(name, attrs) generator.encode_rawstring(data.to_s) when XSD::XSDString generator.encode_tag(name, attrs) generator.encode_string(@charset ? XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s) when XSD::XSDAnySimpleType generator.encode_tag(name, attrs) generator.encode_string(data.to_s) when SOAPStruct generator.encode_tag(name, attrs) data.each do |key, value| generator.encode_child(ns, value, data) end when SOAPArray generator.encode_tag(name, attrs) data.traverse do |child, *rank| data.position = data.sparse ? rank : nil generator.encode_child(ns, child, data) end else raise EncodingStyleError.new( "unknown object:#{data} in this encodingStyle") end end def encode_data_end(generator, ns, data, parent) name = generator.encode_name_end(ns, data) cr = data.is_a?(SOAPCompoundtype) generator.encode_tag_end(name, cr) end ### ## decode interface. # class SOAPTemporalObject attr_accessor :parent attr_accessor :position attr_accessor :id attr_accessor :root def initialize @parent = nil @position = nil @id = nil @root = nil end end class SOAPUnknown < SOAPTemporalObject attr_reader :type attr_accessor :definedtype attr_reader :extraattr def initialize(handler, elename, type, extraattr) super() @handler = handler @elename = elename @type = type @extraattr = extraattr @definedtype = nil end def as_struct o = SOAPStruct.decode(@elename, @type) o.id = @id o.root = @root o.parent = @parent o.position = @position o.extraattr.update(@extraattr) @handler.decode_parent(@parent, o) o end def as_string o = SOAPString.decode(@elename) o.id = @id o.root = @root o.parent = @parent o.position = @position o.extraattr.update(@extraattr) @handler.decode_parent(@parent, o) o end def as_nil o = SOAPNil.decode(@elename) o.id = @id o.root = @root o.parent = @parent o.position = @position o.extraattr.update(@extraattr) @handler.decode_parent(@parent, o) o end end def decode_tag(ns, elename, attrs, parent) @textbuf = '' is_nil, type, arytype, root, offset, position, href, id, extraattr = decode_attrs(ns, attrs) o = nil if is_nil o = SOAPNil.decode(elename) elsif href o = SOAPReference.decode(elename, href) @refpool << o elsif @decode_typemap o = decode_tag_by_wsdl(ns, elename, type, parent.node, arytype, extraattr) else o = decode_tag_by_type(ns, elename, type, parent.node, arytype, extraattr) end if o.is_a?(SOAPArray) if offset o.offset = decode_arypos(offset) o.sparse = true else o.sparse = false end end o.parent = parent o.id = id o.root = root o.position = position unless o.is_a?(SOAPTemporalObject) @idpool << o if o.id decode_parent(parent, o) end o end def decode_tag_end(ns, node) o = node.node if o.is_a?(SOAPUnknown) newnode = if /\A\s*\z/ =~ @textbuf o.as_struct else o.as_string end if newnode.id @idpool << newnode end node.replace_node(newnode) o = node.node end decode_textbuf(o) # unlink definedtype o.definedtype = nil end def decode_text(ns, text) @textbuf << text end def decode_prologue @refpool.clear @idpool.clear @is_first_top_ele = true end def decode_epilogue decode_resolve_id end def decode_parent(parent, node) return unless parent.node case parent.node when SOAPUnknown newparent = parent.node.as_struct node.parent = newparent if newparent.id @idpool << newparent end parent.replace_node(newparent) decode_parent(parent, node) when SOAPStruct parent.node.add(node.elename.name, node) node.parent = parent.node when SOAPArray if node.position parent.node[*(decode_arypos(node.position))] = node parent.node.sparse = true else parent.node.add(node) end node.parent = parent.node else raise EncodingStyleError.new("illegal parent: #{parent.node}") end end private def content_ranksize(typename) typename.scan(/\[[\d,]*\]$/)[0] end def content_typename(typename) typename.sub(/\[,*\]$/, '') end def create_arytype(ns, data) XSD::QName.new(data.arytype.namespace, content_typename(data.arytype.name) + "[#{data.size.join(',')}]") end def encode_attrs(generator, ns, data, parent) attrs = {} return attrs if data.is_a?(SOAPReference) if !parent || parent.encodingstyle != EncodingNamespace if @generate_explicit_type SOAPGenerator.assign_ns(attrs, ns, EnvelopeNamespace) attrs[ns.name(AttrEncodingStyleName)] = EncodingNamespace end data.encodingstyle = EncodingNamespace end if data.is_a?(SOAPNil) attrs[ns.name(XSD::AttrNilName)] = XSD::NilValue elsif @generate_explicit_type if data.type.namespace SOAPGenerator.assign_ns(attrs, ns, data.type.namespace) end if data.is_a?(SOAPArray) if data.arytype.namespace SOAPGenerator.assign_ns(attrs, ns, data.arytype.namespace) end SOAPGenerator.assign_ns(attrs, ns, EncodingNamespace) attrs[ns.name(AttrArrayTypeName)] = ns.name(create_arytype(ns, data)) if data.type.name attrs[ns.name(XSD::AttrTypeName)] = ns.name(data.type) end elsif parent && parent.is_a?(SOAPArray) && (parent.arytype == data.type) # No need to add. elsif !data.type.namespace # No need to add. else attrs[ns.name(XSD::AttrTypeName)] = ns.name(data.type) end end data.extraattr.each do |key, value| SOAPGenerator.assign_ns(attrs, ns, key.namespace) attrs[ns.name(key)] = encode_attr_value(generator, ns, key, value) end if data.id attrs['id'] = data.id end attrs end def encode_attr_value(generator, ns, qname, value) if value.is_a?(SOAPType) ref = SOAPReference.new(value) generator.add_reftarget(qname.name, value) ref.refidstr else value.to_s end end def decode_tag_by_wsdl(ns, elename, typestr, parent, arytypestr, extraattr) o = nil if parent.class == SOAPBody # root element: should branch by root attribute? if @is_first_top_ele # Unqualified name is allowed here. @is_first_top_ele = false type = @decode_typemap[elename] || @decode_typemap.find_name(elename.name) if type o = SOAPStruct.new(elename) o.definedtype = type return o end end # multi-ref element. if typestr typename = ns.parse(typestr) typedef = @decode_typemap[typename] if typedef return decode_definedtype(elename, typename, typedef, arytypestr) end end return decode_tag_by_type(ns, elename, typestr, parent, arytypestr, extraattr) end if parent.type == XSD::AnyTypeName return decode_tag_by_type(ns, elename, typestr, parent, arytypestr, extraattr) end # parent.definedtype == nil means the parent is SOAPUnknown. SOAPUnknown # is generated by decode_tag_by_type when its type is anyType. parenttype = parent.definedtype || @decode_typemap[parent.type] unless parenttype return decode_tag_by_type(ns, elename, typestr, parent, arytypestr, extraattr) end definedtype_name = parenttype.child_type(elename) if definedtype_name and (klass = TypeMap[definedtype_name]) return decode_basetype(klass, elename) elsif definedtype_name == XSD::AnyTypeName return decode_tag_by_type(ns, elename, typestr, parent, arytypestr, extraattr) end if definedtype_name typedef = @decode_typemap[definedtype_name] else typedef = parenttype.child_defined_complextype(elename) end decode_definedtype(elename, definedtype_name, typedef, arytypestr) end def decode_definedtype(elename, typename, typedef, arytypestr) unless typedef raise EncodingStyleError.new("unknown type '#{typename}'") end if typedef.is_a?(::WSDL::XMLSchema::SimpleType) decode_defined_simpletype(elename, typename, typedef, arytypestr) else decode_defined_complextype(elename, typename, typedef, arytypestr) end end def decode_basetype(klass, elename) klass.decode(elename) end def decode_defined_simpletype(elename, typename, typedef, arytypestr) o = decode_basetype(TypeMap[typedef.base], elename) o.definedtype = typedef o end def decode_defined_complextype(elename, typename, typedef, arytypestr) case typedef.compoundtype when :TYPE_STRUCT, :TYPE_MAP o = SOAPStruct.decode(elename, typename) o.definedtype = typedef return o when :TYPE_ARRAY expected_arytype = typedef.find_arytype if arytypestr actual_arytype = XSD::QName.new(expected_arytype.namespace, content_typename(expected_arytype.name) << content_ranksize(arytypestr)) o = SOAPArray.decode(elename, typename, actual_arytype) else o = SOAPArray.new(typename, 1, expected_arytype) o.elename = elename end o.definedtype = typedef return o when :TYPE_EMPTY o = SOAPNil.decode(elename) o.definedtype = typedef return o else raise RuntimeError.new( "Unknown kind of complexType: #{typedef.compoundtype}") end nil end def decode_tag_by_type(ns, elename, typestr, parent, arytypestr, extraattr) if arytypestr type = typestr ? ns.parse(typestr) : ValueArrayName node = SOAPArray.decode(elename, type, ns.parse(arytypestr)) node.extraattr.update(extraattr) return node end type = nil if typestr type = ns.parse(typestr) elsif parent.is_a?(SOAPArray) type = parent.arytype else # Since it's in dynamic(without any type) encoding process, # assumes entity as its type itself. # => type Array in SOAP-ENC. # => type Country in foo. type = elename end if (klass = TypeMap[type]) node = decode_basetype(klass, elename) node.extraattr.update(extraattr) return node end # Unknown type... Struct or String SOAPUnknown.new(self, elename, type, extraattr) end def decode_textbuf(node) case node when XSD::XSDHexBinary, XSD::XSDBase64Binary node.set_encoded(@textbuf) when XSD::XSDString if @charset @textbuf = XSD::Charset.encoding_from_xml(@textbuf, @charset) end if node.definedtype node.definedtype.check_lexical_format(@textbuf) end node.set(@textbuf) when SOAPNil # Nothing to do. when SOAPBasetype node.set(@textbuf) else # Nothing to do... end @textbuf = '' end NilLiteralMap = { 'true' => true, '1' => true, 'false' => false, '0' => false } RootLiteralMap = { '1' => 1, '0' => 0 } def decode_attrs(ns, attrs) is_nil = false type = nil arytype = nil root = nil offset = nil position = nil href = nil id = nil extraattr = {} attrs.each do |key, value| qname = ns.parse(key) case qname.namespace when XSD::InstanceNamespace case qname.name when XSD::NilLiteral is_nil = NilLiteralMap[value] or raise EncodingStyleError.new("cannot accept attribute value: #{value} as the value of xsi:#{XSD::NilLiteral} (expected 'true', 'false', '1', or '0')") next when XSD::AttrType type = value next end when EncodingNamespace case qname.name when AttrArrayType arytype = value next when AttrRoot root = RootLiteralMap[value] or raise EncodingStyleError.new( "illegal root attribute value: #{value}") next when AttrOffset offset = value next when AttrPosition position = value next end end if key == 'href' href = value next elsif key == 'id' id = value next end qname = ns.parse_local(key) extraattr[qname] = decode_attr_value(ns, qname, value) end return is_nil, type, arytype, root, offset, position, href, id, extraattr end def decode_attr_value(ns, qname, value) if /\A#/ =~ value o = SOAPReference.decode(nil, value) @refpool << o o else value end end def decode_arypos(position) /^\[(.+)\]$/ =~ position $1.split(',').collect { |s| s.to_i } end def decode_resolve_id count = @refpool.length # To avoid infinite loop while !@refpool.empty? && count > 0 @refpool = @refpool.find_all { |ref| o = @idpool.find { |item| item.id == ref.refid } if o.is_a?(SOAPReference) true # link of link. elsif o ref.__setobj__(o) false elsif o = ref.rootnode.external_content[ref.refid] ref.__setobj__(o) false else raise EncodingStyleError.new("unresolved reference: #{ref.refid}") end } count -= 1 end end end SOAPHandler.new end end ================================================ FILE: lib/soap/generator.rb ================================================ # SOAP4R - SOAP XML Instance Generator library. # Copyright (C) 2001, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/ns' require 'soap/soap' require 'soap/baseData' require 'soap/encodingstyle/handler' module SOAP ### ## CAUTION: MT-unsafe # class SOAPGenerator include SOAP class FormatEncodeError < Error; end public attr_accessor :charset attr_accessor :default_encodingstyle attr_accessor :generate_explicit_type attr_accessor :use_numeric_character_reference def initialize(opt = {}) @reftarget = nil @handlers = {} @charset = opt[:charset] || XSD::Charset.xml_encoding_label @default_encodingstyle = opt[:default_encodingstyle] || EncodingNamespace @generate_explicit_type = opt.key?(:generate_explicit_type) ? opt[:generate_explicit_type] : true @elementformdefault = opt[:elementformdefault] @attributeformdefault = opt[:attributeformdefault] @use_numeric_character_reference = opt[:use_numeric_character_reference] @indentstr = opt[:no_indent] ? '' : ' ' @buf = @indent = @curr = nil end def generate(obj, io = nil) @buf = io || '' @indent = '' prologue @handlers.each do |uri, handler| handler.encode_prologue end ns = XSD::NS.new @buf << xmldecl encode_data(ns, obj, nil) @handlers.each do |uri, handler| handler.encode_epilogue end epilogue @buf end def encode_data(ns, obj, parent) if obj.is_a?(SOAPEnvelopeElement) encode_element(ns, obj, parent) return end if @reftarget && !obj.precedents.empty? add_reftarget(obj.elename.name, obj) ref = SOAPReference.new(obj) ref.elename = ref.elename.dup_name(obj.elename.name) obj.precedents.clear # Avoid cyclic delay. obj.encodingstyle = parent.encodingstyle # SOAPReference is encoded here. obj = ref end encodingstyle = obj.encodingstyle # Children's encodingstyle is derived from its parent. encodingstyle ||= parent.encodingstyle if parent obj.encodingstyle = encodingstyle handler = find_handler(encodingstyle || @default_encodingstyle) unless handler raise FormatEncodeError.new("Unknown encodingStyle: #{ encodingstyle }.") end if !obj.elename.name raise FormatEncodeError.new("Element name not defined: #{ obj }.") end handler.encode_data(self, ns, obj, parent) handler.encode_data_end(self, ns, obj, parent) end def add_reftarget(name, node) unless @reftarget raise FormatEncodeError.new("Reftarget is not defined.") end @reftarget.add(name, node) end def encode_child(ns, child, parent) indent_backup, @indent = @indent, @indent + @indentstr encode_data(ns.clone_ns, child, parent) @indent = indent_backup end def encode_element(ns, obj, parent) attrs = {} if obj.is_a?(SOAPBody) @reftarget = obj obj.encode(self, ns, attrs) do |child| indent_backup, @indent = @indent, @indent + @indentstr encode_data(ns.clone_ns, child, obj) @indent = indent_backup end @reftarget = nil else if obj.is_a?(SOAPEnvelope) # xsi:nil="true" can appear even if dumping without explicit type. SOAPGenerator.assign_ns(attrs, ns, XSD::InstanceNamespace, XSINamespaceTag) if @generate_explicit_type SOAPGenerator.assign_ns(attrs, ns, XSD::Namespace, XSDNamespaceTag) end end obj.encode(self, ns, attrs) do |child| indent_backup, @indent = @indent, @indent + @indentstr encode_data(ns.clone_ns, child, obj) @indent = indent_backup end end end def encode_name(ns, data, attrs) if element_local?(data) data.elename.name else if element_qualified?(data) SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace, '') else SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace) end ns.name(data.elename) end end def encode_name_end(ns, data) if element_local?(data) data.elename.name else ns.name(data.elename) end end def encode_tag(elename, attrs = nil) if !attrs or attrs.empty? @buf << "\n#{ @indent }<#{ elename }>" elsif attrs.size == 1 key, value = attrs.shift @buf << %Q[\n#{ @indent }<#{ elename } #{ key }="#{ value }">] else @buf << "\n#{ @indent }<#{ elename } " << attrs.collect { |key, value| %Q[#{ key }="#{ value }"] }.join("\n#{ @indent }#{ @indentstr * 2 }") << '>' end end def encode_tag_end(elename, cr = nil) if cr @buf << "\n#{ @indent }" else @buf << "" end end def encode_rawstring(str) @buf << str end EncodeMap = { '&' => '&', '<' => '<', '>' => '>', '"' => '"', '\'' => ''', "\r" => ' ' } EncodeCharRegexp = Regexp.new("[#{EncodeMap.keys.join}]") def encode_string(str) if @use_numeric_character_reference and !XSD::Charset.is_us_ascii(str) str.gsub!(EncodeCharRegexp) { |c| EncodeMap[c] } @buf << str.unpack("U*").collect { |c| if c == 0x9 or c == 0xa or c == 0xd or (c >= 0x20 and c <= 0x7f) c.chr else sprintf("&#x%x;", c) end }.join else @buf << str.gsub(EncodeCharRegexp) { |c| EncodeMap[c] } end end def element_local?(element) element.elename.namespace.nil? end def element_qualified?(element) if element.respond_to?(:qualified) if element.qualified.nil? @elementformdefault else element.qualified end else @elementformdefault end end def self.assign_ns(attrs, ns, namespace, tag = nil) if namespace.nil? raise FormatEncodeError.new("empty namespace") end unless ns.assigned?(namespace) tag = ns.assign(namespace, tag) if tag == '' attr = 'xmlns' else attr = "xmlns:#{tag}" end attrs[attr] = namespace end end private def prologue end def epilogue end def find_handler(encodingstyle) unless @handlers.key?(encodingstyle) handler = SOAP::EncodingStyle::Handler.handler(encodingstyle).new(@charset) handler.generate_explicit_type = @generate_explicit_type handler.encode_prologue @handlers[encodingstyle] = handler end @handlers[encodingstyle] end def xmldecl if @charset %Q[] else %Q[] end end end end ================================================ FILE: lib/soap/header/handler.rb ================================================ # SOAP4R - SOAP Header handler item # Copyright (C) 2003, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/element' module SOAP module Header class Handler attr_reader :elename attr_reader :mustunderstand attr_reader :encodingstyle def initialize(elename) @elename = elename @mustunderstand = false @encodingstyle = nil end # Should return a SOAP/OM, a SOAPHeaderItem or nil. def on_outbound nil end # Given header is a SOAPHeaderItem or nil. def on_inbound(header, mustunderstand = false) # do something. end def on_outbound_headeritem item = on_outbound if item.nil? nil elsif item.is_a?(::SOAP::SOAPHeaderItem) item.elename = @elename item else item.elename = @elename ::SOAP::SOAPHeaderItem.new(item, @mustunderstand, @encodingstyle) end end def on_inbound_headeritem(header) on_inbound(header.element, header.mustunderstand) end end end end ================================================ FILE: lib/soap/header/handlerset.rb ================================================ # SOAP4R - SOAP Header handler set # Copyright (C) 2003, 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/namedelements' module SOAP module Header class HandlerSet def initialize @store = XSD::NamedElements.new end def dup obj = HandlerSet.new obj.store = @store.dup obj end def add(handler) @store << handler end alias << add def delete(handler) @store.delete(handler) end def include?(handler) @store.include?(handler) end # returns: Array of SOAPHeaderItem def on_outbound @store.collect { |handler| handler.on_outbound_headeritem }.compact end # headers: SOAPHeaderItem enumerable object def on_inbound(headers) headers.each do |name, item| handler = @store.find { |handler| handler.elename == item.element.elename } if handler handler.on_inbound_headeritem(item) elsif item.mustunderstand raise UnhandledMustUnderstandHeaderError.new(item.element.elename.to_s) end end end protected def store=(store) @store = store end end end end ================================================ FILE: lib/soap/header/simplehandler.rb ================================================ # SOAP4R - SOAP Simple header item handler # Copyright (C) 2003-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/header/handler' require 'soap/baseData' module SOAP module Header class SimpleHandler < SOAP::Header::Handler def initialize(elename) super(elename) end # Should return a Hash, String or nil. def on_simple_outbound nil end # Given header is a Hash, String or nil. def on_simple_inbound(header, mustunderstand) end def on_outbound h = on_simple_outbound h ? SOAPElement.from_obj(h, elename.namespace) : nil end def on_inbound(header, mustunderstand) h = header.respond_to?(:to_obj) ? header.to_obj : header.data on_simple_inbound(h, mustunderstand) end end end end ================================================ FILE: lib/soap/httpconfigloader.rb ================================================ # SOAP4R - HTTP config loader. # Copyright (C) 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/property' module SOAP module HTTPConfigLoader module_function def set_options(client, options) client.proxy = options["proxy"] options.add_hook("proxy") do |key, value| client.proxy = value end client.no_proxy = options["no_proxy"] options.add_hook("no_proxy") do |key, value| client.no_proxy = value end if client.respond_to?(:protocol_version=) client.protocol_version = options["protocol_version"] options.add_hook("protocol_version") do |key, value| client.protocol_version = value end end ssl_config = options["ssl_config"] ||= ::SOAP::Property.new set_ssl_config(client, ssl_config) ssl_config.add_hook(true) do |key, value| set_ssl_config(client, ssl_config) end basic_auth = options["basic_auth"] ||= ::SOAP::Property.new set_basic_auth(client, basic_auth) basic_auth.add_hook do |key, value| set_basic_auth(client, basic_auth) end options.add_hook("connect_timeout") do |key, value| client.connect_timeout = value end options.add_hook("send_timeout") do |key, value| client.send_timeout = value end options.add_hook("receive_timeout") do |key, value| client.receive_timeout = value end end def set_basic_auth(client, basic_auth) basic_auth.values.each do |url, userid, passwd| client.set_basic_auth(url, userid, passwd) end end def set_ssl_config(client, ssl_config) ssl_config.each do |key, value| cfg = client.ssl_config if cfg.nil? raise NotImplementedError.new("SSL not supported") end case key when 'client_cert' cfg.client_cert = cert_from_file(value) when 'client_key' cfg.client_key = key_from_file(value) when 'client_ca' cfg.client_ca = value when 'ca_path' cfg.set_trust_ca(value) when 'ca_file' cfg.set_trust_ca(value) when 'crl' cfg.set_crl(value) when 'verify_mode' cfg.verify_mode = ssl_config_int(value) when 'verify_depth' cfg.verify_depth = ssl_config_int(value) when 'options' cfg.options = value when 'ciphers' cfg.ciphers = value when 'verify_callback' cfg.verify_callback = value when 'cert_store' cfg.cert_store = value else raise ArgumentError.new("unknown ssl_config property #{key}") end end end def ssl_config_int(value) if value.nil? or value.to_s.empty? nil else begin Integer(value) rescue ArgumentError ::SOAP::Property::Util.const_from_name(value.to_s) end end end def cert_from_file(filename) OpenSSL::X509::Certificate.new(File.open(filename) { |f| f.read }) end def key_from_file(filename) OpenSSL::PKey::RSA.new(File.open(filename) { |f| f.read }) end end end ================================================ FILE: lib/soap/mapping/factory.rb ================================================ # SOAP4R - Mapping factory. # Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module SOAP module Mapping class Factory include TraverseSupport def initialize # nothing to do end def obj2soap(soap_class, obj, info, map) raise NotImplementError.new # return soap_obj end def soap2obj(obj_class, node, info, map) raise NotImplementError.new # return convert_succeeded_or_not, obj end def setiv2obj(obj, node, map) return if node.nil? if obj.is_a?(Array) setiv2ary(obj, node, map) else setiv2struct(obj, node, map) end end def setiv2soap(node, obj, map) if obj.class.class_variables.include?('@@schema_element') obj.class.class_eval('@@schema_element').each do |name, info| type, qname = info if qname elename = qname.name else elename = Mapping.name2elename(name) end node.add(elename, Mapping._obj2soap(obj.instance_variable_get('@' + name), map)) end else # should we sort instance_variables? obj.instance_variables.each do |var| name = var.sub(/^@/, '') elename = Mapping.name2elename(name) node.add(elename, Mapping._obj2soap(obj.instance_variable_get(var), map)) end end end private def setiv2ary(obj, node, map) node.each do |name, value| Array.instance_method(:<<).bind(obj).call(Mapping._soap2obj(value, map)) end end def setiv2struct(obj, node, map) vars = {} node.each do |name, value| vars[Mapping.elename2name(name)] = Mapping._soap2obj(value, map) end Mapping.set_attributes(obj, vars) end end class StringFactory_ < Factory def initialize(allow_original_mapping = false) super() @allow_original_mapping = allow_original_mapping end def obj2soap(soap_class, obj, info, map) if !@allow_original_mapping and !obj.instance_variables.empty? return nil end begin unless XSD::Charset.is_ces(obj, Thread.current[:SOAPExternalCES]) return nil end encoded = XSD::Charset.encoding_conv(obj, Thread.current[:SOAPExternalCES], XSD::Charset.encoding) soap_obj = soap_class.new(encoded) rescue XSD::ValueSpaceError return nil end mark_marshalled_obj(obj, soap_obj) soap_obj end def soap2obj(obj_class, node, info, map) obj = Mapping.create_empty_object(obj_class) decoded = XSD::Charset.encoding_conv(node.data, XSD::Charset.encoding, Thread.current[:SOAPExternalCES]) obj.replace(decoded) mark_unmarshalled_obj(node, obj) return true, obj end end class BasetypeFactory_ < Factory def initialize(allow_original_mapping = false) super() @allow_original_mapping = allow_original_mapping end def obj2soap(soap_class, obj, info, map) if !@allow_original_mapping and !obj.instance_variables.empty? return nil end soap_obj = nil begin soap_obj = soap_class.new(obj) rescue XSD::ValueSpaceError return nil end if @allow_original_mapping # Basetype except String should not be multiref-ed in SOAP/1.1. mark_marshalled_obj(obj, soap_obj) end soap_obj end def soap2obj(obj_class, node, info, map) obj = node.data mark_unmarshalled_obj(node, obj) return true, obj end end class DateTimeFactory_ < Factory def initialize(allow_original_mapping = false) super() @allow_original_mapping = allow_original_mapping end def obj2soap(soap_class, obj, info, map) if !@allow_original_mapping and Time === obj and !obj.instance_variables.empty? return nil end soap_obj = nil begin soap_obj = soap_class.new(obj) rescue XSD::ValueSpaceError return nil end mark_marshalled_obj(obj, soap_obj) soap_obj end def soap2obj(obj_class, node, info, map) if node.respond_to?(:to_obj) obj = node.to_obj(obj_class) return false if obj.nil? mark_unmarshalled_obj(node, obj) return true, obj else return false end end end class Base64Factory_ < Factory def obj2soap(soap_class, obj, info, map) return nil unless obj.instance_variables.empty? soap_obj = soap_class.new(obj) mark_marshalled_obj(obj, soap_obj) if soap_obj soap_obj end def soap2obj(obj_class, node, info, map) obj = node.string mark_unmarshalled_obj(node, obj) return true, obj end end class URIFactory_ < Factory def obj2soap(soap_class, obj, info, map) soap_obj = soap_class.new(obj) mark_marshalled_obj(obj, soap_obj) if soap_obj soap_obj end def soap2obj(obj_class, node, info, map) obj = node.data mark_unmarshalled_obj(node, obj) return true, obj end end class ArrayFactory_ < Factory def initialize(allow_original_mapping = false) super() @allow_original_mapping = allow_original_mapping end # [[1], [2]] is converted to Array of Array, not 2-D Array. # To create M-D Array, you must call Mapping.ary2md. def obj2soap(soap_class, obj, info, map) if !@allow_original_mapping and !obj.instance_variables.empty? return nil end arytype = Mapping.obj2element(obj) if arytype.name arytype.namespace ||= RubyTypeNamespace else arytype = XSD::AnyTypeName end soap_obj = SOAPArray.new(ValueArrayName, 1, arytype) mark_marshalled_obj(obj, soap_obj) obj.each do |item| soap_obj.add(Mapping._obj2soap(item, map)) end soap_obj end def soap2obj(obj_class, node, info, map) obj = Mapping.create_empty_object(obj_class) mark_unmarshalled_obj(node, obj) node.soap2array(obj) do |elem| elem ? Mapping._soap2obj(elem, map) : nil end return true, obj end end class TypedArrayFactory_ < Factory def initialize(allow_original_mapping = false) super() @allow_original_mapping = allow_original_mapping end def obj2soap(soap_class, obj, info, map) if !@allow_original_mapping and !obj.instance_variables.empty? return nil end arytype = info[:type] || info[0] soap_obj = SOAPArray.new(ValueArrayName, 1, arytype) mark_marshalled_obj(obj, soap_obj) obj.each do |var| soap_obj.add(Mapping._obj2soap(var, map)) end soap_obj end def soap2obj(obj_class, node, info, map) if node.rank > 1 return false end arytype = info[:type] || info[0] unless node.arytype == arytype return false end obj = Mapping.create_empty_object(obj_class) mark_unmarshalled_obj(node, obj) node.soap2array(obj) do |elem| elem ? Mapping._soap2obj(elem, map) : nil end return true, obj end end class TypedStructFactory_ < Factory def obj2soap(soap_class, obj, info, map) type = info[:type] || info[0] soap_obj = soap_class.new(type) mark_marshalled_obj(obj, soap_obj) if obj.class <= SOAP::Marshallable setiv2soap(soap_obj, obj, map) else setiv2soap(soap_obj, obj, map) end soap_obj end def soap2obj(obj_class, node, info, map) type = info[:type] || info[0] unless node.type == type return false end obj = Mapping.create_empty_object(obj_class) mark_unmarshalled_obj(node, obj) setiv2obj(obj, node, map) return true, obj end end MapQName = XSD::QName.new(ApacheSOAPTypeNamespace, 'Map') class HashFactory_ < Factory def initialize(allow_original_mapping = false) super() @allow_original_mapping = allow_original_mapping end def obj2soap(soap_class, obj, info, map) if !@allow_original_mapping and !obj.instance_variables.empty? return nil end if !obj.default.nil? or (obj.respond_to?(:default_proc) and obj.default_proc) return nil end soap_obj = SOAPStruct.new(MapQName) mark_marshalled_obj(obj, soap_obj) obj.each do |key, value| elem = SOAPStruct.new elem.add("key", Mapping._obj2soap(key, map)) elem.add("value", Mapping._obj2soap(value, map)) # ApacheAxis allows only 'item' here. soap_obj.add("item", elem) end soap_obj end def soap2obj(obj_class, node, info, map) unless node.type == MapQName return false end if node.class == SOAPStruct and node.key?('default') return false end obj = Mapping.create_empty_object(obj_class) mark_unmarshalled_obj(node, obj) if node.class == SOAPStruct node.each do |key, value| obj[Mapping._soap2obj(value['key'], map)] = Mapping._soap2obj(value['value'], map) end else node.each do |value| obj[Mapping._soap2obj(value['key'], map)] = Mapping._soap2obj(value['value'], map) end end return true, obj end end end end ================================================ FILE: lib/soap/mapping/mapping.rb ================================================ # SOAP4R - Ruby type mapping utility. # Copyright (C) 2000, 2001, 2003-2005 NAKAMURA Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/codegen/gensupport' module SOAP module Mapping RubyTypeNamespace = 'http://www.ruby-lang.org/xmlns/ruby/type/1.6' RubyTypeInstanceNamespace = 'http://www.ruby-lang.org/xmlns/ruby/type-instance' RubyCustomTypeNamespace = 'http://www.ruby-lang.org/xmlns/ruby/type/custom' ApacheSOAPTypeNamespace = 'http://xml.apache.org/xml-soap' # TraverseSupport breaks following thread variables. # Thread.current[:SOAPMarshalDataKey] module TraverseSupport def mark_marshalled_obj(obj, soap_obj) raise if obj.nil? Thread.current[:SOAPMarshalDataKey][obj.__id__] = soap_obj end def mark_unmarshalled_obj(node, obj) return if obj.nil? # node.id is not Object#id but SOAPReference#id Thread.current[:SOAPMarshalDataKey][node.id] = obj end end EMPTY_OPT = {} def self.obj2soap(obj, registry = nil, type = nil, opt = EMPTY_OPT) registry ||= Mapping::DefaultRegistry soap_obj = nil protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do Thread.current[:SOAPMarshalDataKey] = {} Thread.current[:SOAPExternalCES] = opt[:external_ces] || $KCODE Thread.current[:SOAPMarshalNoReference] = opt[:no_reference] soap_obj = _obj2soap(obj, registry, type) end soap_obj end def self.soap2obj(node, registry = nil, klass = nil, opt = EMPTY_OPT) registry ||= Mapping::DefaultRegistry obj = nil protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do Thread.current[:SOAPMarshalDataKey] = {} Thread.current[:SOAPExternalCES] = opt[:external_ces] || $KCODE Thread.current[:SOAPMarshalNoReference] = opt[:no_reference] obj = _soap2obj(node, registry, klass) end obj end def self.ary2soap(ary, type_ns = XSD::Namespace, typename = XSD::AnyTypeLiteral, registry = nil, opt = EMPTY_OPT) registry ||= Mapping::DefaultRegistry type = XSD::QName.new(type_ns, typename) soap_ary = SOAPArray.new(ValueArrayName, 1, type) protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do Thread.current[:SOAPMarshalDataKey] = {} Thread.current[:SOAPExternalCES] = opt[:external_ces] || $KCODE Thread.current[:SOAPMarshalNoReference] = opt[:no_reference] ary.each do |ele| soap_ary.add(_obj2soap(ele, registry, type)) end end soap_ary end def self.ary2md(ary, rank, type_ns = XSD::Namespace, typename = XSD::AnyTypeLiteral, registry = nil, opt = EMPTY_OPT) registry ||= Mapping::DefaultRegistry type = XSD::QName.new(type_ns, typename) md_ary = SOAPArray.new(ValueArrayName, rank, type) protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do Thread.current[:SOAPMarshalDataKey] = {} Thread.current[:SOAPExternalCES] = opt[:external_ces] || $KCODE Thread.current[:SOAPMarshalNoReference] = opt[:no_reference] add_md_ary(md_ary, ary, [], registry) end md_ary end def self.fault2exception(fault, registry = nil) registry ||= Mapping::DefaultRegistry detail = if fault.detail soap2obj(fault.detail, registry) || "" else "" end if detail.is_a?(Mapping::SOAPException) begin e = detail.to_e remote_backtrace = e.backtrace e.set_backtrace(nil) raise e # ruby sets current caller as local backtrace of e => e2. rescue Exception => e e.set_backtrace(remote_backtrace + e.backtrace[1..-1]) raise end else fault.detail = detail fault.set_backtrace( if detail.is_a?(Array) detail else [detail.to_s] end ) raise end end def self._obj2soap(obj, registry, type = nil) if referent = Thread.current[:SOAPMarshalDataKey][obj.__id__] and !Thread.current[:SOAPMarshalNoReference] SOAPReference.new(referent) elsif registry registry.obj2soap(obj, type) else raise MappingError.new("no mapping registry given") end end def self._soap2obj(node, registry, klass = nil) if node.nil? return nil elsif node.is_a?(SOAPReference) target = node.__getobj__ # target.id is not Object#id but SOAPReference#id if referent = Thread.current[:SOAPMarshalDataKey][target.id] and !Thread.current[:SOAPMarshalNoReference] return referent else return _soap2obj(target, registry, klass) end end return registry.soap2obj(node, klass) end if Object.respond_to?(:allocate) # ruby/1.7 or later. def self.create_empty_object(klass) klass.allocate end else MARSHAL_TAG = { String => ['"', 1], Regexp => ['/', 2], Array => ['[', 1], Hash => ['{', 1] } def self.create_empty_object(klass) if klass <= Struct name = klass.name return ::Marshal.load(sprintf("\004\006S:%c%s\000", name.length + 5, name)) end if MARSHAL_TAG.has_key?(klass) tag, terminate = MARSHAL_TAG[klass] return ::Marshal.load(sprintf("\004\006%s%s", tag, "\000" * terminate)) end MARSHAL_TAG.each do |k, v| if klass < k name = klass.name tag, terminate = v return ::Marshal.load(sprintf("\004\006C:%c%s%s%s", name.length + 5, name, tag, "\000" * terminate)) end end name = klass.name ::Marshal.load(sprintf("\004\006o:%c%s\000", name.length + 5, name)) end end # Allow only (Letter | '_') (Letter | Digit | '-' | '_')* here. # Caution: '.' is not allowed here. # To follow XML spec., it should be NCName. # (denied chars) => .[0-F][0-F] # ex. a.b => a.2eb # def self.name2elename(name) name.gsub(/([^a-zA-Z0-9:_\-]+)/n) { '.' << $1.unpack('H2' * $1.size).join('.') }.gsub(/::/n, '..') end def self.elename2name(name) name.gsub(/\.\./n, '::').gsub(/((?:\.[0-9a-fA-F]{2})+)/n) { [$1.delete('.')].pack('H*') } end def self.const_from_name(name, lenient = false) const = ::Object name.sub(/\A::/, '').split('::').each do |const_str| if XSD::CodeGen::GenSupport.safeconstname?(const_str) if const.const_defined?(const_str) const = const.const_get(const_str) next end elsif lenient const_str = XSD::CodeGen::GenSupport.safeconstname(const_str) if const.const_defined?(const_str) const = const.const_get(const_str) next end end return nil end const end def self.class_from_name(name, lenient = false) const = const_from_name(name, lenient) if const.is_a?(::Class) const else nil end end def self.module_from_name(name, lenient = false) const = const_from_name(name, lenient) if const.is_a?(::Module) const else nil end end def self.class2qname(klass) name = schema_type_definition(klass) namespace = schema_ns_definition(klass) XSD::QName.new(namespace, name) end def self.class2element(klass) type = Mapping.class2qname(klass) type.name ||= Mapping.name2elename(klass.name) type.namespace ||= RubyCustomTypeNamespace type end def self.obj2element(obj) name = namespace = nil ivars = obj.instance_variables if ivars.include?('@schema_type') name = obj.instance_variable_get('@schema_type') end if ivars.include?('@schema_ns') namespace = obj.instance_variable_get('@schema_ns') end if !name or !namespace class2qname(obj.class) else XSD::QName.new(namespace, name) end end def self.define_singleton_method(obj, name, &block) sclass = (class << obj; self; end) sclass.class_eval { define_method(name, &block) } end def self.get_attribute(obj, attr_name) if obj.is_a?(::Hash) obj[attr_name] || obj[attr_name.intern] else name = XSD::CodeGen::GenSupport.safevarname(attr_name) if obj.instance_variables.include?('@' + name) obj.instance_variable_get('@' + name) elsif ((obj.is_a?(::Struct) or obj.is_a?(Marshallable)) and obj.respond_to?(name)) obj.__send__(name) end end end def self.set_attributes(obj, values) if obj.is_a?(::SOAP::Mapping::Object) values.each do |attr_name, value| obj.__add_xmlele_value(attr_name, value) end else values.each do |attr_name, value| name = XSD::CodeGen::GenSupport.safevarname(attr_name) setter = name + "=" if obj.respond_to?(setter) obj.__send__(setter, value) else obj.instance_variable_set('@' + name, value) begin define_attr_accessor(obj, name, proc { instance_variable_get('@' + name) }, proc { |value| instance_variable_set('@' + name, value) }) rescue TypeError # singleton class may not exist (e.g. Float) end end end end end def self.define_attr_accessor(obj, name, getterproc, setterproc = nil) define_singleton_method(obj, name, &getterproc) define_singleton_method(obj, name + '=', &setterproc) if setterproc end def self.schema_type_definition(klass) class_schema_variable(:schema_type, klass) end def self.schema_ns_definition(klass) class_schema_variable(:schema_ns, klass) end def self.schema_element_definition(klass) schema_element = class_schema_variable(:schema_element, klass) or return nil schema_ns = schema_ns_definition(klass) elements = [] as_array = [] schema_element.each do |varname, definition| class_name, name = definition if /\[\]$/ =~ class_name class_name = class_name.sub(/\[\]$/, '') as_array << (name ? name.name : varname) end elements << [name || XSD::QName.new(schema_ns, varname), class_name] end [elements, as_array] end def self.schema_attribute_definition(klass) class_schema_variable(:schema_attribute, klass) end class << Mapping private def class_schema_variable(sym, klass) var = "@@#{sym}" klass.class_variables.include?(var) ? klass.class_eval(var) : nil end def protect_threadvars(*symbols) backup = {} begin symbols.each do |sym| backup[sym] = Thread.current[sym] end yield ensure symbols.each do |sym| Thread.current[sym] = backup[sym] end end end def add_md_ary(md_ary, ary, indices, registry) for idx in 0..(ary.size - 1) if ary[idx].is_a?(Array) add_md_ary(md_ary, ary[idx], indices + [idx], registry) else md_ary[*(indices + [idx])] = _obj2soap(ary[idx], registry) end end end end end end ================================================ FILE: lib/soap/mapping/registry.rb ================================================ # SOAP4R - Mapping registry. # Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/baseData' require 'soap/mapping/mapping' require 'soap/mapping/typeMap' require 'soap/mapping/factory' require 'soap/mapping/rubytypeFactory' module SOAP module Marshallable # @@type_ns = Mapping::RubyCustomTypeNamespace end module Mapping module MappedException; end RubyTypeName = XSD::QName.new(RubyTypeInstanceNamespace, 'rubyType') RubyExtendName = XSD::QName.new(RubyTypeInstanceNamespace, 'extends') RubyIVarName = XSD::QName.new(RubyTypeInstanceNamespace, 'ivars') # Inner class to pass an exception. class SOAPException; include Marshallable attr_reader :excn_type_name, :cause def initialize(e) @excn_type_name = Mapping.name2elename(e.class.to_s) @cause = e end def to_e if @cause.is_a?(::Exception) @cause.extend(::SOAP::Mapping::MappedException) return @cause elsif @cause.respond_to?(:message) and @cause.respond_to?(:backtrace) e = RuntimeError.new(@cause.message) e.set_backtrace(@cause.backtrace) return e end klass = Mapping.class_from_name(Mapping.elename2name(@excn_type_name.to_s)) if klass.nil? or not klass <= ::Exception return RuntimeError.new(@cause.inspect) end obj = klass.new(@cause.message) obj.extend(::SOAP::Mapping::MappedException) obj end end # For anyType object: SOAP::Mapping::Object not ::Object class Object; include Marshallable def initialize @__xmlele_type = {} @__xmlele = [] @__xmlattr = {} end def inspect sprintf("#<%s:0x%x%s>", self.class.name, __id__, @__xmlele.collect { |name, value| " #{name}=#{value.inspect}" }.join) end def __xmlattr @__xmlattr end def __xmlele @__xmlele end def [](qname) unless qname.is_a?(XSD::QName) qname = XSD::QName.new(nil, qname) end @__xmlele.each do |k, v| return v if k == qname end # fallback @__xmlele.each do |k, v| return v if k.name == qname.name end nil end def []=(qname, value) unless qname.is_a?(XSD::QName) qname = XSD::QName.new(nil, qname) end found = false @__xmlele.each do |pair| if pair[0] == qname found = true pair[1] = value end end unless found __define_attr_accessor(qname) @__xmlele << [qname, value] end @__xmlele_type[qname] = :single end def __add_xmlele_value(qname, value) found = false @__xmlele.map! do |k, v| if k == qname found = true [k, __set_xmlele_value(k, v, value)] else [k, v] end end unless found __define_attr_accessor(qname) @__xmlele << [qname, value] @__xmlele_type[qname] = :single end value end private if RUBY_VERSION > "1.7.0" def __define_attr_accessor(qname) name = XSD::CodeGen::GenSupport.safemethodname(qname.name) Mapping.define_attr_accessor(self, name, proc { self[qname] }, proc { |value| self[qname] = value }) end else def __define_attr_accessor(qname) name = XSD::CodeGen::GenSupport.safemethodname(qname.name) instance_eval <<-EOS def #{name} self[#{qname.dump}] end def #{name}=(value) self[#{qname.dump}] = value end EOS end end def __set_xmlele_value(key, org, value) case @__xmlele_type[key] when :multi org << value org when :single @__xmlele_type[key] = :multi [org, value] else raise RuntimeError.new("unknown type") end end end class MappingError < Error; end class Registry class Map def initialize(registry) @obj2soap = {} @soap2obj = {} @registry = registry end def obj2soap(obj) klass = obj.class if map = @obj2soap[klass] map.each do |soap_class, factory, info| ret = factory.obj2soap(soap_class, obj, info, @registry) return ret if ret end end ancestors = klass.ancestors ancestors.delete(klass) ancestors.delete(::Object) ancestors.delete(::Kernel) ancestors.each do |klass| if map = @obj2soap[klass] map.each do |soap_class, factory, info| if info[:derived_class] ret = factory.obj2soap(soap_class, obj, info, @registry) return ret if ret end end end end nil end def soap2obj(node, klass = nil) if map = @soap2obj[node.class] map.each do |obj_class, factory, info| next if klass and obj_class != klass conv, obj = factory.soap2obj(obj_class, node, info, @registry) return true, obj if conv end end return false, nil end # Give priority to former entry. def init(init_map = []) clear init_map.reverse_each do |obj_class, soap_class, factory, info| add(obj_class, soap_class, factory, info) end end # Give priority to latter entry. def add(obj_class, soap_class, factory, info) info ||= {} (@obj2soap[obj_class] ||= []).unshift([soap_class, factory, info]) (@soap2obj[soap_class] ||= []).unshift([obj_class, factory, info]) end def clear @obj2soap.clear @soap2obj.clear end def find_mapped_soap_class(target_obj_class) map = @obj2soap[target_obj_class] map.empty? ? nil : map[0][1] end def find_mapped_obj_class(target_soap_class) map = @soap2obj[target_soap_class] map.empty? ? nil : map[0][0] end end StringFactory = StringFactory_.new BasetypeFactory = BasetypeFactory_.new DateTimeFactory = DateTimeFactory_.new ArrayFactory = ArrayFactory_.new Base64Factory = Base64Factory_.new URIFactory = URIFactory_.new TypedArrayFactory = TypedArrayFactory_.new TypedStructFactory = TypedStructFactory_.new HashFactory = HashFactory_.new SOAPBaseMap = [ [::NilClass, ::SOAP::SOAPNil, BasetypeFactory], [::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory], [::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory], [::String, ::SOAP::SOAPString, StringFactory], [::DateTime, ::SOAP::SOAPDateTime, DateTimeFactory], [::Date, ::SOAP::SOAPDate, DateTimeFactory], [::Time, ::SOAP::SOAPDateTime, DateTimeFactory], [::Time, ::SOAP::SOAPTime, DateTimeFactory], [::Float, ::SOAP::SOAPDouble, BasetypeFactory, {:derived_class => true}], [::Float, ::SOAP::SOAPFloat, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPInt, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPLong, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPShort, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPByte, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPNonPositiveInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPNegativeInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPNonNegativeInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPPositiveInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPUnsignedLong, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPUnsignedInt, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPUnsignedShort, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPUnsignedByte, BasetypeFactory, {:derived_class => true}], [::URI::Generic, ::SOAP::SOAPAnyURI, URIFactory, {:derived_class => true}], [::String, ::SOAP::SOAPBase64, Base64Factory], [::String, ::SOAP::SOAPHexBinary, Base64Factory], [::String, ::SOAP::SOAPDecimal, BasetypeFactory], [::String, ::SOAP::SOAPDuration, BasetypeFactory], [::String, ::SOAP::SOAPGYearMonth, BasetypeFactory], [::String, ::SOAP::SOAPGYear, BasetypeFactory], [::String, ::SOAP::SOAPGMonthDay, BasetypeFactory], [::String, ::SOAP::SOAPGDay, BasetypeFactory], [::String, ::SOAP::SOAPGMonth, BasetypeFactory], [::String, ::SOAP::SOAPQName, BasetypeFactory], [::Hash, ::SOAP::SOAPArray, HashFactory], [::Hash, ::SOAP::SOAPStruct, HashFactory], [::Array, ::SOAP::SOAPArray, ArrayFactory, {:derived_class => true}], [::SOAP::Mapping::SOAPException, ::SOAP::SOAPStruct, TypedStructFactory, {:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}], ] RubyOriginalMap = [ [::NilClass, ::SOAP::SOAPNil, BasetypeFactory], [::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory], [::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory], [::String, ::SOAP::SOAPString, StringFactory], [::DateTime, ::SOAP::SOAPDateTime, DateTimeFactory], [::Date, ::SOAP::SOAPDate, DateTimeFactory], [::Time, ::SOAP::SOAPDateTime, DateTimeFactory], [::Time, ::SOAP::SOAPTime, DateTimeFactory], [::Float, ::SOAP::SOAPDouble, BasetypeFactory, {:derived_class => true}], [::Float, ::SOAP::SOAPFloat, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPInt, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPLong, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPShort, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPByte, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPNonPositiveInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPNegativeInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPNonNegativeInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPPositiveInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPUnsignedLong, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPUnsignedInt, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPUnsignedShort, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPUnsignedByte, BasetypeFactory, {:derived_class => true}], [::URI::Generic, ::SOAP::SOAPAnyURI, URIFactory, {:derived_class => true}], [::String, ::SOAP::SOAPBase64, Base64Factory], [::String, ::SOAP::SOAPHexBinary, Base64Factory], [::String, ::SOAP::SOAPDecimal, BasetypeFactory], [::String, ::SOAP::SOAPDuration, BasetypeFactory], [::String, ::SOAP::SOAPGYearMonth, BasetypeFactory], [::String, ::SOAP::SOAPGYear, BasetypeFactory], [::String, ::SOAP::SOAPGMonthDay, BasetypeFactory], [::String, ::SOAP::SOAPGDay, BasetypeFactory], [::String, ::SOAP::SOAPGMonth, BasetypeFactory], [::String, ::SOAP::SOAPQName, BasetypeFactory], [::Hash, ::SOAP::SOAPArray, HashFactory], [::Hash, ::SOAP::SOAPStruct, HashFactory], # Does not allow Array's subclass here. [::Array, ::SOAP::SOAPArray, ArrayFactory], [::SOAP::Mapping::SOAPException, ::SOAP::SOAPStruct, TypedStructFactory, {:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}], ] attr_accessor :default_factory attr_accessor :excn_handler_obj2soap attr_accessor :excn_handler_soap2obj def initialize(config = {}) @config = config @map = Map.new(self) if @config[:allow_original_mapping] @allow_original_mapping = true @map.init(RubyOriginalMap) else @allow_original_mapping = false @map.init(SOAPBaseMap) end @allow_untyped_struct = @config.key?(:allow_untyped_struct) ? @config[:allow_untyped_struct] : true @rubytype_factory = RubytypeFactory.new( :allow_untyped_struct => @allow_untyped_struct, :allow_original_mapping => @allow_original_mapping ) @default_factory = @rubytype_factory @excn_handler_obj2soap = nil @excn_handler_soap2obj = nil end def add(obj_class, soap_class, factory, info = nil) @map.add(obj_class, soap_class, factory, info) end alias set add # general Registry ignores type_qname def obj2soap(obj, type_qname = nil) soap = _obj2soap(obj) if @allow_original_mapping addextend2soap(soap, obj) end soap end def soap2obj(node, klass = nil) obj = _soap2obj(node, klass) if @allow_original_mapping addextend2obj(obj, node.extraattr[RubyExtendName]) addiv2obj(obj, node.extraattr[RubyIVarName]) end obj end def find_mapped_soap_class(obj_class) @map.find_mapped_soap_class(obj_class) end def find_mapped_obj_class(soap_class) @map.find_mapped_obj_class(soap_class) end private def _obj2soap(obj) ret = nil if obj.is_a?(SOAPStruct) or obj.is_a?(SOAPArray) obj.replace do |ele| Mapping._obj2soap(ele, self) end return obj elsif obj.is_a?(SOAPBasetype) return obj end begin ret = @map.obj2soap(obj) || @default_factory.obj2soap(nil, obj, nil, self) return ret if ret rescue MappingError end if @excn_handler_obj2soap ret = @excn_handler_obj2soap.call(obj) { |yield_obj| Mapping._obj2soap(yield_obj, self) } return ret if ret end raise MappingError.new("Cannot map #{ obj.class.name } to SOAP/OM.") end # Might return nil as a mapping result. def _soap2obj(node, klass = nil) if node.extraattr.key?(RubyTypeName) conv, obj = @rubytype_factory.soap2obj(nil, node, nil, self) return obj if conv else conv, obj = @map.soap2obj(node, klass) return obj if conv conv, obj = @default_factory.soap2obj(nil, node, nil, self) return obj if conv end if @excn_handler_soap2obj begin return @excn_handler_soap2obj.call(node) { |yield_node| Mapping._soap2obj(yield_node, self) } rescue Exception end end raise MappingError.new("Cannot map #{ node.type.name } to Ruby object.") end def addiv2obj(obj, attr) return unless attr vars = {} attr.__getobj__.each do |name, value| vars[name] = Mapping._soap2obj(value, self) end Mapping.set_attributes(obj, vars) end if RUBY_VERSION >= '1.8.0' def addextend2obj(obj, attr) return unless attr attr.split(/ /).reverse_each do |mstr| obj.extend(Mapping.module_from_name(mstr)) end end else # (class < false; self; end).ancestors includes "TrueClass" under 1.6... def addextend2obj(obj, attr) return unless attr attr.split(/ /).reverse_each do |mstr| m = Mapping.module_from_name(mstr) obj.extend(m) end end end def addextend2soap(node, obj) return if obj.is_a?(Symbol) or obj.is_a?(Fixnum) list = (class << obj; self; end).ancestors - obj.class.ancestors unless list.empty? node.extraattr[RubyExtendName] = list.collect { |c| if c.name.empty? raise TypeError.new("singleton can't be dumped #{ obj }") end c.name }.join(" ") end end end DefaultRegistry = Registry.new RubyOriginalRegistry = Registry.new(:allow_original_mapping => true) end end ================================================ FILE: lib/soap/mapping/rubytypeFactory.rb ================================================ # SOAP4R - Ruby type mapping factory. # Copyright (C) 2000-2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module SOAP module Mapping class RubytypeFactory < Factory TYPE_STRING = XSD::QName.new(RubyTypeNamespace, 'String') TYPE_TIME = XSD::QName.new(RubyTypeNamespace, 'Time') TYPE_ARRAY = XSD::QName.new(RubyTypeNamespace, 'Array') TYPE_REGEXP = XSD::QName.new(RubyTypeNamespace, 'Regexp') TYPE_RANGE = XSD::QName.new(RubyTypeNamespace, 'Range') TYPE_CLASS = XSD::QName.new(RubyTypeNamespace, 'Class') TYPE_MODULE = XSD::QName.new(RubyTypeNamespace, 'Module') TYPE_SYMBOL = XSD::QName.new(RubyTypeNamespace, 'Symbol') TYPE_STRUCT = XSD::QName.new(RubyTypeNamespace, 'Struct') TYPE_HASH = XSD::QName.new(RubyTypeNamespace, 'Map') def initialize(config = {}) @config = config @allow_untyped_struct = @config.key?(:allow_untyped_struct) ? @config[:allow_untyped_struct] : true @allow_original_mapping = @config.key?(:allow_original_mapping) ? @config[:allow_original_mapping] : false @string_factory = StringFactory_.new(true) @basetype_factory = BasetypeFactory_.new(true) @datetime_factory = DateTimeFactory_.new(true) @array_factory = ArrayFactory_.new(true) @hash_factory = HashFactory_.new(true) end def obj2soap(soap_class, obj, info, map) param = nil case obj when ::String unless @allow_original_mapping return nil end param = @string_factory.obj2soap(SOAPString, obj, info, map) if obj.class != String param.extraattr[RubyTypeName] = obj.class.name end addiv2soapattr(param, obj, map) when ::Time unless @allow_original_mapping return nil end param = @datetime_factory.obj2soap(SOAPDateTime, obj, info, map) if obj.class != Time param.extraattr[RubyTypeName] = obj.class.name end addiv2soapattr(param, obj, map) when ::Array unless @allow_original_mapping return nil end param = @array_factory.obj2soap(nil, obj, info, map) if obj.class != Array param.extraattr[RubyTypeName] = obj.class.name end addiv2soapattr(param, obj, map) when ::NilClass unless @allow_original_mapping return nil end param = @basetype_factory.obj2soap(SOAPNil, obj, info, map) addiv2soapattr(param, obj, map) when ::FalseClass, ::TrueClass unless @allow_original_mapping return nil end param = @basetype_factory.obj2soap(SOAPBoolean, obj, info, map) addiv2soapattr(param, obj, map) when ::Integer unless @allow_original_mapping return nil end param = @basetype_factory.obj2soap(SOAPInt, obj, info, map) param ||= @basetype_factory.obj2soap(SOAPInteger, obj, info, map) param ||= @basetype_factory.obj2soap(SOAPDecimal, obj, info, map) addiv2soapattr(param, obj, map) when ::Float unless @allow_original_mapping return nil end param = @basetype_factory.obj2soap(SOAPDouble, obj, info, map) if obj.class != Float param.extraattr[RubyTypeName] = obj.class.name end addiv2soapattr(param, obj, map) when ::Hash unless @allow_original_mapping return nil end if obj.respond_to?(:default_proc) && obj.default_proc raise TypeError.new("cannot dump hash with default proc") end param = SOAPStruct.new(TYPE_HASH) mark_marshalled_obj(obj, param) if obj.class != Hash param.extraattr[RubyTypeName] = obj.class.name end obj.each do |key, value| elem = SOAPStruct.new # Undefined type. elem.add("key", Mapping._obj2soap(key, map)) elem.add("value", Mapping._obj2soap(value, map)) param.add("item", elem) end param.add('default', Mapping._obj2soap(obj.default, map)) addiv2soapattr(param, obj, map) when ::Regexp unless @allow_original_mapping return nil end param = SOAPStruct.new(TYPE_REGEXP) mark_marshalled_obj(obj, param) if obj.class != Regexp param.extraattr[RubyTypeName] = obj.class.name end param.add('source', SOAPBase64.new(obj.source)) if obj.respond_to?('options') # Regexp#options is from Ruby/1.7 options = obj.options else options = 0 obj.inspect.sub(/^.*\//, '').each_byte do |c| options += case c when ?i 1 when ?x 2 when ?m 4 when ?n 16 when ?e 32 when ?s 48 when ?u 64 end end end param.add('options', SOAPInt.new(options)) addiv2soapattr(param, obj, map) when ::Range unless @allow_original_mapping return nil end param = SOAPStruct.new(TYPE_RANGE) mark_marshalled_obj(obj, param) if obj.class != Range param.extraattr[RubyTypeName] = obj.class.name end param.add('begin', Mapping._obj2soap(obj.begin, map)) param.add('end', Mapping._obj2soap(obj.end, map)) param.add('exclude_end', SOAP::SOAPBoolean.new(obj.exclude_end?)) addiv2soapattr(param, obj, map) when ::Class unless @allow_original_mapping return nil end if obj.to_s[0] == ?# raise TypeError.new("can't dump anonymous class #{obj}") end param = SOAPStruct.new(TYPE_CLASS) mark_marshalled_obj(obj, param) param.add('name', SOAPString.new(obj.name)) addiv2soapattr(param, obj, map) when ::Module unless @allow_original_mapping return nil end if obj.to_s[0] == ?# raise TypeError.new("can't dump anonymous module #{obj}") end param = SOAPStruct.new(TYPE_MODULE) mark_marshalled_obj(obj, param) param.add('name', SOAPString.new(obj.name)) addiv2soapattr(param, obj, map) when ::Symbol unless @allow_original_mapping return nil end param = SOAPStruct.new(TYPE_SYMBOL) mark_marshalled_obj(obj, param) param.add('id', SOAPString.new(obj.id2name)) addiv2soapattr(param, obj, map) when ::Struct unless @allow_original_mapping # treat it as an user defined class. [ruby-talk:104980] #param = unknownobj2soap(soap_class, obj, info, map) param = SOAPStruct.new(XSD::AnyTypeName) mark_marshalled_obj(obj, param) obj.members.each do |member| param.add(Mapping.name2elename(member), Mapping._obj2soap(obj[member], map)) end else param = SOAPStruct.new(TYPE_STRUCT) mark_marshalled_obj(obj, param) param.add('type', ele_type = SOAPString.new(obj.class.to_s)) ele_member = SOAPStruct.new obj.members.each do |member| ele_member.add(Mapping.name2elename(member), Mapping._obj2soap(obj[member], map)) end param.add('member', ele_member) addiv2soapattr(param, obj, map) end when ::IO, ::Binding, ::Continuation, ::Data, ::Dir, ::File::Stat, ::MatchData, Method, ::Proc, ::Thread, ::ThreadGroup # from 1.8: Process::Status, UnboundMethod return nil when ::SOAP::Mapping::Object param = SOAPStruct.new(XSD::AnyTypeName) mark_marshalled_obj(obj, param) obj.__xmlele.each do |key, value| param.add(key.name, Mapping._obj2soap(value, map)) end obj.__xmlattr.each do |key, value| param.extraattr[key] = value end when ::Exception typestr = Mapping.name2elename(obj.class.to_s) param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, typestr)) mark_marshalled_obj(obj, param) param.add('message', Mapping._obj2soap(obj.message, map)) param.add('backtrace', Mapping._obj2soap(obj.backtrace, map)) addiv2soapattr(param, obj, map) else param = unknownobj2soap(soap_class, obj, info, map) end param end def soap2obj(obj_class, node, info, map) rubytype = node.extraattr[RubyTypeName] if rubytype or node.type.namespace == RubyTypeNamespace rubytype2obj(node, info, map, rubytype) elsif node.type == XSD::AnyTypeName or node.type == XSD::AnySimpleTypeName anytype2obj(node, info, map) else unknowntype2obj(node, info, map) end end private def addiv2soapattr(node, obj, map) return if obj.instance_variables.empty? ivars = SOAPStruct.new # Undefined type. setiv2soap(ivars, obj, map) node.extraattr[RubyIVarName] = ivars end def unknownobj2soap(soap_class, obj, info, map) if obj.class.name.empty? raise TypeError.new("can't dump anonymous class #{obj}") end singleton_class = class << obj; self; end if !singleton_methods_true(obj).empty? or !singleton_class.instance_variables.empty? raise TypeError.new("singleton can't be dumped #{obj}") end if !(singleton_class.ancestors - obj.class.ancestors).empty? typestr = Mapping.name2elename(obj.class.to_s) type = XSD::QName.new(RubyTypeNamespace, typestr) else type = Mapping.class2element(obj.class) end param = SOAPStruct.new(type) mark_marshalled_obj(obj, param) setiv2soap(param, obj, map) param end if RUBY_VERSION >= '1.8.0' def singleton_methods_true(obj) obj.singleton_methods(true) end else def singleton_methods_true(obj) obj.singleton_methods end end def rubytype2obj(node, info, map, rubytype) klass = rubytype ? Mapping.class_from_name(rubytype) : nil obj = nil case node when SOAPString return @string_factory.soap2obj(klass || String, node, info, map) when SOAPDateTime #return @datetime_factory.soap2obj(klass || Time, node, info, map) klass ||= Time t = node.to_time arg = [t.year, t.month, t.mday, t.hour, t.min, t.sec, t.usec] obj = t.gmt? ? klass.gm(*arg) : klass.local(*arg) mark_unmarshalled_obj(node, obj) return true, obj when SOAPArray return @array_factory.soap2obj(klass || Array, node, info, map) when SOAPNil, SOAPBoolean, SOAPInt, SOAPInteger, SOAPDecimal, SOAPDouble return @basetype_factory.soap2obj(nil, node, info, map) when SOAPStruct return rubytypestruct2obj(node, info, map, rubytype) else raise end end def rubytypestruct2obj(node, info, map, rubytype) klass = rubytype ? Mapping.class_from_name(rubytype) : nil obj = nil case node.type when TYPE_HASH klass = rubytype ? Mapping.class_from_name(rubytype) : Hash obj = Mapping.create_empty_object(klass) mark_unmarshalled_obj(node, obj) node.each do |key, value| next unless key == 'item' obj[Mapping._soap2obj(value['key'], map)] = Mapping._soap2obj(value['value'], map) end if node.key?('default') obj.default = Mapping._soap2obj(node['default'], map) end when TYPE_REGEXP klass = rubytype ? Mapping.class_from_name(rubytype) : Regexp obj = Mapping.create_empty_object(klass) mark_unmarshalled_obj(node, obj) source = node['source'].string options = node['options'].data || 0 Regexp.instance_method(:initialize).bind(obj).call(source, options) when TYPE_RANGE klass = rubytype ? Mapping.class_from_name(rubytype) : Range obj = Mapping.create_empty_object(klass) mark_unmarshalled_obj(node, obj) first = Mapping._soap2obj(node['begin'], map) last = Mapping._soap2obj(node['end'], map) exclude_end = node['exclude_end'].data Range.instance_method(:initialize).bind(obj).call(first, last, exclude_end) when TYPE_CLASS obj = Mapping.class_from_name(node['name'].data) when TYPE_MODULE obj = Mapping.class_from_name(node['name'].data) when TYPE_SYMBOL obj = node['id'].data.intern when TYPE_STRUCT typestr = Mapping.elename2name(node['type'].data) klass = Mapping.class_from_name(typestr) if klass.nil? return false end unless klass <= ::Struct return false end obj = Mapping.create_empty_object(klass) mark_unmarshalled_obj(node, obj) node['member'].each do |name, value| obj[Mapping.elename2name(name)] = Mapping._soap2obj(value, map) end else return unknowntype2obj(node, info, map) end return true, obj end def anytype2obj(node, info, map) case node when SOAPBasetype return true, node.data when SOAPStruct klass = ::SOAP::Mapping::Object obj = klass.new mark_unmarshalled_obj(node, obj) node.each do |name, value| obj.__add_xmlele_value(XSD::QName.new(nil, name), Mapping._soap2obj(value, map)) end unless node.extraattr.empty? obj.instance_variable_set('@__xmlattr', node.extraattr) end return true, obj else return false end end def unknowntype2obj(node, info, map) case node when SOAPBasetype return true, node.data when SOAPArray return @array_factory.soap2obj(Array, node, info, map) when SOAPStruct obj = unknownstruct2obj(node, info, map) return true, obj if obj if !@allow_untyped_struct return false end return anytype2obj(node, info, map) else # Basetype which is not defined... return false end end def unknownstruct2obj(node, info, map) unless node.type.name return nil end typestr = Mapping.elename2name(node.type.name) klass = Mapping.class_from_name(typestr) if klass.nil? and @allow_untyped_struct klass = Mapping.class_from_name(typestr, true) # lenient end if klass.nil? return nil end if klass <= ::Exception return exception2obj(klass, node, map) end klass_type = Mapping.class2qname(klass) return nil unless node.type.match(klass_type) obj = nil begin obj = Mapping.create_empty_object(klass) rescue # type name "data" tries Data.new which raises TypeError nil end mark_unmarshalled_obj(node, obj) setiv2obj(obj, node, map) obj end def exception2obj(klass, node, map) message = Mapping._soap2obj(node['message'], map) backtrace = Mapping._soap2obj(node['backtrace'], map) obj = Mapping.create_empty_object(klass) obj = obj.exception(message) mark_unmarshalled_obj(node, obj) obj.set_backtrace(backtrace) obj end # Only creates empty array. Do String#replace it with real string. def array2obj(node, map, rubytype) klass = rubytype ? Mapping.class_from_name(rubytype) : Array obj = Mapping.create_empty_object(klass) mark_unmarshalled_obj(node, obj) obj end # Only creates empty string. Do String#replace it with real string. def string2obj(node, map, rubytype) klass = rubytype ? Mapping.class_from_name(rubytype) : String obj = Mapping.create_empty_object(klass) mark_unmarshalled_obj(node, obj) obj end end end end ================================================ FILE: lib/soap/mapping/typeMap.rb ================================================ # SOAP4R - Base type mapping definition # Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module SOAP TypeMap = { XSD::XSDAnySimpleType::Type => SOAPAnySimpleType, XSD::XSDString::Type => SOAPString, XSD::XSDBoolean::Type => SOAPBoolean, XSD::XSDDecimal::Type => SOAPDecimal, XSD::XSDFloat::Type => SOAPFloat, XSD::XSDDouble::Type => SOAPDouble, XSD::XSDDuration::Type => SOAPDuration, XSD::XSDDateTime::Type => SOAPDateTime, XSD::XSDTime::Type => SOAPTime, XSD::XSDDate::Type => SOAPDate, XSD::XSDGYearMonth::Type => SOAPGYearMonth, XSD::XSDGYear::Type => SOAPGYear, XSD::XSDGMonthDay::Type => SOAPGMonthDay, XSD::XSDGDay::Type => SOAPGDay, XSD::XSDGMonth::Type => SOAPGMonth, XSD::XSDHexBinary::Type => SOAPHexBinary, XSD::XSDBase64Binary::Type => SOAPBase64, XSD::XSDAnyURI::Type => SOAPAnyURI, XSD::XSDQName::Type => SOAPQName, XSD::XSDInteger::Type => SOAPInteger, XSD::XSDNonPositiveInteger::Type => SOAPNonPositiveInteger, XSD::XSDNegativeInteger::Type => SOAPNegativeInteger, XSD::XSDLong::Type => SOAPLong, XSD::XSDInt::Type => SOAPInt, XSD::XSDShort::Type => SOAPShort, XSD::XSDByte::Type => SOAPByte, XSD::XSDNonNegativeInteger::Type => SOAPNonNegativeInteger, XSD::XSDUnsignedLong::Type => SOAPUnsignedLong, XSD::XSDUnsignedInt::Type => SOAPUnsignedInt, XSD::XSDUnsignedShort::Type => SOAPUnsignedShort, XSD::XSDUnsignedByte::Type => SOAPUnsignedByte, XSD::XSDPositiveInteger::Type => SOAPPositiveInteger, SOAP::SOAPBase64::Type => SOAPBase64, } end ================================================ FILE: lib/soap/mapping/wsdlencodedregistry.rb ================================================ # SOAP4R - WSDL encoded mapping registry. # Copyright (C) 2000-2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' require 'xsd/namedelements' require 'soap/baseData' require 'soap/mapping/mapping' require 'soap/mapping/typeMap' module SOAP module Mapping class WSDLEncodedRegistry < Registry include TraverseSupport attr_reader :definedelements attr_reader :definedtypes attr_accessor :excn_handler_obj2soap attr_accessor :excn_handler_soap2obj def initialize(definedtypes = XSD::NamedElements::Empty) @definedtypes = definedtypes # @definedelements = definedelements needed? @excn_handler_obj2soap = nil @excn_handler_soap2obj = nil # For mapping AnyType element. @rubytype_factory = RubytypeFactory.new( :allow_untyped_struct => true, :allow_original_mapping => true ) @schema_element_cache = {} end def obj2soap(obj, qname = nil) soap_obj = nil if type = @definedtypes[qname] soap_obj = obj2typesoap(obj, type) else soap_obj = any2soap(obj, qname) end return soap_obj if soap_obj if @excn_handler_obj2soap soap_obj = @excn_handler_obj2soap.call(obj) { |yield_obj| Mapping._obj2soap(yield_obj, self) } return soap_obj if soap_obj end if qname raise MappingError.new("cannot map #{obj.class.name} as #{qname}") else raise MappingError.new("cannot map #{obj.class.name} to SOAP/OM") end end # map anything for now: must refer WSDL while mapping. [ToDo] def soap2obj(node, obj_class = nil) begin return any2obj(node, obj_class) rescue MappingError end if @excn_handler_soap2obj begin return @excn_handler_soap2obj.call(node) { |yield_node| Mapping._soap2obj(yield_node, self) } rescue Exception end end raise MappingError.new("cannot map #{node.type.name} to Ruby object") end private def any2soap(obj, qname) if obj.nil? SOAPNil.new elsif qname.nil? or qname == XSD::AnyTypeName @rubytype_factory.obj2soap(nil, obj, nil, self) elsif obj.is_a?(XSD::NSDBase) soap2soap(obj, qname) elsif (type = TypeMap[qname]) base2soap(obj, type) else nil end end def soap2soap(obj, type_qname) if obj.is_a?(SOAPBasetype) obj elsif obj.is_a?(SOAPStruct) && (type = @definedtypes[type_qname]) soap_obj = obj mark_marshalled_obj(obj, soap_obj) elements2soap(obj, soap_obj, type.content.elements) soap_obj elsif obj.is_a?(SOAPArray) && (type = @definedtypes[type_qname]) soap_obj = obj contenttype = type.child_type mark_marshalled_obj(obj, soap_obj) obj.replace do |ele| Mapping._obj2soap(ele, self, contenttype) end soap_obj else nil end end def obj2typesoap(obj, type) if type.is_a?(::WSDL::XMLSchema::SimpleType) simpleobj2soap(obj, type) else complexobj2soap(obj, type) end end def simpleobj2soap(obj, type) type.check_lexical_format(obj) return SOAPNil.new if obj.nil? # ToDo: check nillable. o = base2soap(obj, TypeMap[type.base]) o end def complexobj2soap(obj, type) case type.compoundtype when :TYPE_STRUCT struct2soap(obj, type.name, type) when :TYPE_ARRAY array2soap(obj, type.name, type) when :TYPE_MAP map2soap(obj, type.name, type) when :TYPE_SIMPLE simpleobj2soap(obj, type.simplecontent) when :TYPE_EMPTY raise MappingError.new("should be empty") unless obj.nil? SOAPNil.new else raise MappingError.new("unknown compound type: #{type.compoundtype}") end end def base2soap(obj, type) soap_obj = nil if type <= XSD::XSDString str = XSD::Charset.encoding_conv(obj.to_s, Thread.current[:SOAPExternalCES], XSD::Charset.encoding) soap_obj = type.new(str) mark_marshalled_obj(obj, soap_obj) else soap_obj = type.new(obj) end soap_obj end def struct2soap(obj, type_qname, type) return SOAPNil.new if obj.nil? # ToDo: check nillable. soap_obj = SOAPStruct.new(type_qname) unless obj.nil? mark_marshalled_obj(obj, soap_obj) elements2soap(obj, soap_obj, type.content.elements) end soap_obj end def array2soap(obj, type_qname, type) return SOAPNil.new if obj.nil? # ToDo: check nillable. arytype = type.child_type soap_obj = SOAPArray.new(ValueArrayName, 1, arytype) unless obj.nil? mark_marshalled_obj(obj, soap_obj) obj.each do |item| soap_obj.add(Mapping._obj2soap(item, self, arytype)) end end soap_obj end MapKeyName = XSD::QName.new(nil, "key") MapValueName = XSD::QName.new(nil, "value") def map2soap(obj, type_qname, type) return SOAPNil.new if obj.nil? # ToDo: check nillable. keytype = type.child_type(MapKeyName) || XSD::AnyTypeName valuetype = type.child_type(MapValueName) || XSD::AnyTypeName soap_obj = SOAPStruct.new(MapQName) unless obj.nil? mark_marshalled_obj(obj, soap_obj) obj.each do |key, value| elem = SOAPStruct.new elem.add("key", Mapping._obj2soap(key, self, keytype)) elem.add("value", Mapping._obj2soap(value, self, valuetype)) # ApacheAxis allows only 'item' here. soap_obj.add("item", elem) end end soap_obj end def elements2soap(obj, soap_obj, elements) elements.each do |element| name = element.name.name child_obj = Mapping.get_attribute(obj, name) soap_obj.add(name, Mapping._obj2soap(child_obj, self, element.type || element.name)) end end def any2obj(node, obj_class) unless obj_class typestr = XSD::CodeGen::GenSupport.safeconstname(node.elename.name) obj_class = Mapping.class_from_name(typestr) end if obj_class and obj_class.class_variables.include?('@@schema_element') soap2stubobj(node, obj_class) else Mapping._soap2obj(node, Mapping::DefaultRegistry, obj_class) end end def soap2stubobj(node, obj_class) obj = Mapping.create_empty_object(obj_class) unless node.is_a?(SOAPNil) add_elements2stubobj(node, obj) end obj end def add_elements2stubobj(node, obj) elements, as_array = schema_element_definition(obj.class) vars = {} node.each do |name, value| item = elements.find { |k, v| k.name == name } if item elename, class_name = item if klass = Mapping.class_from_name(class_name) # klass must be a SOAPBasetype or a class if klass.ancestors.include?(::SOAP::SOAPBasetype) if value.respond_to?(:data) child = klass.new(value.data).data else child = klass.new(nil).data end else child = Mapping._soap2obj(value, self, klass) end elsif klass = Mapping.module_from_name(class_name) # simpletype if value.respond_to?(:data) child = value.data else raise MappingError.new( "cannot map to a module value: #{class_name}") end else raise MappingError.new("unknown class: #{class_name}") end else # untyped element is treated as anyType. child = Mapping._soap2obj(value, self) end vars[name] = child end Mapping.set_attributes(obj, vars) end # it caches @@schema_element. this means that @@schema_element must not be # changed while a lifetime of a WSDLLiteralRegistry. def schema_element_definition(klass) @schema_element_cache[klass] ||= Mapping.schema_element_definition(klass) end end end end ================================================ FILE: lib/soap/mapping/wsdlliteralregistry.rb ================================================ # SOAP4R - WSDL literal mapping registry. # Copyright (C) 2004, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/baseData' require 'soap/mapping/mapping' require 'soap/mapping/typeMap' require 'xsd/codegen/gensupport' require 'xsd/namedelements' module SOAP module Mapping class WSDLLiteralRegistry < Registry attr_reader :definedelements attr_reader :definedtypes attr_accessor :excn_handler_obj2soap attr_accessor :excn_handler_soap2obj def initialize(definedtypes = XSD::NamedElements::Empty, definedelements = XSD::NamedElements::Empty) @definedtypes = definedtypes @definedelements = definedelements @excn_handler_obj2soap = nil @excn_handler_soap2obj = nil @schema_element_cache = {} @schema_attribute_cache = {} end def obj2soap(obj, qname) soap_obj = nil if ele = @definedelements[qname] soap_obj = obj2elesoap(obj, ele) elsif type = @definedtypes[qname] soap_obj = obj2typesoap(obj, type, true) else soap_obj = any2soap(obj, qname) end return soap_obj if soap_obj if @excn_handler_obj2soap soap_obj = @excn_handler_obj2soap.call(obj) { |yield_obj| Mapping.obj2soap(yield_obj, nil, nil, MAPPING_OPT) } return soap_obj if soap_obj end raise MappingError.new("cannot map #{obj.class.name} as #{qname}") end # node should be a SOAPElement def soap2obj(node, obj_class = nil) # obj_class is given when rpc/literal service. but ignored for now. begin return any2obj(node) rescue MappingError end if @excn_handler_soap2obj begin return @excn_handler_soap2obj.call(node) { |yield_node| Mapping.soap2obj(yield_node, nil, nil, MAPPING_OPT) } rescue Exception end end if node.respond_to?(:type) raise MappingError.new("cannot map #{node.type.name} to Ruby object") else raise MappingError.new("cannot map #{node.elename.name} to Ruby object") end end private MAPPING_OPT = { :no_reference => true } def obj2elesoap(obj, ele) o = nil qualified = (ele.elementform == 'qualified') if ele.type if type = @definedtypes[ele.type] o = obj2typesoap(obj, type, qualified) elsif type = TypeMap[ele.type] o = base2soap(obj, type) else raise MappingError.new("cannot find type #{ele.type}") end elsif ele.local_complextype o = obj2typesoap(obj, ele.local_complextype, qualified) add_attributes2soap(obj, o) elsif ele.local_simpletype o = obj2typesoap(obj, ele.local_simpletype, qualified) else raise MappingError.new('illegal schema?') end o.elename = ele.name o end def obj2typesoap(obj, type, qualified) if type.is_a?(::WSDL::XMLSchema::SimpleType) simpleobj2soap(obj, type) else complexobj2soap(obj, type, qualified) end end def simpleobj2soap(obj, type) type.check_lexical_format(obj) return SOAPNil.new if obj.nil? # ToDo: check nillable. o = base2soap(obj, TypeMap[type.base]) o end def complexobj2soap(obj, type, qualified) o = SOAPElement.new(type.name) o.qualified = qualified type.each_element do |child_ele| child = Mapping.get_attribute(obj, child_ele.name.name) if child.nil? if child_ele.nillable # ToDo: test # add empty element child_soap = obj2elesoap(nil, child_ele) o.add(child_soap) elsif Integer(child_ele.minoccurs) == 0 # nothing to do else raise MappingError.new("nil not allowed: #{child_ele.name.name}") end elsif child_ele.map_as_array? child.each do |item| child_soap = obj2elesoap(item, child_ele) o.add(child_soap) end else child_soap = obj2elesoap(child, child_ele) o.add(child_soap) end end o end def any2soap(obj, qname) if obj.is_a?(SOAPElement) obj elsif obj.class.class_variables.include?('@@schema_element') stubobj2soap(obj, qname) elsif obj.is_a?(SOAP::Mapping::Object) mappingobj2soap(obj, qname) elsif obj.is_a?(Hash) ele = SOAPElement.from_obj(obj) ele.elename = qname ele else # expected to be a basetype or an anyType. # SOAPStruct, etc. is used instead of SOAPElement. begin ele = Mapping.obj2soap(obj, nil, nil, MAPPING_OPT) ele.elename = qname ele rescue MappingError ele = SOAPElement.new(qname, obj.to_s) end if obj.respond_to?(:__xmlattr) obj.__xmlattr.each do |key, value| ele.extraattr[key] = value end end ele end end def stubobj2soap(obj, qname) ele = SOAPElement.new(qname) ele.qualified = (obj.class.class_variables.include?('@@schema_qualified') and obj.class.class_eval('@@schema_qualified')) add_elements2soap(obj, ele) add_attributes2soap(obj, ele) ele end def mappingobj2soap(obj, qname) ele = SOAPElement.new(qname) obj.__xmlele.each do |key, value| if value.is_a?(::Array) value.each do |item| ele.add(obj2soap(item, key)) end else ele.add(obj2soap(value, key)) end end obj.__xmlattr.each do |key, value| ele.extraattr[key] = value end ele end def add_elements2soap(obj, ele) elements, as_array = schema_element_definition(obj.class) if elements elements.each do |elename, type| if child = Mapping.get_attribute(obj, elename.name) if as_array.include?(elename.name) child.each do |item| ele.add(obj2soap(item, elename)) end else ele.add(obj2soap(child, elename)) end elsif obj.is_a?(::Array) and as_array.include?(elename.name) obj.each do |item| ele.add(obj2soap(item, elename)) end end end end end def add_attributes2soap(obj, ele) attributes = schema_attribute_definition(obj.class) if attributes attributes.each do |qname, param| attr = obj.__send__('xmlattr_' + XSD::CodeGen::GenSupport.safevarname(qname.name)) ele.extraattr[qname] = attr end end end def base2soap(obj, type) soap_obj = nil if type <= XSD::XSDString str = XSD::Charset.encoding_conv(obj.to_s, Thread.current[:SOAPExternalCES], XSD::Charset.encoding) soap_obj = type.new(str) else soap_obj = type.new(obj) end soap_obj end def anytype2obj(node) if node.is_a?(::SOAP::SOAPBasetype) return node.data end klass = ::SOAP::Mapping::Object obj = klass.new obj end def any2obj(node, obj_class = nil) unless obj_class typestr = XSD::CodeGen::GenSupport.safeconstname(node.elename.name) obj_class = Mapping.class_from_name(typestr) end if obj_class and obj_class.class_variables.include?('@@schema_element') soapele2stubobj(node, obj_class) elsif node.is_a?(SOAPElement) or node.is_a?(SOAPStruct) # SOAPArray for literal? soapele2plainobj(node) else obj = Mapping.soap2obj(node, nil, obj_class, MAPPING_OPT) add_attributes2plainobj(node, obj) obj end end def soapele2stubobj(node, obj_class) obj = Mapping.create_empty_object(obj_class) add_elements2stubobj(node, obj) add_attributes2stubobj(node, obj) obj end def soapele2plainobj(node) obj = anytype2obj(node) add_elements2plainobj(node, obj) add_attributes2plainobj(node, obj) obj end def add_elements2stubobj(node, obj) elements, as_array = schema_element_definition(obj.class) vars = {} node.each do |name, value| item = elements.find { |k, v| k.name == name } if item elename, class_name = item if klass = Mapping.class_from_name(class_name) # klass must be a SOAPBasetype or a class if klass.ancestors.include?(::SOAP::SOAPBasetype) if value.respond_to?(:data) child = klass.new(value.data).data else child = klass.new(nil).data end else child = any2obj(value, klass) end elsif klass = Mapping.module_from_name(class_name) # simpletype if value.respond_to?(:data) child = value.data else raise MappingError.new( "cannot map to a module value: #{class_name}") end else raise MappingError.new("unknown class/module: #{class_name}") end else # untyped element is treated as anyType. child = any2obj(value) end if as_array.include?(elename.name) (vars[name] ||= []) << child else vars[name] = child end end Mapping.set_attributes(obj, vars) end def add_attributes2stubobj(node, obj) if attributes = schema_attribute_definition(obj.class) define_xmlattr(obj) attributes.each do |qname, class_name| attr = node.extraattr[qname] next if attr.nil? or attr.empty? klass = Mapping.class_from_name(class_name) if klass.ancestors.include?(::SOAP::SOAPBasetype) child = klass.new(attr).data else child = attr end obj.__xmlattr[qname] = child define_xmlattr_accessor(obj, qname) end end end def add_elements2plainobj(node, obj) node.each do |name, value| obj.__add_xmlele_value(value.elename, any2obj(value)) end end def add_attributes2plainobj(node, obj) return if node.extraattr.empty? define_xmlattr(obj) node.extraattr.each do |qname, value| obj.__xmlattr[qname] = value define_xmlattr_accessor(obj, qname) end end if RUBY_VERSION > "1.7.0" def define_xmlattr_accessor(obj, qname) name = XSD::CodeGen::GenSupport.safemethodname(qname.name) Mapping.define_attr_accessor(obj, 'xmlattr_' + name, proc { @__xmlattr[qname] }, proc { |value| @__xmlattr[qname] = value }) end else def define_xmlattr_accessor(obj, qname) name = XSD::CodeGen::GenSupport.safemethodname(qname.name) obj.instance_eval <<-EOS def #{name} @__xmlattr[#{qname.dump}] end def #{name}=(value) @__xmlattr[#{qname.dump}] = value end EOS end end if RUBY_VERSION > "1.7.0" def define_xmlattr(obj) obj.instance_variable_set('@__xmlattr', {}) unless obj.respond_to?(:__xmlattr) Mapping.define_attr_accessor(obj, :__xmlattr, proc { @__xmlattr }) end end else def define_xmlattr(obj) obj.instance_variable_set('@__xmlattr', {}) unless obj.respond_to?(:__xmlattr) obj.instance_eval <<-EOS def __xmlattr @__xmlattr end EOS end end end # it caches @@schema_element. this means that @@schema_element must not be # changed while a lifetime of a WSDLLiteralRegistry. def schema_element_definition(klass) @schema_element_cache[klass] ||= Mapping.schema_element_definition(klass) end def schema_attribute_definition(klass) @schema_attribute_cache[klass] ||= Mapping.schema_attribute_definition(klass) end end end end ================================================ FILE: lib/soap/mapping.rb ================================================ # SOAP4R - Ruby type mapping utility. # Copyright (C) 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/mapping/mapping' require 'soap/mapping/registry' ================================================ FILE: lib/soap/marshal.rb ================================================ # SOAP4R - Marshalling/Unmarshalling Ruby's object using SOAP Encoding. # Copyright (C) 2001, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require "soap/mapping" require "soap/processor" module SOAP module Marshal # Trying xsd:dateTime data to be recovered as aTime. MarshalMappingRegistry = Mapping::Registry.new( :allow_original_mapping => true) MarshalMappingRegistry.add( Time, ::SOAP::SOAPDateTime, ::SOAP::Mapping::Registry::DateTimeFactory ) class << self public def dump(obj, io = nil) marshal(obj, MarshalMappingRegistry, io) end def load(stream) unmarshal(stream, MarshalMappingRegistry) end def marshal(obj, mapping_registry = MarshalMappingRegistry, io = nil) elename = Mapping.name2elename(obj.class.to_s) soap_obj = Mapping.obj2soap(obj, mapping_registry) body = SOAPBody.new body.add(elename, soap_obj) env = SOAPEnvelope.new(nil, body) SOAP::Processor.marshal(env, {}, io) end def unmarshal(stream, mapping_registry = MarshalMappingRegistry) env = SOAP::Processor.unmarshal(stream) if env.nil? raise ArgumentError.new("Illegal SOAP marshal format.") end Mapping.soap2obj(env.body.root_node, mapping_registry) end end end end SOAPMarshal = SOAP::Marshal ================================================ FILE: lib/soap/mimemessage.rb ================================================ # SOAP4R - MIME Message implementation. # Copyright (C) 2002 Jamie Herre. # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/attachment' module SOAP # Classes for MIME message handling. Should be put somewhere else! # Tried using the 'tmail' module but found that I needed something # lighter in weight. class MIMEMessage class MIMEMessageError < StandardError; end MultipartContentType = 'multipart/\w+' class Header attr_accessor :str, :key, :root def initialize @attrs = {} end def [](key) @attrs[key] end def []=(key, value) @attrs[key] = value end def to_s @key + ": " + @str end end class Headers < Hash def self.parse(str) new.parse(str) end def parse(str) header_cache = nil str.each do |line| case line when /^\A[^\: \t]+:\s*.+$/ parse_line(header_cache) if header_cache header_cache = line.sub(/\r?\n\z/, '') when /^\A\s+(.*)$/ # a continuous line at the beginning line crashes here. header_cache << line else raise RuntimeError.new("unexpected header: #{line.inspect}") end end parse_line(header_cache) if header_cache self end def parse_line(line) if /^\A([^\: \t]+):\s*(.+)\z/ =~ line header = parse_rhs($2.strip) header.key = $1.strip self[header.key.downcase] = header else raise RuntimeError.new("unexpected header line: #{line.inspect}") end end def parse_rhs(str) a = str.split(/;+\s+/) header = Header.new header.str = str header.root = a.shift a.each do |pair| if pair =~ /(\w+)\s*=\s*"?([^"]+)"?/ header[$1.downcase] = $2 else raise RuntimeError.new("unexpected header component: #{pair.inspect}") end end header end def add(key, value) if key != nil and value != nil header = parse_rhs(value) header.key = key self[key.downcase] = header end end def to_s self.values.collect { |hdr| hdr.to_s }.join("\r\n") end end class Part attr_accessor :headers, :body def initialize @headers = Headers.new @headers.add("Content-Transfer-Encoding", "8bit") @body = nil @contentid = nil end def self.parse(str) new.parse(str) end def parse(str) headers, body = str.split(/\r\n\r\n/s) if headers != nil and body != nil @headers = Headers.parse(headers) @body = body.sub(/\r\n\z/, '') else raise RuntimeError.new("unexpected part: #{str.inspect}") end self end def contentid if @contentid == nil and @headers.key?('content-id') @contentid = @headers['content-id'].str @contentid = $1 if @contentid =~ /^<(.+)>$/ end @contentid end alias content body def to_s @headers.to_s + "\r\n\r\n" + @body end end def initialize @parts = [] @headers = Headers.new @root = nil end def self.parse(head, str) new.parse(head, str) end attr_reader :parts, :headers def close @headers.add( "Content-Type", "multipart/related; type=\"text/xml\"; boundary=\"#{boundary}\"; start=\"#{@parts[0].contentid}\"" ) end def parse(head, str) @headers = Headers.parse(head + "\r\n" + "From: jfh\r\n") boundary = @headers['content-type']['boundary'] if boundary != nil parts = str.split(/--#{Regexp.quote(boundary)}\s*(?:\r\n|--\r\n)/) part = parts.shift # preamble must be ignored. @parts = parts.collect { |part| Part.parse(part) } else @parts = [Part.parse(str)] end if @parts.length < 1 raise MIMEMessageError.new("This message contains no valid parts!") end self end def root if @root == nil start = @headers['content-type']['start'] @root = (start && @parts.find { |prt| prt.contentid == start }) || @parts[0] end @root end def boundary if @boundary == nil @boundary = "----=Part_" + __id__.to_s + rand.to_s end @boundary end def add_part(content) part = Part.new part.headers.add("Content-Type", "text/xml; charset=" + XSD::Charset.xml_encoding_label) part.headers.add("Content-ID", Attachment.contentid(part)) part.body = content @parts.unshift(part) end def add_attachment(attach) part = Part.new part.headers.add("Content-Type", attach.contenttype) part.headers.add("Content-ID", attach.mime_contentid) part.body = attach.content @parts.unshift(part) end def has_parts? (@parts.length > 0) end def headers_str @headers.to_s end def content_str str = '' @parts.each do |prt| str << "--" + boundary + "\r\n" str << prt.to_s + "\r\n" end str << '--' + boundary + "--\r\n" str end def to_s str = headers_str + "\r\n\r\n" + content_str end end end ================================================ FILE: lib/soap/netHttpClient.rb ================================================ # SOAP4R - net/http wrapper # Copyright (C) 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'net/http' module SOAP class NetHttpClient SSLEnabled = begin require 'net/https' true rescue LoadError false end attr_reader :proxy attr_accessor :no_proxy attr_accessor :debug_dev attr_accessor :ssl_config # ignored for now. attr_accessor :protocol_version # ignored for now. attr_accessor :connect_timeout attr_accessor :send_timeout # ignored for now. attr_accessor :receive_timeout def initialize(proxy = nil, agent = nil) @proxy = proxy ? URI.parse(proxy) : nil @agent = agent @debug_dev = nil @session_manager = SessionManager.new @no_proxy = @ssl_config = @protocol_version = nil @connect_timeout = @send_timeout = @receive_timeout = nil end def test_loopback_response raise NotImplementedError.new("not supported for now") end def proxy=(proxy) if proxy.nil? @proxy = nil else if proxy.is_a?(URI) @proxy = proxy else @proxy = URI.parse(proxy) end if @proxy.scheme == nil or @proxy.scheme.downcase != 'http' or @proxy.host == nil or @proxy.port == nil raise ArgumentError.new("unsupported proxy `#{proxy}'") end end reset_all @proxy end def set_basic_auth(uri, user_id, passwd) # net/http does not handle url. @basic_auth = [user_id, passwd] raise NotImplementedError.new("basic_auth is not supported under soap4r + net/http.") end def set_cookie_store(filename) raise NotImplementedError.new end def save_cookie_store(filename) raise NotImplementedError.new end def reset(url) # no persistent connection. ignored. end def reset_all # no persistent connection. ignored. end def post(url, req_body, header = {}) unless url.is_a?(URI) url = URI.parse(url) end extra = header.dup extra['User-Agent'] = @agent if @agent res = start(url) { |http| http.post(url.request_uri, req_body, extra) } Response.new(res) end def get_content(url, header = {}) unless url.is_a?(URI) url = URI.parse(url) end extra = header.dup extra['User-Agent'] = @agent if @agent res = start(url) { |http| http.get(url.request_uri, extra) } res.body end private def start(url) http = create_connection(url) response = nil http.start { |worker| response = yield(worker) worker.finish } @debug_dev << response.body if @debug_dev response end def create_connection(url) proxy_host = proxy_port = nil unless no_proxy?(url) proxy_host = @proxy.host proxy_port = @proxy.port end http = Net::HTTP::Proxy(proxy_host, proxy_port).new(url.host, url.port) if http.respond_to?(:set_debug_output) http.set_debug_output(@debug_dev) end http.open_timeout = @connect_timeout if @connect_timeout http.read_timeout = @receive_timeout if @receive_timeout case url when URI::HTTPS if SSLEnabled http.use_ssl = true else raise RuntimeError.new("Cannot connect to #{url} (OpenSSL is not installed.)") end when URI::HTTP # OK else raise RuntimeError.new("Cannot connect to #{url} (Not HTTP.)") end http end NO_PROXY_HOSTS = ['localhost'] def no_proxy?(uri) if !@proxy or NO_PROXY_HOSTS.include?(uri.host) return true end if @no_proxy @no_proxy.scan(/([^:,]*)(?::(\d+))?/) do |host, port| if /(\A|\.)#{Regexp.quote(host)}\z/i =~ uri.host && (!port || uri.port == port.to_i) return true end end else false end end class SessionManager attr_accessor :connect_timeout attr_accessor :send_timeout attr_accessor :receive_timeout end class Response attr_reader :content attr_reader :status attr_reader :reason attr_reader :contenttype def initialize(res) @status = res.code.to_i @reason = res.message @contenttype = res['content-type'] @content = res.body end end end end ================================================ FILE: lib/soap/parser.rb ================================================ # SOAP4R - SOAP XML Instance Parser library. # Copyright (C) 2001, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/ns' require 'xsd/xmlparser' require 'soap/soap' require 'soap/baseData' require 'soap/encodingstyle/handler' module SOAP class Parser include SOAP class ParseError < Error; end class FormatDecodeError < ParseError; end class UnexpectedElementError < ParseError; end private class ParseFrame attr_reader :node attr_reader :name attr_reader :ns, :encodingstyle class NodeContainer def initialize(node) @node = node end def node @node end def replace_node(node) @node = node end end public def initialize(ns, name, node, encodingstyle) @ns = ns @name = name self.node = node @encodingstyle = encodingstyle end def node=(node) @node = NodeContainer.new(node) end end public attr_accessor :envelopenamespace attr_accessor :default_encodingstyle attr_accessor :decode_typemap attr_accessor :allow_unqualified_element def initialize(opt = {}) @opt = opt @parser = XSD::XMLParser.create_parser(self, opt) @parsestack = nil @lastnode = nil @handlers = {} @envelopenamespace = opt[:envelopenamespace] || EnvelopeNamespace @default_encodingstyle = opt[:default_encodingstyle] || EncodingNamespace @decode_typemap = opt[:decode_typemap] || nil @allow_unqualified_element = opt[:allow_unqualified_element] || false end def charset @parser.charset end def parse(string_or_readable) @parsestack = [] @lastnode = nil @handlers.each do |uri, handler| handler.decode_prologue end @parser.do_parse(string_or_readable) unless @parsestack.empty? raise FormatDecodeError.new("Unbalanced tag in XML.") end @handlers.each do |uri, handler| handler.decode_epilogue end @lastnode end def start_element(name, attrs) lastframe = @parsestack.last ns = parent = parent_encodingstyle = nil if lastframe ns = lastframe.ns.clone_ns parent = lastframe.node parent_encodingstyle = lastframe.encodingstyle else ns = XSD::NS.new parent = ParseFrame::NodeContainer.new(nil) parent_encodingstyle = nil end attrs = XSD::XMLParser.filter_ns(ns, attrs) encodingstyle = find_encodingstyle(ns, attrs) # Children's encodingstyle is derived from its parent. if encodingstyle.nil? if parent.node.is_a?(SOAPHeader) encodingstyle = LiteralNamespace else encodingstyle = parent_encodingstyle || @default_encodingstyle end end node = decode_tag(ns, name, attrs, parent, encodingstyle) @parsestack << ParseFrame.new(ns, name, node, encodingstyle) end def characters(text) lastframe = @parsestack.last if lastframe # Need not to be cloned because character does not have attr. decode_text(lastframe.ns, text, lastframe.encodingstyle) else # Ignore Text outside of SOAP Envelope. p text if $DEBUG end end def end_element(name) lastframe = @parsestack.pop unless name == lastframe.name raise UnexpectedElementError.new("Closing element name '#{ name }' does not match with opening element '#{ lastframe.name }'.") end decode_tag_end(lastframe.ns, lastframe.node, lastframe.encodingstyle) @lastnode = lastframe.node.node end private def find_encodingstyle(ns, attrs) attrs.each do |key, value| if (ns.compare(@envelopenamespace, AttrEncodingStyle, key)) return value end end nil end def decode_tag(ns, name, attrs, parent, encodingstyle) ele = ns.parse(name) # Envelope based parsing. if ((ele.namespace == @envelopenamespace) || (@allow_unqualified_element && ele.namespace.nil?)) o = decode_soap_envelope(ns, ele, attrs, parent) return o if o end # Encoding based parsing. handler = find_handler(encodingstyle) if handler return handler.decode_tag(ns, ele, attrs, parent) else raise FormatDecodeError.new("Unknown encodingStyle: #{ encodingstyle }.") end end def decode_tag_end(ns, node, encodingstyle) return unless encodingstyle handler = find_handler(encodingstyle) if handler return handler.decode_tag_end(ns, node) else raise FormatDecodeError.new("Unknown encodingStyle: #{ encodingstyle }.") end end def decode_text(ns, text, encodingstyle) handler = find_handler(encodingstyle) if handler handler.decode_text(ns, text) else # How should I do? end end def decode_soap_envelope(ns, ele, attrs, parent) o = nil if ele.name == EleEnvelope o = SOAPEnvelope.new if ext = @opt[:external_content] ext.each do |k, v| o.external_content[k] = v end end elsif ele.name == EleHeader unless parent.node.is_a?(SOAPEnvelope) raise FormatDecodeError.new("Header should be a child of Envelope.") end o = SOAPHeader.new parent.node.header = o elsif ele.name == EleBody unless parent.node.is_a?(SOAPEnvelope) raise FormatDecodeError.new("Body should be a child of Envelope.") end o = SOAPBody.new parent.node.body = o elsif ele.name == EleFault unless parent.node.is_a?(SOAPBody) raise FormatDecodeError.new("Fault should be a child of Body.") end o = SOAPFault.new parent.node.fault = o end o end def find_handler(encodingstyle) unless @handlers.key?(encodingstyle) handler_factory = SOAP::EncodingStyle::Handler.handler(encodingstyle) || SOAP::EncodingStyle::Handler.handler(EncodingNamespace) handler = handler_factory.new(@parser.charset) handler.decode_typemap = @decode_typemap handler.decode_prologue @handlers[encodingstyle] = handler end @handlers[encodingstyle] end end end ================================================ FILE: lib/soap/processor.rb ================================================ # SOAP4R - marshal/unmarshal interface. # Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/datatypes' require 'soap/soap' require 'soap/element' require 'soap/parser' require 'soap/generator' require 'soap/encodingstyle/soapHandler' require 'soap/encodingstyle/literalHandler' require 'soap/encodingstyle/aspDotNetHandler' module SOAP module Processor @@default_parser_option = {} class << self public def marshal(env, opt = {}, io = nil) generator = create_generator(opt) marshalled_str = generator.generate(env, io) unless env.external_content.empty? opt[:external_content] = env.external_content end marshalled_str end def unmarshal(stream, opt = {}) parser = create_parser(opt) parser.parse(stream) end def default_parser_option=(rhs) @@default_parser_option = rhs end def default_parser_option @@default_parser_option end private def create_generator(opt) SOAPGenerator.new(opt) end def create_parser(opt) if opt.empty? opt = @@default_parser_option end ::SOAP::Parser.new(opt) end end end end ================================================ FILE: lib/soap/property.rb ================================================ # soap/property.rb: SOAP4R - Property implementation. # Copyright (C) 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module SOAP # Property stream format: # # line separator is \r?\n. 1 line per a property. # line which begins with '#' is a comment line. empty line is ignored, too. # key/value separator is ':' or '='. # '\' as escape character. but line separator cannot be escaped. # \s at the head/tail of key/value are trimmed. # # '[' + key + ']' indicates property section. for example, # # [aaa.bbb] # ccc = ddd # eee.fff = ggg # [] # aaa.hhh = iii # # is the same as; # # aaa.bbb.ccc = ddd # aaa.bbb.eee.fff = ggg # aaa.hhh = iii # class Property FrozenError = (RUBY_VERSION >= "1.9.0") ? RuntimeError : TypeError include Enumerable module Util def const_from_name(fqname) fqname.split("::").inject(Kernel) { |klass, name| klass.const_get(name) } end module_function :const_from_name def require_from_name(fqname) require File.join(fqname.split("::").collect { |ele| ele.downcase }) end module_function :require_from_name end def self.load(stream) new.load(stream) end def self.loadproperty(propname) new.loadproperty(propname) end def initialize @store = Hash.new @hook = Hash.new @self_hook = Array.new @locked = false end KEY_REGSRC = '([^=:\\\\]*(?:\\\\.[^=:\\\\]*)*)' DEF_REGSRC = '\\s*' + KEY_REGSRC + '\\s*[=:]\\s*(.*)' COMMENT_REGEXP = Regexp.new('^(?:#.*|)$') CATDEF_REGEXP = Regexp.new("^\\[\\s*#{KEY_REGSRC}\\s*\\]$") LINE_REGEXP = Regexp.new("^#{DEF_REGSRC}$") def load(stream) key_prefix = "" stream.each_with_index do |line, lineno| line.sub!(/\r?\n\z/, '') case line when COMMENT_REGEXP next when CATDEF_REGEXP key_prefix = $1.strip when LINE_REGEXP key, value = $1.strip, $2.strip key = "#{key_prefix}.#{key}" unless key_prefix.empty? key, value = loadstr(key), loadstr(value) self[key] = value else raise TypeError.new( "property format error at line #{lineno + 1}: `#{line}'") end end self end # find property from $:. def loadproperty(propname) return loadpropertyfile(propname) if File.file?(propname) $:.each do |path| if File.file?(file = File.join(path, propname)) return loadpropertyfile(file) end end nil end # name: a Symbol, String or an Array def [](name) referent(name_to_a(name)) end # name: a Symbol, String or an Array # value: an Object def []=(name, value) name_pair = name_to_a(name).freeze hooks = assign(name_pair, value) hooks.each do |hook| hook.call(name_pair, value) end value end # value: an Object # key is generated by property def <<(value) self[generate_new_key] = value end # name: a Symbol, String or an Array; nil means hook to the root # cascade: true/false; for cascading hook of sub key # hook: block which will be called with 2 args, name and value def add_hook(name = nil, cascade = false, &hook) if name == nil or name == true or name == false cascade = name assign_self_hook(cascade, &hook) else assign_hook(name_to_a(name), cascade, &hook) end end def each @store.each do |key, value| yield(key, value) end end def empty? @store.empty? end def keys @store.keys end def values @store.values end def lock(cascade = false) if cascade each_key do |key| key.lock(cascade) end end @locked = true self end def unlock(cascade = false) @locked = false if cascade each_key do |key| key.unlock(cascade) end end self end def locked? @locked end protected def deref_key(key) check_lock(key) ref = @store[key] ||= self.class.new unless propkey?(ref) raise ArgumentError.new("key `#{key}' already defined as a value") end ref end def local_referent(key) check_lock(key) if propkey?(@store[key]) and @store[key].locked? raise FrozenError.new("cannot split any key from locked property") end @store[key] end def local_assign(key, value) check_lock(key) if @locked if propkey?(value) raise FrozenError.new("cannot add any key to locked property") elsif propkey?(@store[key]) raise FrozenError.new("cannot override any key in locked property") end end @store[key] = value end def local_hook(key, direct) hooks = [] (@self_hook + (@hook[key] || NO_HOOK)).each do |hook, cascade| hooks << hook if direct or cascade end hooks end def local_assign_hook(key, cascade, &hook) check_lock(key) @store[key] ||= nil (@hook[key] ||= []) << [hook, cascade] end private NO_HOOK = [].freeze def referent(ary) ary[0..-2].inject(self) { |ref, name| ref.deref_key(to_key(name)) }.local_referent(to_key(ary.last)) end def assign(ary, value) ref = self hook = NO_HOOK ary[0..-2].each do |name| key = to_key(name) hook += ref.local_hook(key, false) ref = ref.deref_key(key) end last_key = to_key(ary.last) ref.local_assign(last_key, value) hook + ref.local_hook(last_key, true) end def assign_hook(ary, cascade, &hook) ary[0..-2].inject(self) { |ref, name| ref.deref_key(to_key(name)) }.local_assign_hook(to_key(ary.last), cascade, &hook) end def assign_self_hook(cascade, &hook) check_lock(nil) @self_hook << [hook, cascade] end def each_key self.each do |key, value| if propkey?(value) yield(value) end end end def check_lock(key) if @locked and (key.nil? or !@store.key?(key)) raise FrozenError.new("cannot add any key to locked property") end end def propkey?(value) value.is_a?(::SOAP::Property) end def name_to_a(name) case name when Symbol [name] when String name.scan(/[^.\\]+(?:\\.[^.\\])*/) # split with unescaped '.' when Array name else raise ArgumentError.new("Unknown name #{name}(#{name.class})") end end def to_key(name) name.to_s.downcase end def generate_new_key if @store.empty? "0" else (key_max + 1).to_s end end def key_max (@store.keys.max { |l, r| l.to_s.to_i <=> r.to_s.to_i }).to_s.to_i end def loadpropertyfile(file) puts "find property at #{file}" if $DEBUG File.open(file) do |f| load(f) end end def loadstr(str) str.gsub(/\\./) { |c| eval("\"#{c}\"") } end end end # for ruby/1.6. unless Enumerable.instance_methods.include?('inject') module Enumerable def inject(init) result = init each do |item| result = yield(result, item) end result end end end ================================================ FILE: lib/soap/rpc/cgistub.rb ================================================ # SOAP4R - CGI/mod_ruby stub library # Copyright (C) 2001, 2003-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/streamHandler' require 'webrick/httpresponse' require 'webrick/httpstatus' require 'logger' require 'soap/rpc/soaplet' module SOAP module RPC ### # SYNOPSIS # CGIStub.new # # DESCRIPTION # To be written... # class CGIStub < Logger::Application include SOAP include WEBrick class SOAPRequest attr_reader :body def [](var); end def meta_vars; end end class SOAPStdinRequest < SOAPRequest attr_reader :body def initialize(stream) size = ENV['CONTENT_LENGTH'].to_i || 0 @body = stream.read(size) end def [](var) ENV[var.gsub(/-/, '_').upcase] end def meta_vars { 'HTTP_SOAPACTION' => ENV['HTTP_SOAPAction'] } end end class SOAPFCGIRequest < SOAPRequest attr_reader :body def initialize(request) @request = request @body = @request.in.read end def [](var) @request.env[var.gsub(/-/, '_').upcase] end def meta_vars { 'HTTP_SOAPACTION' => @request.env['HTTP_SOAPAction'] } end end def initialize(appname, default_namespace) super(appname) set_log(STDERR) self.level = ERROR @default_namespace = default_namespace @remote_host = ENV['REMOTE_HOST'] || ENV['REMOTE_ADDR'] || 'unknown' @router = ::SOAP::RPC::Router.new(self.class.name) @soaplet = ::SOAP::RPC::SOAPlet.new(@router) on_init end def on_init # do extra initialization in a derived class if needed. end def mapping_registry @router.mapping_registry end def mapping_registry=(value) @router.mapping_registry = value end def generate_explicit_type @router.generate_explicit_type end def generate_explicit_type=(generate_explicit_type) @router.generate_explicit_type = generate_explicit_type end # servant entry interface def add_rpc_servant(obj, namespace = @default_namespace) @router.add_rpc_servant(obj, namespace) end alias add_servant add_rpc_servant def add_headerhandler(obj) @router.add_headerhandler(obj) end alias add_rpc_headerhandler add_headerhandler # method entry interface def add_rpc_method(obj, name, *param) add_rpc_method_with_namespace_as(@default_namespace, obj, name, name, *param) end alias add_method add_rpc_method def add_rpc_method_as(obj, name, name_as, *param) add_rpc_method_with_namespace_as(@default_namespace, obj, name, name_as, *param) end alias add_method_as add_rpc_method_as def add_rpc_method_with_namespace(namespace, obj, name, *param) add_rpc_method_with_namespace_as(namespace, obj, name, name, *param) end alias add_method_with_namespace add_rpc_method_with_namespace def add_rpc_method_with_namespace_as(namespace, obj, name, name_as, *param) qname = XSD::QName.new(namespace, name_as) soapaction = nil param_def = SOAPMethod.derive_rpc_param_def(obj, name, *param) @router.add_rpc_operation(obj, qname, soapaction, name, param_def) end alias add_method_with_namespace_as add_rpc_method_with_namespace_as def add_rpc_operation(receiver, qname, soapaction, name, param_def, opt = {}) @router.add_rpc_operation(receiver, qname, soapaction, name, param_def, opt) end def add_document_operation(receiver, soapaction, name, param_def, opt = {}) @router.add_document_operation(receiver, soapaction, name, param_def, opt) end def set_fcgi_request(request) @fcgi = request end private HTTPVersion = WEBrick::HTTPVersion.new('1.0') # dummy; ignored def run res = WEBrick::HTTPResponse.new({:HTTPVersion => HTTPVersion}) begin @log.info { "received a request from '#{ @remote_host }'" } if @fcgi req = SOAPFCGIRequest.new(@fcgi) else req = SOAPStdinRequest.new($stdin) end @soaplet.do_POST(req, res) rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex res.set_error(ex) rescue HTTPStatus::Error => ex res.set_error(ex) rescue HTTPStatus::Status => ex res.status = ex.code rescue StandardError, NameError => ex # for Ruby 1.6 res.set_error(ex, true) ensure if defined?(MOD_RUBY) r = Apache.request r.status = res.status r.content_type = res.content_type r.send_http_header buf = res.body else buf = '' res.send_response(buf) buf.sub!(/^[^\r]+\r\n/, '') # Trim status line. end @log.debug { "SOAP CGI Response:\n#{ buf }" } if @fcgi @fcgi.out.print buf @fcgi.finish @fcgi = nil else print buf end end 0 end end end end ================================================ FILE: lib/soap/rpc/driver.rb ================================================ # SOAP4R - SOAP RPC driver # Copyright (C) 2000, 2001, 2003-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/soap' require 'soap/mapping' require 'soap/mapping/wsdlliteralregistry' require 'soap/rpc/rpc' require 'soap/rpc/proxy' require 'soap/rpc/element' require 'soap/streamHandler' require 'soap/property' require 'soap/header/handlerset' module SOAP module RPC class Driver class << self if RUBY_VERSION >= "1.7.0" def __attr_proxy(symbol, assignable = false) name = symbol.to_s define_method(name) { @proxy.__send__(name) } if assignable aname = name + '=' define_method(aname) { |rhs| @proxy.__send__(aname, rhs) } end end else def __attr_proxy(symbol, assignable = false) name = symbol.to_s module_eval <<-EOS def #{name} @proxy.#{name} end EOS if assignable module_eval <<-EOS def #{name}=(value) @proxy.#{name} = value end EOS end end end end __attr_proxy :endpoint_url, true __attr_proxy :mapping_registry, true __attr_proxy :default_encodingstyle, true __attr_proxy :generate_explicit_type, true __attr_proxy :allow_unqualified_element, true __attr_proxy :headerhandler __attr_proxy :streamhandler __attr_proxy :test_loopback_response __attr_proxy :reset_stream attr_reader :proxy attr_reader :options attr_accessor :soapaction def inspect "#<#{self.class}:#{@proxy.inspect}>" end def httpproxy options["protocol.http.proxy"] end def httpproxy=(httpproxy) options["protocol.http.proxy"] = httpproxy end def wiredump_dev options["protocol.http.wiredump_dev"] end def wiredump_dev=(wiredump_dev) options["protocol.http.wiredump_dev"] = wiredump_dev end def mandatorycharset options["protocol.mandatorycharset"] end def mandatorycharset=(mandatorycharset) options["protocol.mandatorycharset"] = mandatorycharset end def wiredump_file_base options["protocol.wiredump_file_base"] end def wiredump_file_base=(wiredump_file_base) options["protocol.wiredump_file_base"] = wiredump_file_base end def initialize(endpoint_url, namespace = nil, soapaction = nil) @namespace = namespace @soapaction = soapaction @options = setup_options @wiredump_file_base = nil @proxy = Proxy.new(endpoint_url, @soapaction, @options) end def loadproperty(propertyname) unless options.loadproperty(propertyname) raise LoadError.new("No such property to load -- #{propertyname}") end end def add_rpc_method(name, *params) add_rpc_method_with_soapaction_as(name, name, @soapaction, *params) end def add_rpc_method_as(name, name_as, *params) add_rpc_method_with_soapaction_as(name, name_as, @soapaction, *params) end def add_rpc_method_with_soapaction(name, soapaction, *params) add_rpc_method_with_soapaction_as(name, name, soapaction, *params) end def add_rpc_method_with_soapaction_as(name, name_as, soapaction, *params) param_def = SOAPMethod.create_rpc_param_def(params) qname = XSD::QName.new(@namespace, name_as) @proxy.add_rpc_method(qname, soapaction, name, param_def) add_rpc_method_interface(name, param_def) end # add_method is for shortcut of typical rpc/encoded method definition. alias add_method add_rpc_method alias add_method_as add_rpc_method_as alias add_method_with_soapaction add_rpc_method_with_soapaction alias add_method_with_soapaction_as add_rpc_method_with_soapaction_as def add_document_method(name, soapaction, req_qname, res_qname) param_def = SOAPMethod.create_doc_param_def(req_qname, res_qname) @proxy.add_document_method(soapaction, name, param_def) add_document_method_interface(name, param_def) end def add_rpc_operation(qname, soapaction, name, param_def, opt = {}) @proxy.add_rpc_operation(qname, soapaction, name, param_def, opt) add_rpc_method_interface(name, param_def) end def add_document_operation(soapaction, name, param_def, opt = {}) @proxy.add_document_operation(soapaction, name, param_def, opt) add_document_method_interface(name, param_def) end def invoke(headers, body) if headers and !headers.is_a?(SOAPHeader) headers = create_header(headers) end set_wiredump_file_base(body.elename.name) env = @proxy.invoke(headers, body) if env.nil? return nil, nil else return env.header, env.body end end def call(name, *params) set_wiredump_file_base(name) @proxy.call(name, *params) end private def set_wiredump_file_base(name) if @wiredump_file_base @proxy.set_wiredump_file_base("#{@wiredump_file_base}_#{name}") end end def create_header(headers) header = SOAPHeader.new() headers.each do |content, mustunderstand, encodingstyle| header.add(SOAPHeaderItem.new(content, mustunderstand, encodingstyle)) end header end def setup_options if opt = Property.loadproperty(::SOAP::PropertyName) opt = opt["client"] end opt ||= Property.new opt.add_hook("protocol.mandatorycharset") do |key, value| @proxy.mandatorycharset = value end opt.add_hook("protocol.wiredump_file_base") do |key, value| @wiredump_file_base = value end opt["protocol.http.charset"] ||= XSD::Charset.xml_encoding_label opt["protocol.http.proxy"] ||= Env::HTTP_PROXY opt["protocol.http.no_proxy"] ||= Env::NO_PROXY opt end def add_rpc_method_interface(name, param_def) param_count = RPC::SOAPMethod.param_count(param_def, RPC::SOAPMethod::IN, RPC::SOAPMethod::INOUT) add_method_interface(name, param_count) end def add_document_method_interface(name, param_def) param_count = RPC::SOAPMethod.param_count(param_def, RPC::SOAPMethod::IN) add_method_interface(name, param_count) end if RUBY_VERSION > "1.7.0" def add_method_interface(name, param_count) ::SOAP::Mapping.define_singleton_method(self, name) do |*arg| unless arg.size == param_count raise ArgumentError.new( "wrong number of arguments (#{arg.size} for #{param_count})") end call(name, *arg) end self.method(name) end else def add_method_interface(name, param_count) instance_eval <<-EOS def #{name}(*arg) unless arg.size == #{param_count} raise ArgumentError.new( "wrong number of arguments (\#{arg.size} for #{param_count})") end call(#{name.dump}, *arg) end EOS self.method(name) end end end end end ================================================ FILE: lib/soap/rpc/element.rb ================================================ # SOAP4R - RPC element definition. # Copyright (C) 2000, 2001, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/baseData' module SOAP # Add method definitions for RPC to common definition in element.rb class SOAPBody < SOAPStruct public def request root_node end def response root = root_node if !@is_fault if root.nil? nil elsif root.is_a?(SOAPBasetype) root else # Initial element is [retval]. root[0] end else root end end def outparams root = root_node if !@is_fault and !root.nil? and !root.is_a?(SOAPBasetype) op = root[1..-1] op = nil if op && op.empty? op else nil end end def fault if @is_fault self['fault'] else nil end end def fault=(fault) @is_fault = true add_member('fault', fault) end end module RPC class RPCError < Error; end class MethodDefinitionError < RPCError; end class ParameterError < RPCError; end class SOAPMethod < SOAPStruct RETVAL = 'retval' IN = 'in' OUT = 'out' INOUT = 'inout' attr_reader :param_def attr_reader :inparam attr_reader :outparam attr_reader :retval_name attr_reader :retval_class_name def initialize(qname, param_def = nil) super(nil) @elename = qname @encodingstyle = nil @param_def = param_def @signature = [] @inparam_names = [] @inoutparam_names = [] @outparam_names = [] @inparam = {} @outparam = {} @retval_name = nil @retval_class_name = nil init_param(@param_def) if @param_def end def have_outparam? @outparam_names.size > 0 end def input_params collect_params(IN, INOUT) end def output_params collect_params(OUT, INOUT) end def set_param(params) params.each do |param, data| @inparam[param] = data data.elename.name = param data.parent = self end end def set_outparam(params) params.each do |param, data| @outparam[param] = data data.elename.name = param end end def SOAPMethod.param_count(param_def, *type) count = 0 param_def.each do |io_type, name, param_type| if type.include?(io_type) count += 1 end end count end def SOAPMethod.derive_rpc_param_def(obj, name, *param) if param.size == 1 and param[0].is_a?(Array) return param[0] end if param.empty? method = obj.method(name) param_names = (1..method.arity.abs).collect { |i| "p#{i}" } else param_names = param end create_rpc_param_def(param_names) end def SOAPMethod.create_rpc_param_def(param_names) param_def = [] param_names.each do |param_name| param_def.push([IN, param_name, nil]) end param_def.push([RETVAL, 'return', nil]) param_def end def SOAPMethod.create_doc_param_def(req_qnames, res_qnames) req_qnames = [req_qnames] if req_qnames.is_a?(XSD::QName) res_qnames = [res_qnames] if res_qnames.is_a?(XSD::QName) param_def = [] req_qnames.each do |qname| param_def << [IN, qname.name, [nil, qname.namespace, qname.name]] end res_qnames.each do |qname| param_def << [OUT, qname.name, [nil, qname.namespace, qname.name]] end param_def end private def collect_params(*type) names = [] @signature.each do |io_type, name, param_type| names << name if type.include?(io_type) end names end def init_param(param_def) param_def.each do |io_type, name, param_type| case io_type when IN @signature.push([IN, name, param_type]) @inparam_names.push(name) when OUT @signature.push([OUT, name, param_type]) @outparam_names.push(name) when INOUT @signature.push([INOUT, name, param_type]) @inoutparam_names.push(name) when RETVAL if @retval_name raise MethodDefinitionError.new('duplicated retval') end @retval_name = name @retval_class_name = nil if param_type if param_type[0].is_a?(String) @retval_class_name = Mapping.class_from_name(param_type[0]) else @retval_class_name = param_type[0] end end else raise MethodDefinitionError.new("unknown type: #{io_type}") end end end end class SOAPMethodRequest < SOAPMethod attr_accessor :soapaction def SOAPMethodRequest.create_request(qname, *params) param_def = [] param_value = [] i = 0 params.each do |param| param_name = "p#{i}" i += 1 param_def << [IN, param_name, nil] param_value << [param_name, param] end param_def << [RETVAL, 'return', nil] o = new(qname, param_def) o.set_param(param_value) o end def initialize(qname, param_def = nil, soapaction = nil) check_elename(qname) super(qname, param_def) @soapaction = soapaction end def each input_params.each do |name| unless @inparam[name] raise ParameterError.new("parameter: #{name} was not given") end yield(name, @inparam[name]) end end def dup req = self.class.new(@elename.dup, @param_def, @soapaction) req.encodingstyle = @encodingstyle req end def create_method_response(response_name = nil) response_name ||= XSD::QName.new(@elename.namespace, @elename.name + 'Response') SOAPMethodResponse.new(response_name, @param_def) end private def check_elename(qname) # NCName & ruby's method name unless /\A[\w_][\w\d_\-]*\z/ =~ qname.name raise MethodDefinitionError.new("element name '#{qname.name}' not allowed") end end end class SOAPMethodResponse < SOAPMethod def initialize(qname, param_def = nil) super(qname, param_def) @retval = nil end def retval=(retval) @retval = retval @retval.elename = @retval.elename.dup_name(@retval_name || 'return') retval.parent = self retval end def each if @retval_name and !@retval.is_a?(SOAPVoid) yield(@retval_name, @retval) end output_params.each do |name| unless @outparam[name] raise ParameterError.new("parameter: #{name} was not given") end yield(name, @outparam[name]) end end end # To return(?) void explicitly. # def foo(input_var) # ... # return SOAP::RPC::SOAPVoid.new # end class SOAPVoid < XSD::XSDAnySimpleType include SOAPBasetype extend SOAPModuleUtils Name = XSD::QName.new(Mapping::RubyCustomTypeNamespace, nil) public def initialize() @elename = Name @id = nil @precedents = [] @parent = nil end end end end ================================================ FILE: lib/soap/rpc/httpserver.rb ================================================ # SOAP4R - WEBrick HTTP Server # Copyright (C) 2003, 2004 by NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'logger' require 'soap/rpc/soaplet' require 'soap/streamHandler' require 'webrick' module SOAP module RPC class HTTPServer < Logger::Application attr_reader :server attr_accessor :default_namespace def initialize(config) super(config[:SOAPHTTPServerApplicationName] || self.class.name) @default_namespace = config[:SOAPDefaultNamespace] @webrick_config = config.dup self.level = Logger::Severity::ERROR # keep silent by default @webrick_config[:Logger] ||= @log @log = @webrick_config[:Logger] # sync logger of App and HTTPServer @router = ::SOAP::RPC::Router.new(self.class.name) @soaplet = ::SOAP::RPC::SOAPlet.new(@router) on_init @server = WEBrick::HTTPServer.new(@webrick_config) @server.mount('/', @soaplet) end def on_init # do extra initialization in a derived class if needed. end def status @server.status if @server end def shutdown @server.shutdown if @server end def mapping_registry @router.mapping_registry end def mapping_registry=(mapping_registry) @router.mapping_registry = mapping_registry end def generate_explicit_type @router.generate_explicit_type end def generate_explicit_type=(generate_explicit_type) @router.generate_explicit_type = generate_explicit_type end # servant entry interface def add_rpc_request_servant(factory, namespace = @default_namespace) @router.add_rpc_request_servant(factory, namespace) end def add_rpc_servant(obj, namespace = @default_namespace) @router.add_rpc_servant(obj, namespace) end def add_request_headerhandler(factory) @router.add_request_headerhandler(factory) end def add_headerhandler(obj) @router.add_headerhandler(obj) end alias add_rpc_headerhandler add_headerhandler # method entry interface def add_rpc_method(obj, name, *param) add_rpc_method_as(obj, name, name, *param) end alias add_method add_rpc_method def add_rpc_method_as(obj, name, name_as, *param) qname = XSD::QName.new(@default_namespace, name_as) soapaction = nil param_def = SOAPMethod.derive_rpc_param_def(obj, name, *param) @router.add_rpc_operation(obj, qname, soapaction, name, param_def) end alias add_method_as add_rpc_method_as def add_document_method(obj, soapaction, name, req_qnames, res_qnames) param_def = SOAPMethod.create_doc_param_def(req_qnames, res_qnames) @router.add_document_operation(obj, soapaction, name, param_def) end def add_rpc_operation(receiver, qname, soapaction, name, param_def, opt = {}) @router.add_rpc_operation(receiver, qname, soapaction, name, param_def, opt) end def add_rpc_request_operation(factory, qname, soapaction, name, param_def, opt = {}) @router.add_rpc_request_operation(factory, qname, soapaction, name, param_def, opt) end def add_document_operation(receiver, soapaction, name, param_def, opt = {}) @router.add_document_operation(receiver, soapaction, name, param_def, opt) end def add_document_request_operation(factory, soapaction, name, param_def, opt = {}) @router.add_document_request_operation(factory, soapaction, name, param_def, opt) end private def run @server.start end end end end ================================================ FILE: lib/soap/rpc/proxy.rb ================================================ # SOAP4R - RPC Proxy library. # Copyright (C) 2000, 2003-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/soap' require 'soap/processor' require 'soap/mapping' require 'soap/rpc/rpc' require 'soap/rpc/element' require 'soap/streamHandler' require 'soap/mimemessage' module SOAP module RPC class Proxy include SOAP public attr_accessor :soapaction attr_accessor :mandatorycharset attr_accessor :allow_unqualified_element attr_accessor :default_encodingstyle attr_accessor :generate_explicit_type attr_reader :headerhandler attr_reader :streamhandler attr_accessor :mapping_registry attr_accessor :literal_mapping_registry attr_reader :operation def initialize(endpoint_url, soapaction, options) @endpoint_url = endpoint_url @soapaction = soapaction @options = options @streamhandler = HTTPStreamHandler.new( @options["protocol.http"] ||= ::SOAP::Property.new) @operation = {} @mandatorycharset = nil @allow_unqualified_element = true @default_encodingstyle = nil @generate_explicit_type = true @headerhandler = Header::HandlerSet.new @mapping_registry = nil @literal_mapping_registry = ::SOAP::Mapping::WSDLLiteralRegistry.new end def inspect "#<#{self.class}:#{@endpoint_url}>" end def endpoint_url @endpoint_url end def endpoint_url=(endpoint_url) @endpoint_url = endpoint_url reset_stream end def reset_stream @streamhandler.reset(@endpoint_url) end def set_wiredump_file_base(wiredump_file_base) @streamhandler.wiredump_file_base = wiredump_file_base end def test_loopback_response @streamhandler.test_loopback_response end def add_rpc_operation(qname, soapaction, name, param_def, opt = {}) opt[:request_qname] = qname opt[:request_style] ||= :rpc opt[:response_style] ||= :rpc opt[:request_use] ||= :encoded opt[:response_use] ||= :encoded @operation[name] = Operation.new(soapaction, param_def, opt) end def add_document_operation(soapaction, name, param_def, opt = {}) opt[:request_style] ||= :document opt[:response_style] ||= :document opt[:request_use] ||= :literal opt[:response_use] ||= :literal # default values of these values are unqualified in XML Schema. # set true for backward compatibility. unless opt.key?(:elementformdefault) opt[:elementformdefault] = true end unless opt.key?(:attributeformdefault) opt[:attributeformdefault] = true end @operation[name] = Operation.new(soapaction, param_def, opt) end # add_method is for shortcut of typical rpc/encoded method definition. alias add_method add_rpc_operation alias add_rpc_method add_rpc_operation alias add_document_method add_document_operation def invoke(req_header, req_body, opt = nil) opt ||= create_encoding_opt route(req_header, req_body, opt, opt) end def call(name, *params) unless op_info = @operation[name] raise MethodDefinitionError, "method: #{name} not defined" end mapping_opt = create_mapping_opt req_header = create_request_header req_body = SOAPBody.new( op_info.request_body(params, @mapping_registry, @literal_mapping_registry, mapping_opt) ) reqopt = create_encoding_opt( :soapaction => op_info.soapaction || @soapaction, :envelopenamespace => @options["soap.envelope.requestnamespace"], :default_encodingstyle => @default_encodingstyle || op_info.request_default_encodingstyle, :elementformdefault => op_info.elementformdefault, :attributeformdefault => op_info.attributeformdefault ) resopt = create_encoding_opt( :envelopenamespace => @options["soap.envelope.responsenamespace"], :default_encodingstyle => @default_encodingstyle || op_info.response_default_encodingstyle, :elementformdefault => op_info.elementformdefault, :attributeformdefault => op_info.attributeformdefault ) env = route(req_header, req_body, reqopt, resopt) raise EmptyResponseError unless env receive_headers(env.header) begin check_fault(env.body) rescue ::SOAP::FaultError => e op_info.raise_fault(e, @mapping_registry, @literal_mapping_registry) end op_info.response_obj(env.body, @mapping_registry, @literal_mapping_registry, mapping_opt) end def route(req_header, req_body, reqopt, resopt) req_env = ::SOAP::SOAPEnvelope.new(req_header, req_body) unless reqopt[:envelopenamespace].nil? set_envelopenamespace(req_env, reqopt[:envelopenamespace]) end reqopt[:external_content] = nil conn_data = marshal(req_env, reqopt) if ext = reqopt[:external_content] mime = MIMEMessage.new ext.each do |k, v| mime.add_attachment(v.data) end mime.add_part(conn_data.send_string + "\r\n") mime.close conn_data.send_string = mime.content_str conn_data.send_contenttype = mime.headers['content-type'].str end conn_data = @streamhandler.send(@endpoint_url, conn_data, reqopt[:soapaction]) if conn_data.receive_string.empty? return nil end unmarshal(conn_data, resopt) end def check_fault(body) if body.fault raise SOAP::FaultError.new(body.fault) end end private def set_envelopenamespace(env, namespace) env.elename = XSD::QName.new(namespace, env.elename.name) if env.header env.header.elename = XSD::QName.new(namespace, env.header.elename.name) end if env.body env.body.elename = XSD::QName.new(namespace, env.body.elename.name) end end def create_request_header headers = @headerhandler.on_outbound if headers.empty? nil else h = ::SOAP::SOAPHeader.new headers.each do |header| h.add(header.elename.name, header) end h end end def receive_headers(headers) @headerhandler.on_inbound(headers) if headers end def marshal(env, opt) send_string = Processor.marshal(env, opt) StreamHandler::ConnectionData.new(send_string) end def unmarshal(conn_data, opt) contenttype = conn_data.receive_contenttype if /#{MIMEMessage::MultipartContentType}/i =~ contenttype opt[:external_content] = {} mime = MIMEMessage.parse("Content-Type: " + contenttype, conn_data.receive_string) mime.parts.each do |part| value = Attachment.new(part.content) value.contentid = part.contentid obj = SOAPAttachment.new(value) opt[:external_content][value.contentid] = obj if value.contentid end opt[:charset] = @mandatorycharset || StreamHandler.parse_media_type(mime.root.headers['content-type'].str) env = Processor.unmarshal(mime.root.content, opt) else opt[:charset] = @mandatorycharset || ::SOAP::StreamHandler.parse_media_type(contenttype) env = Processor.unmarshal(conn_data.receive_string, opt) end unless env.is_a?(::SOAP::SOAPEnvelope) raise ResponseFormatError.new( "response is not a SOAP envelope: #{conn_data.receive_string}") end env end def create_header(headers) header = SOAPHeader.new() headers.each do |content, mustunderstand, encodingstyle| header.add(SOAPHeaderItem.new(content, mustunderstand, encodingstyle)) end header end def create_encoding_opt(hash = nil) opt = {} opt[:default_encodingstyle] = @default_encodingstyle opt[:allow_unqualified_element] = @allow_unqualified_element opt[:generate_explicit_type] = @generate_explicit_type opt[:no_indent] = @options["soap.envelope.no_indent"] opt[:use_numeric_character_reference] = @options["soap.envelope.use_numeric_character_reference"] opt.update(hash) if hash opt end def create_mapping_opt(hash = nil) opt = { :external_ces => @options["soap.mapping.external_ces"] } opt.update(hash) if hash opt end class Operation attr_reader :soapaction attr_reader :request_style attr_reader :response_style attr_reader :request_use attr_reader :response_use attr_reader :elementformdefault attr_reader :attributeformdefault def initialize(soapaction, param_def, opt) @soapaction = soapaction @request_style = opt[:request_style] @response_style = opt[:response_style] @request_use = opt[:request_use] @response_use = opt[:response_use] # set nil(unqualified) by default @elementformdefault = opt[:elementformdefault] @attributeformdefault = opt[:attributeformdefault] check_style(@request_style) check_style(@response_style) check_use(@request_use) check_use(@response_use) if @request_style == :rpc @rpc_request_qname = opt[:request_qname] if @rpc_request_qname.nil? raise MethodDefinitionError.new("rpc_request_qname must be given") end @rpc_method_factory = RPC::SOAPMethodRequest.new(@rpc_request_qname, param_def, @soapaction) else @doc_request_qnames = [] @doc_request_qualified = [] @doc_response_qnames = [] @doc_response_qualified = [] param_def.each do |inout, paramname, typeinfo, eleinfo| klass_not_used, nsdef, namedef = typeinfo qualified = eleinfo if namedef.nil? raise MethodDefinitionError.new("qname must be given") end case inout when SOAPMethod::IN @doc_request_qnames << XSD::QName.new(nsdef, namedef) @doc_request_qualified << qualified when SOAPMethod::OUT @doc_response_qnames << XSD::QName.new(nsdef, namedef) @doc_response_qualified << qualified else raise MethodDefinitionError.new( "illegal inout definition for document style: #{inout}") end end end end def request_default_encodingstyle (@request_use == :encoded) ? EncodingNamespace : LiteralNamespace end def response_default_encodingstyle (@response_use == :encoded) ? EncodingNamespace : LiteralNamespace end def request_body(values, mapping_registry, literal_mapping_registry, opt) if @request_style == :rpc request_rpc(values, mapping_registry, literal_mapping_registry, opt) else request_doc(values, mapping_registry, literal_mapping_registry, opt) end end def response_obj(body, mapping_registry, literal_mapping_registry, opt) if @response_style == :rpc response_rpc(body, mapping_registry, literal_mapping_registry, opt) else response_doc(body, mapping_registry, literal_mapping_registry, opt) end end def raise_fault(e, mapping_registry, literal_mapping_registry) if @response_style == :rpc Mapping.fault2exception(e, mapping_registry) else Mapping.fault2exception(e, literal_mapping_registry) end end private def check_style(style) unless [:rpc, :document].include?(style) raise MethodDefinitionError.new("unknown style: #{style}") end end def check_use(use) unless [:encoded, :literal].include?(use) raise MethodDefinitionError.new("unknown use: #{use}") end end def request_rpc(values, mapping_registry, literal_mapping_registry, opt) if @request_use == :encoded request_rpc_enc(values, mapping_registry, opt) else request_rpc_lit(values, literal_mapping_registry, opt) end end def request_doc(values, mapping_registry, literal_mapping_registry, opt) if @request_use == :encoded request_doc_enc(values, mapping_registry, opt) else request_doc_lit(values, literal_mapping_registry, opt) end end def request_rpc_enc(values, mapping_registry, opt) method = @rpc_method_factory.dup names = method.input_params obj = create_request_obj(names, values) soap = Mapping.obj2soap(obj, mapping_registry, @rpc_request_qname, opt) method.set_param(soap) method end def request_rpc_lit(values, mapping_registry, opt) method = @rpc_method_factory.dup params = {} idx = 0 method.input_params.each do |name| params[name] = Mapping.obj2soap(values[idx], mapping_registry, XSD::QName.new(nil, name), opt) idx += 1 end method.set_param(params) method end def request_doc_enc(values, mapping_registry, opt) (0...values.size).collect { |idx| ele = Mapping.obj2soap(values[idx], mapping_registry, nil, opt) ele.elename = @doc_request_qnames[idx] ele } end def request_doc_lit(values, mapping_registry, opt) (0...values.size).collect { |idx| ele = Mapping.obj2soap(values[idx], mapping_registry, @doc_request_qnames[idx], opt) ele.encodingstyle = LiteralNamespace if ele.respond_to?(:qualified) ele.qualified = @doc_request_qualified[idx] end ele } end def response_rpc(body, mapping_registry, literal_mapping_registry, opt) if @response_use == :encoded response_rpc_enc(body, mapping_registry, opt) else response_rpc_lit(body, literal_mapping_registry, opt) end end def response_doc(body, mapping_registry, literal_mapping_registry, opt) if @response_use == :encoded return *response_doc_enc(body, mapping_registry, opt) else return *response_doc_lit(body, literal_mapping_registry, opt) end end def response_rpc_enc(body, mapping_registry, opt) ret = nil if body.response ret = Mapping.soap2obj(body.response, mapping_registry, @rpc_method_factory.retval_class_name, opt) end if body.outparams outparams = body.outparams.collect { |outparam| Mapping.soap2obj(outparam, mapping_registry, nil, opt) } [ret].concat(outparams) else ret end end def response_rpc_lit(body, mapping_registry, opt) body.root_node.collect { |key, value| Mapping.soap2obj(value, mapping_registry, @rpc_method_factory.retval_class_name, opt) } end def response_doc_enc(body, mapping_registry, opt) body.collect { |key, value| Mapping.soap2obj(value, mapping_registry, nil, opt) } end def response_doc_lit(body, mapping_registry, opt) body.collect { |key, value| Mapping.soap2obj(value, mapping_registry) } end def create_request_obj(names, params) o = Object.new idx = 0 while idx < params.length o.instance_variable_set('@' + names[idx], params[idx]) idx += 1 end o end end end end end ================================================ FILE: lib/soap/rpc/router.rb ================================================ # SOAP4R - RPC Routing library # Copyright (C) 2001, 2002, 2004, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/soap' require 'soap/processor' require 'soap/mapping' require 'soap/mapping/wsdlliteralregistry' require 'soap/rpc/rpc' require 'soap/rpc/element' require 'soap/streamHandler' require 'soap/mimemessage' require 'soap/header/handlerset' module SOAP module RPC class Router include SOAP attr_reader :actor attr_accessor :mapping_registry attr_accessor :literal_mapping_registry attr_accessor :generate_explicit_type attr_accessor :external_ces def initialize(actor) @actor = actor @mapping_registry = nil @headerhandler = Header::HandlerSet.new @literal_mapping_registry = ::SOAP::Mapping::WSDLLiteralRegistry.new @generate_explicit_type = true @external_ces = nil @operation_by_soapaction = {} @operation_by_qname = {} @headerhandlerfactory = [] end ### ## header handler interface # def add_request_headerhandler(factory) unless factory.respond_to?(:create) raise TypeError.new("factory must respond to 'create'") end @headerhandlerfactory << factory end def add_headerhandler(handler) @headerhandler.add(handler) end ### ## servant definition interface # def add_rpc_request_servant(factory, namespace) unless factory.respond_to?(:create) raise TypeError.new("factory must respond to 'create'") end obj = factory.create # a dummy instance for introspection ::SOAP::RPC.defined_methods(obj).each do |name| begin qname = XSD::QName.new(namespace, name) param_def = ::SOAP::RPC::SOAPMethod.derive_rpc_param_def(obj, name) opt = create_styleuse_option(:rpc, :encoded) add_rpc_request_operation(factory, qname, nil, name, param_def, opt) rescue SOAP::RPC::MethodDefinitionError => e p e if $DEBUG end end end def add_rpc_servant(obj, namespace) ::SOAP::RPC.defined_methods(obj).each do |name| begin qname = XSD::QName.new(namespace, name) param_def = ::SOAP::RPC::SOAPMethod.derive_rpc_param_def(obj, name) opt = create_styleuse_option(:rpc, :encoded) add_rpc_operation(obj, qname, nil, name, param_def, opt) rescue SOAP::RPC::MethodDefinitionError => e p e if $DEBUG end end end alias add_servant add_rpc_servant ### ## operation definition interface # def add_rpc_operation(receiver, qname, soapaction, name, param_def, opt = {}) ensure_styleuse_option(opt, :rpc, :encoded) opt[:request_qname] = qname op = ApplicationScopeOperation.new(soapaction, receiver, name, param_def, opt) if opt[:request_style] != :rpc raise RPCRoutingError.new("illegal request_style given") end assign_operation(soapaction, qname, op) end alias add_method add_rpc_operation alias add_rpc_method add_rpc_operation def add_rpc_request_operation(factory, qname, soapaction, name, param_def, opt = {}) ensure_styleuse_option(opt, :rpc, :encoded) opt[:request_qname] = qname op = RequestScopeOperation.new(soapaction, factory, name, param_def, opt) if opt[:request_style] != :rpc raise RPCRoutingError.new("illegal request_style given") end assign_operation(soapaction, qname, op) end def add_document_operation(receiver, soapaction, name, param_def, opt = {}) # # adopt workaround for doc/lit wrapper method # (you should consider to simply use rpc/lit service) # #unless soapaction # raise RPCRoutingError.new("soapaction is a must for document method") #end ensure_styleuse_option(opt, :document, :literal) op = ApplicationScopeOperation.new(soapaction, receiver, name, param_def, opt) if opt[:request_style] != :document raise RPCRoutingError.new("illegal request_style given") end assign_operation(soapaction, first_input_part_qname(param_def), op) end alias add_document_method add_document_operation def add_document_request_operation(factory, soapaction, name, param_def, opt = {}) # # adopt workaround for doc/lit wrapper method # (you should consider to simply use rpc/lit service) # #unless soapaction # raise RPCRoutingError.new("soapaction is a must for document method") #end ensure_styleuse_option(opt, :document, :literal) op = RequestScopeOperation.new(soapaction, receiver, name, param_def, opt) if opt[:request_style] != :document raise RPCRoutingError.new("illegal request_style given") end assign_operation(soapaction, first_input_part_qname(param_def), op) end def route(conn_data) # we cannot set request_default_encodingsyle before parsing the content. env = unmarshal(conn_data) if env.nil? raise ArgumentError.new("illegal SOAP marshal format") end op = lookup_operation(conn_data.soapaction, env.body) headerhandler = @headerhandler.dup @headerhandlerfactory.each do |f| headerhandler.add(f.create) end receive_headers(headerhandler, env.header) soap_response = default_encodingstyle = nil begin soap_response = op.call(env.body, @mapping_registry, @literal_mapping_registry, create_mapping_opt) default_encodingstyle = op.response_default_encodingstyle rescue Exception soap_response = fault($!) default_encodingstyle = nil end conn_data.is_fault = true if soap_response.is_a?(SOAPFault) header = call_headers(headerhandler) body = SOAPBody.new(soap_response) env = SOAPEnvelope.new(header, body) marshal(conn_data, env, default_encodingstyle) end # Create fault response string. def create_fault_response(e) env = SOAPEnvelope.new(SOAPHeader.new, SOAPBody.new(fault(e))) opt = {} opt[:external_content] = nil response_string = Processor.marshal(env, opt) conn_data = StreamHandler::ConnectionData.new(response_string) conn_data.is_fault = true if ext = opt[:external_content] mimeize(conn_data, ext) end conn_data end private def first_input_part_qname(param_def) param_def.each do |inout, paramname, typeinfo| if inout == SOAPMethod::IN klass, nsdef, namedef = typeinfo return XSD::QName.new(nsdef, namedef) end end nil end def create_styleuse_option(style, use) opt = {} opt[:request_style] = opt[:response_style] = style opt[:request_use] = opt[:response_use] = use opt end def ensure_styleuse_option(opt, style, use) opt[:request_style] ||= style opt[:response_style] ||= style opt[:request_use] ||= use opt[:response_use] ||= use end def assign_operation(soapaction, qname, op) assigned = false if soapaction and !soapaction.empty? @operation_by_soapaction[soapaction] = op assigned = true end if qname @operation_by_qname[qname] = op assigned = true end unless assigned raise RPCRoutingError.new("cannot assign operation") end end def lookup_operation(soapaction, body) if op = @operation_by_soapaction[soapaction] return op end qname = body.root_node.elename if op = @operation_by_qname[qname] return op end if soapaction raise RPCRoutingError.new( "operation: #{soapaction} #{qname} not supported") else raise RPCRoutingError.new("operation: #{qname} not supported") end end def call_headers(headerhandler) headers = headerhandler.on_outbound if headers.empty? nil else h = ::SOAP::SOAPHeader.new headers.each do |header| h.add(header.elename.name, header) end h end end def receive_headers(headerhandler, headers) headerhandler.on_inbound(headers) if headers end def unmarshal(conn_data) opt = {} contenttype = conn_data.receive_contenttype if /#{MIMEMessage::MultipartContentType}/i =~ contenttype opt[:external_content] = {} mime = MIMEMessage.parse("Content-Type: " + contenttype, conn_data.receive_string) mime.parts.each do |part| value = Attachment.new(part.content) value.contentid = part.contentid obj = SOAPAttachment.new(value) opt[:external_content][value.contentid] = obj if value.contentid end opt[:charset] = StreamHandler.parse_media_type(mime.root.headers['content-type'].str) env = Processor.unmarshal(mime.root.content, opt) else opt[:charset] = ::SOAP::StreamHandler.parse_media_type(contenttype) env = Processor.unmarshal(conn_data.receive_string, opt) end charset = opt[:charset] conn_data.send_contenttype = "text/xml; charset=\"#{charset}\"" env end def marshal(conn_data, env, default_encodingstyle = nil) opt = {} opt[:external_content] = nil opt[:default_encodingstyle] = default_encodingstyle opt[:generate_explicit_type] = @generate_explicit_type response_string = Processor.marshal(env, opt) conn_data.send_string = response_string if ext = opt[:external_content] mimeize(conn_data, ext) end conn_data end def mimeize(conn_data, ext) mime = MIMEMessage.new ext.each do |k, v| mime.add_attachment(v.data) end mime.add_part(conn_data.send_string + "\r\n") mime.close conn_data.send_string = mime.content_str conn_data.send_contenttype = mime.headers['content-type'].str conn_data end # Create fault response. def fault(e) detail = Mapping::SOAPException.new(e) SOAPFault.new( SOAPString.new('Server'), SOAPString.new(e.to_s), SOAPString.new(@actor), Mapping.obj2soap(detail, @mapping_registry)) end def create_mapping_opt { :external_ces => @external_ces } end class Operation attr_reader :name attr_reader :soapaction attr_reader :request_style attr_reader :response_style attr_reader :request_use attr_reader :response_use def initialize(soapaction, name, param_def, opt) @soapaction = soapaction @name = name @request_style = opt[:request_style] @response_style = opt[:response_style] @request_use = opt[:request_use] @response_use = opt[:response_use] check_style(@request_style) check_style(@response_style) check_use(@request_use) check_use(@response_use) if @response_style == :rpc request_qname = opt[:request_qname] or raise @rpc_method_factory = RPC::SOAPMethodRequest.new(request_qname, param_def, @soapaction) @rpc_response_qname = opt[:response_qname] else @doc_request_qnames = [] @doc_request_qualified = [] @doc_response_qnames = [] @doc_response_qualified = [] param_def.each do |inout, paramname, typeinfo, eleinfo| klass, nsdef, namedef = typeinfo qualified = eleinfo case inout when SOAPMethod::IN @doc_request_qnames << XSD::QName.new(nsdef, namedef) @doc_request_qualified << qualified when SOAPMethod::OUT @doc_response_qnames << XSD::QName.new(nsdef, namedef) @doc_response_qualified << qualified else raise ArgumentError.new( "illegal inout definition for document style: #{inout}") end end end end def request_default_encodingstyle (@request_use == :encoded) ? EncodingNamespace : LiteralNamespace end def response_default_encodingstyle (@response_use == :encoded) ? EncodingNamespace : LiteralNamespace end def call(body, mapping_registry, literal_mapping_registry, opt) if @request_style == :rpc values = request_rpc(body, mapping_registry, literal_mapping_registry, opt) else values = request_document(body, mapping_registry, literal_mapping_registry, opt) end result = receiver.method(@name.intern).call(*values) return result if result.is_a?(SOAPFault) if @response_style == :rpc response_rpc(result, mapping_registry, literal_mapping_registry, opt) else response_doc(result, mapping_registry, literal_mapping_registry, opt) end end private def receiver raise NotImplementedError.new('must be defined in derived class') end def request_rpc(body, mapping_registry, literal_mapping_registry, opt) request = body.request unless request.is_a?(SOAPStruct) raise RPCRoutingError.new("not an RPC style") end if @request_use == :encoded request_rpc_enc(request, mapping_registry, opt) else request_rpc_lit(request, literal_mapping_registry, opt) end end def request_document(body, mapping_registry, literal_mapping_registry, opt) # ToDo: compare names with @doc_request_qnames if @request_use == :encoded request_doc_enc(body, mapping_registry, opt) else request_doc_lit(body, literal_mapping_registry, opt) end end def request_rpc_enc(request, mapping_registry, opt) param = Mapping.soap2obj(request, mapping_registry, nil, opt) request.collect { |key, value| param[key] } end def request_rpc_lit(request, mapping_registry, opt) request.collect { |key, value| Mapping.soap2obj(value, mapping_registry, nil, opt) } end def request_doc_enc(body, mapping_registry, opt) body.collect { |key, value| Mapping.soap2obj(value, mapping_registry, nil, opt) } end def request_doc_lit(body, mapping_registry, opt) body.collect { |key, value| Mapping.soap2obj(value, mapping_registry, nil, opt) } end def response_rpc(result, mapping_registry, literal_mapping_registry, opt) if @response_use == :encoded response_rpc_enc(result, mapping_registry, opt) else response_rpc_lit(result, literal_mapping_registry, opt) end end def response_doc(result, mapping_registry, literal_mapping_registry, opt) if @doc_response_qnames.size == 1 and !result.is_a?(Array) result = [result] end if result.size != @doc_response_qnames.size raise "required #{@doc_response_qnames.size} responses " + "but #{result.size} given" end if @response_use == :encoded response_doc_enc(result, mapping_registry, opt) else response_doc_lit(result, literal_mapping_registry, opt) end end def response_rpc_enc(result, mapping_registry, opt) soap_response = @rpc_method_factory.create_method_response(@rpc_response_qname) if soap_response.have_outparam? unless result.is_a?(Array) raise RPCRoutingError.new("out parameter was not returned") end outparams = {} i = 1 soap_response.output_params.each do |outparam| outparams[outparam] = Mapping.obj2soap(result[i], mapping_registry, nil, opt) i += 1 end soap_response.set_outparam(outparams) soap_response.retval = Mapping.obj2soap(result[0], mapping_registry, nil, opt) else soap_response.retval = Mapping.obj2soap(result, mapping_registry, nil, opt) end soap_response end def response_rpc_lit(result, mapping_registry, opt) soap_response = @rpc_method_factory.create_method_response(@rpc_response_qname) if soap_response.have_outparam? unless result.is_a?(Array) raise RPCRoutingError.new("out parameter was not returned") end outparams = {} i = 1 soap_response.output_params.each do |outparam| outparams[outparam] = Mapping.obj2soap(result[i], mapping_registry, XSD::QName.new(nil, outparam), opt) i += 1 end soap_response.set_outparam(outparams) soap_response.retval = Mapping.obj2soap(result[0], mapping_registry, XSD::QName.new(nil, soap_response.elename), opt) else soap_response.retval = Mapping.obj2soap(result, mapping_registry, XSD::QName.new(nil, soap_response.elename), opt) end soap_response end def response_doc_enc(result, mapping_registry, opt) (0...result.size).collect { |idx| ele = Mapping.obj2soap(result[idx], mapping_registry, nil, opt) ele.elename = @doc_response_qnames[idx] ele } end def response_doc_lit(result, mapping_registry, opt) (0...result.size).collect { |idx| ele = Mapping.obj2soap(result[idx], mapping_registry, @doc_response_qnames[idx]) ele.encodingstyle = LiteralNamespace if ele.respond_to?(:qualified) ele.qualified = @doc_response_qualified[idx] end ele } end def check_style(style) unless [:rpc, :document].include?(style) raise ArgumentError.new("unknown style: #{style}") end end def check_use(use) unless [:encoded, :literal].include?(use) raise ArgumentError.new("unknown use: #{use}") end end end class ApplicationScopeOperation < Operation def initialize(soapaction, receiver, name, param_def, opt) super(soapaction, name, param_def, opt) @receiver = receiver end private def receiver @receiver end end class RequestScopeOperation < Operation def initialize(soapaction, receiver_factory, name, param_def, opt) super(soapaction, name, param_def, opt) unless receiver_factory.respond_to?(:create) raise TypeError.new("factory must respond to 'create'") end @receiver_factory = receiver_factory end private def receiver @receiver_factory.create end end end end end ================================================ FILE: lib/soap/rpc/rpc.rb ================================================ # SOAP4R - RPC utility. # Copyright (C) 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module SOAP module RPC ServerException = Mapping::MappedException def self.defined_methods(obj) if obj.is_a?(Module) obj.methods - Module.methods else obj.methods - Object.instance_methods(true) end end end end ================================================ FILE: lib/soap/rpc/soaplet.rb ================================================ # SOAP4R - SOAP handler servlet for WEBrick # Copyright (C) 2001-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'webrick/httpservlet/abstract' require 'webrick/httpstatus' require 'soap/rpc/router' require 'soap/streamHandler' begin require 'stringio' require 'zlib' rescue LoadError warn("Loading stringio or zlib failed. No gzipped response supported.") if $DEBUG end warn("Overriding WEBrick::Log#debug") if $DEBUG require 'webrick/log' module WEBrick class Log < BasicLog alias __debug debug def debug(msg = nil) if block_given? and msg.nil? __debug(yield) else __debug(msg) end end end end module SOAP module RPC class SOAPlet < WEBrick::HTTPServlet::AbstractServlet public attr_reader :options def initialize(router = nil) @router = router || ::SOAP::RPC::Router.new(self.class.name) @options = {} @config = {} end # for backward compatibility def app_scope_router @router end # for backward compatibility def add_servant(obj, namespace) @router.add_rpc_servant(obj, namespace) end def allow_content_encoding_gzip=(allow) @options[:allow_content_encoding_gzip] = allow end ### ## Servlet interfaces for WEBrick. # def get_instance(config, *options) @config = config self end def require_path_info? false end def do_GET(req, res) res.header['Allow'] = 'POST' raise WEBrick::HTTPStatus::MethodNotAllowed, "GET request not allowed" end def do_POST(req, res) logger.debug { "SOAP request: " + req.body } if logger begin conn_data = ::SOAP::StreamHandler::ConnectionData.new setup_req(conn_data, req) @router.external_ces = @options[:external_ces] conn_data = @router.route(conn_data) setup_res(conn_data, req, res) rescue Exception => e conn_data = @router.create_fault_response(e) res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR res.body = conn_data.send_string res['content-type'] = conn_data.send_contenttype || "text/xml" end if res.body.is_a?(IO) res.chunked = true logger.debug { "SOAP response: (chunked response not logged)" } if logger else logger.debug { "SOAP response: " + res.body } if logger end end private def logger @config[:Logger] end def setup_req(conn_data, req) conn_data.receive_string = req.body conn_data.receive_contenttype = req['content-type'] conn_data.soapaction = parse_soapaction(req.meta_vars['HTTP_SOAPACTION']) end def setup_res(conn_data, req, res) res['content-type'] = conn_data.send_contenttype if conn_data.is_fault res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR end if outstring = encode_gzip(req, conn_data.send_string) res['content-encoding'] = 'gzip' res['content-length'] = outstring.size res.body = outstring else res.body = conn_data.send_string end end def parse_soapaction(soapaction) if !soapaction.nil? and !soapaction.empty? if /^"(.+)"$/ =~ soapaction return $1 end end nil end def encode_gzip(req, outstring) unless encode_gzip?(req) return nil end begin ostream = StringIO.new gz = Zlib::GzipWriter.new(ostream) gz.write(outstring) ostream.string ensure gz.close end end def encode_gzip?(req) @options[:allow_content_encoding_gzip] and defined?(::Zlib) and req['accept-encoding'] and req['accept-encoding'].split(/,\s*/).include?('gzip') end end end end ================================================ FILE: lib/soap/rpc/standaloneServer.rb ================================================ # SOAP4R - WEBrick Server # Copyright (C) 2003 by NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/rpc/httpserver' module SOAP module RPC class StandaloneServer < HTTPServer def initialize(appname, default_namespace, host = "0.0.0.0", port = 8080) @appname = appname @default_namespace = default_namespace @host = host @port = port super(create_config) end alias add_servant add_rpc_servant alias add_headerhandler add_rpc_headerhandler private def create_config { :BindAddress => @host, :Port => @port, :AccessLog => [], :SOAPDefaultNamespace => @default_namespace, :SOAPHTTPServerApplicationName => @appname, } end end end end ================================================ FILE: lib/soap/soap.rb ================================================ # soap/soap.rb: SOAP4R - Base definitions. # Copyright (C) 2000-2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' require 'xsd/charset' module SOAP VERSION = Version = '1.5.5' PropertyName = 'soap/property' EnvelopeNamespace = 'http://schemas.xmlsoap.org/soap/envelope/' EncodingNamespace = 'http://schemas.xmlsoap.org/soap/encoding/' LiteralNamespace = 'http://xml.apache.org/xml-soap/literalxml' NextActor = 'http://schemas.xmlsoap.org/soap/actor/next' EleEnvelope = 'Envelope' EleHeader = 'Header' EleBody = 'Body' EleFault = 'Fault' EleFaultString = 'faultstring' EleFaultActor = 'faultactor' EleFaultCode = 'faultcode' EleFaultDetail = 'detail' AttrMustUnderstand = 'mustUnderstand' AttrEncodingStyle = 'encodingStyle' AttrActor = 'actor' AttrRoot = 'root' AttrArrayType = 'arrayType' AttrOffset = 'offset' AttrPosition = 'position' ValueArray = 'Array' EleEnvelopeName = XSD::QName.new(EnvelopeNamespace, EleEnvelope).freeze EleHeaderName = XSD::QName.new(EnvelopeNamespace, EleHeader).freeze EleBodyName = XSD::QName.new(EnvelopeNamespace, EleBody).freeze EleFaultName = XSD::QName.new(EnvelopeNamespace, EleFault).freeze EleFaultStringName = XSD::QName.new(nil, EleFaultString).freeze EleFaultActorName = XSD::QName.new(nil, EleFaultActor).freeze EleFaultCodeName = XSD::QName.new(nil, EleFaultCode).freeze EleFaultDetailName = XSD::QName.new(nil, EleFaultDetail).freeze AttrMustUnderstandName = XSD::QName.new(EnvelopeNamespace, AttrMustUnderstand).freeze AttrEncodingStyleName = XSD::QName.new(EnvelopeNamespace, AttrEncodingStyle).freeze AttrRootName = XSD::QName.new(EncodingNamespace, AttrRoot).freeze AttrArrayTypeName = XSD::QName.new(EncodingNamespace, AttrArrayType).freeze AttrOffsetName = XSD::QName.new(EncodingNamespace, AttrOffset).freeze AttrPositionName = XSD::QName.new(EncodingNamespace, AttrPosition).freeze ValueArrayName = XSD::QName.new(EncodingNamespace, ValueArray).freeze Base64Literal = 'base64' SOAPNamespaceTag = 'env' XSDNamespaceTag = 'xsd' XSINamespaceTag = 'xsi' MediaType = 'text/xml' class Error < StandardError; end class StreamError < Error; end class HTTPStreamError < StreamError; end class PostUnavailableError < HTTPStreamError; end class MPostUnavailableError < HTTPStreamError; end class ArrayIndexOutOfBoundsError < Error; end class ArrayStoreError < Error; end class RPCRoutingError < Error; end class EmptyResponseError < Error; end class ResponseFormatError < Error; end class UnhandledMustUnderstandHeaderError < Error; end class FaultError < Error attr_reader :faultcode attr_reader :faultstring attr_reader :faultactor attr_accessor :detail def initialize(fault) @faultcode = fault.faultcode @faultstring = fault.faultstring @faultactor = fault.faultactor @detail = fault.detail super(self.to_s) end def to_s str = nil if @faultstring and @faultstring.respond_to?('data') str = @faultstring.data end str || '(No faultstring)' end end module Env def self.getenv(name) ENV[name.downcase] || ENV[name.upcase] end use_proxy = getenv('soap_use_proxy') == 'on' HTTP_PROXY = use_proxy ? getenv('http_proxy') : nil NO_PROXY = use_proxy ? getenv('no_proxy') : nil end end unless Object.respond_to?(:instance_variable_get) class Object def instance_variable_get(ivarname) instance_eval(ivarname) end def instance_variable_set(ivarname, value) instance_eval("#{ivarname} = value") end end end unless Kernel.respond_to?(:warn) module Kernel def warn(msg) STDERR.puts(msg + "\n") unless $VERBOSE.nil? end end end ================================================ FILE: lib/soap/streamHandler.rb ================================================ # SOAP4R - Stream handler. # Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/soap' require 'soap/httpconfigloader' begin require 'stringio' require 'zlib' rescue LoadError warn("Loading stringio or zlib failed. No gzipped response support.") if $DEBUG end module SOAP class StreamHandler RUBY_VERSION_STRING = "ruby #{ RUBY_VERSION } (#{ RUBY_RELEASE_DATE }) [#{ RUBY_PLATFORM }]" class ConnectionData attr_accessor :send_string attr_accessor :send_contenttype attr_accessor :receive_string attr_accessor :receive_contenttype attr_accessor :is_fault attr_accessor :soapaction def initialize(send_string = nil) @send_string = send_string @send_contenttype = nil @receive_string = nil @receive_contenttype = nil @is_fault = false @soapaction = nil end end def self.parse_media_type(str) if /^#{ MediaType }(?:\s*;\s*charset=([^"]+|"[^"]+"))?$/i !~ str return nil end charset = $1 charset.gsub!(/"/, '') if charset charset || 'us-ascii' end def self.create_media_type(charset) "#{ MediaType }; charset=#{ charset }" end end class HTTPStreamHandler < StreamHandler include SOAP begin require 'http-access2' if HTTPAccess2::VERSION < "2.0" raise LoadError.new("http-access/2.0 or later is required.") end Client = HTTPAccess2::Client RETRYABLE = true rescue LoadError warn("Loading http-access2 failed. Net/http is used.") if $DEBUG require 'soap/netHttpClient' Client = SOAP::NetHttpClient RETRYABLE = false end public attr_reader :client attr_accessor :wiredump_file_base MAX_RETRY_COUNT = 10 # [times] def initialize(options) super() @client = Client.new(nil, "SOAP4R/#{ Version }") @wiredump_file_base = nil @charset = @wiredump_dev = nil @options = options set_options @client.debug_dev = @wiredump_dev @cookie_store = nil @accept_encoding_gzip = false end def test_loopback_response @client.test_loopback_response end def accept_encoding_gzip=(allow) @accept_encoding_gzip = allow end def inspect "#<#{self.class}>" end def send(endpoint_url, conn_data, soapaction = nil, charset = @charset) conn_data.soapaction ||= soapaction # for backward conpatibility send_post(endpoint_url, conn_data, charset) end def reset(endpoint_url = nil) if endpoint_url.nil? @client.reset_all else @client.reset(endpoint_url) end @client.save_cookie_store if @cookie_store end private def set_options HTTPConfigLoader.set_options(@client, @options) @charset = @options["charset"] || XSD::Charset.xml_encoding_label @options.add_hook("charset") do |key, value| @charset = value end @wiredump_dev = @options["wiredump_dev"] @options.add_hook("wiredump_dev") do |key, value| @wiredump_dev = value @client.debug_dev = @wiredump_dev end set_cookie_store_file(@options["cookie_store_file"]) @options.add_hook("cookie_store_file") do |key, value| set_cookie_store_file(value) end ssl_config = @options["ssl_config"] basic_auth = @options["basic_auth"] @options.lock(true) ssl_config.unlock basic_auth.unlock end def set_cookie_store_file(value) value = nil if value and value.empty? @cookie_store = value @client.set_cookie_store(@cookie_store) if @cookie_store end def send_post(endpoint_url, conn_data, charset) conn_data.send_contenttype ||= StreamHandler.create_media_type(charset) if @wiredump_file_base filename = @wiredump_file_base + '_request.xml' f = File.open(filename, "w") f << conn_data.send_string f.close end extra = {} extra['Content-Type'] = conn_data.send_contenttype extra['SOAPAction'] = "\"#{ conn_data.soapaction }\"" extra['Accept-Encoding'] = 'gzip' if send_accept_encoding_gzip? send_string = conn_data.send_string @wiredump_dev << "Wire dump:\n\n" if @wiredump_dev begin retry_count = 0 while true res = @client.post(endpoint_url, send_string, extra) if RETRYABLE and HTTP::Status.redirect?(res.status) retry_count += 1 if retry_count >= MAX_RETRY_COUNT raise HTTPStreamError.new("redirect count exceeded") end endpoint_url = res.header["location"][0] puts "redirected to #{endpoint_url}" if $DEBUG else break end end rescue @client.reset(endpoint_url) raise end @wiredump_dev << "\n\n" if @wiredump_dev receive_string = res.content if @wiredump_file_base filename = @wiredump_file_base + '_response.xml' f = File.open(filename, "w") f << receive_string f.close end case res.status when 405 raise PostUnavailableError.new("#{ res.status }: #{ res.reason }") when 200, 500 # Nothing to do. else raise HTTPStreamError.new("#{ res.status }: #{ res.reason }") end if res.respond_to?(:header) and !res.header['content-encoding'].empty? and res.header['content-encoding'][0].downcase == 'gzip' receive_string = decode_gzip(receive_string) end conn_data.receive_string = receive_string conn_data.receive_contenttype = res.contenttype conn_data end def send_accept_encoding_gzip? @accept_encoding_gzip and defined?(::Zlib) end def decode_gzip(instring) unless send_accept_encoding_gzip? raise HTTPStreamError.new("Gzipped response content.") end begin gz = Zlib::GzipReader.new(StringIO.new(instring)) gz.read ensure gz.close end end end end ================================================ FILE: lib/soap/wsdlDriver.rb ================================================ # SOAP4R - SOAP WSDL driver # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/parser' require 'wsdl/importer' require 'xsd/qname' require 'xsd/codegen/gensupport' require 'soap/mapping/wsdlencodedregistry' require 'soap/mapping/wsdlliteralregistry' require 'soap/rpc/driver' require 'wsdl/soap/methodDefCreator' module SOAP class WSDLDriverFactory class FactoryError < StandardError; end attr_reader :wsdl def initialize(wsdl) @wsdl = import(wsdl) @methoddefcreator = WSDL::SOAP::MethodDefCreator.new(@wsdl) end def inspect "#<#{self.class}:#{@wsdl.name}>" end def create_rpc_driver(servicename = nil, portname = nil) port = find_port(servicename, portname) drv = SOAP::RPC::Driver.new(port.soap_address.location) init_driver(drv, port) add_operation(drv, port) drv end # depricated old interface def create_driver(servicename = nil, portname = nil) warn("WSDLDriverFactory#create_driver is depricated. Use create_rpc_driver instead.") port = find_port(servicename, portname) WSDLDriver.new(@wsdl, port, nil) end # Backward compatibility. alias createDriver create_driver private def find_port(servicename = nil, portname = nil) service = port = nil if servicename service = @wsdl.service( XSD::QName.new(@wsdl.targetnamespace, servicename)) else service = @wsdl.services[0] end if service.nil? raise FactoryError.new("service #{servicename} not found in WSDL") end if portname port = service.ports[XSD::QName.new(@wsdl.targetnamespace, portname)] if port.nil? raise FactoryError.new("port #{portname} not found in WSDL") end else port = service.ports.find { |port| !port.soap_address.nil? } if port.nil? raise FactoryError.new("no ports have soap:address") end end if port.soap_address.nil? raise FactoryError.new("soap:address element not found in WSDL") end port end def init_driver(drv, port) wsdl_elements = @wsdl.collect_elements wsdl_types = @wsdl.collect_complextypes + @wsdl.collect_simpletypes rpc_decode_typemap = wsdl_types + @wsdl.soap_rpc_complextypes(port.find_binding) drv.proxy.mapping_registry = Mapping::WSDLEncodedRegistry.new(rpc_decode_typemap) drv.proxy.literal_mapping_registry = Mapping::WSDLLiteralRegistry.new(wsdl_types, wsdl_elements) end def add_operation(drv, port) port.find_binding.operations.each do |op_bind| op_name = op_bind.soapoperation_name soapaction = op_bind.soapaction || '' orgname = op_name.name name = XSD::CodeGen::GenSupport.safemethodname(orgname) param_def = create_param_def(op_bind) opt = { :request_style => op_bind.soapoperation_style, :response_style => op_bind.soapoperation_style, :request_use => op_bind.input.soapbody_use, :response_use => op_bind.output.soapbody_use, :elementformdefault => false, :attributeformdefault => false } if op_bind.soapoperation_style == :rpc drv.add_rpc_operation(op_name, soapaction, name, param_def, opt) else drv.add_document_operation(soapaction, name, param_def, opt) end if orgname != name and orgname.capitalize == name.capitalize ::SOAP::Mapping.define_singleton_method(drv, orgname) do |*arg| __send__(name, *arg) end end end end def import(location) WSDL::Importer.import(location) end def create_param_def(op_bind) op = op_bind.find_operation if op_bind.soapoperation_style == :rpc param_def = @methoddefcreator.collect_rpcparameter(op) else param_def = @methoddefcreator.collect_documentparameter(op) end # the first element of typedef in param_def is a String like # "::SOAP::SOAPStruct". turn this String to a class. param_def.collect { |io, name, typedef| typedef[0] = Mapping.class_from_name(typedef[0]) [io, name, typedef] } end def partqname(part) if part.type part.type else part.element end end def param_def(type, name, klass, partqname) [type, name, [klass, partqname.namespace, partqname.name]] end def filter_parts(partsdef, partssource) parts = partsdef.split(/\s+/) partssource.find_all { |part| parts.include?(part.name) } end end class WSDLDriver class << self if RUBY_VERSION >= "1.7.0" def __attr_proxy(symbol, assignable = false) name = symbol.to_s define_method(name) { @servant.__send__(name) } if assignable aname = name + '=' define_method(aname) { |rhs| @servant.__send__(aname, rhs) } end end else def __attr_proxy(symbol, assignable = false) name = symbol.to_s module_eval <<-EOS def #{name} @servant.#{name} end EOS if assignable module_eval <<-EOS def #{name}=(value) @servant.#{name} = value end EOS end end end end __attr_proxy :options __attr_proxy :headerhandler __attr_proxy :streamhandler __attr_proxy :test_loopback_response __attr_proxy :endpoint_url, true __attr_proxy :mapping_registry, true # for RPC unmarshal __attr_proxy :wsdl_mapping_registry, true # for RPC marshal __attr_proxy :default_encodingstyle, true __attr_proxy :generate_explicit_type, true __attr_proxy :allow_unqualified_element, true def httpproxy @servant.options["protocol.http.proxy"] end def httpproxy=(httpproxy) @servant.options["protocol.http.proxy"] = httpproxy end def wiredump_dev @servant.options["protocol.http.wiredump_dev"] end def wiredump_dev=(wiredump_dev) @servant.options["protocol.http.wiredump_dev"] = wiredump_dev end def mandatorycharset @servant.options["protocol.mandatorycharset"] end def mandatorycharset=(mandatorycharset) @servant.options["protocol.mandatorycharset"] = mandatorycharset end def wiredump_file_base @servant.options["protocol.wiredump_file_base"] end def wiredump_file_base=(wiredump_file_base) @servant.options["protocol.wiredump_file_base"] = wiredump_file_base end def initialize(wsdl, port, logdev) @servant = Servant__.new(self, wsdl, port, logdev) end def inspect "#<#{self.class}:#{@servant.port.name}>" end def reset_stream @servant.reset_stream end # Backward compatibility. alias generateEncodeType= generate_explicit_type= class Servant__ include SOAP attr_reader :options attr_reader :port attr_accessor :soapaction attr_accessor :default_encodingstyle attr_accessor :allow_unqualified_element attr_accessor :generate_explicit_type attr_accessor :mapping_registry attr_accessor :wsdl_mapping_registry def initialize(host, wsdl, port, logdev) @host = host @wsdl = wsdl @port = port @logdev = logdev @soapaction = nil @options = setup_options @default_encodingstyle = nil @allow_unqualified_element = nil @generate_explicit_type = false @mapping_registry = nil # for rpc unmarshal @wsdl_mapping_registry = nil # for rpc marshal @wiredump_file_base = nil @mandatorycharset = nil @wsdl_elements = @wsdl.collect_elements @wsdl_types = @wsdl.collect_complextypes + @wsdl.collect_simpletypes @rpc_decode_typemap = @wsdl_types + @wsdl.soap_rpc_complextypes(port.find_binding) @wsdl_mapping_registry = Mapping::WSDLEncodedRegistry.new( @rpc_decode_typemap) @doc_mapper = Mapping::WSDLLiteralRegistry.new( @wsdl_types, @wsdl_elements) endpoint_url = @port.soap_address.location # Convert a map which key is QName, to a Hash which key is String. @operation = {} @port.inputoperation_map.each do |op_name, op_info| orgname = op_name.name name = XSD::CodeGen::GenSupport.safemethodname(orgname) @operation[name] = @operation[orgname] = op_info add_method_interface(op_info) end @proxy = ::SOAP::RPC::Proxy.new(endpoint_url, @soapaction, @options) end def inspect "#<#{self.class}:#{@proxy.inspect}>" end def endpoint_url @proxy.endpoint_url end def endpoint_url=(endpoint_url) @proxy.endpoint_url = endpoint_url end def headerhandler @proxy.headerhandler end def streamhandler @proxy.streamhandler end def test_loopback_response @proxy.test_loopback_response end def reset_stream @proxy.reset_stream end def rpc_call(name, *values) set_wiredump_file_base(name) unless op_info = @operation[name] raise RuntimeError, "method: #{name} not defined" end req_header = create_request_header req_body = create_request_body(op_info, *values) reqopt = create_options({ :soapaction => op_info.soapaction || @soapaction}) resopt = create_options({ :decode_typemap => @rpc_decode_typemap}) env = @proxy.route(req_header, req_body, reqopt, resopt) raise EmptyResponseError unless env receive_headers(env.header) begin @proxy.check_fault(env.body) rescue ::SOAP::FaultError => e Mapping.fault2exception(e) end ret = env.body.response ? Mapping.soap2obj(env.body.response, @mapping_registry) : nil if env.body.outparams outparams = env.body.outparams.collect { |outparam| Mapping.soap2obj(outparam) } return [ret].concat(outparams) else return ret end end # req_header: [[element, mustunderstand, encodingstyle(QName/String)], ...] # req_body: SOAPBasetype/SOAPCompoundtype def document_send(name, header_obj, body_obj) set_wiredump_file_base(name) unless op_info = @operation[name] raise RuntimeError, "method: #{name} not defined" end req_header = header_obj ? header_from_obj(header_obj, op_info) : nil req_body = body_from_obj(body_obj, op_info) opt = create_options({ :soapaction => op_info.soapaction || @soapaction, :decode_typemap => @wsdl_types}) env = @proxy.invoke(req_header, req_body, opt) raise EmptyResponseError unless env if env.body.fault raise ::SOAP::FaultError.new(env.body.fault) end res_body_obj = env.body.response ? Mapping.soap2obj(env.body.response, @mapping_registry) : nil return env.header, res_body_obj end private def create_options(hash = nil) opt = {} opt[:default_encodingstyle] = @default_encodingstyle opt[:allow_unqualified_element] = @allow_unqualified_element opt[:generate_explicit_type] = @generate_explicit_type opt.update(hash) if hash opt end def set_wiredump_file_base(name) if @wiredump_file_base @proxy.set_wiredump_file_base(@wiredump_file_base + "_#{name}") end end def create_request_header headers = @proxy.headerhandler.on_outbound if headers.empty? nil else h = SOAPHeader.new headers.each do |header| h.add(header.elename.name, header) end h end end def receive_headers(headers) @proxy.headerhandler.on_inbound(headers) if headers end def create_request_body(op_info, *values) method = create_method_struct(op_info, *values) SOAPBody.new(method) end def create_method_struct(op_info, *params) parts_names = op_info.bodyparts.collect { |part| part.name } obj = create_method_obj(parts_names, params) method = Mapping.obj2soap(obj, @wsdl_mapping_registry, op_info.op_name) if method.members.size != parts_names.size new_method = SOAPStruct.new method.each do |key, value| if parts_names.include?(key) new_method.add(key, value) end end method = new_method end method.elename = op_info.op_name method.type = XSD::QName.new # Request should not be typed. method end def create_method_obj(names, params) o = Object.new idx = 0 while idx < params.length o.instance_variable_set('@' + names[idx], params[idx]) idx += 1 end o end def header_from_obj(obj, op_info) if obj.is_a?(SOAPHeader) obj elsif op_info.headerparts.empty? if obj.nil? nil else raise RuntimeError.new("no header definition in schema: #{obj}") end elsif op_info.headerparts.size == 1 part = op_info.headerparts[0] header = SOAPHeader.new() header.add(headeritem_from_obj(obj, part.element || part.eletype)) header else header = SOAPHeader.new() op_info.headerparts.each do |part| child = Mapping.get_attribute(obj, part.name) ele = headeritem_from_obj(child, part.element || part.eletype) header.add(part.name, ele) end header end end def headeritem_from_obj(obj, name) if obj.nil? SOAPElement.new(name) elsif obj.is_a?(SOAPHeaderItem) obj else Mapping.obj2soap(obj, @doc_mapper, name) end end def body_from_obj(obj, op_info) if obj.is_a?(SOAPBody) obj elsif op_info.bodyparts.empty? if obj.nil? nil else raise RuntimeError.new("no body found in schema") end elsif op_info.bodyparts.size == 1 part = op_info.bodyparts[0] ele = bodyitem_from_obj(obj, part.element || part.type) SOAPBody.new(ele) else body = SOAPBody.new op_info.bodyparts.each do |part| child = Mapping.get_attribute(obj, part.name) ele = bodyitem_from_obj(child, part.element || part.type) body.add(ele.elename.name, ele) end body end end def bodyitem_from_obj(obj, name) if obj.nil? SOAPElement.new(name) elsif obj.is_a?(SOAPElement) obj else Mapping.obj2soap(obj, @doc_mapper, name) end end def add_method_interface(op_info) name = XSD::CodeGen::GenSupport.safemethodname(op_info.op_name.name) orgname = op_info.op_name.name parts_names = op_info.bodyparts.collect { |part| part.name } case op_info.style when :document if orgname != name and orgname.capitalize == name.capitalize add_document_method_interface(orgname, parts_names) end add_document_method_interface(name, parts_names) when :rpc if orgname != name and orgname.capitalize == name.capitalize add_rpc_method_interface(orgname, parts_names) end add_rpc_method_interface(name, parts_names) else raise RuntimeError.new("unknown style: #{op_info.style}") end end def add_rpc_method_interface(name, parts_names) ::SOAP::Mapping.define_singleton_method(@host, name) do |*arg| unless arg.size == parts_names.size raise ArgumentError.new( "wrong number of arguments (#{arg.size} for #{parts_names.size})") end @servant.rpc_call(name, *arg) end @host.method(name) end def add_document_method_interface(name, parts_names) ::SOAP::Mapping.define_singleton_method(@host, name) do |h, b| @servant.document_send(name, h, b) end @host.method(name) end def setup_options if opt = Property.loadproperty(::SOAP::PropertyName) opt = opt["client"] end opt ||= Property.new opt.add_hook("protocol.mandatorycharset") do |key, value| @mandatorycharset = value end opt.add_hook("protocol.wiredump_file_base") do |key, value| @wiredump_file_base = value end opt["protocol.http.charset"] ||= XSD::Charset.xml_encoding_label opt["protocol.http.proxy"] ||= Env::HTTP_PROXY opt["protocol.http.no_proxy"] ||= Env::NO_PROXY opt end end end end ================================================ FILE: lib/sync.rb ================================================ # # sync.rb - 2 phase lock with counter # $Release Version: 1.0$ # $Revision$ # $Date$ # by Keiju ISHITSUKA(keiju@ishitsuka.com) # # -- # Sync_m, Synchronizer_m # Usage: # obj.extend(Sync_m) # or # class Foo # include Sync_m # : # end # # Sync_m#sync_mode # Sync_m#sync_locked?, locked? # Sync_m#sync_shared?, shared? # Sync_m#sync_exclusive?, sync_exclusive? # Sync_m#sync_try_lock, try_lock # Sync_m#sync_lock, lock # Sync_m#sync_unlock, unlock # # Sync, Synchronicer: # include Sync_m # Usage: # sync = Sync.new # # Sync#mode # Sync#locked? # Sync#shared? # Sync#exclusive? # Sync#try_lock(mode) -- mode = :EX, :SH, :UN # Sync#lock(mode) -- mode = :EX, :SH, :UN # Sync#unlock # Sync#synchronize(mode) {...} # # unless defined? Thread fail "Thread not available for this ruby interpreter" end module Sync_m RCS_ID='-$Header$-' # lock mode UN = :UN SH = :SH EX = :EX # exceptions class Err < StandardError def Err.Fail(*opt) Thread.critical = false fail self, sprintf(self::Message, *opt) end class UnknownLocker < Err Message = "Thread(%s) not locked." def UnknownLocker.Fail(th) super(th.inspect) end end class LockModeFailer < Err Message = "Unknown lock mode(%s)" def LockModeFailer.Fail(mode) if mode.id2name mode = id2name end super(mode) end end end def Sync_m.define_aliases(cl) cl.module_eval %q{ alias locked? sync_locked? alias shared? sync_shared? alias exclusive? sync_exclusive? alias lock sync_lock alias unlock sync_unlock alias try_lock sync_try_lock alias synchronize sync_synchronize } end def Sync_m.append_features(cl) super unless cl.instance_of?(Module) # do nothing for Modules # make aliases and include the proper module. define_aliases(cl) end end def Sync_m.extend_object(obj) super obj.sync_extended end def sync_extended unless (defined? locked? and defined? shared? and defined? exclusive? and defined? lock and defined? unlock and defined? try_lock and defined? synchronize) Sync_m.define_aliases(class< 0 for k, v in sync_upgrade_waiting sync_sh_locker[k] = v end wait = sync_upgrade_waiting self.sync_upgrade_waiting = [] Thread.critical = false for w, v in wait w.run end else wait = sync_waiting self.sync_waiting = [] Thread.critical = false for w in wait w.run end end end Thread.critical = false self end def sync_synchronize(mode = EX) begin sync_lock(mode) yield ensure sync_unlock end end attr :sync_mode, true attr :sync_waiting, true attr :sync_upgrade_waiting, true attr :sync_sh_locker, true attr :sync_ex_locker, true attr :sync_ex_count, true private def sync_initialize @sync_mode = UN @sync_waiting = [] @sync_upgrade_waiting = [] @sync_sh_locker = Hash.new @sync_ex_locker = nil @sync_ex_count = 0 end def initialize(*args) sync_initialize super end def sync_try_lock_sub(m) case m when SH case sync_mode when UN self.sync_mode = m sync_sh_locker[Thread.current] = 1 ret = true when SH count = 0 unless count = sync_sh_locker[Thread.current] sync_sh_locker[Thread.current] = count + 1 ret = true when EX # in EX mode, lock will upgrade to EX lock if sync_ex_locker == Thread.current self.sync_ex_count = sync_ex_count + 1 ret = true else ret = false end end when EX if sync_mode == UN or sync_mode == SH && sync_sh_locker.size == 1 && sync_sh_locker.include?(Thread.current) self.sync_mode = m self.sync_ex_locker = Thread.current self.sync_ex_count = 1 ret = true elsif sync_mode == EX && sync_ex_locker == Thread.current self.sync_ex_count = sync_ex_count + 1 ret = true else ret = false end else Thread.critical = false Err::LockModeFailer.Fail mode end return ret end end Synchronizer_m = Sync_m class Sync #Sync_m.extend_class self include Sync_m def initialize super end end Synchronizer = Sync ================================================ FILE: lib/tempfile.rb ================================================ # # tempfile - manipulates temporary files # # $Id$ # require 'delegate' require 'tmpdir' # A class for managing temporary files. This library is written to be # thread safe. class Tempfile < DelegateClass(File) MAX_TRY = 10 @@cleanlist = [] # Creates a temporary file of mode 0600 in the temporary directory, # opens it with mode "w+", and returns a Tempfile object which # represents the created temporary file. A Tempfile object can be # treated just like a normal File object. # # The basename parameter is used to determine the name of a # temporary file. If an Array is given, the first element is used # as prefix string and the second as suffix string, respectively. # Otherwise it is treated as prefix string. # # If tmpdir is omitted, the temporary directory is determined by # Dir::tmpdir provided by 'tmpdir.rb'. # When $SAFE > 0 and the given tmpdir is tainted, it uses # /tmp. (Note that ENV values are tainted by default) def initialize(basename, tmpdir=Dir::tmpdir) if $SAFE > 0 and tmpdir.tainted? tmpdir = '/tmp' end lock = nil n = failure = 0 begin Thread.critical = true begin tmpname = File.join(tmpdir, make_tmpname(basename, n)) lock = tmpname + '.lock' n += 1 end while @@cleanlist.include?(tmpname) or File.exist?(lock) or File.exist?(tmpname) Dir.mkdir(lock) rescue failure += 1 retry if failure < MAX_TRY raise "cannot generate tempfile `%s'" % tmpname ensure Thread.critical = false end @data = [tmpname] @clean_proc = Tempfile.callback(@data) ObjectSpace.define_finalizer(self, @clean_proc) @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600) @tmpname = tmpname @@cleanlist << @tmpname @data[1] = @tmpfile @data[2] = @@cleanlist super(@tmpfile) # Now we have all the File/IO methods defined, you must not # carelessly put bare puts(), etc. after this. Dir.rmdir(lock) end def make_tmpname(basename, n) case basename when Array prefix, suffix = *basename else prefix, suffix = basename, '' end t = Time.now.strftime("%Y%m%d") path = "#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}-#{n}#{suffix}" end private :make_tmpname # Opens or reopens the file with mode "r+". def open @tmpfile.close if @tmpfile @tmpfile = File.open(@tmpname, 'r+') @data[1] = @tmpfile __setobj__(@tmpfile) end def _close # :nodoc: @tmpfile.close if @tmpfile @tmpfile = nil @data[1] = nil if @data end protected :_close # Closes the file. If the optional flag is true, unlinks the file # after closing. # # If you don't explicitly unlink the temporary file, the removal # will be delayed until the object is finalized. def close(unlink_now=false) if unlink_now close! else _close end end # Closes and unlinks the file. def close! _close @clean_proc.call ObjectSpace.undefine_finalizer(self) @data = @tmpname = nil end # Unlinks the file. On UNIX-like systems, it is often a good idea # to unlink a temporary file immediately after creating and opening # it, because it leaves other programs zero chance to access the # file. def unlink # keep this order for thread safeness begin File.unlink(@tmpname) if File.exist?(@tmpname) @@cleanlist.delete(@tmpname) @data = @tmpname = nil ObjectSpace.undefine_finalizer(self) rescue Errno::EACCES # may not be able to unlink on Windows; just ignore end end alias delete unlink # Returns the full path name of the temporary file. def path @tmpname end # Returns the size of the temporary file. As a side effect, the IO # buffer is flushed before determining the size. def size if @tmpfile @tmpfile.flush @tmpfile.stat.size else 0 end end alias length size class << self def callback(data) # :nodoc: pid = $$ lambda{ if pid == $$ path, tmpfile, cleanlist = *data print "removing ", path, "..." if $DEBUG tmpfile.close if tmpfile # keep this order for thread safeness File.unlink(path) if File.exist?(path) cleanlist.delete(path) if cleanlist print "done\n" if $DEBUG end } end # If no block is given, this is a synonym for new(). # # If a block is given, it will be passed tempfile as an argument, # and the tempfile will automatically be closed when the block # terminates. In this case, open() returns nil. def open(*args) tempfile = new(*args) if block_given? begin yield(tempfile) ensure tempfile.close end nil else tempfile end end end end if __FILE__ == $0 # $DEBUG = true f = Tempfile.new("foo") f.print("foo\n") f.close f.open p f.gets # => "foo\n" f.close! end ================================================ FILE: lib/test/unit/assertionfailederror.rb ================================================ #-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module Test module Unit # Thrown by Test::Unit::Assertions when an assertion fails. class AssertionFailedError < StandardError end end end ================================================ FILE: lib/test/unit/assertions.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/assertionfailederror' require 'test/unit/util/backtracefilter' module Test module Unit ## # Test::Unit::Assertions contains the standard Test::Unit assertions. # Assertions is included in Test::Unit::TestCase. # # To include it in your own code and use its functionality, you simply # need to rescue Test::Unit::AssertionFailedError. Additionally you may # override add_assertion to get notified whenever an assertion is made. # # Notes: # * The message to each assertion, if given, will be propagated with the # failure. # * It is easy to add your own assertions based on assert_block(). # # = Example Custom Assertion # # def deny(boolean, message = nil) # message = build_message message, ' is not false or nil.', boolean # assert_block message do # not boolean # end # end module Assertions ## # The assertion upon which all other assertions are based. Passes if the # block yields true. # # Example: # assert_block "Couldn't do the thing" do # do_the_thing # end public def assert_block(message="assert_block failed.") # :yields: _wrap_assertion do if (! yield) raise AssertionFailedError.new(message.to_s) end end end ## # Asserts that +boolean+ is not false or nil. # # Example: # assert [1, 2].include?(5) public def assert(boolean, message=nil) _wrap_assertion do assert_block("assert should not be called with a block.") { !block_given? } assert_block(build_message(message, " is not true.", boolean)) { boolean } end end ## # Passes if +expected+ == +actual. # # Note that the ordering of arguments is important, since a helpful # error message is generated when this one fails that tells you the # values of expected and actual. # # Example: # assert_equal 'MY STRING', 'my string'.upcase public def assert_equal(expected, actual, message=nil) full_message = build_message(message, < expected but was . EOT assert_block(full_message) { expected == actual } end private def _check_exception_class(args) # :nodoc: args.partition do |klass| next if klass.instance_of?(Module) assert(Exception >= klass, "Should expect a class of exception, #{klass}") true end end private def _expected_exception?(actual_exception, exceptions, modules) # :nodoc: exceptions.include?(actual_exception.class) or modules.any? {|mod| actual_exception.is_a?(mod)} end ## # Passes if the block raises one of the given exceptions. # # Example: # assert_raise RuntimeError, LoadError do # raise 'Boom!!!' # end public def assert_raise(*args) _wrap_assertion do if Module === args.last message = "" else message = args.pop end exceptions, modules = _check_exception_class(args) expected = args.size == 1 ? args.first : args actual_exception = nil full_message = build_message(message, " exception expected but none was thrown.", expected) assert_block(full_message) do begin yield rescue Exception => actual_exception break end false end full_message = build_message(message, " exception expected but was\n?", expected, actual_exception) assert_block(full_message) {_expected_exception?(actual_exception, exceptions, modules)} actual_exception end end ## # Alias of assert_raise. # # Will be deprecated in 1.9, and removed in 2.0. public def assert_raises(*args, &block) assert_raise(*args, &block) end ## # Passes if +object+ .instance_of? +klass+ # # Example: # assert_instance_of String, 'foo' public def assert_instance_of(klass, object, message="") _wrap_assertion do assert_equal(Class, klass.class, "assert_instance_of takes a Class as its first argument") full_message = build_message(message, < expected to be an instance of but was . EOT assert_block(full_message){object.instance_of?(klass)} end end ## # Passes if +object+ is nil. # # Example: # assert_nil [1, 2].uniq! public def assert_nil(object, message="") assert_equal(nil, object, message) end ## # Passes if +object+ .kind_of? +klass+ # # Example: # assert_kind_of Object, 'foo' public def assert_kind_of(klass, object, message="") _wrap_assertion do assert(klass.kind_of?(Module), "The first parameter to assert_kind_of should be a kind_of Module.") full_message = build_message(message, "\nexpected to be kind_of\\?\n but was\n.", object, klass, object.class) assert_block(full_message){object.kind_of?(klass)} end end ## # Passes if +object+ .respond_to? +method+ # # Example: # assert_respond_to 'bugbear', :slice public def assert_respond_to(object, method, message="") _wrap_assertion do full_message = build_message(nil, "\ngiven as the method name argument to #assert_respond_to must be a Symbol or #respond_to\\?(:to_str).", method) assert_block(full_message) do method.kind_of?(Symbol) || method.respond_to?(:to_str) end full_message = build_message(message, < of type expected to respond_to\\?. EOT assert_block(full_message) { object.respond_to?(method) } end end ## # Passes if +string+ =~ +pattern+. # # Example: # assert_match(/\d+/, 'five, 6, seven') public def assert_match(pattern, string, message="") _wrap_assertion do pattern = case(pattern) when String Regexp.new(Regexp.escape(pattern)) else pattern end full_message = build_message(message, " expected to be =~\n.", string, pattern) assert_block(full_message) { string =~ pattern } end end ## # Passes if +actual+ .equal? +expected+ (i.e. they are the same # instance). # # Example: # o = Object.new # assert_same o, o public def assert_same(expected, actual, message="") full_message = build_message(message, < with id expected to be equal\\? to with id . EOT assert_block(full_message) { actual.equal?(expected) } end ## # Compares the +object1+ with +object2+ using +operator+. # # Passes if object1.__send__(operator, object2) is true. # # Example: # assert_operator 5, :>=, 4 public def assert_operator(object1, operator, object2, message="") _wrap_assertion do full_message = build_message(nil, "\ngiven as the operator for #assert_operator must be a Symbol or #respond_to\\?(:to_str).", operator) assert_block(full_message){operator.kind_of?(Symbol) || operator.respond_to?(:to_str)} full_message = build_message(message, < expected to be ? . EOT assert_block(full_message) { object1.__send__(operator, object2) } end end ## # Passes if block does not raise an exception. # # Example: # assert_nothing_raised do # [1, 2].uniq # end public def assert_nothing_raised(*args) _wrap_assertion do if Module === args.last message = "" else message = args.pop end exceptions, modules = _check_exception_class(args) begin yield rescue Exception => e if ((args.empty? && !e.instance_of?(AssertionFailedError)) || _expected_exception?(e, exceptions, modules)) assert_block(build_message(message, "Exception raised:\n?", e)){false} else raise end end nil end end ## # Flunk always fails. # # Example: # flunk 'Not done testing yet.' public def flunk(message="Flunked") assert_block(build_message(message)){false} end ## # Passes if ! +actual+ .equal? +expected+ # # Example: # assert_not_same Object.new, Object.new public def assert_not_same(expected, actual, message="") full_message = build_message(message, < with id expected to not be equal\\? to with id . EOT assert_block(full_message) { !actual.equal?(expected) } end ## # Passes if +expected+ != +actual+ # # Example: # assert_not_equal 'some string', 5 public def assert_not_equal(expected, actual, message="") full_message = build_message(message, " expected to be != to\n.", expected, actual) assert_block(full_message) { expected != actual } end ## # Passes if ! +object+ .nil? # # Example: # assert_not_nil '1 two 3'.sub!(/two/, '2') public def assert_not_nil(object, message="") full_message = build_message(message, " expected to not be nil.", object) assert_block(full_message){!object.nil?} end ## # Passes if +regexp+ !~ +string+ # # Example: # assert_no_match(/two/, 'one 2 three') public def assert_no_match(regexp, string, message="") _wrap_assertion do assert_instance_of(Regexp, regexp, "The first argument to assert_no_match should be a Regexp.") full_message = build_message(message, " expected to not match\n.", regexp, string) assert_block(full_message) { regexp !~ string } end end UncaughtThrow = {NameError => /^uncaught throw \`(.+)\'$/, ThreadError => /^uncaught throw \`(.+)\' in thread /} #` ## # Passes if the block throws +expected_symbol+ # # Example: # assert_throws :done do # throw :done # end public def assert_throws(expected_symbol, message="", &proc) _wrap_assertion do assert_instance_of(Symbol, expected_symbol, "assert_throws expects the symbol that should be thrown for its first argument") assert_block("Should have passed a block to assert_throws."){block_given?} caught = true begin catch(expected_symbol) do proc.call caught = false end full_message = build_message(message, " should have been thrown.", expected_symbol) assert_block(full_message){caught} rescue NameError, ThreadError => error if UncaughtThrow[error.class] !~ error.message raise error end full_message = build_message(message, " expected to be thrown but\n was thrown.", expected_symbol, $1.intern) flunk(full_message) end end end ## # Passes if block does not throw anything. # # Example: # assert_nothing_thrown do # [1, 2].uniq # end public def assert_nothing_thrown(message="", &proc) _wrap_assertion do assert(block_given?, "Should have passed a block to assert_nothing_thrown") begin proc.call rescue NameError, ThreadError => error if UncaughtThrow[error.class] !~ error.message raise error end full_message = build_message(message, " was thrown when nothing was expected", $1.intern) flunk(full_message) end assert(true, "Expected nothing to be thrown") end end ## # Passes if +expected_float+ and +actual_float+ are equal # within +delta+ tolerance. # # Example: # assert_in_delta 0.05, (50000.0 / 10**6), 0.00001 public def assert_in_delta(expected_float, actual_float, delta, message="") _wrap_assertion do {expected_float => "first float", actual_float => "second float", delta => "delta"}.each do |float, name| assert_respond_to(float, :to_f, "The arguments must respond to to_f; the #{name} did not") end assert_operator(delta, :>=, 0.0, "The delta should not be negative") full_message = build_message(message, < and expected to be within of each other. EOT assert_block(full_message) { (expected_float.to_f - actual_float.to_f).abs <= delta.to_f } end end ## # Passes if the method send returns a true value. # # +send_array+ is composed of: # * A receiver # * A method # * Arguments to the method # # Example: # assert_send [[1, 2], :include?, 4] public def assert_send(send_array, message="") _wrap_assertion do assert_instance_of(Array, send_array, "assert_send requires an array of send information") assert(send_array.size >= 2, "assert_send requires at least a receiver and a message name") full_message = build_message(message, < expected to respond to with a true value. EOT assert_block(full_message) { send_array[0].__send__(send_array[1], *send_array[2..-1]) } end end ## # Builds a failure message. +head+ is added before the +template+ and # +arguments+ replaces the '?'s positionally in the template. public def build_message(head, template=nil, *arguments) template &&= template.chomp return AssertionMessage.new(head, template, arguments) end private def _wrap_assertion @_assertion_wrapped ||= false unless (@_assertion_wrapped) @_assertion_wrapped = true begin add_assertion return yield ensure @_assertion_wrapped = false end else return yield end end ## # Called whenever an assertion is made. Define this in classes that # include Test::Unit::Assertions to record assertion counts. private def add_assertion end ## # Select whether or not to use the pretty-printer. If this option is set # to false before any assertions are made, pp.rb will not be required. public def self.use_pp=(value) AssertionMessage.use_pp = value end # :stopdoc: class AssertionMessage @use_pp = true class << self attr_accessor :use_pp end class Literal def initialize(value) @value = value end def inspect @value.to_s end end class Template def self.create(string) parts = (string ? string.scan(/(?=[^\\])\?|(?:\\\?|[^\?])+/m) : []) self.new(parts) end attr_reader :count def initialize(parts) @parts = parts @count = parts.find_all{|e| e == '?'}.size end def result(parameters) raise "The number of parameters does not match the number of substitutions." if(parameters.size != count) params = parameters.dup @parts.collect{|e| e == '?' ? params.shift : e.gsub(/\\\?/m, '?')}.join('') end end def self.literal(value) Literal.new(value) end include Util::BacktraceFilter def initialize(head, template_string, parameters) @head = head @template_string = template_string @parameters = parameters end def convert(object) case object when Exception < Message: <#{convert(object.message)}> ---Backtrace--- #{filter_backtrace(object.backtrace).join("\n")} --------------- EOM else if(self.class.use_pp) begin require 'pp' rescue LoadError self.class.use_pp = false return object.inspect end unless(defined?(PP)) PP.pp(object, '').chomp else object.inspect end end end def template @template ||= Template.create(@template_string) end def add_period(string) (string =~ /\.\Z/ ? string : string + '.') end def to_s message_parts = [] if (@head) head = @head.to_s unless(head.empty?) message_parts << add_period(head) end end tail = template.result(@parameters.collect{|e| convert(e)}) message_parts << tail unless(tail.empty?) message_parts.join("\n") end end # :startdoc: end end end ================================================ FILE: lib/test/unit/autorunner.rb ================================================ require 'test/unit' require 'test/unit/ui/testrunnerutilities' require 'optparse' module Test module Unit class AutoRunner def self.run(force_standalone=false, default_dir=nil, argv=ARGV, &block) r = new(force_standalone || standalone?, &block) r.base = default_dir r.process_args(argv) r.run end def self.standalone? return false unless("-e" == $0) ObjectSpace.each_object(Class) do |klass| return false if(klass < TestCase) end true end RUNNERS = { :console => proc do |r| require 'test/unit/ui/console/testrunner' Test::Unit::UI::Console::TestRunner end, :gtk => proc do |r| require 'test/unit/ui/gtk/testrunner' Test::Unit::UI::GTK::TestRunner end, :gtk2 => proc do |r| require 'test/unit/ui/gtk2/testrunner' Test::Unit::UI::GTK2::TestRunner end, :fox => proc do |r| require 'test/unit/ui/fox/testrunner' Test::Unit::UI::Fox::TestRunner end, :tk => proc do |r| require 'test/unit/ui/tk/testrunner' Test::Unit::UI::Tk::TestRunner end, } OUTPUT_LEVELS = [ [:silent, UI::SILENT], [:progress, UI::PROGRESS_ONLY], [:normal, UI::NORMAL], [:verbose, UI::VERBOSE], ] COLLECTORS = { :objectspace => proc do |r| require 'test/unit/collector/objectspace' c = Collector::ObjectSpace.new c.filter = r.filters c.collect($0.sub(/\.rb\Z/, '')) end, :dir => proc do |r| require 'test/unit/collector/dir' c = Collector::Dir.new c.filter = r.filters c.pattern.concat(r.pattern) if(r.pattern) c.exclude.concat(r.exclude) if(r.exclude) c.base = r.base $:.push(r.base) if r.base c.collect(*(r.to_run.empty? ? ['.'] : r.to_run)) end, } attr_reader :suite attr_accessor :output_level, :filters, :to_run, :pattern, :exclude, :base, :workdir attr_writer :runner, :collector def initialize(standalone) Unit.run = true @standalone = standalone @runner = RUNNERS[:console] @collector = COLLECTORS[(standalone ? :dir : :objectspace)] @filters = [] @to_run = [] @output_level = UI::NORMAL @workdir = nil yield(self) if(block_given?) end def process_args(args = ARGV) begin options.order!(args) {|arg| @to_run << arg} rescue OptionParser::ParseError => e puts e puts options $! = nil abort else @filters << proc{false} unless(@filters.empty?) end not @to_run.empty? end def options @options ||= OptionParser.new do |o| o.banner = "Test::Unit automatic runner." o.banner << "\nUsage: #{$0} [options] [-- untouched arguments]" o.on o.on('-r', '--runner=RUNNER', RUNNERS, "Use the given RUNNER.", "(" + keyword_display(RUNNERS) + ")") do |r| @runner = r end if(@standalone) o.on('-b', '--basedir=DIR', "Base directory of test suites.") do |b| @base = b end o.on('-w', '--workdir=DIR', "Working directory to run tests.") do |w| @workdir = w end o.on('-a', '--add=TORUN', Array, "Add TORUN to the list of things to run;", "can be a file or a directory.") do |a| @to_run.concat(a) end @pattern = [] o.on('-p', '--pattern=PATTERN', Regexp, "Match files to collect against PATTERN.") do |e| @pattern << e end @exclude = [] o.on('-x', '--exclude=PATTERN', Regexp, "Ignore files to collect against PATTERN.") do |e| @exclude << e end end o.on('-n', '--name=NAME', String, "Runs tests matching NAME.", "(patterns may be used).") do |n| n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n) case n when Regexp @filters << proc{|t| n =~ t.method_name ? true : nil} else @filters << proc{|t| n == t.method_name ? true : nil} end end o.on('-t', '--testcase=TESTCASE', String, "Runs tests in TestCases matching TESTCASE.", "(patterns may be used).") do |n| n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n) case n when Regexp @filters << proc{|t| n =~ t.class.name ? true : nil} else @filters << proc{|t| n == t.class.name ? true : nil} end end o.on('-I', "--load-path=DIR[#{File::PATH_SEPARATOR}DIR...]", "Appends directory list to $LOAD_PATH.") do |dirs| $LOAD_PATH.concat(dirs.split(File::PATH_SEPARATOR)) end o.on('-v', '--verbose=[LEVEL]', OUTPUT_LEVELS, "Set the output level (default is verbose).", "(" + keyword_display(OUTPUT_LEVELS) + ")") do |l| @output_level = l || UI::VERBOSE end o.on('--', "Stop processing options so that the", "remaining options will be passed to the", "test."){o.terminate} o.on('-h', '--help', 'Display this help.'){puts o; exit} o.on_tail o.on_tail('Deprecated options:') o.on_tail('--console', 'Console runner (use --runner).') do warn("Deprecated option (--console).") @runner = RUNNERS[:console] end o.on_tail('--gtk', 'GTK runner (use --runner).') do warn("Deprecated option (--gtk).") @runner = RUNNERS[:gtk] end o.on_tail('--fox', 'Fox runner (use --runner).') do warn("Deprecated option (--fox).") @runner = RUNNERS[:fox] end o.on_tail end end def keyword_display(array) list = array.collect {|e, *| e.to_s} Array === array or list.sort! list.collect {|e| e.sub(/^(.)([A-Za-z]+)(?=\w*$)/, '\\1[\\2]')}.join(", ") end def run @suite = @collector[self] result = @runner[self] or return false Dir.chdir(@workdir) if @workdir result.run(@suite, @output_level).passed? end end end end ================================================ FILE: lib/test/unit/collector/dir.rb ================================================ require 'test/unit/testsuite' require 'test/unit/collector' module Test module Unit module Collector class Dir include Collector attr_reader :pattern, :exclude attr_accessor :base def initialize(dir=::Dir, file=::File, object_space=::ObjectSpace, req=nil) super() @dir = dir @file = file @object_space = object_space @req = req @pattern = [/\btest_.*\.rb\Z/m] @exclude = [] end def collect(*from) basedir = @base $:.push(basedir) if basedir if(from.empty?) recursive_collect('.', find_test_cases) elsif(from.size == 1) recursive_collect(from.first, find_test_cases) else suites = [] from.each do |f| suite = recursive_collect(f, find_test_cases) suites << suite unless(suite.tests.empty?) end suite = TestSuite.new("[#{from.join(', ')}]") sort(suites).each{|s| suite << s} suite end ensure $:.delete_at($:.rindex(basedir)) if basedir end def find_test_cases(ignore=[]) cases = [] @object_space.each_object(Class) do |c| cases << c if(c < TestCase && !ignore.include?(c)) end ignore.concat(cases) cases end def recursive_collect(name, already_gathered) sub_suites = [] path = realdir(name) if @file.directory?(path) dir_name = name unless name == '.' @dir.entries(path).each do |e| next if(e == '.' || e == '..') e_name = dir_name ? @file.join(dir_name, e) : e if @file.directory?(realdir(e_name)) next if /\ACVS\z/ =~ e sub_suite = recursive_collect(e_name, already_gathered) sub_suites << sub_suite unless(sub_suite.empty?) else next if /~\z/ =~ e_name or /\A\.\#/ =~ e if @pattern and !@pattern.empty? next unless @pattern.any? {|pat| pat =~ e_name} end if @exclude and !@exclude.empty? next if @exclude.any? {|pat| pat =~ e_name} end collect_file(e_name, sub_suites, already_gathered) end end else collect_file(name, sub_suites, already_gathered) end suite = TestSuite.new(@file.basename(name)) sort(sub_suites).each{|s| suite << s} suite end def collect_file(name, suites, already_gathered) dir = @file.dirname(@file.expand_path(name, @base)) $:.unshift(dir) if(@req) @req.require(name) else require(name) end find_test_cases(already_gathered).each{|t| add_suite(suites, t.suite)} ensure $:.delete_at($:.rindex(dir)) if(dir) end def realdir(path) if @base @file.join(@base, path) else path end end end end end end ================================================ FILE: lib/test/unit/collector/objectspace.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/collector' module Test module Unit module Collector class ObjectSpace include Collector NAME = 'collected from the ObjectSpace' def initialize(source=::ObjectSpace) super() @source = source end def collect(name=NAME) suite = TestSuite.new(name) sub_suites = [] @source.each_object(Class) do |klass| if(Test::Unit::TestCase > klass) add_suite(sub_suites, klass.suite) end end sort(sub_suites).each{|s| suite << s} suite end end end end end ================================================ FILE: lib/test/unit/collector.rb ================================================ module Test module Unit module Collector def initialize @filters = [] end def filter=(filters) @filters = case(filters) when Proc [filters] when Array filters end end def add_suite(destination, suite) to_delete = suite.tests.find_all{|t| !include?(t)} to_delete.each{|t| suite.delete(t)} destination << suite unless(suite.size == 0) end def include?(test) return true if(@filters.empty?) @filters.each do |filter| result = filter[test] if(result.nil?) next elsif(!result) return false else return true end end true end def sort(suites) suites.sort_by{|s| s.name} end end end end ================================================ FILE: lib/test/unit/error.rb ================================================ #-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/util/backtracefilter' module Test module Unit # Encapsulates an error in a test. Created by # Test::Unit::TestCase when it rescues an exception thrown # during the processing of a test. class Error include Util::BacktraceFilter attr_reader(:test_name, :exception) SINGLE_CHARACTER = 'E' # Creates a new Error with the given test_name and # exception. def initialize(test_name, exception) @test_name = test_name @exception = exception end # Returns a single character representation of an error. def single_character_display SINGLE_CHARACTER end # Returns the message associated with the error. def message "#{@exception.class.name}: #{@exception.message}" end # Returns a brief version of the error description. def short_display "#@test_name: #{message.split("\n")[0]}" end # Returns a verbose version of the error description. def long_display backtrace = filter_backtrace(@exception.backtrace).join("\n ") "Error:\n#@test_name:\n#{message}\n #{backtrace}" end # Overridden to return long_display. def to_s long_display end end end end ================================================ FILE: lib/test/unit/failure.rb ================================================ #-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module Test module Unit # Encapsulates a test failure. Created by Test::Unit::TestCase # when an assertion fails. class Failure attr_reader :test_name, :location, :message SINGLE_CHARACTER = 'F' # Creates a new Failure with the given location and # message. def initialize(test_name, location, message) @test_name = test_name @location = location @message = message end # Returns a single character representation of a failure. def single_character_display SINGLE_CHARACTER end # Returns a brief version of the error description. def short_display "#@test_name: #{@message.split("\n")[0]}" end # Returns a verbose version of the error description. def long_display location_display = if(location.size == 1) location[0].sub(/\A(.+:\d+).*/, ' [\\1]') else "\n [#{location.join("\n ")}]" end "Failure:\n#@test_name#{location_display}:\n#@message" end # Overridden to return long_display. def to_s long_display end end end end ================================================ FILE: lib/test/unit/testcase.rb ================================================ #-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/assertions' require 'test/unit/failure' require 'test/unit/error' require 'test/unit/testsuite' require 'test/unit/assertionfailederror' require 'test/unit/util/backtracefilter' module Test module Unit # Ties everything together. If you subclass and add your own # test methods, it takes care of making them into tests and # wrapping those tests into a suite. It also does the # nitty-gritty of actually running an individual test and # collecting its results into a Test::Unit::TestResult object. class TestCase include Assertions include Util::BacktraceFilter attr_reader :method_name STARTED = name + "::STARTED" FINISHED = name + "::FINISHED" ## # These exceptions are not caught by #run. PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException, Interrupt, SystemExit] # Creates a new instance of the fixture for running the # test represented by test_method_name. def initialize(test_method_name) unless(respond_to?(test_method_name) and (method(test_method_name).arity == 0 || method(test_method_name).arity == -1)) throw :invalid_test end @method_name = test_method_name @test_passed = true end # Rolls up all of the test* methods in the fixture into # one suite, creating a new instance of the fixture for # each method. def self.suite method_names = public_instance_methods(true) tests = method_names.delete_if {|method_name| method_name !~ /^test./} suite = TestSuite.new(name) tests.sort.each do |test| catch(:invalid_test) do suite << new(test) end end if (suite.empty?) catch(:invalid_test) do suite << new("default_test") end end return suite end # Runs the individual test method represented by this # instance of the fixture, collecting statistics, failures # and errors in result. def run(result) yield(STARTED, name) @_result = result begin setup __send__(@method_name) rescue AssertionFailedError => e add_failure(e.message, e.backtrace) rescue Exception raise if PASSTHROUGH_EXCEPTIONS.include? $!.class add_error($!) ensure begin teardown rescue AssertionFailedError => e add_failure(e.message, e.backtrace) rescue Exception raise if PASSTHROUGH_EXCEPTIONS.include? $!.class add_error($!) end end result.add_run yield(FINISHED, name) end # Called before every test method runs. Can be used # to set up fixture information. def setup end # Called after every test method runs. Can be used to tear # down fixture information. def teardown end def default_test flunk("No tests were specified") end # Returns whether this individual test passed or # not. Primarily for use in teardown so that artifacts # can be left behind if the test fails. def passed? return @test_passed end private :passed? def size 1 end def add_assertion @_result.add_assertion end private :add_assertion def add_failure(message, all_locations=caller()) @test_passed = false @_result.add_failure(Failure.new(name, filter_backtrace(all_locations), message)) end private :add_failure def add_error(exception) @test_passed = false @_result.add_error(Error.new(name, exception)) end private :add_error # Returns a human-readable name for the specific test that # this instance of TestCase represents. def name "#{@method_name}(#{self.class.name})" end # Overridden to return #name. def to_s name end # It's handy to be able to compare TestCase instances. def ==(other) return false unless(other.kind_of?(self.class)) return false unless(@method_name == other.method_name) self.class == other.class end end end end ================================================ FILE: lib/test/unit/testresult.rb ================================================ #-- # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/util/observable' module Test module Unit # Collects Test::Unit::Failure and Test::Unit::Error so that # they can be displayed to the user. To this end, observers # can be added to it, allowing the dynamic updating of, say, a # UI. class TestResult include Util::Observable CHANGED = "CHANGED" FAULT = "FAULT" attr_reader(:run_count, :assertion_count) # Constructs a new, empty TestResult. def initialize @run_count, @assertion_count = 0, 0 @failures, @errors = Array.new, Array.new end # Records a test run. def add_run @run_count += 1 notify_listeners(CHANGED, self) end # Records a Test::Unit::Failure. def add_failure(failure) @failures << failure notify_listeners(FAULT, failure) notify_listeners(CHANGED, self) end # Records a Test::Unit::Error. def add_error(error) @errors << error notify_listeners(FAULT, error) notify_listeners(CHANGED, self) end # Records an individual assertion. def add_assertion @assertion_count += 1 notify_listeners(CHANGED, self) end # Returns a string contain the recorded runs, assertions, # failures and errors in this TestResult. def to_s "#{run_count} tests, #{assertion_count} assertions, #{failure_count} failures, #{error_count} errors" end # Returns whether or not this TestResult represents # successful completion. def passed? return @failures.empty? && @errors.empty? end # Returns the number of failures this TestResult has # recorded. def failure_count return @failures.size end # Returns the number of errors this TestResult has # recorded. def error_count return @errors.size end end end end ================================================ FILE: lib/test/unit/testsuite.rb ================================================ #-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module Test module Unit # A collection of tests which can be #run. # # Note: It is easy to confuse a TestSuite instance with # something that has a static suite method; I know because _I_ # have trouble keeping them straight. Think of something that # has a suite method as simply providing a way to get a # meaningful TestSuite instance. class TestSuite attr_reader :name, :tests STARTED = name + "::STARTED" FINISHED = name + "::FINISHED" # Creates a new TestSuite with the given name. def initialize(name="Unnamed TestSuite") @name = name @tests = [] end # Runs the tests and/or suites contained in this # TestSuite. def run(result, &progress_block) yield(STARTED, name) @tests.each do |test| test.run(result, &progress_block) end yield(FINISHED, name) end # Adds the test to the suite. def <<(test) @tests << test self end def delete(test) @tests.delete(test) end # Retuns the rolled up number of tests in this suite; # i.e. if the suite contains other suites, it counts the # tests within those suites, not the suites themselves. def size total_size = 0 @tests.each { |test| total_size += test.size } total_size end def empty? tests.empty? end # Overridden to return the name given the suite at # creation. def to_s @name end # It's handy to be able to compare TestSuite instances. def ==(other) return false unless(other.kind_of?(self.class)) return false unless(@name == other.name) @tests == other.tests end end end end ================================================ FILE: lib/test/unit/ui/console/testrunner.rb ================================================ #-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/ui/testrunnermediator' require 'test/unit/ui/testrunnerutilities' module Test module Unit module UI module Console # Runs a Test::Unit::TestSuite on the console. class TestRunner extend TestRunnerUtilities # Creates a new TestRunner for running the passed # suite. If quiet_mode is true, the output while # running is limited to progress dots, errors and # failures, and the final result. io specifies # where runner output should go to; defaults to # STDOUT. def initialize(suite, output_level=NORMAL, io=STDOUT) if (suite.respond_to?(:suite)) @suite = suite.suite else @suite = suite end @output_level = output_level @io = io @already_outputted = false @faults = [] end # Begins the test run. def start setup_mediator attach_to_mediator return start_mediator end private def setup_mediator @mediator = create_mediator(@suite) suite_name = @suite.to_s if ( @suite.kind_of?(Module) ) suite_name = @suite.name end output("Loaded suite #{suite_name}") end def create_mediator(suite) return TestRunnerMediator.new(suite) end def attach_to_mediator @mediator.add_listener(TestResult::FAULT, &method(:add_fault)) @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started)) @mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished)) @mediator.add_listener(TestCase::STARTED, &method(:test_started)) @mediator.add_listener(TestCase::FINISHED, &method(:test_finished)) end def start_mediator return @mediator.run_suite end def add_fault(fault) @faults << fault output_single(fault.single_character_display, PROGRESS_ONLY) @already_outputted = true end def started(result) @result = result output("Started") end def finished(elapsed_time) nl output("Finished in #{elapsed_time} seconds.") @faults.each_with_index do |fault, index| nl output("%3d) %s" % [index + 1, fault.long_display]) end nl output(@result) end def test_started(name) output_single(name + ": ", VERBOSE) end def test_finished(name) output_single(".", PROGRESS_ONLY) unless (@already_outputted) nl(VERBOSE) @already_outputted = false end def nl(level=NORMAL) output("", level) end def output(something, level=NORMAL) @io.puts(something) if (output?(level)) @io.flush end def output_single(something, level=NORMAL) @io.write(something) if (output?(level)) @io.flush end def output?(level) level <= @output_level end end end end end end if __FILE__ == $0 Test::Unit::UI::Console::TestRunner.start_command_line_test end ================================================ FILE: lib/test/unit/ui/fox/testrunner.rb ================================================ #-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'fox' require 'test/unit/ui/testrunnermediator' require 'test/unit/ui/testrunnerutilities' include Fox module Test module Unit module UI module Fox # Runs a Test::Unit::TestSuite in a Fox UI. Obviously, # this one requires you to have Fox # (http://www.fox-toolkit.org/fox.html) and the Ruby # Fox extension (http://fxruby.sourceforge.net/) # installed. class TestRunner extend TestRunnerUtilities RED_STYLE = FXRGBA(0xFF,0,0,0xFF) #0xFF000000 GREEN_STYLE = FXRGBA(0,0xFF,0,0xFF) #0x00FF0000 # Creates a new TestRunner for running the passed # suite. def initialize(suite, output_level = NORMAL) if (suite.respond_to?(:suite)) @suite = suite.suite else @suite = suite end @result = nil @red = false end # Begins the test run. def start setup_ui setup_mediator attach_to_mediator start_ui @result end def setup_mediator @mediator = TestRunnerMediator.new(@suite) suite_name = @suite.to_s if ( @suite.kind_of?(Module) ) suite_name = @suite.name end @suite_name_entry.text = suite_name end def attach_to_mediator @mediator.add_listener(TestRunnerMediator::RESET, &method(:reset_ui)) @mediator.add_listener(TestResult::FAULT, &method(:add_fault)) @mediator.add_listener(TestResult::CHANGED, &method(:result_changed)) @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started)) @mediator.add_listener(TestCase::STARTED, &method(:test_started)) @mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished)) end def start_ui @application.create @window.show(PLACEMENT_SCREEN) @application.addTimeout(1) do @mediator.run_suite end @application.run end def stop @application.exit(0) end def reset_ui(count) @test_progress_bar.barColor = GREEN_STYLE @test_progress_bar.total = count @test_progress_bar.progress = 0 @red = false @test_count_label.text = "0" @assertion_count_label.text = "0" @failure_count_label.text = "0" @error_count_label.text = "0" @fault_list.clearItems end def add_fault(fault) if ( ! @red ) @test_progress_bar.barColor = RED_STYLE @red = true end item = FaultListItem.new(fault) @fault_list.appendItem(item) end def show_fault(fault) raw_show_fault(fault.long_display) end def raw_show_fault(string) @detail_text.setText(string) end def clear_fault raw_show_fault("") end def result_changed(result) @test_progress_bar.progress = result.run_count @test_count_label.text = result.run_count.to_s @assertion_count_label.text = result.assertion_count.to_s @failure_count_label.text = result.failure_count.to_s @error_count_label.text = result.error_count.to_s # repaint now! @info_panel.repaint @application.flush end def started(result) @result = result output_status("Started...") end def test_started(test_name) output_status("Running #{test_name}...") end def finished(elapsed_time) output_status("Finished in #{elapsed_time} seconds") end def output_status(string) @status_entry.text = string @status_entry.repaint end def setup_ui @application = create_application create_tooltip(@application) @window = create_window(@application) @status_entry = create_entry(@window) main_panel = create_main_panel(@window) suite_panel = create_suite_panel(main_panel) create_label(suite_panel, "Suite:") @suite_name_entry = create_entry(suite_panel) create_button(suite_panel, "&Run\tRun the current suite", proc { @mediator.run_suite }) @test_progress_bar = create_progress_bar(main_panel) @info_panel = create_info_panel(main_panel) create_label(@info_panel, "Tests:") @test_count_label = create_label(@info_panel, "0") create_label(@info_panel, "Assertions:") @assertion_count_label = create_label(@info_panel, "0") create_label(@info_panel, "Failures:") @failure_count_label = create_label(@info_panel, "0") create_label(@info_panel, "Errors:") @error_count_label = create_label(@info_panel, "0") list_panel = create_list_panel(main_panel) @fault_list = create_fault_list(list_panel) detail_panel = create_detail_panel(main_panel) @detail_text = create_text(detail_panel) end def create_application app = FXApp.new("TestRunner", "Test::Unit") app.init([]) app end def create_window(app) FXMainWindow.new(app, "Test::Unit TestRunner", nil, nil, DECOR_ALL, 0, 0, 450) end def create_tooltip(app) FXTooltip.new(app) end def create_main_panel(parent) panel = FXVerticalFrame.new(parent, LAYOUT_FILL_X | LAYOUT_FILL_Y) panel.vSpacing = 10 panel end def create_suite_panel(parent) FXHorizontalFrame.new(parent, LAYOUT_SIDE_LEFT | LAYOUT_FILL_X) end def create_button(parent, text, action) FXButton.new(parent, text).connect(SEL_COMMAND, &action) end def create_progress_bar(parent) FXProgressBar.new(parent, nil, 0, PROGRESSBAR_NORMAL | LAYOUT_FILL_X) end def create_info_panel(parent) FXMatrix.new(parent, 1, MATRIX_BY_ROWS | LAYOUT_FILL_X) end def create_label(parent, text) FXLabel.new(parent, text, nil, JUSTIFY_CENTER_X | LAYOUT_FILL_COLUMN) end def create_list_panel(parent) FXHorizontalFrame.new(parent, LAYOUT_FILL_X | FRAME_SUNKEN | FRAME_THICK) end def create_fault_list(parent) list = FXList.new(parent, 10, nil, 0, LIST_SINGLESELECT | LAYOUT_FILL_X) #, 0, 0, 0, 150) list.connect(SEL_COMMAND) do |sender, sel, ptr| if sender.retrieveItem(sender.currentItem).selected? show_fault(sender.retrieveItem(sender.currentItem).fault) else clear_fault end end list end def create_detail_panel(parent) FXHorizontalFrame.new(parent, LAYOUT_FILL_X | LAYOUT_FILL_Y | FRAME_SUNKEN | FRAME_THICK) end def create_text(parent) FXText.new(parent, nil, 0, TEXT_READONLY | LAYOUT_FILL_X | LAYOUT_FILL_Y) end def create_entry(parent) entry = FXTextField.new(parent, 30, nil, 0, TEXTFIELD_NORMAL | LAYOUT_SIDE_BOTTOM | LAYOUT_FILL_X) entry.disable entry end end class FaultListItem < FXListItem attr_reader(:fault) def initialize(fault) super(fault.short_display) @fault = fault end end end end end end if __FILE__ == $0 Test::Unit::UI::Fox::TestRunner.start_command_line_test end ================================================ FILE: lib/test/unit/ui/gtk/testrunner.rb ================================================ #-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'gtk' require 'test/unit/ui/testrunnermediator' require 'test/unit/ui/testrunnerutilities' module Test module Unit module UI module GTK # Runs a Test::Unit::TestSuite in a Gtk UI. Obviously, # this one requires you to have Gtk # (http://www.gtk.org/) and the Ruby Gtk extension # (http://ruby-gnome.sourceforge.net/) installed. class TestRunner extend TestRunnerUtilities # Creates a new TestRunner for running the passed # suite. def initialize(suite, output_level = NORMAL) if (suite.respond_to?(:suite)) @suite = suite.suite else @suite = suite end @result = nil @runner = Thread.current @restart_signal = Class.new(Exception) @viewer = Thread.start do @runner.join rescue @runner.run Gtk.main end @viewer.join rescue nil # wait deadlock to handshake end # Begins the test run. def start setup_mediator setup_ui attach_to_mediator start_ui @result end private def setup_mediator @mediator = TestRunnerMediator.new(@suite) suite_name = @suite.to_s if ( @suite.kind_of?(Module) ) suite_name = @suite.name end suite_name_entry.set_text(suite_name) end def attach_to_mediator run_button.signal_connect("clicked", nil, &method(:run_test)) @mediator.add_listener(TestRunnerMediator::RESET, &method(:reset_ui)) @mediator.add_listener(TestResult::FAULT, &method(:add_fault)) @mediator.add_listener(TestResult::CHANGED, &method(:result_changed)) @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started)) @mediator.add_listener(TestCase::STARTED, &method(:test_started)) @mediator.add_listener(TestCase::FINISHED, &method(:test_finished)) @mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished)) end def run_test(*) @runner.raise(@restart_signal) end def start_ui @viewer.run running = false begin loop do if (running ^= true) run_button.child.text = "Stop" @mediator.run_suite else run_button.child.text = "Run" @viewer.join break end end rescue @restart_signal retry rescue end end def stop(*) Gtk.main_quit end def reset_ui(count) test_progress_bar.set_style(green_style) test_progress_bar.configure(0, 0, count) @red = false run_count_label.set_text("0") assertion_count_label.set_text("0") failure_count_label.set_text("0") error_count_label.set_text("0") fault_list.remove_items(fault_list.children) end def add_fault(fault) if ( ! @red ) test_progress_bar.set_style(red_style) @red = true end item = FaultListItem.new(fault) item.show fault_list.append_items([item]) end def show_fault(fault) raw_show_fault(fault.long_display) end def raw_show_fault(string) fault_detail_label.set_text(string) outer_detail_sub_panel.queue_resize end def clear_fault raw_show_fault("") end def result_changed(result) run_count_label.set_text(result.run_count.to_s) assertion_count_label.set_text(result.assertion_count.to_s) failure_count_label.set_text(result.failure_count.to_s) error_count_label.set_text(result.error_count.to_s) end def started(result) @result = result output_status("Started...") end def test_started(test_name) output_status("Running #{test_name}...") end def test_finished(test_name) test_progress_bar.set_value(test_progress_bar.get_value + 1) end def finished(elapsed_time) output_status("Finished in #{elapsed_time} seconds") end def output_status(string) status_entry.set_text(string) end def setup_ui main_window.signal_connect("destroy", nil, &method(:stop)) main_window.show_all fault_list.signal_connect("select-child", nil) { | list, item, data | show_fault(item.fault) } fault_list.signal_connect("unselect-child", nil) { clear_fault } @red = false end def main_window lazy_initialize(:main_window) { @main_window = Gtk::Window.new(Gtk::WINDOW_TOPLEVEL) @main_window.set_title("Test::Unit TestRunner") @main_window.set_usize(800, 600) @main_window.set_uposition(20, 20) @main_window.set_policy(true, true, false) @main_window.add(main_panel) } end def main_panel lazy_initialize(:main_panel) { @main_panel = Gtk::VBox.new(false, 0) @main_panel.pack_start(suite_panel, false, false, 0) @main_panel.pack_start(progress_panel, false, false, 0) @main_panel.pack_start(info_panel, false, false, 0) @main_panel.pack_start(list_panel, false, false, 0) @main_panel.pack_start(detail_panel, true, true, 0) @main_panel.pack_start(status_panel, false, false, 0) } end def suite_panel lazy_initialize(:suite_panel) { @suite_panel = Gtk::HBox.new(false, 10) @suite_panel.border_width(10) @suite_panel.pack_start(Gtk::Label.new("Suite:"), false, false, 0) @suite_panel.pack_start(suite_name_entry, true, true, 0) @suite_panel.pack_start(run_button, false, false, 0) } end def suite_name_entry lazy_initialize(:suite_name_entry) { @suite_name_entry = Gtk::Entry.new @suite_name_entry.set_editable(false) } end def run_button lazy_initialize(:run_button) { @run_button = Gtk::Button.new("Run") } end def progress_panel lazy_initialize(:progress_panel) { @progress_panel = Gtk::HBox.new(false, 10) @progress_panel.border_width(10) @progress_panel.pack_start(test_progress_bar, true, true, 0) } end def test_progress_bar lazy_initialize(:test_progress_bar) { @test_progress_bar = EnhancedProgressBar.new @test_progress_bar.set_usize(@test_progress_bar.allocation.width, info_panel.size_request.height) @test_progress_bar.set_style(green_style) } end def green_style lazy_initialize(:green_style) { @green_style = Gtk::Style.new @green_style.set_bg(Gtk::STATE_PRELIGHT, 0x0000, 0xFFFF, 0x0000) } end def red_style lazy_initialize(:red_style) { @red_style = Gtk::Style.new @red_style.set_bg(Gtk::STATE_PRELIGHT, 0xFFFF, 0x0000, 0x0000) } end def info_panel lazy_initialize(:info_panel) { @info_panel = Gtk::HBox.new(false, 0) @info_panel.border_width(10) @info_panel.pack_start(Gtk::Label.new("Runs:"), false, false, 0) @info_panel.pack_start(run_count_label, true, false, 0) @info_panel.pack_start(Gtk::Label.new("Assertions:"), false, false, 0) @info_panel.pack_start(assertion_count_label, true, false, 0) @info_panel.pack_start(Gtk::Label.new("Failures:"), false, false, 0) @info_panel.pack_start(failure_count_label, true, false, 0) @info_panel.pack_start(Gtk::Label.new("Errors:"), false, false, 0) @info_panel.pack_start(error_count_label, true, false, 0) } end def run_count_label lazy_initialize(:run_count_label) { @run_count_label = Gtk::Label.new("0") @run_count_label.set_justify(Gtk::JUSTIFY_LEFT) } end def assertion_count_label lazy_initialize(:assertion_count_label) { @assertion_count_label = Gtk::Label.new("0") @assertion_count_label.set_justify(Gtk::JUSTIFY_LEFT) } end def failure_count_label lazy_initialize(:failure_count_label) { @failure_count_label = Gtk::Label.new("0") @failure_count_label.set_justify(Gtk::JUSTIFY_LEFT) } end def error_count_label lazy_initialize(:error_count_label) { @error_count_label = Gtk::Label.new("0") @error_count_label.set_justify(Gtk::JUSTIFY_LEFT) } end def list_panel lazy_initialize(:list_panel) { @list_panel = Gtk::HBox.new @list_panel.border_width(10) @list_panel.pack_start(list_scrolled_window, true, true, 0) } end def list_scrolled_window lazy_initialize(:list_scrolled_window) { @list_scrolled_window = Gtk::ScrolledWindow.new @list_scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC) @list_scrolled_window.set_usize(@list_scrolled_window.allocation.width, 150) @list_scrolled_window.add_with_viewport(fault_list) } end def fault_list lazy_initialize(:fault_list) { @fault_list = Gtk::List.new } end def detail_panel lazy_initialize(:detail_panel) { @detail_panel = Gtk::HBox.new @detail_panel.border_width(10) @detail_panel.pack_start(detail_scrolled_window, true, true, 0) } end def detail_scrolled_window lazy_initialize(:detail_scrolled_window) { @detail_scrolled_window = Gtk::ScrolledWindow.new @detail_scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC) @detail_scrolled_window.set_usize(400, @detail_scrolled_window.allocation.height) @detail_scrolled_window.add_with_viewport(outer_detail_sub_panel) } end def outer_detail_sub_panel lazy_initialize(:outer_detail_sub_panel) { @outer_detail_sub_panel = Gtk::VBox.new @outer_detail_sub_panel.pack_start(inner_detail_sub_panel, false, false, 0) } end def inner_detail_sub_panel lazy_initialize(:inner_detail_sub_panel) { @inner_detail_sub_panel = Gtk::HBox.new @inner_detail_sub_panel.pack_start(fault_detail_label, false, false, 0) } end def fault_detail_label lazy_initialize(:fault_detail_label) { @fault_detail_label = EnhancedLabel.new("") style = Gtk::Style.new font = Gdk::Font.font_load("-*-Courier New-medium-r-normal--*-120-*-*-*-*-*-*") begin style.set_font(font) rescue ArgumentError; end @fault_detail_label.set_style(style) @fault_detail_label.set_justify(Gtk::JUSTIFY_LEFT) @fault_detail_label.set_line_wrap(false) } end def status_panel lazy_initialize(:status_panel) { @status_panel = Gtk::HBox.new @status_panel.border_width(10) @status_panel.pack_start(status_entry, true, true, 0) } end def status_entry lazy_initialize(:status_entry) { @status_entry = Gtk::Entry.new @status_entry.set_editable(false) } end def lazy_initialize(symbol) if (!instance_eval("defined?(@#{symbol.to_s})")) yield end return instance_eval("@" + symbol.to_s) end end class EnhancedProgressBar < Gtk::ProgressBar def set_style(style) super hide show end end class EnhancedLabel < Gtk::Label def set_text(text) super(text.gsub(/\n\t/, "\n" + (" " * 4))) end end class FaultListItem < Gtk::ListItem attr_reader(:fault) def initialize(fault) super(fault.short_display) @fault = fault end end end end end end if __FILE__ == $0 Test::Unit::UI::GTK::TestRunner.start_command_line_test end ================================================ FILE: lib/test/unit/ui/gtk2/testrunner.rb ================================================ #-- # # Author:: Kenta MURATA. # Copyright:: Copyright (c) 2000-2002 Kenta MURATA. All rights reserved. # License:: Ruby license. require "gtk2" require "test/unit/ui/testrunnermediator" require "test/unit/ui/testrunnerutilities" module Test module Unit module UI module GTK2 Gtk.init class EnhancedLabel < Gtk::Label def set_text(text) super(text.gsub(/\n\t/, "\n ")) end end class FaultList < Gtk::TreeView def initialize @faults = [] @model = Gtk::ListStore.new(String, String) super(@model) column = Gtk::TreeViewColumn.new column.visible = false append_column(column) renderer = Gtk::CellRendererText.new column = Gtk::TreeViewColumn.new("Failures", renderer, {:text => 1}) append_column(column) selection.mode = Gtk::SELECTION_SINGLE set_rules_hint(true) set_headers_visible(false) end # def initialize def add_fault(fault) @faults.push(fault) iter = @model.append iter.set_value(0, (@faults.length - 1).to_s) iter.set_value(1, fault.short_display) end # def add_fault(fault) def get_fault(iter) @faults[iter.get_value(0).to_i] end # def get_fault def clear model.clear end # def clear end class TestRunner extend TestRunnerUtilities def lazy_initialize(symbol) if !instance_eval("defined?(@#{symbol})") then yield end return instance_eval("@#{symbol}") end private :lazy_initialize def status_entry lazy_initialize(:status_entry) do @status_entry = Gtk::Entry.new @status_entry.editable = false end end private :status_entry def status_panel lazy_initialize(:status_panel) do @status_panel = Gtk::HBox.new @status_panel.border_width = 10 @status_panel.pack_start(status_entry, true, true, 0) end end private :status_panel def fault_detail_label lazy_initialize(:fault_detail_label) do @fault_detail_label = EnhancedLabel.new("") # style = Gtk::Style.new # font = Gdk::Font. # font_load("-*-Courier 10 Pitch-medium-r-normal--*-120-*-*-*-*-*-*") # style.set_font(font) # @fault_detail_label.style = style @fault_detail_label.justify = Gtk::JUSTIFY_LEFT @fault_detail_label.wrap = false end end private :fault_detail_label def inner_detail_sub_panel lazy_initialize(:inner_detail_sub_panel) do @inner_detail_sub_panel = Gtk::HBox.new @inner_detail_sub_panel.pack_start(fault_detail_label, false, false, 0) end end private :inner_detail_sub_panel def outer_detail_sub_panel lazy_initialize(:outer_detail_sub_panel) do @outer_detail_sub_panel = Gtk::VBox.new @outer_detail_sub_panel.pack_start(inner_detail_sub_panel, false, false, 0) end end private :outer_detail_sub_panel def detail_scrolled_window lazy_initialize(:detail_scrolled_window) do @detail_scrolled_window = Gtk::ScrolledWindow.new @detail_scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC) @detail_scrolled_window. set_size_request(400, @detail_scrolled_window.allocation.height) @detail_scrolled_window.add_with_viewport(outer_detail_sub_panel) end end private :detail_scrolled_window def detail_panel lazy_initialize(:detail_panel) do @detail_panel = Gtk::HBox.new @detail_panel.border_width = 10 @detail_panel.pack_start(detail_scrolled_window, true, true, 0) end end private :detail_panel def fault_list lazy_initialize(:fault_list) do @fault_list = FaultList.new end end private :fault_list def list_scrolled_window lazy_initialize(:list_scrolled_window) do @list_scrolled_window = Gtk::ScrolledWindow.new @list_scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC) @list_scrolled_window. set_size_request(@list_scrolled_window.allocation.width, 150) @list_scrolled_window.add_with_viewport(fault_list) end end private :list_scrolled_window def list_panel lazy_initialize(:list_panel) do @list_panel = Gtk::HBox.new @list_panel.border_width = 10 @list_panel.pack_start(list_scrolled_window, true, true, 0) end end private :list_panel def error_count_label lazy_initialize(:error_count_label) do @error_count_label = Gtk::Label.new("0") @error_count_label.justify = Gtk::JUSTIFY_LEFT end end private :error_count_label def failure_count_label lazy_initialize(:failure_count_label) do @failure_count_label = Gtk::Label.new("0") @failure_count_label.justify = Gtk::JUSTIFY_LEFT end end private :failure_count_label def assertion_count_label lazy_initialize(:assertion_count_label) do @assertion_count_label = Gtk::Label.new("0") @assertion_count_label.justify = Gtk::JUSTIFY_LEFT end end private :assertion_count_label def run_count_label lazy_initialize(:run_count_label) do @run_count_label = Gtk::Label.new("0") @run_count_label.justify = Gtk::JUSTIFY_LEFT end end private :run_count_label def info_panel lazy_initialize(:info_panel) do @info_panel = Gtk::HBox.new(false, 0) @info_panel.border_width = 10 @info_panel.pack_start(Gtk::Label.new("Runs:"), false, false, 0) @info_panel.pack_start(run_count_label, true, false, 0) @info_panel.pack_start(Gtk::Label.new("Assertions:"), false, false, 0) @info_panel.pack_start(assertion_count_label, true, false, 0) @info_panel.pack_start(Gtk::Label.new("Failures:"), false, false, 0) @info_panel.pack_start(failure_count_label, true, false, 0) @info_panel.pack_start(Gtk::Label.new("Errors:"), false, false, 0) @info_panel.pack_start(error_count_label, true, false, 0) end end # def info_panel private :info_panel def green_style lazy_initialize(:green_style) do @green_style = Gtk::Style.new @green_style.set_bg(Gtk::STATE_PRELIGHT, 0x0000, 0xFFFF, 0x0000) end end # def green_style private :green_style def red_style lazy_initialize(:red_style) do @red_style = Gtk::Style.new @red_style.set_bg(Gtk::STATE_PRELIGHT, 0xFFFF, 0x0000, 0x0000) end end # def red_style private :red_style def test_progress_bar lazy_initialize(:test_progress_bar) { @test_progress_bar = Gtk::ProgressBar.new @test_progress_bar.fraction = 0.0 @test_progress_bar. set_size_request(@test_progress_bar.allocation.width, info_panel.size_request[1]) @test_progress_bar.style = green_style } end # def test_progress_bar private :test_progress_bar def progress_panel lazy_initialize(:progress_panel) do @progress_panel = Gtk::HBox.new(false, 10) @progress_panel.border_width = 10 @progress_panel.pack_start(test_progress_bar, true, true, 0) end end # def progress_panel def run_button lazy_initialize(:run_button) do @run_button = Gtk::Button.new("Run") end end # def run_button def suite_name_entry lazy_initialize(:suite_name_entry) do @suite_name_entry = Gtk::Entry.new @suite_name_entry.editable = false end end # def suite_name_entry private :suite_name_entry def suite_panel lazy_initialize(:suite_panel) do @suite_panel = Gtk::HBox.new(false, 10) @suite_panel.border_width = 10 @suite_panel.pack_start(Gtk::Label.new("Suite:"), false, false, 0) @suite_panel.pack_start(suite_name_entry, true, true, 0) @suite_panel.pack_start(run_button, false, false, 0) end end # def suite_panel private :suite_panel def main_panel lazy_initialize(:main_panel) do @main_panel = Gtk::VBox.new(false, 0) @main_panel.pack_start(suite_panel, false, false, 0) @main_panel.pack_start(progress_panel, false, false, 0) @main_panel.pack_start(info_panel, false, false, 0) @main_panel.pack_start(list_panel, false, false, 0) @main_panel.pack_start(detail_panel, true, true, 0) @main_panel.pack_start(status_panel, false, false, 0) end end # def main_panel private :main_panel def main_window lazy_initialize(:main_window) do @main_window = Gtk::Window.new(Gtk::Window::TOPLEVEL) @main_window.set_title("Test::Unit TestRunner") @main_window.set_default_size(800, 600) @main_window.set_resizable(true) @main_window.add(main_panel) end end # def main_window private :main_window def setup_ui main_window.signal_connect("destroy", nil) { stop } main_window.show_all fault_list.selection.signal_connect("changed", nil) do |selection, data| if selection.selected then show_fault(fault_list.get_fault(selection.selected)) else clear_fault end end end # def setup_ui private :setup_ui def output_status(string) status_entry.set_text(string) end # def output_status(string) private :output_status def finished(elapsed_time) test_progress_bar.fraction = 1.0 output_status("Finished in #{elapsed_time} seconds") end # def finished(elapsed_time) private :finished def test_started(test_name) output_status("Running #{test_name}...") end # def test_started(test_name) private :test_started def started(result) @result = result output_status("Started...") end # def started(result) private :started def test_finished(result) test_progress_bar.fraction += 1.0 / @count end # def test_finished(result) def result_changed(result) run_count_label.label = result.run_count.to_s assertion_count_label.label = result.assertion_count.to_s failure_count_label.label = result.failure_count.to_s error_count_label.label = result.error_count.to_s end # def result_changed(result) private :result_changed def clear_fault raw_show_fault("") end # def clear_fault private :clear_fault def raw_show_fault(string) fault_detail_label.set_text(string) outer_detail_sub_panel.queue_resize end # def raw_show_fault(string) private :raw_show_fault def show_fault(fault) raw_show_fault(fault.long_display) end # def show_fault(fault) private :show_fault def add_fault(fault) if not @red then test_progress_bar.style = red_style @red = true end fault_list.add_fault(fault) end # def add_fault(fault) private :add_fault def reset_ui(count) test_progress_bar.style = green_style test_progress_bar.fraction = 0.0 @count = count + 1 @red = false run_count_label.set_text("0") assertion_count_label.set_text("0") failure_count_label.set_text("0") error_count_label.set_text("0") fault_list.clear end # def reset_ui(count) private :reset_ui def stop Gtk.main_quit end # def stop private :stop def run_test @runner.raise(@restart_signal) end private :run_test def start_ui @viewer.run running = false begin loop do if (running ^= true) run_button.child.text = "Stop" @mediator.run_suite else run_button.child.text = "Run" @viewer.join break end end rescue @restart_signal retry rescue end end # def start_ui private :start_ui def attach_to_mediator run_button.signal_connect("clicked", nil) { run_test } @mediator.add_listener(TestRunnerMediator::RESET, &method(:reset_ui)) @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started)) @mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished)) @mediator.add_listener(TestResult::FAULT, &method(:add_fault)) @mediator.add_listener(TestResult::CHANGED, &method(:result_changed)) @mediator.add_listener(TestCase::STARTED, &method(:test_started)) @mediator.add_listener(TestCase::FINISHED, &method(:test_finished)) end # def attach_to_mediator private :attach_to_mediator def setup_mediator @mediator = TestRunnerMediator.new(@suite) suite_name = @suite.to_s if @suite.kind_of?(Module) then suite_name = @suite.name end suite_name_entry.set_text(suite_name) end # def setup_mediator private :setup_mediator def start setup_mediator setup_ui attach_to_mediator start_ui @result end # def start def initialize(suite, output_level = NORMAL) if suite.respond_to?(:suite) then @suite = suite.suite else @suite = suite end @result = nil @runner = Thread.current @restart_signal = Class.new(Exception) @viewer = Thread.start do @runner.join rescue @runner.run Gtk.main end @viewer.join rescue nil # wait deadlock to handshake end # def initialize(suite) end # class TestRunner end # module GTK2 end # module UI end # module Unit end # module Test ================================================ FILE: lib/test/unit/ui/testrunnermediator.rb ================================================ #-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' require 'test/unit/util/observable' require 'test/unit/testresult' module Test module Unit module UI # Provides an interface to write any given UI against, # hopefully making it easy to write new UIs. class TestRunnerMediator RESET = name + "::RESET" STARTED = name + "::STARTED" FINISHED = name + "::FINISHED" include Util::Observable # Creates a new TestRunnerMediator initialized to run # the passed suite. def initialize(suite) @suite = suite end # Runs the suite the TestRunnerMediator was created # with. def run_suite Unit.run = true begin_time = Time.now notify_listeners(RESET, @suite.size) result = create_result notify_listeners(STARTED, result) result_listener = result.add_listener(TestResult::CHANGED) do |updated_result| notify_listeners(TestResult::CHANGED, updated_result) end fault_listener = result.add_listener(TestResult::FAULT) do |fault| notify_listeners(TestResult::FAULT, fault) end @suite.run(result) do |channel, value| notify_listeners(channel, value) end result.remove_listener(TestResult::FAULT, fault_listener) result.remove_listener(TestResult::CHANGED, result_listener) end_time = Time.now elapsed_time = end_time - begin_time notify_listeners(FINISHED, elapsed_time) #"Finished in #{elapsed_time} seconds.") return result end private # A factory method to create the result the mediator # should run with. Can be overridden by subclasses if # one wants to use a different result. def create_result return TestResult.new end end end end end ================================================ FILE: lib/test/unit/ui/testrunnerutilities.rb ================================================ #-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module Test module Unit module UI SILENT = 0 PROGRESS_ONLY = 1 NORMAL = 2 VERBOSE = 3 # Provides some utilities common to most, if not all, # TestRunners. # #-- # # Perhaps there ought to be a TestRunner superclass? There # seems to be a decent amount of shared code between test # runners. module TestRunnerUtilities # Creates a new TestRunner and runs the suite. def run(suite, output_level=NORMAL) return new(suite, output_level).start end # Takes care of the ARGV parsing and suite # determination necessary for running one of the # TestRunners from the command line. def start_command_line_test if ARGV.empty? puts "You should supply the name of a test suite file to the runner" exit end require ARGV[0].gsub(/.+::/, '') new(eval(ARGV[0])).start end end end end end ================================================ FILE: lib/test/unit/ui/tk/testrunner.rb ================================================ #-- # # Original Author:: Nathaniel Talbott. # Author:: Kazuhiro NISHIYAMA. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # Copyright:: Copyright (c) 2003 Kazuhiro NISHIYAMA. All rights reserved. # License:: Ruby license. require 'tk' require 'test/unit/ui/testrunnermediator' require 'test/unit/ui/testrunnerutilities' module Test module Unit module UI module Tk # Runs a Test::Unit::TestSuite in a Tk UI. Obviously, # this one requires you to have Tk # and the Ruby Tk extension installed. class TestRunner extend TestRunnerUtilities # Creates a new TestRunner for running the passed # suite. def initialize(suite, output_level = NORMAL) if (suite.respond_to?(:suite)) @suite = suite.suite else @suite = suite end @result = nil @red = false @fault_detail_list = [] @runner = Thread.current @restart_signal = Class.new(Exception) @viewer = Thread.start do @runner.join rescue @runner.run ::Tk.mainloop end @viewer.join rescue nil # wait deadlock to handshake end # Begins the test run. def start setup_ui setup_mediator attach_to_mediator start_ui @result end private def setup_mediator @mediator = TestRunnerMediator.new(@suite) suite_name = @suite.to_s if ( @suite.kind_of?(Module) ) suite_name = @suite.name end @suite_name_entry.value = suite_name end def attach_to_mediator @run_button.command(method(:run_test)) @fault_list.bind('ButtonPress-1', proc{|y| fault = @fault_detail_list[@fault_list.nearest(y)] if fault show_fault(fault) end }, '%y') @mediator.add_listener(TestRunnerMediator::RESET, &method(:reset_ui)) @mediator.add_listener(TestResult::FAULT, &method(:add_fault)) @mediator.add_listener(TestResult::CHANGED, &method(:result_changed)) @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started)) @mediator.add_listener(TestCase::STARTED, &method(:test_started)) @mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished)) end def run_test @runner.raise(@restart_signal) end def start_ui @viewer.run running = false begin loop do if (running ^= true) @run_button.configure('text'=>'Stop') @mediator.run_suite else @run_button.configure('text'=>'Run') @viewer.join break end end rescue @restart_signal retry rescue end end def stop ::Tk.exit end def reset_ui(count) @test_total_count = count.to_f @test_progress_bar.configure('background'=>'green') @test_progress_bar.place('relwidth'=>(count.zero? ? 0 : 0/count)) @red = false @test_count_label.value = 0 @assertion_count_label.value = 0 @failure_count_label.value = 0 @error_count_label.value = 0 @fault_list.delete(0, 'end') @fault_detail_list = [] clear_fault end def add_fault(fault) if ( ! @red ) @test_progress_bar.configure('background'=>'red') @red = true end @fault_detail_list.push fault @fault_list.insert('end', fault.short_display) end def show_fault(fault) raw_show_fault(fault.long_display) end def raw_show_fault(string) @detail_text.value = string end def clear_fault raw_show_fault("") end def result_changed(result) @test_count_label.value = result.run_count @test_progress_bar.place('relwidth'=>result.run_count/@test_total_count) @assertion_count_label.value = result.assertion_count @failure_count_label.value = result.failure_count @error_count_label.value = result.error_count end def started(result) @result = result output_status("Started...") end def test_started(test_name) output_status("Running #{test_name}...") end def finished(elapsed_time) output_status("Finished in #{elapsed_time} seconds") end def output_status(string) @status_entry.value = string end def setup_ui @status_entry = TkVariable.new l = TkLabel.new(nil, 'textvariable'=>@status_entry, 'relief'=>'sunken') l.pack('side'=>'bottom', 'fill'=>'x') suite_frame = TkFrame.new.pack('fill'=>'x') @run_button = TkButton.new(suite_frame, 'text'=>'Run') @run_button.pack('side'=>'right') TkLabel.new(suite_frame, 'text'=>'Suite:').pack('side'=>'left') @suite_name_entry = TkVariable.new l = TkLabel.new(suite_frame, 'textvariable'=>@suite_name_entry, 'relief'=>'sunken') l.pack('side'=>'left', 'fill'=>'x', 'expand'=>true) f = TkFrame.new(nil, 'relief'=>'sunken', 'borderwidth'=>3, 'height'=>20).pack('fill'=>'x', 'padx'=>1) @test_progress_bar = TkFrame.new(f, 'background'=>'green').place('anchor'=>'nw', 'relwidth'=>0.0, 'relheight'=>1.0) info_frame = TkFrame.new.pack('fill'=>'x') @test_count_label = create_count_label(info_frame, 'Tests:') @assertion_count_label = create_count_label(info_frame, 'Assertions:') @failure_count_label = create_count_label(info_frame, 'Failures:') @error_count_label = create_count_label(info_frame, 'Errors:') if (::Tk.info('command', TkPanedWindow::TkCommandNames[0]) != "") # use panedwindow paned_frame = TkPanedWindow.new("orient"=>"vertical").pack('fill'=>'both', 'expand'=>true) fault_list_frame = TkFrame.new(paned_frame) detail_frame = TkFrame.new(paned_frame) paned_frame.add(fault_list_frame, detail_frame) else # no panedwindow paned_frame = nil fault_list_frame = TkFrame.new.pack('fill'=>'both', 'expand'=>true) detail_frame = TkFrame.new.pack('fill'=>'both', 'expand'=>true) end TkGrid.rowconfigure(fault_list_frame, 0, 'weight'=>1, 'minsize'=>0) TkGrid.columnconfigure(fault_list_frame, 0, 'weight'=>1, 'minsize'=>0) fault_scrollbar_y = TkScrollbar.new(fault_list_frame) fault_scrollbar_x = TkScrollbar.new(fault_list_frame) @fault_list = TkListbox.new(fault_list_frame) @fault_list.yscrollbar(fault_scrollbar_y) @fault_list.xscrollbar(fault_scrollbar_x) TkGrid.rowconfigure(detail_frame, 0, 'weight'=>1, 'minsize'=>0) TkGrid.columnconfigure(detail_frame, 0, 'weight'=>1, 'minsize'=>0) ::Tk.grid(@fault_list, fault_scrollbar_y, 'sticky'=>'news') ::Tk.grid(fault_scrollbar_x, 'sticky'=>'news') detail_scrollbar_y = TkScrollbar.new(detail_frame) detail_scrollbar_x = TkScrollbar.new(detail_frame) @detail_text = TkText.new(detail_frame, 'height'=>10, 'wrap'=>'none') { bindtags(bindtags - [TkText]) } @detail_text.yscrollbar(detail_scrollbar_y) @detail_text.xscrollbar(detail_scrollbar_x) ::Tk.grid(@detail_text, detail_scrollbar_y, 'sticky'=>'news') ::Tk.grid(detail_scrollbar_x, 'sticky'=>'news') # rubber-style pane if paned_frame ::Tk.update @height = paned_frame.winfo_height paned_frame.bind('Configure', proc{|h| paned_frame.sash_place(0, 0, paned_frame.sash_coord(0)[1] * h / @height) @height = h }, '%h') end end def create_count_label(parent, label) TkLabel.new(parent, 'text'=>label).pack('side'=>'left', 'expand'=>true) v = TkVariable.new(0) TkLabel.new(parent, 'textvariable'=>v).pack('side'=>'left', 'expand'=>true) v end end end end end end if __FILE__ == $0 Test::Unit::UI::Tk::TestRunner.start_command_line_test end ================================================ FILE: lib/test/unit/util/backtracefilter.rb ================================================ module Test module Unit module Util module BacktraceFilter TESTUNIT_FILE_SEPARATORS = %r{[\\/:]} TESTUNIT_PREFIX = __FILE__.split(TESTUNIT_FILE_SEPARATORS)[0..-3] TESTUNIT_RB_FILE = /\.rb\Z/ def filter_backtrace(backtrace, prefix=nil) return ["No backtrace"] unless(backtrace) split_p = if(prefix) prefix.split(TESTUNIT_FILE_SEPARATORS) else TESTUNIT_PREFIX end match = proc do |e| split_e = e.split(TESTUNIT_FILE_SEPARATORS)[0, split_p.size] next false unless(split_e[0..-2] == split_p[0..-2]) split_e[-1].sub(TESTUNIT_RB_FILE, '') == split_p[-1] end return backtrace unless(backtrace.detect(&match)) found_prefix = false new_backtrace = backtrace.reverse.reject do |e| if(match[e]) found_prefix = true true elsif(found_prefix) false else true end end.reverse new_backtrace = (new_backtrace.empty? ? backtrace : new_backtrace) new_backtrace = new_backtrace.reject(&match) new_backtrace.empty? ? backtrace : new_backtrace end end end end end ================================================ FILE: lib/test/unit/util/observable.rb ================================================ #-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/util/procwrapper' module Test module Unit module Util # This is a utility class that allows anything mixing # it in to notify a set of listeners about interesting # events. module Observable # We use this for defaults since nil might mean something NOTHING = "NOTHING/#{__id__}" # Adds the passed proc as a listener on the # channel indicated by channel_name. listener_key # is used to remove the listener later; if none is # specified, the proc itself is used. # # Whatever is used as the listener_key is # returned, making it very easy to use the proc # itself as the listener_key: # # listener = add_listener("Channel") { ... } # remove_listener("Channel", listener) def add_listener(channel_name, listener_key=NOTHING, &listener) # :yields: value unless(block_given?) raise ArgumentError.new("No callback was passed as a listener") end key = listener_key if (listener_key == NOTHING) listener_key = listener key = ProcWrapper.new(listener) end channels[channel_name] ||= {} channels[channel_name][key] = listener return listener_key end # Removes the listener indicated by listener_key # from the channel indicated by # channel_name. Returns the registered proc, or # nil if none was found. def remove_listener(channel_name, listener_key) channel = channels[channel_name] return nil unless (channel) key = listener_key if (listener_key.instance_of?(Proc)) key = ProcWrapper.new(listener_key) end if (channel.has_key?(key)) return channel.delete(key) end return nil end # Calls all the procs registered on the channel # indicated by channel_name. If value is # specified, it is passed in to the procs, # otherwise they are called with no arguments. # #-- # # Perhaps this should be private? Would it ever # make sense for an external class to call this # method directly? def notify_listeners(channel_name, *arguments) channel = channels[channel_name] return 0 unless (channel) listeners = channel.values listeners.each { |listener| listener.call(*arguments) } return listeners.size end private def channels @channels ||= {} return @channels end end end end end ================================================ FILE: lib/test/unit/util/procwrapper.rb ================================================ #-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module Test module Unit module Util # Allows the storage of a Proc passed through '&' in a # hash. # # Note: this may be inefficient, since the hash being # used is not necessarily very good. In Observable, # efficiency is not too important, since the hash is # only accessed when adding and removing listeners, # not when notifying. class ProcWrapper # Creates a new wrapper for a_proc. def initialize(a_proc) @a_proc = a_proc @hash = a_proc.inspect.sub(/^(#<#{a_proc.class}:)/){''}.sub(/(>)$/){''}.hex end def hash return @hash end def ==(other) case(other) when ProcWrapper return @a_proc == other.to_proc else return super end end alias :eql? :== def to_proc return @a_proc end end end end end ================================================ FILE: lib/test/unit.rb ================================================ require 'test/unit/testcase' require 'test/unit/autorunner' module Test # :nodoc: # # = Test::Unit - Ruby Unit Testing Framework # # == Introduction # # Unit testing is making waves all over the place, largely due to the # fact that it is a core practice of XP. While XP is great, unit testing # has been around for a long time and has always been a good idea. One # of the keys to good unit testing, though, is not just writing tests, # but having tests. What's the difference? Well, if you just _write_ a # test and throw it away, you have no guarantee that something won't # change later which breaks your code. If, on the other hand, you _have_ # tests (obviously you have to write them first), and run them as often # as possible, you slowly build up a wall of things that cannot break # without you immediately knowing about it. This is when unit testing # hits its peak usefulness. # # Enter Test::Unit, a framework for unit testing in Ruby, helping you to # design, debug and evaluate your code by making it easy to write and # have tests for it. # # # == Notes # # Test::Unit has grown out of and superceded Lapidary. # # # == Feedback # # I like (and do my best to practice) XP, so I value early releases, # user feedback, and clean, simple, expressive code. There is always # room for improvement in everything I do, and Test::Unit is no # exception. Please, let me know what you think of Test::Unit as it # stands, and what you'd like to see expanded/changed/improved/etc. If # you find a bug, let me know ASAP; one good way to let me know what the # bug is is to submit a new test that catches it :-) Also, I'd love to # hear about any successes you have with Test::Unit, and any # documentation you might add will be greatly appreciated. My contact # info is below. # # # == Contact Information # # A lot of discussion happens about Ruby in general on the ruby-talk # mailing list (http://www.ruby-lang.org/en/ml.html), and you can ask # any questions you might have there. I monitor the list, as do many # other helpful Rubyists, and you're sure to get a quick answer. Of # course, you're also welcome to email me (Nathaniel Talbott) directly # at mailto:testunit@talbott.ws, and I'll do my best to help you out. # # # == Credits # # I'd like to thank... # # Matz, for a great language! # # Masaki Suketa, for his work on RubyUnit, which filled a vital need in # the Ruby world for a very long time. I'm also grateful for his help in # polishing Test::Unit and getting the RubyUnit compatibility layer # right. His graciousness in allowing Test::Unit to supercede RubyUnit # continues to be a challenge to me to be more willing to defer my own # rights. # # Ken McKinlay, for his interest and work on unit testing, and for his # willingness to dialog about it. He was also a great help in pointing # out some of the holes in the RubyUnit compatibility layer. # # Dave Thomas, for the original idea that led to the extremely simple # "require 'test/unit'", plus his code to improve it even more by # allowing the selection of tests from the command-line. Also, without # RDoc, the documentation for Test::Unit would stink a lot more than it # does now. # # Everyone who's helped out with bug reports, feature ideas, # encouragement to continue, etc. It's a real privilege to be a part of # the Ruby community. # # The guys at RoleModel Software, for putting up with me repeating, "But # this would be so much easier in Ruby!" whenever we're coding in Java. # # My Creator, for giving me life, and giving it more abundantly. # # # == License # # Test::Unit is copyright (c) 2000-2003 Nathaniel Talbott. It is free # software, and is distributed under the Ruby license. See the COPYING # file in the standard Ruby distribution for details. # # # == Warranty # # This software is provided "as is" and without any express or # implied warranties, including, without limitation, the implied # warranties of merchantibility and fitness for a particular # purpose. # # # == Author # # Nathaniel Talbott. # Copyright (c) 2000-2003, Nathaniel Talbott # # ---- # # = Usage # # The general idea behind unit testing is that you write a _test_ # _method_ that makes certain _assertions_ about your code, working # against a _test_ _fixture_. A bunch of these _test_ _methods_ are # bundled up into a _test_ _suite_ and can be run any time the # developer wants. The results of a run are gathered in a _test_ # _result_ and displayed to the user through some UI. So, lets break # this down and see how Test::Unit provides each of these necessary # pieces. # # # == Assertions # # These are the heart of the framework. Think of an assertion as a # statement of expected outcome, i.e. "I assert that x should be equal # to y". If, when the assertion is executed, it turns out to be # correct, nothing happens, and life is good. If, on the other hand, # your assertion turns out to be false, an error is propagated with # pertinent information so that you can go back and make your # assertion succeed, and, once again, life is good. For an explanation # of the current assertions, see Test::Unit::Assertions. # # # == Test Method & Test Fixture # # Obviously, these assertions have to be called within a context that # knows about them and can do something meaningful with their # pass/fail value. Also, it's handy to collect a bunch of related # tests, each test represented by a method, into a common test class # that knows how to run them. The tests will be in a separate class # from the code they're testing for a couple of reasons. First of all, # it allows your code to stay uncluttered with test code, making it # easier to maintain. Second, it allows the tests to be stripped out # for deployment, since they're really there for you, the developer, # and your users don't need them. Third, and most importantly, it # allows you to set up a common test fixture for your tests to run # against. # # What's a test fixture? Well, tests do not live in a vacuum; rather, # they're run against the code they are testing. Often, a collection # of tests will run against a common set of data, also called a # fixture. If they're all bundled into the same test class, they can # all share the setting up and tearing down of that data, eliminating # unnecessary duplication and making it much easier to add related # tests. # # Test::Unit::TestCase wraps up a collection of test methods together # and allows you to easily set up and tear down the same test fixture # for each test. This is done by overriding #setup and/or #teardown, # which will be called before and after each test method that is # run. The TestCase also knows how to collect the results of your # assertions into a Test::Unit::TestResult, which can then be reported # back to you... but I'm getting ahead of myself. To write a test, # follow these steps: # # * Make sure Test::Unit is in your library path. # * require 'test/unit' in your test script. # * Create a class that subclasses Test::Unit::TestCase. # * Add a method that begins with "test" to your class. # * Make assertions in your test method. # * Optionally define #setup and/or #teardown to set up and/or tear # down your common test fixture. # * You can now run your test as you would any other Ruby # script... try it and see! # # A really simple test might look like this (#setup and #teardown are # commented out to indicate that they are completely optional): # # require 'test/unit' # # class TC_MyTest < Test::Unit::TestCase # # def setup # # end # # # def teardown # # end # # def test_fail # assert(false, 'Assertion was false.') # end # end # # # == Test Runners # # So, now you have this great test class, but you still need a way to # run it and view any failures that occur during the run. This is # where Test::Unit::UI::Console::TestRunner (and others, such as # Test::Unit::UI::GTK::TestRunner) comes into play. The console test # runner is automatically invoked for you if you require 'test/unit' # and simply run the file. To use another runner, or to manually # invoke a runner, simply call its run class method and pass in an # object that responds to the suite message with a # Test::Unit::TestSuite. This can be as simple as passing in your # TestCase class (which has a class suite method). It might look # something like this: # # require 'test/unit/ui/console/testrunner' # Test::Unit::UI::Console::TestRunner.run(TC_MyTest) # # # == Test Suite # # As more and more unit tests accumulate for a given project, it # becomes a real drag running them one at a time, and it also # introduces the potential to overlook a failing test because you # forget to run it. Suddenly it becomes very handy that the # TestRunners can take any object that returns a Test::Unit::TestSuite # in response to a suite method. The TestSuite can, in turn, contain # other TestSuites or individual tests (typically created by a # TestCase). In other words, you can easily wrap up a group of # TestCases and TestSuites like this: # # require 'test/unit/testsuite' # require 'tc_myfirsttests' # require 'tc_moretestsbyme' # require 'ts_anothersetoftests' # # class TS_MyTests # def self.suite # suite = Test::Unit::TestSuite.new # suite << TC_MyFirstTests.suite # suite << TC_MoreTestsByMe.suite # suite << TS_AnotherSetOfTests.suite # return suite # end # end # Test::Unit::UI::Console::TestRunner.run(TS_MyTests) # # Now, this is a bit cumbersome, so Test::Unit does a little bit more # for you, by wrapping these up automatically when you require # 'test/unit'. What does this mean? It means you could write the above # test case like this instead: # # require 'test/unit' # require 'tc_myfirsttests' # require 'tc_moretestsbyme' # require 'ts_anothersetoftests' # # Test::Unit is smart enough to find all the test cases existing in # the ObjectSpace and wrap them up into a suite for you. It then runs # the dynamic suite using the console TestRunner. # # # == Questions? # # I'd really like to get feedback from all levels of Ruby # practitioners about typos, grammatical errors, unclear statements, # missing points, etc., in this document (or any other). # module Unit # Set true when Test::Unit has run. If set to true Test::Unit # will not automatically run at exit. def self.run=(flag) @run = flag end # Already tests have run? def self.run? @run ||= false end end end at_exit do unless $! || Test::Unit.run? Kernel.exit Test::Unit::AutoRunner.run end end ================================================ FILE: lib/thread.rb ================================================ # # NOTE: # This file is overwritten by ext/thread/lib/thread.rb unless ruby # is configured with --disable-fastthread. # # thread.rb - thread support classes # $Date$ # by Yukihiro Matsumoto # # Copyright (C) 2001 Yukihiro Matsumoto # Copyright (C) 2000 Network Applied Communication Laboratory, Inc. # Copyright (C) 2000 Information-technology Promotion Agency, Japan # unless defined? Thread fail "Thread not available for this ruby interpreter" end class Thread # # Wraps a block in Thread.critical, restoring the original value upon exit # from the critical section. # def Thread.exclusive _old = Thread.critical begin Thread.critical = true return yield ensure Thread.critical = _old end end end # # Mutex implements a simple semaphore that can be used to coordinate access to # shared data from multiple concurrent threads. # # Example: # # require 'thread' # semaphore = Mutex.new # # a = Thread.new { # semaphore.synchronize { # # access shared resource # } # } # # b = Thread.new { # semaphore.synchronize { # # access shared resource # } # } # class Mutex # # Creates a new Mutex # def initialize @waiting = [] @locked = false; @waiting.taint # enable tainted comunication self.taint end # # Returns +true+ if this lock is currently held by some thread. # def locked? @locked end # # Attempts to obtain the lock and returns immediately. Returns +true+ if the # lock was granted. # def try_lock result = false Thread.critical = true unless @locked @locked = true result = true end Thread.critical = false result end # # Attempts to grab the lock and waits if it isn't available. # def lock while (Thread.critical = true; @locked) @waiting.push Thread.current Thread.stop end @locked = true Thread.critical = false self end # # Releases the lock. Returns +nil+ if ref wasn't locked. # def unlock return unless @locked Thread.critical = true @locked = false begin t = @waiting.shift t.wakeup if t rescue ThreadError retry end Thread.critical = false begin t.run if t rescue ThreadError end self end # # Obtains a lock, runs the block, and releases the lock when the block # completes. See the example under Mutex. # def synchronize lock begin yield ensure unlock end end # # If the mutex is locked, unlocks the mutex, wakes one waiting thread, and # yields in a critical section. # def exclusive_unlock return unless @locked Thread.exclusive do @locked = false begin t = @waiting.shift t.wakeup if t rescue ThreadError retry end yield end self end end # # ConditionVariable objects augment class Mutex. Using condition variables, # it is possible to suspend while in the middle of a critical section until a # resource becomes available. # # Example: # # require 'thread' # # mutex = Mutex.new # resource = ConditionVariable.new # # a = Thread.new { # mutex.synchronize { # # Thread 'a' now needs the resource # resource.wait(mutex) # # 'a' can now have the resource # } # } # # b = Thread.new { # mutex.synchronize { # # Thread 'b' has finished using the resource # resource.signal # } # } # class ConditionVariable # # Creates a new ConditionVariable # def initialize @waiters = [] end # # Releases the lock held in +mutex+ and waits; reacquires the lock on wakeup. # def wait(mutex) begin mutex.exclusive_unlock do @waiters.push(Thread.current) Thread.stop end ensure mutex.lock end end # # Wakes up the first thread in line waiting for this lock. # def signal begin t = @waiters.shift t.run if t rescue ThreadError retry end end # # Wakes up all threads waiting for this lock. # def broadcast waiters0 = nil Thread.exclusive do waiters0 = @waiters.dup @waiters.clear end for t in waiters0 begin t.run rescue ThreadError end end end end # # This class provides a way to synchronize communication between threads. # # Example: # # require 'thread' # # queue = Queue.new # # producer = Thread.new do # 5.times do |i| # sleep rand(i) # simulate expense # queue << i # puts "#{i} produced" # end # end # # consumer = Thread.new do # 5.times do |i| # value = queue.pop # sleep rand(i/2) # simulate expense # puts "consumed #{value}" # end # end # # consumer.join # class Queue # # Creates a new queue. # def initialize @que = [] @waiting = [] @que.taint # enable tainted comunication @waiting.taint self.taint end # # Pushes +obj+ to the queue. # def push(obj) Thread.critical = true @que.push obj begin t = @waiting.shift t.wakeup if t rescue ThreadError retry ensure Thread.critical = false end begin t.run if t rescue ThreadError end end # # Alias of push # alias << push # # Alias of push # alias enq push # # Retrieves data from the queue. If the queue is empty, the calling thread is # suspended until data is pushed onto the queue. If +non_block+ is true, the # thread isn't suspended, and an exception is raised. # def pop(non_block=false) while (Thread.critical = true; @que.empty?) raise ThreadError, "queue empty" if non_block @waiting.push Thread.current Thread.stop end @que.shift ensure Thread.critical = false end # # Alias of pop # alias shift pop # # Alias of pop # alias deq pop # # Returns +true+ is the queue is empty. # def empty? @que.empty? end # # Removes all objects from the queue. # def clear @que.clear end # # Returns the length of the queue. # def length @que.length end # # Alias of length. # alias size length # # Returns the number of threads waiting on the queue. # def num_waiting @waiting.size end end # # This class represents queues of specified size capacity. The push operation # may be blocked if the capacity is full. # # See Queue for an example of how a SizedQueue works. # class SizedQueue 0 @max = max @queue_wait = [] @queue_wait.taint # enable tainted comunication super() end # # Returns the maximum size of the queue. # def max @max end # # Sets the maximum size of the queue. # def max=(max) Thread.critical = true if max <= @max @max = max Thread.critical = false else diff = max - @max @max = max Thread.critical = false diff.times do begin t = @queue_wait.shift t.run if t rescue ThreadError retry end end end max end # # Pushes +obj+ to the queue. If there is no space left in the queue, waits # until space becomes available. # def push(obj) Thread.critical = true while @que.length >= @max @queue_wait.push Thread.current Thread.stop Thread.critical = true end super end # # Alias of push # alias << push # # Alias of push # alias enq push # # Retrieves data from the queue and runs a waiting thread, if any. # def pop(*args) retval = super Thread.critical = true if @que.length < @max begin t = @queue_wait.shift t.wakeup if t rescue ThreadError retry ensure Thread.critical = false end begin t.run if t rescue ThreadError end end retval end # # Alias of pop # alias shift pop # # Alias of pop # alias deq pop # # Returns the number of threads waiting on the queue. # def num_waiting @waiting.size + @queue_wait.size end end # Documentation comments: # - How do you make RDoc inherit documentation from superclass? ================================================ FILE: lib/thwait.rb ================================================ # # thwait.rb - thread synchronization class # $Release Version: 0.9 $ # $Revision: 1.3 $ # $Date: 1998/06/26 03:19:34 $ # by Keiju ISHITSUKA(Nihpon Rational Software Co.,Ltd.) # # -- # feature: # provides synchronization for multiple threads. # # class methods: # * ThreadsWait.all_waits(thread1,...) # waits until all of specified threads are terminated. # if a block is supplied for the method, evaluates it for # each thread termination. # * th = ThreadsWait.new(thread1,...) # creates synchronization object, specifying thread(s) to wait. # # methods: # * th.threads # list threads to be synchronized # * th.empty? # is there any thread to be synchronized. # * th.finished? # is there already terminated thread. # * th.join(thread1,...) # wait for specified thread(s). # * th.join_nowait(threa1,...) # specifies thread(s) to wait. non-blocking. # * th.next_wait # waits until any of specified threads is terminated. # * th.all_waits # waits until all of specified threads are terminated. # if a block is supplied for the method, evaluates it for # each thread termination. # require "thread.rb" require "e2mmap.rb" # # This class watches for termination of multiple threads. Basic functionality # (wait until specified threads have terminated) can be accessed through the # class method ThreadsWait::all_waits. Finer control can be gained using # instance methods. # # Example: # # ThreadsWait.all_wait(thr1, thr2, ...) do |t| # STDERR.puts "Thread #{t} has terminated." # end # class ThreadsWait RCS_ID='-$Id: thwait.rb,v 1.3 1998/06/26 03:19:34 keiju Exp keiju $-' Exception2MessageMapper.extend_to(binding) def_exception("ErrNoWaitingThread", "No threads for waiting.") def_exception("ErrNoFinishedThread", "No finished threads.") # # Waits until all specified threads have terminated. If a block is provided, # it is executed for each thread termination. # def ThreadsWait.all_waits(*threads) # :yield: thread tw = ThreadsWait.new(*threads) if block_given? tw.all_waits do |th| yield th end else tw.all_waits end end # # Creates a ThreadsWait object, specifying the threads to wait on. # Non-blocking. # def initialize(*threads) @threads = [] @wait_queue = Queue.new join_nowait(*threads) unless threads.empty? end # Returns the array of threads in the wait queue. attr :threads # # Returns +true+ if there are no threads to be synchronized. # def empty? @threads.empty? end # # Returns +true+ if any thread has terminated. # def finished? !@wait_queue.empty? end # # Waits for specified threads to terminate. # def join(*threads) join_nowait(*threads) next_wait end # # Specifies the threads that this object will wait for, but does not actually # wait. # def join_nowait(*threads) threads.flatten! @threads.concat threads for th in threads Thread.start(th) do |t| begin t.join ensure @wait_queue.push t end end end end # # Waits until any of the specified threads has terminated, and returns the one # that does. # # If there is no thread to wait, raises +ErrNoWaitingThread+. If +nonblock+ # is true, and there is no terminated thread, raises +ErrNoFinishedThread+. # def next_wait(nonblock = nil) ThreadsWait.fail ErrNoWaitingThread if @threads.empty? begin @threads.delete(th = @wait_queue.pop(nonblock)) th rescue ThreadError ThreadsWait.fail ErrNoFinishedThread end end # # Waits until all of the specified threads are terminated. If a block is # supplied for the method, it is executed for each thread termination. # # Raises exceptions in the same manner as +next_wait+. # def all_waits until @threads.empty? th = next_wait yield th if block_given? end end end ThWait = ThreadsWait # Documentation comments: # - Source of documentation is evenly split between Nutshell, existing # comments, and my own rephrasing. # - I'm not particularly confident that the comments are all exactly correct. # - The history, etc., up the top appears in the RDoc output. Perhaps it would # be better to direct that not to appear, and put something else there # instead. ================================================ FILE: lib/time.rb ================================================ # # == Introduction # # This library extends the Time class: # * conversion between date string and time object. # * date-time defined by RFC 2822 # * HTTP-date defined by RFC 2616 # * dateTime defined by XML Schema Part 2: Datatypes (ISO 8601) # * various formats handled by Date._parse (string to time only) # # == Design Issues # # === Specialized interface # # This library provides methods dedicated to special purposes: # * RFC 2822, RFC 2616 and XML Schema. # * They makes usual life easier. # # === Doesn't depend on strftime # # This library doesn't use +strftime+. Especially #rfc2822 doesn't depend # on +strftime+ because: # # * %a and %b are locale sensitive # # Since they are locale sensitive, they may be replaced to # invalid weekday/month name in some locales. # Since ruby-1.6 doesn't invoke setlocale by default, # the problem doesn't arise until some external library invokes setlocale. # Ruby/GTK is the example of such library. # # * %z is not portable # # %z is required to generate zone in date-time of RFC 2822 # but it is not portable. # # == Revision Information # # $Id$ # require 'parsedate' # # Implements the extensions to the Time class that are described in the # documentation for the time.rb library. # class Time class << Time ZoneOffset = { 'UTC' => 0, # ISO 8601 'Z' => 0, # RFC 822 'UT' => 0, 'GMT' => 0, 'EST' => -5, 'EDT' => -4, 'CST' => -6, 'CDT' => -5, 'MST' => -7, 'MDT' => -6, 'PST' => -8, 'PDT' => -7, # Following definition of military zones is original one. # See RFC 1123 and RFC 2822 for the error in RFC 822. 'A' => +1, 'B' => +2, 'C' => +3, 'D' => +4, 'E' => +5, 'F' => +6, 'G' => +7, 'H' => +8, 'I' => +9, 'K' => +10, 'L' => +11, 'M' => +12, 'N' => -1, 'O' => -2, 'P' => -3, 'Q' => -4, 'R' => -5, 'S' => -6, 'T' => -7, 'U' => -8, 'V' => -9, 'W' => -10, 'X' => -11, 'Y' => -12, } def zone_offset(zone, year=self.now.year) off = nil zone = zone.upcase if /\A([+-])(\d\d):?(\d\d)\z/ =~ zone off = ($1 == '-' ? -1 : 1) * ($2.to_i * 60 + $3.to_i) * 60 elsif /\A[+-]\d\d\z/ =~ zone off = zone.to_i * 3600 elsif ZoneOffset.include?(zone) off = ZoneOffset[zone] * 3600 elsif ((t = self.local(year, 1, 1)).zone.upcase == zone rescue false) off = t.utc_offset elsif ((t = self.local(year, 7, 1)).zone.upcase == zone rescue false) off = t.utc_offset end off end def zone_utc?(zone) # * +0000 means localtime. [RFC 2822] # * GMT is a localtime abbreviation in Europe/London, etc. if /\A(?:-00:00|-0000|-00|UTC|Z|UT)\z/i =~ zone true else false end end private :zone_utc? LeapYearMonthDays = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] CommonYearMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] def month_days(y, m) if ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0) LeapYearMonthDays[m-1] else CommonYearMonthDays[m-1] end end private :month_days def apply_offset(year, mon, day, hour, min, sec, off) if off < 0 off = -off off, o = off.divmod(60) if o != 0 then sec += o; o, sec = sec.divmod(60); off += o end off, o = off.divmod(60) if o != 0 then min += o; o, min = min.divmod(60); off += o end off, o = off.divmod(24) if o != 0 then hour += o; o, hour = hour.divmod(24); off += o end if off != 0 day += off if month_days(year, mon) < day mon += 1 if 12 < mon mon = 1 year += 1 end day = 1 end end elsif 0 < off off, o = off.divmod(60) if o != 0 then sec -= o; o, sec = sec.divmod(60); off -= o end off, o = off.divmod(60) if o != 0 then min -= o; o, min = min.divmod(60); off -= o end off, o = off.divmod(24) if o != 0 then hour -= o; o, hour = hour.divmod(24); off -= o end if off != 0 then day -= off if day < 1 mon -= 1 if mon < 1 year -= 1 mon = 12 end day = month_days(year, mon) end end end return year, mon, day, hour, min, sec end private :apply_offset def make_time(year, mon, day, hour, min, sec, sec_fraction, zone, now) usec = nil usec = (sec_fraction * 1000000).to_i if sec_fraction if now begin break if year; year = now.year break if mon; mon = now.mon break if day; day = now.day break if hour; hour = now.hour break if min; min = now.min break if sec; sec = now.sec break if sec_fraction; usec = now.tv_usec end until true end year ||= 1970 mon ||= 1 day ||= 1 hour ||= 0 min ||= 0 sec ||= 0 usec ||= 0 off = nil off = zone_offset(zone, year) if zone if off year, mon, day, hour, min, sec = apply_offset(year, mon, day, hour, min, sec, off) t = self.utc(year, mon, day, hour, min, sec, usec) t.localtime if !zone_utc?(zone) t else self.local(year, mon, day, hour, min, sec, usec) end end private :make_time # # Parses +date+ using Date._parse and converts it to a Time object. # # If a block is given, the year described in +date+ is converted by the # block. For example: # # Time.parse(...) {|y| y < 100 ? (y >= 69 ? y + 1900 : y + 2000) : y} # # If the upper components of the given time are broken or missing, they are # supplied with those of +now+. For the lower components, the minimum # values (1 or 0) are assumed if broken or missing. For example: # # # Suppose it is "Thu Nov 29 14:33:20 GMT 2001" now and # # your timezone is GMT: # Time.parse("16:30") #=> Thu Nov 29 16:30:00 GMT 2001 # Time.parse("7/23") #=> Mon Jul 23 00:00:00 GMT 2001 # Time.parse("Aug 31") #=> Fri Aug 31 00:00:00 GMT 2001 # # Since there are numerous conflicts among locally defined timezone # abbreviations all over the world, this method is not made to # understand all of them. For example, the abbreviation "CST" is # used variously as: # # -06:00 in America/Chicago, # -05:00 in America/Havana, # +08:00 in Asia/Harbin, # +09:30 in Australia/Darwin, # +10:30 in Australia/Adelaide, # etc. # # Based on the fact, this method only understands the timezone # abbreviations described in RFC 822 and the system timezone, in the # order named. (i.e. a definition in RFC 822 overrides the system # timezone definition.) The system timezone is taken from # Time.local(year, 1, 1).zone and # Time.local(year, 7, 1).zone. # If the extracted timezone abbreviation does not match any of them, # it is ignored and the given time is regarded as a local time. # # ArgumentError is raised if Date._parse cannot extract information from # +date+ or Time class cannot represent specified date. # # This method can be used as fail-safe for other parsing methods as: # # Time.rfc2822(date) rescue Time.parse(date) # Time.httpdate(date) rescue Time.parse(date) # Time.xmlschema(date) rescue Time.parse(date) # # A failure for Time.parse should be checked, though. # def parse(date, now=self.now) d = Date._parse(date, false) year = d[:year] year = yield(year) if year && block_given? make_time(year, d[:mon], d[:mday], d[:hour], d[:min], d[:sec], d[:sec_fraction], d[:zone], now) end MonthValue = { 'JAN' => 1, 'FEB' => 2, 'MAR' => 3, 'APR' => 4, 'MAY' => 5, 'JUN' => 6, 'JUL' => 7, 'AUG' => 8, 'SEP' => 9, 'OCT' =>10, 'NOV' =>11, 'DEC' =>12 } # # Parses +date+ as date-time defined by RFC 2822 and converts it to a Time # object. The format is identical to the date format defined by RFC 822 and # updated by RFC 1123. # # ArgumentError is raised if +date+ is not compliant with RFC 2822 # or Time class cannot represent specified date. # # See #rfc2822 for more information on this format. # def rfc2822(date) if /\A\s* (?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*,\s*)? (\d{1,2})\s+ (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+ (\d{2,})\s+ (\d{2})\s* :\s*(\d{2})\s* (?::\s*(\d{2}))?\s+ ([+-]\d{4}| UT|GMT|EST|EDT|CST|CDT|MST|MDT|PST|PDT|[A-IK-Z])/ix =~ date # Since RFC 2822 permit comments, the regexp has no right anchor. day = $1.to_i mon = MonthValue[$2.upcase] year = $3.to_i hour = $4.to_i min = $5.to_i sec = $6 ? $6.to_i : 0 zone = $7 # following year completion is compliant with RFC 2822. year = if year < 50 2000 + year elsif year < 1000 1900 + year else year end year, mon, day, hour, min, sec = apply_offset(year, mon, day, hour, min, sec, zone_offset(zone)) t = self.utc(year, mon, day, hour, min, sec) t.localtime if !zone_utc?(zone) t else raise ArgumentError.new("not RFC 2822 compliant date: #{date.inspect}") end end alias rfc822 rfc2822 # # Parses +date+ as HTTP-date defined by RFC 2616 and converts it to a Time # object. # # ArgumentError is raised if +date+ is not compliant with RFC 2616 or Time # class cannot represent specified date. # # See #httpdate for more information on this format. # def httpdate(date) if /\A\s* (?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\x20 (\d{2})\x20 (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\x20 (\d{4})\x20 (\d{2}):(\d{2}):(\d{2})\x20 GMT \s*\z/ix =~ date self.rfc2822(date) elsif /\A\s* (?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday),\x20 (\d\d)-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d\d)\x20 (\d\d):(\d\d):(\d\d)\x20 GMT \s*\z/ix =~ date self.parse(date) elsif /\A\s* (?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)\x20 (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\x20 (\d\d|\x20\d)\x20 (\d\d):(\d\d):(\d\d)\x20 (\d{4}) \s*\z/ix =~ date self.utc($6.to_i, MonthValue[$1.upcase], $2.to_i, $3.to_i, $4.to_i, $5.to_i) else raise ArgumentError.new("not RFC 2616 compliant date: #{date.inspect}") end end # # Parses +date+ as dateTime defined by XML Schema and converts it to a Time # object. The format is restricted version of the format defined by ISO # 8601. # # ArgumentError is raised if +date+ is not compliant with the format or Time # class cannot represent specified date. # # See #xmlschema for more information on this format. # def xmlschema(date) if /\A\s* (-?\d+)-(\d\d)-(\d\d) T (\d\d):(\d\d):(\d\d) (\.\d*)? (Z|[+-]\d\d:\d\d)? \s*\z/ix =~ date year = $1.to_i mon = $2.to_i day = $3.to_i hour = $4.to_i min = $5.to_i sec = $6.to_i usec = 0 usec = ($7[1..-1] + '000000')[0,6].to_i if $7 if $8 zone = $8 year, mon, day, hour, min, sec = apply_offset(year, mon, day, hour, min, sec, zone_offset(zone)) self.utc(year, mon, day, hour, min, sec, usec) else self.local(year, mon, day, hour, min, sec, usec) end else raise ArgumentError.new("invalid date: #{date.inspect}") end end alias iso8601 xmlschema end # class << self # # Returns a string which represents the time as date-time defined by RFC 2822: # # day-of-week, DD month-name CCYY hh:mm:ss zone # # where zone is [+-]hhmm. # # If +self+ is a UTC time, -0000 is used as zone. # def rfc2822 sprintf('%s, %02d %s %d %02d:%02d:%02d ', RFC2822_DAY_NAME[wday], day, RFC2822_MONTH_NAME[mon-1], year, hour, min, sec) + if utc? '-0000' else off = utc_offset sign = off < 0 ? '-' : '+' sprintf('%s%02d%02d', sign, *(off.abs / 60).divmod(60)) end end alias rfc822 rfc2822 RFC2822_DAY_NAME = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ] RFC2822_MONTH_NAME = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ] # # Returns a string which represents the time as rfc1123-date of HTTP-date # defined by RFC 2616: # # day-of-week, DD month-name CCYY hh:mm:ss GMT # # Note that the result is always UTC (GMT). # def httpdate t = dup.utc sprintf('%s, %02d %s %d %02d:%02d:%02d GMT', RFC2822_DAY_NAME[t.wday], t.day, RFC2822_MONTH_NAME[t.mon-1], t.year, t.hour, t.min, t.sec) end # # Returns a string which represents the time as dateTime defined by XML # Schema: # # CCYY-MM-DDThh:mm:ssTZD # CCYY-MM-DDThh:mm:ss.sssTZD # # where TZD is Z or [+-]hh:mm. # # If self is a UTC time, Z is used as TZD. [+-]hh:mm is used otherwise. # # +fractional_seconds+ specifies a number of digits of fractional seconds. # Its default value is 0. # def xmlschema(fraction_digits=0) sprintf('%d-%02d-%02dT%02d:%02d:%02d', year, mon, day, hour, min, sec) + if fraction_digits == 0 '' elsif fraction_digits <= 6 '.' + sprintf('%06d', usec)[0, fraction_digits] else '.' + sprintf('%06d', usec) + '0' * (fraction_digits - 6) end + if utc? 'Z' else off = utc_offset sign = off < 0 ? '-' : '+' sprintf('%s%02d:%02d', sign, *(off.abs / 60).divmod(60)) end end alias iso8601 xmlschema end if __FILE__ == $0 require 'test/unit' class TimeExtentionTest < Test::Unit::TestCase # :nodoc: def test_rfc822 assert_equal(Time.utc(1976, 8, 26, 14, 30) + 4 * 3600, Time.rfc2822("26 Aug 76 14:30 EDT")) assert_equal(Time.utc(1976, 8, 27, 9, 32) + 7 * 3600, Time.rfc2822("27 Aug 76 09:32 PDT")) end def test_rfc2822 assert_equal(Time.utc(1997, 11, 21, 9, 55, 6) + 6 * 3600, Time.rfc2822("Fri, 21 Nov 1997 09:55:06 -0600")) assert_equal(Time.utc(2003, 7, 1, 10, 52, 37) - 2 * 3600, Time.rfc2822("Tue, 1 Jul 2003 10:52:37 +0200")) assert_equal(Time.utc(1997, 11, 21, 10, 1, 10) + 6 * 3600, Time.rfc2822("Fri, 21 Nov 1997 10:01:10 -0600")) assert_equal(Time.utc(1997, 11, 21, 11, 0, 0) + 6 * 3600, Time.rfc2822("Fri, 21 Nov 1997 11:00:00 -0600")) assert_equal(Time.utc(1997, 11, 24, 14, 22, 1) + 8 * 3600, Time.rfc2822("Mon, 24 Nov 1997 14:22:01 -0800")) begin Time.at(-1) rescue ArgumentError # ignore else assert_equal(Time.utc(1969, 2, 13, 23, 32, 54) + 3 * 3600 + 30 * 60, Time.rfc2822("Thu, 13 Feb 1969 23:32:54 -0330")) assert_equal(Time.utc(1969, 2, 13, 23, 32, 0) + 3 * 3600 + 30 * 60, Time.rfc2822(" Thu, 13 Feb 1969 23:32 -0330 (Newfoundland Time)")) end assert_equal(Time.utc(1997, 11, 21, 9, 55, 6), Time.rfc2822("21 Nov 97 09:55:06 GMT")) assert_equal(Time.utc(1997, 11, 21, 9, 55, 6) + 6 * 3600, Time.rfc2822("Fri, 21 Nov 1997 09 : 55 : 06 -0600")) assert_raise(ArgumentError) { # inner comment is not supported. Time.rfc2822("Fri, 21 Nov 1997 09(comment): 55 : 06 -0600") } end def test_rfc2616 t = Time.utc(1994, 11, 6, 8, 49, 37) assert_equal(t, Time.httpdate("Sun, 06 Nov 1994 08:49:37 GMT")) assert_equal(t, Time.httpdate("Sunday, 06-Nov-94 08:49:37 GMT")) assert_equal(t, Time.httpdate("Sun Nov 6 08:49:37 1994")) assert_equal(Time.utc(1995, 11, 15, 6, 25, 24), Time.httpdate("Wed, 15 Nov 1995 06:25:24 GMT")) assert_equal(Time.utc(1995, 11, 15, 4, 58, 8), Time.httpdate("Wed, 15 Nov 1995 04:58:08 GMT")) assert_equal(Time.utc(1994, 11, 15, 8, 12, 31), Time.httpdate("Tue, 15 Nov 1994 08:12:31 GMT")) assert_equal(Time.utc(1994, 12, 1, 16, 0, 0), Time.httpdate("Thu, 01 Dec 1994 16:00:00 GMT")) assert_equal(Time.utc(1994, 10, 29, 19, 43, 31), Time.httpdate("Sat, 29 Oct 1994 19:43:31 GMT")) assert_equal(Time.utc(1994, 11, 15, 12, 45, 26), Time.httpdate("Tue, 15 Nov 1994 12:45:26 GMT")) assert_equal(Time.utc(1999, 12, 31, 23, 59, 59), Time.httpdate("Fri, 31 Dec 1999 23:59:59 GMT")) end def test_rfc3339 t = Time.utc(1985, 4, 12, 23, 20, 50, 520000) s = "1985-04-12T23:20:50.52Z" assert_equal(t, Time.iso8601(s)) assert_equal(s, t.iso8601(2)) t = Time.utc(1996, 12, 20, 0, 39, 57) s = "1996-12-19T16:39:57-08:00" assert_equal(t, Time.iso8601(s)) # There is no way to generate time string with arbitrary timezone. s = "1996-12-20T00:39:57Z" assert_equal(t, Time.iso8601(s)) assert_equal(s, t.iso8601) t = Time.utc(1990, 12, 31, 23, 59, 60) s = "1990-12-31T23:59:60Z" assert_equal(t, Time.iso8601(s)) # leap second is representable only if timezone file has it. s = "1990-12-31T15:59:60-08:00" assert_equal(t, Time.iso8601(s)) begin Time.at(-1) rescue ArgumentError # ignore else t = Time.utc(1937, 1, 1, 11, 40, 27, 870000) s = "1937-01-01T12:00:27.87+00:20" assert_equal(t, Time.iso8601(s)) end end # http://www.w3.org/TR/xmlschema-2/ def test_xmlschema assert_equal(Time.utc(1999, 5, 31, 13, 20, 0) + 5 * 3600, Time.xmlschema("1999-05-31T13:20:00-05:00")) assert_equal(Time.local(2000, 1, 20, 12, 0, 0), Time.xmlschema("2000-01-20T12:00:00")) assert_equal(Time.utc(2000, 1, 20, 12, 0, 0), Time.xmlschema("2000-01-20T12:00:00Z")) assert_equal(Time.utc(2000, 1, 20, 12, 0, 0) - 12 * 3600, Time.xmlschema("2000-01-20T12:00:00+12:00")) assert_equal(Time.utc(2000, 1, 20, 12, 0, 0) + 13 * 3600, Time.xmlschema("2000-01-20T12:00:00-13:00")) assert_equal(Time.utc(2000, 3, 4, 23, 0, 0) - 3 * 3600, Time.xmlschema("2000-03-04T23:00:00+03:00")) assert_equal(Time.utc(2000, 3, 4, 20, 0, 0), Time.xmlschema("2000-03-04T20:00:00Z")) assert_equal(Time.local(2000, 1, 15, 0, 0, 0), Time.xmlschema("2000-01-15T00:00:00")) assert_equal(Time.local(2000, 2, 15, 0, 0, 0), Time.xmlschema("2000-02-15T00:00:00")) assert_equal(Time.local(2000, 1, 15, 12, 0, 0), Time.xmlschema("2000-01-15T12:00:00")) assert_equal(Time.utc(2000, 1, 16, 12, 0, 0), Time.xmlschema("2000-01-16T12:00:00Z")) assert_equal(Time.local(2000, 1, 1, 12, 0, 0), Time.xmlschema("2000-01-01T12:00:00")) assert_equal(Time.utc(1999, 12, 31, 23, 0, 0), Time.xmlschema("1999-12-31T23:00:00Z")) assert_equal(Time.local(2000, 1, 16, 12, 0, 0), Time.xmlschema("2000-01-16T12:00:00")) assert_equal(Time.local(2000, 1, 16, 0, 0, 0), Time.xmlschema("2000-01-16T00:00:00")) assert_equal(Time.utc(2000, 1, 12, 12, 13, 14), Time.xmlschema("2000-01-12T12:13:14Z")) assert_equal(Time.utc(2001, 4, 17, 19, 23, 17, 300000), Time.xmlschema("2001-04-17T19:23:17.3Z")) end def test_encode_xmlschema t = Time.utc(2001, 4, 17, 19, 23, 17, 300000) assert_equal("2001-04-17T19:23:17Z", t.xmlschema) assert_equal("2001-04-17T19:23:17.3Z", t.xmlschema(1)) assert_equal("2001-04-17T19:23:17.300000Z", t.xmlschema(6)) assert_equal("2001-04-17T19:23:17.3000000Z", t.xmlschema(7)) t = Time.utc(2001, 4, 17, 19, 23, 17, 123456) assert_equal("2001-04-17T19:23:17.1234560Z", t.xmlschema(7)) assert_equal("2001-04-17T19:23:17.123456Z", t.xmlschema(6)) assert_equal("2001-04-17T19:23:17.12345Z", t.xmlschema(5)) assert_equal("2001-04-17T19:23:17.1Z", t.xmlschema(1)) begin Time.at(-1) rescue ArgumentError # ignore else t = Time.utc(1960, 12, 31, 23, 0, 0, 123456) assert_equal("1960-12-31T23:00:00.123456Z", t.xmlschema(6)) end assert_equal(249, Time.xmlschema("2008-06-05T23:49:23.000249+09:00").usec) end def test_completion now = Time.local(2001,11,29,21,26,35) assert_equal(Time.local( 2001,11,29,21,12), Time.parse("2001/11/29 21:12", now)) assert_equal(Time.local( 2001,11,29), Time.parse("2001/11/29", now)) assert_equal(Time.local( 2001,11,29), Time.parse( "11/29", now)) #assert_equal(Time.local(2001,11,1), Time.parse("Nov", now)) assert_equal(Time.local( 2001,11,29,10,22), Time.parse( "10:22", now)) end def test_invalid # They were actually used in some web sites. assert_raise(ArgumentError) { Time.httpdate("1 Dec 2001 10:23:57 GMT") } assert_raise(ArgumentError) { Time.httpdate("Sat, 1 Dec 2001 10:25:42 GMT") } assert_raise(ArgumentError) { Time.httpdate("Sat, 1-Dec-2001 10:53:55 GMT") } assert_raise(ArgumentError) { Time.httpdate("Saturday, 01-Dec-2001 10:15:34 GMT") } assert_raise(ArgumentError) { Time.httpdate("Saturday, 01-Dec-101 11:10:07 GMT") } assert_raise(ArgumentError) { Time.httpdate("Fri, 30 Nov 2001 21:30:00 JST") } # They were actually used in some mails. assert_raise(ArgumentError) { Time.rfc2822("01-5-20") } assert_raise(ArgumentError) { Time.rfc2822("7/21/00") } assert_raise(ArgumentError) { Time.rfc2822("2001-8-28") } assert_raise(ArgumentError) { Time.rfc2822("00-5-6 1:13:06") } assert_raise(ArgumentError) { Time.rfc2822("2001-9-27 9:36:49") } assert_raise(ArgumentError) { Time.rfc2822("2000-12-13 11:01:11") } assert_raise(ArgumentError) { Time.rfc2822("2001/10/17 04:29:55") } assert_raise(ArgumentError) { Time.rfc2822("9/4/2001 9:23:19 PM") } assert_raise(ArgumentError) { Time.rfc2822("01 Nov 2001 09:04:31") } assert_raise(ArgumentError) { Time.rfc2822("13 Feb 2001 16:4 GMT") } assert_raise(ArgumentError) { Time.rfc2822("01 Oct 00 5:41:19 PM") } assert_raise(ArgumentError) { Time.rfc2822("2 Jul 00 00:51:37 JST") } assert_raise(ArgumentError) { Time.rfc2822("01 11 2001 06:55:57 -0500") } assert_raise(ArgumentError) { Time.rfc2822("18 \343\366\356\341\370 2000") } assert_raise(ArgumentError) { Time.rfc2822("Fri, Oct 2001 18:53:32") } assert_raise(ArgumentError) { Time.rfc2822("Fri, 2 Nov 2001 03:47:54") } assert_raise(ArgumentError) { Time.rfc2822("Fri, 27 Jul 2001 11.14.14 +0200") } assert_raise(ArgumentError) { Time.rfc2822("Thu, 2 Nov 2000 04:13:53 -600") } assert_raise(ArgumentError) { Time.rfc2822("Wed, 5 Apr 2000 22:57:09 JST") } assert_raise(ArgumentError) { Time.rfc2822("Mon, 11 Sep 2000 19:47:33 00000") } assert_raise(ArgumentError) { Time.rfc2822("Fri, 28 Apr 2000 20:40:47 +-900") } assert_raise(ArgumentError) { Time.rfc2822("Fri, 19 Jan 2001 8:15:36 AM -0500") } assert_raise(ArgumentError) { Time.rfc2822("Thursday, Sep 27 2001 7:42:35 AM EST") } assert_raise(ArgumentError) { Time.rfc2822("3/11/2001 1:31:57 PM Pacific Daylight Time") } assert_raise(ArgumentError) { Time.rfc2822("Mi, 28 Mrz 2001 11:51:36") } assert_raise(ArgumentError) { Time.rfc2822("P, 30 sept 2001 23:03:14") } assert_raise(ArgumentError) { Time.rfc2822("fr, 11 aug 2000 18:39:22") } assert_raise(ArgumentError) { Time.rfc2822("Fr, 21 Sep 2001 17:44:03 -1000") } assert_raise(ArgumentError) { Time.rfc2822("Mo, 18 Jun 2001 19:21:40 -1000") } assert_raise(ArgumentError) { Time.rfc2822("l\366, 12 aug 2000 18:53:20") } assert_raise(ArgumentError) { Time.rfc2822("l\366, 26 maj 2001 00:15:58") } assert_raise(ArgumentError) { Time.rfc2822("Dom, 30 Sep 2001 17:36:30") } assert_raise(ArgumentError) { Time.rfc2822("%&, 31 %2/ 2000 15:44:47 -0500") } assert_raise(ArgumentError) { Time.rfc2822("dom, 26 ago 2001 03:57:07 -0300") } assert_raise(ArgumentError) { Time.rfc2822("ter, 04 set 2001 16:27:58 -0300") } assert_raise(ArgumentError) { Time.rfc2822("Wen, 3 oct 2001 23:17:49 -0400") } assert_raise(ArgumentError) { Time.rfc2822("Wen, 3 oct 2001 23:17:49 -0400") } assert_raise(ArgumentError) { Time.rfc2822("ele, 11 h: 2000 12:42:15 -0500") } assert_raise(ArgumentError) { Time.rfc2822("Tue, 14 Aug 2001 3:55:3 +0200") } assert_raise(ArgumentError) { Time.rfc2822("Fri, 25 Aug 2000 9:3:48 +0800") } assert_raise(ArgumentError) { Time.rfc2822("Fri, 1 Dec 2000 0:57:50 EST") } assert_raise(ArgumentError) { Time.rfc2822("Mon, 7 May 2001 9:39:51 +0200") } assert_raise(ArgumentError) { Time.rfc2822("Wed, 1 Aug 2001 16:9:15 +0200") } assert_raise(ArgumentError) { Time.rfc2822("Wed, 23 Aug 2000 9:17:36 +0800") } assert_raise(ArgumentError) { Time.rfc2822("Fri, 11 Aug 2000 10:4:42 +0800") } assert_raise(ArgumentError) { Time.rfc2822("Sat, 15 Sep 2001 13:22:2 +0300") } assert_raise(ArgumentError) { Time.rfc2822("Wed,16 \276\305\324\302 2001 20:06:25 +0800") } assert_raise(ArgumentError) { Time.rfc2822("Wed,7 \312\256\322\273\324\302 2001 23:47:22 +0800") } assert_raise(ArgumentError) { Time.rfc2822("=?iso-8859-1?Q?(=C5=DA),?= 10 2 2001 23:32:26 +0900 (JST)") } assert_raise(ArgumentError) { Time.rfc2822("\307\341\314\343\332\311, 30 \344\346\335\343\310\321 2001 10:01:06") } assert_raise(ArgumentError) { Time.rfc2822("=?iso-8859-1?Q?(=BF=E5),?= 12 =?iso-8859-1?Q?9=B7=EE?= 2001 14:52:41\n+0900 (JST)") } end def test_zone_0000 assert_equal(true, Time.parse("2000-01-01T00:00:00Z").utc?) assert_equal(true, Time.parse("2000-01-01T00:00:00-00:00").utc?) assert_equal(false, Time.parse("2000-01-01T00:00:00+00:00").utc?) assert_equal(false, Time.parse("Sat, 01 Jan 2000 00:00:00 GMT").utc?) assert_equal(true, Time.parse("Sat, 01 Jan 2000 00:00:00 -0000").utc?) assert_equal(false, Time.parse("Sat, 01 Jan 2000 00:00:00 +0000").utc?) assert_equal(false, Time.rfc2822("Sat, 01 Jan 2000 00:00:00 GMT").utc?) assert_equal(true, Time.rfc2822("Sat, 01 Jan 2000 00:00:00 -0000").utc?) assert_equal(false, Time.rfc2822("Sat, 01 Jan 2000 00:00:00 +0000").utc?) assert_equal(true, Time.rfc2822("Sat, 01 Jan 2000 00:00:00 UTC").utc?) end def test_parse_leap_second t = Time.utc(1998,12,31,23,59,59) assert_equal(t, Time.parse("Thu Dec 31 23:59:59 UTC 1998")) assert_equal(t, Time.parse("Fri Dec 31 23:59:59 -0000 1998"));t.localtime assert_equal(t, Time.parse("Fri Jan 1 08:59:59 +0900 1999")) assert_equal(t, Time.parse("Fri Jan 1 00:59:59 +0100 1999")) assert_equal(t, Time.parse("Fri Dec 31 23:59:59 +0000 1998")) assert_equal(t, Time.parse("Fri Dec 31 22:59:59 -0100 1998"));t.utc t += 1 assert_equal(t, Time.parse("Thu Dec 31 23:59:60 UTC 1998")) assert_equal(t, Time.parse("Fri Dec 31 23:59:60 -0000 1998"));t.localtime assert_equal(t, Time.parse("Fri Jan 1 08:59:60 +0900 1999")) assert_equal(t, Time.parse("Fri Jan 1 00:59:60 +0100 1999")) assert_equal(t, Time.parse("Fri Dec 31 23:59:60 +0000 1998")) assert_equal(t, Time.parse("Fri Dec 31 22:59:60 -0100 1998"));t.utc t += 1 if t.sec == 60 assert_equal(t, Time.parse("Thu Jan 1 00:00:00 UTC 1999")) assert_equal(t, Time.parse("Fri Jan 1 00:00:00 -0000 1999"));t.localtime assert_equal(t, Time.parse("Fri Jan 1 09:00:00 +0900 1999")) assert_equal(t, Time.parse("Fri Jan 1 01:00:00 +0100 1999")) assert_equal(t, Time.parse("Fri Jan 1 00:00:00 +0000 1999")) assert_equal(t, Time.parse("Fri Dec 31 23:00:00 -0100 1998")) end def test_rfc2822_leap_second t = Time.utc(1998,12,31,23,59,59) assert_equal(t, Time.rfc2822("Thu, 31 Dec 1998 23:59:59 UTC")) assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:59 -0000"));t.localtime assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 08:59:59 +0900")) assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 00:59:59 +0100")) assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:59 +0000")) assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 22:59:59 -0100"));t.utc t += 1 assert_equal(t, Time.rfc2822("Thu, 31 Dec 1998 23:59:60 UTC")) assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:60 -0000"));t.localtime assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 08:59:60 +0900")) assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 00:59:60 +0100")) assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:60 +0000")) assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 22:59:60 -0100"));t.utc t += 1 if t.sec == 60 assert_equal(t, Time.rfc2822("Thu, 1 Jan 1999 00:00:00 UTC")) assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 00:00:00 -0000"));t.localtime assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 09:00:00 +0900")) assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 01:00:00 +0100")) assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 00:00:00 +0000")) assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:00:00 -0100")) end def test_xmlschema_leap_second t = Time.utc(1998,12,31,23,59,59) assert_equal(t, Time.xmlschema("1998-12-31T23:59:59Z")) assert_equal(t, Time.xmlschema("1998-12-31T23:59:59-00:00"));t.localtime assert_equal(t, Time.xmlschema("1999-01-01T08:59:59+09:00")) assert_equal(t, Time.xmlschema("1999-01-01T00:59:59+01:00")) assert_equal(t, Time.xmlschema("1998-12-31T23:59:59+00:00")) assert_equal(t, Time.xmlschema("1998-12-31T22:59:59-01:00"));t.utc t += 1 assert_equal(t, Time.xmlschema("1998-12-31T23:59:60Z")) assert_equal(t, Time.xmlschema("1998-12-31T23:59:60-00:00"));t.localtime assert_equal(t, Time.xmlschema("1999-01-01T08:59:60+09:00")) assert_equal(t, Time.xmlschema("1999-01-01T00:59:60+01:00")) assert_equal(t, Time.xmlschema("1998-12-31T23:59:60+00:00")) assert_equal(t, Time.xmlschema("1998-12-31T22:59:60-01:00"));t.utc t += 1 if t.sec == 60 assert_equal(t, Time.xmlschema("1999-01-01T00:00:00Z")) assert_equal(t, Time.xmlschema("1999-01-01T00:00:00-00:00"));t.localtime assert_equal(t, Time.xmlschema("1999-01-01T09:00:00+09:00")) assert_equal(t, Time.xmlschema("1999-01-01T01:00:00+01:00")) assert_equal(t, Time.xmlschema("1999-01-01T00:00:00+00:00")) assert_equal(t, Time.xmlschema("1998-12-31T23:00:00-01:00")) end def test_ruby_talk_152866 t = Time::xmlschema('2005-08-30T22:48:00-07:00') assert_equal(31, t.day) assert_equal(8, t.mon) end def test_parse_fraction assert_equal(500000, Time.parse("2000-01-01T00:00:00.5+00:00").tv_usec) end end end ================================================ FILE: lib/timeout.rb ================================================ #-- # = timeout.rb # # execution timeout # # = Copyright # # Copyright:: (C) 2000 Network Applied Communication Laboratory, Inc. # Copyright:: (C) 2000 Information-technology Promotion Agency, Japan # #++ # # = Description # # A way of performing a potentially long-running operation in a thread, and # terminating it's execution if it hasn't finished within fixed amount of # time. # # Previous versions of timeout didn't use a module for namespace. This version # provides both Timeout.timeout, and a backwards-compatible #timeout. # # = Synopsis # # require 'timeout' # status = Timeout::timeout(5) { # # Something that should be interrupted if it takes too much time... # } # module Timeout ## # Raised by Timeout#timeout when the block times out. class Error < Interrupt end class ExitException < ::Exception # :nodoc: end THIS_FILE = /\A#{Regexp.quote(__FILE__)}:/o CALLER_OFFSET = ((c = caller[0]) && THIS_FILE =~ c) ? 1 : 0 ## # Executes the method's block. If the block execution terminates before +sec+ # seconds has passed, it returns true. If not, it terminates the execution # and raises +exception+ (which defaults to Timeout::Error). # # Note that this is both a method of module Timeout, so you can 'include # Timeout' into your classes so they have a #timeout method, as well as a # module method, so you can call it directly as Timeout.timeout(). def timeout(sec, klass = nil) return yield if sec == nil or sec.zero? raise ThreadError, "timeout within critical session" if Thread.critical exception = klass || Class.new(ExitException) begin x = Thread.current y = Thread.start { sleep sec x.raise exception, "execution expired" if x.alive? } yield sec # return true rescue exception => e rej = /\A#{Regexp.quote(__FILE__)}:#{__LINE__-4}\z/o (bt = e.backtrace).reject! {|m| rej =~ m} level = -caller(CALLER_OFFSET).size while THIS_FILE =~ bt[level] bt.delete_at(level) level += 1 end raise if klass # if exception class is specified, it # would be expected outside. raise Error, e.message, e.backtrace ensure y.kill if y and y.alive? end end module_function :timeout end ## # Identical to: # # Timeout::timeout(n, e, &block). # # Defined for backwards compatibility with earlier versions of timeout.rb, see # Timeout#timeout. def timeout(n, e = nil, &block) # :nodoc: Timeout::timeout(n, e, &block) end ## # Another name for Timeout::Error, defined for backwards compatibility with # earlier versions of timeout.rb. TimeoutError = Timeout::Error # :nodoc: if __FILE__ == $0 p timeout(5) { 45 } p timeout(5, TimeoutError) { 45 } p timeout(nil) { 54 } p timeout(0) { 54 } p timeout(5) { loop { p 10 sleep 1 } } end ================================================ FILE: lib/tmpdir.rb ================================================ # # tmpdir - retrieve temporary directory path # # $Id$ # require 'fileutils' class Dir @@systmpdir = '/tmp' begin require 'Win32API' CSIDL_LOCAL_APPDATA = 0x001c max_pathlen = 260 windir = "\0"*(max_pathlen+1) begin getdir = Win32API.new('shell32', 'SHGetFolderPath', 'LLLLP', 'L') raise RuntimeError if getdir.call(0, CSIDL_LOCAL_APPDATA, 0, 0, windir) != 0 windir = File.expand_path(windir.rstrip) rescue RuntimeError begin getdir = Win32API.new('kernel32', 'GetSystemWindowsDirectory', 'PL', 'L') rescue RuntimeError getdir = Win32API.new('kernel32', 'GetWindowsDirectory', 'PL', 'L') end len = getdir.call(windir, windir.size) windir = File.expand_path(windir[0, len]) end temp = File.join(windir.untaint, 'temp') @@systmpdir = temp if File.directory?(temp) and File.writable?(temp) rescue LoadError end ## # Returns the operating system's temporary file path. def Dir::tmpdir tmp = '.' if $SAFE > 0 tmp = @@systmpdir else for dir in [ENV['TMPDIR'], ENV['TMP'], ENV['TEMP'], ENV['USERPROFILE'], @@systmpdir, '/tmp'] if dir and File.directory?(dir) and File.writable?(dir) tmp = dir break end end File.expand_path(tmp) end end # Dir.mktmpdir creates a temporary directory. # # The directory is created with 0700 permission. # # The prefix and suffix of the name of the directory is specified by # the optional first argument, prefix_suffix. # - If it is not specified or nil, "d" is used as the prefix and no suffix is used. # - If it is a string, it is used as the prefix and no suffix is used. # - If it is an array, first element is used as the prefix and second element is used as a suffix. # # Dir.mktmpdir {|dir| dir is ".../d..." } # Dir.mktmpdir("foo") {|dir| dir is ".../foo..." } # Dir.mktmpdir(["foo", "bar"]) {|dir| dir is ".../foo...bar" } # # The directory is created under Dir.tmpdir or # the optional second argument tmpdir if non-nil value is given. # # Dir.mktmpdir {|dir| dir is "#{Dir.tmpdir}/d..." } # Dir.mktmpdir(nil, "/var/tmp") {|dir| dir is "/var/tmp/d..." } # # If a block is given, # it is yielded with the path of the directory. # The directory and its contents are removed # using FileUtils.remove_entry_secure before Dir.mktmpdir returns. # The value of the block is returned. # # Dir.mktmpdir {|dir| # # use the directory... # open("#{dir}/foo", "w") { ... } # } # # If a block is not given, # The path of the directory is returned. # In this case, Dir.mktmpdir doesn't remove the directory. # # dir = Dir.mktmpdir # begin # # use the directory... # open("#{dir}/foo", "w") { ... } # ensure # # remove the directory. # FileUtils.remove_entry_secure dir # end # def Dir.mktmpdir(prefix_suffix=nil, tmpdir=nil) case prefix_suffix when nil prefix = "d" suffix = "" when String prefix = prefix_suffix suffix = "" when Array prefix = prefix_suffix[0] suffix = prefix_suffix[1] else raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}" end tmpdir ||= Dir.tmpdir t = Time.now.strftime("%Y%m%d") n = nil begin path = "#{tmpdir}/#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}" path << "-#{n}" if n path << suffix Dir.mkdir(path, 0700) rescue Errno::EEXIST n ||= 0 n += 1 retry end if block_given? begin yield path ensure FileUtils.remove_entry_secure path end else path end end end ================================================ FILE: lib/tracer.rb ================================================ # # tracer.rb - # $Release Version: 0.2$ # $Revision: 1.8 $ # $Date: 1998/05/19 03:42:49 $ # by Keiju ISHITSUKA(Nippon Rational Inc.) # # -- # # # # # tracer main class # class Tracer @RCS_ID='-$Id: tracer.rb,v 1.8 1998/05/19 03:42:49 keiju Exp keiju $-' @stdout = STDOUT @verbose = false class << self attr :verbose, true alias verbose? verbose attr :stdout, true end EVENT_SYMBOL = { "line" => "-", "call" => ">", "return" => "<", "class" => "C", "end" => "E", "c-call" => ">", "c-return" => "<", } def initialize @threads = Hash.new if defined? Thread.main @threads[Thread.main.object_id] = 0 else @threads[Thread.current.object_id] = 0 end @get_line_procs = {} @filters = [] end def stdout Tracer.stdout end def on if block_given? on begin yield ensure off end else set_trace_func method(:trace_func).to_proc stdout.print "Trace on\n" if Tracer.verbose? end end def off set_trace_func nil stdout.print "Trace off\n" if Tracer.verbose? end def add_filter(p = proc) @filters.push p end def set_get_line_procs(file, p = proc) @get_line_procs[file] = p end def get_line(file, line) if p = @get_line_procs[file] return p.call(line) end unless list = SCRIPT_LINES__[file] begin f = open(file) begin SCRIPT_LINES__[file] = list = f.readlines ensure f.close end rescue SCRIPT_LINES__[file] = list = [] end end if l = list[line - 1] l else "-\n" end end def get_thread_no if no = @threads[Thread.current.object_id] no else @threads[Thread.current.object_id] = @threads.size end end def trace_func(event, file, line, id, binding, klass, *) return if file == __FILE__ for p in @filters return unless p.call event, file, line, id, binding, klass end saved_crit = Thread.critical Thread.critical = true stdout.printf("#%d:%s:%d:%s:%s: %s", get_thread_no, file, line, klass || '', EVENT_SYMBOL[event], get_line(file, line)) Thread.critical = saved_crit end Single = new def Tracer.on if block_given? Single.on{yield} else Single.on end end def Tracer.off Single.off end def Tracer.set_get_line_procs(file_name, p = proc) Single.set_get_line_procs(file_name, p) end def Tracer.add_filter(p = proc) Single.add_filter(p) end end SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__ if $0 == __FILE__ # direct call $0 = ARGV[0] ARGV.shift Tracer.on require $0 elsif caller(0).size == 1 Tracer.on end ================================================ FILE: lib/tsort.rb ================================================ #!/usr/bin/env ruby #-- # tsort.rb - provides a module for topological sorting and strongly connected components. #++ # # # TSort implements topological sorting using Tarjan's algorithm for # strongly connected components. # # TSort is designed to be able to be used with any object which can be # interpreted as a directed graph. # # TSort requires two methods to interpret an object as a graph, # tsort_each_node and tsort_each_child. # # * tsort_each_node is used to iterate for all nodes over a graph. # * tsort_each_child is used to iterate for child nodes of a given node. # # The equality of nodes are defined by eql? and hash since # TSort uses Hash internally. # # == A Simple Example # # The following example demonstrates how to mix the TSort module into an # existing class (in this case, Hash). Here, we're treating each key in # the hash as a node in the graph, and so we simply alias the required # #tsort_each_node method to Hash's #each_key method. For each key in the # hash, the associated value is an array of the node's child nodes. This # choice in turn leads to our implementation of the required #tsort_each_child # method, which fetches the array of child nodes and then iterates over that # array using the user-supplied block. # # require 'tsort' # # class Hash # include TSort # alias tsort_each_node each_key # def tsort_each_child(node, &block) # fetch(node).each(&block) # end # end # # {1=>[2, 3], 2=>[3], 3=>[], 4=>[]}.tsort # #=> [3, 2, 1, 4] # # {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}.strongly_connected_components # #=> [[4], [2, 3], [1]] # # == A More Realistic Example # # A very simple `make' like tool can be implemented as follows: # # require 'tsort' # # class Make # def initialize # @dep = {} # @dep.default = [] # end # # def rule(outputs, inputs=[], &block) # triple = [outputs, inputs, block] # outputs.each {|f| @dep[f] = [triple]} # @dep[triple] = inputs # end # # def build(target) # each_strongly_connected_component_from(target) {|ns| # if ns.length != 1 # fs = ns.delete_if {|n| Array === n} # raise TSort::Cyclic.new("cyclic dependencies: #{fs.join ', '}") # end # n = ns.first # if Array === n # outputs, inputs, block = n # inputs_time = inputs.map {|f| File.mtime f}.max # begin # outputs_time = outputs.map {|f| File.mtime f}.min # rescue Errno::ENOENT # outputs_time = nil # end # if outputs_time == nil || # inputs_time != nil && outputs_time <= inputs_time # sleep 1 if inputs_time != nil && inputs_time.to_i == Time.now.to_i # block.call # end # end # } # end # # def tsort_each_child(node, &block) # @dep[node].each(&block) # end # include TSort # end # # def command(arg) # print arg, "\n" # system arg # end # # m = Make.new # m.rule(%w[t1]) { command 'date > t1' } # m.rule(%w[t2]) { command 'date > t2' } # m.rule(%w[t3]) { command 'date > t3' } # m.rule(%w[t4], %w[t1 t3]) { command 'cat t1 t3 > t4' } # m.rule(%w[t5], %w[t4 t2]) { command 'cat t4 t2 > t5' } # m.build('t5') # # == Bugs # # * 'tsort.rb' is wrong name because this library uses # Tarjan's algorithm for strongly connected components. # Although 'strongly_connected_components.rb' is correct but too long. # # == References # # R. E. Tarjan, "Depth First Search and Linear Graph Algorithms", # SIAM Journal on Computing, Vol. 1, No. 2, pp. 146-160, June 1972. # module TSort class Cyclic < StandardError end # # Returns a topologically sorted array of nodes. # The array is sorted from children to parents, i.e. # the first element has no child and the last node has no parent. # # If there is a cycle, TSort::Cyclic is raised. # def tsort result = [] tsort_each {|element| result << element} result end # # The iterator version of the #tsort method. # obj.tsort_each is similar to obj.tsort.each, but # modification of _obj_ during the iteration may lead to unexpected results. # # #tsort_each returns +nil+. # If there is a cycle, TSort::Cyclic is raised. # def tsort_each # :yields: node each_strongly_connected_component {|component| if component.size == 1 yield component.first else raise Cyclic.new("topological sort failed: #{component.inspect}") end } end # # Returns strongly connected components as an array of arrays of nodes. # The array is sorted from children to parents. # Each elements of the array represents a strongly connected component. # def strongly_connected_components result = [] each_strongly_connected_component {|component| result << component} result end # # The iterator version of the #strongly_connected_components method. # obj.each_strongly_connected_component is similar to # obj.strongly_connected_components.each, but # modification of _obj_ during the iteration may lead to unexpected results. # # # #each_strongly_connected_component returns +nil+. # def each_strongly_connected_component # :yields: nodes id_map = {} stack = [] tsort_each_node {|node| unless id_map.include? node each_strongly_connected_component_from(node, id_map, stack) {|c| yield c } end } nil end # # Iterates over strongly connected component in the subgraph reachable from # _node_. # # Return value is unspecified. # # #each_strongly_connected_component_from doesn't call #tsort_each_node. # def each_strongly_connected_component_from(node, id_map={}, stack=[]) # :yields: nodes minimum_id = node_id = id_map[node] = id_map.size stack_length = stack.length stack << node tsort_each_child(node) {|child| if id_map.include? child child_id = id_map[child] minimum_id = child_id if child_id && child_id < minimum_id else sub_minimum_id = each_strongly_connected_component_from(child, id_map, stack) {|c| yield c } minimum_id = sub_minimum_id if sub_minimum_id < minimum_id end } if node_id == minimum_id component = stack.slice!(stack_length .. -1) component.each {|n| id_map[n] = nil} yield component end minimum_id end # # Should be implemented by a extended class. # # #tsort_each_node is used to iterate for all nodes over a graph. # def tsort_each_node # :yields: node raise NotImplementedError.new end # # Should be implemented by a extended class. # # #tsort_each_child is used to iterate for child nodes of _node_. # def tsort_each_child(node) # :yields: child raise NotImplementedError.new end end if __FILE__ == $0 require 'test/unit' class TSortHash < Hash # :nodoc: include TSort alias tsort_each_node each_key def tsort_each_child(node, &block) fetch(node).each(&block) end end class TSortArray < Array # :nodoc: include TSort alias tsort_each_node each_index def tsort_each_child(node, &block) fetch(node).each(&block) end end class TSortTest < Test::Unit::TestCase # :nodoc: def test_dag h = TSortHash[{1=>[2, 3], 2=>[3], 3=>[]}] assert_equal([3, 2, 1], h.tsort) assert_equal([[3], [2], [1]], h.strongly_connected_components) end def test_cycle h = TSortHash[{1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}] assert_equal([[4], [2, 3], [1]], h.strongly_connected_components.map {|nodes| nodes.sort}) assert_raise(TSort::Cyclic) { h.tsort } end def test_array a = TSortArray[[1], [0], [0], [2]] assert_equal([[0, 1], [2], [3]], a.strongly_connected_components.map {|nodes| nodes.sort}) a = TSortArray[[], [0]] assert_equal([[0], [1]], a.strongly_connected_components.map {|nodes| nodes.sort}) end end end ================================================ FILE: lib/un.rb ================================================ # # = un.rb # # Copyright (c) 2003 WATANABE Hirofumi # # This program is free software. # You can distribute/modify this program under the same terms of Ruby. # # == Utilities to replace common UNIX commands in Makefiles etc # # == SYNOPSIS # # ruby -run -e cp -- [OPTION] SOURCE DEST # ruby -run -e ln -- [OPTION] TARGET LINK_NAME # ruby -run -e mv -- [OPTION] SOURCE DEST # ruby -run -e rm -- [OPTION] FILE # ruby -run -e mkdir -- [OPTION] DIRS # ruby -run -e rmdir -- [OPTION] DIRS # ruby -run -e install -- [OPTION] SOURCE DEST # ruby -run -e chmod -- [OPTION] OCTAL-MODE FILE # ruby -run -e touch -- [OPTION] FILE # ruby -run -e help [COMMAND] require "fileutils" require "optparse" module FileUtils # @fileutils_label = "" @fileutils_output = $stdout end def setup(options = "") ARGV.map! do |x| case x when /^-/ x.delete "^-#{options}v" when /[*?\[{]/ Dir[x] else x end end ARGV.flatten! ARGV.delete_if{|x| x == "-"} opt_hash = {} OptionParser.new do |o| options.scan(/.:?/) do |s| o.on("-" + s.tr(":", " ")) do |val| opt_hash[s.delete(":").intern] = val end end o.on("-v") do opt_hash[:verbose] = true end o.parse! end yield ARGV, opt_hash end ## # Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY # # ruby -run -e cp -- [OPTION] SOURCE DEST # # -p preserve file attributes if possible # -r copy recursively # -v verbose # def cp setup("pr") do |argv, options| cmd = "cp" cmd += "_r" if options.delete :r options[:preserve] = true if options.delete :p dest = argv.pop argv = argv[0] if argv.size == 1 FileUtils.send cmd, argv, dest, options end end ## # Create a link to the specified TARGET with LINK_NAME. # # ruby -run -e ln -- [OPTION] TARGET LINK_NAME # # -s make symbolic links instead of hard links # -f remove existing destination files # -v verbose # def ln setup("sf") do |argv, options| cmd = "ln" cmd += "_s" if options.delete :s options[:force] = true if options.delete :f dest = argv.pop argv = argv[0] if argv.size == 1 FileUtils.send cmd, argv, dest, options end end ## # Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY. # # ruby -run -e mv -- [OPTION] SOURCE DEST # # -v verbose # def mv setup do |argv, options| dest = argv.pop argv = argv[0] if argv.size == 1 FileUtils.mv argv, dest, options end end ## # Remove the FILE # # ruby -run -e rm -- [OPTION] FILE # # -f ignore nonexistent files # -r remove the contents of directories recursively # -v verbose # def rm setup("fr") do |argv, options| cmd = "rm" cmd += "_r" if options.delete :r options[:force] = true if options.delete :f FileUtils.send cmd, argv, options end end ## # Create the DIR, if they do not already exist. # # ruby -run -e mkdir -- [OPTION] DIR # # -p no error if existing, make parent directories as needed # -v verbose # def mkdir setup("p") do |argv, options| cmd = "mkdir" cmd += "_p" if options.delete :p FileUtils.send cmd, argv, options end end ## # Remove the DIR. # # ruby -run -e rmdir -- [OPTION] DIR # # -v verbose # def rmdir setup do |argv, options| FileUtils.rmdir argv, options end end ## # Copy SOURCE to DEST. # # ruby -run -e install -- [OPTION] SOURCE DEST # # -p apply access/modification times of SOURCE files to # corresponding destination files # -m set permission mode (as in chmod), instead of 0755 # -v verbose # def install setup("pm:") do |argv, options| options[:mode] = (mode = options.delete :m) ? mode.oct : 0755 options[:preserve] = true if options.delete :p dest = argv.pop argv = argv[0] if argv.size == 1 FileUtils.install argv, dest, options end end ## # Change the mode of each FILE to OCTAL-MODE. # # ruby -run -e chmod -- [OPTION] OCTAL-MODE FILE # # -v verbose # def chmod setup do |argv, options| mode = argv.shift.oct FileUtils.chmod mode, argv, options end end ## # Update the access and modification times of each FILE to the current time. # # ruby -run -e touch -- [OPTION] FILE # # -v verbose # def touch setup do |argv, options| FileUtils.touch argv, options end end ## # Display help message. # # ruby -run -e help [COMMAND] # def help setup do |argv,| all = argv.empty? open(__FILE__) do |me| while me.gets("##\n") if help = me.gets("\n\n") if all or argv.delete help[/-e \w+/].sub(/-e /, "") print help.gsub(/^# ?/, "") end end end end end end ================================================ FILE: lib/uri/common.rb ================================================ # = uri/common.rb # # Author:: Akira Yamada # Revision:: $Id$ # License:: # You can redistribute it and/or modify it under the same term as Ruby. # module URI module REGEXP # # Patterns used to parse URI's # module PATTERN # :stopdoc: # RFC 2396 (URI Generic Syntax) # RFC 2732 (IPv6 Literal Addresses in URL's) # RFC 2373 (IPv6 Addressing Architecture) # alpha = lowalpha | upalpha ALPHA = "a-zA-Z" # alphanum = alpha | digit ALNUM = "#{ALPHA}\\d" # hex = digit | "A" | "B" | "C" | "D" | "E" | "F" | # "a" | "b" | "c" | "d" | "e" | "f" HEX = "a-fA-F\\d" # escaped = "%" hex hex ESCAPED = "%[#{HEX}]{2}" # mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | # "(" | ")" # unreserved = alphanum | mark UNRESERVED = "-_.!~*'()#{ALNUM}" # reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | # "$" | "," # reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | # "$" | "," | "[" | "]" (RFC 2732) RESERVED = ";/?:@&=+$,\\[\\]" # uric = reserved | unreserved | escaped URIC = "(?:[#{UNRESERVED}#{RESERVED}]|#{ESCAPED})" # uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" | # "&" | "=" | "+" | "$" | "," URIC_NO_SLASH = "(?:[#{UNRESERVED};?:@&=+$,]|#{ESCAPED})" # query = *uric QUERY = "#{URIC}*" # fragment = *uric FRAGMENT = "#{URIC}*" # domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum DOMLABEL = "(?:[#{ALNUM}](?:[-#{ALNUM}]*[#{ALNUM}])?)" # toplabel = alpha | alpha *( alphanum | "-" ) alphanum TOPLABEL = "(?:[#{ALPHA}](?:[-#{ALNUM}]*[#{ALNUM}])?)" # hostname = *( domainlabel "." ) toplabel [ "." ] HOSTNAME = "(?:#{DOMLABEL}\\.)*#{TOPLABEL}\\.?" # RFC 2373, APPENDIX B: # IPv6address = hexpart [ ":" IPv4address ] # IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT # hexpart = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ] # hexseq = hex4 *( ":" hex4) # hex4 = 1*4HEXDIG # # XXX: This definition has a flaw. "::" + IPv4address must be # allowed too. Here is a replacement. # # IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT IPV4ADDR = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}" # hex4 = 1*4HEXDIG HEX4 = "[#{HEX}]{1,4}" # lastpart = hex4 | IPv4address LASTPART = "(?:#{HEX4}|#{IPV4ADDR})" # hexseq1 = *( hex4 ":" ) hex4 HEXSEQ1 = "(?:#{HEX4}:)*#{HEX4}" # hexseq2 = *( hex4 ":" ) lastpart HEXSEQ2 = "(?:#{HEX4}:)*#{LASTPART}" # IPv6address = hexseq2 | [ hexseq1 ] "::" [ hexseq2 ] IPV6ADDR = "(?:#{HEXSEQ2}|(?:#{HEXSEQ1})?::(?:#{HEXSEQ2})?)" # IPv6prefix = ( hexseq1 | [ hexseq1 ] "::" [ hexseq1 ] ) "/" 1*2DIGIT # unused # ipv6reference = "[" IPv6address "]" (RFC 2732) IPV6REF = "\\[#{IPV6ADDR}\\]" # host = hostname | IPv4address # host = hostname | IPv4address | IPv6reference (RFC 2732) HOST = "(?:#{HOSTNAME}|#{IPV4ADDR}|#{IPV6REF})" # port = *digit PORT = '\d*' # hostport = host [ ":" port ] HOSTPORT = "#{HOST}(?::#{PORT})?" # userinfo = *( unreserved | escaped | # ";" | ":" | "&" | "=" | "+" | "$" | "," ) USERINFO = "(?:[#{UNRESERVED};:&=+$,]|#{ESCAPED})*" # pchar = unreserved | escaped | # ":" | "@" | "&" | "=" | "+" | "$" | "," PCHAR = "(?:[#{UNRESERVED}:@&=+$,]|#{ESCAPED})" # param = *pchar PARAM = "#{PCHAR}*" # segment = *pchar *( ";" param ) SEGMENT = "#{PCHAR}*(?:;#{PARAM})*" # path_segments = segment *( "/" segment ) PATH_SEGMENTS = "#{SEGMENT}(?:/#{SEGMENT})*" # server = [ [ userinfo "@" ] hostport ] SERVER = "(?:#{USERINFO}@)?#{HOSTPORT}" # reg_name = 1*( unreserved | escaped | "$" | "," | # ";" | ":" | "@" | "&" | "=" | "+" ) REG_NAME = "(?:[#{UNRESERVED}$,;:@&=+]|#{ESCAPED})+" # authority = server | reg_name AUTHORITY = "(?:#{SERVER}|#{REG_NAME})" # rel_segment = 1*( unreserved | escaped | # ";" | "@" | "&" | "=" | "+" | "$" | "," ) REL_SEGMENT = "(?:[#{UNRESERVED};@&=+$,]|#{ESCAPED})+" # scheme = alpha *( alpha | digit | "+" | "-" | "." ) SCHEME = "[#{ALPHA}][-+.#{ALPHA}\\d]*" # abs_path = "/" path_segments ABS_PATH = "/#{PATH_SEGMENTS}" # rel_path = rel_segment [ abs_path ] REL_PATH = "#{REL_SEGMENT}(?:#{ABS_PATH})?" # net_path = "//" authority [ abs_path ] NET_PATH = "//#{AUTHORITY}(?:#{ABS_PATH})?" # hier_part = ( net_path | abs_path ) [ "?" query ] HIER_PART = "(?:#{NET_PATH}|#{ABS_PATH})(?:\\?(?:#{QUERY}))?" # opaque_part = uric_no_slash *uric OPAQUE_PART = "#{URIC_NO_SLASH}#{URIC}*" # absoluteURI = scheme ":" ( hier_part | opaque_part ) ABS_URI = "#{SCHEME}:(?:#{HIER_PART}|#{OPAQUE_PART})" # relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ] REL_URI = "(?:#{NET_PATH}|#{ABS_PATH}|#{REL_PATH})(?:\\?#{QUERY})?" # URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] URI_REF = "(?:#{ABS_URI}|#{REL_URI})?(?:##{FRAGMENT})?" # XXX: X_ABS_URI = " (#{PATTERN::SCHEME}): (?# 1: scheme) (?: (#{PATTERN::OPAQUE_PART}) (?# 2: opaque) | (?:(?: //(?: (?:(?:(#{PATTERN::USERINFO})@)? (?# 3: userinfo) (?:(#{PATTERN::HOST})(?::(\\d*))?))?(?# 4: host, 5: port) | (#{PATTERN::REG_NAME}) (?# 6: registry) ) | (?!//)) (?# XXX: '//' is the mark for hostport) (#{PATTERN::ABS_PATH})? (?# 7: path) )(?:\\?(#{PATTERN::QUERY}))? (?# 8: query) ) (?:\\#(#{PATTERN::FRAGMENT}))? (?# 9: fragment) " X_REL_URI = " (?: (?: // (?: (?:(#{PATTERN::USERINFO})@)? (?# 1: userinfo) (#{PATTERN::HOST})?(?::(\\d*))? (?# 2: host, 3: port) | (#{PATTERN::REG_NAME}) (?# 4: registry) ) ) | (#{PATTERN::REL_SEGMENT}) (?# 5: rel_segment) )? (#{PATTERN::ABS_PATH})? (?# 6: abs_path) (?:\\?(#{PATTERN::QUERY}))? (?# 7: query) (?:\\#(#{PATTERN::FRAGMENT}))? (?# 8: fragment) " # :startdoc: end # PATTERN # :stopdoc: # for URI::split ABS_URI = Regexp.new('^' + PATTERN::X_ABS_URI + '$', #' Regexp::EXTENDED, 'N').freeze REL_URI = Regexp.new('^' + PATTERN::X_REL_URI + '$', #' Regexp::EXTENDED, 'N').freeze # for URI::extract URI_REF = Regexp.new(PATTERN::URI_REF, false, 'N').freeze ABS_URI_REF = Regexp.new(PATTERN::X_ABS_URI, Regexp::EXTENDED, 'N').freeze REL_URI_REF = Regexp.new(PATTERN::X_REL_URI, Regexp::EXTENDED, 'N').freeze # for URI::escape/unescape ESCAPED = Regexp.new(PATTERN::ESCAPED, false, 'N').freeze UNSAFE = Regexp.new("[^#{PATTERN::UNRESERVED}#{PATTERN::RESERVED}]", false, 'N').freeze # for Generic#initialize SCHEME = Regexp.new("^#{PATTERN::SCHEME}$", false, 'N').freeze #" USERINFO = Regexp.new("^#{PATTERN::USERINFO}$", false, 'N').freeze #" HOST = Regexp.new("^#{PATTERN::HOST}$", false, 'N').freeze #" PORT = Regexp.new("^#{PATTERN::PORT}$", false, 'N').freeze #" OPAQUE = Regexp.new("^#{PATTERN::OPAQUE_PART}$", false, 'N').freeze #" REGISTRY = Regexp.new("^#{PATTERN::REG_NAME}$", false, 'N').freeze #" ABS_PATH = Regexp.new("^#{PATTERN::ABS_PATH}$", false, 'N').freeze #" REL_PATH = Regexp.new("^#{PATTERN::REL_PATH}$", false, 'N').freeze #" QUERY = Regexp.new("^#{PATTERN::QUERY}$", false, 'N').freeze #" FRAGMENT = Regexp.new("^#{PATTERN::FRAGMENT}$", false, 'N').freeze #" # :startdoc: end # REGEXP module Util # :nodoc: def make_components_hash(klass, array_hash) tmp = {} if array_hash.kind_of?(Array) && array_hash.size == klass.component.size - 1 klass.component[1..-1].each_index do |i| begin tmp[klass.component[i + 1]] = array_hash[i].clone rescue TypeError tmp[klass.component[i + 1]] = array_hash[i] end end elsif array_hash.kind_of?(Hash) array_hash.each do |key, value| begin tmp[key] = value.clone rescue TypeError tmp[key] = value end end else raise ArgumentError, "expected Array of or Hash of components of #{klass.to_s} (#{klass.component[1..-1].join(', ')})" end tmp[:scheme] = klass.to_s.sub(/\A.*::/, '').downcase return tmp end module_function :make_components_hash end module Escape include REGEXP # # == Synopsis # # URI.escape(str [, unsafe]) # # == Args # # +str+:: # String to replaces in. # +unsafe+:: # Regexp that matches all symbols that must be replaced with codes. # By default uses REGEXP::UNSAFE. # When this argument is a String, it represents a character set. # # == Description # # Escapes the string, replacing all unsafe characters with codes. # # == Usage # # require 'uri' # # enc_uri = URI.escape("http://example.com/?a=\11\15") # p enc_uri # # => "http://example.com/?a=%09%0D" # # p URI.unescape(enc_uri) # # => "http://example.com/?a=\t\r" # # p URI.escape("@?@!", "!?") # # => "@%3F@%21" # def escape(str, unsafe = UNSAFE) unless unsafe.kind_of?(Regexp) # perhaps unsafe is String object unsafe = Regexp.new("[#{Regexp.quote(unsafe)}]", false, 'N') end str.gsub(unsafe) do |us| tmp = '' us.each_byte do |uc| tmp << sprintf('%%%02X', uc) end tmp end end alias encode escape # # == Synopsis # # URI.unescape(str) # # == Args # # +str+:: # Unescapes the string. # # == Usage # # require 'uri' # # enc_uri = URI.escape("http://example.com/?a=\11\15") # p enc_uri # # => "http://example.com/?a=%09%0D" # # p URI.unescape(enc_uri) # # => "http://example.com/?a=\t\r" # def unescape(str) str.gsub(ESCAPED) do $&[1,2].hex.chr end end alias decode unescape end include REGEXP extend Escape @@schemes = {} # # Base class for all URI exceptions. # class Error < StandardError; end # # Not a URI. # class InvalidURIError < Error; end # # Not a URI component. # class InvalidComponentError < Error; end # # URI is valid, bad usage is not. # class BadURIError < Error; end # # == Synopsis # # URI::split(uri) # # == Args # # +uri+:: # String with URI. # # == Description # # Splits the string on following parts and returns array with result: # # * Scheme # * Userinfo # * Host # * Port # * Registry # * Path # * Opaque # * Query # * Fragment # # == Usage # # require 'uri' # # p URI.split("http://www.ruby-lang.org/") # # => ["http", nil, "www.ruby-lang.org", nil, nil, "/", nil, nil, nil] # def self.split(uri) case uri when '' # null uri when ABS_URI scheme, opaque, userinfo, host, port, registry, path, query, fragment = $~[1..-1] # URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] # absoluteURI = scheme ":" ( hier_part | opaque_part ) # hier_part = ( net_path | abs_path ) [ "?" query ] # opaque_part = uric_no_slash *uric # abs_path = "/" path_segments # net_path = "//" authority [ abs_path ] # authority = server | reg_name # server = [ [ userinfo "@" ] hostport ] if !scheme raise InvalidURIError, "bad URI(absolute but no scheme): #{uri}" end if !opaque && (!path && (!host && !registry)) raise InvalidURIError, "bad URI(absolute but no path): #{uri}" end when REL_URI scheme = nil opaque = nil userinfo, host, port, registry, rel_segment, abs_path, query, fragment = $~[1..-1] if rel_segment && abs_path path = rel_segment + abs_path elsif rel_segment path = rel_segment elsif abs_path path = abs_path end # URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] # relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ] # net_path = "//" authority [ abs_path ] # abs_path = "/" path_segments # rel_path = rel_segment [ abs_path ] # authority = server | reg_name # server = [ [ userinfo "@" ] hostport ] else raise InvalidURIError, "bad URI(is not URI?): #{uri}" end path = '' if !path && !opaque # (see RFC2396 Section 5.2) ret = [ scheme, userinfo, host, port, # X registry, # X path, # Y opaque, # Y query, fragment ] return ret end # # == Synopsis # # URI::parse(uri_str) # # == Args # # +uri_str+:: # String with URI. # # == Description # # Creates one of the URI's subclasses instance from the string. # # == Raises # # URI::InvalidURIError # Raised if URI given is not a correct one. # # == Usage # # require 'uri' # # uri = URI.parse("http://www.ruby-lang.org/") # p uri # # => # # p uri.scheme # # => "http" # p uri.host # # => "www.ruby-lang.org" # def self.parse(uri) scheme, userinfo, host, port, registry, path, opaque, query, fragment = self.split(uri) if scheme && @@schemes.include?(scheme.upcase) @@schemes[scheme.upcase].new(scheme, userinfo, host, port, registry, path, opaque, query, fragment) else Generic.new(scheme, userinfo, host, port, registry, path, opaque, query, fragment) end end # # == Synopsis # # URI::join(str[, str, ...]) # # == Args # # +str+:: # String(s) to work with # # == Description # # Joins URIs. # # == Usage # # require 'uri' # # p URI.join("http://localhost/","main.rbx") # # => # # def self.join(*str) u = self.parse(str[0]) str[1 .. -1].each do |x| u = u.merge(x) end u end # # == Synopsis # # URI::extract(str[, schemes][,&blk]) # # == Args # # +str+:: # String to extract URIs from. # +schemes+:: # Limit URI matching to a specific schemes. # # == Description # # Extracts URIs from a string. If block given, iterates through all matched URIs. # Returns nil if block given or array with matches. # # == Usage # # require "uri" # # URI.extract("text here http://foo.example.org/bla and here mailto:test@example.com and here also.") # # => ["http://foo.example.com/bla", "mailto:test@example.com"] # def self.extract(str, schemes = nil, &block) if block_given? str.scan(regexp(schemes)) { yield $& } nil else result = [] str.scan(regexp(schemes)) { result.push $& } result end end # # == Synopsis # # URI::regexp([match_schemes]) # # == Args # # +match_schemes+:: # Array of schemes. If given, resulting regexp matches to URIs # whose scheme is one of the match_schemes. # # == Description # Returns a Regexp object which matches to URI-like strings. # The Regexp object returned by this method includes arbitrary # number of capture group (parentheses). Never rely on it's number. # # == Usage # # require 'uri' # # # extract first URI from html_string # html_string.slice(URI.regexp) # # # remove ftp URIs # html_string.sub(URI.regexp(['ftp']) # # # You should not rely on the number of parentheses # html_string.scan(URI.regexp) do |*matches| # p $& # end # def self.regexp(schemes = nil) unless schemes ABS_URI_REF else /(?=#{Regexp.union(*schemes)}:)#{PATTERN::X_ABS_URI}/xn end end end module Kernel # alias for URI.parse. # # This method is introduced at 1.8.2. def URI(uri_str) # :doc: URI.parse(uri_str) end module_function :URI end ================================================ FILE: lib/uri/ftp.rb ================================================ # # = uri/ftp.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # require 'uri/generic' module URI # # FTP URI syntax is defined by RFC1738 section 3.2. # class FTP < Generic DEFAULT_PORT = 21 COMPONENT = [ :scheme, :userinfo, :host, :port, :path, :typecode ].freeze # # Typecode is "a", "i" or "d". # # * "a" indicates a text file (the FTP command was ASCII) # * "i" indicates a binary file (FTP command IMAGE) # * "d" indicates the contents of a directory should be displayed # TYPECODE = ['a', 'i', 'd'].freeze TYPECODE_PREFIX = ';type='.freeze def self.new2(user, password, host, port, path, typecode = nil, arg_check = true) typecode = nil if typecode.size == 0 if typecode && !TYPECODE.include?(typecode) raise ArgumentError, "bad typecode is specified: #{typecode}" end # do escape self.new('ftp', [user, password], host, port, nil, typecode ? path + TYPECODE_PREFIX + typecode : path, nil, nil, nil, arg_check) end # # == Description # # Creates a new URI::FTP object from components, with syntax checking. # # The components accepted are +userinfo+, +host+, +port+, +path+ and # +typecode+. # # The components should be provided either as an Array, or as a Hash # with keys formed by preceding the component names with a colon. # # If an Array is used, the components must be passed in the order # [userinfo, host, port, path, typecode] # # If the path supplied is absolute, it will be escaped in order to # make it absolute in the URI. Examples: # # require 'uri' # # uri = URI::FTP.build(['user:password', 'ftp.example.com', nil, # '/path/file.> zip', 'i']) # puts uri.to_s -> ftp://user:password@ftp.example.com/%2Fpath/file.zip;type=a # # uri2 = URI::FTP.build({:host => 'ftp.example.com', # :path => 'ruby/src'}) # puts uri2.to_s -> ftp://ftp.example.com/ruby/src # def self.build(args) # Fix the incoming path to be generic URL syntax # FTP path -> URL path # foo/bar /foo/bar # /foo/bar /%2Ffoo/bar # if args.kind_of?(Array) args[3] = '/' + args[3].sub(/^\//, '%2F') else args[:path] = '/' + args[:path].sub(/^\//, '%2F') end tmp = Util::make_components_hash(self, args) if tmp[:typecode] if tmp[:typecode].size == 1 tmp[:typecode] = TYPECODE_PREFIX + tmp[:typecode] end tmp[:path] << tmp[:typecode] end return super(tmp) end # # == Description # # Creates a new URI::FTP object from generic URL components with no # syntax checking. # # Unlike build(), this method does not escape the path component as # required by RFC1738; instead it is treated as per RFC2396. # # Arguments are +scheme+, +userinfo+, +host+, +port+, +registry+, +path+, # +opaque+, +query+ and +fragment+, in that order. # def initialize(*arg) super(*arg) @typecode = nil tmp = @path.index(TYPECODE_PREFIX) if tmp typecode = @path[tmp + TYPECODE_PREFIX.size..-1] self.set_path(@path[0..tmp - 1]) if arg[-1] self.typecode = typecode else self.set_typecode(typecode) end end end attr_reader :typecode def check_typecode(v) if TYPECODE.include?(v) return true else raise InvalidComponentError, "bad typecode(expected #{TYPECODE.join(', ')}): #{v}" end end private :check_typecode def set_typecode(v) @typecode = v end protected :set_typecode def typecode=(typecode) check_typecode(typecode) set_typecode(typecode) typecode end def merge(oth) # :nodoc: tmp = super(oth) if self != tmp tmp.set_typecode(oth.typecode) end return tmp end # Returns the path from an FTP URI. # # RFC 1738 specifically states that the path for an FTP URI does not # include the / which separates the URI path from the URI host. Example: # # ftp://ftp.example.com/pub/ruby # # The above URI indicates that the client should connect to # ftp.example.com then cd pub/ruby from the initial login directory. # # If you want to cd to an absolute directory, you must include an # escaped / (%2F) in the path. Example: # # ftp://ftp.example.com/%2Fpub/ruby # # This method will then return "/pub/ruby" # def path return @path.sub(/^\//,'').sub(/^%2F/i,'/') end def to_s save_path = nil if @typecode save_path = @path @path = @path + TYPECODE_PREFIX + @typecode end str = super if @typecode @path = save_path end return str end end @@schemes['FTP'] = FTP end ================================================ FILE: lib/uri/generic.rb ================================================ # # = uri/generic.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # require 'uri/common' module URI # # Base class for all URI classes. # Implements generic URI syntax as per RFC 2396. # class Generic include URI include REGEXP DEFAULT_PORT = nil # # Returns default port # def self.default_port self::DEFAULT_PORT end def default_port self.class.default_port end COMPONENT = [ :scheme, :userinfo, :host, :port, :registry, :path, :opaque, :query, :fragment ].freeze # # Components of the URI in the order. # def self.component self::COMPONENT end USE_REGISTRY = false # # DOC: FIXME! # def self.use_registry self::USE_REGISTRY end # # == Synopsis # # See #new # # == Description # # At first, tries to create a new URI::Generic instance using # URI::Generic::build. But, if exception URI::InvalidComponentError is raised, # then it URI::Escape.escape all URI components and tries again. # # def self.build2(args) begin return self.build(args) rescue InvalidComponentError if args.kind_of?(Array) return self.build(args.collect{|x| if x URI.escape(x) else x end }) elsif args.kind_of?(Hash) tmp = {} args.each do |key, value| tmp[key] = if value URI.escape(value) else value end end return self.build(tmp) end end end # # == Synopsis # # See #new # # == Description # # Creates a new URI::Generic instance from components of URI::Generic # with check. Components are: scheme, userinfo, host, port, registry, path, # opaque, query and fragment. You can provide arguments either by an Array or a Hash. # See #new for hash keys to use or for order of array items. # def self.build(args) if args.kind_of?(Array) && args.size == ::URI::Generic::COMPONENT.size tmp = args elsif args.kind_of?(Hash) tmp = ::URI::Generic::COMPONENT.collect do |c| if args.include?(c) args[c] else nil end end else raise ArgumentError, "expected Array of or Hash of components of #{self.class} (#{self.class.component.join(', ')})" end tmp << true return self.new(*tmp) end # # == Args # # +scheme+:: # Protocol scheme, i.e. 'http','ftp','mailto' and so on. # +userinfo+:: # User name and password, i.e. 'sdmitry:bla' # +host+:: # Server host name # +port+:: # Server port # +registry+:: # DOC: FIXME! # +path+:: # Path on server # +opaque+:: # DOC: FIXME! # +query+:: # Query data # +fragment+:: # A part of URI after '#' sign # +arg_check+:: # Check arguments [false by default] # # == Description # # Creates a new URI::Generic instance from ``generic'' components without check. # def initialize(scheme, userinfo, host, port, registry, path, opaque, query, fragment, arg_check = false) @scheme = nil @user = nil @password = nil @host = nil @port = nil @path = nil @query = nil @opaque = nil @registry = nil @fragment = nil if arg_check self.scheme = scheme self.userinfo = userinfo self.host = host self.port = port self.path = path self.query = query self.opaque = opaque self.registry = registry self.fragment = fragment else self.set_scheme(scheme) self.set_userinfo(userinfo) self.set_host(host) self.set_port(port) self.set_path(path) self.set_query(query) self.set_opaque(opaque) self.set_registry(registry) self.set_fragment(fragment) end if @registry && !self.class.use_registry raise InvalidURIError, "the scheme #{@scheme} does not accept registry part: #{@registry} (or bad hostname?)" end @scheme.freeze if @scheme self.set_path('') if !@path && !@opaque # (see RFC2396 Section 5.2) self.set_port(self.default_port) if self.default_port && !@port end attr_reader :scheme attr_reader :host attr_reader :port attr_reader :registry attr_reader :path attr_reader :query attr_reader :opaque attr_reader :fragment # replace self by other URI object def replace!(oth) if self.class != oth.class raise ArgumentError, "expected #{self.class} object" end component.each do |c| self.__send__("#{c}=", oth.__send__(c)) end end private :replace! def component self.class.component end def check_scheme(v) if v && SCHEME !~ v raise InvalidComponentError, "bad component(expected scheme component): #{v}" end return true end private :check_scheme def set_scheme(v) @scheme = v end protected :set_scheme def scheme=(v) check_scheme(v) set_scheme(v) v end def check_userinfo(user, password = nil) if !password user, password = split_userinfo(user) end check_user(user) check_password(password, user) return true end private :check_userinfo def check_user(v) if @registry || @opaque raise InvalidURIError, "can not set user with registry or opaque" end return v unless v if USERINFO !~ v raise InvalidComponentError, "bad component(expected userinfo component or user component): #{v}" end return true end private :check_user def check_password(v, user = @user) if @registry || @opaque raise InvalidURIError, "can not set password with registry or opaque" end return v unless v if !user raise InvalidURIError, "password component depends user component" end if USERINFO !~ v raise InvalidComponentError, "bad component(expected user component): #{v}" end return true end private :check_password # # Sets userinfo, argument is string like 'name:pass' # def userinfo=(userinfo) if userinfo.nil? return nil end check_userinfo(*userinfo) set_userinfo(*userinfo) # returns userinfo end def user=(user) check_user(user) set_user(user) # returns user end def password=(password) check_password(password) set_password(password) # returns password end def set_userinfo(user, password = nil) unless password user, password = split_userinfo(user) end @user = user @password = password if password [@user, @password] end protected :set_userinfo def set_user(v) set_userinfo(v, @password) v end protected :set_user def set_password(v) @password = v # returns v end protected :set_password def split_userinfo(ui) return nil, nil unless ui user, password = ui.split(/:/, 2) return user, password end private :split_userinfo def escape_userpass(v) v = URI.escape(v, /[@:\/]/o) # RFC 1738 section 3.1 #/ end private :escape_userpass def userinfo if @user.nil? nil elsif @password.nil? @user else @user + ':' + @password end end def user @user end def password @password end def check_host(v) return v unless v if @registry || @opaque raise InvalidURIError, "can not set host with registry or opaque" elsif HOST !~ v raise InvalidComponentError, "bad component(expected host component): #{v}" end return true end private :check_host def set_host(v) @host = v end protected :set_host def host=(v) check_host(v) set_host(v) v end def check_port(v) return v unless v if @registry || @opaque raise InvalidURIError, "can not set port with registry or opaque" elsif !v.kind_of?(Fixnum) && PORT !~ v raise InvalidComponentError, "bad component(expected port component): #{v}" end return true end private :check_port def set_port(v) unless !v || v.kind_of?(Fixnum) if v.empty? v = nil else v = v.to_i end end @port = v end protected :set_port def port=(v) check_port(v) set_port(v) port end def check_registry(v) return v unless v # raise if both server and registry are not nil, because: # authority = server | reg_name # server = [ [ userinfo "@" ] hostport ] if @host || @port || @user # userinfo = @user + ':' + @password raise InvalidURIError, "can not set registry with host, port, or userinfo" elsif v && REGISTRY !~ v raise InvalidComponentError, "bad component(expected registry component): #{v}" end return true end private :check_registry def set_registry(v) @registry = v end protected :set_registry def registry=(v) check_registry(v) set_registry(v) v end def check_path(v) # raise if both hier and opaque are not nil, because: # absoluteURI = scheme ":" ( hier_part | opaque_part ) # hier_part = ( net_path | abs_path ) [ "?" query ] if v && @opaque raise InvalidURIError, "path conflicts with opaque" end if @scheme if v && v != '' && ABS_PATH !~ v raise InvalidComponentError, "bad component(expected absolute path component): #{v}" end else if v && v != '' && ABS_PATH !~ v && REL_PATH !~ v raise InvalidComponentError, "bad component(expected relative path component): #{v}" end end return true end private :check_path def set_path(v) @path = v end protected :set_path def path=(v) check_path(v) set_path(v) v end def check_query(v) return v unless v # raise if both hier and opaque are not nil, because: # absoluteURI = scheme ":" ( hier_part | opaque_part ) # hier_part = ( net_path | abs_path ) [ "?" query ] if @opaque raise InvalidURIError, "query conflicts with opaque" end if v && v != '' && QUERY !~ v raise InvalidComponentError, "bad component(expected query component): #{v}" end return true end private :check_query def set_query(v) @query = v end protected :set_query def query=(v) check_query(v) set_query(v) v end def check_opaque(v) return v unless v # raise if both hier and opaque are not nil, because: # absoluteURI = scheme ":" ( hier_part | opaque_part ) # hier_part = ( net_path | abs_path ) [ "?" query ] if @host || @port || @user || @path # userinfo = @user + ':' + @password raise InvalidURIError, "can not set opaque with host, port, userinfo or path" elsif v && OPAQUE !~ v raise InvalidComponentError, "bad component(expected opaque component): #{v}" end return true end private :check_opaque def set_opaque(v) @opaque = v end protected :set_opaque def opaque=(v) check_opaque(v) set_opaque(v) v end def check_fragment(v) return v unless v if v && v != '' && FRAGMENT !~ v raise InvalidComponentError, "bad component(expected fragment component): #{v}" end return true end private :check_fragment def set_fragment(v) @fragment = v end protected :set_fragment def fragment=(v) check_fragment(v) set_fragment(v) v end # # Checks if URI has a path # def hierarchical? if @path true else false end end # # Checks if URI is an absolute one # def absolute? if @scheme true else false end end alias absolute absolute? # # Checks if URI is relative # def relative? !absolute? end def split_path(path) path.split(%r{/+}, -1) end private :split_path def merge_path(base, rel) # RFC2396, Section 5.2, 5) # RFC2396, Section 5.2, 6) base_path = split_path(base) rel_path = split_path(rel) # RFC2396, Section 5.2, 6), a) base_path << '' if base_path.last == '..' while i = base_path.index('..') base_path.slice!(i - 1, 2) end if (first = rel_path.first) and first.empty? base_path.clear rel_path.shift end # RFC2396, Section 5.2, 6), c) # RFC2396, Section 5.2, 6), d) rel_path.push('') if rel_path.last == '.' || rel_path.last == '..' rel_path.delete('.') # RFC2396, Section 5.2, 6), e) tmp = [] rel_path.each do |x| if x == '..' && !(tmp.empty? || tmp.last == '..') tmp.pop else tmp << x end end add_trailer_slash = !tmp.empty? if base_path.empty? base_path = [''] # keep '/' for root directory elsif add_trailer_slash base_path.pop end while x = tmp.shift if x == '..' # RFC2396, Section 4 # a .. or . in an absolute path has no special meaning base_path.pop if base_path.size > 1 else # if x == '..' # valid absolute (but abnormal) path "/../..." # else # valid absolute path # end base_path << x tmp.each {|t| base_path << t} add_trailer_slash = false break end end base_path.push('') if add_trailer_slash return base_path.join('/') end private :merge_path # # == Args # # +oth+:: # URI or String # # == Description # # Destructive form of #merge # # == Usage # # require 'uri' # # uri = URI.parse("http://my.example.com") # uri.merge!("/main.rbx?page=1") # p uri # # => # # def merge!(oth) t = merge(oth) if self == t nil else replace!(t) self end end # # == Args # # +oth+:: # URI or String # # == Description # # Merges two URI's. # # == Usage # # require 'uri' # # uri = URI.parse("http://my.example.com") # p uri.merge("/main.rbx?page=1") # # => # # def merge(oth) begin base, rel = merge0(oth) rescue raise $!.class, $!.message end if base == rel return base end authority = rel.userinfo || rel.host || rel.port # RFC2396, Section 5.2, 2) if (rel.path.nil? || rel.path.empty?) && !authority && !rel.query base.set_fragment(rel.fragment) if rel.fragment return base end base.set_query(nil) base.set_fragment(nil) # RFC2396, Section 5.2, 4) if !authority base.set_path(merge_path(base.path, rel.path)) if base.path && rel.path else # RFC2396, Section 5.2, 4) base.set_path(rel.path) if rel.path end # RFC2396, Section 5.2, 7) base.set_userinfo(rel.userinfo) if rel.userinfo base.set_host(rel.host) if rel.host base.set_port(rel.port) if rel.port base.set_query(rel.query) if rel.query base.set_fragment(rel.fragment) if rel.fragment return base end # merge alias + merge # return base and rel. # you can modify `base', but can not `rel'. def merge0(oth) case oth when Generic when String oth = URI.parse(oth) else raise ArgumentError, "bad argument(expected URI object or URI string)" end if self.relative? && oth.relative? raise BadURIError, "both URI are relative" end if self.absolute? && oth.absolute? #raise BadURIError, # "both URI are absolute" # hmm... should return oth for usability? return oth, oth end if self.absolute? return self.dup, oth else return oth, oth end end private :merge0 def route_from_path(src, dst) # RFC2396, Section 4.2 return '' if src == dst src_path = split_path(src) dst_path = split_path(dst) # hmm... dst has abnormal absolute path, # like "/./", "/../", "/x/../", ... if dst_path.include?('..') || dst_path.include?('.') return dst.dup end src_path.pop # discard same parts while dst_path.first == src_path.first break if dst_path.empty? src_path.shift dst_path.shift end tmp = dst_path.join('/') # calculate if src_path.empty? if tmp.empty? return './' elsif dst_path.first.include?(':') # (see RFC2396 Section 5) return './' + tmp else return tmp end end return '../' * src_path.size + tmp end private :route_from_path def route_from0(oth) case oth when Generic when String oth = URI.parse(oth) else raise ArgumentError, "bad argument(expected URI object or URI string)" end if self.relative? raise BadURIError, "relative URI: #{self}" end if oth.relative? raise BadURIError, "relative URI: #{oth}" end if self.scheme != oth.scheme return self, self.dup end rel = URI::Generic.new(nil, # it is relative URI self.userinfo, self.host, self.port, self.registry, self.path, self.opaque, self.query, self.fragment) if rel.userinfo != oth.userinfo || rel.host.to_s.downcase != oth.host.to_s.downcase || rel.port != oth.port if self.userinfo.nil? && self.host.nil? return self, self.dup end rel.set_port(nil) if rel.port == oth.default_port return rel, rel end rel.set_userinfo(nil) rel.set_host(nil) rel.set_port(nil) if rel.path && rel.path == oth.path rel.set_path('') rel.set_query(nil) if rel.query == oth.query return rel, rel elsif rel.opaque && rel.opaque == oth.opaque rel.set_opaque('') rel.set_query(nil) if rel.query == oth.query return rel, rel end # you can modify `rel', but can not `oth'. return oth, rel end private :route_from0 # # == Args # # +oth+:: # URI or String # # == Description # # Calculates relative path from oth to self # # == Usage # # require 'uri' # # uri = URI.parse('http://my.example.com/main.rbx?page=1') # p uri.route_from('http://my.example.com') # #=> # # def route_from(oth) # you can modify `rel', but can not `oth'. begin oth, rel = route_from0(oth) rescue raise $!.class, $!.message end if oth == rel return rel end rel.set_path(route_from_path(oth.path, self.path)) if rel.path == './' && self.query # "./?foo" -> "?foo" rel.set_path('') end return rel end alias - route_from # # == Args # # +oth+:: # URI or String # # == Description # # Calculates relative path to oth from self # # == Usage # # require 'uri' # # uri = URI.parse('http://my.example.com') # p uri.route_to('http://my.example.com/main.rbx?page=1') # #=> # # def route_to(oth) case oth when Generic when String oth = URI.parse(oth) else raise ArgumentError, "bad argument(expected URI object or URI string)" end oth.route_from(self) end # # Returns normalized URI # def normalize uri = dup uri.normalize! uri end # # Destructive version of #normalize # def normalize! if path && path == '' set_path('/') end if host && host != host.downcase set_host(self.host.downcase) end end def path_query str = @path if @query str += '?' + @query end str end private :path_query # # Constructs String from URI # def to_s str = '' if @scheme str << @scheme str << ':' end if @opaque str << @opaque else if @registry str << @registry else if @host str << '//' end if self.userinfo str << self.userinfo str << '@' end if @host str << @host end if @port && @port != self.default_port str << ':' str << @port.to_s end end str << path_query end if @fragment str << '#' str << @fragment end str end # # Compares to URI's # def ==(oth) if self.class == oth.class self.normalize.component_ary == oth.normalize.component_ary else false end end def hash self.component_ary.hash end def eql?(oth) self.component_ary.eql?(oth.component_ary) end =begin --- URI::Generic#===(oth) =end # def ===(oth) # raise NotImplementedError # end =begin =end def component_ary component.collect do |x| self.send(x) end end protected :component_ary # == Args # # +components+:: # Multiple Symbol arguments defined in URI::HTTP # # == Description # # Selects specified components from URI # # == Usage # # require 'uri' # # uri = URI.parse('http://myuser:mypass@my.example.com/test.rbx') # p uri.select(:userinfo, :host, :path) # # => ["myuser:mypass", "my.example.com", "/test.rbx"] # def select(*components) components.collect do |c| if component.include?(c) self.send(c) else raise ArgumentError, "expected of components of #{self.class} (#{self.class.component.join(', ')})" end end end @@to_s = Kernel.instance_method(:to_s) def inspect @@to_s.bind(self).call.sub!(/>\z/) {" URL:#{self}>"} end def coerce(oth) case oth when String oth = URI.parse(oth) else super end return oth, self end end end ================================================ FILE: lib/uri/http.rb ================================================ # # = uri/http.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # require 'uri/generic' module URI # # The syntax of HTTP URIs is defined in RFC1738 section 3.3. # # Note that the Ruby URI library allows HTTP URLs containing usernames and # passwords. This is not legal as per the RFC, but used to be # supported in Internet Explorer 5 and 6, before the MS04-004 security # update. See . # class HTTP < Generic DEFAULT_PORT = 80 COMPONENT = [ :scheme, :userinfo, :host, :port, :path, :query, :fragment ].freeze # # == Description # # Create a new URI::HTTP object from components, with syntax checking. # # The components accepted are userinfo, host, port, path, query and # fragment. # # The components should be provided either as an Array, or as a Hash # with keys formed by preceding the component names with a colon. # # If an Array is used, the components must be passed in the order # [userinfo, host, port, path, query, fragment]. # # Example: # # newuri = URI::HTTP.build({:host => 'www.example.com', # :path> => '/foo/bar'}) # # newuri = URI::HTTP.build([nil, "www.example.com", nil, "/path", # "query", 'fragment']) # # Currently, if passed userinfo components this method generates # invalid HTTP URIs as per RFC 1738. # def self.build(args) tmp = Util::make_components_hash(self, args) return super(tmp) end # # == Description # # Create a new URI::HTTP object from generic URI components as per # RFC 2396. No HTTP-specific syntax checking (as per RFC 1738) is # performed. # # Arguments are +scheme+, +userinfo+, +host+, +port+, +registry+, +path+, # +opaque+, +query+ and +fragment+, in that order. # # Example: # # uri = URI::HTTP.new(['http', nil, "www.example.com", nil, "/path", # "query", 'fragment']) # def initialize(*arg) super(*arg) end # # == Description # # Returns the full path for an HTTP request, as required by Net::HTTP::Get. # # If the URI contains a query, the full path is URI#path + '?' + URI#query. # Otherwise, the path is simply URI#path. # def request_uri r = path_query if r[0] != ?/ r = '/' + r end r end end @@schemes['HTTP'] = HTTP end ================================================ FILE: lib/uri/https.rb ================================================ # # = uri/https.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # require 'uri/http' module URI # The default port for HTTPS URIs is 443, and the scheme is 'https:' rather # than 'http:'. Other than that, HTTPS URIs are identical to HTTP URIs; # see URI::HTTP. class HTTPS < HTTP DEFAULT_PORT = 443 end @@schemes['HTTPS'] = HTTPS end ================================================ FILE: lib/uri/ldap.rb ================================================ # # = uri/ldap.rb # # Author:: # Takaaki Tateishi # Akira Yamada # License:: # URI::LDAP is copyrighted free software by Takaaki Tateishi and Akira Yamada. # You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # require 'uri/generic' module URI # # LDAP URI SCHEMA (described in RFC2255) # ldap:///[?[?[?[?]]]] # class LDAP < Generic DEFAULT_PORT = 389 COMPONENT = [ :scheme, :host, :port, :dn, :attributes, :scope, :filter, :extensions, ].freeze SCOPE = [ SCOPE_ONE = 'one', SCOPE_SUB = 'sub', SCOPE_BASE = 'base', ].freeze def self.build(args) tmp = Util::make_components_hash(self, args) if tmp[:dn] tmp[:path] = tmp[:dn] end query = [] [:extensions, :filter, :scope, :attributes].collect do |x| next if !tmp[x] && query.size == 0 query.unshift(tmp[x]) end tmp[:query] = query.join('?') return super(tmp) end def initialize(*arg) super(*arg) if @fragment raise InvalidURIError, 'bad LDAP URL' end parse_dn parse_query end def parse_dn @dn = @path[1..-1] end private :parse_dn def parse_query @attributes = nil @scope = nil @filter = nil @extensions = nil if @query attrs, scope, filter, extensions = @query.split('?') @attributes = attrs if attrs && attrs.size > 0 @scope = scope if scope && scope.size > 0 @filter = filter if filter && filter.size > 0 @extensions = extensions if extensions && extensions.size > 0 end end private :parse_query def build_path_query @path = '/' + @dn query = [] [@extensions, @filter, @scope, @attributes].each do |x| next if !x && query.size == 0 query.unshift(x) end @query = query.join('?') end private :build_path_query def dn @dn end def set_dn(val) @dn = val build_path_query @dn end protected :set_dn def dn=(val) set_dn(val) val end def attributes @attributes end def set_attributes(val) @attributes = val build_path_query @attributes end protected :set_attributes def attributes=(val) set_attributes(val) val end def scope @scope end def set_scope(val) @scope = val build_path_query @scope end protected :set_scope def scope=(val) set_scope(val) val end def filter @filter end def set_filter(val) @filter = val build_path_query @filter end protected :set_filter def filter=(val) set_filter(val) val end def extensions @extensions end def set_extensions(val) @extensions = val build_path_query @extensions end protected :set_extensions def extensions=(val) set_extensions(val) val end def hierarchical? false end end @@schemes['LDAP'] = LDAP end ================================================ FILE: lib/uri/ldaps.rb ================================================ require 'uri/ldap' module URI # The default port for LDAPS URIs is 636, and the scheme is 'ldaps:' rather # than 'ldap:'. Other than that, LDAPS URIs are identical to LDAP URIs; # see URI::LDAP. class LDAPS < LDAP DEFAULT_PORT = 636 end @@schemes['LDAPS'] = LDAPS end ================================================ FILE: lib/uri/mailto.rb ================================================ # # = uri/mailto.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # require 'uri/generic' module URI # # RFC2368, The mailto URL scheme # class MailTo < Generic include REGEXP DEFAULT_PORT = nil COMPONENT = [ :scheme, :to, :headers ].freeze # :stopdoc: # "hname" and "hvalue" are encodings of an RFC 822 header name and # value, respectively. As with "to", all URL reserved characters must # be encoded. # # "#mailbox" is as specified in RFC 822 [RFC822]. This means that it # consists of zero or more comma-separated mail addresses, possibly # including "phrase" and "comment" components. Note that all URL # reserved characters in "to" must be encoded: in particular, # parentheses, commas, and the percent sign ("%"), which commonly occur # in the "mailbox" syntax. # # Within mailto URLs, the characters "?", "=", "&" are reserved. # hname = *urlc # hvalue = *urlc # header = hname "=" hvalue HEADER_PATTERN = "(?:[^?=&]*=[^?=&]*)".freeze HEADER_REGEXP = Regexp.new(HEADER_PATTERN, 'N').freeze # headers = "?" header *( "&" header ) # to = #mailbox # mailtoURL = "mailto:" [ to ] [ headers ] MAILBOX_PATTERN = "(?:#{PATTERN::ESCAPED}|[^(),%?=&])".freeze MAILTO_REGEXP = Regexp.new(" # :nodoc: \\A (#{MAILBOX_PATTERN}*?) (?# 1: to) (?: \\? (#{HEADER_PATTERN}(?:\\&#{HEADER_PATTERN})*) (?# 2: headers) )? (?: \\# (#{PATTERN::FRAGMENT}) (?# 3: fragment) )? \\z ", Regexp::EXTENDED, 'N').freeze # :startdoc: # # == Description # # Creates a new URI::MailTo object from components, with syntax checking. # # Components can be provided as an Array or Hash. If an Array is used, # the components must be supplied as [to, headers]. # # If a Hash is used, the keys are the component names preceded by colons. # # The headers can be supplied as a pre-encoded string, such as # "subject=subscribe&cc=address", or as an Array of Arrays like # [['subject', 'subscribe'], ['cc', 'address']] # # Examples: # # require 'uri' # # m1 = URI::MailTo.build(['joe@example.com', 'subject=Ruby']) # puts m1.to_s -> mailto:joe@example.com?subject=Ruby # # m2 = URI::MailTo.build(['john@example.com', [['Subject', 'Ruby'], ['Cc', 'jack@example.com']]]) # puts m2.to_s -> mailto:john@example.com?Subject=Ruby&Cc=jack@example.com # # m3 = URI::MailTo.build({:to => 'listman@example.com', :headers => [['subject', 'subscribe']]}) # puts m3.to_s -> mailto:listman@example.com?subject=subscribe # def self.build(args) tmp = Util::make_components_hash(self, args) if tmp[:to] tmp[:opaque] = tmp[:to] else tmp[:opaque] = '' end if tmp[:headers] tmp[:opaque] << '?' if tmp[:headers].kind_of?(Array) tmp[:opaque] << tmp[:headers].collect { |x| if x.kind_of?(Array) x[0] + '=' + x[1..-1].to_s else x.to_s end }.join('&') elsif tmp[:headers].kind_of?(Hash) tmp[:opaque] << tmp[:headers].collect { |h,v| h + '=' + v }.join('&') else tmp[:opaque] << tmp[:headers].to_s end end return super(tmp) end # # == Description # # Creates a new URI::MailTo object from generic URL components with # no syntax checking. # # This method is usually called from URI::parse, which checks # the validity of each component. # def initialize(*arg) super(*arg) @to = nil @headers = [] if MAILTO_REGEXP =~ @opaque if arg[-1] self.to = $1 self.headers = $2 else set_to($1) set_headers($2) end else raise InvalidComponentError, "unrecognised opaque part for mailtoURL: #{@opaque}" end end # The primary e-mail address of the URL, as a String attr_reader :to # E-mail headers set by the URL, as an Array of Arrays attr_reader :headers def check_to(v) return true unless v return true if v.size == 0 if OPAQUE !~ v || /\A#{MAILBOX_PATTERN}*\z/o !~ v raise InvalidComponentError, "bad component(expected opaque component): #{v}" end return true end private :check_to def set_to(v) @to = v end protected :set_to def to=(v) check_to(v) set_to(v) v end def check_headers(v) return true unless v return true if v.size == 0 if OPAQUE !~ v || /\A(#{HEADER_PATTERN}(?:\&#{HEADER_PATTERN})*)\z/o !~ v raise InvalidComponentError, "bad component(expected opaque component): #{v}" end return true end private :check_headers def set_headers(v) @headers = [] if v v.scan(HEADER_REGEXP) do |x| @headers << x.split(/=/o, 2) end end end protected :set_headers def headers=(v) check_headers(v) set_headers(v) v end def to_s @scheme + ':' + if @to @to else '' end + if @headers.size > 0 '?' + @headers.collect{|x| x.join('=')}.join('&') else '' end + if @fragment '#' + @fragment else '' end end # Returns the RFC822 e-mail text equivalent of the URL, as a String. # # Example: # # require 'uri' # # uri = URI.parse("mailto:ruby-list@ruby-lang.org?Subject=subscribe&cc=myaddr") # uri.to_mailtext # # => "To: ruby-list@ruby-lang.org\nSubject: subscribe\nCc: myaddr\n\n\n" # def to_mailtext to = URI::unescape(@to) head = '' body = '' @headers.each do |x| case x[0] when 'body' body = URI::unescape(x[1]) when 'to' to << ', ' + URI::unescape(x[1]) else head << URI::unescape(x[0]).capitalize + ': ' + URI::unescape(x[1]) + "\n" end end return "To: #{to} #{head} #{body} " end alias to_rfc822text to_mailtext end @@schemes['MAILTO'] = MailTo end ================================================ FILE: lib/uri.rb ================================================ # # URI support for Ruby # # Author:: Akira Yamada # Documentation:: Akira Yamada , Dmitry V. Sabanin # License:: # Copyright (c) 2001 akira yamada # You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id$ # # See URI for documentation # module URI # :stopdoc: VERSION_CODE = '000911'.freeze VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze # :startdoc: end require 'uri/common' require 'uri/generic' require 'uri/ftp' require 'uri/http' require 'uri/https' require 'uri/ldap' require 'uri/ldaps' require 'uri/mailto' ================================================ FILE: lib/weakref.rb ================================================ require "delegate" # WeakRef is a class to represent a reference to an object that is not seen by # the tracing phase of the garbage collector. This allows the referenced # object to be garbage collected as if nothing is referring to it. Because # WeakRef delegates method calls to the referenced object, it may be used in # place of that object, i.e. it is of the same duck type. # # Usage: # # foo = Object.new # foo = Object.new # p foo.to_s # original's class # foo = WeakRef.new(foo) # p foo.to_s # should be same class # ObjectSpace.garbage_collect # p foo.to_s # should raise exception (recycled) class WeakRef [ref,...] @@id_rev_map = {} # ref -> obj @@final = lambda{|id| __old_status = Thread.critical Thread.critical = true begin rids = @@id_map[id] if rids for rid in rids @@id_rev_map.delete(rid) end @@id_map.delete(id) end rid = @@id_rev_map[id] if rid @@id_rev_map.delete(id) @@id_map[rid].delete(id) @@id_map.delete(rid) if @@id_map[rid].empty? end ensure Thread.critical = __old_status end } # Create a new WeakRef from +orig+. def initialize(orig) super __setobj__(orig) end # Return the object this WeakRef references. Raises RefError if the object # has been garbage collected. The object returned is the object to which # method calls are delegated (see Delegator). def __getobj__ unless @@id_rev_map[self.__id__] == @__id raise RefError, "Illegal Reference - probably recycled", caller(2) end begin ObjectSpace._id2ref(@__id) rescue RangeError raise RefError, "Illegal Reference - probably recycled", caller(2) end end def __setobj__(obj) @__id = obj.__id__ __old_status = Thread.critical begin Thread.critical = true unless @@id_rev_map.key?(self) ObjectSpace.define_finalizer obj, @@final ObjectSpace.define_finalizer self, @@final end @@id_map[@__id] = [] unless @@id_map[@__id] ensure Thread.critical = __old_status end @@id_map[@__id].push self.__id__ @@id_rev_map[self.__id__] = @__id end # Returns true if the referenced object still exists, and false if it has # been garbage collected. def weakref_alive? @@id_rev_map[self.__id__] == @__id end end if __FILE__ == $0 require 'thread' foo = Object.new p foo.to_s # original's class foo = WeakRef.new(foo) p foo.to_s # should be same class ObjectSpace.garbage_collect p foo.to_s # should raise exception (recycled) end ================================================ FILE: lib/webrick/accesslog.rb ================================================ # # accesslog.rb -- Access log handling utilities # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2002 keita yamaguchi # Copyright (c) 2002 Internet Programming with Ruby writers # # $IPR: accesslog.rb,v 1.1 2002/10/01 17:16:32 gotoyuzo Exp $ module WEBrick module AccessLog class AccessLogError < StandardError; end CLF_TIME_FORMAT = "[%d/%b/%Y:%H:%M:%S %Z]" COMMON_LOG_FORMAT = "%h %l %u %t \"%r\" %s %b" CLF = COMMON_LOG_FORMAT REFERER_LOG_FORMAT = "%{Referer}i -> %U" AGENT_LOG_FORMAT = "%{User-Agent}i" COMBINED_LOG_FORMAT = "#{CLF} \"%{Referer}i\" \"%{User-agent}i\"" module_function # This format specification is a subset of mod_log_config of Apache. # http://httpd.apache.org/docs/mod/mod_log_config.html#formats def setup_params(config, req, res) params = Hash.new("") params["a"] = req.peeraddr[3] params["b"] = res.sent_size params["e"] = ENV params["f"] = res.filename || "" params["h"] = req.peeraddr[2] params["i"] = req params["l"] = "-" params["m"] = req.request_method params["n"] = req.attributes params["o"] = res params["p"] = req.port params["q"] = req.query_string params["r"] = req.request_line.sub(/\x0d?\x0a\z/o, '') params["s"] = res.status # won't support "%>s" params["t"] = req.request_time params["T"] = Time.now - req.request_time params["u"] = req.user || "-" params["U"] = req.unparsed_uri params["v"] = config[:ServerName] params end def format(format_string, params) format_string.gsub(/\%(?:\{(.*?)\})?>?([a-zA-Z%])/){ param, spec = $1, $2 case spec[0] when ?e, ?i, ?n, ?o raise AccessLogError, "parameter is required for \"#{spec}\"" unless param param = params[spec][param] ? escape(param) : "-" when ?t params[spec].strftime(param || CLF_TIME_FORMAT) when ?% "%" else escape(params[spec].to_s) end } end def escape(data) if data.tainted? data.gsub(/[[:cntrl:]\\]+/) {$&.dump[1...-1]}.untaint else data end end end end ================================================ FILE: lib/webrick/cgi.rb ================================================ # # cgi.rb -- Yet another CGI library # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2003 Internet Programming with Ruby writers. All rights # reserved. # # $Id$ require "webrick/httprequest" require "webrick/httpresponse" require "webrick/config" require "stringio" module WEBrick class CGI CGIError = Class.new(StandardError) attr_reader :config, :logger def initialize(*args) if defined?(MOD_RUBY) unless ENV.has_key?("GATEWAY_INTERFACE") Apache.request.setup_cgi_env end end if %r{HTTP/(\d+\.\d+)} =~ ENV["SERVER_PROTOCOL"] httpv = $1 end @config = WEBrick::Config::HTTP.dup.update( :ServerSoftware => ENV["SERVER_SOFTWARE"] || "null", :HTTPVersion => HTTPVersion.new(httpv || "1.0"), :RunOnCGI => true, # to detect if it runs on CGI. :NPH => false # set true to run as NPH script. ) if config = args.shift @config.update(config) end @config[:Logger] ||= WEBrick::BasicLog.new($stderr) @logger = @config[:Logger] @options = args end def [](key) @config[key] end def start(env=ENV, stdin=$stdin, stdout=$stdout) sock = WEBrick::CGI::Socket.new(@config, env, stdin, stdout) req = HTTPRequest.new(@config) res = HTTPResponse.new(@config) unless @config[:NPH] or defined?(MOD_RUBY) def res.setup_header unless @header["status"] phrase = HTTPStatus::reason_phrase(@status) @header["status"] = "#{@status} #{phrase}" end super end def res.status_line "" end end begin req.parse(sock) req.script_name = (env["SCRIPT_NAME"] || File.expand_path($0)).dup req.path_info = (env["PATH_INFO"] || "").dup req.query_string = env["QUERY_STRING"] req.user = env["REMOTE_USER"] res.request_method = req.request_method res.request_uri = req.request_uri res.request_http_version = req.http_version res.keep_alive = req.keep_alive? self.service(req, res) rescue HTTPStatus::Error => ex res.set_error(ex) rescue HTTPStatus::Status => ex res.status = ex.code rescue Exception => ex @logger.error(ex) res.set_error(ex, true) ensure req.fixup if defined?(MOD_RUBY) res.setup_header Apache.request.status_line = "#{res.status} #{res.reason_phrase}" Apache.request.status = res.status table = Apache.request.headers_out res.header.each{|key, val| case key when /^content-encoding$/i Apache::request.content_encoding = val when /^content-type$/i Apache::request.content_type = val else table[key] = val.to_s end } res.cookies.each{|cookie| table.add("Set-Cookie", cookie.to_s) } Apache.request.send_http_header res.send_body(sock) else res.send_response(sock) end end end def service(req, res) method_name = "do_" + req.request_method.gsub(/-/, "_") if respond_to?(method_name) __send__(method_name, req, res) else raise HTTPStatus::MethodNotAllowed, "unsupported method `#{req.request_method}'." end end class Socket include Enumerable private def initialize(config, env, stdin, stdout) @config = config @env = env @header_part = StringIO.new @body_part = stdin @out_port = stdout @out_port.binmode @server_addr = @env["SERVER_ADDR"] || "0.0.0.0" @server_name = @env["SERVER_NAME"] @server_port = @env["SERVER_PORT"] @remote_addr = @env["REMOTE_ADDR"] @remote_host = @env["REMOTE_HOST"] || @remote_addr @remote_port = @env["REMOTE_PORT"] || 0 begin @header_part << request_line << CRLF setup_header @header_part << CRLF @header_part.rewind rescue Exception => ex raise CGIError, "invalid CGI environment" end end def request_line meth = @env["REQUEST_METHOD"] || "GET" unless url = @env["REQUEST_URI"] url = (@env["SCRIPT_NAME"] || File.expand_path($0)).dup url << @env["PATH_INFO"].to_s url = WEBrick::HTTPUtils.escape_path(url) if query_string = @env["QUERY_STRING"] unless query_string.empty? url << "?" << query_string end end end # we cannot get real HTTP version of client ;) httpv = @config[:HTTPVersion] return "#{meth} #{url} HTTP/#{httpv}" end def setup_header add_header("CONTENT_TYPE", "Content-Type") add_header("CONTENT_LENGTH", "Content-length") @env.each_key{|name| if /^HTTP_(.*)/ =~ name add_header(name, $1.gsub(/_/, "-")) end } end def add_header(envname, hdrname) if value = @env[envname] unless value.empty? @header_part << hdrname << ": " << value << CRLF end end end def input @header_part.eof? ? @body_part : @header_part end public def peeraddr [nil, @remote_port, @remote_host, @remote_addr] end def addr [nil, @server_port, @server_name, @server_addr] end def gets(eol=LF) input.gets(eol) end def read(size=nil) input.read(size) end def each input.each{|line| yield(line) } end def <<(data) @out_port << data end def cert return nil unless defined?(OpenSSL) if pem = @env["SSL_SERVER_CERT"] OpenSSL::X509::Certificate.new(pem) unless pem.empty? end end def peer_cert return nil unless defined?(OpenSSL) if pem = @env["SSL_CLIENT_CERT"] OpenSSL::X509::Certificate.new(pem) unless pem.empty? end end def peer_cert_chain return nil unless defined?(OpenSSL) if @env["SSL_CLIENT_CERT_CHAIN_0"] keys = @env.keys certs = keys.sort.collect{|k| if /^SSL_CLIENT_CERT_CHAIN_\d+$/ =~ k if pem = @env[k] OpenSSL::X509::Certificate.new(pem) unless pem.empty? end end } certs.compact end end def cipher return nil unless defined?(OpenSSL) if cipher = @env["SSL_CIPHER"] ret = [ cipher ] ret << @env["SSL_PROTOCOL"] ret << @env["SSL_CIPHER_USEKEYSIZE"] ret << @env["SSL_CIPHER_ALGKEYSIZE"] ret end end end end end ================================================ FILE: lib/webrick/compat.rb ================================================ # # compat.rb -- cross platform compatibility # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2002 GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: compat.rb,v 1.6 2002/10/01 17:16:32 gotoyuzo Exp $ module Errno class EPROTO < SystemCallError; end class ECONNRESET < SystemCallError; end class ECONNABORTED < SystemCallError; end end ================================================ FILE: lib/webrick/config.rb ================================================ # # config.rb -- Default configurations. # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2003 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: config.rb,v 1.52 2003/07/22 19:20:42 gotoyuzo Exp $ require 'webrick/version' require 'webrick/httpversion' require 'webrick/httputils' require 'webrick/utils' require 'webrick/log' module WEBrick module Config LIBDIR = File::dirname(__FILE__) # for GenericServer General = { :ServerName => Utils::getservername, :BindAddress => nil, # "0.0.0.0" or "::" or nil :Port => nil, # users MUST specifiy this!! :MaxClients => 100, # maximum number of the concurrent connections :ServerType => nil, # default: WEBrick::SimpleServer :Logger => nil, # default: WEBrick::Log.new :ServerSoftware => "WEBrick/#{WEBrick::VERSION} " + "(Ruby/#{RUBY_VERSION}/#{RUBY_RELEASE_DATE})", :TempDir => ENV['TMPDIR']||ENV['TMP']||ENV['TEMP']||'/tmp', :DoNotListen => false, :StartCallback => nil, :StopCallback => nil, :AcceptCallback => nil, } # for HTTPServer, HTTPRequest, HTTPResponse ... HTTP = General.dup.update( :Port => 80, :RequestTimeout => 30, :HTTPVersion => HTTPVersion.new("1.1"), :AccessLog => nil, :MimeTypes => HTTPUtils::DefaultMimeTypes, :DirectoryIndex => ["index.html","index.htm","index.cgi","index.rhtml"], :DocumentRoot => nil, :DocumentRootOptions => { :FancyIndexing => true }, :RequestHandler => nil, :RequestCallback => nil, # alias of :RequestHandler :ServerAlias => nil, # for HTTPProxyServer :ProxyAuthProc => nil, :ProxyContentHandler => nil, :ProxyVia => true, :ProxyTimeout => true, :ProxyURI => nil, :CGIInterpreter => nil, :CGIPathEnv => nil, # workaround: if Request-URIs contain 8bit chars, # they should be escaped before calling of URI::parse(). :Escape8bitURI => false ) FileHandler = { :NondisclosureName => [".ht*", "*~"], :FancyIndexing => false, :HandlerTable => {}, :HandlerCallback => nil, :DirectoryCallback => nil, :FileCallback => nil, :UserDir => nil, # e.g. "public_html" :AcceptableLanguages => [] # ["en", "ja", ... ] } BasicAuth = { :AutoReloadUserDB => true, } DigestAuth = { :Algorithm => 'MD5-sess', # or 'MD5' :Domain => nil, # an array includes domain names. :Qop => [ 'auth' ], # 'auth' or 'auth-int' or both. :UseOpaque => true, :UseNextNonce => false, :CheckNc => false, :UseAuthenticationInfoHeader => true, :AutoReloadUserDB => true, :NonceExpirePeriod => 30*60, :NonceExpireDelta => 60, :InternetExplorerHack => true, :OperaHack => true, } end end ================================================ FILE: lib/webrick/cookie.rb ================================================ # # cookie.rb -- Cookie class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: cookie.rb,v 1.16 2002/09/21 12:23:35 gotoyuzo Exp $ require 'time' require 'webrick/httputils' module WEBrick class Cookie attr_reader :name attr_accessor :value, :version attr_accessor :domain, :path, :secure attr_accessor :comment, :max_age #attr_accessor :comment_url, :discard, :port def initialize(name, value) @name = name @value = value @version = 0 # Netscape Cookie @domain = @path = @secure = @comment = @max_age = @expires = @comment_url = @discard = @port = nil end def expires=(t) @expires = t && (t.is_a?(Time) ? t.httpdate : t.to_s) end def expires @expires && Time.parse(@expires) end def to_s ret = "" ret << @name << "=" << @value ret << "; " << "Version=" << @version.to_s if @version > 0 ret << "; " << "Domain=" << @domain if @domain ret << "; " << "Expires=" << @expires if @expires ret << "; " << "Max-Age=" << @max_age.to_s if @max_age ret << "; " << "Comment=" << @comment if @comment ret << "; " << "Path=" << @path if @path ret << "; " << "Secure" if @secure ret end # Cookie::parse() # It parses Cookie field sent from the user agent. def self.parse(str) if str ret = [] cookie = nil ver = 0 str.split(/[;,]\s+/).each{|x| key, val = x.split(/=/,2) val = val ? HTTPUtils::dequote(val) : "" case key when "$Version"; ver = val.to_i when "$Path"; cookie.path = val when "$Domain"; cookie.domain = val when "$Port"; cookie.port = val else ret << cookie if cookie cookie = self.new(key, val) cookie.version = ver end } ret << cookie if cookie ret end end def self.parse_set_cookie(str) cookie_elem = str.split(/;/) first_elem = cookie_elem.shift first_elem.strip! key, value = first_elem.split(/=/, 2) cookie = new(key, HTTPUtils.dequote(value)) cookie_elem.each{|pair| pair.strip! key, value = pair.split(/=/, 2) if value value = HTTPUtils.dequote(value.strip) end case key.downcase when "domain" then cookie.domain = value when "path" then cookie.path = value when "expires" then cookie.expires = value when "max-age" then cookie.max_age = Integer(value) when "comment" then cookie.comment = value when "version" then cookie.version = Integer(value) when "secure" then cookie.secure = true end } return cookie end def self.parse_set_cookies(str) return str.split(/,(?=[^;,]*=)|,$/).collect{|c| parse_set_cookie(c) } end end end ================================================ FILE: lib/webrick/htmlutils.rb ================================================ # # htmlutils.rb -- HTMLUtils Module # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: htmlutils.rb,v 1.7 2002/09/21 12:23:35 gotoyuzo Exp $ module WEBrick module HTMLUtils def escape(string) str = string ? string.dup : "" str.gsub!(/&/n, '&') str.gsub!(/\"/n, '"') str.gsub!(/>/n, '>') str.gsub!(/ generate_next_nonce(req), 'rspauth' => digest_res } if @use_opaque opaque_struct.time = req.request_time opaque_struct.nonce = auth_info['nextnonce'] opaque_struct.nc = "%08x" % (auth_req['nc'].hex + 1) end if auth_req['qop'] == "auth" || auth_req['qop'] == "auth-int" ['qop','cnonce','nc'].each{|key| auth_info[key] = auth_req[key] } end res[@resp_info_field] = auth_info.keys.map{|key| if key == 'nc' key + '=' + auth_info[key] else key + "=" + HTTPUtils::quote(auth_info[key]) end }.join(', ') end info('%s: authentication scceeded.', auth_req['username']) req.user = auth_req['username'] return true end def split_param_value(string) ret = {} while string.size != 0 case string when /^\s*([\w\-\.\*\%\!]+)=\s*\"((\\.|[^\"])*)\"\s*,?/ key = $1 matched = $2 string = $' ret[key] = matched.gsub(/\\(.)/, "\\1") when /^\s*([\w\-\.\*\%\!]+)=\s*([^,\"]*),?/ key = $1 matched = $2 string = $' ret[key] = matched.clone when /^s*^,/ string = $' else break end end ret end def generate_next_nonce(req) now = "%012d" % req.request_time.to_i pk = hexdigest(now, @instance_key)[0,32] nonce = [now + ":" + pk].pack("m*").chop # it has 60 length of chars. nonce end def check_nonce(req, auth_req) username = auth_req['username'] nonce = auth_req['nonce'] pub_time, pk = nonce.unpack("m*")[0].split(":", 2) if (!pub_time || !pk) error("%s: empty nonce is given", username) return false elsif (hexdigest(pub_time, @instance_key)[0,32] != pk) error("%s: invalid private-key: %s for %s", username, hexdigest(pub_time, @instance_key)[0,32], pk) return false end diff_time = req.request_time.to_i - pub_time.to_i if (diff_time < 0) error("%s: difference of time-stamp is negative.", username) return false elsif diff_time > @nonce_expire_period error("%s: nonce is expired.", username) return false end return true end def generate_opaque(req) @mutex.synchronize{ now = req.request_time if now - @last_nonce_expire > @nonce_expire_delta @opaques.delete_if{|key,val| (now - val.time) > @nonce_expire_period } @last_nonce_expire = now end begin opaque = Utils::random_string(16) end while @opaques[opaque] @opaques[opaque] = OpaqueInfo.new(now, nil, '00000001') opaque } end def check_opaque(opaque_struct, req, auth_req) if (@use_next_nonce && auth_req['nonce'] != opaque_struct.nonce) error('%s: nonce unmatched. "%s" for "%s"', auth_req['username'], auth_req['nonce'], opaque_struct.nonce) return false elsif !check_nonce(req, auth_req) return false end if (@check_nc && auth_req['nc'] != opaque_struct.nc) error('%s: nc unmatched."%s" for "%s"', auth_req['username'], auth_req['nc'], opaque_struct.nc) return false end true end def check_uri(req, auth_req) uri = auth_req['uri'] if uri != req.request_uri.to_s && uri != req.unparsed_uri && (@internet_explorer_hack && uri != req.path) error('%s: uri unmatch. "%s" for "%s"', auth_req['username'], auth_req['uri'], req.request_uri.to_s) return false end true end def hexdigest(*args) @h.hexdigest(args.join(":")) end end class ProxyDigestAuth < DigestAuth include ProxyAuthenticator def check_uri(req, auth_req) return true end end end end ================================================ FILE: lib/webrick/httpauth/htdigest.rb ================================================ # # httpauth/htdigest.rb -- Apache compatible htdigest file # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2003 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: htdigest.rb,v 1.4 2003/07/22 19:20:45 gotoyuzo Exp $ require 'webrick/httpauth/userdb' require 'webrick/httpauth/digestauth' require 'tempfile' module WEBrick module HTTPAuth class Htdigest include UserDB def initialize(path) @path = path @mtime = Time.at(0) @digest = Hash.new @mutex = Mutex::new @auth_type = DigestAuth open(@path,"a").close unless File::exist?(@path) reload end def reload mtime = File::mtime(@path) if mtime > @mtime @digest.clear open(@path){|io| while line = io.gets line.chomp! user, realm, pass = line.split(/:/, 3) unless @digest[realm] @digest[realm] = Hash.new end @digest[realm][user] = pass end } @mtime = mtime end end def flush(output=nil) output ||= @path tmp = Tempfile.new("htpasswd", File::dirname(output)) begin each{|item| tmp.puts(item.join(":")) } tmp.close File::rename(tmp.path, output) rescue tmp.close(true) end end def get_passwd(realm, user, reload_db) reload() if reload_db if hash = @digest[realm] hash[user] end end def set_passwd(realm, user, pass) @mutex.synchronize{ unless @digest[realm] @digest[realm] = Hash.new end @digest[realm][user] = make_passwd(realm, user, pass) } end def delete_passwd(realm, user) if hash = @digest[realm] hash.delete(user) end end def each @digest.keys.sort.each{|realm| hash = @digest[realm] hash.keys.sort.each{|user| yield([user, realm, hash[user]]) } } end end end end ================================================ FILE: lib/webrick/httpauth/htgroup.rb ================================================ # # httpauth/htgroup.rb -- Apache compatible htgroup file # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2003 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: htgroup.rb,v 1.1 2003/02/16 22:22:56 gotoyuzo Exp $ require 'tempfile' module WEBrick module HTTPAuth class Htgroup def initialize(path) @path = path @mtime = Time.at(0) @group = Hash.new open(@path,"a").close unless File::exist?(@path) reload end def reload if (mtime = File::mtime(@path)) > @mtime @group.clear open(@path){|io| while line = io.gets line.chomp! group, members = line.split(/:\s*/) @group[group] = members.split(/\s+/) end } @mtime = mtime end end def flush(output=nil) output ||= @path tmp = Tempfile.new("htgroup", File::dirname(output)) begin @group.keys.sort.each{|group| tmp.puts(format("%s: %s", group, self.members(group).join(" "))) } tmp.close File::rename(tmp.path, output) rescue tmp.close(true) end end def members(group) reload @group[group] || [] end def add(group, members) @group[group] = members(group) | members end end end end ================================================ FILE: lib/webrick/httpauth/htpasswd.rb ================================================ # # httpauth/htpasswd -- Apache compatible htpasswd file # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2003 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: htpasswd.rb,v 1.4 2003/07/22 19:20:45 gotoyuzo Exp $ require 'webrick/httpauth/userdb' require 'webrick/httpauth/basicauth' require 'tempfile' module WEBrick module HTTPAuth class Htpasswd include UserDB def initialize(path) @path = path @mtime = Time.at(0) @passwd = Hash.new @auth_type = BasicAuth open(@path,"a").close unless File::exist?(@path) reload end def reload mtime = File::mtime(@path) if mtime > @mtime @passwd.clear open(@path){|io| while line = io.gets line.chomp! case line when %r!\A[^:]+:[a-zA-Z0-9./]{13}\z! user, pass = line.split(":") when /:\$/, /:\{SHA\}/ raise NotImplementedError, 'MD5, SHA1 .htpasswd file not supported' else raise StandardError, 'bad .htpasswd file' end @passwd[user] = pass end } @mtime = mtime end end def flush(output=nil) output ||= @path tmp = Tempfile.new("htpasswd", File::dirname(output)) begin each{|item| tmp.puts(item.join(":")) } tmp.close File::rename(tmp.path, output) rescue tmp.close(true) end end def get_passwd(realm, user, reload_db) reload() if reload_db @passwd[user] end def set_passwd(realm, user, pass) @passwd[user] = make_passwd(realm, user, pass) end def delete_passwd(realm, user) @passwd.delete(user) end def each @passwd.keys.sort.each{|user| yield([user, @passwd[user]]) } end end end end ================================================ FILE: lib/webrick/httpauth/userdb.rb ================================================ # # httpauth/userdb.rb -- UserDB mix-in module. # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2003 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: userdb.rb,v 1.2 2003/02/20 07:15:48 gotoyuzo Exp $ module WEBrick module HTTPAuth module UserDB attr_accessor :auth_type # BasicAuth or DigestAuth def make_passwd(realm, user, pass) @auth_type::make_passwd(realm, user, pass) end def set_passwd(realm, user, pass) self[user] = pass end def get_passwd(realm, user, reload_db=false) # reload_db is dummy make_passwd(realm, user, self[user]) end end end end ================================================ FILE: lib/webrick/httpauth.rb ================================================ # # httpauth.rb -- HTTP access authentication # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: httpauth.rb,v 1.14 2003/07/22 19:20:42 gotoyuzo Exp $ require 'webrick/httpauth/basicauth' require 'webrick/httpauth/digestauth' require 'webrick/httpauth/htpasswd' require 'webrick/httpauth/htdigest' require 'webrick/httpauth/htgroup' module WEBrick module HTTPAuth module_function def _basic_auth(req, res, realm, req_field, res_field, err_type, block) user = pass = nil if /^Basic\s+(.*)/o =~ req[req_field] userpass = $1 user, pass = userpass.unpack("m*")[0].split(":", 2) end if block.call(user, pass) req.user = user return end res[res_field] = "Basic realm=\"#{realm}\"" raise err_type end def basic_auth(req, res, realm, &block) _basic_auth(req, res, realm, "Authorization", "WWW-Authenticate", HTTPStatus::Unauthorized, block) end def proxy_basic_auth(req, res, realm, &block) _basic_auth(req, res, realm, "Proxy-Authorization", "Proxy-Authenticate", HTTPStatus::ProxyAuthenticationRequired, block) end end end ================================================ FILE: lib/webrick/httpproxy.rb ================================================ # # httpproxy.rb -- HTTPProxy Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2002 GOTO Kentaro # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: httpproxy.rb,v 1.18 2003/03/08 18:58:10 gotoyuzo Exp $ # $kNotwork: straw.rb,v 1.3 2002/02/12 15:13:07 gotoken Exp $ require "webrick/httpserver" require "net/http" Net::HTTP::version_1_2 if RUBY_VERSION < "1.7" module WEBrick NullReader = Object.new class << NullReader def read(*args) nil end alias gets read end class HTTPProxyServer < HTTPServer def initialize(config) super c = @config @via = "#{c[:HTTPVersion]} #{c[:ServerName]}:#{c[:Port]}" end def service(req, res) if req.request_method == "CONNECT" proxy_connect(req, res) elsif req.unparsed_uri =~ %r!^http://! proxy_service(req, res) else super(req, res) end end def proxy_auth(req, res) if proc = @config[:ProxyAuthProc] proc.call(req, res) end req.header.delete("proxy-authorization") end # Some header fields should not be transferred. HopByHop = %w( connection keep-alive proxy-authenticate upgrade proxy-authorization te trailers transfer-encoding ) ShouldNotTransfer = %w( set-cookie proxy-connection ) def split_field(f) f ? f.split(/,\s+/).collect{|i| i.downcase } : [] end def choose_header(src, dst) connections = split_field(src['connection']) src.each{|key, value| key = key.downcase if HopByHop.member?(key) || # RFC2616: 13.5.1 connections.member?(key) || # RFC2616: 14.10 ShouldNotTransfer.member?(key) # pragmatics @logger.debug("choose_header: `#{key}: #{value}'") next end dst[key] = value } end # Net::HTTP is stupid about the multiple header fields. # Here is workaround: def set_cookie(src, dst) if str = src['set-cookie'] cookies = [] str.split(/,\s*/).each{|token| if /^[^=]+;/o =~ token cookies[-1] << ", " << token elsif /=/o =~ token cookies << token else cookies[-1] << ", " << token end } dst.cookies.replace(cookies) end end def set_via(h) if @config[:ProxyVia] if h['via'] h['via'] << ", " << @via else h['via'] = @via end end end def proxy_uri(req, res) @config[:ProxyURI] end def proxy_service(req, res) # Proxy Authentication proxy_auth(req, res) # Create Request-URI to send to the origin server uri = req.request_uri path = uri.path.dup path << "?" << uri.query if uri.query # Choose header fields to transfer header = Hash.new choose_header(req, header) set_via(header) # select upstream proxy server if proxy = proxy_uri(req, res) proxy_host = proxy.host proxy_port = proxy.port if proxy.userinfo credentials = "Basic " + [proxy.userinfo].pack("m*") credentials.chomp! header['proxy-authorization'] = credentials end end response = nil begin http = Net::HTTP.new(uri.host, uri.port, proxy_host, proxy_port) http.start{ if @config[:ProxyTimeout] ################################## these issues are http.open_timeout = 30 # secs # necessary (maybe bacause http.read_timeout = 60 # secs # Ruby's bug, but why?) ################################## end case req.request_method when "GET" then response = http.get(path, header) when "POST" then response = http.post(path, req.body || "", header) when "HEAD" then response = http.head(path, header) else raise HTTPStatus::MethodNotAllowed, "unsupported method `#{req.request_method}'." end } rescue => err logger.debug("#{err.class}: #{err.message}") raise HTTPStatus::ServiceUnavailable, err.message end # Persistent connction requirements are mysterious for me. # So I will close the connection in every response. res['proxy-connection'] = "close" res['connection'] = "close" # Convert Net::HTTP::HTTPResponse to WEBrick::HTTPProxy res.status = response.code.to_i choose_header(response, res) set_cookie(response, res) set_via(res) res.body = response.body # Process contents if handler = @config[:ProxyContentHandler] handler.call(req, res) end end def proxy_connect(req, res) # Proxy Authentication proxy_auth(req, res) ua = Thread.current[:WEBrickSocket] # User-Agent raise HTTPStatus::InternalServerError, "[BUG] cannot get socket" unless ua host, port = req.unparsed_uri.split(":", 2) # Proxy authentication for upstream proxy server if proxy = proxy_uri(req, res) proxy_request_line = "CONNECT #{host}:#{port} HTTP/1.0" if proxy.userinfo credentials = "Basic " + [proxy.userinfo].pack("m*") credentials.chomp! end host, port = proxy.host, proxy.port end begin @logger.debug("CONNECT: upstream proxy is `#{host}:#{port}'.") os = TCPSocket.new(host, port) # origin server if proxy @logger.debug("CONNECT: sending a Request-Line") os << proxy_request_line << CRLF @logger.debug("CONNECT: > #{proxy_request_line}") if credentials @logger.debug("CONNECT: sending a credentials") os << "Proxy-Authorization: " << credentials << CRLF end os << CRLF proxy_status_line = os.gets(LF) @logger.debug("CONNECT: read a Status-Line form the upstream server") @logger.debug("CONNECT: < #{proxy_status_line}") if %r{^HTTP/\d+\.\d+\s+200\s*} =~ proxy_status_line while line = os.gets(LF) break if /\A(#{CRLF}|#{LF})\z/om =~ line end else raise HTTPStatus::BadGateway end end @logger.debug("CONNECT #{host}:#{port}: succeeded") res.status = HTTPStatus::RC_OK rescue => ex @logger.debug("CONNECT #{host}:#{port}: failed `#{ex.message}'") res.set_error(ex) raise HTTPStatus::EOFError ensure if handler = @config[:ProxyContentHandler] handler.call(req, res) end res.send_response(ua) access_log(@config, req, res) # Should clear request-line not to send the sesponse twice. # see: HTTPServer#run req.parse(NullReader) rescue nil end begin while fds = IO::select([ua, os]) if fds[0].member?(ua) buf = ua.sysread(1024); @logger.debug("CONNECT: #{buf.size} byte from User-Agent") os.syswrite(buf) elsif fds[0].member?(os) buf = os.sysread(1024); @logger.debug("CONNECT: #{buf.size} byte from #{host}:#{port}") ua.syswrite(buf) end end rescue => ex os.close @logger.debug("CONNECT #{host}:#{port}: closed") end raise HTTPStatus::EOFError end def do_OPTIONS(req, res) res['allow'] = "GET,HEAD,POST,OPTIONS,CONNECT" end end end ================================================ FILE: lib/webrick/httprequest.rb ================================================ # # httprequest.rb -- HTTPRequest Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: httprequest.rb,v 1.64 2003/07/13 17:18:22 gotoyuzo Exp $ require 'timeout' require 'uri' require 'webrick/httpversion' require 'webrick/httpstatus' require 'webrick/httputils' require 'webrick/cookie' module WEBrick class HTTPRequest BODY_CONTAINABLE_METHODS = [ "POST", "PUT" ] BUFSIZE = 1024*4 # Request line attr_reader :request_line attr_reader :request_method, :unparsed_uri, :http_version # Request-URI attr_reader :request_uri, :host, :port, :path attr_accessor :script_name, :path_info, :query_string # Header and entity body attr_reader :raw_header, :header, :cookies attr_reader :accept, :accept_charset attr_reader :accept_encoding, :accept_language # Misc attr_accessor :user attr_reader :addr, :peeraddr attr_reader :attributes attr_reader :keep_alive attr_reader :request_time def initialize(config) @config = config @logger = config[:Logger] @request_line = @request_method = @unparsed_uri = @http_version = nil @request_uri = @host = @port = @path = nil @script_name = @path_info = nil @query_string = nil @query = nil @form_data = nil @raw_header = Array.new @header = nil @cookies = [] @accept = [] @accept_charset = [] @accept_encoding = [] @accept_language = [] @body = "" @addr = @peeraddr = nil @attributes = {} @user = nil @keep_alive = false @request_time = nil @remaining_size = nil @socket = nil end def parse(socket=nil) @socket = socket begin @peeraddr = socket.respond_to?(:peeraddr) ? socket.peeraddr : [] @addr = socket.respond_to?(:addr) ? socket.addr : [] rescue Errno::ENOTCONN raise HTTPStatus::EOFError end read_request_line(socket) if @http_version.major > 0 read_header(socket) @header['cookie'].each{|cookie| @cookies += Cookie::parse(cookie) } @accept = HTTPUtils.parse_qvalues(self['accept']) @accept_charset = HTTPUtils.parse_qvalues(self['accept-charset']) @accept_encoding = HTTPUtils.parse_qvalues(self['accept-encoding']) @accept_language = HTTPUtils.parse_qvalues(self['accept-language']) end return if @request_method == "CONNECT" return if @unparsed_uri == "*" begin @request_uri = parse_uri(@unparsed_uri) @path = HTTPUtils::unescape(@request_uri.path) @path = HTTPUtils::normalize_path(@path) @host = @request_uri.host @port = @request_uri.port @query_string = @request_uri.query @script_name = "" @path_info = @path.dup rescue raise HTTPStatus::BadRequest, "bad URI `#{@unparsed_uri}'." end if /close/io =~ self["connection"] @keep_alive = false elsif /keep-alive/io =~ self["connection"] @keep_alive = true elsif @http_version < "1.1" @keep_alive = false else @keep_alive = true end end def body(&block) block ||= Proc.new{|chunk| @body << chunk } read_body(@socket, block) @body.empty? ? nil : @body end def query unless @query parse_query() end @query end def content_length return Integer(self['content-length']) end def content_type return self['content-type'] end def [](header_name) if @header value = @header[header_name.downcase] value.empty? ? nil : value.join(", ") end end def each @header.each{|k, v| value = @header[k] yield(k, value.empty? ? nil : value.join(", ")) } end def keep_alive? @keep_alive end def to_s ret = @request_line.dup @raw_header.each{|line| ret << line } ret << CRLF ret << body if body ret end def fixup() begin body{|chunk| } # read remaining body rescue HTTPStatus::Error => ex @logger.error("HTTPRequest#fixup: #{ex.class} occured.") @keep_alive = false rescue => ex @logger.error(ex) @keep_alive = false end end def meta_vars # This method provides the metavariables defined by the revision 3 # of ``The WWW Common Gateway Interface Version 1.1''. # (http://Web.Golux.Com/coar/cgi/) meta = Hash.new cl = self["Content-Length"] ct = self["Content-Type"] meta["CONTENT_LENGTH"] = cl if cl.to_i > 0 meta["CONTENT_TYPE"] = ct.dup if ct meta["GATEWAY_INTERFACE"] = "CGI/1.1" meta["PATH_INFO"] = @path_info ? @path_info.dup : "" #meta["PATH_TRANSLATED"] = nil # no plan to be provided meta["QUERY_STRING"] = @query_string ? @query_string.dup : "" meta["REMOTE_ADDR"] = @peeraddr[3] meta["REMOTE_HOST"] = @peeraddr[2] #meta["REMOTE_IDENT"] = nil # no plan to be provided meta["REMOTE_USER"] = @user meta["REQUEST_METHOD"] = @request_method.dup meta["REQUEST_URI"] = @request_uri.to_s meta["SCRIPT_NAME"] = @script_name.dup meta["SERVER_NAME"] = @host meta["SERVER_PORT"] = @port.to_s meta["SERVER_PROTOCOL"] = "HTTP/" + @config[:HTTPVersion].to_s meta["SERVER_SOFTWARE"] = @config[:ServerSoftware].dup self.each{|key, val| next if /^content-type$/i =~ key next if /^content-length$/i =~ key name = "HTTP_" + key name.gsub!(/-/o, "_") name.upcase! meta[name] = val } meta end private def read_request_line(socket) @request_line = read_line(socket) if socket @request_time = Time.now raise HTTPStatus::EOFError unless @request_line if /^(\S+)\s+(\S+?)(?:\s+HTTP\/(\d+\.\d+))?\r?\n/mo =~ @request_line @request_method = $1 @unparsed_uri = $2 @http_version = HTTPVersion.new($3 ? $3 : "0.9") else rl = @request_line.sub(/\x0d?\x0a\z/o, '') raise HTTPStatus::BadRequest, "bad Request-Line `#{rl}'." end end def read_header(socket) if socket while line = read_line(socket) break if /\A(#{CRLF}|#{LF})\z/om =~ line @raw_header << line end end @header = HTTPUtils::parse_header(@raw_header.join) end def parse_uri(str, scheme="http") if @config[:Escape8bitURI] str = HTTPUtils::escape8bit(str) end uri = URI::parse(str) return uri if uri.absolute? if self["host"] pattern = /\A(#{URI::REGEXP::PATTERN::HOST})(?::(\d+))?\z/n host, port = *self['host'].scan(pattern)[0] elsif @addr.size > 0 host, port = @addr[2], @addr[1] else host, port = @config[:ServerName], @config[:Port] end uri.scheme = scheme uri.host = host uri.port = port ? port.to_i : nil return URI::parse(uri.to_s) end def read_body(socket, block) return unless socket if tc = self['transfer-encoding'] case tc when /chunked/io then read_chunked(socket, block) else raise HTTPStatus::NotImplemented, "Transfer-Encoding: #{tc}." end elsif self['content-length'] || @remaining_size @remaining_size ||= self['content-length'].to_i while @remaining_size > 0 sz = BUFSIZE < @remaining_size ? BUFSIZE : @remaining_size break unless buf = read_data(socket, sz) @remaining_size -= buf.size block.call(buf) end if @remaining_size > 0 && @socket.eof? raise HTTPStatus::BadRequest, "invalid body size." end elsif BODY_CONTAINABLE_METHODS.member?(@request_method) raise HTTPStatus::LengthRequired end return @body end def read_chunk_size(socket) line = read_line(socket) if /^([0-9a-fA-F]+)(?:;(\S+))?/ =~ line chunk_size = $1.hex chunk_ext = $2 [ chunk_size, chunk_ext ] else raise HTTPStatus::BadRequest, "bad chunk `#{line}'." end end def read_chunked(socket, block) chunk_size, = read_chunk_size(socket) while chunk_size > 0 data = "" while data.size < chunk_size tmp = read_data(socket, chunk_size-data.size) # read chunk-data break unless tmp data << tmp end if data.nil? || data.size != chunk_size raise BadRequest, "bad chunk data size." end read_line(socket) # skip CRLF block.call(data) chunk_size, = read_chunk_size(socket) end read_header(socket) # trailer + CRLF @header.delete("transfer-encoding") @remaining_size = 0 end def _read_data(io, method, arg) begin timeout(@config[:RequestTimeout]){ return io.__send__(method, arg) } rescue Errno::ECONNRESET return nil rescue TimeoutError raise HTTPStatus::RequestTimeout end end def read_line(io) _read_data(io, :gets, LF) end def read_data(io, size) _read_data(io, :read, size) end def parse_query() begin if @request_method == "GET" || @request_method == "HEAD" @query = HTTPUtils::parse_query(@query_string) elsif self['content-type'] =~ /^application\/x-www-form-urlencoded/ @query = HTTPUtils::parse_query(body) elsif self['content-type'] =~ /^multipart\/form-data; boundary=(.+)/ boundary = HTTPUtils::dequote($1) @query = HTTPUtils::parse_form_data(body, boundary) else @query = Hash.new end rescue => ex raise HTTPStatus::BadRequest, ex.message end end end end ================================================ FILE: lib/webrick/httpresponse.rb ================================================ # # httpresponse.rb -- HTTPResponse Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: httpresponse.rb,v 1.45 2003/07/11 11:02:25 gotoyuzo Exp $ require 'time' require 'webrick/httpversion' require 'webrick/htmlutils' require 'webrick/httputils' require 'webrick/httpstatus' module WEBrick class HTTPResponse BUFSIZE = 1024*4 attr_reader :http_version, :status, :header attr_reader :cookies attr_accessor :reason_phrase attr_accessor :body attr_accessor :request_method, :request_uri, :request_http_version attr_accessor :filename attr_accessor :keep_alive attr_reader :config, :sent_size def initialize(config) @config = config @logger = config[:Logger] @header = Hash.new @status = HTTPStatus::RC_OK @reason_phrase = nil @http_version = HTTPVersion::convert(@config[:HTTPVersion]) @body = '' @keep_alive = true @cookies = [] @request_method = nil @request_uri = nil @request_http_version = @http_version # temporary @chunked = false @filename = nil @sent_size = 0 end def status_line "HTTP/#@http_version #@status #@reason_phrase #{CRLF}" end def status=(status) @status = status @reason_phrase = HTTPStatus::reason_phrase(status) end def [](field) @header[field.downcase] end def []=(field, value) @header[field.downcase] = value.to_s end def content_length if len = self['content-length'] return Integer(len) end end def content_length=(len) self['content-length'] = len.to_s end def content_type self['content-type'] end def content_type=(type) self['content-type'] = type end def each @header.each{|k, v| yield(k, v) } end def chunked? @chunked end def chunked=(val) @chunked = val ? true : false end def keep_alive? @keep_alive end def send_response(socket) begin setup_header() send_header(socket) send_body(socket) rescue Errno::EPIPE, Errno::ECONNRESET, Errno::ENOTCONN => ex @logger.debug(ex) @keep_alive = false rescue Exception => ex @logger.error(ex) @keep_alive = false end end def setup_header() @reason_phrase ||= HTTPStatus::reason_phrase(@status) @header['server'] ||= @config[:ServerSoftware] @header['date'] ||= Time.now.httpdate # HTTP/0.9 features if @request_http_version < "1.0" @http_version = HTTPVersion.new("0.9") @keep_alive = false end # HTTP/1.0 features if @request_http_version < "1.1" if chunked? @chunked = false ver = @request_http_version.to_s msg = "chunked is set for an HTTP/#{ver} request. (ignored)" @logger.warn(msg) end end # Determine the message length (RFC2616 -- 4.4 Message Length) if @status == 304 || @status == 204 || HTTPStatus::info?(@status) @header.delete('content-length') @body = "" elsif chunked? @header["transfer-encoding"] = "chunked" @header.delete('content-length') elsif %r{^multipart/byteranges} =~ @header['content-type'] @header.delete('content-length') elsif @header['content-length'].nil? unless @body.is_a?(IO) @header['content-length'] = @body ? @body.size : 0 end end # Keep-Alive connection. if @header['connection'] == "close" @keep_alive = false elsif keep_alive? if chunked? || @header['content-length'] @header['connection'] = "Keep-Alive" end else @header['connection'] = "close" end # Location is a single absoluteURI. if location = @header['location'] if @request_uri @header['location'] = @request_uri.merge(location) end end end def send_header(socket) if @http_version.major > 0 data = status_line() @header.each{|key, value| tmp = key.gsub(/\bwww|^te$|\b\w/){|s| s.upcase } data << "#{tmp}: #{value}" << CRLF } @cookies.each{|cookie| data << "Set-Cookie: " << cookie.to_s << CRLF } data << CRLF _write_data(socket, data) end end def send_body(socket) case @body when IO then send_body_io(socket) else send_body_string(socket) end end def to_s ret = "" send_response(ret) ret end def set_redirect(status, url) @body = "#{url.to_s}.\n" @header['location'] = url.to_s raise status end def set_error(ex, backtrace=false) case ex when HTTPStatus::Status @keep_alive = false if HTTPStatus::error?(ex.code) self.status = ex.code else @keep_alive = false self.status = HTTPStatus::RC_INTERNAL_SERVER_ERROR end @header['content-type'] = "text/html" if respond_to?(:create_error_page) create_error_page() return end if @request_uri host, port = @request_uri.host, @request_uri.port else host, port = @config[:ServerName], @config[:Port] end @body = '' @body << <<-_end_of_html_ #{HTMLUtils::escape(@reason_phrase)}

      #{HTMLUtils::escape(@reason_phrase)}

      #{HTMLUtils::escape(ex.message)}
      _end_of_html_ if backtrace && $DEBUG @body << "backtrace of `#{HTMLUtils::escape(ex.class.to_s)}' " @body << "#{HTMLUtils::escape(ex.message)}" @body << "
      "
              ex.backtrace.each{|line| @body << "\t#{line}\n"}
              @body << "

      " end @body << <<-_end_of_html_
      #{HTMLUtils::escape(@config[:ServerSoftware])} at #{host}:#{port}
      _end_of_html_ end private def send_body_io(socket) begin if @request_method == "HEAD" # do nothing elsif chunked? while buf = @body.read(BUFSIZE) next if buf.empty? data = "" data << format("%x", buf.size) << CRLF data << buf << CRLF _write_data(socket, data) @sent_size += buf.size end _write_data(socket, "0#{CRLF}#{CRLF}") else size = @header['content-length'].to_i _send_file(socket, @body, 0, size) @sent_size = size end ensure @body.close end end def send_body_string(socket) if @request_method == "HEAD" # do nothing elsif chunked? remain = body ? @body.size : 0 while buf = @body[@sent_size, BUFSIZE] break if buf.empty? data = "" data << format("%x", buf.size) << CRLF data << buf << CRLF _write_data(socket, data) @sent_size += buf.size end _write_data(socket, "0#{CRLF}#{CRLF}") else if @body && @body.size > 0 _write_data(socket, @body) @sent_size = @body.size end end end def _send_file(output, input, offset, size) while offset > 0 sz = BUFSIZE < offset ? BUFSIZE : offset buf = input.read(sz) offset -= buf.size end if size == 0 while buf = input.read(BUFSIZE) _write_data(output, buf) end else while size > 0 sz = BUFSIZE < size ? BUFSIZE : size buf = input.read(sz) _write_data(output, buf) size -= buf.size end end end def _write_data(socket, data) socket << data end end end ================================================ FILE: lib/webrick/https.rb ================================================ # # https.rb -- SSL/TLS enhancement for HTTPServer # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2001 GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: https.rb,v 1.15 2003/07/22 19:20:42 gotoyuzo Exp $ require 'webrick/ssl' module WEBrick module Config HTTP.update(SSL) end class HTTPRequest attr_reader :cipher, :server_cert, :client_cert alias orig_parse parse def parse(socket=nil) if socket.respond_to?(:cert) @server_cert = socket.cert || @config[:SSLCertificate] @client_cert = socket.peer_cert @client_cert_chain = socket.peer_cert_chain @cipher = socket.cipher end orig_parse(socket) end alias orig_parse_uri parse_uri def parse_uri(str, scheme="https") if @server_cert return orig_parse_uri(str, scheme) end return orig_parse_uri(str) end alias orig_meta_vars meta_vars def meta_vars meta = orig_meta_vars if @server_cert meta["HTTPS"] = "on" meta["SSL_SERVER_CERT"] = @server_cert.to_pem meta["SSL_CLIENT_CERT"] = @client_cert ? @client_cert.to_pem : "" if @client_cert_chain @client_cert_chain.each_with_index{|cert, i| meta["SSL_CLIENT_CERT_CHAIN_#{i}"] = cert.to_pem } end meta["SSL_CIPHER"] = @cipher[0] meta["SSL_PROTOCOL"] = @cipher[1] meta["SSL_CIPHER_USEKEYSIZE"] = @cipher[2].to_s meta["SSL_CIPHER_ALGKEYSIZE"] = @cipher[3].to_s end meta end end end ================================================ FILE: lib/webrick/httpserver.rb ================================================ # # httpserver.rb -- HTTPServer Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: httpserver.rb,v 1.63 2002/10/01 17:16:32 gotoyuzo Exp $ require 'webrick/server' require 'webrick/httputils' require 'webrick/httpstatus' require 'webrick/httprequest' require 'webrick/httpresponse' require 'webrick/httpservlet' require 'webrick/accesslog' module WEBrick class HTTPServerError < ServerError; end class HTTPServer < ::WEBrick::GenericServer def initialize(config={}, default=Config::HTTP) super @http_version = HTTPVersion::convert(@config[:HTTPVersion]) @mount_tab = MountTable.new if @config[:DocumentRoot] mount("/", HTTPServlet::FileHandler, @config[:DocumentRoot], @config[:DocumentRootOptions]) end unless @config[:AccessLog] @config[:AccessLog] = [ [ $stderr, AccessLog::COMMON_LOG_FORMAT ], [ $stderr, AccessLog::REFERER_LOG_FORMAT ] ] end @virtual_hosts = Array.new end def run(sock) while true res = HTTPResponse.new(@config) req = HTTPRequest.new(@config) server = self begin timeout = @config[:RequestTimeout] while timeout > 0 break if IO.select([sock], nil, nil, 0.5) timeout = 0 if @status != :Running timeout -= 0.5 end raise HTTPStatus::EOFError if timeout <= 0 || sock.eof? req.parse(sock) res.request_method = req.request_method res.request_uri = req.request_uri res.request_http_version = req.http_version res.keep_alive = req.keep_alive? server = lookup_server(req) || self if callback = server[:RequestCallback] || server[:RequestHandler] callback.call(req, res) end server.service(req, res) rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex res.set_error(ex) rescue HTTPStatus::Error => ex @logger.error(ex.message) res.set_error(ex) rescue HTTPStatus::Status => ex res.status = ex.code rescue StandardError => ex @logger.error(ex) res.set_error(ex, true) ensure if req.request_line req.fixup() res.send_response(sock) server.access_log(@config, req, res) end end break if @http_version < "1.1" break unless req.keep_alive? break unless res.keep_alive? end end def service(req, res) if req.unparsed_uri == "*" if req.request_method == "OPTIONS" do_OPTIONS(req, res) raise HTTPStatus::OK end raise HTTPStatus::NotFound, "`#{req.unparsed_uri}' not found." end servlet, options, script_name, path_info = search_servlet(req.path) raise HTTPStatus::NotFound, "`#{req.path}' not found." unless servlet req.script_name = script_name req.path_info = path_info si = servlet.get_instance(self, *options) @logger.debug(format("%s is invoked.", si.class.name)) si.service(req, res) end def do_OPTIONS(req, res) res["allow"] = "GET,HEAD,POST,OPTIONS" end def mount(dir, servlet, *options) @logger.debug(sprintf("%s is mounted on %s.", servlet.inspect, dir)) @mount_tab[dir] = [ servlet, options ] end def mount_proc(dir, proc=nil, &block) proc ||= block raise HTTPServerError, "must pass a proc or block" unless proc mount(dir, HTTPServlet::ProcHandler.new(proc)) end def unmount(dir) @logger.debug(sprintf("unmount %s.", dir)) @mount_tab.delete(dir) end alias umount unmount def search_servlet(path) script_name, path_info = @mount_tab.scan(path) servlet, options = @mount_tab[script_name] if servlet [ servlet, options, script_name, path_info ] end end def virtual_host(server) @virtual_hosts << server @virtual_hosts = @virtual_hosts.sort_by{|s| num = 0 num -= 4 if s[:BindAddress] num -= 2 if s[:Port] num -= 1 if s[:ServerName] num } end def lookup_server(req) @virtual_hosts.find{|s| (s[:BindAddress].nil? || req.addr[3] == s[:BindAddress]) && (s[:Port].nil? || req.port == s[:Port]) && ((s[:ServerName].nil? || req.host == s[:ServerName]) || (!s[:ServerAlias].nil? && s[:ServerAlias].find{|h| h === req.host})) } end def access_log(config, req, res) param = AccessLog::setup_params(config, req, res) @config[:AccessLog].each{|logger, fmt| logger << AccessLog::format(fmt+"\n", param) } end class MountTable def initialize @tab = Hash.new compile end def [](dir) dir = normalize(dir) @tab[dir] end def []=(dir, val) dir = normalize(dir) @tab[dir] = val compile val end def delete(dir) dir = normalize(dir) res = @tab.delete(dir) compile res end def scan(path) @scanner =~ path [ $&, $' ] end private def compile k = @tab.keys k.sort! k.reverse! k.collect!{|path| Regexp.escape(path) } @scanner = Regexp.new("^(" + k.join("|") +")(?=/|$)") end def normalize(dir) ret = dir ? dir.dup : "" ret.sub!(%r|/+$|, "") ret end end end end ================================================ FILE: lib/webrick/httpservlet/abstract.rb ================================================ # # httpservlet.rb -- HTTPServlet Module # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: abstract.rb,v 1.24 2003/07/11 11:16:46 gotoyuzo Exp $ require 'thread' require 'webrick/htmlutils' require 'webrick/httputils' require 'webrick/httpstatus' module WEBrick module HTTPServlet class HTTPServletError < StandardError; end class AbstractServlet def self.get_instance(config, *options) self.new(config, *options) end def initialize(server, *options) @server = @config = server @logger = @server[:Logger] @options = options end def service(req, res) method_name = "do_" + req.request_method.gsub(/-/, "_") if respond_to?(method_name) __send__(method_name, req, res) else raise HTTPStatus::MethodNotAllowed, "unsupported method `#{req.request_method}'." end end def do_GET(req, res) raise HTTPStatus::NotFound, "not found." end def do_HEAD(req, res) do_GET(req, res) end def do_OPTIONS(req, res) m = self.methods.grep(/^do_[A-Z]+$/) m.collect!{|i| i.sub(/do_/, "") } m.sort! res["allow"] = m.join(",") end private def redirect_to_directory_uri(req, res) if req.path[-1] != ?/ location = WEBrick::HTTPUtils.escape_path(req.path + "/") if req.query_string && req.query_string.size > 0 location << "?" << req.query_string end res.set_redirect(HTTPStatus::MovedPermanently, location) end end end end end ================================================ FILE: lib/webrick/httpservlet/cgi_runner.rb ================================================ # # cgi_runner.rb -- CGI launcher. # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU YUUZOU # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: cgi_runner.rb,v 1.9 2002/09/25 11:33:15 gotoyuzo Exp $ def sysread(io, size) buf = "" while size > 0 tmp = io.sysread(size) buf << tmp size -= tmp.size end return buf end STDIN.binmode buf = "" len = sysread(STDIN, 8).to_i out = sysread(STDIN, len) STDOUT.reopen(open(out, "w")) len = sysread(STDIN, 8).to_i err = sysread(STDIN, len) STDERR.reopen(open(err, "w")) len = sysread(STDIN, 8).to_i dump = sysread(STDIN, len) hash = Marshal.restore(dump) ENV.keys.each{|name| ENV.delete(name) } hash.each{|k, v| ENV[k] = v if v } dir = File::dirname(ENV["SCRIPT_FILENAME"]) Dir::chdir dir if interpreter = ARGV[0] argv = ARGV.dup argv << ENV["SCRIPT_FILENAME"] exec(*argv) # NOTREACHED end exec ENV["SCRIPT_FILENAME"] ================================================ FILE: lib/webrick/httpservlet/cgihandler.rb ================================================ # # cgihandler.rb -- CGIHandler Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: cgihandler.rb,v 1.27 2003/03/21 19:56:01 gotoyuzo Exp $ require 'rbconfig' require 'tempfile' require 'webrick/config' require 'webrick/httpservlet/abstract' module WEBrick module HTTPServlet class CGIHandler < AbstractServlet Ruby = File::join(::Config::CONFIG['bindir'], ::Config::CONFIG['ruby_install_name']) Ruby << ::Config::CONFIG['EXEEXT'] CGIRunner = "\"#{Ruby}\" \"#{Config::LIBDIR}/httpservlet/cgi_runner.rb\"" def initialize(server, name) super @script_filename = name @tempdir = server[:TempDir] @cgicmd = "#{CGIRunner} #{server[:CGIInterpreter]}" end def do_GET(req, res) data = nil status = -1 cgi_in = IO::popen(@cgicmd, "wb") cgi_out = Tempfile.new("webrick.cgiout.", @tempdir) cgi_err = Tempfile.new("webrick.cgierr.", @tempdir) begin cgi_in.sync = true meta = req.meta_vars meta["SCRIPT_FILENAME"] = @script_filename meta["PATH"] = @config[:CGIPathEnv] if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM meta["SystemRoot"] = ENV["SystemRoot"] end dump = Marshal.dump(meta) cgi_in.write("%8d" % cgi_out.path.size) cgi_in.write(cgi_out.path) cgi_in.write("%8d" % cgi_err.path.size) cgi_in.write(cgi_err.path) cgi_in.write("%8d" % dump.size) cgi_in.write(dump) if req.body and req.body.size > 0 cgi_in.write(req.body) end ensure cgi_in.close status = $?.exitstatus sleep 0.1 if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM data = cgi_out.read cgi_out.close(true) if errmsg = cgi_err.read if errmsg.size > 0 @logger.error("CGIHandler: #{@script_filename}:\n" + errmsg) end end cgi_err.close(true) end if status != 0 @logger.error("CGIHandler: #{@script_filename} exit with #{status}") end data = "" unless data raw_header, body = data.split(/^[\xd\xa]+/on, 2) raise HTTPStatus::InternalServerError, "Premature end of script headers: #{@script_filename}" if body.nil? begin header = HTTPUtils::parse_header(raw_header) if /^(\d+)/ =~ header['status'][0] res.status = $1.to_i header.delete('status') end if header.has_key?('location') # RFC 3875 6.2.3, 6.2.4 res.status = 302 unless (300...400) === res.status end if header.has_key?('set-cookie') header['set-cookie'].each{|k| res.cookies << Cookie.parse_set_cookie(k) } header.delete('set-cookie') end header.each{|key, val| res[key] = val.join(", ") } rescue => ex raise HTTPStatus::InternalServerError, ex.message end res.body = body end alias do_POST do_GET end end end ================================================ FILE: lib/webrick/httpservlet/erbhandler.rb ================================================ # # erbhandler.rb -- ERBHandler Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: erbhandler.rb,v 1.25 2003/02/24 19:25:31 gotoyuzo Exp $ require 'webrick/httpservlet/abstract.rb' require 'erb' module WEBrick module HTTPServlet class ERBHandler < AbstractServlet def initialize(server, name) super @script_filename = name end def do_GET(req, res) unless defined?(ERB) @logger.warn "#{self.class}: ERB not defined." raise HTTPStatus::Forbidden, "ERBHandler cannot work." end begin data = open(@script_filename){|io| io.read } res.body = evaluate(ERB.new(data), req, res) res['content-type'] = HTTPUtils::mime_type(@script_filename, @config[:MimeTypes]) rescue StandardError => ex raise rescue Exception => ex @logger.error(ex) raise HTTPStatus::InternalServerError, ex.message end end alias do_POST do_GET private def evaluate(erb, servlet_request, servlet_response) Module.new.module_eval{ meta_vars = servlet_request.meta_vars query = servlet_request.query erb.result(binding) } end end end end ================================================ FILE: lib/webrick/httpservlet/filehandler.rb ================================================ # # filehandler.rb -- FileHandler Module # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2003 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: filehandler.rb,v 1.44 2003/06/07 01:34:51 gotoyuzo Exp $ require 'thread' require 'time' require 'webrick/htmlutils' require 'webrick/httputils' require 'webrick/httpstatus' module WEBrick module HTTPServlet class DefaultFileHandler < AbstractServlet def initialize(server, local_path) super @local_path = local_path end def do_GET(req, res) st = File::stat(@local_path) mtime = st.mtime res['etag'] = sprintf("%x-%x-%x", st.ino, st.size, st.mtime.to_i) if not_modified?(req, res, mtime, res['etag']) res.body = '' raise HTTPStatus::NotModified elsif req['range'] make_partial_content(req, res, @local_path, st.size) raise HTTPStatus::PartialContent else mtype = HTTPUtils::mime_type(@local_path, @config[:MimeTypes]) res['content-type'] = mtype res['content-length'] = st.size res['last-modified'] = mtime.httpdate res.body = open(@local_path, "rb") end end def not_modified?(req, res, mtime, etag) if ir = req['if-range'] begin if Time.httpdate(ir) >= mtime return true end rescue if HTTPUtils::split_header_value(ir).member?(res['etag']) return true end end end if (ims = req['if-modified-since']) && Time.parse(ims) >= mtime return true end if (inm = req['if-none-match']) && HTTPUtils::split_header_value(inm).member?(res['etag']) return true end return false end def make_partial_content(req, res, filename, filesize) mtype = HTTPUtils::mime_type(filename, @config[:MimeTypes]) unless ranges = HTTPUtils::parse_range_header(req['range']) raise HTTPStatus::BadRequest, "Unrecognized range-spec: \"#{req['range']}\"" end open(filename, "rb"){|io| if ranges.size > 1 time = Time.now boundary = "#{time.sec}_#{time.usec}_#{Process::pid}" body = '' ranges.each{|range| first, last = prepare_range(range, filesize) next if first < 0 io.pos = first content = io.read(last-first+1) body << "--" << boundary << CRLF body << "Content-Type: #{mtype}" << CRLF body << "Content-Range: #{first}-#{last}/#{filesize}" << CRLF body << CRLF body << content body << CRLF } raise HTTPStatus::RequestRangeNotSatisfiable if body.empty? body << "--" << boundary << "--" << CRLF res["content-type"] = "multipart/byteranges; boundary=#{boundary}" res.body = body elsif range = ranges[0] first, last = prepare_range(range, filesize) raise HTTPStatus::RequestRangeNotSatisfiable if first < 0 if last == filesize - 1 content = io.dup content.pos = first else io.pos = first content = io.read(last-first+1) end res['content-type'] = mtype res['content-range'] = "#{first}-#{last}/#{filesize}" res['content-length'] = last - first + 1 res.body = content else raise HTTPStatus::BadRequest end } end def prepare_range(range, filesize) first = range.first < 0 ? filesize + range.first : range.first return -1, -1 if first < 0 || first >= filesize last = range.last < 0 ? filesize + range.last : range.last last = filesize - 1 if last >= filesize return first, last end end class FileHandler < AbstractServlet HandlerTable = Hash.new def self.add_handler(suffix, handler) HandlerTable[suffix] = handler end def self.remove_handler(suffix) HandlerTable.delete(suffix) end def initialize(server, root, options={}, default=Config::FileHandler) @config = server.config @logger = @config[:Logger] @root = File.expand_path(root) if options == true || options == false options = { :FancyIndexing => options } end @options = default.dup.update(options) end def service(req, res) # if this class is mounted on "/" and /~username is requested. # we're going to override path informations before invoking service. if defined?(Etc) && @options[:UserDir] && req.script_name.empty? if %r|^(/~([^/]+))| =~ req.path_info script_name, user = $1, $2 path_info = $' begin passwd = Etc::getpwnam(user) @root = File::join(passwd.dir, @options[:UserDir]) req.script_name = script_name req.path_info = path_info rescue @logger.debug "#{self.class}#do_GET: getpwnam(#{user}) failed" end end end prevent_directory_traversal(req, res) super(req, res) end def do_GET(req, res) unless exec_handler(req, res) set_dir_list(req, res) end end def do_POST(req, res) unless exec_handler(req, res) raise HTTPStatus::NotFound, "`#{req.path}' not found." end end def do_OPTIONS(req, res) unless exec_handler(req, res) super(req, res) end end # ToDo # RFC2518: HTTP Extensions for Distributed Authoring -- WEBDAV # # PROPFIND PROPPATCH MKCOL DELETE PUT COPY MOVE # LOCK UNLOCK # RFC3253: Versioning Extensions to WebDAV # (Web Distributed Authoring and Versioning) # # VERSION-CONTROL REPORT CHECKOUT CHECK_IN UNCHECKOUT # MKWORKSPACE UPDATE LABEL MERGE ACTIVITY private def trailing_pathsep?(path) # check for trailing path separator: # File.dirname("/aaaa/bbbb/") #=> "/aaaa") # File.dirname("/aaaa/bbbb/x") #=> "/aaaa/bbbb") # File.dirname("/aaaa/bbbb") #=> "/aaaa") # File.dirname("/aaaa/bbbbx") #=> "/aaaa") return File.dirname(path) != File.dirname(path+"x") end def prevent_directory_traversal(req, res) # Preventing directory traversal on Windows platforms; # Backslashes (0x5c) in path_info are not interpreted as special # character in URI notation. So the value of path_info should be # normalize before accessing to the filesystem. if trailing_pathsep?(req.path_info) # File.expand_path removes the trailing path separator. # Adding a character is a workaround to save it. # File.expand_path("/aaa/") #=> "/aaa" # File.expand_path("/aaa/" + "x") #=> "/aaa/x" expanded = File.expand_path(req.path_info + "x") expanded.chop! # remove trailing "x" else expanded = File.expand_path(req.path_info) end req.path_info = expanded end def exec_handler(req, res) raise HTTPStatus::NotFound, "`#{req.path}' not found" unless @root if set_filename(req, res) handler = get_handler(req, res) call_callback(:HandlerCallback, req, res) h = handler.get_instance(@config, res.filename) h.service(req, res) return true end call_callback(:HandlerCallback, req, res) return false end def get_handler(req, res) suffix1 = (/\.(\w+)\z/ =~ res.filename) && $1.downcase if /\.(\w+)\.([\w\-]+)\z/ =~ res.filename if @options[:AcceptableLanguages].include?($2.downcase) suffix2 = $1.downcase end end handler_table = @options[:HandlerTable] return handler_table[suffix1] || handler_table[suffix2] || HandlerTable[suffix1] || HandlerTable[suffix2] || DefaultFileHandler end def set_filename(req, res) res.filename = @root.dup path_info = req.path_info.scan(%r|/[^/]*|) path_info.unshift("") # dummy for checking @root dir while base = path_info.first break if base == "/" break unless File.directory?(File.expand_path(res.filename + base)) shift_path_info(req, res, path_info) call_callback(:DirectoryCallback, req, res) end if base = path_info.first if base == "/" if file = search_index_file(req, res) shift_path_info(req, res, path_info, file) call_callback(:FileCallback, req, res) return true end shift_path_info(req, res, path_info) elsif file = search_file(req, res, base) shift_path_info(req, res, path_info, file) call_callback(:FileCallback, req, res) return true else raise HTTPStatus::NotFound, "`#{req.path}' not found." end end return false end def check_filename(req, res, name) if nondisclosure_name?(name) || windows_ambiguous_name?(name) @logger.warn("the request refers nondisclosure name `#{name}'.") raise HTTPStatus::NotFound, "`#{req.path}' not found." end end def shift_path_info(req, res, path_info, base=nil) tmp = path_info.shift base = base || tmp req.path_info = path_info.join req.script_name << base res.filename = File.expand_path(res.filename + base) check_filename(req, res, File.basename(res.filename)) end def search_index_file(req, res) @config[:DirectoryIndex].each{|index| if file = search_file(req, res, "/"+index) return file end } return nil end def search_file(req, res, basename) langs = @options[:AcceptableLanguages] path = res.filename + basename if File.file?(path) return basename elsif langs.size > 0 req.accept_language.each{|lang| path_with_lang = path + ".#{lang}" if langs.member?(lang) && File.file?(path_with_lang) return basename + ".#{lang}" end } (langs - req.accept_language).each{|lang| path_with_lang = path + ".#{lang}" if File.file?(path_with_lang) return basename + ".#{lang}" end } end return nil end def call_callback(callback_name, req, res) if cb = @options[callback_name] cb.call(req, res) end end def windows_ambiguous_name?(name) return true if /[. ]+\z/ =~ name return true if /::\$DATA\z/ =~ name return false end def nondisclosure_name?(name) @options[:NondisclosureName].each{|pattern| if File.fnmatch(pattern, name, File::FNM_CASEFOLD) return true end } return false end def set_dir_list(req, res) redirect_to_directory_uri(req, res) unless @options[:FancyIndexing] raise HTTPStatus::Forbidden, "no access permission to `#{req.path}'" end local_path = res.filename list = Dir::entries(local_path).collect{|name| next if name == "." || name == ".." next if nondisclosure_name?(name) next if windows_ambiguous_name?(name) st = (File::stat(File.join(local_path, name)) rescue nil) if st.nil? [ name, nil, -1 ] elsif st.directory? [ name + "/", st.mtime, -1 ] else [ name, st.mtime, st.size ] end } list.compact! if d0 = req.query["N"]; idx = 0 elsif d0 = req.query["M"]; idx = 1 elsif d0 = req.query["S"]; idx = 2 else d0 = "A" ; idx = 0 end d1 = (d0 == "A") ? "D" : "A" if d0 == "A" list.sort!{|a,b| a[idx] <=> b[idx] } else list.sort!{|a,b| b[idx] <=> a[idx] } end res['content-type'] = "text/html" res.body = <<-_end_of_html_ Index of #{HTMLUtils::escape(req.path)}

      Index of #{HTMLUtils::escape(req.path)}

      _end_of_html_ res.body << "
      \n"
              res.body << " Name                          "
              res.body << "Last modified         "
              res.body << "Size\n"
              res.body << "
      \n" list.unshift [ "..", File::mtime(local_path+"/.."), -1 ] list.each{ |name, time, size| if name == ".." dname = "Parent Directory" elsif name.size > 25 dname = name.sub(/^(.{23})(.*)/){ $1 + ".." } else dname = name end s = " #{dname}" s << " " * (30 - dname.size) s << (time ? time.strftime("%Y/%m/%d %H:%M ") : " " * 22) s << (size >= 0 ? size.to_s : "-") << "\n" res.body << s } res.body << "

      " res.body << <<-_end_of_html_
      #{HTMLUtils::escape(@config[:ServerSoftware])}
      at #{req.host}:#{req.port}
      _end_of_html_ end end end end ================================================ FILE: lib/webrick/httpservlet/prochandler.rb ================================================ # # prochandler.rb -- ProcHandler Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: prochandler.rb,v 1.7 2002/09/21 12:23:42 gotoyuzo Exp $ require 'webrick/httpservlet/abstract.rb' module WEBrick module HTTPServlet class ProcHandler < AbstractServlet def get_instance(server, *options) self end def initialize(proc) @proc = proc end def do_GET(request, response) @proc.call(request, response) end alias do_POST do_GET end end end ================================================ FILE: lib/webrick/httpservlet.rb ================================================ # # httpservlet.rb -- HTTPServlet Utility File # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: httpservlet.rb,v 1.21 2003/02/23 12:24:46 gotoyuzo Exp $ require 'webrick/httpservlet/abstract' require 'webrick/httpservlet/filehandler' require 'webrick/httpservlet/cgihandler' require 'webrick/httpservlet/erbhandler' require 'webrick/httpservlet/prochandler' module WEBrick module HTTPServlet FileHandler.add_handler("cgi", CGIHandler) FileHandler.add_handler("rhtml", ERBHandler) end end ================================================ FILE: lib/webrick/httpstatus.rb ================================================ # # httpstatus.rb -- HTTPStatus Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: httpstatus.rb,v 1.11 2003/03/24 20:18:55 gotoyuzo Exp $ module WEBrick module HTTPStatus class Status < StandardError def initialize(message=self.class, *rest) super(AccessLog.escape(message), *rest) end class << self attr_reader :code, :reason_phrase end def code() self::class::code end def reason_phrase() self::class::reason_phrase end alias to_i code end class Info < Status; end class Success < Status; end class Redirect < Status; end class Error < Status; end class ClientError < Error; end class ServerError < Error; end class EOFError < StandardError; end StatusMessage = { 100, 'Continue', 101, 'Switching Protocols', 200, 'OK', 201, 'Created', 202, 'Accepted', 203, 'Non-Authoritative Information', 204, 'No Content', 205, 'Reset Content', 206, 'Partial Content', 300, 'Multiple Choices', 301, 'Moved Permanently', 302, 'Found', 303, 'See Other', 304, 'Not Modified', 305, 'Use Proxy', 307, 'Temporary Redirect', 400, 'Bad Request', 401, 'Unauthorized', 402, 'Payment Required', 403, 'Forbidden', 404, 'Not Found', 405, 'Method Not Allowed', 406, 'Not Acceptable', 407, 'Proxy Authentication Required', 408, 'Request Timeout', 409, 'Conflict', 410, 'Gone', 411, 'Length Required', 412, 'Precondition Failed', 413, 'Request Entity Too Large', 414, 'Request-URI Too Large', 415, 'Unsupported Media Type', 416, 'Request Range Not Satisfiable', 417, 'Expectation Failed', 500, 'Internal Server Error', 501, 'Not Implemented', 502, 'Bad Gateway', 503, 'Service Unavailable', 504, 'Gateway Timeout', 505, 'HTTP Version Not Supported' } CodeToError = {} StatusMessage.each{|code, message| message.freeze var_name = message.gsub(/[ \-]/,'_').upcase err_name = message.gsub(/[ \-]/,'') case code when 100...200; parent = Info when 200...300; parent = Success when 300...400; parent = Redirect when 400...500; parent = ClientError when 500...600; parent = ServerError end const_set("RC_#{var_name}", code) err_class = Class.new(parent) err_class.instance_variable_set(:@code, code) err_class.instance_variable_set(:@reason_phrase, message) const_set(err_name, err_class) CodeToError[code] = err_class } def reason_phrase(code) StatusMessage[code.to_i] end def info?(code) code.to_i >= 100 and code.to_i < 200 end def success?(code) code.to_i >= 200 and code.to_i < 300 end def redirect?(code) code.to_i >= 300 and code.to_i < 400 end def error?(code) code.to_i >= 400 and code.to_i < 600 end def client_error?(code) code.to_i >= 400 and code.to_i < 500 end def server_error?(code) code.to_i >= 500 and code.to_i < 600 end def self.[](code) CodeToError[code] end module_function :reason_phrase module_function :info?, :success?, :redirect?, :error? module_function :client_error?, :server_error? end end ================================================ FILE: lib/webrick/httputils.rb ================================================ # # httputils.rb -- HTTPUtils Module # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: httputils.rb,v 1.34 2003/06/05 21:34:08 gotoyuzo Exp $ require 'socket' require 'tempfile' module WEBrick CR = "\x0d" LF = "\x0a" CRLF = "\x0d\x0a" module HTTPUtils def normalize_path(path) raise "abnormal path `#{path}'" if path[0] != ?/ ret = path.dup ret.gsub!(%r{/+}o, '/') # // => / while ret.sub!(%r'/\.(?:/|\Z)', '/'); end # /. => / while ret.sub!(%r'/(?!\.\./)[^/]+/\.\.(?:/|\Z)', '/'); end # /foo/.. => /foo raise "abnormal path `#{path}'" if %r{/\.\.(/|\Z)} =~ ret ret end module_function :normalize_path ##### DefaultMimeTypes = { "ai" => "application/postscript", "asc" => "text/plain", "avi" => "video/x-msvideo", "bin" => "application/octet-stream", "bmp" => "image/bmp", "class" => "application/octet-stream", "cer" => "application/pkix-cert", "crl" => "application/pkix-crl", "crt" => "application/x-x509-ca-cert", #"crl" => "application/x-pkcs7-crl", "css" => "text/css", "dms" => "application/octet-stream", "doc" => "application/msword", "dvi" => "application/x-dvi", "eps" => "application/postscript", "etx" => "text/x-setext", "exe" => "application/octet-stream", "gif" => "image/gif", "htm" => "text/html", "html" => "text/html", "jpe" => "image/jpeg", "jpeg" => "image/jpeg", "jpg" => "image/jpeg", "lha" => "application/octet-stream", "lzh" => "application/octet-stream", "mov" => "video/quicktime", "mpe" => "video/mpeg", "mpeg" => "video/mpeg", "mpg" => "video/mpeg", "pbm" => "image/x-portable-bitmap", "pdf" => "application/pdf", "pgm" => "image/x-portable-graymap", "png" => "image/png", "pnm" => "image/x-portable-anymap", "ppm" => "image/x-portable-pixmap", "ppt" => "application/vnd.ms-powerpoint", "ps" => "application/postscript", "qt" => "video/quicktime", "ras" => "image/x-cmu-raster", "rb" => "text/plain", "rd" => "text/plain", "rtf" => "application/rtf", "sgm" => "text/sgml", "sgml" => "text/sgml", "tif" => "image/tiff", "tiff" => "image/tiff", "txt" => "text/plain", "xbm" => "image/x-xbitmap", "xls" => "application/vnd.ms-excel", "xml" => "text/xml", "xpm" => "image/x-xpixmap", "xwd" => "image/x-xwindowdump", "zip" => "application/zip", } # Load Apache compatible mime.types file. def load_mime_types(file) open(file){ |io| hash = Hash.new io.each{ |line| next if /^#/ =~ line line.chomp! mimetype, ext0 = line.split(/\s+/, 2) next unless ext0 next if ext0.empty? ext0.split(/\s+/).each{ |ext| hash[ext] = mimetype } } hash } end module_function :load_mime_types def mime_type(filename, mime_tab) suffix1 = (/\.(\w+)$/ =~ filename && $1.downcase) suffix2 = (/\.(\w+)\.[\w\-]+$/ =~ filename && $1.downcase) mime_tab[suffix1] || mime_tab[suffix2] || "application/octet-stream" end module_function :mime_type ##### def parse_header(raw) header = Hash.new([].freeze) field = nil raw.each{|line| case line when /^([A-Za-z0-9!\#$%&'*+\-.^_`|~]+):\s*(.*?)\s*\z/om field, value = $1, $2 field.downcase! header[field] = [] unless header.has_key?(field) header[field] << value when /^\s+(.*?)\s*\z/om value = $1 unless field raise HTTPStatus::BadRequest, "bad header '#{line}'." end header[field][-1] << " " << value else raise HTTPStatus::BadRequest, "bad header '#{line}'." end } header.each{|key, values| values.each{|value| value.strip! value.gsub!(/\s+/, " ") } } header end module_function :parse_header def split_header_value(str) str.scan(%r'\G((?:"(?:\\.|[^"])+?"|[^",]+)+) (?:,\s*|\Z)'xn).flatten end module_function :split_header_value def parse_range_header(ranges_specifier) if /^bytes=(.*)/ =~ ranges_specifier byte_range_set = split_header_value($1) byte_range_set.collect{|range_spec| case range_spec when /^(\d+)-(\d+)/ then $1.to_i .. $2.to_i when /^(\d+)-/ then $1.to_i .. -1 when /^-(\d+)/ then -($1.to_i) .. -1 else return nil end } end end module_function :parse_range_header def parse_qvalues(value) tmp = [] if value parts = value.split(/,\s*/) parts.each {|part| if m = %r{^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$}.match(part) val = m[1] q = (m[2] or 1).to_f tmp.push([val, q]) end } tmp = tmp.sort_by{|val, q| -q} tmp.collect!{|val, q| val} end return tmp end module_function :parse_qvalues ##### def dequote(str) ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup ret.gsub!(/\\(.)/, "\\1") ret end module_function :dequote def quote(str) '"' << str.gsub(/[\\\"]/o, "\\\1") << '"' end module_function :quote ##### class FormData < String EmptyRawHeader = [].freeze EmptyHeader = {}.freeze attr_accessor :name, :filename, :next_data protected :next_data def initialize(*args) @name = @filename = @next_data = nil if args.empty? @raw_header = [] @header = nil super("") else @raw_header = EmptyRawHeader @header = EmptyHeader super(args.shift) unless args.empty? @next_data = self.class.new(*args) end end end def [](*key) begin @header[key[0].downcase].join(", ") rescue StandardError, NameError super end end def <<(str) if @header super elsif str == CRLF @header = HTTPUtils::parse_header(@raw_header) if cd = self['content-disposition'] if /\s+name="(.*?)"/ =~ cd then @name = $1 end if /\s+filename="(.*?)"/ =~ cd then @filename = $1 end end else @raw_header << str end self end def append_data(data) tmp = self while tmp unless tmp.next_data tmp.next_data = data break end tmp = tmp.next_data end self end def each_data tmp = self while tmp next_data = tmp.next_data yield(tmp) tmp = next_data end end def list ret = [] each_data{|data| ret << data.to_s } ret end alias :to_ary :list def to_s String.new(self) end end def parse_query(str) query = Hash.new if str str.split(/[&;]/).each{|x| next if x.empty? key, val = x.split(/=/,2) key = unescape_form(key) val = unescape_form(val.to_s) val = FormData.new(val) val.name = key if query.has_key?(key) query[key].append_data(val) next end query[key] = val } end query end module_function :parse_query def parse_form_data(io, boundary) boundary_regexp = /\A--#{boundary}(--)?#{CRLF}\z/ form_data = Hash.new return form_data unless io data = nil io.each{|line| if boundary_regexp =~ line if data data.chop! key = data.name if form_data.has_key?(key) form_data[key].append_data(data) else form_data[key] = data end end data = FormData.new next else if data data << line end end } return form_data end module_function :parse_form_data ##### reserved = ';/?:@&=+$,' num = '0123456789' lowalpha = 'abcdefghijklmnopqrstuvwxyz' upalpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' mark = '-_.!~*\'()' unreserved = num + lowalpha + upalpha + mark control = (0x0..0x1f).collect{|c| c.chr }.join + "\x7f" space = " " delims = '<>#%"' unwise = '{}|\\^[]`' nonascii = (0x80..0xff).collect{|c| c.chr }.join module_function def _make_regex(str) /([#{Regexp.escape(str)}])/n end def _make_regex!(str) /([^#{Regexp.escape(str)}])/n end def _escape(str, regex) str.gsub(regex){ "%%%02X" % $1[0] } end def _unescape(str, regex) str.gsub(regex){ $1.hex.chr } end UNESCAPED = _make_regex(control+space+delims+unwise+nonascii) UNESCAPED_FORM = _make_regex(reserved+control+delims+unwise+nonascii) NONASCII = _make_regex(nonascii) ESCAPED = /%([0-9a-fA-F]{2})/ UNESCAPED_PCHAR = _make_regex!(unreserved+":@&=+$,") def escape(str) _escape(str, UNESCAPED) end def unescape(str) _unescape(str, ESCAPED) end def escape_form(str) ret = _escape(str, UNESCAPED_FORM) ret.gsub!(/ /, "+") ret end def unescape_form(str) _unescape(str.gsub(/\+/, " "), ESCAPED) end def escape_path(str) result = "" str.scan(%r{/([^/]*)}).each{|i| result << "/" << _escape(i[0], UNESCAPED_PCHAR) } return result end def escape8bit(str) _escape(str, NONASCII) end end end ================================================ FILE: lib/webrick/httpversion.rb ================================================ # # HTTPVersion.rb -- presentation of HTTP version # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: httpversion.rb,v 1.5 2002/09/21 12:23:37 gotoyuzo Exp $ module WEBrick class HTTPVersion include Comparable attr_accessor :major, :minor def self.convert(version) version.is_a?(self) ? version : new(version) end def initialize(version) case version when HTTPVersion @major, @minor = version.major, version.minor when String if /^(\d+)\.(\d+)$/ =~ version @major, @minor = $1.to_i, $2.to_i end end if @major.nil? || @minor.nil? raise ArgumentError, format("cannot convert %s into %s", version.class, self.class) end end def <=>(other) unless other.is_a?(self.class) other = self.class.new(other) end if (ret = @major <=> other.major) == 0 return @minor <=> other.minor end return ret end def to_s format("%d.%d", @major, @minor) end end end ================================================ FILE: lib/webrick/log.rb ================================================ # # log.rb -- Log Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: log.rb,v 1.26 2002/10/06 17:06:10 gotoyuzo Exp $ module WEBrick class BasicLog # log-level constant FATAL, ERROR, WARN, INFO, DEBUG = 1, 2, 3, 4, 5 attr_accessor :level def initialize(log_file=nil, level=nil) @level = level || INFO case log_file when String @log = open(log_file, "a+") @log.sync = true @opened = true when NilClass @log = $stderr else @log = log_file # requires "<<". (see BasicLog#log) end end def close @log.close if @opened @log = nil end def log(level, data) if @log && level <= @level data += "\n" if /\n\Z/ !~ data @log << data end end def <<(obj) log(INFO, obj.to_s) end def fatal(msg) log(FATAL, "FATAL " << format(msg)); end def error(msg) log(ERROR, "ERROR " << format(msg)); end def warn(msg) log(WARN, "WARN " << format(msg)); end def info(msg) log(INFO, "INFO " << format(msg)); end def debug(msg) log(DEBUG, "DEBUG " << format(msg)); end def fatal?; @level >= FATAL; end def error?; @level >= ERROR; end def warn?; @level >= WARN; end def info?; @level >= INFO; end def debug?; @level >= DEBUG; end private def format(arg) str = if arg.is_a?(Exception) "#{arg.class}: #{arg.message}\n\t" << arg.backtrace.join("\n\t") << "\n" elsif arg.respond_to?(:to_str) arg.to_str else arg.inspect end end end class Log < BasicLog attr_accessor :time_format def initialize(log_file=nil, level=nil) super(log_file, level) @time_format = "[%Y-%m-%d %H:%M:%S]" end def log(level, data) tmp = Time.now.strftime(@time_format) tmp << " " << data super(level, tmp) end end end ================================================ FILE: lib/webrick/server.rb ================================================ # # server.rb -- GenericServer Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: server.rb,v 1.62 2003/07/22 19:20:43 gotoyuzo Exp $ require 'thread' require 'socket' require 'timeout' require 'webrick/config' require 'webrick/log' module WEBrick class ServerError < StandardError; end class SimpleServer def SimpleServer.start yield end end class Daemon def Daemon.start exit!(0) if fork Process::setsid exit!(0) if fork Dir::chdir("/") File::umask(0) STDIN.reopen("/dev/null") STDOUT.reopen("/dev/null", "w") STDERR.reopen("/dev/null", "w") yield if block_given? end end class GenericServer attr_reader :status, :config, :logger, :tokens, :listeners def initialize(config={}, default=Config::General) @config = default.dup.update(config) @status = :Stop @config[:Logger] ||= Log::new @logger = @config[:Logger] @tokens = SizedQueue.new(@config[:MaxClients]) @config[:MaxClients].times{ @tokens.push(nil) } webrickv = WEBrick::VERSION rubyv = "#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]" @logger.info("WEBrick #{webrickv}") @logger.info("ruby #{rubyv}") @listeners = [] unless @config[:DoNotListen] if @config[:Listen] warn(":Listen option is deprecated; use GenericServer#listen") end listen(@config[:BindAddress], @config[:Port]) if @config[:Port] == 0 @config[:Port] = @listeners[0].addr[1] end end end def [](key) @config[key] end def listen(address, port) @listeners += Utils::create_listeners(address, port, @logger) end def start(&block) raise ServerError, "already started." if @status != :Stop server_type = @config[:ServerType] || SimpleServer server_type.start{ @logger.info \ "#{self.class}#start: pid=#{$$} port=#{@config[:Port]}" call_callback(:StartCallback) thgroup = ThreadGroup.new @status = :Running while @status == :Running begin if svrs = IO.select(@listeners, nil, nil, 2.0) svrs[0].each{|svr| @tokens.pop # blocks while no token is there. if sock = accept_client(svr) th = start_thread(sock, &block) th[:WEBrickThread] = true thgroup.add(th) else @tokens.push(nil) end } end rescue Errno::EBADF, IOError => ex # if the listening socket was closed in GenericServer#shutdown, # IO::select raise it. rescue Exception => ex msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}" @logger.error msg end end @logger.info "going to shutdown ..." thgroup.list.each{|th| th.join if th[:WEBrickThread] } call_callback(:StopCallback) @logger.info "#{self.class}#start done." @status = :Stop } end def stop if @status == :Running @status = :Shutdown end end def shutdown stop @listeners.each{|s| if @logger.debug? addr = s.addr @logger.debug("close TCPSocket(#{addr[2]}, #{addr[1]})") end s.close } @listeners.clear end def run(sock) @logger.fatal "run() must be provided by user." end private def accept_client(svr) sock = nil begin sock = svr.accept sock.sync = true Utils::set_non_blocking(sock) Utils::set_close_on_exec(sock) rescue Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPROTO => ex # TCP connection was established but RST segment was sent # from peer before calling TCPServer#accept. rescue Exception => ex msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}" @logger.error msg end return sock end def start_thread(sock, &block) Thread.start{ begin Thread.current[:WEBrickSocket] = sock begin addr = sock.peeraddr @logger.debug "accept: #{addr[3]}:#{addr[1]}" rescue SocketError @logger.debug "accept:
      " raise end call_callback(:AcceptCallback, sock) block ? block.call(sock) : run(sock) rescue Errno::ENOTCONN @logger.debug "Errno::ENOTCONN raised" rescue ServerError => ex msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}" @logger.error msg rescue Exception => ex @logger.error ex ensure @tokens.push(nil) Thread.current[:WEBrickSocket] = nil if addr @logger.debug "close: #{addr[3]}:#{addr[1]}" else @logger.debug "close:
      " end sock.close end } end def call_callback(callback_name, *args) if cb = @config[callback_name] cb.call(*args) end end end # end of GenericServer end ================================================ FILE: lib/webrick/ssl.rb ================================================ # # ssl.rb -- SSL/TLS enhancement for GenericServer # # Copyright (c) 2003 GOTOU Yuuzou All rights reserved. # # $Id$ require 'webrick' require 'openssl' module WEBrick module Config svrsoft = General[:ServerSoftware] osslv = ::OpenSSL::OPENSSL_VERSION.split[1] SSL = { :ServerSoftware => "#{svrsoft} OpenSSL/#{osslv}", :SSLEnable => false, :SSLCertificate => nil, :SSLPrivateKey => nil, :SSLClientCA => nil, :SSLExtraChainCert => nil, :SSLCACertificateFile => nil, :SSLCACertificatePath => nil, :SSLCertificateStore => nil, :SSLVerifyClient => ::OpenSSL::SSL::VERIFY_NONE, :SSLVerifyDepth => nil, :SSLVerifyCallback => nil, # custom verification :SSLTimeout => nil, :SSLOptions => nil, :SSLStartImmediately => true, # Must specify if you use auto generated certificate. :SSLCertName => nil, :SSLCertComment => "Generated by Ruby/OpenSSL" } General.update(SSL) end module Utils def create_self_signed_cert(bits, cn, comment) rsa = OpenSSL::PKey::RSA.new(bits){|p, n| case p when 0; $stderr.putc "." # BN_generate_prime when 1; $stderr.putc "+" # BN_generate_prime when 2; $stderr.putc "*" # searching good prime, # n = #of try, # but also data from BN_generate_prime when 3; $stderr.putc "\n" # found good prime, n==0 - p, n==1 - q, # but also data from BN_generate_prime else; $stderr.putc "*" # BN_generate_prime end } cert = OpenSSL::X509::Certificate.new cert.version = 3 cert.serial = 0 name = OpenSSL::X509::Name.new(cn) cert.subject = name cert.issuer = name cert.not_before = Time.now cert.not_after = Time.now + (365*24*60*60) cert.public_key = rsa.public_key ef = OpenSSL::X509::ExtensionFactory.new(nil,cert) ef.issuer_certificate = cert cert.extensions = [ ef.create_extension("basicConstraints","CA:FALSE"), ef.create_extension("keyUsage", "keyEncipherment"), ef.create_extension("subjectKeyIdentifier", "hash"), ef.create_extension("extendedKeyUsage", "serverAuth"), ef.create_extension("nsComment", comment), ] aki = ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") cert.add_extension(aki) cert.sign(rsa, OpenSSL::Digest::SHA1.new) return [ cert, rsa ] end module_function :create_self_signed_cert end class GenericServer def ssl_context @ssl_context ||= nil end def listen(address, port) listeners = Utils::create_listeners(address, port, @logger) if @config[:SSLEnable] unless ssl_context @ssl_context = setup_ssl_context(@config) @logger.info("\n" + @config[:SSLCertificate].to_text) end listeners.collect!{|svr| ssvr = ::OpenSSL::SSL::SSLServer.new(svr, ssl_context) ssvr.start_immediately = @config[:SSLStartImmediately] ssvr } end @listeners += listeners end def setup_ssl_context(config) unless config[:SSLCertificate] cn = config[:SSLCertName] comment = config[:SSLCertComment] cert, key = Utils::create_self_signed_cert(1024, cn, comment) config[:SSLCertificate] = cert config[:SSLPrivateKey] = key end ctx = OpenSSL::SSL::SSLContext.new ctx.key = config[:SSLPrivateKey] ctx.cert = config[:SSLCertificate] ctx.client_ca = config[:SSLClientCA] ctx.extra_chain_cert = config[:SSLExtraChainCert] ctx.ca_file = config[:SSLCACertificateFile] ctx.ca_path = config[:SSLCACertificatePath] ctx.cert_store = config[:SSLCertificateStore] ctx.verify_mode = config[:SSLVerifyClient] ctx.verify_depth = config[:SSLVerifyDepth] ctx.verify_callback = config[:SSLVerifyCallback] ctx.timeout = config[:SSLTimeout] ctx.options = config[:SSLOptions] ctx end end end ================================================ FILE: lib/webrick/utils.rb ================================================ # # utils.rb -- Miscellaneous utilities # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: utils.rb,v 1.10 2003/02/16 22:22:54 gotoyuzo Exp $ require 'socket' require 'fcntl' begin require 'etc' rescue LoadError nil end module WEBrick module Utils def set_non_blocking(io) flag = File::NONBLOCK if defined?(Fcntl::F_GETFL) flag |= io.fcntl(Fcntl::F_GETFL) end io.fcntl(Fcntl::F_SETFL, flag) end module_function :set_non_blocking def set_close_on_exec(io) if defined?(Fcntl::FD_CLOEXEC) io.fcntl(Fcntl::FD_CLOEXEC, 1) end end module_function :set_close_on_exec def su(user) if defined?(Etc) pw = Etc.getpwnam(user) Process::initgroups(user, pw.gid) Process::Sys::setgid(pw.gid) Process::Sys::setuid(pw.uid) else warn("WEBrick::Utils::su doesn't work on this platform") end end module_function :su def getservername host = Socket::gethostname begin Socket::gethostbyname(host)[0] rescue host end end module_function :getservername def create_listeners(address, port, logger=nil) unless port raise ArgumentError, "must specify port" end res = Socket::getaddrinfo(address, port, Socket::AF_UNSPEC, # address family Socket::SOCK_STREAM, # socket type 0, # protocol Socket::AI_PASSIVE) # flag last_error = nil sockets = [] res.each{|ai| begin logger.debug("TCPServer.new(#{ai[3]}, #{port})") if logger sock = TCPServer.new(ai[3], port) port = sock.addr[1] if port == 0 Utils::set_close_on_exec(sock) sockets << sock rescue => ex logger.warn("TCPServer Error: #{ex}") if logger last_error = ex end } raise last_error if sockets.empty? return sockets end module_function :create_listeners RAND_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "abcdefghijklmnopqrstuvwxyz" def random_string(len) rand_max = RAND_CHARS.size ret = "" len.times{ ret << RAND_CHARS[rand(rand_max)] } ret end module_function :random_string end end ================================================ FILE: lib/webrick/version.rb ================================================ # # version.rb -- version and release date # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU YUUZOU # Copyright (c) 2003 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: version.rb,v 1.74 2003/07/22 19:20:43 gotoyuzo Exp $ module WEBrick VERSION = "1.3.1" end ================================================ FILE: lib/webrick.rb ================================================ # # WEBrick -- WEB server toolkit. # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU YUUZOU # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: webrick.rb,v 1.12 2002/10/01 17:16:31 gotoyuzo Exp $ require 'webrick/compat.rb' require 'webrick/version.rb' require 'webrick/config.rb' require 'webrick/log.rb' require 'webrick/server.rb' require 'webrick/utils.rb' require 'webrick/accesslog' require 'webrick/htmlutils.rb' require 'webrick/httputils.rb' require 'webrick/cookie.rb' require 'webrick/httpversion.rb' require 'webrick/httpstatus.rb' require 'webrick/httprequest.rb' require 'webrick/httpresponse.rb' require 'webrick/httpserver.rb' require 'webrick/httpservlet.rb' require 'webrick/httpauth.rb' ================================================ FILE: lib/wsdl/binding.rb ================================================ # WSDL4R - WSDL binding definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL class Binding < Info attr_reader :name # required attr_reader :type # required attr_reader :operations attr_reader :soapbinding def initialize super @name = nil @type = nil @operations = XSD::NamedElements.new @soapbinding = nil end def targetnamespace parent.targetnamespace end def parse_element(element) case element when OperationName o = OperationBinding.new @operations << o o when SOAPBindingName o = WSDL::SOAP::Binding.new @soapbinding = o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) when TypeAttrName @type = value else nil end end end end ================================================ FILE: lib/wsdl/data.rb ================================================ # WSDL4R - WSDL data definitions. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' require 'wsdl/documentation' require 'wsdl/definitions' require 'wsdl/types' require 'wsdl/message' require 'wsdl/part' require 'wsdl/portType' require 'wsdl/operation' require 'wsdl/param' require 'wsdl/binding' require 'wsdl/operationBinding' require 'wsdl/service' require 'wsdl/port' require 'wsdl/import' module WSDL ArrayTypeAttrName = XSD::QName.new(Namespace, 'arrayType') BindingName = XSD::QName.new(Namespace, 'binding') DefinitionsName = XSD::QName.new(Namespace, 'definitions') DocumentationName = XSD::QName.new(Namespace, 'documentation') FaultName = XSD::QName.new(Namespace, 'fault') ImportName = XSD::QName.new(Namespace, 'import') InputName = XSD::QName.new(Namespace, 'input') MessageName = XSD::QName.new(Namespace, 'message') OperationName = XSD::QName.new(Namespace, 'operation') OutputName = XSD::QName.new(Namespace, 'output') PartName = XSD::QName.new(Namespace, 'part') PortName = XSD::QName.new(Namespace, 'port') PortTypeName = XSD::QName.new(Namespace, 'portType') ServiceName = XSD::QName.new(Namespace, 'service') TypesName = XSD::QName.new(Namespace, 'types') SchemaName = XSD::QName.new(XSD::Namespace, 'schema') SOAPAddressName = XSD::QName.new(SOAPBindingNamespace, 'address') SOAPBindingName = XSD::QName.new(SOAPBindingNamespace, 'binding') SOAPHeaderName = XSD::QName.new(SOAPBindingNamespace, 'header') SOAPBodyName = XSD::QName.new(SOAPBindingNamespace, 'body') SOAPFaultName = XSD::QName.new(SOAPBindingNamespace, 'fault') SOAPOperationName = XSD::QName.new(SOAPBindingNamespace, 'operation') BindingAttrName = XSD::QName.new(nil, 'binding') ElementAttrName = XSD::QName.new(nil, 'element') LocationAttrName = XSD::QName.new(nil, 'location') MessageAttrName = XSD::QName.new(nil, 'message') NameAttrName = XSD::QName.new(nil, 'name') NamespaceAttrName = XSD::QName.new(nil, 'namespace') ParameterOrderAttrName = XSD::QName.new(nil, 'parameterOrder') TargetNamespaceAttrName = XSD::QName.new(nil, 'targetNamespace') TypeAttrName = XSD::QName.new(nil, 'type') end ================================================ FILE: lib/wsdl/definitions.rb ================================================ # WSDL4R - WSDL definitions. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL class Definitions < Info attr_reader :name attr_reader :targetnamespace attr_reader :imports attr_accessor :location attr_reader :importedschema def initialize super @name = nil @targetnamespace = nil @location = nil @importedschema = {} @types = nil @imports = [] @messages = XSD::NamedElements.new @porttypes = XSD::NamedElements.new @bindings = XSD::NamedElements.new @services = XSD::NamedElements.new @anontypes = XSD::NamedElements.new @root = self end def inspect sprintf("#<%s:0x%x %s>", self.class.name, __id__, @name || '(unnamed)') end def targetnamespace=(targetnamespace) @targetnamespace = targetnamespace if @name @name = XSD::QName.new(@targetnamespace, @name.name) end end def collect_attributes result = XSD::NamedElements.new if @types @types.schemas.each do |schema| result.concat(schema.collect_attributes) end end @imports.each do |import| result.concat(import.content.collect_attributes) end result end def collect_elements result = XSD::NamedElements.new if @types @types.schemas.each do |schema| result.concat(schema.collect_elements) end end @imports.each do |import| result.concat(import.content.collect_elements) end result end def collect_complextypes result = @anontypes.dup if @types @types.schemas.each do |schema| result.concat(schema.collect_complextypes) end end @imports.each do |import| result.concat(import.content.collect_complextypes) end result end def collect_simpletypes result = XSD::NamedElements.new if @types @types.schemas.each do |schema| result.concat(schema.collect_simpletypes) end end @imports.each do |import| result.concat(import.content.collect_simpletypes) end result end # ToDo: simpletype must be accepted... def add_type(complextype) @anontypes << complextype end def messages result = @messages.dup @imports.each do |import| result.concat(import.content.messages) if self.class === import.content end result end def porttypes result = @porttypes.dup @imports.each do |import| result.concat(import.content.porttypes) if self.class === import.content end result end def bindings result = @bindings.dup @imports.each do |import| result.concat(import.content.bindings) if self.class === import.content end result end def services result = @services.dup @imports.each do |import| result.concat(import.content.services) if self.class === import.content end result end def message(name) message = @messages[name] return message if message @imports.each do |import| message = import.content.message(name) if self.class === import.content return message if message end nil end def porttype(name) porttype = @porttypes[name] return porttype if porttype @imports.each do |import| porttype = import.content.porttype(name) if self.class === import.content return porttype if porttype end nil end def binding(name) binding = @bindings[name] return binding if binding @imports.each do |import| binding = import.content.binding(name) if self.class === import.content return binding if binding end nil end def service(name) service = @services[name] return service if service @imports.each do |import| service = import.content.service(name) if self.class === import.content return service if service end nil end def porttype_binding(name) binding = @bindings.find { |item| item.type == name } return binding if binding @imports.each do |import| binding = import.content.porttype_binding(name) if self.class === import.content return binding if binding end nil end def parse_element(element) case element when ImportName o = Import.new @imports << o o when TypesName o = Types.new @types = o o when MessageName o = Message.new @messages << o o when PortTypeName o = PortType.new @porttypes << o o when BindingName o = Binding.new @bindings << o o when ServiceName o = Service.new @services << o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) when TargetNamespaceAttrName self.targetnamespace = value.source else nil end end def self.parse_element(element) if element == DefinitionsName Definitions.new else nil end end private end end ================================================ FILE: lib/wsdl/documentation.rb ================================================ # WSDL4R - WSDL SOAP documentation element. # Copyright (C) 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL class Documentation < Info def initialize super end def parse_element(element) # Accepts any element. self end def parse_attr(attr, value) # Accepts any attribute. true end end end ================================================ FILE: lib/wsdl/import.rb ================================================ # WSDL4R - WSDL import definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/importer' module WSDL class Import < Info attr_reader :namespace attr_reader :location attr_reader :content def initialize super @namespace = nil @location = nil @content = nil @web_client = nil end def parse_element(element) case element when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NamespaceAttrName @namespace = value.source if @content @content.targetnamespace = @namespace end @namespace when LocationAttrName @location = URI.parse(value.source) if @location.relative? and !parent.location.nil? and !parent.location.relative? @location = parent.location + @location end if root.importedschema.key?(@location) @content = root.importedschema[@location] else root.importedschema[@location] = nil # placeholder @content = import(@location) if @content.is_a?(Definitions) @content.root = root if @namespace @content.targetnamespace = @namespace end end root.importedschema[@location] = @content end @location else nil end end private def import(location) Importer.import(location, root) end end end ================================================ FILE: lib/wsdl/importer.rb ================================================ # WSDL4R - WSDL importer library. # Copyright (C) 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/xmlSchema/importer' require 'wsdl/parser' module WSDL class Importer < WSDL::XMLSchema::Importer def self.import(location, originalroot = nil) new.import(location, originalroot) end private def parse(content, location, originalroot) opt = { :location => location, :originalroot => originalroot } begin WSDL::Parser.new(opt).parse(content) rescue WSDL::Parser::ParseError super(content, location, originalroot) end end end end ================================================ FILE: lib/wsdl/info.rb ================================================ # WSDL4R - WSDL information base. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module WSDL class Info attr_accessor :root attr_accessor :parent attr_accessor :id def initialize @root = nil @parent = nil @id = nil end def inspect if self.respond_to?(:name) sprintf("#<%s:0x%x %s>", self.class.name, __id__, self.name) else sprintf("#<%s:0x%x>", self.class.name, __id__) end end def parse_element(element); end # abstract def parse_attr(attr, value); end # abstract def parse_epilogue; end # abstract end end ================================================ FILE: lib/wsdl/message.rb ================================================ # WSDL4R - WSDL message definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL class Message < Info attr_reader :name # required attr_reader :parts def initialize super @name = nil @parts = [] end def targetnamespace parent.targetnamespace end def parse_element(element) case element when PartName o = Part.new @parts << o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(parent.targetnamespace, value.source) else nil end end end end ================================================ FILE: lib/wsdl/operation.rb ================================================ # WSDL4R - WSDL operation definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL class Operation < Info class NameInfo attr_reader :op_name attr_reader :optype_name attr_reader :parts def initialize(op_name, optype_name, parts) @op_name = op_name @optype_name = optype_name @parts = parts end end attr_reader :name # required attr_reader :parameter_order # optional attr_reader :input attr_reader :output attr_reader :fault attr_reader :type # required def initialize super @name = nil @type = nil @parameter_order = nil @input = nil @output = nil @fault = [] end def targetnamespace parent.targetnamespace end def input_info typename = input.find_message.name NameInfo.new(@name, typename, inputparts) end def output_info typename = output.find_message.name NameInfo.new(@name, typename, outputparts) end def inputparts sort_parts(input.find_message.parts) end def inputname XSD::QName.new(targetnamespace, input.name ? input.name.name : @name.name) end def outputparts sort_parts(output.find_message.parts) end def outputname XSD::QName.new(targetnamespace, output.name ? output.name.name : @name.name + 'Response') end def parse_element(element) case element when InputName o = Param.new @input = o o when OutputName o = Param.new @output = o o when FaultName o = Param.new @fault << o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) when TypeAttrName @type = value when ParameterOrderAttrName @parameter_order = value.source.split(/\s+/) else nil end end private def sort_parts(parts) return parts.dup unless parameter_order result = [] parameter_order.each do |orderitem| if (ele = parts.find { |part| part.name == orderitem }) result << ele end end if result.length == 0 return parts.dup end # result length can be shorter than parts's. # return part must not be a part of the parameterOrder. result end end end ================================================ FILE: lib/wsdl/operationBinding.rb ================================================ # WSDL4R - WSDL bound operation definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL class OperationBinding < Info attr_reader :name # required attr_reader :input attr_reader :output attr_reader :fault attr_reader :soapoperation def initialize super @name = nil @input = nil @output = nil @fault = [] @soapoperation = nil end def targetnamespace parent.targetnamespace end def porttype root.porttype(parent.type) end def find_operation porttype.operations[@name] or raise RuntimeError.new("#{@name} not found") end def soapoperation_name if @soapoperation @soapoperation.input_info.op_name else find_operation.name end end def soapoperation_style style = nil if @soapoperation style = @soapoperation.operation_style elsif parent.soapbinding style = parent.soapbinding.style else raise TypeError.new("operation style definition not found") end style || :document end def soapaction if @soapoperation @soapoperation.soapaction else nil end end def parse_element(element) case element when InputName o = Param.new @input = o o when OutputName o = Param.new @output = o o when FaultName o = Param.new @fault << o o when SOAPOperationName o = WSDL::SOAP::Operation.new @soapoperation = o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) else nil end end end end ================================================ FILE: lib/wsdl/param.rb ================================================ # WSDL4R - WSDL param definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL class Param < Info attr_reader :message # required attr_reader :name # optional but required for fault. attr_reader :soapbody attr_reader :soapheader attr_reader :soapfault def initialize super @message = nil @name = nil @soapbody = nil @soapheader = [] @soapfault = nil end def targetnamespace parent.targetnamespace end def find_message root.message(@message) or raise RuntimeError.new("#{@message} not found") end def soapbody_use if @soapbody @soapbody.use || :literal else raise RuntimeError.new("soap:body not found") end end def parse_element(element) case element when SOAPBodyName o = WSDL::SOAP::Body.new @soapbody = o o when SOAPHeaderName o = WSDL::SOAP::Header.new @soapheader << o o when SOAPFaultName o = WSDL::SOAP::Fault.new @soap_fault = o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when MessageAttrName if value.namespace.nil? value = XSD::QName.new(targetnamespace, value.source) end @message = value when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) else nil end end end end ================================================ FILE: lib/wsdl/parser.rb ================================================ # WSDL4R - WSDL XML Instance parser library. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' require 'xsd/ns' require 'xsd/charset' require 'xsd/datatypes' require 'xsd/xmlparser' require 'wsdl/wsdl' require 'wsdl/data' require 'wsdl/xmlSchema/data' require 'wsdl/soap/data' module WSDL class Parser include WSDL class ParseError < Error; end class FormatDecodeError < ParseError; end class UnknownElementError < FormatDecodeError; end class UnknownAttributeError < FormatDecodeError; end class UnexpectedElementError < FormatDecodeError; end class ElementConstraintError < FormatDecodeError; end class AttributeConstraintError < FormatDecodeError; end private class ParseFrame attr_reader :ns attr_reader :name attr_accessor :node private def initialize(ns, name, node) @ns = ns @name = name @node = node end end public def initialize(opt = {}) @parser = XSD::XMLParser.create_parser(self, opt) @parsestack = nil @lastnode = nil @ignored = {} @location = opt[:location] @originalroot = opt[:originalroot] end def parse(string_or_readable) @parsestack = [] @lastnode = nil @textbuf = '' @parser.do_parse(string_or_readable) @lastnode end def charset @parser.charset end def start_element(name, attrs) lastframe = @parsestack.last ns = parent = nil if lastframe ns = lastframe.ns.clone_ns parent = lastframe.node else ns = XSD::NS.new parent = nil end attrs = XSD::XMLParser.filter_ns(ns, attrs) node = decode_tag(ns, name, attrs, parent) @parsestack << ParseFrame.new(ns, name, node) end def characters(text) lastframe = @parsestack.last if lastframe # Need not to be cloned because character does not have attr. ns = lastframe.ns decode_text(ns, text) else p text if $DEBUG end end def end_element(name) lastframe = @parsestack.pop unless name == lastframe.name raise UnexpectedElementError.new("closing element name '#{name}' does not match with opening element '#{lastframe.name}'") end decode_tag_end(lastframe.ns, lastframe.node) @lastnode = lastframe.node end private def decode_tag(ns, name, attrs, parent) o = nil elename = ns.parse(name) if !parent if elename == DefinitionsName o = Definitions.parse_element(elename) o.location = @location else raise UnknownElementError.new("unknown element: #{elename}") end o.root = @originalroot if @originalroot # o.root = o otherwise else if elename == XMLSchema::AnnotationName # only the first annotation element is allowed for each xsd element. o = XMLSchema::Annotation.new else o = parent.parse_element(elename) end unless o unless @ignored.key?(elename) warn("ignored element: #{elename}") @ignored[elename] = elename end o = Documentation.new # which accepts any element. end # node could be a pseudo element. pseudo element has its own parent. o.root = parent.root o.parent = parent if o.parent.nil? end attrs.each do |key, value| attr_ele = ns.parse(key, true) value_ele = ns.parse(value, true) value_ele.source = value # for recovery; value may not be a QName unless o.parse_attr(attr_ele, value_ele) unless @ignored.key?(attr_ele) warn("ignored attr: #{attr_ele}") @ignored[attr_ele] = attr_ele end end end o end def decode_tag_end(ns, node) node.parse_epilogue end def decode_text(ns, text) @textbuf << text end end end ================================================ FILE: lib/wsdl/part.rb ================================================ # WSDL4R - WSDL part definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL class Part < Info attr_reader :name # required attr_reader :element # optional attr_reader :type # optional def initialize super @name = nil @element = nil @type = nil end def parse_element(element) case element when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NameAttrName @name = value.source when ElementAttrName @element = value when TypeAttrName @type = value else nil end end end end ================================================ FILE: lib/wsdl/port.rb ================================================ # WSDL4R - WSDL port definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL class Port < Info attr_reader :name # required attr_reader :binding # required attr_reader :soap_address def initialize super @name = nil @binding = nil @soap_address = nil end def targetnamespace parent.targetnamespace end def porttype root.porttype(find_binding.type) end def find_binding root.binding(@binding) or raise RuntimeError.new("#{@binding} not found") end def inputoperation_map result = {} find_binding.operations.each do |op_bind| op_info = op_bind.soapoperation.input_info result[op_info.op_name] = op_info end result end def outputoperation_map result = {} find_binding.operations.each do |op_bind| op_info = op_bind.soapoperation.output_info result[op_info.op_name] = op_info end result end def parse_element(element) case element when SOAPAddressName o = WSDL::SOAP::Address.new @soap_address = o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) when BindingAttrName @binding = value else nil end end end end ================================================ FILE: lib/wsdl/portType.rb ================================================ # WSDL4R - WSDL portType definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL class PortType < Info attr_reader :name # required attr_reader :operations def targetnamespace parent.targetnamespace end def initialize super @name = nil @operations = XSD::NamedElements.new end def find_binding root.bindings.find { |item| item.type == @name } or raise RuntimeError.new("#{@name} not found") end def locations bind_name = find_binding.name result = [] root.services.each do |service| service.ports.each do |port| if port.binding == bind_name result << port.soap_address.location if port.soap_address end end end result end def parse_element(element) case element when OperationName o = Operation.new @operations << o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) else nil end end end end ================================================ FILE: lib/wsdl/service.rb ================================================ # WSDL4R - WSDL service definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL class Service < Info attr_reader :name # required attr_reader :ports attr_reader :soap_address def initialize super @name = nil @ports = XSD::NamedElements.new @soap_address = nil end def targetnamespace parent.targetnamespace end def parse_element(element) case element when PortName o = Port.new @ports << o o when SOAPAddressName o = WSDL::SOAP::Address.new @soap_address = o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) else nil end end end end ================================================ FILE: lib/wsdl/soap/address.rb ================================================ # WSDL4R - WSDL SOAP address definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module SOAP class Address < Info attr_reader :location def initialize super @location = nil end def parse_element(element) nil end def parse_attr(attr, value) case attr when LocationAttrName @location = value.source else nil end end end end end ================================================ FILE: lib/wsdl/soap/binding.rb ================================================ # WSDL4R - WSDL SOAP binding definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module SOAP class Binding < Info attr_reader :style attr_reader :transport def initialize super @style = nil @transport = nil end def parse_element(element) nil end def parse_attr(attr, value) case attr when StyleAttrName if ["document", "rpc"].include?(value.source) @style = value.source.intern else raise Parser::AttributeConstraintError.new( "Unexpected value #{ value }.") end when TransportAttrName @transport = value.source else nil end end end end end ================================================ FILE: lib/wsdl/soap/body.rb ================================================ # WSDL4R - WSDL SOAP body definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module SOAP class Body < Info attr_reader :parts attr_reader :use # required attr_reader :encodingstyle attr_reader :namespace def initialize super @parts = nil @use = nil @encodingstyle = nil @namespace = nil end def parse_element(element) nil end def parse_attr(attr, value) case attr when PartsAttrName @parts = value.source when UseAttrName if ['literal', 'encoded'].include?(value.source) @use = value.source.intern else raise RuntimeError.new("unknown use of soap:body: #{value.source}") end when EncodingStyleAttrName @encodingstyle = value.source when NamespaceAttrName @namespace = value.source else nil end end end end end ================================================ FILE: lib/wsdl/soap/cgiStubCreator.rb ================================================ # WSDL4R - Creating CGI stub code from WSDL. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/soap/mappingRegistryCreator' require 'wsdl/soap/methodDefCreator' require 'wsdl/soap/classDefCreatorSupport' module WSDL module SOAP class CGIStubCreator include ClassDefCreatorSupport attr_reader :definitions def initialize(definitions) @definitions = definitions end def dump(service_name) warn("CGI stub can have only 1 port. Creating stub for the first port... Rests are ignored.") port = @definitions.service(service_name).ports[0] dump_porttype(port.porttype.name) end private def dump_porttype(name) class_name = create_class_name(name) methoddef, types = MethodDefCreator.new(@definitions).dump(name) mr_creator = MappingRegistryCreator.new(@definitions) c1 = XSD::CodeGen::ClassDef.new(class_name) c1.def_require("soap/rpc/cgistub") c1.def_require("soap/mapping/registry") c1.def_const("MappingRegistry", "::SOAP::Mapping::Registry.new") c1.def_code(mr_creator.dump(types)) c1.def_code <<-EOD Methods = [ #{methoddef.gsub(/^/, " ")} ] EOD c2 = XSD::CodeGen::ClassDef.new(class_name + "App", "::SOAP::RPC::CGIStub") c2.def_method("initialize", "*arg") do <<-EOD super(*arg) servant = #{class_name}.new #{class_name}::Methods.each do |definitions| opt = definitions.last if opt[:request_style] == :document @router.add_document_operation(servant, *definitions) else @router.add_rpc_operation(servant, *definitions) end end self.mapping_registry = #{class_name}::MappingRegistry self.level = Logger::Severity::ERROR EOD end c1.dump + "\n" + c2.dump + format(<<-EOD) #{class_name}App.new('app', nil).start EOD end end end end ================================================ FILE: lib/wsdl/soap/classDefCreator.rb ================================================ # WSDL4R - Creating class definition from WSDL # Copyright (C) 2002, 2003, 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/data' require 'wsdl/soap/classDefCreatorSupport' require 'xsd/codegen' module WSDL module SOAP class ClassDefCreator include ClassDefCreatorSupport def initialize(definitions) @elements = definitions.collect_elements @simpletypes = definitions.collect_simpletypes @complextypes = definitions.collect_complextypes @faulttypes = nil if definitions.respond_to?(:collect_faulttypes) @faulttypes = definitions.collect_faulttypes end end def dump(type = nil) result = "require 'xsd/qname'\n" if type result = dump_classdef(type.name, type) else str = dump_element unless str.empty? result << "\n" unless result.empty? result << str end str = dump_complextype unless str.empty? result << "\n" unless result.empty? result << str end str = dump_simpletype unless str.empty? result << "\n" unless result.empty? result << str end end result end private def dump_element @elements.collect { |ele| if ele.local_complextype dump_classdef(ele.name, ele.local_complextype, ele.elementform == 'qualified') elsif ele.local_simpletype dump_simpletypedef(ele.name, ele.local_simpletype) else nil end }.compact.join("\n") end def dump_simpletype @simpletypes.collect { |type| dump_simpletypedef(type.name, type) }.compact.join("\n") end def dump_complextype @complextypes.collect { |type| case type.compoundtype when :TYPE_STRUCT, :TYPE_EMPTY dump_classdef(type.name, type) when :TYPE_ARRAY dump_arraydef(type) when :TYPE_SIMPLE dump_simpleclassdef(type) when :TYPE_MAP # mapped as a general Hash nil else raise RuntimeError.new( "unknown kind of complexContent: #{type.compoundtype}") end }.compact.join("\n") end def dump_simpletypedef(qname, simpletype) if !simpletype.restriction or simpletype.restriction.enumeration.empty? return nil end c = XSD::CodeGen::ModuleDef.new(create_class_name(qname)) c.comment = "#{qname}" const = {} simpletype.restriction.enumeration.each do |value| constname = safeconstname(value) const[constname] ||= 0 if (const[constname] += 1) > 1 constname += "_#{const[constname]}" end c.def_const(constname, ndq(value)) end c.dump end def dump_simpleclassdef(type_or_element) qname = type_or_element.name base = create_class_name(type_or_element.simplecontent.base) c = XSD::CodeGen::ClassDef.new(create_class_name(qname), base) c.comment = "#{qname}" c.dump end def dump_classdef(qname, typedef, qualified = false) if @faulttypes and @faulttypes.index(qname) c = XSD::CodeGen::ClassDef.new(create_class_name(qname), '::StandardError') else c = XSD::CodeGen::ClassDef.new(create_class_name(qname)) end c.comment = "#{qname}" c.def_classvar('schema_type', ndq(qname.name)) c.def_classvar('schema_ns', ndq(qname.namespace)) c.def_classvar('schema_qualified', dq('true')) if qualified schema_element = [] init_lines = '' params = [] typedef.each_element do |element| if element.type == XSD::AnyTypeName type = nil elsif klass = element_basetype(element) type = klass.name elsif element.type type = create_class_name(element.type) else type = nil # means anyType. # do we define a class for local complexType from it's name? # type = create_class_name(element.name) # # # # # end name = name_element(element).name attrname = safemethodname?(name) ? name : safemethodname(name) varname = safevarname(name) c.def_attr(attrname, true, varname) init_lines << "@#{varname} = #{varname}\n" if element.map_as_array? params << "#{varname} = []" type << '[]' if type else params << "#{varname} = nil" end # nil means @@schema_ns + varname eleqname = (varname == name && element.name.namespace == qname.namespace) ? nil : element.name schema_element << [varname, eleqname, type] end unless typedef.attributes.empty? define_attribute(c, typedef.attributes) init_lines << "@__xmlattr = {}\n" end c.def_classvar('schema_element', '[' + schema_element.collect { |varname, name, type| '[' + ( if name varname.dump + ', [' + ndq(type) + ', ' + dqname(name) + ']' else varname.dump + ', ' + ndq(type) end ) + ']' }.join(', ') + ']' ) c.def_method('initialize', *params) do init_lines end c.dump end def element_basetype(ele) if klass = basetype_class(ele.type) klass elsif ele.local_simpletype basetype_class(ele.local_simpletype.base) else nil end end def attribute_basetype(attr) if klass = basetype_class(attr.type) klass elsif attr.local_simpletype basetype_class(attr.local_simpletype.base) else nil end end def basetype_class(type) return nil if type.nil? if simpletype = @simpletypes[type] basetype_mapped_class(simpletype.base) else basetype_mapped_class(type) end end def define_attribute(c, attributes) schema_attribute = [] attributes.each do |attribute| name = name_attribute(attribute) if klass = attribute_basetype(attribute) type = klass.name else type = nil end methodname = safemethodname('xmlattr_' + name.name) c.def_method(methodname) do <<-__EOD__ (@__xmlattr ||= {})[#{dqname(name)}] __EOD__ end c.def_method(methodname + '=', 'value') do <<-__EOD__ (@__xmlattr ||= {})[#{dqname(name)}] = value __EOD__ end schema_attribute << [name, type] end c.def_classvar('schema_attribute', '{' + schema_attribute.collect { |name, type| dqname(name) + ' => ' + ndq(type) }.join(', ') + '}' ) end def name_element(element) return element.name if element.name return element.ref if element.ref raise RuntimeError.new("cannot define name of #{element}") end def name_attribute(attribute) return attribute.name if attribute.name return attribute.ref if attribute.ref raise RuntimeError.new("cannot define name of #{attribute}") end DEFAULT_ITEM_NAME = XSD::QName.new(nil, 'item') def dump_arraydef(complextype) qname = complextype.name c = XSD::CodeGen::ClassDef.new(create_class_name(qname), '::Array') c.comment = "#{qname}" child_type = complextype.child_type c.def_classvar('schema_type', ndq(child_type.name)) c.def_classvar('schema_ns', ndq(child_type.namespace)) child_element = complextype.find_aryelement schema_element = [] if child_type == XSD::AnyTypeName type = nil elsif child_element and (klass = element_basetype(child_element)) type = klass.name elsif child_type type = create_class_name(child_type) else type = nil end if child_element if child_element.map_as_array? type << '[]' if type end child_element_name = child_element.name else child_element_name = DEFAULT_ITEM_NAME end schema_element << [child_element_name.name, child_element_name, type] c.def_classvar('schema_element', '[' + schema_element.collect { |varname, name, type| '[' + ( if name varname.dump + ', [' + ndq(type) + ', ' + dqname(name) + ']' else varname.dump + ', ' + ndq(type) end ) + ']' }.join(', ') + ']' ) c.dump end end end end ================================================ FILE: lib/wsdl/soap/classDefCreatorSupport.rb ================================================ # WSDL4R - Creating class code support from WSDL. # Copyright (C) 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'soap/mapping' require 'soap/mapping/typeMap' require 'xsd/codegen/gensupport' module WSDL module SOAP module ClassDefCreatorSupport include XSD::CodeGen::GenSupport def create_class_name(qname) if klass = basetype_mapped_class(qname) ::SOAP::Mapping::DefaultRegistry.find_mapped_obj_class(klass).name else safeconstname(qname.name) end end def basetype_mapped_class(name) ::SOAP::TypeMap[name] end def dump_method_signature(operation) name = operation.name.name input = operation.input output = operation.output fault = operation.fault signature = "#{ name }#{ dump_inputparam(input) }" str = <<__EOD__ # SYNOPSIS # #{name}#{dump_inputparam(input)} # # ARGS #{dump_inout_type(input).chomp} # # RETURNS #{dump_inout_type(output).chomp} # __EOD__ unless fault.empty? faultstr = (fault.collect { |f| dump_inout_type(f).chomp }).join(', ') str <<<<__EOD__ # RAISES # #{faultstr} # __EOD__ end str end def dq(ele) ele.dump end def ndq(ele) ele.nil? ? 'nil' : dq(ele) end def sym(ele) ':' + ele end def dqname(qname) qname.dump end private def dump_inout_type(param) if param message = param.find_message params = "" message.parts.each do |part| name = safevarname(part.name) if part.type typename = safeconstname(part.type.name) params << add_at("# #{name}", "#{typename} - #{part.type}\n", 20) elsif part.element typename = safeconstname(part.element.name) params << add_at("# #{name}", "#{typename} - #{part.element}\n", 20) end end unless params.empty? return params end end "# N/A\n" end def dump_inputparam(input) message = input.find_message params = "" message.parts.each do |part| params << ", " unless params.empty? params << safevarname(part.name) end if params.empty? "" else "(#{ params })" end end def add_at(base, str, pos) if base.size >= pos base + ' ' + str else base + ' ' * (pos - base.size) + str end end end end end ================================================ FILE: lib/wsdl/soap/clientSkeltonCreator.rb ================================================ # WSDL4R - Creating client skelton code from WSDL. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/soap/classDefCreatorSupport' module WSDL module SOAP class ClientSkeltonCreator include ClassDefCreatorSupport attr_reader :definitions def initialize(definitions) @definitions = definitions end def dump(service_name) result = "" @definitions.service(service_name).ports.each do |port| result << dump_porttype(port.porttype.name) result << "\n" end result end private def dump_porttype(name) drv_name = create_class_name(name) result = "" result << <<__EOD__ endpoint_url = ARGV.shift obj = #{ drv_name }.new(endpoint_url) # run ruby with -d to see SOAP wiredumps. obj.wiredump_dev = STDERR if $DEBUG __EOD__ @definitions.porttype(name).operations.each do |operation| result << dump_method_signature(operation) result << dump_input_init(operation.input) << "\n" result << dump_operation(operation) << "\n\n" end result end def dump_operation(operation) name = operation.name input = operation.input "puts obj.#{ safemethodname(name.name) }#{ dump_inputparam(input) }" end def dump_input_init(input) result = input.find_message.parts.collect { |part| safevarname(part.name) }.join(" = ") if result.empty? "" else result << " = nil" end result end end end end ================================================ FILE: lib/wsdl/soap/complexType.rb ================================================ # WSDL4R - SOAP complexType definition for WSDL. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/xmlSchema/complexType' require 'soap/mapping' module WSDL module XMLSchema class ComplexType < Info def compoundtype @compoundtype ||= check_type end def check_type if content if attributes.empty? and content.elements.size == 1 and content.elements[0].maxoccurs != '1' if name == ::SOAP::Mapping::MapQName :TYPE_MAP else :TYPE_ARRAY end else :TYPE_STRUCT end elsif complexcontent if complexcontent.base == ::SOAP::ValueArrayName :TYPE_ARRAY else complexcontent.basetype.check_type end elsif simplecontent :TYPE_SIMPLE elsif !attributes.empty? :TYPE_STRUCT else # empty complexType definition (seen in partner.wsdl of salesforce) :TYPE_EMPTY end end def child_type(name = nil) case compoundtype when :TYPE_STRUCT if ele = find_element(name) ele.type elsif ele = find_element_by_name(name.name) ele.type end when :TYPE_ARRAY @contenttype ||= content_arytype when :TYPE_MAP item_ele = find_element_by_name("item") or raise RuntimeError.new("'item' element not found in Map definition.") content = item_ele.local_complextype or raise RuntimeError.new("No complexType definition for 'item'.") if ele = content.find_element(name) ele.type elsif ele = content.find_element_by_name(name.name) ele.type end else raise NotImplementedError.new("Unknown kind of complexType.") end end def child_defined_complextype(name) ele = nil case compoundtype when :TYPE_STRUCT, :TYPE_MAP unless ele = find_element(name) if name.namespace.nil? ele = find_element_by_name(name.name) end end when :TYPE_ARRAY if content.elements.size == 1 ele = content.elements[0] else raise RuntimeError.new("Assert: must not reach.") end else raise RuntimeError.new("Assert: Not implemented.") end unless ele raise RuntimeError.new("Cannot find #{name} as a children of #{@name}.") end ele.local_complextype end def find_arytype unless compoundtype == :TYPE_ARRAY raise RuntimeError.new("Assert: not for array") end if complexcontent complexcontent.attributes.each do |attribute| if attribute.ref == ::SOAP::AttrArrayTypeName return attribute.arytype end end if check_array_content(complexcontent.content) return element_simpletype(complexcontent.content.elements[0]) end elsif check_array_content(content) return element_simpletype(content.elements[0]) end raise RuntimeError.new("Assert: Unknown array definition.") end def find_aryelement unless compoundtype == :TYPE_ARRAY raise RuntimeError.new("Assert: not for array") end if complexcontent if check_array_content(complexcontent.content) return complexcontent.content.elements[0] end elsif check_array_content(content) return content.elements[0] end nil # use default item name end private def element_simpletype(element) if element.type element.type elsif element.local_simpletype element.local_simpletype.base else nil end end def check_array_content(content) content and content.elements.size == 1 and content.elements[0].maxoccurs != '1' end def content_arytype if arytype = find_arytype ns = arytype.namespace name = arytype.name.sub(/\[(?:,)*\]$/, '') XSD::QName.new(ns, name) else nil end end end end end ================================================ FILE: lib/wsdl/soap/data.rb ================================================ # WSDL4R - WSDL SOAP binding data definitions. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' require 'wsdl/soap/definitions' require 'wsdl/soap/binding' require 'wsdl/soap/operation' require 'wsdl/soap/body' require 'wsdl/soap/element' require 'wsdl/soap/header' require 'wsdl/soap/headerfault' require 'wsdl/soap/fault' require 'wsdl/soap/address' require 'wsdl/soap/complexType' module WSDL module SOAP HeaderFaultName = XSD::QName.new(SOAPBindingNamespace, 'headerfault') LocationAttrName = XSD::QName.new(nil, 'location') StyleAttrName = XSD::QName.new(nil, 'style') TransportAttrName = XSD::QName.new(nil, 'transport') UseAttrName = XSD::QName.new(nil, 'use') PartsAttrName = XSD::QName.new(nil, 'parts') PartAttrName = XSD::QName.new(nil, 'part') NameAttrName = XSD::QName.new(nil, 'name') MessageAttrName = XSD::QName.new(nil, 'message') EncodingStyleAttrName = XSD::QName.new(nil, 'encodingStyle') NamespaceAttrName = XSD::QName.new(nil, 'namespace') SOAPActionAttrName = XSD::QName.new(nil, 'soapAction') end end ================================================ FILE: lib/wsdl/soap/definitions.rb ================================================ # WSDL4R - WSDL additional definitions for SOAP. # Copyright (C) 2002-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' require 'soap/mapping' module WSDL class Definitions < Info def self.soap_rpc_complextypes types = XSD::NamedElements.new types << array_complextype types << fault_complextype types << exception_complextype types end def self.array_complextype type = XMLSchema::ComplexType.new(::SOAP::ValueArrayName) type.complexcontent = XMLSchema::ComplexContent.new type.complexcontent.base = ::SOAP::ValueArrayName attr = XMLSchema::Attribute.new attr.ref = ::SOAP::AttrArrayTypeName anytype = XSD::AnyTypeName.dup anytype.name += '[]' attr.arytype = anytype type.complexcontent.attributes << attr type end =begin =end def self.fault_complextype type = XMLSchema::ComplexType.new(::SOAP::EleFaultName) faultcode = XMLSchema::Element.new(::SOAP::EleFaultCodeName, XSD::XSDQName::Type) faultstring = XMLSchema::Element.new(::SOAP::EleFaultStringName, XSD::XSDString::Type) faultactor = XMLSchema::Element.new(::SOAP::EleFaultActorName, XSD::XSDAnyURI::Type) faultactor.minoccurs = 0 detail = XMLSchema::Element.new(::SOAP::EleFaultDetailName, XSD::AnyTypeName) detail.minoccurs = 0 type.all_elements = [faultcode, faultstring, faultactor, detail] type.final = 'extension' type end def self.exception_complextype type = XMLSchema::ComplexType.new(XSD::QName.new( ::SOAP::Mapping::RubyCustomTypeNamespace, 'SOAPException')) excn_name = XMLSchema::Element.new(XSD::QName.new(nil, 'excn_type_name'), XSD::XSDString::Type) cause = XMLSchema::Element.new(XSD::QName.new(nil, 'cause'), XSD::AnyTypeName) backtrace = XMLSchema::Element.new(XSD::QName.new(nil, 'backtrace'), ::SOAP::ValueArrayName) message = XMLSchema::Element.new(XSD::QName.new(nil, 'message'), XSD::XSDString::Type) type.all_elements = [excn_name, cause, backtrace, message] type end def soap_rpc_complextypes(binding) types = rpc_operation_complextypes(binding) types + self.class.soap_rpc_complextypes end def collect_faulttypes result = [] collect_fault_messages.each do |name| faultparts = message(name).parts if faultparts.size != 1 raise RuntimeError.new("expecting fault message to have only 1 part") end if result.index(faultparts[0].type).nil? result << faultparts[0].type end end result end private def collect_fault_messages result = [] porttypes.each do |porttype| porttype.operations.each do |operation| operation.fault.each do |fault| if result.index(fault.message).nil? result << fault.message end end end end result end def rpc_operation_complextypes(binding) types = XSD::NamedElements.new binding.operations.each do |op_bind| if op_bind_rpc?(op_bind) operation = op_bind.find_operation if op_bind.input type = XMLSchema::ComplexType.new(op_bind.soapoperation_name) message = messages[operation.input.message] type.sequence_elements = elements_from_message(message) types << type end if op_bind.output type = XMLSchema::ComplexType.new(operation.outputname) message = messages[operation.output.message] type.sequence_elements = elements_from_message(message) types << type end end end types end def op_bind_rpc?(op_bind) op_bind.soapoperation_style == :rpc end def elements_from_message(message) message.parts.collect { |part| if part.element collect_elements[part.element] elsif part.name.nil? or part.type.nil? raise RuntimeError.new("part of a message must be an element or typed") else qname = XSD::QName.new(nil, part.name) XMLSchema::Element.new(qname, part.type) end } end end end ================================================ FILE: lib/wsdl/soap/driverCreator.rb ================================================ # WSDL4R - Creating driver code from WSDL. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/soap/mappingRegistryCreator' require 'wsdl/soap/methodDefCreator' require 'wsdl/soap/classDefCreatorSupport' require 'xsd/codegen' module WSDL module SOAP class DriverCreator include ClassDefCreatorSupport attr_reader :definitions def initialize(definitions) @definitions = definitions end def dump(porttype = nil) if porttype.nil? result = "" @definitions.porttypes.each do |type| result << dump_porttype(type.name) result << "\n" end else result = dump_porttype(porttype) end result end private def dump_porttype(name) class_name = create_class_name(name) methoddef, types = MethodDefCreator.new(@definitions).dump(name) mr_creator = MappingRegistryCreator.new(@definitions) binding = @definitions.bindings.find { |item| item.type == name } return '' unless binding.soapbinding # not a SOAP binding address = @definitions.porttype(name).locations[0] c = XSD::CodeGen::ClassDef.new(class_name, "::SOAP::RPC::Driver") c.def_require("soap/rpc/driver") c.def_const("MappingRegistry", "::SOAP::Mapping::Registry.new") c.def_const("DefaultEndpointUrl", ndq(address)) c.def_code(mr_creator.dump(types)) c.def_code <<-EOD Methods = [ #{methoddef.gsub(/^/, " ")} ] EOD c.def_method("initialize", "endpoint_url = nil") do <<-EOD endpoint_url ||= DefaultEndpointUrl super(endpoint_url, nil) self.mapping_registry = MappingRegistry init_methods EOD end c.def_privatemethod("init_methods") do <<-EOD Methods.each do |definitions| opt = definitions.last if opt[:request_style] == :document add_document_operation(*definitions) else add_rpc_operation(*definitions) qname = definitions[0] name = definitions[2] if qname.name != name and qname.name.capitalize == name.capitalize ::SOAP::Mapping.define_singleton_method(self, qname.name) do |*arg| __send__(name, *arg) end end end end EOD end c.dump end end end end ================================================ FILE: lib/wsdl/soap/element.rb ================================================ # WSDL4R - XMLSchema element definition for WSDL. # Copyright (C) 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/xmlSchema/element' module WSDL module XMLSchema class Element < Info def map_as_array? maxoccurs != '1' end def attributes @local_complextype.attributes end end end end ================================================ FILE: lib/wsdl/soap/fault.rb ================================================ # WSDL4R - WSDL SOAP body definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module SOAP class Fault < Info attr_reader :name # required attr_reader :use # required attr_reader :encodingstyle attr_reader :namespace def initialize super @name = nil @use = nil @encodingstyle = nil @namespace = nil end def targetnamespace parent.targetnamespace end def parse_element(element) nil end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) when UseAttrName @use = value.source when EncodingStyleAttrName @encodingstyle = value.source when NamespaceAttrName @namespace = value.source else nil end end end end end ================================================ FILE: lib/wsdl/soap/header.rb ================================================ # WSDL4R - WSDL SOAP body definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module SOAP class Header < Info attr_reader :headerfault attr_reader :message # required attr_reader :part # required attr_reader :use # required attr_reader :encodingstyle attr_reader :namespace def initialize super @message = nil @part = nil @use = nil @encodingstyle = nil @namespace = nil @headerfault = nil end def targetnamespace parent.targetnamespace end def find_message root.message(@message) or raise RuntimeError.new("#{@message} not found") end def find_part find_message.parts.each do |part| if part.name == @part return part end end raise RuntimeError.new("#{@part} not found") end def parse_element(element) case element when HeaderFaultName o = WSDL::SOAP::HeaderFault.new @headerfault = o o else nil end end def parse_attr(attr, value) case attr when MessageAttrName if value.namespace.nil? value = XSD::QName.new(targetnamespace, value.source) end @message = value when PartAttrName @part = value.source when UseAttrName @use = value.source when EncodingStyleAttrName @encodingstyle = value.source when NamespaceAttrName @namespace = value.source else nil end end end end end ================================================ FILE: lib/wsdl/soap/headerfault.rb ================================================ # WSDL4R - WSDL SOAP body definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module SOAP class HeaderFault < Info attr_reader :message # required attr_reader :part # required attr_reader :use # required attr_reader :encodingstyle attr_reader :namespace def initialize super @message = nil @part = nil @use = nil @encodingstyle = nil @namespace = nil end def parse_element(element) nil end def parse_attr(attr, value) case attr when MessageAttrName @message = value when PartAttrName @part = value.source when UseAttrName @use = value.source when EncodingStyleAttrName @encodingstyle = value.source when NamespaceAttrName @namespace = value.source else nil end end end end end ================================================ FILE: lib/wsdl/soap/mappingRegistryCreator.rb ================================================ # WSDL4R - Creating MappingRegistry code from WSDL. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/soap/classDefCreatorSupport' module WSDL module SOAP class MappingRegistryCreator include ClassDefCreatorSupport attr_reader :definitions def initialize(definitions) @definitions = definitions @complextypes = @definitions.collect_complextypes @types = nil end def dump(types) @types = types map_cache = [] map = "" @types.each do |type| if map_cache.index(type).nil? map_cache << type if type.namespace != XSD::Namespace if typemap = dump_typemap(type) map << typemap end end end end return map end private def dump_typemap(type) if definedtype = @complextypes[type] case definedtype.compoundtype when :TYPE_STRUCT dump_struct_typemap(definedtype) when :TYPE_ARRAY dump_array_typemap(definedtype) when :TYPE_MAP, :TYPE_EMPTY nil else raise NotImplementedError.new("must not reach here") end end end def dump_struct_typemap(definedtype) ele = definedtype.name return <<__EOD__ MappingRegistry.set( #{create_class_name(ele)}, ::SOAP::SOAPStruct, ::SOAP::Mapping::Registry::TypedStructFactory, { :type => #{dqname(ele)} } ) __EOD__ end def dump_array_typemap(definedtype) ele = definedtype.name arytype = definedtype.find_arytype || XSD::AnyTypeName type = XSD::QName.new(arytype.namespace, arytype.name.sub(/\[(?:,)*\]$/, '')) @types << type return <<__EOD__ MappingRegistry.set( #{create_class_name(ele)}, ::SOAP::SOAPArray, ::SOAP::Mapping::Registry::TypedArrayFactory, { :type => #{dqname(type)} } ) __EOD__ end end end end ================================================ FILE: lib/wsdl/soap/methodDefCreator.rb ================================================ # WSDL4R - Creating driver code from WSDL. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/soap/classDefCreatorSupport' require 'soap/rpc/element' module WSDL module SOAP class MethodDefCreator include ClassDefCreatorSupport attr_reader :definitions def initialize(definitions) @definitions = definitions @simpletypes = @definitions.collect_simpletypes @complextypes = @definitions.collect_complextypes @elements = @definitions.collect_elements @types = [] end def dump(porttype) @types.clear result = "" operations = @definitions.porttype(porttype).operations binding = @definitions.porttype_binding(porttype) operations.each do |operation| op_bind = binding.operations[operation.name] next unless op_bind # no binding is defined next unless op_bind.soapoperation # not a SOAP operation binding result << ",\n" unless result.empty? result << dump_method(operation, op_bind).chomp end return result, @types end def collect_rpcparameter(operation) result = operation.inputparts.collect { |part| collect_type(part.type) param_set(::SOAP::RPC::SOAPMethod::IN, part.name, rpcdefinedtype(part)) } outparts = operation.outputparts if outparts.size > 0 retval = outparts[0] collect_type(retval.type) result << param_set(::SOAP::RPC::SOAPMethod::RETVAL, retval.name, rpcdefinedtype(retval)) cdr(outparts).each { |part| collect_type(part.type) result << param_set(::SOAP::RPC::SOAPMethod::OUT, part.name, rpcdefinedtype(part)) } end result end def collect_documentparameter(operation) param = [] operation.inputparts.each do |input| param << param_set(::SOAP::RPC::SOAPMethod::IN, input.name, documentdefinedtype(input), elementqualified(input)) end operation.outputparts.each do |output| param << param_set(::SOAP::RPC::SOAPMethod::OUT, output.name, documentdefinedtype(output), elementqualified(output)) end param end private def dump_method(operation, binding) name = safemethodname(operation.name.name) name_as = operation.name.name style = binding.soapoperation_style inputuse = binding.input.soapbody_use outputuse = binding.output.soapbody_use namespace = binding.input.soapbody.namespace if style == :rpc qname = XSD::QName.new(namespace, name_as) paramstr = param2str(collect_rpcparameter(operation)) else qname = nil paramstr = param2str(collect_documentparameter(operation)) end if paramstr.empty? paramstr = '[]' else paramstr = "[ " << paramstr.split(/\r?\n/).join("\n ") << " ]" end definitions = <<__EOD__ #{ndq(binding.soapaction)}, #{dq(name)}, #{paramstr}, { :request_style => #{sym(style.id2name)}, :request_use => #{sym(inputuse.id2name)}, :response_style => #{sym(style.id2name)}, :response_use => #{sym(outputuse.id2name)} } __EOD__ if style == :rpc return <<__EOD__ [ #{qname.dump}, #{definitions}] __EOD__ else return <<__EOD__ [ #{definitions}] __EOD__ end end def rpcdefinedtype(part) if mapped = basetype_mapped_class(part.type) ['::' + mapped.name] elsif definedtype = @simpletypes[part.type] ['::' + basetype_mapped_class(definedtype.base).name] elsif definedtype = @elements[part.element] #['::SOAP::SOAPStruct', part.element.namespace, part.element.name] ['nil', part.element.namespace, part.element.name] elsif definedtype = @complextypes[part.type] case definedtype.compoundtype when :TYPE_STRUCT, :TYPE_EMPTY # ToDo: empty should be treated as void. type = create_class_name(part.type) [type, part.type.namespace, part.type.name] when :TYPE_MAP [Hash.name, part.type.namespace, part.type.name] when :TYPE_ARRAY arytype = definedtype.find_arytype || XSD::AnyTypeName ns = arytype.namespace name = arytype.name.sub(/\[(?:,)*\]$/, '') type = create_class_name(XSD::QName.new(ns, name)) [type + '[]', ns, name] else raise NotImplementedError.new("must not reach here") end else raise RuntimeError.new("part: #{part.name} cannot be resolved") end end def documentdefinedtype(part) if mapped = basetype_mapped_class(part.type) ['::' + mapped.name, nil, part.name] elsif definedtype = @simpletypes[part.type] ['::' + basetype_mapped_class(definedtype.base).name, nil, part.name] elsif definedtype = @elements[part.element] ['::SOAP::SOAPElement', part.element.namespace, part.element.name] elsif definedtype = @complextypes[part.type] ['::SOAP::SOAPElement', part.type.namespace, part.type.name] else raise RuntimeError.new("part: #{part.name} cannot be resolved") end end def elementqualified(part) if mapped = basetype_mapped_class(part.type) false elsif definedtype = @simpletypes[part.type] false elsif definedtype = @elements[part.element] definedtype.elementform == 'qualified' elsif definedtype = @complextypes[part.type] false else raise RuntimeError.new("part: #{part.name} cannot be resolved") end end def param_set(io_type, name, type, ele = nil) [io_type, name, type, ele] end def collect_type(type) # ignore inline type definition. return if type.nil? return if @types.include?(type) @types << type return unless @complextypes[type] @complextypes[type].each_element do |element| collect_type(element.type) end end def param2str(params) params.collect { |param| io, name, type, ele = param unless ele.nil? "[#{dq(io)}, #{dq(name)}, #{type2str(type)}, #{ele2str(ele)}]" else "[#{dq(io)}, #{dq(name)}, #{type2str(type)}]" end }.join(",\n") end def type2str(type) if type.size == 1 "[#{dq(type[0])}]" else "[#{dq(type[0])}, #{ndq(type[1])}, #{dq(type[2])}]" end end def ele2str(ele) qualified = ele if qualified "true" else "false" end end def cdr(ary) result = ary.dup result.shift result end end end end ================================================ FILE: lib/wsdl/soap/operation.rb ================================================ # WSDL4R - WSDL SOAP operation definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module SOAP class Operation < Info class OperationInfo attr_reader :style attr_reader :op_name attr_reader :optype_name attr_reader :headerparts attr_reader :bodyparts attr_reader :faultpart attr_reader :soapaction def initialize(style, op_name, optype_name, headerparts, bodyparts, faultpart, soapaction) @style = style @op_name = op_name @optype_name = optype_name @headerparts = headerparts @bodyparts = bodyparts @faultpart = faultpart @soapaction = soapaction end end attr_reader :soapaction attr_reader :style def initialize super @soapaction = nil @style = nil end def parse_element(element) nil end def parse_attr(attr, value) case attr when StyleAttrName if ["document", "rpc"].include?(value.source) @style = value.source.intern else raise Parser::AttributeConstraintError.new( "Unexpected value #{ value }.") end when SOAPActionAttrName @soapaction = value.source else nil end end def input_info name_info = parent.find_operation.input_info param_info(name_info, parent.input) end def output_info name_info = parent.find_operation.output_info param_info(name_info, parent.output) end def operation_style return @style if @style if parent_binding.soapbinding return parent_binding.soapbinding.style end nil end private def parent_binding parent.parent end def param_info(name_info, param) op_name = name_info.op_name optype_name = name_info.optype_name soapheader = param.soapheader headerparts = soapheader.collect { |item| item.find_part } soapbody = param.soapbody if soapbody.encodingstyle and soapbody.encodingstyle != ::SOAP::EncodingNamespace raise NotImplementedError.new( "EncodingStyle '#{ soapbody.encodingstyle }' not supported.") end if soapbody.namespace op_name = XSD::QName.new(soapbody.namespace, op_name.name) end if soapbody.parts target = soapbody.parts.split(/\s+/) bodyparts = name_info.parts.find_all { |part| target.include?(part.name) } else bodyparts = name_info.parts end faultpart = nil OperationInfo.new(operation_style, op_name, optype_name, headerparts, bodyparts, faultpart, parent.soapaction) end end end end ================================================ FILE: lib/wsdl/soap/servantSkeltonCreator.rb ================================================ # WSDL4R - Creating servant skelton code from WSDL. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/soap/classDefCreatorSupport' require 'xsd/codegen' module WSDL module SOAP class ServantSkeltonCreator include ClassDefCreatorSupport include XSD::CodeGen::GenSupport attr_reader :definitions def initialize(definitions) @definitions = definitions end def dump(porttype = nil) if porttype.nil? result = "" @definitions.porttypes.each do |type| result << dump_porttype(type.name) result << "\n" end else result = dump_porttype(porttype) end result end private def dump_porttype(name) class_name = create_class_name(name) c = XSD::CodeGen::ClassDef.new(class_name) operations = @definitions.porttype(name).operations operations.each do |operation| name = safemethodname(operation.name.name) input = operation.input params = input.find_message.parts.collect { |part| safevarname(part.name) } m = XSD::CodeGen::MethodDef.new(name, params) do <<-EOD p [#{params.join(", ")}] raise NotImplementedError.new EOD end m.comment = dump_method_signature(operation) c.add_method(m) end c.dump end end end end ================================================ FILE: lib/wsdl/soap/standaloneServerStubCreator.rb ================================================ # WSDL4R - Creating standalone server stub code from WSDL. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/soap/mappingRegistryCreator' require 'wsdl/soap/methodDefCreator' require 'wsdl/soap/classDefCreatorSupport' module WSDL module SOAP class StandaloneServerStubCreator include ClassDefCreatorSupport attr_reader :definitions def initialize(definitions) @definitions = definitions end def dump(service_name) warn("- Standalone stub can have only 1 port for now. So creating stub for the first port and rests are ignored.") warn("- Standalone server stub ignores port location defined in WSDL. Location is http://localhost:10080/ by default. Generated client from WSDL must be configured to point this endpoint manually.") port = @definitions.service(service_name).ports[0] dump_porttype(port.porttype.name) end private def dump_porttype(name) class_name = create_class_name(name) methoddef, types = MethodDefCreator.new(@definitions).dump(name) mr_creator = MappingRegistryCreator.new(@definitions) c1 = XSD::CodeGen::ClassDef.new(class_name) c1.def_require("soap/rpc/standaloneServer") c1.def_require("soap/mapping/registry") c1.def_const("MappingRegistry", "::SOAP::Mapping::Registry.new") c1.def_code(mr_creator.dump(types)) c1.def_code <<-EOD Methods = [ #{methoddef.gsub(/^/, " ")} ] EOD c2 = XSD::CodeGen::ClassDef.new(class_name + "App", "::SOAP::RPC::StandaloneServer") c2.def_method("initialize", "*arg") do <<-EOD super(*arg) servant = #{class_name}.new #{class_name}::Methods.each do |definitions| opt = definitions.last if opt[:request_style] == :document @router.add_document_operation(servant, *definitions) else @router.add_rpc_operation(servant, *definitions) end end self.mapping_registry = #{class_name}::MappingRegistry EOD end c1.dump + "\n" + c2.dump + format(<<-EOD) if $0 == __FILE__ # Change listen port. server = #{class_name}App.new('app', nil, '0.0.0.0', 10080) trap(:INT) do server.shutdown end server.start end EOD end end end end ================================================ FILE: lib/wsdl/soap/wsdl2ruby.rb ================================================ # WSDL4R - WSDL to ruby mapping library. # Copyright (C) 2002-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'logger' require 'xsd/qname' require 'wsdl/importer' require 'wsdl/soap/classDefCreator' require 'wsdl/soap/servantSkeltonCreator' require 'wsdl/soap/driverCreator' require 'wsdl/soap/clientSkeltonCreator' require 'wsdl/soap/standaloneServerStubCreator' require 'wsdl/soap/cgiStubCreator' module WSDL module SOAP class WSDL2Ruby attr_accessor :location attr_reader :opt attr_accessor :logger attr_accessor :basedir def run unless @location raise RuntimeError, "WSDL location not given" end @wsdl = import(@location) @name = @wsdl.name ? @wsdl.name.name : 'default' create_file end private def initialize @location = nil @opt = {} @logger = Logger.new(STDERR) @basedir = nil @wsdl = nil @name = nil end def create_file create_classdef if @opt.key?('classdef') create_servant_skelton(@opt['servant_skelton']) if @opt.key?('servant_skelton') create_cgi_stub(@opt['cgi_stub']) if @opt.key?('cgi_stub') create_standalone_server_stub(@opt['standalone_server_stub']) if @opt.key?('standalone_server_stub') create_driver(@opt['driver']) if @opt.key?('driver') create_client_skelton(@opt['client_skelton']) if @opt.key?('client_skelton') end def create_classdef @logger.info { "Creating class definition." } @classdef_filename = @name + '.rb' check_file(@classdef_filename) or return write_file(@classdef_filename) do |f| f << WSDL::SOAP::ClassDefCreator.new(@wsdl).dump end end def create_client_skelton(servicename) @logger.info { "Creating client skelton." } servicename ||= @wsdl.services[0].name.name @client_skelton_filename = servicename + 'Client.rb' check_file(@client_skelton_filename) or return write_file(@client_skelton_filename) do |f| f << shbang << "\n" f << "require '#{@driver_filename}'\n\n" if @driver_filename f << WSDL::SOAP::ClientSkeltonCreator.new(@wsdl).dump( create_name(servicename)) end end def create_servant_skelton(porttypename) @logger.info { "Creating servant skelton." } @servant_skelton_filename = (porttypename || @name + 'Servant') + '.rb' check_file(@servant_skelton_filename) or return write_file(@servant_skelton_filename) do |f| f << "require '#{@classdef_filename}'\n\n" if @classdef_filename f << WSDL::SOAP::ServantSkeltonCreator.new(@wsdl).dump( create_name(porttypename)) end end def create_cgi_stub(servicename) @logger.info { "Creating CGI stub." } servicename ||= @wsdl.services[0].name.name @cgi_stubFilename = servicename + '.cgi' check_file(@cgi_stubFilename) or return write_file(@cgi_stubFilename) do |f| f << shbang << "\n" if @servant_skelton_filename f << "require '#{@servant_skelton_filename}'\n\n" end f << WSDL::SOAP::CGIStubCreator.new(@wsdl).dump(create_name(servicename)) end end def create_standalone_server_stub(servicename) @logger.info { "Creating standalone stub." } servicename ||= @wsdl.services[0].name.name @standalone_server_stub_filename = servicename + '.rb' check_file(@standalone_server_stub_filename) or return write_file(@standalone_server_stub_filename) do |f| f << shbang << "\n" f << "require '#{@servant_skelton_filename}'\n\n" if @servant_skelton_filename f << WSDL::SOAP::StandaloneServerStubCreator.new(@wsdl).dump( create_name(servicename)) end end def create_driver(porttypename) @logger.info { "Creating driver." } @driver_filename = (porttypename || @name) + 'Driver.rb' check_file(@driver_filename) or return write_file(@driver_filename) do |f| f << "require '#{@classdef_filename}'\n\n" if @classdef_filename f << WSDL::SOAP::DriverCreator.new(@wsdl).dump( create_name(porttypename)) end end def write_file(filename) if @basedir filename = File.join(basedir, filename) end File.open(filename, "w") do |f| yield f end end def check_file(filename) if @basedir filename = File.join(basedir, filename) end if FileTest.exist?(filename) if @opt.key?('force') @logger.warn { "File '#{filename}' exists but overrides it." } true else @logger.warn { "File '#{filename}' exists. #{$0} did not override it." } false end else @logger.info { "Creates file '#{filename}'." } true end end def shbang "#!/usr/bin/env ruby" end def create_name(name) name ? XSD::QName.new(@wsdl.targetnamespace, name) : nil end def import(location) WSDL::Importer.import(location) end end end end ================================================ FILE: lib/wsdl/types.rb ================================================ # WSDL4R - WSDL types definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL class Types < Info attr_reader :schemas def initialize super @schemas = [] end def parse_element(element) case element when SchemaName o = XMLSchema::Schema.new @schemas << o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) nil end end end ================================================ FILE: lib/wsdl/wsdl.rb ================================================ # WSDL4R - Base definitions. # Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' module WSDL Version = '0.0.2' Namespace = 'http://schemas.xmlsoap.org/wsdl/' SOAPBindingNamespace ='http://schemas.xmlsoap.org/wsdl/soap/' class Error < StandardError; end end ================================================ FILE: lib/wsdl/xmlSchema/all.rb ================================================ # WSDL4R - XMLSchema complexType definition for WSDL. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class All < Info attr_reader :minoccurs attr_reader :maxoccurs attr_reader :elements def initialize super() @minoccurs = '1' @maxoccurs = '1' @elements = [] end def targetnamespace parent.targetnamespace end def elementformdefault parent.elementformdefault end def <<(element) @elements << element end def parse_element(element) case element when AnyName o = Any.new @elements << o o when ElementName o = Element.new @elements << o o else nil end end def parse_attr(attr, value) case attr when MaxOccursAttrName @maxoccurs = value.source when MinOccursAttrName @minoccurs = value.source else nil end end end end end ================================================ FILE: lib/wsdl/xmlSchema/annotation.rb ================================================ # WSDL4R - WSDL SOAP documentation element. # Copyright (C) 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Annotation < Info def initialize super end def parse_element(element) # Accepts any element. self end def parse_attr(attr, value) # Accepts any attribute. true end end end end ================================================ FILE: lib/wsdl/xmlSchema/any.rb ================================================ # WSDL4R - XMLSchema any definition for WSDL. # Copyright (C) 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Any < Info attr_accessor :maxoccurs attr_accessor :minoccurs attr_accessor :namespace attr_accessor :process_contents def initialize super() @maxoccurs = '1' @minoccurs = '1' @namespace = '##any' @process_contents = 'strict' end def targetnamespace parent.targetnamespace end def parse_element(element) nil end def parse_attr(attr, value) case attr when MaxOccursAttrName @maxoccurs = value.source when MinOccursAttrName @minoccurs = value.source when NamespaceAttrName @namespace = value.source when ProcessContentsAttrName @process_contents = value.source else nil end end end end end ================================================ FILE: lib/wsdl/xmlSchema/attribute.rb ================================================ # WSDL4R - XMLSchema attribute definition for WSDL. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Attribute < Info class << self if RUBY_VERSION > "1.7.0" def attr_reader_ref(symbol) name = symbol.to_s define_method(name) { instance_variable_get("@#{name}") || (refelement ? refelement.__send__(name) : nil) } end else def attr_reader_ref(symbol) name = symbol.to_s module_eval <<-EOS def #{name} @#{name} || (refelement ? refelement.#{name} : nil) end EOS end end end attr_writer :use attr_writer :form attr_writer :name attr_writer :type attr_writer :local_simpletype attr_writer :default attr_writer :fixed attr_reader_ref :use attr_reader_ref :form attr_reader_ref :name attr_reader_ref :type attr_reader_ref :local_simpletype attr_reader_ref :default attr_reader_ref :fixed attr_accessor :ref attr_accessor :arytype def initialize super @use = nil @form = nil @name = nil @type = nil @local_simpletype = nil @default = nil @fixed = nil @ref = nil @refelement = nil @arytype = nil end def refelement @refelement ||= root.collect_attributes[@ref] end def targetnamespace parent.targetnamespace end def parse_element(element) case element when SimpleTypeName @local_simpletype = SimpleType.new @local_simpletype end end def parse_attr(attr, value) case attr when RefAttrName @ref = value when UseAttrName @use = value.source when FormAttrName @form = value.source when NameAttrName if directelement? @name = XSD::QName.new(targetnamespace, value.source) else @name = XSD::QName.new(nil, value.source) end when TypeAttrName @type = value when DefaultAttrName @default = value.source when FixedAttrName @fixed = value.source when ArrayTypeAttrName @arytype = if value.namespace.nil? XSD::QName.new(XSD::Namespace, value.source) else value end else nil end end private def directelement? parent.is_a?(Schema) end end end end ================================================ FILE: lib/wsdl/xmlSchema/choice.rb ================================================ # WSDL4R - XMLSchema complexType definition for WSDL. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Choice < Info attr_reader :minoccurs attr_reader :maxoccurs attr_reader :elements def initialize super() @minoccurs = '1' @maxoccurs = '1' @elements = [] end def targetnamespace parent.targetnamespace end def elementformdefault parent.elementformdefault end def <<(element) @elements << element end def parse_element(element) case element when AnyName o = Any.new @elements << o o when ElementName o = Element.new @elements << o o else nil end end def parse_attr(attr, value) case attr when MaxOccursAttrName @maxoccurs = value.source when MinOccursAttrName @minoccurs = value.source else nil end end end end end ================================================ FILE: lib/wsdl/xmlSchema/complexContent.rb ================================================ # WSDL4R - XMLSchema complexContent definition for WSDL. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL module XMLSchema class ComplexContent < Info attr_accessor :base attr_reader :derivetype attr_reader :content attr_reader :attributes def initialize super @base = nil @derivetype = nil @content = nil @attributes = XSD::NamedElements.new @basetype = nil end def targetnamespace parent.targetnamespace end def elementformdefault parent.elementformdefault end def basetype @basetype ||= root.collect_complextypes[@base] end def parse_element(element) case element when RestrictionName, ExtensionName @derivetype = element.name self when AllName if @derivetype.nil? raise Parser::ElementConstraintError.new("base attr not found.") end @content = All.new @content when SequenceName if @derivetype.nil? raise Parser::ElementConstraintError.new("base attr not found.") end @content = Sequence.new @content when ChoiceName if @derivetype.nil? raise Parser::ElementConstraintError.new("base attr not found.") end @content = Choice.new @content when AttributeName if @derivetype.nil? raise Parser::ElementConstraintError.new("base attr not found.") end o = Attribute.new @attributes << o o end end def parse_attr(attr, value) if @derivetype.nil? return nil end case attr when BaseAttrName @base = value else nil end end end end end ================================================ FILE: lib/wsdl/xmlSchema/complexType.rb ================================================ # WSDL4R - XMLSchema complexType definition for WSDL. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/xmlSchema/content' require 'wsdl/xmlSchema/element' require 'xsd/namedelements' module WSDL module XMLSchema class ComplexType < Info attr_accessor :name attr_accessor :complexcontent attr_accessor :simplecontent attr_reader :content attr_accessor :final attr_accessor :mixed attr_reader :attributes def initialize(name = nil) super() @name = name @complexcontent = nil @simplecontent = nil @content = nil @final = nil @mixed = false @attributes = XSD::NamedElements.new end def targetnamespace # inner elements can be qualified # parent.is_a?(WSDL::XMLSchema::Element) ? nil : parent.targetnamespace parent.targetnamespace end def elementformdefault parent.elementformdefault end AnyAsElement = Element.new(XSD::QName.new(nil, 'any'), XSD::AnyTypeName) def each_element if content content.elements.each do |element| if element.is_a?(Any) yield(AnyAsElement) else yield(element) end end end end def find_element(name) if content content.elements.each do |element| if element.is_a?(Any) return AnyAsElement if name == AnyAsElement.name else return element if name == element.name end end end nil end def find_element_by_name(name) if content content.elements.each do |element| if element.is_a?(Any) return AnyAsElement if name == AnyAsElement.name.name else return element if name == element.name.name end end end nil end def sequence_elements=(elements) @content = Sequence.new elements.each do |element| @content << element end end def all_elements=(elements) @content = All.new elements.each do |element| @content << element end end def parse_element(element) case element when AllName @content = All.new when SequenceName @content = Sequence.new when ChoiceName @content = Choice.new when ComplexContentName @complexcontent = ComplexContent.new when SimpleContentName @simplecontent = SimpleContent.new when AttributeName o = Attribute.new @attributes << o o else nil end end def parse_attr(attr, value) case attr when FinalAttrName @final = value.source when MixedAttrName @mixed = (value.source == 'true') when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) else nil end end end end end ================================================ FILE: lib/wsdl/xmlSchema/content.rb ================================================ # WSDL4R - XMLSchema complexType definition for WSDL. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Content < Info attr_accessor :final attr_accessor :mixed attr_accessor :type attr_reader :contents attr_reader :elements def initialize super() @final = nil @mixed = false @type = nil @contents = [] @elements = [] end def targetnamespace parent.targetnamespace end def <<(content) @contents << content update_elements end def each @contents.each do |content| yield content end end def parse_element(element) case element when AllName, SequenceName, ChoiceName o = Content.new o.type = element.name @contents << o o when AnyName o = Any.new @contents << o o when ElementName o = Element.new @contents << o o else nil end end def parse_attr(attr, value) case attr when FinalAttrName @final = value.source when MixedAttrName @mixed = (value.source == 'true') else nil end end def parse_epilogue update_elements end private def update_elements @elements = [] @contents.each do |content| if content.is_a?(Element) @elements << [content.name, content] end end end end end end ================================================ FILE: lib/wsdl/xmlSchema/data.rb ================================================ # WSDL4R - XMLSchema data definitions. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/datatypes' require 'wsdl/xmlSchema/annotation' require 'wsdl/xmlSchema/schema' require 'wsdl/xmlSchema/import' require 'wsdl/xmlSchema/include' require 'wsdl/xmlSchema/simpleType' require 'wsdl/xmlSchema/simpleRestriction' require 'wsdl/xmlSchema/simpleExtension' require 'wsdl/xmlSchema/complexType' require 'wsdl/xmlSchema/complexContent' require 'wsdl/xmlSchema/simpleContent' require 'wsdl/xmlSchema/any' require 'wsdl/xmlSchema/element' require 'wsdl/xmlSchema/all' require 'wsdl/xmlSchema/choice' require 'wsdl/xmlSchema/sequence' require 'wsdl/xmlSchema/attribute' require 'wsdl/xmlSchema/unique' require 'wsdl/xmlSchema/enumeration' require 'wsdl/xmlSchema/length' require 'wsdl/xmlSchema/pattern' module WSDL module XMLSchema AllName = XSD::QName.new(XSD::Namespace, 'all') AnnotationName = XSD::QName.new(XSD::Namespace, 'annotation') AnyName = XSD::QName.new(XSD::Namespace, 'any') AttributeName = XSD::QName.new(XSD::Namespace, 'attribute') ChoiceName = XSD::QName.new(XSD::Namespace, 'choice') ComplexContentName = XSD::QName.new(XSD::Namespace, 'complexContent') ComplexTypeName = XSD::QName.new(XSD::Namespace, 'complexType') ElementName = XSD::QName.new(XSD::Namespace, 'element') EnumerationName = XSD::QName.new(XSD::Namespace, 'enumeration') ExtensionName = XSD::QName.new(XSD::Namespace, 'extension') ImportName = XSD::QName.new(XSD::Namespace, 'import') IncludeName = XSD::QName.new(XSD::Namespace, 'include') LengthName = XSD::QName.new(XSD::Namespace, 'length') PatternName = XSD::QName.new(XSD::Namespace, 'pattern') RestrictionName = XSD::QName.new(XSD::Namespace, 'restriction') SequenceName = XSD::QName.new(XSD::Namespace, 'sequence') SchemaName = XSD::QName.new(XSD::Namespace, 'schema') SimpleContentName = XSD::QName.new(XSD::Namespace, 'simpleContent') SimpleTypeName = XSD::QName.new(XSD::Namespace, 'simpleType') UniqueName = XSD::QName.new(XSD::Namespace, 'unique') AttributeFormDefaultAttrName = XSD::QName.new(nil, 'attributeFormDefault') BaseAttrName = XSD::QName.new(nil, 'base') DefaultAttrName = XSD::QName.new(nil, 'default') ElementFormDefaultAttrName = XSD::QName.new(nil, 'elementFormDefault') FinalAttrName = XSD::QName.new(nil, 'final') FixedAttrName = XSD::QName.new(nil, 'fixed') FormAttrName = XSD::QName.new(nil, 'form') IdAttrName = XSD::QName.new(nil, 'id') MaxOccursAttrName = XSD::QName.new(nil, 'maxOccurs') MinOccursAttrName = XSD::QName.new(nil, 'minOccurs') MixedAttrName = XSD::QName.new(nil, 'mixed') NameAttrName = XSD::QName.new(nil, 'name') NamespaceAttrName = XSD::QName.new(nil, 'namespace') NillableAttrName = XSD::QName.new(nil, 'nillable') ProcessContentsAttrName = XSD::QName.new(nil, 'processContents') RefAttrName = XSD::QName.new(nil, 'ref') SchemaLocationAttrName = XSD::QName.new(nil, 'schemaLocation') TargetNamespaceAttrName = XSD::QName.new(nil, 'targetNamespace') TypeAttrName = XSD::QName.new(nil, 'type') UseAttrName = XSD::QName.new(nil, 'use') ValueAttrName = XSD::QName.new(nil, 'value') end end ================================================ FILE: lib/wsdl/xmlSchema/element.rb ================================================ # WSDL4R - XMLSchema element definition for WSDL. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Element < Info class << self if RUBY_VERSION > "1.7.0" def attr_reader_ref(symbol) name = symbol.to_s define_method(name) { instance_variable_get("@#{name}") || (refelement ? refelement.__send__(name) : nil) } end else def attr_reader_ref(symbol) name = symbol.to_s module_eval <<-EOS def #{name} @#{name} || (refelement ? refelement.#{name} : nil) end EOS end end end attr_writer :name # required attr_writer :form attr_writer :type attr_writer :local_simpletype attr_writer :local_complextype attr_writer :constraint attr_writer :maxoccurs attr_writer :minoccurs attr_writer :nillable attr_reader_ref :name attr_reader_ref :form attr_reader_ref :type attr_reader_ref :local_simpletype attr_reader_ref :local_complextype attr_reader_ref :constraint attr_reader_ref :maxoccurs attr_reader_ref :minoccurs attr_reader_ref :nillable attr_accessor :ref def initialize(name = nil, type = nil) super() @name = name @form = nil @type = type @local_simpletype = @local_complextype = nil @constraint = nil @maxoccurs = '1' @minoccurs = '1' @nillable = nil @ref = nil @refelement = nil end def refelement @refelement ||= (@ref ? root.collect_elements[@ref] : nil) end def targetnamespace parent.targetnamespace end def elementformdefault parent.elementformdefault end def elementform self.form.nil? ? parent.elementformdefault : self.form end def parse_element(element) case element when SimpleTypeName @local_simpletype = SimpleType.new @local_simpletype when ComplexTypeName @type = nil @local_complextype = ComplexType.new @local_complextype when UniqueName @constraint = Unique.new @constraint else nil end end def parse_attr(attr, value) case attr when NameAttrName # namespace may be nil if directelement? or elementform == 'qualified' @name = XSD::QName.new(targetnamespace, value.source) else @name = XSD::QName.new(nil, value.source) end when FormAttrName @form = value.source when TypeAttrName @type = value when RefAttrName @ref = value when MaxOccursAttrName if parent.is_a?(All) if value.source != '1' raise Parser::AttrConstraintError.new( "cannot parse #{value} for #{attr}") end end @maxoccurs = value.source when MinOccursAttrName if parent.is_a?(All) unless ['0', '1'].include?(value.source) raise Parser::AttrConstraintError.new( "cannot parse #{value} for #{attr}") end end @minoccurs = value.source when NillableAttrName @nillable = (value.source == 'true') else nil end end private def directelement? parent.is_a?(Schema) end end end end ================================================ FILE: lib/wsdl/xmlSchema/enumeration.rb ================================================ # WSDL4R - XMLSchema enumeration definition for WSDL. # Copyright (C) 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Enumeration < Info def initialize super end def parse_element(element) nil end def parse_attr(attr, value) case attr when ValueAttrName parent.enumeration << value.source value.source end end end end end ================================================ FILE: lib/wsdl/xmlSchema/import.rb ================================================ # WSDL4R - XMLSchema import definition. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/xmlSchema/importer' module WSDL module XMLSchema class Import < Info attr_reader :namespace attr_reader :schemalocation attr_reader :content def initialize super @namespace = nil @schemalocation = nil @content = nil end def parse_element(element) nil end def parse_attr(attr, value) case attr when NamespaceAttrName @namespace = value.source when SchemaLocationAttrName @schemalocation = URI.parse(value.source) if @schemalocation.relative? and !parent.location.nil? and !parent.location.relative? @schemalocation = parent.location + @schemalocation end if root.importedschema.key?(@schemalocation) @content = root.importedschema[@schemalocation] else root.importedschema[@schemalocation] = nil # placeholder @content = import(@schemalocation) root.importedschema[@schemalocation] = @content end @schemalocation else nil end end private def import(location) Importer.import(location, root) end end end end ================================================ FILE: lib/wsdl/xmlSchema/importer.rb ================================================ # WSDL4R - XSD importer library. # Copyright (C) 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/httpconfigloader' require 'wsdl/xmlSchema/parser' module WSDL module XMLSchema class Importer def self.import(location, originalroot = nil) new.import(location, originalroot) end def initialize @web_client = nil end def import(location, originalroot = nil) unless location.is_a?(URI) location = URI.parse(location) end content = parse(fetch(location), location, originalroot) content.location = location content end private def parse(content, location, originalroot) opt = { :location => location, :originalroot => originalroot } WSDL::XMLSchema::Parser.new(opt).parse(content) end def fetch(location) warn("importing: #{location}") if $DEBUG content = nil if location.scheme == 'file' or (location.relative? and FileTest.exist?(location.path)) content = File.open(location.path).read elsif location.scheme and location.scheme.size == 1 and FileTest.exist?(location.to_s) # ToDo: remove this ugly workaround for a path with drive letter # (D://foo/bar) content = File.open(location.to_s).read else client = web_client.new(nil, "WSDL4R") client.proxy = ::SOAP::Env::HTTP_PROXY client.no_proxy = ::SOAP::Env::NO_PROXY if opt = ::SOAP::Property.loadproperty(::SOAP::PropertyName) ::SOAP::HTTPConfigLoader.set_options(client, opt["client.protocol.http"]) end content = client.get_content(location) end content end def web_client @web_client ||= begin require 'http-access2' if HTTPAccess2::VERSION < "2.0" raise LoadError.new("http-access/2.0 or later is required.") end HTTPAccess2::Client rescue LoadError warn("Loading http-access2 failed. Net/http is used.") if $DEBUG require 'soap/netHttpClient' ::SOAP::NetHttpClient end @web_client end end end end ================================================ FILE: lib/wsdl/xmlSchema/include.rb ================================================ # WSDL4R - XMLSchema include definition. # Copyright (C) 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/xmlSchema/importer' module WSDL module XMLSchema class Include < Info attr_reader :schemalocation attr_reader :content def initialize super @schemalocation = nil @content = nil end def parse_element(element) nil end def parse_attr(attr, value) case attr when SchemaLocationAttrName @schemalocation = URI.parse(value.source) if @schemalocation.relative? @schemalocation = parent.location + @schemalocation end @content = import(@schemalocation) @schemalocation else nil end end private def import(location) Importer.import(location) end end end end ================================================ FILE: lib/wsdl/xmlSchema/length.rb ================================================ # WSDL4R - XMLSchema length definition for WSDL. # Copyright (C) 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Length < Info def initialize super end def parse_element(element) nil end def parse_attr(attr, value) case attr when ValueAttrName value.source end end end end end ================================================ FILE: lib/wsdl/xmlSchema/parser.rb ================================================ # WSDL4R - WSDL XML Instance parser library. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' require 'xsd/ns' require 'xsd/charset' require 'xsd/datatypes' require 'xsd/xmlparser' require 'wsdl/xmlSchema/data' module WSDL module XMLSchema class Parser include XSD class ParseError < Error; end class FormatDecodeError < ParseError; end class UnknownElementError < FormatDecodeError; end class UnknownAttributeError < FormatDecodeError; end class UnexpectedElementError < FormatDecodeError; end class ElementConstraintError < FormatDecodeError; end class AttributeConstraintError < FormatDecodeError; end private class ParseFrame attr_reader :ns attr_reader :name attr_accessor :node private def initialize(ns, name, node) @ns = ns @name = name @node = node end end public def initialize(opt = {}) @parser = XSD::XMLParser.create_parser(self, opt) @parsestack = nil @lastnode = nil @ignored = {} @location = opt[:location] @originalroot = opt[:originalroot] end def parse(string_or_readable) @parsestack = [] @lastnode = nil @textbuf = '' @parser.do_parse(string_or_readable) @lastnode end def charset @parser.charset end def start_element(name, attrs) lastframe = @parsestack.last ns = parent = nil if lastframe ns = lastframe.ns.clone_ns parent = lastframe.node else ns = XSD::NS.new parent = nil end attrs = XSD::XMLParser.filter_ns(ns, attrs) node = decode_tag(ns, name, attrs, parent) @parsestack << ParseFrame.new(ns, name, node) end def characters(text) lastframe = @parsestack.last if lastframe # Need not to be cloned because character does not have attr. ns = lastframe.ns decode_text(ns, text) else p text if $DEBUG end end def end_element(name) lastframe = @parsestack.pop unless name == lastframe.name raise UnexpectedElementError.new("closing element name '#{name}' does not match with opening element '#{lastframe.name}'") end decode_tag_end(lastframe.ns, lastframe.node) @lastnode = lastframe.node end private def decode_tag(ns, name, attrs, parent) o = nil elename = ns.parse(name) if !parent if elename == SchemaName o = Schema.parse_element(elename) o.location = @location else raise UnknownElementError.new("unknown element: #{elename}") end o.root = @originalroot if @originalroot # o.root = o otherwise else if elename == AnnotationName # only the first annotation element is allowed for each element. o = Annotation.new else o = parent.parse_element(elename) end unless o unless @ignored.key?(elename) warn("ignored element: #{elename} of #{parent.class}") @ignored[elename] = elename end o = Documentation.new # which accepts any element. end # node could be a pseudo element. pseudo element has its own parent. o.root = parent.root o.parent = parent if o.parent.nil? end attrs.each do |key, value| attr_ele = ns.parse(key, true) value_ele = ns.parse(value, true) value_ele.source = value # for recovery; value may not be a QName if attr_ele == IdAttrName o.id = value_ele else unless o.parse_attr(attr_ele, value_ele) unless @ignored.key?(attr_ele) warn("ignored attr: #{attr_ele}") @ignored[attr_ele] = attr_ele end end end end o end def decode_tag_end(ns, node) node.parse_epilogue end def decode_text(ns, text) @textbuf << text end end end end ================================================ FILE: lib/wsdl/xmlSchema/pattern.rb ================================================ # WSDL4R - XMLSchema pattern definition for WSDL. # Copyright (C) 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Pattern < Info def initialize super end def parse_element(element) nil end def parse_attr(attr, value) case attr when ValueAttrName parent.pattern = /\A#{value.source}\z/n value.source end end end end end ================================================ FILE: lib/wsdl/xmlSchema/schema.rb ================================================ # WSDL4R - XMLSchema schema definition for WSDL. # Copyright (C) 2002, 2003-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL module XMLSchema class Schema < Info attr_reader :targetnamespace # required attr_reader :complextypes attr_reader :simpletypes attr_reader :elements attr_reader :attributes attr_reader :imports attr_accessor :attributeformdefault attr_accessor :elementformdefault attr_reader :importedschema def initialize super @targetnamespace = nil @complextypes = XSD::NamedElements.new @simpletypes = XSD::NamedElements.new @elements = XSD::NamedElements.new @attributes = XSD::NamedElements.new @imports = [] @attributeformdefault = "unqualified" @elementformdefault = "unqualified" @importedschema = {} @location = nil @root = self end def location @location || (root.nil? ? nil : root.location) end def location=(location) @location = location end def parse_element(element) case element when ImportName o = Import.new @imports << o o when IncludeName o = Include.new @imports << o o when ComplexTypeName o = ComplexType.new @complextypes << o o when SimpleTypeName o = SimpleType.new @simpletypes << o o when ElementName o = Element.new @elements << o o when AttributeName o = Attribute.new @attributes << o o else nil end end def parse_attr(attr, value) case attr when TargetNamespaceAttrName @targetnamespace = value.source when AttributeFormDefaultAttrName @attributeformdefault = value.source when ElementFormDefaultAttrName @elementformdefault = value.source else nil end end def collect_attributes result = XSD::NamedElements.new result.concat(@attributes) @imports.each do |import| result.concat(import.content.collect_attributes) if import.content end result end def collect_elements result = XSD::NamedElements.new result.concat(@elements) @imports.each do |import| result.concat(import.content.collect_elements) if import.content end result end def collect_complextypes result = XSD::NamedElements.new result.concat(@complextypes) @imports.each do |import| result.concat(import.content.collect_complextypes) if import.content end result end def collect_simpletypes result = XSD::NamedElements.new result.concat(@simpletypes) @imports.each do |import| result.concat(import.content.collect_simpletypes) if import.content end result end def self.parse_element(element) if element == SchemaName Schema.new else nil end end end end end ================================================ FILE: lib/wsdl/xmlSchema/sequence.rb ================================================ # WSDL4R - XMLSchema complexType definition for WSDL. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Sequence < Info attr_reader :minoccurs attr_reader :maxoccurs attr_reader :elements def initialize super() @minoccurs = '1' @maxoccurs = '1' @elements = [] end def targetnamespace parent.targetnamespace end def elementformdefault parent.elementformdefault end def <<(element) @elements << element end def parse_element(element) case element when AnyName o = Any.new @elements << o o when ElementName o = Element.new @elements << o o else nil end end def parse_attr(attr, value) case attr when MaxOccursAttrName @maxoccurs = value.source when MinOccursAttrName @minoccurs = value.source else nil end end end end end ================================================ FILE: lib/wsdl/xmlSchema/simpleContent.rb ================================================ # WSDL4R - XMLSchema simpleContent definition for WSDL. # Copyright (C) 2004, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL module XMLSchema class SimpleContent < Info attr_reader :restriction attr_reader :extension def check_lexical_format(value) check(value) end def initialize super @restriction = nil @extension = nil end def base content.base end def targetnamespace parent.targetnamespace end def parse_element(element) case element when RestrictionName @restriction = SimpleRestriction.new @restriction when ExtensionName @extension = SimpleExtension.new @extension end end private def content @restriction || @extension end def check(value) unless content.valid?(value) raise XSD::ValueSpaceError.new("#{@name}: cannot accept '#{value}'") end end end end end ================================================ FILE: lib/wsdl/xmlSchema/simpleExtension.rb ================================================ # WSDL4R - XMLSchema simpleType extension definition for WSDL. # Copyright (C) 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL module XMLSchema class SimpleExtension < Info attr_reader :base attr_reader :attributes def initialize super @base = nil @attributes = XSD::NamedElements.new end def targetnamespace parent.targetnamespace end def valid?(value) true end def parse_element(element) case element when AttributeName o = Attribute.new @attributes << o o end end def parse_attr(attr, value) case attr when BaseAttrName @base = value end end end end end ================================================ FILE: lib/wsdl/xmlSchema/simpleRestriction.rb ================================================ # WSDL4R - XMLSchema simpleContent restriction definition for WSDL. # Copyright (C) 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL module XMLSchema class SimpleRestriction < Info attr_reader :base attr_reader :enumeration attr_accessor :length attr_accessor :pattern def initialize super @base = nil @enumeration = [] # NamedElements? @length = nil @pattern = nil end def valid?(value) return false unless check_restriction(value) return false unless check_length(value) return false unless check_pattern(value) true end def parse_element(element) case element when EnumerationName Enumeration.new # just a parsing handler when LengthName Length.new # just a parsing handler when PatternName Pattern.new # just a parsing handler end end def parse_attr(attr, value) case attr when BaseAttrName @base = value end end private def check_restriction(value) @enumeration.empty? or @enumeration.include?(value) end def check_length(value) @length.nil? or value.size == @length end def check_pattern(value) @pattern.nil? or @pattern =~ value end end end end ================================================ FILE: lib/wsdl/xmlSchema/simpleType.rb ================================================ # WSDL4R - XMLSchema simpleType definition for WSDL. # Copyright (C) 2004, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL module XMLSchema class SimpleType < Info attr_accessor :name attr_reader :restriction def check_lexical_format(value) if @restriction check_restriction(value) else raise ArgumentError.new("incomplete simpleType") end end def base if @restriction @restriction.base else raise ArgumentError.new("incomplete simpleType") end end def initialize(name = nil) super() @name = name @restriction = nil end def targetnamespace parent.targetnamespace end def parse_element(element) case element when RestrictionName @restriction = SimpleRestriction.new @restriction end end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) end end private def check_restriction(value) unless @restriction.valid?(value) raise XSD::ValueSpaceError.new("#{@name}: cannot accept '#{value}'") end end end end end ================================================ FILE: lib/wsdl/xmlSchema/unique.rb ================================================ # WSDL4R - XMLSchema unique element. # Copyright (C) 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Unique < Info def initialize super end def parse_element(element) # Accepts any element. self end def parse_attr(attr, value) # Accepts any attribute. true end end end end ================================================ FILE: lib/wsdl/xmlSchema/xsd2ruby.rb ================================================ # XSD4R - XSD to ruby mapping library. # Copyright (C) 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/codegen/gensupport' require 'wsdl/xmlSchema/importer' require 'wsdl/soap/classDefCreator' module WSDL module XMLSchema class XSD2Ruby attr_accessor :location attr_reader :opt attr_accessor :logger attr_accessor :basedir def run unless @location raise RuntimeError, "XML Schema location not given" end @xsd = import(@location) @name = create_classname(@xsd) create_file end private def initialize @location = nil @opt = {} @logger = Logger.new(STDERR) @basedir = nil @xsd = nil @name = nil end def create_file create_classdef end def create_classdef @logger.info { "Creating class definition." } @classdef_filename = @name + '.rb' check_file(@classdef_filename) or return write_file(@classdef_filename) do |f| f << WSDL::SOAP::ClassDefCreator.new(@xsd).dump end end def write_file(filename) if @basedir filename = File.join(basedir, filename) end File.open(filename, "w") do |f| yield f end end def check_file(filename) if @basedir filename = File.join(basedir, filename) end if FileTest.exist?(filename) if @opt.key?('force') @logger.warn { "File '#{filename}' exists but overrides it." } true else @logger.warn { "File '#{filename}' exists. #{$0} did not override it." } false end else @logger.info { "Creates file '#{filename}'." } true end end def create_classname(xsd) name = nil if xsd.targetnamespace name = xsd.targetnamespace.scan(/[a-zA-Z0-9]+$/)[0] end if name.nil? 'default' else XSD::CodeGen::GenSupport.safevarname(name) end end def import(location) WSDL::XMLSchema::Importer.import(location) end end end end ================================================ FILE: lib/xmlrpc/.document ================================================ README.rdoc ================================================ FILE: lib/xmlrpc/README.txt ================================================ = XMLRPC for Ruby, Standard Library Documentation == Overview XMLRPC is a lightweight protocol that enables remote procedure calls over HTTP. It is defined at http://www.xmlrpc.com. XMLRPC allows you to create simple distributed computing solutions that span computer languages. Its distinctive feature is its simplicity compared to other approaches like SOAP and CORBA. The Ruby standard library package 'xmlrpc' enables you to create a server that implements remote procedures and a client that calls them. Very little code is required to achieve either of these. == Example Try the following code. It calls a standard demonstration remote procedure. require 'xmlrpc/client' require 'pp' server = XMLRPC::Client.new2("http://xmlrpc-c.sourceforge.net/api/sample.php") result = server.call("sample.sumAndDifference", 5, 3) pp result == Documentation See http://www.ntecs.de/projects/xmlrpc4r. There is plenty of detail there to use the client and implement a server. ================================================ FILE: lib/xmlrpc/base64.rb ================================================ =begin = xmlrpc/base64.rb Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) Released under the same term of license as Ruby. = Classes * (()) = XMLRPC::Base64 == Description This class is necessary for (('xmlrpc4r')) to determine that a string should be transmitted base64-encoded and not as a raw-string. You can use (({XMLRPC::Base64})) on the client and server-side as a parameter and/or return-value. == Class Methods --- XMLRPC::Base64.new( str, state = :dec ) Creates a new (({XMLRPC::Base64})) instance with string ((|str|)) as the internal string. When ((|state|)) is (({:dec})) it assumes that the string ((|str|)) is not in base64 format (perhaps already decoded), otherwise if ((|state|)) is (({:enc})) it decodes ((|str|)) and stores it as the internal string. --- XMLRPC::Base64.decode( str ) Decodes string ((|str|)) with base64 and returns that value. --- XMLRPC::Base64.encode( str ) Encodes string ((|str|)) with base64 and returns that value. == Instance Methods --- XMLRPC::Base64#decoded Returns the internal string decoded. --- XMLRPC::Base64#encoded Returns the internal string encoded with base64. =end module XMLRPC class Base64 def initialize(str, state = :dec) case state when :enc @str = Base64.decode(str) when :dec @str = str else raise ArgumentError, "wrong argument; either :enc or :dec" end end def decoded @str end def encoded Base64.encode(@str) end def Base64.decode(str) str.gsub(/\s+/, "").unpack("m")[0] end def Base64.encode(str) [str].pack("m") end end end # module XMLRPC =begin = History $Id$ =end ================================================ FILE: lib/xmlrpc/client.rb ================================================ =begin = xmlrpc/client.rb Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) Released under the same term of license as Ruby. = Classes * (()) * (()) = XMLRPC::Client == Synopsis require "xmlrpc/client" server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) begin param = server.call("michael.add", 4, 5) puts "4 + 5 = #{param}" rescue XMLRPC::FaultException => e puts "Error:" puts e.faultCode puts e.faultString end or require "xmlrpc/client" server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) ok, param = server.call2("michael.add", 4, 5) if ok then puts "4 + 5 = #{param}" else puts "Error:" puts param.faultCode puts param.faultString end == Description Class (({XMLRPC::Client})) provides remote procedure calls to a XML-RPC server. After setting the connection-parameters with (()) which creates a new (({XMLRPC::Client})) instance, you can execute a remote procedure by sending the (()) or (()) message to this new instance. The given parameters indicate which method to call on the remote-side and of course the parameters for the remote procedure. == Class Methods --- XMLRPC::Client.new( host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil, user=nil, password=nil, use_ssl=false, timeout =nil) Creates an object which represents the remote XML-RPC server on the given host ((|host|)). If the server is CGI-based, ((|path|)) is the path to the CGI-script, which will be called, otherwise (in the case of a standalone server) ((|path|)) should be (({"/RPC2"})). ((|port|)) is the port on which the XML-RPC server listens. If ((|proxy_host|)) is given, then a proxy server listening at ((|proxy_host|)) is used. ((|proxy_port|)) is the port of the proxy server. Default values for ((|host|)), ((|path|)) and ((|port|)) are 'localhost', '/RPC2' and '80' respectively using SSL '443'. If ((|user|)) and ((|password|)) are given, each time a request is send, a Authorization header is send. Currently only Basic Authentification is implemented no Digest. If ((|use_ssl|)) is set to (({true})), comunication over SSL is enabled. Note, that you need the SSL package from RAA installed. Parameter ((|timeout|)) is the time to wait for a XML-RPC response, defaults to 30. --- XMLRPC::Client.new2( uri, proxy=nil, timeout=nil) --- XMLRPC::Client.new_from_uri( uri, proxy=nil, timeout=nil) : uri URI specifying protocol (http or https), host, port, path, user and password. Example: https://user:password@host:port/path : proxy Is of the form "host:port". : timeout Defaults to 30. --- XMLRPC::Client.new3( hash={} ) --- XMLRPC::Client.new_from_hash( hash={} ) Parameter ((|hash|)) has following case-insensitive keys: * host * path * port * proxy_host * proxy_port * user * password * use_ssl * timeout Calls (()) with the corresponding values. == Instance Methods --- XMLRPC::Client#call( method, *args ) Invokes the method named ((|method|)) with the parameters given by ((|args|)) on the XML-RPC server. The parameter ((|method|)) is converted into a (({String})) and should be a valid XML-RPC method-name. Each parameter of ((|args|)) must be of one of the following types, where (({Hash})), (({Struct})) and (({Array})) can contain any of these listed ((:types:)): * (({Fixnum})), (({Bignum})) * (({TrueClass})), (({FalseClass})) ((({true})), (({false}))) * (({String})), (({Symbol})) * (({Float})) * (({Hash})), (({Struct})) * (({Array})) * (({Date})), (({Time})), (({XMLRPC::DateTime})) * (({XMLRPC::Base64})) * A Ruby object which class includes XMLRPC::Marshallable (only if Config::ENABLE_MARSHALLABLE is (({true}))). That object is converted into a hash, with one additional key/value pair "___class___" which contains the class name for restoring later that object. The method returns the return-value from the RPC ((-stands for Remote Procedure Call-)). The type of the return-value is one of the above shown, only that a (({Bignum})) is only allowed when it fits in 32-bit and that a XML-RPC (('dateTime.iso8601')) type is always returned as a ((<(({XMLRPC::DateTime}))|URL:datetime.html>)) object and a (({Struct})) is never returned, only a (({Hash})), the same for a (({Symbol})), where always a (({String})) is returned. A (({XMLRPC::Base64})) is returned as a (({String})) from xmlrpc4r version 1.6.1 on. If the remote procedure returned a fault-structure, then a (({XMLRPC::FaultException})) exception is raised, which has two accessor-methods (({faultCode})) and (({faultString})) of type (({Integer})) and (({String})). --- XMLRPC::Client#call2( method, *args ) The difference between this method and (()) is, that this method do ((*not*)) raise a (({XMLRPC::FaultException})) exception. The method returns an array of two values. The first value indicates if the second value is a return-value ((({true}))) or an object of type (({XMLRPC::FaultException})). Both are explained in (()). Simple to remember: The "2" in "call2" denotes the number of values it returns. --- XMLRPC::Client#multicall( *methods ) You can use this method to execute several methods on a XMLRPC server which supports the multi-call extension. Example: s.multicall( ['michael.add', 3, 4], ['michael.sub', 4, 5] ) # => [7, -1] --- XMLRPC::Client#multicall2( *methods ) Same as (()), but returns like (()) two parameters instead of raising an (({XMLRPC::FaultException})). --- XMLRPC::Client#proxy( prefix, *args ) Returns an object of class (({XMLRPC::Client::Proxy})), initialized with ((|prefix|)) and ((|args|)). A proxy object returned by this method behaves like (()), i.e. a call on that object will raise a (({XMLRPC::FaultException})) when a fault-structure is returned by that call. --- XMLRPC::Client#proxy2( prefix, *args ) Almost the same like (()) only that a call on the returned (({XMLRPC::Client::Proxy})) object behaves like (()), i.e. a call on that object will return two parameters. --- XMLRPC::Client#call_async(...) --- XMLRPC::Client#call2_async(...) --- XMLRPC::Client#multicall_async(...) --- XMLRPC::Client#multicall2_async(...) --- XMLRPC::Client#proxy_async(...) --- XMLRPC::Client#proxy2_async(...) In contrast to corresponding methods without "_async", these can be called concurrently and use for each request a new connection, where the non-asynchronous counterparts use connection-alive (one connection for all requests) if possible. Note, that you have to use Threads to call these methods concurrently. The following example calls two methods concurrently: Thread.new { p client.call_async("michael.add", 4, 5) } Thread.new { p client.call_async("michael.div", 7, 9) } --- XMLRPC::Client#timeout --- XMLRPC::Client#user --- XMLRPC::Client#password Return the corresponding attributes. --- XMLRPC::Client#timeout= (new_timeout) --- XMLRPC::Client#user= (new_user) --- XMLRPC::Client#password= (new_password) Set the corresponding attributes. --- XMLRPC::Client#set_writer( writer ) Sets the XML writer to use for generating XML output. Should be an instance of a class from module (({XMLRPC::XMLWriter})). If this method is not called, then (({XMLRPC::Config::DEFAULT_WRITER})) is used. --- XMLRPC::Client#set_parser( parser ) Sets the XML parser to use for parsing XML documents. Should be an instance of a class from module (({XMLRPC::XMLParser})). If this method is not called, then (({XMLRPC::Config::DEFAULT_PARSER})) is used. --- XMLRPC::Client#cookie --- XMLRPC::Client#cookie= (cookieString) Get and set the HTTP Cookie header. --- XMLRPC::Client#http_header_extra= (additionalHeaders) Set extra HTTP headers that are included in the request. --- XMLRPC::Client#http_header_extra Access the via (()) assigned header. --- XMLRPC::Client#http_last_response Returns the (({Net::HTTPResponse})) object of the last RPC. = XMLRPC::Client::Proxy == Synopsis require "xmlrpc/client" server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) michael = server.proxy("michael") michael2 = server.proxy("michael", 4) # both calls should return the same value '9'. p michael.add(4,5) p michael2.add(5) == Description Class (({XMLRPC::Client::Proxy})) makes XML-RPC calls look nicer! You can call any method onto objects of that class - the object handles (({method_missing})) and will forward the method call to a XML-RPC server. Don't use this class directly, but use instead method (()) or (()). == Class Methods --- XMLRPC::Client::Proxy.new( server, prefix, args=[], meth=:call, delim="." ) Creates an object which provides (({method_missing})). ((|server|)) must be of type (({XMLRPC::Client})), which is the XML-RPC server to be used for a XML-RPC call. ((|prefix|)) and ((|delim|)) will be prepended to the methodname called onto this object. Parameter ((|meth|)) is the method (call, call2, call_async, call2_async) to use for a RPC. ((|args|)) are arguments which are automatically given to every XML-RPC call before the arguments provides through (({method_missing})). == Instance Methods Every method call is forwarded to the XML-RPC server defined in (()). Note: Inherited methods from class (({Object})) cannot be used as XML-RPC names, because they get around (({method_missing})). = History $Id$ =end require "xmlrpc/parser" require "xmlrpc/create" require "xmlrpc/config" require "xmlrpc/utils" # ParserWriterChooseMixin require "net/http" module XMLRPC class Client USER_AGENT = "XMLRPC::Client (Ruby #{RUBY_VERSION})" include ParserWriterChooseMixin include ParseContentType # Constructors ------------------------------------------------------------------- def initialize(host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil, user=nil, password=nil, use_ssl=nil, timeout=nil) @http_header_extra = nil @http_last_response = nil @cookie = nil @host = host || "localhost" @path = path || "/RPC2" @proxy_host = proxy_host @proxy_port = proxy_port @proxy_host ||= 'localhost' if @proxy_port != nil @proxy_port ||= 8080 if @proxy_host != nil @use_ssl = use_ssl || false @timeout = timeout || 30 if use_ssl require "net/https" @port = port || 443 else @port = port || 80 end @user, @password = user, password set_auth # convert ports to integers @port = @port.to_i if @port != nil @proxy_port = @proxy_port.to_i if @proxy_port != nil # HTTP object for synchronous calls Net::HTTP.version_1_2 @http = Net::HTTP.new(@host, @port, @proxy_host, @proxy_port) @http.use_ssl = @use_ssl if @use_ssl @http.read_timeout = @timeout @http.open_timeout = @timeout @parser = nil @create = nil end class << self def new2(uri, proxy=nil, timeout=nil) if match = /^([^:]+):\/\/(([^@]+)@)?([^\/]+)(\/.*)?$/.match(uri) proto = match[1] user, passwd = (match[3] || "").split(":") host, port = match[4].split(":") path = match[5] if proto != "http" and proto != "https" raise "Wrong protocol specified. Only http or https allowed!" end else raise "Wrong URI as parameter!" end proxy_host, proxy_port = (proxy || "").split(":") self.new(host, path, port, proxy_host, proxy_port, user, passwd, (proto == "https"), timeout) end alias new_from_uri new2 def new3(hash={}) # convert all keys into lowercase strings h = {} hash.each { |k,v| h[k.to_s.downcase] = v } self.new(h['host'], h['path'], h['port'], h['proxy_host'], h['proxy_port'], h['user'], h['password'], h['use_ssl'], h['timeout']) end alias new_from_hash new3 end # Attribute Accessors ------------------------------------------------------------------- # add additional HTTP headers to the request attr_accessor :http_header_extra # makes last HTTP response accessible attr_reader :http_last_response # Cookie support attr_accessor :cookie attr_reader :timeout, :user, :password def timeout=(new_timeout) @timeout = new_timeout @http.read_timeout = @timeout @http.open_timeout = @timeout end def user=(new_user) @user = new_user set_auth end def password=(new_password) @password = new_password set_auth end # Call methods -------------------------------------------------------------- def call(method, *args) ok, param = call2(method, *args) if ok param else raise param end end def call2(method, *args) request = create().methodCall(method, *args) data = do_rpc(request, false) parser().parseMethodResponse(data) end def call_async(method, *args) ok, param = call2_async(method, *args) if ok param else raise param end end def call2_async(method, *args) request = create().methodCall(method, *args) data = do_rpc(request, true) parser().parseMethodResponse(data) end # Multicall methods -------------------------------------------------------------- def multicall(*methods) ok, params = multicall2(*methods) if ok params else raise params end end def multicall2(*methods) gen_multicall(methods, false) end def multicall_async(*methods) ok, params = multicall2_async(*methods) if ok params else raise params end end def multicall2_async(*methods) gen_multicall(methods, true) end # Proxy generating methods ------------------------------------------ def proxy(prefix=nil, *args) Proxy.new(self, prefix, args, :call) end def proxy2(prefix=nil, *args) Proxy.new(self, prefix, args, :call2) end def proxy_async(prefix=nil, *args) Proxy.new(self, prefix, args, :call_async) end def proxy2_async(prefix=nil, *args) Proxy.new(self, prefix, args, :call2_async) end private # ---------------------------------------------------------- def set_auth if @user.nil? @auth = nil else a = "#@user" a << ":#@password" if @password != nil @auth = ("Basic " + [a].pack("m")).chomp end end def do_rpc(request, async=false) header = { "User-Agent" => USER_AGENT, "Content-Type" => "text/xml; charset=utf-8", "Content-Length" => request.size.to_s, "Connection" => (async ? "close" : "keep-alive") } header["Cookie"] = @cookie if @cookie header.update(@http_header_extra) if @http_header_extra if @auth != nil # add authorization header header["Authorization"] = @auth end resp = nil @http_last_response = nil if async # use a new HTTP object for each call Net::HTTP.version_1_2 http = Net::HTTP.new(@host, @port, @proxy_host, @proxy_port) http.use_ssl = @use_ssl if @use_ssl http.read_timeout = @timeout http.open_timeout = @timeout # post request http.start { resp = http.post2(@path, request, header) } else # reuse the HTTP object for each call => connection alive is possible # we must start connection explicitely first time so that http.request # does not assume that we don't want keepalive @http.start if not @http.started? # post request resp = @http.post2(@path, request, header) end @http_last_response = resp data = resp.body if resp.code == "401" # Authorization Required raise "Authorization failed.\nHTTP-Error: #{resp.code} #{resp.message}" elsif resp.code[0,1] != "2" raise "HTTP-Error: #{resp.code} #{resp.message}" end ct = parse_content_type(resp["Content-Type"]).first if ct != "text/xml" if ct == "text/html" raise "Wrong content-type (received '#{ct}' but expected 'text/xml'): \n#{data}" else raise "Wrong content-type (received '#{ct}' but expected 'text/xml')" end end expected = resp["Content-Length"] || "" if data.nil? or data.size == 0 raise "Wrong size. Was #{data.size}, should be #{expected}" elsif expected != "" and expected.to_i != data.size and resp["Transfer-Encoding"].nil? raise "Wrong size. Was #{data.size}, should be #{expected}" end set_cookies = resp.get_fields("Set-Cookie") if set_cookies and !set_cookies.empty? require 'webrick/cookie' @cookie = set_cookies.collect do |set_cookie| cookie = WEBrick::Cookie.parse_set_cookie(set_cookie) WEBrick::Cookie.new(cookie.name, cookie.value).to_s end.join("; ") end return data end def gen_multicall(methods=[], async=false) meth = :call2 meth = :call2_async if async ok, params = self.send(meth, "system.multicall", methods.collect {|m| {'methodName' => m[0], 'params' => m[1..-1]} } ) if ok params = params.collect do |param| if param.is_a? Array param[0] elsif param.is_a? Hash XMLRPC::FaultException.new(param["faultCode"], param["faultString"]) else raise "Wrong multicall return value" end end end return ok, params end class Proxy def initialize(server, prefix, args=[], meth=:call, delim=".") @server = server @prefix = prefix ? prefix + delim : "" @args = args @meth = meth end def method_missing(mid, *args) pre = @prefix + mid.to_s arg = @args + args @server.send(@meth, pre, *arg) end end # class Proxy end # class Client end # module XMLRPC ================================================ FILE: lib/xmlrpc/config.rb ================================================ # # $Id$ # Configuration file for XML-RPC for Ruby # module XMLRPC module Config DEFAULT_WRITER = XMLWriter::Simple # or XMLWriter::XMLParser # available parser: # * XMLParser::NQXMLTreeParser # * XMLParser::NQXMLStreamParser # * XMLParser::XMLTreeParser # * XMLParser::XMLStreamParser (fastest) # * XMLParser::REXMLStreamParser # * XMLParser::XMLScanStreamParser DEFAULT_PARSER = XMLParser::REXMLStreamParser # enable tag ENABLE_NIL_CREATE = false ENABLE_NIL_PARSER = false # allows integers greater than 32-bit if true ENABLE_BIGINT = false # enable marshalling ruby objects which include XMLRPC::Marshallable ENABLE_MARSHALLING = true # enable multiCall extension by default ENABLE_MULTICALL = false # enable Introspection extension by default ENABLE_INTROSPECTION = false end end ================================================ FILE: lib/xmlrpc/create.rb ================================================ # # Creates XML-RPC call/response documents # # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id$ # require "date" require "xmlrpc/base64" module XMLRPC module XMLWriter class Abstract def ele(name, *children) element(name, nil, *children) end def tag(name, txt) element(name, nil, text(txt)) end end class Simple < Abstract def document_to_str(doc) doc end def document(*params) params.join("") end def pi(name, *params) "" end def element(name, attrs, *children) raise "attributes not yet implemented" unless attrs.nil? if children.empty? "<#{name}/>" else "<#{name}>" + children.join("") + "" end end def text(txt) cleaned = txt.dup cleaned.gsub!(/&/, '&') cleaned.gsub!(//, '>') cleaned end end # class Simple class XMLParser < Abstract def initialize require "xmltreebuilder" end def document_to_str(doc) doc.to_s end def document(*params) XML::SimpleTree::Document.new(*params) end def pi(name, *params) XML::SimpleTree::ProcessingInstruction.new(name, *params) end def element(name, attrs, *children) XML::SimpleTree::Element.new(name, attrs, *children) end def text(txt) XML::SimpleTree::Text.new(txt) end end # class XMLParser Classes = [Simple, XMLParser] # yields an instance of each installed XML writer def self.each_installed_writer XMLRPC::XMLWriter::Classes.each do |klass| begin yield klass.new rescue LoadError end end end end # module XMLWriter class Create def initialize(xml_writer = nil) @writer = xml_writer || Config::DEFAULT_WRITER.new end def methodCall(name, *params) name = name.to_s if name !~ /[a-zA-Z0-9_.:\/]+/ raise ArgumentError, "Wrong XML-RPC method-name" end parameter = params.collect do |param| @writer.ele("param", conv2value(param)) end tree = @writer.document( @writer.pi("xml", 'version="1.0"'), @writer.ele("methodCall", @writer.tag("methodName", name), @writer.ele("params", *parameter) ) ) @writer.document_to_str(tree) + "\n" end # # generates a XML-RPC methodResponse document # # if is_ret == false then the params array must # contain only one element, which is a structure # of a fault return-value. # # if is_ret == true then a normal # return-value of all the given params is created. # def methodResponse(is_ret, *params) if is_ret resp = params.collect do |param| @writer.ele("param", conv2value(param)) end resp = [@writer.ele("params", *resp)] else if params.size != 1 or params[0] === XMLRPC::FaultException raise ArgumentError, "no valid fault-structure given" end resp = @writer.ele("fault", conv2value(params[0].to_h)) end tree = @writer.document( @writer.pi("xml", 'version="1.0"'), @writer.ele("methodResponse", resp) ) @writer.document_to_str(tree) + "\n" end ##################################### private ##################################### # # converts a Ruby object into # a XML-RPC tag # def conv2value(param) val = case param when Fixnum @writer.tag("i4", param.to_s) when Bignum if Config::ENABLE_BIGINT @writer.tag("i4", param.to_s) else if param >= -(2**31) and param <= (2**31-1) @writer.tag("i4", param.to_s) else raise "Bignum is too big! Must be signed 32-bit integer!" end end when TrueClass, FalseClass @writer.tag("boolean", param ? "1" : "0") when String @writer.tag("string", param) when Symbol @writer.tag("string", param.to_s) when NilClass if Config::ENABLE_NIL_CREATE @writer.ele("nil") else raise "Wrong type NilClass. Not allowed!" end when Float @writer.tag("double", param.to_s) when Struct h = param.members.collect do |key| value = param[key] @writer.ele("member", @writer.tag("name", key.to_s), conv2value(value) ) end @writer.ele("struct", *h) when Hash # TODO: can a Hash be empty? h = param.collect do |key, value| @writer.ele("member", @writer.tag("name", key.to_s), conv2value(value) ) end @writer.ele("struct", *h) when Array # TODO: can an Array be empty? a = param.collect {|v| conv2value(v) } @writer.ele("array", @writer.ele("data", *a) ) when Time, Date, ::DateTime @writer.tag("dateTime.iso8601", param.strftime("%Y%m%dT%H:%M:%S")) when XMLRPC::DateTime @writer.tag("dateTime.iso8601", format("%.4d%02d%02dT%02d:%02d:%02d", *param.to_a)) when XMLRPC::Base64 @writer.tag("base64", param.encoded) else if Config::ENABLE_MARSHALLING and param.class.included_modules.include? XMLRPC::Marshallable # convert Ruby object into Hash ret = {"___class___" => param.class.name} param.instance_variables.each {|v| name = v[1..-1] val = param.instance_variable_get(v) if val.nil? ret[name] = val if Config::ENABLE_NIL_CREATE else ret[name] = val end } return conv2value(ret) else ok, pa = wrong_type(param) if ok return conv2value(pa) else raise "Wrong type!" end end end @writer.ele("value", val) end def wrong_type(value) false end end # class Create end # module XMLRPC ================================================ FILE: lib/xmlrpc/datetime.rb ================================================ =begin = xmlrpc/datetime.rb Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) Released under the same term of license as Ruby. = Classes * (()) = XMLRPC::DateTime == Description This class is important to handle XMLRPC (('dateTime.iso8601')) values, correcly, because normal UNIX-dates (class (({Date}))) only handle dates from year 1970 on, and class (({Time})) handles dates without the time component. (({XMLRPC::DateTime})) is able to store a XMLRPC (('dateTime.iso8601')) value correctly. == Class Methods --- XMLRPC::DateTime.new( year, month, day, hour, min, sec ) Creates a new (({XMLRPC::DateTime})) instance with the parameters ((|year|)), ((|month|)), ((|day|)) as date and ((|hour|)), ((|min|)), ((|sec|)) as time. Raises (({ArgumentError})) if a parameter is out of range, or ((|year|)) is not of type (({Integer})). == Instance Methods --- XMLRPC::DateTime#year --- XMLRPC::DateTime#month --- XMLRPC::DateTime#day --- XMLRPC::DateTime#hour --- XMLRPC::DateTime#min --- XMLRPC::DateTime#sec Return the value of the specified date/time component. --- XMLRPC::DateTime#mon Alias for (()). --- XMLRPC::DateTime#year=( value ) --- XMLRPC::DateTime#month=( value ) --- XMLRPC::DateTime#day=( value ) --- XMLRPC::DateTime#hour=( value ) --- XMLRPC::DateTime#min=( value ) --- XMLRPC::DateTime#sec=( value ) Set ((|value|)) as the new date/time component. Raises (({ArgumentError})) if ((|value|)) is out of range, or in the case of (({XMLRPC::DateTime#year=})) if ((|value|)) is not of type (({Integer})). --- XMLRPC::DateTime#mon=( value ) Alias for (()). --- XMLRPC::DateTime#to_time Return a (({Time})) object of the date/time which (({self})) represents. If the (('year')) is below 1970, this method returns (({nil})), because (({Time})) cannot handle years below 1970. The used timezone is GMT. --- XMLRPC::DateTime#to_date Return a (({Date})) object of the date which (({self})) represents. The (({Date})) object do ((*not*)) contain the time component (only date). --- XMLRPC::DateTime#to_a Returns all date/time components in an array. Returns (({[year, month, day, hour, min, sec]})). =end require "date" module XMLRPC class DateTime attr_reader :year, :month, :day, :hour, :min, :sec def year= (value) raise ArgumentError, "date/time out of range" unless value.is_a? Integer @year = value end def month= (value) raise ArgumentError, "date/time out of range" unless (1..12).include? value @month = value end def day= (value) raise ArgumentError, "date/time out of range" unless (1..31).include? value @day = value end def hour= (value) raise ArgumentError, "date/time out of range" unless (0..24).include? value @hour = value end def min= (value) raise ArgumentError, "date/time out of range" unless (0..59).include? value @min = value end def sec= (value) raise ArgumentError, "date/time out of range" unless (0..59).include? value @sec = value end alias mon month alias mon= month= def initialize(year, month, day, hour, min, sec) self.year, self.month, self.day = year, month, day self.hour, self.min, self.sec = hour, min, sec end def to_time if @year >= 1970 Time.gm(*to_a) else nil end end def to_date Date.new(*to_a[0,3]) end def to_a [@year, @month, @day, @hour, @min, @sec] end def ==(o) Array(self) == Array(o) end end end # module XMLRPC =begin = History $Id$ =end ================================================ FILE: lib/xmlrpc/httpserver.rb ================================================ # # Implements a simple HTTP-server by using John W. Small's (jsmall@laser.net) # ruby-generic-server. # # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id$ # require "gserver" class HttpServer < GServer ## # handle_obj specifies the object, that receives calls to request_handler # and ip_auth_handler def initialize(handle_obj, port = 8080, host = DEFAULT_HOST, maxConnections = 4, stdlog = $stdout, audit = true, debug = true) @handler = handle_obj super(port, host, maxConnections, stdlog, audit, debug) end private # Constants ----------------------------------------------- CRLF = "\r\n" HTTP_PROTO = "HTTP/1.0" SERVER_NAME = "HttpServer (Ruby #{RUBY_VERSION})" DEFAULT_HEADER = { "Server" => SERVER_NAME } ## # Mapping of status code and error message # StatusCodeMapping = { 200 => "OK", 400 => "Bad Request", 403 => "Forbidden", 405 => "Method Not Allowed", 411 => "Length Required", 500 => "Internal Server Error" } # Classes ------------------------------------------------- class Request attr_reader :data, :header, :method, :path, :proto def initialize(data, method=nil, path=nil, proto=nil) @header, @data = Table.new, data @method, @path, @proto = method, path, proto end def content_length len = @header['Content-Length'] return nil if len.nil? return len.to_i end end class Response attr_reader :header attr_accessor :body, :status, :status_message def initialize(status=200) @status = status @status_message = nil @header = Table.new end end ## # a case-insensitive Hash class for HTTP header # class Table include Enumerable def initialize(hash={}) @hash = hash update(hash) end def [](key) @hash[key.to_s.capitalize] end def []=(key, value) @hash[key.to_s.capitalize] = value end def update(hash) hash.each {|k,v| self[k] = v} self end def each @hash.each {|k,v| yield k.capitalize, v } end def writeTo(port) each { |k,v| port << "#{k}: #{v}" << CRLF } end end # class Table # Helper Methods ------------------------------------------ def http_header(header=nil) new_header = Table.new(DEFAULT_HEADER) new_header.update(header) unless header.nil? new_header["Connection"] = "close" new_header["Date"] = http_date(Time.now) new_header end def http_date( aTime ) aTime.gmtime.strftime( "%a, %d %b %Y %H:%M:%S GMT" ) end def http_resp(status_code, status_message=nil, header=nil, body=nil) status_message ||= StatusCodeMapping[status_code] str = "" str << "#{HTTP_PROTO} #{status_code} #{status_message}" << CRLF http_header(header).writeTo(str) str << CRLF str << body unless body.nil? str end # Main Serve Loop ----------------------------------------- def serve(io) # perform IP authentification unless @handler.ip_auth_handler(io) io << http_resp(403, "Forbidden") return end # parse first line if io.gets =~ /^(\S+)\s+(\S+)\s+(\S+)/ request = Request.new(io, $1, $2, $3) else io << http_resp(400, "Bad Request") return end # parse HTTP headers while (line=io.gets) !~ /^(\n|\r)/ if line =~ /^([\w-]+):\s*(.*)$/ request.header[$1] = $2.strip end end io.binmode response = Response.new # execute request handler @handler.request_handler(request, response) # write response back to the client io << http_resp(response.status, response.status_message, response.header, response.body) rescue Exception => e io << http_resp(500, "Internal Server Error") end end # class HttpServer ================================================ FILE: lib/xmlrpc/marshal.rb ================================================ # # Marshalling of XML-RPC methodCall and methodResponse # # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id$ # require "xmlrpc/parser" require "xmlrpc/create" require "xmlrpc/config" require "xmlrpc/utils" module XMLRPC class Marshal include ParserWriterChooseMixin # class methods ------------------------------- class << self def dump_call( methodName, *params ) new.dump_call( methodName, *params ) end def dump_response( param ) new.dump_response( param ) end def load_call( stringOrReadable ) new.load_call( stringOrReadable ) end def load_response( stringOrReadable ) new.load_response( stringOrReadable ) end alias dump dump_response alias load load_response end # class self # instance methods ---------------------------- def initialize( parser = nil, writer = nil ) set_parser( parser ) set_writer( writer ) end def dump_call( methodName, *params ) create.methodCall( methodName, *params ) end def dump_response( param ) create.methodResponse( ! param.kind_of?( XMLRPC::FaultException ) , param ) end ## # returns [ methodname, params ] # def load_call( stringOrReadable ) parser.parseMethodCall( stringOrReadable ) end ## # returns paramOrFault # def load_response( stringOrReadable ) parser.parseMethodResponse( stringOrReadable )[1] end end # class Marshal end ================================================ FILE: lib/xmlrpc/parser.rb ================================================ # # Parser for XML-RPC call and response # # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id$ # require "date" require "xmlrpc/base64" require "xmlrpc/datetime" # add some methods to NQXML::Node module NQXML class Node def removeChild(node) @children.delete(node) end def childNodes @children end def hasChildNodes not @children.empty? end def [] (index) @children[index] end def nodeType if @entity.instance_of? NQXML::Text then :TEXT elsif @entity.instance_of? NQXML::Comment then :COMMENT #elsif @entity.instance_of? NQXML::Element then :ELEMENT elsif @entity.instance_of? NQXML::Tag then :ELEMENT else :ELSE end end def nodeValue #TODO: error when wrong Entity-type @entity.text end def nodeName #TODO: error when wrong Entity-type @entity.name end end # class Node end # module NQXML module XMLRPC class FaultException < StandardError attr_reader :faultCode, :faultString alias message faultString def initialize(faultCode, faultString) @faultCode = faultCode @faultString = faultString end # returns a hash def to_h {"faultCode" => @faultCode, "faultString" => @faultString} end end module Convert def self.int(str) str.to_i end def self.boolean(str) case str when "0" then false when "1" then true else raise "RPC-value of type boolean is wrong" end end def self.double(str) str.to_f end def self.dateTime(str) case str when /^(-?\d\d\d\d)-?(\d\d)-?(\d\d)T(\d\d):(\d\d):(\d\d)(?:Z|([+-])(\d\d):?(\d\d))?$/ a = [$1, $2, $3, $4, $5, $6].collect{|i| i.to_i} if $7 ofs = $8.to_i*3600 + $9.to_i*60 ofs = -ofs if $7=='+' utc = Time.utc(*a) + ofs a = [ utc.year, utc.month, utc.day, utc.hour, utc.min, utc.sec ] end XMLRPC::DateTime.new(*a) when /^(-?\d\d)-?(\d\d)-?(\d\d)T(\d\d):(\d\d):(\d\d)(Z|([+-]\d\d):(\d\d))?$/ a = [$1, $2, $3, $4, $5, $6].collect{|i| i.to_i} if a[0] < 70 a[0] += 2000 else a[0] += 1900 end if $7 ofs = $8.to_i*3600 + $9.to_i*60 ofs = -ofs if $7=='+' utc = Time.utc(*a) + ofs a = [ utc.year, utc.month, utc.day, utc.hour, utc.min, utc.sec ] end XMLRPC::DateTime.new(*a) else raise "wrong dateTime.iso8601 format " + str end end def self.base64(str) XMLRPC::Base64.decode(str) end def self.struct(hash) # convert to marhalled object klass = hash["___class___"] if klass.nil? or Config::ENABLE_MARSHALLING == false hash else begin mod = Module klass.split("::").each {|const| mod = mod.const_get(const.strip)} obj = mod.allocate hash.delete "___class___" hash.each {|key, value| obj.instance_variable_set("@#{ key }", value) if key =~ /^([\w_][\w_0-9]*)$/ } obj rescue hash end end end def self.fault(hash) if hash.kind_of? Hash and hash.size == 2 and hash.has_key? "faultCode" and hash.has_key? "faultString" and hash["faultCode"].kind_of? Integer and hash["faultString"].kind_of? String XMLRPC::FaultException.new(hash["faultCode"], hash["faultString"]) else raise "wrong fault-structure: #{hash.inspect}" end end end # module Convert module XMLParser class AbstractTreeParser def parseMethodResponse(str) methodResponse_document(createCleanedTree(str)) end def parseMethodCall(str) methodCall_document(createCleanedTree(str)) end private # # remove all whitespaces but in the tags i4, int, boolean.... # and all comments # def removeWhitespacesAndComments(node) remove = [] childs = node.childNodes.to_a childs.each do |nd| case _nodeType(nd) when :TEXT # TODO: add nil? unless %w(i4 int boolean string double dateTime.iso8601 base64).include? node.nodeName if node.nodeName == "value" if not node.childNodes.to_a.detect {|n| _nodeType(n) == :ELEMENT}.nil? remove << nd if nd.nodeValue.strip == "" end else remove << nd if nd.nodeValue.strip == "" end end when :COMMENT remove << nd else removeWhitespacesAndComments(nd) end end remove.each { |i| node.removeChild(i) } end def nodeMustBe(node, name) cmp = case name when Array name.include?(node.nodeName) when String name == node.nodeName else raise "error" end if not cmp then raise "wrong xml-rpc (name)" end node end # # returns, when successfully the only child-node # def hasOnlyOneChild(node, name=nil) if node.childNodes.to_a.size != 1 raise "wrong xml-rpc (size)" end if name != nil then nodeMustBe(node.firstChild, name) end end def assert(b) if not b then raise "assert-fail" end end # the node `node` has empty string or string def text_zero_one(node) nodes = node.childNodes.to_a.size if nodes == 1 text(node.firstChild) elsif nodes == 0 "" else raise "wrong xml-rpc (size)" end end def integer(node) #TODO: check string for float because to_i returnsa # 0 when wrong string nodeMustBe(node, %w(i4 int)) hasOnlyOneChild(node) Convert.int(text(node.firstChild)) end def boolean(node) nodeMustBe(node, "boolean") hasOnlyOneChild(node) Convert.boolean(text(node.firstChild)) end def v_nil(node) nodeMustBe(node, "nil") assert( node.childNodes.to_a.size == 0 ) nil end def string(node) nodeMustBe(node, "string") text_zero_one(node) end def double(node) #TODO: check string for float because to_f returnsa # 0.0 when wrong string nodeMustBe(node, "double") hasOnlyOneChild(node) Convert.double(text(node.firstChild)) end def dateTime(node) nodeMustBe(node, "dateTime.iso8601") hasOnlyOneChild(node) Convert.dateTime( text(node.firstChild) ) end def base64(node) nodeMustBe(node, "base64") #hasOnlyOneChild(node) Convert.base64(text_zero_one(node)) end def member(node) nodeMustBe(node, "member") assert( node.childNodes.to_a.size == 2 ) [ name(node[0]), value(node[1]) ] end def name(node) nodeMustBe(node, "name") #hasOnlyOneChild(node) text_zero_one(node) end def array(node) nodeMustBe(node, "array") hasOnlyOneChild(node, "data") data(node.firstChild) end def data(node) nodeMustBe(node, "data") node.childNodes.to_a.collect do |val| value(val) end end def param(node) nodeMustBe(node, "param") hasOnlyOneChild(node, "value") value(node.firstChild) end def methodResponse(node) nodeMustBe(node, "methodResponse") hasOnlyOneChild(node, %w(params fault)) child = node.firstChild case child.nodeName when "params" [ true, params(child,false) ] when "fault" [ false, fault(child) ] else raise "unexpected error" end end def methodName(node) nodeMustBe(node, "methodName") hasOnlyOneChild(node) text(node.firstChild) end def params(node, call=true) nodeMustBe(node, "params") if call node.childNodes.to_a.collect do |n| param(n) end else # response (only one param) hasOnlyOneChild(node) param(node.firstChild) end end def fault(node) nodeMustBe(node, "fault") hasOnlyOneChild(node, "value") f = value(node.firstChild) Convert.fault(f) end # _nodeType is defined in the subclass def text(node) assert( _nodeType(node) == :TEXT ) assert( node.hasChildNodes == false ) assert( node.nodeValue != nil ) node.nodeValue.to_s end def struct(node) nodeMustBe(node, "struct") hash = {} node.childNodes.to_a.each do |me| n, v = member(me) hash[n] = v end Convert.struct(hash) end def value(node) nodeMustBe(node, "value") nodes = node.childNodes.to_a.size if nodes == 0 return "" elsif nodes > 1 raise "wrong xml-rpc (size)" end child = node.firstChild case _nodeType(child) when :TEXT text_zero_one(node) when :ELEMENT case child.nodeName when "i4", "int" then integer(child) when "boolean" then boolean(child) when "string" then string(child) when "double" then double(child) when "dateTime.iso8601" then dateTime(child) when "base64" then base64(child) when "struct" then struct(child) when "array" then array(child) when "nil" if Config::ENABLE_NIL_PARSER v_nil(child) else raise "wrong/unknown XML-RPC type 'nil'" end else raise "wrong/unknown XML-RPC type" end else raise "wrong type of node" end end def methodCall(node) nodeMustBe(node, "methodCall") assert( (1..2).include?( node.childNodes.to_a.size ) ) name = methodName(node[0]) if node.childNodes.to_a.size == 2 then pa = params(node[1]) else # no parameters given pa = [] end [name, pa] end end # module TreeParserMixin class AbstractStreamParser def parseMethodResponse(str) parser = @parser_class.new parser.parse(str) raise "No valid method response!" if parser.method_name != nil if parser.fault != nil # is a fault structure [false, parser.fault] else # is a normal return value raise "Missing return value!" if parser.params.size == 0 raise "Too many return values. Only one allowed!" if parser.params.size > 1 [true, parser.params[0]] end end def parseMethodCall(str) parser = @parser_class.new parser.parse(str) raise "No valid method call - missing method name!" if parser.method_name.nil? [parser.method_name, parser.params] end end module StreamParserMixin attr_reader :params attr_reader :method_name attr_reader :fault def initialize(*a) super(*a) @params = [] @values = [] @val_stack = [] @names = [] @name = [] @structs = [] @struct = {} @method_name = nil @fault = nil @data = nil end def startElement(name, attrs=[]) @data = nil case name when "value" @value = nil when "nil" raise "wrong/unknown XML-RPC type 'nil'" unless Config::ENABLE_NIL_PARSER @value = :nil when "array" @val_stack << @values @values = [] when "struct" @names << @name @name = [] @structs << @struct @struct = {} end end def endElement(name) @data ||= "" case name when "string" @value = @data when "i4", "int" @value = Convert.int(@data) when "boolean" @value = Convert.boolean(@data) when "double" @value = Convert.double(@data) when "dateTime.iso8601" @value = Convert.dateTime(@data) when "base64" @value = Convert.base64(@data) when "value" @value = @data if @value.nil? @values << (@value == :nil ? nil : @value) when "array" @value = @values @values = @val_stack.pop when "struct" @value = Convert.struct(@struct) @name = @names.pop @struct = @structs.pop when "name" @name[0] = @data when "member" @struct[@name[0]] = @values.pop when "param" @params << @values[0] @values = [] when "fault" @fault = Convert.fault(@values[0]) when "methodName" @method_name = @data end @data = nil end def character(data) if @data @data << data else @data = data end end end # module StreamParserMixin # --------------------------------------------------------------------------- class XMLStreamParser < AbstractStreamParser def initialize require "xmlparser" @parser_class = Class.new(::XMLParser) { include StreamParserMixin } end end # class XMLStreamParser # --------------------------------------------------------------------------- class NQXMLStreamParser < AbstractStreamParser def initialize require "nqxml/streamingparser" @parser_class = XMLRPCParser end class XMLRPCParser include StreamParserMixin def parse(str) parser = NQXML::StreamingParser.new(str) parser.each do |ele| case ele when NQXML::Text @data = ele.text #character(ele.text) when NQXML::Tag if ele.isTagEnd endElement(ele.name) else startElement(ele.name, ele.attrs) end end end # do end # method parse end # class XMLRPCParser end # class NQXMLStreamParser # --------------------------------------------------------------------------- class XMLTreeParser < AbstractTreeParser def initialize require "xmltreebuilder" # The new XMLParser library (0.6.2+) uses a slightly different DOM implementation. # The following code removes the differences between both versions. if defined? XML::DOM::Builder return if defined? XML::DOM::Node::DOCUMENT # code below has been already executed klass = XML::DOM::Node klass.const_set("DOCUMENT", klass::DOCUMENT_NODE) klass.const_set("TEXT", klass::TEXT_NODE) klass.const_set("COMMENT", klass::COMMENT_NODE) klass.const_set("ELEMENT", klass::ELEMENT_NODE) end end private def _nodeType(node) tp = node.nodeType if tp == XML::SimpleTree::Node::TEXT then :TEXT elsif tp == XML::SimpleTree::Node::COMMENT then :COMMENT elsif tp == XML::SimpleTree::Node::ELEMENT then :ELEMENT else :ELSE end end def methodResponse_document(node) assert( node.nodeType == XML::SimpleTree::Node::DOCUMENT ) hasOnlyOneChild(node, "methodResponse") methodResponse(node.firstChild) end def methodCall_document(node) assert( node.nodeType == XML::SimpleTree::Node::DOCUMENT ) hasOnlyOneChild(node, "methodCall") methodCall(node.firstChild) end def createCleanedTree(str) doc = XML::SimpleTreeBuilder.new.parse(str) doc.documentElement.normalize removeWhitespacesAndComments(doc) doc end end # class XMLParser # --------------------------------------------------------------------------- class NQXMLTreeParser < AbstractTreeParser def initialize require "nqxml/treeparser" end private def _nodeType(node) node.nodeType end def methodResponse_document(node) methodResponse(node) end def methodCall_document(node) methodCall(node) end def createCleanedTree(str) doc = ::NQXML::TreeParser.new(str).document.rootNode removeWhitespacesAndComments(doc) doc end end # class NQXMLTreeParser # --------------------------------------------------------------------------- class REXMLStreamParser < AbstractStreamParser def initialize require "rexml/document" @parser_class = StreamListener end class StreamListener include StreamParserMixin alias :tag_start :startElement alias :tag_end :endElement alias :text :character alias :cdata :character def method_missing(*a) # ignore end def parse(str) parser = REXML::Document.parse_stream(str, self) end end end # --------------------------------------------------------------------------- class XMLScanStreamParser < AbstractStreamParser def initialize require "xmlscan/parser" @parser_class = XMLScanParser end class XMLScanParser include StreamParserMixin Entities = { "lt" => "<", "gt" => ">", "amp" => "&", "quot" => '"', "apos" => "'" } def parse(str) parser = XMLScan::XMLParser.new(self) parser.parse(str) end alias :on_stag :startElement alias :on_etag :endElement def on_stag_end(name); end def on_stag_end_empty(name) startElement(name) endElement(name) end def on_chardata(str) character(str) end def on_cdata(str) character(str) end def on_entityref(ent) str = Entities[ent] if str character(str) else raise "unknown entity" end end def on_charref(code) character(code.chr) end def on_charref_hex(code) character(code.chr) end def method_missing(*a) end # TODO: call/implement? # valid_name? # valid_chardata? # valid_char? # parse_error end end # --------------------------------------------------------------------------- XMLParser = XMLTreeParser NQXMLParser = NQXMLTreeParser Classes = [XMLStreamParser, XMLTreeParser, NQXMLStreamParser, NQXMLTreeParser, REXMLStreamParser, XMLScanStreamParser] # yields an instance of each installed parser def self.each_installed_parser XMLRPC::XMLParser::Classes.each do |klass| begin yield klass.new rescue LoadError end end end end # module XMLParser end # module XMLRPC ================================================ FILE: lib/xmlrpc/server.rb ================================================ =begin = xmlrpc/server.rb Copyright (C) 2001, 2002, 2003, 2005 by Michael Neumann (mneumann@ntecs.de) Released under the same term of license as Ruby. = Classes * (()) * (()) * (()) * (()) * (()) = XMLRPC::BasicServer == Description Is the base class for all XML-RPC server-types (CGI, standalone). You can add handler and set a default handler. Do not use this server, as this is/should be an abstract class. === How the method to call is found The arity (number of accepted arguments) of a handler (method or (({Proc})) object) is compared to the given arguments submitted by the client for a RPC ((-Remote Procedure Call-)). A handler is only called if it accepts the number of arguments, otherwise the search for another handler will go on. When at the end no handler was found, the (()) will be called. With this technique it is possible to do overloading by number of parameters, but only for (({Proc})) handler, because you cannot define two methods of the same name in the same class. == Class Methods --- XMLRPC::BasicServer.new( class_delim="." ) Creates a new (({XMLRPC::BasicServer})) instance, which should not be done, because (({XMLRPC::BasicServer})) is an abstract class. This method should be called from a subclass indirectly by a (({super})) call in the method (({initialize})). The paramter ((|class_delim|)) is used in (()) when an object is added as handler, to delimit the object-prefix and the method-name. == Instance Methods --- XMLRPC::BasicServer#add_handler( name, signature=nil, help=nil ) { aBlock } Adds ((|aBlock|)) to the list of handlers, with ((|name|)) as the name of the method. Parameters ((|signature|)) and ((|help|)) are used by the Introspection method if specified, where ((|signature|)) is either an Array containing strings each representing a type of it's signature (the first is the return value) or an Array of Arrays if the method has multiple signatures. Value type-names are "int, boolean, double, string, dateTime.iso8601, base64, array, struct". Parameter ((|help|)) is a String with informations about how to call this method etc. A handler method or code-block can return the types listed at (()). When a method fails, it can tell it the client by throwing an (({XMLRPC::FaultException})) like in this example: s.add_handler("michael.div") do |a,b| if b == 0 raise XMLRPC::FaultException.new(1, "division by zero") else a / b end end The client gets in the case of (({b==0})) an object back of type (({XMLRPC::FaultException})) that has a ((|faultCode|)) and ((|faultString|)) field. --- XMLRPC::BasicServer#add_handler( prefix, obj ) This is the second form of (()). To add an object write: server.add_handler("michael", MyHandlerClass.new) All public methods of (({MyHandlerClass})) are accessible to the XML-RPC clients by (('michael."name of method"')). This is where the ((|class_delim|)) in (()) has it's role, a XML-RPC method-name is defined by ((|prefix|)) + ((|class_delim|)) + (('"name of method"')). --- XMLRPC::BasicServer#add_handler( interface, obj ) This is the third form of (()). Use (({XMLRPC::interface})) to generate an ServiceInterface object, which represents an interface (with signature and help text) for a handler class. Parameter ((|interface|)) must be of type (({XMLRPC::ServiceInterface})). Adds all methods of ((|obj|)) which are defined in ((|interface|)) to the server. This is the recommended way of adding services to a server! --- XMLRPC::BasicServer#get_default_handler Returns the default-handler, which is called when no handler for a method-name is found. It is a (({Proc})) object or (({nil})). --- XMLRPC::BasicServer#set_default_handler ( &handler ) Sets ((|handler|)) as the default-handler, which is called when no handler for a method-name is found. ((|handler|)) is a code-block. The default-handler is called with the (XML-RPC) method-name as first argument, and the other arguments are the parameters given by the client-call. If no block is specified the default of (({XMLRPC::BasicServer})) is used, which raises a XMLRPC::FaultException saying "method missing". --- XMLRPC::BasicServer#set_writer( writer ) Sets the XML writer to use for generating XML output. Should be an instance of a class from module (({XMLRPC::XMLWriter})). If this method is not called, then (({XMLRPC::Config::DEFAULT_WRITER})) is used. --- XMLRPC::BasicServer#set_parser( parser ) Sets the XML parser to use for parsing XML documents. Should be an instance of a class from module (({XMLRPC::XMLParser})). If this method is not called, then (({XMLRPC::Config::DEFAULT_PARSER})) is used. --- XMLRPC::BasicServer#add_introspection Adds the introspection handlers "system.listMethods", "system.methodSignature" and "system.methodHelp", where only the first one works. --- XMLRPC::BasicServer#add_multicall Adds the multi-call handler "system.multicall". --- XMLRPC::BasicServer#get_service_hook Returns the service-hook, which is called on each service request (RPC) unless it's (({nil})). --- XMLRPC::BasicServer#set_service_hook ( &handler ) A service-hook is called for each service request (RPC). You can use a service-hook for example to wrap existing methods and catch exceptions of them or convert values to values recognized by XMLRPC. You can disable it by passing (({nil})) as parameter ((|handler|)) . The service-hook is called with a (({Proc})) object and with the parameters for this (({Proc})). An example: server.set_service_hook {|obj, *args| begin ret = obj.call(*args) # call the original service-method # could convert the return value resuce # rescue exceptions end } =end require "xmlrpc/parser" require "xmlrpc/create" require "xmlrpc/config" require "xmlrpc/utils" # ParserWriterChooseMixin module XMLRPC class BasicServer include ParserWriterChooseMixin include ParseContentType ERR_METHOD_MISSING = 1 ERR_UNCAUGHT_EXCEPTION = 2 ERR_MC_WRONG_PARAM = 3 ERR_MC_MISSING_PARAMS = 4 ERR_MC_MISSING_METHNAME = 5 ERR_MC_RECURSIVE_CALL = 6 ERR_MC_WRONG_PARAM_PARAMS = 7 ERR_MC_EXPECTED_STRUCT = 8 def initialize(class_delim=".") @handler = [] @default_handler = nil @service_hook = nil @class_delim = class_delim @create = nil @parser = nil add_multicall if Config::ENABLE_MULTICALL add_introspection if Config::ENABLE_INTROSPECTION end def add_handler(prefix, obj_or_signature=nil, help=nil, &block) if block_given? # proc-handler @handler << [prefix, block, obj_or_signature, help] else if prefix.kind_of? String # class-handler raise ArgumentError, "Expected non-nil value" if obj_or_signature.nil? @handler << [prefix + @class_delim, obj_or_signature] elsif prefix.kind_of? XMLRPC::Service::BasicInterface # class-handler with interface # add all methods @handler += prefix.get_methods(obj_or_signature, @class_delim) else raise ArgumentError, "Wrong type for parameter 'prefix'" end end self end def get_service_hook @service_hook end def set_service_hook(&handler) @service_hook = handler self end def get_default_handler @default_handler end def set_default_handler (&handler) @default_handler = handler self end def add_multicall add_handler("system.multicall", %w(array array), "Multicall Extension") do |arrStructs| unless arrStructs.is_a? Array raise XMLRPC::FaultException.new(ERR_MC_WRONG_PARAM, "system.multicall expects an array") end arrStructs.collect {|call| if call.is_a? Hash methodName = call["methodName"] params = call["params"] if params.nil? multicall_fault(ERR_MC_MISSING_PARAMS, "Missing params") elsif methodName.nil? multicall_fault(ERR_MC_MISSING_METHNAME, "Missing methodName") else if methodName == "system.multicall" multicall_fault(ERR_MC_RECURSIVE_CALL, "Recursive system.multicall forbidden") else unless params.is_a? Array multicall_fault(ERR_MC_WRONG_PARAM_PARAMS, "Parameter params have to be an Array") else ok, val = call_method(methodName, *params) if ok # correct return value [val] else # exception multicall_fault(val.faultCode, val.faultString) end end end end else multicall_fault(ERR_MC_EXPECTED_STRUCT, "system.multicall expected struct") end } end # end add_handler self end def add_introspection add_handler("system.listMethods",%w(array), "List methods available on this XML-RPC server") do methods = [] @handler.each do |name, obj| if obj.kind_of? Proc methods << name else obj.class.public_instance_methods(false).each do |meth| methods << "#{name}#{meth}" end end end methods end add_handler("system.methodSignature", %w(array string), "Returns method signature") do |meth| sigs = [] @handler.each do |name, obj, sig| if obj.kind_of? Proc and sig != nil and name == meth if sig[0].kind_of? Array # sig contains multiple signatures, e.g. [["array"], ["array", "string"]] sig.each {|s| sigs << s} else # sig is a single signature, e.g. ["array"] sigs << sig end end end sigs.uniq! || sigs # remove eventually duplicated signatures end add_handler("system.methodHelp", %w(string string), "Returns help on using this method") do |meth| help = nil @handler.each do |name, obj, sig, hlp| if obj.kind_of? Proc and name == meth help = hlp break end end help || "" end self end def process(data) method, params = parser().parseMethodCall(data) handle(method, *params) end private # -------------------------------------------------------------- def multicall_fault(nr, str) {"faultCode" => nr, "faultString" => str} end # # method dispatch # def dispatch(methodname, *args) for name, obj in @handler if obj.kind_of? Proc next unless methodname == name else next unless methodname =~ /^#{name}(.+)$/ next unless obj.respond_to? $1 obj = obj.method($1) end if check_arity(obj, args.size) if @service_hook.nil? return obj.call(*args) else return @service_hook.call(obj, *args) end end end if @default_handler.nil? raise XMLRPC::FaultException.new(ERR_METHOD_MISSING, "Method #{methodname} missing or wrong number of parameters!") else @default_handler.call(methodname, *args) end end # # returns true, if the arity of "obj" matches # def check_arity(obj, n_args) ary = obj.arity if ary >= 0 n_args == ary else n_args >= (ary+1).abs end end def call_method(methodname, *args) begin [true, dispatch(methodname, *args)] rescue XMLRPC::FaultException => e [false, e] rescue Exception => e [false, XMLRPC::FaultException.new(ERR_UNCAUGHT_EXCEPTION, "Uncaught exception #{e.message} in method #{methodname}")] end end # # # def handle(methodname, *args) create().methodResponse(*call_method(methodname, *args)) end end =begin = XMLRPC::CGIServer == Synopsis require "xmlrpc/server" s = XMLRPC::CGIServer.new s.add_handler("michael.add") do |a,b| a + b end s.add_handler("michael.div") do |a,b| if b == 0 raise XMLRPC::FaultException.new(1, "division by zero") else a / b end end s.set_default_handler do |name, *args| raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + " or wrong number of parameters!") end s.serve == Description Implements a CGI-based XML-RPC server. == Superclass (()) == Class Methods --- XMLRPC::CGIServer.new( *a ) Creates a new (({XMLRPC::CGIServer})) instance. All parameters given are by-passed to (()). You can only create ((*one*)) (({XMLRPC::CGIServer})) instance, because more than one makes no sense. == Instance Methods --- XMLRPC::CGIServer#serve Call this after you have added all you handlers to the server. This method processes a XML-RPC methodCall and sends the answer back to the client. Make sure that you don't write to standard-output in a handler, or in any other part of your program, this would case a CGI-based server to fail! =end class CGIServer < BasicServer @@obj = nil def CGIServer.new(*a) @@obj = super(*a) if @@obj.nil? @@obj end def initialize(*a) super(*a) end def serve catch(:exit_serve) { length = ENV['CONTENT_LENGTH'].to_i http_error(405, "Method Not Allowed") unless ENV['REQUEST_METHOD'] == "POST" http_error(400, "Bad Request") unless parse_content_type(ENV['CONTENT_TYPE']).first == "text/xml" http_error(411, "Length Required") unless length > 0 # TODO: do we need a call to binmode? $stdin.binmode if $stdin.respond_to? :binmode data = $stdin.read(length) http_error(400, "Bad Request") if data.nil? or data.size != length http_write(process(data), "Content-type" => "text/xml; charset=utf-8") } end private def http_error(status, message) err = "#{status} #{message}" msg = <<-"MSGEND" #{err}

      #{err}

      Unexpected error occured while processing XML-RPC request!

      MSGEND http_write(msg, "Status" => err, "Content-type" => "text/html") throw :exit_serve # exit from the #serve method end def http_write(body, header) h = {} header.each {|key, value| h[key.to_s.capitalize] = value} h['Status'] ||= "200 OK" h['Content-length'] ||= body.size.to_s str = "" h.each {|key, value| str << "#{key}: #{value}\r\n"} str << "\r\n#{body}" print str end end =begin = XMLRPC::ModRubyServer == Description Implements a XML-RPC server, which works with Apache mod_ruby. Use it in the same way as CGIServer! == Superclass (()) =end class ModRubyServer < BasicServer def initialize(*a) @ap = Apache::request super(*a) end def serve catch(:exit_serve) { header = {} @ap.headers_in.each {|key, value| header[key.capitalize] = value} length = header['Content-length'].to_i http_error(405, "Method Not Allowed") unless @ap.request_method == "POST" http_error(400, "Bad Request") unless parse_content_type(header['Content-type']).first == "text/xml" http_error(411, "Length Required") unless length > 0 # TODO: do we need a call to binmode? @ap.binmode data = @ap.read(length) http_error(400, "Bad Request") if data.nil? or data.size != length http_write(process(data), 200, "Content-type" => "text/xml; charset=utf-8") } end private def http_error(status, message) err = "#{status} #{message}" msg = <<-"MSGEND" #{err}

      #{err}

      Unexpected error occured while processing XML-RPC request!

      MSGEND http_write(msg, status, "Status" => err, "Content-type" => "text/html") throw :exit_serve # exit from the #serve method end def http_write(body, status, header) h = {} header.each {|key, value| h[key.to_s.capitalize] = value} h['Status'] ||= "200 OK" h['Content-length'] ||= body.size.to_s h.each {|key, value| @ap.headers_out[key] = value } @ap.content_type = h["Content-type"] @ap.status = status.to_i @ap.send_http_header @ap.print body end end =begin = XMLRPC::Server == Synopsis require "xmlrpc/server" s = XMLRPC::Server.new(8080) s.add_handler("michael.add") do |a,b| a + b end s.add_handler("michael.div") do |a,b| if b == 0 raise XMLRPC::FaultException.new(1, "division by zero") else a / b end end s.set_default_handler do |name, *args| raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + " or wrong number of parameters!") end s.serve == Description Implements a standalone XML-RPC server. The method (({serve}))) is left if a SIGHUP is sent to the program. == Superclass (()) == Class Methods --- XMLRPC::Server.new( port=8080, host="127.0.0.1", maxConnections=4, stdlog=$stdout, audit=true, debug=true, *a ) Creates a new (({XMLRPC::Server})) instance, which is a XML-RPC server listening on port ((|port|)) and accepts requests for the host ((|host|)), which is by default only the localhost. The server is not started, to start it you have to call (()). Parameters ((|audit|)) and ((|debug|)) are obsolete! All additionally given parameters in ((|*a|)) are by-passed to (()). == Instance Methods --- XMLRPC::Server#serve Call this after you have added all you handlers to the server. This method starts the server to listen for XML-RPC requests and answer them. --- XMLRPC::Server#shutdown Stops and shuts the server down. =end class WEBrickServlet < BasicServer; end # forward declaration class Server < WEBrickServlet def initialize(port=8080, host="127.0.0.1", maxConnections=4, stdlog=$stdout, audit=true, debug=true, *a) super(*a) require 'webrick' @server = WEBrick::HTTPServer.new(:Port => port, :BindAddress => host, :MaxClients => maxConnections, :Logger => WEBrick::Log.new(stdlog)) @server.mount("/", self) end def serve if RUBY_PLATFORM =~ /mingw|mswin32/ signals = [1] else signals = %w[INT TERM HUP] end signals.each { |signal| trap(signal) { @server.shutdown } } @server.start end def shutdown @server.shutdown end end =begin = XMLRPC::WEBrickServlet == Synopsis require "webrick" require "xmlrpc/server" s = XMLRPC::WEBrickServlet.new s.add_handler("michael.add") do |a,b| a + b end s.add_handler("michael.div") do |a,b| if b == 0 raise XMLRPC::FaultException.new(1, "division by zero") else a / b end end s.set_default_handler do |name, *args| raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + " or wrong number of parameters!") end httpserver = WEBrick::HTTPServer.new(:Port => 8080) httpserver.mount("/RPC2", s) trap("HUP") { httpserver.shutdown } # use 1 instead of "HUP" on Windows httpserver.start == Instance Methods --- XMLRPC::WEBrickServlet#set_valid_ip( *ip_addr ) Specifies the valid IP addresses that are allowed to connect to the server. Each IP is either a (({String})) or a (({Regexp})). --- XMLRPC::WEBrickServlet#get_valid_ip Return the via method (()) specified valid IP addresses. == Description Implements a servlet for use with WEBrick, a pure Ruby (HTTP-) server framework. == Superclass (()) =end class WEBrickServlet < BasicServer def initialize(*a) super require "webrick/httpstatus" @valid_ip = nil end # deprecated from WEBrick/1.2.2. # but does not break anything. def require_path_info? false end def get_instance(config, *options) # TODO: set config & options self end def set_valid_ip(*ip_addr) if ip_addr.size == 1 and ip_addr[0].nil? @valid_ip = nil else @valid_ip = ip_addr end end def get_valid_ip @valid_ip end def service(request, response) if @valid_ip raise WEBrick::HTTPStatus::Forbidden unless @valid_ip.any? { |ip| request.peeraddr[3] =~ ip } end if request.request_method != "POST" raise WEBrick::HTTPStatus::MethodNotAllowed, "unsupported method `#{request.request_method}'." end if parse_content_type(request['Content-type']).first != "text/xml" raise WEBrick::HTTPStatus::BadRequest end length = (request['Content-length'] || 0).to_i raise WEBrick::HTTPStatus::LengthRequired unless length > 0 data = request.body if data.nil? or data.size != length raise WEBrick::HTTPStatus::BadRequest end resp = process(data) if resp.nil? or resp.size <= 0 raise WEBrick::HTTPStatus::InternalServerError end response.status = 200 response['Content-Length'] = resp.size response['Content-Type'] = "text/xml; charset=utf-8" response.body = resp end end end # module XMLRPC =begin = History $Id$ =end ================================================ FILE: lib/xmlrpc/utils.rb ================================================ # # Defines ParserWriterChooseMixin, which makes it possible to choose a # different XML writer and/or XML parser then the default one. # The Mixin is used in client.rb (class Client) and server.rb (class # BasicServer) # # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id$ # module XMLRPC # # This module enables a user-class to be marshalled # by XML-RPC for Ruby into a Hash, with one additional # key/value pair "___class___" => ClassName # module Marshallable end module ParserWriterChooseMixin def set_writer(writer) @create = Create.new(writer) self end def set_parser(parser) @parser = parser self end private def create # if set_writer was not already called then call it now if @create.nil? then set_writer(Config::DEFAULT_WRITER.new) end @create end def parser # if set_parser was not already called then call it now if @parser.nil? then set_parser(Config::DEFAULT_PARSER.new) end @parser end end # module ParserWriterChooseMixin module Service # # base class for Service Interface definitions, used # by BasicServer#add_handler # class BasicInterface attr_reader :prefix, :methods def initialize(prefix) @prefix = prefix @methods = [] end def add_method(sig, help=nil, meth_name=nil) mname = nil sig = [sig] if sig.kind_of? String sig = sig.collect do |s| name, si = parse_sig(s) raise "Wrong signatures!" if mname != nil and name != mname mname = name si end @methods << [mname, meth_name || mname, sig, help] end private # --------------------------------- def parse_sig(sig) # sig is a String if sig =~ /^\s*(\w+)\s+([^(]+)(\(([^)]*)\))?\s*$/ params = [$1] name = $2.strip $4.split(",").each {|i| params << i.strip} if $4 != nil return name, params else raise "Syntax error in signature" end end end # class BasicInterface # # class which wraps a Service Interface definition, used # by BasicServer#add_handler # class Interface < BasicInterface def initialize(prefix, &p) raise "No interface specified" if p.nil? super(prefix) instance_eval(&p) end def get_methods(obj, delim=".") prefix = @prefix + delim @methods.collect { |name, meth, sig, help| [prefix + name, obj.method(meth).to_proc, sig, help] } end private # --------------------------------- def meth(*a) add_method(*a) end end # class Interface class PublicInstanceMethodsInterface < BasicInterface def initialize(prefix) super(prefix) end def get_methods(obj, delim=".") prefix = @prefix + delim obj.class.public_instance_methods(false).collect { |name| [prefix + name, obj.method(name).to_proc, nil, nil] } end end end # module Service # # short-form to create a Service::Interface # def self.interface(prefix, &p) Service::Interface.new(prefix, &p) end # short-cut for creating a PublicInstanceMethodsInterface def self.iPIMethods(prefix) Service::PublicInstanceMethodsInterface.new(prefix) end module ParseContentType def parse_content_type(str) a, *b = str.split(";") return a.strip.downcase, *b end end end # module XMLRPC ================================================ FILE: lib/xsd/charset.rb ================================================ # XSD4R - Charset handling library. # Copyright (C) 2001, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module XSD module Charset @internal_encoding = $KCODE class XSDError < StandardError; end class CharsetError < XSDError; end class UnknownCharsetError < CharsetError; end class CharsetConversionError < CharsetError; end public ### ## Maps # EncodingConvertMap = {} def Charset.init EncodingConvertMap[['UTF8', 'X_ISO8859_1']] = Proc.new { |str| str.unpack('U*').pack('C*') } EncodingConvertMap[['X_ISO8859_1', 'UTF8']] = Proc.new { |str| str.unpack('C*').pack('U*') } begin require 'xsd/iconvcharset' @internal_encoding = 'UTF8' sjtag = (/(mswin|bccwin|mingw|cygwin|emx)/ =~ RUBY_PLATFORM) ? 'cp932' : 'shift_jis' EncodingConvertMap[['UTF8', 'EUC' ]] = Proc.new { |str| IconvCharset.safe_iconv("euc-jp", "utf-8", str) } EncodingConvertMap[['EUC' , 'UTF8']] = Proc.new { |str| IconvCharset.safe_iconv("utf-8", "euc-jp", str) } EncodingConvertMap[['EUC' , 'SJIS']] = Proc.new { |str| IconvCharset.safe_iconv(sjtag, "euc-jp", str) } EncodingConvertMap[['UTF8', 'SJIS']] = Proc.new { |str| IconvCharset.safe_iconv(sjtag, "utf-8", str) } EncodingConvertMap[['SJIS', 'UTF8']] = Proc.new { |str| IconvCharset.safe_iconv("utf-8", sjtag, str) } EncodingConvertMap[['SJIS', 'EUC' ]] = Proc.new { |str| IconvCharset.safe_iconv("euc-jp", sjtag, str) } rescue LoadError begin require 'nkf' EncodingConvertMap[['EUC' , 'SJIS']] = Proc.new { |str| NKF.nkf('-sXm0', str) } EncodingConvertMap[['SJIS', 'EUC' ]] = Proc.new { |str| NKF.nkf('-eXm0', str) } rescue LoadError end begin require 'uconv' @internal_encoding = 'UTF8' EncodingConvertMap[['UTF8', 'EUC' ]] = Uconv.method(:u8toeuc) EncodingConvertMap[['UTF8', 'SJIS']] = Uconv.method(:u8tosjis) EncodingConvertMap[['EUC' , 'UTF8']] = Uconv.method(:euctou8) EncodingConvertMap[['SJIS', 'UTF8']] = Uconv.method(:sjistou8) rescue LoadError end end end self.init CharsetMap = { 'NONE' => 'us-ascii', 'EUC' => 'euc-jp', 'SJIS' => 'shift_jis', 'UTF8' => 'utf-8', 'X_ISO_8859_1' => 'iso-8859-1', 'X_UNKNOWN' => nil, } ### ## handlers # def Charset.encoding @internal_encoding end def Charset.encoding=(encoding) warn("xsd charset is set to #{encoding}") if $DEBUG @internal_encoding = encoding end def Charset.xml_encoding_label charset_label(@internal_encoding) end def Charset.encoding_to_xml(str, charset) encoding_conv(str, @internal_encoding, charset_str(charset)) end def Charset.encoding_from_xml(str, charset) encoding_conv(str, charset_str(charset), @internal_encoding) end def Charset.encoding_conv(str, enc_from, enc_to) if enc_from == enc_to or enc_from == 'NONE' or enc_to == 'NONE' str elsif converter = EncodingConvertMap[[enc_from, enc_to]] converter.call(str) else raise CharsetConversionError.new( "Converter not found: #{enc_from} -> #{enc_to}") end end def Charset.charset_label(encoding) CharsetMap[encoding.upcase] end def Charset.charset_str(label) if CharsetMap.respond_to?(:key) CharsetMap.key(label.downcase) || 'X_UNKNOWN' else CharsetMap.index(label.downcase) || 'X_UNKNOWN' end end # us_ascii = '[\x00-\x7F]' us_ascii = '[\x9\xa\xd\x20-\x7F]' # XML 1.0 restricted. USASCIIRegexp = Regexp.new("\\A#{us_ascii}*\\z", nil, "NONE") twobytes_euc = '(?:[\x8E\xA1-\xFE][\xA1-\xFE])' threebytes_euc = '(?:\x8F[\xA1-\xFE][\xA1-\xFE])' character_euc = "(?:#{us_ascii}|#{twobytes_euc}|#{threebytes_euc})" EUCRegexp = Regexp.new("\\A#{character_euc}*\\z", nil, "NONE") # onebyte_sjis = '[\x00-\x7F\xA1-\xDF]' onebyte_sjis = '[\x9\xa\xd\x20-\x7F\xA1-\xDF]' # XML 1.0 restricted. twobytes_sjis = '(?:[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])' character_sjis = "(?:#{onebyte_sjis}|#{twobytes_sjis})" SJISRegexp = Regexp.new("\\A#{character_sjis}*\\z", nil, "NONE") # 0xxxxxxx # 110yyyyy 10xxxxxx twobytes_utf8 = '(?:[\xC0-\xDF][\x80-\xBF])' # 1110zzzz 10yyyyyy 10xxxxxx threebytes_utf8 = '(?:[\xE0-\xEF][\x80-\xBF][\x80-\xBF])' # 11110uuu 10uuuzzz 10yyyyyy 10xxxxxx fourbytes_utf8 = '(?:[\xF0-\xF7][\x80-\xBF][\x80-\xBF][\x80-\xBF])' character_utf8 = "(?:#{us_ascii}|#{twobytes_utf8}|#{threebytes_utf8}|#{fourbytes_utf8})" UTF8Regexp = Regexp.new("\\A#{character_utf8}*\\z", nil, "NONE") def Charset.is_us_ascii(str) USASCIIRegexp =~ str end def Charset.is_utf8(str) UTF8Regexp =~ str end def Charset.is_euc(str) EUCRegexp =~ str end def Charset.is_sjis(str) SJISRegexp =~ str end def Charset.is_ces(str, code = $KCODE) case code when 'NONE' is_us_ascii(str) when 'UTF8' is_utf8(str) when 'EUC' is_euc(str) when 'SJIS' is_sjis(str) else raise UnknownCharsetError.new("Unknown charset: #{code}") end end end end ================================================ FILE: lib/xsd/codegen/classdef.rb ================================================ # XSD4R - Generating class definition code # Copyright (C) 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/codegen/gensupport' require 'xsd/codegen/moduledef' require 'xsd/codegen/methoddef' module XSD module CodeGen class ClassDef < ModuleDef include GenSupport def initialize(name, baseclass = nil) super(name) @baseclass = baseclass @classvar = [] @attrdef = [] end def def_classvar(var, value) var = var.sub(/\A@@/, "") unless safevarname?(var) raise ArgumentError.new("#{var} seems to be unsafe") end @classvar << [var, value] end def def_attr(attrname, writable = true, varname = nil) unless safevarname?(varname || attrname) raise ArgumentError.new("#{varname || attrname} seems to be unsafe") end @attrdef << [attrname, writable, varname] end def dump buf = "" unless @requirepath.empty? buf << dump_requirepath end buf << dump_emptyline unless buf.empty? package = @name.split(/::/)[0..-2] buf << dump_package_def(package) unless package.empty? buf << dump_comment if @comment buf << dump_class_def spacer = false unless @classvar.empty? spacer = true buf << dump_classvar end unless @const.empty? buf << dump_emptyline if spacer spacer = true buf << dump_const end unless @code.empty? buf << dump_emptyline if spacer spacer = true buf << dump_code end unless @attrdef.empty? buf << dump_emptyline if spacer spacer = true buf << dump_attributes end unless @methoddef.empty? buf << dump_emptyline if spacer spacer = true buf << dump_methods end buf << dump_class_def_end buf << dump_package_def_end(package) unless package.empty? buf.gsub(/^\s+$/, '') end private def dump_class_def name = @name.to_s.split(/::/) if @baseclass format("class #{name.last} < #{@baseclass}") else format("class #{name.last}") end end def dump_class_def_end str = format("end") end def dump_classvar dump_static( @classvar.collect { |var, value| %Q(@@#{var.sub(/^@@/, "")} = #{dump_value(value)}) }.join("\n") ) end def dump_attributes str = "" @attrdef.each do |attrname, writable, varname| varname ||= attrname if attrname == varname str << format(dump_accessor(attrname, writable), 2) end end @attrdef.each do |attrname, writable, varname| varname ||= attrname if attrname != varname str << "\n" unless str.empty? str << format(dump_attribute(attrname, writable, varname), 2) end end str end def dump_accessor(attrname, writable) if writable "attr_accessor :#{attrname}" else "attr_reader :#{attrname}" end end def dump_attribute(attrname, writable, varname) str = nil mr = MethodDef.new(attrname) mr.definition = "@#{varname}" str = mr.dump if writable mw = MethodDef.new(attrname + "=", 'value') mw.definition = "@#{varname} = value" str << "\n" + mw.dump end str end end end end if __FILE__ == $0 require 'xsd/codegen/classdef' include XSD::CodeGen c = ClassDef.new("Foo::Bar::HobbitName", String) c.def_require("foo/bar") c.comment = <<-EOD foo bar baz EOD c.def_const("FOO", 1) c.def_classvar("@@foo", "var".dump) c.def_classvar("baz", "1".dump) c.def_attr("Foo", true, "foo") c.def_attr("bar") c.def_attr("baz", true) c.def_attr("Foo2", true, "foo2") c.def_attr("foo3", false, "foo3") c.def_method("foo") do <<-EOD foo.bar = 1 \tbaz.each do |ele| \t ele end EOD end c.def_method("baz", "qux") do <<-EOD [1, 2, 3].each do |i| p i end EOD end m = MethodDef.new("qux", "quxx", "quxxx") do <<-EOD p quxx + quxxx EOD end m.comment = "hello world\n123" c.add_method(m) c.def_code <<-EOD Foo.new Bar.z EOD c.def_code <<-EOD Foo.new Bar.z EOD c.def_privatemethod("foo", "baz", "*arg", "&block") puts c.dump end ================================================ FILE: lib/xsd/codegen/commentdef.rb ================================================ # XSD4R - Generating comment definition code # Copyright (C) 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/codegen/gensupport' module XSD module CodeGen module CommentDef include GenSupport attr_accessor :comment private def dump_comment if /\A#/ =~ @comment format(@comment) else format(@comment).gsub(/^/, '# ') end end end end end ================================================ FILE: lib/xsd/codegen/gensupport.rb ================================================ # XSD4R - Code generation support # Copyright (C) 2004, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module XSD module CodeGen # from the file 'keywords' in 1.9. KEYWORD = {} %w( __LINE__ __FILE__ BEGIN END alias and begin break case class def defined? do else elsif end ensure false for if in module next nil not or redo rescue retry return self super then true undef unless until when while yield ).each { |k| KEYWORD[k] = nil } module GenSupport def capitalize(target) target.sub(/^([a-z])/) { $1.tr!('[a-z]', '[A-Z]') } end module_function :capitalize def uncapitalize(target) target.sub(/^([A-Z])/) { $1.tr!('[A-Z]', '[a-z]') } end module_function :uncapitalize def safeconstname(name) safename = name.scan(/[a-zA-Z0-9_]+/).collect { |ele| GenSupport.capitalize(ele) }.join if /^[A-Z]/ !~ safename or keyword?(safename) safename = "C_#{safename}" end safename end module_function :safeconstname def safeconstname?(name) /\A[A-Z][a-zA-Z0-9_]*\z/ =~ name and !keyword?(name) end module_function :safeconstname? def safemethodname(name) safename = name.scan(/[a-zA-Z0-9_]+/).join('_') safename = uncapitalize(safename) if /^[a-z]/ !~ safename safename = "m_#{safename}" end safename end module_function :safemethodname def safemethodname?(name) /\A[a-zA-Z_][a-zA-Z0-9_]*[=!?]?\z/ =~ name end module_function :safemethodname? def safevarname(name) safename = uncapitalize(name.scan(/[a-zA-Z0-9_]+/).join('_')) if /^[a-z]/ !~ safename or keyword?(safename) "v_#{safename}" else safename end end module_function :safevarname def safevarname?(name) /\A[a-z_][a-zA-Z0-9_]*\z/ =~ name and !keyword?(name) end module_function :safevarname? def keyword?(word) KEYWORD.key?(word) end module_function :keyword? def format(str, indent = nil) str = trim_eol(str) str = trim_indent(str) if indent str.gsub(/^/, " " * indent) else str end end private def trim_eol(str) str.collect { |line| line.sub(/\r?\n\z/, "") + "\n" }.join end def trim_indent(str) indent = nil str = str.collect { |line| untab(line) }.join str.each do |line| head = line.index(/\S/) if !head.nil? and (indent.nil? or head < indent) indent = head end end return str unless indent str.collect { |line| line.sub(/^ {0,#{indent}}/, "") }.join end def untab(line, ts = 8) while pos = line.index(/\t/) line = line.sub(/\t/, " " * (ts - (pos % ts))) end line end def dump_emptyline "\n" end end end end ================================================ FILE: lib/xsd/codegen/methoddef.rb ================================================ # XSD4R - Generating method definition code # Copyright (C) 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/codegen/gensupport' require 'xsd/codegen/commentdef' module XSD module CodeGen class MethodDef include GenSupport include CommentDef attr_accessor :definition def initialize(name, *params) unless safemethodname?(name) raise ArgumentError.new("name '#{name}' seems to be unsafe") end @name = name @params = params @comment = nil @definition = yield if block_given? end def dump buf = "" buf << dump_comment if @comment buf << dump_method_def buf << dump_definition if @definition and !@definition.empty? buf << dump_method_def_end buf end private def dump_method_def if @params.empty? format("def #{@name}") else format("def #{@name}(#{@params.join(", ")})") end end def dump_method_def_end format("end") end def dump_definition format(@definition, 2) end end end end ================================================ FILE: lib/xsd/codegen/moduledef.rb ================================================ # XSD4R - Generating module definition code # Copyright (C) 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/codegen/gensupport' require 'xsd/codegen/methoddef' require 'xsd/codegen/commentdef' module XSD module CodeGen class ModuleDef include GenSupport include CommentDef def initialize(name) @name = name @comment = nil @const = [] @code = [] @requirepath = [] @methoddef = [] end def def_require(path) @requirepath << path end def def_const(const, value) unless safeconstname?(const) raise ArgumentError.new("#{const} seems to be unsafe") end @const << [const, value] end def def_code(code) @code << code end def def_method(name, *params) add_method(MethodDef.new(name, *params) { yield if block_given? }, :public) end alias def_publicmethod def_method def def_protectedmethod(name, *params) add_method(MethodDef.new(name, *params) { yield if block_given? }, :protected) end def def_privatemethod(name, *params) add_method(MethodDef.new(name, *params) { yield if block_given? }, :private) end def add_method(m, visibility = :public) @methoddef << [visibility, m] end def dump buf = "" unless @requirepath.empty? buf << dump_requirepath end buf << dump_emptyline unless buf.empty? package = @name.split(/::/)[0..-2] buf << dump_package_def(package) unless package.empty? buf << dump_comment if @comment buf << dump_module_def spacer = false unless @const.empty? buf << dump_emptyline if spacer spacer = true buf << dump_const end unless @code.empty? buf << dump_emptyline if spacer spacer = true buf << dump_code end unless @methoddef.empty? buf << dump_emptyline if spacer spacer = true buf << dump_methods end buf << dump_module_def_end buf << dump_package_def_end(package) unless package.empty? buf.gsub(/^\s+$/, '') end private def dump_requirepath format( @requirepath.collect { |path| %Q(require '#{path}') }.join("\n") ) end def dump_const dump_static( @const.sort.collect { |var, value| %Q(#{var} = #{dump_value(value)}) }.join("\n") ) end def dump_code dump_static(@code.join("\n")) end def dump_static(str) format(str, 2) end def dump_methods methods = {} @methoddef.each do |visibility, method| (methods[visibility] ||= []) << method end str = "" [:public, :protected, :private].each do |visibility| if methods[visibility] str << "\n" unless str.empty? str << visibility.to_s << "\n\n" unless visibility == :public str << methods[visibility].collect { |m| format(m.dump, 2) }.join("\n") end end str end def dump_value(value) if value.respond_to?(:to_src) value.to_src else value end end def dump_package_def(package) format(package.collect { |ele| "module #{ele}" }.join("; ")) + "\n\n" end def dump_package_def_end(package) "\n\n" + format(package.collect { |ele| "end" }.join("; ")) end def dump_module_def name = @name.to_s.split(/::/) format("module #{name.last}") end def dump_module_def_end format("end") end end end end if __FILE__ == $0 require 'xsd/codegen/moduledef' include XSD::CodeGen m = ModuleDef.new("Foo::Bar::HobbitName") m.def_require("foo/bar") m.def_require("baz") m.comment = <<-EOD foo bar baz EOD m.def_method("foo") do <<-EOD foo.bar = 1 baz.each do |ele| ele + 1 end EOD end m.def_method("baz", "qux") #m.def_protectedmethod("aaa") m.def_privatemethod("bbb") puts m.dump end ================================================ FILE: lib/xsd/codegen.rb ================================================ # XSD4R - Generating code library # Copyright (C) 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/codegen/gensupport' require 'xsd/codegen/moduledef' require 'xsd/codegen/classdef' require 'xsd/codegen/methoddef' ================================================ FILE: lib/xsd/datatypes.rb ================================================ # XSD4R - XML Schema Datatype implementation. # Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' require 'xsd/charset' require 'uri' ### ## XMLSchamaDatatypes general definitions. # module XSD Namespace = 'http://www.w3.org/2001/XMLSchema' InstanceNamespace = 'http://www.w3.org/2001/XMLSchema-instance' AttrType = 'type' NilValue = 'true' AnyTypeLiteral = 'anyType' AnySimpleTypeLiteral = 'anySimpleType' NilLiteral = 'nil' StringLiteral = 'string' BooleanLiteral = 'boolean' DecimalLiteral = 'decimal' FloatLiteral = 'float' DoubleLiteral = 'double' DurationLiteral = 'duration' DateTimeLiteral = 'dateTime' TimeLiteral = 'time' DateLiteral = 'date' GYearMonthLiteral = 'gYearMonth' GYearLiteral = 'gYear' GMonthDayLiteral = 'gMonthDay' GDayLiteral = 'gDay' GMonthLiteral = 'gMonth' HexBinaryLiteral = 'hexBinary' Base64BinaryLiteral = 'base64Binary' AnyURILiteral = 'anyURI' QNameLiteral = 'QName' NormalizedStringLiteral = 'normalizedString' #3.3.2 token #3.3.3 language #3.3.4 NMTOKEN #3.3.5 NMTOKENS #3.3.6 Name #3.3.7 NCName #3.3.8 ID #3.3.9 IDREF #3.3.10 IDREFS #3.3.11 ENTITY #3.3.12 ENTITIES IntegerLiteral = 'integer' NonPositiveIntegerLiteral = 'nonPositiveInteger' NegativeIntegerLiteral = 'negativeInteger' LongLiteral = 'long' IntLiteral = 'int' ShortLiteral = 'short' ByteLiteral = 'byte' NonNegativeIntegerLiteral = 'nonNegativeInteger' UnsignedLongLiteral = 'unsignedLong' UnsignedIntLiteral = 'unsignedInt' UnsignedShortLiteral = 'unsignedShort' UnsignedByteLiteral = 'unsignedByte' PositiveIntegerLiteral = 'positiveInteger' AttrTypeName = QName.new(InstanceNamespace, AttrType) AttrNilName = QName.new(InstanceNamespace, NilLiteral) AnyTypeName = QName.new(Namespace, AnyTypeLiteral) AnySimpleTypeName = QName.new(Namespace, AnySimpleTypeLiteral) class Error < StandardError; end class ValueSpaceError < Error; end ### ## The base class of all datatypes with Namespace. # class NSDBase @@types = [] attr_accessor :type def self.inherited(klass) @@types << klass end def self.types @@types end def initialize end def init(type) @type = type end end ### ## The base class of XSD datatypes. # class XSDAnySimpleType < NSDBase include XSD Type = QName.new(Namespace, AnySimpleTypeLiteral) # @data represents canonical space (ex. Integer: 123). attr_reader :data # @is_nil represents this data is nil or not. attr_accessor :is_nil def initialize(value = nil) init(Type, value) end # true or raise def check_lexical_format(value) screen_data(value) true end # set accepts a string which follows lexical space (ex. String: "+123"), or # an object which follows canonical space (ex. Integer: 123). def set(value) if value.nil? @is_nil = true @data = nil _set(nil) else @is_nil = false _set(screen_data(value)) end end # to_s creates a string which follows lexical space (ex. String: "123"). def to_s() if @is_nil "" else _to_s end end private def init(type, value) super(type) set(value) end # raises ValueSpaceError if check failed def screen_data(value) value end def _set(value) @data = value end def _to_s @data.to_s end end class XSDNil < XSDAnySimpleType Type = QName.new(Namespace, NilLiteral) Value = 'true' def initialize(value = nil) init(Type, value) end end ### ## Primitive datatypes. # class XSDString < XSDAnySimpleType Type = QName.new(Namespace, StringLiteral) def initialize(value = nil) init(Type, value) end private def screen_data(value) unless XSD::Charset.is_ces(value, XSD::Charset.encoding) raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") end value end end class XSDBoolean < XSDAnySimpleType Type = QName.new(Namespace, BooleanLiteral) def initialize(value = nil) init(Type, value) end private def screen_data(value) if value.is_a?(String) str = value.strip if str == 'true' || str == '1' true elsif str == 'false' || str == '0' false else raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") end else value ? true : false end end end class XSDDecimal < XSDAnySimpleType Type = QName.new(Namespace, DecimalLiteral) def initialize(value = nil) init(Type, value) end def nonzero? (@number != '0') end private def screen_data(d) if d.is_a?(String) # Integer("00012") => 10 in Ruby. d.sub!(/^([+\-]?)0*(?=\d)/, "\\1") end screen_data_str(d) end def screen_data_str(str) /^([+\-]?)(\d*)(?:\.(\d*)?)?$/ =~ str.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") end sign = $1 || '+' int_part = $2 frac_part = $3 int_part = '0' if int_part.empty? frac_part = frac_part ? frac_part.sub(/0+$/, '') : '' point = - frac_part.size number = int_part + frac_part # normalize if sign == '+' sign = '' elsif sign == '-' if number == '0' sign = '' end end [sign, point, number] end def _set(data) if data.nil? @sign = @point = @number = @data = nil return end @sign, @point, @number = data @data = _to_s @data.freeze end # 0.0 -> 0; right? def _to_s str = @number.dup if @point.nonzero? str[@number.size + @point, 0] = '.' end @sign + str end end module FloatConstants NaN = 0.0/0.0 POSITIVE_INF = +1.0/0.0 NEGATIVE_INF = -1.0/0.0 POSITIVE_ZERO = +1.0/POSITIVE_INF NEGATIVE_ZERO = -1.0/POSITIVE_INF MIN_POSITIVE_SINGLE = 2.0 ** -149 end class XSDFloat < XSDAnySimpleType include FloatConstants Type = QName.new(Namespace, FloatLiteral) def initialize(value = nil) init(Type, value) end private def screen_data(value) # "NaN".to_f => 0 in some environment. libc? if value.is_a?(Float) return narrow32bit(value) end str = value.to_s.strip if str == 'NaN' NaN elsif str == 'INF' POSITIVE_INF elsif str == '-INF' NEGATIVE_INF else if /^[+\-\.\deE]+$/ !~ str raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") end # Float("-1.4E") might fail on some system. str << '0' if /e$/i =~ str begin return narrow32bit(Float(str)) rescue ArgumentError raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") end end end def _to_s if @data.nan? 'NaN' elsif @data.infinite? == 1 'INF' elsif @data.infinite? == -1 '-INF' else sign = XSDFloat.positive?(@data) ? '+' : '-' sign + sprintf("%.10g", @data.abs).sub(/[eE]([+-])?0+/) { 'e' + $1 } end end # Convert to single-precision 32-bit floating point value. def narrow32bit(f) if f.nan? || f.infinite? f elsif f.abs < MIN_POSITIVE_SINGLE XSDFloat.positive?(f) ? POSITIVE_ZERO : NEGATIVE_ZERO else f end end def self.positive?(value) (1 / value) > 0.0 end end # Ruby's Float is double-precision 64-bit floating point value. class XSDDouble < XSDAnySimpleType include FloatConstants Type = QName.new(Namespace, DoubleLiteral) def initialize(value = nil) init(Type, value) end private def screen_data(value) # "NaN".to_f => 0 in some environment. libc? if value.is_a?(Float) return value end str = value.to_s.strip if str == 'NaN' NaN elsif str == 'INF' POSITIVE_INF elsif str == '-INF' NEGATIVE_INF else begin return Float(str) rescue ArgumentError # '1.4e' cannot be parsed on some architecture. if /e\z/i =~ str begin return Float(str + '0') rescue ArgumentError raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") end else raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") end end end end def _to_s if @data.nan? 'NaN' elsif @data.infinite? == 1 'INF' elsif @data.infinite? == -1 '-INF' else sign = (1 / @data > 0.0) ? '+' : '-' sign + sprintf("%.16g", @data.abs).sub(/[eE]([+-])?0+/) { 'e' + $1 } end end end class XSDDuration < XSDAnySimpleType Type = QName.new(Namespace, DurationLiteral) attr_accessor :sign attr_accessor :year attr_accessor :month attr_accessor :day attr_accessor :hour attr_accessor :min attr_accessor :sec def initialize(value = nil) init(Type, value) end private def screen_data(value) /^([+\-]?)P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/ =~ value.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") end if ($5 and ((!$2 and !$3 and !$4) or (!$6 and !$7 and !$8))) # Should we allow 'PT5S' here? raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") end sign = $1 year = $2.to_i month = $3.to_i day = $4.to_i hour = $6.to_i min = $7.to_i sec = $8 ? XSDDecimal.new($8) : 0 [sign, year, month, day, hour, min, sec] end def _set(data) if data.nil? @sign = @year = @month = @day = @hour = @min = @sec = @data = nil return end @sign, @year, @month, @day, @hour, @min, @sec = data @data = _to_s @data.freeze end def _to_s str = '' str << @sign if @sign str << 'P' l = '' l << "#{ @year }Y" if @year.nonzero? l << "#{ @month }M" if @month.nonzero? l << "#{ @day }D" if @day.nonzero? r = '' r << "#{ @hour }H" if @hour.nonzero? r << "#{ @min }M" if @min.nonzero? r << "#{ @sec }S" if @sec.nonzero? str << l if l.empty? str << "0D" end unless r.empty? str << "T" << r end str end end require 'rational' require 'date' module XSDDateTimeImpl SecInDay = 86400 # 24 * 60 * 60 def to_obj(klass) if klass == Time to_time elsif klass == Date to_date elsif klass == DateTime to_datetime else nil end end def to_time begin if @data.offset * SecInDay == Time.now.utc_offset d = @data usec = (d.sec_fraction * SecInDay * 1000000).round Time.local(d.year, d.month, d.mday, d.hour, d.min, d.sec, usec) else d = @data.newof usec = (d.sec_fraction * SecInDay * 1000000).round Time.gm(d.year, d.month, d.mday, d.hour, d.min, d.sec, usec) end rescue ArgumentError nil end end def to_date Date.new0(@data.class.jd_to_ajd(@data.jd, 0, 0), 0, @data.start) end def to_datetime data end def tz2of(str) /^(?:Z|(?:([+\-])(\d\d):(\d\d))?)$/ =~ str sign = $1 hour = $2.to_i min = $3.to_i of = case sign when '+' of = +(hour.to_r * 60 + min) / 1440 # 24 * 60 when '-' of = -(hour.to_r * 60 + min) / 1440 # 24 * 60 else 0 end of end def of2tz(offset) diffmin = offset * 24 * 60 if diffmin.zero? 'Z' else ((diffmin < 0) ? '-' : '+') << format('%02d:%02d', (diffmin.abs / 60.0).to_i, (diffmin.abs % 60.0).to_i) end end def screen_data(t) # convert t to a DateTime as an internal representation. if t.respond_to?(:to_datetime) # 1.9 or later t.to_datetime elsif t.is_a?(DateTime) t elsif t.is_a?(Date) t = screen_data_str(t) t <<= 12 if t.year < 0 t elsif t.is_a?(Time) jd = DateTime.civil_to_jd(t.year, t.mon, t.mday, DateTime::ITALY) fr = DateTime.time_to_day_fraction(t.hour, t.min, [t.sec, 59].min) + t.usec.to_r / 1000000 / SecInDay of = t.utc_offset.to_r / SecInDay DateTime.new0(DateTime.jd_to_ajd(jd, fr, of), of, DateTime::ITALY) else screen_data_str(t) end end def add_tz(s) s + of2tz(@data.offset) end end class XSDDateTime < XSDAnySimpleType include XSDDateTimeImpl Type = QName.new(Namespace, DateTimeLiteral) def initialize(value = nil) init(Type, value) end private def screen_data_str(t) /^([+\-]?\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d(?:\.(\d*))?)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ t.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") end if $1 == '0000' raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") end year = $1.to_i if year < 0 year += 1 end mon = $2.to_i mday = $3.to_i hour = $4.to_i min = $5.to_i sec = $6.to_i secfrac = $7 zonestr = $8 data = DateTime.civil(year, mon, mday, hour, min, sec, tz2of(zonestr)) if secfrac diffday = secfrac.to_i.to_r / (10 ** secfrac.size) / SecInDay data += diffday # FYI: new0 and jd_to_rjd are not necessary to use if you don't have # exceptional reason. end [data, secfrac] end def _set(data) if data.nil? @data = @secfrac = nil return end @data, @secfrac = data end def _to_s year = (@data.year > 0) ? @data.year : @data.year - 1 s = format('%.4d-%02d-%02dT%02d:%02d:%02d', year, @data.mon, @data.mday, @data.hour, @data.min, @data.sec) if @data.sec_fraction.nonzero? if @secfrac s << ".#{ @secfrac }" else s << sprintf("%.16f", (@data.sec_fraction * SecInDay).to_f).sub(/^0/, '').sub(/0*$/, '') end end add_tz(s) end end class XSDTime < XSDAnySimpleType include XSDDateTimeImpl Type = QName.new(Namespace, TimeLiteral) def initialize(value = nil) init(Type, value) end private def screen_data_str(t) /^(\d\d):(\d\d):(\d\d(?:\.(\d*))?)(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ t.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") end hour = $1.to_i min = $2.to_i sec = $3.to_i secfrac = $4 zonestr = $5 data = DateTime.civil(1, 1, 1, hour, min, sec, tz2of(zonestr)) if secfrac diffday = secfrac.to_i.to_r / (10 ** secfrac.size) / SecInDay data += diffday end [data, secfrac] end def _set(data) if data.nil? @data = @secfrac = nil return end @data, @secfrac = data end def _to_s s = format('%02d:%02d:%02d', @data.hour, @data.min, @data.sec) if @data.sec_fraction.nonzero? if @secfrac s << ".#{ @secfrac }" else s << sprintf("%.16f", (@data.sec_fraction * SecInDay).to_f).sub(/^0/, '').sub(/0*$/, '') end end add_tz(s) end end class XSDDate < XSDAnySimpleType include XSDDateTimeImpl Type = QName.new(Namespace, DateLiteral) def initialize(value = nil) init(Type, value) end private def screen_data_str(t) /^([+\-]?\d{4,})-(\d\d)-(\d\d)(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ t.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") end year = $1.to_i if year < 0 year += 1 end mon = $2.to_i mday = $3.to_i zonestr = $4 DateTime.civil(year, mon, mday, 0, 0, 0, tz2of(zonestr)) end def _to_s year = (@data.year > 0) ? @data.year : @data.year - 1 s = format('%.4d-%02d-%02d', year, @data.mon, @data.mday) add_tz(s) end end class XSDGYearMonth < XSDAnySimpleType include XSDDateTimeImpl Type = QName.new(Namespace, GYearMonthLiteral) def initialize(value = nil) init(Type, value) end private def screen_data_str(t) /^([+\-]?\d{4,})-(\d\d)(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ t.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") end year = $1.to_i if year < 0 year += 1 end mon = $2.to_i zonestr = $3 DateTime.civil(year, mon, 1, 0, 0, 0, tz2of(zonestr)) end def _to_s year = (@data.year > 0) ? @data.year : @data.year - 1 s = format('%.4d-%02d', year, @data.mon) add_tz(s) end end class XSDGYear < XSDAnySimpleType include XSDDateTimeImpl Type = QName.new(Namespace, GYearLiteral) def initialize(value = nil) init(Type, value) end private def screen_data_str(t) /^([+\-]?\d{4,})(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ t.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") end year = $1.to_i if year < 0 year += 1 end zonestr = $2 DateTime.civil(year, 1, 1, 0, 0, 0, tz2of(zonestr)) end def _to_s year = (@data.year > 0) ? @data.year : @data.year - 1 s = format('%.4d', year) add_tz(s) end end class XSDGMonthDay < XSDAnySimpleType include XSDDateTimeImpl Type = QName.new(Namespace, GMonthDayLiteral) def initialize(value = nil) init(Type, value) end private def screen_data_str(t) /^(\d\d)-(\d\d)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ t.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") end mon = $1.to_i mday = $2.to_i zonestr = $3 DateTime.civil(1, mon, mday, 0, 0, 0, tz2of(zonestr)) end def _to_s s = format('%02d-%02d', @data.mon, @data.mday) add_tz(s) end end class XSDGDay < XSDAnySimpleType include XSDDateTimeImpl Type = QName.new(Namespace, GDayLiteral) def initialize(value = nil) init(Type, value) end private def screen_data_str(t) /^(\d\d)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ t.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") end mday = $1.to_i zonestr = $2 DateTime.civil(1, 1, mday, 0, 0, 0, tz2of(zonestr)) end def _to_s s = format('%02d', @data.mday) add_tz(s) end end class XSDGMonth < XSDAnySimpleType include XSDDateTimeImpl Type = QName.new(Namespace, GMonthLiteral) def initialize(value = nil) init(Type, value) end private def screen_data_str(t) /^(\d\d)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ t.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") end mon = $1.to_i zonestr = $2 DateTime.civil(1, mon, 1, 0, 0, 0, tz2of(zonestr)) end def _to_s s = format('%02d', @data.mon) add_tz(s) end end class XSDHexBinary < XSDAnySimpleType Type = QName.new(Namespace, HexBinaryLiteral) # String in Ruby could be a binary. def initialize(value = nil) init(Type, value) end def set_encoded(value) if /^[0-9a-fA-F]*$/ !~ value raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") end @data = String.new(value).strip @is_nil = false end def string [@data].pack("H*") end private def screen_data(value) value.unpack("H*")[0].tr('a-f', 'A-F') end end class XSDBase64Binary < XSDAnySimpleType Type = QName.new(Namespace, Base64BinaryLiteral) # String in Ruby could be a binary. def initialize(value = nil) init(Type, value) end def set_encoded(value) if /^[A-Za-z0-9+\/=]*$/ !~ value raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") end @data = String.new(value).strip @is_nil = false end def string @data.unpack("m")[0] end private def screen_data(value) [value].pack("m").strip end end class XSDAnyURI < XSDAnySimpleType Type = QName.new(Namespace, AnyURILiteral) def initialize(value = nil) init(Type, value) end private def screen_data(value) begin URI.parse(value.to_s.strip) rescue URI::InvalidURIError raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") end end end class XSDQName < XSDAnySimpleType Type = QName.new(Namespace, QNameLiteral) def initialize(value = nil) init(Type, value) end private def screen_data(value) /^(?:([^:]+):)?([^:]+)$/ =~ value.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") end prefix = $1 localpart = $2 [prefix, localpart] end def _set(data) if data.nil? @prefix = @localpart = @data = nil return end @prefix, @localpart = data @data = _to_s @data.freeze end def _to_s if @prefix "#{ @prefix }:#{ @localpart }" else "#{ @localpart }" end end end ### ## Derived types # class XSDNormalizedString < XSDString Type = QName.new(Namespace, NormalizedStringLiteral) def initialize(value = nil) init(Type, value) end private def screen_data(value) if /[\t\r\n]/ =~ value raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") end super end end class XSDInteger < XSDDecimal Type = QName.new(Namespace, IntegerLiteral) def initialize(value = nil) init(Type, value) end private def screen_data_str(str) begin data = Integer(str) rescue ArgumentError raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") end unless validate(data) raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") end data end def _set(value) @data = value end def _to_s() @data.to_s end def validate(v) max = maxinclusive min = mininclusive (max.nil? or v <= max) and (min.nil? or v >= min) end def maxinclusive nil end def mininclusive nil end PositiveMinInclusive = 1 def positive(v) PositiveMinInclusive <= v end end class XSDNonPositiveInteger < XSDInteger Type = QName.new(Namespace, NonPositiveIntegerLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive 0 end def mininclusive nil end end class XSDNegativeInteger < XSDNonPositiveInteger Type = QName.new(Namespace, NegativeIntegerLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive -1 end def mininclusive nil end end class XSDLong < XSDInteger Type = QName.new(Namespace, LongLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive +9223372036854775807 end def mininclusive -9223372036854775808 end end class XSDInt < XSDLong Type = QName.new(Namespace, IntLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive +2147483647 end def mininclusive -2147483648 end end class XSDShort < XSDInt Type = QName.new(Namespace, ShortLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive +32767 end def mininclusive -32768 end end class XSDByte < XSDShort Type = QName.new(Namespace, ByteLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive +127 end def mininclusive -128 end end class XSDNonNegativeInteger < XSDInteger Type = QName.new(Namespace, NonNegativeIntegerLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive nil end def mininclusive 0 end end class XSDUnsignedLong < XSDNonNegativeInteger Type = QName.new(Namespace, UnsignedLongLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive +18446744073709551615 end def mininclusive 0 end end class XSDUnsignedInt < XSDUnsignedLong Type = QName.new(Namespace, UnsignedIntLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive +4294967295 end def mininclusive 0 end end class XSDUnsignedShort < XSDUnsignedInt Type = QName.new(Namespace, UnsignedShortLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive +65535 end def mininclusive 0 end end class XSDUnsignedByte < XSDUnsignedShort Type = QName.new(Namespace, UnsignedByteLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive +255 end def mininclusive 0 end end class XSDPositiveInteger < XSDNonNegativeInteger Type = QName.new(Namespace, PositiveIntegerLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive nil end def mininclusive 1 end end end ================================================ FILE: lib/xsd/datatypes1999.rb ================================================ # XSD4R - XML Schema Datatype 1999 support # Copyright (C) 2001, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/datatypes' module XSD Namespace.replace('http://www.w3.org/1999/XMLSchema') InstanceNamespace.replace('http://www.w3.org/1999/XMLSchema-instance') AnyTypeLiteral.replace('ur-type') AnySimpleTypeLiteral.replace('ur-type') NilLiteral.replace('null') NilValue.replace('1') DateTimeLiteral.replace('timeInstant') end ================================================ FILE: lib/xsd/iconvcharset.rb ================================================ # XSD4R - Charset handling with iconv. # Copyright (C) 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'iconv' module XSD class IconvCharset def self.safe_iconv(to, from, str) iconv = Iconv.new(to, from) out = "" begin out << iconv.iconv(str) rescue Iconv::IllegalSequence => e out << e.success ch, str = e.failed.split(//, 2) out << '?' warn("Failed to convert #{ch}") retry end return out end end end ================================================ FILE: lib/xsd/mapping.rb ================================================ # XSD4R - XML Mapping for Ruby # Copyright (C) 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require "soap/parser" require 'soap/encodingstyle/literalHandler' require "soap/generator" require "soap/mapping" require "soap/mapping/wsdlliteralregistry" module XSD module Mapping MappingRegistry = SOAP::Mapping::WSDLLiteralRegistry.new MappingOpt = {:default_encodingstyle => SOAP::LiteralNamespace} def self.obj2xml(obj, elename = nil, io = nil) if !elename.nil? and !elename.is_a?(XSD::QName) elename = XSD::QName.new(nil, elename) end elename ||= XSD::QName.new(nil, SOAP::Mapping.name2elename(obj.class.to_s)) soap = SOAP::Mapping.obj2soap(obj, MappingRegistry) soap.elename = elename generator = SOAP::SOAPGenerator.new(MappingOpt) generator.generate(soap, io) end def self.xml2obj(stream) parser = SOAP::Parser.new(MappingOpt) soap = parser.parse(stream) SOAP::Mapping.soap2obj(soap, MappingRegistry) end end end ================================================ FILE: lib/xsd/namedelements.rb ================================================ # XSD4R - WSDL named element collection. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module XSD class NamedElements include Enumerable def initialize @elements = [] @cache = {} end def dup o = NamedElements.new o.elements = @elements.dup o end def freeze super @elements.freeze self end def empty? size == 0 end def size @elements.size end def [](idx) if idx.is_a?(Numeric) @elements[idx] else @cache[idx] ||= @elements.find { |item| item.name == idx } end end def find_name(name) @elements.find { |item| item.name.name == name } end def keys collect { |element| element.name } end def each @elements.each do |element| yield(element) end end def <<(rhs) @elements << rhs self end def delete(rhs) @elements.delete(rhs) end def +(rhs) o = NamedElements.new o.elements = @elements + rhs.elements o end def concat(rhs) @elements.concat(rhs.elements) self end Empty = NamedElements.new.freeze protected def elements=(rhs) @elements = rhs end def elements @elements end end end ================================================ FILE: lib/xsd/ns.rb ================================================ # XSD4R - XML Schema Namespace library # Copyright (C) 2000-2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/datatypes' module XSD class NS class Assigner def initialize @count = 0 end def assign(ns) @count += 1 "n#{@count}" end end attr_reader :default_namespace class FormatError < Error; end public def initialize(tag2ns = {}) @tag2ns = tag2ns @assigner = nil @ns2tag = {} @tag2ns.each do |tag, ns| @ns2tag[ns] = tag end @default_namespace = nil end def assign(ns, tag = nil) if (tag == '') @default_namespace = ns tag else @assigner ||= Assigner.new tag ||= @assigner.assign(ns) @ns2tag[ns] = tag @tag2ns[tag] = ns tag end end def assigned?(ns) @default_namespace == ns or @ns2tag.key?(ns) end def assigned_tag?(tag) @tag2ns.key?(tag) end def clone_ns cloned = NS.new(@tag2ns.dup) cloned.assigner = @assigner cloned.assign(@default_namespace, '') if @default_namespace cloned end def name(name) if (name.namespace == @default_namespace) name.name elsif @ns2tag.key?(name.namespace) "#{@ns2tag[name.namespace]}:#{name.name}" else raise FormatError.new("namespace: #{name.namespace} not defined yet") end end def compare(ns, name, rhs) if (ns == @default_namespace) return true if (name == rhs) end @tag2ns.each do |assigned_tag, assigned_ns| if assigned_ns == ns && "#{assigned_tag}:#{name}" == rhs return true end end false end # $1 and $2 are necessary. ParseRegexp = Regexp.new('^([^:]+)(?::(.+))?$') def parse(str, local = false) if ParseRegexp =~ str if (name = $2) and (ns = @tag2ns[$1]) return XSD::QName.new(ns, name) end end XSD::QName.new(local ? nil : @default_namespace, str) end # For local attribute key parsing # # => # {}bar, {urn:a}baz def parse_local(elem) ParseRegexp =~ elem if $2 ns = @tag2ns[$1] name = $2 if !ns raise FormatError.new("unknown namespace qualifier: #{$1}") end elsif $1 ns = nil name = $1 else raise FormatError.new("illegal element format: #{elem}") end XSD::QName.new(ns, name) end def each_ns @ns2tag.each do |ns, tag| yield(ns, tag) end end protected def assigner=(assigner) @assigner = assigner end end end ================================================ FILE: lib/xsd/qname.rb ================================================ # XSD4R - XML QName definition. # Copyright (C) 2002, 2003, 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module XSD class QName attr_accessor :namespace attr_accessor :name attr_accessor :source def initialize(namespace = nil, name = nil) @namespace = namespace @name = name @source = nil end def dup_name(name) XSD::QName.new(@namespace, name) end def dump ns = @namespace.nil? ? 'nil' : @namespace.dump name = @name.nil? ? 'nil' : @name.dump "XSD::QName.new(#{ns}, #{name})" end def match(rhs) if rhs.namespace and (rhs.namespace != @namespace) return false end if rhs.name and (rhs.name != @name) return false end true end def ==(rhs) !rhs.nil? and @namespace == rhs.namespace and @name == rhs.name end def ===(rhs) (self == rhs) end def eql?(rhs) (self == rhs) end def hash @namespace.hash ^ @name.hash end def to_s "{#{ namespace }}#{ name }" end def inspect sprintf("#<%s:0x%x %s>", self.class.name, __id__, "{#{ namespace }}#{ name }") end NormalizedNameRegexp = /^\{([^}]*)\}(.*)$/ def parse(str) NormalizedNameRegexp =~ str self.new($1, $2) end EMPTY = QName.new.freeze end end ================================================ FILE: lib/xsd/xmlparser/parser.rb ================================================ # XSD4R - XML Instance parser library. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' require 'xsd/ns' require 'xsd/charset' module XSD module XMLParser class Parser class ParseError < Error; end class FormatDecodeError < ParseError; end class UnknownElementError < FormatDecodeError; end class UnknownAttributeError < FormatDecodeError; end class UnexpectedElementError < FormatDecodeError; end class ElementConstraintError < FormatDecodeError; end @@parser_factory = nil def self.factory @@parser_factory end def self.create_parser(host, opt = {}) @@parser_factory.new(host, opt) end def self.add_factory(factory) if $DEBUG puts "Set #{ factory } as XML processor." end @@parser_factory = factory end public attr_accessor :charset def initialize(host, opt = {}) @host = host @charset = opt[:charset] || nil end def parse(string_or_readable) @textbuf = '' prologue do_parse(string_or_readable) epilogue end private def do_parse(string_or_readable) raise NotImplementError.new( 'Method do_parse must be defined in derived class.') end def start_element(name, attrs) @host.start_element(name, attrs) end def characters(text) @host.characters(text) end def end_element(name) @host.end_element(name) end def prologue end def epilogue end def xmldecl_encoding=(charset) if @charset.nil? @charset = charset else # Definition in a stream (like HTTP) has a priority. p "encoding definition: #{ charset } is ignored." if $DEBUG end end end end end ================================================ FILE: lib/xsd/xmlparser/rexmlparser.rb ================================================ # XSD4R - REXMLParser XML parser library. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/xmlparser' require 'rexml/streamlistener' require 'rexml/document' module XSD module XMLParser class REXMLParser < XSD::XMLParser::Parser include REXML::StreamListener def do_parse(string_or_readable) source = nil source = REXML::SourceFactory.create_from(string_or_readable) source.encoding = charset if charset # Listener passes a String in utf-8. @charset = 'utf-8' REXML::Document.parse_stream(source, self) end def epilogue end def tag_start(name, attrs) start_element(name, attrs) end def tag_end(name) end_element(name) end def text(text) characters(text) end def xmldecl(version, encoding, standalone) # Version should be checked. end add_factory(self) end end end ================================================ FILE: lib/xsd/xmlparser/xmlparser.rb ================================================ # XSD4R - XMLParser XML parser library. # Copyright (C) 2001, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/xmlparser' require 'xml/parser' module XSD module XMLParser class XMLParser < XSD::XMLParser::Parser class Listener < XML::Parser begin require 'xml/encoding-ja' include XML::Encoding_ja rescue LoadError # uconv may not be installed. end end def do_parse(string_or_readable) # XMLParser passes a String in utf-8. @charset = 'utf-8' @parser = Listener.new @parser.parse(string_or_readable) do |type, name, data| case type when XML::Parser::START_ELEM start_element(name, data) when XML::Parser::END_ELEM end_element(name) when XML::Parser::CDATA characters(data) else raise FormatDecodeError.new("Unexpected XML: #{ type }/#{ name }/#{ data }.") end end end add_factory(self) end end end ================================================ FILE: lib/xsd/xmlparser/xmlscanner.rb ================================================ # XSD4R - XMLScan XML parser library. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/xmlparser' require 'xmlscan/scanner' module XSD module XMLParser class XMLScanner < XSD::XMLParser::Parser include XMLScan::Visitor def do_parse(string_or_readable) @attrs = {} @curattr = nil @scanner = XMLScan::XMLScanner.new(self) @scanner.kcode = XSD::Charset.charset_str(charset) if charset @scanner.parse(string_or_readable) end def scanner_kcode=(charset) @scanner.kcode = XSD::Charset.charset_str(charset) if charset self.xmldecl_encoding = charset end ENTITY_REF_MAP = { 'lt' => '<', 'gt' => '>', 'amp' => '&', 'quot' => '"', 'apos' => '\'' } def parse_error(msg) raise ParseError.new(msg) end def wellformed_error(msg) raise NotWellFormedError.new(msg) end def valid_error(msg) raise NotValidError.new(msg) end def warning(msg) p msg if $DEBUG end # def on_xmldecl; end def on_xmldecl_version(str) # 1.0 expected. end def on_xmldecl_encoding(str) self.scanner_kcode = str end # def on_xmldecl_standalone(str); end # def on_xmldecl_other(name, value); end # def on_xmldecl_end; end # def on_doctype(root, pubid, sysid); end # def on_prolog_space(str); end # def on_comment(str); end # def on_pi(target, pi); end def on_chardata(str) characters(str) end # def on_cdata(str); end def on_etag(name) end_element(name) end def on_entityref(ref) characters(ENTITY_REF_MAP[ref]) end def on_charref(code) characters([code].pack('U')) end def on_charref_hex(code) on_charref(code) end # def on_start_document; end # def on_end_document; end def on_stag(name) @attrs = {} end def on_attribute(name) @attrs[name] = @curattr = '' end def on_attr_value(str) @curattr << str end def on_attr_entityref(ref) @curattr << ENTITY_REF_MAP[ref] end def on_attr_charref(code) @curattr << [code].pack('U') end def on_attr_charref_hex(code) on_attr_charref(code) end # def on_attribute_end(name); end def on_stag_end_empty(name) on_stag_end(name) on_etag(name) end def on_stag_end(name) start_element(name, @attrs) end add_factory(self) end end end ================================================ FILE: lib/xsd/xmlparser.rb ================================================ # XSD4R - XML Instance parser library. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/xmlparser/parser' module XSD module XMLParser def create_parser(host, opt) XSD::XMLParser::Parser.create_parser(host, opt) end module_function :create_parser # $1 is necessary. NSParseRegexp = Regexp.new('^xmlns:?(.*)$') def filter_ns(ns, attrs) return attrs if attrs.nil? or attrs.empty? newattrs = {} attrs.each do |key, value| if (NSParseRegexp =~ key) # '' means 'default namespace'. tag = $1 || '' ns.assign(value, tag) else newattrs[key] = value end end newattrs end module_function :filter_ns end end # Try to load XML processor. loaded = false [ 'xsd/xmlparser/xmlparser', 'xsd/xmlparser/xmlscanner', 'xsd/xmlparser/rexmlparser', ].each do |lib| begin require lib loaded = true break rescue LoadError end end unless loaded raise RuntimeError.new("XML processor module not found.") end ================================================ FILE: lib/yaml/baseemitter.rb ================================================ # # BaseEmitter # require 'yaml/constants' require 'yaml/encoding' require 'yaml/error' module YAML module BaseEmitter def options( opt = nil ) if opt @options[opt] || YAML::DEFAULTS[opt] else @options end end def options=( opt ) @options = opt end # # Emit binary data # def binary_base64( value ) self << "!binary " self.node_text( [value].pack("m"), '|' ) end # # Emit plain, normal flowing text # def node_text( value, block = nil ) @seq_map = false valx = value.dup unless block block = if options(:UseBlock) '|' elsif not options(:UseFold) and valx =~ /\n[ \t]/ and not valx =~ /#{YAML::ESCAPE_CHAR}/ '|' else '>' end indt = $&.to_i if block =~ /\d+/ if valx =~ /(\A\n*[ \t#]|^---\s+)/ indt = options(:Indent) unless indt.to_i > 0 block += indt.to_s end block += if valx =~ /\n\Z\n/ "+" elsif valx =~ /\Z\n/ "" else "-" end end block += "\n" if block[0] == ?" esc_skip = ( "\t\n" unless valx =~ /^[ \t]/ ) || "" valx = fold( YAML::escape( valx, esc_skip ) + "\"" ).chomp self << '"' + indent_text( valx, indt, false ) else if block[0] == ?> valx = fold( valx ) end #p [block, indt] self << block + indent_text( valx, indt ) end end # # Emit a simple, unqouted string # def simple( value ) @seq_map = false self << value.to_s end # # Emit double-quoted string # def double( value ) "\"#{YAML.escape( value )}\"" end # # Emit single-quoted string # def single( value ) "'#{value}'" end # # Write a text block with the current indent # def indent_text( text, mod, first_line = true ) return "" if text.to_s.empty? spacing = indent( mod ) text = text.gsub( /\A([^\n])/, "#{ spacing }\\1" ) if first_line return text.gsub( /\n^([^\n])/, "\n#{spacing}\\1" ) end # # Write a current indent # def indent( mod = nil ) #p [ self.id, level, mod, :INDENT ] if level <= 0 mod ||= 0 else mod ||= options(:Indent) mod += ( level - 1 ) * options(:Indent) end return " " * mod end # # Add indent to the buffer # def indent! self << indent end # # Folding paragraphs within a column # def fold( value ) value.gsub( /(^[ \t]+.*$)|(\S.{0,#{options(:BestWidth) - 1}})(?:[ \t]+|(\n+(?=[ \t]|\Z))|$)/ ) do $1 || $2 + ( $3 || "\n" ) end end # # Quick mapping # def map( type, &e ) val = Mapping.new e.call( val ) self << "#{type} " if type.length.nonzero? # # Empty hashes # if val.length.zero? self << "{}" @seq_map = false else # FIXME # if @buffer.length == 1 and options(:UseHeader) == false and type.length.zero? # @headless = 1 # end defkey = @options.delete( :DefaultKey ) if defkey seq_map_shortcut self << "= : " defkey.to_yaml( :Emitter => self ) end # # Emit the key and value # val.each { |v| seq_map_shortcut if v[0].is_complex_yaml? self << "? " end v[0].to_yaml( :Emitter => self ) if v[0].is_complex_yaml? self << "\n" indent! end self << ": " v[1].to_yaml( :Emitter => self ) } end end def seq_map_shortcut # FIXME: seq_map needs to work with the new anchoring system # if @seq_map # @anchor_extras[@buffer.length - 1] = "\n" + indent # @seq_map = false # else self << "\n" indent! # end end # # Quick sequence # def seq( type, &e ) @seq_map = false val = Sequence.new e.call( val ) self << "#{type} " if type.length.nonzero? # # Empty arrays # if val.length.zero? self << "[]" else # FIXME # if @buffer.length == 1 and options(:UseHeader) == false and type.length.zero? # @headless = 1 # end # # Emit the key and value # val.each { |v| self << "\n" indent! self << "- " @seq_map = true if v.class == Hash v.to_yaml( :Emitter => self ) } end end end # # Emitter helper classes # class Mapping < Array def add( k, v ) push [k, v] end end class Sequence < Array def add( v ) push v end end end ================================================ FILE: lib/yaml/basenode.rb ================================================ # # YAML::BaseNode class # require 'yaml/ypath' module YAML # # YAML Generic Model container # module BaseNode # # Search for YPath entry and return # qualified nodes. # def select( ypath_str ) matches = match_path( ypath_str ) # # Create a new generic view of the elements selected # if matches result = [] matches.each { |m| result.push m.last } YAML.transfer( 'seq', result ) end end # # Search for YPath entry and return # transformed nodes. # def select!( ypath_str ) matches = match_path( ypath_str ) # # Create a new generic view of the elements selected # if matches result = [] matches.each { |m| result.push m.last.transform } result end end # # Search for YPath entry and return a list of # qualified paths. # def search( ypath_str ) matches = match_path( ypath_str ) if matches matches.collect { |m| path = [] m.each_index { |i| path.push m[i] if ( i % 2 ).zero? } "/" + path.compact.join( "/" ) } end end def at( seg ) if Hash === @value self[seg] elsif Array === @value and seg =~ /\A\d+\Z/ and @value[seg.to_i] @value[seg.to_i] end end # # YPath search returning a complete depth array # def match_path( ypath_str ) depth = 0 matches = [] YPath.each_path( ypath_str ) do |ypath| seg = match_segment( ypath, 0 ) matches += seg if seg end matches.uniq end # # Search a node for a single YPath segment # def match_segment( ypath, depth ) deep_nodes = [] seg = ypath.segments[ depth ] if seg == "/" unless String === @value idx = -1 @value.collect { |v| idx += 1 if Hash === @value match_init = [v[0].transform, v[1]] match_deep = v[1].match_segment( ypath, depth ) else match_init = [idx, v] match_deep = v.match_segment( ypath, depth ) end if match_deep match_deep.each { |m| deep_nodes.push( match_init + m ) } end } end depth += 1 seg = ypath.segments[ depth ] end match_nodes = case seg when "." [[nil, self]] when ".." [["..", nil]] when "*" if @value.is_a? Enumerable idx = -1 @value.collect { |h| idx += 1 if Hash === @value [h[0].transform, h[1]] else [idx, h] end } end else if seg =~ /^"(.*)"$/ seg = $1 elsif seg =~ /^'(.*)'$/ seg = $1 end if ( v = at( seg ) ) [[ seg, v ]] end end return deep_nodes unless match_nodes pred = ypath.predicates[ depth ] if pred case pred when /^\.=/ pred = $' # ' match_nodes.reject! { |n| n.last.value != pred } else match_nodes.reject! { |n| n.last.at( pred ).nil? } end end return match_nodes + deep_nodes unless ypath.segments.length > depth + 1 #puts "DEPTH: #{depth + 1}" deep_nodes = [] match_nodes.each { |n| if n[1].is_a? BaseNode match_deep = n[1].match_segment( ypath, depth + 1 ) if match_deep match_deep.each { |m| deep_nodes.push( n + m ) } end else deep_nodes = [] end } deep_nodes = nil if deep_nodes.length == 0 deep_nodes end # # We want the node to act like as Hash # if it is. # def []( *key ) if Hash === @value v = @value.detect { |k,| k.transform == key.first } v[1] if v elsif Array === @value @value.[]( *key ) end end def children if Hash === @value @value.values.collect { |c| c[1] } elsif Array === @value @value end end def children_with_index if Hash === @value @value.keys.collect { |i| [self[i], i] } elsif Array === @value i = -1; @value.collect { |v| i += 1; [v, i] } end end def emit transform.to_yaml end end end ================================================ FILE: lib/yaml/constants.rb ================================================ # # Constants used throughout the library # module YAML # # Constants # VERSION = '0.60' SUPPORTED_YAML_VERSIONS = ['1.0'] # # Parser tokens # WORD_CHAR = 'A-Za-z0-9' PRINTABLE_CHAR = '-_A-Za-z0-9!?/()$\'". ' NOT_PLAIN_CHAR = '\x7f\x0-\x1f\x80-\x9f' ESCAPE_CHAR = '[\\x00-\\x09\\x0b-\\x1f]' INDICATOR_CHAR = '*&!|\\\\^@%{}[]=' SPACE_INDICATORS = '-#:,?' RESTRICTED_INDICATORS = '#:,}]' DNS_COMP_RE = "\\w(?:[-\\w]*\\w)?" DNS_NAME_RE = "(?:(?:#{DNS_COMP_RE}\\.)+#{DNS_COMP_RE}|#{DNS_COMP_RE})" ESCAPES = %w{\x00 \x01 \x02 \x03 \x04 \x05 \x06 \a \x08 \t \n \v \f \r \x0e \x0f \x10 \x11 \x12 \x13 \x14 \x15 \x16 \x17 \x18 \x19 \x1a \e \x1c \x1d \x1e \x1f } UNESCAPES = { 'a' => "\x07", 'b' => "\x08", 't' => "\x09", 'n' => "\x0a", 'v' => "\x0b", 'f' => "\x0c", 'r' => "\x0d", 'e' => "\x1b", '\\' => '\\', } # # Default settings # DEFAULTS = { :Indent => 2, :UseHeader => false, :UseVersion => false, :Version => '1.0', :SortKeys => false, :AnchorFormat => 'id%03d', :ExplicitTypes => false, :WidthType => 'absolute', :BestWidth => 80, :UseBlock => false, :UseFold => false, :Encoding => :None } end ================================================ FILE: lib/yaml/dbm.rb ================================================ require 'yaml' require 'dbm' # # YAML + DBM = YDBM # - Same interface as DBM class # module YAML class DBM < ::DBM VERSION = "0.1" def []( key ) fetch( key ) end def []=( key, val ) store( key, val ) end def fetch( keystr, ifnone = nil ) begin val = super( keystr ) return YAML::load( val ) if String === val rescue IndexError end if block_given? yield keystr else ifnone end end def index( keystr ) super( keystr.to_yaml ) end def values_at( *keys ) keys.collect { |k| fetch( k ) } end def delete( key ) v = super( key ) if String === v v = YAML::load( v ) end v end def delete_if del_keys = keys.dup del_keys.delete_if { |k| yield( k, fetch( k ) ) == false } del_keys.each { |k| delete( k ) } self end def reject hsh = self.to_hash hsh.reject { |k,v| yield k, v } end def each_pair keys.each { |k| yield k, fetch( k ) } self end def each_value super { |v| yield YAML::load( v ) } self end def values super.collect { |v| YAML::load( v ) } end def has_value?( val ) each_value { |v| return true if v == val } return false end def invert h = {} keys.each { |k| h[ self.fetch( k ) ] = k } h end def replace( hsh ) clear update( hsh ) end def shift a = super a[1] = YAML::load( a[1] ) if a a end def select( *keys ) if block_given? self.keys.collect { |k| v = self[k]; [k, v] if yield k, v }.compact else values_at( *keys ) end end def store( key, val ) super( key, val.to_yaml ) val end def update( hsh ) hsh.keys.each do |k| self.store( k, hsh.fetch( k ) ) end self end def to_a a = [] keys.each { |k| a.push [ k, self.fetch( k ) ] } a end def to_hash h = {} keys.each { |k| h[ k ] = self.fetch( k ) } h end alias :each :each_pair end end ================================================ FILE: lib/yaml/encoding.rb ================================================ # # Handle Unicode-to-Internal conversion # module YAML # # Escape the string, condensing common escapes # def YAML.escape( value, skip = "" ) value.gsub( /\\/, "\\\\\\" ). gsub( /"/, "\\\"" ). gsub( /([\x00-\x1f])/ ) do skip[$&] || ESCAPES[ $&.unpack("C")[0] ] end end # # Unescape the condenses escapes # def YAML.unescape( value ) value.gsub( /\\(?:([nevfbart\\])|0?x([0-9a-fA-F]{2})|u([0-9a-fA-F]{4}))/ ) { if $3 ["#$3".hex ].pack('U*') elsif $2 [$2].pack( "H2" ) else UNESCAPES[$1] end } end end ================================================ FILE: lib/yaml/error.rb ================================================ # # Error messages and exception class # module YAML # # Error messages # ERROR_NO_HEADER_NODE = "With UseHeader=false, the node Array or Hash must have elements" ERROR_NEED_HEADER = "With UseHeader=false, the node must be an Array or Hash" ERROR_BAD_EXPLICIT = "Unsupported explicit transfer: '%s'" ERROR_MANY_EXPLICIT = "More than one explicit transfer" ERROR_MANY_IMPLICIT = "More than one implicit request" ERROR_NO_ANCHOR = "No anchor for alias '%s'" ERROR_BAD_ANCHOR = "Invalid anchor: %s" ERROR_MANY_ANCHOR = "More than one anchor" ERROR_ANCHOR_ALIAS = "Can't define both an anchor and an alias" ERROR_BAD_ALIAS = "Invalid alias: %s" ERROR_MANY_ALIAS = "More than one alias" ERROR_ZERO_INDENT = "Can't use zero as an indentation width" ERROR_UNSUPPORTED_VERSION = "This release of YAML.rb does not support YAML version %s" ERROR_UNSUPPORTED_ENCODING = "Attempt to use unsupported encoding: %s" # # YAML Error classes # class Error < StandardError; end class ParseError < Error; end class TypeError < StandardError; end end ================================================ FILE: lib/yaml/loader.rb ================================================ # # YAML::Loader class # .. type handling .. # module YAML class Loader TRANSFER_DOMAINS = { 'yaml.org,2002' => {}, 'ruby.yaml.org,2002' => {} } PRIVATE_TYPES = {} IMPLICIT_TYPES = [ 'null', 'bool', 'time', 'int', 'float' ] end end ================================================ FILE: lib/yaml/rubytypes.rb ================================================ # -*- mode: ruby; ruby-indent-level: 4; tab-width: 4 -*- vim: sw=4 ts=4 require 'date' class Class def to_yaml( opts = {} ) raise TypeError, "can't dump anonymous class %s" % self.class end end class Object yaml_as "tag:ruby.yaml.org,2002:object" def to_yaml_style; end def to_yaml_properties; instance_variables.sort; end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| out.map( taguri, to_yaml_style ) do |map| to_yaml_properties.each do |m| map.add( m[1..-1], instance_variable_get( m ) ) end end end end end class Hash yaml_as "tag:ruby.yaml.org,2002:hash" yaml_as "tag:yaml.org,2002:map" def yaml_initialize( tag, val ) if Array === val update Hash.[]( *val ) # Convert the map to a sequence elsif Hash === val update val else raise YAML::TypeError, "Invalid map explicitly tagged #{ tag }: " + val.inspect end end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| out.map( taguri, to_yaml_style ) do |map| each do |k, v| map.add( k, v ) end end end end end class Struct yaml_as "tag:ruby.yaml.org,2002:struct" def self.yaml_tag_class_name; self.name.gsub( "Struct::", "" ); end def self.yaml_tag_read_class( name ); "Struct::#{ name }"; end def self.yaml_new( klass, tag, val ) if Hash === val struct_type = nil # # Use existing Struct if it exists # props = {} val.delete_if { |k,v| props[k] = v if k =~ /^@/ } begin struct_name, struct_type = YAML.read_type_class( tag, Struct ) rescue NameError end if not struct_type struct_def = [ tag.split( ':', 4 ).last ] struct_type = Struct.new( *struct_def.concat( val.keys.collect { |k| k.intern } ) ) end # # Set the Struct properties # st = YAML::object_maker( struct_type, {} ) st.members.each do |m| st.send( "#{m}=", val[m] ) end props.each do |k,v| st.instance_variable_set(k, v) end st else raise YAML::TypeError, "Invalid Ruby Struct: " + val.inspect end end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| # # Basic struct is passed as a YAML map # out.map( taguri, to_yaml_style ) do |map| self.members.each do |m| map.add( m, self[m] ) end self.to_yaml_properties.each do |m| map.add( m, instance_variable_get( m ) ) end end end end end class Array yaml_as "tag:ruby.yaml.org,2002:array" yaml_as "tag:yaml.org,2002:seq" def yaml_initialize( tag, val ); concat( val.to_a ); end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| out.seq( taguri, to_yaml_style ) do |seq| each do |x| seq.add( x ) end end end end end class Exception yaml_as "tag:ruby.yaml.org,2002:exception" def Exception.yaml_new( klass, tag, val ) o = YAML.object_maker( klass, { 'mesg' => val.delete( 'message' ) } ) val.each_pair do |k,v| o.instance_variable_set("@#{k}", v) end o end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| out.map( taguri, to_yaml_style ) do |map| map.add( 'message', message ) to_yaml_properties.each do |m| map.add( m[1..-1], instance_variable_get( m ) ) end end end end end class String yaml_as "tag:ruby.yaml.org,2002:string" yaml_as "tag:yaml.org,2002:binary" yaml_as "tag:yaml.org,2002:str" def is_complex_yaml? to_yaml_style or not to_yaml_properties.empty? or self =~ /\n.+/ end def is_binary_data? ( self.count( "^ -~", "^\r\n" ).fdiv(self.size) > 0.3 || self.index( "\x00" ) ) unless empty? end def String.yaml_new( klass, tag, val ) val = val.unpack("m")[0] if tag == "tag:yaml.org,2002:binary" val = { 'str' => val } if String === val if Hash === val s = klass.allocate # Thank you, NaHi String.instance_method(:initialize). bind(s). call( val.delete( 'str' ) ) val.each { |k,v| s.instance_variable_set( k, v ) } s else raise YAML::TypeError, "Invalid String: " + val.inspect end end def to_yaml( opts = {} ) YAML::quick_emit( is_complex_yaml? ? self : nil, opts ) do |out| if is_binary_data? out.scalar( "tag:yaml.org,2002:binary", [self].pack("m"), :literal ) elsif to_yaml_properties.empty? out.scalar( taguri, self, self =~ /^:/ ? :quote2 : to_yaml_style ) else out.map( taguri, to_yaml_style ) do |map| map.add( 'str', "#{self}" ) to_yaml_properties.each do |m| map.add( m, instance_variable_get( m ) ) end end end end end end class Symbol yaml_as "tag:ruby.yaml.org,2002:symbol" yaml_as "tag:ruby.yaml.org,2002:sym" def Symbol.yaml_new( klass, tag, val ) if String === val val = YAML::load( val ) if val =~ /\A(["']).*\1\z/ val.intern else raise YAML::TypeError, "Invalid Symbol: " + val.inspect end end def to_yaml( opts = {} ) YAML::quick_emit( nil, opts ) do |out| out.scalar( "tag:yaml.org,2002:str", self.inspect, :plain ) end end end class Range yaml_as "tag:ruby.yaml.org,2002:range" def Range.yaml_new( klass, tag, val ) inr = %r'(\w+|[+-]?\d+(?:\.\d+)?(?:e[+-]\d+)?|"(?:[^\\"]|\\.)*")' opts = {} if String === val and val =~ /^#{inr}(\.{2,3})#{inr}$/o r1, rdots, r2 = $1, $2, $3 opts = { 'begin' => YAML.load( "--- #{r1}" ), 'end' => YAML.load( "--- #{r2}" ), 'excl' => rdots.length == 3 } val = {} elsif Hash === val opts['begin'] = val.delete('begin') opts['end'] = val.delete('end') opts['excl'] = val.delete('excl') end if Hash === opts r = YAML::object_maker( klass, {} ) # Thank you, NaHi Range.instance_method(:initialize). bind(r). call( opts['begin'], opts['end'], opts['excl'] ) val.each { |k,v| r.instance_variable_set( k, v ) } r else raise YAML::TypeError, "Invalid Range: " + val.inspect end end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| # if self.begin.is_complex_yaml? or self.begin.respond_to? :to_str or # self.end.is_complex_yaml? or self.end.respond_to? :to_str or # not to_yaml_properties.empty? out.map( taguri, to_yaml_style ) do |map| map.add( 'begin', self.begin ) map.add( 'end', self.end ) map.add( 'excl', self.exclude_end? ) to_yaml_properties.each do |m| map.add( m, instance_variable_get( m ) ) end end # else # out.scalar( taguri ) do |sc| # sc.embed( self.begin ) # sc.concat( self.exclude_end? ? "..." : ".." ) # sc.embed( self.end ) # end # end end end end class Regexp yaml_as "tag:ruby.yaml.org,2002:regexp" def Regexp.yaml_new( klass, tag, val ) if String === val and val =~ /^\/(.*)\/([mix]*)$/ val = { 'regexp' => $1, 'mods' => $2 } end if Hash === val mods = nil unless val['mods'].to_s.empty? mods = 0x00 mods |= Regexp::EXTENDED if val['mods'].include?( 'x' ) mods |= Regexp::IGNORECASE if val['mods'].include?( 'i' ) mods |= Regexp::MULTILINE if val['mods'].include?( 'm' ) end val.delete( 'mods' ) r = YAML::object_maker( klass, {} ) Regexp.instance_method(:initialize). bind(r). call( val.delete( 'regexp' ), mods ) val.each { |k,v| r.instance_variable_set( k, v ) } r else raise YAML::TypeError, "Invalid Regular expression: " + val.inspect end end def to_yaml( opts = {} ) YAML::quick_emit( nil, opts ) do |out| if to_yaml_properties.empty? out.scalar( taguri, self.inspect, :plain ) else out.map( taguri, to_yaml_style ) do |map| src = self.inspect if src =~ /\A\/(.*)\/([a-z]*)\Z/ map.add( 'regexp', $1 ) map.add( 'mods', $2 ) else raise YAML::TypeError, "Invalid Regular expression: " + src end to_yaml_properties.each do |m| map.add( m, instance_variable_get( m ) ) end end end end end end class Time yaml_as "tag:ruby.yaml.org,2002:time" yaml_as "tag:yaml.org,2002:timestamp" def Time.yaml_new( klass, tag, val ) if Hash === val t = val.delete( 'at' ) val.each { |k,v| t.instance_variable_set( k, v ) } t else raise YAML::TypeError, "Invalid Time: " + val.inspect end end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| tz = "Z" # from the tidy Tobias Peters Thanks! unless self.utc? utc_same_instant = self.dup.utc utc_same_writing = Time.utc(year,month,day,hour,min,sec,usec) difference_to_utc = utc_same_writing - utc_same_instant if (difference_to_utc < 0) difference_sign = '-' absolute_difference = -difference_to_utc else difference_sign = '+' absolute_difference = difference_to_utc end difference_minutes = (absolute_difference/60).round tz = "%s%02d:%02d" % [ difference_sign, difference_minutes / 60, difference_minutes % 60] end standard = self.strftime( "%Y-%m-%d %H:%M:%S" ) standard += ".%06d" % [usec] if usec.nonzero? standard += " %s" % [tz] if to_yaml_properties.empty? out.scalar( taguri, standard, :plain ) else out.map( taguri, to_yaml_style ) do |map| map.add( 'at', standard ) to_yaml_properties.each do |m| map.add( m, instance_variable_get( m ) ) end end end end end end class Date yaml_as "tag:yaml.org,2002:timestamp#ymd" def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| out.scalar( "tag:yaml.org,2002:timestamp", self.to_s, :plain ) end end end class Integer yaml_as "tag:yaml.org,2002:int" def to_yaml( opts = {} ) YAML::quick_emit( nil, opts ) do |out| out.scalar( "tag:yaml.org,2002:int", self.to_s, :plain ) end end end class Float yaml_as "tag:yaml.org,2002:float" def to_yaml( opts = {} ) YAML::quick_emit( nil, opts ) do |out| str = self.to_s if str == "Infinity" str = ".Inf" elsif str == "-Infinity" str = "-.Inf" elsif str == "NaN" str = ".NaN" end out.scalar( "tag:yaml.org,2002:float", str, :plain ) end end end class TrueClass yaml_as "tag:yaml.org,2002:bool#yes" def to_yaml( opts = {} ) YAML::quick_emit( nil, opts ) do |out| out.scalar( taguri, "true", :plain ) end end end class FalseClass yaml_as "tag:yaml.org,2002:bool#no" def to_yaml( opts = {} ) YAML::quick_emit( nil, opts ) do |out| out.scalar( taguri, "false", :plain ) end end end class NilClass yaml_as "tag:yaml.org,2002:null" def to_yaml( opts = {} ) YAML::quick_emit( nil, opts ) do |out| out.scalar( taguri, "", :plain ) end end end ================================================ FILE: lib/yaml/store.rb ================================================ # # YAML::Store # require 'yaml' require 'pstore' class YAML::Store < PStore def initialize( *o ) @opt = YAML::DEFAULTS.dup if String === o.first super(o.shift) end if o.last.is_a? Hash @opt.update(o.pop) end end def dump(table) @table.to_yaml(@opt) end def load(content) table = YAML::load(content) if table == false {} else table end end def marshal_dump_supports_canonical_option? false end EMPTY_MARSHAL_DATA = {}.to_yaml EMPTY_MARSHAL_CHECKSUM = Digest::MD5.digest(EMPTY_MARSHAL_DATA) def empty_marshal_data EMPTY_MARSHAL_DATA end def empty_marshal_checksum EMPTY_MARSHAL_CHECKSUM end end ================================================ FILE: lib/yaml/stream.rb ================================================ module YAML # # YAML::Stream -- for emitting many documents # class Stream attr_accessor :documents, :options def initialize( opts = {} ) @options = opts @documents = [] end def []( i ) @documents[ i ] end def add( doc ) @documents << doc end def edit( doc_num, doc ) @documents[ doc_num ] = doc end def emit( io = nil ) # opts = @options.dup # opts[:UseHeader] = true if @documents.length > 1 out = YAML.emitter out.reset( io || io2 = StringIO.new ) @documents.each { |v| v.to_yaml( out ) } io || ( io2.rewind; io2.read ) end end end ================================================ FILE: lib/yaml/stringio.rb ================================================ # # Limited StringIO if no core lib is available # begin require 'stringio' rescue LoadError # StringIO based on code by MoonWolf class StringIO def initialize(string="") @string=string @pos=0 @eof=(string.size==0) end def pos @pos end def eof @eof end alias eof? eof def readline(rs=$/) if @eof raise EOFError else if p = @string[@pos..-1]=~rs line = @string[@pos,p+1] else line = @string[@pos..-1] end @pos+=line.size @eof =true if @pos==@string.size $_ = line end end def rewind seek(0,0) end def seek(offset,whence) case whence when 0 @pos=offset when 1 @pos+=offset when 2 @pos=@string.size+offset end @eof=(@pos>=@string.size) 0 end end # # Class method for creating streams # def YAML.make_stream( io ) if String === io io = StringIO.new( io ) elsif not IO === io raise YAML::Error, "YAML stream must be an IO or String object." end if YAML::unicode def io.readline YAML.utf_to_internal( readline( @ln_sep ), @utf_encoding ) end def io.check_unicode @utf_encoding = YAML.sniff_encoding( read( 4 ) ) @ln_sep = YAML.enc_separator( @utf_encoding ) seek( -4, IO::SEEK_CUR ) end def io.utf_encoding @utf_encoding end io.check_unicode else def io.utf_encoding :None end end io end end ================================================ FILE: lib/yaml/syck.rb ================================================ # # YAML::Syck module # .. glues syck and yaml.rb together .. # require 'syck' require 'yaml/basenode' module YAML module Syck # # Mixin BaseNode functionality # class Node include YAML::BaseNode end end end ================================================ FILE: lib/yaml/tag.rb ================================================ # -*- mode: ruby; ruby-indent-level: 4; tab-width: 4 -*- vim: sw=4 ts=4 # $Id$ # # = yaml/tag.rb: methods for associating a taguri to a class. # # Author:: why the lucky stiff # module YAML # A dictionary of taguris which map to # Ruby classes. @@tagged_classes = {} # # Associates a taguri _tag_ with a Ruby class _cls_. The taguri is used to give types # to classes when loading YAML. Taguris are of the form: # # tag:authorityName,date:specific # # The +authorityName+ is a domain name or email address. The +date+ is the date the type # was issued in YYYY or YYYY-MM or YYYY-MM-DD format. The +specific+ is a name for # the type being added. # # For example, built-in YAML types have 'yaml.org' as the +authorityName+ and '2002' as the # +date+. The +specific+ is simply the name of the type: # # tag:yaml.org,2002:int # tag:yaml.org,2002:float # tag:yaml.org,2002:timestamp # # The domain must be owned by you on the +date+ declared. If you don't own any domains on the # date you declare the type, you can simply use an e-mail address. # # tag:why@ruby-lang.org,2004:notes/personal # def YAML.tag_class( tag, cls ) if @@tagged_classes.has_key? tag warn "class #{ @@tagged_classes[tag] } held ownership of the #{ tag } tag" end @@tagged_classes[tag] = cls end # Returns the complete dictionary of taguris, paired with classes. The key for # the dictionary is the full taguri. The value for each key is the class constant # associated to that taguri. # # YAML.tagged_classes["tag:yaml.org,2002:int"] => Integer # def YAML.tagged_classes @@tagged_classes end end class Module # :stopdoc: # Adds a taguri _tag_ to a class, used when dumping or loading the class # in YAML. See YAML::tag_class for detailed information on typing and # taguris. def yaml_as( tag, sc = true ) verbose, $VERBOSE = $VERBOSE, nil class_eval <<-"end;", __FILE__, __LINE__+1 attr_writer :taguri def taguri if respond_to? :to_yaml_type YAML::tagurize( to_yaml_type[1..-1] ) else return @taguri if defined?(@taguri) and @taguri tag = #{ tag.dump } if self.class.yaml_tag_subclasses? and self.class != YAML::tagged_classes[tag] tag = "\#{ tag }:\#{ self.class.yaml_tag_class_name }" end tag end end def self.yaml_tag_subclasses?; #{ sc ? 'true' : 'false' }; end end; YAML::tag_class tag, self ensure $VERBOSE = verbose end # Transforms the subclass name into a name suitable for display # in a subclassed tag. def yaml_tag_class_name self.name end # Transforms the subclass name found in the tag into a Ruby # constant name. def yaml_tag_read_class( name ) name end end ================================================ FILE: lib/yaml/types.rb ================================================ # -*- mode: ruby; ruby-indent-level: 4 -*- vim: sw=4 # # Classes required by the full core typeset # module YAML # # Default private type # class PrivateType def self.tag_subclasses?; false; end verbose, $VERBOSE = $VERBOSE, nil def initialize( type, val ) @type_id = type; @value = val @value.taguri = "x-private:#{ @type_id }" end def to_yaml( opts = {} ) @value.to_yaml( opts ) end ensure $VERBOSE = verbose end # # Default domain type # class DomainType def self.tag_subclasses?; false; end verbose, $VERBOSE = $VERBOSE, nil def initialize( domain, type, val ) @domain = domain; @type_id = type; @value = val @value.taguri = "tag:#{ @domain }:#{ @type_id }" end def to_yaml( opts = {} ) @value.to_yaml( opts ) end ensure $VERBOSE = verbose end # # Unresolved objects # class Object def self.tag_subclasses?; false; end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| out.map( "tag:ruby.yaml.org,2002:object:#{ @class }", to_yaml_style ) do |map| @ivars.each do |k,v| map.add( k, v ) end end end end end # # YAML Hash class to support comments and defaults # class SpecialHash < ::Hash attr_accessor :default def inspect self.default.to_s end def to_s self.default.to_s end def update( h ) if YAML::SpecialHash === h @default = h.default if h.default end super( h ) end def to_yaml( opts = {} ) opts[:DefaultKey] = self.default super( opts ) end end # # Builtin collection: !omap # class Omap < ::Array yaml_as "tag:yaml.org,2002:omap" def yaml_initialize( tag, val ) if Array === val val.each do |v| if Hash === v concat( v.to_a ) # Convert the map to a sequence else raise YAML::Error, "Invalid !omap entry: " + val.inspect end end else raise YAML::Error, "Invalid !omap: " + val.inspect end self end def self.[]( *vals ) o = Omap.new 0.step( vals.length - 1, 2 ) do |i| o[vals[i]] = vals[i+1] end o end def []( k ) self.assoc( k ).to_a[1] end def []=( k, *rest ) val, set = rest.reverse if ( tmp = self.assoc( k ) ) and not set tmp[1] = val else self << [ k, val ] end val end def has_key?( k ) self.assoc( k ) ? true : false end def is_complex_yaml? true end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| out.seq( taguri, to_yaml_style ) do |seq| self.each do |v| seq.add( Hash[ *v ] ) end end end end end # # Builtin collection: !pairs # class Pairs < ::Array yaml_as "tag:yaml.org,2002:pairs" def yaml_initialize( tag, val ) if Array === val val.each do |v| if Hash === v concat( v.to_a ) # Convert the map to a sequence else raise YAML::Error, "Invalid !pairs entry: " + val.inspect end end else raise YAML::Error, "Invalid !pairs: " + val.inspect end self end def self.[]( *vals ) p = Pairs.new 0.step( vals.length - 1, 2 ) { |i| p[vals[i]] = vals[i+1] } p end def []( k ) self.assoc( k ).to_a end def []=( k, val ) self << [ k, val ] val end def has_key?( k ) self.assoc( k ) ? true : false end def is_complex_yaml? true end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| out.seq( taguri, to_yaml_style ) do |seq| self.each do |v| seq.add( Hash[ *v ] ) end end end end end # # Builtin collection: !set # class Set < ::Hash yaml_as "tag:yaml.org,2002:set" end end ================================================ FILE: lib/yaml/yamlnode.rb ================================================ # # YAML::YamlNode class # require 'yaml/basenode' module YAML # # YAML Generic Model container # class YamlNode include BaseNode attr_accessor :kind, :type_id, :value, :anchor def initialize( t, v ) @type_id = t if Hash === v @kind = 'map' @value = {} v.each { |k,v| @value[ k.transform ] = [ k, v ] } elsif Array === v @kind = 'seq' @value = v elsif String === v @kind = 'scalar' @value = v end end # # Transform this node fully into a native type # def transform t = nil if @value.is_a? Hash t = {} @value.each { |k,v| t[ k ] = v[1].transform } elsif @value.is_a? Array t = [] @value.each { |v| t.push v.transform } else t = @value end YAML.transfer_method( @type_id, t ) end end end ================================================ FILE: lib/yaml/ypath.rb ================================================ # # YAML::YPath # module YAML class YPath attr_accessor :segments, :predicates, :flags def initialize( str ) @segments = [] @predicates = [] @flags = nil while str =~ /^\/?(\/|[^\/\[]+)(?:\[([^\]]+)\])?/ @segments.push $1 @predicates.push $2 str = $' end unless str.to_s.empty? @segments += str.split( "/" ) end if @segments.length == 0 @segments.push "." end end def YPath.each_path( str ) # # Find choices # paths = [] str = "(#{ str })" while str.sub!( /\(([^()]+)\)/, "\n#{ paths.length }\n" ) paths.push $1.split( '|' ) end # # Construct all possible paths # all = [ str ] ( paths.length - 1 ).downto( 0 ) do |i| all = all.collect do |a| paths[i].collect do |p| a.gsub( /\n#{ i }\n/, p ) end end.flatten.uniq end all.collect do |path| yield YPath.new( path ) end end end end ================================================ FILE: lib/yaml.rb ================================================ # -*- mode: ruby; ruby-indent-level: 4; tab-width: 4 -*- vim: sw=4 ts=4 # $Id$ # # = yaml.rb: top-level module with methods for loading and parsing YAML documents # # Author:: why the lucky stiff # require 'stringio' require 'yaml/error' require 'yaml/syck' require 'yaml/tag' require 'yaml/stream' require 'yaml/constants' # == YAML # # YAML(tm) (rhymes with 'camel') is a # straightforward machine parsable data serialization format designed for # human readability and interaction with scripting languages such as Perl # and Python. YAML is optimized for data serialization, formatted # dumping, configuration files, log files, Internet messaging and # filtering. This specification describes the YAML information model and # serialization format. Together with the Unicode standard for characters, it # provides all the information necessary to understand YAML Version 1.0 # and construct computer programs to process it. # # See http://yaml.org/ for more information. For a quick tutorial, please # visit YAML In Five Minutes (http://yaml.kwiki.org/?YamlInFiveMinutes). # # == About This Library # # The YAML 1.0 specification outlines four stages of YAML loading and dumping. # This library honors all four of those stages, although data is really only # available to you in three stages. # # The four stages are: native, representation, serialization, and presentation. # # The native stage refers to data which has been loaded completely into Ruby's # own types. (See +YAML::load+.) # # The representation stage means data which has been composed into # +YAML::BaseNode+ objects. In this stage, the document is available as a # tree of node objects. You can perform YPath queries and transformations # at this level. (See +YAML::parse+.) # # The serialization stage happens inside the parser. The YAML parser used in # Ruby is called Syck. Serialized nodes are available in the extension as # SyckNode structs. # # The presentation stage is the YAML document itself. This is accessible # to you as a string. (See +YAML::dump+.) # # For more information about the various information models, see Chapter # 3 of the YAML 1.0 Specification (http://yaml.org/spec/#id2491269). # # The YAML module provides quick access to the most common loading (YAML::load) # and dumping (YAML::dump) tasks. This module also provides an API for registering # global types (YAML::add_domain_type). # # == Example # # A simple round-trip (load and dump) of an object. # # require "yaml" # # test_obj = ["dogs", "cats", "badgers"] # # yaml_obj = YAML::dump( test_obj ) # # -> --- # - dogs # - cats # - badgers # ruby_obj = YAML::load( yaml_obj ) # # => ["dogs", "cats", "badgers"] # ruby_obj == test_obj # # => true # # To register your custom types with the global resolver, use +add_domain_type+. # # YAML::add_domain_type( "your-site.com,2004", "widget" ) do |type, val| # Widget.new( val ) # end # module YAML Resolver = YAML::Syck::Resolver DefaultResolver = YAML::Syck::DefaultResolver DefaultResolver.use_types_at( @@tagged_classes ) GenericResolver = YAML::Syck::GenericResolver Parser = YAML::Syck::Parser Emitter = YAML::Syck::Emitter # Returns a new default parser def YAML.parser; Parser.new.set_resolver( YAML.resolver ); end # Returns a new generic parser def YAML.generic_parser; Parser.new.set_resolver( GenericResolver ); end # Returns the default resolver def YAML.resolver; DefaultResolver; end # Returns a new default emitter def YAML.emitter; Emitter.new.set_resolver( YAML.resolver ); end # # Converts _obj_ to YAML and writes the YAML result to _io_. # # File.open( 'animals.yaml', 'w' ) do |out| # YAML.dump( ['badger', 'elephant', 'tiger'], out ) # end # # If no _io_ is provided, a string containing the dumped YAML # is returned. # # YAML.dump( :locked ) # #=> "--- :locked" # def YAML.dump( obj, io = nil ) obj.to_yaml( io || io2 = StringIO.new ) io || ( io2.rewind; io2.read ) end # # Load a document from the current _io_ stream. # # File.open( 'animals.yaml' ) { |yf| YAML::load( yf ) } # #=> ['badger', 'elephant', 'tiger'] # # Can also load from a string. # # YAML.load( "--- :locked" ) # #=> :locked # def YAML.load( io ) yp = parser.load( io ) end # # Load a document from the file located at _filepath_. # # YAML.load_file( 'animals.yaml' ) # #=> ['badger', 'elephant', 'tiger'] # def YAML.load_file( filepath ) File.open( filepath ) do |f| load( f ) end end # # Parse the first document from the current _io_ stream # # File.open( 'animals.yaml' ) { |yf| YAML::load( yf ) } # #=> #, # #, # #]> # # Can also load from a string. # # YAML.parse( "--- :locked" ) # #=> # # def YAML.parse( io ) yp = generic_parser.load( io ) end # # Parse a document from the file located at _filepath_. # # YAML.parse_file( 'animals.yaml' ) # #=> #, # #, # #]> # def YAML.parse_file( filepath ) File.open( filepath ) do |f| parse( f ) end end # # Calls _block_ with each consecutive document in the YAML # stream contained in _io_. # # File.open( 'many-docs.yaml' ) do |yf| # YAML.each_document( yf ) do |ydoc| # ## ydoc contains the single object # ## from the YAML document # end # end # def YAML.each_document( io, &block ) yp = parser.load_documents( io, &block ) end # # Calls _block_ with each consecutive document in the YAML # stream contained in _io_. # # File.open( 'many-docs.yaml' ) do |yf| # YAML.load_documents( yf ) do |ydoc| # ## ydoc contains the single object # ## from the YAML document # end # end # def YAML.load_documents( io, &doc_proc ) YAML.each_document( io, &doc_proc ) end # # Calls _block_ with a tree of +YAML::BaseNodes+, one tree for # each consecutive document in the YAML stream contained in _io_. # # File.open( 'many-docs.yaml' ) do |yf| # YAML.each_node( yf ) do |ydoc| # ## ydoc contains a tree of nodes # ## from the YAML document # end # end # def YAML.each_node( io, &doc_proc ) yp = generic_parser.load_documents( io, &doc_proc ) end # # Calls _block_ with a tree of +YAML::BaseNodes+, one tree for # each consecutive document in the YAML stream contained in _io_. # # File.open( 'many-docs.yaml' ) do |yf| # YAML.parse_documents( yf ) do |ydoc| # ## ydoc contains a tree of nodes # ## from the YAML document # end # end # def YAML.parse_documents( io, &doc_proc ) YAML.each_node( io, &doc_proc ) end # # Loads all documents from the current _io_ stream, # returning a +YAML::Stream+ object containing all # loaded documents. # def YAML.load_stream( io ) d = nil parser.load_documents( io ) do |doc| d = YAML::Stream.new if not d d.add( doc ) end return d end # # Returns a YAML stream containing each of the items in +objs+, # each having their own document. # # YAML.dump_stream( 0, [], {} ) # #=> --- 0 # --- [] # --- {} # def YAML.dump_stream( *objs ) d = YAML::Stream.new objs.each do |doc| d.add( doc ) end d.emit end # # Add a global handler for a YAML domain type. # def YAML.add_domain_type( domain, type_tag, &transfer_proc ) resolver.add_type( "tag:#{ domain }:#{ type_tag }", transfer_proc ) end # # Add a transfer method for a builtin type # def YAML.add_builtin_type( type_tag, &transfer_proc ) resolver.add_type( "tag:yaml.org,2002:#{ type_tag }", transfer_proc ) end # # Add a transfer method for a builtin type # def YAML.add_ruby_type( type_tag, &transfer_proc ) resolver.add_type( "tag:ruby.yaml.org,2002:#{ type_tag }", transfer_proc ) end # # Add a private document type # def YAML.add_private_type( type_re, &transfer_proc ) resolver.add_type( "x-private:" + type_re, transfer_proc ) end # # Detect typing of a string # def YAML.detect_implicit( val ) resolver.detect_implicit( val ) end # # Convert a type_id to a taguri # def YAML.tagurize( val ) resolver.tagurize( val ) end # # Apply a transfer method to a Ruby object # def YAML.transfer( type_id, obj ) resolver.transfer( YAML.tagurize( type_id ), obj ) end # # Apply any implicit a node may qualify for # def YAML.try_implicit( obj ) YAML.transfer( YAML.detect_implicit( obj ), obj ) end # # Method to extract colon-seperated type and class, returning # the type and the constant of the class # def YAML.read_type_class( type, obj_class ) scheme, domain, type, tclass = type.split( ':', 4 ) tclass.split( "::" ).each { |c| obj_class = obj_class.const_get( c ) } if tclass return [ type, obj_class ] end # # Allocate blank object # def YAML.object_maker( obj_class, val ) if Hash === val o = obj_class.allocate val.each_pair { |k,v| o.instance_variable_set("@#{k}", v) } o else raise YAML::Error, "Invalid object explicitly tagged !ruby/Object: " + val.inspect end end # # Allocate an Emitter if needed # def YAML.quick_emit( oid, opts = {}, &e ) out = if opts.is_a? YAML::Emitter opts else emitter.reset( opts ) end oid = case oid when Fixnum, NilClass; oid else oid = "#{oid.object_id}-#{oid.hash}" end out.emit( oid, &e ) end end require 'yaml/rubytypes' require 'yaml/types' module Kernel # # ryan:: You know how Kernel.p is a really convenient way to dump ruby # structures? The only downside is that it's not as legible as # YAML. # # _why:: (listening) # # ryan:: I know you don't want to urinate all over your users' namespaces. # But, on the other hand, convenience of dumping for debugging is, # IMO, a big YAML use case. # # _why:: Go nuts! Have a pony parade! # # ryan:: Either way, I certainly will have a pony parade. # # Prints any supplied _objects_ out in YAML. Intended as # a variation on +Kernel::p+. # # S = Struct.new(:name, :state) # s = S['dave', 'TX'] # y s # # _produces:_ # # --- !ruby/struct:S # name: dave # state: TX # def y( object, *objects ) objects.unshift object puts( if objects.length == 1 YAML::dump( *objects ) else YAML::dump_stream( *objects ) end ) end private :y end ================================================ FILE: main.c ================================================ /********************************************************************** main.c - $Author$ $Date$ created at: Fri Aug 19 13:19:58 JST 1994 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #include "ruby.h" #ifdef __human68k__ int _stacksize = 262144; #endif #if defined __MINGW32__ int _CRT_glob = 0; #endif #if defined(__MACOS__) && defined(__MWERKS__) #include #endif /* to link startup code with ObjC support */ #if (defined(__APPLE__) || defined(__NeXT__)) && defined(__MACH__) static void objcdummyfunction( void ) { objc_msgSend(); } #endif int main(argc, argv, envp) int argc; char **argv, **envp; { #ifdef _WIN32 NtInitialize(&argc, &argv); #endif #if defined(__MACOS__) && defined(__MWERKS__) argc = ccommand(&argv); #endif { RUBY_INIT_STACK ruby_init(); ruby_options(argc, argv); ruby_run(); } return 0; } ================================================ FILE: marktable.c ================================================ /** * A mark table, used during a mark-and-sweep garbage collection cycle. * * This implementation is somewhat slower than default MRI, but is * copy-on-write friendly. It stores mark information for objects in a bit * field located at the beginning of the heap. Mark information for filenames * are stored in a pointer set. */ #ifndef _MARK_TABLE_C_ #define _MARK_TABLE_C_ #include "pointerset.h" /* A mark table for filenames and objects that are not on the heap. */ static PointerSet *mark_table = NULL; static struct heaps_slot *last_heap = NULL; static inline struct heaps_slot * find_heap_slot_for_object(RVALUE *object) { register int i; /* Look in the cache first. */ if (last_heap != NULL && object >= last_heap->slot && object < last_heap->slotlimit) { return last_heap; } for (i = 0; i < heaps_used; i++) { struct heaps_slot *heap = &heaps[i]; if (object >= heap->slot && object < heap->slotlimit) { /* Cache this result. According to empirical evidence, the chance is * high that the next lookup will be for the same heap slot. */ last_heap = heap; return heap; } } return NULL; } static inline void find_position_in_bitfield(struct heaps_slot *hs, RVALUE *object, unsigned int *bitfield_index, unsigned int *bitfield_offset) { unsigned int index; index = object - hs->slot; /* * We use bit operators to calculate the position in the bit field, whenever possible. * This only works if sizeof(int) is a multiple of 2, but I don't know of any platform * on which that is not true. */ if (sizeof(int) == 4 || sizeof(int) == 8 || sizeof(int) == 16) { int int_bits_log; /* Must be equal to the base 2 logarithm of sizeof(int) * 8 */ switch (sizeof(int)) { case 4: int_bits_log = 5; break; case 8: int_bits_log = 6; break; case 16: int_bits_log = 7; break; default: int_bits_log = 0; /* Shut up compiler warning. */ abort(); } *bitfield_index = index >> int_bits_log; *bitfield_offset = index & ((sizeof(int) * 8) - 1); } else { *bitfield_index = index / (sizeof(int) * 8); *bitfield_offset = index % (sizeof(int) * 8); } } static void rb_mark_table_init() { if (mark_table == NULL) { mark_table = pointer_set_new(); } } static void rb_mark_table_prepare() { last_heap = NULL; } static void rb_mark_table_reset(lifetime_t lifetime) { int i; for (i = 0; i < heaps_used; i++) { if (heaps[i].lifetime == lifetime) { MEMZERO(heaps[i].marks, int, heaps[i].marks_size); } } } static inline void rb_mark_table_add(RVALUE *object) { struct heaps_slot *hs; unsigned int bitfield_index, bitfield_offset; hs = find_heap_slot_for_object(object); if (hs != NULL) { find_position_in_bitfield(hs, object, &bitfield_index, &bitfield_offset); hs->marks[bitfield_index] |= (1 << bitfield_offset); } else { pointer_set_insert(mark_table, (void *) object); } } static inline void rb_mark_table_heap_add(struct heaps_slot *hs, RVALUE *object) { unsigned int bitfield_index, bitfield_offset; find_position_in_bitfield(hs, object, &bitfield_index, &bitfield_offset); hs->marks[bitfield_index] |= (1 << bitfield_offset); } static inline int rb_mark_table_contains(RVALUE *object) { struct heaps_slot *hs; unsigned int bitfield_index, bitfield_offset; hs = find_heap_slot_for_object(object); if (hs != NULL) { find_position_in_bitfield(hs, object, &bitfield_index, &bitfield_offset); return hs->marks[bitfield_index] & (1 << bitfield_offset); } else { return pointer_set_contains(mark_table, (void *) object); } } static inline int rb_mark_table_heap_contains(struct heaps_slot *hs, RVALUE *object) { unsigned int bitfield_index, bitfield_offset; find_position_in_bitfield(hs, object, &bitfield_index, &bitfield_offset); last_heap = hs; return hs->marks[bitfield_index] & (1 << bitfield_offset); } static inline void rb_mark_table_remove(RVALUE *object) { struct heaps_slot *hs; unsigned int bitfield_index, bitfield_offset; hs = find_heap_slot_for_object(object); if (hs != NULL) { find_position_in_bitfield(hs, object, &bitfield_index, &bitfield_offset); hs->marks[bitfield_index] &= ~(1 << bitfield_offset); } else { pointer_set_delete(mark_table, (void *) object); } } static inline void rb_mark_table_heap_remove(struct heaps_slot *hs, RVALUE *object) { unsigned int bitfield_index, bitfield_offset; find_position_in_bitfield(hs, object, &bitfield_index, &bitfield_offset); hs->marks[bitfield_index] &= ~(1 << bitfield_offset); } static inline void rb_mark_table_add_filename(char *filename) { pointer_set_insert(mark_table, (void *) filename); } static inline int rb_mark_table_contains_filename(const char *filename) { return pointer_set_contains(mark_table, (void *) filename); } static inline void rb_mark_table_remove_filename(char *filename) { pointer_set_delete(mark_table, (void *) filename); } #ifdef GC_DEBUG static inline void rb_mark_table_add_source_pos(source_position_t *source_pos) { pointer_set_insert(mark_table, (void *) source_pos); } static inline int rb_mark_table_contains_source_pos(const source_position_t *source_pos) { return pointer_set_contains(mark_table, (void *) source_pos); } static inline void rb_mark_table_remove_source_pos(source_position_t *source_pos) { pointer_set_delete(mark_table, (void *) source_pos); } #endif #endif /* _MARK_TABLE_C_ */ ================================================ FILE: marktable.h ================================================ #ifndef _MARK_TABLE_H_ #define _MARK_TABLE_H_ static void rb_mark_table_init(); static void rb_mark_table_prepare(); static void rb_mark_table_reset(lifetime_t lifetime); static void rb_mark_table_add(RVALUE *object); static void rb_mark_table_heap_add(struct heaps_slot *hs, RVALUE *object); static int rb_mark_table_contains(RVALUE *object); static int rb_mark_table_heap_contains(struct heaps_slot *hs, RVALUE *object); static void rb_mark_table_remove(RVALUE *object); static void rb_mark_table_heap_remove(struct heaps_slot *hs, RVALUE *object); static void rb_mark_table_add_filename(char *filename); static int rb_mark_table_contains_filename(const char *filename); static void rb_mark_table_remove_filename(char *filename); #ifdef GC_DEBUG static void rb_mark_table_add_source_pos(source_position_t *source_pos); static int rb_mark_table_contains_source_pos(const source_position_t *source_pos); static void rb_mark_table_remove_source_pos(source_position_t *source_pos); #endif #endif /* _MARK_TABLE_H_ */ ================================================ FILE: marshal.c ================================================ /********************************************************************** marshal.c - $Author$ $Date$ created at: Thu Apr 27 16:30:01 JST 1995 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #include "ruby.h" #include "rubyio.h" #include "st.h" #include "util.h" #include #ifdef HAVE_FLOAT_H #include #endif #ifdef HAVE_IEEEFP_H #include #endif #define BITSPERSHORT (2*CHAR_BIT) #define SHORTMASK ((1<symbols) { rb_raise(rb_eRuntimeError, "Marshal.dump reentered at %s", rb_id2name(sym)); } } static void clear_dump_arg _((struct dump_arg *arg)); static void mark_dump_arg(ptr) void *ptr; { struct dump_arg *p = ptr; if (!p->symbols) return; rb_mark_set(p->data); } static void free_dump_arg(ptr) void *ptr; { clear_dump_arg(ptr); xfree(ptr); } static VALUE class2path(klass) VALUE klass; { VALUE path = rb_class_path(klass); char *n = RSTRING(path)->ptr; if (n[0] == '#') { rb_raise(rb_eTypeError, "can't dump anonymous %s %s", (TYPE(klass) == T_CLASS ? "class" : "module"), n); } if (rb_path2class(n) != rb_class_real(klass)) { rb_raise(rb_eTypeError, "%s can't be referred", n); } return path; } static void w_long _((long, struct dump_arg*)); static void w_nbyte(s, n, arg) const char *s; int n; struct dump_arg *arg; { VALUE buf = arg->str; rb_str_buf_cat(buf, s, n); if (arg->dest && RSTRING(buf)->len >= BUFSIZ) { if (arg->taint) OBJ_TAINT(buf); rb_io_write(arg->dest, buf); rb_str_resize(buf, 0); } } static void w_byte(c, arg) char c; struct dump_arg *arg; { w_nbyte(&c, 1, arg); } static void w_bytes(s, n, arg) const char *s; int n; struct dump_arg *arg; { w_long(n, arg); w_nbyte(s, n, arg); } static void w_short(x, arg) int x; struct dump_arg *arg; { w_byte((x >> 0) & 0xff, arg); w_byte((x >> 8) & 0xff, arg); } static void w_long(x, arg) long x; struct dump_arg *arg; { char buf[sizeof(long)+1]; int i, len = 0; #if SIZEOF_LONG > 4 if (!(RSHIFT(x, 31) == 0 || RSHIFT(x, 31) == -1)) { /* big long does not fit in 4 bytes */ rb_raise(rb_eTypeError, "long too big to dump"); } #endif if (x == 0) { w_byte(0, arg); return; } if (0 < x && x < 123) { w_byte(x + 5, arg); return; } if (-124 < x && x < 0) { w_byte((x - 5)&0xff, arg); return; } for (i=1;i 32 #define MANT_BITS 32 #elif DBL_MANT_DIG > 24 #define MANT_BITS 24 #elif DBL_MANT_DIG > 16 #define MANT_BITS 16 #else #define MANT_BITS 8 #endif static int save_mantissa(d, buf) double d; char *buf; { int e, i = 0; unsigned long m; double n; d = modf(ldexp(frexp(fabs(d), &e), DECIMAL_MANT), &d); if (d > 0) { buf[i++] = 0; do { d = modf(ldexp(d, MANT_BITS), &n); m = (unsigned long)n; #if MANT_BITS > 24 buf[i++] = m >> 24; #endif #if MANT_BITS > 16 buf[i++] = m >> 16; #endif #if MANT_BITS > 8 buf[i++] = m >> 8; #endif buf[i++] = m; } while (d > 0); while (!buf[i - 1]) --i; } return i; } static double load_mantissa(d, buf, len) double d; const char *buf; int len; { if (--len > 0 && !*buf++) { /* binary mantissa mark */ int e, s = d < 0, dig = 0; unsigned long m; modf(ldexp(frexp(fabs(d), &e), DECIMAL_MANT), &d); do { m = 0; switch (len) { default: m = *buf++ & 0xff; #if MANT_BITS > 24 case 3: m = (m << 8) | (*buf++ & 0xff); #endif #if MANT_BITS > 16 case 2: m = (m << 8) | (*buf++ & 0xff); #endif #if MANT_BITS > 8 case 1: m = (m << 8) | (*buf++ & 0xff); #endif } dig -= len < MANT_BITS / 8 ? 8 * (unsigned)len : MANT_BITS; d += ldexp((double)m, dig); } while ((len -= MANT_BITS / 8) > 0); d = ldexp(d, e - DECIMAL_MANT); if (s) d = -d; } return d; } #else #define load_mantissa(d, buf, len) (d) #define save_mantissa(d, buf) 0 #endif #ifdef DBL_DIG #define FLOAT_DIG (DBL_DIG+2) #else #define FLOAT_DIG 17 #endif static void w_float(d, arg) double d; struct dump_arg *arg; { char buf[100]; if (isinf(d)) { if (d < 0) strcpy(buf, "-inf"); else strcpy(buf, "inf"); } else if (isnan(d)) { strcpy(buf, "nan"); } else if (d == 0.0) { if (1.0/d < 0) strcpy(buf, "-0"); else strcpy(buf, "0"); } else { int len; /* xxx: should not use system's sprintf(3) */ sprintf(buf, "%.*g", FLOAT_DIG, d); len = strlen(buf); w_bytes(buf, len + save_mantissa(d, buf + len), arg); return; } w_bytes(buf, strlen(buf), arg); } static void w_symbol(id, arg) ID id; struct dump_arg *arg; { const char *sym = rb_id2name(id); st_data_t num; if (st_lookup(arg->symbols, id, &num)) { w_byte(TYPE_SYMLINK, arg); w_long((long)num, arg); } else { w_byte(TYPE_SYMBOL, arg); w_bytes(sym, strlen(sym), arg); st_add_direct(arg->symbols, id, arg->symbols->num_entries); } } static void w_unique(s, arg) const char *s; struct dump_arg *arg; { if (s[0] == '#') { rb_raise(rb_eTypeError, "can't dump anonymous class %s", s); } w_symbol(rb_intern(s), arg); } static void w_object _((VALUE,struct dump_arg*,int)); static int hash_each(key, value, arg) VALUE key, value; struct dump_call_arg *arg; { w_object(key, arg->arg, arg->limit); w_object(value, arg->arg, arg->limit); return ST_CONTINUE; } static void w_extended(klass, arg, check) VALUE klass; struct dump_arg *arg; int check; { const char *path; if (check && FL_TEST(klass, FL_SINGLETON)) { if (RCLASS(klass)->m_tbl->num_entries || (RCLASS(klass)->iv_tbl && RCLASS(klass)->iv_tbl->num_entries > 1)) { rb_raise(rb_eTypeError, "singleton can't be dumped"); } klass = RCLASS(klass)->super; } while (BUILTIN_TYPE(klass) == T_ICLASS) { path = rb_class2name(RBASIC(klass)->klass); w_byte(TYPE_EXTENDED, arg); w_unique(path, arg); klass = RCLASS(klass)->super; } } static void w_class(type, obj, arg, check) int type; VALUE obj; struct dump_arg *arg; int check; { char *path; VALUE klass = CLASS_OF(obj); w_extended(klass, arg, check); w_byte(type, arg); path = RSTRING(class2path(rb_class_real(klass)))->ptr; w_unique(path, arg); } static void w_uclass(obj, base_klass, arg) VALUE obj, base_klass; struct dump_arg *arg; { VALUE klass = CLASS_OF(obj); w_extended(klass, arg, Qtrue); klass = rb_class_real(klass); if (klass != base_klass) { w_byte(TYPE_UCLASS, arg); w_unique(RSTRING(class2path(klass))->ptr, arg); } } static int w_obj_each(id, value, arg) ID id; VALUE value; struct dump_call_arg *arg; { w_symbol(id, arg->arg); w_object(value, arg->arg, arg->limit); return ST_CONTINUE; } static void w_ivar(tbl, arg) st_table *tbl; struct dump_call_arg *arg; { if (tbl) { w_long(tbl->num_entries, arg->arg); st_foreach_safe(tbl, w_obj_each, (st_data_t)arg); } else { w_long(0, arg->arg); } } static void w_object(obj, arg, limit) VALUE obj; struct dump_arg *arg; int limit; { struct dump_call_arg c_arg; st_table *ivtbl = 0; st_data_t num; if (limit == 0) { rb_raise(rb_eArgError, "exceed depth limit"); } limit--; c_arg.limit = limit; c_arg.arg = arg; if (st_lookup(arg->data, obj, &num)) { w_byte(TYPE_LINK, arg); w_long((long)num, arg); return; } if ((ivtbl = rb_generic_ivar_table(obj)) != 0) { w_byte(TYPE_IVAR, arg); } if (obj == Qnil) { w_byte(TYPE_NIL, arg); } else if (obj == Qtrue) { w_byte(TYPE_TRUE, arg); } else if (obj == Qfalse) { w_byte(TYPE_FALSE, arg); } else if (FIXNUM_P(obj)) { #if SIZEOF_LONG <= 4 w_byte(TYPE_FIXNUM, arg); w_long(FIX2INT(obj), arg); #else if (RSHIFT((long)obj, 31) == 0 || RSHIFT((long)obj, 31) == -1) { w_byte(TYPE_FIXNUM, arg); w_long(FIX2LONG(obj), arg); } else { w_object(rb_int2big(FIX2LONG(obj)), arg, limit); } #endif } else if (SYMBOL_P(obj)) { w_symbol(SYM2ID(obj), arg); } else { if (OBJ_TAINTED(obj)) arg->taint = Qtrue; st_add_direct(arg->data, obj, arg->data->num_entries); if (rb_respond_to(obj, s_mdump)) { volatile VALUE v; v = rb_funcall(obj, s_mdump, 0, 0); check_dump_arg(arg, s_mdump); w_class(TYPE_USRMARSHAL, obj, arg, Qfalse); w_object(v, arg, limit); if (ivtbl) w_ivar(0, &c_arg); return; } if (rb_respond_to(obj, s_dump)) { VALUE v; v = rb_funcall(obj, s_dump, 1, INT2NUM(limit)); check_dump_arg(arg, s_dump); if (TYPE(v) != T_STRING) { rb_raise(rb_eTypeError, "_dump() must return string"); } if (!ivtbl && (ivtbl = rb_generic_ivar_table(v))) { w_byte(TYPE_IVAR, arg); } w_class(TYPE_USERDEF, obj, arg, Qfalse); w_bytes(RSTRING(v)->ptr, RSTRING(v)->len, arg); if (ivtbl) { w_ivar(ivtbl, &c_arg); } return; } switch (BUILTIN_TYPE(obj)) { case T_CLASS: if (FL_TEST(obj, FL_SINGLETON)) { rb_raise(rb_eTypeError, "singleton class can't be dumped"); } w_byte(TYPE_CLASS, arg); { VALUE path = class2path(obj); w_bytes(RSTRING(path)->ptr, RSTRING(path)->len, arg); } break; case T_MODULE: w_byte(TYPE_MODULE, arg); { VALUE path = class2path(obj); w_bytes(RSTRING(path)->ptr, RSTRING(path)->len, arg); } break; case T_FLOAT: w_byte(TYPE_FLOAT, arg); w_float(RFLOAT(obj)->value, arg); break; case T_BIGNUM: w_byte(TYPE_BIGNUM, arg); { char sign = RBIGNUM(obj)->sign ? '+' : '-'; long len = RBIGNUM(obj)->len; BDIGIT *d = RBIGNUM(obj)->digits; w_byte(sign, arg); w_long(SHORTLEN(len), arg); /* w_short? */ while (len--) { #if SIZEOF_BDIGITS > SIZEOF_SHORT BDIGIT num = *d; int i; for (i=0; iptr, RSTRING(obj)->len, arg); break; case T_REGEXP: w_uclass(obj, rb_cRegexp, arg); w_byte(TYPE_REGEXP, arg); w_bytes(RREGEXP(obj)->str, RREGEXP(obj)->len, arg); w_byte(rb_reg_options(obj), arg); break; case T_ARRAY: w_uclass(obj, rb_cArray, arg); w_byte(TYPE_ARRAY, arg); { long len = RARRAY(obj)->len; VALUE *ptr = RARRAY(obj)->ptr; w_long(len, arg); while (len--) { w_object(*ptr, arg, limit); ptr++; } } break; case T_HASH: w_uclass(obj, rb_cHash, arg); if (NIL_P(RHASH(obj)->ifnone)) { w_byte(TYPE_HASH, arg); } else if (FL_TEST(obj, FL_USER2)) { /* FL_USER2 means HASH_PROC_DEFAULT (see hash.c) */ rb_raise(rb_eTypeError, "can't dump hash with default proc"); } else { w_byte(TYPE_HASH_DEF, arg); } w_long(RHASH(obj)->tbl->num_entries, arg); rb_hash_foreach(obj, hash_each, (st_data_t)&c_arg); if (!NIL_P(RHASH(obj)->ifnone)) { w_object(RHASH(obj)->ifnone, arg, limit); } break; case T_STRUCT: w_class(TYPE_STRUCT, obj, arg, Qtrue); { long len = RSTRUCT(obj)->len; VALUE mem; long i; w_long(len, arg); mem = rb_struct_members(obj); for (i=0; iptr[i]), arg); w_object(RSTRUCT(obj)->ptr[i], arg, limit); } } break; case T_OBJECT: w_class(TYPE_OBJECT, obj, arg, Qtrue); w_ivar(ROBJECT(obj)->iv_tbl, &c_arg); break; case T_DATA: { VALUE v; if (!rb_respond_to(obj, s_dump_data)) { rb_raise(rb_eTypeError, "no marshal_dump is defined for class %s", rb_obj_classname(obj)); } v = rb_funcall(obj, s_dump_data, 0); check_dump_arg(arg, s_dump_data); w_class(TYPE_DATA, obj, arg, Qtrue); w_object(v, arg, limit); } break; default: rb_raise(rb_eTypeError, "can't dump %s", rb_obj_classname(obj)); break; } } if (ivtbl) { w_ivar(ivtbl, &c_arg); } } static void clear_dump_arg(arg) struct dump_arg *arg; { if (!arg->symbols) return; st_free_table(arg->symbols); arg->symbols = 0; st_free_table(arg->data); if (arg->taint) { OBJ_TAINT(arg->str); } } /* * call-seq: * dump( obj [, anIO] , limit=--1 ) => anIO * * Serializes obj and all descendent objects. If anIO is * specified, the serialized data will be written to it, otherwise the * data will be returned as a String. If limit is specified, the * traversal of subobjects will be limited to that depth. If limit is * negative, no checking of depth will be performed. * * class Klass * def initialize(str) * @str = str * end * def sayHello * @str * end * end * * (produces no output) * * o = Klass.new("hello\n") * data = Marshal.dump(o) * obj = Marshal.load(data) * obj.sayHello #=> "hello\n" */ static VALUE marshal_dump(argc, argv) int argc; VALUE* argv; { VALUE obj, port, a1, a2; int limit = -1; struct dump_arg *arg; VALUE wrapper; port = Qnil; rb_scan_args(argc, argv, "12", &obj, &a1, &a2); if (argc == 3) { if (!NIL_P(a2)) limit = NUM2INT(a2); if (NIL_P(a1)) goto type_error; port = a1; } else if (argc == 2) { if (FIXNUM_P(a1)) limit = FIX2INT(a1); else if (NIL_P(a1)) goto type_error; else port = a1; } wrapper = Data_Make_Struct(rb_cData, struct dump_arg, mark_dump_arg, free_dump_arg, arg); arg->dest = 0; arg->symbols = st_init_numtable(); arg->data = st_init_numtable(); arg->taint = Qfalse; arg->str = rb_str_buf_new(0); RBASIC(arg->str)->klass = 0; if (!NIL_P(port)) { if (!rb_respond_to(port, s_write)) { type_error: rb_raise(rb_eTypeError, "instance of IO needed"); } arg->dest = port; if (rb_respond_to(port, s_binmode)) { rb_funcall2(port, s_binmode, 0, 0); check_dump_arg(arg, s_binmode); } } else { port = arg->str; } w_byte(MARSHAL_MAJOR, arg); w_byte(MARSHAL_MINOR, arg); w_object(obj, arg, limit); if (arg->dest) { rb_io_write(arg->dest, arg->str); rb_str_resize(arg->str, 0); } RBASIC(arg->str)->klass = rb_cString; clear_dump_arg(arg); RB_GC_GUARD(wrapper); return port; } struct load_arg { VALUE src; long offset; st_table *symbols; st_table *data; VALUE proc; int taint; }; static void check_load_arg(arg, sym) struct load_arg *arg; ID sym; { if (!arg->symbols) { rb_raise(rb_eRuntimeError, "Marshal.load reentered at %s", rb_id2name(sym)); } } static void clear_load_arg _((struct load_arg *arg)); static void mark_load_arg(ptr) void *ptr; { struct load_arg *p = ptr; if (!p->symbols) return; rb_mark_tbl(p->data); } static void free_load_arg(void *ptr) { clear_load_arg(ptr); xfree(ptr); } static VALUE r_object _((struct load_arg *arg)); static int r_byte(arg) struct load_arg *arg; { int c; if (TYPE(arg->src) == T_STRING) { if (RSTRING(arg->src)->len > arg->offset) { c = (unsigned char)RSTRING(arg->src)->ptr[arg->offset++]; } else { rb_raise(rb_eArgError, "marshal data too short"); } } else { VALUE src = arg->src; VALUE v = rb_funcall2(src, s_getc, 0, 0); check_load_arg(arg, s_getc); if (NIL_P(v)) rb_eof_error(); c = (unsigned char)FIX2INT(v); } return c; } static void long_toobig(size) int size; { rb_raise(rb_eTypeError, "long too big for this architecture (size %d, given %d)", sizeof(long), size); } #undef SIGN_EXTEND_CHAR #if __STDC__ # define SIGN_EXTEND_CHAR(c) ((signed char)(c)) #else /* not __STDC__ */ /* As in Harbison and Steele. */ # define SIGN_EXTEND_CHAR(c) ((((unsigned char)(c)) ^ 128) - 128) #endif static long r_long(arg) struct load_arg *arg; { register long x; int c = SIGN_EXTEND_CHAR(r_byte(arg)); long i; if (c == 0) return 0; if (c > 0) { if (4 < c && c < 128) { return c - 5; } if (c > sizeof(long)) long_toobig(c); x = 0; for (i=0;i sizeof(long)) long_toobig(c); x = -1; for (i=0;isrc) == T_STRING) { if (RSTRING(arg->src)->len - arg->offset >= len) { str = rb_str_new(RSTRING(arg->src)->ptr+arg->offset, len); arg->offset += len; } else { too_short: rb_raise(rb_eArgError, "marshal data too short"); } } else { VALUE src = arg->src; VALUE n = LONG2NUM(len); str = rb_funcall2(src, s_read, 1, &n); check_load_arg(arg, s_read); if (NIL_P(str)) goto too_short; StringValue(str); if (RSTRING(str)->len != len) goto too_short; if (OBJ_TAINTED(str)) arg->taint = Qtrue; } return str; } static ID r_symlink(arg) struct load_arg *arg; { ID id; long num = r_long(arg); if (st_lookup(arg->symbols, num, &id)) { return id; } rb_raise(rb_eArgError, "bad symbol"); } static ID r_symreal(arg) struct load_arg *arg; { ID id; id = rb_intern(RSTRING(r_bytes(arg))->ptr); st_insert(arg->symbols, arg->symbols->num_entries, id); return id; } static ID r_symbol(arg) struct load_arg *arg; { if (r_byte(arg) == TYPE_SYMLINK) { return r_symlink(arg); } return r_symreal(arg); } static const char* r_unique(arg) struct load_arg *arg; { return rb_id2name(r_symbol(arg)); } static VALUE r_string(arg) struct load_arg *arg; { return r_bytes(arg); } static VALUE r_entry(v, arg) VALUE v; struct load_arg *arg; { st_insert(arg->data, arg->data->num_entries, (st_data_t)v); if (arg->taint) OBJ_TAINT(v); return v; } static void r_ivar(obj, arg) VALUE obj; struct load_arg *arg; { long len; len = r_long(arg); if (len > 0) { while (len--) { ID id = r_symbol(arg); VALUE val = r_object(arg); rb_ivar_set(obj, id, val); } } } static VALUE path2class(path) const char *path; { VALUE v = rb_path2class(path); if (TYPE(v) != T_CLASS) { rb_raise(rb_eArgError, "%s does not refer class", path); } return v; } static VALUE path2module(path) const char *path; { VALUE v = rb_path2class(path); if (TYPE(v) != T_MODULE) { rb_raise(rb_eArgError, "%s does not refer module", path); } return v; } static VALUE r_object0(arg, proc, ivp, extmod) struct load_arg *arg; VALUE proc; int *ivp; VALUE extmod; { VALUE v = Qnil; int type = r_byte(arg); long id; st_data_t link; switch (type) { case TYPE_LINK: id = r_long(arg); if (!st_lookup(arg->data, (st_data_t)id, &link)) { rb_raise(rb_eArgError, "dump format error (unlinked)"); } v = (st_data_t)link; return v; case TYPE_IVAR: { int ivar = Qtrue; v = r_object0(arg, 0, &ivar, extmod); if (ivar) r_ivar(v, arg); } break; case TYPE_EXTENDED: { VALUE m = path2module(r_unique(arg)); if (NIL_P(extmod)) extmod = rb_ary_new2(0); rb_ary_push(extmod, m); v = r_object0(arg, 0, 0, extmod); while (RARRAY(extmod)->len > 0) { m = rb_ary_pop(extmod); rb_extend_object(v, m); } } break; case TYPE_UCLASS: { VALUE c = path2class(r_unique(arg)); if (FL_TEST(c, FL_SINGLETON)) { rb_raise(rb_eTypeError, "singleton can't be loaded"); } v = r_object0(arg, 0, 0, extmod); if (rb_special_const_p(v) || TYPE(v) == T_OBJECT || TYPE(v) == T_CLASS) { format_error: rb_raise(rb_eArgError, "dump format error (user class)"); } if (TYPE(v) == T_MODULE || !RTEST(rb_class_inherited_p(c, RBASIC(v)->klass))) { VALUE tmp = rb_obj_alloc(c); if (TYPE(v) != TYPE(tmp)) goto format_error; } RBASIC(v)->klass = c; } break; case TYPE_NIL: v = Qnil; break; case TYPE_TRUE: v = Qtrue; break; case TYPE_FALSE: v = Qfalse; break; case TYPE_FIXNUM: { long i = r_long(arg); v = LONG2FIX(i); } break; case TYPE_FLOAT: { double d, t = 0.0; VALUE str = r_bytes(arg); const char *ptr = RSTRING(str)->ptr; if (strcmp(ptr, "nan") == 0) { d = t / t; } else if (strcmp(ptr, "inf") == 0) { d = 1.0 / t; } else if (strcmp(ptr, "-inf") == 0) { d = -1.0 / t; } else { char *e; d = strtod(ptr, &e); d = load_mantissa(d, e, RSTRING(str)->len - (e - ptr)); } v = rb_float_new(d); r_entry(v, arg); } break; case TYPE_BIGNUM: { long len; BDIGIT *digits; volatile VALUE data; NEWOBJ(big, struct RBignum); OBJSETUP(big, rb_cBignum, T_BIGNUM); big->sign = (r_byte(arg) == '+'); len = r_long(arg); data = r_bytes0(len * 2, arg); #if SIZEOF_BDIGITS == SIZEOF_SHORT big->len = len; #else big->len = (len + 1) * 2 / sizeof(BDIGIT); #endif big->digits = digits = ALLOC_N(BDIGIT, big->len); MEMCPY(digits, RSTRING(data)->ptr, char, len * 2); #if SIZEOF_BDIGITS > SIZEOF_SHORT MEMZERO((char *)digits + len * 2, char, big->len * sizeof(BDIGIT) - len * 2); #endif len = big->len; while (len > 0) { unsigned char *p = (unsigned char *)digits; BDIGIT num = 0; #if SIZEOF_BDIGITS > SIZEOF_SHORT int shift = 0; int i; for (i=0; iptr, RSTRING(str)->len, options), arg); } break; case TYPE_ARRAY: { volatile long len = r_long(arg); /* gcc 2.7.2.3 -O2 bug?? */ v = rb_ary_new2(len); r_entry(v, arg); while (len--) { rb_ary_push(v, r_object(arg)); } } break; case TYPE_HASH: case TYPE_HASH_DEF: { long len = r_long(arg); v = rb_hash_new(); r_entry(v, arg); while (len--) { VALUE key = r_object(arg); VALUE value = r_object(arg); rb_hash_aset(v, key, value); } if (type == TYPE_HASH_DEF) { RHASH(v)->ifnone = r_object(arg); } } break; case TYPE_STRUCT: { VALUE klass, mem, values; volatile long i; /* gcc 2.7.2.3 -O2 bug?? */ long len; ID slot; klass = path2class(r_unique(arg)); mem = rb_struct_s_members(klass); len = r_long(arg); values = rb_ary_new2(len); for (i=0; iptr[i] != ID2SYM(slot)) { rb_raise(rb_eTypeError, "struct %s not compatible (:%s for :%s)", rb_class2name(klass), rb_id2name(slot), rb_id2name(SYM2ID(RARRAY(mem)->ptr[i]))); } rb_struct_aset(v, LONG2FIX(i), r_object(arg)); } } break; case TYPE_USERDEF: { VALUE klass = path2class(r_unique(arg)); VALUE data; if (!rb_respond_to(klass, s_load)) { rb_raise(rb_eTypeError, "class %s needs to have method `_load'", rb_class2name(klass)); } data = r_string(arg); if (ivp) { r_ivar(data, arg); *ivp = Qfalse; } v = rb_funcall(klass, s_load, 1, data); check_load_arg(arg, s_load); r_entry(v, arg); } break; case TYPE_USRMARSHAL: { VALUE klass = path2class(r_unique(arg)); VALUE data; v = rb_obj_alloc(klass); if (! NIL_P(extmod)) { while (RARRAY(extmod)->len > 0) { VALUE m = rb_ary_pop(extmod); rb_extend_object(v, m); } } if (!rb_respond_to(v, s_mload)) { rb_raise(rb_eTypeError, "instance of %s needs to have method `marshal_load'", rb_class2name(klass)); } r_entry(v, arg); data = r_object(arg); rb_funcall(v, s_mload, 1, data); check_load_arg(arg, s_mload); } break; case TYPE_OBJECT: { VALUE klass = path2class(r_unique(arg)); v = rb_obj_alloc(klass); if (TYPE(v) != T_OBJECT) { rb_raise(rb_eArgError, "dump format error"); } r_entry(v, arg); r_ivar(v, arg); } break; case TYPE_DATA: { VALUE klass = path2class(r_unique(arg)); if (rb_respond_to(klass, s_alloc)) { static int warn = Qtrue; if (warn) { rb_warn("define `allocate' instead of `_alloc'"); warn = Qfalse; } v = rb_funcall(klass, s_alloc, 0); check_load_arg(arg, s_alloc); } else { v = rb_obj_alloc(klass); } if (TYPE(v) != T_DATA) { rb_raise(rb_eArgError, "dump format error"); } r_entry(v, arg); if (!rb_respond_to(v, s_load_data)) { rb_raise(rb_eTypeError, "class %s needs to have instance method `_load_data'", rb_class2name(klass)); } rb_funcall(v, s_load_data, 1, r_object0(arg, 0, 0, extmod)); check_load_arg(arg, s_load_data); } break; case TYPE_MODULE_OLD: { volatile VALUE str = r_bytes(arg); v = rb_path2class(RSTRING(str)->ptr); r_entry(v, arg); } break; case TYPE_CLASS: { volatile VALUE str = r_bytes(arg); v = path2class(RSTRING(str)->ptr); r_entry(v, arg); } break; case TYPE_MODULE: { volatile VALUE str = r_bytes(arg); v = path2module(RSTRING(str)->ptr); r_entry(v, arg); } break; case TYPE_SYMBOL: v = ID2SYM(r_symreal(arg)); break; case TYPE_SYMLINK: return ID2SYM(r_symlink(arg)); default: rb_raise(rb_eArgError, "dump format error(0x%x)", type); break; } if (proc) { rb_funcall(proc, s_call, 1, v); check_load_arg(arg, s_call); } return v; } static VALUE r_object(arg) struct load_arg *arg; { return r_object0(arg, arg->proc, 0, Qnil); } static void clear_load_arg(arg) struct load_arg *arg; { if (!arg->symbols) return; st_free_table(arg->symbols); arg->symbols = 0; st_free_table(arg->data); } /* * call-seq: * load( source [, proc] ) => obj * restore( source [, proc] ) => obj * * Returns the result of converting the serialized data in source into a * Ruby object (possibly with associated subordinate objects). source * may be either an instance of IO or an object that responds to * to_str. If proc is specified, it will be passed each object as it * is deserialized. */ static VALUE marshal_load(argc, argv) int argc; VALUE *argv; { VALUE port, proc; int major, minor, taint = Qfalse; VALUE v, wrapper; struct load_arg *arg; rb_scan_args(argc, argv, "11", &port, &proc); v = rb_check_string_type(port); if (!NIL_P(v)) { taint = OBJ_TAINTED(port); /* original taintedness */ port = v; } else if (rb_respond_to(port, s_getc) && rb_respond_to(port, s_read)) { if (rb_respond_to(port, s_binmode)) { rb_funcall2(port, s_binmode, 0, 0); } taint = Qtrue; } else { rb_raise(rb_eTypeError, "instance of IO needed"); } wrapper = Data_Make_Struct(rb_cData, struct load_arg, mark_load_arg, free_load_arg, arg); arg->src = port; arg->offset = 0; arg->symbols = st_init_numtable(); arg->data = st_init_numtable(); arg->proc = 0; arg->taint = taint; major = r_byte(arg); minor = r_byte(arg); if (major != MARSHAL_MAJOR || minor > MARSHAL_MINOR) { clear_load_arg(arg); rb_raise(rb_eTypeError, "incompatible marshal file format (can't be read)\n\ \tformat version %d.%d required; %d.%d given", MARSHAL_MAJOR, MARSHAL_MINOR, major, minor); } if (RTEST(ruby_verbose) && minor != MARSHAL_MINOR) { rb_warn("incompatible marshal file format (can be read)\n\ \tformat version %d.%d required; %d.%d given", MARSHAL_MAJOR, MARSHAL_MINOR, major, minor); } if (!NIL_P(proc)) arg->proc = proc; v = r_object(arg); clear_load_arg(arg); RB_GC_GUARD(wrapper); return v; } /* * The marshaling library converts collections of Ruby objects into a * byte stream, allowing them to be stored outside the currently * active script. This data may subsequently be read and the original * objects reconstituted. * Marshaled data has major and minor version numbers stored along * with the object information. In normal use, marshaling can only * load data written with the same major version number and an equal * or lower minor version number. If Ruby's ``verbose'' flag is set * (normally using -d, -v, -w, or --verbose) the major and minor * numbers must match exactly. Marshal versioning is independent of * Ruby's version numbers. You can extract the version by reading the * first two bytes of marshaled data. * * str = Marshal.dump("thing") * RUBY_VERSION #=> "1.8.0" * str[0] #=> 4 * str[1] #=> 8 * * Some objects cannot be dumped: if the objects to be dumped include * bindings, procedure or method objects, instances of class IO, or * singleton objects, a TypeError will be raised. * If your class has special serialization needs (for example, if you * want to serialize in some specific format), or if it contains * objects that would otherwise not be serializable, you can implement * your own serialization strategy by defining two methods, _dump and * _load: * The instance method _dump should return a String object containing * all the information necessary to reconstitute objects of this class * and all referenced objects up to a maximum depth given as an integer * parameter (a value of -1 implies that you should disable depth checking). * The class method _load should take a String and return an object of this class. */ void Init_marshal() { VALUE rb_mMarshal = rb_define_module("Marshal"); s_dump = rb_intern("_dump"); s_load = rb_intern("_load"); s_mdump = rb_intern("marshal_dump"); s_mload = rb_intern("marshal_load"); s_dump_data = rb_intern("_dump_data"); s_load_data = rb_intern("_load_data"); s_alloc = rb_intern("_alloc"); s_call = rb_intern("call"); s_getc = rb_intern("getc"); s_read = rb_intern("read"); s_write = rb_intern("write"); s_binmode = rb_intern("binmode"); rb_define_module_function(rb_mMarshal, "dump", marshal_dump, -1); rb_define_module_function(rb_mMarshal, "load", marshal_load, -1); rb_define_module_function(rb_mMarshal, "restore", marshal_load, -1); rb_define_const(rb_mMarshal, "MAJOR_VERSION", INT2FIX(MARSHAL_MAJOR)); rb_define_const(rb_mMarshal, "MINOR_VERSION", INT2FIX(MARSHAL_MINOR)); } VALUE rb_marshal_dump(obj, port) VALUE obj, port; { int argc = 1; VALUE argv[2]; argv[0] = obj; argv[1] = port; if (!NIL_P(port)) argc = 2; return marshal_dump(argc, argv); } VALUE rb_marshal_load(port) VALUE port; { return marshal_load(1, &port); } ================================================ FILE: math.c ================================================ /********************************************************************** math.c - $Author$ $Date$ created at: Tue Jan 25 14:12:56 JST 1994 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #include "ruby.h" #include #include VALUE rb_mMath; #define Need_Float(x) (x) = rb_Float(x) #define Need_Float2(x,y) do {\ Need_Float(x);\ Need_Float(y);\ } while (0) static void domain_check(x, msg) double x; char *msg; { while(1) { if (errno) { rb_sys_fail(msg); } if (isnan(x)) { #if defined(EDOM) errno = EDOM; #elif defined(ERANGE) errno = ERANGE; #endif continue; } break; } } /* * call-seq: * Math.atan2(y, x) => float * * Computes the arc tangent given y and x. Returns * -PI..PI. * */ static VALUE math_atan2(obj, y, x) VALUE obj, x, y; { Need_Float2(y, x); return rb_float_new(atan2(RFLOAT(y)->value, RFLOAT(x)->value)); } /* * call-seq: * Math.cos(x) => float * * Computes the cosine of x (expressed in radians). Returns * -1..1. */ static VALUE math_cos(obj, x) VALUE obj, x; { Need_Float(x); return rb_float_new(cos(RFLOAT(x)->value)); } /* * call-seq: * Math.sin(x) => float * * Computes the sine of x (expressed in radians). Returns * -1..1. */ static VALUE math_sin(obj, x) VALUE obj, x; { Need_Float(x); return rb_float_new(sin(RFLOAT(x)->value)); } /* * call-seq: * Math.tan(x) => float * * Returns the tangent of x (expressed in radians). */ static VALUE math_tan(obj, x) VALUE obj, x; { Need_Float(x); return rb_float_new(tan(RFLOAT(x)->value)); } /* * call-seq: * Math.acos(x) => float * * Computes the arc cosine of x. Returns 0..PI. */ static VALUE math_acos(obj, x) VALUE obj, x; { double d; Need_Float(x); errno = 0; d = acos(RFLOAT(x)->value); domain_check(d, "acos"); return rb_float_new(d); } /* * call-seq: * Math.asin(x) => float * * Computes the arc sine of x. Returns -{PI/2} .. {PI/2}. */ static VALUE math_asin(obj, x) VALUE obj, x; { double d; Need_Float(x); errno = 0; d = asin(RFLOAT(x)->value); domain_check(d, "asin"); return rb_float_new(d); } /* * call-seq: * Math.atan(x) => float * * Computes the arc tangent of x. Returns -{PI/2} .. {PI/2}. */ static VALUE math_atan(obj, x) VALUE obj, x; { Need_Float(x); return rb_float_new(atan(RFLOAT(x)->value)); } #ifndef HAVE_COSH double cosh(x) double x; { return (exp(x) + exp(-x)) / 2; } #endif /* * call-seq: * Math.cosh(x) => float * * Computes the hyperbolic cosine of x (expressed in radians). */ static VALUE math_cosh(obj, x) VALUE obj, x; { Need_Float(x); return rb_float_new(cosh(RFLOAT(x)->value)); } #ifndef HAVE_SINH double sinh(x) double x; { return (exp(x) - exp(-x)) / 2; } #endif /* * call-seq: * Math.sinh(x) => float * * Computes the hyperbolic sine of x (expressed in * radians). */ static VALUE math_sinh(obj, x) VALUE obj, x; { Need_Float(x); return rb_float_new(sinh(RFLOAT(x)->value)); } #ifndef HAVE_TANH double tanh(x) double x; { return sinh(x) / cosh(x); } #endif /* * call-seq: * Math.tanh() => float * * Computes the hyperbolic tangent of x (expressed in * radians). */ static VALUE math_tanh(obj, x) VALUE obj, x; { Need_Float(x); return rb_float_new(tanh(RFLOAT(x)->value)); } /* * call-seq: * Math.acosh(x) => float * * Computes the inverse hyperbolic cosine of x. */ static VALUE math_acosh(obj, x) VALUE obj, x; { double d; Need_Float(x); errno = 0; d = acosh(RFLOAT(x)->value); domain_check(d, "acosh"); return rb_float_new(d); } /* * call-seq: * Math.asinh(x) => float * * Computes the inverse hyperbolic sine of x. */ static VALUE math_asinh(obj, x) VALUE obj, x; { Need_Float(x); return rb_float_new(asinh(RFLOAT(x)->value)); } /* * call-seq: * Math.atanh(x) => float * * Computes the inverse hyperbolic tangent of x. */ static VALUE math_atanh(obj, x) VALUE obj, x; { double d; Need_Float(x); errno = 0; d = atanh(RFLOAT(x)->value); domain_check(d, "atanh"); return rb_float_new(d); } /* * call-seq: * Math.exp(x) => float * * Returns e**x. */ static VALUE math_exp(obj, x) VALUE obj, x; { Need_Float(x); return rb_float_new(exp(RFLOAT(x)->value)); } #if defined __CYGWIN__ # include # if CYGWIN_VERSION_DLL_MAJOR < 1005 # define nan(x) nan() # endif # define log(x) ((x) < 0.0 ? nan("") : log(x)) # define log10(x) ((x) < 0.0 ? nan("") : log10(x)) #endif /* * call-seq: * Math.log(numeric) => float * * Returns the natural logarithm of numeric. */ static VALUE math_log(obj, x) VALUE obj, x; { double d; Need_Float(x); errno = 0; d = log(RFLOAT(x)->value); domain_check(d, "log"); return rb_float_new(d); } /* * call-seq: * Math.log10(numeric) => float * * Returns the base 10 logarithm of numeric. */ static VALUE math_log10(obj, x) VALUE obj, x; { double d; Need_Float(x); errno = 0; d = log10(RFLOAT(x)->value); domain_check(d, "log10"); return rb_float_new(d); } /* * call-seq: * Math.sqrt(numeric) => float * * Returns the non-negative square root of numeric. */ static VALUE math_sqrt(obj, x) VALUE obj, x; { double d; Need_Float(x); errno = 0; d = sqrt(RFLOAT(x)->value); domain_check(d, "sqrt"); return rb_float_new(d); } /* * call-seq: * Math.frexp(numeric) => [ fraction, exponent ] * * Returns a two-element array containing the normalized fraction (a * Float) and exponent (a Fixnum) of * numeric. * * fraction, exponent = Math.frexp(1234) #=> [0.6025390625, 11] * fraction * 2**exponent #=> 1234.0 */ static VALUE math_frexp(obj, x) VALUE obj, x; { double d; int exp; Need_Float(x); d = frexp(RFLOAT(x)->value, &exp); return rb_assoc_new(rb_float_new(d), INT2NUM(exp)); } /* * call-seq: * Math.ldexp(flt, int) -> float * * Returns the value of flt*(2**int). * * fraction, exponent = Math.frexp(1234) * Math.ldexp(fraction, exponent) #=> 1234.0 */ static VALUE math_ldexp(obj, x, n) VALUE obj, x, n; { Need_Float(x); return rb_float_new(ldexp(RFLOAT(x)->value, NUM2INT(n))); } /* * call-seq: * Math.hypot(x, y) => float * * Returns sqrt(x**2 + y**2), the hypotenuse of a right-angled triangle * with sides x and y. * * Math.hypot(3, 4) #=> 5.0 */ static VALUE math_hypot(obj, x, y) VALUE obj, x, y; { Need_Float2(x, y); return rb_float_new(hypot(RFLOAT(x)->value, RFLOAT(y)->value)); } /* * call-seq: * Math.erf(x) => float * * Calculates the error function of x. */ static VALUE math_erf(obj, x) VALUE obj, x; { Need_Float(x); return rb_float_new(erf(RFLOAT(x)->value)); } /* * call-seq: * Math.erfc(x) => float * * Calculates the complementary error function of x. */ static VALUE math_erfc(obj, x) VALUE obj, x; { Need_Float(x); return rb_float_new(erfc(RFLOAT(x)->value)); } /* * The Math module contains module functions for basic * trigonometric and transcendental functions. See class * Float for a list of constants that * define Ruby's floating point accuracy. */ void Init_Math() { rb_mMath = rb_define_module("Math"); #ifdef M_PI rb_define_const(rb_mMath, "PI", rb_float_new(M_PI)); #else rb_define_const(rb_mMath, "PI", rb_float_new(atan(1.0)*4.0)); #endif #ifdef M_E rb_define_const(rb_mMath, "E", rb_float_new(M_E)); #else rb_define_const(rb_mMath, "E", rb_float_new(exp(1.0))); #endif rb_define_module_function(rb_mMath, "atan2", math_atan2, 2); rb_define_module_function(rb_mMath, "cos", math_cos, 1); rb_define_module_function(rb_mMath, "sin", math_sin, 1); rb_define_module_function(rb_mMath, "tan", math_tan, 1); rb_define_module_function(rb_mMath, "acos", math_acos, 1); rb_define_module_function(rb_mMath, "asin", math_asin, 1); rb_define_module_function(rb_mMath, "atan", math_atan, 1); rb_define_module_function(rb_mMath, "cosh", math_cosh, 1); rb_define_module_function(rb_mMath, "sinh", math_sinh, 1); rb_define_module_function(rb_mMath, "tanh", math_tanh, 1); rb_define_module_function(rb_mMath, "acosh", math_acosh, 1); rb_define_module_function(rb_mMath, "asinh", math_asinh, 1); rb_define_module_function(rb_mMath, "atanh", math_atanh, 1); rb_define_module_function(rb_mMath, "exp", math_exp, 1); rb_define_module_function(rb_mMath, "log", math_log, 1); rb_define_module_function(rb_mMath, "log10", math_log10, 1); rb_define_module_function(rb_mMath, "sqrt", math_sqrt, 1); rb_define_module_function(rb_mMath, "frexp", math_frexp, 1); rb_define_module_function(rb_mMath, "ldexp", math_ldexp, 2); rb_define_module_function(rb_mMath, "hypot", math_hypot, 2); rb_define_module_function(rb_mMath, "erf", math_erf, 1); rb_define_module_function(rb_mMath, "erfc", math_erfc, 1); } ================================================ FILE: mdoc2man.rb ================================================ #!/usr/bin/env ruby ### ### mdoc2man - mdoc to man converter ### ### Quick usage: mdoc2man.rb < mdoc_manpage.8 > man_manpage.8 ### ### Ported from Perl by Akinori MUSHA. ### ### Copyright (c) 2001 University of Illinois Board of Trustees ### Copyright (c) 2001 Mark D. Roth ### Copyright (c) 2002, 2003 Akinori MUSHA ### All rights reserved. ### ### Redistribution and use in source and binary forms, with or without ### modification, are permitted provided that the following conditions ### are met: ### 1. Redistributions of source code must retain the above copyright ### notice, this list of conditions and the following disclaimer. ### 2. Redistributions in binary form must reproduce the above copyright ### notice, this list of conditions and the following disclaimer in the ### documentation and/or other materials provided with the distribution. ### 3. All advertising materials mentioning features or use of this software ### must display the following acknowledgement: ### This product includes software developed by the University of ### Illinois at Urbana, and their contributors. ### 4. The University nor the names of their ### contributors may be used to endorse or promote products derived from ### this software without specific prior written permission. ### ### THIS SOFTWARE IS PROVIDED BY THE TRUSTEES AND CONTRIBUTORS ``AS IS'' AND ### ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ### IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ### ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES OR CONTRIBUTORS BE LIABLE ### FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ### DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ### OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ### HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ### LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ### OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ### SUCH DAMAGE. ### ### $Id$ ### class Mdoc2Man ANGLE = 1 OPTION = 2 PAREN = 3 RE_PUNCT = /^[!"'),\.\/:;>\?\]`]$/ def initialize @name = @date = @id = nil @refauthors = @reftitle = @refissue = @refdate = @refopt = nil @optlist = 0 ### 1 = bullet, 2 = enum, 3 = tag, 4 = item @oldoptlist = 0 @nospace = 0 ### 0, 1, 2 @enum = 0 @synopsis = true @reference = false @ext = false @extopt = false @literal = false end def mdoc2man(i, o) i.each { |line| if /^\./ !~ line o.print line o.print ".br\n" if @literal next end line.slice!(0, 1) next if /\\"/ =~ line line = parse_macro(line) and o.print line } initialize end def parse_macro(line) words = line.split retval = '' quote = [] dl = false while word = words.shift case word when RE_PUNCT while q = quote.pop case q when OPTION retval << ']' when PAREN retval << ')' when ANGLE retval << '>' end end retval << word next when 'Li', 'Pf' @nospace = 1 next when 'Xo' @ext = true retval << ' ' unless retval.empty? || /[\n ]\z/ =~ retval next when 'Xc' @ext = false retval << "\n" unless @extopt break when 'Bd' @literal = true if words[0] == '-literal' retval << "\n" break when 'Ed' @literal = false break when 'Ns' @nospace = 1 if @nospace == 0 retval.chomp!(' ') next when 'No' retval.chomp!(' ') retval << words.shift next when 'Dq' retval << '``' begin retval << words.shift << ' ' end until words.empty? || RE_PUNCT =~ words[0] retval.chomp!(' ') retval << '\'\'' @nospace = 1 if @nospace == 0 && RE_PUNCT =~ words[0] next when 'Sq', 'Ql' retval << '`' << words.shift << '\'' @nospace = 1 if @nospace == 0 && RE_PUNCT =~ words[0] next # when 'Ic' # retval << '\\fB' << words.shift << '\\fP' # next when 'Oo' #retval << "[\\c\n" @extopt = true @nospace = 1 if @nospace == 0 retval << '[' next when 'Oc' @extopt = false retval << ']' next when 'Ao' @nospace = 1 if @nospace == 0 retval << '<' next when 'Ac' retval << '>' next end retval << ' ' if @nospace == 0 && !(retval.empty? || /[\n ]\z/ =~ retval) @nospace = 0 if @nospace == 1 case word when 'Dd' @date = words.join(' ') return nil when 'Dt' if words.size >= 2 && words[1] == '""' && /^(.*)\(([0-9])\)$/ =~ words[0] words[0] = $1 words[1] = $2 end @id = words.join(' ') return nil when 'Os' retval << '.TH ' << @id << ' "' << @date << '" "' << words.join(' ') << '"' break when 'Sh' retval << '.SH' @synopsis = (words[0] == 'SYNOPSIS') next when 'Xr' retval << '\\fB' << words.shift << '\\fP(' << words.shift << ')' << words.shift break when 'Rs' @refauthors = [] @reftitle = '' @refissue = '' @refdate = '' @refopt = '' @reference = true break when 'Re' retval << "\n" # authors while @refauthors.size > 1 retval << @refauthors.shift << ', ' end retval << 'and ' unless retval.empty? retval << @refauthors.shift # title retval << ', \\fI' << @reftitle << '\\fP' # issue retval << ', ' << @refissue unless @refissue.empty? # date retval << ', ' << @refdate unless @refdate.empty? # optional info retval << ', ' << @refopt unless @refopt.empty? retval << ".\n" @reference = false break when 'An' next when 'Dl' retval << ".nf\n" << '\\& ' dl = true next when 'Ux' retval << "UNIX" next end if @reference case word when '%A' @refauthors.unshift(words.join(' ')) break when '%T' @reftitle = words.join(' ') @reftitle.sub!(/^"/, '') @reftitle.sub!(/"$/, '') break when '%N' @refissue = words.join(' ') break when '%D' @refdate = words.join(' ') break when '%O' @refopt = words.join(' ') break end end case word when 'Nm' name = words.empty? ? @name : words.shift @name ||= name retval << ".br\n" if @synopsis retval << "\\fB" << name << "\\fP" @nospace = 1 if @nospace == 0 && RE_PUNCT =~ words[0] next when 'Nd' retval << '\\-' next when 'Fl' retval << '\\fB\\-' << words.shift << '\\fP' @nospace = 1 if @nospace == 0 && RE_PUNCT =~ words[0] next when 'Ar' retval << '\\fI' if words.empty? retval << 'file ...\\fP' else retval << words.shift << '\\fP' while words[0] == '|' retval << ' ' << words.shift << ' \\fI' << words.shift << '\\fP' end @nospace = 1 if @nospace == 0 && RE_PUNCT =~ words[0] next end when 'Cm' retval << '\\fB' << words.shift << '\\fP' while RE_PUNCT =~ words[0] retval << words.shift end next when 'Op' quote << OPTION @nospace = 1 if @nospace == 0 retval << '[' # words.push(words.pop + ']') next when 'Aq' quote << ANGLE @nospace = 1 if @nospace == 0 retval << '<' # words.push(words.pop + '>') next when 'Pp' retval << "\n" next when 'Ss' retval << '.SS' next end if word == 'Pa' && !quote.include?(OPTION) retval << '\\fI' retval << '\\&' if /^\./ =~ words[0] retval << words.shift << '\\fP' while RE_PUNCT =~ words[0] retval << words.shift end # @nospace = 1 if @nospace == 0 && RE_PUNCT =~ words[0] next end case word when 'Dv' retval << '.BR' next when 'Em', 'Ev' retval << '.IR' next when 'Pq' retval << '(' @nospace = 1 quote << PAREN next when 'Sx', 'Sy' retval << '.B ' << words.join(' ') break when 'Ic' retval << '\\fB' until words.empty? || RE_PUNCT =~ words[0] case words[0] when 'Op' words.shift retval << '[' words.push(words.pop + ']') next when 'Aq' words.shift retval << '<' words.push(words.pop + '>') next when 'Ar' words.shift retval << '\\fI' << words.shift << '\\fP' else retval << words.shift end retval << ' ' if @nospace == 0 end retval.chomp!(' ') retval << '\\fP' retval << words.shift unless words.empty? break when 'Bl' @oldoptlist = @optlist case words[0] when '-bullet' @optlist = 1 when '-enum' @optlist = 2 @enum = 0 when '-tag' @optlist = 3 when '-item' @optlist = 4 end break when 'El' @optlist = @oldoptlist next end if @optlist != 0 && word == 'It' case @optlist when 1 # bullets retval << '.IP \\(bu' when 2 # enum @enum += 1 retval << '.IP ' << @enum << '.' when 3 # tags retval << ".TP\n" case words[0] when 'Pa', 'Ev' words.shift retval << '.B' end when 4 # item retval << ".IP\n" end next end case word when 'Sm' case words[0] when 'off' @nospace = 2 when 'on' # retval << "\n" @nospace = 0 end words.shift next end retval << word end return nil if retval == '.' retval.sub!(/\A\.([^a-zA-Z])/, "\\1") # retval.chomp!(' ') while q = quote.pop case q when OPTION retval << ']' when PAREN retval << ')' when ANGLE retval << '>' end end # retval << ' ' unless @nospace == 0 || retval.empty? || /\n\z/ =~ retval retval << ' ' unless !@ext || @extopt || / $/ =~ retval retval << "\n" unless @ext || @extopt || retval.empty? || /\n\z/ =~ retval retval << ".fi\n" if dl return retval end def self.mdoc2man(i, o) new.mdoc2man(i, o) end end if $0 == __FILE__ Mdoc2Man.mdoc2man(ARGF, STDOUT) end ================================================ FILE: misc/README ================================================ README this file inf-ruby.el program to run ruby under emacs ruby-mode.el ruby mode for emacs rubydb2x.el ruby debugger support for emacs 19.2x or before rubydb3x.el ruby debugger support for emacs 19.3x or later ruby-electric.el emacs minor mode providing electric commands Check out http://rubyforge.org/projects/ruby-debug/ also. ================================================ FILE: misc/inf-ruby.el ================================================ ;;; -*-Emacs-Lisp-*- ;;; ;;; $Id$ ;;; $Author$ ;;; $Date$ ;;; ;;; Inferior Ruby Mode - ruby process in a buffer. ;;; adapted from cmuscheme.el ;;; ;;; Usage: ;;; ;;; (0) check ruby-program-name variable that can run your environment. ;;; ;;; (1) modify .emacs to use ruby-mode ;;; for example : ;;; ;;; (autoload 'ruby-mode "ruby-mode" ;;; "Mode for editing ruby source files" t) ;;; (setq auto-mode-alist ;;; (append '(("\\.rb$" . ruby-mode)) auto-mode-alist)) ;;; (setq interpreter-mode-alist (append '(("ruby" . ruby-mode)) ;;; interpreter-mode-alist)) ;;; ;;; (2) set to load inf-ruby and set inf-ruby key definition in ruby-mode. ;;; ;;; (autoload 'run-ruby "inf-ruby" ;;; "Run an inferior Ruby process") ;;; (autoload 'inf-ruby-keys "inf-ruby" ;;; "Set local key defs for inf-ruby in ruby-mode") ;;; (add-hook 'ruby-mode-hook ;;; '(lambda () ;;; (inf-ruby-keys) ;;; )) ;;; ;;; HISTORY ;;; senda - 8 Apr 1998: Created. ;;; $Log$ ;;; Revision 1.7 2004/07/27 08:11:36 matz ;;; * eval.c (rb_eval): copy on write for argument local variable ;;; assignment. ;;; ;;; * eval.c (assign): ditto. ;;; ;;; * eval.c (rb_call0): update ruby_frame->argv with the default ;;; value used for the optional arguments. ;;; ;;; * object.c (Init_Object): "===" calls rb_obj_equal() directly. ;;; [ruby-list:39937] ;;; ;;; Revision 1.6 2002/09/07 14:35:46 nobu ;;; * misc/inf-ruby.el (inferior-ruby-error-regexp-alist): regexp ;;; alist for error message from ruby. ;;; ;;; * misc/inf-ruby.el (inferior-ruby-mode): fixed for Emacs. ;;; ;;; * misc/inf-ruby.el (ruby-send-region): compilation-parse-errors ;;; doesn't parse first line, so insert separators before each ;;; evaluations. ;;; ;;; Revision 1.5 2002/08/19 10:05:47 nobu ;;; * misc/inf-ruby.el (inf-ruby-keys): ruby-send-definition ;;; conflicted with ruby-insert-end. ;;; ;;; * misc/inf-ruby.el (inferior-ruby-mode): compilation-minor-mode. ;;; ;;; * misc/inf-ruby.el (ruby-send-region): send as here document to ;;; adjust source file/line. [ruby-talk:47113], [ruby-dev:17965] ;;; ;;; * misc/inf-ruby.el (ruby-send-terminator): added to make unique ;;; terminator. ;;; ;;; Revision 1.4 2002/01/29 07:16:09 matz ;;; * file.c (rb_stat_rdev_major): added. [new] ;;; ;;; * file.c (rb_stat_rdev_minor): added. [new] ;;; ;;; * file.c (rb_stat_inspect): print mode in octal. ;;; ;;; Revision 1.3 1999/12/01 09:24:18 matz ;;; 19991201 ;;; ;;; Revision 1.2 1999/08/13 05:45:18 matz ;;; 1.4.0 ;;; ;;; Revision 1.1.1.1.2.1 1999/07/15 07:59:59 matz ;;; 990715 ;;; ;;; Revision 1.1.1.1 1999/01/20 04:59:36 matz ;;; ruby 1.3 cycle ;;; ;;; Revision 1.1.2.1 1998/12/16 07:30:36 matz ;;; first public release of 1.1d (pre1.2) series ;;; ;;; Revision 1.4 1998/05/20 02:45:58 senda ;;; default program to irb ;;; ;;; Revision 1.3 1998/04/10 04:11:30 senda ;;; modification by Matsumoto san (1.1b9_09) ;;; remove-in-string defined ;;; global variable : ;;; inferior-ruby-first-prompt-pattern ;;; inferior-ruby-prompt-pattern ;;; defined ;;; ;;; Revision 1.2 1998/04/09 07:53:42 senda ;;; remove M-C-x in inferior-ruby-mode ;;; ;;; Revision 1.1 1998/04/09 07:28:36 senda ;;; Initial revision ;;; ;;; (require 'comint) (require 'compile) (require 'ruby-mode) ;; ;; you may change these variables ;; ;(defvar ruby-program-name "rbc --noreadline" ; "*Program invoked by the run-ruby command") ; ;(defvar inferior-ruby-first-prompt-pattern "^rbc0> *" ; "first prompt regex pattern of ruby interpreter.") ; ;(defvar inferior-ruby-prompt-pattern "^\\(rbc.[>*\"'] *\\)+" ; "prompt regex pattern of ruby interpreter.") ;;;; for irb (defvar ruby-program-name "irb --inf-ruby-mode" "*Program invoked by the run-ruby command") (defvar inferior-ruby-first-prompt-pattern "^irb(.*)[0-9:]+0> *" "first prompt regex pattern of ruby interpreter.") (defvar inferior-ruby-prompt-pattern "^\\(irb(.*)[0-9:]+[>*\"'] *\\)+" "prompt regex pattern of ruby interpreter.") ;; ;; mode variables ;; (defvar inferior-ruby-mode-hook nil "*Hook for customising inferior-ruby mode.") (defvar inferior-ruby-mode-map nil "*Mode map for inferior-ruby-mode") (defconst inferior-ruby-error-regexp-alist '(("SyntaxError: compile error\n^\\([^\(].*\\):\\([1-9][0-9]*\\):" 1 2) ("^\tfrom \\([^\(].*\\):\\([1-9][0-9]*\\)\\(:in `.*'\\)?$" 1 2))) (cond ((not inferior-ruby-mode-map) (setq inferior-ruby-mode-map (copy-keymap comint-mode-map)) ; (define-key inferior-ruby-mode-map "\M-\C-x" ;gnu convention ; 'ruby-send-definition) ; (define-key inferior-ruby-mode-map "\C-x\C-e" 'ruby-send-last-sexp) (define-key inferior-ruby-mode-map "\C-c\C-l" 'ruby-load-file) )) (defun inf-ruby-keys () "Set local key defs for inf-ruby in ruby-mode" (define-key ruby-mode-map "\M-\C-x" 'ruby-send-definition) ; (define-key ruby-mode-map "\C-x\C-e" 'ruby-send-last-sexp) (define-key ruby-mode-map "\C-c\C-b" 'ruby-send-block) (define-key ruby-mode-map "\C-c\M-b" 'ruby-send-block-and-go) (define-key ruby-mode-map "\C-c\C-x" 'ruby-send-definition) (define-key ruby-mode-map "\C-c\M-x" 'ruby-send-definition-and-go) (define-key ruby-mode-map "\C-c\C-r" 'ruby-send-region) (define-key ruby-mode-map "\C-c\M-r" 'ruby-send-region-and-go) (define-key ruby-mode-map "\C-c\C-z" 'switch-to-ruby) (define-key ruby-mode-map "\C-c\C-l" 'ruby-load-file) (define-key ruby-mode-map "\C-c\C-s" 'run-ruby) ) (defvar ruby-buffer nil "current ruby (actually irb) process buffer.") (defun inferior-ruby-mode () "Major mode for interacting with an inferior ruby (irb) process. The following commands are available: \\{inferior-ruby-mode-map} A ruby process can be fired up with M-x run-ruby. Customisation: Entry to this mode runs the hooks on comint-mode-hook and inferior-ruby-mode-hook (in that order). You can send text to the inferior ruby process from other buffers containing Ruby source. switch-to-ruby switches the current buffer to the ruby process buffer. ruby-send-definition sends the current definition to the ruby process. ruby-send-region sends the current region to the ruby process. ruby-send-definition-and-go, ruby-send-region-and-go, switch to the ruby process buffer after sending their text. For information on running multiple processes in multiple buffers, see documentation for variable ruby-buffer. Commands: Return after the end of the process' output sends the text from the end of process to point. Return before the end of the process' output copies the sexp ending at point to the end of the process' output, and sends it. Delete converts tabs to spaces as it moves back. Tab indents for ruby; with argument, shifts rest of expression rigidly with the current line. C-M-q does Tab on each line starting within following expression. Paragraphs are separated only by blank lines. # start comments. If you accidentally suspend your process, use \\[comint-continue-subjob] to continue it." (interactive) (comint-mode) ;; Customise in inferior-ruby-mode-hook ;(setq comint-prompt-regexp "^[^>\n]*>+ *") (setq comint-prompt-regexp inferior-ruby-prompt-pattern) ;;(scheme-mode-variables) (ruby-mode-variables) (setq major-mode 'inferior-ruby-mode) (setq mode-name "Inferior Ruby") (setq mode-line-process '(":%s")) (use-local-map inferior-ruby-mode-map) (setq comint-input-filter (function ruby-input-filter)) (setq comint-get-old-input (function ruby-get-old-input)) (compilation-shell-minor-mode t) (make-local-variable 'compilation-error-regexp-alist) (setq compilation-error-regexp-alist inferior-ruby-error-regexp-alist) (run-hooks 'inferior-ruby-mode-hook)) (defvar inferior-ruby-filter-regexp "\\`\\s *\\S ?\\S ?\\s *\\'" "*Input matching this regexp are not saved on the history list. Defaults to a regexp ignoring all inputs of 0, 1, or 2 letters.") (defun ruby-input-filter (str) "Don't save anything matching inferior-ruby-filter-regexp" (not (string-match inferior-ruby-filter-regexp str))) ;; adapted from replace-in-string in XEmacs (subr.el) (defun remove-in-string (str regexp) "Remove all matches in STR for REGEXP and returns the new string." (let ((rtn-str "") (start 0) match prev-start) (while (setq match (string-match regexp str start)) (setq prev-start start start (match-end 0) rtn-str (concat rtn-str (substring str prev-start match)))) (concat rtn-str (substring str start)))) (defun ruby-get-old-input () "Snarf the sexp ending at point" (save-excursion (let ((end (point))) (re-search-backward inferior-ruby-first-prompt-pattern) (remove-in-string (buffer-substring (point) end) inferior-ruby-prompt-pattern) ))) (defun ruby-args-to-list (string) (let ((where (string-match "[ \t]" string))) (cond ((null where) (list string)) ((not (= where 0)) (cons (substring string 0 where) (ruby-args-to-list (substring string (+ 1 where) (length string))))) (t (let ((pos (string-match "[^ \t]" string))) (if (null pos) nil (ruby-args-to-list (substring string pos (length string))))))))) (defun run-ruby (cmd) "Run an inferior Ruby process, input and output via buffer *ruby*. If there is a process already running in `*ruby*', switch to that buffer. With argument, allows you to edit the command line (default is value of `ruby-program-name'). Runs the hooks `inferior-ruby-mode-hook' \(after the `comint-mode-hook' is run). \(Type \\[describe-mode] in the process buffer for a list of commands.)" (interactive (list (if current-prefix-arg (read-string "Run Ruby: " ruby-program-name) ruby-program-name))) (if (not (comint-check-proc "*ruby*")) (let ((cmdlist (ruby-args-to-list cmd))) (set-buffer (apply 'make-comint "ruby" (car cmdlist) nil (cdr cmdlist))) (inferior-ruby-mode))) (setq ruby-program-name cmd) (setq ruby-buffer "*ruby*") (pop-to-buffer "*ruby*")) (defconst ruby-send-terminator "--inf-ruby-%x-%d-%d-%d--" "Template for irb here document terminator. Must not contain ruby meta characters.") (defconst ruby-eval-separator "") (defun ruby-send-region (start end) "Send the current region to the inferior Ruby process." (interactive "r") (let (term (file (buffer-file-name)) line) (save-excursion (save-restriction (widen) (goto-char start) (setq line (+ start (forward-line (- start)) 1)) (goto-char start) (while (progn (setq term (apply 'format ruby-send-terminator (random) (current-time))) (re-search-forward (concat "^" (regexp-quote term) "$") end t))))) ;; compilation-parse-errors parses from second line. (save-excursion (let ((m (process-mark (ruby-proc)))) (set-buffer (marker-buffer m)) (goto-char m) (insert ruby-eval-separator "\n") (set-marker m (point)))) (comint-send-string (ruby-proc) (format "eval <<'%s', nil, %S, %d\n" term file line)) (comint-send-region (ruby-proc) start end) (comint-send-string (ruby-proc) (concat "\n" term "\n")))) (defun ruby-send-definition () "Send the current definition to the inferior Ruby process." (interactive) (save-excursion (ruby-end-of-defun) (let ((end (point))) (ruby-beginning-of-defun) (ruby-send-region (point) end)))) ;(defun ruby-send-last-sexp () ; "Send the previous sexp to the inferior Ruby process." ; (interactive) ; (ruby-send-region (save-excursion (backward-sexp) (point)) (point))) (defun ruby-send-block () "Send the current block to the inferior Ruby process." (interactive) (save-excursion (ruby-end-of-block) (end-of-line) (let ((end (point))) (ruby-beginning-of-block) (ruby-send-region (point) end)))) (defun switch-to-ruby (eob-p) "Switch to the ruby process buffer. With argument, positions cursor at end of buffer." (interactive "P") (if (get-buffer ruby-buffer) (pop-to-buffer ruby-buffer) (error "No current process buffer. See variable ruby-buffer.")) (cond (eob-p (push-mark) (goto-char (point-max))))) (defun ruby-send-region-and-go (start end) "Send the current region to the inferior Ruby process. Then switch to the process buffer." (interactive "r") (ruby-send-region start end) (switch-to-ruby t)) (defun ruby-send-definition-and-go () "Send the current definition to the inferior Ruby. Then switch to the process buffer." (interactive) (ruby-send-definition) (switch-to-ruby t)) (defun ruby-send-block-and-go () "Send the current block to the inferior Ruby. Then switch to the process buffer." (interactive) (ruby-send-block) (switch-to-ruby t)) (defvar ruby-source-modes '(ruby-mode) "*Used to determine if a buffer contains Ruby source code. If it's loaded into a buffer that is in one of these major modes, it's considered a ruby source file by ruby-load-file. Used by these commands to determine defaults.") (defvar ruby-prev-l/c-dir/file nil "Caches the last (directory . file) pair. Caches the last pair used in the last ruby-load-file command. Used for determining the default in the next one.") (defun ruby-load-file (file-name) "Load a Ruby file into the inferior Ruby process." (interactive (comint-get-source "Load Ruby file: " ruby-prev-l/c-dir/file ruby-source-modes t)) ; T because LOAD ; needs an exact name (comint-check-source file-name) ; Check to see if buffer needs saved. (setq ruby-prev-l/c-dir/file (cons (file-name-directory file-name) (file-name-nondirectory file-name))) (comint-send-string (ruby-proc) (concat "(load \"" file-name "\"\)\n"))) (defun ruby-proc () "Returns the current ruby process. See variable ruby-buffer." (let ((proc (get-buffer-process (if (eq major-mode 'inferior-ruby-mode) (current-buffer) ruby-buffer)))) (or proc (error "No current process. See variable ruby-buffer")))) ;;; Do the user's customisation... (defvar inf-ruby-load-hook nil "This hook is run when inf-ruby is loaded in. This is a good place to put keybindings.") (run-hooks 'inf-ruby-load-hook) (provide 'inf-ruby) ;;; inf-ruby.el ends here ================================================ FILE: misc/ruby-electric.el ================================================ ;; -*-Emacs-Lisp-*- ;; ;; ruby-electric.el --- electric editing commands for ruby files ;; ;; Copyright (C) 2005 by Dee Zsombor . ;; Released under same license terms as Ruby. ;; ;; Due credit: this work was inspired by a code snippet posted by ;; Frederick Ros at http://rubygarden.org/ruby?EmacsExtensions. ;; ;; Following improvements where added: ;; ;; - handling of strings of type 'here document' ;; - more keywords, with special handling for 'do' ;; - packaged into a minor mode ;; ;; Usage: ;; ;; 0) copy ruby-electric.el into directory where emacs can find it. ;; ;; 1) modify your startup file (.emacs or whatever) by adding ;; following line: ;; ;; (require 'ruby-electric) ;; ;; note that you need to have font lock enabled beforehand. ;; ;; 2) toggle Ruby Electric Mode on/off with ruby-electric-mode. ;; ;; Changelog: ;; ;; 2005/Jan/14: inserts matching pair delimiters like {, [, (, ', ", ;; ' and | . ;; ;; 2005/Jan/14: added basic Custom support for configuring keywords ;; with electric closing. ;; ;; 2005/Jan/18: more Custom support for configuring characters for ;; which matching expansion should occur. ;; ;; 2005/Jan/18: no longer uses 'looking-back' or regexp character ;; classes like [:space:] since they are not implemented on XEmacs. ;; ;; 2005/Feb/01: explicitly provide default argument of 1 to ;; 'backward-word' as it requires it on Emacs 21.3 ;; ;; 2005/Mar/06: now stored inside ruby CVS; customize pages now have ;; ruby as parent; cosmetic fixes. (require 'ruby-mode) (defgroup ruby-electric nil "Minor mode providing electric editing commands for ruby files" :group 'ruby) (defconst ruby-electric-expandable-do-re "do\\s-$") (defconst ruby-electric-expandable-bar "\\s-\\(do\\|{\\)\\s-+|") (defvar ruby-electric-matching-delimeter-alist '((?\[ . ?\]) (?\( . ?\)) (?\' . ?\') (?\` . ?\`) (?\" . ?\"))) (defcustom ruby-electric-simple-keywords-re "\\(def\\|if\\|class\\|module\\|unless\\|case\\|while\\|do\\|until\\|for\\|begin\\)" "*Regular expresion matching keywords for which closing 'end' is to be inserted." :type 'regexp :group 'ruby-electric) (defcustom ruby-electric-expand-delimiters-list '(all) "*List of contexts where matching delimiter should be inserted. The word 'all' will do all insertions." :type '(set :extra-offset 8 (const :tag "Everything" all ) (const :tag "Curly brace" ?\{ ) (const :tag "Square brace" ?\[ ) (const :tag "Round brace" ?\( ) (const :tag "Quote" ?\' ) (const :tag "Double quote" ?\" ) (const :tag "Back quote" ?\` ) (const :tag "Vertical bar" ?\| )) :group 'ruby-electric) (defcustom ruby-electric-newline-before-closing-bracket nil "*Controls whether a newline should be inserted before the closing bracket or not." :type 'boolean :group 'ruby-electric) (define-minor-mode ruby-electric-mode "Toggle Ruby Electric minor mode. With no argument, this command toggles the mode. Non-null prefix argument turns on the mode. Null prefix argument turns off the mode. When Ruby Electric mode is enabled, an indented 'end' is heuristicaly inserted whenever typing a word like 'module', 'class', 'def', 'if', 'unless', 'case', 'until', 'for', 'begin', 'do'. Simple, double and back quotes as well as braces are paired auto-magically. Expansion does not occur inside comments and strings. Note that you must have Font Lock enabled." ;; initial value. nil ;;indicator for the mode line. " REl" ;;keymap ruby-mode-map (ruby-electric-setup-keymap)) (defun ruby-electric-setup-keymap() (define-key ruby-mode-map " " 'ruby-electric-space) (define-key ruby-mode-map "{" 'ruby-electric-curlies) (define-key ruby-mode-map "(" 'ruby-electric-matching-char) (define-key ruby-mode-map "[" 'ruby-electric-matching-char) (define-key ruby-mode-map "\"" 'ruby-electric-matching-char) (define-key ruby-mode-map "\'" 'ruby-electric-matching-char) (define-key ruby-mode-map "|" 'ruby-electric-bar)) (defun ruby-electric-space (arg) (interactive "P") (self-insert-command (prefix-numeric-value arg)) (if (ruby-electric-space-can-be-expanded-p) (save-excursion (ruby-indent-line t) (newline) (ruby-insert-end)))) (defun ruby-electric-code-at-point-p() (and ruby-electric-mode (let* ((properties (text-properties-at (point)))) (and (null (memq 'font-lock-string-face properties)) (null (memq 'font-lock-comment-face properties)))))) (defun ruby-electric-string-at-point-p() (and ruby-electric-mode (consp (memq 'font-lock-string-face (text-properties-at (point)))))) (defun ruby-electric-is-last-command-char-expandable-punct-p() (or (memq 'all ruby-electric-expand-delimiters-list) (memq last-command-char ruby-electric-expand-delimiters-list))) (defun ruby-electric-space-can-be-expanded-p() (if (ruby-electric-code-at-point-p) (let* ((ruby-electric-keywords-re (concat ruby-electric-simple-keywords-re "\\s-$")) (ruby-electric-single-keyword-in-line-re (concat "\\s-*" ruby-electric-keywords-re))) (save-excursion (backward-word 1) (or (looking-at ruby-electric-expandable-do-re) (and (looking-at ruby-electric-keywords-re) (not (string= "do" (match-string 1))) (progn (beginning-of-line) (looking-at ruby-electric-single-keyword-in-line-re)))))))) (defun ruby-electric-curlies(arg) (interactive "P") (self-insert-command (prefix-numeric-value arg)) (if (ruby-electric-is-last-command-char-expandable-punct-p) (cond ((ruby-electric-code-at-point-p) (insert " ") (save-excursion (if ruby-electric-newline-before-closing-bracket (newline)) (insert "}"))) ((ruby-electric-string-at-point-p) (save-excursion (backward-char 1) (when (char-equal ?\# (preceding-char)) (forward-char 1) (insert "}"))))))) (defun ruby-electric-matching-char(arg) (interactive "P") (self-insert-command (prefix-numeric-value arg)) (and (ruby-electric-is-last-command-char-expandable-punct-p) (ruby-electric-code-at-point-p) (save-excursion (insert (cdr (assoc last-command-char ruby-electric-matching-delimeter-alist)))))) (defun ruby-electric-bar(arg) (interactive "P") (self-insert-command (prefix-numeric-value arg)) (and (ruby-electric-is-last-command-char-expandable-punct-p) (ruby-electric-code-at-point-p) (and (save-excursion (re-search-backward ruby-electric-expandable-bar nil t)) (= (point) (match-end 0))) ;looking-back is missing on XEmacs (save-excursion (insert "|")))) (provide 'ruby-electric) ================================================ FILE: misc/ruby-mode.el ================================================ ;;; ;;; ruby-mode.el - ;;; ;;; $Author$ ;;; $Date$ ;;; created at: Fri Feb 4 14:49:13 JST 1994 ;;; (defconst ruby-mode-revision "$Revision$") (defconst ruby-mode-version (progn (string-match "[0-9.]+" ruby-mode-revision) (substring ruby-mode-revision (match-beginning 0) (match-end 0)))) (defconst ruby-block-beg-re "class\\|module\\|def\\|if\\|unless\\|case\\|while\\|until\\|for\\|begin\\|do" ) (defconst ruby-non-block-do-re "\\(while\\|until\\|for\\|rescue\\)\\>[^_]" ) (defconst ruby-indent-beg-re "\\(\\s *\\(class\\|module\\|def\\)\\)\\|if\\|unless\\|case\\|while\\|until\\|for\\|begin" ) (defconst ruby-modifier-beg-re "if\\|unless\\|while\\|until" ) (defconst ruby-modifier-re (concat ruby-modifier-beg-re "\\|rescue") ) (defconst ruby-block-mid-re "then\\|else\\|elsif\\|when\\|rescue\\|ensure" ) (defconst ruby-block-op-re "and\\|or\\|not" ) (defconst ruby-block-hanging-re (concat ruby-modifier-beg-re "\\|" ruby-block-op-re) ) (defconst ruby-block-end-re "\\") (defconst ruby-here-doc-beg-re "<<\\(-\\)?\\(\\([a-zA-Z0-9_]+\\)\\|[\"]\\([^\"]+\\)[\"]\\|[']\\([^']+\\)[']\\)") (defun ruby-here-doc-end-match () (concat "^" (if (match-string 1) "[ \t]*" nil) (regexp-quote (or (match-string 3) (match-string 4) (match-string 5))))) (defconst ruby-delimiter (concat "[?$/%(){}#\"'`.:]\\|<<\\|\\[\\|\\]\\|\\<\\(" ruby-block-beg-re "\\)\\>\\|" ruby-block-end-re "\\|^=begin\\|" ruby-here-doc-beg-re) ) (defconst ruby-negative (concat "^[ \t]*\\(\\(" ruby-block-mid-re "\\)\\>\\|" ruby-block-end-re "\\|}\\|\\]\\)") ) (defconst ruby-operator-chars "-,.+*/%&|^~=<>:") (defconst ruby-operator-re (concat "[" ruby-operator-chars "]")) (defconst ruby-symbol-chars "a-zA-Z0-9_") (defconst ruby-symbol-re (concat "[" ruby-symbol-chars "]")) (defvar ruby-mode-abbrev-table nil "Abbrev table in use in ruby-mode buffers.") (define-abbrev-table 'ruby-mode-abbrev-table ()) (defvar ruby-mode-map nil "Keymap used in ruby mode.") (if ruby-mode-map nil (setq ruby-mode-map (make-sparse-keymap)) (define-key ruby-mode-map "{" 'ruby-electric-brace) (define-key ruby-mode-map "}" 'ruby-electric-brace) (define-key ruby-mode-map "\e\C-a" 'ruby-beginning-of-defun) (define-key ruby-mode-map "\e\C-e" 'ruby-end-of-defun) (define-key ruby-mode-map "\e\C-b" 'ruby-backward-sexp) (define-key ruby-mode-map "\e\C-f" 'ruby-forward-sexp) (define-key ruby-mode-map "\e\C-p" 'ruby-beginning-of-block) (define-key ruby-mode-map "\e\C-n" 'ruby-end-of-block) (define-key ruby-mode-map "\e\C-h" 'ruby-mark-defun) (define-key ruby-mode-map "\e\C-q" 'ruby-indent-exp) (define-key ruby-mode-map "\t" 'ruby-indent-command) (define-key ruby-mode-map "\C-c\C-e" 'ruby-insert-end) (define-key ruby-mode-map "\C-j" 'ruby-reindent-then-newline-and-indent) (define-key ruby-mode-map "\C-m" 'newline)) (defvar ruby-mode-syntax-table nil "Syntax table in use in ruby-mode buffers.") (if ruby-mode-syntax-table () (setq ruby-mode-syntax-table (make-syntax-table)) (modify-syntax-entry ?\' "\"" ruby-mode-syntax-table) (modify-syntax-entry ?\" "\"" ruby-mode-syntax-table) (modify-syntax-entry ?\` "\"" ruby-mode-syntax-table) (modify-syntax-entry ?# "<" ruby-mode-syntax-table) (modify-syntax-entry ?\n ">" ruby-mode-syntax-table) (modify-syntax-entry ?\\ "\\" ruby-mode-syntax-table) (modify-syntax-entry ?$ "." ruby-mode-syntax-table) (modify-syntax-entry ?? "_" ruby-mode-syntax-table) (modify-syntax-entry ?_ "_" ruby-mode-syntax-table) (modify-syntax-entry ?< "." ruby-mode-syntax-table) (modify-syntax-entry ?> "." ruby-mode-syntax-table) (modify-syntax-entry ?& "." ruby-mode-syntax-table) (modify-syntax-entry ?| "." ruby-mode-syntax-table) (modify-syntax-entry ?% "." ruby-mode-syntax-table) (modify-syntax-entry ?= "." ruby-mode-syntax-table) (modify-syntax-entry ?/ "." ruby-mode-syntax-table) (modify-syntax-entry ?+ "." ruby-mode-syntax-table) (modify-syntax-entry ?* "." ruby-mode-syntax-table) (modify-syntax-entry ?- "." ruby-mode-syntax-table) (modify-syntax-entry ?\; "." ruby-mode-syntax-table) (modify-syntax-entry ?\( "()" ruby-mode-syntax-table) (modify-syntax-entry ?\) ")(" ruby-mode-syntax-table) (modify-syntax-entry ?\{ "(}" ruby-mode-syntax-table) (modify-syntax-entry ?\} "){" ruby-mode-syntax-table) (modify-syntax-entry ?\[ "(]" ruby-mode-syntax-table) (modify-syntax-entry ?\] ")[" ruby-mode-syntax-table) ) (defcustom ruby-indent-tabs-mode nil "*Indentation can insert tabs in ruby mode if this is non-nil." :type 'boolean :group 'ruby) (defcustom ruby-indent-level 2 "*Indentation of ruby statements." :type 'integer :group 'ruby) (defcustom ruby-comment-column 32 "*Indentation column of comments." :type 'integer :group 'ruby) (defcustom ruby-deep-arglist t "*Deep indent lists in parenthesis when non-nil. Also ignores spaces after parenthesis when 'space." :group 'ruby) (defcustom ruby-deep-indent-paren '(?\( ?\[ ?\] t) "*Deep indent lists in parenthesis when non-nil. t means continuous line. Also ignores spaces after parenthesis when 'space." :group 'ruby) (defcustom ruby-deep-indent-paren-style 'space "Default deep indent style." :options '(t nil space) :group 'ruby) (eval-when-compile (require 'cl)) (defun ruby-imenu-create-index-in-block (prefix beg end) (let ((index-alist '()) (case-fold-search nil) name next pos decl sing) (goto-char beg) (while (re-search-forward "^\\s *\\(\\(class\\>\\(\\s *<<\\)?\\|module\\>\\)\\s *\\([^\(<\n ]+\\)\\|\\(def\\|alias\\)\\>\\s *\\([^\(\n ]+\\)\\)" end t) (setq sing (match-beginning 3)) (setq decl (match-string 5)) (setq next (match-end 0)) (setq name (or (match-string 4) (match-string 6))) (setq pos (match-beginning 0)) (cond ((string= "alias" decl) (if prefix (setq name (concat prefix name))) (push (cons name pos) index-alist)) ((string= "def" decl) (if prefix (setq name (cond ((string-match "^self\." name) (concat (substring prefix 0 -1) (substring name 4))) (t (concat prefix name))))) (push (cons name pos) index-alist) (ruby-accurate-end-of-block end)) (t (if (string= "self" name) (if prefix (setq name (substring prefix 0 -1))) (if prefix (setq name (concat (substring prefix 0 -1) "::" name))) (push (cons name pos) index-alist)) (ruby-accurate-end-of-block end) (setq beg (point)) (setq index-alist (nconc (ruby-imenu-create-index-in-block (concat name (if sing "." "#")) next beg) index-alist)) (goto-char beg)))) index-alist)) (defun ruby-imenu-create-index () (nreverse (ruby-imenu-create-index-in-block nil (point-min) nil))) (defun ruby-accurate-end-of-block (&optional end) (let (state) (or end (setq end (point-max))) (while (and (setq state (apply 'ruby-parse-partial end state)) (>= (nth 2 state) 0) (< (point) end))))) (defun ruby-mode-variables () (set-syntax-table ruby-mode-syntax-table) (setq local-abbrev-table ruby-mode-abbrev-table) (make-local-variable 'indent-line-function) (setq indent-line-function 'ruby-indent-line) (make-local-variable 'require-final-newline) (setq require-final-newline t) (make-variable-buffer-local 'comment-start) (setq comment-start "# ") (make-variable-buffer-local 'comment-end) (setq comment-end "") (make-variable-buffer-local 'comment-column) (setq comment-column ruby-comment-column) (make-variable-buffer-local 'comment-start-skip) (setq comment-start-skip "#+ *") (setq indent-tabs-mode ruby-indent-tabs-mode) (make-local-variable 'parse-sexp-ignore-comments) (setq parse-sexp-ignore-comments t) (make-local-variable 'paragraph-start) (setq paragraph-start (concat "$\\|" page-delimiter)) (make-local-variable 'paragraph-separate) (setq paragraph-separate paragraph-start) (make-local-variable 'paragraph-ignore-fill-prefix) (setq paragraph-ignore-fill-prefix t)) ;;;###autoload (defun ruby-mode () "Major mode for editing ruby scripts. \\[ruby-indent-command] properly indents subexpressions of multi-line class, module, def, if, while, for, do, and case statements, taking nesting into account. The variable ruby-indent-level controls the amount of indentation. \\{ruby-mode-map}" (interactive) (kill-all-local-variables) (use-local-map ruby-mode-map) (setq mode-name "Ruby") (setq major-mode 'ruby-mode) (ruby-mode-variables) (make-local-variable 'imenu-create-index-function) (setq imenu-create-index-function 'ruby-imenu-create-index) (make-local-variable 'add-log-current-defun-function) (setq add-log-current-defun-function 'ruby-add-log-current-method) (set (make-local-variable 'font-lock-defaults) '((ruby-font-lock-keywords) nil nil)) (set (make-local-variable 'font-lock-keywords) ruby-font-lock-keywords) (set (make-local-variable 'font-lock-syntax-table) ruby-font-lock-syntax-table) (set (make-local-variable 'font-lock-syntactic-keywords) ruby-font-lock-syntactic-keywords) (run-mode-hooks 'ruby-mode-hook)) (defun ruby-current-indentation () (save-excursion (beginning-of-line) (back-to-indentation) (current-column))) (defun ruby-indent-line (&optional flag) "Correct indentation of the current ruby line." (ruby-indent-to (ruby-calculate-indent))) (defun ruby-indent-command () (interactive) (ruby-indent-line t)) (defun ruby-indent-to (x) (if x (let (shift top beg) (and (< x 0) (error "invalid nest")) (setq shift (current-column)) (beginning-of-line) (setq beg (point)) (back-to-indentation) (setq top (current-column)) (skip-chars-backward " \t") (if (>= shift top) (setq shift (- shift top)) (setq shift 0)) (if (and (bolp) (= x top)) (move-to-column (+ x shift)) (move-to-column top) (delete-region beg (point)) (beginning-of-line) (indent-to x) (move-to-column (+ x shift)))))) (defun ruby-special-char-p (&optional pnt) (setq pnt (or pnt (point))) (let ((c (char-before pnt)) (b (and (< (point-min) pnt) (char-before (1- pnt))))) (cond ((or (eq c ??) (eq c ?$))) ((and (eq c ?:) (or (not b) (eq (char-syntax b) ? )))) ((eq c ?\\) (eq b ??))))) (defun ruby-expr-beg (&optional option) (save-excursion (store-match-data nil) (let ((space (skip-chars-backward " \t")) (start (point))) (cond ((bolp) t) ((progn (forward-char -1) (and (looking-at "\\?") (or (eq (char-syntax (char-before (point))) ?w) (ruby-special-char-p)))) nil) ((and (eq option 'heredoc) (< space 0)) t) ((or (looking-at ruby-operator-re) (looking-at "[\\[({,;]") (and (looking-at "[!?]") (or (not (eq option 'modifier)) (bolp) (save-excursion (forward-char -1) (looking-at "\\Sw$")))) (and (looking-at ruby-symbol-re) (skip-chars-backward ruby-symbol-chars) (cond ((or (looking-at (concat "\\<\\(" ruby-block-beg-re "|" ruby-block-op-re "|" ruby-block-mid-re "\\)\\>"))) (goto-char (match-end 0)) (not (looking-at "\\s_"))) ((eq option 'expr-qstr) (looking-at "[a-zA-Z][a-zA-z0-9_]* +%[^ \t]")) ((eq option 'expr-re) (looking-at "[a-zA-Z][a-zA-z0-9_]* +/[^ \t]")) (t nil))))))))) (defun ruby-forward-string (term &optional end no-error expand) (let ((n 1) (c (string-to-char term)) (re (if expand (concat "[^\\]\\(\\\\\\\\\\)*\\([" term "]\\|\\(#{\\)\\)") (concat "[^\\]\\(\\\\\\\\\\)*[" term "]")))) (while (and (re-search-forward re end no-error) (if (match-beginning 3) (ruby-forward-string "}{" end no-error nil) (> (setq n (if (eq (char-before (point)) c) (1- n) (1+ n))) 0))) (forward-char -1)) (cond ((zerop n)) (no-error nil) ((error "unterminated string"))))) (defun ruby-deep-indent-paren-p (c) (cond ((listp ruby-deep-indent-paren) (let ((deep (assoc c ruby-deep-indent-paren))) (cond (deep (or (cdr deep) ruby-deep-indent-paren-style)) ((memq c ruby-deep-indent-paren) ruby-deep-indent-paren-style)))) ((eq c ruby-deep-indent-paren) ruby-deep-indent-paren-style) ((eq c ?\( ) ruby-deep-arglist))) (defun ruby-parse-partial (&optional end in-string nest depth pcol indent) (or depth (setq depth 0)) (or indent (setq indent 0)) (when (re-search-forward ruby-delimiter end 'move) (let ((pnt (point)) w re expand) (goto-char (match-beginning 0)) (cond ((and (memq (char-before) '(?@ ?$)) (looking-at "\\sw")) (goto-char pnt)) ((looking-at "[\"`]") ;skip string (cond ((and (not (eobp)) (ruby-forward-string (buffer-substring (point) (1+ (point))) end t t)) nil) (t (setq in-string (point)) (goto-char end)))) ((looking-at "'") (cond ((and (not (eobp)) (re-search-forward "[^\\]\\(\\\\\\\\\\)*'" end t)) nil) (t (setq in-string (point)) (goto-char end)))) ((looking-at "/=") (goto-char pnt)) ((looking-at "/") (cond ((and (not (eobp)) (ruby-expr-beg 'expr-re)) (if (ruby-forward-string "/" end t t) nil (setq in-string (point)) (goto-char end))) (t (goto-char pnt)))) ((looking-at "%") (cond ((and (not (eobp)) (ruby-expr-beg 'expr-qstr) (not (looking-at "%=")) (looking-at "%[QqrxWw]?\\([^a-zA-Z0-9 \t\n]\\)")) (goto-char (match-beginning 1)) (setq expand (not (memq (char-before) '(?q ?w)))) (setq w (match-string 1)) (cond ((string= w "[") (setq re "][")) ((string= w "{") (setq re "}{")) ((string= w "(") (setq re ")(")) ((string= w "<") (setq re "><")) ((and expand (string= w "\\")) (setq w (concat "\\" w)))) (unless (cond (re (ruby-forward-string re end t expand)) (expand (ruby-forward-string w end t t)) (t (re-search-forward (if (string= w "\\") "\\\\[^\\]*\\\\" (concat "[^\\]\\(\\\\\\\\\\)*" w)) end t))) (setq in-string (point)) (goto-char end))) (t (goto-char pnt)))) ((looking-at "\\?") ;skip ?char (cond ((and (ruby-expr-beg) (looking-at "?\\(\\\\C-\\|\\\\M-\\)*\\\\?.")) (goto-char (match-end 0))) (t (goto-char pnt)))) ((looking-at "\\$") ;skip $char (goto-char pnt) (forward-char 1)) ((looking-at "#") ;skip comment (forward-line 1) (goto-char (point)) ) ((looking-at "[\\[{(]") (let ((deep (ruby-deep-indent-paren-p (char-after)))) (if (and deep (or (not (eq (char-after) ?\{)) (ruby-expr-beg))) (progn (and (eq deep 'space) (looking-at ".\\s +[^# \t\n]") (setq pnt (1- (match-end 0)))) (setq nest (cons (cons (char-after (point)) pnt) nest)) (setq pcol (cons (cons pnt depth) pcol)) (setq depth 0)) (setq nest (cons (cons (char-after (point)) pnt) nest)) (setq depth (1+ depth)))) (goto-char pnt) ) ((looking-at "[])}]") (if (ruby-deep-indent-paren-p (matching-paren (char-after))) (setq depth (cdr (car pcol)) pcol (cdr pcol)) (setq depth (1- depth))) (setq nest (cdr nest)) (goto-char pnt)) ((looking-at ruby-block-end-re) (if (or (and (not (bolp)) (progn (forward-char -1) (setq w (char-after (point))) (or (eq ?_ w) (eq ?. w)))) (progn (goto-char pnt) (setq w (char-after (point))) (or (eq ?_ w) (eq ?! w) (eq ?? w)))) nil (setq nest (cdr nest)) (setq depth (1- depth))) (goto-char pnt)) ((looking-at "def\\s +[^(\n;]*") (if (or (bolp) (progn (forward-char -1) (not (eq ?_ (char-after (point)))))) (progn (setq nest (cons (cons nil pnt) nest)) (setq depth (1+ depth)))) (goto-char (match-end 0))) ((looking-at (concat "\\<\\(" ruby-block-beg-re "\\)\\>")) (and (save-match-data (or (not (looking-at "do\\>[^_]")) (save-excursion (back-to-indentation) (not (looking-at ruby-non-block-do-re))))) (or (bolp) (progn (forward-char -1) (setq w (char-after (point))) (not (or (eq ?_ w) (eq ?. w))))) (goto-char pnt) (setq w (char-after (point))) (not (eq ?_ w)) (not (eq ?! w)) (not (eq ?? w)) (skip-chars-forward " \t") (goto-char (match-beginning 0)) (or (not (looking-at ruby-modifier-re)) (ruby-expr-beg 'modifier)) (goto-char pnt) (setq nest (cons (cons nil pnt) nest)) (setq depth (1+ depth))) (goto-char pnt)) ((looking-at ":\\(['\"]\\)") (goto-char (match-beginning 1)) (ruby-forward-string (buffer-substring (match-beginning 1) (match-end 1)) end)) ((looking-at ":\\([-,.+*/%&|^~<>]=?\\|===?\\|<=>\\)") (goto-char (match-end 0))) ((looking-at ":\\([a-zA-Z_][a-zA-Z_0-9]*[!?=]?\\)?") (goto-char (match-end 0))) ((or (looking-at "\\.\\.\\.?") (looking-at "\\.[0-9]+") (looking-at "\\.[a-zA-Z_0-9]+") (looking-at "\\.")) (goto-char (match-end 0))) ((looking-at "^=begin") (if (re-search-forward "^=end" end t) (forward-line 1) (setq in-string (match-end 0)) (goto-char end))) ((looking-at "<<") (cond ((and (ruby-expr-beg 'heredoc) (looking-at "<<\\(-\\)?\\(\\([\"'`]\\)\\([^\n]+?\\)\\3\\|\\(?:\\sw\\|\\s_\\)+\\)")) (setq re (regexp-quote (or (match-string 4) (match-string 2)))) (if (match-beginning 1) (setq re (concat "\\s *" re))) (let* ((id-end (goto-char (match-end 0))) (line-end-position (save-excursion (end-of-line) (point))) (state (list in-string nest depth pcol indent))) ;; parse the rest of the line (while (and (> line-end-position (point)) (setq state (apply 'ruby-parse-partial line-end-position state)))) (setq in-string (car state) nest (nth 1 state) depth (nth 2 state) pcol (nth 3 state) indent (nth 4 state)) ;; skip heredoc section (if (re-search-forward (concat "^" re "$") end 'move) (forward-line 1) (setq in-string id-end) (goto-char end)))) (t (goto-char pnt)))) ((looking-at "^__END__$") (goto-char pnt)) ((looking-at ruby-here-doc-beg-re) (if (re-search-forward (ruby-here-doc-end-match) indent-point t) (forward-line 1) (setq in-string (match-end 0)) (goto-char indent-point))) (t (error (format "bad string %s" (buffer-substring (point) pnt) )))))) (list in-string nest depth pcol)) (defun ruby-parse-region (start end) (let (state) (save-excursion (if start (goto-char start) (ruby-beginning-of-indent)) (save-restriction (narrow-to-region (point) end) (while (and (> end (point)) (setq state (apply 'ruby-parse-partial end state)))))) (list (nth 0 state) ; in-string (car (nth 1 state)) ; nest (nth 2 state) ; depth (car (car (nth 3 state))) ; pcol ;(car (nth 5 state)) ; indent ))) (defun ruby-indent-size (pos nest) (+ pos (* (or nest 1) ruby-indent-level))) (defun ruby-calculate-indent (&optional parse-start) (save-excursion (beginning-of-line) (let ((indent-point (point)) (case-fold-search nil) state bol eol begin op-end (paren (progn (skip-syntax-forward " ") (and (char-after) (matching-paren (char-after))))) (indent 0)) (if parse-start (goto-char parse-start) (ruby-beginning-of-indent) (setq parse-start (point))) (back-to-indentation) (setq indent (current-column)) (setq state (ruby-parse-region parse-start indent-point)) (cond ((nth 0 state) ; within string (setq indent nil)) ; do nothing ((car (nth 1 state)) ; in paren (goto-char (setq begin (cdr (nth 1 state)))) (let ((deep (ruby-deep-indent-paren-p (car (nth 1 state))))) (if deep (cond ((and (eq deep t) (eq (car (nth 1 state)) paren)) (skip-syntax-backward " ") (setq indent (1- (current-column)))) ((let ((s (ruby-parse-region (point) indent-point))) (and (nth 2 s) (> (nth 2 s) 0) (or (goto-char (cdr (nth 1 s))) t))) (forward-word -1) (setq indent (ruby-indent-size (current-column) (nth 2 state)))) (t (setq indent (current-column)) (cond ((eq deep 'space)) (paren (setq indent (1- indent))) (t (setq indent (ruby-indent-size (1- indent) 1)))))) (if (nth 3 state) (goto-char (nth 3 state)) (goto-char parse-start) (back-to-indentation)) (setq indent (ruby-indent-size (current-column) (nth 2 state)))) (and (eq (car (nth 1 state)) paren) (ruby-deep-indent-paren-p (matching-paren paren)) (search-backward (char-to-string paren)) (setq indent (current-column))))) ((and (nth 2 state) (> (nth 2 state) 0)) ; in nest (if (null (cdr (nth 1 state))) (error "invalid nest")) (goto-char (cdr (nth 1 state))) (forward-word -1) ; skip back a keyword (setq begin (point)) (cond ((looking-at "do\\>[^_]") ; iter block is a special case (if (nth 3 state) (goto-char (nth 3 state)) (goto-char parse-start) (back-to-indentation)) (setq indent (ruby-indent-size (current-column) (nth 2 state)))) (t (setq indent (+ (current-column) ruby-indent-level))))) ((and (nth 2 state) (< (nth 2 state) 0)) ; in negative nest (setq indent (ruby-indent-size (current-column) (nth 2 state))))) (when indent (goto-char indent-point) (end-of-line) (setq eol (point)) (beginning-of-line) (cond ((and (not (ruby-deep-indent-paren-p paren)) (re-search-forward ruby-negative eol t)) (and (not (eq ?_ (char-after (match-end 0)))) (setq indent (- indent ruby-indent-level)))) ((and (save-excursion (beginning-of-line) (not (bobp))) (or (ruby-deep-indent-paren-p t) (null (car (nth 1 state))))) ;; goto beginning of non-empty no-comment line (let (end done) (while (not done) (skip-chars-backward " \t\n") (setq end (point)) (beginning-of-line) (if (re-search-forward "^\\s *#" end t) (beginning-of-line) (setq done t)))) (setq bol (point)) (end-of-line) ;; skip the comment at the end (skip-chars-backward " \t") (let (end (pos (point))) (beginning-of-line) (while (and (re-search-forward "#" pos t) (setq end (1- (point))) (or (ruby-special-char-p end) (and (setq state (ruby-parse-region parse-start end)) (nth 0 state)))) (setq end nil)) (goto-char (or end pos)) (skip-chars-backward " \t") (setq begin (if (nth 0 state) pos (cdr (nth 1 state)))) (setq state (ruby-parse-region parse-start (point)))) (or (bobp) (forward-char -1)) (and (or (and (looking-at ruby-symbol-re) (skip-chars-backward ruby-symbol-chars) (looking-at (concat "\\<\\(" ruby-block-hanging-re "\\)\\>")) (not (eq (point) (nth 3 state))) (save-excursion (goto-char (match-end 0)) (not (looking-at "[a-z_]")))) (and (looking-at ruby-operator-re) (not (ruby-special-char-p)) ;; operator at the end of line (let ((c (char-after (point)))) (and ;; (or (null begin) ;; (save-excursion ;; (goto-char begin) ;; (skip-chars-forward " \t") ;; (not (or (eolp) (looking-at "#") ;; (and (eq (car (nth 1 state)) ?{) ;; (looking-at "|")))))) (or (not (eq ?/ c)) (null (nth 0 (ruby-parse-region (or begin parse-start) (point))))) (or (not (eq ?| (char-after (point)))) (save-excursion (or (eolp) (forward-char -1)) (cond ((search-backward "|" nil t) (skip-chars-backward " \t\n") (and (not (eolp)) (progn (forward-char -1) (not (looking-at "{"))) (progn (forward-word -1) (not (looking-at "do\\>[^_]"))))) (t t)))) (not (eq ?, c)) (setq op-end t))))) (setq indent (cond ((and (null op-end) (not (looking-at (concat "\\<\\(" ruby-block-hanging-re "\\)\\>"))) (eq (ruby-deep-indent-paren-p t) 'space) (not (bobp))) (save-excursion (widen) (goto-char (or begin parse-start)) (skip-syntax-forward " ") (current-column))) ((car (nth 1 state)) indent) (t (+ indent ruby-indent-level)))))))) indent))) (defun ruby-electric-brace (arg) (interactive "P") (insert-char last-command-char 1) (ruby-indent-line t) (delete-char -1) (self-insert-command (prefix-numeric-value arg))) (eval-when-compile (defmacro defun-region-command (func args &rest body) (let ((intr (car body))) (when (featurep 'xemacs) (if (stringp intr) (setq intr (cadr body))) (and (eq (car intr) 'interactive) (setq intr (cdr intr)) (setcar intr (concat "_" (car intr))))) (cons 'defun (cons func (cons args body)))))) (defun-region-command ruby-beginning-of-defun (&optional arg) "Move backward to next beginning-of-defun. With argument, do this that many times. Returns t unless search stops due to end of buffer." (interactive "p") (and (re-search-backward (concat "^\\(" ruby-block-beg-re "\\)\\b") nil 'move (or arg 1)) (progn (beginning-of-line) t))) (defun ruby-beginning-of-indent () (and (re-search-backward (concat "^\\(" ruby-indent-beg-re "\\)\\b") nil 'move) (progn (beginning-of-line) t))) (defun-region-command ruby-end-of-defun (&optional arg) "Move forward to next end of defun. An end of a defun is found by moving forward from the beginning of one." (interactive "p") (and (re-search-forward (concat "^\\(" ruby-block-end-re "\\)\\($\\|\\b[^_]\\)") nil 'move (or arg 1)) (progn (beginning-of-line) t)) (forward-line 1)) (defun ruby-move-to-block (n) (let (start pos done down) (setq start (ruby-calculate-indent)) (setq down (looking-at (if (< n 0) ruby-block-end-re (concat "\\<\\(" ruby-block-beg-re "\\)\\>")))) (while (and (not done) (not (if (< n 0) (bobp) (eobp)))) (forward-line n) (cond ((looking-at "^\\s *$")) ((looking-at "^\\s *#")) ((and (> n 0) (looking-at "^=begin\\>")) (re-search-forward "^=end\\>")) ((and (< n 0) (looking-at "^=end\\>")) (re-search-backward "^=begin\\>")) (t (setq pos (current-indentation)) (cond ((< start pos) (setq down t)) ((and down (= pos start)) (setq done t)) ((> start pos) (setq done t))))) (if done (save-excursion (back-to-indentation) (if (looking-at (concat "\\<\\(" ruby-block-mid-re "\\)\\>")) (setq done nil)))))) (back-to-indentation)) (defun-region-command ruby-beginning-of-block (&optional arg) "Move backward to next beginning-of-block" (interactive "p") (ruby-move-to-block (- (or arg 1)))) (defun-region-command ruby-end-of-block (&optional arg) "Move forward to next beginning-of-block" (interactive "p") (ruby-move-to-block (or arg 1))) (defun-region-command ruby-forward-sexp (&optional cnt) (interactive "p") (if (and (numberp cnt) (< cnt 0)) (ruby-backward-sexp (- cnt)) (let ((i (or cnt 1))) (condition-case nil (while (> i 0) (skip-syntax-forward " ") (cond ((looking-at "\\?\\(\\\\[CM]-\\)*\\\\?\\S ") (goto-char (match-end 0))) ((progn (skip-chars-forward ",.:;|&^~=!?\\+\\-\\*") (looking-at "\\s(")) (goto-char (scan-sexps (point) 1))) ((and (looking-at (concat "\\<\\(" ruby-block-beg-re "\\)\\>")) (not (eq (char-before (point)) ?.)) (not (eq (char-before (point)) ?:))) (ruby-end-of-block) (forward-word 1)) ((looking-at "\\(\\$\\|@@?\\)?\\sw") (while (progn (while (progn (forward-word 1) (looking-at "_"))) (cond ((looking-at "::") (forward-char 2) t) ((> (skip-chars-forward ".") 0)) ((looking-at "\\?\\|!\\(=[~=>]\\|[^~=]\\)") (forward-char 1) nil))))) ((let (state expr) (while (progn (setq expr (or expr (ruby-expr-beg) (looking-at "%\\sw?\\Sw\\|[\"'`/]"))) (nth 1 (setq state (apply 'ruby-parse-partial nil state)))) (setq expr t) (skip-chars-forward "<")) (not expr)))) (setq i (1- i))) ((error) (forward-word 1))) i))) (defun-region-command ruby-backward-sexp (&optional cnt) (interactive "p") (if (and (numberp cnt) (< cnt 0)) (ruby-forward-sexp (- cnt)) (let ((i (or cnt 1))) (condition-case nil (while (> i 0) (skip-chars-backward " \t\n,.:;|&^~=!?\\+\\-\\*") (forward-char -1) (cond ((looking-at "\\s)") (goto-char (scan-sexps (1+ (point)) -1)) (case (char-before) (?% (forward-char -1)) ('(?q ?Q ?w ?W ?r ?x) (if (eq (char-before (1- (point))) ?%) (forward-char -2)))) nil) ((looking-at "\\s\"\\|\\\\\\S_") (let ((c (char-to-string (char-before (match-end 0))))) (while (and (search-backward c) (oddp (skip-chars-backward "\\"))))) nil) ((looking-at "\\s.\\|\\s\\") (if (ruby-special-char-p) (forward-char -1))) ((looking-at "\\s(") nil) (t (forward-char 1) (while (progn (forward-word -1) (case (char-before) (?_ t) (?. (forward-char -1) t) ((?$ ?@) (forward-char -1) (and (eq (char-before) (char-after)) (forward-char -1))) (?: (forward-char -1) (eq (char-before) :))))) (if (looking-at ruby-block-end-re) (ruby-beginning-of-block)) nil)) (setq i (1- i))) ((error))) i))) (defun ruby-reindent-then-newline-and-indent () (interactive "*") (newline) (save-excursion (end-of-line 0) (indent-according-to-mode) (delete-region (point) (progn (skip-chars-backward " \t") (point)))) (indent-according-to-mode)) (fset 'ruby-encomment-region (symbol-function 'comment-region)) (defun ruby-decomment-region (beg end) (interactive "r") (save-excursion (goto-char beg) (while (re-search-forward "^\\([ \t]*\\)#" end t) (replace-match "\\1" nil nil) (save-excursion (ruby-indent-line))))) (defun ruby-insert-end () (interactive) (insert "end") (ruby-indent-line t) (end-of-line)) (defun ruby-mark-defun () "Put mark at end of this Ruby function, point at beginning." (interactive) (push-mark (point)) (ruby-end-of-defun) (push-mark (point) nil t) (ruby-beginning-of-defun) (re-search-backward "^\n" (- (point) 1) t)) (defun ruby-indent-exp (&optional shutup-p) "Indent each line in the balanced expression following point syntactically. If optional SHUTUP-P is non-nil, no errors are signalled if no balanced expression is found." (interactive "*P") (let ((here (point-marker)) start top column (nest t)) (set-marker-insertion-type here t) (unwind-protect (progn (beginning-of-line) (setq start (point) top (current-indentation)) (while (and (not (eobp)) (progn (setq column (ruby-calculate-indent start)) (cond ((> column top) (setq nest t)) ((and (= column top) nest) (setq nest nil) t)))) (ruby-indent-to column) (beginning-of-line 2))) (goto-char here) (set-marker here nil)))) (defun ruby-add-log-current-method () "Return current method string." (condition-case nil (save-excursion (let ((mlist nil) (indent 0)) ;; get current method (or class/module) (if (re-search-backward (concat "^[ \t]*\\(def\\|class\\|module\\)[ \t]+" "\\(" ;; \\. for class method "\\(" ruby-symbol-re "\\|\\." "\\)" "+\\)") nil t) (progn (setq mlist (list (match-string 2))) (goto-char (match-beginning 1)) (setq indent (current-column)) (beginning-of-line))) ;; nest class/module (while (and (> indent 0) (re-search-backward (concat "^[ \t]*\\(class\\|module\\)[ \t]+" "\\([A-Z]" ruby-symbol-re "+\\)") nil t)) (goto-char (match-beginning 1)) (if (< (current-column) indent) (progn (setq mlist (cons (match-string 2) mlist)) (setq indent (current-column)) (beginning-of-line)))) ;; generate string (if (consp mlist) (mapconcat (function identity) mlist "::") nil))))) (cond ((featurep 'font-lock) (or (boundp 'font-lock-variable-name-face) (setq font-lock-variable-name-face font-lock-type-face)) (setq ruby-font-lock-syntactic-keywords '( ;; #{ }, #$hoge, #@foo are not comments ("\\(#\\)[{$@]" 1 (1 . nil)) ;; the last $', $", $` in the respective string is not variable ;; the last ?', ?", ?` in the respective string is not ascii code ("\\(^\\|[\[ \t\n<+\(,=]\\)\\(['\"`]\\)\\(\\\\.\\|\\2\\|[^'\"`\n\\\\]\\)*?\\\\?[?$]\\(\\2\\)" (2 (7 . nil)) (4 (7 . nil))) ;; $' $" $` .... are variables ;; ?' ?" ?` are ascii codes ("\\(^\\|[^\\\\]\\)\\(\\\\\\\\\\)*[?$]\\([#\"'`]\\)" 3 (1 . nil)) ;; regexps ("\\(^\\|[=(,~?:;<>]\\|\\(^\\|\\s \\)\\(if\\|elsif\\|unless\\|while\\|until\\|when\\|and\\|or\\|&&\\|||\\)\\|g?sub!?\\|scan\\|split!?\\)\\s *\\(/\\)[^/\n\\\\]*\\(\\\\.[^/\n\\\\]*\\)*\\(/\\)" (4 (7 . ?/)) (6 (7 . ?/))) ("^\\(=\\)begin\\(\\s \\|$\\)" 1 (7 . nil)) ("^\\(=\\)end\\(\\s \\|$\\)" 1 (7 . nil)))) (if (featurep 'xemacs) (put 'ruby-mode 'font-lock-defaults '((ruby-font-lock-keywords) nil nil nil beginning-of-line (font-lock-syntactic-keywords . ruby-font-lock-syntactic-keywords)))) (defun ruby-font-lock-docs (limit) (if (re-search-forward "^=begin\\(\\s \\|$\\)" limit t) (let (beg) (beginning-of-line) (setq beg (point)) (forward-line 1) (if (re-search-forward "^=end\\(\\s \\|$\\)" limit t) (progn (set-match-data (list beg (point))) t))))) (defun ruby-font-lock-maybe-docs (limit) (let (beg) (save-excursion (if (and (re-search-backward "^=\\(begin\\|end\\)\\(\\s \\|$\\)" nil t) (string= (match-string 1) "begin")) (progn (beginning-of-line) (setq beg (point))))) (if (and beg (and (re-search-forward "^=\\(begin\\|end\\)\\(\\s \\|$\\)" nil t) (string= (match-string 1) "end"))) (progn (set-match-data (list beg (point))) t) nil))) (defvar ruby-font-lock-syntax-table (let* ((tbl (copy-syntax-table ruby-mode-syntax-table))) (modify-syntax-entry ?_ "w" tbl) tbl)) (defun ruby-font-lock-here-docs (limit) (if (re-search-forward ruby-here-doc-beg-re limit t) (let (beg) (beginning-of-line) (forward-line) (setq beg (point)) (if (re-search-forward (ruby-here-doc-end-match) nil t) (progn (set-match-data (list beg (point))) t))))) (defun ruby-font-lock-maybe-here-docs (limit) (let (beg) (save-excursion (if (re-search-backward ruby-here-doc-beg-re nil t) (progn (beginning-of-line) (forward-line) (setq beg (point))))) (if (and beg (let ((end-match (ruby-here-doc-end-match))) (and (not (re-search-backward end-match beg t)) (re-search-forward end-match nil t)))) (progn (set-match-data (list beg (point))) t) nil))) (defvar ruby-font-lock-keywords (list ;; functions '("^\\s *def\\s +\\([^( \t\n]+\\)" 1 font-lock-function-name-face) ;; keywords (cons (concat "\\(^\\|[^_:.@$]\\|\\.\\.\\)\\b\\(defined\\?\\|\\(" (mapconcat 'identity '("alias" "and" "begin" "break" "case" "catch" "class" "def" "do" "elsif" "else" "fail" "ensure" "for" "end" "if" "in" "module" "next" "not" "or" "raise" "redo" "rescue" "retry" "return" "then" "throw" "super" "unless" "undef" "until" "when" "while" "yield" ) "\\|") "\\)\\>\\)") 2) ;; variables '("\\(^\\|[^_:.@$]\\|\\.\\.\\)\\b\\(nil\\|self\\|true\\|false\\)\\>" 2 font-lock-variable-name-face) ;; variables '("\\(\\$\\([^a-zA-Z0-9 \n]\\|[0-9]\\)\\)\\W" 1 font-lock-variable-name-face) '("\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+" 0 font-lock-variable-name-face) ;; embedded document '(ruby-font-lock-docs 0 font-lock-comment-face t) '(ruby-font-lock-maybe-docs 0 font-lock-comment-face t) ;; "here" document '(ruby-font-lock-here-docs 0 font-lock-string-face t) '(ruby-font-lock-maybe-here-docs 0 font-lock-string-face t) `(,ruby-here-doc-beg-re 0 font-lock-string-face t) ;; general delimited string '("\\(^\\|[[ \t\n<+(,=]\\)\\(%[xrqQwW]?\\([^<[{(a-zA-Z0-9 \n]\\)[^\n\\\\]*\\(\\\\.[^\n\\\\]*\\)*\\(\\3\\)\\)" (2 font-lock-string-face)) ;; constants '("\\(^\\|[^_]\\)\\b\\([A-Z]+\\(\\w\\|_\\)*\\)" 2 font-lock-type-face) ;; symbols '("\\(^\\|[^:]\\)\\(:\\([-+~]@?\\|[/%&|^`]\\|\\*\\*?\\|<\\(<\\|=>?\\)?\\|>[>=]?\\|===?\\|=~\\|\\[\\]=?\\|\\(\\w\\|_\\)+\\([!?=]\\|\\b_*\\)\\|#{[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\)\\)" 2 font-lock-reference-face) ;; expression expansion '("#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\)" 0 font-lock-variable-name-face t) ;; warn lower camel case ;'("\\<[a-z]+[a-z0-9]*[A-Z][A-Za-z0-9]*\\([!?]?\\|\\>\\)" ; 0 font-lock-warning-face) ) "*Additional expressions to highlight in ruby mode.")) ((featurep 'hilit19) (hilit-set-mode-patterns 'ruby-mode '(("[^$\\?]\\(\"[^\\\"]*\\(\\\\\\(.\\|\n\\)[^\\\"]*\\)*\"\\)" 1 string) ("[^$\\?]\\('[^\\']*\\(\\\\\\(.\\|\n\\)[^\\']*\\)*'\\)" 1 string) ("[^$\\?]\\(`[^\\`]*\\(\\\\\\(.\\|\n\\)[^\\`]*\\)*`\\)" 1 string) ("^\\s *#.*$" nil comment) ("[^$@?\\]\\(#[^$@{\n].*$\\)" 1 comment) ("[^a-zA-Z_]\\(\\?\\(\\\\[CM]-\\)*.\\)" 1 string) ("^\\s *\\(require\\|load\\).*$" nil include) ("^\\s *\\(include\\|alias\\|undef\\).*$" nil decl) ("^\\s *\\<\\(class\\|def\\|module\\)\\>" "[)\n;]" defun) ("[^_]\\<\\(begin\\|case\\|else\\|elsif\\|end\\|ensure\\|for\\|if\\|unless\\|rescue\\|then\\|when\\|while\\|until\\|do\\|yield\\)\\>\\([^_]\\|$\\)" 1 defun) ("[^_]\\<\\(and\\|break\\|next\\|raise\\|fail\\|in\\|not\\|or\\|redo\\|retry\\|return\\|super\\|yield\\|catch\\|throw\\|self\\|nil\\)\\>\\([^_]\\|$\\)" 1 keyword) ("\\$\\(.\\|\\sw+\\)" nil type) ("[$@].[a-zA-Z_0-9]*" nil struct) ("^__END__" nil label)))) ) (provide 'ruby-mode) ================================================ FILE: misc/ruby-style.el ================================================ ;;; -*- emacs-lisp -*- ;;; ;;; ruby-style.el - ;;; ;;; C/C++ mode style for Ruby. ;;; ;;; $Author: nobu $ ;;; created at: Thu Apr 26 13:54:01 JST 2007 ;;; (defconst ruby-style-revision "$Revision: 15588 $" "Ruby style revision string.") (defconst ruby-style-version (progn (string-match "[0-9.]+" ruby-style-revision) (substring ruby-style-revision (match-beginning 0) (match-end 0))) "Ruby style version number.") (defun ruby-style-case-indent (x) (save-excursion (unless (progn (backward-up-list) (back-to-indentation) (> (point) (cdr x))) (goto-char (cdr x)) (if (looking-at "\\") '*)))) (defun ruby-style-label-indent (x) (save-excursion (unless (progn (backward-up-list) (back-to-indentation) (>= (point) (cdr x))) (goto-char (cdr x)) (condition-case () (progn (backward-up-list) (backward-sexp 2) (if (looking-at "\\") '/)) (error))))) (require 'cc-styles) (c-add-style "ruby" '("bsd" (c-basic-offset . 4) (tab-width . 8) (indent-tabs-mode . t) (c-offsets-alist (case-label . *) (label . (ruby-style-label-indent *)) (statement-case-intro . *) (statement-case-open . *) (statement-block-intro . (ruby-style-case-indent +)) (access-label /) ))) (defun ruby-style-c-mode () (interactive) (if (or (string-match "/ruby\\>" (buffer-file-name)) (save-excursion (goto-char (point-min)) (let ((head (progn (forward-line 100) (point))) (case-fold-search nil)) (goto-char (point-min)) (re-search-forward "Copyright (C) .* Yukihiro Matsumoto" head t)))) (setq c-file-style "ruby"))) (provide 'ruby-style) ================================================ FILE: misc/rubydb2x.el ================================================ (require 'gud) (provide 'rubydb) ;; ====================================================================== ;; rubydb functions ;;; History of argument lists passed to rubydb. (defvar gud-rubydb-history nil) (defun gud-rubydb-massage-args (file args) (cons "-I" (cons "." (cons "-r" (cons "debug" (cons file args)))))) ;; There's no guarantee that Emacs will hand the filter the entire ;; marker at once; it could be broken up across several strings. We ;; might even receive a big chunk with several markers in it. If we ;; receive a chunk of text which looks like it might contain the ;; beginning of a marker, we save it here between calls to the ;; filter. (defvar gud-rubydb-marker-acc "") (defun gud-rubydb-marker-filter (string) (save-match-data (setq gud-marker-acc (concat gud-marker-acc string)) (let ((output "")) ;; Process all the complete markers in this chunk. (while (string-match "\032\032\\([^:\n]*\\):\\([0-9]*\\):.*\n" gud-marker-acc) (setq ;; Extract the frame position from the marker. gud-last-frame (cons (substring gud-marker-acc (match-beginning 1) (match-end 1)) (string-to-int (substring gud-marker-acc (match-beginning 2) (match-end 2)))) ;; Append any text before the marker to the output we're going ;; to return - we don't include the marker in this text. output (concat output (substring gud-marker-acc 0 (match-beginning 0))) ;; Set the accumulator to the remaining text. gud-marker-acc (substring gud-marker-acc (match-end 0)))) ;; Does the remaining text look like it might end with the ;; beginning of another marker? If it does, then keep it in ;; gud-marker-acc until we receive the rest of it. Since we ;; know the full marker regexp above failed, it's pretty simple to ;; test for marker starts. (if (string-match "\032.*\\'" gud-marker-acc) (progn ;; Everything before the potential marker start can be output. (setq output (concat output (substring gud-marker-acc 0 (match-beginning 0)))) ;; Everything after, we save, to combine with later input. (setq gud-marker-acc (substring gud-marker-acc (match-beginning 0)))) (setq output (concat output gud-marker-acc) gud-marker-acc "")) output))) (defun gud-rubydb-find-file (f) (find-file-noselect f)) (defvar rubydb-command-name "ruby" "File name for executing ruby.") ;;;###autoload (defun rubydb (command-line) "Run rubydb on program FILE in buffer *gud-FILE*. The directory containing FILE becomes the initial working directory and source-file directory for your debugger." (interactive (list (read-from-minibuffer "Run rubydb (like this): " (if (consp gud-rubydb-history) (car gud-rubydb-history) (concat rubydb-command-name " ")) nil nil '(gud-rubydb-history . 1)))) (gud-overload-functions '((gud-massage-args . gud-rubydb-massage-args) (gud-marker-filter . gud-rubydb-marker-filter) (gud-find-file . gud-rubydb-find-file) )) (gud-common-init command-line) (gud-def gud-break "b %l" "\C-b" "Set breakpoint at current line.") ; (gud-def gud-remove "clear %l" "\C-d" "Remove breakpoint at current line") (gud-def gud-step "s" "\C-s" "Step one source line with display.") (gud-def gud-next "n" "\C-n" "Step one line (skip functions).") (gud-def gud-cont "c" "\C-r" "Continue with display.") (gud-def gud-finish "finish" "\C-f" "Finish executing current function.") (gud-def gud-up "up %p" "<" "Up N stack frames (numeric arg).") (gud-def gud-down "down %p" ">" "Down N stack frames (numeric arg).") (gud-def gud-print "p %e" "\C-p" "Evaluate ruby expression at point.") (setq comint-prompt-regexp "^(rdb:-) ") (setq paragraph-start comint-prompt-regexp) (run-hooks 'rubydb-mode-hook) ) ================================================ FILE: misc/rubydb3x.el ================================================ (require 'gud) (provide 'rubydb) ;; ====================================================================== ;; rubydb functions ;;; History of argument lists passed to rubydb. (defvar gud-rubydb-history nil) (if (fboundp 'gud-overload-functions) (defun gud-rubydb-massage-args (file args) (cons "-r" (cons "debug" (cons file args)))) (defun gud-rubydb-massage-args (file args) (cons "-r" (cons "debug" args)))) ;; There's no guarantee that Emacs will hand the filter the entire ;; marker at once; it could be broken up across several strings. We ;; might even receive a big chunk with several markers in it. If we ;; receive a chunk of text which looks like it might contain the ;; beginning of a marker, we save it here between calls to the ;; filter. (defvar gud-rubydb-marker-acc "") (make-variable-buffer-local 'gud-rubydb-marker-acc) (defun gud-rubydb-marker-filter (string) (setq gud-rubydb-marker-acc (concat gud-rubydb-marker-acc string)) (let ((output "")) ;; Process all the complete markers in this chunk. (while (string-match "\032\032\\([^:\n]*\\):\\([0-9]*\\):.*\n" gud-rubydb-marker-acc) (setq ;; Extract the frame position from the marker. gud-last-frame (cons (substring gud-rubydb-marker-acc (match-beginning 1) (match-end 1)) (string-to-int (substring gud-rubydb-marker-acc (match-beginning 2) (match-end 2)))) ;; Append any text before the marker to the output we're going ;; to return - we don't include the marker in this text. output (concat output (substring gud-rubydb-marker-acc 0 (match-beginning 0))) ;; Set the accumulator to the remaining text. gud-rubydb-marker-acc (substring gud-rubydb-marker-acc (match-end 0)))) ;; Does the remaining text look like it might end with the ;; beginning of another marker? If it does, then keep it in ;; gud-rubydb-marker-acc until we receive the rest of it. Since we ;; know the full marker regexp above failed, it's pretty simple to ;; test for marker starts. (if (string-match "\032.*\\'" gud-rubydb-marker-acc) (progn ;; Everything before the potential marker start can be output. (setq output (concat output (substring gud-rubydb-marker-acc 0 (match-beginning 0)))) ;; Everything after, we save, to combine with later input. (setq gud-rubydb-marker-acc (substring gud-rubydb-marker-acc (match-beginning 0)))) (setq output (concat output gud-rubydb-marker-acc) gud-rubydb-marker-acc "")) output)) (defun gud-rubydb-find-file (f) (save-excursion (let ((buf (find-file-noselect f))) (set-buffer buf) ;; (gud-make-debug-menu) buf))) (defvar rubydb-command-name "ruby" "File name for executing ruby.") ;;;###autoload (defun rubydb (command-line) "Run rubydb on program FILE in buffer *gud-FILE*. The directory containing FILE becomes the initial working directory and source-file directory for your debugger." (interactive (list (read-from-minibuffer "Run rubydb (like this): " (if (consp gud-rubydb-history) (car gud-rubydb-history) (concat rubydb-command-name " ")) nil nil '(gud-rubydb-history . 1)))) (if (not (fboundp 'gud-overload-functions)) (gud-common-init command-line 'gud-rubydb-massage-args 'gud-rubydb-marker-filter 'gud-rubydb-find-file) (gud-overload-functions '((gud-massage-args . gud-rubydb-massage-args) (gud-marker-filter . gud-rubydb-marker-filter) (gud-find-file . gud-rubydb-find-file))) (gud-common-init command-line rubydb-command-name)) (gud-def gud-break "b %l" "\C-b" "Set breakpoint at current line.") ; (gud-def gud-remove "clear %l" "\C-d" "Remove breakpoint at current line") (gud-def gud-step "s" "\C-s" "Step one source line with display.") (gud-def gud-next "n" "\C-n" "Step one line (skip functions).") (gud-def gud-cont "c" "\C-r" "Continue with display.") (gud-def gud-finish "finish" "\C-f" "Finish executing current function.") (gud-def gud-up "up %p" "<" "Up N stack frames (numeric arg).") (gud-def gud-down "down %p" ">" "Down N stack frames (numeric arg).") (gud-def gud-print "p %e" "\C-p" "Evaluate ruby expression at point.") (setq comint-prompt-regexp "^(rdb:-) ") (if (boundp 'comint-last-output-start) (set-marker comint-last-output-start (point))) (set (make-local-variable 'paragraph-start) comint-prompt-regexp) (run-hooks 'rubydb-mode-hook) ) ================================================ FILE: missing/acosh.c ================================================ /********************************************************************** acosh.c - $Author$ $Date$ created at: Fri Apr 12 00:34:17 JST 2002 public domain rewrite of acosh(3), asinh(3) and atanh(3) **********************************************************************/ #include #include #include /* DBL_MANT_DIG must be less than 4 times of bits of int */ #ifndef DBL_MANT_DIG #define DBL_MANT_DIG 53 /* in this case, at least 12 digit precision */ #endif #define BIG_CRITERIA_BIT (1< 0 #define BIG_CRITERIA (1.0*BIG_CRITERIA_BIT) #else #define BIG_CRITERIA (1.0*(1< 0 #define SMALL_CRITERIA (1.0/SMALL_CRITERIA_BIT) #else #define SMALL_CRITERIA (1.0*(1< BIG_CRITERIA) x += x; else x += sqrt((x + 1) * (x - 1)); return log(x); } #endif #ifndef HAVE_ASINH double asinh(x) double x; { int neg = x < 0; double z = fabs(x); if (z < SMALL_CRITERIA) return x; if (z < (1.0/(1< BIG_CRITERIA) { z = log(z + z); } else { z = log(z + sqrt(z * z + 1)); } if (neg) z = -z; return z; } #endif #ifndef HAVE_ATANH double atanh(x) double x; { int neg = x < 0; double z = fabs(x); if (z < SMALL_CRITERIA) return x; z = log(z > 1 ? -1 : (1 + z) / (1 - z)) / 2; if (neg) z = -z; return z; } #endif ================================================ FILE: missing/alloca.c ================================================ /* alloca -- (mostly) portable public-domain implementation -- D A Gwyn last edit: 86/05/30 rms include config.h, since on VMS it renames some symbols. Use xmalloc instead of malloc. This implementation of the PWB library alloca() function, which is used to allocate space off the run-time stack so that it is automatically reclaimed upon procedure exit, was inspired by discussions with J. Q. Johnson of Cornell. It should work under any C implementation that uses an actual procedure stack (as opposed to a linked list of frames). There are some preprocessor constants that can be defined when compiling for your specific system, for improved efficiency; however, the defaults should be okay. The general concept of this implementation is to keep track of all alloca()-allocated blocks, and reclaim any that are found to be deeper in the stack than the current invocation. This heuristic does not reclaim storage as soon as it becomes invalid, but it will do so eventually. As a special case, alloca(0) reclaims storage without allocating any. It is a good idea to use alloca(0) in your main control loop, etc. to force garbage collection. */ #ifndef lint static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */ #endif #include #include "config.h" #ifdef emacs #ifdef static /* actually, only want this if static is defined as "" -- this is for usg, in which emacs must undefine static in order to make unexec workable */ #ifndef STACK_DIRECTION you lose -- must know STACK_DIRECTION at compile-time #endif /* STACK_DIRECTION undefined */ #endif /* static */ #endif /* emacs */ typedef void *pointer; /* generic pointer type */ #define NULL 0 /* null pointer constant */ #ifdef RUBY_LIB #define xmalloc ruby_xmalloc #define xfree ruby_xfree #endif extern void xfree(); extern pointer xmalloc(); /* Define STACK_DIRECTION if you know the direction of stack growth for your system; otherwise it will be automatically deduced at run-time. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ #ifndef STACK_DIRECTION #define STACK_DIRECTION 0 /* direction unknown */ #endif #if STACK_DIRECTION != 0 #define STACK_DIR STACK_DIRECTION /* known at compile-time */ #else /* STACK_DIRECTION == 0; need run-time code */ static int stack_dir; /* 1 or -1 once known */ #define STACK_DIR stack_dir static void find_stack_direction (/* void */) { static char *addr = NULL; /* address of first `dummy', once known */ auto char dummy; /* to get stack address */ if (addr == NULL) { /* initial entry */ addr = &dummy; find_stack_direction (); /* recurse once */ } else /* second entry */ if (&dummy > addr) stack_dir = 1; /* stack grew upward */ else stack_dir = -1; /* stack grew downward */ } #endif /* STACK_DIRECTION == 0 */ /* An "alloca header" is used to: (a) chain together all alloca()ed blocks; (b) keep track of stack depth. It is very important that sizeof(header) agree with malloc() alignment chunk size. The following default should work okay. */ #ifndef ALIGN_SIZE #define ALIGN_SIZE sizeof(double) #endif typedef union hdr { char align[ALIGN_SIZE]; /* to force sizeof(header) */ struct { union hdr *next; /* for chaining headers */ char *deep; /* for stack depth measure */ } h; } header; /* alloca( size ) returns a pointer to at least `size' bytes of storage which will be automatically reclaimed upon exit from the procedure that called alloca(). Originally, this space was supposed to be taken from the current stack frame of the caller, but that method cannot be made to work for some implementations of C, for example under Gould's UTX/32. */ static header *last_alloca_header = NULL; /* -> last alloca header */ pointer alloca (size_t size) /* returns pointer to storage */ { auto char probe; /* probes stack depth: */ register char *depth = &probe; #if STACK_DIRECTION == 0 if (STACK_DIR == 0) /* unknown growth direction */ find_stack_direction (); #endif /* Reclaim garbage, defined as all alloca()ed storage that was allocated from deeper in the stack than currently. */ { register header *hp; /* traverses linked list */ for (hp = last_alloca_header; hp != NULL;) if (STACK_DIR > 0 && hp->h.deep > depth || STACK_DIR < 0 && hp->h.deep < depth) { register header *np = hp->h.next; xfree ((pointer) hp); /* collect garbage */ hp = np; /* -> next header */ } else break; /* rest are not deeper */ last_alloca_header = hp; /* -> last valid storage */ } if (size == 0) return NULL; /* no allocation required */ /* Allocate combined header + user data storage. */ { register pointer new = xmalloc (sizeof (header) + size); /* address of header */ ((header *)new)->h.next = last_alloca_header; ((header *)new)->h.deep = depth; last_alloca_header = (header *)new; /* User storage begins just after header. */ return (pointer)((char *)new + sizeof(header)); } } ================================================ FILE: missing/crypt.c ================================================ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Tom Truscott. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)crypt.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ #ifdef HAVE_UNISTD_H #include #endif #include #ifdef HAVE_PWD_H #include #endif #include #ifndef _PASSWORD_EFMT1 #define _PASSWORD_EFMT1 '_' #endif /* * UNIX password, and DES, encryption. * By Tom Truscott, trt@rti.rti.org, * from algorithms by Robert W. Baldwin and James Gillogly. * * References: * "Mathematical Cryptology for Computer Scientists and Mathematicians," * by Wayne Patterson, 1987, ISBN 0-8476-7438-X. * * "Password Security: A Case History," R. Morris and Ken Thompson, * Communications of the ACM, vol. 22, pp. 594-597, Nov. 1979. * * "DES will be Totally Insecure within Ten Years," M.E. Hellman, * IEEE Spectrum, vol. 16, pp. 32-39, July 1979. */ /* ===== Configuration ==================== */ /* * define "MUST_ALIGN" if your compiler cannot load/store * long integers at arbitrary (e.g. odd) memory locations. * (Either that or never pass unaligned addresses to des_cipher!) */ #if !defined(vax) #define MUST_ALIGN #endif #ifdef CHAR_BITS #if CHAR_BITS != 8 #error C_block structure assumes 8 bit characters #endif #endif /* * define "LONG_IS_32_BITS" only if sizeof(long)==4. * This avoids use of bit fields (your compiler may be sloppy with them). */ #if !defined(cray) #define LONG_IS_32_BITS #endif /* * define "B64" to be the declaration for a 64 bit integer. * XXX this feature is currently unused, see "endian" comment below. */ #if defined(cray) #define B64 long #endif #if defined(convex) #define B64 long long #endif /* * define "LARGEDATA" to get faster permutations, by using about 72 kilobytes * of lookup tables. This speeds up des_setkey() and des_cipher(), but has * little effect on crypt(). */ #if defined(notdef) #define LARGEDATA #endif int des_setkey(), des_cipher(); /* compile with "-DSTATIC=int" when profiling */ #ifndef STATIC #define STATIC static #endif STATIC void init_des(), init_perm(), permute(); #ifdef DEBUG STATIC void prtab(); #endif /* ==================================== */ /* * Cipher-block representation (Bob Baldwin): * * DES operates on groups of 64 bits, numbered 1..64 (sigh). One * representation is to store one bit per byte in an array of bytes. Bit N of * the NBS spec is stored as the LSB of the Nth byte (index N-1) in the array. * Another representation stores the 64 bits in 8 bytes, with bits 1..8 in the * first byte, 9..16 in the second, and so on. The DES spec apparently has * bit 1 in the MSB of the first byte, but that is particularly noxious so we * bit-reverse each byte so that bit 1 is the LSB of the first byte, bit 8 is * the MSB of the first byte. Specifically, the 64-bit input data and key are * converted to LSB format, and the output 64-bit block is converted back into * MSB format. * * DES operates internally on groups of 32 bits which are expanded to 48 bits * by permutation E and shrunk back to 32 bits by the S boxes. To speed up * the computation, the expansion is applied only once, the expanded * representation is maintained during the encryption, and a compression * permutation is applied only at the end. To speed up the S-box lookups, * the 48 bits are maintained as eight 6 bit groups, one per byte, which * directly feed the eight S-boxes. Within each byte, the 6 bits are the * most significant ones. The low two bits of each byte are zero. (Thus, * bit 1 of the 48 bit E expansion is stored as the "4"-valued bit of the * first byte in the eight byte representation, bit 2 of the 48 bit value is * the "8"-valued bit, and so on.) In fact, a combined "SPE"-box lookup is * used, in which the output is the 64 bit result of an S-box lookup which * has been permuted by P and expanded by E, and is ready for use in the next * iteration. Two 32-bit wide tables, SPE[0] and SPE[1], are used for this * lookup. Since each byte in the 48 bit path is a multiple of four, indexed * lookup of SPE[0] and SPE[1] is simple and fast. The key schedule and * "salt" are also converted to this 8*(6+2) format. The SPE table size is * 8*64*8 = 4K bytes. * * To speed up bit-parallel operations (such as XOR), the 8 byte * representation is "union"ed with 32 bit values "i0" and "i1", and, on * machines which support it, a 64 bit value "b64". This data structure, * "C_block", has two problems. First, alignment restrictions must be * honored. Second, the byte-order (e.g. little-endian or big-endian) of * the architecture becomes visible. * * The byte-order problem is unfortunate, since on the one hand it is good * to have a machine-independent C_block representation (bits 1..8 in the * first byte, etc.), and on the other hand it is good for the LSB of the * first byte to be the LSB of i0. We cannot have both these things, so we * currently use the "little-endian" representation and avoid any multi-byte * operations that depend on byte order. This largely precludes use of the * 64-bit datatype since the relative order of i0 and i1 are unknown. It * also inhibits grouping the SPE table to look up 12 bits at a time. (The * 12 bits can be stored in a 16-bit field with 3 low-order zeroes and 1 * high-order zero, providing fast indexing into a 64-bit wide SPE.) On the * other hand, 64-bit datatypes are currently rare, and a 12-bit SPE lookup * requires a 128 kilobyte table, so perhaps this is not a big loss. * * Permutation representation (Jim Gillogly): * * A transformation is defined by its effect on each of the 8 bytes of the * 64-bit input. For each byte we give a 64-bit output that has the bits in * the input distributed appropriately. The transformation is then the OR * of the 8 sets of 64-bits. This uses 8*256*8 = 16K bytes of storage for * each transformation. Unless LARGEDATA is defined, however, a more compact * table is used which looks up 16 4-bit "chunks" rather than 8 8-bit chunks. * The smaller table uses 16*16*8 = 2K bytes for each transformation. This * is slower but tolerable, particularly for password encryption in which * the SPE transformation is iterated many times. The small tables total 9K * bytes, the large tables total 72K bytes. * * The transformations used are: * IE3264: MSB->LSB conversion, initial permutation, and expansion. * This is done by collecting the 32 even-numbered bits and applying * a 32->64 bit transformation, and then collecting the 32 odd-numbered * bits and applying the same transformation. Since there are only * 32 input bits, the IE3264 transformation table is half the size of * the usual table. * CF6464: Compression, final permutation, and LSB->MSB conversion. * This is done by two trivial 48->32 bit compressions to obtain * a 64-bit block (the bit numbering is given in the "CIFP" table) * followed by a 64->64 bit "cleanup" transformation. (It would * be possible to group the bits in the 64-bit block so that 2 * identical 32->32 bit transformations could be used instead, * saving a factor of 4 in space and possibly 2 in time, but * byte-ordering and other complications rear their ugly head. * Similar opportunities/problems arise in the key schedule * transforms.) * PC1ROT: MSB->LSB, PC1 permutation, rotate, and PC2 permutation. * This admittedly baroque 64->64 bit transformation is used to * produce the first code (in 8*(6+2) format) of the key schedule. * PC2ROT[0]: Inverse PC2 permutation, rotate, and PC2 permutation. * It would be possible to define 15 more transformations, each * with a different rotation, to generate the entire key schedule. * To save space, however, we instead permute each code into the * next by using a transformation that "undoes" the PC2 permutation, * rotates the code, and then applies PC2. Unfortunately, PC2 * transforms 56 bits into 48 bits, dropping 8 bits, so PC2 is not * invertible. We get around that problem by using a modified PC2 * which retains the 8 otherwise-lost bits in the unused low-order * bits of each byte. The low-order bits are cleared when the * codes are stored into the key schedule. * PC2ROT[1]: Same as PC2ROT[0], but with two rotations. * This is faster than applying PC2ROT[0] twice, * * The Bell Labs "salt" (Bob Baldwin): * * The salting is a simple permutation applied to the 48-bit result of E. * Specifically, if bit i (1 <= i <= 24) of the salt is set then bits i and * i+24 of the result are swapped. The salt is thus a 24 bit number, with * 16777216 possible values. (The original salt was 12 bits and could not * swap bits 13..24 with 36..48.) * * It is possible, but ugly, to warp the SPE table to account for the salt * permutation. Fortunately, the conditional bit swapping requires only * about four machine instructions and can be done on-the-fly with about an * 8% performance penalty. */ typedef union { unsigned char b[8]; struct { #if defined(LONG_IS_32_BITS) /* long is often faster than a 32-bit bit field */ long i0; long i1; #else long i0: 32; long i1: 32; #endif } b32; #if defined(B64) B64 b64; #endif } C_block; /* * Convert twenty-four-bit long in host-order * to six bits (and 2 low-order zeroes) per char little-endian format. */ #define TO_SIX_BIT(rslt, src) { \ C_block cvt; \ cvt.b[0] = src; src >>= 6; \ cvt.b[1] = src; src >>= 6; \ cvt.b[2] = src; src >>= 6; \ cvt.b[3] = src; \ rslt = (cvt.b32.i0 & 0x3f3f3f3fL) << 2; \ } /* * These macros may someday permit efficient use of 64-bit integers. */ #define ZERO(d,d0,d1) d0 = 0, d1 = 0 #define LOAD(d,d0,d1,bl) d0 = (bl).b32.i0, d1 = (bl).b32.i1 #define LOADREG(d,d0,d1,s,s0,s1) d0 = s0, d1 = s1 #define OR(d,d0,d1,bl) d0 |= (bl).b32.i0, d1 |= (bl).b32.i1 #define STORE(s,s0,s1,bl) (bl).b32.i0 = s0, (bl).b32.i1 = s1 #define DCL_BLOCK(d,d0,d1) long d0, d1 #if defined(LARGEDATA) /* Waste memory like crazy. Also, do permutations in line */ #define LGCHUNKBITS 3 #define CHUNKBITS (1<>4]; OR(D,D0,D1,*tp); p += (1< 0); STORE(D,D0,D1,*out); } #endif /* LARGEDATA */ /* ===== (mostly) Standard DES Tables ==================== */ static unsigned char IP[] = { /* initial permutation */ 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7, }; /* The final permutation is the inverse of IP - no table is necessary */ static unsigned char ExpandTr[] = { /* expansion operation */ 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1, }; static unsigned char PC1[] = { /* permuted choice table 1 */ 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4, }; static unsigned char Rotates[] = { /* PC1 rotation schedule */ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, }; /* note: each "row" of PC2 is left-padded with bits that make it invertible */ static unsigned char PC2[] = { /* permuted choice table 2 */ 9, 18, 14, 17, 11, 24, 1, 5, 22, 25, 3, 28, 15, 6, 21, 10, 35, 38, 23, 19, 12, 4, 26, 8, 43, 54, 16, 7, 27, 20, 13, 2, 0, 0, 41, 52, 31, 37, 47, 55, 0, 0, 30, 40, 51, 45, 33, 48, 0, 0, 44, 49, 39, 56, 34, 53, 0, 0, 46, 42, 50, 36, 29, 32, }; static unsigned char S[8][64] = { /* 48->32 bit substitution tables */ { /* S[1] */ 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13, }, { /* S[2] */ 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9, }, { /* S[3] */ 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12, }, { /* S[4] */ 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14, }, { /* S[5] */ 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3, }, { /* S[6] */ 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13, }, { /* S[7] */ 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12, }, { /* S[8] */ 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11, }, }; static unsigned char P32Tr[] = { /* 32-bit permutation function */ 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25, }; static unsigned char CIFP[] = { /* compressed/interleaved permutation */ 1, 2, 3, 4, 17, 18, 19, 20, 5, 6, 7, 8, 21, 22, 23, 24, 9, 10, 11, 12, 25, 26, 27, 28, 13, 14, 15, 16, 29, 30, 31, 32, 33, 34, 35, 36, 49, 50, 51, 52, 37, 38, 39, 40, 53, 54, 55, 56, 41, 42, 43, 44, 57, 58, 59, 60, 45, 46, 47, 48, 61, 62, 63, 64, }; static unsigned char itoa64[] = /* 0..63 => ascii-64 */ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; /* ===== Tables that are initialized at run time ==================== */ static unsigned char a64toi[128]; /* ascii-64 => 0..63 */ /* Initial key schedule permutation */ static C_block PC1ROT[64/CHUNKBITS][1< final permutation table */ static C_block CF6464[64/CHUNKBITS][1<= 0; ) { if ((t = (unsigned char)setting[i]) == '\0') t = '.'; encp[i] = t; num_iter = (num_iter<<6) | a64toi[t]; } setting += 4; encp += 4; salt_size = 4; break; default: num_iter = 25; salt_size = 2; } salt = 0; for (i = salt_size; --i >= 0; ) { if ((t = (unsigned char)setting[i]) == '\0') t = '.'; encp[i] = t; salt = (salt<<6) | a64toi[t]; } encp += salt_size; if (des_cipher((char *)&constdatablock, (char *)&rsltblock, salt, num_iter)) return (NULL); /* * Encode the 64 cipher bits as 11 ascii characters. */ i = ((long)((rsltblock.b[0]<<8) | rsltblock.b[1])<<8) | rsltblock.b[2]; encp[3] = itoa64[i&0x3f]; i >>= 6; encp[2] = itoa64[i&0x3f]; i >>= 6; encp[1] = itoa64[i&0x3f]; i >>= 6; encp[0] = itoa64[i]; encp += 4; i = ((long)((rsltblock.b[3]<<8) | rsltblock.b[4])<<8) | rsltblock.b[5]; encp[3] = itoa64[i&0x3f]; i >>= 6; encp[2] = itoa64[i&0x3f]; i >>= 6; encp[1] = itoa64[i&0x3f]; i >>= 6; encp[0] = itoa64[i]; encp += 4; i = ((long)((rsltblock.b[6])<<8) | rsltblock.b[7])<<2; encp[2] = itoa64[i&0x3f]; i >>= 6; encp[1] = itoa64[i&0x3f]; i >>= 6; encp[0] = itoa64[i]; encp[3] = 0; return (cryptresult); } /* * The Key Schedule, filled in by des_setkey() or setkey(). */ #define KS_SIZE 16 static C_block KS[KS_SIZE]; /* * Set up the key schedule from the key. */ int des_setkey(key) register const char *key; { register DCL_BLOCK(K, K0, K1); register C_block *ptabp; register int i; static int des_ready = 0; if (!des_ready) { init_des(); des_ready = 1; } PERM6464(K,K0,K1,(unsigned char *)key,(C_block *)PC1ROT); key = (char *)&KS[0]; STORE(K&~0x03030303L, K0&~0x03030303L, K1, *(C_block *)key); for (i = 1; i < 16; i++) { key += sizeof(C_block); STORE(K,K0,K1,*(C_block *)key); ptabp = (C_block *)PC2ROT[Rotates[i]-1]; PERM6464(K,K0,K1,(unsigned char *)key,ptabp); STORE(K&~0x03030303L, K0&~0x03030303L, K1, *(C_block *)key); } return (0); } /* * Encrypt (or decrypt if num_iter < 0) the 8 chars at "in" with abs(num_iter) * iterations of DES, using the the given 24-bit salt and the pre-computed key * schedule, and store the resulting 8 chars at "out" (in == out is permitted). * * NOTE: the performance of this routine is critically dependent on your * compiler and machine architecture. */ int des_cipher(in, out, salt, num_iter) const char *in; char *out; long salt; int num_iter; { /* variables that we want in registers, most important first */ #if defined(pdp11) register int j; #endif register long L0, L1, R0, R1, k; register C_block *kp; register int ks_inc, loop_count; C_block B; L0 = salt; TO_SIX_BIT(salt, L0); /* convert to 4*(6+2) format */ #if defined(vax) || defined(pdp11) salt = ~salt; /* "x &~ y" is faster than "x & y". */ #define SALT (~salt) #else #define SALT salt #endif #if defined(MUST_ALIGN) B.b[0] = in[0]; B.b[1] = in[1]; B.b[2] = in[2]; B.b[3] = in[3]; B.b[4] = in[4]; B.b[5] = in[5]; B.b[6] = in[6]; B.b[7] = in[7]; LOAD(L,L0,L1,B); #else LOAD(L,L0,L1,*(C_block *)in); #endif LOADREG(R,R0,R1,L,L0,L1); L0 &= 0x55555555L; L1 &= 0x55555555L; L0 = (L0 << 1) | L1; /* L0 is the even-numbered input bits */ R0 &= 0xaaaaaaaaL; R1 = (R1 >> 1) & 0x55555555L; L1 = R0 | R1; /* L1 is the odd-numbered input bits */ STORE(L,L0,L1,B); PERM3264(L,L0,L1,B.b, (C_block *)IE3264); /* even bits */ PERM3264(R,R0,R1,B.b+4,(C_block *)IE3264); /* odd bits */ if (num_iter >= 0) { /* encryption */ kp = &KS[0]; ks_inc = sizeof(*kp); } else { /* decryption */ num_iter = -num_iter; kp = &KS[KS_SIZE-1]; ks_inc = -sizeof(*kp); } while (--num_iter >= 0) { loop_count = 8; do { #define SPTAB(t, i) (*(long *)((unsigned char *)t + i*(sizeof(long)/4))) #if defined(gould) /* use this if B.b[i] is evaluated just once ... */ #define DOXOR(x,y,i) x^=SPTAB(SPE[0][i],B.b[i]); y^=SPTAB(SPE[1][i],B.b[i]); #else #if defined(pdp11) /* use this if your "long" int indexing is slow */ #define DOXOR(x,y,i) j=B.b[i]; x^=SPTAB(SPE[0][i],j); y^=SPTAB(SPE[1][i],j); #else /* use this if "k" is allocated to a register ... */ #define DOXOR(x,y,i) k=B.b[i]; x^=SPTAB(SPE[0][i],k); y^=SPTAB(SPE[1][i],k); #endif #endif #define CRUNCH(p0, p1, q0, q1) \ k = (q0 ^ q1) & SALT; \ B.b32.i0 = k ^ q0 ^ kp->b32.i0; \ B.b32.i1 = k ^ q1 ^ kp->b32.i1; \ kp = (C_block *)((char *)kp+ks_inc); \ \ DOXOR(p0, p1, 0); \ DOXOR(p0, p1, 1); \ DOXOR(p0, p1, 2); \ DOXOR(p0, p1, 3); \ DOXOR(p0, p1, 4); \ DOXOR(p0, p1, 5); \ DOXOR(p0, p1, 6); \ DOXOR(p0, p1, 7); CRUNCH(L0, L1, R0, R1); CRUNCH(R0, R1, L0, L1); } while (--loop_count != 0); kp = (C_block *)((char *)kp-(ks_inc*KS_SIZE)); /* swap L and R */ L0 ^= R0; L1 ^= R1; R0 ^= L0; R1 ^= L1; L0 ^= R0; L1 ^= R1; } /* store the encrypted (or decrypted) result */ L0 = ((L0 >> 3) & 0x0f0f0f0fL) | ((L1 << 1) & 0xf0f0f0f0L); L1 = ((R0 >> 3) & 0x0f0f0f0fL) | ((R1 << 1) & 0xf0f0f0f0L); STORE(L,L0,L1,B); PERM6464(L,L0,L1,B.b, (C_block *)CF6464); #if defined(MUST_ALIGN) STORE(L,L0,L1,B); out[0] = B.b[0]; out[1] = B.b[1]; out[2] = B.b[2]; out[3] = B.b[3]; out[4] = B.b[4]; out[5] = B.b[5]; out[6] = B.b[6]; out[7] = B.b[7]; #else STORE(L,L0,L1,*(C_block *)out); #endif return (0); } /* * Initialize various tables. This need only be done once. It could even be * done at compile time, if the compiler were capable of that sort of thing. */ STATIC void init_des() { register int i, j; register long k; register int tableno; static unsigned char perm[64], tmp32[32]; /* "static" for speed */ /* * table that converts chars "./0-9A-Za-z"to integers 0-63. */ for (i = 0; i < 64; i++) a64toi[itoa64[i]] = i; /* * PC1ROT - bit reverse, then PC1, then Rotate, then PC2. */ for (i = 0; i < 64; i++) perm[i] = 0; for (i = 0; i < 64; i++) { if ((k = PC2[i]) == 0) continue; k += Rotates[0]-1; if ((k%28) < Rotates[0]) k -= 28; k = PC1[k]; if (k > 0) { k--; k = (k|07) - (k&07); k++; } perm[i] = k; } #ifdef DEBUG prtab("pc1tab", perm, 8); #endif init_perm(PC1ROT, perm, 8, 8); /* * PC2ROT - PC2 inverse, then Rotate (once or twice), then PC2. */ for (j = 0; j < 2; j++) { unsigned char pc2inv[64]; for (i = 0; i < 64; i++) perm[i] = pc2inv[i] = 0; for (i = 0; i < 64; i++) { if ((k = PC2[i]) == 0) continue; pc2inv[k-1] = i+1; } for (i = 0; i < 64; i++) { if ((k = PC2[i]) == 0) continue; k += j; if ((k%28) <= j) k -= 28; perm[i] = pc2inv[k]; } #ifdef DEBUG prtab("pc2tab", perm, 8); #endif init_perm(PC2ROT[j], perm, 8, 8); } /* * Bit reverse, then initial permutation, then expansion. */ for (i = 0; i < 8; i++) { for (j = 0; j < 8; j++) { k = (j < 2)? 0: IP[ExpandTr[i*6+j-2]-1]; if (k > 32) k -= 32; else if (k > 0) k--; if (k > 0) { k--; k = (k|07) - (k&07); k++; } perm[i*8+j] = k; } } #ifdef DEBUG prtab("ietab", perm, 8); #endif init_perm(IE3264, perm, 4, 8); /* * Compression, then final permutation, then bit reverse. */ for (i = 0; i < 64; i++) { k = IP[CIFP[i]-1]; if (k > 0) { k--; k = (k|07) - (k&07); k++; } perm[k-1] = i+1; } #ifdef DEBUG prtab("cftab", perm, 8); #endif init_perm(CF6464, perm, 8, 8); /* * SPE table */ for (i = 0; i < 48; i++) perm[i] = P32Tr[ExpandTr[i]-1]; for (tableno = 0; tableno < 8; tableno++) { for (j = 0; j < 64; j++) { k = (((j >> 0) &01) << 5)| (((j >> 1) &01) << 3)| (((j >> 2) &01) << 2)| (((j >> 3) &01) << 1)| (((j >> 4) &01) << 0)| (((j >> 5) &01) << 4); k = S[tableno][k]; k = (((k >> 3)&01) << 0)| (((k >> 2)&01) << 1)| (((k >> 1)&01) << 2)| (((k >> 0)&01) << 3); for (i = 0; i < 32; i++) tmp32[i] = 0; for (i = 0; i < 4; i++) tmp32[4 * tableno + i] = (k >> i) & 01; k = 0; for (i = 24; --i >= 0; ) k = (k<<1) | tmp32[perm[i]-1]; TO_SIX_BIT(SPE[0][tableno][j], k); k = 0; for (i = 24; --i >= 0; ) k = (k<<1) | tmp32[perm[i+24]-1]; TO_SIX_BIT(SPE[1][tableno][j], k); } } } /* * Initialize "perm" to represent transformation "p", which rearranges * (perhaps with expansion and/or contraction) one packed array of bits * (of size "chars_in" characters) into another array (of size "chars_out" * characters). * * "perm" must be all-zeroes on entry to this routine. */ STATIC void init_perm(perm, p, chars_in, chars_out) C_block perm[64/CHUNKBITS][1<>LGCHUNKBITS; /* which chunk this bit comes from */ l = 1<<(l&(CHUNKBITS-1)); /* mask for this bit */ for (j = 0; j < (1<>3] |= 1<<(k&07); } } } /* * "setkey" routine (for backwards compatibility) */ int setkey(key) register const char *key; { register int i, j, k; C_block keyblock; for (i = 0; i < 8; i++) { k = 0; for (j = 0; j < 8; j++) { k <<= 1; k |= (unsigned char)*key++; } keyblock.b[i] = k; } return (des_setkey((char *)keyblock.b)); } /* * "encrypt" routine (for backwards compatibility) */ int encrypt(block, flag) register char *block; int flag; { register int i, j, k; C_block cblock; for (i = 0; i < 8; i++) { k = 0; for (j = 0; j < 8; j++) { k <<= 1; k |= (unsigned char)*block++; } cblock.b[i] = k; } if (des_cipher((char *)&cblock, (char *)&cblock, 0L, (flag ? -1: 1))) return (1); for (i = 7; i >= 0; i--) { k = cblock.b[i]; for (j = 7; j >= 0; j--) { *--block = k&01; k >>= 1; } } return (0); } #ifdef DEBUG STATIC void prtab(s, t, num_rows) char *s; unsigned char *t; int num_rows; { register int i, j; (void)printf("%s:\n", s); for (i = 0; i < num_rows; i++) { for (j = 0; j < 8; j++) { (void)printf("%3d", t[i*8+j]); } (void)printf("\n"); } (void)printf("\n"); } #endif ================================================ FILE: missing/dup2.c ================================================ /* * Public domain dup2() lookalike * by Curtis Jackson @ AT&T Technologies, Burlington, NC * electronic address: burl!rcj * * dup2 performs the following functions: * * Check to make sure that fd1 is a valid open file descriptor. * Check to see if fd2 is already open; if so, close it. * Duplicate fd1 onto fd2; checking to make sure fd2 is a valid fd. * Return fd2 if all went well; return BADEXIT otherwise. */ #include "config.h" #if defined(HAVE_FCNTL) # include #endif #if !defined(HAVE_FCNTL) || !defined(F_DUPFD) # include #endif #define BADEXIT -1 int dup2(fd1, fd2) int fd1, fd2; { #if defined(HAVE_FCNTL) && defined(F_DUPFD) if (fd1 != fd2) { #ifdef F_GETFL if (fcntl(fd1, F_GETFL) < 0) return BADEXIT; if (fcntl(fd2, F_GETFL) >= 0) close(fd2); #else close(fd2); #endif if (fcntl(fd1, F_DUPFD, fd2) < 0) return BADEXIT; } return fd2; #else extern int errno; int i, fd, fds[256]; if (fd1 == fd2) return 0; close(fd2); for (i=0; i<256; i++) { fd = fds[i] = dup(fd1); if (fd == fd2) break; } while (i) { close(fds[i--]); } if (fd == fd2) return 0; errno = EMFILE; return BADEXIT; #endif } ================================================ FILE: missing/erf.c ================================================ /* erf.c - public domain implementation of error function erf(3m) reference - Haruhiko Okumura: C-gengo niyoru saishin algorithm jiten (New Algorithm handbook in C language) (Gijyutsu hyouron sha, Tokyo, 1991) p.227 [in Japanese] */ #include #include #ifdef _WIN32 # include # if !defined __MINGW32__ || defined __NO_ISOCEXT # ifndef isnan # define isnan(x) _isnan(x) # endif # ifndef isinf # define isinf(x) (!_finite(x) && !_isnan(x)) # endif # ifndef finite # define finite(x) _finite(x) # endif # endif #endif static double q_gamma(double, double, double); /* Incomplete gamma function 1 / Gamma(a) * Int_0^x exp(-t) t^(a-1) dt */ static double p_gamma(a, x, loggamma_a) double a, x, loggamma_a; { int k; double result, term, previous; if (x >= 1 + a) return 1 - q_gamma(a, x, loggamma_a); if (x == 0) return 0; result = term = exp(a * log(x) - x - loggamma_a) / a; for (k = 1; k < 1000; k++) { term *= x / (a + k); previous = result; result += term; if (result == previous) return result; } fprintf(stderr, "erf.c:%d:p_gamma() could not converge.", __LINE__); return result; } /* Incomplete gamma function 1 / Gamma(a) * Int_x^inf exp(-t) t^(a-1) dt */ static double q_gamma(a, x, loggamma_a) double a, x, loggamma_a; { int k; double result, w, temp, previous; double la = 1, lb = 1 + x - a; /* Laguerre polynomial */ if (x < 1 + a) return 1 - p_gamma(a, x, loggamma_a); w = exp(a * log(x) - x - loggamma_a); result = w / lb; for (k = 2; k < 1000; k++) { temp = ((k - 1 - a) * (lb - la) + (k + x) * lb) / k; la = lb; lb = temp; w *= (k - 1 - a) / k; temp = w / (la * lb); previous = result; result += temp; if (result == previous) return result; } fprintf(stderr, "erf.c:%d:q_gamma() could not converge.", __LINE__); return result; } #define LOG_PI_OVER_2 0.572364942924700087071713675675 /* log_e(PI)/2 */ double erf(x) double x; { if (!finite(x)) { if (isnan(x)) return x; /* erf(NaN) = NaN */ return (x>0 ? 1.0 : -1.0); /* erf(+-inf) = +-1.0 */ } if (x >= 0) return p_gamma(0.5, x * x, LOG_PI_OVER_2); else return - p_gamma(0.5, x * x, LOG_PI_OVER_2); } double erfc(x) double x; { if (!finite(x)) { if (isnan(x)) return x; /* erfc(NaN) = NaN */ return (x>0 ? 0.0 : 2.0); /* erfc(+-inf) = 0.0, 2.0 */ } if (x >= 0) return q_gamma(0.5, x * x, LOG_PI_OVER_2); else return 1 + p_gamma(0.5, x * x, LOG_PI_OVER_2); } ================================================ FILE: missing/file.h ================================================ /* This is file FILE.H */ #ifndef _FILE_H_ #define _FILE_H_ #include #ifndef L_SET # define L_SET 0 /* seek from beginning. */ # define L_CURR 1 /* seek from current position. */ # define L_INCR 1 /* ditto. */ # define L_XTND 2 /* seek from end. */ #endif #ifndef R_OK # define R_OK 4 /* test whether readable. */ # define W_OK 2 /* test whether writable. */ # define X_OK 1 /* test whether execubale. */ # define F_OK 0 /* test whether exist. */ #endif #endif ================================================ FILE: missing/fileblocks.c ================================================ /* dummy for autoconf */ ================================================ FILE: missing/finite.c ================================================ /* public domain rewrite of finite(3) */ int finite(n) double n; { return !isnan(n) && !isinf(n); } ================================================ FILE: missing/flock.c ================================================ #include "config.h" #if defined _WIN32 #elif defined HAVE_FCNTL && defined HAVE_FCNTL_H /* These are the flock() constants. Since this sytems doesn't have flock(), the values of the constants are probably not available. */ # ifndef LOCK_SH # define LOCK_SH 1 # endif # ifndef LOCK_EX # define LOCK_EX 2 # endif # ifndef LOCK_NB # define LOCK_NB 4 # endif # ifndef LOCK_UN # define LOCK_UN 8 # endif #include #include #include int flock(fd, operation) int fd; int operation; { struct flock lock; switch (operation & ~LOCK_NB) { case LOCK_SH: lock.l_type = F_RDLCK; break; case LOCK_EX: lock.l_type = F_WRLCK; break; case LOCK_UN: lock.l_type = F_UNLCK; break; default: errno = EINVAL; return -1; } lock.l_whence = SEEK_SET; lock.l_start = lock.l_len = 0L; return fcntl(fd, (operation & LOCK_NB) ? F_SETLK : F_SETLKW, &lock); } #elif defined(HAVE_LOCKF) #include #include /* Emulate flock() with lockf() or fcntl(). This is just to increase portability of scripts. The calls might not be completely interchangeable. What's really needed is a good file locking module. */ # ifndef F_ULOCK # define F_ULOCK 0 /* Unlock a previously locked region */ # endif # ifndef F_LOCK # define F_LOCK 1 /* Lock a region for exclusive use */ # endif # ifndef F_TLOCK # define F_TLOCK 2 /* Test and lock a region for exclusive use */ # endif # ifndef F_TEST # define F_TEST 3 /* Test a region for other processes locks */ # endif /* These are the flock() constants. Since this sytems doesn't have flock(), the values of the constants are probably not available. */ # ifndef LOCK_SH # define LOCK_SH 1 # endif # ifndef LOCK_EX # define LOCK_EX 2 # endif # ifndef LOCK_NB # define LOCK_NB 4 # endif # ifndef LOCK_UN # define LOCK_UN 8 # endif int flock(fd, operation) int fd; int operation; { switch (operation) { /* LOCK_SH - get a shared lock */ case LOCK_SH: rb_notimplement(); return -1; /* LOCK_EX - get an exclusive lock */ case LOCK_EX: return lockf (fd, F_LOCK, 0); /* LOCK_SH|LOCK_NB - get a non-blocking shared lock */ case LOCK_SH|LOCK_NB: rb_notimplement(); return -1; /* LOCK_EX|LOCK_NB - get a non-blocking exclusive lock */ case LOCK_EX|LOCK_NB: return lockf (fd, F_TLOCK, 0); /* LOCK_UN - unlock */ case LOCK_UN: return lockf (fd, F_ULOCK, 0); /* Default - can't decipher operation */ default: errno = EINVAL; return -1; } } #else int flock(fd, operation) int fd; int operation; { rb_notimplement(); return -1; } #endif ================================================ FILE: missing/hypot.c ================================================ /* public domain rewrite of hypot */ #include double hypot(x,y) double x, y; { if (x < 0) x = -x; if (y < 0) y = -y; if (x < y) { double tmp = x; x = y; y = tmp; } if (y == 0.0) return x; y /= x; return x * sqrt(1.0+y*y); } ================================================ FILE: missing/isinf.c ================================================ /* public domain rewrite of isinf(3) */ #ifdef __osf__ #define _IEEE 1 #include int isinf(n) double n; { if (IsNANorINF(n) && IsINF(n)) { return 1; } else { return 0; } } #else #include "config.h" #if defined(HAVE_FINITE) && defined(HAVE_ISNAN) #include #ifdef HAVE_IEEEFP_H #include #endif /* * isinf may be provided only as a macro. * ex. HP-UX, Solaris 10 * http://www.gnu.org/software/automake/manual/autoconf/Function-Portability.html */ #ifndef isinf int isinf(n) double n; { return (!finite(n) && !isnan(n)); } #endif #else #ifdef HAVE_STRING_H # include #else # include #endif static double zero() { return 0.0; } static double one() { return 1.0; } static double inf() { return one() / zero(); } int isinf(n) double n; { static double pinf = 0.0; static double ninf = 0.0; if (pinf == 0.0) { pinf = inf(); ninf = -pinf; } return memcmp(&n, &pinf, sizeof n) == 0 || memcmp(&n, &ninf, sizeof n) == 0; } #endif #endif ================================================ FILE: missing/isnan.c ================================================ /* public domain rewrite of isnan(3) */ static int double_ne(); int isnan(n) double n; { return double_ne(n, n); } static int double_ne(n1, n2) double n1, n2; { return n1 != n2; } ================================================ FILE: missing/memcmp.c ================================================ /* public domain rewrite of memcmp(3) */ int memcmp(s1,s2,len) char *s1; char *s2; register int len; { register unsigned char *a = (unsigned char*)s1; register unsigned char *b = (unsigned char*)s2; register int tmp; while (len--) { if (tmp = *a++ - *b++) return tmp; } return 0; } ================================================ FILE: missing/memmove.c ================================================ /* public domain rewrite of memcmp(3) */ void * memmove (d, s, n) void *d, *s; int n; { char *dst = d; char *src = s; void *ret = dst; if (src < dst) { src += n; dst += n; while (n--) *--dst = *--src; } else if (dst < src) while (n--) *dst++ = *src++; return ret; } ================================================ FILE: missing/os2.c ================================================ /* os/2 compatibility functions -- follows Ruby's license */ #include "ruby.h" #include #include #include #include #include #include #define INCL_DOS #include int chown(char *path, int owner, int group) { return 0; } int link(char *from, char *to) { return -1; } typedef char* CHARP; int do_spawn(cmd) char *cmd; { register char **a; register char *s; char **argv; char *shell, *sw, *cmd2; int status; if ((shell = getenv("RUBYSHELL")) != NULL && *shell != '\0') { s = shell; do *s = isupper(*s) ? tolower(*s) : *s; while (*++s); if (strstr(shell, "cmd") || strstr(shell, "4os2")) sw = "/c"; else sw = "-c"; } else if ((shell = getenv("SHELL")) != NULL && *shell != '\0') { s = shell; do *s = isupper(*s) ? tolower(*s) : *s; while (*++s); if (strstr(shell, "cmd") || strstr(shell, "4os2")) sw = "/c"; else sw = "-c"; } else if ((shell = getenv("COMSPEC")) != NULL && *shell != '\0') { s = shell; do *s = isupper(*s) ? tolower(*s) : *s; while (*++s); if (strstr(shell, "cmd") || strstr(shell, "4os2")) sw = "/c"; else sw = "-c"; } /* see if there are shell metacharacters in it */ /*SUPPRESS 530*/ /* for (s = cmd; *s && isalpha(*s); s++) ; if (*s == '=') goto doshell; */ for (s = cmd; *s; s++) { if (*sw == '-' && *s != ' ' && !isalpha(*s) && index("$&*(){}[]'\";\\|?<>~`\n",*s)) { if (*s == '\n' && !s[1]) { *s = '\0'; break; } goto doshell; } else if (*sw == '/' && *s != ' ' && !isalpha(*s) && index("^()<>|&\n",*s)) { if (*s == '\n' && !s[1]) { *s = '\0'; break; } doshell: status = spawnlp(P_WAIT,shell,shell,sw,cmd,(char*)NULL); return status; } } argv = ALLOC_N(CHARP,(strlen(cmd) / 2 + 2)); cmd2 = ALLOC_N(char, (strlen(cmd) + 1)); strcpy(cmd2, cmd); a = argv; for (s = cmd2; *s;) { while (*s && isspace(*s)) s++; if (*s) *(a++) = s; while (*s && !isspace(*s)) s++; if (*s) *s++ = '\0'; } *a = NULL; if (argv[0]) { if ((status = spawnvp(P_WAIT, argv[0], argv)) == -1) { free(argv); free(cmd2); return -1; } } free(cmd2); free(argv); return status; } ================================================ FILE: missing/strcasecmp.c ================================================ /* public domain rewrite of strcasecmp(3) */ #include int strcasecmp(p1, p2) char *p1, *p2; { while (*p1 && *p2) { if (toupper(*p1) != toupper(*p2)) return toupper(*p1) - toupper(*p2); p1++; p2++; } return strlen(p1) - strlen(p2); } ================================================ FILE: missing/strchr.c ================================================ /* public domain rewrite of strchr(3) and strrchr(3) */ char * strchr(s, c) char *s; int c; { if (c == 0) return s + strlen(s); while (*s) { if (*s == c) return s; s++; } return 0; } char * strrchr(s, c) char *s; int c; { char *save; if (c == 0) return s + strlen(s); save = 0; while (*s) { if (*s == c) save = s; s++; } return save; } ================================================ FILE: missing/strerror.c ================================================ /* public domain rewrite of strerror(3) */ extern int sys_nerr; extern char *sys_errlist[]; static char msg[50]; char * strerror(error) int error; { if (error <= sys_nerr && error > 0) { return sys_errlist[error]; } sprintf(msg, "Unknown error (%d)", error); return msg; } ================================================ FILE: missing/strftime.c ================================================ /* * strftime.c * * Public-domain implementation of ANSI C library routine. * * It's written in old-style C for maximal portability. * However, since I'm used to prototypes, I've included them too. * * If you want stuff in the System V ascftime routine, add the SYSV_EXT define. * For extensions from SunOS, add SUNOS_EXT. * For stuff needed to implement the P1003.2 date command, add POSIX2_DATE. * For VMS dates, add VMS_EXT. * For a an RFC822 time format, add MAILHEADER_EXT. * For ISO week years, add ISO_DATE_EXT. * For complete POSIX semantics, add POSIX_SEMANTICS. * * The code for %c, %x, and %X now follows the 1003.2 specification for * the POSIX locale. * This version ignores LOCALE information. * It also doesn't worry about multi-byte characters. * So there. * * This file is also shipped with GAWK (GNU Awk), gawk specific bits of * code are included if GAWK is defined. * * Arnold Robbins * January, February, March, 1991 * Updated March, April 1992 * Updated April, 1993 * Updated February, 1994 * Updated May, 1994 * Updated January, 1995 * Updated September, 1995 * Updated January, 1996 * * Fixes from ado@elsie.nci.nih.gov * February 1991, May 1992 * Fixes from Tor Lillqvist tml@tik.vtt.fi * May, 1993 * Further fixes from ado@elsie.nci.nih.gov * February 1994 * %z code from chip@chinacat.unicom.com * Applied September 1995 * %V code fixed (again) and %G, %g added, * January 1996 */ #include "config.h" #ifndef GAWK #include #include #include #include #endif #if defined(TM_IN_SYS_TIME) || !defined(GAWK) && !defined(_WIN32_WCE) #include #include #endif /* defaults: season to taste */ #define SYSV_EXT 1 /* stuff in System V ascftime routine */ #define SUNOS_EXT 1 /* stuff in SunOS strftime routine */ #define POSIX2_DATE 1 /* stuff in Posix 1003.2 date command */ #define VMS_EXT 1 /* include %v for VMS date format */ #define MAILHEADER_EXT 1 /* add %z for HHMM format */ #define ISO_DATE_EXT 1 /* %G and %g for year of ISO week */ #ifndef GAWK #define POSIX_SEMANTICS 1 /* call tzset() if TZ changes */ #endif #if defined(ISO_DATE_EXT) #if ! defined(POSIX2_DATE) #define POSIX2_DATE 1 #endif #endif #if defined(POSIX2_DATE) #if ! defined(SYSV_EXT) #define SYSV_EXT 1 #endif #if ! defined(SUNOS_EXT) #define SUNOS_EXT 1 #endif #endif #if defined(POSIX2_DATE) #define adddecl(stuff) stuff #else #define adddecl(stuff) #endif #undef strchr /* avoid AIX weirdness */ #ifndef __STDC__ #define const /**/ extern void tzset(); static int weeknumber(); adddecl(static int iso8601wknum();) #else extern void tzset(void); static int weeknumber(const struct tm *timeptr, int firstweekday); adddecl(static int iso8601wknum(const struct tm *timeptr);) #endif #ifdef STDC_HEADERS #include #include #else extern void *malloc(); extern void *realloc(); extern char *getenv(); extern char *strchr(); #endif #define range(low, item, hi) max(low, min(item, hi)) #ifdef __CYGWIN__ #define DLL_IMPORT __declspec(dllimport) #endif #ifdef __WIN32__ #define DLL_IMPORT __declspec(dllimport) #endif #if !defined(OS2) && !defined(MSDOS) && defined(HAVE_TZNAME) extern DLL_IMPORT char *tzname[2]; #ifdef HAVE_DAYLIGHT extern DLL_IMPORT int daylight; #endif #ifdef HAVE_VAR_TIMEZONE extern DLL_IMPORT TYPEOF_VAR_TIMEZONE timezone; #endif #ifdef HAVE_VAR_ALTZONE extern DLL_IMPORT TYPEOF_VAR_ALTZONE altzone; #endif #endif #undef min /* just in case */ /* min --- return minimum of two numbers */ #ifndef __STDC__ static inline int min(a, b) int a, b; #else static inline int min(int a, int b) #endif { return (a < b ? a : b); } #undef max /* also, just in case */ /* max --- return maximum of two numbers */ #ifndef __STDC__ static inline int max(a, b) int a, b; #else static inline int max(int a, int b) #endif { return (a > b ? a : b); } /* strftime --- produce formatted time */ #ifndef __STDC__ size_t strftime(s, maxsize, format, timeptr) char *s; size_t maxsize; const char *format; const struct tm *timeptr; #else size_t strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr) #endif { char *endp = s + maxsize; char *start = s; auto char tbuf[100]; long off; int i, w; long y; static short first = 1; #ifdef POSIX_SEMANTICS static char *savetz = NULL; static int savetzlen = 0; char *tz; #endif /* POSIX_SEMANTICS */ #ifndef HAVE_TM_ZONE #ifndef HAVE_TM_NAME struct timeval tv; struct timezone zone; #endif /* HAVE_TM_NAME */ #endif /* HAVE_TM_ZONE */ /* various tables, useful in North America */ static const char *days_a[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", }; static const char *days_l[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", }; static const char *months_a[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", }; static const char *months_l[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", }; static const char *ampm[] = { "AM", "PM", }; if (s == NULL || format == NULL || timeptr == NULL || maxsize == 0) return 0; /* quick check if we even need to bother */ if (strchr(format, '%') == NULL && strlen(format) + 1 >= maxsize) return 0; #ifndef POSIX_SEMANTICS if (first) { tzset(); first = 0; } #else /* POSIX_SEMANTICS */ tz = getenv("TZ"); if (first) { if (tz != NULL) { int tzlen = strlen(tz); savetz = (char *) malloc(tzlen + 1); if (savetz != NULL) { savetzlen = tzlen + 1; strcpy(savetz, tz); } } tzset(); first = 0; } /* if we have a saved TZ, and it is different, recapture and reset */ if (tz && savetz && (tz[0] != savetz[0] || strcmp(tz, savetz) != 0)) { i = strlen(tz) + 1; if (i > savetzlen) { savetz = (char *) realloc(savetz, i); if (savetz) { savetzlen = i; strcpy(savetz, tz); } } else strcpy(savetz, tz); tzset(); } #endif /* POSIX_SEMANTICS */ for (; *format && s < endp - 1; format++) { tbuf[0] = '\0'; if (*format != '%') { *s++ = *format; continue; } again: switch (*++format) { case '\0': *s++ = '%'; goto out; case '%': *s++ = '%'; continue; case 'a': /* abbreviated weekday name */ if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6) strcpy(tbuf, "?"); else strcpy(tbuf, days_a[timeptr->tm_wday]); break; case 'A': /* full weekday name */ if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6) strcpy(tbuf, "?"); else strcpy(tbuf, days_l[timeptr->tm_wday]); break; #ifdef SYSV_EXT case 'h': /* abbreviated month name */ #endif case 'b': /* abbreviated month name */ if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11) strcpy(tbuf, "?"); else strcpy(tbuf, months_a[timeptr->tm_mon]); break; case 'B': /* full month name */ if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11) strcpy(tbuf, "?"); else strcpy(tbuf, months_l[timeptr->tm_mon]); break; case 'c': /* appropriate date and time representation */ strftime(tbuf, sizeof tbuf, "%a %b %e %H:%M:%S %Y", timeptr); break; case 'd': /* day of the month, 01 - 31 */ i = range(1, timeptr->tm_mday, 31); sprintf(tbuf, "%02d", i); break; case 'H': /* hour, 24-hour clock, 00 - 23 */ i = range(0, timeptr->tm_hour, 23); sprintf(tbuf, "%02d", i); break; case 'I': /* hour, 12-hour clock, 01 - 12 */ i = range(0, timeptr->tm_hour, 23); if (i == 0) i = 12; else if (i > 12) i -= 12; sprintf(tbuf, "%02d", i); break; case 'j': /* day of the year, 001 - 366 */ sprintf(tbuf, "%03d", timeptr->tm_yday + 1); break; case 'm': /* month, 01 - 12 */ i = range(0, timeptr->tm_mon, 11); sprintf(tbuf, "%02d", i + 1); break; case 'M': /* minute, 00 - 59 */ i = range(0, timeptr->tm_min, 59); sprintf(tbuf, "%02d", i); break; case 'p': /* am or pm based on 12-hour clock */ i = range(0, timeptr->tm_hour, 23); if (i < 12) strcpy(tbuf, ampm[0]); else strcpy(tbuf, ampm[1]); break; case 'S': /* second, 00 - 60 */ i = range(0, timeptr->tm_sec, 60); sprintf(tbuf, "%02d", i); break; case 'U': /* week of year, Sunday is first day of week */ sprintf(tbuf, "%02d", weeknumber(timeptr, 0)); break; case 'w': /* weekday, Sunday == 0, 0 - 6 */ i = range(0, timeptr->tm_wday, 6); sprintf(tbuf, "%d", i); break; case 'W': /* week of year, Monday is first day of week */ sprintf(tbuf, "%02d", weeknumber(timeptr, 1)); break; case 'x': /* appropriate date representation */ strftime(tbuf, sizeof tbuf, "%m/%d/%y", timeptr); break; case 'X': /* appropriate time representation */ strftime(tbuf, sizeof tbuf, "%H:%M:%S", timeptr); break; case 'y': /* year without a century, 00 - 99 */ i = timeptr->tm_year % 100; sprintf(tbuf, "%02d", i); break; case 'Y': /* year with century */ sprintf(tbuf, "%ld", 1900L + timeptr->tm_year); break; #ifdef MAILHEADER_EXT /* * From: Chip Rosenthal * Date: Sun, 19 Mar 1995 00:33:29 -0600 (CST) * * Warning: the %z [code] is implemented by inspecting the * timezone name conditional compile settings, and * inferring a method to get timezone offsets. I've tried * this code on a couple of machines, but I don't doubt * there is some system out there that won't like it. * Maybe the easiest thing to do would be to bracket this * with an #ifdef that can turn it off. The %z feature * would be an admittedly obscure one that most folks can * live without, but it would be a great help to those of * us that muck around with various message processors. */ case 'z': /* time zone offset east of GMT e.g. -0600 */ #ifdef HAVE_TM_NAME /* * Systems with tm_name probably have tm_tzadj as * secs west of GMT. Convert to mins east of GMT. */ off = -timeptr->tm_tzadj / 60; #else /* !HAVE_TM_NAME */ #ifdef HAVE_TM_ZONE /* * Systems with tm_zone probably have tm_gmtoff as * secs east of GMT. Convert to mins east of GMT. */ off = timeptr->tm_gmtoff / 60; #else /* !HAVE_TM_ZONE */ #ifdef HAVE_GETTIMEOFDAY gettimeofday(&tv, &zone); off = -zone.tz_minuteswest; #else #if HAVE_VAR_TIMEZONE #if HAVE_VAR_ALTZONE off = -(daylight ? timezone : altzone) / 60; #else off = -timezone / 60; #endif #endif #endif #endif /* !HAVE_TM_ZONE */ #endif /* !HAVE_TM_NAME */ if (off < 0) { tbuf[0] = '-'; off = -off; } else { tbuf[0] = '+'; } sprintf(tbuf+1, "%02u%02u", (unsigned)off/60, (unsigned)off%60); break; #endif /* MAILHEADER_EXT */ case 'Z': /* time zone name or abbrevation */ #ifdef HAVE_TZNAME i = (daylight && timeptr->tm_isdst > 0); /* 0 or 1 */ strcpy(tbuf, tzname[i]); #else #ifdef HAVE_TM_ZONE strcpy(tbuf, timeptr->tm_zone); #else #ifdef HAVE_TM_NAME strcpy(tbuf, timeptr->tm_name); #else #ifdef HAVE_TIMEZONE gettimeofday(& tv, & zone); #ifdef TIMEZONE_VOID strcpy(tbuf, timezone()); #else strcpy(tbuf, timezone(zone.tz_minuteswest, timeptr->tm_isdst > 0)); #endif /* TIMEZONE_VOID */ #endif /* HAVE_TIMEZONE */ #endif /* HAVE_TM_NAME */ #endif /* HAVE_TM_ZONE */ #endif /* HAVE_TZNAME */ break; #ifdef SYSV_EXT case 'n': /* same as \n */ tbuf[0] = '\n'; tbuf[1] = '\0'; break; case 't': /* same as \t */ tbuf[0] = '\t'; tbuf[1] = '\0'; break; case 'D': /* date as %m/%d/%y */ strftime(tbuf, sizeof tbuf, "%m/%d/%y", timeptr); break; case 'e': /* day of month, blank padded */ sprintf(tbuf, "%2d", range(1, timeptr->tm_mday, 31)); break; case 'r': /* time as %I:%M:%S %p */ strftime(tbuf, sizeof tbuf, "%I:%M:%S %p", timeptr); break; case 'R': /* time as %H:%M */ strftime(tbuf, sizeof tbuf, "%H:%M", timeptr); break; case 'T': /* time as %H:%M:%S */ strftime(tbuf, sizeof tbuf, "%H:%M:%S", timeptr); break; #endif #ifdef SUNOS_EXT case 'k': /* hour, 24-hour clock, blank pad */ sprintf(tbuf, "%2d", range(0, timeptr->tm_hour, 23)); break; case 'l': /* hour, 12-hour clock, 1 - 12, blank pad */ i = range(0, timeptr->tm_hour, 23); if (i == 0) i = 12; else if (i > 12) i -= 12; sprintf(tbuf, "%2d", i); break; #endif #ifdef VMS_EXT case 'v': /* date as dd-bbb-YYYY */ sprintf(tbuf, "%2d-%3.3s-%4ld", range(1, timeptr->tm_mday, 31), months_a[range(0, timeptr->tm_mon, 11)], timeptr->tm_year + 1900L); for (i = 3; i < 6; i++) if (islower(tbuf[i])) tbuf[i] = toupper(tbuf[i]); break; #endif #ifdef POSIX2_DATE case 'C': sprintf(tbuf, "%02ld", (timeptr->tm_year + 1900L) / 100); break; case 'E': case 'O': /* POSIX locale extensions, ignored for now */ goto again; case 'V': /* week of year according ISO 8601 */ sprintf(tbuf, "%02d", iso8601wknum(timeptr)); break; case 'u': /* ISO 8601: Weekday as a decimal number [1 (Monday) - 7] */ sprintf(tbuf, "%d", timeptr->tm_wday == 0 ? 7 : timeptr->tm_wday); break; #endif /* POSIX2_DATE */ #ifdef ISO_DATE_EXT case 'G': case 'g': /* * Year of ISO week. * * If it's December but the ISO week number is one, * that week is in next year. * If it's January but the ISO week number is 52 or * 53, that week is in last year. * Otherwise, it's this year. */ w = iso8601wknum(timeptr); if (timeptr->tm_mon == 11 && w == 1) y = 1900L + timeptr->tm_year + 1; else if (timeptr->tm_mon == 0 && w >= 52) y = 1900L + timeptr->tm_year - 1; else y = 1900L + timeptr->tm_year; if (*format == 'G') sprintf(tbuf, "%ld", y); else sprintf(tbuf, "%02ld", y % 100); break; #endif /* ISO_DATE_EXT */ default: tbuf[0] = '%'; tbuf[1] = *format; tbuf[2] = '\0'; break; } i = strlen(tbuf); if (i) { if (s + i < endp - 1) { strcpy(s, tbuf); s += i; } else return 0; } } out: if (s < endp && *format == '\0') { *s = '\0'; return (s - start); } else return 0; } /* isleap --- is a year a leap year? */ #ifndef __STDC__ static int isleap(year) long year; #else static int isleap(long year) #endif { return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); } #ifdef POSIX2_DATE /* iso8601wknum --- compute week number according to ISO 8601 */ #ifndef __STDC__ static int iso8601wknum(timeptr) const struct tm *timeptr; #else static int iso8601wknum(const struct tm *timeptr) #endif { /* * From 1003.2: * If the week (Monday to Sunday) containing January 1 * has four or more days in the new year, then it is week 1; * otherwise it is the highest numbered week of the previous * year (52 or 53), and the next week is week 1. * * ADR: This means if Jan 1 was Monday through Thursday, * it was week 1, otherwise week 52 or 53. * * XPG4 erroneously included POSIX.2 rationale text in the * main body of the standard. Thus it requires week 53. */ int weeknum, jan1day; /* get week number, Monday as first day of the week */ weeknum = weeknumber(timeptr, 1); /* * With thanks and tip of the hatlo to tml@tik.vtt.fi * * What day of the week does January 1 fall on? * We know that * (timeptr->tm_yday - jan1.tm_yday) MOD 7 == * (timeptr->tm_wday - jan1.tm_wday) MOD 7 * and that * jan1.tm_yday == 0 * and that * timeptr->tm_wday MOD 7 == timeptr->tm_wday * from which it follows that. . . */ jan1day = timeptr->tm_wday - (timeptr->tm_yday % 7); if (jan1day < 0) jan1day += 7; /* * If Jan 1 was a Monday through Thursday, it was in * week 1. Otherwise it was last year's highest week, which is * this year's week 0. * * What does that mean? * If Jan 1 was Monday, the week number is exactly right, it can * never be 0. * If it was Tuesday through Thursday, the weeknumber is one * less than it should be, so we add one. * Otherwise, Friday, Saturday or Sunday, the week number is * OK, but if it is 0, it needs to be 52 or 53. */ switch (jan1day) { case 1: /* Monday */ break; case 2: /* Tuesday */ case 3: /* Wednesday */ case 4: /* Thursday */ weeknum++; break; case 5: /* Friday */ case 6: /* Saturday */ case 0: /* Sunday */ if (weeknum == 0) { #ifdef USE_BROKEN_XPG4 /* XPG4 (as of March 1994) says 53 unconditionally */ weeknum = 53; #else /* get week number of last week of last year */ struct tm dec31ly; /* 12/31 last year */ dec31ly = *timeptr; dec31ly.tm_year--; dec31ly.tm_mon = 11; dec31ly.tm_mday = 31; dec31ly.tm_wday = (jan1day == 0) ? 6 : jan1day - 1; dec31ly.tm_yday = 364 + isleap(dec31ly.tm_year + 1900L); weeknum = iso8601wknum(& dec31ly); #endif } break; } if (timeptr->tm_mon == 11) { /* * The last week of the year * can be in week 1 of next year. * Sigh. * * This can only happen if * M T W * 29 30 31 * 30 31 * 31 */ int wday, mday; wday = timeptr->tm_wday; mday = timeptr->tm_mday; if ( (wday == 1 && (mday >= 29 && mday <= 31)) || (wday == 2 && (mday == 30 || mday == 31)) || (wday == 3 && mday == 31)) weeknum = 1; } return weeknum; } #endif /* weeknumber --- figure how many weeks into the year */ /* With thanks and tip of the hatlo to ado@elsie.nci.nih.gov */ #ifndef __STDC__ static int weeknumber(timeptr, firstweekday) const struct tm *timeptr; int firstweekday; #else static int weeknumber(const struct tm *timeptr, int firstweekday) #endif { int wday = timeptr->tm_wday; int ret; if (firstweekday == 1) { if (wday == 0) /* sunday */ wday = 6; else wday--; } ret = ((timeptr->tm_yday + 7 - wday) / 7); if (ret < 0) ret = 0; return ret; } #if 0 /* ADR --- I'm loathe to mess with ado's code ... */ Date: Wed, 24 Apr 91 20:54:08 MDT From: Michal Jaegermann To: arnold@audiofax.com Hi Arnold, in a process of fixing of strftime() in libraries on Atari ST I grabbed some pieces of code from your own strftime. When doing that it came to mind that your weeknumber() function compiles a little bit nicer in the following form: /* * firstweekday is 0 if starting in Sunday, non-zero if in Monday */ { return (timeptr->tm_yday - timeptr->tm_wday + (firstweekday ? (timeptr->tm_wday ? 8 : 1) : 7)) / 7; } How nicer it depends on a compiler, of course, but always a tiny bit. Cheers, Michal ntomczak@vm.ucs.ualberta.ca #endif #ifdef TEST_STRFTIME /* * NAME: * tst * * SYNOPSIS: * tst * * DESCRIPTION: * "tst" is a test driver for the function "strftime". * * OPTIONS: * None. * * AUTHOR: * Karl Vogel * Control Data Systems, Inc. * vogelke@c-17igp.wpafb.af.mil * * BUGS: * None noticed yet. * * COMPILE: * cc -o tst -DTEST_STRFTIME strftime.c */ /* ADR: I reformatted this to my liking, and deleted some unneeded code. */ #ifndef NULL #include #endif #include #include #define MAXTIME 132 /* * Array of time formats. */ static char *array[] = { "(%%A) full weekday name, var length (Sunday..Saturday) %A", "(%%B) full month name, var length (January..December) %B", "(%%C) Century %C", "(%%D) date (%%m/%%d/%%y) %D", "(%%E) Locale extensions (ignored) %E", "(%%H) hour (24-hour clock, 00..23) %H", "(%%I) hour (12-hour clock, 01..12) %I", "(%%M) minute (00..59) %M", "(%%O) Locale extensions (ignored) %O", "(%%R) time, 24-hour (%%H:%%M) %R", "(%%S) second (00..60) %S", "(%%T) time, 24-hour (%%H:%%M:%%S) %T", "(%%U) week of year, Sunday as first day of week (00..53) %U", "(%%V) week of year according to ISO 8601 %V", "(%%W) week of year, Monday as first day of week (00..53) %W", "(%%X) appropriate locale time representation (%H:%M:%S) %X", "(%%Y) year with century (1970...) %Y", "(%%Z) timezone (EDT), or blank if timezone not determinable %Z", "(%%a) locale's abbreviated weekday name (Sun..Sat) %a", "(%%b) locale's abbreviated month name (Jan..Dec) %b", "(%%c) full date (Sat Nov 4 12:02:33 1989)%n%t%t%t %c", "(%%d) day of the month (01..31) %d", "(%%e) day of the month, blank-padded ( 1..31) %e", "(%%h) should be same as (%%b) %h", "(%%j) day of the year (001..366) %j", "(%%k) hour, 24-hour clock, blank pad ( 0..23) %k", "(%%l) hour, 12-hour clock, blank pad ( 0..12) %l", "(%%m) month (01..12) %m", "(%%p) locale's AM or PM based on 12-hour clock %p", "(%%r) time, 12-hour (same as %%I:%%M:%%S %%p) %r", "(%%u) ISO 8601: Weekday as decimal number [1 (Monday) - 7] %u", "(%%v) VMS date (dd-bbb-YYYY) %v", "(%%w) day of week (0..6, Sunday == 0) %w", "(%%x) appropriate locale date representation %x", "(%%y) last two digits of year (00..99) %y", "(%%z) timezone offset east of GMT as HHMM (e.g. -0500) %z", (char *) NULL }; /* main routine. */ int main(argc, argv) int argc; char **argv; { long time(); char *next; char string[MAXTIME]; int k; int length; struct tm *tm; long clock; /* Call the function. */ clock = time((long *) 0); tm = localtime(&clock); for (k = 0; next = array[k]; k++) { length = strftime(string, MAXTIME, next, tm); printf("%s\n", string); } exit(0); } #endif /* TEST_STRFTIME */ ================================================ FILE: missing/strncasecmp.c ================================================ /* public domain rewrite of strncasecmp(3) */ #include int strncasecmp(p1, p2, len) char *p1; char *p2; int len; { while (len != 0) { if (toupper(*p1) != toupper(*p2)) { return toupper(*p1) - toupper(*p2); } if (*p1 == '\0') { return 0; } len--; p1++; p2++; } return 0; } ================================================ FILE: missing/strstr.c ================================================ /* public domain rewrite of strstr(3) */ char * strstr(haystack, needle) char *haystack, *needle; { char *hend; char *a, *b; if (*needle == 0) return haystack; hend = haystack + strlen(haystack) - strlen(needle) + 1; while (haystack < hend) { if (*haystack == *needle) { a = haystack; b = needle; for (;;) { if (*b == 0) return haystack; if (*a++ != *b++) { break; } } } haystack++; } return 0; } ================================================ FILE: missing/strtod.c ================================================ /* * strtod.c -- * * Source code for the "strtod" library procedure. * * Copyright (c) 1988-1993 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies. The University of California * makes no representations about the suitability of this * software for any purpose. It is provided "as is" without * express or implied warranty. * * RCS: @(#) $Id$ */ #include "config.h" #ifdef HAVE_STDLIB_H # include #endif #include #include extern int errno; #ifndef __STDC__ # ifdef __GNUC__ # define const __const__ # else # define const # endif #endif #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #ifndef NULL #define NULL 0 #endif static int maxExponent = 511; /* Largest possible base 10 exponent. Any * exponent larger than this will already * produce underflow or overflow, so there's * no need to worry about additional digits. */ static double powersOf10[] = { /* Table giving binary powers of 10. Entry */ 10., /* is 10^2^i. Used to convert decimal */ 100., /* exponents into floating-point numbers. */ 1.0e4, 1.0e8, 1.0e16, 1.0e32, 1.0e64, 1.0e128, 1.0e256 }; /* *---------------------------------------------------------------------- * * strtod -- * * This procedure converts a floating-point number from an ASCII * decimal representation to internal double-precision format. * * Results: * The return value is the double-precision floating-point * representation of the characters in string. If endPtr isn't * NULL, then *endPtr is filled in with the address of the * next character after the last one that was part of the * floating-point number. * * Side effects: * None. * *---------------------------------------------------------------------- */ double strtod(string, endPtr) const char *string; /* A decimal ASCII floating-point number, * optionally preceded by white space. * Must have form "-I.FE-X", where I is the * integer part of the mantissa, F is the * fractional part of the mantissa, and X * is the exponent. Either of the signs * may be "+", "-", or omitted. Either I * or F may be omitted, or both. The decimal * point isn't necessary unless F is present. * The "E" may actually be an "e". E and X * may both be omitted (but not just one). */ char **endPtr; /* If non-NULL, store terminating character's * address here. */ { int sign, expSign = FALSE; double fraction, dblExp, *d; register const char *p; register int c; int exp = 0; /* Exponent read from "EX" field. */ int fracExp = 0; /* Exponent that derives from the fractional * part. Under normal circumstatnces, it is * the negative of the number of digits in F. * However, if I is very long, the last digits * of I get dropped (otherwise a long I with a * large negative exponent could cause an * unnecessary overflow on I alone). In this * case, fracExp is incremented one for each * dropped digit. */ int mantSize; /* Number of digits in mantissa. */ int decPt; /* Number of mantissa digits BEFORE decimal * point. */ const char *pExp; /* Temporarily holds location of exponent * in string. */ /* * Strip off leading blanks and check for a sign. */ p = string; while (isspace(*p)) { p += 1; } if (*p == '-') { sign = TRUE; p += 1; } else { if (*p == '+') { p += 1; } sign = FALSE; } /* * Count the number of digits in the mantissa (including the decimal * point), and also locate the decimal point. */ decPt = -1; for (mantSize = 0; ; mantSize += 1) { c = *p; if (!isdigit(c)) { if ((c != '.') || (decPt >= 0)) { break; } decPt = mantSize; } p += 1; } /* * Now suck up the digits in the mantissa. Use two integers to * collect 9 digits each (this is faster than using floating-point). * If the mantissa has more than 18 digits, ignore the extras, since * they can't affect the value anyway. */ pExp = p; p -= mantSize; if (decPt < 0) { decPt = mantSize; } else { mantSize -= 1; /* One of the digits was the point. */ } if (mantSize > 18) { fracExp = decPt - 18; mantSize = 18; } else { fracExp = decPt - mantSize; } if (mantSize == 0) { fraction = 0.0; p = string; goto done; } else { int frac1, frac2; frac1 = 0; for ( ; mantSize > 9; mantSize -= 1) { c = *p; p += 1; if (c == '.') { c = *p; p += 1; } frac1 = 10*frac1 + (c - '0'); } frac2 = 0; for (; mantSize > 0; mantSize -= 1) { c = *p; p += 1; if (c == '.') { c = *p; p += 1; } frac2 = 10*frac2 + (c - '0'); } fraction = (1.0e9 * frac1) + frac2; } /* * Skim off the exponent. */ p = pExp; if ((*p == 'E') || (*p == 'e')) { p += 1; if (*p == '-') { expSign = TRUE; p += 1; } else { if (*p == '+') { p += 1; } expSign = FALSE; } while (isdigit(*p)) { exp = exp * 10 + (*p - '0'); p += 1; } } if (expSign) { exp = fracExp - exp; } else { exp = fracExp + exp; } /* * Generate a floating-point number that represents the exponent. * Do this by processing the exponent one bit at a time to combine * many powers of 2 of 10. Then combine the exponent with the * fraction. */ if (exp < 0) { expSign = TRUE; exp = -exp; } else { expSign = FALSE; } if (exp > maxExponent) { exp = maxExponent; errno = ERANGE; } dblExp = 1.0; for (d = powersOf10; exp != 0; exp >>= 1, d += 1) { if (exp & 01) { dblExp *= *d; } } if (expSign) { fraction /= dblExp; } else { fraction *= dblExp; } done: if (endPtr != NULL) { *endPtr = (char *) p; } if (sign) { return -fraction; } return fraction; } ================================================ FILE: missing/strtol.c ================================================ /* public domain rewrite of strtol(3) */ #include long strtol(nptr, endptr, base) char *nptr; char **endptr; int base; { long result; char *p = nptr; while (isspace(*p)) { p++; } if (*p == '-') { p++; result = -strtoul(p, endptr, base); } else { if (*p == '+') p++; result = strtoul(p, endptr, base); } if (endptr != 0 && *endptr == p) { *endptr = nptr; } return result; } ================================================ FILE: missing/strtoul.c ================================================ /* * strtoul.c -- * * Source code for the "strtoul" library procedure. * * Copyright 1988 Regents of the University of California * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies. The University of California * makes no representations about the suitability of this * software for any purpose. It is provided "as is" without * express or implied warranty. */ #include /* * The table below is used to convert from ASCII digits to a * numerical equivalent. It maps from '0' through 'z' to integers * (100 for non-digit characters). */ static char cvtIn[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* '0' - '9' */ 100, 100, 100, 100, 100, 100, 100, /* punctuation */ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'A' - 'Z' */ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 100, 100, 100, 100, 100, 100, /* punctuation */ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'a' - 'z' */ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35}; /* *---------------------------------------------------------------------- * * strtoul -- * * Convert an ASCII string into an integer. * * Results: * The return value is the integer equivalent of string. If endPtr * is non-NULL, then *endPtr is filled in with the character * after the last one that was part of the integer. If string * doesn't contain a valid integer value, then zero is returned * and *endPtr is set to string. * * Side effects: * None. * *---------------------------------------------------------------------- */ unsigned long int strtoul(string, endPtr, base) char *string; /* String of ASCII digits, possibly * preceded by white space. For bases * greater than 10, either lower- or * upper-case digits may be used. */ char **endPtr; /* Where to store address of terminating * character, or NULL. */ int base; /* Base for conversion. Must be less * than 37. If 0, then the base is chosen * from the leading characters of string: * "0x" means hex, "0" means octal, anything * else means decimal. */ { register char *p; register unsigned long int result = 0; register unsigned digit; int anyDigits = 0; /* * Skip any leading blanks. */ p = string; while (isspace(*p)) { p += 1; } /* * If no base was provided, pick one from the leading characters * of the string. */ if (base == 0) { if (*p == '0') { p += 1; if (*p == 'x') { p += 1; base = 16; } else { /* * Must set anyDigits here, otherwise "0" produces a * "no digits" error. */ anyDigits = 1; base = 8; } } else base = 10; } else if (base == 16) { /* * Skip a leading "0x" from hex numbers. */ if ((p[0] == '0') && (p[1] == 'x')) { p += 2; } } /* * Sorry this code is so messy, but speed seems important. Do * different things for base 8, 10, 16, and other. */ if (base == 8) { for ( ; ; p += 1) { digit = *p - '0'; if (digit > 7) { break; } result = (result << 3) + digit; anyDigits = 1; } } else if (base == 10) { for ( ; ; p += 1) { digit = *p - '0'; if (digit > 9) { break; } result = (10*result) + digit; anyDigits = 1; } } else if (base == 16) { for ( ; ; p += 1) { digit = *p - '0'; if (digit > ('z' - '0')) { break; } digit = cvtIn[digit]; if (digit > 15) { break; } result = (result << 4) + digit; anyDigits = 1; } } else { for ( ; ; p += 1) { digit = *p - '0'; if (digit > ('z' - '0')) { break; } digit = cvtIn[digit]; if (digit >= base) { break; } result = result*base + digit; anyDigits = 1; } } /* * See if there were any digits at all. */ if (!anyDigits) { p = string; } if (endPtr != 0) { *endPtr = p; } return result; } ================================================ FILE: missing/vsnprintf.c ================================================ /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * IMPORTANT NOTE: * -------------- * From ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change * paragraph 3 above is now null and void. */ /* SNPRINTF.C * fjc 7-31-97 Modified by Mib Software to be a standalone snprintf.c module. * http://www.mibsoftware.com * Mib Software does not warrant this software any differently than the * University of California, Berkeley as described above. All warranties * are disclaimed. Use this software at your own risk. * * All code referencing FILE * functions was eliminated, since it could * never be called. All header files and necessary files are collapsed * into one file, internal functions are declared static. This should * allow inclusion into libraries with less chance of namespace collisions. * * snprintf should be the only externally visible item. * * As of 7-31-97 FLOATING_POINT is NOT provided. The code is somewhat * non-portable, so it is disabled. */ /* Define FLOATING_POINT to get floating point. */ /* #define FLOATING_POINT */ #include #define u_long unsigned long #define u_short unsigned short #define u_int unsigned int #undef __P #if defined(__STDC__) # include # if !defined(__P) # define __P(x) x # endif #else # define __P(x) () # if !defined(const) # define const # endif # include #endif #ifndef _BSD_VA_LIST_ #define _BSD_VA_LIST_ va_list #endif #ifdef __STDC__ # include #else # ifndef LONG_MAX # ifdef HAVE_LIMITS_H # include # else /* assuming 32bit(2's compliment) long */ # define LONG_MAX 2147483647 # endif # endif #endif #if defined(__hpux) && !defined(__GNUC__) && !defined(__STDC__) #define const #endif #if defined(sgi) #undef __const #define __const #endif /* People who don't like const sys_error */ #include #ifndef NULL #define NULL 0 #endif /* * NB: to fit things in six character monocase externals, the stdio * code uses the prefix `__s' for stdio objects, typically followed * by a three-character attempt at a mnemonic. */ /* stdio buffers */ struct __sbuf { unsigned char *_base; int _size; }; /* * stdio state variables. * * The following always hold: * * if (_flags&(__SLBF|__SWR)) == (__SLBF|__SWR), * _lbfsize is -_bf._size, else _lbfsize is 0 * if _flags&__SRD, _w is 0 * if _flags&__SWR, _r is 0 * * This ensures that the getc and putc macros (or inline functions) never * try to write or read from a file that is in `read' or `write' mode. * (Moreover, they can, and do, automatically switch from read mode to * write mode, and back, on "r+" and "w+" files.) * * _lbfsize is used only to make the inline line-buffered output stream * code as compact as possible. * * _ub, _up, and _ur are used when ungetc() pushes back more characters * than fit in the current _bf, or when ungetc() pushes back a character * that does not match the previous one in _bf. When this happens, * _ub._base becomes non-nil (i.e., a stream has ungetc() data iff * _ub._base!=NULL) and _up and _ur save the current values of _p and _r. * * NB: see WARNING above before changing the layout of this structure! */ typedef struct __sFILE { unsigned char *_p; /* current position in (some) buffer */ int _r; /* read space left for getc() */ int _w; /* write space left for putc() */ short _flags; /* flags, below; this FILE is free if 0 */ short _file; /* fileno, if Unix descriptor, else -1 */ struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */ int _lbfsize; /* 0 or -_bf._size, for inline putc */ } FILE; #define __SLBF 0x0001 /* line buffered */ #define __SNBF 0x0002 /* unbuffered */ #define __SRD 0x0004 /* OK to read */ #define __SWR 0x0008 /* OK to write */ /* RD and WR are never simultaneously asserted */ #define __SRW 0x0010 /* open for reading & writing */ #define __SEOF 0x0020 /* found EOF */ #define __SERR 0x0040 /* found error */ #define __SMBF 0x0080 /* _buf is from malloc */ #define __SAPP 0x0100 /* fdopen()ed in append mode */ #define __SSTR 0x0200 /* this is an sprintf/snprintf string */ #define __SOPT 0x0400 /* do fseek() optimisation */ #define __SNPT 0x0800 /* do not do fseek() optimisation */ #define __SOFF 0x1000 /* set iff _offset is in fact correct */ #define __SMOD 0x2000 /* true => fgetln modified _p text */ #define EOF (-1) #define __sfeof(p) (((p)->_flags & __SEOF) != 0) #define __sferror(p) (((p)->_flags & __SERR) != 0) #define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR|__SEOF))) #define __sfileno(p) ((p)->_file) #define feof(p) __sfeof(p) #define ferror(p) __sferror(p) #define clearerr(p) __sclearerr(p) #ifndef _ANSI_SOURCE #define fileno(p) __sfileno(p) #endif #if defined(__hpux) && !defined(__GNUC__) || defined(__DECC) #include #endif /* * I/O descriptors for __sfvwrite(). */ struct __siov { void *iov_base; size_t iov_len; }; struct __suio { struct __siov *uio_iov; int uio_iovcnt; int uio_resid; }; /* * Write some memory regions. Return zero on success, EOF on error. * * This routine is large and unsightly, but most of the ugliness due * to the three different kinds of output buffering is handled here. */ static BSD__sfvwrite(fp, uio) register FILE *fp; register struct __suio *uio; { register size_t len; register char *p; register struct __siov *iov; register int w; if ((len = uio->uio_resid) == 0) return (0); #ifndef __hpux #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif #define COPY(n) (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n)) iov = uio->uio_iov; p = iov->iov_base; len = iov->iov_len; iov++; #define GETIOV(extra_work) \ while (len == 0) { \ extra_work; \ p = iov->iov_base; \ len = iov->iov_len; \ iov++; \ } if (fp->_flags & __SNBF) { /* fjc 7-31-97 Will never happen. We are working with strings only */ } else if ((fp->_flags & __SLBF) == 0) { /* * Fully buffered: fill partially full buffer, if any, * and then flush. If there is no partial buffer, write * one _bf._size byte chunk directly (without copying). * * String output is a special case: write as many bytes * as fit, but pretend we wrote everything. This makes * snprintf() return the number of bytes needed, rather * than the number used, and avoids its write function * (so that the write function can be invalid). */ do { GETIOV(;); w = fp->_w; if (fp->_flags & __SSTR) { if (len < w) w = len; COPY(w); /* copy MIN(fp->_w,len), */ fp->_w -= w; fp->_p += w; w = len; /* but pretend copied all */ } else { /* fjc 7-31-97 Will never happen. We are working with strings only */ } p += w; len -= w; } while ((uio->uio_resid -= w) != 0); } else { /* fjc 7-31-97 Will never happen. We are working with strings only */ } return (0); err: fp->_flags |= __SERR; return (EOF); } /* * Actual printf innards. * * This code is large and complicated... */ #if !defined(__CYGWIN32__) && defined(__hpux) && !defined(__GNUC__) #include #endif /* * Flush out all the vectors defined by the given uio, * then reset it so that it can be reused. */ static int BSD__sprint(fp, uio) FILE *fp; register struct __suio *uio; { register int err; if (uio->uio_resid == 0) { uio->uio_iovcnt = 0; return (0); } err = BSD__sfvwrite(fp, uio); uio->uio_resid = 0; uio->uio_iovcnt = 0; return (err); } /* * Helper function for `fprintf to unbuffered unix file': creates a * temporary buffer. We only work on write-only files; this avoids * worries about ungetc buffers and so forth. */ static int BSD__sbprintf(fp, fmt, ap) register FILE *fp; const char *fmt; va_list ap; { /* We don't support files. */ return 0; } /* * Macros for converting digits to letters and vice versa */ #define to_digit(c) ((c) - '0') #define is_digit(c) ((unsigned)to_digit(c) <= 9) #define to_char(n) ((n) + '0') /* * Convert an unsigned long to ASCII for printf purposes, returning * a pointer to the first character of the string representation. * Octal numbers can be forced to have a leading zero; hex numbers * use the given digits. */ static char * BSD__ultoa(val, endp, base, octzero, xdigs) register u_long val; char *endp; int base, octzero; char *xdigs; { register char *cp = endp; register long sval; /* * Handle the three cases separately, in the hope of getting * better/faster code. */ switch (base) { case 10: if (val < 10) { /* many numbers are 1 digit */ *--cp = to_char(val); return (cp); } /* * On many machines, unsigned arithmetic is harder than * signed arithmetic, so we do at most one unsigned mod and * divide; this is sufficient to reduce the range of * the incoming value to where signed arithmetic works. */ if (val > LONG_MAX) { *--cp = to_char(val % 10); sval = val / 10; } else sval = val; do { *--cp = to_char(sval % 10); sval /= 10; } while (sval != 0); break; case 8: do { *--cp = to_char(val & 7); val >>= 3; } while (val); if (octzero && *cp != '0') *--cp = '0'; break; case 16: do { *--cp = xdigs[val & 15]; val >>= 4; } while (val); break; default: /* oops */ /* abort(); */ break; /* fjc 7-31-97. Don't reference abort() here */ } return (cp); } #ifdef FLOATING_POINT #include /* #include "floatio.h" */ #ifndef MAXEXP # define MAXEXP 1024 #endif #ifndef MAXFRACT # define MAXFRACT 64 #endif #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ #define DEFPREC 6 static char *cvt __P((double, int, int, char *, int *, int, int *)); static int exponent __P((char *, int, int)); #else /* no FLOATING_POINT */ #define BUF 68 #endif /* FLOATING_POINT */ /* * Flags used during conversion. */ #define ALT 0x001 /* alternate form */ #define HEXPREFIX 0x002 /* add 0x or 0X prefix */ #define LADJUST 0x004 /* left adjustment */ #define LONGDBL 0x008 /* long double; unimplemented */ #define LONGINT 0x010 /* long integer */ #ifdef _HAVE_SANE_QUAD_ #define QUADINT 0x020 /* quad integer */ #endif /* _HAVE_SANE_QUAD_ */ #define SHORTINT 0x040 /* short integer */ #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ #define FPT 0x100 /* Floating point number */ static int BSD_vfprintf(fp, fmt0, ap) FILE *fp; const char *fmt0; va_list ap; { register char *fmt; /* format string */ register int ch; /* character from fmt */ register int n; /* handy integer (short term usage) */ register char *cp; /* handy char pointer (short term usage) */ register struct __siov *iovp;/* for PRINT macro */ register int flags; /* flags as above */ int ret; /* return value accumulator */ int width; /* width from format (%8d), or 0 */ int prec; /* precision from format (%.3d), or -1 */ char sign; /* sign prefix (' ', '+', '-', or \0) */ #ifdef FLOATING_POINT char softsign; /* temporary negative sign for floats */ double _double; /* double precision arguments %[eEfgG] */ int expt; /* integer value of exponent */ int expsize; /* character count for expstr */ int ndig; /* actual number of digits returned by cvt */ char expstr[7]; /* buffer for exponent string */ #endif u_long ulval; /* integer arguments %[diouxX] */ #ifdef _HAVE_SANE_QUAD_ u_quad_t uqval; /* %q integers */ #endif /* _HAVE_SANE_QUAD_ */ int base; /* base for [diouxX] conversion */ int dprec; /* a copy of prec if [diouxX], 0 otherwise */ int fieldsz; /* field size expanded by sign, etc */ int realsz; /* field size expanded by dprec */ int size; /* size of converted field or string */ char *xdigs; /* digits for [xX] conversion */ #define NIOV 8 struct __suio uio; /* output information: summary */ struct __siov iov[NIOV];/* ... and individual io vectors */ char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ char ox[2]; /* space for 0x hex-prefix */ /* * Choose PADSIZE to trade efficiency vs. size. If larger printf * fields occur frequently, increase PADSIZE and make the initializers * below longer. */ #define PADSIZE 16 /* pad chunk size */ static char blanks[PADSIZE] = {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; static char zeroes[PADSIZE] = {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; /* * BEWARE, these `goto error' on error, and PAD uses `n'. */ #define PRINT(ptr, len) { \ iovp->iov_base = (ptr); \ iovp->iov_len = (len); \ uio.uio_resid += (len); \ iovp++; \ if (++uio.uio_iovcnt >= NIOV) { \ if (BSD__sprint(fp, &uio)) \ goto error; \ iovp = iov; \ } \ } #define PAD(howmany, with) { \ if ((n = (howmany)) > 0) { \ while (n > PADSIZE) { \ PRINT(with, PADSIZE); \ n -= PADSIZE; \ } \ PRINT(with, n); \ } \ } #define FLUSH() { \ if (uio.uio_resid && BSD__sprint(fp, &uio)) \ goto error; \ uio.uio_iovcnt = 0; \ iovp = iov; \ } /* * To extend shorts properly, we need both signed and unsigned * argument extraction methods. */ #define SARG() \ (flags&LONGINT ? va_arg(ap, long) : \ flags&SHORTINT ? (long)(short)va_arg(ap, int) : \ (long)va_arg(ap, int)) #define UARG() \ (flags&LONGINT ? va_arg(ap, u_long) : \ flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \ (u_long)va_arg(ap, u_int)) /* optimise fprintf(stderr) (and other unbuffered Unix files) */ if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && fp->_file >= 0) return (BSD__sbprintf(fp, fmt0, ap)); fmt = (char *)fmt0; uio.uio_iov = iovp = iov; uio.uio_resid = 0; uio.uio_iovcnt = 0; ret = 0; /* * Scan the format for conversions (`%' character). */ for (;;) { for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) /* void */; if ((n = fmt - cp) != 0) { PRINT(cp, n); ret += n; } if (ch == '\0') goto done; fmt++; /* skip over '%' */ flags = 0; dprec = 0; width = 0; prec = -1; sign = '\0'; rflag: ch = *fmt++; reswitch: switch (ch) { case ' ': /* * ``If the space and + flags both appear, the space * flag will be ignored.'' * -- ANSI X3J11 */ if (!sign) sign = ' '; goto rflag; case '#': flags |= ALT; goto rflag; case '*': /* * ``A negative field width argument is taken as a * - flag followed by a positive field width.'' * -- ANSI X3J11 * They don't exclude field widths read from args. */ if ((width = va_arg(ap, int)) >= 0) goto rflag; width = -width; /* FALLTHROUGH */ case '-': flags |= LADJUST; goto rflag; case '+': sign = '+'; goto rflag; case '.': if ((ch = *fmt++) == '*') { n = va_arg(ap, int); prec = n < 0 ? -1 : n; goto rflag; } n = 0; while (is_digit(ch)) { n = 10 * n + to_digit(ch); ch = *fmt++; } prec = n < 0 ? -1 : n; goto reswitch; case '0': /* * ``Note that 0 is taken as a flag, not as the * beginning of a field width.'' * -- ANSI X3J11 */ flags |= ZEROPAD; goto rflag; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n = 0; do { n = 10 * n + to_digit(ch); ch = *fmt++; } while (is_digit(ch)); width = n; goto reswitch; #ifdef FLOATING_POINT case 'L': flags |= LONGDBL; goto rflag; #endif case 'h': flags |= SHORTINT; goto rflag; case 'l': flags |= LONGINT; goto rflag; #ifdef _HAVE_SANE_QUAD_ case 'q': flags |= QUADINT; goto rflag; #endif /* _HAVE_SANE_QUAD_ */ case 'c': *(cp = buf) = va_arg(ap, int); size = 1; sign = '\0'; break; case 'D': flags |= LONGINT; /*FALLTHROUGH*/ case 'd': case 'i': #ifdef _HAVE_SANE_QUAD_ if (flags & QUADINT) { uqval = va_arg(ap, quad_t); if ((quad_t)uqval < 0) { uqval = -uqval; sign = '-'; } } else { #else /* _HAVE_SANE_QUAD_ */ { #endif /* _HAVE_SANE_QUAD_ */ ulval = SARG(); if ((long)ulval < 0) { ulval = -ulval; sign = '-'; } } base = 10; goto number; #ifdef FLOATING_POINT case 'e': /* anomalous precision */ case 'E': prec = (prec == -1) ? DEFPREC + 1 : prec + 1; /* FALLTHROUGH */ goto fp_begin; case 'f': /* always print trailing zeroes */ if (prec != 0) flags |= ALT; case 'g': case 'G': if (prec == -1) prec = DEFPREC; fp_begin: _double = va_arg(ap, double); /* do this before tricky precision changes */ if (isinf(_double)) { if (_double < 0) sign = '-'; cp = "Inf"; size = 3; break; } if (isnan(_double)) { cp = "NaN"; size = 3; break; } flags |= FPT; cp = cvt(_double, prec, flags, &softsign, &expt, ch, &ndig); if (ch == 'g' || ch == 'G') { if (expt <= -4 || expt > prec) ch = (ch == 'g') ? 'e' : 'E'; else ch = 'g'; } if (ch <= 'e') { /* 'e' or 'E' fmt */ --expt; expsize = exponent(expstr, expt, ch); size = expsize + ndig; if (ndig > 1 || flags & ALT) ++size; } else if (ch == 'f') { /* f fmt */ if (expt > 0) { size = expt; if (prec || flags & ALT) size += prec + 1; } else /* "0.X" */ size = prec + 2; } else if (expt >= ndig) { /* fixed g fmt */ size = expt; if (flags & ALT) ++size; } else size = ndig + (expt > 0 ? 1 : 2 - expt); if (softsign) sign = '-'; break; #endif /* FLOATING_POINT */ case 'n': #ifdef _HAVE_SANE_QUAD_ if (flags & QUADINT) *va_arg(ap, quad_t *) = ret; else if (flags & LONGINT) #else /* _HAVE_SANE_QUAD_ */ if (flags & LONGINT) #endif /* _HAVE_SANE_QUAD_ */ *va_arg(ap, long *) = ret; else if (flags & SHORTINT) *va_arg(ap, short *) = ret; else *va_arg(ap, int *) = ret; continue; /* no output */ case 'O': flags |= LONGINT; /*FALLTHROUGH*/ case 'o': #ifdef _HAVE_SANE_QUAD_ if (flags & QUADINT) uqval = va_arg(ap, u_quad_t); else #endif /* _HAVE_SANE_QUAD_ */ ulval = UARG(); base = 8; goto nosign; case 'p': /* * ``The argument shall be a pointer to void. The * value of the pointer is converted to a sequence * of printable characters, in an implementation- * defined manner.'' * -- ANSI X3J11 */ #ifdef _HAVE_LLP64_ uqval = (u_long)va_arg(ap, void *); flags = (flags) | QUADINT | HEXPREFIX; #else ulval = (u_long)va_arg(ap, void *); #ifdef _HAVE_SANE_QUAD_ flags = (flags & ~QUADINT) | HEXPREFIX; #else /* _HAVE_SANE_QUAD_ */ flags = (flags) | HEXPREFIX; #endif /* _HAVE_SANE_QUAD_ */ #endif base = 16; xdigs = "0123456789abcdef"; ch = 'x'; goto nosign; case 's': if ((cp = va_arg(ap, char *)) == NULL) cp = "(null)"; if (prec >= 0) { /* * can't use strlen; can only look for the * NUL in the first `prec' characters, and * strlen() will go further. */ char *p = (char *)memchr(cp, 0, prec); if (p != NULL) { size = p - cp; if (size > prec) size = prec; } else size = prec; } else size = strlen(cp); sign = '\0'; break; case 'U': flags |= LONGINT; /*FALLTHROUGH*/ case 'u': #ifdef _HAVE_SANE_QUAD_ if (flags & QUADINT) uqval = va_arg(ap, u_quad_t); else #endif /* _HAVE_SANE_QUAD_ */ ulval = UARG(); base = 10; goto nosign; case 'X': xdigs = "0123456789ABCDEF"; goto hex; case 'x': xdigs = "0123456789abcdef"; hex: #ifdef _HAVE_SANE_QUAD_ if (flags & QUADINT) uqval = va_arg(ap, u_quad_t); else #endif /* _HAVE_SANE_QUAD_ */ ulval = UARG(); base = 16; /* leading 0x/X only if non-zero */ if (flags & ALT && #ifdef _HAVE_SANE_QUAD_ (flags & QUADINT ? uqval != 0 : ulval != 0)) #else /* _HAVE_SANE_QUAD_ */ ulval != 0) #endif /* _HAVE_SANE_QUAD_ */ flags |= HEXPREFIX; /* unsigned conversions */ nosign: sign = '\0'; /* * ``... diouXx conversions ... if a precision is * specified, the 0 flag will be ignored.'' * -- ANSI X3J11 */ number: if ((dprec = prec) >= 0) flags &= ~ZEROPAD; /* * ``The result of converting a zero value with an * explicit precision of zero is no characters.'' * -- ANSI X3J11 */ cp = buf + BUF; #ifdef _HAVE_SANE_QUAD_ if (flags & QUADINT) { if (uqval != 0 || prec != 0) cp = __uqtoa(uqval, cp, base, flags & ALT, xdigs); } else { #else /* _HAVE_SANE_QUAD_ */ { #endif /* _HAVE_SANE_QUAD_ */ if (ulval != 0 || prec != 0) cp = BSD__ultoa(ulval, cp, base, flags & ALT, xdigs); } size = buf + BUF - cp; break; default: /* "%?" prints ?, unless ? is NUL */ if (ch == '\0') goto done; /* pretend it was %c with argument ch */ cp = buf; *cp = ch; size = 1; sign = '\0'; break; } /* * All reasonable formats wind up here. At this point, `cp' * points to a string which (if not flags&LADJUST) should be * padded out to `width' places. If flags&ZEROPAD, it should * first be prefixed by any sign or other prefix; otherwise, * it should be blank padded before the prefix is emitted. * After any left-hand padding and prefixing, emit zeroes * required by a decimal [diouxX] precision, then print the * string proper, then emit zeroes required by any leftover * floating precision; finally, if LADJUST, pad with blanks. * * Compute actual size, so we know how much to pad. * fieldsz excludes decimal prec; realsz includes it. */ fieldsz = size; if (sign) fieldsz++; else if (flags & HEXPREFIX) fieldsz += 2; realsz = dprec > fieldsz ? dprec : fieldsz; /* right-adjusting blank padding */ if ((flags & (LADJUST|ZEROPAD)) == 0) PAD(width - realsz, blanks); /* prefix */ if (sign) { PRINT(&sign, 1); } else if (flags & HEXPREFIX) { ox[0] = '0'; ox[1] = ch; PRINT(ox, 2); } /* right-adjusting zero padding */ if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) PAD(width - realsz, zeroes); /* leading zeroes from decimal precision */ PAD(dprec - fieldsz, zeroes); /* the string or number proper */ #ifdef FLOATING_POINT if ((flags & FPT) == 0) { PRINT(cp, size); } else { /* glue together f_p fragments */ if (ch >= 'f') { /* 'f' or 'g' */ if (_double == 0) { /* kludge for __dtoa irregularity */ if (prec == 0 || (flags & ALT) == 0) { PRINT("0", 1); } else { PRINT("0.", 2); PAD(ndig - 1, zeroes); } } else if (expt <= 0) { PRINT("0.", 2); PAD(-expt, zeroes); PRINT(cp, ndig); } else if (expt >= ndig) { PRINT(cp, ndig); PAD(expt - ndig, zeroes); if (flags & ALT) PRINT(".", 1); } else { PRINT(cp, expt); cp += expt; PRINT(".", 1); PRINT(cp, ndig-expt); } } else { /* 'e' or 'E' */ if (ndig > 1 || flags & ALT) { ox[0] = *cp++; ox[1] = '.'; PRINT(ox, 2); if (_double || flags & ALT == 0) { PRINT(cp, ndig-1); } else /* 0.[0..] */ /* __dtoa irregularity */ PAD(ndig - 1, zeroes); } else /* XeYYY */ PRINT(cp, 1); PRINT(expstr, expsize); } } #else PRINT(cp, size); #endif /* left-adjusting padding (always blank) */ if (flags & LADJUST) PAD(width - realsz, blanks); /* finally, adjust ret */ ret += width > realsz ? width : realsz; FLUSH(); /* copy out the I/O vectors */ } done: FLUSH(); error: return (__sferror(fp) ? EOF : ret); /* NOTREACHED */ } #ifdef FLOATING_POINT extern char *BSD__dtoa __P((double, int, int, int *, int *, char **)); static char * cvt(value, ndigits, flags, sign, decpt, ch, length) double value; int ndigits, flags, *decpt, ch, *length; char *sign; { int mode, dsgn; char *digits, *bp, *rve; if (ch == 'f') mode = 3; else { mode = 2; } if (value < 0) { value = -value; *sign = '-'; } else if (value == 0.0 && 1.0/value < 0) { *sign = '-'; } else { *sign = '\000'; } digits = BSD__dtoa(value, mode, ndigits, decpt, &dsgn, &rve); if (flags & ALT) { /* Print trailing zeros */ bp = digits + ndigits; if (ch == 'f') { if (*digits == '0' && value) *decpt = -ndigits + 1; bp += *decpt; } if (value == 0) /* kludge for __dtoa irregularity */ rve = bp; while (rve < bp) *rve++ = '0'; } *length = rve - digits; return (digits); } static int exponent(p0, exp, fmtch) char *p0; int exp, fmtch; { register char *p, *t; char expbuf[MAXEXP]; p = p0; *p++ = fmtch; if (exp < 0) { exp = -exp; *p++ = '-'; } else *p++ = '+'; t = expbuf + MAXEXP; if (exp > 9) { do { *--t = to_char(exp % 10); } while ((exp /= 10) > 9); *--t = to_char(exp); for (; t < expbuf + MAXEXP; *p++ = *t++); } else { *p++ = '0'; *p++ = to_char(exp); } return (p - p0); } #endif /* FLOATING_POINT */ int vsnprintf(str, n, fmt, ap) char *str; size_t n; const char *fmt; _BSD_VA_LIST_ ap; { int ret; FILE f; if ((int)n < 1) return (EOF); f._flags = __SWR | __SSTR; f._bf._base = f._p = (unsigned char *)str; f._bf._size = f._w = n - 1; ret = BSD_vfprintf(&f, fmt, ap); *f._p = 0; return (ret); } #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)snprintf.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ #if defined(__STDC__) # include #else # include #endif int #if defined(__STDC__) snprintf(char *str, size_t n, char const *fmt, ...) #else snprintf(str, n, fmt, va_alist) char *str, *fmt; size_t n; va_dcl #endif { int ret; va_list ap; FILE f; if ((int)n < 1) return (EOF); #if defined(__STDC__) va_start(ap, fmt); #else va_start(ap); #endif f._flags = __SWR | __SSTR; f._bf._base = f._p = (unsigned char *)str; f._bf._size = f._w = n - 1; ret = BSD_vfprintf(&f, fmt, ap); *f._p = 0; va_end(ap); return (ret); } ================================================ FILE: missing/x68.c ================================================ /* x68 compatibility functions -- follows Ruby's license */ #include "config.h" #if !HAVE_SELECT #include "x68/select.c" #endif #if MISSING__DTOS18 #include "x68/_dtos18.c" #endif #if MISSING_FCONVERT #include "x68/_round.c" #include "x68/fconvert.c" #endif /* missing some basic syscalls */ int link(const char *src, const char *dst) { return symlink(src, dst); } #ifndef HAVE_GETTIMEOFDAY #include #include struct timezone { int tz_minuteswest; int tz_dsttime; }; int gettimeofday(struct timeval *tv, struct timezone *tz) { tv->tv_sec = (long)time((time_t*)0); tv->tv_usec = 0; return 0; } #endif ================================================ FILE: missing.h ================================================ /************************************************ missing.h - prototype for *.c in ./missing, and for missing timeval struct $Author$ $Date$ created at: Sat May 11 23:46:03 JST 2002 ************************************************/ #ifndef MISSING_H #define MISSING_H #if defined(HAVE_SYS_TIME_H) # include #elif !defined(_WIN32) # define time_t long struct timeval { time_t tv_sec; /* seconds */ time_t tv_usec; /* microseconds */ }; #endif #if defined(HAVE_SYS_TYPES_H) # include #endif #ifndef HAVE_ACOSH extern double acosh _((double)); extern double asinh _((double)); extern double atanh _((double)); #endif #ifndef HAVE_CRYPT extern char *crypt _((const char *, const char *)); #endif #ifndef HAVE_DUP2 extern int dup2 _((int, int)); #endif #ifndef HAVE_EACCESS extern int eaccess _((const char*, int)); #endif #ifndef HAVE_FINITE extern int finite _((double)); #endif #ifndef HAVE_FLOCK extern int flock _((int, int)); #endif /* #ifndef HAVE_FREXP extern double frexp _((double, int *)); #endif */ #ifndef HAVE_HYPOT extern double hypot _((double, double)); #endif #ifndef HAVE_ERF extern double erf _((double)); extern double erfc _((double)); #endif #ifndef HAVE_ISINF # if defined(HAVE_FINITE) && defined(HAVE_ISNAN) # define isinf(x) (!finite(x) && !isnan(x)) # else extern int isinf _((double)); # endif #endif #ifndef HAVE_ISNAN extern int isnan _((double)); #endif /* #ifndef HAVE_MEMCMP extern int memcmp _((char *, char *, int)); #endif */ #ifndef HAVE_MEMMOVE extern void *memmove _((void *, void *, int)); #endif /* #ifndef HAVE_MODF extern double modf _((double, double *)); #endif */ #ifndef HAVE_STRCASECMP extern int strcasecmp _((char *, char *)); #endif #ifndef HAVE_STRNCASECMP extern int strncasecmp _((char *, char *, int)); #endif #ifndef HAVE_STRCHR extern char *strchr _((char *, int)); extern char *strrchr _((char *, int)); #endif #ifndef HAVE_STRERROR extern char *strerror _((int)); #endif #ifndef HAVE_STRFTIME extern size_t strftime _((char *, size_t, const char *, const struct tm *)); #endif #ifndef HAVE_STRSTR extern char *strstr _((char *, char *)); #endif /* #ifndef HAVE_STRTOL extern long strtol _((char *, char **, int)); #endif */ #ifndef HAVE_STRTOUL extern unsigned long strtoul _((char *, char **, int)); #endif #ifndef HAVE_VSNPRINTF # ifdef HAVE_STDARG_PROTOTYPES # include # else # include # endif extern int snprintf __((char *, size_t n, char const *, ...)); extern int vsnprintf _((char *, size_t n, char const *, va_list)); #endif #endif /* MISSING_H */ ================================================ FILE: mkconfig.rb ================================================ #!./miniruby -s # avoid warnings with -d. $install_name ||= nil $so_name ||= nil srcdir = File.dirname(__FILE__) $:.replace [srcdir+"/lib"] unless defined?(CROSS_COMPILING) $:.unshift(".") require "fileutils" mkconfig = File.basename($0) rbconfig_rb = ARGV[0] || 'rbconfig.rb' unless File.directory?(dir = File.dirname(rbconfig_rb)) FileUtils.makedirs(dir, :verbose => true) end version = RUBY_VERSION def (config = "").write(arg) concat(arg.to_s) end $stdout = config fast = {'prefix'=>TRUE, 'ruby_install_name'=>TRUE, 'INSTALL'=>TRUE, 'EXEEXT'=>TRUE} print %[ # This file was created by #{mkconfig} when ruby was built. Any # changes made to this file will be lost the next time ruby is built. module Config RUBY_VERSION == "#{version}" or raise "ruby lib version (#{version}) doesn't match executable version (\#{RUBY_VERSION})" ] v_fast = [] v_others = [] vars = {} has_version = false continued_name = nil continued_line = nil File.foreach "config.status" do |line| next if /^#/ =~ line name = nil case line when /^s([%,])@(\w+)@\1(?:\|\#_!!_\#\|)?(.*)\1/ name = $2 val = $3.gsub(/\\(?=,)/, '') when /^S\["(\w+)"\]\s*=\s*"(.*)"\s*(\\)?$/ name = $1 val = $2 if $3 continued_line = [] continued_line << val continued_name = name next end when /^"(.+)"\s*(\\)?$/ if continued_line continued_line << $1 unless $2 val = continued_line.join("") name = continued_name continued_line = nil end end when /^(?:ac_given_)?INSTALL=(.*)/ v_fast << " CONFIG[\"INSTALL\"] = " + $1 + "\n" end if name next if /^(?:ac_.*|configure_input|(?:top_)?srcdir|\w+OBJS)$/ =~ name next if /^\$\(ac_\w+\)$/ =~ val next if /^\$\{ac_\w+\}$/ =~ val next if /^\$ac_\w+$/ =~ val next if $install_name and /^RUBY_INSTALL_NAME$/ =~ name next if $so_name and /^RUBY_SO_NAME$/ =~ name next if /^(?:X|(?:MINI|RUN)RUBY$)/ =~ name if /^program_transform_name$/ =~ name and /^s(\\?.)(.*)\1$/ =~ val next if $install_name sep = %r"#{Regexp.quote($1)}" ptn = $2.sub(/\$\$/, '$').split(sep, 2) name = "ruby_install_name" val = "ruby".sub(/#{ptn[0]}/, ptn[1]) end val.gsub!(/ +(?!-)/, "=") if name == "configure_args" && /mswin32/ =~ RUBY_PLATFORM val = val.gsub(/\$(?:\$|\{?(\w+)\}?)/) {$1 ? "$(#{$1})" : $&}.dump if /^prefix$/ =~ name val = "(TOPDIR || DESTDIR + #{val})" end v = " CONFIG[\"#{name}\"] #{vars[name] ? '<< "\n"' : '='} #{val}\n" vars[name] = true if fast[name] v_fast << v else v_others << v end has_version = true if name == "MAJOR" end # break if /^CEOF/ end drive = File::PATH_SEPARATOR == ';' prefix = '/lib/ruby/' + RUBY_VERSION.sub(/\.\d+$/, '') + '/' + RUBY_PLATFORM print " TOPDIR = File.dirname(__FILE__).chomp!(#{prefix.dump})\n" print " DESTDIR = ", (drive ? "TOPDIR && TOPDIR[/\\A[a-z]:/i] || " : ""), "'' unless defined? DESTDIR\n" print " CONFIG = {}\n" print " CONFIG[\"DESTDIR\"] = DESTDIR\n" unless has_version RUBY_VERSION.scan(/(\d+)\.(\d+)\.(\d+)/) { print " CONFIG[\"MAJOR\"] = \"" + $1 + "\"\n" print " CONFIG[\"MINOR\"] = \"" + $2 + "\"\n" print " CONFIG[\"TEENY\"] = \"" + $3 + "\"\n" } patchlevel = IO.foreach(File.join(srcdir, "version.h")) {|l| m = /^\s*#\s*define\s+RUBY_PATCHLEVEL\s+(\d+)/.match(l) and break m[1] } print " CONFIG[\"PATCHLEVEL\"] = \"#{patchlevel}\"\n" end dest = drive ? /= \"(?!\$[\(\{])(?:[a-z]:)?/i : /= \"(?!\$[\(\{])/ v_others.collect! do |x| if /^\s*CONFIG\["(?!abs_|old)[a-z]+(?:_prefix|dir)"\]/ === x x.sub(dest, '= "$(DESTDIR)') else x end end if $install_name v_fast << " CONFIG[\"ruby_install_name\"] = \"" + $install_name + "\"\n" v_fast << " CONFIG[\"RUBY_INSTALL_NAME\"] = \"" + $install_name + "\"\n" end if $so_name v_fast << " CONFIG[\"RUBY_SO_NAME\"] = \"" + $so_name + "\"\n" end print(*v_fast) print(*v_others) print <flags>>FL_USHIFT)&0xff)) #define nd_set_type(n,t) \ RNODE(n)->flags=((RNODE(n)->flags&~FL_UMASK)|(((t)<flags>>NODE_LSHIFT)&NODE_LMASK)) #define nd_set_line(n,l) \ RNODE(n)->flags=((RNODE(n)->flags&~(-1< #define USE_CONTEXT #endif #include #include "st.h" #ifdef USE_CONTEXT typedef struct { ucontext_t context; volatile int status; } rb_jmpbuf_t[1]; #else typedef RUBY_JMP_BUF rb_jmpbuf_t; #endif enum rb_thread_status { THREAD_TO_KILL, THREAD_RUNNABLE, THREAD_STOPPED, THREAD_KILLED, }; typedef struct rb_thread *rb_thread_t; struct rb_thread { rb_thread_t next, prev; rb_jmpbuf_t context; #if (defined _WIN32 && !defined _WIN32_WCE) || defined __CYGWIN__ unsigned long win32_exception_list; #endif VALUE result; size_t stk_len; size_t stk_max; size_t stk_size; VALUE *stk_ptr; VALUE *stk_pos; VALUE *stk_base; VALUE *guard; VALUE *gc_stack_end; #ifdef __ia64 size_t bstr_len; size_t bstr_max; VALUE *bstr_ptr; VALUE *bstr_pos; #endif struct FRAME *frame; struct SCOPE *scope; struct RVarmap *dyna_vars; struct BLOCK *block; struct iter *iter; struct tag *tag; VALUE klass; VALUE wrapper; NODE *cref; int flags; /* misc. states (vmode/rb_trap_immediate/raised) */ NODE *node; int tracing; VALUE errinfo; VALUE last_status; VALUE last_line; VALUE last_match; int safe; enum rb_thread_status status; int wait_for; int fd; fd_set readfds; fd_set writefds; fd_set exceptfds; /* The following scratch structs are exclusively used in eval.c:rb_thread_schedule() to remove pressure from the stack. */ fd_set scratch_readfds; fd_set scratch_writefds; fd_set scratch_exceptfds; struct timeval scratch_delay_tv; int select_value; double delay; rb_thread_t join; int abort; int priority; VALUE thgroup; struct st_table *locals; VALUE thread; VALUE sandbox; }; extern VALUE (*ruby_sandbox_save)_((rb_thread_t)); extern VALUE (*ruby_sandbox_restore)_((rb_thread_t)); extern rb_thread_t rb_curr_thread; extern rb_thread_t rb_main_thread; enum { RAISED_EXCEPTION = 0x1000, RAISED_STACKOVERFLOW = 0x2000, RAISED_NOMEMORY = 0x4000, RAISED_MASK = 0xf000 }; int rb_thread_set_raised(rb_thread_t th); int rb_thread_reset_raised(rb_thread_t th); #define rb_thread_raised_set(th, f) ((th)->flags |= (f)) #define rb_thread_raised_reset(th, f) ((th)->flags &= ~(f)) #define rb_thread_raised_p(th, f) (((th)->flags & (f)) != 0) #define rb_thread_raised_clear(th) (rb_thread_raised_reset(th, RAISED_MASK)) #if defined(__cplusplus) } /* extern "C" { */ #endif #endif ================================================ FILE: numeric.c ================================================ /********************************************************************** numeric.c - $Author$ $Date$ created at: Fri Aug 13 18:33:09 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #include "ruby.h" #include "env.h" #include #include #include #if defined(__FreeBSD__) && __FreeBSD__ < 4 #include #endif #ifdef HAVE_FLOAT_H #include #endif #ifdef HAVE_IEEEFP_H #include #endif /* use IEEE 64bit values if not defined */ #ifndef FLT_RADIX #define FLT_RADIX 2 #endif #ifndef FLT_ROUNDS #define FLT_ROUNDS 1 #endif #ifndef DBL_MIN #define DBL_MIN 2.2250738585072014e-308 #endif #ifndef DBL_MAX #define DBL_MAX 1.7976931348623157e+308 #endif #ifndef DBL_MIN_EXP #define DBL_MIN_EXP (-1021) #endif #ifndef DBL_MAX_EXP #define DBL_MAX_EXP 1024 #endif #ifndef DBL_MIN_10_EXP #define DBL_MIN_10_EXP (-307) #endif #ifndef DBL_MAX_10_EXP #define DBL_MAX_10_EXP 308 #endif #ifndef DBL_DIG #define DBL_DIG 15 #endif #ifndef DBL_MANT_DIG #define DBL_MANT_DIG 53 #endif #ifndef DBL_EPSILON #define DBL_EPSILON 2.2204460492503131e-16 #endif extern double round _((double)); #ifndef HAVE_ROUND double round(x) double x; { double f; if (x > 0.0) { f = floor(x); x = f + (x - f >= 0.5); } else if (x < 0.0) { f = ceil(x); x = f - (f - x >= 0.5); } return x; } #endif static ID id_coerce, id_to_i, id_eq; VALUE rb_cNumeric; VALUE rb_cFloat; VALUE rb_cInteger; VALUE rb_cFixnum; VALUE rb_eZeroDivError; VALUE rb_eFloatDomainError; void rb_num_zerodiv() { rb_raise(rb_eZeroDivError, "divided by 0"); } /* * call-seq: * num.coerce(numeric) => array * * If aNumeric is the same type as num, returns an array * containing aNumeric and num. Otherwise, returns an * array with both aNumeric and num represented as * Float objects. This coercion mechanism is used by * Ruby to handle mixed-type numeric operations: it is intended to * find a compatible common type between the two operands of the operator. * * 1.coerce(2.5) #=> [2.5, 1.0] * 1.2.coerce(3) #=> [3.0, 1.2] * 1.coerce(2) #=> [2, 1] */ static VALUE num_coerce(x, y) VALUE x, y; { if (CLASS_OF(x) == CLASS_OF(y)) return rb_assoc_new(y, x); x = rb_Float(x); y = rb_Float(y); return rb_assoc_new(y, x); } static VALUE coerce_body(x) VALUE *x; { return rb_funcall(x[1], id_coerce, 1, x[0]); } static VALUE coerce_rescue(x) VALUE *x; { volatile VALUE v = rb_inspect(x[1]); rb_raise(rb_eTypeError, "%s can't be coerced into %s", rb_special_const_p(x[1])? RSTRING(v)->ptr: rb_obj_classname(x[1]), rb_obj_classname(x[0])); return Qnil; /* dummy */ } static int do_coerce(x, y, err) VALUE *x, *y; int err; { VALUE ary; VALUE a[2]; a[0] = *x; a[1] = *y; ary = rb_rescue(coerce_body, (VALUE)a, err?coerce_rescue:0, (VALUE)a); if (TYPE(ary) != T_ARRAY || RARRAY(ary)->len != 2) { if (err) { rb_raise(rb_eTypeError, "coerce must return [x, y]"); } return Qfalse; } *x = RARRAY(ary)->ptr[0]; *y = RARRAY(ary)->ptr[1]; return Qtrue; } VALUE rb_num_coerce_bin(x, y) VALUE x, y; { do_coerce(&x, &y, Qtrue); return rb_funcall(x, ruby_frame->orig_func, 1, y); } VALUE rb_num_coerce_cmp(x, y) VALUE x, y; { if (do_coerce(&x, &y, Qfalse)) return rb_funcall(x, ruby_frame->orig_func, 1, y); return Qnil; } VALUE rb_num_coerce_relop(x, y) VALUE x, y; { VALUE c, x0 = x, y0 = y; if (!do_coerce(&x, &y, Qfalse) || NIL_P(c = rb_funcall(x, ruby_frame->orig_func, 1, y))) { rb_cmperr(x0, y0); return Qnil; /* not reached */ } return c; } /* * Trap attempts to add methods to Numeric objects. Always * raises a TypeError */ static VALUE num_sadded(x, name) VALUE x, name; { ruby_frame = ruby_frame->prev; /* pop frame for "singleton_method_added" */ /* Numerics should be values; singleton_methods should not be added to them */ rb_raise(rb_eTypeError, "can't define singleton method \"%s\" for %s", rb_id2name(rb_to_id(name)), rb_obj_classname(x)); return Qnil; /* not reached */ } /* :nodoc: */ static VALUE num_init_copy(x, y) VALUE x, y; { /* Numerics are immutable values, which should not be copied */ rb_raise(rb_eTypeError, "can't copy %s", rb_obj_classname(x)); return Qnil; /* not reached */ } /* * call-seq: * +num => num * * Unary Plus---Returns the receiver's value. */ static VALUE num_uplus(num) VALUE num; { return num; } /* * call-seq: * -num => numeric * * Unary Minus---Returns the receiver's value, negated. */ static VALUE num_uminus(num) VALUE num; { VALUE zero; zero = INT2FIX(0); do_coerce(&zero, &num, Qtrue); return rb_funcall(zero, '-', 1, num); } /* * call-seq: * num.quo(numeric) => result * num.fdiv(numeric) => result * * Equivalent to Numeric#/, but overridden in subclasses. */ static VALUE num_quo(x, y) VALUE x, y; { return rb_funcall(x, '/', 1, y); } static VALUE num_floor(VALUE num); /* * call-seq: * num.div(numeric) => integer * * Uses / to perform division, then converts the result to * an integer. Numeric does not define the / * operator; this is left to subclasses. */ static VALUE num_div(x, y) VALUE x, y; { return num_floor(rb_funcall(x, '/', 1, y)); } /* * call-seq: * num.divmod( aNumeric ) -> anArray * * Returns an array containing the quotient and modulus obtained by * dividing num by aNumeric. If q, r = * x.divmod(y), then * * q = floor(float(x)/float(y)) * x = q*y + r * * The quotient is rounded toward -infinity, as shown in the following table: * * a | b | a.divmod(b) | a/b | a.modulo(b) | a.remainder(b) * ------+-----+---------------+---------+-------------+--------------- * 13 | 4 | 3, 1 | 3 | 1 | 1 * ------+-----+---------------+---------+-------------+--------------- * 13 | -4 | -4, -3 | -3 | -3 | 1 * ------+-----+---------------+---------+-------------+--------------- * -13 | 4 | -4, 3 | -4 | 3 | -1 * ------+-----+---------------+---------+-------------+--------------- * -13 | -4 | 3, -1 | 3 | -1 | -1 * ------+-----+---------------+---------+-------------+--------------- * 11.5 | 4 | 2, 3.5 | 2.875 | 3.5 | 3.5 * ------+-----+---------------+---------+-------------+--------------- * 11.5 | -4 | -3, -0.5 | -2.875 | -0.5 | 3.5 * ------+-----+---------------+---------+-------------+--------------- * -11.5 | 4 | -3, 0.5 | -2.875 | 0.5 | -3.5 * ------+-----+---------------+---------+-------------+--------------- * -11.5 | -4 | 2 -3.5 | 2.875 | -3.5 | -3.5 * * * Examples * 11.divmod(3) #=> [3, 2] * 11.divmod(-3) #=> [-4, -1] * 11.divmod(3.5) #=> [3, 0.5] * (-11).divmod(3.5) #=> [-4, 3.0] * (11.5).divmod(3.5) #=> [3, 1.0] */ static VALUE num_divmod(x, y) VALUE x, y; { return rb_assoc_new(num_div(x, y), rb_funcall(x, '%', 1, y)); } /* * call-seq: * num.modulo(numeric) => result * * Equivalent to * num.divmod(aNumeric)[1]. */ static VALUE num_modulo(x, y) VALUE x, y; { return rb_funcall(x, '%', 1, y); } /* * call-seq: * num.remainder(numeric) => result * * If num and numeric have different signs, returns * mod-numeric; otherwise, returns mod. In * both cases mod is the value * num.modulo(numeric). The * differences between remainder and modulo * (%) are shown in the table under Numeric#divmod. */ static VALUE num_remainder(x, y) VALUE x, y; { VALUE z = rb_funcall(x, '%', 1, y); if ((!rb_equal(z, INT2FIX(0))) && ((RTEST(rb_funcall(x, '<', 1, INT2FIX(0))) && RTEST(rb_funcall(y, '>', 1, INT2FIX(0)))) || (RTEST(rb_funcall(x, '>', 1, INT2FIX(0))) && RTEST(rb_funcall(y, '<', 1, INT2FIX(0)))))) { return rb_funcall(z, '-', 1, y); } return z; } /* * call-seq: * num.integer? -> true or false * * Returns true if num is an Integer * (including Fixnum and Bignum). */ static VALUE num_int_p(num) VALUE num; { return Qfalse; } /* * call-seq: * num.abs => num or numeric * * Returns the absolute value of num. * * 12.abs #=> 12 * (-34.56).abs #=> 34.56 * -34.56.abs #=> 34.56 */ static VALUE num_abs(num) VALUE num; { if (RTEST(rb_funcall(num, '<', 1, INT2FIX(0)))) { return rb_funcall(num, rb_intern("-@"), 0); } return num; } /* * call-seq: * num.zero? => true or false * * Returns true if num has a zero value. */ static VALUE num_zero_p(num) VALUE num; { if (rb_equal(num, INT2FIX(0))) { return Qtrue; } return Qfalse; } /* * call-seq: * num.nonzero? => num or nil * * Returns num if num is not zero, nil * otherwise. This behavior is useful when chaining comparisons: * * a = %w( z Bb bB bb BB a aA Aa AA A ) * b = a.sort {|a,b| (a.downcase <=> b.downcase).nonzero? || a <=> b } * b #=> ["A", "a", "AA", "Aa", "aA", "BB", "Bb", "bB", "bb", "z"] */ static VALUE num_nonzero_p(num) VALUE num; { if (RTEST(rb_funcall(num, rb_intern("zero?"), 0, 0))) { return Qnil; } return num; } /* * call-seq: * num.to_int => integer * * Invokes the child class's to_i method to convert * num to an integer. */ static VALUE num_to_int(num) VALUE num; { return rb_funcall(num, id_to_i, 0, 0); } /******************************************************************** * * Document-class: Float * * Float objects represent real numbers using the native * architecture's double-precision floating point representation. */ VALUE rb_float_new(d) double d; { NEWOBJ(flt, struct RFloat); OBJSETUP(flt, rb_cFloat, T_FLOAT); flt->value = d; return (VALUE)flt; } /* * call-seq: * flt.to_s => string * * Returns a string containing a representation of self. As well as a * fixed or exponential form of the number, the call may return * ``NaN'', ``Infinity'', and * ``-Infinity''. */ static VALUE flo_to_s(flt) VALUE flt; { char buf[32]; double value = RFLOAT(flt)->value; char *p, *e; if (isinf(value)) return rb_str_new2(value < 0 ? "-Infinity" : "Infinity"); else if(isnan(value)) return rb_str_new2("NaN"); sprintf(buf, "%#.15g", value); /* ensure to print decimal point */ if (!(e = strchr(buf, 'e'))) { e = buf + strlen(buf); } if (!ISDIGIT(e[-1])) { /* reformat if ended with decimal point (ex 111111111111111.) */ sprintf(buf, "%#.14e", value); if (!(e = strchr(buf, 'e'))) { e = buf + strlen(buf); } } p = e; while (p[-1]=='0' && ISDIGIT(p[-2])) p--; memmove(p, e, strlen(e)+1); return rb_str_new2(buf); } /* * MISSING: documentation */ static VALUE flo_coerce(x, y) VALUE x, y; { return rb_assoc_new(rb_Float(y), x); } /* * call-seq: * -float => float * * Returns float, negated. */ static VALUE flo_uminus(flt) VALUE flt; { return rb_float_new(-RFLOAT(flt)->value); } /* * call-seq: * float + other => float * * Returns a new float which is the sum of float * and other. */ static VALUE flo_plus(x, y) VALUE x, y; { switch (TYPE(y)) { case T_FIXNUM: return rb_float_new(RFLOAT(x)->value + (double)FIX2LONG(y)); case T_BIGNUM: return rb_float_new(RFLOAT(x)->value + rb_big2dbl(y)); case T_FLOAT: return rb_float_new(RFLOAT(x)->value + RFLOAT(y)->value); default: return rb_num_coerce_bin(x, y); } } /* * call-seq: * float + other => float * * Returns a new float which is the difference of float * and other. */ static VALUE flo_minus(x, y) VALUE x, y; { switch (TYPE(y)) { case T_FIXNUM: return rb_float_new(RFLOAT(x)->value - (double)FIX2LONG(y)); case T_BIGNUM: return rb_float_new(RFLOAT(x)->value - rb_big2dbl(y)); case T_FLOAT: return rb_float_new(RFLOAT(x)->value - RFLOAT(y)->value); default: return rb_num_coerce_bin(x, y); } } /* * call-seq: * float * other => float * * Returns a new float which is the product of float * and other. */ static VALUE flo_mul(x, y) VALUE x, y; { switch (TYPE(y)) { case T_FIXNUM: return rb_float_new(RFLOAT(x)->value * (double)FIX2LONG(y)); case T_BIGNUM: return rb_float_new(RFLOAT(x)->value * rb_big2dbl(y)); case T_FLOAT: return rb_float_new(RFLOAT(x)->value * RFLOAT(y)->value); default: return rb_num_coerce_bin(x, y); } } /* * call-seq: * float / other => float * * Returns a new float which is the result of dividing * float by other. */ static VALUE flo_div(x, y) VALUE x, y; { long f_y; double d; switch (TYPE(y)) { case T_FIXNUM: f_y = FIX2LONG(y); return rb_float_new(RFLOAT(x)->value / (double)f_y); case T_BIGNUM: d = rb_big2dbl(y); return rb_float_new(RFLOAT(x)->value / d); case T_FLOAT: return rb_float_new(RFLOAT(x)->value / RFLOAT(y)->value); default: return rb_num_coerce_bin(x, y); } } static void flodivmod(x, y, divp, modp) double x, y; double *divp, *modp; { double div, mod; #ifdef HAVE_FMOD mod = fmod(x, y); #else { double z; modf(x/y, &z); mod = x - z * y; } #endif if (isinf(x) && !isinf(y) && !isnan(y)) div = x; else div = (x - mod) / y; if (y*mod < 0) { mod += y; div -= 1.0; } if (modp) *modp = mod; if (divp) *divp = div; } /* * call-seq: * flt % other => float * flt.modulo(other) => float * * Return the modulo after division of flt by other. * * 6543.21.modulo(137) #=> 104.21 * 6543.21.modulo(137.24) #=> 92.9299999999996 */ static VALUE flo_mod(x, y) VALUE x, y; { double fy, mod; switch (TYPE(y)) { case T_FIXNUM: fy = (double)FIX2LONG(y); break; case T_BIGNUM: fy = rb_big2dbl(y); break; case T_FLOAT: fy = RFLOAT(y)->value; break; default: return rb_num_coerce_bin(x, y); } flodivmod(RFLOAT(x)->value, fy, 0, &mod); return rb_float_new(mod); } /* * call-seq: * flt.divmod(numeric) => array * * See Numeric#divmod. */ static VALUE flo_divmod(x, y) VALUE x, y; { double fy, div, mod, val; volatile VALUE a, b; switch (TYPE(y)) { case T_FIXNUM: fy = (double)FIX2LONG(y); break; case T_BIGNUM: fy = rb_big2dbl(y); break; case T_FLOAT: fy = RFLOAT(y)->value; break; default: return rb_num_coerce_bin(x, y); } flodivmod(RFLOAT(x)->value, fy, &div, &mod); if (FIXABLE(div)) { val = round(div); a = LONG2FIX(val); } else { a = rb_dbl2big(div); } b = rb_float_new(mod); return rb_assoc_new(a, b); } /* * call-seq: * * flt ** other => float * * Raises float the other power. */ static VALUE flo_pow(x, y) VALUE x, y; { switch (TYPE(y)) { case T_FIXNUM: return rb_float_new(pow(RFLOAT(x)->value, (double)FIX2LONG(y))); case T_BIGNUM: return rb_float_new(pow(RFLOAT(x)->value, rb_big2dbl(y))); case T_FLOAT: return rb_float_new(pow(RFLOAT(x)->value, RFLOAT(y)->value)); default: return rb_num_coerce_bin(x, y); } } /* * call-seq: * num.eql?(numeric) => true or false * * Returns true if num and numeric are the * same type and have equal values. * * 1 == 1.0 #=> true * 1.eql?(1.0) #=> false * (1.0).eql?(1.0) #=> true */ static VALUE num_eql(x, y) VALUE x, y; { if (TYPE(x) != TYPE(y)) return Qfalse; return rb_equal(x, y); } /* * call-seq: * num <=> other -> 0 or nil * * Returns zero if num equals other, nil * otherwise. */ static VALUE num_cmp(x, y) VALUE x, y; { if (x == y) return INT2FIX(0); return Qnil; } static VALUE num_equal(x, y) VALUE x, y; { if (x == y) return Qtrue; return rb_funcall(y, id_eq, 1, x); } /* * call-seq: * flt == obj => true or false * * Returns true only if obj has the same value * as flt. Contrast this with Float#eql?, which * requires obj to be a Float. * * 1.0 == 1 #=> true * */ static VALUE flo_eq(x, y) VALUE x, y; { volatile double a, b; switch (TYPE(y)) { case T_FIXNUM: b = FIX2LONG(y); break; case T_BIGNUM: b = rb_big2dbl(y); break; case T_FLOAT: b = RFLOAT(y)->value; if (isnan(b)) return Qfalse; break; default: return num_equal(x, y); } a = RFLOAT(x)->value; if (isnan(a)) return Qfalse; return (a == b)?Qtrue:Qfalse; } /* * call-seq: * flt.hash => integer * * Returns a hash code for this float. */ static VALUE flo_hash(num) VALUE num; { double d; char *c; int i, hash; d = RFLOAT(num)->value; if (d == 0) d = fabs(d); c = (char*)&d; for (hash=0, i=0; i b) return INT2FIX(1); if (a < b) return INT2FIX(-1); return Qnil; } /* * call-seq: * flt <=> numeric => -1, 0, +1 * * Returns -1, 0, or +1 depending on whether flt is less than, * equal to, or greater than numeric. This is the basis for the * tests in Comparable. */ static VALUE flo_cmp(x, y) VALUE x, y; { double a, b; a = RFLOAT(x)->value; switch (TYPE(y)) { case T_FIXNUM: b = (double)FIX2LONG(y); break; case T_BIGNUM: b = rb_big2dbl(y); break; case T_FLOAT: b = RFLOAT(y)->value; break; default: return rb_num_coerce_cmp(x, y); } return rb_dbl_cmp(a, b); } /* * call-seq: * flt > other => true or false * * true if flt is greater than other. */ static VALUE flo_gt(x, y) VALUE x, y; { double a, b; a = RFLOAT(x)->value; switch (TYPE(y)) { case T_FIXNUM: b = (double)FIX2LONG(y); break; case T_BIGNUM: b = rb_big2dbl(y); break; case T_FLOAT: b = RFLOAT(y)->value; if (isnan(b)) return Qfalse; break; default: return rb_num_coerce_relop(x, y); } if (isnan(a)) return Qfalse; return (a > b)?Qtrue:Qfalse; } /* * call-seq: * flt >= other => true or false * * true if flt is greater than * or equal to other. */ static VALUE flo_ge(x, y) VALUE x, y; { double a, b; a = RFLOAT(x)->value; switch (TYPE(y)) { case T_FIXNUM: b = (double)FIX2LONG(y); break; case T_BIGNUM: b = rb_big2dbl(y); break; case T_FLOAT: b = RFLOAT(y)->value; if (isnan(b)) return Qfalse; break; default: return rb_num_coerce_relop(x, y); } if (isnan(a)) return Qfalse; return (a >= b)?Qtrue:Qfalse; } /* * call-seq: * flt < other => true or false * * true if flt is less than other. */ static VALUE flo_lt(x, y) VALUE x, y; { double a, b; a = RFLOAT(x)->value; switch (TYPE(y)) { case T_FIXNUM: b = (double)FIX2LONG(y); break; case T_BIGNUM: b = rb_big2dbl(y); break; case T_FLOAT: b = RFLOAT(y)->value; if (isnan(b)) return Qfalse; break; default: return rb_num_coerce_relop(x, y); } if (isnan(a)) return Qfalse; return (a < b)?Qtrue:Qfalse; } /* * call-seq: * flt <= other => true or false * * true if flt is less than * or equal to other. */ static VALUE flo_le(x, y) VALUE x, y; { double a, b; a = RFLOAT(x)->value; switch (TYPE(y)) { case T_FIXNUM: b = (double)FIX2LONG(y); break; case T_BIGNUM: b = rb_big2dbl(y); break; case T_FLOAT: b = RFLOAT(y)->value; if (isnan(b)) return Qfalse; break; default: return rb_num_coerce_relop(x, y); } if (isnan(a)) return Qfalse; return (a <= b)?Qtrue:Qfalse; } /* * call-seq: * flt.eql?(obj) => true or false * * Returns true only if obj is a * Float with the same value as flt. Contrast this * with Float#==, which performs type conversions. * * 1.0.eql?(1) #=> false */ static VALUE flo_eql(x, y) VALUE x, y; { if (TYPE(y) == T_FLOAT) { double a = RFLOAT(x)->value; double b = RFLOAT(y)->value; if (isnan(a) || isnan(b)) return Qfalse; if (a == b) return Qtrue; } return Qfalse; } /* * call-seq: * flt.to_f => flt * * As flt is already a float, returns self. */ static VALUE flo_to_f(num) VALUE num; { return num; } /* * call-seq: * flt.abs => float * * Returns the absolute value of flt. * * (-34.56).abs #=> 34.56 * -34.56.abs #=> 34.56 * */ static VALUE flo_abs(flt) VALUE flt; { double val = fabs(RFLOAT(flt)->value); return rb_float_new(val); } /* * call-seq: * flt.zero? -> true or false * * Returns true if flt is 0.0. * */ static VALUE flo_zero_p(num) VALUE num; { if (RFLOAT(num)->value == 0.0) { return Qtrue; } return Qfalse; } /* * call-seq: * flt.nan? -> true or false * * Returns true if flt is an invalid IEEE floating * point number. * * a = -1.0 #=> -1.0 * a.nan? #=> false * a = 0.0/0.0 #=> NaN * a.nan? #=> true */ static VALUE flo_is_nan_p(num) VALUE num; { double value = RFLOAT(num)->value; return isnan(value) ? Qtrue : Qfalse; } /* * call-seq: * flt.infinite? -> nil, -1, +1 * * Returns nil, -1, or +1 depending on whether flt * is finite, -infinity, or +infinity. * * (0.0).infinite? #=> nil * (-1.0/0.0).infinite? #=> -1 * (+1.0/0.0).infinite? #=> 1 */ static VALUE flo_is_infinite_p(num) VALUE num; { double value = RFLOAT(num)->value; if (isinf(value)) { return INT2FIX( value < 0 ? -1 : 1 ); } return Qnil; } /* * call-seq: * flt.finite? -> true or false * * Returns true if flt is a valid IEEE floating * point number (it is not infinite, and nan? is * false). * */ static VALUE flo_is_finite_p(num) VALUE num; { double value = RFLOAT(num)->value; #if HAVE_FINITE if (!finite(value)) return Qfalse; #else if (isinf(value) || isnan(value)) return Qfalse; #endif return Qtrue; } /* * call-seq: * flt.floor => integer * * Returns the largest integer less than or equal to flt. * * 1.2.floor #=> 1 * 2.0.floor #=> 2 * (-1.2).floor #=> -2 * (-2.0).floor #=> -2 */ static VALUE flo_floor(num) VALUE num; { double f = floor(RFLOAT(num)->value); long val; if (!FIXABLE(f)) { return rb_dbl2big(f); } val = f; return LONG2FIX(val); } /* * call-seq: * flt.ceil => integer * * Returns the smallest Integer greater than or equal to * flt. * * 1.2.ceil #=> 2 * 2.0.ceil #=> 2 * (-1.2).ceil #=> -1 * (-2.0).ceil #=> -2 */ static VALUE flo_ceil(num) VALUE num; { double f = ceil(RFLOAT(num)->value); long val; if (!FIXABLE(f)) { return rb_dbl2big(f); } val = f; return LONG2FIX(val); } /* * call-seq: * flt.round => integer * * Rounds flt to the nearest integer. Equivalent to: * * def round * return (self+0.5).floor if self > 0.0 * return (self-0.5).ceil if self < 0.0 * return 0 * end * * 1.5.round #=> 2 * (-1.5).round #=> -2 * */ static VALUE flo_round(num) VALUE num; { double f = RFLOAT(num)->value; long val; f = round(f); if (!FIXABLE(f)) { return rb_dbl2big(f); } val = f; return LONG2FIX(val); } /* * call-seq: * flt.to_i => integer * flt.to_int => integer * flt.truncate => integer * * Returns flt truncated to an Integer. */ static VALUE flo_truncate(num) VALUE num; { double f = RFLOAT(num)->value; long val; if (f > 0.0) f = floor(f); if (f < 0.0) f = ceil(f); if (!FIXABLE(f)) { return rb_dbl2big(f); } val = f; return LONG2FIX(val); } /* * call-seq: * num.floor => integer * * Returns the largest integer less than or equal to num. * Numeric implements this by converting anInteger * to a Float and invoking Float#floor. * * 1.floor #=> 1 * (-1).floor #=> -1 */ static VALUE num_floor(num) VALUE num; { return flo_floor(rb_Float(num)); } /* * call-seq: * num.ceil => integer * * Returns the smallest Integer greater than or equal to * num. Class Numeric achieves this by converting * itself to a Float then invoking * Float#ceil. * * 1.ceil #=> 1 * 1.2.ceil #=> 2 * (-1.2).ceil #=> -1 * (-1.0).ceil #=> -1 */ static VALUE num_ceil(num) VALUE num; { return flo_ceil(rb_Float(num)); } /* * call-seq: * num.round => integer * * Rounds num to the nearest integer. Numeric * implements this by converting itself to a * Float and invoking Float#round. */ static VALUE num_round(num) VALUE num; { return flo_round(rb_Float(num)); } /* * call-seq: * num.truncate => integer * * Returns num truncated to an integer. Numeric * implements this by converting its value to a float and invoking * Float#truncate. */ static VALUE num_truncate(num) VALUE num; { return flo_truncate(rb_Float(num)); } int ruby_float_step _((VALUE from, VALUE to, VALUE step, int excl)); int ruby_float_step(from, to, step, excl) VALUE from, to, step; int excl; { if (TYPE(from) == T_FLOAT || TYPE(to) == T_FLOAT || TYPE(step) == T_FLOAT) { const double epsilon = DBL_EPSILON; double beg = NUM2DBL(from); double end = NUM2DBL(to); double unit = NUM2DBL(step); double n = (end - beg)/unit; double err = (fabs(beg) + fabs(end) + fabs(end-beg)) / fabs(unit) * epsilon; long i; if (err>0.5) err=0.5; n = floor(n + err); if (!excl) n++; for (i=0; i num * * Invokes block with the sequence of numbers starting at * num, incremented by step on each call. The loop * finishes when the value to be passed to the block is greater than * limit (if step is positive) or less than * limit (if step is negative). If all the arguments are * integers, the loop operates using an integer counter. If any of the * arguments are floating point numbers, all are converted to floats, * and the loop is executed floor(n + n*epsilon)+ 1 times, * where n = (limit - num)/step. Otherwise, the loop * starts at num, uses either the < or * > operator to compare the counter against * limit, and increments itself using the + * operator. * * 1.step(10, 2) { |i| print i, " " } * Math::E.step(Math::PI, 0.2) { |f| print f, " " } * * produces: * * 1 3 5 7 9 * 2.71828182845905 2.91828182845905 3.11828182845905 */ static VALUE num_step(argc, argv, from) int argc; VALUE *argv; VALUE from; { VALUE to, step; RETURN_ENUMERATOR(from, argc, argv); if (argc == 1) { to = argv[0]; step = INT2FIX(1); } else { if (argc == 2) { to = argv[0]; step = argv[1]; } else { rb_raise(rb_eArgError, "wrong number of arguments"); } if (rb_equal(step, INT2FIX(0))) { rb_raise(rb_eArgError, "step can't be 0"); } } if (FIXNUM_P(from) && FIXNUM_P(to) && FIXNUM_P(step)) { long i, end, diff; i = FIX2LONG(from); end = FIX2LONG(to); diff = FIX2LONG(step); if (diff > 0) { while (i <= end) { rb_yield(LONG2FIX(i)); i += diff; } } else { while (i >= end) { rb_yield(LONG2FIX(i)); i += diff; } } } else if (!ruby_float_step(from, to, step, Qfalse)) { VALUE i = from; ID cmp; if (RTEST(rb_funcall(step, '>', 1, INT2FIX(0)))) { cmp = '>'; } else { cmp = '<'; } for (;;) { if (RTEST(rb_funcall(i, cmp, 1, to))) break; rb_yield(i); i = rb_funcall(i, '+', 1, step); } } return from; } long rb_num2long(val) VALUE val; { again: if (NIL_P(val)) { rb_raise(rb_eTypeError, "no implicit conversion from nil to integer"); } if (FIXNUM_P(val)) return FIX2LONG(val); switch (TYPE(val)) { case T_FLOAT: if (RFLOAT(val)->value <= (double)LONG_MAX && RFLOAT(val)->value >= (double)LONG_MIN) { return (long)(RFLOAT(val)->value); } else { char buf[24]; char *s; sprintf(buf, "%-.10g", RFLOAT(val)->value); if ((s = strchr(buf, ' ')) != 0) *s = '\0'; rb_raise(rb_eRangeError, "float %s out of range of integer", buf); } case T_BIGNUM: return rb_big2long(val); default: val = rb_to_int(val); goto again; } } unsigned long rb_num2ulong(val) VALUE val; { if (TYPE(val) == T_BIGNUM) { return rb_big2ulong(val); } return (unsigned long)rb_num2long(val); } #if SIZEOF_INT < SIZEOF_LONG static void check_int(num) long num; { const char *s; if (num < INT_MIN) { s = "small"; } else if (num > INT_MAX) { s = "big"; } else { return; } rb_raise(rb_eRangeError, "integer %ld too %s to convert to `int'", num, s); } static void check_uint(num, sign) unsigned long num; VALUE sign; { static const unsigned long mask = ~(unsigned long)UINT_MAX; if (RTEST(sign)) { /* minus */ if ((num & mask) != mask || (num & ~mask) <= INT_MAX + 1UL) rb_raise(rb_eRangeError, "integer %ld too small to convert to `unsigned int'", num); } else { /* plus */ if ((num & mask) != 0) rb_raise(rb_eRangeError, "integer %lu too big to convert to `unsigned int'", num); } } long rb_num2int(val) VALUE val; { long num = rb_num2long(val); check_int(num); return num; } long rb_fix2int(val) VALUE val; { long num = FIXNUM_P(val)?FIX2LONG(val):rb_num2long(val); check_int(num); return num; } unsigned long rb_num2uint(val) VALUE val; { unsigned long num = rb_num2ulong(val); check_uint(num, rb_funcall(val, '<', 1, INT2FIX(0))); return num; } unsigned long rb_fix2uint(val) VALUE val; { unsigned long num; if (!FIXNUM_P(val)) { return rb_num2uint(val); } num = FIX2ULONG(val); check_uint(num, rb_funcall(val, '<', 1, INT2FIX(0))); return num; } #else long rb_num2int(val) VALUE val; { return rb_num2long(val); } long rb_fix2int(val) VALUE val; { return FIX2INT(val); } #endif VALUE rb_num2fix(val) VALUE val; { long v; if (FIXNUM_P(val)) return val; v = rb_num2long(val); if (!FIXABLE(v)) rb_raise(rb_eRangeError, "integer %ld out of range of fixnum", v); return LONG2FIX(v); } #if HAVE_LONG_LONG LONG_LONG rb_num2ll(val) VALUE val; { if (NIL_P(val)) { rb_raise(rb_eTypeError, "no implicit conversion from nil"); } if (FIXNUM_P(val)) return (LONG_LONG)FIX2LONG(val); switch (TYPE(val)) { case T_FLOAT: if (RFLOAT(val)->value <= (double)LLONG_MAX && RFLOAT(val)->value >= (double)LLONG_MIN) { return (LONG_LONG)(RFLOAT(val)->value); } else { char buf[24]; char *s; sprintf(buf, "%-.10g", RFLOAT(val)->value); if ((s = strchr(buf, ' ')) != 0) *s = '\0'; rb_raise(rb_eRangeError, "float %s out of range of long long", buf); } case T_BIGNUM: return rb_big2ll(val); case T_STRING: rb_raise(rb_eTypeError, "no implicit conversion from string"); return Qnil; /* not reached */ case T_TRUE: case T_FALSE: rb_raise(rb_eTypeError, "no implicit conversion from boolean"); return Qnil; /* not reached */ default: val = rb_to_int(val); return NUM2LL(val); } } unsigned LONG_LONG rb_num2ull(val) VALUE val; { if (TYPE(val) == T_BIGNUM) { return rb_big2ull(val); } return (unsigned LONG_LONG)rb_num2ll(val); } #endif /* HAVE_LONG_LONG */ /* * Document-class: Integer * * Integer is the basis for the two concrete classes that * hold whole numbers, Bignum and Fixnum. * */ /* * call-seq: * int.to_i => int * int.to_int => int * int.floor => int * int.ceil => int * int.round => int * int.truncate => int * * As int is already an Integer, all these * methods simply return the receiver. */ static VALUE int_to_i(num) VALUE num; { return num; } /* * call-seq: * int.integer? -> true * * Always returns true. */ static VALUE int_int_p(num) VALUE num; { return Qtrue; } /* * call-seq: * int.odd? -> true or false * * Returns true if int is an odd number. */ static VALUE int_odd_p(VALUE num) { if (rb_funcall(num, '%', 1, INT2FIX(2)) != INT2FIX(0)) { return Qtrue; } return Qfalse; } /* * call-seq: * int.even? -> true or false * * Returns true if int is an even number. */ static VALUE int_even_p(VALUE num) { if (rb_funcall(num, '%', 1, INT2FIX(2)) == INT2FIX(0)) { return Qtrue; } return Qfalse; } /* * call-seq: * int.next => integer * int.succ => integer * * Returns the Integer equal to int + 1. * * 1.next #=> 2 * (-1).next #=> 0 */ static VALUE int_succ(num) VALUE num; { if (FIXNUM_P(num)) { long i = FIX2LONG(num) + 1; return LONG2NUM(i); } return rb_funcall(num, '+', 1, INT2FIX(1)); } /* * call-seq: * int.pred => integer * * Returns the Integer equal to int - 1. * * 1.pred #=> 0 * (-1).pred #=> -2 */ static VALUE int_pred(VALUE num) { if (FIXNUM_P(num)) { long i = FIX2LONG(num) - 1; return LONG2NUM(i); } return rb_funcall(num, '-', 1, INT2FIX(1)); } /* * call-seq: * int.chr => string * * Returns a string containing the ASCII character represented by the * receiver's value. * * 65.chr #=> "A" * ?a.chr #=> "a" * 230.chr #=> "\346" */ static VALUE int_chr(num) VALUE num; { char c; long i = NUM2LONG(num); if (i < 0 || 0xff < i) rb_raise(rb_eRangeError, "%ld out of char range", i); c = i; return rb_str_new(&c, 1); } /* * call-seq: * int.ord => int * * Returns the int itself. * * ?a.ord #=> 97 * * This method is intended for compatibility to * character constant in Ruby 1.9. * For example, ?a.ord returns 97 both in 1.8 and 1.9. */ static VALUE int_ord(num) VALUE num; { return num; } /******************************************************************** * * Document-class: Fixnum * * A Fixnum holds Integer values that can be * represented in a native machine word (minus 1 bit). If any operation * on a Fixnum exceeds this range, the value is * automatically converted to a Bignum. * * Fixnum objects have immediate value. This means that * when they are assigned or passed as parameters, the actual object is * passed, rather than a reference to that object. Assignment does not * alias Fixnum objects. There is effectively only one * Fixnum object instance for any given integer value, so, * for example, you cannot add a singleton method to a * Fixnum. */ /* * call-seq: * Fixnum.induced_from(obj) => fixnum * * Convert obj to a Fixnum. Works with numeric parameters. * Also works with Symbols, but this is deprecated. */ static VALUE rb_fix_induced_from(klass, x) VALUE klass, x; { return rb_num2fix(x); } /* * call-seq: * Integer.induced_from(obj) => fixnum, bignum * * Convert obj to an Integer. */ static VALUE rb_int_induced_from(klass, x) VALUE klass, x; { switch (TYPE(x)) { case T_FIXNUM: case T_BIGNUM: return x; case T_FLOAT: return rb_funcall(x, id_to_i, 0); default: rb_raise(rb_eTypeError, "failed to convert %s into Integer", rb_obj_classname(x)); } } /* * call-seq: * Float.induced_from(obj) => float * * Convert obj to a float. */ static VALUE rb_flo_induced_from(klass, x) VALUE klass, x; { switch (TYPE(x)) { case T_FIXNUM: case T_BIGNUM: return rb_funcall(x, rb_intern("to_f"), 0); case T_FLOAT: return x; default: rb_raise(rb_eTypeError, "failed to convert %s into Float", rb_obj_classname(x)); } } /* * call-seq: * -fix => integer * * Negates fix (which might return a Bignum). */ static VALUE fix_uminus(num) VALUE num; { return LONG2NUM(-FIX2LONG(num)); } VALUE rb_fix2str(x, base) VALUE x; int base; { extern const char ruby_digitmap[]; char buf[SIZEOF_LONG*CHAR_BIT + 2], *b = buf + sizeof buf; long val = FIX2LONG(x); int neg = 0; if (base < 2 || 36 < base) { rb_raise(rb_eArgError, "illegal radix %d", base); } if (val == 0) { return rb_str_new2("0"); } if (val < 0) { val = -val; neg = 1; } *--b = '\0'; do { *--b = ruby_digitmap[(int)(val % base)]; } while (val /= base); if (neg) { *--b = '-'; } return rb_str_new2(b); } /* * call-seq: * fix.to_s( base=10 ) -> aString * * Returns a string containing the representation of fix radix * base (between 2 and 36). * * 12345.to_s #=> "12345" * 12345.to_s(2) #=> "11000000111001" * 12345.to_s(8) #=> "30071" * 12345.to_s(10) #=> "12345" * 12345.to_s(16) #=> "3039" * 12345.to_s(36) #=> "9ix" * */ static VALUE fix_to_s(argc, argv, x) int argc; VALUE *argv; VALUE x; { VALUE b; int base; rb_scan_args(argc, argv, "01", &b); if (argc == 0) base = 10; else base = NUM2INT(b); return rb_fix2str(x, base); } /* * call-seq: * fix + numeric => numeric_result * * Performs addition: the class of the resulting object depends on * the class of numeric and on the magnitude of the * result. */ static VALUE fix_plus(x, y) VALUE x, y; { if (FIXNUM_P(y)) { long a, b, c; VALUE r; a = FIX2LONG(x); b = FIX2LONG(y); c = a + b; r = LONG2NUM(c); return r; } if (TYPE(y) == T_FLOAT) { return rb_float_new((double)FIX2LONG(x) + RFLOAT(y)->value); } return rb_num_coerce_bin(x, y); } /* * call-seq: * fix - numeric => numeric_result * * Performs subtraction: the class of the resulting object depends on * the class of numeric and on the magnitude of the * result. */ static VALUE fix_minus(x, y) VALUE x, y; { if (FIXNUM_P(y)) { long a, b, c; VALUE r; a = FIX2LONG(x); b = FIX2LONG(y); c = a - b; r = LONG2NUM(c); return r; } if (TYPE(y) == T_FLOAT) { return rb_float_new((double)FIX2LONG(x) - RFLOAT(y)->value); } return rb_num_coerce_bin(x, y); } /* * call-seq: * fix * numeric => numeric_result * * Performs multiplication: the class of the resulting object depends on * the class of numeric and on the magnitude of the * result. */ static VALUE fix_mul(x, y) VALUE x, y; { if (FIXNUM_P(y)) { #ifdef __HP_cc /* avoids an optimization bug of HP aC++/ANSI C B3910B A.06.05 [Jul 25 2005] */ volatile #endif long a, b, c; VALUE r; a = FIX2LONG(x); if (a == 0) return x; b = FIX2LONG(y); c = a * b; r = LONG2FIX(c); if (FIX2LONG(r) != c || c/a != b) { r = rb_big_mul(rb_int2big(a), rb_int2big(b)); } return r; } if (TYPE(y) == T_FLOAT) { return rb_float_new((double)FIX2LONG(x) * RFLOAT(y)->value); } return rb_num_coerce_bin(x, y); } static void fixdivmod(x, y, divp, modp) long x, y; long *divp, *modp; { long div, mod; if (y == 0) rb_num_zerodiv(); if (y < 0) { if (x < 0) div = -x / -y; else div = - (x / -y); } else { if (x < 0) div = - (-x / y); else div = x / y; } mod = x - div*y; if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) { mod += y; div -= 1; } if (divp) *divp = div; if (modp) *modp = mod; } /* * call-seq: * fix.quo(numeric) => float * fix.fdiv(numeric) => float * * Returns the floating point result of dividing fix by * numeric. * * 654321.quo(13731) #=> 47.6528293642124 * 654321.quo(13731.24) #=> 47.6519964693647 * */ static VALUE fix_quo(x, y) VALUE x, y; { if (FIXNUM_P(y)) { return rb_float_new((double)FIX2LONG(x) / (double)FIX2LONG(y)); } return rb_num_coerce_bin(x, y); } /* * call-seq: * fix / numeric => numeric_result * fix.div(numeric) => numeric_result * * Performs division: the class of the resulting object depends on * the class of numeric and on the magnitude of the * result. */ static VALUE fix_div(x, y) VALUE x, y; { if (FIXNUM_P(y)) { long div; fixdivmod(FIX2LONG(x), FIX2LONG(y), &div, 0); return LONG2NUM(div); } return rb_num_coerce_bin(x, y); } /* * call-seq: * fix % other => Numeric * fix.modulo(other) => Numeric * * Returns fix modulo other. * See Numeric.divmod for more information. */ static VALUE fix_mod(x, y) VALUE x, y; { if (FIXNUM_P(y)) { long mod; fixdivmod(FIX2LONG(x), FIX2LONG(y), 0, &mod); return LONG2NUM(mod); } return rb_num_coerce_bin(x, y); } /* * call-seq: * fix.divmod(numeric) => array * * See Numeric#divmod. */ static VALUE fix_divmod(x, y) VALUE x, y; { if (FIXNUM_P(y)) { long div, mod; fixdivmod(FIX2LONG(x), FIX2LONG(y), &div, &mod); return rb_assoc_new(LONG2NUM(div), LONG2NUM(mod)); } return rb_num_coerce_bin(x, y); } static VALUE int_pow(x, y) long x; unsigned long y; { int neg = x < 0; long z = 1; if (neg) x = -x; if (y & 1) z = x; else neg = 0; y &= ~1; do { while (y % 2 == 0) { long x2 = x * x; if (x2/x != x || !POSFIXABLE(x2)) { VALUE v; bignum: v = rb_big_pow(rb_int2big(x), LONG2NUM(y)); if (z != 1) v = rb_big_mul(rb_int2big(neg ? -z : z), v); return v; } x = x2; y >>= 1; } { long xz = x * z; if (!POSFIXABLE(xz) || xz / x != z) { goto bignum; } z = xz; } } while (--y); if (neg) z = -z; return LONG2NUM(z); } /* * call-seq: * fix ** other => Numeric * * Raises fix to the other power, which may * be negative or fractional. * * 2 ** 3 #=> 8 * 2 ** -1 #=> 0.5 * 2 ** 0.5 #=> 1.4142135623731 */ static VALUE fix_pow(x, y) VALUE x, y; { static const double zero = 0.0; long a = FIX2LONG(x); if (FIXNUM_P(y)) { long b = FIX2LONG(y); if (b == 0) return INT2FIX(1); if (b == 1) return x; if (a == 0) { if (b > 0) return INT2FIX(0); return rb_float_new(1.0 / zero); } if (a == 1) return INT2FIX(1); if (a == -1) { if (b % 2 == 0) return INT2FIX(1); else return INT2FIX(-1); } if (b > 0) { return int_pow(a, b); } return rb_float_new(pow((double)a, (double)b)); } switch (TYPE(y)) { case T_BIGNUM: if (a == 0) return INT2FIX(0); if (a == 1) return INT2FIX(1); if (a == -1) { if (int_even_p(y)) return INT2FIX(1); else return INT2FIX(-1); } x = rb_int2big(FIX2LONG(x)); return rb_big_pow(x, y); case T_FLOAT: if (RFLOAT(y)->value == 0.0) return rb_float_new(1.0); if (a == 0) { return rb_float_new(RFLOAT(y)->value < 0 ? (1.0 / zero) : 0.0); } if (a == 1) return rb_float_new(1.0); return rb_float_new(pow((double)a, RFLOAT(y)->value)); default: return rb_num_coerce_bin(x, y); } } /* * call-seq: * fix == other * * Return true if fix equals other * numerically. * * 1 == 2 #=> false * 1 == 1.0 #=> true */ static VALUE fix_equal(x, y) VALUE x, y; { if (x == y) return Qtrue; if (FIXNUM_P(y)) return Qfalse; return num_equal(x, y); } /* * call-seq: * fix <=> numeric => -1, 0, +1 * * Comparison---Returns -1, 0, or +1 depending on whether fix is * less than, equal to, or greater than numeric. This is the * basis for the tests in Comparable. */ static VALUE fix_cmp(x, y) VALUE x, y; { if (x == y) return INT2FIX(0); if (FIXNUM_P(y)) { long a = FIX2LONG(x), b = FIX2LONG(y); if (a > b) return INT2FIX(1); return INT2FIX(-1); } else { return rb_num_coerce_cmp(x, y); } } /* * call-seq: * fix > other => true or false * * Returns true if the value of fix is * greater than that of other. */ static VALUE fix_gt(x, y) VALUE x, y; { if (FIXNUM_P(y)) { long a = FIX2LONG(x), b = FIX2LONG(y); if (a > b) return Qtrue; return Qfalse; } else { return rb_num_coerce_relop(x, y); } } /* * call-seq: * fix >= other => true or false * * Returns true if the value of fix is * greater than or equal to that of other. */ static VALUE fix_ge(x, y) VALUE x, y; { if (FIXNUM_P(y)) { long a = FIX2LONG(x), b = FIX2LONG(y); if (a >= b) return Qtrue; return Qfalse; } else { return rb_num_coerce_relop(x, y); } } /* * call-seq: * fix < other => true or false * * Returns true if the value of fix is * less than that of other. */ static VALUE fix_lt(x, y) VALUE x, y; { if (FIXNUM_P(y)) { long a = FIX2LONG(x), b = FIX2LONG(y); if (a < b) return Qtrue; return Qfalse; } else { return rb_num_coerce_relop(x, y); } } /* * call-seq: * fix <= other => true or false * * Returns true if the value of fix is * less thanor equal to that of other. */ static VALUE fix_le(x, y) VALUE x, y; { if (FIXNUM_P(y)) { long a = FIX2LONG(x), b = FIX2LONG(y); if (a <= b) return Qtrue; return Qfalse; } else { return rb_num_coerce_relop(x, y); } } /* * call-seq: * ~fix => integer * * One's complement: returns a number where each bit is flipped. */ static VALUE fix_rev(num) VALUE num; { long val = FIX2LONG(num); val = ~val; return LONG2NUM(val); } static VALUE fix_coerce(x) VALUE x; { while (!FIXNUM_P(x) && TYPE(x) != T_BIGNUM) { x = rb_to_int(x); } return x; } /* * call-seq: * fix & other => integer * * Bitwise AND. */ static VALUE fix_and(x, y) VALUE x, y; { long val; if (!FIXNUM_P(y = fix_coerce(y))) { return rb_big_and(y, x); } val = FIX2LONG(x) & FIX2LONG(y); return LONG2NUM(val); } /* * call-seq: * fix | other => integer * * Bitwise OR. */ static VALUE fix_or(x, y) VALUE x, y; { long val; if (!FIXNUM_P(y = fix_coerce(y))) { return rb_big_or(y, x); } val = FIX2LONG(x) | FIX2LONG(y); return LONG2NUM(val); } /* * call-seq: * fix ^ other => integer * * Bitwise EXCLUSIVE OR. */ static VALUE fix_xor(x, y) VALUE x, y; { long val; if (!FIXNUM_P(y = fix_coerce(y))) { return rb_big_xor(y, x); } val = FIX2LONG(x) ^ FIX2LONG(y); return LONG2NUM(val); } static VALUE fix_lshift _((long, unsigned long)); static VALUE fix_rshift _((long, unsigned long)); /* * call-seq: * fix << count => integer * * Shifts _fix_ left _count_ positions (right if _count_ is negative). */ static VALUE rb_fix_lshift(x, y) VALUE x, y; { long val, width; val = NUM2LONG(x); if (!FIXNUM_P(y)) return rb_big_lshift(rb_int2big(val), y); width = FIX2LONG(y); if (width < 0) return fix_rshift(val, (unsigned long)-width); return fix_lshift(val, width); } static VALUE fix_lshift(val, width) long val; unsigned long width; { if (width > (sizeof(VALUE)*CHAR_BIT-1) || ((unsigned long)val)>>(sizeof(VALUE)*CHAR_BIT-1-width) > 0) { return rb_big_lshift(rb_int2big(val), ULONG2NUM(width)); } val = val << width; return LONG2NUM(val); } /* * call-seq: * fix >> count => integer * * Shifts _fix_ right _count_ positions (left if _count_ is negative). */ static VALUE rb_fix_rshift(x, y) VALUE x, y; { long i, val; val = FIX2LONG(x); if (!FIXNUM_P(y)) return rb_big_rshift(rb_int2big(val), y); i = FIX2LONG(y); if (i == 0) return x; if (i < 0) return fix_lshift(val, (unsigned long)-i); return fix_rshift(val, i); } static VALUE fix_rshift(long val, unsigned long i) { if (i >= sizeof(long)*CHAR_BIT-1) { if (val < 0) return INT2FIX(-1); return INT2FIX(0); } val = RSHIFT(val, i); return LONG2FIX(val); } /* * call-seq: * fix[n] => 0, 1 * * Bit Reference---Returns the nth bit in the binary * representation of fix, where fix[0] is the least * significant bit. * * a = 0b11001100101010 * 30.downto(0) do |n| print a[n] end * * produces: * * 0000000000000000011001100101010 */ static VALUE fix_aref(fix, idx) VALUE fix, idx; { long val = FIX2LONG(fix); long i; if (!FIXNUM_P(idx = fix_coerce(idx))) { idx = rb_big_norm(idx); if (!FIXNUM_P(idx)) { if (!RBIGNUM(idx)->sign || val >= 0) return INT2FIX(0); return INT2FIX(1); } } i = FIX2LONG(idx); if (i < 0) return INT2FIX(0); if (sizeof(VALUE)*CHAR_BIT-1 < i) { if (val < 0) return INT2FIX(1); return INT2FIX(0); } if (val & (1L< float * * Converts fix to a Float. * */ static VALUE fix_to_f(num) VALUE num; { double val; val = (double)FIX2LONG(num); return rb_float_new(val); } /* * call-seq: * fix.abs -> aFixnum * * Returns the absolute value of fix. * * -12345.abs #=> 12345 * 12345.abs #=> 12345 * */ static VALUE fix_abs(fix) VALUE fix; { long i = FIX2LONG(fix); if (i < 0) i = -i; return LONG2NUM(i); } /* * call-seq: * fix.id2name -> string or nil * * Returns the name of the object whose symbol id is fix. If * there is no symbol in the symbol table with this value, returns * nil. id2name has nothing to do with the * Object.id method. See also Fixnum#to_sym, * String#intern, and class Symbol. * * symbol = :@inst_var #=> :@inst_var * id = symbol.to_i #=> 9818 * id.id2name #=> "@inst_var" */ static VALUE fix_id2name(fix) VALUE fix; { const char *name = rb_id2name(FIX2UINT(fix)); if (name) return rb_str_new2(name); return Qnil; } /* * call-seq: * fix.to_sym -> aSymbol * * Returns the symbol whose integer value is fix. See also * Fixnum#id2name. * * fred = :fred.to_i * fred.id2name #=> "fred" * fred.to_sym #=> :fred */ static VALUE fix_to_sym(fix) VALUE fix; { ID id = FIX2UINT(fix); if (rb_id2name(id)) { return ID2SYM(id); } return Qnil; } /* * call-seq: * fix.size -> fixnum * * Returns the number of bytes in the machine representation * of a Fixnum. * * 1.size #=> 4 * -1.size #=> 4 * 2147483647.size #=> 4 */ static VALUE fix_size(fix) VALUE fix; { return INT2FIX(sizeof(long)); } /* * call-seq: * int.upto(limit) {|i| block } => int * * Iterates block, passing in integer values from int * up to and including limit. * * 5.upto(10) { |i| print i, " " } * * produces: * * 5 6 7 8 9 10 */ static VALUE int_upto(from, to) VALUE from, to; { RETURN_ENUMERATOR(from, 1, &to); if (FIXNUM_P(from) && FIXNUM_P(to)) { long i, end; end = FIX2LONG(to); for (i = FIX2LONG(from); i <= end; i++) { rb_yield(LONG2FIX(i)); } } else { VALUE i = from, c; while (!(c = rb_funcall(i, '>', 1, to))) { rb_yield(i); i = rb_funcall(i, '+', 1, INT2FIX(1)); } if (NIL_P(c)) rb_cmperr(i, to); } return from; } /* * call-seq: * int.downto(limit) {|i| block } => int * * Iterates block, passing decreasing values from int * down to and including limit. * * 5.downto(1) { |n| print n, ".. " } * print " Liftoff!\n" * * produces: * * 5.. 4.. 3.. 2.. 1.. Liftoff! */ static VALUE int_downto(from, to) VALUE from, to; { RETURN_ENUMERATOR(from, 1, &to); if (FIXNUM_P(from) && FIXNUM_P(to)) { long i, end; end = FIX2LONG(to); for (i=FIX2LONG(from); i >= end; i--) { rb_yield(LONG2FIX(i)); } } else { VALUE i = from, c; while (!(c = rb_funcall(i, '<', 1, to))) { rb_yield(i); i = rb_funcall(i, '-', 1, INT2FIX(1)); } if (NIL_P(c)) rb_cmperr(i, to); } return from; } /* * call-seq: * int.times {|i| block } => int * * Iterates block int times, passing in values from zero to * int - 1. * * 5.times do |i| * print i, " " * end * * produces: * * 0 1 2 3 4 */ static VALUE int_dotimes(num) VALUE num; { RETURN_ENUMERATOR(num, 0, 0); if (FIXNUM_P(num)) { long i, end; end = FIX2LONG(num); for (i=0; i true or false * * Returns true if fix is zero. * */ static VALUE fix_zero_p(num) VALUE num; { if (FIX2LONG(num) == 0) { return Qtrue; } return Qfalse; } /* * call-seq: * fix.odd? -> true or false * * Returns true if fix is an odd number. */ static VALUE fix_odd_p(VALUE num) { if (num & 2) { return Qtrue; } return Qfalse; } /* * call-seq: * fix.even? -> true or false * * Returns true if fix is an even number. */ static VALUE fix_even_p(VALUE num) { if (num & 2) { return Qfalse; } return Qtrue; } void Init_Numeric() { #if defined(__FreeBSD__) && __FreeBSD__ < 4 /* allow divide by zero -- Inf */ fpsetmask(fpgetmask() & ~(FP_X_DZ|FP_X_INV|FP_X_OFL)); #elif defined(_UNICOSMP) /* Turn off floating point exceptions for divide by zero, etc. */ _set_Creg(0, 0); #elif defined(__BORLANDC__) /* Turn off floating point exceptions for overflow, etc. */ _control87(MCW_EM, MCW_EM); #endif id_coerce = rb_intern("coerce"); id_to_i = rb_intern("to_i"); id_eq = rb_intern("=="); rb_eZeroDivError = rb_define_class("ZeroDivisionError", rb_eStandardError); rb_eFloatDomainError = rb_define_class("FloatDomainError", rb_eRangeError); rb_cNumeric = rb_define_class("Numeric", rb_cObject); rb_define_method(rb_cNumeric, "singleton_method_added", num_sadded, 1); rb_include_module(rb_cNumeric, rb_mComparable); rb_define_method(rb_cNumeric, "initialize_copy", num_init_copy, 1); rb_define_method(rb_cNumeric, "coerce", num_coerce, 1); rb_define_method(rb_cNumeric, "+@", num_uplus, 0); rb_define_method(rb_cNumeric, "-@", num_uminus, 0); rb_define_method(rb_cNumeric, "<=>", num_cmp, 1); rb_define_method(rb_cNumeric, "eql?", num_eql, 1); rb_define_method(rb_cNumeric, "quo", num_quo, 1); rb_define_method(rb_cNumeric, "fdiv", num_quo, 1); rb_define_method(rb_cNumeric, "div", num_div, 1); rb_define_method(rb_cNumeric, "divmod", num_divmod, 1); rb_define_method(rb_cNumeric, "modulo", num_modulo, 1); rb_define_method(rb_cNumeric, "remainder", num_remainder, 1); rb_define_method(rb_cNumeric, "abs", num_abs, 0); rb_define_method(rb_cNumeric, "to_int", num_to_int, 0); rb_define_method(rb_cNumeric, "integer?", num_int_p, 0); rb_define_method(rb_cNumeric, "zero?", num_zero_p, 0); rb_define_method(rb_cNumeric, "nonzero?", num_nonzero_p, 0); rb_define_method(rb_cNumeric, "floor", num_floor, 0); rb_define_method(rb_cNumeric, "ceil", num_ceil, 0); rb_define_method(rb_cNumeric, "round", num_round, 0); rb_define_method(rb_cNumeric, "truncate", num_truncate, 0); rb_define_method(rb_cNumeric, "step", num_step, -1); rb_cInteger = rb_define_class("Integer", rb_cNumeric); rb_undef_alloc_func(rb_cInteger); rb_undef_method(CLASS_OF(rb_cInteger), "new"); rb_define_method(rb_cInteger, "integer?", int_int_p, 0); rb_define_method(rb_cInteger, "odd?", int_odd_p, 0); rb_define_method(rb_cInteger, "even?", int_even_p, 0); rb_define_method(rb_cInteger, "upto", int_upto, 1); rb_define_method(rb_cInteger, "downto", int_downto, 1); rb_define_method(rb_cInteger, "times", int_dotimes, 0); rb_include_module(rb_cInteger, rb_mPrecision); rb_define_method(rb_cInteger, "succ", int_succ, 0); rb_define_method(rb_cInteger, "next", int_succ, 0); rb_define_method(rb_cInteger, "pred", int_pred, 0); rb_define_method(rb_cInteger, "chr", int_chr, 0); rb_define_method(rb_cInteger, "ord", int_ord, 0); rb_define_method(rb_cInteger, "to_i", int_to_i, 0); rb_define_method(rb_cInteger, "to_int", int_to_i, 0); rb_define_method(rb_cInteger, "floor", int_to_i, 0); rb_define_method(rb_cInteger, "ceil", int_to_i, 0); rb_define_method(rb_cInteger, "round", int_to_i, 0); rb_define_method(rb_cInteger, "truncate", int_to_i, 0); rb_cFixnum = rb_define_class("Fixnum", rb_cInteger); rb_include_module(rb_cFixnum, rb_mPrecision); rb_define_singleton_method(rb_cFixnum, "induced_from", rb_fix_induced_from, 1); rb_define_singleton_method(rb_cInteger, "induced_from", rb_int_induced_from, 1); rb_define_method(rb_cFixnum, "to_s", fix_to_s, -1); rb_define_method(rb_cFixnum, "id2name", fix_id2name, 0); rb_define_method(rb_cFixnum, "to_sym", fix_to_sym, 0); rb_define_method(rb_cFixnum, "-@", fix_uminus, 0); rb_define_method(rb_cFixnum, "+", fix_plus, 1); rb_define_method(rb_cFixnum, "-", fix_minus, 1); rb_define_method(rb_cFixnum, "*", fix_mul, 1); rb_define_method(rb_cFixnum, "/", fix_div, 1); rb_define_method(rb_cFixnum, "div", fix_div, 1); rb_define_method(rb_cFixnum, "%", fix_mod, 1); rb_define_method(rb_cFixnum, "modulo", fix_mod, 1); rb_define_method(rb_cFixnum, "divmod", fix_divmod, 1); rb_define_method(rb_cFixnum, "quo", fix_quo, 1); rb_define_method(rb_cFixnum, "fdiv", fix_quo, 1); rb_define_method(rb_cFixnum, "**", fix_pow, 1); rb_define_method(rb_cFixnum, "abs", fix_abs, 0); rb_define_method(rb_cFixnum, "==", fix_equal, 1); rb_define_method(rb_cFixnum, "<=>", fix_cmp, 1); rb_define_method(rb_cFixnum, ">", fix_gt, 1); rb_define_method(rb_cFixnum, ">=", fix_ge, 1); rb_define_method(rb_cFixnum, "<", fix_lt, 1); rb_define_method(rb_cFixnum, "<=", fix_le, 1); rb_define_method(rb_cFixnum, "~", fix_rev, 0); rb_define_method(rb_cFixnum, "&", fix_and, 1); rb_define_method(rb_cFixnum, "|", fix_or, 1); rb_define_method(rb_cFixnum, "^", fix_xor, 1); rb_define_method(rb_cFixnum, "[]", fix_aref, 1); rb_define_method(rb_cFixnum, "<<", rb_fix_lshift, 1); rb_define_method(rb_cFixnum, ">>", rb_fix_rshift, 1); rb_define_method(rb_cFixnum, "to_f", fix_to_f, 0); rb_define_method(rb_cFixnum, "size", fix_size, 0); rb_define_method(rb_cFixnum, "zero?", fix_zero_p, 0); rb_define_method(rb_cFixnum, "odd?", fix_odd_p, 0); rb_define_method(rb_cFixnum, "even?", fix_even_p, 0); rb_cFloat = rb_define_class("Float", rb_cNumeric); rb_undef_alloc_func(rb_cFloat); rb_undef_method(CLASS_OF(rb_cFloat), "new"); rb_define_singleton_method(rb_cFloat, "induced_from", rb_flo_induced_from, 1); rb_include_module(rb_cFloat, rb_mPrecision); rb_define_const(rb_cFloat, "ROUNDS", INT2FIX(FLT_ROUNDS)); rb_define_const(rb_cFloat, "RADIX", INT2FIX(FLT_RADIX)); rb_define_const(rb_cFloat, "MANT_DIG", INT2FIX(DBL_MANT_DIG)); rb_define_const(rb_cFloat, "DIG", INT2FIX(DBL_DIG)); rb_define_const(rb_cFloat, "MIN_EXP", INT2FIX(DBL_MIN_EXP)); rb_define_const(rb_cFloat, "MAX_EXP", INT2FIX(DBL_MAX_EXP)); rb_define_const(rb_cFloat, "MIN_10_EXP", INT2FIX(DBL_MIN_10_EXP)); rb_define_const(rb_cFloat, "MAX_10_EXP", INT2FIX(DBL_MAX_10_EXP)); rb_define_const(rb_cFloat, "MIN", rb_float_new(DBL_MIN)); rb_define_const(rb_cFloat, "MAX", rb_float_new(DBL_MAX)); rb_define_const(rb_cFloat, "EPSILON", rb_float_new(DBL_EPSILON)); rb_define_method(rb_cFloat, "to_s", flo_to_s, 0); rb_define_method(rb_cFloat, "coerce", flo_coerce, 1); rb_define_method(rb_cFloat, "-@", flo_uminus, 0); rb_define_method(rb_cFloat, "+", flo_plus, 1); rb_define_method(rb_cFloat, "-", flo_minus, 1); rb_define_method(rb_cFloat, "*", flo_mul, 1); rb_define_method(rb_cFloat, "/", flo_div, 1); rb_define_method(rb_cFloat, "%", flo_mod, 1); rb_define_method(rb_cFloat, "modulo", flo_mod, 1); rb_define_method(rb_cFloat, "divmod", flo_divmod, 1); rb_define_method(rb_cFloat, "**", flo_pow, 1); rb_define_method(rb_cFloat, "==", flo_eq, 1); rb_define_method(rb_cFloat, "<=>", flo_cmp, 1); rb_define_method(rb_cFloat, ">", flo_gt, 1); rb_define_method(rb_cFloat, ">=", flo_ge, 1); rb_define_method(rb_cFloat, "<", flo_lt, 1); rb_define_method(rb_cFloat, "<=", flo_le, 1); rb_define_method(rb_cFloat, "eql?", flo_eql, 1); rb_define_method(rb_cFloat, "hash", flo_hash, 0); rb_define_method(rb_cFloat, "to_f", flo_to_f, 0); rb_define_method(rb_cFloat, "abs", flo_abs, 0); rb_define_method(rb_cFloat, "zero?", flo_zero_p, 0); rb_define_method(rb_cFloat, "to_i", flo_truncate, 0); rb_define_method(rb_cFloat, "to_int", flo_truncate, 0); rb_define_method(rb_cFloat, "floor", flo_floor, 0); rb_define_method(rb_cFloat, "ceil", flo_ceil, 0); rb_define_method(rb_cFloat, "round", flo_round, 0); rb_define_method(rb_cFloat, "truncate", flo_truncate, 0); rb_define_method(rb_cFloat, "nan?", flo_is_nan_p, 0); rb_define_method(rb_cFloat, "infinite?", flo_is_infinite_p, 0); rb_define_method(rb_cFloat, "finite?", flo_is_finite_p, 0); } ================================================ FILE: object.c ================================================ /********************************************************************** object.c - $Author$ $Date$ created at: Thu Jul 15 12:01:24 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto Copyright (C) 2000 Network Applied Communication Laboratory, Inc. Copyright (C) 2000 Information-technology Promotion Agency, Japan **********************************************************************/ #include "ruby.h" #include "st.h" #include "util.h" #include #include #include #include VALUE rb_mKernel; VALUE rb_cObject; VALUE rb_cModule; VALUE rb_cClass; VALUE rb_cData; VALUE rb_cNilClass; VALUE rb_cTrueClass; VALUE rb_cFalseClass; VALUE rb_cSymbol; #ifdef GC_DEBUG int longlife_moved_objs_count = 0; #endif static ID id_eq, id_eql, id_inspect, id_init_copy; /* * call-seq: * obj === other => true or false * * Case Equality---For class Object, effectively the same * as calling #==, but typically overridden by descendents * to provide meaningful semantics in case statements. */ VALUE rb_equal(obj1, obj2) VALUE obj1, obj2; { VALUE result; if (obj1 == obj2) return Qtrue; result = rb_funcall(obj1, id_eq, 1, obj2); if (RTEST(result)) return Qtrue; return Qfalse; } int rb_eql(obj1, obj2) VALUE obj1, obj2; { return RTEST(rb_funcall(obj1, id_eql, 1, obj2)); } /* * call-seq: * obj == other => true or false * obj.equal?(other) => true or false * obj.eql?(other) => true or false * * Equality---At the Object level, == returns * true only if obj and other are the * same object. Typically, this method is overridden in descendent * classes to provide class-specific meaning. * * Unlike ==, the equal? method should never be * overridden by subclasses: it is used to determine object identity * (that is, a.equal?(b) iff a is the same * object as b). * * The eql? method returns true if obj and anObject have the * same value. Used by Hash to test members for equality. * For objects of class Object, eql? is * synonymous with ==. Subclasses normally continue this * tradition, but there are exceptions. Numeric types, for * example, perform type conversion across ==, but not * across eql?, so: * * 1 == 1.0 #=> true * 1.eql? 1.0 #=> false */ static VALUE rb_obj_equal(obj1, obj2) VALUE obj1, obj2; { if (obj1 == obj2) return Qtrue; return Qfalse; } /* * call-seq: * obj.id => fixnum * * Soon-to-be deprecated version of Object#object_id. */ VALUE rb_obj_id_obsolete(obj) VALUE obj; { rb_warn("Object#id will be deprecated; use Object#object_id"); return rb_obj_id(obj); } VALUE rb_class_real(cl) VALUE cl; { while (FL_TEST(cl, FL_SINGLETON) || TYPE(cl) == T_ICLASS) { cl = RCLASS(cl)->super; } return cl; } /* * call-seq: * obj.type => class * * Deprecated synonym for Object#class. */ VALUE rb_obj_type(obj) VALUE obj; { rb_warn("Object#type is deprecated; use Object#class"); return rb_class_real(CLASS_OF(obj)); } /* * call-seq: * obj.class => class * * Returns the class of obj, now preferred over * Object#type, as an object's type in Ruby is only * loosely tied to that object's class. This method must always be * called with an explicit receiver, as class is also a * reserved word in Ruby. * * 1.class #=> Fixnum * self.class #=> Object */ VALUE rb_obj_class(obj) VALUE obj; { return rb_class_real(CLASS_OF(obj)); } static void init_copy(dest, obj) VALUE dest, obj; { if (OBJ_FROZEN(dest)) { rb_raise(rb_eTypeError, "[bug] frozen object (%s) allocated", rb_obj_classname(dest)); } RBASIC(dest)->flags &= ~(T_MASK|FL_EXIVAR); RBASIC(dest)->flags |= RBASIC(obj)->flags & (T_MASK|FL_EXIVAR|FL_TAINT); if (FL_TEST(obj, FL_EXIVAR)) { rb_copy_generic_ivar(dest, obj); } rb_gc_copy_finalizer(dest, obj); switch (TYPE(obj)) { case T_OBJECT: case T_CLASS: case T_MODULE: if (ROBJECT(dest)->iv_tbl) { st_free_table(ROBJECT(dest)->iv_tbl); ROBJECT(dest)->iv_tbl = 0; } if (ROBJECT(obj)->iv_tbl) { ROBJECT(dest)->iv_tbl = st_copy(ROBJECT(obj)->iv_tbl); } } rb_funcall(dest, id_init_copy, 1, obj); } /* * call-seq: * obj.clone -> an_object * * Produces a shallow copy of obj---the instance variables of * obj are copied, but not the objects they reference. Copies * the frozen and tainted state of obj. See also the discussion * under Object#dup. * * class Klass * attr_accessor :str * end * s1 = Klass.new #=> # * s1.str = "Hello" #=> "Hello" * s2 = s1.clone #=> # * s2.str[1,4] = "i" #=> "i" * s1.inspect #=> "#" * s2.inspect #=> "#" * * This method may have class-specific behavior. If so, that * behavior will be documented under the #+initialize_copy+ method of * the class. */ VALUE rb_obj_clone(obj) VALUE obj; { VALUE clone; if (rb_special_const_p(obj)) { rb_raise(rb_eTypeError, "can't clone %s", rb_obj_classname(obj)); } clone = rb_obj_alloc(rb_obj_class(obj)); RBASIC(clone)->klass = rb_singleton_class_clone(obj); RBASIC(clone)->flags = (RBASIC(obj)->flags | FL_TEST(clone, FL_TAINT)) & ~(FL_FREEZE|FL_FINALIZE); init_copy(clone, obj); RBASIC(clone)->flags |= RBASIC(obj)->flags & FL_FREEZE; return clone; } /* :nodoc: */ VALUE rb_obj_freeze(VALUE obj) { int i; if (!OBJ_MOVED(obj)) { obj = rb_obj_move(obj); switch (TYPE(obj)) { case T_HASH: st_foreach_map(RHASH(obj)->tbl, rb_obj_freeze, rb_obj_freeze); break; case T_ARRAY: for (i = 0; i < RARRAY(obj)->len; i++) { rb_ary_store(obj, i, rb_obj_freeze(rb_ary_entry(obj, i))); } break; } } if (!OBJ_FROZEN(obj) && TYPE(obj) != T_CLASS && TYPE(obj) != T_MODULE) { if (rb_safe_level() >= 4 && !OBJ_TAINTED(obj)) { rb_raise(rb_eSecurityError, "Insecure: can't freeze object"); } OBJ_FREEZE(obj); } return obj; } /* * call-seq: * obj.dup -> an_object * * Produces a shallow copy of obj---the instance variables of * obj are copied, but not the objects they reference. * dup copies the tainted state of obj. See also * the discussion under Object#clone. In general, * clone and dup may have different semantics * in descendent classes. While clone is used to duplicate * an object, including its internal state, dup typically * uses the class of the descendent object to create the new instance. * * This method may have class-specific behavior. If so, that * behavior will be documented under the #+initialize_copy+ method of * the class. */ VALUE rb_obj_dup(obj) VALUE obj; { VALUE dup; if (rb_special_const_p(obj)) { rb_raise(rb_eTypeError, "can't dup %s", rb_obj_classname(obj)); } dup = rb_obj_alloc(rb_obj_class(obj)); init_copy(dup, obj); return dup; } /* :nodoc: */ VALUE rb_obj_init_copy(obj, orig) VALUE obj, orig; { if (obj == orig) return obj; rb_check_frozen(obj); if (TYPE(obj) != TYPE(orig) || rb_obj_class(obj) != rb_obj_class(orig)) { rb_raise(rb_eTypeError, "initialize_copy should take same class object"); } return obj; } /* * call-seq: * obj.to_a -> anArray * * Returns an array representation of obj. For objects of class * Object and others that don't explicitly override the * method, the return value is an array containing self. * However, this latter behavior will soon be obsolete. * * self.to_a #=> -:1: warning: default `to_a' will be obsolete * "hello".to_a #=> ["hello"] * Time.new.to_a #=> [39, 54, 8, 9, 4, 2003, 3, 99, true, "CDT"] */ static VALUE rb_any_to_a(obj) VALUE obj; { rb_warn("default `to_a' will be obsolete"); return rb_ary_new3(1, obj); } /* * call-seq: * obj.to_s => string * * Returns a string representing obj. The default * to_s prints the object's class and an encoding of the * object id. As a special case, the top-level object that is the * initial execution context of Ruby programs returns ``main.'' */ VALUE rb_any_to_s(obj) VALUE obj; { const char *cname = rb_obj_classname(obj); size_t len; VALUE str; len = strlen(cname)+6+16; str = rb_str_new(0, len); /* 6:tags 16:addr */ snprintf(RSTRING(str)->ptr, len+1, "#<%s:0x%lx>", cname, obj); RSTRING(str)->len = strlen(RSTRING(str)->ptr); if (OBJ_TAINTED(obj)) OBJ_TAINT(str); return str; } VALUE rb_inspect(obj) VALUE obj; { return rb_obj_as_string(rb_funcall(obj, id_inspect, 0, 0)); } static int inspect_i(id, value, str) ID id; VALUE value; VALUE str; { VALUE str2; const char *ivname; /* need not to show internal data */ if (CLASS_OF(value) == 0) return ST_CONTINUE; if (!rb_is_instance_id(id)) return ST_CONTINUE; if (RSTRING(str)->ptr[0] == '-') { /* first element */ RSTRING(str)->ptr[0] = '#'; rb_str_cat2(str, " "); } else { rb_str_cat2(str, ", "); } ivname = rb_id2name(id); rb_str_cat2(str, ivname); rb_str_cat2(str, "="); str2 = rb_inspect(value); rb_str_append(str, str2); OBJ_INFECT(str, str2); return ST_CONTINUE; } static VALUE inspect_obj(obj, str) VALUE obj, str; { st_foreach_safe(ROBJECT(obj)->iv_tbl, inspect_i, str); rb_str_cat2(str, ">"); RSTRING(str)->ptr[0] = '#'; OBJ_INFECT(str, obj); return str; } /* * call-seq: * obj.inspect => string * * Returns a string containing a human-readable representation of * obj. If not overridden, uses the to_s method to * generate the string. * * [ 1, 2, 3..4, 'five' ].inspect #=> "[1, 2, 3..4, \"five\"]" * Time.new.inspect #=> "Wed Apr 09 08:54:39 CDT 2003" */ static VALUE rb_obj_inspect(obj) VALUE obj; { if (TYPE(obj) == T_OBJECT && ROBJECT(obj)->iv_tbl && ROBJECT(obj)->iv_tbl->num_entries > 0) { VALUE str; size_t len; const char *c = rb_obj_classname(obj); if (rb_inspecting_p(obj)) { len = strlen(c)+10+16+1; str = rb_str_new(0, len); /* 10:tags 16:addr 1:nul */ snprintf(RSTRING(str)->ptr, len, "#<%s:0x%lx ...>", c, obj); RSTRING(str)->len = strlen(RSTRING(str)->ptr); return str; } len = strlen(c)+6+16+1; str = rb_str_new(0, len); /* 6:tags 16:addr 1:nul */ snprintf(RSTRING(str)->ptr, len, "-<%s:0x%lx", c, obj); RSTRING(str)->len = strlen(RSTRING(str)->ptr); return rb_protect_inspect(inspect_obj, obj, str); } return rb_funcall(obj, rb_intern("to_s"), 0, 0); } /* * call-seq: * obj.instance_of?(class) => true or false * * Returns true if obj is an instance of the given * class. See also Object#kind_of?. */ VALUE rb_obj_is_instance_of(obj, c) VALUE obj, c; { switch (TYPE(c)) { case T_MODULE: case T_CLASS: case T_ICLASS: break; default: rb_raise(rb_eTypeError, "class or module required"); } if (rb_obj_class(obj) == c) return Qtrue; return Qfalse; } /* * call-seq: * obj.is_a?(class) => true or false * obj.kind_of?(class) => true or false * * Returns true if class is the class of * obj, or if class is one of the superclasses of * obj or modules included in obj. * * module M; end * class A * include M * end * class B < A; end * class C < B; end * b = B.new * b.instance_of? A #=> false * b.instance_of? B #=> true * b.instance_of? C #=> false * b.instance_of? M #=> false * b.kind_of? A #=> true * b.kind_of? B #=> true * b.kind_of? C #=> false * b.kind_of? M #=> true */ VALUE rb_obj_is_kind_of(obj, c) VALUE obj, c; { VALUE cl = CLASS_OF(obj); switch (TYPE(c)) { case T_MODULE: case T_CLASS: case T_ICLASS: break; default: rb_raise(rb_eTypeError, "class or module required"); } while (cl) { if (cl == c || RCLASS(cl)->m_tbl == RCLASS(c)->m_tbl) return Qtrue; cl = RCLASS(cl)->super; } return Qfalse; } /* * call-seq: * obj.tap{|x|...} => obj * * Yields x to the block, and then returns x. * The primary purpose of this method is to "tap into" a method chain, * in order to perform operations on intermediate results within the chain. * * (1..10).tap { * |x| puts "original: #{x.inspect}" * }.to_a.tap { * |x| puts "array: #{x.inspect}" * }.select {|x| x%2==0}.tap { * |x| puts "evens: #{x.inspect}" * }.map {|x| x*x}.tap { * |x| puts "squares: #{x.inspect}" * } * */ VALUE rb_obj_tap(obj) VALUE obj; { rb_yield(obj); return obj; } /* * Document-method: inherited * * call-seq: * inherited(subclass) * * Callback invoked whenever a subclass of the current class is created. * * Example: * * class Foo * def self.inherited(subclass) * puts "New subclass: #{subclass}" * end * end * * class Bar < Foo * end * * class Baz < Bar * end * * produces: * * New subclass: Bar * New subclass: Baz */ /* * Document-method: singleton_method_added * * call-seq: * singleton_method_added(symbol) * * Invoked as a callback whenever a singleton method is added to the * receiver. * * module Chatty * def Chatty.singleton_method_added(id) * puts "Adding #{id.id2name}" * end * def self.one() end * def two() end * def Chatty.three() end * end * * produces: * * Adding singleton_method_added * Adding one * Adding three * */ /* * Document-method: singleton_method_removed * * call-seq: * singleton_method_removed(symbol) * * Invoked as a callback whenever a singleton method is removed from * the receiver. * * module Chatty * def Chatty.singleton_method_removed(id) * puts "Removing #{id.id2name}" * end * def self.one() end * def two() end * def Chatty.three() end * class <produces:
      * * Removing three * Removing one */ /* * Document-method: singleton_method_undefined * * call-seq: * singleton_method_undefined(symbol) * * Invoked as a callback whenever a singleton method is undefined in * the receiver. * * module Chatty * def Chatty.singleton_method_undefined(id) * puts "Undefining #{id.id2name}" * end * def Chatty.one() end * class << self * undef_method(:one) * end * end * * produces: * * Undefining one */ /* * Document-method: included * * call-seq: * included( othermod ) * * Callback invoked whenever the receiver is included in another * module or class. This should be used in preference to * Module.append_features if your code wants to perform some * action when a module is included in another. * * module A * def A.included(mod) * puts "#{self} included in #{mod}" * end * end * module Enumerable * include A * end */ /* * Not documented */ static VALUE rb_obj_dummy() { return Qnil; } /* * call-seq: * obj.tainted? => true or false * * Returns true if the object is tainted. */ VALUE rb_obj_tainted(obj) VALUE obj; { if (OBJ_TAINTED(obj)) return Qtrue; return Qfalse; } /* * call-seq: * obj.taint -> obj * * Marks obj as tainted---if the $SAFE level is * set appropriately, many method calls which might alter the running * programs environment will refuse to accept tainted strings. */ VALUE rb_obj_taint(obj) VALUE obj; { rb_secure(4); if (!OBJ_TAINTED(obj)) { if (OBJ_FROZEN(obj)) { rb_error_frozen("object"); } OBJ_TAINT(obj); } return obj; } /* * call-seq: * obj.untaint => obj * * Removes the taint from obj. */ VALUE rb_obj_untaint(obj) VALUE obj; { rb_secure(3); if (OBJ_TAINTED(obj)) { if (OBJ_FROZEN(obj)) { rb_error_frozen("object"); } FL_UNSET(obj, FL_TAINT); } return obj; } void rb_obj_infect(obj1, obj2) VALUE obj1, obj2; { OBJ_INFECT(obj1, obj2); } /* * call-seq: * obj.freeze => obj * * Prevents further modifications to obj. A * TypeError will be raised if modification is attempted. * There is no way to unfreeze a frozen object. See also * Object#frozen?. * * a = [ "a", "b", "c" ] * a.freeze * a << "z" * * produces: * * prog.rb:3:in `<<': can't modify frozen array (TypeError) * from prog.rb:3 */ VALUE rb_obj_move(obj) VALUE obj; { if (!OBJ_MOVED(obj)) { if (TYPE(obj) == T_STRING) { obj = rb_str_move(obj); } else { /* Currently has no real effect */ OBJ_MOVE(obj); } } return obj; } /* * call-seq: * obj.frozen? => true or false * * Returns the freeze status of obj. * * a = [ "a", "b", "c" ] * a.freeze #=> ["a", "b", "c"] * a.frozen? #=> true */ static VALUE rb_obj_frozen_p(obj) VALUE obj; { if (OBJ_FROZEN(obj)) return Qtrue; return Qfalse; } /* * call-seq: * obj.moved? => true or false * * Returns the moved status of obj. * */ static VALUE rb_obj_moved_p(obj) VALUE obj; { if (OBJ_MOVED(obj)) return Qtrue; return Qfalse; } /* * call-seq: * obj.longlived? => true or false * * Returns whether obj is on the longlife heap. * */ static VALUE rb_obj_longlived_p(obj) VALUE obj; { if (OBJ_LONGLIVED(obj)) return Qtrue; return Qfalse; } /* * Document-class: NilClass * * The class of the singleton object nil. */ /* * call-seq: * nil.to_i => 0 * * Always returns zero. * * nil.to_i #=> 0 */ static VALUE nil_to_i(obj) VALUE obj; { return INT2FIX(0); } /* * call-seq: * nil.to_f => 0.0 * * Always returns zero. * * nil.to_f #=> 0.0 */ static VALUE nil_to_f(obj) VALUE obj; { return rb_float_new(0.0); } /* * call-seq: * nil.to_s => "" * * Always returns the empty string. * * nil.to_s #=> "" */ static VALUE nil_to_s(obj) VALUE obj; { return rb_str_new2(""); } /* * call-seq: * nil.to_a => [] * * Always returns an empty array. * * nil.to_a #=> [] */ static VALUE nil_to_a(obj) VALUE obj; { return rb_ary_new2(0); } /* * call-seq: * nil.inspect => "nil" * * Always returns the string "nil". */ static VALUE nil_inspect(obj) VALUE obj; { return rb_str_new2("nil"); } static VALUE main_to_s(obj) VALUE obj; { return rb_str_new2("main"); } /*********************************************************************** * Document-class: TrueClass * * The global value true is the only instance of class * TrueClass and represents a logically true value in * boolean expressions. The class provides operators allowing * true to be used in logical expressions. */ /* * call-seq: * true.to_s => "true" * * The string representation of true is "true". */ static VALUE true_to_s(obj) VALUE obj; { return rb_str_new2("true"); } /* * call-seq: * true & obj => true or false * * And---Returns false if obj is * nil or false, true otherwise. */ static VALUE true_and(obj, obj2) VALUE obj, obj2; { return RTEST(obj2)?Qtrue:Qfalse; } /* * call-seq: * true | obj => true * * Or---Returns true. As anObject is an argument to * a method call, it is always evaluated; there is no short-circuit * evaluation in this case. * * true | puts("or") * true || puts("logical or") * * produces: * * or */ static VALUE true_or(obj, obj2) VALUE obj, obj2; { return Qtrue; } /* * call-seq: * true ^ obj => !obj * * Exclusive Or---Returns true if obj is * nil or false, false * otherwise. */ static VALUE true_xor(obj, obj2) VALUE obj, obj2; { return RTEST(obj2)?Qfalse:Qtrue; } /* * Document-class: FalseClass * * The global value false is the only instance of class * FalseClass and represents a logically false value in * boolean expressions. The class provides operators allowing * false to participate correctly in logical expressions. * */ /* * call-seq: * false.to_s => "false" * * 'nuf said... */ static VALUE false_to_s(obj) VALUE obj; { return rb_str_new2("false"); } /* * call-seq: * false & obj => false * nil & obj => false * * And---Returns false. obj is always * evaluated as it is the argument to a method call---there is no * short-circuit evaluation in this case. */ static VALUE false_and(obj, obj2) VALUE obj, obj2; { return Qfalse; } /* * call-seq: * false | obj => true or false * nil | obj => true or false * * Or---Returns false if obj is * nil or false; true otherwise. */ static VALUE false_or(obj, obj2) VALUE obj, obj2; { return RTEST(obj2)?Qtrue:Qfalse; } /* * call-seq: * false ^ obj => true or false * nil ^ obj => true or false * * Exclusive Or---If obj is nil or * false, returns false; otherwise, returns * true. * */ static VALUE false_xor(obj, obj2) VALUE obj, obj2; { return RTEST(obj2)?Qtrue:Qfalse; } /* * call_seq: * nil.nil? => true * * Only the object nil responds true to nil?. */ static VALUE rb_true(obj) VALUE obj; { return Qtrue; } /* * call_seq: * nil.nil? => true * .nil? => false * * Only the object nil responds true to nil?. */ static VALUE rb_false(obj) VALUE obj; { return Qfalse; } /* * call-seq: * obj =~ other => false * * Pattern Match---Overridden by descendents (notably * Regexp and String) to provide meaningful * pattern-match semantics. */ static VALUE rb_obj_pattern_match(obj1, obj2) VALUE obj1, obj2; { return Qfalse; } /********************************************************************** * Document-class: Symbol * * Symbol objects represent names and some strings * inside the Ruby * interpreter. They are generated using the :name and * :"string" literals * syntax, and by the various to_sym methods. The same * Symbol object will be created for a given name or string * for the duration of a program's execution, regardless of the context * or meaning of that name. Thus if Fred is a constant in * one context, a method in another, and a class in a third, the * Symbol :Fred will be the same object in * all three contexts. * * module One * class Fred * end * $f1 = :Fred * end * module Two * Fred = 1 * $f2 = :Fred * end * def Fred() * end * $f3 = :Fred * $f1.id #=> 2514190 * $f2.id #=> 2514190 * $f3.id #=> 2514190 * */ /* * call-seq: * sym.to_i => fixnum * * Returns an integer that is unique for each symbol within a * particular execution of a program. * * :fred.to_i #=> 9809 * "fred".to_sym.to_i #=> 9809 */ static VALUE sym_to_i(sym) VALUE sym; { ID id = SYM2ID(sym); return LONG2FIX(id); } /* :nodoc: */ static VALUE sym_to_int(sym) VALUE sym; { rb_warning("treating Symbol as an integer"); return sym_to_i(sym); } /* * call-seq: * sym.inspect => string * * Returns the representation of sym as a symbol literal. * * :fred.inspect #=> ":fred" */ static VALUE sym_inspect(sym) VALUE sym; { VALUE str; const char *name; ID id = SYM2ID(sym); name = rb_id2name(id); str = rb_str_new(0, strlen(name)+1); RSTRING(str)->ptr[0] = ':'; strcpy(RSTRING(str)->ptr+1, name); if (!rb_symname_p(name)) { str = rb_str_dump(str); strncpy(RSTRING(str)->ptr, ":\"", 2); } return str; } /* * call-seq: * sym.id2name => string * sym.to_s => string * * Returns the name or string corresponding to sym. * * :fred.id2name #=> "fred" */ static VALUE sym_to_s(sym) VALUE sym; { return rb_str_new2(rb_id2name(SYM2ID(sym))); } /* * call-seq: * sym.to_sym => sym * * In general, to_sym returns the Symbol corresponding * to an object. As sym is already a symbol, self is returned * in this case. */ static VALUE sym_to_sym(sym) VALUE sym; { return sym; } static VALUE sym_call(args, mid) VALUE args, mid; { VALUE obj; if (RARRAY(args)->len < 1) { rb_raise(rb_eArgError, "no receiver given"); } obj = rb_ary_shift(args); return rb_apply(obj, (ID)mid, args); } VALUE rb_proc_new _((VALUE (*)(ANYARGS/* VALUE yieldarg[, VALUE procarg] */), VALUE)); /* * call-seq: * sym.to_proc * * Returns a _Proc_ object which respond to the given method by _sym_. * * (1..3).collect(&:to_s) #=> ["1", "2", "3"] */ static VALUE sym_to_proc(VALUE sym) { return rb_proc_new(sym_call, (VALUE)SYM2ID(sym)); } /*********************************************************************** * * Document-class: Module * * A Module is a collection of methods and constants. The * methods in a module may be instance methods or module methods. * Instance methods appear as methods in a class when the module is * included, module methods do not. Conversely, module methods may be * called without creating an encapsulating object, while instance * methods may not. (See Module#module_function) * * In the descriptions that follow, the parameter syml refers * to a symbol, which is either a quoted string or a * Symbol (such as :name). * * module Mod * include Math * CONST = 1 * def meth * # ... * end * end * Mod.class #=> Module * Mod.constants #=> ["E", "PI", "CONST"] * Mod.instance_methods #=> ["meth"] * */ /* * call-seq: * mod.to_s => string * * Return a string representing this module or class. For basic * classes and modules, this is the name. For singletons, we * show information on the thing we're attached to as well. */ static VALUE rb_mod_to_s(klass) VALUE klass; { if (FL_TEST(klass, FL_SINGLETON)) { VALUE s = rb_str_new2("#<"); VALUE v = rb_iv_get(klass, "__attached__"); rb_str_cat2(s, "Class:"); switch (TYPE(v)) { case T_CLASS: case T_MODULE: rb_str_append(s, rb_inspect(v)); break; default: rb_str_append(s, rb_any_to_s(v)); break; } rb_str_cat2(s, ">"); return s; } return rb_str_dup(rb_class_name(klass)); } /* * call-seq: * mod.freeze * * Prevents further modifications to mod. */ static VALUE rb_mod_freeze(mod) VALUE mod; { rb_mod_to_s(mod); return rb_obj_freeze(mod); } /* * call-seq: * mod === obj => true or false * * Case Equality---Returns true if anObject is an * instance of mod or one of mod's descendents. Of * limited use for modules, but can be used in case * statements to classify objects by class. */ static VALUE rb_mod_eqq(mod, arg) VALUE mod, arg; { return rb_obj_is_kind_of(arg, mod); } /* * call-seq: * mod <= other => true, false, or nil * * Returns true if mod is a subclass of other or * is the same as other. Returns * nil if there's no relationship between the two. * (Think of the relationship in terms of the class definition: * "class Am_tbl == RCLASS(arg)->m_tbl) return Qtrue; mod = RBASIC(mod)->klass; } while (mod) { if (RCLASS(mod)->m_tbl == RCLASS(arg)->m_tbl) return Qtrue; mod = RCLASS(mod)->super; } /* not mod < arg; check if mod > arg */ while (arg) { if (RCLASS(arg)->m_tbl == RCLASS(start)->m_tbl) return Qfalse; arg = RCLASS(arg)->super; } return Qnil; } /* * call-seq: * mod < other => true, false, or nil * * Returns true if mod is a subclass of other. Returns * nil if there's no relationship between the two. * (Think of the relationship in terms of the class definition: * "class A= other => true, false, or nil * * Returns true if mod is an ancestor of other, or the * two modules are the same. Returns * nil if there's no relationship between the two. * (Think of the relationship in terms of the class definition: * "class AA"). * */ static VALUE rb_mod_ge(mod, arg) VALUE mod, arg; { switch (TYPE(arg)) { case T_MODULE: case T_CLASS: break; default: rb_raise(rb_eTypeError, "compared with non class/module"); } return rb_class_inherited_p(arg, mod); } /* * call-seq: * mod > other => true, false, or nil * * Returns true if mod is an ancestor of other. Returns * nil if there's no relationship between the two. * (Think of the relationship in terms of the class definition: * "class AA"). * */ static VALUE rb_mod_gt(mod, arg) VALUE mod, arg; { if (mod == arg) return Qfalse; return rb_mod_ge(mod, arg); } /* * call-seq: * mod <=> other_mod => -1, 0, +1, or nil * * Comparison---Returns -1 if mod includes other_mod, 0 if * mod is the same as other_mod, and +1 if mod is * included by other_mod or if mod has no relationship with * other_mod. Returns nil if other_mod is * not a module. */ static VALUE rb_mod_cmp(mod, arg) VALUE mod, arg; { VALUE cmp; if (mod == arg) return INT2FIX(0); switch (TYPE(arg)) { case T_MODULE: case T_CLASS: break; default: return Qnil; } cmp = rb_class_inherited_p(mod, arg); if (NIL_P(cmp)) return Qnil; if (cmp) { return INT2FIX(-1); } return INT2FIX(1); } static VALUE rb_module_s_alloc _((VALUE)); static VALUE rb_module_s_alloc(klass) VALUE klass; { VALUE mod = rb_module_new(); RBASIC(mod)->klass = klass; return mod; } static VALUE rb_class_s_alloc _((VALUE)); static VALUE rb_class_s_alloc(klass) VALUE klass; { return rb_class_boot(0); } /* * call-seq: * Module.new => mod * Module.new {|mod| block } => mod * * Creates a new anonymous module. If a block is given, it is passed * the module object, and the block is evaluated in the context of this * module using module_eval. * * Fred = Module.new do * def meth1 * "hello" * end * def meth2 * "bye" * end * end * a = "my string" * a.extend(Fred) #=> "my string" * a.meth1 #=> "hello" * a.meth2 #=> "bye" */ static VALUE rb_mod_initialize(module) VALUE module; { if (rb_block_given_p()) { rb_mod_module_eval(0, 0, module); } return Qnil; } /* * call-seq: * Class.new(super_class=Object) => a_class * * Creates a new anonymous (unnamed) class with the given superclass * (or Object if no parameter is given). You can give a * class a name by assigning the class object to a constant. * */ static VALUE rb_class_initialize(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { VALUE super; if (RCLASS(klass)->super != 0) { rb_raise(rb_eTypeError, "already initialized class"); } if (rb_scan_args(argc, argv, "01", &super) == 0) { super = rb_cObject; } else { rb_check_inheritable(super); } RCLASS(klass)->super = super; rb_make_metaclass(klass, RBASIC(super)->klass); rb_mod_initialize(klass); rb_class_inherited(super, klass); return klass; } /* * call-seq: * class.allocate() => obj * * Allocates space for a new object of class's class and does not * call initialize on the new instance. The returned object must be an * instance of class. * * klass = Class.new do * def initialize(*args) * @initialized = true * end * * def initialized? * @initialized || false * end * end * * klass.allocate.initialized? #=> false * */ VALUE rb_obj_alloc(klass) VALUE klass; { VALUE obj; if (RCLASS(klass)->super == 0) { rb_raise(rb_eTypeError, "can't instantiate uninitialized class"); } if (FL_TEST(klass, FL_SINGLETON)) { rb_raise(rb_eTypeError, "can't create instance of virtual class"); } obj = rb_funcall(klass, ID_ALLOCATOR, 0, 0); if (rb_obj_class(obj) != rb_class_real(klass)) { rb_raise(rb_eTypeError, "wrong instance allocation"); } return obj; } static VALUE rb_class_allocate_instance _((VALUE)); static VALUE rb_class_allocate_instance(klass) VALUE klass; { NEWOBJ(obj, struct RObject); OBJSETUP(obj, klass, T_OBJECT); return (VALUE)obj; } /* * call-seq: * class.new(args, ...) => obj * * Calls allocate to create a new object of * class's class, then invokes that object's * initialize method, passing it args. * This is the method that ends up getting called whenever * an object is constructed using .new. * */ VALUE rb_class_new_instance(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { VALUE obj; obj = rb_obj_alloc(klass); rb_obj_call_init(obj, argc, argv); return obj; } /* * call-seq: * class.superclass -> a_super_class or nil * * Returns the superclass of class, or nil. * * File.superclass #=> IO * IO.superclass #=> Object * Object.superclass #=> nil * */ static VALUE rb_class_superclass(klass) VALUE klass; { VALUE super = RCLASS(klass)->super; if (!super) { rb_raise(rb_eTypeError, "uninitialized class"); } if (FL_TEST(klass, FL_SINGLETON)) { super = RBASIC(klass)->klass; } while (TYPE(super) == T_ICLASS) { super = RCLASS(super)->super; } if (!super) { return Qnil; } return super; } static ID str_to_id(str) VALUE str; { VALUE sym = rb_str_intern(str); return SYM2ID(sym); } ID rb_to_id(name) VALUE name; { VALUE tmp; ID id; switch (TYPE(name)) { case T_STRING: return str_to_id(name); case T_FIXNUM: rb_warn("do not use Fixnums as Symbols"); id = FIX2LONG(name); if (!rb_id2name(id)) { rb_raise(rb_eArgError, "%ld is not a symbol", id); } break; case T_SYMBOL: id = SYM2ID(name); break; default: tmp = rb_check_string_type(name); if (!NIL_P(tmp)) { return str_to_id(tmp); } rb_raise(rb_eTypeError, "%s is not a symbol", RSTRING(rb_inspect(name))->ptr); } return id; } /* * call-seq: * attr(symbol, writable=false) => nil * * Defines a named attribute for this module, where the name is * symbol.id2name, creating an instance variable * (@name) and a corresponding access method to read it. * If the optional writable argument is true, also * creates a method called name= to set the attribute. * * module Mod * attr :size, true * end * * is equivalent to: * * module Mod * def size * @size * end * def size=(val) * @size = val * end * end */ static VALUE rb_mod_attr(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { VALUE name, pub; rb_scan_args(argc, argv, "11", &name, &pub); rb_attr(klass, rb_to_id(name), 1, RTEST(pub), Qtrue); return Qnil; } /* * call-seq: * attr_reader(symbol, ...) => nil * * Creates instance variables and corresponding methods that return the * value of each instance variable. Equivalent to calling * ``attr:name'' on each name in turn. */ static VALUE rb_mod_attr_reader(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { int i; for (i=0; i nil * * Creates an accessor method to allow assignment to the attribute * aSymbol.id2name. */ static VALUE rb_mod_attr_writer(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { int i; for (i=0; i nil * * Equivalent to calling ``attrsymbol, * true'' on each symbol in turn. * * module Mod * attr_accessor(:one, :two) * end * Mod.instance_methods.sort #=> ["one", "one=", "two", "two="] */ static VALUE rb_mod_attr_accessor(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { int i; for (i=0; i obj * * Returns the value of the named constant in mod. * * Math.const_get(:PI) #=> 3.14159265358979 */ static VALUE rb_mod_const_get(mod, name) VALUE mod, name; { ID id = rb_to_id(name); if (!rb_is_const_id(id)) { rb_name_error(id, "wrong constant name %s", rb_id2name(id)); } return rb_const_get(mod, id); } /* * call-seq: * mod.const_set(sym, obj) => obj * * Sets the named constant to the given object, returning that object. * Creates a new constant if no constant with the given name previously * existed. * * Math.const_set("HIGH_SCHOOL_PI", 22.0/7.0) #=> 3.14285714285714 * Math::HIGH_SCHOOL_PI - Math::PI #=> 0.00126448926734968 */ static VALUE rb_mod_const_set(mod, name, value) VALUE mod, name, value; { ID id = rb_to_id(name); if (!rb_is_const_id(id)) { rb_name_error(id, "wrong constant name %s", rb_id2name(id)); } rb_const_set(mod, id, value); return value; } /* * call-seq: * mod.const_defined?(sym) => true or false * * Returns true if a constant with the given name is * defined by mod. * * Math.const_defined? "PI" #=> true */ static VALUE rb_mod_const_defined(mod, name) VALUE mod, name; { ID id = rb_to_id(name); if (!rb_is_const_id(id)) { rb_name_error(id, "wrong constant name %s", rb_id2name(id)); } return rb_const_defined_at(mod, id); } /* * call-seq: * obj.methods => array * * Returns a list of the names of methods publicly accessible in * obj. This will include all the methods accessible in * obj's ancestors. * * class Klass * def kMethod() * end * end * k = Klass.new * k.methods[0..9] #=> ["kMethod", "freeze", "nil?", "is_a?", * "class", "instance_variable_set", * "methods", "extend", "__send__", "instance_eval"] * k.methods.length #=> 42 */ static VALUE rb_obj_methods(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { retry: if (argc == 0) { VALUE args[1]; args[0] = Qtrue; return rb_class_instance_methods(1, args, CLASS_OF(obj)); } else { VALUE recur; rb_scan_args(argc, argv, "1", &recur); if (RTEST(recur)) { argc = 0; goto retry; } return rb_obj_singleton_methods(argc, argv, obj); } } /* * call-seq: * obj.protected_methods(all=true) => array * * Returns the list of protected methods accessible to obj. If * the all parameter is set to false, only those methods * in the receiver will be listed. */ static VALUE rb_obj_protected_methods(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { if (argc == 0) { /* hack to stop warning */ VALUE args[1]; args[0] = Qtrue; return rb_class_protected_instance_methods(1, args, CLASS_OF(obj)); } return rb_class_protected_instance_methods(argc, argv, CLASS_OF(obj)); } /* * call-seq: * obj.private_methods(all=true) => array * * Returns the list of private methods accessible to obj. If * the all parameter is set to false, only those methods * in the receiver will be listed. */ static VALUE rb_obj_private_methods(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { if (argc == 0) { /* hack to stop warning */ VALUE args[1]; args[0] = Qtrue; return rb_class_private_instance_methods(1, args, CLASS_OF(obj)); } return rb_class_private_instance_methods(argc, argv, CLASS_OF(obj)); } /* * call-seq: * obj.public_methods(all=true) => array * * Returns the list of public methods accessible to obj. If * the all parameter is set to false, only those methods * in the receiver will be listed. */ static VALUE rb_obj_public_methods(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { if (argc == 0) { /* hack to stop warning */ VALUE args[1]; args[0] = Qtrue; return rb_class_public_instance_methods(1, args, CLASS_OF(obj)); } return rb_class_public_instance_methods(argc, argv, CLASS_OF(obj)); } /* * call-seq: * obj.instance_variable_get(symbol) => obj * * Returns the value of the given instance variable, or nil if the * instance variable is not set. The @ part of the * variable name should be included for regular instance * variables. Throws a NameError exception if the * supplied symbol is not valid as an instance variable name. * * class Fred * def initialize(p1, p2) * @a, @b = p1, p2 * end * end * fred = Fred.new('cat', 99) * fred.instance_variable_get(:@a) #=> "cat" * fred.instance_variable_get("@b") #=> 99 */ static VALUE rb_obj_ivar_get(obj, iv) VALUE obj, iv; { ID id = rb_to_id(iv); if (!rb_is_instance_id(id)) { rb_name_error(id, "`%s' is not allowed as an instance variable name", rb_id2name(id)); } return rb_ivar_get(obj, id); } /* * call-seq: * obj.instance_variable_set(symbol, obj) => obj * * Sets the instance variable names by symbol to * object, thereby frustrating the efforts of the class's * author to attempt to provide proper encapsulation. The variable * did not have to exist prior to this call. * * class Fred * def initialize(p1, p2) * @a, @b = p1, p2 * end * end * fred = Fred.new('cat', 99) * fred.instance_variable_set(:@a, 'dog') #=> "dog" * fred.instance_variable_set(:@c, 'cat') #=> "cat" * fred.inspect #=> "#" */ static VALUE rb_obj_ivar_set(obj, iv, val) VALUE obj, iv, val; { ID id = rb_to_id(iv); if (!rb_is_instance_id(id)) { rb_name_error(id, "`%s' is not allowed as an instance variable name", rb_id2name(id)); } return rb_ivar_set(obj, id, val); } /* * call-seq: * obj.instance_variable_defined?(symbol) => true or false * * Returns true if the given instance variable is * defined in obj. * * class Fred * def initialize(p1, p2) * @a, @b = p1, p2 * end * end * fred = Fred.new('cat', 99) * fred.instance_variable_defined?(:@a) #=> true * fred.instance_variable_defined?("@b") #=> true * fred.instance_variable_defined?("@c") #=> false */ static VALUE rb_obj_ivar_defined(obj, iv) VALUE obj, iv; { ID id = rb_to_id(iv); if (!rb_is_instance_id(id)) { rb_name_error(id, "`%s' is not allowed as an instance variable name", rb_id2name(id)); } return rb_ivar_defined(obj, id); } /* * call-seq: * mod.class_variable_get(symbol) => obj * * Returns the value of the given class variable (or throws a * NameError exception). The @@ part of the * variable name should be included for regular class variables * * class Fred * @@foo = 99 * end * * def Fred.foo * class_variable_get(:@@foo) #=> 99 * end */ static VALUE rb_mod_cvar_get(obj, iv) VALUE obj, iv; { ID id = rb_to_id(iv); if (!rb_is_class_id(id)) { rb_name_error(id, "`%s' is not allowed as a class variable name", rb_id2name(id)); } return rb_cvar_get(obj, id); } /* * call-seq: * obj.class_variable_set(symbol, obj) => obj * * Sets the class variable names by symbol to * object. * * class Fred * @@foo = 99 * def foo * @@foo * end * end * * def Fred.foo * class_variable_set(:@@foo, 101) #=> 101 * end * Fred.foo * Fred.new.foo #=> 101 */ static VALUE rb_mod_cvar_set(obj, iv, val) VALUE obj, iv, val; { ID id = rb_to_id(iv); if (!rb_is_class_id(id)) { rb_name_error(id, "`%s' is not allowed as a class variable name", rb_id2name(id)); } rb_cvar_set(obj, id, val, Qfalse); return val; } /* * call-seq: * obj.class_variable_defined?(symbol) => true or false * * Returns true if the given class variable is defined * in obj. * * class Fred * @@foo = 99 * end * Fred.class_variable_defined?(:@@foo) #=> true * Fred.class_variable_defined?(:@@bar) #=> false */ static VALUE rb_mod_cvar_defined(obj, iv) VALUE obj, iv; { ID id = rb_to_id(iv); if (!rb_is_class_id(id)) { rb_name_error(id, "`%s' is not allowed as a class variable name", rb_id2name(id)); } return rb_cvar_defined(obj, id); } static VALUE convert_type(val, tname, method, raise) VALUE val; const char *tname, *method; int raise; { ID m; m = rb_intern(method); if (!rb_respond_to(val, m)) { if (raise) { rb_raise(rb_eTypeError, "can't convert %s into %s", NIL_P(val) ? "nil" : val == Qtrue ? "true" : val == Qfalse ? "false" : rb_obj_classname(val), tname); } else { return Qnil; } } return rb_funcall(val, m, 0); } VALUE rb_convert_type(val, type, tname, method) VALUE val; int type; const char *tname, *method; { VALUE v; if (TYPE(val) == type) return val; v = convert_type(val, tname, method, Qtrue); if (TYPE(v) != type) { rb_raise(rb_eTypeError, "%s#%s should return %s", rb_obj_classname(val), method, tname); } return v; } VALUE rb_check_convert_type(val, type, tname, method) VALUE val; int type; const char *tname, *method; { VALUE v; /* always convert T_DATA */ if (TYPE(val) == type && type != T_DATA) return val; v = convert_type(val, tname, method, Qfalse); if (NIL_P(v)) return Qnil; if (TYPE(v) != type) { rb_raise(rb_eTypeError, "%s#%s should return %s", rb_obj_classname(val), method, tname); } return v; } static VALUE rb_to_integer(val, method) VALUE val; const char *method; { VALUE v = convert_type(val, "Integer", method, Qtrue); if (!rb_obj_is_kind_of(v, rb_cInteger)) { rb_raise(rb_eTypeError, "%s#%s should return Integer", rb_obj_classname(val), method); } return v; } VALUE rb_check_to_integer(VALUE val, const char *method) { VALUE v; if (FIXNUM_P(val)) return val; v = convert_type(val, "Integer", method, Qfalse); if (!rb_obj_is_kind_of(v, rb_cInteger)) { return Qnil; } return v; } VALUE rb_to_int(val) VALUE val; { return rb_to_integer(val, "to_int"); } VALUE rb_Integer(val) VALUE val; { VALUE tmp; switch (TYPE(val)) { case T_FLOAT: if (RFLOAT(val)->value <= (double)FIXNUM_MAX && RFLOAT(val)->value >= (double)FIXNUM_MIN) { break; } return rb_dbl2big(RFLOAT(val)->value); case T_FIXNUM: case T_BIGNUM: return val; case T_STRING: return rb_str_to_inum(val, 0, Qtrue); default: break; } tmp = convert_type(val, "Integer", "to_int", Qfalse); if (NIL_P(tmp)) { return rb_to_integer(val, "to_i"); } return tmp; } /* * call-seq: * Integer(arg) => integer * * Converts arg to a Fixnum or Bignum. * Numeric types are converted directly (with floating point numbers * being truncated). If arg is a String, leading * radix indicators (0, 0b, and * 0x) are honored. Others are converted using * to_int and to_i. This behavior is * different from that of String#to_i. * * Integer(123.999) #=> 123 * Integer("0x1a") #=> 26 * Integer(Time.new) #=> 1049896590 */ static VALUE rb_f_integer(obj, arg) VALUE obj, arg; { return rb_Integer(arg); } double rb_cstr_to_dbl(p, badcheck) const char *p; int badcheck; { const char *q; char *end; double d; const char *ellipsis = ""; int w; #define OutOfRange() (((w = end - p) > 20) ? (w = 20, ellipsis = "...") : (ellipsis = "")) if (!p) return 0.0; q = p; if (badcheck) { while (ISSPACE(*p)) p++; } else { while (ISSPACE(*p) || *p == '_') p++; } errno = 0; d = strtod(p, &end); if (errno == ERANGE) { OutOfRange(); rb_warn("Float %.*s%s out of range", w, p, ellipsis); errno = 0; } if (p == end) { if (badcheck) { bad: rb_invalid_str(q, "Float()"); } return d; } if (*end) { char *buf = ALLOCA_N(char, strlen(p)+1); char *n = buf; while (p < end) *n++ = *p++; while (*p) { if (*p == '_') { /* remove underscores between digits */ if (badcheck) { if (n == buf || !ISDIGIT(n[-1])) goto bad; ++p; if (!ISDIGIT(*p)) goto bad; } else { while (*++p == '_'); continue; } } *n++ = *p++; } *n = '\0'; p = buf; d = strtod(p, &end); if (errno == ERANGE) { OutOfRange(); rb_warn("Float %.*s%s out of range", w, p, ellipsis); errno = 0; } if (badcheck) { if (!end || p == end) goto bad; while (*end && ISSPACE(*end)) end++; if (*end) goto bad; } } if (errno == ERANGE) { errno = 0; OutOfRange(); rb_raise(rb_eArgError, "Float %.*s%s out of range", w, q, ellipsis); } return d; } double rb_str_to_dbl(str, badcheck) VALUE str; int badcheck; { char *s; long len; StringValue(str); s = RSTRING(str)->ptr; len = RSTRING(str)->len; if (s) { if (s[len]) { /* no sentinel somehow */ char *p = ALLOCA_N(char, len+1); MEMCPY(p, s, char, len); p[len] = '\0'; s = p; } if (badcheck && len != strlen(s)) { rb_raise(rb_eArgError, "string for Float contains null byte"); } } return rb_cstr_to_dbl(s, badcheck); } VALUE rb_Float(val) VALUE val; { switch (TYPE(val)) { case T_FIXNUM: return rb_float_new((double)FIX2LONG(val)); case T_FLOAT: return val; case T_BIGNUM: return rb_float_new(rb_big2dbl(val)); case T_STRING: return rb_float_new(rb_str_to_dbl(val, Qtrue)); case T_NIL: rb_raise(rb_eTypeError, "can't convert nil into Float"); break; default: return rb_convert_type(val, T_FLOAT, "Float", "to_f"); } } /* * call-seq: * Float(arg) => float * * Returns arg converted to a float. Numeric types are converted * directly, the rest are converted using arg.to_f. As of Ruby * 1.8, converting nil generates a TypeError. * * Float(1) #=> 1.0 * Float("123.456") #=> 123.456 */ static VALUE rb_f_float(obj, arg) VALUE obj, arg; { return rb_Float(arg); } double rb_num2dbl(val) VALUE val; { switch (TYPE(val)) { case T_FLOAT: return RFLOAT(val)->value; case T_STRING: rb_raise(rb_eTypeError, "no implicit conversion to float from string"); break; case T_NIL: rb_raise(rb_eTypeError, "no implicit conversion to float from nil"); break; default: break; } return RFLOAT(rb_Float(val))->value; } char* rb_str2cstr(str, len) VALUE str; long *len; { StringValue(str); if (len) *len = RSTRING(str)->len; else if (RTEST(ruby_verbose) && RSTRING(str)->len != strlen(RSTRING(str)->ptr)) { rb_warn("string contains \\0 character"); } return RSTRING(str)->ptr; } VALUE rb_String(val) VALUE val; { return rb_convert_type(val, T_STRING, "String", "to_s"); } /* * call-seq: * String(arg) => string * * Converts arg to a String by calling its * to_s method. * * String(self) #=> "main" * String(self.class #=> "Object" * String(123456) #=> "123456" */ static VALUE rb_f_string(obj, arg) VALUE obj, arg; { return rb_String(arg); } #if 0 VALUE rb_Array(val) VALUE val; { VALUE tmp = rb_check_array_type(val); if (NIL_P(tmp)) { tmp = rb_check_convert_type(val, T_ARRAY, "Array", "to_a"); if (NIL_P(tmp)) { return rb_ary_new3(1, val); } } return tmp; } #endif /* * call-seq: * Array(arg) => array * * Returns arg as an Array. First tries to call * arg.to_ary, then arg.to_a. * If both fail, creates a single element array containing arg * (unless arg is nil). * * Array(1..5) #=> [1, 2, 3, 4, 5] */ static VALUE rb_f_array(obj, arg) VALUE obj, arg; { return rb_Array(arg); } static VALUE boot_defclass(name, super) char *name; VALUE super; { extern st_table *rb_class_tbl; VALUE obj = rb_class_boot(super); ID id = rb_intern(name); rb_name_class(obj, id); st_add_direct(rb_class_tbl, id, obj); rb_const_set((rb_cObject ? rb_cObject : obj), id, obj); return obj; } VALUE ruby_top_self; /* * Document-class: Class * * Classes in Ruby are first-class objects---each is an instance of * class Class. * * When a new class is created (typically using class Name ... * end), an object of type Class is created and * assigned to a global constant (Name in this case). When * Name.new is called to create a new object, the * new method in Class is run by default. * This can be demonstrated by overriding new in * Class: * * class Class * alias oldNew new * def new(*args) * print "Creating a new ", self.name, "\n" * oldNew(*args) * end * end * * * class Name * end * * * n = Name.new * * produces: * * Creating a new Name * * Classes, modules, and objects are interrelated. In the diagram * that follows, the vertical arrows represent inheritance, and the * parentheses meta-classes. All metaclasses are instances * of the class `Class'. * * +------------------+ * | | * Object---->(Object) | * ^ ^ ^ ^ | * | | | | | * | | +-----+ +---------+ | * | | | | | * | +-----------+ | | * | | | | | * +------+ | Module--->(Module) | * | | ^ ^ | * OtherClass-->(OtherClass) | | | * | | | * Class---->(Class) | * ^ | * | | * +----------------+ */ /* * Object is the parent class of all classes in Ruby. Its * methods are therefore available to all objects unless explicitly * overridden. * * Object mixes in the Kernel module, making * the built-in kernel functions globally accessible. Although the * instance methods of Object are defined by the * Kernel module, we have chosen to document them here for * clarity. * * In the descriptions of Object's methods, the parameter symbol refers * to a symbol, which is either a quoted string or a * Symbol (such as :name). */ void Init_Object() { VALUE metaclass; rb_cObject = boot_defclass("Object", 0); rb_cModule = boot_defclass("Module", rb_cObject); rb_cClass = boot_defclass("Class", rb_cModule); metaclass = rb_make_metaclass(rb_cObject, rb_cClass); metaclass = rb_make_metaclass(rb_cModule, metaclass); metaclass = rb_make_metaclass(rb_cClass, metaclass); rb_mKernel = rb_define_module("Kernel"); rb_include_module(rb_cObject, rb_mKernel); rb_define_alloc_func(rb_cObject, rb_class_allocate_instance); rb_define_private_method(rb_cObject, "initialize", rb_obj_dummy, 0); rb_define_private_method(rb_cClass, "inherited", rb_obj_dummy, 1); rb_define_private_method(rb_cModule, "included", rb_obj_dummy, 1); rb_define_private_method(rb_cModule, "extended", rb_obj_dummy, 1); rb_define_private_method(rb_cModule, "method_added", rb_obj_dummy, 1); rb_define_private_method(rb_cModule, "method_removed", rb_obj_dummy, 1); rb_define_private_method(rb_cModule, "method_undefined", rb_obj_dummy, 1); rb_define_method(rb_mKernel, "nil?", rb_false, 0); rb_define_method(rb_mKernel, "==", rb_obj_equal, 1); rb_define_method(rb_mKernel, "equal?", rb_obj_equal, 1); rb_define_method(rb_mKernel, "===", rb_equal, 1); rb_define_method(rb_mKernel, "=~", rb_obj_pattern_match, 1); rb_define_method(rb_mKernel, "eql?", rb_obj_equal, 1); rb_define_method(rb_mKernel, "id", rb_obj_id_obsolete, 0); rb_define_method(rb_mKernel, "type", rb_obj_type, 0); rb_define_method(rb_mKernel, "class", rb_obj_class, 0); rb_define_method(rb_mKernel, "clone", rb_obj_clone, 0); rb_define_method(rb_mKernel, "dup", rb_obj_dup, 0); rb_define_method(rb_mKernel, "initialize_copy", rb_obj_init_copy, 1); rb_define_method(rb_mKernel, "taint", rb_obj_taint, 0); rb_define_method(rb_mKernel, "tainted?", rb_obj_tainted, 0); rb_define_method(rb_mKernel, "untaint", rb_obj_untaint, 0); rb_define_method(rb_mKernel, "freeze", rb_obj_freeze, 0); rb_define_method(rb_mKernel, "frozen?", rb_obj_frozen_p, 0); rb_define_method(rb_mKernel, "moved?", rb_obj_moved_p, 0); rb_define_method(rb_mKernel, "longlived?", rb_obj_longlived_p, 0); rb_define_method(rb_mKernel, "to_a", rb_any_to_a, 0); /* to be removed */ rb_define_method(rb_mKernel, "to_s", rb_any_to_s, 0); rb_define_method(rb_mKernel, "inspect", rb_obj_inspect, 0); rb_define_method(rb_mKernel, "methods", rb_obj_methods, -1); rb_define_method(rb_mKernel, "singleton_methods", rb_obj_singleton_methods, -1); /* in class.c */ rb_define_method(rb_mKernel, "protected_methods", rb_obj_protected_methods, -1); rb_define_method(rb_mKernel, "private_methods", rb_obj_private_methods, -1); rb_define_method(rb_mKernel, "public_methods", rb_obj_public_methods, -1); rb_define_method(rb_mKernel, "instance_variables", rb_obj_instance_variables, 0); /* in variable.c */ rb_define_method(rb_mKernel, "instance_variable_get", rb_obj_ivar_get, 1); rb_define_method(rb_mKernel, "instance_variable_set", rb_obj_ivar_set, 2); rb_define_method(rb_mKernel, "instance_variable_defined?", rb_obj_ivar_defined, 1); rb_define_private_method(rb_mKernel, "remove_instance_variable", rb_obj_remove_instance_variable, 1); /* in variable.c */ rb_define_method(rb_mKernel, "instance_of?", rb_obj_is_instance_of, 1); rb_define_method(rb_mKernel, "kind_of?", rb_obj_is_kind_of, 1); rb_define_method(rb_mKernel, "is_a?", rb_obj_is_kind_of, 1); rb_define_method(rb_mKernel, "tap", rb_obj_tap, 0); rb_define_private_method(rb_mKernel, "singleton_method_added", rb_obj_dummy, 1); rb_define_private_method(rb_mKernel, "singleton_method_removed", rb_obj_dummy, 1); rb_define_private_method(rb_mKernel, "singleton_method_undefined", rb_obj_dummy, 1); rb_define_global_function("sprintf", rb_f_sprintf, -1); /* in sprintf.c */ rb_define_global_function("format", rb_f_sprintf, -1); /* in sprintf.c */ rb_define_global_function("Integer", rb_f_integer, 1); rb_define_global_function("Float", rb_f_float, 1); rb_define_global_function("String", rb_f_string, 1); rb_define_global_function("Array", rb_f_array, 1); rb_cNilClass = rb_define_class("NilClass", rb_cObject); rb_define_method(rb_cNilClass, "to_i", nil_to_i, 0); rb_define_method(rb_cNilClass, "to_f", nil_to_f, 0); rb_define_method(rb_cNilClass, "to_s", nil_to_s, 0); rb_define_method(rb_cNilClass, "to_a", nil_to_a, 0); rb_define_method(rb_cNilClass, "inspect", nil_inspect, 0); rb_define_method(rb_cNilClass, "&", false_and, 1); rb_define_method(rb_cNilClass, "|", false_or, 1); rb_define_method(rb_cNilClass, "^", false_xor, 1); rb_define_method(rb_cNilClass, "nil?", rb_true, 0); rb_undef_alloc_func(rb_cNilClass); rb_undef_method(CLASS_OF(rb_cNilClass), "new"); rb_define_global_const("NIL", Qnil); rb_cSymbol = rb_define_class("Symbol", rb_cObject); rb_define_singleton_method(rb_cSymbol, "all_symbols", rb_sym_all_symbols, 0); /* in parse.y */ rb_undef_alloc_func(rb_cSymbol); rb_undef_method(CLASS_OF(rb_cSymbol), "new"); rb_define_method(rb_cSymbol, "to_i", sym_to_i, 0); rb_define_method(rb_cSymbol, "to_int", sym_to_int, 0); rb_define_method(rb_cSymbol, "inspect", sym_inspect, 0); rb_define_method(rb_cSymbol, "to_s", sym_to_s, 0); rb_define_method(rb_cSymbol, "id2name", sym_to_s, 0); rb_define_method(rb_cSymbol, "to_sym", sym_to_sym, 0); rb_define_method(rb_cSymbol, "to_proc", sym_to_proc, 0); rb_define_method(rb_cSymbol, "===", rb_obj_equal, 1); rb_define_method(rb_cModule, "freeze", rb_mod_freeze, 0); rb_define_method(rb_cModule, "===", rb_mod_eqq, 1); rb_define_method(rb_cModule, "==", rb_obj_equal, 1); rb_define_method(rb_cModule, "<=>", rb_mod_cmp, 1); rb_define_method(rb_cModule, "<", rb_mod_lt, 1); rb_define_method(rb_cModule, "<=", rb_class_inherited_p, 1); rb_define_method(rb_cModule, ">", rb_mod_gt, 1); rb_define_method(rb_cModule, ">=", rb_mod_ge, 1); rb_define_method(rb_cModule, "initialize_copy", rb_mod_init_copy, 1); /* in class.c */ rb_define_method(rb_cModule, "to_s", rb_mod_to_s, 0); rb_define_method(rb_cModule, "included_modules", rb_mod_included_modules, 0); /* in class.c */ rb_define_method(rb_cModule, "include?", rb_mod_include_p, 1); /* in class.c */ rb_define_method(rb_cModule, "name", rb_mod_name, 0); /* in variable.c */ rb_define_method(rb_cModule, "ancestors", rb_mod_ancestors, 0); /* in class.c */ rb_define_private_method(rb_cModule, "attr", rb_mod_attr, -1); rb_define_private_method(rb_cModule, "attr_reader", rb_mod_attr_reader, -1); rb_define_private_method(rb_cModule, "attr_writer", rb_mod_attr_writer, -1); rb_define_private_method(rb_cModule, "attr_accessor", rb_mod_attr_accessor, -1); rb_define_alloc_func(rb_cModule, rb_module_s_alloc); rb_define_method(rb_cModule, "initialize", rb_mod_initialize, 0); rb_define_method(rb_cModule, "instance_methods", rb_class_instance_methods, -1); /* in class.c */ rb_define_method(rb_cModule, "public_instance_methods", rb_class_public_instance_methods, -1); /* in class.c */ rb_define_method(rb_cModule, "protected_instance_methods", rb_class_protected_instance_methods, -1); /* in class.c */ rb_define_method(rb_cModule, "private_instance_methods", rb_class_private_instance_methods, -1); /* in class.c */ rb_define_method(rb_cModule, "class_variable_defined?", rb_mod_cvar_defined, 1); rb_define_method(rb_cModule, "constants", rb_mod_constants, 0); /* in variable.c */ rb_define_method(rb_cModule, "const_get", rb_mod_const_get, 1); rb_define_method(rb_cModule, "const_set", rb_mod_const_set, 2); rb_define_method(rb_cModule, "const_defined?", rb_mod_const_defined, 1); rb_define_private_method(rb_cModule, "remove_const", rb_mod_remove_const, 1); /* in variable.c */ rb_define_method(rb_cModule, "const_missing", rb_mod_const_missing, 1); /* in variable.c */ rb_define_method(rb_cModule, "class_variables", rb_mod_class_variables, 0); /* in variable.c */ rb_define_private_method(rb_cModule, "remove_class_variable", rb_mod_remove_cvar, 1); /* in variable.c */ rb_define_private_method(rb_cModule, "class_variable_get", rb_mod_cvar_get, 1); rb_define_private_method(rb_cModule, "class_variable_set", rb_mod_cvar_set, 2); rb_define_method(rb_cClass, "allocate", rb_obj_alloc, 0); rb_define_method(rb_cClass, "new", rb_class_new_instance, -1); rb_define_method(rb_cClass, "initialize", rb_class_initialize, -1); rb_define_method(rb_cClass, "initialize_copy", rb_class_init_copy, 1); /* in class.c */ rb_define_method(rb_cClass, "superclass", rb_class_superclass, 0); rb_define_alloc_func(rb_cClass, rb_class_s_alloc); rb_undef_method(rb_cClass, "extend_object"); rb_undef_method(rb_cClass, "append_features"); rb_cData = rb_define_class("Data", rb_cObject); rb_undef_alloc_func(rb_cData); rb_global_variable(&ruby_top_self); ruby_top_self = rb_obj_alloc(rb_cObject); rb_define_singleton_method(ruby_top_self, "to_s", main_to_s, 0); rb_cTrueClass = rb_define_class("TrueClass", rb_cObject); rb_define_method(rb_cTrueClass, "to_s", true_to_s, 0); rb_define_method(rb_cTrueClass, "&", true_and, 1); rb_define_method(rb_cTrueClass, "|", true_or, 1); rb_define_method(rb_cTrueClass, "^", true_xor, 1); rb_undef_alloc_func(rb_cTrueClass); rb_undef_method(CLASS_OF(rb_cTrueClass), "new"); rb_define_global_const("TRUE", Qtrue); rb_cFalseClass = rb_define_class("FalseClass", rb_cObject); rb_define_method(rb_cFalseClass, "to_s", false_to_s, 0); rb_define_method(rb_cFalseClass, "&", false_and, 1); rb_define_method(rb_cFalseClass, "|", false_or, 1); rb_define_method(rb_cFalseClass, "^", false_xor, 1); rb_undef_alloc_func(rb_cFalseClass); rb_undef_method(CLASS_OF(rb_cFalseClass), "new"); rb_define_global_const("FALSE", Qfalse); id_eq = rb_intern("=="); id_eql = rb_intern("eql?"); id_inspect = rb_intern("inspect"); id_init_copy = rb_intern("initialize_copy"); } ================================================ FILE: pack.c ================================================ /********************************************************************** pack.c - $Author$ $Date$ created at: Thu Feb 10 15:17:05 JST 1994 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #include "ruby.h" #include #include #define SIZE16 2 #define SIZE32 4 #if SIZEOF_SHORT != 2 || SIZEOF_LONG != 4 # define NATINT_PACK #endif #ifdef NATINT_PACK # define OFF16B(p) ((char*)(p) + (natint?0:(sizeof(short) - SIZE16))) # define OFF32B(p) ((char*)(p) + (natint?0:(sizeof(long) - SIZE32))) # define NATINT_LEN(type,len) (natint?sizeof(type):(len)) # ifdef WORDS_BIGENDIAN # define OFF16(p) OFF16B(p) # define OFF32(p) OFF32B(p) # endif # define NATINT_HTOVS(x) (natint?htovs(x):htov16(x)) # define NATINT_HTOVL(x) (natint?htovl(x):htov32(x)) # define NATINT_HTONS(x) (natint?htons(x):hton16(x)) # define NATINT_HTONL(x) (natint?htonl(x):hton32(x)) #else # define NATINT_LEN(type,len) sizeof(type) # define NATINT_HTOVS(x) htovs(x) # define NATINT_HTOVL(x) htovl(x) # define NATINT_HTONS(x) htons(x) # define NATINT_HTONL(x) htonl(x) #endif #ifndef OFF16 # define OFF16(p) (char*)(p) # define OFF32(p) (char*)(p) #endif #ifndef OFF16B # define OFF16B(p) (char*)(p) # define OFF32B(p) (char*)(p) #endif #define define_swapx(x, xtype) \ static xtype \ TOKEN_PASTE(swap,x)(z) \ xtype z; \ { \ xtype r; \ xtype *zp; \ unsigned char *s, *t; \ int i; \ \ zp = xmalloc(sizeof(xtype)); \ *zp = z; \ s = (unsigned char*)zp; \ t = xmalloc(sizeof(xtype)); \ for (i=0; i>8)&0xFF)) #endif #if SIZEOF_SHORT == 2 #define swaps(x) swap16(x) #else #if SIZEOF_SHORT == 4 #define swaps(x) ((((x)&0xFF)<<24) \ |(((x)>>24)&0xFF) \ |(((x)&0x0000FF00)<<8) \ |(((x)&0x00FF0000)>>8) ) #else define_swapx(s,short) #endif #endif #ifndef swap32 #define swap32(x) ((((x)&0xFF)<<24) \ |(((x)>>24)&0xFF) \ |(((x)&0x0000FF00)<<8) \ |(((x)&0x00FF0000)>>8) ) #endif #if SIZEOF_LONG == 4 #define swapl(x) swap32(x) #else #if SIZEOF_LONG == 8 #define swapl(x) ((((x)&0x00000000000000FF)<<56) \ |(((x)&0xFF00000000000000)>>56) \ |(((x)&0x000000000000FF00)<<40) \ |(((x)&0x00FF000000000000)>>40) \ |(((x)&0x0000000000FF0000)<<24) \ |(((x)&0x0000FF0000000000)>>24) \ |(((x)&0x00000000FF000000)<<8) \ |(((x)&0x000000FF00000000)>>8)) #else define_swapx(l,long) #endif #endif #if SIZEOF_FLOAT == 4 #if SIZEOF_LONG == 4 /* SIZEOF_FLOAT == 4 == SIZEOF_LONG */ #define swapf(x) swapl(x) #define FLOAT_SWAPPER unsigned long #else #if SIZEOF_SHORT == 4 /* SIZEOF_FLOAT == 4 == SIZEOF_SHORT */ #define swapf(x) swaps(x) #define FLOAT_SWAPPER unsigned short #else /* SIZEOF_FLOAT == 4 but undivide by known size of int */ define_swapx(f,float) #endif /* #if SIZEOF_SHORT == 4 */ #endif /* #if SIZEOF_LONG == 4 */ #else /* SIZEOF_FLOAT != 4 */ define_swapx(f,float) #endif /* #if SIZEOF_FLOAT == 4 */ #if SIZEOF_DOUBLE == 8 #if SIZEOF_LONG == 8 /* SIZEOF_DOUBLE == 8 == SIZEOF_LONG */ #define swapd(x) swapl(x) #define DOUBLE_SWAPPER unsigned long #else #if SIZEOF_LONG == 4 /* SIZEOF_DOUBLE == 8 && 4 == SIZEOF_LONG */ static double swapd(d) const double d; { double dtmp = d; unsigned long utmp[2]; unsigned long utmp0; utmp[0] = 0; utmp[1] = 0; memcpy(utmp,&dtmp,sizeof(double)); utmp0 = utmp[0]; utmp[0] = swapl(utmp[1]); utmp[1] = swapl(utmp0); memcpy(&dtmp,utmp,sizeof(double)); return dtmp; } #else #if SIZEOF_SHORT == 4 /* SIZEOF_DOUBLE == 8 && 4 == SIZEOF_SHORT */ static double swapd(d) const double d; { double dtmp = d; unsigned short utmp[2]; unsigned short utmp0; utmp[0] = 0; utmp[1] = 0; memcpy(utmp,&dtmp,sizeof(double)); utmp0 = utmp[0]; utmp[0] = swaps(utmp[1]); utmp[1] = swaps(utmp0); memcpy(&dtmp,utmp,sizeof(double)); return dtmp; } #else /* SIZEOF_DOUBLE == 8 but undivied by known size of int */ define_swapx(d, double) #endif /* #if SIZEOF_SHORT == 4 */ #endif /* #if SIZEOF_LONG == 4 */ #endif /* #if SIZEOF_LONG == 8 */ #else /* SIZEOF_DOUBLE != 8 */ define_swapx(d, double) #endif /* #if SIZEOF_DOUBLE == 8 */ #undef define_swapx #ifdef DYNAMIC_ENDIAN #ifdef ntohs #undef ntohs #undef ntohl #undef htons #undef htonl #endif static int endian() { static int init = 0; static int endian_value; char *p; if (init) return endian_value; init = 1; p = (char*)&init; return endian_value = p[0]?0:1; } #define ntohs(x) (endian()?(x):swaps(x)) #define ntohl(x) (endian()?(x):swapl(x)) #define ntohf(x) (endian()?(x):swapf(x)) #define ntohd(x) (endian()?(x):swapd(x)) #define htons(x) (endian()?(x):swaps(x)) #define htonl(x) (endian()?(x):swapl(x)) #define htonf(x) (endian()?(x):swapf(x)) #define htond(x) (endian()?(x):swapd(x)) #define htovs(x) (endian()?swaps(x):(x)) #define htovl(x) (endian()?swapl(x):(x)) #define htovf(x) (endian()?swapf(x):(x)) #define htovd(x) (endian()?swapd(x):(x)) #define vtohs(x) (endian()?swaps(x):(x)) #define vtohl(x) (endian()?swapl(x):(x)) #define vtohf(x) (endian()?swapf(x):(x)) #define vtohd(x) (endian()?swapd(x):(x)) # ifdef NATINT_PACK #define htov16(x) (endian()?swap16(x):(x)) #define htov32(x) (endian()?swap32(x):(x)) #define hton16(x) (endian()?(x):swap16(x)) #define hton32(x) (endian()?(x):swap32(x)) # endif #else #ifdef WORDS_BIGENDIAN #ifndef ntohs #define ntohs(x) (x) #define ntohl(x) (x) #define htons(x) (x) #define htonl(x) (x) #endif #define ntohf(x) (x) #define ntohd(x) (x) #define htonf(x) (x) #define htond(x) (x) #define htovs(x) swaps(x) #define htovl(x) swapl(x) #define htovf(x) swapf(x) #define htovd(x) swapd(x) #define vtohs(x) swaps(x) #define vtohl(x) swapl(x) #define vtohf(x) swapf(x) #define vtohd(x) swapd(x) # ifdef NATINT_PACK #define htov16(x) swap16(x) #define htov32(x) swap32(x) #define hton16(x) (x) #define hton32(x) (x) # endif #else /* LITTLE ENDIAN */ #ifdef ntohs #undef ntohs #undef ntohl #undef htons #undef htonl #endif #define ntohs(x) swaps(x) #define ntohl(x) swapl(x) #define htons(x) swaps(x) #define htonl(x) swapl(x) #define ntohf(x) swapf(x) #define ntohd(x) swapd(x) #define htonf(x) swapf(x) #define htond(x) swapd(x) #define htovs(x) (x) #define htovl(x) (x) #define htovf(x) (x) #define htovd(x) (x) #define vtohs(x) (x) #define vtohl(x) (x) #define vtohf(x) (x) #define vtohd(x) (x) # ifdef NATINT_PACK #define htov16(x) (x) #define htov32(x) (x) #define hton16(x) swap16(x) #define hton32(x) swap32(x) # endif #endif #endif #ifdef FLOAT_SWAPPER #define FLOAT_CONVWITH(y) FLOAT_SWAPPER y; #define HTONF(x,y) (memcpy(&y,&x,sizeof(float)), \ y = htonf((FLOAT_SWAPPER)y), \ memcpy(&x,&y,sizeof(float)), \ x) #define HTOVF(x,y) (memcpy(&y,&x,sizeof(float)), \ y = htovf((FLOAT_SWAPPER)y), \ memcpy(&x,&y,sizeof(float)), \ x) #define NTOHF(x,y) (memcpy(&y,&x,sizeof(float)), \ y = ntohf((FLOAT_SWAPPER)y), \ memcpy(&x,&y,sizeof(float)), \ x) #define VTOHF(x,y) (memcpy(&y,&x,sizeof(float)), \ y = vtohf((FLOAT_SWAPPER)y), \ memcpy(&x,&y,sizeof(float)), \ x) #else #define FLOAT_CONVWITH(y) #define HTONF(x,y) htonf(x) #define HTOVF(x,y) htovf(x) #define NTOHF(x,y) ntohf(x) #define VTOHF(x,y) vtohf(x) #endif #ifdef DOUBLE_SWAPPER #define DOUBLE_CONVWITH(y) DOUBLE_SWAPPER y; #define HTOND(x,y) (memcpy(&y,&x,sizeof(double)), \ y = htond((DOUBLE_SWAPPER)y), \ memcpy(&x,&y,sizeof(double)), \ x) #define HTOVD(x,y) (memcpy(&y,&x,sizeof(double)), \ y = htovd((DOUBLE_SWAPPER)y), \ memcpy(&x,&y,sizeof(double)), \ x) #define NTOHD(x,y) (memcpy(&y,&x,sizeof(double)), \ y = ntohd((DOUBLE_SWAPPER)y), \ memcpy(&x,&y,sizeof(double)), \ x) #define VTOHD(x,y) (memcpy(&y,&x,sizeof(double)), \ y = vtohd((DOUBLE_SWAPPER)y), \ memcpy(&x,&y,sizeof(double)), \ x) #else #define DOUBLE_CONVWITH(y) #define HTOND(x,y) htond(x) #define HTOVD(x,y) htovd(x) #define NTOHD(x,y) ntohd(x) #define VTOHD(x,y) vtohd(x) #endif unsigned long rb_big2ulong_pack _((VALUE x)); static unsigned long num2i32(x) VALUE x; { x = rb_to_int(x); /* is nil OK? (should not) */ if (FIXNUM_P(x)) return FIX2LONG(x); if (TYPE(x) == T_BIGNUM) { return rb_big2ulong_pack(x); } rb_raise(rb_eTypeError, "can't convert %s to `integer'", rb_obj_classname(x)); return 0; /* not reached */ } #if SIZEOF_LONG == SIZE32 # define EXTEND32(x) #else /* invariant in modulo 1<<31 */ # define EXTEND32(x) do { if (!natint) {(x) = (((1L<<31)-1-(x))^~(~0L<<31));}} while(0) #endif #if SIZEOF_SHORT == SIZE16 # define EXTEND16(x) #else # define EXTEND16(x) do { if (!natint) {(x) = (short)(((1<<15)-1-(x))^~(~0<<15));}} while(0) #endif #ifdef HAVE_LONG_LONG # define QUAD_SIZE sizeof(LONG_LONG) #else # define QUAD_SIZE 8 #endif static const char toofew[] = "too few arguments"; static void encodes _((VALUE,const char*,long,int)); static void qpencode _((VALUE,VALUE,long)); static int uv_to_utf8 _((char*,unsigned long)); static unsigned long utf8_to_uv _((char*,long*)); /* * call-seq: * arr.pack ( aTemplateString ) -> aBinaryString * * Packs the contents of arr into a binary sequence according to * the directives in aTemplateString (see the table below) * Directives ``A,'' ``a,'' and ``Z'' may be followed by a count, * which gives the width of the resulting field. The remaining * directives also may take a count, indicating the number of array * elements to convert. If the count is an asterisk * (``*''), all remaining array elements will be * converted. Any of the directives ``sSiIlL'' may be * followed by an underscore (``_'') to use the underlying * platform's native size for the specified type; otherwise, they use a * platform-independent size. Spaces are ignored in the template * string. See also String#unpack. * * a = [ "a", "b", "c" ] * n = [ 65, 66, 67 ] * a.pack("A3A3A3") #=> "a b c " * a.pack("a3a3a3") #=> "a\000\000b\000\000c\000\000" * n.pack("ccc") #=> "ABC" * * Directives for +pack+. * * Directive Meaning * --------------------------------------------------------------- * @ | Moves to absolute position * A | ASCII string (space padded, count is width) * a | ASCII string (null padded, count is width) * B | Bit string (descending bit order) * b | Bit string (ascending bit order) * C | Unsigned char * c | Char * D, d | Double-precision float, native format * E | Double-precision float, little-endian byte order * e | Single-precision float, little-endian byte order * F, f | Single-precision float, native format * G | Double-precision float, network (big-endian) byte order * g | Single-precision float, network (big-endian) byte order * H | Hex string (high nibble first) * h | Hex string (low nibble first) * I | Unsigned integer * i | Integer * L | Unsigned long * l | Long * M | Quoted printable, MIME encoding (see RFC2045) * m | Base64 encoded string * N | Long, network (big-endian) byte order * n | Short, network (big-endian) byte-order * P | Pointer to a structure (fixed-length string) * p | Pointer to a null-terminated string * Q, q | 64-bit number * S | Unsigned short * s | Short * U | UTF-8 * u | UU-encoded string * V | Long, little-endian byte order * v | Short, little-endian byte order * w | BER-compressed integer\fnm * X | Back up a byte * x | Null byte * Z | Same as ``a'', except that null is added with * */ static VALUE pack_pack(ary, fmt) VALUE ary, fmt; { static const char nul10[] = "\0\0\0\0\0\0\0\0\0\0"; static const char spc10[] = " "; char *p, *pend; VALUE res, from, associates = 0; char type; long items, len, idx, plen; const char *ptr; #ifdef NATINT_PACK int natint; /* native integer */ #endif StringValue(fmt); p = RSTRING(fmt)->ptr; pend = p + RSTRING(fmt)->len; res = rb_str_buf_new(0); items = RARRAY(ary)->len; idx = 0; #define TOO_FEW (rb_raise(rb_eArgError, toofew), 0) #define THISFROM (items > 0 ? RARRAY(ary)->ptr[idx] : TOO_FEW) #define NEXTFROM (items-- > 0 ? RARRAY(ary)->ptr[idx++] : TOO_FEW) while (p < pend) { if (RSTRING(fmt)->ptr + RSTRING(fmt)->len != pend) { rb_raise(rb_eRuntimeError, "format string modified"); } type = *p++; /* get data type */ #ifdef NATINT_PACK natint = 0; #endif if (ISSPACE(type)) continue; if (type == '#') { while ((p < pend) && (*p != '\n')) { p++; } continue; } if (*p == '_' || *p == '!') { const char *natstr = "sSiIlL"; if (strchr(natstr, type)) { #ifdef NATINT_PACK natint = 1; #endif p++; } else { rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, natstr); } } if (*p == '*') { /* set data length */ len = strchr("@Xxu", type) ? 0 : strchr("PMm", type) ? 1 : items; p++; } else if (ISDIGIT(*p)) { len = strtoul(p, (char**)&p, 10); } else { len = 1; } switch (type) { case 'A': case 'a': case 'Z': case 'B': case 'b': case 'H': case 'h': from = NEXTFROM; if (NIL_P(from)) { ptr = ""; plen = 0; } else { StringValue(from); ptr = RSTRING(from)->ptr; plen = RSTRING(from)->len; OBJ_INFECT(res, from); } if (p[-1] == '*') len = plen; switch (type) { case 'a': /* arbitrary binary string (null padded) */ case 'A': /* ASCII string (space padded) */ case 'Z': /* null terminated ASCII string */ if (plen >= len) { rb_str_buf_cat(res, ptr, len); if (p[-1] == '*' && type == 'Z') rb_str_buf_cat(res, nul10, 1); } else { rb_str_buf_cat(res, ptr, plen); len -= plen; while (len >= 10) { rb_str_buf_cat(res, (type == 'A')?spc10:nul10, 10); len -= 10; } rb_str_buf_cat(res, (type == 'A')?spc10:nul10, len); } break; case 'b': /* bit string (ascending) */ { int byte = 0; long i, j = 0; if (len > plen) { j = (len - plen + 1)/2; len = plen; } for (i=0; i++ < len; ptr++) { if (*ptr & 1) byte |= 128; if (i & 7) byte >>= 1; else { char c = byte & 0xff; rb_str_buf_cat(res, &c, 1); byte = 0; } } if (len & 7) { char c; byte >>= 7 - (len & 7); c = byte & 0xff; rb_str_buf_cat(res, &c, 1); } len = j; goto grow; } break; case 'B': /* bit string (descending) */ { int byte = 0; long i, j = 0; if (len > plen) { j = (len - plen + 1)/2; len = plen; } for (i=0; i++ < len; ptr++) { byte |= *ptr & 1; if (i & 7) byte <<= 1; else { char c = byte & 0xff; rb_str_buf_cat(res, &c, 1); byte = 0; } } if (len & 7) { char c; byte <<= 7 - (len & 7); c = byte & 0xff; rb_str_buf_cat(res, &c, 1); } len = j; goto grow; } break; case 'h': /* hex string (low nibble first) */ { int byte = 0; long i, j = 0; if (len > plen) { j = (len + 1) / 2 - (plen + 1) / 2; len = plen; } for (i=0; i++ < len; ptr++) { if (ISALPHA(*ptr)) byte |= (((*ptr & 15) + 9) & 15) << 4; else byte |= (*ptr & 15) << 4; if (i & 1) byte >>= 4; else { char c = byte & 0xff; rb_str_buf_cat(res, &c, 1); byte = 0; } } if (len & 1) { char c = byte & 0xff; rb_str_buf_cat(res, &c, 1); } len = j; goto grow; } break; case 'H': /* hex string (high nibble first) */ { int byte = 0; long i, j = 0; if (len > plen) { j = (len + 1) / 2 - (plen + 1) / 2; len = plen; } for (i=0; i++ < len; ptr++) { if (ISALPHA(*ptr)) byte |= ((*ptr & 15) + 9) & 15; else byte |= *ptr & 15; if (i & 1) byte <<= 4; else { char c = byte & 0xff; rb_str_buf_cat(res, &c, 1); byte = 0; } } if (len & 1) { char c = byte & 0xff; rb_str_buf_cat(res, &c, 1); } len = j; goto grow; } break; } break; case 'c': /* signed char */ case 'C': /* unsigned char */ while (len-- > 0) { char c; from = NEXTFROM; c = num2i32(from); rb_str_buf_cat(res, &c, sizeof(char)); } break; case 's': /* signed short */ case 'S': /* unsigned short */ while (len-- > 0) { short s; from = NEXTFROM; s = num2i32(from); rb_str_buf_cat(res, OFF16(&s), NATINT_LEN(short,2)); } break; case 'i': /* signed int */ case 'I': /* unsigned int */ while (len-- > 0) { long i; from = NEXTFROM; i = num2i32(from); rb_str_buf_cat(res, OFF32(&i), NATINT_LEN(int,4)); } break; case 'l': /* signed long */ case 'L': /* unsigned long */ while (len-- > 0) { long l; from = NEXTFROM; l = num2i32(from); rb_str_buf_cat(res, OFF32(&l), NATINT_LEN(long,4)); } break; case 'q': /* signed quad (64bit) int */ case 'Q': /* unsigned quad (64bit) int */ while (len-- > 0) { char tmp[QUAD_SIZE]; from = NEXTFROM; rb_quad_pack(tmp, from); rb_str_buf_cat(res, (char*)&tmp, QUAD_SIZE); } break; case 'n': /* unsigned short (network byte-order) */ while (len-- > 0) { unsigned short s; from = NEXTFROM; s = num2i32(from); s = NATINT_HTONS(s); rb_str_buf_cat(res, OFF16(&s), NATINT_LEN(short,2)); } break; case 'N': /* unsigned long (network byte-order) */ while (len-- > 0) { unsigned long l; from = NEXTFROM; l = num2i32(from); l = NATINT_HTONL(l); rb_str_buf_cat(res, OFF32(&l), NATINT_LEN(long,4)); } break; case 'v': /* unsigned short (VAX byte-order) */ while (len-- > 0) { unsigned short s; from = NEXTFROM; s = num2i32(from); s = NATINT_HTOVS(s); rb_str_buf_cat(res, OFF16(&s), NATINT_LEN(short,2)); } break; case 'V': /* unsigned long (VAX byte-order) */ while (len-- > 0) { unsigned long l; from = NEXTFROM; l = num2i32(from); l = NATINT_HTOVL(l); rb_str_buf_cat(res, OFF32(&l), NATINT_LEN(long,4)); } break; case 'f': /* single precision float in native format */ case 'F': /* ditto */ while (len-- > 0) { float f; from = NEXTFROM; f = RFLOAT(rb_Float(from))->value; rb_str_buf_cat(res, (char*)&f, sizeof(float)); } break; case 'e': /* single precision float in VAX byte-order */ while (len-- > 0) { float f; FLOAT_CONVWITH(ftmp); from = NEXTFROM; f = RFLOAT(rb_Float(from))->value; f = HTOVF(f,ftmp); rb_str_buf_cat(res, (char*)&f, sizeof(float)); } break; case 'E': /* double precision float in VAX byte-order */ while (len-- > 0) { double d; DOUBLE_CONVWITH(dtmp); from = NEXTFROM; d = RFLOAT(rb_Float(from))->value; d = HTOVD(d,dtmp); rb_str_buf_cat(res, (char*)&d, sizeof(double)); } break; case 'd': /* double precision float in native format */ case 'D': /* ditto */ while (len-- > 0) { double d; from = NEXTFROM; d = RFLOAT(rb_Float(from))->value; rb_str_buf_cat(res, (char*)&d, sizeof(double)); } break; case 'g': /* single precision float in network byte-order */ while (len-- > 0) { float f; FLOAT_CONVWITH(ftmp); from = NEXTFROM; f = RFLOAT(rb_Float(from))->value; f = HTONF(f,ftmp); rb_str_buf_cat(res, (char*)&f, sizeof(float)); } break; case 'G': /* double precision float in network byte-order */ while (len-- > 0) { double d; DOUBLE_CONVWITH(dtmp); from = NEXTFROM; d = RFLOAT(rb_Float(from))->value; d = HTOND(d,dtmp); rb_str_buf_cat(res, (char*)&d, sizeof(double)); } break; case 'x': /* null byte */ grow: while (len >= 10) { rb_str_buf_cat(res, nul10, 10); len -= 10; } rb_str_buf_cat(res, nul10, len); break; case 'X': /* back up byte */ shrink: plen = RSTRING(res)->len; if (plen < len) rb_raise(rb_eArgError, "X outside of string"); RSTRING(res)->len = plen - len; RSTRING(res)->ptr[plen - len] = '\0'; break; case '@': /* null fill to absolute position */ len -= RSTRING(res)->len; if (len > 0) goto grow; len = -len; if (len > 0) goto shrink; break; case '%': rb_raise(rb_eArgError, "%% is not supported"); break; case 'U': /* Unicode character */ while (len-- > 0) { long l; char buf[8]; int le; from = NEXTFROM; from = rb_to_int(from); l = NUM2INT(from); if (l < 0) { rb_raise(rb_eRangeError, "pack(U): value out of range"); } le = uv_to_utf8(buf, l); rb_str_buf_cat(res, (char*)buf, le); } break; case 'u': /* uuencoded string */ case 'm': /* base64 encoded string */ from = NEXTFROM; StringValue(from); ptr = RSTRING(from)->ptr; plen = RSTRING(from)->len; if (len <= 2) len = 45; else len = len / 3 * 3; while (plen > 0) { long todo; if (plen > len) todo = len; else todo = plen; encodes(res, ptr, todo, type); plen -= todo; ptr += todo; } break; case 'M': /* quoted-printable encoded string */ from = rb_obj_as_string(NEXTFROM); if (len <= 1) len = 72; qpencode(res, from, len); break; case 'P': /* pointer to packed byte string */ from = THISFROM; if (!NIL_P(from)) { StringValue(from); if (RSTRING(from)->len < len) { rb_raise(rb_eArgError, "too short buffer for P(%ld for %ld)", RSTRING(from)->len, len); } } len = 1; /* FALL THROUGH */ case 'p': /* pointer to string */ while (len-- > 0) { char *t; from = NEXTFROM; if (NIL_P(from)) { t = 0; } else { t = StringValuePtr(from); } if (!associates) { associates = rb_ary_new(); } rb_ary_push(associates, from); rb_obj_taint(from); rb_str_buf_cat(res, (char*)&t, sizeof(char*)); } break; case 'w': /* BER compressed integer */ while (len-- > 0) { unsigned long ul; VALUE buf = rb_str_new(0, 0); char c, *bufs, *bufe; from = NEXTFROM; if (TYPE(from) == T_BIGNUM) { VALUE big128 = rb_uint2big(128); while (TYPE(from) == T_BIGNUM) { from = rb_big_divmod(from, big128); c = NUM2INT(RARRAY(from)->ptr[1]) | 0x80; /* mod */ rb_str_buf_cat(buf, &c, sizeof(char)); from = RARRAY(from)->ptr[0]; /* div */ } } { long l = NUM2LONG(from); if (l < 0) { rb_raise(rb_eArgError, "can't compress negative numbers"); } ul = l; } while (ul) { c = ((ul & 0x7f) | 0x80); rb_str_buf_cat(buf, &c, sizeof(char)); ul >>= 7; } if (RSTRING(buf)->len) { bufs = RSTRING(buf)->ptr; bufe = bufs + RSTRING(buf)->len - 1; *bufs &= 0x7f; /* clear continue bit */ while (bufs < bufe) { /* reverse */ c = *bufs; *bufs++ = *bufe; *bufe-- = c; } rb_str_buf_cat(res, RSTRING(buf)->ptr, RSTRING(buf)->len); } else { c = 0; rb_str_buf_cat(res, &c, sizeof(char)); } } break; default: break; } } if (associates) { rb_str_associate(res, associates); } OBJ_INFECT(res, fmt); return res; } static const char uu_table[] = "`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"; static const char b64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static void encodes(str, s, len, type) VALUE str; const char *s; long len; int type; { char *buff = ALLOCA_N(char, len * 4 / 3 + 6); long i = 0; const char *trans = type == 'u' ? uu_table : b64_table; int padding; if (type == 'u') { buff[i++] = len + ' '; padding = '`'; } else { padding = '='; } while (len >= 3) { buff[i++] = trans[077 & (*s >> 2)]; buff[i++] = trans[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))]; buff[i++] = trans[077 & (((s[1] << 2) & 074) | ((s[2] >> 6) & 03))]; buff[i++] = trans[077 & s[2]]; s += 3; len -= 3; } if (len == 2) { buff[i++] = trans[077 & (*s >> 2)]; buff[i++] = trans[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))]; buff[i++] = trans[077 & (((s[1] << 2) & 074) | (('\0' >> 6) & 03))]; buff[i++] = padding; } else if (len == 1) { buff[i++] = trans[077 & (*s >> 2)]; buff[i++] = trans[077 & (((*s << 4) & 060) | (('\0' >> 4) & 017))]; buff[i++] = padding; buff[i++] = padding; } buff[i++] = '\n'; rb_str_buf_cat(str, buff, i); } static char hex_table[] = "0123456789ABCDEF"; static void qpencode(str, from, len) VALUE str, from; long len; { char buff[1024]; long i = 0, n = 0, prev = EOF; unsigned char *s = (unsigned char*)RSTRING(from)->ptr; unsigned char *send = s + RSTRING(from)->len; while (s < send) { if ((*s > 126) || (*s < 32 && *s != '\n' && *s != '\t') || (*s == '=')) { buff[i++] = '='; buff[i++] = hex_table[*s >> 4]; buff[i++] = hex_table[*s & 0x0f]; n += 3; prev = EOF; } else if (*s == '\n') { if (prev == ' ' || prev == '\t') { buff[i++] = '='; buff[i++] = *s; } buff[i++] = *s; n = 0; prev = *s; } else { buff[i++] = *s; n++; prev = *s; } if (n > len) { buff[i++] = '='; buff[i++] = '\n'; n = 0; prev = '\n'; } if (i > 1024 - 5) { rb_str_buf_cat(str, buff, i); i = 0; } s++; } if (n > 0) { buff[i++] = '='; buff[i++] = '\n'; } if (i > 0) { rb_str_buf_cat(str, buff, i); } } static inline int hex2num(c) char c; { switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return c - '0'; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': return c - 'a' + 10; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': return c - 'A' + 10; default: return -1; } } #define PACK_LENGTH_ADJUST_SIZE(sz) do { \ tmp = 0; \ if (len > (send-s)/sz) { \ if (!star) { \ tmp = len-(send-s)/sz; \ } \ len = (send-s)/sz; \ } \ } while (0) #ifdef NATINT_PACK #define PACK_LENGTH_ADJUST(type,sz) do { \ int t__len = NATINT_LEN(type,(sz)); \ PACK_LENGTH_ADJUST_SIZE(t__len); \ } while (0) #else #define PACK_LENGTH_ADJUST(type,sz) \ PACK_LENGTH_ADJUST_SIZE(sizeof(type)) #endif #define PACK_ITEM_ADJUST() while (tmp--) rb_ary_push(ary, Qnil) static VALUE infected_str_new(ptr, len, str) const char *ptr; long len; VALUE str; { VALUE s = rb_str_new(ptr, len); OBJ_INFECT(s, str); return s; } /* * call-seq: * str.unpack(format) => anArray * * Decodes str (which may contain binary data) according to the * format string, returning an array of each value extracted. The * format string consists of a sequence of single-character directives, * summarized in the table at the end of this entry. * Each directive may be followed * by a number, indicating the number of times to repeat with this * directive. An asterisk (``*'') will use up all * remaining elements. The directives sSiIlL may each be * followed by an underscore (``_'') to use the underlying * platform's native size for the specified type; otherwise, it uses a * platform-independent consistent size. Spaces are ignored in the * format string. See also Array#pack. * * "abc \0\0abc \0\0".unpack('A6Z6') #=> ["abc", "abc "] * "abc \0\0".unpack('a3a3') #=> ["abc", " \000\000"] * "abc \0abc \0".unpack('Z*Z*') #=> ["abc ", "abc "] * "aa".unpack('b8B8') #=> ["10000110", "01100001"] * "aaa".unpack('h2H2c') #=> ["16", "61", 97] * "\xfe\xff\xfe\xff".unpack('sS') #=> [-2, 65534] * "now=20is".unpack('M*') #=> ["now is"] * "whole".unpack('xax2aX2aX1aX2a') #=> ["h", "e", "l", "l", "o"] * * This table summarizes the various formats and the Ruby classes * returned by each. * * Format | Returns | Function * -------+---------+----------------------------------------- * A | String | with trailing nulls and spaces removed * -------+---------+----------------------------------------- * a | String | string * -------+---------+----------------------------------------- * B | String | extract bits from each character (msb first) * -------+---------+----------------------------------------- * b | String | extract bits from each character (lsb first) * -------+---------+----------------------------------------- * C | Fixnum | extract a character as an unsigned integer * -------+---------+----------------------------------------- * c | Fixnum | extract a character as an integer * -------+---------+----------------------------------------- * d,D | Float | treat sizeof(double) characters as * | | a native double * -------+---------+----------------------------------------- * E | Float | treat sizeof(double) characters as * | | a double in little-endian byte order * -------+---------+----------------------------------------- * e | Float | treat sizeof(float) characters as * | | a float in little-endian byte order * -------+---------+----------------------------------------- * f,F | Float | treat sizeof(float) characters as * | | a native float * -------+---------+----------------------------------------- * G | Float | treat sizeof(double) characters as * | | a double in network byte order * -------+---------+----------------------------------------- * g | Float | treat sizeof(float) characters as a * | | float in network byte order * -------+---------+----------------------------------------- * H | String | extract hex nibbles from each character * | | (most significant first) * -------+---------+----------------------------------------- * h | String | extract hex nibbles from each character * | | (least significant first) * -------+---------+----------------------------------------- * I | Integer | treat sizeof(int) (modified by _) * | | successive characters as an unsigned * | | native integer * -------+---------+----------------------------------------- * i | Integer | treat sizeof(int) (modified by _) * | | successive characters as a signed * | | native integer * -------+---------+----------------------------------------- * L | Integer | treat four (modified by _) successive * | | characters as an unsigned native * | | long integer * -------+---------+----------------------------------------- * l | Integer | treat four (modified by _) successive * | | characters as a signed native * | | long integer * -------+---------+----------------------------------------- * M | String | quoted-printable * -------+---------+----------------------------------------- * m | String | base64-encoded * -------+---------+----------------------------------------- * N | Integer | treat four characters as an unsigned * | | long in network byte order * -------+---------+----------------------------------------- * n | Fixnum | treat two characters as an unsigned * | | short in network byte order * -------+---------+----------------------------------------- * P | String | treat sizeof(char *) characters as a * | | pointer, and return \emph{len} characters * | | from the referenced location * -------+---------+----------------------------------------- * p | String | treat sizeof(char *) characters as a * | | pointer to a null-terminated string * -------+---------+----------------------------------------- * Q | Integer | treat 8 characters as an unsigned * | | quad word (64 bits) * -------+---------+----------------------------------------- * q | Integer | treat 8 characters as a signed * | | quad word (64 bits) * -------+---------+----------------------------------------- * S | Fixnum | treat two (different if _ used) * | | successive characters as an unsigned * | | short in native byte order * -------+---------+----------------------------------------- * s | Fixnum | Treat two (different if _ used) * | | successive characters as a signed short * | | in native byte order * -------+---------+----------------------------------------- * U | Integer | UTF-8 characters as unsigned integers * -------+---------+----------------------------------------- * u | String | UU-encoded * -------+---------+----------------------------------------- * V | Fixnum | treat four characters as an unsigned * | | long in little-endian byte order * -------+---------+----------------------------------------- * v | Fixnum | treat two characters as an unsigned * | | short in little-endian byte order * -------+---------+----------------------------------------- * w | Integer | BER-compressed integer (see Array.pack) * -------+---------+----------------------------------------- * X | --- | skip backward one character * -------+---------+----------------------------------------- * x | --- | skip forward one character * -------+---------+----------------------------------------- * Z | String | with trailing nulls removed * | | upto first null with * * -------+---------+----------------------------------------- * @ | --- | skip to the offset given by the * | | length argument * -------+---------+----------------------------------------- */ static VALUE pack_unpack(str, fmt) VALUE str, fmt; { static const char hexdigits[] = "0123456789abcdef0123456789ABCDEFx"; char *s, *send; char *p, *pend; VALUE ary; char type; long len; int tmp, star; #ifdef NATINT_PACK int natint; /* native integer */ #endif StringValue(str); StringValue(fmt); s = RSTRING(str)->ptr; send = s + RSTRING(str)->len; p = RSTRING(fmt)->ptr; pend = p + RSTRING(fmt)->len; ary = rb_ary_new(); while (p < pend) { type = *p++; #ifdef NATINT_PACK natint = 0; #endif if (ISSPACE(type)) continue; if (type == '#') { while ((p < pend) && (*p != '\n')) { p++; } continue; } star = 0; if (*p == '_' || *p == '!') { static const char natstr[] = "sSiIlL"; if (strchr(natstr, type)) { #ifdef NATINT_PACK natint = 1; #endif p++; } else { rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, natstr); } } if (p >= pend) len = 1; else if (*p == '*') { star = 1; len = send - s; p++; } else if (ISDIGIT(*p)) { len = strtoul(p, (char**)&p, 10); } else { len = (type != '@'); } switch (type) { case '%': rb_raise(rb_eArgError, "%% is not supported"); break; case 'A': if (len > send - s) len = send - s; { long end = len; char *t = s + len - 1; while (t >= s) { if (*t != ' ' && *t != '\0') break; t--; len--; } rb_ary_push(ary, infected_str_new(s, len, str)); s += end; } break; case 'Z': { char *t = s; if (len > send-s) len = send-s; while (t < s+len && *t) t++; rb_ary_push(ary, infected_str_new(s, t-s, str)); if (t < send) t++; s = star ? t : s+len; } break; case 'a': if (len > send - s) len = send - s; rb_ary_push(ary, infected_str_new(s, len, str)); s += len; break; case 'b': { VALUE bitstr; char *t; int bits; long i; if (p[-1] == '*' || len > (send - s) * 8) len = (send - s) * 8; bits = 0; rb_ary_push(ary, bitstr = rb_str_new(0, len)); t = RSTRING(bitstr)->ptr; for (i=0; i>= 1; else bits = *s++; *t++ = (bits & 1) ? '1' : '0'; } } break; case 'B': { VALUE bitstr; char *t; int bits; long i; if (p[-1] == '*' || len > (send - s) * 8) len = (send - s) * 8; bits = 0; rb_ary_push(ary, bitstr = rb_str_new(0, len)); t = RSTRING(bitstr)->ptr; for (i=0; i (send - s) * 2) len = (send - s) * 2; bits = 0; rb_ary_push(ary, bitstr = rb_str_new(0, len)); t = RSTRING(bitstr)->ptr; for (i=0; i>= 4; else bits = *s++; *t++ = hexdigits[bits & 15]; } } break; case 'H': { VALUE bitstr; char *t; int bits; long i; if (p[-1] == '*' || len > (send - s) * 2) len = (send - s) * 2; bits = 0; rb_ary_push(ary, bitstr = rb_str_new(0, len)); t = RSTRING(bitstr)->ptr; for (i=0; i> 4) & 15]; } } break; case 'c': PACK_LENGTH_ADJUST(char,sizeof(char)); while (len-- > 0) { int c = *s++; if (c > (char)127) c-=256; rb_ary_push(ary, INT2FIX(c)); } PACK_ITEM_ADJUST(); break; case 'C': PACK_LENGTH_ADJUST(unsigned char,sizeof(unsigned char)); while (len-- > 0) { unsigned char c = *s++; rb_ary_push(ary, INT2FIX(c)); } PACK_ITEM_ADJUST(); break; case 's': PACK_LENGTH_ADJUST(short,2); while (len-- > 0) { short tmp = 0; memcpy(OFF16(&tmp), s, NATINT_LEN(short,2)); EXTEND16(tmp); s += NATINT_LEN(short,2); rb_ary_push(ary, INT2FIX(tmp)); } PACK_ITEM_ADJUST(); break; case 'S': PACK_LENGTH_ADJUST(unsigned short,2); while (len-- > 0) { unsigned short tmp = 0; memcpy(OFF16(&tmp), s, NATINT_LEN(unsigned short,2)); s += NATINT_LEN(unsigned short,2); rb_ary_push(ary, INT2FIX(tmp)); } PACK_ITEM_ADJUST(); break; case 'i': PACK_LENGTH_ADJUST(int,sizeof(int)); while (len-- > 0) { int tmp; memcpy(&tmp, s, sizeof(int)); s += sizeof(int); rb_ary_push(ary, INT2NUM(tmp)); } PACK_ITEM_ADJUST(); break; case 'I': PACK_LENGTH_ADJUST(unsigned int,sizeof(unsigned int)); while (len-- > 0) { unsigned int tmp; memcpy(&tmp, s, sizeof(unsigned int)); s += sizeof(unsigned int); rb_ary_push(ary, UINT2NUM(tmp)); } PACK_ITEM_ADJUST(); break; case 'l': PACK_LENGTH_ADJUST(long,4); while (len-- > 0) { long tmp = 0; memcpy(OFF32(&tmp), s, NATINT_LEN(long,4)); EXTEND32(tmp); s += NATINT_LEN(long,4); rb_ary_push(ary, LONG2NUM(tmp)); } PACK_ITEM_ADJUST(); break; case 'L': PACK_LENGTH_ADJUST(unsigned long,4); while (len-- > 0) { unsigned long tmp = 0; memcpy(OFF32(&tmp), s, NATINT_LEN(unsigned long,4)); s += NATINT_LEN(unsigned long,4); rb_ary_push(ary, ULONG2NUM(tmp)); } PACK_ITEM_ADJUST(); break; case 'q': PACK_LENGTH_ADJUST_SIZE(QUAD_SIZE); while (len-- > 0) { char *tmp = (char*)s; s += QUAD_SIZE; rb_ary_push(ary, rb_quad_unpack(tmp, 1)); } PACK_ITEM_ADJUST(); break; case 'Q': PACK_LENGTH_ADJUST_SIZE(QUAD_SIZE); while (len-- > 0) { char *tmp = (char*)s; s += QUAD_SIZE; rb_ary_push(ary, rb_quad_unpack(tmp, 0)); } break; case 'n': PACK_LENGTH_ADJUST(unsigned short,2); while (len-- > 0) { unsigned short tmp = 0; memcpy(OFF16B(&tmp), s, NATINT_LEN(unsigned short,2)); s += NATINT_LEN(unsigned short,2); rb_ary_push(ary, UINT2NUM(ntohs(tmp))); } PACK_ITEM_ADJUST(); break; case 'N': PACK_LENGTH_ADJUST(unsigned long,4); while (len-- > 0) { unsigned long tmp = 0; memcpy(OFF32B(&tmp), s, NATINT_LEN(unsigned long,4)); s += NATINT_LEN(unsigned long,4); rb_ary_push(ary, ULONG2NUM(ntohl(tmp))); } PACK_ITEM_ADJUST(); break; case 'v': PACK_LENGTH_ADJUST(unsigned short,2); while (len-- > 0) { unsigned short tmp = 0; memcpy(OFF16(&tmp), s, NATINT_LEN(unsigned short,2)); s += NATINT_LEN(unsigned short,2); rb_ary_push(ary, UINT2NUM(vtohs(tmp))); } PACK_ITEM_ADJUST(); break; case 'V': PACK_LENGTH_ADJUST(unsigned long,4); while (len-- > 0) { unsigned long tmp = 0; memcpy(OFF32(&tmp), s, NATINT_LEN(long,4)); s += NATINT_LEN(long,4); rb_ary_push(ary, ULONG2NUM(vtohl(tmp))); } PACK_ITEM_ADJUST(); break; case 'f': case 'F': PACK_LENGTH_ADJUST(float,sizeof(float)); while (len-- > 0) { float tmp; memcpy(&tmp, s, sizeof(float)); s += sizeof(float); rb_ary_push(ary, rb_float_new((double)tmp)); } PACK_ITEM_ADJUST(); break; case 'e': PACK_LENGTH_ADJUST(float,sizeof(float)); while (len-- > 0) { float tmp; FLOAT_CONVWITH(ftmp); memcpy(&tmp, s, sizeof(float)); s += sizeof(float); tmp = VTOHF(tmp,ftmp); rb_ary_push(ary, rb_float_new((double)tmp)); } PACK_ITEM_ADJUST(); break; case 'E': PACK_LENGTH_ADJUST(double,sizeof(double)); while (len-- > 0) { double tmp; DOUBLE_CONVWITH(dtmp); memcpy(&tmp, s, sizeof(double)); s += sizeof(double); tmp = VTOHD(tmp,dtmp); rb_ary_push(ary, rb_float_new(tmp)); } PACK_ITEM_ADJUST(); break; case 'D': case 'd': PACK_LENGTH_ADJUST(double,sizeof(double)); while (len-- > 0) { double tmp; memcpy(&tmp, s, sizeof(double)); s += sizeof(double); rb_ary_push(ary, rb_float_new(tmp)); } PACK_ITEM_ADJUST(); break; case 'g': PACK_LENGTH_ADJUST(float,sizeof(float)); while (len-- > 0) { float tmp; FLOAT_CONVWITH(ftmp;) memcpy(&tmp, s, sizeof(float)); s += sizeof(float); tmp = NTOHF(tmp,ftmp); rb_ary_push(ary, rb_float_new((double)tmp)); } PACK_ITEM_ADJUST(); break; case 'G': PACK_LENGTH_ADJUST(double,sizeof(double)); while (len-- > 0) { double tmp; DOUBLE_CONVWITH(dtmp); memcpy(&tmp, s, sizeof(double)); s += sizeof(double); tmp = NTOHD(tmp,dtmp); rb_ary_push(ary, rb_float_new(tmp)); } PACK_ITEM_ADJUST(); break; case 'U': if (len > send - s) len = send - s; while (len > 0 && s < send) { long alen = send - s; unsigned long l; l = utf8_to_uv(s, &alen); s += alen; len--; rb_ary_push(ary, ULONG2NUM(l)); } break; case 'u': { VALUE buf = infected_str_new(0, (send - s)*3/4, str); char *ptr = RSTRING(buf)->ptr; long total = 0; while (s < send && *s > ' ' && *s < 'a') { long a,b,c,d; char hunk[4]; hunk[3] = '\0'; len = (*s++ - ' ') & 077; total += len; if (total > RSTRING(buf)->len) { len -= total - RSTRING(buf)->len; total = RSTRING(buf)->len; } while (len > 0) { long mlen = len > 3 ? 3 : len; if (s < send && *s >= ' ') a = (*s++ - ' ') & 077; else a = 0; if (s < send && *s >= ' ') b = (*s++ - ' ') & 077; else b = 0; if (s < send && *s >= ' ') c = (*s++ - ' ') & 077; else c = 0; if (s < send && *s >= ' ') d = (*s++ - ' ') & 077; else d = 0; hunk[0] = a << 2 | b >> 4; hunk[1] = b << 4 | c >> 2; hunk[2] = c << 6 | d; memcpy(ptr, hunk, mlen); ptr += mlen; len -= mlen; } if (*s == '\r') s++; if (*s == '\n') s++; else if (s < send && (s+1 == send || s[1] == '\n')) s += 2; /* possible checksum byte */ } RSTRING(buf)->ptr[total] = '\0'; RSTRING(buf)->len = total; rb_ary_push(ary, buf); } break; case 'm': { VALUE buf = infected_str_new(0, (send - s)*3/4, str); char *ptr = RSTRING(buf)->ptr; int a = -1,b = -1,c = 0,d; static int first = 1; static int b64_xtable[256]; if (first) { int i; first = 0; for (i = 0; i < 256; i++) { b64_xtable[i] = -1; } for (i = 0; i < 64; i++) { b64_xtable[(int)b64_table[i]] = i; } } while (s < send) { a = b = c = d = -1; while((a = b64_xtable[(int)(*(unsigned char*)s)]) == -1 && s < send) { s++; } if( s >= send ) break; s++; while((b = b64_xtable[(int)(*(unsigned char*)s)]) == -1 && s < send) { s++; } if( s >= send ) break; s++; while((c = b64_xtable[(int)(*(unsigned char*)s)]) == -1 && s < send) { if( *s == '=' ) break; s++; } if( *s == '=' || s >= send ) break; s++; while((d = b64_xtable[(int)(*(unsigned char*)s)]) == -1 && s < send) { if( *s == '=' ) break; s++; } if( *s == '=' || s >= send ) break; s++; *ptr++ = a << 2 | b >> 4; *ptr++ = b << 4 | c >> 2; *ptr++ = c << 6 | d; } if (a != -1 && b != -1) { if (c == -1 && *s == '=') *ptr++ = a << 2 | b >> 4; else if (c != -1 && *s == '=') { *ptr++ = a << 2 | b >> 4; *ptr++ = b << 4 | c >> 2; } } *ptr = '\0'; RSTRING(buf)->len = ptr - RSTRING(buf)->ptr; rb_ary_push(ary, buf); } break; case 'M': { VALUE buf = infected_str_new(0, send - s, str); char *ptr = RSTRING(buf)->ptr; int c1, c2; while (s < send) { if (*s == '=') { if (++s == send) break; if (s+1 < send && *s == '\r' && *(s+1) == '\n') s++; if (*s != '\n') { if ((c1 = hex2num(*s)) == -1) break; if (++s == send) break; if ((c2 = hex2num(*s)) == -1) break; *ptr++ = c1 << 4 | c2; } } else { *ptr++ = *s; } s++; } *ptr = '\0'; RSTRING(buf)->len = ptr - RSTRING(buf)->ptr; rb_ary_push(ary, buf); } break; case '@': if (len > RSTRING(str)->len) rb_raise(rb_eArgError, "@ outside of string"); s = RSTRING(str)->ptr + len; break; case 'X': if (len > s - RSTRING(str)->ptr) rb_raise(rb_eArgError, "X outside of string"); s -= len; break; case 'x': if (len > send - s) rb_raise(rb_eArgError, "x outside of string"); s += len; break; case 'P': if (sizeof(char *) <= send - s) { VALUE tmp = Qnil; char *t; memcpy(&t, s, sizeof(char *)); s += sizeof(char *); if (t) { VALUE a, *p, *pend; if (!(a = rb_str_associated(str))) { rb_raise(rb_eArgError, "no associated pointer"); } p = RARRAY(a)->ptr; pend = p + RARRAY(a)->len; while (p < pend) { if (TYPE(*p) == T_STRING && RSTRING(*p)->ptr == t) { if (len < RSTRING(*p)->len) { tmp = rb_tainted_str_new(t, len); rb_str_associate(tmp, a); } else { tmp = *p; } break; } p++; } if (p == pend) { rb_raise(rb_eArgError, "non associated pointer"); } } rb_ary_push(ary, tmp); } break; case 'p': if (len > (send - s) / sizeof(char *)) len = (send - s) / sizeof(char *); while (len-- > 0) { if (send - s < sizeof(char *)) break; else { VALUE tmp = Qnil; char *t; memcpy(&t, s, sizeof(char *)); s += sizeof(char *); if (t) { VALUE a, *p, *pend; if (!(a = rb_str_associated(str))) { rb_raise(rb_eArgError, "no associated pointer"); } p = RARRAY(a)->ptr; pend = p + RARRAY(a)->len; while (p < pend) { if (TYPE(*p) == T_STRING && RSTRING(*p)->ptr == t) { tmp = *p; break; } p++; } if (p == pend) { rb_raise(rb_eArgError, "non associated pointer"); } } rb_ary_push(ary, tmp); } } break; case 'w': { unsigned long ul = 0; unsigned long ulmask = 0xfeUL << ((sizeof(unsigned long) - 1) * 8); while (len > 0 && s < send) { ul <<= 7; ul |= (*s & 0x7f); if (!(*s++ & 0x80)) { rb_ary_push(ary, ULONG2NUM(ul)); len--; ul = 0; } else if (ul & ulmask) { VALUE big = rb_uint2big(ul); VALUE big128 = rb_uint2big(128); while (s < send) { big = rb_big_mul(big, big128); big = rb_big_plus(big, rb_uint2big(*s & 0x7f)); if (!(*s++ & 0x80)) { rb_ary_push(ary, big); len--; ul = 0; break; } } } } } break; default: break; } } return ary; } #define BYTEWIDTH 8 static int uv_to_utf8(buf, uv) char *buf; unsigned long uv; { if (uv <= 0x7f) { buf[0] = (char)uv; return 1; } if (uv <= 0x7ff) { buf[0] = ((uv>>6)&0xff)|0xc0; buf[1] = (uv&0x3f)|0x80; return 2; } if (uv <= 0xffff) { buf[0] = ((uv>>12)&0xff)|0xe0; buf[1] = ((uv>>6)&0x3f)|0x80; buf[2] = (uv&0x3f)|0x80; return 3; } if (uv <= 0x1fffff) { buf[0] = ((uv>>18)&0xff)|0xf0; buf[1] = ((uv>>12)&0x3f)|0x80; buf[2] = ((uv>>6)&0x3f)|0x80; buf[3] = (uv&0x3f)|0x80; return 4; } if (uv <= 0x3ffffff) { buf[0] = ((uv>>24)&0xff)|0xf8; buf[1] = ((uv>>18)&0x3f)|0x80; buf[2] = ((uv>>12)&0x3f)|0x80; buf[3] = ((uv>>6)&0x3f)|0x80; buf[4] = (uv&0x3f)|0x80; return 5; } if (uv <= 0x7fffffff) { buf[0] = ((uv>>30)&0xff)|0xfc; buf[1] = ((uv>>24)&0x3f)|0x80; buf[2] = ((uv>>18)&0x3f)|0x80; buf[3] = ((uv>>12)&0x3f)|0x80; buf[4] = ((uv>>6)&0x3f)|0x80; buf[5] = (uv&0x3f)|0x80; return 6; } rb_raise(rb_eRangeError, "pack(U): value out of range"); } static const unsigned long utf8_limits[] = { 0x0, /* 1 */ 0x80, /* 2 */ 0x800, /* 3 */ 0x10000, /* 4 */ 0x200000, /* 5 */ 0x4000000, /* 6 */ 0x80000000, /* 7 */ }; static unsigned long utf8_to_uv(p, lenp) char *p; long *lenp; { int c = *p++ & 0xff; unsigned long uv = c; long n; if (!(uv & 0x80)) { *lenp = 1; return uv; } if (!(uv & 0x40)) { *lenp = 1; rb_raise(rb_eArgError, "malformed UTF-8 character"); } if (!(uv & 0x20)) { n = 2; uv &= 0x1f; } else if (!(uv & 0x10)) { n = 3; uv &= 0x0f; } else if (!(uv & 0x08)) { n = 4; uv &= 0x07; } else if (!(uv & 0x04)) { n = 5; uv &= 0x03; } else if (!(uv & 0x02)) { n = 6; uv &= 0x01; } else { *lenp = 1; rb_raise(rb_eArgError, "malformed UTF-8 character"); } if (n > *lenp) { rb_raise(rb_eArgError, "malformed UTF-8 character (expected %d bytes, given %d bytes)", n, *lenp); } *lenp = n--; if (n != 0) { while (n--) { c = *p++ & 0xff; if ((c & 0xc0) != 0x80) { *lenp -= n + 1; rb_raise(rb_eArgError, "malformed UTF-8 character"); } else { c &= 0x3f; uv = uv << 6 | c; } } } n = *lenp - 1; if (uv < utf8_limits[n]) { rb_raise(rb_eArgError, "redundant UTF-8 sequence"); } return uv; } void Init_pack() { rb_define_method(rb_cArray, "pack", pack_pack, 1); rb_define_method(rb_cString, "unpack", pack_unpack, 1); } ================================================ FILE: parse.y ================================================ /********************************************************************** parse.y - $Author$ $Date$ created at: Fri May 28 18:02:42 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ %{ #define YYDEBUG 1 #define YYERROR_VERBOSE 1 #ifndef YYSTACK_USE_ALLOCA #define YYSTACK_USE_ALLOCA 0 #endif #include "ruby.h" #include "env.h" #include "intern.h" #include "node.h" #include "st.h" #include #include #include #define YYMALLOC rb_parser_malloc #define YYREALLOC rb_parser_realloc #define YYCALLOC rb_parser_calloc #define YYFREE rb_parser_free #define malloc YYMALLOC #define realloc YYREALLOC #define calloc YYCALLOC #define free YYFREE static void *rb_parser_malloc _((size_t)); static void *rb_parser_realloc _((void *, size_t)); static void *rb_parser_calloc _((size_t, size_t)); static void rb_parser_free _((void *)); #define yyparse ruby_yyparse #define yylex ruby_yylex #define yyerror ruby_yyerror #define yylval ruby_yylval #define yychar ruby_yychar #define yydebug ruby_yydebug #define ID_SCOPE_SHIFT 3 #define ID_SCOPE_MASK 0x07 #define ID_LOCAL 0x01 #define ID_INSTANCE 0x02 #define ID_GLOBAL 0x03 #define ID_ATTRSET 0x04 #define ID_CONST 0x05 #define ID_CLASS 0x06 #define ID_JUNK 0x07 #define ID_INTERNAL ID_JUNK #define is_notop_id(id) ((id)>tLAST_TOKEN) #define is_local_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_LOCAL) #define is_global_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_GLOBAL) #define is_instance_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_INSTANCE) #define is_attrset_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_ATTRSET) #define is_const_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_CONST) #define is_class_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_CLASS) #define is_junk_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_JUNK) #define is_asgn_or_id(id) ((is_notop_id(id)) && \ (((id)&ID_SCOPE_MASK) == ID_GLOBAL || \ ((id)&ID_SCOPE_MASK) == ID_INSTANCE || \ ((id)&ID_SCOPE_MASK) == ID_CLASS)) NODE *ruby_eval_tree_begin = 0; NODE *ruby_eval_tree = 0; char *ruby_sourcefile; /* current source file */ int ruby_sourceline; /* current line no. */ #ifdef GC_DEBUG ID ruby_sourcefunc; /* current func if no other context */ VALUE ruby_sourcefunc_line; /* current func if no other context */ char* ruby_sourcefunc_file; /* current func if no other context */ #endif static int yylex(); static int yyerror(); static enum lex_state { EXPR_BEG, /* ignore newline, +/- is a sign. */ EXPR_END, /* newline significant, +/- is an operator. */ EXPR_ARG, /* newline significant, +/- is an operator. */ EXPR_CMDARG, /* newline significant, +/- is an operator. */ EXPR_ENDARG, /* newline significant, +/- is an operator. */ EXPR_MID, /* newline significant, +/- is an operator. */ EXPR_FNAME, /* ignore newline, no reserved words. */ EXPR_DOT, /* right after `.' or `::', no reserved words. */ EXPR_CLASS, /* immediate after `class', no here document. */ } lex_state; static NODE *lex_strterm; #ifdef HAVE_LONG_LONG typedef unsigned LONG_LONG stack_type; #else typedef unsigned long stack_type; #endif #define BITSTACK_PUSH(stack, n) (stack = (stack<<1)|((n)&1)) #define BITSTACK_POP(stack) (stack >>= 1) #define BITSTACK_LEXPOP(stack) (stack = (stack >> 1) | (stack & 1)) #define BITSTACK_SET_P(stack) (stack&1) static stack_type cond_stack = 0; #define COND_PUSH(n) BITSTACK_PUSH(cond_stack, n) #define COND_POP() BITSTACK_POP(cond_stack) #define COND_LEXPOP() BITSTACK_LEXPOP(cond_stack) #define COND_P() BITSTACK_SET_P(cond_stack) static stack_type cmdarg_stack = 0; #define CMDARG_PUSH(n) BITSTACK_PUSH(cmdarg_stack, n) #define CMDARG_POP() BITSTACK_POP(cmdarg_stack) #define CMDARG_LEXPOP() BITSTACK_LEXPOP(cmdarg_stack) #define CMDARG_P() BITSTACK_SET_P(cmdarg_stack) static int class_nest = 0; static int in_single = 0; static int in_def = 0; static int compile_for_eval = 0; static ID cur_mid = 0; static int command_start = Qtrue; static NODE *deferred_nodes; static NODE *cond(); static NODE *logop(); static int cond_negative(); static NODE *newline_node(); static void fixpos(); static int value_expr0(); static void void_expr0(); static void void_stmts(); static NODE *remove_begin(); #define value_expr(node) value_expr0((node) = remove_begin(node)) #define void_expr(node) void_expr0((node) = remove_begin(node)) static NODE *block_append(); static NODE *list_append(); static NODE *list_concat(); static NODE *arg_concat(); static NODE *arg_prepend(); static NODE *literal_concat(); static NODE *new_evstr(); static NODE *evstr2dstr(); static NODE *call_op(); static int in_defined = 0; static NODE *negate_lit(); static NODE *ret_args(); static NODE *arg_blk_pass(); static NODE *new_call(); static NODE *new_fcall(); static NODE *new_super(); static NODE *new_yield(); static NODE *gettable(); static NODE *assignable(); static NODE *aryset(); static NODE *attrset(); static void rb_backref_error(); static NODE *node_assign(); static NODE *match_gen(); static void local_push(); static void local_pop(); static int local_append(); static int local_cnt(); static int local_id(); static ID *local_tbl(); static ID internal_id(); static struct RVarmap *dyna_push(); static void dyna_pop(); static int dyna_in_block(); static NODE *dyna_init(); static void top_local_init(); static void top_local_setup(); static void fixup_nodes(); #define RE_OPTION_ONCE 0x80 #define NODE_STRTERM NODE_ZARRAY /* nothing to gc */ #define NODE_HEREDOC NODE_ARRAY /* 1, 3 to gc */ #define SIGN_EXTEND(x,n) (((1<<(n)-1)^((x)&~(~0<<(n))))-(1<<(n)-1)) #define nd_func u1.id #if SIZEOF_SHORT == 2 #define nd_term(node) ((signed short)(node)->u2.id) #else #define nd_term(node) SIGN_EXTEND((node)->u2.id, CHAR_BIT*2) #endif #define nd_paren(node) (char)((node)->u2.id >> CHAR_BIT*2) #define nd_nest u3.id #define NEW_BLOCK_VAR(b, v) NEW_NODE(NODE_BLOCK_PASS, 0, b, v) /* Older versions of Yacc set YYMAXDEPTH to a very low value by default (150, for instance). This is too low for Ruby to parse some files, such as date/format.rb, therefore bump the value up to at least Bison's default. */ #ifdef OLD_YACC #ifndef YYMAXDEPTH #define YYMAXDEPTH 10000 #endif #endif %} %union { NODE *node; ID id; int num; struct RVarmap *vars; } %token kCLASS kMODULE kDEF kUNDEF kBEGIN kRESCUE kENSURE kEND kIF kUNLESS kTHEN kELSIF kELSE kCASE kWHEN kWHILE kUNTIL kFOR kBREAK kNEXT kREDO kRETRY kIN kDO kDO_COND kDO_BLOCK kRETURN kYIELD kSUPER kSELF kNIL kTRUE kFALSE kAND kOR kNOT kIF_MOD kUNLESS_MOD kWHILE_MOD kUNTIL_MOD kRESCUE_MOD kALIAS kDEFINED klBEGIN klEND k__LINE__ k__FILE__ %token tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR %token tINTEGER tFLOAT tSTRING_CONTENT %token tNTH_REF tBACK_REF %token tREGEXP_END %type singleton strings string string1 xstring regexp %type string_contents xstring_contents string_content %type words qwords word_list qword_list word %type literal numeric dsym cpath %type bodystmt compstmt stmts stmt expr arg primary command command_call method_call %type expr_value arg_value primary_value %type if_tail opt_else case_body cases opt_rescue exc_list exc_var opt_ensure %type args when_args call_args call_args2 open_args paren_args opt_paren_args %type command_args aref_args opt_block_arg block_arg var_ref var_lhs %type mrhs superclass block_call block_command %type f_arglist f_args f_optarg f_opt f_rest_arg f_block_arg opt_f_block_arg %type assoc_list assocs assoc undef_list backref string_dvar %type for_var block_var opt_block_var block_par %type brace_block cmd_brace_block do_block lhs none fitem %type mlhs mlhs_head mlhs_basic mlhs_entry mlhs_item mlhs_node %type fsym variable sym symbol operation operation2 operation3 %type cname fname op %type f_norm_arg f_arg %token tUPLUS /* unary+ */ %token tUMINUS /* unary- */ %token tPOW /* ** */ %token tCMP /* <=> */ %token tEQ /* == */ %token tEQQ /* === */ %token tNEQ /* != */ %token tGEQ /* >= */ %token tLEQ /* <= */ %token tANDOP tOROP /* && and || */ %token tMATCH tNMATCH /* =~ and !~ */ %token tDOT2 tDOT3 /* .. and ... */ %token tAREF tASET /* [] and []= */ %token tLSHFT tRSHFT /* << and >> */ %token tCOLON2 /* :: */ %token tCOLON3 /* :: at EXPR_BEG */ %token tOP_ASGN /* +=, -= etc. */ %token tASSOC /* => */ %token tLPAREN /* ( */ %token tLPAREN_ARG /* ( */ %token tRPAREN /* ) */ %token tLBRACK /* [ */ %token tLBRACE /* { */ %token tLBRACE_ARG /* { */ %token tSTAR /* * */ %token tAMPER /* & */ %token tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG tWORDS_BEG tQWORDS_BEG %token tSTRING_DBEG tSTRING_DVAR tSTRING_END /* * precedence table */ %nonassoc tLOWEST %nonassoc tLBRACE_ARG %nonassoc kIF_MOD kUNLESS_MOD kWHILE_MOD kUNTIL_MOD %left kOR kAND %right kNOT %nonassoc kDEFINED %right '=' tOP_ASGN %left kRESCUE_MOD %right '?' ':' %nonassoc tDOT2 tDOT3 %left tOROP %left tANDOP %nonassoc tCMP tEQ tEQQ tNEQ tMATCH tNMATCH %left '>' tGEQ '<' tLEQ %left '|' '^' %left '&' %left tLSHFT tRSHFT %left '+' '-' %left '*' '/' '%' %right tUMINUS_NUM tUMINUS %right tPOW %right '!' '~' tUPLUS %token tLAST_TOKEN %% program : { lex_state = EXPR_BEG; top_local_init(); if (ruby_class == rb_cObject) class_nest = 0; else class_nest = 1; } compstmt { if ($2 && !compile_for_eval) { /* last expression should not be void */ if (nd_type($2) != NODE_BLOCK) void_expr($2); else { NODE *node = $2; while (node->nd_next) { node = node->nd_next; } void_expr(node->nd_head); } } ruby_eval_tree = block_append(ruby_eval_tree, $2); top_local_setup(); class_nest = 0; } ; bodystmt : compstmt opt_rescue opt_else opt_ensure { $$ = $1; if ($2) { $$ = NEW_RESCUE($1, $2, $3); } else if ($3) { rb_warn("else without rescue is useless"); $$ = block_append($$, $3); } if ($4) { $$ = NEW_ENSURE($$, $4); } fixpos($$, $1); } ; compstmt : stmts opt_terms { void_stmts($1); fixup_nodes(&deferred_nodes); $$ = $1; } ; stmts : none | stmt { $$ = newline_node($1); } | stmts terms stmt { $$ = block_append($1, newline_node($3)); } | error stmt { $$ = remove_begin($2); } ; stmt : kALIAS fitem {lex_state = EXPR_FNAME;} fitem { $$ = NEW_ALIAS($2, $4); } | kALIAS tGVAR tGVAR { $$ = NEW_VALIAS($2, $3); } | kALIAS tGVAR tBACK_REF { char buf[3]; sprintf(buf, "$%c", (char)$3->nd_nth); $$ = NEW_VALIAS($2, rb_intern(buf)); } | kALIAS tGVAR tNTH_REF { yyerror("can't make alias for the number variables"); $$ = 0; } | kUNDEF undef_list { $$ = $2; } | stmt kIF_MOD expr_value { $$ = NEW_IF(cond($3), remove_begin($1), 0); fixpos($$, $3); if (cond_negative(&$$->nd_cond)) { $$->nd_else = $$->nd_body; $$->nd_body = 0; } } | stmt kUNLESS_MOD expr_value { $$ = NEW_UNLESS(cond($3), remove_begin($1), 0); fixpos($$, $3); if (cond_negative(&$$->nd_cond)) { $$->nd_body = $$->nd_else; $$->nd_else = 0; } } | stmt kWHILE_MOD expr_value { if ($1 && nd_type($1) == NODE_BEGIN) { $$ = NEW_WHILE(cond($3), $1->nd_body, 0); } else { $$ = NEW_WHILE(cond($3), $1, 1); } if (cond_negative(&$$->nd_cond)) { nd_set_type($$, NODE_UNTIL); } } | stmt kUNTIL_MOD expr_value { if ($1 && nd_type($1) == NODE_BEGIN) { $$ = NEW_UNTIL(cond($3), $1->nd_body, 0); } else { $$ = NEW_UNTIL(cond($3), $1, 1); } if (cond_negative(&$$->nd_cond)) { nd_set_type($$, NODE_WHILE); } } | stmt kRESCUE_MOD stmt { NODE *resq = NEW_RESBODY(0, remove_begin($3), 0); $$ = NEW_RESCUE(remove_begin($1), resq, 0); } | klBEGIN { if (in_def || in_single) { yyerror("BEGIN in method"); } local_push(0); } '{' compstmt '}' { ruby_eval_tree_begin = block_append(ruby_eval_tree_begin, NEW_PREEXE($4)); local_pop(); $$ = 0; } | klEND '{' compstmt '}' { if (in_def || in_single) { rb_warn("END in method; use at_exit"); } $$ = NEW_ITER(0, NEW_POSTEXE(), $3); } | lhs '=' command_call { $$ = node_assign($1, $3); } | mlhs '=' command_call { value_expr($3); $1->nd_value = ($1->nd_head) ? NEW_TO_ARY($3) : NEW_ARRAY($3); $$ = $1; } | var_lhs tOP_ASGN command_call { value_expr($3); if ($1) { ID vid = $1->nd_vid; if ($2 == tOROP) { $1->nd_value = $3; $$ = NEW_OP_ASGN_OR(gettable(vid), $1); if (is_asgn_or_id(vid)) { $$->nd_aid = vid; } } else if ($2 == tANDOP) { $1->nd_value = $3; $$ = NEW_OP_ASGN_AND(gettable(vid), $1); } else { $$ = $1; $$->nd_value = call_op(gettable(vid),$2,1,$3); } } else { $$ = 0; } } | primary_value '[' aref_args ']' tOP_ASGN command_call { NODE *args; value_expr($6); if (!$3) $3 = NEW_ZARRAY(); args = arg_concat($6, $3); if ($5 == tOROP) { $5 = 0; } else if ($5 == tANDOP) { $5 = 1; } $$ = NEW_OP_ASGN1($1, $5, args); fixpos($$, $1); } | primary_value '.' tIDENTIFIER tOP_ASGN command_call { value_expr($5); if ($4 == tOROP) { $4 = 0; } else if ($4 == tANDOP) { $4 = 1; } $$ = NEW_OP_ASGN2($1, $3, $4, $5); fixpos($$, $1); } | primary_value '.' tCONSTANT tOP_ASGN command_call { value_expr($5); if ($4 == tOROP) { $4 = 0; } else if ($4 == tANDOP) { $4 = 1; } $$ = NEW_OP_ASGN2($1, $3, $4, $5); fixpos($$, $1); } | primary_value tCOLON2 tIDENTIFIER tOP_ASGN command_call { value_expr($5); if ($4 == tOROP) { $4 = 0; } else if ($4 == tANDOP) { $4 = 1; } $$ = NEW_OP_ASGN2($1, $3, $4, $5); fixpos($$, $1); } | backref tOP_ASGN command_call { rb_backref_error($1); $$ = 0; } | lhs '=' mrhs { $$ = node_assign($1, NEW_SVALUE($3)); } | mlhs '=' arg_value { $1->nd_value = ($1->nd_head) ? NEW_TO_ARY($3) : NEW_ARRAY($3); $$ = $1; } | mlhs '=' mrhs { $1->nd_value = $3; $$ = $1; } | expr ; expr : command_call | expr kAND expr { $$ = logop(NODE_AND, $1, $3); } | expr kOR expr { $$ = logop(NODE_OR, $1, $3); } | kNOT expr { $$ = NEW_NOT(cond($2)); } | '!' command_call { $$ = NEW_NOT(cond($2)); } | arg ; expr_value : expr { value_expr($$); $$ = $1; } ; command_call : command | block_command | kRETURN call_args { $$ = NEW_RETURN(ret_args($2)); } | kBREAK call_args { $$ = NEW_BREAK(ret_args($2)); } | kNEXT call_args { $$ = NEW_NEXT(ret_args($2)); } ; block_command : block_call | block_call '.' operation2 command_args { $$ = new_call($1, $3, $4); } | block_call tCOLON2 operation2 command_args { $$ = new_call($1, $3, $4); } ; cmd_brace_block : tLBRACE_ARG { $$ = dyna_push(); $1 = ruby_sourceline; } opt_block_var {$$ = ruby_dyna_vars;} compstmt '}' { $$ = NEW_ITER($3, 0, dyna_init($5, $4)); nd_set_line($$, $1); dyna_pop($2); } ; command : operation command_args %prec tLOWEST { $$ = new_fcall($1, $2); fixpos($$, $2); } | operation command_args cmd_brace_block { $$ = new_fcall($1, $2); if ($3) { if (nd_type($$) == NODE_BLOCK_PASS) { rb_compile_error("both block arg and actual block given"); } $3->nd_iter = $$; $$ = $3; } fixpos($$, $2); } | primary_value '.' operation2 command_args %prec tLOWEST { $$ = new_call($1, $3, $4); fixpos($$, $1); } | primary_value '.' operation2 command_args cmd_brace_block { $$ = new_call($1, $3, $4); if ($5) { if (nd_type($$) == NODE_BLOCK_PASS) { rb_compile_error("both block arg and actual block given"); } $5->nd_iter = $$; $$ = $5; } fixpos($$, $1); } | primary_value tCOLON2 operation2 command_args %prec tLOWEST { $$ = new_call($1, $3, $4); fixpos($$, $1); } | primary_value tCOLON2 operation2 command_args cmd_brace_block { $$ = new_call($1, $3, $4); if ($5) { if (nd_type($$) == NODE_BLOCK_PASS) { rb_compile_error("both block arg and actual block given"); } $5->nd_iter = $$; $$ = $5; } fixpos($$, $1); } | kSUPER command_args { $$ = new_super($2); fixpos($$, $2); } | kYIELD command_args { $$ = new_yield($2); fixpos($$, $2); } ; mlhs : mlhs_basic | tLPAREN mlhs_entry ')' { $$ = $2; } ; mlhs_entry : mlhs_basic | tLPAREN mlhs_entry ')' { $$ = NEW_MASGN(NEW_LIST($2), 0); } ; mlhs_basic : mlhs_head { $$ = NEW_MASGN($1, 0); } | mlhs_head mlhs_item { $$ = NEW_MASGN(list_append($1,$2), 0); } | mlhs_head tSTAR mlhs_node { $$ = NEW_MASGN($1, $3); } | mlhs_head tSTAR { $$ = NEW_MASGN($1, -1); } | tSTAR mlhs_node { $$ = NEW_MASGN(0, $2); } | tSTAR { $$ = NEW_MASGN(0, -1); } ; mlhs_item : mlhs_node | tLPAREN mlhs_entry ')' { $$ = $2; } ; mlhs_head : mlhs_item ',' { $$ = NEW_LIST($1); } | mlhs_head mlhs_item ',' { $$ = list_append($1, $2); } ; mlhs_node : variable { $$ = assignable($1, 0); } | primary_value '[' aref_args ']' { $$ = aryset($1, $3); } | primary_value '.' tIDENTIFIER { $$ = attrset($1, $3); } | primary_value tCOLON2 tIDENTIFIER { $$ = attrset($1, $3); } | primary_value '.' tCONSTANT { $$ = attrset($1, $3); } | primary_value tCOLON2 tCONSTANT { if (in_def || in_single) yyerror("dynamic constant assignment"); $$ = NEW_CDECL(0, 0, NEW_COLON2($1, $3)); } | tCOLON3 tCONSTANT { if (in_def || in_single) yyerror("dynamic constant assignment"); $$ = NEW_CDECL(0, 0, NEW_COLON3($2)); } | backref { rb_backref_error($1); $$ = 0; } ; lhs : variable { $$ = assignable($1, 0); } | primary_value '[' aref_args ']' { $$ = aryset($1, $3); } | primary_value '.' tIDENTIFIER { $$ = attrset($1, $3); } | primary_value tCOLON2 tIDENTIFIER { $$ = attrset($1, $3); } | primary_value '.' tCONSTANT { $$ = attrset($1, $3); } | primary_value tCOLON2 tCONSTANT { if (in_def || in_single) yyerror("dynamic constant assignment"); $$ = NEW_CDECL(0, 0, NEW_COLON2($1, $3)); } | tCOLON3 tCONSTANT { if (in_def || in_single) yyerror("dynamic constant assignment"); $$ = NEW_CDECL(0, 0, NEW_COLON3($2)); } | backref { rb_backref_error($1); $$ = 0; } ; cname : tIDENTIFIER { yyerror("class/module name must be CONSTANT"); } | tCONSTANT ; cpath : tCOLON3 cname { $$ = NEW_COLON3($2); } | cname { $$ = NEW_COLON2(0, $$); } | primary_value tCOLON2 cname { $$ = NEW_COLON2($1, $3); } ; fname : tIDENTIFIER | tCONSTANT | tFID | op { lex_state = EXPR_END; $$ = $1; } | reswords { lex_state = EXPR_END; $$ = $1; } ; fsym : fname | symbol ; fitem : fsym { $$ = NEW_LIT(ID2SYM($1)); } | dsym ; undef_list : fitem { $$ = NEW_UNDEF($1); } | undef_list ',' {lex_state = EXPR_FNAME;} fitem { $$ = block_append($1, NEW_UNDEF($4)); } ; op : '|' { $$ = '|'; } | '^' { $$ = '^'; } | '&' { $$ = '&'; } | tCMP { $$ = tCMP; } | tEQ { $$ = tEQ; } | tEQQ { $$ = tEQQ; } | tMATCH { $$ = tMATCH; } | '>' { $$ = '>'; } | tGEQ { $$ = tGEQ; } | '<' { $$ = '<'; } | tLEQ { $$ = tLEQ; } | tLSHFT { $$ = tLSHFT; } | tRSHFT { $$ = tRSHFT; } | '+' { $$ = '+'; } | '-' { $$ = '-'; } | '*' { $$ = '*'; } | tSTAR { $$ = '*'; } | '/' { $$ = '/'; } | '%' { $$ = '%'; } | tPOW { $$ = tPOW; } | '~' { $$ = '~'; } | tUPLUS { $$ = tUPLUS; } | tUMINUS { $$ = tUMINUS; } | tAREF { $$ = tAREF; } | tASET { $$ = tASET; } | '`' { $$ = '`'; } ; reswords : k__LINE__ | k__FILE__ | klBEGIN | klEND | kALIAS | kAND | kBEGIN | kBREAK | kCASE | kCLASS | kDEF | kDEFINED | kDO | kELSE | kELSIF | kEND | kENSURE | kFALSE | kFOR | kIN | kMODULE | kNEXT | kNIL | kNOT | kOR | kREDO | kRESCUE | kRETRY | kRETURN | kSELF | kSUPER | kTHEN | kTRUE | kUNDEF | kWHEN | kYIELD | kIF | kUNLESS | kWHILE | kUNTIL ; arg : lhs '=' arg { $$ = node_assign($1, $3); } | lhs '=' arg kRESCUE_MOD arg { $$ = node_assign($1, NEW_RESCUE($3, NEW_RESBODY(0,$5,0), 0)); } | var_lhs tOP_ASGN arg { value_expr($3); if ($1) { ID vid = $1->nd_vid; if ($2 == tOROP) { $1->nd_value = $3; $$ = NEW_OP_ASGN_OR(gettable(vid), $1); if (is_asgn_or_id(vid)) { $$->nd_aid = vid; } } else if ($2 == tANDOP) { $1->nd_value = $3; $$ = NEW_OP_ASGN_AND(gettable(vid), $1); } else { $$ = $1; $$->nd_value = call_op(gettable(vid),$2,1,$3); } } else { $$ = 0; } } | primary_value '[' aref_args ']' tOP_ASGN arg { NODE *args; value_expr($6); if (!$3) $3 = NEW_ZARRAY(); args = arg_concat($6, $3); if ($5 == tOROP) { $5 = 0; } else if ($5 == tANDOP) { $5 = 1; } $$ = NEW_OP_ASGN1($1, $5, args); fixpos($$, $1); } | primary_value '.' tIDENTIFIER tOP_ASGN arg { value_expr($5); if ($4 == tOROP) { $4 = 0; } else if ($4 == tANDOP) { $4 = 1; } $$ = NEW_OP_ASGN2($1, $3, $4, $5); fixpos($$, $1); } | primary_value '.' tCONSTANT tOP_ASGN arg { value_expr($5); if ($4 == tOROP) { $4 = 0; } else if ($4 == tANDOP) { $4 = 1; } $$ = NEW_OP_ASGN2($1, $3, $4, $5); fixpos($$, $1); } | primary_value tCOLON2 tIDENTIFIER tOP_ASGN arg { value_expr($5); if ($4 == tOROP) { $4 = 0; } else if ($4 == tANDOP) { $4 = 1; } $$ = NEW_OP_ASGN2($1, $3, $4, $5); fixpos($$, $1); } | primary_value tCOLON2 tCONSTANT tOP_ASGN arg { yyerror("constant re-assignment"); $$ = 0; } | tCOLON3 tCONSTANT tOP_ASGN arg { yyerror("constant re-assignment"); $$ = 0; } | backref tOP_ASGN arg { rb_backref_error($1); $$ = 0; } | arg tDOT2 arg { value_expr($1); value_expr($3); $$ = NEW_DOT2($1, $3); if (nd_type($1) == NODE_LIT && FIXNUM_P($1->nd_lit) && nd_type($3) == NODE_LIT && FIXNUM_P($3->nd_lit)) { deferred_nodes = list_append(deferred_nodes, $$); } } | arg tDOT3 arg { value_expr($1); value_expr($3); $$ = NEW_DOT3($1, $3); if (nd_type($1) == NODE_LIT && FIXNUM_P($1->nd_lit) && nd_type($3) == NODE_LIT && FIXNUM_P($3->nd_lit)) { deferred_nodes = list_append(deferred_nodes, $$); } } | arg '+' arg { $$ = call_op($1, '+', 1, $3); } | arg '-' arg { $$ = call_op($1, '-', 1, $3); } | arg '*' arg { $$ = call_op($1, '*', 1, $3); } | arg '/' arg { $$ = call_op($1, '/', 1, $3); } | arg '%' arg { $$ = call_op($1, '%', 1, $3); } | arg tPOW arg { $$ = call_op($1, tPOW, 1, $3); } | tUMINUS_NUM tINTEGER tPOW arg { $$ = call_op(call_op($2, tPOW, 1, $4), tUMINUS, 0, 0); } | tUMINUS_NUM tFLOAT tPOW arg { $$ = call_op(call_op($2, tPOW, 1, $4), tUMINUS, 0, 0); } | tUPLUS arg { if ($2 && nd_type($2) == NODE_LIT) { $$ = $2; } else { $$ = call_op($2, tUPLUS, 0, 0); } } | tUMINUS arg { $$ = call_op($2, tUMINUS, 0, 0); } | arg '|' arg { $$ = call_op($1, '|', 1, $3); } | arg '^' arg { $$ = call_op($1, '^', 1, $3); } | arg '&' arg { $$ = call_op($1, '&', 1, $3); } | arg tCMP arg { $$ = call_op($1, tCMP, 1, $3); } | arg '>' arg { $$ = call_op($1, '>', 1, $3); } | arg tGEQ arg { $$ = call_op($1, tGEQ, 1, $3); } | arg '<' arg { $$ = call_op($1, '<', 1, $3); } | arg tLEQ arg { $$ = call_op($1, tLEQ, 1, $3); } | arg tEQ arg { $$ = call_op($1, tEQ, 1, $3); } | arg tEQQ arg { $$ = call_op($1, tEQQ, 1, $3); } | arg tNEQ arg { $$ = NEW_NOT(call_op($1, tEQ, 1, $3)); } | arg tMATCH arg { $$ = match_gen($1, $3); } | arg tNMATCH arg { $$ = NEW_NOT(match_gen($1, $3)); } | '!' arg { $$ = NEW_NOT(cond($2)); } | '~' arg { $$ = call_op($2, '~', 0, 0); } | arg tLSHFT arg { $$ = call_op($1, tLSHFT, 1, $3); } | arg tRSHFT arg { $$ = call_op($1, tRSHFT, 1, $3); } | arg tANDOP arg { $$ = logop(NODE_AND, $1, $3); } | arg tOROP arg { $$ = logop(NODE_OR, $1, $3); } | kDEFINED opt_nl {in_defined = 1;} arg { in_defined = 0; $$ = NEW_DEFINED($4); } | arg '?' arg ':' arg { $$ = NEW_IF(cond($1), $3, $5); fixpos($$, $1); } | primary { $$ = $1; } ; arg_value : arg { value_expr($1); $$ = $1; } ; aref_args : none | command opt_nl { $$ = NEW_LIST($1); } | args trailer { $$ = $1; } | args ',' tSTAR arg opt_nl { value_expr($4); $$ = arg_concat($1, $4); } | assocs trailer { $$ = NEW_LIST(NEW_HASH($1)); } | tSTAR arg opt_nl { value_expr($2); $$ = NEW_NEWLINE(NEW_SPLAT($2)); } ; paren_args : '(' none ')' { $$ = $2; } | '(' call_args opt_nl ')' { $$ = $2; } | '(' block_call opt_nl ')' { $$ = NEW_LIST($2); } | '(' args ',' block_call opt_nl ')' { $$ = list_append($2, $4); } ; opt_paren_args : none | paren_args ; call_args : command { $$ = NEW_LIST($1); } | args opt_block_arg { $$ = arg_blk_pass($1, $2); } | args ',' tSTAR arg_value opt_block_arg { $$ = arg_concat($1, $4); $$ = arg_blk_pass($$, $5); } | assocs opt_block_arg { $$ = NEW_LIST(NEW_HASH($1)); $$ = arg_blk_pass($$, $2); } | assocs ',' tSTAR arg_value opt_block_arg { $$ = arg_concat(NEW_LIST(NEW_HASH($1)), $4); $$ = arg_blk_pass($$, $5); } | args ',' assocs opt_block_arg { $$ = list_append($1, NEW_HASH($3)); $$ = arg_blk_pass($$, $4); } | args ',' assocs ',' tSTAR arg opt_block_arg { value_expr($6); $$ = arg_concat(list_append($1, NEW_HASH($3)), $6); $$ = arg_blk_pass($$, $7); } | tSTAR arg_value opt_block_arg { $$ = arg_blk_pass(NEW_SPLAT($2), $3); } | block_arg ; call_args2 : arg_value ',' args opt_block_arg { $$ = arg_blk_pass(list_concat(NEW_LIST($1),$3), $4); } | arg_value ',' block_arg { $$ = arg_blk_pass($1, $3); } | arg_value ',' tSTAR arg_value opt_block_arg { $$ = arg_concat(NEW_LIST($1), $4); $$ = arg_blk_pass($$, $5); } | arg_value ',' args ',' tSTAR arg_value opt_block_arg { $$ = arg_concat(list_concat(NEW_LIST($1),$3), $6); $$ = arg_blk_pass($$, $7); } | assocs opt_block_arg { $$ = NEW_LIST(NEW_HASH($1)); $$ = arg_blk_pass($$, $2); } | assocs ',' tSTAR arg_value opt_block_arg { $$ = arg_concat(NEW_LIST(NEW_HASH($1)), $4); $$ = arg_blk_pass($$, $5); } | arg_value ',' assocs opt_block_arg { $$ = list_append(NEW_LIST($1), NEW_HASH($3)); $$ = arg_blk_pass($$, $4); } | arg_value ',' args ',' assocs opt_block_arg { $$ = list_append(list_concat(NEW_LIST($1),$3), NEW_HASH($5)); $$ = arg_blk_pass($$, $6); } | arg_value ',' assocs ',' tSTAR arg_value opt_block_arg { $$ = arg_concat(list_append(NEW_LIST($1), NEW_HASH($3)), $6); $$ = arg_blk_pass($$, $7); } | arg_value ',' args ',' assocs ',' tSTAR arg_value opt_block_arg { $$ = arg_concat(list_append(list_concat(NEW_LIST($1), $3), NEW_HASH($5)), $8); $$ = arg_blk_pass($$, $9); } | tSTAR arg_value opt_block_arg { $$ = arg_blk_pass(NEW_SPLAT($2), $3); } | block_arg ; command_args : { $$ = cmdarg_stack; CMDARG_PUSH(1); } open_args { /* CMDARG_POP() */ cmdarg_stack = $1; $$ = $2; } ; open_args : call_args | tLPAREN_ARG {lex_state = EXPR_ENDARG;} ')' { rb_warn("don't put space before argument parentheses"); $$ = 0; } | tLPAREN_ARG call_args2 {lex_state = EXPR_ENDARG;} ')' { rb_warn("don't put space before argument parentheses"); $$ = $2; } ; block_arg : tAMPER arg_value { $$ = NEW_BLOCK_PASS($2); } ; opt_block_arg : ',' block_arg { $$ = $2; } | none ; args : arg_value { $$ = NEW_LIST($1); } | args ',' arg_value { $$ = list_append($1, $3); } ; mrhs : args ',' arg_value { $$ = list_append($1, $3); } | args ',' tSTAR arg_value { $$ = arg_concat($1, $4); } | tSTAR arg_value { $$ = NEW_SPLAT($2); } ; primary : literal | strings | xstring | regexp | words | qwords | var_ref | backref | tFID { $$ = NEW_FCALL($1, 0); } | kBEGIN { $1 = ruby_sourceline; } bodystmt kEND { if ($3 == NULL) $$ = NEW_NIL(); else $$ = NEW_BEGIN($3); nd_set_line($$, $1); } | tLPAREN_ARG expr {lex_state = EXPR_ENDARG;} opt_nl ')' { rb_warning("(...) interpreted as grouped expression"); $$ = $2; } | tLPAREN compstmt ')' { if (!$2) $$ = NEW_NIL(); else $$ = $2; } | primary_value tCOLON2 tCONSTANT { $$ = NEW_COLON2($1, $3); } | tCOLON3 tCONSTANT { $$ = NEW_COLON3($2); } | primary_value '[' aref_args ']' { if ($1 && nd_type($1) == NODE_SELF) $$ = NEW_FCALL(tAREF, $3); else $$ = NEW_CALL($1, tAREF, $3); fixpos($$, $1); } | tLBRACK aref_args ']' { if ($2 == 0) { $$ = NEW_ZARRAY(); /* zero length array*/ } else { $$ = $2; } } | tLBRACE assoc_list '}' { $$ = NEW_HASH($2); } | kRETURN { $$ = NEW_RETURN(0); } | kYIELD '(' call_args ')' { $$ = new_yield($3); } | kYIELD '(' ')' { $$ = NEW_YIELD(0, Qfalse); } | kYIELD { $$ = NEW_YIELD(0, Qfalse); } | kDEFINED opt_nl '(' {in_defined = 1;} expr ')' { in_defined = 0; $$ = NEW_DEFINED($5); } | operation brace_block { $2->nd_iter = NEW_FCALL($1, 0); $$ = $2; fixpos($2->nd_iter, $2); } | method_call | method_call brace_block { if ($1 && nd_type($1) == NODE_BLOCK_PASS) { rb_compile_error("both block arg and actual block given"); } $2->nd_iter = $1; $$ = $2; fixpos($$, $1); } | kIF expr_value then compstmt if_tail kEND { $$ = NEW_IF(cond($2), $4, $5); fixpos($$, $2); if (cond_negative(&$$->nd_cond)) { NODE *tmp = $$->nd_body; $$->nd_body = $$->nd_else; $$->nd_else = tmp; } } | kUNLESS expr_value then compstmt opt_else kEND { $$ = NEW_UNLESS(cond($2), $4, $5); fixpos($$, $2); if (cond_negative(&$$->nd_cond)) { NODE *tmp = $$->nd_body; $$->nd_body = $$->nd_else; $$->nd_else = tmp; } } | kWHILE {COND_PUSH(1);} expr_value do {COND_POP();} compstmt kEND { $$ = NEW_WHILE(cond($3), $6, 1); fixpos($$, $3); if (cond_negative(&$$->nd_cond)) { nd_set_type($$, NODE_UNTIL); } } | kUNTIL {COND_PUSH(1);} expr_value do {COND_POP();} compstmt kEND { $$ = NEW_UNTIL(cond($3), $6, 1); fixpos($$, $3); if (cond_negative(&$$->nd_cond)) { nd_set_type($$, NODE_WHILE); } } | kCASE expr_value opt_terms case_body kEND { $$ = NEW_CASE($2, $4); fixpos($$, $2); } | kCASE opt_terms case_body kEND { $$ = $3; } | kCASE opt_terms kELSE compstmt kEND { $$ = $4; } | kFOR for_var kIN {COND_PUSH(1);} expr_value do {COND_POP();} compstmt kEND { $$ = NEW_FOR($2, $5, $8); fixpos($$, $2); } | kCLASS cpath superclass { if (in_def || in_single) yyerror("class definition in method body"); class_nest++; local_push(0); $$ = ruby_sourceline; } bodystmt kEND { $$ = NEW_CLASS($2, $5, $3); nd_set_line($$, $4); local_pop(); class_nest--; } | kCLASS tLSHFT expr { $$ = in_def; in_def = 0; } term { $$ = in_single; in_single = 0; class_nest++; local_push(0); } bodystmt kEND { $$ = NEW_SCLASS($3, $7); fixpos($$, $3); local_pop(); class_nest--; in_def = $4; in_single = $6; } | kMODULE cpath { if (in_def || in_single) yyerror("module definition in method body"); class_nest++; local_push(0); $$ = ruby_sourceline; } bodystmt kEND { $$ = NEW_MODULE($2, $4); nd_set_line($$, $3); local_pop(); class_nest--; } | kDEF fname { $$ = cur_mid; cur_mid = $2; in_def++; local_push(0); } f_arglist bodystmt kEND { if (!$5) $5 = NEW_NIL(); $$ = NEW_DEFN($2, $4, $5, NOEX_PRIVATE); fixpos($$, $4); local_pop(); in_def--; cur_mid = $3; } | kDEF singleton dot_or_colon {lex_state = EXPR_FNAME;} fname { in_single++; local_push(0); lex_state = EXPR_END; /* force for args */ } f_arglist bodystmt kEND { $$ = NEW_DEFS($2, $5, $7, $8); fixpos($$, $2); local_pop(); in_single--; } | kBREAK { $$ = NEW_BREAK(0); } | kNEXT { $$ = NEW_NEXT(0); } | kREDO { $$ = NEW_REDO(); } | kRETRY { $$ = NEW_RETRY(); } ; primary_value : primary { value_expr($1); $$ = $1; } ; then : term | ':' | kTHEN | term kTHEN ; do : term | ':' | kDO_COND ; if_tail : opt_else | kELSIF expr_value then compstmt if_tail { $$ = NEW_IF(cond($2), $4, $5); fixpos($$, $2); } ; opt_else : none | kELSE compstmt { $$ = $2; } ; for_var : lhs | mlhs ; block_par : mlhs_item { $$ = NEW_LIST($1); } | block_par ',' mlhs_item { $$ = list_append($1, $3); } ; block_var : block_par { if ($1->nd_alen == 1) { $$ = $1->nd_head; rb_gc_force_recycle((VALUE)$1); } else { $$ = NEW_MASGN($1, 0); } } | block_par ',' { $$ = NEW_MASGN($1, 0); } | block_par ',' tAMPER lhs { $$ = NEW_BLOCK_VAR($4, NEW_MASGN($1, 0)); } | block_par ',' tSTAR lhs ',' tAMPER lhs { $$ = NEW_BLOCK_VAR($7, NEW_MASGN($1, $4)); } | block_par ',' tSTAR ',' tAMPER lhs { $$ = NEW_BLOCK_VAR($6, NEW_MASGN($1, -1)); } | block_par ',' tSTAR lhs { $$ = NEW_MASGN($1, $4); } | block_par ',' tSTAR { $$ = NEW_MASGN($1, -1); } | tSTAR lhs ',' tAMPER lhs { $$ = NEW_BLOCK_VAR($5, NEW_MASGN(0, $2)); } | tSTAR ',' tAMPER lhs { $$ = NEW_BLOCK_VAR($4, NEW_MASGN(0, -1)); } | tSTAR lhs { $$ = NEW_MASGN(0, $2); } | tSTAR { $$ = NEW_MASGN(0, -1); } | tAMPER lhs { $$ = NEW_BLOCK_VAR($2, (NODE*)1); } ; opt_block_var : none | '|' /* none */ '|' { $$ = (NODE*)1; command_start = Qtrue; } | tOROP { $$ = (NODE*)1; command_start = Qtrue; } | '|' block_var '|' { $$ = $2; command_start = Qtrue; } ; do_block : kDO_BLOCK { $$ = dyna_push(); $1 = ruby_sourceline; } opt_block_var {$$ = ruby_dyna_vars;} compstmt kEND { $$ = NEW_ITER($3, 0, dyna_init($5, $4)); nd_set_line($$, $1); dyna_pop($2); } ; block_call : command do_block { if ($1 && nd_type($1) == NODE_BLOCK_PASS) { rb_compile_error("both block arg and actual block given"); } $2->nd_iter = $1; $$ = $2; fixpos($$, $1); } | block_call '.' operation2 opt_paren_args { $$ = new_call($1, $3, $4); } | block_call tCOLON2 operation2 opt_paren_args { $$ = new_call($1, $3, $4); } ; method_call : operation paren_args { $$ = new_fcall($1, $2); fixpos($$, $2); } | primary_value '.' operation2 opt_paren_args { $$ = new_call($1, $3, $4); fixpos($$, $1); } | primary_value tCOLON2 operation2 paren_args { $$ = new_call($1, $3, $4); fixpos($$, $1); } | primary_value tCOLON2 operation3 { $$ = new_call($1, $3, 0); } | kSUPER paren_args { $$ = new_super($2); } | kSUPER { $$ = NEW_ZSUPER(); } ; brace_block : '{' { $$ = dyna_push(); $1 = ruby_sourceline; } opt_block_var {$$ = ruby_dyna_vars;} compstmt '}' { $$ = NEW_ITER($3, 0, dyna_init($5, $4)); nd_set_line($$, $1); dyna_pop($2); } | kDO { $$ = dyna_push(); $1 = ruby_sourceline; } opt_block_var {$$ = ruby_dyna_vars;} compstmt kEND { $$ = NEW_ITER($3, 0, dyna_init($5, $4)); nd_set_line($$, $1); dyna_pop($2); } ; case_body : kWHEN when_args then compstmt cases { $$ = NEW_WHEN($2, $4, $5); } ; when_args : args | args ',' tSTAR arg_value { $$ = list_append($1, NEW_WHEN($4, 0, 0)); } | tSTAR arg_value { $$ = NEW_LIST(NEW_WHEN($2, 0, 0)); } ; cases : opt_else | case_body ; opt_rescue : kRESCUE exc_list exc_var then compstmt opt_rescue { if ($3) { $3 = node_assign($3, NEW_GVAR(rb_intern("$!"))); $5 = block_append($3, $5); } $$ = NEW_RESBODY($2, $5, $6); fixpos($$, $2?$2:$5); } | none ; exc_list : arg_value { $$ = NEW_LIST($1); } | mrhs | none ; exc_var : tASSOC lhs { $$ = $2; } | none ; opt_ensure : kENSURE compstmt { if ($2) $$ = $2; else /* place holder */ $$ = NEW_NIL(); } | none ; literal : numeric | symbol { $$ = NEW_LIT(ID2SYM($1)); } | dsym ; strings : string { NODE *node = $1; if (!node) { node = NEW_STR(rb_str_new(0, 0)); } else { node = evstr2dstr(node); } $$ = node; } ; string : string1 | string string1 { $$ = literal_concat($1, $2); } ; string1 : tSTRING_BEG string_contents tSTRING_END { $$ = $2; } ; xstring : tXSTRING_BEG xstring_contents tSTRING_END { NODE *node = $2; if (!node) { node = NEW_XSTR(rb_str_new(0, 0)); } else { switch (nd_type(node)) { case NODE_STR: nd_set_type(node, NODE_XSTR); break; case NODE_DSTR: nd_set_type(node, NODE_DXSTR); break; default: node = NEW_NODE(NODE_DXSTR, rb_str_new(0, 0), 1, NEW_LIST(node)); break; } } $$ = node; } ; regexp : tREGEXP_BEG xstring_contents tREGEXP_END { int options = $3; NODE *node = $2; if (!node) { node = NEW_LIT(rb_reg_new("", 0, options & ~RE_OPTION_ONCE)); } else switch (nd_type(node)) { case NODE_STR: { VALUE src = node->nd_lit; nd_set_type(node, NODE_LIT); node->nd_lit = rb_reg_new(RSTRING(src)->ptr, RSTRING(src)->len, options & ~RE_OPTION_ONCE); } break; default: node = NEW_NODE(NODE_DSTR, rb_str_new(0, 0), 1, NEW_LIST(node)); case NODE_DSTR: if (options & RE_OPTION_ONCE) { nd_set_type(node, NODE_DREGX_ONCE); } else { nd_set_type(node, NODE_DREGX); } node->nd_cflag = options & ~RE_OPTION_ONCE; break; } $$ = node; } ; words : tWORDS_BEG ' ' tSTRING_END { $$ = NEW_ZARRAY(); } | tWORDS_BEG word_list tSTRING_END { $$ = $2; } ; word_list : /* none */ { $$ = 0; } | word_list word ' ' { $$ = list_append($1, evstr2dstr($2)); } ; word : string_content | word string_content { $$ = literal_concat($1, $2); } ; qwords : tQWORDS_BEG ' ' tSTRING_END { $$ = NEW_ZARRAY(); } | tQWORDS_BEG qword_list tSTRING_END { $$ = $2; } ; qword_list : /* none */ { $$ = 0; } | qword_list tSTRING_CONTENT ' ' { $$ = list_append($1, $2); } ; string_contents : /* none */ { $$ = 0; } | string_contents string_content { $$ = literal_concat($1, $2); } ; xstring_contents: /* none */ { $$ = 0; } | xstring_contents string_content { $$ = literal_concat($1, $2); } ; string_content : tSTRING_CONTENT | tSTRING_DVAR { $$ = lex_strterm; lex_strterm = 0; lex_state = EXPR_BEG; } string_dvar { lex_strterm = $2; $$ = NEW_EVSTR($3); } | tSTRING_DBEG { $$ = lex_strterm; lex_strterm = 0; lex_state = EXPR_BEG; COND_PUSH(0); CMDARG_PUSH(0); } compstmt '}' { lex_strterm = $2; COND_LEXPOP(); CMDARG_LEXPOP(); if (($$ = $3) && nd_type($$) == NODE_NEWLINE) { $$ = $$->nd_next; rb_gc_force_recycle((VALUE)$3); } $$ = new_evstr($$); } ; string_dvar : tGVAR {$$ = NEW_GVAR($1);} | tIVAR {$$ = NEW_IVAR($1);} | tCVAR {$$ = NEW_CVAR($1);} | backref ; symbol : tSYMBEG sym { lex_state = EXPR_END; $$ = $2; } ; sym : fname | tIVAR | tGVAR | tCVAR ; dsym : tSYMBEG xstring_contents tSTRING_END { lex_state = EXPR_END; if (!($$ = $2)) { $$ = NEW_NIL(); yyerror("empty symbol literal"); } else { VALUE lit; switch (nd_type($$)) { case NODE_DSTR: nd_set_type($$, NODE_DSYM); break; case NODE_STR: lit = $$->nd_lit; if (RSTRING(lit)->len == 0) { yyerror("empty symbol literal"); break; } if (strlen(RSTRING(lit)->ptr) == RSTRING(lit)->len) { $$->nd_lit = ID2SYM(rb_intern(RSTRING($$->nd_lit)->ptr)); nd_set_type($$, NODE_LIT); break; } /* fall through */ default: $$ = NEW_DSYM(rb_str_new(0, 0), NEW_LIST($$)); break; } } } ; numeric : tINTEGER | tFLOAT | tUMINUS_NUM tINTEGER %prec tLOWEST { $$ = negate_lit($2); } | tUMINUS_NUM tFLOAT %prec tLOWEST { $$ = negate_lit($2); } ; variable : tIDENTIFIER | tIVAR | tGVAR | tCONSTANT | tCVAR | kNIL {$$ = kNIL;} | kSELF {$$ = kSELF;} | kTRUE {$$ = kTRUE;} | kFALSE {$$ = kFALSE;} | k__FILE__ {$$ = k__FILE__;} | k__LINE__ {$$ = k__LINE__;} ; var_ref : variable { $$ = gettable($1); } ; var_lhs : variable { $$ = assignable($1, 0); } ; backref : tNTH_REF | tBACK_REF ; superclass : term { $$ = 0; } | '<' { lex_state = EXPR_BEG; } expr_value term { $$ = $3; } | error term {yyerrok; $$ = 0;} ; f_arglist : '(' f_args opt_nl ')' { $$ = $2; lex_state = EXPR_BEG; command_start = Qtrue; } | f_args term { $$ = $1; } ; f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg { $$ = block_append(NEW_ARGS($1, $3, $5), $6); } | f_arg ',' f_optarg opt_f_block_arg { $$ = block_append(NEW_ARGS($1, $3, 0), $4); } | f_arg ',' f_rest_arg opt_f_block_arg { $$ = block_append(NEW_ARGS($1, 0, $3), $4); } | f_arg opt_f_block_arg { $$ = block_append(NEW_ARGS($1, 0, 0), $2); } | f_optarg ',' f_rest_arg opt_f_block_arg { $$ = block_append(NEW_ARGS(0, $1, $3), $4); } | f_optarg opt_f_block_arg { $$ = block_append(NEW_ARGS(0, $1, 0), $2); } | f_rest_arg opt_f_block_arg { $$ = block_append(NEW_ARGS(0, 0, $1), $2); } | f_block_arg { $$ = block_append(NEW_ARGS(0, 0, 0), $1); } | /* none */ { $$ = NEW_ARGS(0, 0, 0); } ; f_norm_arg : tCONSTANT { yyerror("formal argument cannot be a constant"); } | tIVAR { yyerror("formal argument cannot be an instance variable"); } | tGVAR { yyerror("formal argument cannot be a global variable"); } | tCVAR { yyerror("formal argument cannot be a class variable"); } | tIDENTIFIER { if (!is_local_id($1)) yyerror("formal argument must be local variable"); else if (local_id($1)) yyerror("duplicate argument name"); local_cnt($1); $$ = 1; } ; f_arg : f_norm_arg | f_arg ',' f_norm_arg { $$ += 1; } ; f_opt : tIDENTIFIER '=' arg_value { if (!is_local_id($1)) yyerror("formal argument must be local variable"); else if (local_id($1)) yyerror("duplicate optional argument name"); $$ = assignable($1, $3); } ; f_optarg : f_opt { $$ = NEW_BLOCK($1); $$->nd_end = $$; } | f_optarg ',' f_opt { $$ = block_append($1, $3); } ; restarg_mark : '*' | tSTAR ; f_rest_arg : restarg_mark tIDENTIFIER { if (!is_local_id($2)) yyerror("rest argument must be local variable"); else if (local_id($2)) yyerror("duplicate rest argument name"); if (dyna_in_block()) { rb_dvar_push($2, Qnil); } $$ = assignable($2, 0); } | restarg_mark { if (dyna_in_block()) { $$ = NEW_DASGN_CURR(internal_id(), 0); } else { $$ = NEW_NODE(NODE_LASGN,0,0,local_append(0)); } } ; blkarg_mark : '&' | tAMPER ; f_block_arg : blkarg_mark tIDENTIFIER { if (!is_local_id($2)) yyerror("block argument must be local variable"); else if (local_id($2)) yyerror("duplicate block argument name"); $$ = NEW_BLOCK_ARG($2); } ; opt_f_block_arg : ',' f_block_arg { $$ = $2; } | none ; singleton : var_ref { $$ = $1; value_expr($$); } | '(' {lex_state = EXPR_BEG;} expr opt_nl ')' { if ($3 == 0) { yyerror("can't define singleton method for ()."); } else { switch (nd_type($3)) { case NODE_STR: case NODE_DSTR: case NODE_XSTR: case NODE_DXSTR: case NODE_DREGX: case NODE_LIT: case NODE_ARRAY: case NODE_ZARRAY: yyerror("can't define singleton method for literals"); default: value_expr($3); break; } } $$ = $3; } ; assoc_list : none | assocs trailer { $$ = $1; } | args trailer { if ($1->nd_alen%2 != 0) { yyerror("odd number list for Hash"); } $$ = $1; } ; assocs : assoc | assocs ',' assoc { $$ = list_concat($1, $3); } ; assoc : arg_value tASSOC arg_value { $$ = list_append(NEW_LIST($1), $3); } ; operation : tIDENTIFIER | tCONSTANT | tFID ; operation2 : tIDENTIFIER | tCONSTANT | tFID | op ; operation3 : tIDENTIFIER | tFID | op ; dot_or_colon : '.' | tCOLON2 ; opt_terms : /* none */ | terms ; opt_nl : /* none */ | '\n' ; trailer : /* none */ | '\n' | ',' ; term : ';' {yyerrok;} | '\n' ; terms : term | terms ';' {yyerrok;} ; none : /* none */ {$$ = 0;} ; %% #ifdef yystacksize #undef YYMALLOC #endif #include "regex.h" #include "util.h" /* We remove any previous definition of `SIGN_EXTEND_CHAR', since ours (we hope) works properly with all combinations of machines, compilers, `char' and `unsigned char' argument types. (Per Bothner suggested the basic approach.) */ #undef SIGN_EXTEND_CHAR #if __STDC__ # define SIGN_EXTEND_CHAR(c) ((signed char)(c)) #else /* not __STDC__ */ /* As in Harbison and Steele. */ # define SIGN_EXTEND_CHAR(c) ((((unsigned char)(c)) ^ 128) - 128) #endif #define is_identchar(c) (SIGN_EXTEND_CHAR(c)!=-1&&(ISALNUM(c) || (c) == '_' || ismbchar(c))) static char *tokenbuf = NULL; static int tokidx, toksiz = 0; #define LEAVE_BS 1 static VALUE (*lex_gets)(); /* gets function */ static VALUE lex_input; /* non-nil if File */ static VALUE lex_lastline; /* gc protect */ static char *lex_pbeg; static char *lex_p; static char *lex_pend; static int yyerror(msg) const char *msg; { const int max_line_margin = 30; const char *p, *pe; char *buf; int len, i; rb_compile_error("%s", msg); p = lex_p; while (lex_pbeg <= p) { if (*p == '\n') break; p--; } p++; pe = lex_p; while (pe < lex_pend) { if (*pe == '\n') break; pe++; } len = pe - p; if (len > 4) { char *p2; const char *pre = "", *post = ""; if (len > max_line_margin * 2 + 10) { int re_mbc_startpos _((const char *, int, int, int)); if ((len = lex_p - p) > max_line_margin) { p = p + re_mbc_startpos(p, len, len - max_line_margin, 0); pre = "..."; } if ((len = pe - lex_p) > max_line_margin) { pe = lex_p + re_mbc_startpos(lex_p, len, max_line_margin, 1); post = "..."; } len = pe - p; } buf = ALLOCA_N(char, len+2); MEMCPY(buf, p, char, len); buf[len] = '\0'; rb_compile_error_append("%s%s%s", pre, buf, post); i = lex_p - p; p2 = buf; pe = buf + len; while (p2 < pe) { if (*p2 != '\t') *p2 = ' '; p2++; } buf[i] = '^'; buf[i+1] = '\0'; rb_compile_error_append("%s", buf); } return 0; } static int heredoc_end; int ruby_in_compile = 0; int ruby__end__seen; static VALUE ruby_debug_lines; #ifdef YYMALLOC static NODE *parser_heap; #endif static NODE* yycompile(f, line) char *f; int line; { int n; NODE *node = 0; struct RVarmap *vp, *vars = ruby_dyna_vars; ruby_in_compile = 1; ruby_in_longlife_context++; if (!compile_for_eval && rb_safe_level() == 0 && rb_const_defined(rb_cObject, rb_intern("SCRIPT_LINES__"))) { VALUE hash, fname; hash = rb_const_get(rb_cObject, rb_intern("SCRIPT_LINES__")); if (TYPE(hash) == T_HASH) { fname = rb_str_new2(f); ruby_debug_lines = rb_ary_new(); rb_hash_aset(hash, fname, ruby_debug_lines); } if (line > 1) { VALUE str = rb_str_new(0,0); while (line > 1) { rb_ary_push(ruby_debug_lines, str); line--; } } } ruby__end__seen = 0; ruby_eval_tree = 0; ruby_eval_tree_begin = 0; heredoc_end = 0; lex_strterm = 0; ruby_current_node = 0; ruby_sourcefile = rb_source_filename(f); deferred_nodes = 0; n = yyparse(); ruby_debug_lines = 0; compile_for_eval = 0; ruby_in_compile = 0; ruby_in_longlife_context--; cond_stack = 0; cmdarg_stack = 0; command_start = 1; class_nest = 0; in_single = 0; in_def = 0; cur_mid = 0; deferred_nodes = 0; vp = ruby_dyna_vars; ruby_dyna_vars = vars; lex_strterm = 0; while (vp && vp != vars) { struct RVarmap *tmp = vp; vp = vp->next; rb_gc_force_recycle((VALUE)tmp); } if (n == 0) node = ruby_eval_tree; if (ruby_nerrs) ruby_eval_tree_begin = 0; return node; } static int lex_gets_ptr; static VALUE lex_get_str(s) VALUE s; { char *beg, *end, *pend; beg = RSTRING(s)->ptr; if (lex_gets_ptr) { if (RSTRING(s)->len == lex_gets_ptr) return Qnil; beg += lex_gets_ptr; } pend = RSTRING(s)->ptr + RSTRING(s)->len; end = beg; while (end < pend) { if (*end++ == '\n') break; } lex_gets_ptr = end - RSTRING(s)->ptr; return rb_str_new(beg, end - beg); } static VALUE lex_getline() { VALUE line = (*lex_gets)(lex_input); if (ruby_debug_lines && !NIL_P(line)) { rb_ary_push(ruby_debug_lines, line); } return line; } NODE* rb_compile_string(f, s, line) const char *f; VALUE s; int line; { lex_gets = lex_get_str; lex_gets_ptr = 0; lex_input = s; lex_pbeg = lex_p = lex_pend = 0; ruby_sourceline = line - 1; compile_for_eval = ruby_in_eval; return yycompile(f, line); } NODE* rb_compile_cstr(f, s, len, line) const char *f, *s; int len, line; { return rb_compile_string(f, rb_str_new(s, len), line); } NODE* rb_compile_file(f, file, start) const char *f; VALUE file; int start; { lex_gets = rb_io_gets; lex_input = file; lex_pbeg = lex_p = lex_pend = 0; ruby_sourceline = start - 1; return yycompile(f, start); } static inline int nextc() { int c; if (lex_p == lex_pend) { if (lex_input) { VALUE v = lex_getline(); if (NIL_P(v)) return -1; if (heredoc_end > 0) { ruby_sourceline = heredoc_end; heredoc_end = 0; } ruby_sourceline++; lex_pbeg = lex_p = RSTRING(v)->ptr; lex_pend = lex_p + RSTRING(v)->len; lex_lastline = v; } else { lex_lastline = 0; return -1; } } c = (unsigned char)*lex_p++; if (c == '\r' && lex_p < lex_pend && *lex_p == '\n') { lex_p++; c = '\n'; } return c; } static void pushback(c) int c; { if (c == -1) return; lex_p--; } #define was_bol() (lex_p == lex_pbeg + 1) #define peek(c) (lex_p != lex_pend && (c) == *lex_p) #define tokfix() (tokenbuf[tokidx]='\0') #define tok() tokenbuf #define toklen() tokidx #define toklast() (tokidx>0?tokenbuf[tokidx-1]:0) static char* newtok() { tokidx = 0; if (!tokenbuf) { toksiz = 60; tokenbuf = ALLOC_N(char, 60); } if (toksiz > 4096) { toksiz = 60; REALLOC_N(tokenbuf, char, 60); } return tokenbuf; } static void tokadd(c) char c; { tokenbuf[tokidx++] = c; if (tokidx >= toksiz) { toksiz *= 2; REALLOC_N(tokenbuf, char, toksiz); } } static int read_escape() { int c; switch (c = nextc()) { case '\\': /* Backslash */ return c; case 'n': /* newline */ return '\n'; case 't': /* horizontal tab */ return '\t'; case 'r': /* carriage-return */ return '\r'; case 'f': /* form-feed */ return '\f'; case 'v': /* vertical tab */ return '\13'; case 'a': /* alarm(bell) */ return '\007'; case 'e': /* escape */ return 033; case '0': case '1': case '2': case '3': /* octal constant */ case '4': case '5': case '6': case '7': { int numlen; pushback(c); c = scan_oct(lex_p, 3, &numlen); lex_p += numlen; } return c; case 'x': /* hex constant */ { int numlen; c = scan_hex(lex_p, 2, &numlen); if (numlen == 0) { yyerror("Invalid escape character syntax"); return 0; } lex_p += numlen; } return c; case 'b': /* backspace */ return '\010'; case 's': /* space */ return ' '; case 'M': if ((c = nextc()) != '-') { yyerror("Invalid escape character syntax"); pushback(c); return '\0'; } if ((c = nextc()) == '\\') { return read_escape() | 0x80; } else if (c == -1) goto eof; else { return ((c & 0xff) | 0x80); } case 'C': if ((c = nextc()) != '-') { yyerror("Invalid escape character syntax"); pushback(c); return '\0'; } case 'c': if ((c = nextc())== '\\') { c = read_escape(); } else if (c == '?') return 0177; else if (c == -1) goto eof; return c & 0x9f; eof: case -1: yyerror("Invalid escape character syntax"); return '\0'; default: return c; } } static int tokadd_escape() { int c; switch (c = nextc()) { case '\n': return 0; /* just ignore */ case '0': case '1': case '2': case '3': /* octal constant */ case '4': case '5': case '6': case '7': { int i; tokadd('\\'); tokadd(c); for (i=0; i<2; i++) { c = nextc(); if (c == -1) goto eof; if (c < '0' || '7' < c) { pushback(c); break; } tokadd(c); } } return 0; case 'x': /* hex constant */ { int numlen; tokadd('\\'); tokadd(c); scan_hex(lex_p, 2, &numlen); if (numlen == 0) { yyerror("Invalid escape character syntax"); return -1; } while (numlen--) tokadd(nextc()); } return 0; case 'M': if ((c = nextc()) != '-') { yyerror("Invalid escape character syntax"); pushback(c); return 0; } tokadd('\\'); tokadd('M'); tokadd('-'); goto escaped; case 'C': if ((c = nextc()) != '-') { yyerror("Invalid escape character syntax"); pushback(c); return 0; } tokadd('\\'); tokadd('C'); tokadd('-'); goto escaped; case 'c': tokadd('\\'); tokadd('c'); escaped: if ((c = nextc()) == '\\') { return tokadd_escape(); } else if (c == -1) goto eof; tokadd(c); return 0; eof: case -1: yyerror("Invalid escape character syntax"); return -1; default: tokadd('\\'); tokadd(c); } return 0; } static int regx_options() { char kcode = 0; int options = 0; int c; newtok(); while (c = nextc(), ISALPHA(c)) { switch (c) { case 'i': options |= RE_OPTION_IGNORECASE; break; case 'x': options |= RE_OPTION_EXTENDED; break; case 'm': options |= RE_OPTION_MULTILINE; break; case 'o': options |= RE_OPTION_ONCE; break; case 'n': kcode = 16; break; case 'e': kcode = 32; break; case 's': kcode = 48; break; case 'u': kcode = 64; break; default: tokadd(c); break; } } pushback(c); if (toklen()) { tokfix(); rb_compile_error("unknown regexp option%s - %s", toklen() > 1 ? "s" : "", tok()); } return options | kcode; } #define STR_FUNC_ESCAPE 0x01 #define STR_FUNC_EXPAND 0x02 #define STR_FUNC_REGEXP 0x04 #define STR_FUNC_QWORDS 0x08 #define STR_FUNC_SYMBOL 0x10 #define STR_FUNC_INDENT 0x20 enum string_type { str_squote = (0), str_dquote = (STR_FUNC_EXPAND), str_xquote = (STR_FUNC_EXPAND), str_regexp = (STR_FUNC_REGEXP|STR_FUNC_ESCAPE|STR_FUNC_EXPAND), str_sword = (STR_FUNC_QWORDS), str_dword = (STR_FUNC_QWORDS|STR_FUNC_EXPAND), str_ssym = (STR_FUNC_SYMBOL), str_dsym = (STR_FUNC_SYMBOL|STR_FUNC_EXPAND), }; static void dispose_string(str) VALUE str; { xfree(RSTRING(str)->ptr); rb_gc_force_recycle(str); } static int tokadd_string(func, term, paren, nest) int func, term, paren, *nest; { int c; while ((c = nextc()) != -1) { if (paren && c == paren) { ++*nest; } else if (c == term) { if (!nest || !*nest) { pushback(c); break; } --*nest; } else if ((func & STR_FUNC_EXPAND) && c == '#' && lex_p < lex_pend) { int c2 = *lex_p; if (c2 == '$' || c2 == '@' || c2 == '{') { pushback(c); break; } } else if (c == '\\') { c = nextc(); switch (c) { case '\n': if (func & STR_FUNC_QWORDS) break; if (func & STR_FUNC_EXPAND) continue; tokadd('\\'); break; case '\\': if (func & STR_FUNC_ESCAPE) tokadd(c); break; default: if (func & STR_FUNC_REGEXP) { pushback(c); if (tokadd_escape() < 0) return -1; continue; } else if (func & STR_FUNC_EXPAND) { pushback(c); if (func & STR_FUNC_ESCAPE) tokadd('\\'); c = read_escape(); } else if ((func & STR_FUNC_QWORDS) && ISSPACE(c)) { /* ignore backslashed spaces in %w */ } else if (c != term && !(paren && c == paren)) { tokadd('\\'); } } } else if (ismbchar(c)) { int i, len = mbclen(c)-1; for (i = 0; i < len; i++) { tokadd(c); c = nextc(); } } else if ((func & STR_FUNC_QWORDS) && ISSPACE(c)) { pushback(c); break; } if (!c && (func & STR_FUNC_SYMBOL)) { func &= ~STR_FUNC_SYMBOL; rb_compile_error("symbol cannot contain '\\0'"); continue; } tokadd(c); } return c; } #define NEW_STRTERM(func, term, paren) \ NEW_NODE(NODE_STRTERM, (func), (term) | ((paren) << (CHAR_BIT * 2)), 0) static int parse_string(quote) NODE *quote; { int func = quote->nd_func; int term = nd_term(quote); int paren = nd_paren(quote); int c, space = 0; if (func == -1) return tSTRING_END; c = nextc(); if ((func & STR_FUNC_QWORDS) && ISSPACE(c)) { do {c = nextc();} while (ISSPACE(c)); space = 1; } if (c == term && !quote->nd_nest) { if (func & STR_FUNC_QWORDS) { quote->nd_func = -1; return ' '; } if (!(func & STR_FUNC_REGEXP)) return tSTRING_END; yylval.num = regx_options(); return tREGEXP_END; } if (space) { pushback(c); return ' '; } newtok(); if ((func & STR_FUNC_EXPAND) && c == '#') { switch (c = nextc()) { case '$': case '@': pushback(c); return tSTRING_DVAR; case '{': return tSTRING_DBEG; } tokadd('#'); } pushback(c); if (tokadd_string(func, term, paren, "e->nd_nest) == -1) { ruby_sourceline = nd_line(quote); rb_compile_error("unterminated string meets end of file"); return tSTRING_END; } tokfix(); yylval.node = NEW_STR(rb_str_new(tok(), toklen())); return tSTRING_CONTENT; } static int heredoc_identifier() { int c = nextc(), term, func = 0, len; if (c == '-') { c = nextc(); func = STR_FUNC_INDENT; } switch (c) { case '\'': func |= str_squote; goto quoted; case '"': func |= str_dquote; goto quoted; case '`': func |= str_xquote; quoted: newtok(); tokadd(func); term = c; while ((c = nextc()) != -1 && c != term) { len = mbclen(c); do {tokadd(c);} while (--len > 0 && (c = nextc()) != -1); } if (c == -1) { rb_compile_error("unterminated here document identifier"); return 0; } break; default: if (!is_identchar(c)) { pushback(c); if (func & STR_FUNC_INDENT) { pushback('-'); } return 0; } newtok(); term = '"'; tokadd(func |= str_dquote); do { len = mbclen(c); do {tokadd(c);} while (--len > 0 && (c = nextc()) != -1); } while ((c = nextc()) != -1 && is_identchar(c)); pushback(c); break; } tokfix(); len = lex_p - lex_pbeg; lex_p = lex_pend; lex_strterm = NEW_NODE(NODE_HEREDOC, rb_str_new(tok(), toklen()), /* nd_lit */ len, /* nd_nth */ lex_lastline); /* nd_orig */ return term == '`' ? tXSTRING_BEG : tSTRING_BEG; } static void heredoc_restore(here) NODE *here; { VALUE line = here->nd_orig; lex_lastline = line; lex_pbeg = RSTRING(line)->ptr; lex_pend = lex_pbeg + RSTRING(line)->len; lex_p = lex_pbeg + here->nd_nth; heredoc_end = ruby_sourceline; ruby_sourceline = nd_line(here); dispose_string(here->nd_lit); rb_gc_force_recycle((VALUE)here); } static int whole_match_p(eos, len, indent) char *eos; int len, indent; { char *p = lex_pbeg; int n; if (indent) { while (*p && ISSPACE(*p)) p++; } n= lex_pend - (p + len); if (n < 0 || (n > 0 && p[len] != '\n' && p[len] != '\r')) return Qfalse; if (strncmp(eos, p, len) == 0) return Qtrue; return Qfalse; } static int here_document(here) NODE *here; { int c, func, indent = 0; char *eos, *p, *pend; long len; VALUE str = 0; eos = RSTRING(here->nd_lit)->ptr; len = RSTRING(here->nd_lit)->len - 1; indent = (func = *eos++) & STR_FUNC_INDENT; if ((c = nextc()) == -1) { error: rb_compile_error("can't find string \"%s\" anywhere before EOF", eos); heredoc_restore(lex_strterm); lex_strterm = 0; return 0; } if (was_bol() && whole_match_p(eos, len, indent)) { heredoc_restore(lex_strterm); return tSTRING_END; } if (!(func & STR_FUNC_EXPAND)) { do { p = RSTRING(lex_lastline)->ptr; pend = lex_pend; if (pend > p) { switch (pend[-1]) { case '\n': if (--pend == p || pend[-1] != '\r') { pend++; break; } case '\r': --pend; } } if (str) rb_str_cat(str, p, pend - p); else str = rb_str_new(p, pend - p); if (pend < lex_pend) rb_str_cat(str, "\n", 1); lex_p = lex_pend; if (nextc() == -1) { if (str) dispose_string(str); goto error; } } while (!whole_match_p(eos, len, indent)); } else { newtok(); if (c == '#') { switch (c = nextc()) { case '$': case '@': pushback(c); return tSTRING_DVAR; case '{': return tSTRING_DBEG; } tokadd('#'); } do { pushback(c); if ((c = tokadd_string(func, '\n', 0, NULL)) == -1) goto error; if (c != '\n') { yylval.node = NEW_STR(rb_str_new(tok(), toklen())); return tSTRING_CONTENT; } tokadd(nextc()); if ((c = nextc()) == -1) goto error; } while (!whole_match_p(eos, len, indent)); str = rb_str_new(tok(), toklen()); } heredoc_restore(lex_strterm); lex_strterm = NEW_STRTERM(-1, 0, 0); yylval.node = NEW_STR(str); return tSTRING_CONTENT; } #include "lex.c" static void arg_ambiguous() { rb_warning("ambiguous first argument; put parentheses or even spaces"); } #define IS_ARG() (lex_state == EXPR_ARG || lex_state == EXPR_CMDARG) #define IS_BEG() (lex_state == EXPR_BEG || lex_state == EXPR_MID || lex_state == EXPR_CLASS) static int yylex() { register int c; int space_seen = 0; int cmd_state; enum lex_state last_state; if (lex_strterm) { int token; if (nd_type(lex_strterm) == NODE_HEREDOC) { token = here_document(lex_strterm); if (token == tSTRING_END) { lex_strterm = 0; lex_state = EXPR_END; } } else { token = parse_string(lex_strterm); if (token == tSTRING_END || token == tREGEXP_END) { rb_gc_force_recycle((VALUE)lex_strterm); lex_strterm = 0; lex_state = EXPR_END; } } return token; } cmd_state = command_start; command_start = Qfalse; retry: switch (c = nextc()) { case '\0': /* NUL */ case '\004': /* ^D */ case '\032': /* ^Z */ case -1: /* end of script. */ return 0; /* white spaces */ case ' ': case '\t': case '\f': case '\r': case '\13': /* '\v' */ space_seen++; goto retry; case '#': /* it's a comment */ while ((c = nextc()) != '\n') { if (c == -1) return 0; } /* fall through */ case '\n': switch (lex_state) { case EXPR_BEG: case EXPR_FNAME: case EXPR_DOT: case EXPR_CLASS: goto retry; default: break; } command_start = Qtrue; lex_state = EXPR_BEG; return '\n'; case '*': if ((c = nextc()) == '*') { if ((c = nextc()) == '=') { yylval.id = tPOW; lex_state = EXPR_BEG; return tOP_ASGN; } pushback(c); c = tPOW; } else { if (c == '=') { yylval.id = '*'; lex_state = EXPR_BEG; return tOP_ASGN; } pushback(c); if (IS_ARG() && space_seen && !ISSPACE(c)){ rb_warning("`*' interpreted as argument prefix"); c = tSTAR; } else if (IS_BEG()) { c = tSTAR; } else { c = '*'; } } switch (lex_state) { case EXPR_FNAME: case EXPR_DOT: lex_state = EXPR_ARG; break; default: lex_state = EXPR_BEG; break; } return c; case '!': lex_state = EXPR_BEG; if ((c = nextc()) == '=') { return tNEQ; } if (c == '~') { return tNMATCH; } pushback(c); return '!'; case '=': if (was_bol()) { /* skip embedded rd document */ if (strncmp(lex_p, "begin", 5) == 0 && ISSPACE(lex_p[5])) { for (;;) { lex_p = lex_pend; c = nextc(); if (c == -1) { rb_compile_error("embedded document meets end of file"); return 0; } if (c != '=') continue; if (strncmp(lex_p, "end", 3) == 0 && (lex_p + 3 == lex_pend || ISSPACE(lex_p[3]))) { break; } } lex_p = lex_pend; goto retry; } } switch (lex_state) { case EXPR_FNAME: case EXPR_DOT: lex_state = EXPR_ARG; break; default: lex_state = EXPR_BEG; break; } if ((c = nextc()) == '=') { if ((c = nextc()) == '=') { return tEQQ; } pushback(c); return tEQ; } if (c == '~') { return tMATCH; } else if (c == '>') { return tASSOC; } pushback(c); return '='; case '<': c = nextc(); if (c == '<' && lex_state != EXPR_END && lex_state != EXPR_DOT && lex_state != EXPR_ENDARG && lex_state != EXPR_CLASS && (!IS_ARG() || space_seen)) { int token = heredoc_identifier(); if (token) return token; } switch (lex_state) { case EXPR_FNAME: case EXPR_DOT: lex_state = EXPR_ARG; break; default: lex_state = EXPR_BEG; break; } if (c == '=') { if ((c = nextc()) == '>') { return tCMP; } pushback(c); return tLEQ; } if (c == '<') { if ((c = nextc()) == '=') { yylval.id = tLSHFT; lex_state = EXPR_BEG; return tOP_ASGN; } pushback(c); return tLSHFT; } pushback(c); return '<'; case '>': switch (lex_state) { case EXPR_FNAME: case EXPR_DOT: lex_state = EXPR_ARG; break; default: lex_state = EXPR_BEG; break; } if ((c = nextc()) == '=') { return tGEQ; } if (c == '>') { if ((c = nextc()) == '=') { yylval.id = tRSHFT; lex_state = EXPR_BEG; return tOP_ASGN; } pushback(c); return tRSHFT; } pushback(c); return '>'; case '"': lex_strterm = NEW_STRTERM(str_dquote, '"', 0); return tSTRING_BEG; case '`': if (lex_state == EXPR_FNAME) { lex_state = EXPR_END; return c; } if (lex_state == EXPR_DOT) { if (cmd_state) lex_state = EXPR_CMDARG; else lex_state = EXPR_ARG; return c; } lex_strterm = NEW_STRTERM(str_xquote, '`', 0); return tXSTRING_BEG; case '\'': lex_strterm = NEW_STRTERM(str_squote, '\'', 0); return tSTRING_BEG; case '?': if (lex_state == EXPR_END || lex_state == EXPR_ENDARG) { lex_state = EXPR_BEG; return '?'; } c = nextc(); if (c == -1) { rb_compile_error("incomplete character syntax"); return 0; } if (ISSPACE(c)){ if (!IS_ARG()){ int c2 = 0; switch (c) { case ' ': c2 = 's'; break; case '\n': c2 = 'n'; break; case '\t': c2 = 't'; break; case '\v': c2 = 'v'; break; case '\r': c2 = 'r'; break; case '\f': c2 = 'f'; break; } if (c2) { rb_warn("invalid character syntax; use ?\\%c", c2); } } ternary: pushback(c); lex_state = EXPR_BEG; return '?'; } else if (ismbchar(c)) { rb_warn("multibyte character literal not supported yet; use ?\\%.3o", c); goto ternary; } else if ((ISALNUM(c) || c == '_') && lex_p < lex_pend && is_identchar(*lex_p)) { goto ternary; } else if (c == '\\') { c = read_escape(); } c &= 0xff; lex_state = EXPR_END; yylval.node = NEW_LIT(INT2FIX(c)); return tINTEGER; case '&': if ((c = nextc()) == '&') { lex_state = EXPR_BEG; if ((c = nextc()) == '=') { yylval.id = tANDOP; lex_state = EXPR_BEG; return tOP_ASGN; } pushback(c); return tANDOP; } else if (c == '=') { yylval.id = '&'; lex_state = EXPR_BEG; return tOP_ASGN; } pushback(c); if (IS_ARG() && space_seen && !ISSPACE(c)){ rb_warning("`&' interpreted as argument prefix"); c = tAMPER; } else if (IS_BEG()) { c = tAMPER; } else { c = '&'; } switch (lex_state) { case EXPR_FNAME: case EXPR_DOT: lex_state = EXPR_ARG; break; default: lex_state = EXPR_BEG; } return c; case '|': if ((c = nextc()) == '|') { lex_state = EXPR_BEG; if ((c = nextc()) == '=') { yylval.id = tOROP; lex_state = EXPR_BEG; return tOP_ASGN; } pushback(c); return tOROP; } if (c == '=') { yylval.id = '|'; lex_state = EXPR_BEG; return tOP_ASGN; } if (lex_state == EXPR_FNAME || lex_state == EXPR_DOT) { lex_state = EXPR_ARG; } else { lex_state = EXPR_BEG; } pushback(c); return '|'; case '+': c = nextc(); if (lex_state == EXPR_FNAME || lex_state == EXPR_DOT) { lex_state = EXPR_ARG; if (c == '@') { return tUPLUS; } pushback(c); return '+'; } if (c == '=') { yylval.id = '+'; lex_state = EXPR_BEG; return tOP_ASGN; } if (IS_BEG() || (IS_ARG() && space_seen && !ISSPACE(c))) { if (IS_ARG()) arg_ambiguous(); lex_state = EXPR_BEG; pushback(c); if (ISDIGIT(c)) { c = '+'; goto start_num; } return tUPLUS; } lex_state = EXPR_BEG; pushback(c); return '+'; case '-': c = nextc(); if (lex_state == EXPR_FNAME || lex_state == EXPR_DOT) { lex_state = EXPR_ARG; if (c == '@') { return tUMINUS; } pushback(c); return '-'; } if (c == '=') { yylval.id = '-'; lex_state = EXPR_BEG; return tOP_ASGN; } if (IS_BEG() || (IS_ARG() && space_seen && !ISSPACE(c))) { if (IS_ARG()) arg_ambiguous(); lex_state = EXPR_BEG; pushback(c); if (ISDIGIT(c)) { return tUMINUS_NUM; } return tUMINUS; } lex_state = EXPR_BEG; pushback(c); return '-'; case '.': lex_state = EXPR_BEG; if ((c = nextc()) == '.') { if ((c = nextc()) == '.') { return tDOT3; } pushback(c); return tDOT2; } pushback(c); if (ISDIGIT(c)) { yyerror("no . floating literal anymore; put 0 before dot"); } lex_state = EXPR_DOT; return '.'; start_num: case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { int is_float, seen_point, seen_e, nondigit; is_float = seen_point = seen_e = nondigit = 0; lex_state = EXPR_END; newtok(); if (c == '-' || c == '+') { tokadd(c); c = nextc(); } if (c == '0') { int start = toklen(); c = nextc(); if (c == 'x' || c == 'X') { /* hexadecimal */ c = nextc(); if (ISXDIGIT(c)) { do { if (c == '_') { if (nondigit) break; nondigit = c; continue; } if (!ISXDIGIT(c)) break; nondigit = 0; tokadd(c); } while ((c = nextc()) != -1); } pushback(c); tokfix(); if (toklen() == start) { yyerror("numeric literal without digits"); } else if (nondigit) goto trailing_uc; yylval.node = NEW_LIT(rb_cstr_to_inum(tok(), 16, Qfalse)); return tINTEGER; } if (c == 'b' || c == 'B') { /* binary */ c = nextc(); if (c == '0' || c == '1') { do { if (c == '_') { if (nondigit) break; nondigit = c; continue; } if (c != '0' && c != '1') break; nondigit = 0; tokadd(c); } while ((c = nextc()) != -1); } pushback(c); tokfix(); if (toklen() == start) { yyerror("numeric literal without digits"); } else if (nondigit) goto trailing_uc; yylval.node = NEW_LIT(rb_cstr_to_inum(tok(), 2, Qfalse)); return tINTEGER; } if (c == 'd' || c == 'D') { /* decimal */ c = nextc(); if (ISDIGIT(c)) { do { if (c == '_') { if (nondigit) break; nondigit = c; continue; } if (!ISDIGIT(c)) break; nondigit = 0; tokadd(c); } while ((c = nextc()) != -1); } pushback(c); tokfix(); if (toklen() == start) { yyerror("numeric literal without digits"); } else if (nondigit) goto trailing_uc; yylval.node = NEW_LIT(rb_cstr_to_inum(tok(), 10, Qfalse)); return tINTEGER; } if (c == '_') { /* 0_0 */ goto octal_number; } if (c == 'o' || c == 'O') { /* prefixed octal */ c = nextc(); if (c == '_') { yyerror("numeric literal without digits"); } } if (c >= '0' && c <= '7') { /* octal */ octal_number: do { if (c == '_') { if (nondigit) break; nondigit = c; continue; } if (c < '0' || c > '9') break; if (c > '7') goto invalid_octal; nondigit = 0; tokadd(c); } while ((c = nextc()) != -1); if (toklen() > start) { pushback(c); tokfix(); if (nondigit) goto trailing_uc; yylval.node = NEW_LIT(rb_cstr_to_inum(tok(), 8, Qfalse)); return tINTEGER; } if (nondigit) { pushback(c); goto trailing_uc; } } if (c > '7' && c <= '9') { invalid_octal: yyerror("Illegal octal digit"); } else if (c == '.' || c == 'e' || c == 'E') { tokadd('0'); } else { pushback(c); yylval.node = NEW_LIT(INT2FIX(0)); return tINTEGER; } } for (;;) { switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': nondigit = 0; tokadd(c); break; case '.': if (nondigit) goto trailing_uc; if (seen_point || seen_e) { goto decode_num; } else { int c0 = nextc(); if (!ISDIGIT(c0)) { pushback(c0); goto decode_num; } c = c0; } tokadd('.'); tokadd(c); is_float++; seen_point++; nondigit = 0; break; case 'e': case 'E': if (nondigit) { pushback(c); c = nondigit; goto decode_num; } if (seen_e) { goto decode_num; } tokadd(c); seen_e++; is_float++; nondigit = c; c = nextc(); if (c != '-' && c != '+') continue; tokadd(c); nondigit = c; break; case '_': /* `_' in number just ignored */ if (nondigit) goto decode_num; nondigit = c; break; default: goto decode_num; } c = nextc(); } decode_num: pushback(c); tokfix(); if (nondigit) { char tmp[30]; trailing_uc: sprintf(tmp, "trailing `%c' in number", nondigit); yyerror(tmp); } if (is_float) { double d = strtod(tok(), 0); if (errno == ERANGE) { rb_warn("Float %s out of range", tok()); errno = 0; } yylval.node = NEW_LIT(rb_float_new(d)); return tFLOAT; } yylval.node = NEW_LIT(rb_cstr_to_inum(tok(), 10, Qfalse)); return tINTEGER; } case ']': case '}': case ')': COND_LEXPOP(); CMDARG_LEXPOP(); lex_state = EXPR_END; return c; case ':': c = nextc(); if (c == ':') { if (IS_BEG() || (IS_ARG() && space_seen)) { lex_state = EXPR_BEG; return tCOLON3; } lex_state = EXPR_DOT; return tCOLON2; } if (lex_state == EXPR_END || lex_state == EXPR_ENDARG || ISSPACE(c)) { pushback(c); lex_state = EXPR_BEG; return ':'; } switch (c) { case '\'': lex_strterm = NEW_STRTERM(str_ssym, c, 0); break; case '"': lex_strterm = NEW_STRTERM(str_dsym, c, 0); break; default: pushback(c); break; } lex_state = EXPR_FNAME; return tSYMBEG; case '/': if (IS_BEG()) { lex_strterm = NEW_STRTERM(str_regexp, '/', 0); return tREGEXP_BEG; } if ((c = nextc()) == '=') { yylval.id = '/'; lex_state = EXPR_BEG; return tOP_ASGN; } pushback(c); if (IS_ARG() && space_seen) { if (!ISSPACE(c)) { arg_ambiguous(); lex_strterm = NEW_STRTERM(str_regexp, '/', 0); return tREGEXP_BEG; } } switch (lex_state) { case EXPR_FNAME: case EXPR_DOT: lex_state = EXPR_ARG; break; default: lex_state = EXPR_BEG; break; } return '/'; case '^': if ((c = nextc()) == '=') { yylval.id = '^'; lex_state = EXPR_BEG; return tOP_ASGN; } switch (lex_state) { case EXPR_FNAME: case EXPR_DOT: lex_state = EXPR_ARG; break; default: lex_state = EXPR_BEG; break; } pushback(c); return '^'; case ';': command_start = Qtrue; case ',': lex_state = EXPR_BEG; return c; case '~': if (lex_state == EXPR_FNAME || lex_state == EXPR_DOT) { if ((c = nextc()) != '@') { pushback(c); } } switch (lex_state) { case EXPR_FNAME: case EXPR_DOT: lex_state = EXPR_ARG; break; default: lex_state = EXPR_BEG; break; } return '~'; case '(': command_start = Qtrue; if (IS_BEG()) { c = tLPAREN; } else if (space_seen) { if (lex_state == EXPR_CMDARG) { c = tLPAREN_ARG; } else if (lex_state == EXPR_ARG) { rb_warn("don't put space before argument parentheses"); c = '('; } } COND_PUSH(0); CMDARG_PUSH(0); lex_state = EXPR_BEG; return c; case '[': if (lex_state == EXPR_FNAME || lex_state == EXPR_DOT) { lex_state = EXPR_ARG; if ((c = nextc()) == ']') { if ((c = nextc()) == '=') { return tASET; } pushback(c); return tAREF; } pushback(c); return '['; } else if (IS_BEG()) { c = tLBRACK; } else if (IS_ARG() && space_seen) { c = tLBRACK; } lex_state = EXPR_BEG; COND_PUSH(0); CMDARG_PUSH(0); return c; case '{': if (IS_ARG() || lex_state == EXPR_END) c = '{'; /* block (primary) */ else if (lex_state == EXPR_ENDARG) c = tLBRACE_ARG; /* block (expr) */ else c = tLBRACE; /* hash */ COND_PUSH(0); CMDARG_PUSH(0); lex_state = EXPR_BEG; if (c != tLBRACE) command_start = Qtrue; return c; case '\\': c = nextc(); if (c == '\n') { space_seen = 1; goto retry; /* skip \\n */ } pushback(c); return '\\'; case '%': if (IS_BEG()) { int term; int paren; c = nextc(); quotation: if (!ISALNUM(c)) { term = c; c = 'Q'; } else { term = nextc(); if (ISALNUM(term) || ismbchar(term)) { yyerror("unknown type of %string"); return 0; } } if (c == -1 || term == -1) { rb_compile_error("unterminated quoted string meets end of file"); return 0; } paren = term; if (term == '(') term = ')'; else if (term == '[') term = ']'; else if (term == '{') term = '}'; else if (term == '<') term = '>'; else paren = 0; switch (c) { case 'Q': lex_strterm = NEW_STRTERM(str_dquote, term, paren); return tSTRING_BEG; case 'q': lex_strterm = NEW_STRTERM(str_squote, term, paren); return tSTRING_BEG; case 'W': lex_strterm = NEW_STRTERM(str_dword, term, paren); do {c = nextc();} while (ISSPACE(c)); pushback(c); return tWORDS_BEG; case 'w': lex_strterm = NEW_STRTERM(str_sword, term, paren); do {c = nextc();} while (ISSPACE(c)); pushback(c); return tQWORDS_BEG; case 'x': lex_strterm = NEW_STRTERM(str_xquote, term, paren); return tXSTRING_BEG; case 'r': lex_strterm = NEW_STRTERM(str_regexp, term, paren); return tREGEXP_BEG; case 's': lex_strterm = NEW_STRTERM(str_ssym, term, paren); lex_state = EXPR_FNAME; return tSYMBEG; default: yyerror("unknown type of %string"); return 0; } } if ((c = nextc()) == '=') { yylval.id = '%'; lex_state = EXPR_BEG; return tOP_ASGN; } if (IS_ARG() && space_seen && !ISSPACE(c)) { goto quotation; } switch (lex_state) { case EXPR_FNAME: case EXPR_DOT: lex_state = EXPR_ARG; break; default: lex_state = EXPR_BEG; break; } pushback(c); return '%'; case '$': last_state = lex_state; lex_state = EXPR_END; newtok(); c = nextc(); switch (c) { case '_': /* $_: last read line string */ c = nextc(); if (is_identchar(c)) { tokadd('$'); tokadd('_'); break; } pushback(c); c = '_'; /* fall through */ case '~': /* $~: match-data */ local_cnt(c); /* fall through */ case '*': /* $*: argv */ case '$': /* $$: pid */ case '?': /* $?: last status */ case '!': /* $!: error string */ case '@': /* $@: error position */ case '/': /* $/: input record separator */ case '\\': /* $\: output record separator */ case ';': /* $;: field separator */ case ',': /* $,: output field separator */ case '.': /* $.: last read line number */ case '=': /* $=: ignorecase */ case ':': /* $:: load path */ case '<': /* $<: reading filename */ case '>': /* $>: default output handle */ case '\"': /* $": already loaded files */ tokadd('$'); tokadd(c); tokfix(); yylval.id = rb_intern(tok()); return tGVAR; case '-': tokadd('$'); tokadd(c); c = nextc(); if (is_identchar(c)) { tokadd(c); } else { pushback(c); } gvar: tokfix(); yylval.id = rb_intern(tok()); /* xxx shouldn't check if valid option variable */ return tGVAR; case '&': /* $&: last match */ case '`': /* $`: string before last match */ case '\'': /* $': string after last match */ case '+': /* $+: string matches last paren. */ if (last_state == EXPR_FNAME) { tokadd('$'); tokadd(c); goto gvar; } yylval.node = NEW_BACK_REF(c); return tBACK_REF; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': tokadd('$'); do { tokadd(c); c = nextc(); } while (ISDIGIT(c)); pushback(c); if (last_state == EXPR_FNAME) goto gvar; tokfix(); yylval.node = NEW_NTH_REF(atoi(tok()+1)); return tNTH_REF; default: if (!is_identchar(c)) { pushback(c); return '$'; } case '0': tokadd('$'); } break; case '@': c = nextc(); newtok(); tokadd('@'); if (c == '@') { tokadd('@'); c = nextc(); } if (ISDIGIT(c)) { if (tokidx == 1) { rb_compile_error("`@%c' is not allowed as an instance variable name", c); } else { rb_compile_error("`@@%c' is not allowed as a class variable name", c); } return 0; } if (!is_identchar(c)) { pushback(c); return '@'; } break; case '_': if (was_bol() && whole_match_p("__END__", 7, 0)) { ruby__end__seen = 1; lex_lastline = 0; return -1; } newtok(); break; default: if (!is_identchar(c)) { rb_compile_error("Invalid char `\\%03o' in expression", c); goto retry; } newtok(); break; } do { tokadd(c); if (ismbchar(c)) { int i, len = mbclen(c)-1; for (i = 0; i < len; i++) { c = nextc(); tokadd(c); } } c = nextc(); } while (is_identchar(c)); if ((c == '!' || c == '?') && is_identchar(tok()[0]) && !peek('=')) { tokadd(c); } else { pushback(c); } tokfix(); { int result = 0; last_state = lex_state; switch (tok()[0]) { case '$': lex_state = EXPR_END; result = tGVAR; break; case '@': lex_state = EXPR_END; if (tok()[1] == '@') result = tCVAR; else result = tIVAR; break; default: if (toklast() == '!' || toklast() == '?') { result = tFID; } else { if (lex_state == EXPR_FNAME) { if ((c = nextc()) == '=' && !peek('~') && !peek('>') && (!peek('=') || (lex_p + 1 < lex_pend && lex_p[1] == '>'))) { result = tIDENTIFIER; tokadd(c); tokfix(); } else { pushback(c); } } if (result == 0 && ISUPPER(tok()[0])) { result = tCONSTANT; } else { result = tIDENTIFIER; } } if (lex_state != EXPR_DOT) { const struct kwtable *kw; /* See if it is a reserved word. */ kw = rb_reserved_word(tok(), toklen()); if (kw) { enum lex_state state = lex_state; lex_state = kw->state; if (state == EXPR_FNAME) { yylval.id = rb_intern(kw->name); return kw->id[0]; } if (kw->id[0] == kDO) { command_start = Qtrue; if (COND_P()) return kDO_COND; if (CMDARG_P() && state != EXPR_CMDARG) return kDO_BLOCK; if (state == EXPR_ENDARG) return kDO_BLOCK; return kDO; } if (state == EXPR_BEG) return kw->id[0]; else { if (kw->id[0] != kw->id[1]) lex_state = EXPR_BEG; return kw->id[1]; } } } if (lex_state == EXPR_BEG || lex_state == EXPR_MID || lex_state == EXPR_DOT || lex_state == EXPR_ARG || lex_state == EXPR_CLASS || lex_state == EXPR_CMDARG) { if (cmd_state) { lex_state = EXPR_CMDARG; } else { lex_state = EXPR_ARG; } } else { lex_state = EXPR_END; } } yylval.id = rb_intern(tok()); if (is_local_id(yylval.id) && last_state != EXPR_DOT && ((dyna_in_block() && rb_dvar_defined(yylval.id)) || local_id(yylval.id))) { lex_state = EXPR_END; } return result; } } NODE* rb_node_newnode_eden(type, a0, a1, a2) enum node_type type; VALUE a0, a1, a2; { NODE *n = (NODE*)rb_newobj_eden(type); n->flags |= T_NODE; nd_set_type(n, type); nd_set_line(n, ruby_sourceline); n->nd_file = ruby_sourcefile; n->u1.value = a0; n->u2.value = a1; n->u3.value = a2; return n; } NODE* rb_node_newnode_longlife(type, a0, a1, a2) enum node_type type; VALUE a0, a1, a2; { NODE *n = (NODE*) rb_newobj_longlife((int)type); n->flags |= T_NODE; nd_set_type(n, type); nd_set_line(n, ruby_sourceline); n->nd_file = ruby_sourcefile; n->u1.value = a0; n->u2.value = a1; n->u3.value = a2; return n; } static enum node_type nodetype(node) /* for debug */ NODE *node; { return (enum node_type)nd_type(node); } static int nodeline(node) NODE *node; { return nd_line(node); } static NODE* newline_node(node) NODE *node; { NODE *nl = 0; if (node) { int line; if (nd_type(node) == NODE_NEWLINE) return node; line = nd_line(node); node = remove_begin(node); nl = NEW_NEWLINE(node); nd_set_line(nl, line); nl->nd_nth = line; } return nl; } static void fixpos(node, orig) NODE *node, *orig; { if (!node) return; if (!orig) return; if (orig == (NODE*)1) return; node->nd_file = orig->nd_file; nd_set_line(node, nd_line(orig)); } static void parser_warning(node, mesg) NODE *node; const char *mesg; { int line = ruby_sourceline; ruby_sourceline = nd_line(node); rb_warning("%s", mesg); ruby_sourceline = line; } static void parser_warn(node, mesg) NODE *node; const char *mesg; { int line = ruby_sourceline; ruby_sourceline = nd_line(node); rb_warn("%s", mesg); ruby_sourceline = line; } static NODE* block_append(head, tail) NODE *head, *tail; { NODE *end, *h = head; if (tail == 0) return head; again: if (h == 0) return tail; switch (nd_type(h)) { case NODE_NEWLINE: h = h->nd_next; goto again; case NODE_LIT: case NODE_STR: parser_warning(h, "unused literal ignored"); return tail; default: h = end = NEW_BLOCK(head); end->nd_end = end; fixpos(end, head); head = end; break; case NODE_BLOCK: end = h->nd_end; break; } if (RTEST(ruby_verbose)) { NODE *nd = end->nd_head; newline: switch (nd_type(nd)) { case NODE_RETURN: case NODE_BREAK: case NODE_NEXT: case NODE_REDO: case NODE_RETRY: parser_warning(nd, "statement not reached"); break; case NODE_NEWLINE: nd = nd->nd_next; goto newline; default: break; } } if (nd_type(tail) != NODE_BLOCK) { tail = NEW_BLOCK(tail); tail->nd_end = tail; } end->nd_next = tail; h->nd_end = tail->nd_end; return head; } /* append item to the list */ static NODE* list_append(list, item) NODE *list, *item; { NODE *last; if (list == 0) return NEW_LIST(item); if (list->nd_next) { last = list->nd_next->nd_end; } else { last = list; } list->nd_alen += 1; last->nd_next = NEW_LIST(item); list->nd_next->nd_end = last->nd_next; return list; } /* concat two lists */ static NODE* list_concat(head, tail) NODE *head, *tail; { NODE *last; if (head->nd_next) { last = head->nd_next->nd_end; } else { last = head; } head->nd_alen += tail->nd_alen; last->nd_next = tail; if (tail->nd_next) { head->nd_next->nd_end = tail->nd_next->nd_end; } else { head->nd_next->nd_end = tail; } return head; } /* concat two string literals */ static NODE * literal_concat(head, tail) NODE *head, *tail; { enum node_type htype; if (!head) return tail; if (!tail) return head; htype = nd_type(head); if (htype == NODE_EVSTR) { NODE *node = NEW_DSTR(rb_str_new(0, 0)); head = list_append(node, head); } switch (nd_type(tail)) { case NODE_STR: if (htype == NODE_STR) { rb_str_concat(head->nd_lit, tail->nd_lit); rb_gc_force_recycle((VALUE)tail); } else { list_append(head, tail); } break; case NODE_DSTR: if (htype == NODE_STR) { rb_str_concat(head->nd_lit, tail->nd_lit); tail->nd_lit = head->nd_lit; rb_gc_force_recycle((VALUE)head); head = tail; } else { nd_set_type(tail, NODE_ARRAY); tail->nd_head = NEW_STR(tail->nd_lit); list_concat(head, tail); } break; case NODE_EVSTR: if (htype == NODE_STR) { nd_set_type(head, NODE_DSTR); head->nd_alen = 1; } list_append(head, tail); break; } return head; } static NODE * evstr2dstr(node) NODE *node; { if (nd_type(node) == NODE_EVSTR) { node = list_append(NEW_DSTR(rb_str_new(0, 0)), node); } return node; } static NODE * new_evstr(node) NODE *node; { NODE *head = node; again: if (node) { switch (nd_type(node)) { case NODE_STR: case NODE_DSTR: case NODE_EVSTR: return node; case NODE_NEWLINE: node = node->nd_next; goto again; } } return NEW_EVSTR(head); } static NODE * call_op(recv, id, narg, arg1) NODE *recv; ID id; int narg; NODE *arg1; { value_expr(recv); if (narg == 1) { value_expr(arg1); arg1 = NEW_LIST(arg1); } else { arg1 = 0; } return NEW_CALL(recv, id, arg1); } static NODE* match_gen(node1, node2) NODE *node1; NODE *node2; { local_cnt('~'); value_expr(node1); value_expr(node2); if (node1) { switch (nd_type(node1)) { case NODE_DREGX: case NODE_DREGX_ONCE: return NEW_MATCH2(node1, node2); case NODE_LIT: if (TYPE(node1->nd_lit) == T_REGEXP) { return NEW_MATCH2(node1, node2); } } } if (node2) { switch (nd_type(node2)) { case NODE_DREGX: case NODE_DREGX_ONCE: return NEW_MATCH3(node2, node1); case NODE_LIT: if (TYPE(node2->nd_lit) == T_REGEXP) { return NEW_MATCH3(node2, node1); } } } return NEW_CALL(node1, tMATCH, NEW_LIST(node2)); } static NODE* gettable(id) ID id; { if (id == kSELF) { return NEW_SELF(); } else if (id == kNIL) { return NEW_NIL(); } else if (id == kTRUE) { return NEW_TRUE(); } else if (id == kFALSE) { return NEW_FALSE(); } else if (id == k__FILE__) { return NEW_STR(rb_str_new2(ruby_sourcefile)); } else if (id == k__LINE__) { return NEW_LIT(INT2FIX(ruby_sourceline)); } else if (is_local_id(id)) { if (dyna_in_block() && rb_dvar_defined(id)) return NEW_DVAR(id); if (local_id(id)) return NEW_LVAR(id); /* method call without arguments */ #if 0 /* Rite will warn this */ rb_warn("ambiguous identifier; %s() or self.%s is better for method call", rb_id2name(id), rb_id2name(id)); #endif return NEW_VCALL(id); } else if (is_global_id(id)) { return NEW_GVAR(id); } else if (is_instance_id(id)) { return NEW_IVAR(id); } else if (is_const_id(id)) { return NEW_CONST(id); } else if (is_class_id(id)) { return NEW_CVAR(id); } rb_compile_error("identifier %s is not valid", rb_id2name(id)); return 0; } static VALUE dyna_var_lookup _((ID id)); static NODE* assignable(id, val) ID id; NODE *val; { value_expr(val); if (id == kSELF) { yyerror("Can't change the value of self"); } else if (id == kNIL) { yyerror("Can't assign to nil"); } else if (id == kTRUE) { yyerror("Can't assign to true"); } else if (id == kFALSE) { yyerror("Can't assign to false"); } else if (id == k__FILE__) { yyerror("Can't assign to __FILE__"); } else if (id == k__LINE__) { yyerror("Can't assign to __LINE__"); } else if (is_local_id(id)) { if (rb_dvar_curr(id)) { return NEW_DASGN_CURR(id, val); } else if (dyna_var_lookup(id)) { return NEW_DASGN(id, val); } else if (local_id(id) || !dyna_in_block()) { return NEW_LASGN(id, val); } else{ rb_dvar_push(id, Qnil); return NEW_DASGN_CURR(id, val); } } else if (is_global_id(id)) { return NEW_GASGN(id, val); } else if (is_instance_id(id)) { return NEW_IASGN(id, val); } else if (is_const_id(id)) { if (in_def || in_single) yyerror("dynamic constant assignment"); return NEW_CDECL(id, val, 0); } else if (is_class_id(id)) { if (in_def || in_single) return NEW_CVASGN(id, val); return NEW_CVDECL(id, val); } else { rb_compile_error("identifier %s is not valid", rb_id2name(id)); } return 0; } static NODE * aryset(recv, idx) NODE *recv, *idx; { if (recv && nd_type(recv) == NODE_SELF) recv = (NODE *)1; else value_expr(recv); return NEW_ATTRASGN(recv, tASET, idx); } ID rb_id_attrset(id) ID id; { id &= ~ID_SCOPE_MASK; id |= ID_ATTRSET; return id; } static NODE * attrset(recv, id) NODE *recv; ID id; { if (recv && nd_type(recv) == NODE_SELF) recv = (NODE *)1; else value_expr(recv); return NEW_ATTRASGN(recv, rb_id_attrset(id), 0); } static void rb_backref_error(node) NODE *node; { switch (nd_type(node)) { case NODE_NTH_REF: rb_compile_error("Can't set variable $%d", node->nd_nth); break; case NODE_BACK_REF: rb_compile_error("Can't set variable $%c", (int)node->nd_nth); break; } } static NODE * arg_concat(node1, node2) NODE *node1; NODE *node2; { if (!node2) return node1; return NEW_ARGSCAT(node1, node2); } static NODE * arg_add(node1, node2) NODE *node1; NODE *node2; { if (!node1) return NEW_LIST(node2); if (nd_type(node1) == NODE_ARRAY) { return list_append(node1, node2); } else { return NEW_ARGSPUSH(node1, node2); } } static NODE* node_assign(lhs, rhs) NODE *lhs, *rhs; { if (!lhs) return 0; value_expr(rhs); switch (nd_type(lhs)) { case NODE_GASGN: case NODE_IASGN: case NODE_LASGN: case NODE_DASGN: case NODE_DASGN_CURR: case NODE_MASGN: case NODE_CDECL: case NODE_CVDECL: case NODE_CVASGN: lhs->nd_value = rhs; break; case NODE_ATTRASGN: case NODE_CALL: lhs->nd_args = arg_add(lhs->nd_args, rhs); break; default: /* should not happen */ break; } return lhs; } static int value_expr0(node) NODE *node; { int cond = 0; while (node) { switch (nd_type(node)) { case NODE_DEFN: case NODE_DEFS: parser_warning(node, "void value expression"); return Qfalse; case NODE_RETURN: case NODE_BREAK: case NODE_NEXT: case NODE_REDO: case NODE_RETRY: if (!cond) yyerror("void value expression"); /* or "control never reach"? */ return Qfalse; case NODE_BLOCK: while (node->nd_next) { node = node->nd_next; } node = node->nd_head; break; case NODE_BEGIN: node = node->nd_body; break; case NODE_IF: if (!value_expr(node->nd_body)) return Qfalse; node = node->nd_else; break; case NODE_AND: case NODE_OR: cond = 1; node = node->nd_2nd; break; case NODE_NEWLINE: node = node->nd_next; break; default: return Qtrue; } } return Qtrue; } static void void_expr0(node) NODE *node; { const char *useless = 0; if (!RTEST(ruby_verbose)) return; again: if (!node) return; switch (nd_type(node)) { case NODE_NEWLINE: node = node->nd_next; goto again; case NODE_CALL: switch (node->nd_mid) { case '+': case '-': case '*': case '/': case '%': case tPOW: case tUPLUS: case tUMINUS: case '|': case '^': case '&': case tCMP: case '>': case tGEQ: case '<': case tLEQ: case tEQ: case tNEQ: useless = rb_id2name(node->nd_mid); break; } break; case NODE_LVAR: case NODE_DVAR: case NODE_GVAR: case NODE_IVAR: case NODE_CVAR: case NODE_NTH_REF: case NODE_BACK_REF: useless = "a variable"; break; case NODE_CONST: case NODE_CREF: useless = "a constant"; break; case NODE_LIT: case NODE_STR: case NODE_DSTR: case NODE_DREGX: case NODE_DREGX_ONCE: useless = "a literal"; break; case NODE_COLON2: case NODE_COLON3: useless = "::"; break; case NODE_DOT2: useless = ".."; break; case NODE_DOT3: useless = "..."; break; case NODE_SELF: useless = "self"; break; case NODE_NIL: useless = "nil"; break; case NODE_TRUE: useless = "true"; break; case NODE_FALSE: useless = "false"; break; case NODE_DEFINED: useless = "defined?"; break; } if (useless) { int line = ruby_sourceline; ruby_sourceline = nd_line(node); rb_warn("useless use of %s in void context", useless); ruby_sourceline = line; } } static void void_stmts(node) NODE *node; { if (!RTEST(ruby_verbose)) return; if (!node) return; if (nd_type(node) != NODE_BLOCK) return; for (;;) { if (!node->nd_next) return; void_expr0(node->nd_head); node = node->nd_next; } } static NODE * remove_begin(node) NODE *node; { NODE **n = &node; while (*n) { switch (nd_type(*n)) { case NODE_NEWLINE: n = &(*n)->nd_next; continue; case NODE_BEGIN: *n = (*n)->nd_body; default: return node; } } return node; } static int assign_in_cond(node) NODE *node; { switch (nd_type(node)) { case NODE_MASGN: yyerror("multiple assignment in conditional"); return 1; case NODE_LASGN: case NODE_DASGN: case NODE_GASGN: case NODE_IASGN: break; case NODE_NEWLINE: default: return 0; } switch (nd_type(node->nd_value)) { case NODE_LIT: case NODE_STR: case NODE_NIL: case NODE_TRUE: case NODE_FALSE: /* reports always */ parser_warn(node->nd_value, "found = in conditional, should be =="); return 1; case NODE_DSTR: case NODE_XSTR: case NODE_DXSTR: case NODE_EVSTR: case NODE_DREGX: default: break; } #if 0 if (assign_in_cond(node->nd_value) == 0) { parser_warning(node->nd_value, "assignment in condition"); } #endif return 1; } static int e_option_supplied() { if (strcmp(ruby_sourcefile, "-e") == 0) return Qtrue; return Qfalse; } static void warn_unless_e_option(node, str) NODE *node; const char *str; { if (!e_option_supplied()) parser_warn(node, str); } static void warning_unless_e_option(node, str) NODE *node; const char *str; { if (!e_option_supplied()) parser_warning(node, str); } static void fixup_nodes(rootnode) NODE **rootnode; { NODE *node, *next, *head; for (node = *rootnode; node; node = next) { enum node_type type; VALUE val; next = node->nd_next; head = node->nd_head; rb_gc_force_recycle((VALUE)node); *rootnode = next; switch (type = nd_type(head)) { case NODE_DOT2: case NODE_DOT3: val = rb_range_new(head->nd_beg->nd_lit, head->nd_end->nd_lit, type == NODE_DOT3 ? Qtrue : Qfalse); rb_gc_force_recycle((VALUE)head->nd_beg); rb_gc_force_recycle((VALUE)head->nd_end); nd_set_type(head, NODE_LIT); head->nd_lit = val; break; default: break; } } } static NODE *cond0(); static NODE* range_op(node) NODE *node; { enum node_type type; if (node == 0) return 0; type = nd_type(node); if (type == NODE_NEWLINE) { node = node->nd_next; type = nd_type(node); } value_expr(node); if (type == NODE_LIT && FIXNUM_P(node->nd_lit)) { warn_unless_e_option(node, "integer literal in conditional range"); return call_op(node,tEQ,1,NEW_GVAR(rb_intern("$."))); } return cond0(node); } static int literal_node(node) NODE *node; { if (!node) return 1; /* same as NODE_NIL */ switch (nd_type(node)) { case NODE_LIT: case NODE_STR: case NODE_DSTR: case NODE_EVSTR: case NODE_DREGX: case NODE_DREGX_ONCE: case NODE_DSYM: return 2; case NODE_TRUE: case NODE_FALSE: case NODE_NIL: return 1; } return 0; } static NODE* cond0(node) NODE *node; { if (node == 0) return 0; assign_in_cond(node); switch (nd_type(node)) { case NODE_DSTR: case NODE_EVSTR: case NODE_STR: rb_warn("string literal in condition"); break; case NODE_DREGX: case NODE_DREGX_ONCE: warning_unless_e_option(node, "regex literal in condition"); local_cnt('_'); local_cnt('~'); return NEW_MATCH2(node, NEW_GVAR(rb_intern("$_"))); case NODE_AND: case NODE_OR: node->nd_1st = cond0(node->nd_1st); node->nd_2nd = cond0(node->nd_2nd); break; case NODE_DOT2: case NODE_DOT3: node->nd_beg = range_op(node->nd_beg); node->nd_end = range_op(node->nd_end); if (nd_type(node) == NODE_DOT2) nd_set_type(node,NODE_FLIP2); else if (nd_type(node) == NODE_DOT3) nd_set_type(node, NODE_FLIP3); node->nd_cnt = local_append(internal_id()); if (!e_option_supplied()) { int b = literal_node(node->nd_beg); int e = literal_node(node->nd_end); if ((b == 1 && e == 1) || (b + e >= 2 && RTEST(ruby_verbose))) { parser_warn(node, "range literal in condition"); } } break; case NODE_DSYM: parser_warning(node, "literal in condition"); break; case NODE_LIT: if (TYPE(node->nd_lit) == T_REGEXP) { warn_unless_e_option(node, "regex literal in condition"); nd_set_type(node, NODE_MATCH); local_cnt('_'); local_cnt('~'); } else { parser_warning(node, "literal in condition"); } default: break; } return node; } static NODE* cond(node) NODE *node; { if (node == 0) return 0; value_expr(node); if (nd_type(node) == NODE_NEWLINE){ node->nd_next = cond0(node->nd_next); return node; } return cond0(node); } static NODE* logop(type, left, right) enum node_type type; NODE *left, *right; { value_expr(left); if (left && nd_type(left) == type) { NODE *node = left, *second; while ((second = node->nd_2nd) != 0 && nd_type(second) == type) { node = second; } node->nd_2nd = NEW_NODE(type, second, right, 0); return left; } return NEW_NODE(type, left, right, 0); } static int cond_negative(nodep) NODE **nodep; { NODE *c = *nodep; if (!c) return 0; switch (nd_type(c)) { case NODE_NOT: *nodep = c->nd_body; return 1; case NODE_NEWLINE: if (c->nd_next && nd_type(c->nd_next) == NODE_NOT) { c->nd_next = c->nd_next->nd_body; return 1; } } return 0; } static void no_blockarg(node) NODE *node; { if (node && nd_type(node) == NODE_BLOCK_PASS) { rb_compile_error("block argument should not be given"); } } static NODE * ret_args(node) NODE *node; { if (node) { no_blockarg(node); if (nd_type(node) == NODE_ARRAY && node->nd_next == 0) { node = node->nd_head; } if (node && nd_type(node) == NODE_SPLAT) { node = NEW_SVALUE(node); } } return node; } static NODE * new_yield(node) NODE *node; { long state = Qtrue; if (node) { no_blockarg(node); if (nd_type(node) == NODE_ARRAY && node->nd_next == 0) { node = node->nd_head; state = Qfalse; } if (node && nd_type(node) == NODE_SPLAT) { state = Qtrue; } } else { state = Qfalse; } return NEW_YIELD(node, state); } static NODE* negate_lit(node) NODE *node; { switch (TYPE(node->nd_lit)) { case T_FIXNUM: node->nd_lit = LONG2FIX(-FIX2LONG(node->nd_lit)); break; case T_BIGNUM: node->nd_lit = rb_funcall(node->nd_lit,tUMINUS,0,0); break; case T_FLOAT: RFLOAT(node->nd_lit)->value = -RFLOAT(node->nd_lit)->value; break; default: break; } return node; } static NODE * arg_blk_pass(node1, node2) NODE *node1; NODE *node2; { if (node2) { node2->nd_head = node1; return node2; } return node1; } static NODE* arg_prepend(node1, node2) NODE *node1, *node2; { switch (nd_type(node2)) { case NODE_ARRAY: return list_concat(NEW_LIST(node1), node2); case NODE_SPLAT: return arg_concat(node1, node2->nd_head); case NODE_BLOCK_PASS: node2->nd_body = arg_prepend(node1, node2->nd_body); return node2; default: rb_bug("unknown nodetype(%d) for arg_prepend", nd_type(node2)); } return 0; /* not reached */ } static NODE* new_call(r,m,a) NODE *r; ID m; NODE *a; { if (a && nd_type(a) == NODE_BLOCK_PASS) { a->nd_iter = NEW_CALL(r,m,a->nd_head); return a; } return NEW_CALL(r,m,a); } static NODE* new_fcall(m,a) ID m; NODE *a; { if (a && nd_type(a) == NODE_BLOCK_PASS) { a->nd_iter = NEW_FCALL(m,a->nd_head); return a; } return NEW_FCALL(m,a); } static NODE* new_super(a) NODE *a; { if (a && nd_type(a) == NODE_BLOCK_PASS) { a->nd_iter = NEW_SUPER(a->nd_head); return a; } return NEW_SUPER(a); } static struct local_vars { ID *tbl; int nofree; int cnt; int dlev; struct RVarmap* dyna_vars; struct local_vars *prev; } *lvtbl; static void local_push(top) int top; { struct local_vars *local; local = ALLOC(struct local_vars); local->prev = lvtbl; local->nofree = 0; local->cnt = 0; local->tbl = 0; local->dlev = 0; local->dyna_vars = ruby_dyna_vars; lvtbl = local; if (!top) { /* preserve reference for GC, but link should be cut. */ rb_dvar_push(0, (VALUE)ruby_dyna_vars); ruby_dyna_vars->next = 0; } } static void local_pop() { struct local_vars *local = lvtbl->prev; if (lvtbl->tbl) { if (!lvtbl->nofree) xfree(lvtbl->tbl); else lvtbl->tbl[0] = lvtbl->cnt; } ruby_dyna_vars = lvtbl->dyna_vars; xfree(lvtbl); lvtbl = local; } static ID* local_tbl() { lvtbl->nofree = 1; return lvtbl->tbl; } static int local_append(id) ID id; { if (lvtbl->tbl == 0) { lvtbl->tbl = ALLOC_N(ID, 4); lvtbl->tbl[0] = 0; lvtbl->tbl[1] = '_'; lvtbl->tbl[2] = '~'; lvtbl->cnt = 2; if (id == '_') return 0; if (id == '~') return 1; } else { REALLOC_N(lvtbl->tbl, ID, lvtbl->cnt+2); } lvtbl->tbl[lvtbl->cnt+1] = id; return lvtbl->cnt++; } static int local_cnt(id) ID id; { int cnt, max; if (id == 0) return lvtbl->cnt; for (cnt=1, max=lvtbl->cnt+1; cnttbl[cnt] == id) return cnt-1; } return local_append(id); } static int local_id(id) ID id; { int i, max; if (lvtbl == 0) return Qfalse; for (i=3, max=lvtbl->cnt+1; itbl[i] == id) return Qtrue; } return Qfalse; } static void top_local_init() { local_push(1); lvtbl->cnt = ruby_scope->local_tbl?ruby_scope->local_tbl[0]:0; if (lvtbl->cnt > 0) { lvtbl->tbl = ALLOC_N(ID, lvtbl->cnt+3); MEMCPY(lvtbl->tbl, ruby_scope->local_tbl, ID, lvtbl->cnt+1); } else { lvtbl->tbl = 0; } if (ruby_dyna_vars) lvtbl->dlev = 1; else lvtbl->dlev = 0; } static void top_local_setup() { int len = lvtbl->cnt; int i; if (len > 0) { i = ruby_scope->local_tbl?ruby_scope->local_tbl[0]:0; if (i < len) { if (i == 0 || (ruby_scope->flags & SCOPE_MALLOC) == 0) { VALUE *vars = ALLOC_N(VALUE, len+1); if (ruby_scope->local_vars) { *vars++ = ruby_scope->local_vars[-1]; MEMCPY(vars, ruby_scope->local_vars, VALUE, i); rb_mem_clear(vars+i, len-i); } else { *vars++ = 0; rb_mem_clear(vars, len); } ruby_scope->local_vars = vars; ruby_scope->flags |= SCOPE_MALLOC; } else { VALUE *vars = ruby_scope->local_vars-1; REALLOC_N(vars, VALUE, len+1); ruby_scope->local_vars = vars+1; rb_mem_clear(ruby_scope->local_vars+i, len-i); } if (ruby_scope->local_tbl && ruby_scope->local_vars[-1] == 0) { if (!(ruby_scope->flags & SCOPE_CLONE)) xfree(ruby_scope->local_tbl); } ruby_scope->local_vars[-1] = 0; /* no reference needed */ ruby_scope->local_tbl = local_tbl(); } } local_pop(); } #define DVAR_USED FL_USER6 static VALUE dyna_var_lookup(id) ID id; { struct RVarmap *vars = ruby_dyna_vars; while (vars) { if (vars->id == id) { FL_SET(vars, DVAR_USED); return Qtrue; } vars = vars->next; } return Qfalse; } static struct RVarmap* dyna_push() { struct RVarmap* vars = ruby_dyna_vars; rb_dvar_push(0, 0); lvtbl->dlev++; return vars; } static void dyna_pop(vars) struct RVarmap* vars; { lvtbl->dlev--; ruby_dyna_vars = vars; } static int dyna_in_block() { return (lvtbl->dlev > 0); } static NODE * dyna_init(node, pre) NODE *node; struct RVarmap *pre; { struct RVarmap *post = ruby_dyna_vars; NODE *var; if (!node || !post || pre == post) return node; for (var = 0; post != pre && post->id; post = post->next) { if (FL_TEST(post, DVAR_USED)) { var = NEW_DASGN_CURR(post->id, var); } } return block_append(var, node); } int ruby_parser_stack_on_heap() { #if defined(YYMALLOC) (void)rb_parser_realloc; (void)rb_parser_calloc; (void)nodetype; (void)nodeline; return Qfalse; #else return Qtrue; #endif } void rb_gc_mark_parser() { #if defined YYMALLOC rb_gc_mark((VALUE)parser_heap); #elif defined yystacksize if (yyvsp) rb_gc_mark_locations((VALUE *)yyvs, (VALUE *)yyvsp); #endif } void rb_parser_append_print() { ruby_eval_tree = block_append(ruby_eval_tree, NEW_FCALL(rb_intern("print"), NEW_ARRAY(NEW_GVAR(rb_intern("$_"))))); } void rb_parser_while_loop(chop, split) int chop, split; { if (split) { ruby_eval_tree = block_append(NEW_GASGN(rb_intern("$F"), NEW_CALL(NEW_GVAR(rb_intern("$_")), rb_intern("split"), 0)), ruby_eval_tree); } if (chop) { ruby_eval_tree = block_append(NEW_CALL(NEW_GVAR(rb_intern("$_")), rb_intern("chop!"), 0), ruby_eval_tree); } ruby_eval_tree = NEW_OPT_N(ruby_eval_tree); } static struct { ID token; const char *name; } op_tbl[] = { {tDOT2, ".."}, {tDOT3, "..."}, {'+', "+"}, {'-', "-"}, {'+', "+(binary)"}, {'-', "-(binary)"}, {'*', "*"}, {'/', "/"}, {'%', "%"}, {tPOW, "**"}, {tUPLUS, "+@"}, {tUMINUS, "-@"}, {tUPLUS, "+(unary)"}, {tUMINUS, "-(unary)"}, {'|', "|"}, {'^', "^"}, {'&', "&"}, {tCMP, "<=>"}, {'>', ">"}, {tGEQ, ">="}, {'<', "<"}, {tLEQ, "<="}, {tEQ, "=="}, {tEQQ, "==="}, {tNEQ, "!="}, {tMATCH, "=~"}, {tNMATCH, "!~"}, {'!', "!"}, {'~', "~"}, {'!', "!(unary)"}, {'~', "~(unary)"}, {'!', "!@"}, {'~', "~@"}, {tAREF, "[]"}, {tASET, "[]="}, {tLSHFT, "<<"}, {tRSHFT, ">>"}, {tCOLON2, "::"}, {'`', "`"}, {0, 0} }; static st_table *sym_tbl; static st_table *sym_rev_tbl; void Init_sym() { sym_tbl = st_init_strtable_with_size(200); sym_rev_tbl = st_init_numtable_with_size(200); } static ID last_id = tLAST_TOKEN; static ID internal_id() { return ID_INTERNAL | (++last_id << ID_SCOPE_SHIFT); } static int is_special_global_name(m) const char *m; { switch (*m) { case '~': case '*': case '$': case '?': case '!': case '@': case '/': case '\\': case ';': case ',': case '.': case '=': case ':': case '<': case '>': case '\"': case '&': case '`': case '\'': case '+': case '0': ++m; break; case '-': ++m; if (is_identchar(*m)) m += mbclen(*m); break; default: if (!ISDIGIT(*m)) return 0; do ++m; while (ISDIGIT(*m)); } return !*m; } int rb_symname_p(name) const char *name; { const char *m = name; int localid = Qfalse; if (!m) return Qfalse; switch (*m) { case '\0': return Qfalse; case '$': if (is_special_global_name(++m)) return Qtrue; goto id; case '@': if (*++m == '@') ++m; goto id; case '<': switch (*++m) { case '<': ++m; break; case '=': if (*++m == '>') ++m; break; default: break; } break; case '>': switch (*++m) { case '>': case '=': ++m; break; } break; case '=': switch (*++m) { case '~': ++m; break; case '=': if (*++m == '=') ++m; break; default: return Qfalse; } break; case '*': if (*++m == '*') ++m; break; case '+': case '-': if (*++m == '@') ++m; break; case '|': case '^': case '&': case '/': case '%': case '~': case '`': ++m; break; case '[': if (*++m != ']') return Qfalse; if (*++m == '=') ++m; break; default: localid = !ISUPPER(*m); id: if (*m != '_' && !ISALPHA(*m) && !ismbchar(*m)) return Qfalse; while (is_identchar(*m)) m += mbclen(*m); if (localid) { switch (*m) { case '!': case '?': case '=': ++m; } } break; } return *m ? Qfalse : Qtrue; } int rb_sym_interned_p(str) VALUE str; { ID id; if (st_lookup(sym_tbl, (st_data_t)RSTRING(str)->ptr, (st_data_t *)&id)) return Qtrue; return Qfalse; } ID rb_intern(name) const char *name; { const char *m = name; ID id; int last; if (st_lookup(sym_tbl, (st_data_t)name, (st_data_t *)&id)) return id; last = strlen(name)-1; id = 0; switch (*name) { case '$': id |= ID_GLOBAL; if (is_special_global_name(++m)) goto new_id; break; case '@': if (name[1] == '@') { m++; id |= ID_CLASS; } else { id |= ID_INSTANCE; } m++; break; default: if (name[0] != '_' && ISASCII(name[0]) && !ISALNUM(name[0])) { /* operators */ int i; for (i=0; op_tbl[i].token; i++) { if (*op_tbl[i].name == *name && strcmp(op_tbl[i].name, name) == 0) { id = op_tbl[i].token; goto id_regist; } } } if (name[last] == '=') { /* attribute assignment */ char *buf = ALLOCA_N(char,last+1); strncpy(buf, name, last); buf[last] = '\0'; id = rb_intern(buf); if (id > tLAST_TOKEN && !is_attrset_id(id)) { id = rb_id_attrset(id); goto id_regist; } id = ID_ATTRSET; } else if (ISUPPER(name[0])) { id = ID_CONST; } else { id = ID_LOCAL; } break; } if (!ISDIGIT(*m)) { while (m <= name + last && is_identchar(*m)) { m += mbclen(*m); } } if (*m) id = ID_JUNK; new_id: id |= ++last_id << ID_SCOPE_SHIFT; id_regist: name = strdup(name); st_add_direct(sym_tbl, (st_data_t)name, id); st_add_direct(sym_rev_tbl, id, (st_data_t)name); return id; } const char * rb_id2name(id) ID id; { const char *name; st_data_t data; if (id < tLAST_TOKEN) { int i; for (i=0; op_tbl[i].token; i++) { if (op_tbl[i].token == id) return op_tbl[i].name; } } if (st_lookup(sym_rev_tbl, id, &data)) return (char *)data; if (is_attrset_id(id)) { ID id2 = (id & ~ID_SCOPE_MASK) | ID_LOCAL; again: name = rb_id2name(id2); if (name) { char *buf = ALLOCA_N(char, strlen(name)+2); strcpy(buf, name); strcat(buf, "="); rb_intern(buf); return rb_id2name(id); } if (is_local_id(id2)) { id2 = (id & ~ID_SCOPE_MASK) | ID_CONST; goto again; } } return 0; } static int symbols_i(key, value, ary) char *key; ID value; VALUE ary; { rb_ary_push(ary, ID2SYM(value)); return ST_CONTINUE; } /* * call-seq: * Symbol.all_symbols => array * * Returns an array of all the symbols currently in Ruby's symbol * table. * * Symbol.all_symbols.size #=> 903 * Symbol.all_symbols[1,20] #=> [:floor, :ARGV, :Binding, :symlink, * :chown, :EOFError, :$;, :String, * :LOCK_SH, :"setuid?", :$<, * :default_proc, :compact, :extend, * :Tms, :getwd, :$=, :ThreadGroup, * :wait2, :$>] */ VALUE rb_sym_all_symbols() { VALUE ary = rb_ary_new2(sym_tbl->num_entries); st_foreach(sym_tbl, symbols_i, ary); return ary; } int rb_is_const_id(id) ID id; { if (is_const_id(id)) return Qtrue; return Qfalse; } int rb_is_class_id(id) ID id; { if (is_class_id(id)) return Qtrue; return Qfalse; } int rb_is_instance_id(id) ID id; { if (is_instance_id(id)) return Qtrue; return Qfalse; } int rb_is_local_id(id) ID id; { if (is_local_id(id)) return Qtrue; return Qfalse; } int rb_is_junk_id(id) ID id; { if (is_junk_id(id)) return Qtrue; return Qfalse; } static void special_local_set(c, val) char c; VALUE val; { int cnt; top_local_init(); cnt = local_cnt(c); top_local_setup(); ruby_scope->local_vars[cnt] = val; } VALUE rb_backref_get() { VALUE *var = rb_svar(1); if (var) { return *var; } return Qnil; } void rb_backref_set(val) VALUE val; { VALUE *var = rb_svar(1); if (var) { *var = val; } else { special_local_set('~', val); } } VALUE rb_lastline_get() { VALUE *var = rb_svar(0); if (var) { return *var; } return Qnil; } void rb_lastline_set(val) VALUE val; { VALUE *var = rb_svar(0); if (var) { *var = val; } else { special_local_set('_', val); } } #ifdef YYMALLOC #define HEAPCNT(n, size) ((n) * (size) / sizeof(YYSTYPE)) #define NEWHEAP() NEW_NODE_EDEN(NODE_ALLOCA, 0, (VALUE)parser_heap, 0) #define ADD2HEAP(n, c, p) ((parser_heap = (n))->u1.node = (p), \ (n)->u3.cnt = (c), (p)) static void * rb_parser_malloc(size) size_t size; { size_t cnt = HEAPCNT(1, size); NODE *n = NEWHEAP(); void *ptr = xmalloc(size); return ADD2HEAP(n, cnt, ptr); } static void * rb_parser_calloc(nelem, size) size_t nelem, size; { size_t cnt = HEAPCNT(nelem, size); NODE *n = NEWHEAP(); void *ptr = xcalloc(nelem, size); return ADD2HEAP(n, cnt, ptr); } static void * rb_parser_realloc(ptr, size) void *ptr; size_t size; { NODE *n; size_t cnt = HEAPCNT(1, size); if (ptr && (n = parser_heap) != NULL) { do { if (n->u1.node == ptr) { n->u1.node = ptr = xrealloc(ptr, size); if (n->u3.cnt) n->u3.cnt = cnt; return ptr; } } while ((n = n->u2.node) != NULL); } n = NEWHEAP(); ptr = xrealloc(ptr, size); return ADD2HEAP(n, cnt, ptr); } static void rb_parser_free(ptr) void *ptr; { NODE **prev = &parser_heap, *n; while ((n = *prev) != 0) { if (n->u1.node == ptr) { *prev = n->u2.node; rb_gc_force_recycle((VALUE)n); break; } prev = &n->u2.node; } xfree(ptr); } #endif ================================================ FILE: pointerset.c ================================================ #include "config.h" #include "defines.h" #ifdef HAVE_STDLIB_H #include #endif #include #include "pointerset.h" typedef struct _PointerSetEntry PointerSetEntry; struct _PointerSet { unsigned int num_bins; unsigned int num_entries; PointerSetEntry **bins; }; struct _PointerSetEntry { PointerSetElement element; PointerSetEntry *next; }; /* Table of prime numbers 2^n+a, 2<=n<=30. */ static const long primes[] = { 8 + 3, 16 + 3, 32 + 5, 64 + 3, 128 + 3, 256 + 27, 512 + 9, 1024 + 9, 2048 + 5, 4096 + 3, 8192 + 27, 16384 + 43, 32768 + 3, 65536 + 45, 131072 + 29, 262144 + 3, 524288 + 21, 1048576 + 7, 2097152 + 17, 4194304 + 15, 8388608 + 9, 16777216 + 43, 33554432 + 35, 67108864 + 15, 134217728 + 29, 268435456 + 3, 536870912 + 11, 1073741824 + 85, 0 }; /* The percentage of nonempty buckets, before increasing the number of bins. 1.0 == 100% * A value larger than 1.0 means that it's very likely that some buckets contain more than * 1 entry. */ #define MAX_LOAD_FACTOR 2.0 /* The default for the number of bins allocated initially. Must be a prime number. */ #define DEFAULT_TABLE_SIZE 11 /* MINSIZE is the minimum size of a dictionary. */ #define MINSIZE 8 #if SIZEOF_LONG == SIZEOF_VOIDP typedef unsigned long PointerInt; #elif SIZEOF_LONG_LONG == SIZEOF_VOIDP typedef unsigned LONG_LONG PointerInt; #else #error ---->> pointerset.c requires sizeof(void*) == sizeof(long) to be compiled. <<--- - #endif #define alloc(type) (type*)malloc((unsigned)sizeof(type)) #define Calloc(n,s) (char*)calloc((n),(s)) #define HASH(element, num_bins) ((PointerInt) element) % num_bins #define FIND_ENTRY(set, entry, element) \ do { \ unsigned int bin_pos = HASH(element, set->num_bins); \ entry = (set)->bins[bin_pos]; \ while (entry != NULL && entry->element != element) { \ entry = entry->next; \ } \ } while (0) static int new_size(int size) { int i; int newsize; for (i = 0, newsize = MINSIZE; i < sizeof(primes)/sizeof(primes[0]); i++, newsize <<= 1) { if (newsize > size) return primes[i]; } /* Ran out of polynomials */ return -1; /* should raise exception */ } PointerSet * pointer_set_new() { PointerSet *set; set = alloc(PointerSet); if (set != NULL) { set->num_entries = 0; set->num_bins = DEFAULT_TABLE_SIZE; set->bins = (PointerSetEntry **) Calloc(DEFAULT_TABLE_SIZE, sizeof(PointerSetEntry *)); } return set; } static void free_bin_contents(PointerSet *set) { PointerSetEntry *entry, *next; int i; for(i = 0; i < set->num_bins; i++) { entry = set->bins[i]; while (entry != NULL) { next = entry->next; free(entry); entry = next; } set->bins[i] = NULL; } set->num_entries = 0; } void pointer_set_free(PointerSet *set) { free_bin_contents(set); free(set->bins); free(set); } int pointer_set_contains(PointerSet *set, PointerSetElement element) { PointerSetEntry *entry; FIND_ENTRY(set, entry, element); return entry != NULL; } static void rehash(PointerSet *set, int new_num_bins) { PointerSetEntry *entry, **new_bins; int i; new_bins = (PointerSetEntry **) Calloc(new_num_bins, sizeof(PointerSetEntry *)); for (i = 0; i < set->num_bins; i++) { entry = set->bins[i]; while (entry != NULL) { unsigned int new_bin_pos; PointerSetEntry *next; new_bin_pos = HASH(entry->element, new_num_bins); next = entry->next; entry->next = new_bins[new_bin_pos]; new_bins[new_bin_pos] = entry; entry = next; } } free(set->bins); set->num_bins = new_num_bins; set->bins = new_bins; } void pointer_set_insert(PointerSet *set, PointerSetElement element) { PointerSetEntry *entry; FIND_ENTRY(set, entry, element); if (entry == NULL) { unsigned int bin_pos; if (set->num_entries / (double) set->num_bins > MAX_LOAD_FACTOR) { /* Increase number of bins to the next prime number. */ rehash(set, new_size(set->num_bins + 1)); } bin_pos = HASH(element, set->num_bins); entry = malloc(sizeof(PointerSetEntry)); entry->element = element; entry->next = set->bins[bin_pos]; set->bins[bin_pos] = entry; set->num_entries++; } } void pointer_set_delete(PointerSet *set, PointerSetElement element) { unsigned int bin_pos; PointerSetEntry *entry, *prev; bin_pos = HASH(element, set->num_bins); entry = set->bins[bin_pos]; prev = NULL; while (entry != NULL && entry->element != element) { prev = entry; entry = entry->next; } if (entry != NULL) { if (prev != NULL) { prev->next = entry->next; } else { set->bins[bin_pos] = entry->next; } free(entry); set->num_entries--; /* TODO: is it a good idea to reduce the number of bins? */ } } void pointer_set_reset(PointerSet *set) { free_bin_contents(set); set->bins = realloc(set->bins, sizeof(PointerSetEntry *) * DEFAULT_TABLE_SIZE); set->num_bins = DEFAULT_TABLE_SIZE; memset(set->bins, 0, sizeof(PointerSetEntry *) * DEFAULT_TABLE_SIZE); } unsigned int pointer_set_get_size(PointerSet *set) { return set->num_entries; } unsigned int pointer_set_get_capacity(PointerSet *set) { return set->num_bins; } ================================================ FILE: pointerset.h ================================================ /** * A specialized set data structure, designed to only contain pointers. * It will grow and shrink dynamically. */ #ifndef _POINTER_SET_H_ #define _POINTER_SET_H_ typedef void * PointerSetElement; typedef struct _PointerSet PointerSet; /** * Create a new, empty pointer set. */ PointerSet *pointer_set_new(); /** * Free the given pointer set. */ void pointer_set_free(PointerSet *set); /** * Insert the given pointer into the pointer set. The data that the * pointer pointers to is not touched, so element may even be * an invalid pointer. */ void pointer_set_insert(PointerSet *set, PointerSetElement element); /** * Remove the given pointer from the pointer set. Nothing will happen * if the pointer isn't already in the set. */ void pointer_set_delete(PointerSet *set, PointerSetElement element); /** * Check whether the given pointer is in the pointer set. */ int pointer_set_contains(PointerSet *set, PointerSetElement element); /** * Clear the pointer set. */ void pointer_set_reset(PointerSet *set); /** * Return the number of pointers in the pointer set. */ unsigned int pointer_set_get_size(PointerSet *set); /** * Return the amount of space that is used to store the pointers in the set. * * @invariant pointer_set_get_capacity(set) >= pointer_set_get_size(set) */ unsigned int pointer_set_get_capacity(PointerSet *set); #endif /* _POINTER_SET_H_ */ ================================================ FILE: prec.c ================================================ /********************************************************************** prec.c - $Author$ $Date$ created at: Tue Jan 26 02:40:41 2000 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #include "ruby.h" VALUE rb_mPrecision; static ID prc_pr, prc_if; /* * call-seq: * num.prec(klass) => a_klass * * Converts _self_ into an instance of _klass_. By default, * +prec+ invokes * * klass.induced_from(num) * * and returns its value. So, if klass.induced_from * doesn't return an instance of _klass_, it will be necessary * to reimplement +prec+. */ static VALUE prec_prec(x, klass) VALUE x, klass; { return rb_funcall(klass, prc_if, 1, x); } /* * call-seq: * num.prec_i => Integer * * Returns an +Integer+ converted from _num_. It is equivalent * to prec(Integer). */ static VALUE prec_prec_i(x) VALUE x; { VALUE klass = rb_cInteger; return rb_funcall(x, prc_pr, 1, klass); } /* * call-seq: * num.prec_f => Float * * Returns a +Float+ converted from _num_. It is equivalent * to prec(Float). */ static VALUE prec_prec_f(x) VALUE x; { VALUE klass = rb_cFloat; return rb_funcall(x, prc_pr, 1, klass); } /* * call-seq: * Mod.induced_from(number) => a_mod * * Creates an instance of mod from. This method is overridden * by concrete +Numeric+ classes, so that (for example) * * Fixnum.induced_from(9.9) #=> 9 * * Note that a use of +prec+ in a redefinition may cause * an infinite loop. */ static VALUE prec_induced_from(module, x) VALUE module, x; { rb_raise(rb_eTypeError, "undefined conversion from %s into %s", rb_obj_classname(x), rb_class2name(module)); return Qnil; /* not reached */ } /* * call_seq: * included * * When the +Precision+ module is mixed-in to a class, this +included+ * method is used to add our default +induced_from+ implementation * to the host class. */ static VALUE prec_included(module, include) VALUE module, include; { switch (TYPE(include)) { case T_CLASS: case T_MODULE: break; default: Check_Type(include, T_CLASS); break; } rb_define_singleton_method(include, "induced_from", prec_induced_from, 1); return module; } /* * Precision is a mixin for concrete numeric classes with * precision. Here, `precision' means the fineness of approximation * of a real number, so, this module should not be included into * anything which is not a subset of Real (so it should not be * included in classes such as +Complex+ or +Matrix+). */ void Init_Precision() { rb_mPrecision = rb_define_module("Precision"); rb_define_singleton_method(rb_mPrecision, "included", prec_included, 1); rb_define_method(rb_mPrecision, "prec", prec_prec, 1); rb_define_method(rb_mPrecision, "prec_i", prec_prec_i, 0); rb_define_method(rb_mPrecision, "prec_f", prec_prec_f, 0); prc_pr = rb_intern("prec"); prc_if = rb_intern("induced_from"); } ================================================ FILE: process.c ================================================ /********************************************************************** process.c - $Author$ $Date$ created at: Tue Aug 10 14:30:50 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto Copyright (C) 2000 Network Applied Communication Laboratory, Inc. Copyright (C) 2000 Information-technology Promotion Agency, Japan **********************************************************************/ #include "ruby.h" #include "rubysig.h" #include #include #include #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef __DJGPP__ #include #endif #include #include #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 #endif #ifndef EXIT_FAILURE #define EXIT_FAILURE 1 #endif struct timeval rb_time_interval _((VALUE)); #ifdef HAVE_SYS_WAIT_H # include #endif #ifdef HAVE_SYS_RESOURCE_H # include #endif #include "st.h" #ifdef __EMX__ #undef HAVE_GETPGRP #endif #ifdef HAVE_SYS_TIMES_H #include #endif #ifdef HAVE_GRP_H #include #endif #if defined(HAVE_TIMES) || defined(_WIN32) static VALUE S_Tms; #endif #ifndef WIFEXITED #define WIFEXITED(w) (((w) & 0xff) == 0) #endif #ifndef WIFSIGNALED #define WIFSIGNALED(w) (((w) & 0x7f) > 0 && (((w) & 0x7f) < 0x7f)) #endif #ifndef WIFSTOPPED #define WIFSTOPPED(w) (((w) & 0xff) == 0x7f) #endif #ifndef WEXITSTATUS #define WEXITSTATUS(w) (((w) >> 8) & 0xff) #endif #ifndef WTERMSIG #define WTERMSIG(w) ((w) & 0x7f) #endif #ifndef WSTOPSIG #define WSTOPSIG WEXITSTATUS #endif #if defined(__APPLE__) && ( defined(__MACH__) || defined(__DARWIN__) ) && !defined(__MacOS_X__) #define __MacOS_X__ 1 #endif #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) #define HAVE_44BSD_SETUID 1 #define HAVE_44BSD_SETGID 1 #endif #ifdef __NetBSD__ #undef HAVE_SETRUID #undef HAVE_SETRGID #endif #ifdef BROKEN_SETREUID #define setreuid ruby_setreuid #endif #ifdef BROKEN_SETREGID #define setregid ruby_setregid #endif #if defined(HAVE_44BSD_SETUID) || defined(__MacOS_X__) #if !defined(USE_SETREUID) && !defined(BROKEN_SETREUID) #define OBSOLETE_SETREUID 1 #endif #if !defined(USE_SETREGID) && !defined(BROKEN_SETREGID) #define OBSOLETE_SETREGID 1 #endif #endif #define preserving_errno(stmts) \ do {int saved_errno = errno; stmts; errno = saved_errno;} while (0) /* * call-seq: * Process.pid => fixnum * * Returns the process id of this process. Not available on all * platforms. * * Process.pid #=> 27415 */ static VALUE get_pid() { rb_secure(2); return INT2FIX(getpid()); } /* * call-seq: * Process.ppid => fixnum * * Returns the process id of the parent of this process. Always * returns 0 on NT. Not available on all platforms. * * puts "I am #{Process.pid}" * Process.fork { puts "Dad is #{Process.ppid}" } * * produces: * * I am 27417 * Dad is 27417 */ static VALUE get_ppid() { rb_secure(2); #ifdef _WIN32 return INT2FIX(0); #else return INT2FIX(getppid()); #endif } /********************************************************************* * * Document-class: Process::Status * * Process::Status encapsulates the information on the * status of a running or terminated system process. The built-in * variable $? is either +nil+ or a * Process::Status object. * * fork { exit 99 } #=> 26557 * Process.wait #=> 26557 * $?.class #=> Process::Status * $?.to_i #=> 25344 * $? >> 8 #=> 99 * $?.stopped? #=> false * $?.exited? #=> true * $?.exitstatus #=> 99 * * Posix systems record information on processes using a 16-bit * integer. The lower bits record the process status (stopped, * exited, signaled) and the upper bits possibly contain additional * information (for example the program's return code in the case of * exited processes). Pre Ruby 1.8, these bits were exposed directly * to the Ruby program. Ruby now encapsulates these in a * Process::Status object. To maximize compatibility, * however, these objects retain a bit-oriented interface. In the * descriptions that follow, when we talk about the integer value of * _stat_, we're referring to this 16 bit value. */ static VALUE rb_cProcStatus; VALUE rb_last_status = Qnil; static void last_status_set(status, pid) int status, pid; { rb_last_status = rb_obj_alloc(rb_cProcStatus); rb_iv_set(rb_last_status, "status", INT2FIX(status)); rb_iv_set(rb_last_status, "pid", INT2FIX(pid)); } /* * call-seq: * stat.to_i => fixnum * stat.to_int => fixnum * * Returns the bits in _stat_ as a Fixnum. Poking * around in these bits is platform dependent. * * fork { exit 0xab } #=> 26566 * Process.wait #=> 26566 * sprintf('%04x', $?.to_i) #=> "ab00" */ static VALUE pst_to_i(st) VALUE st; { return rb_iv_get(st, "status"); } /* * call-seq: * stat.to_s => string * * Equivalent to _stat_.to_i.to_s. */ static VALUE pst_to_s(st) VALUE st; { return rb_fix2str(pst_to_i(st), 10); } /* * call-seq: * stat.pid => fixnum * * Returns the process ID that this status object represents. * * fork { exit } #=> 26569 * Process.wait #=> 26569 * $?.pid #=> 26569 */ static VALUE pst_pid(st) VALUE st; { return rb_iv_get(st, "pid"); } /* * call-seq: * stat.inspect => string * * Override the inspection method. */ static VALUE pst_inspect(st) VALUE st; { VALUE pid; int status; VALUE str; char buf[256]; pid = pst_pid(st); status = NUM2INT(st); snprintf(buf, sizeof(buf), "#<%s: pid=%ld", rb_class2name(CLASS_OF(st)), NUM2LONG(pid)); str = rb_str_new2(buf); if (WIFSTOPPED(status)) { int stopsig = WSTOPSIG(status); const char *signame = ruby_signal_name(stopsig); if (signame) { snprintf(buf, sizeof(buf), ",stopped(SIG%s=%d)", signame, stopsig); } else { snprintf(buf, sizeof(buf), ",stopped(%d)", stopsig); } rb_str_cat2(str, buf); } if (WIFSIGNALED(status)) { int termsig = WTERMSIG(status); const char *signame = ruby_signal_name(termsig); if (signame) { snprintf(buf, sizeof(buf), ",signaled(SIG%s=%d)", signame, termsig); } else { snprintf(buf, sizeof(buf), ",signaled(%d)", termsig); } rb_str_cat2(str, buf); } if (WIFEXITED(status)) { snprintf(buf, sizeof(buf), ",exited(%d)", WEXITSTATUS(status)); rb_str_cat2(str, buf); } #ifdef WCOREDUMP if (WCOREDUMP(status)) { rb_str_cat2(str, ",coredumped"); } #endif rb_str_cat2(str, ">"); return str; } /* * call-seq: * stat == other => true or false * * Returns +true+ if the integer value of _stat_ * equals other. */ static VALUE pst_equal(st1, st2) VALUE st1, st2; { if (st1 == st2) return Qtrue; return rb_equal(pst_to_i(st1), st2); } /* * call-seq: * stat & num => fixnum * * Logical AND of the bits in _stat_ with num. * * fork { exit 0x37 } * Process.wait * sprintf('%04x', $?.to_i) #=> "3700" * sprintf('%04x', $? & 0x1e00) #=> "1600" */ static VALUE pst_bitand(st1, st2) VALUE st1, st2; { int status = NUM2INT(st1) & NUM2INT(st2); return INT2NUM(status); } /* * call-seq: * stat >> num => fixnum * * Shift the bits in _stat_ right num places. * * fork { exit 99 } #=> 26563 * Process.wait #=> 26563 * $?.to_i #=> 25344 * $? >> 8 #=> 99 */ static VALUE pst_rshift(st1, st2) VALUE st1, st2; { int status = NUM2INT(st1) >> NUM2INT(st2); return INT2NUM(status); } /* * call-seq: * stat.stopped? => true or false * * Returns +true+ if this process is stopped. This is only * returned if the corresponding wait call had the * WUNTRACED flag set. */ static VALUE pst_wifstopped(st) VALUE st; { int status = NUM2INT(st); if (WIFSTOPPED(status)) return Qtrue; else return Qfalse; } /* * call-seq: * stat.stopsig => fixnum or nil * * Returns the number of the signal that caused _stat_ to stop * (or +nil+ if self is not stopped). */ static VALUE pst_wstopsig(st) VALUE st; { int status = NUM2INT(st); if (WIFSTOPPED(status)) return INT2NUM(WSTOPSIG(status)); return Qnil; } /* * call-seq: * stat.signaled? => true or false * * Returns +true+ if _stat_ terminated because of * an uncaught signal. */ static VALUE pst_wifsignaled(st) VALUE st; { int status = NUM2INT(st); if (WIFSIGNALED(status)) return Qtrue; else return Qfalse; } /* * call-seq: * stat.termsig => fixnum or nil * * Returns the number of the signal that caused _stat_ to * terminate (or +nil+ if self was not terminated by an * uncaught signal). */ static VALUE pst_wtermsig(st) VALUE st; { int status = NUM2INT(st); if (WIFSIGNALED(status)) return INT2NUM(WTERMSIG(status)); return Qnil; } /* * call-seq: * stat.exited? => true or false * * Returns +true+ if _stat_ exited normally (for * example using an exit() call or finishing the * program). */ static VALUE pst_wifexited(st) VALUE st; { int status = NUM2INT(st); if (WIFEXITED(status)) return Qtrue; else return Qfalse; } /* * call-seq: * stat.exitstatus => fixnum or nil * * Returns the least significant eight bits of the return code of * _stat_. Only available if exited? is * +true+. * * fork { } #=> 26572 * Process.wait #=> 26572 * $?.exited? #=> true * $?.exitstatus #=> 0 * * fork { exit 99 } #=> 26573 * Process.wait #=> 26573 * $?.exited? #=> true * $?.exitstatus #=> 99 */ static VALUE pst_wexitstatus(st) VALUE st; { int status = NUM2INT(st); if (WIFEXITED(status)) return INT2NUM(WEXITSTATUS(status)); return Qnil; } /* * call-seq: * stat.success? => true, false or nil * * Returns +true+ if _stat_ is successful, +false+ if not. * Returns +nil+ if exited? is not +true+. */ static VALUE pst_success_p(st) VALUE st; { int status = NUM2INT(st); if (!WIFEXITED(status)) return Qnil; return WEXITSTATUS(status) == EXIT_SUCCESS ? Qtrue : Qfalse; } /* * call-seq: * stat.coredump? => true or false * * Returns +true+ if _stat_ generated a coredump * when it terminated. Not available on all platforms. */ static VALUE pst_wcoredump(st) VALUE st; { #ifdef WCOREDUMP int status = NUM2INT(st); if (WCOREDUMP(status)) return Qtrue; else return Qfalse; #else return Qfalse; #endif } #if !defined(HAVE_WAITPID) && !defined(HAVE_WAIT4) #define NO_WAITPID static st_table *pid_tbl; #endif int rb_waitpid(pid, st, flags) int pid; int *st; int flags; { int result; #ifndef NO_WAITPID int oflags = flags; if (!rb_thread_alone()) { /* there're other threads to run */ flags |= WNOHANG; } retry: TRAP_BEG; #ifdef HAVE_WAITPID result = waitpid(pid, st, flags); #else /* HAVE_WAIT4 */ result = wait4(pid, st, flags, NULL); #endif TRAP_END; if (result < 0) { if (errno == EINTR) { rb_thread_polling(); goto retry; } return -1; } if (result == 0) { if (oflags & WNOHANG) return 0; rb_thread_polling(); if (rb_thread_alone()) flags = oflags; goto retry; } #else /* NO_WAITPID */ if (pid_tbl && st_lookup(pid_tbl, pid, st)) { last_status_set(*st, pid); st_delete(pid_tbl, (st_data_t*)&pid, NULL); return pid; } if (flags) { rb_raise(rb_eArgError, "can't do waitpid with flags"); } for (;;) { TRAP_BEG; result = wait(st); TRAP_END; if (result < 0) { if (errno == EINTR) { rb_thread_schedule(); continue; } return -1; } if (result == pid) { break; } if (!pid_tbl) pid_tbl = st_init_numtable(); st_insert(pid_tbl, pid, st); if (!rb_thread_alone()) rb_thread_schedule(); } #endif if (result > 0) { last_status_set(*st, result); } return result; } #ifdef NO_WAITPID struct wait_data { int pid; int status; }; static int wait_each(pid, status, data) int pid, status; struct wait_data *data; { if (data->status != -1) return ST_STOP; data->pid = pid; data->status = status; return ST_DELETE; } static int waitall_each(pid, status, ary) int pid, status; VALUE ary; { last_status_set(status, pid); rb_ary_push(ary, rb_assoc_new(INT2NUM(pid), rb_last_status)); return ST_DELETE; } #endif /* [MG]:FIXME: I wasn't sure how this should be done, since ::wait() has historically been documented as if it didn't take any arguments despite the fact that it's just an alias for ::waitpid(). The way I have it below is more truthful, but a little confusing. I also took the liberty of putting in the pid values, as they're pretty useful, and it looked as if the original 'ri' output was supposed to contain them after "[...]depending on the value of aPid:". The 'ansi' and 'bs' formats of the ri output don't display the definition list for some reason, but the plain text one does. */ /* * call-seq: * Process.wait() => fixnum * Process.wait(pid=-1, flags=0) => fixnum * Process.waitpid(pid=-1, flags=0) => fixnum * * Waits for a child process to exit, returns its process id, and * sets $? to a Process::Status object * containing information on that process. Which child it waits on * depends on the value of _pid_: * * > 0:: Waits for the child whose process ID equals _pid_. * * 0:: Waits for any child whose process group ID equals that of the * calling process. * * -1:: Waits for any child process (the default if no _pid_ is * given). * * < -1:: Waits for any child whose process group ID equals the absolute * value of _pid_. * * The _flags_ argument may be a logical or of the flag values * Process::WNOHANG (do not block if no child available) * or Process::WUNTRACED (return stopped children that * haven't been reported). Not all flags are available on all * platforms, but a flag value of zero will work on all platforms. * * Calling this method raises a SystemError if there are * no child processes. Not available on all platforms. * * include Process * fork { exit 99 } #=> 27429 * wait #=> 27429 * $?.exitstatus #=> 99 * * pid = fork { sleep 3 } #=> 27440 * Time.now #=> Wed Apr 09 08:57:09 CDT 2003 * waitpid(pid, Process::WNOHANG) #=> nil * Time.now #=> Wed Apr 09 08:57:09 CDT 2003 * waitpid(pid, 0) #=> 27440 * Time.now #=> Wed Apr 09 08:57:12 CDT 2003 */ static VALUE proc_wait(argc, argv) int argc; VALUE *argv; { VALUE vpid, vflags; int pid, flags, status; rb_secure(2); flags = 0; rb_scan_args(argc, argv, "02", &vpid, &vflags); if (argc == 0) { pid = -1; } else { pid = NUM2INT(vpid); if (argc == 2 && !NIL_P(vflags)) { flags = NUM2UINT(vflags); } } if ((pid = rb_waitpid(pid, &status, flags)) < 0) rb_sys_fail(0); if (pid == 0) { return rb_last_status = Qnil; } return INT2FIX(pid); } /* * call-seq: * Process.wait2(pid=-1, flags=0) => [pid, status] * Process.waitpid2(pid=-1, flags=0) => [pid, status] * * Waits for a child process to exit (see Process::waitpid for exact * semantics) and returns an array containing the process id and the * exit status (a Process::Status object) of that * child. Raises a SystemError if there are no child * processes. * * Process.fork { exit 99 } #=> 27437 * pid, status = Process.wait2 * pid #=> 27437 * status.exitstatus #=> 99 */ static VALUE proc_wait2(argc, argv) int argc; VALUE *argv; { VALUE pid = proc_wait(argc, argv); if (NIL_P(pid)) return Qnil; return rb_assoc_new(pid, rb_last_status); } /* * call-seq: * Process.waitall => [ [pid1,status1], ...] * * Waits for all children, returning an array of * _pid_/_status_ pairs (where _status_ is a * Process::Status object). * * fork { sleep 0.2; exit 2 } #=> 27432 * fork { sleep 0.1; exit 1 } #=> 27433 * fork { exit 0 } #=> 27434 * p Process.waitall * * produces: * * [[27434, #], * [27433, #], * [27432, #]] */ static VALUE proc_waitall() { VALUE result; int pid, status; rb_secure(2); result = rb_ary_new(); #ifdef NO_WAITPID if (pid_tbl) { st_foreach(pid_tbl, waitall_each, result); } for (pid = -1;;) { pid = wait(&status); if (pid == -1) { if (errno == ECHILD) break; if (errno == EINTR) { rb_thread_schedule(); continue; } rb_sys_fail(0); } last_status_set(status, pid); rb_ary_push(result, rb_assoc_new(INT2NUM(pid), rb_last_status)); } #else rb_last_status = Qnil; for (pid = -1;;) { pid = rb_waitpid(-1, &status, 0); if (pid == -1) { if (errno == ECHILD) break; rb_sys_fail(0); } rb_ary_push(result, rb_assoc_new(INT2NUM(pid), rb_last_status)); } #endif return result; } static VALUE detach_process_watcher(arg) void *arg; { int pid = (int)(VALUE)arg, status; while (rb_waitpid(pid, &status, WNOHANG) == 0) { rb_thread_sleep(1); } return rb_last_status; } VALUE rb_detach_process(pid) int pid; { return rb_thread_create(detach_process_watcher, (void*)(VALUE)pid); } /* * call-seq: * Process.detach(pid) => thread * * Some operating systems retain the status of terminated child * processes until the parent collects that status (normally using * some variant of wait(). If the parent never collects * this status, the child stays around as a zombie process. * Process::detach prevents this by setting up a * separate Ruby thread whose sole job is to reap the status of the * process _pid_ when it terminates. Use detach * only when you do not intent to explicitly wait for the child to * terminate. detach only checks the status * periodically (currently once each second). * * The waiting thread returns the exit status of the detached process * when it terminates, so you can use Thread#join to * know the result. If specified _pid_ is not a valid child process * ID, the thread returns +nil+ immediately. * * In this first example, we don't reap the first child process, so * it appears as a zombie in the process status display. * * p1 = fork { sleep 0.1 } * p2 = fork { sleep 0.2 } * Process.waitpid(p2) * sleep 2 * system("ps -ho pid,state -p #{p1}") * * produces: * * 27389 Z * * In the next example, Process::detach is used to reap * the child automatically. * * p1 = fork { sleep 0.1 } * p2 = fork { sleep 0.2 } * Process.detach(p1) * Process.waitpid(p2) * sleep 2 * system("ps -ho pid,state -p #{p1}") * * (produces no output) */ static VALUE proc_detach(VALUE obj, VALUE pid) { rb_secure(2); return rb_detach_process(NUM2INT(pid)); } #ifndef HAVE_STRING_H char *strtok(); #endif #ifdef HAVE_SETITIMER #define before_exec() rb_thread_stop_timer() #define after_exec() rb_thread_start_timer() #else #define before_exec() #define after_exec() #endif extern char *dln_find_exe(); static void security(str) char *str; { if (rb_env_path_tainted()) { if (rb_safe_level() > 0) { rb_raise(rb_eSecurityError, "Insecure PATH - %s", str); } } } static int proc_exec_v(argv, prog) char **argv; char *prog; { if (!prog) prog = argv[0]; security(prog); prog = dln_find_exe(prog, 0); if (!prog) return -1; #if (defined(MSDOS) && !defined(DJGPP)) || defined(__human68k__) || defined(__EMX__) || defined(OS2) { #if defined(__human68k__) #define COMMAND "command.x" #endif #if defined(__EMX__) || defined(OS2) /* OS/2 emx */ #define COMMAND "cmd.exe" #endif #if (defined(MSDOS) && !defined(DJGPP)) #define COMMAND "command.com" #endif char *extension; if ((extension = strrchr(prog, '.')) != NULL && strcasecmp(extension, ".bat") == 0) { char **new_argv; char *p; int n; for (n = 0; argv[n]; n++) /* no-op */; new_argv = ALLOCA_N(char*, n + 2); for (; n > 0; n--) new_argv[n + 1] = argv[n]; new_argv[1] = strcpy(ALLOCA_N(char, strlen(argv[0]) + 1), argv[0]); for (p = new_argv[1]; *p != '\0'; p++) if (*p == '/') *p = '\\'; new_argv[0] = COMMAND; argv = new_argv; prog = dln_find_exe(argv[0], 0); if (!prog) { errno = ENOENT; return -1; } } } #endif /* MSDOS or __human68k__ or __EMX__ */ before_exec(); execv(prog, argv); preserving_errno(after_exec()); return -1; } static int proc_exec_n(argc, argv, progv) int argc; VALUE *argv; VALUE progv; { char *prog = 0; char **args; int i; if (progv) { prog = RSTRING(progv)->ptr; } args = ALLOCA_N(char*, argc+1); for (i=0; iptr; } args[i] = 0; if (args[0]) { return proc_exec_v(args, prog); } return -1; } int rb_proc_exec(str) const char *str; { #ifndef _WIN32 const char *s = str; char *ss, *t; char **argv, **a; #endif while (*str && ISSPACE(*str)) str++; #ifdef _WIN32 before_exec(); do_spawn(P_OVERLAY, (char *)str); after_exec(); #else for (s=str; *s; s++) { if (*s != ' ' && !ISALPHA(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s)) { #if defined(MSDOS) int status; before_exec(); status = system(str); after_exec(); if (status != -1) exit(status); #else #if defined(__human68k__) || defined(__CYGWIN32__) || defined(__EMX__) char *shell = dln_find_exe("sh", 0); int status = -1; before_exec(); if (shell) execl(shell, "sh", "-c", str, (char *) NULL); else status = system(str); after_exec(); if (status != -1) exit(status); #else before_exec(); execl("/bin/sh", "sh", "-c", str, (char *)NULL); preserving_errno(after_exec()); #endif #endif return -1; } } a = argv = ALLOCA_N(char*, (s-str)/2+2); ss = ALLOCA_N(char, s-str+1); strcpy(ss, str); if ((*a++ = strtok(ss, " \t")) != 0) { while ((t = strtok(NULL, " \t")) != 0) { *a++ = t; } *a = NULL; } if (argv[0]) { return proc_exec_v(argv, 0); } errno = ENOENT; #endif /* _WIN32 */ return -1; } #if defined(__human68k__) || defined(__DJGPP__) || defined(_WIN32) static int proc_spawn_v(argv, prog) char **argv; char *prog; { #if defined(__human68k__) char *extension; #endif int status; if (!prog) prog = argv[0]; security(prog); prog = dln_find_exe(prog, 0); if (!prog) return -1; #if defined(__human68k__) if ((extension = strrchr(prog, '.')) != NULL && strcasecmp(extension, ".bat") == 0) { char **new_argv; char *p; int n; for (n = 0; argv[n]; n++) /* no-op */; new_argv = ALLOCA_N(char*, n + 2); for (; n > 0; n--) new_argv[n + 1] = argv[n]; new_argv[1] = strcpy(ALLOCA_N(char, strlen(argv[0]) + 1), argv[0]); for (p = new_argv[1]; *p != '\0'; p++) if (*p == '/') *p = '\\'; new_argv[0] = COMMAND; argv = new_argv; prog = dln_find_exe(argv[0], 0); if (!prog) { errno = ENOENT; return -1; } } #endif before_exec(); #if defined(_WIN32) status = do_aspawn(P_WAIT, prog, argv); #else status = spawnv(P_WAIT, prog, argv); #endif after_exec(); return status; } static int proc_spawn_n(argc, argv, prog) int argc; VALUE *argv; VALUE prog; { char **args; int i; args = ALLOCA_N(char*, argc + 1); for (i = 0; i < argc; i++) { SafeStringValue(argv[i]); args[i] = StringValueCStr(argv[i]); } if (prog) SafeStringValue(prog); args[i] = (char*) 0; if (args[0]) return proc_spawn_v(args, prog ? StringValueCStr(prog) : 0); return -1; } #if !defined(_WIN32) static int proc_spawn(sv) VALUE sv; { char *str; char *s, *t; char **argv, **a; int status; SafeStringValue(sv); str = s = StringValueCStr(sv); for (s = str; *s; s++) { if (*s != ' ' && !ISALPHA(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s)) { char *shell = dln_find_exe("sh", 0); before_exec(); status = shell?spawnl(P_WAIT,shell,"sh","-c",str,(char*)NULL):system(str); after_exec(); return status; } } a = argv = ALLOCA_N(char*, (s - str) / 2 + 2); s = ALLOCA_N(char, s - str + 1); strcpy(s, str); if (*a++ = strtok(s, " \t")) { while (t = strtok(NULL, " \t")) *a++ = t; *a = NULL; } return argv[0] ? proc_spawn_v(argv, 0) : -1; } #endif #endif struct rb_exec_arg { int argc; VALUE *argv; VALUE prog; }; static void proc_prepare_args(e, argc, argv, prog) struct rb_exec_arg *e; int argc; VALUE *argv; VALUE prog; { int i; MEMZERO(e, struct rb_exec_arg, 1); if (prog) { SafeStringValue(prog); StringValueCStr(prog); } for (i = 0; i < argc; i++) { SafeStringValue(argv[i]); StringValueCStr(argv[i]); } security(RSTRING(prog ? prog : argv[0])->ptr); e->prog = prog; e->argc = argc; e->argv = argv; } static VALUE proc_exec_args(earg) VALUE earg; { struct rb_exec_arg *e = (struct rb_exec_arg *)earg; int argc = e->argc; VALUE *argv = e->argv; VALUE prog = e->prog; if (argc == 1 && prog == 0) { return (VALUE)rb_proc_exec(RSTRING(argv[0])->ptr); } else { return (VALUE)proc_exec_n(argc, argv, prog); } } /* * call-seq: * exec(command [, arg, ...]) * * Replaces the current process by running the given external _command_. * If +exec+ is given a single argument, that argument is * taken as a line that is subject to shell expansion before being * executed. If multiple arguments are given, the second and subsequent * arguments are passed as parameters to _command_ with no shell * expansion. If the first argument is a two-element array, the first * element is the command to be executed, and the second argument is * used as the argv[0] value, which may show up in process * listings. In MSDOS environments, the command is executed in a * subshell; otherwise, one of the exec(2) system calls is * used, so the running command may inherit some of the environment of * the original program (including open file descriptors). * * exec "echo *" # echoes list of files in current directory * # never get here * * * exec "echo", "*" # echoes an asterisk * # never get here */ VALUE rb_f_exec(argc, argv) int argc; VALUE *argv; { VALUE prog = 0; VALUE tmp; struct rb_exec_arg earg; if (argc == 0) { rb_last_status = Qnil; rb_raise(rb_eArgError, "wrong number of arguments"); } tmp = rb_check_array_type(argv[0]); if (!NIL_P(tmp)) { if (RARRAY(tmp)->len != 2) { rb_raise(rb_eArgError, "wrong first argument"); } prog = RARRAY(tmp)->ptr[0]; argv[0] = RARRAY(tmp)->ptr[1]; SafeStringValue(prog); } proc_prepare_args(&earg, argc, argv, prog); proc_exec_args((VALUE)&earg); rb_sys_fail(RSTRING(argv[0])->ptr); return Qnil; /* dummy */ } /* * call-seq: * Kernel.fork [{ block }] => fixnum or nil * Process.fork [{ block }] => fixnum or nil * * Creates a subprocess. If a block is specified, that block is run * in the subprocess, and the subprocess terminates with a status of * zero. Otherwise, the +fork+ call returns twice, once in * the parent, returning the process ID of the child, and once in * the child, returning _nil_. The child process can exit using * Kernel.exit! to avoid running any * at_exit functions. The parent process should * use Process.wait to collect the termination statuses * of its children or use Process.detach to register * disinterest in their status; otherwise, the operating system * may accumulate zombie processes. * * The thread calling fork is the only thread in the created child process. * fork doesn't copy other threads. */ static VALUE rb_f_fork(obj) VALUE obj; { #if !defined(__human68k__) && !defined(_WIN32) && !defined(__MACOS__) && !defined(__EMX__) && !defined(__VMS) int pid; rb_secure(2); #ifndef __VMS fflush(stdout); fflush(stderr); #endif #if defined(__NetBSD__) || defined(__APPLE__) || defined(linux) before_exec(); #endif pid = fork(); #if defined(__NetBSD__) || defined(__APPLE__) || defined(linux) after_exec(); #endif switch (pid) { case 0: #ifdef linux after_exec(); #endif rb_thread_atfork(); if (rb_block_given_p()) { int status; rb_protect(rb_yield, Qundef, &status); ruby_stop(status); } return Qnil; case -1: rb_sys_fail("fork(2)"); return Qnil; default: return INT2FIX(pid); } #else rb_notimplement(); #endif } /* * call-seq: * Process.exit!(fixnum=-1) * * Exits the process immediately. No exit handlers are * run. fixnum is returned to the underlying system as the * exit status. * * Process.exit!(0) */ static VALUE rb_f_exit_bang(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE status; int istatus; rb_secure(4); if (rb_scan_args(argc, argv, "01", &status) == 1) { switch (status) { case Qtrue: istatus = EXIT_SUCCESS; break; case Qfalse: istatus = EXIT_FAILURE; break; default: istatus = NUM2INT(status); break; } } else { istatus = EXIT_FAILURE; } _exit(istatus); return Qnil; /* not reached */ } #if defined(sun) #define signal(a,b) sigset(a,b) #endif void rb_syswait(pid) int pid; { static int overriding; #ifdef SIGHUP RETSIGTYPE (*hfunc)_((int)) = 0; #endif #ifdef SIGQUIT RETSIGTYPE (*qfunc)_((int)) = 0; #endif RETSIGTYPE (*ifunc)_((int)) = 0; int status; int i, hooked = Qfalse; if (!overriding) { #ifdef SIGHUP hfunc = signal(SIGHUP, SIG_IGN); #endif #ifdef SIGQUIT qfunc = signal(SIGQUIT, SIG_IGN); #endif ifunc = signal(SIGINT, SIG_IGN); overriding = Qtrue; hooked = Qtrue; } do { i = rb_waitpid(pid, &status, 0); } while (i == -1 && errno == EINTR); if (hooked) { #ifdef SIGHUP signal(SIGHUP, hfunc); #endif #ifdef SIGQUIT signal(SIGQUIT, qfunc); #endif signal(SIGINT, ifunc); overriding = Qfalse; } } /* * call-seq: * system(cmd [, arg, ...]) => true or false * * Executes _cmd_ in a subshell, returning +true+ if * the command was found and ran successfully, +false+ * otherwise. An error status is available in $?. The * arguments are processed in the same way as for * Kernel::exec. * * system("echo *") * system("echo", "*") * * produces: * * config.h main.rb * * */ static VALUE rb_f_system(argc, argv) int argc; VALUE *argv; { int status; #if defined(__EMX__) VALUE cmd; fflush(stdout); fflush(stderr); if (argc == 0) { rb_last_status = Qnil; rb_raise(rb_eArgError, "wrong number of arguments"); } if (TYPE(argv[0]) == T_ARRAY) { if (RARRAY(argv[0])->len != 2) { rb_raise(rb_eArgError, "wrong first argument"); } argv[0] = RARRAY(argv[0])->ptr[0]; } cmd = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" ")); SafeStringValue(cmd); status = do_spawn(RSTRING(cmd)->ptr); last_status_set(status, 0); #elif defined(__human68k__) || defined(__DJGPP__) || defined(_WIN32) volatile VALUE prog = 0; fflush(stdout); fflush(stderr); if (argc == 0) { rb_last_status = Qnil; rb_raise(rb_eArgError, "wrong number of arguments"); } if (TYPE(argv[0]) == T_ARRAY) { if (RARRAY(argv[0])->len != 2) { rb_raise(rb_eArgError, "wrong first argument"); } prog = RARRAY(argv[0])->ptr[0]; argv[0] = RARRAY(argv[0])->ptr[1]; } if (argc == 1 && prog == 0) { #if defined(_WIN32) SafeStringValue(argv[0]); status = do_spawn(P_WAIT, StringValueCStr(argv[0])); #else status = proc_spawn(argv[0]); #endif } else { status = proc_spawn_n(argc, argv, prog); } #if !defined(_WIN32) last_status_set(status == -1 ? 127 : status, 0); #else if (status == -1) last_status_set(0x7f << 8, 0); #endif #elif defined(__VMS) VALUE cmd; if (argc == 0) { rb_last_status = Qnil; rb_raise(rb_eArgError, "wrong number of arguments"); } if (TYPE(argv[0]) == T_ARRAY) { if (RARRAY(argv[0])->len != 2) { rb_raise(rb_eArgError, "wrong first argument"); } argv[0] = RARRAY(argv[0])->ptr[0]; } cmd = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" ")); SafeStringValue(cmd); status = system(StringValueCStr(cmd)); last_status_set((status & 0xff) << 8, 0); #else volatile VALUE prog = 0; int pid; struct rb_exec_arg earg; RETSIGTYPE (*chfunc)(int); fflush(stdout); fflush(stderr); if (argc == 0) { rb_last_status = Qnil; rb_raise(rb_eArgError, "wrong number of arguments"); } if (TYPE(argv[0]) == T_ARRAY) { if (RARRAY(argv[0])->len != 2) { rb_raise(rb_eArgError, "wrong first argument"); } prog = RARRAY(argv[0])->ptr[0]; argv[0] = RARRAY(argv[0])->ptr[1]; } proc_prepare_args(&earg, argc, argv, prog); chfunc = signal(SIGCHLD, SIG_DFL); retry: #if defined(__NetBSD__) || defined(__APPLE__) || defined(linux) before_exec(); #endif pid = fork(); if (pid == 0) { /* child process */ rb_thread_atfork(); rb_protect(proc_exec_args, (VALUE)&earg, NULL); _exit(127); } #if defined(__NetBSD__) || defined(__APPLE__) || defined(linux) after_exec(); #endif if (pid < 0) { if (errno == EAGAIN) { rb_thread_sleep(1); goto retry; } } else { rb_syswait(pid); } signal(SIGCHLD, chfunc); if (pid < 0) rb_sys_fail(0); status = NUM2INT(rb_last_status); #endif if (status == EXIT_SUCCESS) return Qtrue; return Qfalse; } /* * call-seq: * sleep([duration]) => fixnum * * Suspends the current thread for _duration_ seconds (which may be any number, * including a +Float+ with fractional seconds). Returns the actual number of * seconds slept (rounded), which may be less than that asked for if another * thread calls Thread#run. Zero arguments causes +sleep+ to sleep * forever. * * Time.new #=> Wed Apr 09 08:56:32 CDT 2003 * sleep 1.2 #=> 1 * Time.new #=> Wed Apr 09 08:56:33 CDT 2003 * sleep 1.9 #=> 2 * Time.new #=> Wed Apr 09 08:56:35 CDT 2003 */ static VALUE rb_f_sleep(argc, argv) int argc; VALUE *argv; { int beg, end; beg = time(0); if (argc == 0) { rb_thread_sleep_forever(); } else if (argc == 1) { rb_thread_wait_for(rb_time_interval(argv[0])); } else { rb_raise(rb_eArgError, "wrong number of arguments"); } end = time(0) - beg; return INT2FIX(end); } #if defined(SIGCLD) && !defined(SIGCHLD) # define SIGCHLD SIGCLD #endif /* * call-seq: * Process.getpgrp => integer * * Returns the process group ID for this process. Not available on * all platforms. * * Process.getpgid(0) #=> 25527 * Process.getpgrp #=> 25527 */ static VALUE proc_getpgrp() { #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID) int pgrp; #endif rb_secure(2); #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID) pgrp = getpgrp(); if (pgrp < 0) rb_sys_fail(0); return INT2FIX(pgrp); #else # ifdef HAVE_GETPGID pgrp = getpgid(0); if (pgrp < 0) rb_sys_fail(0); return INT2FIX(pgrp); # else rb_notimplement(); # endif #endif } /* * call-seq: * Process.setpgrp => 0 * * Equivalent to setpgid(0,0). Not available on all * platforms. */ static VALUE proc_setpgrp() { rb_secure(2); /* check for posix setpgid() first; this matches the posix */ /* getpgrp() above. It appears that configure will set SETPGRP_VOID */ /* even though setpgrp(0,0) would be prefered. The posix call avoids */ /* this confusion. */ #ifdef HAVE_SETPGID if (setpgid(0,0) < 0) rb_sys_fail(0); #elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID) if (setpgrp() < 0) rb_sys_fail(0); #else rb_notimplement(); #endif return INT2FIX(0); } /* * call-seq: * Process.getpgid(pid) => integer * * Returns the process group ID for the given process id. Not * available on all platforms. * * Process.getpgid(Process.ppid()) #=> 25527 */ static VALUE proc_getpgid(obj, pid) VALUE obj, pid; { #if defined(HAVE_GETPGID) && !defined(__CHECKER__) int i; rb_secure(2); i = getpgid(NUM2INT(pid)); if (i < 0) rb_sys_fail(0); return INT2NUM(i); #else rb_notimplement(); #endif } /* * call-seq: * Process.setpgid(pid, integer) => 0 * * Sets the process group ID of _pid_ (0 indicates this * process) to integer. Not available on all platforms. */ static VALUE proc_setpgid(obj, pid, pgrp) VALUE obj, pid, pgrp; { #ifdef HAVE_SETPGID int ipid, ipgrp; rb_secure(2); ipid = NUM2INT(pid); ipgrp = NUM2INT(pgrp); if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0); return INT2FIX(0); #else rb_notimplement(); #endif } /* * call-seq: * Process.setsid => fixnum * * Establishes this process as a new session and process group * leader, with no controlling tty. Returns the session id. Not * available on all platforms. * * Process.setsid #=> 27422 */ static VALUE proc_setsid() { #if defined(HAVE_SETSID) int pid; rb_secure(2); pid = setsid(); if (pid < 0) rb_sys_fail(0); return INT2FIX(pid); #elif defined(HAVE_SETPGRP) && defined(TIOCNOTTY) rb_pid_t pid; int ret; rb_secure(2); pid = getpid(); #if defined(SETPGRP_VOID) ret = setpgrp(); /* If `pid_t setpgrp(void)' is equivalent to setsid(), `ret' will be the same value as `pid', and following open() will fail. In Linux, `int setpgrp(void)' is equivalent to setpgid(0, 0). */ #else ret = setpgrp(0, pid); #endif if (ret == -1) rb_sys_fail(0); if ((fd = open("/dev/tty", O_RDWR)) >= 0) { ioctl(fd, TIOCNOTTY, NULL); close(fd); } return INT2FIX(pid); #else rb_notimplement(); #endif } /* * call-seq: * Process.getpriority(kind, integer) => fixnum * * Gets the scheduling priority for specified process, process group, * or user. kind indicates the kind of entity to find: one * of Process::PRIO_PGRP, * Process::PRIO_USER, or * Process::PRIO_PROCESS. _integer_ is an id * indicating the particular process, process group, or user (an id * of 0 means _current_). Lower priorities are more favorable * for scheduling. Not available on all platforms. * * Process.getpriority(Process::PRIO_USER, 0) #=> 19 * Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19 */ static VALUE proc_getpriority(obj, which, who) VALUE obj, which, who; { #ifdef HAVE_GETPRIORITY int prio, iwhich, iwho; rb_secure(2); iwhich = NUM2INT(which); iwho = NUM2INT(who); errno = 0; prio = getpriority(iwhich, iwho); if (errno) rb_sys_fail(0); return INT2FIX(prio); #else rb_notimplement(); #endif } /* * call-seq: * Process.setpriority(kind, integer, priority) => 0 * * See Process#getpriority. * * Process.setpriority(Process::PRIO_USER, 0, 19) #=> 0 * Process.setpriority(Process::PRIO_PROCESS, 0, 19) #=> 0 * Process.getpriority(Process::PRIO_USER, 0) #=> 19 * Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19 */ static VALUE proc_setpriority(obj, which, who, prio) VALUE obj, which, who, prio; { #ifdef HAVE_GETPRIORITY int iwhich, iwho, iprio; rb_secure(2); iwhich = NUM2INT(which); iwho = NUM2INT(who); iprio = NUM2INT(prio); if (setpriority(iwhich, iwho, iprio) < 0) rb_sys_fail(0); return INT2FIX(0); #else rb_notimplement(); #endif } #if SIZEOF_RLIM_T == SIZEOF_INT # define RLIM2NUM(v) UINT2NUM(v) # define NUM2RLIM(v) NUM2UINT(v) #elif SIZEOF_RLIM_T == SIZEOF_LONG # define RLIM2NUM(v) ULONG2NUM(v) # define NUM2RLIM(v) NUM2ULONG(v) #elif SIZEOF_RLIM_T == SIZEOF_LONG_LONG # define RLIM2NUM(v) ULL2NUM(v) # define NUM2RLIM(v) NUM2ULL(v) #endif /* * call-seq: * Process.getrlimit(resource) => [cur_limit, max_limit] * * Gets the resource limit of the process. * _cur_limit_ means current (soft) limit and * _max_limit_ means maximum (hard) limit. * * _resource_ indicates the kind of resource to limit: * such as Process::RLIMIT_CORE, * Process::RLIMIT_CPU, etc. * See Process.setrlimit for details. * * _cur_limit_ and _max_limit_ may be Process::RLIM_INFINITY, * Process::RLIM_SAVED_MAX or * Process::RLIM_SAVED_CUR. * See Process.setrlimit and the system getrlimit(2) manual for details. */ static VALUE proc_getrlimit(VALUE obj, VALUE resource) { #if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM) struct rlimit rlim; rb_secure(2); if (getrlimit(NUM2INT(resource), &rlim) < 0) { rb_sys_fail("getrlimit"); } return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max)); #else rb_notimplement(); #endif } /* * call-seq: * Process.setrlimit(resource, cur_limit, max_limit) => nil * Process.setrlimit(resource, cur_limit) => nil * * Sets the resource limit of the process. * _cur_limit_ means current (soft) limit and * _max_limit_ means maximum (hard) limit. * * If _max_limit_ is not given, _cur_limit_ is used. * * _resource_ indicates the kind of resource to limit. * The list of resources are OS dependent. * Ruby may support following resources. * * [Process::RLIMIT_CORE] core size (bytes) (SUSv3) * [Process::RLIMIT_CPU] CPU time (seconds) (SUSv3) * [Process::RLIMIT_DATA] data segment (bytes) (SUSv3) * [Process::RLIMIT_FSIZE] file size (bytes) (SUSv3) * [Process::RLIMIT_NOFILE] file descriptors (number) (SUSv3) * [Process::RLIMIT_STACK] stack size (bytes) (SUSv3) * [Process::RLIMIT_AS] total available memory (bytes) (SUSv3, NetBSD, FreeBSD, OpenBSD but 4.4BSD-Lite) * [Process::RLIMIT_MEMLOCK] total size for mlock(2) (bytes) (4.4BSD, GNU/Linux) * [Process::RLIMIT_NPROC] number of processes for the user (number) (4.4BSD, GNU/Linux) * [Process::RLIMIT_RSS] resident memory size (bytes) (4.2BSD, GNU/Linux) * [Process::RLIMIT_SBSIZE] all socket buffers (bytes) (NetBSD, FreeBSD) * * Other Process::RLIMIT_??? constants may be defined. * * _cur_limit_ and _max_limit_ may be Process::RLIM_INFINITY, * which means that the resource is not limited. * They may be Process::RLIM_SAVED_MAX or * Process::RLIM_SAVED_CUR too. * See system setrlimit(2) manual for details. * */ static VALUE proc_setrlimit(int argc, VALUE *argv, VALUE obj) { #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM) VALUE resource, rlim_cur, rlim_max; struct rlimit rlim; rb_secure(2); rb_scan_args(argc, argv, "21", &resource, &rlim_cur, &rlim_max); if (rlim_max == Qnil) rlim_max = rlim_cur; rlim.rlim_cur = NUM2RLIM(rlim_cur); rlim.rlim_max = NUM2RLIM(rlim_max); if (setrlimit(NUM2INT(resource), &rlim) < 0) { rb_sys_fail("setrlimit"); } return Qnil; #else rb_notimplement(); #endif } static int under_uid_switch = 0; static void check_uid_switch() { rb_secure(2); if (under_uid_switch) { rb_raise(rb_eRuntimeError, "can't handle UID while evaluating block given to Process::UID.switch method"); } } static int under_gid_switch = 0; static void check_gid_switch() { rb_secure(2); if (under_gid_switch) { rb_raise(rb_eRuntimeError, "can't handle GID while evaluating block given to Process::UID.switch method"); } } /********************************************************************* * Document-class: Process::Sys * * The Process::Sys module contains UID and GID * functions which provide direct bindings to the system calls of the * same names instead of the more-portable versions of the same * functionality found in the Process, * Process::UID, and Process::GID modules. */ /* * call-seq: * Process::Sys.setuid(integer) => nil * * Set the user ID of the current process to _integer_. Not * available on all platforms. * */ static VALUE p_sys_setuid(obj, id) VALUE obj, id; { #if defined HAVE_SETUID check_uid_switch(); if (setuid(NUM2INT(id)) != 0) rb_sys_fail(0); #else rb_notimplement(); #endif return Qnil; } /* * call-seq: * Process::Sys.setruid(integer) => nil * * Set the real user ID of the calling process to _integer_. * Not available on all platforms. * */ static VALUE p_sys_setruid(obj, id) VALUE obj, id; { #if defined HAVE_SETRUID check_uid_switch(); if (setruid(NUM2INT(id)) != 0) rb_sys_fail(0); #else rb_notimplement(); #endif return Qnil; } /* * call-seq: * Process::Sys.seteuid(integer) => nil * * Set the effective user ID of the calling process to * _integer_. Not available on all platforms. * */ static VALUE p_sys_seteuid(obj, id) VALUE obj, id; { #if defined HAVE_SETEUID check_uid_switch(); if (seteuid(NUM2INT(id)) != 0) rb_sys_fail(0); #else rb_notimplement(); #endif return Qnil; } /* * call-seq: * Process::Sys.setreuid(rid, eid) => nil * * Sets the (integer) real and/or effective user IDs of the current * process to _rid_ and _eid_, respectively. A value of * -1 for either means to leave that ID unchanged. Not * available on all platforms. * */ static VALUE p_sys_setreuid(obj, rid, eid) VALUE obj, rid, eid; { #if defined HAVE_SETREUID check_uid_switch(); if (setreuid(NUM2INT(rid),NUM2INT(eid)) != 0) rb_sys_fail(0); #else rb_notimplement(); #endif return Qnil; } /* * call-seq: * Process::Sys.setresuid(rid, eid, sid) => nil * * Sets the (integer) real, effective, and saved user IDs of the * current process to _rid_, _eid_, and _sid_ respectively. A * value of -1 for any value means to * leave that ID unchanged. Not available on all platforms. * */ static VALUE p_sys_setresuid(obj, rid, eid, sid) VALUE obj, rid, eid, sid; { #if defined HAVE_SETRESUID check_uid_switch(); if (setresuid(NUM2INT(rid),NUM2INT(eid),NUM2INT(sid)) != 0) rb_sys_fail(0); #else rb_notimplement(); #endif return Qnil; } /* * call-seq: * Process.uid => fixnum * Process::UID.rid => fixnum * Process::Sys.getuid => fixnum * * Returns the (real) user ID of this process. * * Process.uid #=> 501 */ static VALUE proc_getuid(obj) VALUE obj; { int uid = getuid(); return INT2FIX(uid); } /* * call-seq: * Process.uid= integer => numeric * * Sets the (integer) user ID for this process. Not available on all * platforms. */ static VALUE proc_setuid(obj, id) VALUE obj, id; { int uid = NUM2INT(id); check_uid_switch(); #if defined(HAVE_SETRESUID) && !defined(__CHECKER__) if (setresuid(uid, -1, -1) < 0) rb_sys_fail(0); #elif defined HAVE_SETREUID if (setreuid(uid, -1) < 0) rb_sys_fail(0); #elif defined HAVE_SETRUID if (setruid(uid) < 0) rb_sys_fail(0); #elif defined HAVE_SETUID { if (geteuid() == uid) { if (setuid(uid) < 0) rb_sys_fail(0); } else { rb_notimplement(); } } #else rb_notimplement(); #endif return INT2FIX(uid); } /******************************************************************** * * Document-class: Process::UID * * The Process::UID module contains a collection of * module functions which can be used to portably get, set, and * switch the current process's real, effective, and saved user IDs. * */ static int SAVED_USER_ID = -1; #ifdef BROKEN_SETREUID int setreuid(ruid, euid) rb_uid_t ruid, euid; { if (ruid != -1 && ruid != getuid()) { if (euid == -1) euid = geteuid(); if (setuid(ruid) < 0) return -1; } if (euid != -1 && euid != geteuid()) { if (seteuid(euid) < 0) return -1; } return 0; } #endif /* * call-seq: * Process::UID.change_privilege(integer) => fixnum * * Change the current process's real and effective user ID to that * specified by _integer_. Returns the new user ID. Not * available on all platforms. * * [Process.uid, Process.euid] #=> [0, 0] * Process::UID.change_privilege(31) #=> 31 * [Process.uid, Process.euid] #=> [31, 31] */ static VALUE p_uid_change_privilege(obj, id) VALUE obj, id; { int uid; check_uid_switch(); uid = NUM2INT(id); if (geteuid() == 0) { /* root-user */ #if defined(HAVE_SETRESUID) if (setresuid(uid, uid, uid) < 0) rb_sys_fail(0); SAVED_USER_ID = uid; #elif defined(HAVE_SETUID) if (setuid(uid) < 0) rb_sys_fail(0); SAVED_USER_ID = uid; #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID) if (getuid() == uid) { if (SAVED_USER_ID == uid) { if (setreuid(-1, uid) < 0) rb_sys_fail(0); } else { if (uid == 0) { /* (r,e,s) == (root, root, x) */ if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0); if (setreuid(SAVED_USER_ID, 0) < 0) rb_sys_fail(0); SAVED_USER_ID = 0; /* (r,e,s) == (x, root, root) */ if (setreuid(uid, uid) < 0) rb_sys_fail(0); SAVED_USER_ID = uid; } else { if (setreuid(0, -1) < 0) rb_sys_fail(0); SAVED_USER_ID = 0; if (setreuid(uid, uid) < 0) rb_sys_fail(0); SAVED_USER_ID = uid; } } } else { if (setreuid(uid, uid) < 0) rb_sys_fail(0); SAVED_USER_ID = uid; } #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID) if (getuid() == uid) { if (SAVED_USER_ID == uid) { if (seteuid(uid) < 0) rb_sys_fail(0); } else { if (uid == 0) { if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0); SAVED_USER_ID = 0; if (setruid(0) < 0) rb_sys_fail(0); } else { if (setruid(0) < 0) rb_sys_fail(0); SAVED_USER_ID = 0; if (seteuid(uid) < 0) rb_sys_fail(0); if (setruid(uid) < 0) rb_sys_fail(0); SAVED_USER_ID = uid; } } } else { if (seteuid(uid) < 0) rb_sys_fail(0); if (setruid(uid) < 0) rb_sys_fail(0); SAVED_USER_ID = uid; } #else rb_notimplement(); #endif } else { /* unprivileged user */ #if defined(HAVE_SETRESUID) if (setresuid((getuid() == uid)? -1: uid, (geteuid() == uid)? -1: uid, (SAVED_USER_ID == uid)? -1: uid) < 0) rb_sys_fail(0); SAVED_USER_ID = uid; #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID) if (SAVED_USER_ID == uid) { if (setreuid((getuid() == uid)? -1: uid, (geteuid() == uid)? -1: uid) < 0) rb_sys_fail(0); } else if (getuid() != uid) { if (setreuid(uid, (geteuid() == uid)? -1: uid) < 0) rb_sys_fail(0); SAVED_USER_ID = uid; } else if (/* getuid() == uid && */ geteuid() != uid) { if (setreuid(geteuid(), uid) < 0) rb_sys_fail(0); SAVED_USER_ID = uid; if (setreuid(uid, -1) < 0) rb_sys_fail(0); } else { /* getuid() == uid && geteuid() == uid */ if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0); if (setreuid(SAVED_USER_ID, uid) < 0) rb_sys_fail(0); SAVED_USER_ID = uid; if (setreuid(uid, -1) < 0) rb_sys_fail(0); } #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID) if (SAVED_USER_ID == uid) { if (geteuid() != uid && seteuid(uid) < 0) rb_sys_fail(0); if (getuid() != uid && setruid(uid) < 0) rb_sys_fail(0); } else if (/* SAVED_USER_ID != uid && */ geteuid() == uid) { if (getuid() != uid) { if (setruid(uid) < 0) rb_sys_fail(0); SAVED_USER_ID = uid; } else { if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0); SAVED_USER_ID = uid; if (setruid(uid) < 0) rb_sys_fail(0); } } else if (/* geteuid() != uid && */ getuid() == uid) { if (seteuid(uid) < 0) rb_sys_fail(0); if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0); SAVED_USER_ID = uid; if (setruid(uid) < 0) rb_sys_fail(0); } else { errno = EPERM; rb_sys_fail(0); } #elif defined HAVE_44BSD_SETUID if (getuid() == uid) { /* (r,e,s)==(uid,?,?) ==> (uid,uid,uid) */ if (setuid(uid) < 0) rb_sys_fail(0); SAVED_USER_ID = uid; } else { errno = EPERM; rb_sys_fail(0); } #elif defined HAVE_SETEUID if (getuid() == uid && SAVED_USER_ID == uid) { if (seteuid(uid) < 0) rb_sys_fail(0); } else { errno = EPERM; rb_sys_fail(0); } #elif defined HAVE_SETUID if (getuid() == uid && SAVED_USER_ID == uid) { if (setuid(uid) < 0) rb_sys_fail(0); } else { errno = EPERM; rb_sys_fail(0); } #else rb_notimplement(); #endif } return INT2FIX(uid); } /* * call-seq: * Process::Sys.setgid(integer) => nil * * Set the group ID of the current process to _integer_. Not * available on all platforms. * */ static VALUE p_sys_setgid(obj, id) VALUE obj, id; { #if defined HAVE_SETGID check_gid_switch(); if (setgid(NUM2INT(id)) != 0) rb_sys_fail(0); #else rb_notimplement(); #endif return Qnil; } /* * call-seq: * Process::Sys.setrgid(integer) => nil * * Set the real group ID of the calling process to _integer_. * Not available on all platforms. * */ static VALUE p_sys_setrgid(obj, id) VALUE obj, id; { #if defined HAVE_SETRGID check_gid_switch(); if (setrgid(NUM2INT(id)) != 0) rb_sys_fail(0); #else rb_notimplement(); #endif return Qnil; } /* * call-seq: * Process::Sys.setegid(integer) => nil * * Set the effective group ID of the calling process to * _integer_. Not available on all platforms. * */ static VALUE p_sys_setegid(obj, id) VALUE obj, id; { #if defined HAVE_SETEGID check_gid_switch(); if (setegid(NUM2INT(id)) != 0) rb_sys_fail(0); #else rb_notimplement(); #endif return Qnil; } /* * call-seq: * Process::Sys.setregid(rid, eid) => nil * * Sets the (integer) real and/or effective group IDs of the current * process to rid and eid, respectively. A value of * -1 for either means to leave that ID unchanged. Not * available on all platforms. * */ static VALUE p_sys_setregid(obj, rid, eid) VALUE obj, rid, eid; { #if defined HAVE_SETREGID check_gid_switch(); if (setregid(NUM2INT(rid),NUM2INT(eid)) != 0) rb_sys_fail(0); #else rb_notimplement(); #endif return Qnil; } /* * call-seq: * Process::Sys.setresgid(rid, eid, sid) => nil * * Sets the (integer) real, effective, and saved user IDs of the * current process to rid, eid, and sid * respectively. A value of -1 for any value means to * leave that ID unchanged. Not available on all platforms. * */ static VALUE p_sys_setresgid(obj, rid, eid, sid) VALUE obj, rid, eid, sid; { #if defined HAVE_SETRESGID check_gid_switch(); if (setresgid(NUM2INT(rid),NUM2INT(eid),NUM2INT(sid)) != 0) rb_sys_fail(0); #else rb_notimplement(); #endif return Qnil; } /* * call-seq: * Process::Sys.issetugid => true or false * * Returns +true+ if the process was created as a result * of an execve(2) system call which had either of the setuid or * setgid bits set (and extra privileges were given as a result) or * if it has changed any of its real, effective or saved user or * group IDs since it began execution. * */ static VALUE p_sys_issetugid(obj) VALUE obj; { #if defined HAVE_ISSETUGID rb_secure(2); if (issetugid()) { return Qtrue; } else { return Qfalse; } #else rb_notimplement(); return Qnil; /* not reached */ #endif } /* * call-seq: * Process.gid => fixnum * Process::GID.rid => fixnum * Process::Sys.getgid => fixnum * * Returns the (real) group ID for this process. * * Process.gid #=> 500 */ static VALUE proc_getgid(obj) VALUE obj; { int gid = getgid(); return INT2FIX(gid); } /* * call-seq: * Process.gid= fixnum => fixnum * * Sets the group ID for this process. */ static VALUE proc_setgid(obj, id) VALUE obj, id; { int gid = NUM2INT(id); check_gid_switch(); #if defined(HAVE_SETRESGID) && !defined(__CHECKER__) if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0); #elif defined HAVE_SETREGID if (setregid(gid, -1) < 0) rb_sys_fail(0); #elif defined HAVE_SETRGID if (setrgid(gid) < 0) rb_sys_fail(0); #elif defined HAVE_SETGID { if (getegid() == gid) { if (setgid(gid) < 0) rb_sys_fail(0); } else { rb_notimplement(); } } #else rb_notimplement(); #endif return INT2FIX(gid); } static size_t maxgroups = 32; /* * call-seq: * Process.groups => array * * Get an Array of the gids of groups in the * supplemental group access list for this process. * * Process.groups #=> [27, 6, 10, 11] * */ static VALUE proc_getgroups(VALUE obj) { #ifdef HAVE_GETGROUPS VALUE ary; size_t ngroups; rb_gid_t *groups; int i; groups = ALLOCA_N(rb_gid_t, maxgroups); ngroups = getgroups(maxgroups, groups); if (ngroups == -1) rb_sys_fail(0); ary = rb_ary_new(); for (i = 0; i < ngroups; i++) rb_ary_push(ary, INT2NUM(groups[i])); return ary; #else rb_notimplement(); return Qnil; #endif } /* * call-seq: * Process.groups= array => array * * Set the supplemental group access list to the given * Array of group IDs. * * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27] * Process.groups = [27, 6, 10, 11] #=> [27, 6, 10, 11] * Process.groups #=> [27, 6, 10, 11] * */ static VALUE proc_setgroups(VALUE obj, VALUE ary) { #ifdef HAVE_SETGROUPS size_t ngroups; rb_gid_t *groups; int i; struct group *gr; Check_Type(ary, T_ARRAY); ngroups = RARRAY(ary)->len; if (ngroups > maxgroups) rb_raise(rb_eArgError, "too many groups, %d max", maxgroups); groups = ALLOCA_N(rb_gid_t, ngroups); for (i = 0; i < ngroups && i < RARRAY(ary)->len; i++) { VALUE g = RARRAY(ary)->ptr[i]; if (FIXNUM_P(g)) { groups[i] = FIX2INT(g); } else { VALUE tmp = rb_check_string_type(g); if (NIL_P(tmp)) { groups[i] = NUM2INT(g); } else { gr = getgrnam(RSTRING(tmp)->ptr); if (gr == NULL) rb_raise(rb_eArgError, "can't find group for %s", RSTRING(tmp)->ptr); groups[i] = gr->gr_gid; } } } i = setgroups(ngroups, groups); if (i == -1) rb_sys_fail(0); return proc_getgroups(obj); #else rb_notimplement(); return Qnil; #endif } /* * call-seq: * Process.initgroups(username, gid) => array * * Initializes the supplemental group access list by reading the * system group database and using all groups of which the given user * is a member. The group with the specified gid is also * added to the list. Returns the resulting Array of the * gids of all the groups in the supplementary group access list. Not * available on all platforms. * * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27] * Process.initgroups( "mgranger", 30 ) #=> [30, 6, 10, 11] * Process.groups #=> [30, 6, 10, 11] * */ static VALUE proc_initgroups(obj, uname, base_grp) VALUE obj, uname, base_grp; { #ifdef HAVE_INITGROUPS if (initgroups(StringValuePtr(uname), (rb_gid_t)NUM2INT(base_grp)) != 0) { rb_sys_fail(0); } return proc_getgroups(obj); #else rb_notimplement(); return Qnil; #endif } /* * call-seq: * Process.maxgroups => fixnum * * Returns the maximum number of gids allowed in the supplemental * group access list. * * Process.maxgroups #=> 32 */ static VALUE proc_getmaxgroups(obj) VALUE obj; { return INT2FIX(maxgroups); } /* * call-seq: * Process.maxgroups= fixnum => fixnum * * Sets the maximum number of gids allowed in the supplemental group * access list. */ static VALUE proc_setmaxgroups(VALUE obj, VALUE val) { size_t ngroups = FIX2INT(val); if (ngroups > 4096) ngroups = 4096; maxgroups = ngroups; return INT2FIX(maxgroups); } /******************************************************************** * * Document-class: Process::GID * * The Process::GID module contains a collection of * module functions which can be used to portably get, set, and * switch the current process's real, effective, and saved group IDs. * */ static int SAVED_GROUP_ID = -1; #ifdef BROKEN_SETREGID int setregid(rgid, egid) rb_gid_t rgid, egid; { if (rgid != -1 && rgid != getgid()) { if (egid == -1) egid = getegid(); if (setgid(rgid) < 0) return -1; } if (egid != -1 && egid != getegid()) { if (setegid(egid) < 0) return -1; } return 0; } #endif /* * call-seq: * Process::GID.change_privilege(integer) => fixnum * * Change the current process's real and effective group ID to that * specified by _integer_. Returns the new group ID. Not * available on all platforms. * * [Process.gid, Process.egid] #=> [0, 0] * Process::GID.change_privilege(33) #=> 33 * [Process.gid, Process.egid] #=> [33, 33] */ static VALUE p_gid_change_privilege(obj, id) VALUE obj, id; { int gid; check_gid_switch(); gid = NUM2INT(id); if (geteuid() == 0) { /* root-user */ #if defined(HAVE_SETRESGID) if (setresgid(gid, gid, gid) < 0) rb_sys_fail(0); SAVED_GROUP_ID = gid; #elif defined HAVE_SETGID if (setgid(gid) < 0) rb_sys_fail(0); SAVED_GROUP_ID = gid; #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID) if (getgid() == gid) { if (SAVED_GROUP_ID == gid) { if (setregid(-1, gid) < 0) rb_sys_fail(0); } else { if (gid == 0) { /* (r,e,s) == (root, y, x) */ if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0); if (setregid(SAVED_GROUP_ID, 0) < 0) rb_sys_fail(0); SAVED_GROUP_ID = 0; /* (r,e,s) == (x, root, root) */ if (setregid(gid, gid) < 0) rb_sys_fail(0); SAVED_GROUP_ID = gid; } else { /* (r,e,s) == (z, y, x) */ if (setregid(0, 0) < 0) rb_sys_fail(0); SAVED_GROUP_ID = 0; if (setregid(gid, gid) < 0) rb_sys_fail(0); SAVED_GROUP_ID = gid; } } } else { if (setregid(gid, gid) < 0) rb_sys_fail(0); SAVED_GROUP_ID = gid; } #elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID) if (getgid() == gid) { if (SAVED_GROUP_ID == gid) { if (setegid(gid) < 0) rb_sys_fail(0); } else { if (gid == 0) { if (setegid(gid) < 0) rb_sys_fail(0); if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0); SAVED_GROUP_ID = 0; if (setrgid(0) < 0) rb_sys_fail(0); } else { if (setrgid(0) < 0) rb_sys_fail(0); SAVED_GROUP_ID = 0; if (setegid(gid) < 0) rb_sys_fail(0); if (setrgid(gid) < 0) rb_sys_fail(0); SAVED_GROUP_ID = gid; } } } else { if (setegid(gid) < 0) rb_sys_fail(0); if (setrgid(gid) < 0) rb_sys_fail(0); SAVED_GROUP_ID = gid; } #else rb_notimplement(); #endif } else { /* unprivileged user */ #if defined(HAVE_SETRESGID) if (setresgid((getgid() == gid)? -1: gid, (getegid() == gid)? -1: gid, (SAVED_GROUP_ID == gid)? -1: gid) < 0) rb_sys_fail(0); SAVED_GROUP_ID = gid; #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID) if (SAVED_GROUP_ID == gid) { if (setregid((getgid() == gid)? -1: gid, (getegid() == gid)? -1: gid) < 0) rb_sys_fail(0); } else if (getgid() != gid) { if (setregid(gid, (getegid() == gid)? -1: gid) < 0) rb_sys_fail(0); SAVED_GROUP_ID = gid; } else if (/* getgid() == gid && */ getegid() != gid) { if (setregid(getegid(), gid) < 0) rb_sys_fail(0); SAVED_GROUP_ID = gid; if (setregid(gid, -1) < 0) rb_sys_fail(0); } else { /* getgid() == gid && getegid() == gid */ if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0); if (setregid(SAVED_GROUP_ID, gid) < 0) rb_sys_fail(0); SAVED_GROUP_ID = gid; if (setregid(gid, -1) < 0) rb_sys_fail(0); } #elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID) if (SAVED_GROUP_ID == gid) { if (getegid() != gid && setegid(gid) < 0) rb_sys_fail(0); if (getgid() != gid && setrgid(gid) < 0) rb_sys_fail(0); } else if (/* SAVED_GROUP_ID != gid && */ getegid() == gid) { if (getgid() != gid) { if (setrgid(gid) < 0) rb_sys_fail(0); SAVED_GROUP_ID = gid; } else { if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0); SAVED_GROUP_ID = gid; if (setrgid(gid) < 0) rb_sys_fail(0); } } else if (/* getegid() != gid && */ getgid() == gid) { if (setegid(gid) < 0) rb_sys_fail(0); if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0); SAVED_GROUP_ID = gid; if (setrgid(gid) < 0) rb_sys_fail(0); } else { errno = EPERM; rb_sys_fail(0); } #elif defined HAVE_44BSD_SETGID if (getgid() == gid) { /* (r,e,s)==(gid,?,?) ==> (gid,gid,gid) */ if (setgid(gid) < 0) rb_sys_fail(0); SAVED_GROUP_ID = gid; } else { errno = EPERM; rb_sys_fail(0); } #elif defined HAVE_SETEGID if (getgid() == gid && SAVED_GROUP_ID == gid) { if (setegid(gid) < 0) rb_sys_fail(0); } else { errno = EPERM; rb_sys_fail(0); } #elif defined HAVE_SETGID if (getgid() == gid && SAVED_GROUP_ID == gid) { if (setgid(gid) < 0) rb_sys_fail(0); } else { errno = EPERM; rb_sys_fail(0); } #else rb_notimplement(); #endif } return INT2FIX(gid); } /* * call-seq: * Process.euid => fixnum * Process::UID.eid => fixnum * Process::Sys.geteuid => fixnum * * Returns the effective user ID for this process. * * Process.euid #=> 501 */ static VALUE proc_geteuid(obj) VALUE obj; { int euid = geteuid(); return INT2FIX(euid); } /* * call-seq: * Process.euid= integer * * Sets the effective user ID for this process. Not available on all * platforms. */ static VALUE proc_seteuid(obj, euid) VALUE obj, euid; { check_uid_switch(); #if defined(HAVE_SETRESUID) && !defined(__CHECKER__) if (setresuid(-1, NUM2INT(euid), -1) < 0) rb_sys_fail(0); #elif defined HAVE_SETREUID if (setreuid(-1, NUM2INT(euid)) < 0) rb_sys_fail(0); #elif defined HAVE_SETEUID if (seteuid(NUM2INT(euid)) < 0) rb_sys_fail(0); #elif defined HAVE_SETUID euid = NUM2INT(euid); if (euid == getuid()) { if (setuid(euid) < 0) rb_sys_fail(0); } else { rb_notimplement(); } #else rb_notimplement(); #endif return euid; } static VALUE rb_seteuid_core(euid) int euid; { int uid; check_uid_switch(); uid = getuid(); #if defined(HAVE_SETRESUID) && !defined(__CHECKER__) if (uid != euid) { if (setresuid(-1,euid,euid) < 0) rb_sys_fail(0); SAVED_USER_ID = euid; } else { if (setresuid(-1,euid,-1) < 0) rb_sys_fail(0); } #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID) if (setreuid(-1, euid) < 0) rb_sys_fail(0); if (uid != euid) { if (setreuid(euid,uid) < 0) rb_sys_fail(0); if (setreuid(uid,euid) < 0) rb_sys_fail(0); SAVED_USER_ID = euid; } #elif defined HAVE_SETEUID if (seteuid(euid) < 0) rb_sys_fail(0); #elif defined HAVE_SETUID if (geteuid() == 0) rb_sys_fail(0); if (setuid(euid) < 0) rb_sys_fail(0); #else rb_notimplement(); #endif return INT2FIX(euid); } /* * call-seq: * Process::UID.grant_privilege(integer) => fixnum * Process::UID.eid= integer => fixnum * * Set the effective user ID, and if possible, the saved user ID of * the process to the given _integer_. Returns the new * effective user ID. Not available on all platforms. * * [Process.uid, Process.euid] #=> [0, 0] * Process::UID.grant_privilege(31) #=> 31 * [Process.uid, Process.euid] #=> [0, 31] */ static VALUE p_uid_grant_privilege(obj, id) VALUE obj, id; { return rb_seteuid_core(NUM2INT(id)); } /* * call-seq: * Process.egid => fixnum * Process::GID.eid => fixnum * Process::Sys.geteid => fixnum * * Returns the effective group ID for this process. Not available on * all platforms. * * Process.egid #=> 500 */ static VALUE proc_getegid(obj) VALUE obj; { int egid = getegid(); return INT2FIX(egid); } /* * call-seq: * Process.egid = fixnum => fixnum * * Sets the effective group ID for this process. Not available on all * platforms. */ static VALUE proc_setegid(obj, egid) VALUE obj, egid; { check_gid_switch(); #if defined(HAVE_SETRESGID) && !defined(__CHECKER__) if (setresgid(-1, NUM2INT(egid), -1) < 0) rb_sys_fail(0); #elif defined HAVE_SETREGID if (setregid(-1, NUM2INT(egid)) < 0) rb_sys_fail(0); #elif defined HAVE_SETEGID if (setegid(NUM2INT(egid)) < 0) rb_sys_fail(0); #elif defined HAVE_SETGID egid = NUM2INT(egid); if (egid == getgid()) { if (setgid(egid) < 0) rb_sys_fail(0); } else { rb_notimplement(); } #else rb_notimplement(); #endif return egid; } static VALUE rb_setegid_core(egid) int egid; { int gid; check_gid_switch(); gid = getgid(); #if defined(HAVE_SETRESGID) && !defined(__CHECKER__) if (gid != egid) { if (setresgid(-1,egid,egid) < 0) rb_sys_fail(0); SAVED_GROUP_ID = egid; } else { if (setresgid(-1,egid,-1) < 0) rb_sys_fail(0); } #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID) if (setregid(-1, egid) < 0) rb_sys_fail(0); if (gid != egid) { if (setregid(egid,gid) < 0) rb_sys_fail(0); if (setregid(gid,egid) < 0) rb_sys_fail(0); SAVED_GROUP_ID = egid; } #elif defined HAVE_SETEGID if (setegid(egid) < 0) rb_sys_fail(0); #elif defined HAVE_SETGID if (geteuid() == 0 /* root user */) rb_sys_fail(0); if (setgid(egid) < 0) rb_sys_fail(0); #else rb_notimplement(); #endif return INT2FIX(egid); } /* * call-seq: * Process::GID.grant_privilege(integer) => fixnum * Process::GID.eid = integer => fixnum * * Set the effective group ID, and if possible, the saved group ID of * the process to the given _integer_. Returns the new * effective group ID. Not available on all platforms. * * [Process.gid, Process.egid] #=> [0, 0] * Process::GID.grant_privilege(31) #=> 33 * [Process.gid, Process.egid] #=> [0, 33] */ static VALUE p_gid_grant_privilege(obj, id) VALUE obj, id; { return rb_setegid_core(NUM2INT(id)); } /* * call-seq: * Process::UID.re_exchangeable? => true or false * * Returns +true+ if the real and effective user IDs of a * process may be exchanged on the current platform. * */ static VALUE p_uid_exchangeable() { #if defined(HAVE_SETRESUID) && !defined(__CHECKER__) return Qtrue; #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID) return Qtrue; #else return Qfalse; #endif } /* * call-seq: * Process::UID.re_exchange => fixnum * * Exchange real and effective user IDs and return the new effective * user ID. Not available on all platforms. * * [Process.uid, Process.euid] #=> [0, 31] * Process::UID.re_exchange #=> 0 * [Process.uid, Process.euid] #=> [31, 0] */ static VALUE p_uid_exchange(obj) VALUE obj; { int uid, euid; check_uid_switch(); uid = getuid(); euid = geteuid(); #if defined(HAVE_SETRESUID) && !defined(__CHECKER__) if (setresuid(euid, uid, uid) < 0) rb_sys_fail(0); SAVED_USER_ID = uid; #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID) if (setreuid(euid,uid) < 0) rb_sys_fail(0); SAVED_USER_ID = uid; #else rb_notimplement(); #endif return INT2FIX(uid); } /* * call-seq: * Process::GID.re_exchangeable? => true or false * * Returns +true+ if the real and effective group IDs of a * process may be exchanged on the current platform. * */ static VALUE p_gid_exchangeable() { #if defined(HAVE_SETRESGID) && !defined(__CHECKER__) return Qtrue; #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID) return Qtrue; #else return Qfalse; #endif } /* * call-seq: * Process::GID.re_exchange => fixnum * * Exchange real and effective group IDs and return the new effective * group ID. Not available on all platforms. * * [Process.gid, Process.egid] #=> [0, 33] * Process::GID.re_exchange #=> 0 * [Process.gid, Process.egid] #=> [33, 0] */ static VALUE p_gid_exchange(obj) VALUE obj; { int gid, egid; check_gid_switch(); gid = getgid(); egid = getegid(); #if defined(HAVE_SETRESGID) && !defined(__CHECKER__) if (setresgid(egid, gid, gid) < 0) rb_sys_fail(0); SAVED_GROUP_ID = gid; #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID) if (setregid(egid,gid) < 0) rb_sys_fail(0); SAVED_GROUP_ID = gid; #else rb_notimplement(); #endif return INT2FIX(gid); } /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */ /* * call-seq: * Process::UID.sid_available? => true or false * * Returns +true+ if the current platform has saved user * ID functionality. * */ static VALUE p_uid_have_saved_id() { #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS) return Qtrue; #else return Qfalse; #endif } #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS) static VALUE p_uid_sw_ensure(id) int id; { under_uid_switch = 0; return rb_seteuid_core(id); } /* * call-seq: * Process::UID.switch => fixnum * Process::UID.switch {|| block} => object * * Switch the effective and real user IDs of the current process. If * a block is given, the user IDs will be switched back * after the block is executed. Returns the new effective user ID if * called without a block, and the return value of the block if one * is given. * */ static VALUE p_uid_switch(obj) VALUE obj; { int uid, euid; check_uid_switch(); uid = getuid(); euid = geteuid(); if (uid != euid) { proc_seteuid(obj, INT2FIX(uid)); if (rb_block_given_p()) { under_uid_switch = 1; return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, SAVED_USER_ID); } else { return INT2FIX(euid); } } else if (euid != SAVED_USER_ID) { proc_seteuid(obj, INT2FIX(SAVED_USER_ID)); if (rb_block_given_p()) { under_uid_switch = 1; return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, euid); } else { return INT2FIX(uid); } } else { errno = EPERM; rb_sys_fail(0); } #else static VALUE p_uid_sw_ensure(obj) VALUE obj; { under_uid_switch = 0; return p_uid_exchange(obj); } static VALUE p_uid_switch(obj) VALUE obj; { int uid, euid; check_uid_switch(); uid = getuid(); euid = geteuid(); if (uid == euid) { errno = EPERM; rb_sys_fail(0); } p_uid_exchange(obj); if (rb_block_given_p()) { under_uid_switch = 1; return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, obj); } else { return INT2FIX(euid); } #endif } /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */ /* * call-seq: * Process::GID.sid_available? => true or false * * Returns +true+ if the current platform has saved group * ID functionality. * */ static VALUE p_gid_have_saved_id() { #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS) return Qtrue; #else return Qfalse; #endif } #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS) static VALUE p_gid_sw_ensure(id) int id; { under_gid_switch = 0; return rb_setegid_core(id); } /* * call-seq: * Process::GID.switch => fixnum * Process::GID.switch {|| block} => object * * Switch the effective and real group IDs of the current process. If * a block is given, the group IDs will be switched back * after the block is executed. Returns the new effective group ID if * called without a block, and the return value of the block if one * is given. * */ static VALUE p_gid_switch(obj) VALUE obj; { int gid, egid; check_gid_switch(); gid = getgid(); egid = getegid(); if (gid != egid) { proc_setegid(obj, INT2FIX(gid)); if (rb_block_given_p()) { under_gid_switch = 1; return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, SAVED_GROUP_ID); } else { return INT2FIX(egid); } } else if (egid != SAVED_GROUP_ID) { proc_setegid(obj, INT2FIX(SAVED_GROUP_ID)); if (rb_block_given_p()) { under_gid_switch = 1; return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, egid); } else { return INT2FIX(gid); } } else { errno = EPERM; rb_sys_fail(0); } #else static VALUE p_gid_sw_ensure(obj) VALUE obj; { under_gid_switch = 0; return p_gid_exchange(obj); } static VALUE p_gid_switch(obj) VALUE obj; { int gid, egid; check_gid_switch(); gid = getgid(); egid = getegid(); if (gid == egid) { errno = EPERM; rb_sys_fail(0); } p_gid_exchange(obj); if (rb_block_given_p()) { under_gid_switch = 1; return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, obj); } else { return INT2FIX(egid); } #endif } /* * call-seq: * Process.times => aStructTms * * Returns a Tms structure (see Struct::Tms * on page 388) that contains user and system CPU times for this * process. * * t = Process.times * [ t.utime, t.stime ] #=> [0.0, 0.02] */ VALUE rb_proc_times(obj) VALUE obj; { #if defined(HAVE_TIMES) && !defined(__CHECKER__) const double hertz = #ifdef HAVE__SC_CLK_TCK (double)sysconf(_SC_CLK_TCK); #else #ifndef HZ # ifdef CLK_TCK # define HZ CLK_TCK # else # define HZ 60 # endif #endif /* HZ */ HZ; #endif struct tms buf; volatile VALUE utime, stime, cutime, sctime; times(&buf); return rb_struct_new(S_Tms, utime = rb_float_new(buf.tms_utime / hertz), stime = rb_float_new(buf.tms_stime / hertz), cutime = rb_float_new(buf.tms_cutime / hertz), sctime = rb_float_new(buf.tms_cstime / hertz)); #else rb_notimplement(); #endif } VALUE rb_mProcess; VALUE rb_mProcUID; VALUE rb_mProcGID; VALUE rb_mProcID_Syscall; /* * The Process module is a collection of methods used to * manipulate processes. */ void Init_process() { rb_define_virtual_variable("$$", get_pid, 0); rb_define_readonly_variable("$?", &rb_last_status); rb_define_global_function("exec", rb_f_exec, -1); rb_define_global_function("fork", rb_f_fork, 0); rb_define_global_function("exit!", rb_f_exit_bang, -1); rb_define_global_function("system", rb_f_system, -1); rb_define_global_function("sleep", rb_f_sleep, -1); rb_mProcess = rb_define_module("Process"); #if !defined(_WIN32) && !defined(DJGPP) #ifdef WNOHANG rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(WNOHANG)); #else rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(0)); #endif #ifdef WUNTRACED rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(WUNTRACED)); #else rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(0)); #endif #endif rb_define_singleton_method(rb_mProcess, "exec", rb_f_exec, -1); rb_define_singleton_method(rb_mProcess, "fork", rb_f_fork, 0); rb_define_singleton_method(rb_mProcess, "exit!", rb_f_exit_bang, -1); rb_define_singleton_method(rb_mProcess, "exit", rb_f_exit, -1); /* in eval.c */ rb_define_singleton_method(rb_mProcess, "abort", rb_f_abort, -1); /* in eval.c */ rb_define_module_function(rb_mProcess, "kill", rb_f_kill, -1); /* in signal.c */ rb_define_module_function(rb_mProcess, "wait", proc_wait, -1); rb_define_module_function(rb_mProcess, "wait2", proc_wait2, -1); rb_define_module_function(rb_mProcess, "waitpid", proc_wait, -1); rb_define_module_function(rb_mProcess, "waitpid2", proc_wait2, -1); rb_define_module_function(rb_mProcess, "waitall", proc_waitall, 0); rb_define_module_function(rb_mProcess, "detach", proc_detach, 1); rb_cProcStatus = rb_define_class_under(rb_mProcess, "Status", rb_cObject); rb_undef_method(CLASS_OF(rb_cProcStatus), "new"); rb_define_method(rb_cProcStatus, "==", pst_equal, 1); rb_define_method(rb_cProcStatus, "&", pst_bitand, 1); rb_define_method(rb_cProcStatus, ">>", pst_rshift, 1); rb_define_method(rb_cProcStatus, "to_i", pst_to_i, 0); rb_define_method(rb_cProcStatus, "to_int", pst_to_i, 0); rb_define_method(rb_cProcStatus, "to_s", pst_to_s, 0); rb_define_method(rb_cProcStatus, "inspect", pst_inspect, 0); rb_define_method(rb_cProcStatus, "pid", pst_pid, 0); rb_define_method(rb_cProcStatus, "stopped?", pst_wifstopped, 0); rb_define_method(rb_cProcStatus, "stopsig", pst_wstopsig, 0); rb_define_method(rb_cProcStatus, "signaled?", pst_wifsignaled, 0); rb_define_method(rb_cProcStatus, "termsig", pst_wtermsig, 0); rb_define_method(rb_cProcStatus, "exited?", pst_wifexited, 0); rb_define_method(rb_cProcStatus, "exitstatus", pst_wexitstatus, 0); rb_define_method(rb_cProcStatus, "success?", pst_success_p, 0); rb_define_method(rb_cProcStatus, "coredump?", pst_wcoredump, 0); rb_define_module_function(rb_mProcess, "pid", get_pid, 0); rb_define_module_function(rb_mProcess, "ppid", get_ppid, 0); rb_define_module_function(rb_mProcess, "getpgrp", proc_getpgrp, 0); rb_define_module_function(rb_mProcess, "setpgrp", proc_setpgrp, 0); rb_define_module_function(rb_mProcess, "getpgid", proc_getpgid, 1); rb_define_module_function(rb_mProcess, "setpgid", proc_setpgid, 2); rb_define_module_function(rb_mProcess, "setsid", proc_setsid, 0); rb_define_module_function(rb_mProcess, "getpriority", proc_getpriority, 2); rb_define_module_function(rb_mProcess, "setpriority", proc_setpriority, 3); #ifdef HAVE_GETPRIORITY rb_define_const(rb_mProcess, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS)); rb_define_const(rb_mProcess, "PRIO_PGRP", INT2FIX(PRIO_PGRP)); rb_define_const(rb_mProcess, "PRIO_USER", INT2FIX(PRIO_USER)); #endif rb_define_module_function(rb_mProcess, "getrlimit", proc_getrlimit, 1); rb_define_module_function(rb_mProcess, "setrlimit", proc_setrlimit, -1); #ifdef RLIM2NUM { VALUE inf = RLIM2NUM(RLIM_INFINITY), v; rb_define_const(rb_mProcess, "RLIM_INFINITY", inf); #ifdef RLIM_SAVED_MAX v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf : RLIM2NUM(RLIM_SAVED_MAX); rb_define_const(rb_mProcess, "RLIM_SAVED_MAX", v); #endif #ifdef RLIM_SAVED_CUR v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf : RLIM2NUM(RLIM_SAVED_CUR); rb_define_const(rb_mProcess, "RLIM_SAVED_CUR", v); #endif } #ifdef RLIMIT_CORE rb_define_const(rb_mProcess, "RLIMIT_CORE", INT2FIX(RLIMIT_CORE)); #endif #ifdef RLIMIT_CPU rb_define_const(rb_mProcess, "RLIMIT_CPU", INT2FIX(RLIMIT_CPU)); #endif #ifdef RLIMIT_DATA rb_define_const(rb_mProcess, "RLIMIT_DATA", INT2FIX(RLIMIT_DATA)); #endif #ifdef RLIMIT_FSIZE rb_define_const(rb_mProcess, "RLIMIT_FSIZE", INT2FIX(RLIMIT_FSIZE)); #endif #ifdef RLIMIT_NOFILE rb_define_const(rb_mProcess, "RLIMIT_NOFILE", INT2FIX(RLIMIT_NOFILE)); #endif #ifdef RLIMIT_STACK rb_define_const(rb_mProcess, "RLIMIT_STACK", INT2FIX(RLIMIT_STACK)); #endif #ifdef RLIMIT_AS rb_define_const(rb_mProcess, "RLIMIT_AS", INT2FIX(RLIMIT_AS)); #endif #ifdef RLIMIT_MEMLOCK rb_define_const(rb_mProcess, "RLIMIT_MEMLOCK", INT2FIX(RLIMIT_MEMLOCK)); #endif #ifdef RLIMIT_NPROC rb_define_const(rb_mProcess, "RLIMIT_NPROC", INT2FIX(RLIMIT_NPROC)); #endif #ifdef RLIMIT_RSS rb_define_const(rb_mProcess, "RLIMIT_RSS", INT2FIX(RLIMIT_RSS)); #endif #ifdef RLIMIT_SBSIZE rb_define_const(rb_mProcess, "RLIMIT_SBSIZE", INT2FIX(RLIMIT_SBSIZE)); #endif #endif rb_define_module_function(rb_mProcess, "uid", proc_getuid, 0); rb_define_module_function(rb_mProcess, "uid=", proc_setuid, 1); rb_define_module_function(rb_mProcess, "gid", proc_getgid, 0); rb_define_module_function(rb_mProcess, "gid=", proc_setgid, 1); rb_define_module_function(rb_mProcess, "euid", proc_geteuid, 0); rb_define_module_function(rb_mProcess, "euid=", proc_seteuid, 1); rb_define_module_function(rb_mProcess, "egid", proc_getegid, 0); rb_define_module_function(rb_mProcess, "egid=", proc_setegid, 1); rb_define_module_function(rb_mProcess, "initgroups", proc_initgroups, 2); rb_define_module_function(rb_mProcess, "groups", proc_getgroups, 0); rb_define_module_function(rb_mProcess, "groups=", proc_setgroups, 1); rb_define_module_function(rb_mProcess, "maxgroups", proc_getmaxgroups, 0); rb_define_module_function(rb_mProcess, "maxgroups=", proc_setmaxgroups, 1); rb_define_module_function(rb_mProcess, "times", rb_proc_times, 0); #if defined(HAVE_TIMES) || defined(_WIN32) S_Tms = rb_struct_define("Tms", "utime", "stime", "cutime", "cstime", NULL); #endif SAVED_USER_ID = geteuid(); SAVED_GROUP_ID = getegid(); rb_mProcUID = rb_define_module_under(rb_mProcess, "UID"); rb_mProcGID = rb_define_module_under(rb_mProcess, "GID"); rb_define_module_function(rb_mProcUID, "rid", proc_getuid, 0); rb_define_module_function(rb_mProcGID, "rid", proc_getgid, 0); rb_define_module_function(rb_mProcUID, "eid", proc_geteuid, 0); rb_define_module_function(rb_mProcGID, "eid", proc_getegid, 0); rb_define_module_function(rb_mProcUID, "change_privilege", p_uid_change_privilege, 1); rb_define_module_function(rb_mProcGID, "change_privilege", p_gid_change_privilege, 1); rb_define_module_function(rb_mProcUID, "grant_privilege", p_uid_grant_privilege, 1); rb_define_module_function(rb_mProcGID, "grant_privilege", p_gid_grant_privilege, 1); rb_define_alias(rb_singleton_class(rb_mProcUID), "eid=", "grant_privilege"); rb_define_alias(rb_singleton_class(rb_mProcGID), "eid=", "grant_privilege"); rb_define_module_function(rb_mProcUID, "re_exchange", p_uid_exchange, 0); rb_define_module_function(rb_mProcGID, "re_exchange", p_gid_exchange, 0); rb_define_module_function(rb_mProcUID, "re_exchangeable?", p_uid_exchangeable, 0); rb_define_module_function(rb_mProcGID, "re_exchangeable?", p_gid_exchangeable, 0); rb_define_module_function(rb_mProcUID, "sid_available?", p_uid_have_saved_id, 0); rb_define_module_function(rb_mProcGID, "sid_available?", p_gid_have_saved_id, 0); rb_define_module_function(rb_mProcUID, "switch", p_uid_switch, 0); rb_define_module_function(rb_mProcGID, "switch", p_gid_switch, 0); rb_mProcID_Syscall = rb_define_module_under(rb_mProcess, "Sys"); rb_define_module_function(rb_mProcID_Syscall, "getuid", proc_getuid, 0); rb_define_module_function(rb_mProcID_Syscall, "geteuid", proc_geteuid, 0); rb_define_module_function(rb_mProcID_Syscall, "getgid", proc_getgid, 0); rb_define_module_function(rb_mProcID_Syscall, "getegid", proc_getegid, 0); rb_define_module_function(rb_mProcID_Syscall, "setuid", p_sys_setuid, 1); rb_define_module_function(rb_mProcID_Syscall, "setgid", p_sys_setgid, 1); rb_define_module_function(rb_mProcID_Syscall, "setruid", p_sys_setruid, 1); rb_define_module_function(rb_mProcID_Syscall, "setrgid", p_sys_setrgid, 1); rb_define_module_function(rb_mProcID_Syscall, "seteuid", p_sys_seteuid, 1); rb_define_module_function(rb_mProcID_Syscall, "setegid", p_sys_setegid, 1); rb_define_module_function(rb_mProcID_Syscall, "setreuid", p_sys_setreuid, 2); rb_define_module_function(rb_mProcID_Syscall, "setregid", p_sys_setregid, 2); rb_define_module_function(rb_mProcID_Syscall, "setresuid", p_sys_setresuid, 3); rb_define_module_function(rb_mProcID_Syscall, "setresgid", p_sys_setresgid, 3); rb_define_module_function(rb_mProcID_Syscall, "issetugid", p_sys_issetugid, 0); } ================================================ FILE: random.c ================================================ /********************************************************************** random.c - $Author$ $Date$ created at: Fri Dec 24 16:39:21 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ /* This is based on trimmed version of MT19937. To get the original version, contact . The original copyright notice follows. A C-program for MT19937, with initialization improved 2002/2/10. Coded by Takuji Nishimura and Makoto Matsumoto. This is a faster version by taking Shawn Cokus's optimization, Matthe Bellew's simplification, Isaku Wada's real version. Before using, initialize the state by using init_genrand(seed) or init_by_array(init_key, key_length). Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Any feedback is very welcome. http://www.math.keio.ac.jp/matumoto/emt.html email: matumoto@math.keio.ac.jp */ /* Period parameters */ #define N 624 #define M 397 #define MATRIX_A 0x9908b0dfUL /* constant vector a */ #define UMASK 0x80000000UL /* most significant w-r bits */ #define LMASK 0x7fffffffUL /* least significant r bits */ #define MIXBITS(u,v) ( ((u) & UMASK) | ((v) & LMASK) ) #define TWIST(u,v) ((MIXBITS(u,v) >> 1) ^ ((v)&1UL ? MATRIX_A : 0UL)) static unsigned long state[N]; /* the array for the state vector */ static int left = 1; static int initf = 0; static unsigned long *next; /* initializes state[N] with a seed */ static void init_genrand(s) unsigned long s; { int j; state[0]= s & 0xffffffffUL; for (j=1; j> 30)) + j); /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ /* In the previous versions, MSBs of the seed affect */ /* only MSBs of the array state[]. */ /* 2002/01/09 modified by Makoto Matsumoto */ state[j] &= 0xffffffffUL; /* for >32 bit machines */ } left = 1; initf = 1; } /* initialize by an array with array-length */ /* init_key is the array for initializing keys */ /* key_length is its length */ /* slight change for C++, 2004/2/26 */ static void init_by_array(unsigned long init_key[], int key_length) { int i, j, k; init_genrand(19650218UL); i=1; j=0; k = (N>key_length ? N : key_length); for (; k; k--) { state[i] = (state[i] ^ ((state[i-1] ^ (state[i-1] >> 30)) * 1664525UL)) + init_key[j] + j; /* non linear */ state[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ i++; j++; if (i>=N) { state[0] = state[N-1]; i=1; } if (j>=key_length) j=0; } for (k=N-1; k; k--) { state[i] = (state[i] ^ ((state[i-1] ^ (state[i-1] >> 30)) * 1566083941UL)) - i; /* non linear */ state[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ i++; if (i>=N) { state[0] = state[N-1]; i=1; } } state[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ left = 1; initf = 1; } static void next_state() { unsigned long *p=state; int j; /* if init_genrand() has not been called, */ /* a default initial seed is used */ if (initf==0) init_genrand(5489UL); left = N; next = state; for (j=N-M+1; --j; p++) *p = p[M] ^ TWIST(p[0], p[1]); for (j=M; --j; p++) *p = p[M-N] ^ TWIST(p[0], p[1]); *p = p[M-N] ^ TWIST(p[0], state[0]); } /* generates a random number on [0,0xffffffff]-interval */ unsigned long rb_genrand_int32(void) { unsigned long y; if (--left == 0) next_state(); y = *next++; /* Tempering */ y ^= (y >> 11); y ^= (y << 7) & 0x9d2c5680UL; y ^= (y << 15) & 0xefc60000UL; y ^= (y >> 18); return y; } /* generates a random number on [0,1) with 53-bit resolution*/ double rb_genrand_real(void) { unsigned long a=rb_genrand_int32()>>5, b=rb_genrand_int32()>>6; return(a*67108864.0+b)*(1.0/9007199254740992.0); } /* These real versions are due to Isaku Wada, 2002/01/09 added */ #undef N #undef M /* These real versions are due to Isaku Wada, 2002/01/09 added */ #include "ruby.h" #ifdef HAVE_UNISTD_H #include #endif #include #include #include #ifdef HAVE_FCNTL_H #include #endif static VALUE saved_seed = INT2FIX(0); static VALUE rand_init(vseed) VALUE vseed; { volatile VALUE seed; VALUE old; long len; unsigned long *buf; seed = rb_to_int(vseed); switch (TYPE(seed)) { case T_FIXNUM: len = sizeof(VALUE); break; case T_BIGNUM: len = RBIGNUM(seed)->len * SIZEOF_BDIGITS; if (len == 0) len = 4; break; default: rb_raise(rb_eTypeError, "failed to convert %s into Integer", rb_obj_classname(vseed)); } len = (len + 3) / 4; /* number of 32bit words */ buf = ALLOC_N(unsigned long, len); /* allocate longs for init_by_array */ memset(buf, 0, len * sizeof(long)); if (FIXNUM_P(seed)) { buf[0] = FIX2ULONG(seed) & 0xffffffff; #if SIZEOF_LONG > 4 buf[1] = FIX2ULONG(seed) >> 32; #endif } else { int i, j; for (i = RBIGNUM(seed)->len-1; 0 <= i; i--) { j = i * SIZEOF_BDIGITS / 4; #if SIZEOF_BDIGITS < 4 buf[j] <<= SIZEOF_BDIGITS * 8; #endif buf[j] |= ((BDIGIT *)RBIGNUM(seed)->digits)[i]; } } while (1 < len && buf[len-1] == 0) { len--; } if (len <= 1) { init_genrand(buf[0]); } else { if (buf[len-1] == 1) /* remove leading-zero-guard */ len--; init_by_array(buf, len); } old = saved_seed; saved_seed = seed; free(buf); return old; } static VALUE random_seed() { static int n = 0; struct timeval tv; int fd; struct stat statbuf; int seed_len; BDIGIT *digits; unsigned long *seed; NEWOBJ(big, struct RBignum); OBJSETUP(big, rb_cBignum, T_BIGNUM); seed_len = 4 * sizeof(long); big->sign = 1; big->len = seed_len / SIZEOF_BDIGITS + 1; digits = big->digits = ALLOC_N(BDIGIT, big->len); seed = (unsigned long *)big->digits; memset(digits, 0, big->len * SIZEOF_BDIGITS); #ifdef S_ISCHR if ((fd = open("/dev/urandom", O_RDONLY #ifdef O_NONBLOCK |O_NONBLOCK #endif #ifdef O_NOCTTY |O_NOCTTY #endif #ifdef O_NOFOLLOW |O_NOFOLLOW #endif )) >= 0) { if (fstat(fd, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)) { read(fd, seed, seed_len); } close(fd); } #endif gettimeofday(&tv, 0); seed[0] ^= tv.tv_usec; seed[1] ^= tv.tv_sec; seed[2] ^= getpid() ^ (n++ << 16); seed[3] ^= (unsigned long)&seed; /* set leading-zero-guard if need. */ digits[big->len-1] = digits[big->len-2] <= 1 ? 1 : 0; return rb_big_norm((VALUE)big); } /* * call-seq: * srand(number=0) => old_seed * * Seeds the pseudorandom number generator to the value of * number.to_i.abs. If number is omitted, * seeds the generator using a combination of the time, the * process id, and a sequence number. (This is also the behavior if * Kernel::rand is called without previously calling * srand, but without the sequence.) By setting the seed * to a known value, scripts can be made deterministic during testing. * The previous seed value is returned. Also see Kernel::rand. */ static VALUE rb_f_srand(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE seed, old; rb_secure(4); if (rb_scan_args(argc, argv, "01", &seed) == 0) { seed = random_seed(); } old = rand_init(seed); return old; } static unsigned long make_mask(unsigned long x) { x = x | x >> 1; x = x | x >> 2; x = x | x >> 4; x = x | x >> 8; x = x | x >> 16; #if 4 < SIZEOF_LONG x = x | x >> 32; #endif return x; } static unsigned long limited_rand(unsigned long limit) { unsigned long mask = make_mask(limit); int i; unsigned long val; retry: val = 0; for (i = SIZEOF_LONG/4-1; 0 <= i; i--) { if (mask >> (i * 32)) { val |= rb_genrand_int32() << (i * 32); val &= mask; if (limit < val) goto retry; } } return val; } static VALUE limited_big_rand(struct RBignum *limit) { unsigned long mask, lim, rnd; struct RBignum *val; int i, len, boundary; len = (limit->len * SIZEOF_BDIGITS + 3) / 4; val = (struct RBignum *)rb_big_clone((VALUE)limit); val->sign = 1; #if SIZEOF_BDIGITS == 2 # define BIG_GET32(big,i) (((BDIGIT *)(big)->digits)[(i)*2] | \ ((i)*2+1 < (big)->len ? (((BDIGIT *)(big)->digits)[(i)*2+1] << 16) \ : 0)) # define BIG_SET32(big,i,d) ((((BDIGIT *)(big)->digits)[(i)*2] = (d) & 0xffff), \ ((i)*2+1 < (big)->len ? (((BDIGIT *)(big)->digits)[(i)*2+1] = (d) >> 16) \ : 0)) #else /* SIZEOF_BDIGITS == 4 */ # define BIG_GET32(big,i) (((BDIGIT *)(big)->digits)[i]) # define BIG_SET32(big,i,d) (((BDIGIT *)(big)->digits)[i] = (d)) #endif retry: mask = 0; boundary = 1; for (i = len-1; 0 <= i; i--) { lim = BIG_GET32(limit, i); mask = mask ? 0xffffffff : make_mask(lim); if (mask) { rnd = rb_genrand_int32() & mask; if (boundary) { if (lim < rnd) goto retry; if (rnd < lim) boundary = 0; } } else { rnd = 0; } BIG_SET32(val, i, rnd); } return rb_big_norm((VALUE)val); } /* * call-seq: * rand(max=0) => number * * Converts max to an integer using max1 = * max.to_i.abs. If the result is zero, returns a * pseudorandom floating point number greater than or equal to 0.0 and * less than 1.0. Otherwise, returns a pseudorandom integer greater * than or equal to zero and less than max1. Kernel::srand * may be used to ensure repeatable sequences of random numbers between * different runs of the program. Ruby currently uses a modified * Mersenne Twister with a period of 2**19937-1. * * srand 1234 #=> 0 * [ rand, rand ] #=> [0.191519450163469, 0.49766366626136] * [ rand(10), rand(1000) ] #=> [6, 817] * srand 1234 #=> 1234 * [ rand, rand ] #=> [0.191519450163469, 0.49766366626136] */ static VALUE rb_f_rand(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE vmax; long val, max; rb_scan_args(argc, argv, "01", &vmax); switch (TYPE(vmax)) { case T_FLOAT: if (RFLOAT(vmax)->value <= LONG_MAX && RFLOAT(vmax)->value >= LONG_MIN) { max = (long)RFLOAT(vmax)->value; break; } if (RFLOAT(vmax)->value < 0) vmax = rb_dbl2big(-RFLOAT(vmax)->value); else vmax = rb_dbl2big(RFLOAT(vmax)->value); /* fall through */ case T_BIGNUM: bignum: { struct RBignum *limit = (struct RBignum *)vmax; if (!limit->sign) { limit = (struct RBignum *)rb_big_clone(vmax); limit->sign = 1; } limit = (struct RBignum *)rb_big_minus((VALUE)limit, INT2FIX(1)); if (FIXNUM_P((VALUE)limit)) { if (FIX2LONG((VALUE)limit) == -1) return rb_float_new(rb_genrand_real()); return LONG2NUM(limited_rand(FIX2LONG((VALUE)limit))); } return limited_big_rand(limit); } case T_NIL: max = 0; break; default: vmax = rb_Integer(vmax); if (TYPE(vmax) == T_BIGNUM) goto bignum; /* fall through */ case T_FIXNUM: max = FIX2LONG(vmax); break; } if (max == 0) { return rb_float_new(rb_genrand_real()); } if (max < 0) max = -max; val = limited_rand(max-1); return LONG2NUM(val); } void Init_Random() { rand_init(random_seed()); rb_define_global_function("srand", rb_f_srand, -1); rb_define_global_function("rand", rb_f_rand, -1); rb_global_variable(&saved_seed); } ================================================ FILE: range.c ================================================ /********************************************************************** range.c - $Author$ $Date$ created at: Thu Aug 19 17:46:47 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #include "ruby.h" VALUE rb_cRange; static ID id_cmp, id_succ, id_beg, id_end, id_excl; #define EXCL(r) RTEST(rb_ivar_get((r), id_excl)) #define SET_EXCL(r,v) rb_ivar_set((r), id_excl, (v) ? Qtrue : Qfalse) static VALUE range_failed() { rb_raise(rb_eArgError, "bad value for range"); return Qnil; /* dummy */ } static VALUE range_check(args) VALUE *args; { return rb_funcall(args[0], id_cmp, 1, args[1]); } static void range_init(range, beg, end, exclude_end) VALUE range, beg, end; int exclude_end; { VALUE args[2]; args[0] = beg; args[1] = end; if (!FIXNUM_P(beg) || !FIXNUM_P(end)) { VALUE v; v = rb_rescue(range_check, (VALUE)args, range_failed, 0); if (NIL_P(v)) range_failed(); } SET_EXCL(range, exclude_end); rb_ivar_set(range, id_beg, beg); rb_ivar_set(range, id_end, end); } VALUE rb_range_new(beg, end, exclude_end) VALUE beg, end; int exclude_end; { VALUE range = rb_obj_alloc(rb_cRange); range_init(range, beg, end, exclude_end); return range; } /* * call-seq: * Range.new(start, end, exclusive=false) => range * * Constructs a range using the given start and end. If the third * parameter is omitted or is false, the range will include * the end object; otherwise, it will be excluded. */ static VALUE range_initialize(argc, argv, range) int argc; VALUE *argv; VALUE range; { VALUE beg, end, flags; rb_scan_args(argc, argv, "21", &beg, &end, &flags); /* Ranges are immutable, so that they should be initialized only once. */ if (rb_ivar_defined(range, id_beg)) { rb_name_error(rb_intern("initialize"), "`initialize' called twice"); } range_init(range, beg, end, RTEST(flags)); return Qnil; } /* * call-seq: * rng.exclude_end? => true or false * * Returns true if rng excludes its end value. */ static VALUE range_exclude_end_p(range) VALUE range; { return EXCL(range) ? Qtrue : Qfalse; } /* * call-seq: * rng == obj => true or false * * Returns true only if obj is a Range, has equivalent * beginning and end items (by comparing them with ==), and has * the same #exclude_end? setting as rng. * * (0..2) == (0..2) #=> true * (0..2) == Range.new(0,2) #=> true * (0..2) == (0...2) #=> false * */ static VALUE range_eq(range, obj) VALUE range, obj; { if (range == obj) return Qtrue; if (!rb_obj_is_instance_of(obj, rb_obj_class(range))) return Qfalse; if (!rb_equal(rb_ivar_get(range, id_beg), rb_ivar_get(obj, id_beg))) return Qfalse; if (!rb_equal(rb_ivar_get(range, id_end), rb_ivar_get(obj, id_end))) return Qfalse; if (EXCL(range) != EXCL(obj)) return Qfalse; return Qtrue; } static int r_lt(a, b) VALUE a, b; { VALUE r = rb_funcall(a, id_cmp, 1, b); if (NIL_P(r)) return Qfalse; if (rb_cmpint(r, a, b) < 0) return Qtrue; return Qfalse; } static int r_le(a, b) VALUE a, b; { int c; VALUE r = rb_funcall(a, id_cmp, 1, b); if (NIL_P(r)) return Qfalse; c = rb_cmpint(r, a, b); if (c == 0) return INT2FIX(0); if (c < 0) return Qtrue; return Qfalse; } /* * call-seq: * rng.eql?(obj) => true or false * * Returns true only if obj is a Range, has equivalent * beginning and end items (by comparing them with #eql?), and has the same * #exclude_end? setting as rng. * * (0..2) == (0..2) #=> true * (0..2) == Range.new(0,2) #=> true * (0..2) == (0...2) #=> false * */ static VALUE range_eql(range, obj) VALUE range, obj; { if (range == obj) return Qtrue; if (!rb_obj_is_instance_of(obj, rb_obj_class(range))) return Qfalse; if (!rb_eql(rb_ivar_get(range, id_beg), rb_ivar_get(obj, id_beg))) return Qfalse; if (!rb_eql(rb_ivar_get(range, id_end), rb_ivar_get(obj, id_end))) return Qfalse; if (EXCL(range) != EXCL(obj)) return Qfalse; return Qtrue; } /* * call-seq: * rng.hash => fixnum * * Generate a hash value such that two ranges with the same start and * end points, and the same value for the "exclude end" flag, generate * the same hash value. */ static VALUE range_hash(range) VALUE range; { long hash = EXCL(range); VALUE v; v = rb_hash(rb_ivar_get(range, id_beg)); hash ^= v << 1; v = rb_hash(rb_ivar_get(range, id_end)); hash ^= v << 9; hash ^= EXCL(range) << 24; return LONG2FIX(hash); } static VALUE str_step(args) VALUE *args; { return rb_str_upto(args[0], args[1], EXCL(args[2])); } static void range_each_func(range, func, v, e, arg) VALUE range; void (*func) _((VALUE, void*)); VALUE v, e; void *arg; { int c; if (EXCL(range)) { while (r_lt(v, e)) { (*func)(v, arg); v = rb_funcall(v, id_succ, 0, 0); } } else { while (RTEST(c = r_le(v, e))) { (*func)(v, arg); if (c == INT2FIX(0)) break; v = rb_funcall(v, id_succ, 0, 0); } } } static VALUE step_i(i, arg) VALUE i; VALUE arg; { VALUE *iter = (VALUE *)arg; if (FIXNUM_P(iter[0])) { iter[0] -= INT2FIX(1) & ~FIXNUM_FLAG; } else { iter[0] = rb_funcall(iter[0], '-', 1, INT2FIX(1)); } if (iter[0] == INT2FIX(0)) { rb_yield(i); iter[0] = iter[1]; } return Qnil; } extern int ruby_float_step _((VALUE from, VALUE to, VALUE step, int excl)); /* * call-seq: * rng.step(n=1) {| obj | block } => rng * * Iterates over rng, passing each nth element to the block. If * the range contains numbers, n is added for each iteration. Otherwise * step invokes succ to iterate through range * elements. The following code uses class Xs, which is defined * in the class-level documentation. * * range = Xs.new(1)..Xs.new(10) * range.step(2) {|x| puts x} * range.step(3) {|x| puts x} * * produces: * * 1 x * 3 xxx * 5 xxxxx * 7 xxxxxxx * 9 xxxxxxxxx * 1 x * 4 xxxx * 7 xxxxxxx * 10 xxxxxxxxxx */ static VALUE range_step(argc, argv, range) int argc; VALUE *argv; VALUE range; { VALUE b, e, step, tmp; RETURN_ENUMERATOR(range, argc, argv); b = rb_ivar_get(range, id_beg); e = rb_ivar_get(range, id_end); if (argc == 0) { step = INT2FIX(1); } else { rb_scan_args(argc, argv, "01", &step); if (!rb_obj_is_kind_of(step, rb_cNumeric)) { step = rb_to_int(step); } if (rb_funcall(step, '<', 1, INT2FIX(0))) { rb_raise(rb_eArgError, "step can't be negative"); } else if (!rb_funcall(step, '>', 1, INT2FIX(0))) { rb_raise(rb_eArgError, "step can't be 0"); } } if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are special */ long end = FIX2LONG(e); long i, unit = FIX2LONG(step); if (!EXCL(range)) end += 1; i = FIX2LONG(b); while (i < end) { rb_yield(LONG2NUM(i)); if (i + unit < i) break; i += unit; } } else if (ruby_float_step(b, e, step, EXCL(range))) { /* done */ } else if (rb_obj_is_kind_of(b, rb_cNumeric) || !NIL_P(rb_check_to_integer(b, "to_int")) || !NIL_P(rb_check_to_integer(e, "to_int"))) { ID op = EXCL(range) ? '<' : rb_intern("<="); while (RTEST(rb_funcall(b, op, 1, e))) { rb_yield(b); b = rb_funcall(b, '+', 1, step); } } else { tmp = rb_check_string_type(b); if (!NIL_P(tmp)) { VALUE args[5], iter[2]; b = tmp; args[0] = e; args[1] = EXCL(range) ? Qtrue : Qfalse; iter[0] = INT2FIX(1); iter[1] = step; rb_block_call(b, rb_intern("upto"), 2, args, step_i, (VALUE)iter); } else if (rb_obj_is_kind_of(b, rb_cNumeric) || !NIL_P(rb_check_to_integer(b, "to_int")) || !NIL_P(rb_check_to_integer(e, "to_int"))) { ID c = EXCL(range) ? '<' : rb_intern("<="); while (RTEST(rb_funcall(b, c, 1, e))) { rb_yield(b); b = rb_funcall(b, '+', 1, step); } } else { VALUE args[2]; if (!rb_respond_to(b, id_succ)) { rb_raise(rb_eTypeError, "can't iterate from %s", rb_obj_classname(b)); } args[0] = INT2FIX(1); args[1] = step; range_each_func(range, step_i, b, e, args); } } return range; } static void each_i(v, arg) VALUE v; void *arg; { rb_yield(v); } /* * call-seq: * rng.each {| i | block } => rng * * Iterates over the elements rng, passing each in turn to the * block. You can only iterate if the start object of the range * supports the +succ+ method (which means that you can't iterate over * ranges of +Float+ objects). * * (10..15).each do |n| * print n, ' ' * end * * produces: * * 10 11 12 13 14 15 */ static VALUE range_each(range) VALUE range; { VALUE beg, end; RETURN_ENUMERATOR(range, 0, 0); beg = rb_ivar_get(range, id_beg); end = rb_ivar_get(range, id_end); if (!rb_respond_to(beg, id_succ)) { rb_raise(rb_eTypeError, "can't iterate from %s", rb_obj_classname(beg)); } if (FIXNUM_P(beg) && FIXNUM_P(end)) { /* fixnums are special */ long lim = FIX2LONG(end); long i; if (!EXCL(range)) lim += 1; for (i=FIX2LONG(beg); i obj * rng.begin => obj * * Returns the first object in rng. */ static VALUE range_first(range) VALUE range; { return rb_ivar_get(range, id_beg); } /* * call-seq: * rng.end => obj * rng.last => obj * * Returns the object that defines the end of rng. * * (1..10).end #=> 10 * (1...10).end #=> 10 */ static VALUE range_last(range) VALUE range; { return rb_ivar_get(range, id_end); } VALUE rb_range_beg_len(range, begp, lenp, len, err) VALUE range; long *begp, *lenp; long len; int err; { long beg, end, b, e; if (!rb_obj_is_kind_of(range, rb_cRange)) return Qfalse; beg = b = NUM2LONG(rb_ivar_get(range, id_beg)); end = e = NUM2LONG(rb_ivar_get(range, id_end)); if (beg < 0) { beg += len; if (beg < 0) goto out_of_range; } if (err == 0 || err == 2) { if (beg > len) goto out_of_range; if (end > len) end = len; } if (end < 0) end += len; if (!EXCL(range)) end++; /* include end point */ len = end - beg; if (len < 0) len = 0; *begp = beg; *lenp = len; return Qtrue; out_of_range: if (err) { rb_raise(rb_eRangeError, "%ld..%s%ld out of range", b, EXCL(range)? "." : "", e); } return Qnil; } /* * call-seq: * rng.to_s => string * * Convert this range object to a printable form. */ static VALUE range_to_s(range) VALUE range; { VALUE str, str2; str = rb_obj_as_string(rb_ivar_get(range, id_beg)); str2 = rb_obj_as_string(rb_ivar_get(range, id_end)); str = rb_str_dup(str); rb_str_cat(str, "...", EXCL(range)?3:2); rb_str_append(str, str2); OBJ_INFECT(str, str2); return str; } /* * call-seq: * rng.inspect => string * * Convert this range object to a printable form (using * inspect to convert the start and end * objects). */ static VALUE range_inspect(range) VALUE range; { VALUE str, str2; str = rb_inspect(rb_ivar_get(range, id_beg)); str2 = rb_inspect(rb_ivar_get(range, id_end)); str = rb_str_dup(str); rb_str_cat(str, "...", EXCL(range)?3:2); rb_str_append(str, str2); OBJ_INFECT(str, str2); return str; } /* * call-seq: * rng === obj => true or false * rng.member?(val) => true or false * rng.include?(val) => true or false * * Returns true if obj is an element of * rng, false otherwise. Conveniently, * === is the comparison operator used by * case statements. * * case 79 * when 1..50 then print "low\n" * when 51..75 then print "medium\n" * when 76..100 then print "high\n" * end * * produces: * * high */ static VALUE range_include(range, val) VALUE range, val; { VALUE beg, end; beg = rb_ivar_get(range, id_beg); end = rb_ivar_get(range, id_end); if (r_le(beg, val)) { if (EXCL(range)) { if (r_lt(val, end)) return Qtrue; } else { if (r_le(val, end)) return Qtrue; } } return Qfalse; } /* A Range represents an interval---a set of values with a * start and an end. Ranges may be constructed using the * s..e and * s...e literals, or with * Range::new. Ranges constructed using .. * run from the start to the end inclusively. Those created using * ... exclude the end value. When used as an iterator, * ranges return each value in the sequence. * * (-1..-5).to_a #=> [] * (-5..-1).to_a #=> [-5, -4, -3, -2, -1] * ('a'..'e').to_a #=> ["a", "b", "c", "d", "e"] * ('a'...'e').to_a #=> ["a", "b", "c", "d"] * * Ranges can be constructed using objects of any type, as long as the * objects can be compared using their <=> operator and * they support the succ method to return the next object * in sequence. * * class Xs # represent a string of 'x's * include Comparable * attr :length * def initialize(n) * @length = n * end * def succ * Xs.new(@length + 1) * end * def <=>(other) * @length <=> other.length * end * def to_s * sprintf "%2d #{inspect}", @length * end * def inspect * 'x' * @length * end * end * * r = Xs.new(3)..Xs.new(6) #=> xxx..xxxxxx * r.to_a #=> [xxx, xxxx, xxxxx, xxxxxx] * r.member?(Xs.new(5)) #=> true * * In the previous code example, class Xs includes the * Comparable module. This is because * Enumerable#member? checks for equality using * ==. Including Comparable ensures that the * == method is defined in terms of the <=> * method implemented in Xs. * */ void Init_Range() { rb_cRange = rb_define_class("Range", rb_cObject); rb_include_module(rb_cRange, rb_mEnumerable); rb_define_method(rb_cRange, "initialize", range_initialize, -1); rb_define_method(rb_cRange, "==", range_eq, 1); rb_define_method(rb_cRange, "===", range_include, 1); rb_define_method(rb_cRange, "eql?", range_eql, 1); rb_define_method(rb_cRange, "hash", range_hash, 0); rb_define_method(rb_cRange, "each", range_each, 0); rb_define_method(rb_cRange, "step", range_step, -1); rb_define_method(rb_cRange, "first", range_first, 0); rb_define_method(rb_cRange, "last", range_last, 0); rb_define_method(rb_cRange, "begin", range_first, 0); rb_define_method(rb_cRange, "end", range_last, 0); rb_define_method(rb_cRange, "to_s", range_to_s, 0); rb_define_method(rb_cRange, "inspect", range_inspect, 0); rb_define_method(rb_cRange, "exclude_end?", range_exclude_end_p, 0); rb_define_method(rb_cRange, "member?", range_include, 1); rb_define_method(rb_cRange, "include?", range_include, 1); id_cmp = rb_intern("<=>"); id_succ = rb_intern("succ"); id_beg = rb_intern("begin"); id_end = rb_intern("end"); id_excl = rb_intern("excl"); } ================================================ FILE: re.c ================================================ /********************************************************************** re.c - $Author$ created at: Mon Aug 9 18:24:49 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #include "ruby.h" #include "re.h" #include VALUE rb_eRegexpError; #define BEG(no) regs->beg[no] #define END(no) regs->end[no] #if 'a' == 97 /* it's ascii */ static const char casetable[] = { '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', /* ' ' '!' '"' '#' '$' '%' '&' ''' */ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', /* '(' ')' '*' '+' ',' '-' '.' '/' */ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', /* '0' '1' '2' '3' '4' '5' '6' '7' */ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', /* '8' '9' ':' ';' '<' '=' '>' '?' */ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', /* '@' 'A' 'B' 'C' 'D' 'E' 'F' 'G' */ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', /* 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' */ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', /* 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W' */ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', /* 'X' 'Y' 'Z' '[' '\' ']' '^' '_' */ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', /* '`' 'a' 'b' 'c' 'd' 'e' 'f' 'g' */ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', /* 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' */ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', /* 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' */ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', /* 'x' 'y' 'z' '{' '|' '}' '~' */ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177', '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307', '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317', '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', }; #else # error >>> "You lose. You will need a translation table for your character set." <<< #endif int rb_memcicmp(x, y, len) const void *x, *y; long len; { const unsigned char *p1 = x, *p2 = y; int tmp; while (len--) { if ((tmp = casetable[(unsigned)*p1++] - casetable[(unsigned)*p2++]) != 0) return tmp; } return 0; } int rb_memcmp(p1, p2, len) const void *p1, *p2; long len; { if (!ruby_ignorecase) { return memcmp(p1, p2, len); } return rb_memcicmp(p1, p2, len); } long rb_memsearch(x0, m, y0, n) const void *x0, *y0; long m, n; { const unsigned char *x = (unsigned char *)x0, *y = (unsigned char *)y0; const unsigned char *s, *e; long i; int d; unsigned long hx, hy; #define KR_REHASH(a, b, h) (((h) << 1) - (((unsigned long)(a))< n) return -1; s = y; e = s + n - m; /* Preprocessing */ /* computes d = 2^(m-1) with the left-shift operator */ d = sizeof(hx) * CHAR_BIT - 1; if (d > m) d = m; if (ruby_ignorecase) { if (n == m) { return rb_memcicmp(x, s, m) == 0 ? 0 : -1; } /* Prepare hash value */ for (hy = hx = i = 0; i < d; ++i) { hx = KR_REHASH(0, casetable[x[i]], hx); hy = KR_REHASH(0, casetable[s[i]], hy); } /* Searching */ while (hx != hy || rb_memcicmp(x, s, m)) { if (s >= e) return -1; hy = KR_REHASH(casetable[*s], casetable[*(s+d)], hy); s++; } } else { if (n == m) { return memcmp(x, s, m) == 0 ? 0 : -1; } /* Prepare hash value */ for (hy = hx = i = 0; i < d; ++i) { hx = KR_REHASH(0, x[i], hx); hy = KR_REHASH(0, s[i], hy); } /* Searching */ while (hx != hy || memcmp(x, s, m)) { if (s >= e) return -1; hy = KR_REHASH(*s, *(s+d), hy); s++; } } return s-y; } #define REG_LITERAL FL_USER5 #define REG_CASESTATE FL_USER0 #define KCODE_NONE 0 #define KCODE_EUC FL_USER1 #define KCODE_SJIS FL_USER2 #define KCODE_UTF8 FL_USER3 #define KCODE_FIXED FL_USER4 #define KCODE_MASK (KCODE_EUC|KCODE_SJIS|KCODE_UTF8) static int reg_kcode = DEFAULT_KCODE; static void kcode_euc(re) struct RRegexp *re; { FL_UNSET(re, KCODE_MASK); FL_SET(re, KCODE_EUC); FL_SET(re, KCODE_FIXED); } static void kcode_sjis(re) struct RRegexp *re; { FL_UNSET(re, KCODE_MASK); FL_SET(re, KCODE_SJIS); FL_SET(re, KCODE_FIXED); } static void kcode_utf8(re) struct RRegexp *re; { FL_UNSET(re, KCODE_MASK); FL_SET(re, KCODE_UTF8); FL_SET(re, KCODE_FIXED); } static void kcode_none(re) struct RRegexp *re; { FL_UNSET(re, KCODE_MASK); FL_SET(re, KCODE_FIXED); } static int curr_kcode; void rb_kcode_set_option(re) VALUE re; { if (!FL_TEST(re, KCODE_FIXED)) return; curr_kcode = RBASIC(re)->flags & KCODE_MASK; if (reg_kcode == curr_kcode) return; switch (curr_kcode) { case KCODE_NONE: re_mbcinit(MBCTYPE_ASCII); break; case KCODE_EUC: re_mbcinit(MBCTYPE_EUC); break; case KCODE_SJIS: re_mbcinit(MBCTYPE_SJIS); break; case KCODE_UTF8: re_mbcinit(MBCTYPE_UTF8); break; } } void rb_kcode_reset_option() { if (reg_kcode == curr_kcode) return; switch (reg_kcode) { case KCODE_NONE: re_mbcinit(MBCTYPE_ASCII); break; case KCODE_EUC: re_mbcinit(MBCTYPE_EUC); break; case KCODE_SJIS: re_mbcinit(MBCTYPE_SJIS); break; case KCODE_UTF8: re_mbcinit(MBCTYPE_UTF8); break; } } int rb_reg_mbclen2(c, re) unsigned int c; VALUE re; { int len; if (!FL_TEST(re, KCODE_FIXED)) return mbclen(c); rb_kcode_set_option(re); len = mbclen(c); rb_kcode_reset_option(); return len; } static void rb_reg_check(re) VALUE re; { if (!RREGEXP(re)->ptr || !RREGEXP(re)->str) { rb_raise(rb_eTypeError, "uninitialized Regexp"); } } static void rb_reg_expr_str(str, s, len) VALUE str; const char *s; long len; { const char *p, *pend; int need_escape = 0; p = s; pend = p + len; while (pptr->options & RE_OPTION_MULTILINE) rb_str_buf_cat2(str, "m"); if (RREGEXP(re)->ptr->options & RE_OPTION_IGNORECASE) rb_str_buf_cat2(str, "i"); if (RREGEXP(re)->ptr->options & RE_OPTION_EXTENDED) rb_str_buf_cat2(str, "x"); if (FL_TEST(re, KCODE_FIXED)) { switch ((RBASIC(re)->flags & KCODE_MASK)) { case KCODE_NONE: rb_str_buf_cat2(str, "n"); break; case KCODE_EUC: rb_str_buf_cat2(str, "e"); break; case KCODE_SJIS: rb_str_buf_cat2(str, "s"); break; case KCODE_UTF8: rb_str_buf_cat2(str, "u"); break; } } } OBJ_INFECT(str, re); return str; } /* * call-seq: * rxp.source => str * * Returns the original string of the pattern. * * /ab+c/ix.source #=> "ab+c" */ static VALUE rb_reg_source(re) VALUE re; { VALUE str; rb_reg_check(re); str = rb_str_new(RREGEXP(re)->str,RREGEXP(re)->len); if (OBJ_TAINTED(re)) OBJ_TAINT(str); return str; } /* * call-seq: * rxp.inspect => string * * Produce a nicely formatted string-version of _rxp_. Perhaps surprisingly, * #inspect actually produces the more natural version of * the string than #to_s. * * /ab+c/ix.to_s #=> /ab+c/ix */ static VALUE rb_reg_inspect(re) VALUE re; { rb_reg_check(re); return rb_reg_desc(RREGEXP(re)->str, RREGEXP(re)->len, re); } /* * call-seq: * rxp.to_s => str * * Returns a string containing the regular expression and its options (using the * (?xxx:yyy) notation. This string can be fed back in to * Regexp::new to a regular expression with the same semantics as * the original. (However, Regexp#== may not return true when * comparing the two, as the source of the regular expression itself may * differ, as the example shows). Regexp#inspect produces a * generally more readable version of rxp. * * r1 = /ab+c/ix #=> /ab+c/ix * s1 = r1.to_s #=> "(?ix-m:ab+c)" * r2 = Regexp.new(s1) #=> /(?ix-m:ab+c)/ * r1 == r2 #=> false * r1.source #=> "ab+c" * r2.source #=> "(?ix-m:ab+c)" */ static VALUE rb_reg_to_s(re) VALUE re; { int options; const int embeddable = RE_OPTION_MULTILINE|RE_OPTION_IGNORECASE|RE_OPTION_EXTENDED; long len; const char* ptr; VALUE str = rb_str_buf_new2("(?"); rb_reg_check(re); options = RREGEXP(re)->ptr->options; ptr = RREGEXP(re)->str; len = RREGEXP(re)->len; again: if (len >= 4 && ptr[0] == '(' && ptr[1] == '?') { int err = 1; ptr += 2; if ((len -= 2) > 0) { do { if (*ptr == 'm') { options |= RE_OPTION_MULTILINE; } else if (*ptr == 'i') { options |= RE_OPTION_IGNORECASE; } else if (*ptr == 'x') { options |= RE_OPTION_EXTENDED; } else break; ++ptr; } while (--len > 0); } if (len > 1 && *ptr == '-') { ++ptr; --len; do { if (*ptr == 'm') { options &= ~RE_OPTION_MULTILINE; } else if (*ptr == 'i') { options &= ~RE_OPTION_IGNORECASE; } else if (*ptr == 'x') { options &= ~RE_OPTION_EXTENDED; } else break; ++ptr; } while (--len > 0); } if (*ptr == ')') { --len; ++ptr; goto again; } if (*ptr == ':' && ptr[len-1] == ')') { Regexp *rp; rb_kcode_set_option(re); rp = ALLOC(Regexp); MEMZERO((char *)rp, Regexp, 1); err = re_compile_pattern(++ptr, len -= 2, rp) != 0; rb_kcode_reset_option(); re_free_pattern(rp); } if (err) { options = RREGEXP(re)->ptr->options; ptr = RREGEXP(re)->str; len = RREGEXP(re)->len; } } if (options & RE_OPTION_MULTILINE) rb_str_buf_cat2(str, "m"); if (options & RE_OPTION_IGNORECASE) rb_str_buf_cat2(str, "i"); if (options & RE_OPTION_EXTENDED) rb_str_buf_cat2(str, "x"); if ((options & embeddable) != embeddable) { rb_str_buf_cat2(str, "-"); if (!(options & RE_OPTION_MULTILINE)) rb_str_buf_cat2(str, "m"); if (!(options & RE_OPTION_IGNORECASE)) rb_str_buf_cat2(str, "i"); if (!(options & RE_OPTION_EXTENDED)) rb_str_buf_cat2(str, "x"); } rb_str_buf_cat2(str, ":"); rb_reg_expr_str(str, ptr, len); rb_str_buf_cat2(str, ")"); OBJ_INFECT(str, re); return str; } static void rb_reg_raise(s, len, err, re) const char *s; long len; const char *err; VALUE re; { VALUE desc = rb_reg_desc(s, len, re); if (ruby_in_compile) rb_compile_error("%s: %s", err, RSTRING(desc)->ptr); else rb_raise(rb_eRegexpError, "%s: %s", err, RSTRING(desc)->ptr); } /* * call-seq: * rxp.casefold? => true or false * * Returns the value of the case-insensitive flag. */ static VALUE rb_reg_casefold_p(re) VALUE re; { rb_reg_check(re); if (RREGEXP(re)->ptr->options & RE_OPTION_IGNORECASE) return Qtrue; return Qfalse; } /* * call-seq: * rxp.options => fixnum * * Returns the set of bits corresponding to the options used when creating this * Regexp (see Regexp::new for details. Note that additional bits * may be set in the returned options: these are used internally by the regular * expression code. These extra bits are ignored if the options are passed to * Regexp::new. * * Regexp::IGNORECASE #=> 1 * Regexp::EXTENDED #=> 2 * Regexp::MULTILINE #=> 4 * * /cat/.options #=> 128 * /cat/ix.options #=> 131 * Regexp.new('cat', true).options #=> 129 * Regexp.new('cat', 0, 's').options #=> 384 * * r = /cat/ix * Regexp.new(r.source, r.options) #=> /cat/ix */ static VALUE rb_reg_options_m(re) VALUE re; { int options = rb_reg_options(re); return INT2NUM(options); } /* * call-seq: * rxp.kcode => str * * Returns the character set code for the regexp. */ static VALUE rb_reg_kcode_m(re) VALUE re; { const char *kcode; if (FL_TEST(re, KCODE_FIXED)) { switch (RBASIC(re)->flags & KCODE_MASK) { case KCODE_NONE: kcode = "none"; break; case KCODE_EUC: kcode = "euc"; break; case KCODE_SJIS: kcode = "sjis"; break; case KCODE_UTF8: kcode = "utf8"; break; default: rb_bug("unknown kcode - should not happen"); break; } return rb_str_new2(kcode); } return Qnil; } static Regexp* make_regexp(s, len, flags) const char *s; long len; int flags; { Regexp *rp; const char *err; /* Handle escaped characters first. */ /* Build a copy of the string (in dest) with the escaped characters translated, and generate the regex from that. */ rp = ALLOC(Regexp); MEMZERO((char *)rp, Regexp, 1); rp->buffer = ALLOC_N(char, 16); rp->allocated = 16; rp->fastmap = ALLOC_N(char, 256); if (flags) { rp->options = flags; } err = re_compile_pattern(s, len, rp); if (err != NULL) { re_free_pattern(rp); rb_reg_raise(s, len, err, 0); return 0; } return rp; } /* * Document-class: MatchData * * MatchData is the type of the special variable $~, * and is the type of the object returned by Regexp#match and * Regexp#last_match. It encapsulates all the results of a pattern * match, results normally accessed through the special variables * $&, $', $`, $1, * $2, and so on. Matchdata is also known as * MatchingData. * */ VALUE rb_cMatch; static VALUE match_alloc _((VALUE)); static VALUE match_alloc(klass) VALUE klass; { NEWOBJ(match, struct RMatch); OBJSETUP(match, klass, T_MATCH); match->str = 0; match->regs = 0; match->regs = ALLOC(struct re_registers); MEMZERO(match->regs, struct re_registers, 1); return (VALUE)match; } static void match_check(VALUE match) { if (!RMATCH(match)->str) { rb_raise(rb_eTypeError, "uninitialized Match"); } } /* :nodoc: */ static VALUE match_init_copy(obj, orig) VALUE obj, orig; { if (obj == orig) return obj; if (!rb_obj_is_instance_of(orig, rb_obj_class(obj))) { rb_raise(rb_eTypeError, "wrong argument class"); } RMATCH(obj)->str = RMATCH(orig)->str; re_free_registers(RMATCH(obj)->regs); RMATCH(obj)->regs->allocated = 0; re_copy_registers(RMATCH(obj)->regs, RMATCH(orig)->regs); return obj; } /* * call-seq: * mtch.length => integer * mtch.size => integer * * Returns the number of elements in the match array. * * m = /(.)(.)(\d+)(\d)/.match("THX1138.") * m.length #=> 5 * m.size #=> 5 */ static VALUE match_size(match) VALUE match; { match_check(match); return INT2FIX(RMATCH(match)->regs->num_regs); } /* * call-seq: * mtch.offset(n) => array * * Returns a two-element array containing the beginning and ending offsets of * the nth match. * * m = /(.)(.)(\d+)(\d)/.match("THX1138.") * m.offset(0) #=> [1, 7] * m.offset(4) #=> [6, 7] */ static VALUE match_offset(match, n) VALUE match, n; { int i = NUM2INT(n); match_check(match); if (i < 0 || RMATCH(match)->regs->num_regs <= i) rb_raise(rb_eIndexError, "index %d out of matches", i); if (RMATCH(match)->regs->beg[i] < 0) return rb_assoc_new(Qnil, Qnil); return rb_assoc_new(INT2FIX(RMATCH(match)->regs->beg[i]), INT2FIX(RMATCH(match)->regs->end[i])); } /* * call-seq: * mtch.begin(n) => integer * * Returns the offset of the start of the nth element of the match * array in the string. * * m = /(.)(.)(\d+)(\d)/.match("THX1138.") * m.begin(0) #=> 1 * m.begin(2) #=> 2 */ static VALUE match_begin(match, n) VALUE match, n; { int i = NUM2INT(n); match_check(match); if (i < 0 || RMATCH(match)->regs->num_regs <= i) rb_raise(rb_eIndexError, "index %d out of matches", i); if (RMATCH(match)->regs->beg[i] < 0) return Qnil; return INT2FIX(RMATCH(match)->regs->beg[i]); } /* * call-seq: * mtch.end(n) => integer * * Returns the offset of the character immediately following the end of the * nth element of the match array in the string. * * m = /(.)(.)(\d+)(\d)/.match("THX1138.") * m.end(0) #=> 7 * m.end(2) #=> 3 */ static VALUE match_end(match, n) VALUE match, n; { int i = NUM2INT(n); match_check(match); if (i < 0 || RMATCH(match)->regs->num_regs <= i) rb_raise(rb_eIndexError, "index %d out of matches", i); if (RMATCH(match)->regs->beg[i] < 0) return Qnil; return INT2FIX(RMATCH(match)->regs->end[i]); } #define MATCH_BUSY FL_USER2 void rb_match_busy(match) VALUE match; { FL_SET(match, MATCH_BUSY); } int ruby_ignorecase; static int may_need_recompile; static void rb_reg_prepare_re(re) VALUE re; { int need_recompile = 0; int state; rb_reg_check(re); state = FL_TEST(re, REG_CASESTATE); /* ignorecase status */ if (ruby_ignorecase && !state) { FL_SET(re, REG_CASESTATE); RREGEXP(re)->ptr->options |= RE_OPTION_IGNORECASE; need_recompile = 1; } if (!ruby_ignorecase && state) { FL_UNSET(re, REG_CASESTATE); RREGEXP(re)->ptr->options &= ~RE_OPTION_IGNORECASE; need_recompile = 1; } if (!FL_TEST(re, KCODE_FIXED) && (RBASIC(re)->flags & KCODE_MASK) != reg_kcode) { need_recompile = 1; RBASIC(re)->flags &= ~KCODE_MASK; RBASIC(re)->flags |= reg_kcode; } if (need_recompile) { const char *err; if (FL_TEST(re, KCODE_FIXED)) rb_kcode_set_option(re); rb_reg_check(re); RREGEXP(re)->ptr->fastmap_accurate = 0; err = re_compile_pattern(RREGEXP(re)->str, RREGEXP(re)->len, RREGEXP(re)->ptr); if (err != NULL) { rb_reg_raise(RREGEXP(re)->str, RREGEXP(re)->len, err, re); } } } long rb_reg_adjust_startpos(re, str, pos, reverse) VALUE re, str; long pos, reverse; { long range; rb_reg_check(re); if (may_need_recompile) rb_reg_prepare_re(re); if (FL_TEST(re, KCODE_FIXED)) rb_kcode_set_option(re); else if (reg_kcode != curr_kcode) rb_kcode_reset_option(); if (reverse) { range = -pos; } else { range = RSTRING(str)->len - pos; } return re_adjust_startpos(RREGEXP(re)->ptr, RSTRING(str)->ptr, RSTRING(str)->len, pos, range); } long rb_reg_search(re, str, pos, reverse) VALUE re, str; long pos, reverse; { long result; VALUE match; struct re_registers regs; long range; if (pos > RSTRING(str)->len || pos < 0) { rb_backref_set(Qnil); return -1; } rb_reg_check(re); if (may_need_recompile) rb_reg_prepare_re(re); if (FL_TEST(re, KCODE_FIXED)) rb_kcode_set_option(re); else if (reg_kcode != curr_kcode) rb_kcode_reset_option(); if (reverse) { range = -pos; } else { range = RSTRING(str)->len - pos; } MEMZERO(®s, struct re_registers, 1); result = re_search(RREGEXP(re)->ptr,RSTRING(str)->ptr,RSTRING(str)->len, pos, range, ®s); if (FL_TEST(re, KCODE_FIXED)) rb_kcode_reset_option(); if (result == -2) { rb_reg_raise(RREGEXP(re)->str, RREGEXP(re)->len, "Stack overflow in regexp matcher", re); } if (result < 0) { re_free_registers(®s); rb_backref_set(Qnil); return result; } match = rb_backref_get(); if (NIL_P(match) || FL_TEST(match, MATCH_BUSY)) { match = match_alloc(rb_cMatch); } else { if (rb_safe_level() >= 3) OBJ_TAINT(match); else FL_UNSET(match, FL_TAINT); } re_copy_registers(RMATCH(match)->regs, ®s); re_free_registers(®s); RMATCH(match)->str = rb_str_new4(str); rb_backref_set(match); OBJ_INFECT(match, re); OBJ_INFECT(match, str); return result; } VALUE rb_reg_nth_defined(nth, match) int nth; VALUE match; { if (NIL_P(match)) return Qnil; match_check(match); if (nth >= RMATCH(match)->regs->num_regs) { return Qnil; } if (nth < 0) { nth += RMATCH(match)->regs->num_regs; if (nth <= 0) return Qnil; } if (RMATCH(match)->BEG(nth) == -1) return Qfalse; return Qtrue; } VALUE rb_reg_nth_match(nth, match) int nth; VALUE match; { VALUE str; long start, end, len; if (NIL_P(match)) return Qnil; match_check(match); if (nth >= RMATCH(match)->regs->num_regs) { return Qnil; } if (nth < 0) { nth += RMATCH(match)->regs->num_regs; if (nth <= 0) return Qnil; } start = RMATCH(match)->BEG(nth); if (start == -1) return Qnil; end = RMATCH(match)->END(nth); len = end - start; str = rb_str_substr(RMATCH(match)->str, start, len); OBJ_INFECT(str, match); return str; } VALUE rb_reg_last_match(match) VALUE match; { return rb_reg_nth_match(0, match); } /* * call-seq: * mtch.pre_match => str * * Returns the portion of the original string before the current match. * Equivalent to the special variable $`. * * m = /(.)(.)(\d+)(\d)/.match("THX1138.") * m.pre_match #=> "T" */ VALUE rb_reg_match_pre(match) VALUE match; { VALUE str; if (NIL_P(match)) return Qnil; match_check(match); if (RMATCH(match)->BEG(0) == -1) return Qnil; str = rb_str_substr(RMATCH(match)->str, 0, RMATCH(match)->BEG(0)); if (OBJ_TAINTED(match)) OBJ_TAINT(str); return str; } /* * call-seq: * mtch.post_match => str * * Returns the portion of the original string after the current match. * Equivalent to the special variable $'. * * m = /(.)(.)(\d+)(\d)/.match("THX1138: The Movie") * m.post_match #=> ": The Movie" */ VALUE rb_reg_match_post(match) VALUE match; { VALUE str; long pos; if (NIL_P(match)) return Qnil; match_check(match); if (RMATCH(match)->BEG(0) == -1) return Qnil; str = RMATCH(match)->str; pos = RMATCH(match)->END(0); str = rb_str_substr(str, pos, RSTRING(str)->len - pos); if (OBJ_TAINTED(match)) OBJ_TAINT(str); return str; } VALUE rb_reg_match_last(match) VALUE match; { int i; if (NIL_P(match)) return Qnil; match_check(match); if (RMATCH(match)->BEG(0) == -1) return Qnil; for (i=RMATCH(match)->regs->num_regs-1; RMATCH(match)->BEG(i) == -1 && i > 0; i--) ; if (i == 0) return Qnil; return rb_reg_nth_match(i, match); } static VALUE last_match_getter() { return rb_reg_last_match(rb_backref_get()); } static VALUE prematch_getter() { return rb_reg_match_pre(rb_backref_get()); } static VALUE postmatch_getter() { return rb_reg_match_post(rb_backref_get()); } static VALUE last_paren_match_getter() { return rb_reg_match_last(rb_backref_get()); } static VALUE match_array(match, start) VALUE match; int start; { struct re_registers *regs; VALUE ary; VALUE target; int i; int taint = OBJ_TAINTED(match); match_check(match); regs = RMATCH(match)->regs; ary = rb_ary_new2(regs->num_regs); target = RMATCH(match)->str; for (i=start; inum_regs; i++) { if (regs->beg[i] == -1) { rb_ary_push(ary, Qnil); } else { VALUE str = rb_str_substr(target, regs->beg[i], regs->end[i]-regs->beg[i]); if (taint) OBJ_TAINT(str); rb_ary_push(ary, str); } } return ary; } /* [MG]:FIXME: I put parens around the /.../.match() in the first line of the second example to prevent the '*' followed by a '/' from ending the comment. */ /* * call-seq: * mtch.to_a => anArray * * Returns the array of matches. * * m = /(.)(.)(\d+)(\d)/.match("THX1138.") * m.to_a #=> ["HX1138", "H", "X", "113", "8"] * * Because to_a is called when expanding * *variable, there's a useful assignment * shortcut for extracting matched fields. This is slightly slower than * accessing the fields directly (as an intermediate array is * generated). * * all,f1,f2,f3 = *(/(.)(.)(\d+)(\d)/.match("THX1138.")) * all #=> "HX1138" * f1 #=> "H" * f2 #=> "X" * f3 #=> "113" */ static VALUE match_to_a(match) VALUE match; { return match_array(match, 0); } /* * call-seq: * mtch.captures => array * * Returns the array of captures; equivalent to mtch.to_a[1..-1]. * * f1,f2,f3,f4 = /(.)(.)(\d+)(\d)/.match("THX1138.").captures * f1 #=> "H" * f2 #=> "X" * f3 #=> "113" * f4 #=> "8" */ static VALUE match_captures(match) VALUE match; { return match_array(match, 1); } /* * call-seq: * mtch[i] => obj * mtch[start, length] => array * mtch[range] => array * * Match Reference---MatchData acts as an array, and may be * accessed using the normal array indexing techniques. mtch[0] is * equivalent to the special variable $&, and returns the entire * matched string. mtch[1], mtch[2], and so on return the values * of the matched backreferences (portions of the pattern between parentheses). * * m = /(.)(.)(\d+)(\d)/.match("THX1138.") * m[0] #=> "HX1138" * m[1, 2] #=> ["H", "X"] * m[1..3] #=> ["H", "X", "113"] * m[-3, 2] #=> ["X", "113"] */ static VALUE match_aref(argc, argv, match) int argc; VALUE *argv; VALUE match; { VALUE idx, rest; rb_scan_args(argc, argv, "11", &idx, &rest); if (!NIL_P(rest) || !FIXNUM_P(idx) || FIX2INT(idx) < 0) { return rb_ary_aref(argc, argv, match_to_a(match)); } return rb_reg_nth_match(FIX2INT(idx), match); } static VALUE match_entry _((VALUE, long)); static VALUE match_entry(match, n) VALUE match; long n; { return rb_reg_nth_match(n, match); } /* * call-seq: * mtch.values_at([index]*) => array * * Uses each index to access the matching values, returning an array of * the corresponding matches. * * m = /(.)(.)(\d+)(\d)/.match("THX1138: The Movie") * m.to_a #=> ["HX1138", "H", "X", "113", "8"] * m.values_at(0, 2, -2) #=> ["HX1138", "X", "113"] */ static VALUE match_values_at(argc, argv, match) int argc; VALUE *argv; VALUE match; { match_check(match); return rb_values_at(match, RMATCH(match)->regs->num_regs, argc, argv, match_entry); } /* * call-seq: * mtch.select{|obj| block} => array * * Returns an array containing match strings for which block * gives true. MatchData#select will be removed from Ruby 1.9. * * m = /(.)(.)(\d+)(\d)/.match("THX1138: The Movie") * p m.select{|x| /X/ =~ x} #=> ["HX1138", "X"] */ static VALUE match_select(argc, argv, match) int argc; VALUE *argv; VALUE match; { if (argc > 0) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc); } else { struct re_registers *regs; VALUE target; VALUE result = rb_ary_new(); int i; int taint = OBJ_TAINTED(match); match_check(match); regs = RMATCH(match)->regs; target = RMATCH(match)->str; for (i=0; inum_regs; i++) { VALUE str = rb_str_substr(target, regs->beg[i], regs->end[i]-regs->beg[i]); if (taint) OBJ_TAINT(str); if (RTEST(rb_yield(str))) { rb_ary_push(result, str); } } return result; } } /* * call-seq: * mtch.to_s => str * * Returns the entire matched string. * * m = /(.)(.)(\d+)(\d)/.match("THX1138.") * m.to_s #=> "HX1138" */ static VALUE match_to_s(match) VALUE match; { VALUE str = rb_reg_last_match(match); if (NIL_P(str)) str = rb_str_new(0,0); if (OBJ_TAINTED(match)) OBJ_TAINT(str); if (OBJ_TAINTED(RMATCH(match)->str)) OBJ_TAINT(str); return str; } /* * call-seq: * mtch.string => str * * Returns a frozen copy of the string passed in to match. * * m = /(.)(.)(\d+)(\d)/.match("THX1138.") * m.string #=> "THX1138." */ static VALUE match_string(match) VALUE match; { match_check(match); return RMATCH(match)->str; /* str is frozen */ } /* * call-seq: * mtch.inspect => str * * Returns a printable version of mtch. * * puts /.$/.match("foo").inspect * #=> # * * puts /(.)(.)(.)/.match("foo").inspect * #=> # * * puts /(.)(.)?(.)/.match("fo").inspect * #=> # * */ static VALUE match_inspect(VALUE match) { const char *cname = rb_obj_classname(match); VALUE str; int i; struct re_registers *regs = RMATCH(match)->regs; int num_regs = regs->num_regs; str = rb_str_buf_new2("#<"); rb_str_buf_cat2(str, cname); for (i = 0; i < num_regs; i++) { VALUE v; rb_str_buf_cat2(str, " "); if (0 < i) { char buf[sizeof(i)*3+1]; snprintf(buf, sizeof(buf), "%d", i); rb_str_buf_cat2(str, buf); rb_str_buf_cat2(str, ":"); } v = rb_reg_nth_match(i, match); if (v == Qnil) rb_str_buf_cat2(str, "nil"); else rb_str_buf_append(str, rb_str_inspect(v)); } rb_str_buf_cat2(str, ">"); return str; } VALUE rb_cRegexp; static void rb_reg_initialize(obj, s, len, options) VALUE obj; const char *s; long len; int options; /* CASEFOLD = 1 */ /* EXTENDED = 2 */ /* MULTILINE = 4 */ /* CODE_NONE = 16 */ /* CODE_EUC = 32 */ /* CODE_SJIS = 48 */ /* CODE_UTF8 = 64 */ { struct RRegexp *re = RREGEXP(obj); if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify regexp"); rb_check_frozen(obj); if (FL_TEST(obj, REG_LITERAL)) rb_raise(rb_eSecurityError, "can't modify literal regexp"); if (re->ptr) re_free_pattern(re->ptr); if (re->str) free(re->str); re->ptr = 0; re->str = 0; switch (options & ~0xf) { case 0: default: FL_SET(re, reg_kcode); break; case 16: kcode_none(re); break; case 32: kcode_euc(re); break; case 48: kcode_sjis(re); break; case 64: kcode_utf8(re); break; } if (options & ~0xf) { rb_kcode_set_option((VALUE)re); } if (ruby_ignorecase) { options |= RE_OPTION_IGNORECASE; FL_SET(re, REG_CASESTATE); } re->ptr = make_regexp(s, len, options & 0xf); re->str = ALLOC_N(char, len+1); memcpy(re->str, s, len); re->str[len] = '\0'; re->len = len; if (options & ~0xf) { rb_kcode_reset_option(); } if (ruby_in_compile) FL_SET(obj, REG_LITERAL); } static VALUE rb_reg_s_alloc _((VALUE)); static VALUE rb_reg_s_alloc(klass) VALUE klass; { NEWOBJ(re, struct RRegexp); OBJSETUP(re, klass, T_REGEXP); re->ptr = 0; re->len = 0; re->str = 0; return (VALUE)re; } VALUE rb_reg_new(s, len, options) const char *s; long len; int options; { VALUE re = rb_reg_s_alloc(rb_cRegexp); rb_reg_initialize(re, s, len, options); return (VALUE)re; } static int case_cache; static int kcode_cache; static VALUE reg_cache; VALUE rb_reg_regcomp(str) VALUE str; { volatile VALUE save_str = str; if (reg_cache && RREGEXP(reg_cache)->len == RSTRING(str)->len && case_cache == ruby_ignorecase && kcode_cache == reg_kcode && memcmp(RREGEXP(reg_cache)->str, RSTRING(str)->ptr, RSTRING(str)->len) == 0) return reg_cache; case_cache = ruby_ignorecase; kcode_cache = reg_kcode; reg_cache = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, ruby_ignorecase); RB_GC_GUARD(save_str); return reg_cache; } static int rb_reg_cur_kcode(re) VALUE re; { if (FL_TEST(re, KCODE_FIXED)) { return RBASIC(re)->flags & KCODE_MASK; } return 0; } /* * call-seq: * rxp.hash => fixnum * * Produce a hash based on the text and options of this regular expression. */ static VALUE rb_reg_hash(re) VALUE re; { int hashval, len; char *p; rb_reg_check(re); hashval = RREGEXP(re)->ptr->options; len = RREGEXP(re)->len; p = RREGEXP(re)->str; while (len--) { hashval = hashval * 33 + *p++; } hashval = hashval + (hashval>>5); return INT2FIX(hashval); } /* * call-seq: * rxp == other_rxp => true or false * rxp.eql?(other_rxp) => true or false * * Equality---Two regexps are equal if their patterns are identical, they have * the same character set code, and their casefold? values are the * same. * * /abc/ == /abc/x #=> false * /abc/ == /abc/i #=> false * /abc/u == /abc/n #=> false */ static VALUE rb_reg_equal(re1, re2) VALUE re1, re2; { if (re1 == re2) return Qtrue; if (TYPE(re2) != T_REGEXP) return Qfalse; rb_reg_check(re1); rb_reg_check(re2); if (RREGEXP(re1)->len != RREGEXP(re2)->len) return Qfalse; if (memcmp(RREGEXP(re1)->str, RREGEXP(re2)->str, RREGEXP(re1)->len) == 0 && rb_reg_cur_kcode(re1) == rb_reg_cur_kcode(re2) && RREGEXP(re1)->ptr->options == RREGEXP(re2)->ptr->options) { return Qtrue; } return Qfalse; } /* * call-seq: * rxp.match(str) => matchdata or nil * * Returns a MatchData object describing the match, or * nil if there was no match. This is equivalent to retrieving the * value of the special variable $~ following a normal match. * * /(.)(.)(.)/.match("abc")[2] #=> "b" */ VALUE rb_reg_match(re, str) VALUE re, str; { long start; if (NIL_P(str)) { rb_backref_set(Qnil); return Qnil; } StringValue(str); start = rb_reg_search(re, str, 0, 0); if (start < 0) { return Qnil; } return LONG2FIX(start); } /* * call-seq: * rxp === str => true or false * * Case Equality---Synonym for Regexp#=~ used in case statements. * * a = "HELLO" * case a * when /^[a-z]*$/; print "Lower case\n" * when /^[A-Z]*$/; print "Upper case\n" * else; print "Mixed case\n" * end * * produces: * * Upper case */ VALUE rb_reg_eqq(re, str) VALUE re, str; { long start; if (TYPE(str) != T_STRING) { str = rb_check_string_type(str); if (NIL_P(str)) { rb_backref_set(Qnil); return Qfalse; } } StringValue(str); start = rb_reg_search(re, str, 0, 0); if (start < 0) { return Qfalse; } return Qtrue; } /* * call-seq: * ~ rxp => integer or nil * * Match---Matches rxp against the contents of $_. * Equivalent to rxp =~ $_. * * $_ = "input data" * ~ /at/ #=> 7 */ VALUE rb_reg_match2(re) VALUE re; { long start; VALUE line = rb_lastline_get(); if (TYPE(line) != T_STRING) { rb_backref_set(Qnil); return Qnil; } start = rb_reg_search(re, line, 0, 0); if (start < 0) { return Qnil; } return LONG2FIX(start); } /* * call-seq: * rxp.match(str) => matchdata or nil * * Returns a MatchData object describing the match, or * nil if there was no match. This is equivalent to retrieving the * value of the special variable $~ following a normal match. * * /(.)(.)(.)/.match("abc")[2] #=> "b" */ static VALUE rb_reg_match_m(re, str) VALUE re, str; { VALUE result = rb_reg_match(re, str); if (NIL_P(result)) return Qnil; result = rb_backref_get(); rb_match_busy(result); return result; } /* * Document-method: compile * * Synonym for Regexp.new */ /* * call-seq: * Regexp.new(string [, options [, lang]]) => regexp * Regexp.new(regexp) => regexp * Regexp.compile(string [, options [, lang]]) => regexp * Regexp.compile(regexp) => regexp * * Constructs a new regular expression from pattern, which can be either * a String or a Regexp (in which case that regexp's * options are propagated, and new options may not be specified (a change as of * Ruby 1.8). If options is a Fixnum, it should be one or * more of the constants Regexp::EXTENDED, * Regexp::IGNORECASE, and Regexp::MULTILINE, * or-ed together. Otherwise, if options is not * nil, the regexp will be case insensitive. The lang * parameter enables multibyte support for the regexp: `n', `N' = none, `e', * `E' = EUC, `s', `S' = SJIS, `u', `U' = UTF-8. * * r1 = Regexp.new('^a-z+:\\s+\w+') #=> /^a-z+:\s+\w+/ * r2 = Regexp.new('cat', true) #=> /cat/i * r3 = Regexp.new('dog', Regexp::EXTENDED) #=> /dog/x * r4 = Regexp.new(r2) #=> /cat/i */ static VALUE rb_reg_initialize_m(argc, argv, self) int argc; VALUE *argv; VALUE self; { const char *s; long len; int flags = 0; if (argc == 0 || argc > 3) { rb_raise(rb_eArgError, "wrong number of arguments"); } if (TYPE(argv[0]) == T_REGEXP) { if (argc > 1) { rb_warn("flags%s ignored", (argc == 3) ? " and encoding": ""); } rb_reg_check(argv[0]); flags = RREGEXP(argv[0])->ptr->options & 0xf; if (FL_TEST(argv[0], KCODE_FIXED)) { switch (RBASIC(argv[0])->flags & KCODE_MASK) { case KCODE_NONE: flags |= 16; break; case KCODE_EUC: flags |= 32; break; case KCODE_SJIS: flags |= 48; break; case KCODE_UTF8: flags |= 64; break; default: break; } } s = RREGEXP(argv[0])->str; len = RREGEXP(argv[0])->len; } else { if (argc >= 2) { if (FIXNUM_P(argv[1])) flags = FIX2INT(argv[1]); else if (RTEST(argv[1])) flags = RE_OPTION_IGNORECASE; } if (argc == 3 && !NIL_P(argv[2])) { char *kcode = StringValuePtr(argv[2]); flags &= ~0x70; switch (kcode[0]) { case 'n': case 'N': flags |= 16; break; case 'e': case 'E': flags |= 32; break; case 's': case 'S': flags |= 48; break; case 'u': case 'U': flags |= 64; break; default: break; } } s = StringValuePtr(argv[0]); len = RSTRING(argv[0])->len; } rb_reg_initialize(self, s, len, flags); return self; } VALUE rb_reg_quote(str) VALUE str; { char *s, *send, *t; VALUE tmp; int c; s = RSTRING(str)->ptr; send = s + RSTRING(str)->len; for (; s < send; s++) { c = *s; if (ismbchar(c)) { int n = mbclen(c); while (n-- && s < send) s++; s--; continue; } switch (c) { case '[': case ']': case '{': case '}': case '(': case ')': case '|': case '-': case '*': case '.': case '\\': case '?': case '+': case '^': case '$': case ' ': case '#': case '\t': case '\f': case '\n': case '\r': goto meta_found; } } return rb_str_new3(str); meta_found: tmp = rb_str_new(0, RSTRING(str)->len*2); t = RSTRING(tmp)->ptr; /* copy upto metacharacter */ memcpy(t, RSTRING(str)->ptr, s - RSTRING(str)->ptr); t += s - RSTRING(str)->ptr; for (; s < send; s++) { c = *s; if (ismbchar(c)) { int n = mbclen(c); while (n-- && s < send) *t++ = *s++; s--; continue; } switch (c) { case '[': case ']': case '{': case '}': case '(': case ')': case '|': case '-': case '*': case '.': case '\\': case '?': case '+': case '^': case '$': case '#': *t++ = '\\'; break; case ' ': *t++ = '\\'; *t++ = ' '; continue; case '\t': *t++ = '\\'; *t++ = 't'; continue; case '\n': *t++ = '\\'; *t++ = 'n'; continue; case '\r': *t++ = '\\'; *t++ = 'r'; continue; case '\f': *t++ = '\\'; *t++ = 'f'; continue; } *t++ = c; } rb_str_resize(tmp, t - RSTRING(tmp)->ptr); OBJ_INFECT(tmp, str); return tmp; } /* * call-seq: * Regexp.escape(str) => a_str * Regexp.quote(str) => a_str * * Escapes any characters that would have special meaning in a regular * expression. Returns a new escaped string, or self if no characters are * escaped. For any string, * Regexp.escape(str)=~str will be true. * * Regexp.escape('\\*?{}.') #=> \\\\\*\?\{\}\. */ static VALUE rb_reg_s_quote(argc, argv) int argc; VALUE *argv; { VALUE str, kcode; int kcode_saved = reg_kcode; rb_scan_args(argc, argv, "11", &str, &kcode); if (!NIL_P(kcode)) { rb_set_kcode(StringValuePtr(kcode)); curr_kcode = reg_kcode; reg_kcode = kcode_saved; } StringValue(str); str = rb_reg_quote(str); rb_kcode_reset_option(); return str; } int rb_kcode() { switch (reg_kcode) { case KCODE_EUC: return MBCTYPE_EUC; case KCODE_SJIS: return MBCTYPE_SJIS; case KCODE_UTF8: return MBCTYPE_UTF8; case KCODE_NONE: return MBCTYPE_ASCII; } rb_bug("wrong reg_kcode value (0x%x)", reg_kcode); } static int rb_reg_get_kcode(re) VALUE re; { switch (RBASIC(re)->flags & KCODE_MASK) { case KCODE_NONE: return 16; case KCODE_EUC: return 32; case KCODE_SJIS: return 48; case KCODE_UTF8: return 64; default: return 0; } } int rb_reg_options(re) VALUE re; { int options; rb_reg_check(re); options = RREGEXP(re)->ptr->options & (RE_OPTION_IGNORECASE|RE_OPTION_MULTILINE|RE_OPTION_EXTENDED); if (FL_TEST(re, KCODE_FIXED)) { options |= rb_reg_get_kcode(re); } return options; } static VALUE rb_reg_s_union(self, args0) VALUE self; VALUE args0; { long argc = RARRAY_LEN(args0); if (argc == 0) { VALUE args[1]; args[0] = rb_str_new2("(?!)"); return rb_class_new_instance(1, args, rb_cRegexp); } else if (argc == 1) { VALUE v; v = rb_check_convert_type(rb_ary_entry(args0, 0), T_REGEXP, "Regexp", "to_regexp"); if (!NIL_P(v)) return v; else { VALUE args[1]; args[0] = rb_reg_s_quote(RARRAY_LEN(args0), RARRAY_PTR(args0)); return rb_class_new_instance(1, args, rb_cRegexp); } } else { int i, kcode = -1; VALUE kcode_re = Qnil; VALUE source = rb_str_buf_new(0); VALUE args[3]; for (i = 0; i < argc; i++) { volatile VALUE v; if (0 < i) rb_str_buf_cat2(source, "|"); v = rb_check_convert_type(rb_ary_entry(args0, i), T_REGEXP, "Regexp", "to_regexp"); if (!NIL_P(v)) { if (FL_TEST(v, KCODE_FIXED)) { if (kcode == -1) { kcode_re = v; kcode = RBASIC(v)->flags & KCODE_MASK; } else if ((RBASIC(v)->flags & KCODE_MASK) != kcode) { volatile VALUE str1, str2; str1 = rb_inspect(kcode_re); str2 = rb_inspect(v); rb_raise(rb_eArgError, "mixed kcode: %s and %s", RSTRING(str1)->ptr, RSTRING(str2)->ptr); } } v = rb_reg_to_s(v); } else { args[0] = rb_ary_entry(args0, i); v = rb_reg_s_quote(1, args); } rb_str_buf_append(source, v); } args[0] = source; args[1] = Qnil; switch (kcode) { case -1: args[2] = Qnil; break; case KCODE_NONE: args[2] = rb_str_new2("n"); break; case KCODE_EUC: args[2] = rb_str_new2("e"); break; case KCODE_SJIS: args[2] = rb_str_new2("s"); break; case KCODE_UTF8: args[2] = rb_str_new2("u"); break; } return rb_class_new_instance(3, args, rb_cRegexp); } } /* * call-seq: * Regexp.union(pat1, pat2, ...) => new_regexp * Regexp.union(pats_ary) => new_regexp * * Return a Regexp object that is the union of the given * patterns, i.e., will match any of its parts. The patterns * can be Regexp objects, in which case their options will be preserved, or * Strings. If no patterns are given, returns /(?!)/. * * Regexp.union #=> /(?!)/ * Regexp.union("penzance") #=> /penzance/ * Regexp.union("a+b*c") #=> /a\+b\*c/ * Regexp.union("skiing", "sledding") #=> /skiing|sledding/ * Regexp.union(["skiing", "sledding"]) #=> /skiing|sledding/ * Regexp.union(/dogs/, /cats/i) #=> /(?-mix:dogs)|(?i-mx:cats)/ */ static VALUE rb_reg_s_union_m(VALUE self, VALUE args) { VALUE v; if (RARRAY_LEN(args) == 1 && !NIL_P(v = rb_check_array_type(rb_ary_entry(args, 0)))) { return rb_reg_s_union(self, v); } return rb_reg_s_union(self, args); } /* :nodoc: */ static VALUE rb_reg_init_copy(copy, re) VALUE copy, re; { if (copy == re) return copy; rb_check_frozen(copy); /* need better argument type check */ if (!rb_obj_is_instance_of(re, rb_obj_class(copy))) { rb_raise(rb_eTypeError, "wrong argument type"); } rb_reg_check(re); rb_reg_initialize(copy, RREGEXP(re)->str, RREGEXP(re)->len, rb_reg_options(re)); return copy; } VALUE rb_reg_regsub(str, src, regs) VALUE str, src; struct re_registers *regs; { VALUE val = 0; char *p, *s, *e, c; int no; p = s = RSTRING(str)->ptr; e = s + RSTRING(str)->len; while (s < e) { char *ss = s; c = *s++; if (ismbchar(c)) { s += mbclen(c) - 1; continue; } if (c != '\\' || s == e) continue; if (!val) { val = rb_str_buf_new(ss-p); rb_str_buf_cat(val, p, ss-p); } else { rb_str_buf_cat(val, p, ss-p); } c = *s++; p = s; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': no = c - '0'; break; case '&': no = 0; break; case '`': rb_str_buf_cat(val, RSTRING(src)->ptr, BEG(0)); continue; case '\'': rb_str_buf_cat(val, RSTRING(src)->ptr+END(0), RSTRING(src)->len-END(0)); continue; case '+': no = regs->num_regs-1; while (BEG(no) == -1 && no > 0) no--; if (no == 0) continue; break; case '\\': rb_str_buf_cat(val, s-1, 1); continue; default: rb_str_buf_cat(val, s-2, 2); continue; } if (no >= 0) { if (no >= regs->num_regs) continue; if (BEG(no) == -1) continue; rb_str_buf_cat(val, RSTRING(src)->ptr+BEG(no), END(no)-BEG(no)); } } if (p < e) { if (!val) { val = rb_str_buf_new(e-p); rb_str_buf_cat(val, p, e-p); } else { rb_str_buf_cat(val, p, e-p); } } if (!val) return str; return val; } const char* rb_get_kcode() { switch (reg_kcode) { case KCODE_SJIS: return "SJIS"; case KCODE_EUC: return "EUC"; case KCODE_UTF8: return "UTF8"; default: return "NONE"; } } static VALUE kcode_getter() { return rb_str_new2(rb_get_kcode()); } void rb_set_kcode(code) const char *code; { if (code == 0) goto set_no_conversion; switch (code[0]) { case 'E': case 'e': reg_kcode = KCODE_EUC; re_mbcinit(MBCTYPE_EUC); break; case 'S': case 's': reg_kcode = KCODE_SJIS; re_mbcinit(MBCTYPE_SJIS); break; case 'U': case 'u': reg_kcode = KCODE_UTF8; re_mbcinit(MBCTYPE_UTF8); break; default: case 'N': case 'n': case 'A': case 'a': set_no_conversion: reg_kcode = KCODE_NONE; re_mbcinit(MBCTYPE_ASCII); break; } } static void kcode_setter(val) VALUE val; { may_need_recompile = 1; rb_set_kcode(StringValuePtr(val)); } static VALUE ignorecase_getter() { return ruby_ignorecase?Qtrue:Qfalse; } static void ignorecase_setter(val, id) VALUE val; ID id; { rb_warn("modifying %s is deprecated", rb_id2name(id)); may_need_recompile = 1; ruby_ignorecase = RTEST(val); } static VALUE match_getter() { VALUE match = rb_backref_get(); if (NIL_P(match)) return Qnil; rb_match_busy(match); return match; } static void match_setter(val) VALUE val; { if (!NIL_P(val)) { Check_Type(val, T_MATCH); } rb_backref_set(val); } /* * call-seq: * Regexp.last_match => matchdata * Regexp.last_match(fixnum) => str * * The first form returns the MatchData object generated by the * last successful pattern match. Equivalent to reading the global variable * $~. The second form returns the nth field in this * MatchData object. * * /c(.)t/ =~ 'cat' #=> 0 * Regexp.last_match #=> # * Regexp.last_match(0) #=> "cat" * Regexp.last_match(1) #=> "a" * Regexp.last_match(2) #=> nil */ static VALUE rb_reg_s_last_match(argc, argv) int argc; VALUE *argv; { VALUE nth; if (rb_scan_args(argc, argv, "01", &nth) == 1) { return rb_reg_nth_match(NUM2INT(nth), rb_backref_get()); } return match_getter(); } /* * Document-class: Regexp * * A Regexp holds a regular expression, used to match a pattern * against strings. Regexps are created using the /.../ and * %r{...} literals, and by the Regexp::new * constructor. * */ void Init_Regexp() { rb_eRegexpError = rb_define_class("RegexpError", rb_eStandardError); re_set_casetable(casetable); #if DEFAULT_KCODE == KCODE_EUC re_mbcinit(MBCTYPE_EUC); #else #if DEFAULT_KCODE == KCODE_SJIS re_mbcinit(MBCTYPE_SJIS); #else #if DEFAULT_KCODE == KCODE_UTF8 re_mbcinit(MBCTYPE_UTF8); #else re_mbcinit(MBCTYPE_ASCII); #endif #endif #endif rb_define_virtual_variable("$~", match_getter, match_setter); rb_define_virtual_variable("$&", last_match_getter, 0); rb_define_virtual_variable("$`", prematch_getter, 0); rb_define_virtual_variable("$'", postmatch_getter, 0); rb_define_virtual_variable("$+", last_paren_match_getter, 0); rb_define_virtual_variable("$=", ignorecase_getter, ignorecase_setter); rb_define_virtual_variable("$KCODE", kcode_getter, kcode_setter); rb_define_virtual_variable("$-K", kcode_getter, kcode_setter); rb_cRegexp = rb_define_class("Regexp", rb_cObject); rb_define_alloc_func(rb_cRegexp, rb_reg_s_alloc); rb_define_singleton_method(rb_cRegexp, "compile", rb_class_new_instance, -1); rb_define_singleton_method(rb_cRegexp, "quote", rb_reg_s_quote, -1); rb_define_singleton_method(rb_cRegexp, "escape", rb_reg_s_quote, -1); rb_define_singleton_method(rb_cRegexp, "union", rb_reg_s_union_m, -2); rb_define_singleton_method(rb_cRegexp, "last_match", rb_reg_s_last_match, -1); rb_define_method(rb_cRegexp, "initialize", rb_reg_initialize_m, -1); rb_define_method(rb_cRegexp, "initialize_copy", rb_reg_init_copy, 1); rb_define_method(rb_cRegexp, "hash", rb_reg_hash, 0); rb_define_method(rb_cRegexp, "eql?", rb_reg_equal, 1); rb_define_method(rb_cRegexp, "==", rb_reg_equal, 1); rb_define_method(rb_cRegexp, "=~", rb_reg_match, 1); rb_define_method(rb_cRegexp, "===", rb_reg_eqq, 1); rb_define_method(rb_cRegexp, "~", rb_reg_match2, 0); rb_define_method(rb_cRegexp, "match", rb_reg_match_m, 1); rb_define_method(rb_cRegexp, "to_s", rb_reg_to_s, 0); rb_define_method(rb_cRegexp, "inspect", rb_reg_inspect, 0); rb_define_method(rb_cRegexp, "source", rb_reg_source, 0); rb_define_method(rb_cRegexp, "casefold?", rb_reg_casefold_p, 0); rb_define_method(rb_cRegexp, "options", rb_reg_options_m, 0); rb_define_method(rb_cRegexp, "kcode", rb_reg_kcode_m, 0); rb_define_const(rb_cRegexp, "IGNORECASE", INT2FIX(RE_OPTION_IGNORECASE)); rb_define_const(rb_cRegexp, "EXTENDED", INT2FIX(RE_OPTION_EXTENDED)); rb_define_const(rb_cRegexp, "MULTILINE", INT2FIX(RE_OPTION_MULTILINE)); rb_global_variable(®_cache); rb_cMatch = rb_define_class("MatchData", rb_cObject); rb_define_global_const("MatchingData", rb_cMatch); rb_define_alloc_func(rb_cMatch, match_alloc); rb_undef_method(CLASS_OF(rb_cMatch), "new"); rb_define_method(rb_cMatch, "initialize_copy", match_init_copy, 1); rb_define_method(rb_cMatch, "size", match_size, 0); rb_define_method(rb_cMatch, "length", match_size, 0); rb_define_method(rb_cMatch, "offset", match_offset, 1); rb_define_method(rb_cMatch, "begin", match_begin, 1); rb_define_method(rb_cMatch, "end", match_end, 1); rb_define_method(rb_cMatch, "to_a", match_to_a, 0); rb_define_method(rb_cMatch, "[]", match_aref, -1); rb_define_method(rb_cMatch, "captures", match_captures, 0); rb_define_method(rb_cMatch, "values_at", match_values_at, -1); rb_define_method(rb_cMatch, "select", match_select, -1); rb_define_method(rb_cMatch, "pre_match", rb_reg_match_pre, 0); rb_define_method(rb_cMatch, "post_match", rb_reg_match_post, 0); rb_define_method(rb_cMatch, "to_s", match_to_s, 0); rb_define_method(rb_cMatch, "inspect", match_inspect, 0); rb_define_method(rb_cMatch, "string", match_string, 0); } ================================================ FILE: re.h ================================================ /********************************************************************** re.h - $Author$ $Date$ created at: Thu Sep 30 14:18:32 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #ifndef RE_H #define RE_H #include #include #include "regex.h" typedef struct re_pattern_buffer Regexp; struct RMatch { struct RBasic basic; VALUE str; struct re_registers *regs; }; #define RMATCH(obj) (R_CAST(RMatch)(obj)) #define RMATCH_REGS(obj) (R_CAST(RMatch)(obj)->regs) VALUE rb_reg_regcomp _((VALUE)); long rb_reg_search _((VALUE, VALUE, long, long)); VALUE rb_reg_regsub _((VALUE, VALUE, struct re_registers *)); long rb_reg_adjust_startpos _((VALUE, VALUE, long, long)); void rb_match_busy _((VALUE)); VALUE rb_reg_quote _((VALUE)); RUBY_EXTERN int ruby_ignorecase; int rb_reg_mbclen2 _((unsigned int, VALUE)); #define mbclen2(c,re) rb_reg_mbclen2((c),(re)) #endif ================================================ FILE: regex.c ================================================ /* Extended regular expression matching and search library. Copyright (C) 1993, 94, 95, 96, 97, 98 Free Software Foundation, Inc. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file LGPL. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Multi-byte extension added May, 1993 by t^2 (Takahiro Tanimoto) Last change: May 21, 1993 by t^2 */ /* removed gapped buffer support, multiple syntax support by matz */ /* Perl5 extension added by matz */ /* UTF-8 extension added Jan 16 1999 by Yoshida Masato */ #include "config.h" #ifdef HAVE_STRING_H # include #else # include #endif /* We write fatal error messages on standard error. */ #include /* isalpha(3) etc. are used for the character classes. */ #include #include #ifndef PARAMS # if defined __GNUC__ || (defined __STDC__ && __STDC__) # define PARAMS(args) args # else # define PARAMS(args) () # endif /* GCC. */ #endif /* Not PARAMS. */ #if defined(STDC_HEADERS) # include #else /* We need this for `regex.h', and perhaps for the Emacs include files. */ # include #endif #ifdef HAVE_STDLIB_H # include #endif #if !defined(__STDC__) && !defined(_MSC_VER) # define volatile #endif #ifdef HAVE_PROTOTYPES # define _(args) args #else # define _(args) () #endif #ifdef RUBY_PLATFORM #include "defines.h" #undef xmalloc #undef xrealloc #undef xcalloc #undef xfree # define RUBY extern int rb_prohibit_interrupt; extern int rb_trap_pending; void rb_trap_exec _((void)); # define CHECK_INTS do {\ if (!rb_prohibit_interrupt) {\ if (rb_trap_pending) rb_trap_exec();\ }\ } while (0) #endif /* Make alloca work the best possible way. */ #ifdef __GNUC__ # ifndef atarist # ifndef alloca # define alloca __builtin_alloca # endif # endif /* atarist */ #else # ifdef HAVE_ALLOCA_H # include # else # ifdef _AIX #pragma alloca # else # ifndef alloca /* predefined by HP cc +Olibcalls */ void *alloca (); # endif # endif /* AIX */ # endif /* HAVE_ALLOCA_H */ #endif /* __GNUC__ */ #ifdef HAVE_STRING_H # include #else # include #endif #define xmalloc malloc #define xrealloc realloc #define xcalloc calloc #define xfree free #ifdef C_ALLOCA #define FREE_VARIABLES() alloca(0) #else #define FREE_VARIABLES() #endif #define FREE_AND_RETURN_VOID(stackb) do { \ FREE_VARIABLES(); \ if (stackb != stacka) xfree(stackb); \ return; \ } while(0) #define FREE_AND_RETURN(stackb,val) do { \ FREE_VARIABLES(); \ if (stackb != stacka) xfree(stackb); \ return(val); \ } while(0) #define DOUBLE_STACK(type) do { \ type *stackx; \ unsigned int xlen = stacke - stackb; \ if (stackb == stacka) { \ stackx = (type*)xmalloc(2 * xlen * sizeof(type)); \ if (!stackx) goto memory_exhausted; \ memcpy(stackx, stackb, xlen * sizeof (type)); \ } \ else { \ stackx = (type*)xrealloc(stackb, 2 * xlen * sizeof(type)); \ if (!stackx) goto memory_exhausted; \ } \ /* Rearrange the pointers. */ \ stackp = stackx + (stackp - stackb); \ stackb = stackx; \ stacke = stackb + 2 * xlen; \ } while (0) #define RE_TALLOC(n,t) ((t*)alloca((n)*sizeof(t))) #define TMALLOC(n,t) ((t*)xmalloc((n)*sizeof(t))) #define TREALLOC(s,n,t) (s=((t*)xrealloc(s,(n)*sizeof(t)))) #define EXPAND_FAIL_STACK() DOUBLE_STACK(unsigned char*) #define ENSURE_FAIL_STACK(n) \ do { \ if (stacke - stackp <= (n)) { \ /* if (len > re_max_failures * MAX_NUM_FAILURE_ITEMS) \ { \ FREE_AND_RETURN(stackb,(-2)); \ }*/ \ \ /* Roughly double the size of the stack. */ \ EXPAND_FAIL_STACK(); \ } \ } while (0) /* Get the interface, including the syntax bits. */ #include "regex.h" /* Subroutines for re_compile_pattern. */ static void store_jump _((char*, int, char*)); static void insert_jump _((int, char*, char*, char*)); static void store_jump_n _((char*, int, char*, unsigned)); static void insert_jump_n _((int, char*, char*, char*, unsigned)); /*static void insert_op _((int, char*, char*));*/ static void insert_op_2 _((int, char*, char*, int, int)); static int memcmp_translate _((unsigned char*, unsigned char*, int)); /* Define the syntax stuff, so we can do the \<, \>, etc. */ /* This must be nonzero for the wordchar and notwordchar pattern commands in re_match. */ #define Sword 1 #define Sword2 2 #define SYNTAX(c) re_syntax_table[c] static char re_syntax_table[256]; static void init_syntax_once _((void)); static const unsigned char *translate = 0; static void init_regs _((struct re_registers*, unsigned int)); static void bm_init_skip _((int *, unsigned char*, int, const unsigned char*)); static int current_mbctype = MBCTYPE_ASCII; #undef P #ifdef RUBY #include "util.h" void rb_warn _((const char*, ...)); # define re_warning(x) rb_warn(x) #endif #ifndef re_warning # define re_warning(x) #endif static void init_syntax_once() { register int c; static int done = 0; if (done) return; memset(re_syntax_table, 0, sizeof re_syntax_table); for (c=0; c<=0x7f; c++) if (isalnum(c)) re_syntax_table[c] = Sword; re_syntax_table['_'] = Sword; for (c=0x80; c<=0xff; c++) if (isalnum(c)) re_syntax_table[c] = Sword2; done = 1; } void re_set_casetable(table) const char *table; { translate = (const unsigned char*)table; } /* Jim Meyering writes: "... Some ctype macros are valid only for character codes that isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when using /bin/cc or gcc but without giving an ansi option). So, all ctype uses should be through macros like ISPRINT... If STDC_HEADERS is defined, then autoconf has verified that the ctype macros don't need to be guarded with references to isascii. ... Defining isascii to 1 should let any compiler worth its salt eliminate the && through constant folding." Solaris defines some of these symbols so we must undefine them first. */ #undef ISASCII #if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII) # define ISASCII(c) 1 #else # define ISASCII(c) isascii(c) #endif #ifdef isblank # define ISBLANK(c) (ISASCII(c) && isblank(c)) #else # define ISBLANK(c) ((c) == ' ' || (c) == '\t') #endif #ifdef isgraph # define ISGRAPH(c) (ISASCII(c) && isgraph(c)) #else # define ISGRAPH(c) (ISASCII(c) && isprint(c) && !isspace(c)) #endif #undef ISPRINT #define ISPRINT(c) (ISASCII(c) && isprint(c)) #define ISDIGIT(c) (ISASCII(c) && isdigit(c)) #define ISALNUM(c) (ISASCII(c) && isalnum(c)) #define ISALPHA(c) (ISASCII(c) && isalpha(c)) #define ISCNTRL(c) (ISASCII(c) && iscntrl(c)) #define ISLOWER(c) (ISASCII(c) && islower(c)) #define ISPUNCT(c) (ISASCII(c) && ispunct(c)) #define ISSPACE(c) (ISASCII(c) && isspace(c)) #define ISUPPER(c) (ISASCII(c) && isupper(c)) #define ISXDIGIT(c) (ISASCII(c) && isxdigit(c)) #ifndef NULL # define NULL (void *)0 #endif /* We remove any previous definition of `SIGN_EXTEND_CHAR', since ours (we hope) works properly with all combinations of machines, compilers, `char' and `unsigned char' argument types. (Per Bothner suggested the basic approach.) */ #undef SIGN_EXTEND_CHAR #if __STDC__ # define SIGN_EXTEND_CHAR(c) ((signed char)(c)) #else /* not __STDC__ */ /* As in Harbison and Steele. */ # define SIGN_EXTEND_CHAR(c) ((((unsigned char)(c)) ^ 128) - 128) #endif /* These are the command codes that appear in compiled regular expressions, one per byte. Some command codes are followed by argument bytes. A command code can specify any interpretation whatsoever for its arguments. Zero-bytes may appear in the compiled regular expression. The value of `exactn' is needed in search.c (search_buffer) in emacs. So regex.h defines a symbol `RE_EXACTN_VALUE' to be 1; the value of `exactn' we use here must also be 1. */ enum regexpcode { unused=0, exactn=1, /* Followed by one byte giving n, then by n literal bytes. */ begline, /* Fail unless at beginning of line. */ endline, /* Fail unless at end of line. */ begbuf, /* Succeeds if at beginning of buffer (if emacs) or at beginning of string to be matched (if not). */ endbuf, /* Analogously, for end of buffer/string. */ endbuf2, /* End of buffer/string, or newline just before it. */ begpos, /* Matches where last scan//gsub left off. */ jump, /* Followed by two bytes giving relative address to jump to. */ jump_past_alt,/* Same as jump, but marks the end of an alternative. */ on_failure_jump, /* Followed by two bytes giving relative address of place to resume at in case of failure. */ finalize_jump, /* Throw away latest failure point and then jump to address. */ maybe_finalize_jump, /* Like jump but finalize if safe to do so. This is used to jump back to the beginning of a repeat. If the command that follows this jump is clearly incompatible with the one at the beginning of the repeat, such that we can be sure that there is no use backtracking out of repetitions already completed, then we finalize. */ dummy_failure_jump, /* Jump, and push a dummy failure point. This failure point will be thrown away if an attempt is made to use it for a failure. A + construct makes this before the first repeat. Also use it as an intermediary kind of jump when compiling an or construct. */ push_dummy_failure, /* Push a dummy failure point and continue. Used at the end of alternatives. */ succeed_n, /* Used like on_failure_jump except has to succeed n times; then gets turned into an on_failure_jump. The relative address following it is useless until then. The address is followed by two bytes containing n. */ jump_n, /* Similar to jump, but jump n times only; also the relative address following is in turn followed by yet two more bytes containing n. */ try_next, /* Jump to next pattern for the first time, leaving this pattern on the failure stack. */ finalize_push, /* Finalize stack and push the beginning of the pattern on the stack to retry (used for non-greedy match) */ finalize_push_n, /* Similar to finalize_push, buf finalize n time only */ set_number_at, /* Set the following relative location to the subsequent number. */ anychar, /* Matches any (more or less) one character excluding newlines. */ anychar_repeat, /* Matches sequence of characters excluding newlines. */ charset, /* Matches any one char belonging to specified set. First following byte is number of bitmap bytes. Then come bytes for a bitmap saying which chars are in. Bits in each byte are ordered low-bit-first. A character is in the set if its bit is 1. A character too large to have a bit in the map is automatically not in the set. */ charset_not, /* Same parameters as charset, but match any character that is not one of those specified. */ start_memory, /* Start remembering the text that is matched, for storing in a memory register. Followed by one byte containing the register number. Register numbers must be in the range 0 through RE_NREGS. */ stop_memory, /* Stop remembering the text that is matched and store it in a memory register. Followed by one byte containing the register number. Register numbers must be in the range 0 through RE_NREGS. */ start_paren, /* Place holder at the start of (?:..). */ stop_paren, /* Place holder at the end of (?:..). */ casefold_on, /* Turn on casefold flag. */ casefold_off, /* Turn off casefold flag. */ option_set, /* Turn on multi line match (match with newlines). */ start_nowidth, /* Save string point to the stack. */ stop_nowidth, /* Restore string place at the point start_nowidth. */ pop_and_fail, /* Fail after popping nowidth entry from stack. */ stop_backtrack, /* Restore backtrack stack at the point start_nowidth. */ duplicate, /* Match a duplicate of something remembered. Followed by one byte containing the index of the memory register. */ wordchar, /* Matches any word-constituent character. */ notwordchar, /* Matches any char that is not a word-constituent. */ wordbeg, /* Succeeds if at word beginning. */ wordend, /* Succeeds if at word end. */ wordbound, /* Succeeds if at a word boundary. */ notwordbound /* Succeeds if not at a word boundary. */ }; /* Number of failure points to allocate space for initially, when matching. If this number is exceeded, more space is allocated, so it is not a hard limit. */ #ifndef NFAILURES #define NFAILURES 160 #endif /* Store NUMBER in two contiguous bytes starting at DESTINATION. */ #define STORE_NUMBER(destination, number) \ do { (destination)[0] = (number) & 0377; \ (destination)[1] = (number) >> 8; } while (0) /* Same as STORE_NUMBER, except increment the destination pointer to the byte after where the number is stored. Watch out that values for DESTINATION such as p + 1 won't work, whereas p will. */ #define STORE_NUMBER_AND_INCR(destination, number) \ do { STORE_NUMBER(destination, number); \ (destination) += 2; } while (0) /* Put into DESTINATION a number stored in two contingous bytes starting at SOURCE. */ #define EXTRACT_NUMBER(destination, source) \ do { (destination) = *(source) & 0377; \ (destination) += SIGN_EXTEND_CHAR(*(char*)((source) + 1)) << 8; } while (0) /* Same as EXTRACT_NUMBER, except increment the pointer for source to point to second byte of SOURCE. Note that SOURCE has to be a value such as p, not, e.g., p + 1. */ #define EXTRACT_NUMBER_AND_INCR(destination, source) \ do { EXTRACT_NUMBER(destination, source); \ (source) += 2; } while (0) /* Specify the precise syntax of regexps for compilation. This provides for compatibility for various utilities which historically have different, incompatible syntaxes. The argument SYNTAX is a bit-mask comprised of the various bits defined in regex.h. */ long re_set_syntax(syntax) long syntax; { /* obsolete */ return 0; } /* Macros for re_compile_pattern, which is found below these definitions. */ #define TRANSLATE_P() ((options&RE_OPTION_IGNORECASE) && translate) #define MAY_TRANSLATE() ((bufp->options&(RE_OPTION_IGNORECASE|RE_MAY_IGNORECASE)) && translate) /* Fetch the next character in the uncompiled pattern---translating it if necessary. Also cast from a signed character in the constant string passed to us by the user to an unsigned char that we can use as an array index (in, e.g., `translate'). */ #define PATFETCH(c) \ do {if (p == pend) goto end_of_pattern; \ c = (unsigned char) *p++; \ if (TRANSLATE_P()) c = (unsigned char)translate[c]; \ } while (0) /* Fetch the next character in the uncompiled pattern, with no translation. */ #define PATFETCH_RAW(c) \ do {if (p == pend) goto end_of_pattern; \ c = (unsigned char)*p++; \ } while (0) /* Go backwards one character in the pattern. */ #define PATUNFETCH p-- #define MBC2WC(c, p) \ do { \ if (current_mbctype == MBCTYPE_UTF8) { \ int n = mbclen(c) - 1; \ c &= (1<<(BYTEWIDTH-2-n)) - 1; \ while (n--) { \ c = c << 6 | (*p++ & ((1<<6)-1)); \ } \ } \ else { \ c <<= 8; \ c |= (unsigned char)*(p)++; \ } \ } while (0) #define PATFETCH_MBC(c) \ do { \ if (p + mbclen(c) - 1 >= pend) goto end_of_pattern; \ MBC2WC(c, p); \ } while(0) #define WC2MBC1ST(c) \ ((current_mbctype != MBCTYPE_UTF8) ? ((c<0x100) ? (c) : (((c)>>8)&0xff)) : utf8_firstbyte(c)) typedef unsigned int (*mbc_startpos_func_t) _((const char *string, unsigned int pos)); static unsigned int asc_startpos _((const char *string, unsigned int pos)); static unsigned int euc_startpos _((const char *string, unsigned int pos)); static unsigned int sjis_startpos _((const char *string, unsigned int pos)); static unsigned int utf8_startpos _((const char *string, unsigned int pos)); static const mbc_startpos_func_t mbc_startpos_func[4] = { asc_startpos, euc_startpos, sjis_startpos, utf8_startpos }; #define mbc_startpos(start, pos) (*mbc_startpos_func[current_mbctype])((start), (pos)) static unsigned int utf8_firstbyte(c) unsigned long c; { if (c < 0x80) return c; if (c <= 0x7ff) return ((c>>6)&0xff)|0xc0; if (c <= 0xffff) return ((c>>12)&0xff)|0xe0; if (c <= 0x1fffff) return ((c>>18)&0xff)|0xf0; if (c <= 0x3ffffff) return ((c>>24)&0xff)|0xf8; if (c <= 0x7fffffff) return ((c>>30)&0xff)|0xfc; #if SIZEOF_INT > 4 if (c <= 0xfffffffff) return 0xfe; #else return 0xfe; #endif } #if 0 static void print_mbc(c) unsigned int c; { if (current_mbctype == MBCTYPE_UTF8) { if (c < 0x80) printf("%c", (int)c); else if (c <= 0x7ff) printf("%c%c", (int)utf8_firstbyte(c), (int)(c & 0x3f)); else if (c <= 0xffff) printf("%c%c%c", (int)utf8_firstbyte(c), (int)((c >> 6) & 0x3f), (int)(c & 0x3f)); else if (c <= 0x1fffff) printf("%c%c%c%c", (int)utf8_firstbyte(c), (int)((c >> 12) & 0x3f), (int)((c >> 6) & 0x3f), (int)(c & 0x3f)); else if (c <= 0x3ffffff) printf("%c%c%c%c%c", (int)utf8_firstbyte(c), (int)((c >> 18) & 0x3f), (int)((c >> 12) & 0x3f), (int)((c >> 6) & 0x3f), (int)(c & 0x3f)); else if (c <= 0x7fffffff) printf("%c%c%c%c%c%c", (int)utf8_firstbyte(c), (int)((c >> 24) & 0x3f), (int)((c >> 18) & 0x3f), (int)((c >> 12) & 0x3f), (int)((c >> 6) & 0x3f), (int)(c & 0x3f)); } else if (c < 0xff) { printf("\\%o", (int)c); } else { printf("%c%c", (int)(c >> BYTEWIDTH), (int)(c &0xff)); } } #endif /* If the buffer isn't allocated when it comes in, use this. */ #define INIT_BUF_SIZE 28 /* Make sure we have at least N more bytes of space in buffer. */ #define GET_BUFFER_SPACE(n) \ do { \ while (b - bufp->buffer + (n) >= bufp->allocated) \ EXTEND_BUFFER; \ } while (0) /* Make sure we have one more byte of buffer space and then add CH to it. */ #define BUFPUSH(ch) \ do { \ GET_BUFFER_SPACE(1); \ *b++ = (char)(ch); \ } while (0) /* Extend the buffer by twice its current size via reallociation and reset the pointers that pointed into the old allocation to point to the correct places in the new allocation. If extending the buffer results in it being larger than 1 << 16, then flag memory exhausted. */ #define EXTEND_BUFFER \ do { char *old_buffer = bufp->buffer; \ if (bufp->allocated == (1L<<16)) goto too_big; \ bufp->allocated *= 2; \ if (bufp->allocated > (1L<<16)) bufp->allocated = (1L<<16); \ bufp->buffer = (char*)xrealloc(bufp->buffer, bufp->allocated); \ if (bufp->buffer == 0) \ goto memory_exhausted; \ b = (b - old_buffer) + bufp->buffer; \ if (fixup_alt_jump) \ fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer; \ if (laststart) \ laststart = (laststart - old_buffer) + bufp->buffer; \ begalt = (begalt - old_buffer) + bufp->buffer; \ if (pending_exact) \ pending_exact = (pending_exact - old_buffer) + bufp->buffer; \ } while (0) /* Set the bit for character C in a character set list. */ #define SET_LIST_BIT(c) \ (b[(unsigned char)(c) / BYTEWIDTH] \ |= 1 << ((unsigned char)(c) % BYTEWIDTH)) /* Get the next unsigned number in the uncompiled pattern. */ #define GET_UNSIGNED_NUMBER(num) \ do { if (p != pend) { \ PATFETCH(c); \ while (ISDIGIT(c)) { \ if (num < 0) \ num = 0; \ num = num * 10 + c - '0'; \ if (p == pend) \ break; \ PATFETCH(c); \ } \ } \ } while (0) #define STREQ(s1, s2) ((strcmp(s1, s2) == 0)) #define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ #define IS_CHAR_CLASS(string) \ (STREQ(string, "alpha") || STREQ(string, "upper") \ || STREQ(string, "lower") || STREQ(string, "digit") \ || STREQ(string, "alnum") || STREQ(string, "xdigit") \ || STREQ(string, "space") || STREQ(string, "print") \ || STREQ(string, "punct") || STREQ(string, "graph") \ || STREQ(string, "cntrl") || STREQ(string, "blank")) #define STORE_MBC(p, c) \ do { \ (p)[0] = (unsigned char)(((c) >>24) & 0xff); \ (p)[1] = (unsigned char)(((c) >>16) & 0xff); \ (p)[2] = (unsigned char)(((c) >> 8) & 0xff); \ (p)[3] = (unsigned char)(((c) >> 0) & 0xff); \ } while (0) #define STORE_MBC_AND_INCR(p, c) \ do { \ *(p)++ = (unsigned char)(((c) >>24) & 0xff); \ *(p)++ = (unsigned char)(((c) >>16) & 0xff); \ *(p)++ = (unsigned char)(((c) >> 8) & 0xff); \ *(p)++ = (unsigned char)(((c) >> 0) & 0xff); \ } while (0) #define EXTRACT_MBC(p) \ ((unsigned int)((unsigned char)(p)[0] << 24 | \ (unsigned char)(p)[1] << 16 | \ (unsigned char)(p)[2] << 8 | \ (unsigned char)(p)[3])) #define EXTRACT_MBC_AND_INCR(p) \ ((unsigned int)((p) += 4, \ (unsigned char)(p)[-4] << 24 | \ (unsigned char)(p)[-3] << 16 | \ (unsigned char)(p)[-2] << 8 | \ (unsigned char)(p)[-1])) #define EXTRACT_UNSIGNED(p) \ ((unsigned char)(p)[0] | (unsigned char)(p)[1] << 8) #define EXTRACT_UNSIGNED_AND_INCR(p) \ ((p) += 2, (unsigned char)(p)[-2] | (unsigned char)(p)[-1] << 8) /* Handle (mb)?charset(_not)?. Structure of mbcharset(_not)? in compiled pattern. struct { unsinged char id; mbcharset(_not)? unsigned char sbc_size; unsigned char sbc_map[sbc_size]; same as charset(_not)? up to here. unsigned short mbc_size; number of intervals. struct { unsigned long beg; beginning of interval. unsigned long end; end of interval. } intervals[mbc_size]; }; */ static void set_list_bits(c1, c2, b) unsigned long c1, c2; unsigned char *b; { unsigned char sbc_size = b[-1]; unsigned short mbc_size = EXTRACT_UNSIGNED(&b[sbc_size]); unsigned short beg, end, upb; if (c1 > c2) return; b = &b[sbc_size + 2]; for (beg = 0, upb = mbc_size; beg < upb; ) { unsigned short mid = (unsigned short)(beg + upb) >> 1; if ((int)c1 - 1 > (int)EXTRACT_MBC(&b[mid*8+4])) beg = mid + 1; else upb = mid; } for (end = beg, upb = mbc_size; end < upb; ) { unsigned short mid = (unsigned short)(end + upb) >> 1; if ((int)c2 >= (int)EXTRACT_MBC(&b[mid*8]) - 1) end = mid + 1; else upb = mid; } if (beg != end) { if (c1 > EXTRACT_MBC(&b[beg*8])) c1 = EXTRACT_MBC(&b[beg*8]); if (c2 < EXTRACT_MBC(&b[(end - 1)*8+4])) c2 = EXTRACT_MBC(&b[(end - 1)*8+4]); } if (end < mbc_size && end != beg + 1) /* NOTE: memcpy() would not work here. */ memmove(&b[(beg + 1)*8], &b[end*8], (mbc_size - end)*8); STORE_MBC(&b[beg*8 + 0], c1); STORE_MBC(&b[beg*8 + 4], c2); mbc_size += beg - end + 1; STORE_NUMBER(&b[-2], mbc_size); } static int is_in_list_sbc(c, b) unsigned long c; const unsigned char *b; { unsigned short size; size = *b++; return ((int)c / BYTEWIDTH < (int)size && b[c / BYTEWIDTH] & 1 << c % BYTEWIDTH); } static int is_in_list_mbc(c, b) unsigned long c; const unsigned char *b; { unsigned short size; unsigned short i, j; size = *b++; b += size + 2; size = EXTRACT_UNSIGNED(&b[-2]); if (size == 0) return 0; for (i = 0, j = size; i < j; ) { unsigned short k = (unsigned short)(i + j) >> 1; if (c > EXTRACT_MBC(&b[k*8+4])) i = k + 1; else j = k; } if (i < size && EXTRACT_MBC(&b[i*8]) <= c) return 1; return 0; } static int is_in_list(c, b) unsigned long c; const unsigned char *b; { return is_in_list_sbc(c, b) || (current_mbctype ? is_in_list_mbc(c, b) : 0); } #if 0 static void print_partial_compiled_pattern(start, end) unsigned char *start; unsigned char *end; { int mcnt, mcnt2; unsigned char *p = start; unsigned char *pend = end; if (start == NULL) { printf("(null)\n"); return; } /* Loop over pattern commands. */ while (p < pend) { switch ((enum regexpcode)*p++) { case unused: printf("/unused"); break; case exactn: mcnt = *p++; printf("/exactn/%d", mcnt); do { putchar('/'); printf("%c", *p++); } while (--mcnt); break; case start_memory: mcnt = *p++; printf("/start_memory/%d/%d", mcnt, *p++); break; case stop_memory: mcnt = *p++; printf("/stop_memory/%d/%d", mcnt, *p++); break; case start_paren: printf("/start_paren"); break; case stop_paren: printf("/stop_paren"); break; case casefold_on: printf("/casefold_on"); break; case casefold_off: printf("/casefold_off"); break; case option_set: printf("/option_set/%d", *p++); break; case start_nowidth: EXTRACT_NUMBER_AND_INCR(mcnt, p); printf("/start_nowidth//%d", mcnt); break; case stop_nowidth: printf("/stop_nowidth//"); p += 2; break; case pop_and_fail: printf("/pop_and_fail"); break; case stop_backtrack: printf("/stop_backtrack//"); p += 2; break; case duplicate: printf("/duplicate/%d", *p++); break; case anychar: printf("/anychar"); break; case anychar_repeat: printf("/anychar_repeat"); break; case charset: case charset_not: { register int c; printf("/charset%s", (enum regexpcode)*(p - 1) == charset_not ? "_not" : ""); mcnt = *p++; printf("/%d", mcnt); for (c = 0; c < mcnt; c++) { unsigned bit; unsigned char map_byte = p[c]; putchar('/'); for (bit = 0; bit < BYTEWIDTH; bit++) if (map_byte & (1 << bit)) printf("%c", c * BYTEWIDTH + bit); } p += mcnt; mcnt = EXTRACT_UNSIGNED_AND_INCR(p); putchar('/'); while (mcnt--) { print_mbc(EXTRACT_MBC_AND_INCR(p)); putchar('-'); print_mbc(EXTRACT_MBC_AND_INCR(p)); } break; } case begline: printf("/begline"); break; case endline: printf("/endline"); break; case on_failure_jump: EXTRACT_NUMBER_AND_INCR(mcnt, p); printf("/on_failure_jump//%d", mcnt); break; case dummy_failure_jump: EXTRACT_NUMBER_AND_INCR(mcnt, p); printf("/dummy_failure_jump//%d", mcnt); break; case push_dummy_failure: printf("/push_dummy_failure"); break; case finalize_jump: EXTRACT_NUMBER_AND_INCR(mcnt, p); printf("/finalize_jump//%d", mcnt); break; case maybe_finalize_jump: EXTRACT_NUMBER_AND_INCR(mcnt, p); printf("/maybe_finalize_jump//%d", mcnt); break; case jump_past_alt: EXTRACT_NUMBER_AND_INCR(mcnt, p); printf("/jump_past_alt//%d", mcnt); break; case jump: EXTRACT_NUMBER_AND_INCR(mcnt, p); printf("/jump//%d", mcnt); break; case succeed_n: EXTRACT_NUMBER_AND_INCR(mcnt, p); EXTRACT_NUMBER_AND_INCR(mcnt2, p); printf("/succeed_n//%d//%d", mcnt, mcnt2); break; case jump_n: EXTRACT_NUMBER_AND_INCR(mcnt, p); EXTRACT_NUMBER_AND_INCR(mcnt2, p); printf("/jump_n//%d//%d", mcnt, mcnt2); break; case set_number_at: EXTRACT_NUMBER_AND_INCR(mcnt, p); EXTRACT_NUMBER_AND_INCR(mcnt2, p); printf("/set_number_at//%d//%d", mcnt, mcnt2); break; case try_next: EXTRACT_NUMBER_AND_INCR(mcnt, p); printf("/try_next//%d", mcnt); break; case finalize_push: EXTRACT_NUMBER_AND_INCR(mcnt, p); printf("/finalize_push//%d", mcnt); break; case finalize_push_n: EXTRACT_NUMBER_AND_INCR(mcnt, p); EXTRACT_NUMBER_AND_INCR(mcnt2, p); printf("/finalize_push_n//%d//%d", mcnt, mcnt2); break; case wordbound: printf("/wordbound"); break; case notwordbound: printf("/notwordbound"); break; case wordbeg: printf("/wordbeg"); break; case wordend: printf("/wordend"); case wordchar: printf("/wordchar"); break; case notwordchar: printf("/notwordchar"); break; case begbuf: printf("/begbuf"); break; case endbuf: printf("/endbuf"); break; case endbuf2: printf("/endbuf2"); break; case begpos: printf("/begpos"); break; default: printf("?%d", *(p-1)); } } printf("/\n"); } static void print_compiled_pattern(bufp) struct re_pattern_buffer *bufp; { unsigned char *buffer = (unsigned char*)bufp->buffer; print_partial_compiled_pattern(buffer, buffer + bufp->used); } #endif static char* calculate_must_string(start, end) char *start; char *end; { int mcnt; int max = 0; unsigned char *p = (unsigned char *)start; unsigned char *pend = (unsigned char *)end; char *must = 0; if (start == NULL) return 0; /* Loop over pattern commands. */ while (p < pend) { switch ((enum regexpcode)*p++) { case unused: break; case exactn: mcnt = *p; if (mcnt > max) { must = (char *)p; max = mcnt; } p += mcnt+1; break; case start_memory: case stop_memory: p += 2; break; case duplicate: case option_set: p++; break; case casefold_on: case casefold_off: return 0; /* should not check must_string */ case pop_and_fail: case anychar: case anychar_repeat: case begline: case endline: case wordbound: case notwordbound: case wordbeg: case wordend: case wordchar: case notwordchar: case begbuf: case endbuf: case endbuf2: case begpos: case push_dummy_failure: case start_paren: case stop_paren: break; case charset: case charset_not: mcnt = *p++; p += mcnt; mcnt = EXTRACT_UNSIGNED_AND_INCR(p); while (mcnt--) { p += 8; } break; case on_failure_jump: EXTRACT_NUMBER_AND_INCR(mcnt, p); if (mcnt > 0) p += mcnt; if ((enum regexpcode)p[-3] == jump) { p -= 2; EXTRACT_NUMBER_AND_INCR(mcnt, p); if (mcnt > 0) p += mcnt; } break; case dummy_failure_jump: case succeed_n: case try_next: case jump: EXTRACT_NUMBER_AND_INCR(mcnt, p); if (mcnt > 0) p += mcnt; break; case start_nowidth: case stop_nowidth: case stop_backtrack: case finalize_jump: case maybe_finalize_jump: case finalize_push: p += 2; break; case jump_n: case set_number_at: case finalize_push_n: p += 4; break; default: break; } } return must; } static unsigned int read_backslash(c) int c; { switch (c) { case 'n': return '\n'; case 't': return '\t'; case 'r': return '\r'; case 'f': return '\f'; case 'v': return '\v'; case 'a': return '\007'; case 'b': return '\010'; case 'e': return '\033'; } return c; } static unsigned int read_special(p, pend, pp) const char *p, *pend, **pp; { int c; PATFETCH_RAW(c); switch (c) { case 'M': PATFETCH_RAW(c); if (c != '-') return -1; PATFETCH_RAW(c); *pp = p; if (c == '\\') { return read_special(--p, pend, pp) | 0x80; } else if (c == -1) return ~0; else { return ((c & 0xff) | 0x80); } case 'C': PATFETCH_RAW(c); if (c != '-') return ~0; case 'c': PATFETCH_RAW(c); *pp = p; if (c == '\\') { c = read_special(--p, pend, pp); } else if (c == '?') return 0177; else if (c == -1) return ~0; return c & 0x9f; default: *pp = p + 1; return read_backslash(c); } end_of_pattern: return ~0; } /* re_compile_pattern takes a regular-expression string and converts it into a buffer full of byte commands for matching. PATTERN is the address of the pattern string SIZE is the length of it. BUFP is a struct re_pattern_buffer * which points to the info on where to store the byte commands. This structure contains a char * which points to the actual space, which should have been obtained with malloc. re_compile_pattern may use realloc to grow the buffer space. The number of bytes of commands can be found out by looking in the `struct re_pattern_buffer' that bufp pointed to, after re_compile_pattern returns. */ const char * re_compile_pattern(pattern, size, bufp) const char *pattern; int size; struct re_pattern_buffer *bufp; { register char *b = bufp->buffer; register const char *p = pattern; const char *nextp; const char *pend = pattern + size; register unsigned int c, c1 = 0; const char *p0; int numlen; #define ERROR_MSG_MAX_SIZE 200 static char error_msg[ERROR_MSG_MAX_SIZE+1]; /* Address of the count-byte of the most recently inserted `exactn' command. This makes it possible to tell whether a new exact-match character can be added to that command or requires a new `exactn' command. */ char *pending_exact = 0; /* Address of the place where a forward-jump should go to the end of the containing expression. Each alternative of an `or', except the last, ends with a forward-jump of this sort. */ char *fixup_alt_jump = 0; /* Address of start of the most recently finished expression. This tells postfix * where to find the start of its operand. */ char *laststart = 0; /* In processing a repeat, 1 means zero matches is allowed. */ char zero_times_ok; /* In processing a repeat, 1 means many matches is allowed. */ char many_times_ok; /* In processing a repeat, 1 means non-greedy matches. */ char greedy; /* Address of beginning of regexp, or inside of last (. */ char *begalt = b; /* Place in the uncompiled pattern (i.e., the {) to which to go back if the interval is invalid. */ const char *beg_interval; /* In processing an interval, at least this many matches must be made. */ int lower_bound; /* In processing an interval, at most this many matches can be made. */ int upper_bound; /* Stack of information saved by ( and restored by ). Five stack elements are pushed by each (: First, the value of b. Second, the value of fixup_alt_jump. Third, the value of begalt. Fourth, the value of regnum. Fifth, the type of the paren. */ int stacka[40]; int *stackb = stacka; int *stackp = stackb; int *stacke = stackb + 40; /* Counts ('s as they are encountered. Remembered for the matching ), where it becomes the register number to put in the stop_memory command. */ int regnum = 1; int range = 0; int had_mbchar = 0; int had_num_literal = 0; int had_char_class = 0; int options = bufp->options; bufp->fastmap_accurate = 0; bufp->must = 0; bufp->must_skip = 0; /* Initialize the syntax table. */ init_syntax_once(); if (bufp->allocated == 0) { bufp->allocated = INIT_BUF_SIZE; /* EXTEND_BUFFER loses when bufp->allocated is 0. */ bufp->buffer = (char*)xrealloc(bufp->buffer, INIT_BUF_SIZE); if (!bufp->buffer) goto memory_exhausted; /* this not happen */ begalt = b = bufp->buffer; } while (p != pend) { PATFETCH(c); switch (c) { case '$': if (bufp->options & RE_OPTION_SINGLELINE) { BUFPUSH(endbuf); } else { p0 = p; /* When testing what follows the $, look past the \-constructs that don't consume anything. */ while (p0 != pend) { if (*p0 == '\\' && p0 + 1 != pend && (p0[1] == 'b' || p0[1] == 'B')) p0 += 2; else break; } BUFPUSH(endline); } break; case '^': if (bufp->options & RE_OPTION_SINGLELINE) BUFPUSH(begbuf); else BUFPUSH(begline); break; case '+': case '?': case '*': /* If there is no previous pattern, char not special. */ if (!laststart) { snprintf(error_msg, ERROR_MSG_MAX_SIZE, "invalid regular expression; there's no previous pattern, to which '%c' would define cardinality at %d", c, p-pattern); FREE_AND_RETURN(stackb, error_msg); } /* If there is a sequence of repetition chars, collapse it down to just one. */ zero_times_ok = c != '+'; many_times_ok = c != '?'; greedy = 1; if (p != pend) { PATFETCH(c); switch (c) { case '?': greedy = 0; break; case '*': case '+': goto nested_meta; default: PATUNFETCH; break; } } repeat: /* Star, etc. applied to an empty pattern is equivalent to an empty pattern. */ if (!laststart) break; if (greedy && many_times_ok && *laststart == anychar && b - laststart <= 2) { if (b[-1] == stop_paren) b--; if (zero_times_ok) *laststart = anychar_repeat; else { BUFPUSH(anychar_repeat); } break; } /* Now we know whether or not zero matches is allowed and also whether or not two or more matches is allowed. */ if (many_times_ok) { /* If more than one repetition is allowed, put in at the end a backward relative jump from b to before the next jump we're going to put in below (which jumps from laststart to after this jump). */ GET_BUFFER_SPACE(3); store_jump(b,greedy?maybe_finalize_jump:finalize_push,laststart-3); b += 3; /* Because store_jump put stuff here. */ } /* On failure, jump from laststart to next pattern, which will be the end of the buffer after this jump is inserted. */ GET_BUFFER_SPACE(3); insert_jump(on_failure_jump, laststart, b + 3, b); b += 3; if (zero_times_ok) { if (greedy == 0) { GET_BUFFER_SPACE(3); insert_jump(try_next, laststart, b + 3, b); b += 3; } } else { /* At least one repetition is required, so insert a `dummy_failure_jump' before the initial `on_failure_jump' instruction of the loop. This effects a skip over that instruction the first time we hit that loop. */ GET_BUFFER_SPACE(3); insert_jump(dummy_failure_jump, laststart, laststart + 6, b); b += 3; } break; case '.': laststart = b; BUFPUSH(anychar); break; case '[': if (p == pend) FREE_AND_RETURN(stackb, "invalid regular expression; '[' can't be the last character ie. can't start range at the end of pattern"); while ((b - bufp->buffer + 9 + (1 << BYTEWIDTH) / BYTEWIDTH) > bufp->allocated) EXTEND_BUFFER; laststart = b; if (*p == '^') { BUFPUSH(charset_not); p++; } else BUFPUSH(charset); p0 = p; BUFPUSH((1 << BYTEWIDTH) / BYTEWIDTH); /* Clear the whole map */ memset(b, 0, (1 << BYTEWIDTH) / BYTEWIDTH + 2); had_mbchar = 0; had_num_literal = 0; had_char_class = 0; /* Read in characters and ranges, setting map bits. */ for (;;) { int size; unsigned last = (unsigned)-1; if ((size = EXTRACT_UNSIGNED(&b[(1 << BYTEWIDTH) / BYTEWIDTH])) || current_mbctype) { /* Ensure the space is enough to hold another interval of multi-byte chars in charset(_not)?. */ size = (1 << BYTEWIDTH) / BYTEWIDTH + 2 + size*8 + 8; while (b + size + 1 > bufp->buffer + bufp->allocated) EXTEND_BUFFER; } range_retry: if (range && had_char_class) { FREE_AND_RETURN(stackb, "invalid regular expression; can't use character class as an end value of range"); } PATFETCH_RAW(c); if (c == ']') { if (p == p0 + 1) { if (p == pend) FREE_AND_RETURN(stackb, "invalid regular expression; empty character class"); re_warning("character class has `]' without escape"); } else /* Stop if this isn't merely a ] inside a bracket expression, but rather the end of a bracket expression. */ break; } /* Look ahead to see if it's a range when the last thing was a character class. */ if (had_char_class && c == '-' && *p != ']') FREE_AND_RETURN(stackb, "invalid regular expression; can't use character class as a start value of range"); if (ismbchar(c)) { PATFETCH_MBC(c); had_mbchar++; } had_char_class = 0; if (c == '-' && ((p != p0 + 1 && *p != ']') || (p[0] == '-' && p[1] != ']') || range)) re_warning("character class has `-' without escape"); if (c == '[' && *p != ':') re_warning("character class has `[' without escape"); /* \ escapes characters when inside [...]. */ if (c == '\\') { PATFETCH_RAW(c); switch (c) { case 'w': for (c = 0; c < (1 << BYTEWIDTH); c++) { if (SYNTAX(c) == Sword || (!current_mbctype && SYNTAX(c) == Sword2)) SET_LIST_BIT(c); } if (current_mbctype) { set_list_bits(0x80, 0xffffffff, b); } had_char_class = 1; last = -1; continue; case 'W': for (c = 0; c < (1 << BYTEWIDTH); c++) { if (SYNTAX(c) != Sword && ((current_mbctype && !re_mbctab[c]) || (!current_mbctype && SYNTAX(c) != Sword2))) SET_LIST_BIT(c); } had_char_class = 1; last = -1; continue; case 's': for (c = 0; c < 256; c++) if (ISSPACE(c)) SET_LIST_BIT(c); had_char_class = 1; last = -1; continue; case 'S': for (c = 0; c < 256; c++) if (!ISSPACE(c)) SET_LIST_BIT(c); if (current_mbctype) set_list_bits(0x80, 0xffffffff, b); had_char_class = 1; last = -1; continue; case 'd': for (c = '0'; c <= '9'; c++) SET_LIST_BIT(c); had_char_class = 1; last = -1; continue; case 'D': for (c = 0; c < 256; c++) if (!ISDIGIT(c)) SET_LIST_BIT(c); if (current_mbctype) set_list_bits(0x80, 0xffffffff, b); had_char_class = 1; last = -1; continue; case 'x': c = scan_hex(p, 2, &numlen); if (numlen == 0) goto invalid_escape; p += numlen; had_num_literal = 1; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': PATUNFETCH; c = scan_oct(p, 3, &numlen); p += numlen; had_num_literal = 1; break; case 'M': case 'C': case 'c': { const char *pp; --p; c = read_special(p, pend, &pp); if (c > 255) goto invalid_escape; p = pp; had_num_literal = 1; } break; default: c = read_backslash(c); if (ismbchar(c)) { PATFETCH_MBC(c); had_mbchar++; } break; } } else if (c == '[' && *p == ':') { /* [:...:] */ /* Leave room for the null. */ char str[CHAR_CLASS_MAX_LENGTH + 1]; PATFETCH_RAW(c); c1 = 0; /* If pattern is `[[:'. */ if (p == pend) FREE_AND_RETURN(stackb, "invalid regular expression; re can't end '[[:'"); for (;;) { PATFETCH_RAW(c); if (c == ':' || c == ']' || p == pend || c1 == CHAR_CLASS_MAX_LENGTH) break; str[c1++] = c; } str[c1] = '\0'; /* If isn't a word bracketed by `[:' and `:]': undo the ending character, the letters, and the leading `:' and `['. */ if (c == ':' && *p == ']') { int ch; char is_alnum = STREQ(str, "alnum"); char is_alpha = STREQ(str, "alpha"); char is_blank = STREQ(str, "blank"); char is_cntrl = STREQ(str, "cntrl"); char is_digit = STREQ(str, "digit"); char is_graph = STREQ(str, "graph"); char is_lower = STREQ(str, "lower"); char is_print = STREQ(str, "print"); char is_punct = STREQ(str, "punct"); char is_space = STREQ(str, "space"); char is_upper = STREQ(str, "upper"); char is_xdigit = STREQ(str, "xdigit"); if (!IS_CHAR_CLASS(str)){ snprintf(error_msg, ERROR_MSG_MAX_SIZE, "invalid regular expression; [:%s:] is not a character class", str); FREE_AND_RETURN(stackb, error_msg); } /* Throw away the ] at the end of the character class. */ PATFETCH(c); if (p == pend) FREE_AND_RETURN(stackb, "invalid regular expression; range doesn't have ending ']' after a character class"); for (ch = 0; ch < 1 << BYTEWIDTH; ch++) { if ( (is_alnum && ISALNUM(ch)) || (is_alpha && ISALPHA(ch)) || (is_blank && ISBLANK(ch)) || (is_cntrl && ISCNTRL(ch)) || (is_digit && ISDIGIT(ch)) || (is_graph && ISGRAPH(ch)) || (is_lower && ISLOWER(ch)) || (is_print && ISPRINT(ch)) || (is_punct && ISPUNCT(ch)) || (is_space && ISSPACE(ch)) || (is_upper && ISUPPER(ch)) || (is_xdigit && ISXDIGIT(ch))) SET_LIST_BIT(ch); } had_char_class = 1; continue; } else { c1 += 2; while (c1--) PATUNFETCH; re_warning("character class has `[' without escape"); c = '['; } } /* Get a range. */ if (range) { if (last > c) goto invalid_pattern; range = 0; if (had_mbchar == 0) { if (TRANSLATE_P()) { for (;last<=c;last++) SET_LIST_BIT(translate[last]); } else { for (;last<=c;last++) SET_LIST_BIT(last); } } else if (had_mbchar == 2) { set_list_bits(last, c, b); } else { /* restriction: range between sbc and mbc */ goto invalid_pattern; } } else if (p[0] == '-' && p[1] != ']') { last = c; PATFETCH_RAW(c1); range = 1; goto range_retry; } else { if (TRANSLATE_P() && c < 0x100) c = (unsigned char)translate[c]; if (had_mbchar == 0 && (!current_mbctype || !had_num_literal)) { SET_LIST_BIT(c); had_num_literal = 0; } else { set_list_bits(c, c, b); } } had_mbchar = 0; } /* Discard any character set/class bitmap bytes that are all 0 at the end of the map. Decrement the map-length byte too. */ while ((int)b[-1] > 0 && b[b[-1] - 1] == 0) b[-1]--; if (b[-1] != (1 << BYTEWIDTH) / BYTEWIDTH) memmove(&b[(unsigned char)b[-1]], &b[(1 << BYTEWIDTH) / BYTEWIDTH], 2 + EXTRACT_UNSIGNED(&b[(1 << BYTEWIDTH) / BYTEWIDTH])*8); b += b[-1] + 2 + EXTRACT_UNSIGNED(&b[(unsigned char)b[-1]])*8; had_num_literal = 0; break; case '(': { int old_options = options; int push_option = 0; int casefold = 0; PATFETCH(c); if (c == '?') { int negative = 0; PATFETCH_RAW(c); switch (c) { case 'x': case 'm': case 'i': case '-': for (;;) { switch (c) { case '-': negative = 1; break; case ':': case ')': break; case 'x': if (negative) options &= ~RE_OPTION_EXTENDED; else options |= RE_OPTION_EXTENDED; break; case 'm': if (negative) { if (options&RE_OPTION_MULTILINE) { options &= ~RE_OPTION_MULTILINE; } } else if (!(options&RE_OPTION_MULTILINE)) { options |= RE_OPTION_MULTILINE; } push_option = 1; break; case 'i': if (negative) { if (options&RE_OPTION_IGNORECASE) { options &= ~RE_OPTION_IGNORECASE; } } else if (!(options&RE_OPTION_IGNORECASE)) { options |= RE_OPTION_IGNORECASE; } casefold = 1; break; default: FREE_AND_RETURN(stackb, "undefined (?...) inline option"); } if (c == ')') { c = '#'; /* read whole in-line options */ break; } if (c == ':') break; PATFETCH_RAW(c); } break; case '#': for (;;) { PATFETCH(c); if (c == ')') break; } c = '#'; break; case ':': case '=': case '!': case '>': break; default: FREE_AND_RETURN(stackb, "undefined (?...) sequence"); } } else { PATUNFETCH; c = '('; } if (c == '#') { if (push_option) { BUFPUSH(option_set); BUFPUSH(options); } if (casefold) { if (options & RE_OPTION_IGNORECASE) BUFPUSH(casefold_on); else BUFPUSH(casefold_off); } break; } if (stackp+8 >= stacke) { DOUBLE_STACK(int); } /* Laststart should point to the start_memory that we are about to push (unless the pattern has RE_NREGS or more ('s). */ /* obsolete: now RE_NREGS is just a default register size. */ *stackp++ = b - bufp->buffer; *stackp++ = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0; *stackp++ = begalt - bufp->buffer; switch (c) { case '(': BUFPUSH(start_memory); BUFPUSH(regnum); *stackp++ = regnum++; *stackp++ = b - bufp->buffer; BUFPUSH(0); /* too many ()'s to fit in a byte. (max 254) */ if (regnum >= RE_REG_MAX) goto too_big; break; case '=': case '!': case '>': BUFPUSH(start_nowidth); *stackp++ = b - bufp->buffer; BUFPUSH(0); /* temporary value */ BUFPUSH(0); if (c != '!') break; BUFPUSH(on_failure_jump); *stackp++ = b - bufp->buffer; BUFPUSH(0); /* temporary value */ BUFPUSH(0); break; case ':': BUFPUSH(start_paren); pending_exact = 0; default: break; } if (push_option) { BUFPUSH(option_set); BUFPUSH(options); } if (casefold) { if (options & RE_OPTION_IGNORECASE) BUFPUSH(casefold_on); else BUFPUSH(casefold_off); } *stackp++ = c; *stackp++ = old_options; fixup_alt_jump = 0; laststart = 0; begalt = b; } break; case ')': if (stackp == stackb) FREE_AND_RETURN(stackb, "unmatched )"); pending_exact = 0; if (fixup_alt_jump) { /* Push a dummy failure point at the end of the alternative for a possible future `finalize_jump' to pop. See comments at `push_dummy_failure' in `re_match'. */ BUFPUSH(push_dummy_failure); /* We allocated space for this jump when we assigned to `fixup_alt_jump', in the `handle_alt' case below. */ store_jump(fixup_alt_jump, jump, b); } if (options != stackp[-1]) { if ((options ^ stackp[-1]) & RE_OPTION_IGNORECASE) { BUFPUSH((options&RE_OPTION_IGNORECASE)?casefold_off:casefold_on); } if ((options ^ stackp[-1]) != RE_OPTION_IGNORECASE) { BUFPUSH(option_set); BUFPUSH(stackp[-1]); } } p0 = b; options = *--stackp; switch (c = *--stackp) { case '(': { char *loc = bufp->buffer + *--stackp; *loc = regnum - stackp[-1]; BUFPUSH(stop_memory); BUFPUSH(stackp[-1]); BUFPUSH(regnum - stackp[-1]); stackp--; } break; case '!': BUFPUSH(pop_and_fail); /* back patch */ STORE_NUMBER(bufp->buffer+stackp[-1], b - bufp->buffer - stackp[-1] - 2); stackp--; /* fall through */ case '=': BUFPUSH(stop_nowidth); /* tell stack-pos place to start_nowidth */ STORE_NUMBER(bufp->buffer+stackp[-1], b - bufp->buffer - stackp[-1] - 2); BUFPUSH(0); /* space to hold stack pos */ BUFPUSH(0); stackp--; break; case '>': BUFPUSH(stop_backtrack); /* tell stack-pos place to start_nowidth */ STORE_NUMBER(bufp->buffer+stackp[-1], b - bufp->buffer - stackp[-1] - 2); BUFPUSH(0); /* space to hold stack pos */ BUFPUSH(0); stackp--; break; case ':': BUFPUSH(stop_paren); break; default: break; } begalt = *--stackp + bufp->buffer; stackp--; fixup_alt_jump = *stackp ? *stackp + bufp->buffer - 1 : 0; laststart = *--stackp + bufp->buffer; if (c == '!' || c == '=') laststart = b; break; case '|': /* Insert before the previous alternative a jump which jumps to this alternative if the former fails. */ GET_BUFFER_SPACE(3); insert_jump(on_failure_jump, begalt, b + 6, b); pending_exact = 0; b += 3; /* The alternative before this one has a jump after it which gets executed if it gets matched. Adjust that jump so it will jump to this alternative's analogous jump (put in below, which in turn will jump to the next (if any) alternative's such jump, etc.). The last such jump jumps to the correct final destination. A picture: _____ _____ | | | | | v | v a | b | c If we are at `b', then fixup_alt_jump right now points to a three-byte space after `a'. We'll put in the jump, set fixup_alt_jump to right after `b', and leave behind three bytes which we'll fill in when we get to after `c'. */ if (fixup_alt_jump) store_jump(fixup_alt_jump, jump_past_alt, b); /* Mark and leave space for a jump after this alternative, to be filled in later either by next alternative or when know we're at the end of a series of alternatives. */ fixup_alt_jump = b; GET_BUFFER_SPACE(3); b += 3; laststart = 0; begalt = b; break; case '{': /* If there is no previous pattern, this is an invalid pattern. */ if (!laststart) { snprintf(error_msg, ERROR_MSG_MAX_SIZE, "invalid regular expression; there's no previous pattern, to which '{' would define cardinality at %d", p-pattern); FREE_AND_RETURN(stackb, error_msg); } if( p == pend) FREE_AND_RETURN(stackb, "invalid regular expression; '{' can't be last character" ); beg_interval = p - 1; lower_bound = -1; /* So can see if are set. */ upper_bound = -1; GET_UNSIGNED_NUMBER(lower_bound); if (c == ',') { GET_UNSIGNED_NUMBER(upper_bound); } else /* Interval such as `{1}' => match exactly once. */ upper_bound = lower_bound; if (lower_bound < 0 || c != '}') goto unfetch_interval; if (lower_bound >= RE_DUP_MAX || upper_bound >= RE_DUP_MAX) FREE_AND_RETURN(stackb, "too big quantifier in {,}"); if (upper_bound < 0) upper_bound = RE_DUP_MAX; if (lower_bound > upper_bound) FREE_AND_RETURN(stackb, "can't do {n,m} with n > m"); beg_interval = 0; pending_exact = 0; greedy = 1; if (p != pend) { PATFETCH(c); if (c == '?') greedy = 0; else PATUNFETCH; } if (lower_bound == 0) { zero_times_ok = 1; if (upper_bound == RE_DUP_MAX) { many_times_ok = 1; goto repeat; } if (upper_bound == 1) { many_times_ok = 0; goto repeat; } } if (lower_bound == 1) { if (upper_bound == 1) { /* No need to repeat */ break; } if (upper_bound == RE_DUP_MAX) { many_times_ok = 1; zero_times_ok = 0; goto repeat; } } /* If upper_bound is zero, don't want to succeed at all; jump from laststart to b + 3, which will be the end of the buffer after this jump is inserted. */ if (upper_bound == 0) { GET_BUFFER_SPACE(3); insert_jump(jump, laststart, b + 3, b); b += 3; break; } /* If lower_bound == upper_bound, repeat count can be removed */ if (lower_bound == upper_bound) { int mcnt; int skip_stop_paren = 0; if (b[-1] == stop_paren) { skip_stop_paren = 1; b--; } if (*laststart == exactn && laststart[1]+2 == b - laststart && laststart[1]*lower_bound < 256) { mcnt = laststart[1]; GET_BUFFER_SPACE((lower_bound-1)*mcnt); laststart[1] = lower_bound*mcnt; while (--lower_bound) { memcpy(b, laststart+2, mcnt); b += mcnt; } if (skip_stop_paren) BUFPUSH(stop_paren); break; } if (lower_bound < 5 && b - laststart < 10) { /* 5 and 10 are the magic numbers */ mcnt = b - laststart; GET_BUFFER_SPACE((lower_bound-1)*mcnt); while (--lower_bound) { memcpy(b, laststart, mcnt); b += mcnt; } if (skip_stop_paren) BUFPUSH(stop_paren); break; } if (skip_stop_paren) b++; /* push back stop_paren */ } /* Otherwise, we have a nontrivial interval. When we're all done, the pattern will look like: set_number_at set_number_at succeed_n jump_n (The upper bound and `jump_n' are omitted if `upper_bound' is 1, though.) */ { /* If the upper bound is > 1, we need to insert more at the end of the loop. */ unsigned nbytes = upper_bound == 1 ? 10 : 20; GET_BUFFER_SPACE(nbytes); /* Initialize lower bound of the `succeed_n', even though it will be set during matching by its attendant `set_number_at' (inserted next), because `re_compile_fastmap' needs to know. Jump to the `jump_n' we might insert below. */ insert_jump_n(succeed_n, laststart, b + (nbytes/2), b, lower_bound); b += 5; /* Just increment for the succeed_n here. */ /* Code to initialize the lower bound. Insert before the `succeed_n'. The `5' is the last two bytes of this `set_number_at', plus 3 bytes of the following `succeed_n'. */ insert_op_2(set_number_at, laststart, b, 5, lower_bound); b += 5; if (upper_bound > 1) { /* More than one repetition is allowed, so append a backward jump to the `succeed_n' that starts this interval. When we've reached this during matching, we'll have matched the interval once, so jump back only `upper_bound - 1' times. */ GET_BUFFER_SPACE(5); store_jump_n(b, greedy?jump_n:finalize_push_n, laststart + 5, upper_bound - 1); b += 5; /* The location we want to set is the second parameter of the `jump_n'; that is `b-2' as an absolute address. `laststart' will be the `set_number_at' we're about to insert; `laststart+3' the number to set, the source for the relative address. But we are inserting into the middle of the pattern -- so everything is getting moved up by 5. Conclusion: (b - 2) - (laststart + 3) + 5, i.e., b - laststart. We insert this at the beginning of the loop so that if we fail during matching, we'll reinitialize the bounds. */ insert_op_2(set_number_at, laststart, b, b - laststart, upper_bound - 1); b += 5; } } break; unfetch_interval: /* If an invalid interval, match the characters as literals. */ re_warning("regexp has invalid interval"); p = beg_interval; beg_interval = 0; /* normal_char and normal_backslash need `c'. */ PATFETCH(c); goto normal_char; case '\\': if (p == pend) FREE_AND_RETURN(stackb, "invalid regular expression; '\\' can't be last character"); /* Do not translate the character after the \, so that we can distinguish, e.g., \B from \b, even if we normally would translate, e.g., B to b. */ PATFETCH_RAW(c); switch (c) { case 's': case 'S': case 'd': case 'D': while (b - bufp->buffer + 9 + (1 << BYTEWIDTH) / BYTEWIDTH > bufp->allocated) EXTEND_BUFFER; laststart = b; if (c == 's' || c == 'd') { BUFPUSH(charset); } else { BUFPUSH(charset_not); } BUFPUSH((1 << BYTEWIDTH) / BYTEWIDTH); memset(b, 0, (1 << BYTEWIDTH) / BYTEWIDTH + 2); if (c == 's' || c == 'S') { SET_LIST_BIT(' '); SET_LIST_BIT('\t'); SET_LIST_BIT('\n'); SET_LIST_BIT('\r'); SET_LIST_BIT('\f'); } else { char cc; for (cc = '0'; cc <= '9'; cc++) { SET_LIST_BIT(cc); } } while ((int)b[-1] > 0 && b[b[-1] - 1] == 0) b[-1]--; if (b[-1] != (1 << BYTEWIDTH) / BYTEWIDTH) memmove(&b[(unsigned char)b[-1]], &b[(1 << BYTEWIDTH) / BYTEWIDTH], 2 + EXTRACT_UNSIGNED(&b[(1 << BYTEWIDTH) / BYTEWIDTH])*8); b += b[-1] + 2 + EXTRACT_UNSIGNED(&b[(unsigned char)b[-1]])*8; break; case 'w': laststart = b; BUFPUSH(wordchar); break; case 'W': laststart = b; BUFPUSH(notwordchar); break; #ifndef RUBY case '<': BUFPUSH(wordbeg); break; case '>': BUFPUSH(wordend); break; #endif case 'b': BUFPUSH(wordbound); break; case 'B': BUFPUSH(notwordbound); break; case 'A': BUFPUSH(begbuf); break; case 'Z': if ((bufp->options & RE_OPTION_SINGLELINE) == 0) { BUFPUSH(endbuf2); break; } /* fall through */ case 'z': BUFPUSH(endbuf); break; case 'G': BUFPUSH(begpos); break; /* hex */ case 'x': had_mbchar = 0; c = scan_hex(p, 2, &numlen); if (numlen == 0) goto invalid_escape; p += numlen; had_num_literal = 1; goto numeric_char; /* octal */ case '0': had_mbchar = 0; c = scan_oct(p, 2, &numlen); p += numlen; had_num_literal = 1; goto numeric_char; /* back-ref or octal */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': PATUNFETCH; p0 = p; had_mbchar = 0; c1 = 0; GET_UNSIGNED_NUMBER(c1); if (!ISDIGIT(c)) PATUNFETCH; if (9 < c1 && c1 >= regnum) { /* need to get octal */ c = scan_oct(p0, 3, &numlen) & 0xff; p = p0 + numlen; c1 = 0; had_num_literal = 1; goto numeric_char; } laststart = b; BUFPUSH(duplicate); BUFPUSH(c1); break; case 'M': case 'C': case 'c': p0 = --p; c = read_special(p, pend, &p0); if (c > 255) goto invalid_escape; p = p0; had_num_literal = 1; goto numeric_char; default: c = read_backslash(c); goto normal_char; } break; case '#': if (options & RE_OPTION_EXTENDED) { while (p != pend) { PATFETCH(c); if (c == '\n') break; } break; } goto normal_char; case ' ': case '\t': case '\f': case '\r': case '\n': if (options & RE_OPTION_EXTENDED) break; default: if (c == ']') re_warning("regexp has `]' without escape"); else if (c == '}') re_warning("regexp has `}' without escape"); normal_char: /* Expects the character in `c'. */ had_mbchar = 0; if (ismbchar(c)) { had_mbchar = 1; c1 = p - pattern; } numeric_char: nextp = p + mbclen(c) - 1; if (!pending_exact || pending_exact + *pending_exact + 1 != b || *pending_exact >= (c1 ? 0176 : 0177) || (nextp < pend && ( *nextp == '+' || *nextp == '?' || *nextp == '*' || *nextp == '^' || *nextp == '{'))) { laststart = b; BUFPUSH(exactn); pending_exact = b; BUFPUSH(0); } if (had_num_literal || c == 0xff) { BUFPUSH(0xff); (*pending_exact)++; had_num_literal = 0; } BUFPUSH(c); (*pending_exact)++; if (had_mbchar) { int len = mbclen(c) - 1; while (len--) { PATFETCH_RAW(c); BUFPUSH(c); (*pending_exact)++; } } } } if (fixup_alt_jump) store_jump(fixup_alt_jump, jump, b); if (stackp != stackb) FREE_AND_RETURN(stackb, "unmatched ("); /* set optimize flags */ laststart = bufp->buffer; if (laststart != b) { if (*laststart == dummy_failure_jump) laststart += 3; else if (*laststart == try_next) laststart += 3; if (*laststart == anychar_repeat) { bufp->options |= RE_OPTIMIZE_ANCHOR; } } bufp->used = b - bufp->buffer; bufp->re_nsub = regnum; laststart = bufp->buffer; if (laststart != b) { if (*laststart == start_memory) laststart += 3; if (*laststart == exactn) { bufp->options |= RE_OPTIMIZE_EXACTN; bufp->must = laststart+1; } } if (!bufp->must) { bufp->must = calculate_must_string(bufp->buffer, b); } if (current_mbctype == MBCTYPE_SJIS) bufp->options |= RE_OPTIMIZE_NO_BM; else if (bufp->must) { int i; int len = (unsigned char)bufp->must[0]; for (i=1; imust[i] == 0xff || (current_mbctype && ismbchar(bufp->must[i]))) { bufp->options |= RE_OPTIMIZE_NO_BM; break; } } if (!(bufp->options & RE_OPTIMIZE_NO_BM)) { bufp->must_skip = (int *) xmalloc((1 << BYTEWIDTH)*sizeof(int)); bm_init_skip(bufp->must_skip, (unsigned char*)bufp->must+1, (unsigned char)bufp->must[0], (unsigned char*)(MAY_TRANSLATE()?translate:0)); } } bufp->regstart = TMALLOC(regnum, unsigned char*); bufp->regend = TMALLOC(regnum, unsigned char*); bufp->old_regstart = TMALLOC(regnum, unsigned char*); bufp->old_regend = TMALLOC(regnum, unsigned char*); bufp->reg_info = TMALLOC(regnum, register_info_type); bufp->best_regstart = TMALLOC(regnum, unsigned char*); bufp->best_regend = TMALLOC(regnum, unsigned char*); FREE_AND_RETURN(stackb, 0); invalid_pattern: FREE_AND_RETURN(stackb, "invalid regular expression"); end_of_pattern: FREE_AND_RETURN(stackb, "premature end of regular expression"); too_big: FREE_AND_RETURN(stackb, "regular expression too big"); memory_exhausted: FREE_AND_RETURN(stackb, "memory exhausted"); nested_meta: FREE_AND_RETURN(stackb, "nested *?+ in regexp"); invalid_escape: FREE_AND_RETURN(stackb, "Invalid escape character syntax"); } void re_free_pattern(bufp) struct re_pattern_buffer *bufp; { xfree(bufp->buffer); xfree(bufp->fastmap); if (bufp->must_skip) xfree(bufp->must_skip); xfree(bufp->regstart); xfree(bufp->regend); xfree(bufp->old_regstart); xfree(bufp->old_regend); xfree(bufp->best_regstart); xfree(bufp->best_regend); xfree(bufp->reg_info); xfree(bufp); } /* Store a jump of the form . Store in the location FROM a jump operation to jump to relative address FROM - TO. OPCODE is the opcode to store. */ static void store_jump(from, opcode, to) char *from, *to; int opcode; { from[0] = (char)opcode; STORE_NUMBER(from + 1, to - (from + 3)); } /* Open up space before char FROM, and insert there a jump to TO. CURRENT_END gives the end of the storage not in use, so we know how much data to copy up. OP is the opcode of the jump to insert. If you call this function, you must zero out pending_exact. */ static void insert_jump(op, from, to, current_end) int op; char *from, *to, *current_end; { register char *pfrom = current_end; /* Copy from here... */ register char *pto = current_end + 3; /* ...to here. */ while (pfrom != from) *--pto = *--pfrom; store_jump(from, op, to); } /* Store a jump of the form . Store in the location FROM a jump operation to jump to relative address FROM - TO. OPCODE is the opcode to store, N is a number the jump uses, say, to decide how many times to jump. If you call this function, you must zero out pending_exact. */ static void store_jump_n(from, opcode, to, n) char *from, *to; int opcode; unsigned n; { from[0] = (char)opcode; STORE_NUMBER(from + 1, to - (from + 3)); STORE_NUMBER(from + 3, n); } /* Similar to insert_jump, but handles a jump which needs an extra number to handle minimum and maximum cases. Open up space at location FROM, and insert there a jump to TO. CURRENT_END gives the end of the storage in use, so we know how much data to copy up. OP is the opcode of the jump to insert. If you call this function, you must zero out pending_exact. */ static void insert_jump_n(op, from, to, current_end, n) int op; char *from, *to, *current_end; unsigned n; { register char *pfrom = current_end; /* Copy from here... */ register char *pto = current_end + 5; /* ...to here. */ while (pfrom != from) *--pto = *--pfrom; store_jump_n(from, op, to, n); } #if 0 /* Open up space at location THERE, and insert operation OP. CURRENT_END gives the end of the storage in use, so we know how much data to copy up. If you call this function, you must zero out pending_exact. */ static void insert_op(op, there, current_end) int op; char *there, *current_end; { register char *pfrom = current_end; /* Copy from here... */ register char *pto = current_end + 1; /* ...to here. */ while (pfrom != there) *--pto = *--pfrom; there[0] = (char)op; } #endif /* Open up space at location THERE, and insert operation OP followed by NUM_1 and NUM_2. CURRENT_END gives the end of the storage in use, so we know how much data to copy up. If you call this function, you must zero out pending_exact. */ static void insert_op_2(op, there, current_end, num_1, num_2) int op; char *there, *current_end; int num_1, num_2; { register char *pfrom = current_end; /* Copy from here... */ register char *pto = current_end + 5; /* ...to here. */ while (pfrom != there) *--pto = *--pfrom; there[0] = (char)op; STORE_NUMBER(there + 1, num_1); STORE_NUMBER(there + 3, num_2); } #define trans_eq(c1, c2, translate) (translate?(translate[c1]==translate[c2]):((c1)==(c2))) static int slow_match(little, lend, big, bend, translate) const unsigned char *little, *lend; const unsigned char *big, *bend; const unsigned char *translate; { int c; while (little < lend && big < bend) { c = *little++; if (c == 0xff) c = *little++; if (!trans_eq(*big++, c, translate)) break; } if (little == lend) return 1; return 0; } static int slow_search(little, llen, big, blen, translate) const unsigned char *little; int llen; const unsigned char *big; int blen; const char *translate; { const unsigned char *bsave = big; const unsigned char *bend = big + blen; register int c; int fescape = 0; c = *little; if (c == 0xff) { c = little[1]; fescape = 1; } else if (translate && !ismbchar(c)) { c = translate[c]; } while (big < bend) { /* look for first character */ if (fescape) { while (big < bend) { if (*big == c) break; big++; } } else if (translate && !ismbchar(c)) { while (big < bend) { if (ismbchar(*big)) big+=mbclen(*big)-1; else if (translate[*big] == c) break; big++; } } else { while (big < bend) { if (*big == c) break; if (ismbchar(*big)) big+=mbclen(*big)-1; big++; } } if (slow_match(little, little+llen, big, bend, (unsigned char *)translate)) return big - bsave; big+=mbclen(*big); } return -1; } static void bm_init_skip(skip, pat, m, translate) int *skip; unsigned char *pat; int m; const unsigned char *translate; { int j, c; for (c=0; c<256; c++) { skip[c] = m; } if (translate) { for (j=0; j= 0 && translate[big[k]] == translate[little[j]]) { k--; j--; } if (j < 0) return k+1; i += skip[translate[big[i]]]; } return -1; } while (i < blen) { k = i; j = llen-1; while (j >= 0 && big[k] == little[j]) { k--; j--; } if (j < 0) return k+1; i += skip[big[i]]; } return -1; } /* Given a pattern, compute a fastmap from it. The fastmap records which of the (1 << BYTEWIDTH) possible characters can start a string that matches the pattern. This fastmap is used by re_search to skip quickly over totally implausible text. The caller must supply the address of a (1 << BYTEWIDTH)-byte data area as bufp->fastmap. The other components of bufp describe the pattern to be used. */ static int re_compile_fastmap0(bufp) struct re_pattern_buffer *bufp; { unsigned char *pattern = (unsigned char*)bufp->buffer; int size = bufp->used; register char *fastmap = bufp->fastmap; register unsigned char *p = pattern; register unsigned char *pend = pattern + size; register int j, k; unsigned is_a_succeed_n; unsigned char *stacka[NFAILURES]; unsigned char **stackb = stacka; unsigned char **stackp = stackb; unsigned char **stacke = stackb + NFAILURES; int options = bufp->options; memset(fastmap, 0, (1 << BYTEWIDTH)); bufp->fastmap_accurate = 1; bufp->can_be_null = 0; while (p) { is_a_succeed_n = 0; if (p == pend) { bufp->can_be_null = 1; break; } #ifdef SWITCH_ENUM_BUG switch ((int)((enum regexpcode)*p++)) #else switch ((enum regexpcode)*p++) #endif { case exactn: if (p[1] == 0xff) { if (TRANSLATE_P()) fastmap[translate[p[2]]] = 2; else fastmap[p[2]] = 2; bufp->options |= RE_OPTIMIZE_BMATCH; } else if (TRANSLATE_P()) fastmap[translate[p[1]]] = 1; else fastmap[p[1]] = 1; break; case begline: case begbuf: case begpos: case endbuf: case endbuf2: case wordbound: case notwordbound: case wordbeg: case wordend: case pop_and_fail: case push_dummy_failure: case start_paren: case stop_paren: continue; case casefold_on: bufp->options |= RE_MAY_IGNORECASE; options |= RE_OPTION_IGNORECASE; continue; case casefold_off: options &= ~RE_OPTION_IGNORECASE; continue; case option_set: options = *p++; continue; case endline: if (TRANSLATE_P()) fastmap[translate['\n']] = 1; else fastmap['\n'] = 1; if ((options & RE_OPTION_SINGLELINE) == 0 && bufp->can_be_null == 0) bufp->can_be_null = 2; break; case jump_n: case finalize_jump: case maybe_finalize_jump: case jump: case jump_past_alt: case dummy_failure_jump: case finalize_push: case finalize_push_n: EXTRACT_NUMBER_AND_INCR(j, p); p += j; if (j > 0) continue; /* Jump backward reached implies we just went through the body of a loop and matched nothing. Opcode jumped to should be an on_failure_jump. Just treat it like an ordinary jump. For a * loop, it has pushed its failure point already; If so, discard that as redundant. */ if ((enum regexpcode)*p != on_failure_jump && (enum regexpcode)*p != try_next && (enum regexpcode)*p != succeed_n) continue; p++; EXTRACT_NUMBER_AND_INCR(j, p); p += j; if (stackp != stackb && *stackp == p) stackp--; /* pop */ continue; case try_next: case start_nowidth: case stop_nowidth: case stop_backtrack: p += 2; continue; case succeed_n: is_a_succeed_n = 1; /* Get to the number of times to succeed. */ EXTRACT_NUMBER(k, p + 2); /* Increment p past the n for when k != 0. */ if (k != 0) { p += 4; continue; } /* fall through */ case on_failure_jump: EXTRACT_NUMBER_AND_INCR(j, p); if (p + j < pend) { if (stackp == stacke) { EXPAND_FAIL_STACK(); } *++stackp = p + j; /* push */ } else { bufp->can_be_null = 1; } if (is_a_succeed_n) EXTRACT_NUMBER_AND_INCR(k, p); /* Skip the n. */ continue; case set_number_at: p += 4; continue; case start_memory: case stop_memory: p += 2; continue; case duplicate: bufp->can_be_null = 1; if (*p >= bufp->re_nsub) break; fastmap['\n'] = 1; case anychar_repeat: case anychar: for (j = 0; j < (1 << BYTEWIDTH); j++) { if (j != '\n' || (options & RE_OPTION_MULTILINE)) fastmap[j] = 1; } if (bufp->can_be_null) { FREE_AND_RETURN(stackb, 0); } /* Don't return; check the alternative paths so we can set can_be_null if appropriate. */ if ((enum regexpcode)p[-1] == anychar_repeat) { continue; } break; case wordchar: for (j = 0; j < 0x80; j++) { if (SYNTAX(j) == Sword) fastmap[j] = 1; } switch (current_mbctype) { case MBCTYPE_ASCII: for (j = 0x80; j < (1 << BYTEWIDTH); j++) { if (SYNTAX(j) == Sword2) fastmap[j] = 1; } break; case MBCTYPE_EUC: case MBCTYPE_SJIS: case MBCTYPE_UTF8: for (j = 0x80; j < (1 << BYTEWIDTH); j++) { if (re_mbctab[j]) fastmap[j] = 1; } break; } break; case notwordchar: for (j = 0; j < 0x80; j++) if (SYNTAX(j) != Sword) fastmap[j] = 1; switch (current_mbctype) { case MBCTYPE_ASCII: for (j = 0x80; j < (1 << BYTEWIDTH); j++) { if (SYNTAX(j) != Sword2) fastmap[j] = 1; } break; case MBCTYPE_EUC: case MBCTYPE_SJIS: case MBCTYPE_UTF8: for (j = 0x80; j < (1 << BYTEWIDTH); j++) { if (!re_mbctab[j]) fastmap[j] = 1; } break; } break; case charset: /* NOTE: Charset for single-byte chars never contain multi-byte char. See set_list_bits(). */ for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) { int tmp = TRANSLATE_P()?translate[j]:j; fastmap[tmp] = 1; } { unsigned short size; unsigned long c, beg, end; p += p[-1] + 2; size = EXTRACT_UNSIGNED(&p[-2]); for (j = 0; j < (int)size; j++) { c = EXTRACT_MBC(&p[j*8]); beg = WC2MBC1ST(c); c = EXTRACT_MBC(&p[j*8+4]); end = WC2MBC1ST(c); /* set bits for 1st bytes of multi-byte chars. */ while (beg <= end) { /* NOTE: Charset for multi-byte chars might contain single-byte chars. We must reject them. */ if (c < 0x100) { fastmap[beg] = 2; bufp->options |= RE_OPTIMIZE_BMATCH; } else if (ismbchar(beg)) fastmap[beg] = 1; beg++; } } } break; case charset_not: /* S: set of all single-byte chars. M: set of all first bytes that can start multi-byte chars. s: any set of single-byte chars. m: any set of first bytes that can start multi-byte chars. We assume S+M = U. ___ _ _ s+m = (S*s+M*m). */ /* Chars beyond end of map must be allowed */ /* NOTE: Charset_not for single-byte chars might contain multi-byte chars. See set_list_bits(). */ for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) if (!ismbchar(j)) fastmap[j] = 1; for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) { if (!ismbchar(j)) fastmap[j] = 1; } { unsigned short size; unsigned long c, beg; int num_literal = 0; p += p[-1] + 2; size = EXTRACT_UNSIGNED(&p[-2]); if (size == 0) { for (j = 0x80; j < (1 << BYTEWIDTH); j++) if (ismbchar(j)) fastmap[j] = 1; break; } for (j = 0,c = 0;j < (int)size; j++) { unsigned int cc = EXTRACT_MBC(&p[j*8]); beg = WC2MBC1ST(cc); while (c <= beg) { if (ismbchar(c)) fastmap[c] = 1; c++; } cc = EXTRACT_MBC(&p[j*8+4]); if (cc < 0xff) { num_literal = 1; while (c <= cc) { if (ismbchar(c)) fastmap[c] = 1; c++; } } c = WC2MBC1ST(cc); } for (j = c; j < (1 << BYTEWIDTH); j++) { if (num_literal) fastmap[j] = 1; if (ismbchar(j)) fastmap[j] = 1; } } break; case unused: /* pacify gcc -Wall */ break; } /* Get here means we have successfully found the possible starting characters of one path of the pattern. We need not follow this path any farther. Instead, look at the next alternative remembered in the stack. */ if (stackp != stackb) p = *stackp--; /* pop */ else break; } FREE_AND_RETURN(stackb, 0); memory_exhausted: FREE_AND_RETURN(stackb, -2); } void re_compile_fastmap(bufp) struct re_pattern_buffer *bufp; { (void)re_compile_fastmap0(bufp); } /* adjust startpos value to the position between characters. */ int re_mbc_startpos(string, size, startpos, range) const char *string; int size, startpos, range; { int i = mbc_startpos(string, startpos); if (i < startpos) { if (range > 0) { startpos = i + mbclen(string[i]); } else { int len = mbclen(string[i]); if (i + len <= startpos) startpos = i + len; else startpos = i; } } return startpos; } int re_adjust_startpos(bufp, string, size, startpos, range) struct re_pattern_buffer *bufp; const char *string; int size, startpos, range; { /* Update the fastmap now if not correct already. */ if (!bufp->fastmap_accurate) { int ret = re_compile_fastmap0(bufp); if (ret) return ret; } /* Adjust startpos for mbc string */ if (current_mbctype && startpos>0 && !(bufp->options&RE_OPTIMIZE_BMATCH)) { startpos = re_mbc_startpos(string, size, startpos, range); } return startpos; } static int re_match_exec _((struct re_pattern_buffer *, const char *, int, int, int, struct re_registers *)); /* Using the compiled pattern in BUFP->buffer, first tries to match STRING, starting first at index STARTPOS, then at STARTPOS + 1, and so on. RANGE is the number of places to try before giving up. If RANGE is negative, it searches backwards, i.e., the starting positions tried are STARTPOS, STARTPOS - 1, etc. STRING is of SIZE. In REGS, return the indices of STRING that matched the entire BUFP->buffer and its contained subexpressions. The value returned is the position in the strings at which the match was found, or -1 if no match was found, or -2 if error (such as failure stack overflow). */ int re_search(bufp, string, size, startpos, range, regs) struct re_pattern_buffer *bufp; const char *string; int size, startpos, range; struct re_registers *regs; { register char *fastmap = bufp->fastmap; int val, anchor = 0, initpos = startpos; /* Check for out-of-range starting position. */ if (startpos < 0 || startpos > size) return -1; if (!string) { if (size == 0) string = ""; else return -1; } /* Update the fastmap now if not correct already. */ if (fastmap && !bufp->fastmap_accurate) { int ret = re_compile_fastmap0(bufp); if (ret) return ret; } /* If the search isn't to be a backwards one, don't waste time in a search for a pattern that must be anchored. */ if (bufp->used > 0) { switch ((enum regexpcode)bufp->buffer[0]) { case begbuf: begbuf_match: if (range > 0) { if (startpos > 0) return -1; else { val = re_match(bufp, string, size, 0, regs); if (val >= 0) return 0; return val; } } break; case begline: anchor = 1; break; case begpos: val = re_match(bufp, string, size, startpos, regs); if (val >= 0) return startpos; return val; default: break; } } if (bufp->options & RE_OPTIMIZE_ANCHOR) { if (bufp->options&RE_OPTION_MULTILINE && range > 0) { goto begbuf_match; } anchor = 1; } if (bufp->must) { int len = ((unsigned char*)bufp->must)[0]; int pos, pbeg, pend; pbeg = startpos; pend = startpos + range; if (pbeg > pend) { /* swap pbeg,pend */ pos = pend; pend = pbeg; pbeg = pos; } pend = size; if (bufp->options & RE_OPTIMIZE_NO_BM) { pos = slow_search((unsigned char *)(bufp->must+1), len, (unsigned char*)(string+pbeg), pend-pbeg, (char *)(MAY_TRANSLATE()?translate:0)); } else { pos = bm_search((unsigned char *)(bufp->must+1), len, (unsigned char *)(string+pbeg), pend-pbeg, bufp->must_skip, MAY_TRANSLATE()?translate:0); } if (pos == -1) return -1; if (range > 0 && (bufp->options & RE_OPTIMIZE_EXACTN)) { startpos += pos; range -= pos; if (range < 0) return -1; } } for (;;) { /* If a fastmap is supplied, skip quickly over characters that cannot possibly be the start of a match. Note, however, that if the pattern can possibly match the null string, we must test it at each starting point so that we take the first null string we get. */ if (fastmap && startpos < size && bufp->can_be_null != 1 && !(anchor && startpos == 0)) { if (range > 0) { /* Searching forwards. */ register unsigned char *p, c; int irange = range; p = (unsigned char*)string+startpos; while (range > 0) { c = *p++; if (ismbchar(c)) { int len; if (fastmap[c]) break; len = mbclen(c) - 1; while (len--) { c = *p++; range--; if (fastmap[c] == 2) goto startpos_adjust; } } else { if (fastmap[MAY_TRANSLATE() ? translate[c] : c]) break; } range--; } startpos_adjust: startpos += irange - range; } else { /* Searching backwards. */ register unsigned char c; c = string[startpos]; c &= 0xff; if (MAY_TRANSLATE() ? !fastmap[translate[c]] : !fastmap[c]) goto advance; } } if (startpos > size) return -1; if ((anchor || !bufp->can_be_null) && range > 0 && size > 0 && startpos == size) return -1; val = re_match_exec(bufp, string, size, startpos, initpos, regs); if (val >= 0) return startpos; if (val == -2) return -2; #ifndef NO_ALLOCA #ifdef C_ALLOCA alloca(0); #endif /* C_ALLOCA */ #endif /* NO_ALLOCA */ if (range > 0) { if (anchor && startpos < size && (startpos < 1 || string[startpos-1] != '\n')) { while (range > 0 && string[startpos] != '\n') { range--; startpos++; } } } advance: if (!range) break; else if (range > 0) { const char *d = string + startpos; if (ismbchar(*d)) { int len = mbclen(*d) - 1; range-=len, startpos+=len; if (!range) break; } range--, startpos++; } else { range++, startpos--; { const char *s, *d, *p; s = string; d = string + startpos; for (p = d; p-- > s && ismbchar(*p); ) /* --p >= s would not work on 80[12]?86. (when the offset of s equals 0 other than huge model.) */ ; if (!((d - p) & 1)) { if (!range) break; range++, startpos--; } } } } return -1; } /* The following are used for re_match, defined below: */ /* Accessing macros used in re_match: */ #define IS_ACTIVE(R) ((R).bits.is_active) #define MATCHED_SOMETHING(R) ((R).bits.matched_something) /* Macros used by re_match: */ /* I.e., regstart, regend, and reg_info. */ #define NUM_REG_ITEMS 3 /* I.e., ptr and count. */ #define NUM_COUNT_ITEMS 2 /* Individual items aside from the registers. */ #define NUM_NONREG_ITEMS 4 /* We push at most this many things on the stack whenever we fail. The `+ 2' refers to PATTERN_PLACE and STRING_PLACE, which are arguments to the PUSH_FAILURE_POINT macro. */ #define MAX_NUM_FAILURE_ITEMS (num_regs * NUM_REG_ITEMS + NUM_NONREG_ITEMS) /* We push this many things on the stack whenever we fail. */ #define NUM_FAILURE_ITEMS (last_used_reg * NUM_REG_ITEMS + NUM_NONREG_ITEMS + 1) /* This pushes counter information for succeed_n and jump_n */ #define PUSH_FAILURE_COUNT(ptr) \ do { \ int c; \ EXTRACT_NUMBER(c, ptr); \ ENSURE_FAIL_STACK(NUM_COUNT_ITEMS); \ *stackp++ = (unsigned char*)(long)c; \ *stackp++ = (ptr); \ num_failure_counts++; \ } while (0) /* This pushes most of the information about the current state we will want if we ever fail back to it. */ #define PUSH_FAILURE_POINT(pattern_place, string_place) \ do { \ long last_used_reg, this_reg; \ \ /* Find out how many registers are active or have been matched. \ (Aside from register zero, which is only set at the end.) */ \ for (last_used_reg = num_regs-1; last_used_reg > 0; last_used_reg--)\ if (!REG_UNSET(regstart[last_used_reg])) \ break; \ \ ENSURE_FAIL_STACK(NUM_FAILURE_ITEMS); \ *stackp++ = (unsigned char*)(long)num_failure_counts; \ num_failure_counts = 0; \ \ /* Now push the info for each of those registers. */ \ for (this_reg = 1; this_reg <= last_used_reg; this_reg++) { \ *stackp++ = regstart[this_reg]; \ *stackp++ = regend[this_reg]; \ *stackp++ = reg_info[this_reg].word; \ } \ \ /* Push how many registers we saved. */ \ *stackp++ = (unsigned char*)last_used_reg; \ \ *stackp++ = pattern_place; \ *stackp++ = string_place; \ *stackp++ = (unsigned char*)(long)options; /* current option status */ \ *stackp++ = (unsigned char*)0; /* non-greedy flag */ \ } while(0) #define NON_GREEDY ((unsigned char*)1) #define POP_FAILURE_COUNT() \ do { \ unsigned char *ptr = *--stackp; \ int count = (long)*--stackp; \ STORE_NUMBER(ptr, count); \ } while (0) /* This pops what PUSH_FAILURE_POINT pushes. */ #define POP_FAILURE_POINT() \ do { \ long temp; \ stackp -= NUM_NONREG_ITEMS; /* Remove failure points (and flag). */ \ temp = (long)*--stackp; /* How many regs pushed. */ \ temp *= NUM_REG_ITEMS; /* How much to take off the stack. */ \ stackp -= temp; /* Remove the register info. */ \ temp = (long)*--stackp; /* How many counters pushed. */ \ while (temp--) { \ POP_FAILURE_COUNT(); /* Remove the counter info. */ \ } \ num_failure_counts = 0; /* Reset num_failure_counts. */ \ } while(0) /* Registers are set to a sentinel when they haven't yet matched. */ #define REG_UNSET_VALUE ((unsigned char*)-1) #define REG_UNSET(e) ((e) == REG_UNSET_VALUE) #define PREFETCH if (d == dend) goto fail /* Call this when have matched something; it sets `matched' flags for the registers corresponding to the subexpressions of which we currently are inside. */ #define SET_REGS_MATCHED \ do { unsigned this_reg; \ for (this_reg = 0; this_reg < num_regs; this_reg++) { \ if (IS_ACTIVE(reg_info[this_reg])) \ MATCHED_SOMETHING(reg_info[this_reg]) = 1; \ else \ MATCHED_SOMETHING(reg_info[this_reg]) = 0; \ } \ } while(0) #define AT_STRINGS_BEG(d) ((d) == string) #define AT_STRINGS_END(d) ((d) == dend) #define IS_A_LETTER(d) (SYNTAX(*(d)) == Sword || \ (current_mbctype ? \ (re_mbctab[*(d)] && ((d)+mbclen(*(d)))<=dend): \ SYNTAX(*(d)) == Sword2)) #define PREV_IS_A_LETTER(d) ((current_mbctype == MBCTYPE_SJIS)? \ IS_A_LETTER((d)-(!AT_STRINGS_BEG((d)-1)&& \ ismbchar((d)[-2])?2:1)): \ ((current_mbctype && ((d)[-1] >= 0x80)) || \ IS_A_LETTER((d)-1))) static void init_regs(regs, num_regs) struct re_registers *regs; unsigned int num_regs; { int i; regs->num_regs = num_regs; if (num_regs < RE_NREGS) num_regs = RE_NREGS; if (regs->allocated == 0) { regs->beg = TMALLOC(num_regs, int); regs->end = TMALLOC(num_regs, int); regs->allocated = num_regs; } else if (regs->allocated < num_regs) { TREALLOC(regs->beg, num_regs, int); TREALLOC(regs->end, num_regs, int); regs->allocated = num_regs; } for (i=0; ibeg[i] = regs->end[i] = -1; } } /* Match the pattern described by BUFP against STRING, which is of SIZE. Start the match at index POS in STRING. In REGS, return the indices of STRING that matched the entire BUFP->buffer and its contained subexpressions. If bufp->fastmap is nonzero, then it had better be up to date. The reason that the data to match are specified as two components which are to be regarded as concatenated is so this function can be used directly on the contents of an Emacs buffer. -1 is returned if there is no match. -2 is returned if there is an error (such as match stack overflow). Otherwise the value is the length of the substring which was matched. */ int re_match(bufp, string_arg, size, pos, regs) struct re_pattern_buffer *bufp; const char *string_arg; int size, pos; struct re_registers *regs; { return re_match_exec(bufp, string_arg, size, pos, pos, regs); } static int re_match_exec(bufp, string_arg, size, pos, beg, regs) struct re_pattern_buffer *bufp; const char *string_arg; int size, pos, beg; struct re_registers *regs; { register unsigned char *p = (unsigned char*)bufp->buffer; unsigned char *p1; /* Pointer to beyond end of buffer. */ register unsigned char *pend = p + bufp->used; unsigned num_regs = bufp->re_nsub; unsigned char *string = (unsigned char*)string_arg; register unsigned char *d, *dend; register int mcnt; /* Multipurpose. */ int options = bufp->options; /* Failure point stack. Each place that can handle a failure further down the line pushes a failure point on this stack. It consists of restart, regend, and reg_info for all registers corresponding to the subexpressions we're currently inside, plus the number of such registers, and, finally, two char *'s. The first char * is where to resume scanning the pattern; the second one is where to resume scanning the strings. If the latter is zero, the failure point is a ``dummy''; if a failure happens and the failure point is a dummy, it gets discarded and the next next one is tried. */ unsigned char **const stacka = 0; unsigned char **stackb; unsigned char **stackp; unsigned char **stacke; /* Information on the contents of registers. These are pointers into the input strings; they record just what was matched (on this attempt) by a subexpression part of the pattern, that is, the regnum-th regstart pointer points to where in the pattern we began matching and the regnum-th regend points to right after where we stopped matching the regnum-th subexpression. (The zeroth register keeps track of what the whole pattern matches.) */ unsigned char **regstart = bufp->regstart; unsigned char **regend = bufp->regend; /* If a group that's operated upon by a repetition operator fails to match anything, then the register for its start will need to be restored because it will have been set to wherever in the string we are when we last see its open-group operator. Similarly for a register's end. */ unsigned char **old_regstart = bufp->old_regstart; unsigned char **old_regend = bufp->old_regend; /* The is_active field of reg_info helps us keep track of which (possibly nested) subexpressions we are currently in. The matched_something field of reg_info[reg_num] helps us tell whether or not we have matched any of the pattern so far this time through the reg_num-th subexpression. These two fields get reset each time through any loop their register is in. */ register_info_type *reg_info = bufp->reg_info; /* The following record the register info as found in the above variables when we find a match better than any we've seen before. This happens as we backtrack through the failure points, which in turn happens only if we have not yet matched the entire string. */ unsigned best_regs_set = 0; unsigned char **best_regstart = bufp->best_regstart; unsigned char **best_regend = bufp->best_regend; int num_failure_counts = 0; if (regs) { init_regs(regs, num_regs); } /* Initialize the stack. */ stackb = TMALLOC(MAX_NUM_FAILURE_ITEMS * NFAILURES, unsigned char*); stackp = stackb; stacke = &stackb[MAX_NUM_FAILURE_ITEMS * NFAILURES]; #ifdef DEBUG_REGEX fprintf(stderr, "Entering re_match(%s)\n", string_arg); #endif /* Initialize subexpression text positions to -1 to mark ones that no ( or ( and ) or ) has been seen for. Also set all registers to inactive and mark them as not having matched anything or ever failed. */ for (mcnt = 0; mcnt < num_regs; mcnt++) { regstart[mcnt] = regend[mcnt] = old_regstart[mcnt] = old_regend[mcnt] = best_regstart[mcnt] = best_regend[mcnt] = REG_UNSET_VALUE; #ifdef __CHECKER__ reg_info[mcnt].word = 0; #endif IS_ACTIVE (reg_info[mcnt]) = 0; MATCHED_SOMETHING (reg_info[mcnt]) = 0; } /* Set up pointers to ends of strings. Don't allow the second string to be empty unless both are empty. */ /* `p' scans through the pattern as `d' scans through the data. `dend' is the end of the input string that `d' points within. `d' is advanced into the following input string whenever necessary, but this happens before fetching; therefore, at the beginning of the loop, `d' can be pointing at the end of a string, but it cannot equal string2. */ d = string + pos, dend = string + size; /* This loops over pattern commands. It exits by returning from the function if match is complete, or it drops through if match fails at this starting point in the input data. */ for (;;) { #ifdef DEBUG_REGEX fprintf(stderr, "regex loop(%d): matching 0x%02d\n", p - (unsigned char*)bufp->buffer, *p); #endif /* End of pattern means we might have succeeded. */ if (p == pend) { /* If not end of string, try backtracking. Otherwise done. */ if ((bufp->options & RE_OPTION_LONGEST) && d != dend) { if (best_regs_set) /* non-greedy, no need to backtrack */ goto restore_best_regs; while (stackp != stackb && stackp[-1] == NON_GREEDY) { if (best_regs_set) /* non-greedy, no need to backtrack */ goto restore_best_regs; POP_FAILURE_POINT(); } if (stackp != stackb) { /* More failure points to try. */ /* If exceeds best match so far, save it. */ if (! best_regs_set || (d > best_regend[0])) { best_regs_set = 1; best_regend[0] = d; /* Never use regstart[0]. */ for (mcnt = 1; mcnt < num_regs; mcnt++) { best_regstart[mcnt] = regstart[mcnt]; best_regend[mcnt] = regend[mcnt]; } } goto fail; } /* If no failure points, don't restore garbage. */ else if (best_regs_set) { restore_best_regs: /* Restore best match. */ d = best_regend[0]; for (mcnt = 0; mcnt < num_regs; mcnt++) { regstart[mcnt] = best_regstart[mcnt]; regend[mcnt] = best_regend[mcnt]; } } } /* If caller wants register contents data back, convert it to indices. */ if (regs) { regs->beg[0] = pos; regs->end[0] = d - string; for (mcnt = 1; mcnt < num_regs; mcnt++) { if (REG_UNSET(regend[mcnt])) { regs->beg[mcnt] = -1; regs->end[mcnt] = -1; continue; } regs->beg[mcnt] = regstart[mcnt] - string; regs->end[mcnt] = regend[mcnt] - string; } } FREE_AND_RETURN(stackb, (d - pos - string)); } /* Otherwise match next pattern command. */ #ifdef SWITCH_ENUM_BUG switch ((int)((enum regexpcode)*p++)) #else switch ((enum regexpcode)*p++) #endif { /* ( [or `(', as appropriate] is represented by start_memory, ) by stop_memory. Both of those commands are followed by a register number in the next byte. The text matched within the ( and ) is recorded under that number. */ case start_memory: old_regstart[*p] = regstart[*p]; regstart[*p] = d; IS_ACTIVE(reg_info[*p]) = 1; MATCHED_SOMETHING(reg_info[*p]) = 0; p += 2; continue; case stop_memory: old_regend[*p] = regend[*p]; regend[*p] = d; IS_ACTIVE(reg_info[*p]) = 0; p += 2; continue; case start_paren: case stop_paren: break; /* \ has been turned into a `duplicate' command which is followed by the numeric value of as the register number. */ case duplicate: { int regno = *p++; /* Get which register to match against */ register unsigned char *d2, *dend2; /* Check if there's corresponding group */ if (regno >= num_regs) goto fail; /* Check if corresponding group is still open */ if (IS_ACTIVE(reg_info[regno])) goto fail; /* Where in input to try to start matching. */ d2 = regstart[regno]; if (REG_UNSET(d2)) goto fail; /* Where to stop matching; if both the place to start and the place to stop matching are in the same string, then set to the place to stop, otherwise, for now have to use the end of the first string. */ dend2 = regend[regno]; if (REG_UNSET(dend2)) goto fail; for (;;) { /* At end of register contents => success */ if (d2 == dend2) break; /* If necessary, advance to next segment in data. */ PREFETCH; /* How many characters left in this segment to match. */ mcnt = dend - d; /* Want how many consecutive characters we can match in one shot, so, if necessary, adjust the count. */ if (mcnt > dend2 - d2) mcnt = dend2 - d2; /* Compare that many; failure if mismatch, else move past them. */ if ((options & RE_OPTION_IGNORECASE) ? memcmp_translate(d, d2, mcnt) : memcmp((char*)d, (char*)d2, mcnt)) goto fail; d += mcnt, d2 += mcnt; } } break; case start_nowidth: PUSH_FAILURE_POINT(0, d); if (stackp - stackb > RE_DUP_MAX) { FREE_AND_RETURN(stackb,(-2)); } EXTRACT_NUMBER_AND_INCR(mcnt, p); STORE_NUMBER(p+mcnt, stackp - stackb); continue; case stop_nowidth: EXTRACT_NUMBER_AND_INCR(mcnt, p); stackp = stackb + mcnt; d = stackp[-3]; POP_FAILURE_POINT(); continue; case stop_backtrack: EXTRACT_NUMBER_AND_INCR(mcnt, p); stackp = stackb + mcnt; POP_FAILURE_POINT(); continue; case pop_and_fail: EXTRACT_NUMBER(mcnt, p+1); stackp = stackb + mcnt; POP_FAILURE_POINT(); goto fail; case anychar: PREFETCH; if (ismbchar(*d)) { if (d + mbclen(*d) > dend) goto fail; SET_REGS_MATCHED; d += mbclen(*d); break; } if (!(options&RE_OPTION_MULTILINE) && (TRANSLATE_P() ? translate[*d] : *d) == '\n') goto fail; SET_REGS_MATCHED; d++; break; case anychar_repeat: for (;;) { PUSH_FAILURE_POINT(p, d); PREFETCH; if (ismbchar(*d)) { if (d + mbclen(*d) > dend) goto fail; SET_REGS_MATCHED; d += mbclen(*d); continue; } if (!(options&RE_OPTION_MULTILINE) && (TRANSLATE_P() ? translate[*d] : *d) == '\n') goto fail; SET_REGS_MATCHED; d++; } break; case charset: case charset_not: { int not; /* Nonzero for charset_not. */ int part = 0; /* true if matched part of mbc */ unsigned char *dsave = d + 1; int cc, c; PREFETCH; c = (unsigned char)*d++; if (ismbchar(c)) { if (d + mbclen(c) - 1 <= dend) { cc = c; MBC2WC(c, d); not = is_in_list_mbc(c, p); if (!not) { part = not = is_in_list_sbc(cc, p); } } else { not = is_in_list(c, p); } } else { if (TRANSLATE_P()) c = (unsigned char)translate[c]; not = is_in_list(c, p); } if (*(p - 1) == (unsigned char)charset_not) { not = !not; } if (!not) goto fail; p += 1 + *p + 2 + EXTRACT_UNSIGNED(&p[1 + *p])*8; SET_REGS_MATCHED; if (part) d = dsave; break; } case begline: if (size == 0 || AT_STRINGS_BEG(d)) break; if (d[-1] == '\n' && !AT_STRINGS_END(d)) break; goto fail; case endline: if (AT_STRINGS_END(d)) { break; } else if (*d == '\n') break; goto fail; /* Match at the very beginning of the string. */ case begbuf: if (AT_STRINGS_BEG(d)) break; goto fail; /* Match at the very end of the data. */ case endbuf: if (AT_STRINGS_END(d)) break; goto fail; /* Match at the very end of the data. */ case endbuf2: if (AT_STRINGS_END(d)) { break; } /* .. or newline just before the end of the data. */ if (*d == '\n' && AT_STRINGS_END(d+1)) break; goto fail; /* `or' constructs are handled by starting each alternative with an on_failure_jump that points to the start of the next alternative. Each alternative except the last ends with a jump to the joining point. (Actually, each jump except for the last one really jumps to the following jump, because tensioning the jumps is a hassle.) */ /* The start of a stupid repeat has an on_failure_jump that points past the end of the repeat text. This makes a failure point so that on failure to match a repetition, matching restarts past as many repetitions have been found with no way to fail and look for another one. */ /* A smart repeat is similar but loops back to the on_failure_jump so that each repetition makes another failure point. */ /* Match at the starting position. */ case begpos: if (d - string == beg) break; goto fail; case on_failure_jump: on_failure: EXTRACT_NUMBER_AND_INCR(mcnt, p); PUSH_FAILURE_POINT(p + mcnt, d); continue; /* The end of a smart repeat has a maybe_finalize_jump back. Change it either to a finalize_jump or an ordinary jump. */ case maybe_finalize_jump: EXTRACT_NUMBER_AND_INCR(mcnt, p); p1 = p; /* Compare the beginning of the repeat with what in the pattern follows its end. If we can establish that there is nothing that they would both match, i.e., that we would have to backtrack because of (as in, e.g., `a*a') then we can change to finalize_jump, because we'll never have to backtrack. This is not true in the case of alternatives: in `(a|ab)*' we do need to backtrack to the `ab' alternative (e.g., if the string was `ab'). But instead of trying to detect that here, the alternative has put on a dummy failure point which is what we will end up popping. */ /* Skip over open/close-group commands. */ while (p1 + 2 < pend) { if ((enum regexpcode)*p1 == stop_memory || (enum regexpcode)*p1 == start_memory) p1 += 3; /* Skip over args, too. */ else if (/*(enum regexpcode)*p1 == start_paren ||*/ (enum regexpcode)*p1 == stop_paren) p1 += 1; else break; } if (p1 == pend) p[-3] = (unsigned char)finalize_jump; else if (*p1 == (unsigned char)exactn || *p1 == (unsigned char)endline) { register int c = *p1 == (unsigned char)endline ? '\n' : p1[2]; register unsigned char *p2 = p + mcnt; /* p2[0] ... p2[2] are an on_failure_jump. Examine what follows that. */ if (p2[3] == (unsigned char)exactn && p2[5] != c) p[-3] = (unsigned char)finalize_jump; else if (p2[3] == (unsigned char)charset || p2[3] == (unsigned char)charset_not) { int not; if (ismbchar(c)) { unsigned char *pp = p1+3; MBC2WC(c, pp); } /* `is_in_list()' is TRUE if c would match */ /* That means it is not safe to finalize. */ not = is_in_list(c, p2 + 4); if (p2[3] == (unsigned char)charset_not) not = !not; if (!not) p[-3] = (unsigned char)finalize_jump; } } p -= 2; /* Point at relative address again. */ if (p[-1] != (unsigned char)finalize_jump) { p[-1] = (unsigned char)jump; goto nofinalize; } /* Note fall through. */ /* The end of a stupid repeat has a finalize_jump back to the start, where another failure point will be made which will point to after all the repetitions found so far. */ /* Take off failure points put on by matching on_failure_jump because didn't fail. Also remove the register information put on by the on_failure_jump. */ case finalize_jump: if (stackp > stackb && stackp[-3] == d) { p = stackp[-4]; POP_FAILURE_POINT(); continue; } POP_FAILURE_POINT(); /* Note fall through. */ /* We need this opcode so we can detect where alternatives end in `group_match_null_string_p' et al. */ case jump_past_alt: /* fall through */ /* Jump without taking off any failure points. */ case jump: nofinalize: EXTRACT_NUMBER_AND_INCR(mcnt, p); if (mcnt < 0 && stackp > stackb && stackp[-3] == d) /* avoid infinite loop */ goto fail; p += mcnt; continue; case dummy_failure_jump: /* Normally, the on_failure_jump pushes a failure point, which then gets popped at finalize_jump. We will end up at finalize_jump, also, and with a pattern of, say, `a+', we are skipping over the on_failure_jump, so we have to push something meaningless for finalize_jump to pop. */ PUSH_FAILURE_POINT(0, 0); goto nofinalize; /* At the end of an alternative, we need to push a dummy failure point in case we are followed by a `finalize_jump', because we don't want the failure point for the alternative to be popped. For example, matching `(a|ab)*' against `aab' requires that we match the `ab' alternative. */ case push_dummy_failure: /* See comments just above at `dummy_failure_jump' about the two zeroes. */ p1 = p; /* Skip over open/close-group commands. */ while (p1 + 2 < pend) { if ((enum regexpcode)*p1 == stop_memory || (enum regexpcode)*p1 == start_memory) p1 += 3; /* Skip over args, too. */ else if (/*(enum regexpcode)*p1 == start_paren ||*/ (enum regexpcode)*p1 == stop_paren) p1 += 1; else break; } if (p1 < pend && (enum regexpcode)*p1 == jump) p[-1] = unused; else PUSH_FAILURE_POINT(0, 0); break; /* Have to succeed matching what follows at least n times. Then just handle like an on_failure_jump. */ case succeed_n: EXTRACT_NUMBER(mcnt, p + 2); /* Originally, this is how many times we HAVE to succeed. */ if (mcnt != 0) { mcnt--; p += 2; PUSH_FAILURE_COUNT(p); STORE_NUMBER_AND_INCR(p, mcnt); PUSH_FAILURE_POINT(0, 0); } else { goto on_failure; } continue; case jump_n: EXTRACT_NUMBER(mcnt, p + 2); /* Originally, this is how many times we CAN jump. */ if (mcnt) { mcnt--; PUSH_FAILURE_COUNT(p + 2); STORE_NUMBER(p + 2, mcnt); goto nofinalize; /* Do the jump without taking off any failure points. */ } /* If don't have to jump any more, skip over the rest of command. */ else p += 4; continue; case set_number_at: EXTRACT_NUMBER_AND_INCR(mcnt, p); p1 = p + mcnt; EXTRACT_NUMBER_AND_INCR(mcnt, p); STORE_NUMBER(p1, mcnt); continue; case try_next: EXTRACT_NUMBER_AND_INCR(mcnt, p); if (p + mcnt < pend) { PUSH_FAILURE_POINT(p, d); stackp[-1] = NON_GREEDY; } p += mcnt; continue; case finalize_push: POP_FAILURE_POINT(); EXTRACT_NUMBER_AND_INCR(mcnt, p); if (mcnt < 0 && stackp > stackb && stackp[-3] == d) /* avoid infinite loop */ goto fail; PUSH_FAILURE_POINT(p + mcnt, d); stackp[-1] = NON_GREEDY; continue; case finalize_push_n: EXTRACT_NUMBER(mcnt, p + 2); /* Originally, this is how many times we CAN jump. */ if (mcnt) { int pos, i; mcnt--; STORE_NUMBER(p + 2, mcnt); EXTRACT_NUMBER(pos, p); EXTRACT_NUMBER(i, p+pos+5); if (i > 0) goto nofinalize; POP_FAILURE_POINT(); EXTRACT_NUMBER_AND_INCR(mcnt, p); PUSH_FAILURE_POINT(p + mcnt, d); stackp[-1] = NON_GREEDY; p += 2; /* skip n */ } /* If don't have to push any more, skip over the rest of command. */ else p += 4; continue; /* Ignore these. Used to ignore the n of succeed_n's which currently have n == 0. */ case unused: continue; case casefold_on: options |= RE_OPTION_IGNORECASE; continue; case casefold_off: options &= ~RE_OPTION_IGNORECASE; continue; case option_set: options = *p++; continue; case wordbound: if (AT_STRINGS_BEG(d)) { if (AT_STRINGS_END(d)) goto fail; if (IS_A_LETTER(d)) break; else goto fail; } if (AT_STRINGS_END(d)) { if (PREV_IS_A_LETTER(d)) break; else goto fail; } if (PREV_IS_A_LETTER(d) != IS_A_LETTER(d)) break; goto fail; case notwordbound: if (AT_STRINGS_BEG(d)) { if (IS_A_LETTER(d)) goto fail; else break; } if (AT_STRINGS_END(d)) { if (PREV_IS_A_LETTER(d)) goto fail; else break; } if (PREV_IS_A_LETTER(d) != IS_A_LETTER(d)) goto fail; break; case wordbeg: if (IS_A_LETTER(d) && (AT_STRINGS_BEG(d) || !PREV_IS_A_LETTER(d))) break; goto fail; case wordend: if (!AT_STRINGS_BEG(d) && PREV_IS_A_LETTER(d) && (!IS_A_LETTER(d) || AT_STRINGS_END(d))) break; goto fail; case wordchar: PREFETCH; if (!IS_A_LETTER(d)) goto fail; if (ismbchar(*d) && d + mbclen(*d) - 1 < dend) d += mbclen(*d) - 1; d++; SET_REGS_MATCHED; break; case notwordchar: PREFETCH; if (IS_A_LETTER(d)) goto fail; if (ismbchar(*d) && d + mbclen(*d) - 1 < dend) d += mbclen(*d) - 1; d++; SET_REGS_MATCHED; break; case exactn: /* Match the next few pattern characters exactly. mcnt is how many characters to match. */ mcnt = *p++; /* This is written out as an if-else so we don't waste time testing `translate' inside the loop. */ if (TRANSLATE_P()) { do { unsigned char c; PREFETCH; if (*p == 0xff) { p++; if (!--mcnt || AT_STRINGS_END(d) || (unsigned char)*d++ != (unsigned char)*p++) goto fail; continue; } c = *d++; if (ismbchar(c)) { int n; if (c != (unsigned char)*p++) goto fail; for (n = mbclen(c) - 1; n > 0; n--) if (!--mcnt /* redundant check if pattern was compiled properly. */ || AT_STRINGS_END(d) || (unsigned char)*d++ != (unsigned char)*p++) goto fail; continue; } /* compiled code translation needed for ruby */ if ((unsigned char)translate[c] != (unsigned char)translate[*p++]) goto fail; } while (--mcnt); } else { do { PREFETCH; if (*p == 0xff) {p++; mcnt--;} if (*d++ != *p++) goto fail; } while (--mcnt); } SET_REGS_MATCHED; break; } #ifdef RUBY CHECK_INTS; #endif continue; /* Successfully executed one pattern command; keep going. */ /* Jump here if any matching operation fails. */ fail: if (stackp != stackb) { /* A restart point is known. Restart there and pop it. */ short last_used_reg, this_reg; /* If this failure point is from a dummy_failure_point, just skip it. */ if (stackp[-4] == 0 || (best_regs_set && stackp[-1] == NON_GREEDY)) { POP_FAILURE_POINT(); goto fail; } stackp--; /* discard greedy flag */ options = (long)*--stackp; d = *--stackp; p = *--stackp; /* Restore register info. */ last_used_reg = (long)*--stackp; /* Make the ones that weren't saved -1 or 0 again. */ for (this_reg = num_regs - 1; this_reg > last_used_reg; this_reg--) { regend[this_reg] = REG_UNSET_VALUE; regstart[this_reg] = REG_UNSET_VALUE; IS_ACTIVE(reg_info[this_reg]) = 0; MATCHED_SOMETHING(reg_info[this_reg]) = 0; } /* And restore the rest from the stack. */ for ( ; this_reg > 0; this_reg--) { reg_info[this_reg].word = *--stackp; regend[this_reg] = *--stackp; regstart[this_reg] = *--stackp; } mcnt = (long)*--stackp; while (mcnt--) { POP_FAILURE_COUNT(); } if (p < pend) { int is_a_jump_n = 0; int failed_paren = 0; p1 = p; /* If failed to a backwards jump that's part of a repetition loop, need to pop this failure point and use the next one. */ switch ((enum regexpcode)*p1) { case jump_n: case finalize_push_n: is_a_jump_n = 1; case maybe_finalize_jump: case finalize_jump: case finalize_push: case jump: p1++; EXTRACT_NUMBER_AND_INCR(mcnt, p1); if (mcnt >= 0) break; /* should be backward jump */ p1 += mcnt; if (( is_a_jump_n && (enum regexpcode)*p1 == succeed_n) || (!is_a_jump_n && (enum regexpcode)*p1 == on_failure_jump)) { if (failed_paren) { p1++; EXTRACT_NUMBER_AND_INCR(mcnt, p1); PUSH_FAILURE_POINT(p1 + mcnt, d); } goto fail; } break; default: /* do nothing */; } } } else break; /* Matching at this starting point really fails. */ } if (best_regs_set) goto restore_best_regs; FREE_AND_RETURN(stackb,(-1)); /* Failure to match. */ memory_exhausted: FREE_AND_RETURN(stackb,(-2)); } static int memcmp_translate(s1, s2, len) unsigned char *s1, *s2; register int len; { register unsigned char *p1 = s1, *p2 = s2, c; while (len) { c = *p1++; if (ismbchar(c)) { int n; if (c != *p2++) return 1; for (n = mbclen(c) - 1; n > 0; n--) if (!--len || *p1++ != *p2++) return 1; } else if (translate[c] != translate[*p2++]) return 1; len--; } return 0; } void re_copy_registers(regs1, regs2) struct re_registers *regs1, *regs2; { int i; if (regs1 == regs2) return; if (regs1->allocated == 0) { regs1->beg = TMALLOC(regs2->num_regs, int); regs1->end = TMALLOC(regs2->num_regs, int); regs1->allocated = regs2->num_regs; } else if (regs1->allocated < regs2->num_regs) { TREALLOC(regs1->beg, regs2->num_regs, int); TREALLOC(regs1->end, regs2->num_regs, int); regs1->allocated = regs2->num_regs; } for (i=0; inum_regs; i++) { regs1->beg[i] = regs2->beg[i]; regs1->end[i] = regs2->end[i]; } regs1->num_regs = regs2->num_regs; } void re_free_registers(regs) struct re_registers *regs; { if (regs->allocated == 0) return; if (regs->beg) xfree(regs->beg); if (regs->end) xfree(regs->end); } /* Functions for multi-byte support. Created for grep multi-byte extension Jul., 1993 by t^2 (Takahiro Tanimoto) Last change: Jul. 9, 1993 by t^2 */ static const unsigned char mbctab_ascii[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static const unsigned char mbctab_euc[] = { /* 0xA1-0xFE */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, }; static const unsigned char mbctab_sjis[] = { /* 0x81-0x9F,0xE0-0xFC */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }; static const unsigned char mbctab_sjis_trail[] = { /* 0x40-0x7E,0x80-0xFC */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }; static const unsigned char mbctab_utf8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 0, 0, }; const unsigned char *re_mbctab = mbctab_ascii; void re_mbcinit(mbctype) int mbctype; { switch (mbctype) { case MBCTYPE_ASCII: re_mbctab = mbctab_ascii; current_mbctype = MBCTYPE_ASCII; break; case MBCTYPE_EUC: re_mbctab = mbctab_euc; current_mbctype = MBCTYPE_EUC; break; case MBCTYPE_SJIS: re_mbctab = mbctab_sjis; current_mbctype = MBCTYPE_SJIS; break; case MBCTYPE_UTF8: re_mbctab = mbctab_utf8; current_mbctype = MBCTYPE_UTF8; break; } } #define mbc_isfirst(t, c) (t)[(unsigned char)(c)] #define mbc_len(t, c) ((t)[(unsigned char)(c)]+1) static unsigned int asc_startpos(string, pos) const char *string; unsigned int pos; { return pos; } #define euc_islead(c) ((unsigned char)((c) - 0xa1) > 0xfe - 0xa1) #define euc_mbclen(c) mbc_len(mbctab_euc, (c)) static unsigned int euc_startpos(string, pos) const char *string; unsigned int pos; { unsigned int i = pos, w; while (i > 0 && !euc_islead(string[i])) { --i; } if (i == pos || i + (w = euc_mbclen(string[i])) > pos) { return i; } i += w; return i + ((pos - i) & ~1); } #define sjis_isfirst(c) mbc_isfirst(mbctab_sjis, (c)) #define sjis_istrail(c) mbctab_sjis_trail[(unsigned char)(c)] #define sjis_mbclen(c) mbc_len(mbctab_sjis, (c)) static unsigned int sjis_startpos(string, pos) const char *string; unsigned int pos; { unsigned int i = pos, w; if (i > 0 && sjis_istrail(string[i])) { do { if (!sjis_isfirst(string[--i])) { ++i; break; } } while (i > 0); } if (i == pos || i + (w = sjis_mbclen(string[i])) > pos) { return i; } i += w; return i + ((pos - i) & ~1); } #define utf8_islead(c) ((unsigned char)((c) & 0xc0) != 0x80) #define utf8_mbclen(c) mbc_len(mbctab_utf8, (c)) static unsigned int utf8_startpos(string, pos) const char *string; unsigned int pos; { unsigned int i = pos, w; while (i > 0 && !utf8_islead(string[i])) { --i; } if (i == pos || i + (w = utf8_mbclen(string[i])) > pos) { return i; } return i + w; } /* vi: sw=2 ts=8 Local variables: mode : C c-file-style : "gnu" tab-width : 8 End */ ================================================ FILE: regex.h ================================================ /* Definitions for data structures and routines for the regular expression library, version 0.12. Copyright (C) 1985,89,90,91,92,93,95,96,97,98 Free Software Foundation, Inc. This file is part of the GNU C Library. Its master source is NOT part of the C library, however. The master source lives in /gd/gnu/lib. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file LGPL. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Multi-byte extension added May, 1993 by t^2 (Takahiro Tanimoto) Last change: May 21, 1993 by t^2 */ /* modified for Ruby by matz@netlab.co.jp */ #ifndef REGEX_H #define REGEX_H /* symbol mangling for ruby */ #ifdef RUBY # define re_adjust_startpos ruby_re_adjust_startpos # define re_compile_fastmap ruby_re_compile_fastmap # define re_compile_pattern ruby_re_compile_pattern # define re_copy_registers ruby_re_copy_registers # define re_free_pattern ruby_re_free_pattern # define re_free_registers ruby_re_free_registers # define re_match ruby_re_match # define re_mbcinit ruby_re_mbcinit # define re_search ruby_re_search # define re_set_casetable ruby_re_set_casetable # define register_info_type ruby_register_info_type #endif #include /* Define number of parens for which we record the beginnings and ends. This affects how much space the `struct re_registers' type takes up. */ #ifndef RE_NREGS #define RE_NREGS 10 #endif #define BYTEWIDTH 8 #define RE_REG_MAX ((1<. .Dd December 31, 2002 .Dt RUBY(1) "" "Ruby Programmers Reference Guide" .\".Dt RUBY 1 .Os UNIX .Sh NAME .Nm ruby .Nd Interpreted object-oriented scripting language .Sh SYNOPSIS .Nm .Op Fl -copyright .Op Fl -version .Op Fl Sacdlnpswvy .Op Fl 0 Ns Op Ar octal .Op Fl C Ar directory .Op Fl F Ar pattern .Op Fl I Ar directory .Op Fl K Ar c .Op Fl T Ns Op Ar level .Op Fl e Ar command .Op Fl i Ns Op Ar extension .Op Fl r Ar library .Op Fl x Ns Op Ar directory .Op Fl - .Op Ar program_file .Op Ar argument ... .Sh DESCRIPTION Ruby is an interpreted scripting language for quick and easy object-oriented programming. It has many features to process text files and to do system management tasks (as in Perl). It is simple, straight-forward, and extensible. .Pp If you want a language for easy object-oriented programming, or you don't like the Perl ugliness, or you do like the concept of LISP, but don't like too much parentheses, Ruby may be the language of your choice. .Sh FEATURES Ruby's features are as follows: .Bl -tag -width 6n .It Sy "Interpretive" Ruby is an interpreted language, so you don't have to recompile programs written in Ruby to execute them. .Pp .It Sy "Variables have no type (dynamic typing)" Variables in Ruby can contain data of any type. You don't have to worry about variable typing. Consequently, it has a weaker compile time check. .Pp .It Sy "No declaration needed" You can use variables in your Ruby programs without any declarations. Variable names denote their scope, local, global, instance, etc. .Pp .It Sy "Simple syntax" Ruby has a simple syntax influenced slightly from Eiffel. .Pp .It Sy "No user-level memory management" Ruby has automatic memory management. Objects no longer referenced from anywhere are automatically collected by the garbage collector built into the interpreter. .Pp .It Sy "Everything is an object" Ruby is the purely object-oriented language, and was so since its creation. Even such basic data as integers are seen as objects. .Pp .It Sy "Class, inheritance, and methods" Of course, as an object-oriented language, Ruby has such basic features like classes, inheritance, and methods. .Pp .It Sy "Singleton methods" Ruby has the ability to define methods for certain objects. For example, you can define a press-button action for certain widget by defining a singleton method for the button. Or, you can make up your own prototype based object system using singleton methods, if you want to. .Pp .It Sy "Mix-in by modules" Ruby intentionally does not have the multiple inheritance as it is a source of confusion. Instead, Ruby has the ability to share implementations across the inheritance tree. This is often called .Sq Mix-in . .Pp .It Sy "Iterators" Ruby has iterators for loop abstraction. .Pp .It Sy "Closures" In Ruby, you can objectify the procedure. .Pp .It Sy "Text processing and regular expression" Ruby has a bunch of text processing features like in Perl. .Pp .It Sy "Bignums" With built-in bignums, you can for example calculate factorial(400). .Pp .It Sy "Exception handling" As in Java(tm). .Pp .It Sy "Direct access to the OS" Ruby can use most .Ux system calls, often used in system programming. .Pp .It Sy "Dynamic loading" On most .Ux systems, you can load object files into the Ruby interpreter on-the-fly. .El .Pp .Sh OPTIONS Ruby interpreter accepts following command-line options (switches). They are quite similar to those of .Xr perl 1 . .Bl -tag -width "1234567890123" -compact .Pp .It Fl -copyright Prints the copyright notice. .Pp .It Fl -version Prints the version of Ruby interpreter. .Pp .It Fl 0 Ns Op Ar octal (The digit .Dq zero . ) Specifies the input record separator .Pf ( Li "$/" ) as an octal number. If no digit is given, the null character is taken as the separator. Other switches may follow the digits. .Fl 00 turns Ruby into paragraph mode. .Fl 0777 makes Ruby read whole file at once as a single string since there is no legal character with that value. .Pp .It Fl C Ar directory Causes Ruby to switch to the directory. .Pp .It Fl F Ar pattern Specifies input field separator .Pf ( Li "$;" ) . .Pp .It Fl I Ar directory Used to tell Ruby where to load the library scripts. Directory path will be added to the load-path variable .Pf ( Li "$:" ) . .Pp .It Fl K Ar kcode Specifies KANJI (Japanese) encoding. .Pp .It Fl S Makes Ruby use the .Ev PATH environment variable to search for script, unless if its name begins with a slash. This is used to emulate .Li #! on machines that don't support it, in the following manner: .Bd -literal -offset indent #! /usr/local/bin/ruby # This line makes the next one a comment in Ruby \e exec /usr/local/bin/ruby -S $0 $* .Ed .Pp .It Fl T Ns Op Ar level Turns on taint checks at the specified level (default 1). .Pp .It Fl a Turns on auto-split mode when used with .Fl n or .Fl p . In auto-split mode, Ruby executes .Dl $F = $_.split at beginning of each loop. .Pp .It Fl c Causes Ruby to check the syntax of the script and exit without executing. If there are no syntax errors, Ruby will print .Dq Syntax OK to the standard output. .Pp .It Fl d .It Fl -debug Turns on debug mode. .Li "$DEBUG" will be set to true. .Pp .It Fl e Ar command Specifies script from command-line while telling Ruby not to search the rest of arguments for a script file name. .Pp .It Fl h .It Fl -help Prints a summary of the options. .Pp .It Fl i Ar extension Specifies in-place-edit mode. The extension, if specified, is added to old file name to make a backup copy. For example: .Bd -literal -offset indent % echo matz > /tmp/junk % cat /tmp/junk matz % ruby -p -i.bak -e '$_.upcase!' /tmp/junk % cat /tmp/junk MATZ % cat /tmp/junk.bak matz .Ed .Pp .It Fl l (The lowercase letter .Dq ell . ) Enables automatic line-ending processing, which means to firstly set .Li "$\e" to the value of .Li "$/" , and secondly chops every line read using .Li chop! . .Pp .It Fl n Causes Ruby to assume the following loop around your script, which makes it iterate over file name arguments somewhat like .Nm sed .Fl n or .Nm awk . .Bd -literal -offset indent while gets ... end .Ed .Pp .It Fl p Acts mostly same as -n switch, but print the value of variable .Li "$_" at the each end of the loop. For example: .Bd -literal -offset indent % echo matz | ruby -p -e '$_.tr! "a-z", "A-Z"' MATZ .Ed .Pp .It Fl r Ar library Causes Ruby to load the library using require. It is useful when using .Fl n or .Fl p . .Pp .It Fl s Enables some switch parsing for switches after script name but before any file name arguments (or before a .Fl - ) . Any switches found there are removed from .Li ARGV and set the corresponding variable in the script. For example: .Bd -literal -offset indent #! /usr/local/bin/ruby -s # prints "true" if invoked with `-xyz' switch. print "true\en" if $xyz .Ed .Pp On some systems .Li "$0" does not always contain the full pathname, so you need the .Fl S switch to tell Ruby to search for the script if necessary. To handle embedded spaces or such. A better construct than .Li "$*" would be .Li ${1+"$@"} , but it does not work if the script is being interpreted by .Xr csh 1 . .Pp .It Fl v .It Fl -verbose Enables verbose mode. Ruby will print its version at the beginning, and set the variable .Li "$VERBOSE" to true. Some methods print extra messages if this variable is true. If this switch is given, and no other switches are present, Ruby quits after printing its version. .Pp .It Fl w Enables verbose mode without printing version message at the beginning. It sets the .Li "$VERBOSE" variable to true. .Pp .It Fl x Ns Op Ar directory Tells Ruby that the script is embedded in a message. Leading garbage will be discarded until the first that starts with .Dq #! and contains the string, .Dq ruby . Any meaningful switches on that line will applied. The end of script must be specified with either .Li EOF , .Li "^D" ( Li "control-D" ) , .Li "^Z" ( Li "control-Z" ) , or reserved word .Li __END__ . If the directory name is specified, Ruby will switch to that directory before executing script. .Pp .It Fl y .It Fl -yydebug Turns on compiler debug mode. Ruby will print a bunch of internal state messages during compiling scripts. You don't have to specify this switch, unless you are going to debug the Ruby interpreter. .El .Pp .Sh ENVIRONMENT .Bl -tag -width "RUBYLIB_PREFIX" -compact .It Ev RUBYLIB A colon-separated list of directories that are added to Ruby's library load path .Pf ( Li "$:" ) . Directories from this environment variable are searched before the standard load path is searched. .Pp e.g.: .Dl RUBYLIB="$HOME/lib/ruby:$HOME/lib/rubyext" .Pp .It Ev RUBYOPT Additional Ruby options. .Pp e.g. .Dl RUBYOPT="-w -Ke" .Pp .It Ev RUBYPATH A colon-separated list of directories that Ruby searches for Ruby programs when the .Fl S flag is specified. This variable precedes the .Ev PATH environment variable. .Pp .It Ev RUBYSHELL The path to the system shell command. This environment variable is enabled for only mswin32, mingw32, and OS/2 platforms. If this variable is not defined, Ruby refers to .Ev COMSPEC . .Pp .It Ev PATH Ruby refers to the .Ev PATH environment variable on calling Kernel#system. .Pp .It Ev RUBYLIB_PREFIX This variable is obsolete. .El .Pp .Sh AUTHORS Ruby is designed and implemented by .An Yukihiro Matsumoto Aq matz@netlab.jp . ================================================ FILE: ruby.c ================================================ /********************************************************************** ruby.c - $Author$ $Date$ created at: Tue Aug 10 12:47:31 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto Copyright (C) 2000 Network Applied Communication Laboratory, Inc. Copyright (C) 2000 Information-technology Promotion Agency, Japan **********************************************************************/ #if defined _WIN32 || defined __CYGWIN__ #include #endif #if defined __CYGWIN__ #include #endif #ifdef _WIN32_WCE #include #include "wince.h" #endif #include "ruby.h" #include "dln.h" #include "node.h" #include #include #include #ifdef __hpux #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifndef HAVE_STRING_H char *strchr _((const char*,const char)); char *strrchr _((const char*,const char)); char *strstr _((const char*,const char*)); #endif #include "util.h" #ifndef HAVE_STDLIB_H char *getenv(); #endif #define RUBY_BINARY_NAME "ruby" #define KIJI_BINARY_NAME "kiji" VALUE ruby_debug = Qfalse; VALUE ruby_verbose = Qfalse; static int sflag = 0; static int xflag = 0; extern int ruby_yydebug; char *ruby_inplace_mode = Qfalse; static void load_stdin _((void)); static void load_file _((const char *, int)); static void forbid_setid _((const char *)); static VALUE do_loop = Qfalse, do_print = Qfalse; static VALUE do_check = Qfalse, do_line = Qfalse; static VALUE do_split = Qfalse; static const char *script; static int origargc; static char **origargv; static void usage(name) const char *name; { /* This message really ought to be max 23 lines. * Removed -h because the user already knows that option. Others? */ static const char *const usage_msg[] = { "-0[octal] specify record separator (\\0, if no argument)", "-a autosplit mode with -n or -p (splits $_ into $F)", "-c check syntax only", "-Cdirectory cd to directory, before executing your script", "-d set debugging flags (set $DEBUG to true)", "-e 'command' one line of script. Several -e's allowed. Omit [programfile]", "-Fpattern split() pattern for autosplit (-a)", "-i[extension] edit ARGV files in place (make backup if extension supplied)", "-Idirectory specify $LOAD_PATH directory (may be used more than once)", "-Kkcode specifies KANJI (Japanese) code-set", "-l enable line ending processing", "-n assume 'while gets(); ... end' loop around your script", "-p assume loop like -n but print line also like sed", "-rlibrary require the library, before executing your script", "-s enable some switch parsing for switches after script name", "-S look for the script using PATH environment variable", "-T[level] turn on tainting checks", "-v print version number, then turn on verbose mode", "-w turn warnings on for your script", "-W[level] set warning level; 0=silence, 1=medium, 2=verbose (default)", "-x[directory] strip off text before #!ruby line and perhaps cd to directory", "--copyright print the copyright", "--version print the version", NULL }; const char *const *p = usage_msg; printf("Usage: %s [switches] [--] [programfile] [arguments]\n", name); while (*p) printf(" %s\n", *p++); } extern VALUE rb_load_path; #ifndef CharNext /* defined as CharNext[AW] on Windows. */ #define CharNext(p) ((p) + mblen(p, RUBY_MBCHAR_MAXSIZE)) #endif #if defined DOSISH || defined __CYGWIN__ static inline void translate_char(char *p, int from, int to) { while (*p) { if ((unsigned char)*p == from) *p = to; p = CharNext(p); } } #endif #if defined _WIN32 || defined __CYGWIN__ || defined __DJGPP__ static VALUE rubylib_mangled_path(const char *s, unsigned int l) { static char *newp, *oldp; static int newl, oldl, notfound; char *ptr; VALUE ret; if (!newp && !notfound) { newp = getenv("RUBYLIB_PREFIX"); if (newp) { oldp = newp = strdup(newp); while (*newp && !ISSPACE(*newp) && *newp != ';') { newp = CharNext(newp); /* Skip digits. */ } oldl = newp - oldp; while (*newp && (ISSPACE(*newp) || *newp == ';')) { newp = CharNext(newp); /* Skip whitespace. */ } newl = strlen(newp); if (newl == 0 || oldl == 0) { rb_fatal("malformed RUBYLIB_PREFIX"); } translate_char(newp, '\\', '/'); } else { notfound = 1; } } if (!newp || l < oldl || strncasecmp(oldp, s, oldl) != 0) { return rb_str_new(s, l); } ret = rb_str_new(0, l + newl - oldl); ptr = RSTRING_PTR(ret); memcpy(ptr, newp, newl); memcpy(ptr + newl, s + oldl, l - oldl); ptr[l + newl - oldl] = 0; return ret; } static VALUE rubylib_mangled_path2(const char *s) { return rubylib_mangled_path(s, strlen(s)); } #else #define rubylib_mangled_path rb_str_new #define rubylib_mangled_path2 rb_str_new2 #endif static void push_include _((const char *path)); static void push_include(path) const char *path; { const char sep = PATH_SEP_CHAR; const char *p, *s; p = path; while (*p) { while (*p == sep) p++; if (!*p) break; for (s = p; *s && *s != sep; s = CharNext(s)); rb_ary_push(rb_load_path, rubylib_mangled_path(p, s - p)); p = s; } } #ifdef __CYGWIN__ static void push_include_cygwin(const char *path) { const char *p, *s; char rubylib[FILENAME_MAX]; VALUE buf = 0; p = path; while (*p) { unsigned int len; while (*p == ';') p++; if (!*p) break; for (s = p; *s && *s != ';'; s = CharNext(s)); len = s - p; if (*s) { if (!buf) { buf = rb_str_new(p, len); p = RSTRING_PTR(buf); } else { rb_str_resize(buf, len); p = strncpy(RSTRING_PTR(buf), p, len); } } if (cygwin_conv_to_posix_path(p, rubylib) == 0) p = rubylib; push_include(p); if (!*s) break; p = s + 1; } } #define push_include push_include_cygwin #endif void ruby_incpush(path) const char *path; { if (path == 0) return; push_include(path); } #if defined DOSISH || defined __CYGWIN__ #define LOAD_RELATIVE 1 #endif void ruby_init_loadpath() { #if defined LOAD_RELATIVE char libpath[FILENAME_MAX+1]; char *p; int rest; #if defined _WIN32 || defined __CYGWIN__ HMODULE libruby = NULL; MEMORY_BASIC_INFORMATION m; #ifndef _WIN32_WCE memset(&m, 0, sizeof(m)); if (VirtualQuery(ruby_init_loadpath, &m, sizeof(m)) && m.State == MEM_COMMIT) libruby = (HMODULE)m.AllocationBase; #endif GetModuleFileName(libruby, libpath, sizeof libpath); #elif defined(DJGPP) extern char *__dos_argv0; strncpy(libpath, __dos_argv0, FILENAME_MAX); #elif defined(__human68k__) extern char **_argv; strncpy(libpath, _argv[0], FILENAME_MAX); #elif defined(__EMX__) _execname(libpath, FILENAME_MAX); #endif libpath[FILENAME_MAX] = '\0'; #if defined DOSISH translate_char(libpath, '\\', '/'); #elif defined __CYGWIN__ { char rubylib[FILENAME_MAX]; cygwin_conv_to_posix_path(libpath, rubylib); strncpy(libpath, rubylib, sizeof(libpath)); } #endif p = strrchr(libpath, '/'); if (p) { *p = 0; if (p - libpath > 3 && !strcasecmp(p - 4, "/bin")) { p -= 4; *p = 0; } } else { strcpy(libpath, "."); p = libpath + 1; } rest = FILENAME_MAX - (p - libpath); #define RUBY_RELATIVE(path) (strncpy(p, (path), rest), libpath) #else #define RUBY_RELATIVE(path) (path) #endif #define incpush(path) rb_ary_push(rb_load_path, rubylib_mangled_path2(path)) if (rb_safe_level() == 0) { ruby_incpush(getenv("RUBYLIB")); } #ifdef RUBY_SEARCH_PATH incpush(RUBY_RELATIVE(RUBY_SEARCH_PATH)); #endif incpush(RUBY_RELATIVE(RUBY_SITE_LIB2)); #ifdef RUBY_SITE_THIN_ARCHLIB incpush(RUBY_RELATIVE(RUBY_SITE_THIN_ARCHLIB)); #endif incpush(RUBY_RELATIVE(RUBY_SITE_ARCHLIB)); incpush(RUBY_RELATIVE(RUBY_SITE_LIB)); incpush(RUBY_RELATIVE(RUBY_VENDOR_LIB2)); #ifdef RUBY_VENDOR_THIN_ARCHLIB incpush(RUBY_RELATIVE(RUBY_VENDOR_THIN_ARCHLIB)); #endif incpush(RUBY_RELATIVE(RUBY_VENDOR_ARCHLIB)); incpush(RUBY_RELATIVE(RUBY_VENDOR_LIB)); incpush(RUBY_RELATIVE(RUBY_LIB)); #ifdef RUBY_THIN_ARCHLIB incpush(RUBY_RELATIVE(RUBY_THIN_ARCHLIB)); #endif incpush(RUBY_RELATIVE(RUBY_ARCHLIB)); if (rb_safe_level() == 0) { incpush("."); } } struct req_list { char *name; struct req_list *next; }; static struct req_list req_list_head, *req_list_last = &req_list_head; static void add_modules(mod) const char *mod; { struct req_list *list; list = ALLOC(struct req_list); list->name = ALLOC_N(char, strlen(mod)+1); strcpy(list->name, mod); list->next = 0; req_list_last->next = list; req_list_last = list; } extern void Init_ext _((void)); static void require_libraries() { extern NODE *ruby_eval_tree; extern NODE *ruby_eval_tree_begin; NODE *save[3]; struct req_list *list = req_list_head.next; struct req_list *tmp; save[0] = ruby_eval_tree; save[1] = ruby_eval_tree_begin; save[2] = NEW_NEWLINE(0); ruby_eval_tree = ruby_eval_tree_begin = 0; ruby_current_node = 0; Init_ext(); /* should be called here for some reason :-( */ ruby_current_node = save[2]; ruby_set_current_source(); req_list_last = 0; while (list) { int state; ruby_current_node = 0; rb_protect((VALUE (*)(VALUE))rb_require, (VALUE)list->name, &state); if (state) rb_jump_tag(state); tmp = list->next; free(list->name); free(list); list = tmp; ruby_current_node = save[2]; ruby_set_current_source(); } req_list_head.next = 0; ruby_eval_tree = save[0]; ruby_eval_tree_begin = save[1]; rb_gc_force_recycle((VALUE)save[2]); ruby_current_node = 0; } static void process_sflag() { if (sflag) { long n; VALUE *args; n = RARRAY(rb_argv)->len; args = RARRAY(rb_argv)->ptr; while (n > 0) { VALUE v = *args++; char *s = StringValuePtr(v); char *p; int hyphen = Qfalse; if (s[0] != '-') break; n--; if (s[1] == '-' && s[2] == '\0') break; v = Qtrue; /* check if valid name before replacing - with _ */ for (p = s + 1; *p; p++) { if (*p == '=') { *p++ = '\0'; v = rb_str_new2(p); break; } if (*p == '-') { hyphen = Qtrue; } else if (*p != '_' && !ISALNUM(*p)) { VALUE name_error[2]; name_error[0] = rb_str_new2("invalid name for global variable - "); if (!(p = strchr(p, '='))) { rb_str_cat2(name_error[0], s); } else { rb_str_cat(name_error[0], s, p - s); } name_error[1] = args[-1]; rb_exc_raise(rb_class_new_instance(2, name_error, rb_eNameError)); } } s[0] = '$'; if (hyphen) { for (p = s + 1; *p; ++p) { if (*p == '-') *p = '_'; } } rb_gv_set(s, v); } n = RARRAY(rb_argv)->len - n; while (n--) { rb_ary_shift(rb_argv); } } sflag = 0; } static void proc_options _((int argc, char **argv)); static char* moreswitches(s) char *s; { int argc; char *argv[3]; char *p = s; argc = 2; argv[0] = argv[2] = 0; while (*s && !ISSPACE(*s)) s++; argv[1] = ALLOCA_N(char, s-p+2); argv[1][0] = '-'; strncpy(argv[1]+1, p, s-p); argv[1][s-p+1] = '\0'; proc_options(argc, argv); while (*s && ISSPACE(*s)) s++; return s; } static void proc_options(argc, argv) int argc; char **argv; { char *argv0 = argv[0]; int do_search; char *s; NODE *volatile script_node = 0; int version = 0; int copyright = 0; int verbose = 0; VALUE e_script = Qfalse; if (argc == 0) return; do_search = Qfalse; for (argc--,argv++; argc > 0; argc--,argv++) { if (argv[0][0] != '-' || !argv[0][1]) break; s = argv[0]+1; reswitch: switch (*s) { case 'a': do_split = Qtrue; s++; goto reswitch; case 'p': do_print = Qtrue; /* through */ case 'n': do_loop = Qtrue; s++; goto reswitch; case 'd': ruby_debug = Qtrue; ruby_verbose = Qtrue; s++; goto reswitch; case 'y': ruby_yydebug = 1; s++; goto reswitch; case 'v': if (argv0 == 0 || verbose) { s++; goto reswitch; } ruby_show_version(); verbose = 1; case 'w': ruby_verbose = Qtrue; s++; goto reswitch; case 'W': { int numlen; int v = 2; /* -W as -W2 */ if (*++s) { v = scan_oct(s, 1, &numlen); if (numlen == 0) v = 1; s += numlen; } switch (v) { case 0: ruby_verbose = Qnil; break; case 1: ruby_verbose = Qfalse; break; default: ruby_verbose = Qtrue; break; } } goto reswitch; case 'c': do_check = Qtrue; s++; goto reswitch; case 's': forbid_setid("-s"); sflag = 1; s++; goto reswitch; case 'h': usage(origargv[0]); exit(0); case 'l': do_line = Qtrue; rb_output_rs = rb_rs; s++; goto reswitch; case 'S': forbid_setid("-S"); do_search = Qtrue; s++; goto reswitch; case 'e': forbid_setid("-e"); if (!*++s) { s = argv[1]; argc--,argv++; } if (!s) { fprintf(stderr, "%s: no code specified for -e\n", origargv[0]); exit(2); } if (!e_script) { e_script = rb_str_new(0,0); if (script == 0) script = "-e"; } rb_str_cat2(e_script, s); rb_str_cat2(e_script, "\n"); break; case 'r': forbid_setid("-r"); if (*++s) { add_modules(s); } else if (argv[1]) { add_modules(argv[1]); argc--,argv++; } break; case 'i': forbid_setid("-i"); if (ruby_inplace_mode) free(ruby_inplace_mode); ruby_inplace_mode = strdup(s+1); break; case 'x': xflag = Qtrue; s++; if (*s && chdir(s) < 0) { rb_fatal("Can't chdir to %s", s); } break; case 'C': case 'X': s++; if (!*s) { s = argv[1]; argc--,argv++; } if (!s || !*s) { rb_fatal("Can't chdir"); } if (chdir(s) < 0) { rb_fatal("Can't chdir to %s", s); } break; case 'F': if (*++s) { rb_fs = rb_reg_new(s, strlen(s), 0); } break; case 'K': if (*++s) { rb_set_kcode(s); s++; } goto reswitch; case 'T': { int numlen; int v = 1; if (*++s) { v = scan_oct(s, 2, &numlen); if (numlen == 0) v = 1; s += numlen; } rb_set_safe_level(v); } goto reswitch; case 'I': forbid_setid("-I"); if (*++s) ruby_incpush(s); else if (argv[1]) { ruby_incpush(argv[1]); argc--,argv++; } break; case '0': { int numlen; int v; char c; v = scan_oct(s, 4, &numlen); s += numlen; if (v > 0377) rb_rs = Qnil; else if (v == 0 && numlen >= 2) { rb_rs = rb_str_new2("\n\n"); } else { c = v & 0xff; rb_rs = rb_str_new(&c, 1); } } goto reswitch; case '-': if (!s[1] || (s[1] == '\r' && !s[2])) { argc--,argv++; goto switch_end; } s++; if (strcmp("copyright", s) == 0) copyright = 1; else if (strcmp("debug", s) == 0) { ruby_debug = Qtrue; ruby_verbose = Qtrue; } else if (strcmp("version", s) == 0) version = 1; else if (strcmp("verbose", s) == 0) { verbose = 1; ruby_verbose = Qtrue; } else if (strcmp("yydebug", s) == 0) ruby_yydebug = 1; else if (strcmp("help", s) == 0) { usage(origargv[0]); exit(0); } else { fprintf(stderr, "%s: invalid option --%s (-h will show valid options)\n", origargv[0], s); exit(2); } break; case '\r': if (!s[1]) break; default: { const char *format; if (ISPRINT(*s)) { format = "%s: invalid option -%c (-h will show valid options)\n"; } else { format = "%s: invalid option -\\%03o (-h will show valid options)\n"; } fprintf(stderr, format, origargv[0], (int)(unsigned char)*s); } exit(2); case 0: break; } } switch_end: if (argv0 == 0) return; if (rb_safe_level() == 0 && (s = getenv("RUBYOPT"))) { while (ISSPACE(*s)) s++; if (*s == 'T' || (*s == '-' && *(s+1) == 'T')) { int numlen; int v = 1; if (*s != 'T') ++s; if (*++s) { v = scan_oct(s, 2, &numlen); if (numlen == 0) v = 1; } rb_set_safe_level(v); } else { while (s && *s) { if (*s == '-') { s++; if (ISSPACE(*s)) { do {s++;} while (ISSPACE(*s)); continue; } } if (!*s) break; if (!strchr("IdvwWrK", *s)) rb_raise(rb_eRuntimeError, "illegal switch in RUBYOPT: -%c", *s); s = moreswitches(s); } } } if (version) { ruby_show_version(); exit(0); } if (copyright) { ruby_show_copyright(); } if (rb_safe_level() >= 4) { OBJ_TAINT(rb_argv); OBJ_TAINT(rb_load_path); } if (!e_script) { if (argc == 0) { /* no more args */ if (verbose) exit(0); script = "-"; } else { script = argv[0]; #if defined DOSISH || defined __CYGWIN__ translate_char(argv[0], '\\', '/'); #endif if (script[0] == '\0') { script = "-"; } else if (do_search) { char *path = getenv("RUBYPATH"); script = 0; if (path) { script = dln_find_file(argv[0], path); } if (!script) { script = dln_find_file(argv[0], getenv(PATH_ENV)); } if (!script) script = argv[0]; script = ruby_sourcefile = rb_source_filename(script); script_node = NEW_NEWLINE(0); #if defined DOSISH || defined __CYGWIN__ translate_char(ruby_sourcefile, '\\', '/'); #endif } argc--; argv++; } } ruby_script(script); ruby_set_argv(argc, argv); process_sflag(); ruby_init_loadpath(); ruby_sourcefile = rb_source_filename(argv0); if (e_script) { require_libraries(); rb_compile_string(script, e_script, 1); } else if (strlen(script) == 1 && script[0] == '-') { load_stdin(); } else { load_file(script, 1); } process_sflag(); xflag = 0; if (rb_safe_level() >= 4) { FL_UNSET(rb_argv, FL_TAINT); FL_UNSET(rb_load_path, FL_TAINT); } } extern int ruby__end__seen; static void load_file(fname, script) const char *fname; int script; { extern VALUE rb_stdin; VALUE f; int line_start = 1; if (!fname) rb_load_fail(fname); if (strcmp(fname, "-") == 0) { f = rb_stdin; } else { FILE *fp = fopen(fname, "r"); if (fp == NULL) { rb_load_fail(fname); } fclose(fp); f = rb_file_open(fname, "r"); #if defined DOSISH || defined __CYGWIN__ { char *ext = strrchr(fname, '.'); if (ext && strcasecmp(ext, ".exe") == 0) rb_io_binmode(f); } #endif } if (script) { VALUE c = 1; /* something not nil */ VALUE line; char *p; if (xflag) { forbid_setid("-x"); xflag = Qfalse; while (!NIL_P(line = rb_io_gets(f))) { line_start++; if (RSTRING(line)->len > 2 && RSTRING(line)->ptr[0] == '#' && RSTRING(line)->ptr[1] == '!') { if (((p = strstr(RSTRING(line)->ptr, RUBY_BINARY_NAME)) != NULL) || ((p = strstr(RSTRING(line)->ptr, KIJI_BINARY_NAME)) != NULL)) { goto start_read; } } } rb_raise(rb_eLoadError, "no Ruby script found in input"); } c = rb_io_getc(f); if (c == INT2FIX('#')) { line = rb_io_gets(f); if (NIL_P(line)) return; line_start++; if (RSTRING(line)->len > 2 && RSTRING(line)->ptr[0] == '!') { if (((p = strstr(RSTRING(line)->ptr, RUBY_BINARY_NAME)) == NULL) && ((p = strstr(RSTRING(line)->ptr, KIJI_BINARY_NAME)) == NULL)) { /* not ruby script, kick the program */ char **argv; char *path; char *pend = RSTRING(line)->ptr + RSTRING(line)->len; p = RSTRING(line)->ptr + 1; /* skip `#!' */ if (pend[-1] == '\n') pend--; /* chomp line */ if (pend[-1] == '\r') pend--; *pend = '\0'; while (p < pend && ISSPACE(*p)) p++; path = p; /* interpreter path */ while (p < pend && !ISSPACE(*p)) p++; *p++ = '\0'; if (p < pend) { argv = ALLOCA_N(char*, origargc+3); argv[1] = p; MEMCPY(argv+2, origargv+1, char*, origargc); } else { argv = origargv; } argv[0] = path; execv(path, argv); ruby_sourcefile = rb_source_filename(fname); ruby_sourceline = 1; rb_fatal("Can't exec %s", path); } start_read: p += 4; RSTRING(line)->ptr[RSTRING(line)->len-1] = '\0'; if (RSTRING(line)->ptr[RSTRING(line)->len-2] == '\r') RSTRING(line)->ptr[RSTRING(line)->len-2] = '\0'; if ((p = strstr(p, " -")) != 0) { p++; /* skip space before `-' */ while (*p == '-') { p = moreswitches(p+1); } } } } else if (!NIL_P(c)) { rb_io_ungetc(f, c); } require_libraries(); /* Why here? unnatural */ if (NIL_P(c)) return; } rb_compile_file(fname, f, line_start); if (script && ruby__end__seen) { rb_define_global_const("DATA", f); } else if (f != rb_stdin) { rb_io_close(f); } } void rb_load_file(fname) const char *fname; { load_file(fname, 0); } static void load_stdin() { forbid_setid("program input from stdin"); load_file("-", 1); } VALUE rb_progname; VALUE rb_argv; VALUE rb_argv0; #if defined(PSTAT_SETCMD) || defined(HAVE_SETPROCTITLE) #elif defined(_WIN32) #elif defined(HAVE_SETENV) && defined(HAVE_UNSETENV) #else #define USE_ENVSPACE_FOR_ARG0 #endif #ifdef USE_ENVSPACE_FOR_ARG0 static struct { char *begin, *end; } envspace; extern char **environ; static void set_arg0space() { char *s; int i; if (!environ || (s = environ[0]) == NULL) return; envspace.begin = s; s += strlen(s); for (i = 1; environ[i]; i++) { if (environ[i] == s + 1) { s++; s += strlen(s); /* this one is ok too */ } } envspace.end = s; } #else #define set_arg0space() ((void)0) #endif static int get_arglen(int argc, char **argv) { char *s = argv[0]; int i; if (!argc) return 0; s += strlen(s); /* See if all the arguments are contiguous in memory */ for (i = 1; i < argc; i++) { if (argv[i] == s + 1) { s++; s += strlen(s); /* this one is ok too */ } else { break; } } #if defined(USE_ENVSPACE_FOR_ARG0) if (environ && (s == environ[0])) { s += strlen(s); for (i = 1; environ[i]; i++) { if (environ[i] == s + 1) { s++; s += strlen(s); /* this one is ok too */ } } ruby_setenv("", NULL); /* duplicate environ vars */ } #endif return s - argv[0]; } static void set_arg0(val, id) VALUE val; ID id; { VALUE progname; char *s; long i; int j; #if !defined(PSTAT_SETCMD) && !defined(HAVE_SETPROCTITLE) static int len = 0; #endif if (origargv == 0) rb_raise(rb_eRuntimeError, "$0 not initialized"); StringValue(val); s = RSTRING(val)->ptr; i = RSTRING(val)->len; #if defined(PSTAT_SETCMD) if (i >= PST_CLEN) { union pstun j; j.pst_command = s; i = PST_CLEN; RSTRING(val)->len = i; *(s + i) = '\0'; pstat(PSTAT_SETCMD, j, PST_CLEN, 0, 0); } else { union pstun j; j.pst_command = s; pstat(PSTAT_SETCMD, j, i, 0, 0); } progname = rb_tainted_str_new(s, i); #elif defined(HAVE_SETPROCTITLE) setproctitle("%.*s", (int)i, s); progname = rb_tainted_str_new(s, i); #else if (len == 0) { len = get_arglen(origargc, origargv); } if (i >= len) { i = len; } memcpy(origargv[0], s, i); s = origargv[0] + i; *s = '\0'; if (++i < len) memset(s + 1, ' ', len - i); for (i = len-1, j = origargc-1; j > 0 && i >= 0; --i, --j) { origargv[j] = origargv[0] + i; *origargv[j] = '\0'; } progname = rb_tainted_str_new2(origargv[0]); #endif rb_progname = rb_obj_freeze(progname); } void ruby_script(name) const char *name; { if (name) { rb_progname = rb_obj_freeze(rb_tainted_str_new2(name)); ruby_sourcefile = rb_source_filename(name); } } static int uid, euid, gid, egid; static void init_ids() { uid = (int)getuid(); euid = (int)geteuid(); gid = (int)getgid(); egid = (int)getegid(); #ifdef VMS uid |= gid << 16; euid |= egid << 16; #endif if (uid && (euid != uid || egid != gid)) { rb_set_safe_level(1); } } static void forbid_setid(s) const char *s; { if (euid != uid) rb_raise(rb_eSecurityError, "no %s allowed while running setuid", s); if (egid != gid) rb_raise(rb_eSecurityError, "no %s allowed while running setgid", s); if (rb_safe_level() > 0) rb_raise(rb_eSecurityError, "no %s allowed in tainted mode", s); } static void verbose_setter(val, id, variable) VALUE val; ID id; VALUE *variable; { ruby_verbose = RTEST(val) ? Qtrue : val; } void ruby_prog_init() { init_ids(); ruby_sourcefile = rb_source_filename("ruby"); rb_define_hooked_variable("$VERBOSE", &ruby_verbose, 0, verbose_setter); rb_define_hooked_variable("$-v", &ruby_verbose, 0, verbose_setter); rb_define_hooked_variable("$-w", &ruby_verbose, 0, verbose_setter); rb_define_variable("$DEBUG", &ruby_debug); rb_define_variable("$-d", &ruby_debug); rb_define_readonly_variable("$-p", &do_print); rb_define_readonly_variable("$-l", &do_line); rb_define_hooked_variable("$0", &rb_progname, 0, set_arg0); rb_define_hooked_variable("$PROGRAM_NAME", &rb_progname, 0, set_arg0); rb_define_readonly_variable("$*", &rb_argv); rb_argv = rb_ary_new(); rb_define_global_const("ARGV", rb_argv); rb_define_readonly_variable("$-a", &do_split); rb_global_variable(&rb_argv0); #ifdef MSDOS /* * There is no way we can refer to them from ruby, so close them to save * space. */ (void)fclose(stdaux); (void)fclose(stdprn); #endif } void ruby_set_argv(argc, argv) int argc; char **argv; { int i; #if defined(USE_DLN_A_OUT) if (origargv) dln_argv0 = origargv[0]; else dln_argv0 = argv[0]; #endif rb_ary_clear(rb_argv); for (i=0; i < argc; i++) { VALUE arg = rb_tainted_str_new2(argv[i]); OBJ_FREEZE(arg); rb_ary_push(rb_argv, arg); } } void ruby_process_options(argc, argv) int argc; char **argv; { origargc = argc; origargv = argv; ruby_script(argv[0]); /* for the time being */ rb_argv0 = rb_progname; #if defined(USE_DLN_A_OUT) dln_argv0 = argv[0]; #endif set_arg0space(); proc_options(argc, argv); if (do_check && ruby_nerrs == 0) { printf("Syntax OK\n"); exit(0); } if (do_print) { rb_parser_append_print(); } if (do_loop) { rb_parser_while_loop(do_line, do_split); } } ================================================ FILE: ruby.h ================================================ /********************************************************************** ruby.h - $Author$ created at: Thu Jun 10 14:26:32 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto Copyright (C) 2000 Network Applied Communication Laboratory, Inc. Copyright (C) 2000 Information-technology Promotion Agency, Japan **********************************************************************/ #ifndef RUBY_H #define RUBY_H #if defined(__cplusplus) extern "C" { #if 0 } /* satisfy cc-mode */ #endif #endif #include "config.h" #ifdef RUBY_EXTCONF_H #include RUBY_EXTCONF_H #endif #define NORETURN_STYLE_NEW 1 #ifndef NORETURN # define NORETURN(x) x #endif #ifndef NOINLINE # define NOINLINE(x) x #endif #include "defines.h" #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #else # include #endif #ifdef HAVE_INTRINSICS_H # include #endif #include #include /* need to include to use these macros */ #ifndef ISPRINT #define ISASCII(c) isascii((int)(unsigned char)(c)) #undef ISPRINT #define ISPRINT(c) (ISASCII(c) && isprint((int)(unsigned char)(c))) #define ISSPACE(c) (ISASCII(c) && isspace((int)(unsigned char)(c))) #define ISUPPER(c) (ISASCII(c) && isupper((int)(unsigned char)(c))) #define ISLOWER(c) (ISASCII(c) && islower((int)(unsigned char)(c))) #define ISALNUM(c) (ISASCII(c) && isalnum((int)(unsigned char)(c))) #define ISALPHA(c) (ISASCII(c) && isalpha((int)(unsigned char)(c))) #define ISDIGIT(c) (ISASCII(c) && isdigit((int)(unsigned char)(c))) #define ISXDIGIT(c) (ISASCII(c) && isxdigit((int)(unsigned char)(c))) #endif #if defined(HAVE_ALLOCA_H) #include #else # ifdef _AIX #pragma alloca # endif #endif #if defined(__VMS) # pragma builtins # define alloca __alloca #endif #if SIZEOF_LONG != SIZEOF_VOIDP # error ---->> ruby requires sizeof(void*) == sizeof(long) to be compiled. <<---- #else typedef unsigned long VALUE; typedef unsigned long ID; #endif #ifdef __STDC__ # include #else # ifndef LONG_MAX # ifdef HAVE_LIMITS_H # include # else /* assuming 32bit(2's compliment) long */ # define LONG_MAX 2147483647 # endif # endif # ifndef LONG_MIN # define LONG_MIN (-LONG_MAX-1) # endif # ifndef CHAR_BIT # define CHAR_BIT 8 # endif #endif #ifdef HAVE_LONG_LONG # ifndef LLONG_MAX # ifdef LONG_LONG_MAX # define LLONG_MAX LONG_LONG_MAX # else # ifdef _I64_MAX # define LLONG_MAX _I64_MAX # else /* assuming 64bit(2's complement) long long */ # define LLONG_MAX 9223372036854775807LL # endif # endif # endif # ifndef LLONG_MIN # ifdef LONG_LONG_MIN # define LLONG_MIN LONG_LONG_MIN # else # ifdef _I64_MIN # define LLONG_MIN _I64_MIN # else # define LLONG_MIN (-LLONG_MAX-1) # endif # endif # endif #endif #define FIXNUM_MAX (LONG_MAX>>1) #define FIXNUM_MIN RSHIFT((long)LONG_MIN,1) #define FIXNUM_FLAG 0x01 #define INT2FIX(i) ((VALUE)(((long)(i))<<1 | FIXNUM_FLAG)) #define LONG2FIX(i) INT2FIX(i) #define rb_fix_new(v) INT2FIX(v) VALUE rb_int2inum _((long)); #define INT2NUM(v) rb_int2inum(v) #define LONG2NUM(v) INT2NUM(v) #define rb_int_new(v) rb_int2inum(v) VALUE rb_uint2inum _((unsigned long)); #define UINT2NUM(v) rb_uint2inum(v) #define ULONG2NUM(v) UINT2NUM(v) #define rb_uint_new(v) rb_uint2inum(v) #ifdef HAVE_LONG_LONG VALUE rb_ll2inum _((LONG_LONG)); #define LL2NUM(v) rb_ll2inum(v) VALUE rb_ull2inum _((unsigned LONG_LONG)); #define ULL2NUM(v) rb_ull2inum(v) #endif #if SIZEOF_OFF_T > SIZEOF_LONG && defined(HAVE_LONG_LONG) # define OFFT2NUM(v) LL2NUM(v) #elif SIZEOF_OFF_T == SIZEOF_LONG # define OFFT2NUM(v) LONG2NUM(v) #else # define OFFT2NUM(v) INT2NUM(v) #endif #define FIX2LONG(x) RSHIFT((long)x,1) #define FIX2ULONG(x) (((unsigned long)(x))>>1) #define FIXNUM_P(f) (((long)(f))&FIXNUM_FLAG) #define POSFIXABLE(f) ((f) < FIXNUM_MAX+1) #define NEGFIXABLE(f) ((f) >= FIXNUM_MIN) #define FIXABLE(f) (POSFIXABLE(f) && NEGFIXABLE(f)) #define IMMEDIATE_MASK 0x03 #define IMMEDIATE_P(x) ((VALUE)(x) & IMMEDIATE_MASK) #define SYMBOL_FLAG 0x0e #define SYMBOL_P(x) (((VALUE)(x)&0xff)==SYMBOL_FLAG) #define ID2SYM(x) ((VALUE)(((long)(x))<<8|SYMBOL_FLAG)) #define SYM2ID(x) RSHIFT((unsigned long)x,8) /* special contants - i.e. non-zero and non-fixnum constants */ #define Qfalse ((VALUE)0) #define Qtrue ((VALUE)2) #define Qnil ((VALUE)4) #define Qundef ((VALUE)6) /* undefined value for placeholder */ #define RTEST(v) (((VALUE)(v) & ~Qnil) != 0) #define NIL_P(v) ((VALUE)(v) == Qnil) #define CLASS_OF(v) rb_class_of((VALUE)(v)) #define T_NONE 0x00 #define T_NIL 0x01 #define T_OBJECT 0x02 #define T_CLASS 0x03 #define T_ICLASS 0x04 #define T_MODULE 0x05 #define T_FLOAT 0x06 #define T_STRING 0x07 #define T_REGEXP 0x08 #define T_ARRAY 0x09 #define T_FIXNUM 0x0a #define T_HASH 0x0b #define T_STRUCT 0x0c #define T_BIGNUM 0x0d #define T_FILE 0x0e #define T_TRUE 0x20 #define T_FALSE 0x21 #define T_DATA 0x22 #define T_MATCH 0x23 #define T_SYMBOL 0x24 #define T_BLKTAG 0x3b #define T_UNDEF 0x3c #define T_VARMAP 0x3d #define T_SCOPE 0x3e #define T_NODE 0x3f #define T_MASK 0x3f // Used by the tracer for types which aren't available statically #define T_UNKNOWN (T_MASK+1) #define BUILTIN_TYPE(x) (((struct RBasic*)(x))->flags & T_MASK) #define TYPE(x) rb_type((VALUE)(x)) #ifdef __GNUC__ #define RB_GC_GUARD_PTR(ptr) \ __extension__ ({volatile VALUE *rb_gc_guarded_ptr = (ptr); rb_gc_guarded_ptr;}) #else #define RB_GC_GUARD_PTR(ptr) (volatile VALUE *)(ptr) #endif #define RB_GC_GUARD(v) (*RB_GC_GUARD_PTR(&(v))) void rb_check_type _((VALUE,int)); #define Check_Type(v,t) rb_check_type((VALUE)(v),t) VALUE rb_str_to_str _((VALUE)); VALUE rb_string_value _((volatile VALUE*)); char *rb_string_value_ptr _((volatile VALUE*)); char *rb_string_value_cstr _((volatile VALUE*)); #define StringValue(v) rb_string_value(&(v)) #define StringValuePtr(v) rb_string_value_ptr(&(v)) #define StringValueCStr(v) rb_string_value_cstr(&(v)) void rb_check_safe_obj _((VALUE)); void rb_check_safe_str _((VALUE)); #define SafeStringValue(v) do {\ StringValue(v);\ rb_check_safe_obj(v);\ } while (0) /* obsolete macro - use SafeStringValue(v) */ #define Check_SafeStr(v) rb_check_safe_str((VALUE)(v)) void rb_secure _((int)); RUBY_EXTERN int ruby_safe_level; #define rb_safe_level() (ruby_safe_level) void rb_set_safe_level _((int)); void rb_secure_update _((VALUE)); long rb_num2long _((VALUE)); unsigned long rb_num2ulong _((VALUE)); #define NUM2LONG(x) (FIXNUM_P(x)?FIX2LONG(x):rb_num2long((VALUE)x)) #define NUM2ULONG(x) rb_num2ulong((VALUE)x) #if SIZEOF_INT < SIZEOF_LONG long rb_num2int _((VALUE)); #define NUM2INT(x) (FIXNUM_P(x)?FIX2INT(x):rb_num2int((VALUE)x)) long rb_fix2int _((VALUE)); #define FIX2INT(x) rb_fix2int((VALUE)x) unsigned long rb_num2uint _((VALUE)); #define NUM2UINT(x) rb_num2uint(x) unsigned long rb_fix2uint _((VALUE)); #define FIX2UINT(x) rb_fix2uint(x) #else #define NUM2INT(x) ((int)NUM2LONG(x)) #define NUM2UINT(x) ((unsigned int)NUM2ULONG(x)) #define FIX2INT(x) ((int)FIX2LONG(x)) #define FIX2UINT(x) ((unsigned int)FIX2ULONG(x)) #endif #ifdef HAVE_LONG_LONG LONG_LONG rb_num2ll _((VALUE)); unsigned LONG_LONG rb_num2ull _((VALUE)); # define NUM2LL(x) (FIXNUM_P(x)?FIX2LONG(x):rb_num2ll((VALUE)x)) # define NUM2ULL(x) rb_num2ull((VALUE)x) #endif #if defined(HAVE_LONG_LONG) && SIZEOF_OFF_T > SIZEOF_LONG # define NUM2OFFT(x) ((off_t)NUM2LL(x)) #else # define NUM2OFFT(x) NUM2LONG(x) #endif double rb_num2dbl _((VALUE)); #define NUM2DBL(x) rb_num2dbl((VALUE)(x)) /* obsolete API - use StringValue() */ char *rb_str2cstr _((VALUE,long*)); /* obsolete API - use StringValuePtr() */ #define STR2CSTR(x) rb_str2cstr((VALUE)(x),0) #define NUM2CHR(x) (((TYPE(x) == T_STRING)&&(RSTRING(x)->len>=1))?\ RSTRING(x)->ptr[0]:(char)(NUM2INT(x)&0xff)) #define CHR2FIX(x) INT2FIX((long)((x)&0xff)) RUBY_EXTERN int ruby_in_longlife_context; #ifdef GC_DEBUG RUBY_EXTERN int gc_debug_on; struct source_position_list; typedef struct source_position { char *file; int line; ID func; VALUE frames_hash; struct source_position *parent; } source_position_t; char *gc_debug_get_backtrace(source_position_t *source_pos); #define GC_DEBUG_ON (unlikely(gc_debug_on)) #define GC_DEBUG_PRINTF(str,...) if (GC_DEBUG_ON) fprintf(gc_data_file, str, __VA_ARGS__); #define GC_DEBUG_PRINT(str) if (GC_DEBUG_ON) fprintf(gc_data_file, str); #define GC_DEBUG_SET_SOURCE if (GC_DEBUG_ON) ruby_set_current_source(); #else #define GC_DEBUG_PRINTF(str,...) ; #define GC_DEBUG_PRINT(str) ; #define GC_DEBUG_ON (0) #define GC_DEBUG_SET_SOURCE #endif /* GC_DEBUG */ VALUE rb_newobj_eden(); VALUE rb_newobj_longlife(); /* Legacy gem compatibility only. Do not use. */ VALUE rb_newobj(); // Default allocator #define NEWOBJ(obj,type) type *obj = (type*)rb_newobj_eden() // Specific allocators #define NEWOBJ_LONGLIFE(obj,type) type *obj = (type*)rb_newobj_longlife() #define NEWOBJ_EDEN(obj,type) type *obj = (type*)rb_newobj_eden() #define OBJSETUP(obj,c,t) do {\ RBASIC(obj)->flags = (t | (RBASIC(obj)->flags & (FL_MOVE|FL_LONGLIFE)));\ RBASIC(obj)->klass = (c);\ if (rb_safe_level() >= 3) FL_SET(obj, FL_TAINT);\ } while (0) #define CLONESETUP(clone,obj) do {\ OBJSETUP(clone,rb_singleton_class_clone((VALUE)obj),RBASIC(obj)->flags);\ rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone);\ if (FL_TEST(obj, FL_EXIVAR)) rb_copy_generic_ivar((VALUE)clone,(VALUE)obj);\ } while (0) #define DUPSETUP(dup,obj) do {\ OBJSETUP(dup,rb_obj_class(obj),(RBASIC(obj)->flags)&(T_MASK|FL_EXIVAR|FL_TAINT));\ if (FL_TEST(obj, FL_EXIVAR)) rb_copy_generic_ivar((VALUE)dup,(VALUE)obj);\ } while (0) struct RBasic { unsigned long flags; VALUE klass; }; struct RObject { struct RBasic basic; struct st_table *iv_tbl; }; struct RClass { struct RBasic basic; struct st_table *iv_tbl; struct st_table *m_tbl; VALUE super; }; #define RCLASS_IV_TBL(c) (RCLASS(c)->iv_tbl) #define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl) #define RCLASS_SUPER(c) (RCLASS(c)->super) #define RMODULE_IV_TBL(m) RCLASS_IV_TBL(m) #define RMODULE_M_TBL(m) RCLASS_M_TBL(m) #define RMODULE_SUPER(m) RCLASS_SUPER(m) struct RFloat { struct RBasic basic; double value; }; #define RFLOAT_VALUE(v) (RFLOAT(v)->value) #define ELTS_SHARED FL_USER2 struct RString { struct RBasic basic; long len; char *ptr; union { long capa; VALUE shared; } aux; }; #define RSTRING_PTR(s) (RSTRING(s)->ptr) #define RSTRING_LEN(s) (RSTRING(s)->len) #define RSTRING_END(s) (RSTRING_PTR(s)+RSTRING_LEN(s)) struct RArray { struct RBasic basic; long len; union { long capa; VALUE shared; } aux; VALUE *ptr; }; #define RARRAY_PTR(s) (RARRAY(s)->ptr) #define RARRAY_LEN(s) (RARRAY(s)->len) struct RRegexp { struct RBasic basic; struct re_pattern_buffer *ptr; long len; char *str; }; #define RREGEXP_SRC_PTR(r) (RREGEXP(r)->src) #define RREGEXP_SRC_LEN(r) (RREGEXP(r)->len) struct RHash { struct RBasic basic; struct st_table *tbl; int iter_lev; VALUE ifnone; }; #define RHASH_TBL(h) (RHASH(h)->tbl) #define RHASH_ITER_LEV(h) (RHASH(h)->iter_lev) #define RHASH_IFNONE(h) (RHASH(h)->ifnone) #define RHASH_SIZE(h) (RHASH(h)->tbl->num_entries) #define RHASH_EMPTY_P(h) (RHASH_SIZE(h) == 0) struct RFile { struct RBasic basic; struct rb_io_t *fptr; }; struct RData { struct RBasic basic; void (*dmark) _((void*)); void (*dfree) _((void*)); void *data; }; #define DATA_PTR(dta) (RDATA(dta)->data) /* #define RUBY_DATA_FUNC(func) ((void (*)_((void*)))func) */ typedef void (*RUBY_DATA_FUNC) _((void*)); VALUE rb_data_object_alloc _((VALUE,void*,RUBY_DATA_FUNC,RUBY_DATA_FUNC)); #define Data_Wrap_Struct(klass,mark,free,sval)\ rb_data_object_alloc(klass,sval,(RUBY_DATA_FUNC)mark,(RUBY_DATA_FUNC)free) #define Data_Make_Struct(klass,type,mark,free,sval) (\ sval = ALLOC(type),\ memset(sval, 0, sizeof(type)),\ Data_Wrap_Struct(klass,mark,free,sval)\ ) #define Data_Get_Struct(obj,type,sval) do {\ Check_Type(obj, T_DATA); \ sval = (type*)DATA_PTR(obj);\ } while (0) struct RStruct { struct RBasic basic; long len; VALUE *ptr; }; #define RSTRUCT_LEN(st) (RSTRUCT(st)->len) #define RSTRUCT_PTR(st) (RSTRUCT(st)->ptr) struct RBignum { struct RBasic basic; char sign; long len; void *digits; }; #define RBIGNUM_SIGN(b) (RBIGNUM(b)->sign) #define RBIGNUM_SET_SIGN(b,s) (RBIGNUM(b)->sign = (s)) #define RBIGNUM_POSITIVE_P(b) RBIGNUM_SIGN(b) #define RBIGNUM_NEGATIVE_P(b) (!RBIGNUM_SIGN(b)) #define RBIGNUM_LEN(b) (RBIGNUM(b)->len) #define RBIGNUM_DIGITS(b) (RBIGNUM(b)->digits) #define R_CAST(st) (struct st*) #define RBASIC(obj) (R_CAST(RBasic)(obj)) #define ROBJECT(obj) (R_CAST(RObject)(obj)) #define RCLASS(obj) (R_CAST(RClass)(obj)) #define RMODULE(obj) RCLASS(obj) #define RFLOAT(obj) (R_CAST(RFloat)(obj)) #define RSTRING(obj) (R_CAST(RString)(obj)) #define RREGEXP(obj) (R_CAST(RRegexp)(obj)) #define RARRAY(obj) (R_CAST(RArray)(obj)) #define RHASH(obj) (R_CAST(RHash)(obj)) #define RDATA(obj) (R_CAST(RData)(obj)) #define RSTRUCT(obj) (R_CAST(RStruct)(obj)) #define RBIGNUM(obj) (R_CAST(RBignum)(obj)) #define RFILE(obj) (R_CAST(RFile)(obj)) #define FL_SINGLETON FL_USER0 #define FL_LONGLIFE (1<<6) #define FL_FINALIZE (1<<7) #define FL_TAINT (1<<8) #define FL_EXIVAR (1<<9) #define FL_FREEZE (1<<10) #define FL_REMEMBERED_SET (1<<11) #define FL_MOVE (1<<12) #define FL_USHIFT 13 #define FL_USER0 (1<<(FL_USHIFT+0)) #define FL_USER1 (1<<(FL_USHIFT+1)) #define FL_USER2 (1<<(FL_USHIFT+2)) #define FL_USER3 (1<<(FL_USHIFT+3)) #define FL_USER4 (1<<(FL_USHIFT+4)) #define FL_USER5 (1<<(FL_USHIFT+5)) #define FL_USER6 (1<<(FL_USHIFT+6)) #define FL_UMASK (0xff<flags&(f)):0) #define FL_SET(x,f) do {if (FL_ABLE(x)) RBASIC(x)->flags |= (f);} while (0) #define FL_UNSET(x,f) do {if (FL_ABLE(x)) RBASIC(x)->flags &= ~(f);} while (0) #define FL_REVERSE(x,f) do {if (FL_ABLE(x)) RBASIC(x)->flags ^= (f);} while (0) #define OBJ_TAINTED(x) FL_TEST((x), FL_TAINT) #define OBJ_TAINT(x) FL_SET((x), FL_TAINT) #define OBJ_INFECT(x,s) do {if (FL_ABLE(x) && FL_ABLE(s)) RBASIC(x)->flags |= RBASIC(s)->flags & FL_TAINT;} while (0) #define OBJ_FROZEN(x) FL_TEST((x), FL_FREEZE) #define OBJ_FREEZE(x) FL_SET((x), FL_FREEZE) #define OBJ_UNFREEZE(x) FL_UNSET((x), FL_FREEZE) #define OBJ_LONGLIVED(x) FL_TEST((x), FL_LONGLIFE) #define OBJ_LONGLIFE(x) FL_SET((x), FL_LONGLIFE) #define OBJ_MOVED(x) FL_TEST((x), FL_MOVE) #define OBJ_MOVE(x) FL_SET((x), FL_MOVE) #define ALLOC_N(type,n) (type*)xmalloc(sizeof(type)*(n)) #define ALLOC(type) (type*)xmalloc(sizeof(type)) #define REALLOC_N(var,type,n) (var)=(type*)xrealloc((char*)(var),sizeof(type)*(n)) #define ALLOCA_N(type,n) (type*)alloca(sizeof(type)*(n)) #define MEMZERO(p,type,n) memset((p), 0, sizeof(type)*(n)) #define MEMCPY(p1,p2,type,n) memcpy((p1), (p2), sizeof(type)*(n)) #define MEMMOVE(p1,p2,type,n) memmove((p1), (p2), sizeof(type)*(n)) #define MEMCMP(p1,p2,type,n) memcmp((p1), (p2), sizeof(type)*(n)) void rb_obj_infect _((VALUE,VALUE)); typedef int ruby_glob_func(const char*,VALUE); void rb_glob _((const char*,void(*)(const char*,VALUE),VALUE)); void rb_globi _((const char*,void(*)(const char*,VALUE),VALUE)); int ruby_brace_expand _((const char*,int,ruby_glob_func*,VALUE)); int ruby_brace_glob _((const char*,int,ruby_glob_func*,VALUE)); VALUE rb_define_class _((const char*,VALUE)); VALUE rb_define_module _((const char*)); VALUE rb_define_class_under _((VALUE, const char*, VALUE)); VALUE rb_define_module_under _((VALUE, const char*)); void rb_include_module _((VALUE,VALUE)); void rb_extend_object _((VALUE,VALUE)); void rb_define_variable _((const char*,VALUE*)); void rb_define_virtual_variable _((const char*,VALUE(*)(ANYARGS),void(*)(ANYARGS))); void rb_define_hooked_variable _((const char*,VALUE*,VALUE(*)(ANYARGS),void(*)(ANYARGS))); int ruby_glob _((const char*,int,int(*)(const char*,VALUE),VALUE)); int ruby_globi _((const char*,int,int(*)(const char*,VALUE),VALUE)); void rb_define_readonly_variable _((const char*,VALUE*)); void rb_define_const _((VALUE,const char*,VALUE)); void rb_define_global_const _((const char*,VALUE)); #define RUBY_METHOD_FUNC(func) ((VALUE (*)(ANYARGS))func) void rb_define_method _((VALUE,const char*,VALUE(*)(ANYARGS),int)); void rb_define_module_function _((VALUE,const char*,VALUE(*)(ANYARGS),int)); void rb_define_global_function _((const char*,VALUE(*)(ANYARGS),int)); void rb_undef_method _((VALUE,const char*)); void rb_define_alias _((VALUE,const char*,const char*)); void rb_define_attr _((VALUE,const char*,int,int)); void rb_global_variable _((VALUE*)); void rb_gc_register_address _((VALUE*)); void rb_gc_unregister_address _((VALUE*)); VALUE rb_temp_enable_longlife(); VALUE rb_temp_disable_longlife(); int rb_gc_is_thread_marked _((VALUE)); ID rb_intern _((const char*)); const char *rb_id2name _((ID)); ID rb_to_id _((VALUE)); const char *rb_class2name _((VALUE)); const char *rb_obj_classname _((VALUE)); void rb_p _((VALUE)); VALUE rb_eval_string _((const char*)); VALUE rb_eval_string_protect _((const char*, int*)); VALUE rb_eval_string_wrap _((const char*, int*)); VALUE rb_funcall __((VALUE, ID, int, ...)); VALUE rb_funcall2 _((VALUE, ID, int, const VALUE*)); VALUE rb_funcall3 _((VALUE, ID, int, const VALUE*)); int rb_scan_args __((int, const VALUE*, const char*, ...)); VALUE rb_call_super _((int, const VALUE*)); VALUE rb_gv_set _((const char*, VALUE)); VALUE rb_gv_get _((const char*)); VALUE rb_iv_get _((VALUE, const char*)); VALUE rb_iv_set _((VALUE, const char*, VALUE)); VALUE rb_equal _((VALUE,VALUE)); RUBY_EXTERN VALUE ruby_verbose, ruby_debug; NORETURN(void rb_raise __((VALUE, const char*, ...))); NORETURN(void rb_fatal __((const char*, ...))); NORETURN(void rb_bug __((const char*, ...))); NORETURN(void rb_sys_fail _((const char*))); NORETURN(void rb_iter_break _((void))); NORETURN(void rb_exit _((int))); NORETURN(void rb_notimplement _((void))); void rb_warning __((const char*, ...)); /* reports if `-w' specified */ void rb_sys_warning __((const char*, ...)); /* reports if `-w' specified */ void rb_warn __((const char*, ...)); /* reports always */ typedef VALUE rb_block_call_func _((VALUE, VALUE)); VALUE rb_each _((VALUE)); VALUE rb_yield _((VALUE)); VALUE rb_yield_values __((int n, ...)); VALUE rb_yield_splat _((VALUE)); int rb_block_given_p _((void)); void rb_need_block _((void)); VALUE rb_iterate _((VALUE(*)(VALUE),VALUE,VALUE(*)(ANYARGS),VALUE)); VALUE rb_rescue _((VALUE(*)(ANYARGS),VALUE,VALUE(*)(ANYARGS),VALUE)); VALUE rb_rescue2 __((VALUE(*)(ANYARGS),VALUE,VALUE(*)(ANYARGS),VALUE,...)); VALUE rb_ensure _((VALUE(*)(ANYARGS),VALUE,VALUE(*)(ANYARGS),VALUE)); VALUE rb_catch _((const char*,VALUE(*)(ANYARGS),VALUE)); NORETURN(void rb_throw _((const char*,VALUE))); VALUE rb_require _((const char*)); #ifdef __ia64 void ruby_init_stack(VALUE*, void*); #define RUBY_INIT_STACK \ VALUE variable_in_this_stack_frame; \ ruby_init_stack(&variable_in_this_stack_frame, rb_ia64_bsp()); #else void ruby_init_stack(VALUE*); #define RUBY_INIT_STACK \ VALUE variable_in_this_stack_frame; \ ruby_init_stack(&variable_in_this_stack_frame); #endif void ruby_init _((void)); void ruby_options _((int, char**)); NORETURN(void ruby_run _((void))); RUBY_EXTERN VALUE rb_mKernel; RUBY_EXTERN VALUE rb_mComparable; RUBY_EXTERN VALUE rb_mEnumerable; RUBY_EXTERN VALUE rb_mPrecision; RUBY_EXTERN VALUE rb_mErrno; RUBY_EXTERN VALUE rb_mFileTest; RUBY_EXTERN VALUE rb_mGC; RUBY_EXTERN VALUE rb_mMath; RUBY_EXTERN VALUE rb_mProcess; RUBY_EXTERN VALUE rb_cObject; RUBY_EXTERN VALUE rb_cArray; RUBY_EXTERN VALUE rb_cBignum; RUBY_EXTERN VALUE rb_cBinding; RUBY_EXTERN VALUE rb_cClass; RUBY_EXTERN VALUE rb_cCont; RUBY_EXTERN VALUE rb_cDir; RUBY_EXTERN VALUE rb_cData; RUBY_EXTERN VALUE rb_cEnumerator; RUBY_EXTERN VALUE rb_cFalseClass; RUBY_EXTERN VALUE rb_cFile; RUBY_EXTERN VALUE rb_cFixnum; RUBY_EXTERN VALUE rb_cFloat; RUBY_EXTERN VALUE rb_cHash; RUBY_EXTERN VALUE rb_cInteger; RUBY_EXTERN VALUE rb_cIO; RUBY_EXTERN VALUE rb_cMatch; RUBY_EXTERN VALUE rb_cMethod; RUBY_EXTERN VALUE rb_cModule; RUBY_EXTERN VALUE rb_cNameErrorMesg; RUBY_EXTERN VALUE rb_cNilClass; RUBY_EXTERN VALUE rb_cNumeric; RUBY_EXTERN VALUE rb_cProc; RUBY_EXTERN VALUE rb_cRange; RUBY_EXTERN VALUE rb_cRegexp; RUBY_EXTERN VALUE rb_cStat; RUBY_EXTERN VALUE rb_cString; RUBY_EXTERN VALUE rb_cStruct; RUBY_EXTERN VALUE rb_cSymbol; RUBY_EXTERN VALUE rb_cThread; RUBY_EXTERN VALUE rb_cTime; RUBY_EXTERN VALUE rb_cTrueClass; RUBY_EXTERN VALUE rb_cUnboundMethod; RUBY_EXTERN VALUE rb_eException; RUBY_EXTERN VALUE rb_eStandardError; RUBY_EXTERN VALUE rb_eSystemExit; RUBY_EXTERN VALUE rb_eInterrupt; RUBY_EXTERN VALUE rb_eSignal; RUBY_EXTERN VALUE rb_eFatal; RUBY_EXTERN VALUE rb_eArgError; RUBY_EXTERN VALUE rb_eEOFError; RUBY_EXTERN VALUE rb_eIndexError; RUBY_EXTERN VALUE rb_eStopIteration; RUBY_EXTERN VALUE rb_eRangeError; RUBY_EXTERN VALUE rb_eIOError; RUBY_EXTERN VALUE rb_eRuntimeError; RUBY_EXTERN VALUE rb_eSecurityError; RUBY_EXTERN VALUE rb_eSystemCallError; RUBY_EXTERN VALUE rb_eThreadError; RUBY_EXTERN VALUE rb_eTypeError; RUBY_EXTERN VALUE rb_eZeroDivError; RUBY_EXTERN VALUE rb_eNotImpError; RUBY_EXTERN VALUE rb_eNoMemError; RUBY_EXTERN VALUE rb_eNoMethodError; RUBY_EXTERN VALUE rb_eFloatDomainError; RUBY_EXTERN VALUE rb_eLocalJumpError; RUBY_EXTERN VALUE rb_eSysStackError; RUBY_EXTERN VALUE rb_eRegexpError; RUBY_EXTERN VALUE rb_eScriptError; RUBY_EXTERN VALUE rb_eNameError; RUBY_EXTERN VALUE rb_eSyntaxError; RUBY_EXTERN VALUE rb_eLoadError; RUBY_EXTERN VALUE rb_stdin, rb_stdout, rb_stderr; RUBY_EXTERN VALUE ruby_errinfo; static inline VALUE #if defined(HAVE_PROTOTYPES) rb_class_of(VALUE obj) #else rb_class_of(obj) VALUE obj; #endif { if (FIXNUM_P(obj)) return rb_cFixnum; if (obj == Qnil) return rb_cNilClass; if (obj == Qfalse) return rb_cFalseClass; if (obj == Qtrue) return rb_cTrueClass; if (SYMBOL_P(obj)) return rb_cSymbol; return RBASIC(obj)->klass; } static inline int #if defined(HAVE_PROTOTYPES) rb_type(VALUE obj) #else rb_type(obj) VALUE obj; #endif { if (FIXNUM_P(obj)) return T_FIXNUM; if (obj == Qnil) return T_NIL; if (obj == Qfalse) return T_FALSE; if (obj == Qtrue) return T_TRUE; if (obj == Qundef) return T_UNDEF; if (SYMBOL_P(obj)) return T_SYMBOL; return BUILTIN_TYPE(obj); } static inline int #if defined(HAVE_PROTOTYPES) rb_special_const_p(VALUE obj) #else rb_special_const_p(obj) VALUE obj; #endif { if (SPECIAL_CONST_P(obj)) return Qtrue; return Qfalse; } #include "missing.h" #include "intern.h" #if defined(EXTLIB) && defined(USE_DLN_A_OUT) /* hook for external modules */ static char *dln_libs_to_be_linked[] = { EXTLIB, 0 }; #endif #if defined(HAVE_LIBPTHREAD) #ifdef HAVE_PTHREAD_H #include #endif typedef pthread_t rb_nativethread_t; # define NATIVETHREAD_CURRENT() pthread_self() # define NATIVETHREAD_EQUAL(t1,t2) pthread_equal((t1),(t2)) # define HAVE_NATIVETHREAD # define NATIVETHREAD_KILL(th,sig) pthread_kill((th),(sig)) # define HAVE_NATIVETHREAD_KILL #elif defined(_WIN32) || defined(_WIN32_WCE) typedef DWORD rb_nativethread_t; # define NATIVETHREAD_CURRENT() GetCurrentThreadId() # define NATIVETHREAD_EQUAL(t1,t2) ((t1) == (t2)) # define HAVE_NATIVETHREAD #endif #ifdef HAVE_NATIVETHREAD int is_ruby_native_thread _((void)); #else #define is_ruby_native_thread() (1) #endif #ifdef HAVE_NATIVETHREAD_KILL void ruby_native_thread_kill _((int)); #endif #if defined(__cplusplus) #if 0 { /* satisfy cc-mode */ #endif } /* extern "C" { */ #endif #endif /* ifndef RUBY_H */ ================================================ FILE: rubyio.h ================================================ /********************************************************************** rubyio.h - $Author$ $Date$ created at: Fri Nov 12 16:47:09 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #ifndef RUBYIO_H #define RUBYIO_H #include #include #if defined(HAVE_STDIO_EXT_H) #include #endif typedef struct rb_io_t { FILE *f; /* stdio ptr for read/write */ FILE *f2; /* additional ptr for rw pipes */ int mode; /* mode flags */ int pid; /* child's pid (for pipes) */ int lineno; /* number of lines read */ char *path; /* pathname for file */ void (*finalize) _((struct rb_io_t*,int)); /* finalize proc */ } rb_io_t; #define HAVE_RB_IO_T 1 #define OpenFile rb_io_t /* for backward compatibility */ #define FMODE_READABLE 1 #define FMODE_WRITABLE 2 #define FMODE_READWRITE 3 #define FMODE_APPEND 64 #define FMODE_CREATE 128 #define FMODE_BINMODE 4 #define FMODE_SYNC 8 #define FMODE_WBUF 16 #define FMODE_RBUF 32 #define FMODE_WSPLIT 0x200 #define FMODE_WSPLIT_INITIALIZED 0x400 #define GetOpenFile(obj,fp) rb_io_check_closed((fp) = RFILE(rb_io_taint_check(obj))->fptr) #define MakeOpenFile(obj, fp) do {\ if (RFILE(obj)->fptr) {\ rb_io_close(obj);\ free(RFILE(obj)->fptr);\ RFILE(obj)->fptr = 0;\ }\ fp = 0;\ fp = RFILE(obj)->fptr = ALLOC(rb_io_t);\ fp->f = fp->f2 = NULL;\ fp->mode = 0;\ fp->pid = 0;\ fp->lineno = 0;\ fp->path = NULL;\ fp->finalize = 0;\ } while (0) #define GetReadFile(fptr) ((fptr)->f) #define GetWriteFile(fptr) (((fptr)->f2) ? (fptr)->f2 : (fptr)->f) FILE *rb_fopen _((const char*, const char*)); FILE *rb_fdopen _((int, const char*)); int rb_getc _((FILE*)); long rb_io_fread _((char *, long, FILE *)); long rb_io_fwrite _((const char *, long, FILE *)); int rb_io_mode_flags _((const char*)); int rb_io_modenum_flags _((int)); void rb_io_check_writable _((rb_io_t*)); void rb_io_check_readable _((rb_io_t*)); void rb_io_fptr_finalize _((rb_io_t*)); void rb_io_synchronized _((rb_io_t*)); void rb_io_check_initialized _((rb_io_t*)); void rb_io_check_closed _((rb_io_t*)); int rb_io_wait_readable _((int)); int rb_io_wait_writable _((int)); void rb_io_set_nonblock(rb_io_t *fptr); VALUE rb_io_taint_check _((VALUE)); NORETURN(void rb_eof_error _((void))); void rb_read_check _((FILE*)); int rb_read_pending _((FILE*)); #endif ================================================ FILE: rubysig.h ================================================ /********************************************************************** rubysig.h - $Author$ $Date$ created at: Wed Aug 16 01:15:38 JST 1995 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #ifndef SIG_H #define SIG_H #include #if defined __ppc__ || defined __powerpc__ || \ defined __ppc64__ || defined __powerpc64__ #define __anyPowerPC__ 1 /* for compatibility with older gcc versions */ #endif /* STACK_WIPE_SITES determines where attempts are made to exorcise "ghost object refereces" from the stack and how the stack is cleared: 0x*001 --> wipe stack just after every thread_switch 0x*002 --> wipe stack just after every EXEC_TAG() 0x*004 --> wipe stack in CHECK_INTS 0x*010 --> wipe stack in while & until loops 0x*020 --> wipe stack before yield() in iterators and outside eval.c 0x*040 --> wipe stack on catch and thread save context 0x*100 --> update stack extent on each object allocation 0x*200 --> update stack extent on each object reallocation 0x*400 --> update stack extent during GC marking passes 0x*800 --> update stack extent on each throw (use with 0x040) 0x1000 --> use inline assembly code for x86, PowerPC, or ARM CPUs 0x0*** --> do not even call rb_wipe_stack() 0x2*** --> call dummy rb_wipe_stack() (for debugging and profiling) 0x4*** --> safe, portable stack clearing in memory allocated with alloca 0x6*** --> use faster, but less safe stack clearing in unallocated stack 0x8*** --> use faster, but less safe stack clearing (with inline code) for most effective gc use 0x*707 for fastest micro-benchmarking use 0x0000 0x*770 prevents almost all memory leaks caused by ghost references without adding much overhead for stack clearing. Other good trade offs are 0x*270, 0x*703, 0x*303 or even 0x*03 In general, you may lessen the default -mpreferred-stack-boundary only if using less safe stack clearing (0x6***). Lessening the stack alignment with portable stack clearing (0x4***) may fail to clear all ghost references off the stack. When using 0x6*** or 0x8***, the compiler could insert stack push(s) between reading the stack pointer and clearing the ghost references. The register(s) pushed will be cleared by the rb_gc_stack_wipe(), typically resulting in a segfault or an interpreter hang. STACK_WIPE_SITES of 0x8770 works well compiled with gcc on most machines using the recommended CFLAGS="-O2 -fno-stack-protector". However... If it hangs or crashes for you, try changing STACK_WIPE_SITES to 0x4770 and please report your details. i.e. CFLAGS, compiler, version, CPU Note that it is redundant to wipe_stack in looping constructs if also doing so in CHECK_INTS. It is also redundant to wipe_stack on each thread_switch if wiping after every thread save context. */ #ifndef STACK_WIPE_SITES # ifdef __x86_64__ /* deal with "red zone" by not inlining stack clearing */ # define STACK_WIPE_SITES 0x6770 # elif defined __anyPowerPC__ /* On any PowerPC, deal with... */ # define STACK_WIPE_SITES 0x7764 /* red zone & alloc(0) doesn't return sp */ # else # define STACK_WIPE_SITES 0x8770 /*normal case, use 0x4770 if problems arise*/ # endif #endif #if (STACK_WIPE_SITES & 0x14) == 0x14 #warning wiping stack in CHECK_INTS makes wiping in loops redundant #endif #if (STACK_WIPE_SITES & 0x41) == 0x41 #warning wiping stack after thread save makes wiping on thread_switch redundant #endif #define STACK_WIPE_METHOD (STACK_WIPE_SITES>>13) #ifdef _WIN32 typedef LONG rb_atomic_t; # define ATOMIC_TEST(var) InterlockedExchange(&(var), 0) # define ATOMIC_SET(var, val) InterlockedExchange(&(var), (val)) # define ATOMIC_INC(var) InterlockedIncrement(&(var)) # define ATOMIC_DEC(var) InterlockedDecrement(&(var)) /* Windows doesn't allow interrupt while system calls */ # define TRAP_BEG do {\ int saved_errno = 0;\ rb_atomic_t trap_immediate = ATOMIC_SET(rb_trap_immediate, 1) # define TRAP_END\ ATOMIC_SET(rb_trap_immediate, trap_immediate);\ saved_errno = errno;\ CHECK_INTS;\ errno = saved_errno;\ } while (0) # define RUBY_CRITICAL(statements) do {\ rb_w32_enter_critical();\ statements;\ rb_w32_leave_critical();\ } while (0) #else typedef int rb_atomic_t; # define ATOMIC_TEST(var) ((var) ? ((var) = 0, 1) : 0) # define ATOMIC_SET(var, val) ((var) = (val)) # define ATOMIC_INC(var) (++(var)) # define ATOMIC_DEC(var) (--(var)) # define TRAP_BEG do {\ int saved_errno = 0;\ int trap_immediate = rb_trap_immediate;\ rb_trap_immediate = 1 # define TRAP_END rb_trap_immediate = trap_immediate;\ saved_errno = errno;\ CHECK_INTS;\ errno = saved_errno;\ } while (0) # define RUBY_CRITICAL(statements) do {\ int trap_immediate = rb_trap_immediate;\ rb_trap_immediate = 0;\ statements;\ rb_trap_immediate = trap_immediate;\ } while (0) #endif RUBY_EXTERN rb_atomic_t rb_trap_immediate; RUBY_EXTERN int rb_prohibit_interrupt; #define DEFER_INTS (rb_prohibit_interrupt++) #define ALLOW_INTS do {\ rb_prohibit_interrupt--;\ CHECK_INTS;\ } while (0) #define ENABLE_INTS (rb_prohibit_interrupt--) VALUE rb_with_disable_interrupt _((VALUE(*)(ANYARGS),VALUE)); RUBY_EXTERN rb_atomic_t rb_trap_pending; void rb_trap_restore_mask _((void)); RUBY_EXTERN int rb_thread_critical; void rb_thread_schedule _((void)); RUBY_EXTERN int rb_gc_stack_grow_direction; /* -1 for down or 1 for up */ #if STACK_GROW_DIRECTION > 0 /* clear stack space between end and sp (not including *sp) */ #define __stack_zero(end,sp) __stack_zero_up(end,sp) /* true if top has grown past limit, i.e. top deeper than limit */ #define __stack_past(limit,top) __stack_past_up(limit,top) /* depth of mid below stack top */ #define __stack_depth(top,mid) __stack_depth_up(top,mid) /* stack pointer top adjusted to include depth more items */ #define __stack_grow(top,depth) __stack_grow_up(top,depth) #elif STACK_GROW_DIRECTION < 0 #define __stack_zero(end,sp) __stack_zero_down(end,sp) #define __stack_past(limit,top) __stack_past_down(limit,top) #define __stack_depth(top,mid) __stack_depth_down(top,mid) #define __stack_grow(top,depth) __stack_grow_down(top,depth) #else /* limp along if stack direction can't be determined at compile time */ #define __stack_zero(end,sp) if (rb_gc_stack_grow_direction<0) \ __stack_zero_down(end,sp); else __stack_zero_up(end,sp); #define __stack_past(limit,top) (rb_gc_stack_grow_direction<0 ? \ __stack_past_down(limit,top) : __stack_past_up(limit,top)) #define __stack_depth(top,mid) (rb_gc_stack_grow_direction<0 ? \ __stack_depth_down(top,mid) : __stack_depth_up(top,mid)) #define __stack_grow(top,depth) (rb_gc_stack_grow_direction<0 ? \ __stack_grow_down(top,depth) : __stack_grow_up(top,depth)) #endif #define __stack_zero_up(end,sp) while (end >= ++sp) *sp=0 #define __stack_past_up(limit,top) ((limit) < (top)) #define __stack_depth_up(top,mid) ((top) - (mid)) #define __stack_grow_up(top,depth) ((top)+(depth)) #define __stack_zero_down(end,sp) while (end <= --sp) *sp=0 #define __stack_past_down(limit,top) ((limit) > (top)) #define __stack_depth_down(top,mid) ((mid) - (top)) #define __stack_grow_down(top,depth) ((top)-(depth)) /* Make alloca work the best possible way. */ #ifdef __GNUC__ # ifndef atarist # ifndef alloca # define alloca __builtin_alloca # endif # endif /* atarist */ # define nativeAllocA __builtin_alloca /* use assembly to get stack pointer quickly */ # if STACK_WIPE_SITES & 0x1000 # define __defspfn(asmb) \ static inline VALUE *__sp(void) __attribute__((always_inline)); \ static inline VALUE *__sp(void) \ { \ VALUE *sp; asm(asmb); \ return sp; \ } # ifdef __anyPowerPC__ __defspfn("addi %0, r1, 0": "=r"(sp)) # elif defined __i386__ __defspfn("movl %%esp, %0": "=r"(sp)) # elif defined __x86_64__ #warn ===> x86_64 inline assembler is known to crash -- change STACK_WIPE_SITES __defspfn("movq %%rsp, %0": "=r"(sp)) # elif __arm__ __defspfn("mov %0, sp": "=r"(sp)) # else # define __sp() ((VALUE *)__builtin_alloca(0)) # warning No assembly version of __sp() defined for this CPU. # endif # else # define __sp() ((VALUE *)__builtin_alloca(0)) # endif #else // not GNUC # ifdef HAVE_ALLOCA_H # include # else # ifndef _AIX # ifndef alloca /* predefined by HP cc +Olibcalls */ void *alloca (); # endif # endif /* AIX */ # endif /* HAVE_ALLOCA_H */ # if STACK_WIPE_SITES & 0x1000 # warning No assembly versions of __sp() defined for this compiler. # endif # if HAVE_ALLOCA # define __sp() ((VALUE *)alloca(0)) # define nativeAllocA alloca # else RUBY_EXTERN VALUE *__sp(void); # if STACK_WIPE_SITES # define STACK_WIPE_SITES 0 # warning Disabled Stack Wiping because there is no native alloca() # endif # endif #endif /* __GNUC__ */ /* Zero memory that was (recently) part of the stack, but is no longer. Invoke when stack is deep to mark its extent and when it's shallow to wipe it. */ #if STACK_WIPE_METHOD == 0 #define rb_gc_wipe_stack() ((void)0) #elif STACK_WIPE_METHOD == 4 #define rb_gc_wipe_stack() do { \ if (rb_curr_thread) { \ VALUE *end = rb_curr_thread->gc_stack_end; \ VALUE *sp = __sp(); \ rb_curr_thread->gc_stack_end = sp; \ __stack_zero(end, sp); \ } \ } while (0) #else RUBY_EXTERN void rb_gc_wipe_stack(void); #endif /* Update our record of maximum stack extent without zeroing unused stack */ #define rb_gc_update_stack_extent() do { \ VALUE *sp = __sp(); \ if (rb_curr_thread && __stack_past(rb_curr_thread->gc_stack_end, sp)) rb_curr_thread->gc_stack_end = sp; \ } while(0) #if STACK_WIPE_SITES & 4 # define CHECK_INTS_wipe_stack() rb_gc_wipe_stack() #else # define CHECK_INTS_wipe_stack() (void)0 #endif #if defined(HAVE_SETITIMER) || defined(_THREAD_SAFE) RUBY_EXTERN int rb_thread_pending; # define CHECK_INTS do {\ CHECK_INTS_wipe_stack(); \ if (!(rb_prohibit_interrupt || rb_thread_critical)) {\ if (rb_thread_pending) rb_thread_schedule();\ if (rb_trap_pending) rb_trap_exec();\ }\ } while (0) #else /* pseudo preemptive thread switching */ RUBY_EXTERN int rb_thread_tick; #define THREAD_TICK 500 #define CHECK_INTS do {\ CHECK_INTS_wipe_stack(); \ if (!(rb_prohibit_interrupt || rb_thread_critical)) {\ if (rb_thread_tick-- <= 0) {\ rb_thread_tick = THREAD_TICK;\ rb_thread_schedule();\ }\ if (rb_trap_pending) rb_trap_exec();\ }\ } while (0) #endif #endif ================================================ FILE: rubytest.rb ================================================ #! ./miniruby exit if defined?(CROSS_COMPILING) load './rbconfig.rb' include Config ruby = "./#{CONFIG['ruby_install_name']}#{CONFIG['EXEEXT']}" unless File.exist? ruby print "#{ruby} is not found.\n" print "Try `make' first, then `make test', please.\n" exit false end if File.exist? CONFIG['LIBRUBY_SO'] case RUBY_PLATFORM when /-hpux/ dldpath = "SHLIB_PATH" when /-aix/ dldpath = "LIBPATH" when /-beos/ dldpath = "LIBRARY_PATH" when /-darwin/ dldpath = "DYLD_LIBRARY_PATH" else dldpath = "LD_LIBRARY_PATH" end x = ENV[dldpath] x = x ? ".:"+x : "." ENV[dldpath] = x end if /linux/ =~ RUBY_PLATFORM and File.exist? CONFIG['LIBRUBY_SO'] ENV["LD_PRELOAD"] = "./#{CONFIG['LIBRUBY_SO']}" end $stderr.reopen($stdout) error = '' srcdir = File.dirname(__FILE__) `#{ruby} -I#{srcdir}/lib #{srcdir}/sample/test.rb`.each do |line| if line =~ /^end of test/ print "test succeeded\n" exit 0 end error << line if line =~ %r:^(sample/test.rb|not): end print error print "test failed\n" exit 1 ================================================ FILE: runruby.rb ================================================ #!./miniruby pure = true while arg = ARGV[0] break ARGV.shift if arg == '--' /\A--([-\w]+)(?:=(.*))?\z/ =~ arg or break arg, value = $1, $2 re = Regexp.new('\A'+arg.gsub(/\w+\b/, '\&\\w*')+'\z', "i") case when re =~ "srcdir" srcdir = value when re =~ "archdir" archdir = value when re =~ "extout" extout = value when re =~ "pure" pure = (value != "no") when re =~ "debugger" debugger = value ? (value.split unless value == "no") : %w"gdb --args" else break end ARGV.shift end srcdir ||= File.dirname(__FILE__) archdir ||= '.' abs_archdir = File.expand_path(archdir) $:.unshift(abs_archdir) require 'rbconfig' config = RbConfig::CONFIG ruby = File.join(archdir, config["RUBY_INSTALL_NAME"]+config['EXEEXT']) unless File.exist?(ruby) abort "#{ruby} is not found.\nTry `make' first, then `make test', please.\n" end libs = [abs_archdir] if extout abs_extout = File.expand_path(extout) libs << File.expand_path("common", abs_extout) << File.expand_path(RUBY_PLATFORM, abs_extout) end libs << File.expand_path("lib", srcdir) config["bindir"] = abs_archdir ENV["RUBY"] = File.expand_path(ruby) ENV["PATH"] = [abs_archdir, ENV["PATH"]].compact.join(File::PATH_SEPARATOR) if pure libs << File.expand_path("ext", srcdir) << "-" elsif e = ENV["RUBYLIB"] libs |= e.split(File::PATH_SEPARATOR) end ENV["RUBYLIB"] = $:.replace(libs).join(File::PATH_SEPARATOR) libruby_so = File.join(abs_archdir, config['LIBRUBY_SO']) if File.file?(libruby_so) if e = config['LIBPATHENV'] and !e.empty? ENV[e] = [abs_archdir, ENV[e]].compact.join(File::PATH_SEPARATOR) end if /linux/ =~ RUBY_PLATFORM ENV["LD_PRELOAD"] = [libruby_so, ENV["LD_PRELOAD"]].compact.join(' ') end end cmd = [ruby] cmd << "-rpurelib.rb" if pure cmd.concat(ARGV) cmd.unshift(*debugger) if debugger exec(*cmd) ================================================ FILE: sample/README ================================================ README this file biorhythm.rb biorhythm calculator cal.rb cal(1) clone cbreak.rb no echo done by ioctl clnt.rb socket client dbmtest.rb test for dbm dir.rb directory access dualstack-fetch.rb IPv6 demo dualstack-httpd.rb IPv6 demo dstore.rb object database on dbm eval.rb simple evaluator export.rb method access example exyacc.rb extrace BNF from yacc file fact.rb factorial calculator fib.awk Fibonacci number (AWK) fib.pl Fibonacci number (Perl) fib.py Fibonacci number (Python) fib.rb Fibonacci number (Ruby) fib.scm Fibonacci number (Scheme) freq.rb count word occurrence from.rb scan mail spool fullpath.rb convert ls -lR to fullpath format getopts.test test fot getopt.rb io.rb io test irb.rb interactive ruby less.rb front end for less list.rb stupid object sample list2.rb stupid object sample list3.rb stupid object sample mine.rb simple mine sweeper mkproto.rb extract prototype from C mpart.rb split file int multi part mrshtest.rb test marshal observ.rb observer design pattern sample occur.pl count word occurrence (Perl) occur.rb count word occurrence (Ruby) occur2.rb count word occurrence - another style philos.rb famous dining philosophers pi.rb calculate PI rcs.awk random character stereogram (AWK) rcs.rb random character stereogram (Ruby) rcs.dat data for random character stereogram rd2html.rb rd (Ruby Document) to HTML translator regx.rb regular expression tester sieve.rb sieve of Eratosthenes svr.rb socket server test.rb test suite used by `make test' time.rb /usr/bin/time clone trojan.rb simple tool to find file that may be trojan horse. tsvr.rb socket server using thread uumerge.rb merge files and uudecode them ================================================ FILE: sample/biorhythm.rb ================================================ #!/usr/local/bin/ruby # # biorhythm.rb - # $Release Version: $ # $Revision$ # $Date$ # by Yasuo OHBA(STAFS Development Room) # # -- # # # # probably based on: # # Newsgroups: comp.sources.misc,de.comp.sources.os9 # From: fkk@stasys.sta.sub.org (Frank Kaefer) # Subject: v41i126: br - Biorhythm v3.0, Part01/01 # Message-ID: <1994Feb1.070616.15982@sparky.sterling.com> # Sender: kent@sparky.sterling.com (Kent Landfield) # Organization: Sterling Software # Date: Tue, 1 Feb 1994 07:06:16 GMT # # Posting-number: Volume 41, Issue 126 # Archive-name: br/part01 # Environment: basic, dos, os9 include Math require "date.rb" require "parsearg.rb" require "parsedate.rb" def usage() print "Usage:\n" print "biorhythm.rb [options]\n" print " options...\n" print " -D YYYYMMDD(birthday) : use default values.\n" print " --sdate | --date YYYYMMDD : use system date; use specified date.\n" print " --birthday YYYYMMDD : specifies your birthday.\n" print " -v | -g : show values or graph.\n" print " --days DAYS : graph range (only in effect for graphs).\n" print " --help : help\n" end $USAGE = 'usage' def printHeader(y, m, d, p, w) print "\n>>> Biorhythm <<<\n" printf "The birthday %04d.%02d.%02d is a %s\n", y, m, d, w printf "Age in days: [%d]\n\n", p end def getPosition(z) pi = Math::PI z = Integer(z) phys = (50.0 * (1.0 + sin((z / 23.0 - (z / 23)) * 360.0 * pi / 180.0))).to_i emot = (50.0 * (1.0 + sin((z / 28.0 - (z / 28)) * 360.0 * pi / 180.0))).to_i geist =(50.0 * (1.0 + sin((z / 33.0 - (z / 33)) * 360.0 * pi / 180.0))).to_i return phys, emot, geist end def parsedate(s) ParseDate::parsedate(s).values_at(0, 1, 2) end def name_of_week(date) Date::DAYNAMES[date.wday] end # # main program # parseArgs(0, nil, "vg", "D:", "sdate", "date:", "birthday:", "days:") if $OPT_D dd = Date.today bd = Date.new(*parsedate($OPT_D)) ausgabeart = "g" else if $OPT_birthday bd = Date.new(*parsedate($OPT_birthday)) else STDERR.print("Birthday (YYYYMMDD) : ") unless (si = STDIN.gets.chop).empty? bd = Date.new(*parsedate(si)) end end if !bd STDERR.print "BAD Input Birthday!!\n" exit() end if $OPT_sdate dd = Date.today elsif $OPT_date dd = Date.new(*parsedate($OPT_date)) else STDERR.print("Date [ for Systemdate] (YYYYMMDD) : ") unless (si = STDIN.gets.chop).empty? dd = Date.new(*parsedate(si)) end end dd ||= Date.today if $OPT_v ausgabeart = "v" elsif $OPT_g ausgabeart = "g" else STDERR.print("Values for today or Graph (v/g) [default g] : ") ausgabeart = STDIN.gets.chop end end if ausgabeart == "v" printHeader(bd.year, bd.month, bd.day, dd - bd, name_of_week(bd)) print "\n" phys, emot, geist = getPosition(dd - bd) printf "Biorhythm: %04d.%02d.%02d\n", dd.year, dd.month, dd.day printf "Physical: %d%%\n", phys printf "Emotional: %d%%\n", emot printf "Mental: %d%%\n", geist print "\n" else if $OPT_days display_period = $OPT_days.to_i elsif $OPT_D display_period = 9 else STDERR.printf("Graph for how many days [default 10] : ") display_period = STDIN.gets.chop if display_period.empty? display_period = 9 else display_period = display_period.to_i - 1 end end printHeader(bd.year, bd.month, bd.day, dd - bd, name_of_week(bd)) print " P=physical, E=emotional, M=mental\n" print " -------------------------+-------------------------\n" print " Bad Condition | Good Condition\n" print " -------------------------+-------------------------\n" (dd - bd).step(dd - bd + display_period) do |z| phys, emot, geist = getPosition(z) printf "%04d.%02d.%02d : ", dd.year, dd.month, dd.day p = (phys / 2.0 + 0.5).to_i e = (emot / 2.0 + 0.5).to_i g = (geist / 2.0 + 0.5).to_i graph = "." * 51 graph[25] = ?| graph[p] = ?P graph[e] = ?E graph[g] = ?M print graph, "\n" dd = dd + 1 end print " -------------------------+-------------------------\n\n" end ================================================ FILE: sample/cal.rb ================================================ #! /usr/bin/env ruby # cal.rb: Written by Tadayoshi Funaba 1998-2004,2006,2008 # $Id: cal.rb,v 2.11 2008-01-06 08:42:17+09 tadf Exp $ require 'date' class Cal START = { 'cn' => Date::GREGORIAN, # China 'de' => 2342032, # Germany (protestant states) 'dk' => 2342032, # Denmark 'es' => 2299161, # Spain 'fi' => 2361390, # Finland 'fr' => 2299227, # France 'gb' => 2361222, # United Kingdom 'gr' => 2423868, # Greece 'hu' => 2301004, # Hungary 'it' => 2299161, # Italy 'jp' => Date::GREGORIAN, # Japan 'no' => 2342032, # Norway 'pl' => 2299161, # Poland 'pt' => 2299161, # Portugal 'ru' => 2421639, # Russia 'se' => 2361390, # Sweden 'us' => 2361222, # United States 'os' => Date::JULIAN, # (old style) 'ns' => Date::GREGORIAN # (new style) } DEFAULT_START = 'gb' def initialize opt_j; opt_m; opt_t; opt_y; opt_c end def opt_j(flag=false) @opt_j = flag end def opt_m(flag=false) @opt_m = flag end def opt_t(flag=false) @opt_t = flag end def opt_y(flag=false) @opt_y = flag end def opt_c(arg=DEFAULT_START) @start = START[arg] end def set_params @dw = if @opt_j then 3 else 2 end @mw = (@dw + 1) * 7 - 1 @mn = if @opt_j then 2 else 3 end @tw = (@mw + 2) * @mn - 2 @k = if @opt_m then 1 else 0 end @da = if @opt_j then :yday else :mday end end def pict(y, m) d = (1..31).detect{|x| Date.valid_date?(y, m, x, @start)} fi = Date.new(y, m, d, @start) fi -= (fi.jd - @k + 1) % 7 ve = (fi..fi + 6).collect{|cu| %w(S M Tu W Th F S)[cu.wday] } ve += (fi..fi + 41).collect{|cu| if cu.mon == m then cu.send(@da) end.to_s } ve = ve.collect{|e| e.rjust(@dw)} gr = group(ve, 7) gr = trans(gr) if @opt_t ta = gr.collect{|xs| xs.join(' ')} ca = %w(January February March April May June July August September October November December)[m - 1] ca = ca + ' ' + y.to_s if !@opt_y ca = ca.center(@mw) ta.unshift(ca) end def group(xs, n) (0..xs.size / n - 1).collect{|i| xs[i * n, n]} end def trans(xs) (0..xs[0].size - 1).collect{|i| xs.collect{|x| x[i]}} end def stack(xs) if xs.empty? then [] else xs[0] + stack(xs[1..-1]) end end def block(xs, n) stack(group(xs, n).collect{|ys| trans(ys).collect{|zs| zs.join(' ')}}) end def unlines(xs) xs.collect{|x| x + "\n"}.join end def monthly(y, m) unlines(pict(y, m)) end def addmon(y, m, n) y, m = (y * 12 + (m - 1) + n).divmod(12) return y, m + 1 end def yearly(y) y.to_s.center(@tw) + "\n\n" + unlines(block((0..11).collect{|n| pict(*addmon(y, 1, n))}, @mn)) + "\n" end def print(y, m) set_params if @opt_y then yearly(y) else monthly(y, m) end end end if __FILE__ == $0 require 'getoptlong' def usage warn 'usage: cal [-c iso3166] [-jmty] [[month] year]' exit 1 end cal = Cal.new begin GetoptLong.new(['-c', GetoptLong::REQUIRED_ARGUMENT], ['-j', GetoptLong::NO_ARGUMENT], ['-m', GetoptLong::NO_ARGUMENT], ['-t', GetoptLong::NO_ARGUMENT], ['-y', GetoptLong::NO_ARGUMENT]). each do |opt, arg| case opt when '-c'; cal.opt_c(arg) || raise when '-j'; cal.opt_j(true) when '-m'; cal.opt_m(true) when '-t'; cal.opt_t(true) when '-y'; cal.opt_y(true) end end rescue usage end y, m = ARGV.values_at(1, 0).compact.collect{|x| x.to_i} cal.opt_y(true) if y && !m to = Date.today y ||= to.year m ||= to.mon usage unless m >= 1 && m <= 12 usage unless y >= -4712 print cal.print(y, m) end # See Bird & Wadler's Introduction to functional programming 4.5. ================================================ FILE: sample/cbreak.rb ================================================ # ioctl example works on Sun CBREAK = 0x00000002 ECHO = 0x00000008 TIOCGETP = 0x40067408 TIOCSETP = 0x80067409 def cbreak () set_cbreak(true) end def cooked () set_cbreak(false) end def set_cbreak (on) tty = "\0" * 256 STDIN.ioctl(TIOCGETP, tty) ttys = tty.unpack("C4 S") if on ttys[4] |= CBREAK ttys[4] &= ~ECHO else ttys[4] &= ~CBREAK ttys[4] |= ECHO end tty = ttys.pack("C4 S") STDIN.ioctl(TIOCSETP, tty) end cbreak(); print("this is no-echo line: "); readline().print cooked(); print("this is echo line: "); readline() ================================================ FILE: sample/clnt.rb ================================================ # socket example - client side # usage: ruby clnt.rb [host] port require "socket" if ARGV.length >= 2 host = ARGV.shift else host = "localhost" end print("Trying ", host, " ...") STDOUT.flush s = TCPSocket.open(host, ARGV.shift) print(" done\n") print("addr: ", s.addr.join(":"), "\n") print("peer: ", s.peeraddr.join(":"), "\n") while line = gets() s.write(line) print(s.readline) end s.close ================================================ FILE: sample/dbmtest.rb ================================================ # ruby dbm acess require "dbm" d = DBM.open("test") keys = d.keys if keys.length > 0 then for k in keys; print k, "\n"; end for v in d.values; print v, "\n"; end else d['foobar'] = 'FB' d['baz'] = 'BZ' d['quux'] = 'QX' end ================================================ FILE: sample/dir.rb ================================================ # directory access # list all files but .*/*~/*.o dirp = Dir.open(".") for f in dirp case f when /^\./, /~$/, /\.o/ # do not print else print f, "\n" end end dirp.close ================================================ FILE: sample/drb/README.rd ================================================ = Sample scripts * array and iteretor * darray.rb --- server * darrayc.rb --- client * simple chat * dchats.rb --- server * dchatc.rb --- client * distributed chasen (for Japanese) * dhasen.rb --- server * dhasenc.rb --- client * simple log server * dlogd.rb --- server * dlogc.rb --- client * Queue server, and DRbUnknown demo * dqueue.rb --- server * dqin.rb --- client. push DQEntry objects. * dqout.rb --- client. pop DQEntry objects. * dqlib.rb --- define DQEntry * IdConv customize demo: reference by name * name.rb --- server * namec.rb --- client * extserv * extserv_test.rb * IdConv customize demo 2: using TimerIdConv * holders.rb --- server * holderc.rb --- client * rinda, remote tuplespace * rinda_ts.rb --- TupleSpace server. * rindas.rb --- provide simple service via TupleSpace. * rindac.rb --- service user * observer cdbiff - (()) * dbiff.rb --- dcdbiff server * dcdbiff.rb --- dcdbiff client * drbssl * drbssl_s.rb * drbssl_c.rb * add DRbProtocl * http0.rb * http0serv.rb * Rinda::Ring * ring_place.rb * ring_echo.rb ================================================ FILE: sample/drb/README.rd.ja ================================================ = ץ륹ץ * Array⡼ȤѤƥƥ졼 * darray.rb --- server * darrayc.rb --- client * ʰץå * dchats.rb --- server * dchatc.rb --- client * ʬchasen * dhasen.rb --- server * dhasenc.rb --- client * ʰץ * dlogd.rb --- server * dlogc.rb --- client * QueueС 饤dqin.rbQueueФΤʤ֥(DQEntry) push뤬DRbUnknownˤꥯ饤dqout.rbpopǤ롣 * dqueue.rb --- server * dqin.rb --- clientDQEntry֥Ȥpush * dqout.rb --- clientDQEntry֥Ȥpop * dqlib.rb --- DQEntry饤֥ * ̾ˤ뻲 IdConv򥫥ޥidǤʤ̾ǻȤ * name.rb --- server * namec.rb --- client * extservΥץ * extserv_test.rb * TimerIdConvλ * holders.rb --- serverruby -d hodlers.rbȤTimerIdConvѤ롣 * holderc.rb --- client * rinda.rbλ * rinda_ts.rb --- TupleSpaceС * rindac.rb --- TupleSpaceclientǥץꥱclient * rindas.rb --- TupleSpaceclientǥץꥱserver * observerλ cdbiff - (()) * dbiff.rb --- dcdbiff server * dcdbiff.rb --- dcdbiff client * drbsslλ * drbssl_s.rb * drbssl_c.rb * DRbProtoclɲ * http0.rb * http0serv.rb * ringλ * ring_place.rb * ring_echo.rb ================================================ FILE: sample/drb/darray.rb ================================================ =begin distributed Ruby --- Array Copyright (c) 1999-2001 Masatoshi SEKI =end require 'drb/drb' here = ARGV.shift DRb.start_service(here, [1, 2, "III", 4, "five", 6]) puts DRb.uri DRb.thread.join ================================================ FILE: sample/drb/darrayc.rb ================================================ =begin distributed Ruby --- Array client Copyright (c) 1999-2001 Masatoshi SEKI =end require 'drb/drb' there = ARGV.shift || raise("usage: #{$0} ") DRb.start_service(nil, nil) ro = DRbObject.new(nil, there) p ro.size puts "# collect" a = ro.collect { |x| x + x } p a puts "# find" p ro.find { |x| x.kind_of? String } puts "# each, break" ro.each do |x| next if x == "five" puts x end puts "# each, break" ro.each do |x| break if x == "five" puts x end puts "# each, next" ro.each do |x| next if x == "five" puts x end puts "# each, redo" count = 0 ro.each do |x| count += 1 puts count redo if count == 3 end puts "# each, retry" retried = false ro.each do |x| puts x if x == 4 && !retried puts 'retry' retried = true retry end end ================================================ FILE: sample/drb/dbiff.rb ================================================ # # dbiff.rb - distributed cdbiff (server) # * original: cdbiff by Satoru Takabayashi require 'drb/drb' require 'drb/eq' require 'drb/observer' class Biff include DRb::DRbObservable def initialize(filename, interval) super() @filename = filename @interval = interval end def run last = Time.now while true begin sleep(@interval) current = File::mtime(@filename) if current > last changed begin notify_observers(@filename, current) rescue Error end last = current end rescue next end end end end def main filename = "/var/mail/#{ENV['USER']}" interval = 15 uri = 'druby://:19903' biff = Biff.new(filename, interval) DRb.start_service(uri, biff) biff.run end main ================================================ FILE: sample/drb/dcdbiff.rb ================================================ # # dcdbiff.rb - distributed cdbiff (client) # * original: cdbiff by Satoru Takabayashi require 'drb/drb' require 'drb/eq' class Notify include DRbUndumped def initialize(biff, command) @biff = biff @command = command @biff.add_observer(self) end def update(filename, time) p [filename, time] if $DEBUG system(@command) end def done begin @biff.delete_observer(self) rescue end end end def main command = 'eject' uri = 'druby://localhost:19903' DRb.start_service biff = DRbObject.new(nil, uri) notify = Notify.new(biff, command) trap("INT"){ notify.done } DRb.thread.join end main ================================================ FILE: sample/drb/dchatc.rb ================================================ =begin distributed Ruby --- chat client Copyright (c) 1999-2000 Masatoshi SEKI =end require 'drb/drb' class ChatClient include DRbUndumped def initialize(name) @name = name @key = nil end attr_reader(:name) attr_accessor(:key) def message(there, str) raise 'invalid key' unless @key == there puts str end end if __FILE__ == $0 begin there = ARGV.shift name = ARGV.shift raise "usage" unless (there and name) rescue $stderr.puts("usage: #{$0} ") exit 1 end DRb.start_service ro = DRbObject.new(nil, there) chat = ChatClient.new(name) entry = ro.add_member(chat) while gets entry.say($_) end end ================================================ FILE: sample/drb/dchats.rb ================================================ =begin distributed Ruby --- chat server Copyright (c) 1999-2000 Masatoshi SEKI =end require 'thread' require 'drb/drb' class ChatEntry include DRbUndumped def initialize(server, there) @server = server @there = there @name = there.name @key = there.key = Time.now end attr :name, true attr :there def say(str) @server.distribute(@there, str) end def listen(str) @there.message(@key, str) end end class ChatServer def initialize @mutex = Mutex.new @members = {} end def add_member(there) client = ChatEntry.new(self, there) @mutex.synchronize do @members[there] = client end client end def distribute(there, str) name = @members[there].name msg = "<#{name}> #{str}" msg2 = ">#{name}< #{str}" @mutex.synchronize do for m in @members.keys begin if m == there @members[m].listen(msg2) else @members[m].listen(msg) end rescue p $! @members.delete(m) end end end end end if __FILE__ == $0 here = ARGV.shift DRb.start_service(here, ChatServer.new) puts DRb.uri DRb.thread.join end ================================================ FILE: sample/drb/dhasen.rb ================================================ =begin distributed Ruby --- dRuby Sample Server --- chasen server Copyright (c) 1999-2001 Masatoshi SEKI =end =begin How to play. Terminal 1 | % ruby dhasen.rb | druby://yourhost:7640 Terminal 2 | % ruby dhasenc.rb druby://yourhost:7640 =end require 'drb/drb' require 'chasen' require 'thread' class Dhasen include DRbUndumped def initialize @mutex = Mutex.new end def sparse(str, *arg) @mutex.synchronize do Chasen.getopt(*arg) Chasen.sparse(str) end end end if __FILE__ == $0 DRb.start_service(nil, Dhasen.new) puts DRb.uri DRb.thread.join end ================================================ FILE: sample/drb/dhasenc.rb ================================================ =begin distributed Ruby --- dRuby Sample Client -- chasen client Copyright (c) 1999-2001 Masatoshi SEKI =end require 'drb/drb' there = ARGV.shift || raise("usage: #{$0} ") DRb.start_service dhasen = DRbObject.new(nil, there) print dhasen.sparse("ϡŷʤꡣ", "-F", '(%BB %m %M)\n', "-j") print dhasen.sparse("ϡŷʤꡣ", "-F", '(%m %M)\n') ================================================ FILE: sample/drb/dlogc.rb ================================================ =begin distributed Ruby --- Log test Copyright (c) 1999-2001 Masatoshi SEKI =end require 'drb/drb' there = ARGV.shift || raise("usage: #{$0} ") DRb.start_service ro = DRbObject.new(nil, there) ro.log(123) ro.log("hello") sleep 2 ro.log("wakeup") ================================================ FILE: sample/drb/dlogd.rb ================================================ =begin distributed Ruby --- Log server Copyright (c) 1999-2000 Masatoshi SEKI =end require 'drb/drb' require 'thread' class Logger def initialize(fname) @fname = fname.to_s @fp = File.open(@fname, "a+") @queue = Queue.new @th = Thread.new { self.flush } end def log(str) @queue.push("#{Time.now}\t" + str.to_s) end def flush begin while(1) @fp.puts(@queue.pop) @fp.flush end ensure @fp.close end end end if __FILE__ == $0 here = ARGV.shift DRb.start_service(here, Logger.new('/usr/tmp/dlogd.log')) puts DRb.uri DRb.thread.join end ================================================ FILE: sample/drb/dqin.rb ================================================ =begin distributed Ruby --- store Copyright (c) 1999-2000 Masatoshi SEKI =end require 'drb/drb' require 'dqlib' there = ARGV.shift || raise("usage: #{$0} ") DRb.start_service queue = DRbObject.new(nil, there) queue.push(DQEntry.new(DRb.uri)) ================================================ FILE: sample/drb/dqlib.rb ================================================ class DQEntry def initialize(name) @name = name end def greeting "Hello, This is #{@name}." end alias to_s greeting end if __FILE__ == $0 puts DQEntry.new('DQEntry') end ================================================ FILE: sample/drb/dqout.rb ================================================ =begin distributed Ruby --- fetch Copyright (c) 1999-2000 Masatoshi SEKI =end require 'drb/drb' require 'dqlib' there = ARGV.shift || raise("usage: #{$0} ") DRb.start_service queue = DRbObject.new(nil, there) entry = queue.pop puts entry.greeting ================================================ FILE: sample/drb/dqueue.rb ================================================ =begin distributed Ruby --- Queue Copyright (c) 1999-2000 Masatoshi SEKI =end require 'thread' require 'drb/drb' DRb.start_service(nil, Queue.new) puts DRb.uri DRb.thread.join ================================================ FILE: sample/drb/drbc.rb ================================================ =begin distributed Ruby --- dRuby Sample Client Copyright (c) 1999-2000 Masatoshi SEKI =end require 'drb/drb' class DRbEx2 include DRbUndumped def initialize(n) @n = n end def to_i @n.to_i end end if __FILE__ == $0 there = ARGV.shift unless there $stderr.puts("usage: #{$0} ") exit 1 end DRb.start_service() ro = DRbObject.new_with_uri(there) puts ro p ro.to_a puts ro.hello p ro.hello puts ro.sample(DRbEx2.new(1), 2, 3) puts ro.sample(1, ro.sample(DRbEx2.new(1), 2, 3), DRbEx2.new(3)) begin ro.err rescue DRb::DRbUnknownError p $! p $!.unknown rescue RuntimeError p $! end end ================================================ FILE: sample/drb/drbch.rb ================================================ =begin distributed Ruby --- dRuby Sample Client Copyright (c) 1999-2000 Masatoshi SEKI =end require 'drb/drb' require 'drb/http' class DRbEx2 include DRbUndumped def initialize(n) @n = n end def to_i @n.to_i end end if __FILE__ == $0 there = ARGV.shift unless there $stderr.puts("usage: #{$0} ") exit 1 end DRb::DRbConn.proxy_map['x68k'] = 'http://x68k/~mas/http_cgi.rb' DRb.start_service() ro = DRbObject.new(nil, there) puts ro p ro.to_a puts ro.hello p ro.hello puts ro.sample(DRbEx2.new(1), 2, 3) puts ro.sample(1, ro.sample(DRbEx2.new(1), 2, 3), DRbEx2.new(3)) begin ro.err rescue DRb::DRbUnknownError p $! p $!.unknown rescue RuntimeError p $! end end ================================================ FILE: sample/drb/drbm.rb ================================================ =begin multiple DRbServer Copyright (c) 1999-2002 Masatoshi SEKI =end =begin How to play. Terminal 1 | % ruby drbm.rb | druby://yourhost:7640 druby://yourhost:7641 Terminal 2 | % ruby drbmc.rb druby://yourhost:7640 druby://yourhost:7641 | [#, "FOO"] | [#, "FOO"] =end require 'drb/drb' class Hoge include DRbUndumped def initialize(s) @str = s end def to_s @str end end class Foo def initialize(s='FOO') @hoge = Hoge.new(s) end def hello @hoge end end class Bar < Foo def initialize(foo) @hoge = foo.hello end end if __FILE__ == $0 foo = Foo.new s1 = DRb::DRbServer.new('druby://:7640', foo) s2 = DRb::DRbServer.new('druby://:7641', Bar.new(foo)) puts "#{s1.uri} #{s2.uri}" s1.thread.join s2.thread.join end ================================================ FILE: sample/drb/drbmc.rb ================================================ =begin multiple DRbServer client Copyright (c) 1999-2002 Masatoshi SEKI =end require 'drb/drb' if __FILE__ == $0 s1 = ARGV.shift s2 = ARGV.shift unless s1 && s2 $stderr.puts("usage: #{$0} ") exit 1 end DRb.start_service() r1 = DRbObject.new(nil, s1) r2 = DRbObject.new(nil, s2) p [r1.hello, r1.hello.to_s] p [r2.hello, r2.hello.to_s] end ================================================ FILE: sample/drb/drbs-acl.rb ================================================ =begin distributed Ruby --- dRuby Sample Server Copyright (c) 1999-2000 Masatoshi SEKI =end =begin How to play. Terminal 1 | % ruby drbs.rb | druby://yourhost:7640 Terminal 2 | % ruby drbc.rb druby://yourhost:7640 | "hello" | 6 | 10 =end require 'drb/drb' require 'acl' class DRbEx def initialize @hello = 'hello' end def hello info = Thread.current['DRb'] p info['socket'].peeraddr if info @hello end def sample(a, b, c) a.to_i + b.to_i + c.to_i end end if __FILE__ == $0 acl = ACL.new(%w(deny all allow 192.168.1.* allow localhost)) DRb.install_acl(acl) DRb.start_service(nil, DRbEx.new) puts DRb.uri DRb.thread.join end ================================================ FILE: sample/drb/drbs.rb ================================================ =begin distributed Ruby --- dRuby Sample Server Copyright (c) 1999-2000,2002 Masatoshi SEKI =end =begin How to play. Terminal 1 | % ruby drbs.rb | druby://yourhost:7640 Terminal 2 | % ruby drbc.rb druby://yourhost:7640 | "hello" | .... =end require 'drb/drb' class DRbEx include DRbUndumped def initialize @hello = 'hello' end def hello cntxt = Thread.current['DRb'] if cntxt p cntxt['server'].uri p cntxt['client'].peeraddr end Foo::Unknown.new end def err raise FooError end def sample(a, b, c) a.to_i + b.to_i + c.to_i end end class Foo class Unknown end end class FooError < RuntimeError end if __FILE__ == $0 DRb.start_service(ARGV.shift || 'druby://:7640', DRbEx.new) puts DRb.uri Thread.new do sleep 10 DRb.stop_service end DRb.thread.join end ================================================ FILE: sample/drb/drbssl_c.rb ================================================ #!/usr/bin/env ruby require 'drb' require 'drb/ssl' there = ARGV.shift || "drbssl://localhost:3456" config = Hash.new config[:SSLVerifyMode] = OpenSSL::SSL::VERIFY_PEER config[:SSLVerifyCallback] = lambda{|ok,x509_store| p [ok, x509_store.error_string] true } DRb.start_service(nil,nil,config) h = DRbObject.new(nil, there) while line = gets p h.hello(line.chomp) end ================================================ FILE: sample/drb/drbssl_s.rb ================================================ #!/usr/bin/env ruby require 'drb' require 'drb/ssl' here = ARGV.shift || "drbssl://localhost:3456" class HelloWorld include DRbUndumped def hello(name) "Hello, #{name}." end end config = Hash.new config[:verbose] = true begin data = open("sample.key"){|io| io.read } config[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(data) data = open("sample.crt"){|io| io.read } config[:SSLCertificate] = OpenSSL::X509::Certificate.new(data) rescue $stderr.puts "Switching to use self-signed certificate" config[:SSLCertName] = [ ["C","JP"], ["O","Foo.DRuby.Org"], ["CN", "Sample"] ] end DRb.start_service(here, HelloWorld.new, config) puts DRb.uri DRb.thread.join ================================================ FILE: sample/drb/extserv_test.rb ================================================ =begin dRuby sample Copyright (c) 2000 Masatoshi SEKI = How to play * Terminal 1 % ruby -I. extserv_test.rb server druby://yourhost:12345 * Terminal 2 % ruby -I. extserv_test.rb druby://yourhost:12345 ... =end require 'drb/drb' def ARGV.shift it = super() raise "usage:\nserver: #{$0} server []\nclient: #{$0} [quit] " unless it it end class Foo include DRbUndumped def initialize(str) @str = str end def hello(it) "#{it}: #{self}" end def to_s @str end end cmd = ARGV.shift case cmd when 'itest1', 'itest2' require 'drb/extserv' front = Foo.new(cmd) server = DRb::DRbServer.new(nil, front) es = DRb::ExtServ.new(ARGV.shift, ARGV.shift, server) server.thread.join when 'server' require 'drb/extservm' DRb::ExtServManager.command['itest1'] = "ruby -I. #{$0} itest1" DRb::ExtServManager.command['itest2'] = "ruby -I. #{$0} itest2" s = DRb::ExtServManager.new DRb.start_service(ARGV.shift, s) puts DRb.uri DRb.thread.join else uri = (cmd == 'quit') ? ARGV.shift : cmd DRb.start_service s = DRbObject.new(nil, uri) t1 = s.service('itest1').front puts t1 t2 = s.service('itest2').front puts t2 puts t1.hello(t2) if (cmd == 'quit') s.service('itest1').stop_service s.service('itest2').stop_service end end ================================================ FILE: sample/drb/gw_ct.rb ================================================ require 'drb/drb' class Foo include DRbUndumped def foo(n) n + n end def bar(n) yield(n) + yield(n) end end DRb.start_service(nil) puts DRb.uri ro = DRbObject.new(nil, ARGV.shift) ro[:tcp] = Foo.new gets it = ro[:unix] p [it, it.foo(1)] gets p it.bar('2') {|n| n * 3} gets ================================================ FILE: sample/drb/gw_cu.rb ================================================ require 'drb/drb' require 'drb/unix' class Foo include DRbUndumped def foo(n) n + n end def bar(n) yield(n) + yield(n) end end DRb.start_service('drubyunix:', nil) puts DRb.uri ro = DRbObject.new(nil, ARGV.shift) ro[:unix] = Foo.new gets it = ro[:tcp] p [it, it.foo(1)] gets p it.bar('2') {|n| n * 3} gets ================================================ FILE: sample/drb/gw_s.rb ================================================ require 'drb/drb' require 'drb/unix' require 'drb/gw' DRb.install_id_conv(DRb::GWIdConv.new) gw = DRb::GW.new s1 = DRb::DRbServer.new(ARGV.shift, gw) s2 = DRb::DRbServer.new(ARGV.shift, gw) s1.thread.join s2.thread.join ================================================ FILE: sample/drb/holderc.rb ================================================ require 'drb/drb' begin there = ARGV.shift || raise rescue $stderr.puts("usage: #{$0} ") exit 1 end DRb.start_service() ro = DRbObject.new(nil, there) ary = [] 10.times do ary.push(ro.gen) end sleep 5 if $DEBUG ary.each do |e| p e.sample([1]) end ================================================ FILE: sample/drb/holders.rb ================================================ =begin = How to play. == with timeridconv: % ruby -d holders.rb druby://yourhost:1234 % ruby holderc.rb druby://yourhost:1234 == without timeridconv: % ruby holders.rb druby://yourhost:1234 % ruby holderc.rb druby://yourhost:1234 =end require 'drb/drb' class DRbEx3 include DRbUndumped def initialize(n) @v = n end def sample(list) sum = 0 list.each do |e| sum += e.to_i end @v * sum end end class DRbEx4 include DRbUndumped def initialize @curr = 1 end def gen begin @curr += 1 DRbEx3.new(@curr) ensure GC.start end end end if __FILE__ == $0 if $DEBUG require 'drb/timeridconv' DRb.install_id_conv(DRb::TimerIdConv.new(2)) end DRb.start_service(nil, DRbEx4.new) puts DRb.uri DRb.thread.join end ================================================ FILE: sample/drb/http0.rb ================================================ require 'drb/drb' require 'net/http' require 'uri' module DRb module HTTP0 class StrStream def initialize(str='') @buf = str end attr_reader :buf def read(n) begin return @buf[0,n] ensure @buf[0,n] = '' end end def write(s) @buf.concat s end end def self.uri_option(uri, config) return uri, nil end def self.open(uri, config) unless /^http:/ =~ uri raise(DRbBadScheme, uri) unless uri =~ /^http:/ raise(DRbBadURI, 'can\'t parse uri:' + uri) end ClientSide.new(uri, config) end class ClientSide def initialize(uri, config) @uri = uri @res = nil @config = config @msg = DRbMessage.new(config) @proxy = ENV['HTTP_PROXY'] end def close; end def alive?; false; end def send_request(ref, msg_id, *arg, &b) stream = StrStream.new @msg.send_request(stream, ref, msg_id, *arg, &b) @reply_stream = StrStream.new post(@uri, stream.buf) end def recv_reply @msg.recv_reply(@reply_stream) end def post(url, data) it = URI.parse(url) path = [(it.path=='' ? '/' : it.path), it.query].compact.join('?') http = Net::HTTP.new(it.host, it.port) sio = StrStream.new http.post(path, data, {'Content-Type'=>'application/octetstream;'}) do |str| sio.write(str) if @config[:load_limit] < sio.buf.size raise TypeError, 'too large packet' end end @reply_stream = sio end end end DRbProtocol.add_protocol(HTTP0) end ================================================ FILE: sample/drb/http0serv.rb ================================================ require 'webrick' require 'drb/drb' require 'drb/http0' require 'thread' module DRb module HTTP0 def self.open_server(uri, config) unless /^http:/ =~ uri raise(DRbBadScheme, uri) unless uri =~ /^http:/ raise(DRbBadURI, 'can\'t parse uri:' + uri) end Server.new(uri, config) end class Callback < WEBrick::HTTPServlet::AbstractServlet def initialize(config, drb) @config = config @drb = drb @queue = Queue.new end def do_POST(req, res) @req = req @res = res @drb.push(self) @res.body = @queue.pop @res['content-type'] = 'application/octet-stream;' end def req_body @req.body end def reply(body) @queue.push(body) end def close @queue.push('') end end class Server def initialize(uri, config) @uri = uri @config = config @queue = Queue.new setup_webrick(uri) end attr_reader :uri def close @server.shutdown if @server @server = nil end def push(callback) @queue.push(callback) end def accept client = @queue.pop ServerSide.new(client, @config) end def setup_webrick(uri) logger = WEBrick::Log::new($stderr, WEBrick::Log::FATAL) u = URI.parse(uri) s = WEBrick::HTTPServer.new(:Port => u.port, :AddressFamily => Socket::AF_INET, :BindAddress => u.host, :Logger => logger, :ServerType => Thread) s.mount(u.path, Callback, self) @server = s s.start end end class ServerSide def initialize(callback, config) @callback = callback @config = config @msg = DRbMessage.new(@config) @req_stream = StrStream.new(@callback.req_body) end def close @callback.close if @callback @callback = nil end def alive?; false; end def recv_request begin @msg.recv_request(@req_stream) rescue close raise $! end end def send_reply(succ, result) begin return unless @callback stream = StrStream.new @msg.send_reply(stream, succ, result) @callback.reply(stream.buf) rescue close raise $! end end end end end ================================================ FILE: sample/drb/name.rb ================================================ =begin distributed Ruby --- NamedObject Sample Copyright (c) 2000-2001 Masatoshi SEKI =end =begin How to play. * start server Terminal 1 | % ruby name.rb druby://yourhost:7640 | druby://yourhost:7640 | [return] to exit * start client Terminal 2 | % ruby namec.rb druby://yourhost:7640 | # | # | 1 | 2 | [return] to continue * restart server Terminal 1 type [return] | % ruby name.rb druby://yourhost:7640 | druby://yourhost:7640 | [return] to exit * continue client Terminal 2 type [return] | 1 | 2 =end require 'thread.rb' require 'drb/drb' module DRbNamedObject DRbNAMEDICT = {} attr_reader(:drb_name) def drb_name=(name) @drb_name = name Thread.exclusive do raise(IndexError, name) if DRbNAMEDICT[name] DRbNAMEDICT[name] = self end end end class DRbNamedIdConv < DRb::DRbIdConv def initialize @dict = DRbNamedObject::DRbNAMEDICT end def to_obj(ref) @dict.fetch(ref) do super end end def to_id(obj) if obj.kind_of? DRbNamedObject return obj.drb_name else return super end end end class Seq include DRbUndumped include DRbNamedObject def initialize(v, name) @counter = v @mutex = Mutex.new self.drb_name = name end def next_value @mutex.synchronize do @counter += 1 return @counter end end end class Front def initialize seq = Seq.new(0, 'seq') mutex = Mutex.new mutex.extend(DRbUndumped) mutex.extend(DRbNamedObject) mutex.drb_name = 'mutex' @name = {} @name['seq'] = seq @name['mutex'] = mutex end def [](k) @name[k] end end if __FILE__ == $0 uri = ARGV.shift name_conv = DRbNamedIdConv.new DRb.install_id_conv(name_conv) DRb.start_service(uri, Front.new) puts DRb.uri DRb.thread.join end ================================================ FILE: sample/drb/namec.rb ================================================ =begin distributed Ruby --- NamedObject Sample Client Copyright (c) 2000-2001 Masatoshi SEKI =end require 'drb/drb' begin there = ARGV.shift || raise rescue puts "usage: #{$0} " exit 1 end DRb.start_service() ro = DRbObject.new(nil, there) seq = ro["seq"] mutex = ro["mutex"] p seq p mutex mutex.synchronize do p seq.next_value p seq.next_value end puts '[return] to continue' gets mutex.synchronize do p seq.next_value p seq.next_value end ================================================ FILE: sample/drb/old_tuplespace.rb ================================================ #!/usr/local/bin/ruby # TupleSpace # Copyright (c) 1999-2000 Masatoshi SEKI # You can redistribute it and/or modify it under the same terms as Ruby. require 'thread' class TupleSpace class Template def initialize(list) @list = list @check_idx = [] @list.each_with_index do |x, i| @check_idx.push i if x end @size = @list.size end attr :size alias length size def match(tuple) return nil if tuple.size != self.size @check_idx.each do |i| unless @list[i] === tuple[i] return false end end return true end end def initialize @que = {} @waiting = {} @que.taint # enable tainted comunication @waiting.taint self.taint end def wakeup_waiting(tuple) sz = tuple.length return nil unless @waiting[sz] x = nil i = -1 found = false @waiting[sz] = @waiting[sz].find_all { |x| if x[0].match(tuple) begin x[1].wakeup rescue ThreadError end false else true end } end def put_waiting(template, thread) sz = template.length @waiting[sz] = [] unless @waiting[sz] @waiting[sz].push([Template.new(template), thread]) end private :wakeup_waiting private :put_waiting def get_que(template) sz = template.length return nil unless @que[sz] template = Template.new(template) x = nil i = -1 found = false @que[sz].each_with_index do |x, i| if template.match(x) found = true break end end return nil unless found @que[sz].delete_at(i) return x end def put_que(tuple) sz = tuple.length @que[sz] = [] unless @que[sz] @que[sz].push tuple end private :get_que private :put_que def out(*tuples) tuples.each do |tuple| Thread.critical = true put_que(tuple) wakeup_waiting(tuple) Thread.critical = false end end alias put out alias write out def in(template, non_block=false) begin loop do Thread.critical = true tuple = get_que(template) unless tuple if non_block raise ThreadError, "queue empty" end put_waiting(template, Thread.current) Thread.stop else return tuple end end ensure Thread.critical = false end end alias get in alias take in def rd(template, non_block=false) tuple = self.in(template, non_block) out(tuple) tuple end alias read rd def mv(dest, template, non_block=false) tuple = self.in(template, non_block) begin dest.out(tuple) rescue self.out(tuple) end end alias move mv end if __FILE__ == $0 ts = TupleSpace.new clients = [] servers = [] def server(ts, id) Thread.start { loop do req = ts.in(['req', nil, nil]) ac = req[1] num = req[2] sleep id ts.out([ac, id, num, num * num]) end } end def client(ts, n) Thread.start { ac = Object.new tuples = (1..10).collect { |i| ['req', ac, i * 10 + n] } ts.out(*tuples) ts.out(tuples[0]) puts "out: #{n}" 11.times do |i| ans = ts.in([ac, nil, nil, nil]) puts "client(#{n}) server(#{ans[1]}) #{ans[2]} #{ans[3]}" end } end def watcher(ts) Thread.start { loop do begin sleep 1 p ts.rd(['req', nil, nil], true) rescue ThreadError puts "'req' not found." end end } end (0..3).each do |n| servers.push(server(ts, n)) end (1..6).each do |n| clients.push(client(ts, n)) end (1..3).each do watcher(ts) end clients.each do |t| t.join end end ================================================ FILE: sample/drb/rinda_ts.rb ================================================ require 'drb/drb' require 'rinda/tuplespace' uri = ARGV.shift DRb.start_service(uri, Rinda::TupleSpace.new) puts DRb.uri DRb.thread.join ================================================ FILE: sample/drb/rindac.rb ================================================ require 'drb/drb' require 'rinda/rinda' uri = ARGV.shift || raise("usage: #{$0} ") DRb.start_service ts = Rinda::TupleSpaceProxy.new(DRbObject.new(nil, uri)) (1..10).each do |n| ts.write(['sum', DRb.uri, n]) end (1..10).each do |n| ans = ts.take(['ans', DRb.uri, n, nil]) p [ans[2], ans[3]] end ================================================ FILE: sample/drb/rindas.rb ================================================ require 'drb/drb' require 'rinda/rinda' def do_it(v) puts "do_it(#{v})" v + v end uri = ARGV.shift || raise("usage: #{$0} ") DRb.start_service ts = Rinda::TupleSpaceProxy.new(DRbObject.new(nil, uri)) while true r = ts.take(['sum', nil, nil]) v = do_it(r[2]) ts.write(['ans', r[1], r[2], v]) end ================================================ FILE: sample/drb/ring_echo.rb ================================================ require 'drb/drb' require 'drb/eq' require 'rinda/ring' require 'thread' class RingEcho include DRbUndumped def initialize(name) @name = name end def echo(str) "#{@name}: #{str}" end end DRb.start_service renewer = Rinda::SimpleRenewer.new finder = Rinda::RingFinger.new ts = finder.lookup_ring_any ts.read_all([:name, :RingEcho, nil, nil]).each do |tuple| p tuple[2] puts tuple[2].echo('Hello, World') rescue nil end ts.write([:name, :RingEcho, RingEcho.new(DRb.uri), ''], renewer) DRb.thread.join ================================================ FILE: sample/drb/ring_inspect.rb ================================================ require 'rinda/ring' require 'drb/drb' class Inspector def initialize end def primary Rinda::RingFinger.primary end def list_place Rinda::RingFinger.to_a end def list(idx = -1) if idx < 0 ts = primary else ts = list_place[idx] raise "RingNotFound" unless ts end ts.read_all([:name, nil, nil, nil]) end end def main DRb.start_service r = Inspector.new end ================================================ FILE: sample/drb/ring_place.rb ================================================ require 'drb/drb' require 'rinda/ring' require 'rinda/tuplespace' unless $DEBUG # Run as a daemon... exit!( 0 ) if fork Process.setsid exit!( 0 ) if fork end DRb.start_service(ARGV.shift) ts = Rinda::TupleSpace.new place = Rinda::RingServer.new(ts) if $DEBUG puts DRb.uri DRb.thread.join else STDIN.reopen('/dev/null') STDOUT.reopen('/dev/null', 'w') STDERR.reopen('/dev/null', 'w') DRb.thread.join end ================================================ FILE: sample/drb/simpletuple.rb ================================================ #!/usr/local/bin/ruby # SimpleTupleSpace # Copyright (c) 1999-2000 Masatoshi SEKI # You can redistribute it and/or modify it under the same terms as Ruby. require 'thread' class SimpleTupleSpace def initialize @hash = {} @waiting = {} @hash.taint @waiting.taint self.taint end def out(key, obj) Thread.critical = true @hash[key] ||= [] @waiting[key] ||= [] @hash[key].push obj begin t = @waiting[key].shift @waiting.delete(key) if @waiting[key].length == 0 t.wakeup if t rescue ThreadError retry ensure Thread.critical = false end end def in(key) Thread.critical = true @hash[key] ||= [] @waiting[key] ||= [] begin loop do if @hash[key].length == 0 @waiting[key].push Thread.current Thread.stop else return @hash[key].shift end end ensure @hash.delete(key) if @hash[key].length == 0 Thread.critical = false end end end if __FILE__ == $0 ts = SimpleTupleSpace.new clients = [] servers = [] def server(ts) Thread.start { loop do req = ts.in('req') ac = req[0] num = req[1] ts.out(ac, num * num) end } end def client(ts, n) Thread.start { ac = Object.new ts.out('req', [ac, n]) ans = ts.in(ac) puts "#{n}: #{ans}" } end 3.times do servers.push(server(ts)) end (1..6).each do |n| clients.push(client(ts, n)) end clients.each do |t| t.join end end ================================================ FILE: sample/drb/speedc.rb ================================================ #!/usr/local/bin/ruby uri = ARGV.shift || raise("usage: #{$0} URI") N = (ARGV.shift || 100).to_i case uri when /^tcpromp:/, /^unixromp:/ require 'romp' client = ROMP::Client.new(uri, false) foo = client.resolve("foo") when /^druby:/ require 'drb/drb' DRb.start_service foo = DRbObject.new(nil, uri) end N.times do |n| foo.foo(n) end ================================================ FILE: sample/drb/speeds.rb ================================================ class Foo attr_reader :i def initialize @i = 0 end def foo(i) @i = i i + i end end # server = ROMP::Server.new('tcpromp://localhost:4242', nil, true) uri = ARGV.shift || raise("usage: #{$0} URI") foo = Foo.new case uri when /^tcpromp:/, /^unixromp:/ require 'romp' server = ROMP::Server.new(uri, nil, true) server.bind(foo, "foo") when /^druby:/ require 'drb/drb' DRb.start_service(uri, Foo.new) end DRb.thread.join ================================================ FILE: sample/dualstack-fetch.rb ================================================ # simple webpage fetcher # The code demonstrates how a multi-protocol client should be written. # TCPSocket is using getaddrinfo() internally, so there should be no problem. require "socket" if ARGV.size != 1 STDERR.print "requires URL\n" exit end url = ARGV[0] if url !~ /^http:\/\/([^\/]+)(\/.*)$/ STDERR.print "only http with full hostname is supported\n" exit end # split URL into host, port and path hostport = $1 path = $2 if (hostport =~ /^(.*):([0-9]+)$/) host = $1 port = $2 else host = hostport port = 80 end if host =~ /^\[(.*)\]$/ host = $1 end #STDERR.print "url=<#{ARGV[0]}>\n" #STDERR.print "host=<#{host}>\n" #STDERR.print "port=<#{port}>\n" #STDERR.print "path=<#{path}>\n" STDERR.print "conntecting to #{host} port #{port}\n" c = TCPSocket.new(host, port) dest = Socket.getnameinfo(c.getpeername, Socket::NI_NUMERICHOST|Socket::NI_NUMERICSERV) STDERR.print "conntected to #{dest[0]} port #{dest[1]}\n" c.print "GET #{path} HTTP/1.0\n" c.print "Host: #{host}\n" c.print "\n" while c.gets print end ================================================ FILE: sample/dualstack-httpd.rb ================================================ # simple httpd # The code demonstrates how a multi-protocol daemon should be written. require "socket" require "thread" port = 8888 res = Socket.getaddrinfo(nil, port, nil, Socket::SOCK_STREAM, nil, Socket::AI_PASSIVE) sockpool = [] names = [] threads = [] res.each do |i| s = TCPserver.new(i[3], i[1]) n = Socket.getnameinfo(s.getsockname, Socket::NI_NUMERICHOST|Socket::NI_NUMERICSERV).join(" port ") sockpool.push s names.push n end (0 .. sockpool.size - 1).each do |i| mysock = sockpool[i] myname = names[i] STDERR.print "socket #{mysock} started, address #{myname}\n" threads[i] = Thread.start do # Thread.start cannot be used here! ls = mysock # copy to dynamic variable t = Thread.current STDERR.print "socket #{myname} listener started, pid #{$$} thread #{t}\n" while true as = ls.accept Thread.start do STDERR.print "socket #{myname} accepted, thread ", Thread.current, "\n" s = as # copy to dynamic variable str = '' while line = s.gets break if line == "\r\n" or line == "\n" str << line end STDERR.print "socket #{myname} got string\n" s.write("HTTP/1.0 200 OK\n") s.write("Content-type: text/plain\n\n") s.write("this is test: my name is #{myname}, you sent:\n") s.write("---start\n") s.write(str) s.write("---end\n") s.close STDERR.print "socket #{myname} processed, thread ", Thread.current, " terminating\n" end end end end for t in threads t.join end ================================================ FILE: sample/erb/erb4html.rb ================================================ require 'erb' class ERB class ERBString < String def to_s; self; end def erb_concat(s) if self.class === s concat(s) else concat(erb_quote(s)) end end def erb_quote(s); s; end end end class ERB4Html < ERB def self.quoted(s) HtmlString.new(s) end class HtmlString < ERB::ERBString def erb_quote(s) ERB::Util::html_escape(s) end end def set_eoutvar(compiler, eoutvar = '_erbout') compiler.put_cmd = "#{eoutvar}.concat" compiler.insert_cmd = "#{eoutvar}.erb_concat" cmd = [] cmd.push "#{eoutvar} = ERB4Html.quoted('')" compiler.pre_cmd = cmd cmd = [] cmd.push(eoutvar) compiler.post_cmd = cmd end end if __FILE__ == $0 page = <<%=title%>

      <%=para%>

      EOP erb = ERB4Html.new(page) title = "" para = "<quoted>" puts erb.result title = "" para = ERB4Html.quoted("<quoted>") puts erb.result end ================================================ FILE: sample/eval.rb ================================================ line = '' indent = 0 $stdout.sync = true print "ruby> " loop do l = gets if l.nil? break if line.empty? else line += l if l =~ /,\s*$/ print "ruby| " next end if l =~ /^\s*(class|module|def|if|unless|case|while|until|for|begin)\b[^_]/ indent += 1 end if l =~ /^\s*end\b[^_]/ indent -= 1 end if l =~ /\{\s*(\|.*\|)?\s*$/ indent += 1 end if l =~ /^\s*\}/ indent -= 1 end if indent > 0 print "ruby| " next end end begin print eval(line).inspect, "\n" rescue ScriptError, StandardError printf "ERR: %s\n", $! || 'exception raised' end break if l.nil? line = '' print "ruby> " end print "\n" ================================================ FILE: sample/export.rb ================================================ # method access permission # output: # foobar # Foo class Foo public :printf def baz print "baz\n" end private :baz def quux print "in QUUX " baz() end end def foobar print "foobar\n" end f = Foo.new #Foo.private :printf class Foo # redefines foobar's scope public :foobar end f.foobar f.printf "%s\n", Foo f.quux class Bar 0 && y > 0 then open(x-1,y-1) end if y > 0 then open(x, y-1) end if x < @wi-1 && y > 0 then open(x+1,y-1) end if x > 0 then open(x-1,y) end if x < @wi-1 then open(x+1,y) end if x > 0 && y < @hi-1 then open(x-1,y+1) end if y < @hi -1 then open(x,y+1) end if x < @wi-1 && y < @hi-1 then open(x+1,y+1) end pos(@cx,@cy) end def fetch(x,y) # (x,y)ΰ֤Ƥο(0 or 1)֤ if x < 0 then 0 elsif x >= @wi then 0 elsif y < 0 then 0 elsif y >= @hi then 0 else @data[y*@wi+x] end end def count(x,y) # (x,y)ܤƤο֤ fetch(x-1,y-1)+fetch(x,y-1)+fetch(x+1,y-1)+ fetch(x-1,y) + fetch(x+1,y)+ fetch(x-1,y+1)+fetch(x,y+1)+fetch(x+1,y+1) end def over(win) # νλ quit unless win pos(@cx,@cy); print CHR[11] end pos(0,@hi) if win then print "*** YOU WIN !! ***" else print "*** GAME OVER ***" end end def over? # νλå # λƤӽФ remain = (@mc+@total == 0) if @over || remain over(remain) true else false end end def quit # (ޤϽλ) # ̤Ƹ @hi.times do|y| pos(0,y) @wi.times do|x| colorstr(if @state[y*@wi+x] == "MARK" then COL[1] else COL[2] end, if fetch(x,y)==1 then CHR[10] else CHR[count(x,y)] end) end end end def down # 򲼤 if @cy < @hi-1 then @cy=@cy+1; pos(@cx, @cy) end end def up # if @cy > 0 then @cy=@cy-1; pos(@cx, @cy) end end def left # 򺸤 if @cx > 0 then @cx=@cx-1; pos(@cx, @cy) end end def right # 򱦤 if @cx < @wi-1 then @cx=@cx+1; pos(@cx, @cy) end end end bd=Board.new(10,10,10) system("stty raw -echo") begin loop do case STDIN.getc when ?n # new game bd.reset when ?m # mark bd.mark when ?j bd.down when ?k bd.up when ?h bd.left when ?l bd.right when ?\s bd.open when ?q,?\C-c # quit game bd.quit break end if bd.over? if STDIN.getc == ?q then break end bd.reset end end ensure system("stty -raw echo") end print "\n" ================================================ FILE: sample/mkproto.rb ================================================ $/ = nil while line = gets() if /^((void|VALUE|int|char *\*|ID|struct [\w_]+ *\*|st_table *\*) *)?\n([\w\d_]+)\(.*\)\n\s*((.+;\n)*)\{/ =~ line line = $' printf "%s %s(", $2, $3 args = [] for arg in $4.split(/;\n\s*/) arg.gsub!(/ +/, ' ') if arg =~ /,/ if arg =~ /(([^*]+) *\** *[\w\d_]+),/ type = $2.strip args.push $1.strip arg = $' else type = "" end while arg.sub!(/(\** *[\w\d_]+)(,|$)/, "") && $~ args.push type + " " + $1.strip end else args.push arg.strip end end printf "%s);\n", args.join(', ') redo end end ================================================ FILE: sample/mpart.rb ================================================ #! ./ruby # split into multi part # usage: mpart.rb [-nnn] file.. lines = 1000 if (ARGV[0] =~ /^-(\d+)$/ ) lines = $1.to_i; ARGV.shift; end basename = ARGV[0] extname = "part" part = 1 line = 0 fline = 0 for i in ifp = open(basename) fline = fline + 1 end ifp.close parts = fline / lines + 1 for i in ifp = open(basename) if line == 0 ofp = open(sprintf("%s.%s%02d", basename, extname, part), "w") printf(ofp, "%s part%02d/%02d\n", basename, part, parts) ofp.write("BEGIN--cut here--cut here\n") end ofp.write(i) line = line + 1 if line >= lines and !ifp.eof? ofp.write("END--cut here--cut here\n") ofp.close part = part + 1 line = 0 end end ofp.write("END--cut here--cut here\n") ofp.close ifp.close ================================================ FILE: sample/mrshtest.rb ================================================ include Marshal a = 25.6; pt = Struct.new('Point', :x,:y); x = pt.new(10, 10) y = pt.new(20, 20) rt = Struct.new('Rectangle', :origin,:corner); z = rt.new(x, y) c = Object.new s = [a, x, z, c, c, "fff"]; p s d = dump(s); p d p load(d) ================================================ FILE: sample/observ.rb ================================================ #! /usr/local/bin/ruby require "thread" require "observer" class Tick include Observable def initialize Thread.start do loop do sleep 0.999 now = Time.now changed notify_observers(now.hour, now.min, now.sec) end end end end class Clock def initialize(tick) @tick = tick @tick.add_observer(self) end def update(h, m, s) printf "\e[8D%02d:%02d:%02d", h, m, s STDOUT.flush end end clock = Clock.new(Tick.new) sleep ================================================ FILE: sample/occur.pl ================================================ while (<>) { for (split(/\W+/)) { $freq{$_}++; } } for (sort keys %freq) { print "$_ -- $freq{$_}\n"; } ================================================ FILE: sample/occur.rb ================================================ # word occurrence listing # usege: ruby occur.rb file.. freq = Hash.new(0) while gets() for word in split(/\W+/) freq[word] += 1 end end for word in freq.keys.sort! print word, " -- ", freq[word], "\n" end ================================================ FILE: sample/occur2.rb ================================================ # word occurrence listing # usege: ruby occur2.rb file.. freq = {} while gets() for word in split(/\W+/) begin freq[word] += 1 rescue NameError freq[word] = 1 end end end for word in freq.keys.sort printf("%s -- %d\n", word, freq[word]) end ================================================ FILE: sample/openssl/c_rehash.rb ================================================ #!/usr/bin/env ruby require 'openssl' require 'digest/md5' class CHashDir include Enumerable def initialize(dirpath) @dirpath = dirpath @fingerprint_cache = @cert_cache = @crl_cache = nil end def hash_dir(silent = false) # ToDo: Should lock the directory... @silent = silent @fingerprint_cache = Hash.new @cert_cache = Hash.new @crl_cache = Hash.new do_hash_dir end def get_certs(name = nil) if name @cert_cache[hash_name(name)] else @cert_cache.values.flatten end end def get_crls(name = nil) if name @crl_cache[hash_name(name)] else @crl_cache.values.flatten end end def delete_crl(crl) File.unlink(crl_filename(crl)) hash_dir(true) end def add_crl(crl) File.open(crl_filename(crl), "w") do |f| f << crl.to_pem end hash_dir(true) end def load_pem_file(filepath) str = File.read(filepath) begin OpenSSL::X509::Certificate.new(str) rescue begin OpenSSL::X509::CRL.new(str) rescue begin OpenSSL::X509::Request.new(str) rescue nil end end end end private def crl_filename(crl) path(hash_name(crl.issuer)) + '.pem' end def do_hash_dir Dir.chdir(@dirpath) do delete_symlink Dir.glob('*.pem') do |pemfile| cert = load_pem_file(pemfile) case cert when OpenSSL::X509::Certificate link_hash_cert(pemfile, cert) when OpenSSL::X509::CRL link_hash_crl(pemfile, cert) else STDERR.puts("WARNING: #{pemfile} does not contain a certificate or CRL: skipping") unless @silent end end end end def delete_symlink Dir.entries(".").each do |entry| next unless /^[\da-f]+\.r{0,1}\d+$/ =~ entry File.unlink(entry) if FileTest.symlink?(entry) end end def link_hash_cert(org_filename, cert) name_hash = hash_name(cert.subject) fingerprint = fingerprint(cert.to_der) filepath = link_hash(org_filename, name_hash, fingerprint) { |idx| "#{name_hash}.#{idx}" } unless filepath unless @silent STDERR.puts("WARNING: Skipping duplicate certificate #{org_filename}") end else (@cert_cache[name_hash] ||= []) << path(filepath) end end def link_hash_crl(org_filename, crl) name_hash = hash_name(crl.issuer) fingerprint = fingerprint(crl.to_der) filepath = link_hash(org_filename, name_hash, fingerprint) { |idx| "#{name_hash}.r#{idx}" } unless filepath unless @silent STDERR.puts("WARNING: Skipping duplicate CRL #{org_filename}") end else (@crl_cache[name_hash] ||= []) << path(filepath) end end def link_hash(org_filename, name, fingerprint) idx = 0 filepath = nil while true filepath = yield(idx) break unless FileTest.symlink?(filepath) or FileTest.exist?(filepath) if @fingerprint_cache[filepath] == fingerprint return false end idx += 1 end STDOUT.puts("#{org_filename} => #{filepath}") unless @silent symlink(org_filename, filepath) @fingerprint_cache[filepath] = fingerprint filepath end def symlink(from, to) begin File.symlink(from, to) rescue File.open(to, "w") do |f| f << File.read(from) end end end def path(filename) File.join(@dirpath, filename) end def hash_name(name) sprintf("%x", name.hash) end def fingerprint(der) Digest::MD5.hexdigest(der).upcase end end if $0 == __FILE__ dirlist = ARGV dirlist << '/usr/ssl/certs' if dirlist.empty? dirlist.each do |dir| CHashDir.new(dir).hash_dir end end ================================================ FILE: sample/openssl/cert2text.rb ================================================ #!/usr/bin/env ruby require 'openssl' include OpenSSL::X509 def cert2text(cert_str) [Certificate, CRL, Request].each do |klass| begin puts klass.new(cert_str).to_text return rescue end end raise ArgumentError.new('Unknown format.') end if ARGV.empty? cert2text(STDIN.read) else ARGV.each do |file| cert2text(File.read(file)) end end ================================================ FILE: sample/openssl/cert_store_view.rb ================================================ #!/usr/bin/env ruby require 'fox' require 'openssl' require 'time' require 'certstore' require 'getopts' include Fox module CertDumpSupport def cert_label(cert) subject_alt_name = cert.extensions.find { |ext| ext.oid == 'subjectAltName' } if subject_alt_name subject_alt_name.value.split(/\s*,\s/).each do |alt_name_pair| alt_tag, alt_name = alt_name_pair.split(/:/) return alt_name end end name_label(cert.subject) end def name_label(name) ary = name.to_a if (cn = ary.find { |rdn| rdn[0] == 'CN' }) return cn[1] end if ary.last[0] == 'OU' return ary.last[1] end name.to_s end def name_text(name) name.to_a.collect { |tag, value| "#{tag} = #{value}" }.reverse.join("\n") end def bn_label(bn) ("0" << sprintf("%X", bn)).scan(/../).join(" ") end end class CertDump include CertDumpSupport def initialize(cert) @cert = cert end def get_dump(tag) case tag when 'Version' version when 'Serial' serial when 'Signature Algorithm' signature_algorithm when 'Issuer' issuer when 'Validity' validity when 'Not before' not_before when 'Not after' not_after when 'Subject' subject when 'Public key' public_key else ext(tag) end end def get_dump_line(tag) case tag when 'Version' version_line when 'Serial' serial_line when 'Signature Algorithm' signature_algorithm_line when 'Subject' subject_line when 'Issuer' issuer_line when 'Validity' validity_line when 'Not before' not_before_line when 'Not after' not_after_line when 'Public key' public_key_line else ext_line(tag) end end private def version "Version: #{@cert.version + 1}" end def version_line version end def serial bn_label(@cert.serial) end def serial_line serial end def signature_algorithm @cert.signature_algorithm end def signature_algorithm_line signature_algorithm end def subject name_text(@cert.subject) end def subject_line @cert.subject.to_s end def issuer name_text(@cert.issuer) end def issuer_line @cert.issuer.to_s end def validity < 0 @tree.removeItem(node.getFirst) end end end class CertInfo def initialize(observer, table) @observer = observer @table = table @table.leadingRows = 0 @table.leadingCols = 0 @table.trailingRows = 0 @table.trailingCols = 0 @table.showVertGrid(false) @table.showHorzGrid(false) @table.setTableSize(1, 2) @table.setColumnWidth(0, 125) @table.setColumnWidth(1, 350) end def show(item) @observer.show_detail(nil, nil) if item.nil? set_column_size(1) return end case item when OpenSSL::X509::Certificate show_cert(item) when OpenSSL::X509::CRL show_crl(item) when OpenSSL::X509::Revoked show_revoked(item) when OpenSSL::X509::Request show_request(item) else raise NotImplementedError.new("Unknown item type #{item.class}.") end end private def show_cert(cert) wrap = CertDump.new(cert) items = [] items << ['Version', wrap.get_dump_line('Version')] items << ['Signature Algorithm', wrap.get_dump_line('Signature Algorithm')] items << ['Issuer', wrap.get_dump_line('Issuer')] items << ['Serial', wrap.get_dump_line('Serial')] #items << ['Not before', wrap.get_dump_line('Not before')] #items << ['Not after', wrap.get_dump_line('Not after')] items << ['Subject', wrap.get_dump_line('Subject')] items << ['Public key', wrap.get_dump_line('Public key')] items << ['Validity', wrap.get_dump_line('Validity')] (cert.extensions.sort { |a, b| a.oid <=> b.oid }).each do |ext| items << [ext.oid, wrap.get_dump_line(ext.oid)] end show_items(cert, items) end def show_crl(crl) wrap = CrlDump.new(crl) items = [] items << ['Version', wrap.get_dump_line('Version')] items << ['Signature Algorithm', wrap.get_dump_line('Signature Algorithm')] items << ['Issuer', wrap.get_dump_line('Issuer')] items << ['Last update', wrap.get_dump_line('Last update')] items << ['Next update', wrap.get_dump_line('Next update')] crl.extensions.each do |ext| items << [ext.oid, wrap.get_dump_line(ext.oid)] end show_items(crl, items) end def show_revoked(revoked) wrap = RevokedDump.new(revoked) items = [] items << ['Serial', wrap.get_dump_line('Serial')] items << ['Time', wrap.get_dump_line('Time')] revoked.extensions.each do |ext| items << [ext.oid, wrap.get_dump_line(ext.oid)] end show_items(revoked, items) end def show_request(req) wrap = RequestDump.new(req) items = [] items << ['Version', wrap.get_dump_line('Version')] items << ['Signature Algorithm', wrap.get_dump_line('Signature Algorithm')] items << ['Subject', wrap.get_dump_line('Subject')] items << ['Public key', wrap.get_dump_line('Public key')] req.attributes.each do |attr| items << [attr.attr, wrap.get_dump_line(attr.oid)] end show_items(req, items) end def show_items(obj, items) set_column_size(items.size) items.each_with_index do |ele, idx| tag, value = ele @table.setItemText(idx, 0, tag) @table.getItem(idx, 0).data = tag @table.setItemText(idx, 1, value.to_s) @table.getItem(idx, 1).data = tag end @table.connect(SEL_COMMAND) do |sender, sel, loc| item = @table.getItem(loc.row, loc.col) @observer.show_detail(obj, item.data) end justify_table end def set_column_size(size) col0_width = @table.getColumnWidth(0) col1_width = @table.getColumnWidth(1) @table.setTableSize(size, 2) @table.setColumnWidth(0, col0_width) @table.setColumnWidth(1, col1_width) end def justify_table for col in 0..@table.numCols-1 for row in 0..@table.numRows-1 @table.getItem(row, col).justify = FXTableItem::LEFT end end end end class CertDetail def initialize(observer, detail) @observer = observer @detail = detail end def show(item, tag) if item.nil? @detail.text = '' return end case item when OpenSSL::X509::Certificate show_cert(item, tag) when OpenSSL::X509::CRL show_crl(item, tag) when OpenSSL::X509::Revoked show_revoked(item, tag) when OpenSSL::X509::Request show_request(item, tag) else raise NotImplementedError.new("Unknown item type #{item.class}.") end end private def show_cert(cert, tag) wrap = CertDump.new(cert) @detail.text = wrap.get_dump(tag) end def show_crl(crl, tag) wrap = CrlDump.new(crl) @detail.text = wrap.get_dump(tag) end def show_revoked(revoked, tag) wrap = RevokedDump.new(revoked) @detail.text = wrap.get_dump(tag) end def show_request(request, tag) wrap = RequestDump.new(request) @detail.text = wrap.get_dump(tag) end end attr_reader :cert_store def initialize(app, cert_store) @cert_store = cert_store @verify_filter = 0 @verify_filename = nil full_width = 800 full_height = 500 horz_pos = 300 super(app, "Certificate store", nil, nil, DECOR_ALL, 0, 0, full_width, full_height) FXTooltip.new(self.getApp()) menubar = FXMenubar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X) file_menu = FXMenuPane.new(self) FXMenuTitle.new(menubar, "&File", nil, file_menu) file_open_menu = FXMenuPane.new(self) FXMenuCommand.new(file_open_menu, "&Directory\tCtl-O").connect(SEL_COMMAND, method(:on_cmd_file_open_dir)) FXMenuCascade.new(file_menu, "&Open\tCtl-O", nil, file_open_menu) FXMenuCommand.new(file_menu, "&Quit\tCtl-Q", nil, getApp(), FXApp::ID_QUIT) tool_menu = FXMenuPane.new(self) FXMenuTitle.new(menubar, "&Tool", nil, tool_menu) FXMenuCommand.new(tool_menu, "&Verify\tCtl-N").connect(SEL_COMMAND, method(:on_cmd_tool_verify)) FXMenuCommand.new(tool_menu, "&Show Request\tCtl-R").connect(SEL_COMMAND, method(:on_cmd_tool_request)) base_frame = FXHorizontalFrame.new(self, LAYOUT_FILL_X | LAYOUT_FILL_Y) splitter_horz = FXSplitter.new(base_frame, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y | SPLITTER_TRACKING | SPLITTER_HORIZONTAL) # Cert tree cert_tree_frame = FXHorizontalFrame.new(splitter_horz, LAYOUT_FILL_X | LAYOUT_FILL_Y | FRAME_SUNKEN | FRAME_THICK) cert_tree_frame.setWidth(horz_pos) cert_tree = FXTreeList.new(cert_tree_frame, 0, nil, 0, TREELIST_BROWSESELECT | TREELIST_SHOWS_LINES | TREELIST_SHOWS_BOXES | TREELIST_ROOT_BOXES | LAYOUT_FILL_X | LAYOUT_FILL_Y) @cert_tree = CertTree.new(self, cert_tree) # Cert info splitter_vert = FXSplitter.new(splitter_horz, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y | SPLITTER_TRACKING | SPLITTER_VERTICAL | SPLITTER_REVERSED) cert_list_base = FXVerticalFrame.new(splitter_vert, LAYOUT_FILL_X | LAYOUT_FILL_Y, 0,0,0,0, 0,0,0,0) cert_list_frame = FXHorizontalFrame.new(cert_list_base, FRAME_SUNKEN | FRAME_THICK | LAYOUT_FILL_X | LAYOUT_FILL_Y) cert_info = FXTable.new(cert_list_frame, 2, 10, nil, 0, FRAME_SUNKEN | TABLE_COL_SIZABLE | LAYOUT_FILL_X | LAYOUT_FILL_Y, 0, 0, 0, 0, 2, 2, 2, 2) @cert_info = CertInfo.new(self, cert_info) cert_detail_base = FXVerticalFrame.new(splitter_vert, LAYOUT_FILL_X | LAYOUT_FILL_Y, 0,0,0,0, 0,0,0,0) cert_detail_frame = FXHorizontalFrame.new(cert_detail_base, FRAME_SUNKEN | FRAME_THICK | LAYOUT_FILL_X | LAYOUT_FILL_Y) cert_detail = FXText.new(cert_detail_frame, nil, 0, TEXT_READONLY | LAYOUT_FILL_X | LAYOUT_FILL_Y) @cert_detail = CertDetail.new(self, cert_detail) show_init end def create super show(PLACEMENT_SCREEN) end def show_init @cert_tree.show(@cert_store) show_item(nil) end def show_certs @cert_tree.show_certs(@cert_store) end def show_request(req) @cert_tree.show_request(req) end def show_verify_path(verify_path) @cert_tree.show_verify_path(verify_path) end def show_item(item) @cert_info.show(item) if @cert_info end def show_detail(item, tag) @cert_detail.show(item, tag) if @cert_detail end def verify(certfile) path = verify_certfile(certfile) show_certs # CRL could be change. show_verify_path(path) end private def on_cmd_file_open_dir(sender, sel, ptr) dir = FXFileDialog.getOpenDirectory(self, "Open certificate directory", ".") unless dir.empty? begin @cert_store = CertStore.new(dir) rescue show_error($!) end show_init end 1 end def on_cmd_tool_verify(sender, sel, ptr) dialog = FXFileDialog.new(self, "Verify certificate") dialog.filename = '' dialog.patternList = ["All Files (*)", "PEM formatted certificate (*.pem)"] dialog.currentPattern = @verify_filter if dialog.execute != 0 @verify_filename = dialog.filename verify(@verify_filename) end @verify_filter = dialog.currentPattern 1 end def on_cmd_tool_request(sender, sel, ptr) dialog = FXFileDialog.new(self, "Show request") dialog.filename = '' dialog.patternList = ["All Files (*)", "PEM formatted certificate (*.pem)"] if dialog.execute != 0 req = @cert_store.generate_cert(dialog.filename) show_request(req) end 1 end def verify_certfile(filename) begin cert = @cert_store.generate_cert(filename) result = @cert_store.verify(cert) @cert_store.scan_certs result rescue show_error($!) [] end end def show_error(e) msg = e.inspect + "\n" + e.backtrace.join("\n") FXMessageBox.error(self, MBOX_OK, "Error", msg) end end getopts nil, "cert:" certs_dir = ARGV.shift or raise "#{$0} cert_dir" certfile = $OPT_cert app = FXApp.new("CertStore", "FoxTest") cert_store = CertStore.new(certs_dir) w = CertStoreView.new(app, cert_store) app.create if certfile w.verify(certfile) end app.run ================================================ FILE: sample/openssl/certstore.rb ================================================ require 'c_rehash' require 'crlstore' class CertStore include OpenSSL include X509 attr_reader :self_signed_ca attr_reader :other_ca attr_reader :ee attr_reader :crl attr_reader :request def initialize(certs_dir) @certs_dir = certs_dir @c_store = CHashDir.new(@certs_dir) @c_store.hash_dir(true) @crl_store = CrlStore.new(@c_store) @x509store = Store.new @self_signed_ca = @other_ca = @ee = @crl = nil # Uncomment this line to let OpenSSL to check CRL for each certs. # @x509store.flags = V_FLAG_CRL_CHECK | V_FLAG_CRL_CHECK_ALL add_path scan_certs end def generate_cert(filename) @c_store.load_pem_file(filename) end def verify(cert) error, crl_map = do_verify(cert) if error [[false, cert, crl_map[cert.subject], error]] else @x509store.chain.collect { |c| [true, c, crl_map[c.subject], nil] } end end def match_cert(cert1, cert2) (cert1.issuer.cmp(cert2.issuer) == 0) and cert1.serial == cert2.serial end def is_ca?(cert) case guess_cert_type(cert) when CERT_TYPE_SELF_SIGNED true when CERT_TYPE_OTHER true else false end end def scan_certs @self_signed_ca = [] @other_ca = [] @ee = [] @crl = [] @request = [] load_certs end private def add_path @x509store.add_path(@certs_dir) end def do_verify(cert) error_map = {} crl_map = {} result = @x509store.verify(cert) do |ok, ctx| cert = ctx.current_cert if ctx.current_crl crl_map[cert.subject] = true end if ok if !ctx.current_crl if crl = @crl_store.find_crl(cert) crl_map[cert.subject] = true if crl.revoked.find { |revoked| revoked.serial == cert.serial } ok = false error_string = 'certification revoked' end end end end error_map[cert.subject] = error_string if error_string ok end error = if result nil else error_map[cert.subject] || @x509store.error_string end return error, crl_map end def load_certs @c_store.get_certs.each do |certfile| cert = generate_cert(certfile) case guess_cert_type(cert) when CERT_TYPE_SELF_SIGNED @self_signed_ca << cert when CERT_TYPE_OTHER @other_ca << cert when CERT_TYPE_EE @ee << cert else raise "Unknown cert type." end end @c_store.get_crls.each do |crlfile| @crl << generate_cert(crlfile) end end CERT_TYPE_SELF_SIGNED = 0 CERT_TYPE_OTHER = 1 CERT_TYPE_EE = 2 def guess_cert_type(cert) ca = self_signed = is_cert_self_signed(cert) cert.extensions.each do |ext| # Ignores criticality of extensions. It's 'guess'ing. case ext.oid when 'basicConstraints' /CA:(TRUE|FALSE), pathlen:(\d+)/ =~ ext.value ca = ($1 == 'TRUE') unless ca when 'keyUsage' usage = ext.value.split(/\s*,\s*/) ca = usage.include?('Certificate Sign') unless ca when 'nsCertType' usage = ext.value.split(/\s*,\s*/) ca = usage.include?('SSL CA') unless ca end end if ca if self_signed CERT_TYPE_SELF_SIGNED else CERT_TYPE_OTHER end else CERT_TYPE_EE end end def is_cert_self_signed(cert) # cert.subject.cmp(cert.issuer) == 0 cert.subject.to_s == cert.issuer.to_s end end if $0 == __FILE__ c = CertStore.new("trust_certs") end ================================================ FILE: sample/openssl/cipher.rb ================================================ #!/usr/bin/env ruby require 'openssl' text = "abcdefghijklmnopqrstuvwxyz" pass = "secret password" salt = "8 octets" # or nil alg = "DES-EDE3-CBC" #alg = "AES-128-CBC" puts "--Setup--" puts %(clear text: "#{text}") puts %(password: "#{pass}") puts %(salt: "#{salt}") puts %(cipher alg: "#{alg}") puts puts "--Encrypting--" des = OpenSSL::Cipher::Cipher.new(alg) des.pkcs5_keyivgen(pass, salt) des.encrypt cipher = des.update(text) cipher << des.final puts %(encrypted text: #{cipher.inspect}) puts puts "--Decrypting--" des = OpenSSL::Cipher::Cipher.new(alg) des.pkcs5_keyivgen(pass, salt) des.decrypt out = des.update(cipher) out << des.final puts %(decrypted text: "#{out}") puts ================================================ FILE: sample/openssl/crlstore.rb ================================================ begin require 'http-access2' rescue LoadError STDERR.puts("Cannot load http-access2. CRL might not be fetched.") end require 'c_rehash' class CrlStore def initialize(c_store) @c_store = c_store @c_store.hash_dir(true) end def find_crl(cert) do_find_crl(cert) end private def do_find_crl(cert) unless ca = find_ca(cert) return nil end unless crlfiles = @c_store.get_crls(ca.subject) if crl = renew_crl(cert, ca) @c_store.add_crl(crl) return crl end return nil end crlfiles.each do |crlfile| next unless crl = load_crl(crlfile) if crl.next_update < Time.now if new_crl = renew_crl(cert, ca) @c_store.delete_crl(crl) @c_store.add_crl(new_crl) crl = new_crl end end if check_valid(crl, ca) return crl end end nil end def find_ca(cert) @c_store.get_certs(cert.issuer).each do |cafile| ca = load_cert(cafile) if cert.verify(ca.public_key) return ca end end nil end def fetch(location) if /\AURI:(.*)\z/ =~ location begin c = HTTPAccess2::Client.new(ENV['http_proxy'] || ENV['HTTP_PROXY']) c.get_content($1) rescue NameError, StandardError nil end else nil end end def load_cert(certfile) load_cert_str(File.read(certfile)) end def load_crl(crlfile) load_crl_str(File.read(crlfile)) end def load_cert_str(cert_str) OpenSSL::X509::Certificate.new(cert_str) end def load_crl_str(crl_str) OpenSSL::X509::CRL.new(crl_str) end def check_valid(crl, ca) unless crl.verify(ca.public_key) return false end crl.last_update <= Time.now end RE_CDP = /\AcrlDistributionPoints\z/ def get_cdp(cert) if cdp_ext = cert.extensions.find { |ext| RE_CDP =~ ext.oid } cdp_ext.value.chomp else false end end def renew_crl(cert, ca) if cdp = get_cdp(cert) if new_crl_str = fetch(cdp) new_crl = load_crl_str(new_crl_str) if check_valid(new_crl, ca) return new_crl end end end false end end if $0 == __FILE__ dir = "trust_certs" c_store = CHashDir.new(dir) s = CrlStore.new(c_store) c = OpenSSL::X509::Certificate.new(File.read("cert_store/google_codesign.pem")) p s.find_crl(c) end ================================================ FILE: sample/openssl/echo_cli.rb ================================================ #!/usr/bin/env ruby require 'socket' require 'openssl' require 'getopts' getopts nil, "p:2000", "c:", "k:", "C:" host = ARGV[0] || "localhost" port = $OPT_p cert_file = $OPT_c key_file = $OPT_k ca_path = $OPT_C ctx = OpenSSL::SSL::SSLContext.new() if cert_file && key_file ctx.cert = OpenSSL::X509::Certificate.new(File::read(cert_file)) ctx.key = OpenSSL::PKey::RSA.new(File::read(key_file)) end if ca_path ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER ctx.ca_path = ca_path else $stderr.puts "!!! WARNING: PEER CERTIFICATE WON'T BE VERIFIED !!!" end s = TCPSocket.new(host, port) ssl = OpenSSL::SSL::SSLSocket.new(s, ctx) ssl.connect # start SSL session ssl.sync_close = true # if true the underlying socket will be # closed in SSLSocket#close. (default: false) while line = $stdin.gets ssl.write line print ssl.gets end ssl.close ================================================ FILE: sample/openssl/echo_svr.rb ================================================ #!/usr/bin/env ruby require 'socket' require 'openssl' require 'getopts' getopts nil, "p:2000", "c:", "k:", "C:" port = $OPT_p cert_file = $OPT_c key_file = $OPT_k ca_path = $OPT_C if cert_file && key_file cert = OpenSSL::X509::Certificate.new(File::read(cert_file)) key = OpenSSL::PKey::RSA.new(File::read(key_file)) else key = OpenSSL::PKey::RSA.new(512){ print "." } puts cert = OpenSSL::X509::Certificate.new cert.version = 2 cert.serial = 0 name = OpenSSL::X509::Name.new([["C","JP"],["O","TEST"],["CN","localhost"]]) cert.subject = name cert.issuer = name cert.not_before = Time.now cert.not_after = Time.now + 3600 cert.public_key = key.public_key ef = OpenSSL::X509::ExtensionFactory.new(nil,cert) cert.extensions = [ ef.create_extension("basicConstraints","CA:FALSE"), ef.create_extension("subjectKeyIdentifier","hash"), ef.create_extension("extendedKeyUsage","serverAuth"), ef.create_extension("keyUsage", "keyEncipherment,dataEncipherment,digitalSignature") ] ef.issuer_certificate = cert cert.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") cert.sign(key, OpenSSL::Digest::SHA1.new) end ctx = OpenSSL::SSL::SSLContext.new() ctx.key = key ctx.cert = cert if ca_path ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT ctx.ca_path = ca_path else $stderr.puts "!!! WARNING: PEER CERTIFICATE WON'T BE VERIFIED !!!" end tcps = TCPServer.new(port) ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) loop do ns = ssls.accept while line = ns.gets ns.write line end ns.close end ================================================ FILE: sample/openssl/gen_csr.rb ================================================ #!/usr/bin/env ruby require 'getopts' require 'openssl' include OpenSSL def usage myname = File::basename($0) $stderr.puts < "iso-2022-jp", "sjis" => "shift_jis"} POSSIBLE_CODES = "(#{(CODES+CODE_ALIASES.keys).join(',')})" ARGV.options do |opts| opts.banner << " argv..." # separater opts.on_tail opts.on_tail("common options:") # no argument, shows at tail opts.on_tail("--help", "show this message") {puts opts; exit} # mandatory argument opts.on("-r", "--require=LIBRARY", String, "require the LIBRARY, before", "executing your script") {|@library|} # optional argument opts.on("-i", "--inplace=[EXTENSION]", "edit ARGV files in place", # multiline description "(make backup if EXTENSION supplied)") {|@inplace| @inplace ||= ''} opts.on("-N=[NUM]", Integer) {|@number|} # additional class opts.on("-t", "--[no-]time[=TIME]", Time, "it's the time") {|@time|} # limit argument syntax opts.on("-[0-7]", "-F", "--irs=[OCTAL]", OptionParser::OctalInteger, "specify record separator", "(\\0, if no argument)") {|@irs|} # boolean switch(default true) @exec = true opts.on("-n", "--no-exec[=FLAG]", TrueClass, "not really execute") {|@exec|} # array opts.on("-a", "--list[=LIST,LIST]", Array, "list") {|@list|} # fixed size array opts.on("--pair[=car,cdr]", Array, "pair") {|@x, @y|} # keyword completion opts.on("--code=CODE", CODES, CODE_ALIASES, "select coding system", "("+CODES.join(",")+",", " "+CODE_ALIASES.keys.join(",")+")") {|@code|} # optional argument with keyword completion opts.on("--type[=TYPE]", [:text, :binary], "select type(text, binary)") {|@type|} # boolean switch with optional argument(default false) opts.on("-v", "--[no-]verbose=[FLAG]", "run verbosely") {|@verbose|} # easy way, set local variable opts.on("-q", "--quit", "quit when ARGV is empty") {|@quit|} # adding on the fly opts.on("--add=SWITCH=[ARG]", "add option on the fly", /\A(\w+)(?:=.+)?\Z/) do |opt, var| opts.on("--#{opt}", "added in runtime", &eval("proc {|@#{var}|}")) end opts.on_head("specific options:") # no argument opts.on_tail("--version", "show version") do puts OptionParser::Version.join('.') exit end opts.parse! end pp self (print ARGV.options; exit) if @quit ARGV.options = nil # no more parse puts "ARGV = #{ARGV.join(' ')}" if !ARGV.empty? #opts.variable.each {|sym| puts "#{sym} = #{opts.send(sym).inspect}"} ================================================ FILE: sample/optparse/subcommand.rb ================================================ #! /usr/bin/ruby # contributed by Minero Aoki. require 'optparse' parser = OptionParser.new parser.on('-i') { puts "-i" } parser.on('-o') { puts '-o' } subparsers = Hash.new {|h,k| $stderr.puts "no such subcommand: #{k}" exit 1 } subparsers['add'] = OptionParser.new.on('-i') { puts "add -i" } subparsers['del'] = OptionParser.new.on('-i') { puts "del -i" } subparsers['list'] = OptionParser.new.on('-i') { puts "list -i" } parser.order!(ARGV) subparsers[ARGV.shift].parse!(ARGV) unless ARGV.empty? ================================================ FILE: sample/philos.rb ================================================ # # The Dining Philosophers - thread example # require "thread" srand #srand N=9 # number of philosophers $forks = [] for i in 0..N-1 $forks[i] = Mutex.new end $state = "-o"*N def wait sleep rand(20)/10.0 end def think(n) wait end def eat(n) wait end def philosopher(n) while true think n $forks[n].lock if not $forks[(n+1)%N].try_lock $forks[n].unlock # avoid deadlock next end $state[n*2] = ?|; $state[(n+1)%N*2] = ?|; $state[n*2+1] = ?*; print $state, "\n" eat(n) $state[n*2] = ?-; $state[(n+1)%N*2] = ?-; $state[n*2+1] = ?o; print $state, "\n" $forks[n].unlock $forks[(n+1)%N].unlock end end for n in 0..N-1 Thread.start(n){|i| philosopher(i)} sleep 0.1 end sleep ================================================ FILE: sample/pi.rb ================================================ #!/usr/local/bin/ruby k, a, b, a1, b1 = 2, 4, 1, 12, 4 loop do # Next approximation p, q, k = k*k, 2*k+1, k+1 a, b, a1, b1 = a1, b1, p*a+q*a1, p*b+q*b1 # Print common digits d = a / b d1 = a1 / b1 while d == d1 print d $stdout.flush a, a1 = 10*(a%b), 10*(a1%b1) d, d1 = a/b, a1/b1 end end ================================================ FILE: sample/rcs.awk ================================================ BEGIN { sw = 40.0; dw = 78.0; hdw = dw / 2.0; w = 20.0; h =1.0; d = 0.2; ss="abcdefghijklmnopqrstuvwxyz0123456789!#$%^&*()-=\\[];'`,./"; rnd = srand(); } { xr = -hdw; y = h * 1.0; maxxl = -999; s = ""; while (xr < hdw) { x = xr * (1 + y) - y * w / 2; i = (x / (1 + h) + sw /2); c = (0 < i && i < length($0)) ? substr($0, i, 1) : "0"; y = h - d * c; xl = xr - w * y / (1 + y); if (xl < -hdw || xl >= hdw || xl <= maxxl) { t = rand() * length(ss); c = substr(ss, t, 1); } else { c = substr(s, xl + hdw, 1); maxxl = xl; } s = s c; xr = xr + 1; } print s; } ================================================ FILE: sample/rcs.rb ================================================ # random dot steraogram # usage: rcs.rb rcs.dat sw = 40.0 # width of original pattern dw = 78.0 # width of generating Random Character Streogram hdw = dw / 2.0 w = 20.0 # distance between eyes h =1.0 # distance from screen and base plane d = 0.2 # z value unit ss="abcdefghijklmnopqrstuvwxyz0123456789#!$%^&*()-=\\[];'`,./" rnd = srand() # You don't actually need this in ruby - srand() is called # on the first call of rand(). while gets() # print($_) xr = -hdw; y = h * 1.0; maxxl = -999 s = "" while xr < hdw x = xr * (1 + y) - y * w / 2 i = (x / (1 + h) + sw / 2) if (1 < i && i < $_.length) c = $_[i, 1].to_i else c = 0 end y = h - d * c xl = xr - w * y / (1 + y) if xl < -hdw || xl >= hdw || xl <= maxxl tt = rand(ss.length) c = ss[tt, 1] else c = s[xl + hdw, 1] maxxl = xl end s += c xr += 1 end print(s, "\n") end ================================================ FILE: sample/regx.rb ================================================ st = "\033[7m" en = "\033[m" #st = "<<" #en = ">>" while true print "str> " STDOUT.flush input = gets break if not input if input != "" str = input str.chop! end print "pat> " STDOUT.flush re = gets break if not re re.chop! str.gsub! re, "#{st}\\&#{en}" print str, "\n" end print "\n" ================================================ FILE: sample/rss/blend.rb ================================================ #!/usr/bin/env ruby require "rss" feeds = [] verbose = false encoding = "UTF-8" def error(exception) mark = "=" * 20 mark = "#{mark} error #{mark}" STDERR.puts mark STDERR.puts exception.class STDERR.puts exception.message STDERR.puts exception.backtrace STDERR.puts mark end before_time = Time.now ARGV.each do |fname| if fname == '-v' verbose = true next end rss = nil f = File.new(fname).read begin ## do validate parse rss = RSS::Parser.parse(f) rescue RSS::InvalidRSSError error($!) if verbose ## do non validate parse for invalid RSS 1.0 begin rss = RSS::Parser.parse(f, false) rescue RSS::Error ## invalid RSS. error($!) if verbose end rescue RSS::Error error($!) if verbose end if rss.nil? STDERR.puts "#{fname} does not include RSS 1.0 or 0.9x/2.0" else begin rss.output_encoding = encoding rescue RSS::UnknownConversionMethodError error($!) if verbose end feeds << rss end end processing_time = Time.now - before_time rss = RSS::Maker.make("1.0") do |maker| maker.encoding = encoding maker.channel.about = "http://example.com/blend.rdf" maker.channel.title = "blended feeds" maker.channel.link = "http://example.com/" maker.channel.description = "blended feeds generated by RSS Parser" feeds.each do |feed| feed.items.each do |item| item.setup_maker(maker.items) end end maker.items.each do |item| item.title ||= "UNKNOWN" item.link ||= "UNKNOWN" end maker.items.do_sort = true maker.items.max_size = 15 end puts rss STDERR.puts "Used XML parser: #{RSS::Parser.default_parser}" STDERR.puts "Processing time: #{processing_time}s" ================================================ FILE: sample/rss/convert.rb ================================================ #!/usr/bin/env ruby require "rss" feeds = [] verbose = false encoding = "UTF-8" to_version = "1.0" def error(exception) mark = "=" * 20 mark = "#{mark} error #{mark}" STDERR.puts mark STDERR.puts exception.class STDERR.puts exception.message STDERR.puts exception.backtrace STDERR.puts mark end before_time = Time.now ARGV.each do |fname| case fname when '-v' verbose = true next when /^-t(0\.91|1\.0|2\.0|atom)$/ to_version = $1 next end rss = nil f = File.read(fname) begin ## do validate parse rss = RSS::Parser.parse(f) rescue RSS::InvalidRSSError error($!) if verbose ## do non validate parse for invalid RSS 1.0 begin rss = RSS::Parser.parse(f, false) rescue RSS::Error ## invalid RSS. error($!) if verbose end rescue RSS::Error error($!) if verbose end if rss.nil? STDERR.puts "#{fname} does not include RSS 1.0 or 0.9x/2.0" else begin rss.output_encoding = encoding rescue RSS::UnknownConversionMethodError error($!) if verbose end feeds << [fname, rss] end end processing_time = Time.now - before_time feeds.each do |fname, rss| converted_rss = rss.to_xml(to_version) output_name = fname.sub(/(\.[^\.]+)$/, "-#{to_version}\\1") File.open(output_name, "w") do |output| output.print(converted_rss) end end STDERR.puts "Used XML parser: #{RSS::Parser.default_parser}" STDERR.puts "Processing time: #{processing_time}s" ================================================ FILE: sample/rss/list_description.rb ================================================ #!/usr/bin/env ruby require "nkf" class String # From tdiary.rb def shorten( len = 120 ) lines = NKF::nkf( "-e -m0 -f#{len}", self.gsub( /\n/, ' ' ) ).split( /\n/ ) lines[0].concat( '...' ) if lines[0] and lines[1] lines[0] end end require "rss" channels = {} verbose = false def error(exception) mark = "=" * 20 mark = "#{mark} error #{mark}" puts mark puts exception.class puts exception.message puts exception.backtrace puts mark end before_time = Time.now ARGV.each do |fname| if fname == '-v' verbose = true next end rss = nil f = File.new(fname).read begin ## do validate parse rss = RSS::Parser.parse(f) rescue RSS::InvalidRSSError error($!) if verbose ## do non validate parse for invalid RSS 1.0 begin rss = RSS::Parser.parse(f, false) rescue RSS::Error ## invalid RSS. error($!) if verbose end rescue RSS::Error error($!) if verbose end if rss.nil? puts "#{fname} does not include RSS 1.0 or 0.9x/2.0" else begin rss.output_encoding = "euc-jp" rescue RSS::UnknownConversionMethodError error($!) if verbose end rss = rss.to_rss("1.0") do |maker| maker.channel.about ||= maker.channel.link maker.channel.description ||= "No description" maker.items.each do |item| item.title ||= "No title" item.link ||= "UNKNOWN" end end next if rss.nil? rss.items.each do |item| channels[rss.channel.title] ||= [] channels[rss.channel.title] << item if item.description end end end processing_time = Time.now - before_time channels.sort do |x, y| x[0] <=> y[0] end[0..20].each do |title, items| puts "Channel: #{title}" unless items.empty? items.sort do |x, y| x.title <=> y.title end[0..10].each do |item| puts " Item: #{item.title.shorten(50)}" puts " Description: #{item.description.shorten(50)}" end end puts "Used XML parser: #{RSS::Parser.default_parser}" puts "Processing time: #{processing_time}s" ================================================ FILE: sample/rss/re_read.rb ================================================ #!/usr/bin/env ruby require "rss" def error(exception) mark = "=" * 20 mark = "#{mark} error #{mark}" puts mark puts exception.class puts exception.message puts exception.backtrace puts mark end verbose = false before_time = Time.now ARGV.each do |fname| if fname == '-v' verbose = true next end source = nil File.open(fname) do |f| source = f.read end rss = nil read = false begin rss = RSS::Parser.parse(source) puts "Re-read valid feed: #{fname}" RSS::Parser.parse(rss.to_s) read = true rescue RSS::InvalidRSSError error($!) if verbose ## do non validate parse for invalid feed begin rss = RSS::Parser.parse(source, false) rescue RSS::Error ## invalid feed error($!) if verbose end rescue RSS::Error error($!) if verbose end if rss.nil? puts "Invalid feed: #{fname}" elsif !read puts "Re-read invalid feed: #{fname}" begin RSS::Parser.parse(rss.to_s) rescue RSS::Error puts " Error occurred: #{fname}" error($!) if verbose end end end processing_time = Time.now - before_time puts "Used XML parser: #{RSS::Parser.default_parser}" puts "Processing time: #{processing_time}s" ================================================ FILE: sample/rss/rss_recent.rb ================================================ #!/usr/bin/env ruby require "nkf" class String # From tdiary.rb def shorten( len = 120 ) lines = NKF::nkf( "-e -m0 -f#{len}", self.gsub( /\n/, ' ' ) ).split( /\n/ ) lines[0].concat( '...' ) if lines[0] and lines[1] lines[0] end end require "rss" items = [] verbose = false def error(exception) mark = "=" * 20 mark = "#{mark} error #{mark}" puts mark puts exception.class puts exception.message puts exception.backtrace puts mark end before_time = Time.now ARGV.each do |fname| if fname == '-v' verbose = true next end rss = nil f = File.new(fname).read begin ## do validate parse rss = RSS::Parser.parse(f) rescue RSS::InvalidRSSError error($!) if verbose ## do non validate parse for invalid RSS 1.0 begin rss = RSS::Parser.parse(f, false) rescue RSS::Error ## invalid RSS. error($!) if verbose end rescue RSS::Error error($!) if verbose end if rss.nil? puts "#{fname} does not include RSS 1.0 or 0.9x/2.0" else begin rss.output_encoding = "euc-jp" rescue RSS::UnknownConversionMethodError error($!) if verbose end rss = rss.to_rss("1.0") do |maker| maker.channel.about ||= maker.channel.link maker.channel.description ||= "No description" maker.items.each do |item| item.title ||= "UNKNOWN" item.link ||= "UNKNOWN" end end next if rss.nil? rss.items.each do |item| items << [rss.channel, item] if item.dc_date end end end processing_time = Time.now - before_time items.sort do |x, y| y[1].dc_date <=> x[1].dc_date end[0..20].each do |channel, item| puts "#{item.dc_date.localtime.iso8601}: " << "#{channel.title}: #{item.title}" puts " Description: #{item.description.shorten(50)}" if item.description end puts "Used XML parser: #{RSS::Parser.default_parser}" puts "Processing time: #{processing_time}s" ================================================ FILE: sample/sieve.rb ================================================ # sieve of Eratosthenes max = Integer(ARGV.shift || 100) sieve = [] for i in 2 .. max sieve[i] = i end for i in 2 .. Math.sqrt(max) next unless sieve[i] (i*i).step(max, i) do |j| sieve[j] = nil end end puts sieve.compact.join(", ") ================================================ FILE: sample/svr.rb ================================================ # socket example - server side # usage: ruby svr.rb # this server might be blocked by an ill-behaved client. # see tsvr.rb which is safe from client blocking. require "socket" gs = TCPserver.open(0) addr = gs.addr addr.shift printf("server is on %s\n", addr.join(":")) socks = [gs] loop do nsock = select(socks); next if nsock == nil for s in nsock[0] if s == gs ns = s.accept socks.push(ns) print(s, " is accepted\n") else if s.eof? print(s, " is gone\n") s.close socks.delete(s) # single thread gets may block whole service elsif str = s.gets s.write(str) end end end end ================================================ FILE: sample/test.rb ================================================ #! /usr/bin/env ruby $KCODE = "none" $testnum=0 $ntest=0 $failed = 0 def test_check(what) printf "%s\n", what $what = what $testnum = 0 end def test_ok(cond,n=1) $testnum+=1 $ntest+=1 if cond printf "ok %d\n", $testnum else where = caller(n)[0] printf "not ok %s %d -- %s\n", $what, $testnum, where $failed+=1 end end # make sure conditional operators work test_check "assignment" a=[]; a[0] ||= "bar"; test_ok(a[0] == "bar") h={}; h["foo"] ||= "bar"; test_ok(h["foo"] == "bar") aa = 5 aa ||= 25 test_ok(aa == 5) bb ||= 25 test_ok(bb == 25) cc &&=33 test_ok(cc == nil) cc = 5 cc &&=44 test_ok(cc == 44) a = nil; test_ok(a == nil) a = 1; test_ok(a == 1) a = []; test_ok(a == []) a = [1]; test_ok(a == [1]) a = [nil]; test_ok(a == [nil]) a = [[]]; test_ok(a == [[]]) a = [1,2]; test_ok(a == [1,2]) a = [*[]]; test_ok(a == []) a = [*[1]]; test_ok(a == [1]) a = [*[1,2]]; test_ok(a == [1,2]) a = *nil; test_ok(a == nil) a = *1; test_ok(a == 1) a = *[]; test_ok(a == nil) a = *[1]; test_ok(a == 1) a = *[nil]; test_ok(a == nil) a = *[[]]; test_ok(a == []) a = *[1,2]; test_ok(a == [1,2]) a = *[*[]]; test_ok(a == nil) a = *[*[1]]; test_ok(a == 1) a = *[*[1,2]]; test_ok(a == [1,2]) a, = nil; test_ok(a == nil) a, = 1; test_ok(a == 1) a, = []; test_ok(a == nil) a, = [1]; test_ok(a == 1) a, = [nil]; test_ok(a == nil) a, = [[]]; test_ok(a == []) a, = 1,2; test_ok(a == 1) a, = [1,2]; test_ok(a == 1) a, = [*[]]; test_ok(a == nil) a, = [*[1]]; test_ok(a == 1) a, = *[1,2]; test_ok(a == 1) a, = [*[1,2]]; test_ok(a == 1) a, = *nil; test_ok(a == nil) a, = *1; test_ok(a == 1) a, = *[]; test_ok(a == nil) a, = *[1]; test_ok(a == 1) a, = *[nil]; test_ok(a == nil) a, = *[[]]; test_ok(a == []) a, = *[1,2]; test_ok(a == 1) a, = *[*[]]; test_ok(a == nil) a, = *[*[1]]; test_ok(a == 1) a, = *[*[1,2]]; test_ok(a == 1) *a = nil; test_ok(a == [nil]) *a = 1; test_ok(a == [1]) *a = []; test_ok(a == [[]]) *a = [1]; test_ok(a == [[1]]) *a = [nil]; test_ok(a == [[nil]]) *a = [[]]; test_ok(a == [[[]]]) *a = [1,2]; test_ok(a == [[1,2]]) *a = [*[]]; test_ok(a == [[]]) *a = [*[1]]; test_ok(a == [[1]]) *a = [*[1,2]]; test_ok(a == [[1,2]]) *a = *nil; test_ok(a == [nil]) *a = *1; test_ok(a == [1]) *a = *[]; test_ok(a == []) *a = *[1]; test_ok(a == [1]) *a = *[nil]; test_ok(a == [nil]) *a = *[[]]; test_ok(a == [[]]) *a = *[1,2]; test_ok(a == [1,2]) *a = *[*[]]; test_ok(a == []) *a = *[*[1]]; test_ok(a == [1]) *a = *[*[1,2]]; test_ok(a == [1,2]) a,b,*c = nil; test_ok([a,b,c] == [nil,nil,[]]) a,b,*c = 1; test_ok([a,b,c] == [1,nil,[]]) a,b,*c = []; test_ok([a,b,c] == [nil,nil,[]]) a,b,*c = [1]; test_ok([a,b,c] == [1,nil,[]]) a,b,*c = [nil]; test_ok([a,b,c] == [nil,nil,[]]) a,b,*c = [[]]; test_ok([a,b,c] == [[],nil,[]]) a,b,*c = [1,2]; test_ok([a,b,c] == [1,2,[]]) a,b,*c = [*[]]; test_ok([a,b,c] == [nil,nil,[]]) a,b,*c = [*[1]]; test_ok([a,b,c] == [1,nil,[]]) a,b,*c = [*[1,2]]; test_ok([a,b,c] == [1,2,[]]) a,b,*c = *nil; test_ok([a,b,c] == [nil,nil,[]]) a,b,*c = *1; test_ok([a,b,c] == [1,nil,[]]) a,b,*c = *[]; test_ok([a,b,c] == [nil,nil,[]]) a,b,*c = *[1]; test_ok([a,b,c] == [1,nil,[]]) a,b,*c = *[nil]; test_ok([a,b,c] == [nil,nil,[]]) a,b,*c = *[[]]; test_ok([a,b,c] == [[],nil,[]]) a,b,*c = *[1,2]; test_ok([a,b,c] == [1,2,[]]) a,b,*c = *[*[]]; test_ok([a,b,c] == [nil,nil,[]]) a,b,*c = *[*[1]]; test_ok([a,b,c] == [1,nil,[]]) a,b,*c = *[*[1,2]]; test_ok([a,b,c] == [1,2,[]]) def f; yield nil; end; f {|a| test_ok(a == nil)} def f; yield 1; end; f {|a| test_ok(a == 1)} def f; yield []; end; f {|a| test_ok(a == [])} def f; yield [1]; end; f {|a| test_ok(a == [1])} def f; yield [nil]; end; f {|a| test_ok(a == [nil])} def f; yield [[]]; end; f {|a| test_ok(a == [[]])} def f; yield [*[]]; end; f {|a| test_ok(a == [])} def f; yield [*[1]]; end; f {|a| test_ok(a == [1])} def f; yield [*[1,2]]; end; f {|a| test_ok(a == [1,2])} def f; yield *nil; end; f {|a| test_ok(a == nil)} def f; yield *1; end; f {|a| test_ok(a == 1)} def f; yield *[1]; end; f {|a| test_ok(a == 1)} def f; yield *[nil]; end; f {|a| test_ok(a == nil)} def f; yield *[[]]; end; f {|a| test_ok(a == [])} def f; yield *[*[1]]; end; f {|a| test_ok(a == 1)} def f; yield; end; f {|a,| test_ok(a == nil)} def f; yield nil; end; f {|a,| test_ok(a == nil)} def f; yield 1; end; f {|a,| test_ok(a == 1)} def f; yield []; end; f {|a,| test_ok(a == nil)} def f; yield [1]; end; f {|a,| test_ok(a == 1)} def f; yield [nil]; end; f {|a,| test_ok(a == nil)} def f; yield [[]]; end; f {|a,| test_ok(a == [])} def f; yield [*[]]; end; f {|a,| test_ok(a == nil)} def f; yield [*[1]]; end; f {|a,| test_ok(a == 1)} def f; yield [*[1,2]]; end; f {|a,| test_ok(a == 1)} def f; yield *nil; end; f {|a,| test_ok(a == nil)} def f; yield *1; end; f {|a,| test_ok(a == 1)} def f; yield *[]; end; f {|a,| test_ok(a == nil)} def f; yield *[1]; end; f {|a,| test_ok(a == 1)} def f; yield *[nil]; end; f {|a,| test_ok(a == nil)} def f; yield *[[]]; end; f {|a,| test_ok(a == [])} def f; yield *[*[]]; end; f {|a,| test_ok(a == nil)} def f; yield *[*[1]]; end; f {|a,| test_ok(a == 1)} def f; yield *[*[1,2]]; end; f {|a,| test_ok(a == 1)} def f; yield; end; f {|*a| test_ok(a == [])} def f; yield nil; end; f {|*a| test_ok(a == [nil])} def f; yield 1; end; f {|*a| test_ok(a == [1])} def f; yield []; end; f {|*a| test_ok(a == [[]])} def f; yield [1]; end; f {|*a| test_ok(a == [[1]])} def f; yield [nil]; end; f {|*a| test_ok(a == [[nil]])} def f; yield [[]]; end; f {|*a| test_ok(a == [[[]]])} def f; yield [1,2]; end; f {|*a| test_ok(a == [[1,2]])} def f; yield [*[]]; end; f {|*a| test_ok(a == [[]])} def f; yield [*[1]]; end; f {|*a| test_ok(a == [[1]])} def f; yield [*[1,2]]; end; f {|*a| test_ok(a == [[1,2]])} def f; yield *nil; end; f {|*a| test_ok(a == [nil])} def f; yield *1; end; f {|*a| test_ok(a == [1])} def f; yield *[]; end; f {|*a| test_ok(a == [])} def f; yield *[1]; end; f {|*a| test_ok(a == [1])} def f; yield *[nil]; end; f {|*a| test_ok(a == [nil])} def f; yield *[[]]; end; f {|*a| test_ok(a == [[]])} def f; yield *[*[]]; end; f {|*a| test_ok(a == [])} def f; yield *[*[1]]; end; f {|*a| test_ok(a == [1])} def f; yield *[*[1,2]]; end; f {|*a| test_ok(a == [1,2])} def f; yield; end; f {|a,b,*c| test_ok([a,b,c] == [nil,nil,[]])} def f; yield nil; end; f {|a,b,*c| test_ok([a,b,c] == [nil,nil,[]])} def f; yield 1; end; f {|a,b,*c| test_ok([a,b,c] == [1,nil,[]])} def f; yield []; end; f {|a,b,*c| test_ok([a,b,c] == [nil,nil,[]])} def f; yield [1]; end; f {|a,b,*c| test_ok([a,b,c] == [1,nil,[]])} def f; yield [nil]; end; f {|a,b,*c| test_ok([a,b,c] == [nil,nil,[]])} def f; yield [[]]; end; f {|a,b,*c| test_ok([a,b,c] == [[],nil,[]])} def f; yield [*[]]; end; f {|a,b,*c| test_ok([a,b,c] == [nil,nil,[]])} def f; yield [*[1]]; end; f {|a,b,*c| test_ok([a,b,c] == [1,nil,[]])} def f; yield [*[1,2]]; end; f {|a,b,*c| test_ok([a,b,c] == [1,2,[]])} def f; yield *nil; end; f {|a,b,*c| test_ok([a,b,c] == [nil,nil,[]])} def f; yield *1; end; f {|a,b,*c| test_ok([a,b,c] == [1,nil,[]])} def f; yield *[]; end; f {|a,b,*c| test_ok([a,b,c] == [nil,nil,[]])} def f; yield *[1]; end; f {|a,b,*c| test_ok([a,b,c] == [1,nil,[]])} def f; yield *[nil]; end; f {|a,b,*c| test_ok([a,b,c] == [nil,nil,[]])} def f; yield *[[]]; end; f {|a,b,*c| test_ok([a,b,c] == [[],nil,[]])} def f; yield *[*[]]; end; f {|a,b,*c| test_ok([a,b,c] == [nil,nil,[]])} def f; yield *[*[1]]; end; f {|a,b,*c| test_ok([a,b,c] == [1,nil,[]])} def f; yield *[*[1,2]]; end; f {|a,b,*c| test_ok([a,b,c] == [1,2,[]])} def r; return; end; a = r(); test_ok(a == nil) def r; return nil; end; a = r(); test_ok(a == nil) def r; return 1; end; a = r(); test_ok(a == 1) def r; return []; end; a = r(); test_ok(a == []) def r; return [1]; end; a = r(); test_ok(a == [1]) def r; return [nil]; end; a = r(); test_ok(a == [nil]) def r; return [[]]; end; a = r(); test_ok(a == [[]]) def r; return [*[]]; end; a = r(); test_ok(a == []) def r; return [*[1]]; end; a = r(); test_ok(a == [1]) def r; return [*[1,2]]; end; a = r(); test_ok(a == [1,2]) def r; return *nil; end; a = r(); test_ok(a == nil) def r; return *1; end; a = r(); test_ok(a == 1) def r; return *[]; end; a = r(); test_ok(a == nil) def r; return *[1]; end; a = r(); test_ok(a == 1) def r; return *[nil]; end; a = r(); test_ok(a == nil) def r; return *[[]]; end; a = r(); test_ok(a == []) def r; return *[*[]]; end; a = r(); test_ok(a == nil) def r; return *[*[1]]; end; a = r(); test_ok(a == 1) def r; return *[*[1,2]]; end; a = r(); test_ok(a == [1,2]) def r; return *nil; end; a = *r(); test_ok(a == nil) def r; return *1; end; a = *r(); test_ok(a == 1) def r; return *[]; end; a = *r(); test_ok(a == nil) def r; return *[1]; end; a = *r(); test_ok(a == 1) def r; return *[nil]; end; a = *r(); test_ok(a == nil) def r; return *[[]]; end; a = *r(); test_ok(a == nil) def r; return *[*[]]; end; a = *r(); test_ok(a == nil) def r; return *[*[1]]; end; a = *r(); test_ok(a == 1) def r; return *[*[1,2]]; end; a = *r(); test_ok(a == [1,2]) def r; return; end; *a = r(); test_ok(a == [nil]) def r; return nil; end; *a = r(); test_ok(a == [nil]) def r; return 1; end; *a = r(); test_ok(a == [1]) def r; return []; end; *a = r(); test_ok(a == [[]]) def r; return [1]; end; *a = r(); test_ok(a == [[1]]) def r; return [nil]; end; *a = r(); test_ok(a == [[nil]]) def r; return [[]]; end; *a = r(); test_ok(a == [[[]]]) def r; return [1,2]; end; *a = r(); test_ok(a == [[1,2]]) def r; return [*[]]; end; *a = r(); test_ok(a == [[]]) def r; return [*[1]]; end; *a = r(); test_ok(a == [[1]]) def r; return [*[1,2]]; end; *a = r(); test_ok(a == [[1,2]]) def r; return *nil; end; *a = r(); test_ok(a == [nil]) def r; return *1; end; *a = r(); test_ok(a == [1]) def r; return *[]; end; *a = r(); test_ok(a == [nil]) def r; return *[1]; end; *a = r(); test_ok(a == [1]) def r; return *[nil]; end; *a = r(); test_ok(a == [nil]) def r; return *[[]]; end; *a = r(); test_ok(a == [[]]) def r; return *[1,2]; end; *a = r(); test_ok(a == [[1,2]]) def r; return *[*[]]; end; *a = r(); test_ok(a == [nil]) def r; return *[*[1]]; end; *a = r(); test_ok(a == [1]) def r; return *[*[1,2]]; end; *a = r(); test_ok(a == [[1,2]]) def r; return *nil; end; *a = *r(); test_ok(a == [nil]) def r; return *1; end; *a = *r(); test_ok(a == [1]) def r; return *[]; end; *a = *r(); test_ok(a == [nil]) def r; return *[1]; end; *a = *r(); test_ok(a == [1]) def r; return *[nil]; end; *a = *r(); test_ok(a == [nil]) def r; return *[[]]; end; *a = *r(); test_ok(a == []) def r; return *[1,2]; end; *a = *r(); test_ok(a == [1,2]) def r; return *[*[]]; end; *a = *r(); test_ok(a == [nil]) def r; return *[*[1]]; end; *a = *r(); test_ok(a == [1]) def r; return *[*[1,2]]; end; *a = *r(); test_ok(a == [1,2]) def r; return; end; a,b,*c = r(); test_ok([a,b,c] == [nil,nil,[]]) def r; return nil; end; a,b,*c = r(); test_ok([a,b,c] == [nil,nil,[]]) def r; return 1; end; a,b,*c = r(); test_ok([a,b,c] == [1,nil,[]]) def r; return []; end; a,b,*c = r(); test_ok([a,b,c] == [nil,nil,[]]) def r; return [1]; end; a,b,*c = r(); test_ok([a,b,c] == [1,nil,[]]) def r; return [nil]; end; a,b,*c = r(); test_ok([a,b,c] == [nil,nil,[]]) def r; return [[]]; end; a,b,*c = r(); test_ok([a,b,c] == [[],nil,[]]) def r; return [1,2]; end; a,b,*c = r(); test_ok([a,b,c] == [1,2,[]]) def r; return [*[]]; end; a,b,*c = r(); test_ok([a,b,c] == [nil,nil,[]]) def r; return [*[1]]; end; a,b,*c = r(); test_ok([a,b,c] == [1,nil,[]]) def r; return [*[1,2]]; end; a,b,*c = r(); test_ok([a,b,c] == [1,2,[]]) def r; return *nil; end; a,b,*c = r(); test_ok([a,b,c] == [nil,nil,[]]) def r; return *1; end; a,b,*c = r(); test_ok([a,b,c] == [1,nil,[]]) def r; return *[]; end; a,b,*c = r(); test_ok([a,b,c] == [nil,nil,[]]) def r; return *[1]; end; a,b,*c = r(); test_ok([a,b,c] == [1,nil,[]]) def r; return *[nil]; end; a,b,*c = r(); test_ok([a,b,c] == [nil,nil,[]]) def r; return *[[]]; end; a,b,*c = r(); test_ok([a,b,c] == [nil,nil,[]]) def r; return *[1,2]; end; a,b,*c = r(); test_ok([a,b,c] == [1,2,[]]) def r; return *[*[]]; end; a,b,*c = r(); test_ok([a,b,c] == [nil,nil,[]]) def r; return *[*[1]]; end; a,b,*c = r(); test_ok([a,b,c] == [1,nil,[]]) def r; return *[*[1,2]]; end; a,b,*c = r(); test_ok([a,b,c] == [1,2,[]]) f = lambda {|r,| test_ok([] == r)} f.call([], *[]) f = lambda {|r,*l| test_ok([] == r); test_ok([1] == l)} f.call([], *[1]) f = lambda{|x| x} test_ok(f.call(42) == 42) test_ok(f.call([42]) == [42]) test_ok(f.call([[42]]) == [[42]]) test_ok(f.call([42,55]) == [42,55]) f = lambda{|x,| x} test_ok(f.call(42) == 42) test_ok(f.call([42]) == [42]) test_ok(f.call([[42]]) == [[42]]) test_ok(f.call([42,55]) == [42,55]) f = lambda{|*x| x} test_ok(f.call(42) == [42]) test_ok(f.call([42]) == [[42]]) test_ok(f.call([[42]]) == [[[42]]]) test_ok(f.call([42,55]) == [[42,55]]) test_ok(f.call(42,55) == [42,55]) a,=*[1] test_ok(a == 1) a,=*[[1]] test_ok(a == [1]) a,=*[[[1]]] test_ok(a == [[1]]) x, (y, z) = 1, 2, 3 test_ok([1,2,nil] == [x,y,z]) x, (y, z) = 1, [2,3] test_ok([1,2,3] == [x,y,z]) x, (y, z) = 1, [2] test_ok([1,2,nil] == [x,y,z]) a = loop do break; end; test_ok(a == nil) a = loop do break nil; end; test_ok(a == nil) a = loop do break 1; end; test_ok(a == 1) a = loop do break []; end; test_ok(a == []) a = loop do break [1]; end; test_ok(a == [1]) a = loop do break [nil]; end; test_ok(a == [nil]) a = loop do break [[]]; end; test_ok(a == [[]]) a = loop do break [*[]]; end; test_ok(a == []) a = loop do break [*[1]]; end; test_ok(a == [1]) a = loop do break [*[1,2]]; end; test_ok(a == [1,2]) a = loop do break *nil; end; test_ok(a == nil) a = loop do break *1; end; test_ok(a == 1) a = loop do break *[]; end; test_ok(a == nil) a = loop do break *[1]; end; test_ok(a == 1) a = loop do break *[nil]; end; test_ok(a == nil) a = loop do break *[[]]; end; test_ok(a == []) a = loop do break *[*[]]; end; test_ok(a == nil) a = loop do break *[*[1]]; end; test_ok(a == 1) a = loop do break *[*[1,2]]; end; test_ok(a == [1,2]) *a = loop do break; end; test_ok(a == [nil]) *a = loop do break nil; end; test_ok(a == [nil]) *a = loop do break 1; end; test_ok(a == [1]) *a = loop do break []; end; test_ok(a == [[]]) *a = loop do break [1]; end; test_ok(a == [[1]]) *a = loop do break [nil]; end; test_ok(a == [[nil]]) *a = loop do break [[]]; end; test_ok(a == [[[]]]) *a = loop do break [1,2]; end; test_ok(a == [[1,2]]) *a = loop do break [*[]]; end; test_ok(a == [[]]) *a = loop do break [*[1]]; end; test_ok(a == [[1]]) *a = loop do break [*[1,2]]; end; test_ok(a == [[1,2]]) *a = loop do break *nil; end; test_ok(a == [nil]) *a = loop do break *1; end; test_ok(a == [1]) *a = loop do break *[]; end; test_ok(a == [nil]) *a = loop do break *[1]; end; test_ok(a == [1]) *a = loop do break *[nil]; end; test_ok(a == [nil]) *a = loop do break *[[]]; end; test_ok(a == [[]]) *a = loop do break *[1,2]; end; test_ok(a == [[1,2]]) *a = loop do break *[*[]]; end; test_ok(a == [nil]) *a = loop do break *[*[1]]; end; test_ok(a == [1]) *a = loop do break *[*[1,2]]; end; test_ok(a == [[1,2]]) *a = *loop do break *nil; end; test_ok(a == [nil]) *a = *loop do break *1; end; test_ok(a == [1]) *a = *loop do break *[]; end; test_ok(a == [nil]) *a = *loop do break *[1]; end; test_ok(a == [1]) *a = *loop do break *[nil]; end; test_ok(a == [nil]) *a = *loop do break *[[]]; end; test_ok(a == []) *a = *loop do break *[1,2]; end; test_ok(a == [1,2]) *a = *loop do break *[*[]]; end; test_ok(a == [nil]) *a = *loop do break *[*[1]]; end; test_ok(a == [1]) *a = *loop do break *[*[1,2]]; end; test_ok(a == [1,2]) a,b,*c = loop do break; end; test_ok([a,b,c] == [nil,nil,[]]) a,b,*c = loop do break nil; end; test_ok([a,b,c] == [nil,nil,[]]) a,b,*c = loop do break 1; end; test_ok([a,b,c] == [1,nil,[]]) a,b,*c = loop do break []; end; test_ok([a,b,c] == [nil,nil,[]]) a,b,*c = loop do break [1]; end; test_ok([a,b,c] == [1,nil,[]]) a,b,*c = loop do break [nil]; end; test_ok([a,b,c] == [nil,nil,[]]) a,b,*c = loop do break [[]]; end; test_ok([a,b,c] == [[],nil,[]]) a,b,*c = loop do break [1,2]; end; test_ok([a,b,c] == [1,2,[]]) a,b,*c = loop do break [*[]]; end; test_ok([a,b,c] == [nil,nil,[]]) a,b,*c = loop do break [*[1]]; end; test_ok([a,b,c] == [1,nil,[]]) a,b,*c = loop do break [*[1,2]]; end; test_ok([a,b,c] == [1,2,[]]) a,b,*c = loop do break *nil; end; test_ok([a,b,c] == [nil,nil,[]]) a,b,*c = loop do break *1; end; test_ok([a,b,c] == [1,nil,[]]) a,b,*c = loop do break *[]; end; test_ok([a,b,c] == [nil,nil,[]]) a,b,*c = loop do break *[1]; end; test_ok([a,b,c] == [1,nil,[]]) a,b,*c = loop do break *[nil]; end; test_ok([a,b,c] == [nil,nil,[]]) a,b,*c = loop do break *[[]]; end; test_ok([a,b,c] == [nil,nil,[]]) a,b,*c = loop do break *[1,2]; end; test_ok([a,b,c] == [1,2,[]]) a,b,*c = loop do break *[*[]]; end; test_ok([a,b,c] == [nil,nil,[]]) a,b,*c = loop do break *[*[1]]; end; test_ok([a,b,c] == [1,nil,[]]) a,b,*c = loop do break *[*[1,2]]; end; test_ok([a,b,c] == [1,2,[]]) def r(val); a = yield(); test_ok(a == val, 2); end r(nil){next} r(nil){next nil} r(1){next 1} r([]){next []} r([1]){next [1]} r([nil]){next [nil]} r([[]]){next [[]]} r([]){next [*[]]} r([1]){next [*[1]]} r([1,2]){next [*[1,2]]} r(nil){next *nil} r(1){next *1} r(nil){next *[]} r(1){next *[1]} r(nil){next *[nil]} r([]){next *[[]]} r(nil){next *[*[]]} r(1){next *[*[1]]} r([1,2]){next *[*[1,2]]} def r(val); *a = yield(); test_ok(a == val, 2); end r([nil]){next} r([nil]){next nil} r([1]){next 1} r([[]]){next []} r([[1]]){next [1]} r([[nil]]){next [nil]} r([[[]]]){next [[]]} r([[1,2]]){next [1,2]} r([[]]){next [*[]]} r([[1]]){next [*[1]]} r([[1,2]]){next [*[1,2]]} def r(val); *a = *yield(); test_ok(a == val, 2); end r([nil]){next *nil} r([1]){next *1} r([nil]){next *[]} r([1]){next *[1]} r([nil]){next *[nil]} r([]){next *[[]]} r([1,2]){next *[1,2]} r([nil]){next *[*[]]} r([1]){next *[*[1]]} r([1,2]){next *[*[1,2]]} def r(val); a,b,*c = yield(); test_ok([a,b,c] == val, 2); end r([nil,nil,[]]){next} r([nil,nil,[]]){next nil} r([1,nil,[]]){next 1} r([nil,nil,[]]){next []} r([1,nil,[]]){next [1]} r([nil,nil,[]]){next [nil]} r([[],nil,[]]){next [[]]} r([1,2,[]]){next [1,2]} r([nil,nil,[]]){next [*[]]} r([1,nil,[]]){next [*[1]]} r([1,2,[]]){next [*[1,2]]} def r(val); a,b,*c = *yield(); test_ok([a,b,c] == val, 2); end r([nil,nil,[]]){next *nil} r([1,nil,[]]){next *1} r([nil,nil,[]]){next *[]} r([1,nil,[]]){next *[1]} r([nil,nil,[]]){next *[nil]} r([nil,nil,[]]){next *[[]]} r([1,2,[]]){next *[1,2]} r([nil,nil,[]]){next *[*[]]} r([1,nil,[]]){next *[*[1]]} r([1,2,[]]){next *[*[1,2]]} test_check "condition" $x = '0'; $x == $x && test_ok(true) $x != $x && test_ok(false) $x == $x || test_ok(false) $x != $x || test_ok(true) # first test to see if we can run the tests. test_check "if/unless"; $x = 'test'; test_ok(if $x == $x then true else false end) $bad = false unless $x == $x $bad = true end test_ok(!$bad) test_ok(unless $x != $x then true else false end) test_check "case" case 5 when 1, 2, 3, 4, 6, 7, 8 test_ok(false) when 5 test_ok(true) end case 5 when 5 test_ok(true) when 1..10 test_ok(false) end case 5 when 1..10 test_ok(true) else test_ok(false) end case 5 when 5 test_ok(true) else test_ok(false) end case "foobar" when /^f.*r$/ test_ok(true) else test_ok(false) end test_check "while/until"; tmp = open("while_tmp", "w") tmp.print "tvi925\n"; tmp.print "tvi920\n"; tmp.print "vt100\n"; tmp.print "Amiga\n"; tmp.print "paper\n"; tmp.close # test break tmp = open("while_tmp", "r") test_ok(tmp.kind_of?(File)) while line = tmp.gets() break if /vt100/ =~ line end test_ok(!tmp.eof? && /vt100/ =~ line) tmp.close # test next $bad = false tmp = open("while_tmp", "r") while line = tmp.gets() next if /vt100/ =~ line $bad = 1 if /vt100/ =~ line end test_ok(!(!tmp.eof? || /vt100/ =~ line || $bad)) tmp.close # test redo $bad = false tmp = open("while_tmp", "r") while tmp.gets() line = $_ gsub(/vt100/, 'VT100') if $_ != line $_.gsub!('VT100', 'Vt100') redo end $bad = 1 if /vt100/ =~ $_ $bad = 1 if /VT100/ =~ $_ end test_ok(tmp.eof? && !$bad) tmp.close sum=0 for i in 1..10 sum += i i -= 1 if i > 0 redo end end test_ok(sum == 220) # test interval $bad = false tmp = open("while_tmp", "r") while line = tmp.gets() break if 3 case line when /vt100/, /Amiga/, /paper/ $bad = true end end test_ok(!$bad) tmp.close File.unlink "while_tmp" or `/bin/rm -f "while_tmp"` test_ok(!File.exist?("while_tmp")) i = 0 until i>4 i+=1 end test_ok(i>4) # exception handling test_check "exception"; begin raise "this must be handled" test_ok(false) rescue test_ok(true) end $bad = true begin raise "this must be handled no.2" rescue if $bad $bad = false retry test_ok(false) end end test_ok(true) # exception in rescue clause $string = "this must be handled no.3" begin begin raise "exception in rescue clause" rescue raise $string end test_ok(false) rescue test_ok(true) if $! == $string end # exception in ensure clause begin begin raise "this must be handled no.4" ensure raise "exception in ensure clause" end test_ok(false) rescue test_ok(true) end $bad = true begin begin raise "this must be handled no.5" ensure $bad = false end rescue end test_ok(!$bad) $bad = true begin begin raise "this must be handled no.6" ensure $bad = false end rescue end test_ok(!$bad) $bad = true while true begin break ensure $bad = false end end test_ok(!$bad) test_ok(catch(:foo) { loop do loop do throw :foo, true break end break test_ok(false) # should no reach here end false }) test_check "array" test_ok([1, 2] + [3, 4] == [1, 2, 3, 4]) test_ok([1, 2] * 2 == [1, 2, 1, 2]) test_ok([1, 2] * ":" == "1:2") test_ok([1, 2].hash == [1, 2].hash) test_ok([1,2,3] & [2,3,4] == [2,3]) test_ok([1,2,3] | [2,3,4] == [1,2,3,4]) test_ok([1,2,3] - [2,3] == [1]) $x = [0, 1, 2, 3, 4, 5] test_ok($x[2] == 2) test_ok($x[1..3] == [1, 2, 3]) test_ok($x[1,3] == [1, 2, 3]) $x[0, 2] = 10 test_ok($x[0] == 10 && $x[1] == 2) $x[0, 0] = -1 test_ok($x[0] == -1 && $x[1] == 10) $x[-1, 1] = 20 test_ok($x[-1] == 20 && $x.pop == 20) # array and/or test_ok(([1,2,3]&[2,4,6]) == [2]) test_ok(([1,2,3]|[2,4,6]) == [1,2,3,4,6]) # compact $x = [nil, 1, nil, nil, 5, nil, nil] $x.compact! test_ok($x == [1, 5]) # uniq $x = [1, 1, 4, 2, 5, 4, 5, 1, 2] $x.uniq! test_ok($x == [1, 4, 2, 5]) # empty? test_ok(!$x.empty?) $x = [] test_ok($x.empty?) # sort $x = ["it", "came", "to", "pass", "that", "..."] $x = $x.sort.join(" ") test_ok($x == "... came it pass that to") $x = [2,5,3,1,7] $x.sort!{|a,b| a<=>b} # sort with condition test_ok($x == [1,2,3,5,7]) $x.sort!{|a,b| b-a} # reverse sort test_ok($x == [7,5,3,2,1]) # split test $x = "The Book of Mormon" test_ok($x.split(//).reverse!.join == $x.reverse) test_ok($x.reverse == $x.reverse!) test_ok("1 byte string".split(//).reverse.join(":") == "g:n:i:r:t:s: :e:t:y:b: :1") $x = "a b c d" test_ok($x.split == ['a', 'b', 'c', 'd']) test_ok($x.split(' ') == ['a', 'b', 'c', 'd']) test_ok(defined? "a".chomp) test_ok("abc".scan(/./) == ["a", "b", "c"]) test_ok("1a2b3c".scan(/(\d.)/) == [["1a"], ["2b"], ["3c"]]) # non-greedy match test_ok("a=12;b=22".scan(/(.*?)=(\d*);?/) == [["a", "12"], ["b", "22"]]) $x = [1] test_ok(($x * 5).join(":") == '1:1:1:1:1') test_ok(($x * 1).join(":") == '1') test_ok(($x * 0).join(":") == '') *$x = *(1..7).to_a test_ok($x.size == 7) test_ok($x == [1, 2, 3, 4, 5, 6, 7]) $x = [1,2,3] $x[1,0] = $x test_ok($x == [1,1,2,3,2,3]) $x = [1,2,3] $x[-1,0] = $x test_ok($x == [1,2,1,2,3,3]) $x = [1,2,3] $x.concat($x) test_ok($x == [1,2,3,1,2,3]) test_check "hash" $x = {1=>2, 2=>4, 3=>6} $y = {1, 2, 2, 4, 3, 6} test_ok($x[1] == 2) test_ok(begin for k,v in $y raise if k*2 != v end true rescue false end) test_ok($x.length == 3) test_ok($x.has_key?(1)) test_ok($x.has_value?(4)) test_ok($x.values_at(2,3) == [4,6]) test_ok($x == {1=>2, 2=>4, 3=>6}) $z = $y.keys.sort.join(":") test_ok($z == "1:2:3") $z = $y.values.sort.join(":") test_ok($z == "2:4:6") test_ok($x == $y) $y.shift test_ok($y.length == 2) $z = [1,2] $y[$z] = 256 test_ok($y[$z] == 256) $x = Hash.new(0) $x[1] = 1 test_ok($x[1] == 1) test_ok($x[2] == 0) $x = Hash.new([]) test_ok($x[22] == []) test_ok($x[22].equal?($x[22])) $x = Hash.new{[]} test_ok($x[22] == []) test_ok(!$x[22].equal?($x[22])) $x = Hash.new{|h,k| $z = k; h[k] = k*2} $z = 0 test_ok($x[22] == 44) test_ok($z == 22) $z = 0 test_ok($x[22] == 44) test_ok($z == 0) $x.default = 5 test_ok($x[23] == 5) $x = Hash.new def $x.default(k) $z = k self[k] = k*2 end $z = 0 test_ok($x[22] == 44) test_ok($z == 22) $z = 0 test_ok($x[22] == 44) test_ok($z == 0) test_check "iterator" test_ok(!iterator?) def ttt test_ok(iterator?) end ttt{} # yield at top level test_ok(!defined?(yield)) $x = [1, 2, 3, 4] $y = [] # iterator over array for i in $x $y.push i end test_ok($x == $y) # nested iterator def tt 1.upto(10) {|i| yield i } end tt{|i| break if i == 5} test_ok(i == 5) def tt2(dummy) yield 1 end def tt3(&block) tt2(raise(ArgumentError,""),&block) end $x = false begin tt3{} rescue ArgumentError $x = true rescue Exception end test_ok($x) def tt4 &block tt2(raise(ArgumentError,""),&block) end $x = false begin tt4{} rescue ArgumentError $x = true rescue Exception end test_ok($x) # iterator break/redo/next/retry done = true loop{ break done = false # should not reach here } test_ok(done) done = false $bad = false loop { break if done done = true next $bad = true # should not reach here } test_ok(!$bad) done = false $bad = false loop { break if done done = true redo $bad = true # should not reach here } test_ok(!$bad) $x = [] for i in 1 .. 7 $x.push i end test_ok($x.size == 7) test_ok($x == [1, 2, 3, 4, 5, 6, 7]) $done = false $x = [] for i in 1 .. 7 # see how retry works in iterator loop if i == 4 and not $done $done = true retry end $x.push(i) end test_ok($x.size == 10) test_ok($x == [1, 2, 3, 1, 2, 3, 4, 5, 6, 7]) # append method to built-in class class Array def iter_test1 collect{|e| [e, yield(e)]}.sort{|a,b|a[1]<=>b[1]} end def iter_test2 a = collect{|e| [e, yield(e)]} a.sort{|a,b|a[1]<=>b[1]} end end $x = [[1,2],[3,4],[5,6]] test_ok($x.iter_test1{|x|x} == $x.iter_test2{|x|x}) class IterTest def initialize(e); @body = e; end def each0(&block); @body.each(&block); end def each1(&block); @body.each {|*x| block.call(*x) } end def each2(&block); @body.each {|*x| block.call(x) } end def each3(&block); @body.each {|x| block.call(*x) } end def each4(&block); @body.each {|x| block.call(x) } end def each5; @body.each {|*x| yield(*x) } end def each6; @body.each {|*x| yield(x) } end def each7; @body.each {|x| yield(*x) } end def each8; @body.each {|x| yield(x) } end def f(a) a end end test_ok(IterTest.new(nil).method(:f).to_proc.call([1]) == [1]) m = /\w+/.match("abc") test_ok(IterTest.new(nil).method(:f).to_proc.call([m]) == [m]) IterTest.new([0]).each0 {|x| test_ok(x == 0)} IterTest.new([1]).each1 {|x| test_ok(x == 1)} IterTest.new([2]).each2 {|x| test_ok(x == [2])} IterTest.new([3]).each3 {|x| test_ok(x == 3)} IterTest.new([4]).each4 {|x| test_ok(x == 4)} IterTest.new([5]).each5 {|x| test_ok(x == 5)} IterTest.new([6]).each6 {|x| test_ok(x == [6])} IterTest.new([7]).each7 {|x| test_ok(x == 7)} IterTest.new([8]).each8 {|x| test_ok(x == 8)} IterTest.new([[0]]).each0 {|x| test_ok(x == [0])} IterTest.new([[1]]).each1 {|x| test_ok(x == [1])} IterTest.new([[2]]).each2 {|x| test_ok(x == [[2]])} IterTest.new([[3]]).each3 {|x| test_ok(x == 3)} IterTest.new([[4]]).each4 {|x| test_ok(x == [4])} IterTest.new([[5]]).each5 {|x| test_ok(x == [5])} IterTest.new([[6]]).each6 {|x| test_ok(x == [[6]])} IterTest.new([[7]]).each7 {|x| test_ok(x == 7)} IterTest.new([[8]]).each8 {|x| test_ok(x == [8])} IterTest.new([[0,0]]).each0 {|x| test_ok(x == [0,0])} IterTest.new([[8,8]]).each8 {|x| test_ok(x == [8,8])} def m0(v) v end def m1 m0(block_given?) end test_ok(m1{p 'test'}) test_ok(!m1) def m m0(block_given?,&proc{}) end test_ok(m1{p 'test'}) test_ok(!m1) class C include Enumerable def initialize @a = [1,2,3] end def each(&block) @a.each(&block) end end test_ok(C.new.collect{|n| n} == [1,2,3]) test_ok(Proc == lambda{}.class) test_ok(Proc == Proc.new{}.class) lambda{|a|test_ok(a==1)}.call(1) def block_test(klass, &block) test_ok(klass === block) end block_test(NilClass) block_test(Proc){} def argument_test(state, proc, *args) x = state begin proc.call(*args) rescue ArgumentError x = !x end test_ok(x,2) end argument_test(true, lambda{||}) argument_test(false, lambda{||}, 1) argument_test(true, lambda{|a,|}, 1) argument_test(false, lambda{|a,|}) argument_test(false, lambda{|a,|}, 1,2) def get_block(&block) block end test_ok(Proc == get_block{}.class) argument_test(true, get_block{||}) argument_test(true, get_block{||}, 1) argument_test(true, get_block{|a,|}, 1) argument_test(true, get_block{|a,|}) argument_test(true, get_block{|a,|}, 1,2) argument_test(true, get_block(&lambda{||})) argument_test(false, get_block(&lambda{||}),1) argument_test(true, get_block(&lambda{|a,|}),1) argument_test(false, get_block(&lambda{|a,|}),1,2) block = get_block{11} test_ok(block.class == Proc) test_ok(block.to_proc.class == Proc) test_ok(block.clone.call == 11) test_ok(get_block(&block).class == Proc) lambda = lambda{44} test_ok(lambda.class == Proc) test_ok(lambda.to_proc.class == Proc) test_ok(lambda.clone.call == 44) test_ok(get_block(&lambda).class == Proc) test_ok(Proc.new{|a,| a}.call(1,2,3) == 1) argument_test(true, Proc.new{|a,|}, 1,2) test_ok(Proc.new{|&b| b.call(10)}.call {|x| x} == 10) test_ok(Proc.new{|a,&b| b.call(a)}.call(12) {|x| x} == 12) def test_return1 Proc.new { return 55 }.call + 5 end test_ok(test_return1() == 55) def test_return2 lambda { return 55 }.call + 5 end test_ok(test_return2() == 60) def proc_call(&b) b.call end def proc_yield() yield end def proc_return1 proc_call{return 42}+1 end test_ok(proc_return1() == 42) def proc_return2 proc_yield{return 42}+1 end test_ok(proc_return2() == 42) def ljump_test(state, proc, *args) x = state begin proc.call(*args) rescue LocalJumpError x = !x end test_ok(x,2) end ljump_test(false, get_block{break}) ljump_test(true, lambda{break}) test_ok(block.arity == -1) test_ok(lambda.arity == -1) test_ok(lambda{||}.arity == 0) test_ok(lambda{|a|}.arity == 1) test_ok(lambda{|a,|}.arity == 1) test_ok(lambda{|a,b|}.arity == 2) def marity_test(m) method = method(m) test_ok(method.arity == method.to_proc.arity) end marity_test(:test_ok) marity_test(:marity_test) marity_test(:p) lambda(&method(:test_ok)).call(true) lambda(&get_block{|a,n| test_ok(a,n)}).call(true, 2) class ITER_TEST1 def a block_given? end end class ITER_TEST2 < ITER_TEST1 def a test_ok(super) super end end test_ok(ITER_TEST2.new.a {}) class ITER_TEST3 def foo x return yield if block_given? x end end class ITER_TEST4 < ITER_TEST3 def foo x test_ok(super == yield) test_ok(super(x, &nil) == x) end end ITER_TEST4.new.foo(44){55} test_check "float" test_ok(2.6.floor == 2) test_ok((-2.6).floor == -3) test_ok(2.6.ceil == 3) test_ok((-2.6).ceil == -2) test_ok(2.6.truncate == 2) test_ok((-2.6).truncate == -2) test_ok(2.6.round == 3) test_ok((-2.4).truncate == -2) test_ok((13.4 % 1 - 0.4).abs < 0.0001) nan = 0.0/0 def nan_test(x,y) test_ok(x != y) test_ok((x < y) == false) test_ok((x > y) == false) test_ok((x <= y) == false) test_ok((x >= y) == false) end nan_test(nan, nan) nan_test(nan, 0) nan_test(nan, 1) nan_test(nan, -1) nan_test(nan, 1000) nan_test(nan, -1000) nan_test(nan, 1_000_000_000_000) nan_test(nan, -1_000_000_000_000) nan_test(nan, 100.0); nan_test(nan, -100.0); nan_test(nan, 0.001); nan_test(nan, -0.001); nan_test(nan, 1.0/0); nan_test(nan, -1.0/0); #s = "3.7517675036461267e+17" #test_ok(s == sprintf("%.16e", s.to_f)) f = 3.7517675036461267e+17 test_ok(f == sprintf("%.16e", f).to_f) test_check "bignum" def fact(n) return 1 if n == 0 f = 1 while n>0 f *= n n -= 1 end return f end $x = fact(40) test_ok($x == $x) test_ok($x == fact(40)) test_ok($x < $x+2) test_ok($x > $x-2) test_ok($x == 815915283247897734345611269596115894272000000000) test_ok($x != 815915283247897734345611269596115894272000000001) test_ok($x+1 == 815915283247897734345611269596115894272000000001) test_ok($x/fact(20) == 335367096786357081410764800000) $x = -$x test_ok($x == -815915283247897734345611269596115894272000000000) test_ok(2-(2**32) == -(2**32-2)) test_ok(2**32 - 5 == (2**32-3)-2) $good = true; for i in 1000..1014 $good = false if ((1 << i) != (2**i)) end test_ok($good) $good = true; n1= 1 << 1000 for i in 1000..1014 $good = false if ((1 << i) != n1) n1 *= 2 end test_ok($good) $good = true; n2=n1 for i in 1..10 n1 = n1 / 2 n2 = n2 >> 1 $good = false if (n1 != n2) end test_ok($good) $good = true; for i in 4000..4096 n1 = 1 << i; if (n1**2-1) / (n1+1) != (n1-1) p i $good = false end end test_ok($good) b = 10**80 a = b * 9 + 7 test_ok(7 == a.modulo(b)) test_ok(-b + 7 == a.modulo(-b)) test_ok(b + -7 == (-a).modulo(b)) test_ok(-7 == (-a).modulo(-b)) test_ok(7 == a.remainder(b)) test_ok(7 == a.remainder(-b)) test_ok(-7 == (-a).remainder(b)) test_ok(-7 == (-a).remainder(-b)) test_ok(10**40+10**20 == 10000000000000000000100000000000000000000) test_ok(10**40/10**20 == 100000000000000000000) a = 677330545177305025495135714080 b = 14269972710765292560 test_ok(a % b == 0) test_ok(-a % b == 0) def shift_test(a) b = a / (2 ** 32) c = a >> 32 test_ok(b == c) b = a * (2 ** 32) c = a << 32 test_ok(b == c) end shift_test(-4518325415524767873) shift_test(-0xfffffffffffffffff) test_check "string & char" test_ok("abcd" == "abcd") test_ok("abcd" =~ /abcd/) test_ok("abcd" === "abcd") # compile time string concatenation test_ok("ab" "cd" == "abcd") test_ok("#{22}aa" "cd#{44}" == "22aacd44") test_ok("#{22}aa" "cd#{44}" "55" "#{66}" == "22aacd445566") test_ok("abc" !~ /^$/) test_ok("abc\n" !~ /^$/) test_ok("abc" !~ /^d*$/) test_ok(("abc" =~ /d*$/) == 3) test_ok("" =~ /^$/) test_ok("\n" =~ /^$/) test_ok("a\n\n" =~ /^$/) test_ok("abcabc" =~ /.*a/ && $& == "abca") test_ok("abcabc" =~ /.*c/ && $& == "abcabc") test_ok("abcabc" =~ /.*?a/ && $& == "a") test_ok("abcabc" =~ /.*?c/ && $& == "abc") test_ok(/(.|\n)*?\n(b|\n)/ =~ "a\nb\n\n" && $& == "a\nb") test_ok(/^(ab+)+b/ =~ "ababb" && $& == "ababb") test_ok(/^(?:ab+)+b/ =~ "ababb" && $& == "ababb") test_ok(/^(ab+)+/ =~ "ababb" && $& == "ababb") test_ok(/^(?:ab+)+/ =~ "ababb" && $& == "ababb") test_ok(/(\s+\d+){2}/ =~ " 1 2" && $& == " 1 2") test_ok(/(?:\s+\d+){2}/ =~ " 1 2" && $& == " 1 2") $x = <') == "") # character constants(assumes ASCII) test_ok("a"[0] == ?a) test_ok(?a == ?a) test_ok(?\C-a == 1) test_ok(?\M-a == 225) test_ok(?\M-\C-a == 129) test_ok("a".upcase![0] == ?A) test_ok("A".downcase![0] == ?a) test_ok("abc".tr!("a-z", "A-Z") == "ABC") test_ok("aabbcccc".tr_s!("a-z", "A-Z") == "ABC") test_ok("abcc".squeeze!("a-z") == "abc") test_ok("abcd".delete!("bc") == "ad") $x = "abcdef" $y = [ ?a, ?b, ?c, ?d, ?e, ?f ] $bad = false $x.each_byte {|i| if i != $y.shift $bad = true break end } test_ok(!$bad) s = "a string" s[0..s.size]="another string" test_ok(s == "another string") s = < Object) == -1) test_ok((Object <=> String) == 1) test_ok((Array <=> String) == nil) test_check "clone" foo = Object.new def foo.test "test" end bar = foo.clone def bar.test2 "test2" end test_ok(bar.test2 == "test2") test_ok(bar.test == "test") test_ok(foo.test == "test") begin foo.test2 test_ok false rescue NoMethodError test_ok true end module M001; end module M002; end module M003; include M002; end module M002; include M001; end module M003; include M002; end test_ok(M003.ancestors == [M003, M002, M001]) test_check "marshal" $x = [1,2,3,[4,5,"foo"],{1=>"bar"},2.5,fact(30)] $y = Marshal.dump($x) test_ok($x == Marshal.load($y)) StrClone=String.clone; test_ok(Marshal.load(Marshal.dump(StrClone.new("abc"))).class == StrClone) [[1,2,3,4], [81, 2, 118, 3146]].each { |w,x,y,z| a = (x.to_f + y.to_f / z.to_f) * Math.exp(w.to_f / (x.to_f + y.to_f / z.to_f)) ma = Marshal.dump(a) b = Marshal.load(ma) test_ok(a == b) } test_check "pack" $format = "c2x5CCxsdils_l_a6"; # Need the expression in here to force ary[5] to be numeric. This avoids # test2 failing because ary2 goes str->numeric->str and ary does not. ary = [1,-100,127,128,32767,987.654321098 / 100.0,12345,123456,-32767,-123456,"abcdef"] $x = ary.pack($format) ary2 = $x.unpack($format) test_ok(ary.length == ary2.length) test_ok(ary.join(':') == ary2.join(':')) test_ok($x =~ /def/) $x = [-1073741825] test_ok($x.pack("q").unpack("q") == $x) test_check "math" test_ok(Math.sqrt(4) == 2) include Math test_ok(sqrt(4) == 2) test_check "struct" struct_test = Struct.new("Test", :foo, :bar) test_ok(struct_test == Struct::Test) test = struct_test.new(1, 2) test_ok(test.foo == 1 && test.bar == 2) test_ok(test[0] == 1 && test[1] == 2) a, b = test.to_a test_ok(a == 1 && b == 2) test[0] = 22 test_ok(test.foo == 22) test.bar = 47 test_ok(test.bar == 47) test_check "variable" test_ok($$.instance_of?(Fixnum)) # read-only variable begin $$ = 5 test_ok false rescue NameError test_ok true end foobar = "foobar" $_ = foobar test_ok($_ == foobar) class Gods @@rule = "Uranus" def ruler0 @@rule end def self.ruler1 # <= per method definition style @@rule end class << self # <= multiple method definition style def ruler2 @@rule end end end module Olympians @@rule ="Zeus" def ruler3 @@rule end end class Titans < Gods @@rule = "Cronus" include Olympians # OK to cause warning (intentional) end test_ok(Gods.new.ruler0 == "Cronus") test_ok(Gods.ruler1 == "Cronus") test_ok(Gods.ruler2 == "Cronus") test_ok(Titans.ruler1 == "Cronus") test_ok(Titans.ruler2 == "Cronus") atlas = Titans.new test_ok(atlas.ruler0 == "Cronus") test_ok(atlas.ruler3 == "Zeus") test_check "trace" $x = 1234 $y = 0 trace_var :$x, proc{$y = $x} $x = 40414 test_ok($y == $x) untrace_var :$x $x = 19660208 test_ok($y != $x) trace_var :$x, proc{$x *= 2} $x = 5 test_ok($x == 10) untrace_var :$x test_check "defined?" test_ok(defined?($x)) # global variable test_ok(defined?($x) == 'global-variable')# returns description foo=5 test_ok(defined?(foo)) # local variable test_ok(defined?(Array)) # constant test_ok(defined?(Object.new)) # method test_ok(!defined?(Object.print))# private method test_ok(defined?(1 == 2)) # operator expression class Foo def foo p :foo end protected :foo def bar(f) test_ok(defined?(self.foo)) test_ok(defined?(f.foo)) end end f = Foo.new test_ok(defined?(f.foo) == nil) f.bar(f) def defined_test return !defined?(yield) end test_ok(defined_test) # not iterator test_ok(!defined_test{}) # called as iterator test_check "alias" class Alias0 def foo; "foo" end end class Alias1 0 printf "test: %d failed %d\n", $ntest, $failed else printf "end of test(test: %d)\n", $ntest end ================================================ FILE: sample/testunit/adder.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. class Adder def initialize(number) @number = number end def add(number) return @number + number end end ================================================ FILE: sample/testunit/subtracter.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. class Subtracter def initialize(number) @number = number end def subtract(number) return @number - number end end ================================================ FILE: sample/testunit/tc_adder.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' require 'adder' class TC_Adder < Test::Unit::TestCase def setup @adder = Adder.new(5) end def test_add assert_equal(7, @adder.add(2), "Should have added correctly") end def teardown @adder = nil end end ================================================ FILE: sample/testunit/tc_subtracter.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' require 'subtracter' class TC_Subtracter < Test::Unit::TestCase def setup @subtracter = Subtracter.new(5) end def test_subtract assert_equal(3, @subtracter.subtract(2), "Should have subtracted correctly") end def teardown @subtracter = nil end end ================================================ FILE: sample/testunit/ts_examples.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' require 'tc_adder' require 'tc_subtracter' ================================================ FILE: sample/time.rb ================================================ #! /usr/bin/env ruby b = Time.now system(*ARGV) e = Time.now tms = Process.times real = e - b user = tms.cutime sys = tms.cstime STDERR.printf("%11.1f real %11.1f user %11.1f sys\n", real, user, sys) ================================================ FILE: sample/trojan.rb ================================================ #! /usr/local/bin/ruby path = ENV['PATH'].split(File::PATH_SEPARATOR) for dir in path if File.directory?(dir) for f in d = Dir.open(dir) fpath = File.join(dir, f) if File.file?(fpath) && (File.stat(fpath).mode & 022) != 0 printf("file %s is writable from other users\n", fpath) end end d.close end end ================================================ FILE: sample/tsvr.rb ================================================ # socket example - server side using thread # usage: ruby tsvr.rb require "socket" gs = TCPserver.open(0) addr = gs.addr addr.shift printf("server is on %s\n", addr.join(":")) loop do Thread.start(gs.accept) do |s| print(s, " is accepted\n") while line = s.gets s.write(line) end print(s, " is gone\n") s.close end end ================================================ FILE: sample/uumerge.rb ================================================ #!/usr/bin/env ruby if ARGV[0] == "-c" out_stdout = 1 ARGV.shift end $sawbegin = 0 $sawend = 0 while line = gets() if /^begin\s*(\d*)\s*(\S*)/ =~ line $mode, $file = $1, $2 $sawbegin+=1 if out_stdout out = STDOUT else out = open($file, "w") if $file != "" end out.binmode break end end raise "missing begin" unless $sawbegin out.binmode while line = gets() if /^end/ =~ line $sawend+=1 out.close unless out_stdout File.chmod $mode.oct, $file unless out_stdout next end line.sub!(/[a-z]+$/, "") # handle stupid trailing lowercase letters next if /[a-z]/ =~ line next if !(((($_[0] - 32) & 077) + 2) / 3 == $_.length / 4) out << $_.unpack("u") if $sawbegin > $sawend end raise "missing end" if $sawbegin > $sawend raise "missing begin" if ! $sawbegin exit 0 ================================================ FILE: sample/webrick/demo-app.rb ================================================ require "pp" module DemoApplication def initialize(config, enctype) super @enctype = enctype end def do_GET(req, res) if req.path_info != "/" res.set_redirect(WEBrick::HTTPStatus::Found, req.script_name + "/") end res.body =<<-_end_of_html_
      text:
      file:
      check: a, b, c,
      _end_of_html_ res['content-type'] = 'text/html; charset=iso-8859-1' end def do_POST(req, res) if req["content-length"].to_i > 1024*10 raise WEBrick::HTTPStatus::Forbidden, "file size too large" end res.body =<<-_end_of_html_

      Query Parameters

      #{display_query(req.query)} return

      Request

      #{WEBrick::HTMLUtils::escape(PP::pp(req, "", 80))}

      Response

      #{WEBrick::HTMLUtils::escape(PP::pp(res, "", 80))}
      _end_of_html_ res['content-type'] = 'text/html; charset=iso-8859-1' end private def display_query(q) ret = "" q.each{|key, val| ret << "

      #{WEBrick::HTMLUtils::escape(key)}

      " ret << "" ret << make_tr("val", val.inspect) ret << make_tr("val.to_a", val.to_a.inspect) ret << make_tr("val.to_ary", val.to_ary.inspect) ret << "
      " } ret end def make_tr(arg0, arg1) "#{arg0}#{WEBrick::HTMLUtils::escape(arg1)}" end end ================================================ FILE: sample/webrick/demo-multipart.cgi ================================================ #!/usr/bin/env ruby require "webrick/cgi" require "webrick/https" # should load if it runs on HTTPS server require "./demo-app" class DemoCGI < WEBrick::CGI include DemoApplication end config = { :NPH => false } cgi = DemoCGI.new(config, "multipart/form-data") cgi.start ================================================ FILE: sample/webrick/demo-servlet.rb ================================================ require "webrick" require "./demo-app" class DemoServlet < WEBrick::HTTPServlet::AbstractServlet include DemoApplication end ================================================ FILE: sample/webrick/demo-urlencoded.cgi ================================================ #!/usr/bin/env ruby require "webrick/cgi" require "webrick/https" # should load if it runs on HTTPS server require "./demo-app" class DemoCGI < WEBrick::CGI include DemoApplication end config = { :NPH => false } cgi = DemoCGI.new(config, "application/x-www-form-urlencoded") cgi.start ================================================ FILE: sample/webrick/hello.cgi ================================================ #!/usr/bin/env ruby require "webrick/cgi" class HelloCGI < WEBrick::CGI def do_GET(req, res) res["content-type"] = "text/plain" res.body = "Hello, world.\n" end end HelloCGI.new.start ================================================ FILE: sample/webrick/hello.rb ================================================ require "webrick" class HelloServlet < WEBrick::HTTPServlet::AbstractServlet def do_GET(req, res) res["content-type"] = "text/plain" res.body = "Hello, world.\n" end end ================================================ FILE: sample/webrick/httpd.rb ================================================ require "webrick" httpd = WEBrick::HTTPServer.new( :DocumentRoot => File::dirname(__FILE__), :Port => 10080, :Logger => WEBrick::Log.new($stderr, WEBrick::Log::DEBUG), :AccessLog => [ [ $stderr, WEBrick::AccessLog::COMMON_LOG_FORMAT ], [ $stderr, WEBrick::AccessLog::REFERER_LOG_FORMAT ], [ $stderr, WEBrick::AccessLog::AGENT_LOG_FORMAT ], ], :CGIPathEnv => ENV["PATH"] # PATH environment variable for CGI. ) require "./hello" httpd.mount("/hello", HelloServlet) require "./demo-servlet" httpd.mount("/urlencoded", DemoServlet, "application/x-www-form-urlencoded") httpd.mount("/multipart", DemoServlet, "multipart/form-data") trap(:INT){ httpd.shutdown } httpd.start ================================================ FILE: sample/webrick/httpproxy.rb ================================================ require "webrick" require "webrick/httpproxy" # :ProxyContentHandler will be invoked before sending # response to User-Agenge. You can inspect the pair of # request and response messages (or can edit the response # message if necessary). pch = Proc.new{|req, res| p [ req.request_line, res.status_line ] } def upstream_proxy if prx = ENV["http_proxy"] return URI.parse(prx) end return nil end httpd = WEBrick::HTTPProxyServer.new( :Port => 10080, :ProxyContentHandler => pch, :ProxyURI => upstream_proxy ) Signal.trap(:INT){ httpd.shutdown } httpd.start ================================================ FILE: sample/webrick/httpsd.rb ================================================ require "webrick" require "webrick/https" hostname = WEBrick::Utils::getservername subject = [["O", "ruby-lang.org"], ["OU", "sample"], ["CN", hostname]] comment = "Comment for self-signed certificate" httpd = WEBrick::HTTPServer.new( :DocumentRoot => File::dirname(__FILE__), :Port => 10443, :SSLEnable => true, # Specify key pair and server certificate. # :SSLPrivateKey => OpenSSL::PKey::RSA.new(File.read("server.key")), # :SSLCertificate => OpenSSL::X509::Certificate.new(File.read("server.crt")), # specify the following SSL options if you want to use auto # generated self-signed certificate. :SSLCertName => subject, :SSLComment => comment, :CGIPathEnv => ENV["PATH"] # PATH environment variable for CGI. ) require "./hello" httpd.mount("/hello", HelloServlet) require "./demo-servlet" httpd.mount("/urlencoded", DemoServlet, "application/x-www-form-urlencoded") httpd.mount("/multipart", DemoServlet, "multipart/form-data") trap(:INT){ httpd.shutdown } httpd.start ================================================ FILE: signal.c ================================================ /********************************************************************** signal.c - $Author$ $Date$ created at: Tue Dec 20 10:13:44 JST 1994 Copyright (C) 1993-2003 Yukihiro Matsumoto Copyright (C) 2000 Network Applied Communication Laboratory, Inc. Copyright (C) 2000 Information-technology Promotion Agency, Japan **********************************************************************/ #include "ruby.h" #include "rubysig.h" #include "node.h" #include #include #include #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef __BEOS__ #undef SIGBUS #endif #if defined HAVE_SIGPROCMASK || defined HAVE_SIGSETMASK #define USE_TRAP_MASK 1 #else #define USE_TRAP_MASK 0 #endif #ifndef NSIG # ifdef DJGPP # define NSIG SIGMAX # else # define NSIG (_SIGMAX + 1) /* For QNX */ # endif #endif static struct signals { const char *signm; int signo; } siglist [] = { {"EXIT", 0}, #ifdef SIGHUP {"HUP", SIGHUP}, #endif {"INT", SIGINT}, #ifdef SIGQUIT {"QUIT", SIGQUIT}, #endif #ifdef SIGILL {"ILL", SIGILL}, #endif #ifdef SIGTRAP {"TRAP", SIGTRAP}, #endif #ifdef SIGIOT {"IOT", SIGIOT}, #endif #ifdef SIGABRT {"ABRT", SIGABRT}, #endif #ifdef SIGEMT {"EMT", SIGEMT}, #endif #ifdef SIGFPE {"FPE", SIGFPE}, #endif #ifdef SIGKILL {"KILL", SIGKILL}, #endif #ifdef SIGBUS {"BUS", SIGBUS}, #endif #ifdef SIGSEGV {"SEGV", SIGSEGV}, #endif #ifdef SIGSYS {"SYS", SIGSYS}, #endif #ifdef SIGPIPE {"PIPE", SIGPIPE}, #endif #ifdef SIGALRM {"ALRM", SIGALRM}, #endif #ifdef SIGTERM {"TERM", SIGTERM}, #endif #ifdef SIGURG {"URG", SIGURG}, #endif #ifdef SIGSTOP {"STOP", SIGSTOP}, #endif #ifdef SIGTSTP {"TSTP", SIGTSTP}, #endif #ifdef SIGCONT {"CONT", SIGCONT}, #endif #ifdef SIGCHLD {"CHLD", SIGCHLD}, #endif #ifdef SIGCLD {"CLD", SIGCLD}, #else # ifdef SIGCHLD {"CLD", SIGCHLD}, # endif #endif #ifdef SIGTTIN {"TTIN", SIGTTIN}, #endif #ifdef SIGTTOU {"TTOU", SIGTTOU}, #endif #ifdef SIGIO {"IO", SIGIO}, #endif #ifdef SIGXCPU {"XCPU", SIGXCPU}, #endif #ifdef SIGXFSZ {"XFSZ", SIGXFSZ}, #endif #ifdef SIGVTALRM {"VTALRM", SIGVTALRM}, #endif #ifdef SIGPROF {"PROF", SIGPROF}, #endif #ifdef SIGWINCH {"WINCH", SIGWINCH}, #endif #ifdef SIGUSR1 {"USR1", SIGUSR1}, #endif #ifdef SIGUSR2 {"USR2", SIGUSR2}, #endif #ifdef SIGLOST {"LOST", SIGLOST}, #endif #ifdef SIGMSG {"MSG", SIGMSG}, #endif #ifdef SIGPWR {"PWR", SIGPWR}, #endif #ifdef SIGPOLL {"POLL", SIGPOLL}, #endif #ifdef SIGDANGER {"DANGER", SIGDANGER}, #endif #ifdef SIGMIGRATE {"MIGRATE", SIGMIGRATE}, #endif #ifdef SIGPRE {"PRE", SIGPRE}, #endif #ifdef SIGGRANT {"GRANT", SIGGRANT}, #endif #ifdef SIGRETRACT {"RETRACT", SIGRETRACT}, #endif #ifdef SIGSOUND {"SOUND", SIGSOUND}, #endif #ifdef SIGINFO {"INFO", SIGINFO}, #endif {NULL, 0} }; static int signm2signo(nm) const char *nm; { struct signals *sigs; for (sigs = siglist; sigs->signm; sigs++) if (strcmp(sigs->signm, nm) == 0) return sigs->signo; return 0; } static const char* signo2signm(no) int no; { struct signals *sigs; for (sigs = siglist; sigs->signm; sigs++) if (sigs->signo == no) return sigs->signm; return 0; } const char * ruby_signal_name(no) int no; { return signo2signm(no); } /* * call-seq: * SignalException.new(sig) => signal_exception * * Construct a new SignalException object. +sig+ should be a known * signal name, or a signal number. */ static VALUE esignal_init(argc, argv, self) int argc; VALUE *argv; VALUE self; { int argnum = 1; VALUE sig = Qnil; int signo; const char *signm; char tmpnm[(sizeof(int)*CHAR_BIT)/3+4]; if (argc > 0) { sig = argv[0]; if (FIXNUM_P(sig)) argnum = 2; } if (argc < 1 || argnum < argc) { rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, argnum); } if (argnum == 2) { signo = FIX2INT(sig); if (signo < 0 || signo > NSIG) { rb_raise(rb_eArgError, "invalid signal number (%d)", signo); } if (argc > 1) { sig = argv[1]; } else { signm = signo2signm(signo); if (signm) { snprintf(tmpnm, sizeof(tmpnm), "SIG%s", signm); } else { snprintf(tmpnm, sizeof(tmpnm), "SIG%u", signo); } sig = rb_str_new2(signm = tmpnm); } } else { signm = SYMBOL_P(sig) ? rb_id2name(SYM2ID(sig)) : StringValuePtr(sig); if (strncmp(signm, "SIG", 3) == 0) signm += 3; signo = signm2signo(signm); if (!signo) { rb_raise(rb_eArgError, "unsupported name `SIG%s'", signm); } if (SYMBOL_P(sig)) { sig = rb_str_new2(signm); } } rb_call_super(1, &sig); rb_iv_set(self, "signo", INT2NUM(signo)); return self; } static VALUE interrupt_init(argc, argv, self) int argc; VALUE *argv; VALUE self; { VALUE args[2]; args[0] = INT2FIX(SIGINT); rb_scan_args(argc, argv, "01", &args[1]); return rb_call_super(2, args); } void ruby_default_signal(sig) int sig; { #ifndef MACOS_UNUSE_SIGNAL extern rb_pid_t getpid _((void)); signal(sig, SIG_DFL); kill(getpid(), sig); #endif } /* * call-seq: * Process.kill(signal, pid, ...) => fixnum * * Sends the given signal to the specified process id(s), or to the * current process if _pid_ is zero. _signal_ may be an * integer signal number or a POSIX signal name (either with or without * a +SIG+ prefix). If _signal_ is negative (or starts * with a minus sign), kills process groups instead of * processes. Not all signals are available on all platforms. * * pid = fork do * Signal.trap("HUP") { puts "Ouch!"; exit } * # ... do some work ... * end * # ... * Process.kill("HUP", pid) * Process.wait * * produces: * * Ouch! */ VALUE rb_f_kill(argc, argv) int argc; VALUE *argv; { int negative = 0; int sig; int i; const char *s; rb_secure(2); if (argc < 2) rb_raise(rb_eArgError, "wrong number of arguments -- kill(sig, pid...)"); switch (TYPE(argv[0])) { case T_FIXNUM: sig = FIX2INT(argv[0]); break; case T_SYMBOL: s = rb_id2name(SYM2ID(argv[0])); if (!s) rb_raise(rb_eArgError, "bad signal"); goto str_signal; case T_STRING: s = RSTRING(argv[0])->ptr; if (s[0] == '-') { negative++; s++; } str_signal: if (strncmp("SIG", s, 3) == 0) s += 3; if((sig = signm2signo(s)) == 0) rb_raise(rb_eArgError, "unsupported name `SIG%s'", s); if (negative) sig = -sig; break; default: { VALUE str; str = rb_check_string_type(argv[0]); if (!NIL_P(str)) { s = RSTRING(str)->ptr; goto str_signal; } rb_raise(rb_eArgError, "bad signal type %s", rb_obj_classname(argv[0])); } break; } if (sig < 0) { sig = -sig; for (i=1; i= NSIG) { rb_bug("trap_handler: Bad signal %d", sig); } #if defined(HAVE_NATIVETHREAD) && defined(HAVE_NATIVETHREAD_KILL) if (!is_ruby_native_thread() && !rb_trap_accept_nativethreads[sig]) { sigsend_to_ruby_thread(sig); return; } #endif #if !defined(BSD_SIGNAL) && !defined(POSIX_SIGNAL) if (rb_trap_accept_nativethreads[sig]) { ruby_nativethread_signal(sig, sighandler); } else { ruby_signal(sig, sighandler); } #endif if (trap_list[sig].cmd == 0 && ATOMIC_TEST(rb_trap_immediate)) { IN_MAIN_CONTEXT(signal_exec, sig); ATOMIC_SET(rb_trap_immediate, 1); } else { ATOMIC_INC(rb_trap_pending); ATOMIC_INC(trap_pending_list[sig]); #ifdef _WIN32 rb_w32_interrupted(); #endif } } #include #ifdef HAVE_STDARG_PROTOTYPES #include #define va_init_list(a,b) va_start(a,b) #else #include #define va_init_list(a,b) va_start(a) #endif void #ifdef HAVE_STDARG_PROTOTYPES sig_printf(const char *fmt, ...) #else sig_printf(fmt, va_alist) const char *fmt; va_dcl #endif { char buf[BUFSIZ]; va_list args; FILE *out = stderr; va_init_list(args, fmt); vfprintf(out, fmt, args); va_end(args); fprintf(out, "\n"); } static void dump_machine_state(uc) ucontext_t *uc; { const char *dump64 = " ----------------- Register state dump ----------------------\n" "rax = 0x%.16x rbx = 0x%.16x rcx = 0x%.16x rdx = 0x%.16x\n" "rdi = 0x%.16x rsi = 0x%.16x rbp = 0x%.16x rsp = 0x%.16x\n" "r8 = 0x%.16x r9 = 0x%.16x r10 = 0x%.16x r11 = 0x%.16x\n" "r12 = 0x%.16x r13 = 0x%.16x r14 = 0x%.16x r15 = 0x%.16x\n" "rip = 0x%.16x rflags = 0x%.16x cs = 0x%.16x fs = 0x%.16x\n" "gs = 0x%.16x"; const char *dump32 = " ----------------- Register state dump -------------------\n" "eax = 0x%.8x ebx = 0x%.8x ecx = 0x%.8x edx = 0x%.8x\n" "edi = 0x%.8x esi = 0x%.8x ebp = 0x%.8x esp = 0x%.8x\n" "ss = 0x%.8x eflags = 0x%.8x eip = 0x%.8x cs = 0x%.8x\n" "ds = 0x%.8x es = 0x%.8x fs = 0x%.8x gs = 0x%.8x\n"; #if defined(__LP64__) && defined(__APPLE__) sig_printf(dump64, uc->uc_mcontext->__ss.__rax, uc->uc_mcontext->__ss.__rbx, uc->uc_mcontext->__ss.__rcx, uc->uc_mcontext->__ss.__rdx, uc->uc_mcontext->__ss.__rdi, uc->uc_mcontext->__ss.__rsi, uc->uc_mcontext->__ss.__rbp, uc->uc_mcontext->__ss.__rsp, uc->uc_mcontext->__ss.__r8, uc->uc_mcontext->__ss.__r9, uc->uc_mcontext->__ss.__r10, uc->uc_mcontext->__ss.__r11, uc->uc_mcontext->__ss.__r12, uc->uc_mcontext->__ss.__r13, uc->uc_mcontext->__ss.__r14, uc->uc_mcontext->__ss.__r15, uc->uc_mcontext->__ss.__rip, uc->uc_mcontext->__ss.__rflags, uc->uc_mcontext->__ss.__cs, uc->uc_mcontext->__ss.__fs, uc->uc_mcontext->__ss.__gs); #elif !defined(__LP64__) && defined(__APPLE__) sig_printf(dump32, uc->uc_mcontext->__ss.__eax, uc->uc_mcontext->__ss.__ebx, uc->uc_mcontext->__ss.__ecx, uc->uc_mcontext->__ss.__edx, uc->uc_mcontext->__ss.__edi, uc->uc_mcontext->__ss.__esi, uc->uc_mcontext->__ss.__ebp, uc->uc_mcontext->__ss.__esp, uc->uc_mcontext->__ss.__ss, uc->uc_mcontext->__ss.__eflags, uc->uc_mcontext->__ss.__eip, uc->uc_mcontext->__ss.__cs, uc->uc_mcontext->__ss.__ds, uc->uc_mcontext->__ss.__es, uc->uc_mcontext->__ss.__fs, uc->uc_mcontext->__ss.__gs); #elif defined(__x86_64__) && defined(BSD) sig_printf(dump64, uc->uc_mcontext.mc_rax, uc->uc_mcontext.mc_rbx, uc->uc_mcontext.mc_rcx, uc->uc_mcontext.mc_rdx, uc->uc_mcontext.mc_rdi, uc->uc_mcontext.mc_rsi, uc->uc_mcontext.mc_rbp, uc->uc_mcontext.mc_rsp, uc->uc_mcontext.mc_r8, uc->uc_mcontext.mc_r9, uc->uc_mcontext.mc_r10, uc->uc_mcontext.mc_r11, uc->uc_mcontext.mc_r12, uc->uc_mcontext.mc_r13, uc->uc_mcontext.mc_r14, uc->uc_mcontext.mc_r15, uc->uc_mcontext.mc_rip, uc->uc_mcontext.mc_rflags, uc->uc_mcontext.mc_cs, uc->uc_mcontext.mc_fs, uc->uc_mcontext.mc_gs); #elif defined(__i386__) sig_printf(dump32, uc->uc_mcontext.gregs[REG_EAX], uc->uc_mcontext.gregs[REG_EBX], uc->uc_mcontext.gregs[REG_ECX], uc->uc_mcontext.gregs[REG_EDX], uc->uc_mcontext.gregs[REG_EDI], uc->uc_mcontext.gregs[REG_ESI], uc->uc_mcontext.gregs[REG_EBP], uc->uc_mcontext.gregs[REG_ESP], uc->uc_mcontext.gregs[REG_SS], uc->uc_mcontext.gregs[REG_EFL], uc->uc_mcontext.gregs[REG_EIP], uc->uc_mcontext.gregs[REG_EIP], uc->uc_mcontext.gregs[REG_DS], uc->uc_mcontext.gregs[REG_ES], uc->uc_mcontext.gregs[REG_FS], uc->uc_mcontext.gregs[REG_FS]); #elif defined(__x86_64__) sig_printf(dump64, uc->uc_mcontext.gregs[REG_RAX], uc->uc_mcontext.gregs[REG_RBX], uc->uc_mcontext.gregs[REG_RCX], uc->uc_mcontext.gregs[REG_RDX], uc->uc_mcontext.gregs[REG_RDI], uc->uc_mcontext.gregs[REG_RSI], uc->uc_mcontext.gregs[REG_RBP], uc->uc_mcontext.gregs[REG_RSP], uc->uc_mcontext.gregs[REG_R8], uc->uc_mcontext.gregs[REG_R9], uc->uc_mcontext.gregs[REG_R10], uc->uc_mcontext.gregs[REG_R11], uc->uc_mcontext.gregs[REG_R12], uc->uc_mcontext.gregs[REG_R13], uc->uc_mcontext.gregs[REG_R14], uc->uc_mcontext.gregs[REG_R15], uc->uc_mcontext.gregs[REG_RIP], uc->uc_mcontext.gregs[REG_EFL], uc->uc_mcontext.gregs[REG_CSGSFS]); #else #endif } static int check_guard(caddr_t fault_addr, rb_thread_t th) { if(fault_addr <= (caddr_t)rb_curr_thread->guard && fault_addr >= (caddr_t)rb_curr_thread->stk_ptr) { return 1; } return 0; } #ifdef SIGBUS #ifdef POSIX_SIGNAL static void sigbus _((int, siginfo_t*, void*)); static void sigbus(sig, ip, context) int sig; siginfo_t *ip; void *context; { #if defined(HAVE_NATIVETHREAD) && defined(HAVE_NATIVETHREAD_KILL) if (!is_ruby_native_thread() && !rb_trap_accept_nativethreads[sig]) { sigsend_to_ruby_thread(sig); return; } #endif dump_machine_state(context); if (check_guard((caddr_t)ip->si_addr, rb_curr_thread)) { /* we hit the guard page, print out a warning to help app developers */ rb_bug("Thread stack overflow! Try increasing it!"); } else { rb_bug("Bus Error"); } } #else /* !defined(POSIX_SIGNAL) */ static RETSIGTYPE sigbus _((int)); static RETSIGTYPE sigbus(sig) int sig; { #if defined(HAVE_NATIVETHREAD) && defined(HAVE_NATIVETHREAD_KILL) if (!is_ruby_native_thread() && !rb_trap_accept_nativethreads[sig]) { sigsend_to_ruby_thread(sig); return; } #endif rb_bug("Bus Error"); } #endif #endif #ifdef SIGSEGV #ifdef POSIX_SIGNAL static void sigsegv _((int, siginfo_t*, void*)); static void sigsegv(sig, ip, context) int sig; siginfo_t *ip; void *context; { #if defined(HAVE_NATIVETHREAD) && defined(HAVE_NATIVETHREAD_KILL) if (!is_ruby_native_thread() && !rb_trap_accept_nativethreads[sig]) { sigsend_to_ruby_thread(sig); return; } #endif dump_machine_state(context); if (check_guard((caddr_t)ip->si_addr, rb_curr_thread)) { /* we hit the guard page, print out a warning to help app developers */ rb_bug("Thread stack overflow! Try increasing it!"); } else { rb_bug("Segmentation fault"); } } #else /* !defined(POSIX_SIGNAL) */ static RETSIGTYPE sigsegv _((int)); static RETSIGTYPE sigsegv(sig) int sig; { #if defined(HAVE_NATIVETHREAD) && defined(HAVE_NATIVETHREAD_KILL) if (!is_ruby_native_thread() && !rb_trap_accept_nativethreads[sig]) { sigsend_to_ruby_thread(sig); return; } #endif rb_gc_unstress(); rb_bug("Segmentation fault"); } #endif #endif #ifdef SIGPIPE static RETSIGTYPE sigpipe _((int)); static RETSIGTYPE sigpipe(sig) int sig; { /* do nothing */ } #endif void rb_trap_exit() { #ifndef MACOS_UNUSE_SIGNAL if (trap_list[0].cmd) { VALUE trap_exit = trap_list[0].cmd; trap_list[0].cmd = 0; rb_eval_cmd(trap_exit, rb_ary_new3(1, INT2FIX(0)), trap_list[0].safe); } #endif } void rb_trap_exec() { #ifndef MACOS_UNUSE_SIGNAL int i; for (i=0; icmd; if (NIL_P(command)) { func = SIG_IGN; } else if (TYPE(command) == T_STRING) { SafeStringValue(command); /* taint check */ if (RSTRING(command)->len == 0) { func = SIG_IGN; } else if (RSTRING(command)->len == 7) { if (strncmp(RSTRING(command)->ptr, "SIG_IGN", 7) == 0) { func = SIG_IGN; } else if (strncmp(RSTRING(command)->ptr, "SIG_DFL", 7) == 0) { func = SIG_DFL; } else if (strncmp(RSTRING(command)->ptr, "DEFAULT", 7) == 0) { func = SIG_DFL; } } else if (RSTRING(command)->len == 6) { if (strncmp(RSTRING(command)->ptr, "IGNORE", 6) == 0) { func = SIG_IGN; } } else if (RSTRING(command)->len == 4) { if (strncmp(RSTRING(command)->ptr, "EXIT", 4) == 0) { func = sigexit; } } } if (func == SIG_IGN || func == SIG_DFL) { command = 0; } switch (TYPE(arg->sig)) { case T_FIXNUM: sig = FIX2INT(arg->sig); break; case T_SYMBOL: s = rb_id2name(SYM2ID(arg->sig)); if (!s) rb_raise(rb_eArgError, "bad signal"); goto str_signal; case T_STRING: s = RSTRING(arg->sig)->ptr; str_signal: if (strncmp("SIG", s, 3) == 0) s += 3; sig = signm2signo(s); if (sig == 0 && strcmp(s, "EXIT") != 0) rb_raise(rb_eArgError, "unsupported signal SIG%s", s); } if (sig < 0 || sig >= NSIG) { rb_raise(rb_eArgError, "invalid signal number (%d)", sig); } #if defined(HAVE_SETITIMER) if (sig == SIGVTALRM) { rb_raise(rb_eArgError, "SIGVTALRM reserved for Thread; can't set handler"); } #endif if (func == SIG_DFL) { switch (sig) { case SIGINT: #ifdef SIGHUP case SIGHUP: #endif #ifdef SIGQUIT case SIGQUIT: #endif #ifdef SIGTERM case SIGTERM: #endif #ifdef SIGALRM case SIGALRM: #endif #ifdef SIGUSR1 case SIGUSR1: #endif #ifdef SIGUSR2 case SIGUSR2: #endif func = sighandler; break; #ifdef SIGBUS case SIGBUS: func = sigbus; break; #endif #ifdef SIGSEGV case SIGSEGV: func = sigsegv; break; #endif #ifdef SIGPIPE case SIGPIPE: func = sigpipe; break; #endif } } oldfunc = ruby_signal(sig, func); oldcmd = trap_list[sig].cmd; if (!oldcmd) { if (oldfunc == SIG_IGN) oldcmd = rb_str_new2("IGNORE"); else if (oldfunc == sighandler) oldcmd = rb_str_new2("DEFAULT"); else oldcmd = Qnil; } trap_list[sig].cmd = command; trap_list[sig].safe = ruby_safe_level; /* enable at least specified signal. */ #if USE_TRAP_MASK #ifdef HAVE_SIGPROCMASK sigdelset(&arg->mask, sig); #else arg->mask &= ~sigmask(sig); #endif #endif return oldcmd; } #if USE_TRAP_MASK static VALUE trap_ensure(arg) struct trap_arg *arg; { /* enable interrupt */ #ifdef HAVE_SIGPROCMASK sigprocmask(SIG_SETMASK, &arg->mask, NULL); #else sigsetmask(arg->mask); #endif trap_last_mask = arg->mask; return 0; } #endif void rb_trap_restore_mask() { #if USE_TRAP_MASK # ifdef HAVE_SIGPROCMASK sigprocmask(SIG_SETMASK, &trap_last_mask, NULL); # else sigsetmask(trap_last_mask); # endif #endif } /* * call-seq: * Signal.trap( signal, proc ) => obj * Signal.trap( signal ) {| | block } => obj * * Specifies the handling of signals. The first parameter is a signal * name (a string such as ``SIGALRM'', ``SIGUSR1'', and so on) or a * signal number. The characters ``SIG'' may be omitted from the * signal name. The command or block specifies code to be run when the * signal is raised. If the command is the string ``IGNORE'' or * ``SIG_IGN'', the signal will be ignored. If the command is * ``DEFAULT'' or ``SIG_DFL'', the operating system's default handler * will be invoked. If the command is ``EXIT'', the script will be * terminated by the signal. Otherwise, the given command or block * will be run. * The special signal name ``EXIT'' or signal number zero will be * invoked just prior to program termination. * trap returns the previous handler for the given signal. * * Signal.trap(0, proc { puts "Terminating: #{$$}" }) * Signal.trap("CLD") { puts "Child died" } * fork && Process.wait * * produces: * Terminating: 27461 * Child died * Terminating: 27460 */ static VALUE sig_trap(argc, argv) int argc; VALUE *argv; { struct trap_arg arg; rb_secure(2); if (argc == 0 || argc > 2) { rb_raise(rb_eArgError, "wrong number of arguments -- trap(sig, cmd)/trap(sig){...}"); } arg.sig = argv[0]; if (argc == 1) { arg.cmd = rb_block_proc(); } else if (argc == 2) { arg.cmd = argv[1]; } if (OBJ_TAINTED(arg.cmd)) { rb_raise(rb_eSecurityError, "Insecure: tainted signal trap"); } #if USE_TRAP_MASK /* disable interrupt */ # ifdef HAVE_SIGPROCMASK sigfillset(&arg.mask); sigprocmask(SIG_BLOCK, &arg.mask, &arg.mask); # else arg.mask = sigblock(~0); # endif return rb_ensure(trap, (VALUE)&arg, trap_ensure, (VALUE)&arg); #else return trap(&arg); #endif } /* * call-seq: * Signal.list => a_hash * * Returns a list of signal names mapped to the corresponding * underlying signal numbers. * * Signal.list #=> {"ABRT"=>6, "ALRM"=>14, "BUS"=>7, "CHLD"=>17, "CLD"=>17, "CONT"=>18, "FPE"=>8, "HUP"=>1, "ILL"=>4, "INT"=>2, "IO"=>29, "IOT"=>6, "KILL"=>9, "PIPE"=>13, "POLL"=>29, "PROF"=>27, "PWR"=>30, "QUIT"=>3, "SEGV"=>11, "STOP"=>19, "SYS"=>31, "TERM"=>15, "TRAP"=>5, "TSTP"=>20, "TTIN"=>21, "TTOU"=>22, "URG"=>23, "USR1"=>10, "USR2"=>12, "VTALRM"=>26, "WINCH"=>28, "XCPU"=>24, "XFSZ"=>25} */ static VALUE sig_list() { VALUE h = rb_hash_new(); struct signals *sigs; for (sigs = siglist; sigs->signm; sigs++) { rb_hash_aset(h, rb_str_new2(sigs->signm), INT2FIX(sigs->signo)); } return h; } static void create_sigstack() { stack_t ss; ss.ss_size = SIGSTKSZ; ss.ss_sp = malloc(ss.ss_size); ss.ss_flags = 0; if (sigaltstack(&ss, NULL) < 0) { free(ss.ss_sp); fprintf(stderr, "Couldn't create signal stack! Error %d: %s\n", errno, strerror(errno)); exit(1); } } static void install_sighandler(signum, handler) int signum; sighandler_t handler; { sighandler_t old; old = ruby_signal(signum, handler); if (old != SIG_DFL) { ruby_signal(signum, old); } } #if 0 /* * If you write a handler which works on any native thread * (even if the thread is NOT a ruby's one), please enable * this function and use it to install the handler, instead * of `install_sighandler()'. */ #ifdef HAVE_NATIVETHREAD static void install_nativethread_sighandler(signum, handler) int signum; sighandler_t handler; { sighandler_t old; int old_st; old_st = rb_trap_accept_nativethreads[signum]; old = ruby_nativethread_signal(signum, handler); if (old != SIG_DFL) { if (old_st) { ruby_nativethread_signal(signum, old); } else { ruby_signal(signum, old); } } } #endif #endif #if defined(SIGCLD) || defined(SIGCHLD) static void init_sigchld(sig) int sig; { sighandler_t oldfunc; #if USE_TRAP_MASK # ifdef HAVE_SIGPROCMASK sigset_t mask; # else int mask; # endif #endif #if USE_TRAP_MASK /* disable interrupt */ # ifdef HAVE_SIGPROCMASK sigfillset(&mask); sigprocmask(SIG_BLOCK, &mask, &mask); # else mask = sigblock(~0); # endif #endif oldfunc = ruby_signal(sig, SIG_DFL); if (oldfunc != SIG_DFL && oldfunc != SIG_IGN) { ruby_signal(sig, oldfunc); } else { trap_list[sig].cmd = 0; } #if USE_TRAP_MASK #ifdef HAVE_SIGPROCMASK sigdelset(&mask, sig); sigprocmask(SIG_SETMASK, &mask, NULL); #else mask &= ~sigmask(sig); sigsetmask(mask); #endif trap_last_mask = mask; #endif } #endif /* * Many operating systems allow signals to be sent to running * processes. Some signals have a defined effect on the process, while * others may be trapped at the code level and acted upon. For * example, your process may trap the USR1 signal and use it to toggle * debugging, and may use TERM to initiate a controlled shutdown. * * pid = fork do * Signal.trap("USR1") do * $debug = !$debug * puts "Debug now: #$debug" * end * Signal.trap("TERM") do * puts "Terminating..." * shutdown() * end * # . . . do some work . . . * end * * Process.detach(pid) * * # Controlling program: * Process.kill("USR1", pid) * # ... * Process.kill("USR1", pid) * # ... * Process.kill("TERM", pid) * * produces: * Debug now: true * Debug now: false * Terminating... * * The list of available signal names and their interpretation is * system dependent. Signal delivery semantics may also vary between * systems; in particular signal delivery may not always be reliable. */ void Init_signal() { #ifndef MACOS_UNUSE_SIGNAL VALUE mSignal = rb_define_module("Signal"); rb_define_global_function("trap", sig_trap, -1); rb_define_module_function(mSignal, "trap", sig_trap, -1); rb_define_module_function(mSignal, "list", sig_list, 0); rb_define_method(rb_eSignal, "initialize", esignal_init, -1); rb_attr(rb_eSignal, rb_intern("signo"), 1, 0, 0); rb_alias(rb_eSignal, rb_intern("signm"), rb_intern("message")); rb_define_method(rb_eInterrupt, "initialize", interrupt_init, -1); create_sigstack(); install_sighandler(SIGINT, sighandler); #ifdef SIGHUP install_sighandler(SIGHUP, sighandler); #endif #ifdef SIGQUIT install_sighandler(SIGQUIT, sighandler); #endif #ifdef SIGTERM install_sighandler(SIGTERM, sighandler); #endif #ifdef SIGALRM install_sighandler(SIGALRM, sighandler); #endif #ifdef SIGUSR1 install_sighandler(SIGUSR1, sighandler); #endif #ifdef SIGUSR2 install_sighandler(SIGUSR2, sighandler); #endif #ifdef SIGBUS install_sighandler(SIGBUS, sigbus); #endif #ifdef SIGSEGV install_sighandler(SIGSEGV, sigsegv); #endif #ifdef SIGPIPE install_sighandler(SIGPIPE, sigpipe); #endif #if defined(SIGCLD) init_sigchld(SIGCLD); #elif defined(SIGCHLD) init_sigchld(SIGCHLD); #endif #endif /* MACOS_UNUSE_SIGNAL */ } ================================================ FILE: sprintf.c ================================================ /********************************************************************** sprintf.c - $Author$ $Date$ created at: Fri Oct 15 10:39:26 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto Copyright (C) 2000 Network Applied Communication Laboratory, Inc. Copyright (C) 2000 Information-technology Promotion Agency, Japan **********************************************************************/ #include "ruby.h" #include "re.h" #include #include #define BIT_DIGITS(N) (((N)*146)/485 + 1) /* log2(10) =~ 146/485 */ #define BITSPERDIG (SIZEOF_BDIGITS*CHAR_BIT) #define EXTENDSIGN(n, l) (((~0 << (n)) >> (((n)*(l)) % BITSPERDIG)) & ~(~0 << (n))) static void fmt_setup _((char*,int,int,int,int)); static char* remove_sign_bits(str, base) char *str; int base; { char *s, *t; s = t = str; if (base == 16) { while (*t == 'f') { t++; } } else if (base == 8) { *t |= EXTENDSIGN(3, strlen(t)); while (*t == '7') { t++; } } else if (base == 2) { while (*t == '1') { t++; } } if (t > s) { while (*t) *s++ = *t++; *s = '\0'; } return str; } static char sign_bits(base, p) int base; const char *p; { char c = '.'; switch (base) { case 16: if (*p == 'X') c = 'F'; else c = 'f'; break; case 8: c = '7'; break; case 2: c = '1'; break; } return c; } #define FNONE 0 #define FSHARP 1 #define FMINUS 2 #define FPLUS 4 #define FZERO 8 #define FSPACE 16 #define FWIDTH 32 #define FPREC 64 #define FPREC0 128 #define CHECK(l) do {\ while (blen + (l) >= bsiz) {\ bsiz*=2;\ }\ rb_str_resize(result, bsiz);\ buf = RSTRING(result)->ptr;\ } while (0) #define PUSH(s, l) do { \ CHECK(l);\ memcpy(&buf[blen], s, l);\ blen += (l);\ } while (0) #define GETARG() (nextvalue != Qundef ? nextvalue : \ posarg < 0 ? \ (rb_raise(rb_eArgError, "unnumbered(%d) mixed with numbered", nextarg), 0) : \ (posarg = nextarg++, GETNTHARG(posarg))) #define GETPOSARG(n) (posarg > 0 ? \ (rb_raise(rb_eArgError, "numbered(%d) after unnumbered(%d)", n, posarg), 0) : \ ((n < 1) ? (rb_raise(rb_eArgError, "invalid index - %d$", n), 0) : \ (posarg = -1, GETNTHARG(n)))) #define GETNTHARG(nth) \ ((nth >= argc) ? (rb_raise(rb_eArgError, "too few arguments"), 0) : argv[nth]) #define GETNUM(n, val) \ for (; p < end && ISDIGIT(*p); p++) { \ int next_n = 10 * n + (*p - '0'); \ if (next_n / 10 != n) {\ rb_raise(rb_eArgError, #val " too big"); \ } \ n = next_n; \ } \ if (p >= end) { \ rb_raise(rb_eArgError, "malformed format string - %%*[0-9]"); \ } #define GETASTER(val) do { \ t = p++; \ n = 0; \ GETNUM(n, val); \ if (*p == '$') { \ tmp = GETPOSARG(n); \ } \ else { \ tmp = GETARG(); \ p = t; \ } \ val = NUM2INT(tmp); \ } while (0) /* * call-seq: * format(format_string [, arguments...] ) => string * sprintf(format_string [, arguments...] ) => string * * Returns the string resulting from applying format_string to * any additional arguments. Within the format string, any characters * other than format sequences are copied to the result. A format * sequence consists of a percent sign, followed by optional flags, * width, and precision indicators, then terminated with a field type * character. The field type controls how the corresponding * sprintf argument is to be interpreted, while the flags * modify that interpretation. The field type characters are listed * in the table at the end of this section. The flag characters are: * * Flag | Applies to | Meaning * ---------+--------------+----------------------------------------- * space | bdeEfgGiouxX | Leave a space at the start of * | | positive numbers. * ---------+--------------+----------------------------------------- * (digit)$ | all | Specifies the absolute argument number * | | for this field. Absolute and relative * | | argument numbers cannot be mixed in a * | | sprintf string. * ---------+--------------+----------------------------------------- * # | beEfgGoxX | Use an alternative format. For the * | | conversions `o', `x', `X', and `b', * | | prefix the result with ``0'', ``0x'', ``0X'', * | | and ``0b'', respectively. For `e', * | | `E', `f', `g', and 'G', force a decimal * | | point to be added, even if no digits follow. * | | For `g' and 'G', do not remove trailing zeros. * ---------+--------------+----------------------------------------- * + | bdeEfgGiouxX | Add a leading plus sign to positive numbers. * ---------+--------------+----------------------------------------- * - | all | Left-justify the result of this conversion. * ---------+--------------+----------------------------------------- * 0 (zero) | bdeEfgGiouxX | Pad with zeros, not spaces. * ---------+--------------+----------------------------------------- * * | all | Use the next argument as the field width. * | | If negative, left-justify the result. If the * | | asterisk is followed by a number and a dollar * | | sign, use the indicated argument as the width. * * * The field width is an optional integer, followed optionally by a * period and a precision. The width specifies the minimum number of * characters that will be written to the result for this field. For * numeric fields, the precision controls the number of decimal places * displayed. For string fields, the precision determines the maximum * number of characters to be copied from the string. (Thus, the format * sequence %10.10s will always contribute exactly ten * characters to the result.) * * The field types are: * * Field | Conversion * ------+-------------------------------------------------------------- * b | Convert argument as a binary number. * c | Argument is the numeric code for a single character. * d | Convert argument as a decimal number. * E | Equivalent to `e', but uses an uppercase E to indicate * | the exponent. * e | Convert floating point argument into exponential notation * | with one digit before the decimal point. The precision * | determines the number of fractional digits (defaulting to six). * f | Convert floating point argument as [-]ddd.ddd, * | where the precision determines the number of digits after * | the decimal point. * G | Equivalent to `g', but use an uppercase `E' in exponent form. * g | Convert a floating point number using exponential form * | if the exponent is less than -4 or greater than or * | equal to the precision, or in d.dddd form otherwise. * i | Identical to `d'. * o | Convert argument as an octal number. * p | The valuing of argument.inspect. * s | Argument is a string to be substituted. If the format * | sequence contains a precision, at most that many characters * | will be copied. * u | Treat argument as an unsigned decimal number. Negative integers * | are displayed as a 32 bit two's complement plus one for the * | underlying architecture; that is, 2 ** 32 + n. However, since * | Ruby has no inherent limit on bits used to represent the * | integer, this value is preceded by two dots (..) in order to * | indicate a infinite number of leading sign bits. * X | Convert argument as a hexadecimal number using uppercase * | letters. Negative numbers will be displayed with two * | leading periods (representing an infinite string of * | leading 'FF's. * x | Convert argument as a hexadecimal number. * | Negative numbers will be displayed with two * | leading periods (representing an infinite string of * | leading 'ff's. * * Examples: * * sprintf("%d %04x", 123, 123) #=> "123 007b" * sprintf("%08b '%4s'", 123, 123) #=> "01111011 ' 123'" * sprintf("%1$*2$s %2$d %1$s", "hello", 8) #=> " hello 8 hello" * sprintf("%1$*2$s %2$d", "hello", -8) #=> "hello -8" * sprintf("%+g:% g:%-g", 1.23, 1.23, 1.23) #=> "+1.23: 1.23:1.23" * sprintf("%u", -123) #=> "..4294967173" */ VALUE rb_f_sprintf(argc, argv) int argc; VALUE *argv; { return rb_str_format(argc - 1, argv + 1, GETNTHARG(0)); } VALUE rb_str_format(argc, argv, fmt) int argc; VALUE *argv; VALUE fmt; { const char *p, *end; char *buf; int blen, bsiz; VALUE result; int width, prec, flags = FNONE; int nextarg = 1; int posarg = 0; int tainted = 0; VALUE nextvalue; VALUE tmp; VALUE str; #define CHECK_FOR_WIDTH(f) \ if ((f) & FWIDTH) { \ rb_raise(rb_eArgError, "width given twice"); \ } \ if ((f) & FPREC0) { \ rb_raise(rb_eArgError, "width after precision"); \ } #define CHECK_FOR_FLAGS(f) \ if ((f) & FWIDTH) { \ rb_raise(rb_eArgError, "flag after width"); \ } \ if ((f) & FPREC0) { \ rb_raise(rb_eArgError, "flag after precision"); \ } ++argc; --argv; if (OBJ_TAINTED(fmt)) tainted = 1; StringValue(fmt); fmt = rb_str_new4(fmt); p = RSTRING(fmt)->ptr; end = p + RSTRING(fmt)->len; blen = 0; bsiz = 120; result = rb_str_buf_new(bsiz); buf = RSTRING(result)->ptr; for (; p < end; p++) { const char *t; int n; for (t = p; t < end && *t != '%'; t++) ; PUSH(p, t - p); if (t >= end) { /* end of fmt string */ goto sprint_exit; } p = t + 1; /* skip `%' */ width = prec = -1; nextvalue = Qundef; retry: switch (*p) { default: if (ISPRINT(*p)) rb_raise(rb_eArgError, "malformed format string - %%%c", *p); else rb_raise(rb_eArgError, "malformed format string"); break; case ' ': CHECK_FOR_FLAGS(flags); flags |= FSPACE; p++; goto retry; case '#': CHECK_FOR_FLAGS(flags); flags |= FSHARP; p++; goto retry; case '+': CHECK_FOR_FLAGS(flags); flags |= FPLUS; p++; goto retry; case '-': CHECK_FOR_FLAGS(flags); flags |= FMINUS; p++; goto retry; case '0': CHECK_FOR_FLAGS(flags); flags |= FZERO; p++; goto retry; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n = 0; GETNUM(n, width); if (*p == '$') { if (nextvalue != Qundef) { rb_raise(rb_eArgError, "value given twice - %d$", n); } nextvalue = GETPOSARG(n); p++; goto retry; } CHECK_FOR_WIDTH(flags); width = n; flags |= FWIDTH; goto retry; case '*': CHECK_FOR_WIDTH(flags); flags |= FWIDTH; GETASTER(width); if (width < 0) { flags |= FMINUS; width = -width; } p++; goto retry; case '.': if (flags & FPREC0) { rb_raise(rb_eArgError, "precision given twice"); } flags |= FPREC|FPREC0; prec = 0; p++; if (*p == '*') { GETASTER(prec); if (prec < 0) { /* ignore negative precision */ flags &= ~FPREC; } p++; goto retry; } GETNUM(prec, precision); goto retry; case '\n': case '\0': p--; case '%': if (flags != FNONE) { rb_raise(rb_eArgError, "illegal format character - %%"); } PUSH("%", 1); break; case 'c': { VALUE val = GETARG(); char c; if (!(flags & FMINUS)) while (--width > 0) PUSH(" ", 1); c = NUM2INT(val) & 0xff; PUSH(&c, 1); while (--width > 0) PUSH(" ", 1); } break; case 's': case 'p': { VALUE arg = GETARG(); long len; if (*p == 'p') arg = rb_inspect(arg); str = rb_obj_as_string(arg); if (OBJ_TAINTED(str)) tainted = 1; len = RSTRING(str)->len; if (flags&FPREC) { if (prec < len) { len = prec; } } /* need to adjust multi-byte string pos */ if (flags&FWIDTH) { if (width > len) { CHECK(width); width -= len; if (!(flags&FMINUS)) { while (width--) { buf[blen++] = ' '; } } memcpy(&buf[blen], RSTRING_PTR(str), len); blen += len; if (flags&FMINUS) { while (width--) { buf[blen++] = ' '; } } break; } } PUSH(RSTRING(str)->ptr, len); } break; case 'd': case 'i': case 'o': case 'x': case 'X': case 'b': case 'B': case 'u': { volatile VALUE val = GETARG(); char fbuf[32], nbuf[64], *s, *t; const char *prefix = 0; int sign = 0; char sc = 0; long v = 0; int base, bignum = 0; int len, pos; volatile VALUE tmp; volatile VALUE tmp1; switch (*p) { case 'd': case 'i': sign = 1; break; case 'o': case 'x': case 'X': case 'b': case 'B': case 'u': default: if (flags&(FPLUS|FSPACE)) sign = 1; break; } if (flags & FSHARP) { switch (*p) { case 'o': prefix = "0"; break; case 'x': prefix = "0x"; break; case 'X': prefix = "0X"; break; case 'b': prefix = "0b"; break; case 'B': prefix = "0B"; break; } if (prefix) { width -= strlen(prefix); } } bin_retry: switch (TYPE(val)) { case T_FLOAT: val = rb_dbl2big(RFLOAT(val)->value); if (FIXNUM_P(val)) goto bin_retry; bignum = 1; break; case T_STRING: val = rb_str_to_inum(val, 0, Qtrue); goto bin_retry; case T_BIGNUM: bignum = 1; break; case T_FIXNUM: v = FIX2LONG(val); break; default: val = rb_Integer(val); goto bin_retry; } switch (*p) { case 'o': base = 8; break; case 'x': case 'X': base = 16; break; case 'b': case 'B': base = 2; break; case 'u': case 'd': case 'i': default: base = 10; break; } if (!bignum) { if (base == 2) { val = rb_int2big(v); goto bin_retry; } if (sign) { char c = *p; if (c == 'i') c = 'd'; /* %d and %i are identical */ if (v < 0) { v = -v; sc = '-'; width--; } else if (flags & FPLUS) { sc = '+'; width--; } else if (flags & FSPACE) { sc = ' '; width--; } sprintf(fbuf, "%%l%c", c); sprintf(nbuf, fbuf, v); s = nbuf; goto format_integer; } s = nbuf; if (v < 0) { if (base == 10) { rb_warning("negative number for %%u specifier"); } if (!(flags&(FPREC|FZERO))) { strcpy(s, ".."); s += 2; } } sprintf(fbuf, "%%l%c", *p == 'X' ? 'x' : *p); sprintf(s, fbuf, v); if (v < 0) { char d = 0; remove_sign_bits(s, base); switch (base) { case 16: d = 'f'; break; case 8: d = '7'; break; } if (d && *s != d) { memmove(s+1, s, strlen(s)+1); *s = d; } } s = nbuf; goto format_integer; } if (sign) { tmp = rb_big2str(val, base); s = RSTRING(tmp)->ptr; if (s[0] == '-') { s++; sc = '-'; width--; } else if (flags & FPLUS) { sc = '+'; width--; } else if (flags & FSPACE) { sc = ' '; width--; } goto format_integer; } if (!RBIGNUM(val)->sign) { val = rb_big_clone(val); rb_big_2comp(val); } tmp1 = tmp = rb_big2str0(val, base, RBIGNUM(val)->sign); s = RSTRING(tmp)->ptr; if (*s == '-') { if (base == 10) { rb_warning("negative number for %%u specifier"); } remove_sign_bits(++s, base); tmp = rb_str_new(0, 3+strlen(s)); t = RSTRING(tmp)->ptr; if (!(flags&(FPREC|FZERO))) { strcpy(t, ".."); t += 2; } switch (base) { case 16: if (s[0] != 'f') strcpy(t++, "f"); break; case 8: if (s[0] != '7') strcpy(t++, "7"); break; case 2: if (s[0] != '1') strcpy(t++, "1"); break; } strcpy(t, s); bignum = 2; } s = RSTRING(tmp)->ptr; format_integer: pos = -1; len = strlen(s); if (*p == 'X') { char *pp = s; while (*pp) { *pp = toupper(*pp); pp++; } } if ((flags&(FZERO|FPREC)) == FZERO) { prec = width; width = 0; } else { if (prec < len) prec = len; width -= prec; } if (!(flags&FMINUS)) { CHECK(width); while (width-- > 0) { buf[blen++] = ' '; } } if (sc) PUSH(&sc, 1); if (prefix) { int plen = strlen(prefix); PUSH(prefix, plen); } CHECK(prec - len); if (!bignum && v < 0) { char c = sign_bits(base, p); while (len < prec--) { buf[blen++] = c; } } else { char c; if (!sign && bignum && !RBIGNUM(val)->sign) c = sign_bits(base, p); else c = '0'; while (len < prec--) { buf[blen++] = c; } } PUSH(s, len); CHECK(width); while (width-- > 0) { buf[blen++] = ' '; } } break; case 'f': case 'g': case 'G': case 'e': case 'E': { VALUE val = GETARG(); double fval; int i, need = 6; char fbuf[32]; fval = RFLOAT(rb_Float(val))->value; #if defined(_WIN32) && !defined(__BORLANDC__) if (isnan(fval) || isinf(fval)) { const char *expr; if (isnan(fval)) { expr = "NaN"; } else { expr = "Inf"; } need = strlen(expr); if ((!isnan(fval) && fval < 0.0) || (flags & FPLUS)) need++; else if (flags & FSPACE) need++; if ((flags & FWIDTH) && need < width) need = width; CHECK(need); sprintf(&buf[blen], "%*s", need, ""); if (flags & FMINUS) { if (!isnan(fval) && fval < 0.0) buf[blen++] = '-'; else if (flags & FPLUS) buf[blen++] = '+'; else if (flags & FSPACE) blen++; strncpy(&buf[blen], expr, strlen(expr)); } else if (flags & FZERO) { if (!isnan(fval) && fval < 0.0) { buf[blen++] = '-'; need--; } else if (flags & FPLUS) { buf[blen++] = '+'; need--; } else if (flags & FSPACE) { blen++; need--; } while (need-- - strlen(expr) > 0) { buf[blen++] = '0'; } strncpy(&buf[blen], expr, strlen(expr)); } else { if (!isnan(fval) && fval < 0.0) buf[blen + need - strlen(expr) - 1] = '-'; else if (flags & FPLUS) buf[blen + need - strlen(expr) - 1] = '+'; strncpy(&buf[blen + need - strlen(expr)], expr, strlen(expr)); } blen += strlen(&buf[blen]); break; } #endif /* defined(_WIN32) && !defined(__BORLANDC__) */ fmt_setup(fbuf, *p, flags, width, prec); need = 0; if (*p != 'e' && *p != 'E') { i = INT_MIN; frexp(fval, &i); if (i > 0) need = BIT_DIGITS(i); } need += (flags&FPREC) ? prec : 6; if ((flags&FWIDTH) && need < width) need = width; need += 20; CHECK(need); sprintf(&buf[blen], fbuf, fval); blen += strlen(&buf[blen]); } break; } flags = FNONE; } sprint_exit: /* XXX - We cannot validiate the number of arguments if (digit)$ style used. */ if (posarg >= 0 && nextarg < argc) { const char *mesg = "too many arguments for format string"; if (RTEST(ruby_debug)) rb_raise(rb_eArgError, mesg); if (RTEST(ruby_verbose)) rb_warn(mesg); } rb_str_resize(result, blen); if (tainted) OBJ_TAINT(result); return result; } static void fmt_setup(buf, c, flags, width, prec) char *buf; int c; int flags, width, prec; { *buf++ = '%'; if (flags & FSHARP) *buf++ = '#'; if (flags & FPLUS) *buf++ = '+'; if (flags & FMINUS) *buf++ = '-'; if (flags & FZERO) *buf++ = '0'; if (flags & FSPACE) *buf++ = ' '; if (flags & FWIDTH) { sprintf(buf, "%d", width); buf += strlen(buf); } if (flags & FPREC) { sprintf(buf, ".%d", prec); buf += strlen(buf); } *buf++ = c; *buf = '\0'; } ================================================ FILE: st.c ================================================ /* This is a public domain general purpose hash table package written by Peter Moore @ UCB. */ /* static char sccsid[] = "@(#) st.c 5.1 89/12/14 Crucible"; */ #include "config.h" #include "defines.h" #include #ifdef HAVE_STDLIB_H #include #endif #include #include "st.h" typedef struct st_table_entry st_table_entry; struct st_table_entry { unsigned int hash; st_data_t key; st_data_t record; st_table_entry *next; }; #define ST_DEFAULT_MAX_DENSITY 5 #define ST_DEFAULT_INIT_TABLE_SIZE 11 /* * DEFAULT_MAX_DENSITY is the default for the largest we allow the * average number of items per bin before increasing the number of * bins * * DEFAULT_INIT_TABLE_SIZE is the default for the number of bins * allocated initially * */ static int numcmp(long, long); static int numhash(long); static struct st_hash_type type_numhash = { numcmp, numhash, }; /* extern int strcmp(const char *, const char *); */ static struct st_hash_type type_strhash = { strcmp, strhash, }; static void rehash(st_table *); #ifdef RUBY #define malloc xmalloc #define calloc xcalloc #endif #define alloc(type) (type*)malloc((unsigned)sizeof(type)) #define Calloc(n,s) (char*)calloc((n),(s)) #define EQUAL(table,x,y) ((x)==(y) || (*table->type->compare)((x),(y)) == 0) #define do_hash(key,table) (unsigned int)(*(table)->type->hash)((key)) #define do_hash_bin(key,table) (do_hash(key, table)%(table)->num_bins) /* * MINSIZE is the minimum size of a dictionary. */ #define MINSIZE 8 /* Table of prime numbers 2^n+a, 2<=n<=30. */ static long primes[] = { 8 + 3, 16 + 3, 32 + 5, 64 + 3, 128 + 3, 256 + 27, 512 + 9, 1024 + 9, 2048 + 5, 4096 + 3, 8192 + 27, 16384 + 43, 32768 + 3, 65536 + 45, 131072 + 29, 262144 + 3, 524288 + 21, 1048576 + 7, 2097152 + 17, 4194304 + 15, 8388608 + 9, 16777216 + 43, 33554432 + 35, 67108864 + 15, 134217728 + 29, 268435456 + 3, 536870912 + 11, 1073741824 + 85, 0 }; static int new_size(size) int size; { int i; #if 0 for (i=3; i<31; i++) { if ((1< size) return 1< size) return primes[i]; } /* Ran out of polynomials */ return -1; /* should raise exception */ #endif } #ifdef HASH_LOG static int collision = 0; static int init_st = 0; static void stat_col() { FILE *f = fopen("/tmp/col", "w"); fprintf(f, "collision: %d\n", collision); fclose(f); } #endif st_table* st_init_table_with_size(type, size) struct st_hash_type *type; int size; { st_table *tbl; #ifdef HASH_LOG if (init_st == 0) { init_st = 1; atexit(stat_col); } #endif size = new_size(size); /* round up to prime number */ tbl = alloc(st_table); tbl->type = type; tbl->num_entries = 0; tbl->num_bins = size; tbl->bins = (st_table_entry **)Calloc(size, sizeof(st_table_entry*)); return tbl; } st_table* st_init_table(type) struct st_hash_type *type; { return st_init_table_with_size(type, 0); } st_table* st_init_numtable(void) { return st_init_table(&type_numhash); } st_table* st_init_numtable_with_size(size) int size; { return st_init_table_with_size(&type_numhash, size); } st_table* st_init_strtable(void) { return st_init_table(&type_strhash); } st_table* st_init_strtable_with_size(size) int size; { return st_init_table_with_size(&type_strhash, size); } void st_free_table(table) st_table *table; { register st_table_entry *ptr, *next; int i; for(i = 0; i < table->num_bins; i++) { ptr = table->bins[i]; while (ptr != 0) { next = ptr->next; free(ptr); ptr = next; } } free(table->bins); free(table); } #define PTR_NOT_EQUAL(table, ptr, hash_val, key) \ ((ptr) != 0 && (ptr->hash != (hash_val) || !EQUAL((table), (key), (ptr)->key))) #ifdef HASH_LOG #define COLLISION collision++ #else #define COLLISION #endif #define FIND_ENTRY(table, ptr, hash_val, bin_pos) do {\ bin_pos = hash_val%(table)->num_bins;\ ptr = (table)->bins[bin_pos];\ if (PTR_NOT_EQUAL(table, ptr, hash_val, key)) {\ COLLISION;\ while (PTR_NOT_EQUAL(table, ptr->next, hash_val, key)) {\ ptr = ptr->next;\ }\ ptr = ptr->next;\ }\ } while (0) int st_lookup(table, key, value) st_table *table; register st_data_t key; st_data_t *value; { unsigned int hash_val, bin_pos; register st_table_entry *ptr; hash_val = do_hash(key, table); FIND_ENTRY(table, ptr, hash_val, bin_pos); if (ptr == 0) { return 0; } else { if (value != 0) *value = ptr->record; return 1; } } #define ADD_DIRECT(table, key, value, hash_val, bin_pos)\ do {\ st_table_entry *entry;\ if (table->num_entries/(table->num_bins) > ST_DEFAULT_MAX_DENSITY) {\ rehash(table);\ bin_pos = hash_val % table->num_bins;\ }\ \ entry = alloc(st_table_entry);\ \ entry->hash = hash_val;\ entry->key = key;\ entry->record = value;\ entry->next = table->bins[bin_pos];\ table->bins[bin_pos] = entry;\ table->num_entries++;\ } while (0) int st_insert(table, key, value) register st_table *table; register st_data_t key; st_data_t value; { unsigned int hash_val, bin_pos; register st_table_entry *ptr; hash_val = do_hash(key, table); FIND_ENTRY(table, ptr, hash_val, bin_pos); if (ptr == 0) { ADD_DIRECT(table, key, value, hash_val, bin_pos); return 0; } else { ptr->record = value; return 1; } } void st_add_direct(table, key, value) st_table *table; st_data_t key; st_data_t value; { unsigned int hash_val, bin_pos; hash_val = do_hash(key, table); bin_pos = hash_val % table->num_bins; ADD_DIRECT(table, key, value, hash_val, bin_pos); } static void rehash(table) register st_table *table; { register st_table_entry *ptr, *next, **new_bins; int i, old_num_bins = table->num_bins, new_num_bins; unsigned int hash_val; new_num_bins = new_size(old_num_bins+1); new_bins = (st_table_entry**)Calloc(new_num_bins, sizeof(st_table_entry*)); for(i = 0; i < old_num_bins; i++) { ptr = table->bins[i]; while (ptr != 0) { next = ptr->next; hash_val = ptr->hash % new_num_bins; ptr->next = new_bins[hash_val]; new_bins[hash_val] = ptr; ptr = next; } } free(table->bins); table->num_bins = new_num_bins; table->bins = new_bins; } st_table* st_copy(old_table) st_table *old_table; { st_table *new_table; st_table_entry *ptr, *entry; int i, num_bins = old_table->num_bins; new_table = alloc(st_table); if (new_table == 0) { return 0; } *new_table = *old_table; new_table->bins = (st_table_entry**) Calloc((unsigned)num_bins, sizeof(st_table_entry*)); if (new_table->bins == 0) { free(new_table); return 0; } for(i = 0; i < num_bins; i++) { new_table->bins[i] = 0; ptr = old_table->bins[i]; while (ptr != 0) { entry = alloc(st_table_entry); if (entry == 0) { free(new_table->bins); free(new_table); return 0; } *entry = *ptr; entry->next = new_table->bins[i]; new_table->bins[i] = entry; ptr = ptr->next; } } return new_table; } int st_delete(table, key, value) register st_table *table; register st_data_t *key; st_data_t *value; { unsigned int hash_val; st_table_entry *tmp; register st_table_entry *ptr; hash_val = do_hash_bin(*key, table); ptr = table->bins[hash_val]; if (ptr == 0) { if (value != 0) *value = 0; return 0; } if (EQUAL(table, *key, ptr->key)) { table->bins[hash_val] = ptr->next; table->num_entries--; if (value != 0) *value = ptr->record; *key = ptr->key; free(ptr); return 1; } for(; ptr->next != 0; ptr = ptr->next) { if (EQUAL(table, ptr->next->key, *key)) { tmp = ptr->next; ptr->next = ptr->next->next; table->num_entries--; if (value != 0) *value = tmp->record; *key = tmp->key; free(tmp); return 1; } } return 0; } int st_delete_safe(table, key, value, never) register st_table *table; register st_data_t *key; st_data_t *value; st_data_t never; { unsigned int hash_val; register st_table_entry *ptr; hash_val = do_hash_bin(*key, table); ptr = table->bins[hash_val]; if (ptr == 0) { if (value != 0) *value = 0; return 0; } for(; ptr != 0; ptr = ptr->next) { if ((ptr->key != never) && EQUAL(table, ptr->key, *key)) { table->num_entries--; *key = ptr->key; if (value != 0) *value = ptr->record; ptr->key = ptr->record = never; return 1; } } return 0; } static int delete_never(key, value, never) st_data_t key, value, never; { if (value == never) return ST_DELETE; return ST_CONTINUE; } void st_cleanup_safe(table, never) st_table *table; st_data_t never; { int num_entries = table->num_entries; st_foreach(table, delete_never, never); table->num_entries = num_entries; } void st_foreach_map(table, map_key_func, map_value_func) st_table *table; st_data_t (*map_key_func)(); st_data_t (*map_value_func)(); { st_table_entry *ptr; st_data_t new_key; int i; for(i = 0; i < table->num_bins; i++) { for(ptr = table->bins[i]; ptr != 0; ptr = ptr->next) { new_key = (*map_key_func)(ptr->key); if(new_key != ptr->key && table->type->compare(new_key, ptr->key)) { rb_bug("Key replaced with non-equal key"); } ptr->key = new_key; ptr->record = (*map_value_func)(ptr->record); } } } int st_foreach(table, func, arg) st_table *table; int (*func)(); st_data_t arg; { st_table_entry *ptr, *last, *tmp; enum st_retval retval; int i; for(i = 0; i < table->num_bins; i++) { last = 0; for(ptr = table->bins[i]; ptr != 0;) { retval = (*func)(ptr->key, ptr->record, arg); switch (retval) { case ST_CHECK: /* check if hash is modified during iteration */ tmp = 0; if (i < table->num_bins) { for (tmp = table->bins[i]; tmp; tmp=tmp->next) { if (tmp == ptr) break; } } if (!tmp) { /* call func with error notice */ return 1; } /* fall through */ case ST_CONTINUE: last = ptr; ptr = ptr->next; break; case ST_STOP: return 0; case ST_DELETE: tmp = ptr; if (last == 0) { table->bins[i] = ptr->next; } else { last->next = ptr->next; } ptr = ptr->next; free(tmp); table->num_entries--; } } } return 0; } int strhash(string) register const char *string; { register int c; #ifdef HASH_ELFHASH register unsigned int h = 0, g; while ((c = *string++) != '\0') { h = ( h << 4 ) + c; if ( g = h & 0xF0000000 ) h ^= g >> 24; h &= ~g; } return h; #elif defined(HASH_PERL) register int val = 0; while ((c = *string++) != '\0') { val += c; val += (val << 10); val ^= (val >> 6); } val += (val << 3); val ^= (val >> 11); return val + (val << 15); #else register int val = 0; while ((c = *string++) != '\0') { val = val*997 + c; } return val + (val>>5); #endif } static int numcmp(x, y) long x, y; { return x != y; } static int numhash(n) long n; { return n; } ================================================ FILE: st.h ================================================ /* This is a public domain general purpose hash table package written by Peter Moore @ UCB. */ /* @(#) st.h 5.1 89/12/14 */ #ifndef ST_INCLUDED #define ST_INCLUDED #if SIZEOF_LONG == SIZEOF_VOIDP typedef unsigned long st_data_t; #elif SIZEOF_LONG_LONG == SIZEOF_VOIDP typedef unsigned LONG_LONG st_data_t; #else # error ---->> st.c requires sizeof(void*) == sizeof(long) to be compiled. <<--- - #endif #define ST_DATA_T_DEFINED typedef struct st_table st_table; struct st_hash_type { int (*compare)(); int (*hash)(); }; struct st_table { struct st_hash_type *type; int num_bins; int num_entries; struct st_table_entry **bins; }; #define st_is_member(table,key) st_lookup(table,key,(st_data_t *)0) enum st_retval {ST_CONTINUE, ST_STOP, ST_DELETE, ST_CHECK}; #ifndef _ # define _(args) args #endif #ifndef ANYARGS # ifdef __cplusplus # define ANYARGS ... # else # define ANYARGS # endif #endif st_table *st_init_table _((struct st_hash_type *)); st_table *st_init_table_with_size _((struct st_hash_type *, int)); st_table *st_init_numtable _((void)); st_table *st_init_numtable_with_size _((int)); st_table *st_init_strtable _((void)); st_table *st_init_strtable_with_size _((int)); int st_delete _((st_table *, st_data_t *, st_data_t *)); int st_delete_safe _((st_table *, st_data_t *, st_data_t *, st_data_t)); int st_insert _((st_table *, st_data_t, st_data_t)); int st_lookup _((st_table *, st_data_t, st_data_t *)); int st_foreach _((st_table *, int (*)(ANYARGS), st_data_t)); void st_foreach_map _((st_table*, st_data_t (*)(ANYARGS), st_data_t (*)(ANYARGS))); void st_add_direct _((st_table *, st_data_t, st_data_t)); void st_free_table _((st_table *)); void st_cleanup_safe _((st_table *, st_data_t)); st_table *st_copy _((st_table *)); #define ST_NUMCMP ((int (*)()) 0) #define ST_NUMHASH ((int (*)()) -2) #define st_numcmp ST_NUMCMP #define st_numhash ST_NUMHASH int st_strhash(); int strhash(const char *); #endif /* ST_INCLUDED */ ================================================ FILE: string.c ================================================ /********************************************************************** string.c - $Author$ $Date$ created at: Mon Aug 9 17:12:58 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto Copyright (C) 2000 Network Applied Communication Laboratory, Inc. Copyright (C) 2000 Information-technology Promotion Agency, Japan **********************************************************************/ #include "ruby.h" #include "re.h" #define BEG(no) regs->beg[no] #define END(no) regs->end[no] #include #include #ifdef HAVE_UNISTD_H #include #endif VALUE rb_cString; #define STR_TMPLOCK FL_USER1 #define STR_ASSOC FL_USER3 #define STR_NOCAPA (ELTS_SHARED|STR_ASSOC) #define RESIZE_CAPA(str,capacity) do {\ REALLOC_N(RSTRING(str)->ptr, char, (capacity)+1);\ if (!FL_TEST(str, STR_NOCAPA))\ RSTRING(str)->aux.capa = (capacity);\ } while (0) VALUE rb_fs; static inline void str_mod_check(s, p, len) VALUE s; char *p; long len; { if (RSTRING(s)->ptr != p || RSTRING(s)->len != len) { rb_raise(rb_eRuntimeError, "string modified"); } } static inline void str_frozen_check(s) VALUE s; { if (OBJ_FROZEN(s)) { rb_raise(rb_eRuntimeError, "string frozen"); } } static VALUE str_alloc_eden(klass) VALUE klass; { NEWOBJ_EDEN(str, struct RString); OBJSETUP(str, klass, T_STRING); str->ptr = 0; str->len = 0; str->aux.capa = 0; return (VALUE)str; } static VALUE str_alloc_longlife(klass) VALUE klass; { NEWOBJ_LONGLIFE(str, struct RString); OBJSETUP(str, klass, T_STRING); str->ptr = 0; str->len = 0; str->aux.capa = 0; return (VALUE)str; } static VALUE str_alloc(klass) VALUE klass; { if (ruby_in_longlife_context) { return str_alloc_longlife(klass); } else { return str_alloc_eden(klass); } } static VALUE str_new(klass, ptr, len) VALUE klass; const char *ptr; long len; { VALUE str; if (len < 0) { rb_raise(rb_eArgError, "negative string size (or size too big)"); } str = str_alloc(klass); RSTRING(str)->len = len; RSTRING(str)->aux.capa = len; RSTRING(str)->ptr = ALLOC_N(char,len+1); if (ptr) { memcpy(RSTRING(str)->ptr, ptr, len); } RSTRING(str)->ptr[len] = '\0'; return str; } VALUE rb_str_new(ptr, len) const char *ptr; long len; { return str_new(rb_cString, ptr, len); } VALUE rb_str_new2(ptr) const char *ptr; { if (!ptr) { rb_raise(rb_eArgError, "NULL pointer given"); } return rb_str_new(ptr, strlen(ptr)); } VALUE rb_tainted_str_new(ptr, len) const char *ptr; long len; { VALUE str = rb_str_new(ptr, len); OBJ_TAINT(str); return str; } VALUE rb_tainted_str_new2(ptr) const char *ptr; { VALUE str = rb_str_new2(ptr); OBJ_TAINT(str); return str; } static VALUE str_new3(klass, str) VALUE klass, str; { VALUE str2 = str_alloc(klass); RSTRING(str2)->len = RSTRING(str)->len; RSTRING(str2)->ptr = RSTRING(str)->ptr; RSTRING(str2)->aux.shared = str; FL_SET(str2, ELTS_SHARED); return str2; } VALUE rb_str_new3(str) VALUE str; { VALUE str2 = str_new3(rb_obj_class(str), str); OBJ_INFECT(str2, str); return str2; } static VALUE str_new4(klass, str) VALUE klass, str; { VALUE str2 = str_alloc(klass); RSTRING(str2)->len = RSTRING(str)->len; RSTRING(str2)->ptr = RSTRING(str)->ptr; if (FL_TEST(str, ELTS_SHARED)) { FL_SET(str2, ELTS_SHARED); RSTRING(str2)->aux.shared = RSTRING(str)->aux.shared; } else { FL_SET(str, ELTS_SHARED); RSTRING(str)->aux.shared = str2; maybe_add_to_longlife_recent_allocations(str); } return str2; } VALUE rb_str_new4(orig) VALUE orig; { VALUE klass, str; if (OBJ_FROZEN(orig)) return orig; klass = rb_obj_class(orig); if (FL_TEST(orig, ELTS_SHARED) && (str = RSTRING(orig)->aux.shared) && klass == RBASIC(str)->klass) { long ofs; ofs = RSTRING(str)->len - RSTRING(orig)->len; if ((ofs > 0) || (!OBJ_TAINTED(str) && OBJ_TAINTED(orig))) { str = str_new3(klass, str); RSTRING(str)->ptr += ofs; RSTRING(str)->len -= ofs; } } else if (FL_TEST(orig, STR_ASSOC)) { str = str_new(klass, RSTRING(orig)->ptr, RSTRING(orig)->len); } else { str = str_new4(klass, orig); } OBJ_INFECT(str, orig); OBJ_FREEZE(str); return str; } VALUE rb_str_new5(obj, ptr, len) VALUE obj; const char *ptr; long len; { return str_new(rb_obj_class(obj), ptr, len); } #define STR_BUF_MIN_SIZE 128 VALUE rb_str_buf_new(capa) long capa; { VALUE str = str_alloc(rb_cString); if (capa < STR_BUF_MIN_SIZE) { capa = STR_BUF_MIN_SIZE; } RSTRING(str)->ptr = 0; RSTRING(str)->len = 0; RSTRING(str)->aux.capa = capa; RSTRING(str)->ptr = ALLOC_N(char, capa+1); RSTRING(str)->ptr[0] = '\0'; return str; } VALUE rb_str_buf_new2(ptr) const char *ptr; { VALUE str; long len = strlen(ptr); str = rb_str_buf_new(len); rb_str_buf_cat(str, ptr, len); return str; } VALUE rb_str_tmp_new(len) long len; { return str_new(0, 0, len); } VALUE rb_str_to_str(str) VALUE str; { return rb_convert_type(str, T_STRING, "String", "to_str"); } static void rb_str_shared_replace(str, str2) VALUE str, str2; { if (str == str2) return; rb_str_modify(str); if (!FL_TEST(str, ELTS_SHARED)) free(RSTRING(str)->ptr); if (NIL_P(str2)) { RSTRING(str)->ptr = 0; RSTRING(str)->len = 0; RSTRING(str)->aux.capa = 0; FL_UNSET(str, STR_NOCAPA); return; } RSTRING(str)->ptr = RSTRING(str2)->ptr; RSTRING(str)->len = RSTRING(str2)->len; FL_UNSET(str, STR_NOCAPA); if (FL_TEST(str2, STR_NOCAPA)) { FL_SET(str, RBASIC(str2)->flags & STR_NOCAPA); RSTRING(str)->aux.shared = RSTRING(str2)->aux.shared; } else { RSTRING(str)->aux.capa = RSTRING(str2)->aux.capa; } RSTRING(str2)->ptr = 0; /* abandon str2 */ RSTRING(str2)->len = 0; RSTRING(str2)->aux.capa = 0; FL_UNSET(str2, STR_NOCAPA); if (OBJ_TAINTED(str2)) OBJ_TAINT(str); maybe_add_to_longlife_recent_allocations(str); } static ID id_to_s; VALUE rb_obj_as_string(obj) VALUE obj; { VALUE str; if (TYPE(obj) == T_STRING) { return obj; } str = rb_funcall(obj, id_to_s, 0); if (TYPE(str) != T_STRING) return rb_any_to_s(obj); if (OBJ_TAINTED(obj)) OBJ_TAINT(str); return str; } static VALUE rb_str_s_alloc _((VALUE)); static VALUE rb_str_replace _((VALUE, VALUE)); VALUE rb_str_dup(str) VALUE str; { VALUE dup = str_alloc(rb_obj_class(str)); rb_str_replace(dup, str); return dup; } /* * call-seq: * String.new(str="") => new_str * * Returns a new string object containing a copy of str. */ static VALUE rb_str_init(argc, argv, str) int argc; VALUE *argv; VALUE str; { VALUE orig; if (rb_scan_args(argc, argv, "01", &orig) == 1) rb_str_replace(str, orig); return str; } /* * call-seq: * str.length => integer * * Returns the length of str. */ static VALUE rb_str_length(str) VALUE str; { return LONG2NUM(RSTRING(str)->len); } /* * call-seq: * str.empty? => true or false * * Returns true if str has a length of zero. * * "hello".empty? #=> false * "".empty? #=> true */ static VALUE rb_str_empty(str) VALUE str; { if (RSTRING(str)->len == 0) return Qtrue; return Qfalse; } /* * call-seq: * str + other_str => new_str * * Concatenation---Returns a new String containing * other_str concatenated to str. * * "Hello from " + self.to_s #=> "Hello from main" */ VALUE rb_str_plus(str1, str2) VALUE str1, str2; { VALUE str3; StringValue(str2); str3 = rb_str_new(0, RSTRING(str1)->len+RSTRING(str2)->len); memcpy(RSTRING(str3)->ptr, RSTRING(str1)->ptr, RSTRING(str1)->len); memcpy(RSTRING(str3)->ptr + RSTRING(str1)->len, RSTRING(str2)->ptr, RSTRING(str2)->len); RSTRING(str3)->ptr[RSTRING(str3)->len] = '\0'; if (OBJ_TAINTED(str1) || OBJ_TAINTED(str2)) OBJ_TAINT(str3); return str3; } /* * call-seq: * str * integer => new_str * * Copy---Returns a new String containing integer copies of * the receiver. * * "Ho! " * 3 #=> "Ho! Ho! Ho! " */ VALUE rb_str_times(str, times) VALUE str; VALUE times; { VALUE str2; long i, len; len = NUM2LONG(times); if (len < 0) { rb_raise(rb_eArgError, "negative argument"); } if (len && LONG_MAX/len < RSTRING(str)->len) { rb_raise(rb_eArgError, "argument too big"); } str2 = rb_str_new5(str,0, len *= RSTRING(str)->len); for (i = 0; i < len; i += RSTRING(str)->len) { memcpy(RSTRING(str2)->ptr + i, RSTRING(str)->ptr, RSTRING(str)->len); } RSTRING(str2)->ptr[RSTRING(str2)->len] = '\0'; OBJ_INFECT(str2, str); return str2; } /* * call-seq: * str % arg => new_str * * Format---Uses str as a format specification, and returns the result * of applying it to arg. If the format specification contains more than * one substitution, then arg must be an Array containing * the values to be substituted. See Kernel::sprintf for details * of the format string. * * "%05d" % 123 #=> "00123" * "%-5s: %08x" % [ "ID", self.id ] #=> "ID : 200e14d6" */ static VALUE rb_str_format_m(str, arg) VALUE str, arg; { volatile VALUE tmp = rb_check_array_type(arg); if (!NIL_P(tmp)) { return rb_str_format(RARRAY_LEN(tmp), RARRAY_PTR(tmp), str); } return rb_str_format(1, &arg, str); } static const char null_str[] = ""; static int str_independent(str) VALUE str; { if (FL_TEST(str, STR_TMPLOCK)) { rb_raise(rb_eRuntimeError, "can't modify string; temporarily locked"); } if (OBJ_FROZEN(str)) rb_error_frozen("string"); if (!OBJ_TAINTED(str) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify string"); if (RSTRING(str)->ptr == null_str) return 0; if (!FL_TEST(str, ELTS_SHARED)) return 1; return 0; } static void str_make_independent(str) VALUE str; { char *ptr; ptr = ALLOC_N(char, RSTRING(str)->len+1); if (RSTRING(str)->ptr) { memcpy(ptr, RSTRING(str)->ptr, RSTRING(str)->len); } ptr[RSTRING(str)->len] = 0; RSTRING(str)->ptr = ptr; RSTRING(str)->aux.capa = RSTRING(str)->len; FL_UNSET(str, STR_NOCAPA); } void rb_str_modify(str) VALUE str; { if (!str_independent(str)) str_make_independent(str); } void rb_str_associate(str, add) VALUE str, add; { if (FL_TEST(str, STR_ASSOC)) { /* already associated */ rb_ary_concat(RSTRING(str)->aux.shared, add); } else { if (FL_TEST(str, ELTS_SHARED)) { str_make_independent(str); } else if (RSTRING(str)->aux.capa != RSTRING(str)->len) { RESIZE_CAPA(str, RSTRING(str)->len); } RSTRING(str)->aux.shared = add; FL_SET(str, STR_ASSOC); maybe_add_to_longlife_recent_allocations(str); } } VALUE rb_str_associated(str) VALUE str; { if (FL_TEST(str, STR_ASSOC)) { return RSTRING(str)->aux.shared; } return Qfalse; } #define make_null_str(s) do { \ FL_SET(s, ELTS_SHARED); \ RSTRING(s)->ptr = (char *)null_str; \ RSTRING(s)->aux.shared = 0; \ } while (0) static VALUE rb_str_s_alloc(klass) VALUE klass; { VALUE str = str_alloc(klass); make_null_str(str); return str; } VALUE rb_string_value(ptr) volatile VALUE *ptr; { VALUE s = *ptr; if (TYPE(s) != T_STRING) { s = rb_str_to_str(s); *ptr = s; } if (!RSTRING(s)->ptr) { make_null_str(s); } return s; } char * rb_string_value_ptr(ptr) volatile VALUE *ptr; { return RSTRING(rb_string_value(ptr))->ptr; } char * rb_string_value_cstr(ptr) volatile VALUE *ptr; { VALUE str = rb_string_value(ptr); char *s = RSTRING(str)->ptr; if (!s || RSTRING(str)->len != strlen(s)) { rb_raise(rb_eArgError, "string contains null byte"); } return s; } VALUE rb_check_string_type(str) VALUE str; { str = rb_check_convert_type(str, T_STRING, "String", "to_str"); if (!NIL_P(str) && !RSTRING(str)->ptr) { make_null_str(str); } return str; } VALUE rb_str_substr(str, beg, len) VALUE str; long beg, len; { VALUE str2; if (len < 0) return Qnil; if (beg > RSTRING(str)->len) return Qnil; if (beg < 0) { beg += RSTRING(str)->len; if (beg < 0) return Qnil; } if (beg + len > RSTRING(str)->len) { len = RSTRING(str)->len - beg; } if (len < 0) { len = 0; } if (len == 0) { str2 = rb_str_new5(str,0,0); } else if (len > sizeof(struct RString)/2 && beg + len == RSTRING(str)->len && !FL_TEST(str, STR_ASSOC)) { str2 = rb_str_new4(str); str2 = str_new3(rb_obj_class(str2), str2); RSTRING(str2)->ptr += RSTRING(str2)->len - len; RSTRING(str2)->len = len; } else { str2 = rb_str_new5(str, RSTRING(str)->ptr+beg, len); } OBJ_INFECT(str2, str); return str2; } #ifdef GC_DEBUG VALUE rb_str_char_ptr(VALUE str) { return LONG2FIX(RSTRING(str)->ptr); } #endif VALUE rb_str_move(str2) VALUE str2; { VALUE str; int len = RSTRING(str2)->len; char *ptr = RSTRING(str2)->ptr; str = str_alloc_longlife(rb_obj_class(str2)); RSTRING(str)->len = len; RSTRING(str)->aux.capa = len; RSTRING(str)->ptr = ALLOC_N(char,len+1); if (ptr) { memcpy(RSTRING(str)->ptr, ptr, len); } RSTRING(str)->ptr[len] = '\0'; OBJ_FREEZE(str2); OBJ_INFECT(str, str2); #ifdef GC_DEBUG longlife_moved_objs_count++; #endif return str; } VALUE rb_str_dup_frozen(str) VALUE str; { if (FL_TEST(str, ELTS_SHARED) && RSTRING(str)->aux.shared) { VALUE shared = RSTRING(str)->aux.shared; if (RSTRING(shared)->len == RSTRING(str)->len) { OBJ_FREEZE(shared); return shared; } } if (OBJ_FROZEN(str)) return str; str = rb_str_dup(str); OBJ_FREEZE(str); return str; } VALUE rb_str_locktmp(str) VALUE str; { if (FL_TEST(str, STR_TMPLOCK)) { rb_raise(rb_eRuntimeError, "temporal locking already locked string"); } FL_SET(str, STR_TMPLOCK); return str; } VALUE rb_str_unlocktmp(str) VALUE str; { if (!FL_TEST(str, STR_TMPLOCK)) { rb_raise(rb_eRuntimeError, "temporal unlocking already unlocked string"); } FL_UNSET(str, STR_TMPLOCK); return str; } void rb_str_set_len(VALUE str, long len) { RSTRING(str)->len = len; RSTRING(str)->ptr[len] = '\0'; } VALUE rb_str_resize(str, len) VALUE str; long len; { if (len < 0) { rb_raise(rb_eArgError, "negative string size (or size too big)"); } rb_str_modify(str); if (len != RSTRING(str)->len) { if (RSTRING(str)->len < len || RSTRING(str)->len - len > 1024) { REALLOC_N(RSTRING(str)->ptr, char, len+1); if (!FL_TEST(str, STR_NOCAPA)) { RSTRING(str)->aux.capa = len; } } RSTRING(str)->len = len; RSTRING(str)->ptr[len] = '\0'; /* sentinel */ } return str; } static VALUE str_buf_cat(str, ptr, len) VALUE str; const char *ptr; long len; { long capa, total, off = -1;; rb_str_modify(str); if (ptr >= RSTRING(str)->ptr && ptr <= RSTRING(str)->ptr + RSTRING(str)->len) { off = ptr - RSTRING(str)->ptr; } if (len == 0) return 0; if (FL_TEST(str, STR_ASSOC)) { FL_UNSET(str, STR_ASSOC); capa = RSTRING(str)->aux.capa = RSTRING(str)->len; } else { capa = RSTRING(str)->aux.capa; } if (RSTRING(str)->len >= LONG_MAX - len) { rb_raise(rb_eArgError, "string sizes too big"); } total = RSTRING(str)->len+len; if (capa <= total) { while (total > capa) { if (capa + 1 >= LONG_MAX / 2) { capa = total; break; } capa = (capa + 1) * 2; } RESIZE_CAPA(str, capa); } if (off != -1) { ptr = RSTRING(str)->ptr + off; } memcpy(RSTRING(str)->ptr + RSTRING(str)->len, ptr, len); RSTRING(str)->len = total; RSTRING(str)->ptr[total] = '\0'; /* sentinel */ return str; } VALUE rb_str_buf_cat(str, ptr, len) VALUE str; const char *ptr; long len; { if (len == 0) return str; if (len < 0) { rb_raise(rb_eArgError, "negative string size (or size too big)"); } return str_buf_cat(str, ptr, len); } VALUE rb_str_buf_cat2(str, ptr) VALUE str; const char *ptr; { return rb_str_buf_cat(str, ptr, strlen(ptr)); } VALUE rb_str_cat(str, ptr, len) VALUE str; const char *ptr; long len; { if (len < 0) { rb_raise(rb_eArgError, "negative string size (or size too big)"); } if (FL_TEST(str, STR_ASSOC)) { rb_str_modify(str); REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len+len+1); memcpy(RSTRING(str)->ptr + RSTRING(str)->len, ptr, len); RSTRING(str)->len += len; RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; /* sentinel */ return str; } return rb_str_buf_cat(str, ptr, len); } VALUE rb_str_cat2(str, ptr) VALUE str; const char *ptr; { return rb_str_cat(str, ptr, strlen(ptr)); } VALUE rb_str_buf_append(str, str2) VALUE str, str2; { str_buf_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); OBJ_INFECT(str, str2); return str; } VALUE rb_str_append(str, str2) VALUE str, str2; { StringValue(str2); rb_str_modify(str); if (RSTRING(str2)->len > 0) { if (FL_TEST(str, STR_ASSOC)) { long len = RSTRING(str)->len+RSTRING(str2)->len; REALLOC_N(RSTRING(str)->ptr, char, len+1); memcpy(RSTRING(str)->ptr + RSTRING(str)->len, RSTRING(str2)->ptr, RSTRING(str2)->len); RSTRING(str)->ptr[len] = '\0'; /* sentinel */ RSTRING(str)->len = len; } else { return rb_str_buf_append(str, str2); } } OBJ_INFECT(str, str2); return str; } /* * call-seq: * str << fixnum => str * str.concat(fixnum) => str * str << obj => str * str.concat(obj) => str * * Append---Concatenates the given object to str. If the object is a * Fixnum between 0 and 255, it is converted to a character before * concatenation. * * a = "hello " * a << "world" #=> "hello world" * a.concat(33) #=> "hello world!" */ VALUE rb_str_concat(str1, str2) VALUE str1, str2; { if (FIXNUM_P(str2)) { int i = FIX2INT(str2); if (0 <= i && i <= 0xff) { /* byte */ char c = i; return rb_str_cat(str1, &c, 1); } } str1 = rb_str_append(str1, str2); return str1; } int rb_str_hash(str) VALUE str; { register long len = RSTRING(str)->len; register char *p = RSTRING(str)->ptr; register int key = 0; #if defined(HASH_ELFHASH) register unsigned int g; while (len--) { key = (key << 4) + *p++; if (g = key & 0xF0000000) key ^= g >> 24; key &= ~g; } #elif defined(HASH_PERL) while (len--) { key += *p++; key += (key << 10); key ^= (key >> 6); } key += (key << 3); key ^= (key >> 11); key += (key << 15); #else while (len--) { key = key*65599 + *p; p++; } key = key + (key>>5); #endif return key; } /* * call-seq: * str.hash => fixnum * * Return a hash based on the string's length and content. */ static VALUE rb_str_hash_m(str) VALUE str; { int key = rb_str_hash(str); return INT2FIX(key); } #define lesser(a,b) (((a)>(b))?(b):(a)) int rb_str_cmp(str1, str2) VALUE str1, str2; { long len; int retval; len = lesser(RSTRING(str1)->len, RSTRING(str2)->len); retval = rb_memcmp(RSTRING(str1)->ptr, RSTRING(str2)->ptr, len); if (retval == 0) { if (RSTRING(str1)->len == RSTRING(str2)->len) return 0; if (RSTRING(str1)->len > RSTRING(str2)->len) return 1; return -1; } if (retval > 0) return 1; return -1; } /* * call-seq: * str == obj => true or false * * Equality---If obj is not a String, returns * false. Otherwise, returns true if str * <=> obj returns zero. */ static VALUE rb_str_equal(str1, str2) VALUE str1, str2; { if (str1 == str2) return Qtrue; if (TYPE(str2) != T_STRING) { if (!rb_respond_to(str2, rb_intern("to_str"))) { return Qfalse; } return rb_equal(str2, str1); } if (RSTRING(str1)->len == RSTRING(str2)->len && rb_str_cmp(str1, str2) == 0) { return Qtrue; } return Qfalse; } #define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{')) /* * call-seq: * str.eql?(other) => true or false * * Two strings are equal if the have the same length and content. */ static VALUE rb_str_eql(str1, str2) VALUE str1, str2; { if (TYPE(str2) != T_STRING || RSTRING(str1)->len != RSTRING(str2)->len) return Qfalse; if (memcmp(RSTRING(str1)->ptr, RSTRING(str2)->ptr, lesser(RSTRING(str1)->len, RSTRING(str2)->len)) == 0) return Qtrue; return Qfalse; } /* * call-seq: * str <=> other_str => -1, 0, +1 * * Comparison---Returns -1 if other_str is less than, 0 if * other_str is equal to, and +1 if other_str is greater than * str. If the strings are of different lengths, and the strings are * equal when compared up to the shortest length, then the longer string is * considered greater than the shorter one. If the variable $= is * false, the comparison is based on comparing the binary values * of each character in the string. In older versions of Ruby, setting * $= allowed case-insensitive comparisons; this is now deprecated * in favor of using String#casecmp. * * <=> is the basis for the methods <, * <=, >, >=, and between?, * included from module Comparable. The method * String#== does not use Comparable#==. * * "abcdef" <=> "abcde" #=> 1 * "abcdef" <=> "abcdef" #=> 0 * "abcdef" <=> "abcdefg" #=> -1 * "abcdef" <=> "ABCDEF" #=> 1 */ static VALUE rb_str_cmp_m(str1, str2) VALUE str1, str2; { long result; if (TYPE(str2) != T_STRING) { if (!rb_respond_to(str2, rb_intern("to_str"))) { return Qnil; } else if (!rb_respond_to(str2, rb_intern("<=>"))) { return Qnil; } else { VALUE tmp = rb_funcall(str2, rb_intern("<=>"), 1, str1); if (NIL_P(tmp)) return Qnil; if (!FIXNUM_P(tmp)) { return rb_funcall(LONG2FIX(0), '-', 1, tmp); } result = -FIX2LONG(tmp); } } else { result = rb_str_cmp(str1, str2); } return LONG2NUM(result); } /* * call-seq: * str.casecmp(other_str) => -1, 0, +1 * * Case-insensitive version of String#<=>. * * "abcdef".casecmp("abcde") #=> 1 * "aBcDeF".casecmp("abcdef") #=> 0 * "abcdef".casecmp("abcdefg") #=> -1 * "abcdef".casecmp("ABCDEF") #=> 0 */ static VALUE rb_str_casecmp(str1, str2) VALUE str1, str2; { long len; int retval; StringValue(str2); len = lesser(RSTRING(str1)->len, RSTRING(str2)->len); retval = rb_memcicmp(RSTRING(str1)->ptr, RSTRING(str2)->ptr, len); if (retval == 0) { if (RSTRING(str1)->len == RSTRING(str2)->len) return INT2FIX(0); if (RSTRING(str1)->len > RSTRING(str2)->len) return INT2FIX(1); return INT2FIX(-1); } if (retval == 0) return INT2FIX(0); if (retval > 0) return INT2FIX(1); return INT2FIX(-1); } static long rb_str_index(str, sub, offset) VALUE str, sub; long offset; { long pos; if (offset < 0) { offset += RSTRING(str)->len; if (offset < 0) return -1; } if (RSTRING(str)->len - offset < RSTRING(sub)->len) return -1; if (RSTRING(sub)->len == 0) return offset; pos = rb_memsearch(RSTRING(sub)->ptr, RSTRING(sub)->len, RSTRING(str)->ptr+offset, RSTRING(str)->len-offset); if (pos < 0) return pos; return pos + offset; } /* * call-seq: * str.index(substring [, offset]) => fixnum or nil * str.index(fixnum [, offset]) => fixnum or nil * str.index(regexp [, offset]) => fixnum or nil * * Returns the index of the first occurrence of the given substring, * character (fixnum), or pattern (regexp) in str. Returns * nil if not found. If the second parameter is present, it * specifies the position in the string to begin the search. * * "hello".index('e') #=> 1 * "hello".index('lo') #=> 3 * "hello".index('a') #=> nil * "hello".index(101) #=> 1 * "hello".index(/[aeiou]/, -3) #=> 4 */ static VALUE rb_str_index_m(argc, argv, str) int argc; VALUE *argv; VALUE str; { VALUE sub; VALUE initpos; long pos; if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) { pos = NUM2LONG(initpos); } else { pos = 0; } if (pos < 0) { pos += RSTRING(str)->len; if (pos < 0) { if (TYPE(sub) == T_REGEXP) { rb_backref_set(Qnil); } return Qnil; } } switch (TYPE(sub)) { case T_REGEXP: pos = rb_reg_adjust_startpos(sub, str, pos, 0); pos = rb_reg_search(sub, str, pos, 0); break; case T_FIXNUM: { int c = FIX2INT(sub); long len = RSTRING(str)->len; unsigned char *p = (unsigned char*)RSTRING(str)->ptr; for (;poslen; char *s, *sbeg, *t; /* substring longer than string */ if (RSTRING(str)->len < len) return -1; if (RSTRING(str)->len - pos < len) { pos = RSTRING(str)->len - len; } sbeg = RSTRING(str)->ptr; s = RSTRING(str)->ptr + pos; t = RSTRING(sub)->ptr; if (len) { while (sbeg <= s) { if (rb_memcmp(s, t, len) == 0) { return s - RSTRING(str)->ptr; } s--; } return -1; } else { return pos; } } /* * call-seq: * str.rindex(substring [, fixnum]) => fixnum or nil * str.rindex(fixnum [, fixnum]) => fixnum or nil * str.rindex(regexp [, fixnum]) => fixnum or nil * * Returns the index of the last occurrence of the given substring, * character (fixnum), or pattern (regexp) in str. Returns * nil if not found. If the second parameter is present, it * specifies the position in the string to end the search---characters beyond * this point will not be considered. * * "hello".rindex('e') #=> 1 * "hello".rindex('l') #=> 3 * "hello".rindex('a') #=> nil * "hello".rindex(101) #=> 1 * "hello".rindex(/[aeiou]/, -2) #=> 1 */ static VALUE rb_str_rindex_m(argc, argv, str) int argc; VALUE *argv; VALUE str; { VALUE sub; VALUE position; long pos; if (rb_scan_args(argc, argv, "11", &sub, &position) == 2) { pos = NUM2LONG(position); if (pos < 0) { pos += RSTRING(str)->len; if (pos < 0) { if (TYPE(sub) == T_REGEXP) { rb_backref_set(Qnil); } return Qnil; } } if (pos > RSTRING(str)->len) pos = RSTRING(str)->len; } else { pos = RSTRING(str)->len; } switch (TYPE(sub)) { case T_REGEXP: if (RREGEXP(sub)->len) { pos = rb_reg_adjust_startpos(sub, str, pos, 1); pos = rb_reg_search(sub, str, pos, 1); } if (pos >= 0) return LONG2NUM(pos); break; default: { VALUE tmp; tmp = rb_check_string_type(sub); if (NIL_P(tmp)) { rb_raise(rb_eTypeError, "type mismatch: %s given", rb_obj_classname(sub)); } sub = tmp; } /* fall through */ case T_STRING: pos = rb_str_rindex(str, sub, pos); if (pos >= 0) return LONG2NUM(pos); break; case T_FIXNUM: { int c = FIX2INT(sub); unsigned char *p = (unsigned char*)RSTRING(str)->ptr + pos; unsigned char *pbeg = (unsigned char*)RSTRING(str)->ptr; if (pos == RSTRING(str)->len) { if (pos == 0) return Qnil; --p; } while (pbeg <= p) { if (*p == c) return LONG2NUM((char*)p - RSTRING(str)->ptr); p--; } return Qnil; } } return Qnil; } /* * call-seq: * str =~ obj => fixnum or nil * * Match---If obj is a Regexp, use it as a pattern to match * against str,and returns the position the match starts, or * nil if there is no match. Otherwise, invokes * obj.=~, passing str as an argument. The default * =~ in Object returns false. * * "cat o' 9 tails" =~ /\d/ #=> 7 * "cat o' 9 tails" =~ 9 #=> false */ static VALUE rb_str_match(x, y) VALUE x, y; { switch (TYPE(y)) { case T_STRING: rb_raise(rb_eTypeError, "type mismatch: String given"); case T_REGEXP: return rb_reg_match(y, x); default: return rb_funcall(y, rb_intern("=~"), 1, x); } } static VALUE get_pat _((VALUE, int)); /* * call-seq: * str.match(pattern) => matchdata or nil * * Converts pattern to a Regexp (if it isn't already one), * then invokes its match method on str. * * 'hello'.match('(.)\1') #=> # * 'hello'.match('(.)\1')[0] #=> "ll" * 'hello'.match(/(.)\1/)[0] #=> "ll" * 'hello'.match('xx') #=> nil */ static VALUE rb_str_match_m(str, re) VALUE str, re; { return rb_funcall(get_pat(re, 0), rb_intern("match"), 1, str); } static char succ_char(s) char *s; { char c = *s; /* numerics */ if ('0' <= c && c < '9') (*s)++; else if (c == '9') { *s = '0'; return '1'; } /* small alphabets */ else if ('a' <= c && c < 'z') (*s)++; else if (c == 'z') { return *s = 'a'; } /* capital alphabets */ else if ('A' <= c && c < 'Z') (*s)++; else if (c == 'Z') { return *s = 'A'; } return 0; } /* * call-seq: * str.succ => new_str * str.next => new_str * * Returns the successor to str. The successor is calculated by * incrementing characters starting from the rightmost alphanumeric (or * the rightmost character if there are no alphanumerics) in the * string. Incrementing a digit always results in another digit, and * incrementing a letter results in another letter of the same case. * Incrementing nonalphanumerics uses the underlying character set's * collating sequence. * * If the increment generates a ``carry,'' the character to the left of * it is incremented. This process repeats until there is no carry, * adding an additional character if necessary. * * "abcd".succ #=> "abce" * "THX1138".succ #=> "THX1139" * "<>".succ #=> "<>" * "1999zzz".succ #=> "2000aaa" * "ZZZ9999".succ #=> "AAAA0000" * "***".succ #=> "**+" */ static VALUE rb_str_succ(orig) VALUE orig; { VALUE str; char *sbeg, *s; int c = -1; long n = 0; str = rb_str_new5(orig, RSTRING(orig)->ptr, RSTRING(orig)->len); OBJ_INFECT(str, orig); if (RSTRING(str)->len == 0) return str; sbeg = RSTRING(str)->ptr; s = sbeg + RSTRING(str)->len - 1; while (sbeg <= s) { if (ISALNUM(*s)) { if ((c = succ_char(s)) == 0) break; n = s - sbeg; } s--; } if (c == -1) { /* str contains no alnum */ sbeg = RSTRING(str)->ptr; s = sbeg + RSTRING(str)->len - 1; c = '\001'; while (sbeg <= s) { if ((*s += 1) != 0) break; s--; } } if (s < sbeg) { RESIZE_CAPA(str, RSTRING(str)->len + 1); s = RSTRING(str)->ptr + n; memmove(s+1, s, RSTRING(str)->len - n); *s = c; RSTRING(str)->len += 1; RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; } return str; } /* * call-seq: * str.succ! => str * str.next! => str * * Equivalent to String#succ, but modifies the receiver in * place. */ static VALUE rb_str_succ_bang(str) VALUE str; { rb_str_shared_replace(str, rb_str_succ(str)); return str; } VALUE rb_str_upto(beg, end, excl) VALUE beg, end; int excl; { VALUE current, after_end; ID succ = rb_intern("succ"); int n; StringValue(end); n = rb_str_cmp(beg, end); if (n > 0 || (excl && n == 0)) return beg; after_end = rb_funcall(end, succ, 0, 0); current = beg; while (!rb_str_equal(current, after_end)) { rb_yield(current); if (!excl && rb_str_equal(current, end)) break; current = rb_funcall(current, succ, 0, 0); StringValue(current); if (excl && rb_str_equal(current, end)) break; StringValue(current); if (RSTRING(current)->len > RSTRING(end)->len || RSTRING(current)->len == 0) break; } return beg; } /* * call-seq: * str.upto(other_str, exclusive=false) {|s| block } => str * * Iterates through successive values, starting at str and * ending at other_str inclusive, passing each value in turn to * the block. The String#succ method is used to generate * each value. If optional second argument exclusive is omitted or is false, * the last value will be included; otherwise it will be excluded. * * "a8".upto("b6") {|s| print s, ' ' } * for s in "a8".."b6" * print s, ' ' * end * * produces: * * a8 a9 b0 b1 b2 b3 b4 b5 b6 * a8 a9 b0 b1 b2 b3 b4 b5 b6 */ static VALUE rb_str_upto_m(argc, argv, beg) int argc; VALUE *argv; VALUE beg; { VALUE end, exclusive; rb_scan_args(argc, argv, "11", &end, &exclusive); return rb_str_upto(beg, end, RTEST(exclusive)); } static VALUE rb_str_subpat(str, re, nth) VALUE str, re; int nth; { if (rb_reg_search(re, str, 0, 0) >= 0) { return rb_reg_nth_match(nth, rb_backref_get()); } return Qnil; } static VALUE rb_str_aref(str, indx) VALUE str; VALUE indx; { long idx; switch (TYPE(indx)) { case T_FIXNUM: idx = FIX2LONG(indx); num_index: if (idx < 0) { idx = RSTRING(str)->len + idx; } if (idx < 0 || RSTRING(str)->len <= idx) { return Qnil; } return INT2FIX(RSTRING(str)->ptr[idx] & 0xff); case T_REGEXP: return rb_str_subpat(str, indx, 0); case T_STRING: if (rb_str_index(str, indx, 0) != -1) return rb_str_dup(indx); return Qnil; default: /* check if indx is Range */ { long beg, len; VALUE tmp; switch (rb_range_beg_len(indx, &beg, &len, RSTRING(str)->len, 0)) { case Qfalse: break; case Qnil: return Qnil; default: tmp = rb_str_substr(str, beg, len); OBJ_INFECT(tmp, indx); return tmp; } } idx = NUM2LONG(indx); goto num_index; } return Qnil; /* not reached */ } /* * call-seq: * str[fixnum] => fixnum or nil * str[fixnum, fixnum] => new_str or nil * str[range] => new_str or nil * str[regexp] => new_str or nil * str[regexp, fixnum] => new_str or nil * str[other_str] => new_str or nil * str.slice(fixnum) => fixnum or nil * str.slice(fixnum, fixnum) => new_str or nil * str.slice(range) => new_str or nil * str.slice(regexp) => new_str or nil * str.slice(regexp, fixnum) => new_str or nil * str.slice(other_str) => new_str or nil * * Element Reference---If passed a single Fixnum, returns the code * of the character at that position. If passed two Fixnum * objects, returns a substring starting at the offset given by the first, and * a length given by the second. If given a range, a substring containing * characters at offsets given by the range is returned. In all three cases, if * an offset is negative, it is counted from the end of str. Returns * nil if the initial offset falls outside the string, the length * is negative, or the beginning of the range is greater than the end. * * If a Regexp is supplied, the matching portion of str is * returned. If a numeric parameter follows the regular expression, that * component of the MatchData is returned instead. If a * String is given, that string is returned if it occurs in * str. In both cases, nil is returned if there is no * match. * * a = "hello there" * a[1] #=> 101 * a[1,3] #=> "ell" * a[1..3] #=> "ell" * a[-3,2] #=> "er" * a[-4..-2] #=> "her" * a[12..-1] #=> nil * a[-2..-4] #=> "" * a[/[aeiou](.)\1/] #=> "ell" * a[/[aeiou](.)\1/, 0] #=> "ell" * a[/[aeiou](.)\1/, 1] #=> "l" * a[/[aeiou](.)\1/, 2] #=> nil * a["lo"] #=> "lo" * a["bye"] #=> nil */ static VALUE rb_str_aref_m(argc, argv, str) int argc; VALUE *argv; VALUE str; { if (argc == 2) { if (TYPE(argv[0]) == T_REGEXP) { return rb_str_subpat(str, argv[0], NUM2INT(argv[1])); } return rb_str_substr(str, NUM2LONG(argv[0]), NUM2LONG(argv[1])); } if (argc != 1) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc); } return rb_str_aref(str, argv[0]); } static void rb_str_splice(str, beg, len, val) VALUE str; long beg, len; VALUE val; { if (len < 0) rb_raise(rb_eIndexError, "negative length %ld", len); StringValue(val); rb_str_modify(str); if (RSTRING(str)->len < beg) { out_of_range: rb_raise(rb_eIndexError, "index %ld out of string", beg); } if (beg < 0) { if (-beg > RSTRING(str)->len) { goto out_of_range; } beg += RSTRING(str)->len; } if (RSTRING(str)->len < len || RSTRING(str)->len < beg + len) { len = RSTRING(str)->len - beg; } if (len < RSTRING(val)->len) { /* expand string */ RESIZE_CAPA(str, RSTRING(str)->len + RSTRING(val)->len - len + 1); } if (RSTRING(val)->len != len) { memmove(RSTRING(str)->ptr + beg + RSTRING(val)->len, RSTRING(str)->ptr + beg + len, RSTRING(str)->len - (beg + len)); } if (RSTRING(str)->len < beg && len < 0) { MEMZERO(RSTRING(str)->ptr + RSTRING(str)->len, char, -len); } if (RSTRING(val)->len > 0) { memmove(RSTRING(str)->ptr+beg, RSTRING(val)->ptr, RSTRING(val)->len); } RSTRING(str)->len += RSTRING(val)->len - len; if (RSTRING(str)->ptr) { RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; } OBJ_INFECT(str, val); } void rb_str_update(str, beg, len, val) VALUE str; long beg, len; VALUE val; { rb_str_splice(str, beg, len, val); } static void rb_str_subpat_set(str, re, nth, val) VALUE str, re; int nth; VALUE val; { VALUE match; long start, end, len; if (rb_reg_search(re, str, 0, 0) < 0) { rb_raise(rb_eIndexError, "regexp not matched"); } match = rb_backref_get(); if (nth >= RMATCH(match)->regs->num_regs) { out_of_range: rb_raise(rb_eIndexError, "index %d out of regexp", nth); } if (nth < 0) { if (-nth >= RMATCH(match)->regs->num_regs) { goto out_of_range; } nth += RMATCH(match)->regs->num_regs; } start = RMATCH(match)->BEG(nth); if (start == -1) { rb_raise(rb_eIndexError, "regexp group %d not matched", nth); } end = RMATCH(match)->END(nth); len = end - start; rb_str_splice(str, start, len, val); } static VALUE rb_str_aset(str, indx, val) VALUE str; VALUE indx, val; { long idx, beg; switch (TYPE(indx)) { case T_FIXNUM: idx = FIX2LONG(indx); num_index: if (RSTRING(str)->len <= idx) { out_of_range: rb_raise(rb_eIndexError, "index %ld out of string", idx); } if (idx < 0) { if (-idx > RSTRING(str)->len) goto out_of_range; idx += RSTRING(str)->len; } if (FIXNUM_P(val)) { rb_str_modify(str); if (RSTRING(str)->len == idx) { RSTRING(str)->len += 1; RESIZE_CAPA(str, RSTRING(str)->len); } RSTRING(str)->ptr[idx] = FIX2INT(val) & 0xff; } else { rb_str_splice(str, idx, 1, val); } return val; case T_REGEXP: rb_str_subpat_set(str, indx, 0, val); return val; case T_STRING: beg = rb_str_index(str, indx, 0); if (beg < 0) { rb_raise(rb_eIndexError, "string not matched"); } rb_str_splice(str, beg, RSTRING(indx)->len, val); return val; default: /* check if indx is Range */ { long beg, len; if (rb_range_beg_len(indx, &beg, &len, RSTRING(str)->len, 2)) { rb_str_splice(str, beg, len, val); return val; } } idx = NUM2LONG(indx); goto num_index; } } /* * call-seq: * str[fixnum] = fixnum * str[fixnum] = new_str * str[fixnum, fixnum] = new_str * str[range] = aString * str[regexp] = new_str * str[regexp, fixnum] = new_str * str[other_str] = new_str * * Element Assignment---Replaces some or all of the content of str. The * portion of the string affected is determined using the same criteria as * String#[]. If the replacement string is not the same length as * the text it is replacing, the string will be adjusted accordingly. If the * regular expression or string is used as the index doesn't match a position * in the string, IndexError is raised. If the regular expression * form is used, the optional second Fixnum allows you to specify * which portion of the match to replace (effectively using the * MatchData indexing rules. The forms that take a * Fixnum will raise an IndexError if the value is * out of range; the Range form will raise a * RangeError, and the Regexp and String * forms will silently ignore the assignment. */ static VALUE rb_str_aset_m(argc, argv, str) int argc; VALUE *argv; VALUE str; { if (argc == 3) { if (TYPE(argv[0]) == T_REGEXP) { rb_str_subpat_set(str, argv[0], NUM2INT(argv[1]), argv[2]); } else { rb_str_splice(str, NUM2LONG(argv[0]), NUM2LONG(argv[1]), argv[2]); } return argv[2]; } if (argc != 2) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)", argc); } return rb_str_aset(str, argv[0], argv[1]); } /* * call-seq: * str.insert(index, other_str) => str * * Inserts other_str before the character at the given * index, modifying str. Negative indices count from the * end of the string, and insert after the given character. * The intent is insert aString so that it starts at the given * index. * * "abcd".insert(0, 'X') #=> "Xabcd" * "abcd".insert(3, 'X') #=> "abcXd" * "abcd".insert(4, 'X') #=> "abcdX" * "abcd".insert(-3, 'X') #=> "abXcd" * "abcd".insert(-1, 'X') #=> "abcdX" */ static VALUE rb_str_insert(str, idx, str2) VALUE str, idx, str2; { long pos = NUM2LONG(idx); if (pos == -1) { pos = RSTRING(str)->len; } else if (pos < 0) { pos++; } rb_str_splice(str, pos, 0, str2); return str; } /* * call-seq: * str.slice!(fixnum) => fixnum or nil * str.slice!(fixnum, fixnum) => new_str or nil * str.slice!(range) => new_str or nil * str.slice!(regexp) => new_str or nil * str.slice!(other_str) => new_str or nil * * Deletes the specified portion from str, and returns the portion * deleted. The forms that take a Fixnum will raise an * IndexError if the value is out of range; the Range * form will raise a RangeError, and the Regexp and * String forms will silently ignore the assignment. * * string = "this is a string" * string.slice!(2) #=> 105 * string.slice!(3..6) #=> " is " * string.slice!(/s.*t/) #=> "sa st" * string.slice!("r") #=> "r" * string #=> "thing" */ static VALUE rb_str_slice_bang(argc, argv, str) int argc; VALUE *argv; VALUE str; { VALUE result; VALUE buf[3]; int i; if (argc < 1 || 2 < argc) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc); } for (i=0; i str or nil * str.sub!(pattern) {|match| block } => str or nil * * Performs the substitutions of String#sub in place, * returning str, or nil if no substitutions were * performed. */ static VALUE rb_str_sub_bang(argc, argv, str) int argc; VALUE *argv; VALUE str; { VALUE pat, repl, match; struct re_registers *regs; int iter = 0; int tainted = 0; long plen; if (argc == 1 && rb_block_given_p()) { iter = 1; } else if (argc == 2) { repl = argv[1]; StringValue(repl); if (OBJ_TAINTED(repl)) tainted = 1; } else { rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)", argc); } pat = get_pat(argv[0], 1); if (rb_reg_search(pat, str, 0, 0) >= 0) { match = rb_backref_get(); regs = RMATCH(match)->regs; if (iter) { char *p = RSTRING(str)->ptr; long len = RSTRING(str)->len; rb_match_busy(match); repl = rb_obj_as_string(rb_yield(rb_reg_nth_match(0, match))); str_mod_check(str, p, len); str_frozen_check(str); rb_backref_set(match); } else { repl = rb_reg_regsub(repl, str, regs); } rb_str_modify(str); if (OBJ_TAINTED(repl)) tainted = 1; plen = END(0) - BEG(0); if (RSTRING(repl)->len > plen) { RESIZE_CAPA(str, RSTRING(str)->len + RSTRING(repl)->len - plen); } if (RSTRING(repl)->len != plen) { memmove(RSTRING(str)->ptr + BEG(0) + RSTRING(repl)->len, RSTRING(str)->ptr + BEG(0) + plen, RSTRING(str)->len - BEG(0) - plen); } memcpy(RSTRING(str)->ptr + BEG(0), RSTRING(repl)->ptr, RSTRING(repl)->len); RSTRING(str)->len += RSTRING(repl)->len - plen; RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; if (tainted) OBJ_TAINT(str); return str; } return Qnil; } /* * call-seq: * str.sub(pattern, replacement) => new_str * str.sub(pattern) {|match| block } => new_str * * Returns a copy of str with the first occurrence of * pattern replaced with either replacement or the value of the * block. The pattern will typically be a Regexp; if it is * a String then no regular expression metacharacters will be * interpreted (that is /\d/ will match a digit, but * '\d' will match a backslash followed by a 'd'). * * If the method call specifies replacement, special variables such as * $& will not be useful, as substitution into the string occurs * before the pattern match starts. However, the sequences \1, * \2, etc., may be used. * * In the block form, the current match string is passed in as a parameter, and * variables such as $1, $2, $`, * $&, and $' will be set appropriately. The value * returned by the block will be substituted for the match on each call. * * The result inherits any tainting in the original string or any supplied * replacement string. * * "hello".sub(/[aeiou]/, '*') #=> "h*llo" * "hello".sub(/([aeiou])/, '<\1>') #=> "hllo" * "hello".sub(/./) {|s| s[0].to_s + ' ' } #=> "104 ello" */ static VALUE rb_str_sub(argc, argv, str) int argc; VALUE *argv; VALUE str; { str = rb_str_dup(str); rb_str_sub_bang(argc, argv, str); return str; } static VALUE str_gsub(argc, argv, str, bang) int argc; VALUE *argv; VALUE str; int bang; { VALUE pat, val, repl, match, dest; struct re_registers *regs; long beg, n; long offset, blen, slen, len; int iter = 0; char *buf, *bp, *sp, *cp; int tainted = 0; if (argc == 1) { RETURN_ENUMERATOR(str, argc, argv); iter = 1; } else if (argc == 2) { repl = argv[1]; StringValue(repl); if (OBJ_TAINTED(repl)) tainted = 1; } else { rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)", argc); } pat = get_pat(argv[0], 1); offset=0; n=0; beg = rb_reg_search(pat, str, 0, 0); if (beg < 0) { if (bang) return Qnil; /* no match, no substitution */ return rb_str_dup(str); } blen = RSTRING(str)->len + 30; /* len + margin */ dest = str_new(0, 0, blen); buf = RSTRING(dest)->ptr; bp = buf; sp = cp = RSTRING(str)->ptr; slen = RSTRING(str)->len; rb_str_locktmp(dest); while (beg >= 0) { n++; match = rb_backref_get(); regs = RMATCH(match)->regs; if (iter) { rb_match_busy(match); val = rb_obj_as_string(rb_yield(rb_reg_nth_match(0, match))); str_mod_check(str, sp, slen); if (bang) str_frozen_check(str); if (val == dest) { /* paranoid chack [ruby-dev:24827] */ rb_raise(rb_eRuntimeError, "block should not cheat"); } rb_backref_set(match); } else { val = rb_reg_regsub(repl, str, regs); } if (OBJ_TAINTED(val)) tainted = 1; len = (bp - buf) + (beg - offset) + RSTRING(val)->len + 3; if (blen < len) { while (blen < len) blen *= 2; len = bp - buf; RESIZE_CAPA(dest, blen); RSTRING(dest)->len = blen; buf = RSTRING(dest)->ptr; bp = buf + len; } len = beg - offset; /* copy pre-match substr */ memcpy(bp, cp, len); bp += len; memcpy(bp, RSTRING(val)->ptr, RSTRING(val)->len); bp += RSTRING(val)->len; offset = END(0); if (BEG(0) == END(0)) { /* * Always consume at least one character of the input string * in order to prevent infinite loops. */ if (RSTRING(str)->len <= END(0)) break; len = mbclen2(RSTRING(str)->ptr[END(0)], pat); memcpy(bp, RSTRING(str)->ptr+END(0), len); bp += len; offset = END(0) + len; } cp = RSTRING(str)->ptr + offset; if (offset > RSTRING(str)->len) break; beg = rb_reg_search(pat, str, offset, 0); } if (RSTRING(str)->len > offset) { len = bp - buf; if (blen - len < RSTRING(str)->len - offset) { blen = len + RSTRING(str)->len - offset; RESIZE_CAPA(dest, blen); buf = RSTRING(dest)->ptr; bp = buf + len; } memcpy(bp, cp, RSTRING(str)->len - offset); bp += RSTRING(str)->len - offset; } rb_backref_set(match); *bp = '\0'; rb_str_unlocktmp(dest); if (bang) { if (str_independent(str)) { free(RSTRING(str)->ptr); } FL_UNSET(str, STR_NOCAPA); RSTRING(str)->ptr = buf; RSTRING(str)->aux.capa = blen; RSTRING(dest)->ptr = 0; RSTRING(dest)->len = 0; } else { RBASIC(dest)->klass = rb_obj_class(str); OBJ_INFECT(dest, str); str = dest; } RSTRING(str)->len = bp - buf; if (tainted) OBJ_TAINT(str); return str; } /* * call-seq: * str.gsub!(pattern, replacement) => str or nil * str.gsub!(pattern) {|match| block } => str or nil * * Performs the substitutions of String#gsub in place, returning * str, or nil if no substitutions were performed. */ static VALUE rb_str_gsub_bang(argc, argv, str) int argc; VALUE *argv; VALUE str; { return str_gsub(argc, argv, str, 1); } /* * call-seq: * str.gsub(pattern, replacement) => new_str * str.gsub(pattern) {|match| block } => new_str * * Returns a copy of str with all occurrences of pattern * replaced with either replacement or the value of the block. The * pattern will typically be a Regexp; if it is a * String then no regular expression metacharacters will be * interpreted (that is /\d/ will match a digit, but * '\d' will match a backslash followed by a 'd'). * * If a string is used as the replacement, special variables from the match * (such as $& and $1) cannot be substituted into it, * as substitution into the string occurs before the pattern match * starts. However, the sequences \1, \2, and so on * may be used to interpolate successive groups in the match. * * In the block form, the current match string is passed in as a parameter, and * variables such as $1, $2, $`, * $&, and $' will be set appropriately. The value * returned by the block will be substituted for the match on each call. * * The result inherits any tainting in the original string or any supplied * replacement string. * * "hello".gsub(/[aeiou]/, '*') #=> "h*ll*" * "hello".gsub(/([aeiou])/, '<\1>') #=> "hll" * "hello".gsub(/./) {|s| s[0].to_s + ' '} #=> "104 101 108 108 111 " */ static VALUE rb_str_gsub(argc, argv, str) int argc; VALUE *argv; VALUE str; { return str_gsub(argc, argv, str, 0); } /* * call-seq: * str.replace(other_str) => str * * Replaces the contents and taintedness of str with the corresponding * values in other_str. * * s = "hello" #=> "hello" * s.replace "world" #=> "world" */ static VALUE rb_str_replace(str, str2) VALUE str, str2; { if (str == str2) return str; StringValue(str2); if (FL_TEST(str2, ELTS_SHARED)) { if (str_independent(str)) { free(RSTRING(str)->ptr); } RSTRING(str)->len = RSTRING(str2)->len; RSTRING(str)->ptr = RSTRING(str2)->ptr; FL_SET(str, ELTS_SHARED); FL_UNSET(str, STR_ASSOC); RSTRING(str)->aux.shared = RSTRING(str2)->aux.shared; } else { if (str_independent(str)) { rb_str_resize(str, RSTRING(str2)->len); memcpy(RSTRING(str)->ptr, RSTRING(str2)->ptr, RSTRING(str2)->len); if (!RSTRING(str)->ptr) { make_null_str(str); } } else { RSTRING(str)->ptr = RSTRING(str2)->ptr; RSTRING(str)->len = RSTRING(str2)->len; str_make_independent(str); } if (FL_TEST(str2, STR_ASSOC)) { FL_SET(str, STR_ASSOC); RSTRING(str)->aux.shared = RSTRING(str2)->aux.shared; } } OBJ_INFECT(str, str2); maybe_add_to_longlife_recent_allocations(str); return str; } static VALUE uscore_get() { VALUE line; line = rb_lastline_get(); if (TYPE(line) != T_STRING) { rb_raise(rb_eTypeError, "$_ value need to be String (%s given)", NIL_P(line) ? "nil" : rb_obj_classname(line)); } return line; } /* * call-seq: * sub!(pattern, replacement) => $_ or nil * sub!(pattern) {|...| block } => $_ or nil * * Equivalent to $_.sub!(args). */ static VALUE rb_f_sub_bang(argc, argv) int argc; VALUE *argv; { return rb_str_sub_bang(argc, argv, uscore_get()); } /* * call-seq: * sub(pattern, replacement) => $_ * sub(pattern) { block } => $_ * * Equivalent to $_.sub(args), except that * $_ will be updated if substitution occurs. */ static VALUE rb_f_sub(argc, argv) int argc; VALUE *argv; { VALUE str = rb_str_dup(uscore_get()); if (NIL_P(rb_str_sub_bang(argc, argv, str))) return str; rb_lastline_set(str); return str; } /* * call-seq: * gsub!(pattern, replacement) => string or nil * gsub!(pattern) {|...| block } => string or nil * * Equivalent to Kernel::gsub, except nil is * returned if $_ is not modified. * * $_ = "quick brown fox" * gsub! /cat/, '*' #=> nil * $_ #=> "quick brown fox" */ static VALUE rb_f_gsub_bang(argc, argv) int argc; VALUE *argv; { return rb_str_gsub_bang(argc, argv, uscore_get()); } /* * call-seq: * gsub(pattern, replacement) => string * gsub(pattern) {|...| block } => string * * Equivalent to $_.gsub..., except that $_ * receives the modified result. * * $_ = "quick brown fox" * gsub /[aeiou]/, '*' #=> "q**ck br*wn f*x" * $_ #=> "q**ck br*wn f*x" */ static VALUE rb_f_gsub(argc, argv) int argc; VALUE *argv; { VALUE str = rb_str_dup(uscore_get()); if (NIL_P(rb_str_gsub_bang(argc, argv, str))) return str; rb_lastline_set(str); return str; } /* * call-seq: * str.reverse! => str * * Reverses str in place. */ static VALUE rb_str_reverse_bang(str) VALUE str; { char *s, *e; char c; if (RSTRING(str)->len > 1) { rb_str_modify(str); s = RSTRING(str)->ptr; e = s + RSTRING(str)->len - 1; while (s < e) { c = *s; *s++ = *e; *e-- = c; } } return str; } /* * call-seq: * str.reverse => new_str * * Returns a new string with the characters from str in reverse order. * * "stressed".reverse #=> "desserts" */ static VALUE rb_str_reverse(str) VALUE str; { VALUE obj; char *s, *e, *p; if (RSTRING(str)->len <= 1) return rb_str_dup(str); obj = rb_str_new5(str, 0, RSTRING(str)->len); s = RSTRING(str)->ptr; e = s + RSTRING(str)->len - 1; p = RSTRING(obj)->ptr; while (e >= s) { *p++ = *e--; } OBJ_INFECT(obj, str); return obj; } /* * call-seq: * str.include? other_str => true or false * str.include? fixnum => true or false * * Returns true if str contains the given string or * character. * * "hello".include? "lo" #=> true * "hello".include? "ol" #=> false * "hello".include? ?h #=> true */ static VALUE rb_str_include(str, arg) VALUE str, arg; { long i; if (FIXNUM_P(arg)) { if (memchr(RSTRING(str)->ptr, FIX2INT(arg), RSTRING(str)->len)) return Qtrue; return Qfalse; } StringValue(arg); i = rb_str_index(str, arg, 0); if (i == -1) return Qfalse; return Qtrue; } /* * call-seq: * str.to_i(base=10) => integer * * Returns the result of interpreting leading characters in str as an * integer base base (between 2 and 36). Extraneous characters past the * end of a valid number are ignored. If there is not a valid number at the * start of str, 0 is returned. This method never raises an * exception. * * "12345".to_i #=> 12345 * "99 red balloons".to_i #=> 99 * "0a".to_i #=> 0 * "0a".to_i(16) #=> 10 * "hello".to_i #=> 0 * "1100101".to_i(2) #=> 101 * "1100101".to_i(8) #=> 294977 * "1100101".to_i(10) #=> 1100101 * "1100101".to_i(16) #=> 17826049 */ static VALUE rb_str_to_i(argc, argv, str) int argc; VALUE *argv; VALUE str; { VALUE b; int base; rb_scan_args(argc, argv, "01", &b); if (argc == 0) base = 10; else base = NUM2INT(b); if (base < 0) { rb_raise(rb_eArgError, "illegal radix %d", base); } return rb_str_to_inum(str, base, Qfalse); } /* * call-seq: * str.to_f => float * * Returns the result of interpreting leading characters in str as a * floating point number. Extraneous characters past the end of a valid number * are ignored. If there is not a valid number at the start of str, * 0.0 is returned. This method never raises an exception. * * "123.45e1".to_f #=> 1234.5 * "45.67 degrees".to_f #=> 45.67 * "thx1138".to_f #=> 0.0 */ static VALUE rb_str_to_f(str) VALUE str; { return rb_float_new(rb_str_to_dbl(str, Qfalse)); } /* * call-seq: * str.to_s => str * str.to_str => str * * Returns the receiver. */ static VALUE rb_str_to_s(str) VALUE str; { if (rb_obj_class(str) != rb_cString) { VALUE dup = str_alloc(rb_cString); rb_str_replace(dup, str); return dup; } return str; } /* * call-seq: * str.inspect => string * * Returns a printable version of _str_, with special characters * escaped. * * str = "hello" * str[3] = 8 * str.inspect #=> "hel\010o" */ VALUE rb_str_inspect(str) VALUE str; { char *p, *pend; VALUE result = rb_str_buf_new2("\""); char s[5]; p = RSTRING(str)->ptr; pend = p + RSTRING(str)->len; while (p < pend) { char c = *p++; int len; if (ismbchar(c) && p + (len = mbclen(c)) <= pend) { rb_str_buf_cat(result, p - 1, len); p += len - 1; } else if (c == '"'|| c == '\\' || (c == '#' && IS_EVSTR(p, pend))) { s[0] = '\\'; s[1] = c; rb_str_buf_cat(result, s, 2); } else if (ISPRINT(c)) { s[0] = c; rb_str_buf_cat(result, s, 1); } else if (c == '\n') { s[0] = '\\'; s[1] = 'n'; rb_str_buf_cat(result, s, 2); } else if (c == '\r') { s[0] = '\\'; s[1] = 'r'; rb_str_buf_cat(result, s, 2); } else if (c == '\t') { s[0] = '\\'; s[1] = 't'; rb_str_buf_cat(result, s, 2); } else if (c == '\f') { s[0] = '\\'; s[1] = 'f'; rb_str_buf_cat(result, s, 2); } else if (c == '\013') { s[0] = '\\'; s[1] = 'v'; rb_str_buf_cat(result, s, 2); } else if (c == '\010') { s[0] = '\\'; s[1] = 'b'; rb_str_buf_cat(result, s, 2); } else if (c == '\007') { s[0] = '\\'; s[1] = 'a'; rb_str_buf_cat(result, s, 2); } else if (c == 033) { s[0] = '\\'; s[1] = 'e'; rb_str_buf_cat(result, s, 2); } else { sprintf(s, "\\%03o", c & 0377); rb_str_buf_cat2(result, s); } } rb_str_buf_cat2(result, "\""); OBJ_INFECT(result, str); return result; } /* * call-seq: * str.dump => new_str * * Produces a version of str with all nonprinting characters replaced by * \nnn notation and all special characters escaped. */ VALUE rb_str_dump(str) VALUE str; { long len; char *p, *pend; char *q, *qend; VALUE result; len = 2; /* "" */ p = RSTRING(str)->ptr; pend = p + RSTRING(str)->len; while (p < pend) { char c = *p++; switch (c) { case '"': case '\\': case '\n': case '\r': case '\t': case '\f': case '\013': case '\010': case '\007': case '\033': len += 2; break; case '#': len += IS_EVSTR(p, pend) ? 2 : 1; break; default: if (ISPRINT(c)) { len++; } else { len += 4; /* \nnn */ } break; } } result = rb_str_new5(str, 0, len); p = RSTRING(str)->ptr; pend = p + RSTRING(str)->len; q = RSTRING(result)->ptr; qend = q + len; *q++ = '"'; while (p < pend) { char c = *p++; if (c == '"' || c == '\\') { *q++ = '\\'; *q++ = c; } else if (c == '#') { if (IS_EVSTR(p, pend)) *q++ = '\\'; *q++ = '#'; } else if (ISPRINT(c)) { *q++ = c; } else if (c == '\n') { *q++ = '\\'; *q++ = 'n'; } else if (c == '\r') { *q++ = '\\'; *q++ = 'r'; } else if (c == '\t') { *q++ = '\\'; *q++ = 't'; } else if (c == '\f') { *q++ = '\\'; *q++ = 'f'; } else if (c == '\013') { *q++ = '\\'; *q++ = 'v'; } else if (c == '\010') { *q++ = '\\'; *q++ = 'b'; } else if (c == '\007') { *q++ = '\\'; *q++ = 'a'; } else if (c == '\033') { *q++ = '\\'; *q++ = 'e'; } else { *q++ = '\\'; sprintf(q, "%03o", c&0xff); q += 3; } } *q++ = '"'; OBJ_INFECT(result, str); return result; } /* * call-seq: * str.upcase! => str or nil * * Upcases the contents of str, returning nil if no changes * were made. */ static VALUE rb_str_upcase_bang(str) VALUE str; { char *s, *send; int modify = 0; rb_str_modify(str); s = RSTRING(str)->ptr; send = s + RSTRING(str)->len; while (s < send) { if (ismbchar(*s)) { s+=mbclen(*s) - 1; } else if (ISLOWER(*s)) { *s = toupper(*s); modify = 1; } s++; } if (modify) return str; return Qnil; } /* * call-seq: * str.upcase => new_str * * Returns a copy of str with all lowercase letters replaced with their * uppercase counterparts. The operation is locale insensitive---only * characters ``a'' to ``z'' are affected. * * "hEllO".upcase #=> "HELLO" */ static VALUE rb_str_upcase(str) VALUE str; { str = rb_str_dup(str); rb_str_upcase_bang(str); return str; } /* * call-seq: * str.downcase! => str or nil * * Downcases the contents of str, returning nil if no * changes were made. */ static VALUE rb_str_downcase_bang(str) VALUE str; { char *s, *send; int modify = 0; rb_str_modify(str); s = RSTRING(str)->ptr; send = s + RSTRING(str)->len; while (s < send) { if (ismbchar(*s)) { s+=mbclen(*s) - 1; } else if (ISUPPER(*s)) { *s = tolower(*s); modify = 1; } s++; } if (modify) return str; return Qnil; } /* * call-seq: * str.downcase => new_str * * Returns a copy of str with all uppercase letters replaced with their * lowercase counterparts. The operation is locale insensitive---only * characters ``A'' to ``Z'' are affected. * * "hEllO".downcase #=> "hello" */ static VALUE rb_str_downcase(str) VALUE str; { str = rb_str_dup(str); rb_str_downcase_bang(str); return str; } /* * call-seq: * str.capitalize! => str or nil * * Modifies str by converting the first character to uppercase and the * remainder to lowercase. Returns nil if no changes are made. * * a = "hello" * a.capitalize! #=> "Hello" * a #=> "Hello" * a.capitalize! #=> nil */ static VALUE rb_str_capitalize_bang(str) VALUE str; { char *s, *send; int modify = 0; rb_str_modify(str); if (RSTRING(str)->len == 0 || !RSTRING(str)->ptr) return Qnil; s = RSTRING(str)->ptr; send = s + RSTRING(str)->len; if (ISLOWER(*s)) { *s = toupper(*s); modify = 1; } while (++s < send) { if (ismbchar(*s)) { s+=mbclen(*s) - 1; } else if (ISUPPER(*s)) { *s = tolower(*s); modify = 1; } } if (modify) return str; return Qnil; } /* * call-seq: * str.capitalize => new_str * * Returns a copy of str with the first character converted to uppercase * and the remainder to lowercase. * * "hello".capitalize #=> "Hello" * "HELLO".capitalize #=> "Hello" * "123ABC".capitalize #=> "123abc" */ static VALUE rb_str_capitalize(str) VALUE str; { str = rb_str_dup(str); rb_str_capitalize_bang(str); return str; } /* * call-seq: * str.swapcase! => str or nil * * Equivalent to String#swapcase, but modifies the receiver in * place, returning str, or nil if no changes were made. */ static VALUE rb_str_swapcase_bang(str) VALUE str; { char *s, *send; int modify = 0; rb_str_modify(str); s = RSTRING(str)->ptr; send = s + RSTRING(str)->len; while (s < send) { if (ismbchar(*s)) { s+=mbclen(*s) - 1; } else if (ISUPPER(*s)) { *s = tolower(*s); modify = 1; } else if (ISLOWER(*s)) { *s = toupper(*s); modify = 1; } s++; } if (modify) return str; return Qnil; } /* * call-seq: * str.swapcase => new_str * * Returns a copy of str with uppercase alphabetic characters converted * to lowercase and lowercase characters converted to uppercase. * * "Hello".swapcase #=> "hELLO" * "cYbEr_PuNk11".swapcase #=> "CyBeR_pUnK11" */ static VALUE rb_str_swapcase(str) VALUE str; { str = rb_str_dup(str); rb_str_swapcase_bang(str); return str; } typedef unsigned char *USTR; struct tr { int gen, now, max; char *p, *pend; }; static int trnext(t) struct tr *t; { for (;;) { if (!t->gen) { if (t->p == t->pend) return -1; if (t->p < t->pend - 1 && *t->p == '\\') { t->p++; } t->now = *(USTR)t->p++; if (t->p < t->pend - 1 && *t->p == '-') { t->p++; if (t->p < t->pend) { if (t->now > *(USTR)t->p) { t->p++; continue; } t->gen = 1; t->max = *(USTR)t->p++; } } return t->now; } else if (++t->now < t->max) { return t->now; } else { t->gen = 0; return t->max; } } } static VALUE rb_str_delete_bang _((int,VALUE*,VALUE)); static VALUE tr_trans(str, src, repl, sflag) VALUE str, src, repl; int sflag; { struct tr trsrc, trrepl; int cflag = 0; int trans[256]; int i, c, modify = 0; char *s, *send; StringValue(src); StringValue(repl); if (RSTRING(str)->len == 0 || !RSTRING(str)->ptr) return Qnil; trsrc.p = RSTRING(src)->ptr; trsrc.pend = trsrc.p + RSTRING(src)->len; if (RSTRING(src)->len >= 2 && RSTRING(src)->ptr[0] == '^') { cflag++; trsrc.p++; } if (RSTRING(repl)->len == 0) { return rb_str_delete_bang(1, &src, str); } trrepl.p = RSTRING(repl)->ptr; trrepl.pend = trrepl.p + RSTRING(repl)->len; trsrc.gen = trrepl.gen = 0; trsrc.now = trrepl.now = 0; trsrc.max = trrepl.max = 0; if (cflag) { for (i=0; i<256; i++) { trans[i] = 1; } while ((c = trnext(&trsrc)) >= 0) { trans[c & 0xff] = -1; } while ((c = trnext(&trrepl)) >= 0) /* retrieve last replacer */; for (i=0; i<256; i++) { if (trans[i] >= 0) { trans[i] = trrepl.now; } } } else { int r; for (i=0; i<256; i++) { trans[i] = -1; } while ((c = trnext(&trsrc)) >= 0) { r = trnext(&trrepl); if (r == -1) r = trrepl.now; trans[c & 0xff] = r; } } rb_str_modify(str); s = RSTRING(str)->ptr; send = s + RSTRING(str)->len; if (sflag) { char *t = s; int c0, last = -1; while (s < send) { c0 = *s++; if ((c = trans[c0 & 0xff]) >= 0) { if (last == c) continue; last = c; *t++ = c & 0xff; modify = 1; } else { last = -1; *t++ = c0; } } if (RSTRING(str)->len > (t - RSTRING(str)->ptr)) { RSTRING(str)->len = (t - RSTRING(str)->ptr); modify = 1; *t = '\0'; } } else { while (s < send) { if ((c = trans[*s & 0xff]) >= 0) { *s = c & 0xff; modify = 1; } s++; } } if (modify) return str; return Qnil; } /* * call-seq: * str.tr!(from_str, to_str) => str or nil * * Translates str in place, using the same rules as * String#tr. Returns str, or nil if no * changes were made. */ static VALUE rb_str_tr_bang(str, src, repl) VALUE str, src, repl; { return tr_trans(str, src, repl, 0); } /* * call-seq: * str.tr(from_str, to_str) => new_str * * Returns a copy of str with the characters in from_str replaced * by the corresponding characters in to_str. If to_str is * shorter than from_str, it is padded with its last character. Both * strings may use the c1--c2 notation to denote ranges of characters, and * from_str may start with a ^, which denotes all * characters except those listed. * * "hello".tr('aeiou', '*') #=> "h*ll*" * "hello".tr('^aeiou', '*') #=> "*e**o" * "hello".tr('el', 'ip') #=> "hippo" * "hello".tr('a-y', 'b-z') #=> "ifmmp" */ static VALUE rb_str_tr(str, src, repl) VALUE str, src, repl; { str = rb_str_dup(str); tr_trans(str, src, repl, 0); return str; } static void tr_setup_table(str, table, init) VALUE str; char table[256]; int init; { char buf[256]; struct tr tr; int i, c; int cflag = 0; tr.p = RSTRING(str)->ptr; tr.pend = tr.p + RSTRING(str)->len; tr.gen = tr.now = tr.max = 0; if (RSTRING(str)->len > 1 && RSTRING(str)->ptr[0] == '^') { cflag = 1; tr.p++; } if (init) { for (i=0; i<256; i++) { table[i] = 1; } } for (i=0; i<256; i++) { buf[i] = cflag; } while ((c = trnext(&tr)) >= 0) { buf[c & 0xff] = !cflag; } for (i=0; i<256; i++) { table[i] = table[i] && buf[i]; } } /* * call-seq: * str.delete!([other_str]+>) => str or nil * * Performs a delete operation in place, returning str, or * nil if str was not modified. */ static VALUE rb_str_delete_bang(argc, argv, str) int argc; VALUE *argv; VALUE str; { char *s, *send, *t; char squeez[256]; int modify = 0; int init = 1; int i; if (argc < 1) { rb_raise(rb_eArgError, "wrong number of arguments"); } for (i=0; iptr; if (!s || RSTRING(str)->len == 0) return Qnil; send = s + RSTRING(str)->len; while (s < send) { if (squeez[*s & 0xff]) modify = 1; else *t++ = *s; s++; } *t = '\0'; RSTRING(str)->len = t - RSTRING(str)->ptr; if (modify) return str; return Qnil; } /* * call-seq: * str.delete([other_str]+) => new_str * * Returns a copy of str with all characters in the intersection of its * arguments deleted. Uses the same rules for building the set of characters as * String#count. * * "hello".delete "l","lo" #=> "heo" * "hello".delete "lo" #=> "he" * "hello".delete "aeiou", "^e" #=> "hell" * "hello".delete "ej-m" #=> "ho" */ static VALUE rb_str_delete(argc, argv, str) int argc; VALUE *argv; VALUE str; { str = rb_str_dup(str); rb_str_delete_bang(argc, argv, str); return str; } /* * call-seq: * str.squeeze!([other_str]*) => str or nil * * Squeezes str in place, returning either str, or * nil if no changes were made. */ static VALUE rb_str_squeeze_bang(argc, argv, str) int argc; VALUE *argv; VALUE str; { char squeez[256]; char *s, *send, *t; int c, save, modify = 0; int init = 1; int i; if (argc == 0) { for (i=0; i<256; i++) { squeez[i] = 1; } } else { for (i=0; iptr; if (!s || RSTRING(str)->len == 0) return Qnil; send = s + RSTRING(str)->len; save = -1; while (s < send) { c = *s++ & 0xff; if (c != save || !squeez[c]) { *t++ = save = c; } } *t = '\0'; if (t - RSTRING(str)->ptr != RSTRING(str)->len) { RSTRING(str)->len = t - RSTRING(str)->ptr; modify = 1; } if (modify) return str; return Qnil; } /* * call-seq: * str.squeeze([other_str]*) => new_str * * Builds a set of characters from the other_str parameter(s) using the * procedure described for String#count. Returns a new string * where runs of the same character that occur in this set are replaced by a * single character. If no arguments are given, all runs of identical * characters are replaced by a single character. * * "yellow moon".squeeze #=> "yelow mon" * " now is the".squeeze(" ") #=> " now is the" * "putters shoot balls".squeeze("m-z") #=> "puters shot balls" */ static VALUE rb_str_squeeze(argc, argv, str) int argc; VALUE *argv; VALUE str; { str = rb_str_dup(str); rb_str_squeeze_bang(argc, argv, str); return str; } /* * call-seq: * str.tr_s!(from_str, to_str) => str or nil * * Performs String#tr_s processing on str in place, * returning str, or nil if no changes were made. */ static VALUE rb_str_tr_s_bang(str, src, repl) VALUE str, src, repl; { return tr_trans(str, src, repl, 1); } /* * call-seq: * str.tr_s(from_str, to_str) => new_str * * Processes a copy of str as described under String#tr, * then removes duplicate characters in regions that were affected by the * translation. * * "hello".tr_s('l', 'r') #=> "hero" * "hello".tr_s('el', '*') #=> "h*o" * "hello".tr_s('el', 'hx') #=> "hhxo" */ static VALUE rb_str_tr_s(str, src, repl) VALUE str, src, repl; { str = rb_str_dup(str); tr_trans(str, src, repl, 1); return str; } /* * call-seq: * str.count([other_str]+) => fixnum * * Each other_str parameter defines a set of characters to count. The * intersection of these sets defines the characters to count in * str. Any other_str that starts with a caret (^) is * negated. The sequence c1--c2 means all characters between c1 and c2. * * a = "hello world" * a.count "lo" #=> 5 * a.count "lo", "o" #=> 2 * a.count "hello", "^l" #=> 4 * a.count "ej-m" #=> 4 */ static VALUE rb_str_count(argc, argv, str) int argc; VALUE *argv; VALUE str; { char table[256]; char *s, *send; int init = 1; int i; if (argc < 1) { rb_raise(rb_eArgError, "wrong number of arguments"); } for (i=0; iptr; if (!s || RSTRING(str)->len == 0) return INT2FIX(0); send = s + RSTRING(str)->len; i = 0; while (s < send) { if (table[*s++ & 0xff]) { i++; } } return INT2NUM(i); } /* * call-seq: * str.split(pattern=$;, [limit]) => anArray * * Divides str into substrings based on a delimiter, returning an array * of these substrings. * * If pattern is a String, then its contents are used as * the delimiter when splitting str. If pattern is a single * space, str is split on whitespace, with leading whitespace and runs * of contiguous whitespace characters ignored. * * If pattern is a Regexp, str is divided where the * pattern matches. Whenever the pattern matches a zero-length string, * str is split into individual characters. * * If pattern is omitted, the value of $; is used. If * $; is nil (which is the default), str is * split on whitespace as if ` ' were specified. * * If the limit parameter is omitted, trailing null fields are * suppressed. If limit is a positive number, at most that number of * fields will be returned (if limit is 1, the entire * string is returned as the only entry in an array). If negative, there is no * limit to the number of fields returned, and trailing null fields are not * suppressed. * * " now's the time".split #=> ["now's", "the", "time"] * " now's the time".split(' ') #=> ["now's", "the", "time"] * " now's the time".split(/ /) #=> ["", "now's", "", "the", "time"] * "1, 2.34,56, 7".split(%r{,\s*}) #=> ["1", "2.34", "56", "7"] * "hello".split(//) #=> ["h", "e", "l", "l", "o"] * "hello".split(//, 3) #=> ["h", "e", "llo"] * "hi mom".split(%r{\s*}) #=> ["h", "i", "m", "o", "m"] * * "mellow yellow".split("ello") #=> ["m", "w y", "w"] * "1,2,,3,4,,".split(',') #=> ["1", "2", "", "3", "4"] * "1,2,,3,4,,".split(',', 4) #=> ["1", "2", "", "3,4,,"] * "1,2,,3,4,,".split(',', -4) #=> ["1", "2", "", "3", "4", "", ""] */ static VALUE rb_str_split_m(argc, argv, str) int argc; VALUE *argv; VALUE str; { VALUE spat; VALUE limit; int awk_split = Qfalse; long beg, end, i = 0; int lim = 0; VALUE result, tmp; if (rb_scan_args(argc, argv, "02", &spat, &limit) == 2) { lim = NUM2INT(limit); if (lim <= 0) limit = Qnil; else if (lim == 1) { if (RSTRING(str)->len == 0) return rb_ary_new2(0); return rb_ary_new3(1, str); } i = 1; } if (NIL_P(spat)) { if (!NIL_P(rb_fs)) { spat = rb_fs; goto fs_set; } awk_split = Qtrue; } else { fs_set: if (TYPE(spat) == T_STRING && RSTRING(spat)->len == 1) { if (RSTRING(spat)->ptr[0] == ' ') { awk_split = Qtrue; } else { spat = rb_reg_regcomp(rb_reg_quote(spat)); } } else { spat = get_pat(spat, 1); } } result = rb_ary_new(); beg = 0; if (awk_split) { char *ptr = RSTRING(str)->ptr; long len = RSTRING(str)->len; char *eptr = ptr + len; int skip = 1; for (end = beg = 0; ptr= 0) { regs = RMATCH(rb_backref_get())->regs; if (start == end && BEG(0) == END(0)) { if (!RSTRING(str)->ptr) { rb_ary_push(result, rb_str_new("", 0)); break; } else if (last_null == 1) { rb_ary_push(result, rb_str_substr(str, beg, mbclen2(RSTRING(str)->ptr[beg],spat))); beg = start; } else { start += mbclen2(RSTRING(str)->ptr[start],spat); last_null = 1; continue; } } else { rb_ary_push(result, rb_str_substr(str, beg, end-beg)); beg = start = END(0); } last_null = 0; for (idx=1; idx < regs->num_regs; idx++) { if (BEG(idx) == -1) continue; if (BEG(idx) == END(idx)) tmp = rb_str_new5(str, 0, 0); else tmp = rb_str_substr(str, BEG(idx), END(idx)-BEG(idx)); rb_ary_push(result, tmp); } if (!NIL_P(limit) && lim <= ++i) break; } } if (RSTRING(str)->len > 0 && (!NIL_P(limit) || RSTRING(str)->len > beg || lim < 0)) { if (RSTRING(str)->len == beg) tmp = rb_str_new5(str, 0, 0); else tmp = rb_str_substr(str, beg, RSTRING(str)->len-beg); rb_ary_push(result, tmp); } if (NIL_P(limit) && lim == 0) { while (RARRAY(result)->len > 0 && RSTRING(RARRAY(result)->ptr[RARRAY(result)->len-1])->len == 0) rb_ary_pop(result); } return result; } VALUE rb_str_split(str, sep0) VALUE str; const char *sep0; { VALUE sep; StringValue(str); sep = rb_str_new2(sep0); return rb_str_split_m(1, &sep, str); } /* * call-seq: * split([pattern [, limit]]) => array * * Equivalent to $_.split(pattern, limit). * See String#split. */ static VALUE rb_f_split(argc, argv) int argc; VALUE *argv; { return rb_str_split_m(argc, argv, uscore_get()); } /* * Document-method: lines * call-seq: * str.lines(separator=$/) => anEnumerator * str.lines(separator=$/) {|substr| block } => str * * Returns an enumerator that gives each line in the string. If a block is * given, it iterates over each line in the string. * * "foo\nbar\n".lines.to_a #=> ["foo\n", "bar\n"] * "foo\nb ar".lines.sort #=> ["b ar", "foo\n"] */ /* * call-seq: * str.each(separator=$/) {|substr| block } => str * str.each_line(separator=$/) {|substr| block } => str * * Splits str using the supplied parameter as the record separator * ($/ by default), passing each substring in turn to the supplied * block. If a zero-length record separator is supplied, the string is split * into paragraphs delimited by multiple successive newlines. * * print "Example one\n" * "hello\nworld".each {|s| p s} * print "Example two\n" * "hello\nworld".each('l') {|s| p s} * print "Example three\n" * "hello\n\n\nworld".each('') {|s| p s} * * produces: * * Example one * "hello\n" * "world" * Example two * "hel" * "l" * "o\nworl" * "d" * Example three * "hello\n\n\n" * "world" */ static VALUE rb_str_each_line(argc, argv, str) int argc; VALUE *argv; VALUE str; { VALUE rs; int newline; char *p = RSTRING(str)->ptr, *pend = p + RSTRING(str)->len, *s; char *ptr = p; long len = RSTRING(str)->len, rslen; VALUE line; if (rb_scan_args(argc, argv, "01", &rs) == 0) { rs = rb_rs; } RETURN_ENUMERATOR(str, argc, argv); if (NIL_P(rs)) { rb_yield(str); return str; } StringValue(rs); rslen = RSTRING(rs)->len; if (rslen == 0) { newline = '\n'; } else { newline = RSTRING(rs)->ptr[rslen-1]; } for (s = p, p += rslen; p < pend; p++) { if (rslen == 0 && *p == '\n') { if (*++p != '\n') continue; while (*p == '\n') p++; } if (RSTRING(str)->ptr < p && p[-1] == newline && (rslen <= 1 || rb_memcmp(RSTRING(rs)->ptr, p-rslen, rslen) == 0)) { line = rb_str_new5(str, s, p - s); OBJ_INFECT(line, str); rb_yield(line); str_mod_check(str, ptr, len); s = p; } } if (s != pend) { if (p > pend) p = pend; line = rb_str_new5(str, s, p - s); OBJ_INFECT(line, str); rb_yield(line); } return str; } /* * Document-method: bytes * call-seq: * str.bytes => anEnumerator * str.bytes {|fixnum| block } => str * * Returns an enumerator that gives each byte in the string. If a block is * given, it iterates over each byte in the string. * * "hello".bytes.to_a #=> [104, 101, 108, 108, 111] */ /* * call-seq: * str.each_byte {|fixnum| block } => str * * Passes each byte in str to the given block. * * "hello".each_byte {|c| print c, ' ' } * * produces: * * 104 101 108 108 111 */ static VALUE rb_str_each_byte(str) VALUE str; { long i; RETURN_ENUMERATOR(str, 0, 0); for (i=0; ilen; i++) { rb_yield(INT2FIX(RSTRING(str)->ptr[i] & 0xff)); } return str; } /* * Document-method: chars * call-seq: * str.chars => anEnumerator * str.chars {|substr| block } => str * * Returns an enumerator that gives each character in the string. * If a block is given, it iterates over each character in the string. * * "foo".chars.to_a #=> ["f","o","o"] */ /* * Document-method: each_char * call-seq: * str.each_char {|cstr| block } => str * * Passes each character in str to the given block. * * "hello".each_char {|c| print c, ' ' } * * produces: * * h e l l o */ static VALUE rb_str_each_char(VALUE str) { int i, len, n; const char *ptr; RETURN_ENUMERATOR(str, 0, 0); str = rb_str_new4(str); ptr = RSTRING(str)->ptr; len = RSTRING(str)->len; for (i = 0; i < len; i += n) { n = mbclen(ptr[i]); rb_yield(rb_str_substr(str, i, n)); } return str; } /* * call-seq: * str.chop! => str or nil * * Processes str as for String#chop, returning str, * or nil if str is the empty string. See also * String#chomp!. */ static VALUE rb_str_chop_bang(str) VALUE str; { if (RSTRING(str)->len > 0) { rb_str_modify(str); RSTRING(str)->len--; if (RSTRING(str)->ptr[RSTRING(str)->len] == '\n') { if (RSTRING(str)->len > 0 && RSTRING(str)->ptr[RSTRING(str)->len-1] == '\r') { RSTRING(str)->len--; } } RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; return str; } return Qnil; } /* * call-seq: * str.chop => new_str * * Returns a new String with the last character removed. If the * string ends with \r\n, both characters are removed. Applying * chop to an empty string returns an empty * string. String#chomp is often a safer alternative, as it leaves * the string unchanged if it doesn't end in a record separator. * * "string\r\n".chop #=> "string" * "string\n\r".chop #=> "string\n" * "string\n".chop #=> "string" * "string".chop #=> "strin" * "x".chop.chop #=> "" */ static VALUE rb_str_chop(str) VALUE str; { str = rb_str_dup(str); rb_str_chop_bang(str); return str; } /* * call-seq: * chop! => $_ or nil * * Equivalent to $_.chop!. * * a = "now\r\n" * $_ = a * chop! #=> "now" * chop! #=> "no" * chop! #=> "n" * chop! #=> "" * chop! #=> nil * $_ #=> "" * a #=> "" */ static VALUE rb_f_chop_bang(str) VALUE str; { return rb_str_chop_bang(uscore_get()); } /* * call-seq: * chop => string * * Equivalent to ($_.dup).chop!, except nil * is never returned. See String#chop!. * * a = "now\r\n" * $_ = a * chop #=> "now" * $_ #=> "now" * chop #=> "no" * chop #=> "n" * chop #=> "" * chop #=> "" * a #=> "now\r\n" */ static VALUE rb_f_chop() { VALUE str = uscore_get(); if (RSTRING(str)->len > 0) { str = rb_str_dup(str); rb_str_chop_bang(str); rb_lastline_set(str); } return str; } /* * call-seq: * str.chomp!(separator=$/) => str or nil * * Modifies str in place as described for String#chomp, * returning str, or nil if no modifications were made. */ static VALUE rb_str_chomp_bang(argc, argv, str) int argc; VALUE *argv; VALUE str; { VALUE rs; int newline; char *p; long len, rslen; if (rb_scan_args(argc, argv, "01", &rs) == 0) { len = RSTRING(str)->len; if (len == 0) return Qnil; p = RSTRING(str)->ptr; rs = rb_rs; if (rs == rb_default_rs) { smart_chomp: rb_str_modify(str); if (RSTRING(str)->ptr[len-1] == '\n') { RSTRING(str)->len--; if (RSTRING(str)->len > 0 && RSTRING(str)->ptr[RSTRING(str)->len-1] == '\r') { RSTRING(str)->len--; } } else if (RSTRING(str)->ptr[len-1] == '\r') { RSTRING(str)->len--; } else { return Qnil; } RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; return str; } } if (NIL_P(rs)) return Qnil; StringValue(rs); len = RSTRING(str)->len; if (len == 0) return Qnil; p = RSTRING(str)->ptr; rslen = RSTRING(rs)->len; if (rslen == 0) { while (len>0 && p[len-1] == '\n') { len--; if (len>0 && p[len-1] == '\r') len--; } if (len < RSTRING(str)->len) { rb_str_modify(str); RSTRING(str)->len = len; RSTRING(str)->ptr[len] = '\0'; return str; } return Qnil; } if (rslen > len) return Qnil; newline = RSTRING(rs)->ptr[rslen-1]; if (rslen == 1 && newline == '\n') goto smart_chomp; if (p[len-1] == newline && (rslen <= 1 || rb_memcmp(RSTRING(rs)->ptr, p+len-rslen, rslen) == 0)) { rb_str_modify(str); RSTRING(str)->len -= rslen; RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; return str; } return Qnil; } /* * call-seq: * str.chomp(separator=$/) => new_str * * Returns a new String with the given record separator removed * from the end of str (if present). If $/ has not been * changed from the default Ruby record separator, then chomp also * removes carriage return characters (that is it will remove \n, * \r, and \r\n). * * "hello".chomp #=> "hello" * "hello\n".chomp #=> "hello" * "hello\r\n".chomp #=> "hello" * "hello\n\r".chomp #=> "hello\n" * "hello\r".chomp #=> "hello" * "hello \n there".chomp #=> "hello \n there" * "hello".chomp("llo") #=> "he" */ static VALUE rb_str_chomp(argc, argv, str) int argc; VALUE *argv; VALUE str; { str = rb_str_dup(str); rb_str_chomp_bang(argc, argv, str); return str; } /* * call-seq: * chomp! => $_ or nil * chomp!(string) => $_ or nil * * Equivalent to $_.chomp!(string). See * String#chomp! * * $_ = "now\n" * chomp! #=> "now" * $_ #=> "now" * chomp! "x" #=> nil * $_ #=> "now" */ static VALUE rb_f_chomp_bang(argc, argv) int argc; VALUE *argv; { return rb_str_chomp_bang(argc, argv, uscore_get()); } /* * call-seq: * chomp => $_ * chomp(string) => $_ * * Equivalent to $_ = $_.chomp(string). See * String#chomp. * * $_ = "now\n" * chomp #=> "now" * $_ #=> "now" * chomp "ow" #=> "n" * $_ #=> "n" * chomp "xxx" #=> "n" * $_ #=> "n" */ static VALUE rb_f_chomp(argc, argv) int argc; VALUE *argv; { VALUE str = uscore_get(); VALUE dup = rb_str_dup(str); if (NIL_P(rb_str_chomp_bang(argc, argv, dup))) return str; rb_lastline_set(dup); return dup; } /* * call-seq: * str.lstrip! => self or nil * * Removes leading whitespace from str, returning nil if no * change was made. See also String#rstrip! and * String#strip!. * * " hello ".lstrip #=> "hello " * "hello".lstrip! #=> nil */ static VALUE rb_str_lstrip_bang(str) VALUE str; { char *s, *t, *e; s = RSTRING(str)->ptr; if (!s || RSTRING(str)->len == 0) return Qnil; e = t = s + RSTRING(str)->len; /* remove spaces at head */ while (s < t && ISSPACE(*s)) s++; if (s > RSTRING(str)->ptr) { rb_str_modify(str); RSTRING(str)->len = t-s; memmove(RSTRING(str)->ptr, s, RSTRING(str)->len); RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; return str; } return Qnil; } /* * call-seq: * str.lstrip => new_str * * Returns a copy of str with leading whitespace removed. See also * String#rstrip and String#strip. * * " hello ".lstrip #=> "hello " * "hello".lstrip #=> "hello" */ static VALUE rb_str_lstrip(str) VALUE str; { str = rb_str_dup(str); rb_str_lstrip_bang(str); return str; } /* * call-seq: * str.rstrip! => self or nil * * Removes trailing whitespace from str, returning nil if * no change was made. See also String#lstrip! and * String#strip!. * * " hello ".rstrip #=> " hello" * "hello".rstrip! #=> nil */ static VALUE rb_str_rstrip_bang(str) VALUE str; { char *s, *t, *e; s = RSTRING(str)->ptr; if (!s || RSTRING(str)->len == 0) return Qnil; e = t = s + RSTRING(str)->len; /* remove trailing '\0's */ while (s < t && t[-1] == '\0') t--; /* remove trailing spaces */ while (s < t && ISSPACE(*(t-1))) t--; if (t < e) { rb_str_modify(str); RSTRING(str)->len = t-s; RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; return str; } return Qnil; } /* * call-seq: * str.rstrip => new_str * * Returns a copy of str with trailing whitespace removed. See also * String#lstrip and String#strip. * * " hello ".rstrip #=> " hello" * "hello".rstrip #=> "hello" */ static VALUE rb_str_rstrip(str) VALUE str; { str = rb_str_dup(str); rb_str_rstrip_bang(str); return str; } /* * call-seq: * str.strip! => str or nil * * Removes leading and trailing whitespace from str. Returns * nil if str was not altered. */ static VALUE rb_str_strip_bang(str) VALUE str; { VALUE l = rb_str_lstrip_bang(str); VALUE r = rb_str_rstrip_bang(str); if (NIL_P(l) && NIL_P(r)) return Qnil; return str; } /* * call-seq: * str.strip => new_str * * Returns a copy of str with leading and trailing whitespace removed. * * " hello ".strip #=> "hello" * "\tgoodbye\r\n".strip #=> "goodbye" */ static VALUE rb_str_strip(str) VALUE str; { str = rb_str_dup(str); rb_str_strip_bang(str); return str; } static VALUE scan_once(str, pat, start) VALUE str, pat; long *start; { VALUE result, match; struct re_registers *regs; long i; if (rb_reg_search(pat, str, *start, 0) >= 0) { match = rb_backref_get(); regs = RMATCH(match)->regs; if (BEG(0) == END(0)) { /* * Always consume at least one character of the input string */ if (RSTRING(str)->len > END(0)) *start = END(0)+mbclen2(RSTRING(str)->ptr[END(0)],pat); else *start = END(0)+1; } else { *start = END(0); } if (regs->num_regs == 1) { return rb_reg_nth_match(0, match); } result = rb_ary_new2(regs->num_regs); for (i=1; i < regs->num_regs; i++) { rb_ary_push(result, rb_reg_nth_match(i, match)); } return result; } return Qnil; } /* * call-seq: * str.scan(pattern) => array * str.scan(pattern) {|match, ...| block } => str * * Both forms iterate through str, matching the pattern (which may be a * Regexp or a String). For each match, a result is * generated and either added to the result array or passed to the block. If * the pattern contains no groups, each individual result consists of the * matched string, $&. If the pattern contains groups, each * individual result is itself an array containing one entry per group. * * a = "cruel world" * a.scan(/\w+/) #=> ["cruel", "world"] * a.scan(/.../) #=> ["cru", "el ", "wor"] * a.scan(/(...)/) #=> [["cru"], ["el "], ["wor"]] * a.scan(/(..)(..)/) #=> [["cr", "ue"], ["l ", "wo"]] * * And the block form: * * a.scan(/\w+/) {|w| print "<<#{w}>> " } * print "\n" * a.scan(/(.)(.)/) {|x,y| print y, x } * print "\n" * * produces: * * <> <> * rceu lowlr */ static VALUE rb_str_scan(str, pat) VALUE str, pat; { VALUE result; long start = 0; VALUE match = Qnil; char *p = RSTRING(str)->ptr; long len = RSTRING(str)->len; pat = get_pat(pat, 1); if (!rb_block_given_p()) { VALUE ary = rb_ary_new(); while (!NIL_P(result = scan_once(str, pat, &start))) { match = rb_backref_get(); rb_ary_push(ary, result); } rb_backref_set(match); return ary; } while (!NIL_P(result = scan_once(str, pat, &start))) { match = rb_backref_get(); rb_match_busy(match); rb_yield(result); str_mod_check(str, p, len); rb_backref_set(match); /* restore $~ value */ } rb_backref_set(match); return str; } /* * call-seq: * scan(pattern) => array * scan(pattern) {|///| block } => $_ * * Equivalent to calling $_.scan. See * String#scan. */ static VALUE rb_f_scan(self, pat) VALUE self, pat; { return rb_str_scan(uscore_get(), pat); } /* * call-seq: * str.hex => integer * * Treats leading characters from str as a string of hexadecimal digits * (with an optional sign and an optional 0x) and returns the * corresponding number. Zero is returned on error. * * "0x0a".hex #=> 10 * "-1234".hex #=> -4660 * "0".hex #=> 0 * "wombat".hex #=> 0 */ static VALUE rb_str_hex(str) VALUE str; { return rb_str_to_inum(str, 16, Qfalse); } /* * call-seq: * str.oct => integer * * Treats leading characters of str as a string of octal digits (with an * optional sign) and returns the corresponding number. Returns 0 if the * conversion fails. * * "123".oct #=> 83 * "-377".oct #=> -255 * "bad".oct #=> 0 * "0377bad".oct #=> 255 */ static VALUE rb_str_oct(str) VALUE str; { return rb_str_to_inum(str, -8, Qfalse); } /* * call-seq: * str.crypt(other_str) => new_str * * Applies a one-way cryptographic hash to str by invoking the standard * library function crypt. The argument is the salt string, which * should be two characters long, each character drawn from * [a-zA-Z0-9./]. */ static VALUE rb_str_crypt(str, salt) VALUE str, salt; { extern char *crypt _((const char *, const char*)); VALUE result; const char *s; StringValue(salt); if (RSTRING(salt)->len < 2) rb_raise(rb_eArgError, "salt too short(need >=2 bytes)"); if (RSTRING(str)->ptr) s = RSTRING(str)->ptr; else s = ""; result = rb_str_new2(crypt(s, RSTRING(salt)->ptr)); OBJ_INFECT(result, str); OBJ_INFECT(result, salt); return result; } /* * call-seq: * str.intern => symbol * str.to_sym => symbol * * Returns the Symbol corresponding to str, creating the * symbol if it did not previously exist. See Symbol#id2name. * * "Koala".intern #=> :Koala * s = 'cat'.to_sym #=> :cat * s == :cat #=> true * s = '@cat'.to_sym #=> :@cat * s == :@cat #=> true * * This can also be used to create symbols that cannot be represented using the * :xxx notation. * * 'cat and dog'.to_sym #=> :"cat and dog" */ VALUE rb_str_intern(s) VALUE s; { volatile VALUE str = s; ID id; if (!RSTRING(str)->ptr || RSTRING(str)->len == 0) { rb_raise(rb_eArgError, "interning empty string"); } if (strlen(RSTRING(str)->ptr) != RSTRING(str)->len) rb_raise(rb_eArgError, "symbol string may not contain `\\0'"); if (OBJ_TAINTED(str) && rb_safe_level() >= 1 && !rb_sym_interned_p(str)) { rb_raise(rb_eSecurityError, "Insecure: can't intern tainted string"); } id = rb_intern(RSTRING(str)->ptr); return ID2SYM(id); } /* * call-seq: * str.sum(n=16) => integer * * Returns a basic n-bit checksum of the characters in str, * where n is the optional Fixnum parameter, defaulting * to 16. The result is simply the sum of the binary value of each character in * str modulo 2n - 1. This is not a particularly good * checksum. */ static VALUE rb_str_sum(argc, argv, str) int argc; VALUE *argv; VALUE str; { VALUE vbits; int bits; char *ptr, *p, *pend; long len; if (rb_scan_args(argc, argv, "01", &vbits) == 0) { bits = 16; } else bits = NUM2INT(vbits); ptr = p = RSTRING(str)->ptr; len = RSTRING(str)->len; pend = p + len; if (bits >= sizeof(long)*CHAR_BIT) { VALUE sum = INT2FIX(0); while (p < pend) { str_mod_check(str, ptr, len); sum = rb_funcall(sum, '+', 1, INT2FIX((unsigned char)*p)); p++; } if (bits != 0) { VALUE mod; mod = rb_funcall(INT2FIX(1), rb_intern("<<"), 1, INT2FIX(bits)); mod = rb_funcall(mod, '-', 1, INT2FIX(1)); sum = rb_funcall(sum, '&', 1, mod); } return sum; } else { unsigned long sum = 0; while (p < pend) { str_mod_check(str, ptr, len); sum += (unsigned char)*p; p++; } if (bits != 0) { sum &= (((unsigned long)1)<ptr; flen = RSTRING(pad)->len; if (flen == 0) { rb_raise(rb_eArgError, "zero width padding"); } } if (width < 0 || RSTRING(str)->len >= width) return rb_str_dup(str); res = rb_str_new5(str, 0, width); p = RSTRING(res)->ptr; if (jflag != 'l') { n = width - RSTRING(str)->len; pend = p + ((jflag == 'r') ? n : n/2); if (flen <= 1) { while (p < pend) { *p++ = *f; } } else { const char *q = f; while (p + flen <= pend) { memcpy(p,f,flen); p += flen; } while (p < pend) { *p++ = *q++; } } } memcpy(p, RSTRING(str)->ptr, RSTRING(str)->len); if (jflag != 'r') { p += RSTRING(str)->len; pend = RSTRING(res)->ptr + width; if (flen <= 1) { while (p < pend) { *p++ = *f; } } else { while (p + flen <= pend) { memcpy(p,f,flen); p += flen; } while (p < pend) { *p++ = *f++; } } } OBJ_INFECT(res, str); if (flen > 0) OBJ_INFECT(res, pad); return res; } /* * call-seq: * str.ljust(integer, padstr=' ') => new_str * * If integer is greater than the length of str, returns a new * String of length integer with str left justified * and padded with padstr; otherwise, returns str. * * "hello".ljust(4) #=> "hello" * "hello".ljust(20) #=> "hello " * "hello".ljust(20, '1234') #=> "hello123412341234123" */ static VALUE rb_str_ljust(argc, argv, str) int argc; VALUE *argv; VALUE str; { return rb_str_justify(argc, argv, str, 'l'); } /* * call-seq: * str.rjust(integer, padstr=' ') => new_str * * If integer is greater than the length of str, returns a new * String of length integer with str right justified * and padded with padstr; otherwise, returns str. * * "hello".rjust(4) #=> "hello" * "hello".rjust(20) #=> " hello" * "hello".rjust(20, '1234') #=> "123412341234123hello" */ static VALUE rb_str_rjust(argc, argv, str) int argc; VALUE *argv; VALUE str; { return rb_str_justify(argc, argv, str, 'r'); } /* * call-seq: * str.center(integer, padstr) => new_str * * If integer is greater than the length of str, returns a new * String of length integer with str centered and * padded with padstr; otherwise, returns str. * * "hello".center(4) #=> "hello" * "hello".center(20) #=> " hello " * "hello".center(20, '123') #=> "1231231hello12312312" */ static VALUE rb_str_center(argc, argv, str) int argc; VALUE *argv; VALUE str; { return rb_str_justify(argc, argv, str, 'c'); } /* * call-seq: * str.partition(sep) => [head, sep, tail] * * Searches the string for sep and returns the part before it, * the sep, and the part after it. If sep is not * found, returns str and two empty strings. If no argument * is given, Enumerable#partition is called. * * "hello".partition("l") #=> ["he", "l", "lo"] * "hello".partition("x") #=> ["hello", "", ""] */ static VALUE rb_str_partition(argc, argv, str) int argc; VALUE *argv; VALUE str; { VALUE sep; long pos; if (argc == 0) return rb_call_super(argc, argv); rb_scan_args(argc, argv, "1", &sep); if (TYPE(sep) != T_REGEXP) { VALUE tmp; tmp = rb_check_string_type(sep); if (NIL_P(tmp)) { rb_raise(rb_eTypeError, "type mismatch: %s given", rb_obj_classname(sep)); } sep = get_arg_pat(tmp); } pos = rb_reg_search(sep, str, 0, 0); if (pos < 0) { failed: return rb_ary_new3(3, str, rb_str_new(0,0),rb_str_new(0,0)); } sep = rb_str_subpat(str, sep, 0); if (pos == 0 && RSTRING(sep)->len == 0) goto failed; return rb_ary_new3(3, rb_str_substr(str, 0, pos), sep, rb_str_substr(str, pos+RSTRING(sep)->len, RSTRING(str)->len-pos-RSTRING(sep)->len)); } /* * call-seq: * str.rpartition(sep) => [head, sep, tail] * * Searches sep in the string from the end of the string, and * returns the part before it, the sep, and the part after it. * If sep is not found, returns two empty strings and * str. * * "hello".rpartition("l") #=> ["hel", "l", "o"] * "hello".rpartition("x") #=> ["", "", "hello"] */ static VALUE rb_str_rpartition(str, sep) VALUE str; VALUE sep; { long pos = RSTRING(str)->len; if (TYPE(sep) != T_REGEXP) { VALUE tmp; tmp = rb_check_string_type(sep); if (NIL_P(tmp)) { rb_raise(rb_eTypeError, "type mismatch: %s given", rb_obj_classname(sep)); } sep = get_arg_pat(tmp); } pos = rb_reg_search(sep, str, pos, 1); if (pos < 0) { return rb_ary_new3(3, rb_str_new(0,0),rb_str_new(0,0), str); } sep = rb_reg_nth_match(0, rb_backref_get()); return rb_ary_new3(3, rb_str_substr(str, 0, pos), sep, rb_str_substr(str, pos+RSTRING(sep)->len, RSTRING(str)->len-pos-RSTRING(sep)->len)); } /* * call-seq: * str.start_with?([prefix]+) => true or false * * Returns true if str starts with the prefix given. */ static VALUE rb_str_start_with(argc, argv, str) int argc; VALUE *argv; VALUE str; { int i; VALUE pat; for (i=0; ilen < RSTRING(prefix)->len) continue; pat = get_arg_pat(prefix); if (rb_reg_search(pat, str, 0, 1) >= 0) return Qtrue; } return Qfalse; } /* * call-seq: * str.end_with?([suffix]+) => true or false * * Returns true if str ends with the suffix given. */ static VALUE rb_str_end_with(argc, argv, str) int argc; VALUE *argv; VALUE str; { int i; long pos; VALUE pat; for (i=0; ilen < RSTRING(suffix)->len) continue; pat = get_arg_pat(suffix); pos = rb_reg_adjust_startpos(pat, str, RSTRING(str)->len - RSTRING(suffix)->len, 0); if (rb_reg_search(pat, str, pos, 0) >= 0) return Qtrue; } return Qfalse; } void rb_str_setter(val, id, var) VALUE val; ID id; VALUE *var; { if (!NIL_P(val) && TYPE(val) != T_STRING) { rb_raise(rb_eTypeError, "value of %s must be String", rb_id2name(id)); } *var = val; } /* * A String object holds and manipulates an arbitrary sequence of * bytes, typically representing characters. String objects may be created * using String::new or as literals. * * Because of aliasing issues, users of strings should be aware of the methods * that modify the contents of a String object. Typically, * methods with names ending in ``!'' modify their receiver, while those * without a ``!'' return a new String. However, there are * exceptions, such as String#[]=. * */ void Init_String() { rb_cString = rb_define_class("String", rb_cObject); rb_include_module(rb_cString, rb_mComparable); rb_include_module(rb_cString, rb_mEnumerable); rb_define_alloc_func(rb_cString, rb_str_s_alloc); rb_define_method(rb_cString, "initialize", rb_str_init, -1); rb_define_method(rb_cString, "initialize_copy", rb_str_replace, 1); rb_define_method(rb_cString, "<=>", rb_str_cmp_m, 1); rb_define_method(rb_cString, "==", rb_str_equal, 1); rb_define_method(rb_cString, "eql?", rb_str_eql, 1); rb_define_method(rb_cString, "hash", rb_str_hash_m, 0); rb_define_method(rb_cString, "casecmp", rb_str_casecmp, 1); rb_define_method(rb_cString, "+", rb_str_plus, 1); rb_define_method(rb_cString, "*", rb_str_times, 1); rb_define_method(rb_cString, "%", rb_str_format_m, 1); rb_define_method(rb_cString, "[]", rb_str_aref_m, -1); rb_define_method(rb_cString, "[]=", rb_str_aset_m, -1); rb_define_method(rb_cString, "insert", rb_str_insert, 2); rb_define_method(rb_cString, "length", rb_str_length, 0); rb_define_method(rb_cString, "size", rb_str_length, 0); rb_define_method(rb_cString, "bytesize", rb_str_length, 0); rb_define_method(rb_cString, "empty?", rb_str_empty, 0); rb_define_method(rb_cString, "=~", rb_str_match, 1); rb_define_method(rb_cString, "match", rb_str_match_m, 1); rb_define_method(rb_cString, "succ", rb_str_succ, 0); rb_define_method(rb_cString, "succ!", rb_str_succ_bang, 0); rb_define_method(rb_cString, "next", rb_str_succ, 0); rb_define_method(rb_cString, "next!", rb_str_succ_bang, 0); rb_define_method(rb_cString, "upto", rb_str_upto_m, -1); rb_define_method(rb_cString, "index", rb_str_index_m, -1); rb_define_method(rb_cString, "rindex", rb_str_rindex_m, -1); rb_define_method(rb_cString, "replace", rb_str_replace, 1); rb_define_method(rb_cString, "to_i", rb_str_to_i, -1); rb_define_method(rb_cString, "to_f", rb_str_to_f, 0); rb_define_method(rb_cString, "to_s", rb_str_to_s, 0); rb_define_method(rb_cString, "to_str", rb_str_to_s, 0); rb_define_method(rb_cString, "inspect", rb_str_inspect, 0); rb_define_method(rb_cString, "dump", rb_str_dump, 0); rb_define_method(rb_cString, "upcase", rb_str_upcase, 0); rb_define_method(rb_cString, "downcase", rb_str_downcase, 0); rb_define_method(rb_cString, "capitalize", rb_str_capitalize, 0); rb_define_method(rb_cString, "swapcase", rb_str_swapcase, 0); rb_define_method(rb_cString, "upcase!", rb_str_upcase_bang, 0); rb_define_method(rb_cString, "downcase!", rb_str_downcase_bang, 0); rb_define_method(rb_cString, "capitalize!", rb_str_capitalize_bang, 0); rb_define_method(rb_cString, "swapcase!", rb_str_swapcase_bang, 0); rb_define_method(rb_cString, "hex", rb_str_hex, 0); rb_define_method(rb_cString, "oct", rb_str_oct, 0); rb_define_method(rb_cString, "split", rb_str_split_m, -1); rb_define_method(rb_cString, "reverse", rb_str_reverse, 0); rb_define_method(rb_cString, "reverse!", rb_str_reverse_bang, 0); rb_define_method(rb_cString, "concat", rb_str_concat, 1); rb_define_method(rb_cString, "<<", rb_str_concat, 1); rb_define_method(rb_cString, "crypt", rb_str_crypt, 1); rb_define_method(rb_cString, "intern", rb_str_intern, 0); rb_define_method(rb_cString, "to_sym", rb_str_intern, 0); rb_define_method(rb_cString, "include?", rb_str_include, 1); rb_define_method(rb_cString, "start_with?", rb_str_start_with, -1); rb_define_method(rb_cString, "end_with?", rb_str_end_with, -1); rb_define_method(rb_cString, "scan", rb_str_scan, 1); rb_define_method(rb_cString, "ljust", rb_str_ljust, -1); rb_define_method(rb_cString, "rjust", rb_str_rjust, -1); rb_define_method(rb_cString, "center", rb_str_center, -1); rb_define_method(rb_cString, "sub", rb_str_sub, -1); rb_define_method(rb_cString, "gsub", rb_str_gsub, -1); rb_define_method(rb_cString, "chop", rb_str_chop, 0); rb_define_method(rb_cString, "chomp", rb_str_chomp, -1); rb_define_method(rb_cString, "strip", rb_str_strip, 0); rb_define_method(rb_cString, "lstrip", rb_str_lstrip, 0); rb_define_method(rb_cString, "rstrip", rb_str_rstrip, 0); rb_define_method(rb_cString, "sub!", rb_str_sub_bang, -1); rb_define_method(rb_cString, "gsub!", rb_str_gsub_bang, -1); rb_define_method(rb_cString, "chop!", rb_str_chop_bang, 0); rb_define_method(rb_cString, "chomp!", rb_str_chomp_bang, -1); rb_define_method(rb_cString, "strip!", rb_str_strip_bang, 0); rb_define_method(rb_cString, "lstrip!", rb_str_lstrip_bang, 0); rb_define_method(rb_cString, "rstrip!", rb_str_rstrip_bang, 0); rb_define_method(rb_cString, "tr", rb_str_tr, 2); rb_define_method(rb_cString, "tr_s", rb_str_tr_s, 2); rb_define_method(rb_cString, "delete", rb_str_delete, -1); rb_define_method(rb_cString, "squeeze", rb_str_squeeze, -1); rb_define_method(rb_cString, "count", rb_str_count, -1); rb_define_method(rb_cString, "tr!", rb_str_tr_bang, 2); rb_define_method(rb_cString, "tr_s!", rb_str_tr_s_bang, 2); rb_define_method(rb_cString, "delete!", rb_str_delete_bang, -1); rb_define_method(rb_cString, "squeeze!", rb_str_squeeze_bang, -1); rb_define_method(rb_cString, "each_line", rb_str_each_line, -1); rb_define_method(rb_cString, "each", rb_str_each_line, -1); rb_define_method(rb_cString, "each_byte", rb_str_each_byte, 0); rb_define_method(rb_cString, "each_char", rb_str_each_char, 0); rb_define_method(rb_cString, "lines", rb_str_each_line, -1); rb_define_method(rb_cString, "bytes", rb_str_each_byte, 0); rb_define_method(rb_cString, "chars", rb_str_each_char, 0); rb_define_method(rb_cString, "sum", rb_str_sum, -1); rb_define_global_function("sub", rb_f_sub, -1); rb_define_global_function("gsub", rb_f_gsub, -1); rb_define_global_function("sub!", rb_f_sub_bang, -1); rb_define_global_function("gsub!", rb_f_gsub_bang, -1); rb_define_global_function("chop", rb_f_chop, 0); rb_define_global_function("chop!", rb_f_chop_bang, 0); rb_define_global_function("chomp", rb_f_chomp, -1); rb_define_global_function("chomp!", rb_f_chomp_bang, -1); rb_define_global_function("split", rb_f_split, -1); rb_define_global_function("scan", rb_f_scan, 1); rb_define_method(rb_cString, "slice", rb_str_aref_m, -1); rb_define_method(rb_cString, "slice!", rb_str_slice_bang, -1); rb_define_method(rb_cString, "partition", rb_str_partition, -1); rb_define_method(rb_cString, "rpartition", rb_str_rpartition, 1); #ifdef GC_DEBUG rb_define_method(rb_cString, "__char_ptr__", rb_str_char_ptr, 0); #endif id_to_s = rb_intern("to_s"); rb_fs = Qnil; rb_define_variable("$;", &rb_fs); rb_define_variable("$-F", &rb_fs); } ================================================ FILE: struct.c ================================================ /********************************************************************** struct.c - $Author$ $Date$ created at: Tue Mar 22 18:44:30 JST 1995 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #include "ruby.h" #include "env.h" VALUE rb_cStruct; static VALUE struct_alloc _((VALUE)); VALUE rb_struct_iv_get(c, name) VALUE c; const char *name; { ID id; id = rb_intern(name); for (;;) { if (rb_ivar_defined(c, id)) return rb_ivar_get(c, id); c = RCLASS(c)->super; if (c == 0 || c == rb_cStruct) return Qnil; } } VALUE rb_struct_s_members(klass) VALUE klass; { VALUE members = rb_struct_iv_get(klass, "__members__"); if (NIL_P(members)) { rb_raise(rb_eTypeError, "uninitialized struct"); } if (TYPE(members) != T_ARRAY) { rb_raise(rb_eTypeError, "corrupted struct"); } return members; } VALUE rb_struct_members(s) VALUE s; { VALUE members = rb_struct_s_members(rb_obj_class(s)); if (RSTRUCT(s)->len != RARRAY(members)->len) { rb_raise(rb_eTypeError, "struct size differs (%d required %d given)", RARRAY(members)->len, RSTRUCT(s)->len); } return members; } static VALUE rb_struct_s_members_m(klass) VALUE klass; { VALUE members, ary; VALUE *p, *pend; members = rb_struct_s_members(klass); ary = rb_ary_new2(RARRAY(members)->len); p = RARRAY(members)->ptr; pend = p + RARRAY(members)->len; while (p < pend) { rb_ary_push(ary, rb_str_new2(rb_id2name(SYM2ID(*p)))); p++; } return ary; } /* * call-seq: * struct.members => array * * Returns an array of strings representing the names of the instance * variables. * * Customer = Struct.new(:name, :address, :zip) * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) * joe.members #=> ["name", "address", "zip"] */ static VALUE rb_struct_members_m(obj) VALUE obj; { return rb_struct_s_members_m(rb_obj_class(obj)); } VALUE rb_struct_getmember(obj, id) VALUE obj; ID id; { VALUE members, slot; long i; members = rb_struct_members(obj); slot = ID2SYM(id); for (i=0; ilen; i++) { if (RARRAY(members)->ptr[i] == slot) { return RSTRUCT(obj)->ptr[i]; } } rb_name_error(id, "%s is not struct member", rb_id2name(id)); return Qnil; /* not reached */ } static VALUE rb_struct_ref(obj) VALUE obj; { return rb_struct_getmember(obj, ruby_frame->orig_func); } static VALUE rb_struct_ref0(obj) VALUE obj; {return RSTRUCT(obj)->ptr[0];} static VALUE rb_struct_ref1(obj) VALUE obj; {return RSTRUCT(obj)->ptr[1];} static VALUE rb_struct_ref2(obj) VALUE obj; {return RSTRUCT(obj)->ptr[2];} static VALUE rb_struct_ref3(obj) VALUE obj; {return RSTRUCT(obj)->ptr[3];} static VALUE rb_struct_ref4(obj) VALUE obj; {return RSTRUCT(obj)->ptr[4];} static VALUE rb_struct_ref5(obj) VALUE obj; {return RSTRUCT(obj)->ptr[5];} static VALUE rb_struct_ref6(obj) VALUE obj; {return RSTRUCT(obj)->ptr[6];} static VALUE rb_struct_ref7(obj) VALUE obj; {return RSTRUCT(obj)->ptr[7];} static VALUE rb_struct_ref8(obj) VALUE obj; {return RSTRUCT(obj)->ptr[8];} static VALUE rb_struct_ref9(obj) VALUE obj; {return RSTRUCT(obj)->ptr[9];} static VALUE (*ref_func[10])() = { rb_struct_ref0, rb_struct_ref1, rb_struct_ref2, rb_struct_ref3, rb_struct_ref4, rb_struct_ref5, rb_struct_ref6, rb_struct_ref7, rb_struct_ref8, rb_struct_ref9, }; static void rb_struct_modify(s) VALUE s; { if (OBJ_FROZEN(s)) rb_error_frozen("Struct"); if (!OBJ_TAINTED(s) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify Struct"); } static VALUE rb_struct_set(obj, val) VALUE obj, val; { VALUE members, slot; ID id; long i; members = rb_struct_members(obj); rb_struct_modify(obj); id = ruby_frame->orig_func; for (i=0; ilen; i++) { slot = RARRAY(members)->ptr[i]; if (rb_id_attrset(SYM2ID(slot)) == id) { return RSTRUCT(obj)->ptr[i] = val; } } rb_name_error(ruby_frame->last_func, "`%s' is not a struct member", rb_id2name(id)); return Qnil; /* not reached */ } static VALUE make_struct(name, members, klass) VALUE name, members, klass; { VALUE nstr; ID id; long i; OBJ_FREEZE(members); if (NIL_P(name)) { nstr = rb_class_new(klass); rb_make_metaclass(nstr, RBASIC(klass)->klass); rb_class_inherited(klass, nstr); } else { char *cname = StringValuePtr(name); id = rb_intern(cname); if (!rb_is_const_id(id)) { rb_name_error(id, "identifier %s needs to be constant", cname); } if (rb_const_defined_at(klass, id)) { rb_warn("redefining constant Struct::%s", cname); rb_mod_remove_const(klass, ID2SYM(id)); } nstr = rb_define_class_under(klass, rb_id2name(id), klass); } rb_iv_set(nstr, "__size__", LONG2NUM(RARRAY(members)->len)); rb_iv_set(nstr, "__members__", members); rb_define_alloc_func(nstr, struct_alloc); rb_define_singleton_method(nstr, "new", rb_class_new_instance, -1); rb_define_singleton_method(nstr, "[]", rb_class_new_instance, -1); rb_define_singleton_method(nstr, "members", rb_struct_s_members_m, 0); for (i=0; i< RARRAY(members)->len; i++) { ID id = SYM2ID(RARRAY(members)->ptr[i]); if (rb_is_local_id(id) || rb_is_const_id(id)) { if (i<10) { rb_define_method_id(nstr, id, ref_func[i], 0); } else { rb_define_method_id(nstr, id, rb_struct_ref, 0); } rb_define_method_id(nstr, rb_id_attrset(id), rb_struct_set, 1); } } return nstr; } #ifdef HAVE_STDARG_PROTOTYPES #include #define va_init_list(a,b) va_start(a,b) #else #include #define va_init_list(a,b) va_start(a) #endif VALUE #ifdef HAVE_STDARG_PROTOTYPES rb_struct_define(const char *name, ...) #else rb_struct_define(name, va_alist) const char *name; va_dcl #endif { va_list ar; VALUE nm, ary; char *mem; if (!name) nm = Qnil; else nm = rb_str_new2(name); ary = rb_ary_new(); va_init_list(ar, name); while ((mem = va_arg(ar, char*)) != 0) { ID slot = rb_intern(mem); rb_ary_push(ary, ID2SYM(slot)); } va_end(ar); return make_struct(nm, ary, rb_cStruct); } /* * call-seq: * Struct.new( [aString] [, aSym]+> ) => StructClass * StructClass.new(arg, ...) => obj * StructClass[arg, ...] => obj * * Creates a new class, named by aString, containing accessor * methods for the given symbols. If the name aString is * omitted, an anonymous structure class will be created. Otherwise, * the name of this struct will appear as a constant in class * Struct, so it must be unique for all * Structs in the system and should start with a capital * letter. Assigning a structure class to a constant effectively gives * the class the name of the constant. * * Struct::new returns a new Class object, * which can then be used to create specific instances of the new * structure. The number of actual parameters must be * less than or equal to the number of attributes defined for this * class; unset parameters default to \nil{}. Passing too many * parameters will raise an \E{ArgumentError}. * * The remaining methods listed in this section (class and instance) * are defined for this generated class. * * # Create a structure with a name in Struct * Struct.new("Customer", :name, :address) #=> Struct::Customer * Struct::Customer.new("Dave", "123 Main") #=> # * * # Create a structure named by its constant * Customer = Struct.new(:name, :address) #=> Customer * Customer.new("Dave", "123 Main") #=> # */ static VALUE rb_struct_s_def(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { VALUE name, rest; long i; VALUE st; ID id; rb_scan_args(argc, argv, "1*", &name, &rest); if (!NIL_P(name) && SYMBOL_P(name)) { rb_ary_unshift(rest, name); name = Qnil; } for (i=0; ilen; i++) { id = rb_to_id(RARRAY(rest)->ptr[i]); RARRAY(rest)->ptr[i] = ID2SYM(id); } st = make_struct(name, rest, klass); if (rb_block_given_p()) { rb_mod_module_eval(0, 0, st); } return st; } /* */ static VALUE rb_struct_initialize(self, values) VALUE self, values; { VALUE klass = rb_obj_class(self); VALUE size; long n; rb_struct_modify(self); size = rb_struct_iv_get(klass, "__size__"); n = FIX2LONG(size); if (n < RARRAY(values)->len) { rb_raise(rb_eArgError, "struct size differs"); } MEMCPY(RSTRUCT(self)->ptr, RARRAY(values)->ptr, VALUE, RARRAY(values)->len); if (n > RARRAY(values)->len) { rb_mem_clear(RSTRUCT(self)->ptr+RARRAY(values)->len, n-RARRAY(values)->len); } return Qnil; } static VALUE struct_alloc(klass) VALUE klass; { VALUE size; long n; NEWOBJ(st, struct RStruct); OBJSETUP(st, klass, T_STRUCT); size = rb_struct_iv_get(klass, "__size__"); n = FIX2LONG(size); st->ptr = ALLOC_N(VALUE, n); rb_mem_clear(st->ptr, n); st->len = n; return (VALUE)st; } VALUE rb_struct_alloc(klass, values) VALUE klass, values; { return rb_class_new_instance(RARRAY(values)->len, RARRAY(values)->ptr, klass); } VALUE #ifdef HAVE_STDARG_PROTOTYPES rb_struct_new(VALUE klass, ...) #else rb_struct_new(klass, va_alist) VALUE klass; va_dcl #endif { VALUE sz, *mem; long size, i; va_list args; sz = rb_struct_iv_get(klass, "__size__"); size = FIX2LONG(sz); mem = ALLOCA_N(VALUE, size); va_init_list(args, klass); for (i=0; i struct * * Calls block once for each instance variable, passing the * value as a parameter. * * Customer = Struct.new(:name, :address, :zip) * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) * joe.each {|x| puts(x) } * * produces: * * Joe Smith * 123 Maple, Anytown NC * 12345 */ static VALUE rb_struct_each(s) VALUE s; { long i; RETURN_ENUMERATOR(s, 0, 0); for (i=0; ilen; i++) { rb_yield(RSTRUCT(s)->ptr[i]); } return s; } /* * call-seq: * struct.each_pair {|sym, obj| block } => struct * * Calls block once for each instance variable, passing the name * (as a symbol) and the value as parameters. * * Customer = Struct.new(:name, :address, :zip) * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) * joe.each_pair {|name, value| puts("#{name} => #{value}") } * * produces: * * name => Joe Smith * address => 123 Maple, Anytown NC * zip => 12345 */ static VALUE rb_struct_each_pair(s) VALUE s; { VALUE members; long i; RETURN_ENUMERATOR(s, 0, 0); members = rb_struct_members(s); for (i=0; ilen; i++) { rb_yield_values(2, rb_ary_entry(members, i), RSTRUCT(s)->ptr[i]); } return s; } static VALUE inspect_struct(s) VALUE s; { const char *cname = rb_class2name(rb_obj_class(s)); VALUE str, members; long i; members = rb_struct_members(s); str = rb_str_buf_new2("#len; i++) { VALUE slot; ID id; const char *p; if (i > 0) { rb_str_cat2(str, ", "); } slot = RARRAY(members)->ptr[i]; id = SYM2ID(slot); if (rb_is_local_id(id) || rb_is_const_id(id)) { p = rb_id2name(id); rb_str_cat2(str, p); } else { rb_str_append(str, rb_inspect(slot)); } rb_str_cat2(str, "="); rb_str_append(str, rb_inspect(RSTRUCT(s)->ptr[i])); } rb_str_cat2(str, ">"); OBJ_INFECT(str, s); return str; } /* * call-seq: * struct.to_s => string * struct.inspect => string * * Describe the contents of this struct in a string. */ static VALUE rb_struct_inspect(s) VALUE s; { if (rb_inspecting_p(s)) { const char *cname = rb_class2name(rb_obj_class(s)); size_t len = strlen(cname) + 14; VALUE str = rb_str_new(0, len); snprintf(RSTRING(str)->ptr, len+1, "#", cname); RSTRING(str)->len = strlen(RSTRING(str)->ptr); return str; } return rb_protect_inspect(inspect_struct, s, 0); } /* * call-seq: * struct.to_a => array * struct.values => array * * Returns the values for this instance as an array. * * Customer = Struct.new(:name, :address, :zip) * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) * joe.to_a[1] #=> "123 Maple, Anytown NC" */ static VALUE rb_struct_to_a(s) VALUE s; { return rb_ary_new4(RSTRUCT(s)->len, RSTRUCT(s)->ptr); } /* :nodoc: */ static VALUE rb_struct_init_copy(copy, s) VALUE copy, s; { if (copy == s) return copy; rb_check_frozen(copy); if (!rb_obj_is_instance_of(s, rb_obj_class(copy))) { rb_raise(rb_eTypeError, "wrong argument class"); } if (RSTRUCT(copy)->len != RSTRUCT(s)->len) { rb_raise(rb_eTypeError, "struct size mismatch"); } MEMCPY(RSTRUCT(copy)->ptr, RSTRUCT(s)->ptr, VALUE, RSTRUCT(copy)->len); return copy; } static VALUE rb_struct_aref_id(s, id) VALUE s; ID id; { VALUE members; long i, len; members = rb_struct_members(s); len = RARRAY(members)->len; for (i=0; iptr[i]) == id) { return RSTRUCT(s)->ptr[i]; } } rb_name_error(id, "no member '%s' in struct", rb_id2name(id)); return Qnil; /* not reached */ } /* * call-seq: * struct[symbol] => anObject * struct[fixnum] => anObject * * Attribute Reference---Returns the value of the instance variable * named by symbol, or indexed (0..length-1) by * fixnum. Will raise NameError if the named * variable does not exist, or IndexError if the index is * out of range. * * Customer = Struct.new(:name, :address, :zip) * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) * * joe["name"] #=> "Joe Smith" * joe[:name] #=> "Joe Smith" * joe[0] #=> "Joe Smith" */ VALUE rb_struct_aref(s, idx) VALUE s, idx; { long i; if (TYPE(idx) == T_STRING || TYPE(idx) == T_SYMBOL) { return rb_struct_aref_id(s, rb_to_id(idx)); } i = NUM2LONG(idx); if (i < 0) i = RSTRUCT(s)->len + i; if (i < 0) rb_raise(rb_eIndexError, "offset %ld too small for struct(size:%ld)", i, RSTRUCT(s)->len); if (RSTRUCT(s)->len <= i) rb_raise(rb_eIndexError, "offset %ld too large for struct(size:%ld)", i, RSTRUCT(s)->len); return RSTRUCT(s)->ptr[i]; } static VALUE rb_struct_aset_id(s, id, val) VALUE s, val; ID id; { VALUE members; long i, len; members = rb_struct_members(s); rb_struct_modify(s); len = RARRAY(members)->len; if (RSTRUCT(s)->len != RARRAY(members)->len) { rb_raise(rb_eTypeError, "struct size differs (%d required %d given)", RARRAY(members)->len, RSTRUCT(s)->len); } for (i=0; iptr[i]) == id) { RSTRUCT(s)->ptr[i] = val; return val; } } rb_name_error(id, "no member '%s' in struct", rb_id2name(id)); } /* * call-seq: * struct[symbol] = obj => obj * struct[fixnum] = obj => obj * * Attribute Assignment---Assigns to the instance variable named by * symbol or fixnum the value obj and * returns it. Will raise a NameError if the named * variable does not exist, or an IndexError if the index * is out of range. * * Customer = Struct.new(:name, :address, :zip) * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) * * joe["name"] = "Luke" * joe[:zip] = "90210" * * joe.name #=> "Luke" * joe.zip #=> "90210" */ VALUE rb_struct_aset(s, idx, val) VALUE s, idx, val; { long i; if (TYPE(idx) == T_STRING || TYPE(idx) == T_SYMBOL) { return rb_struct_aset_id(s, rb_to_id(idx), val); } i = NUM2LONG(idx); if (i < 0) i = RSTRUCT(s)->len + i; if (i < 0) { rb_raise(rb_eIndexError, "offset %ld too small for struct(size:%ld)", i, RSTRUCT(s)->len); } if (RSTRUCT(s)->len <= i) { rb_raise(rb_eIndexError, "offset %ld too large for struct(size:%ld)", i, RSTRUCT(s)->len); } rb_struct_modify(s); return RSTRUCT(s)->ptr[i] = val; } static VALUE struct_entry _((VALUE, long)); static VALUE struct_entry(s, n) VALUE s; long n; { return rb_struct_aref(s, LONG2NUM(n)); } /* * call-seq: * struct.values_at(selector,... ) => an_array * * Returns an array containing the elements in * _self_ corresponding to the given selector(s). The selectors * may be either integer indices or ranges. * See also .select. * * a = %w{ a b c d e f } * a.values_at(1, 3, 5) * a.values_at(1, 3, 5, 7) * a.values_at(-1, -3, -5, -7) * a.values_at(1..3, 2...5) */ static VALUE rb_struct_values_at(argc, argv, s) int argc; VALUE *argv; VALUE s; { return rb_values_at(s, RSTRUCT(s)->len, argc, argv, struct_entry); } /* * call-seq: * struct.select {|i| block } => array * * Invokes the block passing in successive elements from * struct, returning an array containing those elements * for which the block returns a true value (equivalent to * Enumerable#select). * * Lots = Struct.new(:a, :b, :c, :d, :e, :f) * l = Lots.new(11, 22, 33, 44, 55, 66) * l.select {|v| (v % 2).zero? } #=> [22, 44, 66] */ static VALUE rb_struct_select(argc, argv, s) int argc; VALUE *argv; VALUE s; { VALUE result; long i; if (argc > 0) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc); } result = rb_ary_new(); for (i = 0; i < RSTRUCT(s)->len; i++) { if (RTEST(rb_yield(RSTRUCT(s)->ptr[i]))) { rb_ary_push(result, RSTRUCT(s)->ptr[i]); } } return result; } /* * call-seq: * struct == other_struct => true or false * * Equality---Returns true if other_struct is * equal to this one: they must be of the same class as generated by * Struct::new, and the values of all instance variables * must be equal (according to Object#==). * * Customer = Struct.new(:name, :address, :zip) * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) * joejr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) * jane = Customer.new("Jane Doe", "456 Elm, Anytown NC", 12345) * joe == joejr #=> true * joe == jane #=> false */ static VALUE rb_struct_equal(s, s2) VALUE s, s2; { long i; if (s == s2) return Qtrue; if (TYPE(s2) != T_STRUCT) return Qfalse; if (rb_obj_class(s) != rb_obj_class(s2)) return Qfalse; if (RSTRUCT(s)->len != RSTRUCT(s2)->len) { rb_bug("inconsistent struct"); /* should never happen */ } for (i=0; ilen; i++) { if (!rb_equal(RSTRUCT(s)->ptr[i], RSTRUCT(s2)->ptr[i])) return Qfalse; } return Qtrue; } /* * call-seq: * struct.hash => fixnum * * Return a hash value based on this struct's contents. */ static VALUE rb_struct_hash(s) VALUE s; { long i, h; VALUE n; h = rb_hash(rb_obj_class(s)); for (i = 0; i < RSTRUCT(s)->len; i++) { h = (h << 1) | (h<0 ? 1 : 0); n = rb_hash(RSTRUCT(s)->ptr[i]); h ^= NUM2LONG(n); } return LONG2FIX(h); } /* * code-seq: * struct.eql?(other) => true or false * * Two structures are equal if they are the same object, or if all their * fields are equal (using eql?). */ static VALUE rb_struct_eql(s, s2) VALUE s, s2; { long i; if (s == s2) return Qtrue; if (TYPE(s2) != T_STRUCT) return Qfalse; if (rb_obj_class(s) != rb_obj_class(s2)) return Qfalse; if (RSTRUCT(s)->len != RSTRUCT(s2)->len) { rb_bug("inconsistent struct"); /* should never happen */ } for (i=0; ilen; i++) { if (!rb_eql(RSTRUCT(s)->ptr[i], RSTRUCT(s2)->ptr[i])) return Qfalse; } return Qtrue; } /* * call-seq: * struct.length => fixnum * struct.size => fixnum * * Returns the number of instance variables. * * Customer = Struct.new(:name, :address, :zip) * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) * joe.length #=> 3 */ static VALUE rb_struct_size(s) VALUE s; { return LONG2FIX(RSTRUCT(s)->len); } /* * A Struct is a convenient way to bundle a number of * attributes together, using accessor methods, without having to write * an explicit class. * * The Struct class is a generator of specific classes, * each one of which is defined to hold a set of variables and their * accessors. In these examples, we'll call the generated class * ``CustomerClass,'' and we'll show an example instance of that * class as ``CustomerInst.'' * * In the descriptions that follow, the parameter symbol refers * to a symbol, which is either a quoted string or a * Symbol (such as :name). */ void Init_Struct() { rb_cStruct = rb_define_class("Struct", rb_cObject); rb_include_module(rb_cStruct, rb_mEnumerable); rb_undef_alloc_func(rb_cStruct); rb_define_singleton_method(rb_cStruct, "new", rb_struct_s_def, -1); rb_define_method(rb_cStruct, "initialize", rb_struct_initialize, -2); rb_define_method(rb_cStruct, "initialize_copy", rb_struct_init_copy, 1); rb_define_method(rb_cStruct, "==", rb_struct_equal, 1); rb_define_method(rb_cStruct, "eql?", rb_struct_eql, 1); rb_define_method(rb_cStruct, "hash", rb_struct_hash, 0); rb_define_method(rb_cStruct, "to_s", rb_struct_inspect, 0); rb_define_method(rb_cStruct, "inspect", rb_struct_inspect, 0); rb_define_method(rb_cStruct, "to_a", rb_struct_to_a, 0); rb_define_method(rb_cStruct, "values", rb_struct_to_a, 0); rb_define_method(rb_cStruct, "size", rb_struct_size, 0); rb_define_method(rb_cStruct, "length", rb_struct_size, 0); rb_define_method(rb_cStruct, "each", rb_struct_each, 0); rb_define_method(rb_cStruct, "each_pair", rb_struct_each_pair, 0); rb_define_method(rb_cStruct, "[]", rb_struct_aref, 1); rb_define_method(rb_cStruct, "[]=", rb_struct_aset, 2); rb_define_method(rb_cStruct, "select", rb_struct_select, -1); rb_define_method(rb_cStruct, "values_at", rb_struct_values_at, -1); rb_define_method(rb_cStruct, "members", rb_struct_members_m, 0); } ================================================ FILE: system_allocator.c ================================================ /* * The problem * ----------- * On platforms that use a two-level symbol namespace for dynamic libraries * (most notably MacOS X), integrating tcmalloc requires special modifications. * * Most Unix platforms use a flat namespace for symbol lookup, which is why * linking to tcmalloc causes it override malloc() and free() for the entire * process. This is not the case on OS X: if Ruby calls a function from library * that's not compiled with -flat_namespace, then that library will use the * system's memory allocator instead of tcmalloc. * * The Ruby readline extension is a good example of how things can go wrong. * The readline extension calls the readline() function in the readline library. * This library is not compiled with -flat_namespace; readline() returns a string * that's allocated by the system memory allocator. The Ruby readline extension * then frees this string by passing it to tcmalloc's free() function. This * results in a crash. * Note that setting DYLD_FORCE_FLAT_NAMESPACE on OS X does not work: the * resulting Ruby interpreter will crash immediately. * * * The solution * ------------ * This can be fixed by making it possible for Ruby extensions to call the * system's memory allocator functions, instead of tcmalloc's, if it knows * that a piece of memory is allocated by the system's memory allocator. * * This library, libsystem_allocator provides wrapper functions for the system * memory allocator. libsystem_allocator will be compiled without -flat_namespace * on OS X, and so it will always use the system's memory allocator instead of * tcmalloc. * * libsystem_allocator will not be compiled on systems that only support flat * namespaces (e.g. Linux). On those platforms, system_malloc() and * system_free() have no special effect. */ #include void * system_malloc(long size) { return malloc(size); } void system_free(void *ptr) { free(ptr); } ================================================ FILE: test/callerforallthreads/test_caller_for_each_thread.rb ================================================ # -*- ruby-indent-level: 4 -*- require 'thread' require 'test/unit' class AClassWithNestedmethods def an_ultra_nested_method(skip) caller_for_all_threads skip end def a_nested_method(skip) an_ultra_nested_method skip end def a_method(skip=0) a_nested_method skip end end class CallerForEachThreadTest < Test::Unit::TestCase def testCollectMeaningfulBacktraceForASingleThread backtraces = AClassWithNestedmethods.new.a_method backtrace = backtraces[Thread.current] assert_not_nil backtrace assert_equal __FILE__ + ":8:in `an_ultra_nested_method'", backtrace[0] assert_equal __FILE__ + ":12:in `a_nested_method'", backtrace[1] assert_equal __FILE__ + ":16:in `a_method'", backtrace[2] assert_equal __FILE__ + ":24:in `testCollectMeaningfulBacktraceForASingleThread'", backtrace[3] end def testCanSkipFirstStackEntries backtraces = AClassWithNestedmethods.new.a_method 2 backtrace = backtraces[Thread.current] assert_not_nil backtrace assert_equal __FILE__ + ":16:in `a_method'", backtrace[0] assert_equal __FILE__ + ":35:in `testCanSkipFirstStackEntries'", backtrace[1] end def testCollectMeaningfulBacktraceForMultipleThreads first_thread = Thread.new do loop do Thread.pass sleep 1 end end second_thread = Thread.new do loop do Thread.pass sleep 1 end end backtraces = AClassWithNestedmethods.new.a_method backtrace = backtraces[Thread.current] assert_not_nil backtrace assert_match __FILE__ + ":8:in `an_ultra_nested_method'", backtrace[0] assert_match __FILE__ + ":12:in `a_nested_method'", backtrace[1] assert_equal __FILE__ + ":16:in `a_method'", backtrace[2] assert_equal __FILE__ + ":58:in `testCollectMeaningfulBacktraceForMultipleThreads'", backtrace[3] backtrace = backtraces[first_thread] assert_not_nil backtrace assert_equal __FILE__ + ":47:in `testCollectMeaningfulBacktraceForMultipleThreads'", backtrace[0] assert_equal __FILE__ + ":45:in `loop'", backtrace[1] assert_equal __FILE__ + ":45:in `testCollectMeaningfulBacktraceForMultipleThreads'", backtrace[2] assert_equal __FILE__ + ":44:in `initialize'",backtrace[3] assert_equal __FILE__ + ":44:in `new'", backtrace[4] assert_equal __FILE__ + ":44:in `testCollectMeaningfulBacktraceForMultipleThreads'", backtrace[5] backtrace = backtraces[second_thread] assert_not_nil backtrace assert_equal __FILE__ + ":53:in `testCollectMeaningfulBacktraceForMultipleThreads'", backtrace[0] assert_equal __FILE__ + ":52:in `loop'", backtrace[1] assert_equal __FILE__ + ":52:in `testCollectMeaningfulBacktraceForMultipleThreads'", backtrace[2] assert_equal __FILE__ + ":51:in `initialize'",backtrace[3] assert_equal __FILE__ + ":51:in `new'", backtrace[4] assert_equal __FILE__ + ":51:in `testCollectMeaningfulBacktraceForMultipleThreads'", backtrace[5] end end ================================================ FILE: test/csv/test_csv.rb ================================================ require 'test/unit' require 'tempfile' require 'fileutils' require 'csv' class CSV class StreamBuf # Let buffer work hard. remove_const("BufSize") BufSize = 2 end end module CSVTestSupport def d(data) data end end class TestCSV < Test::Unit::TestCase file = Tempfile.new("crlf") file << "\n" file.open file.binmode RSEP = file.read file.close include CSVTestSupport class << self include CSVTestSupport end @@simpleCSVData = { [nil] => '', [''] => '""', [nil, nil] => ',', [nil, nil, nil] => ',,', ['foo'] => 'foo', [','] => '","', [',', ','] => '",",","', [';'] => ';', [';', ';'] => ';,;', ["\"\r", "\"\r"] => "\"\"\"\r\",\"\"\"\r\"", ["\"\n", "\"\n"] => "\"\"\"\n\",\"\"\"\n\"", ["\t"] => "\t", ["\t", "\t"] => "\t,\t", ['foo', 'bar'] => 'foo,bar', ['foo', '"bar"', 'baz'] => 'foo,"""bar""",baz', ['foo', 'foo,bar', 'baz'] => 'foo,"foo,bar",baz', ['foo', '""', 'baz'] => 'foo,"""""",baz', ['foo', '', 'baz'] => 'foo,"",baz', ['foo', nil, 'baz'] => 'foo,,baz', [nil, 'foo', 'bar'] => ',foo,bar', ['foo', 'bar', nil] => 'foo,bar,', ['foo', "\r", 'baz'] => "foo,\"\r\",baz", ['foo', "\n", 'baz'] => "foo,\"\n\",baz", ['foo', "\r\n\r", 'baz'] => "foo,\"\r\n\r\",baz", ['foo', "\r\n", 'baz'] => "foo,\"\r\n\",baz", ['foo', "\r.\n", 'baz'] => "foo,\"\r.\n\",baz", ['foo', "\r\n\n", 'baz'] => "foo,\"\r\n\n\",baz", ['foo', '"', 'baz'] => 'foo,"""",baz', } @@fullCSVData = { [d(nil)] => '', [d('')] => '""', [d(nil), d(nil)] => ',', [d(nil), d(nil), d(nil)] => ',,', [d('foo')] => 'foo', [d('foo'), d('bar')] => 'foo,bar', [d('foo'), d('"bar"'), d('baz')] => 'foo,"""bar""",baz', [d('foo'), d('foo,bar'), d('baz')] => 'foo,"foo,bar",baz', [d('foo'), d('""'), d('baz')] => 'foo,"""""",baz', [d('foo'), d(''), d('baz')] => 'foo,"",baz', [d('foo'), d(nil), d('baz')] => 'foo,,baz', [d('foo'), d("\r"), d('baz')] => "foo,\"\r\",baz", [d('foo'), d("\n"), d('baz')] => "foo,\"\n\",baz", [d('foo'), d("\r\n"), d('baz')] => "foo,\"\r\n\",baz", [d('foo'), d("\r.\n"), d('baz')] => "foo,\"\r.\n\",baz", [d('foo'), d("\r\n\n"), d('baz')] => "foo,\"\r\n\n\",baz", [d('foo'), d('"'), d('baz')] => 'foo,"""",baz', } @@fullCSVDataArray = @@fullCSVData.collect { |key, value| key } def ssv2csv(ssvStr, row_sep = nil) sepConv(ssvStr, ?;, ?,, row_sep) end def csv2ssv(csvStr, row_sep = nil) sepConv(csvStr, ?,, ?;, row_sep) end def tsv2csv(tsvStr, row_sep = nil) sepConv(tsvStr, ?\t, ?,, row_sep) end def csv2tsv(csvStr, row_sep = nil) sepConv(csvStr, ?,, ?\t, row_sep) end def sepConv(srcStr, srcSep, destSep, row_sep = nil) rows = [] cols, idx = CSV.parse_row(srcStr, 0, rows, srcSep, row_sep) destStr = '' cols = CSV.generate_row(rows, rows.size, destStr, destSep, row_sep) destStr end public def setup @tmpdir = File.join(Dir.tmpdir, "ruby_test_csv_tmp_#{$$}") Dir.mkdir(@tmpdir) @infile = File.join(@tmpdir, 'in.csv') @infiletsv = File.join(@tmpdir, 'in.tsv') @emptyfile = File.join(@tmpdir, 'empty.csv') @outfile = File.join(@tmpdir, 'out.csv') @bomfile = File.join(@tmpdir, "bom.csv") @macfile = File.join(@tmpdir, "mac.csv") CSV.open(@infile, "wb") do |writer| @@fullCSVDataArray.each do |row| writer.add_row(row) end end CSV.open(@infiletsv, "wb", ?\t) do |writer| @@fullCSVDataArray.each do |row| writer.add_row(row) end end CSV.generate(@emptyfile) do |writer| # Create empty file. end File.open(@bomfile, "wb") do |f| f.write("\357\273\277\"foo\"\r\n\"bar\"\r\n") end File.open(@macfile, "wb") do |f| f.write("\"Avenches\",\"aus Umgebung\"\r\"Bad Hersfeld\",\"Ausgrabung\"") end end def teardown FileUtils.rm_rf(@tmpdir) end #### CSV::Reader unit test def test_Reader_each file = File.open(@infile, "rb") begin reader = CSV::Reader.create(file) expectedArray = @@fullCSVDataArray.dup first = true ret = reader.each { |row| if first assert_instance_of(Array, row) first = false end expected = expectedArray.shift assert_equal(expected, row) } assert_nil(ret, "Return is nil") assert(expectedArray.empty?) ensure file.close end # Illegal format. reader = CSV::Reader.create("a,b\r\na,b,\"c\"\ra") assert_raises(CSV::IllegalFormatError) do reader.each do |row| end end reader = CSV::Reader.create("a,b\r\n\"") assert_raises(CSV::IllegalFormatError) do reader.each do |row| end end end def test_Reader_shift file = File.open(@infile, "rb") begin reader = CSV::Reader.create(file) first = true checked = 0 @@fullCSVDataArray.each do |expected| actual = reader.shift if first assert_instance_of(Array, actual) first = false end assert_equal(expected, actual) checked += 1 end assert(checked == @@fullCSVDataArray.size) ensure file.close end # Illegal format. reader = CSV::Reader.create("a,b\r\na,b,\"c\"\ra") assert_raises(CSV::IllegalFormatError) do reader.shift reader.shift end reader = CSV::Reader.create("a,b\r\na,b,\"c\"\ra") assert_raises(CSV::IllegalFormatError) do reader.shift reader.shift end end def test_Reader_getRow if CSV::Reader.respond_to?(:allocate) obj = CSV::Reader.allocate assert_raises(NotImplementedError) do row = [] obj.shift end end end def test_IOReader_close_on_terminate f = File.open(@infile, "r") reader = CSV::IOReader.create(f) reader.close assert(!f.closed?) f.close f = File.open(@infile, "r") writer = CSV::IOReader.create(f) writer.close_on_terminate writer.close assert(f.closed?) end def test_Reader_close f = File.open(@infile, "r") reader = CSV::IOReader.create(f) reader.close_on_terminate reader.close assert(f.closed?) end def test_Reader_s_new assert_raises(RuntimeError) do CSV::Reader.new(nil) end end def test_Reader_s_create reader = CSV::Reader.create("abc") assert_instance_of(CSV::StringReader, reader, "With a String") file = File.open(@infile, "rb") reader = CSV::Reader.create(file) assert_instance_of(CSV::IOReader, reader, 'With an IO') obj = Object.new def obj.sysread(size) "abc" end def obj.read(size) "abc" end reader = CSV::Reader.create(obj) assert_instance_of(CSV::IOReader, reader, "With not an IO or String") # No need to test Tempfile because it's a pseudo IO. I test this here # fors other tests. reader = CSV::Reader.create(Tempfile.new("in.csv")) assert_instance_of(CSV::IOReader, reader, "With an pseudo IO.") file.close end def test_IOReader_s_create_binmode file = File.open(@outfile, "wb") file << "\"\r\n\",\"\r\",\"\n\"\r1,2,3" file.close file = File.open(@outfile, "rb") begin reader = CSV::IOReader.new(file, ?,, ?\r) assert_equal(["\r\n", "\r", "\n"], reader.shift.to_a) assert_equal(["1", "2", "3"], reader.shift.to_a) reader.close ensure file.close end file = File.open(@outfile, "r") # not "rb" begin lfincell = (RSEP == "\n" ? "\r\n" : "\n") reader = CSV::IOReader.new(file, ?,, ?\r) assert_equal([lfincell, "\r", "\n"], reader.shift.to_a) assert_equal(["1", "2", "3"], reader.shift.to_a) reader.close ensure file.close end end def test_Reader_s_parse ret = CSV::Reader.parse("a,b,c") { |row| assert_instance_of(Array, row, "Block parameter") } assert_nil(ret, "Return is nil") ret = CSV::Reader.parse("a;b;c", ?;) { |row| assert_instance_of(Array, row, "Block parameter") } file = Tempfile.new("in.csv") file << "a,b,c" file.open ret = CSV::Reader.parse(file) { |row| assert_instance_of(Array, row, "Block parameter") } assert_nil(ret, "Return is nil") file = Tempfile.new("in.csv") file << "a,b,c" file.open ret = CSV::Reader.parse(file, ?,) { |row| assert_instance_of(Array, row, "Block parameter") } # Illegal format. assert_raises(CSV::IllegalFormatError) do CSV::Reader.parse("a,b\r\na,b,\"c\"\ra") do |row| end end assert_raises(CSV::IllegalFormatError) do CSV::Reader.parse("a,b\r\na,b\"") do |row| end end end #### CSV::Writer unit test def test_Writer_s_new assert_raises(RuntimeError) do CSV::Writer.new(nil) end end def test_Writer_s_generate ret = CSV::Writer.generate(STDOUT) { |writer| assert_instance_of(CSV::BasicWriter, writer, "Block parameter") } ret = CSV::Writer.generate(STDOUT, ?;) { |writer| assert_instance_of(CSV::BasicWriter, writer, "Block parameter") } assert_nil(ret, "Return is nil") end def test_Writer_s_create writer = CSV::Writer.create(STDERR) assert_instance_of(CSV::BasicWriter, writer, "String") writer = CSV::Writer.create(STDERR, ?;) assert_instance_of(CSV::BasicWriter, writer, "String") writer = CSV::Writer.create(Tempfile.new("out.csv")) assert_instance_of(CSV::BasicWriter, writer, "IO") end def test_Writer_LSHIFT # '<<' file = Tempfile.new("out.csv") CSV::Writer.generate(file) do |writer| ret = writer << ['a', 'b', 'c'] assert_instance_of(CSV::BasicWriter, ret, 'Return is self') writer << [nil, 'e', 'f'] << [nil, nil, ''] end file.open file.binmode str = file.read assert_equal("a,b,c#{RSEP},e,f#{RSEP},,\"\"#{RSEP}", str, 'Normal') file = Tempfile.new("out2.csv") CSV::Writer.generate(file) do |writer| ret = writer << [d('a'), d('b'), d('c')] assert_instance_of(CSV::BasicWriter, ret, 'Return is self') writer << [d(nil), d('e'), d('f')] << [d(nil), d(nil), d('')] end file.open file.binmode str = file.read assert_equal("a,b,c#{RSEP},e,f#{RSEP},,\"\"#{RSEP}", str, 'Normal') end def test_Writer_add_row file = Tempfile.new("out.csv") CSV::Writer.generate(file) do |writer| ret = writer.add_row( [d('a'), d('b'), d('c')]) assert_instance_of(CSV::BasicWriter, ret, 'Return is self') writer.add_row( [d(nil), d('e'), d('f')] ).add_row( [d(nil), d(nil), d('')] ) end file.open file.binmode str = file.read assert_equal("a,b,c#{RSEP},e,f#{RSEP},,\"\"#{RSEP}", str, 'Normal') end def test_Writer_close f = File.open(@outfile, "w") writer = CSV::BasicWriter.create(f) writer.close_on_terminate writer.close assert(f.closed?) end def test_BasicWriter_close_on_terminate f = File.open(@outfile, "w") writer = CSV::BasicWriter.create(f) writer.close assert(!f.closed?) f.close f = File.open(@outfile, "w") writer = CSV::BasicWriter.new(f) writer.close_on_terminate writer.close assert(f.closed?) end def test_BasicWriter_s_create_binmode file = File.open(@outfile, "w") # not "wb" begin writer = CSV::BasicWriter.new(file, ?,, ?\r) writer << ["\r\n", "\r", "\n"] writer << ["1", "2", "3"] writer.close ensure file.close end file = File.open(@outfile, "rb") str = file.read file.close assert_equal("\"\r#{RSEP}\",\"\r\",\"#{RSEP}\"\r1,2,3\r", str) end #### CSV unit test def test_s_open_reader assert_raises(ArgumentError, 'Illegal mode') do CSV.open("temp", "a") end assert_raises(ArgumentError, 'Illegal mode') do CSV.open("temp", "a", ?;) end reader = CSV.open(@infile, "r") assert_instance_of(CSV::IOReader, reader) reader.close reader = CSV.open(@infile, "rb") assert_instance_of(CSV::IOReader, reader) reader.close reader = CSV.open(@infile, "r", ?;) assert_instance_of(CSV::IOReader, reader) reader.close CSV.open(@infile, "r") do |row| assert_instance_of(Array, row) break end CSV.open(@infiletsv, "r", ?\t) do |row| assert_instance_of(Array, row) break end assert_raises(Errno::ENOENT) do CSV.open("NoSuchFileOrDirectory", "r") end assert_raises(Errno::ENOENT) do CSV.open("NoSuchFileOrDirectory", "r", ?;) end # Illegal format. File.open(@outfile, "wb") do |f| f << "a,b\r\na,b,\"c\"\ra" end assert_raises(CSV::IllegalFormatError) do CSV.open(@outfile, "r") do |row| end end File.open(@outfile, "wb") do |f| f << "a,b\r\na,b\"" end assert_raises(CSV::IllegalFormatError) do CSV.open(@outfile, "r") do |row| end end CSV.open(@emptyfile, "r") do |row| assert_fail("Must not reach here") end end def test_s_parse result = CSV.parse(File.read(@infile)) assert_instance_of(Array, result) assert_instance_of(Array, result[0]) result = CSV.parse(File.read(@infile)) assert_instance_of(Array, result) assert_instance_of(Array, result[0]) assert_equal([], CSV.parse("")) assert_equal([[nil]], CSV.parse("\n")) CSV.parse(File.read(@infile)) do |row| assert_instance_of(Array, row) break end CSV.parse(File.read(@infiletsv), ?\t) do |row| assert_instance_of(Array, row) break end CSV.parse("") do |row| assert(false) end count = 0 CSV.parse("\n") do |row| assert_equal([nil], row) count += 1 end assert_equal(1, count) assert_equal([["a|b-c|d"]], CSV.parse("a|b-c|d")) assert_equal([["a", "b"], ["c", "d"]], CSV.parse("a|b-c|d", "|", "-")) end def test_s_open_writer writer = CSV.open(@outfile, "w") assert_instance_of(CSV::BasicWriter, writer) writer.close writer = CSV.open(@outfile, "wb") assert_instance_of(CSV::BasicWriter, writer) writer.close writer = CSV.open(@outfile, "wb", ?;) assert_instance_of(CSV::BasicWriter, writer) writer.close CSV.open(@outfile, "w") do |writer| assert_instance_of(CSV::BasicWriter, writer) end CSV.open(@outfile, "w", ?;) do |writer| assert_instance_of(CSV::BasicWriter, writer) end begin CSV.open(@tmpdir, "w") assert(false) rescue Exception => ex assert(ex.is_a?(Errno::EEXIST) || ex.is_a?(Errno::EISDIR) || ex.is_a?(Errno::EACCES)) end end def test_s_generate writer = CSV.generate(@outfile) assert_instance_of(CSV::BasicWriter, writer) writer.close writer = CSV.generate(@outfile, ?;) assert_instance_of(CSV::BasicWriter, writer) writer.close CSV.generate(@outfile) do |writer| assert_instance_of(CSV::BasicWriter, writer) end CSV.generate(@outfile, ?;) do |writer| assert_instance_of(CSV::BasicWriter, writer) end begin CSV.generate(@tmpdir) assert(false) rescue Exception => ex assert(ex.is_a?(Errno::EEXIST) || ex.is_a?(Errno::EISDIR) || ex.is_a?(Errno::EACCES)) end end def test_s_generate_line str = CSV.generate_line([]) assert_equal('', str, "Extra boundary check.") str = CSV.generate_line([], ?;) assert_equal('', str, "Extra boundary check.") @@simpleCSVData.each do |col, str| buf = CSV.generate_line(col) assert_equal(str, buf) end @@simpleCSVData.each do |col, str| buf = CSV.generate_line(col, ?;) assert_equal(str + "\n", ssv2csv(buf)) end @@simpleCSVData.each do |col, str| buf = CSV.generate_line(col, ?\t) assert_equal(str + "\n", tsv2csv(buf)) end str = CSV.generate_line(['a', 'b'], nil, ?|) assert_equal('a,b', str) str = CSV.generate_line(['a', 'b'], nil, "a") assert_equal('"a",b', str) end def test_s_generate_row buf = '' cols = CSV.generate_row([], 0, buf) assert_equal(0, cols) assert_equal("\n", buf, "Extra boundary check.") buf = '' cols = CSV.generate_row([], 0, buf, ?;) assert_equal(0, cols) assert_equal("\n", buf, "Extra boundary check.") buf = '' cols = CSV.generate_row([], 0, buf, ?\t) assert_equal(0, cols) assert_equal("\n", buf, "Extra boundary check.") buf = '' cols = CSV.generate_row([], 0, buf, ?\t, ?|) assert_equal(0, cols) assert_equal("|", buf, "Extra boundary check.") buf = '' cols = CSV.generate_row([d('1')], 2, buf) assert_equal('1,', buf) buf = '' cols = CSV.generate_row([d('1')], 2, buf, ?;) assert_equal('1;', buf) buf = '' cols = CSV.generate_row([d('1')], 2, buf, ?\t) assert_equal("1\t", buf) buf = '' cols = CSV.generate_row([d('1')], 2, buf, ?\t, ?|) assert_equal("1\t", buf) buf = '' cols = CSV.generate_row([d('1'), d('2')], 1, buf) assert_equal("1\n", buf) buf = '' cols = CSV.generate_row([d('1'), d('2')], 1, buf, ?;) assert_equal("1\n", buf) buf = '' cols = CSV.generate_row([d('1'), d('2')], 1, buf, ?\t) assert_equal("1\n", buf) buf = '' cols = CSV.generate_row([d('1'), d('2')], 1, buf, ?\t, ?\n) assert_equal("1\n", buf) buf = '' cols = CSV.generate_row([d('1'), d('2')], 1, buf, ?\t, ?\r) assert_equal("1\r", buf) buf = '' cols = CSV.generate_row([d('1'), d('2')], 1, buf, ?\t, ?|) assert_equal("1|", buf) @@fullCSVData.each do |col, str| buf = '' cols = CSV.generate_row(col, col.size, buf) assert_equal(col.size, cols) assert_equal(str + "\n", buf) end @@fullCSVData.each do |col, str| buf = '' cols = CSV.generate_row(col, col.size, buf, ?;) assert_equal(col.size, cols) assert_equal(str + "\n", ssv2csv(buf)) end @@fullCSVData.each do |col, str| buf = '' cols = CSV.generate_row(col, col.size, buf, ?\t) assert_equal(col.size, cols) assert_equal(str + "\n", tsv2csv(buf)) end # row separator @@fullCSVData.each do |col, str| buf = '' cols = CSV.generate_row(col, col.size, buf, ?,, ?|) assert_equal(col.size, cols) assert_equal(str + "|", buf) end # col and row separator @@fullCSVData.each do |col, str| buf = '' cols = CSV.generate_row(col, col.size, buf, ?\t, ?|) assert_equal(col.size, cols) assert_equal(str + "|", tsv2csv(buf, ?|)) end buf = '' toBe = '' cols = 0 colsToBe = 0 @@fullCSVData.each do |col, str| cols += CSV.generate_row(col, col.size, buf) toBe << str << "\n" colsToBe += col.size end assert_equal(colsToBe, cols) assert_equal(toBe, buf) buf = '' toBe = '' cols = 0 colsToBe = 0 @@fullCSVData.each do |col, str| lineBuf = '' cols += CSV.generate_row(col, col.size, lineBuf, ?;) buf << ssv2csv(lineBuf) << "\n" toBe << ssv2csv(lineBuf) << "\n" colsToBe += col.size end assert_equal(colsToBe, cols) assert_equal(toBe, buf) buf = '' toBe = '' cols = 0 colsToBe = 0 @@fullCSVData.each do |col, str| lineBuf = '' cols += CSV.generate_row(col, col.size, lineBuf, ?\t) buf << tsv2csv(lineBuf) << "\n" toBe << tsv2csv(lineBuf) << "\n" colsToBe += col.size end assert_equal(colsToBe, cols) assert_equal(toBe, buf) buf = '' toBe = '' cols = 0 colsToBe = 0 @@fullCSVData.each do |col, str| lineBuf = '' cols += CSV.generate_row(col, col.size, lineBuf, ?|) buf << tsv2csv(lineBuf, ?|) toBe << tsv2csv(lineBuf, ?|) colsToBe += col.size end assert_equal(colsToBe, cols) assert_equal(toBe, buf) end def test_s_parse_line @@simpleCSVData.each do |col, str| row = CSV.parse_line(str) assert_instance_of(Array, row) assert_equal(col.size, row.size) assert_equal(col, row) end @@simpleCSVData.each do |col, str| str = csv2ssv(str) row = CSV.parse_line(str, ?;) assert_instance_of(Array, row) assert_equal(col.size, row.size, str.inspect) assert_equal(col, row, str.inspect) end @@simpleCSVData.each do |col, str| str = csv2tsv(str) row = CSV.parse_line(str, ?\t) assert_instance_of(Array, row) assert_equal(col.size, row.size) assert_equal(col, row) end assert_equal(['a', 'b', 'c'], CSV.parse_line("a,b,c", nil, nil)) assert_equal(['a', nil], CSV.parse_line("a,b,c", nil, ?b)) assert_equal(['a', 'b', nil], CSV.parse_line("a,b,c", nil, "c")) assert_equal([nil], CSV.parse_line("")) assert_equal([nil], CSV.parse_line("\n")) assert_equal([""], CSV.parse_line("\"\"\n")) # Illegal format. buf = [] row = CSV.parse_line("a,b,\"c\"\ra") assert_instance_of(Array, row) assert_equal(0, row.size) buf = Array.new row = CSV.parse_line("a;b;\"c\"\ra", ?;) assert_instance_of(Array, row) assert_equal(0, row.size) buf = Array.new row = CSV.parse_line("a\tb\t\"c\"\ra", ?\t) assert_instance_of(Array, row) assert_equal(0, row.size) row = CSV.parse_line("a,b\"") assert_instance_of(Array, row) assert_equal(0, row.size) row = CSV.parse_line("a;b\"", ?;) assert_instance_of(Array, row) assert_equal(0, row.size) row = CSV.parse_line("a\tb\"", ?\t) assert_instance_of(Array, row) assert_equal(0, row.size) row = CSV.parse_line("\"a,b\"\r,") assert_instance_of(Array, row) assert_equal(0, row.size) row = CSV.parse_line("\"a;b\"\r;", ?;) assert_instance_of(Array, row) assert_equal(0, row.size) row = CSV.parse_line("\"a\tb\"\r\t", ?\t) assert_instance_of(Array, row) assert_equal(0, row.size) row = CSV.parse_line("\"a,b\"\r\"") assert_instance_of(Array, row) assert_equal(0, row.size) row = CSV.parse_line("\"a;b\"\r\"", ?;) assert_instance_of(Array, row) assert_equal(0, row.size) row = CSV.parse_line("\"a\tb\"\r\"", ?\t) assert_instance_of(Array, row) assert_equal(0, row.size) end def test_s_parse_row @@fullCSVData.each do |col, str| buf = Array.new cols, idx = CSV.parse_row(str + "\r\n", 0, buf) assert_equal(cols, buf.size, "Reported size.") assert_equal(col.size, buf.size, "Size.") assert_equal(col, buf, str.inspect) buf = Array.new cols, idx = CSV.parse_row(str + "\n", 0, buf, ?,, ?\n) assert_equal(cols, buf.size, "Reported size.") assert_equal(col.size, buf.size, "Size.") assert_equal(col, buf, str.inspect) # separator: | buf = Array.new cols, idx = CSV.parse_row(str + "|", 0, buf, ?,) assert_not_equal(col, buf) buf = Array.new cols, idx = CSV.parse_row(str + "|", 0, buf, ?,, ?|) assert_equal(cols, buf.size, "Reported size.") assert_equal(col.size, buf.size, "Size.") assert_equal(col, buf, str.inspect) end @@fullCSVData.each do |col, str| str = csv2ssv(str) buf = Array.new cols, idx = CSV.parse_row(str + "\r\n", 0, buf, ?;) assert_equal(cols, buf.size, "Reported size.") assert_equal(col.size, buf.size, "Size.") assert_equal(col, buf, str) end @@fullCSVData.each do |col, str| str = csv2tsv(str) buf = Array.new cols, idx = CSV.parse_row(str + "\r\n", 0, buf, ?\t) assert_equal(cols, buf.size, "Reported size.") assert_equal(col.size, buf.size, "Size.") assert_equal(col, buf, str) end @@fullCSVData.each do |col, str| str = csv2tsv(str, ?|) buf = Array.new cols, idx = CSV.parse_row(str + "|", 0, buf, ?\t, ?|) assert_equal(cols, buf.size, "Reported size.") assert_equal(col.size, buf.size, "Size.") assert_equal(col, buf, str) end buf = [] CSV.parse_row("a,b,c", 0, buf, nil, nil) assert_equal(['a', 'b', 'c'], buf) buf = [] CSV.parse_row("a,b,c", 0, buf, nil, ?b) assert_equal(['a', nil], buf) buf = [] CSV.parse_row("a,b,c", 0, buf, nil, "c") assert_equal(['a', 'b', nil], buf) buf = Array.new cols, idx = CSV.parse_row("a,b,\"c\r\"", 0, buf) assert_equal(["a", "b", "c\r"], buf.to_a) buf = Array.new cols, idx = CSV.parse_row("a;b;\"c\r\"", 0, buf, ?;) assert_equal(["a", "b", "c\r"], buf.to_a) buf = Array.new cols, idx = CSV.parse_row("a\tb\t\"c\r\"", 0, buf, ?\t) assert_equal(["a", "b", "c\r"], buf.to_a) buf = Array.new cols, idx = CSV.parse_row("a,b,c\n", 0, buf, ?,, ?\n) assert_equal(["a", "b", "c"], buf.to_a) buf = Array.new cols, idx = CSV.parse_row("a\tb\tc\n", 0, buf, ?\t, ?\n) assert_equal(["a", "b", "c"], buf.to_a) # Illegal format. buf = Array.new cols, idx = CSV.parse_row("a,b,c\"", 0, buf) assert_equal(0, cols, "Illegal format; unbalanced double-quote.") buf = Array.new cols, idx = CSV.parse_row("a;b;c\"", 0, buf, ?;) assert_equal(0, cols, "Illegal format; unbalanced double-quote.") buf = Array.new cols, idx = CSV.parse_row("a,b,\"c\"\ra", 0, buf) assert_equal(0, cols) assert_equal(0, idx) buf = Array.new cols, idx = CSV.parse_row("a,b,\"c\"\ra", 0, buf, ?;) assert_equal(0, cols) assert_equal(0, idx) buf = Array.new cols, idx = CSV.parse_row("a,b\"", 0, buf) assert_equal(0, cols) assert_equal(0, idx) buf = Array.new cols, idx = CSV.parse_row("a;b\"", 0, buf, ?;) assert_equal(0, cols) assert_equal(0, idx) buf = Array.new cols, idx = CSV.parse_row("\"a,b\"\r,", 0, buf) assert_equal(0, cols) assert_equal(0, idx) buf = Array.new cols, idx = CSV.parse_row("a\r,", 0, buf) assert_equal(0, cols) assert_equal(0, idx) buf = Array.new cols, idx = CSV.parse_row("a\r", 0, buf) assert_equal(0, cols) assert_equal(0, idx) buf = Array.new cols, idx = CSV.parse_row("a\rbc", 0, buf) assert_equal(0, cols) assert_equal(0, idx) buf = Array.new cols, idx = CSV.parse_row("a\r\"\"", 0, buf) assert_equal(0, cols) assert_equal(0, idx) buf = Array.new cols, idx = CSV.parse_row("a\r\rabc,", 0, buf) assert_equal(0, cols) assert_equal(0, idx) buf = Array.new cols, idx = CSV.parse_row("\"a;b\"\r;", 0, buf, ?;) assert_equal(0, cols) assert_equal(0, idx) buf = Array.new cols, idx = CSV.parse_row("\"a,b\"\r\"", 0, buf) assert_equal(0, cols) assert_equal(0, idx) buf = Array.new cols, idx = CSV.parse_row("\"a;b\"\r\"", 0, buf, ?;) assert_equal(0, cols) assert_equal(0, idx) end def test_s_parse_rowEOF @@fullCSVData.each do |col, str| if str == '' # String "" is not allowed. next end buf = Array.new cols, idx = CSV.parse_row(str, 0, buf) assert_equal(col.size, cols, "Reported size.") assert_equal(col.size, buf.size, "Size.") assert_equal(col, buf) end end def test_s_parse_rowConcat buf = '' toBe = [] @@fullCSVData.each do |col, str| buf << str << "\r\n" toBe.concat(col) end idx = 0 cols = 0 parsed = Array.new parsedCols = 0 begin cols, idx = CSV.parse_row(buf, idx, parsed) parsedCols += cols end while cols > 0 assert_equal(toBe.size, parsedCols) assert_equal(toBe.size, parsed.size) assert_equal(toBe, parsed) buf = '' toBe = [] @@fullCSVData.each do |col, str| buf << str << "\n" toBe.concat(col) end idx = 0 cols = 0 parsed = Array.new parsedCols = 0 begin cols, idx = CSV.parse_row(buf, idx, parsed, ?,, ?\n) parsedCols += cols end while cols > 0 assert_equal(toBe.size, parsedCols) assert_equal(toBe.size, parsed.size) assert_equal(toBe, parsed) buf = '' toBe = [] @@fullCSVData.sort { |a, b| a[0].length <=> b[0].length }.each do |col, str| buf << str << "\n" toBe.concat(col) end idx = 0 cols = 0 parsed = Array.new parsedCols = 0 begin cols, idx = CSV.parse_row(buf, idx, parsed, ?,, ?\n) parsedCols += cols end while cols > 0 assert_equal(toBe.size, parsedCols) assert_equal(toBe.size, parsed.size) assert_equal(toBe, parsed) buf = '' toBe = [] @@fullCSVData.each do |col, str| buf << str << "|" toBe.concat(col) end idx = 0 cols = 0 parsed = [] parsedCols = 0 begin cols, idx = CSV.parse_row(buf, idx, parsed, ?,, ?|) parsedCols += cols end while cols > 0 assert_equal(toBe.size, parsedCols) assert_equal(toBe.size, parsed.size) assert_equal(toBe, parsed) end def test_utf8 rows = [] CSV.open(@bomfile, "r") do |row| rows << row.to_a end assert_equal([["foo"], ["bar"]], rows) rows = [] file = File.open(@bomfile) CSV::Reader.parse(file) do |row| rows << row.to_a end assert_equal([["foo"], ["bar"]], rows) file.close end def test_macCR rows = [] CSV.open(@macfile, "r", ?,, ?\r) do |row| rows << row.to_a end assert_equal([["Avenches", "aus Umgebung"], ["Bad Hersfeld", "Ausgrabung"]], rows) rows = [] assert_raises(CSV::IllegalFormatError) do CSV.open(@macfile, "r") do |row| rows << row.to_a end assert_equal([["Avenches", "aus Umgebung\r\"Bad Hersfeld", "Ausgrabung"]], rows) end rows = [] file = File.open(@macfile) begin CSV::Reader.parse(file, ?,, ?\r) do |row| rows << row.to_a end assert_equal([["Avenches", "aus Umgebung"], ["Bad Hersfeld", "Ausgrabung"]], rows) ensure file.close end rows = [] file = File.open(@macfile) begin assert_raises(CSV::IllegalFormatError) do CSV::Reader.parse(file, ?,) do |row| rows << row.to_a end assert_equal([["Avenches", "aus Umgebung\r\"Bad Hersfeld", "Ausgrabung"]], rows) end ensure file.close end end #### CSV unit test InputStreamPattern = '0123456789' InputStreamPatternSize = InputStreamPattern.size def expChar(idx) InputStreamPattern[idx % InputStreamPatternSize] end def expStr(idx, n) if n > InputStreamPatternSize InputStreamPattern + expStr(0, n - InputStreamPatternSize) else InputStreamPattern[idx % InputStreamPatternSize, n] end end def setupInputStream(size, bufSize = nil) setBufSize(bufSize) if bufSize m = ((size / InputStreamPatternSize) + 1).to_i File.open(@outfile, "wb") do |f| f << (InputStreamPattern * m)[0, size] end file = File.open(@outfile, "rb") buf = CSV::IOBuf.new(file) if block_given? yield(buf) file.close nil else buf end end def setBufSize(size) CSV::StreamBuf.module_eval('remove_const("BufSize")') CSV::StreamBuf.module_eval("BufSize = #{ size }") end class StrBuf < CSV::StreamBuf private def initialize(string) @str = string @idx = 0 super() end def read(size) str = @str[@idx, size] if str.empty? nil else @idx += str.size str end end end class ErrBuf < CSV::StreamBuf class Error < RuntimeError; end private def initialize @first = true super() end def read(size) if @first @first = false "a" * size else raise ErrBuf::Error.new end end end def test_StreamBuf_MyBuf # At first, check ruby's behaviour. s = "abc" assert_equal(?a, s[0]) assert_equal(?b, s[1]) assert_equal(?c, s[2]) assert_equal(nil, s[3]) assert_equal("a", s[0, 1]) assert_equal("b", s[1, 1]) assert_equal("c", s[2, 1]) assert_equal("", s[3, 1]) assert_equal(nil, s[4, 1]) s = StrBuf.new("abc") assert_equal(?a, s[0]) assert_equal(?b, s.get(1)) assert_equal(?c, s[2]) assert_equal(nil, s.get(3)) assert_equal("a", s[0, 1]) assert_equal("b", s.get(1, 1)) assert_equal("c", s[2, 1]) assert_equal("", s.get(3, 1)) assert_equal(nil, s[4, 1]) dropped = s.drop(1) assert_equal(1, dropped) assert_equal(?b, s[0]) assert(!s.is_eos?) dropped = s.drop(1) assert_equal(1, dropped) assert_equal(?c, s[0]) assert(!s.is_eos?) dropped = s.drop(1) assert_equal(1, dropped) assert_equal(nil, s[0]) assert(s.is_eos?) dropped = s.drop(1) assert_equal(0, dropped) assert_equal(nil, s[0]) assert(s.is_eos?) s = StrBuf.new("") assert_equal(nil, s[0]) s = StrBuf.new("") dropped = s.drop(1) assert_equal(0, dropped) assert_raises(TestCSV::ErrBuf::Error) do s = ErrBuf.new s[1024] end assert_raises(TestCSV::ErrBuf::Error) do s = ErrBuf.new s.drop(1024) end end def test_StreamBuf_AREF # '[idx]' setupInputStream(22, 1024) do |s| [0, 1, 9, 10, 19, 20, 21].each do |idx| assert_equal(expChar(idx), s[idx], idx.to_s) end [22, 23].each do |idx| assert_equal(nil, s[idx], idx.to_s) end assert_equal(nil, s[-1]) end setupInputStream(22, 1) do |s| [0, 1, 9, 10, 19, 20, 21].each do |idx| assert_equal(expChar(idx), s[idx], idx.to_s) end [22, 23].each do |idx| assert_equal(nil, s[idx], idx.to_s) end end setupInputStream(1024, 1) do |s| [1023, 0].each do |idx| assert_equal(expChar(idx), s[idx], idx.to_s) end [1024, 1025].each do |idx| assert_equal(nil, s[idx], idx.to_s) end end setupInputStream(1, 1) do |s| [0].each do |idx| assert_equal(expChar(idx), s[idx], idx.to_s) end [1, 2].each do |idx| assert_equal(nil, s[idx], idx.to_s) end end end def test_StreamBuf_AREF_n # '[idx, n]' # At first, check ruby's behaviour. assert_equal("", "abc"[3, 1]) assert_equal(nil, "abc"[4, 1]) setupInputStream(22, 1024) do |s| [0, 1, 9, 10, 19, 20, 21].each do |idx| assert_equal(expStr(idx, 1), s[idx, 1], idx.to_s) end assert_equal("", s[22, 1]) assert_equal(nil, s[23, 1]) end setupInputStream(22, 1) do |s| [0, 1, 9, 10, 19, 20, 21].each do |idx| assert_equal(expStr(idx, 1), s[idx, 1], idx.to_s) end assert_equal("", s[22, 1]) assert_equal(nil, s[23, 1]) end setupInputStream(1024, 1) do |s| [1023, 0].each do |idx| assert_equal(expStr(idx, 1), s[idx, 1], idx.to_s) end assert_equal("", s[1024, 1]) assert_equal(nil, s[1025, 1]) end setupInputStream(1, 1) do |s| [0].each do |idx| assert_equal(expStr(idx, 1), s[idx, 1], idx.to_s) end assert_equal("", s[1, 1]) assert_equal(nil, s[2, 1]) end setupInputStream(22, 11) do |s| [0, 1, 10, 11, 20].each do |idx| assert_equal(expStr(idx, 2), s[idx, 2], idx.to_s) end assert_equal(expStr(21, 1), s[21, 2]) assert_equal(expStr(0, 12), s[0, 12]) assert_equal(expStr(10, 12), s[10, 12]) assert_equal(expStr(10, 12), s[10, 13]) assert_equal(expStr(10, 12), s[10, 14]) assert_equal(expStr(10, 12), s[10, 1024]) assert_equal(nil, s[0, -1]) assert_equal(nil, s[21, -1]) assert_equal(nil, s[-1, 10]) assert_equal(nil, s[-1, -1]) end end def test_StreamBuf_get setupInputStream(22, 1024) do |s| [0, 1, 9, 10, 19, 20, 21].each do |idx| assert_equal(expChar(idx), s.get(idx), idx.to_s) end [22, 23].each do |idx| assert_equal(nil, s.get(idx), idx.to_s) end assert_equal(nil, s.get(-1)) end end def test_StreamBuf_get_n setupInputStream(22, 1024) do |s| [0, 1, 9, 10, 19, 20, 21].each do |idx| assert_equal(expStr(idx, 1), s.get(idx, 1), idx.to_s) end assert_equal("", s.get(22, 1)) assert_equal(nil, s.get(23, 1)) assert_equal(nil, s.get(-1, 1)) assert_equal(nil, s.get(-1, -1)) end end def test_StreamBuf_drop setupInputStream(22, 1024) do |s| assert_equal(expChar(0), s[0]) assert_equal(expChar(21), s[21]) assert_equal(nil, s[22]) dropped = s.drop(-1) assert_equal(0, dropped) assert_equal(expChar(0), s[0]) dropped = s.drop(0) assert_equal(0, dropped) assert_equal(expChar(0), s[0]) dropped = s.drop(1) assert_equal(1, dropped) assert_equal(expChar(1), s[0]) assert_equal(expChar(2), s[1]) dropped = s.drop(1) assert_equal(1, dropped) assert_equal(expChar(2), s[0]) assert_equal(expChar(3), s[1]) end setupInputStream(4, 2) do |s| dropped = s.drop(2) assert_equal(2, dropped) assert_equal(expChar(2), s[0]) assert_equal(expChar(3), s[1]) dropped = s.drop(1) assert_equal(1, dropped) assert_equal(expChar(3), s[0]) assert_equal(nil, s[1]) dropped = s.drop(1) assert_equal(1, dropped) assert_equal(nil, s[0]) assert_equal(nil, s[1]) dropped = s.drop(0) assert_equal(0, dropped) assert_equal(nil, s[0]) assert_equal(nil, s[1]) end setupInputStream(6, 3) do |s| dropped = s.drop(2) assert_equal(2, dropped) dropped = s.drop(2) assert_equal(2, dropped) assert_equal(expChar(4), s[0]) assert_equal(expChar(5), s[1]) dropped = s.drop(3) assert_equal(2, dropped) assert_equal(nil, s[0]) assert_equal(nil, s[1]) end end def test_StreamBuf_is_eos? setupInputStream(3, 1024) do |s| assert(!s.is_eos?) s.drop(1) assert(!s.is_eos?) s.drop(1) assert(!s.is_eos?) s.drop(1) assert(s.is_eos?) s.drop(1) assert(s.is_eos?) end setupInputStream(3, 2) do |s| assert(!s.is_eos?) s.drop(1) assert(!s.is_eos?) s.drop(1) assert(!s.is_eos?) s.drop(1) assert(s.is_eos?) s.drop(1) assert(s.is_eos?) end end def test_StreamBuf_s_new # NotImplementedError should be raised from StreamBuf#read. assert_raises(NotImplementedError) do CSV::StreamBuf.new end end def test_IOBuf_close f = File.open(@outfile, "wb") f << "tst" f.close f = File.open(@outfile, "rb") iobuf = CSV::IOBuf.new(f) iobuf.close assert(true) # iobuf.close does not raise any exception. f.close end def test_IOBuf_s_new iobuf = CSV::IOBuf.new(Tempfile.new("in.csv")) assert_instance_of(CSV::IOBuf, iobuf) end #### CSV functional test # sample data # # 1 2 3 4 5 6 7 8 # +------+-------+---------+-------+--------+------+----+------+ # | foo | "foo" | foo,bar | "" |(empty) |(null)| \r | \r\n | # +------+-------+---------+-------+--------+------+----+------+ # | NaHi | "Na" | Na,Hi | \r.\n | \r\n\n | " | \n | \r\n | # +------+-------+---------+-------+--------+------+----+------+ # def test_s_parseAndCreate colSize = 8 csvStr = "foo,!!!foo!!!,!foo,bar!,!!!!!!,!!,,!\r!,!\r\n!\nNaHi,!!!Na!!!,!Na,Hi!,!\r.\n!,!\r\n\n!,!!!!,!\n!,!\r\n!".gsub!('!', '"') csvStrTerminated = csvStr + "\n" myStr = csvStr.dup res1 = []; res2 = [] idx = 0 col, idx = CSV::parse_row(myStr, 0, res1) col, idx = CSV::parse_row(myStr, idx, res2) buf = '' col = CSV::generate_row(res1, colSize, buf) col = CSV::generate_row(res2, colSize, buf) assert_equal(csvStrTerminated, buf) parsed = [] CSV::Reader.parse(csvStrTerminated) do |row| parsed << row end buf = '' CSV::Writer.generate(buf) do |writer| parsed.each do |row| writer.add_row(row) end end assert_equal(csvStrTerminated, buf) buf = '' CSV::Writer.generate(buf) do |writer| parsed.each do |row| writer << row end end assert_equal(csvStrTerminated, buf) end def test_writer_fs_rs_generate buf = '' CSV::Writer.generate(buf, ",,") do |writer| writer << [] end assert_equal("\n", buf) buf = '' CSV::Writer.generate(buf, ",,") do |writer| writer << [] << [] end assert_equal("\n\n", buf) buf = '' CSV::Writer.generate(buf, ",,") do |writer| writer << [1] end assert_equal("1\n", buf) buf = '' CSV::Writer.generate(buf, ",,") do |writer| writer << [1, 2, 3] writer << [4, ",,", 5] end assert_equal("1,,2,,3\n4,,\",,\",,5\n", buf) buf = '' CSV::Writer.generate(buf, ",,:", ",,;") do |writer| writer << [nil, nil, nil] writer << [nil, ",,", nil] end assert_equal(",,:,,:,,;,,:,,,,:,,;", buf) buf = '' CSV::Writer.generate(buf, "---") do |writer| writer << [1, 2, 3] writer << [4, "---\"---", 5] end assert_equal("1---2---3\n4---\"---\"\"---\"---5\n", buf) buf = '' CSV::Writer.generate(buf, nil) do |writer| writer << [1, 2, 3] writer << [4, ",\",", 5] end assert_equal("1,2,3\n4,\",\"\",\",5\n", buf) end def test_writer_fs_rs_parse reader = CSV::Reader.create('a||b--c||d', '||', '--') assert_equal(['a', 'b'], reader.shift) assert_equal(['c', 'd'], reader.shift) reader = CSV::Reader.create("a@|b@-c@|d", "@|", "@-") assert_equal(['a', 'b'], reader.shift) assert_equal(['c', 'd'], reader.shift) reader = CSV::Reader.create("ababfsababrs", "abfs", "abrs") assert_equal(['ab', 'ab'], reader.shift) reader = CSV::Reader.create('"ab"abfsababrs', "abfs", "abrs") assert_equal(['ab', 'ab'], reader.shift) reader = CSV::Reader.create('"ab"aabfsababrs', "abfs", "abrs") assert_raises(CSV::IllegalFormatError) do reader.shift end # fs match while matching rs progress reader = CSV::Reader.create("ab,ababrs", nil, "abrs") assert_equal(['ab', 'ab'], reader.shift) reader = CSV::Reader.create(',ababrs', nil, "abrs") assert_equal([nil, 'ab'], reader.shift) reader = CSV::Reader.create('"",ababrs', nil, "abrs") assert_equal(['', 'ab'], reader.shift) reader = CSV::Reader.create('ab,"ab"abrs', nil, "abrs") assert_equal(['ab', 'ab'], reader.shift) reader = CSV::Reader.create('ab,"ab"aabrs', nil, "abrs") assert_raises(CSV::IllegalFormatError) do reader.shift end # rs match while matching fs progress reader = CSV::Reader.create("ab|abc", 'ab-', "ab|") assert_equal([nil], reader.shift) assert_equal(['abc'], reader.shift) reader = CSV::Reader.create("ab\ncdabcef", "abc", "\n") assert_equal(['ab'], reader.shift) assert_equal(['cd', "ef"], reader.shift) # EOF while fs/rs matching reader = CSV::Reader.create("ab", 'ab-', "xyz") assert_equal(['ab'], reader.shift) reader = CSV::Reader.create("ab", 'xyz', "ab|") assert_equal(['ab'], reader.shift) reader = CSV::Reader.create("ab", 'ab-', "ab|") assert_equal(['ab'], reader.shift) reader = CSV::Reader.create(",,:,,:,,;,,:,,,,:,,;", ",,:", ",,;") assert_equal([nil, nil, nil], reader.shift) assert_equal([nil, ",,", nil], reader.shift) end def test_s_foreach File.open(@outfile, "w") do |f| f << "1,2,3\n4,5,6" end row = [] CSV.foreach(@outfile) { |line| row << line } assert_equal([['1', '2', '3'], ['4', '5', '6']], row) File.open(@outfile, "w") do |f| f << "1,2,3\r4,5,6" end row = [] CSV.foreach(@outfile, "\r") { |line| row << line } assert_equal([['1', '2', '3'], ['4', '5', '6']], row) end def test_s_readlines File.open(@outfile, "w") do |f| f << "1,2,3\n4,5,6" end assert_equal([["1", "2", "3"], ["4", "5", "6"]], CSV.readlines(@outfile)) assert_equal([["1", "2", nil], [nil, "5", "6"]], CSV.readlines(@outfile, "3\n4")) end def test_s_read File.open(@outfile, "w") do |f| f << "1,2,3\n4,5,6" end assert_equal([["1", "2", "3"], ["4", "5", "6"]], CSV.read(@outfile)) assert_equal([["1", "2"]], CSV.read(@outfile, 3)) assert_equal([[nil], ["4", nil]], CSV.read(@outfile, 3, 5)) end end ================================================ FILE: test/dbm/test_dbm.rb ================================================ require 'test/unit' begin require 'dbm' rescue LoadError end if defined? DBM require 'tmpdir' require 'fileutils' class TestDBM < Test::Unit::TestCase def TestDBM.uname_s require 'rbconfig' case Config::CONFIG['target_os'] when 'cygwin' require 'Win32API' uname = Win32API.new('cygwin1', 'uname', 'P', 'I') utsname = ' ' * 100 raise 'cannot get system name' if uname.call(utsname) == -1 utsname.unpack('A20' * 5)[0] else Config::CONFIG['target_os'] end end SYSTEM = uname_s def setup @path = "tmptest_dbm_" assert_instance_of(DBM, @dbm = DBM.new(@path)) # prepare to make readonly DBM file DBM.open("tmptest_dbm_rdonly") {|dbm| dbm['foo'] = 'FOO' } File.chmod(0400, *Dir.glob("tmptest_dbm_rdonly.*")) assert_instance_of(DBM, @dbm_rdonly = DBM.new("tmptest_dbm_rdonly", nil)) end def teardown assert_nil(@dbm.close) assert_nil(@dbm_rdonly.close) ObjectSpace.each_object(DBM) do |obj| obj.close unless obj.closed? end File.delete *Dir.glob("tmptest_dbm*").to_a p Dir.glob("tmptest_dbm*") if $DEBUG end def check_size(expect, dbm=@dbm) assert_equal(expect, dbm.size) n = 0 dbm.each { n+=1 } assert_equal(expect, n) if expect == 0 assert_equal(true, dbm.empty?) else assert_equal(false, dbm.empty?) end end def have_fork? begin fork{} true rescue NotImplementedError false end end def test_s_new_has_no_block # DBM.new ignore the block foo = true assert_instance_of(DBM, dbm = DBM.new("tmptest_dbm") { foo = false }) assert_equal(foo, true) assert_nil(dbm.close) end def test_s_open_no_create assert_nil(dbm = DBM.open("tmptest_dbm", nil)) ensure dbm.close if dbm end def test_s_open_with_block assert_equal(DBM.open("tmptest_dbm") { :foo }, :foo) end def test_close assert_instance_of(DBM, dbm = DBM.open("tmptest_dbm")) assert_nil(dbm.close) # closed DBM file assert_raise(DBMError) { dbm.close } end def test_aref assert_equal('bar', @dbm['foo'] = 'bar') assert_equal('bar', @dbm['foo']) assert_nil(@dbm['bar']) end def test_fetch assert_equal('bar', @dbm['foo']='bar') assert_equal('bar', @dbm.fetch('foo')) # key not found assert_raise(IndexError) { @dbm.fetch('bar') } # test for `ifnone' arg assert_equal('baz', @dbm.fetch('bar', 'baz')) # test for `ifnone' block assert_equal('foobar', @dbm.fetch('bar') {|key| 'foo' + key }) end def test_aset num = 0 2.times {|i| assert_equal('foo', @dbm['foo'] = 'foo') assert_equal('foo', @dbm['foo']) assert_equal('bar', @dbm['foo'] = 'bar') assert_equal('bar', @dbm['foo']) num += 1 if i == 0 assert_equal(num, @dbm.size) # assign nil assert_equal('', @dbm['bar'] = '') assert_equal('', @dbm['bar']) num += 1 if i == 0 assert_equal(num, @dbm.size) # empty string assert_equal('', @dbm[''] = '') assert_equal('', @dbm['']) num += 1 if i == 0 assert_equal(num, @dbm.size) # Fixnum assert_equal('200', @dbm['100'] = '200') assert_equal('200', @dbm['100']) num += 1 if i == 0 assert_equal(num, @dbm.size) # Big key and value assert_equal('y' * 100, @dbm['x' * 100] = 'y' * 100) assert_equal('y' * 100, @dbm['x' * 100]) num += 1 if i == 0 assert_equal(num, @dbm.size) } end def test_index assert_equal('bar', @dbm['foo'] = 'bar') assert_equal('foo', @dbm.index('bar')) assert_nil(@dbm['bar']) end def test_indexes keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @dbm[keys[0]], @dbm[keys[1]], @dbm[keys[2]] = values assert_equal(values.reverse, @dbm.indexes(*keys.reverse)) end def test_values_at keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @dbm[keys[0]], @dbm[keys[1]], @dbm[keys[2]] = values assert_equal(values.reverse, @dbm.values_at(*keys.reverse)) end def test_select_with_block keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @dbm[keys[0]], @dbm[keys[1]], @dbm[keys[2]] = values ret = @dbm.select {|k,v| assert_equal(k.upcase, v) k != "bar" } assert_equal([['baz', 'BAZ'], ['foo', 'FOO']], ret.sort) end def test_length num = 10 assert_equal(0, @dbm.size) num.times {|i| i = i.to_s @dbm[i] = i } assert_equal(num, @dbm.size) @dbm.shift assert_equal(num - 1, @dbm.size) end def test_empty? assert_equal(true, @dbm.empty?) @dbm['foo'] = 'FOO' assert_equal(false, @dbm.empty?) end def test_each_pair n = 0 @dbm.each_pair { n += 1 } assert_equal(0, n) keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @dbm[keys[0]], @dbm[keys[1]], @dbm[keys[2]] = values n = 0 ret = @dbm.each_pair {|key, val| assert_not_nil(i = keys.index(key)) assert_equal(val, values[i]) n += 1 } assert_equal(keys.size, n) assert_equal(@dbm, ret) end def test_each_value n = 0 @dbm.each_value { n += 1 } assert_equal(0, n) keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @dbm[keys[0]], @dbm[keys[1]], @dbm[keys[2]] = values n = 0 ret = @dbm.each_value {|val| assert_not_nil(key = @dbm.index(val)) assert_not_nil(i = keys.index(key)) assert_equal(val, values[i]) n += 1 } assert_equal(keys.size, n) assert_equal(@dbm, ret) end def test_each_key n = 0 @dbm.each_key { n += 1 } assert_equal(0, n) keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @dbm[keys[0]], @dbm[keys[1]], @dbm[keys[2]] = values n = 0 ret = @dbm.each_key {|key| assert_not_nil(i = keys.index(key)) assert_equal(@dbm[key], values[i]) n += 1 } assert_equal(keys.size, n) assert_equal(@dbm, ret) end def test_keys assert_equal([], @dbm.keys) keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @dbm[keys[0]], @dbm[keys[1]], @dbm[keys[2]] = values assert_equal(keys.sort, @dbm.keys.sort) assert_equal(values.sort, @dbm.values.sort) end def test_values test_keys end def test_shift assert_nil(@dbm.shift) assert_equal(0, @dbm.size) keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @dbm[keys[0]], @dbm[keys[1]], @dbm[keys[2]] = values ret_keys = [] ret_values = [] while ret = @dbm.shift ret_keys.push ret[0] ret_values.push ret[1] assert_equal(keys.size - ret_keys.size, @dbm.size) end assert_equal(keys.sort, ret_keys.sort) assert_equal(values.sort, ret_values.sort) end def test_delete keys = %w(foo bar baz) values = %w(FOO BAR BAZ) key = keys[1] assert_nil(@dbm.delete(key)) assert_equal(0, @dbm.size) @dbm[keys[0]], @dbm[keys[1]], @dbm[keys[2]] = values assert_equal('BAR', @dbm.delete(key)) assert_nil(@dbm[key]) assert_equal(2, @dbm.size) assert_nil(@dbm.delete(key)) if /^CYGWIN_9/ !~ SYSTEM assert_raise(DBMError) { @dbm_rdonly.delete("foo") } assert_nil(@dbm_rdonly.delete("bar")) end end def test_delete_with_block key = 'no called block' @dbm[key] = 'foo' assert_equal('foo', @dbm.delete(key) {|k| k.replace 'called block'}) assert_equal('no called block', key) assert_equal(0, @dbm.size) key = 'no called block' assert_equal(:blockval, @dbm.delete(key) {|k| k.replace 'called block'; :blockval}) assert_equal('called block', key) assert_equal(0, @dbm.size) end def test_delete_if v = "0" 100.times {@dbm[v] = v; v = v.next} ret = @dbm.delete_if {|key, val| key.to_i < 50} assert_equal(@dbm, ret) check_size(50, @dbm) ret = @dbm.delete_if {|key, val| key.to_i >= 50} assert_equal(@dbm, ret) check_size(0, @dbm) # break v = "0" 100.times {@dbm[v] = v; v = v.next} check_size(100, @dbm) n = 0; @dbm.delete_if {|key, val| break if n > 50 n+=1 true } assert_equal(51, n) check_size(49, @dbm) @dbm.clear # raise v = "0" 100.times {@dbm[v] = v; v = v.next} check_size(100, @dbm) n = 0; begin @dbm.delete_if {|key, val| raise "runtime error" if n > 50 n+=1 true } rescue end assert_equal(51, n) check_size(49, @dbm) end def test_reject v = "0" 100.times {@dbm[v] = v; v = v.next} hash = @dbm.reject {|key, val| key.to_i < 50} assert_instance_of(Hash, hash) assert_equal(100, @dbm.size) assert_equal(50, hash.size) hash.each_pair {|key,val| assert_equal(false, key.to_i < 50) assert_equal(key, val) } hash = @dbm.reject {|key, val| key.to_i < 100} assert_instance_of(Hash, hash) assert_equal(true, hash.empty?) end def test_clear v = "1" 100.times {v = v.next; @dbm[v] = v} assert_equal(@dbm, @dbm.clear) # validate DBM#size i = 0 @dbm.each { i += 1 } assert_equal(@dbm.size, i) assert_equal(0, i) end def test_invert v = "0" 100.times {@dbm[v] = v; v = v.next} hash = @dbm.invert assert_instance_of(Hash, hash) assert_equal(100, hash.size) hash.each_pair {|key, val| assert_equal(key.to_i, val.to_i) } end def test_update hash = {} v = "0" 100.times {v = v.next; hash[v] = v} @dbm["101"] = "101" @dbm.update hash assert_equal(101, @dbm.size) @dbm.each_pair {|key, val| assert_equal(key.to_i, val.to_i) } end def test_replace hash = {} v = "0" 100.times {v = v.next; hash[v] = v} @dbm["101"] = "101" @dbm.replace hash assert_equal(100, @dbm.size) @dbm.each_pair {|key, val| assert_equal(key.to_i, val.to_i) } end def test_haskey? assert_equal('bar', @dbm['foo']='bar') assert_equal(true, @dbm.has_key?('foo')) assert_equal(false, @dbm.has_key?('bar')) end def test_has_value? assert_equal('bar', @dbm['foo']='bar') assert_equal(true, @dbm.has_value?('bar')) assert_equal(false, @dbm.has_value?('foo')) end def test_to_a v = "0" 100.times {v = v.next; @dbm[v] = v} ary = @dbm.to_a assert_instance_of(Array, ary) assert_equal(100, ary.size) ary.each {|key,val| assert_equal(key.to_i, val.to_i) } end def test_to_hash v = "0" 100.times {v = v.next; @dbm[v] = v} hash = @dbm.to_hash assert_instance_of(Hash, hash) assert_equal(100, hash.size) hash.each {|key,val| assert_equal(key.to_i, val.to_i) } end end class TestDBM2 < Test::Unit::TestCase TMPROOT = "#{Dir.tmpdir}/ruby-dbm.#{$$}" def setup Dir.mkdir TMPROOT end def teardown FileUtils.rm_rf TMPROOT if File.directory?(TMPROOT) end def test_reader_open DBM.open("#{TMPROOT}/a") {} v = DBM.open("#{TMPROOT}/a", nil, DBM::READER) {|d| # Errno::EPERM is raised on Solaris which use ndbm. # DBMError is raised on Debian which use gdbm. assert_raises(Errno::EPERM, DBMError) { d["k"] = "v" } true } assert(v) end def test_newdb_open DBM.open("#{TMPROOT}/a") {|dbm| dbm["k"] = "v" } v = DBM.open("#{TMPROOT}/a", nil, DBM::NEWDB) {|d| assert_equal(0, d.length) assert_nil(d["k"]) true } assert(v) end def test_freeze DBM.open("#{TMPROOT}/a") {|d| d.freeze assert_raises(TypeError) { d["k"] = "v" } } end end end ================================================ FILE: test/digest/test_digest.rb ================================================ #!/usr/bin/env ruby # # $RoughId: test.rb,v 1.4 2001/07/13 15:38:27 knu Exp $ # $Id$ require 'test/unit' require 'digest' %w[digest/md5 digest/rmd160 digest/sha1 digest/sha2].each do |lib| begin require lib rescue LoadError end end module TestDigest Data1 = "abc" Data2 = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" def test_s_hexdigest self.class::DATA.each do |str, digest| assert_equal(digest, self.class::ALGO.hexdigest(str)) end end def test_s_digest self.class::DATA.each do |str, digest| assert_equal([digest].pack("H*"), self.class::ALGO.digest(str)) end end def test_update # This test is also for digest() and hexdigest() str = "ABC" md = self.class::ALGO.new md.update str assert_equal(self.class::ALGO.hexdigest(str), md.hexdigest) assert_equal(self.class::ALGO.digest(str), md.digest) end def test_eq # This test is also for clone() md1 = self.class::ALGO.new md1 << "ABC" assert_equal(md1, md1.clone, self.class::ALGO) md2 = self.class::ALGO.new md2 << "A" assert(md1 != md2, self.class::ALGO) md2 << "BC" assert_equal(md1, md2, self.class::ALGO) end def test_instance_eval assert_nothing_raised { self.class::ALGO.new.instance_eval { update "a" } } end class TestMD5 < Test::Unit::TestCase include TestDigest ALGO = Digest::MD5 DATA = { Data1 => "900150983cd24fb0d6963f7d28e17f72", Data2 => "8215ef0796a20bcaaae116d3876c664a", } end if defined?(Digest::MD5) class TestSHA1 < Test::Unit::TestCase include TestDigest ALGO = Digest::SHA1 DATA = { Data1 => "a9993e364706816aba3e25717850c26c9cd0d89d", Data2 => "84983e441c3bd26ebaae4aa1f95129e5e54670f1", } end if defined?(Digest::SHA1) class TestSHA256 < Test::Unit::TestCase include TestDigest ALGO = Digest::SHA256 DATA = { Data1 => "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", Data2 => "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", } end if defined?(Digest::SHA256) class TestSHA384 < Test::Unit::TestCase include TestDigest ALGO = Digest::SHA384 DATA = { Data1 => "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", Data2 => "3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b", } end if defined?(Digest::SHA384) class TestSHA512 < Test::Unit::TestCase include TestDigest ALGO = Digest::SHA512 DATA = { Data1 => "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", Data2 => "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445", } end if defined?(Digest::SHA512) class TestRMD160 < Test::Unit::TestCase include TestDigest ALGO = Digest::RMD160 DATA = { Data1 => "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", Data2 => "12a053384a9c0c88e405a06c27dcf49ada62eb2b", } end if defined?(Digest::RMD160) end ================================================ FILE: test/drb/drbtest.rb ================================================ require 'test/unit' require 'drb/drb' require 'drb/extservm' require 'timeout' begin loadpath = $:.dup $:.replace($: | [File.expand_path("../ruby", File.dirname(__FILE__))]) require 'envutil' ensure $:.replace(loadpath) end class DRbService @@manager = DRb::ExtServManager.new @@ruby = EnvUtil.rubybin @@ruby += " -d" if $DEBUG def self.add_service_command(nm) dir = File.dirname(File.expand_path(__FILE__)) DRb::ExtServManager.command[nm] = "\"#{@@ruby}\" \"#{dir}/#{nm}\"" end %w(ut_drb.rb ut_array.rb ut_port.rb ut_large.rb ut_safe1.rb ut_eval.rb).each do |nm| add_service_command(nm) end @server = @@server = DRb::DRbServer.new('druby://localhost:0', @@manager, {}) @@manager.uri = @@server.uri def self.manager @@manager end def self.server @server || @@server end def self.ext_service(name) timeout(100, RuntimeError) do manager.service(name) end end end class Onecky include DRbUndumped def initialize(n) @num = n end def to_i @num.to_i end def sleep(n) Kernel.sleep(n) to_i end end class FailOnecky < Onecky class OneckyError < RuntimeError; end def to_i raise(OneckyError, @num.to_s) end end class XArray < Array def initialize(ary) ary.each do |x| self.push(x) end end end module DRbCore def setup @ext = DRbService.ext_service('ut_drb.rb') @there = @ext.front end def teardown @ext.stop_service if @ext end def test_00_DRbObject ro = DRbObject.new(nil, 'druby://localhost:12345') assert_equal('druby://localhost:12345', ro.__drburi) assert_equal(nil, ro.__drbref) ro = DRbObject.new_with_uri('druby://localhost:12345') assert_equal('druby://localhost:12345', ro.__drburi) assert_equal(nil, ro.__drbref) ro = DRbObject.new_with_uri('druby://localhost:12345?foobar') assert_equal('druby://localhost:12345', ro.__drburi) assert_equal(DRb::DRbURIOption.new('foobar'), ro.__drbref) end def test_01 assert_equal("hello", @there.hello) onecky = Onecky.new('3') assert_equal(6, @there.sample(onecky, 1, 2)) ary = @there.to_a assert_kind_of(DRb::DRbObject, ary) assert(@there.respond_to?(:to_a, true)) assert(@there.respond_to?(:eval, true)) assert(! @there.respond_to?(:eval, false)) assert(! @there.respond_to?(:eval)) end def test_01_02_loop onecky = Onecky.new('3') 50.times do assert_equal(6, @there.sample(onecky, 1, 2)) ary = @there.to_a assert_kind_of(DRb::DRbObject, ary) end end def test_02_unknown obj = @there.unknown_class assert_kind_of(DRb::DRbUnknown, obj) assert_equal('Unknown2', obj.name) obj = @there.unknown_module assert_kind_of(DRb::DRbUnknown, obj) if RUBY_VERSION >= '1.8' assert_equal('DRbEx::', obj.name) else assert_equal('DRbEx', obj.name) end assert_raises(DRb::DRbUnknownError) do @there.unknown_error end onecky = FailOnecky.new('3') assert_raises(FailOnecky::OneckyError) do @there.sample(onecky, 1, 2) end end def test_03 assert_equal(8, @there.sum(1, 1, 1, 1, 1, 1, 1, 1)) assert_raises(ArgumentError) do @there.sum(1, 1, 1, 1, 1, 1, 1, 1, 1) end assert_raises(DRb::DRbConnError) do @there.sum('1' * 4096) end end def test_04 assert_respond_to(@there, 'sum') assert(!(@there.respond_to? "foobar")) end def test_05_eq a = @there.to_a[0] b = @there.to_a[0] assert(a.object_id != b.object_id) assert(a == b) assert_equal(a, b) assert(a == @there) assert_equal(a.hash, b.hash) assert_equal(a.hash, @there.hash) assert(a.eql?(b)) assert(a.eql?(@there)) end def test_06_timeout ten = Onecky.new(10) assert_raises(TimeoutError) do @there.do_timeout(ten) end assert_raises(TimeoutError) do @there.do_timeout(ten) end end def test_07_public_private_protected_missing assert_nothing_raised() { begin @there.method_missing(:eval) rescue NoMethodError assert_match(/^private method \`eval\'/, $!.message) end } assert_nothing_raised() { begin @there.call_private_method rescue NoMethodError assert_equal(NoMethodError, $!.class) assert_match(/^private method \`call_private_method\'/, $!.message) end } assert_nothing_raised() { begin @there.call_protected_method rescue NoMethodError assert_equal(NoMethodError, $!.class) assert_match(/^protected method \`call_protected_method\'/, $!.message) end } assert_nothing_raised() { begin @there.method_missing(:undefined_method_test) rescue NoMethodError assert_equal(NoMethodError, $!.class) assert_match(/^undefined method \`undefined_method_test\'/, $!.message) end } assert_raises(SecurityError) do @there.method_missing(:__send__, :to_s) end assert_equal(true, @there.missing) end def test_08_here ro = DRbObject.new(nil, DRb.uri) assert_kind_of(String, ro.to_s) ro = DRbObject.new_with_uri(DRb.uri) assert_kind_of(String, ro.to_s) end def uri_concat_option(uri, opt) "#{uri}?#{opt}" end def test_09_option uri = uri_concat_option(@there.__drburi, "foo") ro = DRbObject.new_with_uri(uri) assert_equal(ro.__drburi, @there.__drburi) assert_equal(3, ro.size) uri = uri_concat_option(@there.__drburi, "") ro = DRbObject.new_with_uri(uri) assert_equal(ro.__drburi, @there.__drburi) assert_equal(DRb::DRbURIOption.new(''), ro.__drbref) uri = uri_concat_option(@there.__drburi, "hello?world") ro = DRbObject.new_with_uri(uri) assert_equal(DRb::DRbURIOption.new('hello?world'), ro.__drbref) uri = uri_concat_option(@there.__drburi, "?hello?world") ro = DRbObject.new_with_uri(uri) assert_equal(DRb::DRbURIOption.new('?hello?world'), ro.__drbref) end def test_10_yield @there.simple_hash.each do |k, v| assert_kind_of(String, k) assert_kind_of(Symbol, v) end end def test_10_yield_undumped @there.xarray2_hash.each do |k, v| assert_kind_of(String, k) assert_kind_of(DRbObject, v) end end def test_11_remote_no_method_error assert_raises(DRb::DRbRemoteError) do @there.remote_no_method_error end begin @there.remote_no_method_error rescue error = $! assert_match(/^undefined method .*\(NoMethodError\)/, error.message) assert_equal('NoMethodError', error.reason) end end end module DRbAry def setup @ext = DRbService.ext_service('ut_array.rb') @there = @ext.front end def teardown @ext.stop_service if @ext end def test_01 assert_kind_of(DRb::DRbObject, @there) end def test_02_collect ary = @there.collect do |x| x + x end assert_kind_of(Array, ary) assert_equal([2, 4, 'IIIIII', 8, 'fivefive', 12], ary) end def test_03_redo ary = [] count = 0 @there.each do |x| count += 1 ary.push x redo if count == 3 end assert_equal([1, 2, 'III', 'III', 4, 'five', 6], ary) end def test_04_retry retried = false ary = [] @there.each do |x| ary.push x if x == 4 && !retried retried = true retry end end assert_equal([1, 2, 'III', 4, 1, 2, 'III', 4, 'five', 6], ary) end def test_05_break ary = [] @there.each do |x| ary.push x break if x == 4 end assert_equal([1, 2, 'III', 4], ary) end def test_06_next ary = [] @there.each do |x| next if String === x ary.push x end assert_equal([1, 2, 4, 6], ary) end class_eval < " unless it it end DRb.start_service(nil, [1, 2, 'III', 4, "five", 6]) es = DRb::ExtServ.new(ARGV.shift, ARGV.shift) DRb.thread.join end ================================================ FILE: test/drb/ut_array_drbssl.rb ================================================ require 'drb/drb' require 'drb/extserv' require 'drb/ssl' if __FILE__ == $0 def ARGV.shift it = super() raise "usage: #{$0} " unless it it end config = Hash.new config[:SSLVerifyMode] = OpenSSL::SSL::VERIFY_PEER config[:SSLVerifyCallback] = lambda{|ok,x509_store| true } config[:SSLCertName] = [ ["C","JP"], ["O","Foo.DRuby.Org"], ["CN", "Sample"] ] DRb.start_service('drbssl://:0', [1, 2, 'III', 4, "five", 6], config) es = DRb::ExtServ.new(ARGV.shift, ARGV.shift) DRb.thread.join end ================================================ FILE: test/drb/ut_array_drbunix.rb ================================================ require 'drb/drb' require 'drb/extserv' if __FILE__ == $0 def ARGV.shift it = super() raise "usage: #{$0} " unless it it end DRb.start_service('drbunix:', [1, 2, 'III', 4, "five", 6]) es = DRb::ExtServ.new(ARGV.shift, ARGV.shift) DRb.thread.join end ================================================ FILE: test/drb/ut_drb.rb ================================================ require 'drb/drb' require 'drb/extserv' require 'timeout' class XArray < Array def initialize(ary) ary.each do |x| self.push(x) end end end class XArray2 < XArray include DRbUndumped end class Unknown2 def initialize @foo = 'unknown2' end end class DRbEx include DRbUndumped class FooBar def initialize @foo = 'bar' end end class UError < RuntimeError; end def initialize @hello = 'hello' end attr_reader :hello def sample(a, b, c) a.to_i + b.to_i + c.to_i end def sum(*a) s = 0 a.each do |e| s += e.to_i end s end def do_timeout(n) timeout(0.1) do n.sleep(2) end end def unknown_module FooBar.new end def unknown_class Unknown2.new end def unknown_error raise UError end def remote_no_method_error invoke_no_method(self) end def test_yield yield yield([]) yield(*[]) end def echo_yield(*arg) yield(*arg) nil end def echo_yield_0 yield nil end def echo_yield_1(one) yield(one) nil end def echo_yield_2(one, two) yield(one, two) nil end def xarray_each xary = [XArray.new([0])] xary.each do |x| yield(x) end nil end def xarray2_hash unless @xary2_hash @xary2_hash = { "a" => XArray2.new([0]), "b" => XArray2.new([1]) } end DRbObject.new(@xary2_hash) end def simple_hash unless @hash @hash = { 'a'=>:a, 'b'=>:b } end DRbObject.new(@hash) end def [](key) key.to_s end def to_a [self] end def method_missing(msg, *a, &b) if msg == :missing return true else super(msg, *a, &b) end end private def call_private_method true end protected def call_protected_method true end end if __FILE__ == $0 def ARGV.shift it = super() raise "usage: #{$0} " unless it it end DRb::DRbServer.default_argc_limit(8) DRb::DRbServer.default_load_limit(4096) DRb.start_service('druby://localhost:0', DRbEx.new) es = DRb::ExtServ.new(ARGV.shift, ARGV.shift) DRb.thread.join end ================================================ FILE: test/drb/ut_drb_drbssl.rb ================================================ require "#{File.dirname(File.expand_path(__FILE__))}/ut_drb" require 'drb/ssl' if __FILE__ == $0 def ARGV.shift it = super() raise "usage: #{$0} " unless it it end config = Hash.new config[:SSLVerifyMode] = OpenSSL::SSL::VERIFY_PEER config[:SSLVerifyCallback] = lambda{|ok,x509_store| true } config[:SSLCertName] = [ ["C","JP"], ["O","Foo.DRuby.Org"], ["CN", "Sample"] ] DRb::DRbServer.default_argc_limit(8) DRb::DRbServer.default_load_limit(4096) DRb.start_service('drbssl://localhost:0', DRbEx.new, config) es = DRb::ExtServ.new(ARGV.shift, ARGV.shift) DRb.thread.join end ================================================ FILE: test/drb/ut_drb_drbunix.rb ================================================ require "#{File.dirname(File.expand_path(__FILE__))}/ut_drb" if __FILE__ == $0 def ARGV.shift it = super() raise "usage: #{$0} " unless it it end DRb::DRbServer.default_argc_limit(8) DRb::DRbServer.default_load_limit(4096) DRb.start_service('drbunix:', DRbEx.new) es = DRb::ExtServ.new(ARGV.shift, ARGV.shift) DRb.thread.join end ================================================ FILE: test/drb/ut_eval.rb ================================================ require 'drb/drb' require 'drb/extserv' class EvalAttack def initialize @four = DRb::DRbServer.new('druby://localhost:0', self, {:safe_level => 4}) end def four DRbObject.new_with_uri(@four.uri) end def remote_class DRbObject.new(self.class) end end if __FILE__ == $0 def ARGV.shift it = super() raise "usage: #{$0} " unless it it end $SAFE = 1 DRb.start_service('druby://localhost:0', EvalAttack.new, {:safe_level => 2}) es = DRb::ExtServ.new(ARGV.shift, ARGV.shift) DRb.thread.join end ================================================ FILE: test/drb/ut_large.rb ================================================ require 'drb/drb' require 'drb/extserv' require 'timeout' class DRbLarge include DRbUndumped def size(ary) ary.size end def sum(ary) sum = 0 ary.each do |e| sum += e.to_i end sum end def arg_test(*arg) # nop end end if __FILE__ == $0 def ARGV.shift it = super() raise "usage: #{$0} " unless it it end DRb::DRbServer.default_argc_limit(3) DRb::DRbServer.default_load_limit(100000) DRb.start_service('druby://localhost:0', DRbLarge.new) es = DRb::ExtServ.new(ARGV.shift, ARGV.shift) DRb.thread.join end ================================================ FILE: test/drb/ut_port.rb ================================================ require 'drb/drb' require 'drb/extserv' if __FILE__ == $0 def ARGV.shift it = super() raise "usage: #{$0} " unless it it end DRb.start_service('druby://:8473', [1, 2, 'III', 4, "five", 6]) es = DRb::ExtServ.new(ARGV.shift, ARGV.shift) DRb.thread.join end ================================================ FILE: test/drb/ut_safe1.rb ================================================ require 'drb/drb' require 'drb/extserv' if __FILE__ == $0 def ARGV.shift it = super() raise "usage: #{$0} " unless it it end DRb.start_service('druby://localhost:0', [1, 2, 'III', 4, "five", 6], {:safe_level => 1}) es = DRb::ExtServ.new(ARGV.shift, ARGV.shift) DRb.thread.join end ================================================ FILE: test/drb/ut_timerholder.rb ================================================ require 'runit/testcase' require 'runit/cui/testrunner' require 'timerholder' class TimerHolderTest < RUNIT::TestCase def do_test(timeout, keeper_sleep = nil) holder = TimerHolder.new(timeout) holder.keeper_sleep = keeper_sleep if keeper_sleep key = holder.add(self) sleep(timeout * 0.5) assert_equal(holder.peek(key), self) holder.delete(key) assert(!holder.include?(key)) key = holder.add(self) sleep(timeout+0.5) assert_equal(holder.fetch(key), nil) key = holder.add(self) assert_equal(holder.fetch(key), self) holder.store(key, true) assert_equal(holder.fetch(key), true) assert_equal(holder.include?(key), true) sleep(timeout+0.5) assert_exception(TimerHolder::InvalidIndexError) do holder.store(key, 1) end assert_equal(holder.include?(key), false) key = holder.add(self) sleep(timeout * 0.5) assert(holder.include?(key)) holder.extend(key, timeout) sleep(timeout * 0.5) assert(holder.include?(key)) sleep(timeout * 0.6) assert(!holder.include?(key)) holder.delete(key) end def test_00 do_test(0.5) end def test_01 do_test(1, 0.5) end end if __FILE__ == $0 RUNIT::CUI::TestRunner.run(TimerHolderTest.suite) end ================================================ FILE: test/erb/hello.erb ================================================ = hello <% 3.times do |n| %> * <%= n %> <% end %> ================================================ FILE: test/erb/test_erb.rb ================================================ require 'test/unit' require 'erb' class TestERB < Test::Unit::TestCase class MyError < RuntimeError ; end def test_without_filename erb = ERB.new("<% raise ::TestERB::MyError %>") e = assert_raise(MyError) { erb.result } assert_equal("(erb):1", e.backtrace[0]) end def test_with_filename erb = ERB.new("<% raise ::TestERB::MyError %>") erb.filename = "test filename" e = assert_raise(MyError) { erb.result } assert_equal("test filename:1", e.backtrace[0]) end def test_without_filename_with_safe_level erb = ERB.new("<% raise ::TestERB::MyError %>", 1) e = assert_raise(MyError) { erb.result } assert_equal("(erb):1", e.backtrace[0]) end def test_with_filename_and_safe_level erb = ERB.new("<% raise ::TestERB::MyError %>", 1) erb.filename = "test filename" e = assert_raise(MyError) { erb.result } assert_equal("test filename:1", e.backtrace[0]) end end class TestERBCore < Test::Unit::TestCase def setup @erb = ERB end def test_core _test_core(nil) _test_core(0) _test_core(1) _test_core(2) _test_core(3) end def _test_core(safe) erb = @erb.new("hello") assert_equal("hello", erb.result) erb = @erb.new("hello", safe, 0) assert_equal("hello", erb.result) erb = @erb.new("hello", safe, 1) assert_equal("hello", erb.result) erb = @erb.new("hello", safe, 2) assert_equal("hello", erb.result) src = < % n=0 * <%= n %> <% end %> EOS ans = <') assert_equal(ans.chomp, erb.result) ans = <') assert_equal(ans, erb.result) ans = <') assert_equal(ans.chomp, erb.result) ans = <') assert_equal(ans, erb.result) end def test_safe_04 erb = @erb.new('<%=$SAFE%>', 4) assert_equal('4', erb.result(TOPLEVEL_BINDING.taint)) end class Foo; end def test_def_class erb = @erb.new('hello') cls = erb.def_class assert_equal(Object, cls.superclass) assert(cls.new.respond_to?('result')) cls = erb.def_class(Foo) assert_equal(Foo, cls.superclass) assert(cls.new.respond_to?('result')) cls = erb.def_class(Object, 'erb') assert_equal(Object, cls.superclass) assert(cls.new.respond_to?('erb')) end def test_percent src = < EOS assert_equal("1\n", ERB.new(src, nil, '%').result) src = < EOS ans = "\n" assert_equal(ans, ERB.new(src, nil, '%').result) src = "<%\n%>" # ans = "\n" ans = "" assert_equal(ans, ERB.new(src, nil, '%').result) src = <<%= n%> EOS assert_equal("1\n", ERB.new(src, nil, '%').result) src = < %% %%><%%<%= i%><% end%> %%% EOS ans = <<%0 % %%><%1 %% EOS assert_equal(ans, ERB.new(src, nil, '%').result) end def test_def_method klass = Class.new klass.module_eval do extend ERB::DefMethod fname = File.join(File.dirname(File.expand_path(__FILE__)), 'hello.erb') def_erb_method('hello', fname) end assert(klass.new.respond_to?('hello')) assert(! klass.new.respond_to?('hello_world')) erb = @erb.new('hello, world') klass.module_eval do def_erb_method('hello_world', erb) end assert(klass.new.respond_to?('hello_world')) end def test_escape src = < 2.%%> : <%="%%>"%> 3. % x = "foo" <%=x%> 4. %% print "foo" 5. %% <%="foo"%> 6.<%=" % print 'foo' "%> 7.<%=" %% print 'foo' "%> EOS ans = < : %> 3. foo 4. % print "foo" 5. % foo 6. % print 'foo' 7. %% print 'foo' EOS assert_equal(ans, ERB.new(src, nil, '%').result) end def test_keep_lineno src = < % raise("lineno") EOS erb = ERB.new(src, nil, '%') begin erb.result assert(false) rescue assert_equal("(erb):4", $@[0].to_s) end src = < Hello, <% x = "World%%> "%> <%= x%> EOS ans = <Hello, World%> EOS assert_equal(ans, ERB.new(src, nil, '>').result) ans = < Hello, World%> EOS assert_equal(ans, ERB.new(src, nil, '<>').result) ans = < Hello, World%> EOS assert_equal(ans, ERB.new(src).result) src = < <%= x%> <% raise("lineno") %> EOS erb = ERB.new(src) begin erb.result assert(false) rescue assert_equal("(erb):5", $@[0].to_s) end erb = ERB.new(src, nil, '>') begin erb.result assert(false) rescue assert_equal("(erb):5", $@[0].to_s) end erb = ERB.new(src, nil, '<>') begin erb.result assert(false) rescue assert_equal("(erb):5", $@[0].to_s) end src = < <%= x %><%- x = nil -%> <% raise("lineno") %> EOS erb = ERB.new(src, nil, '-') begin erb.result assert(false) rescue assert_equal("(erb):5", $@[0].to_s) end erb = ERB.new(src, nil, '%-') begin erb.result assert(false) rescue assert_equal("(erb):5", $@[0].to_s) end end def test_explicit src = < NotSkip <%- y = x -%> NotSkip <% x.each do |w| -%> <%- up = w.upcase -%> * <%= up %> <% end -%> <%- z = nil -%> NotSkip <%- z = x %> <%- z.each do |w| -%> <%- down = w.downcase -%> * <%= down %> <%- up = w.upcase -%> * <%= up %> <%- end -%> KeepNewLine <%- z = nil -%> EOS ans = <%", nil, "%").result) end end class TestERBCoreWOStrScan < TestERBCore def setup @save_map = ERB::Compiler::Scanner.instance_variable_get('@scanner_map') map = {[nil, false]=>ERB::Compiler::SimpleScanner} ERB::Compiler::Scanner.instance_variable_set('@scanner_map', map) super end def teardown ERB::Compiler::Scanner.instance_variable_set('@scanner_map', @save_map) end end ================================================ FILE: test/fileutils/fileasserts.rb ================================================ # $Id$ module Test module Unit module Assertions # redefine def assert_same_file(from, to) _wrap_assertion { assert_block("file #{from} != #{to}") { File.read(from) == File.read(to) } } end def assert_same_entry(from, to) a = File.stat(from) b = File.stat(to) assert_equal a.mode, b.mode, "mode #{a.mode} != #{b.mode}" #assert_equal a.atime, b.atime assert_equal a.mtime, b.mtime, "mtime #{a.mtime} != #{b.mtime}" assert_equal a.uid, b.uid, "uid #{a.uid} != #{b.uid}" assert_equal a.gid, b.gid, "gid #{a.gid} != #{b.gid}" end def assert_file_exist(path) _wrap_assertion { assert_block("file not exist: #{path}") { File.exist?(path) } } end def assert_file_not_exist(path) _wrap_assertion { assert_block("file not exist: #{path}") { not File.exist?(path) } } end def assert_directory(path) _wrap_assertion { assert_block("is not directory: #{path}") { File.directory?(path) } } end def assert_symlink(path) _wrap_assertion { assert_block("is not a symlink: #{path}") { File.symlink?(path) } } end def assert_not_symlink(path) _wrap_assertion { assert_block("is a symlink: #{path}") { not File.symlink?(path) } } end end end end ================================================ FILE: test/fileutils/test_dryrun.rb ================================================ # $Id$ require 'test/unit' require 'fileutils' class TestFileUtilsDryRun < Test::Unit::TestCase include FileUtils::DryRun def test_visibility FileUtils::METHODS.each do |m| assert_equal true, FileUtils::DryRun.respond_to?(m, true), "FileUtils::DryRun.#{m} not defined" assert_equal true, FileUtils::DryRun.respond_to?(m, false), "FileUtils::DryRun.#{m} not public" end FileUtils::METHODS.each do |m| assert_equal true, respond_to?(m, true) "FileUtils::DryRun\##{m} is not defined" assert_equal true, FileUtils::DryRun.private_method_defined?(m), "FileUtils::DryRun\##{m} is not private" end end end ================================================ FILE: test/fileutils/test_fileutils.rb ================================================ # $Id$ require 'fileutils' require 'fileasserts' require 'pathname' require 'tmpdir' require 'test/unit' class TestFileUtils < Test::Unit::TestCase TMPROOT = "#{Dir.tmpdir}/fileutils.rb.#{$$}" end prevdir = Dir.pwd tmproot = TestFileUtils::TMPROOT Dir.mkdir tmproot unless File.directory?(tmproot) Dir.chdir tmproot def have_drive_letter? /djgpp|mswin(?!ce)|mingw|bcc|emx/ =~ RUBY_PLATFORM end def have_file_perm? /djgpp|mswin|mingw|bcc|wince|emx/ !~ RUBY_PLATFORM end $fileutils_rb_have_symlink = nil def have_symlink? if $fileutils_rb_have_symlink == nil $fileutils_rb_have_symlink = check_have_symlink? end $fileutils_rb_have_symlink end def check_have_symlink? File.symlink nil, nil rescue NotImplementedError return false rescue return true end $fileutils_rb_have_hardlink = nil def have_hardlink? if $fileutils_rb_have_hardlink == nil $fileutils_rb_have_hardlink = check_have_hardlink? end $fileutils_rb_have_hardlink end def check_have_hardlink? File.link nil, nil rescue NotImplementedError return false rescue return true end begin Dir.mkdir("\n") Dir.rmdir("\n") def lf_in_path_allowed? true end rescue def lf_in_path_allowed? false end end Dir.chdir prevdir Dir.rmdir tmproot class TestFileUtils include FileUtils def check_singleton(name) assert_equal true, ::FileUtils.public_methods.include?(name.to_s) end def my_rm_rf(path) if File.exist?('/bin/rm') system %Q[/bin/rm -rf "#{path}"] else FileUtils.rm_rf path end end def mymkdir(path) Dir.mkdir path File.chown nil, Process.gid, path if have_file_perm? end def setup @prevdir = Dir.pwd tmproot = TMPROOT mymkdir tmproot unless File.directory?(tmproot) Dir.chdir tmproot my_rm_rf 'data'; mymkdir 'data' my_rm_rf 'tmp'; mymkdir 'tmp' prepare_data_file end def teardown tmproot = Dir.pwd Dir.chdir @prevdir my_rm_rf tmproot end TARGETS = %w( data/a data/all data/random data/zero ) def prepare_data_file File.open('data/a', 'w') {|f| 32.times do f.puts 'a' * 50 end } all_chars = (0..255).map {|n| n.chr }.join('') File.open('data/all', 'w') {|f| 32.times do f.puts all_chars end } random_chars = (0...50).map { rand(256).chr }.join('') File.open('data/random', 'w') {|f| 32.times do f.puts random_chars end } File.open('data/zero', 'w') {|f| ; } end BIGFILE = 'data/big' def prepare_big_file File.open('data/big', 'w') {|f| (4 * 1024 * 1024 / 256).times do # 4MB f.print "aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa\n" end } end def prepare_time_data File.open('data/old', 'w') {|f| f.puts 'dummy' } File.open('data/newer', 'w') {|f| f.puts 'dummy' } File.open('data/newest', 'w') {|f| f.puts 'dummy' } t = Time.now File.utime t-8, t-8, 'data/old' File.utime t-4, t-4, 'data/newer' end def each_srcdest TARGETS.each do |path| yield path, "tmp/#{File.basename(path)}" end end # # Test Cases # def test_pwd check_singleton :pwd assert_equal Dir.pwd, pwd() cwd = Dir.pwd if have_drive_letter? cd('C:/') { assert_equal 'C:/', pwd() } assert_equal cwd, pwd() else cd('/') { assert_equal '/', pwd() } assert_equal cwd, pwd() end end def test_cmp check_singleton :cmp TARGETS.each do |fname| assert cmp(fname, fname), 'not same?' end assert_raises(ArgumentError) { cmp TARGETS[0], TARGETS[0], :undefinedoption => true } # pathname touch 'tmp/cmptmp' assert_nothing_raised { cmp Pathname.new('tmp/cmptmp'), 'tmp/cmptmp' cmp 'tmp/cmptmp', Pathname.new('tmp/cmptmp') cmp Pathname.new('tmp/cmptmp'), Pathname.new('tmp/cmptmp') } end def test_cp check_singleton :cp each_srcdest do |srcpath, destpath| cp srcpath, destpath assert_same_file srcpath, destpath cp srcpath, File.dirname(destpath) assert_same_file srcpath, destpath cp srcpath, File.dirname(destpath) + '/' assert_same_file srcpath, destpath cp srcpath, destpath, :preserve => true assert_same_file srcpath, destpath assert_same_entry srcpath, destpath end # src==dest (1) same path touch 'tmp/cptmp' assert_raises(ArgumentError) { cp 'tmp/cptmp', 'tmp/cptmp' } if have_symlink? # src==dest (2) symlink and its target File.symlink 'cptmp', 'tmp/cptmp_symlink' assert_raises(ArgumentError) { cp 'tmp/cptmp', 'tmp/cptmp_symlink' } assert_raises(ArgumentError) { cp 'tmp/cptmp_symlink', 'tmp/cptmp' } # src==dest (3) looped symlink File.symlink 'symlink', 'tmp/symlink' assert_raises(Errno::ELOOP) { cp 'tmp/symlink', 'tmp/symlink' } end # pathname assert_nothing_raised { cp 'tmp/cptmp', Pathname.new('tmp/tmpdest') cp Pathname.new('tmp/cptmp'), 'tmp/tmpdest' cp Pathname.new('tmp/cptmp'), Pathname.new('tmp/tmpdest') mkdir 'tmp/tmpdir' cp ['tmp/cptmp', 'tmp/tmpdest'], Pathname.new('tmp/tmpdir') } end def test_cp_r check_singleton :cp_r cp_r 'data', 'tmp' TARGETS.each do |fname| assert_same_file fname, "tmp/#{fname}" end cp_r 'data', 'tmp2', :preserve => true TARGETS.each do |fname| assert_same_entry fname, "tmp2/#{File.basename(fname)}" assert_same_file fname, "tmp2/#{File.basename(fname)}" end # a/* -> b/* mkdir 'tmp/cpr_src' mkdir 'tmp/cpr_dest' File.open('tmp/cpr_src/a', 'w') {|f| f.puts 'a' } File.open('tmp/cpr_src/b', 'w') {|f| f.puts 'b' } File.open('tmp/cpr_src/c', 'w') {|f| f.puts 'c' } mkdir 'tmp/cpr_src/d' cp_r 'tmp/cpr_src/.', 'tmp/cpr_dest' assert_same_file 'tmp/cpr_src/a', 'tmp/cpr_dest/a' assert_same_file 'tmp/cpr_src/b', 'tmp/cpr_dest/b' assert_same_file 'tmp/cpr_src/c', 'tmp/cpr_dest/c' assert_directory 'tmp/cpr_dest/d' my_rm_rf 'tmp/cpr_src' my_rm_rf 'tmp/cpr_dest' if have_symlink? # symlink in a directory mkdir 'tmp/cpr_src' ln_s 'SLdest', 'tmp/cpr_src/symlink' cp_r 'tmp/cpr_src', 'tmp/cpr_dest' assert_symlink 'tmp/cpr_dest/symlink' assert_equal 'SLdest', File.readlink('tmp/cpr_dest/symlink') # root is a symlink ln_s 'cpr_src', 'tmp/cpr_src2' cp_r 'tmp/cpr_src2', 'tmp/cpr_dest2' assert_directory 'tmp/cpr_dest2' #assert_not_symlink 'tmp/cpr_dest2' # * 2005-05-26: feature change on trunk #assert_symlink 'tmp/cpr_dest2' # * 2005-09-19: revert for 1.8 (:dereference_root => true by default) assert_not_symlink 'tmp/cpr_dest2' assert_symlink 'tmp/cpr_dest2/symlink' assert_equal 'SLdest', File.readlink('tmp/cpr_dest2/symlink') end # pathname touch 'tmp/cprtmp' assert_nothing_raised { cp_r Pathname.new('tmp/cprtmp'), 'tmp/tmpdest' cp_r 'tmp/cprtmp', Pathname.new('tmp/tmpdest') cp_r Pathname.new('tmp/cprtmp'), Pathname.new('tmp/tmpdest') } end def test_mv check_singleton :mv mkdir 'tmp/dest' TARGETS.each do |fname| cp fname, 'tmp/mvsrc' mv 'tmp/mvsrc', 'tmp/mvdest' assert_same_file fname, 'tmp/mvdest' mv 'tmp/mvdest', 'tmp/dest/' assert_same_file fname, 'tmp/dest/mvdest' mv 'tmp/dest/mvdest', 'tmp' assert_same_file fname, 'tmp/mvdest' end # [ruby-talk:124368] mkdir 'tmp/tmpdir' mkdir_p 'tmp/dest2/tmpdir' assert_raises(Errno::EEXIST) { mv 'tmp/tmpdir', 'tmp/dest2' } mkdir 'tmp/dest2/tmpdir/junk' assert_raises(Errno::EEXIST) { mv 'tmp/tmpdir', 'tmp/dest2' } # src==dest (1) same path touch 'tmp/cptmp' assert_raises(ArgumentError) { mv 'tmp/cptmp', 'tmp/cptmp' } if have_symlink? # src==dest (2) symlink and its target File.symlink 'cptmp', 'tmp/cptmp_symlink' assert_raises(ArgumentError) { mv 'tmp/cptmp', 'tmp/cptmp_symlink' } assert_raises(ArgumentError) { mv 'tmp/cptmp_symlink', 'tmp/cptmp' } # src==dest (3) looped symlink File.symlink 'symlink', 'tmp/symlink' assert_raises(Errno::ELOOP) { mv 'tmp/symlink', 'tmp/symlink' } end # pathname assert_nothing_raised { touch 'tmp/mvtmpsrc' mv Pathname.new('tmp/mvtmpsrc'), 'tmp/mvtmpdest' touch 'tmp/mvtmpsrc' mv 'tmp/mvtmpsrc', Pathname.new('tmp/mvtmpdest') touch 'tmp/mvtmpsrc' mv Pathname.new('tmp/mvtmpsrc'), Pathname.new('tmp/mvtmpdest') } end def test_rm check_singleton :rm TARGETS.each do |fname| cp fname, 'tmp/rmsrc' rm 'tmp/rmsrc' assert_file_not_exist 'tmp/rmsrc' end # pathname touch 'tmp/rmtmp1' touch 'tmp/rmtmp2' touch 'tmp/rmtmp3' assert_nothing_raised { rm Pathname.new('tmp/rmtmp1') rm [Pathname.new('tmp/rmtmp2'), Pathname.new('tmp/rmtmp3')] } assert_file_not_exist 'tmp/rmtmp1' assert_file_not_exist 'tmp/rmtmp2' assert_file_not_exist 'tmp/rmtmp3' end def test_rm_f check_singleton :rm_f TARGETS.each do |fname| cp fname, 'tmp/rmsrc' rm_f 'tmp/rmsrc' assert_file_not_exist 'tmp/rmsrc' end if have_symlink? File.open('tmp/lnf_symlink_src', 'w') {|f| f.puts 'dummy' } File.symlink 'tmp/lnf_symlink_src', 'tmp/lnf_symlink_dest' rm_f 'tmp/lnf_symlink_dest' assert_file_not_exist 'tmp/lnf_symlink_dest' assert_file_exist 'tmp/lnf_symlink_src' end rm_f 'notexistdatafile' rm_f 'tmp/notexistdatafile' my_rm_rf 'tmpdatadir' Dir.mkdir 'tmpdatadir' # rm_f 'tmpdatadir' Dir.rmdir 'tmpdatadir' Dir.mkdir 'tmp/tmpdir' File.open('tmp/tmpdir/a', 'w') {|f| f.puts 'dummy' } File.open('tmp/tmpdir/c', 'w') {|f| f.puts 'dummy' } rm_f ['tmp/tmpdir/a', 'tmp/tmpdir/b', 'tmp/tmpdir/c'] assert_file_not_exist 'tmp/tmpdir/a' assert_file_not_exist 'tmp/tmpdir/c' Dir.rmdir 'tmp/tmpdir' # pathname touch 'tmp/rmtmp1' touch 'tmp/rmtmp2' touch 'tmp/rmtmp3' touch 'tmp/rmtmp4' assert_nothing_raised { rm_f Pathname.new('tmp/rmtmp1') rm_f [Pathname.new('tmp/rmtmp2'), Pathname.new('tmp/rmtmp3')] } assert_file_not_exist 'tmp/rmtmp1' assert_file_not_exist 'tmp/rmtmp2' assert_file_not_exist 'tmp/rmtmp3' assert_file_exist 'tmp/rmtmp4' end def test_rm_r check_singleton :rm_r my_rm_rf 'tmpdatadir' Dir.mkdir 'tmpdatadir' rm_r 'tmpdatadir' assert_file_not_exist 'tmpdatadir' Dir.mkdir 'tmpdatadir' rm_r 'tmpdatadir/' assert_file_not_exist 'tmpdatadir' Dir.mkdir 'tmp/tmpdir' rm_r 'tmp/tmpdir/' assert_file_not_exist 'tmp/tmpdir' assert_file_exist 'tmp' Dir.mkdir 'tmp/tmpdir' rm_r 'tmp/tmpdir' assert_file_not_exist 'tmp/tmpdir' assert_file_exist 'tmp' Dir.mkdir 'tmp/tmpdir' File.open('tmp/tmpdir/a', 'w') {|f| f.puts 'dummy' } File.open('tmp/tmpdir/b', 'w') {|f| f.puts 'dummy' } File.open('tmp/tmpdir/c', 'w') {|f| f.puts 'dummy' } rm_r 'tmp/tmpdir' assert_file_not_exist 'tmp/tmpdir' assert_file_exist 'tmp' Dir.mkdir 'tmp/tmpdir' File.open('tmp/tmpdir/a', 'w') {|f| f.puts 'dummy' } File.open('tmp/tmpdir/c', 'w') {|f| f.puts 'dummy' } rm_r ['tmp/tmpdir/a', 'tmp/tmpdir/b', 'tmp/tmpdir/c'], :force => true assert_file_not_exist 'tmp/tmpdir/a' assert_file_not_exist 'tmp/tmpdir/c' Dir.rmdir 'tmp/tmpdir' if have_symlink? # [ruby-talk:94635] a symlink to the directory Dir.mkdir 'tmp/tmpdir' File.symlink '..', 'tmp/tmpdir/symlink_to_dir' rm_r 'tmp/tmpdir' assert_file_not_exist 'tmp/tmpdir' assert_file_exist 'tmp' end # pathname Dir.mkdir 'tmp/tmpdir1'; touch 'tmp/tmpdir1/tmp' Dir.mkdir 'tmp/tmpdir2'; touch 'tmp/tmpdir2/tmp' Dir.mkdir 'tmp/tmpdir3'; touch 'tmp/tmpdir3/tmp' assert_nothing_raised { rm_r Pathname.new('tmp/tmpdir1') rm_r [Pathname.new('tmp/tmpdir2'), Pathname.new('tmp/tmpdir3')] } assert_file_not_exist 'tmp/tmpdir1' assert_file_not_exist 'tmp/tmpdir2' assert_file_not_exist 'tmp/tmpdir3' end def test_remove_entry_secure check_singleton :remove_entry_secure my_rm_rf 'tmpdatadir' Dir.mkdir 'tmpdatadir' remove_entry_secure 'tmpdatadir' assert_file_not_exist 'tmpdatadir' Dir.mkdir 'tmpdatadir' remove_entry_secure 'tmpdatadir/' assert_file_not_exist 'tmpdatadir' Dir.mkdir 'tmp/tmpdir' remove_entry_secure 'tmp/tmpdir/' assert_file_not_exist 'tmp/tmpdir' assert_file_exist 'tmp' Dir.mkdir 'tmp/tmpdir' remove_entry_secure 'tmp/tmpdir' assert_file_not_exist 'tmp/tmpdir' assert_file_exist 'tmp' Dir.mkdir 'tmp/tmpdir' File.open('tmp/tmpdir/a', 'w') {|f| f.puts 'dummy' } File.open('tmp/tmpdir/b', 'w') {|f| f.puts 'dummy' } File.open('tmp/tmpdir/c', 'w') {|f| f.puts 'dummy' } remove_entry_secure 'tmp/tmpdir' assert_file_not_exist 'tmp/tmpdir' assert_file_exist 'tmp' Dir.mkdir 'tmp/tmpdir' File.open('tmp/tmpdir/a', 'w') {|f| f.puts 'dummy' } File.open('tmp/tmpdir/c', 'w') {|f| f.puts 'dummy' } remove_entry_secure 'tmp/tmpdir/a', true remove_entry_secure 'tmp/tmpdir/b', true remove_entry_secure 'tmp/tmpdir/c', true assert_file_not_exist 'tmp/tmpdir/a' assert_file_not_exist 'tmp/tmpdir/c' Dir.rmdir 'tmp/tmpdir' if have_symlink? # [ruby-talk:94635] a symlink to the directory Dir.mkdir 'tmp/tmpdir' File.symlink '..', 'tmp/tmpdir/symlink_to_dir' remove_entry_secure 'tmp/tmpdir' assert_file_not_exist 'tmp/tmpdir' assert_file_exist 'tmp' end # pathname Dir.mkdir 'tmp/tmpdir1'; touch 'tmp/tmpdir1/tmp' assert_nothing_raised { remove_entry_secure Pathname.new('tmp/tmpdir1') } assert_file_not_exist 'tmp/tmpdir1' end def test_with_big_file prepare_big_file cp BIGFILE, 'tmp/cpdest' assert_same_file BIGFILE, 'tmp/cpdest' assert cmp(BIGFILE, 'tmp/cpdest'), 'orig != copied' mv 'tmp/cpdest', 'tmp/mvdest' assert_same_file BIGFILE, 'tmp/mvdest' assert_file_not_exist 'tmp/cpdest' rm 'tmp/mvdest' assert_file_not_exist 'tmp/mvdest' end if have_hardlink? def test_ln TARGETS.each do |fname| ln fname, 'tmp/lndest' assert_same_file fname, 'tmp/lndest' File.unlink 'tmp/lndest' end ln TARGETS, 'tmp' TARGETS.each do |fname| assert_same_file fname, 'tmp/' + File.basename(fname) end TARGETS.each do |fname| File.unlink 'tmp/' + File.basename(fname) end # src==dest (1) same path touch 'tmp/cptmp' assert_raises(Errno::EEXIST) { ln 'tmp/cptmp', 'tmp/cptmp' } if have_symlink? # src==dest (2) symlink and its target File.symlink 'cptmp', 'tmp/symlink' assert_raises(Errno::EEXIST) { ln 'tmp/cptmp', 'tmp/symlink' # normal file -> symlink } assert_raises(Errno::EEXIST) { ln 'tmp/symlink', 'tmp/cptmp' # symlink -> normal file } # src==dest (3) looped symlink File.symlink 'cptmp_symlink', 'tmp/cptmp_symlink' begin ln 'tmp/cptmp_symlink', 'tmp/cptmp_symlink' rescue => err assert_kind_of SystemCallError, err end end # pathname touch 'tmp/lntmp' assert_nothing_raised { ln Pathname.new('tmp/lntmp'), 'tmp/lndesttmp1' ln 'tmp/lntmp', Pathname.new('tmp/lndesttmp2') ln Pathname.new('tmp/lntmp'), Pathname.new('tmp/lndesttmp3') } end end if have_symlink? def test_ln_s check_singleton :ln_s TARGETS.each do |fname| ln_s fname, 'tmp/lnsdest' assert FileTest.symlink?('tmp/lnsdest'), 'not symlink' assert_equal fname, File.readlink('tmp/lnsdest') rm_f 'tmp/lnsdest' end assert_nothing_raised { ln_s 'symlink', 'tmp/symlink' } assert_symlink 'tmp/symlink' # pathname touch 'tmp/lnsdest' assert_nothing_raised { ln_s Pathname.new('lnsdest'), 'tmp/symlink_tmp1' ln_s 'lnsdest', Pathname.new('tmp/symlink_tmp2') ln_s Pathname.new('lnsdest'), Pathname.new('tmp/symlink_tmp3') } end end if have_symlink? def test_ln_sf check_singleton :ln_sf TARGETS.each do |fname| ln_sf fname, 'tmp/lnsdest' assert FileTest.symlink?('tmp/lnsdest'), 'not symlink' assert_equal fname, File.readlink('tmp/lnsdest') ln_sf fname, 'tmp/lnsdest' ln_sf fname, 'tmp/lnsdest' end assert_nothing_raised { ln_sf 'symlink', 'tmp/symlink' } # pathname touch 'tmp/lns_dest' assert_nothing_raised { ln_sf Pathname.new('lns_dest'), 'tmp/symlink_tmp1' ln_sf 'lns_dest', Pathname.new('tmp/symlink_tmp2') ln_sf Pathname.new('lns_dest'), Pathname.new('tmp/symlink_tmp3') } end end def test_mkdir check_singleton :mkdir my_rm_rf 'tmpdatadir' mkdir 'tmpdatadir' assert_directory 'tmpdatadir' Dir.rmdir 'tmpdatadir' mkdir 'tmpdatadir/' assert_directory 'tmpdatadir' Dir.rmdir 'tmpdatadir' mkdir 'tmp/mkdirdest' assert_directory 'tmp/mkdirdest' Dir.rmdir 'tmp/mkdirdest' mkdir 'tmp/tmp', :mode => 0700 assert_directory 'tmp/tmp' assert_equal 0700, (File.stat('tmp/tmp').mode & 0777) if have_file_perm? Dir.rmdir 'tmp/tmp' if have_file_perm? mkdir 'tmp/tmp', :mode => 07777 assert_directory 'tmp/tmp' assert_equal 07777, (File.stat('tmp/tmp').mode & 07777) Dir.rmdir 'tmp/tmp' end if lf_in_path_allowed? mkdir "tmp-first-line\ntmp-second-line" assert_directory "tmp-first-line\ntmp-second-line" Dir.rmdir "tmp-first-line\ntmp-second-line" end # pathname assert_nothing_raised { mkdir Pathname.new('tmp/tmpdirtmp') mkdir [Pathname.new('tmp/tmpdirtmp2'), Pathname.new('tmp/tmpdirtmp3')] } end def test_mkdir_p check_singleton :mkdir_p dirs = %w( tmpdir/dir/ tmpdir/dir/./ tmpdir/dir/./.././dir/ tmpdir/a tmpdir/a/ tmpdir/a/b tmpdir/a/b/ tmpdir/a/b/c/ tmpdir/a/b/c tmpdir/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a tmpdir/a/a ) my_rm_rf 'tmpdir' dirs.each do |d| mkdir_p d assert_directory d assert_file_not_exist "#{d}/a" assert_file_not_exist "#{d}/b" assert_file_not_exist "#{d}/c" my_rm_rf 'tmpdir' end dirs.each do |d| mkdir_p d assert_directory d end rm_rf 'tmpdir' dirs.each do |d| mkdir_p "#{Dir.pwd}/#{d}" assert_directory d end rm_rf 'tmpdir' mkdir_p 'tmp/tmp/tmp', :mode => 0700 assert_directory 'tmp/tmp' assert_directory 'tmp/tmp/tmp' assert_equal 0700, (File.stat('tmp/tmp').mode & 0777) if have_file_perm? assert_equal 0700, (File.stat('tmp/tmp/tmp').mode & 0777) if have_file_perm? rm_rf 'tmp/tmp' mkdir_p 'tmp/tmp', :mode => 0 assert_directory 'tmp/tmp' assert_equal 0, (File.stat('tmp/tmp').mode & 0777) if have_file_perm? # DO NOT USE rm_rf here. # (rm(1) try to chdir to parent directory, it fails to remove directory.) Dir.rmdir 'tmp/tmp' Dir.rmdir 'tmp' if have_file_perm? mkdir_p 'tmp/tmp/tmp', :mode => 07777 assert_directory 'tmp/tmp/tmp' assert_equal 07777, (File.stat('tmp/tmp/tmp').mode & 07777) Dir.rmdir 'tmp/tmp/tmp' Dir.rmdir 'tmp/tmp' end # pathname assert_nothing_raised { mkdir_p Pathname.new('tmp/tmp/tmp') } end def test_install check_singleton :install File.open('tmp/aaa', 'w') {|f| f.puts 'aaa' } File.open('tmp/bbb', 'w') {|f| f.puts 'bbb' } install 'tmp/aaa', 'tmp/bbb', :mode => 0600 assert_equal "aaa\n", File.read('tmp/bbb') assert_equal 0600, (File.stat('tmp/bbb').mode & 0777) if have_file_perm? t = File.mtime('tmp/bbb') install 'tmp/aaa', 'tmp/bbb' assert_equal "aaa\n", File.read('tmp/bbb') assert_equal 0600, (File.stat('tmp/bbb').mode & 0777) if have_file_perm? assert_equal t, File.mtime('tmp/bbb') File.unlink 'tmp/aaa' File.unlink 'tmp/bbb' # src==dest (1) same path touch 'tmp/cptmp' assert_raises(ArgumentError) { install 'tmp/cptmp', 'tmp/cptmp' } if have_symlink? # src==dest (2) symlink and its target File.symlink 'cptmp', 'tmp/cptmp_symlink' assert_raises(ArgumentError) { install 'tmp/cptmp', 'tmp/cptmp_symlink' } assert_raises(ArgumentError) { install 'tmp/cptmp_symlink', 'tmp/cptmp' } # src==dest (3) looped symlink File.symlink 'symlink', 'tmp/symlink' assert_raises(Errno::ELOOP) { # File#install invokes open(2), always ELOOP must be raised install 'tmp/symlink', 'tmp/symlink' } end # pathname assert_nothing_raised { rm_f 'tmp/a'; touch 'tmp/a' install 'tmp/a', Pathname.new('tmp/b') rm_f 'tmp/a'; touch 'tmp/a' install Pathname.new('tmp/a'), 'tmp/b' rm_f 'tmp/a'; touch 'tmp/a' install Pathname.new('tmp/a'), Pathname.new('tmp/b') rm_f 'tmp/a' touch 'tmp/a' touch 'tmp/b' mkdir 'tmp/dest' install [Pathname.new('tmp/a'), Pathname.new('tmp/b')], 'tmp/dest' my_rm_rf 'tmp/dest' mkdir 'tmp/dest' install [Pathname.new('tmp/a'), Pathname.new('tmp/b')], Pathname.new('tmp/dest') } end if have_file_perm? def test_chmod check_singleton :chmod touch 'tmp/a' chmod 0700, 'tmp/a' assert_equal 0700, File.stat('tmp/a').mode & 0777 chmod 0500, 'tmp/a' assert_equal 0500, File.stat('tmp/a').mode & 0777 end def test_chmod_R check_singleton :chmod_R mkdir_p 'tmp/dir/dir' touch %w( tmp/dir/file tmp/dir/dir/file ) chmod_R 0700, 'tmp/dir' assert_equal 0700, File.stat('tmp/dir').mode & 0777 assert_equal 0700, File.stat('tmp/dir/file').mode & 0777 assert_equal 0700, File.stat('tmp/dir/dir').mode & 0777 assert_equal 0700, File.stat('tmp/dir/dir/file').mode & 0777 chmod_R 0500, 'tmp/dir' assert_equal 0500, File.stat('tmp/dir').mode & 0777 assert_equal 0500, File.stat('tmp/dir/file').mode & 0777 assert_equal 0500, File.stat('tmp/dir/dir').mode & 0777 assert_equal 0500, File.stat('tmp/dir/dir/file').mode & 0777 chmod_R 0700, 'tmp/dir' # to remove end # FIXME: How can I test this method? def test_chown check_singleton :chown end # FIXME: How can I test this method? def test_chown_R check_singleton :chown_R end end def test_copy_entry check_singleton :copy_entry each_srcdest do |srcpath, destpath| copy_entry srcpath, destpath assert_same_file srcpath, destpath assert_equal File.stat(srcpath).ftype, File.stat(destpath).ftype end if have_symlink? # root is a symlink File.symlink 'somewhere', 'tmp/symsrc' copy_entry 'tmp/symsrc', 'tmp/symdest' assert_symlink 'tmp/symdest' assert_equal 'somewhere', File.readlink('tmp/symdest') # content is a symlink mkdir 'tmp/dir' File.symlink 'somewhere', 'tmp/dir/sym' copy_entry 'tmp/dir', 'tmp/dirdest' assert_directory 'tmp/dirdest' assert_not_symlink 'tmp/dirdest' assert_symlink 'tmp/dirdest/sym' assert_equal 'somewhere', File.readlink('tmp/dirdest/sym') end end def test_copy_file check_singleton :copy_file each_srcdest do |srcpath, destpath| copy_file srcpath, destpath assert_same_file srcpath, destpath end end def test_copy_stream check_singleton :copy_stream # IO each_srcdest do |srcpath, destpath| File.open(srcpath) {|src| File.open(destpath, 'w') {|dest| copy_stream src, dest } } assert_same_file srcpath, destpath end # duck typing test [ruby-dev:25369] my_rm_rf 'tmp' Dir.mkdir 'tmp' each_srcdest do |srcpath, destpath| File.open(srcpath) {|src| File.open(destpath, 'w') {|dest| copy_stream Stream.new(src), Stream.new(dest) } } assert_same_file srcpath, destpath end end def test_remove_file check_singleton :remove_file File.open('data/tmp', 'w') {|f| f.puts 'dummy' } remove_file 'data/tmp' assert_file_not_exist 'data/tmp' if have_file_perm? File.open('data/tmp', 'w') {|f| f.puts 'dummy' } File.chmod 0, 'data/tmp' remove_file 'data/tmp' assert_file_not_exist 'data/tmp' end end def test_remove_dir check_singleton :remove_dir Dir.mkdir 'data/tmpdir' File.open('data/tmpdir/a', 'w') {|f| f.puts 'dummy' } remove_dir 'data/tmpdir' assert_file_not_exist 'data/tmpdir' if have_file_perm? Dir.mkdir 'data/tmpdir' File.chmod 0555, 'data/tmpdir' remove_dir 'data/tmpdir' assert_file_not_exist 'data/tmpdir' end end def test_compare_file check_singleton :compare_file # FIXME end def test_compare_stream check_singleton :compare_stream # FIXME end class Stream def initialize(f) @f = f end def read(n) @f.read(n) end def write(str) @f.write str end end def test_uptodate? check_singleton :uptodate? prepare_time_data Dir.chdir('data') { assert( uptodate?('newest', %w(old newer notexist)) ) assert( ! uptodate?('newer', %w(old newest notexist)) ) assert( ! uptodate?('notexist', %w(old newest newer)) ) } # pathname touch 'tmp/a' touch 'tmp/b' touch 'tmp/c' assert_nothing_raised { uptodate? Pathname.new('tmp/a'), ['tmp/b', 'tmp/c'] uptodate? 'tmp/a', [Pathname.new('tmp/b'), 'tmp/c'] uptodate? 'tmp/a', ['tmp/b', Pathname.new('tmp/c')] uptodate? Pathname.new('tmp/a'), [Pathname.new('tmp/b'), Pathname.new('tmp/c')] } end def test_cd check_singleton :cd end def test_chdir check_singleton :chdir end def test_getwd check_singleton :getwd end def test_identical? check_singleton :identical? end def test_link check_singleton :link end def test_makedirs check_singleton :makedirs end def test_mkpath check_singleton :mkpath end def test_move check_singleton :move end def test_rm_rf check_singleton :rm_rf end def test_rmdir check_singleton :rmdir end def test_rmtree check_singleton :rmtree end def test_safe_unlink check_singleton :safe_unlink end def test_symlink check_singleton :symlink end def test_touch check_singleton :touch end def test_collect_methods end def test_commands end def test_have_option? end def test_options end def test_options_of end end ================================================ FILE: test/fileutils/test_nowrite.rb ================================================ # $Id$ require 'fileutils' require 'fileasserts' require 'tmpdir' require 'test/unit' class TestFileUtilsNoWrite < Test::Unit::TestCase include FileUtils::NoWrite def test_visibility FileUtils::METHODS.each do |m| assert_equal true, FileUtils::NoWrite.respond_to?(m, true), "FileUtils::NoWrite.#{m} is not defined" assert_equal true, FileUtils::NoWrite.respond_to?(m, false), "FileUtils::NoWrite.#{m} is not public" end FileUtils::METHODS.each do |m| assert_equal true, respond_to?(m, true), "FileUtils::NoWrite\##{m} is not defined" assert_equal true, FileUtils::NoWrite.private_method_defined?(m), "FileUtils::NoWrite\##{m} is not private" end end def my_rm_rf(path) if File.exist?('/bin/rm') system %Q[/bin/rm -rf "#{path}"] else FileUtils.rm_rf path end end SRC = 'data/src' COPY = 'data/copy' def setup @prevdir = Dir.pwd tmproot = "#{Dir.tmpdir}/fileutils.rb.#{$$}" Dir.mkdir tmproot unless File.directory?(tmproot) Dir.chdir tmproot my_rm_rf 'data'; Dir.mkdir 'data' my_rm_rf 'tmp'; Dir.mkdir 'tmp' File.open(SRC, 'w') {|f| f.puts 'dummy' } File.open(COPY, 'w') {|f| f.puts 'dummy' } end def teardown tmproot = Dir.pwd Dir.chdir @prevdir my_rm_rf tmproot end def test_cp cp SRC, 'tmp/cp' check 'tmp/cp' end def test_mv mv SRC, 'tmp/mv' check 'tmp/mv' end def check(dest) assert_file_not_exist dest assert_file_exist SRC assert_same_file SRC, COPY end def test_rm rm SRC assert_file_exist SRC assert_same_file SRC, COPY end def test_rm_f rm_f SRC assert_file_exist SRC assert_same_file SRC, COPY end def test_rm_rf rm_rf SRC assert_file_exist SRC assert_same_file SRC, COPY end def test_mkdir mkdir 'dir' assert_file_not_exist 'dir' end def test_mkdir_p mkdir 'dir/dir/dir' assert_file_not_exist 'dir' end end ================================================ FILE: test/fileutils/test_verbose.rb ================================================ # $Id$ require 'test/unit' require 'fileutils' class TestFileUtilsVerbose < Test::Unit::TestCase include FileUtils::Verbose def test_visibility FileUtils::METHODS.each do |m| assert_equal true, FileUtils::Verbose.respond_to?(m, true), "FileUtils::Verbose.#{m} is not defined" assert_equal true, FileUtils::Verbose.respond_to?(m, false), "FileUtils::Verbose.#{m} is not public" end FileUtils::METHODS.each do |m| assert_equal true, respond_to?(m, true), "FileUtils::Verbose.#{m} is not defined" assert_equal true, FileUtils::Verbose.private_method_defined?(m), "FileUtils::Verbose.#{m} is not private" end end end ================================================ FILE: test/gdbm/test_gdbm.rb ================================================ require 'test/unit' begin require 'gdbm' rescue LoadError end if defined? GDBM require 'tmpdir' require 'fileutils' class TestGDBM < Test::Unit::TestCase def TestGDBM.uname_s require 'rbconfig' case Config::CONFIG['target_os'] when 'cygwin' require 'Win32API' uname = Win32API.new('cygwin1', 'uname', 'P', 'I') utsname = ' ' * 100 raise 'cannot get system name' if uname.call(utsname) == -1 utsname.unpack('A20' * 5)[0] else Config::CONFIG['target_os'] end end SYSTEM = uname_s def setup @path = "tmptest_gdbm_" assert_instance_of(GDBM, @gdbm = GDBM.new(@path)) # prepare to make readonly GDBM file GDBM.open("tmptest_gdbm_rdonly", 0400) {|gdbm| gdbm['foo'] = 'FOO' } assert_instance_of(GDBM, @gdbm_rdonly = GDBM.new("tmptest_gdbm_rdonly", nil)) end def teardown assert_nil(@gdbm.close) assert_nil(@gdbm_rdonly.close) ObjectSpace.each_object(GDBM) do |obj| obj.close unless obj.closed? end File.delete *Dir.glob("*tmptest_gdbm*").to_a p Dir.glob("*tmptest_gdbm*") if $DEBUG end def check_size(expect, gdbm=@gdbm) assert_equal(expect, gdbm.size) n = 0 gdbm.each { n+=1 } assert_equal(expect, n) if expect == 0 assert_equal(true, gdbm.empty?) else assert_equal(false, gdbm.empty?) end end def have_fork? begin fork{} true rescue NotImplementedError false end end def test_s_new_has_no_block # GDBM.new ignore the block foo = true assert_instance_of(GDBM, gdbm = GDBM.new("tmptest_gdbm") { foo = false }) assert_equal(foo, true) assert_nil(gdbm.close) end def test_s_open_create_new return if /^CYGWIN_9/ =~ SYSTEM save_mask = File.umask(0) begin assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm")) gdbm.close assert_equal(File.stat("tmptest_gdbm").mode & 0777, 0666) assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm2", 0644)) gdbm.close assert_equal(File.stat("tmptest_gdbm2").mode & 0777, 0644) ensure File.umask save_mask end end def test_s_open_no_create assert_nil(gdbm = GDBM.open("tmptest_gdbm", nil), "this test is failed on libgdbm 1.8.0") ensure gdbm.close if gdbm end def test_s_open_3rd_arg assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm", 0644, GDBM::FAST)) gdbm.close # gdbm 1.8.0 specific if defined? GDBM::SYNC assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm", 0644, GDBM::SYNC)) gdbm.close end # gdbm 1.8.0 specific if defined? GDBM::NOLOCK assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm", 0644, GDBM::NOLOCK)) gdbm.close end end def test_s_open_with_block assert_equal(GDBM.open("tmptest_gdbm") { :foo }, :foo) end def test_s_open_lock return unless have_fork? # snip this test pid = fork() { assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm", 0644)) sleep 2 } begin sleep 1 assert_raise(Errno::EWOULDBLOCK) { begin assert_instance_of(GDBM, gdbm2 = GDBM.open("tmptest_gdbm", 0644)) rescue Errno::EAGAIN, Errno::EACCES raise Errno::EWOULDBLOCK end } ensure Process.wait pid end end =begin # Is it guaranteed on many OS? def test_s_open_lock_one_process # locking on one process assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm", 0644)) assert_raise(Errno::EWOULDBLOCK) { begin GDBM.open("tmptest_gdbm", 0644) rescue Errno::EAGAIN raise Errno::EWOULDBLOCK end } end =end def test_s_open_nolock # gdbm 1.8.0 specific if not defined? GDBM::NOLOCK return end return unless have_fork? # snip this test pid = fork() { assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm", 0644, GDBM::NOLOCK)) sleep 2 } sleep 1 begin gdbm2 = nil assert_nothing_raised(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) { assert_instance_of(GDBM, gdbm2 = GDBM.open("tmptest_gdbm", 0644)) } ensure Process.wait pid gdbm2.close if gdbm2 end p Dir.glob("tmptest_gdbm*") if $DEBUG pid = Process.fork() { assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm", 0644)) sleep 2 } begin sleep 1 gdbm2 = nil assert_nothing_raised(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) { # this test is failed on Cygwin98 (???) assert_instance_of(GDBM, gdbm2 = GDBM.open("tmptest_gdbm", 0644, GDBM::NOLOCK)) } ensure Process.wait pid gdbm2.close if gdbm2 end end def test_s_open_error return if /(ms|bcc)win|mingw|djgpp/ =~ RUBY_PLATFORM assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm", 0)) assert_raise(Errno::EACCES) { GDBM.open("tmptest_gdbm", 0) } gdbm.close end def test_close assert_instance_of(GDBM, gdbm = GDBM.open("tmptest_gdbm")) assert_nil(gdbm.close) # closed GDBM file assert_raise(RuntimeError) { gdbm.close } end def test_aref assert_equal('bar', @gdbm['foo'] = 'bar') assert_equal('bar', @gdbm['foo']) assert_nil(@gdbm['bar']) end def test_fetch assert_equal('bar', @gdbm['foo']='bar') assert_equal('bar', @gdbm.fetch('foo')) # key not found assert_raise(IndexError) { @gdbm.fetch('bar') } # test for `ifnone' arg assert_equal('baz', @gdbm.fetch('bar', 'baz')) # test for `ifnone' block assert_equal('foobar', @gdbm.fetch('bar') {|key| 'foo' + key }) end def test_aset num = 0 2.times {|i| assert_equal('foo', @gdbm['foo'] = 'foo') assert_equal('foo', @gdbm['foo']) assert_equal('bar', @gdbm['foo'] = 'bar') assert_equal('bar', @gdbm['foo']) num += 1 if i == 0 assert_equal(num, @gdbm.size) # assign nil assert_equal('', @gdbm['bar'] = '') assert_equal('', @gdbm['bar']) num += 1 if i == 0 assert_equal(num, @gdbm.size) # empty string assert_equal('', @gdbm[''] = '') assert_equal('', @gdbm['']) num += 1 if i == 0 assert_equal(num, @gdbm.size) # Fixnum assert_equal('200', @gdbm['100'] = '200') assert_equal('200', @gdbm['100']) num += 1 if i == 0 assert_equal(num, @gdbm.size) # Big key and value assert_equal('y' * 100, @gdbm['x' * 100] = 'y' * 100) assert_equal('y' * 100, @gdbm['x' * 100]) num += 1 if i == 0 assert_equal(num, @gdbm.size) } end def test_index assert_equal('bar', @gdbm['foo'] = 'bar') assert_equal('foo', @gdbm.index('bar')) assert_nil(@gdbm['bar']) end def test_values_at keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values assert_equal(values.reverse, @gdbm.values_at(*keys.reverse)) end def test_select_with_block keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values ret = @gdbm.select {|k,v| assert_equal(k.upcase, v) k != "bar" } assert_equal([['baz', 'BAZ'], ['foo', 'FOO']], ret.sort) end def test_length num = 10 assert_equal(0, @gdbm.size) num.times {|i| i = i.to_s @gdbm[i] = i } assert_equal(num, @gdbm.size) @gdbm.shift assert_equal(num - 1, @gdbm.size) end def test_empty? assert_equal(true, @gdbm.empty?) @gdbm['foo'] = 'FOO' assert_equal(false, @gdbm.empty?) end def test_each_pair n = 0 @gdbm.each_pair { n += 1 } assert_equal(0, n) keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values n = 0 ret = @gdbm.each_pair {|key, val| assert_not_nil(i = keys.index(key)) assert_equal(val, values[i]) n += 1 } assert_equal(keys.size, n) assert_equal(@gdbm, ret) end def test_each_value n = 0 @gdbm.each_value { n += 1 } assert_equal(0, n) keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values n = 0 ret = @gdbm.each_value {|val| assert_not_nil(key = @gdbm.index(val)) assert_not_nil(i = keys.index(key)) assert_equal(val, values[i]) n += 1 } assert_equal(keys.size, n) assert_equal(@gdbm, ret) end def test_each_key n = 0 @gdbm.each_key { n += 1 } assert_equal(0, n) keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values n = 0 ret = @gdbm.each_key {|key| assert_not_nil(i = keys.index(key)) assert_equal(@gdbm[key], values[i]) n += 1 } assert_equal(keys.size, n) assert_equal(@gdbm, ret) end def test_keys assert_equal([], @gdbm.keys) keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values assert_equal(keys.sort, @gdbm.keys.sort) assert_equal(values.sort, @gdbm.values.sort) end def test_values test_keys end def test_shift assert_nil(@gdbm.shift) assert_equal(0, @gdbm.size) keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values ret_keys = [] ret_values = [] while ret = @gdbm.shift ret_keys.push ret[0] ret_values.push ret[1] assert_equal(keys.size - ret_keys.size, @gdbm.size) end assert_equal(keys.sort, ret_keys.sort) assert_equal(values.sort, ret_values.sort) end def test_delete keys = %w(foo bar baz) values = %w(FOO BAR BAZ) key = keys[1] assert_nil(@gdbm.delete(key)) assert_equal(0, @gdbm.size) @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values assert_equal('BAR', @gdbm.delete(key)) assert_nil(@gdbm[key]) assert_equal(2, @gdbm.size) assert_nil(@gdbm.delete(key)) if /^CYGWIN_9/ !~ SYSTEM assert_raise(GDBMError) { @gdbm_rdonly.delete("foo") } assert_nil(@gdbm_rdonly.delete("bar")) end end def test_delete_with_block key = 'no called block' @gdbm[key] = 'foo' assert_equal('foo', @gdbm.delete(key) {|k| k.replace 'called block'}) assert_equal('no called block', key) assert_equal(0, @gdbm.size) key = 'no called block' assert_equal(:blockval, @gdbm.delete(key) {|k| k.replace 'called block'; :blockval}) assert_equal('called block', key) assert_equal(0, @gdbm.size) end def test_delete_if v = "0" 100.times {@gdbm[v] = v; v = v.next} ret = @gdbm.delete_if {|key, val| key.to_i < 50} assert_equal(@gdbm, ret) check_size(50, @gdbm) ret = @gdbm.delete_if {|key, val| key.to_i >= 50} assert_equal(@gdbm, ret) check_size(0, @gdbm) # break v = "0" 100.times {@gdbm[v] = v; v = v.next} check_size(100, @gdbm) n = 0; @gdbm.delete_if {|key, val| break if n > 50 n+=1 true } assert_equal(51, n) check_size(49, @gdbm) @gdbm.clear # raise v = "0" 100.times {@gdbm[v] = v; v = v.next} check_size(100, @gdbm) n = 0; begin @gdbm.delete_if {|key, val| raise "runtime error" if n > 50 n+=1 true } rescue end assert_equal(51, n) check_size(49, @gdbm) end def test_reject v = "0" 100.times {@gdbm[v] = v; v = v.next} hash = @gdbm.reject {|key, val| key.to_i < 50} assert_instance_of(Hash, hash) assert_equal(100, @gdbm.size) assert_equal(50, hash.size) hash.each_pair {|key,val| assert_equal(false, key.to_i < 50) assert_equal(key, val) } hash = @gdbm.reject {|key, val| key.to_i < 100} assert_instance_of(Hash, hash) assert_equal(true, hash.empty?) end def test_clear v = "1" 100.times {v = v.next; @gdbm[v] = v} assert_equal(@gdbm, @gdbm.clear) # validate GDBM#size i = 0 @gdbm.each { i += 1 } assert_equal(@gdbm.size, i) assert_equal(0, i) end def test_invert v = "0" 100.times {@gdbm[v] = v; v = v.next} hash = @gdbm.invert assert_instance_of(Hash, hash) assert_equal(100, hash.size) hash.each_pair {|key, val| assert_equal(key.to_i, val.to_i) } end def test_update hash = {} v = "0" 100.times {v = v.next; hash[v] = v} @gdbm["101"] = "101" @gdbm.update hash assert_equal(101, @gdbm.size) @gdbm.each_pair {|key, val| assert_equal(key.to_i, val.to_i) } end def test_replace hash = {} v = "0" 100.times {v = v.next; hash[v] = v} @gdbm["101"] = "101" @gdbm.replace hash assert_equal(100, @gdbm.size) @gdbm.each_pair {|key, val| assert_equal(key.to_i, val.to_i) } end def test_reorganize size1 = File.size(@path) i = "1" 1000.times {i = i.next; @gdbm[i] = i} @gdbm.clear @gdbm.sync size2 = File.size(@path) @gdbm.reorganize size3 = File.size(@path) # p [size1, size2, size3] assert_equal(true, size1 < size2) # this test is failed on Cygwin98. `GDBM version 1.8.0, as of May 19, 1999' assert_equal(true, size3 < size2) assert_equal(size1, size3) end def test_sync assert_instance_of(GDBM, gdbm = GDBM.open('tmptest_gdbm', 0666, GDBM::FAST)) assert_equal(gdbm.sync, gdbm) gdbm.close assert_instance_of(GDBM, gdbm = GDBM.open('tmptest_gdbm', 0666)) assert_equal(gdbm.sync, gdbm) gdbm.close end def test_cachesize= assert_equal(@gdbm.cachesize = 1024, 1024) end def test_fastmode= assert_equal(@gdbm.fastmode = true, true) end def test_syncmode= assert_equal(@gdbm.syncmode = true, true) end def test_haskey? assert_equal('bar', @gdbm['foo']='bar') assert_equal(true, @gdbm.has_key?('foo')) assert_equal(false, @gdbm.has_key?('bar')) end def test_has_value? assert_equal('bar', @gdbm['foo']='bar') assert_equal(true, @gdbm.has_value?('bar')) assert_equal(false, @gdbm.has_value?('foo')) end def test_to_a v = "0" 100.times {v = v.next; @gdbm[v] = v} ary = @gdbm.to_a assert_instance_of(Array, ary) assert_equal(100, ary.size) ary.each {|key,val| assert_equal(key.to_i, val.to_i) } end def test_to_hash v = "0" 100.times {v = v.next; @gdbm[v] = v} hash = @gdbm.to_hash assert_instance_of(Hash, hash) assert_equal(100, hash.size) hash.each {|key,val| assert_equal(key.to_i, val.to_i) } end end class TestGDBM2 < Test::Unit::TestCase TMPROOT = "#{Dir.tmpdir}/ruby-gdbm.#{$$}" def setup Dir.mkdir TMPROOT end def teardown FileUtils.rm_rf TMPROOT if File.directory?(TMPROOT) end def test_reader_open GDBM.open("#{TMPROOT}/a.dbm") {} v = GDBM.open("#{TMPROOT}/a.dbm", nil, GDBM::READER) {|d| assert_raises(GDBMError) { d["k"] = "v" } true } assert(v) end def test_newdb_open GDBM.open("#{TMPROOT}/a.dbm") {|dbm| dbm["k"] = "v" } v = GDBM.open("#{TMPROOT}/a.dbm", nil, GDBM::NEWDB) {|d| assert_equal(0, d.length) assert_nil(d["k"]) true } assert(v) end def test_freeze GDBM.open("#{TMPROOT}/a.dbm") {|d| d.freeze assert_raises(TypeError) { d["k"] = "v" } } end end end ================================================ FILE: test/iconv/test_basic.rb ================================================ require File.expand_path("../utils.rb", __FILE__) class TestIconv::Basic < TestIconv def test_euc2sjis iconv = Iconv.open('SHIFT_JIS', 'EUC-JP') str = iconv.iconv(EUCJ_STR) str << iconv.iconv(nil) assert_equal(SJIS_STR, str) iconv.close end def test_close iconv = Iconv.new('Shift_JIS', 'EUC-JP') output = "" begin output += iconv.iconv(EUCJ_STR) output += iconv.iconv(nil) ensure assert_respond_to(iconv, :close) assert_equal("", iconv.close) assert_equal(SJIS_STR, output) end end def test_open_without_block assert_respond_to(Iconv, :open) iconv = Iconv.open('SHIFT_JIS', 'EUC-JP') str = iconv.iconv(EUCJ_STR) str << iconv.iconv(nil) assert_equal(SJIS_STR, str ) iconv.close end def test_open_with_block input = "#{EUCJ_STR}\n"*2 output = "" Iconv.open("Shift_JIS", "EUC-JP") do |cd| input.each_line do |s| output << cd.iconv(s) end output << cd.iconv(nil) end assert_equal("#{SJIS_STR}\n"*2, output) end def test_unknown_encoding assert_raise(Iconv::InvalidEncoding) { Iconv.iconv("utf-8", "X-UKNOWN", "heh") } assert_raise(Iconv::InvalidEncoding, '[ruby-dev:39487]') { Iconv.iconv("X-UNKNOWN-1", "X-UNKNOWN-2") {break} } end end if defined?(TestIconv) ================================================ FILE: test/iconv/test_option.rb ================================================ require File.expand_path("../utils.rb", __FILE__) class TestIconv::Option < TestIconv def test_ignore_option iconv = Iconv.new('SHIFT_JIS', 'EUC-JP//ignore') str = iconv.iconv(EUCJ_STR) str << iconv.iconv(nil) assert_equal(SJIS_STR, str) iconv.close iconv = Iconv.new('SHIFT_JIS//IGNORE', 'EUC-JP//ignore') str = iconv.iconv(EUCJ_STR) str << iconv.iconv(nil) assert_equal(SJIS_STR, str) iconv.close end def test_translit_option iconv = Iconv.new('SHIFT_JIS', 'EUC-JP//ignore') str = iconv.iconv(EUCJ_STR) str << iconv.iconv(nil) assert_equal(SJIS_STR, str) iconv.close iconv = Iconv.new('SHIFT_JIS//TRANSLIT', 'EUC-JP//translit//ignore') str = iconv.iconv(EUCJ_STR) str << iconv.iconv(nil) assert_equal(SJIS_STR, str) iconv.close end end if defined?(TestIconv) ================================================ FILE: test/iconv/test_partial.rb ================================================ require File.expand_path("../utils.rb", __FILE__) class TestIconv::Partial < TestIconv def test_partial_ascii c = Iconv.open(ASCII, ASCII) ref = '[ruby-core:17092]' rescue return else assert_equal("abc", c.iconv("abc")) assert_equal("c", c.iconv("abc", 2), "#{ref}: with start") assert_equal("c", c.iconv("abc", 2, 1), "#{ref}: with start, length") assert_equal("c", c.iconv("abc", 2, 5), "#{ref}: with start, longer length") assert_equal("bc", c.iconv("abc", -2), "#{ref}: with nagative start") assert_equal("b", c.iconv("abc", -2, 1), "#{ref}: with nagative start, length") assert_equal("bc", c.iconv("abc", -2, 5), "#{ref}: with nagative start, longer length") assert_equal("", c.iconv("abc", 5), "#{ref}: with OOB") assert_equal("", c.iconv("abc", 5, 2), "#{ref}: with OOB, length") ensure c.close if c end def test_partial_euc2sjis c = Iconv.open('SHIFT_JIS', 'EUC-JP') rescue return else assert_equal(SJIS_STR[0, 2], c.iconv(EUCJ_STR, 0, 2)) assert_equal(SJIS_STR, c.iconv(EUCJ_STR, 0, 20)) assert_equal(SJIS_STR[2..-1], c.iconv(EUCJ_STR, 2)) assert_equal(SJIS_STR[2, 2], c.iconv(EUCJ_STR, 2, 2)) assert_equal(SJIS_STR[2..-1], c.iconv(EUCJ_STR, 2, 20)) assert_equal(SJIS_STR[-4..-1], c.iconv(EUCJ_STR, -4)) assert_equal(SJIS_STR[-4, 2], c.iconv(EUCJ_STR, -4, 2)) assert_equal(SJIS_STR[-4..-1], c.iconv(EUCJ_STR, -4, 20)) assert_equal("", c.iconv(EUCJ_STR, 20)) assert_equal("", c.iconv(EUCJ_STR, 20, 2)) ensure c.close end end if defined?(TestIconv) ================================================ FILE: test/iconv/utils.rb ================================================ begin require 'iconv' rescue LoadError else require 'test/unit' end class TestIconv < ::Test::Unit::TestCase if defined?(::Encoding) and String.method_defined?(:force_encoding) def self.encode(str, enc) str.force_encoding(enc) end else def self.encode(str, enc) str end end def default_test self.class == TestIconv or super end ASCII = "ascii" EUCJ_STR = encode("\xa4\xa2\xa4\xa4\xa4\xa6\xa4\xa8\xa4\xaa", "EUC-JP").freeze SJIS_STR = encode("\x82\xa0\x82\xa2\x82\xa4\x82\xa6\x82\xa8", "Shift_JIS").freeze end if defined?(::Iconv) ================================================ FILE: test/io/nonblock/test_flush.rb ================================================ require 'test/unit' begin require 'io/nonblock' rescue LoadError end class TestIONonblock < Test::Unit::TestCase def test_flush # [ruby-dev:24985] r,w = IO.pipe w.nonblock = true w.sync = false w << "b" w.flush w << "a" * 4096 Thread.new { Thread.pass w.close } result = "" t = Thread.new { while (Thread.pass; s = r.read(4096)) result << s end } assert_raise(IOError) {w.flush} assert_nothing_raised {t.join} end end if IO.method_defined?(:nonblock) ================================================ FILE: test/logger/test_logger.rb ================================================ require 'test/unit' require 'logger' require 'tempfile' class TestLoggerSeverity < Test::Unit::TestCase def test_enum logger_levels = Logger.constants levels = ["WARN", "UNKNOWN", "INFO", "FATAL", "DEBUG", "ERROR"] Logger::Severity.constants.each do |level| assert(levels.include?(level)) assert(logger_levels.include?(level)) end assert_equal(levels.size, Logger::Severity.constants.size) end end class TestLogger < Test::Unit::TestCase include Logger::Severity def setup @logger = Logger.new(nil) end def test_const_progname assert %r!\Alogger\.rb/\S+\z! === Logger::ProgName end class Log attr_reader :label, :datetime, :pid, :severity, :progname, :msg def initialize(line) /\A(\w+), \[([^#]*)#(\d+)\]\s+(\w+) -- (\w*): ([\x0-\xff]*)/ =~ line @label, @datetime, @pid, @severity, @progname, @msg = $1, $2, $3, $4, $5, $6 end end def log_add(logger, severity, msg, progname = nil, &block) log(logger, :add, severity, msg, progname, &block) end def log(logger, msg_id, *arg, &block) Log.new(log_raw(logger, msg_id, *arg, &block)) end def log_raw(logger, msg_id, *arg, &block) logdev = Tempfile.new(File.basename(__FILE__) + '.log') logger.instance_eval { @logdev = Logger::LogDevice.new(logdev) } logger.__send__(msg_id, *arg, &block) logdev.open msg = logdev.read logdev.close msg end def test_level @logger.level = UNKNOWN assert_equal(UNKNOWN, @logger.level) @logger.level = INFO assert_equal(INFO, @logger.level) @logger.sev_threshold = ERROR assert_equal(ERROR, @logger.sev_threshold) @logger.sev_threshold = WARN assert_equal(WARN, @logger.sev_threshold) assert_equal(WARN, @logger.level) @logger.level = DEBUG assert(@logger.debug?) assert(@logger.info?) @logger.level = INFO assert(!@logger.debug?) assert(@logger.info?) assert(@logger.warn?) @logger.level = WARN assert(!@logger.info?) assert(@logger.warn?) assert(@logger.error?) @logger.level = ERROR assert(!@logger.warn?) assert(@logger.error?) assert(@logger.fatal?) @logger.level = FATAL assert(!@logger.error?) assert(@logger.fatal?) @logger.level = UNKNOWN assert(!@logger.error?) assert(!@logger.fatal?) end def test_progname assert_nil(@logger.progname) @logger.progname = "name" assert_equal("name", @logger.progname) end def test_datetime_format dummy = STDERR logger = Logger.new(dummy) log = log_add(logger, INFO, "foo") assert_match(/^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d.\s*\d+ $/, log.datetime) logger.datetime_format = "%d%b%Y@%H:%M:%S" log = log_add(logger, INFO, "foo") assert_match(/^\d\d\w\w\w\d\d\d\d@\d\d:\d\d:\d\d$/, log.datetime) logger.datetime_format = "" log = log_add(logger, INFO, "foo") assert_match(/^$/, log.datetime) end def test_formatter dummy = STDERR logger = Logger.new(dummy) # default log = log(logger, :info, "foo") assert_equal("foo\n", log.msg) # config logger.formatter = proc { |severity, timestamp, progname, msg| "#{severity}:#{msg}\n\n" } line = log_raw(logger, :info, "foo") assert_equal("INFO:foo\n\n", line) # recover logger.formatter = nil log = log(logger, :info, "foo") assert_equal("foo\n", log.msg) # again o = Object.new def o.call(severity, timestamp, progname, msg) "<<#{severity}-#{msg}>>\n" end logger.formatter = o line = log_raw(logger, :info, "foo") assert_equal("<>\n", line) end def test_initialize logger = Logger.new(STDERR) assert_nil(logger.progname) assert_equal(DEBUG, logger.level) assert_nil(logger.datetime_format) end def test_add logger = Logger.new(nil) logger.progname = "my_progname" assert(logger.add(INFO)) log = log_add(logger, nil, "msg") assert_equal("ANY", log.severity) assert_equal("my_progname", log.progname) logger.level = WARN assert(logger.log(INFO)) assert_nil(log_add(logger, INFO, "msg").msg) log = log_add(logger, WARN, nil) { "msg" } assert_equal("msg\n", log.msg) log = log_add(logger, WARN, "") { "msg" } assert_equal("\n", log.msg) assert_equal("my_progname", log.progname) log = log_add(logger, WARN, nil, "progname?") assert_equal("progname?\n", log.msg) assert_equal("my_progname", log.progname) end def test_level_log logger = Logger.new(nil) logger.progname = "my_progname" log = log(logger, :debug, "custom_progname") { "msg" } assert_equal("msg\n", log.msg) assert_equal("custom_progname", log.progname) assert_equal("DEBUG", log.severity) assert_equal("D", log.label) # log = log(logger, :debug) { "msg_block" } assert_equal("msg_block\n", log.msg) assert_equal("my_progname", log.progname) log = log(logger, :debug, "msg_inline") assert_equal("msg_inline\n", log.msg) assert_equal("my_progname", log.progname) # log = log(logger, :info, "custom_progname") { "msg" } assert_equal("msg\n", log.msg) assert_equal("custom_progname", log.progname) assert_equal("INFO", log.severity) assert_equal("I", log.label) # log = log(logger, :warn, "custom_progname") { "msg" } assert_equal("msg\n", log.msg) assert_equal("custom_progname", log.progname) assert_equal("WARN", log.severity) assert_equal("W", log.label) # log = log(logger, :error, "custom_progname") { "msg" } assert_equal("msg\n", log.msg) assert_equal("custom_progname", log.progname) assert_equal("ERROR", log.severity) assert_equal("E", log.label) # log = log(logger, :fatal, "custom_progname") { "msg" } assert_equal("msg\n", log.msg) assert_equal("custom_progname", log.progname) assert_equal("FATAL", log.severity) assert_equal("F", log.label) # log = log(logger, :unknown, "custom_progname") { "msg" } assert_equal("msg\n", log.msg) assert_equal("custom_progname", log.progname) assert_equal("ANY", log.severity) assert_equal("A", log.label) end def test_close r, w = IO.pipe assert(!w.closed?) logger = Logger.new(w) logger.close assert(w.closed?) r.close end class MyError < StandardError end class MyMsg def inspect "my_msg" end end def test_format logger = Logger.new(nil) log = log_add(logger, INFO, "msg\n") assert_equal("msg\n\n", log.msg) begin raise MyError.new("excn") rescue MyError => e log = log_add(logger, INFO, e) assert_match(/^excn \(TestLogger::MyError\)/, log.msg) # expects backtrace is dumped across multi lines. 10 might be changed. assert(log.msg.split(/\n/).size >= 10) end log = log_add(logger, INFO, MyMsg.new) assert_equal("my_msg\n", log.msg) end def test_lshift r, w = IO.pipe logger = Logger.new(w) logger << "msg" read_ready, = IO.select([r], nil, nil, 0.1) w.close msg = r.read r.close assert_equal("msg", msg) # r, w = IO.pipe logger = Logger.new(w) logger << "msg2\n\n" read_ready, = IO.select([r], nil, nil, 0.1) w.close msg = r.read r.close assert_equal("msg2\n\n", msg) end end class TestLogDevice < Test::Unit::TestCase def d(log) Logger::LogDevice.new(log) end def test_initialize logdev = d(STDERR) assert_equal(STDERR, logdev.dev) assert_nil(logdev.filename) assert_raises(TypeError) do d(nil) end # filename = __FILE__ + ".#{$$}" begin logdev = d(filename) assert(File.exist?(filename)) assert(logdev.dev.sync) assert_equal(filename, logdev.filename) ensure logdev.close File.unlink(filename) end end def test_write r, w = IO.pipe logdev = d(w) logdev.write("msg2\n\n") read_ready, = IO.select([r], nil, nil, 0.1) w.close msg = r.read r.close assert_equal("msg2\n\n", msg) end def test_close r, w = IO.pipe logdev = d(w) logdev.write("msg2\n\n") read_ready, = IO.select([r], nil, nil, 0.1) assert(!w.closed?) logdev.close assert(w.closed?) r.close end def test_shifting_size logfile = File.basename(__FILE__) + '_1.log' logfile0 = logfile + '.0' logfile1 = logfile + '.1' logfile2 = logfile + '.2' logfile3 = logfile + '.3' File.unlink(logfile) if File.exist?(logfile) File.unlink(logfile0) if File.exist?(logfile0) File.unlink(logfile1) if File.exist?(logfile1) File.unlink(logfile2) if File.exist?(logfile2) logger = Logger.new(logfile, 4, 100) logger.error("0" * 15) assert(File.exist?(logfile)) assert(!File.exist?(logfile0)) logger.error("0" * 15) assert(File.exist?(logfile0)) assert(!File.exist?(logfile1)) logger.error("0" * 15) assert(File.exist?(logfile1)) assert(!File.exist?(logfile2)) logger.error("0" * 15) assert(File.exist?(logfile2)) assert(!File.exist?(logfile3)) logger.error("0" * 15) assert(!File.exist?(logfile3)) logger.error("0" * 15) assert(!File.exist?(logfile3)) logger.close File.unlink(logfile) File.unlink(logfile0) File.unlink(logfile1) File.unlink(logfile2) logfile = File.basename(__FILE__) + '_2.log' logfile0 = logfile + '.0' logfile1 = logfile + '.1' logfile2 = logfile + '.2' logfile3 = logfile + '.3' logger = Logger.new(logfile, 4, 150) logger.error("0" * 15) assert(File.exist?(logfile)) assert(!File.exist?(logfile0)) logger.error("0" * 15) assert(!File.exist?(logfile0)) logger.error("0" * 15) assert(File.exist?(logfile0)) assert(!File.exist?(logfile1)) logger.error("0" * 15) assert(!File.exist?(logfile1)) logger.error("0" * 15) assert(File.exist?(logfile1)) assert(!File.exist?(logfile2)) logger.error("0" * 15) assert(!File.exist?(logfile2)) logger.error("0" * 15) assert(File.exist?(logfile2)) assert(!File.exist?(logfile3)) logger.error("0" * 15) assert(!File.exist?(logfile3)) logger.error("0" * 15) assert(!File.exist?(logfile3)) logger.error("0" * 15) assert(!File.exist?(logfile3)) logger.close File.unlink(logfile) File.unlink(logfile0) File.unlink(logfile1) File.unlink(logfile2) end end ================================================ FILE: test/matrix/test_matrix.rb ================================================ require 'test/unit' require 'matrix' class TestMatrix < Test::Unit::TestCase def setup @m1 = Matrix[[1,2,3], [4,5,6]] @m2 = Matrix[[1,2,3], [4,5,6]] @m3 = @m1.clone @m4 = Matrix[[1,0, 2.0, 3.0], [4.0, 5.0, 6.0]] @n1 = Matrix[[2,3,4], [5,6,7]] end def test_identity assert_same @m1, @m1 assert_not_same @m1, @m2 assert_not_same @m1, @m3 assert_not_same @m1, @m4 assert_not_same @m1, @n1 end def test_equality assert_equal @m1, @m1 assert_equal @m1, @m2 assert_equal @m1, @m3 assert_not_equal @m1, @m4 assert_not_equal @m1, @n1 end def test_hash_equality assert @m1.eql?(@m1) assert @m1.eql?(@m2) assert @m1.eql?(@m3) assert !@m1.eql?(@m4) assert !@m1.eql?(@n1) hash = { @m1 => :value } assert hash.key?(@m1) assert hash.key?(@m2) assert hash.key?(@m3) assert !hash.key?(@m4) assert !hash.key?(@n1) end end ================================================ FILE: test/matrix/test_vector.rb ================================================ require 'test/unit' require 'matrix' class TestVector < Test::Unit::TestCase def setup @v1 = Vector[1,2,3] @v2 = Vector[1,2,3] @v3 = @v1.clone @v4 = Vector[1,0, 2.0, 3.0] @w1 = Vector[2,3,4] end def test_identity assert_same @v1, @v1 assert_not_same @v1, @v2 assert_not_same @v1, @v3 assert_not_same @v1, @v4 assert_not_same @v1, @w1 end def test_equality assert_equal @v1, @v1 assert_equal @v1, @v2 assert_equal @v1, @v3 assert_not_equal @v1, @v4 assert_not_equal @v1, @w1 end def test_hash_equality assert @v1.eql?(@v1) assert @v1.eql?(@v2) assert @v1.eql?(@v3) assert !@v1.eql?(@v4) assert !@v1.eql?(@w1) hash = { @v1 => :value } assert hash.key?(@v1) assert hash.key?(@v2) assert hash.key?(@v3) assert !hash.key?(@v4) assert !hash.key?(@w1) end end ================================================ FILE: test/monitor/test_monitor.rb ================================================ require "monitor" require "thread" require "test/unit" class TestMonitor < Test::Unit::TestCase def setup @monitor = Monitor.new end def test_enter ary = [] queue = Queue.new th = Thread.start { queue.pop @monitor.enter for i in 6 .. 10 ary.push(i) Thread.pass end @monitor.exit } @monitor.enter queue.enq(nil) for i in 1 .. 5 ary.push(i) Thread.pass end @monitor.exit th.join assert_equal((1..10).to_a, ary) end def test_synchronize ary = [] queue = Queue.new th = Thread.start { queue.pop @monitor.synchronize do for i in 6 .. 10 ary.push(i) Thread.pass end end } @monitor.synchronize do queue.enq(nil) for i in 1 .. 5 ary.push(i) Thread.pass end end th.join assert_equal((1..10).to_a, ary) end def test_killed_thread_in_synchronize ary = [] queue = Queue.new t1 = Thread.start { queue.pop @monitor.synchronize { ary << :t1 } } t2 = Thread.start { queue.pop @monitor.synchronize { ary << :t2 } } @monitor.synchronize do queue.enq(nil) queue.enq(nil) assert_equal([], ary) t1.kill t2.kill ary << :main end assert_equal([:main], ary) end def test_try_enter queue1 = Queue.new queue2 = Queue.new th = Thread.start { queue1.deq @monitor.enter queue2.enq(nil) queue1.deq @monitor.exit queue2.enq(nil) } assert_equal(true, @monitor.try_enter) @monitor.exit queue1.enq(nil) queue2.deq assert_equal(false, @monitor.try_enter) queue1.enq(nil) queue2.deq assert_equal(true, @monitor.try_enter) end def test_cond cond = @monitor.new_cond a = "foo" queue1 = Queue.new Thread.start do queue1.deq @monitor.synchronize do a = "bar" cond.signal end end @monitor.synchronize do queue1.enq(nil) assert_equal("foo", a) result1 = cond.wait assert_equal(true, result1) assert_equal("bar", a) end end def test_timedwait cond = @monitor.new_cond b = "foo" queue2 = Queue.new Thread.start do queue2.deq @monitor.synchronize do b = "bar" cond.signal end end @monitor.synchronize do queue2.enq(nil) assert_equal("foo", b) result2 = cond.wait(0.1) assert_equal(true, result2) assert_equal("bar", b) end c = "foo" queue3 = Queue.new Thread.start do queue3.deq @monitor.synchronize do c = "bar" cond.signal end end @monitor.synchronize do assert_equal("foo", c) result3 = cond.wait(0.1) assert_equal(false, result3) assert_equal("foo", c) queue3.enq(nil) result4 = cond.wait assert_equal(true, result4) assert_equal("bar", c) end # d = "foo" # cumber_thread = Thread.start { # loop do # @monitor.synchronize do # d = "foo" # end # end # } # queue3 = Queue.new # Thread.start do # queue3.pop # @monitor.synchronize do # d = "bar" # cond.signal # end # end # @monitor.synchronize do # queue3.enq(nil) # assert_equal("foo", d) # result5 = cond.wait # assert_equal(true, result5) # # this thread has priority over cumber_thread # assert_equal("bar", d) # end # cumber_thread.kill end end ================================================ FILE: test/net/http/test_connection.rb ================================================ require 'net/http' require 'test/unit' module TestHTTP class HTTPConnectionTest < Test::Unit::TestCase def test_connection_refused_in_request bug2708 = '[ruby-core:28028]' port = nil localhost = "127.0.0.1" t = Thread.new { TCPServer.open(localhost, 0) do |serv| _, port, _, _ = serv.addr if clt = serv.accept clt.close end end } begin sleep 0.1 until port assert_raise(Errno::ECONNRESET, bug2708) { n = Net::HTTP.new(localhost, port) n.request_get('/') } ensure t.join if t end assert_raise(Errno::ECONNREFUSED, bug2708) { n = Net::HTTP.new(localhost, port) n.request_get('/') } end end end ================================================ FILE: test/net/http/test_httpheader.rb ================================================ require 'net/http' require 'test/unit' class HTTPHeaderTest < Test::Unit::TestCase class C include Net::HTTPHeader def initialize initialize_http_header({}) end attr_accessor :body end def setup @c = C.new end def test_size assert_equal 0, @c.size @c['a'] = 'a' assert_equal 1, @c.size @c['b'] = 'b' assert_equal 2, @c.size @c['b'] = 'b' assert_equal 2, @c.size @c['c'] = 'c' assert_equal 3, @c.size end def test_ASET @c['My-Header'] = 'test string' @c['my-Header'] = 'test string' @c['My-header'] = 'test string' @c['my-header'] = 'test string' @c['MY-HEADER'] = 'test string' assert_equal 1, @c.size @c['AaA'] = 'aaa' @c['aaA'] = 'aaa' @c['AAa'] = 'aaa' assert_equal 2, @c.length end def test_AREF @c['My-Header'] = 'test string' assert_equal 'test string', @c['my-header'] assert_equal 'test string', @c['MY-header'] assert_equal 'test string', @c['my-HEADER'] @c['Next-Header'] = 'next string' assert_equal 'next string', @c['next-header'] end def test_add_field @c.add_field 'My-Header', 'a' assert_equal 'a', @c['My-Header'] assert_equal ['a'], @c.get_fields('My-Header') @c.add_field 'My-Header', 'b' assert_equal 'a, b', @c['My-Header'] assert_equal ['a', 'b'], @c.get_fields('My-Header') @c.add_field 'My-Header', 'c' assert_equal 'a, b, c', @c['My-Header'] assert_equal ['a', 'b', 'c'], @c.get_fields('My-Header') @c.add_field 'My-Header', 'd, d' assert_equal 'a, b, c, d, d', @c['My-Header'] assert_equal ['a', 'b', 'c', 'd, d'], @c.get_fields('My-Header') end def test_get_fields @c['My-Header'] = 'test string' assert_equal ['test string'], @c.get_fields('my-header') assert_equal ['test string'], @c.get_fields('My-header') assert_equal ['test string'], @c.get_fields('my-Header') assert_nil @c.get_fields('not-found') assert_nil @c.get_fields('Not-Found') @c.get_fields('my-header').push 'junk' assert_equal ['test string'], @c.get_fields('my-header') @c.get_fields('my-header').clear assert_equal ['test string'], @c.get_fields('my-header') end def test_delete @c['My-Header'] = 'test' assert_equal 'test', @c['My-Header'] assert_nil @c['not-found'] @c.delete 'My-Header' assert_nil @c['My-Header'] assert_nil @c['not-found'] @c.delete 'My-Header' @c.delete 'My-Header' assert_nil @c['My-Header'] assert_nil @c['not-found'] end def test_each @c['My-Header'] = 'test' @c.each do |k, v| assert_equal 'my-header', k assert_equal 'test', v end @c.each do |k, v| assert_equal 'my-header', k assert_equal 'test', v end end def test_each_key @c['My-Header'] = 'test' @c.each_key do |k| assert_equal 'my-header', k end @c.each_key do |k| assert_equal 'my-header', k end end def test_each_value @c['My-Header'] = 'test' @c.each_value do |v| assert_equal 'test', v end @c.each_value do |v| assert_equal 'test', v end end def test_canonical_each @c['my-header'] = ['a', 'b'] @c.canonical_each do |k,v| assert_equal 'My-Header', k assert_equal 'a, b', v end end def test_each_capitalized @c['my-header'] = ['a', 'b'] @c.each_capitalized do |k,v| assert_equal 'My-Header', k assert_equal 'a, b', v end end def test_key? @c['My-Header'] = 'test' assert_equal true, @c.key?('My-Header') assert_equal true, @c.key?('my-header') assert_equal false, @c.key?('Not-Found') assert_equal false, @c.key?('not-found') assert_equal false, @c.key?('') assert_equal false, @c.key?('x' * 1024) end def test_to_hash end def test_range try_range(1..5, '1-5') try_range(234..567, '234-567') try_range(-5..-1, '-5') try_range(1..-1, '1-') end def try_range(r, s) @c['range'] = "bytes=#{s}" assert_equal r, Array(@c.range)[0] end def test_range= @c.range = 0..499 assert_equal 'bytes=0-499', @c['range'] @c.range = 0...500 assert_equal 'bytes=0-499', @c['range'] @c.range = 300 assert_equal 'bytes=0-299', @c['range'] @c.range = -400 assert_equal 'bytes=-400', @c['range'] @c.set_range 0, 500 assert_equal 'bytes=0-499', @c['range'] end def test_content_range end def test_range_length @c['Content-Range'] = "bytes 0-499/1000" assert_equal 500, @c.range_length @c['Content-Range'] = "bytes 1-500/1000" assert_equal 500, @c.range_length @c['Content-Range'] = "bytes 1-1/1000" assert_equal 1, @c.range_length end def test_chunked? try_chunked true, 'chunked' try_chunked true, ' chunked ' try_chunked true, '(OK)chunked' try_chunked false, 'not-chunked' try_chunked false, 'chunked-but-not-chunked' end def try_chunked(bool, str) @c['transfer-encoding'] = str assert_equal bool, @c.chunked? end def test_content_length @c.delete('content-length') assert_nil @c['content-length'] try_content_length 500, '500' try_content_length 10000_0000_0000, '1000000000000' try_content_length 123, ' 123' try_content_length 1, '1 23' try_content_length 500, '(OK)500' assert_raises(Net::HTTPHeaderSyntaxError, 'here is no digit, but') { @c['content-length'] = 'no digit' @c.content_length } end def try_content_length(len, str) @c['content-length'] = str assert_equal len, @c.content_length end def test_content_length= @c.content_length = 0 assert_equal 0, @c.content_length @c.content_length = 1 assert_equal 1, @c.content_length @c.content_length = 999 assert_equal 999, @c.content_length @c.content_length = 10000000000000 assert_equal 10000000000000, @c.content_length end def test_content_type assert_nil @c.content_type @c.content_type = 'text/html' assert_equal 'text/html', @c.content_type @c.content_type = 'application/pdf' assert_equal 'application/pdf', @c.content_type @c.set_content_type 'text/html', {'charset' => 'iso-2022-jp'} assert_equal 'text/html', @c.content_type @c.content_type = 'text' assert_equal 'text', @c.content_type end def test_main_type assert_nil @c.main_type @c.content_type = 'text/html' assert_equal 'text', @c.main_type @c.content_type = 'application/pdf' assert_equal 'application', @c.main_type @c.set_content_type 'text/html', {'charset' => 'iso-2022-jp'} assert_equal 'text', @c.main_type @c.content_type = 'text' assert_equal 'text', @c.main_type end def test_sub_type assert_nil @c.sub_type @c.content_type = 'text/html' assert_equal 'html', @c.sub_type @c.content_type = 'application/pdf' assert_equal 'pdf', @c.sub_type @c.set_content_type 'text/html', {'charset' => 'iso-2022-jp'} assert_equal 'html', @c.sub_type @c.content_type = 'text' assert_nil @c.sub_type end def test_type_params assert_equal({}, @c.type_params) @c.content_type = 'text/html' assert_equal({}, @c.type_params) @c.content_type = 'application/pdf' assert_equal({}, @c.type_params) @c.set_content_type 'text/html', {'charset' => 'iso-2022-jp'} assert_equal({'charset' => 'iso-2022-jp'}, @c.type_params) @c.content_type = 'text' assert_equal({}, @c.type_params) end def test_set_content_type end def test_form_data= @c.form_data = {"cmd"=>"search", "q"=>"ruby", "max"=>"50"} assert_equal 'application/x-www-form-urlencoded', @c.content_type assert_equal %w( cmd=search max=50 q=ruby ), @c.body.split('&').sort end def test_set_form_data @c.set_form_data "cmd"=>"search", "q"=>"ruby", "max"=>"50" assert_equal 'application/x-www-form-urlencoded', @c.content_type assert_equal %w( cmd=search max=50 q=ruby ), @c.body.split('&').sort @c.set_form_data "cmd"=>"search", "q"=>"ruby", "max"=>50 assert_equal 'application/x-www-form-urlencoded', @c.content_type assert_equal %w( cmd=search max=50 q=ruby ), @c.body.split('&').sort @c.set_form_data({"cmd"=>"search", "q"=>"ruby", "max"=>"50"}, ';') assert_equal 'application/x-www-form-urlencoded', @c.content_type assert_equal %w( cmd=search max=50 q=ruby ), @c.body.split(';').sort end def test_basic_auth end def test_proxy_basic_auth end end ================================================ FILE: test/net/http/test_https_proxy.rb ================================================ begin require 'net/https' rescue LoadError end require 'test/unit' class HTTPSProxyTest < Test::Unit::TestCase def test_https_proxy_authentication t = nil TCPServer.open("127.0.0.1", 0) {|serv| _, port, _, _ = serv.addr t = Thread.new { proxy = Net::HTTP.Proxy("127.0.0.1", port, 'user', 'password') http = proxy.new("foo.example.org", 8000) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE begin http.start rescue EOFError end } sock = serv.accept proxy_request = sock.gets("\r\n\r\n") assert_equal( "CONNECT foo.example.org:8000 HTTP/1.1\r\n" + "Host: foo.example.org:8000\r\n" + "Proxy-Authorization: Basic dXNlcjpwYXNzd29yZA==\r\n" + "\r\n", proxy_request, "[ruby-dev:25673]") sock.close } ensure t.join if t end end if defined?(OpenSSL) ================================================ FILE: test/net/imap/test_imap.rb ================================================ require "net/imap" require "test/unit" class IMAPTest < Test::Unit::TestCase def test_parse_nomodesq parser = Net::IMAP::ResponseParser.new r = parser.parse(%Q'* OK [NOMODSEQ] Sorry, modsequences have not been enabled on this mailbox\r\n') assert_equal("OK", r.name) assert_equal("NOMODSEQ", r.data.code.name) end end ================================================ FILE: test/net/pop/test_pop.rb ================================================ require 'net/pop' require 'test/unit' require 'digest/md5' class TestPOP < Test::Unit::TestCase def setup @users = {'user' => 'pass' } @ok_user = 'user' @stamp_base = "#{$$}.#{Time.now.to_i}@localhost" end def test_pop_auth_ok pop_test(false) do |pop| assert_instance_of Net::POP3, pop assert_nothing_raised do pop.start(@ok_user, @users[@ok_user]) end end end def test_pop_auth_ng pop_test(false) do |pop| assert_instance_of Net::POP3, pop assert_raise Net::POPAuthenticationError do pop.start(@ok_user, 'bad password') end end end def test_apop_ok pop_test(@stamp_base) do |pop| assert_instance_of Net::APOP, pop assert_nothing_raised do pop.start(@ok_user, @users[@ok_user]) end end end def test_apop_ng pop_test(@stamp_base) do |pop| assert_instance_of Net::APOP, pop assert_raise Net::POPAuthenticationError do pop.start(@ok_user, 'bad password') end end end def test_apop_invalid pop_test("\x80"+@stamp_base) do |pop| assert_instance_of Net::APOP, pop assert_raise Net::POPAuthenticationError do pop.start(@ok_user, @users[@ok_user]) end end end def test_apop_invalid_at pop_test(@stamp_base.sub('@', '.')) do |pop| assert_instance_of Net::APOP, pop e = assert_raise Net::POPAuthenticationError do pop.start(@ok_user, @users[@ok_user]) end end end def pop_test(apop=false) host = 'localhost' server = TCPServer.new(host, 0) port = server.addr[1] thread = Thread.start do sock = server.accept begin pop_server_loop(sock, apop) ensure sock.close end end begin pop = Net::POP3::APOP(apop).new(host, port) #pop.set_debug_output $stderr yield pop ensure begin pop.finish rescue IOError raise unless $!.message == "POP session not yet started" end end ensure server.close thread.value end def pop_server_loop(sock, apop) if apop sock.print "+OK ready <#{apop}>\r\n" else sock.print "+OK ready\r\n" end user = nil while line = sock.gets case line when /^USER (.+)\r\n/ user = $1 if @users.key?(user) sock.print "+OK\r\n" else sock.print "-ERR unknown user\r\n" end when /^PASS (.+)\r\n/ if @users[user] == $1 sock.print "+OK\r\n" else sock.print "-ERR invalid password\r\n" end when /^APOP (.+) (.+)\r\n/ user = $1 if apop && Digest::MD5.hexdigest("<#{apop}>#{@users[user]}") == $2 sock.print "+OK\r\n" else sock.print "-ERR authentication failed\r\n" end when /^QUIT/ sock.print "+OK bye\r\n" return else sock.print "-ERR command not recognized\r\n" return end end end end ================================================ FILE: test/nkf/test_kconv.rb ================================================ require 'test/unit' require 'kconv' class TestKconv < Test::Unit::TestCase EUC_STR = "\ \xa5\xaa\xa5\xd6\xa5\xb8\xa5\xa7\xa5\xaf\xa5\xc8\xbb\xd8\xb8\xfe\ \xa5\xd7\xa5\xed\xa5\xb0\xa5\xe9\xa5\xdf\xa5\xf3\xa5\xb0\xb8\xc0\xb8\xec \x52\x75\x62\x79" UTF8_STR = "\ \xe3\x82\xaa\xe3\x83\x96\xe3\x82\xb8\xe3\x82\xa7\ \xe3\x82\xaf\xe3\x83\x88\xe6\x8c\x87\xe5\x90\x91\ \xe3\x83\x97\xe3\x83\xad\xe3\x82\xb0\xe3\x83\xa9\xe3\x83\x9f\ \xe3\x83\xb3\xe3\x82\xb0\xe8\xa8\x80\xe8\xaa\x9e \x52\x75\x62\x79" SJIS_STR = "\ \x83\x49\x83\x75\x83\x57\x83\x46\x83\x4e\x83\x67\x8e\x77\x8c\xfc\ \x83\x76\x83\x8d\x83\x4f\x83\x89\x83\x7e\x83\x93\x83\x4f\x8c\xbe\x8c\xea \x52\x75\x62\x79" JIS_STR = "\ \x1b\x24\x42\x25\x2a\x25\x56\x25\x38\x25\x27\x25\x2f\x25\x48\x3b\x58\x38\x7e\ \x25\x57\x25\x6d\x25\x30\x25\x69\x25\x5f\x25\x73\x25\x30\x38\x40\x38\x6c\x1b\x28\x42 \x52\x75\x62\x79" def test_eucjp assert(EUC_STR.iseuc) assert_equal(::Kconv::EUC, Kconv.guess(EUC_STR)) assert_equal(EUC_STR, EUC_STR.toeuc) assert_equal(EUC_STR, SJIS_STR.toeuc) assert_equal(EUC_STR, UTF8_STR.toeuc) assert_equal(EUC_STR, JIS_STR.toeuc) assert_equal(EUC_STR, EUC_STR.kconv(::NKF::EUC)) assert_equal(EUC_STR, SJIS_STR.kconv(::NKF::EUC)) assert_equal(EUC_STR, UTF8_STR.kconv(::NKF::EUC)) assert_equal(EUC_STR, JIS_STR.kconv(::NKF::EUC)) end def test_shiftjis assert(SJIS_STR.issjis) assert_equal(::Kconv::SJIS, Kconv.guess(SJIS_STR)) assert_equal(SJIS_STR, EUC_STR.tosjis) assert_equal(SJIS_STR, SJIS_STR.tosjis) assert_equal(SJIS_STR, UTF8_STR.tosjis) assert_equal(SJIS_STR, JIS_STR.tosjis) assert_equal(SJIS_STR, EUC_STR.kconv(::NKF::SJIS)) assert_equal(SJIS_STR, SJIS_STR.kconv(::NKF::SJIS)) assert_equal(SJIS_STR, UTF8_STR.kconv(::NKF::SJIS)) assert_equal(SJIS_STR, JIS_STR.kconv(::NKF::SJIS)) end def test_utf8 assert(UTF8_STR.isutf8) assert_equal(::Kconv::UTF8, Kconv.guess(UTF8_STR)) assert_equal(UTF8_STR, EUC_STR.toutf8) assert_equal(UTF8_STR, SJIS_STR.toutf8) assert_equal(UTF8_STR, UTF8_STR.toutf8) assert_equal(UTF8_STR, JIS_STR.toutf8) assert_equal(UTF8_STR, EUC_STR.kconv(::NKF::UTF8)) assert_equal(UTF8_STR, SJIS_STR.kconv(::NKF::UTF8)) assert_equal(UTF8_STR, UTF8_STR.kconv(::NKF::UTF8)) assert_equal(UTF8_STR, JIS_STR.kconv(::NKF::UTF8)) end def test_jis assert_equal(::Kconv::JIS, Kconv.guess(JIS_STR)) assert_equal(JIS_STR, EUC_STR.tojis) assert_equal(JIS_STR, SJIS_STR.tojis) assert_equal(JIS_STR, UTF8_STR.tojis) assert_equal(JIS_STR, JIS_STR.tojis) assert_equal(JIS_STR, EUC_STR.kconv(::NKF::JIS)) assert_equal(JIS_STR, SJIS_STR.kconv(::NKF::JIS)) assert_equal(JIS_STR, UTF8_STR.kconv(::NKF::JIS)) assert_equal(JIS_STR, JIS_STR.kconv(::NKF::JIS)) end end ================================================ FILE: test/nkf/test_nkf.rb ================================================ require 'test/unit' require 'nkf' class TestNKF < Test::Unit::TestCase EUC_STR = "\xa5\xaa\xa5\xd6\xa5\xb8\xa5\xa7\xa5\xaf\xa5\xc8\xbb\xd8\xb8\xfe\ \xa5\xb9\xa5\xaf\xa5\xea\xa5\xd7\xa5\xc8\xb8\xc0\xb8\xec\ Ruby" def test_guess str_euc = EUC_STR str_jis = NKF.nkf('-j', str_euc) assert_equal(::NKF::JIS, NKF.guess(str_jis)) assert_equal(::NKF::EUC, NKF.guess(str_euc)) end end ================================================ FILE: test/openssl/ssl_server.rb ================================================ require "socket" require "thread" require "openssl" require File.join(File.dirname(__FILE__), "utils.rb") def get_pem(io=$stdin) buf = "" while line = io.gets if /^-----BEGIN / =~ line buf << line break end end while line = io.gets buf << line if /^-----END / =~ line break end end return buf end def make_key(pem) begin return OpenSSL::PKey::RSA.new(pem) rescue return OpenSSL::PKey::DSA.new(pem) end end ca_cert = OpenSSL::X509::Certificate.new(get_pem) ssl_cert = OpenSSL::X509::Certificate.new(get_pem) ssl_key = make_key(get_pem) port = Integer(ARGV.shift) verify_mode = Integer(ARGV.shift) start_immediately = (/yes/ =~ ARGV.shift) store = OpenSSL::X509::Store.new store.add_cert(ca_cert) store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT ctx = OpenSSL::SSL::SSLContext.new ctx.cert_store = store #ctx.extra_chain_cert = [ ca_cert ] ctx.cert = ssl_cert ctx.key = ssl_key ctx.verify_mode = verify_mode Socket.do_not_reverse_lookup = true tcps = nil 100.times{|i| begin tcps = TCPServer.new("0.0.0.0", port+i) port = port + i break rescue Errno::EADDRINUSE next end } ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) ssls.start_immediately = start_immediately $stdout.sync = true $stdout.puts Process.pid $stdout.puts port loop do ssl = ssls.accept rescue next Thread.start{ q = Queue.new th = Thread.start{ ssl.write(q.shift) while true } while line = ssl.gets if line =~ /^STARTTLS$/ ssl.accept next end q.push(line) end th.kill if q.empty? ssl.close } end ================================================ FILE: test/openssl/test_asn1.rb ================================================ begin require "openssl" require File.join(File.dirname(__FILE__), "utils.rb") rescue LoadError end require 'test/unit' class OpenSSL::TestASN1 < Test::Unit::TestCase def test_decode subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA") key = OpenSSL::TestUtils::TEST_KEY_RSA1024 now = Time.at(Time.now.to_i) # suppress usec s = 0xdeadbeafdeadbeafdeadbeafdeadbeaf exts = [ ["basicConstraints","CA:TRUE,pathlen:1",true], ["keyUsage","keyCertSign, cRLSign",true], ["subjectKeyIdentifier","hash",false], ] dgst = OpenSSL::Digest::SHA1.new cert = OpenSSL::TestUtils.issue_cert( subj, key, s, now, now+3600, exts, nil, nil, dgst) asn1 = OpenSSL::ASN1.decode(cert) assert_equal(OpenSSL::ASN1::Sequence, asn1.class) assert_equal(3, asn1.value.size) tbs_cert, sig_alg, sig_val = *asn1.value assert_equal(OpenSSL::ASN1::Sequence, tbs_cert.class) assert_equal(8, tbs_cert.value.size) version = tbs_cert.value[0] assert_equal(:CONTEXT_SPECIFIC, version.tag_class) assert_equal(0, version.tag) assert_equal(1, version.value.size) assert_equal(OpenSSL::ASN1::Integer, version.value[0].class) assert_equal(2, version.value[0].value) serial = tbs_cert.value[1] assert_equal(OpenSSL::ASN1::Integer, serial.class) assert_equal(0xdeadbeafdeadbeafdeadbeafdeadbeaf, serial.value) sig = tbs_cert.value[2] assert_equal(OpenSSL::ASN1::Sequence, sig.class) assert_equal(2, sig.value.size) assert_equal(OpenSSL::ASN1::ObjectId, sig.value[0].class) assert_equal("1.2.840.113549.1.1.5", sig.value[0].oid) assert_equal(OpenSSL::ASN1::Null, sig.value[1].class) dn = tbs_cert.value[3] # issuer assert_equal(subj.hash, OpenSSL::X509::Name.new(dn).hash) assert_equal(OpenSSL::ASN1::Sequence, dn.class) assert_equal(3, dn.value.size) assert_equal(OpenSSL::ASN1::Set, dn.value[0].class) assert_equal(OpenSSL::ASN1::Set, dn.value[1].class) assert_equal(OpenSSL::ASN1::Set, dn.value[2].class) assert_equal(1, dn.value[0].value.size) assert_equal(1, dn.value[1].value.size) assert_equal(1, dn.value[2].value.size) assert_equal(OpenSSL::ASN1::Sequence, dn.value[0].value[0].class) assert_equal(OpenSSL::ASN1::Sequence, dn.value[1].value[0].class) assert_equal(OpenSSL::ASN1::Sequence, dn.value[2].value[0].class) assert_equal(2, dn.value[0].value[0].value.size) assert_equal(2, dn.value[1].value[0].value.size) assert_equal(2, dn.value[2].value[0].value.size) oid, value = *dn.value[0].value[0].value assert_equal(OpenSSL::ASN1::ObjectId, oid.class) assert_equal("0.9.2342.19200300.100.1.25", oid.oid) assert_equal(OpenSSL::ASN1::IA5String, value.class) assert_equal("org", value.value) oid, value = *dn.value[1].value[0].value assert_equal(OpenSSL::ASN1::ObjectId, oid.class) assert_equal("0.9.2342.19200300.100.1.25", oid.oid) assert_equal(OpenSSL::ASN1::IA5String, value.class) assert_equal("ruby-lang", value.value) oid, value = *dn.value[2].value[0].value assert_equal(OpenSSL::ASN1::ObjectId, oid.class) assert_equal("2.5.4.3", oid.oid) assert_equal(OpenSSL::ASN1::UTF8String, value.class) assert_equal("TestCA", value.value) validity = tbs_cert.value[4] assert_equal(OpenSSL::ASN1::Sequence, validity.class) assert_equal(2, validity.value.size) assert_equal(OpenSSL::ASN1::UTCTime, validity.value[0].class) assert_equal(now, validity.value[0].value) assert_equal(OpenSSL::ASN1::UTCTime, validity.value[1].class) assert_equal(now+3600, validity.value[1].value) dn = tbs_cert.value[5] # subject assert_equal(subj.hash, OpenSSL::X509::Name.new(dn).hash) assert_equal(OpenSSL::ASN1::Sequence, dn.class) assert_equal(3, dn.value.size) assert_equal(OpenSSL::ASN1::Set, dn.value[0].class) assert_equal(OpenSSL::ASN1::Set, dn.value[1].class) assert_equal(OpenSSL::ASN1::Set, dn.value[2].class) assert_equal(1, dn.value[0].value.size) assert_equal(1, dn.value[1].value.size) assert_equal(1, dn.value[2].value.size) assert_equal(OpenSSL::ASN1::Sequence, dn.value[0].value[0].class) assert_equal(OpenSSL::ASN1::Sequence, dn.value[1].value[0].class) assert_equal(OpenSSL::ASN1::Sequence, dn.value[2].value[0].class) assert_equal(2, dn.value[0].value[0].value.size) assert_equal(2, dn.value[1].value[0].value.size) assert_equal(2, dn.value[2].value[0].value.size) oid, value = *dn.value[0].value[0].value assert_equal(OpenSSL::ASN1::ObjectId, oid.class) assert_equal("0.9.2342.19200300.100.1.25", oid.oid) assert_equal(OpenSSL::ASN1::IA5String, value.class) assert_equal("org", value.value) oid, value = *dn.value[1].value[0].value assert_equal(OpenSSL::ASN1::ObjectId, oid.class) assert_equal("0.9.2342.19200300.100.1.25", oid.oid) assert_equal(OpenSSL::ASN1::IA5String, value.class) assert_equal("ruby-lang", value.value) oid, value = *dn.value[2].value[0].value assert_equal(OpenSSL::ASN1::ObjectId, oid.class) assert_equal("2.5.4.3", oid.oid) assert_equal(OpenSSL::ASN1::UTF8String, value.class) assert_equal("TestCA", value.value) pkey = tbs_cert.value[6] assert_equal(OpenSSL::ASN1::Sequence, pkey.class) assert_equal(2, pkey.value.size) assert_equal(OpenSSL::ASN1::Sequence, pkey.value[0].class) assert_equal(2, pkey.value[0].value.size) assert_equal(OpenSSL::ASN1::ObjectId, pkey.value[0].value[0].class) assert_equal("1.2.840.113549.1.1.1", pkey.value[0].value[0].oid) assert_equal(OpenSSL::ASN1::BitString, pkey.value[1].class) assert_equal(0, pkey.value[1].unused_bits) spkey = OpenSSL::ASN1.decode(pkey.value[1].value) assert_equal(OpenSSL::ASN1::Sequence, spkey.class) assert_equal(2, spkey.value.size) assert_equal(OpenSSL::ASN1::Integer, spkey.value[0].class) assert_equal(143085709396403084580358323862163416700436550432664688288860593156058579474547937626086626045206357324274536445865308750491138538454154232826011964045825759324933943290377903384882276841880081931690695505836279972214003660451338124170055999155993192881685495391496854691199517389593073052473319331505702779271, spkey.value[0].value) assert_equal(OpenSSL::ASN1::Integer, spkey.value[1].class) assert_equal(65537, spkey.value[1].value) extensions = tbs_cert.value[7] assert_equal(:CONTEXT_SPECIFIC, extensions.tag_class) assert_equal(3, extensions.tag) assert_equal(1, extensions.value.size) assert_equal(OpenSSL::ASN1::Sequence, extensions.value[0].class) assert_equal(3, extensions.value[0].value.size) ext = extensions.value[0].value[0] # basicConstraints assert_equal(OpenSSL::ASN1::Sequence, ext.class) assert_equal(3, ext.value.size) assert_equal(OpenSSL::ASN1::ObjectId, ext.value[0].class) assert_equal("2.5.29.19", ext.value[0].oid) assert_equal(OpenSSL::ASN1::Boolean, ext.value[1].class) assert_equal(true, ext.value[1].value) assert_equal(OpenSSL::ASN1::OctetString, ext.value[2].class) extv = OpenSSL::ASN1.decode(ext.value[2].value) assert_equal(OpenSSL::ASN1::Sequence, extv.class) assert_equal(2, extv.value.size) assert_equal(OpenSSL::ASN1::Boolean, extv.value[0].class) assert_equal(true, extv.value[0].value) assert_equal(OpenSSL::ASN1::Integer, extv.value[1].class) assert_equal(1, extv.value[1].value) ext = extensions.value[0].value[1] # keyUsage assert_equal(OpenSSL::ASN1::Sequence, ext.class) assert_equal(3, ext.value.size) assert_equal(OpenSSL::ASN1::ObjectId, ext.value[0].class) assert_equal("2.5.29.15", ext.value[0].oid) assert_equal(OpenSSL::ASN1::Boolean, ext.value[1].class) assert_equal(true, ext.value[1].value) assert_equal(OpenSSL::ASN1::OctetString, ext.value[2].class) extv = OpenSSL::ASN1.decode(ext.value[2].value) assert_equal(OpenSSL::ASN1::BitString, extv.class) str = "\000"; str[0] = 0b00000110 assert_equal(str, extv.value) ext = extensions.value[0].value[2] # subjetKeyIdentifier assert_equal(OpenSSL::ASN1::Sequence, ext.class) assert_equal(2, ext.value.size) assert_equal(OpenSSL::ASN1::ObjectId, ext.value[0].class) assert_equal("2.5.29.14", ext.value[0].oid) assert_equal(OpenSSL::ASN1::OctetString, ext.value[1].class) extv = OpenSSL::ASN1.decode(ext.value[1].value) assert_equal(OpenSSL::ASN1::OctetString, extv.class) sha1 = OpenSSL::Digest::SHA1.new sha1.update(pkey.value[1].value) assert_equal(sha1.digest, extv.value) assert_equal(OpenSSL::ASN1::Sequence, sig_alg.class) assert_equal(2, sig_alg.value.size) assert_equal(OpenSSL::ASN1::ObjectId, pkey.value[0].value[0].class) assert_equal("1.2.840.113549.1.1.1", pkey.value[0].value[0].oid) assert_equal(OpenSSL::ASN1::Null, pkey.value[0].value[1].class) assert_equal(OpenSSL::ASN1::BitString, sig_val.class) cululated_sig = key.sign(OpenSSL::Digest::SHA1.new, tbs_cert.to_der) assert_equal(cululated_sig, sig_val.value) end end if defined?(OpenSSL) ================================================ FILE: test/openssl/test_cipher.rb ================================================ begin require "openssl" rescue LoadError end require "test/unit" if defined?(OpenSSL) class OpenSSL::TestCipher < Test::Unit::TestCase def setup @c1 = OpenSSL::Cipher::Cipher.new("DES-EDE3-CBC") @c2 = OpenSSL::Cipher::DES.new(:EDE3, "CBC") @key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" @iv = "\0\0\0\0\0\0\0\0" @hexkey = "0000000000000000000000000000000000000000000000" @hexiv = "0000000000000000" @data = "DATA" end def teardown @c1 = @c2 = nil end def test_crypt @c1.encrypt.pkcs5_keyivgen(@key, @iv) @c2.encrypt.pkcs5_keyivgen(@key, @iv) s1 = @c1.update(@data) + @c1.final s2 = @c2.update(@data) + @c2.final assert_equal(s1, s2, "encrypt") @c1.decrypt.pkcs5_keyivgen(@key, @iv) @c2.decrypt.pkcs5_keyivgen(@key, @iv) assert_equal(@data, @c1.update(s1)+@c1.final, "decrypt") assert_equal(@data, @c2.update(s2)+@c2.final, "decrypt") end def test_info assert_equal("DES-EDE3-CBC", @c1.name, "name") assert_equal("DES-EDE3-CBC", @c2.name, "name") assert_kind_of(Fixnum, @c1.key_len, "key_len") assert_kind_of(Fixnum, @c1.iv_len, "iv_len") end def test_dup assert_equal(@c1.name, @c1.dup.name, "dup") assert_equal(@c1.name, @c1.clone.name, "clone") @c1.encrypt @c1.key = @key @c1.iv = @iv tmpc = @c1.dup s1 = @c1.update(@data) + @c1.final s2 = tmpc.update(@data) + tmpc.final assert_equal(s1, s2, "encrypt dup") end def test_reset @c1.encrypt @c1.key = @key @c1.iv = @iv s1 = @c1.update(@data) + @c1.final @c1.reset s2 = @c1.update(@data) + @c1.final assert_equal(s1, s2, "encrypt reset") end def test_empty_data @c1.encrypt assert_raises(ArgumentError){ @c1.update("") } end if OpenSSL::OPENSSL_VERSION_NUMBER > 0x00907000 def test_ciphers OpenSSL::Cipher.ciphers.each{|name| assert(OpenSSL::Cipher::Cipher.new(name).is_a?(OpenSSL::Cipher::Cipher)) } end def test_AES pt = File.read(__FILE__) %w(ECB CBC CFB OFB).each{|mode| c1 = OpenSSL::Cipher::AES256.new(mode) c1.encrypt c1.pkcs5_keyivgen("passwd") ct = c1.update(pt) + c1.final c2 = OpenSSL::Cipher::AES256.new(mode) c2.decrypt c2.pkcs5_keyivgen("passwd") assert_equal(pt, c2.update(ct) + c2.final) } end end end end ================================================ FILE: test/openssl/test_digest.rb ================================================ begin require "openssl" rescue LoadError end require "digest/md5" require "test/unit" if defined?(OpenSSL) class OpenSSL::TestDigest < Test::Unit::TestCase def setup @d1 = OpenSSL::Digest::Digest::new("MD5") @d2 = OpenSSL::Digest::MD5.new @md = Digest::MD5.new @data = "DATA" end def teardown @d1 = @d2 = @md = nil end def test_digest assert_equal(@md.digest, @d1.digest) assert_equal(@md.hexdigest, @d1.hexdigest) @d1 << @data @d2 << @data @md << @data assert_equal(@md.digest, @d1.digest) assert_equal(@md.hexdigest, @d1.hexdigest) assert_equal(@d1.digest, @d2.digest) assert_equal(@d1.hexdigest, @d2.hexdigest) assert_equal(@md.digest, OpenSSL::Digest::MD5.digest(@data)) assert_equal(@md.hexdigest, OpenSSL::Digest::MD5.hexdigest(@data)) end def test_eql assert(@d1 == @d2, "==") d = @d1.clone assert(d == @d1, "clone") end def test_info assert_equal("MD5", @d1.name, "name") assert_equal("MD5", @d2.name, "name") assert_equal(16, @d1.size, "size") end def test_dup @d1.update(@data) assert_equal(@d1.name, @d1.dup.name, "dup") assert_equal(@d1.name, @d1.clone.name, "clone") assert_equal(@d1.digest, @d1.clone.digest, "clone .digest") end def test_reset @d1.update(@data) dig1 = @d1.digest @d1.reset @d1.update(@data) dig2 = @d1.digest assert_equal(dig1, dig2, "reset") end if OpenSSL::OPENSSL_VERSION_NUMBER > 0x00908000 def encode16(str) str.unpack("H*").first end def test_098_features sha224_a = "abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5" sha256_a = "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb" sha384_a = "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31" sha512_a = "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75" assert_equal(sha224_a, OpenSSL::Digest::SHA224.hexdigest("a")) assert_equal(sha256_a, OpenSSL::Digest::SHA256.hexdigest("a")) assert_equal(sha384_a, OpenSSL::Digest::SHA384.hexdigest("a")) assert_equal(sha512_a, OpenSSL::Digest::SHA512.hexdigest("a")) assert_equal(sha224_a, encode16(OpenSSL::Digest::SHA224.digest("a"))) assert_equal(sha256_a, encode16(OpenSSL::Digest::SHA256.digest("a"))) assert_equal(sha384_a, encode16(OpenSSL::Digest::SHA384.digest("a"))) assert_equal(sha512_a, encode16(OpenSSL::Digest::SHA512.digest("a"))) end end end end ================================================ FILE: test/openssl/test_ec.rb ================================================ begin require "openssl" require File.join(File.dirname(__FILE__), "utils.rb") rescue LoadError end require "test/unit" if defined?(OpenSSL::PKey::EC) class OpenSSL::TestEC < Test::Unit::TestCase def setup @data1 = 'foo' @data2 = 'bar' * 1000 # data too long for DSA sig @group1 = OpenSSL::PKey::EC::Group.new('secp112r1') @group2 = OpenSSL::PKey::EC::Group.new('sect163k1') @key1 = OpenSSL::PKey::EC.new @key1.group = @group1 @key1.generate_key @key2 = OpenSSL::PKey::EC.new(@group2.curve_name) @key2.generate_key @groups = [@group1, @group2] @keys = [@key1, @key2] end def compare_keys(k1, k2) assert_equal(k1.to_pem, k2.to_pem) end def test_curve_names @groups.each_with_index do |group, idx| key = @keys[idx] assert_equal(group.curve_name, key.group.curve_name) end end def test_check_key for key in @keys assert_equal(key.check_key, true) assert_equal(key.private_key?, true) assert_equal(key.public_key?, true) end end def test_encoding for group in @groups for meth in [:to_der, :to_pem] txt = group.send(meth) gr = OpenSSL::PKey::EC::Group.new(txt) assert_equal(txt, gr.send(meth)) assert_equal(group.generator.to_bn, gr.generator.to_bn) assert_equal(group.cofactor, gr.cofactor) assert_equal(group.order, gr.order) assert_equal(group.seed, gr.seed) assert_equal(group.degree, gr.degree) end end for key in @keys group = key.group for meth in [:to_der, :to_pem] txt = key.send(meth) assert_equal(txt, OpenSSL::PKey::EC.new(txt).send(meth)) end bn = key.public_key.to_bn assert_equal(bn, OpenSSL::PKey::EC::Point.new(group, bn).to_bn) end end def test_set_keys for key in @keys k = OpenSSL::PKey::EC.new k.group = key.group k.private_key = key.private_key k.public_key = key.public_key compare_keys(key, k) end end def test_dsa_sign_verify for key in @keys sig = key.dsa_sign_asn1(@data1) assert_equal(key.dsa_verify_asn1(@data1, sig), true) assert_raises(OpenSSL::PKey::ECError) { key.dsa_sign_asn1(@data2) } end end def test_dh_compute_key for key in @keys k = OpenSSL::PKey::EC.new(key.group) k.generate_key puba = key.public_key pubb = k.public_key a = key.dh_compute_key(pubb) b = k.dh_compute_key(puba) assert_equal(a, b) end end # test Group: asn1_flag, point_conversion end end ================================================ FILE: test/openssl/test_hmac.rb ================================================ begin require "openssl" rescue LoadError end require "test/unit" if defined?(OpenSSL) class OpenSSL::TestHMAC < Test::Unit::TestCase def setup @digest = OpenSSL::Digest::MD5.new @key = "KEY" @data = "DATA" @h1 = OpenSSL::HMAC.new(@key, @digest) @h2 = OpenSSL::HMAC.new(@key, @digest) end def teardown end def test_hmac @h1.update(@data) assert_equal(OpenSSL::HMAC.digest(@digest, @key, @data), @h1.digest, "digest") assert_equal(OpenSSL::HMAC.hexdigest(@digest, @key, @data), @h1.hexdigest, "hexdigest") end def test_dup @h1.update(@data) h = @h1.dup assert_equal(@h1.digest, h.digest, "dup digest") end end end ================================================ FILE: test/openssl/test_ns_spki.rb ================================================ begin require "openssl" require File.join(File.dirname(__FILE__), "utils.rb") rescue LoadError end require "test/unit" if defined?(OpenSSL) class OpenSSL::TestNSSPI < Test::Unit::TestCase def setup # This request data is adopt from the specification of # "Netscape Extensions for User Key Generation". # -- http://wp.netscape.com/eng/security/comm4-keygen.html @b64 = "MIHFMHEwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAnX0TILJrOMUue+PtwBRE6XfV" @b64 << "WtKQbsshxk5ZhcUwcwyvcnIq9b82QhJdoACdD34rqfCAIND46fXKQUnb0mvKzQID" @b64 << "AQABFhFNb3ppbGxhSXNNeUZyaWVuZDANBgkqhkiG9w0BAQQFAANBAAKv2Eex2n/S" @b64 << "r/7iJNroWlSzSMtTiQTEB+ADWHGj9u1xrUrOilq/o2cuQxIfZcNZkYAkWP4DubqW" @b64 << "i0//rgBvmco=" end def teardown end def test_build_data key1 = OpenSSL::TestUtils::TEST_KEY_RSA1024 key2 = OpenSSL::TestUtils::TEST_KEY_RSA2048 spki = OpenSSL::Netscape::SPKI.new spki.challenge = "RandomString" spki.public_key = key1.public_key spki.sign(key1, OpenSSL::Digest::SHA1.new) assert(spki.verify(spki.public_key)) assert(spki.verify(key1.public_key)) assert(!spki.verify(key2.public_key)) der = spki.to_der spki = OpenSSL::Netscape::SPKI.new(der) assert_equal("RandomString", spki.challenge) assert_equal(key1.public_key.to_der, spki.public_key.to_der) assert(spki.verify(spki.public_key)) end def test_decode_data spki = OpenSSL::Netscape::SPKI.new(@b64) assert_equal(@b64, spki.to_pem) assert_equal(@b64.unpack("m").first, spki.to_der) assert_equal("MozillaIsMyFriend", spki.challenge) assert_equal(OpenSSL::PKey::RSA, spki.public_key.class) spki = OpenSSL::Netscape::SPKI.new(@b64.unpack("m").first) assert_equal(@b64, spki.to_pem) assert_equal(@b64.unpack("m").first, spki.to_der) assert_equal("MozillaIsMyFriend", spki.challenge) assert_equal(OpenSSL::PKey::RSA, spki.public_key.class) end end end ================================================ FILE: test/openssl/test_pair.rb ================================================ begin require "openssl" rescue LoadError end require 'test/unit' if defined?(OpenSSL) require 'socket' dir = File.expand_path(__FILE__) 2.times {dir = File.dirname(dir)} $:.replace([File.join(dir, "ruby")] | $:) require 'ut_eof' module SSLPair def server host = "127.0.0.1" port = 0 ctx = OpenSSL::SSL::SSLContext.new() ctx.ciphers = "ADH" tcps = TCPServer.new(host, port) ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) return ssls end def client(port) host = "127.0.0.1" ctx = OpenSSL::SSL::SSLContext.new() ctx.ciphers = "ADH" s = TCPSocket.new(host, port) ssl = OpenSSL::SSL::SSLSocket.new(s, ctx) ssl.connect ssl.sync_close = true ssl end def ssl_pair ssls = server th = Thread.new { ns = ssls.accept ssls.close ns } port = ssls.to_io.addr[1] c = client(port) s = th.value if block_given? begin yield c, s ensure c.close unless c.closed? s.close unless s.closed? end else return c, s end end end class OpenSSL::TestEOF1 < Test::Unit::TestCase include TestEOF include SSLPair def open_file(content) s1, s2 = ssl_pair Thread.new { s2 << content; s2.close } yield s1 end end class OpenSSL::TestEOF2 < Test::Unit::TestCase include TestEOF include SSLPair def open_file(content) s1, s2 = ssl_pair Thread.new { s1 << content; s1.close } yield s2 end end class OpenSSL::TestPair < Test::Unit::TestCase include SSLPair def test_getc ssl_pair {|s1, s2| s1 << "a" assert_equal(?a, s2.getc) } end def test_readpartial ssl_pair {|s1, s2| s2.write "a\nbcd" assert_equal("a\n", s1.gets) assert_equal("bcd", s1.readpartial(10)) s2.write "efg" assert_equal("efg", s1.readpartial(10)) s2.close assert_raise(EOFError) { s1.readpartial(10) } assert_raise(EOFError) { s1.readpartial(10) } assert_equal("", s1.readpartial(0)) } end def test_readall ssl_pair {|s1, s2| s2.close assert_equal("", s1.read) } end def test_readline ssl_pair {|s1, s2| s2.close assert_raise(EOFError) { s1.readline } } end def test_puts_meta ssl_pair {|s1, s2| begin old = $/ $/ = '*' s1.puts 'a' ensure $/ = old end s1.close assert_equal("a\n", s2.read) } end def test_puts_empty ssl_pair {|s1, s2| s1.puts s1.close assert_equal("\n", s2.read) } end end end ================================================ FILE: test/openssl/test_pkcs7.rb ================================================ begin require "openssl" require File.join(File.dirname(__FILE__), "utils.rb") rescue LoadError end require "test/unit" if defined?(OpenSSL) class OpenSSL::TestPKCS7 < Test::Unit::TestCase def setup @rsa1024 = OpenSSL::TestUtils::TEST_KEY_RSA1024 @rsa2048 = OpenSSL::TestUtils::TEST_KEY_RSA2048 ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1") ee2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE2") now = Time.now ca_exts = [ ["basicConstraints","CA:TRUE",true], ["keyUsage","keyCertSign, cRLSign",true], ["subjectKeyIdentifier","hash",false], ["authorityKeyIdentifier","keyid:always",false], ] @ca_cert = issue_cert(ca, @rsa2048, 1, Time.now, Time.now+3600, ca_exts, nil, nil, OpenSSL::Digest::SHA1.new) ee_exts = [ ["keyUsage","Non Repudiation, Digital Signature, Key Encipherment",true], ["authorityKeyIdentifier","keyid:always",false], ["extendedKeyUsage","clientAuth, emailProtection, codeSigning",false], ] @ee1_cert = issue_cert(ee1, @rsa1024, 2, Time.now, Time.now+1800, ee_exts, @ca_cert, @rsa2048, OpenSSL::Digest::SHA1.new) @ee2_cert = issue_cert(ee2, @rsa1024, 3, Time.now, Time.now+1800, ee_exts, @ca_cert, @rsa2048, OpenSSL::Digest::SHA1.new) end def issue_cert(*args) OpenSSL::TestUtils.issue_cert(*args) end def test_signed store = OpenSSL::X509::Store.new store.add_cert(@ca_cert) ca_certs = [@ca_cert] data = "aaaaa\r\nbbbbb\r\nccccc\r\n" tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs) p7 = OpenSSL::PKCS7::PKCS7.new(tmp.to_der) certs = p7.certificates signers = p7.signers assert(p7.verify([], store)) assert_equal(data, p7.data) assert_equal(2, certs.size) assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s) assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s) assert_equal(1, signers.size) assert_equal(@ee1_cert.serial, signers[0].serial) assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) # Normaly OpenSSL tries to translate the supplied content into canonical # MIME format (e.g. a newline character is converted into CR+LF). # If the content is a binary, PKCS7::BINARY flag should be used. data = "aaaaa\nbbbbb\nccccc\n" flag = OpenSSL::PKCS7::BINARY tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs, flag) p7 = OpenSSL::PKCS7::PKCS7.new(tmp.to_der) certs = p7.certificates signers = p7.signers assert(p7.verify([], store)) assert_equal(data, p7.data) assert_equal(2, certs.size) assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s) assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s) assert_equal(1, signers.size) assert_equal(@ee1_cert.serial, signers[0].serial) assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) # A signed-data which have multiple signatures can be created # through the following steps. # 1. create two signed-data # 2. copy signerInfo and certificate from one to another tmp1 = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, [], flag) tmp2 = OpenSSL::PKCS7.sign(@ee2_cert, @rsa1024, data, [], flag) tmp1.add_signer(tmp2.signers[0]) tmp1.add_certificate(@ee2_cert) p7 = OpenSSL::PKCS7::PKCS7.new(tmp1.to_der) certs = p7.certificates signers = p7.signers assert(p7.verify([], store)) assert_equal(data, p7.data) assert_equal(2, certs.size) assert_equal(2, signers.size) assert_equal(@ee1_cert.serial, signers[0].serial) assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) assert_equal(@ee2_cert.serial, signers[1].serial) assert_equal(@ee2_cert.issuer.to_s, signers[1].issuer.to_s) end def test_detached_sign store = OpenSSL::X509::Store.new store.add_cert(@ca_cert) ca_certs = [@ca_cert] data = "aaaaa\nbbbbb\nccccc\n" flag = OpenSSL::PKCS7::BINARY|OpenSSL::PKCS7::DETACHED tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs, flag) p7 = OpenSSL::PKCS7::PKCS7.new(tmp.to_der) a1 = OpenSSL::ASN1.decode(p7) certs = p7.certificates signers = p7.signers assert(!p7.verify([], store)) assert(p7.verify([], store, data)) assert_equal(data, p7.data) assert_equal(2, certs.size) assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s) assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s) assert_equal(1, signers.size) assert_equal(@ee1_cert.serial, signers[0].serial) assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) end def test_enveloped if OpenSSL::OPENSSL_VERSION_NUMBER <= 0x0090704f # PKCS7_encrypt() of OpenSSL-0.9.7d goes to SEGV. # http://www.mail-archive.com/openssl-dev@openssl.org/msg17376.html return end certs = [@ee1_cert, @ee2_cert] cipher = OpenSSL::Cipher::AES.new("128-CBC") data = "aaaaa\nbbbbb\nccccc\n" tmp = OpenSSL::PKCS7.encrypt(certs, data, cipher, OpenSSL::PKCS7::BINARY) p7 = OpenSSL::PKCS7::PKCS7.new(tmp.to_der) recip = p7.recipients assert_equal(:enveloped, p7.type) assert_equal(2, recip.size) assert_equal(@ca_cert.subject.to_s, recip[0].issuer.to_s) assert_equal(2, recip[0].serial) assert_equal(data, p7.decrypt(@rsa1024, @ee1_cert)) assert_equal(@ca_cert.subject.to_s, recip[1].issuer.to_s) assert_equal(3, recip[1].serial) assert_equal(data, p7.decrypt(@rsa1024, @ee2_cert)) end end end ================================================ FILE: test/openssl/test_pkey_rsa.rb ================================================ begin require "openssl" require File.join(File.dirname(__FILE__), "utils.rb") rescue LoadError end require 'test/unit' if defined?(OpenSSL) class OpenSSL::TestPKeyRSA < Test::Unit::TestCase def test_padding key = OpenSSL::PKey::RSA.new(512, 3) # Need right size for raw mode plain0 = "x" * (512/8) cipher = key.private_encrypt(plain0, OpenSSL::PKey::RSA::NO_PADDING) plain1 = key.public_decrypt(cipher, OpenSSL::PKey::RSA::NO_PADDING) assert_equal(plain0, plain1) # Need smaller size for pkcs1 mode plain0 = "x" * (512/8 - 11) cipher1 = key.private_encrypt(plain0, OpenSSL::PKey::RSA::PKCS1_PADDING) plain1 = key.public_decrypt(cipher1, OpenSSL::PKey::RSA::PKCS1_PADDING) assert_equal(plain0, plain1) cipherdef = key.private_encrypt(plain0) # PKCS1_PADDING is default plain1 = key.public_decrypt(cipherdef) assert_equal(plain0, plain1) assert_equal(cipher1, cipherdef) # Failure cases assert_raise(ArgumentError){ key.private_encrypt() } assert_raise(ArgumentError){ key.private_encrypt("hi", 1, nil) } assert_raise(OpenSSL::PKey::RSAError){ key.private_encrypt(plain0, 666) } end def test_private key = OpenSSL::PKey::RSA.new(512, 3) assert(key.private?) key2 = OpenSSL::PKey::RSA.new(key.to_der) assert(key2.private?) key3 = key.public_key assert(!key3.private?) key4 = OpenSSL::PKey::RSA.new(key3.to_der) assert(!key4.private?) end end end ================================================ FILE: test/openssl/test_ssl.rb ================================================ begin require "openssl" require File.join(File.dirname(__FILE__), "utils.rb") rescue LoadError end require "rbconfig" require "socket" require "test/unit" begin loadpath = $:.dup $:.replace($: | [File.expand_path("../ruby", File.dirname(__FILE__))]) require 'envutil' ensure $:.replace(loadpath) end if defined?(OpenSSL) class OpenSSL::TestSSL < Test::Unit::TestCase RUBY = EnvUtil.rubybin SSL_SERVER = File.join(File.dirname(__FILE__), "ssl_server.rb") PORT = 20443 ITERATIONS = ($0 == __FILE__) ? 100 : 10 def setup @ca_key = OpenSSL::TestUtils::TEST_KEY_RSA2048 @svr_key = OpenSSL::TestUtils::TEST_KEY_RSA1024 @cli_key = OpenSSL::TestUtils::TEST_KEY_DSA256 @ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") @svr = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") @cli = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") now = Time.at(Time.now.to_i) ca_exts = [ ["basicConstraints","CA:TRUE",true], ["keyUsage","cRLSign,keyCertSign",true], ] ee_exts = [ ["keyUsage","keyEncipherment,digitalSignature",true], ] @ca_cert = issue_cert(@ca, @ca_key, 1, now, now+3600, ca_exts, nil, nil, OpenSSL::Digest::SHA1.new) @svr_cert = issue_cert(@svr, @svr_key, 2, now, now+1800, ee_exts, @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) @cli_cert = issue_cert(@cli, @cli_key, 3, now, now+1800, ee_exts, @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) @server = nil end def teardown end def issue_cert(*arg) OpenSSL::TestUtils.issue_cert(*arg) end def issue_crl(*arg) OpenSSL::TestUtils.issue_crl(*arg) end def readwrite_loop(ctx, ssl) while line = ssl.gets if line =~ /^STARTTLS$/ ssl.accept next end ssl.write(line) end rescue OpenSSL::SSL::SSLError rescue IOError ensure ssl.close rescue nil end def server_loop(ctx, ssls, server_proc) loop do ssl = nil begin ssl = ssls.accept rescue OpenSSL::SSL::SSLError retry end Thread.start do Thread.current.abort_on_exception = true server_proc.call(ctx, ssl) end end rescue Errno::EBADF, IOError end def start_server(port0, verify_mode, start_immediately, args = {}, &block) ctx_proc = args[:ctx_proc] server_proc = args[:server_proc] server_proc ||= method(:readwrite_loop) store = OpenSSL::X509::Store.new store.add_cert(@ca_cert) store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT ctx = OpenSSL::SSL::SSLContext.new ctx.cert_store = store #ctx.extra_chain_cert = [ ca_cert ] ctx.cert = @svr_cert ctx.key = @svr_key ctx.verify_mode = verify_mode ctx_proc.call(ctx) if ctx_proc Socket.do_not_reverse_lookup = true tcps = nil port = port0 begin tcps = TCPServer.new("127.0.0.1", port) rescue Errno::EADDRINUSE port += 1 retry end ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) ssls.start_immediately = start_immediately begin server = Thread.new do Thread.current.abort_on_exception = true server_loop(ctx, ssls, server_proc) end $stderr.printf("%s started: pid=%d port=%d\n", SSL_SERVER, pid, port) if $DEBUG block.call(server, port.to_i) ensure tcps.close if (tcps) if (server) server.join(5) if server.alive? server.kill server.join flunk("TCPServer was closed and SSLServer is still alive") unless $! end end end end def starttls(ssl) ssl.puts("STARTTLS") sleep 1 # When this line is eliminated, process on Cygwin blocks # forever at ssl.connect. But I don't know why it does. ssl.connect end def test_ctx_setup ctx = OpenSSL::SSL::SSLContext.new assert_equal(ctx.setup, true) assert_equal(ctx.setup, nil) end def test_connect_and_close start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) assert(ssl.connect) ssl.close assert(!sock.closed?) sock.close sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) ssl.sync_close = true # !! assert(ssl.connect) ssl.close assert(sock.closed?) } end def test_read_and_write start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) ssl.sync_close = true ssl.connect # syswrite and sysread ITERATIONS.times{|i| str = "x" * 100 + "\n" ssl.syswrite(str) assert_equal(str, ssl.sysread(str.size)) str = "x" * i * 100 + "\n" buf = "" ssl.syswrite(str) assert_equal(buf.object_id, ssl.sysread(str.size, buf).object_id) assert_equal(str, buf) } # read and write ITERATIONS.times{|i| str = "x" * 100 + "\n" ssl.write(str) assert_equal(str, ssl.read(str.size)) str = "x" * i * 100 + "\n" buf = "" ssl.write(str) assert_equal(buf.object_id, ssl.read(str.size, buf).object_id) assert_equal(str, buf) } ssl.close } end def test_client_auth vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT start_server(PORT, vflag, true){|server, port| assert_raises(OpenSSL::SSL::SSLError){ sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) ssl.connect } ctx = OpenSSL::SSL::SSLContext.new ctx.key = @cli_key ctx.cert = @cli_cert sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) ssl.sync_close = true ssl.connect ssl.puts("foo") assert_equal("foo\n", ssl.gets) ssl.close called = nil ctx = OpenSSL::SSL::SSLContext.new ctx.client_cert_cb = Proc.new{ |sslconn| called = true [@cli_cert, @cli_key] } sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) ssl.sync_close = true ssl.connect assert(called) ssl.puts("foo") assert_equal("foo\n", ssl.gets) ssl.close } end def test_starttls start_server(PORT, OpenSSL::SSL::VERIFY_NONE, false){|server, port| sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) ssl.sync_close = true str = "x" * 1000 + "\n" ITERATIONS.times{ ssl.puts(str) assert_equal(str, ssl.gets) } starttls(ssl) ITERATIONS.times{ ssl.puts(str) assert_equal(str, ssl.gets) } ssl.close } end def test_parallel GC.start start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| ssls = [] 10.times{ sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) ssl.connect ssl.sync_close = true ssls << ssl } str = "x" * 1000 + "\n" ITERATIONS.times{ ssls.each{|ssl| ssl.puts(str) assert_equal(str, ssl.gets) } } ssls.each{|ssl| ssl.close } } end def test_verify_result start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| sock = TCPSocket.new("127.0.0.1", port) ctx = OpenSSL::SSL::SSLContext.new ctx.set_params ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) assert_raise(OpenSSL::SSL::SSLError){ ssl.connect } assert_equal(OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, ssl.verify_result) sock = TCPSocket.new("127.0.0.1", port) ctx = OpenSSL::SSL::SSLContext.new ctx.set_params( :verify_callback => Proc.new do |preverify_ok, store_ctx| store_ctx.error = OpenSSL::X509::V_OK true end ) ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) ssl.connect assert_equal(OpenSSL::X509::V_OK, ssl.verify_result) sock = TCPSocket.new("127.0.0.1", port) ctx = OpenSSL::SSL::SSLContext.new ctx.set_params( :verify_callback => Proc.new do |preverify_ok, store_ctx| store_ctx.error = OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION false end ) ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) assert_raise(OpenSSL::SSL::SSLError){ ssl.connect } assert_equal(OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION, ssl.verify_result) } end def test_sslctx_set_params start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| sock = TCPSocket.new("127.0.0.1", port) ctx = OpenSSL::SSL::SSLContext.new ctx.set_params assert_equal(OpenSSL::SSL::VERIFY_PEER, ctx.verify_mode) assert_equal(OpenSSL::SSL::OP_ALL, ctx.options) ciphers = ctx.ciphers ciphers_versions = ciphers.collect{|_, v, _, _| v } ciphers_names = ciphers.collect{|v, _, _, _| v } assert(ciphers_names.all?{|v| /ADH/ !~ v }) assert(ciphers_versions.all?{|v| /SSLv2/ !~ v }) ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) assert_raise(OpenSSL::SSL::SSLError){ ssl.connect } assert_equal(OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, ssl.verify_result) } end def test_post_connection_check sslerr = OpenSSL::SSL::SSLError start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) ssl.connect assert_raises(sslerr){ssl.post_connection_check("localhost.localdomain")} assert_raises(sslerr){ssl.post_connection_check("127.0.0.1")} assert(ssl.post_connection_check("localhost")) assert_raises(sslerr){ssl.post_connection_check("foo.example.com")} cert = ssl.peer_cert assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain")) assert(!OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1")) assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost")) assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com")) } now = Time.now exts = [ ["keyUsage","keyEncipherment,digitalSignature",true], ["subjectAltName","DNS:localhost.localdomain",false], ["subjectAltName","IP:127.0.0.1",false], ] @svr_cert = issue_cert(@svr, @svr_key, 4, now, now+1800, exts, @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) ssl.connect assert(ssl.post_connection_check("localhost.localdomain")) assert(ssl.post_connection_check("127.0.0.1")) assert_raises(sslerr){ssl.post_connection_check("localhost")} assert_raises(sslerr){ssl.post_connection_check("foo.example.com")} cert = ssl.peer_cert assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain")) assert(OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1")) assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost")) assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com")) } now = Time.now exts = [ ["keyUsage","keyEncipherment,digitalSignature",true], ["subjectAltName","DNS:*.localdomain",false], ] @svr_cert = issue_cert(@svr, @svr_key, 5, now, now+1800, exts, @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) ssl.connect assert(ssl.post_connection_check("localhost.localdomain")) assert_raises(sslerr){ssl.post_connection_check("127.0.0.1")} assert_raises(sslerr){ssl.post_connection_check("localhost")} assert_raises(sslerr){ssl.post_connection_check("foo.example.com")} cert = ssl.peer_cert assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain")) assert(!OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1")) assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost")) assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com")) } end def test_client_session last_session = nil start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) do |server, port| 2.times do sock = TCPSocket.new("127.0.0.1", port) # Debian's openssl 0.9.8g-13 failed at assert(ssl.session_reused?), # when use default SSLContext. [ruby-dev:36167] ctx = OpenSSL::SSL::SSLContext.new("TLSv1") ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) ssl.sync_close = true ssl.session = last_session if last_session ssl.connect session = ssl.session if last_session assert(ssl.session_reused?) if session.respond_to?(:id) assert_equal(session.id, last_session.id) end assert_equal(session.to_pem, last_session.to_pem) assert_equal(session.to_der, last_session.to_der) # Older version of OpenSSL may not be consistent. Look up which versions later. assert_equal(session.to_text, last_session.to_text) else assert(!ssl.session_reused?) end last_session = session str = "x" * 100 + "\n" ssl.puts(str) assert_equal(str, ssl.gets) ssl.close end end end def test_server_session connections = 0 saved_session = nil ctx_proc = Proc.new do |ctx, ssl| # add test for session callbacks here end server_proc = Proc.new do |ctx, ssl| session = ssl.session stats = ctx.session_cache_stats case connections when 0 assert_equal(stats[:cache_num], 1) assert_equal(stats[:cache_hits], 0) assert_equal(stats[:cache_misses], 0) assert(!ssl.session_reused?) when 1 assert_equal(stats[:cache_num], 1) assert_equal(stats[:cache_hits], 1) assert_equal(stats[:cache_misses], 0) assert(ssl.session_reused?) ctx.session_remove(session) saved_session = session when 2 assert_equal(stats[:cache_num], 1) assert_equal(stats[:cache_hits], 1) assert_equal(stats[:cache_misses], 1) assert(!ssl.session_reused?) ctx.session_add(saved_session) when 3 assert_equal(stats[:cache_num], 2) assert_equal(stats[:cache_hits], 2) assert_equal(stats[:cache_misses], 1) assert(ssl.session_reused?) ctx.flush_sessions(Time.now + 5000) when 4 assert_equal(stats[:cache_num], 1) assert_equal(stats[:cache_hits], 2) assert_equal(stats[:cache_misses], 2) assert(!ssl.session_reused?) ctx.session_add(saved_session) end connections += 1 readwrite_loop(ctx, ssl) end first_session = nil start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port| 10.times do |i| sock = TCPSocket.new("127.0.0.1", port) ctx = OpenSSL::SSL::SSLContext.new if defined?(OpenSSL::SSL::OP_NO_TICKET) # disable RFC4507 support ctx.options = OpenSSL::SSL::OP_NO_TICKET end ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) ssl.sync_close = true ssl.session = first_session if first_session ssl.connect session = ssl.session if first_session case i when 1; assert(ssl.session_reused?) when 2; assert(!ssl.session_reused?) when 3; assert(ssl.session_reused?) when 4; assert(!ssl.session_reused?) when 5..10; assert(ssl.session_reused?) end end first_session ||= session str = "x" * 100 + "\n" ssl.puts(str) assert_equal(str, ssl.gets) ssl.close end end end end end ================================================ FILE: test/openssl/test_x509cert.rb ================================================ begin require "openssl" require File.join(File.dirname(__FILE__), "utils.rb") rescue LoadError end require "test/unit" if defined?(OpenSSL) class OpenSSL::TestX509Certificate < Test::Unit::TestCase def setup @rsa1024 = OpenSSL::TestUtils::TEST_KEY_RSA1024 @rsa2048 = OpenSSL::TestUtils::TEST_KEY_RSA2048 @dsa256 = OpenSSL::TestUtils::TEST_KEY_DSA256 @dsa512 = OpenSSL::TestUtils::TEST_KEY_DSA512 @ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") @ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1") @ee2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE2") end def teardown end def issue_cert(*args) OpenSSL::TestUtils.issue_cert(*args) end def test_serial [1, 2**32, 2**100].each{|s| cert = issue_cert(@ca, @rsa2048, s, Time.now, Time.now+3600, [], nil, nil, OpenSSL::Digest::SHA1.new) assert_equal(s, cert.serial) cert = OpenSSL::X509::Certificate.new(cert.to_der) assert_equal(s, cert.serial) } end def test_public_key exts = [ ["basicConstraints","CA:TRUE",true], ["subjectKeyIdentifier","hash",false], ["authorityKeyIdentifier","keyid:always",false], ] sha1 = OpenSSL::Digest::SHA1.new dss1 = OpenSSL::Digest::DSS1.new [ [@rsa1024, sha1], [@rsa2048, sha1], [@dsa256, dss1], [@dsa512, dss1], ].each{|pk, digest| cert = issue_cert(@ca, pk, 1, Time.now, Time.now+3600, exts, nil, nil, digest) assert_equal(cert.extensions[1].value, OpenSSL::TestUtils.get_subject_key_id(cert)) cert = OpenSSL::X509::Certificate.new(cert.to_der) assert_equal(cert.extensions[1].value, OpenSSL::TestUtils.get_subject_key_id(cert)) } end def test_validity now = Time.now until now && now.usec != 0 cert = issue_cert(@ca, @rsa2048, 1, now, now+3600, [], nil, nil, OpenSSL::Digest::SHA1.new) assert_not_equal(now, cert.not_before) assert_not_equal(now+3600, cert.not_after) now = Time.at(now.to_i) cert = issue_cert(@ca, @rsa2048, 1, now, now+3600, [], nil, nil, OpenSSL::Digest::SHA1.new) assert_equal(now.getutc, cert.not_before) assert_equal((now+3600).getutc, cert.not_after) now = Time.at(0) cert = issue_cert(@ca, @rsa2048, 1, now, now, [], nil, nil, OpenSSL::Digest::SHA1.new) assert_equal(now.getutc, cert.not_before) assert_equal(now.getutc, cert.not_after) now = Time.at(0x7fffffff) cert = issue_cert(@ca, @rsa2048, 1, now, now, [], nil, nil, OpenSSL::Digest::SHA1.new) assert_equal(now.getutc, cert.not_before) assert_equal(now.getutc, cert.not_after) end def test_extension ca_exts = [ ["basicConstraints","CA:TRUE",true], ["keyUsage","keyCertSign, cRLSign",true], ["subjectKeyIdentifier","hash",false], ["authorityKeyIdentifier","keyid:always",false], ] ca_cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, ca_exts, nil, nil, OpenSSL::Digest::SHA1.new) ca_cert.extensions.each_with_index{|ext, i| assert_equal(ca_exts[i].first, ext.oid) assert_equal(ca_exts[i].last, ext.critical?) } ee1_exts = [ ["keyUsage","Non Repudiation, Digital Signature, Key Encipherment",true], ["subjectKeyIdentifier","hash",false], ["authorityKeyIdentifier","keyid:always",false], ["extendedKeyUsage","clientAuth, emailProtection, codeSigning",false], ["subjectAltName","email:ee1@ruby-lang.org",false], ] ee1_cert = issue_cert(@ee1, @rsa1024, 2, Time.now, Time.now+1800, ee1_exts, ca_cert, @rsa2048, OpenSSL::Digest::SHA1.new) assert_equal(ca_cert.subject.to_der, ee1_cert.issuer.to_der) ee1_cert.extensions.each_with_index{|ext, i| assert_equal(ee1_exts[i].first, ext.oid) assert_equal(ee1_exts[i].last, ext.critical?) } ee2_exts = [ ["keyUsage","Non Repudiation, Digital Signature, Key Encipherment",true], ["subjectKeyIdentifier","hash",false], ["authorityKeyIdentifier","issuer:always",false], ["extendedKeyUsage","clientAuth, emailProtection, codeSigning",false], ["subjectAltName","email:ee2@ruby-lang.org",false], ] ee2_cert = issue_cert(@ee2, @rsa1024, 3, Time.now, Time.now+1800, ee2_exts, ca_cert, @rsa2048, OpenSSL::Digest::MD5.new) assert_equal(ca_cert.subject.to_der, ee2_cert.issuer.to_der) ee2_cert.extensions.each_with_index{|ext, i| assert_equal(ee2_exts[i].first, ext.oid) assert_equal(ee2_exts[i].last, ext.critical?) } end def test_sign_and_verify cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], nil, nil, OpenSSL::Digest::SHA1.new) assert_equal(false, cert.verify(@rsa1024)) assert_equal(true, cert.verify(@rsa2048)) assert_equal(false, certificate_error_returns_false { cert.verify(@dsa256) }) assert_equal(false, certificate_error_returns_false { cert.verify(@dsa512) }) cert.serial = 2 assert_equal(false, cert.verify(@rsa2048)) cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], nil, nil, OpenSSL::Digest::MD5.new) assert_equal(false, cert.verify(@rsa1024)) assert_equal(true, cert.verify(@rsa2048)) assert_equal(false, certificate_error_returns_false { cert.verify(@dsa256) }) assert_equal(false, certificate_error_returns_false { cert.verify(@dsa512) }) cert.subject = @ee1 assert_equal(false, cert.verify(@rsa2048)) cert = issue_cert(@ca, @dsa512, 1, Time.now, Time.now+3600, [], nil, nil, OpenSSL::Digest::DSS1.new) assert_equal(false, certificate_error_returns_false { cert.verify(@rsa1024) }) assert_equal(false, certificate_error_returns_false { cert.verify(@rsa2048) }) assert_equal(false, cert.verify(@dsa256)) assert_equal(true, cert.verify(@dsa512)) cert.not_after = Time.now assert_equal(false, cert.verify(@dsa512)) assert_raises(OpenSSL::X509::CertificateError){ cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], nil, nil, OpenSSL::Digest::DSS1.new) } assert_raises(OpenSSL::X509::CertificateError){ cert = issue_cert(@ca, @dsa512, 1, Time.now, Time.now+3600, [], nil, nil, OpenSSL::Digest::MD5.new) } assert_raises(OpenSSL::X509::CertificateError){ cert = issue_cert(@ca, @dsa512, 1, Time.now, Time.now+3600, [], nil, nil, OpenSSL::Digest::SHA1.new) } end private def certificate_error_returns_false yield rescue OpenSSL::X509::CertificateError false end end end ================================================ FILE: test/openssl/test_x509crl.rb ================================================ begin require "openssl" require File.join(File.dirname(__FILE__), "utils.rb") rescue LoadError end require "test/unit" if defined?(OpenSSL) class OpenSSL::TestX509CRL < Test::Unit::TestCase def setup @rsa1024 = OpenSSL::TestUtils::TEST_KEY_RSA1024 @rsa2048 = OpenSSL::TestUtils::TEST_KEY_RSA2048 @dsa256 = OpenSSL::TestUtils::TEST_KEY_DSA256 @dsa512 = OpenSSL::TestUtils::TEST_KEY_DSA512 @ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") @ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1") @ee2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE2") end def teardown end def issue_crl(*args) OpenSSL::TestUtils.issue_crl(*args) end def issue_cert(*args) OpenSSL::TestUtils.issue_cert(*args) end def test_basic now = Time.at(Time.now.to_i) cert = issue_cert(@ca, @rsa2048, 1, now, now+3600, [], nil, nil, OpenSSL::Digest::SHA1.new) crl = issue_crl([], 1, now, now+1600, [], cert, @rsa2048, OpenSSL::Digest::SHA1.new) assert_equal(1, crl.version) assert_equal(cert.issuer.to_der, crl.issuer.to_der) assert_equal(now, crl.last_update) assert_equal(now+1600, crl.next_update) crl = OpenSSL::X509::CRL.new(crl.to_der) assert_equal(1, crl.version) assert_equal(cert.issuer.to_der, crl.issuer.to_der) assert_equal(now, crl.last_update) assert_equal(now+1600, crl.next_update) end def test_revoked # CRLReason ::= ENUMERATED { # unspecified (0), # keyCompromise (1), # cACompromise (2), # affiliationChanged (3), # superseded (4), # cessationOfOperation (5), # certificateHold (6), # removeFromCRL (8), # privilegeWithdrawn (9), # aACompromise (10) } now = Time.at(Time.now.to_i) revoke_info = [ [1, Time.at(0), 1], [2, Time.at(0x7fffffff), 2], [3, now, 3], [4, now, 4], [5, now, 5], ] cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], nil, nil, OpenSSL::Digest::SHA1.new) crl = issue_crl(revoke_info, 1, Time.now, Time.now+1600, [], cert, @rsa2048, OpenSSL::Digest::SHA1.new) revoked = crl.revoked assert_equal(5, revoked.size) assert_equal(1, revoked[0].serial) assert_equal(2, revoked[1].serial) assert_equal(3, revoked[2].serial) assert_equal(4, revoked[3].serial) assert_equal(5, revoked[4].serial) assert_equal(Time.at(0), revoked[0].time) assert_equal(Time.at(0x7fffffff), revoked[1].time) assert_equal(now, revoked[2].time) assert_equal(now, revoked[3].time) assert_equal(now, revoked[4].time) assert_equal("CRLReason", revoked[0].extensions[0].oid) assert_equal("CRLReason", revoked[1].extensions[0].oid) assert_equal("CRLReason", revoked[2].extensions[0].oid) assert_equal("CRLReason", revoked[3].extensions[0].oid) assert_equal("CRLReason", revoked[4].extensions[0].oid) assert_equal("Key Compromise", revoked[0].extensions[0].value) assert_equal("CA Compromise", revoked[1].extensions[0].value) assert_equal("Affiliation Changed", revoked[2].extensions[0].value) assert_equal("Superseded", revoked[3].extensions[0].value) assert_equal("Cessation Of Operation", revoked[4].extensions[0].value) assert_equal(false, revoked[0].extensions[0].critical?) assert_equal(false, revoked[1].extensions[0].critical?) assert_equal(false, revoked[2].extensions[0].critical?) assert_equal(false, revoked[3].extensions[0].critical?) assert_equal(false, revoked[4].extensions[0].critical?) crl = OpenSSL::X509::CRL.new(crl.to_der) assert_equal("Key Compromise", revoked[0].extensions[0].value) assert_equal("CA Compromise", revoked[1].extensions[0].value) assert_equal("Affiliation Changed", revoked[2].extensions[0].value) assert_equal("Superseded", revoked[3].extensions[0].value) assert_equal("Cessation Of Operation", revoked[4].extensions[0].value) revoke_info = (1..1000).collect{|i| [i, now, 0] } crl = issue_crl(revoke_info, 1, Time.now, Time.now+1600, [], cert, @rsa2048, OpenSSL::Digest::SHA1.new) revoked = crl.revoked assert_equal(1000, revoked.size) assert_equal(1, revoked[0].serial) assert_equal(1000, revoked[999].serial) end def test_extension cert_exts = [ ["basicConstraints", "CA:TRUE", true], ["subjectKeyIdentifier", "hash", false], ["authorityKeyIdentifier", "keyid:always", false], ["subjectAltName", "email:xyzzy@ruby-lang.org", false], ["keyUsage", "cRLSign, keyCertSign", true], ] crl_exts = [ ["authorityKeyIdentifier", "keyid:always", false], ["issuerAltName", "issuer:copy", false], ] cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, cert_exts, nil, nil, OpenSSL::Digest::SHA1.new) crl = issue_crl([], 1, Time.now, Time.now+1600, crl_exts, cert, @rsa2048, OpenSSL::Digest::SHA1.new) exts = crl.extensions assert_equal(3, exts.size) assert_equal("1", exts[0].value) assert_equal("crlNumber", exts[0].oid) assert_equal(false, exts[0].critical?) assert_equal("authorityKeyIdentifier", exts[1].oid) keyid = OpenSSL::TestUtils.get_subject_key_id(cert) assert_match(/^keyid:#{keyid}/, exts[1].value) assert_equal(false, exts[1].critical?) assert_equal("issuerAltName", exts[2].oid) assert_equal("email:xyzzy@ruby-lang.org", exts[2].value) assert_equal(false, exts[2].critical?) crl = OpenSSL::X509::CRL.new(crl.to_der) exts = crl.extensions assert_equal(3, exts.size) assert_equal("1", exts[0].value) assert_equal("crlNumber", exts[0].oid) assert_equal(false, exts[0].critical?) assert_equal("authorityKeyIdentifier", exts[1].oid) keyid = OpenSSL::TestUtils.get_subject_key_id(cert) assert_match(/^keyid:#{keyid}/, exts[1].value) assert_equal(false, exts[1].critical?) assert_equal("issuerAltName", exts[2].oid) assert_equal("email:xyzzy@ruby-lang.org", exts[2].value) assert_equal(false, exts[2].critical?) end def test_crlnumber cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], nil, nil, OpenSSL::Digest::SHA1.new) crl = issue_crl([], 1, Time.now, Time.now+1600, [], cert, @rsa2048, OpenSSL::Digest::SHA1.new) assert_match(1.to_s, crl.extensions[0].value) assert_match(/X509v3 CRL Number:\s+#{1}/m, crl.to_text) crl = issue_crl([], 2**32, Time.now, Time.now+1600, [], cert, @rsa2048, OpenSSL::Digest::SHA1.new) assert_match((2**32).to_s, crl.extensions[0].value) assert_match(/X509v3 CRL Number:\s+#{2**32}/m, crl.to_text) crl = issue_crl([], 2**100, Time.now, Time.now+1600, [], cert, @rsa2048, OpenSSL::Digest::SHA1.new) assert_match(/X509v3 CRL Number:\s+#{2**100}/m, crl.to_text) assert_match((2**100).to_s, crl.extensions[0].value) end def test_sign_and_verify cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], nil, nil, OpenSSL::Digest::SHA1.new) crl = issue_crl([], 1, Time.now, Time.now+1600, [], cert, @rsa2048, OpenSSL::Digest::SHA1.new) assert_equal(false, crl.verify(@rsa1024)) assert_equal(true, crl.verify(@rsa2048)) assert_equal(false, crl_error_returns_false { crl.verify(@dsa256) }) assert_equal(false, crl_error_returns_false { crl.verify(@dsa512) }) crl.version = 0 assert_equal(false, crl.verify(@rsa2048)) cert = issue_cert(@ca, @dsa512, 1, Time.now, Time.now+3600, [], nil, nil, OpenSSL::Digest::DSS1.new) crl = issue_crl([], 1, Time.now, Time.now+1600, [], cert, @dsa512, OpenSSL::Digest::DSS1.new) assert_equal(false, crl_error_returns_false { crl.verify(@rsa1024) }) assert_equal(false, crl_error_returns_false { crl.verify(@rsa2048) }) assert_equal(false, crl.verify(@dsa256)) assert_equal(true, crl.verify(@dsa512)) crl.version = 0 assert_equal(false, crl.verify(@dsa512)) end private def crl_error_returns_false yield rescue OpenSSL::X509::CRLError false end end end ================================================ FILE: test/openssl/test_x509ext.rb ================================================ begin require "openssl" require File.join(File.dirname(__FILE__), "utils.rb") rescue LoadError end require "test/unit" if defined?(OpenSSL) class OpenSSL::TestX509Extension < Test::Unit::TestCase def setup @basic_constraints_value = OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::Boolean(true), # CA OpenSSL::ASN1::Integer(2) # pathlen ]) @basic_constraints = OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::ObjectId("basicConstraints"), OpenSSL::ASN1::Boolean(true), OpenSSL::ASN1::OctetString(@basic_constraints_value.to_der), ]) end def teardown end def test_new ext = OpenSSL::X509::Extension.new(@basic_constraints.to_der) assert_equal("basicConstraints", ext.oid) assert_equal(true, ext.critical?) assert_equal("CA:TRUE, pathlen:2", ext.value) ext = OpenSSL::X509::Extension.new("2.5.29.19", @basic_constraints_value.to_der, true) assert_equal(@basic_constraints.to_der, ext.to_der) end def test_create_by_factory ef = OpenSSL::X509::ExtensionFactory.new bc = ef.create_extension("basicConstraints", "critical, CA:TRUE, pathlen:2") assert_equal(@basic_constraints.to_der, bc.to_der) bc = ef.create_extension("basicConstraints", "CA:TRUE, pathlen:2", true) assert_equal(@basic_constraints.to_der, bc.to_der) begin ef.config = OpenSSL::Config.parse(<<-_end_of_cnf_) [crlDistPts] URI.1 = http://www.example.com/crl URI.2 = ldap://ldap.example.com/cn=ca?certificateRevocationList;binary _end_of_cnf_ rescue NotImplementedError return end cdp = ef.create_extension("crlDistributionPoints", "@crlDistPts") assert_equal(false, cdp.critical?) assert_equal("crlDistributionPoints", cdp.oid) assert_match(%{URI:http://www\.example\.com/crl}, cdp.value) assert_match( %r{URI:ldap://ldap\.example\.com/cn=ca\?certificateRevocationList;binary}, cdp.value) cdp = ef.create_extension("crlDistributionPoints", "critical, @crlDistPts") assert_equal(true, cdp.critical?) assert_equal("crlDistributionPoints", cdp.oid) assert_match(%{URI:http://www.example.com/crl}, cdp.value) assert_match( %r{URI:ldap://ldap.example.com/cn=ca\?certificateRevocationList;binary}, cdp.value) end end end ================================================ FILE: test/openssl/test_x509name.rb ================================================ begin require "openssl" rescue LoadError end require "test/unit" if defined?(OpenSSL) class OpenSSL::TestX509Name < Test::Unit::TestCase OpenSSL::ASN1::ObjectId.register( "1.2.840.113549.1.9.1", "emailAddress", "emailAddress") OpenSSL::ASN1::ObjectId.register( "2.5.4.5", "serialNumber", "serialNumber") def setup @obj_type_tmpl = Hash.new(OpenSSL::ASN1::PRINTABLESTRING) @obj_type_tmpl.update(OpenSSL::X509::Name::OBJECT_TYPE_TEMPLATE) end def teardown end def test_s_new dn = [ ["C", "JP"], ["O", "example"], ["CN", "www.example.jp"] ] name = OpenSSL::X509::Name.new(dn) ary = name.to_a assert_equal("/C=JP/O=example/CN=www.example.jp", name.to_s) assert_equal("C", ary[0][0]) assert_equal("O", ary[1][0]) assert_equal("CN", ary[2][0]) assert_equal("JP", ary[0][1]) assert_equal("example", ary[1][1]) assert_equal("www.example.jp", ary[2][1]) assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2]) assert_equal(OpenSSL::ASN1::UTF8STRING, ary[1][2]) assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) dn = [ ["countryName", "JP"], ["organizationName", "example"], ["commonName", "www.example.jp"] ] name = OpenSSL::X509::Name.new(dn) ary = name.to_a assert_equal("/C=JP/O=example/CN=www.example.jp", name.to_s) assert_equal("C", ary[0][0]) assert_equal("O", ary[1][0]) assert_equal("CN", ary[2][0]) assert_equal("JP", ary[0][1]) assert_equal("example", ary[1][1]) assert_equal("www.example.jp", ary[2][1]) assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2]) assert_equal(OpenSSL::ASN1::UTF8STRING, ary[1][2]) assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) name = OpenSSL::X509::Name.new(dn, @obj_type_tmpl) ary = name.to_a assert_equal("/C=JP/O=example/CN=www.example.jp", name.to_s) assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2]) assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[1][2]) assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[2][2]) dn = [ ["countryName", "JP", OpenSSL::ASN1::PRINTABLESTRING], ["organizationName", "example", OpenSSL::ASN1::PRINTABLESTRING], ["commonName", "www.example.jp", OpenSSL::ASN1::PRINTABLESTRING] ] name = OpenSSL::X509::Name.new(dn) ary = name.to_a assert_equal("/C=JP/O=example/CN=www.example.jp", name.to_s) assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2]) assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[1][2]) assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[2][2]) dn = [ ["DC", "org"], ["DC", "ruby-lang"], ["CN", "GOTOU Yuuzou"], ["emailAddress", "gotoyuzo@ruby-lang.org"], ["serialNumber", "123"], ] name = OpenSSL::X509::Name.new(dn) ary = name.to_a assert_equal("/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou/emailAddress=gotoyuzo@ruby-lang.org/serialNumber=123", name.to_s) assert_equal("DC", ary[0][0]) assert_equal("DC", ary[1][0]) assert_equal("CN", ary[2][0]) assert_equal("emailAddress", ary[3][0]) assert_equal("serialNumber", ary[4][0]) assert_equal("org", ary[0][1]) assert_equal("ruby-lang", ary[1][1]) assert_equal("GOTOU Yuuzou", ary[2][1]) assert_equal("gotoyuzo@ruby-lang.org", ary[3][1]) assert_equal("123", ary[4][1]) assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) assert_equal(OpenSSL::ASN1::IA5STRING, ary[3][2]) assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[4][2]) name_from_der = OpenSSL::X509::Name.new(name.to_der) assert_equal(name_from_der.to_s, name.to_s) assert_equal(name_from_der.to_a, name.to_a) assert_equal(name_from_der.to_der, name.to_der) end def test_s_parse dn = "/DC=org/DC=ruby-lang/CN=www.ruby-lang.org" name = OpenSSL::X509::Name.parse(dn) assert_equal(dn, name.to_s) ary = name.to_a assert_equal("DC", ary[0][0]) assert_equal("DC", ary[1][0]) assert_equal("CN", ary[2][0]) assert_equal("org", ary[0][1]) assert_equal("ruby-lang", ary[1][1]) assert_equal("www.ruby-lang.org", ary[2][1]) assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) dn2 = "DC=org, DC=ruby-lang, CN=www.ruby-lang.org" name = OpenSSL::X509::Name.parse(dn) ary = name.to_a assert_equal(dn, name.to_s) assert_equal("org", ary[0][1]) assert_equal("ruby-lang", ary[1][1]) assert_equal("www.ruby-lang.org", ary[2][1]) name = OpenSSL::X509::Name.parse(dn, @obj_type_tmpl) ary = name.to_a assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[2][2]) end def test_s_parse_rfc2253 scanner = OpenSSL::X509::Name::RFC2253DN.method(:scan) assert_equal([["C", "JP"]], scanner.call("C=JP")) assert_equal([ ["DC", "org"], ["DC", "ruby-lang"], ["CN", "GOTOU Yuuzou"], ["emailAddress", "gotoyuzo@ruby-lang.org"], ], scanner.call( "emailAddress=gotoyuzo@ruby-lang.org,CN=GOTOU Yuuzou,"+ "DC=ruby-lang,DC=org") ) u8 = OpenSSL::ASN1::UTF8STRING assert_equal([ ["DC", "org"], ["DC", "ruby-lang"], ["O", ",=+<>#;"], ["O", ",=+<>#;"], ["OU", ""], ["OU", ""], ["L", "aaa=\"bbb, ccc\""], ["L", "aaa=\"bbb, ccc\""], ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265"], ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265"], ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265"], ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265", u8], ["2.5.4.3", "GOTOU, Yuuzou"], ["2.5.4.3", "GOTOU, Yuuzou"], ["2.5.4.3", "GOTOU, Yuuzou"], ["2.5.4.3", "GOTOU, Yuuzou"], ["CN", "GOTOU \"gotoyuzo\" Yuuzou"], ["CN", "GOTOU \"gotoyuzo\" Yuuzou"], ["1.2.840.113549.1.9.1", "gotoyuzo@ruby-lang.org"], ["emailAddress", "gotoyuzo@ruby-lang.org"], ], scanner.call( "emailAddress=gotoyuzo@ruby-lang.org," + "1.2.840.113549.1.9.1=gotoyuzo@ruby-lang.org," + 'CN=GOTOU \"gotoyuzo\" Yuuzou,' + 'CN="GOTOU \"gotoyuzo\" Yuuzou",' + '2.5.4.3=GOTOU\,\20Yuuzou,' + '2.5.4.3=GOTOU\, Yuuzou,' + '2.5.4.3="GOTOU, Yuuzou",' + '2.5.4.3="GOTOU\, Yuuzou",' + "CN=#0C0CE5BE8CE897A4E8A395E894B5," + 'CN=\E5\BE\8C\E8\97\A4\E8\A3\95\E8\94\B5,' + "CN=\"\xE5\xBE\x8C\xE8\x97\xA4\xE8\xA3\x95\xE8\x94\xB5\"," + "CN=\xE5\xBE\x8C\xE8\x97\xA4\xE8\xA3\x95\xE8\x94\xB5," + 'L=aaa\=\"bbb\, ccc\",' + 'L="aaa=\"bbb, ccc\"",' + 'OU=,' + 'OU="",' + 'O=\,\=\+\<\>\#\;,' + 'O=",=+<>#;",' + "DC=ruby-lang," + "DC=org") ) [ "DC=org+DC=jp", "DC=org,DC=ruby-lang+DC=rubyist,DC=www" ].each{|dn| ex = scanner.call(dn) rescue $! dn_r = Regexp.escape(dn) assert_match(/^multi-valued RDN is not supported: #{dn_r}/, ex.message) } [ ["DC=org,DC=exapmle,CN", "CN"], ["DC=org,DC=example,", ""], ["DC=org,DC=exapmle,CN=www.example.org;", "CN=www.example.org;"], ["DC=org,DC=exapmle,CN=#www.example.org", "CN=#www.example.org"], ["DC=org,DC=exapmle,CN=#777777.example.org", "CN=#777777.example.org"], ["DC=org,DC=exapmle,CN=\"www.example\".org", "CN=\"www.example\".org"], ["DC=org,DC=exapmle,CN=www.\"example.org\"", "CN=www.\"example.org\""], ["DC=org,DC=exapmle,CN=www.\"example\".org", "CN=www.\"example\".org"], ].each{|dn, msg| ex = scanner.call(dn) rescue $! assert_match(/^malformed RDN: .*=>#{Regexp.escape(msg)}/, ex.message) } dn = "CN=www.ruby-lang.org,DC=ruby-lang,DC=org" name = OpenSSL::X509::Name.parse_rfc2253(dn) assert_equal(dn, name.to_s(OpenSSL::X509::Name::RFC2253)) ary = name.to_a assert_equal("DC", ary[0][0]) assert_equal("DC", ary[1][0]) assert_equal("CN", ary[2][0]) assert_equal("org", ary[0][1]) assert_equal("ruby-lang", ary[1][1]) assert_equal("www.ruby-lang.org", ary[2][1]) assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) end def test_add_entry dn = [ ["DC", "org"], ["DC", "ruby-lang"], ["CN", "GOTOU Yuuzou"], ["emailAddress", "gotoyuzo@ruby-lang.org"], ["serialNumber", "123"], ] name = OpenSSL::X509::Name.new dn.each{|attr| name.add_entry(*attr) } ary = name.to_a assert_equal("/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou/emailAddress=gotoyuzo@ruby-lang.org/serialNumber=123", name.to_s) assert_equal("DC", ary[0][0]) assert_equal("DC", ary[1][0]) assert_equal("CN", ary[2][0]) assert_equal("emailAddress", ary[3][0]) assert_equal("serialNumber", ary[4][0]) assert_equal("org", ary[0][1]) assert_equal("ruby-lang", ary[1][1]) assert_equal("GOTOU Yuuzou", ary[2][1]) assert_equal("gotoyuzo@ruby-lang.org", ary[3][1]) assert_equal("123", ary[4][1]) assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) assert_equal(OpenSSL::ASN1::IA5STRING, ary[3][2]) assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[4][2]) end end end ================================================ FILE: test/openssl/test_x509req.rb ================================================ begin require "openssl" require File.join(File.dirname(__FILE__), "utils.rb") rescue LoadError end require "test/unit" if defined?(OpenSSL) class OpenSSL::TestX509Request < Test::Unit::TestCase def setup @rsa1024 = OpenSSL::TestUtils::TEST_KEY_RSA1024 @rsa2048 = OpenSSL::TestUtils::TEST_KEY_RSA2048 @dsa256 = OpenSSL::TestUtils::TEST_KEY_DSA256 @dsa512 = OpenSSL::TestUtils::TEST_KEY_DSA512 @dn = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou") end def issue_csr(ver, dn, key, digest) req = OpenSSL::X509::Request.new req.version = ver req.subject = dn req.public_key = key.public_key req.sign(key, digest) req end def test_public_key req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) assert_equal(@rsa1024.public_key.to_der, req.public_key.to_der) req = OpenSSL::X509::Request.new(req.to_der) assert_equal(@rsa1024.public_key.to_der, req.public_key.to_der) req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest::DSS1.new) assert_equal(@dsa512.public_key.to_der, req.public_key.to_der) req = OpenSSL::X509::Request.new(req.to_der) assert_equal(@dsa512.public_key.to_der, req.public_key.to_der) end def test_version req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) assert_equal(0, req.version) req = OpenSSL::X509::Request.new(req.to_der) assert_equal(0, req.version) req = issue_csr(1, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) assert_equal(1, req.version) req = OpenSSL::X509::Request.new(req.to_der) assert_equal(1, req.version) end def test_subject req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) assert_equal(@dn.to_der, req.subject.to_der) req = OpenSSL::X509::Request.new(req.to_der) assert_equal(@dn.to_der, req.subject.to_der) end def create_ext_req(exts) ef = OpenSSL::X509::ExtensionFactory.new exts = exts.collect{|e| ef.create_extension(*e) } return OpenSSL::ASN1::Set([OpenSSL::ASN1::Sequence(exts)]) end def get_ext_req(ext_req_value) set = OpenSSL::ASN1.decode(ext_req_value) seq = set.value[0] seq.value.collect{|asn1ext| OpenSSL::X509::Extension.new(asn1ext).to_a } end def test_attr exts = [ ["keyUsage", "Digital Signature, Key Encipherment", true], ["subjectAltName", "email:gotoyuzo@ruby-lang.org", false], ] attrval = create_ext_req(exts) attrs = [ OpenSSL::X509::Attribute.new("extReq", attrval), OpenSSL::X509::Attribute.new("msExtReq", attrval), ] req0 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) attrs.each{|attr| req0.add_attribute(attr) } req1 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) req1.attributes = attrs assert_equal(req0.to_der, req1.to_der) attrs = req0.attributes assert_equal(2, attrs.size) assert_equal("extReq", attrs[0].oid) assert_equal("msExtReq", attrs[1].oid) assert_equal(exts, get_ext_req(attrs[0].value)) assert_equal(exts, get_ext_req(attrs[1].value)) req = OpenSSL::X509::Request.new(req0.to_der) attrs = req.attributes assert_equal(2, attrs.size) assert_equal("extReq", attrs[0].oid) assert_equal("msExtReq", attrs[1].oid) assert_equal(exts, get_ext_req(attrs[0].value)) assert_equal(exts, get_ext_req(attrs[1].value)) end def test_sign_and_verify req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) assert_equal(true, req.verify(@rsa1024)) assert_equal(false, req.verify(@rsa2048)) assert_equal(false, request_error_returns_false { req.verify(@dsa256) }) assert_equal(false, request_error_returns_false { req.verify(@dsa512) }) req.version = 1 assert_equal(false, req.verify(@rsa1024)) req = issue_csr(0, @dn, @rsa2048, OpenSSL::Digest::MD5.new) assert_equal(false, req.verify(@rsa1024)) assert_equal(true, req.verify(@rsa2048)) assert_equal(false, request_error_returns_false { req.verify(@dsa256) }) assert_equal(false, request_error_returns_false { req.verify(@dsa512) }) req.subject = OpenSSL::X509::Name.parse("/C=JP/CN=FooBar") assert_equal(false, req.verify(@rsa2048)) req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest::DSS1.new) assert_equal(false, request_error_returns_false { req.verify(@rsa1024) }) assert_equal(false, request_error_returns_false { req.verify(@rsa2048) }) assert_equal(false, req.verify(@dsa256)) assert_equal(true, req.verify(@dsa512)) req.public_key = @rsa1024.public_key assert_equal(false, req.verify(@dsa512)) assert_raise(OpenSSL::X509::RequestError){ issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::DSS1.new) } assert_raise(OpenSSL::X509::RequestError){ issue_csr(0, @dn, @dsa512, OpenSSL::Digest::SHA1.new) } assert_raise(OpenSSL::X509::RequestError){ issue_csr(0, @dn, @dsa512, OpenSSL::Digest::MD5.new) } end private def request_error_returns_false yield rescue OpenSSL::X509::RequestError false end end end ================================================ FILE: test/openssl/test_x509store.rb ================================================ begin require "openssl" require File.join(File.dirname(__FILE__), "utils.rb") rescue LoadError end require "test/unit" if defined?(OpenSSL) class OpenSSL::TestX509Store < Test::Unit::TestCase def setup @rsa1024 = OpenSSL::TestUtils::TEST_KEY_RSA1024 @rsa2048 = OpenSSL::TestUtils::TEST_KEY_RSA2048 @dsa256 = OpenSSL::TestUtils::TEST_KEY_DSA256 @dsa512 = OpenSSL::TestUtils::TEST_KEY_DSA512 @ca1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA1") @ca2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA2") @ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1") @ee2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE2") end def teardown end def issue_cert(*args) OpenSSL::TestUtils.issue_cert(*args) end def issue_crl(*args) OpenSSL::TestUtils.issue_crl(*args) end def test_verify now = Time.at(Time.now.to_i) ca_exts = [ ["basicConstraints","CA:TRUE",true], ["keyUsage","cRLSign,keyCertSign",true], ] ee_exts = [ ["keyUsage","keyEncipherment,digitalSignature",true], ] ca1_cert = issue_cert(@ca1, @rsa2048, 1, now, now+3600, ca_exts, nil, nil, OpenSSL::Digest::SHA1.new) ca2_cert = issue_cert(@ca2, @rsa1024, 2, now, now+1800, ca_exts, ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) ee1_cert = issue_cert(@ee1, @dsa256, 10, now, now+1800, ee_exts, ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) ee2_cert = issue_cert(@ee2, @dsa512, 20, now, now+1800, ee_exts, ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) ee3_cert = issue_cert(@ee2, @dsa512, 30, now-100, now-1, ee_exts, ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) ee4_cert = issue_cert(@ee2, @dsa512, 40, now+1000, now+2000, ee_exts, ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) revoke_info = [] crl1 = issue_crl(revoke_info, 1, now, now+1800, [], ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) revoke_info = [ [2, now, 1], ] crl1_2 = issue_crl(revoke_info, 2, now, now+1800, [], ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) revoke_info = [ [20, now, 1], ] crl2 = issue_crl(revoke_info, 1, now, now+1800, [], ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) revoke_info = [] crl2_2 = issue_crl(revoke_info, 2, now-100, now-1, [], ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) assert(true, ca1_cert.verify(ca1_cert.public_key)) # self signed assert(true, ca2_cert.verify(ca1_cert.public_key)) # issued by ca1 assert(true, ee1_cert.verify(ca2_cert.public_key)) # issued by ca2 assert(true, ee2_cert.verify(ca2_cert.public_key)) # issued by ca2 assert(true, ee3_cert.verify(ca2_cert.public_key)) # issued by ca2 assert(true, crl1.verify(ca1_cert.public_key)) # issued by ca1 assert(true, crl1_2.verify(ca1_cert.public_key)) # issued by ca1 assert(true, crl2.verify(ca2_cert.public_key)) # issued by ca2 assert(true, crl2_2.verify(ca2_cert.public_key)) # issued by ca2 store = OpenSSL::X509::Store.new assert_equal(false, store.verify(ca1_cert)) assert_not_equal(OpenSSL::X509::V_OK, store.error) assert_equal(false, store.verify(ca2_cert)) assert_not_equal(OpenSSL::X509::V_OK, store.error) store.add_cert(ca1_cert) assert_equal(true, store.verify(ca2_cert)) assert_equal(OpenSSL::X509::V_OK, store.error) assert_equal("ok", store.error_string) chain = store.chain assert_equal(2, chain.size) assert_equal(@ca2.to_der, chain[0].subject.to_der) assert_equal(@ca1.to_der, chain[1].subject.to_der) store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT assert_equal(false, store.verify(ca2_cert)) assert_not_equal(OpenSSL::X509::V_OK, store.error) store.purpose = OpenSSL::X509::PURPOSE_CRL_SIGN assert_equal(true, store.verify(ca2_cert)) assert_equal(OpenSSL::X509::V_OK, store.error) store.add_cert(ca2_cert) store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT assert_equal(true, store.verify(ee1_cert)) assert_equal(true, store.verify(ee2_cert)) assert_equal(OpenSSL::X509::V_OK, store.error) assert_equal("ok", store.error_string) chain = store.chain assert_equal(3, chain.size) assert_equal(@ee2.to_der, chain[0].subject.to_der) assert_equal(@ca2.to_der, chain[1].subject.to_der) assert_equal(@ca1.to_der, chain[2].subject.to_der) assert_equal(false, store.verify(ee3_cert)) assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) assert_match(/expire/i, store.error_string) assert_equal(false, store.verify(ee4_cert)) assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error) assert_match(/not yet valid/i, store.error_string) store = OpenSSL::X509::Store.new store.add_cert(ca1_cert) store.add_cert(ca2_cert) store.time = now + 1500 assert_equal(true, store.verify(ca1_cert)) assert_equal(true, store.verify(ca2_cert)) assert_equal(true, store.verify(ee4_cert)) store.time = now + 1900 assert_equal(true, store.verify(ca1_cert)) assert_equal(false, store.verify(ca2_cert)) assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) assert_equal(false, store.verify(ee4_cert)) assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) store.time = now + 4000 assert_equal(false, store.verify(ee1_cert)) assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) assert_equal(false, store.verify(ee4_cert)) assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) # the underlying X509 struct caches the result of the last # verification for signature and not-before. so the following code # rebuilds new objects to avoid site effect. store.time = Time.now - 4000 assert_equal(false, store.verify(OpenSSL::X509::Certificate.new(ca2_cert))) assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error) assert_equal(false, store.verify(OpenSSL::X509::Certificate.new(ee1_cert))) assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error) return unless defined?(OpenSSL::X509::V_FLAG_CRL_CHECK) store = OpenSSL::X509::Store.new store.purpose = OpenSSL::X509::PURPOSE_ANY store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK store.add_cert(ca1_cert) store.add_crl(crl1) # revoke no cert store.add_crl(crl2) # revoke ee2_cert assert_equal(true, store.verify(ca1_cert)) assert_equal(true, store.verify(ca2_cert)) assert_equal(true, store.verify(ee1_cert, [ca2_cert])) assert_equal(false, store.verify(ee2_cert, [ca2_cert])) store = OpenSSL::X509::Store.new store.purpose = OpenSSL::X509::PURPOSE_ANY store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK store.add_cert(ca1_cert) store.add_crl(crl1_2) # revoke ca2_cert store.add_crl(crl2) # revoke ee2_cert assert_equal(true, store.verify(ca1_cert)) assert_equal(false, store.verify(ca2_cert)) assert_equal(true, store.verify(ee1_cert, [ca2_cert]), "This test is expected to be success with OpenSSL 0.9.7c or later.") assert_equal(false, store.verify(ee2_cert, [ca2_cert])) store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL assert_equal(true, store.verify(ca1_cert)) assert_equal(false, store.verify(ca2_cert)) assert_equal(false, store.verify(ee1_cert, [ca2_cert])) assert_equal(false, store.verify(ee2_cert, [ca2_cert])) store = OpenSSL::X509::Store.new store.purpose = OpenSSL::X509::PURPOSE_ANY store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL store.add_cert(ca1_cert) store.add_cert(ca2_cert) store.add_crl(crl1) store.add_crl(crl2_2) # issued by ca2 but expired. assert_equal(true, store.verify(ca1_cert)) assert_equal(true, store.verify(ca2_cert)) assert_equal(false, store.verify(ee1_cert)) assert_equal(OpenSSL::X509::V_ERR_CRL_HAS_EXPIRED, store.error) assert_equal(false, store.verify(ee2_cert)) end def test_set_errors now = Time.now ca1_cert = issue_cert(@ca1, @rsa2048, 1, now, now+3600, [], nil, nil, OpenSSL::Digest::SHA1.new) store = OpenSSL::X509::Store.new store.add_cert(ca1_cert) assert_raises(OpenSSL::X509::StoreError){ store.add_cert(ca1_cert) # add same certificate twice } revoke_info = [] crl1 = issue_crl(revoke_info, 1, now, now+1800, [], ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) revoke_info = [ [2, now, 1], ] crl2 = issue_crl(revoke_info, 2, now+1800, now+3600, [], ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) store.add_crl(crl1) assert_raises(OpenSSL::X509::StoreError){ store.add_crl(crl2) # add CRL issued by same CA twice. } end end end ================================================ FILE: test/openssl/utils.rb ================================================ require "openssl" require "test/unit" module OpenSSL::TestUtils TEST_KEY_RSA1024 = OpenSSL::PKey::RSA.new <<-_end_of_pem_ -----BEGIN RSA PRIVATE KEY----- MIICXgIBAAKBgQDLwsSw1ECnPtT+PkOgHhcGA71nwC2/nL85VBGnRqDxOqjVh7Cx aKPERYHsk4BPCkE3brtThPWc9kjHEQQ7uf9Y1rbCz0layNqHyywQEVLFmp1cpIt/ Q3geLv8ZD9pihowKJDyMDiN6ArYUmZczvW4976MU3+l54E6lF/JfFEU5hwIDAQAB AoGBAKSl/MQarye1yOysqX6P8fDFQt68VvtXkNmlSiKOGuzyho0M+UVSFcs6k1L0 maDE25AMZUiGzuWHyaU55d7RXDgeskDMakD1v6ZejYtxJkSXbETOTLDwUWTn618T gnb17tU1jktUtU67xK/08i/XodlgnQhs6VoHTuCh3Hu77O6RAkEA7+gxqBuZR572 74/akiW/SuXm0SXPEviyO1MuSRwtI87B02D0qgV8D1UHRm4AhMnJ8MCs1809kMQE JiQUCrp9mQJBANlt2ngBO14us6NnhuAseFDTBzCHXwUUu1YKHpMMmxpnGqaldGgX sOZB3lgJsT9VlGf3YGYdkLTNVbogQKlKpB8CQQDiSwkb4vyQfDe8/NpU5Not0fII 8jsDUCb+opWUTMmfbxWRR3FBNu8wnym/m19N4fFj8LqYzHX4KY0oVPu6qvJxAkEA wa5snNekFcqONLIE4G5cosrIrb74sqL8GbGb+KuTAprzj5z1K8Bm0UW9lTjVDjDi qRYgZfZSL+x1P/54+xTFSwJAY1FxA/N3QPCXCjPh5YqFxAMQs2VVYTfg+t0MEcJD dPMQD5JX6g5HKnHFg2mZtoXQrWmJSn7p8GJK8yNTopEErA== -----END RSA PRIVATE KEY----- _end_of_pem_ TEST_KEY_RSA2048 = OpenSSL::PKey::RSA.new <<-_end_of_pem_ -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAuV9ht9J7k4NBs38jOXvvTKY9gW8nLICSno5EETR1cuF7i4pN s9I1QJGAFAX0BEO4KbzXmuOvfCpD3CU+Slp1enenfzq/t/e/1IRW0wkJUJUFQign 4CtrkJL+P07yx18UjyPlBXb81ApEmAB5mrJVSrWmqbjs07JbuS4QQGGXLc+Su96D kYKmSNVjBiLxVVSpyZfAY3hD37d60uG+X8xdW5v68JkRFIhdGlb6JL8fllf/A/bl NwdJOhVr9mESHhwGjwfSeTDPfd8ZLE027E5lyAVX9KZYcU00mOX+fdxOSnGqS/8J DRh0EPHDL15RcJjV2J6vZjPb0rOYGDoMcH+94wIDAQABAoIBAAzsamqfYQAqwXTb I0CJtGg6msUgU7HVkOM+9d3hM2L791oGHV6xBAdpXW2H8LgvZHJ8eOeSghR8+dgq PIqAffo4x1Oma+FOg3A0fb0evyiACyrOk+EcBdbBeLo/LcvahBtqnDfiUMQTpy6V seSoFCwuN91TSCeGIsDpRjbG1vxZgtx+uI+oH5+ytqJOmfCksRDCkMglGkzyfcl0 Xc5CUhIJ0my53xijEUQl19rtWdMnNnnkdbG8PT3LZlOta5Do86BElzUYka0C6dUc VsBDQ0Nup0P6rEQgy7tephHoRlUGTYamsajGJaAo1F3IQVIrRSuagi7+YpSpCqsW wORqorkCgYEA7RdX6MDVrbw7LePnhyuaqTiMK+055/R1TqhB1JvvxJ1CXk2rDL6G 0TLHQ7oGofd5LYiemg4ZVtWdJe43BPZlVgT6lvL/iGo8JnrncB9Da6L7nrq/+Rvj XGjf1qODCK+LmreZWEsaLPURIoR/Ewwxb9J2zd0CaMjeTwafJo1CZvcCgYEAyCgb aqoWvUecX8VvARfuA593Lsi50t4MEArnOXXcd1RnXoZWhbx5rgO8/ATKfXr0BK/n h2GF9PfKzHFm/4V6e82OL7gu/kLy2u9bXN74vOvWFL5NOrOKPM7Kg+9I131kNYOw Ivnr/VtHE5s0dY7JChYWE1F3vArrOw3T00a4CXUCgYEA0SqY+dS2LvIzW4cHCe9k IQqsT0yYm5TFsUEr4sA3xcPfe4cV8sZb9k/QEGYb1+SWWZ+AHPV3UW5fl8kTbSNb v4ng8i8rVVQ0ANbJO9e5CUrepein2MPL0AkOATR8M7t7dGGpvYV0cFk8ZrFx0oId U0PgYDotF/iueBWlbsOM430CgYEAqYI95dFyPI5/AiSkY5queeb8+mQH62sdcCCr vd/w/CZA/K5sbAo4SoTj8dLk4evU6HtIa0DOP63y071eaxvRpTNqLUOgmLh+D6gS Cc7TfLuFrD+WDBatBd5jZ+SoHccVrLR/4L8jeodo5FPW05A+9gnKXEXsTxY4LOUC 9bS4e1kCgYAqVXZh63JsMwoaxCYmQ66eJojKa47VNrOeIZDZvd2BPVf30glBOT41 gBoDG3WMPZoQj9pb7uMcrnvs4APj2FIhMU8U15LcPAj59cD6S6rWnAxO8NFK7HQG 4Jxg3JNNf8ErQoCHb1B3oVdXJkmbJkARoDpBKmTCgKtP8ADYLmVPQw== -----END RSA PRIVATE KEY----- _end_of_pem_ TEST_KEY_DSA256 = OpenSSL::PKey::DSA.new <<-_end_of_pem_ -----BEGIN DSA PRIVATE KEY----- MIH3AgEAAkEAhk2libbY2a8y2Pt21+YPYGZeW6wzaW2yfj5oiClXro9XMR7XWLkE 9B7XxLNFCS2gmCCdMsMW1HulaHtLFQmB2wIVAM43JZrcgpu6ajZ01VkLc93gu/Ed AkAOhujZrrKV5CzBKutKLb0GVyVWmdC7InoNSMZEeGU72rT96IjM59YzoqmD0pGM 3I1o4cGqg1D1DfM1rQlnN1eSAkBq6xXfEDwJ1mLNxF6q8Zm/ugFYWR5xcX/3wFiT b4+EjHP/DbNh9Vm5wcfnDBJ1zKvrMEf2xqngYdrV/3CiGJeKAhRvL57QvJZcQGvn ISNX5cMzFHRW3Q== -----END DSA PRIVATE KEY----- _end_of_pem_ TEST_KEY_DSA512 = OpenSSL::PKey::DSA.new <<-_end_of_pem_ -----BEGIN DSA PRIVATE KEY----- MIH4AgEAAkEA5lB4GvEwjrsMlGDqGsxrbqeFRh6o9OWt6FgTYiEEHaOYhkIxv0Ok RZPDNwOG997mDjBnvDJ1i56OmS3MbTnovwIVAJgub/aDrSDB4DZGH7UyarcaGy6D AkB9HdFw/3td8K4l1FZHv7TCZeJ3ZLb7dF3TWoGUP003RCqoji3/lHdKoVdTQNuR S/m6DlCwhjRjiQ/lBRgCLCcaAkEAjN891JBjzpMj4bWgsACmMggFf57DS0Ti+5++ Q1VB8qkJN7rA7/2HrCR3gTsWNb1YhAsnFsoeRscC+LxXoXi9OAIUBG98h4tilg6S 55jreJD3Se3slps= -----END DSA PRIVATE KEY----- _end_of_pem_ module_function def issue_cert(dn, key, serial, not_before, not_after, extensions, issuer, issuer_key, digest) cert = OpenSSL::X509::Certificate.new issuer = cert unless issuer issuer_key = key unless issuer_key cert.version = 2 cert.serial = serial cert.subject = dn cert.issuer = issuer.subject cert.public_key = key.public_key cert.not_before = not_before cert.not_after = not_after ef = OpenSSL::X509::ExtensionFactory.new ef.subject_certificate = cert ef.issuer_certificate = issuer extensions.each{|oid, value, critical| cert.add_extension(ef.create_extension(oid, value, critical)) } cert.sign(issuer_key, digest) cert end def issue_crl(revoke_info, serial, lastup, nextup, extensions, issuer, issuer_key, digest) crl = OpenSSL::X509::CRL.new crl.issuer = issuer.subject crl.version = 1 crl.last_update = lastup crl.next_update = nextup revoke_info.each{|serial, time, reason_code| revoked = OpenSSL::X509::Revoked.new revoked.serial = serial revoked.time = time enum = OpenSSL::ASN1::Enumerated(reason_code) ext = OpenSSL::X509::Extension.new("CRLReason", enum) revoked.add_extension(ext) crl.add_revoked(revoked) } ef = OpenSSL::X509::ExtensionFactory.new ef.issuer_certificate = issuer ef.crl = crl crlnum = OpenSSL::ASN1::Integer(serial) crl.add_extension(OpenSSL::X509::Extension.new("crlNumber", crlnum)) extensions.each{|oid, value, critical| crl.add_extension(ef.create_extension(oid, value, critical)) } crl.sign(issuer_key, digest) crl end def get_subject_key_id(cert) asn1_cert = OpenSSL::ASN1.decode(cert) tbscert = asn1_cert.value[0] pkinfo = tbscert.value[6] publickey = pkinfo.value[1] pkvalue = publickey.value OpenSSL::Digest::SHA1.hexdigest(pkvalue).scan(/../).join(":").upcase end end ================================================ FILE: test/optparse/test_getopts.rb ================================================ require 'test/unit' class TestOptionParserGetopts < Test::Unit::TestCase def setup @opt = OptionParser.new end def test_short_noarg o = @opt.getopts(%w[-a], "ab") assert_equal(true, o['a']) assert_equal(false, o['b']) end def test_short_arg o = @opt.getopts(%w[-a1], "a:b:") assert_equal("1", o['a']) assert_equal(nil, o['b']) end def test_long_noarg o = @opt.getopts(%w[--foo], "", "foo", "bar") assert_equal(true, o['foo']) assert_equal(false, o['bar']) end def test_long_arg o = @opt.getopts(%w[--bar ZOT], "", "foo:FOO", "bar:BAR") assert_equal("FOO", o['foo']) assert_equal("ZOT", o['bar']) end end ================================================ FILE: test/optparse/test_noarg.rb ================================================ require 'test_optparse' module TestOptionParser::NoArg class Def1 < TestOptionParser include NoArg def setup super @opt.def_option("-x") {|x| @flag = x} @opt.def_option("--option") {|x| @flag = x} end end class Def2 < TestOptionParser include NoArg def setup super @opt.def_option("-x", "--option") {|x| @flag = x} end end def test_short assert_raises(OptionParser::InvalidOption) {@opt.parse!(%w"-xq")} assert_equal(%w"", no_error {@opt.parse!(%w"-x")}) assert_equal(true, @flag) @flag = nil assert_equal(%w"foo", no_error {@opt.parse!(%w"-x foo")}) assert_equal(true, @flag) end def test_abbrev assert_raises(OptionParser::InvalidOption) {@opt.parse!(%w"-oq")} assert_equal(%w"", no_error {@opt.parse!(%w"-o")}) assert_equal(true, @flag) @flag = nil assert_raises(OptionParser::InvalidOption) {@opt.parse!(%w"-O")} assert_nil(@flag) @flag = nil assert_equal(%w"foo", no_error {@opt.parse!(%w"-o foo")}) assert_equal(true, @flag) end def test_long assert_raises(OptionParser::NeedlessArgument) {@opt.parse!(%w"--option=x")} assert_equal(%w"", no_error {@opt.parse!(%w"--opt")}) assert_equal(true, @flag) @flag = nil assert_equal(%w"foo", no_error {@opt.parse!(%w"--opt foo")}) assert_equal(true, @flag) end def test_ambiguous @opt.def_option("--open") {|x|} assert_raises(OptionParser::AmbiguousOption) {@opt.parse!(%w"--op")} assert_raises(OptionParser::AmbiguousOption) {@opt.parse!(%w"-o")} assert_equal(%w"", no_error {@opt.parse!(%w"--opt")}) assert_equal(true, @flag) end end ================================================ FILE: test/optparse/test_optarg.rb ================================================ require 'test_optparse' class TestOptionParser::OptArg < TestOptionParser def setup super @opt.def_option("-x[VAL]") {|x| @flag = x} @opt.def_option("--option[=VAL]") {|x| @flag = x} end def test_short assert_equal(%w"", no_error {@opt.parse!(%w"-x")}) assert_equal(nil, @flag) @flag = false assert_equal(%w"foo", no_error {@opt.parse!(%w"-x foo")}) assert_equal(nil, @flag) assert_equal(%w"", no_error {@opt.parse!(%w"-xfoo")}) assert_equal("foo", @flag) assert_equal(%w"", no_error {@opt.parse!(%w"-x=")}) assert_equal("=", @flag) end def test_abbrev assert_equal(%w"", no_error {@opt.parse!(%w"-o")}) assert_equal(nil, @flag) @flag = false assert_equal(%w"foo", no_error {@opt.parse!(%w"-o foo")}) assert_equal(nil, @flag) assert_equal(%w"", no_error {@opt.parse!(%w"-ofoo")}) assert_equal("foo", @flag) assert_equal(%w"", no_error {@opt.parse!(%w"-o=")}) assert_equal("=", @flag) end def test_long assert_equal(%w"", no_error {@opt.parse!(%w"--opt")}) assert_equal(nil, @flag) assert_equal(%w"foo", no_error {@opt.parse!(%w"--opt= foo")}) assert_equal("", @flag) assert_equal(%w"", no_error {@opt.parse!(%w"--opt=foo")}) assert_equal("foo", @flag) assert_equal(%w"foo", no_error {@opt.parse!(%w"--opt foo")}) assert_equal(nil, @flag) end end ================================================ FILE: test/optparse/test_optparse.rb ================================================ require 'test/unit' require 'optparse' class TestOptionParser < Test::Unit::TestCase def setup @opt = OptionParser.new @flag = self.class # cannot set by option end def no_error(*args) assert_nothing_raised(*args) {return yield} end def test_permute assert_equal(%w"", no_error {@opt.permute!(%w"")}) assert_equal(self.class, @flag) assert_equal(%w"foo bar", no_error {@opt.permute!(%w"foo bar")}) assert_equal(self.class, @flag) assert_equal(%w"- foo bar", no_error {@opt.permute!(%w"- foo bar")}) assert_equal(self.class, @flag) assert_equal(%w"foo bar", no_error {@opt.permute!(%w"-- foo bar")}) assert_equal(self.class, @flag) assert_equal(%w"foo - bar", no_error {@opt.permute!(%w"foo - bar")}) assert_equal(self.class, @flag) assert_equal(%w"foo bar", no_error {@opt.permute!(%w"foo -- bar")}) assert_equal(self.class, @flag) assert_equal(%w"foo --help bar", no_error {@opt.permute!(%w"foo -- --help bar")}) assert_equal(self.class, @flag) end def test_order assert_equal(%w"", no_error {@opt.order!(%w"")}) assert_equal(self.class, @flag) assert_equal(%w"foo bar", no_error {@opt.order!(%w"foo bar")}) assert_equal(self.class, @flag) assert_equal(%w"- foo bar", no_error {@opt.order!(%w"- foo bar")}) assert_equal(self.class, @flag) assert_equal(%w"foo bar", no_error {@opt.permute!(%w"-- foo bar")}) assert_equal(self.class, @flag) assert_equal(%w"foo - bar", no_error {@opt.order!(%w"foo - bar")}) assert_equal(self.class, @flag) assert_equal(%w"foo -- bar", no_error {@opt.order!(%w"foo -- bar")}) assert_equal(self.class, @flag) assert_equal(%w"foo -- --help bar", no_error {@opt.order!(%w"foo -- --help bar")}) assert_equal(self.class, @flag) end end ================================================ FILE: test/optparse/test_placearg.rb ================================================ require 'test_optparse' class TestOptionParser::PlaceArg < TestOptionParser def setup super @opt.def_option("-x [VAL]") {|x| @flag = x} @opt.def_option("--option [VAL]") {|x| @flag = x} @opt.def_option("-n") {} end def test_short assert_equal(%w"", no_error {@opt.parse!(%w"-x -n")}) assert_equal(nil, @flag) @flag = false assert_equal(%w"", no_error {@opt.parse!(%w"-x foo")}) assert_equal("foo", @flag) assert_equal(%w"", no_error {@opt.parse!(%w"-xbar")}) assert_equal("bar", @flag) assert_equal(%w"", no_error {@opt.parse!(%w"-x=")}) assert_equal("=", @flag) end def test_abbrev assert_equal(%w"", no_error {@opt.parse!(%w"-o -n")}) assert_equal(nil, @flag) @flag = false assert_equal(%w"", no_error {@opt.parse!(%w"-o foo")}) assert_equal("foo", @flag) assert_equal(%w"", no_error {@opt.parse!(%w"-obar")}) assert_equal("bar", @flag) assert_equal(%w"", no_error {@opt.parse!(%w"-o=")}) assert_equal("=", @flag) end def test_long assert_equal(%w"", no_error {@opt.parse!(%w"--opt -n")}) assert_equal(nil, @flag) assert_equal(%w"foo", no_error {@opt.parse!(%w"--opt= foo")}) assert_equal("", @flag) assert_equal(%w"", no_error {@opt.parse!(%w"--opt=foo")}) assert_equal("foo", @flag) assert_equal(%w"", no_error {@opt.parse!(%w"--opt bar")}) assert_equal("bar", @flag) end end ================================================ FILE: test/optparse/test_reqarg.rb ================================================ require 'test_optparse' module TestOptionParser::ReqArg class Def1 < TestOptionParser include ReqArg def setup super @opt.def_option("-xVAL") {|x| @flag = x} @opt.def_option("--option=VAL") {|x| @flag = x} end end class Def2 < TestOptionParser include ReqArg def setup super @opt.def_option("-x", "--option=VAL") {|x| @flag = x} end end class Def3 < TestOptionParser include ReqArg def setup super @opt.def_option("--option=VAL", "-x") {|x| @flag = x} end end class Def4 < TestOptionParser include ReqArg def setup super @opt.def_option("-xVAL", "--option=VAL") {|x| @flag = x} end end def test_short assert_raises(OptionParser::MissingArgument) {@opt.parse!(%w"-x")} assert_equal(%w"", no_error {@opt.parse!(%w"-x foo")}) assert_equal("foo", @flag) assert_equal(%w"", no_error {@opt.parse!(%w"-xbar")}) assert_equal("bar", @flag) assert_equal(%w"", no_error {@opt.parse!(%w"-x=")}) assert_equal("=", @flag) end def test_abbrev assert_raises(OptionParser::MissingArgument) {@opt.parse!(%w"-o")} assert_equal(%w"", no_error {@opt.parse!(%w"-o foo")}) assert_equal("foo", @flag) assert_equal(%w"", no_error {@opt.parse!(%w"-obar")}) assert_equal("bar", @flag) assert_equal(%w"", no_error {@opt.parse!(%w"-o=")}) assert_equal("=", @flag) end def test_long assert_raises(OptionParser::MissingArgument) {@opt.parse!(%w"--opt")} assert_equal(%w"", no_error {@opt.parse!(%w"--opt foo")}) assert_equal("foo", @flag) assert_equal(%w"foo", no_error {@opt.parse!(%w"--opt= foo")}) assert_equal("", @flag) assert_equal(%w"", no_error {@opt.parse!(%w"--opt=foo")}) assert_equal("foo", @flag) end end ================================================ FILE: test/optparse/test_summary.rb ================================================ require 'test/unit' require 'optparse' class TestOptionParser < Test::Unit::TestCase; end class TestOptionParser::SummaryTest < Test::Unit::TestCase def test_short_clash r = nil o = OptionParser.new do |opts| opts.on("-f", "--first-option", "description 1", "description 2"){r = "first-option"} opts.on("-t", "--test-option"){r = "test-option"} opts.on("-t", "--another-test-option"){r = "another-test-option"} opts.separator "this is\nseparator" opts.on("-l", "--last-option"){r = "last-option"} end s = o.summarize o.parse("-t") assert_match(/--#{r}/, s.grep(/^\s*-t,/)[0]) assert_match(/first-option/, s[0]) assert_match(/description 1/, s[0]) assert_match(/description 2/, s[1]) assert_match(/last-option/, s[-1]) end end ================================================ FILE: test/ostruct/test_ostruct.rb ================================================ require 'test/unit' require 'ostruct' class TC_OpenStruct < Test::Unit::TestCase def assert_not_respond_to(object, method, message="") _wrap_assertion do full_message = build_message(message, < of type expected not to respond_to\\?. EOT _wrap_assertion do if object.respond_to?(method) raise Test::Unit::AssertionFailedError, full_message, caller(5) end end end end def test_equality o1 = OpenStruct.new o2 = OpenStruct.new assert_equal(o1, o2) o1.a = 'a' assert_not_equal(o1, o2) o2.a = 'a' assert_equal(o1, o2) o1.a = 'b' assert_not_equal(o1, o2) o2 = Object.new o2.instance_eval{@table = {:a => 'b'}} assert_not_equal(o1, o2) end def test_inspect foo = OpenStruct.new assert_equal("#", foo.inspect) foo.bar = 1 foo.baz = 2 foo.foo = 0 assert_match(/\A#))?)+>\z/, foo.inspect) assert_match(/ foo=0(?:, |>\z)/, foo.inspect) assert_match(/ bar=1(?:, |>\z)/, foo.inspect) assert_match(/ baz=2(?:, |>\z)/, foo.inspect) foo = OpenStruct.new foo.bar = OpenStruct.new assert_equal('#>', foo.inspect) foo.bar.foo = foo assert_equal('#>>', foo.inspect) end def test_frozen o = OpenStruct.new o.a = 'a' o.freeze assert_raise(TypeError) {o.b = 'b'} assert_not_respond_to(o, :b) assert_raise(TypeError) {o.a = 'z'} assert_equal('a', o.a) end end ================================================ FILE: test/pathname/test_pathname.rb ================================================ #!/usr/bin/env ruby require 'test/unit' require 'pathname' require 'fileutils' require 'tmpdir' require 'enumerator' class TestPathname < Test::Unit::TestCase def self.define_assertion(name, &block) @defassert_num ||= {} @defassert_num[name] ||= 0 @defassert_num[name] += 1 define_method("test_#{name}_#{@defassert_num[name]}", &block) end def self.defassert(name, result, *args) define_assertion(name) { assert_equal(result, self.send(name, *args), "#{name}(#{args.map {|a| a.inspect }.join(', ')})") } end DOSISH = File::ALT_SEPARATOR != nil DOSISH_DRIVE_LETTER = File.dirname("A:") == "A:." DOSISH_UNC = File.dirname("//") == "//" def cleanpath_aggressive(path) Pathname.new(path).cleanpath.to_s end defassert(:cleanpath_aggressive, '/', '/') defassert(:cleanpath_aggressive, '.', '') defassert(:cleanpath_aggressive, '.', '.') defassert(:cleanpath_aggressive, '..', '..') defassert(:cleanpath_aggressive, 'a', 'a') defassert(:cleanpath_aggressive, '/', '/.') defassert(:cleanpath_aggressive, '/', '/..') defassert(:cleanpath_aggressive, '/a', '/a') defassert(:cleanpath_aggressive, '.', './') defassert(:cleanpath_aggressive, '..', '../') defassert(:cleanpath_aggressive, 'a', 'a/') defassert(:cleanpath_aggressive, 'a/b', 'a//b') defassert(:cleanpath_aggressive, 'a', 'a/.') defassert(:cleanpath_aggressive, 'a', 'a/./') defassert(:cleanpath_aggressive, '.', 'a/..') defassert(:cleanpath_aggressive, '.', 'a/../') defassert(:cleanpath_aggressive, '/a', '/a/.') defassert(:cleanpath_aggressive, '..', './..') defassert(:cleanpath_aggressive, '..', '../.') defassert(:cleanpath_aggressive, '..', './../') defassert(:cleanpath_aggressive, '..', '.././') defassert(:cleanpath_aggressive, '/', '/./..') defassert(:cleanpath_aggressive, '/', '/../.') defassert(:cleanpath_aggressive, '/', '/./../') defassert(:cleanpath_aggressive, '/', '/.././') defassert(:cleanpath_aggressive, 'a/b/c', 'a/b/c') defassert(:cleanpath_aggressive, 'b/c', './b/c') defassert(:cleanpath_aggressive, 'a/c', 'a/./c') defassert(:cleanpath_aggressive, 'a/b', 'a/b/.') defassert(:cleanpath_aggressive, '.', 'a/../.') defassert(:cleanpath_aggressive, '/a', '/../.././../a') defassert(:cleanpath_aggressive, '../../d', 'a/b/../../../../c/../d') if DOSISH_UNC defassert(:cleanpath_aggressive, '//a/b/c', '//a/b/c/') else defassert(:cleanpath_aggressive, '/', '///') defassert(:cleanpath_aggressive, '/a', '///a') defassert(:cleanpath_aggressive, '/', '///..') defassert(:cleanpath_aggressive, '/', '///.') defassert(:cleanpath_aggressive, '/', '///a/../..') end def cleanpath_conservative(path) Pathname.new(path).cleanpath(true).to_s end defassert(:cleanpath_conservative, '/', '/') defassert(:cleanpath_conservative, '.', '') defassert(:cleanpath_conservative, '.', '.') defassert(:cleanpath_conservative, '..', '..') defassert(:cleanpath_conservative, 'a', 'a') defassert(:cleanpath_conservative, '/', '/.') defassert(:cleanpath_conservative, '/', '/..') defassert(:cleanpath_conservative, '/a', '/a') defassert(:cleanpath_conservative, '.', './') defassert(:cleanpath_conservative, '..', '../') defassert(:cleanpath_conservative, 'a/', 'a/') defassert(:cleanpath_conservative, 'a/b', 'a//b') defassert(:cleanpath_conservative, 'a/.', 'a/.') defassert(:cleanpath_conservative, 'a/.', 'a/./') defassert(:cleanpath_conservative, 'a/..', 'a/../') defassert(:cleanpath_conservative, '/a/.', '/a/.') defassert(:cleanpath_conservative, '..', './..') defassert(:cleanpath_conservative, '..', '../.') defassert(:cleanpath_conservative, '..', './../') defassert(:cleanpath_conservative, '..', '.././') defassert(:cleanpath_conservative, '/', '/./..') defassert(:cleanpath_conservative, '/', '/../.') defassert(:cleanpath_conservative, '/', '/./../') defassert(:cleanpath_conservative, '/', '/.././') defassert(:cleanpath_conservative, 'a/b/c', 'a/b/c') defassert(:cleanpath_conservative, 'b/c', './b/c') defassert(:cleanpath_conservative, 'a/c', 'a/./c') defassert(:cleanpath_conservative, 'a/b/.', 'a/b/.') defassert(:cleanpath_conservative, 'a/..', 'a/../.') defassert(:cleanpath_conservative, '/a', '/../.././../a') defassert(:cleanpath_conservative, 'a/b/../../../../c/../d', 'a/b/../../../../c/../d') if DOSISH_UNC defassert(:cleanpath_conservative, '//', '//') else defassert(:cleanpath_conservative, '/', '//') end # has_trailing_separator?(path) -> bool def has_trailing_separator?(path) Pathname.allocate.__send__(:has_trailing_separator?, path) end defassert(:has_trailing_separator?, false, "/") defassert(:has_trailing_separator?, false, "///") defassert(:has_trailing_separator?, false, "a") defassert(:has_trailing_separator?, true, "a/") def add_trailing_separator(path) Pathname.allocate.__send__(:add_trailing_separator, path) end def del_trailing_separator(path) Pathname.allocate.__send__(:del_trailing_separator, path) end defassert(:del_trailing_separator, "/", "/") defassert(:del_trailing_separator, "/a", "/a") defassert(:del_trailing_separator, "/a", "/a/") defassert(:del_trailing_separator, "/a", "/a//") defassert(:del_trailing_separator, ".", ".") defassert(:del_trailing_separator, ".", "./") defassert(:del_trailing_separator, ".", ".//") if DOSISH_DRIVE_LETTER defassert(:del_trailing_separator, "A:", "A:") defassert(:del_trailing_separator, "A:/", "A:/") defassert(:del_trailing_separator, "A:/", "A://") defassert(:del_trailing_separator, "A:.", "A:.") defassert(:del_trailing_separator, "A:.", "A:./") defassert(:del_trailing_separator, "A:.", "A:.//") end if DOSISH_UNC defassert(:del_trailing_separator, "//", "//") defassert(:del_trailing_separator, "//a", "//a") defassert(:del_trailing_separator, "//a", "//a/") defassert(:del_trailing_separator, "//a", "//a//") defassert(:del_trailing_separator, "//a/b", "//a/b") defassert(:del_trailing_separator, "//a/b", "//a/b/") defassert(:del_trailing_separator, "//a/b", "//a/b//") defassert(:del_trailing_separator, "//a/b/c", "//a/b/c") defassert(:del_trailing_separator, "//a/b/c", "//a/b/c/") defassert(:del_trailing_separator, "//a/b/c", "//a/b/c//") else defassert(:del_trailing_separator, "/", "///") defassert(:del_trailing_separator, "///a", "///a/") end if DOSISH defassert(:del_trailing_separator, "a", "a\\") require 'Win32API' if Win32API.new('kernel32', 'GetACP', nil, 'L').call == 932 defassert(:del_trailing_separator, "\225\\", "\225\\\\") # SJIS end end def plus(path1, path2) # -> path (Pathname.new(path1) + Pathname.new(path2)).to_s end defassert(:plus, '/', '/', '/') defassert(:plus, 'a/b', 'a', 'b') defassert(:plus, 'a', 'a', '.') defassert(:plus, 'b', '.', 'b') defassert(:plus, '.', '.', '.') defassert(:plus, '/b', 'a', '/b') defassert(:plus, '/', '/', '..') defassert(:plus, '.', 'a', '..') defassert(:plus, 'a', 'a/b', '..') defassert(:plus, '../..', '..', '..') defassert(:plus, '/c', '/', '../c') defassert(:plus, 'c', 'a', '../c') defassert(:plus, 'a/c', 'a/b', '../c') defassert(:plus, '../../c', '..', '../c') defassert(:plus, 'a//b/d//e', 'a//b/c', '../d//e') def relative?(path) Pathname.new(path).relative? end defassert(:relative?, false, '/') defassert(:relative?, false, '/a') defassert(:relative?, false, '/..') defassert(:relative?, true, 'a') defassert(:relative?, true, 'a/b') if DOSISH_DRIVE_LETTER defassert(:relative?, false, 'A:') defassert(:relative?, false, 'A:/') defassert(:relative?, false, 'A:/a') end if File.dirname('//') == '//' defassert(:relative?, false, '//') defassert(:relative?, false, '//a') defassert(:relative?, false, '//a/') defassert(:relative?, false, '//a/b') defassert(:relative?, false, '//a/b/') defassert(:relative?, false, '//a/b/c') end def relative_path_from(dest_directory, base_directory) Pathname.new(dest_directory).relative_path_from(Pathname.new(base_directory)).to_s end defassert(:relative_path_from, "../a", "a", "b") defassert(:relative_path_from, "../a", "a", "b/") defassert(:relative_path_from, "../a", "a/", "b") defassert(:relative_path_from, "../a", "a/", "b/") defassert(:relative_path_from, "../a", "/a", "/b") defassert(:relative_path_from, "../a", "/a", "/b/") defassert(:relative_path_from, "../a", "/a/", "/b") defassert(:relative_path_from, "../a", "/a/", "/b/") defassert(:relative_path_from, "../b", "a/b", "a/c") defassert(:relative_path_from, "../a", "../a", "../b") defassert(:relative_path_from, "a", "a", ".") defassert(:relative_path_from, "..", ".", "a") defassert(:relative_path_from, ".", ".", ".") defassert(:relative_path_from, ".", "..", "..") defassert(:relative_path_from, "..", "..", ".") defassert(:relative_path_from, "c/d", "/a/b/c/d", "/a/b") defassert(:relative_path_from, "../..", "/a/b", "/a/b/c/d") defassert(:relative_path_from, "../../../../e", "/e", "/a/b/c/d") defassert(:relative_path_from, "../b/c", "a/b/c", "a/d") defassert(:relative_path_from, "../a", "/../a", "/b") defassert(:relative_path_from, "../../a", "../a", "b") defassert(:relative_path_from, ".", "/a/../../b", "/b") defassert(:relative_path_from, "..", "a/..", "a") defassert(:relative_path_from, ".", "a/../b", "b") defassert(:relative_path_from, "a", "a", "b/..") defassert(:relative_path_from, "b/c", "b/c", "b/..") def self.defassert_raise(name, exc, *args) define_assertion(name) { message = "#{name}(#{args.map {|a| a.inspect }.join(', ')})" assert_raise(exc, message) { self.send(name, *args) } } end defassert_raise(:relative_path_from, ArgumentError, "/", ".") defassert_raise(:relative_path_from, ArgumentError, ".", "/") defassert_raise(:relative_path_from, ArgumentError, "a", "..") defassert_raise(:relative_path_from, ArgumentError, ".", "..") def realpath(path) Pathname.new(path).realpath.to_s end def test_realpath begin File.symlink(nil, nil) rescue NotImplementedError return rescue TypeError end Dir.mktmpdir('rubytest-pathname') {|dir| File.symlink("not-exist-target", "#{dir}/not-exist") assert_raise(Errno::ENOENT) { realpath("#{dir}/not-exist") } File.symlink("loop", "#{dir}/loop") assert_raise(Errno::ELOOP) { realpath("#{dir}/loop") } } end def descend(path) Pathname.new(path).enum_for(:descend).map {|v| v.to_s } end defassert(:descend, %w[/ /a /a/b /a/b/c], "/a/b/c") defassert(:descend, %w[a a/b a/b/c], "a/b/c") defassert(:descend, %w[. ./a ./a/b ./a/b/c], "./a/b/c") defassert(:descend, %w[a/], "a/") def ascend(path) Pathname.new(path).enum_for(:ascend).map {|v| v.to_s } end defassert(:ascend, %w[/a/b/c /a/b /a /], "/a/b/c") defassert(:ascend, %w[a/b/c a/b a], "a/b/c") defassert(:ascend, %w[./a/b/c ./a/b ./a .], "./a/b/c") defassert(:ascend, %w[a/], "a/") def test_initialize p1 = Pathname.new('a') assert_equal('a', p1.to_s) p2 = Pathname.new(p1) assert_equal(p1, p2) end def test_initialize_nul assert_raise(ArgumentError) { Pathname.new("a\0") } end class AnotherStringLike # :nodoc: def initialize(s) @s = s end def to_str() @s end def ==(other) @s == other end end def test_equality obj = Pathname.new("a") str = "a" sym = :a ano = AnotherStringLike.new("a") assert_equal(false, obj == str) assert_equal(false, str == obj) assert_equal(false, obj == ano) assert_equal(false, ano == obj) assert_equal(false, obj == sym) assert_equal(false, sym == obj) obj2 = Pathname.new("a") assert_equal(true, obj == obj2) assert_equal(true, obj === obj2) assert_equal(true, obj.eql?(obj2)) end def test_hashkey h = {} h[Pathname.new("a")] = 1 h[Pathname.new("a")] = 2 assert_equal(1, h.size) end def assert_pathname_cmp(e, s1, s2) p1 = Pathname.new(s1) p2 = Pathname.new(s2) r = p1 <=> p2 assert(e == r, "#{p1.inspect} <=> #{p2.inspect}: <#{e}> expected but was <#{r}>") end def test_comparison assert_pathname_cmp( 0, "a", "a") assert_pathname_cmp( 1, "b", "a") assert_pathname_cmp(-1, "a", "b") ss = %w( a a/ a/b a. a0 ) s1 = ss.shift ss.each {|s2| assert_pathname_cmp(-1, s1, s2) s1 = s2 } end def test_comparison_string assert_equal(nil, Pathname.new("a") <=> "a") assert_equal(nil, "a" <=> Pathname.new("a")) end def pathsub(path, pat, repl) Pathname.new(path).sub(pat, repl).to_s end defassert(:pathsub, "a.o", "a.c", /\.c\z/, ".o") def test_sub_matchdata result = Pathname("abc.gif").sub(/\..*/) { assert_not_nil($~) assert_equal(".gif", $~[0]) ".png" } assert_equal("abc.png", result.to_s) end def root?(path) Pathname.new(path).root? end defassert(:root?, true, "/") defassert(:root?, true, "//") defassert(:root?, true, "///") defassert(:root?, false, "") defassert(:root?, false, "a") def test_destructive_update path = Pathname.new("a") path.to_s.replace "b" assert_equal(Pathname.new("a"), path) end def test_null_character assert_raise(ArgumentError) { Pathname.new("\0") } end def test_taint obj = Pathname.new("a"); assert_same(obj, obj.taint) obj = Pathname.new("a"); assert_same(obj, obj.untaint) assert_equal(false, Pathname.new("a" ) .tainted?) assert_equal(false, Pathname.new("a" ) .to_s.tainted?) assert_equal(true, Pathname.new("a" ).taint .tainted?) assert_equal(true, Pathname.new("a" ).taint.to_s.tainted?) assert_equal(true, Pathname.new("a".taint) .tainted?) assert_equal(true, Pathname.new("a".taint) .to_s.tainted?) assert_equal(true, Pathname.new("a".taint).taint .tainted?) assert_equal(true, Pathname.new("a".taint).taint.to_s.tainted?) str = "a" path = Pathname.new(str) str.taint assert_equal(false, path .tainted?) assert_equal(false, path.to_s.tainted?) end def test_untaint obj = Pathname.new("a"); assert_same(obj, obj.untaint) assert_equal(false, Pathname.new("a").taint.untaint .tainted?) assert_equal(false, Pathname.new("a").taint.untaint.to_s.tainted?) str = "a".taint path = Pathname.new(str) str.untaint assert_equal(true, path .tainted?) assert_equal(true, path.to_s.tainted?) end def test_freeze obj = Pathname.new("a"); assert_same(obj, obj.freeze) assert_equal(false, Pathname.new("a" ) .frozen?) assert_equal(false, Pathname.new("a".freeze) .frozen?) assert_equal(true, Pathname.new("a" ).freeze .frozen?) assert_equal(true, Pathname.new("a".freeze).freeze .frozen?) assert_equal(false, Pathname.new("a" ) .to_s.frozen?) assert_equal(false, Pathname.new("a".freeze) .to_s.frozen?) assert_equal(false, Pathname.new("a" ).freeze.to_s.frozen?) assert_equal(false, Pathname.new("a".freeze).freeze.to_s.frozen?) end def test_to_s str = "a" obj = Pathname.new(str) assert_equal(str, obj.to_s) assert_not_same(str, obj.to_s) assert_not_same(obj.to_s, obj.to_s) end def test_kernel_open count = 0 result = Kernel.open(Pathname.new(__FILE__)) {|f| assert(File.identical?(__FILE__, f)) count += 1 2 } assert_equal(1, count) assert_equal(2, result) end def test_each_filename result = [] Pathname.new("/usr/bin/ruby").each_filename {|f| result << f } assert_equal(%w[usr bin ruby], result) end def test_kernel_pathname assert_equal(Pathname.new("a"), Pathname("a")) end end ================================================ FILE: test/rational/test_fixnum_gcd.rb ================================================ require 'rational' require 'pp' require 'test/unit' require 'rbconfig' class GcdTest < Test::Unit::TestCase @@biggest_positive_fixnum = 1 until (x = ((@@biggest_positive_fixnum << 1) + 1)).class == Bignum @@biggest_positive_fixnum = x end @@biggest_positive_fixnum = (@@biggest_positive_fixnum - 10) until (x = (@@biggest_positive_fixnum + 1)).class == Bignum @@biggest_positive_fixnum = x end @@smallest_positive_bignum = x @@biggest_negative_fixnum = -1 until (x = (@@biggest_negative_fixnum << 1)).class == Bignum @@biggest_negative_fixnum = x end until (x = (@@biggest_negative_fixnum - 1)).class == Bignum @@biggest_negative_fixnum = x end @@smallest_negative_bignum = x def xc x [ x.class, x ].inspect end case RbConfig::CONFIG['build_cpu'] when 'amd64', 'x86_64' # values generated by ruby 1.8.7 (2009-06-12 patchlevel 174) [x86_64-linux] @@expected = [["[Fixnum, 1] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, 4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, -4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Bignum, -4611686018427387905] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Bignum, 4611686018427387905] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Fixnum, 2] => ", "[Fixnum, 2]"], ["[Fixnum, 2] gcd [Fixnum, 4] => ", "[Fixnum, 2]"], ["[Fixnum, 2] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Fixnum, -2] => ", "[Fixnum, 2]"], ["[Fixnum, 2] gcd [Fixnum, -4] => ", "[Fixnum, 2]"], ["[Fixnum, 2] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Fixnum, 4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Fixnum, -4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 2]"], ["[Fixnum, 2] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 2]"], ["[Fixnum, 2] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 2]"], ["[Fixnum, 2] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 2]"], ["[Fixnum, 2] gcd [Bignum, -4611686018427387905] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Bignum, 4611686018427387905] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Fixnum, 2] => ", "[Fixnum, 2]"], ["[Fixnum, 4] gcd [Fixnum, 4] => ", "[Fixnum, 4]"], ["[Fixnum, 4] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Fixnum, -2] => ", "[Fixnum, 2]"], ["[Fixnum, 4] gcd [Fixnum, -4] => ", "[Fixnum, 4]"], ["[Fixnum, 4] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Fixnum, 4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Fixnum, -4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 4]"], ["[Fixnum, 4] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 4]"], ["[Fixnum, 4] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 4]"], ["[Fixnum, 4] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 4]"], ["[Fixnum, 4] gcd [Bignum, -4611686018427387905] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Bignum, 4611686018427387905] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, 5] => ", "[Fixnum, 5]"], ["[Fixnum, 5] gcd [Fixnum, 25] => ", "[Fixnum, 5]"], ["[Fixnum, 5] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, -5] => ", "[Fixnum, 5]"], ["[Fixnum, 5] gcd [Fixnum, -25] => ", "[Fixnum, 5]"], ["[Fixnum, 5] gcd [Fixnum, 4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, -4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Bignum, -4611686018427387905] => ", "[Fixnum, 5]"], ["[Fixnum, 5] gcd [Bignum, 4611686018427387905] => ", "[Fixnum, 5]"], ["[Fixnum, 25] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Fixnum, 5] => ", "[Fixnum, 5]"], ["[Fixnum, 25] gcd [Fixnum, 25] => ", "[Fixnum, 25]"], ["[Fixnum, 25] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Fixnum, -5] => ", "[Fixnum, 5]"], ["[Fixnum, 25] gcd [Fixnum, -25] => ", "[Fixnum, 25]"], ["[Fixnum, 25] gcd [Fixnum, 4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Fixnum, -4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Bignum, -4611686018427387905] => ", "[Fixnum, 5]"], ["[Fixnum, 25] gcd [Bignum, 4611686018427387905] => ", "[Fixnum, 5]"], ["[Fixnum, -1] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, 4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, -4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Bignum, -4611686018427387905] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Bignum, 4611686018427387905] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Fixnum, 2] => ", "[Fixnum, 2]"], ["[Fixnum, -2] gcd [Fixnum, 4] => ", "[Fixnum, 2]"], ["[Fixnum, -2] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Fixnum, -2] => ", "[Fixnum, 2]"], ["[Fixnum, -2] gcd [Fixnum, -4] => ", "[Fixnum, 2]"], ["[Fixnum, -2] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Fixnum, 4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Fixnum, -4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 2]"], ["[Fixnum, -2] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 2]"], ["[Fixnum, -2] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 2]"], ["[Fixnum, -2] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 2]"], ["[Fixnum, -2] gcd [Bignum, -4611686018427387905] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Bignum, 4611686018427387905] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Fixnum, 2] => ", "[Fixnum, 2]"], ["[Fixnum, -4] gcd [Fixnum, 4] => ", "[Fixnum, 4]"], ["[Fixnum, -4] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Fixnum, -2] => ", "[Fixnum, 2]"], ["[Fixnum, -4] gcd [Fixnum, -4] => ", "[Fixnum, 4]"], ["[Fixnum, -4] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Fixnum, 4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Fixnum, -4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 4]"], ["[Fixnum, -4] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 4]"], ["[Fixnum, -4] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 4]"], ["[Fixnum, -4] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 4]"], ["[Fixnum, -4] gcd [Bignum, -4611686018427387905] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Bignum, 4611686018427387905] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, 5] => ", "[Fixnum, 5]"], ["[Fixnum, -5] gcd [Fixnum, 25] => ", "[Fixnum, 5]"], ["[Fixnum, -5] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, -5] => ", "[Fixnum, 5]"], ["[Fixnum, -5] gcd [Fixnum, -25] => ", "[Fixnum, 5]"], ["[Fixnum, -5] gcd [Fixnum, 4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, -4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Bignum, -4611686018427387905] => ", "[Fixnum, 5]"], ["[Fixnum, -5] gcd [Bignum, 4611686018427387905] => ", "[Fixnum, 5]"], ["[Fixnum, -25] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Fixnum, 5] => ", "[Fixnum, 5]"], ["[Fixnum, -25] gcd [Fixnum, 25] => ", "[Fixnum, 25]"], ["[Fixnum, -25] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Fixnum, -5] => ", "[Fixnum, 5]"], ["[Fixnum, -25] gcd [Fixnum, -25] => ", "[Fixnum, 25]"], ["[Fixnum, -25] gcd [Fixnum, 4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Fixnum, -4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Bignum, -4611686018427387905] => ", "[Fixnum, 5]"], ["[Fixnum, -25] gcd [Bignum, 4611686018427387905] => ", "[Fixnum, 5]"], ["[Fixnum, 4611686018427387903] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, 4611686018427387903] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Fixnum, 4611686018427387903] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Fixnum, 4611686018427387903] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, 4611686018427387903] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, 4611686018427387903] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, 4611686018427387903] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Fixnum, 4611686018427387903] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Fixnum, 4611686018427387903] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, 4611686018427387903] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, 4611686018427387903] gcd [Fixnum, 4611686018427387903] => ", "[Fixnum, 4611686018427387903]"], ["[Fixnum, 4611686018427387903] gcd [Fixnum, -4611686018427387903] => ", "[Fixnum, 4611686018427387903]"], ["[Fixnum, 4611686018427387903] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, 4611686018427387903] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, 4611686018427387903] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, 4611686018427387903] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, 4611686018427387903] gcd [Bignum, -4611686018427387905] => ", "[Fixnum, 1]"], ["[Fixnum, 4611686018427387903] gcd [Bignum, 4611686018427387905] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387903] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387903] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387903] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387903] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387903] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387903] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387903] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387903] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387903] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387903] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387903] gcd [Fixnum, 4611686018427387903] => ", "[Fixnum, 4611686018427387903]"], ["[Fixnum, -4611686018427387903] gcd [Fixnum, -4611686018427387903] => ", "[Fixnum, 4611686018427387903]"], ["[Fixnum, -4611686018427387903] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387903] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387903] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387903] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387903] gcd [Bignum, -4611686018427387905] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387903] gcd [Bignum, 4611686018427387905] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, 2] => ", "[Fixnum, 2]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, 4] => ", "[Fixnum, 4]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, -2] => ", "[Fixnum, 2]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, -4] => ", "[Fixnum, 4]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, 4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, -4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, -4611686018427387904] => ", "[Bignum, 4611686018427387904]"], ["[Fixnum, -4611686018427387904] gcd [Bignum, 4611686018427387904] => ", "[Bignum, 4611686018427387904]"], ["[Fixnum, -4611686018427387904] gcd [Bignum, 4611686018427387904] => ", "[Bignum, 4611686018427387904]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, -4611686018427387904] => ", "[Bignum, 4611686018427387904]"], ["[Fixnum, -4611686018427387904] gcd [Bignum, -4611686018427387905] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Bignum, 4611686018427387905] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, 2] => ", "[Fixnum, 2]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, 4] => ", "[Fixnum, 4]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, -2] => ", "[Fixnum, 2]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, -4] => ", "[Fixnum, 4]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, 4611686018427387903] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, -4611686018427387903] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, -4611686018427387904] => ", "[Bignum, 4611686018427387904]"], ["[Bignum, 4611686018427387904] gcd [Bignum, 4611686018427387904] => ", "[Bignum, 4611686018427387904]"], ["[Bignum, 4611686018427387904] gcd [Bignum, 4611686018427387904] => ", "[Bignum, 4611686018427387904]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, -4611686018427387904] => ", "[Bignum, 4611686018427387904]"], ["[Bignum, 4611686018427387904] gcd [Bignum, -4611686018427387905] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Bignum, 4611686018427387905] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, 2] => ", "[Fixnum, 2]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, 4] => ", "[Fixnum, 4]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, -2] => ", "[Fixnum, 2]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, -4] => ", "[Fixnum, 4]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, 4611686018427387903] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, -4611686018427387903] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, -4611686018427387904] => ", "[Bignum, 4611686018427387904]"], ["[Bignum, 4611686018427387904] gcd [Bignum, 4611686018427387904] => ", "[Bignum, 4611686018427387904]"], ["[Bignum, 4611686018427387904] gcd [Bignum, 4611686018427387904] => ", "[Bignum, 4611686018427387904]"], ["[Bignum, 4611686018427387904] gcd [Fixnum, -4611686018427387904] => ", "[Bignum, 4611686018427387904]"], ["[Bignum, 4611686018427387904] gcd [Bignum, -4611686018427387905] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387904] gcd [Bignum, 4611686018427387905] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, 2] => ", "[Fixnum, 2]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, 4] => ", "[Fixnum, 4]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, -2] => ", "[Fixnum, 2]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, -4] => ", "[Fixnum, 4]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, 4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, -4611686018427387903] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, -4611686018427387904] => ", "[Bignum, 4611686018427387904]"], ["[Fixnum, -4611686018427387904] gcd [Bignum, 4611686018427387904] => ", "[Bignum, 4611686018427387904]"], ["[Fixnum, -4611686018427387904] gcd [Bignum, 4611686018427387904] => ", "[Bignum, 4611686018427387904]"], ["[Fixnum, -4611686018427387904] gcd [Fixnum, -4611686018427387904] => ", "[Bignum, 4611686018427387904]"], ["[Fixnum, -4611686018427387904] gcd [Bignum, -4611686018427387905] => ", "[Fixnum, 1]"], ["[Fixnum, -4611686018427387904] gcd [Bignum, 4611686018427387905] => ", "[Fixnum, 1]"], ["[Bignum, -4611686018427387905] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Bignum, -4611686018427387905] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Bignum, -4611686018427387905] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Bignum, -4611686018427387905] gcd [Fixnum, 5] => ", "[Fixnum, 5]"], ["[Bignum, -4611686018427387905] gcd [Fixnum, 25] => ", "[Fixnum, 5]"], ["[Bignum, -4611686018427387905] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Bignum, -4611686018427387905] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Bignum, -4611686018427387905] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Bignum, -4611686018427387905] gcd [Fixnum, -5] => ", "[Fixnum, 5]"], ["[Bignum, -4611686018427387905] gcd [Fixnum, -25] => ", "[Fixnum, 5]"], ["[Bignum, -4611686018427387905] gcd [Fixnum, 4611686018427387903] => ", "[Fixnum, 1]"], ["[Bignum, -4611686018427387905] gcd [Fixnum, -4611686018427387903] => ", "[Fixnum, 1]"], ["[Bignum, -4611686018427387905] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Bignum, -4611686018427387905] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Bignum, -4611686018427387905] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Bignum, -4611686018427387905] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Bignum, -4611686018427387905] gcd [Bignum, -4611686018427387905] => ", "[Bignum, 4611686018427387905]"], ["[Bignum, -4611686018427387905] gcd [Bignum, 4611686018427387905] => ", "[Bignum, 4611686018427387905]"], ["[Bignum, 4611686018427387905] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387905] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387905] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387905] gcd [Fixnum, 5] => ", "[Fixnum, 5]"], ["[Bignum, 4611686018427387905] gcd [Fixnum, 25] => ", "[Fixnum, 5]"], ["[Bignum, 4611686018427387905] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387905] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387905] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387905] gcd [Fixnum, -5] => ", "[Fixnum, 5]"], ["[Bignum, 4611686018427387905] gcd [Fixnum, -25] => ", "[Fixnum, 5]"], ["[Bignum, 4611686018427387905] gcd [Fixnum, 4611686018427387903] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387905] gcd [Fixnum, -4611686018427387903] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387905] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387905] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387905] gcd [Bignum, 4611686018427387904] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387905] gcd [Fixnum, -4611686018427387904] => ", "[Fixnum, 1]"], ["[Bignum, 4611686018427387905] gcd [Bignum, -4611686018427387905] => ", "[Bignum, 4611686018427387905]"], ["[Bignum, 4611686018427387905] gcd [Bignum, 4611686018427387905] => ", "[Bignum, 4611686018427387905]"]] when 'i686', 'i386' # values generated by ruby 1.8.7 (2009-06-12 patchlevel 174) [i486-linux] @@expected = [["[Fixnum, 1] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, 1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, -1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Bignum, -1073741825] => ", "[Fixnum, 1]"], ["[Fixnum, 1] gcd [Bignum, 1073741825] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Fixnum, 2] => ", "[Fixnum, 2]"], ["[Fixnum, 2] gcd [Fixnum, 4] => ", "[Fixnum, 2]"], ["[Fixnum, 2] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Fixnum, -2] => ", "[Fixnum, 2]"], ["[Fixnum, 2] gcd [Fixnum, -4] => ", "[Fixnum, 2]"], ["[Fixnum, 2] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Fixnum, 1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Fixnum, -1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Fixnum, -1073741824] => ", "[Fixnum, 2]"], ["[Fixnum, 2] gcd [Bignum, 1073741824] => ", "[Fixnum, 2]"], ["[Fixnum, 2] gcd [Bignum, 1073741824] => ", "[Fixnum, 2]"], ["[Fixnum, 2] gcd [Fixnum, -1073741824] => ", "[Fixnum, 2]"], ["[Fixnum, 2] gcd [Bignum, -1073741825] => ", "[Fixnum, 1]"], ["[Fixnum, 2] gcd [Bignum, 1073741825] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Fixnum, 2] => ", "[Fixnum, 2]"], ["[Fixnum, 4] gcd [Fixnum, 4] => ", "[Fixnum, 4]"], ["[Fixnum, 4] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Fixnum, -2] => ", "[Fixnum, 2]"], ["[Fixnum, 4] gcd [Fixnum, -4] => ", "[Fixnum, 4]"], ["[Fixnum, 4] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Fixnum, 1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Fixnum, -1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Fixnum, -1073741824] => ", "[Fixnum, 4]"], ["[Fixnum, 4] gcd [Bignum, 1073741824] => ", "[Fixnum, 4]"], ["[Fixnum, 4] gcd [Bignum, 1073741824] => ", "[Fixnum, 4]"], ["[Fixnum, 4] gcd [Fixnum, -1073741824] => ", "[Fixnum, 4]"], ["[Fixnum, 4] gcd [Bignum, -1073741825] => ", "[Fixnum, 1]"], ["[Fixnum, 4] gcd [Bignum, 1073741825] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, 5] => ", "[Fixnum, 5]"], ["[Fixnum, 5] gcd [Fixnum, 25] => ", "[Fixnum, 5]"], ["[Fixnum, 5] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, -5] => ", "[Fixnum, 5]"], ["[Fixnum, 5] gcd [Fixnum, -25] => ", "[Fixnum, 5]"], ["[Fixnum, 5] gcd [Fixnum, 1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, -1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, 5] gcd [Bignum, -1073741825] => ", "[Fixnum, 5]"], ["[Fixnum, 5] gcd [Bignum, 1073741825] => ", "[Fixnum, 5]"], ["[Fixnum, 25] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Fixnum, 5] => ", "[Fixnum, 5]"], ["[Fixnum, 25] gcd [Fixnum, 25] => ", "[Fixnum, 25]"], ["[Fixnum, 25] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Fixnum, -5] => ", "[Fixnum, 5]"], ["[Fixnum, 25] gcd [Fixnum, -25] => ", "[Fixnum, 25]"], ["[Fixnum, 25] gcd [Fixnum, 1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Fixnum, -1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, 25] gcd [Bignum, -1073741825] => ", "[Fixnum, 25]"], ["[Fixnum, 25] gcd [Bignum, 1073741825] => ", "[Fixnum, 25]"], ["[Fixnum, -1] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, 1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, -1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Bignum, -1073741825] => ", "[Fixnum, 1]"], ["[Fixnum, -1] gcd [Bignum, 1073741825] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Fixnum, 2] => ", "[Fixnum, 2]"], ["[Fixnum, -2] gcd [Fixnum, 4] => ", "[Fixnum, 2]"], ["[Fixnum, -2] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Fixnum, -2] => ", "[Fixnum, 2]"], ["[Fixnum, -2] gcd [Fixnum, -4] => ", "[Fixnum, 2]"], ["[Fixnum, -2] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Fixnum, 1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Fixnum, -1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Fixnum, -1073741824] => ", "[Fixnum, 2]"], ["[Fixnum, -2] gcd [Bignum, 1073741824] => ", "[Fixnum, 2]"], ["[Fixnum, -2] gcd [Bignum, 1073741824] => ", "[Fixnum, 2]"], ["[Fixnum, -2] gcd [Fixnum, -1073741824] => ", "[Fixnum, 2]"], ["[Fixnum, -2] gcd [Bignum, -1073741825] => ", "[Fixnum, 1]"], ["[Fixnum, -2] gcd [Bignum, 1073741825] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Fixnum, 2] => ", "[Fixnum, 2]"], ["[Fixnum, -4] gcd [Fixnum, 4] => ", "[Fixnum, 4]"], ["[Fixnum, -4] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Fixnum, -2] => ", "[Fixnum, 2]"], ["[Fixnum, -4] gcd [Fixnum, -4] => ", "[Fixnum, 4]"], ["[Fixnum, -4] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Fixnum, 1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Fixnum, -1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Fixnum, -1073741824] => ", "[Fixnum, 4]"], ["[Fixnum, -4] gcd [Bignum, 1073741824] => ", "[Fixnum, 4]"], ["[Fixnum, -4] gcd [Bignum, 1073741824] => ", "[Fixnum, 4]"], ["[Fixnum, -4] gcd [Fixnum, -1073741824] => ", "[Fixnum, 4]"], ["[Fixnum, -4] gcd [Bignum, -1073741825] => ", "[Fixnum, 1]"], ["[Fixnum, -4] gcd [Bignum, 1073741825] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, 5] => ", "[Fixnum, 5]"], ["[Fixnum, -5] gcd [Fixnum, 25] => ", "[Fixnum, 5]"], ["[Fixnum, -5] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, -5] => ", "[Fixnum, 5]"], ["[Fixnum, -5] gcd [Fixnum, -25] => ", "[Fixnum, 5]"], ["[Fixnum, -5] gcd [Fixnum, 1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, -1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, -5] gcd [Bignum, -1073741825] => ", "[Fixnum, 5]"], ["[Fixnum, -5] gcd [Bignum, 1073741825] => ", "[Fixnum, 5]"], ["[Fixnum, -25] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Fixnum, 5] => ", "[Fixnum, 5]"], ["[Fixnum, -25] gcd [Fixnum, 25] => ", "[Fixnum, 25]"], ["[Fixnum, -25] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Fixnum, -5] => ", "[Fixnum, 5]"], ["[Fixnum, -25] gcd [Fixnum, -25] => ", "[Fixnum, 25]"], ["[Fixnum, -25] gcd [Fixnum, 1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Fixnum, -1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, -25] gcd [Bignum, -1073741825] => ", "[Fixnum, 25]"], ["[Fixnum, -25] gcd [Bignum, 1073741825] => ", "[Fixnum, 25]"], ["[Fixnum, 1073741823] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, 1073741823] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Fixnum, 1073741823] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Fixnum, 1073741823] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, 1073741823] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, 1073741823] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, 1073741823] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Fixnum, 1073741823] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Fixnum, 1073741823] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, 1073741823] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, 1073741823] gcd [Fixnum, 1073741823] => ", "[Fixnum, 1073741823]"], ["[Fixnum, 1073741823] gcd [Fixnum, -1073741823] => ", "[Fixnum, 1073741823]"], ["[Fixnum, 1073741823] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, 1073741823] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, 1073741823] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, 1073741823] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, 1073741823] gcd [Bignum, -1073741825] => ", "[Fixnum, 1]"], ["[Fixnum, 1073741823] gcd [Bignum, 1073741825] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741823] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741823] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741823] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741823] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741823] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741823] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741823] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741823] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741823] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741823] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741823] gcd [Fixnum, 1073741823] => ", "[Fixnum, 1073741823]"], ["[Fixnum, -1073741823] gcd [Fixnum, -1073741823] => ", "[Fixnum, 1073741823]"], ["[Fixnum, -1073741823] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741823] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741823] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741823] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741823] gcd [Bignum, -1073741825] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741823] gcd [Bignum, 1073741825] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Fixnum, 2] => ", "[Fixnum, 2]"], ["[Fixnum, -1073741824] gcd [Fixnum, 4] => ", "[Fixnum, 4]"], ["[Fixnum, -1073741824] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Fixnum, -2] => ", "[Fixnum, 2]"], ["[Fixnum, -1073741824] gcd [Fixnum, -4] => ", "[Fixnum, 4]"], ["[Fixnum, -1073741824] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Fixnum, 1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Fixnum, -1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Fixnum, -1073741824] => ", "[Bignum, 1073741824]"], ["[Fixnum, -1073741824] gcd [Bignum, 1073741824] => ", "[Bignum, 1073741824]"], ["[Fixnum, -1073741824] gcd [Bignum, 1073741824] => ", "[Bignum, 1073741824]"], ["[Fixnum, -1073741824] gcd [Fixnum, -1073741824] => ", "[Bignum, 1073741824]"], ["[Fixnum, -1073741824] gcd [Bignum, -1073741825] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Bignum, 1073741825] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Fixnum, 2] => ", "[Fixnum, 2]"], ["[Bignum, 1073741824] gcd [Fixnum, 4] => ", "[Fixnum, 4]"], ["[Bignum, 1073741824] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Fixnum, -2] => ", "[Fixnum, 2]"], ["[Bignum, 1073741824] gcd [Fixnum, -4] => ", "[Fixnum, 4]"], ["[Bignum, 1073741824] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Fixnum, 1073741823] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Fixnum, -1073741823] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Fixnum, -1073741824] => ", "[Bignum, 1073741824]"], ["[Bignum, 1073741824] gcd [Bignum, 1073741824] => ", "[Bignum, 1073741824]"], ["[Bignum, 1073741824] gcd [Bignum, 1073741824] => ", "[Bignum, 1073741824]"], ["[Bignum, 1073741824] gcd [Fixnum, -1073741824] => ", "[Bignum, 1073741824]"], ["[Bignum, 1073741824] gcd [Bignum, -1073741825] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Bignum, 1073741825] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Fixnum, 2] => ", "[Fixnum, 2]"], ["[Bignum, 1073741824] gcd [Fixnum, 4] => ", "[Fixnum, 4]"], ["[Bignum, 1073741824] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Fixnum, -2] => ", "[Fixnum, 2]"], ["[Bignum, 1073741824] gcd [Fixnum, -4] => ", "[Fixnum, 4]"], ["[Bignum, 1073741824] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Fixnum, 1073741823] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Fixnum, -1073741823] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Fixnum, -1073741824] => ", "[Bignum, 1073741824]"], ["[Bignum, 1073741824] gcd [Bignum, 1073741824] => ", "[Bignum, 1073741824]"], ["[Bignum, 1073741824] gcd [Bignum, 1073741824] => ", "[Bignum, 1073741824]"], ["[Bignum, 1073741824] gcd [Fixnum, -1073741824] => ", "[Bignum, 1073741824]"], ["[Bignum, 1073741824] gcd [Bignum, -1073741825] => ", "[Fixnum, 1]"], ["[Bignum, 1073741824] gcd [Bignum, 1073741825] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Fixnum, 2] => ", "[Fixnum, 2]"], ["[Fixnum, -1073741824] gcd [Fixnum, 4] => ", "[Fixnum, 4]"], ["[Fixnum, -1073741824] gcd [Fixnum, 5] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Fixnum, 25] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Fixnum, -2] => ", "[Fixnum, 2]"], ["[Fixnum, -1073741824] gcd [Fixnum, -4] => ", "[Fixnum, 4]"], ["[Fixnum, -1073741824] gcd [Fixnum, -5] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Fixnum, -25] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Fixnum, 1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Fixnum, -1073741823] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Fixnum, -1073741824] => ", "[Bignum, 1073741824]"], ["[Fixnum, -1073741824] gcd [Bignum, 1073741824] => ", "[Bignum, 1073741824]"], ["[Fixnum, -1073741824] gcd [Bignum, 1073741824] => ", "[Bignum, 1073741824]"], ["[Fixnum, -1073741824] gcd [Fixnum, -1073741824] => ", "[Bignum, 1073741824]"], ["[Fixnum, -1073741824] gcd [Bignum, -1073741825] => ", "[Fixnum, 1]"], ["[Fixnum, -1073741824] gcd [Bignum, 1073741825] => ", "[Fixnum, 1]"], ["[Bignum, -1073741825] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Bignum, -1073741825] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Bignum, -1073741825] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Bignum, -1073741825] gcd [Fixnum, 5] => ", "[Fixnum, 5]"], ["[Bignum, -1073741825] gcd [Fixnum, 25] => ", "[Fixnum, 25]"], ["[Bignum, -1073741825] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Bignum, -1073741825] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Bignum, -1073741825] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Bignum, -1073741825] gcd [Fixnum, -5] => ", "[Fixnum, 5]"], ["[Bignum, -1073741825] gcd [Fixnum, -25] => ", "[Fixnum, 25]"], ["[Bignum, -1073741825] gcd [Fixnum, 1073741823] => ", "[Fixnum, 1]"], ["[Bignum, -1073741825] gcd [Fixnum, -1073741823] => ", "[Fixnum, 1]"], ["[Bignum, -1073741825] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Bignum, -1073741825] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Bignum, -1073741825] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Bignum, -1073741825] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Bignum, -1073741825] gcd [Bignum, -1073741825] => ", "[Bignum, 1073741825]"], ["[Bignum, -1073741825] gcd [Bignum, 1073741825] => ", "[Bignum, 1073741825]"], ["[Bignum, 1073741825] gcd [Fixnum, 1] => ", "[Fixnum, 1]"], ["[Bignum, 1073741825] gcd [Fixnum, 2] => ", "[Fixnum, 1]"], ["[Bignum, 1073741825] gcd [Fixnum, 4] => ", "[Fixnum, 1]"], ["[Bignum, 1073741825] gcd [Fixnum, 5] => ", "[Fixnum, 5]"], ["[Bignum, 1073741825] gcd [Fixnum, 25] => ", "[Fixnum, 25]"], ["[Bignum, 1073741825] gcd [Fixnum, -1] => ", "[Fixnum, 1]"], ["[Bignum, 1073741825] gcd [Fixnum, -2] => ", "[Fixnum, 1]"], ["[Bignum, 1073741825] gcd [Fixnum, -4] => ", "[Fixnum, 1]"], ["[Bignum, 1073741825] gcd [Fixnum, -5] => ", "[Fixnum, 5]"], ["[Bignum, 1073741825] gcd [Fixnum, -25] => ", "[Fixnum, 25]"], ["[Bignum, 1073741825] gcd [Fixnum, 1073741823] => ", "[Fixnum, 1]"], ["[Bignum, 1073741825] gcd [Fixnum, -1073741823] => ", "[Fixnum, 1]"], ["[Bignum, 1073741825] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Bignum, 1073741825] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Bignum, 1073741825] gcd [Bignum, 1073741824] => ", "[Fixnum, 1]"], ["[Bignum, 1073741825] gcd [Fixnum, -1073741824] => ", "[Fixnum, 1]"], ["[Bignum, 1073741825] gcd [Bignum, -1073741825] => ", "[Bignum, 1073741825]"], ["[Bignum, 1073741825] gcd [Bignum, 1073741825] => ", "[Bignum, 1073741825]"]] else pp RbConfig::CONFIG @@expected = nil end def test_results values = [ 1, 2, 4, 5, 25, -1, -2, -4, -5, -25, @@biggest_positive_fixnum, - @@biggest_positive_fixnum, @@biggest_negative_fixnum, - @@biggest_negative_fixnum, @@smallest_positive_bignum, - @@smallest_positive_bignum, @@smallest_negative_bignum, - @@smallest_negative_bignum, ] result = [ ] values.each do | x | values.each do | y | result << [ "#{xc(x)} gcd #{xc(y)} => ", begin xc(x.gcd(y)) rescue => err err end ] end end if @@expected if result != @@expected @@expected.each_with_index do | x, i | y = result[i] assert_equal x, y end end else puts "@@expected = " pp result end end end ================================================ FILE: test/rational/test_rational.rb ================================================ require 'test/unit' require 'rational' class RationalSub < Rational; end class Rational_Test < Test::Unit::TestCase def setup @complex = defined?(Complex) if @complex @keiju = Complex.instance_variables.include?(:@RCS_ID) end seps = [File::SEPARATOR, File::ALT_SEPARATOR].compact.map{|x| Regexp.escape(x)}.join("|") @unify = $".grep(/(?:^|#{seps})mathn(?:\.(?:rb|so))?/).size != 0 end ## [1.8] Rational#convert is missing =begin def test_ratsub c = RationalSub.__send__(:convert, 1) assert_kind_of(Numeric, c) if @unify assert_instance_of(Fixnum, c) else assert_instance_of(RationalSub, c) c2 = c + 1 assert_instance_of(RationalSub, c2) c2 = c - 1 assert_instance_of(RationalSub, c2) c3 = c - c2 assert_instance_of(RationalSub, c3) s = Marshal.dump(c) c5 = Marshal.load(s) assert_equal(c, c5) assert_instance_of(RationalSub, c5) end c1 = Rational(1) assert_equal(c1.hash, c.hash, '[ruby-dev:38850]') assert_equal([true, true], [c.eql?(c1), c1.eql?(c)]) end =end def test_eql_p c = Rational(0) c2 = Rational(0) c3 = Rational(1) assert_equal(true, c.eql?(c2)) assert_equal(false, c.eql?(c3)) if @unify assert_equal(true, c.eql?(0)) else assert_equal(false, c.eql?(0)) end end def test_hash assert_instance_of(Fixnum, Rational(1,2).hash) h = {} h[Rational(0)] = 0 h[Rational(1,1)] = 1 h[Rational(2,1)] = 2 h[Rational(3,1)] = 3 assert_equal(4, h.size) assert_equal(2, h[Rational(2,1)]) h[Rational(0,1)] = 9 assert_equal(4, h.size) end def test_freeze c = Rational(1) c.freeze unless @unify assert_equal(true, c.frozen?) end assert_instance_of(String, c.to_s) end def test_conv c = Rational(0,1) assert_equal(Rational(0,1), c) c = Rational(2**32, 2**32) assert_equal(Rational(2**32,2**32), c) assert_equal([1,1], [c.numerator,c.denominator]) c = Rational(-2**32, 2**32) assert_equal(Rational(-2**32,2**32), c) assert_equal([-1,1], [c.numerator,c.denominator]) c = Rational(2**32, -2**32) assert_equal(Rational(2**32,-2**32), c) assert_equal([-1,1], [c.numerator,c.denominator]) c = Rational(-2**32, -2**32) assert_equal(Rational(-2**32,-2**32), c) assert_equal([1,1], [c.numerator,c.denominator]) ## [1.8] Rational() blindly expects arguments to be integers =begin c = Rational(Rational(1,2),2) assert_equal(Rational(1,4), c) c = Rational(2,Rational(1,2)) assert_equal(Rational(4), c) c = Rational(Rational(1,2),Rational(1,2)) assert_equal(Rational(1), c) =end if @complex && !@keiju c = Rational(Complex(1,2),2) assert_equal(Complex(Rational(1,2),1), c) c = Rational(2,Complex(1,2)) assert_equal(Complex(Rational(2,5),Rational(-4,5)), c) c = Rational(Complex(1,2),Complex(1,2)) assert_equal(Rational(1), c) end assert_equal(Rational(3),Rational(3)) assert_equal(Rational(1),Rational(3,3)) ## [1.8] Float#to_r is missing =begin assert_equal(3.3.to_r,Rational(3.3)) =end ## [1.8] Rational() blindly expects arguments to be integers =begin assert_equal(1,Rational(3.3,3.3)) assert_equal(Rational(3),Rational('3')) assert_equal(Rational(1),Rational('3.0','3.0')) assert_equal(Rational(1),Rational('3/3','3/3')) assert_raise(TypeError){Rational(nil)} assert_raise(ArgumentError){Rational('')} assert_raise(TypeError){Rational(Object.new)} =end assert_raise(ArgumentError){Rational()} assert_raise(ArgumentError){Rational(1,2,3)} ## [1.8] Rational() blindly expects arguments to be integers =begin if (0.0/0).nan? assert_raise(FloatDomainError){Rational(0.0/0)} end if (1.0/0).infinite? assert_raise(FloatDomainError){Rational(1.0/0)} end =end end def test_attr c = Rational(4) assert_equal(4, c.numerator) assert_equal(1, c.denominator) c = Rational(4,5) assert_equal(4, c.numerator) assert_equal(5, c.denominator) c = Rational(4) assert_equal(4, c.numerator) assert_equal(1, c.denominator) c = Rational(4,5) assert_equal(4, c.numerator) assert_equal(5, c.denominator) c = Rational(4) assert_equal(4, c.numerator) assert_equal(1, c.denominator) c = Rational(4,5) assert_equal(4, c.numerator) assert_equal(5, c.denominator) end def test_attr2 c = Rational(1) if @unify =begin assert_equal(true, c.finite?) assert_equal(false, c.infinite?) assert_equal(false, c.nan?) assert_equal(true, c.integer?) assert_equal(false, c.float?) assert_equal(true, c.rational?) =end ## [1.8] Numeric#real? is missing =begin assert_equal(true, c.real?) =end =begin assert_equal(false, c.complex?) assert_equal(true, c.exact?) assert_equal(false, c.inexact?) =end else =begin assert_equal(true, c.finite?) assert_equal(false, c.infinite?) assert_equal(false, c.nan?) assert_equal(false, c.integer?) assert_equal(false, c.float?) assert_equal(true, c.rational?) =end ## [1.8] Numeric#real? is missing =begin assert_equal(true, c.real?) =end =begin assert_equal(false, c.complex?) assert_equal(true, c.exact?) assert_equal(false, c.inexact?) =end end =begin assert_equal(true, Rational(0).positive?) assert_equal(true, Rational(1).positive?) assert_equal(false, Rational(-1).positive?) assert_equal(false, Rational(0).negative?) assert_equal(false, Rational(1).negative?) assert_equal(true, Rational(-1).negative?) assert_equal(0, Rational(0).sign) assert_equal(1, Rational(2).sign) assert_equal(-1, Rational(-2).sign) =end assert_equal(true, Rational(0).zero?) assert_equal(true, Rational(0,1).zero?) assert_equal(false, Rational(1,1).zero?) assert_equal(nil, Rational(0).nonzero?) assert_equal(nil, Rational(0,1).nonzero?) assert_equal(Rational(1,1), Rational(1,1).nonzero?) end def test_uplus assert_equal(Rational(1), +Rational(1)) assert_equal(Rational(-1), +Rational(-1)) assert_equal(Rational(1,1), +Rational(1,1)) assert_equal(Rational(-1,1), +Rational(-1,1)) assert_equal(Rational(-1,1), +Rational(1,-1)) assert_equal(Rational(1,1), +Rational(-1,-1)) end def test_negate assert_equal(Rational(-1), -Rational(1)) assert_equal(Rational(1), -Rational(-1)) assert_equal(Rational(-1,1), -Rational(1,1)) assert_equal(Rational(1,1), -Rational(-1,1)) assert_equal(Rational(1,1), -Rational(1,-1)) assert_equal(Rational(-1,1), -Rational(-1,-1)) =begin assert_equal(0, Rational(0).negate) assert_equal(-2, Rational(2).negate) assert_equal(2, Rational(-2).negate) =end end def test_add c = Rational(1,2) c2 = Rational(2,3) assert_equal(Rational(7,6), c + c2) assert_equal(Rational(5,2), c + 2) assert_equal(2.5, c + 2.0) end def test_sub c = Rational(1,2) c2 = Rational(2,3) assert_equal(Rational(-1,6), c - c2) assert_equal(Rational(-3,2), c - 2) assert_equal(-1.5, c - 2.0) end def test_mul c = Rational(1,2) c2 = Rational(2,3) assert_equal(Rational(1,3), c * c2) assert_equal(Rational(1,1), c * 2) assert_equal(1.0, c * 2.0) end def test_div c = Rational(1,2) c2 = Rational(2,3) assert_equal(Rational(3,4), c / c2) assert_equal(Rational(1,4), c / 2) assert_equal(0.25, c / 2.0) assert_raise(ZeroDivisionError){Rational(1, 3) / 0} assert_raise(ZeroDivisionError){Rational(1, 3) / Rational(0)} end def assert_eql(exp, act, *args) unless Array === exp exp = [exp] end unless Array === act act = [act] end exp.zip(act).each do |e, a| na = [e, a] + args assert_equal(*na) na = [e.class, a] + args assert_instance_of(*na) end end def test_idiv c = Rational(1,2) c2 = Rational(2,3) assert_eql(0, c.div(c2)) assert_eql(0, c.div(2)) assert_eql(0, c.div(2.0)) c = Rational(301,100) c2 = Rational(7,5) assert_equal(2, c.div(c2)) assert_equal(-3, c.div(-c2)) assert_equal(-3, (-c).div(c2)) assert_equal(2, (-c).div(-c2)) c = Rational(301,100) c2 = Rational(2) assert_equal(1, c.div(c2)) assert_equal(-2, c.div(-c2)) assert_equal(-2, (-c).div(c2)) assert_equal(1, (-c).div(-c2)) unless @unify c = Rational(11) c2 = Rational(3) assert_equal(3, c.div(c2)) assert_equal(-4, c.div(-c2)) assert_equal(-4, (-c).div(c2)) assert_equal(3, (-c).div(-c2)) end end def test_modulo c = Rational(1,2) c2 = Rational(2,3) assert_eql(Rational(1,2), c.modulo(c2)) assert_eql(Rational(1,2), c.modulo(2)) assert_eql(0.5, c.modulo(2.0)) c = Rational(301,100) c2 = Rational(7,5) assert_equal(Rational(21,100), c.modulo(c2)) assert_equal(Rational(-119,100), c.modulo(-c2)) assert_equal(Rational(119,100), (-c).modulo(c2)) assert_equal(Rational(-21,100), (-c).modulo(-c2)) c = Rational(301,100) c2 = Rational(2) assert_equal(Rational(101,100), c.modulo(c2)) assert_equal(Rational(-99,100), c.modulo(-c2)) assert_equal(Rational(99,100), (-c).modulo(c2)) assert_equal(Rational(-101,100), (-c).modulo(-c2)) unless @unify c = Rational(11) c2 = Rational(3) assert_equal(2, c.modulo(c2)) assert_equal(-1, c.modulo(-c2)) assert_equal(1, (-c).modulo(c2)) assert_equal(-2, (-c).modulo(-c2)) end end def test_divmod c = Rational(1,2) c2 = Rational(2,3) assert_eql([0, Rational(1,2)], c.divmod(c2)) assert_eql([0, Rational(1,2)], c.divmod(2)) assert_eql([0, 0.5], c.divmod(2.0)) c = Rational(301,100) c2 = Rational(7,5) assert_equal([2, Rational(21,100)], c.divmod(c2)) assert_equal([-3, Rational(-119,100)], c.divmod(-c2)) assert_equal([-3, Rational(119,100)], (-c).divmod(c2)) assert_equal([2, Rational(-21,100)], (-c).divmod(-c2)) c = Rational(301,100) c2 = Rational(2) assert_equal([1, Rational(101,100)], c.divmod(c2)) assert_equal([-2, Rational(-99,100)], c.divmod(-c2)) assert_equal([-2, Rational(99,100)], (-c).divmod(c2)) assert_equal([1, Rational(-101,100)], (-c).divmod(-c2)) unless @unify c = Rational(11) c2 = Rational(3) assert_equal([3,2], c.divmod(c2)) assert_equal([-4,-1], c.divmod(-c2)) assert_equal([-4,1], (-c).divmod(c2)) assert_equal([3,-2], (-c).divmod(-c2)) end end =begin def test_quot c = Rational(1,2) c2 = Rational(2,3) assert_eql(0, c.quot(c2)) assert_eql(0, c.quot(2)) assert_eql(0, c.quot(2.0)) c = Rational(301,100) c2 = Rational(7,5) assert_equal(2, c.quot(c2)) assert_equal(-2, c.quot(-c2)) assert_equal(-2, (-c).quot(c2)) assert_equal(2, (-c).quot(-c2)) c = Rational(301,100) c2 = Rational(2) assert_equal(1, c.quot(c2)) assert_equal(-1, c.quot(-c2)) assert_equal(-1, (-c).quot(c2)) assert_equal(1, (-c).quot(-c2)) unless @unify c = Rational(11) c2 = Rational(3) assert_equal(3, c.quot(c2)) assert_equal(-3, c.quot(-c2)) assert_equal(-3, (-c).quot(c2)) assert_equal(3, (-c).quot(-c2)) end end =end def test_remainder c = Rational(1,2) c2 = Rational(2,3) assert_eql(Rational(1,2), c.remainder(c2)) assert_eql(Rational(1,2), c.remainder(2)) assert_eql(0.5, c.remainder(2.0)) c = Rational(301,100) c2 = Rational(7,5) assert_equal(Rational(21,100), c.remainder(c2)) assert_equal(Rational(21,100), c.remainder(-c2)) assert_equal(Rational(-21,100), (-c).remainder(c2)) assert_equal(Rational(-21,100), (-c).remainder(-c2)) c = Rational(301,100) c2 = Rational(2) assert_equal(Rational(101,100), c.remainder(c2)) assert_equal(Rational(101,100), c.remainder(-c2)) assert_equal(Rational(-101,100), (-c).remainder(c2)) assert_equal(Rational(-101,100), (-c).remainder(-c2)) unless @unify c = Rational(11) c2 = Rational(3) assert_equal(2, c.remainder(c2)) assert_equal(2, c.remainder(-c2)) assert_equal(-2, (-c).remainder(c2)) assert_equal(-2, (-c).remainder(-c2)) end end =begin def test_quotrem c = Rational(1,2) c2 = Rational(2,3) assert_eql([0, Rational(1,2)], c.quotrem(c2)) assert_eql([0, Rational(1,2)], c.quotrem(2)) assert_eql([0, 0.5], c.quotrem(2.0)) c = Rational(301,100) c2 = Rational(7,5) assert_equal([2, Rational(21,100)], c.quotrem(c2)) assert_equal([-2, Rational(21,100)], c.quotrem(-c2)) assert_equal([-2, Rational(-21,100)], (-c).quotrem(c2)) assert_equal([2, Rational(-21,100)], (-c).quotrem(-c2)) c = Rational(301,100) c2 = Rational(2) assert_equal([1, Rational(101,100)], c.quotrem(c2)) assert_equal([-1, Rational(101,100)], c.quotrem(-c2)) assert_equal([-1, Rational(-101,100)], (-c).quotrem(c2)) assert_equal([1, Rational(-101,100)], (-c).quotrem(-c2)) unless @unify c = Rational(11) c2 = Rational(3) assert_equal([3,2], c.quotrem(c2)) assert_equal([-3,2], c.quotrem(-c2)) assert_equal([-3,-2], (-c).quotrem(c2)) assert_equal([3,-2], (-c).quotrem(-c2)) end end =end def test_quo c = Rational(1,2) c2 = Rational(2,3) assert_equal(Rational(3,4), c.quo(c2)) assert_equal(Rational(1,4), c.quo(2)) assert_equal(0.25, c.quo(2.0)) end def test_fdiv c = Rational(1,2) c2 = Rational(2,3) assert_equal(0.75, c.fdiv(c2)) assert_equal(0.25, c.fdiv(2)) assert_equal(0.25, c.fdiv(2.0)) end def test_expt c = Rational(1,2) c2 = Rational(2,3) r = c ** c2 assert_in_delta(0.6299, r, 0.001) assert_equal(Rational(1,4), c ** 2) assert_equal(Rational(4), c ** -2) assert_equal(Rational(1,4), (-c) ** 2) assert_equal(Rational(4), (-c) ** -2) assert_equal(0.25, c ** 2.0) assert_equal(4.0, c ** -2.0) assert_equal(Rational(1,4), c ** Rational(2)) assert_equal(Rational(4), c ** Rational(-2)) assert_equal(Rational(1), 0 ** Rational(0)) assert_equal(Rational(1), Rational(0) ** 0) assert_equal(Rational(1), Rational(0) ** Rational(0)) # p ** p x = 2 ** Rational(2) ## [1.8] Fixnum#coerce tries to convert the other operand to Float. =begin assert_equal(Rational(4), x) unless @unify assert_instance_of(Rational, x) end assert_equal(4, x.numerator) assert_equal(1, x.denominator) =end assert_equal(4.0, x) unless @unify assert_instance_of(Float, x) end x = Rational(2) ** 2 assert_equal(Rational(4), x) unless @unify assert_instance_of(Rational, x) end assert_equal(4, x.numerator) assert_equal(1, x.denominator) x = Rational(2) ** Rational(2) ## [1.8] Rational#** calculates Rational**Rational in Float. =begin assert_equal(Rational(4), x) unless @unify assert_instance_of(Rational, x) end assert_equal(4, x.numerator) assert_equal(1, x.denominator) =end assert_equal(4.0, x) unless @unify assert_instance_of(Float, x) end # -p ** p x = (-2) ** Rational(2) ## [1.8] Fixnum#coerce tries to convert the other operand to Float. =begin assert_equal(Rational(4), x) unless @unify assert_instance_of(Rational, x) end assert_equal(4, x.numerator) assert_equal(1, x.denominator) =end assert_equal(4.0, x) unless @unify assert_instance_of(Float, x) end x = Rational(-2) ** 2 assert_equal(Rational(4), x) unless @unify assert_instance_of(Rational, x) end assert_equal(4, x.numerator) assert_equal(1, x.denominator) x = Rational(-2) ** Rational(2) ## [1.8] Rational#** calculates Rational**Rational in Float. =begin assert_equal(Rational(4), x) unless @unify assert_instance_of(Rational, x) end assert_equal(4, x.numerator) assert_equal(1, x.denominator) =end assert_equal(4.0, x) unless @unify assert_instance_of(Float, x) end # p ** -p x = 2 ** Rational(-2) ## [1.8] Fixnum#coerce tries to convert the other operand to Float. =begin assert_equal(Rational(1,4), x) assert_instance_of(Rational, x) assert_equal(1, x.numerator) assert_equal(4, x.denominator) =end assert_equal(0.25, x) assert_instance_of(Float, x) x = Rational(2) ** -2 assert_equal(Rational(1,4), x) assert_instance_of(Rational, x) assert_equal(1, x.numerator) assert_equal(4, x.denominator) x = Rational(2) ** Rational(-2) ## [1.8] Rational#** calculates Rational**Rational in Float. =begin assert_equal(Rational(1,4), x) assert_instance_of(Rational, x) assert_equal(1, x.numerator) assert_equal(4, x.denominator) =end assert_equal(0.25, x) assert_instance_of(Float, x) # -p ** -p x = (-2) ** Rational(-2) ## [1.8] Fixnum#coerce tries to convert the other operand to Float. =begin assert_equal(Rational(1,4), x) assert_instance_of(Rational, x) assert_equal(1, x.numerator) assert_equal(4, x.denominator) =end assert_equal(0.25, x) assert_instance_of(Float, x) x = Rational(-2) ** -2 assert_equal(Rational(1,4), x) assert_instance_of(Rational, x) assert_equal(1, x.numerator) assert_equal(4, x.denominator) x = Rational(-2) ** Rational(-2) ## [1.8] Rational#** calculates Rational**Rational in Float. =begin assert_equal(Rational(1,4), x) assert_instance_of(Rational, x) assert_equal(1, x.numerator) assert_equal(4, x.denominator) =end assert_equal(0.25, x) assert_instance_of(Float, x) unless @unify # maybe bug mathn ## [1.8] returns Infinity =begin assert_raise(ZeroDivisionError){0 ** -1} =end end end def test_cmp assert_equal(-1, Rational(-1) <=> Rational(0)) assert_equal(0, Rational(0) <=> Rational(0)) assert_equal(+1, Rational(+1) <=> Rational(0)) assert_equal(-1, Rational(-1) <=> 0) assert_equal(0, Rational(0) <=> 0) assert_equal(+1, Rational(+1) <=> 0) assert_equal(-1, Rational(-1) <=> 0.0) assert_equal(0, Rational(0) <=> 0.0) assert_equal(+1, Rational(+1) <=> 0.0) assert_equal(-1, Rational(1,2) <=> Rational(2,3)) assert_equal(0, Rational(2,3) <=> Rational(2,3)) assert_equal(+1, Rational(2,3) <=> Rational(1,2)) f = 2**30-1 b = 2**30 assert_equal(0, Rational(f) <=> Rational(f)) assert_equal(-1, Rational(f) <=> Rational(b)) assert_equal(+1, Rational(b) <=> Rational(f)) assert_equal(0, Rational(b) <=> Rational(b)) assert_equal(-1, Rational(f-1) <=> Rational(f)) assert_equal(+1, Rational(f) <=> Rational(f-1)) assert_equal(-1, Rational(b-1) <=> Rational(b)) assert_equal(+1, Rational(b) <=> Rational(b-1)) assert_equal(false, Rational(0) < Rational(0)) assert_equal(true, Rational(0) <= Rational(0)) assert_equal(true, Rational(0) >= Rational(0)) assert_equal(false, Rational(0) > Rational(0)) assert_equal(nil, Rational(0) <=> nil) assert_equal(nil, Rational(0) <=> 'foo') end def test_eqeq assert(Rational(1,1) == Rational(1)) assert(Rational(-1,1) == Rational(-1)) assert_equal(false, Rational(2,1) == Rational(1)) assert_equal(true, Rational(2,1) != Rational(1)) assert_equal(false, Rational(1) == nil) assert_equal(false, Rational(1) == '') end def test_coerce assert_equal([Rational(2),Rational(1)], Rational(1).coerce(2)) ## [1.8] Rational coerces itself to Float =begin assert_equal([Rational(2.2),Rational(1)], Rational(1).coerce(2.2)) =end assert_equal([2.2,1.0], Rational(1).coerce(2.2)) assert_equal([Rational(2),Rational(1)], Rational(1).coerce(Rational(2))) end def test_unify if @unify assert_instance_of(Fixnum, Rational(1,2) + Rational(1,2)) assert_instance_of(Fixnum, Rational(1,2) - Rational(1,2)) assert_instance_of(Fixnum, Rational(1,2) * 2) assert_instance_of(Fixnum, Rational(1,2) / Rational(1,2)) assert_instance_of(Fixnum, Rational(1,2).div(Rational(1,2))) assert_instance_of(Fixnum, Rational(1,2).quo(Rational(1,2))) assert_instance_of(Fixnum, Rational(1,2) ** -2) end end def test_math assert_equal(Rational(1,2), Rational(1,2).abs) assert_equal(Rational(1,2), Rational(-1,2).abs) if @complex && !@keiju assert_equal(Rational(1,2), Rational(1,2).magnitude) assert_equal(Rational(1,2), Rational(-1,2).magnitude) end assert_equal(1, Rational(1,2).numerator) assert_equal(2, Rational(1,2).denominator) end def test_trunc [[Rational(13, 5), [ 2, 3, 2, 3]], # 2.6 [Rational(5, 2), [ 2, 3, 2, 3]], # 2.5 [Rational(12, 5), [ 2, 3, 2, 2]], # 2.4 [Rational(-12,5), [-3, -2, -2, -2]], # -2.4 [Rational(-5, 2), [-3, -2, -2, -3]], # -2.5 [Rational(-13, 5), [-3, -2, -2, -3]], # -2.6 ].each do |i, a| assert_equal(a[0], i.floor) assert_equal(a[1], i.ceil) assert_equal(a[2], i.truncate) assert_equal(a[3], i.round) end end def test_to_s c = Rational(1,2) assert_instance_of(String, c.to_s) assert_equal('1/2', c.to_s) if @unify assert_equal('0', Rational(0,2).to_s) assert_equal('0', Rational(0,-2).to_s) else ## [1.8] Float#to_r is missing =begin assert_equal('0/1', Rational(0,2).to_s) assert_equal('0/1', Rational(0,-2).to_s) =end assert_equal('0', Rational(0,2).to_s) assert_equal('0', Rational(0,-2).to_s) end assert_equal('1/2', Rational(1,2).to_s) assert_equal('-1/2', Rational(-1,2).to_s) assert_equal('1/2', Rational(-1,-2).to_s) assert_equal('-1/2', Rational(1,-2).to_s) assert_equal('1/2', Rational(-1,-2).to_s) end def test_inspect c = Rational(1,2) assert_instance_of(String, c.inspect) ## [1.8] Format changed in 1.9 =begin assert_equal('(1/2)', c.inspect) =end assert_equal('Rational(1, 2)', c.inspect) end def test_marshal c = Rational(1,2) c.instance_eval{@ivar = 9} s = Marshal.dump(c) c2 = Marshal.load(s) assert_equal(c, c2) assert_equal(9, c2.instance_variable_get(:@ivar)) assert_instance_of(Rational, c2) ## [1.8] No support (yet) for the marshal format of Rational in 1.9 =begin assert_raise(ZeroDivisionError){ Marshal.load("\x04\bU:\rRational[\ai\x06i\x05") } =end end ## [1.8] String#to_r is missing =begin def test_parse assert_equal(Rational(5), '5'.to_r) assert_equal(Rational(-5), '-5'.to_r) assert_equal(Rational(5,3), '5/3'.to_r) assert_equal(Rational(-5,3), '-5/3'.to_r) # assert_equal(Rational(5,-3), '5/-3'.to_r) # assert_equal(Rational(-5,-3), '-5/-3'.to_r) assert_equal(Rational(5), '5.0'.to_r) assert_equal(Rational(-5), '-5.0'.to_r) assert_equal(Rational(5,3), '5.0/3'.to_r) assert_equal(Rational(-5,3), '-5.0/3'.to_r) # assert_equal(Rational(5,-3), '5.0/-3'.to_r) # assert_equal(Rational(-5,-3), '-5.0/-3'.to_r) assert_equal(Rational(5), '5e0'.to_r) assert_equal(Rational(-5), '-5e0'.to_r) assert_equal(Rational(5,3), '5e0/3'.to_r) assert_equal(Rational(-5,3), '-5e0/3'.to_r) # assert_equal(Rational(5,-3), '5e0/-3'.to_r) # assert_equal(Rational(-5,-3), '-5e0/-3'.to_r) assert_equal(Rational(33,100), '.33'.to_r) assert_equal(Rational(33,100), '0.33'.to_r) assert_equal(Rational(-33,100), '-.33'.to_r) assert_equal(Rational(-33,100), '-0.33'.to_r) assert_equal(Rational(-33,100), '-0.3_3'.to_r) assert_equal(Rational(1,2), '5e-1'.to_r) assert_equal(Rational(50), '5e+1'.to_r) assert_equal(Rational(1,2), '5.0e-1'.to_r) assert_equal(Rational(50), '5.0e+1'.to_r) assert_equal(Rational(50), '5e1'.to_r) assert_equal(Rational(50), '5E1'.to_r) assert_equal(Rational(500), '5e2'.to_r) assert_equal(Rational(5000), '5e3'.to_r) assert_equal(Rational(500000000000), '5e1_1'.to_r) assert_equal(Rational(5), Rational('5')) assert_equal(Rational(-5), Rational('-5')) assert_equal(Rational(5,3), Rational('5/3')) assert_equal(Rational(-5,3), Rational('-5/3')) # assert_equal(Rational(5,-3), Rational('5/-3')) # assert_equal(Rational(-5,-3), Rational('-5/-3')) assert_equal(Rational(5), Rational('5.0')) assert_equal(Rational(-5), Rational('-5.0')) assert_equal(Rational(5,3), Rational('5.0/3')) assert_equal(Rational(-5,3), Rational('-5.0/3')) # assert_equal(Rational(5,-3), Rational('5.0/-3')) # assert_equal(Rational(-5,-3), Rational('-5.0/-3')) assert_equal(Rational(5), Rational('5e0')) assert_equal(Rational(-5), Rational('-5e0')) assert_equal(Rational(5,3), Rational('5e0/3')) assert_equal(Rational(-5,3), Rational('-5e0/3')) # assert_equal(Rational(5,-3), Rational('5e0/-3')) # assert_equal(Rational(-5,-3), Rational('-5e0/-3')) assert_equal(Rational(33,100), Rational('.33')) assert_equal(Rational(33,100), Rational('0.33')) assert_equal(Rational(-33,100), Rational('-.33')) assert_equal(Rational(-33,100), Rational('-0.33')) assert_equal(Rational(-33,100), Rational('-0.3_3')) assert_equal(Rational(1,2), Rational('5e-1')) assert_equal(Rational(50), Rational('5e+1')) assert_equal(Rational(1,2), Rational('5.0e-1')) assert_equal(Rational(50), Rational('5.0e+1')) assert_equal(Rational(50), Rational('5e1')) assert_equal(Rational(50), Rational('5E1')) assert_equal(Rational(500), Rational('5e2')) assert_equal(Rational(5000), Rational('5e3')) assert_equal(Rational(500000000000), Rational('5e1_1')) assert_equal(Rational(0), ''.to_r) assert_equal(Rational(0), ' '.to_r) assert_equal(Rational(5), "\f\n\r\t\v5\0".to_r) assert_equal(Rational(0), '_'.to_r) assert_equal(Rational(0), '_5'.to_r) assert_equal(Rational(5), '5_'.to_r) assert_equal(Rational(5), '5x'.to_r) assert_equal(Rational(5), '5/_3'.to_r) assert_equal(Rational(5,3), '5/3_'.to_r) assert_equal(Rational(5,3), '5/3.3'.to_r) assert_equal(Rational(5,3), '5/3x'.to_r) assert_raise(ArgumentError){ Rational('')} assert_raise(ArgumentError){ Rational('_')} assert_raise(ArgumentError){ Rational("\f\n\r\t\v5\0")} assert_raise(ArgumentError){ Rational('_5')} assert_raise(ArgumentError){ Rational('5_')} assert_raise(ArgumentError){ Rational('5x')} assert_raise(ArgumentError){ Rational('5/_3')} assert_raise(ArgumentError){ Rational('5/3_')} assert_raise(ArgumentError){ Rational('5/3.3')} assert_raise(ArgumentError){ Rational('5/3x')} end =end =begin def test_reciprocal assert_equal(Rational(1,9), Rational(9,1).reciprocal) assert_equal(Rational(9,1), Rational(1,9).reciprocal) assert_equal(Rational(-1,9), Rational(-9,1).reciprocal) assert_equal(Rational(-9,1), Rational(-1,9).reciprocal) assert_equal(Rational(1,9), Rational(9,1).inverse) assert_equal(Rational(9,1), Rational(1,9).inverse) assert_equal(Rational(-1,9), Rational(-9,1).inverse) assert_equal(Rational(-9,1), Rational(-1,9).inverse) end =end def test_to_i assert_equal(1, Rational(3,2).to_i) assert_equal(1, Integer(Rational(3,2))) end def test_to_f assert_equal(1.5, Rational(3,2).to_f) assert_equal(1.5, Float(Rational(3,2))) end def test_to_c if @complex && !@keiju if @unify assert_equal(Rational(3,2), Rational(3,2).to_c) assert_equal(Rational(3,2), Complex(Rational(3,2))) else assert_equal(Complex(Rational(3,2)), Rational(3,2).to_c) assert_equal(Complex(Rational(3,2)), Complex(Rational(3,2))) end end end def test_to_r ## [1.8] Float#to_r is missing =begin c = nil.to_r assert_equal([0,1], [c.numerator, c.denominator]) =end c = 0.to_r assert_equal([0,1], [c.numerator, c.denominator]) c = 1.to_r assert_equal([1,1], [c.numerator, c.denominator]) ## [1.8] Float#to_r is missing =begin c = 1.1.to_r assert_equal([2476979795053773, 2251799813685248], [c.numerator, c.denominator]) =end c = Rational(1,2).to_r assert_equal([1,2], [c.numerator, c.denominator]) if @complex if @keiju assert_raise(NoMethodError){Complex(1,2).to_r} else assert_raise(RangeError){Complex(1,2).to_r} end end ## [1.8] Float#to_r is missing =begin if (0.0/0).nan? assert_raise(FloatDomainError){(0.0/0).to_r} end if (1.0/0).infinite? assert_raise(FloatDomainError){(1.0/0).to_r} end =end end ## [1.8] #rationalize is missing =begin def test_rationalize c = nil.rationalize assert_equal([0,1], [c.numerator, c.denominator]) c = 0.rationalize assert_equal([0,1], [c.numerator, c.denominator]) c = 1.rationalize assert_equal([1,1], [c.numerator, c.denominator]) c = 1.1.rationalize assert_equal([11, 10], [c.numerator, c.denominator]) c = Rational(1,2).rationalize assert_equal([1,2], [c.numerator, c.denominator]) assert_equal(nil.rationalize(Rational(1,10)), Rational(0)) assert_equal(0.rationalize(Rational(1,10)), Rational(0)) assert_equal(10.rationalize(Rational(1,10)), Rational(10)) r = 0.3333 assert_equal(r.rationalize, Rational(3333, 10000)) assert_equal(r.rationalize(Rational(1,10)), Rational(1,3)) assert_equal(r.rationalize(Rational(-1,10)), Rational(1,3)) r = Rational(5404319552844595,18014398509481984) assert_equal(r.rationalize, r) assert_equal(r.rationalize(Rational(1,10)), Rational(1,3)) assert_equal(r.rationalize(Rational(-1,10)), Rational(1,3)) r = -0.3333 assert_equal(r.rationalize, Rational(-3333, 10000)) assert_equal(r.rationalize(Rational(1,10)), Rational(-1,3)) assert_equal(r.rationalize(Rational(-1,10)), Rational(-1,3)) r = Rational(-5404319552844595,18014398509481984) assert_equal(r.rationalize, r) assert_equal(r.rationalize(Rational(1,10)), Rational(-1,3)) assert_equal(r.rationalize(Rational(-1,10)), Rational(-1,3)) if @complex if @keiju else assert_raise(RangeError){Complex(1,2).rationalize} end end if (0.0/0).nan? assert_raise(FloatDomainError){(0.0/0).rationalize} end if (1.0/0).infinite? assert_raise(FloatDomainError){(1.0/0).rationalize} end end =end def test_gcdlcm assert_equal(7, 91.gcd(-49)) assert_equal(5, 5.gcd(0)) assert_equal(5, 0.gcd(5)) assert_equal(70, 14.lcm(35)) assert_equal(0, 5.lcm(0)) assert_equal(0, 0.lcm(5)) assert_equal([5,0], 0.gcdlcm(5)) assert_equal([5,0], 5.gcdlcm(0)) assert_equal(1, 1073741827.gcd(1073741789)) assert_equal(1152921470247108503, 1073741827.lcm(1073741789)) assert_equal(1, 1073741789.gcd(1073741827)) assert_equal(1152921470247108503, 1073741789.lcm(1073741827)) end def test_supp ## [1.8] Numeric#real? is missing =begin assert_equal(true, 1.real?) assert_equal(true, 1.1.real?) =end assert_equal(1, 1.numerator) assert_equal(9, 9.numerator) assert_equal(1, 1.denominator) assert_equal(1, 9.denominator) ## [1.8] Float#to_r is missing =begin assert_equal(1.0, 1.0.numerator) assert_equal(9.0, 9.0.numerator) assert_equal(1.0, 1.0.denominator) assert_equal(1.0, 9.0.denominator) =end =begin assert_equal(Rational(1,9), 9.reciprocal) assert_in_delta(0.1111, 9.0.reciprocal, 0.001) assert_equal(Rational(1,9), 9.inverse) assert_in_delta(0.1111, 9.0.inverse, 0.001) =end assert_equal(Rational(1,2), 1.quo(2)) assert_equal(Rational(5000000000), 10000000000.quo(2)) assert_equal(0.5, 1.0.quo(2)) assert_equal(Rational(1,4), Rational(1,2).quo(2)) assert_equal(0.5, 1.fdiv(2)) assert_equal(5000000000.0, 10000000000.fdiv(2)) assert_equal(0.5, 1.0.fdiv(2)) assert_equal(0.25, Rational(1,2).fdiv(2)) end ## [1.8] Not for me =begin def test_ruby19 assert_raise(NoMethodError){ Rational.new(1) } assert_raise(NoMethodError){ Rational.new!(1) } end =end def test_fixed_bug if @unify assert_instance_of(Fixnum, Rational(1,2) ** 0) # mathn's bug end n = Float::MAX.to_i * 2 ## [1.8] Bug still exists (or is left as "a feature") =begin assert_equal(1.0, Rational(n + 2, n + 1).to_f, '[ruby-dev:33852]') =end end def test_known_bug end end ================================================ FILE: test/rational/test_rational2.rb ================================================ require 'test/unit' require 'rational' class Rational_Test2 < Test::Unit::TestCase def test_kumi assert_equal(Rational(1, 1), +Rational(1, 1)) assert_equal(Rational(-1, 1), -Rational(1, 1)) assert_equal(Rational(2, 1), Rational(1, 1) + Rational(1, 1)) assert_equal(Rational(0, 1), Rational(1, 1) - Rational(1, 1)) assert_equal(Rational(1, 1), Rational(1, 1) * Rational(1, 1)) assert_equal(Rational(1, 1), Rational(1, 1) / Rational(1, 1)) assert_equal(Rational(3, 1), Rational(1, 1) + Rational(2, 1)) assert_equal(Rational(-1, 1), Rational(1, 1) - Rational(2, 1)) assert_equal(Rational(2, 1), Rational(1, 1) * Rational(2, 1)) assert_equal(Rational(1, 2), Rational(1, 1) / Rational(2, 1)) assert_equal(Rational(4, 1), Rational(1, 1) + Rational(3, 1)) assert_equal(Rational(-2, 1), Rational(1, 1) - Rational(3, 1)) assert_equal(Rational(3, 1), Rational(1, 1) * Rational(3, 1)) assert_equal(Rational(1, 3), Rational(1, 1) / Rational(3, 1)) assert_equal(Rational(1073741790, 1), Rational(1, 1) + Rational(1073741789, 1)) assert_equal(Rational(-1073741788, 1), Rational(1, 1) - Rational(1073741789, 1)) assert_equal(Rational(1073741789, 1), Rational(1, 1) * Rational(1073741789, 1)) assert_equal(Rational(1, 1073741789), Rational(1, 1) / Rational(1073741789, 1)) assert_equal(Rational(1073741828, 1), Rational(1, 1) + Rational(1073741827, 1)) assert_equal(Rational(-1073741826, 1), Rational(1, 1) - Rational(1073741827, 1)) assert_equal(Rational(1073741827, 1), Rational(1, 1) * Rational(1073741827, 1)) assert_equal(Rational(1, 1073741827), Rational(1, 1) / Rational(1073741827, 1)) assert_equal(Rational(5, 3), Rational(1, 1) + Rational(2, 3)) assert_equal(Rational(1, 3), Rational(1, 1) - Rational(2, 3)) assert_equal(Rational(2, 3), Rational(1, 1) * Rational(2, 3)) assert_equal(Rational(3, 2), Rational(1, 1) / Rational(2, 3)) assert_equal(Rational(5, 2), Rational(1, 1) + Rational(3, 2)) assert_equal(Rational(-1, 2), Rational(1, 1) - Rational(3, 2)) assert_equal(Rational(3, 2), Rational(1, 1) * Rational(3, 2)) assert_equal(Rational(2, 3), Rational(1, 1) / Rational(3, 2)) assert_equal(Rational(1073741792, 1073741789), Rational(1, 1) + Rational(3, 1073741789)) assert_equal(Rational(1073741786, 1073741789), Rational(1, 1) - Rational(3, 1073741789)) assert_equal(Rational(3, 1073741789), Rational(1, 1) * Rational(3, 1073741789)) assert_equal(Rational(1073741789, 3), Rational(1, 1) / Rational(3, 1073741789)) assert_equal(Rational(1073741792, 3), Rational(1, 1) + Rational(1073741789, 3)) assert_equal(Rational(-1073741786, 3), Rational(1, 1) - Rational(1073741789, 3)) assert_equal(Rational(1073741789, 3), Rational(1, 1) * Rational(1073741789, 3)) assert_equal(Rational(3, 1073741789), Rational(1, 1) / Rational(1073741789, 3)) assert_equal(Rational(1073741830, 1073741827), Rational(1, 1) + Rational(3, 1073741827)) assert_equal(Rational(1073741824, 1073741827), Rational(1, 1) - Rational(3, 1073741827)) assert_equal(Rational(3, 1073741827), Rational(1, 1) * Rational(3, 1073741827)) assert_equal(Rational(1073741827, 3), Rational(1, 1) / Rational(3, 1073741827)) assert_equal(Rational(1073741830, 3), Rational(1, 1) + Rational(1073741827, 3)) assert_equal(Rational(-1073741824, 3), Rational(1, 1) - Rational(1073741827, 3)) assert_equal(Rational(1073741827, 3), Rational(1, 1) * Rational(1073741827, 3)) assert_equal(Rational(3, 1073741827), Rational(1, 1) / Rational(1073741827, 3)) assert_equal(Rational(2147483616, 1073741827), Rational(1, 1) + Rational(1073741789, 1073741827)) assert_equal(Rational(38, 1073741827), Rational(1, 1) - Rational(1073741789, 1073741827)) assert_equal(Rational(1073741789, 1073741827), Rational(1, 1) * Rational(1073741789, 1073741827)) assert_equal(Rational(1073741827, 1073741789), Rational(1, 1) / Rational(1073741789, 1073741827)) assert_equal(Rational(2147483616, 1073741789), Rational(1, 1) + Rational(1073741827, 1073741789)) assert_equal(Rational(-38, 1073741789), Rational(1, 1) - Rational(1073741827, 1073741789)) assert_equal(Rational(1073741827, 1073741789), Rational(1, 1) * Rational(1073741827, 1073741789)) assert_equal(Rational(1073741789, 1073741827), Rational(1, 1) / Rational(1073741827, 1073741789)) assert_equal(Rational(2, 1), +Rational(2, 1)) assert_equal(Rational(-2, 1), -Rational(2, 1)) assert_equal(Rational(3, 1), Rational(2, 1) + Rational(1, 1)) assert_equal(Rational(1, 1), Rational(2, 1) - Rational(1, 1)) assert_equal(Rational(2, 1), Rational(2, 1) * Rational(1, 1)) assert_equal(Rational(2, 1), Rational(2, 1) / Rational(1, 1)) assert_equal(Rational(4, 1), Rational(2, 1) + Rational(2, 1)) assert_equal(Rational(0, 1), Rational(2, 1) - Rational(2, 1)) assert_equal(Rational(4, 1), Rational(2, 1) * Rational(2, 1)) assert_equal(Rational(1, 1), Rational(2, 1) / Rational(2, 1)) assert_equal(Rational(5, 1), Rational(2, 1) + Rational(3, 1)) assert_equal(Rational(-1, 1), Rational(2, 1) - Rational(3, 1)) assert_equal(Rational(6, 1), Rational(2, 1) * Rational(3, 1)) assert_equal(Rational(2, 3), Rational(2, 1) / Rational(3, 1)) assert_equal(Rational(1073741791, 1), Rational(2, 1) + Rational(1073741789, 1)) assert_equal(Rational(-1073741787, 1), Rational(2, 1) - Rational(1073741789, 1)) assert_equal(Rational(2147483578, 1), Rational(2, 1) * Rational(1073741789, 1)) assert_equal(Rational(2, 1073741789), Rational(2, 1) / Rational(1073741789, 1)) assert_equal(Rational(1073741829, 1), Rational(2, 1) + Rational(1073741827, 1)) assert_equal(Rational(-1073741825, 1), Rational(2, 1) - Rational(1073741827, 1)) assert_equal(Rational(2147483654, 1), Rational(2, 1) * Rational(1073741827, 1)) assert_equal(Rational(2, 1073741827), Rational(2, 1) / Rational(1073741827, 1)) assert_equal(Rational(8, 3), Rational(2, 1) + Rational(2, 3)) assert_equal(Rational(4, 3), Rational(2, 1) - Rational(2, 3)) assert_equal(Rational(4, 3), Rational(2, 1) * Rational(2, 3)) assert_equal(Rational(3, 1), Rational(2, 1) / Rational(2, 3)) assert_equal(Rational(7, 2), Rational(2, 1) + Rational(3, 2)) assert_equal(Rational(1, 2), Rational(2, 1) - Rational(3, 2)) assert_equal(Rational(3, 1), Rational(2, 1) * Rational(3, 2)) assert_equal(Rational(4, 3), Rational(2, 1) / Rational(3, 2)) assert_equal(Rational(2147483581, 1073741789), Rational(2, 1) + Rational(3, 1073741789)) assert_equal(Rational(2147483575, 1073741789), Rational(2, 1) - Rational(3, 1073741789)) assert_equal(Rational(6, 1073741789), Rational(2, 1) * Rational(3, 1073741789)) assert_equal(Rational(2147483578, 3), Rational(2, 1) / Rational(3, 1073741789)) assert_equal(Rational(1073741795, 3), Rational(2, 1) + Rational(1073741789, 3)) assert_equal(Rational(-1073741783, 3), Rational(2, 1) - Rational(1073741789, 3)) assert_equal(Rational(2147483578, 3), Rational(2, 1) * Rational(1073741789, 3)) assert_equal(Rational(6, 1073741789), Rational(2, 1) / Rational(1073741789, 3)) assert_equal(Rational(2147483657, 1073741827), Rational(2, 1) + Rational(3, 1073741827)) assert_equal(Rational(2147483651, 1073741827), Rational(2, 1) - Rational(3, 1073741827)) assert_equal(Rational(6, 1073741827), Rational(2, 1) * Rational(3, 1073741827)) assert_equal(Rational(2147483654, 3), Rational(2, 1) / Rational(3, 1073741827)) assert_equal(Rational(1073741833, 3), Rational(2, 1) + Rational(1073741827, 3)) assert_equal(Rational(-1073741821, 3), Rational(2, 1) - Rational(1073741827, 3)) assert_equal(Rational(2147483654, 3), Rational(2, 1) * Rational(1073741827, 3)) assert_equal(Rational(6, 1073741827), Rational(2, 1) / Rational(1073741827, 3)) assert_equal(Rational(3221225443, 1073741827), Rational(2, 1) + Rational(1073741789, 1073741827)) assert_equal(Rational(1073741865, 1073741827), Rational(2, 1) - Rational(1073741789, 1073741827)) assert_equal(Rational(2147483578, 1073741827), Rational(2, 1) * Rational(1073741789, 1073741827)) assert_equal(Rational(2147483654, 1073741789), Rational(2, 1) / Rational(1073741789, 1073741827)) assert_equal(Rational(3221225405, 1073741789), Rational(2, 1) + Rational(1073741827, 1073741789)) assert_equal(Rational(1073741751, 1073741789), Rational(2, 1) - Rational(1073741827, 1073741789)) assert_equal(Rational(2147483654, 1073741789), Rational(2, 1) * Rational(1073741827, 1073741789)) assert_equal(Rational(2147483578, 1073741827), Rational(2, 1) / Rational(1073741827, 1073741789)) assert_equal(Rational(3, 1), +Rational(3, 1)) assert_equal(Rational(-3, 1), -Rational(3, 1)) assert_equal(Rational(4, 1), Rational(3, 1) + Rational(1, 1)) assert_equal(Rational(2, 1), Rational(3, 1) - Rational(1, 1)) assert_equal(Rational(3, 1), Rational(3, 1) * Rational(1, 1)) assert_equal(Rational(3, 1), Rational(3, 1) / Rational(1, 1)) assert_equal(Rational(5, 1), Rational(3, 1) + Rational(2, 1)) assert_equal(Rational(1, 1), Rational(3, 1) - Rational(2, 1)) assert_equal(Rational(6, 1), Rational(3, 1) * Rational(2, 1)) assert_equal(Rational(3, 2), Rational(3, 1) / Rational(2, 1)) assert_equal(Rational(6, 1), Rational(3, 1) + Rational(3, 1)) assert_equal(Rational(0, 1), Rational(3, 1) - Rational(3, 1)) assert_equal(Rational(9, 1), Rational(3, 1) * Rational(3, 1)) assert_equal(Rational(1, 1), Rational(3, 1) / Rational(3, 1)) assert_equal(Rational(1073741792, 1), Rational(3, 1) + Rational(1073741789, 1)) assert_equal(Rational(-1073741786, 1), Rational(3, 1) - Rational(1073741789, 1)) assert_equal(Rational(3221225367, 1), Rational(3, 1) * Rational(1073741789, 1)) assert_equal(Rational(3, 1073741789), Rational(3, 1) / Rational(1073741789, 1)) assert_equal(Rational(1073741830, 1), Rational(3, 1) + Rational(1073741827, 1)) assert_equal(Rational(-1073741824, 1), Rational(3, 1) - Rational(1073741827, 1)) assert_equal(Rational(3221225481, 1), Rational(3, 1) * Rational(1073741827, 1)) assert_equal(Rational(3, 1073741827), Rational(3, 1) / Rational(1073741827, 1)) assert_equal(Rational(11, 3), Rational(3, 1) + Rational(2, 3)) assert_equal(Rational(7, 3), Rational(3, 1) - Rational(2, 3)) assert_equal(Rational(2, 1), Rational(3, 1) * Rational(2, 3)) assert_equal(Rational(9, 2), Rational(3, 1) / Rational(2, 3)) assert_equal(Rational(9, 2), Rational(3, 1) + Rational(3, 2)) assert_equal(Rational(3, 2), Rational(3, 1) - Rational(3, 2)) assert_equal(Rational(9, 2), Rational(3, 1) * Rational(3, 2)) assert_equal(Rational(2, 1), Rational(3, 1) / Rational(3, 2)) assert_equal(Rational(3221225370, 1073741789), Rational(3, 1) + Rational(3, 1073741789)) assert_equal(Rational(3221225364, 1073741789), Rational(3, 1) - Rational(3, 1073741789)) assert_equal(Rational(9, 1073741789), Rational(3, 1) * Rational(3, 1073741789)) assert_equal(Rational(1073741789, 1), Rational(3, 1) / Rational(3, 1073741789)) assert_equal(Rational(1073741798, 3), Rational(3, 1) + Rational(1073741789, 3)) assert_equal(Rational(-1073741780, 3), Rational(3, 1) - Rational(1073741789, 3)) assert_equal(Rational(1073741789, 1), Rational(3, 1) * Rational(1073741789, 3)) assert_equal(Rational(9, 1073741789), Rational(3, 1) / Rational(1073741789, 3)) assert_equal(Rational(3221225484, 1073741827), Rational(3, 1) + Rational(3, 1073741827)) assert_equal(Rational(3221225478, 1073741827), Rational(3, 1) - Rational(3, 1073741827)) assert_equal(Rational(9, 1073741827), Rational(3, 1) * Rational(3, 1073741827)) assert_equal(Rational(1073741827, 1), Rational(3, 1) / Rational(3, 1073741827)) assert_equal(Rational(1073741836, 3), Rational(3, 1) + Rational(1073741827, 3)) assert_equal(Rational(-1073741818, 3), Rational(3, 1) - Rational(1073741827, 3)) assert_equal(Rational(1073741827, 1), Rational(3, 1) * Rational(1073741827, 3)) assert_equal(Rational(9, 1073741827), Rational(3, 1) / Rational(1073741827, 3)) assert_equal(Rational(4294967270, 1073741827), Rational(3, 1) + Rational(1073741789, 1073741827)) assert_equal(Rational(2147483692, 1073741827), Rational(3, 1) - Rational(1073741789, 1073741827)) assert_equal(Rational(3221225367, 1073741827), Rational(3, 1) * Rational(1073741789, 1073741827)) assert_equal(Rational(3221225481, 1073741789), Rational(3, 1) / Rational(1073741789, 1073741827)) assert_equal(Rational(4294967194, 1073741789), Rational(3, 1) + Rational(1073741827, 1073741789)) assert_equal(Rational(2147483540, 1073741789), Rational(3, 1) - Rational(1073741827, 1073741789)) assert_equal(Rational(3221225481, 1073741789), Rational(3, 1) * Rational(1073741827, 1073741789)) assert_equal(Rational(3221225367, 1073741827), Rational(3, 1) / Rational(1073741827, 1073741789)) assert_equal(Rational(1073741789, 1), +Rational(1073741789, 1)) assert_equal(Rational(-1073741789, 1), -Rational(1073741789, 1)) assert_equal(Rational(1073741790, 1), Rational(1073741789, 1) + Rational(1, 1)) assert_equal(Rational(1073741788, 1), Rational(1073741789, 1) - Rational(1, 1)) assert_equal(Rational(1073741789, 1), Rational(1073741789, 1) * Rational(1, 1)) assert_equal(Rational(1073741789, 1), Rational(1073741789, 1) / Rational(1, 1)) assert_equal(Rational(1073741791, 1), Rational(1073741789, 1) + Rational(2, 1)) assert_equal(Rational(1073741787, 1), Rational(1073741789, 1) - Rational(2, 1)) assert_equal(Rational(2147483578, 1), Rational(1073741789, 1) * Rational(2, 1)) assert_equal(Rational(1073741789, 2), Rational(1073741789, 1) / Rational(2, 1)) assert_equal(Rational(1073741792, 1), Rational(1073741789, 1) + Rational(3, 1)) assert_equal(Rational(1073741786, 1), Rational(1073741789, 1) - Rational(3, 1)) assert_equal(Rational(3221225367, 1), Rational(1073741789, 1) * Rational(3, 1)) assert_equal(Rational(1073741789, 3), Rational(1073741789, 1) / Rational(3, 1)) assert_equal(Rational(2147483578, 1), Rational(1073741789, 1) + Rational(1073741789, 1)) assert_equal(Rational(0, 1), Rational(1073741789, 1) - Rational(1073741789, 1)) assert_equal(Rational(1152921429444920521, 1), Rational(1073741789, 1) * Rational(1073741789, 1)) assert_equal(Rational(1, 1), Rational(1073741789, 1) / Rational(1073741789, 1)) assert_equal(Rational(2147483616, 1), Rational(1073741789, 1) + Rational(1073741827, 1)) assert_equal(Rational(-38, 1), Rational(1073741789, 1) - Rational(1073741827, 1)) assert_equal(Rational(1152921470247108503, 1), Rational(1073741789, 1) * Rational(1073741827, 1)) assert_equal(Rational(1073741789, 1073741827), Rational(1073741789, 1) / Rational(1073741827, 1)) assert_equal(Rational(3221225369, 3), Rational(1073741789, 1) + Rational(2, 3)) assert_equal(Rational(3221225365, 3), Rational(1073741789, 1) - Rational(2, 3)) assert_equal(Rational(2147483578, 3), Rational(1073741789, 1) * Rational(2, 3)) assert_equal(Rational(3221225367, 2), Rational(1073741789, 1) / Rational(2, 3)) assert_equal(Rational(2147483581, 2), Rational(1073741789, 1) + Rational(3, 2)) assert_equal(Rational(2147483575, 2), Rational(1073741789, 1) - Rational(3, 2)) assert_equal(Rational(3221225367, 2), Rational(1073741789, 1) * Rational(3, 2)) assert_equal(Rational(2147483578, 3), Rational(1073741789, 1) / Rational(3, 2)) assert_equal(Rational(1152921429444920524, 1073741789), Rational(1073741789, 1) + Rational(3, 1073741789)) assert_equal(Rational(1152921429444920518, 1073741789), Rational(1073741789, 1) - Rational(3, 1073741789)) assert_equal(Rational(3, 1), Rational(1073741789, 1) * Rational(3, 1073741789)) assert_equal(Rational(1152921429444920521, 3), Rational(1073741789, 1) / Rational(3, 1073741789)) assert_equal(Rational(4294967156, 3), Rational(1073741789, 1) + Rational(1073741789, 3)) assert_equal(Rational(2147483578, 3), Rational(1073741789, 1) - Rational(1073741789, 3)) assert_equal(Rational(1152921429444920521, 3), Rational(1073741789, 1) * Rational(1073741789, 3)) assert_equal(Rational(3, 1), Rational(1073741789, 1) / Rational(1073741789, 3)) assert_equal(Rational(1152921470247108506, 1073741827), Rational(1073741789, 1) + Rational(3, 1073741827)) assert_equal(Rational(1152921470247108500, 1073741827), Rational(1073741789, 1) - Rational(3, 1073741827)) assert_equal(Rational(3221225367, 1073741827), Rational(1073741789, 1) * Rational(3, 1073741827)) assert_equal(Rational(1152921470247108503, 3), Rational(1073741789, 1) / Rational(3, 1073741827)) assert_equal(Rational(4294967194, 3), Rational(1073741789, 1) + Rational(1073741827, 3)) assert_equal(Rational(2147483540, 3), Rational(1073741789, 1) - Rational(1073741827, 3)) assert_equal(Rational(1152921470247108503, 3), Rational(1073741789, 1) * Rational(1073741827, 3)) assert_equal(Rational(3221225367, 1073741827), Rational(1073741789, 1) / Rational(1073741827, 3)) assert_equal(Rational(1152921471320850292, 1073741827), Rational(1073741789, 1) + Rational(1073741789, 1073741827)) assert_equal(Rational(1152921469173366714, 1073741827), Rational(1073741789, 1) - Rational(1073741789, 1073741827)) assert_equal(Rational(1152921429444920521, 1073741827), Rational(1073741789, 1) * Rational(1073741789, 1073741827)) assert_equal(Rational(1073741827, 1), Rational(1073741789, 1) / Rational(1073741789, 1073741827)) assert_equal(Rational(1152921430518662348, 1073741789), Rational(1073741789, 1) + Rational(1073741827, 1073741789)) assert_equal(Rational(1152921428371178694, 1073741789), Rational(1073741789, 1) - Rational(1073741827, 1073741789)) assert_equal(Rational(1073741827, 1), Rational(1073741789, 1) * Rational(1073741827, 1073741789)) assert_equal(Rational(1152921429444920521, 1073741827), Rational(1073741789, 1) / Rational(1073741827, 1073741789)) assert_equal(Rational(1073741827, 1), +Rational(1073741827, 1)) assert_equal(Rational(-1073741827, 1), -Rational(1073741827, 1)) assert_equal(Rational(1073741828, 1), Rational(1073741827, 1) + Rational(1, 1)) assert_equal(Rational(1073741826, 1), Rational(1073741827, 1) - Rational(1, 1)) assert_equal(Rational(1073741827, 1), Rational(1073741827, 1) * Rational(1, 1)) assert_equal(Rational(1073741827, 1), Rational(1073741827, 1) / Rational(1, 1)) assert_equal(Rational(1073741829, 1), Rational(1073741827, 1) + Rational(2, 1)) assert_equal(Rational(1073741825, 1), Rational(1073741827, 1) - Rational(2, 1)) assert_equal(Rational(2147483654, 1), Rational(1073741827, 1) * Rational(2, 1)) assert_equal(Rational(1073741827, 2), Rational(1073741827, 1) / Rational(2, 1)) assert_equal(Rational(1073741830, 1), Rational(1073741827, 1) + Rational(3, 1)) assert_equal(Rational(1073741824, 1), Rational(1073741827, 1) - Rational(3, 1)) assert_equal(Rational(3221225481, 1), Rational(1073741827, 1) * Rational(3, 1)) assert_equal(Rational(1073741827, 3), Rational(1073741827, 1) / Rational(3, 1)) assert_equal(Rational(2147483616, 1), Rational(1073741827, 1) + Rational(1073741789, 1)) assert_equal(Rational(38, 1), Rational(1073741827, 1) - Rational(1073741789, 1)) assert_equal(Rational(1152921470247108503, 1), Rational(1073741827, 1) * Rational(1073741789, 1)) assert_equal(Rational(1073741827, 1073741789), Rational(1073741827, 1) / Rational(1073741789, 1)) assert_equal(Rational(2147483654, 1), Rational(1073741827, 1) + Rational(1073741827, 1)) assert_equal(Rational(0, 1), Rational(1073741827, 1) - Rational(1073741827, 1)) assert_equal(Rational(1152921511049297929, 1), Rational(1073741827, 1) * Rational(1073741827, 1)) assert_equal(Rational(1, 1), Rational(1073741827, 1) / Rational(1073741827, 1)) assert_equal(Rational(3221225483, 3), Rational(1073741827, 1) + Rational(2, 3)) assert_equal(Rational(3221225479, 3), Rational(1073741827, 1) - Rational(2, 3)) assert_equal(Rational(2147483654, 3), Rational(1073741827, 1) * Rational(2, 3)) assert_equal(Rational(3221225481, 2), Rational(1073741827, 1) / Rational(2, 3)) assert_equal(Rational(2147483657, 2), Rational(1073741827, 1) + Rational(3, 2)) assert_equal(Rational(2147483651, 2), Rational(1073741827, 1) - Rational(3, 2)) assert_equal(Rational(3221225481, 2), Rational(1073741827, 1) * Rational(3, 2)) assert_equal(Rational(2147483654, 3), Rational(1073741827, 1) / Rational(3, 2)) assert_equal(Rational(1152921470247108506, 1073741789), Rational(1073741827, 1) + Rational(3, 1073741789)) assert_equal(Rational(1152921470247108500, 1073741789), Rational(1073741827, 1) - Rational(3, 1073741789)) assert_equal(Rational(3221225481, 1073741789), Rational(1073741827, 1) * Rational(3, 1073741789)) assert_equal(Rational(1152921470247108503, 3), Rational(1073741827, 1) / Rational(3, 1073741789)) assert_equal(Rational(4294967270, 3), Rational(1073741827, 1) + Rational(1073741789, 3)) assert_equal(Rational(2147483692, 3), Rational(1073741827, 1) - Rational(1073741789, 3)) assert_equal(Rational(1152921470247108503, 3), Rational(1073741827, 1) * Rational(1073741789, 3)) assert_equal(Rational(3221225481, 1073741789), Rational(1073741827, 1) / Rational(1073741789, 3)) assert_equal(Rational(1152921511049297932, 1073741827), Rational(1073741827, 1) + Rational(3, 1073741827)) assert_equal(Rational(1152921511049297926, 1073741827), Rational(1073741827, 1) - Rational(3, 1073741827)) assert_equal(Rational(3, 1), Rational(1073741827, 1) * Rational(3, 1073741827)) assert_equal(Rational(1152921511049297929, 3), Rational(1073741827, 1) / Rational(3, 1073741827)) assert_equal(Rational(4294967308, 3), Rational(1073741827, 1) + Rational(1073741827, 3)) assert_equal(Rational(2147483654, 3), Rational(1073741827, 1) - Rational(1073741827, 3)) assert_equal(Rational(1152921511049297929, 3), Rational(1073741827, 1) * Rational(1073741827, 3)) assert_equal(Rational(3, 1), Rational(1073741827, 1) / Rational(1073741827, 3)) assert_equal(Rational(1152921512123039718, 1073741827), Rational(1073741827, 1) + Rational(1073741789, 1073741827)) assert_equal(Rational(1152921509975556140, 1073741827), Rational(1073741827, 1) - Rational(1073741789, 1073741827)) assert_equal(Rational(1073741789, 1), Rational(1073741827, 1) * Rational(1073741789, 1073741827)) assert_equal(Rational(1152921511049297929, 1073741789), Rational(1073741827, 1) / Rational(1073741789, 1073741827)) assert_equal(Rational(1152921471320850330, 1073741789), Rational(1073741827, 1) + Rational(1073741827, 1073741789)) assert_equal(Rational(1152921469173366676, 1073741789), Rational(1073741827, 1) - Rational(1073741827, 1073741789)) assert_equal(Rational(1152921511049297929, 1073741789), Rational(1073741827, 1) * Rational(1073741827, 1073741789)) assert_equal(Rational(1073741789, 1), Rational(1073741827, 1) / Rational(1073741827, 1073741789)) assert_equal(Rational(2, 3), +Rational(2, 3)) assert_equal(Rational(-2, 3), -Rational(2, 3)) assert_equal(Rational(5, 3), Rational(2, 3) + Rational(1, 1)) assert_equal(Rational(-1, 3), Rational(2, 3) - Rational(1, 1)) assert_equal(Rational(2, 3), Rational(2, 3) * Rational(1, 1)) assert_equal(Rational(2, 3), Rational(2, 3) / Rational(1, 1)) assert_equal(Rational(8, 3), Rational(2, 3) + Rational(2, 1)) assert_equal(Rational(-4, 3), Rational(2, 3) - Rational(2, 1)) assert_equal(Rational(4, 3), Rational(2, 3) * Rational(2, 1)) assert_equal(Rational(1, 3), Rational(2, 3) / Rational(2, 1)) assert_equal(Rational(11, 3), Rational(2, 3) + Rational(3, 1)) assert_equal(Rational(-7, 3), Rational(2, 3) - Rational(3, 1)) assert_equal(Rational(2, 1), Rational(2, 3) * Rational(3, 1)) assert_equal(Rational(2, 9), Rational(2, 3) / Rational(3, 1)) assert_equal(Rational(3221225369, 3), Rational(2, 3) + Rational(1073741789, 1)) assert_equal(Rational(-3221225365, 3), Rational(2, 3) - Rational(1073741789, 1)) assert_equal(Rational(2147483578, 3), Rational(2, 3) * Rational(1073741789, 1)) assert_equal(Rational(2, 3221225367), Rational(2, 3) / Rational(1073741789, 1)) assert_equal(Rational(3221225483, 3), Rational(2, 3) + Rational(1073741827, 1)) assert_equal(Rational(-3221225479, 3), Rational(2, 3) - Rational(1073741827, 1)) assert_equal(Rational(2147483654, 3), Rational(2, 3) * Rational(1073741827, 1)) assert_equal(Rational(2, 3221225481), Rational(2, 3) / Rational(1073741827, 1)) assert_equal(Rational(4, 3), Rational(2, 3) + Rational(2, 3)) assert_equal(Rational(0, 1), Rational(2, 3) - Rational(2, 3)) assert_equal(Rational(4, 9), Rational(2, 3) * Rational(2, 3)) assert_equal(Rational(1, 1), Rational(2, 3) / Rational(2, 3)) assert_equal(Rational(13, 6), Rational(2, 3) + Rational(3, 2)) assert_equal(Rational(-5, 6), Rational(2, 3) - Rational(3, 2)) assert_equal(Rational(1, 1), Rational(2, 3) * Rational(3, 2)) assert_equal(Rational(4, 9), Rational(2, 3) / Rational(3, 2)) assert_equal(Rational(2147483587, 3221225367), Rational(2, 3) + Rational(3, 1073741789)) assert_equal(Rational(2147483569, 3221225367), Rational(2, 3) - Rational(3, 1073741789)) assert_equal(Rational(2, 1073741789), Rational(2, 3) * Rational(3, 1073741789)) assert_equal(Rational(2147483578, 9), Rational(2, 3) / Rational(3, 1073741789)) assert_equal(Rational(1073741791, 3), Rational(2, 3) + Rational(1073741789, 3)) assert_equal(Rational(-357913929, 1), Rational(2, 3) - Rational(1073741789, 3)) assert_equal(Rational(2147483578, 9), Rational(2, 3) * Rational(1073741789, 3)) assert_equal(Rational(2, 1073741789), Rational(2, 3) / Rational(1073741789, 3)) assert_equal(Rational(2147483663, 3221225481), Rational(2, 3) + Rational(3, 1073741827)) assert_equal(Rational(2147483645, 3221225481), Rational(2, 3) - Rational(3, 1073741827)) assert_equal(Rational(2, 1073741827), Rational(2, 3) * Rational(3, 1073741827)) assert_equal(Rational(2147483654, 9), Rational(2, 3) / Rational(3, 1073741827)) assert_equal(Rational(357913943, 1), Rational(2, 3) + Rational(1073741827, 3)) assert_equal(Rational(-1073741825, 3), Rational(2, 3) - Rational(1073741827, 3)) assert_equal(Rational(2147483654, 9), Rational(2, 3) * Rational(1073741827, 3)) assert_equal(Rational(2, 1073741827), Rational(2, 3) / Rational(1073741827, 3)) assert_equal(Rational(5368709021, 3221225481), Rational(2, 3) + Rational(1073741789, 1073741827)) assert_equal(Rational(-1073741713, 3221225481), Rational(2, 3) - Rational(1073741789, 1073741827)) assert_equal(Rational(2147483578, 3221225481), Rational(2, 3) * Rational(1073741789, 1073741827)) assert_equal(Rational(2147483654, 3221225367), Rational(2, 3) / Rational(1073741789, 1073741827)) assert_equal(Rational(5368709059, 3221225367), Rational(2, 3) + Rational(1073741827, 1073741789)) assert_equal(Rational(-1073741903, 3221225367), Rational(2, 3) - Rational(1073741827, 1073741789)) assert_equal(Rational(2147483654, 3221225367), Rational(2, 3) * Rational(1073741827, 1073741789)) assert_equal(Rational(2147483578, 3221225481), Rational(2, 3) / Rational(1073741827, 1073741789)) assert_equal(Rational(3, 2), +Rational(3, 2)) assert_equal(Rational(-3, 2), -Rational(3, 2)) assert_equal(Rational(5, 2), Rational(3, 2) + Rational(1, 1)) assert_equal(Rational(1, 2), Rational(3, 2) - Rational(1, 1)) assert_equal(Rational(3, 2), Rational(3, 2) * Rational(1, 1)) assert_equal(Rational(3, 2), Rational(3, 2) / Rational(1, 1)) assert_equal(Rational(7, 2), Rational(3, 2) + Rational(2, 1)) assert_equal(Rational(-1, 2), Rational(3, 2) - Rational(2, 1)) assert_equal(Rational(3, 1), Rational(3, 2) * Rational(2, 1)) assert_equal(Rational(3, 4), Rational(3, 2) / Rational(2, 1)) assert_equal(Rational(9, 2), Rational(3, 2) + Rational(3, 1)) assert_equal(Rational(-3, 2), Rational(3, 2) - Rational(3, 1)) assert_equal(Rational(9, 2), Rational(3, 2) * Rational(3, 1)) assert_equal(Rational(1, 2), Rational(3, 2) / Rational(3, 1)) assert_equal(Rational(2147483581, 2), Rational(3, 2) + Rational(1073741789, 1)) assert_equal(Rational(-2147483575, 2), Rational(3, 2) - Rational(1073741789, 1)) assert_equal(Rational(3221225367, 2), Rational(3, 2) * Rational(1073741789, 1)) assert_equal(Rational(3, 2147483578), Rational(3, 2) / Rational(1073741789, 1)) assert_equal(Rational(2147483657, 2), Rational(3, 2) + Rational(1073741827, 1)) assert_equal(Rational(-2147483651, 2), Rational(3, 2) - Rational(1073741827, 1)) assert_equal(Rational(3221225481, 2), Rational(3, 2) * Rational(1073741827, 1)) assert_equal(Rational(3, 2147483654), Rational(3, 2) / Rational(1073741827, 1)) assert_equal(Rational(13, 6), Rational(3, 2) + Rational(2, 3)) assert_equal(Rational(5, 6), Rational(3, 2) - Rational(2, 3)) assert_equal(Rational(1, 1), Rational(3, 2) * Rational(2, 3)) assert_equal(Rational(9, 4), Rational(3, 2) / Rational(2, 3)) assert_equal(Rational(3, 1), Rational(3, 2) + Rational(3, 2)) assert_equal(Rational(0, 1), Rational(3, 2) - Rational(3, 2)) assert_equal(Rational(9, 4), Rational(3, 2) * Rational(3, 2)) assert_equal(Rational(1, 1), Rational(3, 2) / Rational(3, 2)) assert_equal(Rational(3221225373, 2147483578), Rational(3, 2) + Rational(3, 1073741789)) assert_equal(Rational(3221225361, 2147483578), Rational(3, 2) - Rational(3, 1073741789)) assert_equal(Rational(9, 2147483578), Rational(3, 2) * Rational(3, 1073741789)) assert_equal(Rational(1073741789, 2), Rational(3, 2) / Rational(3, 1073741789)) assert_equal(Rational(2147483587, 6), Rational(3, 2) + Rational(1073741789, 3)) assert_equal(Rational(-2147483569, 6), Rational(3, 2) - Rational(1073741789, 3)) assert_equal(Rational(1073741789, 2), Rational(3, 2) * Rational(1073741789, 3)) assert_equal(Rational(9, 2147483578), Rational(3, 2) / Rational(1073741789, 3)) assert_equal(Rational(3221225487, 2147483654), Rational(3, 2) + Rational(3, 1073741827)) assert_equal(Rational(3221225475, 2147483654), Rational(3, 2) - Rational(3, 1073741827)) assert_equal(Rational(9, 2147483654), Rational(3, 2) * Rational(3, 1073741827)) assert_equal(Rational(1073741827, 2), Rational(3, 2) / Rational(3, 1073741827)) assert_equal(Rational(2147483663, 6), Rational(3, 2) + Rational(1073741827, 3)) assert_equal(Rational(-2147483645, 6), Rational(3, 2) - Rational(1073741827, 3)) assert_equal(Rational(1073741827, 2), Rational(3, 2) * Rational(1073741827, 3)) assert_equal(Rational(9, 2147483654), Rational(3, 2) / Rational(1073741827, 3)) assert_equal(Rational(5368709059, 2147483654), Rational(3, 2) + Rational(1073741789, 1073741827)) assert_equal(Rational(1073741903, 2147483654), Rational(3, 2) - Rational(1073741789, 1073741827)) assert_equal(Rational(3221225367, 2147483654), Rational(3, 2) * Rational(1073741789, 1073741827)) assert_equal(Rational(3221225481, 2147483578), Rational(3, 2) / Rational(1073741789, 1073741827)) assert_equal(Rational(5368709021, 2147483578), Rational(3, 2) + Rational(1073741827, 1073741789)) assert_equal(Rational(1073741713, 2147483578), Rational(3, 2) - Rational(1073741827, 1073741789)) assert_equal(Rational(3221225481, 2147483578), Rational(3, 2) * Rational(1073741827, 1073741789)) assert_equal(Rational(3221225367, 2147483654), Rational(3, 2) / Rational(1073741827, 1073741789)) assert_equal(Rational(3, 1073741789), +Rational(3, 1073741789)) assert_equal(Rational(-3, 1073741789), -Rational(3, 1073741789)) assert_equal(Rational(1073741792, 1073741789), Rational(3, 1073741789) + Rational(1, 1)) assert_equal(Rational(-1073741786, 1073741789), Rational(3, 1073741789) - Rational(1, 1)) assert_equal(Rational(3, 1073741789), Rational(3, 1073741789) * Rational(1, 1)) assert_equal(Rational(3, 1073741789), Rational(3, 1073741789) / Rational(1, 1)) assert_equal(Rational(2147483581, 1073741789), Rational(3, 1073741789) + Rational(2, 1)) assert_equal(Rational(-2147483575, 1073741789), Rational(3, 1073741789) - Rational(2, 1)) assert_equal(Rational(6, 1073741789), Rational(3, 1073741789) * Rational(2, 1)) assert_equal(Rational(3, 2147483578), Rational(3, 1073741789) / Rational(2, 1)) assert_equal(Rational(3221225370, 1073741789), Rational(3, 1073741789) + Rational(3, 1)) assert_equal(Rational(-3221225364, 1073741789), Rational(3, 1073741789) - Rational(3, 1)) assert_equal(Rational(9, 1073741789), Rational(3, 1073741789) * Rational(3, 1)) assert_equal(Rational(1, 1073741789), Rational(3, 1073741789) / Rational(3, 1)) assert_equal(Rational(1152921429444920524, 1073741789), Rational(3, 1073741789) + Rational(1073741789, 1)) assert_equal(Rational(-1152921429444920518, 1073741789), Rational(3, 1073741789) - Rational(1073741789, 1)) assert_equal(Rational(3, 1), Rational(3, 1073741789) * Rational(1073741789, 1)) assert_equal(Rational(3, 1152921429444920521), Rational(3, 1073741789) / Rational(1073741789, 1)) assert_equal(Rational(1152921470247108506, 1073741789), Rational(3, 1073741789) + Rational(1073741827, 1)) assert_equal(Rational(-1152921470247108500, 1073741789), Rational(3, 1073741789) - Rational(1073741827, 1)) assert_equal(Rational(3221225481, 1073741789), Rational(3, 1073741789) * Rational(1073741827, 1)) assert_equal(Rational(3, 1152921470247108503), Rational(3, 1073741789) / Rational(1073741827, 1)) assert_equal(Rational(2147483587, 3221225367), Rational(3, 1073741789) + Rational(2, 3)) assert_equal(Rational(-2147483569, 3221225367), Rational(3, 1073741789) - Rational(2, 3)) assert_equal(Rational(2, 1073741789), Rational(3, 1073741789) * Rational(2, 3)) assert_equal(Rational(9, 2147483578), Rational(3, 1073741789) / Rational(2, 3)) assert_equal(Rational(3221225373, 2147483578), Rational(3, 1073741789) + Rational(3, 2)) assert_equal(Rational(-3221225361, 2147483578), Rational(3, 1073741789) - Rational(3, 2)) assert_equal(Rational(9, 2147483578), Rational(3, 1073741789) * Rational(3, 2)) assert_equal(Rational(2, 1073741789), Rational(3, 1073741789) / Rational(3, 2)) assert_equal(Rational(6, 1073741789), Rational(3, 1073741789) + Rational(3, 1073741789)) assert_equal(Rational(0, 1), Rational(3, 1073741789) - Rational(3, 1073741789)) assert_equal(Rational(9, 1152921429444920521), Rational(3, 1073741789) * Rational(3, 1073741789)) assert_equal(Rational(1, 1), Rational(3, 1073741789) / Rational(3, 1073741789)) assert_equal(Rational(1152921429444920530, 3221225367), Rational(3, 1073741789) + Rational(1073741789, 3)) assert_equal(Rational(-1152921429444920512, 3221225367), Rational(3, 1073741789) - Rational(1073741789, 3)) assert_equal(Rational(1, 1), Rational(3, 1073741789) * Rational(1073741789, 3)) assert_equal(Rational(9, 1152921429444920521), Rational(3, 1073741789) / Rational(1073741789, 3)) assert_equal(Rational(6442450848, 1152921470247108503), Rational(3, 1073741789) + Rational(3, 1073741827)) assert_equal(Rational(114, 1152921470247108503), Rational(3, 1073741789) - Rational(3, 1073741827)) assert_equal(Rational(9, 1152921470247108503), Rational(3, 1073741789) * Rational(3, 1073741827)) assert_equal(Rational(1073741827, 1073741789), Rational(3, 1073741789) / Rational(3, 1073741827)) assert_equal(Rational(1152921470247108512, 3221225367), Rational(3, 1073741789) + Rational(1073741827, 3)) assert_equal(Rational(-1152921470247108494, 3221225367), Rational(3, 1073741789) - Rational(1073741827, 3)) assert_equal(Rational(1073741827, 1073741789), Rational(3, 1073741789) * Rational(1073741827, 3)) assert_equal(Rational(9, 1152921470247108503), Rational(3, 1073741789) / Rational(1073741827, 3)) assert_equal(Rational(1152921432666146002, 1152921470247108503), Rational(3, 1073741789) + Rational(1073741789, 1073741827)) assert_equal(Rational(-1152921426223695040, 1152921470247108503), Rational(3, 1073741789) - Rational(1073741789, 1073741827)) assert_equal(Rational(3, 1073741827), Rational(3, 1073741789) * Rational(1073741789, 1073741827)) assert_equal(Rational(3221225481, 1152921429444920521), Rational(3, 1073741789) / Rational(1073741789, 1073741827)) assert_equal(Rational(1073741830, 1073741789), Rational(3, 1073741789) + Rational(1073741827, 1073741789)) assert_equal(Rational(-1073741824, 1073741789), Rational(3, 1073741789) - Rational(1073741827, 1073741789)) assert_equal(Rational(3221225481, 1152921429444920521), Rational(3, 1073741789) * Rational(1073741827, 1073741789)) assert_equal(Rational(3, 1073741827), Rational(3, 1073741789) / Rational(1073741827, 1073741789)) assert_equal(Rational(1073741789, 3), +Rational(1073741789, 3)) assert_equal(Rational(-1073741789, 3), -Rational(1073741789, 3)) assert_equal(Rational(1073741792, 3), Rational(1073741789, 3) + Rational(1, 1)) assert_equal(Rational(1073741786, 3), Rational(1073741789, 3) - Rational(1, 1)) assert_equal(Rational(1073741789, 3), Rational(1073741789, 3) * Rational(1, 1)) assert_equal(Rational(1073741789, 3), Rational(1073741789, 3) / Rational(1, 1)) assert_equal(Rational(1073741795, 3), Rational(1073741789, 3) + Rational(2, 1)) assert_equal(Rational(1073741783, 3), Rational(1073741789, 3) - Rational(2, 1)) assert_equal(Rational(2147483578, 3), Rational(1073741789, 3) * Rational(2, 1)) assert_equal(Rational(1073741789, 6), Rational(1073741789, 3) / Rational(2, 1)) assert_equal(Rational(1073741798, 3), Rational(1073741789, 3) + Rational(3, 1)) assert_equal(Rational(1073741780, 3), Rational(1073741789, 3) - Rational(3, 1)) assert_equal(Rational(1073741789, 1), Rational(1073741789, 3) * Rational(3, 1)) assert_equal(Rational(1073741789, 9), Rational(1073741789, 3) / Rational(3, 1)) assert_equal(Rational(4294967156, 3), Rational(1073741789, 3) + Rational(1073741789, 1)) assert_equal(Rational(-2147483578, 3), Rational(1073741789, 3) - Rational(1073741789, 1)) assert_equal(Rational(1152921429444920521, 3), Rational(1073741789, 3) * Rational(1073741789, 1)) assert_equal(Rational(1, 3), Rational(1073741789, 3) / Rational(1073741789, 1)) assert_equal(Rational(4294967270, 3), Rational(1073741789, 3) + Rational(1073741827, 1)) assert_equal(Rational(-2147483692, 3), Rational(1073741789, 3) - Rational(1073741827, 1)) assert_equal(Rational(1152921470247108503, 3), Rational(1073741789, 3) * Rational(1073741827, 1)) assert_equal(Rational(1073741789, 3221225481), Rational(1073741789, 3) / Rational(1073741827, 1)) assert_equal(Rational(1073741791, 3), Rational(1073741789, 3) + Rational(2, 3)) assert_equal(Rational(357913929, 1), Rational(1073741789, 3) - Rational(2, 3)) assert_equal(Rational(2147483578, 9), Rational(1073741789, 3) * Rational(2, 3)) assert_equal(Rational(1073741789, 2), Rational(1073741789, 3) / Rational(2, 3)) assert_equal(Rational(2147483587, 6), Rational(1073741789, 3) + Rational(3, 2)) assert_equal(Rational(2147483569, 6), Rational(1073741789, 3) - Rational(3, 2)) assert_equal(Rational(1073741789, 2), Rational(1073741789, 3) * Rational(3, 2)) assert_equal(Rational(2147483578, 9), Rational(1073741789, 3) / Rational(3, 2)) assert_equal(Rational(1152921429444920530, 3221225367), Rational(1073741789, 3) + Rational(3, 1073741789)) assert_equal(Rational(1152921429444920512, 3221225367), Rational(1073741789, 3) - Rational(3, 1073741789)) assert_equal(Rational(1, 1), Rational(1073741789, 3) * Rational(3, 1073741789)) assert_equal(Rational(1152921429444920521, 9), Rational(1073741789, 3) / Rational(3, 1073741789)) assert_equal(Rational(2147483578, 3), Rational(1073741789, 3) + Rational(1073741789, 3)) assert_equal(Rational(0, 1), Rational(1073741789, 3) - Rational(1073741789, 3)) assert_equal(Rational(1152921429444920521, 9), Rational(1073741789, 3) * Rational(1073741789, 3)) assert_equal(Rational(1, 1), Rational(1073741789, 3) / Rational(1073741789, 3)) assert_equal(Rational(1152921470247108512, 3221225481), Rational(1073741789, 3) + Rational(3, 1073741827)) assert_equal(Rational(1152921470247108494, 3221225481), Rational(1073741789, 3) - Rational(3, 1073741827)) assert_equal(Rational(1073741789, 1073741827), Rational(1073741789, 3) * Rational(3, 1073741827)) assert_equal(Rational(1152921470247108503, 9), Rational(1073741789, 3) / Rational(3, 1073741827)) assert_equal(Rational(715827872, 1), Rational(1073741789, 3) + Rational(1073741827, 3)) assert_equal(Rational(-38, 3), Rational(1073741789, 3) - Rational(1073741827, 3)) assert_equal(Rational(1152921470247108503, 9), Rational(1073741789, 3) * Rational(1073741827, 3)) assert_equal(Rational(1073741789, 1073741827), Rational(1073741789, 3) / Rational(1073741827, 3)) assert_equal(Rational(1152921473468333870, 3221225481), Rational(1073741789, 3) + Rational(1073741789, 1073741827)) assert_equal(Rational(1152921467025883136, 3221225481), Rational(1073741789, 3) - Rational(1073741789, 1073741827)) assert_equal(Rational(1152921429444920521, 3221225481), Rational(1073741789, 3) * Rational(1073741789, 1073741827)) assert_equal(Rational(1073741827, 3), Rational(1073741789, 3) / Rational(1073741789, 1073741827)) assert_equal(Rational(1152921432666146002, 3221225367), Rational(1073741789, 3) + Rational(1073741827, 1073741789)) assert_equal(Rational(1152921426223695040, 3221225367), Rational(1073741789, 3) - Rational(1073741827, 1073741789)) assert_equal(Rational(1073741827, 3), Rational(1073741789, 3) * Rational(1073741827, 1073741789)) assert_equal(Rational(1152921429444920521, 3221225481), Rational(1073741789, 3) / Rational(1073741827, 1073741789)) assert_equal(Rational(3, 1073741827), +Rational(3, 1073741827)) assert_equal(Rational(-3, 1073741827), -Rational(3, 1073741827)) assert_equal(Rational(1073741830, 1073741827), Rational(3, 1073741827) + Rational(1, 1)) assert_equal(Rational(-1073741824, 1073741827), Rational(3, 1073741827) - Rational(1, 1)) assert_equal(Rational(3, 1073741827), Rational(3, 1073741827) * Rational(1, 1)) assert_equal(Rational(3, 1073741827), Rational(3, 1073741827) / Rational(1, 1)) assert_equal(Rational(2147483657, 1073741827), Rational(3, 1073741827) + Rational(2, 1)) assert_equal(Rational(-2147483651, 1073741827), Rational(3, 1073741827) - Rational(2, 1)) assert_equal(Rational(6, 1073741827), Rational(3, 1073741827) * Rational(2, 1)) assert_equal(Rational(3, 2147483654), Rational(3, 1073741827) / Rational(2, 1)) assert_equal(Rational(3221225484, 1073741827), Rational(3, 1073741827) + Rational(3, 1)) assert_equal(Rational(-3221225478, 1073741827), Rational(3, 1073741827) - Rational(3, 1)) assert_equal(Rational(9, 1073741827), Rational(3, 1073741827) * Rational(3, 1)) assert_equal(Rational(1, 1073741827), Rational(3, 1073741827) / Rational(3, 1)) assert_equal(Rational(1152921470247108506, 1073741827), Rational(3, 1073741827) + Rational(1073741789, 1)) assert_equal(Rational(-1152921470247108500, 1073741827), Rational(3, 1073741827) - Rational(1073741789, 1)) assert_equal(Rational(3221225367, 1073741827), Rational(3, 1073741827) * Rational(1073741789, 1)) assert_equal(Rational(3, 1152921470247108503), Rational(3, 1073741827) / Rational(1073741789, 1)) assert_equal(Rational(1152921511049297932, 1073741827), Rational(3, 1073741827) + Rational(1073741827, 1)) assert_equal(Rational(-1152921511049297926, 1073741827), Rational(3, 1073741827) - Rational(1073741827, 1)) assert_equal(Rational(3, 1), Rational(3, 1073741827) * Rational(1073741827, 1)) assert_equal(Rational(3, 1152921511049297929), Rational(3, 1073741827) / Rational(1073741827, 1)) assert_equal(Rational(2147483663, 3221225481), Rational(3, 1073741827) + Rational(2, 3)) assert_equal(Rational(-2147483645, 3221225481), Rational(3, 1073741827) - Rational(2, 3)) assert_equal(Rational(2, 1073741827), Rational(3, 1073741827) * Rational(2, 3)) assert_equal(Rational(9, 2147483654), Rational(3, 1073741827) / Rational(2, 3)) assert_equal(Rational(3221225487, 2147483654), Rational(3, 1073741827) + Rational(3, 2)) assert_equal(Rational(-3221225475, 2147483654), Rational(3, 1073741827) - Rational(3, 2)) assert_equal(Rational(9, 2147483654), Rational(3, 1073741827) * Rational(3, 2)) assert_equal(Rational(2, 1073741827), Rational(3, 1073741827) / Rational(3, 2)) assert_equal(Rational(6442450848, 1152921470247108503), Rational(3, 1073741827) + Rational(3, 1073741789)) assert_equal(Rational(-114, 1152921470247108503), Rational(3, 1073741827) - Rational(3, 1073741789)) assert_equal(Rational(9, 1152921470247108503), Rational(3, 1073741827) * Rational(3, 1073741789)) assert_equal(Rational(1073741789, 1073741827), Rational(3, 1073741827) / Rational(3, 1073741789)) assert_equal(Rational(1152921470247108512, 3221225481), Rational(3, 1073741827) + Rational(1073741789, 3)) assert_equal(Rational(-1152921470247108494, 3221225481), Rational(3, 1073741827) - Rational(1073741789, 3)) assert_equal(Rational(1073741789, 1073741827), Rational(3, 1073741827) * Rational(1073741789, 3)) assert_equal(Rational(9, 1152921470247108503), Rational(3, 1073741827) / Rational(1073741789, 3)) assert_equal(Rational(6, 1073741827), Rational(3, 1073741827) + Rational(3, 1073741827)) assert_equal(Rational(0, 1), Rational(3, 1073741827) - Rational(3, 1073741827)) assert_equal(Rational(9, 1152921511049297929), Rational(3, 1073741827) * Rational(3, 1073741827)) assert_equal(Rational(1, 1), Rational(3, 1073741827) / Rational(3, 1073741827)) assert_equal(Rational(1152921511049297938, 3221225481), Rational(3, 1073741827) + Rational(1073741827, 3)) assert_equal(Rational(-1152921511049297920, 3221225481), Rational(3, 1073741827) - Rational(1073741827, 3)) assert_equal(Rational(1, 1), Rational(3, 1073741827) * Rational(1073741827, 3)) assert_equal(Rational(9, 1152921511049297929), Rational(3, 1073741827) / Rational(1073741827, 3)) assert_equal(Rational(1073741792, 1073741827), Rational(3, 1073741827) + Rational(1073741789, 1073741827)) assert_equal(Rational(-1073741786, 1073741827), Rational(3, 1073741827) - Rational(1073741789, 1073741827)) assert_equal(Rational(3221225367, 1152921511049297929), Rational(3, 1073741827) * Rational(1073741789, 1073741827)) assert_equal(Rational(3, 1073741789), Rational(3, 1073741827) / Rational(1073741789, 1073741827)) assert_equal(Rational(1152921514270523296, 1152921470247108503), Rational(3, 1073741827) + Rational(1073741827, 1073741789)) assert_equal(Rational(-1152921507828072562, 1152921470247108503), Rational(3, 1073741827) - Rational(1073741827, 1073741789)) assert_equal(Rational(3, 1073741789), Rational(3, 1073741827) * Rational(1073741827, 1073741789)) assert_equal(Rational(3221225367, 1152921511049297929), Rational(3, 1073741827) / Rational(1073741827, 1073741789)) assert_equal(Rational(1073741827, 3), +Rational(1073741827, 3)) assert_equal(Rational(-1073741827, 3), -Rational(1073741827, 3)) assert_equal(Rational(1073741830, 3), Rational(1073741827, 3) + Rational(1, 1)) assert_equal(Rational(1073741824, 3), Rational(1073741827, 3) - Rational(1, 1)) assert_equal(Rational(1073741827, 3), Rational(1073741827, 3) * Rational(1, 1)) assert_equal(Rational(1073741827, 3), Rational(1073741827, 3) / Rational(1, 1)) assert_equal(Rational(1073741833, 3), Rational(1073741827, 3) + Rational(2, 1)) assert_equal(Rational(1073741821, 3), Rational(1073741827, 3) - Rational(2, 1)) assert_equal(Rational(2147483654, 3), Rational(1073741827, 3) * Rational(2, 1)) assert_equal(Rational(1073741827, 6), Rational(1073741827, 3) / Rational(2, 1)) assert_equal(Rational(1073741836, 3), Rational(1073741827, 3) + Rational(3, 1)) assert_equal(Rational(1073741818, 3), Rational(1073741827, 3) - Rational(3, 1)) assert_equal(Rational(1073741827, 1), Rational(1073741827, 3) * Rational(3, 1)) assert_equal(Rational(1073741827, 9), Rational(1073741827, 3) / Rational(3, 1)) assert_equal(Rational(4294967194, 3), Rational(1073741827, 3) + Rational(1073741789, 1)) assert_equal(Rational(-2147483540, 3), Rational(1073741827, 3) - Rational(1073741789, 1)) assert_equal(Rational(1152921470247108503, 3), Rational(1073741827, 3) * Rational(1073741789, 1)) assert_equal(Rational(1073741827, 3221225367), Rational(1073741827, 3) / Rational(1073741789, 1)) assert_equal(Rational(4294967308, 3), Rational(1073741827, 3) + Rational(1073741827, 1)) assert_equal(Rational(-2147483654, 3), Rational(1073741827, 3) - Rational(1073741827, 1)) assert_equal(Rational(1152921511049297929, 3), Rational(1073741827, 3) * Rational(1073741827, 1)) assert_equal(Rational(1, 3), Rational(1073741827, 3) / Rational(1073741827, 1)) assert_equal(Rational(357913943, 1), Rational(1073741827, 3) + Rational(2, 3)) assert_equal(Rational(1073741825, 3), Rational(1073741827, 3) - Rational(2, 3)) assert_equal(Rational(2147483654, 9), Rational(1073741827, 3) * Rational(2, 3)) assert_equal(Rational(1073741827, 2), Rational(1073741827, 3) / Rational(2, 3)) assert_equal(Rational(2147483663, 6), Rational(1073741827, 3) + Rational(3, 2)) assert_equal(Rational(2147483645, 6), Rational(1073741827, 3) - Rational(3, 2)) assert_equal(Rational(1073741827, 2), Rational(1073741827, 3) * Rational(3, 2)) assert_equal(Rational(2147483654, 9), Rational(1073741827, 3) / Rational(3, 2)) assert_equal(Rational(1152921470247108512, 3221225367), Rational(1073741827, 3) + Rational(3, 1073741789)) assert_equal(Rational(1152921470247108494, 3221225367), Rational(1073741827, 3) - Rational(3, 1073741789)) assert_equal(Rational(1073741827, 1073741789), Rational(1073741827, 3) * Rational(3, 1073741789)) assert_equal(Rational(1152921470247108503, 9), Rational(1073741827, 3) / Rational(3, 1073741789)) assert_equal(Rational(715827872, 1), Rational(1073741827, 3) + Rational(1073741789, 3)) assert_equal(Rational(38, 3), Rational(1073741827, 3) - Rational(1073741789, 3)) assert_equal(Rational(1152921470247108503, 9), Rational(1073741827, 3) * Rational(1073741789, 3)) assert_equal(Rational(1073741827, 1073741789), Rational(1073741827, 3) / Rational(1073741789, 3)) assert_equal(Rational(1152921511049297938, 3221225481), Rational(1073741827, 3) + Rational(3, 1073741827)) assert_equal(Rational(1152921511049297920, 3221225481), Rational(1073741827, 3) - Rational(3, 1073741827)) assert_equal(Rational(1, 1), Rational(1073741827, 3) * Rational(3, 1073741827)) assert_equal(Rational(1152921511049297929, 9), Rational(1073741827, 3) / Rational(3, 1073741827)) assert_equal(Rational(2147483654, 3), Rational(1073741827, 3) + Rational(1073741827, 3)) assert_equal(Rational(0, 1), Rational(1073741827, 3) - Rational(1073741827, 3)) assert_equal(Rational(1152921511049297929, 9), Rational(1073741827, 3) * Rational(1073741827, 3)) assert_equal(Rational(1, 1), Rational(1073741827, 3) / Rational(1073741827, 3)) assert_equal(Rational(1152921514270523296, 3221225481), Rational(1073741827, 3) + Rational(1073741789, 1073741827)) assert_equal(Rational(1152921507828072562, 3221225481), Rational(1073741827, 3) - Rational(1073741789, 1073741827)) assert_equal(Rational(1073741789, 3), Rational(1073741827, 3) * Rational(1073741789, 1073741827)) assert_equal(Rational(1152921511049297929, 3221225367), Rational(1073741827, 3) / Rational(1073741789, 1073741827)) assert_equal(Rational(1152921473468333984, 3221225367), Rational(1073741827, 3) + Rational(1073741827, 1073741789)) assert_equal(Rational(1152921467025883022, 3221225367), Rational(1073741827, 3) - Rational(1073741827, 1073741789)) assert_equal(Rational(1152921511049297929, 3221225367), Rational(1073741827, 3) * Rational(1073741827, 1073741789)) assert_equal(Rational(1073741789, 3), Rational(1073741827, 3) / Rational(1073741827, 1073741789)) assert_equal(Rational(1073741789, 1073741827), +Rational(1073741789, 1073741827)) assert_equal(Rational(-1073741789, 1073741827), -Rational(1073741789, 1073741827)) assert_equal(Rational(2147483616, 1073741827), Rational(1073741789, 1073741827) + Rational(1, 1)) assert_equal(Rational(-38, 1073741827), Rational(1073741789, 1073741827) - Rational(1, 1)) assert_equal(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827) * Rational(1, 1)) assert_equal(Rational(1073741789, 1073741827), Rational(1073741789, 1073741827) / Rational(1, 1)) assert_equal(Rational(3221225443, 1073741827), Rational(1073741789, 1073741827) + Rational(2, 1)) assert_equal(Rational(-1073741865, 1073741827), Rational(1073741789, 1073741827) - Rational(2, 1)) assert_equal(Rational(2147483578, 1073741827), Rational(1073741789, 1073741827) * Rational(2, 1)) assert_equal(Rational(1073741789, 2147483654), Rational(1073741789, 1073741827) / Rational(2, 1)) assert_equal(Rational(4294967270, 1073741827), Rational(1073741789, 1073741827) + Rational(3, 1)) assert_equal(Rational(-2147483692, 1073741827), Rational(1073741789, 1073741827) - Rational(3, 1)) assert_equal(Rational(3221225367, 1073741827), Rational(1073741789, 1073741827) * Rational(3, 1)) assert_equal(Rational(1073741789, 3221225481), Rational(1073741789, 1073741827) / Rational(3, 1)) assert_equal(Rational(1152921471320850292, 1073741827), Rational(1073741789, 1073741827) + Rational(1073741789, 1)) assert_equal(Rational(-1152921469173366714, 1073741827), Rational(1073741789, 1073741827) - Rational(1073741789, 1)) assert_equal(Rational(1152921429444920521, 1073741827), Rational(1073741789, 1073741827) * Rational(1073741789, 1)) assert_equal(Rational(1, 1073741827), Rational(1073741789, 1073741827) / Rational(1073741789, 1)) assert_equal(Rational(1152921512123039718, 1073741827), Rational(1073741789, 1073741827) + Rational(1073741827, 1)) assert_equal(Rational(-1152921509975556140, 1073741827), Rational(1073741789, 1073741827) - Rational(1073741827, 1)) assert_equal(Rational(1073741789, 1), Rational(1073741789, 1073741827) * Rational(1073741827, 1)) assert_equal(Rational(1073741789, 1152921511049297929), Rational(1073741789, 1073741827) / Rational(1073741827, 1)) assert_equal(Rational(5368709021, 3221225481), Rational(1073741789, 1073741827) + Rational(2, 3)) assert_equal(Rational(1073741713, 3221225481), Rational(1073741789, 1073741827) - Rational(2, 3)) assert_equal(Rational(2147483578, 3221225481), Rational(1073741789, 1073741827) * Rational(2, 3)) assert_equal(Rational(3221225367, 2147483654), Rational(1073741789, 1073741827) / Rational(2, 3)) assert_equal(Rational(5368709059, 2147483654), Rational(1073741789, 1073741827) + Rational(3, 2)) assert_equal(Rational(-1073741903, 2147483654), Rational(1073741789, 1073741827) - Rational(3, 2)) assert_equal(Rational(3221225367, 2147483654), Rational(1073741789, 1073741827) * Rational(3, 2)) assert_equal(Rational(2147483578, 3221225481), Rational(1073741789, 1073741827) / Rational(3, 2)) assert_equal(Rational(1152921432666146002, 1152921470247108503), Rational(1073741789, 1073741827) + Rational(3, 1073741789)) assert_equal(Rational(1152921426223695040, 1152921470247108503), Rational(1073741789, 1073741827) - Rational(3, 1073741789)) assert_equal(Rational(3, 1073741827), Rational(1073741789, 1073741827) * Rational(3, 1073741789)) assert_equal(Rational(1152921429444920521, 3221225481), Rational(1073741789, 1073741827) / Rational(3, 1073741789)) assert_equal(Rational(1152921473468333870, 3221225481), Rational(1073741789, 1073741827) + Rational(1073741789, 3)) assert_equal(Rational(-1152921467025883136, 3221225481), Rational(1073741789, 1073741827) - Rational(1073741789, 3)) assert_equal(Rational(1152921429444920521, 3221225481), Rational(1073741789, 1073741827) * Rational(1073741789, 3)) assert_equal(Rational(3, 1073741827), Rational(1073741789, 1073741827) / Rational(1073741789, 3)) assert_equal(Rational(1073741792, 1073741827), Rational(1073741789, 1073741827) + Rational(3, 1073741827)) assert_equal(Rational(1073741786, 1073741827), Rational(1073741789, 1073741827) - Rational(3, 1073741827)) assert_equal(Rational(3221225367, 1152921511049297929), Rational(1073741789, 1073741827) * Rational(3, 1073741827)) assert_equal(Rational(1073741789, 3), Rational(1073741789, 1073741827) / Rational(3, 1073741827)) assert_equal(Rational(1152921514270523296, 3221225481), Rational(1073741789, 1073741827) + Rational(1073741827, 3)) assert_equal(Rational(-1152921507828072562, 3221225481), Rational(1073741789, 1073741827) - Rational(1073741827, 3)) assert_equal(Rational(1073741789, 3), Rational(1073741789, 1073741827) * Rational(1073741827, 3)) assert_equal(Rational(3221225367, 1152921511049297929), Rational(1073741789, 1073741827) / Rational(1073741827, 3)) assert_equal(Rational(2147483578, 1073741827), Rational(1073741789, 1073741827) + Rational(1073741789, 1073741827)) assert_equal(Rational(0, 1), Rational(1073741789, 1073741827) - Rational(1073741789, 1073741827)) assert_equal(Rational(1152921429444920521, 1152921511049297929), Rational(1073741789, 1073741827) * Rational(1073741789, 1073741827)) assert_equal(Rational(1, 1), Rational(1073741789, 1073741827) / Rational(1073741789, 1073741827)) assert_equal(Rational(2305842940494218450, 1152921470247108503), Rational(1073741789, 1073741827) + Rational(1073741827, 1073741789)) assert_equal(Rational(-81604377408, 1152921470247108503), Rational(1073741789, 1073741827) - Rational(1073741827, 1073741789)) assert_equal(Rational(1, 1), Rational(1073741789, 1073741827) * Rational(1073741827, 1073741789)) assert_equal(Rational(1152921429444920521, 1152921511049297929), Rational(1073741789, 1073741827) / Rational(1073741827, 1073741789)) assert_equal(Rational(1073741827, 1073741789), +Rational(1073741827, 1073741789)) assert_equal(Rational(-1073741827, 1073741789), -Rational(1073741827, 1073741789)) assert_equal(Rational(2147483616, 1073741789), Rational(1073741827, 1073741789) + Rational(1, 1)) assert_equal(Rational(38, 1073741789), Rational(1073741827, 1073741789) - Rational(1, 1)) assert_equal(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789) * Rational(1, 1)) assert_equal(Rational(1073741827, 1073741789), Rational(1073741827, 1073741789) / Rational(1, 1)) assert_equal(Rational(3221225405, 1073741789), Rational(1073741827, 1073741789) + Rational(2, 1)) assert_equal(Rational(-1073741751, 1073741789), Rational(1073741827, 1073741789) - Rational(2, 1)) assert_equal(Rational(2147483654, 1073741789), Rational(1073741827, 1073741789) * Rational(2, 1)) assert_equal(Rational(1073741827, 2147483578), Rational(1073741827, 1073741789) / Rational(2, 1)) assert_equal(Rational(4294967194, 1073741789), Rational(1073741827, 1073741789) + Rational(3, 1)) assert_equal(Rational(-2147483540, 1073741789), Rational(1073741827, 1073741789) - Rational(3, 1)) assert_equal(Rational(3221225481, 1073741789), Rational(1073741827, 1073741789) * Rational(3, 1)) assert_equal(Rational(1073741827, 3221225367), Rational(1073741827, 1073741789) / Rational(3, 1)) assert_equal(Rational(1152921430518662348, 1073741789), Rational(1073741827, 1073741789) + Rational(1073741789, 1)) assert_equal(Rational(-1152921428371178694, 1073741789), Rational(1073741827, 1073741789) - Rational(1073741789, 1)) assert_equal(Rational(1073741827, 1), Rational(1073741827, 1073741789) * Rational(1073741789, 1)) assert_equal(Rational(1073741827, 1152921429444920521), Rational(1073741827, 1073741789) / Rational(1073741789, 1)) assert_equal(Rational(1152921471320850330, 1073741789), Rational(1073741827, 1073741789) + Rational(1073741827, 1)) assert_equal(Rational(-1152921469173366676, 1073741789), Rational(1073741827, 1073741789) - Rational(1073741827, 1)) assert_equal(Rational(1152921511049297929, 1073741789), Rational(1073741827, 1073741789) * Rational(1073741827, 1)) assert_equal(Rational(1, 1073741789), Rational(1073741827, 1073741789) / Rational(1073741827, 1)) assert_equal(Rational(5368709059, 3221225367), Rational(1073741827, 1073741789) + Rational(2, 3)) assert_equal(Rational(1073741903, 3221225367), Rational(1073741827, 1073741789) - Rational(2, 3)) assert_equal(Rational(2147483654, 3221225367), Rational(1073741827, 1073741789) * Rational(2, 3)) assert_equal(Rational(3221225481, 2147483578), Rational(1073741827, 1073741789) / Rational(2, 3)) assert_equal(Rational(5368709021, 2147483578), Rational(1073741827, 1073741789) + Rational(3, 2)) assert_equal(Rational(-1073741713, 2147483578), Rational(1073741827, 1073741789) - Rational(3, 2)) assert_equal(Rational(3221225481, 2147483578), Rational(1073741827, 1073741789) * Rational(3, 2)) assert_equal(Rational(2147483654, 3221225367), Rational(1073741827, 1073741789) / Rational(3, 2)) assert_equal(Rational(1073741830, 1073741789), Rational(1073741827, 1073741789) + Rational(3, 1073741789)) assert_equal(Rational(1073741824, 1073741789), Rational(1073741827, 1073741789) - Rational(3, 1073741789)) assert_equal(Rational(3221225481, 1152921429444920521), Rational(1073741827, 1073741789) * Rational(3, 1073741789)) assert_equal(Rational(1073741827, 3), Rational(1073741827, 1073741789) / Rational(3, 1073741789)) assert_equal(Rational(1152921432666146002, 3221225367), Rational(1073741827, 1073741789) + Rational(1073741789, 3)) assert_equal(Rational(-1152921426223695040, 3221225367), Rational(1073741827, 1073741789) - Rational(1073741789, 3)) assert_equal(Rational(1073741827, 3), Rational(1073741827, 1073741789) * Rational(1073741789, 3)) assert_equal(Rational(3221225481, 1152921429444920521), Rational(1073741827, 1073741789) / Rational(1073741789, 3)) assert_equal(Rational(1152921514270523296, 1152921470247108503), Rational(1073741827, 1073741789) + Rational(3, 1073741827)) assert_equal(Rational(1152921507828072562, 1152921470247108503), Rational(1073741827, 1073741789) - Rational(3, 1073741827)) assert_equal(Rational(3, 1073741789), Rational(1073741827, 1073741789) * Rational(3, 1073741827)) assert_equal(Rational(1152921511049297929, 3221225367), Rational(1073741827, 1073741789) / Rational(3, 1073741827)) assert_equal(Rational(1152921473468333984, 3221225367), Rational(1073741827, 1073741789) + Rational(1073741827, 3)) assert_equal(Rational(-1152921467025883022, 3221225367), Rational(1073741827, 1073741789) - Rational(1073741827, 3)) assert_equal(Rational(1152921511049297929, 3221225367), Rational(1073741827, 1073741789) * Rational(1073741827, 3)) assert_equal(Rational(3, 1073741789), Rational(1073741827, 1073741789) / Rational(1073741827, 3)) assert_equal(Rational(2305842940494218450, 1152921470247108503), Rational(1073741827, 1073741789) + Rational(1073741789, 1073741827)) assert_equal(Rational(81604377408, 1152921470247108503), Rational(1073741827, 1073741789) - Rational(1073741789, 1073741827)) assert_equal(Rational(1, 1), Rational(1073741827, 1073741789) * Rational(1073741789, 1073741827)) assert_equal(Rational(1152921511049297929, 1152921429444920521), Rational(1073741827, 1073741789) / Rational(1073741789, 1073741827)) assert_equal(Rational(2147483654, 1073741789), Rational(1073741827, 1073741789) + Rational(1073741827, 1073741789)) assert_equal(Rational(0, 1), Rational(1073741827, 1073741789) - Rational(1073741827, 1073741789)) assert_equal(Rational(1152921511049297929, 1152921429444920521), Rational(1073741827, 1073741789) * Rational(1073741827, 1073741789)) assert_equal(Rational(1, 1), Rational(1073741827, 1073741789) / Rational(1073741827, 1073741789)) end end ================================================ FILE: test/rdoc/parsers/test_parse_c.rb ================================================ require 'stringio' require 'tempfile' require 'test/unit' require 'rdoc/parsers/parse_c' class RDoc::C_Parser attr_accessor :classes public :do_classes, :do_constants end class TestRdocC_Parser < Test::Unit::TestCase def setup @tempfile = Tempfile.new self.class.name filename = @tempfile.path @top_level = RDoc::TopLevel.new filename @fn = filename @options = Options.instance @stats = RDoc::Stats.new @progress = StringIO.new end def teardown @tempfile.unlink end def test_do_classes_boot_class content = <<-EOF /* Document-class: Foo * this is the Foo boot class */ VALUE cFoo = boot_defclass("Foo", 0); EOF klass = util_get_class content, 'cFoo' assert_equal " this is the Foo boot class\n ", klass.comment end def test_do_classes_class content = <<-EOF /* Document-class: Foo * this is the Foo class */ VALUE cFoo = rb_define_class("Foo", rb_cObject); EOF klass = util_get_class content, 'cFoo' assert_equal " this is the Foo class\n ", klass.comment end def test_do_classes_class_under content = <<-EOF /* Document-class: Kernel::Foo * this is the Foo class under Kernel */ VALUE cFoo = rb_define_class_under(rb_mKernel, "Foo", rb_cObject); EOF klass = util_get_class content, 'cFoo' assert_equal " this is the Foo class under Kernel\n ", klass.comment end def test_do_classes_module content = <<-EOF /* Document-module: Foo * this is the Foo module */ VALUE mFoo = rb_define_module("Foo"); EOF klass = util_get_class content, 'mFoo' assert_equal " this is the Foo module\n ", klass.comment end def test_do_classes_module_under content = <<-EOF /* Document-module: Kernel::Foo * this is the Foo module under Kernel */ VALUE mFoo = rb_define_module_under(rb_mKernel, "Foo"); EOF klass = util_get_class content, 'mFoo' assert_equal " this is the Foo module under Kernel\n ", klass.comment end def test_do_constants content = <<-EOF #include void Init_foo(){ VALUE cFoo = rb_define_class("Foo", rb_cObject); /* 300: The highest possible score in bowling */ rb_define_const(cFoo, "PERFECT", INT2FIX(300)); /* Huzzah!: What you cheer when you roll a perfect game */ rb_define_const(cFoo, "CHEER", rb_str_new2("Huzzah!")); /* TEST\:TEST: Checking to see if escaped semicolon works */ rb_define_const(cFoo, "TEST", rb_str_new2("TEST:TEST")); /* \\: The file separator on MS Windows */ rb_define_const(cFoo, "MSEPARATOR", rb_str_new2("\\")); /* /: The file separator on Unix */ rb_define_const(cFoo, "SEPARATOR", rb_str_new2("/")); /* C:\\Program Files\\Stuff: A directory on MS Windows */ rb_define_const(cFoo, "STUFF", rb_str_new2("C:\\Program Files\\Stuff")); /* Default definition */ rb_define_const(cFoo, "NOSEMI", INT2FIX(99)); rb_define_const(cFoo, "NOCOMMENT", rb_str_new2("No comment")); /* * Multiline comment goes here because this comment spans multiple lines. * Multiline comment goes here because this comment spans multiple lines. */ rb_define_const(cFoo, "MULTILINE", INT2FIX(1)); /* * 1: Multiline comment goes here because this comment spans multiple lines. * Multiline comment goes here because this comment spans multiple lines. */ rb_define_const(cFoo, "MULTILINE_VALUE", INT2FIX(1)); /* Multiline comment goes here because this comment spans multiple lines. * Multiline comment goes here because this comment spans multiple lines. */ rb_define_const(cFoo, "MULTILINE_NOT_EMPTY", INT2FIX(1)); } EOF parser = util_parser content parser.do_classes parser.do_constants klass = parser.classes['cFoo'] assert klass constants = klass.constants assert !klass.constants.empty? constants = constants.map { |c| [c.name, c.value, c.comment] } assert_equal ['PERFECT', '300', "\n The highest possible score in bowling \n "], constants.shift assert_equal ['CHEER', 'Huzzah!', "\n What you cheer when you roll a perfect game \n "], constants.shift assert_equal ['TEST', 'TEST:TEST', "\n Checking to see if escaped semicolon works \n "], constants.shift assert_equal ['MSEPARATOR', '\\', "\n The file separator on MS Windows \n "], constants.shift assert_equal ['SEPARATOR', '/', "\n The file separator on Unix \n "], constants.shift assert_equal ['STUFF', 'C:\\Program Files\\Stuff', "\n A directory on MS Windows \n "], constants.shift assert_equal ['NOSEMI', 'INT2FIX(99)', "\n Default definition \n "], constants.shift assert_equal ['NOCOMMENT', 'rb_str_new2("No comment")', nil], constants.shift comment = <<-EOF.chomp Multiline comment goes here because this comment spans multiple lines. Multiline comment goes here because this comment spans multiple lines. EOF assert_equal ['MULTILINE', 'INT2FIX(1)', comment], constants.shift assert_equal ['MULTILINE_VALUE', '1', comment], constants.shift comment = <<-EOF.chomp Multiline comment goes here because this comment spans multiple lines. Multiline comment goes here because this comment spans multiple lines. EOF assert_equal ['MULTILINE_NOT_EMPTY', 'INT2FIX(1)', comment], constants.shift assert constants.empty?, constants.inspect end def test_find_class_comment_init content = <<-EOF /* * a comment for class Foo */ void Init_Foo(void) { VALUE foo = rb_define_class("Foo", rb_cObject); } EOF klass = util_get_class content, 'foo' assert_equal " \n a comment for class Foo\n \n", klass.comment end def test_find_class_comment_define_class content = <<-EOF /* * a comment for class Foo */ VALUE foo = rb_define_class("Foo", rb_cObject); EOF klass = util_get_class content, 'foo' assert_equal " \n a comment for class Foo\n ", klass.comment end def test_find_class_comment_define_class content = <<-EOF /* * a comment for class Foo on Init */ void Init_Foo(void) { /* * a comment for class Foo on rb_define_class */ VALUE foo = rb_define_class("Foo", rb_cObject); } EOF klass = util_get_class content, 'foo' assert_equal " \n a comment for class Foo on Init\n \n", klass.comment end def util_get_class(content, name) parser = util_parser content parser.do_classes parser.classes[name] end def util_parser(content) parser = RDoc::C_Parser.new @top_level, @fn, content, @options, @stats parser.progress = @progress parser end end ================================================ FILE: test/readline/test_readline.rb ================================================ begin require "readline" rescue LoadError end if defined?(Readline) && !/EditLine/n.match(Readline::VERSION) require "test/unit" require "tempfile" class TestReadline < Test::Unit::TestCase def test_readline stdin = Tempfile.new("test_readline_stdin") stdout = Tempfile.new("test_readline_stdout") begin stdin.write("hello\n") stdin.close stdout.close line = replace_stdio(stdin.path, stdout.path) { Readline.readline("> ", true) } assert_equal("hello", line) assert_equal(true, line.tainted?) stdout.open assert_equal("> ", stdout.read(2)) assert_equal(1, Readline::HISTORY.length) assert_equal("hello", Readline::HISTORY[0]) assert_raises(SecurityError) do Thread.start { $SAFE = 1 replace_stdio(stdin.path, stdout.path) do Readline.readline("> ".taint) end }.join end assert_raises(SecurityError) do Thread.start { $SAFE = 4 replace_stdio(stdin.path, stdout.path) { Readline.readline("> ") } }.join end ensure stdin.close(true) stdout.close(true) end end def test_completion_append_character begin Readline.completion_append_character = "x" assert_equal("x", Readline.completion_append_character) Readline.completion_append_character = "xyz" assert_equal("x", Readline.completion_append_character) Readline.completion_append_character = nil assert_equal(nil, Readline.completion_append_character) Readline.completion_append_character = "" assert_equal(nil, Readline.completion_append_character) rescue NotImplementedError end end private def replace_stdio(stdin_path, stdout_path) open(stdin_path, "r"){|stdin| open(stdout_path, "w"){|stdout| orig_stdin = STDIN.dup orig_stdout = STDOUT.dup STDIN.reopen(stdin) STDOUT.reopen(stdout) begin yield ensure STDIN.reopen(orig_stdin) STDOUT.reopen(orig_stdout) orig_stdin.close orig_stdout.close end } } end end end ================================================ FILE: test/rexml/test_document.rb ================================================ require "rexml/document" require "test/unit" class REXML::TestDocument < Test::Unit::TestCase def test_new doc = REXML::Document.new(< Hello world! EOF assert_equal("Hello world!", doc.root.children.first.value) end XML_WITH_NESTED_ENTITY = < ]> &a; EOF XML_WITH_4_ENTITY_EXPANSION = < ]> &a; &a2; < EOF def test_entity_expansion_limit doc = REXML::Document.new(XML_WITH_NESTED_ENTITY) assert_raise(RuntimeError) do doc.root.children.first.value end REXML::Document.entity_expansion_limit = 100 assert_equal(100, REXML::Document.entity_expansion_limit) doc = REXML::Document.new(XML_WITH_NESTED_ENTITY) assert_raise(RuntimeError) do doc.root.children.first.value end assert_equal(101, doc.entity_expansion_count) REXML::Document.entity_expansion_limit = 4 doc = REXML::Document.new(XML_WITH_4_ENTITY_EXPANSION) assert_equal("\na\na a\n<\n", doc.root.children.first.value) REXML::Document.entity_expansion_limit = 3 doc = REXML::Document.new(XML_WITH_4_ENTITY_EXPANSION) assert_raise(RuntimeError) do doc.root.children.first.value end ensure REXML::Document.entity_expansion_limit = 10000 end end ================================================ FILE: test/rinda/test_rinda.rb ================================================ require 'test/unit' require 'drb/drb' require 'drb/eq' require 'rinda/tuplespace' require 'singleton' module Rinda class MockClock include Singleton class MyTS < Rinda::TupleSpace def keeper_thread nil end end def initialize @now = 2 @reso = 1 @ts = MyTS.new @ts.write([2, :now]) @inf = 2**31 - 1 end def now @now.to_f end def at(n) n end def _forward(n=nil) now ,= @ts.take([nil, :now]) @now = now + n n = @reso if n.nil? @ts.write([@now, :now]) end def forward(n) while n > 0 _forward(@reso) n -= @reso Thread.pass end end def rewind now ,= @ts.take([nil, :now]) @ts.write([@inf, :now]) @ts.take([nil, :now]) @now = 2 @ts.write([2, :now]) end def sleep(n=nil) now ,= @ts.read([nil, :now]) @ts.read([(now + n)..@inf, :now]) 0 end end module Time def sleep(n) @m.sleep(n) end module_function :sleep def at(n) n end module_function :at def now @m ? @m.now : 2 end module_function :now def rewind @m.rewind end module_function :rewind def forward(n) @m.forward(n) end module_function :forward @m = MockClock.instance end class TupleSpace def sleep(n) Time.sleep(n) end end module TupleSpaceTestModule def sleep(n) if Thread.current == Thread.main Time.forward(n) else Time.sleep(n) end end def thread_join(th) while th.alive? Kernel.sleep(0.1) sleep(1) end th.value end def test_00_tuple tuple = Rinda::TupleEntry.new([1,2,3]) assert(!tuple.canceled?) assert(!tuple.expired?) assert(tuple.alive?) end def test_00_template tmpl = Rinda::Template.new([1,2,3]) assert_equal(3, tmpl.size) assert_equal(3, tmpl[2]) assert(tmpl.match([1,2,3])) assert(!tmpl.match([1,nil,3])) tmpl = Rinda::Template.new([/^rinda/i, nil, :hello]) assert_equal(3, tmpl.size) assert(tmpl.match(['Rinda', 2, :hello])) assert(!tmpl.match(['Rinda', 2, Symbol])) assert(!tmpl.match([1, 2, :hello])) assert(tmpl.match([/^rinda/i, 2, :hello])) tmpl = Rinda::Template.new([Symbol]) assert_equal(1, tmpl.size) assert(tmpl.match([:hello])) assert(tmpl.match([Symbol])) assert(!tmpl.match(['Symbol'])) tmpl = Rinda::Template.new({"message"=>String, "name"=>String}) assert_equal(2, tmpl.size) assert(tmpl.match({"message"=>"Hello", "name"=>"Foo"})) assert(!tmpl.match({"message"=>"Hello", "name"=>"Foo", "1"=>2})) assert(!tmpl.match({"message"=>"Hi", "name"=>"Foo", "age"=>1})) assert(!tmpl.match({"message"=>"Hello", "no_name"=>"Foo"})) assert_raises(Rinda::InvalidHashTupleKey) do tmpl = Rinda::Template.new({:message=>String, "name"=>String}) end tmpl = Rinda::Template.new({"name"=>String}) assert_equal(1, tmpl.size) assert(tmpl.match({"name"=>"Foo"})) assert(!tmpl.match({"message"=>"Hello", "name"=>"Foo"})) assert(!tmpl.match({"message"=>:symbol, "name"=>"Foo", "1"=>2})) assert(!tmpl.match({"message"=>"Hi", "name"=>"Foo", "age"=>1})) assert(!tmpl.match({"message"=>"Hello", "no_name"=>"Foo"})) tmpl = Rinda::Template.new({"message"=>String, "name"=>String}) assert_equal(2, tmpl.size) assert(tmpl.match({"message"=>"Hello", "name"=>"Foo"})) assert(!tmpl.match({"message"=>"Hello", "name"=>"Foo", "1"=>2})) assert(!tmpl.match({"message"=>"Hi", "name"=>"Foo", "age"=>1})) assert(!tmpl.match({"message"=>"Hello", "no_name"=>"Foo"})) tmpl = Rinda::Template.new({"message"=>String}) assert_equal(1, tmpl.size) assert(tmpl.match({"message"=>"Hello"})) assert(!tmpl.match({"message"=>"Hello", "name"=>"Foo"})) assert(!tmpl.match({"message"=>"Hello", "name"=>"Foo", "1"=>2})) assert(!tmpl.match({"message"=>"Hi", "name"=>"Foo", "age"=>1})) assert(!tmpl.match({"message"=>"Hello", "no_name"=>"Foo"})) tmpl = Rinda::Template.new({"message"=>String, "name"=>nil}) assert_equal(2, tmpl.size) assert(tmpl.match({"message"=>"Hello", "name"=>"Foo"})) assert(!tmpl.match({"message"=>"Hello", "name"=>"Foo", "1"=>2})) assert(!tmpl.match({"message"=>"Hi", "name"=>"Foo", "age"=>1})) assert(!tmpl.match({"message"=>"Hello", "no_name"=>"Foo"})) assert_raises(Rinda::InvalidHashTupleKey) do @ts.write({:message=>String, "name"=>String}) end @ts.write([1, 2, 3]) assert_equal([1, 2, 3], @ts.take([1, 2, 3])) @ts.write({'1'=>1, '2'=>2, '3'=>3}) assert_equal({'1'=>1, '2'=>2, '3'=>3}, @ts.take({'1'=>1, '2'=>2, '3'=>3})) entry = @ts.write(['1'=>1, '2'=>2, '3'=>3]) assert_raises(Rinda::RequestExpiredError) do assert_equal({'1'=>1, '2'=>2, '3'=>3}, @ts.read({'1'=>1}, 0)) end entry.cancel end def test_00_DRbObject ro = DRbObject.new(nil, "druby://host:1234") tmpl = Rinda::DRbObjectTemplate.new assert(tmpl === ro) tmpl = Rinda::DRbObjectTemplate.new("druby://host:1234") assert(tmpl === ro) tmpl = Rinda::DRbObjectTemplate.new("druby://host:12345") assert(!(tmpl === ro)) tmpl = Rinda::DRbObjectTemplate.new(/^druby:\/\/host:/) assert(tmpl === ro) ro = DRbObject.new_with(12345, 1234) assert(!(tmpl === ro)) ro = DRbObject.new_with("druby://foo:12345", 1234) assert(!(tmpl === ro)) tmpl = Rinda::DRbObjectTemplate.new(/^druby:\/\/(foo|bar):/) assert(tmpl === ro) ro = DRbObject.new_with("druby://bar:12345", 1234) assert(tmpl === ro) ro = DRbObject.new_with("druby://baz:12345", 1234) assert(!(tmpl === ro)) end def test_inp_rdp assert_raises(Rinda::RequestExpiredError) do @ts.take([:empty], 0) end assert_raises(Rinda::RequestExpiredError) do @ts.read([:empty], 0) end end def test_ruby_talk_264062 th = Thread.new { @ts.take([:empty], 1) } sleep(10) assert_raises(Rinda::RequestExpiredError) do thread_join(th) end th = Thread.new { @ts.read([:empty], 1) } sleep(10) assert_raises(Rinda::RequestExpiredError) do thread_join(th) end end def test_symbol_tuple @ts.write([:symbol, :symbol]) @ts.write(['string', :string]) assert_equal([[:symbol, :symbol]], @ts.read_all([:symbol, nil])) assert_equal([[:symbol, :symbol]], @ts.read_all([Symbol, nil])) assert_equal([], @ts.read_all([:nil, nil])) end def test_core_01 5.times do |n| @ts.write([:req, 2]) end assert_equal([[:req, 2], [:req, 2], [:req, 2], [:req, 2], [:req, 2]], @ts.read_all([nil, nil])) taker = Thread.new do s = 0 while true begin tuple = @ts.take([:req, Integer], 1) assert_equal(2, tuple[1]) s += tuple[1] rescue Rinda::RequestExpiredError break end end @ts.write([:ans, s]) s end assert_equal(10, thread_join(taker)) tuple = @ts.take([:ans, nil]) assert_equal(10, tuple[1]) end def test_core_02 taker = Thread.new do s = 0 while true begin tuple = @ts.take([:req, Integer], 1) assert_equal(2, tuple[1]) s += tuple[1] rescue Rinda::RequestExpiredError break end end @ts.write([:ans, s]) s end 5.times do |n| @ts.write([:req, 2]) end assert_equal(10, thread_join(taker)) tuple = @ts.take([:ans, nil]) assert_equal(10, tuple[1]) assert_equal([], @ts.read_all([nil, nil])) end def test_core_03_notify notify1 = @ts.notify(nil, [:req, Integer]) notify2 = @ts.notify(nil, [:ans, Integer], 8) notify3 = @ts.notify(nil, {"message"=>String, "name"=>String}, 8) @ts.write({"message"=>"first", "name"=>"3"}, 3) @ts.write({"message"=>"second", "name"=>"1"}, 1) @ts.write({"message"=>"third", "name"=>"0"}) @ts.take({"message"=>"third", "name"=>"0"}) listener1 = Thread.new do lv = 0 n = 0 notify1.each do |ev, tuple| n += 1 if ev == 'write' lv = lv + 1 elsif ev == 'take' lv = lv - 1 else break end assert(lv >= 0) assert_equal([:req, 2], tuple) end [lv, n] end listener2 = Thread.new do result = nil lv = 0 n = 0 notify2.each do |ev, tuple| n += 1 if ev == 'write' lv = lv + 1 elsif ev == 'take' lv = lv - 1 elsif ev == 'close' result = [lv, n] else break end assert(lv >= 0) assert_equal([:ans, 10], tuple) end result end taker = Thread.new do s = 0 while true begin tuple = @ts.take([:req, Integer], 1) s += tuple[1] rescue Rinda::RequestExpiredError break end end @ts.write([:ans, s]) s end 5.times do |n| @ts.write([:req, 2]) end @ts.take({"message"=>"first", "name"=>"3"}) sleep(4) assert_equal(10, thread_join(taker)) # notify2 must not expire until this @ts.take. # sleep(4) might be short enough for the timeout of notify2 (8 secs) tuple = @ts.take([:ans, nil]) assert_equal(10, tuple[1]) assert_equal([], @ts.read_all([nil, nil])) notify1.cancel sleep(7) # notify2 expired (sleep(4)+sleep(7) > 8) assert_equal([0, 11], thread_join(listener1)) assert_equal([0, 3], thread_join(listener2)) ary = [] ary.push(["write", {"message"=>"first", "name"=>"3"}]) ary.push(["write", {"message"=>"second", "name"=>"1"}]) ary.push(["write", {"message"=>"third", "name"=>"0"}]) ary.push(["take", {"message"=>"third", "name"=>"0"}]) ary.push(["take", {"message"=>"first", "name"=>"3"}]) ary.push(["delete", {"message"=>"second", "name"=>"1"}]) ary.push(["close"]) notify3.each do |ev| assert_equal(ary.shift, ev) end assert_equal([], ary) end def test_cancel_01 entry = @ts.write([:removeme, 1]) assert_equal([[:removeme, 1]], @ts.read_all([nil, nil])) entry.cancel assert_equal([], @ts.read_all([nil, nil])) template = nil taker = Thread.new do @ts.take([:take, nil], 10) do |template| Thread.new do template.cancel end end end sleep(2) assert_raises(Rinda::RequestCanceledError) do assert_nil(thread_join(taker)) end assert(template.canceled?) @ts.write([:take, 1]) assert_equal([[:take, 1]], @ts.read_all([nil, nil])) end def test_cancel_02 entry = @ts.write([:removeme, 1]) assert_equal([[:removeme, 1]], @ts.read_all([nil, nil])) entry.cancel assert_equal([], @ts.read_all([nil, nil])) template = nil reader = Thread.new do @ts.read([:take, nil], 10) do |template| Thread.new do template.cancel end end end sleep(2) assert_raises(Rinda::RequestCanceledError) do assert_nil(thread_join(reader)) end assert(template.canceled?) @ts.write([:take, 1]) assert_equal([[:take, 1]], @ts.read_all([nil, nil])) end class SimpleRenewer def initialize(sec, n = 1) @sec = sec @n = n end def renew return -1 if @n <= 0 @n -= 1 return @sec end end def test_00_renewer tuple = Rinda::TupleEntry.new([1,2,3], true) assert(!tuple.canceled?) assert(tuple.expired?) assert(!tuple.alive?) tuple = Rinda::TupleEntry.new([1,2,3], 1) assert(!tuple.canceled?) assert(!tuple.expired?) assert(tuple.alive?) sleep(2) assert(tuple.expired?) assert(!tuple.alive?) @renewer = SimpleRenewer.new(1,2) tuple = Rinda::TupleEntry.new([1,2,3], @renewer) assert(!tuple.canceled?) assert(!tuple.expired?) assert(tuple.alive?) sleep(1) assert(!tuple.canceled?) assert(!tuple.expired?) assert(tuple.alive?) sleep(2) assert(tuple.expired?) assert(!tuple.alive?) end end class TupleSpaceTest < Test::Unit::TestCase include TupleSpaceTestModule def setup ThreadGroup.new.add(Thread.current) @ts = Rinda::TupleSpace.new(1) end end class TupleSpaceProxyTest < Test::Unit::TestCase include TupleSpaceTestModule def setup ThreadGroup.new.add(Thread.current) @ts_base = Rinda::TupleSpace.new(1) @ts = Rinda::TupleSpaceProxy.new(@ts_base) end def test_remote_array_and_hash @ts.write(DRbObject.new([1, 2, 3])) assert_equal([1, 2, 3], @ts.take([1, 2, 3], 0)) @ts.write(DRbObject.new({'head' => 1, 'tail' => 2})) assert_equal({'head' => 1, 'tail' => 2}, @ts.take({'head' => 1, 'tail' => 2}, 0)) end @server = DRb.primary_server || DRb.start_service end end ================================================ FILE: test/rss/rss-assertions.rb ================================================ require 'erb' module RSS module Assertions def assert_parse(rss, assert_method, *args) __send__("assert_#{assert_method}", *args) do ::RSS::Parser.parse(rss) end __send__("assert_#{assert_method}", *args) do ::RSS::Parser.parse(rss, false).validate end end def assert_ns(prefix, uri) _wrap_assertion do begin yield flunk("Not raise NSError") rescue ::RSS::NSError => e assert_equal(prefix, e.prefix) assert_equal(uri, e.uri) end end end def assert_missing_tag(tag, parent) _wrap_assertion do begin yield flunk("Not raise MissingTagError") rescue ::RSS::MissingTagError => e assert_equal(tag, e.tag) assert_equal(parent, e.parent) end end end def assert_too_much_tag(tag, parent) _wrap_assertion do begin yield flunk("Not raise TooMuchTagError") rescue ::RSS::TooMuchTagError => e assert_equal(tag, e.tag) assert_equal(parent, e.parent) end end end def assert_missing_attribute(tag, attrname) _wrap_assertion do begin yield flunk("Not raise MissingAttributeError") rescue ::RSS::MissingAttributeError => e assert_equal(tag, e.tag) assert_equal(attrname, e.attribute) end end end def assert_not_expected_tag(tag, uri, parent) _wrap_assertion do begin yield flunk("Not raise NotExpectedTagError") rescue ::RSS::NotExpectedTagError => e assert_equal(tag, e.tag) assert_equal(uri, e.uri) assert_equal(parent, e.parent) end end end def assert_not_available_value(tag, value, attribute=nil) _wrap_assertion do begin yield flunk("Not raise NotAvailableValueError") rescue ::RSS::NotAvailableValueError => e assert_equal(tag, e.tag) assert_equal(value, e.value) assert_equal(attribute, e.attribute) end end end def assert_not_set_error(name, variables) _wrap_assertion do begin yield flunk("Not raise NotSetError") rescue ::RSS::NotSetError => e assert_equal(name, e.name) assert_kind_of(Array, variables) assert_equal(variables.sort, e.variables.sort) end end end def assert_xml_declaration(version, encoding, standalone, rss) _wrap_assertion do assert_equal(version, rss.version) assert_equal(encoding, rss.encoding) assert_equal(standalone, rss.standalone) end end def assert_xml_stylesheet_attrs(attrs, xsl) _wrap_assertion do n_attrs = normalized_attrs(attrs) ::RSS::XMLStyleSheet::ATTRIBUTES.each do |name| assert_equal(n_attrs[name], xsl.__send__(name)) end end end def assert_xml_stylesheet(target, attrs, xsl) _wrap_assertion do if attrs.has_key?(:href) if !attrs.has_key?(:type) and attrs.has_key?(:guess_type) attrs[:type] = attrs[:guess_type] end assert_equal("xml-stylesheet", target) assert_xml_stylesheet_attrs(attrs, xsl) else assert_nil(target) assert_equal("", xsl.to_s) end end end def assert_xml_stylesheet_pis(attrs_ary, rss=nil) _wrap_assertion do if rss.nil? rss = ::RSS::RDF.new setup_rss10(rss) end xss_strs = [] attrs_ary.each do |attrs| xss = ::RSS::XMLStyleSheet.new(attrs) xss_strs.push(xss.to_s) rss.xml_stylesheets.push(xss) end pi_str = rss.to_s.gsub(/<\?xml .*\n/, "").gsub(/\s*<[^\?].*\z/m, "") assert_equal(xss_strs.join("\n"), pi_str) end end def assert_xml_stylesheets(attrs, xss) _wrap_assertion do xss.each_with_index do |xs, i| assert_xml_stylesheet_attrs(attrs[i], xs) end end end def assert_atom_person(tag_name, generator) _wrap_assertion do name = "Mark Pilgrim" uri = "http://example.org/" email = "f8dy@example.com" assert_parse(generator.call(<<-EOA), :missing_tag, "name", tag_name) <#{tag_name}/> EOA assert_parse(generator.call(<<-EOA), :missing_tag, "name", tag_name) <#{tag_name}> #{uri} #{email} EOA assert_parse(generator.call(<<-EOA), :nothing_raised) <#{tag_name}> #{name} EOA feed = RSS::Parser.parse(generator.call(<<-EOA)) <#{tag_name}> #{name} #{uri} #{email} EOA person = yield(feed) assert_not_nil(person) assert_equal(name, person.name.content) assert_equal(uri, person.uri.content) assert_equal(email, person.email.content) end end def assert_atom_category(generator) _wrap_assertion do term = "Music" scheme = "http://xmlns.com/wordnet/1.6/" label = "music" missing_args = [:missing_attribute, "category", "term"] assert_parse(generator.call(<<-EOA), *missing_args) EOA assert_parse(generator.call(<<-EOA), *missing_args) EOA assert_parse(generator.call(<<-EOA), :nothing_raised) EOA feed = RSS::Parser.parse(generator.call(<<-EOA)) EOA category = yield(feed) assert_not_nil(category) assert_equal(term, category.term) assert_equal(scheme, category.scheme) assert_equal(label, category.label) end end def assert_atom_link(generator) _wrap_assertion do href = "http://example.org/feed.atom" rel = "self" type = "application/atom+xml" hreflang = "en" title = "Atom" length = "1024" assert_parse(generator.call(<<-EOA), :missing_attribute, "link", "href") EOA assert_parse(generator.call(<<-EOA), :missing_attribute, "link", "href") EOA assert_parse(generator.call(<<-EOA), :nothing_raised) EOA feed = RSS::Parser.parse(generator.call(<<-EOA)) EOA link = yield(feed) assert_not_nil(link) assert_equal(href, link.href) assert_equal(rel, link.rel) assert_equal(type, link.type) assert_equal(hreflang, link.hreflang) assert_equal(title, link.title) assert_equal(length, link.length) href = "http://example.org/index.html.ja" parent = link.parent.tag_name return if parent == "source" optional_attributes = %w(hreflang="ja" type="text/html") 0.upto(optional_attributes.size) do |i| combination(optional_attributes, i).each do |attributes| attrs = attributes.join(" ") assert_parse(generator.call(<<-EOA), :too_much_tag, "link", parent) EOA end end end end def assert_atom_generator(generator) _wrap_assertion do uri = "http://www.example.com/" version = "1.0" content = "Example Toolkit" assert_parse(generator.call(<<-EOA), :nothing_raised) EOA assert_parse(generator.call(<<-EOA), :nothing_raised) EOA feed = RSS::Parser.parse(generator.call(<<-EOA)) #{content} EOA gen = yield(feed) assert_not_nil(gen) assert_equal(uri, gen.uri) assert_equal(version, gen.version) assert_equal(content, gen.content) end end def assert_atom_icon(generator) _wrap_assertion do content = "http://www.example.com/example.png" assert_parse(generator.call(<<-EOA), :nothing_raised) EOA feed = RSS::Parser.parse(generator.call(<<-EOA)) #{content} EOA icon = yield(feed) assert_not_nil(icon) assert_equal(content, icon.content) end end def assert_atom_text_construct(tag_name, generator) _wrap_assertion do [nil, "text", "html"].each do |type| attr = "" attr = " type=\"#{type}\""if type assert_parse(generator.call(<<-EOA), :nothing_raised) <#{tag_name}#{attr}/> EOA end assert_parse(generator.call(<<-EOA), :missing_tag, "div", tag_name) <#{tag_name} type="xhtml"/> EOA args = ["x", Atom::URI, tag_name] assert_parse(generator.call(<<-EOA), :not_expected_tag, *args) <#{tag_name} type="xhtml"> EOA invalid_value = "invalid" args = ["type", invalid_value] assert_parse(generator.call(<<-EOA), :not_available_value, *args) <#{tag_name} type="#{invalid_value}"/> EOA [ [nil, "A lot of effort went into making this effortless"], ["text", "A lot of effort went into making this effortless"], ["html", "A lot of effort went into making this effortless"], ].each do |type, content| attr = "" attr = " type=\"#{type}\"" if type feed = RSS::Parser.parse(generator.call(<<-EOA)) <#{tag_name}#{attr}>#{h content} EOA element = yield(feed) assert_not_nil(element) assert_equal(type, element.type) assert_equal(content, element.content) end [false, true].each do |with_space| xhtml_uri = "http://www.w3.org/1999/xhtml" xhtml_content = "
      abc
      " xhtml_element = RSS::XML::Element.new("div", nil, xhtml_uri, {"xmlns" => xhtml_uri}, ["abc"]) content = xhtml_content content = " #{content} " if with_space feed = RSS::Parser.parse(generator.call(<<-EOA)) <#{tag_name} type="xhtml">#{content} EOA element = yield(feed) assert_not_nil(element) assert_equal("xhtml", element.type) assert_equal(xhtml_content, element.content) assert_equal(xhtml_element, element.xhtml) end end end def assert_atom_date_construct(tag_name, generator) _wrap_assertion do args = [tag_name, ""] assert_parse(generator.call(<<-EOR), :not_available_value, *args) <#{tag_name}/> EOR [ ["xxx", false], ["2007", false], ["2007/02/09", true], ].each do |invalid_value, can_parse| assert_not_available_value(tag_name, invalid_value) do RSS::Parser.parse(generator.call(<<-EOR)) <#{tag_name}>#{invalid_value} EOR end feed = RSS::Parser.parse(generator.call(<<-EOR), false) <#{tag_name}>#{invalid_value} EOR value = yield(feed).content if can_parse assert_equal(Time.parse(invalid_value), value) else assert_nil(value) end end [ "2003-12-13T18:30:02Z", "2003-12-13T18:30:02.25Z", "2003-12-13T18:30:02+01:00", "2003-12-13T18:30:02.25+01:00", ].each do |valid_value| assert_parse(generator.call(<<-EOR), :nothing_raised) <#{tag_name}>#{valid_value} EOR feed = RSS::Parser.parse(generator.call(<<-EOR)) <#{tag_name}>#{valid_value} EOR assert_equal(Time.parse(valid_value), yield(feed).content) end end end def assert_atom_logo(generator) _wrap_assertion do content = "http://www.example.com/example.png" assert_parse(generator.call(<<-EOA), :nothing_raised) EOA feed = RSS::Parser.parse(generator.call(<<-EOA)) #{content} EOA logo = yield(feed) assert_not_nil(logo) assert_equal(content, logo.content) end end def assert_atom_content(generator, &getter) _wrap_assertion do assert_atom_content_inline_text(generator, &getter) assert_atom_content_inline_xhtml(generator, &getter) assert_atom_content_inline_other(generator, &getter) assert_atom_content_out_of_line(generator, &getter) end end def assert_atom_content_inline_text(generator) _wrap_assertion do [nil, "text", "html"].each do |type| content = "sample
      content"] ].each do |type, content_content| feed = RSS::Parser.parse(generator.call(<<-EOA)) #{h content_content} EOA content = yield(feed) assert_equal(type, content.type) if %w(text html).include?(type) assert(content.inline_text?) else assert(!content.inline_text?) end if type == "html" assert(content.inline_html?) else assert(!content.inline_html?) end assert(!content.inline_xhtml?) if type == "text/plain" assert(content.inline_other?) assert(content.inline_other_text?) else assert(!content.inline_other?) assert(!content.inline_other_text?) end assert(!content.inline_other_xml?) assert(!content.inline_other_base64?) assert(!content.out_of_line?) assert(!content.have_xml_content?) assert_equal(content_content, content.content) end end end def assert_atom_content_inline_xhtml(generator) _wrap_assertion do args = ["div", "content"] assert_parse(generator.call(<<-EOA), :missing_tag, *args) EOA args = ["x", Atom::URI, "content"] assert_parse(generator.call(<<-EOA), :not_expected_tag, *args) EOA xhtml_uri = "http://www.w3.org/1999/xhtml" xhtml_content = "
      abc
      " xhtml_element = RSS::XML::Element.new("div", nil, xhtml_uri, {"xmlns" => xhtml_uri}, ["abc"]) feed = RSS::Parser.parse(generator.call(<<-EOA)) #{xhtml_content} EOA content = yield(feed) assert_not_nil(content) assert_equal("xhtml", content.type) assert(!content.inline_text?) assert(!content.inline_html?) assert(content.inline_xhtml?) assert(!content.inline_other?) assert(!content.inline_other_text?) assert(!content.inline_other_xml?) assert(!content.inline_other_base64?) assert(!content.out_of_line?) assert(content.have_xml_content?) assert_equal(xhtml_content, content.content) assert_equal(xhtml_element, content.xhtml) end end def assert_atom_content_inline_other(generator, &getter) _wrap_assertion do assert_atom_content_inline_other_text(generator, &getter) assert_atom_content_inline_other_xml(generator, &getter) end end def assert_atom_content_inline_other_text(generator) _wrap_assertion do type = "image/png" assert_parse(generator.call(<<-EOA), :nothing_raised) EOA png_file = File.join(File.dirname(__FILE__), "dot.png") png = File.open(png_file, "rb") {|file| file.read} base64_content = [png].pack("m") [false, true].each do |with_space| xml_content = base64_content xml_content = " #{base64_content}" if with_space feed = RSS::Parser.parse(generator.call(<<-EOA)) #{xml_content} EOA content = yield(feed) assert_not_nil(content) assert_equal(type, content.type) assert(!content.inline_text?) assert(!content.inline_html?) assert(!content.inline_xhtml?) assert(content.inline_other?) assert(!content.inline_other_text?) assert(!content.inline_other_xml?) assert(content.inline_other_base64?) assert(!content.out_of_line?) assert(!content.have_xml_content?) assert_equal(png, content.content) xml = REXML::Document.new(content.to_s).root assert_rexml_element([], {"type" => type}, base64_content, xml) end end end def assert_atom_content_inline_other_xml(generator) _wrap_assertion do type = "image/svg+xml" assert_parse(generator.call(<<-EOA), :nothing_raised) EOA svg_uri = "http://www.w3.org/2000/svg" svg_width = "50pt" svg_height = "20pt" svg_version = "1.0" text_x = "15" text_y = "15" text = "text" svg_content = <<-EOS #{text} EOS text_element = RSS::XML::Element.new("text", nil, svg_uri, { "x" => text_x, "y" => text_y, }, [text]) svg_element = RSS::XML::Element.new("svg", nil, svg_uri, { "xmlns" => svg_uri, "width" => svg_width, "height" => svg_height, "version" => svg_version, }, [text_element]) feed = RSS::Parser.parse(generator.call(<<-EOA)) #{svg_content} EOA content = yield(feed) assert_not_nil(content) assert_equal(type, content.type) assert(!content.inline_text?) assert(!content.inline_html?) assert(!content.inline_xhtml?) assert(content.inline_other?) assert(!content.inline_other_text?) assert(content.inline_other_xml?) assert(!content.inline_other_base64?) assert(!content.out_of_line?) assert(content.have_xml_content?) assert_equal(REXML::Document.new(svg_content).to_s.chomp, REXML::Document.new(content.content).to_s.chomp) assert_equal(svg_element, content.xml) assert_nil(content.xhtml) end end def assert_atom_content_out_of_line(generator) _wrap_assertion do text_type = "text/plain" text_src = "http://example.com/README.txt" missing_args = [:missing_attribute, "content", "type"] # RSS Parser raises error even if this is "should" not "must". assert_parse(generator.call(<<-EOA), *missing_args) EOA content_content = "xxx" not_available_value_args = [:not_available_value, "content", content_content] assert_parse(generator.call(<<-EOA), *not_available_value_args) #{content_content} EOA feed = RSS::Parser.parse(generator.call(<<-EOA)) EOA content = yield(feed) assert_not_nil(content) assert_equal(text_type, content.type) assert_equal(text_src, content.src) assert(!content.inline_text?) assert(!content.inline_html?) assert(!content.inline_xhtml?) assert(!content.inline_other?) assert(!content.inline_other_text?) assert(!content.inline_other_xml?) assert(!content.inline_other_base64?) assert(content.out_of_line?) assert(!content.have_xml_content?) assert_nil(content.xml) assert_nil(content.xhtml) assert_equal("", content.content) end end def assert_atom_source(generator, &getter) _wrap_assertion do assert_atom_source_author(generator, &getter) assert_atom_source_category(generator, &getter) assert_atom_source_contributor(generator, &getter) assert_atom_source_generator(generator, &getter) assert_atom_source_icon(generator, &getter) assert_atom_source_id(generator, &getter) assert_atom_source_link(generator, &getter) assert_atom_source_logo(generator, &getter) assert_atom_source_rights(generator, &getter) assert_atom_source_subtitle(generator, &getter) assert_atom_source_title(generator, &getter) assert_atom_source_updated(generator, &getter) end end def assert_atom_source_author(generator) assert_atom_person("author", generator) do |feed| source = yield(feed) assert_equal(1, source.authors.size) source.author end end def assert_atom_source_category(generator) assert_atom_category(generator) do |feed| source = yield(feed) assert_equal(1, source.categories.size) source.category end end def assert_atom_source_contributor(generator) assert_atom_person("contributor", generator) do |feed| source = yield(feed) assert_equal(1, source.contributors.size) source.contributor end end def assert_atom_source_generator(generator) assert_atom_generator(generator) do |feed| yield(feed).generator end end def assert_atom_source_icon(generator) assert_atom_icon(generator) do |feed| yield(feed).icon end end def assert_atom_source_id(generator) id_content = "urn:uuid:a2fb588b-5674-4898-b420-265a734fea69" id = "#{id_content}" feed = RSS::Parser.parse(generator.call(id)) assert_equal(id_content, yield(feed).id.content) end def assert_atom_source_link(generator) assert_atom_link(generator) do |feed| source = yield(feed) assert_equal(1, source.links.size) source.link end end def assert_atom_source_logo(generator) assert_atom_logo(generator) do |feed| yield(feed).logo end end def assert_atom_source_rights(generator) assert_atom_text_construct("rights", generator) do |feed| yield(feed).rights end end def assert_atom_source_subtitle(generator) assert_atom_text_construct("subtitle", generator) do |feed| yield(feed).subtitle end end def assert_atom_source_title(generator) assert_atom_text_construct("title", generator) do |feed| yield(feed).title end end def assert_atom_source_updated(generator) assert_atom_date_construct("updated", generator) do |feed| yield(feed).updated end end def assert_dublin_core(elems, target) _wrap_assertion do elems.each do |name, value| assert_equal(value, target.__send__("dc_#{name}")) end end end def assert_multiple_dublin_core(elems, target) _wrap_assertion do elems.each do |name, values, plural| plural ||= "#{name}s" actual = target.__send__("dc_#{plural}").collect{|x| x.value} assert_equal(values, actual) end end end def assert_syndication(elems, target) _wrap_assertion do elems.each do |name, value| meth = "sy_#{name}" value = value.to_i if meth == "sy_updateFrequency" assert_equal(value, target.__send__(meth )) end end end def assert_content(elems, target) _wrap_assertion do elems.each do |name, value| assert_equal(value, target.__send__("content_#{name}")) end end end def assert_trackback(attrs, target) _wrap_assertion do n_attrs = normalized_attrs(attrs) if n_attrs["ping"] assert_equal(n_attrs["ping"], target.trackback_ping) end if n_attrs["abouts"] n_attrs["abouts"].each_with_index do |about, i| assert_equal(about, target.trackback_abouts[i].value) end end end end def assert_taxo_topic(topics, target) _wrap_assertion do topics.each_with_index do |topic, i| taxo_topic = target.taxo_topics[i] topic.each do |name, value| case name when :link assert_equal(value, taxo_topic.about) assert_equal(value, taxo_topic.taxo_link) when :topics assert_equal(value, taxo_topic.taxo_topics.resources) else assert_equal(value, taxo_topic.__send__("dc_#{name}")) end end end end end def assert_attributes(attrs, names, target) _wrap_assertion do n_attrs = normalized_attrs(attrs) names.each do |info| if info.is_a?(String) name = info type = nil else name, type = info end value = n_attrs[name] if value.is_a?(Time) actual = target.__send__(name) assert_instance_of(Time, actual) assert_equal(value.to_i, actual.to_i) elsif value case type when :integer value = value.to_i when :boolean value = value == "true" if value.is_a?(String) end assert_equal(value, target.__send__(name)) end end end end def assert_rexml_element(children, attrs, text, element, text_type=nil) _wrap_assertion do if children children_info = element.elements.collect {|e| [e.namespace, e.name]} assert_equal(children.collect {|uri, name| [uri, name]}.sort, children_info.sort) end if attrs assert_equal(attrs.collect {|k, v| [k, v]}.sort, element.attributes.collect {|k, v| [k, v]}.sort) end case text_type when :time assert_not_nil(element.text) assert_equal(Time.parse(text).to_s, Time.parse(element.text).to_s) else assert_equal(text, element.text) end end end def _assert_maker_atom_persons(feed_type, maker_readers, feed_readers) _wrap_assertion do persons = [] feed = RSS::Maker.make("atom:#{feed_type}") do |maker| yield maker targets = chain_reader(maker, maker_readers) targets.each do |target| person = { :name => target.name, :uri => target.uri, :email => target.email, } persons << person if person[:name] end end actual_persons = chain_reader(feed, feed_readers) || [] actual_persons = actual_persons.collect do |person| { :name => person.name ? person.name.content : nil, :uri => person.uri ? person.uri.content : nil, :email => person.email ? person.email.content : nil, } end assert_equal(persons, actual_persons) end end def assert_maker_atom_persons(feed_type, maker_readers, feed_readers, not_set_error_name=nil, parent_not_set_error_name=nil, parent_not_set_variable=nil) _wrap_assertion do not_set_error_name ||= "maker.#{maker_readers.join('.')}" args = [feed_type, maker_readers, feed_readers] if parent_not_set_error_name or parent_not_set_variable assert_not_set_error(parent_not_set_error_name, parent_not_set_variable) do _assert_maker_atom_persons(*args) do |maker| yield maker end end else _assert_maker_atom_persons(*args) do |maker| yield maker end end assert_not_set_error(not_set_error_name, %w(name)) do _assert_maker_atom_persons(feed_type, maker_readers, feed_readers) do |maker| yield maker targets = chain_reader(maker, maker_readers) target = targets.new_child end end assert_not_set_error(not_set_error_name, %w(name)) do _assert_maker_atom_persons(feed_type, maker_readers, feed_readers) do |maker| yield maker targets = chain_reader(maker, maker_readers) target = targets.new_child target.uri = "http://example.com/~me/" end end assert_not_set_error(not_set_error_name, %w(name)) do _assert_maker_atom_persons(feed_type, maker_readers, feed_readers) do |maker| yield maker targets = chain_reader(maker, maker_readers) target = targets.new_child target.email = "me@example.com" end end assert_not_set_error(not_set_error_name, %w(name)) do _assert_maker_atom_persons(feed_type, maker_readers, feed_readers) do |maker| yield maker targets = chain_reader(maker, maker_readers) target = targets.new_child target.uri = "http://example.com/~me/" target.email = "me@example.com" end end _assert_maker_atom_persons(feed_type, maker_readers, feed_readers) do |maker| yield maker targets = chain_reader(maker, maker_readers) target = targets.new_child target.name = "me" end _assert_maker_atom_persons(feed_type, maker_readers, feed_readers) do |maker| yield maker targets = chain_reader(maker, maker_readers) target = targets.new_child target.name = "me" target.uri = "http://example.com/~me/" end _assert_maker_atom_persons(feed_type, maker_readers, feed_readers) do |maker| yield maker targets = chain_reader(maker, maker_readers) target = targets.new_child target.name = "me" target.email = "me@example.com" end _assert_maker_atom_persons(feed_type, maker_readers, feed_readers) do |maker| yield maker targets = chain_reader(maker, maker_readers) target = targets.new_child target.name = "me" target.uri = "http://example.com/~me/" target.email = "me@example.com" end _assert_maker_atom_persons(feed_type, maker_readers, feed_readers) do |maker| yield maker targets = chain_reader(maker, maker_readers) target = targets.new_child target.name = "me" target.uri = "http://example.com/~me/" target.email = "me@example.com" target = targets.new_child target.name = "you" target.uri = "http://example.com/~you/" target.email = "you@example.com" end assert_not_set_error(not_set_error_name, %w(name)) do _assert_maker_atom_persons(feed_type, maker_readers, feed_readers) do |maker| yield maker targets = chain_reader(maker, maker_readers) target = targets.new_child target.name = "me" target.uri = "http://example.com/~me/" target.email = "me@example.com" target = targets.new_child end end end end def _assert_maker_atom_text_construct(feed_type, maker_readers, feed_readers, &block) maker_extractor = Proc.new do |target| text = { :type => target.type, :content => target.content, :xml_content => target.xml_content, } if text[:type] == "xhtml" if text[:xml_content] xml_content = text[:xml_content] xhtml_uri = "http://www.w3.org/1999/xhtml" unless xml_content.is_a?(RSS::XML::Element) and ["div", xhtml_uri] == [xml_content.name, xml_content.uri] children = xml_content children = [children] unless children.is_a?(Array) xml_content = RSS::XML::Element.new("div", nil, xhtml_uri, {"xmlns" => xhtml_uri}, children) text[:xml_content] = xml_content end text else nil end else text[:content] ? text : nil end end feed_extractor = Proc.new do |target| { :type => target.type, :content => target.content, :xml_content => target.xhtml, } end _assert_maker_atom_element(feed_type, maker_readers, feed_readers, maker_extractor, feed_extractor, &block) end def assert_maker_atom_text_construct(feed_type, maker_readers, feed_readers, parent_not_set_error_name=nil, parent_not_set_variable=nil, not_set_error_name=nil) _wrap_assertion do not_set_error_name ||= "maker.#{maker_readers.join('.')}" args = [feed_type, maker_readers, feed_readers] if parent_not_set_error_name or parent_not_set_variable assert_not_set_error(parent_not_set_error_name, parent_not_set_variable) do _assert_maker_atom_text_construct(*args) do |maker| yield maker end end else _assert_maker_atom_text_construct(*args) do |maker| yield maker end end assert_not_set_error(not_set_error_name, %w(content)) do _assert_maker_atom_text_construct(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) {|x| x} target.type = "text" end end assert_not_set_error(not_set_error_name, %w(content)) do _assert_maker_atom_text_construct(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) {|x| x} target.type = "html" end end assert_not_set_error(not_set_error_name, %w(xml_content)) do _assert_maker_atom_text_construct(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) {|x| x} target.type = "xhtml" end end assert_not_set_error(not_set_error_name, %w(xml_content)) do _assert_maker_atom_text_construct(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) {|x| x} target.type = "xhtml" target.content = "Content" end end _assert_maker_atom_text_construct(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) {|x| x} target.type = "text" target.content = "Content" end _assert_maker_atom_text_construct(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) {|x| x} target.type = "html" target.content = "Content" end _assert_maker_atom_text_construct(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) {|x| x} target.type = "xhtml" target.xml_content = "text only" end _assert_maker_atom_text_construct(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) {|x| x} target.type = "xhtml" target.xml_content = RSS::XML::Element.new("unknown") end end end def _assert_maker_atom_date_construct(feed_type, maker_readers, feed_readers, &block) maker_extractor = Proc.new do |target| date = { :content => target, } date[:content] ? date : nil end feed_extractor = Proc.new do |target| { :content => target.content, } end _assert_maker_atom_element(feed_type, maker_readers, feed_readers, maker_extractor, feed_extractor, &block) end def assert_maker_atom_date_construct(feed_type, maker_readers, feed_readers, parent_not_set_error_name=nil, parent_not_set_variable=nil) _wrap_assertion do args = [feed_type, maker_readers, feed_readers] if parent_not_set_error_name or parent_not_set_variable assert_not_set_error(parent_not_set_error_name, parent_not_set_variable) do _assert_maker_atom_date_construct(*args) do |maker| yield maker end end else _assert_maker_atom_date_construct(*args) do |maker| yield maker end end maker_readers = maker_readers.dup writer = "#{maker_readers.pop}=" _assert_maker_atom_date_construct(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) target.__send__(writer, Time.now) end end end def _assert_maker_atom_element(feed_type, maker_readers, feed_readers, maker_extractor, feed_extractor) _wrap_assertion do element = nil feed = RSS::Maker.make("atom:#{feed_type}") do |maker| yield maker target = chain_reader(maker, maker_readers) {|x| x} element = maker_extractor.call(target) end target = chain_reader(feed, feed_readers) if target actual_element = feed_extractor.call(target) else actual_element = nil end assert_equal(element, actual_element) end end def _assert_maker_atom_elements(feed_type, maker_readers, feed_readers, maker_extractor, feed_extractor, invalid_feed_checker=nil) _wrap_assertion do elements = [] invalid_feed = false feed = RSS::Maker.make("atom:#{feed_type}") do |maker| yield maker targets = chain_reader(maker, maker_readers) targets.each do |target| element = maker_extractor.call(target) elements << element if element end if invalid_feed_checker invalid_feed = invalid_feed_checker.call(targets) end end if invalid_feed assert_nil(feed) else actual_elements = chain_reader(feed, feed_readers) || [] actual_elements = actual_elements.collect do |target| feed_extractor.call(target) end assert_equal(elements, actual_elements) end end end def assert_maker_atom_element(feed_type, maker_readers, feed_readers, setup_target, optional_variables, required_variable, assert_method_name, not_set_error_name=nil, *additional_args) _wrap_assertion do not_set_error_name ||= "maker.#{maker_readers.join('.')}" 0.upto(optional_variables.size) do |i| combination(optional_variables, i).each do |names| have = {} names.each do |name| have[name.intern] = true end have_required_variable_too = have.merge({required_variable.intern => true}) assert_not_set_error(not_set_error_name, [required_variable]) do __send__(assert_method_name, feed_type, maker_readers, feed_readers, *additional_args) do |maker| yield maker target = chain_reader(maker, maker_readers) {|x| x} setup_target.call(target, have) end end __send__(assert_method_name, feed_type, maker_readers, feed_readers, *additional_args) do |maker| yield maker target = chain_reader(maker, maker_readers) {|x| x} setup_target.call(target, have_required_variable_too) end end end end end def assert_maker_atom_elements(feed_type, maker_readers, feed_readers, setup_target, optional_variables, required_variable, assert_method_name, not_set_error_name=nil, *additional_args) _wrap_assertion do not_set_error_name ||= "maker.#{maker_readers.join('.')}" 0.upto(optional_variables.size) do |i| combination(optional_variables, i).each do |names| have = {} names.each do |name| have[name.intern] = true end have_required_variable_too = have.merge({required_variable.intern => true}) assert_not_set_error(not_set_error_name, [required_variable]) do __send__(assert_method_name, feed_type, maker_readers, feed_readers, *additional_args) do |maker| yield maker targets = chain_reader(maker, maker_readers) setup_target.call(targets, have) end end __send__(assert_method_name, feed_type, maker_readers, feed_readers, *additional_args) do |maker| yield maker targets = chain_reader(maker, maker_readers) setup_target.call(targets, have_required_variable_too) end __send__(assert_method_name, feed_type, maker_readers, feed_readers, *additional_args) do |maker| yield maker targets = chain_reader(maker, maker_readers) setup_target.call(targets, have_required_variable_too) setup_target.call(targets, have_required_variable_too) end assert_not_set_error(not_set_error_name, [required_variable]) do __send__(assert_method_name, feed_type, maker_readers, feed_readers, *additional_args) do |maker| yield maker targets = chain_reader(maker, maker_readers) setup_target.call(targets, have_required_variable_too) setup_target.call(targets, have) end end end end end end def _assert_maker_atom_categories(feed_type, maker_readers, feed_readers, &block) maker_extractor = Proc.new do |target| category = { :term => target.term, :scheme => target.scheme, :label => target.label, } category[:term] ? category : nil end feed_extractor = Proc.new do |target| { :term => target.term, :scheme => target.scheme, :label => target.label, } end _assert_maker_atom_elements(feed_type, maker_readers, feed_readers, maker_extractor, feed_extractor, &block) end def assert_maker_atom_categories(feed_type, maker_readers, feed_readers, not_set_error_name=nil, &block) _wrap_assertion do _assert_maker_atom_categories(feed_type, maker_readers, feed_readers) do |maker| yield maker end setup_target = Proc.new do |targets, have| target = targets.new_child target.term = "music" if have[:term] target.scheme = "http://example.com/category/music" if have[:scheme] target.label = "Music" if have[:label] end optional_variables = %w(scheme label) assert_maker_atom_elements(feed_type, maker_readers, feed_readers, setup_target, optional_variables, "term", :_assert_maker_atom_categories, not_set_error_name, &block) end end def _assert_maker_atom_generator(feed_type, maker_readers, feed_readers, &block) maker_extractor = Proc.new do |target| generator = { :uri => target.uri, :version => target.version, :content => target.content, } generator[:content] ? generator : nil end feed_extractor = Proc.new do |target| { :uri => target.uri, :version => target.version, :content => target.content, } end _assert_maker_atom_element(feed_type, maker_readers, feed_readers, maker_extractor, feed_extractor, &block) end def assert_maker_atom_generator(feed_type, maker_readers, feed_readers, not_set_error_name=nil, &block) _wrap_assertion do not_set_error_name ||= "maker.#{maker_readers.join('.')}" _assert_maker_atom_generator(feed_type, maker_readers, feed_readers) do |maker| yield maker end setup_target = Proc.new do |target, have| target.content = "RSS Maker" if have[:content] target.uri = "http://example.com/rss/maker" if have[:uri] target.version = "0.0.1" if have[:version] end optional_variables = %w(uri version) assert_maker_atom_element(feed_type, maker_readers, feed_readers, setup_target, optional_variables, "content", :_assert_maker_atom_generator, not_set_error_name, &block) end end def _assert_maker_atom_icon(feed_type, maker_readers, feed_readers, accessor_base, &block) maker_extractor = Proc.new do |target| icon = { :content => target.__send__(accessor_base), } icon[:content] ? icon : nil end feed_extractor = Proc.new do |target| { :content => target.content, } end _assert_maker_atom_element(feed_type, maker_readers, feed_readers, maker_extractor, feed_extractor, &block) end def assert_maker_atom_icon(feed_type, maker_readers, feed_readers, accessor_base=nil, not_set_error_name=nil) _wrap_assertion do accessor_base ||= "url" not_set_error_name ||= "maker.#{maker_readers.join('.')}" _assert_maker_atom_icon(feed_type, maker_readers, feed_readers, accessor_base) do |maker| yield maker end _assert_maker_atom_icon(feed_type, maker_readers, feed_readers, accessor_base) do |maker| yield maker target = chain_reader(maker, maker_readers) target.__send__("#{accessor_base}=", "http://example.com/icon.png") end end end def _assert_maker_atom_links(feed_type, maker_readers, feed_readers, allow_duplication=false, &block) maker_extractor = Proc.new do |target| link = { :href => target.href, :rel => target.rel, :type => target.type, :hreflang => target.hreflang, :title => target.title, :length => target.length, } link[:href] ? link : nil end feed_extractor = Proc.new do |target| { :href => target.href, :rel => target.rel, :type => target.type, :hreflang => target.hreflang, :title => target.title, :length => target.length, } end invalid_feed_checker = Proc.new do |targets| infos = {} invalid = false targets.each do |target| key = [target.hreflang, target.type] if infos.has_key?(key) invalid = true break end infos[key] = true if target.rel.nil? or target.rel == "alternate" end invalid end invalid_feed_checker = nil if allow_duplication _assert_maker_atom_elements(feed_type, maker_readers, feed_readers, maker_extractor, feed_extractor, invalid_feed_checker, &block) end def assert_maker_atom_links(feed_type, maker_readers, feed_readers, not_set_error_name=nil, allow_duplication=false, &block) _wrap_assertion do _assert_maker_atom_links(feed_type, maker_readers, feed_readers) do |maker| yield maker end langs = %(ja en fr zh po) setup_target = Proc.new do |targets, have| target = targets.new_child lang = langs[targets.size % langs.size] target.href = "http://example.com/index.html.#{lang}" if have[:href] target.rel = "alternate" if have[:rel] target.type = "text/xhtml" if have[:type] target.hreflang = lang if have[:hreflang] target.title = "FrontPage(#{lang})" if have[:title] target.length = 1024 if have[:length] end optional_variables = %w(rel type hreflang title length) assert_maker_atom_elements(feed_type, maker_readers, feed_readers, setup_target, optional_variables, "href", :_assert_maker_atom_links, not_set_error_name, allow_duplication, &block) end end def _assert_maker_atom_logo(feed_type, maker_readers, feed_readers, accessor_base, &block) maker_extractor = Proc.new do |target| logo = { :uri => target.__send__(accessor_base), } logo[:uri] ? logo : nil end feed_extractor = Proc.new do |target| { :uri => target.content, } end _assert_maker_atom_element(feed_type, maker_readers, feed_readers, maker_extractor, feed_extractor, &block) end def assert_maker_atom_logo(feed_type, maker_readers, feed_readers, accessor_base=nil, not_set_error_name=nil) _wrap_assertion do accessor_base ||= "uri" not_set_error_name ||= "maker.#{maker_readers.join('.')}" _assert_maker_atom_logo(feed_type, maker_readers, feed_readers, accessor_base) do |maker| yield maker end _assert_maker_atom_logo(feed_type, maker_readers, feed_readers, accessor_base) do |maker| yield maker target = chain_reader(maker, maker_readers) target.__send__("#{accessor_base}=", "http://example.com/logo.png") end end end def _assert_maker_atom_id(feed_type, maker_readers, feed_readers, &block) maker_extractor = Proc.new do |target| id = { :uri => target.id, } id[:uri] ? id : nil end feed_extractor = Proc.new do |target| if target.id { :uri => target.id.content, } else nil end end _assert_maker_atom_element(feed_type, maker_readers, feed_readers, maker_extractor, feed_extractor, &block) end def assert_maker_atom_id(feed_type, maker_readers, feed_readers, not_set_error_name=nil) _wrap_assertion do not_set_error_name ||= "maker.#{maker_readers.join('.')}" args = [feed_type, maker_readers, feed_readers] _assert_maker_atom_id(*args) do |maker| yield maker end _assert_maker_atom_id(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) target.id = "http://example.com/id/1" end end end def _assert_maker_atom_content(feed_type, maker_readers, feed_readers, &block) maker_extractor = Proc.new do |target| content = { :type => target.type, :src => target.src, :content => target.content, :xml => target.xml, :inline_text => target.inline_text?, :inline_html => target.inline_html?, :inline_xhtml => target.inline_xhtml?, :inline_other => target.inline_other?, :inline_other_text => target.inline_other_text?, :inline_other_xml => target.inline_other_xml?, :inline_other_base64 => target.inline_other_base64?, :out_of_line => target.out_of_line?, } content[:src] = nil if content[:src] and content[:content] if content[:type] or content[:content] content else nil end end feed_extractor = Proc.new do |target| { :type => target.type, :src => target.src, :content => target.content, :xml => target.xml, :inline_text => target.inline_text?, :inline_html => target.inline_html?, :inline_xhtml => target.inline_xhtml?, :inline_other => target.inline_other?, :inline_other_text => target.inline_other_text?, :inline_other_xml => target.inline_other_xml?, :inline_other_base64 => target.inline_other_base64?, :out_of_line => target.out_of_line?, } end _assert_maker_atom_element(feed_type, maker_readers, feed_readers, maker_extractor, feed_extractor, &block) end def assert_maker_atom_content(feed_type, maker_readers, feed_readers, not_set_error_name=nil, &block) _wrap_assertion do not_set_error_name ||= "maker.#{maker_readers.join('.')}" args = [feed_type, maker_readers, feed_readers, not_set_error_name] assert_maker_atom_content_inline_text(*args, &block) assert_maker_atom_content_inline_xhtml(*args, &block) assert_maker_atom_content_inline_other(*args, &block) assert_maker_atom_content_out_of_line(*args, &block) end end def assert_maker_atom_content_inline_text(feed_type, maker_readers, feed_readers, not_set_error_name) _wrap_assertion do args = [feed_type, maker_readers, feed_readers] _assert_maker_atom_content(*args) do |maker| yield maker end assert_not_set_error(not_set_error_name, %w(content)) do RSS::Maker.make("atom:#{feed_type}") do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "text" end end assert_not_set_error(not_set_error_name, %w(content)) do RSS::Maker.make("atom:#{feed_type}") do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "html" end end _assert_maker_atom_content(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) target.content = "" end _assert_maker_atom_content(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "text" target.content = "example content" end _assert_maker_atom_content(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "html" target.content = "text" end end end def assert_maker_atom_content_inline_xhtml(feed_type, maker_readers, feed_readers, not_set_error_name) _wrap_assertion do args = [feed_type, maker_readers, feed_readers] assert_not_set_error(not_set_error_name, %w(xml_content)) do RSS::Maker.make("atom:#{feed_type}") do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "xhtml" end end assert_not_set_error(not_set_error_name, %w(xml_content)) do RSS::Maker.make("atom:#{feed_type}") do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "xhtml" target.content = "dummy" end end _assert_maker_atom_content(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "xhtml" target.xml_content = "text" end _assert_maker_atom_content(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "xhtml" target.xml = "text" end _assert_maker_atom_content(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "xhtml" target.xml_content = RSS::XML::Element.new("em", nil, nil, {}, ["text"]) end _assert_maker_atom_content(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "xhtml" target.xml = RSS::XML::Element.new("em", nil, nil, {}, ["text"]) end xhtml_uri = "http://www.w3.org/1999/xhtml" em = RSS::XML::Element.new("em", nil, nil, {}, ["text"]) em_with_xhtml_uri = RSS::XML::Element.new("em", nil, xhtml_uri, {}, ["text"]) feed = RSS::Maker.make("atom:#{feed_type}") do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "xhtml" target.xml = em end assert_equal(RSS::XML::Element.new("div", nil, xhtml_uri, {"xmlns" => xhtml_uri}, [em_with_xhtml_uri]), chain_reader(feed, feed_readers).xml) div = RSS::XML::Element.new("div", nil, xhtml_uri, {"xmlns" => xhtml_uri, "class" => "sample"}, ["text"]) feed = RSS::Maker.make("atom:#{feed_type}") do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "xhtml" target.xml = div end assert_equal(div, chain_reader(feed, feed_readers).xml) end end def assert_maker_atom_content_inline_other(*args, &block) _wrap_assertion do assert_maker_atom_content_inline_other_xml(*args, &block) assert_maker_atom_content_inline_other_text(*args, &block) assert_maker_atom_content_inline_other_base64(*args, &block) end end def assert_maker_atom_content_inline_other_xml(feed_type, maker_readers, feed_readers, not_set_error_name) _wrap_assertion do args = [feed_type, maker_readers, feed_readers] assert_not_set_error(not_set_error_name, %w(xml_content)) do RSS::Maker.make("atom:#{feed_type}") do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "application/xml" end end assert_not_set_error(not_set_error_name, %w(xml_content)) do RSS::Maker.make("atom:#{feed_type}") do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "svg/image+xml" end end svg_uri = "http://www.w3.org/2000/svg" rect = RSS::XML::Element.new("rect", nil, svg_uri, {"x" => "0.5cm", "y" => "0.5cm", "width" => "2cm", "height" => "1cm"}) svg = RSS::XML::Element.new("svg", nil, svg_uri, {"xmlns" => svg_uri, "version" => "1.1", "width" => "5cm", "height" => "4cm"}, [rect]) _assert_maker_atom_content(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "image/svg+xml" target.xml = svg end feed = RSS::Maker.make("atom:#{feed_type}") do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "image/svg+xml" target.xml = svg end assert_equal(svg, chain_reader(feed, feed_readers).xml) end end def assert_maker_atom_content_inline_other_text(feed_type, maker_readers, feed_readers, not_set_error_name) _wrap_assertion do args = [feed_type, maker_readers, feed_readers] assert_not_set_error(not_set_error_name, %w(content)) do RSS::Maker.make("atom:#{feed_type}") do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "text/plain" end end _assert_maker_atom_content(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "text/plain" target.content = "text" end end end def assert_maker_atom_content_inline_other_base64(feed_type, maker_readers, feed_readers, not_set_error_name) _wrap_assertion do args = [feed_type, maker_readers, feed_readers] content = "\211PNG\r\n\032\n" _assert_maker_atom_content(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "image/png" target.content = content end _assert_maker_atom_content(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "image/png" target.src = "http://example.com/logo.png" target.content = content end feed = RSS::Maker.make("atom:#{feed_type}") do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "image/png" target.src = "http://example.com/logo.png" target.content = content end target = chain_reader(feed, feed_readers) assert_nil(target.src) assert_equal(content, target.content) end end def assert_maker_atom_content_out_of_line(feed_type, maker_readers, feed_readers, not_set_error_name) _wrap_assertion do args = [feed_type, maker_readers, feed_readers] assert_not_set_error(not_set_error_name, %w(content)) do RSS::Maker.make("atom:#{feed_type}") do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "image/png" end end assert_not_set_error(not_set_error_name, %w(type)) do RSS::Maker.make("atom:#{feed_type}") do |maker| yield maker target = chain_reader(maker, maker_readers) target.src = "http://example.com/logo.png" end end _assert_maker_atom_content(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "image/png" target.src = "http://example.com/logo.png" end _assert_maker_atom_content(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "image/png" target.content = "\211PNG\r\n\032\n" end _assert_maker_atom_content(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "application/xml" target.src = "http://example.com/sample.xml" end _assert_maker_atom_content(*args) do |maker| yield maker target = chain_reader(maker, maker_readers) target.type = "text/plain" target.src = "http://example.com/README.txt" end end end def assert_slash_elements(expected, target) assert_equal(expected, { "section" => target.slash_section, "department" => target.slash_department, "comments" => target.slash_comments, "hit_parades" => target.slash_hit_parades, }) assert_equal(expected["hit_parades"].join(","), target.slash_hit_parade) end def chain_reader(target, readers, &block) readers.inject(target) do |result, reader| return nil if result.nil? result.__send__(reader, &block) end end def normalized_attrs(attrs) n_attrs = {} attrs.each do |name, value| n_attrs[name.to_s] = value end n_attrs end def combination(elements, n) if n <= 0 or elements.size < n [] elsif n == 1 elements.collect {|element| [element]} else first, *rest = elements combination(rest, n - 1).collect do |sub_elements| [first, *sub_elements] end + combination(rest, n) end end def tag(name, content=nil, attributes={}) attributes = attributes.collect do |key, value| "#{ERB::Util.h(key)}=\"#{ERB::Util.h(value)}\"" end.join(" ") begin_tag = "<#{name}" begin_tag << " #{attributes}" unless attributes.empty? if content "#{begin_tag}>#{content}\n" else "#{begin_tag}/>\n" end end end end ================================================ FILE: test/rss/rss-testcase.rb ================================================ require "erb" require "test/unit" require 'rss-assertions' require "rss" module RSS class TestCase < Test::Unit::TestCase include ERB::Util include RSS include Assertions XMLDECL_VERSION = "1.0" XMLDECL_ENCODING = "UTF-8" XMLDECL_STANDALONE = "no" RDF_ABOUT = "http://www.xml.com/xml/news.rss" RDF_RESOURCE = "http://xml.com/universal/images/xml_tiny.gif" TITLE_VALUE = "XML.com" LINK_VALUE = "http://xml.com/pub" URL_VALUE = "http://xml.com/universal/images/xml_tiny.gif" NAME_VALUE = "hogehoge" LANGUAGE_VALUE = "ja" DESCRIPTION_VALUE = " XML.com features a rich mix of information and services for the XML community. " RESOURCES = [ "http://xml.com/pub/2000/08/09/xslt/xslt.html", "http://xml.com/pub/2000/08/09/rdfdb/index.html", ] CLOUD_DOMAIN = "data.ourfavoritesongs.com" CLOUD_PORT = "80" CLOUD_PATH = "/RPC2" CLOUD_REGISTER_PROCEDURE = "ourFavoriteSongs.rssPleaseNotify" CLOUD_PROTOCOL = "xml-rpc" ENCLOSURE_URL = "http://www.scripting.com/mp3s/weatherReportSuite.mp3" ENCLOSURE_LENGTH = "12216320" ENCLOSURE_TYPE = "audio/mpeg" CATEGORY_DOMAIN = "http://www.superopendirectory.com/" FEED_TITLE = "dive into mark" FEED_UPDATED = "2003-12-13T18:30:02Z" FEED_AUTHOR_NAME = "John Doe" FEED_ID = "urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6" ENTRY_TITLE = "Atom-Powered Robots Run Amok" ENTRY_LINK = "http://example.org/2003/12/13/atom03" ENTRY_ID = "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a" ENTRY_UPDATED = "2003-12-13T18:30:02Z" ENTRY_SUMMARY = "Some text." t = Time.iso8601("2000-01-01T12:00:05+00:00") class << t alias_method(:to_s, :iso8601) end DC_ELEMENTS = { :title => "hoge", :description => " XML is placing increasingly heavy loads on the existing technical infrastructure of the Internet.", :creator => "Rael Dornfest (mailto:rael@oreilly.com)", :subject => "XML", :publisher => "The O'Reilly Network", :contributor => "hogehoge", :type => "fugafuga", :format => "hohoho", :identifier => "fufufu", :source => "barbar", :language => "ja", :relation => "cococo", :rights => "Copyright (c) 2000 O'Reilly & Associates, Inc.", :date => t, } DC_NODES = DC_ELEMENTS.collect do |name, value| "<#{DC_PREFIX}:#{name}>#{value}" end.join("\n") def default_test # This class isn't tested end private def make_xmldecl(v=XMLDECL_VERSION, e=XMLDECL_ENCODING, s=XMLDECL_STANDALONE) rv = "" rv end def make_RDF(content=nil, xmlns=[]) <<-EORSS #{make_xmldecl} #{block_given? ? yield : content} EORSS end def make_channel(content=nil) <<-EOC #{TITLE_VALUE} #{LINK_VALUE} #{DESCRIPTION_VALUE} #{RESOURCES.collect do |res| '' end.join("\n")} #{block_given? ? yield : content} EOC end def make_image(content=nil) <<-EOI #{TITLE_VALUE} #{URL_VALUE} #{LINK_VALUE} #{block_given? ? yield : content} EOI end def make_item(content=nil) <<-EOI #{TITLE_VALUE} #{LINK_VALUE} #{DESCRIPTION_VALUE} #{block_given? ? yield : content} EOI end def make_textinput(content=nil) <<-EOT #{TITLE_VALUE} #{DESCRIPTION_VALUE} #{NAME_VALUE} #{LINK_VALUE} #{block_given? ? yield : content} EOT end def make_sample_RDF make_RDF(<<-EOR) #{make_channel} #{make_image} #{make_item} #{make_textinput} EOR end def make_rss20(content=nil, xmlns=[]) <<-EORSS #{make_xmldecl} #{block_given? ? yield : content} EORSS end def make_sample_items20 RESOURCES.collect do |res| elems = ["#{res}"] elems << "title of #{res}" elems = elems.join("\n") item = "\n#{elems}\n" end.join("\n") end def make_channel20(content=nil) <<-EOC #{TITLE_VALUE} #{LINK_VALUE} #{DESCRIPTION_VALUE} #{LANGUAGE_VALUE} #{RDF_RESOURCE} #{TITLE_VALUE} #{LINK_VALUE} #{make_sample_items20} #{TITLE_VALUE} #{DESCRIPTION_VALUE} #{NAME_VALUE} #{RDF_RESOURCE} #{block_given? ? yield : content} EOC end def make_item20(content=nil) <<-EOI #{TITLE_VALUE} #{LINK_VALUE} #{DESCRIPTION_VALUE} #{block_given? ? yield : content} EOI end def make_cloud20 <<-EOC EOC end def make_sample_rss20 make_rss20(<<-EOR) #{make_channel20} EOR end def make_feed_without_entry(content=nil, xmlns=[]) <<-EOA #{FEED_ID} #{FEED_TITLE} #{FEED_UPDATED} #{FEED_AUTHOR_NAME} #{block_given? ? yield : content} EOA end def make_entry(content=nil) <<-EOA #{ENTRY_TITLE} #{ENTRY_ID} #{ENTRY_UPDATED} #{block_given? ? yield : content} EOA end def make_feed_with_open_entry(content=nil, xmlns=[], &block) make_feed_without_entry(<<-EOA, xmlns) #{make_entry(content, &block)} EOA end def make_feed_with_open_entry_source(content=nil, xmlns=[]) make_feed_with_open_entry(<<-EOA, xmlns) #{block_given? ? yield : content} EOA end def make_feed(content=nil, xmlns=[]) make_feed_without_entry(<<-EOA, xmlns) #{ENTRY_TITLE} #{ENTRY_ID} #{ENTRY_UPDATED} #{ENTRY_SUMMARY} #{block_given? ? yield : content} EOA end def make_entry_document(content=nil, xmlns=[]) <<-EOA #{ENTRY_ID} #{ENTRY_TITLE} #{ENTRY_UPDATED} #{FEED_AUTHOR_NAME} #{block_given? ? yield : content} EOA end def make_entry_document_with_open_source(content=nil, xmlns=[]) make_entry_document(<<-EOA, xmlns) #{block_given? ? yield : content} EOA end def make_element(elem_name, attrs, contents) attrs_str = attrs.collect do |name, value| "#{h name}='#{h value}'" end.join(" ") attrs_str = " #{attrs_str}" unless attrs_str.empty? if contents.is_a?(String) contents_str = h(contents) else contents_str = contents.collect do |name, value| "#{Element::INDENT}<#{h name}>#{h value}" end.join("\n") contents_str = "\n#{contents_str}\n" end "<#{h elem_name}#{attrs_str}>#{contents_str}" end def xmlns_container(xmlns_decls, content) attributes = xmlns_decls.collect do |prefix, uri| "xmlns:#{h prefix}=\"#{h uri}\"" end.join(" ") "#{content}" end private def setup_rss10(rdf) assert_equal("", rdf.to_s) channel = RDF::Channel.new assert_equal("", channel.to_s) channel.about = "http://example.com/index.rdf" channel.title = "title" channel.link = "http://example.com/" channel.description = "description" assert_equal("", channel.to_s) item_title = "item title" item_link = "http://example.com/item" channel.items = RDF::Channel::Items.new channel.items.Seq.lis << RDF::Channel::Items::Seq::Li.new(item_link) assert_not_equal("", channel.to_s) rdf.channel = channel assert_equal("", rdf.to_s) item = RDF::Item.new item.title = item_title item.link = item_link item.about = item_link rdf.items << item assert_not_equal("", rdf.to_s) end def setup_rss20(rss) assert_equal("", rss.to_s) channel = Rss::Channel.new assert_equal("", channel.to_s) channel.title = "title" channel.link = "http://example.com/" channel.description = "description" assert_not_equal("", channel.to_s) rss.channel = channel assert_not_equal("", rss.to_s) end def setup_dummy_channel(maker) about = "http://hoge.com" title = "fugafuga" link = "http://hoge.com/feed.xml" description = "fugafugafugafuga" language = "ja" maker.channel.about = about maker.channel.title = title maker.channel.link = link maker.channel.description = description maker.channel.language = language end def setup_dummy_channel_atom(maker) updated = Time.now author = "Foo" setup_dummy_channel(maker) maker.channel.links.first.rel = "self" maker.channel.links.first.type = "application/atom+xml" maker.channel.updated = updated maker.channel.author = author end def setup_dummy_image(maker) title = "fugafuga" link = "http://hoge.com" url = "http://hoge.com/hoge.png" maker.channel.link = link if maker.channel.link.nil? maker.image.title = title maker.image.url = url end def setup_dummy_textinput(maker) title = "fugafuga" description = "text hoge fuga" name = "hoge" link = "http://hoge.com/search.cgi" maker.textinput.title = title maker.textinput.description = description maker.textinput.name = name maker.textinput.link = link end def setup_dummy_item(maker) title = "TITLE" link = "http://hoge.com/" item = maker.items.new_item item.title = title item.link = link end def setup_dummy_item_atom(maker) setup_dummy_item(maker) item = maker.items.first item.id = "http://example.net/xxx" item.updated = Time.now end def setup_taxo_topic(target, topics) topics.each do |topic| taxo_topic = target.taxo_topics.new_taxo_topic topic.each do |name, value| case name when :link taxo_topic.taxo_link = value when :topics value.each do |t| taxo_topic.taxo_topics << t end else dc_elems = taxo_topic.__send__("dc_#{name}s") dc_elem = dc_elems.__send__("new_#{name}") dc_elem.value = value end end end end end end ================================================ FILE: test/rss/test_1.0.rb ================================================ require "rexml/document" require "rss-testcase" require "rss/1.0" module RSS class TestRSS10Core < TestCase def setup @rdf_prefix = "rdf" @rdf_uri = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" @uri = "http://purl.org/rss/1.0/" end def test_RDF version = "1.0" encoding = "UTF-8" standalone = false rdf = RDF.new(version, encoding, standalone) setup_rss10(rdf) doc = REXML::Document.new(rdf.to_s) xmldecl = doc.xml_decl %w(version encoding).each do |x| assert_equal(instance_eval(x), xmldecl.__send__(x)) end assert_equal(standalone, !xmldecl.standalone.nil?) assert_equal(@rdf_uri, doc.root.namespace) end def test_not_displayed_xml_stylesheets rdf = RDF.new() plain_rdf = rdf.to_s 3.times do rdf.xml_stylesheets.push(XMLStyleSheet.new) assert_equal(plain_rdf, rdf.to_s) end end def test_xml_stylesheets [ [{:href => "a.xsl", :type => "text/xsl"}], [ {:href => "a.xsl", :type => "text/xsl"}, {:href => "a.css", :type => "text/css"}, ], ].each do |attrs_ary| assert_xml_stylesheet_pis(attrs_ary) end end def test_channel about = "http://hoge.com" title = "fugafuga" link = "http://hoge.com" description = "fugafugafugafuga" resource = "http://hoge.com/hoge.png" item_title = "item title" item_link = "http://hoge.com/item" image = RDF::Channel::Image.new(resource) items = RDF::Channel::Items.new items.Seq.lis << items.class::Seq::Li.new(item_link) textinput = RDF::Channel::Textinput.new(resource) rss_item = RDF::Item.new rss_item.title = item_title rss_item.link = item_link rss_item.about = item_link channel = RDF::Channel.new(about) %w(title link description image items textinput).each do |x| channel.__send__("#{x}=", instance_eval(x)) end doc = REXML::Document.new(make_RDF(<<-EOR)) #{channel} #{rss_item} EOR c = doc.root.elements[1] assert_equal(about, c.attributes["about"]) %w(title link description image textinput).each do |x| elem = c.elements[x] assert_equal(x, elem.name) assert_equal(@uri, elem.namespace) if x == "image" or x == "textinput" excepted = resource res = elem.attributes.get_attribute("resource") assert_equal(@rdf_uri, res.namespace) value = res.value else excepted = instance_eval(x) value = elem.text end assert_equal(excepted, value) end assert_equal(@uri, c.elements["items"].namespace) assert_equal("items", c.elements["items"].name) end def test_channel_image resource = "http://hoge.com/hoge.png" image = RDF::Channel::Image.new(resource) doc = REXML::Document.new(make_RDF(image.to_s)) i = doc.root.elements[1] assert_equal("image", i.name) assert_equal(@uri, i.namespace) res = i.attributes.get_attribute("resource") assert_equal(@rdf_uri, res.namespace) assert_equal(resource, res.value) end def test_channel_textinput resource = "http://hoge.com/hoge.png" textinput = RDF::Channel::Textinput.new(resource) doc = REXML::Document.new(make_RDF(textinput.to_s)) t = doc.root.elements[1] assert_equal("textinput", t.name) assert_equal(@uri, t.namespace) res = t.attributes.get_attribute("resource") assert_equal(@rdf_uri, res.namespace) assert_equal(resource, res.value) end def test_channel_items item_link = "http://example.com/item" items = RDF::Channel::Items.new li = items.Seq.class::Li.new(item_link) items.Seq.lis << li doc = REXML::Document.new(make_RDF(items.to_s)) i = doc.root.elements[1] assert_equal("items", i.name) assert_equal(@uri, i.namespace) assert_equal(1, i.elements.size) seq = i.elements[1] assert_equal("Seq", seq.name) assert_equal(@rdf_uri, seq.namespace) assert_equal(1, seq.elements.size) l = seq.elements[1] assert_equal("li", l.name) assert_equal(@rdf_uri, l.namespace) assert_equal(item_link, l.attributes["resource"]) end def test_seq item_link = "http://example.com/item" seq = RDF::Seq.new li = seq.class::Li.new(item_link) seq.lis << li doc = REXML::Document.new(make_RDF(seq.to_s)) s = doc.root.elements[1] assert_equal("Seq", s.name) assert_equal(@rdf_uri, s.namespace) assert_equal(1, s.elements.size) l = s.elements[1] assert_equal("li", l.name) assert_equal(@rdf_uri, l.namespace) assert_equal(item_link, l.attributes["resource"]) end def test_li resource = "http://hoge.com/" li = RDF::Li.new(resource) doc = REXML::Document.new(make_RDF(li.to_s)) l = doc.root.elements[1] assert_equal("li", l.name) assert_equal(@rdf_uri, l.namespace(l.prefix)) res = l.attributes.get_attribute("resource") assert_equal('', res.instance_eval("@prefix")) assert_equal(resource, res.value) end def test_image about = "http://hoge.com" title = "fugafuga" url = "http://hoge.com/hoge" link = "http://hoge.com/fuga" image = RDF::Image.new(about) %w(title url link).each do |x| image.__send__("#{x}=", instance_eval(x)) end doc = REXML::Document.new(make_RDF(image.to_s)) i = doc.root.elements[1] assert_equal(about, i.attributes["about"]) %w(title url link).each do |x| elem = i.elements[x] assert_equal(x, elem.name) assert_equal(@uri, elem.namespace) assert_equal(instance_eval(x), elem.text) end end def test_item about = "http://hoge.com" title = "fugafuga" link = "http://hoge.com/fuga" description = "hogehogehoge" item = RDF::Item.new(about) %w(title link description).each do |x| item.__send__("#{x}=", instance_eval(x)) end doc = REXML::Document.new(make_RDF(item.to_s)) i = doc.root.elements[1] assert_equal(about, i.attributes["about"]) %w(title link description).each do |x| elem = i.elements[x] assert_equal(x, elem.name) assert_equal(@uri, elem.namespace) assert_equal(instance_eval(x), elem.text) end end def test_textinput about = "http://hoge.com" title = "fugafuga" link = "http://hoge.com/fuga" name = "foo" description = "hogehogehoge" textinput = RDF::Textinput.new(about) %w(title link name description).each do |x| textinput.__send__("#{x}=", instance_eval(x)) end doc = REXML::Document.new(make_RDF(textinput.to_s)) t = doc.root.elements[1] assert_equal(about, t.attributes["about"]) %w(title link name description).each do |x| elem = t.elements[x] assert_equal(x, elem.name) assert_equal(@uri, elem.namespace) assert_equal(instance_eval(x), elem.text) end end def test_to_xml rss = RSS::Parser.parse(make_sample_RDF) assert_equal(rss.to_s, rss.to_xml) assert_equal(rss.to_s, rss.to_xml("1.0")) rss09 = rss.to_xml("0.91") do |maker| maker.channel.language = "en-us" end rss09 = RSS::Parser.parse(rss09) assert_equal("0.91", rss09.rss_version) assert_equal(["rss", "0.91", nil], rss09.feed_info) rss20 = RSS::Parser.parse(rss.to_xml("2.0")) assert_equal("2.0", rss20.rss_version) assert_equal(["rss", "2.0", nil], rss20.feed_info) atom_xml = rss.to_xml("atom") do |maker| maker.channel.author = "Alice" maker.channel.updated ||= Time.now maker.items.each do |item| item.updated ||= Time.now end end atom = RSS::Parser.parse(atom_xml) assert_equal(["atom", "1.0", "feed"], atom.feed_info) end end end ================================================ FILE: test/rss/test_2.0.rb ================================================ require "rexml/document" require "rss-testcase" module RSS class TestRSS20Core < TestCase def setup @rss_version = "2.0" end def test_Rss version = "1.0" encoding = "UTF-8" standalone = false rss = Rss.new(@rss_version, version, encoding, standalone) setup_rss20(rss) doc = REXML::Document.new(rss.to_s(false)) xmldecl = doc.xml_decl %w(version encoding).each do |x| assert_equal(instance_eval(x), xmldecl.__send__(x)) end assert_equal(standalone, !xmldecl.standalone.nil?) assert_equal("", doc.root.namespace) assert_equal(@rss_version, doc.root.attributes["version"]) end def test_not_displayed_xml_stylesheets rss = Rss.new(@rss_version) plain_rss = rss.to_s 3.times do rss.xml_stylesheets.push(XMLStyleSheet.new) assert_equal(plain_rss, rss.to_s) end end def test_xml_stylesheets [ [{:href => "a.xsl", :type => "text/xsl"}], [ {:href => "a.xsl", :type => "text/xsl"}, {:href => "a.css", :type => "text/css"}, ], ].each do |attrs_ary| rss = Rss.new(@rss_version) setup_rss20(rss) assert_xml_stylesheet_pis(attrs_ary, rss) end end def test_channel title = "fugafuga" link = "http://hoge.com" description = "fugafugafugafuga" language = "en-us" copyright = "Copyright 2002, Spartanburg Herald-Journal" managingEditor = "geo@herald.com (George Matesky)" webMaster = "betty@herald.com (Betty Guernsey)" pubDate = Time.parse("Sat, 07 Sep 2002 00:00:01 GMT") lastBuildDate = Time.parse("Sat, 07 Sep 2002 09:42:31 GMT") categories = [ { :content => "Newspapers", }, { :domain => "Syndic8", :content => "1765", } ] generator = "MightyInHouse Content System v2.3" docs = "http://blogs.law.harvard.edu/tech/rss" ttl = "60" rating = '(PICS-1.1 "http://www.rsac.org/ratingsv01.html" l gen true comment "RSACi North America Server" for "http://www.rsac.org" on "1996.04.16T08:15-0500" r (n 0 s 0 v 0 l 0))' channel = Rss::Channel.new elems = %w(title link description language copyright managingEditor webMaster pubDate lastBuildDate generator docs ttl rating) elems.each do |x| value = instance_eval(x) value = value.rfc822 if %w(pubDate lastBuildDate).include?(x) channel.__send__("#{x}=", value) end categories.each do |cat| channel.categories << Rss::Channel::Category.new(cat[:domain], cat[:content]) end doc = REXML::Document.new(make_rss20(channel.to_s)) c = doc.root.elements[1] elems.each do |x| elem = c.elements[x] assert_equal(x, elem.name) assert_equal("", elem.namespace) expected = instance_eval(x) case x when "pubDate", "lastBuildDate" assert_equal(expected, Time.parse(elem.text)) when "ttl" expected = channel.__send__(x) assert_equal(expected, elem.text.to_i) else assert_equal(expected, elem.text) end end categories.each_with_index do |cat, i| cat = cat.dup cat[:domain] ||= nil category = c.elements["category[#{i+1}]"] actual = { :domain => category.attributes["domain"], :content => category.text, } assert_equal(cat, actual) end end def test_channel_cloud cloud_params = { :domain => "rpc.sys.com", :port => "80", :path => "/RPC2", :registerProcedure => "myCloud.rssPleaseNotify", :protocol => "xml-rpc", } cloud = Rss::Channel::Cloud.new(cloud_params[:domain], cloud_params[:port], cloud_params[:path], cloud_params[:registerProcedure], cloud_params[:protocol]) cloud_params[:port] = cloud.port doc = REXML::Document.new(cloud.to_s) cloud_elem = doc.root actual = {} cloud_elem.attributes.each do |name, value| value = value.to_i if name == "port" actual[name.intern] = value end assert_equal(cloud_params, actual) end def test_channel_image image_params = { :url => "http://hoge.com/hoge.png", :title => "fugafuga", :link => "http://hoge.com", :width => "144", :height => "400", :description => "an image", } image = Rss::Channel::Image.new(image_params[:url], image_params[:title], image_params[:link], image_params[:width], image_params[:height], image_params[:description]) doc = REXML::Document.new(image.to_s) image_elem = doc.root image_params.each do |name, value| value = image.__send__(name) actual = image_elem.elements[name.to_s].text actual = actual.to_i if [:width, :height].include?(name) assert_equal(value, actual) end end def test_channel_textInput textInput_params = { :title => "fugafuga", :description => "text hoge fuga", :name => "hoge", :link => "http://hoge.com", } textInput = Rss::Channel::TextInput.new(textInput_params[:title], textInput_params[:description], textInput_params[:name], textInput_params[:link]) doc = REXML::Document.new(textInput.to_s) input_elem = doc.root textInput_params.each do |name, value| actual = input_elem.elements[name.to_s].text assert_equal(value, actual) end end def test_channel_skip_days skipDays_values = [ "Sunday", "Monday", ] skipDays = Rss::Channel::SkipDays.new skipDays_values.each do |value| skipDays.days << Rss::Channel::SkipDays::Day.new(value) end doc = REXML::Document.new(skipDays.to_s) days_elem = doc.root skipDays_values.each_with_index do |value, i| assert_equal(value, days_elem.elements[i + 1].text) end end def test_channel_skip_hours skipHours_values = [ "0", "13", ] skipHours = Rss::Channel::SkipHours.new skipHours_values.each do |value| skipHours.hours << Rss::Channel::SkipHours::Hour.new(value) end doc = REXML::Document.new(skipHours.to_s) hours_elem = doc.root skipHours_values.each_with_index do |value, i| expected = skipHours.hours[i].content assert_equal(expected, hours_elem.elements[i + 1].text.to_i) end end def test_item title = "fugafuga" link = "http://hoge.com/" description = "text hoge fuga" author = "oprah@oxygen.net" categories = [ { :content => "Newspapers", }, { :domain => "Syndic8", :content => "1765", } ] comments = "http://www.myblog.org/cgi-local/mt/mt-comments.cgi?entry_id=290" pubDate = Time.parse("Sat, 07 Sep 2002 00:00:01 GMT") channel = Rss::Channel.new channel.title = "title" channel.link = "http://example.com/" channel.description = "description" item = Rss::Channel::Item.new channel.items << item elems = %w(title link description author comments pubDate) elems.each do |x| value = instance_eval(x) value = value.rfc822 if x == "pubDate" item.__send__("#{x}=", value) end categories.each do |cat| item.categories << Rss::Channel::Category.new(cat[:domain], cat[:content]) end doc = REXML::Document.new(channel.to_s) channel_elem = doc.root item_elem = channel_elem.elements["item[1]"] elems.each do |x| elem = item_elem.elements[x] assert_equal(x, elem.name) assert_equal("", elem.namespace) expected = instance_eval(x) case x when "pubDate" assert_equal(expected, Time.parse(elem.text)) else assert_equal(expected, elem.text) end end categories.each_with_index do |cat, i| cat = cat.dup cat[:domain] ||= nil category = item_elem.elements["category[#{i+1}]"] actual = { :domain => category.attributes["domain"], :content => category.text, } assert_equal(cat, actual) end end def test_item_enclosure enclosure_params = { :url => "http://www.scripting.com/mp3s/weatherReportSuite.mp3", :length => "12216320", :type => "audio/mpeg", } enclosure = Rss::Channel::Item::Enclosure.new(enclosure_params[:url], enclosure_params[:length], enclosure_params[:type]) enclosure_params[:length] = enclosure.length doc = REXML::Document.new(enclosure.to_s) enclosure_elem = doc.root actual = {} enclosure_elem.attributes.each do |name, value| value = value.to_i if name == "length" actual[name.intern] = value end assert_equal(enclosure_params, actual) end def test_item_guid test_params = [ { :content => "http://some.server.com/weblogItem3207", }, { :isPermaLink => "true", :content => "http://inessential.com/2002/09/01.php#a2", }, ] test_params.each do |guid_params| guid = Rss::Channel::Item::Guid.new(guid_params[:isPermaLink], guid_params[:content]) if guid_params.has_key?(:isPermaLink) guid_params[:isPermaLink] = guid.isPermaLink end if guid.isPermaLink.nil? assert_equal(true, guid.PermaLink?) else assert_equal(guid.isPermaLink, guid.PermaLink?) end doc = REXML::Document.new(guid.to_s) guid_elem = doc.root actual = {} actual[:content] = guid_elem.text if guid_elem.text guid_elem.attributes.each do |name, value| value = value == "true" if name == "isPermaLink" actual[name.intern] = value end assert_equal(guid_params, actual) end end def test_item_source source_params = { :url => "http://www.tomalak.org/links2.xml", :content => "Tomalak's Realm", } source = Rss::Channel::Item::Source.new(source_params[:url], source_params[:content]) doc = REXML::Document.new(source.to_s) source_elem = doc.root actual = {} actual[:content] = source_elem.text source_elem.attributes.each do |name, value| actual[name.intern] = value end assert_equal(source_params, actual) end def test_to_xml rss = RSS::Parser.parse(make_sample_rss20) assert_equal(rss.to_s, rss.to_xml) assert_equal(rss.to_s, rss.to_xml("2.0")) rss09_xml = rss.to_xml("0.91") do |maker| setup_dummy_image(maker) end rss09 = RSS::Parser.parse(rss09_xml) assert_equal("0.91", rss09.rss_version) rss10 = rss.to_xml("1.0") do |maker| maker.channel.about = "http://www.example.com/index.rdf" end rss10 = RSS::Parser.parse(rss10) assert_equal("1.0", rss10.rss_version) atom_xml = rss.to_xml("atom1.0") do |maker| maker.channel.id = "http://www.example.com/atom.xml" maker.channel.author = "Alice" maker.channel.updated = Time.now maker.items.each do |item| item.author = "Bob" item.updated = Time.now end end atom = RSS::Parser.parse(atom_xml) assert_equal(["atom", "1.0", "feed"], atom.feed_info) end end end ================================================ FILE: test/rss/test_accessor.rb ================================================ require "rss-testcase" require "rss/1.0" require "rss/2.0" require "rss/syndication" require "rss/image" module RSS class TestAccessor < TestCase def test_date channel = Rss::Channel.new channel.pubDate = nil assert_nil(channel.pubDate) time = Time.now channel.pubDate = time assert_equal(time, channel.pubDate) time = Time.parse(Time.now.rfc822) channel.pubDate = time.rfc822 assert_equal(time, channel.pubDate) time = Time.parse(Time.now.iso8601) value = time.iso8601 assert_not_available_value("pubDate", value) do channel.pubDate = value end channel.do_validate = false time = Time.parse(Time.now.iso8601) value = time.iso8601 channel.pubDate = value assert_equal(time, channel.pubDate) channel.pubDate = nil assert_nil(channel.pubDate) end def test_integer image_item = RDF::Item::ImageItem.new image_item.width = nil assert_nil(image_item.width) width = 10 image_item.width = width assert_equal(width, image_item.width) width = 10.0 image_item.width = width assert_equal(width, image_item.width) width = "10" image_item.width = width assert_equal(width.to_i, image_item.width) width = "10.0" assert_not_available_value("image:width", width) do image_item.width = width end image_item.do_validate = false width = "10.0" image_item.width = width assert_equal(width.to_i, image_item.width) image_item.width = nil assert_nil(image_item.width) end def test_positive_integer channel = RDF::Channel.new channel.sy_updateFrequency = nil assert_nil(channel.sy_updateFrequency) freq = 10 channel.sy_updateFrequency = freq assert_equal(freq, channel.sy_updateFrequency) freq = 10.0 channel.sy_updateFrequency = freq assert_equal(freq, channel.sy_updateFrequency) freq = "10" channel.sy_updateFrequency = freq assert_equal(freq.to_i, channel.sy_updateFrequency) freq = "10.0" assert_not_available_value("sy:updateFrequency", freq) do channel.sy_updateFrequency = freq end channel.do_validate = false freq = "10.0" channel.sy_updateFrequency = freq assert_equal(freq.to_i, channel.sy_updateFrequency) channel.sy_updateFrequency = nil assert_nil(channel.sy_updateFrequency) end end end ================================================ FILE: test/rss/test_atom.rb ================================================ require "rexml/document" require "rss-testcase" require "rss/atom" module RSS class TestAtomCore < TestCase def setup @uri = "http://www.w3.org/2005/Atom" @xhtml_uri = "http://www.w3.org/1999/xhtml" end def test_feed version = "1.0" encoding = "UTF-8" standalone = false feed = Atom::Feed.new(version, encoding, standalone) assert_equal("", feed.to_s) author = feed.class::Author.new name = feed.class::Author::Name.new name.content = "an author" author.name = name assert_not_equal("", author.to_s) feed.authors << author assert_equal("", feed.to_s) id = feed.class::Id.new id.content = "http://example.com/atom.xml" assert_not_equal("", id.to_s) feed.id = id assert_equal("", feed.to_s) title = feed.class::Title.new title.content = "a title" assert_not_equal("", title.to_s) feed.title = title assert_equal("", feed.to_s) updated = feed.class::Updated.new updated.content = Time.now assert_not_equal("", updated.to_s) feed.updated = updated assert_not_equal("", feed.to_s) feed.authors.clear assert_equal("", feed.to_s) entry = Atom::Feed::Entry.new setup_entry(entry) assert_not_equal("", entry.to_s) author = entry.authors.first entry.authors.clear assert_equal("", entry.to_s) entry.parent = feed assert_equal("", entry.to_s) feed.authors << author assert_not_equal("", entry.to_s) feed.authors.clear feed.entries << entry assert_equal("", feed.to_s) entry.authors << author assert_not_equal("", entry.to_s) assert_not_equal("", feed.to_s) doc = REXML::Document.new(feed.to_s) xmldecl = doc.xml_decl %w(version encoding).each do |x| assert_equal(instance_eval(x), xmldecl.__send__(x)) end assert_equal(standalone, !xmldecl.standalone.nil?) assert_equal(@uri, doc.root.namespace) end def test_entry version = "1.0" encoding = "UTF-8" standalone = false entry = Atom::Entry.new(version, encoding, standalone) setup_entry(entry) author = entry.authors.first entry.authors.clear assert_equal("", entry.to_s) source = Atom::Entry::Source.new source.authors << author entry.source = source assert_not_equal("", entry.to_s) doc = REXML::Document.new(entry.to_s) xmldecl = doc.xml_decl %w(version encoding).each do |x| assert_equal(instance_eval(x), xmldecl.__send__(x)) end assert_equal(standalone, !xmldecl.standalone.nil?) assert_equal(@uri, doc.root.namespace) end def test_not_displayed_xml_stylesheets feed = Atom::Feed.new plain_feed = feed.to_s 3.times do feed.xml_stylesheets.push(XMLStyleSheet.new) assert_equal(plain_feed, feed.to_s) end end def test_atom_author assert_atom_person_to_s(Atom::Feed::Author) assert_atom_person_to_s(Atom::Feed::Entry::Author) assert_atom_person_to_s(Atom::Entry::Author) assert_atom_person_to_s(Atom::Feed::Entry::Source::Author) assert_atom_person_to_s(Atom::Entry::Source::Author) end def test_atom_category assert_atom_category_to_s(Atom::Feed::Category) assert_atom_category_to_s(Atom::Feed::Entry::Category) assert_atom_category_to_s(Atom::Entry::Category) assert_atom_category_to_s(Atom::Feed::Entry::Source::Category) assert_atom_category_to_s(Atom::Entry::Source::Category) end def test_atom_contributor assert_atom_person_to_s(Atom::Feed::Contributor) assert_atom_person_to_s(Atom::Feed::Entry::Contributor) assert_atom_person_to_s(Atom::Entry::Contributor) assert_atom_person_to_s(Atom::Feed::Entry::Source::Contributor) assert_atom_person_to_s(Atom::Entry::Source::Contributor) end def test_atom_generator assert_atom_generator_to_s(Atom::Feed::Generator) assert_atom_generator_to_s(Atom::Feed::Entry::Source::Generator) assert_atom_generator_to_s(Atom::Entry::Source::Generator) end def test_atom_icon assert_atom_icon_to_s(Atom::Feed::Icon) assert_atom_icon_to_s(Atom::Feed::Entry::Source::Icon) assert_atom_icon_to_s(Atom::Entry::Source::Icon) end def test_atom_id assert_atom_id_to_s(Atom::Feed::Id) assert_atom_id_to_s(Atom::Feed::Entry::Id) assert_atom_id_to_s(Atom::Entry::Id) assert_atom_id_to_s(Atom::Feed::Entry::Source::Id) assert_atom_id_to_s(Atom::Entry::Source::Id) end def test_atom_link assert_atom_link_to_s(Atom::Feed::Link) assert_atom_link_to_s(Atom::Feed::Entry::Link) assert_atom_link_to_s(Atom::Entry::Link) assert_atom_link_to_s(Atom::Feed::Entry::Source::Link) assert_atom_link_to_s(Atom::Entry::Source::Link) end def test_atom_logo assert_atom_logo_to_s(Atom::Feed::Logo) assert_atom_logo_to_s(Atom::Feed::Entry::Source::Logo) assert_atom_logo_to_s(Atom::Entry::Source::Logo) end def test_atom_rights assert_atom_text_construct_to_s(Atom::Feed::Rights) assert_atom_text_construct_to_s(Atom::Feed::Entry::Rights) assert_atom_text_construct_to_s(Atom::Entry::Rights) assert_atom_text_construct_to_s(Atom::Feed::Entry::Source::Rights) assert_atom_text_construct_to_s(Atom::Entry::Source::Rights) end def test_atom_subtitle assert_atom_text_construct_to_s(Atom::Feed::Subtitle) assert_atom_text_construct_to_s(Atom::Feed::Entry::Source::Subtitle) assert_atom_text_construct_to_s(Atom::Entry::Source::Subtitle) end def test_atom_title assert_atom_text_construct_to_s(Atom::Feed::Title) assert_atom_text_construct_to_s(Atom::Feed::Entry::Title) assert_atom_text_construct_to_s(Atom::Entry::Title) assert_atom_text_construct_to_s(Atom::Feed::Entry::Source::Title) assert_atom_text_construct_to_s(Atom::Entry::Source::Title) end def test_atom_updated assert_atom_date_construct_to_s(Atom::Feed::Updated) assert_atom_date_construct_to_s(Atom::Feed::Entry::Updated) assert_atom_date_construct_to_s(Atom::Entry::Updated) assert_atom_date_construct_to_s(Atom::Feed::Entry::Source::Updated) assert_atom_date_construct_to_s(Atom::Entry::Source::Updated) end def test_atom_content assert_atom_content_to_s(Atom::Feed::Entry::Content) assert_atom_content_to_s(Atom::Entry::Content) end def test_atom_published assert_atom_date_construct_to_s(Atom::Feed::Entry::Published) assert_atom_date_construct_to_s(Atom::Entry::Published) end def test_atom_summary assert_atom_text_construct_to_s(Atom::Feed::Entry::Summary) assert_atom_text_construct_to_s(Atom::Entry::Summary) end def test_to_xml(with_convenience_way=true) atom = RSS::Parser.parse(make_feed) assert_equal(atom.to_s, atom.to_xml) assert_equal(atom.to_s, atom.to_xml("atom")) assert_equal(atom.to_s, atom.to_xml("atom1.0")) assert_equal(atom.to_s, atom.to_xml("atom1.0:feed")) assert_equal(atom.to_s, atom.to_xml("atom:feed")) rss09_xml = atom.to_xml("0.91") do |maker| maker.channel.language = "en-us" maker.channel.link = "http://example.com/" if with_convenience_way maker.channel.description = atom.title.content else maker.channel.description {|d| d.content = atom.title.content} end maker.image.url = "http://example.com/logo.png" maker.image.title = "Logo" end rss09 = RSS::Parser.parse(rss09_xml) assert_equal(["rss", "0.91", nil], rss09.feed_info) rss20_xml = atom.to_xml("2.0") do |maker| maker.channel.link = "http://example.com/" if with_convenience_way maker.channel.description = atom.title.content else maker.channel.description {|d| d.content = atom.title.content} end end rss20 = RSS::Parser.parse(rss20_xml) assert_equal("2.0", rss20.rss_version) assert_equal(["rss", "2.0", nil], rss20.feed_info) end def test_to_xml_with_new_api_since_018 test_to_xml(false) end private def setup_entry(entry) _wrap_assertion do assert_equal("", entry.to_s) author = entry.class::Author.new name = entry.class::Author::Name.new name.content = "an author" author.name = name assert_not_equal("", author.to_s) entry.authors << author assert_equal("", entry.to_s) id = entry.class::Id.new id.content = "http://example.com/atom.xml" assert_not_equal("", id.to_s) entry.id = id assert_equal("", entry.to_s) title = entry.class::Title.new title.content = "a title" assert_not_equal("", title.to_s) entry.title = title assert_equal("", entry.to_s) updated = entry.class::Updated.new updated.content = Time.now assert_not_equal("", updated.to_s) entry.updated = updated assert_not_equal("", entry.to_s) end end def assert_atom_person_to_s(target_class) _wrap_assertion do name = "A person" uri = "http://example.com/person/" email = "person@example.com" target = target_class.new assert_equal("", target.to_s) target = target_class.new person_name = target_class::Name.new person_name.content = name target.name = person_name xml_target = REXML::Document.new(target.to_s).root assert_equal(["name"], xml_target.elements.collect {|e| e.name}) assert_equal([name], xml_target.elements.collect {|e| e.text}) person_uri = target_class::Uri.new person_uri.content = uri target.uri = person_uri xml_target = REXML::Document.new(target.to_s).root assert_equal(["name", "uri"], xml_target.elements.collect {|e| e.name}) assert_equal([name, uri], xml_target.elements.collect {|e| e.text}) person_email = target_class::Email.new person_email.content = email target.email = person_email xml_target = REXML::Document.new(target.to_s).root assert_equal(["name", "uri", "email"], xml_target.elements.collect {|e| e.name}) assert_equal([name, uri, email], xml_target.elements.collect {|e| e.text}) end end def assert_atom_category_to_s(target_class) _wrap_assertion do term = "music" scheme = "http://example.com/music" label = "Music" category = target_class.new assert_equal("", category.to_s) category = target_class.new category.scheme = scheme assert_equal("", category.to_s) category = target_class.new category.label = label assert_equal("", category.to_s) category = target_class.new category.scheme = scheme category.label = label assert_equal("", category.to_s) category = target_class.new category.term = term xml = REXML::Document.new(category.to_s).root assert_rexml_element([], {"term" => term}, nil, xml) category = target_class.new category.term = term category.scheme = scheme xml = REXML::Document.new(category.to_s).root assert_rexml_element([], {"term" => term, "scheme" => scheme}, nil, xml) category = target_class.new category.term = term category.label = label xml = REXML::Document.new(category.to_s).root assert_rexml_element([], {"term" => term, "label" => label}, nil, xml) category = target_class.new category.term = term category.scheme = scheme category.label = label xml = REXML::Document.new(category.to_s).root attrs = {"term" => term, "scheme" => scheme, "label" => label} assert_rexml_element([], attrs, nil, xml) end end def assert_atom_generator_to_s(target_class) _wrap_assertion do content = "Feed generator" uri = "http://example.com/generator" version = "0.0.1" generator = target_class.new assert_equal("", generator.to_s) generator = target_class.new generator.uri = uri assert_equal("", generator.to_s) generator = target_class.new generator.version = version assert_equal("", generator.to_s) generator = target_class.new generator.uri = uri generator.version = version assert_equal("", generator.to_s) generator = target_class.new generator.content = content xml = REXML::Document.new(generator.to_s).root assert_rexml_element([], {}, content, xml) generator = target_class.new generator.content = content generator.uri = uri xml = REXML::Document.new(generator.to_s).root assert_rexml_element([], {"uri" => uri}, content, xml) generator = target_class.new generator.content = content generator.version = version xml = REXML::Document.new(generator.to_s).root assert_rexml_element([], {"version" => version}, content, xml) generator = target_class.new generator.content = content generator.uri = uri generator.version = version xml = REXML::Document.new(generator.to_s).root assert_rexml_element([], {"uri" => uri, "version" => version}, content, xml) end end def assert_atom_icon_to_s(target_class) _wrap_assertion do content = "http://example.com/icon.png" icon = target_class.new assert_equal("", icon.to_s) icon = target_class.new icon.content = content xml = REXML::Document.new(icon.to_s).root assert_rexml_element([], {}, content, xml) end end def assert_atom_id_to_s(target_class) _wrap_assertion do content = "http://example.com/1" id = target_class.new assert_equal("", id.to_s) id = target_class.new id.content = content xml = REXML::Document.new(id.to_s).root assert_rexml_element([], {}, content, xml) end end def assert_atom_link_to_s(target_class) _wrap_assertion do href = "http://example.com/atom.xml" rel = "self" type = "application/atom+xml" hreflang = "ja" title = "Atom Feed" length = "801" link = target_class.new assert_equal("", link.to_s) link = target_class.new link.href = href xml = REXML::Document.new(link.to_s).root assert_rexml_element([], {"href" => href}, nil, xml) optional_arguments = %w(rel type hreflang title length) optional_arguments.each do |name| rest = optional_arguments.reject {|x| x == name} link = target_class.new link.__send__("#{name}=", eval(name)) assert_equal("", link.to_s) rest.each do |n| link.__send__("#{n}=", eval(n)) assert_equal("", link.to_s) end link = target_class.new link.href = href link.__send__("#{name}=", eval(name)) attrs = [["href", href], [name, eval(name)]] xml = REXML::Document.new(link.to_s).root assert_rexml_element([], attrs, nil, xml) rest.each do |n| link.__send__("#{n}=", eval(n)) attrs << [n, eval(n)] xml = REXML::Document.new(link.to_s).root assert_rexml_element([], attrs, nil, xml) end end end end def assert_atom_logo_to_s(target_class) _wrap_assertion do content = "http://example.com/logo.png" logo = target_class.new assert_equal("", logo.to_s) logo = target_class.new logo.content = content xml = REXML::Document.new(logo.to_s).root assert_rexml_element([], {}, content, xml) end end def assert_atom_text_construct_to_s(target_class) _wrap_assertion do text_content = "plain text" html_content = "#{text_content}" xhtml_uri = "http://www.w3.org/1999/xhtml" xhtml_em = RSS::XML::Element.new("em", nil, xhtml_uri, {}, text_content) xhtml_content = RSS::XML::Element.new("div", nil, xhtml_uri, {"xmlns" => xhtml_uri}, [xhtml_em]) text = target_class.new assert_equal("", text.to_s) text = target_class.new text.type = "text" assert_equal("", text.to_s) text = target_class.new text.content = text_content xml = REXML::Document.new(text.to_s).root assert_rexml_element([], {}, text_content, xml) text = target_class.new text.type = "text" text.content = text_content xml = REXML::Document.new(text.to_s).root assert_rexml_element([], {"type" => "text"}, text_content, xml) text = target_class.new text.type = "html" text.content = html_content xml = REXML::Document.new(text.to_s).root assert_rexml_element([], {"type" => "html"}, html_content, xml) text = target_class.new text.type = "xhtml" text.content = xhtml_content assert_equal("", text.to_s) text = target_class.new text.type = "xhtml" text.__send__(target_class.xml_setter, xhtml_content) xml = REXML::Document.new(text.to_s).root assert_rexml_element([[xhtml_uri, "div"]], {"type" => "xhtml"}, nil, xml) assert_rexml_element([[xhtml_uri, "em"]], nil, nil, xml.elements[1]) assert_rexml_element([], {}, text_content, xml.elements[1].elements[1]) text = target_class.new text.type = "xhtml" text.__send__(target_class.xml_setter, xhtml_em) xml = REXML::Document.new(text.to_s).root assert_rexml_element([[xhtml_uri, "div"]], {"type" => "xhtml"}, nil, xml) assert_rexml_element([[xhtml_uri, "em"]], nil, nil, xml.elements[1]) assert_rexml_element([], {}, text_content, xml.elements[1].elements[1]) end end def assert_atom_date_construct_to_s(target_class) _wrap_assertion do date = target_class.new assert_equal("", date.to_s) [ "2003-12-13T18:30:02Z", "2003-12-13T18:30:02.25Z", "2003-12-13T18:30:02+01:00", "2003-12-13T18:30:02.25+01:00", ].each do |content| date = target_class.new date.content = content xml = REXML::Document.new(date.to_s).root assert_rexml_element([], {}, content, xml, :time) date = target_class.new date.content = Time.parse(content) xml = REXML::Document.new(date.to_s).root assert_rexml_element([], {}, content, xml, :time) end end end def assert_atom_content_to_s(target_class) _wrap_assertion do assert_atom_text_construct_to_s(target_class) assert_atom_content_inline_other_xml_to_s(target_class) assert_atom_content_inline_other_text_to_s(target_class) assert_atom_content_inline_other_base64_to_s(target_class) assert_atom_content_out_of_line_to_s(target_class) end end def assert_atom_content_inline_other_xml_to_s(target_class) _wrap_assertion do content = target_class.new content.type = "text/xml" assert_equal("", content.to_s) content = target_class.new content.type = "text/xml" content.xml = RSS::XML::Element.new("em") xml = REXML::Document.new(content.to_s).root assert_rexml_element([["", "em"]], {"type" => "text/xml"}, nil, xml) end end def assert_atom_content_inline_other_text_to_s(target_class) _wrap_assertion do content = target_class.new content.type = "text/plain" assert_equal("", content.to_s) content = target_class.new content.type = "text/plain" content.xml = RSS::XML::Element.new("em") assert_equal("", content.to_s) content = target_class.new content.type = "text/plain" content.content = "content" xml = REXML::Document.new(content.to_s).root assert_rexml_element([], {"type" => "text/plain"}, "content", xml) end end def assert_atom_content_inline_other_base64_to_s(target_class) _wrap_assertion do type = "image/png" png_file = File.join(File.dirname(__FILE__), "dot.png") original_content = File.open(png_file, "rb") {|file| file.read} content = target_class.new content.type = type content.content = original_content xml = REXML::Document.new(content.to_s).root assert_rexml_element([], {"type" => type}, [original_content].pack("m"), xml) end end def assert_atom_content_out_of_line_to_s(target_class) _wrap_assertion do type = "application/zip" src = "http://example.com/xxx.zip" content = target_class.new assert(!content.out_of_line?) content.src = src assert(content.out_of_line?) xml = REXML::Document.new(content.to_s).root assert_rexml_element([], {"src" => src}, nil, xml) content = target_class.new assert(!content.out_of_line?) content.type = type assert(!content.out_of_line?) content.src = src assert(content.out_of_line?) xml = REXML::Document.new(content.to_s).root assert_rexml_element([], {"type" => type, "src" => src}, nil, xml) end end end end ================================================ FILE: test/rss/test_content.rb ================================================ require "cgi" require "rexml/document" require "rss-testcase" require "rss/content" module RSS class TestContent < TestCase def setup @prefix = "content" @uri = "http://purl.org/rss/1.0/modules/content/" @elems = { :encoded => "ATTENTION", } @content_nodes = @elems.collect do |name, value| "<#{@prefix}:#{name}>#{CGI.escapeHTML(value.to_s)}" end.join("\n") @rss10_source = make_RDF(<<-EOR, {@prefix => @uri}) #{make_channel()} #{make_image()} #{make_item(@content_nodes)} #{make_textinput()} EOR @rss10 = Parser.parse(@rss10_source) @rss20_source = make_rss20(<<-EOR, {@prefix => @uri}) #{make_channel20(make_item20(@content_nodes))} EOR @rss20 = Parser.parse(@rss20_source) end def test_parser assert_nothing_raised do Parser.parse(@rss10_source) end assert_nothing_raised do Parser.parse(@rss20_source) end @elems.each do |tag, value| tag_name = "#{@prefix}:#{tag}" content_encodes = make_element(tag_name, {}, value) * 2 assert_too_much_tag(tag.to_s, "item") do Parser.parse(make_RDF(<<-EOR, {@prefix => @uri})) #{make_channel} #{make_item(content_encodes)} EOR end assert_too_much_tag(tag.to_s, "item") do Parser.parse(make_rss20(<<-EOR, {@prefix => @uri})) #{make_channel20(make_item20(content_encodes))} EOR end end end def test_accessor new_value = { :encoded => "hoge]]>", } @elems.each do |name, value| [@rss10, @rss20].each do |rss| meth = "#{RSS::CONTENT_PREFIX}_#{name}" parent = rss.items.last assert_equal(value, parent.__send__(meth)) parent.__send__("#{meth}=", new_value[name].to_s) assert_equal(new_value[name], parent.__send__(meth)) end end end def test_to_s @elems.each do |name, value| excepted = make_element("#{@prefix}:#{name}", {}, value) meth = "#{RSS::CONTENT_PREFIX}_#{name}_element" [@rss10, @rss20].each do |rss| assert_equal(excepted, rss.items.last.__send__(meth)) end end [@rss10_source, @rss20_source].each do |source| REXML::Document.new(source).root.each_element do |parent| next unless parent.name != "item" parent.each_element do |elem| if elem.namespace == @uri assert_equal(elem.text, @elems[elem.name.intern].to_s) end end end end end end end ================================================ FILE: test/rss/test_dublincore.rb ================================================ require "cgi" require "rexml/document" require "rss-testcase" require "rss/1.0" require "rss/dublincore" module RSS class TestDublinCore < TestCase def setup @rss10_parents = [%w(channel), %w(image), %w(item), %w(textinput)] @rss10_source = make_RDF(<<-EOR, {DC_PREFIX => DC_URI}) #{make_channel(DC_NODES)} #{make_image(DC_NODES)} #{make_item(DC_NODES)} #{make_textinput(DC_NODES)} EOR @rss20_parents = [%w(channel), %w(items last)] @rss20_source = make_rss20(<<-EOR, {DC_PREFIX => DC_URI}) #{make_channel20(DC_NODES + make_item20(DC_NODES))} EOR @atom_feed_parents = [[], %w(entries last)] @atom_feed_source = make_feed(<<-EOR, {DC_PREFIX => DC_URI}) #{DC_NODES} #{make_entry(DC_NODES)} EOR @atom_entry_parents = [[]] @atom_entry_source = make_entry_document(<<-EOR, {DC_PREFIX => DC_URI}) #{DC_NODES} EOR end def test_parser rss10_maker = Proc.new do |content, xmlns| make_RDF(<<-EOR, xmlns) #{make_channel(content)} #{make_image(content)} #{make_item(content)} #{make_textinput(content)} EOR end assert_dc_parse(@rss10_source, @rss10_parents, false, &rss10_maker) assert_dc_parse(@rss10_source, @rss10_parents, true, &rss10_maker) rss20_maker = Proc.new do |content, xmlns| make_rss20(<<-EOR, xmlns) #{make_channel20(content + make_item20(content))} EOR end assert_dc_parse(@rss20_source, @rss20_parents, false, &rss20_maker) assert_dc_parse(@rss20_source, @rss20_parents, true, &rss20_maker) atom_feed_maker = Proc.new do |content, xmlns| make_feed(<<-EOR, xmlns) #{content} #{make_entry(content)} EOR end assert_dc_parse(@atom_feed_source, @atom_feed_parents, false, &atom_feed_maker) assert_dc_parse(@atom_feed_source, @atom_feed_parents, true, &atom_feed_maker) atom_entry_maker = Proc.new do |content, xmlns| make_entry_document(<<-EOR, xmlns) #{content} EOR end assert_dc_parse(@atom_entry_source, @atom_entry_parents, false, &atom_entry_maker) assert_dc_parse(@atom_entry_source, @atom_entry_parents, true, &atom_entry_maker) end def test_singular_accessor assert_dc_singular_accessor(@rss10_source, @rss10_parents) assert_dc_singular_accessor(@rss20_source, @rss20_parents) assert_dc_singular_accessor(@atom_feed_source, @atom_feed_parents) assert_dc_singular_accessor(@atom_entry_source, @atom_entry_parents) end def test_plural_accessor assert_dc_plural_accessor(@rss10_source, @rss10_parents, false) assert_dc_plural_accessor(@rss10_source, @rss10_parents, true) assert_dc_plural_accessor(@rss20_source, @rss20_parents, false) assert_dc_plural_accessor(@rss20_source, @rss20_parents, true) assert_dc_plural_accessor(@atom_feed_source, @atom_feed_parents, false) assert_dc_plural_accessor(@atom_feed_source, @atom_feed_parents, true) assert_dc_plural_accessor(@atom_entry_source, @atom_entry_parents, false) assert_dc_plural_accessor(@atom_entry_source, @atom_entry_parents, true) end def test_to_s assert_dc_to_s(@rss10_source, @rss10_parents, false) assert_dc_to_s(@rss10_source, @rss10_parents, true) targets = ["channel", "channel/item[3]"] assert_dc_to_s(@rss20_source, @rss20_parents, false, targets) assert_dc_to_s(@rss20_source, @rss20_parents, true, targets) targets = [".", "entry"] assert_dc_to_s(@atom_feed_source, @atom_feed_parents, false, targets) assert_dc_to_s(@atom_feed_source, @atom_feed_parents, true, targets) targets = ["."] assert_dc_to_s(@atom_entry_source, @atom_entry_parents, false, targets) assert_dc_to_s(@atom_entry_source, @atom_entry_parents, true, targets) end private def dc_plural_suffix(name, check_backward_compatibility) if name == :rights if check_backward_compatibility "es" else "_list" end else "s" end end def assert_dc_parse(source, parents, check_backward_compatibility, &maker) assert_nothing_raised do Parser.parse(source) end DC_ELEMENTS.each do |name, value| parents.each do |parent_readers| feed = nil assert_nothing_raised do tag = "#{DC_PREFIX}:#{name}" dc_content = "<#{tag}>#{value}\n" dc_content *= 2 feed = Parser.parse(maker.call(dc_content, {DC_PREFIX => DC_URI})) end parent = chain_reader(feed, parent_readers) plural_suffix = dc_plural_suffix(name, check_backward_compatibility) plural_reader = "dc_#{name}#{plural_suffix}" values = parent.__send__(plural_reader).collect do |x| val = x.value if val.kind_of?(String) CGI.escapeHTML(val) else val end end assert_equal([value, value], values) end end end def assert_dc_singular_accessor(source, parents) feed = Parser.parse(source) new_value = "hoge" parents.each do |parent_readers| parent = chain_reader(feed, parent_readers) DC_ELEMENTS.each do |name, value| parsed_value = parent.__send__("dc_#{name}") if parsed_value.kind_of?(String) parsed_value = CGI.escapeHTML(parsed_value) end assert_equal(value, parsed_value) if name == :date t = Time.iso8601("2003-01-01T02:30:23+09:00") class << t alias_method(:to_s, :iso8601) end parent.__send__("dc_#{name}=", t.iso8601) assert_equal(t, parent.__send__("dc_#{name}")) if parent.class.method_defined?(:date_without_dc_date=) assert_nil(parent.date) else assert_equal(t, parent.date) end parent.date = value assert_equal(value, parent.date) assert_equal(value, parent.__send__("dc_#{name}")) else parent.__send__("dc_#{name}=", new_value) assert_equal(new_value, parent.__send__("dc_#{name}")) end end end end def assert_dc_plural_accessor(source, parents, check_backward_compatibility) feed = Parser.parse(source) new_value = "hoge" DC_ELEMENTS.each do |name, value| parents.each do |parent_readers| parent = chain_reader(feed, parent_readers) parsed_value = parent.__send__("dc_#{name}") if parsed_value.kind_of?(String) parsed_value = CGI.escapeHTML(parsed_value) end assert_equal(value, parsed_value) plural_suffix = dc_plural_suffix(name, check_backward_compatibility) plural_reader = "dc_#{name}#{plural_suffix}" klass_name = "DublinCore#{Utils.to_class_name(name.to_s)}" klass = DublinCoreModel.const_get(klass_name) if name == :date t = Time.iso8601("2003-01-01T02:30:23+09:00") class << t alias_method(:to_s, :iso8601) end elems = parent.__send__(plural_reader) elems << klass.new(t.iso8601) new_elems = parent.__send__(plural_reader) values = new_elems.collect{|x| x.value} assert_equal([parent.__send__("dc_#{name}"), t], values) else elems = parent.__send__(plural_reader) elems << klass.new(new_value) new_elems = parent.__send__(plural_reader) values = new_elems.collect{|x| x.value} assert_equal([parent.__send__("dc_#{name}"), new_value], values) end end end end def assert_dc_to_s(source, parents, check_backward_compatibility, targets=nil) feed = Parser.parse(source) DC_ELEMENTS.each do |name, value| excepted = "<#{DC_PREFIX}:#{name}>#{value}" parents.each do |parent_readers| parent = chain_reader(feed, parent_readers) assert_equal(excepted, parent.__send__("dc_#{name}_elements")) end plural_suffix = dc_plural_suffix(name, check_backward_compatibility) reader = "dc_#{name}#{plural_suffix}" excepted = Array.new(2, excepted).join("\n") parents.each do |parent_readers| parent = chain_reader(feed, parent_readers) elems = parent.__send__(reader) klass_name = "DublinCore#{Utils.to_class_name(name.to_s)}" klass = DublinCoreModel.const_get(klass_name) elems << klass.new(parent.__send__("dc_#{name}")) assert_equal(excepted, parent.__send__("dc_#{name}_elements")) end end targets ||= parents.collect do |parent_readers| parent_readers.first end feed_root = REXML::Document.new(source).root targets.each do |target_xpath| parent = feed_root.elements[target_xpath] parent.each_element do |elem| if elem.namespace == DC_URI assert_equal(CGI.escapeHTML(elem.text), DC_ELEMENTS[elem.name.intern].to_s) end end end end end end ================================================ FILE: test/rss/test_image.rb ================================================ require "cgi" require "rexml/document" require "rss-testcase" require "rss/1.0" require "rss/image" module RSS class TestImage < TestCase def setup @prefix = "image" @uri = "http://purl.org/rss/1.0/modules/image/" @favicon_attrs = { "rdf:about" => "http://www.kuro5hin.org/favicon.ico", "#{@prefix}:size" => "small", } @favicon_contents = {"dc:title" => "Kuro5hin",} @items = [ [ { "rdf:about" => "http://www.example.org/item.png", "rdf:resource" => "http://www.example.org/item", }, { "dc:title" => "Example Image", "#{@prefix}:width" => "100", "#{@prefix}:height" => "65", }, ], [ { "rdf:about" => "http://www.kuro5hin.org/images/topics/culture.jpg", }, { "dc:title" => "Culture", "#{@prefix}:width" => "80", "#{@prefix}:height" => "50", }, ] ] @channel_nodes = make_element("#{@prefix}:favicon", @favicon_attrs, @favicon_contents) items = "" @items.each do |attrs, contents| image_item = make_element("#{@prefix}:item", attrs, contents) items << make_item(image_item) end @ns = { @prefix => @uri, DC_PREFIX => DC_URI, } @rss_source = make_RDF(<<-EOR, @ns) #{make_channel(@channel_nodes)} #{make_image} #{items} #{make_textinput} EOR @rss = Parser.parse(@rss_source) end def test_parser assert_nothing_raised do Parser.parse(@rss_source) end assert_too_much_tag("favicon", "channel") do Parser.parse(make_RDF(<<-EOR, @ns)) #{make_channel(@channel_nodes * 2)} #{make_item} EOR end attrs = {"rdf:about" => "http://www.example.org/item.png"} contents = [["#{@prefix}:width", "80"]] * 5 image_item = make_element("#{@prefix}:item", attrs, contents) assert_too_much_tag("width", "item") do Parser.parse(make_RDF(<<-EOR, @ns)) #{make_channel} #{make_item(image_item)} EOR end end def test_favicon_accessor favicon = @rss.channel.image_favicon [ %w(about rdf:about http://example.com/favicon.ico), %w(size image:size large), %w(image_size image:size medium), ].each do |name, full_name, new_value| assert_equal(@favicon_attrs[full_name], favicon.__send__(name)) favicon.__send__("#{name}=", new_value) assert_equal(new_value, favicon.__send__(name)) favicon.__send__("#{name}=", @favicon_attrs[full_name]) assert_equal(@favicon_attrs[full_name], favicon.__send__(name)) end %w(small medium large).each do |value| assert_nothing_raised do favicon.size = value favicon.image_size = value end end %w(aaa AAA SMALL MEDIUM LARGE).each do |value| args = ["#{@prefix}:favicon", value, "#{@prefix}:size"] assert_not_available_value(*args) do favicon.size = value end assert_not_available_value(*args) do favicon.image_size = value end end [ %w(dc_title dc:title sample-favicon), ].each do |name, full_name, new_value| assert_equal(@favicon_contents[full_name], favicon.__send__(name)) favicon.__send__("#{name}=", new_value) assert_equal(new_value, favicon.__send__(name)) favicon.__send__("#{name}=", @favicon_contents[full_name]) assert_equal(@favicon_contents[full_name], favicon.__send__(name)) end end def test_item_accessor @rss.items.each_with_index do |item, i| image_item = item.image_item attrs, contents = @items[i] [ %w(about rdf:about http://example.com/image.png), %w(resource rdf:resource http://example.com/), ].each do |name, full_name, new_value| assert_equal(attrs[full_name], image_item.__send__(name)) image_item.__send__("#{name}=", new_value) assert_equal(new_value, image_item.__send__(name)) image_item.__send__("#{name}=", attrs[full_name]) assert_equal(attrs[full_name], image_item.__send__(name)) end [ ["width", "image:width", "111"], ["image_width", "image:width", "44"], ["height", "image:height", "222"], ["image_height", "image:height", "88"], ].each do |name, full_name, new_value| assert_equal(contents[full_name].to_i, image_item.__send__(name)) image_item.__send__("#{name}=", new_value) assert_equal(new_value.to_i, image_item.__send__(name)) image_item.__send__("#{name}=", contents[full_name]) assert_equal(contents[full_name].to_i, image_item.__send__(name)) end [ ["dc_title", "dc:title", "sample-image"], ].each do |name, full_name, new_value| assert_equal(contents[full_name], image_item.__send__(name)) image_item.__send__("#{name}=", new_value) assert_equal(new_value, image_item.__send__(name)) image_item.__send__("#{name}=", contents[full_name]) assert_equal(contents[full_name], image_item.__send__(name)) end end end def test_favicon_to_s favicon = @rss.channel.image_favicon expected_xml = image_xmlns_container(make_element("#{@prefix}:favicon", @favicon_attrs, @favicon_contents)) expected = REXML::Document.new(expected_xml) actual_xml = image_xmlns_container(favicon.to_s(false, "")) actual = REXML::Document.new(actual_xml) assert_equal(expected.to_s, actual.to_s) end def test_item_to_s @rss.items.each_with_index do |item, i| attrs, contents = @items[i] expected_xml = make_element("#{@prefix}:item", attrs, contents) expected_xml = image_xmlns_container(expected_xml) expected = REXML::Document.new(expected_xml) actual_xml = image_xmlns_container(item.image_item.to_s(false, "")) actual = REXML::Document.new(actual_xml) assert_equal(expected[0].attributes, actual[0].attributes) %w(image:height image:width dc:title).each do |name| actual_target = actual.elements["//#{name}"] expected_target = expected.elements["//#{name}"] assert_equal(expected_target.to_s, actual_target.to_s) end end end private def image_xmlns_container(content) xmlns_container({ @prefix => @uri, "dc" => "http://purl.org/dc/elements/1.1/", "rdf" => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", }, content) end end end ================================================ FILE: test/rss/test_inherit.rb ================================================ require "rss-testcase" require "rss/1.0" module RSS class TestInherit < TestCase class InheritedImage < RSS::RDF::Image def self.indent_size; 1; end def self.tag_name; 'image'; end end def setup @rss = make_RDF(<<-EOR) #{make_channel} #{make_image} #{make_item} #{make_textinput} EOR end def test_inherit rss = RSS::Parser.parse(@rss) orig_image = rss.image prefix = "[INHERIT]" image = InheritedImage.new("#{prefix} #{orig_image.about}") image.title = "#{prefix} #{orig_image.title}" image.url = "#{prefix} #{orig_image.url}" image.link = "#{prefix} #{orig_image.link}" rss.image = image new_rss = RSS::Parser.parse(rss.to_s) new_image = new_rss.image assert_equal("#{prefix} #{orig_image.about}", new_image.about) assert_equal("#{prefix} #{orig_image.title}", new_image.title) assert_equal("#{prefix} #{orig_image.url}", new_image.url) assert_equal("#{prefix} #{orig_image.link}", new_image.link) end end end ================================================ FILE: test/rss/test_itunes.rb ================================================ require "cgi" require "rexml/document" require "rss-testcase" require "rss/2.0" require "rss/itunes" module RSS class TestITunes < TestCase def test_author assert_itunes_author(%w(channel)) do |content, xmlns| make_rss20(make_channel20(content), xmlns) end assert_itunes_author(%w(items last)) do |content, xmlns| make_rss20(make_channel20(make_item20(content)), xmlns) end end def test_block assert_itunes_block(%w(items last)) do |content, xmlns| make_rss20(make_channel20(make_item20(content)), xmlns) end end def test_category assert_itunes_category(%w(channel)) do |content, xmlns| make_rss20(make_channel20(content), xmlns) end end def test_image assert_itunes_image(%w(channel)) do |content, xmlns| make_rss20(make_channel20(content), xmlns) end end def test_duration assert_itunes_duration(%w(items last)) do |content, xmlns| make_rss20(make_channel20(make_item20(content)), xmlns) end end def test_explicit assert_itunes_explicit(%w(channel)) do |content, xmlns| make_rss20(make_channel20(content), xmlns) end assert_itunes_explicit(%w(items last)) do |content, xmlns| make_rss20(make_channel20(make_item20(content)), xmlns) end end def test_keywords assert_itunes_keywords(%w(channel)) do |content, xmlns| make_rss20(make_channel20(content), xmlns) end assert_itunes_keywords(%w(items last)) do |content, xmlns| make_rss20(make_channel20(make_item20(content)), xmlns) end end def test_new_feed_url assert_itunes_new_feed_url(%w(channel)) do |content, xmlns| make_rss20(make_channel20(content), xmlns) end end def test_owner assert_itunes_owner(%w(channel)) do |content, xmlns| make_rss20(make_channel20(content), xmlns) end end def test_subtitle assert_itunes_subtitle(%w(channel)) do |content, xmlns| make_rss20(make_channel20(content), xmlns) end assert_itunes_subtitle(%w(items last)) do |content, xmlns| make_rss20(make_channel20(make_item20(content)), xmlns) end end def test_summary assert_itunes_summary(%w(channel)) do |content, xmlns| make_rss20(make_channel20(content), xmlns) end assert_itunes_summary(%w(items last)) do |content, xmlns| make_rss20(make_channel20(make_item20(content)), xmlns) end end private def itunes_rss20_parse(content, &maker) xmlns = {"itunes" => "http://www.itunes.com/dtds/podcast-1.0.dtd"} rss20_xml = maker.call(content, xmlns) ::RSS::Parser.parse(rss20_xml) end def assert_itunes_author(readers, &rss20_maker) _wrap_assertion do author = "John Lennon" rss20 = itunes_rss20_parse(tag("itunes:author", author), &rss20_maker) target = chain_reader(rss20, readers) assert_equal(author, target.itunes_author) end end def _assert_itunes_block(value, boolean_value, readers, &rss20_maker) rss20 = itunes_rss20_parse(tag("itunes:block", value), &rss20_maker) target = chain_reader(rss20, readers) assert_equal(value, target.itunes_block) assert_equal(boolean_value, target.itunes_block?) end def assert_itunes_block(readers, &rss20_maker) _wrap_assertion do _assert_itunes_block("yes", true, readers, &rss20_maker) _assert_itunes_block("Yes", true, readers, &rss20_maker) _assert_itunes_block("no", false, readers, &rss20_maker) _assert_itunes_block("", false, readers, &rss20_maker) end end def _assert_itunes_category(categories, readers, &rss20_maker) cats = categories.collect do |category| if category.is_a?(Array) category, sub_category = category tag("itunes:category", tag("itunes:category", nil, {"text" => sub_category}), {"text" => category}) else tag("itunes:category", nil, {"text" => category}) end end.join rss20 = itunes_rss20_parse(cats, &rss20_maker) target = chain_reader(rss20, readers) actual_categories = target.itunes_categories.collect do |category| cat = category.text if category.itunes_categories.empty? cat else [cat, *category.itunes_categories.collect {|c| c.text}] end end assert_equal(categories, actual_categories) end def assert_itunes_category(readers, &rss20_maker) _wrap_assertion do _assert_itunes_category(["Audio Blogs"], readers, &rss20_maker) _assert_itunes_category([["Arts & Entertainment", "Games"]], readers, &rss20_maker) _assert_itunes_category([["Arts & Entertainment", "Games"], ["Technology", "Computers"], "Audio Blogs"], readers, &rss20_maker) end end def assert_itunes_image(readers, &rss20_maker) _wrap_assertion do url = "http://example.com/podcasts/everything/AllAboutEverything.jpg" content = tag("itunes:image", nil, {"href" => url}) rss20 = itunes_rss20_parse(content, &rss20_maker) target = chain_reader(rss20, readers) assert_not_nil(target.itunes_image) assert_equal(url, target.itunes_image.href) assert_missing_attribute("image", "href") do content = tag("itunes:image") itunes_rss20_parse(content, &rss20_maker) end end end def _assert_itunes_duration(hour, minute, second, value, readers, &rss20_maker) content = tag("itunes:duration", value) rss20 = itunes_rss20_parse(content, &rss20_maker) duration = chain_reader(rss20, readers).itunes_duration assert_equal(value, duration.content) assert_equal(hour, duration.hour) assert_equal(minute, duration.minute) assert_equal(second, duration.second) end def _assert_itunes_duration_not_available_value(value, &rss20_maker) assert_not_available_value("duration", value) do content = tag("itunes:duration", value) itunes_rss20_parse(content, &rss20_maker) end end def assert_itunes_duration(readers, &rss20_maker) _wrap_assertion do _assert_itunes_duration(7, 14, 5, "07:14:05", readers, &rss20_maker) _assert_itunes_duration(7, 14, 5, "7:14:05", readers, &rss20_maker) _assert_itunes_duration(0, 4, 55, "04:55", readers, &rss20_maker) _assert_itunes_duration(0, 4, 5, "4:05", readers, &rss20_maker) _assert_itunes_duration_not_available_value("5", &rss20_maker) _assert_itunes_duration_not_available_value("09:07:14:05", &rss20_maker) _assert_itunes_duration_not_available_value("10:5", &rss20_maker) _assert_itunes_duration_not_available_value("10:03:5", &rss20_maker) _assert_itunes_duration_not_available_value("10:3:05", &rss20_maker) _assert_itunes_duration_not_available_value("xx:xx:xx", &rss20_maker) end end def _assert_itunes_explicit(explicit, value, readers, &rss20_maker) content = tag("itunes:explicit", value) rss20 = itunes_rss20_parse(content, &rss20_maker) target = chain_reader(rss20, readers) assert_equal(value, target.itunes_explicit) assert_equal(explicit, target.itunes_explicit?) end def assert_itunes_explicit(readers, &rss20_maker) _wrap_assertion do _assert_itunes_explicit(true, "yes", readers, &rss20_maker) _assert_itunes_explicit(false, "clean", readers, &rss20_maker) _assert_itunes_explicit(nil, "no", readers, &rss20_maker) end end def _assert_itunes_keywords(keywords, value, readers, &rss20_maker) content = tag("itunes:keywords", value) rss20 = itunes_rss20_parse(content, &rss20_maker) target = chain_reader(rss20, readers) assert_equal(keywords, target.itunes_keywords) end def assert_itunes_keywords(readers, &rss20_maker) _wrap_assertion do _assert_itunes_keywords(["salt"], "salt", readers, &rss20_maker) _assert_itunes_keywords(["salt"], " salt ", readers, &rss20_maker) _assert_itunes_keywords(["salt", "pepper", "shaker", "exciting"], "salt, pepper, shaker, exciting", readers, &rss20_maker) _assert_itunes_keywords(["metric", "socket", "wrenches", "toolsalt"], "metric, socket, wrenches, toolsalt", readers, &rss20_maker) _assert_itunes_keywords(["olitics", "red", "blue", "state"], "olitics, red, blue, state", readers, &rss20_maker) end end def assert_itunes_new_feed_url(readers, &rss20_maker) _wrap_assertion do url = "http://newlocation.com/example.rss" content = tag("itunes:new-feed-url", url) rss20 = itunes_rss20_parse(content, &rss20_maker) target = chain_reader(rss20, readers) assert_equal(url, target.itunes_new_feed_url) end end def _assert_itunes_owner(name, email, readers, &rss20_maker) content = tag("itunes:owner", tag("itunes:name", name) + tag("itunes:email", email)) rss20 = itunes_rss20_parse(content, &rss20_maker) owner = chain_reader(rss20, readers).itunes_owner assert_equal(name, owner.itunes_name) assert_equal(email, owner.itunes_email) end def assert_itunes_owner(readers, &rss20_maker) _wrap_assertion do _assert_itunes_owner("John Doe", "john.doe@example.com", readers, &rss20_maker) assert_missing_tag("name", "owner") do content = tag("itunes:owner") itunes_rss20_parse(content, &rss20_maker) end assert_missing_tag("name", "owner") do content = tag("itunes:owner", tag("itunes:email", "john.doe@example.com")) itunes_rss20_parse(content, &rss20_maker) end assert_missing_tag("email", "owner") do content = tag("itunes:owner", tag("itunes:name", "John Doe")) itunes_rss20_parse(content, &rss20_maker) end end end def _assert_itunes_subtitle(value, readers, &rss20_maker) content = tag("itunes:subtitle", value) rss20 = itunes_rss20_parse(content, &rss20_maker) target = chain_reader(rss20, readers) assert_equal(value, target.itunes_subtitle) end def assert_itunes_subtitle(readers, &rss20_maker) _wrap_assertion do _assert_itunes_subtitle("A show about everything", readers, &rss20_maker) _assert_itunes_subtitle("A short primer on table spices", readers, &rss20_maker) _assert_itunes_subtitle("Comparing socket wrenches is fun!", readers, &rss20_maker) _assert_itunes_subtitle("Red + Blue != Purple", readers, &rss20_maker) end end def _assert_itunes_summary(value, readers, &rss20_maker) content = tag("itunes:summary", value) rss20 = itunes_rss20_parse(content, &rss20_maker) target = chain_reader(rss20, readers) assert_equal(value, target.itunes_summary) end def assert_itunes_summary(readers, &rss20_maker) _wrap_assertion do _assert_itunes_summary("All About Everything is a show about " + "everything. Each week we dive into any " + "subject known to man and talk about it as " + "much as we can. Look for our Podcast in " + "the iTunes Music Store", readers, &rss20_maker) _assert_itunes_summary("This week we talk about salt and pepper " + "shakers, comparing and contrasting pour " + "rates, construction materials, and overall " + "aesthetics. Come and join the party!", readers, &rss20_maker) _assert_itunes_summary("This week we talk about metric vs. old " + "english socket wrenches. Which one is " + "better? Do you really need both? Get all " + "of your answers here.", readers, &rss20_maker) _assert_itunes_summary("This week we talk about surviving in a " + "Red state if you're a Blue person. Or " + "vice versa.", readers, &rss20_maker) end end end end ================================================ FILE: test/rss/test_maker_0.9.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestMaker09 < TestCase def test_rss rss = RSS::Maker.make("0.91") assert_nil(rss) rss = RSS::Maker.make("0.9") do |maker| setup_dummy_channel(maker) setup_dummy_image(maker) end assert_equal("0.92", rss.rss_version) rss = RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) setup_dummy_image(maker) end assert_equal("0.91", rss.rss_version) rss = RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) setup_dummy_image(maker) maker.encoding = "EUC-JP" end assert_equal("0.91", rss.rss_version) assert_equal("EUC-JP", rss.encoding) rss = RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) setup_dummy_image(maker) maker.standalone = "yes" end assert_equal("0.91", rss.rss_version) assert_equal("yes", rss.standalone) rss = RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) setup_dummy_image(maker) maker.encoding = "EUC-JP" maker.standalone = "yes" end assert_equal("0.91", rss.rss_version) assert_equal("EUC-JP", rss.encoding) assert_equal("yes", rss.standalone) end def test_channel title = "fugafuga" link = "http://hoge.com" description = "fugafugafugafuga" language = "ja" copyright = "foo" managingEditor = "bar" webMaster = "web master" rating = '(PICS-1.1 "http://www.rsac.org/ratingsv01.html" l gen true comment "RSACi North America Server" for "http://www.rsac.org" on "1996.04.16T08:15-0500" r (n 0 s 0 v 0 l 0))' docs = "http://foo.com/doc" skipDays = [ "Sunday", "Monday", ] skipHours = [ "0", "13", ] pubDate = Time.now lastBuildDate = Time.now image_url = "http://example.com/logo.png" image_title = "Logo" rss = RSS::Maker.make("0.91") do |maker| maker.channel.title = title maker.channel.link = link maker.channel.description = description maker.channel.language = language maker.channel.copyright = copyright maker.channel.managingEditor = managingEditor maker.channel.webMaster = webMaster maker.channel.rating = rating maker.channel.docs = docs maker.channel.pubDate = pubDate maker.channel.lastBuildDate = lastBuildDate skipDays.each do |day| maker.channel.skipDays.new_day do |new_day| new_day.content = day end end skipHours.each do |hour| maker.channel.skipHours.new_hour do |new_hour| new_hour.content = hour end end maker.image.url = image_url maker.image.title = image_title end channel = rss.channel assert_equal(title, channel.title) assert_equal(link, channel.link) assert_equal(description, channel.description) assert_equal(language, channel.language) assert_equal(copyright, channel.copyright) assert_equal(managingEditor, channel.managingEditor) assert_equal(webMaster, channel.webMaster) assert_equal(rating, channel.rating) assert_equal(docs, channel.docs) assert_equal(pubDate, channel.pubDate) assert_equal(pubDate, channel.date) assert_equal(lastBuildDate, channel.lastBuildDate) skipDays.each_with_index do |day, i| assert_equal(day, channel.skipDays.days[i].content) end skipHours.each_with_index do |hour, i| assert_equal(hour.to_i, channel.skipHours.hours[i].content) end assert(channel.items.empty?) assert_equal(image_url, channel.image.url) assert_equal(image_title, channel.image.title) assert_equal(link, channel.image.link) assert_nil(channel.textInput) end def test_not_valid_channel title = "fugafuga" link = "http://hoge.com" description = "fugafugafugafuga" language = "ja" assert_not_set_error("maker.channel", %w(title)) do RSS::Maker.make("0.91") do |maker| # maker.channel.title = title maker.channel.link = link maker.channel.description = description maker.channel.language = language end end assert_not_set_error("maker.channel", %w(link)) do RSS::Maker.make("0.91") do |maker| maker.channel.title = title # maker.channel.link = link maker.channel.link = nil maker.channel.description = description maker.channel.language = language end end assert_not_set_error("maker.channel", %w(description)) do RSS::Maker.make("0.91") do |maker| maker.channel.title = title maker.channel.link = link # maker.channel.description = description maker.channel.language = language end end assert_not_set_error("maker.channel", %w(language)) do RSS::Maker.make("0.91") do |maker| maker.channel.title = title maker.channel.link = link maker.channel.description = description # maker.channel.language = language end end end def test_image title = "fugafuga" link = "http://hoge.com" url = "http://hoge.com/hoge.png" width = "144" height = "400" description = "an image" rss = RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) maker.channel.link = link maker.image.title = title maker.image.url = url maker.image.width = width maker.image.height = height maker.image.description = description end image = rss.image assert_equal(title, image.title) assert_equal(link, image.link) assert_equal(url, image.url) assert_equal(width.to_i, image.width) assert_equal(height.to_i, image.height) assert_equal(description, image.description) assert_not_set_error("maker.channel", %w(description title language)) do RSS::Maker.make("0.91") do |maker| # setup_dummy_channel(maker) maker.channel.link = link maker.image.title = title maker.image.url = url maker.image.width = width maker.image.height = height maker.image.description = description end end end def test_not_valid_image title = "fugafuga" link = "http://hoge.com" url = "http://hoge.com/hoge.png" width = "144" height = "400" description = "an image" assert_not_set_error("maker.image", %w(title)) do RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) maker.channel.link = link # maker.image.title = title maker.image.url = url maker.image.width = width maker.image.height = height maker.image.description = description end end assert_not_set_error("maker.channel", %w(link)) do RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) # maker.channel.link = link maker.channel.link = nil maker.image.title = title maker.image.url = url maker.image.width = width maker.image.height = height maker.image.description = description end end assert_not_set_error("maker.image", %w(url)) do RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) maker.channel.link = link maker.image.title = title # maker.image.url = url maker.image.width = width maker.image.height = height maker.image.description = description end end end def test_items(with_convenience_way=true) title = "TITLE" link = "http://hoge.com/" description = "text hoge fuga" rss = RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) setup_dummy_image(maker) end assert(rss.channel.items.empty?) rss = RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) maker.items.new_item do |item| item.title = title item.link = link # item.description = description end setup_dummy_image(maker) end assert_equal(1, rss.channel.items.size) item = rss.channel.items.first assert_equal(title, item.title) assert_equal(link, item.link) assert_nil(item.description) item_size = 5 rss = RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) item_size.times do |i| maker.items.new_item do |_item| _item.title = "#{title}#{i}" _item.link = "#{link}#{i}" _item.description = "#{description}#{i}" end end maker.items.do_sort = true setup_dummy_image(maker) end assert_equal(item_size, rss.items.size) rss.channel.items.each_with_index do |_item, i| assert_equal("#{title}#{i}", _item.title) assert_equal("#{link}#{i}", _item.link) assert_equal("#{description}#{i}", _item.description) end rss = RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) item_size.times do |i| maker.items.new_item do |_item| _item.title = "#{title}#{i}" _item.link = "#{link}#{i}" _item.description = "#{description}#{i}" end end maker.items.do_sort = Proc.new do |x, y| if with_convenience_way y.title[-1] <=> x.title[-1] else y.title {|t| t.content[-1]} <=> x.title {|t| t.content[-1]} end end setup_dummy_image(maker) end assert_equal(item_size, rss.items.size) rss.channel.items.reverse.each_with_index do |_item, i| assert_equal("#{title}#{i}", _item.title) assert_equal("#{link}#{i}", _item.link) assert_equal("#{description}#{i}", _item.description) end end def test_items_with_new_api_since_018 test_items(false) end def test_textInput title = "fugafuga" description = "text hoge fuga" name = "hoge" link = "http://hoge.com" rss = RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) setup_dummy_image(maker) maker.textinput.title = title maker.textinput.description = description maker.textinput.name = name maker.textinput.link = link end textInput = rss.channel.textInput assert_equal(title, textInput.title) assert_equal(description, textInput.description) assert_equal(name, textInput.name) assert_equal(link, textInput.link) assert_not_set_error("maker.channel", %w(link language description title)) do RSS::Maker.make("0.91") do |maker| # setup_dummy_channel(maker) maker.textinput.title = title maker.textinput.description = description maker.textinput.name = name maker.textinput.link = link end end end def test_not_valid_textInput title = "fugafuga" description = "text hoge fuga" name = "hoge" link = "http://hoge.com" rss = RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) setup_dummy_image(maker) # maker.textinput.title = title maker.textinput.description = description maker.textinput.name = name maker.textinput.link = link end assert_nil(rss.channel.textInput) rss = RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) setup_dummy_image(maker) maker.textinput.title = title # maker.textinput.description = description maker.textinput.name = name maker.textinput.link = link end assert_nil(rss.channel.textInput) rss = RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) setup_dummy_image(maker) maker.textinput.title = title maker.textinput.description = description # maker.textinput.name = name maker.textinput.link = link end assert_nil(rss.channel.textInput) rss = RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) setup_dummy_image(maker) maker.textinput.title = title maker.textinput.description = description maker.textinput.name = name # maker.textinput.link = link end assert_nil(rss.channel.textInput) end end end ================================================ FILE: test/rss/test_maker_1.0.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestMaker10 < TestCase def test_rdf rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) end assert_equal("1.0", rss.rss_version) rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) maker.encoding = "EUC-JP" setup_dummy_item(maker) end assert_equal("1.0", rss.rss_version) assert_equal("EUC-JP", rss.encoding) rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) maker.standalone = "yes" setup_dummy_item(maker) end assert_equal("1.0", rss.rss_version) assert_equal("yes", rss.standalone) rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) maker.encoding = "EUC-JP" maker.standalone = "yes" setup_dummy_item(maker) end assert_equal("1.0", rss.rss_version) assert_equal("EUC-JP", rss.encoding) assert_equal("yes", rss.standalone) end def test_channel about = "http://hoge.com" title = "fugafuga" link = "http://hoge.com" description = "fugafugafugafuga" rss = RSS::Maker.make("1.0") assert_nil(rss) rss = RSS::Maker.make("1.0") do |maker| maker.channel.about = about maker.channel.title = title maker.channel.link = link maker.channel.description = description setup_dummy_item(maker) end channel = rss.channel assert_equal(about, channel.about) assert_equal(title, channel.title) assert_equal(link, channel.link) assert_equal(description, channel.description) assert_equal(1, channel.items.Seq.lis.size) assert_nil(channel.image) assert_nil(channel.textinput) rss = RSS::Maker.make("1.0") do |maker| maker.channel.about = about maker.channel.title = title maker.channel.link = link maker.channel.description = description setup_dummy_image(maker) setup_dummy_textinput(maker) setup_dummy_item(maker) end channel = rss.channel assert_equal(about, channel.about) assert_equal(title, channel.title) assert_equal(link, channel.link) assert_equal(description, channel.description) assert_equal(1, channel.items.Seq.lis.size) assert_equal(rss.image.about, channel.image.resource) assert_equal(rss.textinput.about, channel.textinput.resource) end def test_not_valid_channel about = "http://hoge.com" title = "fugafuga" link = "http://hoge.com" description = "fugafugafugafuga" assert_not_set_error("maker.channel", %w(about)) do RSS::Maker.make("1.0") do |maker| # maker.channel.about = about maker.channel.title = title maker.channel.link = link maker.channel.description = description end end assert_not_set_error("maker.channel", %w(title)) do RSS::Maker.make("1.0") do |maker| maker.channel.about = about # maker.channel.title = title maker.channel.link = link maker.channel.description = description end end assert_not_set_error("maker.channel", %w(link)) do RSS::Maker.make("1.0") do |maker| maker.channel.about = about maker.channel.title = title # maker.channel.link = link maker.channel.description = description end end assert_not_set_error("maker.channel", %w(description)) do RSS::Maker.make("1.0") do |maker| maker.channel.about = about maker.channel.title = title maker.channel.link = link # maker.channel.description = description end end end def test_image title = "fugafuga" link = "http://hoge.com" url = "http://hoge.com/hoge.png" rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) maker.channel.link = link maker.image.title = title maker.image.url = url setup_dummy_item(maker) end image = rss.image assert_equal(url, image.about) assert_equal(url, rss.channel.image.resource) assert_equal(title, image.title) assert_equal(link, image.link) assert_equal(url, image.url) assert_not_set_error("maker.channel", %w(about title description)) do RSS::Maker.make("1.0") do |maker| # setup_dummy_channel(maker) maker.channel.link = link maker.image.title = title maker.image.url = url end end end def test_not_valid_image title = "fugafuga" link = "http://hoge.com" url = "http://hoge.com/hoge.png" rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) maker.channel.link = link # maker.image.url = url maker.image.title = title setup_dummy_item(maker) end assert_nil(rss.channel.image) assert_nil(rss.image) rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) maker.channel.link = link maker.image.url = url # maker.image.title = title setup_dummy_item(maker) end assert_nil(rss.channel.image) assert_nil(rss.image) assert_not_set_error("maker.channel", %w(link)) do RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) # maker.channel.link = link maker.channel.link = nil maker.image.url = url maker.image.title = title setup_dummy_item(maker) end end end def test_items(with_convenience_way=true) title = "TITLE" link = "http://hoge.com/" description = "text hoge fuga" assert_not_set_error("maker", %w(items)) do RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) end end rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) maker.items.new_item do |item| item.title = title item.link = link # item.description = description end end assert_equal(1, rss.items.size) item = rss.items.first assert_equal(link, item.about) assert_equal(title, item.title) assert_equal(link, item.link) assert_nil(item.description) item_size = 5 rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) item_size.times do |i| maker.items.new_item do |_item| _item.title = "#{title}#{i}" _item.link = "#{link}#{i}" _item.description = "#{description}#{i}" end end maker.items.do_sort = true end assert_equal(item_size, rss.items.size) rss.items.each_with_index do |_item, i| assert_equal("#{link}#{i}", _item.about) assert_equal("#{title}#{i}", _item.title) assert_equal("#{link}#{i}", _item.link) assert_equal("#{description}#{i}", _item.description) end rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) item_size.times do |i| maker.items.new_item do |_item| _item.title = "#{title}#{i}" _item.link = "#{link}#{i}" _item.description = "#{description}#{i}" end end maker.items.do_sort = Proc.new do |x, y| if with_convenience_way y.title[-1] <=> x.title[-1] else y.title {|t| t.content[-1]} <=> x.title {|t| t.content[-1]} end end end assert_equal(item_size, rss.items.size) rss.items.reverse.each_with_index do |_item, i| assert_equal("#{link}#{i}", _item.about) assert_equal("#{title}#{i}", _item.title) assert_equal("#{link}#{i}", _item.link) assert_equal("#{description}#{i}", _item.description) end max_size = item_size / 2 rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) item_size.times do |i| maker.items.new_item do |_item| _item.title = "#{title}#{i}" _item.link = "#{link}#{i}" _item.description = "#{description}#{i}" end end maker.items.max_size = max_size end assert_equal(max_size, rss.items.size) rss.items.each_with_index do |_item, i| assert_equal("#{link}#{i}", _item.about) assert_equal("#{title}#{i}", _item.title) assert_equal("#{link}#{i}", _item.link) assert_equal("#{description}#{i}", _item.description) end max_size = 0 assert_not_set_error("maker", %w(items)) do RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) item_size.times do |i| maker.items.new_item do |_item| _item.title = "#{title}#{i}" _item.link = "#{link}#{i}" _item.description = "#{description}#{i}" end end maker.items.max_size = max_size end end max_size = -2 rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) item_size.times do |i| maker.items.new_item do |_item| _item.title = "#{title}#{i}" _item.link = "#{link}#{i}" _item.description = "#{description}#{i}" end end maker.items.max_size = max_size end assert_equal(item_size + max_size + 1, rss.items.size) rss.items.each_with_index do |_item, i| assert_equal("#{link}#{i}", _item.about) assert_equal("#{title}#{i}", _item.title) assert_equal("#{link}#{i}", _item.link) assert_equal("#{description}#{i}", _item.description) end end def test_items_with_new_api_since_018 test_items(false) end def test_not_valid_items title = "TITLE" link = "http://hoge.com/" assert_not_set_error("maker.item", %w(title)) do RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) maker.items.new_item do |item| # item.title = title item.link = link end end end assert_not_set_error("maker.item", %w(link)) do RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) maker.items.new_item do |item| item.title = title # item.link = link end end end assert_not_set_error("maker.item", %w(title link)) do RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) maker.items.new_item do |item| # item.title = title # item.link = link end end end end def test_textinput title = "fugafuga" description = "text hoge fuga" name = "hoge" link = "http://hoge.com" rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) maker.textinput.link = link maker.textinput.title = title maker.textinput.description = description maker.textinput.name = name setup_dummy_item(maker) end textinput = rss.textinput assert_equal(link, textinput.about) assert_equal(link, rss.channel.textinput.resource) assert_equal(title, textinput.title) assert_equal(name, textinput.name) assert_equal(description, textinput.description) assert_equal(link, textinput.link) assert_not_set_error("maker.channel", %w(about link description title)) do RSS::Maker.make("1.0") do |maker| # setup_dummy_channel(maker) maker.textinput.link = link maker.textinput.title = title maker.textinput.description = description maker.textinput.name = name end end end def test_not_valid_textinput title = "fugafuga" description = "text hoge fuga" name = "hoge" link = "http://hoge.com" rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) # maker.textinput.link = link maker.textinput.title = title maker.textinput.description = description maker.textinput.name = name setup_dummy_item(maker) end assert_nil(rss.channel.textinput) assert_nil(rss.textinput) rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) maker.textinput.link = link # maker.textinput.title = title maker.textinput.description = description maker.textinput.name = name setup_dummy_item(maker) end assert_nil(rss.channel.textinput) assert_nil(rss.textinput) rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) maker.textinput.link = link maker.textinput.title = title # maker.textinput.description = description maker.textinput.name = name setup_dummy_item(maker) end assert_nil(rss.channel.textinput) assert_nil(rss.textinput) rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) maker.textinput.link = link maker.textinput.title = title maker.textinput.description = description # maker.textinput.name = name setup_dummy_item(maker) end assert_nil(rss.channel.textinput) assert_nil(rss.textinput) end end end ================================================ FILE: test/rss/test_maker_2.0.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestMaker20 < TestCase def test_rss rss = RSS::Maker.make("2.0") assert_nil(rss) rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) end assert_equal("2.0", rss.rss_version) rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) maker.encoding = "EUC-JP" end assert_equal("2.0", rss.rss_version) assert_equal("EUC-JP", rss.encoding) rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) maker.standalone = "yes" end assert_equal("2.0", rss.rss_version) assert_equal("yes", rss.standalone) rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) maker.encoding = "EUC-JP" maker.standalone = "yes" end assert_equal("2.0", rss.rss_version) assert_equal("EUC-JP", rss.encoding) assert_equal("yes", rss.standalone) end def test_channel title = "fugafuga" link = "http://hoge.com" description = "fugafugafugafuga" language = "ja" copyright = "foo" managingEditor = "bar" webMaster = "web master" rating = '(PICS-1.1 "http://www.rsac.org/ratingsv01.html" l gen true comment "RSACi North America Server" for "http://www.rsac.org" on "1996.04.16T08:15-0500" r (n 0 s 0 v 0 l 0))' docs = "http://foo.com/doc" skipDays = [ "Sunday", "Monday", ] skipHours = [ "0", "13", ] pubDate = Time.now lastBuildDate = Time.now categories = [ "Nespapers", "misc", ] generator = "RSS Maker" ttl = "60" rss = RSS::Maker.make("2.0") do |maker| maker.channel.title = title maker.channel.link = link maker.channel.description = description maker.channel.language = language maker.channel.copyright = copyright maker.channel.managingEditor = managingEditor maker.channel.webMaster = webMaster maker.channel.rating = rating maker.channel.docs = docs maker.channel.pubDate = pubDate maker.channel.lastBuildDate = lastBuildDate skipDays.each do |day| maker.channel.skipDays.new_day do |new_day| new_day.content = day end end skipHours.each do |hour| maker.channel.skipHours.new_hour do |new_hour| new_hour.content = hour end end categories.each do |category| maker.channel.categories.new_category do |new_category| new_category.content = category end end maker.channel.generator = generator maker.channel.ttl = ttl end channel = rss.channel assert_equal(title, channel.title) assert_equal(link, channel.link) assert_equal(description, channel.description) assert_equal(language, channel.language) assert_equal(copyright, channel.copyright) assert_equal(managingEditor, channel.managingEditor) assert_equal(webMaster, channel.webMaster) assert_equal(rating, channel.rating) assert_equal(docs, channel.docs) assert_equal(pubDate, channel.pubDate) assert_equal(pubDate, channel.date) assert_equal(lastBuildDate, channel.lastBuildDate) skipDays.each_with_index do |day, i| assert_equal(day, channel.skipDays.days[i].content) end skipHours.each_with_index do |hour, i| assert_equal(hour.to_i, channel.skipHours.hours[i].content) end channel.categories.each_with_index do |category, i| assert_equal(categories[i], category.content) end assert_equal(generator, channel.generator) assert_equal(ttl.to_i, channel.ttl) assert(channel.items.empty?) assert_nil(channel.image) assert_nil(channel.textInput) end def test_not_valid_channel title = "fugafuga" link = "http://hoge.com" description = "fugafugafugafuga" language = "ja" assert_not_set_error("maker.channel", %w(title)) do RSS::Maker.make("2.0") do |maker| # maker.channel.title = title maker.channel.link = link maker.channel.description = description maker.channel.language = language end end assert_not_set_error("maker.channel", %w(link)) do RSS::Maker.make("2.0") do |maker| maker.channel.title = title # maker.channel.link = link maker.channel.description = description maker.channel.language = language end end assert_not_set_error("maker.channel", %w(description)) do RSS::Maker.make("2.0") do |maker| maker.channel.title = title maker.channel.link = link # maker.channel.description = description maker.channel.language = language end end rss = RSS::Maker.make("2.0") do |maker| maker.channel.title = title maker.channel.link = link maker.channel.description = description # maker.channel.language = language end assert_not_nil(rss) end def test_cloud domain = "rpc.sys.com" port = "80" path = "/RPC2" registerProcedure = "myCloud.rssPleaseNotify" protocol = "xml-rpc" rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) maker.channel.cloud.domain = domain maker.channel.cloud.port = port maker.channel.cloud.path = path maker.channel.cloud.registerProcedure = registerProcedure maker.channel.cloud.protocol = protocol end cloud = rss.channel.cloud assert_equal(domain, cloud.domain) assert_equal(port.to_i, cloud.port) assert_equal(path, cloud.path) assert_equal(registerProcedure, cloud.registerProcedure) assert_equal(protocol, cloud.protocol) end def test_not_valid_cloud domain = "rpc.sys.com" port = "80" path = "/RPC2" registerProcedure = "myCloud.rssPleaseNotify" protocol = "xml-rpc" rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) # maker.channel.cloud.domain = domain maker.channel.cloud.port = port maker.channel.cloud.path = path maker.channel.cloud.registerProcedure = registerProcedure maker.channel.cloud.protocol = protocol end assert_nil(rss.channel.cloud) rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) maker.channel.cloud.domain = domain # maker.channel.cloud.port = port maker.channel.cloud.path = path maker.channel.cloud.registerProcedure = registerProcedure maker.channel.cloud.protocol = protocol end assert_nil(rss.channel.cloud) rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) maker.channel.cloud.domain = domain maker.channel.cloud.port = port # maker.channel.cloud.path = path maker.channel.cloud.registerProcedure = registerProcedure maker.channel.cloud.protocol = protocol end assert_nil(rss.channel.cloud) rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) maker.channel.cloud.domain = domain maker.channel.cloud.port = port maker.channel.cloud.path = path # maker.channel.cloud.registerProcedure = registerProcedure maker.channel.cloud.protocol = protocol end assert_nil(rss.channel.cloud) rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) maker.channel.cloud.domain = domain maker.channel.cloud.port = port maker.channel.cloud.path = path maker.channel.cloud.registerProcedure = registerProcedure # maker.channel.cloud.protocol = protocol end assert_nil(rss.channel.cloud) end def test_image title = "fugafuga" link = "http://hoge.com" url = "http://hoge.com/hoge.png" width = "144" height = "400" description = "an image" rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) maker.channel.link = link maker.image.title = title maker.image.url = url maker.image.width = width maker.image.height = height maker.image.description = description end image = rss.image assert_equal(title, image.title) assert_equal(link, image.link) assert_equal(url, image.url) assert_equal(width.to_i, image.width) assert_equal(height.to_i, image.height) assert_equal(description, image.description) assert_not_set_error("maker.channel", %w(title description)) do RSS::Maker.make("2.0") do |maker| # setup_dummy_channel(maker) maker.channel.link = link maker.image.title = title maker.image.url = url maker.image.width = width maker.image.height = height maker.image.description = description end end end def test_not_valid_image title = "fugafuga" link = "http://hoge.com" url = "http://hoge.com/hoge.png" width = "144" height = "400" description = "an image" rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) maker.channel.link = link # maker.image.title = title maker.image.url = url maker.image.width = width maker.image.height = height maker.image.description = description end assert_nil(rss.image) assert_not_set_error("maker.channel", %w(link)) do RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) # maker.channel.link = link maker.channel.link = nil maker.image.title = title maker.image.url = url maker.image.width = width maker.image.height = height maker.image.description = description end end rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) maker.channel.link = link maker.image.title = title # maker.image.url = url maker.image.width = width maker.image.height = height maker.image.description = description end assert_nil(rss.image) end def test_items(with_convenience_way=true) title = "TITLE" link = "http://hoge.com/" description = "text hoge fuga" author = "oprah@oxygen.net" comments = "http://www.myblog.org/cgi-local/mt/mt-comments.cgi?entry_id=290" pubDate = Time.now rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) end assert(rss.channel.items.empty?) item_size = 5 rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) item_size.times do |i| maker.items.new_item do |item| item.title = "#{title}#{i}" item.link = "#{link}#{i}" item.description = "#{description}#{i}" item.author = "#{author}#{i}" item.comments = "#{comments}#{i}" item.date = pubDate end end maker.items.do_sort = true end assert_equal(item_size, rss.items.size) rss.channel.items.each_with_index do |item, i| assert_equal("#{title}#{i}", item.title) assert_equal("#{link}#{i}", item.link) assert_equal("#{description}#{i}", item.description) assert_equal("#{author}#{i}", item.author) assert_equal("#{comments}#{i}", item.comments) assert_equal(pubDate, item.pubDate) assert_equal(pubDate, item.date) end rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) item_size.times do |i| maker.items.new_item do |item| item.title = "#{title}#{i}" item.link = "#{link}#{i}" item.description = "#{description}#{i}" item.author = "#{author}#{i}" item.comments = "#{comments}#{i}" item.date = pubDate end end maker.items.do_sort = Proc.new do |x, y| if with_convenience_way y.title[-1] <=> x.title[-1] else y.title {|t| t.content[-1]} <=> x.title {|t| t.content[-1]} end end end assert_equal(item_size, rss.items.size) rss.channel.items.reverse.each_with_index do |item, i| assert_equal("#{title}#{i}", item.title) assert_equal("#{link}#{i}", item.link) assert_equal("#{description}#{i}", item.description) assert_equal("#{author}#{i}", item.author) assert_equal("#{comments}#{i}", item.comments) assert_equal(pubDate, item.pubDate) assert_equal(pubDate, item.date) end end def test_items_with_new_api_since_018 test_items(false) end def test_pubDate_without_description title = "TITLE" link = "http://hoge.com/" description = "text hoge fuga" author = "oprah@oxygen.net" pubDate = Time.now rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) maker.items.new_item do |item| item.title = title item.link = link # item.description = description item.author = author item.pubDate = pubDate end end assert_equal(1, rss.items.size) rss.channel.items.each_with_index do |item, i| assert_equal(title, item.title) assert_equal(link, item.link) # assert_equal(description, item.description) assert_equal(author, item.author) assert_equal(pubDate, item.pubDate) assert_equal(pubDate, item.date) end end def test_guid isPermaLink = "true" content = "http://inessential.com/2002/09/01.php#a2" rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) guid = maker.items.last.guid guid.isPermaLink = isPermaLink guid.content = content end guid = rss.channel.items.last.guid assert_equal(isPermaLink == "true", guid.isPermaLink) assert_equal(content, guid.content) end def test_not_valid_guid content = "http://inessential.com/2002/09/01.php#a2" rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) guid = maker.items.last.guid # guid.content = content end assert_nil(rss.channel.items.last.guid) end def test_enclosure url = "http://www.scripting.com/mp3s/weatherReportSuite.mp3" length = "12216320" type = "audio/mpeg" rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) enclosure = maker.items.last.enclosure enclosure.url = url enclosure.length = length enclosure.type = type end enclosure = rss.channel.items.last.enclosure assert_equal(url, enclosure.url) assert_equal(length.to_i, enclosure.length) assert_equal(type, enclosure.type) end def test_not_valid_enclosure url = "http://www.scripting.com/mp3s/weatherReportSuite.mp3" length = "12216320" type = "audio/mpeg" rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) enclosure = maker.items.last.enclosure # enclosure.url = url enclosure.length = length enclosure.type = type end assert_nil(rss.channel.items.last.enclosure) rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) enclosure = maker.items.last.enclosure enclosure.url = url # enclosure.length = length enclosure.type = type end assert_nil(rss.channel.items.last.enclosure) rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) enclosure = maker.items.last.enclosure enclosure.url = url enclosure.length = length # enclosure.type = type end assert_nil(rss.channel.items.last.enclosure) end def test_source url = "http://static.userland.com/tomalak/links2.xml" content = "Tomalak's Realm" rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) source = maker.items.last.source source.url = url source.content = content end source = rss.channel.items.last.source assert_equal(url, source.url) assert_equal(content, source.content) end def test_not_valid_source url = "http://static.userland.com/tomalak/links2.xml" content = "Tomalak's Realm" rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) source = maker.items.last.source # source.url = url source.content = content end assert_nil(rss.channel.items.last.source) rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) source = maker.items.last.source source.url = url # source.content = content end assert_nil(rss.channel.items.last.source) end def test_category domain = "http://www.fool.com/cusips" content = "MSFT" rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) maker.items.last.categories.new_category do |category| category.domain = domain category.content = content end end category = rss.channel.items.last.categories.last assert_equal(domain, category.domain) assert_equal(content, category.content) end def test_not_valid_category content = "Grateful Dead" rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) maker.items.last.categories.new_category do |category| # category.content = content end end assert(rss.channel.items.last.categories.empty?) end def test_textInput title = "fugafuga" description = "text hoge fuga" name = "hoge" link = "http://hoge.com" rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) maker.textinput.title = title maker.textinput.description = description maker.textinput.name = name maker.textinput.link = link end textInput = rss.channel.textInput assert_equal(title, textInput.title) assert_equal(description, textInput.description) assert_equal(name, textInput.name) assert_equal(link, textInput.link) assert_not_set_error("maker.channel", %w(link description title)) do RSS::Maker.make("2.0") do |maker| # setup_dummy_channel(maker) maker.textinput.title = title maker.textinput.description = description maker.textinput.name = name maker.textinput.link = link end end end def test_not_valid_textInput title = "fugafuga" description = "text hoge fuga" name = "hoge" link = "http://hoge.com" rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) # maker.textinput.title = title maker.textinput.description = description maker.textinput.name = name maker.textinput.link = link end assert_nil(rss.channel.textInput) rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) maker.textinput.title = title # maker.textinput.description = description maker.textinput.name = name maker.textinput.link = link end assert_nil(rss.channel.textInput) rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) maker.textinput.title = title maker.textinput.description = description # maker.textinput.name = name maker.textinput.link = link end assert_nil(rss.channel.textInput) rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) maker.textinput.title = title maker.textinput.description = description maker.textinput.name = name # maker.textinput.link = link end assert_nil(rss.channel.textInput) end end end ================================================ FILE: test/rss/test_maker_atom_entry.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestMakerAtomEntry < TestCase def test_root_element entry = Maker.make("atom:entry") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end assert_equal(["atom", "1.0", "entry"], entry.feed_info) entry = Maker.make("atom:entry") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) maker.encoding = "EUC-JP" end assert_equal(["atom", "1.0", "entry"], entry.feed_info) assert_equal("EUC-JP", entry.encoding) entry = Maker.make("atom:entry") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) maker.standalone = "yes" end assert_equal(["atom", "1.0", "entry"], entry.feed_info) assert_equal("yes", entry.standalone) entry = Maker.make("atom:entry") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) maker.encoding = "EUC-JP" maker.standalone = "yes" end assert_equal(["atom", "1.0", "entry"], entry.feed_info) assert_equal("EUC-JP", entry.encoding) assert_equal("yes", entry.standalone) end def test_invalid_feed assert_not_set_error("maker.item", %w(id title author updated)) do Maker.make("atom:entry") do |maker| end end assert_not_set_error("maker.item", %w(id title updated)) do Maker.make("atom:entry") do |maker| maker.channel.author = "foo" end end assert_not_set_error("maker.item", %w(title updated)) do Maker.make("atom:entry") do |maker| maker.channel.author = "foo" maker.channel.id = "http://example.com" end end assert_not_set_error("maker.item", %w(updated)) do Maker.make("atom:entry") do |maker| maker.channel.author = "foo" maker.channel.id = "http://example.com" maker.channel.title = "Atom Feed" end end assert_not_set_error("maker.item", %w(author)) do Maker.make("atom:entry") do |maker| maker.channel.id = "http://example.com" maker.channel.title = "Atom Feed" maker.channel.updated = Time.now end end entry = Maker.make("atom:entry") do |maker| maker.channel.author = "Foo" maker.channel.id = "http://example.com" maker.channel.title = "Atom Feed" maker.channel.updated = Time.now end assert_not_nil(entry) end def test_author assert_maker_atom_persons("entry", ["channel", "authors"], ["authors"], "maker.channel.author") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end assert_maker_atom_persons("entry", ["items", "first", "authors"], ["authors"], "maker.item.author", "maker.item", ["author"]) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) maker.channel.authors.clear maker.items.first.authors.clear end assert_maker_atom_persons("entry", ["items", "first", "source", "authors"], ["source", "authors"], "maker.item.source.author") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_category assert_maker_atom_categories("entry", ["channel", "categories"], ["categories"], "maker.channel.category") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end assert_maker_atom_categories("entry", ["items", "first", "categories"], ["categories"], "maker.item.category") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end assert_maker_atom_categories("entry", ["items", "first", "source", "categories"], ["source", "categories"], "maker.item.source.category") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_content assert_maker_atom_content("entry", ["items", "first", "content"], ["content"], "maker.item.content") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_contributor assert_maker_atom_persons("entry", ["channel", "contributors"], ["contributors"], "maker.channel.contributor") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end assert_maker_atom_persons("entry", ["items", "first", "contributors"], ["contributors"], "maker.item.contributor") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end assert_maker_atom_persons("entry", ["items", "first", "source", "contributors"], ["source", "contributors"], "maker.item.source.contributor") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_link assert_maker_atom_links("entry", ["channel", "links"], ["links"], "maker.channel.link") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) maker.channel.links.clear maker.items.first.links.clear end assert_maker_atom_links("entry", ["items", "first", "links"], ["links"], "maker.item.link") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) maker.channel.links.clear maker.items.first.links.clear end assert_maker_atom_links("entry", ["items", "first", "source", "links"], ["source", "links"], "maker.item.source.link", true) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_published assert_maker_atom_date_construct("entry", ["items", "first", "published"], ["published"] ) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_rights assert_maker_atom_text_construct("entry", ["channel", "copyright"], ["rights"]) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end assert_maker_atom_text_construct("entry", ["items", "first", "rights"], ["rights"], nil, nil, "maker.item.rights" ) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end assert_maker_atom_text_construct("entry", ["items", "first", "source", "rights"], ["source", "rights"], nil, nil, "maker.item.source.rights" ) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_source_generator assert_maker_atom_generator("entry", ["items", "first", "source", "generator"], ["source", "generator"], "maker.item.source.generator") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_source_icon assert_maker_atom_icon("entry", ["items", "first", "source", "icon"], ["source", "icon"], nil, "maker.item.source.icon") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_source_id assert_maker_atom_id("entry", ["items", "first", "source"], ["source"], "maker.item.source") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_source_logo assert_maker_atom_logo("entry", ["items", "first", "source", "logo"], ["source", "logo"], nil, "maker.item.source.logo") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_source_subtitle assert_maker_atom_text_construct("entry", ["items", "first", "source", "subtitle"], ["source", "subtitle"], nil, nil, "maker.item.source.subtitle") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_summary assert_maker_atom_text_construct("entry", ["items", "first", "description"], ["summary"], nil, nil, "maker.item.description" ) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_title assert_maker_atom_text_construct("entry", ["channel", "title"], ["title"], "maker.item", ["title"], "maker.channel.title") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) maker.channel.title = nil maker.items.first.title = nil end assert_maker_atom_text_construct("entry", ["items", "first", "title"], ["title"], "maker.item", ["title"], "maker.item.title") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) maker.channel.title = nil maker.items.first.title = nil end assert_maker_atom_text_construct("entry", ["items", "first", "source", "title"], ["source", "title"], nil, nil, "maker.item.source.title" ) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_updated assert_maker_atom_date_construct("entry", ["channel", "updated"], ["updated"], "maker.item", ["updated"]) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) maker.channel.updated = nil maker.items.first.updated = nil end assert_maker_atom_date_construct("entry", ["items", "first", "updated"], ["updated"], "maker.item", ["updated"]) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) maker.channel.updated = nil maker.items.first.updated = nil end assert_maker_atom_date_construct("entry", ["items", "first", "source", "updated"], ["source", "updated"]) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end end end ================================================ FILE: test/rss/test_maker_atom_feed.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestMakerAtomFeed < TestCase def test_root_element feed = Maker.make("atom") do |maker| setup_dummy_channel_atom(maker) end assert_equal(["atom", "1.0", "feed"], feed.feed_info) feed = Maker.make("atom") do |maker| setup_dummy_channel_atom(maker) maker.encoding = "EUC-JP" end assert_equal(["atom", "1.0", "feed"], feed.feed_info) assert_equal("EUC-JP", feed.encoding) feed = Maker.make("atom") do |maker| setup_dummy_channel_atom(maker) maker.standalone = "yes" end assert_equal(["atom", "1.0", "feed"], feed.feed_info) assert_equal("yes", feed.standalone) feed = Maker.make("atom") do |maker| setup_dummy_channel_atom(maker) maker.encoding = "EUC-JP" maker.standalone = "yes" end assert_equal(["atom", "1.0", "feed"], feed.feed_info) assert_equal("EUC-JP", feed.encoding) assert_equal("yes", feed.standalone) end def test_invalid_feed assert_not_set_error("maker.channel", %w(id title author updated)) do Maker.make("atom") do |maker| end end assert_not_set_error("maker.channel", %w(id title updated)) do Maker.make("atom") do |maker| maker.channel.author = "foo" end end assert_not_set_error("maker.channel", %w(title updated)) do Maker.make("atom") do |maker| maker.channel.author = "foo" maker.channel.id = "http://example.com" end end assert_not_set_error("maker.channel", %w(updated)) do Maker.make("atom") do |maker| maker.channel.author = "foo" maker.channel.id = "http://example.com" maker.channel.title = "Atom Feed" end end assert_not_set_error("maker.channel", %w(author)) do Maker.make("atom") do |maker| maker.channel.id = "http://example.com" maker.channel.title = "Atom Feed" maker.channel.updated = Time.now end end feed = Maker.make("atom") do |maker| maker.channel.author = "Foo" maker.channel.id = "http://example.com" maker.channel.title = "Atom Feed" maker.channel.updated = Time.now end assert_not_nil(feed) end def test_author assert_maker_atom_persons("feed", ["channel", "authors"], ["authors"], "maker.channel.author") do |maker| setup_dummy_channel_atom(maker) end assert_not_set_error("maker.channel", %w(author)) do RSS::Maker.make("atom") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) maker.channel.authors.clear end end assert_maker_atom_persons("feed", ["items", "first", "authors"], ["entries", "first", "authors"], "maker.item.author") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end assert_maker_atom_persons("feed", ["items", "first", "source", "authors"], ["entries", "first", "source", "authors"], "maker.item.source.author") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_category assert_maker_atom_categories("feed", ["channel", "categories"], ["categories"], "maker.channel.category") do |maker| setup_dummy_channel_atom(maker) end assert_maker_atom_categories("feed", ["items", "first", "categories"], ["entries", "first", "categories"], "maker.item.category") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end assert_maker_atom_categories("feed", ["items", "first", "source", "categories"], ["entries", "first", "source", "categories"], "maker.item.source.category") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_contributor assert_maker_atom_persons("feed", ["channel", "contributors"], ["contributors"], "maker.channel.contributor") do |maker| setup_dummy_channel_atom(maker) end assert_maker_atom_persons("feed", ["items", "first", "contributors"], ["entries", "first", "contributors"], "maker.item.contributor") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end assert_maker_atom_persons("feed", ["items", "first", "source", "contributors"], ["entries", "first", "source", "contributors"], "maker.item.source.contributor") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_generator assert_maker_atom_generator("feed", ["channel", "generator"], ["generator"]) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end assert_maker_atom_generator("feed", ["items", "first", "source", "generator"], ["entries", "first", "source", "generator"], "maker.item.source.generator") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_icon assert_maker_atom_icon("feed", ["channel"], ["icon"], "icon") do |maker| setup_dummy_channel_atom(maker) end assert_maker_atom_icon("feed", ["items", "first", "source", "icon"], ["entries", "first", "source", "icon"], nil, "maker.item.source.icon") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_link assert_maker_atom_links("feed", ["channel", "links"], ["links"], "maker.channel.link") do |maker| setup_dummy_channel_atom(maker) end assert_maker_atom_links("feed", ["items", "first", "links"], ["entries", "first", "links"], "maker.item.link") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end assert_maker_atom_links("feed", ["items", "first", "source", "links"], ["entries", "first", "source", "links"], "maker.item.source.link", true) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_logo assert_maker_atom_logo("feed", ["channel"], ["logo"], "logo") do |maker| setup_dummy_channel_atom(maker) end assert_maker_atom_logo("feed", ["image"], ["logo"], "url") do |maker| setup_dummy_channel_atom(maker) end assert_maker_atom_logo("feed", ["items", "first", "source", "logo"], ["entries", "first", "source", "logo"], nil, "maker.item.source.logo") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_rights assert_maker_atom_text_construct("feed", ["channel", "copyright"], ["rights"]) do |maker| setup_dummy_channel_atom(maker) end assert_maker_atom_text_construct("feed", ["items", "first", "rights"], ["entries", "first", "rights"], nil, nil, "maker.item.rights" ) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end assert_maker_atom_text_construct("feed", ["items", "first", "source", "rights"], ["entries", "first", "source", "rights"], nil, nil, "maker.item.source.rights" ) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_subtitle assert_maker_atom_text_construct("feed", ["channel", "subtitle"], ["subtitle"], nil, nil, "maker.channel.description") do |maker| setup_dummy_channel_atom(maker) maker.channel.description = nil end assert_maker_atom_text_construct("feed", ["channel", "subtitle"], ["subtitle"], nil, nil, "maker.channel.description") do |maker| setup_dummy_channel_atom(maker) maker.channel.description {|d| d.content = nil} end assert_maker_atom_text_construct("feed", ["items", "first", "source", "subtitle"], ["entries", "first", "source", "subtitle"], nil, nil, "maker.item.source.subtitle") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_title assert_maker_atom_text_construct("feed", ["channel", "title"], ["title"], "maker.channel", ["title"]) do |maker| setup_dummy_channel_atom(maker) maker.channel.title = nil end assert_maker_atom_text_construct("feed", ["items", "first", "title"], ["entries", "first", "title"], "maker.item", ["title"], "maker.item.title") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) maker.items.first.title = nil end assert_maker_atom_text_construct("feed", ["items", "first", "source", "title"], ["entries", "first", "source", "title"], nil, nil, "maker.item.source.title" ) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_updated assert_maker_atom_date_construct("feed", ["channel", "updated"], ["updated"], "maker.channel", ["updated"]) do |maker| setup_dummy_channel_atom(maker) maker.channel.updated = nil end assert_maker_atom_date_construct("feed", ["items", "first", "updated"], ["entries", "first", "updated"], "maker.item", ["updated"]) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) maker.items.first.updated = nil end assert_maker_atom_date_construct("feed", ["items", "first", "source", "updated"], ["entries", "first", "source", "updated"] ) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_published assert_maker_atom_date_construct("feed", ["items", "first", "published"], ["entries", "first", "published"] ) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_summary assert_maker_atom_text_construct("feed", ["items", "first", "description"], ["entries", "first", "summary"], nil, nil, "maker.item.description" ) do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_content assert_maker_atom_content("feed", ["items", "first", "content"], ["entries", "first", "content"], "maker.item.content") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end def test_id assert_maker_atom_id("feed", ["items", "first", "source"], ["entries", "first", "source"], "maker.item.source") do |maker| setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end end end end ================================================ FILE: test/rss/test_maker_content.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestMakerContent < TestCase def setup @uri = "http://purl.org/rss/1.0/modules/content/" @elements = { :encoded => "ATTENTION", } end def test_rss10 rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) item = maker.items.last @elements.each do |name, value| item.__send__("#{accessor_name(name)}=", value) end end assert_content(@elements, rss.items.last) end def test_rss20 rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) item = maker.items.last @elements.each do |name, value| item.__send__("#{accessor_name(name)}=", value) end end assert_content(@elements, rss.items.last) end private def accessor_name(name) "content_#{name}" end end end ================================================ FILE: test/rss/test_maker_dc.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestMakerDublinCore < TestCase def setup @uri = "http://purl.org/dc/elements/1.1/" t = Time.iso8601("2000-01-01T12:00:05+00:00") class << t alias_method(:to_s, :iso8601) end @elements = { :title => "hoge", :description => " XML is placing increasingly heavy loads on the existing technical infrastructure of the Internet.", :creator => "Rael Dornfest (mailto:rael@oreilly.com)", :subject => "XML", :publisher => "The O'Reilly Network", :contributor => "hogehoge", :type => "fugafuga", :format => "hohoho", :identifier => "fufufu", :source => "barbar", :language => "ja", :relation => "cococo", :rights => "Copyright (c) 2000 O'Reilly & Associates, Inc.", :date => t, } end def test_rss10 rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) set_elements(maker.channel) setup_dummy_image(maker) set_elements(maker.image) setup_dummy_item(maker) item = maker.items.last @elements.each do |name, value| item.__send__("#{accessor_name(name)}=", value) end setup_dummy_textinput(maker) set_elements(maker.textinput) end assert_dublin_core(@elements, rss.channel) assert_dublin_core(@elements, rss.image) assert_dublin_core(@elements, rss.items.last) assert_dublin_core(@elements, rss.textinput) end def test_rss10_multiple assert_multiple_dublin_core_rss10("_list") assert_multiple_dublin_core_rss10("es") end def assert_multiple_dublin_core_rss10(multiple_rights_suffix) elems = [] @elements.each do |name, value| plural = name.to_s + (name == :rights ? multiple_rights_suffix : "s") values = [value] if name == :date values << value + 60 else values << value * 2 end elems << [name, values, plural] end rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) set_multiple_elements(maker.channel, elems) setup_dummy_image(maker) set_multiple_elements(maker.image, elems) setup_dummy_item(maker) item = maker.items.last elems.each do |name, values, plural| dc_elems = item.__send__("dc_#{plural}") values.each do |value| dc_elems.__send__("new_#{name}") do |elem| elem.value = value end end end setup_dummy_textinput(maker) set_multiple_elements(maker.textinput, elems) end assert_multiple_dublin_core(elems, rss.channel) assert_multiple_dublin_core(elems, rss.image) assert_multiple_dublin_core(elems, rss.items.last) assert_multiple_dublin_core(elems, rss.textinput) end def test_date t1 = Time.iso8601("2000-01-01T12:00:05+00:00") t2 = Time.iso8601("2005-01-01T12:00:05+00:00") rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) maker.channel.date = t1 maker.channel.dc_dates.new_date do |date| date.value = t2 end setup_dummy_item(maker) item = maker.items.last item.date = t2 item.dc_dates.new_date do |date| date.value = t1 end end assert_equal([t1, t2], rss.channel.dc_dates.collect{|x| x.value}) assert_equal([t2, t1], rss.items.last.dc_dates.collect{|x| x.value}) end private def accessor_name(name) "dc_#{name}" end def set_elements(target, elems=@elements) elems.each do |name, value| target.__send__("#{accessor_name(name)}=", value) end end def set_multiple_elements(target, elems) elems.each do |name, values, plural| plural ||= "#{name}s" dc_elems = target.__send__("dc_#{plural}") values.each do |value| dc_elems.__send__("new_#{name}") do |new_dc_elem| new_dc_elem.value = value end end end end end end ================================================ FILE: test/rss/test_maker_image.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestMakerImage < TestCase def setup @uri = "http://web.resource.org/rss/1.0/modules/image/" @favicon_infos = { "about" => "http://www.kuro5hin.org/favicon.ico", "image_size" => "small", "dc_title" => "example", } @item_infos = { "about" => "http://www.example.org/item.png", "resource" => "http://www.example.org/item", "dc_title" => "Example Image", "image_width" => "100", "image_height" => "65", } end def test_rss10 rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) @favicon_infos.each do |name, value| maker.channel.image_favicon.__send__("#{name}=", value) end setup_dummy_image(maker) setup_dummy_item(maker) item = maker.items.last @item_infos.each do |name, value| item.image_item.__send__("#{name}=", value) end setup_dummy_textinput(maker) end setup_rss = RSS::Maker.make("1.0") do |maker| rss.setup_maker(maker) end [rss, setup_rss].each_with_index do |target, i| favicon = target.channel.image_favicon assert_equal(@favicon_infos["about"], favicon.about) assert_equal(@favicon_infos["image_size"], favicon.image_size) assert_equal(@favicon_infos["dc_title"], favicon.dc_title) item = target.items.last.image_item assert_equal(@item_infos["about"], item.about) assert_equal(@item_infos["resource"], item.resource) assert_equal(@item_infos["image_width"].to_i, item.image_width) assert_equal(@item_infos["image_height"].to_i, item.image_height) assert_equal(@item_infos["dc_title"], item.dc_title) end end end end ================================================ FILE: test/rss/test_maker_itunes.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestMakerITunes < TestCase def test_author assert_maker_itunes_author(%w(channel)) assert_maker_itunes_author(%w(items last)) end def test_block assert_maker_itunes_block(%w(channel)) assert_maker_itunes_block(%w(items last)) end def test_category assert_maker_itunes_category(%w(channel)) end def test_image assert_maker_itunes_image(%w(channel)) end def test_duration assert_maker_itunes_duration(%w(items last)) end def test_explicit assert_maker_itunes_explicit(%w(channel)) assert_maker_itunes_explicit(%w(items last)) end def test_keywords assert_maker_itunes_keywords(%w(channel)) assert_maker_itunes_keywords(%w(items last)) end def test_new_feed_url assert_maker_itunes_new_feed_url(%w(channel)) end def test_owner assert_maker_itunes_owner(%w(channel)) end def test_subtitle assert_maker_itunes_subtitle(%w(channel)) assert_maker_itunes_subtitle(%w(items last)) end def test_summary assert_maker_itunes_summary(%w(channel)) assert_maker_itunes_summary(%w(items last)) end private def assert_maker_itunes_author(maker_readers, feed_readers=nil) _wrap_assertion do feed_readers ||= maker_readers author = "John Doe" rss20 = ::RSS::Maker.make("rss2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) target = chain_reader(maker, maker_readers) target.itunes_author = author end target = chain_reader(rss20, feed_readers) assert_equal(author, target.itunes_author) end end def _assert_maker_itunes_block(value, boolean_value, maker_readers, feed_readers) rss20 = ::RSS::Maker.make("rss2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) target = chain_reader(maker, maker_readers) target.itunes_block = value assert_equal(value, target.itunes_block) assert_equal(boolean_value, target.itunes_block?) end target = chain_reader(rss20, feed_readers) if [true, false].include?(value) feed_expected_value = value = value ? "yes" : "no" else feed_expected_value = value end assert_equal(value, target.itunes_block) assert_equal(boolean_value, target.itunes_block?) end def assert_maker_itunes_block(maker_readers, feed_readers=nil) _wrap_assertion do feed_readers ||= maker_readers _assert_maker_itunes_block("yes", true, maker_readers, feed_readers) _assert_maker_itunes_block("Yes", true, maker_readers, feed_readers) _assert_maker_itunes_block("no", false, maker_readers, feed_readers) _assert_maker_itunes_block("", false, maker_readers, feed_readers) _assert_maker_itunes_block(true, true, maker_readers, feed_readers) _assert_maker_itunes_block(false, false, maker_readers, feed_readers) _assert_maker_itunes_block(nil, false, maker_readers, feed_readers) end end def _assert_maker_itunes_category(categories, maker_readers, feed_readers) rss20 = ::RSS::Maker.make("rss2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) target = chain_reader(maker, maker_readers) categories.each do |category| sub_target = target.itunes_categories if category.is_a?(Array) category.each do |sub_category| sub_target = sub_target.new_category sub_target.text = sub_category end else sub_target.new_category.text = category end end end target = chain_reader(rss20, feed_readers) actual_categories = target.itunes_categories.collect do |category| cat = category.text if category.itunes_categories.empty? cat else [cat, *category.itunes_categories.collect {|c| c.text}] end end assert_equal(categories, actual_categories) end def assert_maker_itunes_category(maker_readers, feed_readers=nil) _wrap_assertion do feed_readers ||= maker_readers _assert_maker_itunes_category(["Audio Blogs"], maker_readers, feed_readers) _assert_maker_itunes_category([["Arts & Entertainment", "Games"]], maker_readers, feed_readers) _assert_maker_itunes_category([["Arts & Entertainment", "Games"], ["Technology", "Computers"], "Audio Blogs"], maker_readers, feed_readers) end end def assert_maker_itunes_image(maker_readers, feed_readers=nil) _wrap_assertion do feed_readers ||= maker_readers url = "http://example.com/podcasts/everything/AllAboutEverything.jpg" rss20 = ::RSS::Maker.make("rss2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) target = chain_reader(maker, maker_readers) target.itunes_image = url end target = chain_reader(rss20, feed_readers) assert_not_nil(target.itunes_image) assert_equal(url, target.itunes_image.href) end end def _assert_maker_itunes_duration(hour, minute, second, value, maker_readers, feed_readers) _assert_maker_itunes_duration_by_value(hour, minute, second, value, maker_readers, feed_readers) _assert_maker_itunes_duration_by_hour_minute_second(hour, minute, second, value, maker_readers, feed_readers) end def _assert_maker_itunes_duration_by(hour, minute, second, value, maker_readers, feed_readers) expected_value = nil rss20 = ::RSS::Maker.make("rss2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) target = chain_reader(maker, maker_readers) expected_value = yield(target) assert_equal(expected_value, target.itunes_duration) target.itunes_duration do |duration| assert_equal([hour, minute, second, expected_value], [duration.hour, duration.minute, duration.second, duration.content]) end end target = chain_reader(rss20, feed_readers) duration = target.itunes_duration assert_not_nil(duration) assert_equal([hour, minute, second, expected_value], [duration.hour, duration.minute, duration.second, duration.content]) end def _assert_maker_itunes_duration_by_value(hour, minute, second, value, maker_readers, feed_readers) _assert_maker_itunes_duration_by(hour, minute, second, value, maker_readers, feed_readers) do |target| target.itunes_duration = value value end end def _assert_maker_itunes_duration_by_hour_minute_second(hour, minute, second, value, maker_readers, feed_readers) _assert_maker_itunes_duration_by(hour, minute, second, value, maker_readers, feed_readers) do |target| target.itunes_duration do |duration| duration.hour = hour duration.minute = minute duration.second = second end value.split(":").collect {|v| "%02d" % v.to_i}.join(":") end end def _assert_maker_itunes_duration_invalid_value(value, maker_readers) assert_raise(ArgumentError) do ::RSS::Maker.make("rss2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) target = chain_reader(maker, maker_readers) target.itunes_duration = value end end end def assert_maker_itunes_duration(maker_readers, feed_readers=nil) _wrap_assertion do feed_readers ||= maker_readers _assert_maker_itunes_duration(7, 14, 5, "07:14:05", maker_readers, feed_readers) _assert_maker_itunes_duration(7, 14, 5, "7:14:05", maker_readers, feed_readers) _assert_maker_itunes_duration(0, 4, 55, "04:55", maker_readers, feed_readers) _assert_maker_itunes_duration(0, 4, 5, "4:05", maker_readers, feed_readers) _assert_maker_itunes_duration_invalid_value("5", maker_readers) _assert_maker_itunes_duration_invalid_value("09:07:14:05", maker_readers) _assert_maker_itunes_duration_invalid_value("10:5", maker_readers) _assert_maker_itunes_duration_invalid_value("10:03:5", maker_readers) _assert_maker_itunes_duration_invalid_value("10:3:05", maker_readers) _assert_maker_itunes_duration_invalid_value("xx:xx:xx", maker_readers) end end def _assert_maker_itunes_explicit(explicit, value, maker_readers, feed_readers) rss20 = ::RSS::Maker.make("rss2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) target = chain_reader(maker, maker_readers) target.itunes_explicit = value assert_equal(explicit, target.itunes_explicit?) end target = chain_reader(rss20, feed_readers) assert_equal(value, target.itunes_explicit) assert_equal(explicit, target.itunes_explicit?) end def assert_maker_itunes_explicit(maker_readers, feed_readers=nil) _wrap_assertion do feed_readers ||= maker_readers _assert_maker_itunes_explicit(true, "yes", maker_readers, feed_readers) _assert_maker_itunes_explicit(false, "clean", maker_readers, feed_readers) _assert_maker_itunes_explicit(nil, "no", maker_readers, feed_readers) end end def _assert_maker_itunes_keywords(keywords, value, maker_readers, feed_readers) _assert_maker_itunes_keywords_by_value(keywords, value, maker_readers, feed_readers) _assert_maker_itunes_keywords_by_keywords(keywords, maker_readers, feed_readers) end def _assert_maker_itunes_keywords_by(keywords, maker_readers, feed_readers) rss20 = ::RSS::Maker.make("rss2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) target = chain_reader(maker, maker_readers) yield(target) end assert_nothing_raised do rss20 = ::RSS::Parser.parse(rss20.to_s) end target = chain_reader(rss20, feed_readers) assert_equal(keywords, target.itunes_keywords) end def _assert_maker_itunes_keywords_by_value(keywords, value, maker_readers, feed_readers) _assert_maker_itunes_keywords_by(keywords, maker_readers, feed_readers) do |target| target.itunes_keywords = value end end def _assert_maker_itunes_keywords_by_keywords(keywords, maker_readers, feed_readers) _assert_maker_itunes_keywords_by(keywords, maker_readers, feed_readers) do |target| target.itunes_keywords = keywords end end def assert_maker_itunes_keywords(maker_readers, feed_readers=nil) _wrap_assertion do feed_readers ||= maker_readers _assert_maker_itunes_keywords(["salt"], "salt", maker_readers, feed_readers) _assert_maker_itunes_keywords(["salt"], " salt ", maker_readers, feed_readers) _assert_maker_itunes_keywords(["salt", "pepper", "shaker", "exciting"], "salt, pepper, shaker, exciting", maker_readers, feed_readers) _assert_maker_itunes_keywords(["metric", "socket", "wrenches", "toolsalt"], "metric, socket, wrenches, toolsalt", maker_readers, feed_readers) _assert_maker_itunes_keywords(["olitics", "red", "blue", "state"], "olitics, red, blue, state", maker_readers, feed_readers) end end def assert_maker_itunes_new_feed_url(maker_readers, feed_readers=nil) feed_readers ||= maker_readers url = "http://newlocation.com/example.rss" rss20 = ::RSS::Maker.make("rss2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) target = chain_reader(maker, maker_readers) target.itunes_new_feed_url = url end target = chain_reader(rss20, feed_readers) assert_equal(url, target.itunes_new_feed_url) end def _assert_maker_itunes_owner(name, email, maker_readers, feed_readers) rss20 = ::RSS::Maker.make("rss2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) target = chain_reader(maker, maker_readers) owner = target.itunes_owner owner.itunes_name = name owner.itunes_email = email end owner = chain_reader(rss20, feed_readers).itunes_owner if name.nil? and email.nil? assert_nil(owner) else assert_not_nil(owner) assert_equal(name, owner.itunes_name) assert_equal(email, owner.itunes_email) end end def assert_maker_itunes_owner(maker_readers, feed_readers=nil) _wrap_assertion do feed_readers ||= maker_readers _assert_maker_itunes_owner("John Doe", "john.doe@example.com", maker_readers, feed_readers) not_set_name = (["maker"] + maker_readers + ["itunes_owner"]).join(".") assert_not_set_error(not_set_name, ["itunes_name"]) do _assert_maker_itunes_owner(nil, "john.doe@example.com", maker_readers, feed_readers) end assert_not_set_error(not_set_name, ["itunes_email"]) do _assert_maker_itunes_owner("John Doe", nil, maker_readers, feed_readers) end _assert_maker_itunes_owner(nil, nil, maker_readers, feed_readers) end end def _assert_maker_itunes_subtitle(subtitle, maker_readers, feed_readers) rss20 = ::RSS::Maker.make("rss2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) target = chain_reader(maker, maker_readers) target.itunes_subtitle = subtitle end target = chain_reader(rss20, feed_readers) assert_equal(subtitle, target.itunes_subtitle) end def assert_maker_itunes_subtitle(maker_readers, feed_readers=nil) _wrap_assertion do feed_readers ||= maker_readers _assert_maker_itunes_subtitle("A show about everything", maker_readers, feed_readers) _assert_maker_itunes_subtitle("A short primer on table spices", maker_readers, feed_readers) _assert_maker_itunes_subtitle("Comparing socket wrenches is fun!", maker_readers, feed_readers) _assert_maker_itunes_subtitle("Red + Blue != Purple", maker_readers, feed_readers) end end def _assert_maker_itunes_summary(summary, maker_readers, feed_readers) rss20 = ::RSS::Maker.make("rss2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) target = chain_reader(maker, maker_readers) target.itunes_summary = summary end target = chain_reader(rss20, feed_readers) assert_equal(summary, target.itunes_summary) end def assert_maker_itunes_summary(maker_readers, feed_readers=nil) _wrap_assertion do feed_readers ||= maker_readers _assert_maker_itunes_summary("All About Everything is a show about " + "everything. Each week we dive into any " + "subject known to man and talk about it " + "as much as we can. Look for our Podcast " + "in the iTunes Music Store", maker_readers, feed_readers) _assert_maker_itunes_summary("This week we talk about salt and pepper " + "shakers, comparing and contrasting pour " + "rates, construction materials, and " + "overall aesthetics. Come and join the " + "party!", maker_readers, feed_readers) _assert_maker_itunes_summary("This week we talk about metric vs. old " + "english socket wrenches. Which one is " + "better? Do you really need both? Get " + "all of your answers here.", maker_readers, feed_readers) _assert_maker_itunes_summary("This week we talk about surviving in a " + "Red state if you’re a Blue person. Or " + "vice versa.", maker_readers, feed_readers) end end end end ================================================ FILE: test/rss/test_maker_slash.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestMakerSlash < TestCase def setup @elements = { "section" => "articles", "department" => "not-an-ocean-unless-there-are-lobsters", "comments" => 177, "hit_parades" => [177, 155, 105, 33, 6, 3, 0], } end def test_rss10 rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) item = maker.items.last @elements.each do |name, value| item.send("slash_#{name}=", value) end end item = rss.items.last assert_not_nil(item) assert_slash_elements(item) end private def assert_slash_elements(target) super(@elements, target) end end end ================================================ FILE: test/rss/test_maker_sy.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestMakerSyndication < TestCase def setup @uri = "http://purl.org/rss/1.0/modules/syndication/" t = Time.iso8601("2000-01-01T12:00:05+00:00") class << t alias_method(:to_s, :iso8601) end @elements = { :updatePeriod => "hourly", :updateFrequency => "2", :updateBase => t, } end def test_rss10 rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) set_elements(maker.channel) setup_dummy_item(maker) end assert_syndication(@elements, rss.channel) end private def accessor_name(name) "sy_#{name}" end def set_elements(target) @elements.each do |name, value| target.__send__("#{accessor_name(name)}=", value) end end end end ================================================ FILE: test/rss/test_maker_taxo.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestMakerTaxonomy < TestCase def setup @uri = "http://purl.org/rss/1.0/modules/taxonomy/" @resources = [ "http://meerkat.oreillynet.com/?c=cat23", "http://meerkat.oreillynet.com/?c=47", "http://dmoz.org/Computers/Data_Formats/Markup_Languages/XML/", ] @topics = [ { :link => "http://meerkat.oreillynet.com/?c=cat23", :title => "Data: XML", :description => "A Meerkat channel", }, { :link => "http://dmoz.org/Computers/Data_Formats/Markup_Languages/XML/", :title => "XML", :subject => "XML", :description => "DMOZ category", :topics => [ "http://meerkat.oreillynet.com/?c=cat23", "http://dmoz.org/Computers/Data_Formats/Markup_Languages/SGML/", "http://dmoz.org/Computers/Programming/Internet/", ] }, ] end def test_rss10 rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) set_topics(maker.channel) setup_dummy_item(maker) set_topics(maker.items.last) setup_taxo_topic(maker, @topics) end assert_equal(@resources, rss.channel.taxo_topics.resources) assert_equal(@resources, rss.items.last.taxo_topics.resources) assert_taxo_topic(@topics, rss) end def _test_date t1 = Time.iso8601("2000-01-01T12:00:05+00:00") t2 = Time.iso8601("2005-01-01T12:00:05+00:00") rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) maker.channel.date = t1 maker.channel.dc_dates.new_date do |date| date.value = t2 end setup_dummy_item(maker) item = maker.items.last item.date = t2 item.dc_dates.new_date do |date| date.value = t1 end end assert_equal([t1, t2], rss.channel.dc_dates.collect{|x| x.value}) assert_equal([t2, t1], rss.items.last.dc_dates.collect{|x| x.value}) end private def set_topics(target, resources=@resources) resources.each do |value| target.taxo_topics << value end end end end ================================================ FILE: test/rss/test_maker_trackback.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestMakerTrackBack < TestCase def setup @uri = "http://madskills.com/public/xml/rss/module/trackback/" @elements = { :ping => "http://bar.com/tb.cgi?tb_id=rssplustrackback", :abouts => [ "http://foo.com/trackback/tb.cgi?tb_id=20020923", "http://bar.com/trackback/tb.cgi?tb_id=20041114", ], } end def test_rss10 rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) item = maker.items.last item.trackback_ping = @elements[:ping] @elements[:abouts].each do |about| item.trackback_abouts.new_about do |new_about| new_about.value = about end end end assert_trackback(@elements, rss.items.last) end private def accessor_name(name) "trackback_#{name}" end end end ================================================ FILE: test/rss/test_maker_xml-stylesheet.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestMakerXMLStyleSheet < TestCase def test_xml_stylesheet href = 'a.xsl' type = 'text/xsl' title = 'sample' media = 'printer' charset = 'UTF-8' alternate = 'yes' rss = RSS::Maker.make("1.0") do |maker| maker.xml_stylesheets.new_xml_stylesheet do |xss| xss.href = href xss.type = type xss.title = title xss.media = media xss.charset = charset xss.alternate = alternate end setup_dummy_channel(maker) setup_dummy_item(maker) end xss = rss.xml_stylesheets.first assert_equal(href, xss.href) assert_equal(type, xss.type) assert_equal(title, xss.title) assert_equal(media, xss.media) assert_equal(charset, xss.charset) assert_equal(alternate, xss.alternate) href = 'http://example.com/index.xsl' type = 'text/xsl' rss = RSS::Maker.make("1.0") do |maker| maker.xml_stylesheets.new_xml_stylesheet do |_xss| _xss.href = href end setup_dummy_channel(maker) setup_dummy_item(maker) end xss = rss.xml_stylesheets.first assert_equal(href, xss.href) assert_equal(type, xss.type) end def test_not_valid_xml_stylesheet href = 'xss.XXX' type = "text/xsl" rss = RSS::Maker.make("1.0") do |maker| maker.xml_stylesheets.new_xml_stylesheet do |xss| # xss.href = href xss.type = type end setup_dummy_channel(maker) setup_dummy_item(maker) end assert(rss.xml_stylesheets.empty?) rss = RSS::Maker.make("1.0") do |maker| maker.xml_stylesheets.new_xml_stylesheet do |xss| xss.href = href # xss.type = type end setup_dummy_channel(maker) setup_dummy_item(maker) end assert(rss.xml_stylesheets.empty?) end end end ================================================ FILE: test/rss/test_parser.rb ================================================ require "fileutils" require "rss-testcase" require "rss/1.0" require "rss/dublincore" module RSS class TestParser < TestCase def setup @_default_parser = Parser.default_parser @rss10 = make_RDF(<<-EOR) #{make_channel} #{make_item} #{make_textinput} #{make_image} EOR @rss_file = "rss10.rdf" File.open(@rss_file, "w") {|f| f.print(@rss10)} end def teardown Parser.default_parser = @_default_parser FileUtils.rm_f(@rss_file) end def test_default_parser assert_nothing_raised do Parser.default_parser = RSS::AVAILABLE_PARSERS.first end assert_raise(RSS::NotValidXMLParser) do Parser.default_parser = RSS::Parser end end def test_parse assert_not_nil(RSS::Parser.parse(@rss_file)) garbage_rss_file = @rss_file + "-garbage" if RSS::Parser.default_parser.name == "RSS::XMLParserParser" assert_raise(RSS::NotWellFormedError) do RSS::Parser.parse(garbage_rss_file) end else assert_nil(RSS::Parser.parse(garbage_rss_file)) end end def test_parse_tag_includes_hyphen assert_nothing_raised do RSS::Parser.parse(make_RDF(<<-EOR)) #{make_channel} #{make_item} #{make_textinput} #{make_image} EOR end end end end ================================================ FILE: test/rss/test_parser_1.0.rb ================================================ require "rss-testcase" require "rss/1.0" require "rss/dublincore" module RSS class TestParser10 < TestCase def test_RDF assert_ns("", RDF::URI) do Parser.parse(<<-EOR) #{make_xmldecl} EOR end assert_ns("", RDF::URI) do Parser.parse(<<-EOR) #{make_xmldecl} EOR end assert_ns("rdf", RDF::URI) do Parser.parse(<<-EOR) #{make_xmldecl} EOR end assert_parse(<<-EOR, :missing_tag, "channel", "RDF") #{make_xmldecl} EOR assert_parse(<<-EOR, :missing_tag, "channel", "RDF") #{make_xmldecl} EOR assert_parse(<<-EOR, :missing_tag, "channel", "RDF") #{make_xmldecl} EOR assert_parse(make_RDF(<<-EOR), :missing_tag, "item", "RDF") #{make_channel} EOR assert_parse(make_RDF(<<-EOR), :missing_tag, "item", "RDF") #{make_channel} #{make_image} EOR assert_parse(make_RDF(<<-EOR), :missing_tag, "item", "RDF") #{make_channel} #{make_textinput} EOR assert_too_much_tag("image", "RDF") do Parser.parse(make_RDF(<<-EOR)) #{make_channel} #{make_image} #{make_image} #{make_item} #{make_textinput} EOR end assert_parse(make_RDF(<<-EOR), :nothing_raised) #{make_channel} #{make_item} #{make_image} #{make_textinput} EOR assert_parse(make_RDF(<<-EOR), :nothing_raised) #{make_channel} #{make_item} #{make_textinput} #{make_image} EOR assert_parse(make_RDF(<<-EOR), :nothing_raised) #{make_channel} #{make_image} #{make_item} EOR assert_parse(make_RDF(<<-EOR), :nothing_raised) #{make_channel} #{make_image} #{make_item} #{make_textinput} EOR 1.step(15, 3) do |i| rss = make_RDF() do res = make_channel i.times { res << make_item } res end assert_parse(rss, :nothing_raised) end end def test_undefined_entity return unless RSS::Parser.default_parser.raise_for_undefined_entity? assert_parse(make_RDF(<<-EOR), :raises, RSS::NotWellFormedError) #{make_channel} #{make_image} #{TITLE_VALUE} &UNKNOWN_ENTITY; #{LINK_VALUE} #{DESCRIPTION_VALUE} #{make_textinput} EOR end def test_channel assert_parse(make_RDF(<<-EOR), :missing_attribute, "channel", "rdf:about") EOR assert_parse(make_RDF(<<-EOR), :missing_tag, "title", "channel") EOR assert_parse(make_RDF(<<-EOR), :missing_tag, "link", "channel") hoge EOR assert_parse(make_RDF(< hoge http://example.com/ EOR assert_parse(make_RDF(<<-EOR), :missing_tag, "items", "channel") hoge http://example.com/ hogehoge EOR assert_parse(make_RDF(<<-EOR), :missing_attribute, "image", "rdf:resource") hoge http://example.com/ hogehoge EOR assert_parse(make_RDF(<<-EOR), :missing_tag, "items", "channel") hoge http://example.com/ hogehoge EOR rss = make_RDF(<<-EOR) hoge http://example.com/ hogehoge EOR assert_missing_tag("Seq", "items") do Parser.parse(rss) end assert_missing_tag("item", "RDF") do Parser.parse(rss, false).validate end assert_parse(make_RDF(<<-EOR), :missing_tag, "item", "RDF") hoge http://example.com/ hogehoge EOR assert_parse(make_RDF(<<-EOR), :missing_attribute, "textinput", "rdf:resource") hoge http://example.com/ hogehoge EOR assert_parse(make_RDF(<<-EOR), :missing_tag, "item", "RDF") hoge http://example.com/ hogehoge EOR end def test_rdf_li rss = make_RDF(<<-EOR) hoge http://example.com/ hogehoge #{make_item} EOR source = Proc.new do |rdf_li_attr| eval(%Q[%Q[#{rss}]], binding) end attr = %q[resource="http://example.com/hoge"] assert_parse(source.call(attr), :nothing_raised) attr = %q[rdf:resource="http://example.com/hoge"] assert_parse(source.call(attr), :nothing_raised) assert_parse(source.call(""), :missing_attribute, "li", "resource") end def test_image assert_parse(make_RDF(<<-EOR), :missing_attribute, "image", "rdf:about") #{make_channel} EOR assert_parse(make_RDF(<<-EOR), :missing_tag, "title", "image") #{make_channel} EOR assert_parse(make_RDF(<<-EOR), :missing_tag, "url", "image") #{make_channel} hoge EOR assert_parse(make_RDF(<<-EOR), :missing_tag, "link", "image") #{make_channel} hoge http://example.com/hoge.png EOR assert_parse(make_RDF(<<-EOR), :missing_tag, "item", "RDF") #{make_channel} hoge http://example.com/hoge.png http://example.com/ EOR rss = make_RDF(<<-EOR) #{make_channel} http://example.com/ http://example.com/hoge.png hoge EOR assert_missing_tag("item", "RDF") do Parser.parse(rss) end assert_missing_tag("item", "RDF") do Parser.parse(rss, false).validate end end def test_item assert_parse(make_RDF(<<-EOR), :missing_attribute, "item", "rdf:about") #{make_channel} #{make_image} EOR assert_parse(make_RDF(<<-EOR), :missing_tag, "title", "item") #{make_channel} #{make_image} EOR assert_parse(make_RDF(<<-EOR), :missing_tag, "link", "item") #{make_channel} #{make_image} hoge EOR assert_too_much_tag("title", "item") do Parser.parse(make_RDF(<<-EOR)) #{make_channel} #{make_image} hoge hoge http://example.com/hoge.html EOR end assert_parse(make_RDF(<<-EOR), :nothing_raised) #{make_channel} #{make_image} hoge http://example.com/hoge.html EOR assert_parse(make_RDF(<<-EOR), :nothing_raised) #{make_channel} #{make_image} hoge http://example.com/hoge.html hogehoge EOR end def test_textinput assert_parse(make_RDF(<<-EOR), :missing_attribute, "textinput", "rdf:about") #{make_channel} #{make_image} #{make_item} EOR assert_parse(make_RDF(<<-EOR), :missing_tag, "title", "textinput") #{make_channel} #{make_image} #{make_item} EOR assert_parse(make_RDF(<<-EOR), :missing_tag, "description", "textinput") #{make_channel} #{make_image} #{make_item} hoge EOR assert_too_much_tag("title", "textinput") do Parser.parse(make_RDF(<<-EOR)) #{make_channel} #{make_image} #{make_item} hoge hoge hogehoge EOR end assert_parse(make_RDF(<<-EOR), :missing_tag, "name", "textinput") #{make_channel} #{make_image} #{make_item} hoge hogehoge EOR assert_parse(make_RDF(<<-EOR), :missing_tag, "link", "textinput") #{make_channel} #{make_image} #{make_item} hoge hogehoge key EOR assert_parse(make_RDF(<<-EOR), :nothing_raised) #{make_channel} #{make_image} #{make_item} hoge hogehoge key http://example.com/search.html EOR end def test_ignore name = "a" rss = make_RDF(<<-EOR) #{make_channel} #{make_item} <#{name}/> EOR assert_not_expected_tag(name, ::RSS::URI, "RDF") do Parser.parse(rss, true, false) end uri = "" name = "a" rss = make_RDF(<<-EOR) #{make_channel} #{make_item} <#{name} xmlns=""/> EOR assert_parse(rss, :nothing_raised) assert_not_expected_tag(name, uri, "RDF") do Parser.parse(rss, true, false) end uri = "http://example.com/" name = "a" rss = make_RDF(<<-EOR) #{make_channel} #{make_item} EOR assert_parse(rss, :nothing_raised) assert_not_expected_tag(name, uri, "RDF") do Parser.parse(rss, true, false) end uri = ::RSS::URI name = "a" rss = make_RDF(<<-EOR) #{make_channel} #{make_item} #{make_image("<#{name}/>")} EOR assert_parse(rss, :nothing_raised) assert_not_expected_tag(name, uri, "image") do Parser.parse(rss, true, false) end uri = CONTENT_URI name = "encoded" elem = "<#{name} xmlns='#{uri}'/>" rss = make_RDF(<<-EOR) #{make_channel} #{make_item} #{make_image(elem)} EOR assert_parse(rss, :nothing_raised) assert_not_expected_tag(name, uri, "image") do Parser.parse(rss, true, false) end end def test_unknown_duplicated_element xmlns = {"test" => "http://localhost/test"} assert_parse(make_RDF(<<-EOR, xmlns), :nothing_raised) #{make_channel("")} #{make_item} #{make_image} EOR end end end ================================================ FILE: test/rss/test_parser_2.0.rb ================================================ require "rss-testcase" require "rss/2.0" module RSS class TestParser20 < TestCase def test_rss20 assert_parse(make_rss20(<<-EOR), :missing_tag, "channel", "rss") EOR assert_parse(make_rss20(<<-EOR), :nothing_raised) #{make_channel20("")} EOR end def test_cloud20 attrs = [ ["domain", CLOUD_DOMAIN], ["port", CLOUD_PORT], ["path", CLOUD_PATH], ["registerProcedure", CLOUD_REGISTER_PROCEDURE], ["protocol", CLOUD_PROTOCOL], ] (attrs.size + 1).times do |i| missing_attr = attrs[i] if missing_attr meth = :missing_attribute args = ["cloud", missing_attr[0]] else meth = :nothing_raised args = [] end cloud_attrs = [] attrs.each_with_index do |attr, j| unless i == j cloud_attrs << %Q[#{attr[0]}="#{attr[1]}"] end end assert_parse(make_rss20(<<-EOR), meth, *args) #{make_channel20(%Q[])} EOR end end def test_source20 assert_parse(make_rss20(<<-EOR), :missing_attribute, "source", "url") #{make_channel20(make_item20(%Q[Example]))} EOR assert_parse(make_rss20(<<-EOR), :nothing_raised) #{make_channel20(make_item20(%Q[]))} EOR assert_parse(make_rss20(<<-EOR), :nothing_raised) #{make_channel20(make_item20(%Q[Example]))} EOR end def test_enclosure20 attrs = [ ["url", ENCLOSURE_URL], ["length", ENCLOSURE_LENGTH], ["type", ENCLOSURE_TYPE], ] (attrs.size + 1).times do |i| missing_attr = attrs[i] if missing_attr meth = :missing_attribute args = ["enclosure", missing_attr[0]] else meth = :nothing_raised args = [] end enclosure_attrs = [] attrs.each_with_index do |attr, j| unless i == j enclosure_attrs << %Q[#{attr[0]}="#{attr[1]}"] end end assert_parse(make_rss20(<<-EOR), meth, *args) #{make_channel20(%Q[ #{make_item20(%Q[ ])} ])} EOR end end def test_category20 values = [nil, CATEGORY_DOMAIN] values.each do |value| domain = "" domain << %Q[domain="#{value}"] if value ["", "Example Text"].each do |text| rss_src = make_rss20(<<-EOR) #{make_channel20(%Q[ #{make_item20(%Q[ #{text} ])} ])} EOR assert_parse(rss_src, :nothing_raised) rss = RSS::Parser.parse(rss_src) category = rss.items.last.categories.first assert_equal(value, category.domain) assert_equal(text, category.content) end end end end end ================================================ FILE: test/rss/test_parser_atom_entry.rb ================================================ require "rss-testcase" require "rss/atom" module RSS class TestParserAtom < TestCase def test_entry_validation assert_ns("", Atom::URI) do Parser.parse(<<-EOA) EOA end assert_ns("", Atom::URI) do Parser.parse(<<-EOA) EOA end assert_parse(<<-EOA, :missing_tag, "id", "entry") do EOA end assert_parse(<<-EOA, :missing_tag, "title", "entry") do urn:uuid:506e336c-a26e-4457-917b-b89dca7ae746 EOA end assert_parse(<<-EOA, :missing_tag, "updated", "entry") do urn:uuid:506e336c-a26e-4457-917b-b89dca7ae746 Example Entry EOA end assert_parse(<<-EOA, :missing_tag, "author", "entry") do urn:uuid:506e336c-a26e-4457-917b-b89dca7ae746 Example Entry 2003-10-10T18:30:02Z EOA end assert_parse(<<-EOA, :nothing_raised) do urn:uuid:506e336c-a26e-4457-917b-b89dca7ae746 Example Entry 2003-10-10T18:30:02Z A person EOA end end def test_entry entry = RSS::Parser.parse(<<-EOA) A person Atom-Powered Robots Run Amok urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a 2003-12-13T18:30:02Z Some text. EOA assert_not_nil(entry) assert_equal("Atom-Powered Robots Run Amok", entry.title.content) assert_equal("http://example.org/2003/12/13/atom03", entry.link.href) assert_equal("urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a", entry.id.content) assert_equal(Time.parse("2003-12-13T18:30:02Z"), entry.updated.content) assert_equal("Some text.", entry.summary.content) end def test_entry_author assert_atom_person("author", method(:make_entry_document)) do |entry| assert_equal(2, entry.authors.size) entry.authors.last end end def test_entry_category assert_atom_category(method(:make_entry_document)) do |entry| assert_equal(1, entry.categories.size) entry.category end end def test_entry_content_text assert_atom_content(method(:make_entry_document)) do |entry| entry.content end end def test_entry_contributor assert_atom_person("contributor", method(:make_entry_document)) do |entry| assert_equal(1, entry.contributors.size) entry.contributor end end def test_entry_id entry = RSS::Parser.parse(make_entry_document) assert_equal(ENTRY_ID, entry.id.content) end def test_entry_link assert_atom_link(method(:make_entry_document)) do |entry| assert_equal(1, entry.links.size) entry.link end end def test_published generator = method(:make_entry_document) assert_atom_date_construct("published", generator) do |entry| entry.published end end def test_entry_rights generator = method(:make_entry_document) assert_atom_text_construct("rights", generator) do |entry| entry.rights end end def test_entry_source generator = method(:make_entry_document_with_open_source) assert_atom_source(generator) do |entry| assert_not_nil(entry.source) entry.source end end def test_entry_summary generator = method(:make_entry_document) assert_atom_text_construct("summary", generator) do |entry| entry.summary end end def test_entry_title entry = RSS::Parser.parse(make_entry_document) assert_equal(ENTRY_TITLE, entry.title.content) end def test_entry_updated entry = RSS::Parser.parse(make_entry_document) assert_equal(Time.parse(ENTRY_UPDATED), entry.updated.content) end end end ================================================ FILE: test/rss/test_parser_atom_feed.rb ================================================ require "rss-testcase" require "rss/atom" module RSS class TestParserAtomFeed < TestCase def test_feed_validation assert_ns("", Atom::URI) do Parser.parse(<<-EOA) EOA end assert_ns("", Atom::URI) do Parser.parse(<<-EOA) EOA end assert_parse(<<-EOA, :missing_tag, "id", "feed") do EOA end assert_parse(<<-EOA, :missing_tag, "title", "feed") do urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6 EOA end assert_parse(<<-EOA, :missing_tag, "updated", "feed") do urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6 Example Feed EOA end assert_parse(<<-EOA, :missing_tag, "author", "feed") do urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6 Example Feed 2003-12-13T18:30:02Z EOA end assert_parse(<<-EOA, :nothing_raised) do urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6 Example Feed 2003-12-13T18:30:02Z A person EOA end end def test_lang feed = RSS::Parser.parse(<<-EOA) urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6 Example Feed 2003-12-13T18:30:02Z A person EOA assert_equal("ja", feed.lang) assert_equal("ja", feed.id.lang) assert_equal("en", feed.title.lang) assert_equal("ja", feed.updated.lang) assert_equal("en", feed.author.lang) assert_equal("en", feed.author.name.lang) end def test_base feed = RSS::Parser.parse(<<-EOA) urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6 Example Feed 2003-12-13T18:30:02Z Generator A person person EOA assert_equal("http://example.com/", feed.base) assert_equal("http://example.com/", feed.id.base) assert_equal("http://example.com/", feed.title.base) assert_equal("http://example.com/", feed.updated.base) assert_equal("http://example.com/", feed.generator.base) assert_equal("http://example.com/generator", feed.generator.uri) assert_equal("http://example.com/", feed.links[0].base) assert_equal("http://example.org/link1", feed.links[0].href) assert_equal("http://example.com/", feed.links[1].base) assert_equal("http://example.com/link2", feed.links[1].href) assert_equal("http://example.net/", feed.links[2].base) assert_equal("http://example.net/link3", feed.links[2].href) assert_equal("http://example.com/person", feed.author.uri.content) end def test_feed_author assert_atom_person("author", method(:make_feed)) do |feed| assert_equal(2, feed.authors.size) feed.authors[1] end end def test_entry_author generator = method(:make_feed_with_open_entry) assert_atom_person("author", generator) do |feed| assert_equal(1, feed.entries.size) assert_equal(1, feed.entry.authors.size) feed.entry.author end end def test_feed_category assert_atom_category(method(:make_feed)) do |feed| assert_equal(1, feed.categories.size) feed.category end end def test_entry_category assert_atom_category(method(:make_feed_with_open_entry)) do |feed| assert_equal(1, feed.entries.size) assert_equal(1, feed.entry.categories.size) feed.entry.category end end def test_entry_content assert_atom_content(method(:make_feed_with_open_entry)) do |feed| assert_equal(1, feed.entries.size) feed.entry.content end end def test_feed_contributor assert_atom_person("contributor", method(:make_feed)) do |feed| assert_equal(1, feed.contributors.size) feed.contributor end end def test_entry_contributor generator = method(:make_feed_with_open_entry) assert_atom_person("contributor", generator) do |feed| assert_equal(1, feed.entries.size) assert_equal(1, feed.entry.contributors.size) feed.entry.contributor end end def test_feed_generator assert_atom_generator(method(:make_feed)) do |feed| feed.generator end end def test_feed_icon assert_atom_icon(method(:make_feed)) do |feed| feed.icon end end def test_feed_id feed = RSS::Parser.parse(make_feed('')) assert_equal(FEED_ID, feed.id.content) end def test_entry_id feed = RSS::Parser.parse(make_feed('')) assert_equal(ENTRY_ID, feed.entry.id.content) end def test_feed_link assert_atom_link(method(:make_feed)) do |feed| assert_equal(1, feed.links.size) feed.link end end def test_entry_link assert_atom_link(method(:make_feed_with_open_entry)) do |feed| assert_equal(1, feed.entries.size) assert_equal(1, feed.entry.links.size) feed.entry.link end end def test_feed_logo assert_atom_logo(method(:make_feed)) do |feed| feed.logo end end def test_feed_rights assert_atom_text_construct("rights", method(:make_feed)) do |feed| feed.rights end end def test_entry_rights generator = method(:make_feed_with_open_entry) assert_atom_text_construct("rights", generator) do |feed| assert_equal(1, feed.entries.size) feed.entry.rights end end def test_entry_source assert_atom_source(method(:make_feed_with_open_entry_source)) do |feed| assert_equal(1, feed.entries.size) assert_not_nil(feed.entry.source) feed.entry.source end end def test_feed_subtitle assert_atom_text_construct("subtitle", method(:make_feed)) do |feed| feed.subtitle end end def test_feed_title feed = RSS::Parser.parse(make_feed('')) assert_equal(FEED_TITLE, feed.title.content) end def test_entry_title feed = RSS::Parser.parse(make_feed('')) assert_equal(ENTRY_TITLE, feed.entry.title.content) end def test_feed_updated feed = RSS::Parser.parse(make_feed('')) assert_equal(Time.parse(FEED_UPDATED), feed.updated.content) end def test_entry_updated feed = RSS::Parser.parse(make_feed('')) assert_equal(Time.parse(ENTRY_UPDATED), feed.entry.updated.content) end def test_entry_published generator = method(:make_feed_with_open_entry) assert_atom_date_construct("published", generator) do |feed| assert_equal(1, feed.entries.size) feed.entry.published end end def test_entry_summary generator = method(:make_feed_with_open_entry) assert_atom_text_construct("summary", generator) do |feed| assert_equal(1, feed.entries.size) feed.entry.summary end end end end ================================================ FILE: test/rss/test_setup_maker_0.9.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestSetupMaker09 < TestCase def test_setup_maker_channel title = "fugafuga" link = "http://hoge.com" description = "fugafugafugafuga" language = "ja" copyright = "foo" managingEditor = "bar" webMaster = "web master" rating = '(PICS-1.1 "http://www.rsac.org/ratingsv01.html" l gen true comment "RSACi North America Server" for "http://www.rsac.org" on "1996.04.16T08:15-0500" r (n 0 s 0 v 0 l 0))' docs = "http://foo.com/doc" skipDays = [ "Sunday", "Monday", ] skipHours = [ "0", "13", ] pubDate = Time.now lastBuildDate = Time.now rss = RSS::Maker.make("0.91") do |maker| maker.channel.title = title maker.channel.link = link maker.channel.description = description maker.channel.language = language maker.channel.copyright = copyright maker.channel.managingEditor = managingEditor maker.channel.webMaster = webMaster maker.channel.rating = rating maker.channel.docs = docs maker.channel.pubDate = pubDate maker.channel.lastBuildDate = lastBuildDate skipDays.each do |day| maker.channel.skipDays.new_day do |new_day| new_day.content = day end end skipHours.each do |hour| maker.channel.skipHours.new_hour do |new_hour| new_hour.content = hour end end setup_dummy_image(maker) end assert_not_set_error("maker.image", %w(title url)) do RSS::Maker.make("0.91") do |maker| rss.channel.setup_maker(maker) end end new_rss = RSS::Maker.make("0.91") do |maker| rss.channel.setup_maker(maker) setup_dummy_image(maker) end channel = new_rss.channel assert_equal(title, channel.title) assert_equal(link, channel.link) assert_equal(description, channel.description) assert_equal(language, channel.language) assert_equal(copyright, channel.copyright) assert_equal(managingEditor, channel.managingEditor) assert_equal(webMaster, channel.webMaster) assert_equal(rating, channel.rating) assert_equal(docs, channel.docs) assert_equal(pubDate, channel.pubDate) assert_equal(lastBuildDate, channel.lastBuildDate) skipDays.each_with_index do |day, i| assert_equal(day, channel.skipDays.days[i].content) end skipHours.each_with_index do |hour, i| assert_equal(hour.to_i, channel.skipHours.hours[i].content) end assert(channel.items.empty?) assert_nil(channel.textInput) end def test_setup_maker_image title = "fugafuga" link = "http://hoge.com" url = "http://hoge.com/hoge.png" width = "144" height = "400" description = "an image" rss = RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) maker.channel.link = link maker.image.title = title maker.image.url = url maker.image.width = width maker.image.height = height maker.image.description = description end new_rss = RSS::Maker.make("0.91") do |maker| rss.channel.setup_maker(maker) rss.image.setup_maker(maker) end image = new_rss.image assert_equal(title, image.title) assert_equal(link, image.link) assert_equal(url, image.url) assert_equal(width.to_i, image.width) assert_equal(height.to_i, image.height) assert_equal(description, image.description) end def test_setup_maker_textinput title = "fugafuga" description = "text hoge fuga" name = "hoge" link = "http://hoge.com" rss = RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) setup_dummy_image(maker) maker.textinput.title = title maker.textinput.description = description maker.textinput.name = name maker.textinput.link = link end new_rss = RSS::Maker.make("0.91") do |maker| rss.channel.setup_maker(maker) rss.image.setup_maker(maker) rss.textinput.setup_maker(maker) end textInput = new_rss.channel.textInput assert_equal(title, textInput.title) assert_equal(description, textInput.description) assert_equal(name, textInput.name) assert_equal(link, textInput.link) end def test_setup_maker_items(for_backward_compatibility=false) title = "TITLE" link = "http://hoge.com/" description = "text hoge fuga" item_size = 5 rss = RSS::Maker.make("0.91") do |maker| setup_dummy_channel(maker) item_size.times do |i| maker.items.new_item do |item| item.title = "#{title}#{i}" item.link = "#{link}#{i}" item.description = "#{description}#{i}" end end setup_dummy_image(maker) end new_rss = RSS::Maker.make("0.91") do |maker| rss.channel.setup_maker(maker) rss.items.each do |item| if for_backward_compatibility item.setup_maker(maker) else item.setup_maker(maker.items) end end rss.image.setup_maker(maker) end assert_equal(item_size, new_rss.items.size) new_rss.items.each_with_index do |item, i| assert_equal("#{title}#{i}", item.title) assert_equal("#{link}#{i}", item.link) assert_equal("#{description}#{i}", item.description) end end def test_setup_maker_items_backward_compatibility test_setup_maker_items(true) end def test_setup_maker encoding = "EUC-JP" standalone = true href = 'a.xsl' type = 'text/xsl' title = 'sample' media = 'printer' charset = 'UTF-8' alternate = 'yes' rss = RSS::Maker.make("0.91") do |maker| maker.encoding = encoding maker.standalone = standalone maker.xml_stylesheets.new_xml_stylesheet do |xss| xss.href = href xss.type = type xss.title = title xss.media = media xss.charset = charset xss.alternate = alternate end setup_dummy_channel(maker) setup_dummy_image(maker) end new_rss = RSS::Maker.make("0.91") do |maker| rss.setup_maker(maker) end assert_equal("0.91", new_rss.rss_version) assert_equal(encoding, new_rss.encoding) assert_equal(standalone, new_rss.standalone) xss = rss.xml_stylesheets.first assert_equal(1, rss.xml_stylesheets.size) assert_equal(href, xss.href) assert_equal(type, xss.type) assert_equal(title, xss.title) assert_equal(media, xss.media) assert_equal(charset, xss.charset) assert_equal(alternate, xss.alternate) end end end ================================================ FILE: test/rss/test_setup_maker_1.0.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestSetupMaker10 < TestCase def setup t = Time.iso8601("2000-01-01T12:00:05+00:00") class << t alias_method(:to_s, :iso8601) end @dc_elems = { :title => "hoge", :description => " XML is placing increasingly heavy loads on the existing technical infrastructure of the Internet.", :creator => "Rael Dornfest (mailto:rael@oreilly.com)", :subject => "XML", :publisher => "The O'Reilly Network", :contributor => "hogehoge", :type => "fugafuga", :format => "hohoho", :identifier => "fufufu", :source => "barbar", :language => "ja", :relation => "cococo", :rights => "Copyright (c) 2000 O'Reilly & Associates, Inc.", :date => t, } @sy_elems = { :updatePeriod => "hourly", :updateFrequency => "2", :updateBase => t, } @content_elems = { :encoded => "ATTENTION", } @trackback_elems = { :ping => "http://bar.com/tb.cgi?tb_id=rssplustrackback", :about => [ "http://foo.com/trackback/tb.cgi?tb_id=20020923", "http://foo.com/trackback/tb.cgi?tb_id=20021010", ], } @taxo_topic_elems = [ { :link => "http://meerkat.oreillynet.com/?c=cat23", :title => "Data: XML", :description => "A Meerkat channel", }, { :link => "http://dmoz.org/Computers/Data_Formats/Markup_Languages/XML/", :title => "XML", :subject => "XML", :description => "DMOZ category", :topics => [ "http://meerkat.oreillynet.com/?c=cat23", "http://dmoz.org/Computers/Data_Formats/Markup_Languages/SGML/", "http://dmoz.org/Computers/Programming/Internet/", ] }, ] end def test_setup_maker_channel about = "http://hoge.com" title = "fugafuga" link = "http://hoge.com" description = "fugafugafugafuga" rss = RSS::Maker.make("1.0") do |maker| maker.channel.about = about maker.channel.title = title maker.channel.link = link maker.channel.description = description @dc_elems.each do |var, value| maker.channel.__send__("dc_#{var}=", value) end @sy_elems.each do |var, value| maker.channel.__send__("sy_#{var}=", value) end setup_dummy_item(maker) end new_rss = RSS::Maker.make("1.0") do |maker| rss.channel.setup_maker(maker) rss.items.each do |item| item.setup_maker(maker) end end channel = new_rss.channel assert_equal(about, channel.about) assert_equal(title, channel.title) assert_equal(link, channel.link) assert_equal(description, channel.description) assert_equal(1, channel.items.Seq.lis.size) assert_nil(channel.image) assert_nil(channel.textinput) @dc_elems.each do |var, value| assert_equal(value, channel.__send__("dc_#{var}")) end @sy_elems.each do |var, value| value = value.to_i if var == :updateFrequency assert_equal(value, channel.__send__("sy_#{var}")) end end def test_setup_maker_image title = "fugafuga" link = "http://hoge.com" url = "http://hoge.com/hoge.png" rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) maker.channel.link = link maker.image.title = title maker.image.url = url @dc_elems.each do |var, value| maker.image.__send__("dc_#{var}=", value) end setup_dummy_item(maker) end new_rss = RSS::Maker.make("1.0") do |maker| rss.channel.setup_maker(maker) rss.image.setup_maker(maker) rss.items.each do |item| item.setup_maker(maker) end end image = new_rss.image assert_equal(url, image.about) assert_equal(url, new_rss.channel.image.resource) assert_equal(title, image.title) assert_equal(link, image.link) assert_equal(url, image.url) @dc_elems.each do |var, value| assert_equal(image.__send__("dc_#{var}"), value) end end def test_setup_maker_textinput title = "fugafuga" description = "text hoge fuga" name = "hoge" link = "http://hoge.com" rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) maker.textinput.link = link maker.textinput.title = title maker.textinput.description = description maker.textinput.name = name @dc_elems.each do |var, value| maker.textinput.__send__("dc_#{var}=", value) end setup_dummy_item(maker) end new_rss = RSS::Maker.make("1.0") do |maker| rss.channel.setup_maker(maker) rss.textinput.setup_maker(maker) rss.items.each do |item| item.setup_maker(maker) end end textinput = new_rss.textinput assert_equal(link, textinput.about) assert_equal(link, new_rss.channel.textinput.resource) assert_equal(title, textinput.title) assert_equal(name, textinput.name) assert_equal(description, textinput.description) assert_equal(link, textinput.link) @dc_elems.each do |var, value| assert_equal(textinput.__send__("dc_#{var}"), value) end end def test_setup_maker_items(for_backward_compatibility=false) title = "TITLE" link = "http://hoge.com/" description = "text hoge fuga" item_size = 5 rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) item_size.times do |i| maker.items.new_item do |item| item.title = "#{title}#{i}" item.link = "#{link}#{i}" item.description = "#{description}#{i}" @dc_elems.each do |var, value| item.__send__("dc_#{var}=", value) end @content_elems.each do |var, value| item.__send__("content_#{var}=", value) end item.trackback_ping = @trackback_elems[:ping] @trackback_elems[:about].each do |value| item.trackback_abouts.new_about do |new_about| new_about.value = value end end end end end new_rss = RSS::Maker.make("1.0") do |maker| rss.channel.setup_maker(maker) rss.items.each do |item| if for_backward_compatibility item.setup_maker(maker) else item.setup_maker(maker.items) end end end assert_equal(item_size, new_rss.items.size) new_rss.items.each_with_index do |item, i| assert_equal("#{link}#{i}", item.about) assert_equal("#{title}#{i}", item.title) assert_equal("#{link}#{i}", item.link) assert_equal("#{description}#{i}", item.description) @dc_elems.each do |var, value| assert_equal(item.__send__("dc_#{var}"), value) end @content_elems.each do |var, value| assert_equal(item.__send__("content_#{var}"), value) end assert_equal(@trackback_elems[:ping], item.trackback_ping) assert_equal(@trackback_elems[:about].size, item.trackback_abouts.size) item.trackback_abouts.each_with_index do |about, j| assert_equal(@trackback_elems[:about][j], about.value) end end end def test_setup_maker_items_sort title = "TITLE" link = "http://hoge.com/" description = "text hoge fuga" item_size = 5 rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) item_size.times do |i| item = RSS::RDF::Item.new("#{link}#{i}") item.title = "#{title}#{i}" item.link = "#{link}#{i}" item.description = "#{description}#{i}" item.dc_date = Time.now + i * 60 item.setup_maker(maker.items) end maker.items.do_sort = false end assert_equal(item_size, rss.items.size) rss.items.each_with_index do |item, i| assert_equal("#{link}#{i}", item.about) assert_equal("#{title}#{i}", item.title) assert_equal("#{link}#{i}", item.link) assert_equal("#{description}#{i}", item.description) end rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) item_size.times do |i| item = RSS::RDF::Item.new("#{link}#{i}") item.title = "#{title}#{i}" item.link = "#{link}#{i}" item.description = "#{description}#{i}" item.dc_date = Time.now + i * 60 item.setup_maker(maker.items) end maker.items.do_sort = true end assert_equal(item_size, rss.items.size) rss.items.reverse.each_with_index do |item, i| assert_equal("#{link}#{i}", item.about) assert_equal("#{title}#{i}", item.title) assert_equal("#{link}#{i}", item.link) assert_equal("#{description}#{i}", item.description) end end def test_setup_maker_items_backward_compatibility test_setup_maker_items(true) end def test_setup_maker encoding = "EUC-JP" standalone = true href = 'a.xsl' type = 'text/xsl' title = 'sample' media = 'printer' charset = 'UTF-8' alternate = 'yes' rss = RSS::Maker.make("1.0") do |maker| maker.encoding = encoding maker.standalone = standalone maker.xml_stylesheets.new_xml_stylesheet do |xss| xss.href = href xss.type = type xss.title = title xss.media = media xss.charset = charset xss.alternate = alternate end setup_dummy_channel(maker) setup_dummy_item(maker) end new_rss = RSS::Maker.make("1.0") do |maker| rss.setup_maker(maker) end assert_equal("1.0", new_rss.rss_version) assert_equal(encoding, new_rss.encoding) assert_equal(standalone, new_rss.standalone) xss = new_rss.xml_stylesheets.first assert_equal(1, new_rss.xml_stylesheets.size) assert_equal(href, xss.href) assert_equal(type, xss.type) assert_equal(title, xss.title) assert_equal(media, xss.media) assert_equal(charset, xss.charset) assert_equal(alternate, xss.alternate) end def test_setup_maker_full encoding = "EUC-JP" standalone = true href = 'a.xsl' type = 'text/xsl' title = 'sample' media = 'printer' charset = 'UTF-8' alternate = 'yes' channel_about = "http://hoge.com" channel_title = "fugafuga" channel_link = "http://hoge.com" channel_description = "fugafugafugafuga" image_title = "fugafuga" image_url = "http://hoge.com/hoge.png" textinput_title = "fugafuga" textinput_description = "text hoge fuga" textinput_name = "hoge" textinput_link = "http://hoge.com" item_title = "TITLE" item_link = "http://hoge.com/" item_description = "text hoge fuga" item_size = 5 rss = RSS::Maker.make("1.0") do |maker| maker.encoding = encoding maker.standalone = standalone maker.xml_stylesheets.new_xml_stylesheet do |xss| xss.href = href xss.type = type xss.title = title xss.media = media xss.charset = charset xss.alternate = alternate end maker.channel.about = channel_about maker.channel.title = channel_title maker.channel.link = channel_link maker.channel.description = channel_description @dc_elems.each do |var, value| maker.channel.__send__("dc_#{var}=", value) end @sy_elems.each do |var, value| maker.channel.__send__("sy_#{var}=", value) end maker.image.title = image_title maker.image.url = image_url @dc_elems.each do |var, value| maker.image.__send__("dc_#{var}=", value) end maker.textinput.link = textinput_link maker.textinput.title = textinput_title maker.textinput.description = textinput_description maker.textinput.name = textinput_name @dc_elems.each do |var, value| maker.textinput.__send__("dc_#{var}=", value) end item_size.times do |i| maker.items.new_item do |item| item.title = "#{item_title}#{i}" item.link = "#{item_link}#{i}" item.description = "#{item_description}#{i}" @dc_elems.each do |var, value| item.__send__("dc_#{var}=", value) end @content_elems.each do |var, value| item.__send__("content_#{var}=", value) end item.trackback_ping = @trackback_elems[:ping] @trackback_elems[:about].each do |value| item.trackback_abouts.new_about do |new_about| new_about.value = value end end end end setup_taxo_topic(maker, @taxo_topic_elems) end new_rss = RSS::Maker.make("1.0") do |maker| rss.setup_maker(maker) end assert_equal("1.0", new_rss.rss_version) assert_equal(encoding, new_rss.encoding) assert_equal(standalone, new_rss.standalone) xss = new_rss.xml_stylesheets.first assert_equal(1, new_rss.xml_stylesheets.size) assert_equal(href, xss.href) assert_equal(type, xss.type) assert_equal(title, xss.title) assert_equal(media, xss.media) assert_equal(charset, xss.charset) assert_equal(alternate, xss.alternate) channel = new_rss.channel assert_equal(channel_about, channel.about) assert_equal(channel_title, channel.title) assert_equal(channel_link, channel.link) assert_equal(channel_description, channel.description) item_resources = [] item_size.times do |i| item_resources << "#{item_link}#{i}" end assert_equal(item_resources, channel.items.resources) assert_equal(image_url, channel.image.resource) assert_equal(textinput_link, channel.textinput.resource) @dc_elems.each do |var, value| assert_equal(value, channel.__send__("dc_#{var}")) end @sy_elems.each do |var, value| value = value.to_i if var == :updateFrequency assert_equal(value, channel.__send__("sy_#{var}")) end image = new_rss.image assert_equal(image_url, image.about) assert_equal(image_url, new_rss.channel.image.resource) assert_equal(image_title, image.title) assert_equal(channel_link, image.link) assert_equal(image_url, image.url) @dc_elems.each do |var, value| assert_equal(image.__send__("dc_#{var}"), value) end textinput = new_rss.textinput assert_equal(textinput_link, textinput.about) assert_equal(textinput_link, new_rss.channel.textinput.resource) assert_equal(textinput_title, textinput.title) assert_equal(textinput_name, textinput.name) assert_equal(textinput_description, textinput.description) assert_equal(textinput_link, textinput.link) @dc_elems.each do |var, value| assert_equal(textinput.__send__("dc_#{var}"), value) end assert_equal(item_size, new_rss.items.size) new_rss.items.each_with_index do |item, i| assert_equal("#{item_link}#{i}", item.about) assert_equal("#{item_title}#{i}", item.title) assert_equal("#{item_link}#{i}", item.link) assert_equal("#{item_description}#{i}", item.description) @dc_elems.each do |var, value| assert_equal(item.__send__("dc_#{var}"), value) end @content_elems.each do |var, value| assert_equal(item.__send__("content_#{var}"), value) end assert_equal(@trackback_elems[:ping], item.trackback_ping) assert_equal(@trackback_elems[:about].size, item.trackback_abouts.size) item.trackback_abouts.each_with_index do |about, j| assert_equal(@trackback_elems[:about][j], about.value) end end assert_taxo_topic(@taxo_topic_elems, new_rss) end end end ================================================ FILE: test/rss/test_setup_maker_2.0.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestSetupMaker20 < TestCase def test_setup_maker_channel title = "fugafuga" link = "http://hoge.com" description = "fugafugafugafuga" language = "ja" copyright = "foo" managingEditor = "bar" webMaster = "web master" rating = '(PICS-1.1 "http://www.rsac.org/ratingsv01.html" l gen true comment "RSACi North America Server" for "http://www.rsac.org" on "1996.04.16T08:15-0500" r (n 0 s 0 v 0 l 0))' docs = "http://foo.com/doc" skipDays = [ "Sunday", "Monday", ] skipHours = [ "0", "13", ] pubDate = Time.now lastBuildDate = Time.now categories = [ "Nespapers", "misc", ] generator = "RSS Maker" ttl = "60" rss = RSS::Maker.make("2.0") do |maker| maker.channel.title = title maker.channel.link = link maker.channel.description = description maker.channel.language = language maker.channel.copyright = copyright maker.channel.managingEditor = managingEditor maker.channel.webMaster = webMaster maker.channel.rating = rating maker.channel.docs = docs maker.channel.pubDate = pubDate maker.channel.lastBuildDate = lastBuildDate skipDays.each do |day| maker.channel.skipDays.new_day do |new_day| new_day.content = day end end skipHours.each do |hour| maker.channel.skipHours.new_hour do |new_hour| new_hour.content = hour end end categories.each do |category| maker.channel.categories.new_category do |new_category| new_category.content = category end end maker.channel.generator = generator maker.channel.ttl = ttl end new_rss = RSS::Maker.make("2.0") do |maker| rss.channel.setup_maker(maker) end channel = new_rss.channel assert_equal(title, channel.title) assert_equal(link, channel.link) assert_equal(description, channel.description) assert_equal(language, channel.language) assert_equal(copyright, channel.copyright) assert_equal(managingEditor, channel.managingEditor) assert_equal(webMaster, channel.webMaster) assert_equal(rating, channel.rating) assert_equal(docs, channel.docs) assert_equal(pubDate, channel.pubDate) assert_equal(lastBuildDate, channel.lastBuildDate) skipDays.each_with_index do |day, i| assert_equal(day, channel.skipDays.days[i].content) end skipHours.each_with_index do |hour, i| assert_equal(hour.to_i, channel.skipHours.hours[i].content) end channel.categories.each_with_index do |category, i| assert_equal(categories[i], category.content) end assert_equal(generator, channel.generator) assert_equal(ttl.to_i, channel.ttl) assert(channel.items.empty?) assert_nil(channel.image) assert_nil(channel.textInput) end def test_setup_maker_image title = "fugafuga" link = "http://hoge.com" url = "http://hoge.com/hoge.png" width = "144" height = "400" description = "an image" rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) maker.channel.link = link maker.image.title = title maker.image.url = url maker.image.width = width maker.image.height = height maker.image.description = description end new_rss = RSS::Maker.make("2.0") do |maker| rss.channel.setup_maker(maker) rss.image.setup_maker(maker) end image = new_rss.image assert_equal(title, image.title) assert_equal(link, image.link) assert_equal(url, image.url) assert_equal(width.to_i, image.width) assert_equal(height.to_i, image.height) assert_equal(description, image.description) end def test_setup_maker_textinput title = "fugafuga" description = "text hoge fuga" name = "hoge" link = "http://hoge.com" rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) maker.textinput.title = title maker.textinput.description = description maker.textinput.name = name maker.textinput.link = link end new_rss = RSS::Maker.make("2.0") do |maker| rss.channel.setup_maker(maker) rss.textinput.setup_maker(maker) end textInput = new_rss.channel.textInput assert_equal(title, textInput.title) assert_equal(description, textInput.description) assert_equal(name, textInput.name) assert_equal(link, textInput.link) end def test_setup_maker_items(for_backward_compatibility=false) title = "TITLE" link = "http://hoge.com/" description = "text hoge fuga" author = "oprah@oxygen.net" comments = "http://www.myblog.org/cgi-local/mt/mt-comments.cgi?entry_id=290" pubDate = Time.now guid_isPermaLink = "true" guid_content = "http://inessential.com/2002/09/01.php#a2" enclosure_url = "http://www.scripting.com/mp3s/weatherReportSuite.mp3" enclosure_length = "12216320" enclosure_type = "audio/mpeg" source_url = "http://static.userland.com/tomalak/links2.xml" source_content = "Tomalak's Realm" category_domain = "http://www.fool.com/cusips" category_content = "MSFT" item_size = 5 rss = RSS::Maker.make("2.0") do |maker| setup_dummy_channel(maker) item_size.times do |i| maker.items.new_item do |item| item.title = "#{title}#{i}" item.link = "#{link}#{i}" item.description = "#{description}#{i}" item.author = "#{author}#{i}" item.comments = "#{comments}#{i}" item.date = pubDate item.guid.isPermaLink = guid_isPermaLink item.guid.content = guid_content item.enclosure.url = enclosure_url item.enclosure.length = enclosure_length item.enclosure.type = enclosure_type item.source.url = source_url item.source.content = source_content category = item.categories.new_category category.domain = category_domain category.content = category_content end end end new_rss = RSS::Maker.make("2.0") do |maker| rss.channel.setup_maker(maker) rss.items.each do |item| if for_backward_compatibility item.setup_maker(maker) else item.setup_maker(maker.items) end end end assert_equal(item_size, new_rss.items.size) new_rss.items.each_with_index do |item, i| assert_equal("#{title}#{i}", item.title) assert_equal("#{link}#{i}", item.link) assert_equal("#{description}#{i}", item.description) assert_equal("#{author}#{i}", item.author) assert_equal("#{comments}#{i}", item.comments) assert_equal(pubDate, item.pubDate) assert_equal(guid_isPermaLink == "true", item.guid.isPermaLink) assert_equal(guid_content, item.guid.content) assert_equal(enclosure_url, item.enclosure.url) assert_equal(enclosure_length.to_i, item.enclosure.length) assert_equal(enclosure_type, item.enclosure.type) assert_equal(source_url, item.source.url) assert_equal(source_content, item.source.content) assert_equal(1, item.categories.size) assert_equal(category_domain, item.category.domain) assert_equal(category_content, item.category.content) end end def test_setup_maker_items_backward_compatibility test_setup_maker_items(true) end def test_setup_maker encoding = "EUC-JP" standalone = true href = 'a.xsl' type = 'text/xsl' title = 'sample' media = 'printer' charset = 'UTF-8' alternate = 'yes' rss = RSS::Maker.make("2.0") do |maker| maker.encoding = encoding maker.standalone = standalone maker.xml_stylesheets.new_xml_stylesheet do |xss| xss.href = href xss.type = type xss.title = title xss.media = media xss.charset = charset xss.alternate = alternate end setup_dummy_channel(maker) end new_rss = RSS::Maker.make("2.0") do |maker| rss.setup_maker(maker) end assert_equal("2.0", new_rss.rss_version) assert_equal(encoding, new_rss.encoding) assert_equal(standalone, new_rss.standalone) xss = rss.xml_stylesheets.first assert_equal(1, rss.xml_stylesheets.size) assert_equal(href, xss.href) assert_equal(type, xss.type) assert_equal(title, xss.title) assert_equal(media, xss.media) assert_equal(charset, xss.charset) assert_equal(alternate, xss.alternate) end end end ================================================ FILE: test/rss/test_setup_maker_atom_entry.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestSetupMakerAtomEntry < TestCase def setup t = Time.iso8601("2000-01-01T12:00:05+00:00") class << t alias_method(:to_s, :iso8601) end @dc_elems = { :title => "hoge", :description => " XML is placing increasingly heavy loads on the existing technical infrastructure of the Internet.", :creator => "Rael Dornfest (mailto:rael@oreilly.com)", :subject => "XML", :publisher => "The O'Reilly Network", :contributor => "hogehoge", :type => "fugafuga", :format => "hohoho", :identifier => "fufufu", :source => "barbar", :language => "ja", :relation => "cococo", :rights => "Copyright (c) 2000 O'Reilly & Associates, Inc.", :date => t, } end def test_setup_maker_entry(with_dc=true) authors = [ { :name => "Bob", :uri => "http://example.com/~bob/", :email => "bob@example.com", }, { :name => "Alice", :uri => "http://example.com/~alice/", :email => "alice@example.com", }, ] categories = [ { :term => "music", :label => "Music", }, { :term => "book", :scheme => "http://example.com/category/book/", :label => "Book", }, ] contributors = [ { :name => "Chris", :email => "chris@example.com", }, { :name => "Eva", :uri => "http://example.com/~eva/", }, ] id = "urn:uuid:8b105336-7e20-45fc-bb78-37fb3e1db25a" link = "http://hoge.com" published = Time.now - 60 * 3600 rights = "Copyrights (c) 2007 Alice and Bob" description = "fugafugafugafuga" title = "fugafuga" updated = Time.now feed = RSS::Maker.make("atom:entry") do |maker| maker.items.new_item do |item| authors.each do |author_info| item.authors.new_author do |author| author_info.each do |key, value| author.__send__("#{key}=", value) end end end categories.each do |category_info| item.categories.new_category do |category| category_info.each do |key, value| category.__send__("#{key}=", value) end end end contributors.each do |contributor_info| item.contributors.new_contributor do |contributor| contributor_info.each do |key, value| contributor.__send__("#{key}=", value) end end end item.id = id item.link = link item.published = published item.rights = rights item.description = description item.title = title item.updated = updated if with_dc @dc_elems.each do |var, value| if var == :date item.new_dc_date(value) else item.__send__("dc_#{var}=", value) end end end end end assert_not_nil(feed) new_feed = RSS::Maker.make("atom:entry") do |maker| feed.setup_maker(maker) end assert_not_nil(new_feed) new_authors = new_feed.authors.collect do |author| { :name => author.name.content, :uri => author.uri.content, :email => author.email.content, } end assert_equal(authors, new_authors) new_categories = new_feed.categories.collect do |category| { :term => category.term, :scheme => category.scheme, :label => category.label, }.reject {|key, value| value.nil?} end assert_equal(categories, new_categories) new_contributors = new_feed.contributors.collect do |contributor| info = {} info[:name] = contributor.name.content info[:uri] = contributor.uri.content if contributor.uri info[:email] = contributor.email.content if contributor.email info end assert_equal(contributors, new_contributors) assert_equal(id, new_feed.id.content) assert_equal(link, new_feed.link.href) assert_equal(published, new_feed.published.content) assert_equal(rights, new_feed.rights.content) assert_equal(description, new_feed.summary.content) assert_equal(title, new_feed.title.content) assert_equal(updated, new_feed.updated.content) if with_dc @dc_elems.each do |var, value| if var == :date assert_equal([updated, value], new_feed.dc_dates.collect {|date| date.value}) else assert_equal(value, new_feed.__send__("dc_#{var}")) end end end assert_equal(1, new_feed.items.size) end def test_setup_maker_entry_without_dc test_setup_maker_entry(false) end def test_setup_maker_items(for_backward_compatibility=false) title = "TITLE" link = "http://hoge.com/" description = "text hoge fuga" updated = Time.now item_size = 5 feed = RSS::Maker.make("atom:entry") do |maker| setup_dummy_channel_atom(maker) item_size.times do |i| maker.items.new_item do |item| item.title = "#{title}#{i}" item.link = "#{link}#{i}" item.description = "#{description}#{i}" item.updated = updated + i * 60 end end end new_feed = RSS::Maker.make("atom:entry") do |maker| feed.items.each do |item| if for_backward_compatibility item.setup_maker(maker) else item.setup_maker(maker.items) end end feed.items.clear feed.setup_maker(maker) end assert_equal(1, new_feed.items.size) new_feed.items[0..1].each_with_index do |item, i| assert_equal("#{title}#{i}", item.title.content) assert_equal("#{link}#{i}", item.link.href) assert_equal("#{description}#{i}", item.summary.content) assert_equal(updated + i * 60, item.updated.content) end end def test_setup_maker_items_sort title = "TITLE" link = "http://hoge.com/" summary = "text hoge fuga" updated = Time.now feed_size = 5 feed = RSS::Maker.make("atom:entry") do |maker| setup_dummy_channel_atom(maker) feed_size.times do |i| entry_class = RSS::Atom::Entry entry = entry_class.new entry.title = entry_class::Title.new(:content => "#{title}#{i}") entry.links << entry_class::Link.new(:href => "#{link}#{i}") entry.summary = entry_class::Summary.new(:content => "#{summary}#{i}") entry.updated = entry_class::Updated.new(:content => updated + i * 60) entry.setup_maker(maker.items) end maker.items.do_sort = false end assert_equal(1, feed.items.size) assert_equal("#{title}0", feed.title.content) assert_equal("#{link}0", feed.link.href) assert_equal("#{summary}0", feed.summary.content) feed = RSS::Maker.make("atom:entry") do |maker| setup_dummy_channel_atom(maker) feed_size.times do |i| entry_class = RSS::Atom::Entry entry = entry_class.new entry.title = entry_class::Title.new(:content => "#{title}#{i}") entry.links << entry_class::Link.new(:href => "#{link}#{i}") entry.summary = entry_class::Summary.new(:content => "#{summary}#{i}") entry.updated = entry_class::Updated.new(:content => updated + i * 60) entry.setup_maker(maker.items) end maker.items.do_sort = true end assert_equal(1, feed.items.size) assert_equal("#{title}#{feed_size - 1}", feed.title.content) assert_equal("#{link}#{feed_size - 1}", feed.link.href) assert_equal("#{summary}#{feed_size - 1}", feed.summary.content) end def test_setup_maker_items_backward_compatibility test_setup_maker_items(true) end def test_setup_maker encoding = "EUC-JP" standalone = true href = 'a.xsl' type = 'text/xsl' title = 'sample' media = 'printer' charset = 'UTF-8' alternate = 'yes' feed = RSS::Maker.make("atom:entry") do |maker| maker.encoding = encoding maker.standalone = standalone maker.xml_stylesheets.new_xml_stylesheet do |xss| xss.href = href xss.type = type xss.title = title xss.media = media xss.charset = charset xss.alternate = alternate end setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end assert_not_nil(feed) new_feed = RSS::Maker.make("atom:entry") do |maker| feed.setup_maker(maker) end assert_equal(["atom", "1.0", "entry"], new_feed.feed_info) assert_equal(encoding, new_feed.encoding) assert_equal(standalone, new_feed.standalone) xss = new_feed.xml_stylesheets.first assert_equal(1, new_feed.xml_stylesheets.size) assert_equal(href, xss.href) assert_equal(type, xss.type) assert_equal(title, xss.title) assert_equal(media, xss.media) assert_equal(charset, xss.charset) assert_equal(alternate, xss.alternate) end def test_setup_maker_full encoding = "EUC-JP" standalone = true href = 'a.xsl' type = 'text/xsl' title = 'sample' media = 'printer' charset = 'UTF-8' alternate = 'yes' channel_about = "http://hoge.com" channel_title = "fugafuga" channel_link = "http://hoge.com" channel_description = "fugafugafugafuga" channel_author = "Bob" image_url = "http://hoge.com/hoge.png" item_title = "TITLE" item_link = "http://hoge.com/" item_description = "text hoge fuga" entry_size = 5 feed = RSS::Maker.make("atom:entry") do |maker| maker.encoding = encoding maker.standalone = standalone maker.xml_stylesheets.new_xml_stylesheet do |xss| xss.href = href xss.type = type xss.title = title xss.media = media xss.charset = charset xss.alternate = alternate end maker.channel.about = channel_about maker.channel.title = channel_title maker.channel.link = channel_link maker.channel.description = channel_description maker.channel.author = channel_author @dc_elems.each do |var, value| maker.channel.__send__("dc_#{var}=", value) end maker.image.url = image_url entry_size.times do |i| maker.items.new_item do |item| item.title = "#{item_title}#{i}" item.link = "#{item_link}#{i}" item.description = "#{item_description}#{i}" @dc_elems.each do |var, value| item.__send__("dc_#{var}=", value) end end end end new_feed = RSS::Maker.make("atom:entry") do |maker| feed.setup_maker(maker) end assert_equal(["atom", "1.0", "entry"], new_feed.feed_info) assert_equal(encoding, new_feed.encoding) assert_equal(standalone, new_feed.standalone) xss = new_feed.xml_stylesheets.first assert_equal(1, new_feed.xml_stylesheets.size) assert_equal(href, xss.href) assert_equal(type, xss.type) assert_equal(title, xss.title) assert_equal(media, xss.media) assert_equal(charset, xss.charset) assert_equal(alternate, xss.alternate) assert_equal("#{item_title}0", new_feed.title.content) assert_equal("#{item_link}0", new_feed.link.href) assert_equal("#{item_description}0", new_feed.summary.content) @dc_elems.each do |var, value| assert_equal(value, new_feed.__send__("dc_#{var}")) end assert_equal(1, new_feed.items.size) end end end ================================================ FILE: test/rss/test_setup_maker_atom_feed.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestSetupMakerAtomFeed < TestCase def setup t = Time.iso8601("2000-01-01T12:00:05+00:00") class << t alias_method(:to_s, :iso8601) end @dc_elems = { :title => "hoge", :description => " XML is placing increasingly heavy loads on the existing technical infrastructure of the Internet.", :creator => "Rael Dornfest (mailto:rael@oreilly.com)", :subject => "XML", :publisher => "The O'Reilly Network", :contributor => "hogehoge", :type => "fugafuga", :format => "hohoho", :identifier => "fufufu", :source => "barbar", :language => "ja", :relation => "cococo", :rights => "Copyright (c) 2000 O'Reilly & Associates, Inc.", :date => t, } end def test_setup_maker_feed(with_dc=true) authors = [ { :name => "Bob", :uri => "http://example.com/~bob/", :email => "bob@example.com", }, { :name => "Alice", :uri => "http://example.com/~alice/", :email => "alice@example.com", }, ] categories = [ { :term => "music", :label => "Music", }, { :term => "book", :scheme => "http://example.com/category/book/", :label => "Book", }, ] contributors = [ { :name => "Chris", :email => "chris@example.com", }, { :name => "Eva", :uri => "http://example.com/~eva/", }, ] generator = { :uri => "http://example.com/generator/", :version => "0.0.1", :content => "Feed Generator", } icon = "http://example.com/icon.png" about = "http://hoge.com" title = "fugafuga" link = "http://hoge.com" logo = "http://example.com/logo.png" rights = "Copyrights (c) 2007 Alice and Bob" description = "fugafugafugafuga" updated = Time.now feed = RSS::Maker.make("atom") do |maker| authors.each do |author_info| maker.channel.authors.new_author do |author| author_info.each do |key, value| author.__send__("#{key}=", value) end end end categories.each do |category_info| maker.channel.categories.new_category do |category| category_info.each do |key, value| category.__send__("#{key}=", value) end end end contributors.each do |contributor_info| maker.channel.contributors.new_contributor do |contributor| contributor_info.each do |key, value| contributor.__send__("#{key}=", value) end end end generator.each do |key, value| maker.channel.generator do |g| g.__send__("#{key}=", value) end end maker.channel.icon = icon maker.channel.about = about maker.channel.link = link maker.channel.logo = logo maker.channel.rights = rights maker.channel.title = title maker.channel.description = description maker.channel.updated = updated if with_dc @dc_elems.each do |var, value| if var == :date maker.channel.new_dc_date(value) else maker.channel.__send__("dc_#{var}=", value) end end end setup_dummy_item_atom(maker) end assert_not_nil(feed) new_feed = RSS::Maker.make("atom") do |maker| feed.setup_maker(maker) end assert_not_nil(new_feed) new_authors = new_feed.authors.collect do |author| { :name => author.name.content, :uri => author.uri.content, :email => author.email.content, } end assert_equal(authors, new_authors) new_categories = new_feed.categories.collect do |category| { :term => category.term, :scheme => category.scheme, :label => category.label, }.reject {|key, value| value.nil?} end assert_equal(categories, new_categories) new_contributors = new_feed.contributors.collect do |contributor| info = {} info[:name] = contributor.name.content info[:uri] = contributor.uri.content if contributor.uri info[:email] = contributor.email.content if contributor.email info end assert_equal(contributors, new_contributors) new_generator = { :uri => new_feed.generator.uri, :version => new_feed.generator.version, :content => new_feed.generator.content, } assert_equal(generator, new_generator) assert_equal(icon, new_feed.icon.content) assert_equal(about, new_feed.id.content) assert_equal(link, new_feed.link.href) assert_equal(logo, new_feed.logo.content) assert_equal(rights, new_feed.rights.content) assert_equal(description, new_feed.subtitle.content) assert_equal(title, new_feed.title.content) assert_equal(updated, new_feed.updated.content) if with_dc @dc_elems.each do |var, value| if var == :date assert_equal([updated, value], new_feed.dc_dates.collect {|date| date.value}) else assert_equal(value, new_feed.__send__("dc_#{var}")) end end end assert_equal(1, new_feed.items.size) end def test_setup_maker_feed_without_dc test_setup_maker_feed(false) end def test_setup_maker_items(for_backward_compatibility=false) title = "TITLE" link = "http://hoge.com/" description = "text hoge fuga" updated = Time.now item_size = 5 feed = RSS::Maker.make("atom") do |maker| setup_dummy_channel_atom(maker) item_size.times do |i| maker.items.new_item do |item| item.title = "#{title}#{i}" item.link = "#{link}#{i}" item.description = "#{description}#{i}" item.updated = updated + i * 60 end end end new_feed = RSS::Maker.make("atom") do |maker| feed.items.each do |item| if for_backward_compatibility item.setup_maker(maker) else item.setup_maker(maker.items) end end feed.items.clear feed.setup_maker(maker) end assert_equal(item_size, new_feed.items.size) new_feed.items.each_with_index do |item, i| assert_equal("#{title}#{i}", item.title.content) assert_equal("#{link}#{i}", item.link.href) assert_equal("#{description}#{i}", item.summary.content) assert_equal(updated + i * 60, item.updated.content) end end def test_setup_maker_items_sort title = "TITLE" link = "http://hoge.com/" summary = "text hoge fuga" updated = Time.now feed_size = 5 feed = RSS::Maker.make("atom") do |maker| setup_dummy_channel_atom(maker) feed_size.times do |i| entry_class = RSS::Atom::Feed::Entry entry = entry_class.new entry.title = entry_class::Title.new(:content => "#{title}#{i}") entry.links << entry_class::Link.new(:href => "#{link}#{i}") entry.summary = entry_class::Summary.new(:content => "#{summary}#{i}") entry.updated = entry_class::Updated.new(:content => updated + i * 60) entry.setup_maker(maker.items) end maker.items.do_sort = false end assert_equal(feed_size, feed.entries.size) feed.entries.each_with_index do |entry, i| assert_equal("#{title}#{i}", entry.title.content) assert_equal("#{link}#{i}", entry.link.href) assert_equal("#{summary}#{i}", entry.summary.content) end feed = RSS::Maker.make("atom") do |maker| setup_dummy_channel_atom(maker) feed_size.times do |i| entry_class = RSS::Atom::Feed::Entry entry = entry_class.new entry.title = entry_class::Title.new(:content => "#{title}#{i}") entry.links << entry_class::Link.new(:href => "#{link}#{i}") entry.summary = entry_class::Summary.new(:content => "#{summary}#{i}") entry.updated = entry_class::Updated.new(:content => updated + i * 60) entry.setup_maker(maker.items) end maker.items.do_sort = true end assert_equal(feed_size, feed.entries.size) feed.entries.reverse.each_with_index do |entry, i| assert_equal("#{title}#{i}", entry.title.content) assert_equal("#{link}#{i}", entry.link.href) assert_equal("#{summary}#{i}", entry.summary.content) end end def test_setup_maker_items_backward_compatibility test_setup_maker_items(true) end def test_setup_maker encoding = "EUC-JP" standalone = true href = 'a.xsl' type = 'text/xsl' title = 'sample' media = 'printer' charset = 'UTF-8' alternate = 'yes' feed = RSS::Maker.make("atom") do |maker| maker.encoding = encoding maker.standalone = standalone maker.xml_stylesheets.new_xml_stylesheet do |xss| xss.href = href xss.type = type xss.title = title xss.media = media xss.charset = charset xss.alternate = alternate end setup_dummy_channel_atom(maker) setup_dummy_item_atom(maker) end assert_not_nil(feed) new_feed = RSS::Maker.make("atom") do |maker| feed.setup_maker(maker) end assert_equal(["atom", "1.0", "feed"], new_feed.feed_info) assert_equal(encoding, new_feed.encoding) assert_equal(standalone, new_feed.standalone) xss = new_feed.xml_stylesheets.first assert_equal(1, new_feed.xml_stylesheets.size) assert_equal(href, xss.href) assert_equal(type, xss.type) assert_equal(title, xss.title) assert_equal(media, xss.media) assert_equal(charset, xss.charset) assert_equal(alternate, xss.alternate) end def test_setup_maker_full encoding = "EUC-JP" standalone = true href = 'a.xsl' type = 'text/xsl' title = 'sample' media = 'printer' charset = 'UTF-8' alternate = 'yes' channel_about = "http://hoge.com" channel_title = "fugafuga" channel_link = "http://hoge.com" channel_description = "fugafugafugafuga" channel_author = "Bob" image_url = "http://hoge.com/hoge.png" item_title = "TITLE" item_link = "http://hoge.com/" item_description = "text hoge fuga" entry_size = 5 feed = RSS::Maker.make("atom") do |maker| maker.encoding = encoding maker.standalone = standalone maker.xml_stylesheets.new_xml_stylesheet do |xss| xss.href = href xss.type = type xss.title = title xss.media = media xss.charset = charset xss.alternate = alternate end maker.channel.about = channel_about maker.channel.title = channel_title maker.channel.link = channel_link maker.channel.description = channel_description maker.channel.author = channel_author @dc_elems.each do |var, value| maker.channel.__send__("dc_#{var}=", value) end maker.image.url = image_url entry_size.times do |i| maker.items.new_item do |item| item.title = "#{item_title}#{i}" item.link = "#{item_link}#{i}" item.description = "#{item_description}#{i}" @dc_elems.each do |var, value| item.__send__("dc_#{var}=", value) end end end end new_feed = RSS::Maker.make("atom") do |maker| feed.setup_maker(maker) end assert_equal(["atom", "1.0", "feed"], new_feed.feed_info) assert_equal(encoding, new_feed.encoding) assert_equal(standalone, new_feed.standalone) xss = new_feed.xml_stylesheets.first assert_equal(1, new_feed.xml_stylesheets.size) assert_equal(href, xss.href) assert_equal(type, xss.type) assert_equal(title, xss.title) assert_equal(media, xss.media) assert_equal(charset, xss.charset) assert_equal(alternate, xss.alternate) assert_equal(channel_title, new_feed.title.content) assert_equal(channel_link, new_feed.link.href) assert_equal(channel_description, new_feed.subtitle.content) assert_equal(channel_author, new_feed.author.name.content) assert_equal(image_url, new_feed.logo.content) @dc_elems.each do |var, value| assert_equal(value, new_feed.__send__("dc_#{var}")) end assert_equal(entry_size, new_feed.entries.size) new_feed.entries.each_with_index do |entry, i| assert_equal("#{item_title}#{i}", entry.title.content) assert_equal("#{item_link}#{i}", entry.link.href) assert_equal("#{item_description}#{i}", entry.summary.content) @dc_elems.each do |var, value| assert_equal(value, entry.__send__("dc_#{var}")) end end end end end ================================================ FILE: test/rss/test_setup_maker_itunes.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestSetupMakerITunes < TestCase def test_setup_maker_simple author = "John Doe" block = true categories = ["Audio Blogs"] image = "http://example.com/podcasts/everything/AllAboutEverything.jpg" duration = "4:05" duration_components = [0, 4, 5] explicit = true keywords = ["salt", "pepper", "shaker", "exciting"] new_feed_url = "http://newlocation.com/example.rss" owner = {:name => "John Doe", :email => "john.doe@example.com"} subtitle = "A show about everything" summary = "All About Everything is a show about " + "everything. Each week we dive into any " + "subject known to man and talk about it " + "as much as we can. Look for our Podcast " + "in the iTunes Music Store" feed = RSS::Maker.make("rss2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) channel = maker.channel channel.itunes_author = author channel.itunes_block = block categories.each do |category| channel.itunes_categories.new_category.text = category end channel.itunes_image = image channel.itunes_explicit = explicit channel.itunes_keywords = keywords channel.itunes_owner.itunes_name = owner[:name] channel.itunes_owner.itunes_email = owner[:email] channel.itunes_subtitle = subtitle channel.itunes_summary = summary item = maker.items.last item.itunes_author = author item.itunes_block = block item.itunes_duration = duration item.itunes_explicit = explicit item.itunes_keywords = keywords item.itunes_subtitle = subtitle item.itunes_summary = summary end assert_not_nil(feed) new_feed = RSS::Maker.make("rss2.0") do |maker| feed.setup_maker(maker) end assert_not_nil(new_feed) channel = new_feed.channel item = new_feed.items.last assert_equal(author, channel.itunes_author) assert_equal(author, item.itunes_author) assert_equal(block, channel.itunes_block?) assert_equal(block, item.itunes_block?) assert_equal(categories, collect_itunes_categories(channel.itunes_categories)) assert_equal(image, channel.itunes_image.href) assert_equal(duration_components, [item.itunes_duration.hour, item.itunes_duration.minute, item.itunes_duration.second]) assert_equal(explicit, channel.itunes_explicit?) assert_equal(explicit, item.itunes_explicit?) assert_equal(keywords, channel.itunes_keywords) assert_equal(keywords, item.itunes_keywords) assert_equal(owner, { :name => channel.itunes_owner.itunes_name, :email => channel.itunes_owner.itunes_email }) assert_equal(subtitle, channel.itunes_subtitle) assert_equal(subtitle, item.itunes_subtitle) assert_equal(summary, channel.itunes_summary) assert_equal(summary, item.itunes_summary) end def test_setup_maker_with_nested_categories categories = [["Arts & Entertainment", "Games"], ["Technology", "Computers"], "Audio Blogs"] feed = RSS::Maker.make("rss2.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) channel = maker.channel categories.each do |category| target = channel.itunes_categories if category.is_a?(Array) category.each do |sub_category| target = target.new_category target.text = sub_category end else target.new_category.text = category end end end assert_not_nil(feed) new_feed = RSS::Maker.make("rss2.0") do |maker| feed.setup_maker(maker) end assert_not_nil(new_feed) channel = new_feed.channel assert_equal(categories, collect_itunes_categories(channel.itunes_categories)) end private def collect_itunes_categories(categories) categories.collect do |c| rest = collect_itunes_categories(c.itunes_categories) if rest.empty? c.text else [c.text, *rest] end end end end end ================================================ FILE: test/rss/test_setup_maker_slash.rb ================================================ require "rss-testcase" require "rss/maker" module RSS class TestSetupMakerSlash < TestCase def test_setup_maker elements = { "section" => "articles", "department" => "not-an-ocean-unless-there-are-lobsters", "comments" => 177, "hit_parades" => [177, 155, 105, 33, 6, 3, 0], } rss = RSS::Maker.make("rss1.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) item = maker.items.last item.slash_section = elements["section"] item.slash_department = elements["department"] item.slash_comments = elements["comments"] item.slash_hit_parade = elements["hit_parades"].join(",") end assert_not_nil(rss) new_rss = RSS::Maker.make("rss1.0") do |maker| rss.setup_maker(maker) end assert_not_nil(new_rss) item = new_rss.items.last assert_not_nil(item) assert_slash_elements(elements, item) end end end ================================================ FILE: test/rss/test_slash.rb ================================================ require "cgi" require "rexml/document" require "rss-testcase" require "rss/1.0" require "rss/slash" module RSS class TestSlash < TestCase def setup @elements = { "section" => "articles", "department" => "not-an-ocean-unless-there-are-lobsters", "comments" => 177, "hit_parades" => [177, 155, 105, 33, 6, 3, 0], } slash_nodes = @elements.collect do |name, value| if name == "hit_parades" name = "hit_parade" value = value.join(",") end "#{value}" end.join("\n") slash_ns = {"slash" => "http://purl.org/rss/1.0/modules/slash/"} @source = make_RDF(<<-EOR, slash_ns) #{make_channel} #{make_image} #{make_item(slash_nodes)} #{make_textinput} EOR end def test_parser rss = RSS::Parser.parse(@source) assert_not_nil(rss) item = rss.items[0] assert_not_nil(item) assert_slash_elements(item) end def test_to_s rss = RSS::Parser.parse(@source) rss = RSS::Parser.parse(rss.to_s) assert_not_nil(rss) item = rss.items[0] assert_not_nil(item) assert_slash_elements(item) end private def assert_slash_elements(target) super(@elements, target) end end end ================================================ FILE: test/rss/test_syndication.rb ================================================ require "cgi" require "rexml/document" require "rss-testcase" require "rss/1.0" require "rss/syndication" module RSS class TestSyndication < TestCase def setup @prefix = "sy" @uri = "http://purl.org/rss/1.0/modules/syndication/" @parents = %w(channel) t = Time.iso8601("2000-01-01T12:00:05+00:00") class << t alias_method(:to_s, :iso8601) end @elems = { :updatePeriod => "hourly", :updateFrequency => "2", :updateBase => t, } @sy_nodes = @elems.collect do |name, value| "<#{@prefix}:#{name}>#{CGI.escapeHTML(value.to_s)}" end.join("\n") @rss_source = make_RDF(<<-EOR, {@prefix => @uri}) #{make_channel(@sy_nodes)} #{make_image()} #{make_item()} #{make_textinput()} EOR @rss = Parser.parse(@rss_source) end def test_parser assert_nothing_raised do Parser.parse(@rss_source) end @elems.each do |tag, value| assert_too_much_tag(tag.to_s, "channel") do Parser.parse(make_RDF(<<-EOR, {@prefix => @uri})) #{make_channel(("<" + @prefix + ":" + tag.to_s + ">" + CGI.escapeHTML(value.to_s) + "") * 2)} #{make_item} EOR end end end def test_accessor t = Time.iso8601("2003-01-01T12:00:23+09:00") class << t alias_method(:to_s, :iso8601) end new_value = { :updatePeriod => "daily", :updateFrequency => "11", :updateBase => t, } @elems.each do |name, value| value = value.to_i if name == :updateFrequency @parents.each do |parent| assert_equal(value, @rss.__send__(parent).__send__("sy_#{name}")) @rss.__send__(parent).__send__("sy_#{name}=", new_value[name]) new_val = new_value[name] new_val = new_val.to_i if name == :updateFrequency assert_equal(new_val, @rss.__send__(parent).__send__("sy_#{name}")) end end %w(hourly daily weekly monthly yearly).each do |x| @parents.each do |parent| assert_nothing_raised do @rss.__send__(parent).sy_updatePeriod = x end end end %w(-2 0.3 -0.4).each do |x| @parents.each do |parent| assert_not_available_value("sy:updateBase", x) do @rss.__send__(parent).sy_updateBase = x end end end end def test_to_s @elems.each do |name, value| excepted = "<#{@prefix}:#{name}>#{value}" @parents.each do |parent| assert_equal(excepted, @rss.__send__(parent).__send__("sy_#{name}_element")) end end REXML::Document.new(@rss_source).root.each_element do |parent| if @parents.include?(parent.name) parent.each_element do |elem| if elem.namespace == @uri assert_equal(elem.text, @elems[elem.name.intern].to_s) end end end end end end end ================================================ FILE: test/rss/test_taxonomy.rb ================================================ require "cgi" require "rss-testcase" require "rss/1.0" require "rss/2.0" require "rss/taxonomy" module RSS class TestTaxonomy < TestCase def setup @prefix = "taxo" @uri = "http://purl.org/rss/1.0/modules/taxonomy/" @dc_prefix = "dc" @dc_uri = "http://purl.org/dc/elements/1.1/" @ns = { @prefix => @uri, @dc_prefix => @dc_uri, } @topics_parents = %w(channel item) @topics_lis = [ "http://meerkat.oreillynet.com/?c=cat23", "http://meerkat.oreillynet.com/?c=47", "http://dmoz.org/Computers/Data_Formats/Markup_Languages/XML/", ] @topics_node = "<#{@prefix}:topics>\n" @topics_node << " \n" @topics_lis.each do |value| resource = CGI.escapeHTML(value) @topics_node << " \n" end @topics_node << " \n" @topics_node << "" @topic_topics_lis = \ [ "http://meerkat.oreillynet.com/?c=cat23", "http://dmoz.org/Computers/Data_Formats/Markup_Languages/SGML/", "http://dmoz.org/Computers/Programming/Internet/", ] @topic_contents = \ [ { :link => "http://meerkat.oreillynet.com/?c=cat23", :title => "Data: XML", :description => "A Meerkat channel", }, { :link => "http://dmoz.org/Computers/Data_Formats/Markup_Languages/XML/", :title => "XML", :subject => "XML", :description => "DMOZ category", :topics => @topic_topics_lis, } ] @topic_nodes = @topic_contents.collect do |info| link = info[:link] rv = "<#{@prefix}:topic rdf:about=\"#{link}\">\n" info.each do |name, value| case name when :topics rv << " <#{@prefix}:topics>\n" rv << " \n" value.each do |li| resource = CGI.escapeHTML(li) rv << " \n" end rv << " \n" rv << " \n" else prefix = (name == :link ? @prefix : @dc_prefix) rv << " <#{prefix}:#{name}>#{value}\n" end end rv << "" end @rss_source = make_RDF(<<-EOR, @ns) #{make_channel(@topics_node)} #{make_image()} #{make_item(@topics_node)} #{make_textinput()} #{@topic_nodes.join("\n")} EOR @rss = Parser.parse(@rss_source) end def test_parser assert_nothing_raised do Parser.parse(@rss_source) end assert_too_much_tag("topics", "channel") do Parser.parse(make_RDF(<<-EOR, @ns)) #{make_channel(@topics_node * 2)} #{make_item()} EOR end assert_too_much_tag("topics", "item") do Parser.parse(make_RDF(<<-EOR, @ns)) #{make_channel()} #{make_item(@topics_node * 2)} EOR end end def test_accessor topics = @rss.channel.taxo_topics assert_equal(@topics_lis.sort, topics.Bag.lis.collect {|li| li.resource}.sort) assert_equal(@topics_lis.sort, topics.resources.sort) assert_equal(@rss.taxo_topics.first, @rss.taxo_topic) @topic_contents.each_with_index do |info, i| topic = @rss.taxo_topics[i] info.each do |name, value| case name when :link assert_equal(value, topic.about) assert_equal(value, topic.taxo_link) when :topics assert_equal(value.sort, topic.taxo_topics.resources.sort) else assert_equal(value, topic.__send__("dc_#{name}")) end end end end def test_to_s @topics_parents.each do |parent| meth = "taxo_topics_element" assert_equal(@topics_node, @rss.__send__(parent).__send__(meth)) end @topic_nodes.each_with_index do |node, i| expected_xml = taxo_xmlns_container(node) expected = REXML::Document.new(expected_xml).root.elements[1] actual_xml = taxo_xmlns_container(@rss.taxo_topics[i].to_s(true, "")) actual = REXML::Document.new(actual_xml).root.elements[1] expected_elems = expected.reject {|x| x.is_a?(REXML::Text)} actual_elems = actual.reject {|x| x.is_a?(REXML::Text)} expected_elems.sort! {|x, y| x.name <=> y.name} actual_elems.sort! {|x, y| x.name <=> y.name} assert_equal(expected_elems.collect {|x| x.to_s}, actual_elems.collect {|x| x.to_s}) assert_equal(expected.attributes.sort, actual.attributes.sort) end end private def taxo_xmlns_container(content) xmlns_container({ @prefix => @uri, "dc" => "http://purl.org/dc/elements/1.1/", "rdf" => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", }, content) end end end ================================================ FILE: test/rss/test_to_s.rb ================================================ require "rexml/document" require "rss-testcase" require "rss/maker" require "rss/1.0" require "rss/2.0" require "rss/content" require "rss/dublincore" require "rss/syndication" require "rss/trackback" module RSS class TestToS < TestCase def setup @image_url = "http://example.com/foo.png" @textinput_link = "http://example.com/search.cgi" @item_links = [ "http://example.com/1", "http://example.com/2", ] setup_xml_declaration_info setup_xml_stylesheet_infos setup_channel_info setup_item_infos setup_image_info setup_textinput_info setup_dublin_core_info setup_syndication_info setup_content_info setup_trackback_info end def test_to_s_10 rss = RSS::Maker.make("1.0") do |maker| setup_full(maker) end assert_xml_declaration(@version, @encoding, @standalone, rss) assert_xml_stylesheets(@xs_infos, rss.xml_stylesheets) assert_channel10(@channel_info, rss.channel) assert_items10(@item_infos, rss.items) rss.items.each do |item| assert_trackback(@trackback_info, item) end assert_image10(@image_info, rss.image) assert_textinput10(@textinput_info, rss.textinput) rss = RSS::Parser.parse(rss.to_s) assert_xml_declaration(@version, @encoding, @standalone, rss) assert_xml_stylesheets(@xs_infos, rss.xml_stylesheets) assert_channel10(@channel_info, rss.channel) assert_items10(@item_infos, rss.items) assert_image10(@image_info, rss.image) assert_textinput10(@textinput_info, rss.textinput) end def test_to_s_09 rss = RSS::Maker.make("0.91") do |maker| setup_full(maker) end assert_xml_declaration(@version, @encoding, @standalone, rss) assert_xml_stylesheets(@xs_infos, rss.xml_stylesheets) assert_channel09(@channel_info, rss.channel) assert_items09(@item_infos, rss.items) assert_image09(@image_info, rss.image) assert_textinput09(@textinput_info, rss.textinput) rss = RSS::Parser.parse(rss.to_s) assert_xml_declaration(@version, @encoding, @standalone, rss) assert_xml_stylesheets(@xs_infos, rss.xml_stylesheets) assert_channel09(@channel_info, rss.channel) assert_items09(@item_infos, rss.items) assert_image09(@image_info, rss.image) assert_textinput09(@textinput_info, rss.textinput) end def test_to_s_20 rss = RSS::Maker.make("2.0") do |maker| setup_full(maker) end assert_xml_declaration(@version, @encoding, @standalone, rss) assert_xml_stylesheets(@xs_infos, rss.xml_stylesheets) assert_channel20(@channel_info, rss.channel) assert_items20(@item_infos, rss.items) assert_image20(@image_info, rss.image) assert_textinput20(@textinput_info, rss.textinput) rss = RSS::Parser.parse(rss.to_s) assert_xml_declaration(@version, @encoding, @standalone, rss) assert_xml_stylesheets(@xs_infos, rss.xml_stylesheets) assert_channel20(@channel_info, rss.channel) assert_items20(@item_infos, rss.items) assert_image20(@image_info, rss.image) assert_textinput20(@textinput_info, rss.textinput) end private def setup_xml_declaration_info @version = "1.0" @encoding = "UTF-8" @standalone = false end def setup_xml_stylesheet_infos @xs_infos = [ { "href" => "XXX.xsl", "type" => "text/xsl", "title" => "XXX", "media" => "print", "alternate" => "no", }, { "href" => "YYY.css", "type" => "text/css", "title" => "YYY", "media" => "all", "alternate" => "no", }, ] end def setup_channel_info @channel_info = { "about" => "http://example.com/index.rdf", "title" => "Sample RSS", "link" => "http://example.com/", "description" => "Sample\n\n\n\n\nSite", "language" => "en", "copyright" => "FDL", "managingEditor" => "foo@example.com", "webMaster" => "webmaster@example.com", "rating" => '(PICS-1.1 "http://www.rsac.org/ratingsv01.html" l gen true comment "RSACi North America Server" for "http://www.rsac.org" on "1996.04.16T08:15-0500" r (n 0 s 0 v 0 l 0))', "docs" => "http://backend.userland.com/rss091", "skipDays" => [ "Monday", "Friday", ], "skipHours" => [ "12", "23", ], "date" => Time.now, "lastBuildDate" => Time.now - 3600, "generator" => "RSS Maker", "ttl" => "60", "cloud" => { "domain" => "rpc.sys.com", "port" => "80", "path" => "/RPC2", "registerProcedure" => "myCloud.rssPleaseNotify", "protocol" => "xml-rpc", }, "category" => { "domain" => "http://example.com/misc/", "content" => "misc", }, "image" => { "resource" => @image_url, }, "textinput" => { "resource" => @textinput_link, }, "items" => @item_links.collect{|link| {"resource" => link}}, } end def setup_item_infos @item_infos = [ { "title" => "Sample item1", "link" => @item_links[0], "description" => "Sample description1", "date" => Time.now - 3600, "author" => "foo@example.com", "comments" => "http://example.com/1/comments", "guid" => { "isPermaLink" => "true", "content" => "http://example.com/1", }, "enclosure" => { "url" => "http://example.com/1.mp3", "length" => "100", "type" => "audio/mpeg", }, "source" => { "url" => "http:/example.com/", "content" => "Sample site", }, "category" => { "domain" => "http://example.com/misc/", "content" => "misc", }, }, { "title" => "Sample item2", "link" => @item_links[1], "description" => "Sample description2", "date" => Time.now - 7200, "author" => "foo@example.com", "comments" => "http://example.com/2/comments", "guid" => { "isPermaLink" => "false", "content" => "http://example.com/2", }, "enclosure" => { "url" => "http://example.com/2.mp3", "length" => "200", "type" => "audio/mpeg", }, "source" => { "url" => "http:/example.com/", "content" => "Sample site", }, "category" => { "domain" => "http://example.com/misc/", "content" => "misc", }, }, ] end def setup_image_info @image_info = { "title" => "Sample image", "url" => @image_url, "width" => "88", "height" => "31", "description" => "Sample", } end def setup_textinput_info @textinput_info = { "title" => "Sample textinput", "description" => "Search", "name" => "key", "link" => @textinput_link, } end def setup_dublin_core_info @dc_info = { "title" => "DC title", "description" => "DC desc", "creator" => "DC creator", "subject" => "DC subject", "publisher" => "DC publisher", "contributor" => "DC contributor", "type" => "DC type", "format" => "DC format", "identifier" => "DC identifier", "source" => "DC source", "language" => "ja", "relation" => "DC relation", "coverage" => "DC coverage", "rights" => "DC rights", "date" => Time.now - 60, } end def setup_syndication_info @sy_info = { "updatePeriod" => "hourly", "updateFrequency" => "2", "updateBase" => Time.now - 3600, } end def setup_content_info @content_info = { "encoded" => "

      p

      ", } end def setup_trackback_info @trackback_info = { "ping" => "http://example.com/tb.cgi?tb_id=XXX", "abouts" => [ "http://example.net/tb.cgi?tb_id=YYY", "http://example.org/tb.cgi?tb_id=ZZZ", ] } end def setup_full(maker) setup_xml_declaration(maker) setup_xml_stylesheets(maker) setup_channel(maker) setup_image(maker) setup_items(maker) setup_textinput(maker) end def setup_xml_declaration(maker) %w(version encoding standalone).each do |name| maker.__send__("#{name}=", instance_eval("@#{name}")) end end def setup_xml_stylesheets(maker) @xs_infos.each do |info| xs = maker.xml_stylesheets.new_xml_stylesheet info.each do |name, value| xs.__send__("#{name}=", value) end end end def setup_channel(maker) channel = maker.channel info = @channel_info %w(about title link description language copyright managingEditor webMaster rating docs date lastBuildDate generator ttl).each do |name| channel.__send__("#{name}=", info[name]) end skipDays = channel.skipDays info["skipDays"].each do |day| new_day = skipDays.new_day new_day.content = day end skipHours = channel.skipHours info["skipHours"].each do |hour| new_hour = skipHours.new_hour new_hour.content = hour end cloud = channel.cloud %w(domain port path registerProcedure protocol).each do |name| cloud.__send__("#{name}=", info["cloud"][name]) end category = channel.categories.new_category %w(domain content).each do |name| category.__send__("#{name}=", info["category"][name]) end end def setup_image(maker) image = maker.image info = @image_info %w(title url width height description).each do |name| image.__send__("#{name}=", info[name]) end end def setup_items(maker) items = maker.items @item_infos.each do |info| item = items.new_item %w(title link description date author comments).each do |name| item.__send__("#{name}=", info[name]) end guid = item.guid %w(isPermaLink content).each do |name| guid.__send__("#{name}=", info["guid"][name]) end enclosure = item.enclosure %w(url length type).each do |name| enclosure.__send__("#{name}=", info["enclosure"][name]) end source = item.source %w(url content).each do |name| source.__send__("#{name}=", info["source"][name]) end category = item.categories.new_category %w(domain content).each do |name| category.__send__("#{name}=", info["category"][name]) end setup_trackback(item) end end def setup_textinput(maker) textinput = maker.textinput info = @textinput_info %w(title description name link).each do |name| textinput.__send__("#{name}=", info[name]) end end def setup_content(target) prefix = "content" %w(encoded).each do |name| target.__send__("#{prefix}_#{name}=", @content_info[name]) end end def setup_dublin_core(target) prefix = "dc" %w(title description creator subject publisher contributor type format identifier source language relation coverage rights).each do |name| target.__send__("#{prefix}_#{name}=", @dc_info[name]) end end def setup_syndicate(target) prefix = "sy" %w(updatePeriod updateFrequency updateBase).each do |name| target.__send__("#{prefix}_#{name}=", @sy_info[name]) end end def setup_trackback(target) target.trackback_ping = @trackback_info["ping"] @trackback_info["abouts"].each do |about| new_about = target.trackback_abouts.new_about new_about.value = about end end def assert_channel10(attrs, channel) _wrap_assertion do n_attrs = normalized_attrs(attrs) names = %w(about title link description) assert_attributes(attrs, names, channel) %w(image items textinput).each do |name| value = n_attrs[name] if value target = channel.__send__(name) __send__("assert_channel10_#{name}", value, target) end end end end def assert_channel10_image(attrs, image) _wrap_assertion do assert_attributes(attrs, %w(resource), image) end end def assert_channel10_textinput(attrs, textinput) _wrap_assertion do assert_attributes(attrs, %w(resource), textinput) end end def assert_channel10_items(attrs, items) _wrap_assertion do assert_equal(items.resources, items.Seq.lis.collect {|x| x.resource}) items.Seq.lis.each_with_index do |li, i| assert_attributes(attrs[i], %w(resource), li) end end end def assert_image10(attrs, image) _wrap_assertion do names = %w(about title url link) assert_attributes(attrs, names, image) end end def assert_items10(attrs, items) _wrap_assertion do names = %w(about title link description) items.each_with_index do |item, i| assert_attributes(attrs[i], names, item) end end end def assert_textinput10(attrs, textinput) _wrap_assertion do names = %w(about title description name link) assert_attributes(attrs, names, textinput) end end def assert_channel09(attrs, channel) _wrap_assertion do n_attrs = normalized_attrs(attrs) names = %w(title description link language rating copyright pubDate lastBuildDate docs managingEditor webMaster) assert_attributes(attrs, names, channel) %w(skipHours skipDays).each do |name| value = n_attrs[name] if value target = channel.__send__(name) __send__("assert_channel09_#{name}", value, target) end end end end def assert_channel09_skipDays(contents, skipDays) _wrap_assertion do days = skipDays.days contents.each_with_index do |content, i| assert_equal(content, days[i].content) end end end def assert_channel09_skipHours(contents, skipHours) _wrap_assertion do hours = skipHours.hours contents.each_with_index do |content, i| assert_equal(content.to_i, hours[i].content) end end end def assert_image09(attrs, image) _wrap_assertion do names = %w(url link title description) names << ["width", :integer] names << ["height", :integer] assert_attributes(attrs, names, image) end end def assert_items09(attrs, items) _wrap_assertion do names = %w(title link description) items.each_with_index do |item, i| assert_attributes(attrs[i], names, item) end end end def assert_textinput09(attrs, textinput) _wrap_assertion do names = %w(title description name link) assert_attributes(attrs, names, textinput) end end def assert_channel20(attrs, channel) _wrap_assertion do n_attrs = normalized_attrs(attrs) names = %w(title link description language copyright managingEditor webMaster pubDate lastBuildDate generator docs rating) names << ["ttl", :integer] assert_attributes(attrs, names, channel) %w(cloud categories skipHours skipDays).each do |name| value = n_attrs[name] if value target = channel.__send__(name) __send__("assert_channel20_#{name}", value, target) end end end end def assert_channel20_skipDays(contents, skipDays) assert_channel09_skipDays(contents, skipDays) end def assert_channel20_skipHours(contents, skipHours) assert_channel09_skipHours(contents, skipHours) end def assert_channel20_cloud(attrs, cloud) _wrap_assertion do names = %w(domain path registerProcedure protocol) names << ["port", :integer] assert_attributes(attrs, names, cloud) end end def assert_channel20_categories(attrs, categories) _wrap_assertion do names = %w(domain content) categories.each_with_index do |category, i| assert_attributes(attrs[i], names, category) end end end def assert_image20(attrs, image) _wrap_assertion do names = %w(url link title description) names << ["width", :integer] names << ["height", :integer] assert_attributes(attrs, names, image) end end def assert_items20(attrs, items) _wrap_assertion do names = %w(about title link description) items.each_with_index do |item, i| assert_attributes(attrs[i], names, item) n_attrs = normalized_attrs(attrs[i]) %w(source enclosure categories guid).each do |name| value = n_attrs[name] if value target = item.__send__(name) __send__("assert_items20_#{name}", value, target) end end end end end def assert_items20_source(attrs, source) _wrap_assertion do assert_attributes(attrs, %w(url content), source) end end def assert_items20_enclosure(attrs, enclosure) _wrap_assertion do names = ["url", ["length", :integer], "type"] assert_attributes(attrs, names, enclosure) end end def assert_items20_categories(attrs, categories) _wrap_assertion do assert_channel20_categories(attrs, categories) end end def assert_items20_guid(attrs, guid) _wrap_assertion do names = [["isPermaLink", :boolean], ["content"]] assert_attributes(attrs, names, guid) end end def assert_textinput20(attrs, textinput) _wrap_assertion do names = %w(title description name link) assert_attributes(attrs, names, textinput) end end end end ================================================ FILE: test/rss/test_trackback.rb ================================================ require "cgi" require "rexml/document" require "rss-testcase" require "rss/1.0" require "rss/2.0" require "rss/trackback" module RSS class TestTrackBack < TestCase def setup @prefix = "trackback" @uri = "http://madskills.com/public/xml/rss/module/trackback/" @parents = %w(item) @elems = { :ping => "http://bar.com/tb.cgi?tb_id=rssplustrackback", :about => "http://foo.com/trackback/tb.cgi?tb_id=20020923", } @content_nodes = @elems.collect do |name, value| "<#{@prefix}:#{name} rdf:resource=\"#{CGI.escapeHTML(value.to_s)}\"/>" end.join("\n") @content_nodes2 = @elems.collect do |name, value| "<#{@prefix}:#{name}>#{CGI.escapeHTML(value.to_s)}" end.join("\n") @rss_source = make_RDF(<<-EOR, {@prefix => @uri}) #{make_channel()} #{make_image()} #{make_item(@content_nodes)} #{make_textinput()} EOR @rss = Parser.parse(@rss_source) @rss20_source = make_rss20(nil, {@prefix => @uri}) do make_channel20(nil) do make_item20(@content_nodes2) end end @rss20 = Parser.parse(@rss20_source, false) end def test_parser assert_nothing_raised do Parser.parse(@rss_source) end @elems.find_all{|k, v| k == :ping}.each do |tag, value| assert_too_much_tag(tag.to_s, "item") do Parser.parse(make_RDF(<<-EOR, {@prefix => @uri})) #{make_channel()} #{make_item(("<" + @prefix + ":" + tag.to_s + " rdf:resource=\"" + CGI.escapeHTML(value.to_s) + "\"/>") * 2)} EOR end end @elems.find_all{|k, v| k == :about}.each do |tag, value| assert_missing_tag("trackback:ping", "item") do Parser.parse(make_RDF(<<-EOR, {@prefix => @uri})) #{make_channel()} #{make_item(("<" + @prefix + ":" + tag.to_s + " rdf:resource=\"" + CGI.escapeHTML(value.to_s) + "\"/>") * 2)} EOR end end end def test_accessor new_value = { :ping => "http://baz.com/trackback/tb.cgi?tb_id=20030808", :about => "http://hoge.com/trackback/tb.cgi?tb_id=90030808", } @elems.each do |name, value| @parents.each do |parent| accessor = "#{RSS::TRACKBACK_PREFIX}_#{name}" target = @rss.__send__(parent) target20 = @rss20.channel.__send__(parent, -1) assert_equal(value, target.__send__(accessor)) assert_equal(value, target20.__send__(accessor)) if name == :about # abount is zero or more target.__send__("#{accessor}=", 0, new_value[name].to_s) target20.__send__("#{accessor}=", 0, new_value[name].to_s) else target.__send__("#{accessor}=", new_value[name].to_s) target20.__send__("#{accessor}=", new_value[name].to_s) end assert_equal(new_value[name], target.__send__(accessor)) assert_equal(new_value[name], target20.__send__(accessor)) end end end def test_to_s @elems.each do |name, value| excepted = %Q!<#{@prefix}:#{name} rdf:resource="#{CGI.escapeHTML(value)}"/>! @parents.each do |parent| meth = "#{RSS::TRACKBACK_PREFIX}_#{name}_element" meth << "s" if name == :about assert_equal(excepted, @rss.__send__(parent).__send__(meth)) end end REXML::Document.new(@rss_source).root.each_element do |parent| if @parents.include?(parent.name) parent.each_element do |elem| if elem.namespace == @uri assert_equal(elem.attributes["resource"], @elems[elem.name.intern]) end end end end end end end ================================================ FILE: test/rss/test_version.rb ================================================ require "rss-testcase" module RSS class TestVersion < TestCase def test_version assert_equal("0.2.4", ::RSS::VERSION) end end end ================================================ FILE: test/rss/test_xml-stylesheet.rb ================================================ require "rexml/document" require "rss-testcase" require "rss/1.0" require "rss/xml-stylesheet" module RSS class TestXMLStyleSheet < TestCase def test_accessor [ {:href => "a.xsl", :type => "text/xsl"}, {:media => "print", :title => "FOO"}, {:charset => "UTF-8", :alternate => "yes"}, ].each do |attrs| assert_xml_stylesheet_attrs(attrs, XMLStyleSheet.new(attrs)) end end def test_to_s [ {:href => "a.xsl", :type => "text/xsl"}, {:type => "text/xsl"}, {:href => "a.xsl", :guess_type => "text/xsl"}, {:href => "a.css", :type => "text/css"}, {:href => "a.css", :type => "text/xsl", :guess_type => "text/css"}, {:href => "a.xsl", :type => "text/xsl", :title => "sample", :media => "printer", :charset => "UTF-8", :alternate => "yes"}, {:href => "a.css", :guess_type => "text/css", :alternate => "no"}, {:type => "text/xsl", :title => "sample", :media => "printer", :charset => "UTF-8", :alternate => "yes"}, ].each do |attrs| target, contents = parse_pi(XMLStyleSheet.new(attrs).to_s) assert_xml_stylesheet(target, attrs, XMLStyleSheet.new(contents)) end end def test_bad_alternate %w(a ___ ??? BAD_ALTERNATE).each do |value| xss = XMLStyleSheet.new assert_raise(NotAvailableValueError) do xss.alternate = value end xss.do_validate = false assert_nothing_raised do xss.alternate = value end assert_nil(xss.alternate) end end def test_parse [ [{:href => "a.xsl", :type => "text/xsl"},], [{:media => "print", :title => "FOO"},], [{:charset => "UTF-8", :alternate => "yes"},], [{:href => "a.xsl", :type => "text/xsl"}, {:type => "text/xsl"}, {:href => "a.xsl", :guess_type => "text/xsl"}, {:href => "a.css", :type => "text/css"}, {:href => "a.css", :type => "text/xsl", :guess_type => "text/css"}, {:href => "a.xsl", :type => "text/xsl", :title => "sample", :media => "printer", :charset => "UTF-8", :alternate => "yes"}, {:href => "a.css", :guess_type => "text/css", :alternate => "no"}, {:type => "text/xsl", :title => "sample", :media => "printer", :charset => "UTF-8", :alternate => "yes"},], ].each do |xsss| doc = REXML::Document.new(make_sample_RDF) root = doc.root xsss.each do |xss| content = xss.collect do |key, name| %Q[#{key}="#{name}"] end.join(" ") pi = REXML::Instruction.new("xml-stylesheet", content) root.previous_sibling = pi end rss = Parser.parse(doc.to_s) have_href_xsss = xsss.find_all {|xss| xss.has_key?(:href)} assert_equal(have_href_xsss.size, rss.xml_stylesheets.size) rss.xml_stylesheets.each_with_index do |stylesheet, i| target, = parse_pi(stylesheet.to_s) assert_xml_stylesheet(target, have_href_xsss[i], stylesheet) end end end def parse_pi(pi) /\A\s*<\?(\S+)([^(?:\?>)]+)\?>\s*\z/ =~ pi target = $1 dummy = REXML::Document.new("").root contents = {} dummy.attributes.each do |name, value| contents[name] = value end [target, contents] end end end ================================================ FILE: test/ruby/beginmainend.rb ================================================ errout = ARGV.shift BEGIN { puts "b1" local_begin1 = "local_begin1" $global_begin1 = "global_begin1" ConstBegin1 = "ConstBegin1" } BEGIN { puts "b2" BEGIN { puts "b2-1" } } # for scope check raise if defined?(local_begin1) raise unless defined?($global_begin1) raise unless defined?(::ConstBegin1) local_for_end2 = "e2" $global_for_end1 = "e1" puts "main" END { puts local_for_end2 # e2 } eval <2, 3=>4}) end def test_hash_default h = Hash.new(:default) h[5] = 6 marshal_equal(h) end def test_hash_subclass h = MyHash.new(7, 8) h[4] = 5 marshal_equal(h) end def test_hash_default_proc h = Hash.new {} assert_raises(TypeError) { marshaltest(h) } end def test_hash_ivar o1 = Hash.new o1.instance_eval { @iv = 1 } marshal_equal(o1) {|o| o.instance_eval { @iv }} end def test_hash_extend o1 = Hash.new o1.extend(Mod1) marshal_equal(o1) { |o| (class << self; self; end).ancestors } o1.extend(Mod2) marshal_equal(o1) { |o| (class << self; self; end).ancestors } end def test_hash_subclass_extend o1 = MyHash.new(2) o1.extend(Mod1) marshal_equal(o1) { |o| (class << self; self; end).ancestors } o1.extend(Mod2) marshal_equal(o1) { |o| (class << self; self; end).ancestors } end def test_bignum marshal_equal(-0x4000_0000_0000_0001) marshal_equal(-0x4000_0001) marshal_equal(0x4000_0000) marshal_equal(0x4000_0000_0000_0000) end def test_fixnum marshal_equal(-0x4000_0000) marshal_equal(-0x3fff_ffff) marshal_equal(-1) marshal_equal(0) marshal_equal(1) marshal_equal(0x3fff_ffff) end def test_fixnum_ivar o1 = 1 o1.instance_eval { @iv = 2 } marshal_equal(o1) {|o| o.instance_eval { @iv }} ensure 1.instance_eval { remove_instance_variable("@iv") } end def test_fixnum_ivar_self o1 = 1 o1.instance_eval { @iv = 1 } marshal_equal(o1) {|o| o.instance_eval { @iv }} ensure 1.instance_eval { remove_instance_variable("@iv") } end def test_fixnum_64bit obj = [1220278665, 1220278662, 1220278661, 1220278661, 1220278656] marshal_equal(obj) end def test_float marshal_equal(-1.0) marshal_equal(0.0) marshal_equal(1.0) end def test_float_inf_nan marshal_equal(1.0/0.0) marshal_equal(-1.0/0.0) marshal_equal(0.0/0.0) {|o| o.nan?} marshal_equal(NegativeZero) {|o| 1.0/o} end def test_float_ivar o1 = 1.23 o1.instance_eval { @iv = 1 } marshal_equal(o1) {|o| o.instance_eval { @iv }} end def test_float_ivar_self o1 = 5.5 o1.instance_eval { @iv = o1 } marshal_equal(o1) {|o| o.instance_eval { @iv }} end def test_float_extend o1 = 0.0/0.0 o1.extend(Mod1) marshal_equal(o1) { |o| (class << self; self; end).ancestors } o1.extend(Mod2) marshal_equal(o1) { |o| (class << self; self; end).ancestors } end class MyRange < Range; def initialize(v, *args) super(*args); @v = v; end end def test_range marshal_equal(1..2) marshal_equal(1...3) end def test_range_subclass marshal_equal(MyRange.new(4,5,8, false)) end class MyRegexp < Regexp; def initialize(v, *args) super(*args); @v = v; end end def test_regexp marshal_equal(/a/) marshal_equal(/A/i) marshal_equal(/A/mx) end def test_regexp_subclass marshal_equal(MyRegexp.new(10, "a")) end class MyString < String; def initialize(v, *args) super(*args); @v = v; end end def test_string marshal_equal("abc") end def test_string_ivar o1 = "" o1.instance_eval { @iv = 1 } marshal_equal(o1) {|o| o.instance_eval { @iv }} end def test_string_subclass marshal_equal(MyString.new(10, "a")) end def test_string_subclass_cycle str = MyString.new(10, "b") str.instance_eval { @v = str } marshal_equal(str) { |o| assert_equal(o.__id__, o.instance_eval { @v }.__id__) o.instance_eval { @v } } end def test_string_subclass_extend o = "abc" o.extend(Mod1) str = MyString.new(o, "c") marshal_equal(str) { |o| assert(o.instance_eval { @v }).kind_of?(Mod1) } end MyStruct = Struct.new("MyStruct", :a, :b) if RUBY_VERSION < "1.8.0" # Struct#== is not defined in ruby/1.6 class MyStruct def ==(rhs) return true if __id__ == rhs.__id__ return false unless rhs.is_a?(::Struct) return false if self.class != rhs.class members.each do |member| return false if self.__send__(member) != rhs.__send__(member) end return true end end end class MySubStruct < MyStruct; def initialize(v, *args) super(*args); @v = v; end end def test_struct marshal_equal(MyStruct.new(1,2)) end def test_struct_subclass if RUBY_VERSION < "1.8.0" # Substruct instance cannot be dumped in ruby/1.6 # ::Marshal.dump(MySubStruct.new(10, 1, 2)) #=> uninitialized struct return false end marshal_equal(MySubStruct.new(10,1,2)) end def test_struct_ivar o1 = MyStruct.new o1.instance_eval { @iv = 1 } marshal_equal(o1) {|o| o.instance_eval { @iv }} end def test_struct_subclass_extend o1 = MyStruct.new o1.extend(Mod1) marshal_equal(o1) { |o| (class << self; self; end).ancestors } o1.extend(Mod2) marshal_equal(o1) { |o| (class << self; self; end).ancestors } end def test_symbol marshal_equal(:a) marshal_equal(:a?) marshal_equal(:a!) marshal_equal(:a=) marshal_equal(:|) marshal_equal(:^) marshal_equal(:&) marshal_equal(:<=>) marshal_equal(:==) marshal_equal(:===) marshal_equal(:=~) marshal_equal(:>) marshal_equal(:>=) marshal_equal(:<) marshal_equal(:<=) marshal_equal(:<<) marshal_equal(:>>) marshal_equal(:+) marshal_equal(:-) marshal_equal(:*) marshal_equal(:/) marshal_equal(:%) marshal_equal(:**) marshal_equal(:~) marshal_equal(:+@) marshal_equal(:-@) marshal_equal(:[]) marshal_equal(:[]=) marshal_equal(:`) #` marshal_equal("a b".intern) end class MyTime < Time; def initialize(v, *args) super(*args); @v = v; end end def test_time # once there was a bug caused by usec overflow. try a little harder. 10.times do t = Time.now marshal_equal(t, t.usec.to_s) end end def test_time_subclass marshal_equal(MyTime.new(10)) end def test_time_ivar o1 = Time.now o1.instance_eval { @iv = 1 } marshal_equal(o1) {|o| o.instance_eval { @iv }} end def test_true marshal_equal(true) end def test_nil marshal_equal(nil) end def test_share o = [:share] o1 = [o, o] o2 = marshaltest(o1) assert_same(o2.first, o2.last) end class CyclicRange < Range def <=>(other); true; end end def test_range_cyclic return unless CyclicRange.respond_to?(:allocate) # test for 1.8 o1 = CyclicRange.allocate o1.instance_eval { initialize(o1, o1) } o2 = marshaltest(o1) assert_same(o2, o2.begin) assert_same(o2, o2.end) end def test_singleton o = Object.new def o.m() end assert_raises(TypeError) { marshaltest(o) } o = Object.new c = class << o @v = 1 class C; self; end end assert_raises(TypeError) { marshaltest(o) } assert_raises(TypeError) { marshaltest(c) } assert_raises(TypeError) { marshaltest(ARGF) } assert_raises(TypeError) { marshaltest(ENV) } end def test_extend o = Object.new o.extend Mod1 marshal_equal(o) { |obj| obj.kind_of? Mod1 } o = Object.new o.extend Mod1 o.extend Mod2 marshal_equal(o) {|obj| class << obj; ancestors end} o = Object.new o.extend Module.new assert_raises(TypeError) { marshaltest(o) } end def test_extend_string o = "" o.extend Mod1 marshal_equal(o) { |obj| obj.kind_of? Mod1 } o = "" o.extend Mod1 o.extend Mod2 marshal_equal(o) {|obj| class << obj; ancestors end} o = "" o.extend Module.new assert_raises(TypeError) { marshaltest(o) } end def test_anonymous c = Class.new assert_raises(TypeError) { marshaltest(c) } o = c.new assert_raises(TypeError) { marshaltest(o) } m = Module.new assert_raises(TypeError) { marshaltest(m) } end def test_string_empty marshal_equal("") end def test_string_crlf marshal_equal("\r\n") end def test_string_escape marshal_equal("\0<;;>\1;;") end MyStruct2 = Struct.new(:a, :b) if RUBY_VERSION < "1.8.0" # Struct#== is not defined in ruby/1.6 class MyStruct2 def ==(rhs) return true if __id__ == rhs.__id__ return false unless rhs.is_a?(::Struct) return false if self.class != rhs.class members.each do |member| return false if self.__send__(member) != rhs.__send__(member) end return true end end end def test_struct_toplevel o = MyStruct2.new(1,2) marshal_equal(o) end end ================================================ FILE: test/ruby/suicide.rb ================================================ STDERR.reopen(STDOUT) at_exit{Process.kill(:INT, $$); sleep 0} # brent@mbari.org says # sleep 0 avoids race between process termination and signal reception ================================================ FILE: test/ruby/test_alias.rb ================================================ require 'test/unit' class TestAlias < Test::Unit::TestCase class Alias0 def foo; "foo" end end class Alias1b} # sort with condition assert_equal([1,2,3,5,7], x) x.sort!{|a,b| b-a} # reverse sort assert_equal([7,5,3,2,1], x) end def test_split_0 x = "The Boassert of Mormon" assert_equal(x.reverse, x.split(//).reverse!.join) assert_equal(x.reverse, x.reverse!) assert_equal("g:n:i:r:t:s: :e:t:y:b: :1", "1 byte string".split(//).reverse.join(":")) x = "a b c d" assert_equal(['a', 'b', 'c', 'd'], x.split) assert_equal(['a', 'b', 'c', 'd'], x.split(' ')) end def test_misc_0 assert(defined? "a".chomp) assert_equal(["a", "b", "c"], "abc".scan(/./)) assert_equal([["1a"], ["2b"], ["3c"]], "1a2b3c".scan(/(\d.)/)) # non-greedy match assert_equal([["a", "12"], ["b", "22"]], "a=12;b=22".scan(/(.*?)=(\d*);?/)) x = [1] assert_equal('1:1:1:1:1', (x * 5).join(":")) assert_equal('1', (x * 1).join(":")) assert_equal('', (x * 0).join(":")) *x = *(1..7).to_a assert_equal(7, x.size) assert_equal([1, 2, 3, 4, 5, 6, 7], x) x = [1,2,3] x[1,0] = x assert_equal([1,1,2,3,2,3], x) x = [1,2,3] x[-1,0] = x assert_equal([1,2,1,2,3,3], x) x = [1,2,3] x.concat(x) assert_equal([1,2,3,1,2,3], x) x = [1,2,3] x.clear assert_equal([], x) x = [1,2,3] y = x.dup x << 4 y << 5 assert_equal([1,2,3,4], x) assert_equal([1,2,3,5], y) end def test_beg_end_0 x = [1, 2, 3, 4, 5] assert_equal(1, x.first) assert_equal([1], x.first(1)) assert_equal([1, 2, 3], x.first(3)) assert_equal(5, x.last) assert_equal([5], x.last(1)) assert_equal([3, 4, 5], x.last(3)) assert_equal(1, x.shift) assert_equal([2, 3, 4], x.shift(3)) assert_equal([5], x) assert_equal([2, 3, 4, 5], x.unshift(2, 3, 4)) assert_equal([1, 2, 3, 4, 5], x.unshift(1)) assert_equal([1, 2, 3, 4, 5], x) assert_equal(5, x.pop) assert_equal([3, 4], x.pop(2)) assert_equal([1, 2], x) assert_equal([1, 2, 3, 4], x.push(3, 4)) assert_equal([1, 2, 3, 4, 5], x.push(5)) assert_equal([1, 2, 3, 4, 5], x) end def test_find_all_0 assert_respond_to([], :find_all) assert_respond_to([], :select) # Alias assert_equal([], [].find_all{ |obj| obj == "foo"}) x = ["foo", "bar", "baz", "baz", 1, 2, 3, 3, 4] assert_equal(["baz","baz"], x.find_all{ |obj| obj == "baz" }) assert_equal([3,3], x.find_all{ |obj| obj == 3 }) end def test_fill_0 assert_equal([-1, -1, -1, -1, -1, -1], [0, 1, 2, 3, 4, 5].fill(-1)) assert_equal([0, 1, 2, -1, -1, -1], [0, 1, 2, 3, 4, 5].fill(-1, 3)) assert_equal([0, 1, 2, -1, -1, 5], [0, 1, 2, 3, 4, 5].fill(-1, 3, 2)) assert_equal([0, 1, 2, -1, -1, -1, -1, -1], [0, 1, 2, 3, 4, 5].fill(-1, 3, 5)) assert_equal([0, 1, -1, -1, 4, 5], [0, 1, 2, 3, 4, 5].fill(-1, 2, 2)) assert_equal([0, 1, -1, -1, -1, -1, -1], [0, 1, 2, 3, 4, 5].fill(-1, 2, 5)) assert_equal([0, 1, 2, 3, -1, 5], [0, 1, 2, 3, 4, 5].fill(-1, -2, 1)) assert_equal([0, 1, 2, 3, -1, -1, -1], [0, 1, 2, 3, 4, 5].fill(-1, -2, 3)) assert_equal([0, 1, 2, -1, -1, 5], [0, 1, 2, 3, 4, 5].fill(-1, 3..4)) assert_equal([0, 1, 2, -1, 4, 5], [0, 1, 2, 3, 4, 5].fill(-1, 3...4)) assert_equal([0, 1, -1, -1, -1, 5], [0, 1, 2, 3, 4, 5].fill(-1, 2..-2)) assert_equal([0, 1, -1, -1, 4, 5], [0, 1, 2, 3, 4, 5].fill(-1, 2...-2)) assert_equal([10, 11, 12, 13, 14, 15], [0, 1, 2, 3, 4, 5].fill{|i| i+10}) assert_equal([0, 1, 2, 13, 14, 15], [0, 1, 2, 3, 4, 5].fill(3){|i| i+10}) assert_equal([0, 1, 2, 13, 14, 5], [0, 1, 2, 3, 4, 5].fill(3, 2){|i| i+10}) assert_equal([0, 1, 2, 13, 14, 15, 16, 17], [0, 1, 2, 3, 4, 5].fill(3, 5){|i| i+10}) assert_equal([0, 1, 2, 13, 14, 5], [0, 1, 2, 3, 4, 5].fill(3..4){|i| i+10}) assert_equal([0, 1, 2, 13, 4, 5], [0, 1, 2, 3, 4, 5].fill(3...4){|i| i+10}) assert_equal([0, 1, 12, 13, 14, 5], [0, 1, 2, 3, 4, 5].fill(2..-2){|i| i+10}) assert_equal([0, 1, 12, 13, 4, 5], [0, 1, 2, 3, 4, 5].fill(2...-2){|i| i+10}) end # From rubicon def setup @cls = Array end def test_00_new a = @cls.new() assert_instance_of(@cls, a) assert_equal(0, a.length) assert_nil(a[0]) end def test_01_square_brackets a = @cls[ 5, 4, 3, 2, 1 ] assert_instance_of(@cls, a) assert_equal(5, a.length) 5.times { |i| assert_equal(5-i, a[i]) } assert_nil(a[6]) end def test_AND # '&' assert_equal(@cls[1, 3], @cls[ 1, 1, 3, 5 ] & @cls[ 1, 2, 3 ]) assert_equal(@cls[], @cls[ 1, 1, 3, 5 ] & @cls[ ]) assert_equal(@cls[], @cls[ ] & @cls[ 1, 2, 3 ]) assert_equal(@cls[], @cls[ 1, 2, 3 ] & @cls[ 4, 5, 6 ]) end def test_MUL # '*' assert_equal(@cls[], @cls[]*3) assert_equal(@cls[1, 1, 1], @cls[1]*3) assert_equal(@cls[1, 2, 1, 2, 1, 2], @cls[1, 2]*3) assert_equal(@cls[], @cls[1, 2, 3] * 0) assert_raise(ArgumentError) { @cls[1, 2]*(-3) } assert_equal('1-2-3-4-5', @cls[1, 2, 3, 4, 5] * '-') assert_equal('12345', @cls[1, 2, 3, 4, 5] * '') end def test_PLUS # '+' assert_equal(@cls[], @cls[] + @cls[]) assert_equal(@cls[1], @cls[1] + @cls[]) assert_equal(@cls[1], @cls[] + @cls[1]) assert_equal(@cls[1, 1], @cls[1] + @cls[1]) assert_equal(@cls['cat', 'dog', 1, 2, 3], %w(cat dog) + (1..3).to_a) end def test_MINUS # '-' assert_equal(@cls[], @cls[1] - @cls[1]) assert_equal(@cls[1], @cls[1, 2, 3, 4, 5] - @cls[2, 3, 4, 5]) # Ruby 1.8 feature change #assert_equal(@cls[1], @cls[1, 2, 1, 3, 1, 4, 1, 5] - @cls[2, 3, 4, 5]) assert_equal(@cls[1, 1, 1, 1], @cls[1, 2, 1, 3, 1, 4, 1, 5] - @cls[2, 3, 4, 5]) a = @cls[] 1000.times { a << 1 } assert_equal(1000, a.length) #assert_equal(@cls[1], a - @cls[2]) assert_equal(@cls[1] * 1000, a - @cls[2]) #assert_equal(@cls[1], @cls[1, 2, 1] - @cls[2]) assert_equal(@cls[1, 1], @cls[1, 2, 1] - @cls[2]) assert_equal(@cls[1, 2, 3], @cls[1, 2, 3] - @cls[4, 5, 6]) end def test_LSHIFT # '<<' a = @cls[] a << 1 assert_equal(@cls[1], a) a << 2 << 3 assert_equal(@cls[1, 2, 3], a) a << nil << 'cat' assert_equal(@cls[1, 2, 3, nil, 'cat'], a) a << a assert_equal(@cls[1, 2, 3, nil, 'cat', a], a) end def test_CMP # '<=>' assert_equal(0, @cls[] <=> @cls[]) assert_equal(0, @cls[1] <=> @cls[1]) assert_equal(0, @cls[1, 2, 3, 'cat'] <=> @cls[1, 2, 3, 'cat']) assert_equal(-1, @cls[] <=> @cls[1]) assert_equal(1, @cls[1] <=> @cls[]) assert_equal(-1, @cls[1, 2, 3] <=> @cls[1, 2, 3, 'cat']) assert_equal(1, @cls[1, 2, 3, 'cat'] <=> @cls[1, 2, 3]) assert_equal(-1, @cls[1, 2, 3, 'cat'] <=> @cls[1, 2, 3, 'dog']) assert_equal(1, @cls[1, 2, 3, 'dog'] <=> @cls[1, 2, 3, 'cat']) end def test_EQUAL # '==' assert(@cls[] == @cls[]) assert(@cls[1] == @cls[1]) assert(@cls[1, 1, 2, 2] == @cls[1, 1, 2, 2]) assert(@cls[1.0, 1.0, 2.0, 2.0] == @cls[1, 1, 2, 2]) end def test_VERY_EQUAL # '===' assert(@cls[] === @cls[]) assert(@cls[1] === @cls[1]) assert(@cls[1, 1, 2, 2] === @cls[1, 1, 2, 2]) assert(@cls[1.0, 1.0, 2.0, 2.0] === @cls[1, 1, 2, 2]) end def test_AREF # '[]' a = @cls[*(1..100).to_a] assert_equal(1, a[0]) assert_equal(100, a[99]) assert_nil(a[100]) assert_equal(100, a[-1]) assert_equal(99, a[-2]) assert_equal(1, a[-100]) assert_nil(a[-101]) assert_nil(a[-101,0]) assert_nil(a[-101,1]) assert_nil(a[-101,-1]) assert_nil(a[10,-1]) assert_equal(@cls[1], a[0,1]) assert_equal(@cls[100], a[99,1]) assert_equal(@cls[], a[100,1]) assert_equal(@cls[100], a[99,100]) assert_equal(@cls[100], a[-1,1]) assert_equal(@cls[99], a[-2,1]) assert_equal(@cls[], a[-100,0]) assert_equal(@cls[1], a[-100,1]) assert_equal(@cls[10, 11, 12], a[9, 3]) assert_equal(@cls[10, 11, 12], a[-91, 3]) assert_equal(@cls[1], a[0..0]) assert_equal(@cls[100], a[99..99]) assert_equal(@cls[], a[100..100]) assert_equal(@cls[100], a[99..200]) assert_equal(@cls[100], a[-1..-1]) assert_equal(@cls[99], a[-2..-2]) assert_equal(@cls[10, 11, 12], a[9..11]) assert_equal(@cls[10, 11, 12], a[-91..-89]) assert_nil(a[10, -3]) # Ruby 1.8 feature change: # Array#[size..x] returns [] instead of nil. #assert_nil(a[10..7]) assert_equal [], a[10..7] assert_raise(TypeError) {a['cat']} end def test_ASET # '[]=' a = @cls[*(0..99).to_a] assert_equal(0, a[0] = 0) assert_equal(@cls[0] + @cls[*(1..99).to_a], a) a = @cls[*(0..99).to_a] assert_equal(0, a[10,10] = 0) assert_equal(@cls[*(0..9).to_a] + @cls[0] + @cls[*(20..99).to_a], a) a = @cls[*(0..99).to_a] assert_equal(0, a[-1] = 0) assert_equal(@cls[*(0..98).to_a] + @cls[0], a) a = @cls[*(0..99).to_a] assert_equal(0, a[-10, 10] = 0) assert_equal(@cls[*(0..89).to_a] + @cls[0], a) a = @cls[*(0..99).to_a] assert_equal(0, a[0,1000] = 0) assert_equal(@cls[0] , a) a = @cls[*(0..99).to_a] assert_equal(0, a[10..19] = 0) assert_equal(@cls[*(0..9).to_a] + @cls[0] + @cls[*(20..99).to_a], a) b = @cls[*%w( a b c )] a = @cls[*(0..99).to_a] assert_equal(b, a[0,1] = b) assert_equal(b + @cls[*(1..99).to_a], a) a = @cls[*(0..99).to_a] assert_equal(b, a[10,10] = b) assert_equal(@cls[*(0..9).to_a] + b + @cls[*(20..99).to_a], a) a = @cls[*(0..99).to_a] assert_equal(b, a[-1, 1] = b) assert_equal(@cls[*(0..98).to_a] + b, a) a = @cls[*(0..99).to_a] assert_equal(b, a[-10, 10] = b) assert_equal(@cls[*(0..89).to_a] + b, a) a = @cls[*(0..99).to_a] assert_equal(b, a[0,1000] = b) assert_equal(b , a) a = @cls[*(0..99).to_a] assert_equal(b, a[10..19] = b) assert_equal(@cls[*(0..9).to_a] + b + @cls[*(20..99).to_a], a) # Ruby 1.8 feature change: # assigning nil does not remove elements. =begin a = @cls[*(0..99).to_a] assert_equal(nil, a[0,1] = nil) assert_equal(@cls[*(1..99).to_a], a) a = @cls[*(0..99).to_a] assert_equal(nil, a[10,10] = nil) assert_equal(@cls[*(0..9).to_a] + @cls[*(20..99).to_a], a) a = @cls[*(0..99).to_a] assert_equal(nil, a[-1, 1] = nil) assert_equal(@cls[*(0..98).to_a], a) a = @cls[*(0..99).to_a] assert_equal(nil, a[-10, 10] = nil) assert_equal(@cls[*(0..89).to_a], a) a = @cls[*(0..99).to_a] assert_equal(nil, a[0,1000] = nil) assert_equal(@cls[] , a) a = @cls[*(0..99).to_a] assert_equal(nil, a[10..19] = nil) assert_equal(@cls[*(0..9).to_a] + @cls[*(20..99).to_a], a) =end a = @cls[1, 2, 3] a[1, 0] = a assert_equal([1, 1, 2, 3, 2, 3], a) a = @cls[1, 2, 3] a[-1, 0] = a assert_equal([1, 2, 1, 2, 3, 3], a) end def test_assoc a1 = @cls[*%w( cat feline )] a2 = @cls[*%w( dog canine )] a3 = @cls[*%w( mule asinine )] a = @cls[ a1, a2, a3 ] assert_equal(a1, a.assoc('cat')) assert_equal(a3, a.assoc('mule')) assert_equal(nil, a.assoc('asinine')) assert_equal(nil, a.assoc('wombat')) assert_equal(nil, a.assoc(1..2)) end def test_at a = @cls[*(0..99).to_a] assert_equal(0, a.at(0)) assert_equal(10, a.at(10)) assert_equal(99, a.at(99)) assert_equal(nil, a.at(100)) assert_equal(99, a.at(-1)) assert_equal(0, a.at(-100)) assert_equal(nil, a.at(-101)) assert_raise(TypeError) { a.at('cat') } end def test_clear a = @cls[1, 2, 3] b = a.clear assert_equal(@cls[], a) assert_equal(@cls[], b) assert_equal(a.__id__, b.__id__) end def test_clone for taint in [ false, true ] for frozen in [ false, true ] a = @cls[*(0..99).to_a] a.taint if taint a.freeze if frozen b = a.clone assert_equal(a, b) assert(a.__id__ != b.__id__) assert_equal(a.frozen?, b.frozen?) assert_equal(a.tainted?, b.tainted?) end end end def test_collect a = @cls[ 1, 'cat', 1..1 ] assert_equal([ Fixnum, String, Range], a.collect {|e| e.class} ) assert_equal([ 99, 99, 99], a.collect { 99 } ) assert_equal([], @cls[].collect { 99 }) assert_equal([1, 2, 3], @cls[1, 2, 3].collect) end # also update map! def test_collect! a = @cls[ 1, 'cat', 1..1 ] assert_equal([ Fixnum, String, Range], a.collect! {|e| e.class} ) assert_equal([ Fixnum, String, Range], a) a = @cls[ 1, 'cat', 1..1 ] assert_equal([ 99, 99, 99], a.collect! { 99 } ) assert_equal([ 99, 99, 99], a) a = @cls[ ] assert_equal([], a.collect! { 99 }) assert_equal([], a) end def test_compact a = @cls[ 1, nil, nil, 2, 3, nil, 4 ] assert_equal(@cls[1, 2, 3, 4], a.compact) a = @cls[ nil, 1, nil, 2, 3, nil, 4 ] assert_equal(@cls[1, 2, 3, 4], a.compact) a = @cls[ 1, nil, nil, 2, 3, nil, 4, nil ] assert_equal(@cls[1, 2, 3, 4], a.compact) a = @cls[ 1, 2, 3, 4 ] assert_equal(@cls[1, 2, 3, 4], a.compact) end def test_compact! a = @cls[ 1, nil, nil, 2, 3, nil, 4 ] assert_equal(@cls[1, 2, 3, 4], a.compact!) assert_equal(@cls[1, 2, 3, 4], a) a = @cls[ nil, 1, nil, 2, 3, nil, 4 ] assert_equal(@cls[1, 2, 3, 4], a.compact!) assert_equal(@cls[1, 2, 3, 4], a) a = @cls[ 1, nil, nil, 2, 3, nil, 4, nil ] assert_equal(@cls[1, 2, 3, 4], a.compact!) assert_equal(@cls[1, 2, 3, 4], a) a = @cls[ 1, 2, 3, 4 ] assert_equal(nil, a.compact!) assert_equal(@cls[1, 2, 3, 4], a) end def test_concat assert_equal(@cls[1, 2, 3, 4], @cls[1, 2].concat(@cls[3, 4])) assert_equal(@cls[1, 2, 3, 4], @cls[].concat(@cls[1, 2, 3, 4])) assert_equal(@cls[1, 2, 3, 4], @cls[1, 2, 3, 4].concat(@cls[])) assert_equal(@cls[], @cls[].concat(@cls[])) assert_equal(@cls[@cls[1, 2], @cls[3, 4]], @cls[@cls[1, 2]].concat(@cls[@cls[3, 4]])) a = @cls[1, 2, 3] a.concat(a) assert_equal([1, 2, 3, 1, 2, 3], a) end def test_count a = @cls[1, 2, 3, 1, 2] assert_equal(5, a.count) assert_equal(2, a.count(1)) assert_equal(3, a.count {|x| x % 2 == 1 }) assert_equal(2, a.count(1) {|x| x % 2 == 1 }) assert_raise(ArgumentError) { a.count(0, 1) } end def test_delete a = @cls[*('cab'..'cat').to_a] assert_equal('cap', a.delete('cap')) assert_equal(@cls[*('cab'..'cao').to_a] + @cls[*('caq'..'cat').to_a], a) a = @cls[*('cab'..'cat').to_a] assert_equal('cab', a.delete('cab')) assert_equal(@cls[*('cac'..'cat').to_a], a) a = @cls[*('cab'..'cat').to_a] assert_equal('cat', a.delete('cat')) assert_equal(@cls[*('cab'..'cas').to_a], a) a = @cls[*('cab'..'cat').to_a] assert_equal(nil, a.delete('cup')) assert_equal(@cls[*('cab'..'cat').to_a], a) a = @cls[*('cab'..'cat').to_a] assert_equal(99, a.delete('cup') { 99 } ) assert_equal(@cls[*('cab'..'cat').to_a], a) end def test_delete_at a = @cls[*(1..5).to_a] assert_equal(3, a.delete_at(2)) assert_equal(@cls[1, 2, 4, 5], a) a = @cls[*(1..5).to_a] assert_equal(4, a.delete_at(-2)) assert_equal(@cls[1, 2, 3, 5], a) a = @cls[*(1..5).to_a] assert_equal(nil, a.delete_at(5)) assert_equal(@cls[1, 2, 3, 4, 5], a) a = @cls[*(1..5).to_a] assert_equal(nil, a.delete_at(-6)) assert_equal(@cls[1, 2, 3, 4, 5], a) end # also reject! def test_delete_if a = @cls[ 1, 2, 3, 4, 5 ] assert_equal(a, a.delete_if { false }) assert_equal(@cls[1, 2, 3, 4, 5], a) a = @cls[ 1, 2, 3, 4, 5 ] assert_equal(a, a.delete_if { true }) assert_equal(@cls[], a) a = @cls[ 1, 2, 3, 4, 5 ] assert_equal(a, a.delete_if { |i| i > 3 }) assert_equal(@cls[1, 2, 3], a) end def test_dup for taint in [ false, true ] for frozen in [ false, true ] a = @cls[*(0..99).to_a] a.taint if taint a.freeze if frozen b = a.dup assert_equal(a, b) assert(a.__id__ != b.__id__) assert_equal(false, b.frozen?) assert_equal(a.tainted?, b.tainted?) end end end def test_each a = @cls[*%w( ant bat cat dog )] i = 0 a.each { |e| assert_equal(a[i], e) i += 1 } assert_equal(4, i) a = @cls[] i = 0 a.each { |e| assert_equal(a[i], e) i += 1 } assert_equal(0, i) assert_equal(a, a.each {}) end def test_each_index a = @cls[*%w( ant bat cat dog )] i = 0 a.each_index { |ind| assert_equal(i, ind) i += 1 } assert_equal(4, i) a = @cls[] i = 0 a.each_index { |ind| assert_equal(i, ind) i += 1 } assert_equal(0, i) assert_equal(a, a.each_index {}) end def test_empty? assert(@cls[].empty?) assert(!@cls[1].empty?) end def test_eql? assert(@cls[].eql?(@cls[])) assert(@cls[1].eql?(@cls[1])) assert(@cls[1, 1, 2, 2].eql?(@cls[1, 1, 2, 2])) assert(!@cls[1.0, 1.0, 2.0, 2.0].eql?(@cls[1, 1, 2, 2])) end def test_fill assert_equal(@cls[], @cls[].fill(99)) assert_equal(@cls[], @cls[].fill(99, 0)) assert_equal(@cls[99], @cls[].fill(99, 0, 1)) assert_equal(@cls[99], @cls[].fill(99, 0..0)) assert_equal(@cls[99], @cls[1].fill(99)) assert_equal(@cls[99], @cls[1].fill(99, 0)) assert_equal(@cls[99], @cls[1].fill(99, 0, 1)) assert_equal(@cls[99], @cls[1].fill(99, 0..0)) assert_equal(@cls[99, 99], @cls[1, 2].fill(99)) assert_equal(@cls[99, 99], @cls[1, 2].fill(99, 0)) assert_equal(@cls[99, 99], @cls[1, 2].fill(99, nil)) assert_equal(@cls[1, 99], @cls[1, 2].fill(99, 1, nil)) assert_equal(@cls[99, 2], @cls[1, 2].fill(99, 0, 1)) assert_equal(@cls[99, 2], @cls[1, 2].fill(99, 0..0)) end def test_first assert_equal(3, @cls[3, 4, 5].first) assert_equal(nil, @cls[].first) end def test_flatten a1 = @cls[ 1, 2, 3] a2 = @cls[ 5, 6 ] a3 = @cls[ 4, a2 ] a4 = @cls[ a1, a3 ] assert_equal(@cls[1, 2, 3, 4, 5, 6], a4.flatten) assert_equal(@cls[ a1, a3], a4) a5 = @cls[ a1, @cls[], a3 ] assert_equal(@cls[1, 2, 3, 4, 5, 6], a5.flatten) assert_equal(@cls[], @cls[].flatten) assert_equal(@cls[], @cls[@cls[@cls[@cls[],@cls[]],@cls[@cls[]],@cls[]],@cls[@cls[@cls[]]]].flatten) assert_raise(TypeError, "[ruby-dev:31197]") { [[]].flatten("") } end def test_flatten! a1 = @cls[ 1, 2, 3] a2 = @cls[ 5, 6 ] a3 = @cls[ 4, a2 ] a4 = @cls[ a1, a3 ] assert_equal(@cls[1, 2, 3, 4, 5, 6], a4.flatten!) assert_equal(@cls[1, 2, 3, 4, 5, 6], a4) a5 = @cls[ a1, @cls[], a3 ] assert_equal(@cls[1, 2, 3, 4, 5, 6], a5.flatten!) assert_equal(@cls[1, 2, 3, 4, 5, 6], a5) assert_equal(@cls[], @cls[].flatten) assert_equal(@cls[], @cls[@cls[@cls[@cls[],@cls[]],@cls[@cls[]],@cls[]],@cls[@cls[@cls[]]]].flatten) end def test_flatten_with_callcc respond_to?(:callcc, true) or require 'continuation' o = Object.new def o.to_ary() callcc {|k| @cont = k; [1,2,3]} end begin assert_equal([10, 20, 1, 2, 3, 30, 1, 2, 3, 40], [10, 20, o, 30, o, 40].flatten) rescue => e else o.instance_eval {@cont}.call end assert_instance_of(RuntimeError, e, '[ruby-dev:34798]') assert_match(/reentered/, e.message, '[ruby-dev:34798]') end def test_hash a1 = @cls[ 'cat', 'dog' ] a2 = @cls[ 'cat', 'dog' ] a3 = @cls[ 'dog', 'cat' ] assert(a1.hash == a2.hash) assert(a1.hash != a3.hash) end def test_include? a = @cls[ 'cat', 99, /a/, @cls[ 1, 2, 3] ] assert(a.include?('cat')) assert(a.include?(99)) assert(a.include?(/a/)) assert(a.include?([1,2,3])) assert(!a.include?('ca')) assert(!a.include?([1,2])) end def test_index a = @cls[ 'cat', 99, /a/, 99, @cls[ 1, 2, 3] ] assert_equal(0, a.index('cat')) assert_equal(1, a.index(99)) assert_equal(4, a.index([1,2,3])) assert_nil(a.index('ca')) assert_nil(a.index([1,2])) end def test_values_at a = @cls[*('a'..'j').to_a] assert_equal(@cls['a', 'c', 'e'], a.values_at(0, 2, 4)) assert_equal(@cls['j', 'h', 'f'], a.values_at(-1, -3, -5)) assert_equal(@cls['h', nil, 'a'], a.values_at(-3, 99, 0)) end def test_join $, = "" a = @cls[] assert_equal("", a.join) assert_equal("", a.join(',')) $, = "" a = @cls[1, 2] assert_equal("12", a.join) assert_equal("1,2", a.join(',')) $, = "" a = @cls[1, 2, 3] assert_equal("123", a.join) assert_equal("1,2,3", a.join(',')) $, = ":" a = @cls[1, 2, 3] assert_equal("1:2:3", a.join) assert_equal("1,2,3", a.join(',')) $, = "" end def test_last assert_equal(nil, @cls[].last) assert_equal(1, @cls[1].last) assert_equal(99, @cls[*(3..99).to_a].last) end def test_length assert_equal(0, @cls[].length) assert_equal(1, @cls[1].length) assert_equal(2, @cls[1, nil].length) assert_equal(2, @cls[nil, 1].length) assert_equal(234, @cls[*(0..233).to_a].length) end # also update collect! def test_map! a = @cls[ 1, 'cat', 1..1 ] assert_equal(@cls[ Fixnum, String, Range], a.map! {|e| e.class} ) assert_equal(@cls[ Fixnum, String, Range], a) a = @cls[ 1, 'cat', 1..1 ] assert_equal(@cls[ 99, 99, 99], a.map! { 99 } ) assert_equal(@cls[ 99, 99, 99], a) a = @cls[ ] assert_equal(@cls[], a.map! { 99 }) assert_equal(@cls[], a) end def test_nitems assert_equal(0, @cls[].nitems) assert_equal(1, @cls[1].nitems) assert_equal(1, @cls[1, nil].nitems) assert_equal(1, @cls[nil, 1].nitems) assert_equal(3, @cls[1, nil, nil, 2, nil, 3, nil].nitems) end def test_pack a = @cls[*%w( cat wombat x yy)] assert_equal("catwomx yy ", a.pack("A3A3A3A3")) assert_equal("cat", a.pack("A*")) assert_equal("cwx yy ", a.pack("A3@1A3@2A3A3")) assert_equal("catwomx\000\000yy\000", a.pack("a3a3a3a3")) assert_equal("cat", a.pack("a*")) assert_equal("ca", a.pack("a2")) assert_equal("cat\000\000", a.pack("a5")) assert_equal("\x61", @cls["01100001"].pack("B8")) assert_equal("\x61", @cls["01100001"].pack("B*")) assert_equal("\x61", @cls["0110000100110111"].pack("B8")) assert_equal("\x61\x37", @cls["0110000100110111"].pack("B16")) assert_equal("\x61\x37", @cls["01100001", "00110111"].pack("B8B8")) assert_equal("\x60", @cls["01100001"].pack("B4")) assert_equal("\x40", @cls["01100001"].pack("B2")) assert_equal("\x86", @cls["01100001"].pack("b8")) assert_equal("\x86", @cls["01100001"].pack("b*")) assert_equal("\x86", @cls["0110000100110111"].pack("b8")) assert_equal("\x86\xec", @cls["0110000100110111"].pack("b16")) assert_equal("\x86\xec", @cls["01100001", "00110111"].pack("b8b8")) assert_equal("\x06", @cls["01100001"].pack("b4")) assert_equal("\x02", @cls["01100001"].pack("b2")) assert_equal("ABC", @cls[ 65, 66, 67 ].pack("C3")) assert_equal("\377BC", @cls[ -1, 66, 67 ].pack("C*")) assert_equal("ABC", @cls[ 65, 66, 67 ].pack("c3")) assert_equal("\377BC", @cls[ -1, 66, 67 ].pack("c*")) assert_equal("AB\n\x10", @cls["4142", "0a", "12"].pack("H4H2H1")) assert_equal("AB\n\x02", @cls["1424", "a0", "21"].pack("h4h2h1")) assert_equal("abc=02def=\ncat=\n=01=\n", @cls["abc\002def", "cat", "\001"].pack("M9M3M4")) assert_equal("aGVsbG8K\n", @cls["hello\n"].pack("m")) assert_equal(",:&5L;&\\*:&5L;&\\*\n", @cls["hello\nhello\n"].pack("u")) assert_equal("\xc2\xa9B\xe2\x89\xa0", @cls[0xa9, 0x42, 0x2260].pack("U*")) format = "c2x5CCxsdils_l_a6"; # Need the expression in here to force ary[5] to be numeric. This avoids # test2 failing because ary2 goes str->numeric->str and ary does not. ary = [1, -100, 127, 128, 32767, 987.654321098/100.0, 12345, 123456, -32767, -123456, "abcdef"] x = ary.pack(format) ary2 = x.unpack(format) assert_equal(ary.length, ary2.length) assert_equal(ary.join(':'), ary2.join(':')) assert_not_nil(x =~ /def/) =begin skipping "Not tested: D,d & double-precision float, native format\\ E & double-precision float, little-endian byte order\\ e & single-precision float, little-endian byte order\\ F,f & single-precision float, native format\\ G & double-precision float, network (big-endian) byte order\\ g & single-precision float, network (big-endian) byte order\\ I & unsigned integer\\ i & integer\\ L & unsigned long\\ l & long\\ N & long, network (big-endian) byte order\\ n & short, network (big-endian) byte-order\\ P & pointer to a structure (fixed-length string)\\ p & pointer to a null-terminated string\\ S & unsigned short\\ s & short\\ V & long, little-endian byte order\\ v & short, little-endian byte order\\ X & back up a byte\\ x & null byte\\ Z & ASCII string (null padded, count is width)\\ " =end end def test_pop a = @cls[ 'cat', 'dog' ] assert_equal('dog', a.pop) assert_equal(@cls['cat'], a) assert_equal('cat', a.pop) assert_equal(@cls[], a) assert_nil(a.pop) assert_equal(@cls[], a) end def test_push a = @cls[1, 2, 3] assert_equal(@cls[1, 2, 3, 4, 5], a.push(4, 5)) assert_equal(@cls[1, 2, 3, 4, 5, nil], a.push(nil)) # Ruby 1.8 feature: # Array#push accepts any number of arguments. #assert_raise(ArgumentError, "a.push()") { a.push() } a.push assert_equal @cls[1, 2, 3, 4, 5, nil], a a.push 6, 7 assert_equal @cls[1, 2, 3, 4, 5, nil, 6, 7], a end def test_rassoc a1 = @cls[*%w( cat feline )] a2 = @cls[*%w( dog canine )] a3 = @cls[*%w( mule asinine )] a = @cls[ a1, a2, a3 ] assert_equal(a1, a.rassoc('feline')) assert_equal(a3, a.rassoc('asinine')) assert_equal(nil, a.rassoc('dog')) assert_equal(nil, a.rassoc('mule')) assert_equal(nil, a.rassoc(1..2)) end # also delete_if def test_reject! a = @cls[ 1, 2, 3, 4, 5 ] assert_equal(nil, a.reject! { false }) assert_equal(@cls[1, 2, 3, 4, 5], a) a = @cls[ 1, 2, 3, 4, 5 ] assert_equal(a, a.reject! { true }) assert_equal(@cls[], a) a = @cls[ 1, 2, 3, 4, 5 ] assert_equal(a, a.reject! { |i| i > 3 }) assert_equal(@cls[1, 2, 3], a) end def test_replace a = @cls[ 1, 2, 3] a_id = a.__id__ assert_equal(@cls[4, 5, 6], a.replace(@cls[4, 5, 6])) assert_equal(@cls[4, 5, 6], a) assert_equal(a_id, a.__id__) assert_equal(@cls[], a.replace(@cls[])) end def test_reverse a = @cls[*%w( dog cat bee ant )] assert_equal(@cls[*%w(ant bee cat dog)], a.reverse) assert_equal(@cls[*%w(dog cat bee ant)], a) assert_equal(@cls[], @cls[].reverse) end def test_reverse! a = @cls[*%w( dog cat bee ant )] assert_equal(@cls[*%w(ant bee cat dog)], a.reverse!) assert_equal(@cls[*%w(ant bee cat dog)], a) # Ruby 1.8 feature change: # Array#reverse always returns self. #assert_nil(@cls[].reverse!) assert_equal @cls[], @cls[].reverse! end def test_reverse_each a = @cls[*%w( dog cat bee ant )] i = a.length a.reverse_each { |e| i -= 1 assert_equal(a[i], e) } assert_equal(0, i) a = @cls[] i = 0 a.reverse_each { |e| assert(false, "Never get here") } assert_equal(0, i) end def test_rindex a = @cls[ 'cat', 99, /a/, 99, [ 1, 2, 3] ] assert_equal(0, a.rindex('cat')) assert_equal(3, a.rindex(99)) assert_equal(4, a.rindex([1,2,3])) assert_nil(a.rindex('ca')) assert_nil(a.rindex([1,2])) end def test_shift a = @cls[ 'cat', 'dog' ] assert_equal('cat', a.shift) assert_equal(@cls['dog'], a) assert_equal('dog', a.shift) assert_equal(@cls[], a) assert_nil(a.shift) assert_equal(@cls[], a) end def test_size assert_equal(0, @cls[].size) assert_equal(1, @cls[1].size) assert_equal(100, @cls[*(0..99).to_a].size) end def test_slice a = @cls[*(1..100).to_a] assert_equal(1, a.slice(0)) assert_equal(100, a.slice(99)) assert_nil(a.slice(100)) assert_equal(100, a.slice(-1)) assert_equal(99, a.slice(-2)) assert_equal(1, a.slice(-100)) assert_nil(a.slice(-101)) assert_equal(@cls[1], a.slice(0,1)) assert_equal(@cls[100], a.slice(99,1)) assert_equal(@cls[], a.slice(100,1)) assert_equal(@cls[100], a.slice(99,100)) assert_equal(@cls[100], a.slice(-1,1)) assert_equal(@cls[99], a.slice(-2,1)) assert_equal(@cls[10, 11, 12], a.slice(9, 3)) assert_equal(@cls[10, 11, 12], a.slice(-91, 3)) assert_nil(a.slice(-101, 2)) assert_equal(@cls[1], a.slice(0..0)) assert_equal(@cls[100], a.slice(99..99)) assert_equal(@cls[], a.slice(100..100)) assert_equal(@cls[100], a.slice(99..200)) assert_equal(@cls[100], a.slice(-1..-1)) assert_equal(@cls[99], a.slice(-2..-2)) assert_equal(@cls[10, 11, 12], a.slice(9..11)) assert_equal(@cls[10, 11, 12], a.slice(-91..-89)) assert_nil(a.slice(-101..-1)) assert_nil(a.slice(10, -3)) # Ruby 1.8 feature change: # Array#slice[size..x] always returns []. #assert_nil(a.slice(10..7)) assert_equal @cls[], a.slice(10..7) end def test_slice! a = @cls[1, 2, 3, 4, 5] assert_equal(3, a.slice!(2)) assert_equal(@cls[1, 2, 4, 5], a) a = @cls[1, 2, 3, 4, 5] assert_equal(4, a.slice!(-2)) assert_equal(@cls[1, 2, 3, 5], a) a = @cls[1, 2, 3, 4, 5] assert_equal(@cls[3,4], a.slice!(2,2)) assert_equal(@cls[1, 2, 5], a) a = @cls[1, 2, 3, 4, 5] assert_equal(@cls[4,5], a.slice!(-2,2)) assert_equal(@cls[1, 2, 3], a) a = @cls[1, 2, 3, 4, 5] assert_equal(@cls[3,4], a.slice!(2..3)) assert_equal(@cls[1, 2, 5], a) a = @cls[1, 2, 3, 4, 5] assert_equal(nil, a.slice!(20)) assert_equal(@cls[1, 2, 3, 4, 5], a) a = @cls[1, 2, 3, 4, 5] assert_equal(nil, a.slice!(-6)) assert_equal(@cls[1, 2, 3, 4, 5], a) a = @cls[1, 2, 3, 4, 5] assert_equal(nil, a.slice!(-6..4)) assert_equal(@cls[1, 2, 3, 4, 5], a) a = @cls[1, 2, 3, 4, 5] assert_equal(nil, a.slice!(-6,2)) assert_equal(@cls[1, 2, 3, 4, 5], a) end def test_sort a = @cls[ 4, 1, 2, 3 ] assert_equal(@cls[1, 2, 3, 4], a.sort) assert_equal(@cls[4, 1, 2, 3], a) assert_equal(@cls[4, 3, 2, 1], a.sort { |x, y| y <=> x} ) assert_equal(@cls[4, 1, 2, 3], a) a.fill(1) assert_equal(@cls[1, 1, 1, 1], a.sort) assert_equal(@cls[], @cls[].sort) end def test_sort! a = @cls[ 4, 1, 2, 3 ] assert_equal(@cls[1, 2, 3, 4], a.sort!) assert_equal(@cls[1, 2, 3, 4], a) assert_equal(@cls[4, 3, 2, 1], a.sort! { |x, y| y <=> x} ) assert_equal(@cls[4, 3, 2, 1], a) a.fill(1) assert_equal(@cls[1, 1, 1, 1], a.sort!) assert_equal(@cls[1], @cls[1].sort!) assert_equal(@cls[], @cls[].sort!) end def test_to_a a = @cls[ 1, 2, 3 ] a_id = a.__id__ assert_equal(a, a.to_a) assert_equal(a_id, a.to_a.__id__) end def test_to_ary a = [ 1, 2, 3 ] b = @cls[*a] a_id = a.__id__ assert_equal(a, b.to_ary) if (@cls == Array) assert_equal(a_id, a.to_ary.__id__) end end def test_to_s $, = "" a = @cls[] assert_equal("", a.to_s) $, = "" a = @cls[1, 2] assert_equal("12", a.to_s) $, = "" a = @cls[1, 2, 3] assert_equal("123", a.to_s) $, = ":" a = @cls[1, 2, 3] assert_equal("1:2:3", a.to_s) $, = "" end def test_uniq a = @cls[ 1, 2, 3, 2, 1, 2, 3, 4, nil ] b = a.dup assert_equal(@cls[1, 2, 3, 4, nil], a.uniq) assert_equal(b, a) assert_equal(@cls[1, 2, 3], @cls[1, 2, 3].uniq) end def test_uniq! a = @cls[ 1, 2, 3, 2, 1, 2, 3, 4, nil ] assert_equal(@cls[1, 2, 3, 4, nil], a.uniq!) assert_equal(@cls[1, 2, 3, 4, nil], a) assert_nil(@cls[1, 2, 3].uniq!) end def test_unshift a = @cls[] assert_equal(@cls['cat'], a.unshift('cat')) assert_equal(@cls['dog', 'cat'], a.unshift('dog')) assert_equal(@cls[nil, 'dog', 'cat'], a.unshift(nil)) assert_equal(@cls[@cls[1,2], nil, 'dog', 'cat'], a.unshift(@cls[1, 2])) end def test_OR # '|' assert_equal(@cls[], @cls[] | @cls[]) assert_equal(@cls[1], @cls[1] | @cls[]) assert_equal(@cls[1], @cls[] | @cls[1]) assert_equal(@cls[1], @cls[1] | @cls[1]) assert_equal(@cls[1,2], @cls[1] | @cls[2]) assert_equal(@cls[1,2], @cls[1, 1] | @cls[2, 2]) assert_equal(@cls[1,2], @cls[1, 2] | @cls[1, 2]) end def test_combination assert_equal(@cls[[]], @cls[1,2,3,4].combination(0).to_a) assert_equal(@cls[[1],[2],[3],[4]], @cls[1,2,3,4].combination(1).to_a) assert_equal(@cls[[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]], @cls[1,2,3,4].combination(2).to_a) assert_equal(@cls[[1,2,3],[1,2,4],[1,3,4],[2,3,4]], @cls[1,2,3,4].combination(3).to_a) assert_equal(@cls[[1,2,3,4]], @cls[1,2,3,4].combination(4).to_a) assert_equal(@cls[], @cls[1,2,3,4].combination(5).to_a) end def test_product assert_equal(@cls[[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]], @cls[1,2,3].product([4,5])) assert_equal(@cls[[1,1],[1,2],[2,1],[2,2]], @cls[1,2].product([1,2])) assert_equal(@cls[[1,3,5],[1,3,6],[1,4,5],[1,4,6], [2,3,5],[2,3,6],[2,4,5],[2,4,6]], @cls[1,2].product([3,4],[5,6])) assert_equal(@cls[[1],[2]], @cls[1,2].product) assert_equal(@cls[], @cls[1,2].product([])) end def test_permutation a = @cls[1,2,3] assert_equal(@cls[[]], a.permutation(0).to_a) assert_equal(@cls[[1],[2],[3]], a.permutation(1).to_a.sort) assert_equal(@cls[[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]], a.permutation(2).to_a.sort) assert_equal(@cls[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]], a.permutation(3).sort.to_a) assert_equal(@cls[], a.permutation(4).to_a) assert_equal(@cls[], a.permutation(-1).to_a) assert_equal("abcde".each_char.to_a.permutation(5).sort, "edcba".each_char.to_a.permutation(5).sort) assert_equal(@cls[].permutation(0).to_a, @cls[[]]) end def test_take assert_equal([1,2,3], [1,2,3,4,5,0].take(3)) assert_raise(ArgumentError, '[ruby-dev:34123]') { [1,2].take(-1) } assert_equal([1,2], [1,2].take(1000000000), '[ruby-dev:34123]') end def test_take_while assert_equal([1,2], [1,2,3,4,5,0].take_while {|i| i < 3 }) end def test_drop assert_equal([4,5,0], [1,2,3,4,5,0].drop(3)) assert_raise(ArgumentError, '[ruby-dev:34123]') { [1,2].drop(-1) } assert_equal([], [1,2].drop(1000000000), '[ruby-dev:34123]') end def test_drop_while assert_equal([3,4,5,0], [1,2,3,4,5,0].drop_while {|i| i < 3 }) end end ================================================ FILE: test/ruby/test_assignment.rb ================================================ require 'test/unit' class TestAssignment < Test::Unit::TestCase def test_assign a=[]; a[0] ||= "bar"; assert_equal("bar", a[0]) h={}; h["foo"] ||= "bar"; assert_equal("bar", h["foo"]) aa = 5 aa ||= 25 assert_equal(5, aa) bb ||= 25 assert_equal(25, bb) cc &&=33 assert_nil(cc) cc = 5 cc &&=44 assert_equal(44, cc) a = nil; assert_nil(a) a = 1; assert_equal(1, a) a = []; assert_equal([], a) a = [1]; assert_equal([1], a) a = [nil]; assert_equal([nil], a) a = [[]]; assert_equal([[]], a) a = [1,2]; assert_equal([1,2], a) a = [*[]]; assert_equal([], a) a = [*[1]]; assert_equal([1], a) a = [*[1,2]]; assert_equal([1,2], a) a = *nil; assert_nil(a) a = *1; assert_equal(1, a) a = *[]; assert_nil(a) a = *[1]; assert_equal(1, a) a = *[nil]; assert_nil(a) a = *[[]]; assert_equal([], a) a = *[1,2]; assert_equal([1,2], a) a = *[*[]]; assert_nil(a) a = *[*[1]]; assert_equal(1, a) a = *[*[1,2]]; assert_equal([1,2], a) *a = nil; assert_equal([nil], a) *a = 1; assert_equal([1], a) *a = []; assert_equal([[]], a) *a = [1]; assert_equal([[1]], a) *a = [nil]; assert_equal([[nil]], a) *a = [[]]; assert_equal([[[]]], a) *a = [1,2]; assert_equal([[1,2]], a) *a = [*[]]; assert_equal([[]], a) *a = [*[1]]; assert_equal([[1]], a) *a = [*[1,2]]; assert_equal([[1,2]], a) *a = *nil; assert_equal([nil], a) *a = *1; assert_equal([1], a) *a = *[]; assert_equal([], a) *a = *[1]; assert_equal([1], a) *a = *[nil]; assert_equal([nil], a) *a = *[[]]; assert_equal([[]], a) *a = *[1,2]; assert_equal([1,2], a) *a = *[*[]]; assert_equal([], a) *a = *[*[1]]; assert_equal([1], a) *a = *[*[1,2]]; assert_equal([1,2], a) a,b,*c = nil; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = 1; assert_equal([1,nil,[]], [a,b,c]) a,b,*c = []; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = [1]; assert_equal([1,nil,[]], [a,b,c]) a,b,*c = [nil]; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = [[]]; assert_equal([[],nil,[]], [a,b,c]) a,b,*c = [1,2]; assert_equal([1,2,[]], [a,b,c]) a,b,*c = [*[]]; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = [*[1]]; assert_equal([1,nil,[]], [a,b,c]) a,b,*c = [*[1,2]]; assert_equal([1,2,[]], [a,b,c]) a,b,*c = *nil; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = *1; assert_equal([1,nil,[]], [a,b,c]) a,b,*c = *[]; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = *[1]; assert_equal([1,nil,[]], [a,b,c]) a,b,*c = *[nil]; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = *[[]]; assert_equal([[],nil,[]], [a,b,c]) a,b,*c = *[1,2]; assert_equal([1,2,[]], [a,b,c]) a,b,*c = *[*[]]; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = *[*[1]]; assert_equal([1,nil,[]], [a,b,c]) a,b,*c = *[*[1,2]]; assert_equal([1,2,[]], [a,b,c]) end def test_yield def f; yield nil; end; f {|a| assert_nil(a)} def f; yield 1; end; f {|a| assert_equal(1, a)} def f; yield []; end; f {|a| assert_equal([], a)} def f; yield [1]; end; f {|a| assert_equal([1], a)} def f; yield [nil]; end; f {|a| assert_equal([nil], a)} def f; yield [[]]; end; f {|a| assert_equal([[]], a)} def f; yield [*[]]; end; f {|a| assert_equal([], a)} def f; yield [*[1]]; end; f {|a| assert_equal([1], a)} def f; yield [*[1,2]]; end; f {|a| assert_equal([1,2], a)} def f; yield *nil; end; f {|a| assert_nil(a)} def f; yield *1; end; f {|a| assert_equal(1, a)} def f; yield *[1]; end; f {|a| assert_equal(1, a)} def f; yield *[nil]; end; f {|a| assert_nil(a)} def f; yield *[[]]; end; f {|a| assert_equal([], a)} def f; yield *[*[1]]; end; f {|a| assert_equal(1, a)} def f; yield; end; f {|*a| assert_equal([], a)} def f; yield nil; end; f {|*a| assert_equal([nil], a)} def f; yield 1; end; f {|*a| assert_equal([1], a)} def f; yield []; end; f {|*a| assert_equal([[]], a)} def f; yield [1]; end; f {|*a| assert_equal([[1]], a)} def f; yield [nil]; end; f {|*a| assert_equal([[nil]], a)} def f; yield [[]]; end; f {|*a| assert_equal([[[]]], a)} def f; yield [1,2]; end; f {|*a| assert_equal([[1,2]], a)} def f; yield [*[]]; end; f {|*a| assert_equal([[]], a)} def f; yield [*[1]]; end; f {|*a| assert_equal([[1]], a)} def f; yield [*[1,2]]; end; f {|*a| assert_equal([[1,2]], a)} def f; yield *nil; end; f {|*a| assert_equal([nil], a)} def f; yield *1; end; f {|*a| assert_equal([1], a)} def f; yield *[]; end; f {|*a| assert_equal([], a)} def f; yield *[1]; end; f {|*a| assert_equal([1], a)} def f; yield *[nil]; end; f {|*a| assert_equal([nil], a)} def f; yield *[[]]; end; f {|*a| assert_equal([[]], a)} def f; yield *[*[]]; end; f {|*a| assert_equal([], a)} def f; yield *[*[1]]; end; f {|*a| assert_equal([1], a)} def f; yield *[*[1,2]]; end; f {|*a| assert_equal([1,2], a)} def f; yield; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])} def f; yield nil; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])} def f; yield 1; end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])} def f; yield []; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])} def f; yield [1]; end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])} def f; yield [nil]; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])} def f; yield [[]]; end; f {|a,b,*c| assert_equal([[],nil,[]], [a,b,c])} def f; yield [*[]]; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])} def f; yield [*[1]]; end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])} def f; yield [*[1,2]]; end; f {|a,b,*c| assert_equal([1,2,[]], [a,b,c])} def f; yield *nil; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])} def f; yield *1; end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])} def f; yield *[]; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])} def f; yield *[1]; end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])} def f; yield *[nil]; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])} def f; yield *[[]]; end; f {|a,b,*c| assert_equal([[],nil,[]], [a,b,c])} def f; yield *[*[]]; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])} def f; yield *[*[1]]; end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])} def f; yield *[*[1,2]]; end; f {|a,b,*c| assert_equal([1,2,[]], [a,b,c])} end def test_return def r; return; end; a = r(); assert_nil(a) def r; return nil; end; a = r(); assert_nil(a) def r; return 1; end; a = r(); assert_equal(1, a) def r; return []; end; a = r(); assert_equal([], a) def r; return [1]; end; a = r(); assert_equal([1], a) def r; return [nil]; end; a = r(); assert_equal([nil], a) def r; return [[]]; end; a = r(); assert_equal([[]], a) def r; return [*[]]; end; a = r(); assert_equal([], a) def r; return [*[1]]; end; a = r(); assert_equal([1], a) def r; return [*[1,2]]; end; a = r(); assert_equal([1,2], a) def r; return *nil; end; a = r(); assert_nil(a) def r; return *1; end; a = r(); assert_equal(1, a) def r; return *[]; end; a = r(); assert_nil(a) def r; return *[1]; end; a = r(); assert_equal(1, a) def r; return *[nil]; end; a = r(); assert_nil(a) def r; return *[[]]; end; a = r(); assert_equal([], a) def r; return *[*[]]; end; a = r(); assert_nil(a) def r; return *[*[1]]; end; a = r(); assert_equal(1, a) def r; return *[*[1,2]]; end; a = r(); assert_equal([1,2], a) def r; return *nil; end; a = *r(); assert_nil(a) def r; return *1; end; a = *r(); assert_equal(1, a) def r; return *[]; end; a = *r(); assert_nil(a) def r; return *[1]; end; a = *r(); assert_equal(1, a) def r; return *[nil]; end; a = *r(); assert_nil(a) def r; return *[[]]; end; a = *r(); assert_nil(a) def r; return *[*[]]; end; a = *r(); assert_nil(a) def r; return *[*[1]]; end; a = *r(); assert_equal(1, a) def r; return *[*[1,2]]; end; a = *r(); assert_equal([1,2], a) def r; return; end; *a = r(); assert_equal([nil], a) def r; return nil; end; *a = r(); assert_equal([nil], a) def r; return 1; end; *a = r(); assert_equal([1], a) def r; return []; end; *a = r(); assert_equal([[]], a) def r; return [1]; end; *a = r(); assert_equal([[1]], a) def r; return [nil]; end; *a = r(); assert_equal([[nil]], a) def r; return [[]]; end; *a = r(); assert_equal([[[]]], a) def r; return [1,2]; end; *a = r(); assert_equal([[1,2]], a) def r; return [*[]]; end; *a = r(); assert_equal([[]], a) def r; return [*[1]]; end; *a = r(); assert_equal([[1]], a) def r; return [*[1,2]]; end; *a = r(); assert_equal([[1,2]], a) def r; return *nil; end; *a = r(); assert_equal([nil], a) def r; return *1; end; *a = r(); assert_equal([1], a) def r; return *[]; end; *a = r(); assert_equal([nil], a) def r; return *[1]; end; *a = r(); assert_equal([1], a) def r; return *[nil]; end; *a = r(); assert_equal([nil], a) def r; return *[[]]; end; *a = r(); assert_equal([[]], a) def r; return *[1,2]; end; *a = r(); assert_equal([[1,2]], a) def r; return *[*[]]; end; *a = r(); assert_equal([nil], a) def r; return *[*[1]]; end; *a = r(); assert_equal([1], a) def r; return *[*[1,2]]; end; *a = r(); assert_equal([[1,2]], a) def r; return *nil; end; *a = *r(); assert_equal([nil], a) def r; return *1; end; *a = *r(); assert_equal([1], a) def r; return *[]; end; *a = *r(); assert_equal([nil], a) def r; return *[1]; end; *a = *r(); assert_equal([1], a) def r; return *[nil]; end; *a = *r(); assert_equal([nil], a) def r; return *[[]]; end; *a = *r(); assert_equal([], a) def r; return *[1,2]; end; *a = *r(); assert_equal([1,2], a) def r; return *[*[]]; end; *a = *r(); assert_equal([nil], a) def r; return *[*[1]]; end; *a = *r(); assert_equal([1], a) def r; return *[*[1,2]]; end; *a = *r(); assert_equal([1,2], a) def r; return; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) def r; return nil; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) def r; return 1; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]) def r; return []; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) def r; return [1]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]) def r; return [nil]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) def r; return [[]]; end; a,b,*c = r(); assert_equal([[],nil,[]], [a,b,c]) def r; return [1,2]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]) def r; return [*[]]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) def r; return [*[1]]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]) def r; return [*[1,2]]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]) def r; return *nil; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) def r; return *1; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]) def r; return *[]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) def r; return *[1]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]) def r; return *[nil]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) def r; return *[[]]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) def r; return *[1,2]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]) def r; return *[*[]]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]) def r; return *[*[1]]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]) def r; return *[*[1,2]]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]) end def test_lambda f = lambda {|r,| assert_equal([], r)} f.call([], *[]) f = lambda {|r,*l| assert_equal([], r); assert_equal([1], l)} f.call([], *[1]) f = lambda{|x| x} assert_equal(42, f.call(42)) assert_equal([42], f.call([42])) assert_equal([[42]], f.call([[42]])) assert_equal([42,55], f.call([42,55])) f = lambda{|x,| x} assert_equal(42, f.call(42)) assert_equal([42], f.call([42])) assert_equal([[42]], f.call([[42]])) assert_equal([42,55], f.call([42,55])) f = lambda{|*x| x} assert_equal([42], f.call(42)) assert_equal([[42]], f.call([42])) assert_equal([[[42]]], f.call([[42]])) assert_equal([[42,55]], f.call([42,55])) assert_equal([42,55], f.call(42,55)) end def test_multi a,=*[1] assert_equal(1, a) a,=*[[1]] assert_equal([1], a) a,=*[[[1]]] assert_equal([[1]], a) x, (y, z) = 1, 2, 3 assert_equal([1,2,nil], [x,y,z]) x, (y, z) = 1, [2,3] assert_equal([1,2,3], [x,y,z]) x, (y, z) = 1, [2] assert_equal([1,2,nil], [x,y,z]) end def test_break a = loop do break; end; assert_nil(a) a = loop do break nil; end; assert_nil(a) a = loop do break 1; end; assert_equal(1, a) a = loop do break []; end; assert_equal([], a) a = loop do break [1]; end; assert_equal([1], a) a = loop do break [nil]; end; assert_equal([nil], a) a = loop do break [[]]; end; assert_equal([[]], a) a = loop do break [*[]]; end; assert_equal([], a) a = loop do break [*[1]]; end; assert_equal([1], a) a = loop do break [*[1,2]]; end; assert_equal([1,2], a) a = loop do break *nil; end; assert_nil(a) a = loop do break *1; end; assert_equal(1, a) a = loop do break *[]; end; assert_nil(a) a = loop do break *[1]; end; assert_equal(1, a) a = loop do break *[nil]; end; assert_nil(a) a = loop do break *[[]]; end; assert_equal([], a) a = loop do break *[*[]]; end; assert_nil(a) a = loop do break *[*[1]]; end; assert_equal(1, a) a = loop do break *[*[1,2]]; end; assert_equal([1,2], a) *a = loop do break; end; assert_equal([nil], a) *a = loop do break nil; end; assert_equal([nil], a) *a = loop do break 1; end; assert_equal([1], a) *a = loop do break []; end; assert_equal([[]], a) *a = loop do break [1]; end; assert_equal([[1]], a) *a = loop do break [nil]; end; assert_equal([[nil]], a) *a = loop do break [[]]; end; assert_equal([[[]]], a) *a = loop do break [1,2]; end; assert_equal([[1,2]], a) *a = loop do break [*[]]; end; assert_equal([[]], a) *a = loop do break [*[1]]; end; assert_equal([[1]], a) *a = loop do break [*[1,2]]; end; assert_equal([[1,2]], a) *a = loop do break *nil; end; assert_equal([nil], a) *a = loop do break *1; end; assert_equal([1], a) *a = loop do break *[]; end; assert_equal([nil], a) *a = loop do break *[1]; end; assert_equal([1], a) *a = loop do break *[nil]; end; assert_equal([nil], a) *a = loop do break *[[]]; end; assert_equal([[]], a) *a = loop do break *[1,2]; end; assert_equal([[1,2]], a) *a = loop do break *[*[]]; end; assert_equal([nil], a) *a = loop do break *[*[1]]; end; assert_equal([1], a) *a = loop do break *[*[1,2]]; end; assert_equal([[1,2]], a) *a = *loop do break *nil; end; assert_equal([nil], a) *a = *loop do break *1; end; assert_equal([1], a) *a = *loop do break *[]; end; assert_equal([nil], a) *a = *loop do break *[1]; end; assert_equal([1], a) *a = *loop do break *[nil]; end; assert_equal([nil], a) *a = *loop do break *[[]]; end; assert_equal([], a) *a = *loop do break *[1,2]; end; assert_equal([1,2], a) *a = *loop do break *[*[]]; end; assert_equal([nil], a) *a = *loop do break *[*[1]]; end; assert_equal([1], a) *a = *loop do break *[*[1,2]]; end; assert_equal([1,2], a) a,b,*c = loop do break; end; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = loop do break nil; end; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = loop do break 1; end; assert_equal([1,nil,[]], [a,b,c]) a,b,*c = loop do break []; end; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = loop do break [1]; end; assert_equal([1,nil,[]], [a,b,c]) a,b,*c = loop do break [nil]; end; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = loop do break [[]]; end; assert_equal([[],nil,[]], [a,b,c]) a,b,*c = loop do break [1,2]; end; assert_equal([1,2,[]], [a,b,c]) a,b,*c = loop do break [*[]]; end; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = loop do break [*[1]]; end; assert_equal([1,nil,[]], [a,b,c]) a,b,*c = loop do break [*[1,2]]; end; assert_equal([1,2,[]], [a,b,c]) a,b,*c = loop do break *nil; end; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = loop do break *1; end; assert_equal([1,nil,[]], [a,b,c]) a,b,*c = loop do break *[]; end; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = loop do break *[1]; end; assert_equal([1,nil,[]], [a,b,c]) a,b,*c = loop do break *[nil]; end; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = loop do break *[[]]; end; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = loop do break *[1,2]; end; assert_equal([1,2,[]], [a,b,c]) a,b,*c = loop do break *[*[]]; end; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = loop do break *[*[1]]; end; assert_equal([1,nil,[]], [a,b,c]) a,b,*c = loop do break *[*[1,2]]; end; assert_equal([1,2,[]], [a,b,c]) end def test_next def r(val); a = yield(); assert_equal(val, a); end r(nil){next} r(nil){next nil} r(1){next 1} r([]){next []} r([1]){next [1]} r([nil]){next [nil]} r([[]]){next [[]]} r([]){next [*[]]} r([1]){next [*[1]]} r([1,2]){next [*[1,2]]} r(nil){next *nil} r(1){next *1} r(nil){next *[]} r(1){next *[1]} r(nil){next *[nil]} r([]){next *[[]]} r(nil){next *[*[]]} r(1){next *[*[1]]} r([1,2]){next *[*[1,2]]} def r(val); *a = yield(); assert_equal(val, a); end r([nil]){next} r([nil]){next nil} r([1]){next 1} r([[]]){next []} r([[1]]){next [1]} r([[nil]]){next [nil]} r([[[]]]){next [[]]} r([[1,2]]){next [1,2]} r([[]]){next [*[]]} r([[1]]){next [*[1]]} r([[1,2]]){next [*[1,2]]} def r(val); *a = *yield(); assert_equal(val, a); end r([nil]){next *nil} r([1]){next *1} r([nil]){next *[]} r([1]){next *[1]} r([nil]){next *[nil]} r([]){next *[[]]} r([1,2]){next *[1,2]} r([nil]){next *[*[]]} r([1]){next *[*[1]]} r([1,2]){next *[*[1,2]]} def r(val); a,b,*c = yield(); assert_equal(val, [a,b,c]); end r([nil,nil,[]]){next} r([nil,nil,[]]){next nil} r([1,nil,[]]){next 1} r([nil,nil,[]]){next []} r([1,nil,[]]){next [1]} r([nil,nil,[]]){next [nil]} r([[],nil,[]]){next [[]]} r([1,2,[]]){next [1,2]} r([nil,nil,[]]){next [*[]]} r([1,nil,[]]){next [*[1]]} r([1,2,[]]){next [*[1,2]]} def r(val); a,b,*c = *yield(); assert_equal(val, [a,b,c]); end r([nil,nil,[]]){next *nil} r([1,nil,[]]){next *1} r([nil,nil,[]]){next *[]} r([1,nil,[]]){next *[1]} r([nil,nil,[]]){next *[nil]} r([nil,nil,[]]){next *[[]]} r([1,2,[]]){next *[1,2]} r([nil,nil,[]]){next *[*[]]} r([1,nil,[]]){next *[*[1]]} r([1,2,[]]){next *[*[1,2]]} end def test_assign2 a = nil assert(defined?(a)) assert_nil(a) # multiple asignment a, b = 1, 2 assert(a == 1 && b == 2) a, b = b, a assert(a == 2 && b == 1) a, = 1,2 assert_equal(1, a) a, *b = 1, 2, 3 assert(a == 1 && b == [2, 3]) a, (b, c), d = 1, [2, 3], 4 assert(a == 1 && b == 2 && c == 3 && d == 4) *a = 1, 2, 3 assert_equal([1, 2, 3], a) *a = 4 assert_equal([4], a) *a = nil assert_equal([nil], a) end end ================================================ FILE: test/ruby/test_beginendblock.rb ================================================ require 'test/unit' require 'tempfile' $:.replace([File.dirname(File.expand_path(__FILE__))] | $:) require 'envutil' class TestBeginEndBlock < Test::Unit::TestCase DIR = File.dirname(File.expand_path(__FILE__)) def q(content) "\"#{content}\"" end def test_beginendblock ruby = EnvUtil.rubybin target = File.join(DIR, 'beginmainend.rb') result = IO.popen("#{q(ruby)} #{q(target)}"){|io|io.read} assert_equal(%w(b1 b2-1 b2 main b3-1 b3 b4 e1 e4 e3 e2 e4-2 e4-1 e1-1 e4-1-1), result.split) end def test_begininmethod assert_raises(SyntaxError) do eval("def foo; BEGIN {}; end") end assert_raises(SyntaxError) do eval('eval("def foo; BEGIN {}; end")') end end def test_endblockwarn ruby = EnvUtil.rubybin # Use Tempfile to create temporary file path. launcher = Tempfile.new(self.class.name) errout = Tempfile.new(self.class.name) launcher << <0 f *= n n -= 1 end return f end def test_bignum $x = fact(40) assert_equal($x, $x) assert_equal($x, fact(40)) assert($x < $x+2) assert($x > $x-2) assert_equal(815915283247897734345611269596115894272000000000, $x) assert_not_equal(815915283247897734345611269596115894272000000001, $x) assert_equal(815915283247897734345611269596115894272000000001, $x+1) assert_equal(335367096786357081410764800000, $x/fact(20)) $x = -$x assert_equal(-815915283247897734345611269596115894272000000000, $x) assert_equal(2-(2**32), -(2**32-2)) assert_equal(2**32 - 5, (2**32-3)-2) for i in 1000..1014 assert_equal(2 ** i, 1 << i) end n1 = 1 << 1000 for i in 1000..1014 assert_equal(n1, 1 << i) n1 *= 2 end n2=n1 for i in 1..10 n1 = n1 / 2 n2 = n2 >> 1 assert_equal(n1, n2) end for i in 4000..4096 n1 = 1 << i; assert_equal(n1-1, (n1**2-1) / (n1+1)) end end def test_calc b = 10**80 a = b * 9 + 7 assert_equal(7, a.modulo(b)) assert_equal(-b + 7, a.modulo(-b)) assert_equal(b + -7, (-a).modulo(b)) assert_equal(-7, (-a).modulo(-b)) assert_equal(7, a.remainder(b)) assert_equal(7, a.remainder(-b)) assert_equal(-7, (-a).remainder(b)) assert_equal(-7, (-a).remainder(-b)) assert_equal(10000000000000000000100000000000000000000, 10**40+10**20) assert_equal(100000000000000000000, 10**40/10**20) a = 677330545177305025495135714080 b = 14269972710765292560 assert_equal(0, a % b) assert_equal(0, -a % b) end def shift_test(a) b = a / (2 ** 32) c = a >> 32 assert_equal(b, c) b = a * (2 ** 32) c = a << 32 assert_equal(b, c) end def test_shift shift_test(-4518325415524767873) shift_test(-0xfffffffffffffffff) end def test_to_s # [ruby-core:10686] assert_equal("fvvvvvvvvvvvv" ,18446744073709551615.to_s(32)) assert_equal("g000000000000" ,18446744073709551616.to_s(32)) assert_equal("3w5e11264sgsf" ,18446744073709551615.to_s(36)) assert_equal("3w5e11264sgsg" ,18446744073709551616.to_s(36)) assert_equal("nd075ib45k86f" ,18446744073709551615.to_s(31)) assert_equal("nd075ib45k86g" ,18446744073709551616.to_s(31)) assert_equal("1777777777777777777777" ,18446744073709551615.to_s(8)) assert_equal("-1777777777777777777777" ,-18446744073709551615.to_s(8)) end def test_too_big_to_s if (big = 2**31-1).is_a?(Fixnum) return end e = assert_raise(RangeError) {(1 << big).to_s} assert_match(/too big to convert/, e.message) end end ================================================ FILE: test/ruby/test_call.rb ================================================ require 'test/unit' class TestCall < Test::Unit::TestCase def aaa(a, b=100, *rest) res = [a, b] res += rest if rest return res end def test_call assert_raises(ArgumentError) {aaa()} assert_raises(ArgumentError) {aaa} assert_equal([1, 100], aaa(1)) assert_equal([1, 2], aaa(1, 2)) assert_equal([1, 2, 3, 4], aaa(1, 2, 3, 4)) assert_equal([1, 2, 3, 4], aaa(1, *[2, 3, 4])) end end ================================================ FILE: test/ruby/test_case.rb ================================================ require 'test/unit' class TestCase < Test::Unit::TestCase def test_case case 5 when 1, 2, 3, 4, 6, 7, 8 assert(false) when 5 assert(true) end case 5 when 5 assert(true) when 1..10 assert(false) end case 5 when 1..10 assert(true) else assert(false) end case 5 when 5 assert(true) else assert(false) end case "foobar" when /^f.*r$/ assert(true) else assert(false) end case when true assert(true) when false, nil assert(false) else assert(false) end end end ================================================ FILE: test/ruby/test_clone.rb ================================================ require 'test/unit' class TestClone < Test::Unit::TestCase module M001; end module M002; end module M003; include M002; end module M002; include M001; end module M003; include M002; end def test_clone foo = Object.new def foo.test "test" end bar = foo.clone def bar.test2 "test2" end assert_equal("test2", bar.test2) assert_equal("test", bar.test) assert_equal("test", foo.test) assert_raises(NoMethodError) {foo.test2} assert_equal([M003, M002, M001], M003.ancestors) end end ================================================ FILE: test/ruby/test_condition.rb ================================================ require 'test/unit' class TestCondition < Test::Unit::TestCase # [should] first test to see if we can run the tests. def test_condition $x = '0'; $x == $x && assert(true) $x != $x && assert(false) $x == $x || assert(false) $x != $x || assert(true) end end ================================================ FILE: test/ruby/test_const.rb ================================================ require 'test/unit' class TestConst < Test::Unit::TestCase TEST1 = 1 TEST2 = 2 module Const TEST3 = 3 TEST4 = 4 end module Const2 TEST3 = 6 TEST4 = 8 end def test_const self.class.class_eval { include Const } assert_equal([1,2,3,4], [TEST1,TEST2,TEST3,TEST4]) self.class.class_eval { include Const2 } STDERR.print "intentionally redefines TEST3, TEST4\n" if $VERBOSE assert_equal([1,2,6,8], [TEST1,TEST2,TEST3,TEST4]) assert_equal(-1, (String <=> Object)) assert_equal(1, (Object <=> String)) assert_equal(nil, (Array <=> String)) end end ================================================ FILE: test/ruby/test_defined.rb ================================================ require 'test/unit' class TestDefined < Test::Unit::TestCase class Foo def foo p :foo end protected :foo def bar(f) yield(defined?(self.foo)) yield(defined?(f.foo)) end end def defined_test return !defined?(yield) end def test_defined $x = nil assert(defined?($x)) # global variable assert_equal('global-variable', defined?($x))# returns description assert_nil(defined?(foo)) # undefined foo=5 assert(defined?(foo)) # local variable assert(defined?(Array)) # constant assert(defined?(::Array)) # toplevel constant assert(defined?(File::Constants)) # nested constant assert(defined?(Object.new)) # method assert(!defined?(Object.print)) # private method assert(defined?(1 == 2)) # operator expression f = Foo.new assert_nil(defined?(f.foo)) f.bar(f) { |v| assert(v) } assert(defined_test) # not iterator assert(!defined_test{}) # called as iterator end end ================================================ FILE: test/ruby/test_dir.rb ================================================ require 'test/unit' require 'tmpdir' require 'fileutils' class TestDir < Test::Unit::TestCase ROOT = File.join(Dir.tmpdir, "__test_dir__#{$$}") def setup Dir.mkdir(ROOT) for i in ?a..?z if i % 2 == 0 FileUtils.touch(File.join(ROOT, i.chr)) else FileUtils.mkdir(File.join(ROOT, i.chr)) end end end def teardown FileUtils.rm_rf ROOT if File.directory?(ROOT) end def test_seek dir = Dir.open(ROOT) begin cache = [] loop do pos = dir.tell break unless name = dir.read cache << [pos, name] end for x in cache.sort_by {|x| x[0] % 3 } # shuffle dir.seek(x[0]) assert_equal(x[1], dir.read) end ensure dir.close end end end ================================================ FILE: test/ruby/test_enum.rb ================================================ require 'test/unit' class TestEnumerable < Test::Unit::TestCase def setup @obj = Object.new class << @obj include Enumerable def each yield 1 yield 2 yield 3 yield 1 yield 2 end end @verbose = $VERBOSE $VERBOSE = nil end def teardown $VERBOSE = @verbose end def test_grep assert_equal([1, 2, 1, 2], @obj.grep(1..2)) a = [] @obj.grep(2) {|x| a << x } assert_equal([2, 2], a) end def test_count assert_equal(5, @obj.count) assert_equal(2, @obj.count(1)) assert_equal(3, @obj.count {|x| x % 2 == 1 }) assert_equal(2, @obj.count(1) {|x| x % 2 == 1 }) assert_raise(ArgumentError) { @obj.count(0, 1) } end def test_find assert_equal(2, @obj.find {|x| x % 2 == 0 }) assert_equal(nil, @obj.find {|x| false }) assert_equal(:foo, @obj.find(proc { :foo }) {|x| false }) end def test_find_index assert_equal(1, @obj.find_index(2)) assert_equal(1, @obj.find_index {|x| x % 2 == 0 }) assert_equal(nil, @obj.find_index {|x| false }) assert_raise(ArgumentError) { @obj.find_index(0, 1) } end def test_find_all assert_equal([1, 3, 1], @obj.find_all {|x| x % 2 == 1 }) end def test_reject assert_equal([2, 3, 2], @obj.reject {|x| x < 2 }) end def test_to_a assert_equal([1, 2, 3, 1, 2], @obj.to_a) end def test_inject assert_equal(12, @obj.inject {|z, x| z * x }) assert_equal(48, @obj.inject {|z, x| z * 2 + x }) assert_equal(12, @obj.inject(:*)) assert_equal(24, @obj.inject(2) {|z, x| z * x }) assert_equal(24, @obj.inject(2, :*) {|z, x| z * x }) end def test_partition assert_equal([[1, 3, 1], [2, 2]], @obj.partition {|x| x % 2 == 1 }) end def test_group_by h = { 1 => [1, 1], 2 => [2, 2], 3 => [3] } assert_equal(h, @obj.group_by {|x| x }) end def test_first assert_equal(1, @obj.first) assert_equal([1, 2, 3], @obj.first(3)) end def test_sort assert_equal([1, 1, 2, 2, 3], @obj.sort) end def test_sort_by assert_equal([3, 2, 2, 1, 1], @obj.sort_by {|x| -x }) end def test_all assert_equal(true, @obj.all? {|x| x <= 3 }) assert_equal(false, @obj.all? {|x| x < 3 }) assert_equal(true, @obj.all?) assert_equal(false, [true, true, false].all?) end def test_any assert_equal(true, @obj.any? {|x| x >= 3 }) assert_equal(false, @obj.any? {|x| x > 3 }) assert_equal(true, @obj.any?) assert_equal(false, [false, false, false].any?) end def test_one assert(@obj.one? {|x| x == 3 }) assert(!(@obj.one? {|x| x == 1 })) assert(!(@obj.one? {|x| x == 4 })) assert(%w{ant bear cat}.one? {|word| word.length == 4}) assert(!(%w{ant bear cat}.one? {|word| word.length > 4})) assert(!(%w{ant bear cat}.one? {|word| word.length < 4})) assert(!([ nil, true, 99 ].one?)) assert([ nil, true, false ].one?) end def test_none assert(@obj.none? {|x| x == 4 }) assert(!(@obj.none? {|x| x == 1 })) assert(!(@obj.none? {|x| x == 3 })) assert(%w{ant bear cat}.none? {|word| word.length == 5}) assert(!(%w{ant bear cat}.none? {|word| word.length >= 4})) assert([].none?) assert([nil].none?) assert([nil,false].none?) end def test_min assert_equal(1, @obj.min) assert_equal(3, @obj.min {|a,b| b <=> a }) a = %w(albatross dog horse) assert_equal("albatross", a.min) assert_equal("dog", a.min {|a,b| a.length <=> b.length }) assert_equal(1, [3,2,1].min) end def test_max assert_equal(3, @obj.max) assert_equal(1, @obj.max {|a,b| b <=> a }) a = %w(albatross dog horse) assert_equal("horse", a.max) assert_equal("albatross", a.max {|a,b| a.length <=> b.length }) assert_equal(1, [3,2,1].max{|a,b| b <=> a }) end def test_minmax assert_equal([1, 3], @obj.minmax) assert_equal([3, 1], @obj.minmax {|a,b| b <=> a }) a = %w(albatross dog horse) assert_equal(["albatross", "horse"], a.minmax) assert_equal(["dog", "albatross"], a.minmax {|a,b| a.length <=> b.length }) assert_equal([1, 3], [2,3,1].minmax) assert_equal([3, 1], [2,3,1].minmax {|a,b| b <=> a }) end def test_min_by assert_equal(3, @obj.min_by {|x| -x }) a = %w(albatross dog horse) assert_equal("dog", a.min_by {|x| x.length }) assert_equal(3, [2,3,1].min_by {|x| -x }) end def test_max_by assert_equal(1, @obj.max_by {|x| -x }) a = %w(albatross dog horse) assert_equal("albatross", a.max_by {|x| x.length }) assert_equal(1, [2,3,1].max_by {|x| -x }) end def test_minmax_by assert_equal([3, 1], @obj.minmax_by {|x| -x }) a = %w(albatross dog horse) assert_equal(["dog", "albatross"], a.minmax_by {|x| x.length }) assert_equal([3, 1], [2,3,1].minmax_by {|x| -x }) end def test_member assert(@obj.member?(1)) assert(!(@obj.member?(4))) assert([1,2,3].member?(1)) assert(!([1,2,3].member?(4))) end def test_each_with_index a = [] @obj.each_with_index {|x, i| a << [x, i] } assert_equal([[1,0],[2,1],[3,2],[1,3],[2,4]], a) hash = Hash.new %w(cat dog wombat).each_with_index do |item, index| hash[item] = index end assert_equal({"cat"=>0, "wombat"=>2, "dog"=>1}, hash) end def test_zip assert_equal([[1,1],[2,2],[3,3],[1,1],[2,2]], @obj.zip(@obj)) a = [] @obj.zip([:a, :b, :c]) {|x,y| a << [x, y] } assert_equal([[1,:a],[2,:b],[3,:c],[1,nil],[2,nil]], a) end def test_take assert_equal([1,2,3], @obj.take(3)) end def test_take_while assert_equal([1,2], @obj.take_while {|x| x <= 2}) end def test_drop assert_equal([3,1,2], @obj.drop(2)) end def test_drop_while assert_equal([3,1,2], @obj.drop_while {|x| x <= 2}) end def test_cycle assert_equal([1,2,3,1,2,1,2,3,1,2], @obj.cycle.take(10)) end def test_callcc assert_raise(RuntimeError) do c = nil @obj.sort_by {|x| callcc {|c2| c ||= c2 }; x } c.call end assert_raise(RuntimeError) do c = nil o = Object.new class << o; self; end.class_eval do define_method(:<=>) do |x| callcc {|c2| c ||= c2 } 0 end end [o, o].sort_by {|x| x } c.call end assert_raise(RuntimeError) do c = nil o = Object.new class << o; self; end.class_eval do define_method(:<=>) do |x| callcc {|c2| c ||= c2 } 0 end end [o, o, o].sort_by {|x| x } c.call end end end ================================================ FILE: test/ruby/test_enumerator.rb ================================================ require 'test/unit' class TestEnumerator < Test::Unit::TestCase def setup @obj = Object.new class << @obj include Enumerable def foo(*a) a.each {|x| yield x } end end end def enum_test obj i = 0 obj.map{|e| e }.sort end def test_iterators assert_equal [0, 1, 2], enum_test(3.times) assert_equal ["x", "y", "z"], enum_test(["z", "y", "x"].each) assert_equal [["x", 1], ["y", 2]], enum_test({"y"=>2, "x"=>1}) end ## Enumerator as Iterator def test_next e = 3.times 3.times{|i| assert_equal i, e.next } assert_raise(StopIteration){e.next} end def test_loop e = 3.times i = 0 loop{ assert_equal(i, e.next) i += 1 } end def test_nested_itaration def (o = Object.new).each yield :ok1 yield [:ok2, :x].each.next end e = o.to_enum assert_equal :ok1, e.next assert_equal :ok2, e.next assert_raise(StopIteration){e.next} end def test_initialize assert_equal([1, 2, 3], @obj.to_enum(:foo, 1, 2, 3).to_a) assert_equal([1, 2, 3], Enumerable::Enumerator.new(@obj, :foo, 1, 2, 3).to_a) assert_raise(ArgumentError) { Enumerable::Enumerator.new } end def test_initialize_copy assert_equal([1, 2, 3], @obj.to_enum(:foo, 1, 2, 3).dup.to_a) e = @obj.to_enum(:foo, 1, 2, 3) assert_nothing_raised { assert_equal(1, e.next) } #assert_raise(TypeError) { e.dup } end def test_gc assert_nothing_raised do 1.times do foo = [1,2,3].to_enum GC.start end GC.start end end def test_slice assert_equal([[1,2,3],[4,5,6],[7,8,9],[10]], (1..10).each_slice(3).to_a) end def test_cons a = [[1,2,3], [2,3,4], [3,4,5], [4,5,6], [5,6,7], [6,7,8], [7,8,9], [8,9,10]] assert_equal(a, (1..10).each_cons(3).to_a) end def test_with_index assert_equal([[1,0],[2,1],[3,2]], @obj.to_enum(:foo, 1, 2, 3).with_index.to_a) end def test_next_rewind e = @obj.to_enum(:foo, 1, 2, 3) assert_equal(1, e.next) assert_equal(2, e.next) e.rewind assert_equal(1, e.next) assert_equal(2, e.next) assert_equal(3, e.next) assert_raise(StopIteration) { e.next } end end ================================================ FILE: test/ruby/test_env.rb ================================================ require 'test/unit' class TestEnv < Test::Unit::TestCase IGNORE_CASE = /djgpp|bccwin|mswin|mingw/ =~ RUBY_PLATFORM def setup @backup = ENV.delete('test') @BACKUP = ENV.delete('TEST') end def teardown ENV['test'] = @backup if @backup ENV['TEST'] = @BACKUP if @BACKUP end def test_bracket assert_nil(ENV['test']) assert_nil(ENV['TEST']) ENV['test'] = 'foo' assert_equal('foo', ENV['test']) if IGNORE_CASE assert_equal('foo', ENV['TEST']) else assert_nil(ENV['TEST']) end ENV['TEST'] = 'bar' assert_equal('bar', ENV['TEST']) if IGNORE_CASE assert_equal('bar', ENV['test']) else assert_equal('foo', ENV['test']) end assert_raises(TypeError) { tmp = ENV[1] } assert_raises(TypeError) { ENV[1] = 'foo' } assert_raises(TypeError) { ENV['test'] = 0 } end def test_has_value val = 'a' val.succ! while ENV.has_value?(val) && ENV.has_value?(val.upcase) ENV['test'] = val[0...-1] assert_equal(false, ENV.has_value?(val)) assert_equal(false, ENV.has_value?(val.upcase)) ENV['test'] = val assert_equal(true, ENV.has_value?(val)) assert_equal(false, ENV.has_value?(val.upcase)) ENV['test'] = val.upcase assert_equal(false, ENV.has_value?(val)) assert_equal(true, ENV.has_value?(val.upcase)) end def test_index val = 'a' val.succ! while ENV.has_value?(val) && ENV.has_value?(val.upcase) ENV['test'] = val[0...-1] assert_nil(ENV.index(val)) assert_nil(ENV.index(val.upcase)) ENV['test'] = val if IGNORE_CASE assert_equal('TEST', ENV.index(val).upcase) else assert_equal('test', ENV.index(val)) end assert_nil(ENV.index(val.upcase)) ENV['test'] = val.upcase assert_nil(ENV.index(val)) if IGNORE_CASE assert_equal('TEST', ENV.index(val.upcase).upcase) else assert_equal('test', ENV.index(val.upcase)) end end end ================================================ FILE: test/ruby/test_eval.rb ================================================ require 'test/unit' class TestEval < Test::Unit::TestCase # eval with binding def test_ev local1 = "local1" lambda { local2 = "local2" return binding }.call end def test_eval assert_nil(eval("")) $bad=false eval 'while false; $bad = true; print "foo\n" end' assert(!$bad) assert(eval('TRUE')) assert(eval('true')) assert(!eval('NIL')) assert(!eval('nil')) assert(!eval('FALSE')) assert(!eval('false')) $foo = 'assert(true)' begin eval $foo rescue assert(false) end assert_equal('assert(true)', eval("$foo")) assert_equal(true, eval("true")) i = 5 assert(eval("i == 5")) assert_equal(5, eval("i")) assert(eval("defined? i")) $x = test_ev assert_equal("local1", eval("local1", $x)) # normal local var assert_equal("local2", eval("local2", $x)) # nested local var $bad = true begin p eval("local1") rescue NameError # must raise error $bad = false end assert(!$bad) # !! use class_eval to avoid nested definition self.class.class_eval %q( module EvTest EVTEST1 = 25 evtest2 = 125 $x = binding end ) assert_equal(25, eval("EVTEST1", $x)) # constant in module assert_equal(125, eval("evtest2", $x)) # local var in module $bad = true begin eval("EVTEST1") rescue NameError # must raise error $bad = false end assert(!$bad) x = proc{} eval "i4 = 1", x assert_equal(1, eval("i4", x)) x = proc{proc{}}.call eval "i4 = 22", x assert_equal(22, eval("i4", x)) $x = [] x = proc{proc{}}.call eval "(0..9).each{|i5| $x[i5] = proc{i5*2}}", x assert_equal(8, $x[4].call) x = binding eval "i = 1", x assert_equal(1, eval("i", x)) x = proc{binding}.call eval "i = 22", x assert_equal(22, eval("i", x)) $x = [] x = proc{binding}.call eval "(0..9).each{|i5| $x[i5] = proc{i5*2}}", x assert_equal(8, $x[4].call) x = proc{binding}.call eval "for i6 in 1..1; j6=i6; end", x assert(eval("defined? i6", x)) assert(eval("defined? j6", x)) proc { p = binding eval "foo11 = 1", p foo22 = 5 proc{foo11=22}.call proc{foo22=55}.call assert_equal(eval("foo11"), eval("foo11", p)) assert_equal(1, eval("foo11")) assert_equal(eval("foo22"), eval("foo22", p)) assert_equal(55, eval("foo22")) }.call p1 = proc{i7 = 0; proc{i7}}.call assert_equal(0, p1.call) eval "i7=5", p1 assert_equal(5, p1.call) assert(!defined?(i7)) p1 = proc{i7 = 0; proc{i7}}.call i7 = nil assert_equal(0, p1.call) eval "i7=1", p1 assert_equal(1, p1.call) eval "i7=5", p1 assert_equal(5, p1.call) assert_nil(i7) end def test_nil_instance_eval_cvar # [ruby-dev:24103] def nil.test_binding binding end bb = eval("nil.instance_eval \"binding\"", nil.test_binding) assert_raise(NameError) { eval("@@a", bb) } class << nil remove_method :test_binding end end def test_fixnum_instance_eval_cvar # [ruby-dev:24213] assert_raise(NameError) { 1.instance_eval "@@a" } end def test_cvar_scope_with_instance_eval # [ruby-dev:24223] Fixnum.class_eval "@@test_cvar_scope_with_instance_eval = 1" # depends on [ruby-dev:24229] @@test_cvar_scope_with_instance_eval = 4 assert_equal(4, 1.instance_eval("@@test_cvar_scope_with_instance_eval")) Fixnum.__send__(:remove_class_variable, :@@test_cvar_scope_with_instance_eval) end def test_eval_and_define_method # [ruby-dev:24228] assert_nothing_raised { def temporally_method_for_test_eval_and_define_method(&block) lambda { class << Object.new; self end.__send__(:define_method, :zzz, &block) } end v = eval("temporally_method_for_test_eval_and_define_method {}") {}[0] = {} v.call } end end ================================================ FILE: test/ruby/test_exception.rb ================================================ require 'test/unit' class TestException < Test::Unit::TestCase def test_exception begin raise "this must be handled" assert(false) rescue assert(true) end $bad = true begin raise "this must be handled no.2" rescue if $bad $bad = false retry assert(false) end end assert(true) # exception in rescue clause $string = "this must be handled no.3" e = assert_raises(RuntimeError) do begin raise "exception in rescue clause" rescue raise $string end assert(false) end assert_equal($string, e.message) # exception in ensure clause $string = "exception in ensure clause" e = assert_raises(RuntimeError) do begin raise "this must be handled no.4" ensure assert_instance_of(RuntimeError, $!) assert_equal("this must be handled no.4", $!.message) raise "exception in ensure clause" end assert(false) end assert_equal($string, e.message) $bad = true begin begin raise "this must be handled no.5" ensure $bad = false end rescue end assert(!$bad) $bad = true begin begin raise "this must be handled no.6" ensure $bad = false end rescue end assert(!$bad) $bad = true while true begin break ensure $bad = false end end assert(!$bad) assert(catch(:foo) { loop do loop do throw :foo, true break end break assert(false) # should no reach here end false }) end def test_else begin assert(true) rescue assert(false) else assert(true) end begin assert(true) raise assert(false) rescue assert(true) else assert(false) end begin assert(true) begin assert(true) rescue assert(false) else assert(true) end assert(true) rescue assert(false) else assert(true) end begin assert(true) begin assert(true) raise assert(false) rescue assert(true) else assert(false) end assert(true) rescue assert(false) else assert(true) end begin assert(true) begin assert(true) rescue assert(false) else assert(true) end assert(true) raise assert(false) rescue assert(true) else assert(false) end begin assert(true) begin assert(true) raise assert(false) rescue assert(true) else assert(false) end assert(true) raise assert(false) rescue assert(true) else assert(false) end end end ================================================ FILE: test/ruby/test_file.rb ================================================ require 'test/unit' require 'tempfile' $:.replace([File.dirname(File.expand_path(__FILE__))] | $:) require 'ut_eof' class TestFile < Test::Unit::TestCase # I don't know Ruby's spec about "unlink-before-close" exactly. # This test asserts current behaviour. def test_unlink_before_close filename = File.basename(__FILE__) + ".#{$$}" w = File.open(filename, "w") w << "foo" w.close r = File.open(filename, "r") begin if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM begin File.unlink(filename) assert(false) rescue Errno::EACCES assert(true) end else File.unlink(filename) assert(true) end ensure r.close File.unlink(filename) if File.exist?(filename) end end include TestEOF def open_file(content) f = Tempfile.new("test-eof") f << content f.rewind yield f end alias open_file_rw open_file include TestEOF::Seek def test_fnmatch # from [ruby-dev:22815] and [ruby-dev:22819] assert(true, File.fnmatch('\[1\]' , '[1]')) assert(true, File.fnmatch('*?', 'a')) end def test_truncate_wbuf # [ruby-dev:24191] f = Tempfile.new("test-truncate") f.print "abc" f.truncate(0) f.print "def" f.close assert_equal("\0\0\0def", File.read(f.path)) end def test_truncate_rbuf # [ruby-dev:24197] f = Tempfile.new("test-truncate") f.puts "abc" f.puts "def" f.close f.open assert_equal("abc\n", f.gets) f.truncate(3) assert_equal(nil, f.gets) end def test_read_all_extended_file f = Tempfile.new("test-extended-file") assert_nil(f.getc) open(f.path, "w") {|g| g.print "a" } assert_equal("a", f.read) end def test_gets_extended_file f = Tempfile.new("test-extended-file") assert_nil(f.getc) open(f.path, "w") {|g| g.print "a" } assert_equal("a", f.gets("a")) end def test_gets_para_extended_file f = Tempfile.new("test-extended-file") assert_nil(f.getc) open(f.path, "w") {|g| g.print "\na" } assert_equal("a", f.gets("")) end def test_each_byte_extended_file f = Tempfile.new("test-extended-file") assert_nil(f.getc) open(f.path, "w") {|g| g.print "a" } result = [] f.each_byte {|b| result << b } assert_equal([?a], result) end def test_getc_extended_file f = Tempfile.new("test-extended-file") assert_nil(f.getc) open(f.path, "w") {|g| g.print "a" } assert_equal(?a, f.getc) end end ================================================ FILE: test/ruby/test_file_exhaustive.rb ================================================ require "test/unit" require "fileutils" require "tmpdir" class TestFileExhaustive < Test::Unit::TestCase def setup @dir = Dir.mktmpdir("rubytest-file") File.chown(-1, Process.gid, @dir) @file = make_tmp_filename("file") @zerofile = make_tmp_filename("zerofile") @nofile = make_tmp_filename("nofile") @symlinkfile = make_tmp_filename("symlinkfile") @hardlinkfile = make_tmp_filename("hardlinkfile") make_file("foo", @file) make_file("", @zerofile) @time = Time.now begin File.symlink(@file, @symlinkfile) rescue NotImplementedError @symlinkfile = nil end begin File.link(@file, @hardlinkfile) rescue NotImplementedError, Errno::EINVAL # EINVAL for Windows Vista @hardlinkfile = nil end end def teardown GC.start FileUtils.remove_entry_secure @dir end def make_file(content, file = @file) open(file, "w") {|fh| fh << content } end def make_tmp_filename(prefix) @hardlinkfile = @dir + "/" + prefix + File.basename(__FILE__) + ".#{$$}.test" end def test_path file = @file assert_equal(file, File.open(file) {|f| f.path}) end def assert_integer(n) assert(n.is_a?(Integer), n.inspect + " is not Fixnum.") end def assert_integer_or_nil(n) assert(n.is_a?(Integer) || n.equal?(nil), n.inspect + " is neither Fixnum nor nil.") end def test_stat sleep(@time - Time.now + 1.1) make_file("foo", @file + "2") fs1, fs2 = File.stat(@file), File.stat(@file + "2") assert_nothing_raised do assert_equal(0, fs1 <=> fs1) assert_equal(-1, fs1 <=> fs2) assert_equal(1, fs2 <=> fs1) assert_nil(fs1 <=> nil) assert_integer(fs1.dev) assert_integer_or_nil(fs1.rdev) assert_integer_or_nil(fs1.dev_major) assert_integer_or_nil(fs1.dev_minor) assert_integer_or_nil(fs1.rdev_major) assert_integer_or_nil(fs1.rdev_minor) assert_integer(fs1.ino) assert_integer(fs1.mode) unless /emx/ =~ RUBY_PLATFORM assert_equal(@hardlinkfile ? 2 : 1, fs1.nlink) end assert_integer(fs1.uid) assert_integer(fs1.gid) assert_equal(3, fs1.size) assert_integer_or_nil(fs1.blksize) assert_integer_or_nil(fs1.blocks) assert_kind_of(Time, fs1.atime) assert_kind_of(Time, fs1.mtime) assert_kind_of(Time, fs1.ctime) assert_kind_of(String, fs1.inspect) end assert_raise(Errno::ENOENT) { File.stat(@nofile) } assert_kind_of(File::Stat, File.open(@file) {|f| f.stat}) assert_raise(Errno::ENOENT) { File.lstat(@nofile) } assert_kind_of(File::Stat, File.open(@file) {|f| f.lstat}) end def test_directory_p assert(File.directory?(@dir)) assert(!(File.directory?(@dir+"/..."))) assert(!(File.directory?(@file))) assert(!(File.directory?(@nofile))) end def test_pipe_p ## xxx assert(!(File.pipe?(@dir))) assert(!(File.pipe?(@file))) assert(!(File.pipe?(@nofile))) end def test_symlink_p assert(!(File.symlink?(@dir))) assert(!(File.symlink?(@file))) assert(File.symlink?(@symlinkfile)) if @symlinkfile assert(!(File.symlink?(@hardlinkfile))) if @hardlinkfile assert(!(File.symlink?(@nofile))) end def test_socket_p ## xxx assert(!(File.socket?(@dir))) assert(!(File.socket?(@file))) assert(!(File.socket?(@nofile))) end def test_blockdev_p ## xxx assert(!(File.blockdev?(@dir))) assert(!(File.blockdev?(@file))) assert(!(File.blockdev?(@nofile))) end def test_chardev_p ## xxx assert(!(File.chardev?(@dir))) assert(!(File.chardev?(@file))) assert(!(File.chardev?(@nofile))) end def test_exist_p assert(File.exist?(@dir)) assert(File.exist?(@file)) assert(!(File.exist?(@nofile))) end def test_readable_p return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM File.chmod(0200, @file) assert(!(File.readable?(@file))) File.chmod(0600, @file) assert(File.readable?(@file)) assert(!(File.readable?(@nofile))) end def test_readable_real_p return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM File.chmod(0200, @file) assert(!(File.readable_real?(@file))) File.chmod(0600, @file) assert(File.readable_real?(@file)) assert(!(File.readable_real?(@nofile))) end def test_writable_p return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM File.chmod(0400, @file) assert(!(File.writable?(@file))) File.chmod(0600, @file) assert(File.writable?(@file)) assert(!(File.writable?(@nofile))) end def test_writable_real_p return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM File.chmod(0400, @file) assert(!(File.writable_real?(@file))) File.chmod(0600, @file) assert(File.writable_real?(@file)) assert(!(File.writable_real?(@nofile))) end def test_executable_p return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM File.chmod(0100, @file) assert(File.executable?(@file)) File.chmod(0600, @file) assert(!(File.executable?(@file))) assert(!(File.executable?(@nofile))) end def test_executable_real_p return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM File.chmod(0100, @file) assert(File.executable_real?(@file)) File.chmod(0600, @file) assert(!(File.executable_real?(@file))) assert(!(File.executable_real?(@nofile))) end def test_file_p assert(!(File.file?(@dir))) assert(File.file?(@file)) assert(!(File.file?(@nofile))) end def test_zero_p assert_nothing_raised { File.zero?(@dir) } assert(!(File.zero?(@file))) assert(File.zero?(@zerofile)) assert(!(File.zero?(@nofile))) end def test_size_p assert_nothing_raised { File.size?(@dir) } assert_equal(3, File.size?(@file)) assert(!(File.size?(@zerofile))) assert(!(File.size?(@nofile))) end def test_owned_p ## xxx return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM assert(File.owned?(@file)) assert(File.grpowned?(@file)) end def test_suid_sgid_sticky ## xxx assert(!(File.setuid?(@file))) assert(!(File.setgid?(@file))) assert(!(File.sticky?(@file))) end def test_identical_p assert(File.identical?(@file, @file)) assert(!(File.identical?(@file, @zerofile))) assert(!(File.identical?(@file, @nofile))) assert(!(File.identical?(@nofile, @file))) end def test_size assert_integer(File.size(@dir)) assert_equal(3, File.size(@file)) assert_equal(0, File.size(@zerofile)) assert_raise(Errno::ENOENT) { File.size(@nofile) } end def test_ftype assert_equal("directory", File.ftype(@dir)) assert_equal("file", File.ftype(@file)) assert_equal("link", File.ftype(@symlinkfile)) if @symlinkfile assert_equal("file", File.ftype(@hardlinkfile)) if @hardlinkfile assert_raise(Errno::ENOENT) { File.ftype(@nofile) } end def test_atime t1 = File.atime(@file) t2 = File.open(@file) {|f| f.atime} assert_kind_of(Time, t1) assert_kind_of(Time, t2) assert_equal(t1, t2) assert_raise(Errno::ENOENT) { File.atime(@nofile) } end def test_mtime t1 = File.mtime(@file) t2 = File.open(@file) {|f| f.mtime} assert_kind_of(Time, t1) assert_kind_of(Time, t2) assert_equal(t1, t2) assert_raise(Errno::ENOENT) { File.mtime(@nofile) } end def test_ctime t1 = File.ctime(@file) t2 = File.open(@file) {|f| f.ctime} assert_kind_of(Time, t1) assert_kind_of(Time, t2) assert_equal(t1, t2) assert_raise(Errno::ENOENT) { File.ctime(@nofile) } end def test_chmod return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM assert_equal(1, File.chmod(0444, @file)) assert_equal(0444, File.stat(@file).mode % 01000) assert_equal(0, File.open(@file) {|f| f.chmod(0222)}) assert_equal(0222, File.stat(@file).mode % 01000) File.chmod(0600, @file) assert_raise(Errno::ENOENT) { File.chmod(0600, @nofile) } end def test_lchmod return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM assert_equal(1, File.lchmod(0444, @file)) assert_equal(0444, File.stat(@file).mode % 01000) File.lchmod(0600, @file) assert_raise(Errno::ENOENT) { File.lchmod(0600, @nofile) } rescue NotImplementedError end def test_chown ## xxx end def test_lchown ## xxx end def test_symlink return unless @symlinkfile assert_equal("link", File.ftype(@symlinkfile)) assert_raise(Errno::EEXIST) { File.symlink(@file, @file) } end def test_utime t = Time.local(2000) File.utime(t + 1, t + 2, @zerofile) assert_equal(t + 1, File.atime(@zerofile)) assert_equal(t + 2, File.mtime(@zerofile)) end def test_hardlink return unless @hardlinkfile assert_equal("file", File.ftype(@hardlinkfile)) assert_raise(Errno::EEXIST) { File.link(@file, @file) } end def test_symlink2 return unless @symlinkfile assert_equal(@file, File.readlink(@symlinkfile)) assert_raise(Errno::EINVAL) { File.readlink(@file) } assert_raise(Errno::ENOENT) { File.readlink(@nofile) } rescue NotImplementedError end def test_unlink assert_equal(1, File.unlink(@file)) make_file("foo", @file) assert_raise(Errno::ENOENT) { File.unlink(@nofile) } end def test_rename assert_equal(0, File.rename(@file, @nofile)) assert(!(File.exist?(@file))) assert(File.exist?(@nofile)) assert_equal(0, File.rename(@nofile, @file)) assert_raise(Errno::ENOENT) { File.rename(@nofile, @file) } end def test_umask return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM prev = File.umask(0777) assert_equal(0777, File.umask) open(@nofile, "w") { } assert_equal(0, File.stat(@nofile).mode % 01000) File.unlink(@nofile) assert_equal(0777, File.umask(prev)) assert_raise(ArgumentError) { File.umask(0, 1, 2) } end def test_expand_path assert_equal(@file, File.expand_path(File.basename(@file), File.dirname(@file))) if /cygwin|mingw|mswin|bccwin/ =~ RUBY_PLATFORM assert_equal(@file, File.expand_path(@file + " ")) assert_equal(@file, File.expand_path(@file + ".")) assert_equal(@file, File.expand_path(@file + "::$DATA")) end end def test_basename assert_equal(File.basename(@file).sub(/\.test$/, ""), File.basename(@file, ".test")) assert_equal("", File.basename("")) assert_equal("foo", File.basename("foo")) assert_equal("foo", File.basename("foo", ".ext")) assert_equal("foo", File.basename("foo.ext", ".ext")) assert_equal("foo", File.basename("foo.ext", ".*")) if /cygwin|mingw|mswin|bccwin/ =~ RUBY_PLATFORM basename = File.basename(@file) assert_equal(basename, File.basename(@file + " ")) assert_equal(basename, File.basename(@file + ".")) assert_equal(basename, File.basename(@file + "::$DATA")) basename.chomp!(".test") assert_equal(basename, File.basename(@file + " ", ".test")) assert_equal(basename, File.basename(@file + ".", ".test")) assert_equal(basename, File.basename(@file + "::$DATA", ".test")) assert_equal(basename, File.basename(@file + " ", ".*")) assert_equal(basename, File.basename(@file + ".", ".*")) assert_equal(basename, File.basename(@file + "::$DATA", ".*")) end end def test_dirname assert(@file.start_with?(File.dirname(@file))) assert_equal(".", File.dirname("")) end def test_extname assert(".test", File.extname(@file)) prefixes = ["", "/", ".", "/.", "bar/.", "/bar/."] infixes = ["", " ", "."] infixes2 = infixes + [".ext "] appendixes = [""] if /cygwin|mingw|mswin|bccwin/ =~ RUBY_PLATFORM appendixes << " " << "." << "::$DATA" << "::$DATA.bar" end prefixes.each do |prefix| appendixes.each do |appendix| infixes.each do |infix| path = "#{prefix}foo#{infix}#{appendix}" assert_equal("", File.extname(path), "File.extname(#{path.inspect})") end infixes2.each do |infix| path = "#{prefix}foo#{infix}.ext#{appendix}" assert_equal(".ext", File.extname(path), "File.extname(#{path.inspect})") end end end end def test_split d, b = File.split(@file) assert_equal(File.dirname(@file), d) assert_equal(File.basename(@file), b) end def test_join s = "foo" + File::SEPARATOR + "bar" + File::SEPARATOR + "baz" assert_equal(s, File.join("foo", "bar", "baz")) assert_equal(s, File.join(["foo", "bar", "baz"])) assert_equal(s, File.join("foo" + File::SEPARATOR, "bar", File::SEPARATOR + "baz")) end def test_truncate assert_equal(0, File.truncate(@file, 1)) assert(File.exist?(@file)) assert_equal(1, File.size(@file)) assert_equal(0, File.truncate(@file, 0)) assert(File.exist?(@file)) assert(File.zero?(@file)) make_file("foo", @file) assert_raise(Errno::ENOENT) { File.truncate(@nofile, 0) } f = File.new(@file, "w") assert_equal(0, f.truncate(2)) assert(File.exist?(@file)) assert_equal(2, File.size(@file)) assert_equal(0, f.truncate(0)) assert(File.exist?(@file)) assert(File.zero?(@file)) f.close make_file("foo", @file) assert_raise(IOError) { File.open(@file) {|f| f.truncate(0)} } rescue NotImplementedError end def test_flock ## xxx f = File.new(@file, "r+") f.flock(File::LOCK_EX) f.flock(File::LOCK_SH) f.flock(File::LOCK_UN) f.close rescue NotImplementedError end def test_test sleep(@time - Time.now + 1.1) make_file("foo", @file + "2") [@dir, @file, @zerofile, @symlinkfile, @hardlinkfile].compact.each do |f| assert_equal(File.atime(f), test(?A, f)) assert_equal(File.ctime(f), test(?C, f)) assert_equal(File.mtime(f), test(?M, f)) assert_equal(File.blockdev?(f), test(?b, f)) assert_equal(File.chardev?(f), test(?c, f)) assert_equal(File.directory?(f), test(?d, f)) assert_equal(File.exist?(f), test(?e, f)) assert_equal(File.file?(f), test(?f, f)) assert_equal(File.setgid?(f), test(?g, f)) assert_equal(File.grpowned?(f), test(?G, f)) assert_equal(File.sticky?(f), test(?k, f)) assert_equal(File.symlink?(f), test(?l, f)) assert_equal(File.owned?(f), test(?o, f)) assert_nothing_raised { test(?O, f) } assert_equal(File.pipe?(f), test(?p, f)) assert_equal(File.readable?(f), test(?r, f)) assert_equal(File.readable_real?(f), test(?R, f)) assert_equal(File.size?(f), test(?s, f)) assert_equal(File.socket?(f), test(?S, f)) assert_equal(File.setuid?(f), test(?u, f)) assert_equal(File.writable?(f), test(?w, f)) assert_equal(File.executable?(f), test(?x, f)) assert_equal(File.executable_real?(f), test(?X, f)) assert_equal(File.zero?(f), test(?z, f)) end assert_equal(false, test(?-, @dir, @file)) assert_equal(true, test(?-, @file, @file)) assert_equal(true, test(?=, @file, @file)) assert_equal(false, test(?>, @file, @file)) assert_equal(false, test(?<, @file, @file)) unless /cygwin/ =~ RUBY_PLATFORM assert_equal(false, test(?=, @file, @file + "2")) assert_equal(false, test(?>, @file, @file + "2")) assert_equal(true, test(?>, @file + "2", @file)) assert_equal(true, test(?<, @file, @file + "2")) assert_equal(false, test(?<, @file + "2", @file)) end assert_raise(ArgumentError) { test } assert_raise(Errno::ENOENT) { test(?A, @nofile) } assert_raise(ArgumentError) { test(?a) } end def test_stat_init sleep(@time - Time.now + 1.1) make_file("foo", @file + "2") fs1, fs2 = File::Stat.new(@file), File::Stat.new(@file + "2") assert_nothing_raised do assert_equal(0, fs1 <=> fs1) assert_equal(-1, fs1 <=> fs2) assert_equal(1, fs2 <=> fs1) assert_nil(fs1 <=> nil) assert_integer(fs1.dev) assert_integer_or_nil(fs1.rdev) assert_integer_or_nil(fs1.dev_major) assert_integer_or_nil(fs1.dev_minor) assert_integer_or_nil(fs1.rdev_major) assert_integer_or_nil(fs1.rdev_minor) assert_integer(fs1.ino) assert_integer(fs1.mode) unless /emx/ =~ RUBY_PLATFORM assert_equal(@hardlinkfile ? 2 : 1, fs1.nlink) end assert_integer(fs1.uid) assert_integer(fs1.gid) assert_equal(3, fs1.size) assert_integer_or_nil(fs1.blksize) assert_integer_or_nil(fs1.blocks) assert_kind_of(Time, fs1.atime) assert_kind_of(Time, fs1.mtime) assert_kind_of(Time, fs1.ctime) assert_kind_of(String, fs1.inspect) end assert_raise(Errno::ENOENT) { File::Stat.new(@nofile) } assert_kind_of(File::Stat, File::Stat.new(@file).dup) assert_raise(TypeError) do File::Stat.new(@file).instance_eval { initialize_copy(0) } end end def test_stat_ftype assert_equal("directory", File::Stat.new(@dir).ftype) assert_equal("file", File::Stat.new(@file).ftype) # File::Stat uses stat assert_equal("file", File::Stat.new(@symlinkfile).ftype) if @symlinkfile assert_equal("file", File::Stat.new(@hardlinkfile).ftype) if @hardlinkfile end def test_stat_directory_p assert(File::Stat.new(@dir).directory?) assert(!(File::Stat.new(@file).directory?)) end def test_stat_pipe_p ## xxx assert(!(File::Stat.new(@dir).pipe?)) assert(!(File::Stat.new(@file).pipe?)) end def test_stat_symlink_p assert(!(File::Stat.new(@dir).symlink?)) assert(!(File::Stat.new(@file).symlink?)) # File::Stat uses stat assert(!(File::Stat.new(@symlinkfile).symlink?)) if @symlinkfile assert(!(File::Stat.new(@hardlinkfile).symlink?)) if @hardlinkfile end def test_stat_socket_p ## xxx assert(!(File::Stat.new(@dir).socket?)) assert(!(File::Stat.new(@file).socket?)) end def test_stat_blockdev_p ## xxx assert(!(File::Stat.new(@dir).blockdev?)) assert(!(File::Stat.new(@file).blockdev?)) end def test_stat_chardev_p ## xxx assert(!(File::Stat.new(@dir).chardev?)) assert(!(File::Stat.new(@file).chardev?)) end def test_stat_readable_p return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM File.chmod(0200, @file) assert(!(File::Stat.new(@file).readable?)) File.chmod(0600, @file) assert(File::Stat.new(@file).readable?) end def test_stat_readable_real_p return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM File.chmod(0200, @file) assert(!(File::Stat.new(@file).readable_real?)) File.chmod(0600, @file) assert(File::Stat.new(@file).readable_real?) end def test_stat_writable_p return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM File.chmod(0400, @file) assert(!(File::Stat.new(@file).writable?)) File.chmod(0600, @file) assert(File::Stat.new(@file).writable?) end def test_stat_writable_real_p return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM File.chmod(0400, @file) assert(!(File::Stat.new(@file).writable_real?)) File.chmod(0600, @file) assert(File::Stat.new(@file).writable_real?) end def test_stat_executable_p return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM File.chmod(0100, @file) assert(File::Stat.new(@file).executable?) File.chmod(0600, @file) assert(!(File::Stat.new(@file).executable?)) end def test_stat_executable_real_p return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM File.chmod(0100, @file) assert(File::Stat.new(@file).executable_real?) File.chmod(0600, @file) assert(!(File::Stat.new(@file).executable_real?)) end def test_stat_file_p assert(!(File::Stat.new(@dir).file?)) assert(File::Stat.new(@file).file?) end def test_stat_zero_p assert_nothing_raised { File::Stat.new(@dir).zero? } assert(!(File::Stat.new(@file).zero?)) assert(File::Stat.new(@zerofile).zero?) end def test_stat_size_p assert_nothing_raised { File::Stat.new(@dir).size? } assert_equal(3, File::Stat.new(@file).size?) assert(!(File::Stat.new(@zerofile).size?)) end def test_stat_owned_p ## xxx return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM assert(File::Stat.new(@file).owned?) assert(File::Stat.new(@file).grpowned?) end def test_stat_suid_sgid_sticky ## xxx assert(!(File::Stat.new(@file).setuid?)) assert(!(File::Stat.new(@file).setgid?)) assert(!(File::Stat.new(@file).sticky?)) end def test_stat_size assert_integer(File::Stat.new(@dir).size) assert_equal(3, File::Stat.new(@file).size) assert_equal(0, File::Stat.new(@zerofile).size) end def test_path_check assert_nothing_raised { ENV["PATH"] } end def test_find_file assert_raise(SecurityError) do Thread.new do $SAFE = 4 load(@file) end.join end end end ================================================ FILE: test/ruby/test_fixnum.rb ================================================ require 'test/unit' class TestFixnum < Test::Unit::TestCase def setup @verbose = $VERBOSE $VERBOSE = nil end def teardown $VERBOSE = @verbose end def test_pow [1, 2, 2**64, 2**63*3, 2**64*3].each do |y| [-1, 0, 1].each do |x| z1 = x**y z2 = (-x)**y if y % 2 == 1 assert_equal(z2, -z1) else assert_equal(z2, z1) end end end end end ================================================ FILE: test/ruby/test_float.rb ================================================ require 'test/unit' class TestFloat < Test::Unit::TestCase def test_float assert_equal(2, 2.6.floor) assert_equal(-3, (-2.6).floor) assert_equal(3, 2.6.ceil) assert_equal(-2, (-2.6).ceil) assert_equal(2, 2.6.truncate) assert_equal(-2, (-2.6).truncate) assert_equal(3, 2.6.round) assert_equal(-2, (-2.4).truncate) assert((13.4 % 1 - 0.4).abs < 0.0001) end def nan_test(x,y) extend Test::Unit::Assertions assert(x != y) assert_equal(false, (x < y)) assert_equal(false, (x > y)) assert_equal(false, (x <= y)) assert_equal(false, (x >= y)) end def test_nan nan = 0.0/0 nan_test(nan, nan) nan_test(nan, 0) nan_test(nan, 1) nan_test(nan, -1) nan_test(nan, 1000) nan_test(nan, -1000) nan_test(nan, 1_000_000_000_000) nan_test(nan, -1_000_000_000_000) nan_test(nan, 100.0); nan_test(nan, -100.0); nan_test(nan, 0.001); nan_test(nan, -0.001); nan_test(nan, 1.0/0); nan_test(nan, -1.0/0); end def test_precision u = 3.7517675036461267e+17 v = sprintf("%.16e", u).to_f assert_in_delta(u, v, u.abs * Float::EPSILON) assert_in_delta(u, v, v.abs * Float::EPSILON) end def test_symmetry_bignum # [ruby-bugs-ja:118] a = 100000000000000000000000 b = 100000000000000000000000.0 assert_equal(a == b, b == a) end def test_strtod a = Float("0") assert(a.abs < Float::EPSILON) a = Float("0.0") assert(a.abs < Float::EPSILON) a = Float("+0.0") assert(a.abs < Float::EPSILON) a = Float("-0.0") assert(a.abs < Float::EPSILON) a = Float("0.0000000000000000001") assert(a != 0.0) a = Float("+0.0000000000000000001") assert(a != 0.0) a = Float("-0.0000000000000000001") assert(a != 0.0) a = Float(".0") assert(a.abs < Float::EPSILON) a = Float("+.0") assert(a.abs < Float::EPSILON) a = Float("-.0") assert(a.abs < Float::EPSILON) assert(a.abs < Float::EPSILON) assert_raise(ArgumentError){Float(".")} assert_raise(ArgumentError){Float("+")} assert_raise(ArgumentError){Float("+.")} assert_raise(ArgumentError){Float("-")} assert_raise(ArgumentError){Float("-.")} assert_raise(ArgumentError){Float("1e")} # add expected behaviour here. end def test_divmod assert_equal([2, 3.5], 11.5.divmod(4)) assert_equal([-3, -0.5], 11.5.divmod(-4)) assert_equal([-3, 0.5], (-11.5).divmod(4)) assert_equal([2, -3.5], (-11.5).divmod(-4)) end def test_div assert_equal(2, 11.5.div(4)) assert_equal(-3, 11.5.div(-4)) assert_equal(-3, (-11.5).div(4)) assert_equal(2, (-11.5).div(-4)) end def test_modulo assert_equal(3.5, 11.5.modulo(4)) assert_equal(-0.5, 11.5.modulo(-4)) assert_equal(0.5, (-11.5).modulo(4)) assert_equal(-3.5, (-11.5).modulo(-4)) end def test_remainder assert_equal(3.5, 11.5.remainder(4)) assert_equal(3.5, 11.5.remainder(-4)) assert_equal(-3.5, (-11.5).remainder(4)) assert_equal(-3.5, (-11.5).remainder(-4)) end def test_to_i assert_operator(4611686018427387905.0.to_i, :>, 0) assert_operator(4611686018427387904.0.to_i, :>, 0) assert_operator(4611686018427387903.8.to_i, :>, 0) assert_operator(4611686018427387903.5.to_i, :>, 0) assert_operator(4611686018427387903.2.to_i, :>, 0) assert_operator(4611686018427387903.0.to_i, :>, 0) assert_operator(4611686018427387902.0.to_i, :>, 0) assert_operator(1073741825.0.to_i, :>, 0) assert_operator(1073741824.0.to_i, :>, 0) assert_operator(1073741823.8.to_i, :>, 0) assert_operator(1073741823.5.to_i, :>, 0) assert_operator(1073741823.2.to_i, :>, 0) assert_operator(1073741823.0.to_i, :>, 0) assert_operator(1073741822.0.to_i, :>, 0) assert_operator((-1073741823.0).to_i, :<, 0) assert_operator((-1073741824.0).to_i, :<, 0) assert_operator((-1073741824.2).to_i, :<, 0) assert_operator((-1073741824.5).to_i, :<, 0) assert_operator((-1073741824.8).to_i, :<, 0) assert_operator((-1073741825.0).to_i, :<, 0) assert_operator((-1073741826.0).to_i, :<, 0) assert_operator((-4611686018427387903.0).to_i, :<, 0) assert_operator((-4611686018427387904.0).to_i, :<, 0) assert_operator((-4611686018427387904.2).to_i, :<, 0) assert_operator((-4611686018427387904.5).to_i, :<, 0) assert_operator((-4611686018427387904.8).to_i, :<, 0) assert_operator((-4611686018427387905.0).to_i, :<, 0) assert_operator((-4611686018427387906.0).to_i, :<, 0) end end ================================================ FILE: test/ruby/test_gc.rb ================================================ require 'test/unit' class TestGc < Test::Unit::TestCase class S def initialize(a) @a = a end end def test_gc assert_nothing_raised do 1.upto(10000) { tmp = [0,1,2,3,4,5,6,7,8,9] } tmp = nil end l=nil 100000.times { l = S.new(l) } GC.start assert true # reach here or dumps core l = [] 100000.times { l.push([l]) } GC.start assert true # reach here or dumps core 100000.times { Time.now } assert true, '[ruby-dev:39201]' # reach here or dumps core end end ================================================ FILE: test/ruby/test_hash.rb ================================================ require 'test/unit' class TestHash < Test::Unit::TestCase def test_hash x = {1=>2, 2=>4, 3=>6} y = {1, 2, 2, 4, 3, 6} assert_equal(2, x[1]) assert(begin for k,v in y raise if k*2 != v end true rescue false end) assert_equal(3, x.length) assert(x.has_key?(1)) assert(x.has_value?(4)) assert_equal([4,6], x.values_at(2,3)) assert_equal({1=>2, 2=>4, 3=>6}, x) z = y.keys.join(":") assert_equal("1:2:3", z) z = y.values.join(":") assert_equal("2:4:6", z) assert_equal(x, y) y.shift assert_equal(2, y.length) z = [1,2] y[z] = 256 assert_equal(256, y[z]) x = Hash.new(0) x[1] = 1 assert_equal(1, x[1]) assert_equal(0, x[2]) x = Hash.new([]) assert_equal([], x[22]) assert_same(x[22], x[22]) x = Hash.new{[]} assert_equal([], x[22]) assert_not_same(x[22], x[22]) x = Hash.new{|h,k| z = k; h[k] = k*2} z = 0 assert_equal(44, x[22]) assert_equal(22, z) z = 0 assert_equal(44, x[22]) assert_equal(0, z) x.default = 5 assert_equal(5, x[23]) x = Hash.new def x.default(k) $z = k self[k] = k*2 end $z = 0 assert_equal(44, x[22]) assert_equal(22, $z) $z = 0 assert_equal(44, x[22]) assert_equal(0, $z) end # From rubicon def setup @cls = Hash @h = @cls[ 1 => 'one', 2 => 'two', 3 => 'three', self => 'self', true => 'true', nil => 'nil', 'nil' => nil ] end def test_s_AREF h = @cls["a" => 100, "b" => 200] assert_equal(100, h['a']) assert_equal(200, h['b']) assert_nil(h['c']) h = @cls.[]("a" => 100, "b" => 200) assert_equal(100, h['a']) assert_equal(200, h['b']) assert_nil(h['c']) end def test_s_new h = @cls.new assert_instance_of(@cls, h) assert_nil(h.default) assert_nil(h['spurious']) h = @cls.new('default') assert_instance_of(@cls, h) assert_equal('default', h.default) assert_equal('default', h['spurious']) end def test_AREF # '[]' t = Time.now h = @cls[ 1 => 'one', 2 => 'two', 3 => 'three', self => 'self', t => 'time', nil => 'nil', 'nil' => nil ] assert_equal('one', h[1]) assert_equal('two', h[2]) assert_equal('three', h[3]) assert_equal('self', h[self]) assert_equal('time', h[t]) assert_equal('nil', h[nil]) assert_equal(nil, h['nil']) assert_equal(nil, h['koala']) h1 = h.dup h1.default = :default assert_equal('one', h1[1]) assert_equal('two', h1[2]) assert_equal('three', h1[3]) assert_equal('self', h1[self]) assert_equal('time', h1[t]) assert_equal('nil', h1[nil]) assert_equal(nil, h1['nil']) assert_equal(:default, h1['koala']) end def test_ASET # '[]=' t = Time.now h = @cls.new h[1] = 'one' h[2] = 'two' h[3] = 'three' h[self] = 'self' h[t] = 'time' h[nil] = 'nil' h['nil'] = nil assert_equal('one', h[1]) assert_equal('two', h[2]) assert_equal('three', h[3]) assert_equal('self', h[self]) assert_equal('time', h[t]) assert_equal('nil', h[nil]) assert_equal(nil, h['nil']) assert_equal(nil, h['koala']) h[1] = 1 h[nil] = 99 h['nil'] = nil z = [1,2] h[z] = 256 assert_equal(1, h[1]) assert_equal('two', h[2]) assert_equal('three', h[3]) assert_equal('self', h[self]) assert_equal('time', h[t]) assert_equal(99, h[nil]) assert_equal(nil, h['nil']) assert_equal(nil, h['koala']) assert_equal(256, h[z]) end def test_EQUAL # '==' h1 = @cls[ "a" => 1, "c" => 2 ] h2 = @cls[ "a" => 1, "c" => 2, 7 => 35 ] h3 = @cls[ "a" => 1, "c" => 2, 7 => 35 ] h4 = @cls[ ] assert(h1 == h1) assert(h2 == h2) assert(h3 == h3) assert(h4 == h4) assert(!(h1 == h2)) assert(h2 == h3) assert(!(h3 == h4)) end def test_clear assert(@h.size > 0) @h.clear assert_equal(0, @h.size) assert_nil(@h[1]) end def test_clone for taint in [ false, true ] for frozen in [ false, true ] a = @h.clone a.taint if taint a.freeze if frozen b = a.clone assert_equal(a, b) assert(a.__id__ != b.__id__) assert_equal(a.frozen?, b.frozen?) assert_equal(a.tainted?, b.tainted?) end end end def test_default assert_nil(@h.default) h = @cls.new(:xyzzy) assert_equal(:xyzzy, h.default) end def test_default= assert_nil(@h.default) @h.default = :xyzzy assert_equal(:xyzzy, @h.default) end def test_delete h1 = @cls[ 1 => 'one', 2 => 'two', true => 'true' ] h2 = @cls[ 1 => 'one', 2 => 'two' ] h3 = @cls[ 2 => 'two' ] assert_equal('true', h1.delete(true)) assert_equal(h2, h1) assert_equal('one', h1.delete(1)) assert_equal(h3, h1) assert_equal('two', h1.delete(2)) assert_equal(@cls[], h1) assert_nil(h1.delete(99)) assert_equal(@cls[], h1) assert_equal('default 99', h1.delete(99) {|i| "default #{i}" }) end def test_delete_if base = @cls[ 1 => 'one', 2 => false, true => 'true', 'cat' => 99 ] h1 = @cls[ 1 => 'one', 2 => false, true => 'true' ] h2 = @cls[ 2 => false, 'cat' => 99 ] h3 = @cls[ 2 => false ] h = base.dup assert_equal(h, h.delete_if { false }) assert_equal(@cls[], h.delete_if { true }) h = base.dup assert_equal(h1, h.delete_if {|k,v| k.instance_of?(String) }) assert_equal(h1, h) h = base.dup assert_equal(h2, h.delete_if {|k,v| v.instance_of?(String) }) assert_equal(h2, h) h = base.dup assert_equal(h3, h.delete_if {|k,v| v }) assert_equal(h3, h) h = base.dup n = 0 h.delete_if {|*a| n += 1 assert_equal(2, a.size) assert_equal(base[a[0]], a[1]) h.shift true } assert_equal(base.size, n) end def test_dup for taint in [ false, true ] for frozen in [ false, true ] a = @h.dup a.taint if taint a.freeze if frozen b = a.dup assert_equal(a, b) assert(a.__id__ != b.__id__) assert_equal(false, b.frozen?) assert_equal(a.tainted?, b.tainted?) end end end def test_each count = 0 @cls[].each { |k, v| count + 1 } assert_equal(0, count) h = @h h.each do |k, v| assert_equal(v, h.delete(k)) end assert_equal(@cls[], h) end def test_each_key count = 0 @cls[].each_key { |k| count + 1 } assert_equal(0, count) h = @h h.each_key do |k| h.delete(k) end assert_equal(@cls[], h) end def test_each_pair count = 0 @cls[].each_pair { |k, v| count + 1 } assert_equal(0, count) h = @h h.each_pair do |k, v| assert_equal(v, h.delete(k)) end assert_equal(@cls[], h) end def test_each_value res = [] @cls[].each_value { |v| res << v } assert_equal(0, [].length) @h.each_value { |v| res << v } assert_equal(0, [].length) expected = [] @h.each { |k, v| expected << v } assert_equal([], expected - res) assert_equal([], res - expected) end def test_empty? assert(@cls[].empty?) assert(!@h.empty?) end def test_fetch assert_raise(IndexError) { @cls[].fetch(1) } assert_raise(IndexError) { @h.fetch('gumby') } assert_equal('gumbygumby', @h.fetch('gumby') {|k| k * 2 }) assert_equal('pokey', @h.fetch('gumby', 'pokey')) assert_equal('one', @h.fetch(1)) assert_equal(nil, @h.fetch('nil')) assert_equal('nil', @h.fetch(nil)) end def test_key? assert(!@cls[].key?(1)) assert(!@cls[].key?(nil)) assert(@h.key?(nil)) assert(@h.key?(1)) assert(!@h.key?('gumby')) end def test_value? assert(!@cls[].value?(1)) assert(!@cls[].value?(nil)) assert(@h.value?('one')) assert(@h.value?(nil)) assert(!@h.value?('gumby')) end def test_include? assert(!@cls[].include?(1)) assert(!@cls[].include?(nil)) assert(@h.include?(nil)) assert(@h.include?(1)) assert(!@h.include?('gumby')) end def test_values_at res = @h.values_at('dog', 'cat', 'horse') assert(res.length == 3) assert_equal([nil, nil, nil], res) res = @h.values_at assert(res.length == 0) res = @h.values_at(3, 2, 1, nil) assert_equal 4, res.length assert_equal %w( three two one nil ), res res = @h.values_at(3, 99, 1, nil) assert_equal 4, res.length assert_equal ['three', nil, 'one', 'nil'], res end def test_invert h = @h.invert assert_equal(1, h['one']) assert_equal(true, h['true']) assert_equal(nil, h['nil']) h.each do |k, v| assert(@h.key?(v)) # not true in general, but works here end h = @cls[ 'a' => 1, 'b' => 2, 'c' => 1].invert assert_equal(2, h.length) assert(h[1] == 'a' || h[1] == 'c') assert_equal('b', h[2]) end def test_key? assert(!@cls[].key?(1)) assert(!@cls[].key?(nil)) assert(@h.key?(nil)) assert(@h.key?(1)) assert(!@h.key?('gumby')) end def test_keys assert_equal([], @cls[].keys) keys = @h.keys expected = [] @h.each { |k, v| expected << k } assert_equal([], keys - expected) assert_equal([], expected - keys) end def test_length assert_equal(0, @cls[].length) assert_equal(7, @h.length) end def test_member? assert(!@cls[].member?(1)) assert(!@cls[].member?(nil)) assert(@h.member?(nil)) assert(@h.member?(1)) assert(!@h.member?('gumby')) end def test_rehash a = [ "a", "b" ] c = [ "c", "d" ] h = @cls[ a => 100, c => 300 ] assert_equal(100, h[a]) a[0] = "z" assert_nil(h[a]) h.rehash assert_equal(100, h[a]) end def test_reject base = @cls[ 1 => 'one', 2 => false, true => 'true', 'cat' => 99 ] h1 = @cls[ 1 => 'one', 2 => false, true => 'true' ] h2 = @cls[ 2 => false, 'cat' => 99 ] h3 = @cls[ 2 => false ] h = base.dup assert_equal(h, h.reject { false }) assert_equal(@cls[], h.reject { true }) h = base.dup assert_equal(h1, h.reject {|k,v| k.instance_of?(String) }) assert_equal(h2, h.reject {|k,v| v.instance_of?(String) }) assert_equal(h3, h.reject {|k,v| v }) assert_equal(base, h) end def test_reject! base = @cls[ 1 => 'one', 2 => false, true => 'true', 'cat' => 99 ] h1 = @cls[ 1 => 'one', 2 => false, true => 'true' ] h2 = @cls[ 2 => false, 'cat' => 99 ] h3 = @cls[ 2 => false ] h = base.dup assert_equal(nil, h.reject! { false }) assert_equal(@cls[], h.reject! { true }) h = base.dup assert_equal(h1, h.reject! {|k,v| k.instance_of?(String) }) assert_equal(h1, h) h = base.dup assert_equal(h2, h.reject! {|k,v| v.instance_of?(String) }) assert_equal(h2, h) h = base.dup assert_equal(h3, h.reject! {|k,v| v }) assert_equal(h3, h) end def test_replace h = @cls[ 1 => 2, 3 => 4 ] h1 = h.replace(@cls[ 9 => 8, 7 => 6 ]) assert_equal(h, h1) assert_equal(8, h[9]) assert_equal(6, h[7]) assert_nil(h[1]) assert_nil(h[2]) end def test_shift h = @h.dup @h.length.times { k, v = h.shift assert(@h.key?(k)) assert_equal(@h[k], v) } assert_equal(0, h.length) end def test_size assert_equal(0, @cls[].length) assert_equal(7, @h.length) end def test_sort h = @cls[].sort assert_equal([], h) h = @cls[ 1 => 1, 2 => 1 ].sort assert_equal([[1,1], [2,1]], h) h = @cls[ 'cat' => 'feline', 'ass' => 'asinine', 'bee' => 'beeline' ] h1 = h.sort assert_equal([ %w(ass asinine), %w(bee beeline), %w(cat feline)], h1) end def test_store t = Time.now h = @cls.new h.store(1, 'one') h.store(2, 'two') h.store(3, 'three') h.store(self, 'self') h.store(t, 'time') h.store(nil, 'nil') h.store('nil', nil) assert_equal('one', h[1]) assert_equal('two', h[2]) assert_equal('three', h[3]) assert_equal('self', h[self]) assert_equal('time', h[t]) assert_equal('nil', h[nil]) assert_equal(nil, h['nil']) assert_equal(nil, h['koala']) h.store(1, 1) h.store(nil, 99) h.store('nil', nil) assert_equal(1, h[1]) assert_equal('two', h[2]) assert_equal('three', h[3]) assert_equal('self', h[self]) assert_equal('time', h[t]) assert_equal(99, h[nil]) assert_equal(nil, h['nil']) assert_equal(nil, h['koala']) end def test_to_a assert_equal([], @cls[].to_a) assert_equal([[1,2]], @cls[ 1=>2 ].to_a) a = @cls[ 1=>2, 3=>4, 5=>6 ].to_a assert_equal([1,2], a.delete([1,2])) assert_equal([3,4], a.delete([3,4])) assert_equal([5,6], a.delete([5,6])) assert_equal(0, a.length) end def test_to_hash h = @h.to_hash assert_equal(@h, h) end def test_to_s h = @cls[ 1 => 2, "cat" => "dog", 1.5 => :fred ] assert_equal(h.to_a.join, h.to_s) $, = ":" assert_equal(h.to_a.join, h.to_s) h = @cls[] assert_equal(h.to_a.join, h.to_s) $, = nil end def test_update h1 = @cls[ 1 => 2, 2 => 3, 3 => 4 ] h2 = @cls[ 2 => 'two', 4 => 'four' ] ha = @cls[ 1 => 2, 2 => 'two', 3 => 4, 4 => 'four' ] hb = @cls[ 1 => 2, 2 => 3, 3 => 4, 4 => 'four' ] assert_equal(ha, h1.update(h2)) assert_equal(ha, h1) h1 = @cls[ 1 => 2, 2 => 3, 3 => 4 ] h2 = @cls[ 2 => 'two', 4 => 'four' ] assert_equal(hb, h2.update(h1)) assert_equal(hb, h2) end def test_value? assert(!@cls[].value?(1)) assert(!@cls[].value?(nil)) assert(@h.value?(nil)) assert(@h.value?('one')) assert(!@h.value?('gumby')) end def test_values assert_equal([], @cls[].values) vals = @h.values expected = [] @h.each { |k, v| expected << v } assert_equal([], vals - expected) assert_equal([], expected - vals) end def test_hash_hash assert_equal({0=>2,11=>1}.hash, {11=>1,0=>2}.hash) end def test_hash_bignum_hash x = 2<<(32-3)-1 assert_equal({x=>1}.hash, {x=>1}.hash) x = 2<<(64-3)-1 assert_equal({x=>1}.hash, {x=>1}.hash) o = Object.new def o.hash; 2<<100; end assert_equal({x=>1}.hash, {x=>1}.hash) end end ================================================ FILE: test/ruby/test_ifunless.rb ================================================ require 'test/unit' class TestIfunless < Test::Unit::TestCase def test_if_unless $x = 'test'; assert(if $x == $x then true else false end) $bad = false unless $x == $x $bad = true end assert(!$bad) assert(unless $x != $x then true else false end) end end ================================================ FILE: test/ruby/test_integer.rb ================================================ require 'test/unit' class TestInteger < Test::Unit::TestCase VS = [ -0x1000000000000000000000000000000000000000000000002, -0x1000000000000000000000000000000000000000000000001, -0x1000000000000000000000000000000000000000000000000, -0xffffffffffffffffffffffffffffffffffffffffffffffff, -0x1000000000000000000000002, -0x1000000000000000000000001, -0x1000000000000000000000000, -0xffffffffffffffffffffffff, -0x10000000000000002, -0x10000000000000001, -0x10000000000000000, -0xffffffffffffffff, -0x4000000000000002, -0x4000000000000001, -0x4000000000000000, -0x3fffffffffffffff, -0x100000002, -0x100000001, -0x100000000, -0xffffffff, -0xc717a08d, # 0xc717a08d * 0x524b2245 = 0x4000000000000001 -0x80000002, -0x80000001, -0x80000000, -0x7fffffff, -0x524b2245, -0x40000002, -0x40000001, -0x40000000, -0x3fffffff, -0x10002, -0x10001, -0x10000, -0xffff, -0x8101, # 0x8101 * 0x7f01 = 0x40000001 -0x8002, -0x8001, -0x8000, -0x7fff, -0x7f01, -65, -64, -63, -62, -33, -32, -31, -30, -3, -2, -1, 0, 1, 2, 3, 30, 31, 32, 33, 62, 63, 64, 65, 0x7f01, 0x7ffe, 0x7fff, 0x8000, 0x8001, 0x8101, 0xfffe, 0xffff, 0x10000, 0x10001, 0x3ffffffe, 0x3fffffff, 0x40000000, 0x40000001, 0x524b2245, 0x7ffffffe, 0x7fffffff, 0x80000000, 0x80000001, 0xc717a08d, 0xfffffffe, 0xffffffff, 0x100000000, 0x100000001, 0x3ffffffffffffffe, 0x3fffffffffffffff, 0x4000000000000000, 0x4000000000000001, 0xfffffffffffffffe, 0xffffffffffffffff, 0x10000000000000000, 0x10000000000000001, 0xffffffffffffffffffffffff, 0x1000000000000000000000000, 0x1000000000000000000000001, 0xffffffffffffffffffffffffffffffffffffffffffffffff, 0x1000000000000000000000000000000000000000000000000, 0x1000000000000000000000000000000000000000000000001 ] #VS.map! {|v| 0x4000000000000000.coerce(v)[0] } BDSIZE = 0x4000000000000000.coerce(0)[0].size def self.bdsize(x) ((x + 1) / 8 + BDSIZE) / BDSIZE * BDSIZE end def bdsize(x) self.class.bdsize(x) end min = -1 min *= 2 while min.class == Fixnum FIXNUM_MIN = min/2 max = 1 max *= 2 while (max-1).class == Fixnum FIXNUM_MAX = max/2-1 def test_fixnum_range assert_instance_of(Bignum, FIXNUM_MIN-1) assert_instance_of(Fixnum, FIXNUM_MIN) assert_instance_of(Fixnum, FIXNUM_MAX) assert_instance_of(Bignum, FIXNUM_MAX+1) end def check_class(n) if FIXNUM_MIN <= n && n <= FIXNUM_MAX assert_instance_of(Fixnum, n) else assert_instance_of(Bignum, n) end end def test_aref VS.each {|a| 100.times {|i| assert_equal((a >> i).odd? ? 1 : 0, a[i], "(#{a})[#{i}]") } } VS.each {|a| VS.each {|b| c = nil assert_nothing_raised("(#{a})[#{b}]") { c = a[b] } check_class(c) if b < 0 assert_equal(0, c, "(#{a})[#{b}]") else assert_equal((a >> b).odd? ? 1 : 0, c, "(#{a})[#{b}]") end } } # assert_equal(1, (1 << 0x40000000)[0x40000000], "[ruby-dev:31271]") # assert_equal(0, (-1 << 0x40000001)[0x40000000], "[ruby-dev:31271]") big_zero = 0x40000000.coerce(0)[0] assert_equal(0, (-0x40000002)[big_zero], "[ruby-dev:31271]") assert_equal(1, 0x400000001[big_zero], "[ruby-dev:31271]") end def test_plus VS.each {|a| VS.each {|b| c = a + b check_class(c) assert_equal(b + a, c, "#{a} + #{b}") assert_equal(a, c - b, "(#{a} + #{b}) - #{b}") assert_equal(a-~b-1, c, "#{a} + #{b}") # Hacker's Delight assert_equal((a^b)+2*(a&b), c, "#{a} + #{b}") # Hacker's Delight assert_equal((a|b)+(a&b), c, "#{a} + #{b}") # Hacker's Delight assert_equal(2*(a|b)-(a^b), c, "#{a} + #{b}") # Hacker's Delight } } end def test_minus VS.each {|a| VS.each {|b| c = a - b check_class(c) assert_equal(a, c + b, "(#{a} - #{b}) + #{b}") assert_equal(-b, c - a, "(#{a} - #{b}) - #{a}") assert_equal(a+~b+1, c, "#{a} - #{b}") # Hacker's Delight assert_equal((a^b)-2*(b&~a), c, "#{a} - #{b}") # Hacker's Delight assert_equal((a&~b)-(b&~a), c, "#{a} - #{b}") # Hacker's Delight assert_equal(2*(a&~b)-(a^b), c, "#{a} - #{b}") # Hacker's Delight } } end def test_mult VS.each {|a| VS.each {|b| c = a * b check_class(c) assert_equal(b * a, c, "#{a} * #{b}") assert_equal(b, c / a, "(#{a} * #{b}) / #{a}") if a != 0 assert_equal(a.abs * b.abs, (a * b).abs, "(#{a} * #{b}).abs") assert_equal((a-100)*(b-100)+(a-100)*100+(b-100)*100+10000, c, "#{a} * #{b}") assert_equal((a+100)*(b+100)-(a+100)*100-(b+100)*100+10000, c, "#{a} * #{b}") } } end def test_divmod VS.each {|a| VS.each {|b| if b == 0 assert_raise(ZeroDivisionError) { a.divmod(b) } else q, r = a.divmod(b) check_class(q) check_class(r) assert_equal(a, b*q+r) assert(r.abs < b.abs) assert(0 < b ? (0 <= r && r < b) : (b < r && r <= 0)) assert_equal(q, a/b) assert_equal(q, a.div(b)) assert_equal(r, a%b) assert_equal(r, a.modulo(b)) end } } end def test_pow small_values = VS.find_all {|v| 0 <= v && v < 1000 } VS.each {|a| small_values.each {|b| c = a ** b check_class(c) d = 1 b.times { d *= a } assert_equal(d, c, "(#{a}) ** #{b}") if a != 0 d = c b.times { d /= a } assert_equal(1, d, "((#{a}) ** #{b}) / #{a} / ...(#{b} times)...") end } } assert_equal(0**-1 == 0, false) end def test_not VS.each {|a| b = ~a check_class(b) assert_equal(-1 ^ a, b, "~#{a}") assert_equal(-a-1, b, "~#{a}") # Hacker's Delight assert_equal(0, a & b, "#{a} & ~#{a}") assert_equal(-1, a | b, "#{a} | ~#{a}") } end def test_or VS.each {|a| VS.each {|b| c = a | b check_class(c) assert_equal(b | a, c, "#{a} | #{b}") assert_equal(a + b - (a&b), c, "#{a} | #{b}") assert_equal((a & ~b) + b, c, "#{a} | #{b}") # Hacker's Delight assert_equal(-1, c | ~a, "(#{a} | #{b}) | ~#{a})") } } end def test_and VS.each {|a| VS.each {|b| c = a & b check_class(c) assert_equal(b & a, c, "#{a} & #{b}") assert_equal(a + b - (a|b), c, "#{a} & #{b}") assert_equal((~a | b) - ~a, c, "#{a} & #{b}") # Hacker's Delight assert_equal(0, c & ~a, "(#{a} & #{b}) & ~#{a}") } } end def test_xor VS.each {|a| VS.each {|b| c = a ^ b check_class(c) assert_equal(b ^ a, c, "#{a} ^ #{b}") assert_equal((a|b)-(a&b), c, "#{a} ^ #{b}") # Hacker's Delight assert_equal(b, c ^ a, "(#{a} ^ #{b}) ^ #{a}") } } end def test_lshift small_values = VS.find_all {|v| v < 8000 } VS.each {|a| small_values.each {|b| c = a << b check_class(c) if 0 <= b assert_equal(a, c >> b, "(#{a} << #{b}) >> #{b}") assert_equal(a * 2**b, c, "#{a} << #{b}") end 0.upto(c.size*8+10) {|nth| assert_equal(a[nth-b], c[nth], "(#{a} << #{b})[#{nth}]") } } } assert_equal(0, 1 << -0x40000000) assert_equal(0, 1 << -0x40000001) assert_equal(0, 1 << -0x80000000) assert_equal(0, 1 << -0x80000001) # assert_equal(bdsize(0x80000000), (1 << 0x80000000).size) end def test_rshift small_values = VS.find_all {|v| -8000 < v } VS.each {|a| small_values.each {|b| c = a >> b check_class(c) if b <= 0 assert_equal(a, c << b, "(#{a} >> #{b}) << #{b}") assert_equal(a * 2**(-b), c, "#{a} >> #{b}") end 0.upto(c.size*8+10) {|nth| assert_equal(a[nth+b], c[nth], "(#{a} >> #{b})[#{nth}]") } } } # assert_equal(bdsize(0x40000001), (1 >> -0x40000001).size) assert((1 >> 0x80000000).zero?) assert((1 >> 0xffffffff).zero?) assert((1 >> 0x100000000).zero?) # assert_equal((1 << 0x40000000), (1 >> -0x40000000)) # assert_equal((1 << 0x40000001), (1 >> -0x40000001)) end def test_succ VS.each {|a| b = a.succ check_class(b) assert_equal(a+1, b, "(#{a}).succ") assert_equal(a, b.pred, "(#{a}).succ.pred") assert_equal(a, b-1, "(#{a}).succ - 1") } end def test_pred VS.each {|a| b = a.pred check_class(b) assert_equal(a-1, b, "(#{a}).pred") assert_equal(a, b.succ, "(#{a}).pred.succ") assert_equal(a, b + 1, "(#{a}).pred + 1") } end def test_unary_plus VS.each {|a| b = +a check_class(b) assert_equal(a, b, "+(#{a})") } end def test_unary_minus VS.each {|a| b = -a check_class(b) assert_equal(0-a, b, "-(#{a})") assert_equal(~a+1, b, "-(#{a})") assert_equal(0, a+b, "#{a}+(-(#{a}))") } end def test_cmp VS.each_with_index {|a, i| VS.each_with_index {|b, j| assert_equal(i <=> j, a <=> b, "#{a} <=> #{b}") assert_equal(i < j, a < b, "#{a} < #{b}") assert_equal(i <= j, a <= b, "#{a} <= #{b}") assert_equal(i > j, a > b, "#{a} > #{b}") assert_equal(i >= j, a >= b, "#{a} >= #{b}") } } end def test_eq VS.each_with_index {|a, i| VS.each_with_index {|b, j| c = a == b assert_equal(b == a, c, "#{a} == #{b}") assert_equal(i == j, c, "#{a} == #{b}") } } end def test_abs VS.each {|a| b = a.abs check_class(b) if a < 0 assert_equal(-a, b, "(#{a}).abs") else assert_equal(a, b, "(#{a}).abs") end } end def test_ceil VS.each {|a| b = a.ceil check_class(b) assert_equal(a, b, "(#{a}).ceil") } end def test_floor VS.each {|a| b = a.floor check_class(b) assert_equal(a, b, "(#{a}).floor") } end def test_round VS.each {|a| b = a.round check_class(b) assert_equal(a, b, "(#{a}).round") } end def test_truncate VS.each {|a| b = a.truncate check_class(b) assert_equal(a, b, "(#{a}).truncate") } end def test_remainder VS.each {|a| VS.each {|b| if b == 0 assert_raise(ZeroDivisionError) { a.divmod(b) } else r = a.remainder(b) check_class(r) if a < 0 assert_operator(-b.abs, :<, r, "#{a}.remainder(#{b})") assert_operator(0, :>=, r, "#{a}.remainder(#{b})") elsif 0 < a assert_operator(0, :<=, r, "#{a}.remainder(#{b})") assert_operator(b.abs, :>, r, "#{a}.remainder(#{b})") else assert_equal(0, r, "#{a}.remainder(#{b})") end end } } end def test_zero_nonzero VS.each {|a| z = a.zero? n = a.nonzero? if a == 0 assert_equal(true, z, "(#{a}).zero?") assert_equal(nil, n, "(#{a}).nonzero?") else assert_equal(false, z, "(#{a}).zero?") assert_equal(a, n, "(#{a}).nonzero?") check_class(n) end assert(z ^ n, "(#{a}).zero? ^ (#{a}).nonzero?") } end def test_even_odd VS.each {|a| e = a.even? o = a.odd? assert_equal((a % 2) == 0, e, "(#{a}).even?") assert_equal((a % 2) == 1, o, "(#{a}).odd") assert_equal((a & 1) == 0, e, "(#{a}).even?") assert_equal((a & 1) == 1, o, "(#{a}).odd") assert(e ^ o, "(#{a}).even? ^ (#{a}).odd?") } end def test_to_s 2.upto(36) {|radix| VS.each {|a| s = a.to_s(radix) b = s.to_i(radix) assert_equal(a, b, "(#{a}).to_s(#{radix}).to_i(#{radix})") } } end def test_printf_x VS.reverse_each {|a| s = sprintf("%x", a) if /\A\.\./ =~ s b = -($'.tr('0123456789abcdef', 'fedcba9876543210').to_i(16) + 1) else b = s.to_i(16) end assert_equal(a, b, "sprintf('%x', #{a}) = #{s.inspect}") } end def test_printf_x_sign VS.reverse_each {|a| s = sprintf("%+x", a) b = s.to_i(16) assert_equal(a, b, "sprintf('%+x', #{a}) = #{s.inspect}") s = sprintf("% x", a) b = s.to_i(16) assert_equal(a, b, "sprintf('% x', #{a}) = #{s.inspect}") } end def test_printf_o VS.reverse_each {|a| s = sprintf("%o", a) if /\A\.\./ =~ s b = -($'.tr('01234567', '76543210').to_i(8) + 1) else b = s.to_i(8) end assert_equal(a, b, "sprintf('%o', #{a}) = #{s.inspect}") } end def test_printf_o_sign VS.reverse_each {|a| s = sprintf("%+o", a) b = s.to_i(8) assert_equal(a, b, "sprintf('%+o', #{a}) = #{s.inspect}") s = sprintf("% o", a) b = s.to_i(8) assert_equal(a, b, "sprintf('% o', #{a}) = #{s.inspect}") } end def test_printf_b VS.reverse_each {|a| s = sprintf("%b", a) if /\A\.\./ =~ s b = -($'.tr('01', '10').to_i(2) + 1) else b = s.to_i(2) end assert_equal(a, b, "sprintf('%b', #{a}) = #{s.inspect}") } end def test_printf_b_sign VS.reverse_each {|a| s = sprintf("%+b", a) b = s.to_i(2) assert_equal(a, b, "sprintf('%+b', #{a}) = #{s.inspect}") s = sprintf("% b", a) b = s.to_i(2) assert_equal(a, b, "sprintf('% b', #{a}) = #{s.inspect}") } end def test_printf_di VS.reverse_each {|a| s = sprintf("%d", a) b = s.to_i assert_equal(a, b, "sprintf('%d', #{a}) = #{s.inspect}") s = sprintf("%i", a) b = s.to_i assert_equal(a, b, "sprintf('%i', #{a}) = #{s.inspect}") } end def test_marshal VS.reverse_each {|a| s = Marshal.dump(a) b = Marshal.load(s) assert_equal(a, b, "Marshal.load(Marshal.dump(#{a}))") } end def test_pack_ber template = "w" VS.reverse_each {|a| if a < 0 assert_raise(ArgumentError) { [a].pack(template) } else s = [a].pack(template) b = s.unpack(template)[0] assert_equal(a, b, "[#{a}].pack(#{template.dump}).unpack(#{template.dump})") end } end def test_pack_utf8 template = "U" VS.reverse_each {|a| if a < 0 || 0x7fffffff < a assert_raise(RangeError) { [a].pack(template) } else s = [a].pack(template) b = s.unpack(template)[0] assert_equal(a, b, "[#{a}].pack(#{template.dump}).unpack(#{template.dump})") end } end def test_Integer assert_raise(ArgumentError) {Integer("0x-1")} assert_raise(ArgumentError) {Integer("-0x-1")} assert_raise(ArgumentError) {Integer("0x 123")} assert_raise(ArgumentError) {Integer("0x 123")} assert_raise(ArgumentError) {Integer("0x0x5")} assert_raise(ArgumentError) {Integer("0x0x000000005")} assert_nothing_raised(ArgumentError) { assert_equal(1540841, "0x0x5".to_i(36)) } assert_raise(ArgumentError) { Integer("--0") } assert_raise(ArgumentError) { Integer("-+0") } assert_raise(ArgumentError) { Integer("++1") } assert_raise(ArgumentError) { Integer("") } assert_raise(ArgumentError) { Integer("10 x") } assert_raise(ArgumentError) { Integer("1__2") } assert_raise(ArgumentError) { Integer("1z") } assert_raise(ArgumentError) { Integer("46116860184273__87904") } assert_raise(ArgumentError) { Integer("4611686018427387904_") } assert_raise(ArgumentError) { Integer("4611686018427387904 :") } assert_equal(0x4000000000000000, Integer("46_11_686_0184273_87904")) assert_raise(ArgumentError) { Integer("\0") } assert_nothing_raised(ArgumentError, "[ruby-core:13873]") { assert_equal(0, Integer("0 ")) } assert_nothing_raised(ArgumentError, "[ruby-core:14139]") { assert_equal(0377, Integer("0_3_7_7")) } assert_raise(ArgumentError, "[ruby-core:14139]") {Integer("0__3_7_7")} end end ================================================ FILE: test/ruby/test_io.rb ================================================ require 'test/unit' require 'tmpdir' require 'tempfile' class TestIO < Test::Unit::TestCase def mkcdtmpdir Dir.mktmpdir {|d| Dir.chdir(d) { yield } } end def test_gets_rs r, w = IO.pipe w.print "\377xyz" w.close assert_equal("\377", r.gets("\377"), "[ruby-dev:24460]") r.close end def test_readpartial_pos mkcdtmpdir { open("foo", "w") {|f| f << "abc" } open("foo") {|f| f.seek(0) assert_equal("ab", f.readpartial(2)) assert_equal(2, f.pos) } } end def make_tempfile t = Tempfile.new("foo") t.binmode t.puts "foo" t.puts "bar" t.puts "baz" t.close t end def test_binmode_after_closed t = make_tempfile t.close assert_raise(IOError) {t.binmode} end def test_pos t = make_tempfile open(t.path, IO::RDWR|IO::CREAT|IO::TRUNC, 0600) do |f| f.write "Hello" assert_equal(5, f.pos) end open(t.path, IO::RDWR|IO::CREAT|IO::TRUNC, 0600) do |f| f.sync = true f.read f.write "Hello" assert_equal(5, f.pos) end end end ================================================ FILE: test/ruby/test_iterator.rb ================================================ require 'test/unit' class Array def iter_test1 collect{|e| [e, yield(e)]}.sort{|a,b|a[1]<=>b[1]} end def iter_test2 a = collect{|e| [e, yield(e)]} a.sort{|a,b|a[1]<=>b[1]} end end class TestIterator < Test::Unit::TestCase def ttt assert(iterator?) end def test_iterator assert(!iterator?) ttt{} # yield at top level !! here's not toplevel assert(!defined?(yield)) end def test_array $x = [1, 2, 3, 4] $y = [] # iterator over array for i in $x $y.push i end assert_equal($x, $y) end def tt 1.upto(10) {|i| yield i } end def tt2(dummy) yield 1 end def tt3(&block) tt2(raise(ArgumentError,""),&block) end def test_nested_iterator i = 0 tt{|i| break if i == 5} assert_equal(5, i) assert_raises(ArgumentError) do tt3{} end end def tt4 &block tt2(raise(ArgumentError,""),&block) end def test_block_argument_without_paren assert_raises(ArgumentError) do tt4{} end end # iterator break/redo/next/retry def test_break done = true loop{ break done = false # should not reach here } assert(done) done = false $bad = false loop { break if done done = true next $bad = true # should not reach here } assert(!$bad) done = false $bad = false loop { break if done done = true redo $bad = true # should not reach here } assert(!$bad) $x = [] for i in 1 .. 7 $x.push i end assert_equal(7, $x.size) assert_equal([1, 2, 3, 4, 5, 6, 7], $x) $done = false $x = [] for i in 1 .. 7 # see how retry works in iterator loop if i == 4 and not $done $done = true retry end $x.push(i) end assert_equal(10, $x.size) assert_equal([1, 2, 3, 1, 2, 3, 4, 5, 6, 7], $x) end def test_append_method_to_built_in_class $x = [[1,2],[3,4],[5,6]] assert_equal($x.iter_test1{|x|x}, $x.iter_test2{|x|x}) end class IterTest def initialize(e); @body = e; end def each0(&block); @body.each(&block); end def each1(&block); @body.each {|*x| block.call(*x) } end def each2(&block); @body.each {|*x| block.call(x) } end def each3(&block); @body.each {|x| block.call(*x) } end def each4(&block); @body.each {|x| block.call(x) } end def each5; @body.each {|*x| yield(*x) } end def each6; @body.each {|*x| yield(x) } end def each7; @body.each {|x| yield(*x) } end def each8; @body.each {|x| yield(x) } end def f(a) a end end def test_itertest assert_equal([1], IterTest.new(nil).method(:f).to_proc.call([1])) m = /\w+/.match("abc") assert_equal([m], IterTest.new(nil).method(:f).to_proc.call([m])) IterTest.new([0]).each0 {|x| assert_equal(0, x)} IterTest.new([1]).each1 {|x| assert_equal(1, x)} IterTest.new([2]).each2 {|x| assert_equal([2], x)} IterTest.new([3]).each3 {|x| assert_equal(3, x)} IterTest.new([4]).each4 {|x| assert_equal(4, x)} IterTest.new([5]).each5 {|x| assert_equal(5, x)} IterTest.new([6]).each6 {|x| assert_equal([6], x)} IterTest.new([7]).each7 {|x| assert_equal(7, x)} IterTest.new([8]).each8 {|x| assert_equal(8, x)} IterTest.new([[0]]).each0 {|x| assert_equal([0], x)} IterTest.new([[1]]).each1 {|x| assert_equal([1], x)} IterTest.new([[2]]).each2 {|x| assert_equal([[2]], x)} IterTest.new([[3]]).each3 {|x| assert_equal(3, x)} IterTest.new([[4]]).each4 {|x| assert_equal([4], x)} IterTest.new([[5]]).each5 {|x| assert_equal([5], x)} IterTest.new([[6]]).each6 {|x| assert_equal([[6]], x)} IterTest.new([[7]]).each7 {|x| assert_equal(7, x)} IterTest.new([[8]]).each8 {|x| assert_equal([8], x)} IterTest.new([[0,0]]).each0 {|x| assert_equal([0,0], x)} IterTest.new([[8,8]]).each8 {|x| assert_equal([8,8], x)} end def m(var) var end def m1 m(block_given?) end def m2 m(block_given?,&proc{}) end def test_block_given assert(m1{p 'test'}) assert(m2{p 'test'}) assert(!m1()) assert(!m2()) end def m3(var, &block) m(yield(var), &block) end def m4(&block) m(m1(), &block) end def test_block_passing assert(!m4()) assert(!m4 {}) assert_equal(100, m3(10) {|x|x*x}) end class C include Enumerable def initialize @a = [1,2,3] end def each(&block) @a.each(&block) end end def test_collect assert_equal([1,2,3], C.new.collect{|n| n}) end def test_proc assert_instance_of(Proc, lambda{}) assert_instance_of(Proc, Proc.new{}) lambda{|a|assert_equal(a, 1)}.call(1) end def test_block assert_instance_of(NilClass, get_block) assert_instance_of(Proc, get_block{}) end def test_argument assert_nothing_raised {lambda{||}.call} assert_raises(ArgumentError) {lambda{||}.call(1)} assert_nothing_raised {lambda{|a,|}.call(1)} assert_raises(ArgumentError) {lambda{|a,|}.call()} assert_raises(ArgumentError) {lambda{|a,|}.call(1,2)} end def get_block(&block) block end def test_get_block assert_instance_of(Proc, get_block{}) assert_nothing_raised {get_block{||}.call()} assert_nothing_raised {get_block{||}.call(1)} assert_nothing_raised {get_block{|a,|}.call(1)} assert_nothing_raised {get_block{|a,|}.call()} assert_nothing_raised {get_block{|a,|}.call(1,2)} assert_nothing_raised {get_block(&lambda{||}).call()} assert_raises(ArgumentError) {get_block(&lambda{||}).call(1)} assert_nothing_raised {get_block(&lambda{|a,|}).call(1)} assert_raises(ArgumentError) {get_block(&lambda{|a,|}).call(1,2)} block = get_block{11} assert_instance_of(Proc, block) assert_instance_of(Proc, block.to_proc) assert_equal(block.clone.call, 11) assert_instance_of(Proc, get_block(&block)) lambda = lambda{44} assert_instance_of(Proc, lambda) assert_instance_of(Proc, lambda.to_proc) assert_equal(lambda.clone.call, 44) assert_instance_of(Proc, get_block(&lambda)) assert_equal(1, Proc.new{|a,| a}.call(1,2,3)) assert_nothing_raised {Proc.new{|a,|}.call(1,2)} end def return1_test Proc.new { return 55 }.call + 5 end def test_return1 assert_equal(55, return1_test()) end def return2_test lambda { return 55 }.call + 5 end def test_return2 assert_equal(60, return2_test()) end def proc_call(&b) b.call end def proc_yield() yield end def proc_return1 proc_call{return 42}+1 end def test_proc_return1 assert_equal(42, proc_return1()) end def proc_return2 proc_yield{return 42}+1 end def test_proc_return2 assert_equal(42, proc_return2()) end def test_ljump block = get_block{11} lambda = lambda{44} assert_raises(LocalJumpError) {get_block{break}.call} assert_nothing_raised {lambda{break}.call} assert_instance_of(LocalJumpError, (get_block{break}.call rescue $!)) assert_equal(-1, block.arity) assert_equal(-1, lambda.arity) assert_equal(0, lambda{||}.arity) assert_equal(1, lambda{|a|}.arity) assert_equal(1, lambda{|a,|}.arity) assert_equal(2, lambda{|a,b|}.arity) end def marity_test(m) method = method(m) assert_equal(method.arity, method.to_proc.arity) end def test_marity marity_test(:assert) marity_test(:marity_test) marity_test(:p) lambda(&method(:assert)).call(true) lambda(&get_block{|a,n| assert(a,n)}).call(true, "marity") end def foo yield([:key, :value]) end def bar(&blk) blk.call([:key, :value]) end def test_yield_vs_call foo{|k,v| assert_equal([:key, :value], [k,v])} bar{|k,v| assert_equal([:key, :value], [k,v])} end class H def each yield [:key, :value] end end def test_assoc_yield [{:key=>:value}, H.new].each {|h| h.each{|a| assert_equal([:key, :value], a)} h.each{|*a| assert_equal([[:key, :value]], a)} h.each{|k,v| assert_equal([:key, :value], [k,v])} } end class ITER_TEST1 def a block_given? end end class ITER_TEST2 < ITER_TEST1 include Test::Unit::Assertions def a assert(super) super end end def test_iter_test2 assert(ITER_TEST2.new.a {}) end class ITER_TEST3 def foo x return yield if block_given? x end end class ITER_TEST4 < ITER_TEST3 include Test::Unit::Assertions def foo x assert_equal(super, yield) assert_equal(x, super(x, &nil)) end end def test_iter4 ITER_TEST4.new.foo(44){55} end def test_break__nested_loop1 _test_break__nested_loop1 do break end end def _test_break__nested_loop1 while true yield end assert(false, "must not reach here") end def test_break__nested_loop2 _test_break__nested_loop2 do break end end def _test_break__nested_loop2 until false yield end assert(false, "must not reach here") end def test_break__nested_loop3 _test_break__nested_loop3 do break end end def _test_break__nested_loop3 loop do yield end assert(false, "must not reach here") end def test_break_from_enum result = ["a"].inject("ng") {|x,y| break "ok"} assert_equal("ok", result) end def _test_return_trace_func(x) set_trace_func(proc {}) [].fetch(2) {return x} ensure set_trace_func(nil) end def test_return_trace_func ok = "returned gracefully" result = "skipped" result = _test_return_trace_func(ok) ensure assert_equal(ok, result) return end class IterString < ::String def ===(other) super if !block_given? end end # Check that the block passed to an iterator # does not get propagated inappropriately def test_block_given_within_iterator assert_equal(["b"], ["a", "b", "c"].grep(IterString.new("b")) {|s| s}) end end ================================================ FILE: test/ruby/test_marshal.rb ================================================ require 'test/unit' dir = File.dirname(File.expand_path(__FILE__)) orgpath = $:.dup begin $:.push(dir) require 'marshaltestlib' ensure $:.replace(orgpath) end class TestMarshal < Test::Unit::TestCase include MarshalTestLib def encode(o) stress, GC.stress = GC.stress, true Marshal.dump(o) ensure GC.stress = stress end def decode(s) stress, GC.stress = GC.stress, true Marshal.load(s) ensure GC.stress = stress end def fact(n) return 1 if n == 0 f = 1 while n>0 f *= n n -= 1 end return f end StrClone=String.clone; def test_marshal $x = [1,2,3,[4,5,"foo"],{1=>"bar"},2.5,fact(30)] $y = Marshal.dump($x) assert_equal($x, Marshal.load($y)) assert_instance_of(StrClone, Marshal.load(Marshal.dump(StrClone.new("abc")))) [[1,2,3,4], [81, 2, 118, 3146]].each { |w,x,y,z| a = (x.to_f + y.to_f / z.to_f) * Math.exp(w.to_f / (x.to_f + y.to_f / z.to_f)) ma = Marshal.dump(a) b = Marshal.load(ma) assert_equal(a, b) } end class C def initialize(str) @str = str end def _dump(limit) @str end def self._load(s) new(s) end end def test_too_long_string (data = Marshal.dump(C.new("a")))[-2, 1] = "\003\377\377\377" e = assert_raise(ArgumentError, "[ruby-dev:32054]") { Marshal.load(data) } assert_equal("marshal data too short", e.message) end class DumpTest def marshal_dump loop { Thread.pass } end end class LoadTest def marshal_dump nil end def marshal_load(obj) loop { Thread.pass } end end def test_context_switch o = DumpTest.new Thread.new { Marshal.dump(o) } GC.start assert(true, '[ruby-dev:39425]') o = LoadTest.new m = Marshal.dump(o) Thread.new { Marshal.load(m) } GC.start assert(true, '[ruby-dev:39425]') end def test_taint x = Object.new x.taint s = Marshal.dump(x) assert_equal(true, s.tainted?) y = Marshal.load(s) assert_equal(true, y.tainted?) end end ================================================ FILE: test/ruby/test_math.rb ================================================ require 'test/unit' class TestMath < Test::Unit::TestCase def test_math assert_equal(2, Math.sqrt(4)) self.class.class_eval { include Math } assert_equal(2, sqrt(4)) end end ================================================ FILE: test/ruby/test_method.rb ================================================ require 'test/unit' class TestMethod < Test::Unit::TestCase def m0() end def m1(a) end def m2(a, b) end def mo1(a = nil, &b) end def mo2(a, b = nil) end def mo3(*a) end def mo4(a, *b, &c) end class Base def foo() :base end end class Derived < Base def foo() :derived end end def test_arity assert_equal(0, method(:m0).arity) assert_equal(1, method(:m1).arity) assert_equal(2, method(:m2).arity) assert_equal(-1, method(:mo1).arity) assert_equal(-2, method(:mo2).arity) assert_equal(-1, method(:mo3).arity) assert_equal(-2, method(:mo4).arity) end def test_unbind assert_equal(:derived, Derived.new.foo) um = Derived.new.method(:foo).unbind assert_instance_of(UnboundMethod, um) Derived.class_eval do def foo() :changed end end assert_equal(:changed, Derived.new.foo) assert_equal(:derived, um.bind(Derived.new).call) assert_raise(TypeError) do um.bind(Base.new) end end def test_receiver_name_owner o = Object.new def o.foo; end m = o.method(:foo) assert_equal(o, m.receiver) assert_equal("foo", m.name) assert_equal(class << o; self; end, m.owner) assert_equal("foo", m.unbind.name) assert_equal(class << o; self; end, m.unbind.owner) end end ================================================ FILE: test/ruby/test_objectspace.rb ================================================ require 'test/unit' class TestObjectSpace < Test::Unit::TestCase def self.deftest_id2ref(obj) /:(\d+)/ =~ caller[0] file = $` line = $1.to_i code = <<"End" define_method("test_id2ref_#{line}") {\ o = ObjectSpace._id2ref(obj.object_id);\ assert_same(obj, o, "didn't round trip: \#{obj.inspect}");\ } End eval code, binding, file, line end deftest_id2ref(-0x4000000000000001) deftest_id2ref(-0x4000000000000000) deftest_id2ref(-0x40000001) deftest_id2ref(-0x40000000) deftest_id2ref(-1) deftest_id2ref(0) deftest_id2ref(1) deftest_id2ref(0x3fffffff) deftest_id2ref(0x40000000) deftest_id2ref(0x3fffffffffffffff) deftest_id2ref(0x4000000000000000) deftest_id2ref(:a) deftest_id2ref(:abcdefghijilkjl) deftest_id2ref(:==) deftest_id2ref(Object.new) deftest_id2ref(self) deftest_id2ref(true) deftest_id2ref(false) deftest_id2ref(nil) end ================================================ FILE: test/ruby/test_pack.rb ================================================ require 'test/unit' class TestPack < Test::Unit::TestCase def test_pack $format = "c2x5CCxsdils_l_a6"; # Need the expression in here to force ary[5] to be numeric. This avoids # test2 failing because ary2 goes str->numeric->str and ary does not. ary = [1,-100,127,128,32767,987.654321098 / 100.0,12345,123456,-32767,-123456,"abcdef"] $x = ary.pack($format) ary2 = $x.unpack($format) assert_equal(ary.length, ary2.length) assert_equal(ary.join(':'), ary2.join(':')) assert_match(/def/, $x) $x = [-1073741825] assert_equal($x, $x.pack("q").unpack("q")) $x = [-1] assert_equal($x, $x.pack("l").unpack("l")) end def test_pack_N assert_equal "\000\000\000\000", [0].pack('N') assert_equal "\000\000\000\001", [1].pack('N') assert_equal "\000\000\000\002", [2].pack('N') assert_equal "\000\000\000\003", [3].pack('N') assert_equal "\377\377\377\376", [4294967294].pack('N') assert_equal "\377\377\377\377", [4294967295].pack('N') assert_equal "\200\000\000\000", [2**31].pack('N') assert_equal "\177\377\377\377", [-2**31-1].pack('N') assert_equal "\377\377\377\377", [-1].pack('N') assert_equal "\000\000\000\001\000\000\000\001", [1,1].pack('N*') assert_equal "\000\000\000\001\000\000\000\001\000\000\000\001", [1,1,1].pack('N*') end def test_unpack_N assert_equal 1, "\000\000\000\001".unpack('N')[0] assert_equal 2, "\000\000\000\002".unpack('N')[0] assert_equal 3, "\000\000\000\003".unpack('N')[0] assert_equal 3, "\000\000\000\003".unpack('N')[0] assert_equal 4294967295, "\377\377\377\377".unpack('N')[0] assert_equal [1,1], "\000\000\000\001\000\000\000\001".unpack('N*') assert_equal [1,1,1], "\000\000\000\001\000\000\000\001\000\000\000\001".unpack('N*') end def test_pack_U assert_raises(RangeError) { [-0x40000001].pack("U") } assert_raises(RangeError) { [-0x40000000].pack("U") } assert_raises(RangeError) { [-1].pack("U") } assert_equal "\000", [0].pack("U") assert_equal "\374\277\277\277\277\277", [0x3fffffff].pack("U") assert_equal "\375\200\200\200\200\200", [0x40000000].pack("U") assert_equal "\375\277\277\277\277\277", [0x7fffffff].pack("U") assert_raises(RangeError) { [0x80000000].pack("U") } assert_raises(RangeError) { [0x100000000].pack("U") } end def test_pack_unpack_hH assert_equal("\x01\xfe", ["10ef"].pack("h*")) assert_equal("", ["10ef"].pack("h0")) assert_equal("\x01\x0e", ["10ef"].pack("h3")) assert_equal("\x01\xfe\x0", ["10ef"].pack("h5")) assert_equal("\xff\x0f", ["fff"].pack("h3")) assert_equal("\xff\x0f", ["fff"].pack("h4")) assert_equal("\xff\x0f\0", ["fff"].pack("h5")) assert_equal("\xff\x0f\0", ["fff"].pack("h6")) assert_equal("\xff\x0f\0\0", ["fff"].pack("h7")) assert_equal("\xff\x0f\0\0", ["fff"].pack("h8")) assert_equal("\x10\xef", ["10ef"].pack("H*")) assert_equal("", ["10ef"].pack("H0")) assert_equal("\x10\xe0", ["10ef"].pack("H3")) assert_equal("\x10\xef\x0", ["10ef"].pack("H5")) assert_equal("\xff\xf0", ["fff"].pack("H3")) assert_equal("\xff\xf0", ["fff"].pack("H4")) assert_equal("\xff\xf0\0", ["fff"].pack("H5")) assert_equal("\xff\xf0\0", ["fff"].pack("H6")) assert_equal("\xff\xf0\0\0", ["fff"].pack("H7")) assert_equal("\xff\xf0\0\0", ["fff"].pack("H8")) assert_equal(["10ef"], "\x01\xfe".unpack("h*")) assert_equal([""], "\x01\xfe".unpack("h0")) assert_equal(["1"], "\x01\xfe".unpack("h1")) assert_equal(["10"], "\x01\xfe".unpack("h2")) assert_equal(["10e"], "\x01\xfe".unpack("h3")) assert_equal(["10ef"], "\x01\xfe".unpack("h4")) assert_equal(["10ef"], "\x01\xfe".unpack("h5")) assert_equal(["10ef"], "\x10\xef".unpack("H*")) assert_equal([""], "\x10\xef".unpack("H0")) assert_equal(["1"], "\x10\xef".unpack("H1")) assert_equal(["10"], "\x10\xef".unpack("H2")) assert_equal(["10e"], "\x10\xef".unpack("H3")) assert_equal(["10ef"], "\x10\xef".unpack("H4")) assert_equal(["10ef"], "\x10\xef".unpack("H5")) end end ================================================ FILE: test/ruby/test_path.rb ================================================ require 'test/unit' class TestPath < Test::Unit::TestCase def test_path assert_equal("a", File.basename("a")) assert_equal("b", File.basename("a/b")) assert_equal("b", File.basename("a/b/")) assert_equal("/", File.basename("/")) assert_equal("/", File.basename("//")) assert_equal("/", File.basename("///")) assert_equal("b", File.basename("a/b////")) assert_equal("a", File.basename("a.rb", ".rb")) assert_equal("a", File.basename("a.rb///", ".rb")) assert_equal("a", File.basename("a.rb///", ".*")) assert_equal("a.rb", File.basename("a.rb///", ".c")) assert_equal(".", File.dirname("a")) assert_equal("/", File.dirname("/")) assert_equal("/", File.dirname("/a")) assert_equal("a", File.dirname("a/b")) assert_equal("a/b", File.dirname("a/b/c")) assert_equal("/a/b", File.dirname("/a/b/c")) assert_equal("/a", File.dirname("/a/b/")) assert_equal("/a", File.dirname("/a/b///")) case Dir.pwd when %r'\A\w:' assert_match(/\A\w:\/\z/, File.expand_path(".", "/")) assert_match(/\A\w:\/a\z/, File.expand_path("a", "/")) dosish = true when %r'\A//' assert_match(%r'\A//[^/]+/[^/]+\z', File.expand_path(".", "/")) assert_match(%r'\A//[^/]+/[^/]+/a\z', File.expand_path(".", "/")) dosish = true else assert_equal("/", File.expand_path(".", "/")) assert_equal("/sub", File.expand_path("sub", "/")) end if dosish assert_equal("//machine/share", File.expand_path("/", "//machine/share/sub")) assert_equal("//machine/share/dir", File.expand_path("/dir", "//machine/share/sub")) assert_equal("z:/", File.expand_path("/", "z:/sub")) assert_equal("z:/dir", File.expand_path("/dir", "z:/sub")) end assert_equal("//", File.expand_path(".", "//")) assert_equal("//sub", File.expand_path("sub", "//")) end def test_dirname # [ruby-dev:27738] if /(bcc|ms)win\d|mingw|cygwin|djgpp|human|emx/ =~ RUBY_PLATFORM # DOSISH_DRIVE_LETTER assert_equal('C:.', File.dirname('C:')) assert_equal('C:.', File.dirname('C:a')) assert_equal('C:.', File.dirname('C:a/')) assert_equal('C:a', File.dirname('C:a/b')) assert_equal('C:/', File.dirname('C:/')) assert_equal('C:/', File.dirname('C:/a')) assert_equal('C:/', File.dirname('C:/a/')) assert_equal('C:/a', File.dirname('C:/a/b')) assert_equal('C:/', File.dirname('C://')) assert_equal('C:/', File.dirname('C://a')) assert_equal('C:/', File.dirname('C://a/')) assert_equal('C:/a', File.dirname('C://a/b')) assert_equal('C:/', File.dirname('C:///')) assert_equal('C:/', File.dirname('C:///a')) assert_equal('C:/', File.dirname('C:///a/')) assert_equal('C:/a', File.dirname('C:///a/b')) else # others assert_equal('.', File.dirname('C:')) assert_equal('.', File.dirname('C:a')) assert_equal('.', File.dirname('C:a/')) assert_equal('C:a', File.dirname('C:a/b')) assert_equal('.', File.dirname('C:/')) assert_equal('C:', File.dirname('C:/a')) assert_equal('C:', File.dirname('C:/a/')) assert_equal('C:/a', File.dirname('C:/a/b')) assert_equal('.', File.dirname('C://')) assert_equal('C:', File.dirname('C://a')) assert_equal('C:', File.dirname('C://a/')) # not spec. #assert_equal('C://a', File.dirname('C://a/b')) assert_equal('.', File.dirname('C:///')) assert_equal('C:', File.dirname('C:///a')) assert_equal('C:', File.dirname('C:///a/')) # not spec. #assert_equal('C:///a', File.dirname('C:///a/b')) end assert_equal('.', File.dirname('')) assert_equal('.', File.dirname('a')) assert_equal('.', File.dirname('a/')) assert_equal('a', File.dirname('a/b')) assert_equal('/', File.dirname('/')) assert_equal('/', File.dirname('/a')) assert_equal('/', File.dirname('/a/')) assert_equal('/a', File.dirname('/a/b')) if /(bcc|ms|cyg)win|mingw|djgpp|human|emx/ =~ RUBY_PLATFORM # DOSISH_UNC assert_equal('//', File.dirname('//')) assert_equal('//a', File.dirname('//a')) assert_equal('//a', File.dirname('//a/')) assert_equal('//a/b', File.dirname('//a/b')) assert_equal('//a/b', File.dirname('//a/b/')) assert_equal('//a/b', File.dirname('//a/b/c')) assert_equal('//', File.dirname('///')) assert_equal('//a', File.dirname('///a')) assert_equal('//a', File.dirname('///a/')) assert_equal('//a/b', File.dirname('///a/b')) assert_equal('//a/b', File.dirname('///a/b/')) assert_equal('//a/b', File.dirname('///a/b/c')) else # others assert_equal('/', File.dirname('//')) assert_equal('/', File.dirname('//a')) assert_equal('/', File.dirname('//a/')) assert_equal('/a', File.dirname('//a/b')) assert_equal('/a', File.dirname('//a/b/')) assert_equal('/a/b', File.dirname('//a/b/c')) assert_equal('/', File.dirname('///')) assert_equal('/', File.dirname('///a')) assert_equal('/', File.dirname('///a/')) assert_equal('/a', File.dirname('///a/b')) assert_equal('/a', File.dirname('///a/b/')) assert_equal('/a/b', File.dirname('///a/b/c')) end end def test_basename # [ruby-dev:27766] if /(bcc|ms)win\d|mingw|cygwin|djgpp|human|emx/ =~ RUBY_PLATFORM # DOSISH_DRIVE_LETTER assert_equal('', File.basename('C:')) assert_equal('a', File.basename('C:a')) assert_equal('a', File.basename('C:a/')) assert_equal('b', File.basename('C:a/b')) assert_equal('/', File.basename('C:/')) assert_equal('a', File.basename('C:/a')) assert_equal('a', File.basename('C:/a/')) assert_equal('b', File.basename('C:/a/b')) assert_equal('/', File.basename('C://')) assert_equal('a', File.basename('C://a')) assert_equal('a', File.basename('C://a/')) assert_equal('b', File.basename('C://a/b')) assert_equal('/', File.basename('C:///')) assert_equal('a', File.basename('C:///a')) assert_equal('a', File.basename('C:///a/')) assert_equal('b', File.basename('C:///a/b')) else # others assert_equal('C:', File.basename('C:')) assert_equal('C:a', File.basename('C:a')) assert_equal('C:a', File.basename('C:a/')) assert_equal('b', File.basename('C:a/b')) assert_equal('C:', File.basename('C:/')) assert_equal('a', File.basename('C:/a')) assert_equal('a', File.basename('C:/a/')) assert_equal('b', File.basename('C:/a/b')) assert_equal('C:', File.basename('C://')) assert_equal('a', File.basename('C://a')) assert_equal('a', File.basename('C://a/')) assert_equal('b', File.basename('C://a/b')) assert_equal('C:', File.basename('C:///')) assert_equal('a', File.basename('C:///a')) assert_equal('a', File.basename('C:///a/')) assert_equal('b', File.basename('C:///a/b')) end assert_equal('', File.basename('')) assert_equal('a', File.basename('a')) assert_equal('a', File.basename('a/')) assert_equal('b', File.basename('a/b')) assert_equal('/', File.basename('/')) assert_equal('a', File.basename('/a')) assert_equal('a', File.basename('/a/')) assert_equal('b', File.basename('/a/b')) if /(bcc|ms|cyg)win|mingw|djgpp|human|emx/ =~ RUBY_PLATFORM # DOSISH_UNC assert_equal('/', File.basename('//')) assert_equal('/', File.basename('//a')) assert_equal('/', File.basename('//a/')) assert_equal('/', File.basename('//a/b')) assert_equal('/', File.basename('//a/b/')) assert_equal('c', File.basename('//a/b/c')) assert_equal('/', File.basename('///')) assert_equal('/', File.basename('///a')) assert_equal('/', File.basename('///a/')) assert_equal('/', File.basename('///a/b')) assert_equal('/', File.basename('///a/b/')) assert_equal('c', File.basename('///a/b/c')) else # others assert_equal('/', File.basename('//')) assert_equal('a', File.basename('//a')) assert_equal('a', File.basename('//a/')) assert_equal('b', File.basename('//a/b')) assert_equal('b', File.basename('//a/b/')) assert_equal('c', File.basename('//a/b/c')) assert_equal('/', File.basename('///')) assert_equal('a', File.basename('///a')) assert_equal('a', File.basename('///a/')) assert_equal('b', File.basename('///a/b')) assert_equal('b', File.basename('///a/b/')) assert_equal('c', File.basename('///a/b/c')) end end end ================================================ FILE: test/ruby/test_pipe.rb ================================================ require 'test/unit' $:.replace([File.dirname(File.expand_path(__FILE__))] | $:) require 'ut_eof' require 'envutil' class TestPipe < Test::Unit::TestCase include TestEOF def open_file(content) r, w = IO.pipe w << content w.close begin yield r ensure r.close end end def test_write bug2559 = '[ruby-core:27425]' a, b = IO.pipe begin a.close assert_raises(Errno::EPIPE, bug2559) do b.write("hi") end ensure a.close if !a.closed? b.close if !b.closed? end end end ================================================ FILE: test/ruby/test_proc.rb ================================================ require 'test/unit' class TestProc < Test::Unit::TestCase def test_proc p1 = proc{|i| i} assert_equal(2, p1.call(2)) assert_equal(3, p1.call(3)) p1 = proc{|i| i*2} assert_equal(4, p1.call(2)) assert_equal(6, p1.call(3)) p2 = nil x=0 proc{ iii=5 # nested local variable p1 = proc{|i| iii = i } p2 = proc { x = iii # nested variables shared by procs } # scope of nested variables assert(defined?(iii)) }.call assert(!defined?(iii)) # out of scope loop{iii=5; assert(eval("defined? iii")); break} loop { iii = 10 def self.dyna_var_check loop { assert(!defined?(iii)) break } end dyna_var_check break } p1.call(5) p2.call assert_equal(5, x) end def assert_arity(n) meta = class << self; self; end meta.class_eval {define_method(:foo, Proc.new)} assert_equal(n, method(:foo).arity) end def test_arity assert_equal(-1, proc{}.arity) assert_equal(0, proc{||}.arity) assert_equal(1, proc{|x|}.arity) assert_equal(2, proc{|x, y|}.arity) assert_equal(-2, proc{|x, *y|}.arity) assert_equal(-1, proc{|*x|}.arity) assert_equal(-1, proc{|*|}.arity) assert_arity(-1) {} assert_arity(0) {||} assert_arity(1) {|x|} assert_arity(2) {|x, y|} assert_arity(-2) {|x, *y|} assert_arity(-1) {|*x|} assert_arity(-1) {|*|} end # [ruby-dev:22592] def m(x) lambda { x } end def test_eq # [ruby-dev:22592] a = m(1) b = m(2) assert_not_equal(a, b) assert_not_equal(a.call, b.call) # [ruby-dev:22599] assert_not_equal(proc {||}, proc {|x,y|}) # [ruby-dev:22601] a = lambda {|x| lambda {} }.call(1) b = lambda {} assert_not_equal(a, b) end def test_block_par assert_equal(10, Proc.new{|&b| b.call(10)}.call {|x| x}) assert_equal(12, Proc.new{|a,&b| b.call(a)}.call(12) {|x| x}) end def test_define_method_scope a = 1 c = Class.new c.send(:define_method, :x) do |*| lambda {a = 2}.call end c.new.x(nil) assert_equal(2, a, '[ruby-core:23050]') end end ================================================ FILE: test/ruby/test_process.rb ================================================ require 'test/unit' class TestProcess < Test::Unit::TestCase def test_rlimit_availability begin Process.getrlimit(nil) rescue NotImplementedError assert_raise(NotImplementedError) { Process.setrlimit } rescue TypeError assert_raise(ArgumentError) { Process.setrlimit } end end def rlimit_exist? Process.getrlimit(nil) rescue NotImplementedError return false rescue TypeError return true end def test_rlimit_nofile return unless rlimit_exist? pid = fork { cur_nofile, max_nofile = Process.getrlimit(Process::RLIMIT_NOFILE) begin Process.setrlimit(Process::RLIMIT_NOFILE, 0, max_nofile) rescue Errno::EINVAL exit 0 end begin IO.pipe rescue Errno::EMFILE exit 0 end exit 1 } Process.wait pid assert_equal(0, $?.to_i) end end ================================================ FILE: test/ruby/test_rand.rb ================================================ require 'test/unit' class TestRand < Test::Unit::TestCase def test_mt srand(0x00000456_00000345_00000234_00000123) %w(1067595299 955945823 477289528 4107218783 4228976476).each {|w| assert_equal(w.to_i, rand(0x100000000)) } end def test_0x3fffffff srand(0) %w(209652396 398764591 924231285 404868288 441365315).each {|w| assert_equal(w.to_i, rand(0x3fffffff)) } end def test_0x40000000 srand(0) %w(209652396 398764591 924231285 404868288 441365315).each {|w| assert_equal(w.to_i, rand(0x40000000)) } end def test_0x40000001 srand(0) %w(209652396 398764591 924231285 441365315 192771779).each {|w| assert_equal(w.to_i, rand(0x40000001)) } end def test_0xffffffff srand(0) %w(2357136044 2546248239 3071714933 3626093760 2588848963).each {|w| assert_equal(w.to_i, rand(0xffffffff)) } end def test_0x100000000 srand(0) %w(2357136044 2546248239 3071714933 3626093760 2588848963).each {|w| assert_equal(w.to_i, rand(0x100000000)) } end def test_0x100000001 srand(0) %w(2546248239 1277901399 243580376 1171049868 2051556033).each {|w| assert_equal(w.to_i, rand(0x100000001)) } end def test_rand_0x100000000 srand(311702798) %w(4119812344 3870378946 80324654 4294967296 410016213).each {|w| assert_equal(w.to_i, rand(0x100000001)) } end def test_0x1000000000000 srand(0) %w(11736396900911 183025067478208 197104029029115 130583529618791 180361239846611).each {|w| assert_equal(w.to_i, rand(0x1000000000000)) } end def test_0x1000000000001 srand(0) %w(187121911899765 197104029029115 180361239846611 236336749852452 208739549485656).each {|w| assert_equal(w.to_i, rand(0x1000000000001)) } end def test_0x3fffffffffffffff srand(0) %w(900450186894289455 3969543146641149120 1895649597198586619 827948490035658087 3203365596207111891).each {|w| assert_equal(w.to_i, rand(0x3fffffffffffffff)) } end def test_0x4000000000000000 srand(0) %w(900450186894289455 3969543146641149120 1895649597198586619 827948490035658087 3203365596207111891).each {|w| assert_equal(w.to_i, rand(0x4000000000000000)) } end def test_0x4000000000000001 srand(0) %w(900450186894289455 3969543146641149120 1895649597198586619 827948490035658087 2279347887019741461).each {|w| assert_equal(w.to_i, rand(0x4000000000000001)) } end def test_neg_0x10000000000 ws = %w(455570294424 1073054410371 790795084744 2445173525 1088503892627) srand(3) ws.each {|w| assert_equal(w.to_i, rand(0x10000000000)) } srand(3) ws.each {|w| assert_equal(w.to_i, rand(-0x10000000000)) } end def test_neg_0x10000 ws = %w(2732 43567 42613 52416 45891) srand(0) ws.each {|w| assert_equal(w.to_i, rand(0x10000)) } srand(0) ws.each {|w| assert_equal(w.to_i, rand(-0x10000)) } end end ================================================ FILE: test/ruby/test_range.rb ================================================ require 'test/unit' class TestRange < Test::Unit::TestCase def test_range_string # XXX: Is this really the test of Range? assert_equal([], ("a" ... "a").to_a) assert_equal(["a"], ("a" .. "a").to_a) assert_equal(["a"], ("a" ... "b").to_a) assert_equal(["a", "b"], ("a" .. "b").to_a) end def test_evaluation_order arr = [1,2] r = (arr.shift)..(arr.shift) assert_equal(1..2, r, "[ruby-dev:26383]") end end ================================================ FILE: test/ruby/test_readpartial.rb ================================================ require 'test/unit' require 'timeout' require 'fcntl' class TestReadPartial < Test::Unit::TestCase def make_pipe r, w = IO.pipe begin yield r, w ensure r.close unless r.closed? w.close unless w.closed? end end def pipe make_pipe {|r, w| yield r, w } return unless defined?(Fcntl::F_SETFL) return unless defined?(Fcntl::F_GETFL) return unless defined?(Fcntl::O_NONBLOCK) make_pipe {|r, w| r.fcntl(Fcntl::F_SETFL, r.fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK) yield r, w } end def test_length_zero pipe {|r, w| assert_equal('', r.readpartial(0)) } end def test_closed_pipe pipe {|r, w| w << 'abc' w.close assert_equal('ab', r.readpartial(2)) assert_equal('c', r.readpartial(2)) assert_raises(EOFError) { r.readpartial(2) } assert_raises(EOFError) { r.readpartial(2) } } end if !File::ALT_SEPARATOR # read on pipe cannot timeout on Windows. def test_open_pipe pipe {|r, w| w << 'abc' assert_equal('ab', r.readpartial(2)) assert_equal('c', r.readpartial(2)) assert_raises(TimeoutError) { timeout(0.1) { r.readpartial(2) } } } end def test_with_stdio pipe {|r, w| w << "abc\ndef\n" assert_equal("abc\n", r.gets) w << "ghi\n" assert_equal("de", r.readpartial(2)) assert_equal("f\n", r.readpartial(4096)) assert_equal("ghi\n", r.readpartial(4096)) assert_raises(TimeoutError) { timeout(0.1) { r.readpartial(2) } } } end end end ================================================ FILE: test/ruby/test_settracefunc.rb ================================================ require 'test/unit' class TestSetTraceFunc < Test::Unit::TestCase def foo; end; def bar events = [] set_trace_func(Proc.new { |event, file, lineno, mid, bidning, klass| events << [event, lineno, mid, klass] }) return events end def test_event events = [] set_trace_func(Proc.new { |event, file, lineno, mid, bidning, klass| events << [event, lineno, mid, klass] }) a = 1 foo a b = 1 + 2 if b == 3 case b when 2 c = "b == 2" when 3 c = "b == 3" end end begin raise "error" rescue end eval("class Foo; end") set_trace_func nil assert_equal(["line", 19, :test_event, TestSetTraceFunc], events.shift) # a = 1 assert_equal(["line", 20, :test_event, TestSetTraceFunc], events.shift) # foo assert_equal(["call", 4, :foo, TestSetTraceFunc], events.shift) # foo assert_equal(["return", 4, :foo, TestSetTraceFunc], events.shift) # foo assert_equal(["line", 21, :test_event, TestSetTraceFunc], events.shift) # a assert_equal(["line", 22, :test_event, TestSetTraceFunc], events.shift) # b = 1 + 2 assert_equal(["c-call", 22, :+, Fixnum], events.shift) # 1 + 2 assert_equal(["c-return", 22, :+, Fixnum], events.shift) # 1 + 2 assert_equal(["line", 23, :test_event, TestSetTraceFunc], events.shift) # if b == 3 assert_equal(["c-call", 23, :==, Fixnum], events.shift) # b == 3 assert_equal(["c-return", 23, :==, Fixnum], events.shift) # b == 3 assert_equal(["line", 23, :test_event, TestSetTraceFunc], events.shift) # if b == 3 assert_equal(["line", 24, :test_event, TestSetTraceFunc], events.shift) # case b assert_equal(["line", 25, :test_event, TestSetTraceFunc], events.shift) # when 2 assert_equal(["c-call", 25, :===, Kernel], events.shift) # when 2 assert_equal(["c-call", 25, :==, Fixnum], events.shift) # when 2 assert_equal(["c-return", 25, :==, Fixnum], events.shift) # when 2 assert_equal(["c-return", 25, :===, Kernel], events.shift) # when 2 assert_equal(["line", 27, :test_event, TestSetTraceFunc], events.shift) # when 3 assert_equal(["c-call", 27, :===, Kernel], events.shift) # when 3 assert_equal(["c-return", 27, :===, Kernel], events.shift) # when 3 assert_equal(["line", 28, :test_event, TestSetTraceFunc], events.shift) # c = "b == 3" assert_equal(["line", 31, :test_event, TestSetTraceFunc], events.shift) # begin assert_equal(["line", 32, :test_event, TestSetTraceFunc], events.shift) # raise "error" assert_equal(["c-call", 32, :raise, Kernel], events.shift) # raise "error" assert_equal(["c-call", 32, :new, Class], events.shift) # raise "error" assert_equal(["c-call", 32, :initialize, Exception], events.shift) # raise "error" assert_equal(["c-return", 32, :initialize, Exception], events.shift) # raise "error" assert_equal(["c-return", 32, :new, Class], events.shift) # raise "error" assert_equal(["c-call", 32, :backtrace, Exception], events.shift) # raise "error" assert_equal(["c-return", 32, :backtrace, Exception], events.shift) # raise "error" assert_equal(["c-call", 32, :set_backtrace, Exception], events.shift) # raise "error" assert_equal(["c-return", 32, :set_backtrace, Exception], events.shift) # raise "error" assert_equal(["raise", 32, :test_event, TestSetTraceFunc], events.shift) # raise "error" assert_equal(["c-return", 32, :raise, Kernel], events.shift) # raise "error" assert_equal(["line", 35, :test_event, TestSetTraceFunc], events.shift) # eval(<", $x.sub(/.*\.([^\.]+)$/, '<\&>')) end def test_char # character constants(assumes ASCII) assert_equal(?a, "a"[0]) assert_equal(?a, ?a) assert_equal(1, ?\C-a) assert_equal(225, ?\M-a) assert_equal(129, ?\M-\C-a) assert_equal(?A, "a".upcase![0]) assert_equal(?a, "A".downcase![0]) assert_equal("ABC", "abc".tr!("a-z", "A-Z")) assert_equal("ABC", "aabbcccc".tr_s!("a-z", "A-Z")) assert_equal("abc", "abcc".squeeze!("a-z")) assert_equal("ad", "abcd".delete!("bc")) $x = "abcdef" $y = [ ?a, ?b, ?c, ?d, ?e, ?f ] $bad = false $x.each_byte {|i| if i != $y.shift $bad = true break end } assert(!$bad) s = "a string" s[0..s.size]="another string" assert_equal("another string", s) s = <>') assert_inspect_evaled(':<=') assert_inspect_evaled(':>=') assert_inspect_evaled(':=~') assert_inspect_evaled(':==') assert_inspect_evaled(':===') assert_raise(SyntaxError) {eval ':='} assert_inspect_evaled(':*') assert_inspect_evaled(':**') assert_raise(SyntaxError) {eval ':***'} assert_inspect_evaled(':+') assert_inspect_evaled(':-') assert_inspect_evaled(':+@') assert_inspect_evaled(':-@') assert_inspect_evaled(':|') assert_inspect_evaled(':^') assert_inspect_evaled(':&') assert_inspect_evaled(':/') assert_inspect_evaled(':%') assert_inspect_evaled(':~') assert_inspect_evaled(':`') assert_inspect_evaled(':[]') assert_inspect_evaled(':[]=') assert_raise(SyntaxError) {eval ':||'} assert_raise(SyntaxError) {eval ':&&'} assert_raise(SyntaxError) {eval ':['} end def test_inspect_dollar # 4) :$- always treats next character literally: sym = "$-".intern assert_nothing_raised(SyntaxError) {assert_equal(sym, eval(':$-'))} assert_nothing_raised(SyntaxError) {assert_equal(sym, eval(":$-\n"))} assert_nothing_raised(SyntaxError) {assert_equal(sym, eval(":$- "))} assert_nothing_raised(SyntaxError) {assert_equal(sym, eval(":$-#"))} assert_raise(SyntaxError) {eval ':$-('} end def test_inspect_number # 5) Inconsistency between :$0 and :$1? The first one is valid, but the # latter isn't. assert_inspect_evaled(':$0') assert_inspect_evaled(':$1') end def test_to_proc assert_equal %w(1 2 3), (1..3).map(&:to_s) [ [], [1], [1, 2], [1, [2, 3]], ].each do |ary| ary_id = ary.object_id assert_equal ary_id, :object_id.to_proc.call(ary) ary_ids = ary.collect{|x| x.object_id } assert_equal ary_ids, ary.collect(&:object_id) end end end ================================================ FILE: test/ruby/test_system.rb ================================================ require 'test/unit' $:.replace([File.dirname(File.expand_path(__FILE__))] | $:) require 'envutil' class TestSystem < Test::Unit::TestCase def valid_syntax?(code, fname) code = code.sub(/\A(?:\s*\#.*$)*(\n)?/n) { "#$&#{"\n" if $1 && !$2}BEGIN{return true}\n" } eval(code, nil, fname, 0) end def test_system ruby = EnvUtil.rubybin assert_equal("foobar\n", `echo foobar`) assert_equal('foobar', `#{ruby} -e 'print "foobar"'`) tmp = open("script_tmp", "w") tmp.print "print $zzz\n"; tmp.close assert_equal('true', `#{ruby} -s script_tmp -zzz`) assert_equal('555', `#{ruby} -s script_tmp -zzz=555`) tmp = open("script_tmp", "w") tmp.print "#! /usr/local/bin/ruby -s\n"; tmp.print "print $zzz\n"; tmp.close assert_equal('678', `#{ruby} script_tmp -zzz=678`) tmp = open("script_tmp", "w") tmp.print "this is a leading junk\n"; tmp.print "#! /usr/local/bin/ruby -s\n"; tmp.print "print $zzz\n"; tmp.print "__END__\n"; tmp.print "this is a trailing junk\n"; tmp.close assert_equal('nil', `#{ruby} -x script_tmp`) assert_equal('555', `#{ruby} -x script_tmp -zzz=555`) tmp = open("script_tmp", "w") for i in 1..5 tmp.print i, "\n" end tmp.close `#{ruby} -i.bak -pe 'sub(/^[0-9]+$/){$&.to_i * 5}' script_tmp` tmp = open("script_tmp", "r") while tmp.gets assert_equal(0, $_.to_i % 5) end tmp.close File.unlink "script_tmp" or `/bin/rm -f "script_tmp"` File.unlink "script_tmp.bak" or `/bin/rm -f "script_tmp.bak"` end def test_syntax assert_nothing_raised(Exception) do for script in Dir[File.expand_path("../../../{lib,sample,ext}/**/*.rb", __FILE__)] valid_syntax? IO::read(script), script end end end end ================================================ FILE: test/ruby/test_time.rb ================================================ require 'test/unit' class TestTime < Test::Unit::TestCase def test_time_add() assert_equal(Time.utc(2000, 3, 21, 3, 30) + 3 * 3600, Time.utc(2000, 3, 21, 6, 30)) assert_equal(Time.utc(2000, 3, 21, 3, 30) + (-3 * 3600), Time.utc(2000, 3, 21, 0, 30)) assert_equal(0, (Time.at(1.1) + 0.9).usec) end def test_time_subt() assert_equal(Time.utc(2000, 3, 21, 3, 30) - 3 * 3600, Time.utc(2000, 3, 21, 0, 30)) assert_equal(Time.utc(2000, 3, 21, 3, 30) - (-3 * 3600), Time.utc(2000, 3, 21, 6, 30)) assert_equal(900000, (Time.at(1.1) - 0.2).usec) end def test_time_time() assert_equal(Time.utc(2000, 3, 21, 3, 30) \ -Time.utc(2000, 3, 21, 0, 30), 3*3600) assert_equal(Time.utc(2000, 3, 21, 0, 30) \ -Time.utc(2000, 3, 21, 3, 30), -3*3600) end def negative_time_t? begin Time.at(-1) true rescue ArgumentError false end end def test_timegm if negative_time_t? assert_equal(-0x80000000, Time.utc(1901, 12, 13, 20, 45, 52).tv_sec) assert_equal(-2, Time.utc(1969, 12, 31, 23, 59, 58).tv_sec) assert_equal(-1, Time.utc(1969, 12, 31, 23, 59, 59).tv_sec) end assert_equal(0, Time.utc(1970, 1, 1, 0, 0, 0).tv_sec) # the Epoch assert_equal(1, Time.utc(1970, 1, 1, 0, 0, 1).tv_sec) assert_equal(31535999, Time.utc(1970, 12, 31, 23, 59, 59).tv_sec) assert_equal(31536000, Time.utc(1971, 1, 1, 0, 0, 0).tv_sec) assert_equal(78796799, Time.utc(1972, 6, 30, 23, 59, 59).tv_sec) # 1972-06-30T23:59:60Z is the first leap second. if Time.utc(1972, 7, 1, 0, 0, 0) - Time.utc(1972, 6, 30, 23, 59, 59) == 1 # no leap second. assert_equal(78796800, Time.utc(1972, 7, 1, 0, 0, 0).tv_sec) assert_equal(78796801, Time.utc(1972, 7, 1, 0, 0, 1).tv_sec) assert_equal(946684800, Time.utc(2000, 1, 1, 0, 0, 0).tv_sec) assert_equal(0x7fffffff, Time.utc(2038, 1, 19, 3, 14, 7).tv_sec) else # leap seconds supported. assert_equal(2, Time.utc(1972, 7, 1, 0, 0, 0) - Time.utc(1972, 6, 30, 23, 59, 59)) assert_equal(78796800, Time.utc(1972, 6, 30, 23, 59, 60).tv_sec) assert_equal(78796801, Time.utc(1972, 7, 1, 0, 0, 0).tv_sec) assert_equal(78796802, Time.utc(1972, 7, 1, 0, 0, 1).tv_sec) assert_equal(946684822, Time.utc(2000, 1, 1, 0, 0, 0).tv_sec) end end def test_huge_difference # [ruby-dev:22619] if negative_time_t? assert_equal(Time.at(-0x80000000), Time.at(0x7fffffff) - 0xffffffff) assert_equal(Time.at(-0x80000000), Time.at(0x7fffffff) + (-0xffffffff)) assert_equal(Time.at(0x7fffffff), Time.at(-0x80000000) + 0xffffffff) assert_equal(Time.at(0x7fffffff), Time.at(-0x80000000) - (-0xffffffff)) end end def test_at assert_equal(100000, Time.at(0.1).usec) assert_equal(10000, Time.at(0.01).usec) assert_equal(1000, Time.at(0.001).usec) assert_equal(100, Time.at(0.0001).usec) assert_equal(10, Time.at(0.00001).usec) assert_equal(1, Time.at(0.000001).usec) assert_equal(0, Time.at(1e-7).usec) assert_equal(0, Time.at(4e-7).usec) assert_equal(1, Time.at(6e-7).usec) assert_equal(1, Time.at(14e-7).usec) assert_equal(2, Time.at(16e-7).usec) if negative_time_t? assert_equal(0, Time.at(-1e-7).usec) assert_equal(0, Time.at(-4e-7).usec) assert_equal(999999, Time.at(-6e-7).usec) assert_equal(999999, Time.at(-14e-7).usec) assert_equal(999998, Time.at(-16e-7).usec) end end end ================================================ FILE: test/ruby/test_trace.rb ================================================ require 'test/unit' class TestTrace < Test::Unit::TestCase def test_trace $x = 1234 $y = 0 trace_var :$x, proc{$y = $x} $x = 40414 assert_equal($x, $y) untrace_var :$x $x = 19660208 assert_not_equal($x, $y) trace_var :$x, proc{$x *= 2} $x = 5 assert_equal(10, $x) untrace_var :$x end end ================================================ FILE: test/ruby/test_variable.rb ================================================ require 'test/unit' class TestVariable < Test::Unit::TestCase class Gods @@rule = "Uranus" def ruler0 @@rule end def self.ruler1 # <= per method definition style @@rule end class << self # <= multiple method definition style def ruler2 @@rule end end end module Olympians @@rule ="Zeus" def ruler3 @@rule end end class Titans < Gods @@rule = "Cronus" include Olympians # OK to cause warning (intentional) end def test_variable assert_instance_of(Fixnum, $$) # read-only variable assert_raises(NameError) do $$ = 5 end foobar = "foobar" $_ = foobar assert_equal(foobar, $_) assert_equal("Cronus", Gods.new.ruler0) assert_equal("Cronus", Gods.ruler1) assert_equal("Cronus", Gods.ruler2) assert_equal("Cronus", Titans.ruler1) assert_equal("Cronus", Titans.ruler2) atlas = Titans.new assert_equal("Cronus", atlas.ruler0) assert_equal("Zeus", atlas.ruler3) end end ================================================ FILE: test/ruby/test_whileuntil.rb ================================================ require 'test/unit' class TestWhileuntil < Test::Unit::TestCase def test_while tmp = open("while_tmp", "w") tmp.print "tvi925\n"; tmp.print "tvi920\n"; tmp.print "vt100\n"; tmp.print "Amiga\n"; tmp.print "paper\n"; tmp.close tmp = open("while_tmp", "r") assert_instance_of(File, tmp) while line = tmp.gets() break if /vt100/ =~ line end assert(!tmp.eof?) assert_match(/vt100/, line) tmp.close tmp = open("while_tmp", "r") while line = tmp.gets() next if /vt100/ =~ line assert_no_match(/vt100/, line) end assert(tmp.eof?) assert_no_match(/vt100/, line) tmp.close tmp = open("while_tmp", "r") while tmp.gets() line = $_ gsub(/vt100/, 'VT100') if $_ != line $_.gsub!('VT100', 'Vt100') redo end assert_no_match(/vt100/, $_) assert_no_match(/VT100/, $_) end assert(tmp.eof?) tmp.close sum=0 for i in 1..10 sum += i i -= 1 if i > 0 redo end end assert_equal(220, sum) tmp = open("while_tmp", "r") while line = tmp.gets() break if 3 assert_no_match(/vt100/, line) assert_no_match(/Amiga/, line) assert_no_match(/paper/, line) end tmp.close File.unlink "while_tmp" or `/bin/rm -f "while_tmp"` assert(!File.exist?("while_tmp")) end def test_until i = 0 until i>4 i+=1 end assert(i>4) end end ================================================ FILE: test/ruby/ut_eof.rb ================================================ require 'test/unit' module TestEOF def test_eof_0 open_file("") {|f| assert_equal("", f.read(0)) assert_equal("", f.read(0)) assert_equal("", f.read) assert_nil(f.read(0)) assert_nil(f.read(0)) } open_file("") {|f| assert_nil(f.read(1)) assert_equal("", f.read) assert_nil(f.read(1)) } open_file("") {|f| s = "x" assert_equal("", f.read(nil, s)) assert_equal("", s) } open_file("") {|f| s = "x" assert_nil(f.read(10, s)) assert_equal("", s) } end def test_eof_0_rw return unless respond_to? :open_file_rw open_file_rw("") {|f| assert_equal("", f.read) assert_equal("", f.read) assert_equal(0, f.syswrite("")) assert_equal("", f.read) } end def test_eof_1 open_file("a") {|f| assert_equal("", f.read(0)) assert_equal("a", f.read(1)) assert_equal("" , f.read(0)) assert_equal("" , f.read(0)) assert_equal("", f.read) assert_nil(f.read(0)) assert_nil(f.read(0)) } open_file("a") {|f| assert_equal("a", f.read(1)) assert_nil(f.read(1)) } open_file("a") {|f| assert_equal("a", f.read(2)) assert_nil(f.read(1)) assert_equal("", f.read) assert_nil(f.read(1)) } open_file("a") {|f| assert_equal("a", f.read) assert_nil(f.read(1)) assert_equal("", f.read) assert_nil(f.read(1)) } open_file("a") {|f| assert_equal("a", f.read(2)) assert_equal("", f.read) assert_equal("", f.read) } open_file("a") {|f| assert_equal("a", f.read) assert_nil(f.read(0)) } open_file("a") {|f| s = "x" assert_equal("a", f.read(nil, s)) assert_equal("a", s) } open_file("a") {|f| s = "x" assert_equal("a", f.read(10, s)) assert_equal("a", s) } end def test_eof_2 open_file("") {|f| assert_equal("", f.read) assert(f.eof?) } end def test_eof_3 open_file("") {|f| assert(f.eof?) } end module Seek def open_file_seek(content, pos) open_file(content) do |f| f.seek(pos) yield f end end def test_eof_0_seek open_file_seek("", 10) {|f| assert_equal(10, f.pos) assert_equal("", f.read(0)) assert_equal("", f.read) assert_nil(f.read(0)) assert_equal("", f.read) } end def test_eof_1_seek open_file_seek("a", 10) {|f| assert_equal("", f.read) assert_equal("", f.read) } open_file_seek("a", 1) {|f| assert_equal("", f.read) assert_equal("", f.read) } end end end ================================================ FILE: test/runner.rb ================================================ require 'test/unit' rcsid = %w$Id$ Version = rcsid[2].scan(/\d+/).collect!(&method(:Integer)).freeze rescue nil Release = rcsid[3].freeze rescue nil exit Test::Unit::AutoRunner.run(true, File.dirname($0)) ================================================ FILE: test/sdbm/test_sdbm.rb ================================================ require 'test/unit' begin require 'sdbm' rescue LoadError end class TestSDBM < Test::Unit::TestCase def setup @path = "tmptest_sdbm_" assert_instance_of(SDBM, @sdbm = SDBM.new(@path)) end def teardown assert_nil(@sdbm.close) ObjectSpace.each_object(SDBM) do |obj| obj.close unless obj.closed? end File.delete *Dir.glob("tmptest_sdbm*").to_a p Dir.glob("tmptest_sdbm*") if $DEBUG end def check_size(expect, sdbm=@sdbm) assert_equal(expect, sdbm.size) n = 0 sdbm.each { n+=1 } assert_equal(expect, n) if expect == 0 assert_equal(true, sdbm.empty?) else assert_equal(false, sdbm.empty?) end end def have_fork? begin fork{} true rescue NotImplementedError false end end def test_version assert(! SDBM.const_defined?(:VERSION)) end def test_s_new_has_no_block # SDBM.new ignore the block foo = true assert_instance_of(SDBM, sdbm = SDBM.new("tmptest_sdbm") { foo = false }) assert_equal(foo, true) assert_nil(sdbm.close) end def test_s_open_no_create assert_nil(sdbm = SDBM.open("tmptest_sdbm", nil)) ensure sdbm.close if sdbm end def test_s_open_with_block assert_equal(SDBM.open("tmptest_sdbm") { :foo }, :foo) end =begin # Is it guaranteed on many OS? def test_s_open_lock_one_process # locking on one process assert_instance_of(SDBM, sdbm = SDBM.open("tmptest_sdbm", 0644)) assert_raise(Errno::EWOULDBLOCK) { begin SDBM.open("tmptest_sdbm", 0644) rescue Errno::EAGAIN raise Errno::EWOULDBLOCK end } end =end def test_s_open_nolock # sdbm 1.8.0 specific if not defined? SDBM::NOLOCK return end return unless have_fork? # snip this test fork() { assert_instance_of(SDBM, sdbm = SDBM.open("tmptest_sdbm", 0644, SDBM::NOLOCK)) sleep 2 } sleep 1 begin sdbm2 = nil assert_no_exception(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) { assert_instance_of(SDBM, sdbm2 = SDBM.open("tmptest_sdbm", 0644)) } ensure Process.wait sdbm2.close if sdbm2 end p Dir.glob("tmptest_sdbm*") if $DEBUG fork() { assert_instance_of(SDBM, sdbm = SDBM.open("tmptest_sdbm", 0644)) sleep 2 } begin sleep 1 sdbm2 = nil assert_no_exception(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) { # this test is failed on Cygwin98 (???) assert_instance_of(SDBM, sdbm2 = SDBM.open("tmptest_sdbm", 0644, SDBM::NOLOCK)) } ensure Process.wait sdbm2.close if sdbm2 end end def test_s_open_error return if /(ms|bcc)win|mingw|djgpp/ =~ RUBY_PLATFORM assert_instance_of(SDBM, sdbm = SDBM.open("tmptest_sdbm", 0)) assert_raise(Errno::EACCES) { SDBM.open("tmptest_sdbm", 0) } sdbm.close end def test_close assert_instance_of(SDBM, sdbm = SDBM.open("tmptest_sdbm")) assert_nil(sdbm.close) # closed SDBM file assert_raise(SDBMError) { sdbm.close } end def test_aref assert_equal('bar', @sdbm['foo'] = 'bar') assert_equal('bar', @sdbm['foo']) assert_nil(@sdbm['bar']) end def test_fetch assert_equal('bar', @sdbm['foo']='bar') assert_equal('bar', @sdbm.fetch('foo')) # key not found assert_raise(IndexError) { @sdbm.fetch('bar') } # test for `ifnone' arg assert_equal('baz', @sdbm.fetch('bar', 'baz')) # test for `ifnone' block assert_equal('foobar', @sdbm.fetch('bar') {|key| 'foo' + key }) end def test_aset num = 0 2.times {|i| assert_equal('foo', @sdbm['foo'] = 'foo') assert_equal('foo', @sdbm['foo']) assert_equal('bar', @sdbm['foo'] = 'bar') assert_equal('bar', @sdbm['foo']) num += 1 if i == 0 assert_equal(num, @sdbm.size) # assign nil assert_equal('', @sdbm['bar'] = '') assert_equal('', @sdbm['bar']) num += 1 if i == 0 assert_equal(num, @sdbm.size) # empty string assert_equal('', @sdbm[''] = '') assert_equal('', @sdbm['']) num += 1 if i == 0 assert_equal(num, @sdbm.size) # Fixnum assert_equal('200', @sdbm['100'] = '200') assert_equal('200', @sdbm['100']) num += 1 if i == 0 assert_equal(num, @sdbm.size) # Big key and value assert_equal('y' * 100, @sdbm['x' * 100] = 'y' * 100) assert_equal('y' * 100, @sdbm['x' * 100]) num += 1 if i == 0 assert_equal(num, @sdbm.size) } end def test_index assert_equal('bar', @sdbm['foo'] = 'bar') assert_equal('foo', @sdbm.index('bar')) assert_nil(@sdbm['bar']) end def test_indexes keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values assert_equal(values.reverse, @sdbm.indexes(*keys.reverse)) end def test_values_at keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values assert_equal(values.reverse, @sdbm.values_at(*keys.reverse)) end def test_select_with_block keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values ret = @sdbm.select {|k,v| assert_equal(k.upcase, v) k != "bar" } assert_equal([['baz', 'BAZ'], ['foo', 'FOO']], ret.sort) end def test_length num = 10 assert_equal(0, @sdbm.size) num.times {|i| i = i.to_s @sdbm[i] = i } assert_equal(num, @sdbm.size) @sdbm.shift assert_equal(num - 1, @sdbm.size) end def test_empty? assert_equal(true, @sdbm.empty?) @sdbm['foo'] = 'FOO' assert_equal(false, @sdbm.empty?) end def test_each_pair n = 0 @sdbm.each_pair { n += 1 } assert_equal(0, n) keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values n = 0 ret = @sdbm.each_pair {|key, val| assert_not_nil(i = keys.index(key)) assert_equal(val, values[i]) n += 1 } assert_equal(keys.size, n) assert_equal(@sdbm, ret) end def test_each_value n = 0 @sdbm.each_value { n += 1 } assert_equal(0, n) keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values n = 0 ret = @sdbm.each_value {|val| assert_not_nil(key = @sdbm.index(val)) assert_not_nil(i = keys.index(key)) assert_equal(val, values[i]) n += 1 } assert_equal(keys.size, n) assert_equal(@sdbm, ret) end def test_each_key n = 0 @sdbm.each_key { n += 1 } assert_equal(0, n) keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values n = 0 ret = @sdbm.each_key {|key| assert_not_nil(i = keys.index(key)) assert_equal(@sdbm[key], values[i]) n += 1 } assert_equal(keys.size, n) assert_equal(@sdbm, ret) end def test_keys assert_equal([], @sdbm.keys) keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values assert_equal(keys.sort, @sdbm.keys.sort) assert_equal(values.sort, @sdbm.values.sort) end def test_values test_keys end def test_shift assert_nil(@sdbm.shift) assert_equal(0, @sdbm.size) keys = %w(foo bar baz) values = %w(FOO BAR BAZ) @sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values ret_keys = [] ret_values = [] while ret = @sdbm.shift ret_keys.push ret[0] ret_values.push ret[1] assert_equal(keys.size - ret_keys.size, @sdbm.size) end assert_equal(keys.sort, ret_keys.sort) assert_equal(values.sort, ret_values.sort) end def test_delete keys = %w(foo bar baz) values = %w(FOO BAR BAZ) key = keys[1] assert_nil(@sdbm.delete(key)) assert_equal(0, @sdbm.size) @sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values assert_equal('BAR', @sdbm.delete(key)) assert_nil(@sdbm[key]) assert_equal(2, @sdbm.size) assert_nil(@sdbm.delete(key)) end def test_delete_with_block key = 'no called block' @sdbm[key] = 'foo' assert_equal('foo', @sdbm.delete(key) {|k| k.replace 'called block'}) assert_equal('no called block', key) assert_equal(0, @sdbm.size) key = 'no called block' assert_equal(:blockval, @sdbm.delete(key) {|k| k.replace 'called block'; :blockval}) assert_equal('called block', key) assert_equal(0, @sdbm.size) end def test_delete_if v = "0" 100.times {@sdbm[v] = v; v = v.next} ret = @sdbm.delete_if {|key, val| key.to_i < 50} assert_equal(@sdbm, ret) check_size(50, @sdbm) ret = @sdbm.delete_if {|key, val| key.to_i >= 50} assert_equal(@sdbm, ret) check_size(0, @sdbm) # break v = "0" 100.times {@sdbm[v] = v; v = v.next} check_size(100, @sdbm) n = 0; @sdbm.delete_if {|key, val| break if n > 50 n+=1 true } assert_equal(51, n) check_size(49, @sdbm) @sdbm.clear # raise v = "0" 100.times {@sdbm[v] = v; v = v.next} check_size(100, @sdbm) n = 0; begin @sdbm.delete_if {|key, val| raise "runtime error" if n > 50 n+=1 true } rescue end assert_equal(51, n) check_size(49, @sdbm) end def test_reject v = "0" 100.times {@sdbm[v] = v; v = v.next} hash = @sdbm.reject {|key, val| key.to_i < 50} assert_instance_of(Hash, hash) assert_equal(100, @sdbm.size) assert_equal(50, hash.size) hash.each_pair {|key,val| assert_equal(false, key.to_i < 50) assert_equal(key, val) } hash = @sdbm.reject {|key, val| key.to_i < 100} assert_instance_of(Hash, hash) assert_equal(true, hash.empty?) end def test_clear v = "1" 100.times {v = v.next; @sdbm[v] = v} assert_equal(@sdbm, @sdbm.clear) # validate SDBM#size i = 0 @sdbm.each { i += 1 } assert_equal(@sdbm.size, i) assert_equal(0, i) end def test_invert v = "0" 100.times {@sdbm[v] = v; v = v.next} hash = @sdbm.invert assert_instance_of(Hash, hash) assert_equal(100, hash.size) hash.each_pair {|key, val| assert_equal(key.to_i, val.to_i) } end def test_update hash = {} v = "0" 100.times {v = v.next; hash[v] = v} @sdbm["101"] = "101" @sdbm.update hash assert_equal(101, @sdbm.size) @sdbm.each_pair {|key, val| assert_equal(key.to_i, val.to_i) } end def test_replace hash = {} v = "0" 100.times {v = v.next; hash[v] = v} @sdbm["101"] = "101" @sdbm.replace hash assert_equal(100, @sdbm.size) @sdbm.each_pair {|key, val| assert_equal(key.to_i, val.to_i) } end def test_haskey? assert_equal('bar', @sdbm['foo']='bar') assert_equal(true, @sdbm.has_key?('foo')) assert_equal(false, @sdbm.has_key?('bar')) end def test_has_value? assert_equal('bar', @sdbm['foo']='bar') assert_equal(true, @sdbm.has_value?('bar')) assert_equal(false, @sdbm.has_value?('foo')) end def test_to_a v = "0" 100.times {v = v.next; @sdbm[v] = v} ary = @sdbm.to_a assert_instance_of(Array, ary) assert_equal(100, ary.size) ary.each {|key,val| assert_equal(key.to_i, val.to_i) } end def test_to_hash v = "0" 100.times {v = v.next; @sdbm[v] = v} hash = @sdbm.to_hash assert_instance_of(Hash, hash) assert_equal(100, hash.size) hash.each {|key,val| assert_equal(key.to_i, val.to_i) } end end ================================================ FILE: test/soap/asp.net/hello.wsdl ================================================ ================================================ FILE: test/soap/asp.net/test_aspdotnet.rb ================================================ require 'test/unit' require 'soap/rpc/standaloneServer' require 'soap/rpc/driver' module SOAP; module ASPDotNet class TestASPDotNet < Test::Unit::TestCase class Server < ::SOAP::RPC::StandaloneServer Namespace = "http://localhost/WebService/" def on_init add_document_method( self, Namespace + 'SayHello', 'sayHello', XSD::QName.new(Namespace, 'SayHello'), XSD::QName.new(Namespace, 'SayHelloResponse') ) end def sayHello(arg) name = arg['name'] "Hello #{name}" end end Port = 17171 Endpoint = "http://localhost:#{Port}/" def setup setup_server @client = nil end def teardown teardown_server @client.reset_stream if @client end def setup_server @server = Server.new('Test', Server::Namespace, '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @server_thread = start_server_thread(@server) end def teardown_server @server.shutdown @server_thread.kill @server_thread.join end def start_server_thread(server) t = Thread.new { Thread.current.abort_on_exception = true server.start } t end def test_document_method @client = SOAP::RPC::Driver.new(Endpoint, Server::Namespace) @client.wiredump_dev = STDOUT if $DEBUG @client.add_document_method('sayHello', Server::Namespace + 'SayHello', XSD::QName.new(Server::Namespace, 'SayHello'), XSD::QName.new(Server::Namespace, 'SayHelloResponse')) assert_equal("Hello Mike", @client.sayHello(:name => "Mike")) end def test_aspdotnethandler @client = SOAP::RPC::Driver.new(Endpoint, Server::Namespace) @client.wiredump_dev = STDOUT if $DEBUG @client.add_method_with_soapaction('sayHello', Server::Namespace + 'SayHello', 'name') @client.default_encodingstyle = SOAP::EncodingStyle::ASPDotNetHandler::Namespace assert_equal("Hello Mike", @client.sayHello("Mike")) end if defined?(HTTPAccess2) # qualified! REQUEST_ASPDOTNETHANDLER = %q[ Mike ] def test_aspdotnethandler_envelope @client = SOAP::RPC::Driver.new(Endpoint, Server::Namespace) @client.wiredump_dev = str = '' @client.add_method_with_soapaction('sayHello', Server::Namespace + 'SayHello', 'name') @client.default_encodingstyle = SOAP::EncodingStyle::ASPDotNetHandler::Namespace assert_equal("Hello Mike", @client.sayHello("Mike")) assert_equal(REQUEST_ASPDOTNETHANDLER, parse_requestxml(str)) end def parse_requestxml(str) str.split(/\r?\n\r?\n/)[3] end end end end; end ================================================ FILE: test/soap/calc/calc.rb ================================================ module CalcService def self.add(lhs, rhs) lhs + rhs end def self.sub(lhs, rhs) lhs - rhs end def self.multi(lhs, rhs) lhs * rhs end def self.div(lhs, rhs) lhs / rhs end end ================================================ FILE: test/soap/calc/calc2.rb ================================================ class CalcService2 def initialize(value = 0) @value = value end def set_value(value) @value = value end def get_value @value end def +(rhs) @value + rhs end def -(rhs) @value - rhs end def *(rhs) @value * rhs end def /(rhs) @value / rhs end end ================================================ FILE: test/soap/calc/server.cgi ================================================ require 'soap/rpc/cgistub' class CalcServer < SOAP::RPC::CGIStub def initialize(*arg) super require 'calc' servant = CalcService add_servant(servant, 'http://tempuri.org/calcService') end end status = CalcServer.new('CalcServer', nil).start ================================================ FILE: test/soap/calc/server.rb ================================================ #!/usr/bin/env ruby require 'soap/rpc/standaloneServer' require 'calc' class CalcServer < SOAP::RPC::StandaloneServer def initialize(*arg) super servant = CalcService add_servant(servant, 'http://tempuri.org/calcService') end end if $0 == __FILE__ status = CalcServer.new('CalcServer', nil, '0.0.0.0', 17171).start end ================================================ FILE: test/soap/calc/server2.rb ================================================ #!/usr/bin/env ruby require 'soap/rpc/standaloneServer' require 'calc2' class CalcServer2 < SOAP::RPC::StandaloneServer def on_init servant = CalcService2.new add_method(servant, 'set_value', 'newValue') add_method(servant, 'get_value') add_method_as(servant, '+', 'add', 'lhs') add_method_as(servant, '-', 'sub', 'lhs') add_method_as(servant, '*', 'multi', 'lhs') add_method_as(servant, '/', 'div', 'lhs') end end if $0 == __FILE__ status = CalcServer2.new('CalcServer', 'http://tempuri.org/calcService', '0.0.0.0', 17171).start end ================================================ FILE: test/soap/calc/test_calc.rb ================================================ require 'test/unit' require 'soap/rpc/driver' require 'server.rb' module SOAP module Calc class TestCalc < Test::Unit::TestCase Port = 17171 def setup @server = CalcServer.new(self.class.name, nil, '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @t = Thread.new { @server.start } @endpoint = "http://localhost:#{Port}/" @calc = SOAP::RPC::Driver.new(@endpoint, 'http://tempuri.org/calcService') @calc.add_method('add', 'lhs', 'rhs') @calc.add_method('sub', 'lhs', 'rhs') @calc.add_method('multi', 'lhs', 'rhs') @calc.add_method('div', 'lhs', 'rhs') end def teardown @server.shutdown @t.kill @t.join @calc.reset_stream end def test_calc assert_equal(3, @calc.add(1, 2)) assert_equal(-1.1, @calc.sub(1.1, 2.2)) assert_equal(2.42, @calc.multi(1.1, 2.2)) assert_equal(2, @calc.div(5, 2)) assert_equal(2.5, @calc.div(5.0, 2)) assert_equal(1.0/0.0, @calc.div(1.1, 0)) assert_raises(ZeroDivisionError) do @calc.div(1, 0) end end end end end ================================================ FILE: test/soap/calc/test_calc2.rb ================================================ require 'test/unit' require 'soap/rpc/driver' require 'server2.rb' module SOAP module Calc class TestCalc2 < Test::Unit::TestCase Port = 17171 def setup @server = CalcServer2.new('CalcServer', 'http://tempuri.org/calcService', '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @t = Thread.new { Thread.current.abort_on_exception = true @server.start } @endpoint = "http://localhost:#{Port}/" @var = SOAP::RPC::Driver.new(@endpoint, 'http://tempuri.org/calcService') @var.wiredump_dev = STDERR if $DEBUG @var.add_method('set_value', 'newValue') @var.add_method('get_value') @var.add_method_as('+', 'add', 'rhs') @var.add_method_as('-', 'sub', 'rhs') @var.add_method_as('*', 'multi', 'rhs') @var.add_method_as('/', 'div', 'rhs') end def teardown @server.shutdown @t.kill @t.join @var.reset_stream end def test_calc2 assert_equal(1, @var.set_value(1)) assert_equal(3, @var + 2) assert_equal(-1.2, @var - 2.2) assert_equal(2.2, @var * 2.2) assert_equal(0, @var / 2) assert_equal(0.5, @var / 2.0) assert_raises(ZeroDivisionError) do @var / 0 end end end end end ================================================ FILE: test/soap/calc/test_calc_cgi.rb ================================================ require 'test/unit' require 'soap/rpc/driver' require 'logger' require 'webrick' require 'rbconfig' module SOAP module Calc class TestCalcCGI < Test::Unit::TestCase # This test shuld be run after installing ruby. RUBYBIN = File.join( Config::CONFIG["bindir"], Config::CONFIG["ruby_install_name"] + Config::CONFIG["EXEEXT"] ) RUBYBIN << " -d" if $DEBUG Port = 17171 def setup logger = Logger.new(STDERR) logger.level = Logger::Severity::ERROR @server = WEBrick::HTTPServer.new( :BindAddress => "0.0.0.0", :Logger => logger, :Port => Port, :AccessLog => [], :DocumentRoot => File.dirname(File.expand_path(__FILE__)), :CGIPathEnv => ENV['PATH'], :CGIInterpreter => RUBYBIN ) @t = Thread.new { Thread.current.abort_on_exception = true @server.start } @endpoint = "http://localhost:#{Port}/server.cgi" @calc = SOAP::RPC::Driver.new(@endpoint, 'http://tempuri.org/calcService') @calc.wiredump_dev = STDERR if $DEBUG @calc.add_method('add', 'lhs', 'rhs') @calc.add_method('sub', 'lhs', 'rhs') @calc.add_method('multi', 'lhs', 'rhs') @calc.add_method('div', 'lhs', 'rhs') end def teardown @server.shutdown @t.kill @t.join @calc.reset_stream end def test_calc_cgi assert_equal(3, @calc.add(1, 2)) assert_equal(-1.1, @calc.sub(1.1, 2.2)) assert_equal(2.42, @calc.multi(1.1, 2.2)) assert_equal(2, @calc.div(5, 2)) assert_equal(2.5, @calc.div(5.0, 2)) assert_equal(1.0/0.0, @calc.div(1.1, 0)) assert_raises(ZeroDivisionError) do @calc.div(1, 0) end end end end end ================================================ FILE: test/soap/fault/test_customfault.rb ================================================ require 'test/unit' require 'soap/rpc/driver' require 'soap/rpc/standaloneServer' module SOAP module Fault class TestCustomFault < Test::Unit::TestCase Port = 17171 class CustomFaultServer < SOAP::RPC::StandaloneServer def on_init add_method(self, 'fault', 'msg') end def fault(msg) SOAPFault.new(SOAPString.new("mycustom"), SOAPString.new("error: #{msg}"), SOAPString.new(self.class.name)) end end def setup @server = CustomFaultServer.new('customfault', 'urn:customfault', '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @t = Thread.new { Thread.current.abort_on_exception = true @server.start } @endpoint = "http://localhost:#{Port}/" @client = SOAP::RPC::Driver.new(@endpoint, 'urn:customfault') @client.wiredump_dev = STDERR if $DEBUG @client.add_method("fault", "msg") end def teardown @server.shutdown @t.kill @t.join @client.reset_stream end def test_custom_fault begin @client.fault("message") assert(false, 'exception not raised') rescue SOAP::FaultError => e assert(true, 'exception raised') assert_equal('error: message', e.message) end end end end end ================================================ FILE: test/soap/header/server.cgi ================================================ require 'pstore' require 'soap/rpc/cgistub' require 'soap/header/simplehandler' class AuthHeaderPortServer < SOAP::RPC::CGIStub PortName = 'http://tempuri.org/authHeaderPort' SupportPortName = 'http://tempuri.org/authHeaderSupportPort' MyHeaderName = XSD::QName.new("http://tempuri.org/authHeader", "auth") SessionDB = File.join(File.expand_path(File.dirname(__FILE__)), 'session.pstoredb') class AuthHeaderService def self.create new end def deposit(amt) "deposit #{amt} OK" end def withdrawal(amt) "withdrawal #{amt} OK" end end class AuthHeaderSupportService def delete_sessiondb File.unlink(SessionDB) if File.file?(SessionDB) backup = SessionDB + "~" File.unlink(backup) if File.file?(backup) end end def initialize(*arg) super add_rpc_servant(AuthHeaderService.new, PortName) add_rpc_servant(AuthHeaderSupportService.new, SupportPortName) add_rpc_headerhandler(ServerAuthHeaderHandler.new) end class ServerAuthHeaderHandler < SOAP::Header::SimpleHandler Users = { 'NaHi' => 'passwd', 'HiNa' => 'wspass' } def initialize super(MyHeaderName) @db = PStore.new(SessionDB) @db.transaction do @db["root"] = {} unless @db.root?("root") end @userid = @sessionid = nil end def login(userid, passwd) userid and passwd and Users[userid] == passwd end def auth(sessionid) in_sessiondb do |root| root[sessionid][0] end end def create_session(userid) in_sessiondb do |root| while true key = create_sessionkey break unless root[key] end root[key] = [userid] key end end def destroy_session(sessionkey) in_sessiondb do |root| root.delete(sessionkey) end end def on_simple_outbound { "sessionid" => @sessionid } end def on_simple_inbound(my_header, mu) succeeded = false userid = my_header["userid"] passwd = my_header["passwd"] if login(userid, passwd) succeeded = true elsif sessionid = my_header["sessionid"] if userid = auth(sessionid) destroy_session(sessionid) succeeded = true end end raise RuntimeError.new("authentication failed") unless succeeded @userid = userid @sessionid = create_session(userid) end private def create_sessionkey Time.now.usec.to_s end def in_sessiondb @db.transaction do yield(@db["root"]) end end end end status = AuthHeaderPortServer.new('AuthHeaderPortServer', nil).start ================================================ FILE: test/soap/header/test_authheader.rb ================================================ require 'test/unit' require 'soap/rpc/driver' require 'soap/rpc/standaloneServer' require 'soap/header/simplehandler' module SOAP module Header class TestAuthHeader < Test::Unit::TestCase Port = 17171 PortName = 'http://tempuri.org/authHeaderPort' MyHeaderName = XSD::QName.new("http://tempuri.org/authHeader", "auth") DummyHeaderName = XSD::QName.new("http://tempuri.org/authHeader", "dummy") class AuthHeaderPortServer < SOAP::RPC::StandaloneServer class AuthHeaderService def self.create new end def deposit(amt) "deposit #{amt} OK" end def withdrawal(amt) "withdrawal #{amt} OK" end end def initialize(*arg) super add_rpc_servant(AuthHeaderService.new, PortName) ServerAuthHeaderHandler.init add_request_headerhandler(ServerAuthHeaderHandler) end class ServerAuthHeaderHandler < SOAP::Header::SimpleHandler class << self def create new end def init @users = { 'NaHi' => 'passwd', 'HiNa' => 'wspass' } @sessions = {} end def login(userid, passwd) userid and passwd and @users[userid] == passwd end def auth(sessionid) @sessions[sessionid][0] end def create_session(userid) while true key = create_sessionkey break unless @sessions[key] end @sessions[key] = [userid] key end def destroy_session(sessionkey) @sessions.delete(sessionkey) end def sessions @sessions end private def create_sessionkey Time.now.usec.to_s end end def initialize super(MyHeaderName) @userid = @sessionid = nil end def on_simple_outbound { "sessionid" => @sessionid } end def on_simple_inbound(my_header, mu) auth = false userid = my_header["userid"] passwd = my_header["passwd"] if self.class.login(userid, passwd) auth = true elsif sessionid = my_header["sessionid"] if userid = self.class.auth(sessionid) self.class.destroy_session(sessionid) auth = true end end raise RuntimeError.new("authentication failed") unless auth @userid = userid @sessionid = self.class.create_session(userid) end end end class ClientAuthHeaderHandler < SOAP::Header::SimpleHandler def initialize(userid, passwd, mustunderstand) super(MyHeaderName) @sessionid = nil @userid = userid @passwd = passwd @mustunderstand = mustunderstand end def on_simple_outbound if @sessionid { "sessionid" => @sessionid } else { "userid" => @userid, "passwd" => @passwd } end end def on_simple_inbound(my_header, mustunderstand) @sessionid = my_header["sessionid"] end def sessionid @sessionid end end class DummyHeaderHandler < SOAP::Header::SimpleHandler def initialize(mustunderstand) super(DummyHeaderName) @mustunderstand = mustunderstand end def on_simple_outbound { XSD::QName.new("foo", "bar") => nil } end def on_simple_inbound(my_header, mustunderstand) end end def setup @endpoint = "http://localhost:#{Port}/" setup_server setup_client end def setup_server @server = AuthHeaderPortServer.new(self.class.name, nil, '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @t = Thread.new { @server.start } end def setup_client @client = SOAP::RPC::Driver.new(@endpoint, PortName) @client.wiredump_dev = STDERR if $DEBUG @client.add_method('deposit', 'amt') @client.add_method('withdrawal', 'amt') end def teardown teardown_server teardown_client end def teardown_server @server.shutdown @t.kill @t.join end def teardown_client @client.reset_stream end def test_success_no_mu h = ClientAuthHeaderHandler.new('NaHi', 'passwd', false) @client.headerhandler << h do_transaction_check(h) end def test_success_mu h = ClientAuthHeaderHandler.new('NaHi', 'passwd', true) @client.headerhandler << h do_transaction_check(h) end def test_no_mu h = ClientAuthHeaderHandler.new('NaHi', 'passwd', true) @client.headerhandler << h @client.headerhandler << DummyHeaderHandler.new(false) do_transaction_check(h) end def test_mu h = ClientAuthHeaderHandler.new('NaHi', 'passwd', true) @client.headerhandler << h @client.headerhandler << (h2 = DummyHeaderHandler.new(true)) assert_raise(SOAP::UnhandledMustUnderstandHeaderError) do assert_equal("deposit 150 OK", @client.deposit(150)) end @client.headerhandler.delete(h2) @client.headerhandler << (h2 = DummyHeaderHandler.new(false)) do_transaction_check(h) end def do_transaction_check(h) assert_equal("deposit 150 OK", @client.deposit(150)) serversess = AuthHeaderPortServer::ServerAuthHeaderHandler.sessions[h.sessionid] assert_equal("NaHi", serversess[0]) assert_equal("withdrawal 120 OK", @client.withdrawal(120)) serversess = AuthHeaderPortServer::ServerAuthHeaderHandler.sessions[h.sessionid] assert_equal("NaHi", serversess[0]) end def test_authfailure h = ClientAuthHeaderHandler.new('NaHi', 'pa', false) @client.headerhandler << h assert_raises(RuntimeError) do @client.deposit(150) end end end end end ================================================ FILE: test/soap/header/test_authheader_cgi.rb ================================================ require 'test/unit' require 'soap/rpc/driver' require 'soap/rpc/standaloneServer' require 'soap/header/simplehandler' require 'logger' require 'webrick' require 'rbconfig' module SOAP module Header class TestAuthHeaderCGI < Test::Unit::TestCase # This test shuld be run after installing ruby. RUBYBIN = File.join( Config::CONFIG["bindir"], Config::CONFIG["ruby_install_name"] + Config::CONFIG["EXEEXT"] ) RUBYBIN << " -d" if $DEBUG Port = 17171 PortName = 'http://tempuri.org/authHeaderPort' SupportPortName = 'http://tempuri.org/authHeaderSupportPort' MyHeaderName = XSD::QName.new("http://tempuri.org/authHeader", "auth") class ClientAuthHeaderHandler < SOAP::Header::SimpleHandler def initialize(userid, passwd) super(MyHeaderName) @sessionid = nil @userid = userid @passwd = passwd end def on_simple_outbound if @sessionid { "sessionid" => @sessionid } else { "userid" => @userid, "passwd" => @passwd } end end def on_simple_inbound(my_header, mustunderstand) @sessionid = my_header["sessionid"] end def sessionid @sessionid end end def setup @endpoint = "http://localhost:#{Port}/" setup_server setup_client end def setup_server @endpoint = "http://localhost:#{Port}/server.cgi" logger = Logger.new(STDERR) logger.level = Logger::Severity::ERROR @server = WEBrick::HTTPServer.new( :BindAddress => "0.0.0.0", :Logger => logger, :Port => Port, :AccessLog => [], :DocumentRoot => File.dirname(File.expand_path(__FILE__)), :CGIPathEnv => ENV['PATH'], :CGIInterpreter => RUBYBIN ) @t = Thread.new { Thread.current.abort_on_exception = true @server.start } end def setup_client @client = SOAP::RPC::Driver.new(@endpoint, PortName) @client.wiredump_dev = STDERR if $DEBUG @client.add_method('deposit', 'amt') @client.add_method('withdrawal', 'amt') @supportclient = SOAP::RPC::Driver.new(@endpoint, SupportPortName) @supportclient.add_method('delete_sessiondb') end def teardown @supportclient.delete_sessiondb teardown_server teardown_client end def teardown_server @server.shutdown @t.kill @t.join end def teardown_client @client.reset_stream @supportclient.reset_stream end def test_success h = ClientAuthHeaderHandler.new('NaHi', 'passwd') @client.headerhandler << h assert_equal("deposit 150 OK", @client.deposit(150)) assert_equal("withdrawal 120 OK", @client.withdrawal(120)) end def test_authfailure h = ClientAuthHeaderHandler.new('NaHi', 'pa') @client.headerhandler << h assert_raises(RuntimeError) do @client.deposit(150) end end end end end ================================================ FILE: test/soap/header/test_simplehandler.rb ================================================ require 'test/unit' require 'soap/rpc/driver' require 'soap/rpc/standaloneServer' require 'soap/header/simplehandler' module SOAP module Header class TestSimpleHandler < Test::Unit::TestCase Port = 17171 PortName = 'http://tempuri.org/authHeaderPort' class PingPortServer < SOAP::RPC::StandaloneServer class PingService def self.create new end def ping Thread.current[:pingheader] end end def initialize(*arg) super add_rpc_servant(PingService.new, PortName) add_request_headerhandler(PingServerHeaderHandler) end class PingServerHeaderHandler < SOAP::Header::SimpleHandler MyHeaderName = XSD::QName.new("http://xmlsoap.org/Ping", "PingHeader") def self.create new end def initialize() super(MyHeaderName) end def on_simple_outbound "dummy" end def on_simple_inbound(my_header, mu) Thread.current[:pingheader] = my_header end end end class PingClientHeaderHandler < SOAP::Header::SimpleHandler MyHeaderName = XSD::QName.new("http://xmlsoap.org/Ping", "PingHeader") def initialize(pingHeader) super(MyHeaderName) @pingHeader = pingHeader @mustunderstand = false end def on_simple_outbound @pingHeader # --- note, not a Hash end def on_simple_inbound(my_header, mustunderstand) Thread.current[:pingheader] = my_header end end def setup @endpoint = "http://localhost:#{Port}/" setup_server setup_client end def setup_server @server = PingPortServer.new(self.class.name, nil, '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @t = Thread.new { @server.start } end def setup_client @client = SOAP::RPC::Driver.new(@endpoint, PortName) @client.wiredump_dev = STDERR if $DEBUG @client.add_method('ping') end def teardown teardown_server teardown_client end def teardown_server @server.shutdown @t.kill @t.join end def teardown_client @client.reset_stream end def test_string h = PingClientHeaderHandler.new('pingheader') @client.headerhandler << h assert_equal("pingheader", @client.ping) assert_equal("dummy", Thread.current[:pingheader]) end end end end ================================================ FILE: test/soap/helloworld/hw_s.rb ================================================ require 'soap/rpc/standaloneServer' class HelloWorldServer < SOAP::RPC::StandaloneServer def on_init add_method(self, 'hello_world', 'from') end def hello_world(from) "Hello World, from #{ from }" end end if $0 == __FILE__ server = HelloWorldServer.new('hws', 'urn:hws', '0.0.0.0', 17171) server.start end ================================================ FILE: test/soap/helloworld/test_helloworld.rb ================================================ require 'test/unit' require 'soap/rpc/driver' require 'hw_s.rb' module SOAP module HelloWorld class TestHelloWorld < Test::Unit::TestCase Port = 17171 def setup @server = HelloWorldServer.new('hws', 'urn:hws', '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @t = Thread.new { Thread.current.abort_on_exception = true @server.start } @endpoint = "http://localhost:#{Port}/" @client = SOAP::RPC::Driver.new(@endpoint, 'urn:hws') @client.add_method("hello_world", "from") end def teardown @server.shutdown @t.kill @t.join @client.reset_stream end def test_hello_world assert_equal("Hello World, from NaHi", @client.hello_world("NaHi")) assert_equal("Hello World, from <&>", @client.hello_world("<&>")) end end end end ================================================ FILE: test/soap/marshal/test_digraph.rb ================================================ require 'test/unit' require 'soap/marshal' module SOAP module Marshal class Node; include SOAP::Marshallable attr_reader :first, :second, :str def initialize(*init_next) @first = init_next[0] @second = init_next[1] end end class TestDigraph < Test::Unit::TestCase def setup @n9 = Node.new @n81 = Node.new(@n9) @n82 = Node.new(@n9) @n7 = Node.new(@n81, @n82) @n61 = Node.new(@n7) @n62 = Node.new(@n7) @n5 = Node.new(@n61, @n62) @n41 = Node.new(@n5) @n42 = Node.new(@n5) @n3 = Node.new(@n41, @n42) @n21 = Node.new(@n3) @n22 = Node.new(@n3) @n1 = Node.new(@n21, @n22) end def test_marshal f = File.open("digraph_marshalled_string.soap", "wb") SOAP::Marshal.dump(@n1, f) f.close f = File.open("digraph_marshalled_string.soap") str = f.read f.close newnode = SOAP::Marshal.unmarshal(str) assert_equal(newnode.first.first.__id__, newnode.second.first.__id__) assert_equal(newnode.first.first.first.first.__id__, newnode.second.first.second.first.__id__) end def teardown if File.exist?("digraph_marshalled_string.soap") File.unlink("digraph_marshalled_string.soap") end end end end end ================================================ FILE: test/soap/marshal/test_marshal.rb ================================================ require 'test/unit' require 'soap/marshal' dir = File.join(File.dirname(File.expand_path(__FILE__)), '../../ruby') orgpath = $:.dup begin $:.push(dir) require 'marshaltestlib' ensure $:.replace(orgpath) end module SOAP module Marshal class TestMarshal < Test::Unit::TestCase include MarshalTestLib def encode(o) SOAPMarshal.dump(o) end def decode(s) SOAPMarshal.load(s) end end end end ================================================ FILE: test/soap/marshal/test_struct.rb ================================================ require 'test/unit' require 'soap/marshal' module SOAP module Marshal Foo1 = ::Struct.new("Foo1", :m) Foo2 = ::Struct.new(:m) class Foo3 attr_accessor :m end class TestStruct < Test::Unit::TestCase def test_foo1 org = Foo1.new org.m = org obj = convert(org) assert_equal(Foo1, obj.class) assert_equal(obj.m, obj) end def test_foo2 org = Foo2.new org.m = org obj = convert(org) assert_equal(Foo2, obj.class) assert_equal(obj.m, obj) end def test_foo3 org = Foo3.new org.m = org obj = convert(org) assert_equal(Foo3, obj.class) assert_equal(obj.m, obj) end def convert(obj) SOAP::Marshal.unmarshal(SOAP::Marshal.marshal(obj)) end end end end ================================================ FILE: test/soap/ssl/README ================================================ * certificates and keys in this directory is copied from http-access2 test. ================================================ FILE: test/soap/ssl/ca.cert ================================================ -----BEGIN CERTIFICATE----- MIID0DCCArigAwIBAgIBADANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGDAJKUDES MBAGA1UECgwJSklOLkdSLkpQMQwwCgYDVQQLDANSUlIxCzAJBgNVBAMMAkNBMB4X DTA0MDEzMDAwNDIzMloXDTM2MDEyMjAwNDIzMlowPDELMAkGA1UEBgwCSlAxEjAQ BgNVBAoMCUpJTi5HUi5KUDEMMAoGA1UECwwDUlJSMQswCQYDVQQDDAJDQTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANbv0x42BTKFEQOE+KJ2XmiSdZpR wjzQLAkPLRnLB98tlzs4xo+y4RyY/rd5TT9UzBJTIhP8CJi5GbS1oXEerQXB3P0d L5oSSMwGGyuIzgZe5+vZ1kgzQxMEKMMKlzA73rbMd4Jx3u5+jdbP0EDrPYfXSvLY bS04n2aX7zrN3x5KdDrNBfwBio2/qeaaj4+9OxnwRvYP3WOvqdW0h329eMfHw0pi JI0drIVdsEqClUV4pebT/F+CPUPkEh/weySgo9wANockkYu5ujw2GbLFcO5LXxxm dEfcVr3r6t6zOA4bJwL0W/e6LBcrwiG/qPDFErhwtgTLYf6Er67SzLyA66UCAwEA AaOB3DCB2TAPBgNVHRMBAf8EBTADAQH/MDEGCWCGSAGG+EIBDQQkFiJSdWJ5L09w ZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBRJ7Xd380KzBV7f USKIQ+O/vKbhDzAOBgNVHQ8BAf8EBAMCAQYwZAYDVR0jBF0wW4AUSe13d/NCswVe 31EiiEPjv7ym4Q+hQKQ+MDwxCzAJBgNVBAYMAkpQMRIwEAYDVQQKDAlKSU4uR1Iu SlAxDDAKBgNVBAsMA1JSUjELMAkGA1UEAwwCQ0GCAQAwDQYJKoZIhvcNAQEFBQAD ggEBAIu/mfiez5XN5tn2jScgShPgHEFJBR0BTJBZF6xCk0jyqNx/g9HMj2ELCuK+ r/Y7KFW5c5M3AQ+xWW0ZSc4kvzyTcV7yTVIwj2jZ9ddYMN3nupZFgBK1GB4Y05GY MJJFRkSu6d/Ph5ypzBVw2YMT/nsOo5VwMUGLgS7YVjU+u/HNWz80J3oO17mNZllj PvORJcnjwlroDnS58KoJ7GDgejv3ESWADvX1OHLE4cRkiQGeLoEU4pxdCxXRqX0U PbwIkZN9mXVcrmPHq8MWi4eC/V7hnbZETMHuWhUoiNdOEfsAXr3iP4KjyyRdwc7a d/xgcK06UVQRL/HbEYGiQL056mc= -----END CERTIFICATE----- ================================================ FILE: test/soap/ssl/client.cert ================================================ -----BEGIN CERTIFICATE----- MIIDKDCCAhCgAwIBAgIBAjANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGDAJKUDES MBAGA1UECgwJSklOLkdSLkpQMQwwCgYDVQQLDANSUlIxCzAJBgNVBAMMAkNBMB4X DTA0MDEzMTAzMTQ1OFoXDTM1MDEyMzAzMTQ1OFowZTELMAkGA1UEBgwCSlAxEjAQ BgNVBAoMCUpJTi5HUi5KUDEMMAoGA1UECwwDUlJSMRAwDgYDVQQDDAdleGFtcGxl MSIwIAYJKoZIhvcNAQkBDBNleGFtcGxlQGV4YW1wbGUub3JnMIGfMA0GCSqGSIb3 DQEBAQUAA4GNADCBiQKBgQDRWssrK8Gyr+500hpLjCGR3+AHL8/hEJM5zKi/MgLW jTkvsgOwbYwXOiNtAbR9y4/ucDq7EY+cMUMHES4uFaPTcOaAV0aZRmk8AgslN1tQ gNS6ew7/Luq3DcVeWkX8PYgR9VG0mD1MPfJ6+IFA5d3vKpdBkBgN4l46jjO0/2Xf ewIDAQABo4GPMIGMMAwGA1UdEwEB/wQCMAAwMQYJYIZIAYb4QgENBCQWIlJ1Ynkv T3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFOFvay0H7lr2 xUx6waYEV2bVDYQhMAsGA1UdDwQEAwIF4DAdBgNVHSUEFjAUBggrBgEFBQcDAgYI KwYBBQUHAwQwDQYJKoZIhvcNAQEFBQADggEBABd2dYWqbDIWf5sWFvslezxJv8gI w64KCJBuyJAiDuf+oazr3016kMzAlt97KecLZDusGNagPrq02UX7YMoQFsWJBans cDtHrkM0al5r6/WGexNMgtYbNTYzt/IwodISGBgZ6dsOuhznwms+IBsTNDAvWeLP lt2tOqD8kEmjwMgn0GDRuKjs4EoboA3kMULb1p9akDV9ZESU3eOtpS5/G5J5msLI 9WXbYBjcjvkLuJH9VsJhb+R58Vl0ViemvAHhPilSl1SPWVunGhv6FcIkdBEi1k9F e8BNMmsEjFiANiIRvpdLRbiGBt0KrKTndVfsmoKCvY48oCOvnzxtahFxfs8= -----END CERTIFICATE----- ================================================ FILE: test/soap/ssl/client.key ================================================ -----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQDRWssrK8Gyr+500hpLjCGR3+AHL8/hEJM5zKi/MgLWjTkvsgOw bYwXOiNtAbR9y4/ucDq7EY+cMUMHES4uFaPTcOaAV0aZRmk8AgslN1tQgNS6ew7/ Luq3DcVeWkX8PYgR9VG0mD1MPfJ6+IFA5d3vKpdBkBgN4l46jjO0/2XfewIDAQAB AoGAZcz8llWErtsV3QB9gNb3S/PNADGjqBFjReva8n3jG2k4sZSibpwWTwUaTNtT ZQgjSRKRvH1hk9XwffNAvXAQZNNkuj/16gO2oO45nyLj4dO365ujLptWnVIWDHOE uN0GeiZO+VzcCisT0WCq4tvtLeH8svrxzA8cbXIEyOK7NiECQQDwo2zPFyKAZ/Cu lDJ6zKT+RjfWwW7DgWzirAlTrt4ViMaW+IaDH29TmQpb4V4NuR3Xi+2Xl4oicu6S 36TW9+/FAkEA3rgfOQJuLlWSnw1RTGwvnC816a/W7iYYY7B+0U4cDbfWl7IoXT4y M8nV/HESooviZLqBwzAYSoj3fFKYBKpGPwJAUO8GN5iWWA2dW3ooiDiv/X1sZmRk dojfMFWgRW747tEzya8Ivq0h6kH8w+5GjeMG8Gn1nRiwsulo6Ckj7dEx6QJACyui 7UIQ8qP6GZ4aYMHgVW4Mvy7Bkeo5OO7GPYs0Xv/EdJFL8vlGnVBXOjUVoS9w6Gpu TbLg1QQvnX2rADjmEwJANxZO2GUkaWGsEif8aGW0x5g/IdaMGG27pTWk5zqix7P3 1UDrdo/JOXhptovhRi06EppIxAxYmbh9vd9VN8Itlw== -----END RSA PRIVATE KEY----- ================================================ FILE: test/soap/ssl/server.cert ================================================ -----BEGIN CERTIFICATE----- MIIC/zCCAeegAwIBAgIBATANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQGDAJKUDES MBAGA1UECgwJSklOLkdSLkpQMQwwCgYDVQQLDANSUlIxDjAMBgNVBAMMBVN1YkNB MB4XDTA0MDEzMTAzMTMxNloXDTMzMDEyMzAzMTMxNlowQzELMAkGA1UEBgwCSlAx EjAQBgNVBAoMCUpJTi5HUi5KUDEMMAoGA1UECwwDUlJSMRIwEAYDVQQDDAlsb2Nh bGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANFJTxWqup3nV9dsJAku p+WaXnPNIzcpAA3qMGZDJTJsfa8Du7ZxTP0XJK5mETttBrn711cJxAuP3KjqnW9S vtZ9lY2sXJ6Zj62sN5LwG3VVe25dI28yR1EsbHjJ5Zjf9tmggMC6am52dxuHbt5/ vHo4ngJuKE/U+eeGRivMn6gFAgMBAAGjgYUwgYIwDAYDVR0TAQH/BAIwADAxBglg hkgBhvhCAQ0EJBYiUnVieS9PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAd BgNVHQ4EFgQUpZIyygD9JxFYHHOTEuWOLbCKfckwCwYDVR0PBAQDAgWgMBMGA1Ud JQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBBQUAA4IBAQBwAIj5SaBHaA5X31IP CFCJiep96awfp7RANO0cuUj+ZpGoFn9d6FXY0g+Eg5wAkCNIzZU5NHN9xsdOpnUo zIBbyTfQEPrge1CMWMvL6uGaoEXytq84VTitF/xBTky4KtTn6+es4/e7jrrzeUXQ RC46gkHObmDT91RkOEGjHLyld2328jo3DIN/VTHIryDeVHDWjY5dENwpwdkhhm60 DR9IrNBbXWEe9emtguNXeN0iu1ux0lG1Hc6pWGQxMlRKNvGh0yZB9u5EVe38tOV0 jQaoNyL7qzcQoXD3Dmbi1p0iRmg/+HngISsz8K7k7MBNVsSclztwgCzTZOBiVtkM rRlQ -----END CERTIFICATE----- ================================================ FILE: test/soap/ssl/server.key ================================================ -----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQDRSU8Vqrqd51fXbCQJLqflml5zzSM3KQAN6jBmQyUybH2vA7u2 cUz9FySuZhE7bQa5+9dXCcQLj9yo6p1vUr7WfZWNrFyemY+trDeS8Bt1VXtuXSNv MkdRLGx4yeWY3/bZoIDAumpudncbh27ef7x6OJ4CbihP1PnnhkYrzJ+oBQIDAQAB AoGBAIf4CstW2ltQO7+XYGoex7Hh8s9lTSW/G2vu5Hbr1LTHy3fzAvdq8MvVR12O rk9fa+lU9vhzPc0NMB0GIDZ9GcHuhW5hD1Wg9OSCbTOkZDoH3CAFqonjh4Qfwv5W IPAFn9KHukdqGXkwEMdErsUaPTy9A1V/aROVEaAY+HJgq/eZAkEA/BP1QMV04WEZ Oynzz7/lLizJGGxp2AOvEVtqMoycA/Qk+zdKP8ufE0wbmCE3Qd6GoynavsHb6aGK gQobb8zDZwJBANSK6MrXlrZTtEaeZuyOB4mAmRzGzOUVkUyULUjEx2GDT93ujAma qm/2d3E+wXAkNSeRpjUmlQXy/2oSqnGvYbMCQQDRM+cYyEcGPUVpWpnj0shrF/QU 9vSot/X1G775EMTyaw6+BtbyNxVgOIu2J+rqGbn3c+b85XqTXOPL0A2RLYkFAkAm syhSDtE9X55aoWsCNZY/vi+i4rvaFoQ/WleogVQAeGVpdo7/DK9t9YWoFBIqth0L mGSYFu9ZhvZkvQNV8eYrAkBJ+rOIaLDsmbrgkeDruH+B/9yrm4McDtQ/rgnOGYnH LjLpLLOrgUxqpzLWe++EwSLwK2//dHO+SPsQJ4xsyQJy -----END RSA PRIVATE KEY----- ================================================ FILE: test/soap/ssl/sslsvr.rb ================================================ require 'webrick/https' require 'logger' require 'rbconfig' require 'soap/rpc/httpserver' class HelloWorldServer < SOAP::RPC::HTTPServer private def on_init self.level = Logger::Severity::FATAL @default_namespace = 'urn:ssltst' add_method(self, 'hello_world', 'from') end def hello_world(from) "Hello World, from #{ from }" end end if $0 == __FILE__ PORT = 17171 DIR = File.dirname(File.expand_path(__FILE__)) def cert(filename) OpenSSL::X509::Certificate.new(File.open(File.join(DIR, filename)) { |f| f.read }) end def key(filename) OpenSSL::PKey::RSA.new(File.open(File.join(DIR, filename)) { |f| f.read }) end $server = HelloWorldServer.new( :BindAddress => "0.0.0.0", :Port => PORT, :AccessLog => [], :SSLEnable => true, :SSLCACertificateFile => File.join(DIR, 'ca.cert'), :SSLCertificate => cert('server.cert'), :SSLPrivateKey => key('server.key'), :SSLVerifyClient => nil, #OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT|OpenSSL::SSL::VERIFY_PEER, :SSLClientCA => cert('ca.cert'), :SSLCertName => nil ) t = Thread.new { Thread.current.abort_on_exception = true $server.start } STDOUT.sync = true puts $$ t.join end ================================================ FILE: test/soap/ssl/subca.cert ================================================ -----BEGIN CERTIFICATE----- MIIDaDCCAlCgAwIBAgIBATANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGDAJKUDES MBAGA1UECgwJSklOLkdSLkpQMQwwCgYDVQQLDANSUlIxCzAJBgNVBAMMAkNBMB4X DTA0MDEzMDAwNDMyN1oXDTM1MDEyMjAwNDMyN1owPzELMAkGA1UEBgwCSlAxEjAQ BgNVBAoMCUpJTi5HUi5KUDEMMAoGA1UECwwDUlJSMQ4wDAYDVQQDDAVTdWJDQTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ0Ou7AyRcRXnB/kVHv/6kwe ANzgg/DyJfsAUqW90m7Lu1nqyug8gK0RBd77yU0w5HOAMHTVSdpjZK0g2sgx4Mb1 d/213eL9TTl5MRVEChTvQr8q5DVG/8fxPPE7fMI8eOAzd98/NOAChk+80r4Sx7fC kGVEE1bKwY1MrUsUNjOY2d6t3M4HHV3HX1V8ShuKfsHxgCmLzdI8U+5CnQedFgkm 3e+8tr8IX5RR1wA1Ifw9VadF7OdI/bGMzog/Q8XCLf+WPFjnK7Gcx6JFtzF6Gi4x 4dp1Xl45JYiVvi9zQ132wu8A1pDHhiNgQviyzbP+UjcB/tsOpzBQF8abYzgEkWEC AwEAAaNyMHAwDwYDVR0TAQH/BAUwAwEB/zAxBglghkgBhvhCAQ0EJBYiUnVieS9P cGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUlCjXWLsReYzH LzsxwVnCXmKoB/owCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQCJ/OyN rT8Cq2Y+G2yA/L1EMRvvxwFBqxavqaqHl/6rwsIBFlB3zbqGA/0oec6MAVnYynq4 c4AcHTjx3bQ/S4r2sNTZq0DH4SYbQzIobx/YW8PjQUJt8KQdKMcwwi7arHP7A/Ha LKu8eIC2nsUBnP4NhkYSGhbmpJK+PFD0FVtD0ZIRlY/wsnaZNjWWcnWF1/FNuQ4H ySjIblqVQkPuzebv3Ror6ZnVDukn96Mg7kP4u6zgxOeqlJGRe1M949SS9Vudjl8X SF4aZUUB9pQGhsqQJVqaz2OlhGOp9D0q54xko/rekjAIcuDjl1mdX4F2WRrzpUmZ uY/bPeOBYiVsOYVe -----END CERTIFICATE----- ================================================ FILE: test/soap/ssl/test_ssl.rb ================================================ require 'test/unit' begin require 'http-access2' rescue LoadError end require 'soap/rpc/driver' if defined?(HTTPAccess2) and defined?(OpenSSL) module SOAP; module SSL class TestSSL < Test::Unit::TestCase PORT = 17171 DIR = File.dirname(File.expand_path(__FILE__)) require 'rbconfig' RUBY = File.join( Config::CONFIG["bindir"], Config::CONFIG["ruby_install_name"] + Config::CONFIG["EXEEXT"] ) def setup @url = "https://localhost:#{PORT}/hello" @serverpid = @client = nil @verify_callback_called = false setup_server setup_client end def teardown teardown_client teardown_server end def test_options cfg = @client.streamhandler.client.ssl_config assert_nil(cfg.client_cert) assert_nil(cfg.client_key) assert_nil(cfg.client_ca) assert_equal(OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT, cfg.verify_mode) assert_nil(cfg.verify_callback) assert_nil(cfg.timeout) assert_equal(OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv2, cfg.options) assert_equal("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH", cfg.ciphers) assert_instance_of(OpenSSL::X509::Store, cfg.cert_store) # dummy call to ensure sslsvr initialization finished. assert_raise(OpenSSL::SSL::SSLError) do @client.hello_world("ssl client") end end def test_verification cfg = @client.options cfg["protocol.http.ssl_config.verify_callback"] = method(:verify_callback).to_proc @verify_callback_called = false ssle = assert_raise(OpenSSL::SSL::SSLError) {@client.hello_world("ssl client")} assert_equal("certificate verify failed", ssle.message) assert(@verify_callback_called) # cfg["protocol.http.ssl_config.client_cert"] = File.join(DIR, "client.cert") cfg["protocol.http.ssl_config.client_key"] = File.join(DIR, "client.key") @verify_callback_called = false ssle = assert_raise(OpenSSL::SSL::SSLError) {@client.hello_world("ssl client")} assert_equal("certificate verify failed", ssle.message) assert(@verify_callback_called) # cfg["protocol.http.ssl_config.ca_file"] = File.join(DIR, "ca.cert") @verify_callback_called = false ssle = assert_raise(OpenSSL::SSL::SSLError) {@client.hello_world("ssl client")} assert_equal("certificate verify failed", ssle.message) assert(@verify_callback_called) # cfg["protocol.http.ssl_config.ca_file"] = File.join(DIR, "subca.cert") @verify_callback_called = false assert_equal("Hello World, from ssl client", @client.hello_world("ssl client")) assert(@verify_callback_called) # cfg["protocol.http.ssl_config.verify_depth"] = "1" @verify_callback_called = false ssle = assert_raise(OpenSSL::SSL::SSLError) {@client.hello_world("ssl client")} assert_equal("certificate verify failed", ssle.message) assert(@verify_callback_called) # cfg["protocol.http.ssl_config.verify_depth"] = "" cfg["protocol.http.ssl_config.cert_store"] = OpenSSL::X509::Store.new cfg["protocol.http.ssl_config.verify_mode"] = OpenSSL::SSL::VERIFY_PEER.to_s ssle = assert_raise(OpenSSL::SSL::SSLError) {@client.hello_world("ssl client")} assert_equal("certificate verify failed", ssle.message) # cfg["protocol.http.ssl_config.verify_mode"] = "" assert_equal("Hello World, from ssl client", @client.hello_world("ssl client")) end def test_property testpropertyname = File.join(DIR, 'soapclient.properties') File.open(testpropertyname, "w") do |f| f <<<<__EOP__ protocol.http.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_PEER # depth: 1 causes an error (intentional) protocol.http.ssl_config.verify_depth = 1 protocol.http.ssl_config.client_cert = #{File.join(DIR, 'client.cert')} protocol.http.ssl_config.client_key = #{File.join(DIR, 'client.key')} protocol.http.ssl_config.ca_file = #{File.join(DIR, 'ca.cert')} protocol.http.ssl_config.ca_file = #{File.join(DIR, 'subca.cert')} protocol.http.ssl_config.ciphers = ALL __EOP__ end begin @client.loadproperty(testpropertyname) @client.options["protocol.http.ssl_config.verify_callback"] = method(:verify_callback).to_proc @verify_callback_called = false # NG with String ssle = assert_raise(OpenSSL::SSL::SSLError) {@client.hello_world("ssl client")} assert_equal("certificate verify failed", ssle.message) assert(@verify_callback_called) # NG with Integer @client.options["protocol.http.ssl_config.verify_depth"] = 0 ssle = assert_raise(OpenSSL::SSL::SSLError) {@client.hello_world("ssl client")} assert_equal("certificate verify failed", ssle.message) assert(@verify_callback_called) # OK with empty @client.options["protocol.http.ssl_config.verify_depth"] = "" @verify_callback_called = false assert_equal("Hello World, from ssl client", @client.hello_world("ssl client")) assert(@verify_callback_called) # OK with nil @client.options["protocol.http.ssl_config.verify_depth"] = nil @verify_callback_called = false assert_equal("Hello World, from ssl client", @client.hello_world("ssl client")) assert(@verify_callback_called) # OK with String @client.options["protocol.http.ssl_config.verify_depth"] = "3" @verify_callback_called = false assert_equal("Hello World, from ssl client", @client.hello_world("ssl client")) assert(@verify_callback_called) # OK with Integer @client.options["protocol.http.ssl_config.verify_depth"] = 3 @verify_callback_called = false assert_equal("Hello World, from ssl client", @client.hello_world("ssl client")) assert(@verify_callback_called) ensure File.unlink(testpropertyname) end end def test_ciphers cfg = @client.options cfg["protocol.http.ssl_config.client_cert"] = File.join(DIR, 'client.cert') cfg["protocol.http.ssl_config.client_key"] = File.join(DIR, 'client.key') cfg["protocol.http.ssl_config.ca_file"] = File.join(DIR, "ca.cert") cfg["protocol.http.ssl_config.ca_file"] = File.join(DIR, "subca.cert") #cfg.timeout = 123 cfg["protocol.http.ssl_config.ciphers"] = "!ALL" # ssle = assert_raise(OpenSSL::SSL::SSLError) {@client.hello_world("ssl client")} # depends on OpenSSL version. (?:0.9.8|0.9.7) assert_match(/\A(?:SSL_CTX_set_cipher_list:: no cipher match|no ciphers available)\z/, ssle.message) # cfg["protocol.http.ssl_config.ciphers"] = "ALL" assert_equal("Hello World, from ssl client", @client.hello_world("ssl client")) end private def q(str) %Q["#{str}"] end def setup_server svrcmd = "#{q(RUBY)} " #svrcmd << "-d " if $DEBUG svrcmd << File.join(DIR, "sslsvr.rb") svrout = IO.popen(svrcmd) @serverpid = Integer(svrout.gets.chomp) end def setup_client @client = SOAP::RPC::Driver.new(@url, 'urn:ssltst') @client.add_method("hello_world", "from") end def teardown_server if @serverpid Process.kill('KILL', @serverpid) Process.waitpid(@serverpid) end end def teardown_client @client.reset_stream if @client end def verify_callback(ok, cert) @verify_callback_called = true p ["client", ok, cert] if $DEBUG ok end end end; end end ================================================ FILE: test/soap/struct/test_struct.rb ================================================ require 'test/unit' require 'soap/rpc/httpserver' require 'soap/rpc/driver' module SOAP; module Struct class TestStruct < Test::Unit::TestCase Namespace = "urn:example.com:simpletype-rpc" class Server < ::SOAP::RPC::HTTPServer @@test_struct = ::Struct.new(:one, :two) def on_init add_method(self, 'a_method') end def a_method @@test_struct.new("string", 1) end end Port = 17171 def setup setup_server setup_client end def setup_server @server = Server.new( :Port => Port, :BindAddress => "0.0.0.0", :AccessLog => [], :SOAPDefaultNamespace => Namespace ) @server.level = Logger::Severity::ERROR @server_thread = start_server_thread(@server) end def setup_client @client = ::SOAP::RPC::Driver.new("http://localhost:#{Port}/", Namespace) @client.wiredump_dev = STDERR if $DEBUG @client.add_method('a_method') end def teardown teardown_server teardown_client end def teardown_server @server.shutdown @server_thread.kill @server_thread.join end def teardown_client @client.reset_stream end def start_server_thread(server) t = Thread.new { Thread.current.abort_on_exception = true server.start } t end def test_struct assert_equal("string", @client.a_method.one) assert_equal(1, @client.a_method.two) end end end; end ================================================ FILE: test/soap/swa/test_file.rb ================================================ require 'test/unit' require 'soap/rpc/driver' require 'soap/rpc/standaloneServer' require 'soap/attachment' module SOAP module SWA class TestFile < Test::Unit::TestCase Port = 17171 THIS_FILE = File.expand_path(__FILE__) class SwAService def get_file return { 'name' => $0, 'file' => SOAP::Attachment.new(File.open(THIS_FILE)) # closed when GCed. } end def put_file(name, file) "File '#{name}' was received ok." end end def setup @server = SOAP::RPC::StandaloneServer.new('SwAServer', 'http://www.acmetron.com/soap', '0.0.0.0', Port) @server.add_servant(SwAService.new) @server.level = Logger::Severity::ERROR @t = Thread.new { @server.start } @endpoint = "http://localhost:#{Port}/" @client = SOAP::RPC::Driver.new(@endpoint, 'http://www.acmetron.com/soap') @client.add_method('get_file') @client.add_method('put_file', 'name', 'file') @client.wiredump_dev = STDERR if $DEBUG end def teardown @server.shutdown @t.kill @t.join @client.reset_stream end def test_get_file assert_equal( File.open(THIS_FILE) { |f| f.read }, @client.get_file['file'].content ) end def test_put_file assert_equal( "File 'foo' was received ok.", @client.put_file('foo', SOAP::Attachment.new(File.open(THIS_FILE))) ) assert_equal( "File 'bar' was received ok.", @client.put_file('bar', SOAP::Attachment.new(File.open(THIS_FILE) { |f| f.read })) ) end end end end ================================================ FILE: test/soap/test_basetype.rb ================================================ require 'test/unit' require 'soap/baseData' module SOAP class TestSOAP < Test::Unit::TestCase NegativeZero = (-1.0 / (1.0 / 0.0)) def setup # Nothing to do. end def teardown # Nothing to do. end def assert_parsed_result(klass, str) o = klass.new(str) assert_equal(str, o.to_s) end def test_SOAPNil o = SOAP::SOAPNil.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::NilLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) o = SOAP::SOAPNil.new(nil) assert_equal(true, o.is_nil) assert_equal(nil, o.data) assert_equal("", o.to_s) o = SOAP::SOAPNil.new('var') assert_equal(false, o.is_nil) assert_equal('var', o.data) assert_equal('var', o.to_s) end def test_SOAPString o = SOAP::SOAPString.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::StringLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) str = "abc" assert_equal(str, SOAP::SOAPString.new(str).data) assert_equal(str, SOAP::SOAPString.new(str).to_s) assert_raises(XSD::ValueSpaceError) do SOAP::SOAPString.new("\0") end assert_raises(XSD::ValueSpaceError) do p SOAP::SOAPString.new("\xC0\xC0").to_s end end def test_SOAPBoolean o = SOAP::SOAPBoolean.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::BooleanLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ ["true", true], ["1", true], ["false", false], ["0", false], ] targets.each do |data, expected| assert_equal(expected, SOAP::SOAPBoolean.new(data).data) assert_equal(expected.to_s, SOAP::SOAPBoolean.new(data).to_s) end assert_raises(XSD::ValueSpaceError) do SOAP::SOAPBoolean.new("nil").to_s end end def test_SOAPDecimal o = SOAP::SOAPDecimal.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::DecimalLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 0, 1000000000, -9999999999, 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890, 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890, -1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789, ] targets.each do |dec| assert_equal(dec.to_s, SOAP::SOAPDecimal.new(dec).data) end targets = [ "0", "0.00000001", "1000000000", "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "-12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123.45678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789", ] targets.each do |str| assert_equal(str, SOAP::SOAPDecimal.new(str).to_s) end targets = [ ["-0", "0"], ["+0", "0"], ["0.0", "0"], ["-0.0", "0"], ["+0.0", "0"], ["0.", "0"], [".0", "0"], [ "+0.12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "0.1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" ], [ ".0000012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "0.000001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" ], [ "-12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890.", "-12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" ], ] targets.each do |data, expected| assert_equal(expected, SOAP::SOAPDecimal.new(data).to_s) end targets = [ "0.000000000000a", "00a.0000000000001", "+-5", ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do SOAP::SOAPDecimal.new(d) end end end def test_SOAPFloat o = SOAP::SOAPFloat.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::FloatLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 3.14159265358979, 12.34e36, 1.402e-45, -1.402e-45, ] targets.each do |f| assert_equal(f, SOAP::SOAPFloat.new(f).data) end targets = [ "+3.141592654", "+1.234e+37", "+1.402e-45", "-1.402e-45", ] targets.each do |f| assert_equal(f, SOAP::SOAPFloat.new(f).to_s) end targets = [ [3, "+3"], # should be 3.0? [-2, "-2"], # ditto [3.14159265358979, "+3.141592654"], [12.34e36, "+1.234e+37"], [1.402e-45, "+1.402e-45"], [-1.402e-45, "-1.402e-45"], ["1.402e", "+1.402"], ["12.34E36", "+1.234e+37"], ["1.402E-45", "+1.402e-45"], ["-1.402E-45", "-1.402e-45"], ["1.402E", "+1.402"], ] targets.each do |f, str| assert_equal(str, SOAP::SOAPFloat.new(f).to_s) end assert_equal("+0", SOAP::SOAPFloat.new(+0.0).to_s) assert_equal("-0", SOAP::SOAPFloat.new(NegativeZero).to_s) assert(SOAP::SOAPFloat.new(0.0/0.0).data.nan?) assert_equal("INF", SOAP::SOAPFloat.new(1.0/0.0).to_s) assert_equal(1, SOAP::SOAPFloat.new(1.0/0.0).data.infinite?) assert_equal("-INF", SOAP::SOAPFloat.new(-1.0/0.0).to_s) assert_equal(-1, SOAP::SOAPFloat.new(-1.0/0.0).data.infinite?) targets = [ "0.000000000000a", "00a.0000000000001", "+-5", "5_0", ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do SOAP::SOAPFloat.new(d) end end end def test_SOAPDouble o = SOAP::SOAPDouble.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::DoubleLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 3.14159265358979, 12.34e36, 1.402e-45, -1.402e-45, ] targets.each do |f| assert_equal(f, SOAP::SOAPDouble.new(f).data) end targets = [ "+3.14159265358979", "+1.234e+37", "+1.402e-45", "-1.402e-45", ] targets.each do |f| assert_equal(f, SOAP::SOAPDouble.new(f).to_s) end targets = [ [3, "+3"], # should be 3.0? [-2, "-2"], # ditto. [3.14159265358979, "+3.14159265358979"], [12.34e36, "+1.234e+37"], [1.402e-45, "+1.402e-45"], [-1.402e-45, "-1.402e-45"], ["1.402e", "+1.402"], ["12.34E36", "+1.234e+37"], ["1.402E-45", "+1.402e-45"], ["-1.402E-45", "-1.402e-45"], ["1.402E", "+1.402"], ] targets.each do |f, str| assert_equal(str, SOAP::SOAPDouble.new(f).to_s) end assert_equal("+0", SOAP::SOAPFloat.new(+0.0).to_s) assert_equal("-0", SOAP::SOAPFloat.new(NegativeZero).to_s) assert_equal("NaN", SOAP::SOAPDouble.new(0.0/0.0).to_s) assert(SOAP::SOAPDouble.new(0.0/0.0).data.nan?) assert_equal("INF", SOAP::SOAPDouble.new(1.0/0.0).to_s) assert_equal(1, SOAP::SOAPDouble.new(1.0/0.0).data.infinite?) assert_equal("-INF", SOAP::SOAPDouble.new(-1.0/0.0).to_s) assert_equal(-1, SOAP::SOAPDouble.new(-1.0/0.0).data.infinite?) targets = [ "0.000000000000a", "00a.0000000000001", "+-5", ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do SOAP::SOAPDouble.new(d) end end end def test_SOAPDuration o = SOAP::SOAPDuration.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::DurationLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "P1Y2M3DT4H5M6S", "P1234Y5678M9012DT3456H7890M1234.5678S", "P0DT3456H7890M1234.5678S", "P1234Y5678M9012D", "-P1234Y5678M9012DT3456H7890M1234.5678S", "P5678M9012DT3456H7890M1234.5678S", "-P1234Y9012DT3456H7890M1234.5678S", "+P1234Y5678MT3456H7890M1234.5678S", "P1234Y5678M9012DT7890M1234.5678S", "-P1234Y5678M9012DT3456H1234.5678S", "+P1234Y5678M9012DT3456H7890M", "P123400000000000Y", "-P567800000000000M", "+P901200000000000D", "P0DT345600000000000H", "-P0DT789000000000000M", "+P0DT123400000000000.000000000005678S", "P1234YT1234.5678S", "-P5678MT7890M", "+P9012DT3456H", ] targets.each do |str| assert_parsed_result(SOAP::SOAPDuration, str) end targets = [ ["P0Y0M0DT0H0M0S", "P0D"], ["-P0DT0S", "-P0D"], ["P01234Y5678M9012DT3456H7890M1234.5678S", "P1234Y5678M9012DT3456H7890M1234.5678S"], ["P1234Y005678M9012DT3456H7890M1234.5678S", "P1234Y5678M9012DT3456H7890M1234.5678S"], ["P1234Y5678M0009012DT3456H7890M1234.5678S", "P1234Y5678M9012DT3456H7890M1234.5678S"], ["P1234Y5678M9012DT00003456H7890M1234.5678S", "P1234Y5678M9012DT3456H7890M1234.5678S"], ["P1234Y5678M9012DT3456H000007890M1234.5678S", "P1234Y5678M9012DT3456H7890M1234.5678S"], ["P1234Y5678M9012DT3456H7890M0000001234.5678S", "P1234Y5678M9012DT3456H7890M1234.5678S"], ] targets.each do |data, expected| assert_equal(expected, SOAP::SOAPDuration.new(data).to_s) end end def test_SOAPDateTime o = SOAP::SOAPDateTime.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::DateTimeLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "2002-05-18T16:52:20Z", "0001-01-01T00:00:00Z", "9999-12-31T23:59:59Z", "19999-12-31T23:59:59Z", "2002-12-31T23:59:59.999Z", "2002-12-31T23:59:59.001Z", "2002-12-31T23:59:59.99999999999999999999Z", "2002-12-31T23:59:59.00000000000000000001Z", "2002-12-31T23:59:59+09:00", "2002-12-31T23:59:59+00:01", "2002-12-31T23:59:59-00:01", "2002-12-31T23:59:59-23:59", "2002-12-31T23:59:59.00000000000000000001+13:30", "2002-12-31T23:59:59.51375Z", "2002-12-31T23:59:59.51345+12:34", "-2002-05-18T16:52:20Z", "-4711-12-31T23:59:59Z", "-4713-01-01T12:00:00Z", "-19999-12-31T23:59:59Z", "-2002-12-31T23:59:59+00:01", "-0001-12-31T23:59:59.00000000000000000001+13:30", ] targets.each do |str| assert_parsed_result(SOAP::SOAPDateTime, str) end targets = [ ["2002-12-31T23:59:59.00", "2002-12-31T23:59:59Z"], ["2002-12-31T23:59:59+00:00", "2002-12-31T23:59:59Z"], ["2002-12-31T23:59:59-00:00", "2002-12-31T23:59:59Z"], ["-2002-12-31T23:59:59.00", "-2002-12-31T23:59:59Z"], ["-2002-12-31T23:59:59+00:00", "-2002-12-31T23:59:59Z"], ["-2002-12-31T23:59:59-00:00", "-2002-12-31T23:59:59Z"], ] targets.each do |data, expected| assert_equal(expected, SOAP::SOAPDateTime.new(data).to_s) d = DateTime.parse(data) d >>= 12 if d.year < 0 # XSDDateTime.year(-1) == DateTime.year(0) assert_equal(expected, SOAP::SOAPDateTime.new(d).to_s) end targets = [ "1-05-18T16:52:20Z", "05-18T16:52:20Z", "2002-05T16:52:20Z", "2002-05-18T16:52Z", "", ] targets.each do |d| assert_raises(XSD::ValueSpaceError, d.to_s) do SOAP::SOAPDateTime.new(d) end end end def test_SOAPTime o = SOAP::SOAPTime.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::TimeLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "16:52:20Z", "00:00:00Z", "23:59:59Z", "23:59:59.999Z", "23:59:59.001Z", "23:59:59.99999999999999999999Z", "23:59:59.00000000000000000001Z", "23:59:59+09:00", "23:59:59+00:01", "23:59:59-00:01", "23:59:59-23:59", "23:59:59.00000000000000000001+13:30", "23:59:59.51375Z", "23:59:59.51375+12:34", "23:59:59+00:01", ] targets.each do |str| assert_parsed_result(SOAP::SOAPTime, str) end targets = [ ["23:59:59.00", "23:59:59Z"], ["23:59:59+00:00", "23:59:59Z"], ["23:59:59-00:00", "23:59:59Z"], ] targets.each do |data, expected| assert_equal(expected, SOAP::SOAPTime.new(data).to_s) end end def test_SOAPDate o = SOAP::SOAPDate.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::DateLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "2002-05-18Z", "0001-01-01Z", "9999-12-31Z", "19999-12-31Z", "2002-12-31+09:00", "2002-12-31+00:01", "2002-12-31-00:01", "2002-12-31-23:59", "2002-12-31+13:30", "-2002-05-18Z", "-19999-12-31Z", "-2002-12-31+00:01", "-0001-12-31+13:30", ] targets.each do |str| assert_parsed_result(SOAP::SOAPDate, str) end targets = [ ["2002-12-31", "2002-12-31Z"], ["2002-12-31+00:00", "2002-12-31Z"], ["2002-12-31-00:00", "2002-12-31Z"], ["-2002-12-31", "-2002-12-31Z"], ["-2002-12-31+00:00", "-2002-12-31Z"], ["-2002-12-31-00:00", "-2002-12-31Z"], ] targets.each do |data, expected| assert_equal(expected, SOAP::SOAPDate.new(data).to_s) d = Date.parse(data) d >>= 12 if d.year < 0 # XSDDate.year(-1) == Date.year(0) assert_equal(expected, SOAP::SOAPDate.new(d).to_s) end end def test_SOAPGYearMonth o = SOAP::SOAPGYearMonth.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::GYearMonthLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "2002-05Z", "0001-01Z", "9999-12Z", "19999-12Z", "2002-12+09:00", "2002-12+00:01", "2002-12-00:01", "2002-12-23:59", "2002-12+13:30", "-2002-05Z", "-19999-12Z", "-2002-12+00:01", "-0001-12+13:30", ] targets.each do |str| assert_parsed_result(SOAP::SOAPGYearMonth, str) end targets = [ ["2002-12", "2002-12Z"], ["2002-12+00:00", "2002-12Z"], ["2002-12-00:00", "2002-12Z"], ["-2002-12", "-2002-12Z"], ["-2002-12+00:00", "-2002-12Z"], ["-2002-12-00:00", "-2002-12Z"], ] targets.each do |data, expected| assert_equal(expected, SOAP::SOAPGYearMonth.new(data).to_s) end end def test_SOAPGYear o = SOAP::SOAPGYear.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::GYearLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "2002Z", "0001Z", "9999Z", "19999Z", "2002+09:00", "2002+00:01", "2002-00:01", "2002-23:59", "2002+13:30", "-2002Z", "-19999Z", "-2002+00:01", "-0001+13:30", ] targets.each do |str| assert_parsed_result(SOAP::SOAPGYear, str) end targets = [ ["2002", "2002Z"], ["2002+00:00", "2002Z"], ["2002-00:00", "2002Z"], ["-2002", "-2002Z"], ["-2002+00:00", "-2002Z"], ["-2002-00:00", "-2002Z"], ] targets.each do |data, expected| assert_equal(expected, SOAP::SOAPGYear.new(data).to_s) end end def test_SOAPGMonthDay o = SOAP::SOAPGMonthDay.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::GMonthDayLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "05-18Z", "01-01Z", "12-31Z", "12-31+09:00", "12-31+00:01", "12-31-00:01", "12-31-23:59", "12-31+13:30", ] targets.each do |str| assert_parsed_result(SOAP::SOAPGMonthDay, str) end targets = [ ["12-31", "12-31Z"], ["12-31+00:00", "12-31Z"], ["12-31-00:00", "12-31Z"], ] targets.each do |data, expected| assert_equal(expected, SOAP::SOAPGMonthDay.new(data).to_s) end end def test_SOAPGDay o = SOAP::SOAPGDay.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::GDayLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "18Z", "01Z", "31Z", "31+09:00", "31+00:01", "31-00:01", "31-23:59", "31+13:30", ] targets.each do |str| assert_parsed_result(SOAP::SOAPGDay, str) end targets = [ ["31", "31Z"], ["31+00:00", "31Z"], ["31-00:00", "31Z"], ] targets.each do |data, expected| assert_equal(expected, SOAP::SOAPGDay.new(data).to_s) end end def test_SOAPGMonth o = SOAP::SOAPGMonth.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::GMonthLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "05Z", "01Z", "12Z", "12+09:00", "12+00:01", "12-00:01", "12-23:59", "12+13:30", ] targets.each do |str| assert_parsed_result(SOAP::SOAPGMonth, str) end targets = [ ["12", "12Z"], ["12+00:00", "12Z"], ["12-00:00", "12Z"], ] targets.each do |data, expected| assert_equal(expected, SOAP::SOAPGMonth.new(data).to_s) end end def test_SOAPHexBinary o = SOAP::SOAPHexBinary.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::HexBinaryLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "abcdef", "\xe3\x81\xaa\xe3\x81\xb2", "\0", "", ] targets.each do |str| assert_equal(str, SOAP::SOAPHexBinary.new(str).string) assert_equal(str.unpack("H*")[0].tr('a-f', 'A-F'), SOAP::SOAPHexBinary.new(str).data) o = SOAP::SOAPHexBinary.new o.set_encoded(str.unpack("H*")[0].tr('a-f', 'A-F')) assert_equal(str, o.string) o.set_encoded(str.unpack("H*")[0].tr('A-F', 'a-f')) assert_equal(str, o.string) end targets = [ "0FG7", "0fg7", ] targets.each do |d| assert_raises(XSD::ValueSpaceError, d.to_s) do o = SOAP::SOAPHexBinary.new o.set_encoded(d) p o.string end end end def test_SOAPBase64Binary o = SOAP::SOAPBase64.new assert_equal(SOAP::EncodingNamespace, o.type.namespace) assert_equal(SOAP::Base64Literal, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "abcdef", "\xe3\x81\xaa\xe3\x81\xb2", "\0", "", ] targets.each do |str| assert_equal(str, SOAP::SOAPBase64.new(str).string) assert_equal([str].pack("m").chomp, SOAP::SOAPBase64.new(str).data) o = SOAP::SOAPBase64.new o.set_encoded([str].pack("m").chomp) assert_equal(str, o.string) end targets = [ "-", "*", ] targets.each do |d| assert_raises(XSD::ValueSpaceError, d.to_s) do o = SOAP::SOAPBase64.new o.set_encoded(d) p o.string end end end def test_SOAPAnyURI o = SOAP::SOAPAnyURI.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::AnyURILiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) # Too few tests here I know. Believe uri module. :) targets = [ "foo", "http://foo", "http://foo/bar/baz", "http://foo/bar#baz", "http://foo/bar%20%20?a+b", "HTTP://FOO/BAR%20%20?A+B", ] targets.each do |str| assert_parsed_result(SOAP::SOAPAnyURI, str) end end def test_SOAPQName o = SOAP::SOAPQName.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::QNameLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) # More strict test is needed but current implementation allows all non-':' # chars like ' ', C0 or C1... targets = [ "foo", "foo:bar", "a:b", ] targets.each do |str| assert_parsed_result(SOAP::SOAPQName, str) end end ### ## Derived types # def test_SOAPInteger o = SOAP::SOAPInteger.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::IntegerLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 0, 1000000000, -9999999999, 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890, 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890, -1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789, ] targets.each do |int| assert_equal(int, SOAP::SOAPInteger.new(int).data) end targets = [ "0", "1000000000", "-9999999999", "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "-1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789", ] targets.each do |str| assert_equal(str, SOAP::SOAPInteger.new(str).to_s) end targets = [ ["-0", "0"], ["+0", "0"], ["000123", "123"], ["-000123", "-123"], [ "+12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" ], ] targets.each do |data, expected| assert_equal(expected, SOAP::SOAPInteger.new(data).to_s) end targets = [ "0.0", "-5.2", "0.000000000000a", "+-5", "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890." ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do SOAP::SOAPInteger.new(d) end end end def test_SOAPLong o = SOAP::SOAPLong.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::LongLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 0, 123, -123, 9223372036854775807, -9223372036854775808, ] targets.each do |lng| assert_equal(lng, SOAP::SOAPLong.new(lng).data) end targets = [ "0", "123", "-123", "9223372036854775807", "-9223372036854775808", ] targets.each do |str| assert_equal(str, SOAP::SOAPLong.new(str).to_s) end targets = [ ["-0", "0"], ["+0", "0"], ["000123", "123"], ["-000123", "-123"], ] targets.each do |data, expected| assert_equal(expected, SOAP::SOAPLong.new(data).to_s) end targets = [ 9223372036854775808, -9223372036854775809, "0.0", "-5.2", "0.000000000000a", "+-5", ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do SOAP::SOAPLong.new(d) end end end def test_SOAPInt o = SOAP::SOAPInt.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::IntLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 0, 123, -123, 2147483647, -2147483648, ] targets.each do |lng| assert_equal(lng, SOAP::SOAPInt.new(lng).data) end targets = [ "0", "123", "-123", "2147483647", "-2147483648", ] targets.each do |str| assert_equal(str, SOAP::SOAPInt.new(str).to_s) end targets = [ ["-0", "0"], ["+0", "0"], ["000123", "123"], ["-000123", "-123"], ] targets.each do |data, expected| assert_equal(expected, SOAP::SOAPInt.new(data).to_s) end targets = [ 2147483648, -2147483649, "0.0", "-5.2", "0.000000000000a", "+-5", ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do SOAP::SOAPInt.new(d) end end end end end ================================================ FILE: test/soap/test_envelopenamespace.rb ================================================ require 'test/unit' require 'soap/rpc/driver' require 'webrick' require 'logger' module SOAP class TestEnvelopeNamespace < Test::Unit::TestCase Port = 17171 TemporaryNamespace = 'urn:foo' def setup @logger = Logger.new(STDERR) @logger.level = Logger::Severity::ERROR @url = "http://localhost:#{Port}/" @server = @client = nil @server_thread = nil setup_server setup_client end def teardown teardown_client teardown_server end def setup_server @server = WEBrick::HTTPServer.new( :BindAddress => "0.0.0.0", :Logger => @logger, :Port => Port, :AccessLog => [], :DocumentRoot => File.dirname(File.expand_path(__FILE__)) ) @server.mount( '/', WEBrick::HTTPServlet::ProcHandler.new(method(:do_server_proc).to_proc) ) @server_thread = start_server_thread(@server) end def setup_client @client = SOAP::RPC::Driver.new(@url, '') @client.add_method("do_server_proc") end def teardown_server @server.shutdown @server_thread.kill @server_thread.join end def teardown_client @client.reset_stream end def start_server_thread(server) t = Thread.new { Thread.current.abort_on_exception = true server.start } t end def do_server_proc(req, res) res['content-type'] = 'text/xml' res.body = <<__EOX__ hello world __EOX__ end def test_normal assert_raise(SOAP::ResponseFormatError) do @client.do_server_proc end @client.options["soap.envelope.requestnamespace"] = TemporaryNamespace @client.options["soap.envelope.responsenamespace"] = TemporaryNamespace assert_equal('hello world', @client.do_server_proc) end end end ================================================ FILE: test/soap/test_httpconfigloader.rb ================================================ require 'test/unit' require 'soap/httpconfigloader' require 'soap/rpc/driver' if defined?(HTTPAccess2) module SOAP class TestHTTPConfigLoader < Test::Unit::TestCase DIR = File.dirname(File.expand_path(__FILE__)) def setup @client = SOAP::RPC::Driver.new(nil, nil) end def test_property testpropertyname = File.join(DIR, 'soapclient.properties') File.open(testpropertyname, "w") do |f| f <<<<__EOP__ protocol.http.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_PEER # depth: 1 causes an error (intentional) protocol.http.ssl_config.verify_depth = 1 protocol.http.ssl_config.ciphers = ALL __EOP__ end begin @client.loadproperty(testpropertyname) assert_equal('ALL', @client.options['protocol.http.ssl_config.ciphers']) ensure File.unlink(testpropertyname) end end end end end ================================================ FILE: test/soap/test_mapping.rb ================================================ require 'test/unit' require 'soap/mapping' module SOAP class TestMapping < Test::Unit::TestCase def test_date targets = [ ["2002-12-31", "2002-12-31Z"], ["2002-12-31+00:00", "2002-12-31Z"], ["2002-12-31-00:00", "2002-12-31Z"], ["-2002-12-31", "-2002-12-31Z"], ["-2002-12-31+00:00", "-2002-12-31Z"], ["-2002-12-31-00:00", "-2002-12-31Z"], ] targets.each do |str, expectec| d = Date.parse(str) assert_equal(d.class, convert(d).class) assert_equal(d, convert(d)) end end def test_datetime targets = [ ["2002-12-31T23:59:59.00", "2002-12-31T23:59:59Z"], ["2002-12-31T23:59:59+00:00", "2002-12-31T23:59:59Z"], ["2002-12-31T23:59:59-00:00", "2002-12-31T23:59:59Z"], ["-2002-12-31T23:59:59.00", "-2002-12-31T23:59:59Z"], ["-2002-12-31T23:59:59+00:00", "-2002-12-31T23:59:59Z"], ["-2002-12-31T23:59:59-00:00", "-2002-12-31T23:59:59Z"], ] targets.each do |str, expectec| d = DateTime.parse(str) assert_equal(d.class, convert(d).class) assert_equal(d, convert(d)) end end def convert(obj) SOAP::Mapping.soap2obj(SOAP::Mapping.obj2soap(obj)) end end end ================================================ FILE: test/soap/test_no_indent.rb ================================================ require 'test/unit' require 'soap/rpc/standaloneServer' require 'soap/rpc/driver' if defined?(HTTPAccess2) module SOAP class TestNoIndent < Test::Unit::TestCase Port = 17171 class NopServer < SOAP::RPC::StandaloneServer def initialize(*arg) super add_rpc_method(self, 'nop') end def nop SOAP::RPC::SOAPVoid.new end end def setup @server = NopServer.new(self.class.name, nil, '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @t = Thread.new { @server.start } @endpoint = "http://localhost:#{Port}/" @client = SOAP::RPC::Driver.new(@endpoint) @client.add_rpc_method('nop') end def teardown @server.shutdown @t.kill @t.join @client.reset_stream end INDENT_XML = %q[ ] NO_INDENT_XML = %q[ ] def test_indent @client.wiredump_dev = str = '' @client.options["soap.envelope.no_indent"] = false @client.nop assert_equal(INDENT_XML, parse_requestxml(str)) end def test_no_indent @client.wiredump_dev = str = '' @client.options["soap.envelope.no_indent"] = true @client.nop assert_equal(NO_INDENT_XML, parse_requestxml(str)) end def parse_requestxml(str) str.split(/\r?\n\r?\n/)[3] end end end end ================================================ FILE: test/soap/test_property.rb ================================================ require 'test/unit' require 'soap/property' module SOAP class TestProperty < Test::Unit::TestCase FrozenError = (RUBY_VERSION >= "1.9.0") ? RuntimeError : TypeError def setup @prop = ::SOAP::Property.new end def teardown # Nothing to do. end def test_s_load propstr = <<__EOP__ # comment1 # comment2\r # comment2 \r a.b.0 = 1 a.b.1 = 2 a.b.2 = 3 client.protocol.http.proxy=http://myproxy:8080 \r client.protocol.http.no_proxy: intranet.example.com,local.example.com\r client.protocol.http.protocol_version = 1.0 foo\\:bar\\=baz = qux foo\\\\.bar.baz=\tq\\\\ux\ttab a\\ b = 1 [ppp.qqq.rrr] sss = 3 ttt.uuu = 4 [ sss.ttt.uuu ] vvv.www = 5 [ ] xxx.yyy.zzz = 6 __EOP__ prop = Property.load(propstr) assert_equal(["1", "2", "3"], prop["a.b"].values.sort) assert_equal("intranet.example.com,local.example.com", prop["client.protocol.http.no_proxy"]) assert_equal("http://myproxy:8080", prop["client.protocol.http.proxy"]) assert_equal("1.0", prop["client.protocol.http.protocol_version"]) assert_equal("q\\ux\ttab", prop['foo\.bar.baz']) assert_equal("1", prop['a b']) assert_equal("3", prop['ppp.qqq.rrr.sss']) assert_equal("4", prop['ppp.qqq.rrr.ttt.uuu']) assert_equal("5", prop['sss.ttt.uuu.vvv.www']) assert_equal("6", prop['xxx.yyy.zzz']) end def test_load prop = Property.new hooked = false prop.add_hook("foo.bar.baz") do |name, value| assert_equal(["foo", "bar", "baz"], name) assert_equal("123", value) hooked = true end prop.lock prop["foo.bar"].lock prop.load("foo.bar.baz = 123") assert(hooked) assert_raises(FrozenError) do prop.load("foo.bar.qux = 123") end prop.load("foo.baz = 456") assert_equal("456", prop["foo.baz"]) end def test_initialize prop = ::SOAP::Property.new # store is empty assert_nil(prop["a"]) # does hook work? assert_equal(1, prop["a"] = 1) end def test_aref # name_to_a assert_nil(@prop[:foo]) assert_nil(@prop["foo"]) assert_nil(@prop[[:foo]]) assert_nil(@prop[["foo"]]) assert_raises(ArgumentError) do @prop[1] end @prop[:foo] = :foo assert_equal(:foo, @prop[:foo]) assert_equal(:foo, @prop["foo"]) assert_equal(:foo, @prop[[:foo]]) assert_equal(:foo, @prop[["foo"]]) end def test_referent # referent(1) assert_nil(@prop["foo.foo"]) assert_nil(@prop[["foo", "foo"]]) assert_nil(@prop[["foo", :foo]]) @prop["foo.foo"] = :foo assert_equal(:foo, @prop["foo.foo"]) assert_equal(:foo, @prop[["foo", "foo"]]) assert_equal(:foo, @prop[[:foo, "foo"]]) # referent(2) @prop["bar.bar.bar"] = :bar assert_equal(:bar, @prop["bar.bar.bar"]) assert_equal(:bar, @prop[["bar", "bar", "bar"]]) assert_equal(:bar, @prop[[:bar, "bar", :bar]]) end def test_to_key_and_deref @prop["foo.foo"] = :foo assert_equal(:foo, @prop["fOo.FoO"]) assert_equal(:foo, @prop[[:fOO, :FOO]]) assert_equal(:foo, @prop[["FoO", :Foo]]) # deref_key negative test assert_raises(ArgumentError) do @prop["baz"] = 1 @prop["baz.qux"] = 2 end end def test_hook_name tag = Object.new tested = false @prop.add_hook("foo.bar") do |key, value| assert_raise(FrozenError) do key << "baz" end tested = true end @prop["foo.bar"] = tag assert(tested) end def test_value_hook tag = Object.new tested = false @prop.add_hook("FOO.BAR.BAZ") do |key, value| assert_equal(["Foo", "baR", "baZ"], key) assert_equal(tag, value) tested = true end @prop["Foo.baR.baZ"] = tag assert_equal(tag, @prop["foo.bar.baz"]) assert(tested) @prop["foo.bar"] = 1 # unhook the above block assert_equal(1, @prop["foo.bar"]) end def test_key_hook_no_cascade tag = Object.new tested = 0 @prop.add_hook do |key, value| assert(false) end @prop.add_hook(false) do |key, value| assert(false) end @prop.add_hook("foo") do |key, value| assert(false) end @prop.add_hook("foo.bar", false) do |key, value| assert(false) end @prop.add_hook("foo.bar.baz") do |key, value| assert(false) end @prop.add_hook("foo.bar.baz.qux", false) do |key, value| assert_equal(["foo", "bar", "baz", "qux"], key) assert_equal(tag, value) tested += 1 end @prop["foo.bar.baz.qux"] = tag assert_equal(tag, @prop["foo.bar.baz.qux"]) assert_equal(1, tested) end def test_key_hook_cascade tag = Object.new tested = 0 @prop.add_hook(true) do |key, value| assert_equal(["foo", "bar", "baz", "qux"], key) assert_equal(tag, value) tested += 1 end @prop.add_hook("foo", true) do |key, value| assert_equal(["foo", "bar", "baz", "qux"], key) assert_equal(tag, value) tested += 1 end @prop.add_hook("foo.bar", true) do |key, value| assert_equal(["foo", "bar", "baz", "qux"], key) assert_equal(tag, value) tested += 1 end @prop.add_hook("foo.bar.baz", true) do |key, value| assert_equal(["foo", "bar", "baz", "qux"], key) assert_equal(tag, value) tested += 1 end @prop.add_hook("foo.bar.baz.qux", true) do |key, value| assert_equal(["foo", "bar", "baz", "qux"], key) assert_equal(tag, value) tested += 1 end @prop["foo.bar.baz.qux"] = tag assert_equal(tag, @prop["foo.bar.baz.qux"]) assert_equal(5, tested) end def test_keys assert(@prop.keys.empty?) @prop["foo"] = 1 @prop["bar"] @prop["BAz"] = 2 assert_equal(2, @prop.keys.size) assert(@prop.keys.member?("foo")) assert(@prop.keys.member?("baz")) # assert_nil(@prop["a"]) @prop["a.a"] = 1 assert_instance_of(::SOAP::Property, @prop["a"]) @prop["a.b"] = 1 @prop["a.c"] = 1 assert_equal(3, @prop["a"].keys.size) assert(@prop["a"].keys.member?("a")) assert(@prop["a"].keys.member?("b")) assert(@prop["a"].keys.member?("c")) end def test_lshift assert(@prop.empty?) @prop << 1 assert_equal([1], @prop.values) assert_equal(1, @prop["0"]) @prop << 1 assert_equal([1, 1], @prop.values) assert_equal(1, @prop["1"]) @prop << 1 assert_equal([1, 1, 1], @prop.values) assert_equal(1, @prop["2"]) # @prop["abc.def"] = o = SOAP::Property.new tested = 0 o.add_hook do |k, v| tested += 1 end @prop["abc.def"] << 1 @prop["abc.def"] << 2 @prop["abc.def"] << 3 @prop["abc.def"] << 4 assert_equal(4, tested) end def test_lock_each @prop["a.b.c.d.e"] = 1 @prop["a.b.d"] = branch = ::SOAP::Property.new @prop["a.b.d.e.f"] = 2 @prop.lock assert(@prop.locked?) assert_instance_of(::SOAP::Property, @prop["a"]) assert_raises(FrozenError) do @prop["b"] end # @prop["a"].lock assert_raises(FrozenError) do @prop["a"] end assert_instance_of(::SOAP::Property, @prop["a.b"]) # @prop["a.b"].lock assert_raises(FrozenError) do @prop["a.b"] end assert_raises(FrozenError) do @prop["a"] end # @prop["a.b.c.d"].lock assert_instance_of(::SOAP::Property, @prop["a.b.c"]) assert_raises(FrozenError) do @prop["a.b.c.d"] end assert_instance_of(::SOAP::Property, @prop["a.b.d"]) # branch["e"].lock assert_instance_of(::SOAP::Property, @prop["a.b.d"]) assert_raises(FrozenError) do @prop["a.b.d.e"] end assert_raises(FrozenError) do branch["e"] end end def test_lock_cascade @prop["a.a"] = nil @prop["a.b.c"] = 1 @prop["b"] = false @prop.lock(true) assert(@prop.locked?) assert_equal(nil, @prop["a.a"]) assert_equal(1, @prop["a.b.c"]) assert_equal(false, @prop["b"]) assert_raises(FrozenError) do @prop["c"] end assert_raises(FrozenError) do @prop["c"] = 2 end assert_raises(FrozenError) do @prop["a.b.R"] end assert_raises(FrozenError) do @prop.add_hook do assert(false) end end assert_raises(FrozenError) do @prop.add_hook("c") do assert(false) end end assert_raises(FrozenError) do @prop.add_hook("a.c") do assert(false) end end assert_nil(@prop["a.a"]) @prop["a.a"] = 2 assert_equal(2, @prop["a.a"]) # @prop.unlock(true) assert_nil(@prop["c"]) @prop["c"] = 2 assert_equal(2, @prop["c"]) @prop["a.d.a.a"] = :foo assert_equal(:foo, @prop["a.d.a.a"]) tested = false @prop.add_hook("a.c") do |name, value| assert(true) tested = true end @prop["a.c"] = 3 assert(tested) end def test_hook_then_lock tested = false @prop.add_hook("a.b.c") do |name, value| assert_equal(["a", "b", "c"], name) tested = true end @prop["a.b"].lock assert(!tested) @prop["a.b.c"] = 5 assert(tested) assert_equal(5, @prop["a.b.c"]) assert_raises(FrozenError) do @prop["a.b.d"] = 5 end end def test_lock_unlock_return assert_equal(@prop, @prop.lock) assert_equal(@prop, @prop.unlock) end def test_lock_split @prop["a.b.c"] = 1 assert_instance_of(::SOAP::Property, @prop["a.b"]) @prop["a.b.d"] = branch = ::SOAP::Property.new @prop["a.b.d.e"] = 2 assert_equal(branch, @prop["a.b.d"]) assert_equal(branch, @prop[:a][:b][:d]) @prop.lock(true) # split error 1 assert_raises(FrozenError) do @prop["a.b"] end # split error 2 assert_raises(FrozenError) do @prop["a"] end @prop["a.b.c"] = 2 assert_equal(2, @prop["a.b.c"]) # replace error assert_raises(FrozenError) do @prop["a.b.c"] = ::SOAP::Property.new end # override error assert_raises(FrozenError) do @prop["a.b"] = 1 end # assert_raises(FrozenError) do @prop["a.b.d"] << 1 end assert_raises(FrozenError) do branch << 1 end branch.unlock(true) branch << 1 branch << 2 branch << 3 assert_equal(2, @prop["a.b.d.e"]) assert_equal(1, @prop["a.b.d.1"]) assert_equal(2, @prop["a.b.d.2"]) assert_equal(3, @prop["a.b.d.3"]) end end end ================================================ FILE: test/soap/test_soapelement.rb ================================================ require 'test/unit' require 'soap/baseData' require 'soap/mapping' module SOAP class TestSOAPElement < Test::Unit::TestCase include SOAP def setup # Nothing to do. end def teardown # Nothing to do. end def d(elename = nil, text = nil) elename ||= n(nil, nil) if text SOAPElement.new(elename, text) else SOAPElement.new(elename) # do not merge. end end def n(namespace, name) XSD::QName.new(namespace, name) end def test_initialize elename = n(nil, nil) obj = d(elename) assert_equal(elename, obj.elename) assert_equal(LiteralNamespace, obj.encodingstyle) assert_equal({}, obj.extraattr) assert_equal([], obj.precedents) assert_equal(nil, obj.qualified) assert_equal(nil, obj.text) assert(obj.members.empty?) obj = d("foo", "text") assert_equal(n(nil, "foo"), obj.elename) assert_equal("text", obj.text) end def test_add obj = d() child = d("abc") obj.add(child) assert(obj.key?("abc")) assert_same(child, obj["abc"]) assert_same(child, obj.abc) def obj.foo; 1; end child = d("foo") obj.add(child) assert_equal(1, obj.foo) assert_equal(child, obj.var_foo) child = d("_?a?b_") obj.add(child) assert_equal(child, obj.__send__('_?a?b_')) end def test_member obj = d() c1 = d("c1") obj.add(c1) c2 = d("c2") obj.add(c2) assert(obj.key?("c1")) assert(obj.key?("c2")) assert_equal(c1, obj["c1"]) assert_equal(c2, obj["c2"]) c22 = d("c22") obj["c2"] = c22 assert(obj.key?("c2")) assert_equal(c22, obj["c2"]) assert_equal(["c1", "c2"], obj.members.sort) # k_expect = ["c1", "c2"] v_expect = [c1, c22] obj.each do |k, v| assert(k_expect.include?(k)) assert(v_expect.include?(v)) k_expect.delete(k) v_expect.delete(v) end assert(k_expect.empty?) assert(v_expect.empty?) end def test_to_obj obj = d("root") ct1 = d("ct1", "t1") obj.add(ct1) c2 = d("c2") ct2 = d("ct2", "t2") c2.add(ct2) obj.add(c2) assert_equal({ "ct1" => "t1", "c2" => { "ct2" => "t2" }}, obj.to_obj) # assert_equal(nil, d().to_obj) assert_equal("abc", d(nil, "abc").to_obj) assert_equal(nil, d("abc", nil).to_obj) end def test_from_obj source = { "ct1" => "t1", "c2" => { "ct2" => "t2" }} assert_equal(source, SOAPElement.from_obj(source).to_obj) source = { "1" => nil } assert_equal(source, SOAPElement.from_obj(source).to_obj) source = {} assert_equal(nil, SOAPElement.from_obj(source).to_obj) # not {} source = nil assert_equal(nil, SOAPElement.from_obj(source).to_obj) end end end ================================================ FILE: test/soap/test_streamhandler.rb ================================================ require 'test/unit' require 'soap/rpc/driver' require 'webrick' require 'webrick/httpproxy' require 'logger' module SOAP class TestStreamHandler < Test::Unit::TestCase Port = 17171 ProxyPort = 17172 def setup @logger = Logger.new(STDERR) @logger.level = Logger::Severity::ERROR @url = "http://localhost:#{Port}/" @proxyurl = "http://localhost:#{ProxyPort}/" @server = @proxyserver = @client = nil @server_thread = @proxyserver_thread = nil setup_server setup_client end def teardown teardown_client teardown_proxyserver if @proxyserver teardown_server end def setup_server @server = WEBrick::HTTPServer.new( :BindAddress => "0.0.0.0", :Logger => @logger, :Port => Port, :AccessLog => [], :DocumentRoot => File.dirname(File.expand_path(__FILE__)) ) @server.mount( '/', WEBrick::HTTPServlet::ProcHandler.new(method(:do_server_proc).to_proc) ) @server_thread = start_server_thread(@server) end def setup_proxyserver @proxyserver = WEBrick::HTTPProxyServer.new( :BindAddress => "0.0.0.0", :Logger => @logger, :Port => ProxyPort, :AccessLog => [] ) @proxyserver_thread = start_server_thread(@proxyserver) end def setup_client @client = SOAP::RPC::Driver.new(@url, '') @client.add_method("do_server_proc") end def teardown_server @server.shutdown @server_thread.kill @server_thread.join end def teardown_proxyserver @proxyserver.shutdown @proxyserver_thread.kill @proxyserver_thread.join end def teardown_client @client.reset_stream end def start_server_thread(server) t = Thread.new { Thread.current.abort_on_exception = true server.start } t end def do_server_proc(req, res) res['content-type'] = 'text/xml' res.body = <<__EOX__ __EOX__ end def parse_req_header(str) if ::SOAP::HTTPStreamHandler::Client.to_s == 'SOAP::NetHttpClient' str = eval(str.split(/\r?\n/)[4][3..-1]) end parse_req_header_http_access2(str) end def parse_req_header_http_access2(str) headerp = false headers = {} req = nil str.split(/(?:\r?\n)/).each do |line| if headerp and /^$/ =~line headerp = false break end if headerp k, v = line.scan(/^([^:]+):\s*(.*)$/)[0] headers[k.downcase] = v end if /^POST/ =~ line req = line headerp = true end end return req, headers end def test_normal str = "" @client.wiredump_dev = str assert_nil(@client.do_server_proc) r, h = parse_req_header(str) assert_match(%r"POST / HTTP/1.", r) assert(/^text\/xml;/ =~ h["content-type"]) end def test_uri # initialize client with URI object @client = SOAP::RPC::Driver.new(URI.parse(@url), '') @client.add_method("do_server_proc") # same as test_normal str = "" @client.wiredump_dev = str assert_nil(@client.do_server_proc) r, h = parse_req_header(str) assert_match(%r"POST / HTTP/1.", r) assert(/^text\/xml;/ =~ h["content-type"]) end def test_basic_auth unless Object.const_defined?('HTTPAccess2') # soap4r + net/http + basic_auth is not supported. # use http-access2 instead. assert(true) return end str = "" @client.wiredump_dev = str @client.options["protocol.http.basic_auth"] << [@url, "foo", "bar"] assert_nil(@client.do_server_proc) r, h = parse_req_header(str) assert_equal("Basic Zm9vOmJhcg==", h["authorization"]) end def test_proxy if Object.const_defined?('HTTPAccess2') backup = HTTPAccess2::Client::NO_PROXY_HOSTS.dup HTTPAccess2::Client::NO_PROXY_HOSTS.clear else backup = SOAP::NetHttpClient::NO_PROXY_HOSTS.dup SOAP::NetHttpClient::NO_PROXY_HOSTS.clear end setup_proxyserver str = "" @client.wiredump_dev = str @client.options["protocol.http.proxy"] = @proxyurl assert_nil(@client.do_server_proc) r, h = parse_req_header(str) assert_match(%r"POST http://localhost:17171/ HTTP/1.", r) # illegal proxy uri assert_raise(ArgumentError) do @client.options["protocol.http.proxy"] = 'ftp://foo:8080' end ensure if Object.const_defined?('HTTPAccess2') HTTPAccess2::Client::NO_PROXY_HOSTS.replace(backup) else SOAP::NetHttpClient::NO_PROXY_HOSTS.replace(backup) end end def test_charset str = "" @client.wiredump_dev = str @client.options["protocol.http.charset"] = "iso-8859-8" assert_nil(@client.do_server_proc) r, h = parse_req_header(str) assert_equal("text/xml; charset=iso-8859-8", h["content-type"]) # str.replace("") @client.options["protocol.http.charset"] = "iso-8859-3" assert_nil(@client.do_server_proc) r, h = parse_req_header(str) assert_equal("text/xml; charset=iso-8859-3", h["content-type"]) end end end ================================================ FILE: test/soap/test_styleuse.rb ================================================ require 'test/unit' require 'soap/rpc/httpserver' require 'soap/rpc/driver' module SOAP class TestStyleUse < Test::Unit::TestCase # rpc driver: obj in(Hash allowed for literal), obj out # # style: not visible from user # rpc: wrapped element # document: unwrappted element # # use: # encoding: a graph (SOAP Data Model) # literal: not a graph (SOAPElement) # # rpc stub: obj in, obj out(Hash is allowed for literal) # # style: not visible from user # rpc: wrapped element # document: unwrappted element # # use: # encoding: a graph (SOAP Data Model) # literal: not a graph (SOAPElement) # # document driver: SOAPElement in, SOAPElement out? [not implemented] # # style: ditto # use: ditto # # # document stub: SOAPElement in, SOAPElement out? [not implemented] # # style: ditto # use: ditto # class GenericServant # method name style: requeststyle_requestuse_responsestyle_responseuse # 2 params -> array def rpc_enc_rpc_enc(obj1, obj2) [obj1, [obj1, obj2]] end # 2 objs -> array def rpc_lit_rpc_enc(obj1, obj2) [obj2, obj1] end # 2 params -> 2 params def rpc_enc_rpc_lit(obj1, obj2) klass = [obj1.class.name, obj2.class.name] [obj2, obj1] end # 2 objs -> 2 objs def rpc_lit_rpc_lit(obj1, obj2) [obj1, obj2] end # 2 params -> array def doc_enc_doc_enc(obj1, obj2) [obj1, [obj1, obj2]] end # 2 objs -> array def doc_lit_doc_enc(obj1, obj2) [obj2, obj1] end # 2 params -> 2 hashes def doc_enc_doc_lit(obj1, obj2) klass = [obj1.class.name, obj2.class.name] return {'obj1' => {'klass' => klass}, 'misc' => 'hash does not have an order'}, {'obj2' => {'klass' => klass}} end # 2 objs -> 2 objs def doc_lit_doc_lit(obj1, obj2) return obj1, obj2 end end Namespace = "urn:styleuse" module Op def self.opt(request_style, request_use, response_style, response_use) { :request_style => request_style, :request_use => request_use, :response_style => response_style, :response_use => response_use } end Op_rpc_enc_rpc_enc = [ XSD::QName.new(Namespace, 'rpc_enc_rpc_enc'), nil, 'rpc_enc_rpc_enc', [ ['in', 'obj1', nil], ['in', 'obj2', nil], ['retval', 'return', nil]], opt(:rpc, :encoded, :rpc, :encoded) ] Op_rpc_lit_rpc_enc = [ XSD::QName.new(Namespace, 'rpc_lit_rpc_enc'), nil, 'rpc_lit_rpc_enc', [ ['in', 'obj1', nil], ['in', 'obj2', nil], ['retval', 'return', nil]], opt(:rpc, :literal, :rpc, :encoded) ] Op_rpc_enc_rpc_lit = [ XSD::QName.new(Namespace, 'rpc_enc_rpc_lit'), nil, 'rpc_enc_rpc_lit', [ ['in', 'obj1', nil], ['in', 'obj2', nil], ['retval', 'ret1', nil], ['out', 'ret2', nil]], opt(:rpc, :encoded, :rpc, :literal) ] Op_rpc_lit_rpc_lit = [ XSD::QName.new(Namespace, 'rpc_lit_rpc_lit'), nil, 'rpc_lit_rpc_lit', [ ['in', 'obj1', nil], ['in', 'obj2', nil], ['retval', 'ret1', nil], ['out', 'ret2', nil]], opt(:rpc, :literal, :rpc, :literal) ] Op_doc_enc_doc_enc = [ Namespace + 'doc_enc_doc_enc', 'doc_enc_doc_enc', [ ['in', 'obj1', [nil, Namespace, 'obj1']], ['in', 'obj2', [nil, Namespace, 'obj2']], ['out', 'ret1', [nil, Namespace, 'ret1']], ['out', 'ret2', [nil, Namespace, 'ret2']]], opt(:document, :encoded, :document, :encoded) ] Op_doc_lit_doc_enc = [ Namespace + 'doc_lit_doc_enc', 'doc_lit_doc_enc', [ ['in', 'obj1', [nil, Namespace, 'obj1']], ['in', 'obj2', [nil, Namespace, 'obj2']], ['out', 'ret1', [nil, Namespace, 'ret1']], ['out', 'ret2', [nil, Namespace, 'ret2']]], opt(:document, :literal, :document, :encoded) ] Op_doc_enc_doc_lit = [ Namespace + 'doc_enc_doc_lit', 'doc_enc_doc_lit', [ ['in', 'obj1', [nil, Namespace, 'obj1']], ['in', 'obj2', [nil, Namespace, 'obj2']], ['out', 'ret1', [nil, Namespace, 'ret1']], ['out', 'ret2', [nil, Namespace, 'ret2']]], opt(:document, :encoded, :document, :literal) ] Op_doc_lit_doc_lit = [ Namespace + 'doc_lit_doc_lit', 'doc_lit_doc_lit', [ ['in', 'obj1', [nil, Namespace, 'obj1']], ['in', 'obj2', [nil, Namespace, 'obj2']], ['out', 'ret1', [nil, Namespace, 'ret1']], ['out', 'ret2', [nil, Namespace, 'ret2']]], opt(:document, :literal, :document, :literal) ] end include Op class Server < ::SOAP::RPC::HTTPServer include Op def on_init @servant = GenericServant.new add_rpc_operation(@servant, *Op_rpc_enc_rpc_enc) add_rpc_operation(@servant, *Op_rpc_lit_rpc_enc) add_rpc_operation(@servant, *Op_rpc_enc_rpc_lit) add_rpc_operation(@servant, *Op_rpc_lit_rpc_lit) add_document_operation(@servant, *Op_doc_enc_doc_enc) add_document_operation(@servant, *Op_doc_lit_doc_enc) add_document_operation(@servant, *Op_doc_enc_doc_lit) add_document_operation(@servant, *Op_doc_lit_doc_lit) end end Port = 17171 def setup setup_server setup_client end def setup_server @server = Server.new( :BindAddress => "0.0.0.0", :Port => Port, :AccessLog => [], :SOAPDefaultNamespace => Namespace ) @server.level = Logger::Severity::ERROR @server_thread = start_server_thread(@server) end def setup_client @client = ::SOAP::RPC::Driver.new("http://localhost:#{Port}/", Namespace) @client.wiredump_dev = STDERR if $DEBUG @client.add_rpc_operation(*Op_rpc_enc_rpc_enc) @client.add_rpc_operation(*Op_rpc_lit_rpc_enc) @client.add_rpc_operation(*Op_rpc_enc_rpc_lit) @client.add_rpc_operation(*Op_rpc_lit_rpc_lit) @client.add_document_operation(*Op_doc_enc_doc_enc) @client.add_document_operation(*Op_doc_lit_doc_enc) @client.add_document_operation(*Op_doc_enc_doc_lit) @client.add_document_operation(*Op_doc_lit_doc_lit) end def teardown teardown_server teardown_client end def teardown_server @server.shutdown @server_thread.kill @server_thread.join end def teardown_client @client.reset_stream end def start_server_thread(server) t = Thread.new { Thread.current.abort_on_exception = true server.start } t end def test_rpc_enc_rpc_enc o = "hello" obj1 = o obj2 = [1] ret = @client.rpc_enc_rpc_enc(obj1, obj2) # server returns [obj1, [obj1, obj2]] assert_equal([obj1, [obj1, obj2]], ret) assert_same(ret[0], ret[1][0]) end S1 = ::Struct.new(:a) S2 = ::Struct.new(:c) def test_rpc_lit_rpc_enc ret1, ret2 = @client.rpc_lit_rpc_enc(S1.new('b'), S2.new('d')) assert_equal('d', ret1.c) assert_equal('b', ret2.a) # Hash is allowed for literal ret1, ret2 = @client.rpc_lit_rpc_enc({'a' => 'b'}, {'c' => 'd'}) assert_equal('d', ret1.c) assert_equal('b', ret2.a) # simple value assert_equal( ['1', 'a'], @client.rpc_lit_rpc_enc('a', 1) ) end def test_rpc_enc_rpc_lit assert_equal( ['1', 'a'], @client.rpc_enc_rpc_lit('a', '1') ) end def test_rpc_lit_rpc_lit ret1, ret2 = @client.rpc_lit_rpc_lit({'a' => 'b'}, {'c' => 'd'}) assert_equal('b', ret1["a"]) assert_equal('d', ret2["c"]) end def test_doc_enc_doc_enc o = "hello" obj1 = o obj2 = [1] ret = @client.rpc_enc_rpc_enc(obj1, obj2) # server returns [obj1, [obj1, obj2]] assert_equal([obj1, [obj1, obj2]], ret) assert_same(ret[0], ret[1][0]) end def test_doc_lit_doc_enc ret1, ret2 = @client.doc_lit_doc_enc({'a' => 'b'}, {'c' => 'd'}) assert_equal('d', ret1.c) assert_equal('b', ret2.a) assert_equal( ['a', '1'], @client.doc_lit_doc_enc(1, 'a') ) end def test_doc_enc_doc_lit ret1, ret2 = @client.doc_enc_doc_lit('a', 1) # literal Array assert_equal(['String', 'Fixnum'], ret1['obj1']['klass']) # same value assert_equal(ret1['obj1']['klass'], ret2['obj2']['klass']) # not the same object (not encoded) assert_not_same(ret1['obj1']['klass'], ret2['obj2']['klass']) end def test_doc_lit_doc_lit ret1, ret2 = @client.doc_lit_doc_lit({'a' => 'b'}, {'c' => 'd'}) assert_equal('b', ret1["a"]) assert_equal('d', ret2["c"]) end end end ================================================ FILE: test/soap/wsdlDriver/README.txt ================================================ echo_version.rb is generated by wsdl2ruby.rb; % wsdl2ruby.rb --wsdl simpletype.wsdl --classdef --force ================================================ FILE: test/soap/wsdlDriver/calc.wsdl ================================================ calculator service ================================================ FILE: test/soap/wsdlDriver/document.wsdl ================================================ ================================================ FILE: test/soap/wsdlDriver/echo_version.rb ================================================ # urn:example.com:simpletype-rpc-type class Version_struct @@schema_type = "version_struct" @@schema_ns = "urn:example.com:simpletype-rpc-type" attr_accessor :version attr_accessor :msg def initialize(version = nil, msg = nil) @version = version @msg = msg end end # urn:example.com:simpletype-rpc-type module Versions C_16 = "1.6" C_18 = "1.8" C_19 = "1.9" end ================================================ FILE: test/soap/wsdlDriver/simpletype.wsdl ================================================ ================================================ FILE: test/soap/wsdlDriver/test_calc.rb ================================================ require 'test/unit' require 'soap/rpc/httpserver' require 'soap/wsdlDriver' module SOAP class TestCalc < Test::Unit::TestCase class Server < ::SOAP::RPC::HTTPServer def on_init add_method(self, 'add', 'x', 'y') end def add(x, y) x.to_f + y.to_f end end DIR = File.dirname(File.expand_path(__FILE__)) Port = 17171 def setup setup_server setup_client end def setup_server @server = Server.new( :BindAddress => "0.0.0.0", :Port => Port, :AccessLog => [], :SOAPDefaultNamespace => 'http://www.fred.com' ) @server.level = Logger::Severity::ERROR @server_thread = start_server_thread(@server) end def setup_client @wsdl = File.join(DIR, 'calc.wsdl') end def teardown teardown_server teardown_client end def teardown_server @server.shutdown @server_thread.kill @server_thread.join end def teardown_client @client.reset_stream if @client end def start_server_thread(server) t = Thread.new { Thread.current.abort_on_exception = true server.start } t end def test_rpc_driver @client = ::SOAP::WSDLDriverFactory.new(@wsdl).create_rpc_driver @client.wiredump_dev = STDOUT if $DEBUG @client.endpoint_url = "http://localhost:#{Port}/" @client.generate_explicit_type = true assert_equal(0.3, @client.add(0.1, 0.2)) @client.generate_explicit_type = false assert_equal(0.3, @client.add(0.1, 0.2)) end def test_old_driver silent do @client = ::SOAP::WSDLDriverFactory.new(@wsdl).create_driver end @client.wiredump_dev = STDOUT if $DEBUG @client.endpoint_url = "http://localhost:#{Port}/" @client.generate_explicit_type = true assert_equal(0.3, @client.add(0.1, 0.2)) @client.generate_explicit_type = false assert_equal(0.3, @client.add(0.1, 0.2)) end def silent back = $VERBOSE $VERBOSE = nil begin yield ensure $VERBOSE = back end end end end ================================================ FILE: test/soap/wsdlDriver/test_document.rb ================================================ require 'test/unit' require 'soap/rpc/standaloneServer' require 'soap/wsdlDriver' module SOAP class TestDocument < Test::Unit::TestCase Namespace = 'urn:example.com:document' class Server < ::SOAP::RPC::StandaloneServer def on_init add_document_method(self, 'urn:example.com:document#submit', 'submit', XSD::QName.new(Namespace, 'ruby'), XSD::QName.new(Namespace, 'ruby')) end def submit(ruby) ruby end end DIR = File.dirname(File.expand_path(__FILE__)) Port = 17171 def setup setup_server setup_client end def setup_server @server = Server.new('Test', Namespace, '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @server_thread = start_server_thread(@server) end def setup_client wsdl = File.join(DIR, 'document.wsdl') @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver @client.endpoint_url = "http://localhost:#{Port}/" @client.wiredump_dev = STDOUT if $DEBUG end def teardown teardown_server teardown_client end def teardown_server @server.shutdown @server_thread.kill @server_thread.join end def teardown_client @client.reset_stream end def start_server_thread(server) t = Thread.new { Thread.current.abort_on_exception = true server.start } t end def test_document msg = {'myversion' => "1.9", 'date' => "2004-01-01T00:00:00Z"} reply_msg = @client.submit(msg) assert_equal('1.9', reply_msg.myversion) assert_equal('1.9', reply_msg['myversion']) assert_equal('2004-01-01T00:00:00Z', reply_msg.date) assert_equal('2004-01-01T00:00:00Z', reply_msg['date']) end end end ================================================ FILE: test/soap/wsdlDriver/test_simpletype.rb ================================================ require 'test/unit' require 'soap/rpc/httpserver' require 'soap/wsdlDriver' module SOAP class TestSimpleType < Test::Unit::TestCase class Server < ::SOAP::RPC::HTTPServer def on_init add_method(self, 'echo_version', 'version') end def echo_version(version) # "2.0" is out of range. Version_struct.new(version || "2.0", 'checked') end end DIR = File.dirname(File.expand_path(__FILE__)) require File.join(DIR, 'echo_version') Port = 17171 def setup setup_server setup_client end def setup_server @server = Server.new( :BindAddress => "0.0.0.0", :Port => Port, :AccessLog => [], :SOAPDefaultNamespace => "urn:example.com:simpletype-rpc" ) @server.level = Logger::Severity::ERROR @server_thread = start_server_thread(@server) end def setup_client wsdl = File.join(DIR, 'simpletype.wsdl') @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver @client.wiredump_dev = STDOUT if $DEBUG @client.endpoint_url = "http://localhost:#{Port}/" @client.generate_explicit_type = false end def teardown teardown_server teardown_client end def teardown_server @server.shutdown @server_thread.kill @server_thread.join end def teardown_client @client.reset_stream end def start_server_thread(server) t = Thread.new { Thread.current.abort_on_exception = true server.start } t end def test_ping result = @client.echo_version("1.9") assert_equal("1.9", result.version) assert_equal("checked", result.msg) assert_raise(XSD::ValueSpaceError) do @client.echo_version("2.0") end assert_raise(XSD::ValueSpaceError) do @client.echo_version(nil) # nil => "2.0" => out of range end end end end ================================================ FILE: test/socket/test_nonblock.rb ================================================ begin require "socket" rescue LoadError end require "test/unit" require "tempfile" require "timeout" class TestNonblockSocket < Test::Unit::TestCase def test_accept_nonblock serv = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) serv.bind(Socket.sockaddr_in(0, "127.0.0.1")) serv.listen(5) assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { serv.accept_nonblock } c = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) c.connect(serv.getsockname) s, sockaddr = serv.accept_nonblock assert_equal(Socket.unpack_sockaddr_in(c.getsockname), Socket.unpack_sockaddr_in(sockaddr)) ensure serv.close if serv c.close if c s.close if s end def test_connect_nonblock serv = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) serv.bind(Socket.sockaddr_in(0, "127.0.0.1")) serv.listen(5) c = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) servaddr = serv.getsockname begin c.connect_nonblock(servaddr) rescue Errno::EINPROGRESS IO.select nil, [c] assert_nothing_raised { begin c.connect_nonblock(servaddr) rescue Errno::EISCONN end } end s, sockaddr = serv.accept assert_equal(Socket.unpack_sockaddr_in(c.getsockname), Socket.unpack_sockaddr_in(sockaddr)) ensure serv.close if serv c.close if c s.close if s end def test_udp_recvfrom_nonblock u1 = UDPSocket.new u2 = UDPSocket.new u1.bind("127.0.0.1", 0) assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { u1.recvfrom_nonblock(100) } assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::EINVAL) { u2.recvfrom_nonblock(100) } u2.send("aaa", 0, u1.getsockname) IO.select [u1] mesg, inet_addr = u1.recvfrom_nonblock(100) assert_equal(4, inet_addr.length) assert_equal("aaa", mesg) af, port, host, addr = inet_addr u2_port, u2_addr = Socket.unpack_sockaddr_in(u2.getsockname) assert_equal(u2_port, port) assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { u1.recvfrom_nonblock(100) } u2.send("", 0, u1.getsockname) assert_nothing_raised("cygwin 1.5.19 has a problem to send an empty UDP packet. [ruby-dev:28915]") { timeout(1) { IO.select [u1] } } mesg, inet_addr = u1.recvfrom_nonblock(100) assert_equal("", mesg) ensure u1.close if u1 u2.close if u2 end def test_udp_recv_nonblock u1 = UDPSocket.new u2 = UDPSocket.new u1.bind("127.0.0.1", 0) assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { u1.recv_nonblock(100) } assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::EINVAL) { u2.recv_nonblock(100) } u2.send("aaa", 0, u1.getsockname) IO.select [u1] mesg = u1.recv_nonblock(100) assert_equal("aaa", mesg) assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { u1.recv_nonblock(100) } u2.send("", 0, u1.getsockname) assert_nothing_raised("cygwin 1.5.19 has a problem to send an empty UDP packet. [ruby-dev:28915]") { timeout(1) { IO.select [u1] } } mesg = u1.recv_nonblock(100) assert_equal("", mesg) ensure u1.close if u1 u2.close if u2 end def test_socket_recvfrom_nonblock s1 = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0) s1.bind(Socket.sockaddr_in(0, "127.0.0.1")) s2 = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0) assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { s1.recvfrom_nonblock(100) } assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::EINVAL) { s2.recvfrom_nonblock(100) } s2.send("aaa", 0, s1.getsockname) IO.select [s1] mesg, sockaddr = s1.recvfrom_nonblock(100) assert_equal("aaa", mesg) port, addr = Socket.unpack_sockaddr_in(sockaddr) s2_port, s2_addr = Socket.unpack_sockaddr_in(s2.getsockname) assert_equal(s2_port, port) ensure s1.close if s1 s2.close if s2 end def tcp_pair serv = TCPServer.new("127.0.0.1", 0) af, port, host, addr = serv.addr c = TCPSocket.new(addr, port) s = serv.accept return c, s ensure serv.close if serv end def test_tcp_recv_nonblock c, s = tcp_pair assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { c.recv_nonblock(100) } assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { s.recv_nonblock(100) } c.write("abc") IO.select [s] assert_equal("a", s.recv_nonblock(1)) assert_equal("bc", s.recv_nonblock(100)) assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { s.recv_nonblock(100) } ensure c.close if c s.close if s end def test_read_nonblock c, s = tcp_pair assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { c.read_nonblock(100) } assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { s.read_nonblock(100) } c.write("abc") IO.select [s] assert_equal("a", s.read_nonblock(1)) assert_equal("bc", s.read_nonblock(100)) assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { s.read_nonblock(100) } ensure c.close if c s.close if s end =begin def test_write_nonblock c, s = tcp_pair str = "a" * 10000 _, ws, _ = IO.select(nil, [c], nil) assert_equal([c], ws) ret = c.write_nonblock(str) assert_operator(ret, :>, 0) loop { assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { loop { ret = c.write_nonblock(str) assert_operator(ret, :>, 0) } } _, ws, _ = IO.select(nil, [c], nil, 0) break if !ws } ensure c.close if c s.close if s end =end end if defined?(Socket) ================================================ FILE: test/socket/test_socket.rb ================================================ begin require "socket" require "test/unit" rescue LoadError end class TestBasicSocket < Test::Unit::TestCase def inet_stream sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) yield sock ensure assert_raise(IOError) {sock.close} end def test_getsockopt inet_stream do |s| n = s.getsockopt(Socket::SOL_SOCKET, Socket::SO_TYPE) assert_equal([Socket::SOCK_STREAM].pack("i"), n) n = s.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR) assert_equal([0].pack("i"), n) val = Object.new class << val; self end.__send__(:define_method, :to_int) { s.close Socket::SO_TYPE } assert_raise(IOError) { n = s.getsockopt(Socket::SOL_SOCKET, val) } end end def test_setsockopt # [ruby-dev:25039] s = nil linger = [0, 0].pack("ii") val = Object.new class << val; self end.__send__(:define_method, :to_str) { s.close linger } inet_stream do |s| assert_equal(0, s.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, linger)) assert_raise(IOError) { s.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, val) } end val = Object.new class << val; self end.__send__(:define_method, :to_int) { s.close Socket::SO_LINGER } inet_stream do |s| assert_raise(IOError) { s.setsockopt(Socket::SOL_SOCKET, val, linger) } end end def test_listen s = nil log = Object.new class << log; self end.__send__(:define_method, :to_int) { s.close 2 } inet_stream do |s| assert_raise(IOError) { s.listen(log) } end end end if defined?(Socket) class TestSocket < Test::Unit::TestCase def test_unpack_sockaddr sockaddr_in = Socket.sockaddr_in(80, "") assert_raise(ArgumentError) { Socket.unpack_sockaddr_un(sockaddr_in) } sockaddr_un = Socket.sockaddr_un("/tmp/s") assert_raise(ArgumentError) { Socket.unpack_sockaddr_in(sockaddr_un) } end end if defined?(Socket) && Socket.respond_to?(:sockaddr_un) ================================================ FILE: test/socket/test_unix.rb ================================================ begin require "socket" rescue LoadError end require "test/unit" require "tempfile" class TestUNIXSocket < Test::Unit::TestCase def test_fd_passing r1, w = IO.pipe s1, s2 = UNIXSocket.pair begin s1.send_io(nil) rescue NotImplementedError assert_raise(NotImplementedError) { s2.recv_io } rescue TypeError s1.send_io(r1) r2 = s2.recv_io assert_equal(r1.stat.ino, r2.stat.ino) assert_not_equal(r1.fileno, r2.fileno) w.syswrite "a" assert_equal("a", r2.sysread(10)) ensure s1.close s2.close w.close r1.close r2.close if r2 && !r2.closed? end end def bound_unix_socket(klass) tmpfile = Tempfile.new("testrubysock") path = tmpfile.path tmpfile.close(true) yield klass.new(path), path ensure File.unlink path if path && File.socket?(path) end def test_addr bound_unix_socket(UNIXServer) {|serv, path| c = UNIXSocket.new(path) s = serv.accept assert_equal(["AF_UNIX", path], c.peeraddr) assert_equal(["AF_UNIX", ""], c.addr) assert_equal(["AF_UNIX", ""], s.peeraddr) assert_equal(["AF_UNIX", path], s.addr) assert_equal(path, s.path) assert_equal("", c.path) } end def test_noname_path s1, s2 = UNIXSocket.pair assert_equal("", s1.path) assert_equal("", s2.path) ensure s1.close s2.close end def test_noname_addr s1, s2 = UNIXSocket.pair assert_equal(["AF_UNIX", ""], s1.addr) assert_equal(["AF_UNIX", ""], s2.addr) ensure s1.close s2.close end def test_noname_peeraddr s1, s2 = UNIXSocket.pair assert_equal(["AF_UNIX", ""], s1.peeraddr) assert_equal(["AF_UNIX", ""], s2.peeraddr) ensure s1.close s2.close end def test_noname_unpack_sockaddr_un s1, s2 = UNIXSocket.pair n = nil assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s1.getsockname) != "" assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s1.getsockname) != "" assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s2.getsockname) != "" assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s1.getpeername) != "" assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s2.getpeername) != "" ensure s1.close s2.close end def test_noname_recvfrom s1, s2 = UNIXSocket.pair s2.write("a") assert_equal(["a", ["AF_UNIX", ""]], s1.recvfrom(10)) ensure s1.close s2.close end def test_noname_recv_nonblock s1, s2 = UNIXSocket.pair s2.write("a") IO.select [s1] assert_equal("a", s1.recv_nonblock(10)) ensure s1.close s2.close end def test_too_long_path assert_raise(ArgumentError) { Socket.sockaddr_un("a" * 300) } assert_raise(ArgumentError) { UNIXServer.new("a" * 300) } end def test_nul assert_raise(ArgumentError) { Socket.sockaddr_un("a\0b") } assert_raise(ArgumentError) { UNIXServer.new("a\0b") } end def test_dgram_pair s1, s2 = UNIXSocket.pair(Socket::SOCK_DGRAM) assert_raise(Errno::EAGAIN) { s1.recv_nonblock(10) } s2.send("", 0) s2.send("haha", 0) s2.send("", 0) s2.send("", 0) assert_equal("", s1.recv(10)) assert_equal("haha", s1.recv(10)) assert_equal("", s1.recv(10)) assert_equal("", s1.recv(10)) assert_raise(Errno::EAGAIN) { s1.recv_nonblock(10) } ensure s1.close if s1 s2.close if s2 end end if defined?(UNIXSocket) && /cygwin/ !~ RUBY_PLATFORM ================================================ FILE: test/stringio/test_stringio.rb ================================================ require 'test/unit' require 'stringio' dir = File.expand_path(__FILE__) 2.times {dir = File.dirname(dir)} $:.replace([File.join(dir, "ruby")] | $:) require 'ut_eof' class TestStringIO < Test::Unit::TestCase include TestEOF def open_file(content) f = StringIO.new(content) yield f end alias open_file_rw open_file include TestEOF::Seek def test_truncate # [ruby-dev:24190] io = StringIO.new("") io.puts "abc" io.truncate(0) io.puts "def" assert_equal("\0\0\0\0def\n", io.string) end def test_seek_beyond_eof # [ruby-dev:24194] io = StringIO.new n = 100 io.seek(n) io.print "last" assert_equal("\0" * n + "last", io.string) end def test_overwrite # [ruby-core:03836] stringio = StringIO.new responses = ['', 'just another ruby', 'hacker'] responses.each do |resp| stringio.puts(resp) stringio.rewind end assert_equal("hacker\nother ruby\n", stringio.string) end def test_reopen f = StringIO.new("foo\nbar\nbaz\n") assert_equal("foo\n", f.gets) f.reopen("qux\nquux\nquuux\n") assert_equal("qux\n", f.gets) f2 = StringIO.new("") f2.reopen(f) assert_equal("quux\n", f2.gets) ensure f.close unless f.closed? end end ================================================ FILE: test/strscan/test_stringscanner.rb ================================================ # # test/strscan/test_stringscanner.rb # require 'strscan' require 'test/unit' class TestStringScanner < Test::Unit::TestCase def test_s_new s = StringScanner.new('test string') assert_instance_of StringScanner, s assert_equal false, s.eos? assert_equal false, s.tainted? str = 'test string' str.taint s = StringScanner.new(str, false) assert_instance_of StringScanner, s assert_equal false, s.eos? assert_same str, s.string assert_equal true, s.string.tainted? str = 'test string' str.taint s = StringScanner.new(str) assert_equal true, s.string.tainted? end UNINIT_ERROR = ArgumentError def test_s_allocate s = StringScanner.allocate assert_equal '#', s.inspect.sub(/StringScanner_C/, 'StringScanner') assert_raises(UNINIT_ERROR) { s.eos? } assert_raises(UNINIT_ERROR) { s.scan(/a/) } s.string = 'test' assert_equal '#', s.inspect.sub(/StringScanner_C/, 'StringScanner') assert_nothing_raised(UNINIT_ERROR) { s.eos? } assert_equal false, s.eos? end def test_s_mustc assert_nothing_raised(NotImplementedError) { StringScanner.must_C_version } end def test_dup s = StringScanner.new('test string') d = s.dup assert_equal s.inspect, d.inspect assert_equal s.string, d.string assert_equal s.pos, d.pos assert_equal s.matched?, d.matched? assert_equal s.eos?, d.eos? s = StringScanner.new('test string') s.scan(/test/) d = s.dup assert_equal s.inspect, d.inspect assert_equal s.string, d.string assert_equal s.pos, d.pos assert_equal s.matched?, d.matched? assert_equal s.eos?, d.eos? s = StringScanner.new('test string') s.scan(/test/) s.scan(/NOT MATCH/) d = s.dup assert_equal s.inspect, d.inspect assert_equal s.string, d.string assert_equal s.pos, d.pos assert_equal s.matched?, d.matched? assert_equal s.eos?, d.eos? s = StringScanner.new('test string') s.terminate d = s.dup assert_equal s.inspect, d.inspect assert_equal s.string, d.string assert_equal s.pos, d.pos assert_equal s.matched?, d.matched? assert_equal s.eos?, d.eos? end def test_const_Version assert_instance_of String, StringScanner::Version assert_equal true, StringScanner::Version.frozen? end def test_const_Id assert_instance_of String, StringScanner::Id assert_equal true, StringScanner::Id.frozen? end def test_inspect str = 'test string' str.taint s = StringScanner.new(str, false) assert_instance_of String, s.inspect assert_equal s.inspect, s.inspect assert_equal '#', s.inspect.sub(/StringScanner_C/, 'StringScanner') s.get_byte assert_equal '#', s.inspect.sub(/StringScanner_C/, 'StringScanner') assert_equal true, s.inspect.tainted? s = StringScanner.new("\n") assert_equal '#', s.inspect end def test_eos? s = StringScanner.new('test string') assert_equal false, s.eos? assert_equal false, s.eos? s.scan(/\w+/) assert_equal false, s.eos? assert_equal false, s.eos? s.scan(/\s+/) s.scan(/\w+/) assert_equal true, s.eos? assert_equal true, s.eos? s.scan(/\w+/) assert_equal true, s.eos? s = StringScanner.new('test') s.scan(/te/) s.string.replace '' assert_equal true, s.eos? end def test_bol? s = StringScanner.new("a\nbbb\n\ncccc\nddd\r\neee") assert_equal true, s.bol? assert_equal true, s.bol? s.scan(/a/) assert_equal false, s.bol? assert_equal false, s.bol? s.scan(/\n/) assert_equal true, s.bol? s.scan(/b/) assert_equal false, s.bol? s.scan(/b/) assert_equal false, s.bol? s.scan(/b/) assert_equal false, s.bol? s.scan(/\n/) assert_equal true, s.bol? s.unscan assert_equal false, s.bol? s.scan(/\n/) s.scan(/\n/) assert_equal true, s.bol? s.scan(/c+\n/) assert_equal true, s.bol? s.scan(/d+\r\n/) assert_equal true, s.bol? s.scan(/e+/) assert_equal false, s.bol? end def test_string s = StringScanner.new('test') assert_equal 'test', s.string s.string = 'a' assert_equal 'a', s.string s.scan(/a/) s.string = 'b' assert_equal 0, s.pos end def test_pos s = StringScanner.new('test string') assert_equal 0, s.pos s.get_byte assert_equal 1, s.pos s.get_byte assert_equal 2, s.pos s.terminate assert_equal 11, s.pos end def test_concat s = StringScanner.new('a') s.scan(/a/) s.concat 'b' assert_equal false, s.eos? assert_equal 'b', s.scan(/b/) assert_equal true, s.eos? s.concat 'c' assert_equal false, s.eos? assert_equal 'c', s.scan(/c/) assert_equal true, s.eos? end def test_scan s = StringScanner.new('stra strb strc', true) tmp = s.scan(/\w+/) assert_equal 'stra', tmp assert_equal false, tmp.tainted? tmp = s.scan(/\s+/) assert_equal ' ', tmp assert_equal false, tmp.tainted? assert_equal 'strb', s.scan(/\w+/) assert_equal ' ', s.scan(/\s+/) tmp = s.scan(/\w+/) assert_equal 'strc', tmp assert_equal false, tmp.tainted? assert_nil s.scan(/\w+/) assert_nil s.scan(/\w+/) str = 'stra strb strc' str.taint s = StringScanner.new(str, false) tmp = s.scan(/\w+/) assert_equal 'stra', tmp assert_equal true, tmp.tainted? tmp = s.scan(/\s+/) assert_equal ' ', tmp assert_equal true, tmp.tainted? assert_equal 'strb', s.scan(/\w+/) assert_equal ' ', s.scan(/\s+/) tmp = s.scan(/\w+/) assert_equal 'strc', tmp assert_equal true, tmp.tainted? assert_nil s.scan(/\w+/) assert_nil s.scan(/\w+/) s = StringScanner.new('test') s.scan(/te/) # This assumes #string does not duplicate string, # but it is implementation specific issue. # DO NOT RELY ON THIS FEATURE. s.string.replace '' # unspecified: assert_equal 2, s.pos assert_equal nil, s.scan(/test/) # [ruby-bugs:4361] s = StringScanner.new("") assert_equal "", s.scan(//) assert_equal "", s.scan(//) # [ruby-dev:29914] %w( NONE EUC SJIS UTF8 ).each do |kcode| begin $KCODE = kcode assert_equal "a", StringScanner.new("a:b").scan(/[^\x01\:]+/n) assert_equal "a", StringScanner.new("a:b").scan(/[^\x01\:]+/e) assert_equal "a", StringScanner.new("a:b").scan(/[^\x01\:]+/s) assert_equal "a", StringScanner.new("a:b").scan(/[^\x01\:]+/u) ensure $KCODE = 'NONE' end end end def test_skip s = StringScanner.new('stra strb strc', true) assert_equal 4, s.skip(/\w+/) assert_equal 1, s.skip(/\s+/) assert_equal 4, s.skip(/\w+/) assert_equal 1, s.skip(/\s+/) assert_equal 4, s.skip(/\w+/) assert_nil s.skip(/\w+/) assert_nil s.skip(/\s+/) assert_equal true, s.eos? s = StringScanner.new('test') s.scan(/te/) s.string.replace '' assert_equal nil, s.skip(/./) # [ruby-bugs:4361] s = StringScanner.new("") assert_equal 0, s.skip(//) assert_equal 0, s.skip(//) end def test_getch s = StringScanner.new('abcde') assert_equal 'a', s.getch assert_equal 'b', s.getch assert_equal 'c', s.getch assert_equal 'd', s.getch assert_equal 'e', s.getch assert_nil s.getch str = 'abc' str.taint s = StringScanner.new(str) assert_equal true, s.getch.tainted? assert_equal true, s.getch.tainted? assert_equal true, s.getch.tainted? assert_nil s.getch kc_backup = $KCODE begin $KCODE = 'EUC' s = StringScanner.new("\244\242") assert_equal "\244\242", s.getch assert_nil s.getch ensure $KCODE = kc_backup end s = StringScanner.new('test') s.scan(/te/) s.string.replace '' assert_equal nil, s.getch end def test_get_byte s = StringScanner.new('abcde') assert_equal 'a', s.get_byte assert_equal 'b', s.get_byte assert_equal 'c', s.get_byte assert_equal 'd', s.get_byte assert_equal 'e', s.get_byte assert_nil s.get_byte assert_nil s.get_byte str = 'abc' str.taint s = StringScanner.new(str) assert_equal true, s.get_byte.tainted? assert_equal true, s.get_byte.tainted? assert_equal true, s.get_byte.tainted? assert_nil s.get_byte kc_backup = $KCODE begin $KCODE = 'EUC' s = StringScanner.new("\244\242") assert_equal "\244", s.get_byte assert_equal "\242", s.get_byte assert_nil s.get_byte ensure $KCODE = kc_backup end s = StringScanner.new('test') s.scan(/te/) s.string.replace '' assert_equal nil, s.get_byte end def test_matched s = StringScanner.new('stra strb strc') s.scan(/\w+/) assert_equal 'stra', s.matched assert_equal false, s.matched.tainted? s.scan(/\s+/) assert_equal ' ', s.matched s.scan(/\w+/) assert_equal 'strb', s.matched s.scan(/\s+/) assert_equal ' ', s.matched s.scan(/\w+/) assert_equal 'strc', s.matched s.scan(/\w+/) assert_nil s.matched s.getch assert_nil s.matched s = StringScanner.new('stra strb strc') s.getch assert_equal 's', s.matched assert_equal false, s.matched.tainted? s.get_byte assert_equal 't', s.matched assert_equal 't', s.matched assert_equal false, s.matched.tainted? str = 'test' str.taint s = StringScanner.new(str) s.scan(/\w+/) assert_equal true, s.matched.tainted? assert_equal true, s.matched.tainted? end def test_AREF s = StringScanner.new('stra strb strc') s.scan(/\w+/) assert_nil s[-2] assert_equal 'stra', s[-1] assert_equal 'stra', s[0] assert_nil s[1] assert_equal false, s[-1].tainted? assert_equal false, s[0].tainted? s.skip(/\s+/) assert_nil s[-2] assert_equal ' ', s[-1] assert_equal ' ', s[0] assert_nil s[1] s.scan(/(s)t(r)b/) assert_nil s[-100] assert_nil s[-4] assert_equal 'strb', s[-3] assert_equal 's', s[-2] assert_equal 'r', s[-1] assert_equal 'strb', s[0] assert_equal 's', s[1] assert_equal 'r', s[2] assert_nil s[3] assert_nil s[100] s.scan(/\s+/) s.getch assert_nil s[-2] assert_equal 's', s[-1] assert_equal 's', s[0] assert_nil s[1] s.get_byte assert_nil s[-2] assert_equal 't', s[-1] assert_equal 't', s[0] assert_nil s[1] s.scan(/.*/) s.scan(/./) assert_nil s[0] assert_nil s[0] kc_backup = $KCODE begin $KCODE = 'EUC' s = StringScanner.new("\244\242") s.getch assert_equal "\244\242", s[0] ensure $KCODE = kc_backup end str = 'test' str.taint s = StringScanner.new(str) s.scan(/(t)(e)(s)(t)/) assert_equal true, s[0].tainted? assert_equal true, s[1].tainted? assert_equal true, s[2].tainted? assert_equal true, s[3].tainted? assert_equal true, s[4].tainted? end def test_pre_match s = StringScanner.new('a b c d e') s.scan(/\w/) assert_equal '', s.pre_match assert_equal false, s.pre_match.tainted? s.skip(/\s/) assert_equal 'a', s.pre_match assert_equal false, s.pre_match.tainted? s.scan(/\w/) assert_equal 'a ', s.pre_match s.scan_until(/c/) assert_equal 'a b ', s.pre_match s.getch assert_equal 'a b c', s.pre_match s.get_byte assert_equal 'a b c ', s.pre_match s.get_byte assert_equal 'a b c d', s.pre_match s.scan(/never match/) assert_nil s.pre_match str = 'test string' str.taint s = StringScanner.new(str) s.scan(/\w+/) assert_equal true, s.pre_match.tainted? s.scan(/\s+/) assert_equal true, s.pre_match.tainted? s.scan(/\w+/) assert_equal true, s.pre_match.tainted? end def test_post_match s = StringScanner.new('a b c d e') s.scan(/\w/) assert_equal ' b c d e', s.post_match s.skip(/\s/) assert_equal 'b c d e', s.post_match s.scan(/\w/) assert_equal ' c d e', s.post_match s.scan_until(/c/) assert_equal ' d e', s.post_match s.getch assert_equal 'd e', s.post_match s.get_byte assert_equal ' e', s.post_match s.get_byte assert_equal 'e', s.post_match s.scan(/never match/) assert_nil s.post_match s.scan(/./) assert_equal '', s.post_match s.scan(/./) assert_nil s.post_match str = 'test string' str.taint s = StringScanner.new(str) s.scan(/\w+/) assert_equal true, s.post_match.tainted? s.scan(/\s+/) assert_equal true, s.post_match.tainted? s.scan(/\w+/) assert_equal true, s.post_match.tainted? end def test_terminate s = StringScanner.new('ssss') s.getch s.terminate assert_equal true, s.eos? s.terminate assert_equal true, s.eos? end def test_reset s = StringScanner.new('ssss') s.getch s.reset assert_equal 0, s.pos s.scan(/\w+/) s.reset assert_equal 0, s.pos s.reset assert_equal 0, s.pos end def test_matched_size s = StringScanner.new('test string') assert_nil s.matched_size s.scan(/test/) assert_equal 4, s.matched_size assert_equal 4, s.matched_size s.scan(//) assert_equal 0, s.matched_size s.scan(/x/) assert_nil s.matched_size assert_nil s.matched_size s.terminate assert_nil s.matched_size # obsolete s = StringScanner.new('test string') assert_nil s.matchedsize s.scan(/test/) assert_equal 4, s.matched_size s.terminate assert_nil s.matched_size end end ================================================ FILE: test/testunit/collector/test_dir.rb ================================================ require 'test/unit' require 'test/unit/collector/dir' require 'pp' module Test module Unit module Collector class TestDir < TestCase class FileSystem class Directory def initialize(name, fs, parent=self, &block) @name = name @fs = fs @parent = parent @contents = {'.' => self, '..' => parent} instance_eval(&block) if(block) end def file(name, contents) @contents[name] = contents end def dir(name, &block) @contents[name] = self.class.new(name, @fs, self, &block) end def entries @contents.keys end def directory?(name) return true if(name.nil? || name.empty?) return false unless(@contents.include?(name)) @contents[name].kind_of?(self.class) end def file?(name) return false unless(@contents.include?(name)) !directory?(name) end def exist?(name) @contents.include?(name) end def [](name) raise Errno::ENOENT, name unless(@contents.include?(name)) @contents[name] end def path_to(name=nil) if(!name) @parent.path_to(@name) elsif(@parent == self) @fs.join('/', name) else @fs.join(@parent.path_to(@name), name) end end end class ObjectSpace def initialize @objects = [] end def each_object(klass, &block) @objects.find_all{|o| o.kind_of?(klass)}.each(&block) end def <<(object) @objects << object end end attr_reader :object_space def initialize(&block) @root = Directory.new('/', self, &block) @pwd = @root @object_space = ObjectSpace.new @required = [] end def entries(dir) e = find(dir) require_directory(dir) e.entries end def directory?(name) return true if (base = basename(name)) == '/' e = find(dirname(name)) return false unless(e) e.directory?(base) end def find(path) if(/\A\// =~ path) thing = @root else thing = @pwd end path.scan(/[^\/]+/) do |e| break thing = false unless(thing.kind_of?(Directory)) thing = thing[e] end thing end def dirname(name) if (name = name.tr_s('/', '/')) == '/' name else name[%r"\A.+(?=/[^/]+/?\z)|\A/"] || "." end end def basename(name) name[%r"(\A/|[^/]+)/*\z", 1] end def split(name) [dirname(name), basename(name)] end def join(*parts) parts.join('/').gsub(%r{/+}, '/') end def file?(name) e = find(dirname(name)) return false unless(e) e.file?(basename(name)) end def pwd @pwd.path_to end def chdir(to) e = find(to) require_directory(to) @pwd = e end def expand_path(path, base = nil) until /\A\// =~ path base ||= pwd path = join(base, path) base = nil end path.gsub!(%r"(?:/\.)+(?=/)", '') nil while path.sub!(%r"/(?!\.\./)[^/]+/\.\.(?=/)", '') path.sub!(%r"\A(?:/\.\.)+(?=/)", '') path.sub!(%r"(?:\A(/)|/)\.\.?\z", '\1') path end def require_directory(path) raise Errno::ENOTDIR, path unless(directory?(path)) end def require(file) return false if(@required.include?(file)) begin e = find(file) rescue Errno::ENOENT => e if(/\.rb\Z/ =~ file) raise LoadError, file end e = find(file + '.rb') end @required << file @object_space << e true rescue Errno::ENOENT raise LoadError, file end end def test_dir inner_dir = nil dirs = FileSystem::Directory.new('/', nil) do file 'a', nil inner_dir = dir 'b' end assert_equal(inner_dir, dirs['b']) end def test_fs fs = FileSystem.new do file 'a', nil dir 'b' end assert_equal(['.', '..', 'a', 'b'].sort, fs.entries('/').sort) assert(fs.directory?('/')) assert(!fs.directory?('/a')) assert(!fs.directory?('/bogus')) assert(fs.file?('/a')) assert(!fs.file?('/')) assert(!fs.file?('/bogus')) assert(fs.directory?('/b')) assert(fs.file?('a')) assert(fs.directory?('b')) end def test_fs_sub fs = FileSystem.new do dir 'a' do file 'b', nil dir 'c' do file 'd', nil end end end assert(fs.file?('/a/b')) assert(!fs.file?('/a/b/c/d')) assert(fs.file?('/a/c/d')) end def test_fs_pwd fs = FileSystem.new do file 'a', nil dir 'b' do file 'c', nil dir 'd' do file 'e', nil end end end assert_equal('/', fs.pwd) assert_raises(Errno::ENOENT) do fs.chdir('bogus') end assert_raises(Errno::ENOTDIR) do fs.chdir('a') end fs.chdir('b') assert_equal('/b', fs.pwd) fs.chdir('d') assert_equal('/b/d', fs.pwd) fs.chdir('..') assert_equal('/b', fs.pwd) fs.chdir('..') assert_equal('/', fs.pwd) end def test_fs_entries fs = FileSystem.new do file 'a', nil dir 'b' do file 'c', nil file 'd', nil end file 'e', nil dir 'f' do file 'g', nil dir 'h' do file 'i', nil end end end assert_equal(['.', '..', 'a', 'b', 'e', 'f'], fs.entries('/').sort) assert_equal(['.', '..', 'a', 'b', 'e', 'f'], fs.entries('.').sort) assert_equal(['.', '..', 'a', 'b', 'e', 'f'], fs.entries('b/..').sort) assert_equal(['.', '..', 'c', 'd'], fs.entries('b').sort) assert_raises(Errno::ENOENT) do fs.entries('z') end assert_raises(Errno::ENOTDIR) do fs.entries('a') end fs.chdir('f') assert_equal(['.', '..', 'i'], fs.entries('h').sort) end class TestClass1 end class TestClass2 end def test_fs_require fs = FileSystem.new do file 'test_class1.rb', TestClass1 dir 'dir' do file 'test_class2.rb', TestClass2 end end c = [] fs.object_space.each_object(Class) do |o| c << o end assert_equal([], c) assert_raises(LoadError) do fs.require('bogus') end assert(fs.require('test_class1.rb')) assert(!fs.require('test_class1.rb')) c = [] fs.object_space.each_object(Class) do |o| c << o end assert_equal([TestClass1], c) fs.require('dir/test_class2') c = [] fs.object_space.each_object(Class) do |o| c << o end assert_equal([TestClass1, TestClass2], c) c = [] fs.object_space.each_object(Time) do |o| c << o end assert_equal([], c) end def setup @t1 = t1 = create_test(1) @t2 = t2 = create_test(2) @t3 = t3 = create_test(3) @t4 = t4 = create_test(4) @t5 = t5 = create_test(5) @t6 = t6 = create_test(6) fs = FileSystem.new do file 'test_1.rb', t1 file 'test_2.rb', t2 dir 'd1' do file 'test_3.rb', t3 end file 't4.rb', t4 dir 'd2' do file 'test_5', t5 file 'test_6.rb', Time end file 't6.rb', t6 end fs.require('t6') @c = Dir.new(fs, fs, fs.object_space, fs) end def create_test(name) t = Class.new(TestCase) t.class_eval <<-EOC def self.name "T\#{#{name}}" end def test_#{name}a end def test_#{name}b end EOC t end def test_simple_collect expected = TestSuite.new('d1') expected << (@t3.suite) assert_equal(expected, @c.collect('d1')) end def test_multilevel_collect expected = TestSuite.new('.') expected << @t1.suite << @t2.suite expected << (TestSuite.new('d1') << @t3.suite) assert_equal(expected, @c.collect) end def test_collect_file expected = TestSuite.new('test_1.rb') expected << @t1.suite assert_equal(expected, @c.collect('test_1.rb')) expected = TestSuite.new('t4.rb') expected << @t4.suite assert_equal(expected, @c.collect('t4.rb')) end def test_nil_pattern expected = TestSuite.new('d2') expected << @t5.suite @c.pattern.clear assert_equal(expected, @c.collect('d2')) end def test_filtering expected = TestSuite.new('.') expected << @t1.suite @c.filter = proc{|t| t.method_name == 'test_1a' || t.method_name == 'test_1b'} assert_equal(expected, @c.collect) end def test_collect_multi expected = TestSuite.new('[d1, d2]') expected << (TestSuite.new('d1') << @t3.suite) expected << (TestSuite.new('d2') << @t5.suite) @c.pattern.replace([/\btest_/]) assert_equal(expected, @c.collect('d1', 'd2')) end end end end end ================================================ FILE: test/testunit/collector/test_objectspace.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' require 'test/unit/collector/objectspace' module Test module Unit module Collector class TC_ObjectSpace < TestCase def setup @tc1 = Class.new(TestCase) do def self.name "tc_1" end def test_1 end def test_2 end end @tc2 = Class.new(TestCase) do def self.name "tc_2" end def test_0 end end @no_tc = Class.new do def test_4 end end @object_space = {Class => [@tc1, @tc2, @no_tc], String => ['']} def @object_space.each_object(type) self[type].each{|item| yield(item) } end @c = ObjectSpace.new(@object_space) end def full_suite(name=ObjectSpace::NAME) expected = TestSuite.new(name) expected << (TestSuite.new(@tc1.name) << @tc1.new('test_1') << @tc1.new('test_2')) expected << (TestSuite.new(@tc2.name) << @tc2.new('test_0')) end def empty_suite TestSuite.new(ObjectSpace::NAME) end def test_basic_collection assert_equal(full_suite("name"), @c.collect("name")) @c.filter = [] assert_equal(full_suite("name"), @c.collect("name")) end def test_filtered_collection @c.filter = proc{false} assert_equal(empty_suite, @c.collect) @c.filter = proc{true} assert_equal(full_suite, @c.collect) @c.filter = proc{nil} assert_equal(full_suite, @c.collect) @c.filter = [proc{false}, proc{true}] assert_equal(empty_suite, @c.collect) @c.filter = [proc{true}, proc{false}] assert_equal(full_suite, @c.collect) @c.filter = [proc{nil}, proc{false}] assert_equal(empty_suite, @c.collect) @c.filter = [proc{nil}, proc{true}] assert_equal(full_suite, @c.collect) expected = TestSuite.new(ObjectSpace::NAME) expected << (TestSuite.new(@tc1.name) << @tc1.new('test_1')) expected << (TestSuite.new(@tc2.name) << @tc2.new('test_0')) @c.filter = proc{|test| ['test_1', 'test_0'].include?(test.method_name)} assert_equal(expected, @c.collect) expected = TestSuite.new(ObjectSpace::NAME) expected << (TestSuite.new(@tc1.name) << @tc1.new('test_1')) expected << (TestSuite.new(@tc2.name) << @tc2.new('test_0')) @c.filter = [proc{|t| t.method_name == 'test_1' ? true : nil}, proc{|t| t.method_name == 'test_0' ? true : nil}, proc{false}] assert_equal(expected, @c.collect) end end end end end ================================================ FILE: test/testunit/runit/test_assert.rb ================================================ # Author:: Masaki Suketa. # Adapted by:: Nathaniel Talbott. # Copyright:: Copyright (c) Masaki Suketa. All rights reserved. # Copyright:: Copyright (c) 2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'rubyunit' module RUNIT class TargetAssert include RUNIT::Assert end class TestAssert < RUNIT::TestCase def setup @assert = TargetAssert.new @e = nil end def test_assert sub_test_assert_pass(true) sub_test_assert_pass(TRUE) sub_test_assert_failure(false) sub_test_assert_failure(FALSE) sub_test_assert_failure(nil) sub_test_assert_pass("") sub_test_assert_pass("ok") sub_test_assert_pass(0) sub_test_assert_pass(1) end def test_assert_with_2_argument assert_no_exception { assert(true, "3") } assert_no_exception { assert(true) } end def test_assert_equal_float_0_1 assert_proc = Proc.new { @assert.assert_equal_float(1.4, 1.35, 0.1) } sub_assert_pass(assert_proc) end def test_assert_equal_float_0_5 assert_proc = Proc.new { @assert.assert_equal_float(1.4, 1.34, 0.5) } sub_assert_pass(assert_proc) end def test_assert_equal_float_0 assert_proc = Proc.new { @assert.assert_equal_float(1.4, 1.4, 0) } sub_assert_pass(assert_proc) end def test_assert_equal_float_0_raise assert_proc = Proc.new { @assert.assert_equal_float(1.4, 1.34, 0) } sub_assert_raise_fail(assert_proc) end def test_assert_equal_float_0_01 assert_proc = Proc.new { @assert.assert_equal_float(1.4, 1.35, 0.01) } sub_assert_raise_fail(assert_proc) end def test_assert_equal_float_0_001 assert_proc = Proc.new { @assert.assert_equal_float(Math.sqrt(2), 1.414, 0.001) } sub_assert_pass(assert_proc) end def test_assert_equal_float_minus_1_0 assert_proc = Proc.new { @assert.assert_equal_float(1.4, 1.35, -1.0) } sub_assert_raise_fail(assert_proc) end def test_assert_fail except = nil begin @assert.assert_fail("failure") rescue Exception except = $! end assert_not_nil(except) end def sub_test_assert_pass(obj) assert_proc = Proc.new { @assert.assert(obj) } sub_assert_pass(assert_proc) end def sub_test_assert_failure(obj) assert_proc = Proc.new { @assert.assert(obj) } sub_assert_raise_fail(assert_proc) end def test_assert_equal assert_proc = Proc.new { @assert.assert_equal(2, 2) } sub_assert_pass(assert_proc) assert_proc = Proc.new { @assert.assert_equal(2, 3) } sub_assert_raise_fail(assert_proc) end def test_assert_nil obj = nil assert_proc = Proc.new { @assert.assert_nil(obj) } sub_assert_pass(assert_proc) obj = 'string' sub_assert_raise_fail(assert_proc) end def test_assert_not_nil obj = 'string' assert_proc = Proc.new { @assert.assert_not_nil(obj) } sub_assert_pass(assert_proc) obj = nil sub_assert_raise_fail(assert_proc) end def test_assert_operator assert_proc = Proc.new { @assert.assert_operator(2, :<, 3) } sub_assert_pass(assert_proc) assert_proc = Proc.new { @assert.assert_operator(2, :>, 3) } sub_assert_raise_fail(assert_proc) end def test_assert_respond_to sub_test_assert_respond_to('string', 'sub', 'foo') sub_test_assert_respond_to('string', :sub, :foo) end def sub_test_assert_respond_to(obj, msg, dummy_msg) assert_proc = Proc.new { @assert.assert_respond_to(msg, obj) } sub_assert_pass(assert_proc) assert_proc = Proc.new { @assert.assert_respond_to(dummy_msg, obj) } sub_assert_raise_fail(assert_proc) end def test_assert_send assert_proc = Proc.new { ary = [] @assert.assert_send ary, :empty? } sub_assert_pass(assert_proc) assert_proc = Proc.new { ary = [2,3] @assert.assert_send ary, :empty? } sub_assert_raise_fail(assert_proc) assert_proc = Proc.new { str = "abc" @assert.assert_send str, :sub!, "z", "y" } sub_assert_raise_fail(assert_proc) end def test_assert_kind_of assert_proc = Proc.new { @assert.assert_kind_of(String, "string") } sub_assert_pass(assert_proc) assert_proc = Proc.new { @assert.assert_kind_of(Regexp, "string") } sub_assert_raise_fail(assert_proc) end def test_assert_instance_of assert_proc = Proc.new { @assert.assert_instance_of(String, "string") } sub_assert_pass(assert_proc) assert_proc = Proc.new { @assert.assert_instance_of(Object, "string") } sub_assert_raise_fail(assert_proc) end def test_assert_match assert_proc = Proc.new{ @assert.assert_match('foostring', /foo/) } sub_assert_pass(assert_proc) assert_proc = Proc.new { @assert.assert_match('barstring', /foo/) } sub_assert_raise_fail(assert_proc) match = @assert.assert_match('foostring', /foo/) assert_instance_of(MatchData, match) assert_equal('foo', match[0]) end def test_assert_matches assert_proc = Proc.new{ @assert.assert_matches('foostring', /foo/) } sub_assert_pass(assert_proc) assert_proc = Proc.new { @assert.assert_matches('barstring', /foo/) } sub_assert_raise_fail(assert_proc) end def test_assert_not_match assert_proc = Proc.new{ @assert.assert_not_match('barstring', /foo/) } sub_assert_pass(assert_proc) assert_proc = Proc.new { @assert.assert_not_match('foostring', /foo/) } sub_assert_raise_fail(assert_proc) assert_proc = Proc.new { @assert.assert_not_match('foobarbaz', /ba.+/) } sub_assert_raise_fail(assert_proc) end def test_assert_same flag = false e = "foo" a = e assert_proc = Proc.new {@assert.assert_same(e, a)} sub_assert_pass(assert_proc) a = "foo" sub_assert_raise_fail(assert_proc) end def test_assert_exception assert_proc = Proc.new{ @assert.assert_exception(IOError) { raise IOError } } sub_assert_pass(assert_proc) assert_proc = Proc.new{ @assert.assert_exception(StandardError) { raise IOError } } sub_assert_raise_fail(assert_proc) assert_proc = Proc.new{ @assert.assert_exception(IOError, "Exception") { raise StandardError } } sub_assert_raise_fail(assert_proc) assert_proc = Proc.new { @assert.assert_exception(StandardError) { "No Exception raised in this block" } } sub_assert_raise_fail(assert_proc) assert_proc = Proc.new { @assert.assert_exception(StandardError) { exit(33) } } sub_assert_raise_fail(assert_proc) t = @assert.assert_exception(IOError) { raise IOError } assert_instance_of(IOError, t) t = @assert.assert_exception(NameError) { non_existent_method } assert_instance_of(NameError, t) t = @assert.assert_exception(SystemExit) { exit(33) } assert_instance_of(SystemExit, t) end def test_assert_no_exception assert_proc = Proc.new{ @assert.assert_no_exception(IOError, ArgumentError) { "No Exception raised in this block" } } sub_assert_pass(assert_proc) assert_proc = Proc.new{ @assert.assert_no_exception(IOError, ArgumentError) { raise StandardError, "Standard Error raised" } } sub_assert_raise_error(assert_proc) assert_proc = Proc.new{ @assert.assert_no_exception(IOError, ArgumentError) { raise ArgumentError, "Bad Argument" } } sub_assert_raise_fail(assert_proc) assert_proc = Proc.new{ @assert.assert_no_exception { raise ArgumentError, "Bad Argument" } } sub_assert_raise_fail(assert_proc) assert_proc = Proc.new{ @assert.assert_no_exception { raise NameError, "Bad Name" } } sub_assert_raise_fail(assert_proc) assert_proc = Proc.new { @assert.assert_no_exception { raise NoMemoryError } } sub_assert_raise_fail(assert_proc) end def sub_assert_pass(p) flag = false err = nil begin p.call flag = true rescue err = $! flag = false end assert(flag, err.to_s) end def sub_assert_raise_fail(p) flag = false err = nil begin p.call flag = false rescue RUNIT::AssertionFailedError flag = true err = $! rescue Exception flag = false err = $! end assert(flag, err.to_s) end def sub_assert_raise_error(p) flag = false err = nil begin p.call flag = false rescue RUNIT::AssertionFailedError flag = false err = $! rescue Exception flag = true err = $! end assert(flag, err.to_s) end end end ================================================ FILE: test/testunit/runit/test_testcase.rb ================================================ # Author:: Masaki Suketa. # Adapted by:: Nathaniel Talbott. # Copyright:: Copyright (c) Masaki Suketa. All rights reserved. # Copyright:: Copyright (c) 2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'rubyunit' module RUNIT class DummyError < StandardError end class TestTestCase < RUNIT::TestCase def setup @dummy_testcase = Class.new(RUNIT::TestCase) do def self.name "DummyTestCase" end attr_reader :status, :dummy_called, :dummy2_called def initialize(*arg) super(*arg) @status = 0 @dummy_called = false @dummy2_called = false end def setup @status = 1 if @status == 0 end def test_dummy @status = 2 if @status == 1 @dummy_called = true end def test_dummy2 @status = 2 if @status == 1 @dummy2_called = true raise DummyError end def teardown @status = 3 if @status == 2 end end @test1 = @dummy_testcase.new('test_dummy') @test2 = @dummy_testcase.new('test_dummy2', 'TestCase') end def test_name assert_equal('DummyTestCase#test_dummy', @test1.name) # The second parameter to #initialize is ignored in emulation assert_equal('DummyTestCase#test_dummy2', @test2.name) end def test_run result = RUNIT::TestResult.new @test1.run(result) assert_equal(1, result.run_count) end def test_s_suite suite = @dummy_testcase.suite assert_instance_of(RUNIT::TestSuite, suite) assert_equal(2, suite.count_test_cases) end def test_teardown_err suite = Class.new(RUNIT::TestCase) do def test_foo assert(false) end def test_bar assert(true) end def teardown raise StandardError end end.suite result = RUNIT::TestResult.new suite.run(result) assert_equal(2, result.error_size) assert_equal(1, result.failure_size) end end end ================================================ FILE: test/testunit/runit/test_testresult.rb ================================================ # Author:: Masaki Suketa. # Adapted by:: Nathaniel Talbott. # Copyright:: Copyright (c) Masaki Suketa. All rights reserved. # Copyright:: Copyright (c) 2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'rubyunit' module RUNIT class TestTestResult < RUNIT::TestCase def setup @result = RUNIT::TestResult.new @normal_suite = Class::new(RUNIT::TestCase) do def test_1 assert(true) assert(true) end end.suite @failure_suite = Class::new(RUNIT::TestCase) do def test_1 assert(true) assert(false) end end.suite @error_suite = Class::new(RUNIT::TestCase) do def setup raise ScriptError end def test_1 assert(true) end end.suite @multi_failure_suite = Class::new(RUNIT::TestCase) do def test1 assert(false) end def test2 assert(false) end def test3 assert(false) end end.suite @with_error_suite = Class::new(RUNIT::TestCase) do def test1 raise StandardError end end.suite @multi_error_suite = Class::new(RUNIT::TestCase) do def test1 raise StandardError end def test2 raise StandardError end def test3 raise StandardError end end.suite @multi_suite = Class::new(RUNIT::TestCase) do def test_1 assert(true) assert(true) end def test_2 assert(true) end def test_3 assert(true) assert(false) assert(true) end end.suite end def test_error_size @normal_suite.run(@result) assert_equal(0, @result.error_size) @with_error_suite.run(@result) assert_equal(1, @result.error_size) @multi_error_suite.run(@result) assert_equal(4, @result.error_size) end def test_errors @normal_suite.run(@result) assert_equal(0, @result.errors.size) end def test_failure_size @normal_suite.run(@result) assert_equal(0, @result.failure_size) @failure_suite.run(@result) assert_equal(1, @result.failure_size) @multi_failure_suite.run(@result) assert_equal(4, @result.failure_size) end def test_failures @normal_suite.run(@result) assert_equal(0, @result.failures.size) @failure_suite.run(@result) assert_equal(1, @result.failures.size) @multi_failure_suite.run(@result) assert_equal(4, @result.failures.size) end def test_run_no_exception assert_no_exception { @error_suite.run(@result) } end def test_run_asserts @normal_suite.run(@result) assert_equal(2, @result.run_asserts) end def test_run_asserts2 @failure_suite.run(@result) assert_equal(2, @result.run_asserts) end def test_run_tests assert_equal(0, @result.run_tests) @normal_suite.run(@result) assert_equal(1, @result.run_tests) @multi_suite.run(@result) assert_equal(4, @result.run_tests) end def test_succeed? @normal_suite.run(@result) assert(@result.succeed?) end end end ================================================ FILE: test/testunit/runit/test_testsuite.rb ================================================ # Author:: Masaki Suketa. # Adapted by:: Nathaniel Talbott. # Copyright:: Copyright (c) Masaki Suketa. All rights reserved. # Copyright:: Copyright (c) 2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'rubyunit' module RUNIT class TestTestSuite < RUNIT::TestCase def setup @testsuite = RUNIT::TestSuite.new @dummy_test = Class.new(RUNIT::TestCase) do def test_foo end def test_bar end end @dummy_empty_test = Class.new(RUNIT::TestCase){} end def test_count_test_cases assert_equal(0, @testsuite.count_test_cases) @testsuite.add(@dummy_empty_test.suite) assert_equal(0, @testsuite.count_test_cases) @testsuite.add(@dummy_test.suite) assert_equal(2, @testsuite.count_test_cases) @testsuite.add(@dummy_test.suite) assert_equal(4, @testsuite.count_test_cases) dummytest_foo = @dummy_test.new('test_foo') @testsuite.add(dummytest_foo) assert_equal(5, @testsuite.count_test_cases) end def test_add @testsuite.add(@dummy_empty_test.suite) assert_equal(0, @testsuite.size) assert_equal(0, @testsuite.count_test_cases) @testsuite.add(@dummy_test.suite) assert_equal(2, @testsuite.size) assert_equal(2, @testsuite.count_test_cases) end end end ================================================ FILE: test/testunit/test_assertions.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' module Test module Unit class TC_Assertions < TestCase def check(value, message="") add_assertion if (!value) raise AssertionFailedError.new(message) end end def check_assertions(expect_fail, expected_message="", return_value_expected=false) @actual_assertion_count = 0 failed = true actual_message = nil @catch_assertions = true return_value = nil begin return_value = yield failed = false rescue AssertionFailedError => error actual_message = error.message end @catch_assertions = false check(expect_fail == failed, (expect_fail ? "Should have failed, but didn't" : "Should not have failed, but did with message\n<#{actual_message}>")) check(1 == @actual_assertion_count, "Should have made one assertion but made <#{@actual_assertion_count}>") if (expect_fail) case expected_message when String check(actual_message == expected_message, "Should have the correct message.\n<#{expected_message.inspect}> expected but was\n<#{actual_message.inspect}>") when Regexp check(actual_message =~ expected_message, "The message should match correctly.\n expected to match\n<#{actual_message.inspect}>") else check(false, "Incorrect expected message type in assert_nothing_failed") end else if (!return_value_expected) check(return_value.nil?, "Should not return a value but returned <#{return_value}>") else check(!return_value.nil?, "Should return a value") end end return return_value end def check_nothing_fails(return_value_expected=false, &proc) check_assertions(false, "", return_value_expected, &proc) end def check_fails(expected_message="", &proc) check_assertions(true, expected_message, &proc) end def test_assert_block check_nothing_fails { assert_block {true} } check_nothing_fails { assert_block("successful assert_block") {true} } check_nothing_fails { assert_block("successful assert_block") {true} } check_fails("assert_block failed.") { assert_block {false} } check_fails("failed assert_block") { assert_block("failed assert_block") {false} } end def test_assert check_nothing_fails{assert("a")} check_nothing_fails{assert(true)} check_nothing_fails{assert(true, "successful assert")} check_fails(" is not true."){assert(nil)} check_fails(" is not true."){assert(false)} check_fails("failed assert.\n is not true."){assert(false, "failed assert")} end def test_assert_equal check_nothing_fails { assert_equal("string1", "string1") } check_nothing_fails { assert_equal( "string1", "string1", "successful assert_equal") } check_nothing_fails { assert_equal("string1", "string1", "successful assert_equal") } check_fails(%Q{<"string1"> expected but was\n<"string2">.}) { assert_equal("string1", "string2") } check_fails(%Q{failed assert_equal.\n<"string1"> expected but was\n<"string2">.}) { assert_equal("string1", "string2", "failed assert_equal") } check_fails(%Q{<"1"> expected but was\n<1>.}) do assert_equal("1", 1) end end def test_assert_raise return_value = nil check_nothing_fails(true) { return_value = assert_raise(RuntimeError) { raise "Error" } } check(return_value.kind_of?(Exception), "Should have returned the exception from a successful assert_raise") check(return_value.message == "Error", "Should have returned the correct exception from a successful assert_raise") check_nothing_fails(true) { assert_raise(ArgumentError, "successful assert_raise") { raise ArgumentError.new("Error") } } check_nothing_fails(true) { assert_raise(RuntimeError) { raise "Error" } } check_nothing_fails(true) { assert_raise(RuntimeError, "successful assert_raise") { raise "Error" } } check_fails(" exception expected but none was thrown.") { assert_raise(RuntimeError) { 1 + 1 } } check_fails(%r{\Afailed assert_raise.\n exception expected but was\nClass: \nMessage: <"Error">\n---Backtrace---\n.+\n---------------\Z}m) { assert_raise(ArgumentError, "failed assert_raise") { raise "Error" } } check_fails("Should expect a class of exception, Object.\n is not true.") { assert_nothing_raised(Object) { 1 + 1 } } exceptions = [ArgumentError, TypeError] modules = [Math, Comparable] rescues = exceptions + modules exceptions.each do |exc| check_nothing_fails(true) { return_value = assert_raise(*rescues) { raise exc, "Error" } } check(return_value.instance_of?(exc), "Should have returned #{exc} but was #{return_value.class}") check(return_value.message == "Error", "Should have returned the correct exception from a successful assert_raise") end modules.each do |mod| check_nothing_fails(true) { return_value = assert_raise(*rescues) { raise Exception.new("Error").extend(mod) } } check(mod === return_value, "Should have returned #{mod}") check(return_value.message == "Error", "Should have returned the correct exception from a successful assert_raise") end check_fails("<[ArgumentError, TypeError, Math, Comparable]> exception expected but none was thrown.") { assert_raise(*rescues) { 1 + 1 } } check_fails(%r{\Afailed assert_raise. <\[ArgumentError, TypeError\]> exception expected but was Class: Message: <"Error"> ---Backtrace--- .+ ---------------\Z}m) { assert_raise(ArgumentError, TypeError, "failed assert_raise") { raise "Error" } } end def test_assert_instance_of check_nothing_fails { assert_instance_of(String, "string") } check_nothing_fails { assert_instance_of(String, "string", "successful assert_instance_of") } check_nothing_fails { assert_instance_of(String, "string", "successful assert_instance_of") } check_fails(%Q{<"string"> expected to be an instance of\n but was\n.}) { assert_instance_of(Hash, "string") } check_fails(%Q{failed assert_instance_of.\n<"string"> expected to be an instance of\n but was\n.}) { assert_instance_of(Hash, "string", "failed assert_instance_of") } end def test_assert_nil check_nothing_fails { assert_nil(nil) } check_nothing_fails { assert_nil(nil, "successful assert_nil") } check_nothing_fails { assert_nil(nil, "successful assert_nil") } check_fails(%Q{ expected but was\n<"string">.}) { assert_nil("string") } check_fails(%Q{failed assert_nil.\n expected but was\n<"string">.}) { assert_nil("string", "failed assert_nil") } end def test_assert_not_nil check_nothing_fails{assert_not_nil(false)} check_nothing_fails{assert_not_nil(false, "message")} check_fails(" expected to not be nil."){assert_not_nil(nil)} check_fails("message.\n expected to not be nil.") {assert_not_nil(nil, "message")} end def test_assert_kind_of check_nothing_fails { assert_kind_of(Module, Array) } check_nothing_fails { assert_kind_of(Object, "string", "successful assert_kind_of") } check_nothing_fails { assert_kind_of(Object, "string", "successful assert_kind_of") } check_nothing_fails { assert_kind_of(Comparable, 1) } check_fails(%Q{<"string">\nexpected to be kind_of?\n but was\n.}) { assert_kind_of(Class, "string") } check_fails(%Q{failed assert_kind_of.\n<"string">\nexpected to be kind_of?\n but was\n.}) { assert_kind_of(Class, "string", "failed assert_kind_of") } end def test_assert_match check_nothing_fails { assert_match(/strin./, "string") } check_nothing_fails { assert_match("strin", "string") } check_nothing_fails { assert_match(/strin./, "string", "successful assert_match") } check_nothing_fails { assert_match(/strin./, "string", "successful assert_match") } check_fails(%Q{<"string"> expected to be =~\n.}) { assert_match(/slin./, "string") } check_fails(%Q{<"string"> expected to be =~\n.}) { assert_match("strin.", "string") } check_fails(%Q{failed assert_match.\n<"string"> expected to be =~\n.}) { assert_match(/slin./, "string", "failed assert_match") } end def test_assert_same thing = "thing" check_nothing_fails { assert_same(thing, thing) } check_nothing_fails { assert_same(thing, thing, "successful assert_same") } check_nothing_fails { assert_same(thing, thing, "successful assert_same") } thing2 = "thing" check_fails(%Q{<"thing">\nwith id <#{thing.__id__}> expected to be equal? to\n<"thing">\nwith id <#{thing2.__id__}>.}) { assert_same(thing, thing2) } check_fails(%Q{failed assert_same.\n<"thing">\nwith id <#{thing.__id__}> expected to be equal? to\n<"thing">\nwith id <#{thing2.__id__}>.}) { assert_same(thing, thing2, "failed assert_same") } end def test_assert_nothing_raised check_nothing_fails { assert_nothing_raised { 1 + 1 } } check_nothing_fails { assert_nothing_raised("successful assert_nothing_raised") { 1 + 1 } } check_nothing_fails { assert_nothing_raised("successful assert_nothing_raised") { 1 + 1 } } check_nothing_fails { begin assert_nothing_raised(RuntimeError, StandardError, Comparable, "successful assert_nothing_raised") { raise ZeroDivisionError.new("ArgumentError") } rescue ZeroDivisionError end } check_fails("Should expect a class of exception, Object.\n is not true.") { assert_nothing_raised(Object) { 1 + 1 } } check_fails(%r{\AException raised:\nClass: \nMessage: <"Error">\n---Backtrace---\n.+\n---------------\Z}m) { assert_nothing_raised { raise "Error" } } check_fails(%r{\Afailed assert_nothing_raised\.\nException raised:\nClass: \nMessage: <"Error">\n---Backtrace---\n.+\n---------------\Z}m) { assert_nothing_raised("failed assert_nothing_raised") { raise "Error" } } check_fails(%r{\AException raised:\nClass: \nMessage: <"Error">\n---Backtrace---\n.+\n---------------\Z}m) { assert_nothing_raised(StandardError, RuntimeError) { raise "Error" } } check_fails("Failure.") do assert_nothing_raised do flunk("Failure") end end end def test_flunk check_fails("Flunked.") { flunk } check_fails("flunk message.") { flunk("flunk message") } end def test_assert_not_same thing = "thing" thing2 = "thing" check_nothing_fails { assert_not_same(thing, thing2) } check_nothing_fails { assert_not_same(thing, thing2, "message") } check_fails(%Q{<"thing">\nwith id <#{thing.__id__}> expected to not be equal? to\n<"thing">\nwith id <#{thing.__id__}>.}) { assert_not_same(thing, thing) } check_fails(%Q{message.\n<"thing">\nwith id <#{thing.__id__}> expected to not be equal? to\n<"thing">\nwith id <#{thing.__id__}>.}) { assert_not_same(thing, thing, "message") } end def test_assert_not_equal check_nothing_fails { assert_not_equal("string1", "string2") } check_nothing_fails { assert_not_equal("string1", "string2", "message") } check_fails(%Q{<"string"> expected to be != to\n<"string">.}) { assert_not_equal("string", "string") } check_fails(%Q{message.\n<"string"> expected to be != to\n<"string">.}) { assert_not_equal("string", "string", "message") } end def test_assert_no_match check_nothing_fails{assert_no_match(/sling/, "string")} check_nothing_fails{assert_no_match(/sling/, "string", "message")} check_fails(%Q{The first argument to assert_no_match should be a Regexp.\n<"asdf"> expected to be an instance of\n but was\n.}) do assert_no_match("asdf", "asdf") end check_fails(%Q{ expected to not match\n<"string">.}) do assert_no_match(/string/, "string") end check_fails(%Q{message.\n expected to not match\n<"string">.}) do assert_no_match(/string/, "string", "message") end end def test_assert_throws check_nothing_fails { assert_throws(:thing, "message") { throw :thing } } check_fails("message.\n<:thing> expected to be thrown but\n<:thing2> was thrown.") { assert_throws(:thing, "message") { throw :thing2 } } check_fails("message.\n<:thing> should have been thrown.") { assert_throws(:thing, "message") { 1 + 1 } } end def test_assert_nothing_thrown check_nothing_fails { assert_nothing_thrown("message") { 1 + 1 } } check_fails("message.\n<:thing> was thrown when nothing was expected.") { assert_nothing_thrown("message") { throw :thing } } end def test_assert_operator check_nothing_fails { assert_operator("thing", :==, "thing", "message") } check_fails(%Q{<0.15>\ngiven as the operator for #assert_operator must be a Symbol or #respond_to?(:to_str).}) do assert_operator("thing", 0.15, "thing") end check_fails(%Q{message.\n<"thing1"> expected to be\n==\n<"thing2">.}) { assert_operator("thing1", :==, "thing2", "message") } end def test_assert_respond_to check_nothing_fails { assert_respond_to("thing", :to_s, "message") } check_nothing_fails { assert_respond_to("thing", "to_s", "message") } check_fails("<0.15>\ngiven as the method name argument to #assert_respond_to must be a Symbol or #respond_to?(:to_str).") { assert_respond_to("thing", 0.15) } check_fails("message.\n<:symbol>\nof type \nexpected to respond_to?<:non_existent>.") { assert_respond_to(:symbol, :non_existent, "message") } end def test_assert_in_delta check_nothing_fails { assert_in_delta(1.4, 1.4, 0) } check_nothing_fails { assert_in_delta(0.5, 0.4, 0.1, "message") } check_nothing_fails { float_thing = Object.new def float_thing.to_f 0.2 end assert_in_delta(0.1, float_thing, 0.1) } check_fails("message.\n<0.5> and\n<0.4> expected to be within\n<0.05> of each other.") { assert_in_delta(0.5, 0.4, 0.05, "message") } check_fails(%r{The arguments must respond to to_f; the first float did not\.\n<.+>\nof type \nexpected to respond_to\?<:to_f>.}) { assert_in_delta(Object.new, 0.4, 0.1) } check_fails("The delta should not be negative.\n<-0.1> expected to be\n>=\n<0.0>.") { assert_in_delta(0.5, 0.4, -0.1, "message") } end def test_assert_send object = Object.new class << object private def return_argument(argument, bogus) return argument end end check_nothing_fails { assert_send([object, :return_argument, true, "bogus"], "message") } check_fails(%r{\Amessage\.\n<.+> expected to respond to\n with a true value.\Z}) { assert_send([object, :return_argument, false, "bogus"], "message") } end def test_condition_invariant object = Object.new def object.inspect @changed = true end def object.==(other) @changed ||= false return (!@changed) end check_nothing_fails { assert_equal(object, object, "message") } end def add_failure(message, location=caller) if (!@catch_assertions) super end end def add_assertion if (!@catch_assertions) super else @actual_assertion_count += 1 end end end end end ================================================ FILE: test/testunit/test_error.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' module Test module Unit class TC_Error < TestCase TF_Exception = Struct.new('TF_Exception', :message, :backtrace) def test_display ex = TF_Exception.new("message1\nmessage2", ['line1', 'line2']) e = Error.new("name", ex) assert_equal("name: #{TF_Exception.name}: message1", e.short_display) assert_equal(<)", fault.test_name == "test_failure(TC_FailureError)") r = /\A.*#{Regexp.escape(File.basename(__FILE__))}:\d+:in `test_failure'\Z/ location = fault.location check("The location should be an array", location.kind_of?(Array)) check("The location should have two lines (was: <#{location.inspect}>)", location.size == 2) check("The Failure should have the correct location (was <#{location[0].inspect}>, expected <#{r.inspect}>)", r =~ location[0]) called = true } progress = [] test_case.run(result) { |*arguments| progress << arguments } check("The failure should have triggered the listener", called) check("The failure should have set passed?", !test_case.return_passed?) check("The progress block should have been updated correctly", [[TestCase::STARTED, test_case.name], [TestCase::FINISHED, test_case.name]] == progress) end def test_add_failure_nested test_case = @tc_failure_error.new(:test_nested_failure) check("passed? should start out true", test_case.return_passed?) result = TestResult.new called = false result.add_listener(TestResult::FAULT) { | fault | check("Should have a Failure", fault.instance_of?(Failure)) check("The Failure should have the correct message", "nested" == fault.message) check("The Failure should have the correct test_name (was <#{fault.test_name}>)", fault.test_name == "test_nested_failure(TC_FailureError)") r = location = fault.location check("The location should be an array", location.kind_of?(Array)) check("The location should have the correct number of lines (was: <#{location.inspect}>)", location.size == 3) check("The Failure should have the correct location (was <#{location[0].inspect}>)", /\A.*#{Regexp.escape(File.basename(__FILE__))}:\d+:in `nested'\Z/ =~ location[0]) check("The Failure should have the correct location (was <#{location[1].inspect}>)", /\A.*#{Regexp.escape(File.basename(__FILE__))}:\d+:in `test_nested_failure'\Z/ =~ location[1]) called = true } test_case.run(result){} check("The failure should have triggered the listener", called) end def test_add_error test_case = @tc_failure_error.new(:test_error) check("passed? should start out true", test_case.return_passed?) result = TestResult.new called = false result.add_listener(TestResult::FAULT) { | fault | check("Should have a TestError", fault.instance_of?(Error)) check("The Error should have the correct message", "ZeroDivisionError: divided by 0" == fault.message) check("The Error should have the correct test_name", "test_error(TC_FailureError)" == fault.test_name) check("The Error should have the correct exception", fault.exception.instance_of?(ZeroDivisionError)) called = true } test_case.run(result) {} check("The error should have triggered the listener", called) check("The error should have set passed?", !test_case.return_passed?) end def test_no_tests suite = TestCase.suite check("Should have a test suite", suite.instance_of?(TestSuite)) check("Should have one test", suite.size == 1) check("Should have the default test", suite.tests.first.name == "default_test(Test::Unit::TestCase)") result = TestResult.new suite.run(result) {} check("Should have had one test run", result.run_count == 1) check("Should have had one test failure", result.failure_count == 1) check("Should have had no errors", result.error_count == 0) end def test_suite tc = Class.new(TestCase) do def test_succeed assert_block {true} end def test_fail assert_block {false} end def test_error 1/0 end def dont_run assert_block {true} end def test_dont_run(argument) assert_block {true} end def test assert_block {true} end end suite = tc.suite check("Should have a test suite", suite.instance_of?(TestSuite)) check("Should have three tests", suite.size == 3) result = TestResult.new suite.run(result) {} check("Should have had three test runs", result.run_count == 3) check("Should have had one test failure", result.failure_count == 1) check("Should have had one test error", result.error_count == 1) end def test_setup_teardown tc = Class.new(TestCase) do attr_reader(:setup_called, :teardown_called) def initialize(test) super(test) @setup_called = false @teardown_called = false end def setup @setup_called = true end def teardown @teardown_called = true end def test_succeed assert_block {true} end def test_fail assert_block {false} end def test_error raise "Error!" end end result = TestResult.new test = tc.new(:test_succeed) test.run(result) {} check("Should have called setup the correct number of times", test.setup_called) check("Should have called teardown the correct number of times", test.teardown_called) test = tc.new(:test_fail) test.run(result) {} check("Should have called setup the correct number of times", test.setup_called) check("Should have called teardown the correct number of times", test.teardown_called) test = tc.new(:test_error) test.run(result) {} check("Should have called setup the correct number of times", test.setup_called) check("Should have called teardown the correct number of times", test.teardown_called) check("Should have had two test runs", result.run_count == 3) check("Should have had a test failure", result.failure_count == 1) check("Should have had a test error", result.error_count == 1) end def test_assertion_failed_not_called tc = Class.new(TestCase) do def test_thing raise AssertionFailedError.new end end suite = tc.suite check("Should have one test", suite.size == 1) result = TestResult.new suite.run(result) {} check("Should have had one test run", result.run_count == 1) check("Should have had one assertion failure", result.failure_count == 1) check("Should not have any assertion errors but had #{result.error_count}", result.error_count == 0) end def test_equality tc1 = Class.new(TestCase) do def test_1 end def test_2 end end tc2 = Class.new(TestCase) do def test_1 end end test1 = tc1.new('test_1') test2 = tc1.new('test_1') check("Should be equal", test1 == test2) check("Should be equal", test2 == test1) test1 = tc1.new('test_2') check("Should not be equal", test1 != test2) check("Should not be equal", test2 != test1) test2 = tc1.new('test_2') check("Should be equal", test1 == test2) check("Should be equal", test2 == test1) test1 = tc1.new('test_1') test2 = tc2.new('test_1') check("Should not be equal", test1 != test2) check("Should not be equal", test2 != test1) check("Should not be equal", test1 != Object.new) check("Should not be equal", Object.new != test1) end def check(message, passed) @_result.add_assertion if ! passed raise AssertionFailedError.new(message) end end end end end ================================================ FILE: test/testunit/test_testresult.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/testcase' require 'test/unit/testresult' module Test module Unit class TC_TestResult < TestCase def setup @my_result = TestResult.new @my_result.add_assertion() @my_result.add_failure("") @my_result.add_error("") end def test_result_changed_notification called1 = false @my_result.add_listener( TestResult::CHANGED) { |result| assert_block("The result should be correct") { result == @my_result } called1 = true } @my_result.add_assertion assert_block("Should have been notified when the assertion happened") { called1 } called1, called2 = false, false @my_result.add_listener( TestResult::CHANGED) { |result| assert_block("The result should be correct") { result == @my_result } called2 = true } @my_result.add_assertion assert_block("Both listeners should have been notified for a success") { called1 && called2 } called1, called2 = false, false @my_result.add_failure("") assert_block("Both listeners should have been notified for a failure") { called1 && called2 } called1, called2 = false, false @my_result.add_error("") assert_block("Both listeners should have been notified for an error") { called1 && called2 } called1, called2 = false, false @my_result.add_run assert_block("Both listeners should have been notified for a run") { called1 && called2 } end def test_fault_notification called1 = false fault = "fault" @my_result.add_listener(TestResult::FAULT) { | passed_fault | assert_block("The fault should be correct") { passed_fault == fault } called1 = true } @my_result.add_assertion assert_block("Should not have been notified when the assertion happened") { !called1 } @my_result.add_failure(fault) assert_block("Should have been notified when the failure happened") { called1 } called1, called2 = false, false @my_result.add_listener(TestResult::FAULT) { | passed_fault | assert_block("The fault should be correct") { passed_fault == fault } called2 = true } @my_result.add_assertion assert_block("Neither listener should have been notified for a success") { !(called1 || called2) } called1, called2 = false, false @my_result.add_failure(fault) assert_block("Both listeners should have been notified for a failure") { called1 && called2 } called1, called2 = false, false @my_result.add_error(fault) assert_block("Both listeners should have been notified for an error") { called1 && called2 } called1, called2 = false, false @my_result.add_run assert_block("Neither listener should have been notified for a run") { !(called1 || called2) } end def test_passed? result = TestResult.new assert(result.passed?, "An empty result should have passed") result.add_assertion assert(result.passed?, "Adding an assertion should not cause the result to not pass") result.add_run assert(result.passed?, "Adding a run should not cause the result to not pass") result.add_failure("") assert(!result.passed?, "Adding a failed assertion should cause the result to not pass") result = TestResult.new result.add_error("") assert(!result.passed?, "Adding an error should cause the result to not pass") end end end end ================================================ FILE: test/testunit/test_testsuite.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' module Test module Unit class TC_TestSuite < TestCase def setup @testcase1 = Class.new(TestCase) do def test_succeed1 assert_block { true } end def test_fail assert_block { false } end end @testcase2 = Class.new(TestCase) do def test_succeed2 assert_block { true } end def test_error raise end end end def test_add s = TestSuite.new assert_equal(s, s << self.class.new("test_add")) end def test_delete s = TestSuite.new t1 = self.class.new("test_delete") s << t1 t2 = self.class.new("test_add") s << t2 assert_equal(t1, s.delete(t1)) assert_nil(s.delete(t1)) assert_equal(TestSuite.new << t2, s) end def test_size suite = TestSuite.new suite2 = TestSuite.new suite2 << self.class.new("test_size") suite << suite2 suite << self.class.new("test_size") assert_equal(2, suite.size, "The count should be correct") end def test_run progress = [] suite = @testcase1.suite result = TestResult.new suite.run(result) { |*values| progress << values } assert_equal(2, result.run_count, "Should have had four test runs") assert_equal(1, result.failure_count, "Should have had one test failure") assert_equal(0, result.error_count, "Should have had one test error") assert_equal([[TestSuite::STARTED, suite.name], [TestCase::STARTED, "test_fail(#{suite.name})"], [TestCase::FINISHED, "test_fail(#{suite.name})"], [TestCase::STARTED, "test_succeed1(#{suite.name})"], [TestCase::FINISHED, "test_succeed1(#{suite.name})"], [TestSuite::FINISHED, suite.name]], progress, "Should have had the correct progress") suite = TestSuite.new suite << @testcase1.suite suite << @testcase2.suite result = TestResult.new progress = [] suite.run(result) { |*values| progress << values } assert_equal(4, result.run_count, "Should have had four test runs") assert_equal(1, result.failure_count, "Should have had one test failure") assert_equal(1, result.error_count, "Should have had one test error") assert_equal(14, progress.size, "Should have had the correct number of progress calls") end def test_empty? assert(TestSuite.new.empty?, "A new test suite should be empty?") assert(!@testcase2.suite.empty?, "A test suite with tests should not be empty") end def test_equality suite1 = TestSuite.new suite2 = TestSuite.new assert_equal(suite1, suite2) assert_equal(suite2, suite1) suite1 = TestSuite.new('name') assert_not_equal(suite1, suite2) assert_not_equal(suite2, suite1) suite2 = TestSuite.new('name') assert_equal(suite1, suite2) assert_equal(suite2, suite1) suite1 << 'test' assert_not_equal(suite1, suite2) assert_not_equal(suite2, suite1) suite2 << 'test' assert_equal(suite1, suite2) assert_equal(suite2, suite1) suite2 = Object.new class << suite2 def name 'name' end def tests ['test'] end end assert_not_equal(suite1, suite2) assert_not_equal(suite2, suite1) assert_not_equal(suite1, Object.new) assert_not_equal(Object.new, suite1) end end end end ================================================ FILE: test/testunit/util/test_backtracefilter.rb ================================================ require 'test/unit' require 'test/unit/util/backtracefilter' module Test::Unit::Util class TestBacktraceFilter < Test::Unit::TestCase include BacktraceFilter def test_filter_backtrace backtrace = [%q{C:\some\old\path/test/unit/assertions.rb:44:in 'assert'}, %q{tc_thing.rb:4:in 'a'}, %q{tc_thing.rb:4:in 'test_stuff'}, %q{C:\some\old\path/test/unit/testcase.rb:44:in 'send'}, %q{C:\some\old\path\test\unit\testcase.rb:44:in 'run'}, %q{C:\some\old\path\test\unit.rb:44:in 'run'}, %q{tc_thing.rb:3}] assert_equal(backtrace[1..2], filter_backtrace(backtrace, %q{C:\some\old\path\test\unit}), "Should filter out all TestUnit-specific lines") backtrace = [%q{tc_thing.rb:4:in 'a'}, %q{tc_thing.rb:4:in 'test_stuff'}, %q{tc_thing.rb:3}] assert_equal(backtrace, filter_backtrace(backtrace, %q{C:\some\old\path\test\unit}), "Shouldn't filter too much") backtrace = [%q{C:\some\old\path/test/unit/assertions.rb:44:in 'assert'}, %q{tc_thing.rb:4:in 'a'}, %q{tc_thing.rb:4:in 'test_stuff'}, %q{tc_thing.rb:3}] assert_equal(backtrace[1..3], filter_backtrace(backtrace, %q{C:\some\old\path\test\unit}), "Should filter out all TestUnit-specific lines") backtrace = [%q{C:\some\old\path/test/unit/assertions.rb:44:in 'assert'}, %q{C:\some\old\path/test/unit/testcase.rb:44:in 'send'}, %q{C:\some\old\path\test\unit\testcase.rb:44:in 'run'}, %q{C:\some\old\path\test\unit.rb:44:in 'run'}] assert_equal(backtrace, filter_backtrace(backtrace, %q{C:\some\old\path\test\unit}), "Should filter out all TestUnit-specific lines") end def test_nil_backtrace assert_equal(["No backtrace"], filter_backtrace(nil)) end end end ================================================ FILE: test/testunit/util/test_observable.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/util/observable' module Test module Unit module Util class TC_Observable < TestCase class TF_Observable include Observable end def setup @observable = TF_Observable.new end def test_simple_observation assert_raises(ArgumentError, "add_listener should throw an exception if no callback is supplied") do @observable.add_listener(:property, "a") end heard = false callback = proc { heard = true } assert_equal("a", @observable.add_listener(:property, "a", &callback), "add_listener should return the listener that was added") count = 0 @observable.instance_eval do count = notify_listeners(:property) end assert_equal(1, count, "notify_listeners should have returned the number of listeners that were notified") assert(heard, "Should have heard the property changed") heard = false assert_equal(callback, @observable.remove_listener(:property, "a"), "remove_listener should return the callback") count = 1 @observable.instance_eval do count = notify_listeners(:property) end assert_equal(0, count, "notify_listeners should have returned the number of listeners that were notified") assert(!heard, "Should not have heard the property change") end def test_value_observation value = nil @observable.add_listener(:property, "a") do |passed_value| value = passed_value end count = 0 @observable.instance_eval do count = notify_listeners(:property, "stuff") end assert_equal(1, count, "Should have update the correct number of listeners") assert_equal("stuff", value, "Should have received the value as an argument to the listener") end def test_multiple_value_observation values = [] @observable.add_listener(:property, "a") do |first_value, second_value| values = [first_value, second_value] end count = 0 @observable.instance_eval do count = notify_listeners(:property, "stuff", "more stuff") end assert_equal(1, count, "Should have update the correct number of listeners") assert_equal(["stuff", "more stuff"], values, "Should have received the value as an argument to the listener") end def test_add_remove_with_default_listener assert_raises(ArgumentError, "add_listener should throw an exception if no callback is supplied") do @observable.add_listener(:property) end heard = false callback = proc { heard = true } assert_equal(callback, @observable.add_listener(:property, &callback), "add_listener should return the listener that was added") count = 0 @observable.instance_eval do count = notify_listeners(:property) end assert_equal(1, count, "notify_listeners should have returned the number of listeners that were notified") assert(heard, "Should have heard the property changed") heard = false assert_equal(callback, @observable.remove_listener(:property, callback), "remove_listener should return the callback") count = 1 @observable.instance_eval do count = notify_listeners(:property) end assert_equal(0, count, "notify_listeners should have returned the number of listeners that were notified") assert(!heard, "Should not have heard the property change") end end end end end ================================================ FILE: test/testunit/util/test_procwrapper.rb ================================================ # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' require 'test/unit/util/procwrapper' module Test module Unit module Util class TC_ProcWrapper < TestCase def munge_proc(&a_proc) return a_proc end def setup @original = proc {} @munged = munge_proc(&@original) @wrapped_original = ProcWrapper.new(@original) @wrapped_munged = ProcWrapper.new(@munged) end def test_wrapping assert_same(@original, @wrapped_original.to_proc, "The wrapper should return what was wrapped") end def test_hashing assert_equal(@wrapped_original.hash, @wrapped_munged.hash, "The original and munged should have the same hash when wrapped") assert_equal(@wrapped_original, @wrapped_munged, "The wrappers should be equivalent") a_hash = {@wrapped_original => @original} assert(a_hash[@wrapped_original], "Should be able to access the wrapper in the hash") assert_equal(a_hash[@wrapped_original], @original, "Should be able to access the wrapper in the hash") end end end end end ================================================ FILE: test/thread/lbtest.rb ================================================ #! /usr/bin/ruby require 'thread' class LocalBarrier def initialize(n) @wait = Queue.new @done = Queue.new @keeper = begin_keeper(n) end def sync @done.push(true) @wait.pop end def join @keeper.join end private def begin_keeper(n) Thread.start do n.times do @done.pop end n.times do @wait.push(true) end end end end n = 10 lb = LocalBarrier.new(n) (n - 1).times do |i| Thread.start do sleep((rand(n) + 1) / 10.0) puts "#{i}: done" lb.sync puts "#{i}: cont" end end lb.sync puts "#{n-1}: done" # lb.join # leaving waiting threads. puts "exit." ================================================ FILE: test/thread/test_thread.rb ================================================ # -*- ruby-indent-level: 4 -*- require 'thread' require 'test/unit' class TC_Thread < Test::Unit::TestCase def setup Thread.abort_on_exception = true end def teardown Thread.abort_on_exception = false end def test_condvar mutex = Mutex.new condvar = ConditionVariable.new result = [] mutex.synchronize do t = Thread.new do mutex.synchronize do result << 1 condvar.signal end end result << 0 condvar.wait(mutex) result << 2 t.join end assert_equal([0, 1, 2], result) end def test_condvar_wait_not_owner mutex = Mutex.new condvar = ConditionVariable.new assert_raises(ThreadError) { condvar.wait(mutex) } end def test_condvar_wait_exception_handling # Calling wait in the only thread running should raise a ThreadError of # 'stopping only thread' mutex = Mutex.new condvar = ConditionVariable.new Thread.abort_on_exception = false locked = false thread = Thread.new do mutex.synchronize do begin condvar.wait(mutex) rescue Exception locked = mutex.locked? raise end end end while !thread.stop? sleep(0.1) end thread.raise Interrupt, "interrupt a dead condition variable" assert_raises(Interrupt) { thread.value } assert(locked) end def test_local_barrier dir = File.dirname(__FILE__) lbtest = File.join(dir, "lbtest.rb") $:.unshift File.join(File.dirname(dir), 'ruby') require 'envutil' $:.shift 10.times { result = `#{EnvUtil.rubybin} #{lbtest}` assert(!$?.coredump?, '[ruby-dev:30653]') assert_equal("exit.", result[/.*\Z/], '[ruby-dev:30653]') } end def test_queue_rescue require "timeout" queue = Queue.new assert_raises(Timeout::Error) {Timeout.timeout(0.001) {queue.pop}} queue.push(1) assert_nothing_raised("[ruby-dev:37545]") {assert_equal(1, queue.pop)} assert(queue.empty?) end end ================================================ FILE: test/uri/test_common.rb ================================================ require 'test/unit' require 'uri' module URI class TestCommon < Test::Unit::TestCase def setup end def teardown end def test_extract assert_equal(['http://example.com'], URI.extract('http://example.com')) assert_equal(['http://example.com'], URI.extract('(http://example.com)')) assert_equal(['http://example.com/foo)'], URI.extract('(http://example.com/foo)')) assert_equal(['http://example.jphttp://example.jp'], URI.extract('http://example.jphttp://example.jp'), "[ruby-list:36086]") assert_equal(['http://example.jphttp://example.jp'], URI.extract('http://example.jphttp://example.jp', ['http']), "[ruby-list:36086]") assert_equal(['http://', 'mailto:'].sort, URI.extract('ftp:// http:// mailto: https://', ['http', 'mailto']).sort) # reported by Doug Kearns assert_equal(['From:', 'mailto:xxx@xxx.xxx.xxx]'].sort, URI.extract('From: XXX [mailto:xxx@xxx.xxx.xxx]').sort) end def test_regexp assert_instance_of Regexp, URI.regexp assert_instance_of Regexp, URI.regexp(['http']) assert_equal URI.regexp, URI.regexp assert_equal 'http://', 'x http:// x'.slice(URI.regexp) assert_equal 'http://', 'x http:// x'.slice(URI.regexp(['http'])) assert_equal 'http://', 'x http:// x ftp://'.slice(URI.regexp(['http'])) assert_equal nil, 'http://'.slice(URI.regexp([])) assert_equal nil, ''.slice(URI.regexp) assert_equal nil, 'xxxx'.slice(URI.regexp) assert_equal nil, ':'.slice(URI.regexp) assert_equal 'From:', 'From:'.slice(URI.regexp) end def test_kernel_uri expected = URI.parse("http://www.ruby-lang.org/") assert_equal(expected, URI("http://www.ruby-lang.org/")) assert_equal(expected, Kernel::URI("http://www.ruby-lang.org/")) assert_raise(NoMethodError) { Object.new.URI("http://www.ruby-lang.org/") } end end end ================================================ FILE: test/uri/test_ftp.rb ================================================ require 'test/unit' require 'uri/ftp' module URI class TestFTP < Test::Unit::TestCase def setup end def test_parse url = URI.parse('ftp://user:pass@host.com/abc/def') assert_kind_of(URI::FTP, url) exp = [ 'ftp', 'user:pass', 'host.com', URI::FTP.default_port, 'abc/def', nil, ] ary = [ url.scheme, url.userinfo, url.host, url.port, url.path, url.opaque ] assert_equal(exp, ary) assert_equal('user', url.user) assert_equal('pass', url.password) end def test_paths # If you think what's below is wrong, please read RubyForge bug 2055, # RFC 1738 section 3.2.2, and RFC 2396. u = URI.parse('ftp://ftp.example.com/foo/bar/file.ext') assert_equal(u.path, 'foo/bar/file.ext') u = URI.parse('ftp://ftp.example.com//foo/bar/file.ext') assert_equal(u.path, '/foo/bar/file.ext') u = URI.parse('ftp://ftp.example.com/%2Ffoo/bar/file.ext') assert_equal(u.path, '/foo/bar/file.ext') end def test_assemble # uri/ftp is conservative and uses the older RFC 1738 rules, rather than # assuming everyone else has implemented RFC 2396. uri = URI::FTP.build(['user:password', 'ftp.example.com', nil, '/path/file.zip', 'i']) assert_equal(uri.to_s, 'ftp://user:password@ftp.example.com/%2Fpath/file.zip;type=i') end def test_select assert_equal(['ftp', 'a.b.c', 21], URI.parse('ftp://a.b.c/').select(:scheme, :host, :port)) u = URI.parse('ftp://a.b.c/') ary = u.component.collect {|c| u.send(c)} assert_equal(ary, u.select(*u.component)) assert_raises(ArgumentError) do u.select(:scheme, :host, :not_exist, :port) end end end end ================================================ FILE: test/uri/test_generic.rb ================================================ require 'test/unit' require 'uri' module URI class TestGeneric < Test::Unit::TestCase def setup @url = 'http://a/b/c/d;p?q' @base_url = URI.parse(@url) end def teardown end def uri_to_ary(uri) uri.class.component.collect {|c| uri.send(c)} end def test_parse # 0 assert_kind_of(URI::HTTP, @base_url) exp = [ 'http', nil, 'a', URI::HTTP.default_port, '/b/c/d;p', 'q', nil ] ary = uri_to_ary(@base_url) assert_equal(exp, ary) # 1 url = URI.parse('ftp://ftp.is.co.za/rfc/rfc1808.txt') assert_kind_of(URI::FTP, url) exp = [ 'ftp', nil, 'ftp.is.co.za', URI::FTP.default_port, 'rfc/rfc1808.txt', nil, ] ary = uri_to_ary(url) assert_equal(exp, ary) # 1' url = URI.parse('ftp://ftp.is.co.za/%2Frfc/rfc1808.txt') assert_kind_of(URI::FTP, url) exp = [ 'ftp', nil, 'ftp.is.co.za', URI::FTP.default_port, '/rfc/rfc1808.txt', nil, ] ary = uri_to_ary(url) assert_equal(exp, ary) # 2 url = URI.parse('gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles') assert_kind_of(URI::Generic, url) exp = [ 'gopher', nil, 'spinaltap.micro.umn.edu', nil, nil, '/00/Weather/California/Los%20Angeles', nil, nil, nil ] ary = uri_to_ary(url) assert_equal(exp, ary) # 3 url = URI.parse('http://www.math.uio.no/faq/compression-faq/part1.html') assert_kind_of(URI::HTTP, url) exp = [ 'http', nil, 'www.math.uio.no', URI::HTTP.default_port, '/faq/compression-faq/part1.html', nil, nil ] ary = uri_to_ary(url) assert_equal(exp, ary) # 4 url = URI.parse('mailto:mduerst@ifi.unizh.ch') assert_kind_of(URI::Generic, url) exp = [ 'mailto', 'mduerst@ifi.unizh.ch', [] ] ary = uri_to_ary(url) assert_equal(exp, ary) # 5 url = URI.parse('news:comp.infosystems.www.servers.unix') assert_kind_of(URI::Generic, url) exp = [ 'news', nil, nil, nil, nil, nil, 'comp.infosystems.www.servers.unix', nil, nil ] ary = uri_to_ary(url) assert_equal(exp, ary) # 6 url = URI.parse('telnet://melvyl.ucop.edu/') assert_kind_of(URI::Generic, url) exp = [ 'telnet', nil, 'melvyl.ucop.edu', nil, nil, '/', nil, nil, nil ] ary = uri_to_ary(url) assert_equal(exp, ary) # 7 # reported by Mr. Kubota assert_raises(URI::InvalidURIError) { URI.parse('http://a_b:80/') } assert_raises(URI::InvalidURIError) { URI.parse('http://a_b/') } # 8 # reported by m_seki uri = URI.parse('file:///foo/bar.txt') assert_kind_of(URI::Generic, url) uri = URI.parse('file:/foo/bar.txt') assert_kind_of(URI::Generic, url) # 9 url = URI.parse('ftp://:pass@localhost/') assert_equal('', url.user, "[ruby-dev:25667]") assert_equal('pass', url.password) assert_equal(':pass', url.userinfo, "[ruby-dev:25667]") url = URI.parse('ftp://user@localhost/') assert_equal('user', url.user) assert_equal(nil, url.password) assert_equal('user', url.userinfo) url = URI.parse('ftp://localhost/') assert_equal(nil, url.user) assert_equal(nil, url.password) assert_equal(nil, url.userinfo) end def test_merge u1 = URI.parse('http://foo') u2 = URI.parse('http://foo/') u3 = URI.parse('http://foo/bar') u4 = URI.parse('http://foo/bar/') assert_equal(URI.parse('http://foo/baz'), u1 + 'baz') assert_equal(URI.parse('http://foo/baz'), u2 + 'baz') assert_equal(URI.parse('http://foo/baz'), u3 + 'baz') assert_equal(URI.parse('http://foo/bar/baz'), u4 + 'baz') assert_equal(URI.parse('http://foo/baz'), u1 + '/baz') assert_equal(URI.parse('http://foo/baz'), u2 + '/baz') assert_equal(URI.parse('http://foo/baz'), u3 + '/baz') assert_equal(URI.parse('http://foo/baz'), u4 + '/baz') url = URI.parse('http://hoge/a.html') + 'b.html' assert_equal('http://hoge/b.html', url.to_s, "[ruby-dev:11508]") # reported by Mr. Kubota url = URI.parse('http://a/b') + 'http://x/y' assert_equal('http://x/y', url.to_s) assert_equal(url, URI.parse('') + 'http://x/y') assert_equal(url, URI.parse('').normalize + 'http://x/y') assert_equal(url, URI.parse('http://a/b').normalize + 'http://x/y') u = URI.parse('http://foo/bar/baz') assert_equal(nil, u.merge!("")) assert_equal(nil, u.merge!(u)) assert(nil != u.merge!(".")) assert_equal('http://foo/bar/', u.to_s) assert(nil != u.merge!("../baz")) assert_equal('http://foo/baz', u.to_s) u0 = URI.parse('mailto:foo@example.com') u1 = URI.parse('mailto:foo@example.com#bar') assert_equal(uri_to_ary(u0 + '#bar'), uri_to_ary(u1), "[ruby-dev:23628]") u0 = URI.parse('http://www.example.com/') u1 = URI.parse('http://www.example.com/foo/..') + './' assert_equal(u0, u1, "[ruby-list:39838]") u0 = URI.parse('http://www.example.com/foo/') u1 = URI.parse('http://www.example.com/foo/bar/..') + './' assert_equal(u0, u1) u0 = URI.parse('http://www.example.com/foo/bar/') u1 = URI.parse('http://www.example.com/foo/bar/baz/..') + './' assert_equal(u0, u1) u0 = URI.parse('http://www.example.com/') u1 = URI.parse('http://www.example.com/foo/bar/../..') + './' assert_equal(u0, u1) u0 = URI.parse('http://www.example.com/foo/') u1 = URI.parse('http://www.example.com/foo/bar/baz/../..') + './' assert_equal(u0, u1) u = URI.parse('http://www.example.com/') u0 = u + './foo/' u1 = u + './foo/bar/..' assert_equal(u0, u1, "[ruby-list:39844]") u = URI.parse('http://www.example.com/') u0 = u + './' u1 = u + './foo/bar/../..' assert_equal(u0, u1) end def test_route url = URI.parse('http://hoge/a.html').route_to('http://hoge/b.html') assert_equal('b.html', url.to_s) url = URI.parse('http://hoge/a/').route_to('http://hoge/b/') assert_equal('../b/', url.to_s) url = URI.parse('http://hoge/a/b').route_to('http://hoge/b/') assert_equal('../b/', url.to_s) url = URI.parse('http://hoge/a/b/').route_to('http://hoge/b/') assert_equal('../../b/', url.to_s) url = URI.parse('http://hoge/a/b/').route_to('http://HOGE/b/') assert_equal('../../b/', url.to_s) url = URI.parse('http://hoge/a/b/').route_to('http://MOGE/b/') assert_equal('//MOGE/b/', url.to_s) url = URI.parse('file:///a/b/').route_to('file:///a/b/') assert_equal('', url.to_s) url = URI.parse('mailto:foo@example.com').route_to('mailto:foo@example.com#bar') assert_equal('#bar', url.to_s) url = URI.parse('mailto:foo@example.com#bar').route_to('mailto:foo@example.com') assert_equal('', url.to_s) url = URI.parse('mailto:foo@example.com').route_to('mailto:foo@example.com') assert_equal('', url.to_s) end def test_rfc3986_examples # http://a/b/c/d;p?q # g:h = g:h url = @base_url.merge('g:h') assert_kind_of(URI::Generic, url) assert_equal('g:h', url.to_s) url = @base_url.route_to('g:h') assert_kind_of(URI::Generic, url) assert_equal('g:h', url.to_s) # http://a/b/c/d;p?q # g = http://a/b/c/g url = @base_url.merge('g') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/g', url.to_s) url = @base_url.route_to('http://a/b/c/g') assert_kind_of(URI::Generic, url) assert_equal('g', url.to_s) # http://a/b/c/d;p?q # ./g = http://a/b/c/g url = @base_url.merge('./g') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/g', url.to_s) url = @base_url.route_to('http://a/b/c/g') assert_kind_of(URI::Generic, url) assert('./g' != url.to_s) # ok assert_equal('g', url.to_s) # http://a/b/c/d;p?q # g/ = http://a/b/c/g/ url = @base_url.merge('g/') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/g/', url.to_s) url = @base_url.route_to('http://a/b/c/g/') assert_kind_of(URI::Generic, url) assert_equal('g/', url.to_s) # http://a/b/c/d;p?q # /g = http://a/g url = @base_url.merge('/g') assert_kind_of(URI::HTTP, url) assert_equal('http://a/g', url.to_s) url = @base_url.route_to('http://a/g') assert_kind_of(URI::Generic, url) assert('/g' != url.to_s) # ok assert_equal('../../g', url.to_s) # http://a/b/c/d;p?q # //g = http://g url = @base_url.merge('//g') assert_kind_of(URI::HTTP, url) assert_equal('http://g', url.to_s) url = @base_url.route_to('http://g') assert_kind_of(URI::Generic, url) assert_equal('//g', url.to_s) # http://a/b/c/d;p?q # ?y = http://a/b/c/d;p?y url = @base_url.merge('?y') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/d;p?y', url.to_s) url = @base_url.route_to('http://a/b/c/d;p?y') assert_kind_of(URI::Generic, url) assert_equal('?y', url.to_s) # http://a/b/c/d;p?q # g?y = http://a/b/c/g?y url = @base_url.merge('g?y') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/g?y', url.to_s) url = @base_url.route_to('http://a/b/c/g?y') assert_kind_of(URI::Generic, url) assert_equal('g?y', url.to_s) # http://a/b/c/d;p?q # #s = http://a/b/c/d;p?q#s url = @base_url.merge('#s') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/d;p?q#s', url.to_s) url = @base_url.route_to('http://a/b/c/d;p?q#s') assert_kind_of(URI::Generic, url) assert_equal('#s', url.to_s) # http://a/b/c/d;p?q # g#s = http://a/b/c/g#s url = @base_url.merge('g#s') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/g#s', url.to_s) url = @base_url.route_to('http://a/b/c/g#s') assert_kind_of(URI::Generic, url) assert_equal('g#s', url.to_s) # http://a/b/c/d;p?q # g?y#s = http://a/b/c/g?y#s url = @base_url.merge('g?y#s') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/g?y#s', url.to_s) url = @base_url.route_to('http://a/b/c/g?y#s') assert_kind_of(URI::Generic, url) assert_equal('g?y#s', url.to_s) # http://a/b/c/d;p?q # ;x = http://a/b/c/;x url = @base_url.merge(';x') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/;x', url.to_s) url = @base_url.route_to('http://a/b/c/;x') assert_kind_of(URI::Generic, url) assert_equal(';x', url.to_s) # http://a/b/c/d;p?q # g;x = http://a/b/c/g;x url = @base_url.merge('g;x') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/g;x', url.to_s) url = @base_url.route_to('http://a/b/c/g;x') assert_kind_of(URI::Generic, url) assert_equal('g;x', url.to_s) # http://a/b/c/d;p?q # g;x?y#s = http://a/b/c/g;x?y#s url = @base_url.merge('g;x?y#s') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/g;x?y#s', url.to_s) url = @base_url.route_to('http://a/b/c/g;x?y#s') assert_kind_of(URI::Generic, url) assert_equal('g;x?y#s', url.to_s) # http://a/b/c/d;p?q # . = http://a/b/c/ url = @base_url.merge('.') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/', url.to_s) url = @base_url.route_to('http://a/b/c/') assert_kind_of(URI::Generic, url) assert('.' != url.to_s) # ok assert_equal('./', url.to_s) # http://a/b/c/d;p?q # ./ = http://a/b/c/ url = @base_url.merge('./') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/', url.to_s) url = @base_url.route_to('http://a/b/c/') assert_kind_of(URI::Generic, url) assert_equal('./', url.to_s) # http://a/b/c/d;p?q # .. = http://a/b/ url = @base_url.merge('..') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/', url.to_s) url = @base_url.route_to('http://a/b/') assert_kind_of(URI::Generic, url) assert('..' != url.to_s) # ok assert_equal('../', url.to_s) # http://a/b/c/d;p?q # ../ = http://a/b/ url = @base_url.merge('../') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/', url.to_s) url = @base_url.route_to('http://a/b/') assert_kind_of(URI::Generic, url) assert_equal('../', url.to_s) # http://a/b/c/d;p?q # ../g = http://a/b/g url = @base_url.merge('../g') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/g', url.to_s) url = @base_url.route_to('http://a/b/g') assert_kind_of(URI::Generic, url) assert_equal('../g', url.to_s) # http://a/b/c/d;p?q # ../.. = http://a/ url = @base_url.merge('../..') assert_kind_of(URI::HTTP, url) assert_equal('http://a/', url.to_s) url = @base_url.route_to('http://a/') assert_kind_of(URI::Generic, url) assert('../..' != url.to_s) # ok assert_equal('../../', url.to_s) # http://a/b/c/d;p?q # ../../ = http://a/ url = @base_url.merge('../../') assert_kind_of(URI::HTTP, url) assert_equal('http://a/', url.to_s) url = @base_url.route_to('http://a/') assert_kind_of(URI::Generic, url) assert_equal('../../', url.to_s) # http://a/b/c/d;p?q # ../../g = http://a/g url = @base_url.merge('../../g') assert_kind_of(URI::HTTP, url) assert_equal('http://a/g', url.to_s) url = @base_url.route_to('http://a/g') assert_kind_of(URI::Generic, url) assert_equal('../../g', url.to_s) # http://a/b/c/d;p?q # <> = (current document) url = @base_url.merge('') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/d;p?q', url.to_s) url = @base_url.route_to('http://a/b/c/d;p?q') assert_kind_of(URI::Generic, url) assert_equal('', url.to_s) # http://a/b/c/d;p?q # /./g = http://a/g url = @base_url.merge('/./g') assert_kind_of(URI::HTTP, url) assert_equal('http://a/g', url.to_s) # url = @base_url.route_to('http://a/./g') # assert_kind_of(URI::Generic, url) # assert_equal('/./g', url.to_s) # http://a/b/c/d;p?q # /../g = http://a/g url = @base_url.merge('/../g') assert_kind_of(URI::HTTP, url) assert_equal('http://a/g', url.to_s) # url = @base_url.route_to('http://a/../g') # assert_kind_of(URI::Generic, url) # assert_equal('/../g', url.to_s) # http://a/b/c/d;p?q # g. = http://a/b/c/g. url = @base_url.merge('g.') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/g.', url.to_s) url = @base_url.route_to('http://a/b/c/g.') assert_kind_of(URI::Generic, url) assert_equal('g.', url.to_s) # http://a/b/c/d;p?q # .g = http://a/b/c/.g url = @base_url.merge('.g') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/.g', url.to_s) url = @base_url.route_to('http://a/b/c/.g') assert_kind_of(URI::Generic, url) assert_equal('.g', url.to_s) # http://a/b/c/d;p?q # g.. = http://a/b/c/g.. url = @base_url.merge('g..') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/g..', url.to_s) url = @base_url.route_to('http://a/b/c/g..') assert_kind_of(URI::Generic, url) assert_equal('g..', url.to_s) # http://a/b/c/d;p?q # ..g = http://a/b/c/..g url = @base_url.merge('..g') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/..g', url.to_s) url = @base_url.route_to('http://a/b/c/..g') assert_kind_of(URI::Generic, url) assert_equal('..g', url.to_s) # http://a/b/c/d;p?q # ../../../g = http://a/g url = @base_url.merge('../../../g') assert_kind_of(URI::HTTP, url) assert_equal('http://a/g', url.to_s) url = @base_url.route_to('http://a/g') assert_kind_of(URI::Generic, url) assert('../../../g' != url.to_s) # ok? yes, it confuses you assert_equal('../../g', url.to_s) # and it is clearly # http://a/b/c/d;p?q # ../../../../g = http://a/g url = @base_url.merge('../../../../g') assert_kind_of(URI::HTTP, url) assert_equal('http://a/g', url.to_s) url = @base_url.route_to('http://a/g') assert_kind_of(URI::Generic, url) assert('../../../../g' != url.to_s) # ok? yes, it confuses you assert_equal('../../g', url.to_s) # and it is clearly # http://a/b/c/d;p?q # ./../g = http://a/b/g url = @base_url.merge('./../g') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/g', url.to_s) url = @base_url.route_to('http://a/b/g') assert_kind_of(URI::Generic, url) assert('./../g' != url.to_s) # ok assert_equal('../g', url.to_s) # http://a/b/c/d;p?q # ./g/. = http://a/b/c/g/ url = @base_url.merge('./g/.') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/g/', url.to_s) url = @base_url.route_to('http://a/b/c/g/') assert_kind_of(URI::Generic, url) assert('./g/.' != url.to_s) # ok assert_equal('g/', url.to_s) # http://a/b/c/d;p?q # g/./h = http://a/b/c/g/h url = @base_url.merge('g/./h') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/g/h', url.to_s) url = @base_url.route_to('http://a/b/c/g/h') assert_kind_of(URI::Generic, url) assert('g/./h' != url.to_s) # ok assert_equal('g/h', url.to_s) # http://a/b/c/d;p?q # g/../h = http://a/b/c/h url = @base_url.merge('g/../h') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/h', url.to_s) url = @base_url.route_to('http://a/b/c/h') assert_kind_of(URI::Generic, url) assert('g/../h' != url.to_s) # ok assert_equal('h', url.to_s) # http://a/b/c/d;p?q # g;x=1/./y = http://a/b/c/g;x=1/y url = @base_url.merge('g;x=1/./y') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/g;x=1/y', url.to_s) url = @base_url.route_to('http://a/b/c/g;x=1/y') assert_kind_of(URI::Generic, url) assert('g;x=1/./y' != url.to_s) # ok assert_equal('g;x=1/y', url.to_s) # http://a/b/c/d;p?q # g;x=1/../y = http://a/b/c/y url = @base_url.merge('g;x=1/../y') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/y', url.to_s) url = @base_url.route_to('http://a/b/c/y') assert_kind_of(URI::Generic, url) assert('g;x=1/../y' != url.to_s) # ok assert_equal('y', url.to_s) # http://a/b/c/d;p?q # g?y/./x = http://a/b/c/g?y/./x url = @base_url.merge('g?y/./x') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/g?y/./x', url.to_s) url = @base_url.route_to('http://a/b/c/g?y/./x') assert_kind_of(URI::Generic, url) assert_equal('g?y/./x', url.to_s) # http://a/b/c/d;p?q # g?y/../x = http://a/b/c/g?y/../x url = @base_url.merge('g?y/../x') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/g?y/../x', url.to_s) url = @base_url.route_to('http://a/b/c/g?y/../x') assert_kind_of(URI::Generic, url) assert_equal('g?y/../x', url.to_s) # http://a/b/c/d;p?q # g#s/./x = http://a/b/c/g#s/./x url = @base_url.merge('g#s/./x') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/g#s/./x', url.to_s) url = @base_url.route_to('http://a/b/c/g#s/./x') assert_kind_of(URI::Generic, url) assert_equal('g#s/./x', url.to_s) # http://a/b/c/d;p?q # g#s/../x = http://a/b/c/g#s/../x url = @base_url.merge('g#s/../x') assert_kind_of(URI::HTTP, url) assert_equal('http://a/b/c/g#s/../x', url.to_s) url = @base_url.route_to('http://a/b/c/g#s/../x') assert_kind_of(URI::Generic, url) assert_equal('g#s/../x', url.to_s) # http://a/b/c/d;p?q # http:g = http:g ; for validating parsers # | http://a/b/c/g ; for backwards compatibility url = @base_url.merge('http:g') assert_kind_of(URI::HTTP, url) assert_equal('http:g', url.to_s) url = @base_url.route_to('http:g') assert_kind_of(URI::Generic, url) assert_equal('http:g', url.to_s) end def test_join assert_equal(URI.parse('http://foo/bar'), URI.join('http://foo/bar')) assert_equal(URI.parse('http://foo/bar'), URI.join('http://foo', 'bar')) assert_equal(URI.parse('http://foo/bar/'), URI.join('http://foo', 'bar/')) assert_equal(URI.parse('http://foo/baz'), URI.join('http://foo', 'bar', 'baz')) assert_equal(URI.parse('http://foo/baz'), URI.join('http://foo', 'bar', '/baz')) assert_equal(URI.parse('http://foo/baz/'), URI.join('http://foo', 'bar', '/baz/')) assert_equal(URI.parse('http://foo/bar/baz'), URI.join('http://foo', 'bar/', 'baz')) assert_equal(URI.parse('http://foo/hoge'), URI.join('http://foo', 'bar', 'baz', 'hoge')) assert_equal(URI.parse('http://foo/bar/baz'), URI.join('http://foo', 'bar/baz')) assert_equal(URI.parse('http://foo/bar/hoge'), URI.join('http://foo', 'bar/baz', 'hoge')) assert_equal(URI.parse('http://foo/bar/baz/hoge'), URI.join('http://foo', 'bar/baz/', 'hoge')) assert_equal(URI.parse('http://foo/hoge'), URI.join('http://foo', 'bar/baz', '/hoge')) assert_equal(URI.parse('http://foo/bar/hoge'), URI.join('http://foo', 'bar/baz', 'hoge')) assert_equal(URI.parse('http://foo/bar/baz/hoge'), URI.join('http://foo', 'bar/baz/', 'hoge')) assert_equal(URI.parse('http://foo/hoge'), URI.join('http://foo', 'bar/baz', '/hoge')) end # ruby-dev:16728 def test_set_component uri = URI.parse('http://foo:bar@baz') assert_equal('oof', uri.user = 'oof') assert_equal('http://oof:bar@baz', uri.to_s) assert_equal('rab', uri.password = 'rab') assert_equal('http://oof:rab@baz', uri.to_s) assert_equal('foo', uri.userinfo = 'foo') assert_equal('http://foo:rab@baz', uri.to_s) assert_equal(['foo', 'bar'], uri.userinfo = ['foo', 'bar']) assert_equal('http://foo:bar@baz', uri.to_s) assert_equal(['foo'], uri.userinfo = ['foo']) assert_equal('http://foo:bar@baz', uri.to_s) assert_equal('zab', uri.host = 'zab') assert_equal('http://foo:bar@zab', uri.to_s) assert_equal(8080, uri.port = 8080) assert_equal('http://foo:bar@zab:8080', uri.to_s) assert_equal('/', uri.path = '/') assert_equal('http://foo:bar@zab:8080/', uri.to_s) assert_equal('a=1', uri.query = 'a=1') assert_equal('http://foo:bar@zab:8080/?a=1', uri.to_s) assert_equal('b123', uri.fragment = 'b123') assert_equal('http://foo:bar@zab:8080/?a=1#b123', uri.to_s) uri = URI.parse('http://example.com') assert_raises(URI::InvalidURIError) { uri.password = 'bar' } uri.userinfo = 'foo:bar' assert_equal('http://foo:bar@example.com', uri.to_s) assert_raises(URI::InvalidURIError) { uri.registry = 'bar' } assert_raises(URI::InvalidURIError) { uri.opaque = 'bar' } uri = URI.parse('mailto:foo@example.com') assert_raises(URI::InvalidURIError) { uri.user = 'bar' } assert_raises(URI::InvalidURIError) { uri.password = 'bar' } assert_raises(URI::InvalidURIError) { uri.userinfo = ['bar', 'baz'] } assert_raises(URI::InvalidURIError) { uri.host = 'bar' } assert_raises(URI::InvalidURIError) { uri.port = 'bar' } assert_raises(URI::InvalidURIError) { uri.path = 'bar' } assert_raises(URI::InvalidURIError) { uri.query = 'bar' } end end end ================================================ FILE: test/uri/test_http.rb ================================================ require 'test/unit' require 'uri/http' module URI class TestHTTP < Test::Unit::TestCase def setup end def teardown end def uri_to_ary(uri) uri.class.component.collect {|c| uri.send(c)} end def test_parse u = URI.parse('http://a') assert_kind_of(URI::HTTP, u) assert_equal(['http', nil, 'a', URI::HTTP.default_port, '', nil, nil], uri_to_ary(u)) end def test_normalize host = 'aBcD' u1 = URI.parse('http://' + host + '/eFg?HiJ') u2 = URI.parse('http://' + host.downcase + '/eFg?HiJ') assert(u1.normalize.host == 'abcd') assert(u1.normalize.path == u1.path) assert(u1.normalize == u2.normalize) assert(!u1.normalize.host.equal?(u1.host)) assert( u2.normalize.host.equal?(u2.host)) assert_equal('http://abc/', URI.parse('http://abc').normalize.to_s) end def test_equal assert(URI.parse('http://abc') == URI.parse('http://ABC')) assert(URI.parse('http://abc/def') == URI.parse('http://ABC/def')) assert(URI.parse('http://abc/def') != URI.parse('http://ABC/DEF')) end def test_request_uri assert_equal('/', URI.parse('http://a.b.c/').request_uri) assert_equal('/?abc=def', URI.parse('http://a.b.c/?abc=def').request_uri) assert_equal('/', URI.parse('http://a.b.c').request_uri) assert_equal('/?abc=def', URI.parse('http://a.b.c?abc=def').request_uri) end def test_select assert_equal(['http', 'a.b.c', 80], URI.parse('http://a.b.c/').select(:scheme, :host, :port)) u = URI.parse('http://a.b.c/') assert_equal(uri_to_ary(u), u.select(*u.component)) assert_raises(ArgumentError) do u.select(:scheme, :host, :not_exist, :port) end end end end ================================================ FILE: test/uri/test_ldap.rb ================================================ require 'test/unit' require 'uri/ldap' module URI class TestLDAP < Test::Unit::TestCase def setup end def teardown end def uri_to_ary(uri) uri.class.component.collect {|c| uri.send(c)} end def test_parse url = 'ldap://ldap.jaist.ac.jp/o=JAIST,c=JP?sn?base?(sn=ttate*)' u = URI.parse(url) assert_kind_of(URI::LDAP, u) assert_equal(url, u.to_s) assert_equal('o=JAIST,c=JP', u.dn) assert_equal('sn', u.attributes) assert_equal('base', u.scope) assert_equal('(sn=ttate*)', u.filter) assert_equal(nil, u.extensions) u.scope = URI::LDAP::SCOPE_SUB u.attributes = 'sn,cn,mail' assert_equal('ldap://ldap.jaist.ac.jp/o=JAIST,c=JP?sn,cn,mail?sub?(sn=ttate*)', u.to_s) assert_equal('o=JAIST,c=JP', u.dn) assert_equal('sn,cn,mail', u.attributes) assert_equal('sub', u.scope) assert_equal('(sn=ttate*)', u.filter) assert_equal(nil, u.extensions) # from RFC2255, section 6. urls = { 'ldap:///o=University%20of%20Michigan,c=US' => ['ldap', nil, URI::LDAP::DEFAULT_PORT, 'o=University%20of%20Michigan,c=US', nil, nil, nil, nil], 'ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US' => ['ldap', 'ldap.itd.umich.edu', URI::LDAP::DEFAULT_PORT, 'o=University%20of%20Michigan,c=US', nil, nil, nil, nil], 'ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US?postalAddress' => ['ldap', 'ldap.itd.umich.edu', URI::LDAP::DEFAULT_PORT, 'o=University%20of%20Michigan,c=US', 'postalAddress', nil, nil, nil], 'ldap://host.com:6666/o=University%20of%20Michigan,c=US??sub?(cn=Babs%20Jensen)' => ['ldap', 'host.com', 6666, 'o=University%20of%20Michigan,c=US', nil, 'sub', '(cn=Babs%20Jensen)', nil], 'ldap://ldap.itd.umich.edu/c=GB?objectClass?one' => ['ldap', 'ldap.itd.umich.edu', URI::LDAP::DEFAULT_PORT, 'c=GB', 'objectClass', 'one', nil, nil], 'ldap://ldap.question.com/o=Question%3f,c=US?mail' => ['ldap', 'ldap.question.com', URI::LDAP::DEFAULT_PORT, 'o=Question%3f,c=US', 'mail', nil, nil, nil], 'ldap://ldap.netscape.com/o=Babsco,c=US??(int=%5c00%5c00%5c00%5c04)' => ['ldap', 'ldap.netscape.com', URI::LDAP::DEFAULT_PORT, 'o=Babsco,c=US', nil, '(int=%5c00%5c00%5c00%5c04)', nil, nil], 'ldap:///??sub??bindname=cn=Manager%2co=Foo' => ['ldap', nil, URI::LDAP::DEFAULT_PORT, '', nil, 'sub', nil, 'bindname=cn=Manager%2co=Foo'], 'ldap:///??sub??!bindname=cn=Manager%2co=Foo' => ['ldap', nil, URI::LDAP::DEFAULT_PORT, '', nil, 'sub', nil, '!bindname=cn=Manager%2co=Foo'], }.each do |url, ary| u = URI.parse(url) assert_equal(ary, uri_to_ary(u)) end end def test_select u = URI.parse('ldap:///??sub??!bindname=cn=Manager%2co=Foo') assert_equal(uri_to_ary(u), u.select(*u.component)) assert_raises(ArgumentError) do u.select(:scheme, :host, :not_exist, :port) end end end end ================================================ FILE: test/uri/test_mailto.rb ================================================ require 'test/unit' require 'uri/mailto' module URI class TestMailTo < Test::Unit::TestCase def setup @u = URI::MailTo end def teardown end def uri_to_ary(uri) uri.class.component.collect {|c| uri.send(c)} end def test_build ok = [] bad = [] # RFC2368, 6. Examples # mailto:chris@example.com ok << ["mailto:chris@example.com"] ok[-1] << ["chris@example.com", nil] ok[-1] << {:to => "chris@example.com"} # mailto:infobot@example.com?subject=current-issue ok << ["mailto:infobot@example.com?subject=current-issue"] ok[-1] << ["infobot@example.com", ["subject=current-issue"]] ok[-1] << {:to => "infobot@example.com", :headers => ["subject=current-issue"]} # mailto:infobot@example.com?body=send%20current-issue ok << ["mailto:infobot@example.com?body=send%20current-issue"] ok[-1] << ["infobot@example.com", ["body=send%20current-issue"]] ok[-1] << {:to => "infobot@example.com", :headers => ["body=send%20current-issue"]} # mailto:infobot@example.com?body=send%20current-issue%0D%0Asend%20index ok << ["mailto:infobot@example.com?body=send%20current-issue%0D%0Asend%20index"] ok[-1] << ["infobot@example.com", ["body=send%20current-issue%0D%0Asend%20index"]] ok[-1] << {:to => "infobot@example.com", :headers => ["body=send%20current-issue%0D%0Asend%20index"]} # mailto:foobar@example.com?In-Reply-To=%3c3469A91.D10AF4C@example.com ok << ["mailto:foobar@example.com?In-Reply-To=%3c3469A91.D10AF4C@example.com"] ok[-1] << ["foobar@example.com", ["In-Reply-To=%3c3469A91.D10AF4C@example.com"]] ok[-1] << {:to => "foobar@example.com", :headers => ["In-Reply-To=%3c3469A91.D10AF4C@example.com"]} # mailto:majordomo@example.com?body=subscribe%20bamboo-l ok << ["mailto:majordomo@example.com?body=subscribe%20bamboo-l"] ok[-1] << ["majordomo@example.com", ["body=subscribe%20bamboo-l"]] ok[-1] << {:to => "majordomo@example.com", :headers => ["body=subscribe%20bamboo-l"]} # mailto:joe@example.com?cc=bob@example.com&body=hello ok << ["mailto:joe@example.com?cc=bob@example.com&body=hello"] ok[-1] << ["joe@example.com", ["cc=bob@example.com", "body=hello"]] ok[-1] << {:to => "joe@example.com", :headers => ["cc=bob@example.com", "body=hello"]} # mailto:?to=joe@example.com&cc=bob@example.com&body=hello ok << ["mailto:?to=joe@example.com&cc=bob@example.com&body=hello"] ok[-1] << [nil, ["to=joe@example.com", "cc=bob@example.com", "body=hello"]] ok[-1] << {:headers => ["to=joe@example.com", "cc=bob@example.com", "body=hello"]} # mailto:gorby%25kremvax@example.com ok << ["mailto:gorby%25kremvax@example.com"] ok[-1] << ["gorby%25kremvax@example.com", nil] ok[-1] << {:to => "gorby%25kremvax@example.com"} # mailto:unlikely%3Faddress@example.com?blat=foop ok << ["mailto:unlikely%3Faddress@example.com?blat=foop"] ok[-1] << ["unlikely%3Faddress@example.com", ["blat=foop"]] ok[-1] << {:to => "unlikely%3Faddress@example.com", :headers => ["blat=foop"]} ok_all = ok.flatten.join("\0") # mailto:joe@example.com?cc=bob@example.com?body=hello ; WRONG! bad << ["joe@example.com", ["cc=bob@example.com?body=hello"]] # mailto:javascript:alert() bad << ["javascript:alert()", []] # '=' which is in hname or hvalue is wrong. bad << ["foo@example.jp?subject=1+1=2", []] ok.each do |x| assert_equal(x[0], @u.build(x[1]).to_s) assert_equal(x[0], @u.build(x[2]).to_s) end bad.each do |x| assert_raises(URI::InvalidComponentError) { @u.build(x) } end assert_equal(ok_all, ok.flatten.join("\0")) end def test_select u = URI.parse('mailto:joe@example.com?cc=bob@example.com&body=hello') assert_equal(uri_to_ary(u), u.select(*u.component)) assert_raises(ArgumentError) do u.select(:scheme, :host, :not_exist, :port) end end end end ================================================ FILE: test/webrick/.htaccess ================================================ this file should not be published. ================================================ FILE: test/webrick/test_cgi.rb ================================================ require "webrick" require File.join(File.dirname(__FILE__), "utils.rb") require "test/unit" class TestWEBrickCGI < Test::Unit::TestCase def test_cgi accepted = started = stopped = 0 requested0 = requested1 = 0 config = { :CGIInterpreter => TestWEBrick::RubyBin, :DocumentRoot => File.dirname(__FILE__), :DirectoryIndex => ["webrick.cgi"], } if RUBY_PLATFORM =~ /mswin32|mingw|cygwin|bccwin32/ config[:CGIPathEnv] = ENV['PATH'] # runtime dll may not be in system dir. end TestWEBrick.start_httpserver(config){|server, addr, port| http = Net::HTTP.new(addr, port) req = Net::HTTP::Get.new("/webrick.cgi") http.request(req){|res| assert_equal("/webrick.cgi", res.body)} req = Net::HTTP::Get.new("/webrick.cgi/path/info") http.request(req){|res| assert_equal("/path/info", res.body)} req = Net::HTTP::Get.new("/webrick.cgi/%3F%3F%3F?foo=bar") http.request(req){|res| assert_equal("/???", res.body)} req = Net::HTTP::Get.new("/webrick.cgi/%A4%DB%A4%B2/%A4%DB%A4%B2") http.request(req){|res| assert_equal("/\xA4\xDB\xA4\xB2/\xA4\xDB\xA4\xB2", res.body)} req = Net::HTTP::Get.new("/webrick.cgi?a=1;a=2;b=x") http.request(req){|res| assert_equal("a=1, a=2, b=x", res.body)} req = Net::HTTP::Get.new("/webrick.cgi?a=1&a=2&b=x") http.request(req){|res| assert_equal("a=1, a=2, b=x", res.body)} req = Net::HTTP::Post.new("/webrick.cgi?a=x;a=y;b=1") req["Content-Type"] = "application/x-www-form-urlencoded" http.request(req, "a=1;a=2;b=x"){|res| assert_equal("a=1, a=2, b=x", res.body)} req = Net::HTTP::Post.new("/webrick.cgi?a=x&a=y&b=1") req["Content-Type"] = "application/x-www-form-urlencoded" http.request(req, "a=1&a=2&b=x"){|res| assert_equal("a=1, a=2, b=x", res.body)} req = Net::HTTP::Get.new("/") http.request(req){|res| ary = res.body.to_a assert_match(%r{/$}, ary[0]) assert_match(%r{/webrick.cgi$}, ary[1]) } req = Net::HTTP::Get.new("/webrick.cgi") req["Cookie"] = "CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001" http.request(req){|res| assert_equal( "CUSTOMER=WILE_E_COYOTE\nPART_NUMBER=ROCKET_LAUNCHER_0001\n", res.body) } req = Net::HTTP::Get.new("/webrick.cgi") cookie = %{$Version="1"; } cookie << %{Customer="WILE_E_COYOTE"; $Path="/acme"; } cookie << %{Part_Number="Rocket_Launcher_0001"; $Path="/acme"; } cookie << %{Shipping="FedEx"; $Path="/acme"} req["Cookie"] = cookie http.request(req){|res| assert_equal("Customer=WILE_E_COYOTE, Shipping=FedEx", res["Set-Cookie"]) assert_equal("Customer=WILE_E_COYOTE\n" + "Part_Number=Rocket_Launcher_0001\n" + "Shipping=FedEx\n", res.body) } } end end ================================================ FILE: test/webrick/test_cookie.rb ================================================ require "test/unit" require "webrick/cookie" class TestWEBrickCookie < Test::Unit::TestCase def test_new cookie = WEBrick::Cookie.new("foo","bar") assert_equal("foo", cookie.name) assert_equal("bar", cookie.value) assert_equal("foo=bar", cookie.to_s) end def test_time cookie = WEBrick::Cookie.new("foo","bar") t = 1000000000 cookie.max_age = t assert_match(t.to_s, cookie.to_s) cookie = WEBrick::Cookie.new("foo","bar") t = Time.at(1000000000) cookie.expires = t assert_equal(Time, cookie.expires.class) assert_equal(t, cookie.expires) ts = t.httpdate cookie.expires = ts assert_equal(Time, cookie.expires.class) assert_equal(t, cookie.expires) assert_match(ts, cookie.to_s) end def test_parse data = "" data << '$Version="1"; ' data << 'Customer="WILE_E_COYOTE"; $Path="/acme"; ' data << 'Part_Number="Rocket_Launcher_0001"; $Path="/acme"; ' data << 'Shipping="FedEx"; $Path="/acme"' cookies = WEBrick::Cookie.parse(data) assert_equal(1, cookies[0].version) assert_equal("Customer", cookies[0].name) assert_equal("WILE_E_COYOTE", cookies[0].value) assert_equal("/acme", cookies[0].path) assert_equal(1, cookies[1].version) assert_equal("Part_Number", cookies[1].name) assert_equal("Rocket_Launcher_0001", cookies[1].value) assert_equal(1, cookies[2].version) assert_equal("Shipping", cookies[2].name) assert_equal("FedEx", cookies[2].value) data = "hoge=moge; __div__session=9865ecfd514be7f7" cookies = WEBrick::Cookie.parse(data) assert_equal(0, cookies[0].version) assert_equal("hoge", cookies[0].name) assert_equal("moge", cookies[0].value) assert_equal("__div__session", cookies[1].name) assert_equal("9865ecfd514be7f7", cookies[1].value) end def test_parse_set_cookie data = %(Customer="WILE_E_COYOTE"; Version="1"; Path="/acme") cookie = WEBrick::Cookie.parse_set_cookie(data) assert_equal("Customer", cookie.name) assert_equal("WILE_E_COYOTE", cookie.value) assert_equal(1, cookie.version) assert_equal("/acme", cookie.path) data = %(Shipping="FedEx"; Version="1"; Path="/acme"; Secure) cookie = WEBrick::Cookie.parse_set_cookie(data) assert_equal("Shipping", cookie.name) assert_equal("FedEx", cookie.value) assert_equal(1, cookie.version) assert_equal("/acme", cookie.path) assert_equal(true, cookie.secure) end def test_parse_set_cookies data = %(Shipping="FedEx"; Version="1"; Path="/acme"; Secure) data << %(, CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT; path=/; Secure) data << %(, name="Aaron"; Version="1"; path="/acme") cookies = WEBrick::Cookie.parse_set_cookies(data) assert_equal(3, cookies.length) fed_ex = cookies.find { |c| c.name == 'Shipping' } assert_not_nil(fed_ex) assert_equal("Shipping", fed_ex.name) assert_equal("FedEx", fed_ex.value) assert_equal(1, fed_ex.version) assert_equal("/acme", fed_ex.path) assert_equal(true, fed_ex.secure) name = cookies.find { |c| c.name == 'name' } assert_not_nil(name) assert_equal("name", name.name) assert_equal("Aaron", name.value) assert_equal(1, name.version) assert_equal("/acme", name.path) customer = cookies.find { |c| c.name == 'CUSTOMER' } assert_not_nil(customer) assert_equal("CUSTOMER", customer.name) assert_equal("WILE_E_COYOTE", customer.value) assert_equal(0, customer.version) assert_equal("/", customer.path) assert_equal(Time.utc(1999, 11, 9, 23, 12, 40), customer.expires) end end ================================================ FILE: test/webrick/test_filehandler.rb ================================================ require "test/unit" require "webrick" require "stringio" require File.join(File.dirname(__FILE__), "utils.rb") class WEBrick::TestFileHandler < Test::Unit::TestCase def default_file_handler(filename) klass = WEBrick::HTTPServlet::DefaultFileHandler klass.new(WEBrick::Config::HTTP, filename) end def windows? File.directory?("\\") end def get_res_body(res) return res.body.read rescue res.body end def make_range_request(range_spec) msg = <<-_end_of_request_ GET / HTTP/1.0 Range: #{range_spec} _end_of_request_ return StringIO.new(msg.gsub(/^ {6}/, "")) end def make_range_response(file, range_spec) req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) req.parse(make_range_request(range_spec)) res = WEBrick::HTTPResponse.new(WEBrick::Config::HTTP) size = File.size(file) handler = default_file_handler(file) handler.make_partial_content(req, res, file, size) return res end def test_make_partial_content filename = __FILE__ filesize = File.size(filename) res = make_range_response(filename, "bytes=#{filesize-100}-") assert_match(%r{^text/plain}, res["content-type"]) assert_equal(get_res_body(res).size, 100) res = make_range_response(filename, "bytes=-100") assert_match(%r{^text/plain}, res["content-type"]) assert_equal(get_res_body(res).size, 100) res = make_range_response(filename, "bytes=0-99") assert_match(%r{^text/plain}, res["content-type"]) assert_equal(get_res_body(res).size, 100) res = make_range_response(filename, "bytes=100-199") assert_match(%r{^text/plain}, res["content-type"]) assert_equal(get_res_body(res).size, 100) res = make_range_response(filename, "bytes=0-0") assert_match(%r{^text/plain}, res["content-type"]) assert_equal(get_res_body(res).size, 1) res = make_range_response(filename, "bytes=-1") assert_match(%r{^text/plain}, res["content-type"]) assert_equal(get_res_body(res).size, 1) res = make_range_response(filename, "bytes=0-0, -2") assert_match(%r{^multipart/byteranges}, res["content-type"]) end def test_filehandler config = { :DocumentRoot => File.dirname(__FILE__), } this_file = File.basename(__FILE__) TestWEBrick.start_httpserver(config) do |server, addr, port| http = Net::HTTP.new(addr, port) req = Net::HTTP::Get.new("/") http.request(req){|res| assert_equal("200", res.code) assert_equal("text/html", res.content_type) assert_match(/HREF="#{this_file}"/, res.body) } req = Net::HTTP::Get.new("/#{this_file}") http.request(req){|res| assert_equal("200", res.code) assert_equal("text/plain", res.content_type) assert_equal(File.read(__FILE__), res.body) } end end def test_non_disclosure_name config = { :DocumentRoot => File.dirname(__FILE__), } this_file = File.basename(__FILE__) TestWEBrick.start_httpserver(config) do |server, addr, port| http = Net::HTTP.new(addr, port) doc_root_opts = server[:DocumentRootOptions] doc_root_opts[:NondisclosureName] = %w(.ht* *~ test_*) req = Net::HTTP::Get.new("/") http.request(req){|res| assert_equal("200", res.code) assert_equal("text/html", res.content_type) assert_no_match(/HREF="#{File.basename(__FILE__)}"/, res.body) } req = Net::HTTP::Get.new("/#{this_file}") http.request(req){|res| assert_equal("404", res.code) } doc_root_opts[:NondisclosureName] = %w(.ht* *~ TEST_*) http.request(req){|res| assert_equal("404", res.code) } end end def test_directory_traversal config = { :DocumentRoot => File.dirname(__FILE__), } this_file = File.basename(__FILE__) TestWEBrick.start_httpserver(config) do |server, addr, port| http = Net::HTTP.new(addr, port) req = Net::HTTP::Get.new("/../../") http.request(req){|res| assert_equal("400", res.code) } req = Net::HTTP::Get.new("/..%5c../#{File.basename(__FILE__)}") http.request(req){|res| assert_equal(windows? ? "200" : "404", res.code) } req = Net::HTTP::Get.new("/..%5c..%5cruby.c") http.request(req){|res| assert_equal("404", res.code) } end end def test_unwise_in_path if windows? config = { :DocumentRoot => File.dirname(__FILE__), } this_file = File.basename(__FILE__) TestWEBrick.start_httpserver(config) do |server, addr, port| http = Net::HTTP.new(addr, port) req = Net::HTTP::Get.new("/..%5c..") http.request(req){|res| assert_equal("301", res.code) } end end end def test_short_filename config = { :CGIInterpreter => TestWEBrick::RubyBin, :DocumentRoot => File.dirname(__FILE__), :CGIPathEnv => ENV['PATH'], } TestWEBrick.start_httpserver(config) do |server, addr, port| http = Net::HTTP.new(addr, port) req = Net::HTTP::Get.new("/webric~1.cgi/test") http.request(req) do |res| if windows? assert_equal("200", res.code) assert_equal("/test", res.body) else assert_equal("404", res.code) end end req = Net::HTTP::Get.new("/.htaccess") http.request(req) {|res| assert_equal("404", res.code) } req = Net::HTTP::Get.new("/htacce~1") http.request(req) {|res| assert_equal("404", res.code) } req = Net::HTTP::Get.new("/HTACCE~1") http.request(req) {|res| assert_equal("404", res.code) } end end def test_script_disclosure config = { :CGIInterpreter => TestWEBrick::RubyBin, :DocumentRoot => File.dirname(__FILE__), :CGIPathEnv => ENV['PATH'], } TestWEBrick.start_httpserver(config) do |server, addr, port| http = Net::HTTP.new(addr, port) req = Net::HTTP::Get.new("/webrick.cgi/test") http.request(req) do |res| assert_equal("200", res.code) assert_equal("/test", res.body) end response_assertion = Proc.new do |res| if windows? assert_equal("200", res.code) assert_equal("/test", res.body) else assert_equal("404", res.code) end end req = Net::HTTP::Get.new("/webrick.cgi%20/test") http.request(req, &response_assertion) req = Net::HTTP::Get.new("/webrick.cgi./test") http.request(req, &response_assertion) req = Net::HTTP::Get.new("/webrick.cgi::$DATA/test") http.request(req, &response_assertion) end end end ================================================ FILE: test/webrick/test_httpauth.rb ================================================ require "test/unit" require "net/http" require "tempfile" require "webrick" require "webrick/httpauth/basicauth" require File.join(File.dirname(__FILE__), "utils.rb") class TestWEBrickHTTPAuth < Test::Unit::TestCase def test_basic_auth TestWEBrick.start_httpserver{|server, addr, port| realm = "WEBrick's realm" path = "/basic_auth" server.mount_proc(path){|req, res| WEBrick::HTTPAuth.basic_auth(req, res, realm){|user, pass| user == "webrick" && pass == "supersecretpassword" } res.body = "hoge" } http = Net::HTTP.new(addr, port) g = Net::HTTP::Get.new(path) g.basic_auth("webrick", "supersecretpassword") http.request(g){|res| assert_equal("hoge", res.body)} g.basic_auth("webrick", "not super") http.request(g){|res| assert_not_equal("hoge", res.body)} } end def test_basic_auth2 TestWEBrick.start_httpserver{|server, addr, port| realm = "WEBrick's realm" path = "/basic_auth2" tmpfile = Tempfile.new("test_webrick_auth") tmpfile.close tmp_pass = WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path) tmp_pass.set_passwd(realm, "webrick", "supersecretpassword") tmp_pass.set_passwd(realm, "foo", "supersecretpassword") tmp_pass.flush htpasswd = WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path) users = [] htpasswd.each{|user, pass| users << user } assert_equal(2, users.size) assert(users.member?("webrick")) assert(users.member?("foo")) server.mount_proc(path){|req, res| auth = WEBrick::HTTPAuth::BasicAuth.new( :Realm => realm, :UserDB => htpasswd, :Logger => server.logger ) auth.authenticate(req, res) res.body = "hoge" } http = Net::HTTP.new(addr, port) g = Net::HTTP::Get.new(path) g.basic_auth("webrick", "supersecretpassword") http.request(g){|res| assert_equal("hoge", res.body)} g.basic_auth("webrick", "not super") http.request(g){|res| assert_not_equal("hoge", res.body)} } end def test_basic_auth3 tmpfile = Tempfile.new("test_webrick_auth") tmpfile.puts("webrick:{SHA}GJYFRpBbdchp595jlh3Bhfmgp8k=") tmpfile.flush assert_raises(NotImplementedError){ WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path) } tmpfile.close(true) tmpfile = Tempfile.new("test_webrick_auth") tmpfile.puts("webrick:$apr1$IOVMD/..$rmnOSPXr0.wwrLPZHBQZy0") tmpfile.flush assert_raises(NotImplementedError){ WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path) } tmpfile.close(true) end end ================================================ FILE: test/webrick/test_httprequest.rb ================================================ require "webrick" require "stringio" require "test/unit" class TestWEBrickHTTPRequest < Test::Unit::TestCase def test_parse_09 msg = <<-_end_of_message_ GET / foobar # HTTP/0.9 request don't have header nor entity body. _end_of_message_ req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) req.parse(StringIO.new(msg.gsub(/^ {6}/, ""))) assert_equal("GET", req.request_method) assert_equal("/", req.unparsed_uri) assert_equal(WEBrick::HTTPVersion.new("0.9"), req.http_version) assert_equal(WEBrick::Config::HTTP[:ServerName], req.host) assert_equal(80, req.port) assert_equal(false, req.keep_alive?) assert_equal(nil, req.body) assert(req.query.empty?) end def test_parse_10 msg = <<-_end_of_message_ GET / HTTP/1.0 _end_of_message_ req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) req.parse(StringIO.new(msg.gsub(/^ {6}/, ""))) assert_equal("GET", req.request_method) assert_equal("/", req.unparsed_uri) assert_equal(WEBrick::HTTPVersion.new("1.0"), req.http_version) assert_equal(WEBrick::Config::HTTP[:ServerName], req.host) assert_equal(80, req.port) assert_equal(false, req.keep_alive?) assert_equal(nil, req.body) assert(req.query.empty?) end def test_parse_11 msg = <<-_end_of_message_ GET /path HTTP/1.1 _end_of_message_ req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) req.parse(StringIO.new(msg.gsub(/^ {6}/, ""))) assert_equal("GET", req.request_method) assert_equal("/path", req.unparsed_uri) assert_equal("", req.script_name) assert_equal("/path", req.path_info) assert_equal(WEBrick::HTTPVersion.new("1.1"), req.http_version) assert_equal(WEBrick::Config::HTTP[:ServerName], req.host) assert_equal(80, req.port) assert_equal(true, req.keep_alive?) assert_equal(nil, req.body) assert(req.query.empty?) end def test_parse_headers msg = <<-_end_of_message_ GET /path HTTP/1.1 Host: test.ruby-lang.org:8080 Connection: close Accept: text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5 Accept-Encoding: compress;q=0.5 Accept-Encoding: gzip;q=1.0, identity; q=0.4, *;q=0 Accept-Language: en;q=0.5, *; q=0 Accept-Language: ja Content-Type: text/plain Content-Length: 7 foobar _end_of_message_ req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) req.parse(StringIO.new(msg.gsub(/^ {6}/, ""))) assert_equal( URI.parse("http://test.ruby-lang.org:8080/path"), req.request_uri) assert_equal("test.ruby-lang.org", req.host) assert_equal(8080, req.port) assert_equal(false, req.keep_alive?) assert_equal( %w(text/html;level=1 text/html */* text/html;level=2 text/*), req.accept) assert_equal(%w(gzip compress identity *), req.accept_encoding) assert_equal(%w(ja en *), req.accept_language) assert_equal(7, req.content_length) assert_equal("text/plain", req.content_type) assert_equal("foobar\n", req.body) assert(req.query.empty?) end def test_parse_header2() msg = <<-_end_of_message_ POST /foo/bar/../baz?q=a HTTP/1.0 Content-Length: 9 User-Agent: FOO BAR BAZ hogehoge _end_of_message_ req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) req.parse(StringIO.new(msg.gsub(/^ {6}/, ""))) assert_equal("POST", req.request_method) assert_equal("/foo/baz", req.path) assert_equal("", req.script_name) assert_equal("/foo/baz", req.path_info) assert_equal("9", req['content-length']) assert_equal("FOO BAR BAZ", req['user-agent']) assert_equal("hogehoge\n", req.body) end def test_parse_headers3 msg = <<-_end_of_message_ GET /path HTTP/1.1 Host: test.ruby-lang.org _end_of_message_ req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) req.parse(StringIO.new(msg.gsub(/^ {6}/, ""))) assert_equal(URI.parse("http://test.ruby-lang.org/path"), req.request_uri) assert_equal("test.ruby-lang.org", req.host) assert_equal(80, req.port) msg = <<-_end_of_message_ GET /path HTTP/1.1 Host: 192.168.1.1 _end_of_message_ req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) req.parse(StringIO.new(msg.gsub(/^ {6}/, ""))) assert_equal(URI.parse("http://192.168.1.1/path"), req.request_uri) assert_equal("192.168.1.1", req.host) assert_equal(80, req.port) msg = <<-_end_of_message_ GET /path HTTP/1.1 Host: [fe80::208:dff:feef:98c7] _end_of_message_ req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) req.parse(StringIO.new(msg.gsub(/^ {6}/, ""))) assert_equal(URI.parse("http://[fe80::208:dff:feef:98c7]/path"), req.request_uri) assert_equal("[fe80::208:dff:feef:98c7]", req.host) assert_equal(80, req.port) msg = <<-_end_of_message_ GET /path HTTP/1.1 Host: 192.168.1.1:8080 _end_of_message_ req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) req.parse(StringIO.new(msg.gsub(/^ {6}/, ""))) assert_equal(URI.parse("http://192.168.1.1:8080/path"), req.request_uri) assert_equal("192.168.1.1", req.host) assert_equal(8080, req.port) msg = <<-_end_of_message_ GET /path HTTP/1.1 Host: [fe80::208:dff:feef:98c7]:8080 _end_of_message_ req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) req.parse(StringIO.new(msg.gsub(/^ {6}/, ""))) assert_equal(URI.parse("http://[fe80::208:dff:feef:98c7]:8080/path"), req.request_uri) assert_equal("[fe80::208:dff:feef:98c7]", req.host) assert_equal(8080, req.port) end def test_parse_get_params param = "foo=1;foo=2;foo=3;bar=x" msg = <<-_end_of_message_ GET /path?#{param} HTTP/1.1 Host: test.ruby-lang.org:8080 _end_of_message_ req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) req.parse(StringIO.new(msg.gsub(/^ {6}/, ""))) query = req.query assert_equal("1", query["foo"]) assert_equal(["1", "2", "3"], query["foo"].to_ary) assert_equal(["1", "2", "3"], query["foo"].list) assert_equal("x", query["bar"]) assert_equal(["x"], query["bar"].list) end def test_parse_post_params param = "foo=1;foo=2;foo=3;bar=x" msg = <<-_end_of_message_ POST /path?foo=x;foo=y;foo=z;bar=1 HTTP/1.1 Host: test.ruby-lang.org:8080 Content-Length: #{param.size} Content-Type: application/x-www-form-urlencoded #{param} _end_of_message_ req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) req.parse(StringIO.new(msg.gsub(/^ {6}/, ""))) query = req.query assert_equal("1", query["foo"]) assert_equal(["1", "2", "3"], query["foo"].to_ary) assert_equal(["1", "2", "3"], query["foo"].list) assert_equal("x", query["bar"]) assert_equal(["x"], query["bar"].list) end def test_chunked crlf = "\x0d\x0a" msg = <<-_end_of_message_ POST /path HTTP/1.1 Host: test.ruby-lang.org:8080 Transfer-Encoding: chunked _end_of_message_ msg.gsub!(/^ {6}/, "") open(__FILE__){|io| while chunk = io.read(100) msg << chunk.size.to_s(16) << crlf msg << chunk << crlf end } msg << "0" << crlf req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) req.parse(StringIO.new(msg)) assert_equal(File.read(__FILE__), req.body) end def test_bad_messages param = "foo=1;foo=2;foo=3;bar=x" msg = <<-_end_of_message_ POST /path?foo=x;foo=y;foo=z;bar=1 HTTP/1.1 Host: test.ruby-lang.org:8080 Content-Type: application/x-www-form-urlencoded #{param} _end_of_message_ assert_raises(WEBrick::HTTPStatus::LengthRequired){ req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) req.parse(StringIO.new(msg.gsub(/^ {6}/, ""))) req.body } msg = <<-_end_of_message_ POST /path?foo=x;foo=y;foo=z;bar=1 HTTP/1.1 Host: test.ruby-lang.org:8080 Content-Length: 100000 body is too short. _end_of_message_ assert_raises(WEBrick::HTTPStatus::BadRequest){ req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) req.parse(StringIO.new(msg.gsub(/^ {6}/, ""))) req.body } msg = <<-_end_of_message_ POST /path?foo=x;foo=y;foo=z;bar=1 HTTP/1.1 Host: test.ruby-lang.org:8080 Transfer-Encoding: foobar body is too short. _end_of_message_ assert_raises(WEBrick::HTTPStatus::NotImplemented){ req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) req.parse(StringIO.new(msg.gsub(/^ {6}/, ""))) req.body } end end ================================================ FILE: test/webrick/test_httpserver.rb ================================================ require "test/unit" require "net/http" require "webrick" require File.join(File.dirname(__FILE__), "utils.rb") class TestWEBrickHTTPServer < Test::Unit::TestCase def test_mount httpd = WEBrick::HTTPServer.new( :Logger => WEBrick::Log.new(TestWEBrick::NullWriter), :DoNotListen=>true ) httpd.mount("/", :Root) httpd.mount("/foo", :Foo) httpd.mount("/foo/bar", :Bar, :bar1) httpd.mount("/foo/bar/baz", :Baz, :baz1, :baz2) serv, opts, script_name, path_info = httpd.search_servlet("/") assert_equal(:Root, serv) assert_equal([], opts) assert_equal(script_name, "") assert_equal(path_info, "/") serv, opts, script_name, path_info = httpd.search_servlet("/sub") assert_equal(:Root, serv) assert_equal([], opts) assert_equal(script_name, "") assert_equal(path_info, "/sub") serv, opts, script_name, path_info = httpd.search_servlet("/sub/") assert_equal(:Root, serv) assert_equal([], opts) assert_equal(script_name, "") assert_equal(path_info, "/sub/") serv, opts, script_name, path_info = httpd.search_servlet("/foo") assert_equal(:Foo, serv) assert_equal([], opts) assert_equal(script_name, "/foo") assert_equal(path_info, "") serv, opts, script_name, path_info = httpd.search_servlet("/foo/") assert_equal(:Foo, serv) assert_equal([], opts) assert_equal(script_name, "/foo") assert_equal(path_info, "/") serv, opts, script_name, path_info = httpd.search_servlet("/foo/sub") assert_equal(:Foo, serv) assert_equal([], opts) assert_equal(script_name, "/foo") assert_equal(path_info, "/sub") serv, opts, script_name, path_info = httpd.search_servlet("/foo/bar") assert_equal(:Bar, serv) assert_equal([:bar1], opts) assert_equal(script_name, "/foo/bar") assert_equal(path_info, "") serv, opts, script_name, path_info = httpd.search_servlet("/foo/bar/baz") assert_equal(:Baz, serv) assert_equal([:baz1, :baz2], opts) assert_equal(script_name, "/foo/bar/baz") assert_equal(path_info, "") end class Req attr_reader :port, :host def initialize(addr, port, host) @addr, @port, @host = addr, port, host end def addr [0,0,0,@addr] end end def httpd(addr, port, host, ali) config ={ :Logger => WEBrick::Log.new(TestWEBrick::NullWriter), :DoNotListen => true, :BindAddress => addr, :Port => port, :ServerName => host, :ServerAlias => ali, } return WEBrick::HTTPServer.new(config) end def assert_eql?(v1, v2) assert_equal(v1.object_id, v2.object_id) end def test_lookup_server addr1 = "192.168.100.1" addr2 = "192.168.100.2" addrz = "192.168.100.254" local = "127.0.0.1" port1 = 80 port2 = 8080 port3 = 10080 portz = 32767 name1 = "www.example.com" name2 = "www2.example.com" name3 = "www3.example.com" namea = "www.example.co.jp" nameb = "www.example.jp" namec = "www2.example.co.jp" named = "www2.example.jp" namez = "foobar.example.com" alias1 = [namea, nameb] alias2 = [namec, named] host1 = httpd(nil, port1, name1, nil) hosts = [ host2 = httpd(addr1, port1, name1, nil), host3 = httpd(addr1, port1, name2, alias1), host4 = httpd(addr1, port2, name1, nil), host5 = httpd(addr1, port2, name2, alias1), host6 = httpd(addr1, port2, name3, alias2), host7 = httpd(addr2, nil, name1, nil), host8 = httpd(addr2, nil, name2, alias1), host9 = httpd(addr2, nil, name3, alias2), host10 = httpd(local, nil, nil, nil), host11 = httpd(nil, port3, nil, nil), ].sort_by{ rand } hosts.each{|h| host1.virtual_host(h) } # connect to addr1 assert_eql?(host2, host1.lookup_server(Req.new(addr1, port1, name1))) assert_eql?(host3, host1.lookup_server(Req.new(addr1, port1, name2))) assert_eql?(host3, host1.lookup_server(Req.new(addr1, port1, namea))) assert_eql?(host3, host1.lookup_server(Req.new(addr1, port1, nameb))) assert_eql?(nil, host1.lookup_server(Req.new(addr1, port1, namez))) assert_eql?(host4, host1.lookup_server(Req.new(addr1, port2, name1))) assert_eql?(host5, host1.lookup_server(Req.new(addr1, port2, name2))) assert_eql?(host5, host1.lookup_server(Req.new(addr1, port2, namea))) assert_eql?(host5, host1.lookup_server(Req.new(addr1, port2, nameb))) assert_eql?(nil, host1.lookup_server(Req.new(addr1, port2, namez))) assert_eql?(host11, host1.lookup_server(Req.new(addr1, port3, name1))) assert_eql?(host11, host1.lookup_server(Req.new(addr1, port3, name2))) assert_eql?(host11, host1.lookup_server(Req.new(addr1, port3, namea))) assert_eql?(host11, host1.lookup_server(Req.new(addr1, port3, nameb))) assert_eql?(host11, host1.lookup_server(Req.new(addr1, port3, namez))) assert_eql?(nil, host1.lookup_server(Req.new(addr1, portz, name1))) assert_eql?(nil, host1.lookup_server(Req.new(addr1, portz, name2))) assert_eql?(nil, host1.lookup_server(Req.new(addr1, portz, namea))) assert_eql?(nil, host1.lookup_server(Req.new(addr1, portz, nameb))) assert_eql?(nil, host1.lookup_server(Req.new(addr1, portz, namez))) # connect to addr2 assert_eql?(host7, host1.lookup_server(Req.new(addr2, port1, name1))) assert_eql?(host8, host1.lookup_server(Req.new(addr2, port1, name2))) assert_eql?(host8, host1.lookup_server(Req.new(addr2, port1, namea))) assert_eql?(host8, host1.lookup_server(Req.new(addr2, port1, nameb))) assert_eql?(nil, host1.lookup_server(Req.new(addr2, port1, namez))) assert_eql?(host7, host1.lookup_server(Req.new(addr2, port2, name1))) assert_eql?(host8, host1.lookup_server(Req.new(addr2, port2, name2))) assert_eql?(host8, host1.lookup_server(Req.new(addr2, port2, namea))) assert_eql?(host8, host1.lookup_server(Req.new(addr2, port2, nameb))) assert_eql?(nil, host1.lookup_server(Req.new(addr2, port2, namez))) assert_eql?(host7, host1.lookup_server(Req.new(addr2, port3, name1))) assert_eql?(host8, host1.lookup_server(Req.new(addr2, port3, name2))) assert_eql?(host8, host1.lookup_server(Req.new(addr2, port3, namea))) assert_eql?(host8, host1.lookup_server(Req.new(addr2, port3, nameb))) assert_eql?(host11, host1.lookup_server(Req.new(addr2, port3, namez))) assert_eql?(host7, host1.lookup_server(Req.new(addr2, portz, name1))) assert_eql?(host8, host1.lookup_server(Req.new(addr2, portz, name2))) assert_eql?(host8, host1.lookup_server(Req.new(addr2, portz, namea))) assert_eql?(host8, host1.lookup_server(Req.new(addr2, portz, nameb))) assert_eql?(nil, host1.lookup_server(Req.new(addr2, portz, namez))) # connect to addrz assert_eql?(nil, host1.lookup_server(Req.new(addrz, port1, name1))) assert_eql?(nil, host1.lookup_server(Req.new(addrz, port1, name2))) assert_eql?(nil, host1.lookup_server(Req.new(addrz, port1, namea))) assert_eql?(nil, host1.lookup_server(Req.new(addrz, port1, nameb))) assert_eql?(nil, host1.lookup_server(Req.new(addrz, port1, namez))) assert_eql?(nil, host1.lookup_server(Req.new(addrz, port2, name1))) assert_eql?(nil, host1.lookup_server(Req.new(addrz, port2, name2))) assert_eql?(nil, host1.lookup_server(Req.new(addrz, port2, namea))) assert_eql?(nil, host1.lookup_server(Req.new(addrz, port2, nameb))) assert_eql?(nil, host1.lookup_server(Req.new(addrz, port2, namez))) assert_eql?(host11, host1.lookup_server(Req.new(addrz, port3, name1))) assert_eql?(host11, host1.lookup_server(Req.new(addrz, port3, name2))) assert_eql?(host11, host1.lookup_server(Req.new(addrz, port3, namea))) assert_eql?(host11, host1.lookup_server(Req.new(addrz, port3, nameb))) assert_eql?(host11, host1.lookup_server(Req.new(addrz, port3, namez))) assert_eql?(nil, host1.lookup_server(Req.new(addrz, portz, name1))) assert_eql?(nil, host1.lookup_server(Req.new(addrz, portz, name2))) assert_eql?(nil, host1.lookup_server(Req.new(addrz, portz, namea))) assert_eql?(nil, host1.lookup_server(Req.new(addrz, portz, nameb))) assert_eql?(nil, host1.lookup_server(Req.new(addrz, portz, namez))) # connect to localhost assert_eql?(host10, host1.lookup_server(Req.new(local, port1, name1))) assert_eql?(host10, host1.lookup_server(Req.new(local, port1, name2))) assert_eql?(host10, host1.lookup_server(Req.new(local, port1, namea))) assert_eql?(host10, host1.lookup_server(Req.new(local, port1, nameb))) assert_eql?(host10, host1.lookup_server(Req.new(local, port1, namez))) assert_eql?(host10, host1.lookup_server(Req.new(local, port2, name1))) assert_eql?(host10, host1.lookup_server(Req.new(local, port2, name2))) assert_eql?(host10, host1.lookup_server(Req.new(local, port2, namea))) assert_eql?(host10, host1.lookup_server(Req.new(local, port2, nameb))) assert_eql?(host10, host1.lookup_server(Req.new(local, port2, namez))) assert_eql?(host10, host1.lookup_server(Req.new(local, port3, name1))) assert_eql?(host10, host1.lookup_server(Req.new(local, port3, name2))) assert_eql?(host10, host1.lookup_server(Req.new(local, port3, namea))) assert_eql?(host10, host1.lookup_server(Req.new(local, port3, nameb))) assert_eql?(host10, host1.lookup_server(Req.new(local, port3, namez))) assert_eql?(host10, host1.lookup_server(Req.new(local, portz, name1))) assert_eql?(host10, host1.lookup_server(Req.new(local, portz, name2))) assert_eql?(host10, host1.lookup_server(Req.new(local, portz, namea))) assert_eql?(host10, host1.lookup_server(Req.new(local, portz, nameb))) assert_eql?(host10, host1.lookup_server(Req.new(local, portz, namez))) end def test_callbacks accepted = started = stopped = 0 requested0 = requested1 = 0 config = { :ServerName => "localhost", :AcceptCallback => Proc.new{ accepted += 1 }, :StartCallback => Proc.new{ started += 1 }, :StopCallback => Proc.new{ stopped += 1 }, :RequestCallback => Proc.new{|req, res| requested0 += 1 }, } TestWEBrick.start_httpserver(config){|server, addr, port| vhost_config = { :ServerName => "myhostname", :BindAddress => addr, :Port => port, :DoNotListen => true, :Logger => WEBrick::Log.new(TestWEBrick::NullWriter), :AccessLog => [], :RequestCallback => Proc.new{|req, res| requested1 += 1 }, } server.virtual_host(WEBrick::HTTPServer.new(vhost_config)) true while server.status != :Running assert_equal(started, 1) assert_equal(stopped, 0) assert_equal(accepted, 0) http = Net::HTTP.new(addr, port) req = Net::HTTP::Get.new("/") req["Host"] = "myhostname:#{port}" http.request(req){|res| assert_equal("404", res.code)} http.request(req){|res| assert_equal("404", res.code)} http.request(req){|res| assert_equal("404", res.code)} req["Host"] = "localhost:#{port}" http.request(req){|res| assert_equal("404", res.code)} http.request(req){|res| assert_equal("404", res.code)} http.request(req){|res| assert_equal("404", res.code)} assert_equal(6, accepted) assert_equal(3, requested0) assert_equal(3, requested1) } assert_equal(started, 1) assert_equal(stopped, 1) end end ================================================ FILE: test/webrick/test_httputils.rb ================================================ require "test/unit" require "webrick/httputils" class TestWEBrickHTTPUtils < Test::Unit::TestCase include WEBrick::HTTPUtils def test_normilize_path assert_equal("/foo", normalize_path("/foo")) assert_equal("/foo/bar/", normalize_path("/foo/bar/")) assert_equal("/", normalize_path("/foo/../")) assert_equal("/", normalize_path("/foo/..")) assert_equal("/", normalize_path("/foo/bar/../../")) assert_equal("/", normalize_path("/foo/bar/../..")) assert_equal("/", normalize_path("/foo/bar/../..")) assert_equal("/baz", normalize_path("/foo/bar/../../baz")) assert_equal("/baz", normalize_path("/foo/../bar/../baz")) assert_equal("/baz/", normalize_path("/foo/../bar/../baz/")) assert_equal("/...", normalize_path("/bar/../...")) assert_equal("/.../", normalize_path("/bar/../.../")) assert_equal("/foo/", normalize_path("/foo/./")) assert_equal("/foo/", normalize_path("/foo/.")) assert_equal("/foo/", normalize_path("/foo/././")) assert_equal("/foo/", normalize_path("/foo/./.")) assert_equal("/foo/bar", normalize_path("/foo/./bar")) assert_equal("/foo/bar/", normalize_path("/foo/./bar/.")) assert_equal("/foo/bar/", normalize_path("/./././foo/./bar/.")) assert_equal("/foo/bar/", normalize_path("//foo///.//bar/.///.//")) assert_equal("/", normalize_path("//foo///..///bar/.///..//.//")) assert_raises(RuntimeError){ normalize_path("foo/bar") } assert_raises(RuntimeError){ normalize_path("..") } assert_raises(RuntimeError){ normalize_path("/..") } assert_raises(RuntimeError){ normalize_path("/./..") } assert_raises(RuntimeError){ normalize_path("/./../") } assert_raises(RuntimeError){ normalize_path("/./../..") } assert_raises(RuntimeError){ normalize_path("/./../../") } assert_raises(RuntimeError){ normalize_path("/./../") } assert_raises(RuntimeError){ normalize_path("/../..") } assert_raises(RuntimeError){ normalize_path("/../../") } assert_raises(RuntimeError){ normalize_path("/../../..") } assert_raises(RuntimeError){ normalize_path("/../../../") } assert_raises(RuntimeError){ normalize_path("/../foo/../") } assert_raises(RuntimeError){ normalize_path("/../foo/../../") } assert_raises(RuntimeError){ normalize_path("/foo/bar/../../../../") } assert_raises(RuntimeError){ normalize_path("/foo/../bar/../../") } assert_raises(RuntimeError){ normalize_path("/./../bar/") } assert_raises(RuntimeError){ normalize_path("/./../") } end def test_split_header_value assert_equal(['foo', 'bar'], split_header_value('foo, bar')) assert_equal(['"foo"', 'bar'], split_header_value('"foo", bar')) assert_equal(['foo', '"bar"'], split_header_value('foo, "bar"')) assert_equal(['*'], split_header_value('*')) assert_equal(['W/"xyzzy"', 'W/"r2d2xxxx"', 'W/"c3piozzzz"'], split_header_value('W/"xyzzy", W/"r2d2xxxx", W/"c3piozzzz"')) end def test_escape assert_equal("/foo/bar", escape("/foo/bar")) assert_equal("/~foo/bar", escape("/~foo/bar")) assert_equal("/~foo%20bar", escape("/~foo bar")) assert_equal("/~foo%20bar", escape("/~foo bar")) assert_equal("/~foo%09bar", escape("/~foo\tbar")) assert_equal("/~foo+bar", escape("/~foo+bar")) end def test_escape_form assert_equal("%2Ffoo%2Fbar", escape_form("/foo/bar")) assert_equal("%2F~foo%2Fbar", escape_form("/~foo/bar")) assert_equal("%2F~foo+bar", escape_form("/~foo bar")) assert_equal("%2F~foo+%2B+bar", escape_form("/~foo + bar")) end def test_unescape assert_equal("/foo/bar", unescape("%2ffoo%2fbar")) assert_equal("/~foo/bar", unescape("/%7efoo/bar")) assert_equal("/~foo/bar", unescape("%2f%7efoo%2fbar")) assert_equal("/~foo+bar", unescape("/%7efoo+bar")) end def test_unescape_form assert_equal("//foo/bar", unescape_form("/%2Ffoo/bar")) assert_equal("//foo/bar baz", unescape_form("/%2Ffoo/bar+baz")) assert_equal("/~foo/bar baz", unescape_form("/%7Efoo/bar+baz")) end def test_escape_path assert_equal("/foo/bar", escape_path("/foo/bar")) assert_equal("/foo/bar/", escape_path("/foo/bar/")) assert_equal("/%25foo/bar/", escape_path("/%foo/bar/")) end end ================================================ FILE: test/webrick/test_httpversion.rb ================================================ require "test/unit" require "webrick/httpversion" class TestWEBrickHTTPVersion < Test::Unit::TestCase def setup @v09 = WEBrick::HTTPVersion.new("0.9") @v10 = WEBrick::HTTPVersion.new("1.0") @v11 = WEBrick::HTTPVersion.new("1.001") end def test_to_s() assert_equal("0.9", @v09.to_s) assert_equal("1.0", @v10.to_s) assert_equal("1.1", @v11.to_s) end def test_major() assert_equal(0, @v09.major) assert_equal(1, @v10.major) assert_equal(1, @v11.major) end def test_minor() assert_equal(9, @v09.minor) assert_equal(0, @v10.minor) assert_equal(1, @v11.minor) end def test_compar() assert_equal(0, @v09 <=> "0.9") assert_equal(0, @v09 <=> "0.09") assert_equal(-1, @v09 <=> @v10) assert_equal(-1, @v09 <=> "1.00") assert_equal(1, @v11 <=> @v09) assert_equal(1, @v11 <=> "1.0") assert_equal(1, @v11 <=> "0.9") end end ================================================ FILE: test/webrick/test_server.rb ================================================ require "test/unit" require "tempfile" require "webrick" require File.join(File.dirname(__FILE__), "utils.rb") class TestWEBrickServer < Test::Unit::TestCase class Echo < WEBrick::GenericServer def run(sock) while line = sock.gets sock << line end end end def test_server TestWEBrick.start_server(Echo){|server, addr, port| TCPSocket.open(addr, port){|sock| sock.puts("foo"); assert_equal("foo\n", sock.gets) sock.puts("bar"); assert_equal("bar\n", sock.gets) sock.puts("baz"); assert_equal("baz\n", sock.gets) sock.puts("qux"); assert_equal("qux\n", sock.gets) } } end def test_callbacks accepted = started = stopped = 0 config = { :AcceptCallback => Proc.new{ accepted += 1 }, :StartCallback => Proc.new{ started += 1 }, :StopCallback => Proc.new{ stopped += 1 }, } TestWEBrick.start_server(Echo, config){|server, addr, port| true while server.status != :Running assert_equal(started, 1) assert_equal(stopped, 0) assert_equal(accepted, 0) TCPSocket.open(addr, port){|sock| (sock << "foo\n").gets } TCPSocket.open(addr, port){|sock| (sock << "foo\n").gets } TCPSocket.open(addr, port){|sock| (sock << "foo\n").gets } assert_equal(accepted, 3) } assert_equal(started, 1) assert_equal(stopped, 1) end def test_daemon begin r, w = IO.pipe Process.fork{ r.close WEBrick::Daemon.start w.puts(Process.pid) sleep } assert(Process.kill(:KILL, r.gets.to_i)) rescue NotImplementedError # snip this test ensure r.close w.close end end end ================================================ FILE: test/webrick/utils.rb ================================================ begin loadpath = $:.dup $:.replace($: | [File.expand_path("../ruby", File.dirname(__FILE__))]) require 'envutil' ensure $:.replace(loadpath) end require "webrick" begin require "webrick/https" rescue LoadError end require "webrick/httpproxy" module TestWEBrick NullWriter = Object.new def NullWriter.<<(msg) puts msg if $DEBUG return self end RubyBin = "\"#{EnvUtil.rubybin}\"" RubyBin << " \"-I#{File.expand_path("../..", File.dirname(__FILE__))}/lib\"" RubyBin << " \"-I#{File.dirname(EnvUtil.rubybin)}/.ext/common\"" RubyBin << " \"-I#{File.dirname(EnvUtil.rubybin)}/.ext/#{RUBY_PLATFORM}\"" module_function def start_server(klass, config={}, &block) server = klass.new({ :BindAddress => "127.0.0.1", :Port => 0, :Logger => WEBrick::Log.new(NullWriter), :AccessLog => [[NullWriter, ""]] }.update(config)) begin thread = Thread.start{ server.start } addr = server.listeners[0].addr block.call([server, addr[3], addr[1]]) ensure server.stop thread.join end end def start_httpserver(config={}, &block) start_server(WEBrick::HTTPServer, config, &block) end def start_httpproxy(config={}, &block) start_server(WEBrick::HTTPProxyServer, config, &block) end end ================================================ FILE: test/webrick/webrick.cgi ================================================ #!ruby -d require "webrick/cgi" class TestApp < WEBrick::CGI def do_GET(req, res) res["content-type"] = "text/plain" if (p = req.path_info) && p.length > 0 res.body = p elsif (q = req.query).size > 0 res.body = q.keys.sort.collect{|key| q[key].list.sort.collect{|v| "#{key}=#{v}" }.join(", ") }.join(", ") elsif %r{/$} =~ req.request_uri.to_s res.body = "" res.body << req.request_uri.to_s << "\n" res.body << req.script_name elsif !req.cookies.empty? res.body = req.cookies.inject(""){|result, cookie| result << "%s=%s\n" % [cookie.name, cookie.value] } res.cookies << WEBrick::Cookie.new("Customer", "WILE_E_COYOTE") res.cookies << WEBrick::Cookie.new("Shipping", "FedEx") else res.body = req.script_name end end def do_POST(req, res) do_GET(req, res) end end cgi = TestApp.new cgi.start ================================================ FILE: test/webrick/webrick_long_filename.cgi ================================================ #!ruby -d require "webrick/cgi" class TestApp < WEBrick::CGI def do_GET(req, res) res["content-type"] = "text/plain" if (p = req.path_info) && p.length > 0 res.body = p elsif (q = req.query).size > 0 res.body = q.keys.sort.collect{|key| q[key].list.sort.collect{|v| "#{key}=#{v}" }.join(", ") }.join(", ") elsif %r{/$} =~ req.request_uri.to_s res.body = "" res.body << req.request_uri.to_s << "\n" res.body << req.script_name elsif !req.cookies.empty? res.body = req.cookies.inject(""){|result, cookie| result << "%s=%s\n" % [cookie.name, cookie.value] } res.cookies << WEBrick::Cookie.new("Customer", "WILE_E_COYOTE") res.cookies << WEBrick::Cookie.new("Shipping", "FedEx") else res.body = req.script_name end end def do_POST(req, res) do_GET(req, res) end end cgi = TestApp.new cgi.start ================================================ FILE: test/wsdl/any/any.wsdl ================================================ ================================================ FILE: test/wsdl/any/expectedDriver.rb ================================================ require 'echo.rb' require 'soap/rpc/driver' class Echo_port_type < ::SOAP::RPC::Driver DefaultEndpointUrl = "http://localhost:10080" MappingRegistry = ::SOAP::Mapping::Registry.new MappingRegistry.set( FooBar, ::SOAP::SOAPStruct, ::SOAP::Mapping::Registry::TypedStructFactory, { :type => XSD::QName.new("urn:example.com:echo-type", "foo.bar") } ) Methods = [ [ XSD::QName.new("urn:example.com:echo", "echo"), "urn:example.com:echo", "echo", [ ["in", "echoitem", ["FooBar", "urn:example.com:echo-type", "foo.bar"]], ["retval", "echoitem", ["FooBar", "urn:example.com:echo-type", "foo.bar"]] ], { :request_style => :rpc, :request_use => :encoded, :response_style => :rpc, :response_use => :encoded } ] ] def initialize(endpoint_url = nil) endpoint_url ||= DefaultEndpointUrl super(endpoint_url, nil) self.mapping_registry = MappingRegistry init_methods end private def init_methods Methods.each do |definitions| opt = definitions.last if opt[:request_style] == :document add_document_operation(*definitions) else add_rpc_operation(*definitions) qname = definitions[0] name = definitions[2] if qname.name != name and qname.name.capitalize == name.capitalize ::SOAP::Mapping.define_singleton_method(self, qname.name) do |*arg| __send__(name, *arg) end end end end end end ================================================ FILE: test/wsdl/any/expectedEcho.rb ================================================ require 'xsd/qname' # {urn:example.com:echo-type}foo.bar class FooBar @@schema_type = "foo.bar" @@schema_ns = "urn:example.com:echo-type" @@schema_element = [["any", [nil, XSD::QName.new(nil, "any")]]] attr_accessor :any def initialize(any = nil) @any = any end end ================================================ FILE: test/wsdl/any/expectedService.rb ================================================ #!/usr/bin/env ruby require 'echoServant.rb' require 'soap/rpc/standaloneServer' require 'soap/mapping/registry' class Echo_port_type MappingRegistry = ::SOAP::Mapping::Registry.new MappingRegistry.set( FooBar, ::SOAP::SOAPStruct, ::SOAP::Mapping::Registry::TypedStructFactory, { :type => XSD::QName.new("urn:example.com:echo-type", "foo.bar") } ) Methods = [ [ XSD::QName.new("urn:example.com:echo", "echo"), "urn:example.com:echo", "echo", [ ["in", "echoitem", ["FooBar", "urn:example.com:echo-type", "foo.bar"]], ["retval", "echoitem", ["FooBar", "urn:example.com:echo-type", "foo.bar"]] ], { :request_style => :rpc, :request_use => :encoded, :response_style => :rpc, :response_use => :encoded } ] ] end class Echo_port_typeApp < ::SOAP::RPC::StandaloneServer def initialize(*arg) super(*arg) servant = Echo_port_type.new Echo_port_type::Methods.each do |definitions| opt = definitions.last if opt[:request_style] == :document @router.add_document_operation(servant, *definitions) else @router.add_rpc_operation(servant, *definitions) end end self.mapping_registry = Echo_port_type::MappingRegistry end end if $0 == __FILE__ # Change listen port. server = Echo_port_typeApp.new('app', nil, '0.0.0.0', 10080) trap(:INT) do server.shutdown end server.start end ================================================ FILE: test/wsdl/any/test_any.rb ================================================ require 'test/unit' require 'wsdl/parser' require 'wsdl/soap/wsdl2ruby' module WSDL; module Any class TestAny < Test::Unit::TestCase DIR = File.dirname(File.expand_path(__FILE__)) def pathname(filename) File.join(DIR, filename) end def test_any gen = WSDL::SOAP::WSDL2Ruby.new gen.location = pathname("any.wsdl") gen.basedir = DIR gen.logger.level = Logger::FATAL gen.opt['classdef'] = nil gen.opt['driver'] = nil gen.opt['client_skelton'] = nil gen.opt['servant_skelton'] = nil gen.opt['standalone_server_stub'] = nil gen.opt['force'] = true suppress_warning do gen.run end compare("expectedDriver.rb", "echoDriver.rb") compare("expectedEcho.rb", "echo.rb") compare("expectedService.rb", "echo_service.rb") File.unlink(pathname("echo_service.rb")) File.unlink(pathname("echo.rb")) File.unlink(pathname("echo_serviceClient.rb")) File.unlink(pathname("echoDriver.rb")) File.unlink(pathname("echoServant.rb")) end def compare(expected, actual) assert_equal(loadfile(expected), loadfile(actual), actual) end def loadfile(file) File.open(pathname(file)) { |f| f.read } end def suppress_warning back = $VERBOSE $VERBOSE = nil begin yield ensure $VERBOSE = back end end end end; end ================================================ FILE: test/wsdl/axisArray/axisArray.wsdl ================================================ ================================================ FILE: test/wsdl/axisArray/itemList.rb ================================================ # Generated by wsdl2ruby.rb with axisArray.wsdl. # urn:jp.gr.jin.rrr.example.itemListType class Item @@schema_type = "Item" @@schema_ns = "urn:jp.gr.jin.rrr.example.itemListType" def name @name end def name=(value) @name = value end def initialize(name = nil) @name = name end end # urn:jp.gr.jin.rrr.example.itemListType class ItemList < Array # Contents type should be dumped here... @@schema_type = "ItemList" @@schema_ns = "urn:jp.gr.jin.rrr.example.itemListType" end ================================================ FILE: test/wsdl/axisArray/test_axisarray.rb ================================================ require 'test/unit' require 'soap/processor' require 'soap/mapping' require 'soap/rpc/element' require 'wsdl/importer' require 'itemList.rb' module WSDL class TestAxisArray < Test::Unit::TestCase def setup @xml =<<__EOX__ name3 name1 name2 __EOX__ end def test_by_stub header, body = ::SOAP::Processor.unmarshal(@xml) ary = ::SOAP::Mapping.soap2obj(body.response) assert_equal(3, ary.size) assert_equal("name1", ary[0].name) assert_equal("name2", ary[1].name) assert_equal("name3", ary[2].name) end def test_by_wsdl wsdlfile = File.join(File.dirname(File.expand_path(__FILE__)), 'axisArray.wsdl') wsdl = WSDL::Importer.import(wsdlfile) service = wsdl.services[0] port = service.ports[0] wsdl_types = wsdl.collect_complextypes rpc_decode_typemap = wsdl_types + wsdl.soap_rpc_complextypes(port.find_binding) opt = {} opt[:default_encodingstyle] = ::SOAP::EncodingNamespace opt[:decode_typemap] = rpc_decode_typemap header, body = ::SOAP::Processor.unmarshal(@xml, opt) ary = ::SOAP::Mapping.soap2obj(body.response) assert_equal(3, ary.size) assert_equal("name1", ary[0].name) assert_equal("name2", ary[1].name) assert_equal("name3", ary[2].name) end end end ================================================ FILE: test/wsdl/datetime/DatetimeService.rb ================================================ #!/usr/bin/env ruby require 'datetimeServant.rb' require 'soap/rpc/standaloneServer' require 'soap/mapping/registry' class DatetimePortType MappingRegistry = ::SOAP::Mapping::Registry.new Methods = [ ["now", "now", [ ["in", "now", [::SOAP::SOAPDateTime]], ["retval", "now", [::SOAP::SOAPDateTime]] ], "", "urn:jp.gr.jin.rrr.example.datetime", :rpc ] ] end class DatetimePortTypeApp < ::SOAP::RPC::StandaloneServer def initialize(*arg) super(*arg) servant = DatetimePortType.new DatetimePortType::Methods.each do |name_as, name, param_def, soapaction, namespace, style| if style == :document @router.add_document_operation(servant, soapaction, name, param_def) else qname = XSD::QName.new(namespace, name_as) @router.add_rpc_operation(servant, qname, soapaction, name, param_def) end end self.mapping_registry = DatetimePortType::MappingRegistry end end if $0 == __FILE__ # Change listen port. server = DatetimePortTypeApp.new('app', nil, '0.0.0.0', 10080) trap(:INT) do server.shutdown end server.start end ================================================ FILE: test/wsdl/datetime/datetime.rb ================================================ ================================================ FILE: test/wsdl/datetime/datetime.wsdl ================================================ ================================================ FILE: test/wsdl/datetime/datetimeServant.rb ================================================ require 'datetime.rb' class DatetimePortType # SYNOPSIS # now(now) # # ARGS # now - {http://www.w3.org/2001/XMLSchema}dateTime # # RETURNS # now - {http://www.w3.org/2001/XMLSchema}dateTime # # RAISES # (undefined) # def now(now) #raise NotImplementedError.new now + 1 end end ================================================ FILE: test/wsdl/datetime/test_datetime.rb ================================================ require 'test/unit' require 'soap/wsdlDriver' require 'DatetimeService.rb' module WSDL module Datetime class TestDatetime < Test::Unit::TestCase DIR = File.dirname(File.expand_path(__FILE__)) Port = 17171 def setup setup_server setup_client end def setup_server @server = DatetimePortTypeApp.new('Datetime server', nil, '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @t = Thread.new { Thread.current.abort_on_exception = true @server.start } end def setup_client wsdl = File.join(DIR, 'datetime.wsdl') @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver @client.endpoint_url = "http://localhost:#{Port}/" @client.generate_explicit_type = true @client.wiredump_dev = STDOUT if $DEBUG end def teardown teardown_server teardown_client end def teardown_server @server.shutdown @t.kill @t.join end def teardown_client @client.reset_stream end def test_datetime d = DateTime.now d1 = d + 1 d2 = @client.now(d) assert_equal(d1.year, d2.year) assert_equal(d1.month, d2.month) assert_equal(d1.day, d2.day) assert_equal(d1.hour, d2.hour) assert_equal(d1.min, d2.min) assert_equal(d1.sec, d2.sec) assert_equal(d1.sec, d2.sec) end def test_time d = DateTime.now t = Time.gm(d.year, d.month, d.day, d.hour, d.min, d.sec) d1 = d + 1 d2 = @client.now(t) assert_equal(d1.year, d2.year) assert_equal(d1.month, d2.month) assert_equal(d1.day, d2.day) assert_equal(d1.hour, d2.hour) assert_equal(d1.min, d2.min) assert_equal(d1.sec, d2.sec) assert_equal(d1.sec, d2.sec) end end end end ================================================ FILE: test/wsdl/document/document.wsdl ================================================ ================================================ FILE: test/wsdl/document/echo.rb ================================================ require 'xsd/qname' # {urn:docrpc}echoele class Echoele @@schema_type = "echoele" @@schema_ns = "urn:docrpc" @@schema_attribute = {XSD::QName.new(nil, "attr_string") => "SOAP::SOAPString", XSD::QName.new(nil, "attr-int") => "SOAP::SOAPInt"} @@schema_element = [["struct1", ["Echo_struct", XSD::QName.new(nil, "struct1")]], ["struct_2", ["Echo_struct", XSD::QName.new(nil, "struct-2")]]] attr_accessor :struct1 attr_accessor :struct_2 def xmlattr_attr_string (@__xmlattr ||= {})[XSD::QName.new(nil, "attr_string")] end def xmlattr_attr_string=(value) (@__xmlattr ||= {})[XSD::QName.new(nil, "attr_string")] = value end def xmlattr_attr_int (@__xmlattr ||= {})[XSD::QName.new(nil, "attr-int")] end def xmlattr_attr_int=(value) (@__xmlattr ||= {})[XSD::QName.new(nil, "attr-int")] = value end def initialize(struct1 = nil, struct_2 = nil) @struct1 = struct1 @struct_2 = struct_2 @__xmlattr = {} end end # {urn:docrpc}echo_response class Echo_response @@schema_type = "echo_response" @@schema_ns = "urn:docrpc" @@schema_attribute = {XSD::QName.new(nil, "attr_string") => "SOAP::SOAPString", XSD::QName.new(nil, "attr-int") => "SOAP::SOAPInt"} @@schema_element = [["struct1", ["Echo_struct", XSD::QName.new(nil, "struct1")]], ["struct_2", ["Echo_struct", XSD::QName.new(nil, "struct-2")]]] attr_accessor :struct1 attr_accessor :struct_2 def xmlattr_attr_string (@__xmlattr ||= {})[XSD::QName.new(nil, "attr_string")] end def xmlattr_attr_string=(value) (@__xmlattr ||= {})[XSD::QName.new(nil, "attr_string")] = value end def xmlattr_attr_int (@__xmlattr ||= {})[XSD::QName.new(nil, "attr-int")] end def xmlattr_attr_int=(value) (@__xmlattr ||= {})[XSD::QName.new(nil, "attr-int")] = value end def initialize(struct1 = nil, struct_2 = nil) @struct1 = struct1 @struct_2 = struct_2 @__xmlattr = {} end end # {urn:docrpc}echo_struct class Echo_struct @@schema_type = "echo_struct" @@schema_ns = "urn:docrpc" @@schema_attribute = {XSD::QName.new(nil, "m_attr") => "SOAP::SOAPString"} @@schema_element = [["m_string", ["SOAP::SOAPString", XSD::QName.new(nil, "m_string")]], ["m_datetime", ["SOAP::SOAPDateTime", XSD::QName.new(nil, "m_datetime")]]] attr_accessor :m_string attr_accessor :m_datetime def xmlattr_m_attr (@__xmlattr ||= {})[XSD::QName.new(nil, "m_attr")] end def xmlattr_m_attr=(value) (@__xmlattr ||= {})[XSD::QName.new(nil, "m_attr")] = value end def initialize(m_string = nil, m_datetime = nil) @m_string = m_string @m_datetime = m_datetime @__xmlattr = {} end end ================================================ FILE: test/wsdl/document/number.wsdl ================================================ ================================================ FILE: test/wsdl/document/ping_nosoapaction.wsdl ================================================ ================================================ FILE: test/wsdl/document/test_nosoapaction.rb ================================================ require 'test/unit' require 'wsdl/parser' require 'wsdl/soap/wsdl2ruby' require 'soap/rpc/standaloneServer' require 'soap/wsdlDriver' require 'soap/rpc/driver' module WSDL; module Document class TestNoSOAPAction < Test::Unit::TestCase class Server < ::SOAP::RPC::StandaloneServer Namespace = 'http://xmlsoap.org/Ping' def on_init add_document_method( self, Namespace + '/ping', 'ping_with_soapaction', XSD::QName.new(Namespace, 'Ping'), XSD::QName.new(Namespace, 'PingResponse') ) add_document_method( self, nil, 'ping', XSD::QName.new(Namespace, 'Ping'), XSD::QName.new(Namespace, 'PingResponse') ) # When no SOAPAction given, latter method(ping) is called. end def ping(arg) arg.text = 'ping' arg end def ping_with_soapaction(arg) arg.text = 'ping_with_soapaction' arg end end DIR = File.dirname(File.expand_path(__FILE__)) Port = 17171 def setup setup_server @client = nil end def teardown teardown_server @client.reset_stream if @client end def setup_server @server = Server.new('Test', Server::Namespace, '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @server_thread = start_server_thread(@server) end def teardown_server @server.shutdown @server_thread.kill @server_thread.join end def start_server_thread(server) t = Thread.new { Thread.current.abort_on_exception = true server.start } t end def test_with_soapaction wsdl = File.join(DIR, 'ping_nosoapaction.wsdl') @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver @client.endpoint_url = "http://localhost:#{Port}/" @client.wiredump_dev = STDOUT if $DEBUG rv = @client.ping(:scenario => 'scenario', :origin => 'origin', :text => 'text') assert_equal('scenario', rv.scenario) assert_equal('origin', rv.origin) assert_equal('ping', rv.text) end def test_without_soapaction @client = ::SOAP::RPC::Driver.new("http://localhost:#{Port}/", Server::Namespace) @client.add_document_method('ping', Server::Namespace + '/ping', XSD::QName.new(Server::Namespace, 'Ping'), XSD::QName.new(Server::Namespace, 'PingResponse')) @client.wiredump_dev = STDOUT if $DEBUG rv = @client.ping(:scenario => 'scenario', :origin => 'origin', :text => 'text') assert_equal('scenario', rv.scenario) assert_equal('origin', rv.origin) assert_equal('ping_with_soapaction', rv.text) end end end; end ================================================ FILE: test/wsdl/document/test_number.rb ================================================ require 'test/unit' require 'wsdl/parser' require 'wsdl/soap/wsdl2ruby' require 'soap/rpc/standaloneServer' require 'soap/wsdlDriver' module WSDL; module Document class TestNumber < Test::Unit::TestCase class Server < ::SOAP::RPC::StandaloneServer Namespace = 'urn:foo' def on_init add_document_method( self, Namespace + ':get_foo', 'get_foo', XSD::QName.new(Namespace, 'get_foo'), XSD::QName.new(Namespace, 'get_foo_response') ) end def get_foo(arg) arg.number end end DIR = File.dirname(File.expand_path(__FILE__)) Port = 17171 def setup setup_server setup_classdef @client = nil end def teardown teardown_server File.unlink(pathname('foo.rb')) @client.reset_stream if @client end def setup_server @server = Server.new('Test', "urn:rpc", '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @server_thread = start_server_thread(@server) end def setup_classdef gen = WSDL::SOAP::WSDL2Ruby.new gen.location = pathname("number.wsdl") gen.basedir = DIR gen.logger.level = Logger::FATAL gen.opt['classdef'] = nil gen.opt['force'] = true gen.run require pathname('foo') end def teardown_server @server.shutdown @server_thread.kill @server_thread.join end def start_server_thread(server) t = Thread.new { Thread.current.abort_on_exception = true server.start } t end def pathname(filename) File.join(DIR, filename) end def test_wsdl wsdl = File.join(DIR, 'number.wsdl') @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver @client.endpoint_url = "http://localhost:#{Port}/" @client.wiredump_dev = STDOUT if $DEBUG # with the Struct defined in foo.rb, which is generated from WSDL assert_equal("12345", @client.get_foo(Get_foo.new("12345"))) # with Hash assert_equal("12345", @client.get_foo({:number => "12345"})) # with Original struct get_foo_struct = Struct.new(:number) assert_equal("12345", @client.get_foo(get_foo_struct.new("12345"))) end end end; end ================================================ FILE: test/wsdl/document/test_rpc.rb ================================================ require 'test/unit' require 'wsdl/parser' require 'wsdl/soap/wsdl2ruby' require 'soap/rpc/standaloneServer' require 'soap/wsdlDriver' module WSDL; module Document class TestRPC < Test::Unit::TestCase class Server < ::SOAP::RPC::StandaloneServer Namespace = 'urn:docrpc' def on_init add_document_method( self, Namespace + ':echo', 'echo', XSD::QName.new(Namespace, 'echo'), XSD::QName.new(Namespace, 'echo_response') ) end def echo(arg) if arg.is_a?(Echoele) # swap args tmp = arg.struct1 arg.struct1 = arg.struct_2 arg.struct_2 = tmp arg else # swap args tmp = arg["struct1"] arg["struct1"] = arg["struct-2"] arg["struct-2"] = tmp arg end end end DIR = File.dirname(File.expand_path(__FILE__)) Port = 17171 def setup setup_server setup_classdef @client = nil end def teardown teardown_server #File.unlink(pathname('echo.rb')) @client.reset_stream if @client end def setup_server @server = Server.new('Test', "urn:rpc", '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @server_thread = start_server_thread(@server) end def setup_classdef gen = WSDL::SOAP::WSDL2Ruby.new gen.location = pathname("document.wsdl") gen.basedir = DIR gen.logger.level = Logger::FATAL gen.opt['classdef'] = nil gen.opt['force'] = true gen.run require pathname('echo') end def teardown_server @server.shutdown @server_thread.kill @server_thread.join end def start_server_thread(server) t = Thread.new { Thread.current.abort_on_exception = true server.start } t end def pathname(filename) File.join(DIR, filename) end def test_wsdl wsdl = File.join(DIR, 'document.wsdl') @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver @client.endpoint_url = "http://localhost:#{Port}/" @client.wiredump_dev = STDOUT if $DEBUG struct1 = Echo_struct.new("mystring1", now1 = Time.now) struct1.xmlattr_m_attr = 'myattr1' struct2 = Echo_struct.new("mystring2", now2 = Time.now) struct2.xmlattr_m_attr = 'myattr2' echo = Echoele.new(struct1, struct2) echo.xmlattr_attr_string = 'attr_string' echo.xmlattr_attr_int = 5 ret = @client.echo(echo) # struct#m_datetime in a response is a DateTime even though # struct#m_datetime in a request is a Time. timeformat = "%Y-%m-%dT%H:%M:%S" assert_equal("mystring2", ret.struct1.m_string) assert_equal(now2.strftime(timeformat), date2time(ret.struct1.m_datetime).strftime(timeformat)) assert_equal("mystring1", ret.struct_2.m_string) assert_equal(now1.strftime(timeformat), date2time(ret.struct_2.m_datetime).strftime(timeformat)) assert_equal("attr_string", ret.xmlattr_attr_string) assert_equal(5, ret.xmlattr_attr_int) end def date2time(date) if date.respond_to?(:to_time) date.to_time else d = date.new_offset(0) d.instance_eval { Time.utc(year, mon, mday, hour, min, sec, (sec_fraction * 86400000000).to_i) }.getlocal end end include ::SOAP def test_naive @client = ::SOAP::RPC::Driver.new("http://localhost:#{Port}/") @client.add_document_method('echo', 'urn:docrpc:echo', XSD::QName.new('urn:docrpc', 'echoele'), XSD::QName.new('urn:docrpc', 'echo_response')) @client.wiredump_dev = STDOUT if $DEBUG echo = SOAPElement.new('foo') echo.extraattr['attr_string'] = 'attr_string' echo.extraattr['attr-int'] = 5 echo.add(struct1 = SOAPElement.new('struct1')) struct1.add(SOAPElement.new('m_string', 'mystring1')) struct1.add(SOAPElement.new('m_datetime', '2005-03-17T19:47:31+01:00')) struct1.extraattr['m_attr'] = 'myattr1' echo.add(struct2 = SOAPElement.new('struct-2')) struct2.add(SOAPElement.new('m_string', 'mystring2')) struct2.add(SOAPElement.new('m_datetime', '2005-03-17T19:47:32+02:00')) struct2.extraattr['m_attr'] = 'myattr2' ret = @client.echo(echo) timeformat = "%Y-%m-%dT%H:%M:%S" assert_equal('mystring2', ret.struct1.m_string) assert_equal('2005-03-17T19:47:32', ret.struct1.m_datetime.strftime(timeformat)) assert_equal("mystring1", ret.struct_2.m_string) assert_equal('2005-03-17T19:47:31', ret.struct_2.m_datetime.strftime(timeformat)) assert_equal('attr_string', ret.xmlattr_attr_string) assert_equal(5, ret.xmlattr_attr_int) echo = {'struct1' => {'m_string' => 'mystring1', 'm_datetime' => '2005-03-17T19:47:31+01:00'}, 'struct-2' => {'m_string' => 'mystring2', 'm_datetime' => '2005-03-17T19:47:32+02:00'}} ret = @client.echo(echo) timeformat = "%Y-%m-%dT%H:%M:%S" assert_equal('mystring2', ret.struct1.m_string) assert_equal('2005-03-17T19:47:32', ret.struct1.m_datetime.strftime(timeformat)) assert_equal("mystring1", ret.struct_2.m_string) assert_equal('2005-03-17T19:47:31', ret.struct_2.m_datetime.strftime(timeformat)) end end end; end ================================================ FILE: test/wsdl/emptycomplextype.wsdl ================================================ ================================================ FILE: test/wsdl/map/map.wsdl ================================================ ================================================ FILE: test/wsdl/map/map.xml ================================================ a a1 a1 a2 a2 b b1 b1 b2 b2 ================================================ FILE: test/wsdl/map/test_map.rb ================================================ require 'test/unit' require 'soap/rpc/httpserver' require 'soap/wsdlDriver' module WSDL class TestMap < Test::Unit::TestCase Port = 17171 DIR = File.dirname(File.expand_path(__FILE__)) class Server < ::SOAP::RPC::HTTPServer def on_init add_method(self, 'map') add_method(self, 'map2', 'arg') end def map {1 => "a", 2 => "b"} end def map2(arg) arg end end def setup setup_server setup_client end def setup_server @server = Server.new( :BindAddress => "0.0.0.0", :Port => Port, :AccessLog => [], :SOAPDefaultNamespace => "urn:map" ) @server.level = Logger::Severity::ERROR @t = Thread.new { Thread.current.abort_on_exception = true @server.start } end def setup_client wsdl = File.join(DIR, 'map.wsdl') @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver @client.endpoint_url = "http://localhost:#{Port}/" @client.generate_explicit_type = true @client.wiredump_dev = STDOUT if $DEBUG end def teardown teardown_server teardown_client end def teardown_server @server.shutdown @t.kill @t.join end def teardown_client @client.reset_stream end def test_by_wsdl dir = File.dirname(File.expand_path(__FILE__)) wsdlfile = File.join(dir, 'map.wsdl') xml = File.open(File.join(dir, 'map.xml')) { |f| f.read } wsdl = WSDL::Importer.import(wsdlfile) service = wsdl.services[0] port = service.ports[0] wsdl_types = wsdl.collect_complextypes rpc_decode_typemap = wsdl_types + wsdl.soap_rpc_complextypes(port.find_binding) opt = {} opt[:default_encodingstyle] = ::SOAP::EncodingNamespace opt[:decode_typemap] = rpc_decode_typemap header, body = ::SOAP::Processor.unmarshal(xml, opt) map = ::SOAP::Mapping.soap2obj(body.response) assert_equal(["a1"], map["a"]["a1"]) assert_equal(["a2"], map["a"]["a2"]) assert_equal(["b1"], map["b"]["b1"]) assert_equal(["b2"], map["b"]["b2"]) end def test_wsdldriver assert_equal({1 => "a", 2 => "b"}, @client.map) assert_equal({1 => 2}, @client.map2({1 => 2})) assert_equal({1 => {2 => 3}}, @client.map2({1 => {2 => 3}})) assert_equal({["a", 2] => {2 => 3}}, @client.map2({["a", 2] => {2 => 3}})) end end end ================================================ FILE: test/wsdl/marshal/person.wsdl ================================================ ================================================ FILE: test/wsdl/marshal/person_org.rb ================================================ require 'xsd/qname' # {http://www.jin.gr.jp/~nahi/xmlns/sample/Person}Person class Person @@schema_type = "Person" @@schema_ns = "http://www.jin.gr.jp/~nahi/xmlns/sample/Person" @@schema_element = [["familyname", ["SOAP::SOAPString", XSD::QName.new(nil, "familyname")]], ["givenname", ["SOAP::SOAPString", XSD::QName.new(nil, "givenname")]], ["var1", ["SOAP::SOAPInt", XSD::QName.new(nil, "var1")]], ["var2", ["SOAP::SOAPDouble", XSD::QName.new(nil, "var2")]], ["var3", ["SOAP::SOAPString", XSD::QName.new(nil, "var3")]]] attr_accessor :familyname attr_accessor :givenname attr_accessor :var1 attr_accessor :var2 attr_accessor :var3 def initialize(familyname = nil, givenname = nil, var1 = nil, var2 = nil, var3 = nil) @familyname = familyname @givenname = givenname @var1 = var1 @var2 = var2 @var3 = var3 end end ================================================ FILE: test/wsdl/marshal/test_wsdlmarshal.rb ================================================ require 'test/unit' require 'wsdl/parser' require 'soap/mapping/wsdlencodedregistry' require 'soap/marshal' require 'wsdl/soap/wsdl2ruby' class WSDLMarshaller include SOAP def initialize(wsdlfile) wsdl = WSDL::Parser.new.parse(File.open(wsdlfile) { |f| f.read }) types = wsdl.collect_complextypes @opt = { :decode_typemap => types, :generate_explicit_type => false, :pretty => true } @mapping_registry = Mapping::WSDLEncodedRegistry.new(types) end def dump(obj, io = nil) type = Mapping.class2element(obj.class) ele = Mapping.obj2soap(obj, @mapping_registry, type) ele.elename = ele.type Processor.marshal(SOAPEnvelope.new(nil, SOAPBody.new(ele)), @opt, io) end def load(io) header, body = Processor.unmarshal(io, @opt) Mapping.soap2obj(body.root_node) end end require File.join(File.dirname(__FILE__), 'person_org') class Person def ==(rhs) @familyname == rhs.familyname and @givenname == rhs.givenname and @var1 == rhs.var1 and @var2 == rhs.var2 and @var3 == rhs.var3 end end class TestWSDLMarshal < Test::Unit::TestCase DIR = File.dirname(File.expand_path(__FILE__)) def test_marshal marshaller = WSDLMarshaller.new(pathname('person.wsdl')) obj = Person.new("NAKAMURA", "Hiroshi", 1, 1.0, "1") str = marshaller.dump(obj) obj2 = marshaller.load(str) assert_equal(obj, obj2) assert_equal(str, marshaller.dump(obj2)) end def test_classdef gen = WSDL::SOAP::WSDL2Ruby.new gen.location = pathname("person.wsdl") gen.basedir = DIR gen.logger.level = Logger::FATAL gen.opt['classdef'] = nil gen.opt['force'] = true gen.run compare("person_org.rb", "Person.rb") File.unlink(pathname('Person.rb')) end def compare(expected, actual) assert_equal(loadfile(expected), loadfile(actual), actual) end def loadfile(file) File.open(pathname(file)) { |f| f.read } end def pathname(filename) File.join(DIR, filename) end end ================================================ FILE: test/wsdl/multiplefault.wsdl ================================================ ================================================ FILE: test/wsdl/qualified/lp.rb ================================================ ================================================ FILE: test/wsdl/qualified/lp.wsdl ================================================ ================================================ FILE: test/wsdl/qualified/lp.xsd ================================================ ================================================ FILE: test/wsdl/qualified/np.wsdl ================================================ ================================================ FILE: test/wsdl/qualified/test_qualified.rb ================================================ require 'test/unit' require 'wsdl/soap/wsdl2ruby' require 'soap/rpc/standaloneServer' require 'soap/wsdlDriver' if defined?(HTTPAccess2) module WSDL class TestQualified < Test::Unit::TestCase class Server < ::SOAP::RPC::StandaloneServer Namespace = 'http://www50.brinkster.com/vbfacileinpt/np' def on_init add_document_method( self, Namespace + '/GetPrimeNumbers', 'GetPrimeNumbers', XSD::QName.new(Namespace, 'GetPrimeNumbers'), XSD::QName.new(Namespace, 'GetPrimeNumbersResponse') ) end def GetPrimeNumbers(arg) nil end end DIR = File.dirname(File.expand_path(__FILE__)) Port = 17171 def setup setup_server setup_clientdef @client = nil end def teardown teardown_server unless $DEBUG File.unlink(pathname('default.rb')) File.unlink(pathname('defaultDriver.rb')) end @client.reset_stream if @client end def setup_server @server = Server.new('Test', "urn:lp", '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @server_thread = start_server_thread(@server) end def setup_clientdef backupdir = Dir.pwd begin Dir.chdir(DIR) gen = WSDL::SOAP::WSDL2Ruby.new gen.location = pathname("np.wsdl") gen.basedir = DIR gen.logger.level = Logger::FATAL gen.opt['classdef'] = nil gen.opt['driver'] = nil gen.opt['force'] = true gen.run require pathname('default.rb') ensure Dir.chdir(backupdir) end end def teardown_server @server.shutdown @server_thread.kill @server_thread.join end def start_server_thread(server) t = Thread.new { Thread.current.abort_on_exception = true server.start } t end def pathname(filename) File.join(DIR, filename) end LOGIN_REQUEST_QUALIFIED_NS = %q[ 10 ] LOGIN_REQUEST_QUALIFIED = %q[ 10 ] def test_wsdl wsdl = File.join(DIR, 'np.wsdl') @client = nil backupdir = Dir.pwd begin Dir.chdir(DIR) @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver ensure Dir.chdir(backupdir) end @client.endpoint_url = "http://localhost:#{Port}/" @client.wiredump_dev = str = '' @client.GetPrimeNumbers(:Max => 10) assert_equal(LOGIN_REQUEST_QUALIFIED_NS, parse_requestxml(str)) end include ::SOAP def test_naive backupdir = Dir.pwd begin Dir.chdir(DIR) require pathname('defaultDriver') ensure Dir.chdir(backupdir) end @client = PnumSoap.new("http://localhost:#{Port}/") @client.wiredump_dev = str = '' @client.getPrimeNumbers(GetPrimeNumbers.new(10)) assert_equal(LOGIN_REQUEST_QUALIFIED, parse_requestxml(str)) end def parse_requestxml(str) str.split(/\r?\n\r?\n/)[3] end end end end ================================================ FILE: test/wsdl/qualified/test_unqualified.rb ================================================ require 'test/unit' require 'wsdl/soap/wsdl2ruby' require 'soap/rpc/standaloneServer' require 'soap/wsdlDriver' if defined?(HTTPAccess2) module WSDL class TestUnqualified < Test::Unit::TestCase class Server < ::SOAP::RPC::StandaloneServer Namespace = 'urn:lp' def on_init add_document_method( self, Namespace + ':login', 'login', XSD::QName.new(Namespace, 'login'), XSD::QName.new(Namespace, 'loginResponse') ) end def login(arg) nil end end DIR = File.dirname(File.expand_path(__FILE__)) Port = 17171 def setup setup_server setup_clientdef @client = nil end def teardown teardown_server File.unlink(pathname('lp.rb')) File.unlink(pathname('lpDriver.rb')) @client.reset_stream if @client end def setup_server @server = Server.new('Test', "urn:lp", '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @server_thread = start_server_thread(@server) end def setup_clientdef backupdir = Dir.pwd begin Dir.chdir(DIR) gen = WSDL::SOAP::WSDL2Ruby.new gen.location = pathname("lp.wsdl") gen.basedir = DIR gen.logger.level = Logger::FATAL gen.opt['classdef'] = nil gen.opt['driver'] = nil gen.opt['force'] = true gen.run require pathname('lp') ensure Dir.chdir(backupdir) end end def teardown_server @server.shutdown @server_thread.kill @server_thread.join end def start_server_thread(server) t = Thread.new { Thread.current.abort_on_exception = true server.start } t end def pathname(filename) File.join(DIR, filename) end LOGIN_REQUEST_QUALIFIED = %q[ NaHi passwd JST ] def test_wsdl wsdl = File.join(DIR, 'lp.wsdl') @client = nil backupdir = Dir.pwd begin Dir.chdir(DIR) @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver ensure Dir.chdir(backupdir) end @client.endpoint_url = "http://localhost:#{Port}/" @client.wiredump_dev = str = '' @client.login(:timezone => 'JST', :password => 'passwd', :username => 'NaHi') assert_equal(LOGIN_REQUEST_QUALIFIED, parse_requestxml(str)) end include ::SOAP def test_naive backupdir = Dir.pwd begin Dir.chdir(DIR) require pathname('lpDriver') ensure Dir.chdir(backupdir) end @client = Lp_porttype.new("http://localhost:#{Port}/") @client.wiredump_dev = str = '' @client.login(Login.new('NaHi', 'passwd', 'JST')) assert_equal(LOGIN_REQUEST_QUALIFIED, parse_requestxml(str)) end def parse_requestxml(str) str.split(/\r?\n\r?\n/)[3] end end end end ================================================ FILE: test/wsdl/raa/RAA.rb ================================================ # http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/ class Category @@schema_type = "Category" @@schema_ns = "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/" def major @major end def major=(value) @major = value end def minor @minor end def minor=(value) @minor = value end def initialize(major = nil, minor = nil) @major = major @minor = minor end end # http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/ class Product @@schema_type = "Product" @@schema_ns = "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/" def id @id end def id=(value) @id = value end def name @name end def name=(value) @name = value end def short_description @short_description end def short_description=(value) @short_description = value end def version @version end def version=(value) @version = value end def status @status end def status=(value) @status = value end def homepage @homepage end def homepage=(value) @homepage = value end def download @download end def download=(value) @download = value end def license @license end def license=(value) @license = value end def description @description end def description=(value) @description = value end def initialize(id = nil, name = nil, short_description = nil, version = nil, status = nil, homepage = nil, download = nil, license = nil, description = nil) @id = id @name = name @short_description = short_description @version = version @status = status @homepage = homepage @download = download @license = license @description = description end end # http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/ class Owner @@schema_type = "Owner" @@schema_ns = "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/" def id @id end def id=(value) @id = value end def email @email end def email=(value) @email = value end def name @name end def name=(value) @name = value end def initialize(id = nil, email = nil, name = nil) @id = id @email = email @name = name end end # http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/ class Info @@schema_type = "Info" @@schema_ns = "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/" def category @category end def category=(value) @category = value end def product @product end def product=(value) @product = value end def owner @owner end def owner=(value) @owner = value end def created @created end def created=(value) @created = value end def updated @updated end def updated=(value) @updated = value end def initialize(category = nil, product = nil, owner = nil, created = nil, updated = nil) @category = category @product = product @owner = owner @created = created @updated = updated end end # http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/ class InfoArray < Array # Contents type should be dumped here... @@schema_type = "InfoArray" @@schema_ns = "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/" end # http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/ class StringArray < Array # Contents type should be dumped here... @@schema_type = "StringArray" @@schema_ns = "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/" end # http://xml.apache.org/xml-soap class Map < Array # Contents type should be dumped here... @@schema_type = "Map" @@schema_ns = "http://xml.apache.org/xml-soap" end ================================================ FILE: test/wsdl/raa/RAAServant.rb ================================================ class RAABaseServicePortType # SYNOPSIS # getAllListings # # ARGS # N/A # # RETURNS # return StringArray - {http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/}StringArray # # RAISES # (undefined) # def getAllListings #raise NotImplementedError.new ["ruby", "soap4r"] end # SYNOPSIS # getProductTree # # ARGS # N/A # # RETURNS # return Map - {http://xml.apache.org/xml-soap}Map # # RAISES # (undefined) # def getProductTree raise NotImplementedError.new end # SYNOPSIS # getInfoFromCategory(category) # # ARGS # category Category - {http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/}Category # # RETURNS # return InfoArray - {http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/}InfoArray # # RAISES # (undefined) # def getInfoFromCategory(category) raise NotImplementedError.new end # SYNOPSIS # getModifiedInfoSince(timeInstant) # # ARGS # timeInstant - {http://www.w3.org/2001/XMLSchema}dateTime # # RETURNS # return InfoArray - {http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/}InfoArray # # RAISES # (undefined) # def getModifiedInfoSince(timeInstant) raise NotImplementedError.new end # SYNOPSIS # getInfoFromName(productName) # # ARGS # productName - {http://www.w3.org/2001/XMLSchema}string # # RETURNS # return Info - {http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/}Info # # RAISES # (undefined) # def getInfoFromName(productName) raise NotImplementedError.new end # SYNOPSIS # getInfoFromOwnerId(ownerId) # # ARGS # ownerId - {http://www.w3.org/2001/XMLSchema}int # # RETURNS # return InfoArray - {http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/}InfoArray # # RAISES # (undefined) # def getInfoFromOwnerId(ownerId) raise NotImplementedError.new end end ================================================ FILE: test/wsdl/raa/RAAService.rb ================================================ #!/usr/bin/env ruby require 'RAAServant.rb' require 'soap/rpc/standaloneServer' class RAABaseServicePortType MappingRegistry = SOAP::Mapping::Registry.new MappingRegistry.set( StringArray, ::SOAP::SOAPArray, ::SOAP::Mapping::Registry::TypedArrayFactory, { :type => XSD::QName.new("http://www.w3.org/2001/XMLSchema", "string") } ) MappingRegistry.set( Map, ::SOAP::SOAPArray, ::SOAP::Mapping::Registry::TypedArrayFactory, { :type => XSD::QName.new("http://www.w3.org/2001/XMLSchema", "anyType") } ) MappingRegistry.set( Category, ::SOAP::SOAPStruct, ::SOAP::Mapping::Registry::TypedStructFactory, { :type => XSD::QName.new("http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Category") } ) MappingRegistry.set( InfoArray, ::SOAP::SOAPArray, ::SOAP::Mapping::Registry::TypedArrayFactory, { :type => XSD::QName.new("http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Info") } ) MappingRegistry.set( Info, ::SOAP::SOAPStruct, ::SOAP::Mapping::Registry::TypedStructFactory, { :type => XSD::QName.new("http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Info") } ) MappingRegistry.set( Product, ::SOAP::SOAPStruct, ::SOAP::Mapping::Registry::TypedStructFactory, { :type => XSD::QName.new("http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Product") } ) MappingRegistry.set( Owner, ::SOAP::SOAPStruct, ::SOAP::Mapping::Registry::TypedStructFactory, { :type => XSD::QName.new("http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Owner") } ) Methods = [ ["getAllListings", "getAllListings", [ ["retval", "return", [::SOAP::SOAPArray, "http://www.w3.org/2001/XMLSchema", "string"]]], "", "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"], ["getProductTree", "getProductTree", [ ["retval", "return", [::SOAP::SOAPArray, "http://www.w3.org/2001/XMLSchema", "anyType"]]], "", "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"], ["getInfoFromCategory", "getInfoFromCategory", [ ["in", "category", [::SOAP::SOAPStruct, "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Category"]], ["retval", "return", [::SOAP::SOAPArray, "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Info"]]], "", "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"], ["getModifiedInfoSince", "getModifiedInfoSince", [ ["in", "timeInstant", [SOAP::SOAPDateTime]], ["retval", "return", [::SOAP::SOAPArray, "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Info"]]], "", "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"], ["getInfoFromName", "getInfoFromName", [ ["in", "productName", [SOAP::SOAPString]], ["retval", "return", [::SOAP::SOAPStruct, "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Info"]]], "", "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"], ["getInfoFromOwnerId", "getInfoFromOwnerId", [ ["in", "ownerId", [SOAP::SOAPInt]], ["retval", "return", [::SOAP::SOAPArray, "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Info"]]], "", "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"] ] end class App < SOAP::RPC::StandaloneServer def initialize(*arg) super servant = RAABaseServicePortType.new RAABaseServicePortType::Methods.each do |name_as, name, params, soapaction, namespace| qname = XSD::QName.new(namespace, name_as) @router.add_method(servant, qname, soapaction, name, params) end self.mapping_registry = RAABaseServicePortType::MappingRegistry end end # Change listen port. if $0 == __FILE__ App.new('app', nil, '0.0.0.0', 10080).start end ================================================ FILE: test/wsdl/raa/README.txt ================================================ RAAServant.rb: based on the file which is generated with the following command; bin/wsdl2ruby.rb --wsdl raa.wsdl --servant_skelton --force RAAService.rb: generated with the following command; bin/wsdl2ruby.rb --wsdl raa.wsdl --standalone_server_stub --force RAA.rb: generated with the following command; bin/wsdl2ruby.rb --wsdl raa.wsdl --classdef --force ================================================ FILE: test/wsdl/raa/raa.wsdl ================================================ ================================================ FILE: test/wsdl/raa/server.rb ================================================ #!/usr/bin/env ruby require 'soap/rpc/standaloneServer' require 'RAA.rb' class RAABaseServicePortType MappingRegistry = SOAP::Mapping::Registry.new MappingRegistry.set( StringArray, ::SOAP::SOAPArray, ::SOAP::Mapping::Registry::TypedArrayFactory, { :type => XSD::QName.new("http://www.w3.org/2001/XMLSchema", "string") } ) MappingRegistry.set( Map, ::SOAP::SOAPStruct, ::SOAP::Mapping::Registry::TypedStructFactory, { :type => XSD::QName.new("http://xml.apache.org/xml-soap", "Map") } ) MappingRegistry.set( Category, ::SOAP::SOAPStruct, ::SOAP::Mapping::Registry::TypedStructFactory, { :type => XSD::QName.new("http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Category") } ) MappingRegistry.set( InfoArray, ::SOAP::SOAPArray, ::SOAP::Mapping::Registry::TypedArrayFactory, { :type => XSD::QName.new("http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Info") } ) MappingRegistry.set( Info, ::SOAP::SOAPStruct, ::SOAP::Mapping::Registry::TypedStructFactory, { :type => XSD::QName.new("http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Info") } ) MappingRegistry.set( Product, ::SOAP::SOAPStruct, ::SOAP::Mapping::Registry::TypedStructFactory, { :type => XSD::QName.new("http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Product") } ) MappingRegistry.set( Owner, ::SOAP::SOAPStruct, ::SOAP::Mapping::Registry::TypedStructFactory, { :type => XSD::QName.new("http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Owner") } ) Methods = [ ["getAllListings", "getAllListings", [ ["retval", "return", [::SOAP::SOAPArray, "http://www.w3.org/2001/XMLSchema", "string"]]], "", "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"], ["getProductTree", "getProductTree", [ ["retval", "return", [::SOAP::SOAPStruct, "http://xml.apache.org/xml-soap", "Map"]]], "", "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"], ["getInfoFromCategory", "getInfoFromCategory", [ ["in", "category", [::SOAP::SOAPStruct, "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Category"]], ["retval", "return", [::SOAP::SOAPArray, "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Info"]]], "", "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"], ["getModifiedInfoSince", "getModifiedInfoSince", [ ["in", "timeInstant", [SOAP::SOAPDateTime]], ["retval", "return", [::SOAP::SOAPArray, "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Info"]]], "", "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"], ["getInfoFromName", "getInfoFromName", [ ["in", "productName", [SOAP::SOAPString]], ["retval", "return", [::SOAP::SOAPStruct, "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Info"]]], "", "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"], ["getInfoFromOwnerId", "getInfoFromOwnerId", [ ["in", "ownerId", [SOAP::SOAPInt]], ["retval", "return", [::SOAP::SOAPArray, "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/", "Info"]]], "", "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.2/"] ] def getAllListings ["ruby", "soap4r"] end end class RAABaseServiceServer < SOAP::RPC::StandaloneServer def initialize(*arg) super servant = RAABaseServicePortType.new RAABaseServicePortType::Methods.each do |name_as, name, params, soapaction, namespace| qname = XSD::QName.new(namespace, name_as) @router.add_method(servant, qname, soapaction, name, params) end self.mapping_registry = RAABaseServicePortType::MappingRegistry end end ================================================ FILE: test/wsdl/raa/test_raa.rb ================================================ require 'test/unit' require 'soap/wsdlDriver' require 'RAA.rb' require 'RAAServant.rb' require 'RAAService.rb' module WSDL module RAA class TestRAA < Test::Unit::TestCase DIR = File.dirname(File.expand_path(__FILE__)) Port = 17171 def setup setup_server setup_client end def setup_server @server = App.new('RAA server', nil, '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @t = Thread.new { Thread.current.abort_on_exception = true @server.start } end def setup_client wsdl = File.join(DIR, 'raa.wsdl') @raa = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver @raa.endpoint_url = "http://localhost:#{Port}/" end def teardown teardown_server teardown_client end def teardown_server @server.shutdown @t.kill @t.join end def teardown_client @raa.reset_stream end def test_raa assert_equal(["ruby", "soap4r"], @raa.getAllListings) end def foo p @raa.getProductTree() p @raa.getInfoFromCategory(Category.new("Library", "XML")) t = Time.at(Time.now.to_i - 24 * 3600) p @raa.getModifiedInfoSince(t) p @raa.getModifiedInfoSince(DateTime.new(t.year, t.mon, t.mday, t.hour, t.min, t.sec)) o = @raa.getInfoFromName("SOAP4R") p o.type p o.owner.name p o end end end end ================================================ FILE: test/wsdl/ref/expectedProduct.rb ================================================ require 'xsd/qname' # {urn:product}Rating module Rating C_0 = "0" C_1 = "+1" C_1_2 = "-1" end # {urn:product}Product-Bag class ProductBag @@schema_type = "Product-Bag" @@schema_ns = "urn:product" @@schema_attribute = {XSD::QName.new("urn:product", "version") => "SOAP::SOAPString", XSD::QName.new("urn:product", "yesno") => "SOAP::SOAPString"} @@schema_element = [["bag", ["Product[]", XSD::QName.new(nil, "bag")]], ["rating", ["SOAP::SOAPString[]", XSD::QName.new("urn:product", "Rating")]], ["product_Bag", [nil, XSD::QName.new("urn:product", "Product-Bag")]], ["comment_1", [nil, XSD::QName.new(nil, "comment_1")]], ["comment_2", ["Comment[]", XSD::QName.new(nil, "comment-2")]]] attr_accessor :bag attr_accessor :product_Bag attr_accessor :comment_1 attr_accessor :comment_2 def Rating @rating end def Rating=(value) @rating = value end def xmlattr_version (@__xmlattr ||= {})[XSD::QName.new("urn:product", "version")] end def xmlattr_version=(value) (@__xmlattr ||= {})[XSD::QName.new("urn:product", "version")] = value end def xmlattr_yesno (@__xmlattr ||= {})[XSD::QName.new("urn:product", "yesno")] end def xmlattr_yesno=(value) (@__xmlattr ||= {})[XSD::QName.new("urn:product", "yesno")] = value end def initialize(bag = [], rating = [], product_Bag = nil, comment_1 = [], comment_2 = []) @bag = bag @rating = rating @product_Bag = product_Bag @comment_1 = comment_1 @comment_2 = comment_2 @__xmlattr = {} end end # {urn:product}Creator class Creator @@schema_type = "Creator" @@schema_ns = "urn:product" @@schema_element = [] def initialize end end # {urn:product}Product class Product @@schema_type = "Product" @@schema_ns = "urn:product" @@schema_element = [["name", ["SOAP::SOAPString", XSD::QName.new(nil, "name")]], ["rating", ["SOAP::SOAPString", XSD::QName.new("urn:product", "Rating")]]] attr_accessor :name def Rating @rating end def Rating=(value) @rating = value end def initialize(name = nil, rating = nil) @name = name @rating = rating end end # {urn:product}Comment class Comment < String end ================================================ FILE: test/wsdl/ref/product.wsdl ================================================ ================================================ FILE: test/wsdl/ref/test_ref.rb ================================================ require 'test/unit' require 'soap/rpc/standaloneServer' require 'soap/wsdlDriver' require 'wsdl/soap/wsdl2ruby' module WSDL module Ref class TestRef < Test::Unit::TestCase DIR = File.dirname(File.expand_path(__FILE__)) Port = 17171 def test_classdef gen = WSDL::SOAP::WSDL2Ruby.new gen.location = pathname("product.wsdl") gen.basedir = DIR gen.logger.level = Logger::FATAL gen.opt['classdef'] = nil gen.opt['force'] = true suppress_warning do gen.run end compare("expectedProduct.rb", "product.rb") File.unlink(pathname('product.rb')) end def compare(expected, actual) assert_equal(loadfile(expected), loadfile(actual), actual) end def loadfile(file) File.open(pathname(file)) { |f| f.read } end def pathname(filename) File.join(DIR, filename) end def suppress_warning back = $VERBOSE $VERBOSE = nil begin yield ensure $VERBOSE = back end end end end end ================================================ FILE: test/wsdl/rpc/echoDriver.rb ================================================ require 'echo.rb' require 'soap/rpc/driver' class Echo_port_type < ::SOAP::RPC::Driver DefaultEndpointUrl = "http://localhost:10080" MappingRegistry = ::SOAP::Mapping::Registry.new MappingRegistry.set( Person, ::SOAP::SOAPStruct, ::SOAP::Mapping::Registry::TypedStructFactory, { :type => XSD::QName.new("urn:rpc-type", "person") } ) Methods = [ ["echo", "echo", [ ["in", "arg1", [::SOAP::SOAPStruct, "urn:rpc-type", "person"]], ["in", "arg2", [::SOAP::SOAPStruct, "urn:rpc-type", "person"]], ["retval", "return", [::SOAP::SOAPStruct, "urn:rpc-type", "person"]] ], "", "urn:rpc", :rpc ] ] def initialize(endpoint_url = nil) endpoint_url ||= DefaultEndpointUrl super(endpoint_url, nil) self.mapping_registry = MappingRegistry init_methods end private def init_methods Methods.each do |name_as, name, params, soapaction, namespace, style| qname = XSD::QName.new(namespace, name_as) if style == :document @proxy.add_document_method(soapaction, name, params) add_document_method_interface(name, params) else @proxy.add_rpc_method(qname, soapaction, name, params) add_rpc_method_interface(name, params) end if name_as != name and name_as.capitalize == name.capitalize sclass = class << self; self; end sclass.__send__(:define_method, name_as, proc { |*arg| __send__(name, *arg) }) end end end end ================================================ FILE: test/wsdl/rpc/echo_serviceClient.rb ================================================ #!/usr/bin/env ruby require 'echoDriver.rb' endpoint_url = ARGV.shift obj = Echo_port_type.new(endpoint_url) # Uncomment the below line to see SOAP wiredumps. # obj.wiredump_dev = STDERR # SYNOPSIS # echo(arg1, arg2) # # ARGS # arg1 Person - {urn:rpc-type}person # arg2 Person - {urn:rpc-type}person # # RETURNS # v_return Person - {urn:rpc-type}person # arg1 = arg2 = nil puts obj.echo(arg1, arg2) ================================================ FILE: test/wsdl/rpc/rpc.wsdl ================================================ ================================================ FILE: test/wsdl/rpc/test-rpc-lit.wsdl ================================================ ================================================ FILE: test/wsdl/rpc/test-rpc-lit12.wsdl ================================================ ================================================ FILE: test/wsdl/rpc/test_rpc.rb ================================================ require 'test/unit' require 'wsdl/parser' require 'wsdl/soap/wsdl2ruby' require 'soap/rpc/standaloneServer' require 'soap/wsdlDriver' module WSDL; module RPC class TestRPC < Test::Unit::TestCase class Server < ::SOAP::RPC::StandaloneServer def on_init self.generate_explicit_type = false add_rpc_method(self, 'echo', 'arg1', 'arg2') add_rpc_method(self, 'echo_err', 'arg1', 'arg2') end DummyPerson = Struct.new("family-name".intern, :given_name) def echo(arg1, arg2) case arg1.family_name when 'normal' arg1.family_name = arg2.family_name arg1.given_name = arg2.given_name arg1.age = arg2.age arg1 when 'dummy' DummyPerson.new("family-name", "given_name") else raise end end ErrPerson = Struct.new(:given_name, :no_such_element) def echo_err(arg1, arg2) ErrPerson.new(58, Time.now) end end DIR = File.dirname(File.expand_path(__FILE__)) Port = 17171 def setup setup_server setup_classdef @client = nil end def teardown teardown_server File.unlink(pathname('echo.rb')) @client.reset_stream if @client end def setup_server @server = Server.new('Test', "urn:rpc", '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @server_thread = start_server_thread(@server) end def setup_classdef gen = WSDL::SOAP::WSDL2Ruby.new gen.location = pathname("rpc.wsdl") gen.basedir = DIR gen.logger.level = Logger::FATAL gen.opt['classdef'] = nil gen.opt['force'] = true gen.run require pathname('echo') end def teardown_server @server.shutdown @server_thread.kill @server_thread.join end def start_server_thread(server) t = Thread.new { Thread.current.abort_on_exception = true server.start } t end def pathname(filename) File.join(DIR, filename) end def test_wsdl wsdl = File.join(DIR, 'rpc.wsdl') @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver @client.endpoint_url = "http://localhost:#{Port}/" @client.wiredump_dev = STDOUT if $DEBUG ret = @client.echo(Person.new("normal", "", 12), Person.new("Hi", "Na", 21)) assert_equal(Person, ret.class) assert_equal("Hi", ret.family_name) assert_equal("Na", ret.given_name) assert_equal(21, ret.age) ret = @client.echo(Person.new("dummy", "", 12), Person.new("Hi", "Na", 21)) assert_equal(Person, ret.class) assert_equal("family-name", ret.family_name) assert_equal("given_name", ret.given_name) assert_equal(nil, ret.age) ret = @client.echo_err(Person.new("Na", "Hi"), Person.new("Hi", "Na")) assert_equal(Person, ret.class) assert_equal("58", ret.given_name) assert_equal(nil, ret.family_name) assert_equal(nil, ret.age) end end end; end ================================================ FILE: test/wsdl/rpc/test_rpc_lit.rb ================================================ require 'test/unit' require 'wsdl/soap/wsdl2ruby' require 'soap/rpc/standaloneServer' require 'soap/wsdlDriver' if defined?(HTTPAccess2) and defined?(OpenSSL) module WSDL; module RPC class TestRPCLIT < Test::Unit::TestCase class Server < ::SOAP::RPC::StandaloneServer Namespace = "http://soapbuilders.org/rpc-lit-test" def on_init self.generate_explicit_type = false add_rpc_operation(self, XSD::QName.new(Namespace, 'echoStringArray'), nil, 'echoStringArray', [ ['in', 'inputStringArray', nil], ['retval', 'return', nil] ], { :request_style => :rpc, :request_use => :literal, :response_style => :rpc, :response_use => :literal } ) add_rpc_operation(self, XSD::QName.new(Namespace, 'echoStringArrayInline'), nil, 'echoStringArrayInline', [ ['in', 'inputStringArray', nil], ['retval', 'return', nil] ], { :request_style => :rpc, :request_use => :literal, :response_style => :rpc, :response_use => :literal } ) add_rpc_operation(self, XSD::QName.new(Namespace, 'echoNestedStruct'), nil, 'echoNestedStruct', [ ['in', 'inputNestedStruct', nil], ['retval', 'return', nil] ], { :request_style => :rpc, :request_use => :literal, :response_style => :rpc, :response_use => :literal } ) add_rpc_operation(self, XSD::QName.new(Namespace, 'echoStructArray'), nil, 'echoStructArray', [ ['in', 'inputStructArray', nil], ['retval', 'return', nil] ], { :request_style => :rpc, :request_use => :literal, :response_style => :rpc, :response_use => :literal } ) end def echoStringArray(strings) # strings.stringItem => Array ArrayOfstring[*strings.stringItem] end def echoStringArrayInline(strings) ArrayOfstringInline[*strings.stringItem] end def echoNestedStruct(struct) struct end def echoStructArray(ary) ary end end DIR = File.dirname(File.expand_path(__FILE__)) Port = 17171 def setup setup_server setup_classdef @client = nil end def teardown teardown_server unless $DEBUG File.unlink(pathname('RPC-Literal-TestDefinitions.rb')) File.unlink(pathname('RPC-Literal-TestDefinitionsDriver.rb')) end @client.reset_stream if @client end def setup_server @server = Server.new('Test', Server::Namespace, '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @server_thread = start_server_thread(@server) end def setup_classdef gen = WSDL::SOAP::WSDL2Ruby.new gen.location = pathname("test-rpc-lit.wsdl") gen.basedir = DIR gen.logger.level = Logger::FATAL gen.opt['classdef'] = nil gen.opt['driver'] = nil gen.opt['force'] = true gen.run backupdir = Dir.pwd begin Dir.chdir(DIR) require pathname('RPC-Literal-TestDefinitions.rb') require pathname('RPC-Literal-TestDefinitionsDriver.rb') ensure Dir.chdir(backupdir) end end def teardown_server @server.shutdown @server_thread.kill @server_thread.join end def start_server_thread(server) t = Thread.new { Thread.current.abort_on_exception = true server.start } t end def pathname(filename) File.join(DIR, filename) end def test_wsdl_echoStringArray wsdl = pathname('test-rpc-lit.wsdl') @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver @client.endpoint_url = "http://localhost:#{Port}/" @client.wiredump_dev = STDOUT if $DEBUG # response contains only 1 part. result = @client.echoStringArray(ArrayOfstring["a", "b", "c"])[0] assert_equal(["a", "b", "c"], result.stringItem) end ECHO_STRING_ARRAY_REQUEST = %q[ a b c ] ECHO_STRING_ARRAY_RESPONSE = %q[ a b c ] def test_stub_echoStringArray drv = SoapTestPortTypeRpc.new("http://localhost:#{Port}/") drv.wiredump_dev = str = '' # response contains only 1 part. result = drv.echoStringArray(ArrayOfstring["a", "b", "c"])[0] assert_equal(["a", "b", "c"], result.stringItem) assert_equal(ECHO_STRING_ARRAY_REQUEST, parse_requestxml(str)) assert_equal(ECHO_STRING_ARRAY_RESPONSE, parse_responsexml(str)) end ECHO_STRING_ARRAY_INLINE_REQUEST = %q[ a b c ] ECHO_STRING_ARRAY_INLINE_RESPONSE = %q[ a b c ] def test_stub_echoStringArrayInline drv = SoapTestPortTypeRpc.new("http://localhost:#{Port}/") drv.wiredump_dev = str = '' # response contains only 1 part. result = drv.echoStringArrayInline(ArrayOfstringInline["a", "b", "c"])[0] assert_equal(["a", "b", "c"], result.stringItem) assert_equal(ECHO_STRING_ARRAY_INLINE_REQUEST, parse_requestxml(str)) assert_equal(ECHO_STRING_ARRAY_INLINE_RESPONSE, parse_responsexml(str)) end ECHO_NESTED_STRUCT_REQUEST = %q[ str 1 +1 str 1 +1 ] ECHO_NESTED_STRUCT_RESPONSE = %q[ str 1 +1 str 1 +1 ] def test_wsdl_echoNestedStruct wsdl = pathname('test-rpc-lit.wsdl') @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver @client.endpoint_url = "http://localhost:#{Port}/" @client.wiredump_dev = str = '' # response contains only 1 part. result = @client.echoNestedStruct(SOAPStructStruct.new("str", 1, 1.0, SOAPStruct.new("str", 1, 1.0)))[0] assert_equal('str', result.varString) assert_equal('1', result.varInt) assert_equal('+1', result.varFloat) assert_equal('str', result.structItem.varString) assert_equal('1', result.structItem.varInt) assert_equal('+1', result.structItem.varFloat) assert_equal(ECHO_NESTED_STRUCT_REQUEST, parse_requestxml(str)) assert_equal(ECHO_NESTED_STRUCT_RESPONSE, parse_responsexml(str)) end def test_stub_echoNestedStruct drv = SoapTestPortTypeRpc.new("http://localhost:#{Port}/") drv.wiredump_dev = str = '' # response contains only 1 part. result = drv.echoNestedStruct(SOAPStructStruct.new("str", 1, 1.0, SOAPStruct.new("str", 1, 1.0)))[0] assert_equal('str', result.varString) assert_equal('1', result.varInt) assert_equal('+1', result.varFloat) assert_equal('str', result.structItem.varString) assert_equal('1', result.structItem.varInt) assert_equal('+1', result.structItem.varFloat) assert_equal(ECHO_NESTED_STRUCT_REQUEST, parse_requestxml(str)) assert_equal(ECHO_NESTED_STRUCT_RESPONSE, parse_responsexml(str)) end ECHO_STRUCT_ARRAY_REQUEST = %q[ str 2 +2.1 str 2 +2.1 ] ECHO_STRUCT_ARRAY_RESPONSE = %q[ str 2 +2.1 str 2 +2.1 ] def test_wsdl_echoStructArray wsdl = pathname('test-rpc-lit.wsdl') @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver @client.endpoint_url = "http://localhost:#{Port}/" @client.wiredump_dev = str = '' # response contains only 1 part. e = SOAPStruct.new("str", 2, 2.1) result = @client.echoStructArray(ArrayOfSOAPStruct[e, e]) assert_equal(ECHO_STRUCT_ARRAY_REQUEST, parse_requestxml(str)) assert_equal(ECHO_STRUCT_ARRAY_RESPONSE, parse_responsexml(str)) end def test_stub_echoStructArray drv = SoapTestPortTypeRpc.new("http://localhost:#{Port}/") drv.wiredump_dev = str = '' # response contains only 1 part. e = SOAPStruct.new("str", 2, 2.1) result = drv.echoStructArray(ArrayOfSOAPStruct[e, e]) assert_equal(ECHO_STRUCT_ARRAY_REQUEST, parse_requestxml(str)) assert_equal(ECHO_STRUCT_ARRAY_RESPONSE, parse_responsexml(str)) end def parse_requestxml(str) str.split(/\r?\n\r?\n/)[3] end def parse_responsexml(str) str.split(/\r?\n\r?\n/)[6] end end end; end end ================================================ FILE: test/wsdl/simpletype/rpc/expectedClient.rb ================================================ #!/usr/bin/env ruby require 'echo_versionDriver.rb' endpoint_url = ARGV.shift obj = Echo_version_port_type.new(endpoint_url) # run ruby with -d to see SOAP wiredumps. obj.wiredump_dev = STDERR if $DEBUG # SYNOPSIS # echo_version(version) # # ARGS # version Version - {urn:example.com:simpletype-rpc-type}version # # RETURNS # version_struct Version_struct - {urn:example.com:simpletype-rpc-type}version_struct # version = nil puts obj.echo_version(version) # SYNOPSIS # echo_version_r(version_struct) # # ARGS # version_struct Version_struct - {urn:example.com:simpletype-rpc-type}version_struct # # RETURNS # version Version - {urn:example.com:simpletype-rpc-type}version # version_struct = nil puts obj.echo_version_r(version_struct) ================================================ FILE: test/wsdl/simpletype/rpc/expectedDriver.rb ================================================ require 'echo_version.rb' require 'soap/rpc/driver' class Echo_version_port_type < ::SOAP::RPC::Driver DefaultEndpointUrl = "http://localhost:10080" MappingRegistry = ::SOAP::Mapping::Registry.new MappingRegistry.set( Version_struct, ::SOAP::SOAPStruct, ::SOAP::Mapping::Registry::TypedStructFactory, { :type => XSD::QName.new("urn:example.com:simpletype-rpc-type", "version_struct") } ) Methods = [ [ XSD::QName.new("urn:example.com:simpletype-rpc", "echo_version"), "urn:example.com:simpletype-rpc", "echo_version", [ ["in", "version", ["::SOAP::SOAPString"]], ["retval", "version_struct", ["Version_struct", "urn:example.com:simpletype-rpc-type", "version_struct"]] ], { :request_style => :rpc, :request_use => :encoded, :response_style => :rpc, :response_use => :encoded } ], [ XSD::QName.new("urn:example.com:simpletype-rpc", "echo_version_r"), "urn:example.com:simpletype-rpc", "echo_version_r", [ ["in", "version_struct", ["Version_struct", "urn:example.com:simpletype-rpc-type", "version_struct"]], ["retval", "version", ["::SOAP::SOAPString"]] ], { :request_style => :rpc, :request_use => :encoded, :response_style => :rpc, :response_use => :encoded } ] ] def initialize(endpoint_url = nil) endpoint_url ||= DefaultEndpointUrl super(endpoint_url, nil) self.mapping_registry = MappingRegistry init_methods end private def init_methods Methods.each do |definitions| opt = definitions.last if opt[:request_style] == :document add_document_operation(*definitions) else add_rpc_operation(*definitions) qname = definitions[0] name = definitions[2] if qname.name != name and qname.name.capitalize == name.capitalize ::SOAP::Mapping.define_singleton_method(self, qname.name) do |*arg| __send__(name, *arg) end end end end end end ================================================ FILE: test/wsdl/simpletype/rpc/expectedEchoVersion.rb ================================================ require 'xsd/qname' # {urn:example.com:simpletype-rpc-type}version_struct class Version_struct @@schema_type = "version_struct" @@schema_ns = "urn:example.com:simpletype-rpc-type" @@schema_element = [["version", ["SOAP::SOAPString", XSD::QName.new(nil, "version")]], ["msg", ["SOAP::SOAPString", XSD::QName.new(nil, "msg")]]] attr_accessor :version attr_accessor :msg def initialize(version = nil, msg = nil) @version = version @msg = msg end end # {urn:example.com:simpletype-rpc-type}version module Version C_16 = "1.6" C_18 = "1.8" C_19 = "1.9" end ================================================ FILE: test/wsdl/simpletype/rpc/expectedServant.rb ================================================ require 'echo_version.rb' class Echo_version_port_type # SYNOPSIS # echo_version(version) # # ARGS # version Version - {urn:example.com:simpletype-rpc-type}version # # RETURNS # version_struct Version_struct - {urn:example.com:simpletype-rpc-type}version_struct # def echo_version(version) p [version] raise NotImplementedError.new end # SYNOPSIS # echo_version_r(version_struct) # # ARGS # version_struct Version_struct - {urn:example.com:simpletype-rpc-type}version_struct # # RETURNS # version Version - {urn:example.com:simpletype-rpc-type}version # def echo_version_r(version_struct) p [version_struct] raise NotImplementedError.new end end ================================================ FILE: test/wsdl/simpletype/rpc/expectedService.rb ================================================ #!/usr/bin/env ruby require 'echo_versionServant.rb' require 'soap/rpc/standaloneServer' require 'soap/mapping/registry' class Echo_version_port_type MappingRegistry = ::SOAP::Mapping::Registry.new MappingRegistry.set( Version_struct, ::SOAP::SOAPStruct, ::SOAP::Mapping::Registry::TypedStructFactory, { :type => XSD::QName.new("urn:example.com:simpletype-rpc-type", "version_struct") } ) Methods = [ [ XSD::QName.new("urn:example.com:simpletype-rpc", "echo_version"), "urn:example.com:simpletype-rpc", "echo_version", [ ["in", "version", ["::SOAP::SOAPString"]], ["retval", "version_struct", ["Version_struct", "urn:example.com:simpletype-rpc-type", "version_struct"]] ], { :request_style => :rpc, :request_use => :encoded, :response_style => :rpc, :response_use => :encoded } ], [ XSD::QName.new("urn:example.com:simpletype-rpc", "echo_version_r"), "urn:example.com:simpletype-rpc", "echo_version_r", [ ["in", "version_struct", ["Version_struct", "urn:example.com:simpletype-rpc-type", "version_struct"]], ["retval", "version", ["::SOAP::SOAPString"]] ], { :request_style => :rpc, :request_use => :encoded, :response_style => :rpc, :response_use => :encoded } ] ] end class Echo_version_port_typeApp < ::SOAP::RPC::StandaloneServer def initialize(*arg) super(*arg) servant = Echo_version_port_type.new Echo_version_port_type::Methods.each do |definitions| opt = definitions.last if opt[:request_style] == :document @router.add_document_operation(servant, *definitions) else @router.add_rpc_operation(servant, *definitions) end end self.mapping_registry = Echo_version_port_type::MappingRegistry end end if $0 == __FILE__ # Change listen port. server = Echo_version_port_typeApp.new('app', nil, '0.0.0.0', 10080) trap(:INT) do server.shutdown end server.start end ================================================ FILE: test/wsdl/simpletype/rpc/rpc.wsdl ================================================ ================================================ FILE: test/wsdl/simpletype/rpc/test_rpc.rb ================================================ require 'test/unit' require 'wsdl/parser' require 'wsdl/soap/wsdl2ruby' module WSDL; module SimpleType class TestRPC < Test::Unit::TestCase DIR = File.dirname(File.expand_path(__FILE__)) def pathname(filename) File.join(DIR, filename) end def test_rpc gen = WSDL::SOAP::WSDL2Ruby.new gen.location = pathname("rpc.wsdl") gen.basedir = DIR gen.logger.level = Logger::FATAL gen.opt['classdef'] = nil gen.opt['driver'] = nil gen.opt['client_skelton'] = nil gen.opt['servant_skelton'] = nil gen.opt['standalone_server_stub'] = nil gen.opt['force'] = true suppress_warning do gen.run end compare("expectedEchoVersion.rb", "echo_version.rb") compare("expectedDriver.rb", "echo_versionDriver.rb") compare("expectedService.rb", "echo_version_service.rb") compare("expectedClient.rb", "echo_version_serviceClient.rb") compare("expectedServant.rb", "echo_versionServant.rb") File.unlink(pathname("echo_version.rb")) File.unlink(pathname("echo_versionDriver.rb")) File.unlink(pathname("echo_version_service.rb")) File.unlink(pathname("echo_version_serviceClient.rb")) File.unlink(pathname("echo_versionServant.rb")) end def compare(expected, actual) assert_equal(loadfile(expected), loadfile(actual), actual) end def loadfile(file) File.open(pathname(file)) { |f| f.read } end def suppress_warning back = $VERBOSE $VERBOSE = nil begin yield ensure $VERBOSE = back end end end end; end ================================================ FILE: test/wsdl/simpletype/simpletype.wsdl ================================================ ================================================ FILE: test/wsdl/simpletype/test_simpletype.rb ================================================ require 'test/unit' require 'soap/rpc/standaloneServer' require 'soap/wsdlDriver' module WSDL module SimpleType class TestSimpleType < Test::Unit::TestCase class Server < ::SOAP::RPC::StandaloneServer def on_init add_document_method(self, 'urn:example.com:simpletype:ping', 'ping', XSD::QName.new('urn:example.com:simpletype', 'ruby'), XSD::QName.new('http://www.w3.org/2001/XMLSchema', 'string')) add_document_method(self, 'urn:example.com:simpletype:ping_id', 'ping_id', XSD::QName.new('urn:example.com:simpletype', 'myid'), XSD::QName.new('urn:example.com:simpletype', 'myid')) end def ping(ruby) version = ruby["myversion"] date = ruby["date"] "#{version} (#{date})" end def ping_id(id) id end end DIR = File.dirname(File.expand_path(__FILE__)) Port = 17171 def setup setup_server setup_client end def setup_server @server = Server.new('Test', "urn:example.com:simpletype", '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @server_thread = start_server_thread(@server) end def setup_client wsdl = File.join(DIR, 'simpletype.wsdl') @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver @client.endpoint_url = "http://localhost:#{Port}/" @client.generate_explicit_type = false @client.wiredump_dev = STDOUT if $DEBUG end def teardown teardown_server teardown_client end def teardown_server @server.shutdown @server_thread.kill @server_thread.join end def teardown_client @client.reset_stream end def start_server_thread(server) t = Thread.new { Thread.current.abort_on_exception = true server.start } t end def test_ping ret = @client.ping({:myversion => "1.9", :date => "2004-01-01T00:00:00Z"}) assert_equal("1.9 (2004-01-01T00:00:00Z)", ret) end def test_ping_id ret = @client.ping_id("012345678901234567") assert_equal("012345678901234567", ret) # length assert_raise(XSD::ValueSpaceError) do @client.ping_id("0123456789012345678") end # pattern assert_raise(XSD::ValueSpaceError) do @client.ping_id("01234567890123456;") end end end end end ================================================ FILE: test/wsdl/soap/soapbodyparts.wsdl ================================================ ================================================ FILE: test/wsdl/soap/test_soapbodyparts.rb ================================================ require 'test/unit' require 'soap/rpc/standaloneServer' require 'soap/wsdlDriver' module WSDL module SOAP class TestSOAPBodyParts < Test::Unit::TestCase class Server < ::SOAP::RPC::StandaloneServer def on_init add_method(self, 'foo', 'p1', 'p2', 'p3') add_method(self, 'bar', 'p1', 'p2', 'p3') add_method(self, 'baz', 'p1', 'p2', 'p3') end def foo(p1, p2, p3) [p1, p2, p3] end alias bar foo def baz(p1, p2, p3) [p3, p2, p1] end end DIR = File.dirname(File.expand_path(__FILE__)) Port = 17171 def setup setup_server setup_client end def setup_server @server = Server.new('Test', "urn:www.example.com:soapbodyparts:v1", '0.0.0.0', Port) @server.level = Logger::Severity::ERROR @t = Thread.new { Thread.current.abort_on_exception = true @server.start } end def setup_client wsdl = File.join(DIR, 'soapbodyparts.wsdl') @client = ::SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver @client.endpoint_url = "http://localhost:#{Port}/" @client.wiredump_dev = STDERR if $DEBUG end def teardown teardown_server teardown_client end def teardown_server @server.shutdown @t.kill @t.join end def teardown_client @client.reset_stream end def test_soapbodyparts assert_equal(["1", "2", "3"], @client.foo("1", "2", "3")) assert_equal(["3", "2", "1"], @client.foo("3", "2", "1")) assert_equal(["1", "2", "3"], @client.bar("1", "2", "3")) assert_equal(["3", "2", "1"], @client.baz("1", "2", "3")) end end end end ================================================ FILE: test/wsdl/test_emptycomplextype.rb ================================================ require 'test/unit' require 'wsdl/parser' module WSDL class TestWSDL < Test::Unit::TestCase def setup @file = File.join(File.dirname(File.expand_path(__FILE__)), 'emptycomplextype.wsdl') end def test_wsdl @wsdl = WSDL::Parser.new.parse(File.open(@file) { |f| f.read }) assert(/\{urn:jp.gr.jin.rrr.example.emptycomplextype\}emptycomplextype/ =~ @wsdl.inspect) end end end ================================================ FILE: test/wsdl/test_fault.rb ================================================ require 'test/unit' require 'soap/processor' require 'soap/mapping' require 'soap/rpc/element' require 'wsdl/parser' module WSDL class TestFault < Test::Unit::TestCase def setup @xml =<<__EOX__ Server faultstring faultactor type 5 __EOX__ end def test_by_wsdl rpc_decode_typemap = WSDL::Definitions.soap_rpc_complextypes opt = {} opt[:default_encodingstyle] = ::SOAP::EncodingNamespace opt[:decode_typemap] = rpc_decode_typemap header, body = ::SOAP::Processor.unmarshal(@xml, opt) fault = ::SOAP::Mapping.soap2obj(body.response) assert_equal("Server", fault.faultcode) assert_equal("faultstring", fault.faultstring) assert_equal(URI.parse("faultactor"), fault.faultactor) assert_equal(5, fault.detail.cause) end end end ================================================ FILE: test/wsdl/test_multiplefault.rb ================================================ require 'test/unit' require 'wsdl/parser' require 'wsdl/soap/classDefCreator' module WSDL class TestMultipleFault < Test::Unit::TestCase def self.setup(filename) @@filename = filename end def test_multiplefault @wsdl = WSDL::Parser.new.parse(File.open(@@filename) { |f| f.read }) classdefstr = WSDL::SOAP::ClassDefCreator.new(@wsdl).dump yield_eval_binding(classdefstr) do |b| assert_equal( WSDL::TestMultipleFault::AuthenticationError, eval("AuthenticationError", b) ) assert_equal( WSDL::TestMultipleFault::AuthorizationError, eval("AuthorizationError", b) ) end end def yield_eval_binding(evaled) b = binding eval(evaled, b) yield(b) end end TestMultipleFault.setup(File.join(File.dirname(__FILE__), 'multiplefault.wsdl')) end ================================================ FILE: test/xmlrpc/data/bug_bool.expected ================================================ --- - true - false ================================================ FILE: test/xmlrpc/data/bug_bool.xml ================================================ 0 ================================================ FILE: test/xmlrpc/data/bug_cdata.expected ================================================ --- - true - test ================================================ FILE: test/xmlrpc/data/bug_cdata.xml ================================================ ================================================ FILE: test/xmlrpc/data/bug_covert.expected ================================================ --- - true - > Site,SANs,Array Configured Capacity,Array Reserved Capacity,Array Ava ilable Capacity,Array % Reserved,Host Allocated,Host Used,Host Free,Host % Used ================================================ FILE: test/xmlrpc/data/bug_covert.xml ================================================ Site,SANs,Array Configured Capacity,Array Reserved Capacity,Array Ava ilable Capacity,Array % Reserved,Host Allocated,Host Used,Host Free,Host % Used ================================================ FILE: test/xmlrpc/data/datetime_iso8601.xml ================================================ 20041105T01:15:23Z ================================================ FILE: test/xmlrpc/data/fault.xml ================================================ faultCode 4 faultString an error message ================================================ FILE: test/xmlrpc/data/value.expected ================================================ --- - Test - - Hallo Leute - " Hallo " - '' - " " ================================================ FILE: test/xmlrpc/data/value.xml ================================================ Test Hallo Leute Hallo ================================================ FILE: test/xmlrpc/data/xml1.expected ================================================ --- - true - - subscriber: MegaCorp lastName: Baker telephone1: 1-508-791-1267 telephone2: 1-800-445-2588 password: p1111 OID: "1" email: hbaker@yahoo.com adminId: hbaker objectName: AdministratorDO - subscriber: CornerStore lastName: Dragon telephone1: 1-781-789-9089 telephone2: 1-800-445-2588 password: p3333 OID: "3" email: adragon@yahoo.com adminId: adragon objectName: AdministratorDO - subscriber: Cyberdyne lastName: Rodman telephone1: 1-617-789-1890 telephone2: 1-800-445-2588 password: p4444 OID: "4" email: mrodman@yahoo.com adminId: mrodman objectName: AdministratorDO - subscriber: StarSports lastName: Jordan telephone1: 1-617-890-7897 telephone2: 1-800-445-2588 password: p5555 OID: "5" email: mjordan@yahoo.com adminId: mjordan objectName: AdministratorDO - subscriber: GreatBooks lastName: Pippen telephone1: 1-781-789-9876 telephone2: 1-800-445-2588 password: p6666 OID: "6" email: gpippen@yahoo.com adminId: gpippen objectName: AdministratorDO - subscriber: AxisChemicals lastName: Andhrew telephone1: 1-781-678-8970 telephone2: 1-800-445-2588 password: p7777 OID: "7" email: aandrew@yahoo.com adminId: aandrew objectName: AdministratorDO - subscriber: MediaShop lastName: Vincent telephone1: 1-786-897-8908 telephone2: 1-800-445-2588 password: p8888 OID: "8" email: tvincent@yahoo.com adminId: tvincent objectName: AdministratorDO - subscriber: SmartShop lastName: Richard telephone1: 1-508-789-6789 telephone2: 1-800-445-2588 password: p9999 OID: "9" email: krichard@yahoo.com adminId: krichard objectName: AdministratorDO - subscriber: HomeNeeds lastName: Cornell telephone1: 1-617-789-8979 telephone2: 1-800-445-2588 password: paaaa OID: "10" email: gconell@yahoo.com adminId: gcornell objectName: AdministratorDO - subscriber: MegaCorp lastName: HorstMann telephone1: 1-508-791-1267 telephone2: 1-800-445-2588 password: p1111 OID: "11" email: shorstmann@yahoo.com adminId: shorstmann objectName: AdministratorDO - subscriber: CornerStore lastName: Bob telephone1: 1-781-789-9089 telephone2: 1-800-445-2588 password: p3333 OID: "13" email: rbob@yahoo.com adminId: rbob objectName: AdministratorDO - subscriber: Cyberdyne lastName: Peter telephone1: 1-617-789-1890 telephone2: 1-800-445-2588 password: p4444 OID: "14" email: speter@yahoo.com adminId: speter objectName: AdministratorDO - subscriber: StarSports lastName: Novak telephone1: 1-617-890-7897 telephone2: 1-800-445-2588 password: p5555 OID: "15" email: pnovak@yahoo.com adminId: pnovak objectName: AdministratorDO - subscriber: GreatBooks lastName: Nancy telephone1: 1-781-789-9876 telephone2: 1-800-445-2588 password: p6666 OID: "16" email: pnancy@yahoo.com adminId: pnancy objectName: AdministratorDO - subscriber: AxisChemicals lastName: Michel telephone1: 1-781-678-8970 telephone2: 1-800-445-2588 password: p7777 OID: "17" email: hmichel@yahoo.com adminId: hmichel objectName: AdministratorDO - subscriber: MediaShop lastName: David telephone1: 1-786-897-8908 telephone2: 1-800-445-2588 password: p8888 OID: "18" email: kdavid@yahoo.com adminId: kdavid objectName: AdministratorDO - subscriber: SmartShop lastName: Valnoor telephone1: 1-508-789-6789 telephone2: 1-800-445-2588 password: p9999 OID: "19" email: pvalnoor@yahoo.com adminId: pvalnoor objectName: AdministratorDO - subscriber: HomeNeeds lastName: Smith telephone1: 1-617-789-8979 telephone2: 1-800-445-2588 password: paaaa OID: "20" email: wsmith@yahoo.com adminId: wsmith objectName: AdministratorDO - subscriber: MegaCorp lastName: Caral telephone1: 1-781-789-9876 telephone2: 1-800-445-2588 password: p6666 OID: "21" email: gcaral@yahoo.com adminId: gcaral objectName: AdministratorDO - subscriber: CornerStore lastName: Hillary telephone1: 1-786-897-8908 telephone2: 1-800-445-2588 password: p8888 OID: "23" email: phillary@yahoo.com adminId: phillary objectName: AdministratorDO - subscriber: Cyberdyne lastName: Philip telephone1: 1-508-789-6789 telephone2: 1-800-445-2588 password: p9999 OID: "24" email: bphilip@yahoo.com adminId: bphilip objectName: AdministratorDO - subscriber: StarSports lastName: Andrea telephone1: 1-617-789-8979 telephone2: 1-800-445-2588 password: paaaa OID: "25" email: sandrea@yahoo.com adminId: sandrea objectName: AdministratorDO - subscriber: s4 lastName: "null" telephone1: "null" telephone2: "null" password: s4 OID: "26" email: "null" adminId: s4 objectName: AdministratorDO - subscriber: BigBank lastName: administrator telephone1: '' telephone2: '' password: admin OID: "82" email: '' adminId: admin objectName: AdministratorDO ================================================ FILE: test/xmlrpc/data/xml1.xml ================================================ objectNameAdministratorDOadminIdhbakeremailhbaker@yahoo.comtelephone21-800-445-2588telephone11-508-791-1267OID1passwordp1111lastNameBakersubscriberMegaCorpobjectNameAdministratorDOadminIdadragonemailadragon@yahoo.comtelephone21-800-445-2588telephone11-781-789-9089OID3passwordp3333lastNameDragonsubscriberCornerStoreobjectNameAdministratorDOadminIdmrodmanemailmrodman@yahoo.comtelephone21-800-445-2588telephone11-617-789-1890OID4passwordp4444lastNameRodmansubscriberCyberdyneobjectNameAdministratorDOadminIdmjordanemailmjordan@yahoo.comtelephone21-800-445-2588telephone11-617-890-7897OID5passwordp5555lastNameJordansubscriberStarSportsobjectNameAdministratorDOadminIdgpippenemailgpippen@yahoo.comtelephone21-800-445-2588telephone11-781-789-9876OID6passwordp6666lastNamePippensubscriberGreatBooksobjectNameAdministratorDOadminIdaandrewemailaandrew@yahoo.comtelephone21-800-445-2588telephone11-781-678-8970OID7passwordp7777lastNameAndhrewsubscriberAxisChemicalsobjectNameAdministratorDOadminIdtvincentemailtvincent@yahoo.comtelephone21-800-445-2588telephone11-786-897-8908OID8passwordp8888lastNameVincentsubscriberMediaShopobjectNameAdministratorDOadminIdkrichardemailkrichard@yahoo.comtelephone21-800-445-2588telephone11-508-789-6789OID9passwordp9999lastNameRichardsubscriberSmartShopobjectNameAdministratorDOadminIdgcornellemailgconell@yahoo.comtelephone21-800-445-2588telephone11-617-789-8979OID10passwordpaaaalastNameCornellsubscriberHomeNeedsobjectNameAdministratorDOadminIdshorstmannemailshorstmann@yahoo.comtelephone21-800-445-2588telephone11-508-791-1267OID11passwordp1111lastNameHorstMannsubscriberMegaCorpobjectNameAdministratorDOadminIdrbobemailrbob@yahoo.comtelephone21-800-445-2588telephone11-781-789-9089OID13passwordp3333lastNameBobsubscriberCornerStoreobjectNameAdministratorDOadminIdspeteremailspeter@yahoo.comtelephone21-800-445-2588telephone11-617-789-1890OID14passwordp4444lastNamePetersubscriberCyberdyneobjectNameAdministratorDOadminIdpnovakemailpnovak@yahoo.comtelephone21-800-445-2588telephone11-617-890-7897OID15passwordp5555lastNameNovaksubscriberStarSportsobjectNameAdministratorDOadminIdpnancyemailpnancy@yahoo.comtelephone21-800-445-2588telephone11-781-789-9876OID16passwordp6666lastNameNancysubscriberGreatBooksobjectNameAdministratorDOadminIdhmichelemailhmichel@yahoo.comtelephone21-800-445-2588telephone11-781-678-8970OID17passwordp7777lastNameMichelsubscriberAxisChemicalsobjectNameAdministratorDOadminIdkdavidemailkdavid@yahoo.comtelephone21-800-445-2588telephone11-786-897-8908OID18passwordp8888lastNameDavidsubscriberMediaShopobjectNameAdministratorDOadminIdpvalnooremailpvalnoor@yahoo.comtelephone21-800-445-2588telephone11-508-789-6789OID19passwordp9999lastNameValnoorsubscriberSmartShopobjectNameAdministratorDOadminIdwsmithemailwsmith@yahoo.comtelephone21-800-445-2588telephone11-617-789-8979OID20passwordpaaaalastNameSmithsubscriberHomeNeedsobjectNameAdministratorDOadminIdgcaralemailgcaral@yahoo.comtelephone21-800-445-2588telephone11-781-789-9876OID21passwordp6666lastNameCaralsubscriberMegaCorpobjectNameAdministratorDOadminIdphillaryemailphillary@yahoo.comtelephone21-800-445-2588telephone11-786-897-8908OID23passwordp8888lastNameHillarysubscriberCornerStoreobjectNameAdministratorDOadminIdbphilipemailbphilip@yahoo.comtelephone21-800-445-2588telephone11-508-789-6789OID24passwordp9999lastNamePhilipsubscriberCyberdyneobjectNameAdministratorDOadminIdsandreaemailsandrea@yahoo.comtelephone21-800-445-2588telephone11-617-789-8979OID25passwordpaaaalastNameAndreasubscriberStarSportsobjectNameAdministratorDOadminIds4emailnulltelephone2nulltelephone1nullOID26passwords4lastNamenullsubscribers4objectNameAdministratorDOadminIdadminemailtelephone2telephone1OID82passwordadminlastNameadministratorsubscriberBigBank ================================================ FILE: test/xmlrpc/test_cookie.rb ================================================ require 'test/unit' require 'time' require 'webrick' require File.join(File.dirname(__FILE__), 'webrick_testing') require "xmlrpc/server" require 'xmlrpc/client' class TestCookie < Test::Unit::TestCase include WEBrick_Testing def create_servlet s = XMLRPC::WEBrickServlet.new def s.logged_in_users @logged_in_users ||= {} end def s.request @request end def s.response @response end def s.service(request, response) @request = request @response = response super ensure @request = nil @response = nil end key = Time.now.to_i.to_s valid_user = "valid-user" s.add_handler("test.login") do |user, password| ok = (user == valid_user and password == "secret") if ok s.logged_in_users[key] = user expires = (Time.now + 60 * 60).httpdate cookies = s.response.cookies cookies << "key=\"#{key}\"; path=\"/RPC2\"; expires=#{expires}" cookies << "user=\"#{user}\"; path=\"/RPC2\"" end ok end s.add_handler("test.require_authenticate_echo") do |string| cookies = {} s.request.cookies.each do |cookie| cookies[cookie.name] = cookie.value end if cookies == {"key" => key, "user" => valid_user} string else raise XMLRPC::FaultException.new(29, "Authentication required") end end s.set_default_handler do |name, *args| raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + " or wrong number of parameters!") end s.add_introspection s end def setup_http_server(port) option = {:Port => port} start_server(option) {|w| w.mount('/RPC2', create_servlet) } @s = XMLRPC::Client.new3(:port => port) end PORT = 8070 def test_cookie begin setup_http_server(PORT) do_test ensure stop_server end end def do_test assert(!@s.call("test.login", "invalid-user", "invalid-password")) exception = assert_raise(XMLRPC::FaultException) do @s.call("test.require_authenticate_echo", "Hello") end assert_equal(29, exception.faultCode) assert(@s.call("test.login", "valid-user", "secret")) assert_equal("Hello", @s.call("test.require_authenticate_echo", "Hello")) end end ================================================ FILE: test/xmlrpc/test_datetime.rb ================================================ require 'test/unit' require "xmlrpc/datetime" class Test_DateTime < Test::Unit::TestCase def test_new dt = createDateTime() assert_instance_of(XMLRPC::DateTime, dt) end def test_new_exception assert_raises(ArgumentError) { XMLRPC::DateTime.new(4.5, 13, 32, 25, 60, 60) } assert_raises(ArgumentError) { XMLRPC::DateTime.new(2001, 12, 32, 25, 60, 60) } assert_raises(ArgumentError) { XMLRPC::DateTime.new(2001, 12, 31, 25, 60, 60) } assert_raises(ArgumentError) { XMLRPC::DateTime.new(2001, 12, 31, 24, 60, 60) } assert_raises(ArgumentError) { XMLRPC::DateTime.new(2001, 12, 31, 24, 59, 60) } assert_nothing_raised(ArgumentError) { XMLRPC::DateTime.new(2001, 12, 31, 24, 59, 59) } assert_raises(ArgumentError) { XMLRPC::DateTime.new(2001, 0, 0, -1, -1, -1) } assert_raises(ArgumentError) { XMLRPC::DateTime.new(2001, 1, 0, -1, -1, -1) } assert_raises(ArgumentError) { XMLRPC::DateTime.new(2001, 1, 1, -1, -1, -1) } assert_raises(ArgumentError) { XMLRPC::DateTime.new(2001, 1, 1, 0, -1, -1) } assert_raises(ArgumentError) { XMLRPC::DateTime.new(2001, 1, 1, 0, 0, -1) } assert_nothing_raised(ArgumentError) { XMLRPC::DateTime.new(2001, 1, 1, 0, 0, 0) } end def test_get_values y, m, d, h, mi, s = 1970, 3, 24, 12, 0, 5 dt = XMLRPC::DateTime.new(y, m, d, h, mi, s) assert_equal(y, dt.year) assert_equal(m, dt.month) assert_equal(m, dt.mon) assert_equal(d, dt.day) assert_equal(h, dt.hour) assert_equal(mi,dt.min) assert_equal(s, dt.sec) end def test_set_values dt = createDateTime() y, m, d, h, mi, s = 1950, 12, 9, 8, 52, 30 dt.year = y dt.month = m dt.day = d dt.hour = h dt.min = mi dt.sec = s assert_equal(y, dt.year) assert_equal(m, dt.month) assert_equal(m, dt.mon) assert_equal(d, dt.day) assert_equal(h, dt.hour) assert_equal(mi,dt.min) assert_equal(s, dt.sec) dt.mon = 5 assert_equal(5, dt.month) assert_equal(5, dt.mon) end def test_set_exception dt = createDateTime() assert_raises(ArgumentError) { dt.year = 4.5 } assert_nothing_raised(ArgumentError) { dt.year = -2000 } assert_raises(ArgumentError) { dt.month = 0 } assert_raises(ArgumentError) { dt.month = 13 } assert_nothing_raised(ArgumentError) { dt.month = 7 } assert_raises(ArgumentError) { dt.mon = 0 } assert_raises(ArgumentError) { dt.mon = 13 } assert_nothing_raised(ArgumentError) { dt.mon = 7 } assert_raises(ArgumentError) { dt.day = 0 } assert_raises(ArgumentError) { dt.day = 32 } assert_nothing_raised(ArgumentError) { dt.day = 16 } assert_raises(ArgumentError) { dt.hour = -1 } assert_raises(ArgumentError) { dt.hour = 25 } assert_nothing_raised(ArgumentError) { dt.hour = 12 } assert_raises(ArgumentError) { dt.min = -1 } assert_raises(ArgumentError) { dt.min = 60 } assert_nothing_raised(ArgumentError) { dt.min = 30 } assert_raises(ArgumentError) { dt.sec = -1 } assert_raises(ArgumentError) { dt.sec = 60 } assert_nothing_raised(ArgumentError) { dt.sec = 30 } end def test_to_a y, m, d, h, mi, s = 1970, 3, 24, 12, 0, 5 dt = XMLRPC::DateTime.new(y, m, d, h, mi, s) a = dt.to_a assert_instance_of(Array, a) assert_equal(6, a.size, "Returned array has wrong size") assert_equal(y, a[0]) assert_equal(m, a[1]) assert_equal(d, a[2]) assert_equal(h, a[3]) assert_equal(mi, a[4]) assert_equal(s, a[5]) end def test_to_time1 y, m, d, h, mi, s = 1970, 3, 24, 12, 0, 5 dt = XMLRPC::DateTime.new(y, m, d, h, mi, s) time = dt.to_time assert_not_nil(time) assert_equal(y, time.year) assert_equal(m, time.month) assert_equal(d, time.day) assert_equal(h, time.hour) assert_equal(mi, time.min) assert_equal(s, time.sec) end def test_to_time2 dt = createDateTime() dt.year = 1969 assert_nil(dt.to_time) end def test_to_date1 y, m, d, h, mi, s = 1970, 3, 24, 12, 0, 5 dt = XMLRPC::DateTime.new(y, m, d, h, mi, s) date = dt.to_date assert_equal(y, date.year) assert_equal(m, date.month) assert_equal(d, date.day) end def test_to_date2 dt = createDateTime() dt.year = 666 assert_equal(666, dt.to_date.year) end def createDateTime XMLRPC::DateTime.new(1970, 3, 24, 12, 0, 5) end end ================================================ FILE: test/xmlrpc/test_features.rb ================================================ require 'test/unit' require "xmlrpc/create" require "xmlrpc/parser" require "xmlrpc/config" class Test_Features < Test::Unit::TestCase def setup @params = [nil, {"test" => nil}, [nil, 1, nil]] end def test_nil_create XMLRPC::XMLWriter.each_installed_writer do |writer| c = XMLRPC::Create.new(writer) XMLRPC::Config.module_eval {remove_const(:ENABLE_NIL_CREATE)} XMLRPC::Config.const_set(:ENABLE_NIL_CREATE, false) assert_raises(RuntimeError) { str = c.methodCall("test", *@params) } XMLRPC::Config.module_eval {remove_const(:ENABLE_NIL_CREATE)} XMLRPC::Config.const_set(:ENABLE_NIL_CREATE, true) assert_nothing_raised { str = c.methodCall("test", *@params) } end end def test_nil_parse XMLRPC::Config.module_eval {remove_const(:ENABLE_NIL_CREATE)} XMLRPC::Config.const_set(:ENABLE_NIL_CREATE, true) XMLRPC::XMLWriter.each_installed_writer do |writer| c = XMLRPC::Create.new(writer) str = c.methodCall("test", *@params) XMLRPC::XMLParser.each_installed_parser do |parser| para = nil XMLRPC::Config.module_eval {remove_const(:ENABLE_NIL_PARSER)} XMLRPC::Config.const_set(:ENABLE_NIL_PARSER, false) assert_raises(RuntimeError) { para = parser.parseMethodCall(str) } XMLRPC::Config.module_eval {remove_const(:ENABLE_NIL_PARSER)} XMLRPC::Config.const_set(:ENABLE_NIL_PARSER, true) assert_nothing_raised { para = parser.parseMethodCall(str) } assert_equal(para[1], @params) end end end end ================================================ FILE: test/xmlrpc/test_marshal.rb ================================================ require 'test/unit' require "xmlrpc/marshal" class Test_Marshal < Test::Unit::TestCase # for test_parser_values class Person include XMLRPC::Marshallable attr_reader :name def initialize(name) @name = name end end def test1_dump_response assert_nothing_raised(NameError) { XMLRPC::Marshal.dump_response('arg') } end def test1_dump_call assert_nothing_raised(NameError) { XMLRPC::Marshal.dump_call('methodName', 'arg') } end def test2_dump_load_response value = [1, 2, 3, {"test" => true}, 3.4] res = XMLRPC::Marshal.dump_response(value) assert_equal(value, XMLRPC::Marshal.load_response(res)) end def test2_dump_load_call methodName = "testMethod" value = [1, 2, 3, {"test" => true}, 3.4] exp = [methodName, [value, value]] res = XMLRPC::Marshal.dump_call(methodName, value, value) assert_equal(exp, XMLRPC::Marshal.load_call(res)) end def test_parser_values v1 = [ 1, -7778, # integers 1.0, 0.0, -333.0, 2343434343.0, # floats false, true, true, false, # booleans "Hallo", "with < and >", "" # strings ] v2 = [ [v1, v1, v1], {"a" => v1} ] v3 = [ XMLRPC::Base64.new("\001"*1000), # base64 :aSymbol, :anotherSym # symbols (-> string) ] v3_exp = [ "\001"*1000, "aSymbol", "anotherSym" ] person = Person.new("Michael") XMLRPC::XMLParser.each_installed_parser do |parser| m = XMLRPC::Marshal.new(parser) assert_equal( v1, m.load_response(m.dump_response(v1)) ) assert_equal( v2, m.load_response(m.dump_response(v2)) ) assert_equal( v3_exp, m.load_response(m.dump_response(v3)) ) pers = m.load_response(m.dump_response(person)) assert( pers.is_a?(Person) ) assert( person.name == pers.name ) end # missing, Date, Time, DateTime # Struct end def test_no_params_tag # bug found by Idan Sofer expect = %{myMethod\n} str = XMLRPC::Marshal.dump_call("myMethod") assert_equal(expect, str) end end ================================================ FILE: test/xmlrpc/test_parser.rb ================================================ require 'test/unit' require 'xmlrpc/datetime' require "xmlrpc/parser" require 'yaml' module GenericParserTest def datafile(base) File.join(File.dirname(__FILE__), "data", base) end def load_data(name) [File.read(datafile(name) + ".xml"), YAML.load(File.read(datafile(name) + ".expected"))] end def setup @xml1, @expected1 = load_data('xml1') @xml2, @expected2 = load_data('bug_covert') @xml3, @expected3 = load_data('bug_bool') @xml4, @expected4 = load_data('value') @cdata_xml, @cdata_expected = load_data('bug_cdata') @datetime_xml = File.read(datafile('datetime_iso8601.xml')) @datetime_expected = XMLRPC::DateTime.new(2004, 11, 5, 1, 15, 23) @fault_doc = File.read(datafile('fault.xml')) end # test parseMethodResponse -------------------------------------------------- def test_parseMethodResponse1 assert_equal(@expected1, @p.parseMethodResponse(@xml1)) end def test_parseMethodResponse2 assert_equal(@expected2, @p.parseMethodResponse(@xml2)) end def test_parseMethodResponse3 assert_equal(@expected3, @p.parseMethodResponse(@xml3)) end def test_cdata assert_equal(@cdata_expected, @p.parseMethodResponse(@cdata_xml)) end def test_dateTime assert_equal(@datetime_expected, @p.parseMethodResponse(@datetime_xml)[1]) end # test parseMethodCall ------------------------------------------------------ def test_parseMethodCall assert_equal(@expected4, @p.parseMethodCall(@xml4)) end # test fault ---------------------------------------------------------------- def test_fault flag, fault = @p.parseMethodResponse(@fault_doc) assert_equal(flag, false) unless fault.is_a? XMLRPC::FaultException assert(false, "must be an instance of class XMLRPC::FaultException") end assert_equal(fault.faultCode, 4) assert_equal(fault.faultString, "an error message") end end # create test class for each installed parser XMLRPC::XMLParser.each_installed_parser do |parser| klass = parser.class name = klass.to_s.split("::").last eval %{ class Test_#{name} < Test::Unit::TestCase include GenericParserTest def setup super @p = #{klass}.new end end } end ================================================ FILE: test/xmlrpc/test_webrick_server.rb ================================================ require 'test/unit' require 'webrick' require File.join(File.dirname(__FILE__), 'webrick_testing') require "xmlrpc/server" require 'xmlrpc/client' class Test_Webrick < Test::Unit::TestCase include WEBrick_Testing def create_servlet s = XMLRPC::WEBrickServlet.new s.add_handler("test.add") do |a,b| a + b end s.add_handler("test.div") do |a,b| if b == 0 raise XMLRPC::FaultException.new(1, "division by zero") else a / b end end s.set_default_handler do |name, *args| raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + " or wrong number of parameters!") end s.add_introspection return s end def setup_http_server(port, use_ssl) option = { :Port => port, :SSLEnable => use_ssl, } if use_ssl require 'webrick/https' option.update( :SSLVerifyClient => ::OpenSSL::SSL::VERIFY_NONE, :SSLCertName => [] ) end start_server(option) {|w| w.mount('/RPC2', create_servlet) } @s = XMLRPC::Client.new3(:port => port, :use_ssl => use_ssl) end PORT = 8070 def test_client_server # NOTE: I don't enable SSL testing as this hangs [false].each do |use_ssl| begin setup_http_server(PORT, use_ssl) do_test ensure stop_server end end end def do_test # simple call assert_equal 9, @s.call('test.add', 4, 5) # fault exception assert_raises(XMLRPC::FaultException) { @s.call('test.div', 1, 0) } # fault exception via call2 ok, param = @s.call2('test.div', 1, 0) assert_equal false, ok assert_instance_of XMLRPC::FaultException, param assert_equal 1, param.faultCode assert_equal 'division by zero', param.faultString # call2 without fault exception ok, param = @s.call2('test.div', 10, 5) assert_equal true, ok assert_equal param, 2 # introspection assert_equal ["test.add", "test.div", "system.listMethods", "system.methodSignature", "system.methodHelp"], @s.call("system.listMethods") # default handler (missing handler) ok, param = @s.call2('test.nonexisting') assert_equal false, ok assert_equal -99, param.faultCode # default handler (wrong number of arguments) ok, param = @s.call2('test.add', 1, 2, 3) assert_equal false, ok assert_equal -99, param.faultCode end end ================================================ FILE: test/xmlrpc/webrick_testing.rb ================================================ require 'timeout' module WEBrick_Testing class DummyLog < WEBrick::BasicLog def initialize() super(self) end def <<(*args) end end def start_server(config={}) raise "already started" if @__server @__started = false Thread.new { @__server = WEBrick::HTTPServer.new( { :Logger => DummyLog.new, :AccessLog => [], :StartCallback => proc { @__started = true } }.update(config)) yield @__server @__server.start @__started = false } Timeout.timeout(5) { nil until @__started # wait until the server is ready } end def stop_server Timeout.timeout(5) { @__server.shutdown nil while @__started # wait until the server is down } @__server = nil end end ================================================ FILE: test/xsd/codegen/test_classdef.rb ================================================ require 'test/unit' require 'xsd/codegen/classdef' module XSD; module CodeGen class TestClassDefCreator < Test::Unit::TestCase include XSD::CodeGen include GenSupport def test_classdef_simple c = ClassDef.new("Foo") assert_equal(format(<<-EOD), c.dump) class Foo end EOD end def test_classdef_complex c = ClassDef.new("Foo::Bar::Baz", String) assert_equal(format(<<-EOD), c.dump) module Foo; module Bar class Baz < String end end; end EOD end def test_require c = ClassDef.new("Foo") c.def_require("foo/bar") assert_equal(format(<<-EOD), c.dump) require 'foo/bar' class Foo end EOD end def test_comment c = ClassDef.new("Foo") c.def_require("foo/bar") c.comment = <<-EOD foo EOD assert_equal(format(<<-EOD), c.dump) require 'foo/bar' # foo class Foo end EOD c.comment = <<-EOD foo bar baz EOD assert_equal(format(<<-EOD), c.dump) require 'foo/bar' # foo # # bar # baz # class Foo end EOD end def test_emptymethod c = ClassDef.new("Foo") c.def_method('foo') do end c.def_method('bar') do '' end assert_equal(format(<<-EOD), c.dump) class Foo def foo end def bar end end EOD end def test_full c = ClassDef.new("Foo::Bar::HobbitName", String) c.def_require("foo/bar") c.comment = <<-EOD foo bar baz EOD c.def_const("FOO", 1) c.def_classvar("@@foo", "var".dump) c.def_classvar("baz", "1".dump) c.def_attr("Foo", true, "foo") c.def_attr("bar") c.def_attr("baz", true) c.def_attr("Foo2", true, "foo2") c.def_attr("foo3", false, "foo3") c.def_method("foo") do <<-EOD foo.bar = 1 \tbaz.each do |ele| \t ele end EOD end c.def_method("baz", "qux") do <<-EOD [1, 2, 3].each do |i| p i end EOD end m = MethodDef.new("qux", "quxx", "quxxx") do <<-EOD p quxx + quxxx EOD end m.comment = "hello world\n123" c.add_method(m) c.def_code <<-EOD Foo.new Bar.z EOD c.def_code <<-EOD Foo.new Bar.z EOD c.def_privatemethod("foo", "baz", "*arg", "&block") assert_equal(format(<<-EOD), c.dump) require 'foo/bar' module Foo; module Bar # foo # bar # baz class HobbitName < String @@foo = "var" @@baz = "1" FOO = 1 Foo.new Bar.z Foo.new Bar.z attr_accessor :bar attr_accessor :baz attr_reader :foo3 def Foo @foo end def Foo=(value) @foo = value end def Foo2 @foo2 end def Foo2=(value) @foo2 = value end def foo foo.bar = 1 baz.each do |ele| ele end end def baz(qux) [1, 2, 3].each do |i| p i end end # hello world # 123 def qux(quxx, quxxx) p quxx + quxxx end private def foo(baz, *arg, &block) end end end; end EOD end end end; end ================================================ FILE: test/xsd/noencoding.xml ================================================ ================================================ FILE: test/xsd/test_noencoding.rb ================================================ require 'test/unit' require 'wsdl/xmlSchema/parser' module XSD class TestEmptyCharset < Test::Unit::TestCase def setup @file = File.join(File.dirname(File.expand_path(__FILE__)), 'noencoding.xml') end def test_wsdl begin xml = WSDL::XMLSchema::Parser.new.parse(File.open(@file) { |f| f.read }) rescue RuntimeError if XSD::XMLParser.const_defined?("REXMLParser") STDERR.puts("rexml cannot handle euc-jp without iconv/uconv.") return end raise rescue Errno::EINVAL # unsupported encoding return end assert_equal(WSDL::XMLSchema::Schema, xml.class) assert_equal(0, xml.collect_elements.size) end end end ================================================ FILE: test/xsd/test_xmlschemaparser.rb ================================================ require 'test/unit' require 'wsdl/xmlSchema/parser' module XSD class TestXMLSchemaParser < Test::Unit::TestCase def setup @file = File.join(File.dirname(File.expand_path(__FILE__)), 'xmlschema.xml') end def test_wsdl @wsdl = WSDL::XMLSchema::Parser.new.parse(File.open(@file) { |f| f.read }) assert_equal(WSDL::XMLSchema::Schema, @wsdl.class) assert_equal(1, @wsdl.collect_elements.size) end end end ================================================ FILE: test/xsd/test_xsd.rb ================================================ require 'test/unit' require 'xsd/datatypes' module XSD class TestXSD < Test::Unit::TestCase NegativeZero = (-1.0 / (1.0 / 0.0)) def setup end def teardown end def assert_parsed_result(klass, str) o = klass.new(str) assert_equal(str, o.to_s) end def test_NSDBase o = XSD::NSDBase.new assert_equal(nil, o.type) end def test_XSDBase o = XSD::XSDAnySimpleType.new assert_equal(nil, o.data) assert_equal(true, o.is_nil) assert_equal('', o.to_s) end def test_XSDNil o = XSD::XSDNil.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::NilLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) o = XSD::XSDNil.new(nil) assert_equal(true, o.is_nil) assert_equal(nil, o.data) assert_equal("", o.to_s) o = XSD::XSDNil.new('var') assert_equal(false, o.is_nil) assert_equal('var', o.data) assert_equal('var', o.to_s) end def test_XSDString_UTF8 o = XSD::XSDString.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::StringLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) str = "abc" assert_equal(str, XSD::XSDString.new(str).data) assert_equal(str, XSD::XSDString.new(str).to_s) assert_raises(XSD::ValueSpaceError) do XSD::XSDString.new("\0") end assert_raises(XSD::ValueSpaceError) do p XSD::XSDString.new("\xC0\xC0").to_s end end def test_XSDString_NONE XSD::Charset.module_eval { @encoding_backup = @encoding; @encoding = "NONE" } begin o = XSD::XSDString.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::StringLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) str = "abc" assert_equal(str, XSD::XSDString.new(str).data) assert_equal(str, XSD::XSDString.new(str).to_s) assert_raises(XSD::ValueSpaceError) do XSD::XSDString.new("\0") end assert_raises(XSD::ValueSpaceError) do p XSD::XSDString.new("\xC0\xC0").to_s end ensure XSD::Charset.module_eval { @encoding = @encoding_backup } end end def test_XSDBoolean o = XSD::XSDBoolean.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::BooleanLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ ["true", true], ["1", true], ["false", false], ["0", false], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDBoolean.new(data).data) assert_equal(expected.to_s, XSD::XSDBoolean.new(data).to_s) end assert_raises(XSD::ValueSpaceError) do XSD::XSDBoolean.new("nil").to_s end end def test_XSDDecimal o = XSD::XSDDecimal.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::DecimalLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 0, 1000000000, -9999999999, 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890, 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890, -1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789, ] targets.each do |dec| assert_equal(dec.to_s, XSD::XSDDecimal.new(dec).data) end targets = [ "0", "0.00000001", "1000000000", "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "-12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123.45678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789", ] targets.each do |str| assert_equal(str, XSD::XSDDecimal.new(str).to_s) end targets = [ ["-0", "0"], ["+0", "0"], ["0.0", "0"], ["-0.0", "0"], ["+0.0", "0"], ["0.", "0"], [".0", "0"], [ "+0.12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "0.1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" ], [ ".0000012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "0.000001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" ], [ "-12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890.", "-12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" ], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDDecimal.new(data).to_s) end targets = [ "0.000000000000a", "00a.0000000000001", "+-5", ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do XSD::XSDDecimal.new(d) end end end def test_XSDFloat o = XSD::XSDFloat.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::FloatLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 3.14159265358979, 12.34e36, 1.402e-45, -1.402e-45, ] targets.each do |f| assert_equal(f, XSD::XSDFloat.new(f).data) end targets = [ "+3.141592654", "+1.234e+37", "+1.402e-45", "-1.402e-45", ] targets.each do |f| assert_equal(f, XSD::XSDFloat.new(f).to_s) end targets = [ [3, "+3"], # should be 3.0? [-2, "-2"], # ditto [3.14159265358979, "+3.141592654"], [12.34e36, "+1.234e+37"], [1.402e-45, "+1.402e-45"], [-1.402e-45, "-1.402e-45"], ["1.402e", "+1.402"], ["12.34E36", "+1.234e+37"], ["1.402E-45", "+1.402e-45"], ["-1.402E-45", "-1.402e-45"], ["1.402E", "+1.402"], ] targets.each do |f, str| assert_equal(str, XSD::XSDFloat.new(f).to_s) end assert_equal("+0", XSD::XSDFloat.new(+0.0).to_s) assert_equal("-0", XSD::XSDFloat.new(NegativeZero).to_s) assert(XSD::XSDFloat.new(0.0/0.0).data.nan?) assert_equal("INF", XSD::XSDFloat.new(1.0/0.0).to_s) assert_equal(1, XSD::XSDFloat.new(1.0/0.0).data.infinite?) assert_equal("-INF", XSD::XSDFloat.new(-1.0/0.0).to_s) assert_equal(-1, XSD::XSDFloat.new(-1.0/0.0).data.infinite?) targets = [ "0.000000000000a", "00a.0000000000001", "+-5", "5_0", ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do XSD::XSDFloat.new(d) end end end def test_XSDDouble o = XSD::XSDDouble.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::DoubleLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 3.14159265358979, 12.34e36, 1.402e-45, -1.402e-45, ] targets.each do |f| assert_equal(f, XSD::XSDDouble.new(f).data) end targets = [ "+3.14159265358979", "+1.234e+37", "+1.402e-45", "-1.402e-45", ] targets.each do |f| assert_equal(f, XSD::XSDDouble.new(f).to_s) end targets = [ [3, "+3"], # should be 3.0? [-2, "-2"], # ditto. [3.14159265358979, "+3.14159265358979"], [12.34e36, "+1.234e+37"], [1.402e-45, "+1.402e-45"], [-1.402e-45, "-1.402e-45"], ["1.402e", "+1.402"], ["12.34E36", "+1.234e+37"], ["1.402E-45", "+1.402e-45"], ["-1.402E-45", "-1.402e-45"], ["1.402E", "+1.402"], ] targets.each do |f, str| assert_equal(str, XSD::XSDDouble.new(f).to_s) end assert_equal("+0", XSD::XSDFloat.new(+0.0).to_s) assert_equal("-0", XSD::XSDFloat.new(NegativeZero).to_s) assert_equal("NaN", XSD::XSDDouble.new(0.0/0.0).to_s) assert(XSD::XSDDouble.new(0.0/0.0).data.nan?) assert_equal("INF", XSD::XSDDouble.new(1.0/0.0).to_s) assert_equal(1, XSD::XSDDouble.new(1.0/0.0).data.infinite?) assert_equal("-INF", XSD::XSDDouble.new(-1.0/0.0).to_s) assert_equal(-1, XSD::XSDDouble.new(-1.0/0.0).data.infinite?) targets = [ "0.000000000000a", "00a.0000000000001", "+-5", ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do XSD::XSDDouble.new(d) end end end def test_XSDDuration o = XSD::XSDDuration.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::DurationLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "P1Y2M3DT4H5M6S", "P1234Y5678M9012DT3456H7890M1234.5678S", "P0DT3456H7890M1234.5678S", "P1234Y5678M9012D", "-P1234Y5678M9012DT3456H7890M1234.5678S", "P5678M9012DT3456H7890M1234.5678S", "-P1234Y9012DT3456H7890M1234.5678S", "+P1234Y5678MT3456H7890M1234.5678S", "P1234Y5678M9012DT7890M1234.5678S", "-P1234Y5678M9012DT3456H1234.5678S", "+P1234Y5678M9012DT3456H7890M", "P123400000000000Y", "-P567800000000000M", "+P901200000000000D", "P0DT345600000000000H", "-P0DT789000000000000M", "+P0DT123400000000000.000000000005678S", "P1234YT1234.5678S", "-P5678MT7890M", "+P9012DT3456H", ] targets.each do |str| assert_parsed_result(XSD::XSDDuration, str) end targets = [ ["P0Y0M0DT0H0M0S", "P0D"], ["-P0DT0S", "-P0D"], ["P01234Y5678M9012DT3456H7890M1234.5678S", "P1234Y5678M9012DT3456H7890M1234.5678S"], ["P1234Y005678M9012DT3456H7890M1234.5678S", "P1234Y5678M9012DT3456H7890M1234.5678S"], ["P1234Y5678M0009012DT3456H7890M1234.5678S", "P1234Y5678M9012DT3456H7890M1234.5678S"], ["P1234Y5678M9012DT00003456H7890M1234.5678S", "P1234Y5678M9012DT3456H7890M1234.5678S"], ["P1234Y5678M9012DT3456H000007890M1234.5678S", "P1234Y5678M9012DT3456H7890M1234.5678S"], ["P1234Y5678M9012DT3456H7890M0000001234.5678S", "P1234Y5678M9012DT3456H7890M1234.5678S"], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDDuration.new(data).to_s) end end def test_XSDDateTime o = XSD::XSDDateTime.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::DateTimeLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "2002-05-18T16:52:20Z", "0001-01-01T00:00:00Z", "9999-12-31T23:59:59Z", "19999-12-31T23:59:59Z", "2002-12-31T23:59:59.999Z", "2002-12-31T23:59:59.001Z", "2002-12-31T23:59:59.99999999999999999999Z", "2002-12-31T23:59:59.00000000000000000001Z", "2002-12-31T23:59:59+09:00", "2002-12-31T23:59:59+00:01", "2002-12-31T23:59:59-00:01", "2002-12-31T23:59:59-23:59", "2002-12-31T23:59:59.00000000000000000001+13:30", "2002-12-31T23:59:59.5137Z", "2002-12-31T23:59:59.51375Z", # 411/800 "2002-12-31T23:59:59.51375+12:34", "-2002-05-18T16:52:20Z", "-4713-01-01T12:00:00Z", "-2002-12-31T23:59:59+00:01", "-0001-12-31T23:59:59.00000000000000000001+13:30", ] targets.each do |str| assert_parsed_result(XSD::XSDDateTime, str) end targets = [ ["2002-12-31T23:59:59.00", "2002-12-31T23:59:59Z"], ["2002-12-31T23:59:59+00:00", "2002-12-31T23:59:59Z"], ["2002-12-31T23:59:59-00:00", "2002-12-31T23:59:59Z"], ["-2002-12-31T23:59:59.00", "-2002-12-31T23:59:59Z"], ["-2002-12-31T23:59:59+00:00", "-2002-12-31T23:59:59Z"], ["-2002-12-31T23:59:59-00:00", "-2002-12-31T23:59:59Z"], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDDateTime.new(data).to_s) d = DateTime.parse(data) d >>= 12 if d.year < 0 # XSDDateTime.year(-1) == DateTime.year(0) assert_equal(expected, XSD::XSDDateTime.new(d).to_s) end targets = [ "0000-05-18T16:52:20Z", "05-18T16:52:20Z", "2002-05T16:52:20Z", "2002-05-18T16:52Z", "", ] targets.each do |d| assert_raises(XSD::ValueSpaceError, d.to_s) do XSD::XSDDateTime.new(d) end end end def test_XSDTime o = XSD::XSDTime.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::TimeLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "16:52:20Z", "00:00:00Z", "23:59:59Z", "23:59:59.999Z", "23:59:59.001Z", "23:59:59.99999999999999999999Z", "23:59:59.00000000000000000001Z", "23:59:59+09:00", "23:59:59+00:01", "23:59:59-00:01", "23:59:59-23:59", "23:59:59.00000000000000000001+13:30", "23:59:59.51345Z", "23:59:59.51345+12:34", "23:59:59+00:01", ] targets.each do |str| assert_parsed_result(XSD::XSDTime, str) end targets = [ ["23:59:59.00", "23:59:59Z"], ["23:59:59+00:00", "23:59:59Z"], ["23:59:59-00:00", "23:59:59Z"], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDTime.new(data).to_s) end end def test_XSDDate o = XSD::XSDDate.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::DateLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "2002-05-18Z", "0001-01-01Z", "9999-12-31Z", "19999-12-31Z", "2002-12-31+09:00", "2002-12-31+00:01", "2002-12-31-00:01", "2002-12-31-23:59", "2002-12-31+13:30", "-2002-05-18Z", "-19999-12-31Z", "-2002-12-31+00:01", "-0001-12-31+13:30", ] targets.each do |str| assert_parsed_result(XSD::XSDDate, str) end targets = [ ["2002-12-31", "2002-12-31Z"], ["2002-12-31+00:00", "2002-12-31Z"], ["2002-12-31-00:00", "2002-12-31Z"], ["-2002-12-31", "-2002-12-31Z"], ["-2002-12-31+00:00", "-2002-12-31Z"], ["-2002-12-31-00:00", "-2002-12-31Z"], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDDate.new(data).to_s) d = Date.parse(data) d >>= 12 if d.year < 0 # XSDDate.year(-1) == Date.year(0) assert_equal(expected, XSD::XSDDate.new(d).to_s) end end end class TestXSD2 < Test::Unit::TestCase def setup # Nothing to do. end def teardown # Nothing to do. end def assert_parsed_result(klass, str) o = klass.new(str) assert_equal(str, o.to_s) end def test_XSDGYearMonth o = XSD::XSDGYearMonth.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::GYearMonthLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "2002-05Z", "0001-01Z", "9999-12Z", "19999-12Z", "2002-12+09:00", "2002-12+00:01", "2002-12-00:01", "2002-12-23:59", "2002-12+13:30", "-2002-05Z", "-19999-12Z", "-2002-12+00:01", "-0001-12+13:30", ] targets.each do |str| assert_parsed_result(XSD::XSDGYearMonth, str) end targets = [ ["2002-12", "2002-12Z"], ["2002-12+00:00", "2002-12Z"], ["2002-12-00:00", "2002-12Z"], ["-2002-12", "-2002-12Z"], ["-2002-12+00:00", "-2002-12Z"], ["-2002-12-00:00", "-2002-12Z"], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDGYearMonth.new(data).to_s) end end def test_XSDGYear o = XSD::XSDGYear.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::GYearLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "2002Z", "0001Z", "9999Z", "19999Z", "2002+09:00", "2002+00:01", "2002-00:01", "2002-23:59", "2002+13:30", "-2002Z", "-19999Z", "-2002+00:01", "-0001+13:30", ] targets.each do |str| assert_parsed_result(XSD::XSDGYear, str) end targets = [ ["2002", "2002Z"], ["2002+00:00", "2002Z"], ["2002-00:00", "2002Z"], ["-2002", "-2002Z"], ["-2002+00:00", "-2002Z"], ["-2002-00:00", "-2002Z"], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDGYear.new(data).to_s) end end def test_XSDGMonthDay o = XSD::XSDGMonthDay.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::GMonthDayLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "05-18Z", "01-01Z", "12-31Z", "12-31+09:00", "12-31+00:01", "12-31-00:01", "12-31-23:59", "12-31+13:30", ] targets.each do |str| assert_parsed_result(XSD::XSDGMonthDay, str) end targets = [ ["12-31", "12-31Z"], ["12-31+00:00", "12-31Z"], ["12-31-00:00", "12-31Z"], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDGMonthDay.new(data).to_s) end end def test_XSDGDay o = XSD::XSDGDay.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::GDayLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "18Z", "01Z", "31Z", "31+09:00", "31+00:01", "31-00:01", "31-23:59", "31+13:30", ] targets.each do |str| assert_parsed_result(XSD::XSDGDay, str) end targets = [ ["31", "31Z"], ["31+00:00", "31Z"], ["31-00:00", "31Z"], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDGDay.new(data).to_s) end end def test_XSDGMonth o = XSD::XSDGMonth.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::GMonthLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "05Z", "01Z", "12Z", "12+09:00", "12+00:01", "12-00:01", "12-23:59", "12+13:30", ] targets.each do |str| assert_parsed_result(XSD::XSDGMonth, str) end targets = [ ["12", "12Z"], ["12+00:00", "12Z"], ["12-00:00", "12Z"], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDGMonth.new(data).to_s) end end def test_XSDHexBinary o = XSD::XSDHexBinary.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::HexBinaryLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "abcdef", "\xe3\x81\xaa\xe3\x81\xb2", %Q(\0), "", ] targets.each do |str| assert_equal(str, XSD::XSDHexBinary.new(str).string) assert_equal(str.unpack("H*")[0 ].tr('a-f', 'A-F'), XSD::XSDHexBinary.new(str).data) o = XSD::XSDHexBinary.new o.set_encoded(str.unpack("H*")[0 ].tr('a-f', 'A-F')) assert_equal(str, o.string) o.set_encoded(str.unpack("H*")[0 ].tr('A-F', 'a-f')) assert_equal(str, o.string) end targets = [ "0FG7", "0fg7", ] targets.each do |d| assert_raises(XSD::ValueSpaceError, d.to_s) do o = XSD::XSDHexBinary.new o.set_encoded(d) p o.string end end end def test_XSDBase64Binary o = XSD::XSDBase64Binary.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::Base64BinaryLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ "abcdef", "\xe3\x81\xaa\xe3\x81\xb2", %Q(\0), "", ] targets.each do |str| assert_equal(str, XSD::XSDBase64Binary.new(str).string) assert_equal([str ].pack("m").chomp, XSD::XSDBase64Binary.new(str).data) o = XSD::XSDBase64Binary.new o.set_encoded([str ].pack("m").chomp) assert_equal(str, o.string) end targets = [ "-", "*", ] targets.each do |d| assert_raises(XSD::ValueSpaceError, d.to_s) do o = XSD::XSDBase64Binary.new o.set_encoded(d) p o.string end end end def test_XSDAnyURI o = XSD::XSDAnyURI.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::AnyURILiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) # Too few tests here I know. Believe uri module. :) targets = [ "foo", "http://foo", "http://foo/bar/baz", "http://foo/bar#baz", "http://foo/bar%20%20?a+b", "HTTP://FOO/BAR%20%20?A+B", ] targets.each do |str| assert_parsed_result(XSD::XSDAnyURI, str) end end def test_XSDQName o = XSD::XSDQName.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::QNameLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) # More strict test is needed but current implementation allows all non-':' # chars like ' ', C0 or C1... targets = [ "foo", "foo:bar", "a:b", ] targets.each do |str| assert_parsed_result(XSD::XSDQName, str) end end ### ## Derived types # def test_XSDInteger o = XSD::XSDInteger.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::IntegerLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 0, 1000000000, -9999999999, 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890, 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890, -1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789, ] targets.each do |int| assert_equal(int, XSD::XSDInteger.new(int).data) end targets = [ "0", "1000000000", "-9999999999", "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "-1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789", ] targets.each do |str| assert_equal(str, XSD::XSDInteger.new(str).to_s) end targets = [ ["-0", "0"], ["+0", "0"], ["000123", "123"], ["-000123", "-123"], [ "+12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" ], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDInteger.new(data).to_s) end targets = [ "0.0", "-5.2", "0.000000000000a", "+-5", "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890." ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do XSD::XSDInteger.new(d) end end end def test_XSDNonPositiveInteger o = XSD::XSDNonPositiveInteger.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::NonPositiveIntegerLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 0, -9999999999, -1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789, ] targets.each do |int| assert_equal(int, XSD::XSDNonPositiveInteger.new(int).data) end targets = [ "0", "-9999999999", "-1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789", ] targets.each do |str| assert_equal(str, XSD::XSDNonPositiveInteger.new(str).to_s) end targets = [ ["-0", "0"], ["-000123", "-123"], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDNonPositiveInteger.new(data).to_s) end targets = [ "0.0", "-5.2", "0.000000000000a", "+-5", "-12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890." ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do XSD::XSDNonPositiveInteger.new(d) end end end def test_XSDNegativeInteger o = XSD::XSDNegativeInteger.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::NegativeIntegerLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ -1, -9999999999, -1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789, ] targets.each do |int| assert_equal(int, XSD::XSDNegativeInteger.new(int).data) end targets = [ "-1", "-9999999999", "-1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789", ] targets.each do |str| assert_equal(str, XSD::XSDNegativeInteger.new(str).to_s) end targets = [ ["-000123", "-123"], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDNegativeInteger.new(data).to_s) end targets = [ "-0.0", "-5.2", "-0.000000000000a", "+-5", "-12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890." ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do XSD::XSDNegativeInteger.new(d) end end end def test_XSDLong o = XSD::XSDLong.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::LongLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 0, 123, -123, 9223372036854775807, -9223372036854775808, ] targets.each do |lng| assert_equal(lng, XSD::XSDLong.new(lng).data) end targets = [ "0", "123", "-123", "9223372036854775807", "-9223372036854775808", ] targets.each do |str| assert_equal(str, XSD::XSDLong.new(str).to_s) end targets = [ ["-0", "0"], ["+0", "0"], ["000123", "123"], ["-000123", "-123"], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDLong.new(data).to_s) end targets = [ 9223372036854775808, -9223372036854775809, "0.0", "-5.2", "0.000000000000a", "+-5", ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do XSD::XSDLong.new(d) end end end def test_XSDInt o = XSD::XSDInt.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::IntLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 0, 123, -123, 2147483647, -2147483648, ] targets.each do |lng| assert_equal(lng, XSD::XSDInt.new(lng).data) end targets = [ "0", "123", "-123", "2147483647", "-2147483648", ] targets.each do |str| assert_equal(str, XSD::XSDInt.new(str).to_s) end targets = [ ["-0", "0"], ["+0", "0"], ["000123", "123"], ["-000123", "-123"], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDInt.new(data).to_s) end targets = [ 2147483648, -2147483649, "0.0", "-5.2", "0.000000000000a", "+-5", ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do XSD::XSDInt.new(d) end end end def test_XSDShort o = XSD::XSDShort.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::ShortLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 0, 123, -123, 32767, -32768, ] targets.each do |lng| assert_equal(lng, XSD::XSDShort.new(lng).data) end targets = [ "0", "123", "-123", "32767", "-32768", ] targets.each do |str| assert_equal(str, XSD::XSDShort.new(str).to_s) end targets = [ ["-0", "0"], ["+0", "0"], ["000123", "123"], ["-000123", "-123"], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDShort.new(data).to_s) end targets = [ 32768, -32769, "0.0", "-5.2", "0.000000000000a", "+-5", ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do XSD::XSDShort.new(d) end end end def test_XSDByte o = XSD::XSDByte.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::ByteLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 0, 123, -123, 127, -128, ] targets.each do |lng| assert_equal(lng, XSD::XSDByte.new(lng).data) end targets = [ "0", "123", "-123", "127", "-128", ] targets.each do |str| assert_equal(str, XSD::XSDByte.new(str).to_s) end targets = [ ["-0", "0"], ["+0", "0"], ["000123", "123"], ["-000123", "-123"], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDByte.new(data).to_s) end targets = [ 128, -129, "0.0", "-5.2", "0.000000000000a", "+-5", ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do XSD::XSDByte.new(d) end end end def test_XSDNonNegativeInteger o = XSD::XSDNonNegativeInteger.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::NonNegativeIntegerLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 0, 1000000000, 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890, ] targets.each do |int| assert_equal(int, XSD::XSDNonNegativeInteger.new(int).data) end targets = [ "0", "1000000000", "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", ] targets.each do |str| assert_equal(str, XSD::XSDNonNegativeInteger.new(str).to_s) end targets = [ ["-0", "0"], ["+0", "0"], ["000123", "123"], [ "+12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" ], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDNonNegativeInteger.new(data).to_s) end targets = [ "0.0", "0.000000000000a", "+-5", "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890." ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do XSD::XSDNonNegativeInteger.new(d) end end end def test_XSDUnsignedLong o = XSD::XSDUnsignedLong.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::UnsignedLongLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 0, 1000000000, 18446744073709551615, ] targets.each do |int| assert_equal(int, XSD::XSDUnsignedLong.new(int).data) end targets = [ "0", "1000000000", "18446744073709551615", ] targets.each do |str| assert_equal(str, XSD::XSDUnsignedLong.new(str).to_s) end targets = [ ["-0", "0"], ["+0", "0"], ["000123", "123"], ["+18446744073709551615", "18446744073709551615"], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDUnsignedLong.new(data).to_s) end targets = [ "0.0", "0.000000000000a", "+-5", "18446744073709551615." ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do XSD::XSDUnsignedLong.new(d) end end end def test_XSDUnsignedInt o = XSD::XSDUnsignedInt.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::UnsignedIntLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 0, 1000000000, 4294967295, ] targets.each do |int| assert_equal(int, XSD::XSDUnsignedInt.new(int).data) end targets = [ "0", "1000000000", "4294967295", ] targets.each do |str| assert_equal(str, XSD::XSDUnsignedInt.new(str).to_s) end targets = [ ["-0", "0"], ["+0", "0"], ["000123", "123"], ["+4294967295", "4294967295"], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDUnsignedInt.new(data).to_s) end targets = [ "0.0", "0.000000000000a", "+-5", "4294967295." ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do XSD::XSDUnsignedInt.new(d) end end end def test_XSDUnsignedShort o = XSD::XSDUnsignedShort.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::UnsignedShortLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 0, 10000, 65535, ] targets.each do |int| assert_equal(int, XSD::XSDUnsignedShort.new(int).data) end targets = [ "0", "1000", "65535", ] targets.each do |str| assert_equal(str, XSD::XSDUnsignedShort.new(str).to_s) end targets = [ ["-0", "0"], ["+0", "0"], ["000123", "123"], ["+65535", "65535"], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDUnsignedShort.new(data).to_s) end targets = [ "0.0", "0.000000000000a", "+-5", "65535." ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do XSD::XSDUnsignedShort.new(d) end end end def test_XSDUnsignedByte o = XSD::XSDUnsignedByte.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::UnsignedByteLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 0, 10, 255, ] targets.each do |int| assert_equal(int, XSD::XSDUnsignedByte.new(int).data) end targets = [ "0", "10", "255", ] targets.each do |str| assert_equal(str, XSD::XSDUnsignedByte.new(str).to_s) end targets = [ ["-0", "0"], ["+0", "0"], ["000123", "123"], ["+255", "255"], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDUnsignedByte.new(data).to_s) end targets = [ "0.0", "0.000000000000a", "+-5", "255." ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do XSD::XSDUnsignedByte.new(d) end end end def test_XSDPositiveInteger o = XSD::XSDPositiveInteger.new assert_equal(XSD::Namespace, o.type.namespace) assert_equal(XSD::PositiveIntegerLiteral, o.type.name) assert_equal(nil, o.data) assert_equal(true, o.is_nil) targets = [ 1, 1000000000, 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890, ] targets.each do |int| assert_equal(int, XSD::XSDPositiveInteger.new(int).data) end targets = [ "1", "1000000000", "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", ] targets.each do |str| assert_equal(str, XSD::XSDPositiveInteger.new(str).to_s) end targets = [ ["+1", "1"], ["000123", "123"], [ "+12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" ], ] targets.each do |data, expected| assert_equal(expected, XSD::XSDPositiveInteger.new(data).to_s) end targets = [ "1.0", "1.000000000000a", "+-5", "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890." ] targets.each do |d| assert_raises(XSD::ValueSpaceError) do XSD::XSDPositiveInteger.new(d) end end end end end ================================================ FILE: test/xsd/xmlschema.xml ================================================ ================================================ FILE: test/yaml/test_yaml.rb ================================================ # -*- mode: ruby; ruby-indent-level: 4; tab-width: 4 -*- # vim:sw=4:ts=4 # $Id$ # require 'test/unit' require 'yaml' # [ruby-core:01946] module YAML_Tests StructTest = Struct::new( :c ) end class YAML_Unit_Tests < Test::Unit::TestCase # # Convert between YAML and the object to verify correct parsing and # emitting # def assert_to_yaml( obj, yaml ) assert_equal( obj, YAML::load( yaml ) ) assert_equal( obj, YAML::parse( yaml ).transform ) assert_equal( obj, YAML::load( obj.to_yaml ) ) assert_equal( obj, YAML::parse( obj.to_yaml ).transform ) assert_equal( obj, YAML::load( obj.to_yaml( :UseVersion => true, :UseHeader => true, :SortKeys => true ) ) ) end # # Test parser only # def assert_parse_only( obj, yaml ) assert_equal( obj, YAML::load( yaml ) ) assert_equal( obj, YAML::parse( yaml ).transform ) end def assert_cycle( obj ) assert_equal( obj, YAML::load( obj.to_yaml ) ) end def assert_path_segments( path, segments ) YAML::YPath.each_path( path ) { |choice| assert_equal( choice.segments, segments.shift ) } assert_equal( segments.length, 0, "Some segments leftover: #{ segments.inspect }" ) end # # Make a time with the time zone # def mktime( year, mon, day, hour, min, sec, usec, zone = "Z" ) usec = usec.to_s.to_f * 1000000 val = Time::utc( year.to_i, mon.to_i, day.to_i, hour.to_i, min.to_i, sec.to_i, usec ) if zone != "Z" hour = zone[0,3].to_i * 3600 min = zone[3,2].to_i * 60 ofs = (hour + min) val = Time.at( val.to_f - ofs ) end return val end # # Tests modified from 00basic.t in YAML.pm # def test_basic_map # Simple map assert_parse_only( { 'one' => 'foo', 'three' => 'baz', 'two' => 'bar' }, < 'simple string', 2 => 42, 3 => '1 Single Quoted String', 4 => 'YAML\'s Double "Quoted" String', 5 => "A block\n with several\n lines.\n", 6 => "A \"chomped\" block", 7 => "A folded\n string\n", 8 => ": started string" }, < A folded string 8: ": started string" EOY ) end # # Test the specification examples # - Many examples have been changes because of whitespace problems that # caused the two to be inequivalent, or keys to be sorted wrong # def test_spec_simple_implicit_sequence # Simple implicit sequence assert_to_yaml( [ 'Mark McGwire', 'Sammy Sosa', 'Ken Griffey' ], < 65, 'avg' => 0.278, 'rbi' => 147 }, < [ 'Boston Red Sox', 'Detroit Tigers', 'New York Yankees' ], 'national' => [ 'New York Mets', 'Chicago Cubs', 'Atlanta Braves' ] }, < 'Mark McGwire', 'hr' => 65, 'avg' => 0.278}, {'name' => 'Sammy Sosa', 'hr' => 63, 'avg' => 0.288} ], < { 'hr' => 65, 'avg' => 0.278 }, 'Sammy Sosa' => { 'hr' => 63, 'avg' => 0.288 } }, < [ 'Mark McGwire', 'Sammy Sosa' ], 'rbi' => [ 'Sammy Sosa', 'Ken Griffey' ] }, < [ 'Mark McGwire', 'Sammy Sosa' ], 'rbi' => [ 'Sammy Sosa', 'Ken Griffey' ] }, <"EDI", "departure"=>"LAX", "fareref"=>"DOGMA", "currency"=>"GBP"}, {"arrival"=>"MEL", "departure"=>"SYD", "fareref"=>"MADF", "currency"=>"AUD"}, {"arrival"=>"MCO", "departure"=>"JFK", "fareref"=>"DFSF", "currency"=>"USD"}], <["fareref", "currency", "departure", "arrival"], "FARES"=>[{"arrival"=>"EDI", "departure"=>"LAX", "fareref"=>"DOGMA", "currency"=>"GBP"}, {"arrival"=>"MEL", "departure"=>"SYD", "fareref"=>"MADF", "currency"=>"AUD"}, {"arrival"=>"MCO", "departure"=>"JFK", "fareref"=>"DFSF", "currency"=>"USD"}]}, < [ Date.new( 2001, 7, 23 ) ], [ 'New York Yankees', 'Atlanta Braves' ] => [ Date.new( 2001, 7, 2 ), Date.new( 2001, 8, 12 ), Date.new( 2001, 8, 14 ) ] }, < [ Date.new( 2001, 7, 2 ), Date.new( 2001, 8, 12 ), Date.new( 2001, 8, 14 ) ], [ 'Detroit Tigers', 'Chicago Cubs' ] => [ Date.new( 2001, 7, 23 ) ] }, < 34843, 'date' => Date.new( 2001, 1, 23 ), 'bill-to' => 'Chris Dumars', 'product' => [ { 'item' => 'Super Hoop', 'quantity' => 1 }, { 'item' => 'Basketball', 'quantity' => 4 }, { 'item' => 'Big Shoes', 'quantity' => 1 } ] }, < nil }, [ { 'five' => [ 'six' ] } ], [ 'seven' ] ], [ 'eight', 'nine' ] ], < Mark McGwire\'s year was crippled by a knee injury. EOY ) end def test_spec_preserve_indent # Preserve indented spaces assert_parse_only( "Sammy Sosa completed another fine season with great stats.\n\n 63 Home Runs\n 0.288 Batting Average\n\nWhat a year!\n", < Sammy Sosa completed another fine season with great stats. 63 Home Runs 0.288 Batting Average What a year! EOY ) end def test_spec_indentation_determines_scope assert_parse_only( { 'name' => 'Mark McGwire', 'accomplishment' => "Mark set a major league home run record in 1998.\n", 'stats' => "65 Home Runs\n0.278 Batting Average\n" }, < Mark set a major league home run record in 1998. stats: | 65 Home Runs 0.278 Batting Average EOY ) end def test_spec_multiline_scalars # Multiline flow scalars assert_parse_only( { 'plain' => 'This unquoted scalar spans many lines.', 'quoted' => "So does this quoted scalar.\n" }, < 12345, 'decimal' => 12345, 'octal' => '014'.oct, 'hexadecimal' => '0xC'.hex }, < 685230, 'decimal' => 685230, 'octal' => 02472256, 'hexadecimal' => 0x0A74AE, 'sexagesimal' => 685230 }, < 1230.15, 'exponential' => 1230.15, 'fixed' => 1230.15, 'negative infinity' => -1.0/0.0 }, < nil, true => true, false => false, 'string' => '12345' }, < 'Chris', 'family' => 'Dumars', 'address' => { 'lines' => "458 Walkman Dr.\nSuite #292\n", 'city' => 'Royal Oak', 'state' => 'MI', 'postal' => 48046 } } assert_parse_only( { 'invoice' => 34843, 'date' => Date.new( 2001, 1, 23 ), 'bill-to' => id001, 'ship-to' => id001, 'product' => [ { 'sku' => 'BL394D', 'quantity' => 4, 'description' => 'Basketball', 'price' => 450.00 }, { 'sku' => 'BL4438H', 'quantity' => 1, 'description' => 'Super Hoop', 'price' => 2392.00 } ], 'tax' => 251.42, 'total' => 4443.52, 'comments' => "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338.\n" }, < Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338. EOY ) end def test_spec_log_file doc_ct = 0 YAML::load_documents( < This is an error message for the log file --- Time: 2001-11-23 15:02:31 -05:00 User: ed Warning: > A slightly different error message. --- Date: 2001-11-23 15:03:17 -05:00 User: ed Fatal: > Unknown variable "bar" Stack: - file: TopClass.py line: 23 code: | x = MoreObject("345\\n") - file: MoreClass.py line: 58 code: |- foo = bar EOY ) { |doc| case doc_ct when 0 assert_equal( doc, { 'Time' => mktime( 2001, 11, 23, 15, 01, 42, 00, "-05:00" ), 'User' => 'ed', 'Warning' => "This is an error message for the log file\n" } ) when 1 assert_equal( doc, { 'Time' => mktime( 2001, 11, 23, 15, 02, 31, 00, "-05:00" ), 'User' => 'ed', 'Warning' => "A slightly different error message.\n" } ) when 2 assert_equal( doc, { 'Date' => mktime( 2001, 11, 23, 15, 03, 17, 00, "-05:00" ), 'User' => 'ed', 'Fatal' => "Unknown variable \"bar\"\n", 'Stack' => [ { 'file' => 'TopClass.py', 'line' => 23, 'code' => "x = MoreObject(\"345\\n\")\n" }, { 'file' => 'MoreClass.py', 'line' => 58, 'code' => "foo = bar" } ] } ) end doc_ct += 1 } assert_equal( doc_ct, 3 ) end def test_spec_root_fold y = YAML::load( < This YAML stream contains a single text value. The next stream is a log file - a sequence of log entries. Adding an entry to the log is a simple matter of appending it at the end. EOY ) assert_equal( y, "This YAML stream contains a single text value. The next stream is a log file - a sequence of log entries. Adding an entry to the log is a simple matter of appending it at the end.\n" ) end def test_spec_root_mapping y = YAML::load( < 34843, 'date' => Date.new( 2001, 1, 23 ), 'total' => 4443.52 } ) end def test_spec_oneline_docs doc_ct = 0 YAML::load_documents( < { "customers"=> [ { "given"=>"Chris", "type"=>"domain customer", "family"=>"Dumars" } ], "type"=>"domain invoice" } }, <"contains three lines of text.\nThe third one starts with a\n# character. This isn't a comment.\n"}, < 12, 'also int' => 12, 'string' => '12' }, < 8, 'color' => 'black' } ) when 1 assert_equal( doc['bearing'].type_id, 'x-private:ball' ) assert_equal( doc['bearing'].transform.value, { 'material' => 'steel' } ) end doc_ct += 1 } assert_equal( doc_ct, 2 ) end def test_spec_url_escaping YAML.add_domain_type( "domain.tld,2002", "type0" ) { |type, val| "ONE: #{val}" } YAML.add_domain_type( "domain.tld,2002", "type%30" ) { |type, val| "TWO: #{val}" } assert_parse_only( { 'same' => [ 'ONE: value', 'ONE: value' ], 'different' => [ 'TWO: value' ] }, < 'This scalar has an anchor.', 'override' => a001, 'alias' => a001 }, < The alias node below is a repeated use of this value. alias : *A001 EOY ) end def test_spec_explicit_families YAML.add_domain_type( "somewhere.com,2002", 'type' ) { |type, val| "SOMEWHERE: #{val}" } assert_parse_only( { 'not-date' => '2002-04-28', 'picture' => "GIF89a\f\000\f\000\204\000\000\377\377\367\365\365\356\351\351\345fff\000\000\000\347\347\347^^^\363\363\355\216\216\216\340\340\340\237\237\237\223\223\223\247\247\247\236\236\236i^\020' \202\n\001\000;", 'hmm' => "SOMEWHERE: family above is short for\nhttp://somewhere.com/type\n" }, <7, "center"=>{"x"=>73, "y"=>129}, "TYPE"=>"Shape: graph/circle"}, {"finish"=>{"x"=>89, "y"=>102}, "TYPE"=>"Shape: graph/line", "start"=>{"x"=>73, "y"=>129}}, {"TYPE"=>"Shape: graph/text", "value"=>"Pretty vector drawing.", "start"=>{"x"=>73, "y"=>129}, "color"=>16772795}, "Shape Container"]], < [], 'in-line' => [ 'one', 'two', 'three', 'four', 'five' ], 'nested' => [ 'First item in top sequence', [ 'Subordinate sequence entry' ], "A multi-line sequence entry\n", 'Sixth item in top sequence' ] }, < A multi-line sequence entry - Sixth item in top sequence EOY ) end def test_spec_builtin_map # Assortment of mappings assert_parse_only( { 'empty' => {}, 'in-line' => { 'one' => 1, 'two' => 2 }, 'spanning' => { 'one' => 1, 'two' => 2 }, 'nested' => { 'first' => 'First entry', 'second' => { 'key' => 'Subordinate mapping' }, 'third' => [ 'Subordinate sequence', {}, 'Previous mapping is empty.', { 'A key' => 'value pair in a sequence.', 'A second' => 'key:value pair.' }, 'The previous entry is equal to the following one.', { 'A key' => 'value pair in a sequence.', 'A second' => 'key:value pair.' } ], 12.0 => 'This key is a float.', "?\n" => 'This key had to be protected.', "\a" => 'This key had to be escaped.', "This is a multi-line folded key\n" => "Whose value is also multi-line.\n", [ 'This key', 'is a sequence' ] => [ 'With a sequence value.' ] } }, < ? : This key had to be protected. "\\a" : This key had to be escaped. ? > This is a multi-line folded key : > Whose value is also multi-line. ? - This key - is a sequence : - With a sequence value. # The following parses correctly, # but Ruby 1.6.* fails the comparison! # ? # This: key # is a: mapping # : # with a: mapping value. EOY ) end def test_spec_builtin_literal_blocks # Assortment of literal scalar blocks assert_parse_only( {"both are equal to"=>" This has no newline.", "is equal to"=>"The \\ ' \" characters may be\nfreely used. Leading white\n space is significant.\n\nLine breaks are significant.\nThus this value contains one\nempty line and ends with a\nsingle line break, but does\nnot start with one.\n", "also written as"=>" This has no newline.", "indented and chomped"=>" This has no newline.", "empty"=>"", "literal"=>"The \\ ' \" characters may be\nfreely used. Leading white\n space is significant.\n\nLine breaks are significant.\nThus this value contains one\nempty line and ends with a\nsingle line break, but does\nnot start with one.\n"}, < str1, 'same as "clipped" above' => str1, 'stripped' => str2, 'same as "stripped" above' => str2, 'kept' => str3, 'same as "kept" above' => str3 }, <"a single quote ' must be escaped.", "second"=>"! : \\ etc. can be used freely.", "is same as"=>"this contains six spaces\nand one line break", "empty"=>"", "span"=>"this contains six spaces\nand one line break"}, <"this contains four spaces", "third"=>"a \" or a \\ must be escaped.", "second"=>"! : etc. can be used freely.", "empty"=>"", "fourth"=>"this value ends with an LF.\n", "span"=>"this contains four spaces"}, < mktime( 2001, 12, 14, 21, 59, 43, ".10", "-05:00" ), "canonical" => mktime( 2001, 12, 15, 2, 59, 43, ".10" ), "date (noon UTC)" => Date.new( 2002, 12, 14), "valid iso8601" => mktime( 2001, 12, 14, 21, 59, 43, ".10", "-05:00" ) }, < arrow_gif, 'base64' => arrow_gif, 'description' => "The binary value above is a tiny arrow encoded as a gif image.\n" }, < /George McFly/i }, < 2, :UseVersion => 0 ) y.add( { 'hi' => 'hello', 'map' => { 'good' => 'two' }, 'time' => Time.now, 'try' => /^po(.*)$/, 'bye' => 'goodbye' } ) y.add( { 'po' => 'nil', 'oper' => 90 } ) y.add( { 'hi' => 'wow!', 'bye' => 'wow!' } ) y.add( { [ 'Red Socks', 'Boston' ] => [ 'One', 'Two', 'Three' ] } ) y.add( [ true, false, false ] ) end # # Test YPath choices parsing # def test_ypath_parsing assert_path_segments( "/*/((one|three)/name|place)|//place", [ ["*", "one", "name"], ["*", "three", "name"], ["*", "place"], ["/", "place"] ] ) end # # Tests from Tanaka Akira on [ruby-core] # def test_akira # Commas in plain scalars [ruby-core:1066] assert_to_yaml( {"A"=>"A,","B"=>"B"}, <2, "2"=>3}, <"b"}] * 2, <"b", "c"=>"d"} } # YAML::load( a.to_yaml ) end # # Test Time.now cycle # def test_time_now_cycle # # From Minero Aoki [ruby-core:2305] # require 'yaml' t = Time.now 5.times do assert_cycle(t) end end # # Test Range cycle # def test_range_cycle # # From Minero Aoki [ruby-core:02306] # assert_cycle("a".."z") # # From Nobu Nakada [ruby-core:02311] # assert_cycle(0..1) assert_cycle(1.0e20 .. 2.0e20) assert_cycle("0".."1") assert_cycle(".."..."...") assert_cycle(".rb"..".pl") assert_cycle(".rb"...".pl") assert_cycle('"'...".") assert_cycle("'"...".") end # # Circular references # def test_circular_references a = []; a[0] = a; a[1] = a inspect_str = "[[...], [...]]" assert_equal( inspect_str, YAML::load( a.to_yaml ).inspect ) end # # Test Symbol cycle # def test_symbol_cycle # # From Aaron Schrab [ruby-Bugs:2535] # assert_cycle(:"^foo") end # # Test Numeric cycle # class NumericTest < Numeric def initialize(value) @value = value end def ==(other) @value == other.instance_eval{ @value } end end def test_numeric_cycle assert_cycle(1) # Fixnum assert_cycle(111111111111111111111111111111111) # Bignum assert_cycle(NumericTest.new(3)) # Subclass of Numeric end # # Test empty map/seq in map cycle # def test_empty_map_key # # empty seq as key # o = YAML.load({[]=>""}.to_yaml) assert_equal(Hash, o.class) assert_equal([[]], o.keys) # # empty map as key # o = YAML.load({{}=>""}.to_yaml) assert_equal(Hash, o.class) assert_equal([{}], o.keys) end # # contributed by riley lynch [ruby-Bugs-8548] # def test_object_id_collision omap = YAML::Omap.new 1000.times { |i| omap["key_#{i}"] = { "value" => i } } raise "id collision in ordered map" if omap.to_yaml =~ /id\d+/ end end if $0 == __FILE__ suite = Test::Unit::TestSuite.new('YAML') ObjectSpace.each_object(Class) do |klass| suite << klass.suite if (Test::Unit::TestCase > klass) end require 'test/unit/ui/console/testrunner' Test::Unit::UI::Console::TestRunner.run(suite).passed? end ================================================ FILE: test/yaml/test_yamlstore.rb ================================================ require 'test/unit' require 'yaml/store' class YAMLStoreTest < Test::Unit::TestCase def setup @yamlstore_file = "yamlstore.tmp.#{Process.pid}" @yamlstore = YAML::Store.new(@yamlstore_file) end def teardown File.unlink(@yamlstore_file) rescue nil end def test_opening_new_file_in_readonly_mode_should_result_in_empty_values @yamlstore.transaction(true) do assert_nil @yamlstore[:foo] assert_nil @yamlstore[:bar] end end def test_opening_new_file_in_readwrite_mode_should_result_in_empty_values @yamlstore.transaction do assert_nil @yamlstore[:foo] assert_nil @yamlstore[:bar] end end def test_data_should_be_loaded_correctly_when_in_readonly_mode @yamlstore.transaction do @yamlstore[:foo] = "bar" end @yamlstore.transaction(true) do assert_equal "bar", @yamlstore[:foo] end end def test_data_should_be_loaded_correctly_when_in_readwrite_mode @yamlstore.transaction do @yamlstore[:foo] = "bar" end @yamlstore.transaction do assert_equal "bar", @yamlstore[:foo] end end def test_changes_after_commit_are_discarded @yamlstore.transaction do @yamlstore[:foo] = "bar" @yamlstore.commit @yamlstore[:foo] = "baz" end @yamlstore.transaction(true) do assert_equal "bar", @yamlstore[:foo] end end def test_changes_are_not_written_on_abort @yamlstore.transaction do @yamlstore[:foo] = "bar" @yamlstore.abort end @yamlstore.transaction(true) do assert_nil @yamlstore[:foo] end end def test_writing_inside_readonly_transaction_raises_error assert_raise(PStore::Error) do @yamlstore.transaction(true) do @yamlstore[:foo] = "bar" end end end end ================================================ FILE: test/zlib/test_zlib.rb ================================================ require 'test/unit/testsuite' require 'test/unit/testcase' require 'stringio' begin require 'zlib' rescue LoadError end if defined? Zlib class TestZlibGzipReader < Test::Unit::TestCase D0 = "\037\213\010\000S`\017A\000\003\003\000\000\000\000\000\000\000\000\000" def test_read0 assert_equal("", Zlib::GzipReader.new(StringIO.new(D0)).read(0)) end def test_ungetc # [ruby-dev:24060] s = "" w = Zlib::GzipWriter.new(StringIO.new(s)) w << (1...1000).to_a.inspect w.close r = Zlib::GzipReader.new(StringIO.new(s)) r.read(100) r.ungetc ?a assert_nothing_raised { r.read(100) r.read r.close } end def test_ungetc_paragraph # [ruby-dev:24065] s = "" w = Zlib::GzipWriter.new(StringIO.new(s)) w << "abc" w.close r = Zlib::GzipReader.new(StringIO.new(s)) r.ungetc ?\n assert_equal("abc", r.gets("")) assert_nothing_raised { r.read r.close } end end class TestZlibGzipWriter < Test::Unit::TestCase def test_invalid_new # [ruby-dev:23228] assert_raise(NoMethodError) { Zlib::GzipWriter.new(nil).close } # [ruby-dev:23344] assert_raise(NoMethodError) { Zlib::GzipWriter.new(true).close } assert_raise(NoMethodError) { Zlib::GzipWriter.new(0).close } assert_raise(NoMethodError) { Zlib::GzipWriter.new(:hoge).close } end end end ================================================ FILE: time.c ================================================ /********************************************************************** time.c - $Author$ $Date$ created at: Tue Dec 28 14:31:59 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #include "ruby.h" #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include VALUE rb_cTime; struct time_object { struct timeval tv; struct tm tm; int gmt; int tm_got; }; #define GetTimeval(obj, tobj) \ Data_Get_Struct(obj, struct time_object, tobj) static void time_free _((void *)); static VALUE time_utc_offset _((VALUE)); static void time_free(tobj) void *tobj; { if (tobj) free(tobj); } static VALUE time_s_alloc _((VALUE)); static VALUE time_s_alloc(klass) VALUE klass; { VALUE obj; struct time_object *tobj; obj = Data_Make_Struct(klass, struct time_object, 0, time_free, tobj); tobj->tm_got=0; tobj->tv.tv_sec = 0; tobj->tv.tv_usec = 0; return obj; } static void time_modify(time) VALUE time; { rb_check_frozen(time); if (!OBJ_TAINTED(time) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify Time"); } /* * Document-method: now * * Synonym for Time.new. Returns a +Time+ object * initialized tot he current system time. * * call-seq: * Time.new -> time * * Returns a Time object initialized to the current system * time. Note: The object created will be created using the * resolution available on your system clock, and so may include * fractional seconds. * * a = Time.new #=> Wed Apr 09 08:56:03 CDT 2003 * b = Time.new #=> Wed Apr 09 08:56:03 CDT 2003 * a == b #=> false * "%.6f" % a.to_f #=> "1049896563.230740" * "%.6f" % b.to_f #=> "1049896563.231466" * */ static VALUE time_init(time) VALUE time; { struct time_object *tobj; time_modify(time); GetTimeval(time, tobj); tobj->tm_got=0; tobj->tv.tv_sec = 0; tobj->tv.tv_usec = 0; if (gettimeofday(&tobj->tv, 0) < 0) { rb_sys_fail("gettimeofday"); } return time; } #define NDIV(x,y) (-(-((x)+1)/(y))-1) #define NMOD(x,y) ((y)-(-((x)+1)%(y))-1) static void time_overflow_p(secp, usecp) time_t *secp, *usecp; { time_t tmp, sec = *secp, usec = *usecp; if (usec >= 1000000) { /* usec positive overflow */ tmp = sec + usec / 1000000; usec %= 1000000; if (sec > 0 && tmp < 0) { rb_raise(rb_eRangeError, "out of Time range"); } sec = tmp; } if (usec < 0) { /* usec negative overflow */ tmp = sec + NDIV(usec,1000000); /* negative div */ usec = NMOD(usec,1000000); /* negative mod */ if (sec < 0 && tmp > 0) { rb_raise(rb_eRangeError, "out of Time range"); } sec = tmp; } #ifndef NEGATIVE_TIME_T if (sec < 0 || (sec == 0 && usec < 0)) rb_raise(rb_eArgError, "time must be positive"); #endif *secp = sec; *usecp = usec; } static VALUE time_new_internal _((VALUE, time_t, time_t)); static VALUE time_new_internal(klass, sec, usec) VALUE klass; time_t sec, usec; { VALUE time = time_s_alloc(klass); struct time_object *tobj; GetTimeval(time, tobj); time_overflow_p(&sec, &usec); tobj->tv.tv_sec = sec; tobj->tv.tv_usec = usec; return time; } VALUE rb_time_new(sec, usec) time_t sec, usec; { return time_new_internal(rb_cTime, sec, usec); } static struct timeval time_timeval(time, interval) VALUE time; int interval; { struct timeval t; const char *tstr = interval ? "time interval" : "time"; #ifndef NEGATIVE_TIME_T interval = 1; #endif switch (TYPE(time)) { case T_FIXNUM: t.tv_sec = FIX2LONG(time); if (interval && t.tv_sec < 0) rb_raise(rb_eArgError, "%s must be positive", tstr); t.tv_usec = 0; break; case T_FLOAT: if (interval && RFLOAT(time)->value < 0.0) rb_raise(rb_eArgError, "%s must be positive", tstr); else { double f, d; d = modf(RFLOAT(time)->value, &f); if (d >= 0) { t.tv_usec = (int)(d*1e6+0.5); } else if ((t.tv_usec = (int)(-d*1e6+0.5)) > 0) { t.tv_usec = 1000000 - t.tv_usec; f -= 1; } t.tv_sec = (time_t)f; if (f != t.tv_sec) { rb_raise(rb_eRangeError, "%f out of Time range", RFLOAT(time)->value); } } break; case T_BIGNUM: t.tv_sec = NUM2LONG(time); if (interval && t.tv_sec < 0) rb_raise(rb_eArgError, "%s must be positive", tstr); t.tv_usec = 0; break; default: rb_raise(rb_eTypeError, "can't convert %s into %s", rb_obj_classname(time), tstr); break; } return t; } struct timeval rb_time_interval(time) VALUE time; { return time_timeval(time, Qtrue); } struct timeval rb_time_timeval(time) VALUE time; { struct time_object *tobj; struct timeval t; if (TYPE(time) == T_DATA && RDATA(time)->dfree == time_free) { GetTimeval(time, tobj); t = tobj->tv; return t; } return time_timeval(time, Qfalse); } /* * call-seq: * Time.at( aTime ) => time * Time.at( seconds [, microseconds] ) => time * * Creates a new time object with the value given by aTime, or * the given number of seconds (and optional * microseconds) from epoch. A non-portable feature allows the * offset to be negative on some systems. * * Time.at(0) #=> Wed Dec 31 18:00:00 CST 1969 * Time.at(946702800) #=> Fri Dec 31 23:00:00 CST 1999 * Time.at(-284061600) #=> Sat Dec 31 00:00:00 CST 1960 */ static VALUE time_s_at(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { struct timeval tv; VALUE time, t; if (rb_scan_args(argc, argv, "11", &time, &t) == 2) { tv.tv_sec = NUM2LONG(time); tv.tv_usec = NUM2LONG(t); } else { tv = rb_time_timeval(time); } t = time_new_internal(klass, tv.tv_sec, tv.tv_usec); if (TYPE(time) == T_DATA && RDATA(time)->dfree == time_free) { struct time_object *tobj, *tobj2; GetTimeval(time, tobj); GetTimeval(t, tobj2); tobj2->gmt = tobj->gmt; } return t; } static const char months[][4] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec", }; static long obj2long(obj) VALUE obj; { if (TYPE(obj) == T_STRING) { obj = rb_str_to_inum(obj, 10, Qfalse); } return NUM2LONG(obj); } static void time_arg(argc, argv, tm, usec) int argc; VALUE *argv; struct tm *tm; time_t *usec; { VALUE v[8]; int i; long year; MEMZERO(tm, struct tm, 1); *usec = 0; if (argc == 10) { v[0] = argv[5]; v[1] = argv[4]; v[2] = argv[3]; v[3] = argv[2]; v[4] = argv[1]; v[5] = argv[0]; v[6] = Qnil; tm->tm_isdst = RTEST(argv[8]) ? 1 : 0; } else { rb_scan_args(argc, argv, "17", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6],&v[7]); /* v[6] may be usec or zone (parsedate) */ /* v[7] is wday (parsedate; ignored) */ tm->tm_wday = -1; tm->tm_isdst = -1; } year = obj2long(v[0]); if (0 <= year && year < 39) { year += 100; rb_warning("2 digits year is used"); } else if (69 <= year && year < 139) { rb_warning("2 or 3 digits year is used"); } else { year -= 1900; } tm->tm_year = year; if (NIL_P(v[1])) { tm->tm_mon = 0; } else { VALUE s = rb_check_string_type(v[1]); if (!NIL_P(s)) { tm->tm_mon = -1; for (i=0; i<12; i++) { if (RSTRING(s)->len == 3 && strcasecmp(months[i], RSTRING(s)->ptr) == 0) { tm->tm_mon = i; break; } } if (tm->tm_mon == -1) { char c = RSTRING(s)->ptr[0]; if ('0' <= c && c <= '9') { tm->tm_mon = obj2long(s)-1; } } } else { tm->tm_mon = obj2long(v[1])-1; } } if (NIL_P(v[2])) { tm->tm_mday = 1; } else { tm->tm_mday = obj2long(v[2]); } tm->tm_hour = NIL_P(v[3])?0:obj2long(v[3]); tm->tm_min = NIL_P(v[4])?0:obj2long(v[4]); tm->tm_sec = NIL_P(v[5])?0:obj2long(v[5]); if (!NIL_P(v[6])) { if (argc == 8) { /* v[6] is timezone, but ignored */ } else if (argc == 7) { *usec = obj2long(v[6]); } } /* value validation */ if ( tm->tm_year != year || #ifndef NEGATIVE_TIME_T tm->tm_year < 69 || #endif tm->tm_mon < 0 || tm->tm_mon > 11 || tm->tm_mday < 1 || tm->tm_mday > 31 || tm->tm_hour < 0 || tm->tm_hour > 23 || tm->tm_min < 0 || tm->tm_min > 59 || tm->tm_sec < 0 || tm->tm_sec > 60) rb_raise(rb_eArgError, "argument out of range"); } static VALUE time_gmtime _((VALUE)); static VALUE time_localtime _((VALUE)); static VALUE time_get_tm _((VALUE, int)); static int leap_year_p(y) long y; { return ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0); } #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d)) static time_t timegm_noleapsecond(tm) struct tm *tm; { static int common_year_yday_offset[] = { -1, -1 + 31, -1 + 31 + 28, -1 + 31 + 28 + 31, -1 + 31 + 28 + 31 + 30, -1 + 31 + 28 + 31 + 30 + 31, -1 + 31 + 28 + 31 + 30 + 31 + 30, -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31, -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 /* 1 2 3 4 5 6 7 8 9 10 11 */ }; static int leap_year_yday_offset[] = { -1, -1 + 31, -1 + 31 + 29, -1 + 31 + 29 + 31, -1 + 31 + 29 + 31 + 30, -1 + 31 + 29 + 31 + 30 + 31, -1 + 31 + 29 + 31 + 30 + 31 + 30, -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31, -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31, -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30, -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 /* 1 2 3 4 5 6 7 8 9 10 11 */ }; long tm_year = tm->tm_year; int tm_yday = tm->tm_mday; if (leap_year_p(tm_year + 1900)) tm_yday += leap_year_yday_offset[tm->tm_mon]; else tm_yday += common_year_yday_offset[tm->tm_mon]; /* * `Seconds Since the Epoch' in SUSv3: * tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 + * (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 - * ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400 */ return tm->tm_sec + tm->tm_min*60 + tm->tm_hour*3600 + (time_t)(tm_yday + (tm_year-70)*365 + DIV(tm_year-69,4) - DIV(tm_year-1,100) + DIV(tm_year+299,400))*86400; } static int tmcmp(a, b) struct tm *a; struct tm *b; { if (a->tm_year != b->tm_year) return a->tm_year < b->tm_year ? -1 : 1; else if (a->tm_mon != b->tm_mon) return a->tm_mon < b->tm_mon ? -1 : 1; else if (a->tm_mday != b->tm_mday) return a->tm_mday < b->tm_mday ? -1 : 1; else if (a->tm_hour != b->tm_hour) return a->tm_hour < b->tm_hour ? -1 : 1; else if (a->tm_min != b->tm_min) return a->tm_min < b->tm_min ? -1 : 1; else if (a->tm_sec != b->tm_sec) return a->tm_sec < b->tm_sec ? -1 : 1; else return 0; } #if SIZEOF_TIME_T == SIZEOF_LONG typedef unsigned long unsigned_time_t; #elif SIZEOF_TIME_T == SIZEOF_INT typedef unsigned int unsigned_time_t; #elif SIZEOF_TIME_T == SIZEOF_LONG_LONG typedef unsigned LONG_LONG unsigned_time_t; #else # error cannot find integer type which size is same as time_t. #endif static time_t search_time_t(tptr, utc_p) struct tm *tptr; int utc_p; { time_t guess, guess_lo, guess_hi; struct tm *tm, tm_lo, tm_hi; int d, have_guess; int find_dst; find_dst = 0 < tptr->tm_isdst; #ifdef NEGATIVE_TIME_T guess_lo = (time_t)~((unsigned_time_t)~(time_t)0 >> 1); #else guess_lo = 0; #endif guess_hi = ((time_t)-1) < ((time_t)0) ? (time_t)((unsigned_time_t)~(time_t)0 >> 1) : ~(time_t)0; guess = timegm_noleapsecond(tptr); tm = (utc_p ? gmtime : localtime)(&guess); if (tm) { d = tmcmp(tptr, tm); if (d == 0) return guess; if (d < 0) { guess_hi = guess; guess -= 24 * 60 * 60; } else { guess_lo = guess; guess += 24 * 60 * 60; } if (guess_lo < guess && guess < guess_hi && (tm = (utc_p ? gmtime : localtime)(&guess)) != NULL) { d = tmcmp(tptr, tm); if (d == 0) return guess; if (d < 0) guess_hi = guess; else guess_lo = guess; } } tm = (utc_p ? gmtime : localtime)(&guess_lo); if (!tm) goto error; d = tmcmp(tptr, tm); if (d < 0) goto out_of_range; if (d == 0) return guess_lo; tm_lo = *tm; tm = (utc_p ? gmtime : localtime)(&guess_hi); if (!tm) goto error; d = tmcmp(tptr, tm); if (d > 0) goto out_of_range; if (d == 0) return guess_hi; tm_hi = *tm; have_guess = 0; while (guess_lo + 1 < guess_hi) { /* there is a gap between guess_lo and guess_hi. */ unsigned long range = 0; if (!have_guess) { int a, b; /* Try precious guess by a linear interpolation at first. `a' and `b' is a coefficient of guess_lo and guess_hi as: guess = (guess_lo * a + guess_hi * b) / (a + b) However this causes overflow in most cases, following assignment is used instead: guess = guess_lo / d * a + (guess_lo % d) * a / d + guess_hi / d * b + (guess_hi % d) * b / d where d = a + b To avoid overflow in this assignment, `d' is restricted to less than sqrt(2**31). By this restriction and other reasons, the guess is not accurate and some error is expected. `range' approximates the maximum error. When these parameters are not suitable, i.e. guess is not within guess_lo and guess_hi, simple guess by binary search is used. */ range = 366 * 24 * 60 * 60; a = (tm_hi.tm_year - tptr->tm_year); b = (tptr->tm_year - tm_lo.tm_year); /* 46000 is selected as `some big number less than sqrt(2**31)'. */ if (a + b <= 46000 / 12) { range = 31 * 24 * 60 * 60; a *= 12; b *= 12; a += tm_hi.tm_mon - tptr->tm_mon; b += tptr->tm_mon - tm_lo.tm_mon; if (a + b <= 46000 / 31) { range = 24 * 60 * 60; a *= 31; b *= 31; a += tm_hi.tm_mday - tptr->tm_mday; b += tptr->tm_mday - tm_lo.tm_mday; if (a + b <= 46000 / 24) { range = 60 * 60; a *= 24; b *= 24; a += tm_hi.tm_hour - tptr->tm_hour; b += tptr->tm_hour - tm_lo.tm_hour; if (a + b <= 46000 / 60) { range = 60; a *= 60; b *= 60; a += tm_hi.tm_min - tptr->tm_min; b += tptr->tm_min - tm_lo.tm_min; if (a + b <= 46000 / 60) { range = 1; a *= 60; b *= 60; a += tm_hi.tm_sec - tptr->tm_sec; b += tptr->tm_sec - tm_lo.tm_sec; } } } } } if (a <= 0) a = 1; if (b <= 0) b = 1; d = a + b; /* Although `/' and `%' may produce unexpected result with negative argument, it doesn't cause serious problem because there is a fail safe. */ guess = guess_lo / d * a + (guess_lo % d) * a / d + guess_hi / d * b + (guess_hi % d) * b / d; have_guess = 1; } if (guess <= guess_lo || guess_hi <= guess) { /* Precious guess is invalid. try binary search. */ guess = guess_lo / 2 + guess_hi / 2; if (guess <= guess_lo) guess = guess_lo + 1; else if (guess >= guess_hi) guess = guess_hi - 1; range = 0; } tm = (utc_p ? gmtime : localtime)(&guess); if (!tm) goto error; have_guess = 0; d = tmcmp(tptr, tm); if (d < 0) { guess_hi = guess; tm_hi = *tm; if (range) { guess = guess - range; range = 0; if (guess_lo < guess && guess < guess_hi) have_guess = 1; } } else if (d > 0) { guess_lo = guess; tm_lo = *tm; if (range) { guess = guess + range; range = 0; if (guess_lo < guess && guess < guess_hi) have_guess = 1; } } else { if (!utc_p) { /* If localtime is nonmonotonic, another result may exist. */ time_t guess2; if (find_dst) { guess2 = guess - 2 * 60 * 60; tm = localtime(&guess2); if (tm) { if (tptr->tm_hour != (tm->tm_hour + 2) % 24 || tptr->tm_min != tm->tm_min || tptr->tm_sec != tm->tm_sec) { guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 + (tm->tm_min - tptr->tm_min) * 60 + (tm->tm_sec - tptr->tm_sec); if (tptr->tm_mday != tm->tm_mday) guess2 += 24 * 60 * 60; if (guess != guess2) { tm = localtime(&guess2); if (tmcmp(tptr, tm) == 0) { if (guess < guess2) return guess; else return guess2; } } } } } else { guess2 = guess + 2 * 60 * 60; tm = localtime(&guess2); if (tm) { if ((tptr->tm_hour + 2) % 24 != tm->tm_hour || tptr->tm_min != tm->tm_min || tptr->tm_sec != tm->tm_sec) { guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 + (tm->tm_min - tptr->tm_min) * 60 + (tm->tm_sec - tptr->tm_sec); if (tptr->tm_mday != tm->tm_mday) guess2 -= 24 * 60 * 60; if (guess != guess2) { tm = localtime(&guess2); if (tmcmp(tptr, tm) == 0) { if (guess < guess2) return guess2; else return guess; } } } } } } return guess; } } /* Given argument has no corresponding time_t. Let's outerpolation. */ if (tm_lo.tm_year == tptr->tm_year && tm_lo.tm_mon == tptr->tm_mon) { return guess_lo + (tptr->tm_mday - tm_lo.tm_mday) * 24 * 60 * 60 + (tptr->tm_hour - tm_lo.tm_hour) * 60 * 60 + (tptr->tm_min - tm_lo.tm_min) * 60 + (tptr->tm_sec - tm_lo.tm_sec); } else if (tm_hi.tm_year == tptr->tm_year && tm_hi.tm_mon == tptr->tm_mon) { return guess_hi + (tptr->tm_mday - tm_hi.tm_mday) * 24 * 60 * 60 + (tptr->tm_hour - tm_hi.tm_hour) * 60 * 60 + (tptr->tm_min - tm_hi.tm_min) * 60 + (tptr->tm_sec - tm_hi.tm_sec); } out_of_range: rb_raise(rb_eArgError, "time out of range"); error: rb_raise(rb_eArgError, "gmtime/localtime error"); return 0; /* not reached */ } static time_t make_time_t(tptr, utc_p) struct tm *tptr; int utc_p; { time_t t; #ifdef NEGATIVE_TIME_T struct tm *tmp; #endif struct tm buf; buf = *tptr; if (utc_p) { #if defined(HAVE_TIMEGM) if ((t = timegm(&buf)) != -1) return t; #ifdef NEGATIVE_TIME_T if ((tmp = gmtime(&t)) && tptr->tm_year == tmp->tm_year && tptr->tm_mon == tmp->tm_mon && tptr->tm_mday == tmp->tm_mday && tptr->tm_hour == tmp->tm_hour && tptr->tm_min == tmp->tm_min && tptr->tm_sec == tmp->tm_sec) return t; #endif #endif return search_time_t(&buf, utc_p); } else { #if defined(HAVE_MKTIME) if ((t = mktime(&buf)) != -1) return t; #ifdef NEGATIVE_TIME_T if ((tmp = localtime(&t)) && tptr->tm_year == tmp->tm_year && tptr->tm_mon == tmp->tm_mon && tptr->tm_mday == tmp->tm_mday && tptr->tm_hour == tmp->tm_hour && tptr->tm_min == tmp->tm_min && tptr->tm_sec == tmp->tm_sec) return t; #endif #endif return search_time_t(&buf, utc_p); } } static VALUE time_utc_or_local(argc, argv, utc_p, klass) int argc; VALUE *argv; int utc_p; VALUE klass; { struct tm tm; VALUE time; time_t usec; time_arg(argc, argv, &tm, &usec); time = time_new_internal(klass, make_time_t(&tm, utc_p), usec); if (utc_p) return time_gmtime(time); return time_localtime(time); } /* * call-seq: * Time.utc( year [, month, day, hour, min, sec, usec] ) => time * Time.utc( sec, min, hour, day, month, year, wday, yday, isdst, tz * ) => time * Time.gm( year [, month, day, hour, min, sec, usec] ) => time * Time.gm( sec, min, hour, day, month, year, wday, yday, isdst, tz * ) => time * * Creates a time based on given values, interpreted as UTC (GMT). The * year must be specified. Other values default to the minimum value * for that field (and may be nil or omitted). Months may * be specified by numbers from 1 to 12, or by the three-letter English * month names. Hours are specified on a 24-hour clock (0..23). Raises * an ArgumentError if any values are out of range. Will * also accept ten arguments in the order output by * Time#to_a. * * Time.utc(2000,"jan",1,20,15,1) #=> Sat Jan 01 20:15:01 UTC 2000 * Time.gm(2000,"jan",1,20,15,1) #=> Sat Jan 01 20:15:01 UTC 2000 */ static VALUE time_s_mkutc(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { return time_utc_or_local(argc, argv, Qtrue, klass); } /* * call-seq: * Time.local( year [, month, day, hour, min, sec, usec] ) => time * Time.local( sec, min, hour, day, month, year, wday, yday, isdst, * tz ) => time * Time.mktime( year, month, day, hour, min, sec, usec ) => time * * Same as Time::gm, but interprets the values in the * local time zone. * * Time.local(2000,"jan",1,20,15,1) #=> Sat Jan 01 20:15:01 CST 2000 */ static VALUE time_s_mktime(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { return time_utc_or_local(argc, argv, Qfalse, klass); } /* * call-seq: * time.to_i => int * time.tv_sec => int * * Returns the value of time as an integer number of seconds * since epoch. * * t = Time.now * "%10.5f" % t.to_f #=> "1049896564.17839" * t.to_i #=> 1049896564 */ static VALUE time_to_i(time) VALUE time; { struct time_object *tobj; GetTimeval(time, tobj); return LONG2NUM(tobj->tv.tv_sec); } /* * call-seq: * time.to_f => float * * Returns the value of time as a floating point number of * seconds since epoch. * * t = Time.now * "%10.5f" % t.to_f #=> "1049896564.13654" * t.to_i #=> 1049896564 */ static VALUE time_to_f(time) VALUE time; { struct time_object *tobj; GetTimeval(time, tobj); return rb_float_new((double)tobj->tv.tv_sec+(double)tobj->tv.tv_usec/1e6); } /* * call-seq: * time.usec => int * time.tv_usec => int * * Returns just the number of microseconds for time. * * t = Time.now #=> Wed Apr 09 08:56:04 CDT 2003 * "%10.6f" % t.to_f #=> "1049896564.259970" * t.usec #=> 259970 */ static VALUE time_usec(time) VALUE time; { struct time_object *tobj; GetTimeval(time, tobj); return LONG2NUM(tobj->tv.tv_usec); } /* * call-seq: * time <=> other_time => -1, 0, +1 * time <=> numeric => -1, 0, +1 * * Comparison---Compares time with other_time or with * numeric, which is the number of seconds (possibly * fractional) since epoch. * * t = Time.now #=> Wed Apr 09 08:56:03 CDT 2003 * t2 = t + 2592000 #=> Fri May 09 08:56:03 CDT 2003 * t <=> t2 #=> -1 * t2 <=> t #=> 1 * t <=> t #=> 0 */ static VALUE time_cmp(time1, time2) VALUE time1, time2; { struct time_object *tobj1, *tobj2; GetTimeval(time1, tobj1); if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) { GetTimeval(time2, tobj2); if (tobj1->tv.tv_sec == tobj2->tv.tv_sec) { if (tobj1->tv.tv_usec == tobj2->tv.tv_usec) return INT2FIX(0); if (tobj1->tv.tv_usec > tobj2->tv.tv_usec) return INT2FIX(1); return INT2FIX(-1); } if (tobj1->tv.tv_sec > tobj2->tv.tv_sec) return INT2FIX(1); return INT2FIX(-1); } return Qnil; } /* * call-seq: * time.eql?(other_time) * * Return true if time and other_time are * both Time objects with the same seconds and fractional * seconds. */ static VALUE time_eql(time1, time2) VALUE time1, time2; { struct time_object *tobj1, *tobj2; GetTimeval(time1, tobj1); if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) { GetTimeval(time2, tobj2); if (tobj1->tv.tv_sec == tobj2->tv.tv_sec) { if (tobj1->tv.tv_usec == tobj2->tv.tv_usec) return Qtrue; } } return Qfalse; } /* * call-seq: * time.utc? => true or false * time.gmt? => true or false * * Returns true if time represents a time in UTC * (GMT). * * t = Time.now #=> Wed Apr 09 08:56:04 CDT 2003 * t.utc? #=> false * t = Time.gm(2000,"jan",1,20,15,1) #=> Sat Jan 01 20:15:01 UTC 2000 * t.utc? #=> true * * t = Time.now #=> Wed Apr 09 08:56:03 CDT 2003 * t.gmt? #=> false * t = Time.gm(2000,1,1,20,15,1) #=> Sat Jan 01 20:15:01 UTC 2000 * t.gmt? #=> true */ static VALUE time_utc_p(time) VALUE time; { struct time_object *tobj; GetTimeval(time, tobj); if (tobj->gmt) return Qtrue; return Qfalse; } /* * call-seq: * time.hash => fixnum * * Return a hash code for this time object. */ static VALUE time_hash(time) VALUE time; { struct time_object *tobj; long hash; GetTimeval(time, tobj); hash = tobj->tv.tv_sec ^ tobj->tv.tv_usec; return LONG2FIX(hash); } /* :nodoc: */ static VALUE time_init_copy(copy, time) VALUE copy, time; { struct time_object *tobj, *tcopy; if (copy == time) return copy; time_modify(copy); if (TYPE(time) != T_DATA || RDATA(time)->dfree != time_free) { rb_raise(rb_eTypeError, "wrong argument type"); } GetTimeval(time, tobj); GetTimeval(copy, tcopy); MEMCPY(tcopy, tobj, struct time_object, 1); return copy; } static VALUE time_dup(time) VALUE time; { VALUE dup = time_s_alloc(CLASS_OF(time)); time_init_copy(dup, time); return dup; } /* * call-seq: * time.localtime => time * * Converts time to local time (using the local time zone in * effect for this process) modifying the receiver. * * t = Time.gm(2000, "jan", 1, 20, 15, 1) * t.gmt? #=> true * t.localtime #=> Sat Jan 01 14:15:01 CST 2000 * t.gmt? #=> false */ static VALUE time_localtime(time) VALUE time; { struct time_object *tobj; struct tm *tm_tmp; time_t t; GetTimeval(time, tobj); if (!tobj->gmt) { if (tobj->tm_got) return time; } else { time_modify(time); } t = tobj->tv.tv_sec; tm_tmp = localtime(&t); if (!tm_tmp) rb_raise(rb_eArgError, "localtime error"); tobj->tm = *tm_tmp; tobj->tm_got = 1; tobj->gmt = 0; return time; } /* * call-seq: * time.gmtime => time * time.utc => time * * Converts time to UTC (GMT), modifying the receiver. * * t = Time.now #=> Wed Apr 09 08:56:03 CDT 2003 * t.gmt? #=> false * t.gmtime #=> Wed Apr 09 13:56:03 UTC 2003 * t.gmt? #=> true * * t = Time.now #=> Wed Apr 09 08:56:04 CDT 2003 * t.utc? #=> false * t.utc #=> Wed Apr 09 13:56:04 UTC 2003 * t.utc? #=> true */ static VALUE time_gmtime(time) VALUE time; { struct time_object *tobj; struct tm *tm_tmp; time_t t; GetTimeval(time, tobj); if (tobj->gmt) { if (tobj->tm_got) return time; } else { time_modify(time); } t = tobj->tv.tv_sec; tm_tmp = gmtime(&t); if (!tm_tmp) rb_raise(rb_eArgError, "gmtime error"); tobj->tm = *tm_tmp; tobj->tm_got = 1; tobj->gmt = 1; return time; } /* * call-seq: * time.getlocal => new_time * * Returns a new new_time object representing time in * local time (using the local time zone in effect for this process). * * t = Time.gm(2000,1,1,20,15,1) #=> Sat Jan 01 20:15:01 UTC 2000 * t.gmt? #=> true * l = t.getlocal #=> Sat Jan 01 14:15:01 CST 2000 * l.gmt? #=> false * t == l #=> true */ static VALUE time_getlocaltime(time) VALUE time; { return time_localtime(time_dup(time)); } /* * call-seq: * time.getgm => new_time * time.getutc => new_time * * Returns a new new_time object representing time in * UTC. * * t = Time.local(2000,1,1,20,15,1) #=> Sat Jan 01 20:15:01 CST 2000 * t.gmt? #=> false * y = t.getgm #=> Sun Jan 02 02:15:01 UTC 2000 * y.gmt? #=> true * t == y #=> true */ static VALUE time_getgmtime(time) VALUE time; { return time_gmtime(time_dup(time)); } static VALUE time_get_tm(time, gmt) VALUE time; int gmt; { if (gmt) return time_gmtime(time); return time_localtime(time); } /* * call-seq: * time.asctime => string * time.ctime => string * * Returns a canonical string representation of time. * * Time.now.asctime #=> "Wed Apr 9 08:56:03 2003" */ static VALUE time_asctime(time) VALUE time; { struct time_object *tobj; char *s; GetTimeval(time, tobj); if (tobj->tm_got == 0) { time_get_tm(time, tobj->gmt); } s = asctime(&tobj->tm); if (s[24] == '\n') s[24] = '\0'; return rb_str_new2(s); } /* * call-seq: * time.inspect => string * time.to_s => string * * Returns a string representing time. Equivalent to calling * Time#strftime with a format string of ``%a * %b %d %H:%M:%S * %Z %Y''. * * Time.now.to_s #=> "Wed Apr 09 08:56:04 CDT 2003" */ static VALUE time_to_s(time) VALUE time; { struct time_object *tobj; char buf[128]; int len; GetTimeval(time, tobj); if (tobj->tm_got == 0) { time_get_tm(time, tobj->gmt); } if (tobj->gmt == 1) { len = strftime(buf, 128, "%a %b %d %H:%M:%S UTC %Y", &tobj->tm); } else { time_t off; char buf2[32]; char sign = '+'; #if defined(HAVE_STRUCT_TM_TM_GMTOFF) off = tobj->tm.tm_gmtoff; #else VALUE tmp = time_utc_offset(time); off = NUM2INT(tmp); #endif if (off < 0) { sign = '-'; off = -off; } sprintf(buf2, "%%a %%b %%d %%H:%%M:%%S %c%02d%02d %%Y", sign, (int)(off/3600), (int)(off%3600/60)); len = strftime(buf, 128, buf2, &tobj->tm); } return rb_str_new(buf, len); } static VALUE time_add(tobj, offset, sign) struct time_object *tobj; VALUE offset; int sign; { double v = NUM2DBL(offset); double f, d; unsigned_time_t sec_off; time_t usec_off, sec, usec; VALUE result; if (v < 0) { v = -v; sign = -sign; } d = modf(v, &f); sec_off = (unsigned_time_t)f; if (f != (double)sec_off) rb_raise(rb_eRangeError, "time %s %f out of Time range", sign < 0 ? "-" : "+", v); usec_off = (time_t)(d*1e6+0.5); if (sign < 0) { sec = tobj->tv.tv_sec - sec_off; usec = tobj->tv.tv_usec - usec_off; if (sec > tobj->tv.tv_sec) rb_raise(rb_eRangeError, "time - %f out of Time range", v); } else { sec = tobj->tv.tv_sec + sec_off; usec = tobj->tv.tv_usec + usec_off; if (sec < tobj->tv.tv_sec) rb_raise(rb_eRangeError, "time + %f out of Time range", v); } result = rb_time_new(sec, usec); if (tobj->gmt) { GetTimeval(result, tobj); tobj->gmt = 1; } return result; } /* * call-seq: * time + numeric => time * * Addition---Adds some number of seconds (possibly fractional) to * time and returns that value as a new time. * * t = Time.now #=> Wed Apr 09 08:56:03 CDT 2003 * t + (60 * 60 * 24) #=> Thu Apr 10 08:56:03 CDT 2003 */ static VALUE time_plus(time1, time2) VALUE time1, time2; { struct time_object *tobj; GetTimeval(time1, tobj); if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) { rb_raise(rb_eTypeError, "time + time?"); } return time_add(tobj, time2, 1); } /* * call-seq: * time - other_time => float * time - numeric => time * * Difference---Returns a new time that represents the difference * between two times, or subtracts the given number of seconds in * numeric from time. * * t = Time.now #=> Wed Apr 09 08:56:03 CDT 2003 * t2 = t + 2592000 #=> Fri May 09 08:56:03 CDT 2003 * t2 - t #=> 2592000.0 * t2 - 2592000 #=> Wed Apr 09 08:56:03 CDT 2003 */ static VALUE time_minus(time1, time2) VALUE time1, time2; { struct time_object *tobj; GetTimeval(time1, tobj); if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) { struct time_object *tobj2; double f; GetTimeval(time2, tobj2); f = (double)tobj->tv.tv_sec - (double)tobj2->tv.tv_sec; f += ((double)tobj->tv.tv_usec - (double)tobj2->tv.tv_usec)*1e-6; /* XXX: should check float overflow on 64bit time_t platforms */ return rb_float_new(f); } return time_add(tobj, time2, -1); } /* * call-seq: * time.succ => new_time * * Return a new time object, one second later than time. */ static VALUE time_succ(time) VALUE time; { struct time_object *tobj; int gmt; GetTimeval(time, tobj); gmt = tobj->gmt; time = rb_time_new(tobj->tv.tv_sec + 1, tobj->tv.tv_usec); GetTimeval(time, tobj); tobj->gmt = gmt; return time; } /* * call-seq: * time.sec => fixnum * * Returns the second of the minute (0..60)[Yes, seconds really can * range from zero to 60. This allows the system to inject leap seconds * every now and then to correct for the fact that years are not really * a convenient number of hours long.] for time. * * t = Time.now #=> Wed Apr 09 08:56:04 CDT 2003 * t.sec #=> 4 */ static VALUE time_sec(time) VALUE time; { struct time_object *tobj; GetTimeval(time, tobj); if (tobj->tm_got == 0) { time_get_tm(time, tobj->gmt); } return INT2FIX(tobj->tm.tm_sec); } /* * call-seq: * time.min => fixnum * * Returns the minute of the hour (0..59) for time. * * t = Time.now #=> Wed Apr 09 08:56:03 CDT 2003 * t.min #=> 56 */ static VALUE time_min(time) VALUE time; { struct time_object *tobj; GetTimeval(time, tobj); if (tobj->tm_got == 0) { time_get_tm(time, tobj->gmt); } return INT2FIX(tobj->tm.tm_min); } /* * call-seq: * time.hour => fixnum * * Returns the hour of the day (0..23) for time. * * t = Time.now #=> Wed Apr 09 08:56:03 CDT 2003 * t.hour #=> 8 */ static VALUE time_hour(time) VALUE time; { struct time_object *tobj; GetTimeval(time, tobj); if (tobj->tm_got == 0) { time_get_tm(time, tobj->gmt); } return INT2FIX(tobj->tm.tm_hour); } /* * call-seq: * time.day => fixnum * time.mday => fixnum * * Returns the day of the month (1..n) for time. * * t = Time.now #=> Wed Apr 09 08:56:03 CDT 2003 * t.day #=> 9 * t.mday #=> 9 */ static VALUE time_mday(time) VALUE time; { struct time_object *tobj; GetTimeval(time, tobj); if (tobj->tm_got == 0) { time_get_tm(time, tobj->gmt); } return INT2FIX(tobj->tm.tm_mday); } /* * call-seq: * time.mon => fixnum * time.month => fixnum * * Returns the month of the year (1..12) for time. * * t = Time.now #=> Wed Apr 09 08:56:03 CDT 2003 * t.mon #=> 4 * t.month #=> 4 */ static VALUE time_mon(time) VALUE time; { struct time_object *tobj; GetTimeval(time, tobj); if (tobj->tm_got == 0) { time_get_tm(time, tobj->gmt); } return INT2FIX(tobj->tm.tm_mon+1); } /* * call-seq: * time.year => fixnum * * Returns the year for time (including the century). * * t = Time.now #=> Wed Apr 09 08:56:04 CDT 2003 * t.year #=> 2003 */ static VALUE time_year(time) VALUE time; { struct time_object *tobj; GetTimeval(time, tobj); if (tobj->tm_got == 0) { time_get_tm(time, tobj->gmt); } return LONG2NUM((long)tobj->tm.tm_year+1900); } /* * call-seq: * time.wday => fixnum * * Returns an integer representing the day of the week, 0..6, with * Sunday == 0. * * t = Time.now #=> Wed Apr 09 08:56:04 CDT 2003 * t.wday #=> 3 */ static VALUE time_wday(time) VALUE time; { struct time_object *tobj; GetTimeval(time, tobj); if (tobj->tm_got == 0) { time_get_tm(time, tobj->gmt); } return INT2FIX(tobj->tm.tm_wday); } /* * call-seq: * time.yday => fixnum * * Returns an integer representing the day of the year, 1..366. * * t = Time.now #=> Wed Apr 09 08:56:04 CDT 2003 * t.yday #=> 99 */ static VALUE time_yday(time) VALUE time; { struct time_object *tobj; GetTimeval(time, tobj); if (tobj->tm_got == 0) { time_get_tm(time, tobj->gmt); } return INT2FIX(tobj->tm.tm_yday+1); } /* * call-seq: * time.isdst => true or false * time.dst? => true or false * * Returns true if time occurs during Daylight * Saving Time in its time zone. * * Time.local(2000, 7, 1).isdst #=> true * Time.local(2000, 1, 1).isdst #=> false * Time.local(2000, 7, 1).dst? #=> true * Time.local(2000, 1, 1).dst? #=> false */ static VALUE time_isdst(time) VALUE time; { struct time_object *tobj; GetTimeval(time, tobj); if (tobj->tm_got == 0) { time_get_tm(time, tobj->gmt); } return tobj->tm.tm_isdst?Qtrue:Qfalse; } /* * call-seq: * time.zone => string * * Returns the name of the time zone used for time. As of Ruby * 1.8, returns ``UTC'' rather than ``GMT'' for UTC times. * * t = Time.gm(2000, "jan", 1, 20, 15, 1) * t.zone #=> "UTC" * t = Time.local(2000, "jan", 1, 20, 15, 1) * t.zone #=> "CST" */ static VALUE time_zone(time) VALUE time; { struct time_object *tobj; #if !defined(HAVE_TM_ZONE) && (!defined(HAVE_TZNAME) || !defined(HAVE_DAYLIGHT)) char buf[64]; int len; #endif GetTimeval(time, tobj); if (tobj->tm_got == 0) { time_get_tm(time, tobj->gmt); } if (tobj->gmt == 1) { return rb_str_new2("UTC"); } #if defined(HAVE_TM_ZONE) return rb_str_new2(tobj->tm.tm_zone); #elif defined(HAVE_TZNAME) && defined(HAVE_DAYLIGHT) return rb_str_new2(tzname[daylight && tobj->tm.tm_isdst]); #else len = strftime(buf, 64, "%Z", &tobj->tm); return rb_str_new(buf, len); #endif } /* * call-seq: * time.gmt_offset => fixnum * time.gmtoff => fixnum * time.utc_offset => fixnum * * Returns the offset in seconds between the timezone of time * and UTC. * * t = Time.gm(2000,1,1,20,15,1) #=> Sat Jan 01 20:15:01 UTC 2000 * t.gmt_offset #=> 0 * l = t.getlocal #=> Sat Jan 01 14:15:01 CST 2000 * l.gmt_offset #=> -21600 */ static VALUE time_utc_offset(time) VALUE time; { struct time_object *tobj; GetTimeval(time, tobj); if (tobj->tm_got == 0) { time_get_tm(time, tobj->gmt); } if (tobj->gmt == 1) { return INT2FIX(0); } else { #if defined(HAVE_STRUCT_TM_TM_GMTOFF) return INT2NUM(tobj->tm.tm_gmtoff); #else struct tm *u, *l; time_t t; long off; l = &tobj->tm; t = tobj->tv.tv_sec; u = gmtime(&t); if (!u) rb_raise(rb_eArgError, "gmtime error"); if (l->tm_year != u->tm_year) off = l->tm_year < u->tm_year ? -1 : 1; else if (l->tm_mon != u->tm_mon) off = l->tm_mon < u->tm_mon ? -1 : 1; else if (l->tm_mday != u->tm_mday) off = l->tm_mday < u->tm_mday ? -1 : 1; else off = 0; off = off * 24 + l->tm_hour - u->tm_hour; off = off * 60 + l->tm_min - u->tm_min; off = off * 60 + l->tm_sec - u->tm_sec; return LONG2FIX(off); #endif } } /* * call-seq: * time.to_a => array * * Returns a ten-element array of values for time: * {[ sec, min, hour, day, month, year, wday, yday, isdst, zone * ]}. See the individual methods for an explanation of the * valid ranges of each value. The ten elements can be passed directly * to Time::utc or Time::local to create a * new Time. * * now = Time.now #=> Wed Apr 09 08:56:04 CDT 2003 * t = now.to_a #=> [4, 56, 8, 9, 4, 2003, 3, 99, true, "CDT"] */ static VALUE time_to_a(time) VALUE time; { struct time_object *tobj; GetTimeval(time, tobj); if (tobj->tm_got == 0) { time_get_tm(time, tobj->gmt); } return rb_ary_new3(10, INT2FIX(tobj->tm.tm_sec), INT2FIX(tobj->tm.tm_min), INT2FIX(tobj->tm.tm_hour), INT2FIX(tobj->tm.tm_mday), INT2FIX(tobj->tm.tm_mon+1), LONG2NUM((long)tobj->tm.tm_year+1900), INT2FIX(tobj->tm.tm_wday), INT2FIX(tobj->tm.tm_yday+1), tobj->tm.tm_isdst?Qtrue:Qfalse, time_zone(time)); } #define SMALLBUF 100 static int rb_strftime(buf, format, time) char **buf; const char *format; struct tm *time; { int size, len, flen; (*buf)[0] = '\0'; flen = strlen(format); if (flen == 0) { return 0; } errno = 0; len = strftime(*buf, SMALLBUF, format, time); if (len != 0 || (**buf == '\0' && errno != ERANGE)) return len; for (size=1024; ; size*=2) { *buf = xmalloc(size); (*buf)[0] = '\0'; len = strftime(*buf, size, format, time); /* * buflen can be zero EITHER because there's not enough * room in the string, or because the control command * goes to the empty string. Make a reasonable guess that * if the buffer is 1024 times bigger than the length of the * format string, it's not failing for lack of room. */ if (len > 0 || size >= 1024 * flen) return len; free(*buf); } /* not reached */ } /* * call-seq: * time.strftime( string ) => string * * Formats time according to the directives in the given format * string. Any text not listed as a directive will be passed through * to the output string. * * Format meaning: * %a - The abbreviated weekday name (``Sun'') * %A - The full weekday name (``Sunday'') * %b - The abbreviated month name (``Jan'') * %B - The full month name (``January'') * %c - The preferred local date and time representation * %d - Day of the month (01..31) * %H - Hour of the day, 24-hour clock (00..23) * %I - Hour of the day, 12-hour clock (01..12) * %j - Day of the year (001..366) * %m - Month of the year (01..12) * %M - Minute of the hour (00..59) * %p - Meridian indicator (``AM'' or ``PM'') * %S - Second of the minute (00..60) * %U - Week number of the current year, * starting with the first Sunday as the first * day of the first week (00..53) * %W - Week number of the current year, * starting with the first Monday as the first * day of the first week (00..53) * %w - Day of the week (Sunday is 0, 0..6) * %x - Preferred representation for the date alone, no time * %X - Preferred representation for the time alone, no date * %y - Year without a century (00..99) * %Y - Year with century * %Z - Time zone name * %% - Literal ``%'' character * * t = Time.now * t.strftime("Printed on %m/%d/%Y") #=> "Printed on 04/09/2003" * t.strftime("at %I:%M%p") #=> "at 08:56AM" */ static VALUE time_strftime(time, format) VALUE time, format; { struct time_object *tobj; char buffer[SMALLBUF], *buf = buffer; const char *fmt; long len; VALUE str; GetTimeval(time, tobj); if (tobj->tm_got == 0) { time_get_tm(time, tobj->gmt); } StringValue(format); format = rb_str_new4(format); fmt = RSTRING(format)->ptr; len = RSTRING(format)->len; if (len == 0) { rb_warning("strftime called with empty format string"); } else if (strlen(fmt) < len) { /* Ruby string may contain \0's. */ const char *p = fmt, *pe = fmt + len; str = rb_str_new(0, 0); while (p < pe) { len = rb_strftime(&buf, p, &tobj->tm); rb_str_cat(str, buf, len); p += strlen(p); if (buf != buffer) { free(buf); buf = buffer; } for (fmt = p; p < pe && !*p; ++p); if (p > fmt) rb_str_cat(str, fmt, p - fmt); } return str; } else { len = rb_strftime(&buf, RSTRING(format)->ptr, &tobj->tm); } str = rb_str_new(buf, len); if (buf != buffer) free(buf); return str; } /* * call-seq: * Time.times => struct_tms * * Deprecated in favor of Process::times */ static VALUE time_s_times(obj) VALUE obj; { rb_warn("obsolete method Time::times; use Process::times"); return rb_proc_times(obj); } /* * undocumented */ static VALUE time_mdump(time) VALUE time; { struct time_object *tobj; struct tm *tm; unsigned long p, s; char buf[8]; time_t t; int i; GetTimeval(time, tobj); t = tobj->tv.tv_sec; tm = gmtime(&t); if ((tm->tm_year & 0xffff) != tm->tm_year) rb_raise(rb_eArgError, "year too big to marshal"); p = 0x1UL << 31 | /* 1 */ tobj->gmt << 30 | /* 1 */ tm->tm_year << 14 | /* 16 */ tm->tm_mon << 10 | /* 4 */ tm->tm_mday << 5 | /* 5 */ tm->tm_hour; /* 5 */ s = tm->tm_min << 26 | /* 6 */ tm->tm_sec << 20 | /* 6 */ tobj->tv.tv_usec; /* 20 */ for (i=0; i<4; i++) { buf[i] = p & 0xff; p = RSHIFT(p, 8); } for (i=4; i<8; i++) { buf[i] = s & 0xff; s = RSHIFT(s, 8); } return rb_str_new(buf, 8); } /* * call-seq: * time._dump => string * * Dump _time_ for marshaling. */ static VALUE time_dump(argc, argv, time) int argc; VALUE *argv; VALUE time; { VALUE str; rb_scan_args(argc, argv, "01", 0); str = time_mdump(time); if (FL_TEST(time, FL_EXIVAR)) { rb_copy_generic_ivar(str, time); FL_SET(str, FL_EXIVAR); } return str; } /* * undocumented */ static VALUE time_mload(time, str) VALUE time, str; { struct time_object *tobj; unsigned long p, s; time_t sec, usec; unsigned char *buf; struct tm tm; int i, gmt; time_modify(time); StringValue(str); buf = (unsigned char *)RSTRING(str)->ptr; if (RSTRING(str)->len != 8) { rb_raise(rb_eTypeError, "marshaled time format differ"); } p = s = 0; for (i=0; i<4; i++) { p |= buf[i]<<(8*i); } for (i=4; i<8; i++) { s |= buf[i]<<(8*(i-4)); } if ((p & (1UL<<31)) == 0) { sec = p; usec = s; } else { p &= ~(1UL<<31); gmt = (p >> 30) & 0x1; tm.tm_year = (p >> 14) & 0xffff; tm.tm_mon = (p >> 10) & 0xf; tm.tm_mday = (p >> 5) & 0x1f; tm.tm_hour = p & 0x1f; tm.tm_min = (s >> 26) & 0x3f; tm.tm_sec = (s >> 20) & 0x3f; tm.tm_isdst = 0; sec = make_time_t(&tm, Qtrue); usec = (time_t)(s & 0xfffff); } time_overflow_p(&sec, &usec); GetTimeval(time, tobj); tobj->tm_got = 0; tobj->gmt = gmt; tobj->tv.tv_sec = sec; tobj->tv.tv_usec = usec; return time; } /* * call-seq: * Time._load(string) => time * * Unmarshal a dumped +Time+ object. */ static VALUE time_load(klass, str) VALUE klass, str; { VALUE time = time_s_alloc(klass); if (FL_TEST(str, FL_EXIVAR)) { rb_copy_generic_ivar(time, str); FL_SET(time, FL_EXIVAR); } time_mload(time, str); return time; } /* * Time is an abstraction of dates and times. Time is * stored internally as the number of seconds and microseconds since * the epoch, January 1, 1970 00:00 UTC. On some operating * systems, this offset is allowed to be negative. Also see the * library modules Date and ParseDate. The * Time class treats GMT (Greenwich Mean Time) and UTC * (Coordinated Universal Time)[Yes, UTC really does stand for * Coordinated Universal Time. There was a committee involved.] * as equivalent. GMT is the older way of referring to these * baseline times but persists in the names of calls on Posix * systems. * * All times are stored with some number of microseconds. Be aware of * this fact when comparing times with each other---times that are * apparently equal when displayed may be different when compared. */ void Init_Time() { rb_cTime = rb_define_class("Time", rb_cObject); rb_include_module(rb_cTime, rb_mComparable); rb_define_alloc_func(rb_cTime, time_s_alloc); rb_define_singleton_method(rb_cTime, "now", rb_class_new_instance, -1); rb_define_singleton_method(rb_cTime, "at", time_s_at, -1); rb_define_singleton_method(rb_cTime, "utc", time_s_mkutc, -1); rb_define_singleton_method(rb_cTime, "gm", time_s_mkutc, -1); rb_define_singleton_method(rb_cTime, "local", time_s_mktime, -1); rb_define_singleton_method(rb_cTime, "mktime", time_s_mktime, -1); rb_define_singleton_method(rb_cTime, "times", time_s_times, 0); rb_define_method(rb_cTime, "to_i", time_to_i, 0); rb_define_method(rb_cTime, "to_f", time_to_f, 0); rb_define_method(rb_cTime, "<=>", time_cmp, 1); rb_define_method(rb_cTime, "eql?", time_eql, 1); rb_define_method(rb_cTime, "hash", time_hash, 0); rb_define_method(rb_cTime, "initialize", time_init, 0); rb_define_method(rb_cTime, "initialize_copy", time_init_copy, 1); rb_define_method(rb_cTime, "localtime", time_localtime, 0); rb_define_method(rb_cTime, "gmtime", time_gmtime, 0); rb_define_method(rb_cTime, "utc", time_gmtime, 0); rb_define_method(rb_cTime, "getlocal", time_getlocaltime, 0); rb_define_method(rb_cTime, "getgm", time_getgmtime, 0); rb_define_method(rb_cTime, "getutc", time_getgmtime, 0); rb_define_method(rb_cTime, "ctime", time_asctime, 0); rb_define_method(rb_cTime, "asctime", time_asctime, 0); rb_define_method(rb_cTime, "to_s", time_to_s, 0); rb_define_method(rb_cTime, "inspect", time_to_s, 0); rb_define_method(rb_cTime, "to_a", time_to_a, 0); rb_define_method(rb_cTime, "+", time_plus, 1); rb_define_method(rb_cTime, "-", time_minus, 1); rb_define_method(rb_cTime, "succ", time_succ, 0); rb_define_method(rb_cTime, "sec", time_sec, 0); rb_define_method(rb_cTime, "min", time_min, 0); rb_define_method(rb_cTime, "hour", time_hour, 0); rb_define_method(rb_cTime, "mday", time_mday, 0); rb_define_method(rb_cTime, "day", time_mday, 0); rb_define_method(rb_cTime, "mon", time_mon, 0); rb_define_method(rb_cTime, "month", time_mon, 0); rb_define_method(rb_cTime, "year", time_year, 0); rb_define_method(rb_cTime, "wday", time_wday, 0); rb_define_method(rb_cTime, "yday", time_yday, 0); rb_define_method(rb_cTime, "isdst", time_isdst, 0); rb_define_method(rb_cTime, "dst?", time_isdst, 0); rb_define_method(rb_cTime, "zone", time_zone, 0); rb_define_method(rb_cTime, "gmtoff", time_utc_offset, 0); rb_define_method(rb_cTime, "gmt_offset", time_utc_offset, 0); rb_define_method(rb_cTime, "utc_offset", time_utc_offset, 0); rb_define_method(rb_cTime, "utc?", time_utc_p, 0); rb_define_method(rb_cTime, "gmt?", time_utc_p, 0); rb_define_method(rb_cTime, "tv_sec", time_to_i, 0); rb_define_method(rb_cTime, "tv_usec", time_usec, 0); rb_define_method(rb_cTime, "usec", time_usec, 0); rb_define_method(rb_cTime, "strftime", time_strftime, 1); /* methods for marshaling */ rb_define_method(rb_cTime, "_dump", time_dump, -1); rb_define_singleton_method(rb_cTime, "_load", time_load, 1); #if 0 /* Time will support marshal_dump and marshal_load in the future (1.9 maybe) */ rb_define_method(rb_cTime, "marshal_dump", time_mdump, 0); rb_define_method(rb_cTime, "marshal_load", time_mload, 1); #endif } ================================================ FILE: util.c ================================================ /********************************************************************** util.c - $Author$ $Date$ created at: Fri Mar 10 17:22:34 JST 1995 Copyright (C) 1993-2008 Yukihiro Matsumoto **********************************************************************/ #include "ruby.h" #include #include #include #include #include #ifdef _WIN32 #include "missing/file.h" #endif #if defined(__CYGWIN32__) || defined(_WIN32) #include #endif #include "util.h" #ifndef HAVE_STRING_H char *strchr _((char*,char)); #endif unsigned long scan_oct(start, len, retlen) const char *start; int len; int *retlen; { register const char *s = start; register unsigned long retval = 0; while (len-- && *s >= '0' && *s <= '7') { retval <<= 3; retval |= *s++ - '0'; } *retlen = s - start; return retval; } unsigned long scan_hex(start, len, retlen) const char *start; int len; int *retlen; { static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF"; register const char *s = start; register unsigned long retval = 0; char *tmp; while (len-- && *s && (tmp = strchr(hexdigit, *s))) { retval <<= 4; retval |= (tmp - hexdigit) & 15; s++; } *retlen = s - start; return retval; } #include #include #ifdef HAVE_UNISTD_H #include #endif #if defined(HAVE_FCNTL_H) #include #endif #ifndef S_ISDIR # define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) #endif #if defined(MSDOS) || defined(__CYGWIN32__) || defined(_WIN32) /* * Copyright (c) 1993, Intergraph Corporation * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the perl README file. * * Various Unix compatibility functions and NT specific functions. * * Some of this code was derived from the MSDOS port(s) and the OS/2 port. * */ /* * Suffix appending for in-place editing under MS-DOS and OS/2 (and now NT!). * * Here are the rules: * * Style 0: Append the suffix exactly as standard perl would do it. * If the filesystem groks it, use it. (HPFS will always * grok it. So will NTFS. FAT will rarely accept it.) * * Style 1: The suffix begins with a '.'. The extension is replaced. * If the name matches the original name, use the fallback method. * * Style 2: The suffix is a single character, not a '.'. Try to add the * suffix to the following places, using the first one that works. * [1] Append to extension. * [2] Append to filename, * [3] Replace end of extension, * [4] Replace end of filename. * If the name matches the original name, use the fallback method. * * Style 3: Any other case: Ignore the suffix completely and use the * fallback method. * * Fallback method: Change the extension to ".$$$". If that matches the * original name, then change the extension to ".~~~". * * If filename is more than 1000 characters long, we die a horrible * death. Sorry. * * The filename restriction is a cheat so that we can use buf[] to store * assorted temporary goo. * * Examples, assuming style 0 failed. * * suffix = ".bak" (style 1) * foo.bar => foo.bak * foo.bak => foo.$$$ (fallback) * foo.$$$ => foo.~~~ (fallback) * makefile => makefile.bak * * suffix = "~" (style 2) * foo.c => foo.c~ * foo.c~ => foo.c~~ * foo.c~~ => foo~.c~~ * foo~.c~~ => foo~~.c~~ * foo~~~~~.c~~ => foo~~~~~.$$$ (fallback) * * foo.pas => foo~.pas * makefile => makefile.~ * longname.fil => longname.fi~ * longname.fi~ => longnam~.fi~ * longnam~.fi~ => longnam~.$$$ * */ static int valid_filename(char *s); static const char suffix1[] = ".$$$"; static const char suffix2[] = ".~~~"; #define ext (&buf[1000]) #define strEQ(s1,s2) (strcmp(s1,s2) == 0) void ruby_add_suffix(str, suffix) VALUE str; char *suffix; { int baselen; int extlen = strlen(suffix); char *s, *t, *p; long slen; char buf[1024]; if (RSTRING(str)->len > 1000) rb_fatal("Cannot do inplace edit on long filename (%ld characters)", RSTRING(str)->len); #if defined(DJGPP) || defined(__CYGWIN32__) || defined(_WIN32) /* Style 0 */ slen = RSTRING(str)->len; rb_str_cat(str, suffix, extlen); #if defined(DJGPP) if (_USE_LFN) return; #else if (valid_filename(RSTRING(str)->ptr)) return; #endif /* Fooey, style 0 failed. Fix str before continuing. */ RSTRING(str)->ptr[RSTRING(str)->len = slen] = '\0'; #endif slen = extlen; t = buf; baselen = 0; s = RSTRING(str)->ptr; while ((*t = *s) && *s != '.') { baselen++; if (*s == '\\' || *s == '/') baselen = 0; s++; t++; } p = t; t = ext; extlen = 0; while (*t++ = *s++) extlen++; if (extlen == 0) { ext[0] = '.'; ext[1] = 0; extlen++; } if (*suffix == '.') { /* Style 1 */ if (strEQ(ext, suffix)) goto fallback; strcpy(p, suffix); } else if (suffix[1] == '\0') { /* Style 2 */ if (extlen < 4) { ext[extlen] = *suffix; ext[++extlen] = '\0'; } else if (baselen < 8) { *p++ = *suffix; } else if (ext[3] != *suffix) { ext[3] = *suffix; } else if (buf[7] != *suffix) { buf[7] = *suffix; } else goto fallback; strcpy(p, ext); } else { /* Style 3: Panic */ fallback: (void)memcpy(p, strEQ(ext, suffix1) ? suffix2 : suffix1, 5); } rb_str_resize(str, strlen(buf)); memcpy(RSTRING(str)->ptr, buf, RSTRING(str)->len); } #if defined(__CYGWIN32__) || defined(_WIN32) #if defined __CYGWIN32__ || defined __MINGW32__ extern int _open(const char *, int, ...); extern int _close(int); extern int _unlink(const char *); #endif static int valid_filename(char *s) { int fd; /* // It doesn't exist, so see if we can open it. */ if ((fd = _open(s, O_CREAT|O_EXCL, 0666)) >= 0) { _close(fd); _unlink(s); /* don't leave it laying around */ return 1; } else if (errno == EEXIST) { /* if the file exists, then it's a valid filename! */ return 1; } return 0; } #endif #endif #if defined __DJGPP__ #include static char dbcs_table[256]; int make_dbcs_table() { __dpmi_regs r; struct { unsigned char start; unsigned char end; } vec; int offset; memset(&r, 0, sizeof(r)); r.x.ax = 0x6300; __dpmi_int(0x21, &r); offset = r.x.ds * 16 + r.x.si; for (;;) { int i; dosmemget(offset, sizeof vec, &vec); if (!vec.start && !vec.end) break; for (i = vec.start; i <= vec.end; i++) dbcs_table[i] = 1; offset += 2; } } int mblen(const char *s, size_t n) { static int need_init = 1; if (need_init) { make_dbcs_table(); need_init = 0; } if (s) { if (n == 0 || *s == 0) return 0; else if (!s[1]) return 1; return dbcs_table[(unsigned char)*s] + 1; } else return 1; } struct PathList { struct PathList *next; char *path; }; struct PathInfo { struct PathList *head; int count; }; static int push_element(const char *path, VALUE vinfo) { struct PathList *p; struct PathInfo *info = (struct PathInfo *)vinfo; p = ALLOC(struct PathList); MEMZERO(p, struct PathList, 1); p->path = ruby_strdup(path); p->next = info->head; info->head = p; info->count++; return 0; } #include int __opendir_flags = __OPENDIR_PRESERVE_CASE; char ** __crt0_glob_function(char *path) { int len = strlen(path); int i; char **rv; char path_buffer[PATH_MAX]; char *buf = path_buffer; char *p; struct PathInfo info; struct PathList *plist; if (PATH_MAX <= len) buf = ruby_xmalloc(len + 1); strncpy(buf, path, len); buf[len] = '\0'; for (p = buf; *p; p += mblen(p, MB_CUR_MAX)) if (*p == '\\') *p = '/'; info.count = 0; info.head = 0; ruby_glob(buf, 0, push_element, (VALUE)&info); if (buf != path_buffer) ruby_xfree(buf); if (info.count == 0) return 0; rv = ruby_xmalloc((info.count + 1) * sizeof (char *)); plist = info.head; i = 0; while (plist) { struct PathList *cur; rv[i] = plist->path; cur = plist; plist = plist->next; ruby_xfree(cur); i++; } rv[i] = 0; return rv; } #endif /* mm.c */ #define A ((int*)a) #define B ((int*)b) #define C ((int*)c) #define D ((int*)d) #define mmprepare(base, size) do {\ if (((long)base & (0x3)) == 0)\ if (size >= 16) mmkind = 1;\ else mmkind = 0;\ else mmkind = -1;\ high = (size & (~0xf));\ low = (size & 0x0c);\ } while (0)\ #define mmarg mmkind, size, high, low static void mmswap_(a, b, mmarg) register char *a, *b; int mmarg; { register int s; if (a == b) return; if (mmkind >= 0) { if (mmkind > 0) { register char *t = a + high; do { s = A[0]; A[0] = B[0]; B[0] = s; s = A[1]; A[1] = B[1]; B[1] = s; s = A[2]; A[2] = B[2]; B[2] = s; s = A[3]; A[3] = B[3]; B[3] = s; a += 16; b += 16; } while (a < t); } if (low != 0) { s = A[0]; A[0] = B[0]; B[0] = s; if (low >= 8) { s = A[1]; A[1] = B[1]; B[1] = s; if (low == 12) {s = A[2]; A[2] = B[2]; B[2] = s;}}} } else { register char *t = a + size; do {s = *a; *a++ = *b; *b++ = s;} while (a < t); } } #define mmswap(a,b) mmswap_((a),(b),mmarg) static void mmrot3_(a, b, c, mmarg) register char *a, *b, *c; int mmarg; { register int s; if (mmkind >= 0) { if (mmkind > 0) { register char *t = a + high; do { s = A[0]; A[0] = B[0]; B[0] = C[0]; C[0] = s; s = A[1]; A[1] = B[1]; B[1] = C[1]; C[1] = s; s = A[2]; A[2] = B[2]; B[2] = C[2]; C[2] = s; s = A[3]; A[3] = B[3]; B[3] = C[3]; C[3] = s; a += 16; b += 16; c += 16; } while (a < t); } if (low != 0) { s = A[0]; A[0] = B[0]; B[0] = C[0]; C[0] = s; if (low >= 8) { s = A[1]; A[1] = B[1]; B[1] = C[1]; C[1] = s; if (low == 12) {s = A[2]; A[2] = B[2]; B[2] = C[2]; C[2] = s;}}} } else { register char *t = a + size; do {s = *a; *a++ = *b; *b++ = *c; *c++ = s;} while (a < t); } } #define mmrot3(a,b,c) mmrot3_((a),(b),(c),mmarg) /* qs6.c */ /*****************************************************/ /* */ /* qs6 (Quick sort function) */ /* */ /* by Tomoyuki Kawamura 1995.4.21 */ /* kawamura@tokuyama.ac.jp */ /*****************************************************/ typedef struct { char *LL, *RR; } stack_node; /* Stack structure for L,l,R,r */ #define PUSH(ll,rr) do { top->LL = (ll); top->RR = (rr); ++top; } while (0) /* Push L,l,R,r */ #define POP(ll,rr) do { --top; ll = top->LL; rr = top->RR; } while (0) /* Pop L,l,R,r */ #define med3(a,b,c) ((*cmp)(a,b,d)<0 ? \ ((*cmp)(b,c,d)<0 ? b : ((*cmp)(a,c,d)<0 ? c : a)) : \ ((*cmp)(b,c,d)>0 ? b : ((*cmp)(a,c,d)<0 ? a : c))) void ruby_qsort (base, nel, size, cmp, d) void* base; const int nel; const int size; int (*cmp)(); void *d; { register char *l, *r, *m; /* l,r:left,right group m:median point */ register int t, eq_l, eq_r; /* eq_l: all items in left group are equal to S */ char *L = base; /* left end of curren region */ char *R = (char*)base + size*(nel-1); /* right end of current region */ int chklim = 63; /* threshold of ordering element check */ stack_node stack[32], *top = stack; /* 32 is enough for 32bit CPU */ int mmkind, high, low; if (nel <= 1) return; /* need not to sort */ mmprepare(base, size); goto start; nxt: if (stack == top) return; /* return if stack is empty */ POP(L,R); for (;;) { start: if (L + size == R) { /* 2 elements */ if ((*cmp)(L,R,d) > 0) mmswap(L,R); goto nxt; } l = L; r = R; t = (r - l + size) / size; /* number of elements */ m = l + size * (t >> 1); /* calculate median value */ if (t >= 60) { register char *m1; register char *m3; if (t >= 200) { t = size*(t>>3); /* number of bytes in splitting 8 */ { register char *p1 = l + t; register char *p2 = p1 + t; register char *p3 = p2 + t; m1 = med3(p1, p2, p3); p1 = m + t; p2 = p1 + t; p3 = p2 + t; m3 = med3(p1, p2, p3); } } else { t = size*(t>>2); /* number of bytes in splitting 4 */ m1 = l + t; m3 = m + t; } m = med3(m1, m, m3); } if ((t = (*cmp)(l,m,d)) < 0) { /*3-5-?*/ if ((t = (*cmp)(m,r,d)) < 0) { /*3-5-7*/ if (chklim && nel >= chklim) { /* check if already ascending order */ char *p; chklim = 0; for (p=l; p 0) goto fail; goto nxt; } fail: goto loopA; /*3-5-7*/ } if (t > 0) { if ((*cmp)(l,r,d) <= 0) {mmswap(m,r); goto loopA;} /*3-5-4*/ mmrot3(r,m,l); goto loopA; /*3-5-2*/ } goto loopB; /*3-5-5*/ } if (t > 0) { /*7-5-?*/ if ((t = (*cmp)(m,r,d)) > 0) { /*7-5-3*/ if (chklim && nel >= chklim) { /* check if already ascending order */ char *p; chklim = 0; for (p=l; p 0) {mmswap(l,r); goto loopB;} /*5-5-3*/ /* determining splitting type in case 5-5-5 */ /*5-5-5*/ for (;;) { if ((l += size) == r) goto nxt; /*5-5-5*/ if (l == m) continue; if ((t = (*cmp)(l,m,d)) > 0) {mmswap(l,r); l = L; goto loopA;}/*575-5*/ if (t < 0) {mmswap(L,l); l = L; goto loopB;} /*535-5*/ } loopA: eq_l = 1; eq_r = 1; /* splitting type A */ /* left <= median < right */ for (;;) { for (;;) { if ((l += size) == r) {l -= size; if (l != m) mmswap(m,l); l -= size; goto fin;} if (l == m) continue; if ((t = (*cmp)(l,m,d)) > 0) {eq_r = 0; break;} if (t < 0) eq_l = 0; } for (;;) { if (l == (r -= size)) {l -= size; if (l != m) mmswap(m,l); l -= size; goto fin;} if (r == m) {m = l; break;} if ((t = (*cmp)(r,m,d)) < 0) {eq_l = 0; break;} if (t == 0) break; } mmswap(l,r); /* swap left and right */ } loopB: eq_l = 1; eq_r = 1; /* splitting type B */ /* left < median <= right */ for (;;) { for (;;) { if (l == (r -= size)) {r += size; if (r != m) mmswap(r,m); r += size; goto fin;} if (r == m) continue; if ((t = (*cmp)(r,m,d)) < 0) {eq_l = 0; break;} if (t > 0) eq_r = 0; } for (;;) { if ((l += size) == r) {r += size; if (r != m) mmswap(r,m); r += size; goto fin;} if (l == m) {m = r; break;} if ((t = (*cmp)(l,m,d)) > 0) {eq_r = 0; break;} if (t == 0) break; } mmswap(l,r); /* swap left and right */ } fin: if (eq_l == 0) /* need to sort left side */ if (eq_r == 0) /* need to sort right side */ if (l-L < R-r) {PUSH(r,R); R = l;} /* sort left side first */ else {PUSH(L,l); L = r;} /* sort right side first */ else R = l; /* need to sort left side only */ else if (eq_r == 0) L = r; /* need to sort right side only */ else goto nxt; /* need not to sort both sides */ } } char * ruby_strdup(str) const char *str; { char *tmp; int len = strlen(str) + 1; tmp = xmalloc(len); memcpy(tmp, str, len); return tmp; } /* Mask system strdup to fix tcmalloc issue on OS X*/ #define strdup(s) strdup(s) char * strdup(str) const char *str; { return ruby_strdup(str); } #define strdup(s) ruby_strdup(s) char * ruby_getcwd() { #ifdef HAVE_GETCWD int size = 200; char *buf = xmalloc(size); while (!getcwd(buf, size)) { if (errno != ERANGE) { free(buf); rb_sys_fail("getcwd"); } size *= 2; buf = xrealloc(buf, size); } #else # ifndef PATH_MAX # define PATH_MAX 8192 # endif char *buf = xmalloc(PATH_MAX+1); if (!getwd(buf)) { free(buf); rb_sys_fail("getwd"); } #endif return buf; } /**************************************************************** * * The author of this software is David M. Gay. * * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. * * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. * ***************************************************************/ /* Please send bug reports to David M. Gay (dmg at acm dot org, * with " at " changed at "@" and " dot " changed to "."). */ /* On a machine with IEEE extended-precision registers, it is * necessary to specify double-precision (53-bit) rounding precision * before invoking strtod or dtoa. If the machine uses (the equivalent * of) Intel 80x87 arithmetic, the call * _control87(PC_53, MCW_PC); * does this with many compilers. Whether this or another call is * appropriate depends on the compiler; for this to work, it may be * necessary to #include "float.h" or another system-dependent header * file. */ /* strtod for IEEE-, VAX-, and IBM-arithmetic machines. * * This strtod returns a nearest machine number to the input decimal * string (or sets errno to ERANGE). With IEEE arithmetic, ties are * broken by the IEEE round-even rule. Otherwise ties are broken by * biased rounding (add half and chop). * * Inspired loosely by William D. Clinger's paper "How to Read Floating * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. * * Modifications: * * 1. We only require IEEE, IBM, or VAX double-precision * arithmetic (not IEEE double-extended). * 2. We get by with floating-point arithmetic in a case that * Clinger missed -- when we're computing d * 10^n * for a small integer d and the integer n is not too * much larger than 22 (the maximum integer k for which * we can represent 10^k exactly), we may be able to * compute (d*10^k) * 10^(e-k) with just one roundoff. * 3. Rather than a bit-at-a-time adjustment of the binary * result in the hard case, we use floating-point * arithmetic to determine the adjustment to within * one bit; only in really hard cases do we need to * compute a second residual. * 4. Because of 3., we don't need a large table of powers of 10 * for ten-to-e (just some small tables, e.g. of 10^k * for 0 <= k <= 22). */ /* * #define IEEE_LITTLE_ENDIAN for IEEE-arithmetic machines where the least * significant byte has the lowest address. * #define IEEE_BIG_ENDIAN for IEEE-arithmetic machines where the most * significant byte has the lowest address. * #define Long int on machines with 32-bit ints and 64-bit longs. * #define IBM for IBM mainframe-style floating-point arithmetic. * #define VAX for VAX-style floating-point arithmetic (D_floating). * #define No_leftright to omit left-right logic in fast floating-point * computation of dtoa. * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 * and strtod and dtoa should round accordingly. * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 * and Honor_FLT_ROUNDS is not #defined. * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines * that use extended-precision instructions to compute rounded * products and quotients) with IBM. * #define ROUND_BIASED for IEEE-format with biased rounding. * #define Inaccurate_Divide for IEEE-format with correctly rounded * products but inaccurate quotients, e.g., for Intel i860. * #define NO_LONG_LONG on machines that do not have a "long long" * integer type (of >= 64 bits). On such machines, you can * #define Just_16 to store 16 bits per 32-bit Long when doing * high-precision integer arithmetic. Whether this speeds things * up or slows things down depends on the machine and the number * being converted. If long long is available and the name is * something other than "long long", #define Llong to be the name, * and if "unsigned Llong" does not work as an unsigned version of * Llong, #define #ULLong to be the corresponding unsigned type. * #define KR_headers for old-style C function headers. * #define Bad_float_h if your system lacks a float.h or if it does not * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) * if memory is available and otherwise does something you deem * appropriate. If MALLOC is undefined, malloc will be invoked * directly -- and assumed always to succeed. * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making * memory allocations from a private pool of memory when possible. * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, * unless #defined to be a different length. This default length * suffices to get rid of MALLOC calls except for unusual cases, * such as decimal-to-binary conversion of a very long string of * digits. The longest string dtoa can return is about 751 bytes * long. For conversions by strtod of strings of 800 digits and * all dtoa conversions in single-threaded executions with 8-byte * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte * pointers, PRIVATE_MEM >= 7112 appears adequate. * #define INFNAN_CHECK on IEEE systems to cause strtod to check for * Infinity and NaN (case insensitively). On some systems (e.g., * some HP systems), it may be necessary to #define NAN_WORD0 * appropriately -- to the most significant word of a quiet NaN. * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, * strtod also accepts (case insensitively) strings of the form * NaN(x), where x is a string of hexadecimal digits and spaces; * if there is only one string of hexadecimal digits, it is taken * for the 52 fraction bits of the resulting NaN; if there are two * or more strings of hex digits, the first is for the high 20 bits, * the second and subsequent for the low 32 bits, with intervening * white space ignored; but if this results in none of the 52 * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0 * and NAN_WORD1 are used instead. * #define MULTIPLE_THREADS if the system offers preemptively scheduled * multiple threads. In this case, you must provide (or suitably * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed * in pow5mult, ensures lazy evaluation of only one copy of high * powers of 5; omitting this lock would introduce a small * probability of wasting memory, but would otherwise be harmless.) * You must also invoke freedtoa(s) to free the value s returned by * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined. * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that * avoids underflows on inputs whose result does not underflow. * If you #define NO_IEEE_Scale on a machine that uses IEEE-format * floating-point numbers and flushes underflows to zero rather * than implementing gradual underflow, then you must also #define * Sudden_Underflow. * #define YES_ALIAS to permit aliasing certain double values with * arrays of ULongs. This leads to slightly better code with * some compilers and was always used prior to 19990916, but it * is not strictly legal and can cause trouble with aggressively * optimizing compilers (e.g., gcc 2.95.1 under -O2). * #define USE_LOCALE to use the current locale's decimal_point value. * #define SET_INEXACT if IEEE arithmetic is being used and extra * computation should be done to set the inexact flag when the * result is inexact and avoid setting inexact when the result * is exact. In this case, dtoa.c must be compiled in * an environment, perhaps provided by #include "dtoa.c" in a * suitable wrapper, that defines two functions, * int get_inexact(void); * void clear_inexact(void); * such that get_inexact() returns a nonzero value if the * inexact bit is already set, and clear_inexact() sets the * inexact bit to 0. When SET_INEXACT is #defined, strtod * also does extra computations to set the underflow and overflow * flags when appropriate (i.e., when the result is tiny and * inexact or when it is a numeric value rounded to +-infinity). * #define NO_ERRNO if strtod should not assign errno = ERANGE when * the result overflows to +-Infinity or underflows to 0. */ #ifdef WORDS_BIGENDIAN #define IEEE_BIG_ENDIAN #else #define IEEE_LITTLE_ENDIAN #endif #ifdef __vax__ #define VAX #undef IEEE_BIG_ENDIAN #undef IEEE_LITTLE_ENDIAN #endif #if defined(__arm__) && !defined(__VFP_FP__) #define IEEE_BIG_ENDIAN #undef IEEE_LITTLE_ENDIAN #endif #undef Long #undef ULong #if SIZEOF_INT == 4 #define Long int #define ULong unsigned int #elif SIZEOF_LONG == 4 #define Long long int #define ULong unsigned long int #endif #if HAVE_LONG_LONG #define Llong LONG_LONG #endif #ifdef DEBUG #include "stdio.h" #define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} #endif #include "stdlib.h" #include "string.h" #ifdef USE_LOCALE #include "locale.h" #endif #ifdef MALLOC extern void *MALLOC(size_t); #else #define MALLOC malloc #endif #ifndef Omit_Private_Memory #ifndef PRIVATE_MEM #define PRIVATE_MEM 2304 #endif #define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) static double private_mem[PRIVATE_mem], *pmem_next = private_mem; #endif #undef IEEE_Arith #undef Avoid_Underflow #ifdef IEEE_BIG_ENDIAN #define IEEE_Arith #endif #ifdef IEEE_LITTLE_ENDIAN #define IEEE_Arith #endif #include "errno.h" #ifdef Bad_float_h #ifdef IEEE_Arith #define DBL_DIG 15 #define DBL_MAX_10_EXP 308 #define DBL_MAX_EXP 1024 #define FLT_RADIX 2 #endif /*IEEE_Arith*/ #ifdef IBM #define DBL_DIG 16 #define DBL_MAX_10_EXP 75 #define DBL_MAX_EXP 63 #define FLT_RADIX 16 #define DBL_MAX 7.2370055773322621e+75 #endif #ifdef VAX #define DBL_DIG 16 #define DBL_MAX_10_EXP 38 #define DBL_MAX_EXP 127 #define FLT_RADIX 2 #define DBL_MAX 1.7014118346046923e+38 #endif #ifndef LONG_MAX #define LONG_MAX 2147483647 #endif #else /* ifndef Bad_float_h */ #include "float.h" #endif /* Bad_float_h */ #ifndef __MATH_H__ #include "math.h" #endif #ifdef __cplusplus extern "C" { #endif #if defined(IEEE_LITTLE_ENDIAN) + defined(IEEE_BIG_ENDIAN) + defined(VAX) + defined(IBM) != 1 Exactly one of IEEE_LITTLE_ENDIAN, IEEE_BIG_ENDIAN, VAX, or IBM should be defined. #endif typedef union { double d; ULong L[2]; } U; #ifdef YES_ALIAS typedef double double_u; # define dval(x) x # ifdef IEEE_LITTLE_ENDIAN # define word0(x) (((ULong *)&x)[1]) # define word1(x) (((ULong *)&x)[0]) # else # define word0(x) (((ULong *)&x)[0]) # define word1(x) (((ULong *)&x)[1]) # endif #else typedef U double_u; # ifdef IEEE_LITTLE_ENDIAN # define word0(x) (x.L[1]) # define word1(x) (x.L[0]) # else # define word0(x) (x.L[0]) # define word1(x) (x.L[1]) # endif # define dval(x) (x.d) #endif /* The following definition of Storeinc is appropriate for MIPS processors. * An alternative that might be better on some machines is * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) */ #if defined(IEEE_LITTLE_ENDIAN) + defined(VAX) + defined(__arm__) #define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ ((unsigned short *)a)[0] = (unsigned short)c, a++) #else #define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ ((unsigned short *)a)[1] = (unsigned short)c, a++) #endif /* #define P DBL_MANT_DIG */ /* Ten_pmax = floor(P*log(2)/log(5)) */ /* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ /* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ /* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ #ifdef IEEE_Arith #define Exp_shift 20 #define Exp_shift1 20 #define Exp_msk1 0x100000 #define Exp_msk11 0x100000 #define Exp_mask 0x7ff00000 #define P 53 #define Bias 1023 #define Emin (-1022) #define Exp_1 0x3ff00000 #define Exp_11 0x3ff00000 #define Ebits 11 #define Frac_mask 0xfffff #define Frac_mask1 0xfffff #define Ten_pmax 22 #define Bletch 0x10 #define Bndry_mask 0xfffff #define Bndry_mask1 0xfffff #define LSB 1 #define Sign_bit 0x80000000 #define Log2P 1 #define Tiny0 0 #define Tiny1 1 #define Quick_max 14 #define Int_max 14 #ifndef NO_IEEE_Scale #define Avoid_Underflow #ifdef Flush_Denorm /* debugging option */ #undef Sudden_Underflow #endif #endif #ifndef Flt_Rounds #ifdef FLT_ROUNDS #define Flt_Rounds FLT_ROUNDS #else #define Flt_Rounds 1 #endif #endif /*Flt_Rounds*/ #ifdef Honor_FLT_ROUNDS #define Rounding rounding #undef Check_FLT_ROUNDS #define Check_FLT_ROUNDS #else #define Rounding Flt_Rounds #endif #else /* ifndef IEEE_Arith */ #undef Check_FLT_ROUNDS #undef Honor_FLT_ROUNDS #undef SET_INEXACT #undef Sudden_Underflow #define Sudden_Underflow #ifdef IBM #undef Flt_Rounds #define Flt_Rounds 0 #define Exp_shift 24 #define Exp_shift1 24 #define Exp_msk1 0x1000000 #define Exp_msk11 0x1000000 #define Exp_mask 0x7f000000 #define P 14 #define Bias 65 #define Exp_1 0x41000000 #define Exp_11 0x41000000 #define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ #define Frac_mask 0xffffff #define Frac_mask1 0xffffff #define Bletch 4 #define Ten_pmax 22 #define Bndry_mask 0xefffff #define Bndry_mask1 0xffffff #define LSB 1 #define Sign_bit 0x80000000 #define Log2P 4 #define Tiny0 0x100000 #define Tiny1 0 #define Quick_max 14 #define Int_max 15 #else /* VAX */ #undef Flt_Rounds #define Flt_Rounds 1 #define Exp_shift 23 #define Exp_shift1 7 #define Exp_msk1 0x80 #define Exp_msk11 0x800000 #define Exp_mask 0x7f80 #define P 56 #define Bias 129 #define Exp_1 0x40800000 #define Exp_11 0x4080 #define Ebits 8 #define Frac_mask 0x7fffff #define Frac_mask1 0xffff007f #define Ten_pmax 24 #define Bletch 2 #define Bndry_mask 0xffff007f #define Bndry_mask1 0xffff007f #define LSB 0x10000 #define Sign_bit 0x8000 #define Log2P 1 #define Tiny0 0x80 #define Tiny1 0 #define Quick_max 15 #define Int_max 15 #endif /* IBM, VAX */ #endif /* IEEE_Arith */ #ifndef IEEE_Arith #define ROUND_BIASED #endif #ifdef RND_PRODQUOT #define rounded_product(a,b) a = rnd_prod(a, b) #define rounded_quotient(a,b) a = rnd_quot(a, b) extern double rnd_prod(double, double), rnd_quot(double, double); #else #define rounded_product(a,b) a *= b #define rounded_quotient(a,b) a /= b #endif #define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) #define Big1 0xffffffff #ifndef Pack_32 #define Pack_32 #endif #define FFFFFFFF 0xffffffffUL #ifdef NO_LONG_LONG #undef ULLong #ifdef Just_16 #undef Pack_32 /* When Pack_32 is not defined, we store 16 bits per 32-bit Long. * This makes some inner loops simpler and sometimes saves work * during multiplications, but it often seems to make things slightly * slower. Hence the default is now to store 32 bits per Long. */ #endif #else /* long long available */ #ifndef Llong #define Llong long long #endif #ifndef ULLong #define ULLong unsigned Llong #endif #endif /* NO_LONG_LONG */ #ifndef MULTIPLE_THREADS #define ACQUIRE_DTOA_LOCK(n) /*nothing*/ #define FREE_DTOA_LOCK(n) /*nothing*/ #endif #define Kmax 15 struct Bigint { struct Bigint *next; int k, maxwds, sign, wds; ULong x[1]; }; typedef struct Bigint Bigint; static Bigint *freelist[Kmax+1]; static Bigint * Balloc(int k) { int x; Bigint *rv; #ifndef Omit_Private_Memory unsigned int len; #endif ACQUIRE_DTOA_LOCK(0); if ((rv = freelist[k]) != 0) { freelist[k] = rv->next; } else { x = 1 << k; #ifdef Omit_Private_Memory rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); #else len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) /sizeof(double); if (pmem_next - private_mem + len <= PRIVATE_mem) { rv = (Bigint*)pmem_next; pmem_next += len; } else rv = (Bigint*)MALLOC(len*sizeof(double)); #endif rv->k = k; rv->maxwds = x; } FREE_DTOA_LOCK(0); rv->sign = rv->wds = 0; return rv; } static void Bfree(Bigint *v) { if (v) { ACQUIRE_DTOA_LOCK(0); v->next = freelist[v->k]; freelist[v->k] = v; FREE_DTOA_LOCK(0); } } #define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ y->wds*sizeof(Long) + 2*sizeof(int)) static Bigint * multadd(Bigint *b, int m, int a) /* multiply by m and add a */ { int i, wds; #ifdef ULLong ULong *x; ULLong carry, y; #else ULong carry, *x, y; #ifdef Pack_32 ULong xi, z; #endif #endif Bigint *b1; wds = b->wds; x = b->x; i = 0; carry = a; do { #ifdef ULLong y = *x * (ULLong)m + carry; carry = y >> 32; *x++ = y & FFFFFFFF; #else #ifdef Pack_32 xi = *x; y = (xi & 0xffff) * m + carry; z = (xi >> 16) * m + (y >> 16); carry = z >> 16; *x++ = (z << 16) + (y & 0xffff); #else y = *x * m + carry; carry = y >> 16; *x++ = y & 0xffff; #endif #endif } while (++i < wds); if (carry) { if (wds >= b->maxwds) { b1 = Balloc(b->k+1); Bcopy(b1, b); Bfree(b); b = b1; } b->x[wds++] = carry; b->wds = wds; } return b; } static Bigint * s2b(const char *s, int nd0, int nd, ULong y9) { Bigint *b; int i, k; Long x, y; x = (nd + 8) / 9; for (k = 0, y = 1; x > y; y <<= 1, k++) ; #ifdef Pack_32 b = Balloc(k); b->x[0] = y9; b->wds = 1; #else b = Balloc(k+1); b->x[0] = y9 & 0xffff; b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; #endif i = 9; if (9 < nd0) { s += 9; do { b = multadd(b, 10, *s++ - '0'); } while (++i < nd0); s++; } else s += 10; for (; i < nd; i++) b = multadd(b, 10, *s++ - '0'); return b; } static int hi0bits(register ULong x) { register int k = 0; if (!(x & 0xffff0000)) { k = 16; x <<= 16; } if (!(x & 0xff000000)) { k += 8; x <<= 8; } if (!(x & 0xf0000000)) { k += 4; x <<= 4; } if (!(x & 0xc0000000)) { k += 2; x <<= 2; } if (!(x & 0x80000000)) { k++; if (!(x & 0x40000000)) return 32; } return k; } static int lo0bits(ULong *y) { register int k; register ULong x = *y; if (x & 7) { if (x & 1) return 0; if (x & 2) { *y = x >> 1; return 1; } *y = x >> 2; return 2; } k = 0; if (!(x & 0xffff)) { k = 16; x >>= 16; } if (!(x & 0xff)) { k += 8; x >>= 8; } if (!(x & 0xf)) { k += 4; x >>= 4; } if (!(x & 0x3)) { k += 2; x >>= 2; } if (!(x & 1)) { k++; x >>= 1; if (!x) return 32; } *y = x; return k; } static Bigint * i2b(int i) { Bigint *b; b = Balloc(1); b->x[0] = i; b->wds = 1; return b; } static Bigint * mult(Bigint *a, Bigint *b) { Bigint *c; int k, wa, wb, wc; ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; ULong y; #ifdef ULLong ULLong carry, z; #else ULong carry, z; #ifdef Pack_32 ULong z2; #endif #endif if (a->wds < b->wds) { c = a; a = b; b = c; } k = a->k; wa = a->wds; wb = b->wds; wc = wa + wb; if (wc > a->maxwds) k++; c = Balloc(k); for (x = c->x, xa = x + wc; x < xa; x++) *x = 0; xa = a->x; xae = xa + wa; xb = b->x; xbe = xb + wb; xc0 = c->x; #ifdef ULLong for (; xb < xbe; xc0++) { if ((y = *xb++) != 0) { x = xa; xc = xc0; carry = 0; do { z = *x++ * (ULLong)y + *xc + carry; carry = z >> 32; *xc++ = z & FFFFFFFF; } while (x < xae); *xc = carry; } } #else #ifdef Pack_32 for (; xb < xbe; xb++, xc0++) { if (y = *xb & 0xffff) { x = xa; xc = xc0; carry = 0; do { z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; carry = z >> 16; z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; carry = z2 >> 16; Storeinc(xc, z2, z); } while (x < xae); *xc = carry; } if (y = *xb >> 16) { x = xa; xc = xc0; carry = 0; z2 = *xc; do { z = (*x & 0xffff) * y + (*xc >> 16) + carry; carry = z >> 16; Storeinc(xc, z, z2); z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; carry = z2 >> 16; } while (x < xae); *xc = z2; } } #else for (; xb < xbe; xc0++) { if (y = *xb++) { x = xa; xc = xc0; carry = 0; do { z = *x++ * y + *xc + carry; carry = z >> 16; *xc++ = z & 0xffff; } while (x < xae); *xc = carry; } } #endif #endif for (xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; c->wds = wc; return c; } static Bigint *p5s; static Bigint * pow5mult(Bigint *b, int k) { Bigint *b1, *p5, *p51; int i; static int p05[3] = { 5, 25, 125 }; if ((i = k & 3) != 0) b = multadd(b, p05[i-1], 0); if (!(k >>= 2)) return b; if (!(p5 = p5s)) { /* first time */ #ifdef MULTIPLE_THREADS ACQUIRE_DTOA_LOCK(1); if (!(p5 = p5s)) { p5 = p5s = i2b(625); p5->next = 0; } FREE_DTOA_LOCK(1); #else p5 = p5s = i2b(625); p5->next = 0; #endif } for (;;) { if (k & 1) { b1 = mult(b, p5); Bfree(b); b = b1; } if (!(k >>= 1)) break; if (!(p51 = p5->next)) { #ifdef MULTIPLE_THREADS ACQUIRE_DTOA_LOCK(1); if (!(p51 = p5->next)) { p51 = p5->next = mult(p5,p5); p51->next = 0; } FREE_DTOA_LOCK(1); #else p51 = p5->next = mult(p5,p5); p51->next = 0; #endif } p5 = p51; } return b; } static Bigint * lshift(Bigint *b, int k) { int i, k1, n, n1; Bigint *b1; ULong *x, *x1, *xe, z; #ifdef Pack_32 n = k >> 5; #else n = k >> 4; #endif k1 = b->k; n1 = n + b->wds + 1; for (i = b->maxwds; n1 > i; i <<= 1) k1++; b1 = Balloc(k1); x1 = b1->x; for (i = 0; i < n; i++) *x1++ = 0; x = b->x; xe = x + b->wds; #ifdef Pack_32 if (k &= 0x1f) { k1 = 32 - k; z = 0; do { *x1++ = *x << k | z; z = *x++ >> k1; } while (x < xe); if ((*x1 = z) != 0) ++n1; } #else if (k &= 0xf) { k1 = 16 - k; z = 0; do { *x1++ = *x << k & 0xffff | z; z = *x++ >> k1; } while (x < xe); if (*x1 = z) ++n1; } #endif else do { *x1++ = *x++; } while (x < xe); b1->wds = n1 - 1; Bfree(b); return b1; } static int cmp(Bigint *a, Bigint *b) { ULong *xa, *xa0, *xb, *xb0; int i, j; i = a->wds; j = b->wds; #ifdef DEBUG if (i > 1 && !a->x[i-1]) Bug("cmp called with a->x[a->wds-1] == 0"); if (j > 1 && !b->x[j-1]) Bug("cmp called with b->x[b->wds-1] == 0"); #endif if (i -= j) return i; xa0 = a->x; xa = xa0 + j; xb0 = b->x; xb = xb0 + j; for (;;) { if (*--xa != *--xb) return *xa < *xb ? -1 : 1; if (xa <= xa0) break; } return 0; } static Bigint * diff(Bigint *a, Bigint *b) { Bigint *c; int i, wa, wb; ULong *xa, *xae, *xb, *xbe, *xc; #ifdef ULLong ULLong borrow, y; #else ULong borrow, y; #ifdef Pack_32 ULong z; #endif #endif i = cmp(a,b); if (!i) { c = Balloc(0); c->wds = 1; c->x[0] = 0; return c; } if (i < 0) { c = a; a = b; b = c; i = 1; } else i = 0; c = Balloc(a->k); c->sign = i; wa = a->wds; xa = a->x; xae = xa + wa; wb = b->wds; xb = b->x; xbe = xb + wb; xc = c->x; borrow = 0; #ifdef ULLong do { y = (ULLong)*xa++ - *xb++ - borrow; borrow = y >> 32 & (ULong)1; *xc++ = y & FFFFFFFF; } while (xb < xbe); while (xa < xae) { y = *xa++ - borrow; borrow = y >> 32 & (ULong)1; *xc++ = y & FFFFFFFF; } #else #ifdef Pack_32 do { y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; borrow = (z & 0x10000) >> 16; Storeinc(xc, z, y); } while (xb < xbe); while (xa < xae) { y = (*xa & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; z = (*xa++ >> 16) - borrow; borrow = (z & 0x10000) >> 16; Storeinc(xc, z, y); } #else do { y = *xa++ - *xb++ - borrow; borrow = (y & 0x10000) >> 16; *xc++ = y & 0xffff; } while (xb < xbe); while (xa < xae) { y = *xa++ - borrow; borrow = (y & 0x10000) >> 16; *xc++ = y & 0xffff; } #endif #endif while (!*--xc) wa--; c->wds = wa; return c; } static double ulp(double x_) { register Long L; double_u x, a; dval(x) = x_; L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; #ifndef Avoid_Underflow #ifndef Sudden_Underflow if (L > 0) { #endif #endif #ifdef IBM L |= Exp_msk1 >> 4; #endif word0(a) = L; word1(a) = 0; #ifndef Avoid_Underflow #ifndef Sudden_Underflow } else { L = -L >> Exp_shift; if (L < Exp_shift) { word0(a) = 0x80000 >> L; word1(a) = 0; } else { word0(a) = 0; L -= Exp_shift; word1(a) = L >= 31 ? 1 : 1 << 31 - L; } } #endif #endif return dval(a); } static double b2d(Bigint *a, int *e) { ULong *xa, *xa0, w, y, z; int k; double_u d; #ifdef VAX ULong d0, d1; #else #define d0 word0(d) #define d1 word1(d) #endif xa0 = a->x; xa = xa0 + a->wds; y = *--xa; #ifdef DEBUG if (!y) Bug("zero y in b2d"); #endif k = hi0bits(y); *e = 32 - k; #ifdef Pack_32 if (k < Ebits) { d0 = Exp_1 | y >> (Ebits - k); w = xa > xa0 ? *--xa : 0; d1 = y << ((32-Ebits) + k) | w >> (Ebits - k); goto ret_d; } z = xa > xa0 ? *--xa : 0; if (k -= Ebits) { d0 = Exp_1 | y << k | z >> (32 - k); y = xa > xa0 ? *--xa : 0; d1 = z << k | y >> (32 - k); } else { d0 = Exp_1 | y; d1 = z; } #else if (k < Ebits + 16) { z = xa > xa0 ? *--xa : 0; d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; w = xa > xa0 ? *--xa : 0; y = xa > xa0 ? *--xa : 0; d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; goto ret_d; } z = xa > xa0 ? *--xa : 0; w = xa > xa0 ? *--xa : 0; k -= Ebits + 16; d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; y = xa > xa0 ? *--xa : 0; d1 = w << k + 16 | y << k; #endif ret_d: #ifdef VAX word0(d) = d0 >> 16 | d0 << 16; word1(d) = d1 >> 16 | d1 << 16; #else #undef d0 #undef d1 #endif return dval(d); } static Bigint * d2b(double d_, int *e, int *bits) { double_u d; Bigint *b; int de, k; ULong *x, y, z; #ifndef Sudden_Underflow int i; #endif #ifdef VAX ULong d0, d1; #endif dval(d) = d_; #ifdef VAX d0 = word0(d) >> 16 | word0(d) << 16; d1 = word1(d) >> 16 | word1(d) << 16; #else #define d0 word0(d) #define d1 word1(d) #endif #ifdef Pack_32 b = Balloc(1); #else b = Balloc(2); #endif x = b->x; z = d0 & Frac_mask; d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ #ifdef Sudden_Underflow de = (int)(d0 >> Exp_shift); #ifndef IBM z |= Exp_msk11; #endif #else if ((de = (int)(d0 >> Exp_shift)) != 0) z |= Exp_msk1; #endif #ifdef Pack_32 if ((y = d1) != 0) { if ((k = lo0bits(&y)) != 0) { x[0] = y | z << (32 - k); z >>= k; } else x[0] = y; #ifndef Sudden_Underflow i = #endif b->wds = (x[1] = z) ? 2 : 1; } else { #ifdef DEBUG if (!z) Bug("Zero passed to d2b"); #endif k = lo0bits(&z); x[0] = z; #ifndef Sudden_Underflow i = #endif b->wds = 1; k += 32; } #else if (y = d1) { if (k = lo0bits(&y)) if (k >= 16) { x[0] = y | z << 32 - k & 0xffff; x[1] = z >> k - 16 & 0xffff; x[2] = z >> k; i = 2; } else { x[0] = y & 0xffff; x[1] = y >> 16 | z << 16 - k & 0xffff; x[2] = z >> k & 0xffff; x[3] = z >> k+16; i = 3; } else { x[0] = y & 0xffff; x[1] = y >> 16; x[2] = z & 0xffff; x[3] = z >> 16; i = 3; } } else { #ifdef DEBUG if (!z) Bug("Zero passed to d2b"); #endif k = lo0bits(&z); if (k >= 16) { x[0] = z; i = 0; } else { x[0] = z & 0xffff; x[1] = z >> 16; i = 1; } k += 32; } while (!x[i]) --i; b->wds = i + 1; #endif #ifndef Sudden_Underflow if (de) { #endif #ifdef IBM *e = (de - Bias - (P-1) << 2) + k; *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask); #else *e = de - Bias - (P-1) + k; *bits = P - k; #endif #ifndef Sudden_Underflow } else { *e = de - Bias - (P-1) + 1 + k; #ifdef Pack_32 *bits = 32*i - hi0bits(x[i-1]); #else *bits = (i+2)*16 - hi0bits(x[i]); #endif } #endif return b; } #undef d0 #undef d1 static double ratio(Bigint *a, Bigint *b) { double_u da, db; int k, ka, kb; dval(da) = b2d(a, &ka); dval(db) = b2d(b, &kb); #ifdef Pack_32 k = ka - kb + 32*(a->wds - b->wds); #else k = ka - kb + 16*(a->wds - b->wds); #endif #ifdef IBM if (k > 0) { word0(da) += (k >> 2)*Exp_msk1; if (k &= 3) dval(da) *= 1 << k; } else { k = -k; word0(db) += (k >> 2)*Exp_msk1; if (k &= 3) dval(db) *= 1 << k; } #else if (k > 0) word0(da) += k*Exp_msk1; else { k = -k; word0(db) += k*Exp_msk1; } #endif return dval(da) / dval(db); } static const double tens[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22 #ifdef VAX , 1e23, 1e24 #endif }; static const double #ifdef IEEE_Arith bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, #ifdef Avoid_Underflow 9007199254740992.*9007199254740992.e-256 /* = 2^106 * 1e-53 */ #else 1e-256 #endif }; /* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ /* flag unnecessarily. It leads to a song and dance at the end of strtod. */ #define Scale_Bit 0x10 #define n_bigtens 5 #else #ifdef IBM bigtens[] = { 1e16, 1e32, 1e64 }; static const double tinytens[] = { 1e-16, 1e-32, 1e-64 }; #define n_bigtens 3 #else bigtens[] = { 1e16, 1e32 }; static const double tinytens[] = { 1e-16, 1e-32 }; #define n_bigtens 2 #endif #endif #ifndef IEEE_Arith #undef INFNAN_CHECK #endif #ifdef INFNAN_CHECK #ifndef NAN_WORD0 #define NAN_WORD0 0x7ff80000 #endif #ifndef NAN_WORD1 #define NAN_WORD1 0 #endif static int match(const char **sp, char *t) { int c, d; const char *s = *sp; while (d = *t++) { if ((c = *++s) >= 'A' && c <= 'Z') c += 'a' - 'A'; if (c != d) return 0; } *sp = s + 1; return 1; } #ifndef No_Hex_NaN static void hexnan(double *rvp, const char **sp) { ULong c, x[2]; const char *s; int havedig, udx0, xshift; x[0] = x[1] = 0; havedig = xshift = 0; udx0 = 1; s = *sp; while (c = *(const unsigned char*)++s) { if (c >= '0' && c <= '9') c -= '0'; else if (c >= 'a' && c <= 'f') c += 10 - 'a'; else if (c >= 'A' && c <= 'F') c += 10 - 'A'; else if (c <= ' ') { if (udx0 && havedig) { udx0 = 0; xshift = 1; } continue; } else if (/*(*/ c == ')' && havedig) { *sp = s + 1; break; } else return; /* invalid form: don't change *sp */ havedig = 1; if (xshift) { xshift = 0; x[0] = x[1]; x[1] = 0; } if (udx0) x[0] = (x[0] << 4) | (x[1] >> 28); x[1] = (x[1] << 4) | c; } if ((x[0] &= 0xfffff) || x[1]) { word0(*rvp) = Exp_mask | x[0]; word1(*rvp) = x[1]; } } #endif /*No_Hex_NaN*/ #endif /* INFNAN_CHECK */ double ruby_strtod(const char *s00, char **se) { #ifdef Avoid_Underflow int scale; #endif int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; const char *s, *s0, *s1; double aadj, adj; double_u aadj1, rv, rv0; Long L; ULong y, z; Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; #ifdef SET_INEXACT int inexact, oldinexact; #endif #ifdef Honor_FLT_ROUNDS int rounding; #endif #ifdef USE_LOCALE const char *s2; #endif errno = 0; sign = nz0 = nz = 0; dval(rv) = 0.; for (s = s00;;s++) switch (*s) { case '-': sign = 1; /* no break */ case '+': if (*++s) goto break2; /* no break */ case 0: goto ret0; case '\t': case '\n': case '\v': case '\f': case '\r': case ' ': continue; default: goto break2; } break2: if (*s == '0') { nz0 = 1; while (*++s == '0') ; if (!*s) goto ret; } s0 = s; y = z = 0; for (nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) if (nd < 9) y = 10*y + c - '0'; else if (nd < 16) z = 10*z + c - '0'; nd0 = nd; #ifdef USE_LOCALE s1 = localeconv()->decimal_point; if (c == *s1) { c = '.'; if (*++s1) { s2 = s; for (;;) { if (*++s2 != *s1) { c = 0; break; } if (!*++s1) { s = s2; break; } } } } #endif if (c == '.') { if (!ISDIGIT(s[1])) goto dig_done; c = *++s; if (!nd) { for (; c == '0'; c = *++s) nz++; if (c > '0' && c <= '9') { s0 = s; nf += nz; nz = 0; goto have_dig; } goto dig_done; } for (; c >= '0' && c <= '9'; c = *++s) { have_dig: nz++; if (c -= '0') { nf += nz; for (i = 1; i < nz; i++) if (nd++ < 9) y *= 10; else if (nd <= DBL_DIG + 1) z *= 10; if (nd++ < 9) y = 10*y + c; else if (nd <= DBL_DIG + 1) z = 10*z + c; nz = 0; } } } dig_done: e = 0; if (c == 'e' || c == 'E') { if (!nd && !nz && !nz0) { goto ret0; } s00 = s; esign = 0; switch (c = *++s) { case '-': esign = 1; case '+': c = *++s; } if (c >= '0' && c <= '9') { while (c == '0') c = *++s; if (c > '0' && c <= '9') { L = c - '0'; s1 = s; while ((c = *++s) >= '0' && c <= '9') L = 10*L + c - '0'; if (s - s1 > 8 || L > 19999) /* Avoid confusion from exponents * so large that e might overflow. */ e = 19999; /* safe for 16 bit ints */ else e = (int)L; if (esign) e = -e; } else e = 0; } else s = s00; } if (!nd) { if (!nz && !nz0) { #ifdef INFNAN_CHECK /* Check for Nan and Infinity */ switch (c) { case 'i': case 'I': if (match(&s,"nf")) { --s; if (!match(&s,"inity")) ++s; word0(rv) = 0x7ff00000; word1(rv) = 0; goto ret; } break; case 'n': case 'N': if (match(&s, "an")) { word0(rv) = NAN_WORD0; word1(rv) = NAN_WORD1; #ifndef No_Hex_NaN if (*s == '(') /*)*/ hexnan(&rv, &s); #endif goto ret; } } #endif /* INFNAN_CHECK */ ret0: s = s00; sign = 0; } goto ret; } e1 = e -= nf; /* Now we have nd0 digits, starting at s0, followed by a * decimal point, followed by nd-nd0 digits. The number we're * after is the integer represented by those digits times * 10**e */ if (!nd0) nd0 = nd; k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; dval(rv) = y; if (k > 9) { #ifdef SET_INEXACT if (k > DBL_DIG) oldinexact = get_inexact(); #endif dval(rv) = tens[k - 9] * dval(rv) + z; } bd0 = bb = bd = bs = delta = 0; if (nd <= DBL_DIG #ifndef RND_PRODQUOT #ifndef Honor_FLT_ROUNDS && Flt_Rounds == 1 #endif #endif ) { if (!e) goto ret; if (e > 0) { if (e <= Ten_pmax) { #ifdef VAX goto vax_ovfl_check; #else #ifdef Honor_FLT_ROUNDS /* round correctly FLT_ROUNDS = 2 or 3 */ if (sign) { rv = -rv; sign = 0; } #endif /* rv = */ rounded_product(dval(rv), tens[e]); goto ret; #endif } i = DBL_DIG - nd; if (e <= Ten_pmax + i) { /* A fancier test would sometimes let us do * this for larger i values. */ #ifdef Honor_FLT_ROUNDS /* round correctly FLT_ROUNDS = 2 or 3 */ if (sign) { rv = -rv; sign = 0; } #endif e -= i; dval(rv) *= tens[i]; #ifdef VAX /* VAX exponent range is so narrow we must * worry about overflow here... */ vax_ovfl_check: word0(rv) -= P*Exp_msk1; /* rv = */ rounded_product(dval(rv), tens[e]); if ((word0(rv) & Exp_mask) > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) goto ovfl; word0(rv) += P*Exp_msk1; #else /* rv = */ rounded_product(dval(rv), tens[e]); #endif goto ret; } } #ifndef Inaccurate_Divide else if (e >= -Ten_pmax) { #ifdef Honor_FLT_ROUNDS /* round correctly FLT_ROUNDS = 2 or 3 */ if (sign) { rv = -rv; sign = 0; } #endif /* rv = */ rounded_quotient(dval(rv), tens[-e]); goto ret; } #endif } e1 += nd - k; #ifdef IEEE_Arith #ifdef SET_INEXACT inexact = 1; if (k <= DBL_DIG) oldinexact = get_inexact(); #endif #ifdef Avoid_Underflow scale = 0; #endif #ifdef Honor_FLT_ROUNDS if ((rounding = Flt_Rounds) >= 2) { if (sign) rounding = rounding == 2 ? 0 : 2; else if (rounding != 2) rounding = 0; } #endif #endif /*IEEE_Arith*/ /* Get starting approximation = rv * 10**e1 */ if (e1 > 0) { if ((i = e1 & 15) != 0) dval(rv) *= tens[i]; if (e1 &= ~15) { if (e1 > DBL_MAX_10_EXP) { ovfl: #ifndef NO_ERRNO errno = ERANGE; #endif /* Can't trust HUGE_VAL */ #ifdef IEEE_Arith #ifdef Honor_FLT_ROUNDS switch (rounding) { case 0: /* toward 0 */ case 3: /* toward -infinity */ word0(rv) = Big0; word1(rv) = Big1; break; default: word0(rv) = Exp_mask; word1(rv) = 0; } #else /*Honor_FLT_ROUNDS*/ word0(rv) = Exp_mask; word1(rv) = 0; #endif /*Honor_FLT_ROUNDS*/ #ifdef SET_INEXACT /* set overflow bit */ dval(rv0) = 1e300; dval(rv0) *= dval(rv0); #endif #else /*IEEE_Arith*/ word0(rv) = Big0; word1(rv) = Big1; #endif /*IEEE_Arith*/ if (bd0) goto retfree; goto ret; } e1 >>= 4; for (j = 0; e1 > 1; j++, e1 >>= 1) if (e1 & 1) dval(rv) *= bigtens[j]; /* The last multiplication could overflow. */ word0(rv) -= P*Exp_msk1; dval(rv) *= bigtens[j]; if ((z = word0(rv) & Exp_mask) > Exp_msk1*(DBL_MAX_EXP+Bias-P)) goto ovfl; if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { /* set to largest number */ /* (Can't trust DBL_MAX) */ word0(rv) = Big0; word1(rv) = Big1; } else word0(rv) += P*Exp_msk1; } } else if (e1 < 0) { e1 = -e1; if ((i = e1 & 15) != 0) dval(rv) /= tens[i]; if (e1 >>= 4) { if (e1 >= 1 << n_bigtens) goto undfl; #ifdef Avoid_Underflow if (e1 & Scale_Bit) scale = 2*P; for (j = 0; e1 > 0; j++, e1 >>= 1) if (e1 & 1) dval(rv) *= tinytens[j]; if (scale && (j = 2*P + 1 - ((word0(rv) & Exp_mask) >> Exp_shift)) > 0) { /* scaled rv is denormal; zap j low bits */ if (j >= 32) { word1(rv) = 0; if (j >= 53) word0(rv) = (P+2)*Exp_msk1; else word0(rv) &= 0xffffffff << (j-32); } else word1(rv) &= 0xffffffff << j; } #else for (j = 0; e1 > 1; j++, e1 >>= 1) if (e1 & 1) dval(rv) *= tinytens[j]; /* The last multiplication could underflow. */ dval(rv0) = dval(rv); dval(rv) *= tinytens[j]; if (!dval(rv)) { dval(rv) = 2.*dval(rv0); dval(rv) *= tinytens[j]; #endif if (!dval(rv)) { undfl: dval(rv) = 0.; #ifndef NO_ERRNO errno = ERANGE; #endif if (bd0) goto retfree; goto ret; } #ifndef Avoid_Underflow word0(rv) = Tiny0; word1(rv) = Tiny1; /* The refinement below will clean * this approximation up. */ } #endif } } /* Now the hard part -- adjusting rv to the correct value.*/ /* Put digits into bd: true value = bd * 10^e */ bd0 = s2b(s0, nd0, nd, y); for (;;) { bd = Balloc(bd0->k); Bcopy(bd, bd0); bb = d2b(dval(rv), &bbe, &bbbits); /* rv = bb * 2^bbe */ bs = i2b(1); if (e >= 0) { bb2 = bb5 = 0; bd2 = bd5 = e; } else { bb2 = bb5 = -e; bd2 = bd5 = 0; } if (bbe >= 0) bb2 += bbe; else bd2 -= bbe; bs2 = bb2; #ifdef Honor_FLT_ROUNDS if (rounding != 1) bs2++; #endif #ifdef Avoid_Underflow j = bbe - scale; i = j + bbbits - 1; /* logb(rv) */ if (i < Emin) /* denormal */ j += P - Emin; else j = P + 1 - bbbits; #else /*Avoid_Underflow*/ #ifdef Sudden_Underflow #ifdef IBM j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); #else j = P + 1 - bbbits; #endif #else /*Sudden_Underflow*/ j = bbe; i = j + bbbits - 1; /* logb(rv) */ if (i < Emin) /* denormal */ j += P - Emin; else j = P + 1 - bbbits; #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow*/ bb2 += j; bd2 += j; #ifdef Avoid_Underflow bd2 += scale; #endif i = bb2 < bd2 ? bb2 : bd2; if (i > bs2) i = bs2; if (i > 0) { bb2 -= i; bd2 -= i; bs2 -= i; } if (bb5 > 0) { bs = pow5mult(bs, bb5); bb1 = mult(bs, bb); Bfree(bb); bb = bb1; } if (bb2 > 0) bb = lshift(bb, bb2); if (bd5 > 0) bd = pow5mult(bd, bd5); if (bd2 > 0) bd = lshift(bd, bd2); if (bs2 > 0) bs = lshift(bs, bs2); delta = diff(bb, bd); dsign = delta->sign; delta->sign = 0; i = cmp(delta, bs); #ifdef Honor_FLT_ROUNDS if (rounding != 1) { if (i < 0) { /* Error is less than an ulp */ if (!delta->x[0] && delta->wds <= 1) { /* exact */ #ifdef SET_INEXACT inexact = 0; #endif break; } if (rounding) { if (dsign) { adj = 1.; goto apply_adj; } } else if (!dsign) { adj = -1.; if (!word1(rv) && !(word0(rv) & Frac_mask)) { y = word0(rv) & Exp_mask; #ifdef Avoid_Underflow if (!scale || y > 2*P*Exp_msk1) #else if (y) #endif { delta = lshift(delta,Log2P); if (cmp(delta, bs) <= 0) adj = -0.5; } } apply_adj: #ifdef Avoid_Underflow if (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) word0(adj) += (2*P+1)*Exp_msk1 - y; #else #ifdef Sudden_Underflow if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { word0(rv) += P*Exp_msk1; dval(rv) += adj*ulp(dval(rv)); word0(rv) -= P*Exp_msk1; } else #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow*/ dval(rv) += adj*ulp(dval(rv)); } break; } adj = ratio(delta, bs); if (adj < 1.) adj = 1.; if (adj <= 0x7ffffffe) { /* adj = rounding ? ceil(adj) : floor(adj); */ y = adj; if (y != adj) { if (!((rounding>>1) ^ dsign)) y++; adj = y; } } #ifdef Avoid_Underflow if (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) word0(adj) += (2*P+1)*Exp_msk1 - y; #else #ifdef Sudden_Underflow if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { word0(rv) += P*Exp_msk1; adj *= ulp(dval(rv)); if (dsign) dval(rv) += adj; else dval(rv) -= adj; word0(rv) -= P*Exp_msk1; goto cont; } #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow*/ adj *= ulp(dval(rv)); if (dsign) dval(rv) += adj; else dval(rv) -= adj; goto cont; } #endif /*Honor_FLT_ROUNDS*/ if (i < 0) { /* Error is less than half an ulp -- check for * special case of mantissa a power of two. */ if (dsign || word1(rv) || word0(rv) & Bndry_mask #ifdef IEEE_Arith #ifdef Avoid_Underflow || (word0(rv) & Exp_mask) <= (2*P+1)*Exp_msk1 #else || (word0(rv) & Exp_mask) <= Exp_msk1 #endif #endif ) { #ifdef SET_INEXACT if (!delta->x[0] && delta->wds <= 1) inexact = 0; #endif break; } if (!delta->x[0] && delta->wds <= 1) { /* exact result */ #ifdef SET_INEXACT inexact = 0; #endif break; } delta = lshift(delta,Log2P); if (cmp(delta, bs) > 0) goto drop_down; break; } if (i == 0) { /* exactly half-way between */ if (dsign) { if ((word0(rv) & Bndry_mask1) == Bndry_mask1 && word1(rv) == ( #ifdef Avoid_Underflow (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : #endif 0xffffffff)) { /*boundary case -- increment exponent*/ word0(rv) = (word0(rv) & Exp_mask) + Exp_msk1 #ifdef IBM | Exp_msk1 >> 4 #endif ; word1(rv) = 0; #ifdef Avoid_Underflow dsign = 0; #endif break; } } else if (!(word0(rv) & Bndry_mask) && !word1(rv)) { drop_down: /* boundary case -- decrement exponent */ #ifdef Sudden_Underflow /*{{*/ L = word0(rv) & Exp_mask; #ifdef IBM if (L < Exp_msk1) #else #ifdef Avoid_Underflow if (L <= (scale ? (2*P+1)*Exp_msk1 : Exp_msk1)) #else if (L <= Exp_msk1) #endif /*Avoid_Underflow*/ #endif /*IBM*/ goto undfl; L -= Exp_msk1; #else /*Sudden_Underflow}{*/ #ifdef Avoid_Underflow if (scale) { L = word0(rv) & Exp_mask; if (L <= (2*P+1)*Exp_msk1) { if (L > (P+2)*Exp_msk1) /* round even ==> */ /* accept rv */ break; /* rv = smallest denormal */ goto undfl; } } #endif /*Avoid_Underflow*/ L = (word0(rv) & Exp_mask) - Exp_msk1; #endif /*Sudden_Underflow}}*/ word0(rv) = L | Bndry_mask1; word1(rv) = 0xffffffff; #ifdef IBM goto cont; #else break; #endif } #ifndef ROUND_BIASED if (!(word1(rv) & LSB)) break; #endif if (dsign) dval(rv) += ulp(dval(rv)); #ifndef ROUND_BIASED else { dval(rv) -= ulp(dval(rv)); #ifndef Sudden_Underflow if (!dval(rv)) goto undfl; #endif } #ifdef Avoid_Underflow dsign = 1 - dsign; #endif #endif break; } if ((aadj = ratio(delta, bs)) <= 2.) { if (dsign) aadj = dval(aadj1) = 1.; else if (word1(rv) || word0(rv) & Bndry_mask) { #ifndef Sudden_Underflow if (word1(rv) == Tiny1 && !word0(rv)) goto undfl; #endif aadj = 1.; dval(aadj1) = -1.; } else { /* special case -- power of FLT_RADIX to be */ /* rounded down... */ if (aadj < 2./FLT_RADIX) aadj = 1./FLT_RADIX; else aadj *= 0.5; dval(aadj1) = -aadj; } } else { aadj *= 0.5; dval(aadj1) = dsign ? aadj : -aadj; #ifdef Check_FLT_ROUNDS switch (Rounding) { case 2: /* towards +infinity */ aadj1 -= 0.5; break; case 0: /* towards 0 */ case 3: /* towards -infinity */ aadj1 += 0.5; } #else if (Flt_Rounds == 0) dval(aadj1) += 0.5; #endif /*Check_FLT_ROUNDS*/ } y = word0(rv) & Exp_mask; /* Check for overflow */ if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { dval(rv0) = dval(rv); word0(rv) -= P*Exp_msk1; adj = dval(aadj1) * ulp(dval(rv)); dval(rv) += adj; if ((word0(rv) & Exp_mask) >= Exp_msk1*(DBL_MAX_EXP+Bias-P)) { if (word0(rv0) == Big0 && word1(rv0) == Big1) goto ovfl; word0(rv) = Big0; word1(rv) = Big1; goto cont; } else word0(rv) += P*Exp_msk1; } else { #ifdef Avoid_Underflow if (scale && y <= 2*P*Exp_msk1) { if (aadj <= 0x7fffffff) { if ((z = aadj) <= 0) z = 1; aadj = z; dval(aadj1) = dsign ? aadj : -aadj; } word0(aadj1) += (2*P+1)*Exp_msk1 - y; } adj = dval(aadj1) * ulp(dval(rv)); dval(rv) += adj; #else #ifdef Sudden_Underflow if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { dval(rv0) = dval(rv); word0(rv) += P*Exp_msk1; adj = aadj1 * ulp(dval(rv)); dval(rv) += adj; #ifdef IBM if ((word0(rv) & Exp_mask) < P*Exp_msk1) #else if ((word0(rv) & Exp_mask) <= P*Exp_msk1) #endif { if (word0(rv0) == Tiny0 && word1(rv0) == Tiny1) goto undfl; word0(rv) = Tiny0; word1(rv) = Tiny1; goto cont; } else word0(rv) -= P*Exp_msk1; } else { adj = aadj1 * ulp(dval(rv)); dval(rv) += adj; } #else /*Sudden_Underflow*/ /* Compute adj so that the IEEE rounding rules will * correctly round rv + adj in some half-way cases. * If rv * ulp(rv) is denormalized (i.e., * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid * trouble from bits lost to denormalization; * example: 1.2e-307 . */ if (y <= (P-1)*Exp_msk1 && aadj > 1.) { aadj1 = (double)(int)(aadj + 0.5); if (!dsign) aadj1 = -aadj1; } adj = aadj1 * ulp(dval(rv)); dval(rv) += adj; #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow*/ } z = word0(rv) & Exp_mask; #ifndef SET_INEXACT #ifdef Avoid_Underflow if (!scale) #endif if (y == z) { /* Can we stop now? */ L = (Long)aadj; aadj -= L; /* The tolerances below are conservative. */ if (dsign || word1(rv) || word0(rv) & Bndry_mask) { if (aadj < .4999999 || aadj > .5000001) break; } else if (aadj < .4999999/FLT_RADIX) break; } #endif cont: Bfree(bb); Bfree(bd); Bfree(bs); Bfree(delta); } #ifdef SET_INEXACT if (inexact) { if (!oldinexact) { word0(rv0) = Exp_1 + (70 << Exp_shift); word1(rv0) = 0; dval(rv0) += 1.; } } else if (!oldinexact) clear_inexact(); #endif #ifdef Avoid_Underflow if (scale) { word0(rv0) = Exp_1 - 2*P*Exp_msk1; word1(rv0) = 0; dval(rv) *= dval(rv0); #ifndef NO_ERRNO /* try to avoid the bug of testing an 8087 register value */ if (word0(rv) == 0 && word1(rv) == 0) errno = ERANGE; #endif } #endif /* Avoid_Underflow */ #ifdef SET_INEXACT if (inexact && !(word0(rv) & Exp_mask)) { /* set underflow bit */ dval(rv0) = 1e-300; dval(rv0) *= dval(rv0); } #endif retfree: Bfree(bb); Bfree(bd); Bfree(bs); Bfree(bd0); Bfree(delta); ret: if (se) *se = (char *)s; return sign ? -dval(rv) : dval(rv); } static int quorem(Bigint *b, Bigint *S) { int n; ULong *bx, *bxe, q, *sx, *sxe; #ifdef ULLong ULLong borrow, carry, y, ys; #else ULong borrow, carry, y, ys; #ifdef Pack_32 ULong si, z, zs; #endif #endif n = S->wds; #ifdef DEBUG /*debug*/ if (b->wds > n) /*debug*/ Bug("oversize b in quorem"); #endif if (b->wds < n) return 0; sx = S->x; sxe = sx + --n; bx = b->x; bxe = bx + n; q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ #ifdef DEBUG /*debug*/ if (q > 9) /*debug*/ Bug("oversized quotient in quorem"); #endif if (q) { borrow = 0; carry = 0; do { #ifdef ULLong ys = *sx++ * (ULLong)q + carry; carry = ys >> 32; y = *bx - (ys & FFFFFFFF) - borrow; borrow = y >> 32 & (ULong)1; *bx++ = y & FFFFFFFF; #else #ifdef Pack_32 si = *sx++; ys = (si & 0xffff) * q + carry; zs = (si >> 16) * q + (ys >> 16); carry = zs >> 16; y = (*bx & 0xffff) - (ys & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; z = (*bx >> 16) - (zs & 0xffff) - borrow; borrow = (z & 0x10000) >> 16; Storeinc(bx, z, y); #else ys = *sx++ * q + carry; carry = ys >> 16; y = *bx - (ys & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; *bx++ = y & 0xffff; #endif #endif } while (sx <= sxe); if (!*bxe) { bx = b->x; while (--bxe > bx && !*bxe) --n; b->wds = n; } } if (cmp(b, S) >= 0) { q++; borrow = 0; carry = 0; bx = b->x; sx = S->x; do { #ifdef ULLong ys = *sx++ + carry; carry = ys >> 32; y = *bx - (ys & FFFFFFFF) - borrow; borrow = y >> 32 & (ULong)1; *bx++ = y & FFFFFFFF; #else #ifdef Pack_32 si = *sx++; ys = (si & 0xffff) + carry; zs = (si >> 16) + (ys >> 16); carry = zs >> 16; y = (*bx & 0xffff) - (ys & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; z = (*bx >> 16) - (zs & 0xffff) - borrow; borrow = (z & 0x10000) >> 16; Storeinc(bx, z, y); #else ys = *sx++ + carry; carry = ys >> 16; y = *bx - (ys & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; *bx++ = y & 0xffff; #endif #endif } while (sx <= sxe); bx = b->x; bxe = bx + n; if (!*bxe) { while (--bxe > bx && !*bxe) --n; b->wds = n; } } return q; } #ifndef MULTIPLE_THREADS static char *dtoa_result; #endif static char * rv_alloc(int i) { int j, k, *r; j = sizeof(ULong); for (k = 0; sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i; j <<= 1) k++; r = (int*)Balloc(k); *r = k; return #ifndef MULTIPLE_THREADS dtoa_result = #endif (char *)(r+1); } static char * nrv_alloc(const char *s, char **rve, int n) { char *rv, *t; t = rv = rv_alloc(n+1); while ((*t = *s++) != 0) t++; if (rve) *rve = t; return rv; } #define rv_strdup(s, rve) nrv_alloc(s, rve, strlen(s)+1) /* freedtoa(s) must be used to free values s returned by dtoa * when MULTIPLE_THREADS is #defined. It should be used in all cases, * but for consistency with earlier versions of dtoa, it is optional * when MULTIPLE_THREADS is not defined. */ void freedtoa(char *s) { Bigint *b = (Bigint *)((int *)s - 1); b->maxwds = 1 << (b->k = *(int*)b); Bfree(b); #ifndef MULTIPLE_THREADS if (s == dtoa_result) dtoa_result = 0; #endif } /* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. * * Inspired by "How to Print Floating-Point Numbers Accurately" by * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. * * Modifications: * 1. Rather than iterating, we use a simple numeric overestimate * to determine k = floor(log10(d)). We scale relevant * quantities using O(log2(k)) rather than O(k) multiplications. * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't * try to generate digits strictly left to right. Instead, we * compute with fewer bits and propagate the carry if necessary * when rounding the final digit up. This is often faster. * 3. Under the assumption that input will be rounded nearest, * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. * That is, we allow equality in stopping tests when the * round-nearest rule will give the same floating-point value * as would satisfaction of the stopping test with strict * inequality. * 4. We remove common factors of powers of 2 from relevant * quantities. * 5. When converting floating-point integers less than 1e16, * we use floating-point arithmetic rather than resorting * to multiple-precision integers. * 6. When asked to produce fewer than 15 digits, we first try * to get by with floating-point arithmetic; we resort to * multiple-precision integer arithmetic only if we cannot * guarantee that the floating-point calculation has given * the correctly rounded result. For k requested digits and * "uniformly" distributed input, the probability is * something like 10^(k-15) that we must resort to the Long * calculation. */ char * dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve) { /* Arguments ndigits, decpt, sign are similar to those of ecvt and fcvt; trailing zeros are suppressed from the returned string. If not null, *rve is set to point to the end of the return value. If d is +-Infinity or NaN, then *decpt is set to 9999. mode: 0 ==> shortest string that yields d when read in and rounded to nearest. 1 ==> like 0, but with Steele & White stopping rule; e.g. with IEEE P754 arithmetic , mode 0 gives 1e23 whereas mode 1 gives 9.999999999999999e22. 2 ==> max(1,ndigits) significant digits. This gives a return value similar to that of ecvt, except that trailing zeros are suppressed. 3 ==> through ndigits past the decimal point. This gives a return value similar to that from fcvt, except that trailing zeros are suppressed, and ndigits can be negative. 4,5 ==> similar to 2 and 3, respectively, but (in round-nearest mode) with the tests of mode 0 to possibly return a shorter string that rounds to d. With IEEE arithmetic and compilation with -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same as modes 2 and 3 when FLT_ROUNDS != 1. 6-9 ==> Debugging modes similar to mode - 4: don't try fast floating-point estimate (if applicable). Values of mode other than 0-9 are treated as mode 0. Sufficient space is allocated to the return value to hold the suppressed trailing zeros. */ int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, spec_case, try_quick; Long L; #ifndef Sudden_Underflow int denorm; ULong x; #endif Bigint *b, *b1, *delta, *mlo = 0, *mhi = 0, *S; double ds; double_u d, d2, eps; char *s, *s0; #ifdef Honor_FLT_ROUNDS int rounding; #endif #ifdef SET_INEXACT int inexact, oldinexact; #endif dval(d) = d_; #ifndef MULTIPLE_THREADS if (dtoa_result) { freedtoa(dtoa_result); dtoa_result = 0; } #endif if (word0(d) & Sign_bit) { /* set sign for everything, including 0's and NaNs */ *sign = 1; word0(d) &= ~Sign_bit; /* clear sign bit */ } else *sign = 0; #if defined(IEEE_Arith) + defined(VAX) #ifdef IEEE_Arith if ((word0(d) & Exp_mask) == Exp_mask) #else if (word0(d) == 0x8000) #endif { /* Infinity or NaN */ *decpt = 9999; #ifdef IEEE_Arith if (!word1(d) && !(word0(d) & 0xfffff)) return rv_strdup("Infinity", rve); #endif return rv_strdup("NaN", rve); } #endif #ifdef IBM dval(d) += 0; /* normalize */ #endif if (!dval(d)) { *decpt = 1; return rv_strdup("0", rve); } #ifdef SET_INEXACT try_quick = oldinexact = get_inexact(); inexact = 1; #endif #ifdef Honor_FLT_ROUNDS if ((rounding = Flt_Rounds) >= 2) { if (*sign) rounding = rounding == 2 ? 0 : 2; else if (rounding != 2) rounding = 0; } #endif b = d2b(dval(d), &be, &bbits); #ifdef Sudden_Underflow i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); #else if ((i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) != 0) { #endif dval(d2) = dval(d); word0(d2) &= Frac_mask1; word0(d2) |= Exp_11; #ifdef IBM if (j = 11 - hi0bits(word0(d2) & Frac_mask)) dval(d2) /= 1 << j; #endif /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 * log10(x) = log(x) / log(10) * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) * * This suggests computing an approximation k to log10(d) by * * k = (i - Bias)*0.301029995663981 * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); * * We want k to be too large rather than too small. * The error in the first-order Taylor series approximation * is in our favor, so we just round up the constant enough * to compensate for any error in the multiplication of * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, * adding 1e-13 to the constant term more than suffices. * Hence we adjust the constant term to 0.1760912590558. * (We could get a more accurate k by invoking log10, * but this is probably not worthwhile.) */ i -= Bias; #ifdef IBM i <<= 2; i += j; #endif #ifndef Sudden_Underflow denorm = 0; } else { /* d is denormalized */ i = bbits + be + (Bias + (P-1) - 1); x = i > 32 ? word0(d) << (64 - i) | word1(d) >> (i - 32) : word1(d) << (32 - i); dval(d2) = x; word0(d2) -= 31*Exp_msk1; /* adjust exponent */ i -= (Bias + (P-1) - 1) + 1; denorm = 1; } #endif ds = (dval(d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; k = (int)ds; if (ds < 0. && ds != k) k--; /* want k = floor(ds) */ k_check = 1; if (k >= 0 && k <= Ten_pmax) { if (dval(d) < tens[k]) k--; k_check = 0; } j = bbits - i - 1; if (j >= 0) { b2 = 0; s2 = j; } else { b2 = -j; s2 = 0; } if (k >= 0) { b5 = 0; s5 = k; s2 += k; } else { b2 -= k; b5 = -k; s5 = 0; } if (mode < 0 || mode > 9) mode = 0; #ifndef SET_INEXACT #ifdef Check_FLT_ROUNDS try_quick = Rounding == 1; #else try_quick = 1; #endif #endif /*SET_INEXACT*/ if (mode > 5) { mode -= 4; try_quick = 0; } leftright = 1; ilim = ilim1 = -1; switch (mode) { case 0: case 1: i = 18; ndigits = 0; break; case 2: leftright = 0; /* no break */ case 4: if (ndigits <= 0) ndigits = 1; ilim = ilim1 = i = ndigits; break; case 3: leftright = 0; /* no break */ case 5: i = ndigits + k + 1; ilim = i; ilim1 = i - 1; if (i <= 0) i = 1; } s = s0 = rv_alloc(i+1); #ifdef Honor_FLT_ROUNDS if (mode > 1 && rounding != 1) leftright = 0; #endif if (ilim >= 0 && ilim <= Quick_max && try_quick) { /* Try to get by with floating-point arithmetic. */ i = 0; dval(d2) = dval(d); k0 = k; ilim0 = ilim; ieps = 2; /* conservative */ if (k > 0) { ds = tens[k&0xf]; j = k >> 4; if (j & Bletch) { /* prevent overflows */ j &= Bletch - 1; dval(d) /= bigtens[n_bigtens-1]; ieps++; } for (; j; j >>= 1, i++) if (j & 1) { ieps++; ds *= bigtens[i]; } dval(d) /= ds; } else if ((j1 = -k) != 0) { dval(d) *= tens[j1 & 0xf]; for (j = j1 >> 4; j; j >>= 1, i++) if (j & 1) { ieps++; dval(d) *= bigtens[i]; } } if (k_check && dval(d) < 1. && ilim > 0) { if (ilim1 <= 0) goto fast_failed; ilim = ilim1; k--; dval(d) *= 10.; ieps++; } dval(eps) = ieps*dval(d) + 7.; word0(eps) -= (P-1)*Exp_msk1; if (ilim == 0) { S = mhi = 0; dval(d) -= 5.; if (dval(d) > dval(eps)) goto one_digit; if (dval(d) < -dval(eps)) goto no_digits; goto fast_failed; } #ifndef No_leftright if (leftright) { /* Use Steele & White method of only * generating digits needed. */ dval(eps) = 0.5/tens[ilim-1] - dval(eps); for (i = 0;;) { L = dval(d); dval(d) -= L; *s++ = '0' + (int)L; if (dval(d) < dval(eps)) goto ret1; if (1. - dval(d) < dval(eps)) goto bump_up; if (++i >= ilim) break; dval(eps) *= 10.; dval(d) *= 10.; } } else { #endif /* Generate ilim digits, then fix them up. */ dval(eps) *= tens[ilim-1]; for (i = 1;; i++, dval(d) *= 10.) { L = (Long)(dval(d)); if (!(dval(d) -= L)) ilim = i; *s++ = '0' + (int)L; if (i == ilim) { if (dval(d) > 0.5 + dval(eps)) goto bump_up; else if (dval(d) < 0.5 - dval(eps)) { while (*--s == '0') ; s++; goto ret1; } break; } } #ifndef No_leftright } #endif fast_failed: s = s0; dval(d) = dval(d2); k = k0; ilim = ilim0; } /* Do we have a "small" integer? */ if (be >= 0 && k <= Int_max) { /* Yes. */ ds = tens[k]; if (ndigits < 0 && ilim <= 0) { S = mhi = 0; if (ilim < 0 || dval(d) <= 5*ds) goto no_digits; goto one_digit; } for (i = 1;; i++, dval(d) *= 10.) { L = (Long)(dval(d) / ds); dval(d) -= L*ds; #ifdef Check_FLT_ROUNDS /* If FLT_ROUNDS == 2, L will usually be high by 1 */ if (dval(d) < 0) { L--; dval(d) += ds; } #endif *s++ = '0' + (int)L; if (!dval(d)) { #ifdef SET_INEXACT inexact = 0; #endif break; } if (i == ilim) { #ifdef Honor_FLT_ROUNDS if (mode > 1) switch (rounding) { case 0: goto ret1; case 2: goto bump_up; } #endif dval(d) += dval(d); if (dval(d) > ds || (dval(d) == ds && (L & 1))) { bump_up: while (*--s == '9') if (s == s0) { k++; *s = '0'; break; } ++*s++; } break; } } goto ret1; } m2 = b2; m5 = b5; if (leftright) { i = #ifndef Sudden_Underflow denorm ? be + (Bias + (P-1) - 1 + 1) : #endif #ifdef IBM 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); #else 1 + P - bbits; #endif b2 += i; s2 += i; mhi = i2b(1); } if (m2 > 0 && s2 > 0) { i = m2 < s2 ? m2 : s2; b2 -= i; m2 -= i; s2 -= i; } if (b5 > 0) { if (leftright) { if (m5 > 0) { mhi = pow5mult(mhi, m5); b1 = mult(mhi, b); Bfree(b); b = b1; } if ((j = b5 - m5) != 0) b = pow5mult(b, j); } else b = pow5mult(b, b5); } S = i2b(1); if (s5 > 0) S = pow5mult(S, s5); /* Check for special case that d is a normalized power of 2. */ spec_case = 0; if ((mode < 2 || leftright) #ifdef Honor_FLT_ROUNDS && rounding == 1 #endif ) { if (!word1(d) && !(word0(d) & Bndry_mask) #ifndef Sudden_Underflow && word0(d) & (Exp_mask & ~Exp_msk1) #endif ) { /* The special case */ b2 += Log2P; s2 += Log2P; spec_case = 1; } } /* Arrange for convenient computation of quotients: * shift left if necessary so divisor has 4 leading 0 bits. * * Perhaps we should just compute leading 28 bits of S once * and for all and pass them and a shift to quorem, so it * can do shifts and ors to compute the numerator for q. */ #ifdef Pack_32 if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) != 0) i = 32 - i; #else if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf) != 0) i = 16 - i; #endif if (i > 4) { i -= 4; b2 += i; m2 += i; s2 += i; } else if (i < 4) { i += 28; b2 += i; m2 += i; s2 += i; } if (b2 > 0) b = lshift(b, b2); if (s2 > 0) S = lshift(S, s2); if (k_check) { if (cmp(b,S) < 0) { k--; b = multadd(b, 10, 0); /* we botched the k estimate */ if (leftright) mhi = multadd(mhi, 10, 0); ilim = ilim1; } } if (ilim <= 0 && (mode == 3 || mode == 5)) { if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { /* no digits, fcvt style */ no_digits: k = -1 - ndigits; goto ret; } one_digit: *s++ = '1'; k++; goto ret; } if (leftright) { if (m2 > 0) mhi = lshift(mhi, m2); /* Compute mlo -- check for special case * that d is a normalized power of 2. */ mlo = mhi; if (spec_case) { mhi = Balloc(mhi->k); Bcopy(mhi, mlo); mhi = lshift(mhi, Log2P); } for (i = 1;;i++) { dig = quorem(b,S) + '0'; /* Do we yet have the shortest decimal string * that will round to d? */ j = cmp(b, mlo); delta = diff(S, mhi); j1 = delta->sign ? 1 : cmp(b, delta); Bfree(delta); #ifndef ROUND_BIASED if (j1 == 0 && mode != 1 && !(word1(d) & 1) #ifdef Honor_FLT_ROUNDS && rounding >= 1 #endif ) { if (dig == '9') goto round_9_up; if (j > 0) dig++; #ifdef SET_INEXACT else if (!b->x[0] && b->wds <= 1) inexact = 0; #endif *s++ = dig; goto ret; } #endif if (j < 0 || (j == 0 && mode != 1 #ifndef ROUND_BIASED && !(word1(d) & 1) #endif )) { if (!b->x[0] && b->wds <= 1) { #ifdef SET_INEXACT inexact = 0; #endif goto accept_dig; } #ifdef Honor_FLT_ROUNDS if (mode > 1) switch (rounding) { case 0: goto accept_dig; case 2: goto keep_dig; } #endif /*Honor_FLT_ROUNDS*/ if (j1 > 0) { b = lshift(b, 1); j1 = cmp(b, S); if ((j1 > 0 || (j1 == 0 && (dig & 1))) && dig++ == '9') goto round_9_up; } accept_dig: *s++ = dig; goto ret; } if (j1 > 0) { #ifdef Honor_FLT_ROUNDS if (!rounding) goto accept_dig; #endif if (dig == '9') { /* possible if i == 1 */ round_9_up: *s++ = '9'; goto roundoff; } *s++ = dig + 1; goto ret; } #ifdef Honor_FLT_ROUNDS keep_dig: #endif *s++ = dig; if (i == ilim) break; b = multadd(b, 10, 0); if (mlo == mhi) mlo = mhi = multadd(mhi, 10, 0); else { mlo = multadd(mlo, 10, 0); mhi = multadd(mhi, 10, 0); } } } else for (i = 1;; i++) { *s++ = dig = quorem(b,S) + '0'; if (!b->x[0] && b->wds <= 1) { #ifdef SET_INEXACT inexact = 0; #endif goto ret; } if (i >= ilim) break; b = multadd(b, 10, 0); } /* Round off last digit */ #ifdef Honor_FLT_ROUNDS switch (rounding) { case 0: goto trimzeros; case 2: goto roundoff; } #endif b = lshift(b, 1); j = cmp(b, S); if (j > 0 || (j == 0 && (dig & 1))) { roundoff: while (*--s == '9') if (s == s0) { k++; *s++ = '1'; goto ret; } ++*s++; } else { while (*--s == '0') ; s++; } ret: Bfree(S); if (mhi) { if (mlo && mlo != mhi) Bfree(mlo); Bfree(mhi); } ret1: #ifdef SET_INEXACT if (inexact) { if (!oldinexact) { word0(d) = Exp_1 + (70 << Exp_shift); word1(d) = 0; dval(d) += 1.; } } else if (!oldinexact) clear_inexact(); #endif Bfree(b); *s = 0; *decpt = k + 1; if (rve) *rve = s; return s0; } void ruby_each_words(const char *str, void (*func)(const char*, int, void*), void *arg) { const char *end; int len; if (!str) return; for (; *str; str = end) { while (ISSPACE(*str) || *str == ',') str++; if (!*str) break; end = str; while (*end && !ISSPACE(*end) && *end != ',') end++; len = end - str; (*func)(str, len, arg); } } #ifdef __cplusplus } #endif ================================================ FILE: util.h ================================================ /********************************************************************** util.h - $Author$ $Date$ created at: Thu Mar 9 11:55:53 JST 1995 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #ifndef UTIL_H #define UTIL_H #ifndef _ #ifdef __cplusplus # ifndef HAVE_PROTOTYPES # define HAVE_PROTOTYPES 1 # endif # ifndef HAVE_STDARG_PROTOTYPES # define HAVE_STDARG_PROTOTYPES 1 # endif #endif #ifdef HAVE_PROTOTYPES # define _(args) args #else # define _(args) () #endif #ifdef HAVE_STDARG_PROTOTYPES # define __(args) args #else # define __(args) () #endif #endif #define scan_oct ruby_scan_oct unsigned long scan_oct _((const char*, int, int*)); #define scan_hex ruby_scan_hex unsigned long scan_hex _((const char*, int, int*)); #if defined(MSDOS) || defined(__CYGWIN32__) || defined(_WIN32) void ruby_add_suffix(); #endif void ruby_qsort _((void*, const int, const int, int (*)(), void*)); #define qsort(b,n,s,c,d) ruby_qsort(b,n,s,c,d) void ruby_setenv _((const char*, const char*)); void ruby_unsetenv _((const char*)); #undef setenv #undef unsetenv #define setenv(name,val) ruby_setenv(name,val) #define unsetenv(name,val) ruby_unsetenv(name); char *ruby_strdup _((const char*)); char *strdup _((const char*)); #undef strdup #define strdup(s) ruby_strdup(s) char *ruby_getcwd _((void)); #define my_getcwd() ruby_getcwd() double ruby_strtod _((const char*, char **)); #undef strtod #define strtod(s,e) ruby_strtod(s,e) #endif /* UTIL_H */ ================================================ FILE: variable.c ================================================ /********************************************************************** variable.c - $Author$ $Date$ created at: Tue Apr 19 23:55:15 JST 1994 Copyright (C) 1993-2003 Yukihiro Matsumoto Copyright (C) 2000 Network Applied Communication Laboratory, Inc. Copyright (C) 2000 Information-technology Promotion Agency, Japan **********************************************************************/ #include "ruby.h" #include "env.h" #include "node.h" #include "st.h" #include "util.h" st_table *rb_global_tbl; st_table *rb_class_tbl; static ID autoload, classpath, tmp_classpath; void Init_var_tables() { rb_global_tbl = st_init_numtable(); rb_class_tbl = st_init_numtable(); autoload = rb_intern("__autoload__"); classpath = rb_intern("__classpath__"); tmp_classpath = rb_intern("__tmp_classpath__"); } struct fc_result { ID name; VALUE klass; VALUE path; VALUE track; struct fc_result *prev; }; static VALUE fc_path(fc, name) struct fc_result *fc; ID name; { VALUE path, tmp; path = rb_str_new2(rb_id2name(name)); while (fc) { if (fc->track == rb_cObject) break; if (ROBJECT(fc->track)->iv_tbl && st_lookup(ROBJECT(fc->track)->iv_tbl, classpath, &tmp)) { tmp = rb_str_dup(tmp); rb_str_cat2(tmp, "::"); rb_str_append(tmp, path); return tmp; } tmp = rb_str_new2(rb_id2name(fc->name)); rb_str_cat2(tmp, "::"); rb_str_append(tmp, path); path = tmp; fc = fc->prev; } return path; } static int fc_i(key, value, res) ID key; VALUE value; struct fc_result *res; { if (!rb_is_const_id(key)) return ST_CONTINUE; if (value == res->klass) { res->path = fc_path(res, key); return ST_STOP; } switch (TYPE(value)) { case T_MODULE: case T_CLASS: if (!RCLASS(value)->iv_tbl) return ST_CONTINUE; else { struct fc_result arg; struct fc_result *list; list = res; while (list) { if (list->track == value) return ST_CONTINUE; list = list->prev; } arg.name = key; arg.path = 0; arg.klass = res->klass; arg.track = value; arg.prev = res; st_foreach_safe(RCLASS(value)->iv_tbl, fc_i, (st_data_t)&arg); if (arg.path) { res->path = arg.path; return ST_STOP; } } break; default: break; } return ST_CONTINUE; } static VALUE find_class_path(klass) VALUE klass; { struct fc_result arg; arg.name = 0; arg.path = 0; arg.klass = klass; arg.track = rb_cObject; arg.prev = 0; if (RCLASS(rb_cObject)->iv_tbl) { st_foreach_safe(RCLASS(rb_cObject)->iv_tbl, fc_i, (st_data_t)&arg); } if (arg.path == 0) { st_foreach(rb_class_tbl, fc_i, (st_data_t)&arg); } if (arg.path) { if (!ROBJECT(klass)->iv_tbl) { ROBJECT(klass)->iv_tbl = st_init_numtable(); } st_insert(ROBJECT(klass)->iv_tbl, classpath, arg.path); st_delete(RCLASS(klass)->iv_tbl, &tmp_classpath, 0); return arg.path; } return Qnil; } static VALUE classname(klass) VALUE klass; { VALUE path = Qnil; if (!klass) klass = rb_cObject; if (ROBJECT(klass)->iv_tbl) { if (!st_lookup(ROBJECT(klass)->iv_tbl, classpath, &path)) { ID classid = rb_intern("__classid__"); if (!st_lookup(ROBJECT(klass)->iv_tbl, classid, &path)) { return find_class_path(klass); } path = rb_str_new2(rb_id2name(SYM2ID(path))); st_insert(ROBJECT(klass)->iv_tbl, classpath, path); st_delete(RCLASS(klass)->iv_tbl, (st_data_t*)&classid, 0); } if (TYPE(path) != T_STRING) { rb_bug("class path is not set properly"); } return path; } return find_class_path(klass); } /* * call-seq: * mod.name => string * * Returns the name of the module mod. */ VALUE rb_mod_name(mod) VALUE mod; { VALUE path = classname(mod); if (!NIL_P(path)) return rb_str_dup(path); return rb_str_new(0,0); } VALUE rb_class_path(klass) VALUE klass; { VALUE path = classname(klass); if (!NIL_P(path)) return path; if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, tmp_classpath, &path)) { return path; } else { const char *s = "Class"; size_t len; if (TYPE(klass) == T_MODULE) { if (rb_obj_class(klass) == rb_cModule) { s = "Module"; } else { s = rb_class2name(RBASIC(klass)->klass); } } len = 2 + strlen(s) + 3 + 2 * SIZEOF_LONG + 1; path = rb_str_new(0, len); snprintf(RSTRING(path)->ptr, len+1, "#<%s:0x%lx>", s, klass); RSTRING(path)->len = strlen(RSTRING(path)->ptr); rb_ivar_set(klass, tmp_classpath, path); return path; } } void rb_set_class_path(klass, under, name) VALUE klass, under; const char *name; { VALUE str; if (under == rb_cObject) { str = rb_str_new2(name); } else { str = rb_str_dup(rb_class_path(under)); rb_str_cat2(str, "::"); rb_str_cat2(str, name); } rb_ivar_set(klass, classpath, str); } VALUE rb_path2class(path) const char *path; { const char *pbeg, *p; ID id; VALUE c = rb_cObject; VALUE str = 0; if (path[0] == '#') { rb_raise(rb_eArgError, "can't retrieve anonymous class %s", path); } pbeg = p = path; while (*p) { while (*p && *p != ':') p++; if (str) { RSTRING(str)->len = 0; rb_str_cat(str, pbeg, p-pbeg); } else { str = rb_str_new(pbeg, p-pbeg); } id = rb_intern(RSTRING(str)->ptr); if (p[0] == ':') { if (p[1] != ':') goto undefined_class; p += 2; pbeg = p; } if (!rb_const_defined(c, id)) { undefined_class: rb_raise(rb_eArgError, "undefined class/module %.*s", p-path, path); } c = rb_const_get_at(c, id); switch (TYPE(c)) { case T_MODULE: case T_CLASS: break; default: rb_raise(rb_eTypeError, "%s does not refer class/module", path); } } return c; } void rb_name_class(klass, id) VALUE klass; ID id; { rb_iv_set(klass, "__classid__", ID2SYM(id)); } VALUE rb_class_name(klass) VALUE klass; { return rb_class_path(rb_class_real(klass)); } const char * rb_class2name(klass) VALUE klass; { return RSTRING(rb_class_name(klass))->ptr; } const char * rb_obj_classname(obj) VALUE obj; { return rb_class2name(CLASS_OF(obj)); } struct trace_var { int removed; void (*func)(); VALUE data; struct trace_var *next; }; struct global_variable { int counter; void *data; VALUE (*getter)(); void (*setter)(); void (*marker)(); int block_trace; struct trace_var *trace; }; struct global_entry { struct global_variable *var; ID id; }; static VALUE undef_getter(); static void undef_setter(); static void undef_marker(); static VALUE val_getter(); static void val_setter(); static void val_marker(); static VALUE var_getter(); static void var_setter(); static void var_marker(); struct global_entry* rb_global_entry(id) ID id; { struct global_entry *entry; st_data_t data; if (!st_lookup(rb_global_tbl, id, &data)) { struct global_variable *var; entry = ALLOC(struct global_entry); var = ALLOC(struct global_variable); entry->id = id; entry->var = var; var->counter = 1; var->data = 0; var->getter = undef_getter; var->setter = undef_setter; var->marker = undef_marker; var->block_trace = 0; var->trace = 0; st_add_direct(rb_global_tbl, id, (st_data_t)entry); } else { entry = (struct global_entry *)data; } return entry; } static VALUE undef_getter(id) ID id; { rb_warning("global variable `%s' not initialized", rb_id2name(id)); return Qnil; } static void undef_setter(val, id, data, var) VALUE val; ID id; void *data; struct global_variable *var; { var->getter = val_getter; var->setter = val_setter; var->marker = val_marker; var->data = (void*)val; } static void undef_marker() { } static VALUE val_getter(id, val) ID id; VALUE val; { return val; } static void val_setter(val, id, data, var) VALUE val; ID id; void *data; struct global_variable *var; { var->data = (void*)val; } static void val_marker(data) VALUE data; { if (data) rb_gc_mark_maybe(data); } static VALUE var_getter(id, var) ID id; VALUE *var; { if (!var) return Qnil; return *var; } static void var_setter(val, id, var) VALUE val; ID id; VALUE *var; { *var = val; } static void var_marker(var) VALUE *var; { if (var) rb_gc_mark_maybe(*var); } static void readonly_setter(val, id, var) VALUE val; ID id; void *var; { rb_name_error(id, "%s is a read-only variable", rb_id2name(id)); } static int mark_global_entry(key, entry) ID key; struct global_entry *entry; { struct trace_var *trace; struct global_variable *var = entry->var; (*var->marker)(var->data); trace = var->trace; while (trace) { if (trace->data) rb_gc_mark_maybe(trace->data); trace = trace->next; } return ST_CONTINUE; } void rb_gc_mark_global_tbl() { if (rb_global_tbl) { st_foreach(rb_global_tbl, mark_global_entry, 0); } } static ID global_id(name) const char *name; { ID id; if (name[0] == '$') id = rb_intern(name); else { char *buf = ALLOCA_N(char, strlen(name)+2); buf[0] = '$'; strcpy(buf+1, name); id = rb_intern(buf); } return id; } void rb_define_hooked_variable(name, var, getter, setter) const char *name; VALUE *var; VALUE (*getter)(); void (*setter)(); { struct global_variable *gvar; ID id = global_id(name); gvar = rb_global_entry(id)->var; gvar->data = (void*)var; gvar->getter = getter?getter:var_getter; gvar->setter = setter?setter:var_setter; gvar->marker = var_marker; } void rb_define_variable(name, var) const char *name; VALUE *var; { rb_define_hooked_variable(name, var, 0, 0); } void rb_define_readonly_variable(name, var) const char *name; VALUE *var; { rb_define_hooked_variable(name, var, 0, readonly_setter); } void rb_define_virtual_variable(name, getter, setter) const char *name; VALUE (*getter)(); void (*setter)(); { if (!getter) getter = val_getter; if (!setter) setter = readonly_setter; rb_define_hooked_variable(name, 0, getter, setter); } static void rb_trace_eval(cmd, val) VALUE cmd, val; { rb_eval_cmd(cmd, rb_ary_new3(1, val), 0); } /* * call-seq: * trace_var(symbol, cmd ) => nil * trace_var(symbol) {|val| block } => nil * * Controls tracing of assignments to global variables. The parameter * +symbol_ identifies the variable (as either a string name or a * symbol identifier). _cmd_ (which may be a string or a * +Proc+ object) or block is executed whenever the variable * is assigned. The block or +Proc+ object receives the * variable's new value as a parameter. Also see * Kernel::untrace_var. * * trace_var :$_, proc {|v| puts "$_ is now '#{v}'" } * $_ = "hello" * $_ = ' there' * * produces: * * $_ is now 'hello' * $_ is now ' there' */ VALUE rb_f_trace_var(argc, argv) int argc; VALUE *argv; { VALUE var, cmd; struct global_entry *entry; struct trace_var *trace; rb_secure(4); if (rb_scan_args(argc, argv, "11", &var, &cmd) == 1) { cmd = rb_block_proc(); } if (NIL_P(cmd)) { return rb_f_untrace_var(argc, argv); } entry = rb_global_entry(rb_to_id(var)); if (OBJ_TAINTED(cmd)) { rb_raise(rb_eSecurityError, "Insecure: tainted variable trace"); } trace = ALLOC(struct trace_var); trace->next = entry->var->trace; trace->func = rb_trace_eval; trace->data = cmd; trace->removed = 0; entry->var->trace = trace; return Qnil; } static void remove_trace(var) struct global_variable *var; { struct trace_var *trace = var->trace; struct trace_var t; struct trace_var *next; t.next = trace; trace = &t; while (trace->next) { next = trace->next; if (next->removed) { trace->next = next->next; free(next); } else { trace = next; } } var->trace = t.next; } /* * call-seq: * untrace_var(symbol [, cmd] ) => array or nil * * Removes tracing for the specified command on the given global * variable and returns +nil+. If no command is specified, * removes all tracing for that variable and returns an array * containing the commands actually removed. */ VALUE rb_f_untrace_var(argc, argv) int argc; VALUE *argv; { VALUE var, cmd; ID id; struct global_entry *entry; struct trace_var *trace; st_data_t data; rb_secure(4); rb_scan_args(argc, argv, "11", &var, &cmd); id = rb_to_id(var); if (!st_lookup(rb_global_tbl, id, &data)) { rb_name_error(id, "undefined global variable %s", rb_id2name(id)); } trace = (entry = (struct global_entry *)data)->var->trace; if (NIL_P(cmd)) { VALUE ary = rb_ary_new(); while (trace) { struct trace_var *next = trace->next; rb_ary_push(ary, (VALUE)trace->data); trace->removed = 1; trace = next; } if (!entry->var->block_trace) remove_trace(entry->var); return ary; } else { while (trace) { if (trace->data == cmd) { trace->removed = 1; if (!entry->var->block_trace) remove_trace(entry->var); return rb_ary_new3(1, cmd); } trace = trace->next; } } return Qnil; } VALUE rb_gvar_get(entry) struct global_entry *entry; { struct global_variable *var = entry->var; return (*var->getter)(entry->id, var->data, var); } struct trace_data { struct trace_var *trace; VALUE val; }; static VALUE trace_ev(data) struct trace_data *data; { struct trace_var *trace = data->trace; while (trace) { (*trace->func)(trace->data, data->val); trace = trace->next; } return Qnil; /* not reached */ } static VALUE trace_en(var) struct global_variable *var; { var->block_trace = 0; remove_trace(var); return Qnil; /* not reached */ } VALUE rb_gvar_set(entry, val) struct global_entry *entry; VALUE val; { struct trace_data trace; struct global_variable *var = entry->var; if (rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't change global variable value"); (*var->setter)(val, entry->id, var->data, var); if (var->trace && !var->block_trace) { var->block_trace = 1; trace.trace = var->trace; trace.val = val; rb_ensure(trace_ev, (VALUE)&trace, trace_en, (VALUE)var); } return val; } VALUE rb_gv_set(name, val) const char *name; VALUE val; { struct global_entry *entry; entry = rb_global_entry(global_id(name)); return rb_gvar_set(entry, val); } VALUE rb_gv_get(name) const char *name; { struct global_entry *entry; entry = rb_global_entry(global_id(name)); return rb_gvar_get(entry); } VALUE rb_gvar_defined(entry) struct global_entry *entry; { if (entry->var->getter == undef_getter) return Qfalse; return Qtrue; } static int gvar_i(key, entry, ary) ID key; struct global_entry *entry; VALUE ary; { rb_ary_push(ary, rb_str_new2(rb_id2name(key))); return ST_CONTINUE; } /* * call-seq: * global_variables => array * * Returns an array of the names of global variables. * * global_variables.grep /std/ #=> ["$stderr", "$stdout", "$stdin"] */ VALUE rb_f_global_variables() { VALUE ary = rb_ary_new(); char buf[4]; const char *s = "&`'+123456789"; st_foreach(rb_global_tbl, gvar_i, ary); if (!NIL_P(rb_backref_get())) { while (*s) { sprintf(buf, "$%c", *s++); rb_ary_push(ary, rb_str_new2(buf)); } } return ary; } void rb_alias_variable(name1, name2) ID name1; ID name2; { struct global_entry *entry1, *entry2; st_data_t data1; if (rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't alias global variable"); entry2 = rb_global_entry(name2); if (!st_lookup(rb_global_tbl, name1, &data1)) { entry1 = ALLOC(struct global_entry); entry1->id = name1; st_add_direct(rb_global_tbl, name1, (st_data_t)entry1); } else if ((entry1 = (struct global_entry *)data1)->var != entry2->var) { struct global_variable *var = entry1->var; if (var->block_trace) { rb_raise(rb_eRuntimeError, "can't alias in tracer"); } var->counter--; if (var->counter == 0) { struct trace_var *trace = var->trace; while (trace) { struct trace_var *next = trace->next; free(trace); trace = next; } free(var); } } else { return; } entry2->var->counter++; entry1->var = entry2->var; } static int special_generic_ivar = 0; static st_table *generic_iv_tbl; st_table* rb_generic_ivar_table(obj) VALUE obj; { st_data_t tbl; if (!FL_TEST(obj, FL_EXIVAR)) return 0; if (!generic_iv_tbl) return 0; if (!st_lookup(generic_iv_tbl, obj, &tbl)) return 0; return (st_table *)tbl; } static VALUE generic_ivar_get(obj, id, warn) VALUE obj; ID id; int warn; { st_data_t tbl; VALUE val; if (generic_iv_tbl) { if (st_lookup(generic_iv_tbl, obj, &tbl)) { if (st_lookup((st_table *)tbl, id, &val)) { return val; } } } if (warn) { rb_warning("instance variable %s not initialized", rb_id2name(id)); } return Qnil; } static void generic_ivar_set(obj, id, val) VALUE obj; ID id; VALUE val; { st_table *tbl; st_data_t data; if (rb_special_const_p(obj)) { special_generic_ivar = 1; } if (!generic_iv_tbl) { generic_iv_tbl = st_init_numtable(); } if (!st_lookup(generic_iv_tbl, obj, &data)) { FL_SET(obj, FL_EXIVAR); tbl = st_init_numtable(); st_add_direct(generic_iv_tbl, obj, (st_data_t)tbl); st_add_direct(tbl, id, val); return; } st_insert((st_table *)data, id, val); } static VALUE generic_ivar_defined(obj, id) VALUE obj; ID id; { st_table *tbl; st_data_t data; VALUE val; if (!generic_iv_tbl) return Qfalse; if (!st_lookup(generic_iv_tbl, obj, &data)) return Qfalse; tbl = (st_table *)data; if (st_lookup(tbl, id, &val)) { return Qtrue; } return Qfalse; } static int generic_ivar_remove(obj, id, valp) VALUE obj; ID id; VALUE *valp; { st_table *tbl; st_data_t data; int status; if (!generic_iv_tbl) return 0; if (!st_lookup(generic_iv_tbl, obj, &data)) return 0; tbl = (st_table *)data; status = st_delete(tbl, &id, valp); if (tbl->num_entries == 0) { st_delete(generic_iv_tbl, &obj, &data); st_free_table((st_table *)data); } return status; } void rb_mark_generic_ivar(obj) VALUE obj; { st_data_t tbl; if (!generic_iv_tbl) return; if (st_lookup(generic_iv_tbl, obj, &tbl)) { rb_mark_tbl((st_table *)tbl); } } void add_generic_ivar_to_remembered_set(obj) VALUE obj; { st_data_t tbl; if (!generic_iv_tbl) return; if (st_lookup(generic_iv_tbl, obj, &tbl)) { add_table_to_remembered_set((st_table *)tbl); } } static int givar_mark_i(key, value) ID key; VALUE value; { rb_gc_mark(value); return ST_CONTINUE; } static int givar_i(obj, tbl) VALUE obj; st_table *tbl; { if (rb_special_const_p(obj)) { st_foreach(tbl, givar_mark_i, 0); } return ST_CONTINUE; } void rb_mark_generic_ivar_tbl() { if (!generic_iv_tbl) return; if (special_generic_ivar == 0) return; st_foreach_safe(generic_iv_tbl, givar_i, 0); } void rb_free_generic_ivar(obj) VALUE obj; { st_data_t tbl; if (!generic_iv_tbl) return; if (st_delete(generic_iv_tbl, &obj, &tbl)) st_free_table((st_table *)tbl); } void rb_copy_generic_ivar(clone, obj) VALUE clone, obj; { st_data_t data; if (!generic_iv_tbl) return; if (!FL_TEST(obj, FL_EXIVAR)) return; if (st_lookup(generic_iv_tbl, obj, &data)) { st_table *tbl = (st_table *)data; if (st_lookup(generic_iv_tbl, clone, &data)) { st_free_table((st_table *)data); st_insert(generic_iv_tbl, clone, (st_data_t)st_copy(tbl)); } else { st_add_direct(generic_iv_tbl, clone, (st_data_t)st_copy(tbl)); } } } static VALUE ivar_get(obj, id, warn) VALUE obj; ID id; int warn; { VALUE val; switch (TYPE(obj)) { case T_OBJECT: case T_CLASS: case T_MODULE: if (ROBJECT(obj)->iv_tbl && st_lookup(ROBJECT(obj)->iv_tbl, id, &val)) return val; break; default: if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) return generic_ivar_get(obj, id, warn); break; } if (warn) { rb_warning("instance variable %s not initialized", rb_id2name(id)); } return Qnil; } VALUE rb_ivar_get(obj, id) VALUE obj; ID id; { return ivar_get(obj, id, Qtrue); } VALUE rb_attr_get(obj, id) VALUE obj; ID id; { return ivar_get(obj, id, Qfalse); } VALUE rb_ivar_set(obj, id, val) VALUE obj; ID id; VALUE val; { if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable"); if (OBJ_FROZEN(obj)) rb_error_frozen("object"); switch (TYPE(obj)) { case T_OBJECT: case T_CLASS: case T_MODULE: if (!ROBJECT(obj)->iv_tbl) ROBJECT(obj)->iv_tbl = st_init_numtable(); st_insert(ROBJECT(obj)->iv_tbl, id, val); break; default: generic_ivar_set(obj, id, val); break; } return val; } VALUE rb_ivar_defined(obj, id) VALUE obj; ID id; { switch (TYPE(obj)) { case T_OBJECT: case T_CLASS: case T_MODULE: if (ROBJECT(obj)->iv_tbl && st_lookup(ROBJECT(obj)->iv_tbl, id, 0)) return Qtrue; break; default: if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) return generic_ivar_defined(obj, id); break; } return Qfalse; } static int ivar_i(key, entry, ary) ID key; struct global_entry *entry; VALUE ary; { if (rb_is_instance_id(key)) { rb_ary_push(ary, rb_str_new2(rb_id2name(key))); } return ST_CONTINUE; } /* * call-seq: * obj.instance_variables => array * * Returns an array of instance variable names for the receiver. Note * that simply defining an accessor does not create the corresponding * instance variable. * * class Fred * attr_accessor :a1 * def initialize * @iv = 3 * end * end * Fred.new.instance_variables #=> ["@iv"] */ VALUE rb_obj_instance_variables(obj) VALUE obj; { VALUE ary; ary = rb_ary_new(); switch (TYPE(obj)) { case T_OBJECT: case T_CLASS: case T_MODULE: if (ROBJECT(obj)->iv_tbl) { st_foreach_safe(ROBJECT(obj)->iv_tbl, ivar_i, ary); } break; default: if (!generic_iv_tbl) break; if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) { st_data_t tbl; if (st_lookup(generic_iv_tbl, obj, &tbl)) { st_foreach_safe((st_table *)tbl, ivar_i, ary); } } break; } return ary; } /* * call-seq: * obj.remove_instance_variable(symbol) => obj * * Removes the named instance variable from obj, returning that * variable's value. * * class Dummy * attr_reader :var * def initialize * @var = 99 * end * def remove * remove_instance_variable(:@var) * end * end * d = Dummy.new * d.var #=> 99 * d.remove #=> 99 * d.var #=> nil */ VALUE rb_obj_remove_instance_variable(obj, name) VALUE obj, name; { VALUE val = Qnil; ID id = rb_to_id(name); if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable"); if (OBJ_FROZEN(obj)) rb_error_frozen("object"); if (!rb_is_instance_id(id)) { rb_name_error(id, "`%s' is not allowed as an instance variable name", rb_id2name(id)); } switch (TYPE(obj)) { case T_OBJECT: case T_CLASS: case T_MODULE: if (ROBJECT(obj)->iv_tbl && st_delete(ROBJECT(obj)->iv_tbl, (st_data_t*)&id, &val)) { return val; } break; default: if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) { if (generic_ivar_remove(obj, id, &val)) { return val; } } break; } rb_name_error(id, "instance variable %s not defined", rb_id2name(id)); return Qnil; /* not reached */ } NORETURN(static void uninitialized_constant _((VALUE, ID))); static void uninitialized_constant(klass, id) VALUE klass; ID id; { if (klass && klass != rb_cObject) rb_name_error(id, "uninitialized constant %s::%s", rb_class2name(klass), rb_id2name(id)); else { rb_name_error(id, "uninitialized constant %s", rb_id2name(id)); } } static VALUE const_missing(klass, id) VALUE klass; ID id; { return rb_funcall(klass, rb_intern("const_missing"), 1, ID2SYM(id)); } /* * call-seq: * mod.const_missing(sym) => obj * * Invoked when a reference is made to an undefined constant in * mod. It is passed a symbol for the undefined constant, and * returns a value to be used for that constant. The * following code is a (very bad) example: if reference is made to * an undefined constant, it attempts to load a file whose name is * the lowercase version of the constant (thus class Fred is * assumed to be in file fred.rb). If found, it returns the * value of the loaded class. It therefore implements a perverse * kind of autoload facility. * * def Object.const_missing(name) * @looked_for ||= {} * str_name = name.to_s * raise "Class not found: #{name}" if @looked_for[str_name] * @looked_for[str_name] = 1 * file = str_name.downcase * require file * klass = const_get(name) * return klass if klass * raise "Class not found: #{name}" * end * */ VALUE rb_mod_const_missing(klass, name) VALUE klass, name; { ruby_frame = ruby_frame->prev; /* pop frame for "const_missing" */ uninitialized_constant(klass, rb_to_id(name)); return Qnil; /* not reached */ } static struct st_table * check_autoload_table(av) VALUE av; { Check_Type(av, T_DATA); if (RDATA(av)->dmark != (RUBY_DATA_FUNC)rb_mark_tbl || RDATA(av)->dfree != (RUBY_DATA_FUNC)st_free_table) { rb_raise(rb_eTypeError, "wrong autoload table: %s", RSTRING(rb_inspect(av))->ptr); } return (struct st_table *)DATA_PTR(av); } void rb_autoload(mod, id, file) VALUE mod; ID id; const char *file; { VALUE av, fn; struct st_table *tbl; if (!rb_is_const_id(id)) { rb_raise(rb_eNameError, "autoload must be constant name", rb_id2name(id)); } if (!file || !*file) { rb_raise(rb_eArgError, "empty file name"); } if ((tbl = RCLASS(mod)->iv_tbl) && st_lookup(tbl, id, &av) && av != Qundef) return; rb_const_set(mod, id, Qundef); tbl = RCLASS(mod)->iv_tbl; if (st_lookup(tbl, autoload, &av)) { tbl = check_autoload_table(av); } else { av = Data_Wrap_Struct(0 , rb_mark_tbl, st_free_table, 0); st_add_direct(tbl, autoload, av); DATA_PTR(av) = tbl = st_init_numtable(); } fn = rb_str_new2(file); FL_UNSET(fn, FL_TAINT); OBJ_FREEZE(fn); st_insert(tbl, id, (st_data_t)NEW_NODE_EDEN(NODE_MEMO, fn, ruby_safe_level, 0)); } static NODE* autoload_delete(mod, id) VALUE mod; ID id; { VALUE val; st_data_t load = 0; st_delete(RCLASS(mod)->iv_tbl, (st_data_t*)&id, 0); if (st_lookup(RCLASS(mod)->iv_tbl, autoload, &val)) { struct st_table *tbl = check_autoload_table(val); st_delete(tbl, (st_data_t*)&id, &load); if (tbl->num_entries == 0) { id = autoload; st_delete(RCLASS(mod)->iv_tbl, (st_data_t*)&id, &val); } } return (NODE *)load; } VALUE rb_autoload_load(klass, id) VALUE klass; ID id; { VALUE file; NODE *load = autoload_delete(klass, id); if (!load || !(file = load->nd_lit) || rb_provided(RSTRING(file)->ptr)) { return Qfalse; } return rb_require_safe(file, load->nd_nth); } static VALUE autoload_file(mod, id) VALUE mod; ID id; { VALUE val, file; struct st_table *tbl; st_data_t load; if (!st_lookup(RCLASS(mod)->iv_tbl, autoload, &val) || !(tbl = check_autoload_table(val)) || !st_lookup(tbl, id, &load)) { return Qnil; } file = ((NODE *)load)->nd_lit; Check_Type(file, T_STRING); if (!RSTRING(file)->ptr || !*RSTRING(file)->ptr) { rb_raise(rb_eArgError, "empty file name"); } if (!rb_provided(RSTRING(file)->ptr)) { return file; } /* already loaded but not defined */ st_delete(tbl, (st_data_t*)&id, 0); if (!tbl->num_entries) { id = autoload; st_delete(RCLASS(mod)->iv_tbl, (st_data_t*)&id, &val); } return Qnil; } VALUE rb_autoload_p(mod, id) VALUE mod; ID id; { struct st_table *tbl = RCLASS(mod)->iv_tbl; VALUE val; if (!tbl || !st_lookup(tbl, id, &val) || val != Qundef) { return Qnil; } return autoload_file(mod, id); } static VALUE rb_const_get_0(klass, id, exclude, recurse) VALUE klass; ID id; int exclude, recurse; { VALUE value, tmp; int mod_retry = 0; tmp = klass; retry: while (tmp) { while (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) { if (value == Qundef) { if (!RTEST(rb_autoload_load(tmp, id))) break; continue; } if (exclude && tmp == rb_cObject && klass != rb_cObject) { rb_warn("toplevel constant %s referenced by %s::%s", rb_id2name(id), rb_class2name(klass), rb_id2name(id)); } return value; } if (!recurse && klass != rb_cObject) break; tmp = RCLASS(tmp)->super; } if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) { mod_retry = 1; tmp = rb_cObject; goto retry; } return const_missing(klass, id); } VALUE rb_const_get_from(klass, id) VALUE klass; ID id; { return rb_const_get_0(klass, id, Qtrue, Qtrue); } VALUE rb_const_get(klass, id) VALUE klass; ID id; { return rb_const_get_0(klass, id, Qfalse, Qtrue); } VALUE rb_const_get_at(klass, id) VALUE klass; ID id; { return rb_const_get_0(klass, id, Qtrue, Qfalse); } /* * call-seq: * remove_const(sym) => obj * * Removes the definition of the given constant, returning that * constant's value. Predefined classes and singleton objects (such as * true) cannot be removed. */ VALUE rb_mod_remove_const(mod, name) VALUE mod, name; { ID id = rb_to_id(name); VALUE val; if (!rb_is_const_id(id)) { rb_name_error(id, "`%s' is not allowed as a constant name", rb_id2name(id)); } if (!OBJ_TAINTED(mod) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't remove constant"); if (OBJ_FROZEN(mod)) rb_error_frozen("class/module"); if (RCLASS(mod)->iv_tbl && st_delete(ROBJECT(mod)->iv_tbl, (st_data_t*)&id, &val)) { if (val == Qundef) { autoload_delete(mod, id); val = Qnil; } return val; } if (rb_const_defined_at(mod, id)) { rb_name_error(id, "cannot remove %s::%s", rb_class2name(mod), rb_id2name(id)); } rb_name_error(id, "constant %s::%s not defined", rb_class2name(mod), rb_id2name(id)); return Qnil; /* not reached */ } static int sv_i(key, value, tbl) ID key; VALUE value; st_table *tbl; { if (rb_is_const_id(key)) { if (!st_lookup(tbl, key, 0)) { st_insert(tbl, key, key); } } return ST_CONTINUE; } void* rb_mod_const_at(mod, data) VALUE mod; void *data; { st_table *tbl = data; if (!tbl) { tbl = st_init_numtable(); } if (RCLASS(mod)->iv_tbl) { st_foreach_safe(RCLASS(mod)->iv_tbl, sv_i, (st_data_t)tbl); } return tbl; } void* rb_mod_const_of(mod, data) VALUE mod; void *data; { VALUE tmp = mod; for (;;) { data = rb_mod_const_at(tmp, data); tmp = RCLASS(tmp)->super; if (!tmp) break; if (tmp == rb_cObject && mod != rb_cObject) break; } return data; } static int list_i(key, value, ary) ID key, value; VALUE ary; { rb_ary_push(ary, rb_str_new2(rb_id2name(key))); return ST_CONTINUE; } VALUE rb_const_list(data) void *data; { st_table *tbl = data; VALUE ary; if (!tbl) return rb_ary_new2(0); ary = rb_ary_new2(tbl->num_entries); st_foreach(tbl, list_i, ary); st_free_table(tbl); return ary; } /* * call-seq: * mod.constants => array * * Returns an array of the names of the constants accessible in * mod. This includes the names of constants in any included * modules (example at start of section). */ VALUE rb_mod_constants(mod) VALUE mod; { return rb_const_list(rb_mod_const_of(mod, 0)); } static int rb_const_defined_0(klass, id, exclude, recurse) VALUE klass; ID id; int exclude, recurse; { VALUE value, tmp; int mod_retry = 0; tmp = klass; retry: while (tmp) { if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl, id, &value)) { if (value == Qundef && NIL_P(autoload_file(klass, id))) return Qfalse; return Qtrue; } if (!recurse && klass != rb_cObject) break; tmp = RCLASS(tmp)->super; } if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) { mod_retry = 1; tmp = rb_cObject; goto retry; } return Qfalse; } int rb_const_defined_from(klass, id) VALUE klass; ID id; { return rb_const_defined_0(klass, id, Qtrue, Qtrue); } int rb_const_defined(klass, id) VALUE klass; ID id; { return rb_const_defined_0(klass, id, Qfalse, Qtrue); } int rb_const_defined_at(klass, id) VALUE klass; ID id; { return rb_const_defined_0(klass, id, Qtrue, Qfalse); } static void mod_av_set(klass, id, val, isconst) VALUE klass; ID id; VALUE val; int isconst; { const char *dest = isconst ? "constant" : "class variable"; if (!OBJ_TAINTED(klass) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't set %s", dest); if (OBJ_FROZEN(klass)) { if (BUILTIN_TYPE(klass) == T_MODULE) { rb_error_frozen("module"); } else { rb_error_frozen("class"); } } if (!RCLASS(klass)->iv_tbl) { RCLASS(klass)->iv_tbl = st_init_numtable(); } else if (isconst) { VALUE value = Qfalse; if (st_lookup(RCLASS(klass)->iv_tbl, id, &value)) { if (value == Qundef) autoload_delete(klass, id); else rb_warn("already initialized %s %s", dest, rb_id2name(id)); } } st_insert(RCLASS(klass)->iv_tbl, id, val); } void rb_const_set(klass, id, val) VALUE klass; ID id; VALUE val; { if (NIL_P(klass)) { rb_raise(rb_eTypeError, "no class/module to define constant %s", rb_id2name(id)); } mod_av_set(klass, id, val, Qtrue); } void rb_define_const(klass, name, val) VALUE klass; const char *name; VALUE val; { ID id = rb_intern(name); if (!rb_is_const_id(id)) { rb_warn("rb_define_const: invalid name `%s' for constant", name); } if (klass == rb_cObject) { rb_secure(4); } rb_const_set(klass, id, val); } void rb_define_global_const(name, val) const char *name; VALUE val; { rb_define_const(rb_cObject, name, val); } static VALUE original_module(c) VALUE c; { if (TYPE(c) == T_ICLASS) return RBASIC(c)->klass; return c; } static void cvar_override_check(id, a) ID id; VALUE a; { VALUE base = original_module(a); a = RCLASS(a)->super; while (a) { if (RCLASS(a)->iv_tbl) { if (st_lookup(RCLASS(a)->iv_tbl,id,0)) { rb_warning("class variable %s of %s is overridden by %s", rb_id2name(id), rb_class2name(original_module(a)), rb_class2name(base)); } } a = RCLASS(a)->super; } } void rb_cvar_set(klass, id, val, warn) VALUE klass; ID id; VALUE val; int warn; { VALUE tmp; tmp = klass; while (tmp) { if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,0)) { if (OBJ_FROZEN(tmp)) rb_error_frozen("class/module"); if (!OBJ_TAINTED(tmp) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify class variable"); if (warn && RTEST(ruby_verbose) && klass != tmp) { rb_warning("already initialized class variable %s", rb_id2name(id)); } st_insert(RCLASS(tmp)->iv_tbl,id,val); if (RTEST(ruby_verbose)) { cvar_override_check(id, tmp); } return; } tmp = RCLASS(tmp)->super; } mod_av_set(klass, id, val, Qfalse); } VALUE rb_cvar_get(klass, id) VALUE klass; ID id; { VALUE value; VALUE tmp; tmp = klass; while (tmp) { if (RCLASS(tmp)->iv_tbl) { if (st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) { if (RTEST(ruby_verbose)) { cvar_override_check(id, tmp); } return value; } } tmp = RCLASS(tmp)->super; } rb_name_error(id,"uninitialized class variable %s in %s", rb_id2name(id), rb_class2name(klass)); return Qnil; /* not reached */ } VALUE rb_cvar_defined(klass, id) VALUE klass; ID id; { VALUE tmp; tmp = klass; while (tmp) { if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,0)) { return Qtrue; } tmp = RCLASS(tmp)->super; } return Qfalse; } void rb_cv_set(klass, name, val) VALUE klass; const char *name; VALUE val; { ID id = rb_intern(name); if (!rb_is_class_id(id)) { rb_name_error(id, "wrong class variable name %s", name); } rb_cvar_set(klass, id, val, Qfalse); } VALUE rb_cv_get(klass, name) VALUE klass; const char *name; { ID id = rb_intern(name); if (!rb_is_class_id(id)) { rb_name_error(id, "wrong class variable name %s", name); } return rb_cvar_get(klass, id); } void rb_define_class_variable(klass, name, val) VALUE klass; const char *name; VALUE val; { ID id = rb_intern(name); if (!rb_is_class_id(id)) { rb_name_error(id, "wrong class variable name %s", name); } rb_cvar_set(klass, id, val, Qtrue); } static int cv_i(key, value, ary) ID key; VALUE value; VALUE ary; { if (rb_is_class_id(key)) { VALUE kval = rb_str_new2(rb_id2name(key)); if (!rb_ary_includes(ary, kval)) { rb_ary_push(ary, kval); } } return ST_CONTINUE; } /* * call-seq: * mod.class_variables => array * * Returns an array of the names of class variables in mod and * the ancestors of mod. * * class One * @@var1 = 1 * end * class Two < One * @@var2 = 2 * end * One.class_variables #=> ["@@var1"] * Two.class_variables #=> ["@@var2", "@@var1"] */ VALUE rb_mod_class_variables(obj) VALUE obj; { VALUE ary = rb_ary_new(); for (;;) { if (RCLASS(obj)->iv_tbl) { st_foreach_safe(RCLASS(obj)->iv_tbl, cv_i, ary); } obj = RCLASS(obj)->super; if (!obj) break; } return ary; } /* * call-seq: * remove_class_variable(sym) => obj * * Removes the definition of the sym, returning that * constant's value. * * class Dummy * @@var = 99 * puts @@var * remove_class_variable(:@@var) * puts(defined? @@var) * end * * produces: * * 99 * nil */ VALUE rb_mod_remove_cvar(mod, name) VALUE mod, name; { ID id = rb_to_id(name); VALUE val; if (!rb_is_class_id(id)) { rb_name_error(id, "wrong class variable name %s", rb_id2name(id)); } if (!OBJ_TAINTED(mod) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't remove class variable"); if (OBJ_FROZEN(mod)) rb_error_frozen("class/module"); if (RCLASS(mod)->iv_tbl && st_delete(ROBJECT(mod)->iv_tbl, (st_data_t*)&id, &val)) { return val; } if (rb_cvar_defined(mod, id)) { rb_name_error(id, "cannot remove %s for %s", rb_id2name(id), rb_class2name(mod)); } rb_name_error(id, "class variable %s not defined for %s", rb_id2name(id), rb_class2name(mod)); return Qnil; /* not reached */ } VALUE rb_iv_get(obj, name) VALUE obj; const char *name; { ID id = rb_intern(name); return rb_ivar_get(obj, id); } VALUE rb_iv_set(obj, name, val) VALUE obj; const char *name; VALUE val; { ID id = rb_intern(name); return rb_ivar_set(obj, id, val); } ================================================ FILE: version.c ================================================ /********************************************************************** version.c - $Author$ $Date$ created at: Thu Sep 30 20:08:01 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #include "ruby.h" #include "rubysig.h" #include "version.h" #include #define PRINT(type) puts(ruby_##type) #define MKSTR(type) rb_obj_freeze(rb_str_new(ruby_##type, sizeof(ruby_##type)-1)) const char ruby_engine[] = RUBY_ENGINE; const char ruby_version[] = RUBY_VERSION; const char ruby_release_date[] = RUBY_RELEASE_DATE; const char ruby_platform[] = RUBY_PLATFORM; const int ruby_patchlevel = RUBY_PATCHLEVEL; const char *ruby_description; const char *ruby_copyright; #define REE_VERSION "2010.02" #define KIJI_VERSION "0.11" const char ruby_kiji_version[] = KIJI_VERSION; void Init_version() { static char description[128]; static char copyright[128]; VALUE e = MKSTR(engine); VALUE v = MKSTR(version); VALUE d = MKSTR(release_date); VALUE p = MKSTR(platform); VALUE k = MKSTR(kiji_version); VALUE tmp; rb_define_global_const("RUBY_ENGINE", e); rb_define_global_const("RUBY_VERSION", v); rb_define_global_const("RUBY_RELEASE_DATE", d); rb_define_global_const("RUBY_PLATFORM", p); rb_define_global_const("RUBY_PATCHLEVEL", INT2FIX(RUBY_PATCHLEVEL)); rb_define_global_const("KIJI_VERSION", k); snprintf(description, sizeof(description), "ruby %s (%s %s %d) [%s], MBARI 0x%x, " "Ruby Enterprise Edition %s, Kiji %s", RUBY_VERSION, RUBY_RELEASE_DATE, RUBY_RELEASE_STR, RUBY_RELEASE_NUM, RUBY_PLATFORM, STACK_WIPE_SITES, REE_VERSION, KIJI_VERSION); ruby_description = description; tmp = rb_obj_freeze(rb_str_new2(description)); rb_define_global_const("RUBY_DESCRIPTION", tmp); snprintf(copyright, sizeof(copyright), "ruby - Copyright (C) %d-%d %s", RUBY_BIRTH_YEAR, RUBY_RELEASE_YEAR, RUBY_AUTHOR); ruby_copyright = copyright; tmp = rb_obj_freeze(rb_str_new2(copyright)); rb_define_global_const("RUBY_COPYRIGHT", tmp); /* obsolete constants */ rb_define_global_const("VERSION", v); rb_define_global_const("RELEASE_DATE", d); rb_define_global_const("PLATFORM", p); } void ruby_show_version() { PRINT(description); fflush(stdout); } void ruby_show_copyright() { PRINT(copyright); exit(0); } ================================================ FILE: version.h ================================================ #define RUBY_ENGINE "ruby" #define RUBY_VERSION "1.8.7" #define RUBY_RELEASE_DATE "2010-04-19" #define RUBY_VERSION_CODE 187 #define RUBY_RELEASE_CODE 20100419 #define RUBY_PATCHLEVEL 253 #define RUBY_VERSION_MAJOR 1 #define RUBY_VERSION_MINOR 8 #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_YEAR 2010 #define RUBY_RELEASE_MONTH 4 #define RUBY_RELEASE_DAY 19 #ifdef RUBY_EXTERN RUBY_EXTERN const char ruby_version[]; RUBY_EXTERN const char ruby_release_date[]; RUBY_EXTERN const char ruby_platform[]; RUBY_EXTERN const int ruby_patchlevel; RUBY_EXTERN const char *ruby_description; RUBY_EXTERN const char *ruby_copyright; #endif #define RUBY_AUTHOR "Yukihiro Matsumoto" #define RUBY_BIRTH_YEAR 1993 #define RUBY_BIRTH_MONTH 2 #define RUBY_BIRTH_DAY 24 #define RUBY_RELEASE_STR "patchlevel" #define RUBY_RELEASE_NUM RUBY_PATCHLEVEL ================================================ FILE: vms/vms.h ================================================ #ifndef VMSRUBY_VMS_H_INCLUDED #define VMSRUBY_VMS_H_INCLUDED extern int isinf(double); extern int isnan(double); extern int flock(int fd, int oper); extern int vsnprintf(); #endif ================================================ FILE: vms/vmsruby_private.c ================================================ #include "vmsruby_private.h" #include #include void _vmsruby_init(void) { _vmsruby_set_switch("DECC$WLS", "TRUE"); } #include #include #include #include struct item_list_3 { short buflen; short itmcod; void *bufadr; void *retlen; }; long _vmsruby_set_switch(char *name, char *value) { long status; struct item_list_3 itemlist[20]; int i; i = 0; itemlist[i].itmcod = LNM$_STRING; itemlist[i].buflen = strlen(value); itemlist[i].bufadr = value; itemlist[i].retlen = NULL; i++; itemlist[i].itmcod = 0; itemlist[i].buflen = 0; $DESCRIPTOR(TABLE_d, "LNM$PROCESS"); $DESCRIPTOR(lognam_d, ""); lognam_d.dsc$a_pointer = name; lognam_d.dsc$w_length = strlen(name); status = sys$crelnm ( 0, &TABLE_d, &lognam_d, 0, /* usermode */ itemlist); return status; } ================================================ FILE: vms/vmsruby_private.h ================================================ #ifndef VMSRUBY_H_INCLUDED #define VMSRUBY_H_INCLUDED void _vmsruby_init(void); long _vmsruby_set_switch(char *, char *); #endif /* VMSRUBY_H_INCLUDED */ ================================================ FILE: win32/Makefile.sub ================================================ # -*- makefile -*- SHELL = $(COMSPEC) MKFILES = Makefile NULL = nul !ifndef MFLAGS MFLAGS=-l !endif !ifndef CROSS_COMPILING CROSS_COMPILING = 0 !endif !ifndef LARGEFILE_SUPPORT LARGEFILE_SUPPORT = 1 !endif !ifndef win_srcdir win_srcdir = $(srcdir)/win32 !endif #### Start of system configuration section. #### ## variables may be overridden by $(compile_dir)/Makefile !ifndef srcdir srcdir = .. !endif !ifndef RUBY_INSTALL_NAME RUBY_INSTALL_NAME = ruby$(RUBY_SUFFIX) !endif !if !defined(RUBYW_INSTALL_NAME) || "$(RUBYW_INSTALL_NAME)" == "$(RUBY_INSTALL_NAME)" RUBYW_INSTALL_NAME = $(RUBY_INSTALL_NAME:ruby=rubyw) !endif !if "$(RUBYW_INSTALL_NAME)" == "$(RUBY_INSTALL_NAME)" RUBYW_INSTALL_NAME = $(RUBY_INSTALL_NAME)w !endif !if !defined(icondirs) && defined(ICONDIRS) icondirs=$(ICONDIRS) !endif !if defined(icondirs) icondirs=$(icondirs:\=/) iconinc=-I$(icondirs: = -I) !endif ############### VPATH = $(srcdir);$(srcdir)/missing;$(srcdir)/win32 .SUFFIXES: .y .def .lib !if !defined(CC) CC = cl !endif !if !defined(CPP) || "$(CPP)" == "cl" CPP = $(CC) -E !endif !if !defined(YACC) YACC = byacc !endif AR = lib -nologo PURIFY = AUTOCONF = autoconf RM = $(COMSPEC) /C $(srcdir:/=\)\win32\rm.bat !if !defined(PROCESSOR_ARCHITECTURE) PROCESSOR_ARCHITECTURE = x86 !endif MACHINE = $(PROCESSOR_ARCHITECTURE) !if "$(PROCESSOR_ARCHITECTURE)" == "x86" !if !defined(PROCESSOR_LEVEL) PROCESSOR_LEVEL = 5 !endif !if 6 < $(PROCESSOR_LEVEL) PROCESSOR_LEVEL = 6 !endif !if $(MSC_VER) < 1400 PROCESSOR_FLAG = -G$(PROCESSOR_LEVEL) !endif CPU = i$(PROCESSOR_LEVEL)86 ARCH = i386 !else CPU = $(PROCESSOR_ARCHITECTURE) ARCH = $(PROCESSOR_ARCHITECTURE) !endif !if !defined(DEBUGFLAGS) && $(MSC_VER) < 1400 DEBUGFLAGS = -Zi !endif !if !defined(OPTFLAGS) !if $(MSC_VER) < 1400 OPTFLAGS = -O2b2xg- !else OPTFLAGS = -O2b2xty- !endif !endif !if !defined(OS) OS = mswin32 !endif !if !defined(RT) !error RT not defined. Retry from configure pass. !endif arch = $(ARCH)-$(OS) !ifndef RUBY_SO_NAME RUBY_SO_NAME = $(RT)-$(RUBY_INSTALL_NAME)$(MAJOR)$(MINOR) !endif !ifndef RUBY_PLATFORM RUBY_PLATFORM = $(arch) !endif !if !defined(prefix) prefix = /usr !endif !if !defined(exec_prefix) exec_prefix = $(prefix) !endif !if !defined(libdir) libdir = $(exec_prefix)/lib !endif !if !defined(datadir) datadir = /share !endif !ifndef EXTOUT EXTOUT = .ext !endif !ifndef RIDATADIR RIDATADIR = $(DESTDIR)$(datadir)/ri/$(MAJOR).$(MINOR)/system !endif !ifndef TESTUI TESTUI = console !endif !ifndef TESTS TESTS = !endif !ifndef RDOCTARGET RDOCTARGET = install-nodoc !endif OUTFLAG = -Fe !if !defined(RUNTIMEFLAG) RUNTIMEFLAG = -MD !endif !if !defined(CFLAGS) CFLAGS = $(RUNTIMEFLAG) $(DEBUGFLAGS) $(WARNFLAGS) $(OPTFLAGS) $(PROCESSOR_FLAG) !endif !if !defined(LDFLAGS) LDFLAGS = -link -incremental:no -debug -opt:ref -opt:icf !endif !if !defined(XLDFLAGS) XLDFLAGS = -stack:$(STACK) !endif !if !defined(RFLAGS) RFLAGS = -r !endif !if !defined(EXTLIBS) EXTLIBS = !endif !if !defined(LIBS) LIBS = oldnames.lib user32.lib advapi32.lib shell32.lib !if !defined(USE_WINSOCK2) LIBS = $(LIBS) wsock32.lib !else LIBS = $(LIBS) ws2_32.lib !endif LIBS = $(LIBS) $(EXTLIBS) !endif !if !defined(MISSING) MISSING = acosh.obj crypt.obj erf.obj win32.obj !endif ARFLAGS = -machine:$(MACHINE) -out: CC = $(CC) -nologo LD = $(CC) LDSHARED = $(LD) -LD XCFLAGS = -DRUBY_EXPORT -I. -I$(srcdir) -I$(srcdir)/missing $(XCFLAGS) !if $(MSC_VER) >= 1400 # Prevents VC++ 2005 (cl ver 14) warnings CRTDEFFLAGS = -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE MANIFESTTOOL = mt -nologo LDSHARED_1 = @if exist $(@).manifest $(MANIFESTTOOL) -manifest $(@).manifest -outputresource:$(@);2 LDSHARED_2 = @if exist $(@).manifest $(RM) $(@:/=\).manifest !endif CPPFLAGS = $(CRTDEFFLAGS) $(DEFS) $(ARCHDEFS) $(CPPFLAGS) DLDFLAGS = $(LDFLAGS) -dll SOLIBS = LIBRUBY_LDSHARED = $(LDSHARED) LIBRUBY_DLDFLAGS = $(EXTLDFLAGS) -def:$(RUBYDEF) EXEEXT = .exe !if !defined(PROGRAM) PROGRAM=$(RUBY_INSTALL_NAME)$(EXEEXT) !endif !if !defined(WPROGRAM) && defined(RUBYW_INSTALL_NAME) WPROGRAM=$(RUBYW_INSTALL_NAME)$(EXEEXT) !endif RUBYDEF = $(RUBY_SO_NAME).def !if $(CROSS_COMPILING) MINIRUBY = $(RUBY) -I$(MAKEDIR) -rfake RUNRUBY = $(MINIRUBY) !else MINIRUBY = .\miniruby$(EXEEXT) -I$(srcdir)/lib RUNRUBY = .\$(PROGRAM) !endif MINIRUBY = $(MINIRUBY) $(MINIRUBYOPT) RUNRUBY = $(RUNRUBY) "$(srcdir)/runruby.rb" --extout="$(EXTOUT)" -- !if !defined(STACK) STACK = 0x2000000 !if defined(STACK_COMMIT) STACK = $(STACK),$(STACK_COMMIT) !endif !endif ORGLIBPATH = $(LIB) #### End of system configuration section. #### LIBRUBY_A = $(RUBY_SO_NAME)-static.lib LIBRUBY_SO = $(RUBY_SO_NAME).dll LIBRUBY = $(RUBY_SO_NAME).lib LIBRUBYARG = $(LIBRUBY) !if $(CROSS_COMPILING) PREP = fake.rb !else PREP = miniruby$(EXEEXT) !endif !if !defined(EXTSTATIC) EXTSTATIC = !endif OBJEXT = obj ASMEXT = asm INSTALLED_LIST= .installed.list !if !defined(WINMAINOBJ) WINMAINOBJ = winmain.$(OBJEXT) !endif MINIOBJS = dmydln.$(OBJEXT) LIBOBJS = acosh.obj crypt.obj erf.obj strlcpy.obj strlcat.obj win32.obj $(LIBOBJS) !ifndef COMMON_LIBS COMMON_LIBS = m !endif !ifndef COMMON_MACROS COMMON_MACROS = WIN32_LEAN_AND_MEAN WIN32 !endif !ifndef COMMON_HEADERS !if !defined(USE_WINSOCK2) COMMON_HEADERS = winsock.h !else COMMON_HEADERS = winsock2.h ws2tcpip.h !endif COMMON_HEADERS = $(COMMON_HEADERS) windows.h !endif all: $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub $(srcdir)/common.mk ruby: $(PROGRAM) rubyw: $(WPROGRAM) !include $(srcdir)/common.mk $(MKFILES): $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub $(win_srcdir)/configure.bat $(win_srcdir)/setup.mak $(COMSPEC) /C $(win_srcdir:/=\)\configure.bat $(configure_args) @echo $(MKFILES) should be updated, re-run $(MAKE). @exit 1 CONFIG_H = ./.config.h.time config: config.status config.status: $(CONFIG_H) BANG = ! !if exist(config.h) !include config.h !endif $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub @echo Creating config.h @$(COMSPEC) /C $(srcdir:/=\)\win32\ifchange.bat config.h << #if _MSC_VER != $(MSC_VER) #error MSC version unmatch: _MSC_VER: $(MSC_VER) is expected. #endif !if defined(USE_WINSOCK2) #define USE_WINSOCK2 $(USE_WINSOCK2) !endif #define STDC_HEADERS 1 #define HAVE_SYS_TYPES_H 1 #define HAVE_SYS_STAT_H 1 #define HAVE_STDLIB_H 1 #define HAVE_STRING_H 1 #define HAVE_MEMORY_H 1 !if $(MSC_VER) >= 1400 #define HAVE_LONG_LONG 1 !endif #define HAVE_OFF_T 1 #define SIZEOF_INT 4 #define SIZEOF_SHORT 2 #define SIZEOF_LONG 4 !if $(MSC_VER) >= 1400 #define SIZEOF_LONG_LONG 8 !else #define SIZEOF_LONG_LONG 0 !endif #define SIZEOF___INT64 8 #define SIZEOF_OFF_T 4 #define SIZEOF_VOIDP 4 #define SIZEOF_FLOAT 4 #define SIZEOF_DOUBLE 8 !if $(MSC_VER) >= 1400 #define SIZEOF_TIME_T 8 !else #define SIZEOF_TIME_T 4 !endif #define HAVE_PROTOTYPES 1 #define TOKEN_PASTE(x,y) x##y #define HAVE_STDARG_PROTOTYPES 1 !if $(MSC_VER) > 1100 #define NORETURN(x) __declspec(noreturn) x !endif !if $(MSC_VER) >= 1300 #define DEPRECATED(x) __declspec(deprecated) x #define NOINLINE(x) __declspec(noinline) x !endif #define RUBY_EXTERN extern __declspec(dllimport) #define HAVE_DECL_SYS_NERR 1 !if !defined(WIN32_WCE) #define HAVE_LIMITS_H 1 !endif #define HAVE_FCNTL_H 1 #define HAVE_SYS_UTIME_H 1 #define HAVE_FLOAT_H 1 #define rb_pid_t int #define rb_gid_t int #define rb_uid_t int #define HAVE_STRUCT_STAT_ST_RDEV 1 #define HAVE_ST_RDEV 1 #define GETGROUPS_T int #define RETSIGTYPE void !if !defined(WIN32_WCE) #define HAVE_ALLOCA 1 !endif #define HAVE_DUP2 1 #define HAVE_MEMCMP 1 #define HAVE_MEMMOVE 1 #define HAVE_MKDIR 1 #define HAVE_STRCASECMP 1 #define HAVE_STRNCASECMP 1 #define HAVE_STRERROR 1 #define HAVE_STRFTIME 1 #define HAVE_STRCHR 1 #define HAVE_STRSTR 1 #define HAVE_STRTOD 1 #define HAVE_STRTOL 1 #define HAVE_STRTOUL 1 #define HAVE_FLOCK 1 #define HAVE_VSNPRINTF 1 #define HAVE_ISNAN 1 #define HAVE_FINITE 1 #define HAVE_HYPOT 1 #define HAVE_FMOD 1 #define HAVE_FREXP 1 #define HAVE_MODF 1 #define HAVE_WAITPID 1 #define HAVE_FSYNC 1 #define HAVE_GETCWD 1 #define HAVE_CHSIZE 1 #define HAVE_TIMES 1 #define HAVE_FCNTL 1 #define HAVE_LINK 1 !if !defined(WIN32_WCE) #define HAVE__SETJMP 1 !endif #define HAVE_TELLDIR 1 #define HAVE_SEEKDIR 1 #define HAVE_MKTIME 1 #define HAVE_COSH 1 #define HAVE_SINH 1 #define HAVE_TANH 1 #define HAVE_TZNAME 1 #define HAVE_DAYLIGHT 1 #define SETPGRP_VOID 1 #define RSHIFT(x,y) ((x)>>(int)y) #define FILE_COUNT _cnt #define FILE_READPTR _ptr #define RUBY_SETJMP(env) _setjmp(env) #define RUBY_LONGJMP(env,val) longjmp(env,val) #define RUBY_JMP_BUF jmp_buf #define inline __inline #define NEED_IO_SEEK_BETWEEN_RW 1 !if "$(PROCESSOR_ARCHITECTURE)" == "x86" || "$(ARCH)" == "x64" || "$(ARCH)" == "ia64" #define STACK_GROW_DIRECTION -1 !endif #define DEFAULT_KCODE KCODE_NONE #define DLEXT ".so" #define DLEXT2 ".dll" #define RUBY_LIB "/lib/ruby/$(MAJOR).$(MINOR)" #define RUBY_SITE_LIB "/lib/ruby/site_ruby" #define RUBY_SITE_LIB2 "/lib/ruby/site_ruby/$(MAJOR).$(MINOR)" #define RUBY_VENDOR_LIB "/lib/ruby/vendor_ruby" #define RUBY_VENDOR_LIB2 "/lib/ruby/vendor_ruby/$(MAJOR).$(MINOR)" #define RUBY_PLATFORM "$(arch)" #define RUBY_ARCHLIB "/lib/ruby/$(MAJOR).$(MINOR)/$(ARCH)-$(OS)" #define RUBY_SITE_ARCHLIB "/lib/ruby/site_ruby/$(MAJOR).$(MINOR)/$(ARCH)-$(RT)" #define RUBY_VENDOR_ARCHLIB "/lib/ruby/vendor_ruby/$(MAJOR).$(MINOR)/$(ARCH)-$(RT)" #define LIBRUBY_SO "$(LIBRUBY_SO)" #if 0 $(BANG)if "$(RUBY_SO_NAME)"!="$$(RUBY_SO_NAME)" || "$(ARCH)-$(OS)"!="$$(ARCH)-$$(OS)" config.h: nul $(BANG)endif #endif !if defined(WIN32_WCE) #define GC_MALLOC_LIMIT 4000000 #define stricmp _stricmp #define fopen wce_fopen #define open _open #define read _read #define write _write #define lseek _lseek #if _WIN32_WCE < 300 #define isascii(c) ( (c>=0x00&&c<=0x7f)?1:0 ) #define isspace(c) ( ((c>=0x09&&c<=0x0d)||c==0x20)?1:0 ) #define isdigit(c) ( (c>=0x30&&c<=0x39)?1:0 ) #define isupper(c) ( (c>='A'&&c<='Z')?1:0 ) #define isalpha(c) ( ((c>='A'&&c<='Z')||(c>='a'&&c<='z'))?1:0 ) #define isprint(c) ( (c>=0x20&&c<=0x7e)?1:0 ) #define isalnum(c) ( (isalpha(c)||isdigit(c))?1:0 ) #define iscntrl(c) ( ((c>=0x00&&c<=0x1f)||c==0x7f)?1:0 ) #define islower(c) ( (c>='a'&&c<='z')?1:0 ) #define ispunct(c) ( !(isalnum(c)||isspace(c))?1:0 ) #define isxdigit(c) ( ((c>=0&&c<=9)||(c>='A'&&c<='F')||(c>='a'&&c<='f'))?1:0 ) #endif !endif << @exit > $(@:/=\) config.status: $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub $(srcdir)/common.mk @echo Creating $@ @exit <<$@ # Generated automatically by Makefile.sub. s,@SHELL@,$$(COMSPEC),;t t s,@BUILD_FILE_SEPARATOR@,\,;t t s,@PATH_SEPARATOR@,;,;t t s,@CFLAGS@,$(CFLAGS),;t t s,@CPPFLAGS@,$(CPPFLAGS),;t t s,@CXXFLAGS@,$(CXXFLAGS),;t t s,@FFLAGS@,$(FFLAGS),;t t s,@LDFLAGS@,,;t t s,@LIBS@,$(LIBS),;t t s,@exec_prefix@,$${prefix},;t t s,@prefix@,,;t t s,@program_transform_name@,s,$$,$(RUBY_SUFFIX),,;t t s,@bindir@,$${exec_prefix}/bin,;t t s,@sbindir@,$${exec_prefix}/sbin,;t t s,@libexecdir@,$${exec_prefix}/libexec,;t t s,@datadir@,$${prefix}/share,;t t s,@sysconfdir@,$${prefix}/etc,;t t s,@sharedstatedir@,/etc,;t t s,@localstatedir@,/var,;t t s,@libdir@,$${exec_prefix}/lib,;t t s,@includedir@,$${prefix}/include,;t t s,@oldincludedir@,/usr/include,;t t s,@infodir@,$${prefix}/info,;t t s,@mandir@,$${prefix}/man,;t t s,@build@,$(CPU)-pc-$(OS),;t t s,@build_alias@,$(CPU)-$(OS),;t t s,@build_cpu@,$(CPU),;t t s,@build_vendor@,pc,;t t s,@build_os@,$(OS),;t t s,@host@,$(CPU)-pc-$(OS),;t t s,@host_alias@,$(CPU)-$(OS),;t t s,@host_cpu@,$(CPU),;t t s,@host_vendor@,pc,;t t s,@host_os@,$(OS),;t t s,@target@,$(ARCH)-pc-$(OS),;t t s,@target_alias@,$(ARCH)-$(OS),;t t s,@target_cpu@,$(ARCH),;t t s,@target_vendor@,pc,;t t s,@target_os@,$(OS),;t t s,@CC@,$(CC),;t t s,@CPP@,$(CPP),;t t s,@YACC@,$(YACC),;t t s,@RANLIB@,,;t t s,@AR@,$(AR),;t t s,@ARFLAGS@,$(ARFLAGS),;t t s,@LN_S@,$(LN_S),;t t s,@SET_MAKE@,MFLAGS = -$$(MAKEFLAGS),;t t s,@CP@,copy > nul,;t t s,@LIBOBJS@,$(LIBOBJS),;t t s,@ALLOCA@,$(ALLOCA),;t t s,@DEFAULT_KCODE@,$(DEFAULT_KCODE),;t t s,@EXEEXT@,.exe,;t t s,@OBJEXT@,$(OBJEXT),;t t s,@XCFLAGS@,$(XCFLAGS),;t t s,@XLDFLAGS@,$(XLDFLAGS),;t t s,@DLDFLAGS@,$(DLDFLAGS) $$(LIBPATH),;t t s,@ARCH_FLAG@,$(ARCH_FLAG),;t t s,@STATIC@,$(STATIC),;t t s,@CCDLFLAGS@,,;t t s,@LDSHARED@,$(LDSHARED),;t t s,@DLEXT@,so,;t t s,@DLEXT2@,dll,;t t s,@LIBEXT@,lib,;t t s,@STRIP@,$(STRIP),;t t s,@EXTSTATIC@,$(EXTSTATIC),;t t s,@setup@,Setup,;t t s,@MINIRUBY@,$(MINIRUBY),;t t s,@PREP@,miniruby$(EXEEXT),;t t s,@RUNRUBY@,$(RUNRUBY),;t t s,@EXTOUT@,$(EXTOUT),;t t s,@ARCHFILE@,,;t t s,@RDOCTARGET@,$(RDOCTARGET),;t t s,@LIBRUBY_LDSHARED@,$(LIBRUBY_LDSHARED),;t t s,@LIBRUBY_DLDFLAGS@,$(LIBRUBY_DLDFLAGS),;t t s,@RUBY_INSTALL_NAME@,$(RUBY_INSTALL_NAME),;t t s,@rubyw_install_name@,$(RUBYW_INSTALL_NAME),;t t s,@RUBYW_INSTALL_NAME@,$(RUBYW_INSTALL_NAME),;t t s,@RUBY_SO_NAME@,$(RUBY_SO_NAME),;t t s,@LIBRUBY_A@,$$(RUBY_SO_NAME)-static.lib,;t t s,@LIBRUBY_SO@,$$(RUBY_SO_NAME).dll,;t t s,@LIBRUBY_ALIASES@,$(LIBRUBY_ALIASES),;t t s,@LIBRUBY@,$$(RUBY_SO_NAME).lib,;t t s,@LIBRUBYARG@,$$(LIBRUBYARG_SHARED),;t t s,@LIBRUBYARG_STATIC@,$$(LIBRUBY_A),;t t s,@LIBRUBYARG_SHARED@,$$(LIBRUBY),;t t s,@SOLIBS@,$(SOLIBS),;t t s,@DLDLIBS@,$(DLDLIBS),;t t s,@ENABLE_SHARED@,yes,;t t s,@OUTFLAG@,$(OUTFLAG),;t t s,@CPPOUTFILE@,-P,;t t s,@LIBPATHFLAG@, -libpath:"%s",;t t s,@RPATHFLAG@,,;t t s,@LIBARG@,%s.lib,;t t s,@LINK_SO@,$$(LDSHARED) -Fe$$(@) $$(OBJS) $$(LIBS) $$(LOCAL_LIBS) $$(DLDFLAGS) -implib:$$(*F:.so=)-$$(arch).lib -pdb:$$(*F:.so=)-$$(arch).pdb -def:$$(DEFFILE),;t t !if $(MSC_VER) >= 1400 s,@LINK_SO@,$(MANIFESTTOOL) -manifest $$(@).manifest -outputresource:$$(@);2,;t t s,@LINK_SO@,@$$(RM) $$(@:/=\).manifest,;t t !endif s,@COMPILE_C@,$$(CC) $$(INCFLAGS) $$(CFLAGS) $$(CPPFLAGS) -c -Tc$$(<:\=/),;t t s,@COMPILE_CXX@,$$(CXX) $$(INCFLAGS) $$(CXXFLAGS) $$(CPPFLAGS) -c -Tp$$(<:\=/),;t t s,@COMPILE_RULES@,{$$(hdrdir)}.%s{}.%s: {$$(topdir)}.%s{}.%s: {$$(srcdir)}.%s{}.%s: .%s.%s:,;t t s,@RULE_SUBST@,{.;$$(VPATH)}%s,;t t s,@TRY_LINK@,$$(CC) -Feconftest $$(INCFLAGS) -I$$(hdrdir) $$(CPPFLAGS) $$(CFLAGS) $$(src) $$(LOCAL_LIBS) $$(LIBS) -link $$(LDFLAGS) $$(LIBPATH) $$(XLDFLAGS),;t t s,@COMMON_LIBS@,$(COMMON_LIBS),;t t s,@COMMON_MACROS@,$(COMMON_MACROS),;t t s,@COMMON_HEADERS@,$(COMMON_HEADERS),;t t s,@DISTCLEANFILES@,vc*.pdb,;t t s,@EXPORT_PREFIX@, ,;t t s,@arch@,$(ARCH)-$(OS),;t t s,@sitearch@,$(ARCH)-$(RT),;t t s,@sitedir@,$${prefix}/lib/ruby/site_ruby,;t t s,@vendordir@,$${prefix}/lib/ruby/vendor_ruby,;t t s,@configure_args@,--with-make-prog=nmake --enable-shared $(configure_args),;t t s,@configure_input@,$$configure_input,;t t s,@srcdir@,$(srcdir),;t t s,@top_srcdir@,$(srcdir),;t t < $@ @del y.tab.c $(OBJS): {$(srcdir)}win32/win32.h dir.$(OBJEXT) win32.$(OBJEXT): {$(srcdir)}win32/dir.h ext/extinit.obj: ext/extinit.c $(SETUP) $(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -Fo$@ -c ext/extinit.c ================================================ FILE: win32/README.win32 ================================================ =begin = How to build ruby using Visual C++ == Requirement (1) Visual C++ 5.0 or later. (2) If you want to run `((%nmake clean%))' or `((%nmake distclean%))' properly, you must install UNIX compatible `((%rm%))' command on your ((|PATH|)) if you want to clean after compile. (3) Please set environment variable (({INCLUDE})), (({LIB})), (({PATH})) to run required commands properly from the command line. Note: building ruby requires following commands. * nmake * cl * lib * dumpbin == How to compile and install (1) Execute win32\configure.bat on your build directory. You can specify the target platform as an argument. For example, run `((%configure i686-mswin32%))' (2) Change ((|RUBY_INSTALL_NAME|)) and ((|RUBY_SO_NAME|)) in (({Makefile})) if you want to change the name of the executable files. And add ((|RUBYW_INSTALL_NAME|)) to change the name of the executable without console window if also you want. (3) Run `((%nmake%))' (4) If you want to make rubyw.exe, run `((%nmake rubyw.exe%))' (5) Run `((%nmake test%))' (6) Run `((%nmake DESTDIR= install%))' This command will create following directories and install files onto them. * \bin * \lib * \lib\ruby * \lib\ruby\. * \lib\ruby\.\ * \lib\ruby\site_ruby * \lib\ruby\site_ruby\. * \lib\ruby\site_ruby\.\ * \man\man1 If Ruby's version is `x.y.z', the ((||)) is `x' and the ((||)) is `y'. The default ((||)) is `(({i386-mswin32}))'. == Icons Any icon files(*.ico) in the build directory, directories specified with ((|icondirs|)) make variable and (({win32})) directory under the ruby source directory will be included in DLL or executable files, according to their base names. $(RUBY_INSTALL_NAME).ico or ruby.ico --> $(RUBY_INSTALL_NAME).exe $(RUBYW_INSTALL_NAME).ico or rubyw.ico --> $(RUBYW_INSTALL_NAME).exe the others --> $(RUBY_SO_NAME).dll Although no icons are distributed with the ruby source or in the official site, you can use anything you like. For example, followings are written in Japanese, but you can download at least. * (()) or (()) * (()) or (()) == Build examples * Build on the ruby source directory. ex.) ruby source directory: C:\ruby build directory: C:\ruby install directory: C:\usr\local C: cd \ruby win32\configure nmake nmake test nmake DESTDIR=/usr/local install * Build on the relative directory from the ruby source directory. ex.) ruby source directory: C:\ruby build directory: C:\ruby\mswin32 install directory: C:\usr\local C: cd \ruby mkdir mswin32 cd mswin32 ..\win32\configure nmake nmake test nmake DESTDIR=/usr/local install * Build on the different drive. ex.) ruby source directory: C:\src\ruby build directory: D:\build\ruby install directory: C:\usr\local D: cd D:\build\ruby C:\src\ruby\win32\configure nmake nmake test nmake DESTDIR=C:/usr/local install == Bugs You can ((*NOT*)) use a path name contains any white space characters as the ruby source directory, this restriction comes from the behavior of (({!INCLUDE})) directives of (({NMAKE})). ((- you may call it a bug. -)) =end ================================================ FILE: win32/configure.bat ================================================ @echo off ::: Don't set environment variable in batch file other than autoexec.bat ::: to avoid "Out of environment space" problem on Windows 95/98. ::: set TMPMAKE=~tmp~.mak echo> ~tmp~.mak #### echo>> ~tmp~.mak conf = %0 echo>> ~tmp~.mak $(conf:\=/): nul echo>> ~tmp~.mak @del ~tmp~.mak echo>> ~tmp~.mak @-$(MAKE) -l$(MAKEFLAGS) -f $(@D)/setup.mak \ :loop if "%1" == "" goto :end if "%1" == "--prefix" goto :prefix if "%1" == "--srcdir" goto :srcdir if "%1" == "srcdir" goto :srcdir if "%1" == "--target" goto :target if "%1" == "target" goto :target if "%1" == "--with-static-linked-ext" goto :extstatic if "%1" == "--with-winsock2" goto :winsock2 if "%1" == "--program-suffix" goto :suffix if "%1" == "--program-name" goto :installname if "%1" == "--install-name" goto :installname if "%1" == "--so-name" goto :soname if "%1" == "--enable-install-doc" goto :enable-rdoc if "%1" == "--disable-install-doc" goto :disable-rdoc if "%1" == "--extout" goto :extout if "%1" == "-h" goto :help if "%1" == "--help" goto :help echo>> ~tmp~.mak "%1" \ shift goto :loop :srcdir echo>> ~tmp~.mak "srcdir=%2" \ shift shift goto :loop :prefix echo>> ~tmp~.mak "prefix=%2" \ shift shift goto :loop :suffix echo>> ~tmp~.mak "RUBY_SUFFIX=%2" \ shift shift goto :loop :installname echo>> ~tmp~.mak "RUBY_INSTALL_NAME=%2" \ shift shift goto :loop :soname echo>> ~tmp~.mak "RUBY_SO_NAME=%2" \ shift shift goto :loop :target echo>> ~tmp~.mak "%2" \ shift shift goto :loop :extstatic echo>> ~tmp~.mak "EXTSTATIC=static" \ shift goto :loop :winsock2 echo>> ~tmp~.mak "USE_WINSOCK2=1" \ shift goto :loop :enable-rdoc echo>> ~tmp~.mak "RDOCTARGET=install-doc" \ shift goto :loop :disable-rdoc echo>> ~tmp~.mak "RDOCTARGET=install-nodoc" \ shift goto :loop :extout echo>> ~tmp~.mak "EXTOUT=%2" \ shift shift goto :loop :help echo Configuration: echo --help display this help echo --srcdir=DIR find the sources in DIR [configure dir or `..'] echo Installation directories: echo --prefix=PREFIX install files in PREFIX (ignored currently) echo System types: echo --target=TARGET configure for TARGET [i386-mswin32] echo Optional Package: echo --with-winsock2 link winsock2 echo --with-static-linked-ext link external modules statically echo --enable-install-doc install rdoc indexes during install del ~tmp~.mak goto :exit :end echo>> ~tmp~.mak WIN32DIR=$(@D) nmake -alf ~tmp~.mak :exit ================================================ FILE: win32/dir.h ================================================ #ifdef __BORLANDC__ # ifndef WIN32_DIR_H_ # define WIN32_DIR_H_ # include # endif #endif struct direct { long d_namlen; ino_t d_ino; char d_name[256]; char d_isdir; /* directory */ char d_isrep; /* reparse point */ }; typedef struct { char *start; char *curr; long size; long nfiles; long loc; /* [0, nfiles) */ struct direct dirstr; char *bits; /* used for d_isdir and d_isrep */ } DIR; DIR* rb_w32_opendir(const char*); struct direct* rb_w32_readdir(DIR *); long rb_w32_telldir(DIR *); void rb_w32_seekdir(DIR *, long); void rb_w32_rewinddir(DIR *); void rb_w32_closedir(DIR *); #define opendir rb_w32_opendir #define readdir rb_w32_readdir #define telldir rb_w32_telldir #define seekdir rb_w32_seekdir #define rewinddir rb_w32_rewinddir #define closedir rb_w32_closedir ================================================ FILE: win32/ifchange.bat ================================================ @echo off :: usage: ifchange target temporary :: check if fc.exe works. echo foo > conftest1.tmp echo bar > conftest2.tmp fc.exe conftest1.tmp conftest2.tmp > nul if not errorlevel 1 goto :brokenfc del conftest1.tmp > nul del conftest2.tmp > nul :: target does not exist or new file differs from it. if not exist %1 goto :update fc.exe %1 %2 > nul if errorlevel 1 goto :update :unchange echo %1 unchanged. del %2 goto :end :brokenfc del conftest1.tmp > nul del conftest2.tmp > nul echo FC.EXE does not work properly. echo assuming %1 should be changed. :update echo %1 updated. if exist %1 del %1 copy %2 %1 > nul :end ================================================ FILE: win32/mkexports.rb ================================================ #!./miniruby -s $name = $library = $description = nil SYM = {} objs = ARGV.collect {|s| s.tr('/', '\\')} IO.foreach("|dumpbin -symbols " + objs.join(' ')) do |l| next if /^[0-9A-F]+ 0+ UNDEF / =~ l next unless l.sub!(/.*?\s(\(\)\s+)?External\s+\|\s+/, "") is_data = !$1 if /^[@_](?!\w+@\d+$)/ =~ l next if /(?!^)@.*@/ =~ l || /@[0-9a-f]{16}$/ =~ l l.sub!(/^[@_]/, '') elsif !l.sub!(/^(\S+) \([^@?\`\']*\)$/, '\1') next end SYM[l.strip] = is_data end exports = [] if $name exports << "Name " + $name elsif $library exports << "Library " + $library end exports << "Description " + $description.dump if $description exports << "EXPORTS" SYM.sort.each do |sym, is_data| exports << (is_data ? "#{sym} DATA" : sym) end if $output open($output, 'w') {|f| f.puts exports.join("\n")} else puts exports.join("\n") end ================================================ FILE: win32/resource.rb ================================================ #!./miniruby -sI. require 'rbconfig' CONFIG = Config::MAKEFILE_CONFIG version = %w'MAJOR MINOR TEENY PATCHLEVEL'.map {|v| CONFIG[v] || '0'} fversion = version.join(',') rversion = version.join('.') $ruby_name ||= CONFIG["RUBY_INSTALL_NAME"] $rubyw_name ||= CONFIG["RUBYW_INSTALL_NAME"] || $ruby_name.sub(/ruby/, '\&w') $so_name ||= CONFIG["RUBY_SO_NAME"] icons = {} def icons.find(path) if File.directory?(path) Dir.open(File.expand_path(path)) do |d| d.grep(/\.ico$/i) {|i| self[$`] = i} end else self[File.basename(path, '.ico')] = path end self end if ARGV.empty? icons.find('.') else ARGV.each {|i| icons.find(i)} end ruby_icon = rubyw_icon = nil [$ruby_name, 'ruby'].find do |i| if i = icons[i] ruby_icon = "1 ICON DISCARDABLE "+i.dump+"\n" end end [$rubyw_name, 'rubyw'].find do |i| if i = icons[i] rubyw_icon = "1 ICON DISCARDABLE "+i.dump+"\n" end end dll_icons = [] icons.keys.sort.each do |i| dll_icons << "#{dll_icons.size + 1} ICON DISCARDABLE "+icons[i].dump+"\n" end [ # base name extension file type desc, icons [$ruby_name, CONFIG["EXEEXT"], 'VFT_APP', 'CUI', ruby_icon], [$rubyw_name, CONFIG["EXEEXT"], 'VFT_APP', 'GUI', rubyw_icon || ruby_icon], [$so_name, '.dll', 'VFT_DLL', 'DLL', dll_icons.join], ].each do |base, ext, type, desc, icons| open(base + '.rc', "w") { |f| f.binmode if /mingw/ =~ RUBY_PLATFORM f.print < #include #endif #{icons || ''} VS_VERSION_INFO VERSIONINFO FILEVERSION #{fversion} PRODUCTVERSION #{fversion} FILEFLAGSMASK 0x3fL FILEFLAGS 0x0L FILEOS VOS__WINDOWS32 FILETYPE #{type} FILESUBTYPE VFT2_UNKNOWN BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "000004b0" BEGIN VALUE "FileDescription", "Ruby interpreter (#{desc}) #{rversion} [#{RUBY_PLATFORM}]\\0" VALUE "FileVersion", "#{fversion}\\0" VALUE "Home Page", "http://www.ruby-lang.org/\\0" VALUE "InternalName", "#{base + ext}\\0" VALUE "LegalCopyright", "Copyright (C) 1993-#{RUBY_RELEASE_DATE[/\d+/]} Yukihiro Matsumoto\\0" VALUE "OriginalFilename", "#{base + ext}\\0" VALUE "Platform", "#{RUBY_PLATFORM}\\0" VALUE "ProductVersion", "#{fversion}\\0" VALUE "Release Date", "#{RUBY_RELEASE_DATE}\\0" VALUE "Version", "#{rversion}\\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0, 0x4b0 END END EOF } end ================================================ FILE: win32/rm.bat ================================================ @echo off if "%1" == "-f" shift :begin if "%1" == "" goto :end if exist "%1" del "%1" shift goto :begin :end ================================================ FILE: win32/setup.mak ================================================ # -*- makefile -*- !if "$(srcdir)" != "" WIN32DIR = $(srcdir)/win32 !elseif "$(WIN32DIR)" == "win32" srcdir = . !elseif "$(WIN32DIR)" == "$(WIN32DIR:/win32=)/win32" srcdir = $(WIN32DIR:/win32=) !else srcdir = $(WIN32DIR)/.. !endif !ifndef prefix prefix = /usr !endif OS = mswin32 BANG = ! APPEND = echo.>>$(MAKEFILE) !ifdef MAKEFILE MAKE = $(MAKE) -f $(MAKEFILE) !else MAKEFILE = Makefile !endif ARCH = PROCESSOR_ARCHITECTURE CPU = PROCESSOR_LEVEL CC = cl -nologo CPP = $(CC) -EP all: -prologue- -generic- -epilogue- i386-$(OS): -prologue- -i386- -epilogue- i486-$(OS): -prologue- -i486- -epilogue- i586-$(OS): -prologue- -i586- -epilogue- i686-$(OS): -prologue- -i686- -epilogue- alpha-$(OS): -prologue- -alpha- -epilogue- -prologue-: -basic-vars- -system-vars- -version- -program-name- -basic-vars-: nul @type << > $(MAKEFILE) ### Makefile for ruby $(OS) ### MAKE = nmake srcdir = $(srcdir:\=/) prefix = $(prefix:\=/) EXTSTATIC = $(EXTSTATIC) !if defined(USE_WINSOCK2) USE_WINSOCK2 = $(USE_WINSOCK2) !endif !if defined(RDOCTARGET) RDOCTARGET = $(RDOCTARGET) !endif !if defined(EXTOUT) EXTOUT = $(EXTOUT) !endif << -system-vars-: -osname- -runtime- -osname-: nul @echo OS = mswin32 >>$(MAKEFILE) -runtime-: nul @$(CC) -MD < nul #include #include #include #include #include #ifndef MAXPATHLEN # define MAXPATHLEN 1024 #endif int runtime_name() { char libpath[MAXPATHLEN+1]; char *p, *base = NULL, *ver = NULL; HMODULE msvcrt = NULL; MEMORY_BASIC_INFORMATION m; memset(&m, 0, sizeof(m)); if (VirtualQuery(stdin, &m, sizeof(m)) && m.State == MEM_COMMIT) msvcrt = (HMODULE)m.AllocationBase; GetModuleFileName(msvcrt, libpath, sizeof libpath); libpath[sizeof(libpath) - 1] = '\0'; for (p = libpath; *p; p = CharNext(p)) { if (*p == '\\') { base = ++p; } } if (!base) return 0; if (p = strchr(base, '.')) *p = '\0'; for (p = base; *p; p = CharNext(p)) { if (!isascii(*p)) continue; if (isupper(*p)) { *p = tolower(*p); } if (!isdigit(*p)) { ver = NULL; } else if (!ver) { ver = p; } } if (ver) printf("OS = $$(OS)_%s\n", ver); printf("RT = %s\n", base); return 1; } int main(int argc, char **argv) { if (!runtime_name()) return EXIT_FAILURE; return EXIT_SUCCESS; } << @.\rtname >>$(MAKEFILE) @del rtname.* -version-: nul @$(APPEND) @$(CPP) -I$(srcdir) <<"Creating $(MAKEFILE)" | find "=" >>$(MAKEFILE) #include "version.h" MAJOR = RUBY_VERSION_MAJOR MINOR = RUBY_VERSION_MINOR TEENY = RUBY_VERSION_TEENY MSC_VER = _MSC_VER << -program-name-: @type << >>$(MAKEFILE) !ifdef RUBY_SUFFIX RUBY_SUFFIX = $(RUBY_SUFFIX) !endif !ifdef RUBY_INSTALL_NAME RUBY_INSTALL_NAME = $(RUBY_INSTALL_NAME) !endif !ifdef RUBY_SO_NAME RUBY_SO_NAME = $(RUBY_SO_NAME) !endif << -generic-: nul !if defined($(ARCH)) || defined($(CPU)) @type << >>$(MAKEFILE) !if defined($(ARCH)) $(ARCH) = $(PROCESSOR_ARCHITECTURE) !endif !if defined($(CPU)) $(CPU) = $(PROCESSOR_LEVEL) !endif << !endif -alpha-: nul @echo $(ARCH) = alpha>>$(MAKEFILE) -ix86-: nul @echo $(ARCH) = x86>>$(MAKEFILE) -i386-: -ix86- @echo $(CPU) = 3>>$(MAKEFILE) -i486-: -ix86- @echo $(CPU) = 4>>$(MAKEFILE) -i586-: -ix86- @echo $(CPU) = 5>>$(MAKEFILE) -i686-: -ix86- @echo $(CPU) = 6>>$(MAKEFILE) -epilogue-: nul @type << >>$(MAKEFILE) # OS = $(OS) # RUBY_INSTALL_NAME = ruby # RUBY_SO_NAME = $$(RT)-$$(RUBY_INSTALL_NAME)$$(MAJOR)$$(MINOR) # CFLAGS = -nologo -MD $$(DEBUGFLAGS) $$(OPTFLAGS) $$(PROCESSOR_FLAG) # CPPFLAGS = -I. -I$$(srcdir) -I$$(srcdir)/missing -DLIBRUBY_SO=\"$$(LIBRUBY_SO)\" # STACK = 0x2000000 # LDFLAGS = $$(CFLAGS) -Fm # XLDFLAGS = # RFLAGS = -r # EXTLIBS = $(BANG)include $$(srcdir)/win32/Makefile.sub << @$(COMSPEC) /C $(srcdir:/=\)\win32\rm.bat config.h config.status @echo type `$(MAKE)' to make ruby for $(OS). ================================================ FILE: win32/win32.c ================================================ /* * Copyright (c) 1993, Intergraph Corporation * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the perl README file. * * Various Unix compatibility functions and NT specific functions. * * Some of this code was derived from the MSDOS port(s) and the OS/2 port. * */ #include "ruby.h" #include "rubysig.h" #include "dln.h" #include #include #include /* #include */ #include #include #include #include #include #include #include #include #include #if _MSC_VER >= 1400 #include #endif #ifdef __MINGW32__ #include #include #endif #include "win32.h" #include "win32/dir.h" #ifdef _WIN32_WCE #include "wince.h" #endif #ifndef index #define index(x, y) strchr((x), (y)) #endif #define isdirsep(x) ((x) == '/' || (x) == '\\') #undef stat #undef fclose #undef close #undef setsockopt #ifndef bool #define bool int #endif #if defined __BORLANDC__ || defined _WIN32_WCE # define _filbuf _fgetc # define _flsbuf _fputc # define enough_to_get(n) (--(n) >= 0) # define enough_to_put(n) (++(n) < 0) #else # define enough_to_get(n) (--(n) >= 0) # define enough_to_put(n) (--(n) >= 0) #endif #if HAVE_WSAWAITFORMULTIPLEEVENTS # define USE_INTERRUPT_WINSOCK #endif #if USE_INTERRUPT_WINSOCK # define WaitForMultipleEvents WSAWaitForMultipleEvents # define CreateSignal() (HANDLE)WSACreateEvent() # define SetSignal(ev) WSASetEvent(ev) # define ResetSignal(ev) WSAResetEvent(ev) #else /* USE_INTERRUPT_WINSOCK */ # define WaitForMultipleEvents WaitForMultipleObjectsEx # define CreateSignal() CreateEvent(NULL, FALSE, FALSE, NULL); # define SetSignal(ev) SetEvent(ev) # define ResetSignal(ev) (void)0 #endif /* USE_INTERRUPT_WINSOCK */ #ifdef WIN32_DEBUG #define Debug(something) something #else #define Debug(something) /* nothing */ #endif #define TO_SOCKET(x) _get_osfhandle(x) static struct ChildRecord *CreateChild(const char *, const char *, SECURITY_ATTRIBUTES *, HANDLE, HANDLE, HANDLE); static bool has_redirection(const char *); static void StartSockets (); static DWORD wait_events(HANDLE event, DWORD timeout); #if !defined(_WIN32_WCE) static int rb_w32_open_osfhandle(long osfhandle, int flags); #else #define rb_w32_open_osfhandle(osfhandle, flags) _open_osfhandle(osfhandle, flags) #endif /* errno mapping */ static struct { DWORD winerr; int err; } errmap[] = { { ERROR_INVALID_FUNCTION, EINVAL }, { ERROR_FILE_NOT_FOUND, ENOENT }, { ERROR_PATH_NOT_FOUND, ENOENT }, { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, { ERROR_ACCESS_DENIED, EACCES }, { ERROR_INVALID_HANDLE, EBADF }, { ERROR_ARENA_TRASHED, ENOMEM }, { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, { ERROR_INVALID_BLOCK, ENOMEM }, { ERROR_BAD_ENVIRONMENT, E2BIG }, { ERROR_BAD_FORMAT, ENOEXEC }, { ERROR_INVALID_ACCESS, EINVAL }, { ERROR_INVALID_DATA, EINVAL }, { ERROR_INVALID_DRIVE, ENOENT }, { ERROR_CURRENT_DIRECTORY, EACCES }, { ERROR_NOT_SAME_DEVICE, EXDEV }, { ERROR_NO_MORE_FILES, ENOENT }, { ERROR_WRITE_PROTECT, EROFS }, { ERROR_BAD_UNIT, ENODEV }, { ERROR_NOT_READY, ENXIO }, { ERROR_BAD_COMMAND, EACCES }, { ERROR_CRC, EACCES }, { ERROR_BAD_LENGTH, EACCES }, { ERROR_SEEK, EIO }, { ERROR_NOT_DOS_DISK, EACCES }, { ERROR_SECTOR_NOT_FOUND, EACCES }, { ERROR_OUT_OF_PAPER, EACCES }, { ERROR_WRITE_FAULT, EIO }, { ERROR_READ_FAULT, EIO }, { ERROR_GEN_FAILURE, EACCES }, { ERROR_LOCK_VIOLATION, EACCES }, { ERROR_SHARING_VIOLATION, EACCES }, { ERROR_WRONG_DISK, EACCES }, { ERROR_SHARING_BUFFER_EXCEEDED, EACCES }, { ERROR_BAD_NETPATH, ENOENT }, { ERROR_NETWORK_ACCESS_DENIED, EACCES }, { ERROR_BAD_NET_NAME, ENOENT }, { ERROR_FILE_EXISTS, EEXIST }, { ERROR_CANNOT_MAKE, EACCES }, { ERROR_FAIL_I24, EACCES }, { ERROR_INVALID_PARAMETER, EINVAL }, { ERROR_NO_PROC_SLOTS, EAGAIN }, { ERROR_DRIVE_LOCKED, EACCES }, { ERROR_BROKEN_PIPE, EPIPE }, { ERROR_DISK_FULL, ENOSPC }, { ERROR_INVALID_TARGET_HANDLE, EBADF }, { ERROR_INVALID_HANDLE, EINVAL }, { ERROR_WAIT_NO_CHILDREN, ECHILD }, { ERROR_CHILD_NOT_COMPLETE, ECHILD }, { ERROR_DIRECT_ACCESS_HANDLE, EBADF }, { ERROR_NEGATIVE_SEEK, EINVAL }, { ERROR_SEEK_ON_DEVICE, EACCES }, { ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, { ERROR_DIRECTORY, ENOTDIR }, { ERROR_NOT_LOCKED, EACCES }, { ERROR_BAD_PATHNAME, ENOENT }, { ERROR_MAX_THRDS_REACHED, EAGAIN }, { ERROR_LOCK_FAILED, EACCES }, { ERROR_ALREADY_EXISTS, EEXIST }, { ERROR_INVALID_STARTING_CODESEG, ENOEXEC }, { ERROR_INVALID_STACKSEG, ENOEXEC }, { ERROR_INVALID_MODULETYPE, ENOEXEC }, { ERROR_INVALID_EXE_SIGNATURE, ENOEXEC }, { ERROR_EXE_MARKED_INVALID, ENOEXEC }, { ERROR_BAD_EXE_FORMAT, ENOEXEC }, { ERROR_ITERATED_DATA_EXCEEDS_64k,ENOEXEC }, { ERROR_INVALID_MINALLOCSIZE, ENOEXEC }, { ERROR_DYNLINK_FROM_INVALID_RING,ENOEXEC }, { ERROR_IOPL_NOT_ENABLED, ENOEXEC }, { ERROR_INVALID_SEGDPL, ENOEXEC }, { ERROR_AUTODATASEG_EXCEEDS_64k, ENOEXEC }, { ERROR_RING2SEG_MUST_BE_MOVABLE, ENOEXEC }, { ERROR_RELOC_CHAIN_XEEDS_SEGLIM, ENOEXEC }, { ERROR_INFLOOP_IN_RELOC_CHAIN, ENOEXEC }, { ERROR_FILENAME_EXCED_RANGE, ENOENT }, { ERROR_NESTING_NOT_ALLOWED, EAGAIN }, { ERROR_NOT_ENOUGH_QUOTA, ENOMEM }, { WSAENAMETOOLONG, ENAMETOOLONG }, { WSAENOTEMPTY, ENOTEMPTY }, { WSAEINTR, EINTR }, { WSAEBADF, EBADF }, { WSAEACCES, EACCES }, { WSAEFAULT, EFAULT }, { WSAEINVAL, EINVAL }, { WSAEMFILE, EMFILE }, }; int rb_w32_map_errno(DWORD winerr) { int i; if (winerr == 0) { return 0; } for (i = 0; i < sizeof(errmap) / sizeof(*errmap); i++) { if (errmap[i].winerr == winerr) { return errmap[i].err; } } if (winerr >= WSABASEERR) { return winerr; } return EINVAL; } #define map_errno rb_w32_map_errno static const char *NTLoginName; #ifdef WIN95 static DWORD Win32System = (DWORD)-1; DWORD rb_w32_osid(void) { static OSVERSIONINFO osver; if (osver.dwPlatformId != Win32System) { memset(&osver, 0, sizeof(OSVERSIONINFO)); osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osver); Win32System = osver.dwPlatformId; } return (Win32System); } #endif #define IsWinNT() rb_w32_iswinnt() #define IsWin95() rb_w32_iswin95() /* main thread constants */ static struct { HANDLE handle; DWORD id; } main_thread; /* interrupt stuff */ static HANDLE interrupted_event; HANDLE GetCurrentThreadHandle(void) { static HANDLE current_process_handle = NULL; HANDLE h; if (!current_process_handle) current_process_handle = GetCurrentProcess(); if (!DuplicateHandle(current_process_handle, GetCurrentThread(), current_process_handle, &h, 0, FALSE, DUPLICATE_SAME_ACCESS)) return NULL; return h; } /* simulate flock by locking a range on the file */ #define LK_ERR(f,i) \ do { \ if (f) \ i = 0; \ else { \ DWORD err = GetLastError(); \ if (err == ERROR_LOCK_VIOLATION) \ errno = EWOULDBLOCK; \ else if (err == ERROR_NOT_LOCKED) \ i = 0; \ else \ errno = map_errno(err); \ } \ } while (0) #define LK_LEN ULONG_MAX static VALUE flock_winnt(VALUE self, int argc, VALUE* argv) { OVERLAPPED o; int i = -1; const HANDLE fh = (HANDLE)self; const int oper = argc; memset(&o, 0, sizeof(o)); switch(oper) { case LOCK_SH: /* shared lock */ LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, LK_LEN, &o), i); break; case LOCK_EX: /* exclusive lock */ LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, LK_LEN, &o), i); break; case LOCK_SH|LOCK_NB: /* non-blocking shared lock */ LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, LK_LEN, &o), i); break; case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */ LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, LK_LEN, &o), i); break; case LOCK_UN: /* unlock lock */ case LOCK_UN|LOCK_NB: /* unlock is always non-blocking, I hope */ LK_ERR(UnlockFileEx(fh, 0, LK_LEN, LK_LEN, &o), i); break; default: /* unknown */ errno = EINVAL; break; } return i; } #ifdef WIN95 static VALUE flock_win95(VALUE self, int argc, VALUE* argv) { int i = -1; const HANDLE fh = (HANDLE)self; const int oper = argc; switch(oper) { case LOCK_EX: do { LK_ERR(LockFile(fh, 0, 0, LK_LEN, LK_LEN), i); } while (i && errno == EWOULDBLOCK); break; case LOCK_EX|LOCK_NB: LK_ERR(LockFile(fh, 0, 0, LK_LEN, LK_LEN), i); break; case LOCK_UN: case LOCK_UN|LOCK_NB: LK_ERR(UnlockFile(fh, 0, 0, LK_LEN, LK_LEN), i); break; default: errno = EINVAL; break; } return i; } #endif #undef LK_ERR int flock(int fd, int oper) { #ifdef WIN95 static asynchronous_func_t locker = NULL; if (!locker) { if (IsWinNT()) locker = flock_winnt; else locker = flock_win95; } #else const asynchronous_func_t locker = flock_winnt; #endif return rb_w32_asynchronize(locker, (VALUE)_get_osfhandle(fd), oper, NULL, (DWORD)-1); } static void init_stdhandle(void); #if _MSC_VER >= 1400 static void invalid_parameter(const wchar_t *expr, const wchar_t *func, const wchar_t *file, unsigned int line, uintptr_t dummy) { // nothing to do } static int __cdecl rtc_error_handler(int e, const char *src, int line, const char *exe, const char *fmt, ...) { return 0; } #endif static CRITICAL_SECTION select_mutex; static BOOL fWinsock; static char *envarea; static void exit_handler(void) { if (fWinsock) { WSACleanup(); fWinsock = FALSE; } if (envarea) { FreeEnvironmentStrings(envarea); envarea = NULL; } DeleteCriticalSection(&select_mutex); } static void init_env(void) { char env[_MAX_PATH]; DWORD len; BOOL f; LPITEMIDLIST pidl; if (!GetEnvironmentVariable("HOME", env, sizeof(env))) { f = FALSE; if (GetEnvironmentVariable("HOMEDRIVE", env, sizeof(env))) len = strlen(env); else len = 0; if (GetEnvironmentVariable("HOMEPATH", env + len, sizeof(env) - len) || len) { f = TRUE; } else if (GetEnvironmentVariable("USERPROFILE", env, sizeof(env))) { f = TRUE; } else if (SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &pidl) == 0) { LPMALLOC alloc; f = SHGetPathFromIDList(pidl, env); SHGetMalloc(&alloc); alloc->lpVtbl->Free(alloc, pidl); alloc->lpVtbl->Release(alloc); } if (f) { char *p = env; while (*p) { if (*p == '\\') *p = '/'; p = CharNext(p); } if (p - env == 2 && env[1] == ':') { *p++ = '/'; *p = 0; } SetEnvironmentVariable("HOME", env); } } if (!GetEnvironmentVariable("USER", env, sizeof env)) { if (GetEnvironmentVariable("USERNAME", env, sizeof env) || GetUserName(env, (len = sizeof env, &len))) { SetEnvironmentVariable("USER", env); } else { NTLoginName = ""; return; } } NTLoginName = strdup(env); } // // Initialization stuff // void NtInitialize(int *argc, char ***argv) { #if _MSC_VER >= 1400 static void set_pioinfo_extra(void); _CrtSetReportMode(_CRT_ASSERT, 0); _set_invalid_parameter_handler(invalid_parameter); _RTC_SetErrorFunc(rtc_error_handler); set_pioinfo_extra(); #endif // // subvert cmd.exe's feeble attempt at command line parsing // *argc = rb_w32_cmdvector(GetCommandLine(), argv); // // Now set up the correct time stuff // tzset(); init_env(); init_stdhandle(); InitializeCriticalSection(&select_mutex); atexit(exit_handler); // Initialize Winsock StartSockets(); #ifdef _WIN32_WCE // free commandline buffer wce_FreeCommandLine(); #endif } char * getlogin() { return (char *)NTLoginName; } #define MAXCHILDNUM 256 /* max num of child processes */ static struct ChildRecord { HANDLE hProcess; /* process handle */ rb_pid_t pid; /* process id */ } ChildRecord[MAXCHILDNUM]; #define FOREACH_CHILD(v) do { \ struct ChildRecord* v; \ for (v = ChildRecord; v < ChildRecord + sizeof(ChildRecord) / sizeof(ChildRecord[0]); ++v) #define END_FOREACH_CHILD } while (0) static struct ChildRecord * FindChildSlot(rb_pid_t pid) { FOREACH_CHILD(child) { if (child->pid == pid) { return child; } } END_FOREACH_CHILD; return NULL; } static struct ChildRecord * FindChildSlotByHandle(HANDLE h) { FOREACH_CHILD(child) { if (child->hProcess == h) { return child; } } END_FOREACH_CHILD; return NULL; } static void CloseChildHandle(struct ChildRecord *child) { HANDLE h = child->hProcess; child->hProcess = NULL; child->pid = 0; CloseHandle(h); } static struct ChildRecord * FindFreeChildSlot(void) { FOREACH_CHILD(child) { if (!child->pid) { child->pid = -1; /* lock the slot */ child->hProcess = NULL; return child; } } END_FOREACH_CHILD; return NULL; } /* ruby -lne 'BEGIN{$cmds = Hash.new(0); $mask = 1}' -e '$cmds[$_.downcase] |= $mask' -e '$mask <<= 1 if ARGF.eof' -e 'END{$cmds.sort.each{|n,f|puts " \"\\#{f.to_s(8)}\" #{n.dump} + 1,"}}' 98cmd ntcmd */ static const char *const szInternalCmds[] = { "\2" "assoc" + 1, "\3" "break" + 1, "\3" "call" + 1, "\3" "cd" + 1, "\1" "chcp" + 1, "\3" "chdir" + 1, "\3" "cls" + 1, "\2" "color" + 1, "\3" "copy" + 1, "\1" "ctty" + 1, "\3" "date" + 1, "\3" "del" + 1, "\3" "dir" + 1, "\3" "echo" + 1, "\2" "endlocal" + 1, "\3" "erase" + 1, "\3" "exit" + 1, "\3" "for" + 1, "\2" "ftype" + 1, "\3" "goto" + 1, "\3" "if" + 1, "\1" "lfnfor" + 1, "\1" "lh" + 1, "\1" "lock" + 1, "\3" "md" + 1, "\3" "mkdir" + 1, "\2" "move" + 1, "\3" "path" + 1, "\3" "pause" + 1, "\2" "popd" + 1, "\3" "prompt" + 1, "\2" "pushd" + 1, "\3" "rd" + 1, "\3" "rem" + 1, "\3" "ren" + 1, "\3" "rename" + 1, "\3" "rmdir" + 1, "\3" "set" + 1, "\2" "setlocal" + 1, "\3" "shift" + 1, "\2" "start" + 1, "\3" "time" + 1, "\2" "title" + 1, "\1" "truename" + 1, "\3" "type" + 1, "\1" "unlock" + 1, "\3" "ver" + 1, "\3" "verify" + 1, "\3" "vol" + 1, }; static int internal_match(const void *key, const void *elem) { return strcmp(key, *(const char *const *)elem); } static int is_command_com(const char *interp) { int i = strlen(interp) - 11; if ((i == 0 || i > 0 && isdirsep(interp[i-1])) && strcasecmp(interp+i, "command.com") == 0) { return 1; } return 0; } static int is_internal_cmd(const char *cmd, int nt) { char cmdname[9], *b = cmdname, c, **nm; do { if (!(c = *cmd++)) return 0; } while (isspace(c)); while (isalpha(c)) { *b++ = tolower(c); if (b == cmdname + sizeof(cmdname)) return 0; c = *cmd++; } if (c == '.') c = *cmd; switch (c) { case '<': case '>': case '|': return 1; case '\0': case ' ': case '\t': case '\n': break; default: return 0; } *b = 0; nm = bsearch(cmdname, szInternalCmds, sizeof(szInternalCmds) / sizeof(*szInternalCmds), sizeof(*szInternalCmds), internal_match); if (!nm || !(nm[0][-1] & (nt ? 2 : 1))) return 0; return 1; } SOCKET rb_w32_get_osfhandle(int fh) { return _get_osfhandle(fh); } rb_pid_t pipe_exec(const char *cmd, int mode, FILE **fpr, FILE **fpw) { struct ChildRecord* child; HANDLE hReadIn, hReadOut; HANDLE hWriteIn, hWriteOut; HANDLE hDupInFile, hDupOutFile; HANDLE hCurProc; SECURITY_ATTRIBUTES sa; BOOL fRet; BOOL reading, writing; int fd; int pipemode; char modes[3]; int ret; /* Figure out what we're doing... */ writing = (mode & (O_WRONLY | O_RDWR)) ? TRUE : FALSE; reading = ((mode & O_RDWR) || !writing) ? TRUE : FALSE; if (mode & O_BINARY) { pipemode = O_BINARY; modes[1] = 'b'; modes[2] = '\0'; } else { pipemode = O_TEXT; modes[1] = '\0'; } sa.nLength = sizeof (SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; ret = -1; hWriteIn = hReadOut = NULL; RUBY_CRITICAL(do { /* create pipe */ hCurProc = GetCurrentProcess(); if (reading) { fRet = CreatePipe(&hReadIn, &hReadOut, &sa, 2048L); if (!fRet) { errno = map_errno(GetLastError()); break; } if (!DuplicateHandle(hCurProc, hReadIn, hCurProc, &hDupInFile, 0, FALSE, DUPLICATE_SAME_ACCESS)) { errno = map_errno(GetLastError()); CloseHandle(hReadIn); CloseHandle(hReadOut); CloseHandle(hCurProc); break; } CloseHandle(hReadIn); } if (writing) { fRet = CreatePipe(&hWriteIn, &hWriteOut, &sa, 2048L); if (!fRet) { errno = map_errno(GetLastError()); write_pipe_failed: if (reading) { CloseHandle(hDupInFile); CloseHandle(hReadOut); } break; } if (!DuplicateHandle(hCurProc, hWriteOut, hCurProc, &hDupOutFile, 0, FALSE, DUPLICATE_SAME_ACCESS)) { errno = map_errno(GetLastError()); CloseHandle(hWriteIn); CloseHandle(hWriteOut); CloseHandle(hCurProc); goto write_pipe_failed; } CloseHandle(hWriteOut); } CloseHandle(hCurProc); /* create child process */ child = CreateChild(cmd, NULL, &sa, hWriteIn, hReadOut, NULL); if (!child) { if (reading) { CloseHandle(hReadOut); CloseHandle(hDupInFile); } if (writing) { CloseHandle(hWriteIn); CloseHandle(hDupOutFile); } break; } /* associate handle to fp */ if (reading) { fd = rb_w32_open_osfhandle((long)hDupInFile, (_O_RDONLY | pipemode)); CloseHandle(hReadOut); if (fd == -1) { CloseHandle(hDupInFile); read_open_failed: if (writing) { CloseHandle(hWriteIn); CloseHandle(hDupOutFile); } CloseChildHandle(child); break; } modes[0] = 'r'; if ((*fpr = (FILE *)fdopen(fd, modes)) == NULL) { _close(fd); goto read_open_failed; } } if (writing) { fd = rb_w32_open_osfhandle((long)hDupOutFile, (_O_WRONLY | pipemode)); CloseHandle(hWriteIn); if (fd == -1) { CloseHandle(hDupOutFile); write_open_failed: if (reading) { fclose(*fpr); } CloseChildHandle(child); break; } modes[0] = 'w'; if ((*fpw = (FILE *)fdopen(fd, modes)) == NULL) { _close(fd); goto write_open_failed; } } ret = child->pid; } while (0)); return ret; } extern VALUE rb_last_status; int do_spawn(int mode, const char *cmd) { struct ChildRecord *child; DWORD exitcode; switch (mode) { case P_WAIT: case P_NOWAIT: case P_OVERLAY: break; default: errno = EINVAL; return -1; } child = CreateChild(cmd, NULL, NULL, NULL, NULL, NULL); if (!child) { return -1; } switch (mode) { case P_WAIT: rb_syswait(child->pid); return NUM2INT(rb_last_status); case P_NOWAIT: return child->pid; case P_OVERLAY: WaitForSingleObject(child->hProcess, INFINITE); GetExitCodeProcess(child->hProcess, &exitcode); CloseChildHandle(child); _exit(exitcode); default: return -1; /* not reached */ } } int do_aspawn(int mode, const char *prog, char **argv) { char *cmd, *p, *q, *s, **t; int len, n, bs, quote; struct ChildRecord *child; DWORD exitcode; switch (mode) { case P_WAIT: case P_NOWAIT: case P_OVERLAY: break; default: errno = EINVAL; return -1; } for (t = argv, len = 0; *t; t++) { for (p = *t, n = quote = bs = 0; *p; ++p) { switch (*p) { case '\\': ++bs; break; case '"': n += bs + 1; bs = 0; quote = 1; break; case ' ': case '\t': quote = 1; default: bs = 0; p = CharNext(p) - 1; break; } } len += p - *t + n + 1; if (quote) len += 2; } cmd = ALLOCA_N(char, len); for (t = argv, q = cmd; p = *t; t++) { quote = 0; s = p; if (!*p || strpbrk(p, " \t\"")) { quote = 1; *q++ = '"'; } for (bs = 0; *p; ++p) { switch (*p) { case '\\': ++bs; break; case '"': memcpy(q, s, n = p - s); q += n; s = p; memset(q, '\\', ++bs); q += bs; bs = 0; break; default: bs = 0; p = CharNext(p) - 1; break; } } memcpy(q, s, n = p - s); q += n; if (quote) *q++ = '"'; *q++ = ' '; } if (q > cmd) --q; *q = '\0'; child = CreateChild(cmd, prog, NULL, NULL, NULL, NULL); if (!child) { return -1; } switch (mode) { case P_WAIT: rb_syswait(child->pid); return NUM2INT(rb_last_status); case P_NOWAIT: return child->pid; case P_OVERLAY: WaitForSingleObject(child->hProcess, INFINITE); GetExitCodeProcess(child->hProcess, &exitcode); CloseChildHandle(child); _exit(exitcode); default: return -1; /* not reached */ } } static struct ChildRecord * CreateChild(const char *cmd, const char *prog, SECURITY_ATTRIBUTES *psa, HANDLE hInput, HANDLE hOutput, HANDLE hError) { BOOL fRet; DWORD dwCreationFlags; STARTUPINFO aStartupInfo; PROCESS_INFORMATION aProcessInformation; SECURITY_ATTRIBUTES sa; const char *shell; struct ChildRecord *child; char *p = NULL; if (!cmd && !prog) { errno = EFAULT; return NULL; } child = FindFreeChildSlot(); if (!child) { errno = EAGAIN; return NULL; } if (!psa) { sa.nLength = sizeof (SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; psa = &sa; } memset(&aStartupInfo, 0, sizeof (STARTUPINFO)); memset(&aProcessInformation, 0, sizeof (PROCESS_INFORMATION)); aStartupInfo.cb = sizeof (STARTUPINFO); if (hInput || hOutput || hError) { aStartupInfo.dwFlags = STARTF_USESTDHANDLES; if (hInput) { aStartupInfo.hStdInput = hInput; } else { aStartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); } if (hOutput) { aStartupInfo.hStdOutput = hOutput; } else { aStartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); } if (hError) { aStartupInfo.hStdError = hError; } else { aStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); } } dwCreationFlags = (NORMAL_PRIORITY_CLASS); if (prog) { if (!(p = dln_find_exe(prog, NULL))) { shell = prog; } } else { int redir = -1; int len = 0; int nt; while (ISSPACE(*cmd)) cmd++; for (prog = cmd; *prog; prog = CharNext(prog)) { if (ISSPACE(*prog)) { len = prog - cmd; do ++prog; while (ISSPACE(*prog)); if (!*prog--) break; } else { len = 0; } } if (!len) len = strlen(cmd); if ((shell = getenv("RUBYSHELL")) && (redir = has_redirection(cmd))) { char *tmp = ALLOCA_N(char, strlen(shell) + len + sizeof(" -c ") + 2); sprintf(tmp, "%s -c \"%.*s\"", shell, len, cmd); cmd = tmp; } else if ((shell = getenv("COMSPEC")) && (nt = !is_command_com(shell), (redir < 0 ? has_redirection(cmd) : redir) || is_internal_cmd(cmd, nt))) { char *tmp = ALLOCA_N(char, strlen(shell) + len + sizeof(" /c ") + (nt ? 2 : 0)); sprintf(tmp, nt ? "%s /c \"%.*s\"" : "%s /c %.*s", shell, len, cmd); cmd = tmp; } else { shell = NULL; prog = cmd; for (;;) { if (!*prog) { p = dln_find_exe(cmd, NULL); break; } if (strchr(".:*?\"/\\", *prog)) { if (cmd[len]) { char *tmp = ALLOCA_N(char, len + 1); memcpy(tmp, cmd, len); tmp[len] = 0; cmd = tmp; } break; } if (ISSPACE(*prog) || strchr("<>|", *prog)) { len = prog - cmd; p = ALLOCA_N(char, len + 1); memcpy(p, cmd, len); p[len] = 0; p = dln_find_exe(p, NULL); break; } prog++; } } } if (p) { char *tmp = ALLOCA_N(char, strlen(p) + 1); strcpy(tmp, p); shell = tmp; while (*tmp) { if ((unsigned char)*tmp == '/') *tmp = '\\'; tmp = CharNext(tmp); } } RUBY_CRITICAL({ fRet = CreateProcess(shell, (char *)cmd, psa, psa, psa->bInheritHandle, dwCreationFlags, NULL, NULL, &aStartupInfo, &aProcessInformation); errno = map_errno(GetLastError()); }); if (!fRet) { child->pid = 0; /* release the slot */ return NULL; } CloseHandle(aProcessInformation.hThread); child->hProcess = aProcessInformation.hProcess; child->pid = (rb_pid_t)aProcessInformation.dwProcessId; if (!IsWinNT()) { /* On Win9x, make pid positive similarly to cygwin and perl */ child->pid = -child->pid; } return child; } typedef struct _NtCmdLineElement { struct _NtCmdLineElement *next; char *str; int len; int flags; } NtCmdLineElement; // // Possible values for flags // #define NTGLOB 0x1 // element contains a wildcard #define NTMALLOC 0x2 // string in element was malloc'ed #define NTSTRING 0x4 // element contains a quoted string static int insert(const char *path, VALUE vinfo) { NtCmdLineElement *tmpcurr; NtCmdLineElement ***tail = (NtCmdLineElement ***)vinfo; tmpcurr = (NtCmdLineElement *)malloc(sizeof(NtCmdLineElement)); if (!tmpcurr) return -1; MEMZERO(tmpcurr, NtCmdLineElement, 1); tmpcurr->len = strlen(path); tmpcurr->str = strdup(path); if (!tmpcurr->str) return -1; tmpcurr->flags |= NTMALLOC; **tail = tmpcurr; *tail = &tmpcurr->next; return 0; } #ifdef HAVE_SYS_PARAM_H # include #else # define MAXPATHLEN 512 #endif static NtCmdLineElement ** cmdglob(NtCmdLineElement *patt, NtCmdLineElement **tail) { char buffer[MAXPATHLEN], *buf = buffer; char *p; NtCmdLineElement **last = tail; int status; if (patt->len >= MAXPATHLEN) if (!(buf = malloc(patt->len + 1))) return 0; strncpy (buf, patt->str, patt->len); buf[patt->len] = '\0'; for (p = buf; *p; p = CharNext(p)) if (*p == '\\') *p = '/'; status = ruby_glob(buf, 0, insert, (VALUE)&tail); if (buf != buffer) free(buf); if (status || last == tail) return 0; if (patt->flags & NTMALLOC) free(patt->str); free(patt); return tail; } // // Check a command string to determine if it has I/O redirection // characters that require it to be executed by a command interpreter // static bool has_redirection(const char *cmd) { char quote = '\0'; const char *ptr; // // Scan the string, looking for redirection (< or >) or pipe // characters (|) that are not in a quoted string // for (ptr = cmd; *ptr;) { switch (*ptr) { case '\'': case '\"': if (!quote) quote = *ptr; else if (quote == *ptr) quote = '\0'; ptr++; break; case '>': case '<': case '|': if (!quote) return TRUE; ptr++; break; case '\\': ptr++; default: ptr = CharNext(ptr); break; } } return FALSE; } static inline char * skipspace(char *ptr) { while (ISSPACE(*ptr)) ptr++; return ptr; } int rb_w32_cmdvector(const char *cmd, char ***vec) { int globbing, len; int elements, strsz, done; int slashes, escape; char *ptr, *base, *buffer, *cmdline; char **vptr; char quote; NtCmdLineElement *curr, **tail; NtCmdLineElement *cmdhead = NULL, **cmdtail = &cmdhead; // // just return if we don't have a command line // while (ISSPACE(*cmd)) cmd++; if (!*cmd) { *vec = NULL; return 0; } ptr = cmdline = strdup(cmd); // // Ok, parse the command line, building a list of CmdLineElements. // When we've finished, and it's an input command (meaning that it's // the processes argv), we'll do globing and then build the argument // vector. // The outer loop does one interation for each element seen. // The inner loop does one interation for each character in the element. // while (*(ptr = skipspace(ptr))) { base = ptr; quote = slashes = globbing = escape = 0; for (done = 0; !done && *ptr; ) { // // Switch on the current character. We only care about the // white-space characters, the wild-card characters, and the // quote characters. // switch (*ptr) { case '\\': if (quote != '\'') slashes++; break; case ' ': case '\t': case '\n': // // if we're not in a string, then we're finished with this // element // if (!quote) { *ptr = 0; done = 1; } break; case '*': case '?': case '[': case '{': // // record the fact that this element has a wildcard character // N.B. Don't glob if inside a single quoted string // if (quote != '\'') globbing++; slashes = 0; break; case '\'': case '\"': // // if we're already in a string, see if this is the // terminating close-quote. If it is, we're finished with // the string, but not neccessarily with the element. // If we're not already in a string, start one. // if (!(slashes & 1)) { if (!quote) quote = *ptr; else if (quote == *ptr) { if (quote == '"' && quote == ptr[1]) ptr++; quote = '\0'; } } escape++; slashes = 0; break; default: ptr = CharNext(ptr); slashes = 0; continue; } ptr++; } // // when we get here, we've got a pair of pointers to the element, // base and ptr. Base points to the start of the element while ptr // points to the character following the element. // len = ptr - base; if (done) --len; // // if it's an input vector element and it's enclosed by quotes, // we can remove them. // if (escape) { char *p = base, c; slashes = quote = 0; while (p < base + len) { switch (c = *p) { case '\\': p++; if (quote != '\'') slashes++; break; case '\'': case '"': if (!(slashes & 1) && quote && quote != c) { p++; slashes = 0; break; } memcpy(p - ((slashes + 1) >> 1), p + (~slashes & 1), base + len - p); len -= ((slashes + 1) >> 1) + (~slashes & 1); p -= (slashes + 1) >> 1; if (!(slashes & 1)) { if (quote) { if (quote == '"' && quote == *p) p++; quote = '\0'; } else quote = c; } else p++; slashes = 0; break; default: p = CharNext(p); slashes = 0; break; } } } curr = (NtCmdLineElement *)calloc(sizeof(NtCmdLineElement), 1); if (!curr) goto do_nothing; curr->str = base; curr->len = len; if (globbing && (tail = cmdglob(curr, cmdtail))) { cmdtail = tail; } else { *cmdtail = curr; cmdtail = &curr->next; } } // // Almost done! // Count up the elements, then allocate space for a vector of pointers // (argv) and a string table for the elements. // for (elements = 0, strsz = 0, curr = cmdhead; curr; curr = curr->next) { elements++; strsz += (curr->len + 1); } len = (elements+1)*sizeof(char *) + strsz; buffer = (char *)malloc(len); if (!buffer) { do_nothing: while (curr = cmdhead) { cmdhead = curr->next; if (curr->flags & NTMALLOC) free(curr->str); free(curr); } free(cmdline); for (vptr = *vec; *vptr; ++vptr); return vptr - *vec; } // // make vptr point to the start of the buffer // and ptr point to the area we'll consider the string table. // // buffer (*vec) // | // V ^---------------------V // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ // | | | .... | NULL | | ..... |\0 | | ..... |\0 |... // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ // |- elements+1 -| ^ 1st element ^ 2nd element vptr = (char **) buffer; ptr = buffer + (elements+1) * sizeof(char *); while (curr = cmdhead) { memcpy(ptr, curr->str, curr->len); *vptr++ = ptr; ptr += curr->len; *ptr++ = '\0'; cmdhead = curr->next; if (curr->flags & NTMALLOC) free(curr->str); free(curr); } *vptr = 0; *vec = (char **) buffer; free(cmdline); return elements; } // // UNIX compatible directory access functions for NT // #define PATHLEN 1024 // // The idea here is to read all the directory names into a string table // (separated by nulls) and when one of the other dir functions is called // return the pointer to the current file name. // #define GetBit(bits, i) ((bits)[(i) / CHAR_BIT] & (1 << (i) % CHAR_BIT)) #define SetBit(bits, i) ((bits)[(i) / CHAR_BIT] |= (1 << (i) % CHAR_BIT)) #define BitOfIsDir(n) ((n) * 2) #define BitOfIsRep(n) ((n) * 2 + 1) #define DIRENT_PER_CHAR (CHAR_BIT / 2) static HANDLE open_dir_handle(const char *filename, WIN32_FIND_DATA *fd) { HANDLE fh; static const char wildcard[] = "/*"; long len = strlen(filename); char *scanname = malloc(len + sizeof(wildcard)); // // Create the search pattern // if (!scanname) { return INVALID_HANDLE_VALUE; } memcpy(scanname, filename, len + 1); if (index("/\\:", *CharPrev(scanname, scanname + len)) == NULL) memcpy(scanname + len, wildcard, sizeof(wildcard)); else memcpy(scanname + len, wildcard + 1, sizeof(wildcard) - 1); // // do the FindFirstFile call // fh = FindFirstFile(scanname, fd); free(scanname); if (fh == INVALID_HANDLE_VALUE) { errno = map_errno(GetLastError()); } return fh; } DIR * rb_w32_opendir(const char *filename) { DIR *p; long len; long idx; struct stat sbuf; WIN32_FIND_DATA fd; HANDLE fh; // // check to see if we've got a directory // if (rb_w32_stat(filename, &sbuf) < 0) return NULL; if (!(sbuf.st_mode & S_IFDIR) && (!ISALPHA(filename[0]) || filename[1] != ':' || filename[2] != '\0' || ((1 << (filename[0] & 0x5f) - 'A') & GetLogicalDrives()) == 0)) { errno = ENOTDIR; return NULL; } fh = open_dir_handle(filename, &fd); if (fh == INVALID_HANDLE_VALUE) { return NULL; } // // Get us a DIR structure // p = calloc(sizeof(DIR), 1); if (p == NULL) return NULL; // // now allocate the first part of the string table for the // filenames that we find. // idx = strlen(fd.cFileName)+1; if (!(p->start = (char *)malloc(idx)) || !(p->bits = (char *)malloc(1))) { error: rb_w32_closedir(p); FindClose(fh); errno = ENOMEM; return NULL; } strcpy(p->start, fd.cFileName); p->bits[0] = 0; if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) SetBit(p->bits, BitOfIsDir(0)); if (fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) SetBit(p->bits, BitOfIsRep(0)); p->nfiles++; // // loop finding all the files that match the wildcard // (which should be all of them in this directory!). // the variable idx should point one past the null terminator // of the previous string found. // while (FindNextFile(fh, &fd)) { char *newpath; len = strlen(fd.cFileName) + 1; // // bump the string table size by enough for the // new name and it's null terminator // newpath = (char *)realloc(p->start, idx + len); if (newpath == NULL) { goto error; } p->start = newpath; strcpy(&p->start[idx], fd.cFileName); if (p->nfiles % DIRENT_PER_CHAR == 0) { char *tmp = realloc(p->bits, p->nfiles / DIRENT_PER_CHAR + 1); if (!tmp) goto error; p->bits = tmp; p->bits[p->nfiles / DIRENT_PER_CHAR] = 0; } if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) SetBit(p->bits, BitOfIsDir(p->nfiles)); if (fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) SetBit(p->bits, BitOfIsRep(p->nfiles)); p->nfiles++; idx += len; } FindClose(fh); p->size = idx; p->curr = p->start; return p; } // // Move to next entry // static void move_to_next_entry(DIR *dirp) { if (dirp->curr) { dirp->loc++; dirp->curr += strlen(dirp->curr) + 1; if (dirp->curr >= (dirp->start + dirp->size)) { dirp->curr = NULL; } } } // // Readdir just returns the current string pointer and bumps the // string pointer to the next entry. // struct direct * rb_w32_readdir(DIR *dirp) { static int dummy = 0; if (dirp->curr) { // // first set up the structure to return // strcpy(dirp->dirstr.d_name, dirp->curr); dirp->dirstr.d_namlen = strlen(dirp->curr); // // Fake inode // dirp->dirstr.d_ino = dummy++; // // Attributes // dirp->dirstr.d_isdir = GetBit(dirp->bits, BitOfIsDir(dirp->loc)); dirp->dirstr.d_isrep = GetBit(dirp->bits, BitOfIsRep(dirp->loc)); // // Now set up for the next call to readdir // move_to_next_entry(dirp); return &(dirp->dirstr); } else return NULL; } // // Telldir returns the current string pointer position // long rb_w32_telldir(DIR *dirp) { return dirp->loc; } // // Seekdir moves the string pointer to a previously saved position // (Saved by telldir). void rb_w32_seekdir(DIR *dirp, long loc) { rb_w32_rewinddir(dirp); while (dirp->curr && loc-- > 0) { move_to_next_entry(dirp); } } // // Rewinddir resets the string pointer to the start // void rb_w32_rewinddir(DIR *dirp) { dirp->curr = dirp->start; dirp->loc = 0; } // // This just free's the memory allocated by opendir // void rb_w32_closedir(DIR *dirp) { free(dirp->start); free(dirp->bits); free(dirp); } EXTERN_C void __cdecl _lock_fhandle(int); EXTERN_C void __cdecl _unlock_fhandle(int); EXTERN_C void __cdecl _unlock(int); #if (defined _MT || defined __MSVCRT__) && !defined __BORLANDC__ #define MSVCRT_THREADS #endif #ifdef MSVCRT_THREADS # define MTHREAD_ONLY(x) x # define STHREAD_ONLY(x) #elif defined(__BORLANDC__) # define MTHREAD_ONLY(x) # define STHREAD_ONLY(x) #else # define MTHREAD_ONLY(x) # define STHREAD_ONLY(x) x #endif typedef struct { long osfhnd; /* underlying OS file HANDLE */ char osfile; /* attributes of file (e.g., open in text mode?) */ char pipech; /* one char buffer for handles opened on pipes */ #ifdef MSVCRT_THREADS int lockinitflag; CRITICAL_SECTION lock; #if _MSC_VER >= 1400 char textmode; char pipech2[2]; #endif #endif } ioinfo; #if !defined _CRTIMP || defined __MINGW32__ #undef _CRTIMP #define _CRTIMP __declspec(dllimport) #endif #if !defined(__BORLANDC__) && !defined(_WIN32_WCE) EXTERN_C _CRTIMP ioinfo * __pioinfo[]; #define IOINFO_L2E 5 #define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E) #define _pioinfo(i) ((ioinfo*)((char*)(__pioinfo[i >> IOINFO_L2E]) + (i & (IOINFO_ARRAY_ELTS - 1)) * (sizeof(ioinfo) + pioinfo_extra))) #define _osfhnd(i) (_pioinfo(i)->osfhnd) #define _osfile(i) (_pioinfo(i)->osfile) #define _pipech(i) (_pioinfo(i)->pipech) #if _MSC_VER >= 1400 static size_t pioinfo_extra = 0; /* workaround for VC++8 SP1 */ static void set_pioinfo_extra(void) { int fd; fd = open("NUL", O_RDONLY); for (pioinfo_extra = 0; pioinfo_extra <= 64; pioinfo_extra += sizeof(void *)) { if (_osfhnd(fd) == _get_osfhandle(fd)) { break; } } close(fd); if (pioinfo_extra > 64) { /* not found, maybe something wrong... */ pioinfo_extra = 0; } } #else #define pioinfo_extra 0 #endif #define _set_osfhnd(fh, osfh) (void)(_osfhnd(fh) = osfh) #define _set_osflags(fh, flags) (_osfile(fh) = (flags)) #define FOPEN 0x01 /* file handle open */ #define FNOINHERIT 0x10 /* file handle opened O_NOINHERIT */ #define FAPPEND 0x20 /* file handle opened O_APPEND */ #define FDEV 0x40 /* file handle refers to device */ #define FTEXT 0x80 /* file handle is in text mode */ static int rb_w32_open_osfhandle(long osfhandle, int flags) { int fh; char fileflags; /* _osfile flags */ HANDLE hF; /* copy relevant flags from second parameter */ fileflags = FDEV; if (flags & O_APPEND) fileflags |= FAPPEND; if (flags & O_TEXT) fileflags |= FTEXT; if (flags & O_NOINHERIT) fileflags |= FNOINHERIT; /* attempt to allocate a C Runtime file handle */ hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL); fh = _open_osfhandle((long)hF, 0); CloseHandle(hF); if (fh == -1) { errno = EMFILE; /* too many open files */ _doserrno = 0L; /* not an OS error */ } else { MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fh)->lock))); /* the file is open. now, set the info in _osfhnd array */ _set_osfhnd(fh, osfhandle); fileflags |= FOPEN; /* mark as open */ _set_osflags(fh, fileflags); /* set osfile entry */ MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fh)->lock)); } return fh; /* return handle */ } static void init_stdhandle(void) { if (fileno(stdin) < 0) { stdin->_file = 0; } if (fileno(stdout) < 0) { stdout->_file = 1; } if (fileno(stderr) < 0) { stderr->_file = 2; } setvbuf(stderr, NULL, _IONBF, 0); } #else #define _set_osfhnd(fh, osfh) (void)((fh), (osfh)) #define _set_osflags(fh, flags) (void)((fh), (flags)) static void init_stdhandle(void) { } #endif #ifdef __BORLANDC__ static int rb_w32_open_osfhandle(long osfhandle, int flags) { int fd = _open_osfhandle(osfhandle, flags); if (fd == -1) { errno = EMFILE; /* too many open files */ _doserrno = 0L; /* not an OS error */ } return fd; } #endif #undef getsockopt static int is_socket(SOCKET fd) { char sockbuf[80]; int optlen; int retval; int result = TRUE; optlen = sizeof(sockbuf); RUBY_CRITICAL({ retval = getsockopt(fd, SOL_SOCKET, SO_TYPE, sockbuf, &optlen); if (retval == SOCKET_ERROR) { int iRet; iRet = WSAGetLastError(); if (iRet == WSAENOTSOCK || iRet == WSANOTINITIALISED) result = FALSE; } }); // // If we get here, then fd is actually a socket. // return result; } // // Since the errors returned by the socket error function // WSAGetLastError() are not known by the library routine strerror // we have to roll our own. // #undef strerror char * rb_w32_strerror(int e) { static char buffer[512]; #if !defined __MINGW32__ extern int sys_nerr; #endif DWORD source = 0; char *p; #if defined __BORLANDC__ && defined ENOTEMPTY // _sys_errlist is broken switch (e) { case ENAMETOOLONG: return "Filename too long"; case ENOTEMPTY: return "Directory not empty"; } #endif if (e < 0 || e > sys_nerr) { if (e < 0) e = GetLastError(); if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, &source, e, 0, buffer, sizeof(buffer), NULL) == 0) { strcpy(buffer, "Unknown Error"); } } else { strncpy(buffer, strerror(e), sizeof(buffer)); buffer[sizeof(buffer) - 1] = 0; } p = buffer; while ((p = strpbrk(p, "\r\n")) != NULL) { memmove(p, p + 1, strlen(p)); } return buffer; } // // various stubs // // Ownership // // Just pretend that everyone is a superuser. NT will let us know if // we don't really have permission to do something. // #define ROOT_UID 0 #define ROOT_GID 0 rb_uid_t getuid(void) { return ROOT_UID; } rb_uid_t geteuid(void) { return ROOT_UID; } rb_gid_t getgid(void) { return ROOT_GID; } rb_gid_t getegid(void) { return ROOT_GID; } int setuid(rb_uid_t uid) { return (uid == ROOT_UID ? 0 : -1); } int setgid(rb_gid_t gid) { return (gid == ROOT_GID ? 0 : -1); } // // File system stuff // int /* ioctl(int i, unsigned int u, char *data) */ #ifdef __BORLANDC__ ioctl(int i, int u, ...) #else ioctl(int i, unsigned int u, long data) #endif { errno = EINVAL; return -1; } #undef FD_SET void rb_w32_fdset(int fd, fd_set *set) { unsigned int i; SOCKET s = TO_SOCKET(fd); for (i = 0; i < set->fd_count; i++) { if (set->fd_array[i] == s) { return; } } if (i == set->fd_count) { if (set->fd_count < FD_SETSIZE) { set->fd_array[i] = s; set->fd_count++; } } } #undef FD_CLR void rb_w32_fdclr(int fd, fd_set *set) { unsigned int i; SOCKET s = TO_SOCKET(fd); for (i = 0; i < set->fd_count; i++) { if (set->fd_array[i] == s) { while (i < set->fd_count - 1) { set->fd_array[i] = set->fd_array[i + 1]; i++; } set->fd_count--; break; } } } #undef FD_ISSET int rb_w32_fdisset(int fd, fd_set *set) { int ret; SOCKET s = TO_SOCKET(fd); if (s == (SOCKET)INVALID_HANDLE_VALUE) return 0; RUBY_CRITICAL(ret = __WSAFDIsSet(s, set)); return ret; } // // Networking trampolines // These are used to avoid socket startup/shutdown overhead in case // the socket routines aren't used. // #undef select static int NtSocketsInitialized = 0; static int extract_fd(fd_set *dst, fd_set *src, int (*func)(SOCKET)) { int s = 0; if (!src || !dst) return 0; while (s < src->fd_count) { SOCKET fd = src->fd_array[s]; if (!func || (*func)(fd)) { /* move it to dst */ int d; for (d = 0; d < dst->fd_count; d++) { if (dst->fd_array[d] == fd) break; } if (d == dst->fd_count && dst->fd_count < FD_SETSIZE) { dst->fd_array[dst->fd_count++] = fd; } memmove( &src->fd_array[s], &src->fd_array[s+1], sizeof(src->fd_array[0]) * (--src->fd_count - s)); } else s++; } return dst->fd_count; } static int is_not_socket(SOCKET sock) { return !is_socket(sock); } static int is_pipe(SOCKET sock) /* DONT call this for SOCKET! it clains it is PIPE. */ { int ret; RUBY_CRITICAL( ret = (GetFileType((HANDLE)sock) == FILE_TYPE_PIPE) ); return ret; } static int is_readable_pipe(SOCKET sock) /* call this for pipe only */ { int ret; DWORD n = 0; RUBY_CRITICAL( if (PeekNamedPipe((HANDLE)sock, NULL, 0, NULL, &n, NULL)) { ret = (n > 0); } else { ret = (GetLastError() == ERROR_BROKEN_PIPE); /* pipe was closed */ } ); return ret; } static int is_console(SOCKET sock) /* DONT call this for SOCKET! */ { int ret; DWORD n = 0; INPUT_RECORD ir; RUBY_CRITICAL( ret = (PeekConsoleInput((HANDLE)sock, &ir, 1, &n)) ); return ret; } static int is_readable_console(SOCKET sock) /* call this for console only */ { int ret = 0; DWORD n = 0; INPUT_RECORD ir; RUBY_CRITICAL( if (PeekConsoleInput((HANDLE)sock, &ir, 1, &n) && n > 0) { if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown && ir.Event.KeyEvent.uChar.AsciiChar) { ret = 1; } else { ReadConsoleInput((HANDLE)sock, &ir, 1, &n); } } ); return ret; } static int do_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *timeout) { int r = 0; if (nfds == 0) { if (timeout) rb_w32_sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000); else rb_w32_sleep(INFINITE); } else { RUBY_CRITICAL( EnterCriticalSection(&select_mutex); r = select(nfds, rd, wr, ex, timeout); LeaveCriticalSection(&select_mutex); if (r == SOCKET_ERROR) { errno = map_errno(WSAGetLastError()); r = -1; } ); } return r; } static inline int subtract(struct timeval *rest, const struct timeval *wait) { if (rest->tv_sec < wait->tv_sec) { return 0; } while (rest->tv_usec <= wait->tv_usec) { if (rest->tv_sec <= wait->tv_sec) { return 0; } rest->tv_sec -= 1; rest->tv_usec += 1000 * 1000; } rest->tv_sec -= wait->tv_sec; rest->tv_usec -= wait->tv_usec; return 1; } static inline int compare(const struct timeval *t1, const struct timeval *t2) { if (t1->tv_sec < t2->tv_sec) return -1; if (t1->tv_sec > t2->tv_sec) return 1; if (t1->tv_usec < t2->tv_usec) return -1; if (t1->tv_usec > t2->tv_usec) return 1; return 0; } #undef Sleep long rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *timeout) { long r; fd_set pipe_rd; fd_set cons_rd; fd_set else_rd; fd_set else_wr; int nonsock = 0; struct timeval limit; if (nfds < 0 || (timeout && (timeout->tv_sec < 0 || timeout->tv_usec < 0))) { errno = EINVAL; return -1; } if (timeout) { if (timeout->tv_sec < 0 || timeout->tv_usec < 0 || timeout->tv_usec >= 1000000) { errno = EINVAL; return -1; } gettimeofday(&limit, NULL); limit.tv_sec += timeout->tv_sec; limit.tv_usec += timeout->tv_usec; if (limit.tv_usec >= 1000000) { limit.tv_usec -= 1000000; limit.tv_sec++; } } if (!NtSocketsInitialized) { StartSockets(); } // assume else_{rd,wr} (other than socket, pipe reader, console reader) // are always readable/writable. but this implementation still has // problem. if pipe's buffer is full, writing to pipe will block // until some data is read from pipe. but ruby is single threaded system, // so whole system will be blocked forever. else_rd.fd_count = 0; nonsock += extract_fd(&else_rd, rd, is_not_socket); pipe_rd.fd_count = 0; extract_fd(&pipe_rd, &else_rd, is_pipe); // should not call is_pipe for socket cons_rd.fd_count = 0; extract_fd(&cons_rd, &else_rd, is_console); // ditto else_wr.fd_count = 0; nonsock += extract_fd(&else_wr, wr, is_not_socket); r = 0; if (rd && rd->fd_count > r) r = rd->fd_count; if (wr && wr->fd_count > r) r = wr->fd_count; if (ex && ex->fd_count > r) r = ex->fd_count; if (nfds > r) nfds = r; { struct timeval rest; struct timeval wait; struct timeval zero; wait.tv_sec = 0; wait.tv_usec = 10 * 1000; // 10ms zero.tv_sec = 0; zero.tv_usec = 0; // 0ms if (timeout) rest = *timeout; for (;;) { if (nonsock) { // modifying {else,pipe,cons}_rd is safe because // if they are modified, function returns immediately. extract_fd(&else_rd, &pipe_rd, is_readable_pipe); extract_fd(&else_rd, &cons_rd, is_readable_console); } if (else_rd.fd_count || else_wr.fd_count) { r = do_select(nfds, rd, wr, ex, &zero); // polling if (r < 0) break; // XXX: should I ignore error and return signaled handles? r += extract_fd(rd, &else_rd, NULL); // move all r += extract_fd(wr, &else_wr, NULL); // move all break; } else { fd_set orig_rd; fd_set orig_wr; fd_set orig_ex; struct timeval *dowait = &wait; if (timeout && compare(&rest, &wait) < 0) dowait = &rest; if (rd) orig_rd = *rd; if (wr) orig_wr = *wr; if (ex) orig_ex = *ex; r = do_select(nfds, rd, wr, ex, dowait); if (r != 0) break; // signaled or error if (rd) *rd = orig_rd; if (wr) *wr = orig_wr; if (ex) *ex = orig_ex; if (timeout) { struct timeval now; gettimeofday(&now, NULL); rest = limit; if (!subtract(&rest, &now)) break; } } } } return r; } static void StartSockets () { WORD version; WSADATA retdata; int ret; #ifndef USE_WINSOCK2 int iSockOpt; #endif // // initalize the winsock interface and insure that it's // cleaned up at exit. // #ifdef USE_WINSOCK2 version = MAKEWORD(2, 0); if (WSAStartup(version, &retdata)) rb_fatal ("Unable to locate winsock library!\n"); if (LOBYTE(retdata.wVersion) != 2) rb_fatal("could not find version 2 of winsock dll\n"); #else version = MAKEWORD(1, 1); if (ret = WSAStartup(version, &retdata)) rb_fatal ("Unable to locate winsock library!\n"); if (LOBYTE(retdata.wVersion) != 1) rb_fatal("could not find version 1 of winsock dll\n"); if (HIBYTE(retdata.wVersion) != 1) rb_fatal("could not find version 1 of winsock dll\n"); #endif /* USE_WINSOCK2 */ fWinsock = TRUE; #ifndef USE_WINSOCK2 # ifndef SO_SYNCHRONOUS_NONALERT # define SO_SYNCHRONOUS_NONALERT 0x20 # endif iSockOpt = SO_SYNCHRONOUS_NONALERT; /* * Enable the use of sockets as filehandles */ # ifndef SO_OPENTYPE # define SO_OPENTYPE 0x7008 # endif setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&iSockOpt, sizeof(iSockOpt)); #endif /* USE_WINSOCK2 */ main_thread.handle = GetCurrentThreadHandle(); main_thread.id = GetCurrentThreadId(); interrupted_event = CreateSignal(); if (!interrupted_event) rb_fatal("Unable to create interrupt event!\n"); NtSocketsInitialized = 1; } #undef accept int rb_w32_accept(int s, struct sockaddr *addr, int *addrlen) { SOCKET r; int fd; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ HANDLE h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL); fd = rb_w32_open_osfhandle((long)h, O_RDWR|O_BINARY|O_NOINHERIT); if (fd != -1) { r = accept(TO_SOCKET(s), addr, addrlen); if (r != INVALID_SOCKET) { MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock))); _set_osfhnd(fd, r); MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); CloseHandle(h); } else { errno = map_errno(WSAGetLastError()); close(fd); fd = -1; } } else CloseHandle(h); }); return fd; } #undef bind int rb_w32_bind(int s, struct sockaddr *addr, int addrlen) { int r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = bind(TO_SOCKET(s), addr, addrlen); if (r == SOCKET_ERROR) errno = map_errno(WSAGetLastError()); }); return r; } #undef connect int rb_w32_connect(int s, struct sockaddr *addr, int addrlen) { int r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = connect(TO_SOCKET(s), addr, addrlen); if (r == SOCKET_ERROR) { int err = WSAGetLastError(); if (err != WSAEWOULDBLOCK) errno = map_errno(err); else errno = EINPROGRESS; } }); return r; } #undef getpeername int rb_w32_getpeername(int s, struct sockaddr *addr, int *addrlen) { int r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = getpeername(TO_SOCKET(s), addr, addrlen); if (r == SOCKET_ERROR) errno = map_errno(WSAGetLastError()); }); return r; } #undef getsockname int rb_w32_getsockname(int s, struct sockaddr *addr, int *addrlen) { int r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = getsockname(TO_SOCKET(s), addr, addrlen); if (r == SOCKET_ERROR) errno = map_errno(WSAGetLastError()); }); return r; } int rb_w32_getsockopt(int s, int level, int optname, char *optval, int *optlen) { int r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = getsockopt(TO_SOCKET(s), level, optname, optval, optlen); if (r == SOCKET_ERROR) errno = map_errno(WSAGetLastError()); }); return r; } #undef ioctlsocket int rb_w32_ioctlsocket(int s, long cmd, u_long *argp) { int r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = ioctlsocket(TO_SOCKET(s), cmd, argp); if (r == SOCKET_ERROR) errno = map_errno(WSAGetLastError()); }); return r; } #undef listen int rb_w32_listen(int s, int backlog) { int r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = listen(TO_SOCKET(s), backlog); if (r == SOCKET_ERROR) errno = map_errno(WSAGetLastError()); }); return r; } #undef recv int rb_w32_recv(int s, char *buf, int len, int flags) { int r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = recv(TO_SOCKET(s), buf, len, flags); if (r == SOCKET_ERROR) errno = map_errno(WSAGetLastError()); }); return r; } #undef recvfrom int rb_w32_recvfrom(int s, char *buf, int len, int flags, struct sockaddr *from, int *fromlen) { int r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = recvfrom(TO_SOCKET(s), buf, len, flags, from, fromlen); if (r == SOCKET_ERROR) errno = map_errno(WSAGetLastError()); }); return r; } #undef send int rb_w32_send(int s, const char *buf, int len, int flags) { int r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = send(TO_SOCKET(s), buf, len, flags); if (r == SOCKET_ERROR) errno = map_errno(WSAGetLastError()); }); return r; } #undef sendto int rb_w32_sendto(int s, const char *buf, int len, int flags, struct sockaddr *to, int tolen) { int r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = sendto(TO_SOCKET(s), buf, len, flags, to, tolen); if (r == SOCKET_ERROR) errno = map_errno(WSAGetLastError()); }); return r; } #undef setsockopt int rb_w32_setsockopt(int s, int level, int optname, char *optval, int optlen) { int r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = setsockopt(TO_SOCKET(s), level, optname, optval, optlen); if (r == SOCKET_ERROR) errno = map_errno(WSAGetLastError()); }); return r; } #undef shutdown int rb_w32_shutdown(int s, int how) { int r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = shutdown(TO_SOCKET(s), how); if (r == SOCKET_ERROR) errno = map_errno(WSAGetLastError()); }); return r; } #ifdef USE_WINSOCK2 static SOCKET open_ifs_socket(int af, int type, int protocol) { unsigned long proto_buffers_len = 0; int error_code; SOCKET out = INVALID_SOCKET; if (WSAEnumProtocols(NULL, NULL, &proto_buffers_len) == SOCKET_ERROR) { error_code = WSAGetLastError(); if (error_code == WSAENOBUFS) { WSAPROTOCOL_INFO *proto_buffers; int protocols_available = 0; proto_buffers = (WSAPROTOCOL_INFO *)malloc(proto_buffers_len); if (!proto_buffers) { WSASetLastError(WSA_NOT_ENOUGH_MEMORY); return INVALID_SOCKET; } protocols_available = WSAEnumProtocols(NULL, proto_buffers, &proto_buffers_len); if (protocols_available != SOCKET_ERROR) { int i; for (i = 0; i < protocols_available; i++) { if ((af != AF_UNSPEC && af != proto_buffers[i].iAddressFamily) || (type != proto_buffers[i].iSocketType) || (protocol != 0 && protocol != proto_buffers[i].iProtocol)) continue; if ((proto_buffers[i].dwServiceFlags1 & XP1_IFS_HANDLES) == 0) continue; out = WSASocket(af, type, protocol, &(proto_buffers[i]), 0, 0); break; } if (out == INVALID_SOCKET) out = WSASocket(af, type, protocol, NULL, 0, 0); } free(proto_buffers); } } return out; } #endif /* USE_WINSOCK2 */ #undef socket #ifdef USE_WINSOCK2 #define open_socket(a, t, p) open_ifs_socket(a, t, p) #else #define open_socket(a, t, p) socket(a, t, p) #endif int rb_w32_socket(int af, int type, int protocol) { SOCKET s; int fd; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ s = open_socket(af, type, protocol); if (s == INVALID_SOCKET) { errno = map_errno(WSAGetLastError()); fd = -1; } else { fd = rb_w32_open_osfhandle(s, O_RDWR|O_BINARY); } }); return fd; } #undef gethostbyaddr struct hostent * rb_w32_gethostbyaddr (char *addr, int len, int type) { struct hostent *r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = gethostbyaddr(addr, len, type); if (r == NULL) errno = map_errno(WSAGetLastError()); }); return r; } #undef gethostbyname struct hostent * rb_w32_gethostbyname (char *name) { struct hostent *r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = gethostbyname(name); if (r == NULL) errno = map_errno(WSAGetLastError()); }); return r; } #undef gethostname int rb_w32_gethostname (char *name, int len) { int r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = gethostname(name, len); if (r == SOCKET_ERROR) errno = map_errno(WSAGetLastError()); }); return r; } #undef getprotobyname struct protoent * rb_w32_getprotobyname (char *name) { struct protoent *r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = getprotobyname(name); if (r == NULL) errno = map_errno(WSAGetLastError()); }); return r; } #undef getprotobynumber struct protoent * rb_w32_getprotobynumber (int num) { struct protoent *r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = getprotobynumber(num); if (r == NULL) errno = map_errno(WSAGetLastError()); }); return r; } #undef getservbyname struct servent * rb_w32_getservbyname (char *name, char *proto) { struct servent *r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = getservbyname(name, proto); if (r == NULL) errno = map_errno(WSAGetLastError()); }); return r; } #undef getservbyport struct servent * rb_w32_getservbyport (int port, char *proto) { struct servent *r; if (!NtSocketsInitialized) { StartSockets(); } RUBY_CRITICAL({ r = getservbyport(port, proto); if (r == NULL) errno = map_errno(WSAGetLastError()); }); return r; } // // Networking stubs // void endhostent() {} void endnetent() {} void endprotoent() {} void endservent() {} struct netent *getnetent (void) {return (struct netent *) NULL;} struct netent *getnetbyaddr(long net, int type) {return (struct netent *)NULL;} struct netent *getnetbyname(char *name) {return (struct netent *)NULL;} struct protoent *getprotoent (void) {return (struct protoent *) NULL;} struct servent *getservent (void) {return (struct servent *) NULL;} void sethostent (int stayopen) {} void setnetent (int stayopen) {} void setprotoent (int stayopen) {} void setservent (int stayopen) {} int fcntl(int fd, int cmd, ...) { SOCKET sock = TO_SOCKET(fd); va_list va; int arg; int ret; u_long ioctlArg; if (!is_socket(sock)) { errno = EBADF; return -1; } if (cmd != F_SETFL) { errno = EINVAL; return -1; } va_start(va, cmd); arg = va_arg(va, int); va_end(va); if (arg & O_NONBLOCK) { ioctlArg = 1; } else { ioctlArg = 0; } RUBY_CRITICAL({ ret = ioctlsocket(sock, FIONBIO, &ioctlArg); if (ret == -1) { errno = map_errno(WSAGetLastError()); } }); return ret; } #ifndef WNOHANG #define WNOHANG -1 #endif static rb_pid_t poll_child_status(struct ChildRecord *child, int *stat_loc) { DWORD exitcode; DWORD err; if (!GetExitCodeProcess(child->hProcess, &exitcode)) { /* If an error occured, return immediatly. */ err = GetLastError(); if (err == ERROR_INVALID_PARAMETER) errno = ECHILD; else errno = map_errno(GetLastError()); CloseChildHandle(child); return -1; } if (exitcode != STILL_ACTIVE) { /* If already died, return immediatly. */ rb_pid_t pid = child->pid; CloseChildHandle(child); if (stat_loc) *stat_loc = exitcode << 8; return pid; } return 0; } rb_pid_t waitpid(rb_pid_t pid, int *stat_loc, int options) { DWORD timeout; if (options == WNOHANG) { timeout = 0; } else { timeout = INFINITE; } if (pid == -1) { int count = 0; DWORD ret; HANDLE events[MAXCHILDNUM + 1]; FOREACH_CHILD(child) { if (!child->pid || child->pid < 0) continue; if ((pid = poll_child_status(child, stat_loc))) return pid; events[count++] = child->hProcess; } END_FOREACH_CHILD; if (!count) { errno = ECHILD; return -1; } events[count] = interrupted_event; ret = WaitForMultipleEvents(count + 1, events, FALSE, timeout, TRUE); if (ret == WAIT_TIMEOUT) return 0; if ((ret -= WAIT_OBJECT_0) == count) { ResetSignal(interrupted_event); errno = EINTR; return -1; } if (ret > count) { errno = map_errno(GetLastError()); return -1; } return poll_child_status(FindChildSlotByHandle(events[ret]), stat_loc); } else { struct ChildRecord* child = FindChildSlot(pid); if (!child) { errno = ECHILD; return -1; } while (!(pid = poll_child_status(child, stat_loc))) { /* wait... */ if (wait_events(child->hProcess, timeout) != WAIT_OBJECT_0) { /* still active */ pid = 0; break; } } } return pid; } #include static int filetime_to_timeval(const FILETIME* ft, struct timeval *tv) { ULARGE_INTEGER tmp; unsigned LONG_LONG lt; tmp.LowPart = ft->dwLowDateTime; tmp.HighPart = ft->dwHighDateTime; lt = tmp.QuadPart; /* lt is now 100-nanosec intervals since 1601/01/01 00:00:00 UTC, convert it into UNIX time (since 1970/01/01 00:00:00 UTC). the first leap second is at 1972/06/30, so we doesn't need to think about it. */ lt /= 10; /* to usec */ lt -= (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60 * 1000 * 1000; tv->tv_sec = lt / (1000 * 1000); tv->tv_usec = lt % (1000 * 1000); return tv->tv_sec > 0 ? 0 : -1; } int _cdecl gettimeofday(struct timeval *tv, struct timezone *tz) { FILETIME ft; GetSystemTimeAsFileTime(&ft); filetime_to_timeval(&ft, tv); return 0; } char * rb_w32_getcwd(char *buffer, int size) { char *p = buffer; char *bp; int len; len = GetCurrentDirectory(0, NULL); if (!len) { errno = map_errno(GetLastError()); return NULL; } if (p) { if (size < len) { errno = ERANGE; return NULL; } } else { p = malloc(len); size = len; if (!p) { errno = ENOMEM; return NULL; } } if (!GetCurrentDirectory(size, p)) { errno = map_errno(GetLastError()); if (!buffer) free(p); return NULL; } for (bp = p; *bp != '\0'; bp = CharNext(bp)) { if (*bp == '\\') { *bp = '/'; } } return p; } int chown(const char *path, int owner, int group) { return 0; } int kill(int pid, int sig) { int ret = 0; DWORD err; if (pid <= 0) { errno = EINVAL; return -1; } if (IsWin95()) pid = -pid; if ((unsigned int)pid == GetCurrentProcessId() && (sig != 0 && sig != SIGKILL)) { if ((ret = raise(sig)) != 0) { /* MSVCRT doesn't set errno... */ errno = EINVAL; } return ret; } switch (sig) { case 0: RUBY_CRITICAL({ HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid); if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) { if (GetLastError() == ERROR_INVALID_PARAMETER) { errno = ESRCH; } else { errno = EPERM; } ret = -1; } else { CloseHandle(hProc); } }); break; case SIGINT: RUBY_CRITICAL({ if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, (DWORD)pid)) { if ((err = GetLastError()) == 0) errno = EPERM; else errno = map_errno(GetLastError()); ret = -1; } }); break; case SIGKILL: RUBY_CRITICAL({ HANDLE hProc = OpenProcess(PROCESS_TERMINATE, FALSE, (DWORD)pid); if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) { if (GetLastError() == ERROR_INVALID_PARAMETER) { errno = ESRCH; } else { errno = EPERM; } ret = -1; } else { if (!TerminateProcess(hProc, 0)) { errno = EPERM; ret = -1; } CloseHandle(hProc); } }); break; default: errno = EINVAL; ret = -1; break; } return ret; } int link(char *from, char *to) { static BOOL (WINAPI *pCreateHardLink)(LPCTSTR, LPCTSTR, LPSECURITY_ATTRIBUTES) = NULL; static int myerrno = 0; if (!pCreateHardLink && !myerrno) { HANDLE hKernel; hKernel = GetModuleHandle("kernel32.dll"); if (hKernel) { pCreateHardLink = (BOOL (WINAPI *)(LPCTSTR, LPCTSTR, LPSECURITY_ATTRIBUTES))GetProcAddress(hKernel, "CreateHardLinkA"); if (!pCreateHardLink) { myerrno = map_errno(GetLastError()); } CloseHandle(hKernel); } else { myerrno = map_errno(GetLastError()); } } if (!pCreateHardLink) { errno = myerrno; return -1; } if (!pCreateHardLink(to, from, NULL)) { errno = map_errno(GetLastError()); return -1; } return 0; } int wait() { return 0; } char * rb_w32_getenv(const char *name) { int len = strlen(name); char *env; if (envarea) FreeEnvironmentStrings(envarea); envarea = GetEnvironmentStrings(); if (!envarea) { map_errno(GetLastError()); return NULL; } for (env = envarea; *env; env += strlen(env) + 1) if (strncasecmp(env, name, len) == 0 && *(env + len) == '=') return env + len + 1; return NULL; } int rb_w32_rename(const char *oldpath, const char *newpath) { int res = 0; int oldatts; int newatts; oldatts = GetFileAttributes(oldpath); newatts = GetFileAttributes(newpath); if (oldatts == -1) { errno = map_errno(GetLastError()); return -1; } RUBY_CRITICAL({ if (newatts != -1 && newatts & FILE_ATTRIBUTE_READONLY) SetFileAttributesA(newpath, newatts & ~ FILE_ATTRIBUTE_READONLY); if (!MoveFile(oldpath, newpath)) res = -1; if (res) { switch (GetLastError()) { case ERROR_ALREADY_EXISTS: case ERROR_FILE_EXISTS: if (IsWinNT()) { if (MoveFileEx(oldpath, newpath, MOVEFILE_REPLACE_EXISTING)) res = 0; } else { for (;;) { if (!DeleteFile(newpath) && GetLastError() != ERROR_FILE_NOT_FOUND) break; else if (MoveFile(oldpath, newpath)) { res = 0; break; } } } } } if (res) errno = map_errno(GetLastError()); else SetFileAttributes(newpath, oldatts); }); return res; } static int isUNCRoot(const char *path) { if (path[0] == '\\' && path[1] == '\\') { const char *p; for (p = path + 2; *p; p = CharNext(p)) { if (*p == '\\') break; } if (p[0] && p[1]) { for (p++; *p; p = CharNext(p)) { if (*p == '\\') break; } if (!p[0] || !p[1] || (p[1] == '.' && !p[2])) return 1; } } return 0; } static time_t filetime_to_unixtime(const FILETIME *ft) { struct timeval tv; if (filetime_to_timeval(ft, &tv) == (time_t)-1) return 0; else return tv.tv_sec; } static unsigned fileattr_to_unixmode(DWORD attr, const char *path) { unsigned mode = 0; if (attr & FILE_ATTRIBUTE_READONLY) { mode |= S_IREAD; } else { mode |= S_IREAD | S_IWRITE | S_IWUSR; } if (attr & FILE_ATTRIBUTE_DIRECTORY) { mode |= S_IFDIR | S_IEXEC; } else { mode |= S_IFREG; } if (path && (mode & S_IFREG)) { const char *end = path + strlen(path); while (path < end) { end = CharPrev(path, end); if (*end == '.') { if ((strcmpi(end, ".bat") == 0) || (strcmpi(end, ".cmd") == 0) || (strcmpi(end, ".com") == 0) || (strcmpi(end, ".exe") == 0)) { mode |= S_IEXEC; } break; } } } mode |= (mode & 0700) >> 3; mode |= (mode & 0700) >> 6; return mode; } static int check_valid_dir(const char *path) { WIN32_FIND_DATA fd; HANDLE fh = open_dir_handle(path, &fd); if (fh == INVALID_HANDLE_VALUE) return -1; FindClose(fh); return 0; } static int winnt_stat(const char *path, struct stat *st) { HANDLE h; WIN32_FIND_DATA wfd; memset(st, 0, sizeof(struct stat)); st->st_nlink = 1; if (_mbspbrk(path, "?*")) { errno = ENOENT; return -1; } h = FindFirstFile(path, &wfd); if (h != INVALID_HANDLE_VALUE) { FindClose(h); st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path); st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime); st->st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime); st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime); st->st_size = wfd.nFileSizeLow; /* TODO: 64bit support */ } else { // If runtime stat(2) is called for network shares, it fails on WinNT. // Because GetDriveType returns 1 for network shares. (Win98 returns 4) DWORD attr = GetFileAttributes(path); if (attr == -1) { errno = map_errno(GetLastError()); return -1; } if (attr & FILE_ATTRIBUTE_DIRECTORY) { if (check_valid_dir(path)) return -1; } st->st_mode = fileattr_to_unixmode(attr, path); } st->st_dev = st->st_rdev = (isalpha(path[0]) && path[1] == ':') ? toupper(path[0]) - 'A' : _getdrive() - 1; return 0; } #ifdef WIN95 static int win95_stat(const char *path, struct stat *st) { int ret = stat(path, st); if (ret) return ret; if (st->st_mode & S_IFDIR) { return check_valid_dir(path); } return 0; } #else #define win95_stat(path, st) -1 #endif int rb_w32_stat(const char *path, struct stat *st) { const char *p; char *buf1, *s, *end; int len; int ret; if (!path || !st) { errno = EFAULT; return -1; } buf1 = ALLOCA_N(char, strlen(path) + 2); for (p = path, s = buf1; *p; p++, s++) { if (*p == '/') *s = '\\'; else *s = *p; } *s = '\0'; len = s - buf1; if (!len || '\"' == *(--s)) { errno = ENOENT; return -1; } end = CharPrev(buf1, buf1 + len); if (isUNCRoot(buf1)) { if (*end == '.') *end = '\0'; else if (*end != '\\') strcat(buf1, "\\"); } else if (*end == '\\' || (buf1 + 1 == end && *end == ':')) strcat(buf1, "."); ret = IsWinNT() ? winnt_stat(buf1, st) : win95_stat(buf1, st); if (ret == 0) { st->st_mode &= ~(S_IWGRP | S_IWOTH); } return ret; } static long filetime_to_clock(FILETIME *ft) { __int64 qw = ft->dwHighDateTime; qw <<= 32; qw |= ft->dwLowDateTime; qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */ return (long) qw; } int rb_w32_times(struct tms *tmbuf) { FILETIME create, exit, kernel, user; if (GetProcessTimes(GetCurrentProcess(),&create, &exit, &kernel, &user)) { tmbuf->tms_utime = filetime_to_clock(&user); tmbuf->tms_stime = filetime_to_clock(&kernel); tmbuf->tms_cutime = 0; tmbuf->tms_cstime = 0; } else { tmbuf->tms_utime = clock(); tmbuf->tms_stime = 0; tmbuf->tms_cutime = 0; tmbuf->tms_cstime = 0; } return 0; } #define yield_once() Sleep(0) #define yield_until(condition) do yield_once(); while (!(condition)) static DWORD wait_events(HANDLE event, DWORD timeout) { HANDLE events[2]; int count = 0; DWORD ret; if (event) { events[count++] = event; } events[count++] = interrupted_event; ret = WaitForMultipleEvents(count, events, FALSE, timeout, TRUE); if (ret == WAIT_OBJECT_0 + count - 1) { ResetSignal(interrupted_event); errno = EINTR; } return ret; } static CRITICAL_SECTION * system_state(void) { static int initialized = 0; static CRITICAL_SECTION syssect; if (!initialized) { InitializeCriticalSection(&syssect); initialized = 1; } return &syssect; } static LONG flag_interrupt = -1; static volatile DWORD tlsi_interrupt = TLS_OUT_OF_INDEXES; void rb_w32_enter_critical(void) { if (IsWinNT()) { EnterCriticalSection(system_state()); return; } if (tlsi_interrupt == TLS_OUT_OF_INDEXES) { tlsi_interrupt = TlsAlloc(); } { DWORD ti = (DWORD)TlsGetValue(tlsi_interrupt); while (InterlockedIncrement(&flag_interrupt) > 0 && !ti) { InterlockedDecrement(&flag_interrupt); Sleep(1); } TlsSetValue(tlsi_interrupt, (PVOID)++ti); } } void rb_w32_leave_critical(void) { if (IsWinNT()) { LeaveCriticalSection(system_state()); return; } InterlockedDecrement(&flag_interrupt); TlsSetValue(tlsi_interrupt, (PVOID)((DWORD)TlsGetValue(tlsi_interrupt) - 1)); } struct handler_arg_t { void (*handler)(int); int arg; int status; int finished; HANDLE handshake; }; static void rb_w32_call_handler(struct handler_arg_t* h) { int status; RUBY_CRITICAL(rb_protect((VALUE (*)(VALUE))h->handler, (VALUE)h->arg, &h->status); status = h->status; SetEvent(h->handshake)); if (status) { rb_jump_tag(status); } h->finished = 1; yield_until(0); } static struct handler_arg_t * setup_handler(struct handler_arg_t *harg, int arg, void (*handler)(int), HANDLE handshake) { harg->handler = handler; harg->arg = arg; harg->status = 0; harg->finished = 0; harg->handshake = handshake; return harg; } static void setup_call(CONTEXT* ctx, struct handler_arg_t *harg) { #ifdef _M_IX86 DWORD *esp = (DWORD *)ctx->Esp; *--esp = (DWORD)harg; *--esp = ctx->Eip; ctx->Esp = (DWORD)esp; ctx->Eip = (DWORD)rb_w32_call_handler; #else #ifndef _WIN32_WCE #error unsupported processor #endif #endif } void rb_w32_interrupted(void) { SetSignal(interrupted_event); } int rb_w32_main_context(int arg, void (*handler)(int)) { static HANDLE interrupt_done = NULL; struct handler_arg_t harg; CONTEXT ctx_orig; HANDLE current_thread = GetCurrentThread(); int old_priority = GetThreadPriority(current_thread); if (GetCurrentThreadId() == main_thread.id) return FALSE; rb_w32_interrupted(); RUBY_CRITICAL({ /* the main thread must be in user state */ CONTEXT ctx; SuspendThread(main_thread.handle); SetThreadPriority(current_thread, GetThreadPriority(main_thread.handle)); ZeroMemory(&ctx, sizeof(CONTEXT)); ctx.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT; GetThreadContext(main_thread.handle, &ctx); ctx_orig = ctx; /* handler context setup */ if (!interrupt_done) { interrupt_done = CreateEvent(NULL, FALSE, FALSE, NULL); /* anonymous one-shot event */ } else { ResetEvent(interrupt_done); } setup_call(&ctx, setup_handler(&harg, arg, handler, interrupt_done)); ctx.ContextFlags = CONTEXT_CONTROL; SetThreadContext(main_thread.handle, &ctx); ResumeThread(main_thread.handle); }); /* give a chance to the main thread */ yield_once(); WaitForSingleObject(interrupt_done, INFINITE); /* handshaking */ if (!harg.status) { /* no exceptions raised, restore old context. */ RUBY_CRITICAL({ /* ensure the main thread is in user state. */ yield_until(harg.finished); SuspendThread(main_thread.handle); ctx_orig.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT; SetThreadContext(main_thread.handle, &ctx_orig); ResumeThread(main_thread.handle); }); } /* otherwise leave the main thread raised */ SetThreadPriority(current_thread, old_priority); return TRUE; } int rb_w32_sleep(unsigned long msec) { DWORD ret; RUBY_CRITICAL(ret = wait_events(NULL, msec)); yield_once(); CHECK_INTS; return ret != WAIT_TIMEOUT; } static void catch_interrupt(void) { yield_once(); RUBY_CRITICAL(wait_events(NULL, 0)); CHECK_INTS; } #undef fgetc int rb_w32_getc(FILE* stream) { int c, trap_immediate = rb_trap_immediate; #ifndef _WIN32_WCE if (enough_to_get(stream->FILE_COUNT)) { c = (unsigned char)*stream->FILE_READPTR++; rb_trap_immediate = trap_immediate; } else #endif { c = _filbuf(stream); #if defined __BORLANDC__ || defined _WIN32_WCE if ((c == EOF) && (errno == EPIPE)) { clearerr(stream); } #endif rb_trap_immediate = trap_immediate; catch_interrupt(); } return c; } #undef fputc int rb_w32_putc(int c, FILE* stream) { int trap_immediate = rb_trap_immediate; #ifndef _WIN32_WCE if (enough_to_put(stream->FILE_COUNT)) { c = (unsigned char)(*stream->FILE_READPTR++ = (char)c); rb_trap_immediate = trap_immediate; } else #endif { c = _flsbuf(c, stream); rb_trap_immediate = trap_immediate; catch_interrupt(); } return c; } struct asynchronous_arg_t { /* output field */ void* stackaddr; int errnum; /* input field */ VALUE (*func)(VALUE self, int argc, VALUE* argv); VALUE self; int argc; VALUE* argv; }; static DWORD WINAPI call_asynchronous(PVOID argp) { DWORD ret; struct asynchronous_arg_t *arg = argp; arg->stackaddr = &argp; ret = (DWORD)arg->func(arg->self, arg->argc, arg->argv); arg->errnum = errno; return ret; } VALUE rb_w32_asynchronize(asynchronous_func_t func, VALUE self, int argc, VALUE* argv, VALUE intrval) { DWORD val; BOOL interrupted = FALSE; HANDLE thr; RUBY_CRITICAL({ struct asynchronous_arg_t arg; arg.stackaddr = NULL; arg.errnum = 0; arg.func = func; arg.self = self; arg.argc = argc; arg.argv = argv; thr = CreateThread(NULL, 0, call_asynchronous, &arg, 0, &val); if (thr) { yield_until(arg.stackaddr); if (wait_events(thr, INFINITE) != WAIT_OBJECT_0) { interrupted = TRUE; if (TerminateThread(thr, intrval)) { yield_once(); } } GetExitCodeThread(thr, &val); CloseHandle(thr); if (interrupted) { /* must release stack of killed thread, why doesn't Windows? */ MEMORY_BASIC_INFORMATION m; memset(&m, 0, sizeof(m)); if (!VirtualQuery(arg.stackaddr, &m, sizeof(m))) { Debug(fprintf(stderr, "couldn't get stack base:%p:%d\n", arg.stackaddr, GetLastError())); } else if (!VirtualFree(m.AllocationBase, 0, MEM_RELEASE)) { Debug(fprintf(stderr, "couldn't release stack:%p:%d\n", m.AllocationBase, GetLastError())); } errno = EINTR; } else { errno = arg.errnum; } } }); if (!thr) { rb_fatal("failed to launch waiter thread:%d", GetLastError()); } if (interrupted) { CHECK_INTS; } return val; } char ** rb_w32_get_environ(void) { char *envtop, *env; char **myenvtop, **myenv; int num; /* * We avoid values started with `='. If you want to deal those values, * change this function, and some functions in hash.c which recognize * `=' as delimiter or rb_w32_getenv() and ruby_setenv(). * CygWin deals these values by changing first `=' to '!'. But we don't * use such trick and follow cmd.exe's way that just doesn't show these * values. * (U.N. 2001-11-15) */ envtop = GetEnvironmentStrings(); for (env = envtop, num = 0; *env; env += strlen(env) + 1) if (*env != '=') num++; myenvtop = (char **)malloc(sizeof(char *) * (num + 1)); for (env = envtop, myenv = myenvtop; *env; env += strlen(env) + 1) { if (*env != '=') { if (!(*myenv = (char *)malloc(strlen(env) + 1))) { break; } strcpy(*myenv, env); myenv++; } } *myenv = NULL; FreeEnvironmentStrings(envtop); return myenvtop; } void rb_w32_free_environ(char **env) { char **t = env; while (*t) free(*t++); free(env); } #undef getpid rb_pid_t rb_w32_getpid(void) { rb_pid_t pid; pid = getpid(); if (IsWin95()) pid = -pid; return pid; } int rb_w32_fclose(FILE *fp) { int fd = fileno(fp); SOCKET sock = TO_SOCKET(fd); int save_errno = errno; if (fflush(fp)) return -1; if (!is_socket(sock)) { UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN); return fclose(fp); } _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE); fclose(fp); errno = save_errno; if (closesocket(sock) == SOCKET_ERROR) { errno = map_errno(WSAGetLastError()); return -1; } return 0; } int rb_w32_close(int fd) { SOCKET sock = TO_SOCKET(fd); int save_errno = errno; if (!is_socket(sock)) { UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN); return _close(fd); } _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE); _close(fd); errno = save_errno; if (closesocket(sock) == SOCKET_ERROR) { errno = map_errno(WSAGetLastError()); return -1; } return 0; } #undef read size_t rb_w32_read(int fd, void *buf, size_t size) { SOCKET sock = TO_SOCKET(fd); if (!is_socket(sock)) return read(fd, buf, size); else return rb_w32_recv(fd, buf, size, 0); } #undef write size_t rb_w32_write(int fd, const void *buf, size_t size) { SOCKET sock = TO_SOCKET(fd); if (!is_socket(sock)) return write(fd, buf, size); else return rb_w32_send(fd, buf, size, 0); } static int unixtime_to_filetime(time_t time, FILETIME *ft) { struct tm *tm; SYSTEMTIME st; FILETIME lt; tm = localtime(&time); st.wYear = tm->tm_year + 1900; st.wMonth = tm->tm_mon + 1; st.wDayOfWeek = tm->tm_wday; st.wDay = tm->tm_mday; st.wHour = tm->tm_hour; st.wMinute = tm->tm_min; st.wSecond = tm->tm_sec; st.wMilliseconds = 0; if (!SystemTimeToFileTime(&st, <) || !LocalFileTimeToFileTime(<, ft)) { errno = map_errno(GetLastError()); return -1; } return 0; } int rb_w32_utime(const char *path, struct utimbuf *times) { HANDLE hFile; FILETIME atime, mtime; struct stat stat; int ret = 0; if (rb_w32_stat(path, &stat)) { return -1; } if (times) { if (unixtime_to_filetime(times->actime, &atime)) { return -1; } if (unixtime_to_filetime(times->modtime, &mtime)) { return -1; } } else { GetSystemTimeAsFileTime(&atime); mtime = atime; } RUBY_CRITICAL({ const DWORD attr = GetFileAttributes(path); if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) SetFileAttributes(path, attr & ~FILE_ATTRIBUTE_READONLY); hFile = CreateFile(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING, IsWin95() ? 0 : FILE_FLAG_BACKUP_SEMANTICS, 0); if (hFile == INVALID_HANDLE_VALUE) { errno = map_errno(GetLastError()); ret = -1; } else { if (!SetFileTime(hFile, NULL, &atime, &mtime)) { errno = map_errno(GetLastError()); ret = -1; } CloseHandle(hFile); } if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) SetFileAttributes(path, attr); }); return ret; } int rb_w32_vsnprintf(char *buf, size_t size, const char *format, va_list va) { int ret = _vsnprintf(buf, size, format, va); if (size > 0) buf[size - 1] = 0; return ret; } int rb_w32_snprintf(char *buf, size_t size, const char *format, ...) { int ret; va_list va; va_start(va, format); ret = vsnprintf(buf, size, format, va); va_end(va); return ret; } int rb_w32_mkdir(const char *path, int mode) { int ret = -1; RUBY_CRITICAL(do { if (CreateDirectory(path, NULL) == FALSE) { errno = map_errno(GetLastError()); break; } if (chmod(path, mode) == -1) { RemoveDirectory(path); break; } ret = 0; } while (0)); return ret; } int rb_w32_rmdir(const char *path) { int ret = 0; RUBY_CRITICAL({ const DWORD attr = GetFileAttributes(path); if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) { SetFileAttributes(path, attr & ~FILE_ATTRIBUTE_READONLY); } if (RemoveDirectory(path) == FALSE) { errno = map_errno(GetLastError()); ret = -1; if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) { SetFileAttributes(path, attr); } } }); return ret; } int rb_w32_unlink(const char *path) { int ret = 0; RUBY_CRITICAL({ const DWORD attr = GetFileAttributes(path); if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) { SetFileAttributes(path, attr & ~FILE_ATTRIBUTE_READONLY); } if (DeleteFile(path) == FALSE) { errno = map_errno(GetLastError()); ret = -1; if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) { SetFileAttributes(path, attr); } } }); return ret; } #if !defined(__BORLANDC__) && !defined(_WIN32_WCE) int rb_w32_isatty(int fd) { // validate fd by using _get_osfhandle() because we cannot access _nhandle if (_get_osfhandle(fd) == -1) { return 0; } if (!(_osfile(fd) & FOPEN)) { errno = EBADF; return 0; } if (!(_osfile(fd) & FDEV)) { errno = ENOTTY; return 0; } return 1; } #endif // // Fix bcc32's stdio bug // #ifdef __BORLANDC__ static int too_many_files() { FILE *f; for (f = _streams; f < _streams + _nfile; f++) { if (f->fd < 0) return 0; } return 1; } #undef fopen FILE * rb_w32_fopen(const char *path, const char *mode) { FILE *f = (errno = 0, fopen(path, mode)); if (f == NULL && errno == 0) { if (too_many_files()) errno = EMFILE; } return f; } FILE * rb_w32_fdopen(int handle, const char *type) { FILE *f = (errno = 0, _fdopen(handle, (char *)type)); if (f == NULL && errno == 0) { if (handle < 0) errno = EBADF; else if (too_many_files()) errno = EMFILE; } return f; } FILE * rb_w32_fsopen(const char *path, const char *mode, int shflags) { FILE *f = (errno = 0, _fsopen(path, mode, shflags)); if (f == NULL && errno == 0) { if (too_many_files()) errno = EMFILE; } return f; } #endif RUBY_EXTERN int __cdecl _CrtDbgReportW() {return 0;} ================================================ FILE: win32/win32.h ================================================ #ifndef RUBY_WIN32_H #define RUBY_WIN32_H /* * Copyright (c) 1993, Intergraph Corporation * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the perl README file. * */ // // Definitions for NT port of Perl // // // Ok now we can include the normal include files. // // #include conflict with varargs.h? #if !defined(IN) && !defined(FLOAT) #ifdef __BORLANDC__ #define USE_WINSOCK2 #endif #ifdef USE_WINSOCK2 #include #include #include #else #include #include #endif #endif #define NT 1 /* deprecated */ #ifdef _WIN32_WCE #undef CharNext #define CharNext CharNextA #endif // // We're not using Microsoft's "extensions" to C for // Structured Exception Handling (SEH) so we can nuke these // #undef try #undef except #undef finally #undef leave #include #include #include #include #include #include #if defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER == 1200 extern "C++" { /* template without extern "C++" */ #endif #include #if defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER == 1200 } #endif #include #include #include #if !defined(__BORLANDC__) # include #else # include #endif #include #include #ifdef _M_IX86 # define WIN95 1 #else # undef WIN95 #endif #ifdef WIN95 extern DWORD rb_w32_osid(void); #define rb_w32_iswinnt() (rb_w32_osid() == VER_PLATFORM_WIN32_NT) #define rb_w32_iswin95() (rb_w32_osid() == VER_PLATFORM_WIN32_WINDOWS) #else #define rb_w32_iswinnt() TRUE #define rb_w32_iswin95() FALSE #endif #define WNOHANG -1 #undef getc #undef putc #undef fgetc #undef fputc #undef getchar #undef putchar #undef fgetchar #undef fputchar #undef utime #define getc(_stream) rb_w32_getc(_stream) #define putc(_c, _stream) rb_w32_putc(_c, _stream) #define fgetc(_stream) getc(_stream) #define fputc(_c, _stream) putc(_c, _stream) #define getchar() rb_w32_getc(stdin) #define putchar(_c) rb_w32_putc(_c, stdout) #define fgetchar() getchar() #define fputchar(_c) putchar(_c) #define utime(_p, _t) rb_w32_utime(_p, _t) #define strcasecmp(s1, s2) stricmp(s1, s2) #define strncasecmp(s1, s2, n) strnicmp(s1, s2, n) #define close(h) rb_w32_close(h) #define fclose(f) rb_w32_fclose(f) #define read(f, b, s) rb_w32_read(f, b, s) #define write(f, b, s) rb_w32_write(f, b, s) #define getpid() rb_w32_getpid() #define sleep(x) rb_w32_sleep((x)*1000) #ifdef __BORLANDC__ #define creat(p, m) _creat(p, m) #define eof() _eof() #define filelength(h) _filelength(h) #define mktemp(t) _mktemp(t) #define tell(h) _tell(h) #define unlink(p) _unlink(p) #define _open _sopen #define sopen _sopen #undef fopen #define fopen(p, m) rb_w32_fopen(p, m) #undef fdopen #define fdopen(h, m) rb_w32_fdopen(h, m) #undef fsopen #define fsopen(p, m, sh) rb_w32_fsopen(p, m, sh) #endif #define fsync(h) _commit(h) #undef stat #define stat(path,st) rb_w32_stat(path,st) #undef execv #define execv(path,argv) do_aspawn(P_OVERLAY,path,argv) #if !defined(__BORLANDC__) && !defined(_WIN32_WCE) #undef isatty #define isatty(h) rb_w32_isatty(h) #endif #undef mkdir #define mkdir(p, m) rb_w32_mkdir(p, m) #undef rmdir #define rmdir(p) rb_w32_rmdir(p) #undef unlink #define unlink(p) rb_w32_unlink(p) #ifdef __MINGW32__ struct timezone { int tz_minuteswest; int tz_dsttime; }; #undef isascii #define isascii __isascii #endif extern void NtInitialize(int *, char ***); extern int rb_w32_cmdvector(const char *, char ***); extern rb_pid_t pipe_exec(const char *, int, FILE **, FILE **); extern int flock(int fd, int oper); extern int rb_w32_accept(int, struct sockaddr *, int *); extern int rb_w32_bind(int, struct sockaddr *, int); extern int rb_w32_connect(int, struct sockaddr *, int); extern void rb_w32_fdset(int, fd_set*); extern void rb_w32_fdclr(int, fd_set*); extern int rb_w32_fdisset(int, fd_set*); extern long rb_w32_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); extern int rb_w32_getpeername(int, struct sockaddr *, int *); extern int rb_w32_getsockname(int, struct sockaddr *, int *); extern int rb_w32_getsockopt(int, int, int, char *, int *); extern int rb_w32_ioctlsocket(int, long, u_long *); extern int rb_w32_listen(int, int); extern int rb_w32_recv(int, char *, int, int); extern int rb_w32_recvfrom(int, char *, int, int, struct sockaddr *, int *); extern int rb_w32_send(int, const char *, int, int); extern int rb_w32_sendto(int, const char *, int, int, struct sockaddr *, int); extern int rb_w32_setsockopt(int, int, int, char *, int); extern int rb_w32_shutdown(int, int); extern int rb_w32_socket(int, int, int); extern SOCKET rb_w32_get_osfhandle(int); extern struct hostent * rb_w32_gethostbyaddr(char *, int, int); extern struct hostent * rb_w32_gethostbyname(char *); extern int rb_w32_gethostname(char *, int); extern struct protoent * rb_w32_getprotobyname(char *); extern struct protoent * rb_w32_getprotobynumber(int); extern struct servent * rb_w32_getservbyname(char *, char *); extern struct servent * rb_w32_getservbyport(int, char *); extern char * rb_w32_getcwd(char *, int); extern char * rb_w32_getenv(const char *); extern int rb_w32_rename(const char *, const char *); extern int rb_w32_stat(const char *, struct stat *); extern char **rb_w32_get_environ(void); extern void rb_w32_free_environ(char **); extern int rb_w32_map_errno(DWORD); #define vsnprintf(s,n,f,l) rb_w32_vsnprintf(s,n,f,l) #define snprintf rb_w32_snprintf extern int rb_w32_vsnprintf(char *, size_t, const char *, va_list); extern int rb_w32_snprintf(char *, size_t, const char *, ...); extern int chown(const char *, int, int); extern int link(char *, char *); extern int gettimeofday(struct timeval *, struct timezone *); extern rb_pid_t waitpid (rb_pid_t, int *, int); extern int do_spawn(int, const char *); extern int do_aspawn(int, const char *, char **); extern int kill(int, int); extern int fcntl(int, int, ...); extern rb_pid_t rb_w32_getpid(void); #if !defined(__BORLANDC__) && !defined(_WIN32_WCE) extern int rb_w32_isatty(int); #endif extern int rb_w32_mkdir(const char *, int); extern int rb_w32_rmdir(const char *); extern int rb_w32_unlink(const char*); #ifdef __BORLANDC__ extern FILE *rb_w32_fopen(const char *, const char *); extern FILE *rb_w32_fdopen(int, const char *); extern FILE *rb_w32_fsopen(const char *, const char *, int); #endif #include #if !defined __MINGW32__ || defined __NO_ISOCEXT #ifndef isnan #define isnan(x) _isnan(x) #endif #ifndef finite #define finite(x) _finite(x) #endif #ifndef copysign #define copysign(a, b) _copysign(a, b) #endif #ifndef scalb #define scalb(a, b) _scalb(a, b) #endif #endif #if !defined S_IFIFO && defined _S_IFIFO #define S_IFIFO _S_IFIFO #endif #ifdef __BORLANDC__ #undef S_ISDIR #undef S_ISFIFO #undef S_ISBLK #undef S_ISCHR #undef S_ISREG #define S_ISDIR(m) (((unsigned short)(m) & S_IFMT) == S_IFDIR) #define S_ISFIFO(m) (((unsigned short)(m) & S_IFMT) == S_IFIFO) #define S_ISBLK(m) (((unsigned short)(m) & S_IFMT) == S_IFBLK) #define S_ISCHR(m) (((unsigned short)(m) & S_IFMT) == S_IFCHR) #define S_ISREG(m) (((unsigned short)(m) & S_IFMT) == S_IFREG) #endif #if !defined S_IRUSR && !defined __MINGW32__ #define S_IRUSR 0400 #endif #ifndef S_IRGRP #define S_IRGRP 0040 #endif #ifndef S_IROTH #define S_IROTH 0004 #endif #if !defined S_IWUSR && !defined __MINGW32__ #define S_IWUSR 0200 #endif #ifndef S_IWGRP #define S_IWGRP 0020 #endif #ifndef S_IWOTH #define S_IWOTH 0002 #endif #if !defined S_IXUSR && !defined __MINGW32__ #define S_IXUSR 0100 #endif #ifndef S_IXGRP #define S_IXGRP 0010 #endif #ifndef S_IXOTH #define S_IXOTH 0001 #endif // // define this so we can do inplace editing // #define SUFFIX // // stubs // #if !defined(__BORLANDC__) extern int ioctl (int, unsigned int, long); #endif extern rb_uid_t getuid (void); extern rb_uid_t geteuid (void); extern rb_gid_t getgid (void); extern rb_gid_t getegid (void); extern int setuid (rb_uid_t); extern int setgid (rb_gid_t); extern char *rb_w32_strerror(int); #define strerror(e) rb_w32_strerror(e) #define PIPE_BUF 1024 #define LOCK_SH 1 #define LOCK_EX 2 #define LOCK_NB 4 #define LOCK_UN 8 #ifndef SIGINT #define SIGINT 2 #endif #ifndef SIGKILL #define SIGKILL 9 #endif /* #undef va_start */ /* #undef va_end */ /* winsock error map */ #define EWOULDBLOCK WSAEWOULDBLOCK #define EINPROGRESS WSAEINPROGRESS #define EALREADY WSAEALREADY #define ENOTSOCK WSAENOTSOCK #define EDESTADDRREQ WSAEDESTADDRREQ #define EMSGSIZE WSAEMSGSIZE #define EPROTOTYPE WSAEPROTOTYPE #define ENOPROTOOPT WSAENOPROTOOPT #define EPROTONOSUPPORT WSAEPROTONOSUPPORT #define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT #define EOPNOTSUPP WSAEOPNOTSUPP #define EPFNOSUPPORT WSAEPFNOSUPPORT #define EAFNOSUPPORT WSAEAFNOSUPPORT #define EADDRINUSE WSAEADDRINUSE #define EADDRNOTAVAIL WSAEADDRNOTAVAIL #define ENETDOWN WSAENETDOWN #define ENETUNREACH WSAENETUNREACH #define ENETRESET WSAENETRESET #define ECONNABORTED WSAECONNABORTED #define ECONNRESET WSAECONNRESET #define ENOBUFS WSAENOBUFS #define EISCONN WSAEISCONN #define ENOTCONN WSAENOTCONN #define ESHUTDOWN WSAESHUTDOWN #define ETOOMANYREFS WSAETOOMANYREFS #define ETIMEDOUT WSAETIMEDOUT #define ECONNREFUSED WSAECONNREFUSED #define ELOOP WSAELOOP /*#define ENAMETOOLONG WSAENAMETOOLONG*/ #define EHOSTDOWN WSAEHOSTDOWN #define EHOSTUNREACH WSAEHOSTUNREACH /*#define ENOTEMPTY WSAENOTEMPTY*/ #define EPROCLIM WSAEPROCLIM #define EUSERS WSAEUSERS #define EDQUOT WSAEDQUOT #define ESTALE WSAESTALE #define EREMOTE WSAEREMOTE #define F_SETFL 1 #define O_NONBLOCK 1 #ifdef accept #undef accept #endif #define accept(s, a, l) rb_w32_accept(s, a, l) #ifdef bind #undef bind #endif #define bind(s, a, l) rb_w32_bind(s, a, l) #ifdef connect #undef connect #endif #define connect(s, a, l) rb_w32_connect(s, a, l) #undef FD_SET #define FD_SET(f, s) rb_w32_fdset(f, s) #undef FD_CLR #define FD_CLR(f, s) rb_w32_fdclr(f, s) #undef FD_ISSET #define FD_ISSET(f, s) rb_w32_fdisset(f, s) #undef select #define select(n, r, w, e, t) rb_w32_select(n, r, w, e, t) #ifdef getpeername #undef getpeername #endif #define getpeername(s, a, l) rb_w32_getpeername(s, a, l) #ifdef getsockname #undef getsockname #endif #define getsockname(s, a, l) rb_w32_getsockname(s, a, l) #ifdef getsockopt #undef getsockopt #endif #define getsockopt(s, v, n, o, l) rb_w32_getsockopt(s, v, n, o, l) #ifdef ioctlsocket #undef ioctlsocket #endif #define ioctlsocket(s, c, a) rb_w32_ioctlsocket(s, c, a) #ifdef listen #undef listen #endif #define listen(s, b) rb_w32_listen(s, b) #ifdef recv #undef recv #endif #define recv(s, b, l, f) rb_w32_recv(s, b, l, f) #ifdef recvfrom #undef recvfrom #endif #define recvfrom(s, b, l, f, fr, frl) rb_w32_recvfrom(s, b, l, f, fr, frl) #ifdef send #undef send #endif #define send(s, b, l, f) rb_w32_send(s, b, l, f) #ifdef sendto #undef sendto #endif #define sendto(s, b, l, f, t, tl) rb_w32_sendto(s, b, l, f, t, tl) #ifdef setsockopt #undef setsockopt #endif #define setsockopt(s, v, n, o, l) rb_w32_setsockopt(s, v, n, o, l) #ifdef shutdown #undef shutdown #endif #define shutdown(s, h) rb_w32_shutdown(s, h) #ifdef socket #undef socket #endif #define socket(s, t, p) rb_w32_socket(s, t, p) #ifdef gethostbyaddr #undef gethostbyaddr #endif #define gethostbyaddr(a, l, t) rb_w32_gethostbyaddr(a, l, t) #ifdef gethostbyname #undef gethostbyname #endif #define gethostbyname(n) rb_w32_gethostbyname(n) #ifdef gethostname #undef gethostname #endif #define gethostname(n, l) rb_w32_gethostname(n, l) #ifdef getprotobyname #undef getprotobyname #endif #define getprotobyname(n) rb_w32_getprotobyname(n) #ifdef getprotobynumber #undef getprotobynumber #endif #define getprotobynumber(n) rb_w32_getprotobynumber(n) #ifdef getservbyname #undef getservbyname #endif #define getservbyname(n, p) rb_w32_getservbyname(n, p) #ifdef getservbyport #undef getservbyport #endif #define getservbyport(p, pr) rb_w32_getservbyport(p, pr) #ifdef get_osfhandle #undef get_osfhandle #endif #define get_osfhandle(h) rb_w32_get_osfhandle(h) #ifdef getcwd #undef getcwd #endif #define getcwd(b, s) rb_w32_getcwd(b, s) #ifdef getenv #undef getenv #endif #define getenv(n) rb_w32_getenv(n) #ifdef rename #undef rename #endif #define rename(o, n) rb_w32_rename(o, n) struct tms { long tms_utime; long tms_stime; long tms_cutime; long tms_cstime; }; #ifdef times #undef times #endif #define times(t) rb_w32_times(t) int rb_w32_times(struct tms *); /* thread stuff */ HANDLE GetCurrentThreadHandle(void); void rb_w32_interrupted(void); int rb_w32_main_context(int arg, void (*handler)(int)); int rb_w32_sleep(unsigned long msec); void rb_w32_enter_critical(void); void rb_w32_leave_critical(void); int rb_w32_putc(int, FILE*); int rb_w32_getc(FILE*); int rb_w32_close(int); int rb_w32_fclose(FILE*); size_t rb_w32_read(int, void *, size_t); size_t rb_w32_write(int, const void *, size_t); int rb_w32_utime(const char *, struct utimbuf *); #define Sleep(msec) (void)rb_w32_sleep(msec) /* == ***CAUTION*** Since this function is very dangerous, ((*NEVER*)) * lock any HANDLEs(i.e. Mutex, Semaphore, CriticalSection and so on) or, * use anything like TRAP_BEG...TRAP_END block structure, in asynchronous_func_t. */ typedef DWORD (*asynchronous_func_t)(DWORD self, int argc, DWORD* argv); DWORD rb_w32_asynchronize(asynchronous_func_t func, DWORD self, int argc, DWORD* argv, DWORD intrval); #endif ================================================ FILE: win32/winmain.c ================================================ #include #include extern int main(int, char**, char**); int WINAPI WinMain(HINSTANCE current, HINSTANCE prev, LPSTR cmdline, int showcmd) { return main(0, NULL, NULL); } ================================================ FILE: wince/Makefile.sub ================================================ # -*- makefile -*- CROSS_COMPILING = 1 LARGEFILE_SUPPORT = 0 !ifndef win_srcdir win_srcdir = $(srcdir)/wince !endif !if !defined(OS) || !defined(RT) OS = mswince RT = $(OS) !endif !if !defined(WARNFLAGS) WARNFLAGS = -w !endif ARCHDEFS = $(CECPUDEF) -DUNDER_CE -D_WIN32_WCE=$(SUBSYSVERSION:.=) \ -DFILENAME_MAX=MAX_PATH -DTLS_OUT_OF_INDEXES=0xFFFFFFFF \ -DBUFSIZ=512 -D_UNICODE -DUNICODE !if !defined(LDFLAGS) LDFLAGS = -link -incremental:yes -pdb:none -machine:$(MACHINE) -subsystem:$(SUBSYSTEM) !endif !if !defined(XLDFLAGS) XLDFLAGS = -stack:$(STACK) -subsystem:$(SUBSYSTEM) !endif LIBS = coredll.lib ceshell.lib winsock.lib $(EXTLIBS) MISSING = acosh.obj crypt.obj dup2.obj erf.obj hypot.obj \ isinf.obj isnan.obj strftime.obj win32.obj \ assert.obj direct.obj errno.obj io_wce.obj process_wce.obj \ signal_wce.obj stdio.obj stdlib.obj string_wce.obj \ time_wce.obj wince.obj winsock2.obj \ stat.obj timeb.obj utime.obj LIBOBJS = isinf.obj isnan.obj COMMON_LIBS = coredll winsock COMMON_MACROS = WIN32_LEAN_AND_MEAN COMMON_HEADERS = winsock.h windows.h XCFLAGS = -I$(srcdir)/wince !if !defined(STACK_COMMIT) STACK_COMMIT = 0x10000 !endif WINMAINOBJ = wincemain.$(OBJEXT) !include $(srcdir)/win32/Makefile.sub ================================================ FILE: wince/README.wince ================================================ =begin = How to build ruby using eMbedded Visual C++ == Requirement (1) eMbedded Visual C++ 3.0 or later. (2) If you want to run `((%nmake clean%))' or `((%nmake distclean%))' properly, you must install UNIX compatible `((%rm%))' command on your ((|PATH|)) if you want to clean after compile. (3) Please set environment variable (({INCLUDE})), (({LIB})), (({PATH})), (({CE_TOOLS_DIR})), (({EMBEDDED_TOOLS_DIR})) to run required commands properly from the command line. Note: building ruby requires following commands. * nmake * clarm or clmips or shcl * lib * dumpbin == How to compile and install (1) Execute wince\configure.bat on your build directory. You can specify the target platform as an argument. For example, run `((%configure arm-hpc2k-wince%))' (2) Change ((|RUBY_INSTALL_NAME|)) and ((|RUBY_SO_NAME|)) in (({Makefile})) if you want to change the name of the executable files. (3) Run `((%nmake%))' (4) Run `((%nmake DESTDIR= install%))' This command will create following directories and copy (not install :-P) files onto them. * \bin * \lib * \lib\ruby * \lib\ruby\. * \lib\ruby\.\ * \lib\ruby\site_ruby * \lib\ruby\site_ruby\. * \lib\ruby\site_ruby\.\ * \man\man1 If Ruby's version is `x.y.z', the ((||)) is `x' and the ((||)) is `y'. In case of `mips-hpc2k-wince', The ((||)) is `(({mips-mswince}))'. (5) Copy to your WindowsCE machine. == Icons Any icon files(*.ico) in the build directory, directories specified with ((|icondirs|)) make variable and (({win32})) directory under the ruby source directory will be included in DLL or executable files, according to their base names. $(RUBY_INSTALL_NAME).ico or ruby.ico --> $(RUBY_INSTALL_NAME).exe $(RUBYW_INSTALL_NAME).ico or rubyw.ico --> $(RUBYW_INSTALL_NAME).exe the others --> $(RUBY_SO_NAME).dll Although no icons are distributed with the ruby source or in the official site, you can use anything you like. For example, followings are written in Japanese, but you can download at least. * (()) or (()) * (()) or (()) == Build examples * Build on the ruby source directory. ex.) ruby source directory: C:\ruby build directory: C:\ruby install directory: C:\usr\local C: cd \ruby win32\configure nmake nmake DESTDIR=/usr/local install * Build on the relative directory from the ruby source directory. ex.) ruby source directory: C:\ruby build directory: C:\ruby\mswin32 install directory: C:\usr\local C: cd \ruby mkdir mswin32 cd mswin32 ..\win32\configure nmake nmake DESTDIR=/usr/local install * Build on the different drive. ex.) ruby source directory: C:\src\ruby build directory: D:\build\ruby install directory: C:\usr\local D: cd D:\build\ruby C:\src\ruby\win32\configure nmake nmake DESTDIR=C:/usr/local install == Bugs You can ((*NOT*)) use a path name contains any white space characters as the ruby source directory, this restriction comes from the behavior of (({!INCLUDE})) directives of (({NMAKE})). ((- you may call it a bug. -)) =end ================================================ FILE: wince/assert.c ================================================ #include #include #include "assert.h" void assert( int expression ) { if( expression==0 ) exit(2); } ================================================ FILE: wince/assert.h ================================================ #ifndef _ASSERT_H_ #define _ASSERT_H_ void assert( int expression ); #endif ================================================ FILE: wince/configure.bat ================================================ @echo off ::: Don't set environment variable in batch file other than autoexec.bat ::: to avoid "Out of environment space" problem on Windows 95/98. ::: set TMPMAKE=~tmp~.mak echo> ~tmp~.mak #### echo>> ~tmp~.mak conf = %0 echo>> ~tmp~.mak $(conf:\=/): nul echo>> ~tmp~.mak @del ~tmp~.mak echo>> ~tmp~.mak @-$(MAKE) -l$(MAKEFLAGS) -f $(@D)/setup.mak \ :loop if "%1" == "" goto :end if "%1" == "--prefix" goto :prefix if "%1" == "--srcdir" goto :srcdir if "%1" == "srcdir" goto :srcdir if "%1" == "--target" goto :target if "%1" == "target" goto :target if "%1" == "--with-static-linked-ext" goto :extstatic if "%1" == "--program-suffix" goto :suffix if "%1" == "--program-name" goto :progname if "%1" == "--enable-install-doc" goto :enable-rdoc if "%1" == "--disable-install-doc" goto :disable-rdoc if "%1" == "--extout" goto :extout if "%1" == "-h" goto :help if "%1" == "--help" goto :help if "%1" == "CC" goto :define if "%1" == "EMBEDDED_TOOLS_DIR" goto :define if "%1" == "CE_TOOLS_DIR" goto :define if "%1" == "EMBEDDED_TOOLS4_DIR" goto :define if "%1" == "CE_TOOLS4_DIR" goto :define echo>> ~tmp~.mak "%1" \ shift goto :loop :srcdir echo>> ~tmp~.mak "srcdir=%2" \ shift shift goto :loop :prefix echo>> ~tmp~.mak "prefix=%2" \ shift shift goto :loop :suffix echo>> ~tmp~.mak "RUBY_SUFFIX=%2" \ shift shift goto :loop :installname echo>> ~tmp~.mak "RUBY_INSTALL_NAME=%2" \ shift shift goto :loop :soname echo>> ~tmp~.mak "RUBY_SO_NAME=%2" \ shift shift goto :loop :define echo>> ~tmp~.mak "%1=%2" \ shift shift goto :loop :target echo>> ~tmp~.mak "%2" \ shift shift goto :loop :extstatic echo>> ~tmp~.mak "EXTSTATIC=static" \ shift goto :loop :enable-rdoc echo>> ~tmp~.mak "RDOCTARGET=install-doc" \ shift goto :loop :disable-rdoc echo>> ~tmp~.mak "RDOCTARGET=install-nodoc" \ shift goto :loop :extout echo>> ~tmp~.mak "EXTOUT=%2" \ shift shift goto :loop :help echo Configuration: echo --help display this help echo --srcdir=DIR find the sources in DIR [configure dir or `..'] echo Installation directories: echo --prefix=PREFIX install files in PREFIX (ignored currently) echo System types: echo --target=TARGET configure for TARGET [i386-mswin32] echo Optional Package: echo --with-static-linked-ext link external modules statically echo --enable-install-doc install rdoc indexes during install del ~tmp~.mak goto :exit :end echo>> ~tmp~.mak WIN32DIR=$(@D) nmake -alf ~tmp~.mak :exit ================================================ FILE: wince/direct.c ================================================ /*************************************************************** direct.c ***************************************************************/ #include #include #include #include "wince.h" /* for wce_mbtowc */ /* global for chdir, getcwd */ char _currentdir[MAX_PATH+1]; char *getcwd(char* buffer, int maxlen) { strcpy( buffer, _currentdir ); return buffer; } int _chdir(const char * dirname) { if( MAX_PATH < strlen(dirname) ) return -1; strcpy( _currentdir, dirname ); return 0; } int _rmdir(const char * dir) { wchar_t *wdir; BOOL rc; /* replace with RemoveDirectory. */ wdir = wce_mbtowc(dir); rc = RemoveDirectoryW(wdir); free(wdir); return rc==TRUE ? 0 : -1; } int _mkdir(const char * dir) { wchar_t* wdir; BOOL rc; /* replace with CreateDirectory. */ wdir = wce_mbtowc(dir); rc = CreateDirectoryW(wdir, NULL); free(wdir); return rc==TRUE ? 0 : -1; } ================================================ FILE: wince/direct.h ================================================ #ifndef DIRECT_H #define DIRECT_H 1 #ifdef __cplusplus extern "C" { #endif char *getcwd(char* buffer, int maxlen); int _chdir(const char * dirname); int _rmdir(const char * dir); int _mkdir(const char * dir); #ifdef __cplusplus }; #endif #define chdir _chdir #define rmdir _rmdir #define mkdir _mkdir #endif ================================================ FILE: wince/errno.c ================================================ /*************************************************************** errno.c ***************************************************************/ #include int errno; int _doserrno; int _sys_nerr; ================================================ FILE: wince/errno.h ================================================ #ifndef ERRNO_H #define ERRNO_H 1 #define EPERM 1 #define ENOENT 2 #define ESRCH 3 #define EINTR 4 #define EIO 5 #define ENXIO 6 #define E2BIG 7 #define ENOEXEC 8 #define EBADF 9 #define ECHILD 10 #define EAGAIN 11 #define ENOMEM 12 #define EACCES 13 #define EFAULT 14 #define EOSERR 15 // rk #define EBUSY 16 #define EEXIST 17 #define EXDEV 18 #define ENODEV 19 #define ENOTDIR 20 #define EISDIR 21 #define EINVAL 22 #define ENFILE 23 #define EMFILE 24 #define ENOTTY 25 #define EFBIG 27 #define ENOSPC 28 #define ESPIPE 29 #define EROFS 30 #define EMLINK 31 #define EPIPE 32 #define EDOM 33 #define ERANGE 34 #define EDEADLK 36 #define ENOSYS 37 #ifdef __cplusplus extern "C" { #endif extern int errno; extern int _doserrno; extern int _sys_nerr; #define sys_nerr _sys_nerr #ifdef __cplusplus }; #endif #endif ================================================ FILE: wince/fcntl.h ================================================ #ifndef FCNTL_H #define FCNTL_H 1 #define F_SETFL 1 #define F_SETFD 2 #define F_GETFL 3 #define _O_RDONLY 0x0000 /* open for reading only */ #define _O_WRONLY 0x0001 /* open for writing only */ #define _O_RDWR 0x0002 /* open for reading and writing */ #define _O_NONBLOCK 0x0004 #define _O_APPEND 0x0008 /* writes done at eof */ #define _O_CREAT 0x0100 /* create and open file */ #define _O_TRUNC 0x0200 /* open and truncate */ #define _O_EXCL 0x0400 /* open only if file doesn't already exist */ #define _O_TEXT 0x4000 /* file mode is text (translated) */ #define _O_BINARY 0x8000 /* file mode is binary (untranslated) */ #define _O_ACCMODE 0x10000 #define _O_NOINHERIT 0 #define O_NOINHERIT _O_NOINHERIT #define O_RDONLY _O_RDONLY #define O_WRONLY _O_WRONLY #define O_RDWR _O_RDWR #define O_NONBLOCK _O_NONBLOCK #define O_APPEND _O_APPEND #define O_CREAT _O_CREAT #define O_TRUNC _O_TRUNC #define O_EXCL _O_EXCL #define O_TEXT _O_TEXT #define O_BINARY _O_BINARY #define O_ACCMODE _O_ACCMODE #endif ================================================ FILE: wince/io.h ================================================ #ifndef _IO_WINCE_H_ #define _IO_WINCE_H_ #ifndef _TIME_T_DEFINED typedef unsigned long time_t; #define _TIME_T_DEFINED #endif #ifndef _FSIZE_T_DEFINED typedef unsigned long _fsize_t; /* Could be 64 bits for Win32 */ #define _FSIZE_T_DEFINED #endif #ifndef _FINDDATA_T_DEFINED struct _finddata_t { unsigned attrib; time_t time_create; /* -1 for FAT file systems */ time_t time_access; /* -1 for FAT file systems */ time_t time_write; _fsize_t size; char name[260]; }; #define _FINDDATA_T_DEFINED #endif #ifdef __cplusplus extern "C" { #endif int _chsize(int handle, long size); int _rename (const char *oldname, const char *newname); int _unlink(const char *file); int _umask(int cmask); int _chmod(const char *path, int mode); int dup( int handle ); //int dup2( int handle1, int handle2 ); int _isatty(int fd); int _pipe(int *phandles, unsigned int psize, int textmode); int _access(const char *filename, int flags); int _open_osfhandle ( long osfhandle, int flags); long _get_osfhandle( int filehandle ); int _open(const char *file, int mode,...); int close(int fd); int _read(int fd, void *buffer, int length); int _write(int fd, const void *buffer, unsigned count); long _lseek(int handle, long offset, int origin); long _findfirst( char *filespec, struct _finddata_t *fileinfo ); int _findnext( long handle, struct _finddata_t *fileinfo ); int _findclose( long handle ); #ifdef __cplusplus }; #endif #define chmod _chmod #define chsize _chsize #define rename _rename #define unlink _unlink #define open _open //#define close _close #define read _read #define write _write #define umask _umask //#define dup _dup #define isatty _isatty #define access _access #define pipe _pipe #define setmode _setmode #define lseek _lseek #define _close close #endif ================================================ FILE: wince/io_wce.c ================================================ /*************************************************************** io.c author : uema2 date : Nov 30, 2002 You can freely use, copy, modify, and redistribute the whole contents. ***************************************************************/ #include #include #include #include #include #include #include "wince.h" /* for wce_mbtowc */ extern int _errno; int _rename(const char *oldname, const char *newname) { wchar_t *wold, *wnew; BOOL rc; wold = wce_mbtowc(oldname); wnew = wce_mbtowc(newname); /* replace with MoveFile. */ rc = MoveFileW(wold, wnew); free(wold); free(wnew); return rc==TRUE ? 0 : -1; } int _unlink(const char *file) { wchar_t *wfile; BOOL rc; /* replace with DeleteFile. */ wfile = wce_mbtowc(file); rc = DeleteFileW(wfile); free(wfile); return rc==TRUE ? 0 : -1; } /* replace "open" with "CreateFile", etc. */ int _open(const char *file, int mode, va_list arg) { wchar_t *wfile; DWORD access=0, share=0, create=0; HANDLE h; if( (mode&_O_RDWR) != 0 ) access = GENERIC_READ|GENERIC_WRITE; else if( (mode&_O_RDONLY) != 0 ) access = GENERIC_READ; else if( (mode&_O_WRONLY) != 0 ) access = GENERIC_WRITE; if( (mode&_O_CREAT) != 0 ) create = CREATE_ALWAYS; else create = OPEN_ALWAYS; wfile = wce_mbtowc(file); h = CreateFileW(wfile, access, share, NULL, create, 0, NULL ); free(wfile); return (int)h; } int close(int fd) { CloseHandle( (HANDLE)fd ); return 0; } int _read(int fd, void *buffer, int length) { DWORD dw; ReadFile( (HANDLE)fd, buffer, length, &dw, NULL ); return (int)dw; } int _write(int fd, const void *buffer, unsigned count) { DWORD dw; WriteFile( (HANDLE)fd, buffer, count, &dw, NULL ); return (int)dw; } long _lseek(int handle, long offset, int origin) { DWORD flag, ret; switch(origin) { case SEEK_SET: flag = FILE_BEGIN; break; case SEEK_CUR: flag = FILE_CURRENT; break; case SEEK_END: flag = FILE_END; break; default: flag = FILE_CURRENT; break; } ret = SetFilePointer( (HANDLE)handle, offset, NULL, flag ); return ret==0xFFFFFFFF ? -1 : 0; } /* _findfirst, _findnext, _findclose. */ /* replace them with FindFirstFile, etc. */ long _findfirst( char *file, struct _finddata_t *fi ) { HANDLE h; WIN32_FIND_DATAA fda; h = FindFirstFileA( file, &fda ); if( h==NULL ) { errno = EINVAL; return -1; } fi->attrib = fda.dwFileAttributes; fi->time_create = wce_FILETIME2time_t( &fda.ftCreationTime ); fi->time_access = wce_FILETIME2time_t( &fda.ftLastAccessTime ); fi->time_write = wce_FILETIME2time_t( &fda.ftLastWriteTime ); fi->size = fda.nFileSizeLow + (fda.nFileSizeHigh<<32); strcpy( fi->name, fda.cFileName ); return (long)h; } int _findnext( long handle, struct _finddata_t *fi ) { WIN32_FIND_DATAA fda; BOOL b; b = FindNextFileA( (HANDLE)handle, &fda ); if( b==FALSE ) { errno = ENOENT; return -1; } fi->attrib = fda.dwFileAttributes; fi->time_create = wce_FILETIME2time_t( &fda.ftCreationTime ); fi->time_access = wce_FILETIME2time_t( &fda.ftLastAccessTime ); fi->time_write = wce_FILETIME2time_t( &fda.ftLastWriteTime ); fi->size = fda.nFileSizeLow + (fda.nFileSizeHigh<<32); strcpy( fi->name, fda.cFileName ); return 0; } int _findclose( long handle ) { BOOL b; b = FindClose( (HANDLE)handle ); return b==FALSE ? -1 : 0; } /* below functions unsupported... */ /* I have no idea how to replace... */ int _chsize(int handle, long size) { errno = EACCES; return -1; } int _umask(int cmask) { return 0; } int _chmod(const char *path, int mode) { return 0; } /* WinCE doesn't have dup and dup2. */ /* so, we cannot use missing/dup2.c. */ int dup( int handle ) { errno = EBADF; return -1; } /* int dup2( int handle1, int handle2 ) { errno = EBADF; return -1; } */ int _isatty(int fd) { if( fd==(int)_fileno(stdin) || fd==(int)_fileno(stdout)|| fd==(int)_fileno(stderr) ) return 1; else return 0; } int _pipe(int *phandles, unsigned int psize, int textmode) { return -1; } int _access(const char *filename, int flags) { return 0; } int _open_osfhandle( long osfhandle, int flags) { /* return 0; */ return (int)osfhandle; } long _get_osfhandle( int filehandle ) { /* return 0; */ return (long)filehandle; } ================================================ FILE: wince/process.h ================================================ #ifndef PROCESS_H #define PROCESS_H 1 #define _P_WAIT 0 #define _P_NOWAIT 1 #define _P_OVERLAY 2 #define _P_DETACH 4 #define P_WAIT _P_WAIT #define P_NOWAIT _P_NOWAIT #define P_DETACH _P_DETACH #define P_OVERLAY _P_OVERLAY #ifndef _INTPTR_T_DEFINED typedef int intptr_t; #define _INTPTR_T_DEFINED #endif #ifdef __cplusplus extern "C" { #endif int _getpid(void); int _cwait(int *, int, int); void abort(void); int _execl(const char *, const char *, ...); //int _execv(const char *, const char * const *); int execv(const char *path, char *const argv[]); intptr_t _spawnle(int, const char *, const char *, ...); intptr_t _spawnvpe(int, const char *, const char * const *, const char * const *); #ifdef __cplusplus }; #endif //#define getpid _getpid #define execl _execl #define execv _execv #endif ================================================ FILE: wince/process_wce.c ================================================ /*************************************************************** process.c ***************************************************************/ #include #include "process.h" int _getpid(void) { return (int)GetCurrentProcessId(); } /* I wonder _exec and _swawn should be replaced with CreateProcess... */ int _execl(const char *cmdname, const char *arg0, va_list va_args) { return 0; } int execv(const char *path, char *const argv[]) { return 0; } void abort(void) { } int _cwait( int *termstat, int procHandle, int action ) { return 0; } intptr_t _spawnle(int mode, const char *cmdname, const char *arg0, va_list va_argn) { return 0; } intptr_t _spawnvpe(int mode, const char *cmdname, const char *const *argv, const char *const *envp) { return 0; } ================================================ FILE: wince/setup.mak ================================================ # -*- makefile -*- !if "$(srcdir)" != "" WIN32DIR = $(srcdir)/win32 !elseif "$(WIN32DIR)" == "win32" srcdir = . !elseif "$(WIN32DIR)" == "$(WIN32DIR:/win32=)/win32" srcdir = $(WIN32DIR:/win32=) !else srcdir = $(WIN32DIR)/.. !endif !ifndef prefix prefix = /usr !endif OS = mswince RT = msvcrt INCLUDE = !include APPEND = echo>>$(MAKEFILE) !ifdef MAKEFILE MAKE = $(MAKE) -f $(MAKEFILE) !else MAKEFILE = Makefile !endif ARCH = PROCESSOR_ARCHITECTURE CPU = PROCESSOR_LEVEL CPP = cl -nologo -EP all: -prologue- -generic- -epilogue- i386-$(OS): -prologue- -i386- -epilogue- i486-$(OS): -prologue- -i486- -epilogue- i586-$(OS): -prologue- -i586- -epilogue- i686-$(OS): -prologue- -i686- -epilogue- alpha-$(OS): -prologue- -alpha- -epilogue- # CE mips-hpc2k-wince: -prologue- -mips- -hpc2k- -epilogue- mips-ppc-wince: -prologue- -mips- -ppc- -epilogue- mips-hpcpro-wince: -prologue- -mips- -hpcpro- -epilogue- arm-hpc2k-wince: -prologue- -arm- -hpc2k- -epilogue- arm-ppc-wince: -prologue- -arm- -ppc- -epilogue- arm-hpcpro-wince: -prologue- -arm- -hpcpro- -epilogue- sh3-ppc-wince: -prologue- -sh3- -ppc- -epilogue- sh3-hpcpro-wince: -prologue- -sh3- -hpcpro- -epilogue- sh4-hpcpro-wince: -prologue- -sh4- -hpcpro- -epilogue- armv4-.net41-wince: -prologue- -armv4- -.net41- -epilogue- armv4t-.net41-wince: -prologue- -armv4t- -.net41- -epilogue- armv4i-sig3-wince: -prologue- -armv4i- -sig3- -epilogue- -prologue-: nul @type << > $(MAKEFILE) ### Makefile for ruby $(OS) ### srcdir = $(srcdir:\=/) prefix = $(prefix:\=/) EXTSTATIC = $(EXTSTATIC) !if defined(RDOCTARGET) RDOCTARGET = $(RDOCTARGET) !endif !if defined(EXTOUT) EXTOUT = $(EXTOUT) !endif << @$(CPP) -I$(srcdir) <<"Creating $(MAKEFILE)" >> $(MAKEFILE) #include "version.h" MAJOR = RUBY_VERSION_MAJOR MINOR = RUBY_VERSION_MINOR TEENY = RUBY_VERSION_TEENY MSC_VER = _MSC_VER << -generic-: nul !if defined($(ARCH)) || defined($(CPU)) @type << >>$(MAKEFILE) !if defined($(ARCH)) $(ARCH) = $(PROCESSOR_ARCHITECTURE) !endif !if defined($(CPU)) $(CPU) = $(PROCESSOR_LEVEL) !endif << !endif -alpha-: nul @$(APPEND) $(ARCH) = alpha -ix86-: nul @$(APPEND) $(ARCH) = x86 -i386-: -ix86- @$(APPEND) $(CPU) = 3 -i486-: -ix86- @$(APPEND) $(CPU) = 4 -i586-: -ix86- @$(APPEND) $(CPU) = 5 -i686-: -ix86- @$(APPEND) $(CPU) = 6 # CE -mips- -arm- -sh3- -sh4-:: @$(APPEND) $(ARCH) = $(@:-=) -mips- -arm-:: @$(APPEND) CC = cl$(@:-=) -sh3- -sh4-:: @$(APPEND) CC = shcl -armv4- -armv4i-:: @$(APPEND) CC = clarm @$(APPEND) ARCHFOLDER = $(@:-=) -armv4t-:: @$(APPEND) CC = clthumb @$(APPEND) ARCHFOLDER = $(@:-=) -arm-:: @$(APPEND) CECPUDEF = -DARM -D_ARM_ -mips-:: @$(APPEND) CECPUDEF = -DMIPS -D_MIPS_ -sh3-:: @$(APPEND) CECPUDEF = -DSHx -DSH3 -D_SH3_ -sh4-:: @$(APPEND) CECPUDEF = -DSHx -DSH4 -D_SH4_ @$(APPEND) QSH4 = -Qsh4 -armv4-:: @$(APPEND) CECPUDEF = -DARM -D_ARM_ -DARMV4 @$(APPEND) $(ARCH) = ARM -armv4t- -armv4i-:: @$(APPEND) CECPUDEF = -DARM -D_ARM_ -DARMV4T -DTHUMB -D_THUMB_ @$(APPEND) $(ARCH) = THUMB -hpc2k-: -hpc2000- -ppc-: "-MS Pocket PC-" -hpcpro2-: "-MS HPC Pro-" -hpcpro-: "-MS HPC Pro--" -mswin32-: @type << >>$(MAKEFILE) OS = mswin32 RT = msvcrt << -mswince-: @type << >>$(MAKEFILE) !ifdef CE_TOOLS_DIR CE_TOOLS_DIR = $(CE_TOOLS_DIR) !endif !ifdef EMBEDDED_TOOLS_DIR EMBEDDED_TOOLS_DIR = $(EMBEDDED_TOOLS_DIR) !endif OS = mswince RT = $$(OS) << -mswince4-: @type << >>$(MAKEFILE) !ifdef CE_TOOLS4_DIR CE_TOOLS4_DIR = $(CE_TOOLS4_DIR) !endif !ifdef EMBEDDED_TOOLS4_DIR EMBEDDED_TOOLS4_DIR = $(EMBEDDED_TOOLS4_DIR) !endif OS = mswince RT = $$(OS) << -mswince-3.00 -mswince-2.11: -mswince- @type << >>$(MAKEFILE) SUBSYSVERSION = $(@:-mswince-=) PATH = $$(EMBEDDED_TOOLS_DIR)/common/evc/bin;$$(EMBEDDED_TOOLS_DIR)/EVC/WCE$$(SUBSYSVERSION:.=)/bin << -mswince-4.10: -mswince4- @type << >>$(MAKEFILE) SUBSYSVERSION = $(@:-mswince-=) EXTLIBS = ws2.lib PATH = $$(EMBEDDED_TOOLS4_DIR)/common/evc/bin;$$(EMBEDDED_TOOLS4_DIR)/EVC/WCE$$(SUBSYSVERSION:.=)/bin << -hpc2000- "-MS Pocket PC-": -mswince-3.00 "-MS HPC Pro-" "-MS HPC Pro--": -mswince-2.11 -.net41- -sig3-: -mswince-4.10 -hpc2000-: @type << >>$(MAKEFILE) SUBSYSTEM = windowsce,3.0 INCLUDE = $$(CE_TOOLS_DIR)/wce$$(SUBSYSVERSION:.=)/$(@:-=)/include LIB = $$(CE_TOOLS_DIR)/wce$$(SUBSYSVERSION:.=)/$(@:-=)/lib/$$(PROCESSOR_ARCHITECTURE) << "-MS Pocket PC-": @type << >>$(MAKEFILE) SUBSYSTEM = windowsce,3.0 INCLUDE = $$(CE_TOOLS_DIR)/wce$$(SUBSYSVERSION:.=)/MS Pocket PC/include LIB = $$(CE_TOOLS_DIR)/wce$$(SUBSYSVERSION:.=)/MS Pocket PC/lib/$$(PROCESSOR_ARCHITECTURE) << "-MS HPC Pro--": @type << >>$(MAKEFILE) SUBSYSTEM = windowsce,2.11 INCLUDE = $$(CE_TOOLS_DIR)/wce$$(SUBSYSVERSION:.=)/MS HPC Pro/include LIB = $$(CE_TOOLS_DIR)/wce$$(SUBSYSVERSION:.=)/MS HPC Pro/lib/$$(PROCESSOR_ARCHITECTURE) << -.net41-: @type << >>$(MAKEFILE) SUBSYSTEM = windowsce,4.1 INCLUDE = $$(CE_TOOLS4_DIR)/wce400/STANDARDSDK/include/$$(ARCHFOLDER) LIB = $$(CE_TOOLS4_DIR)/wce400/STANDARDSDK/lib/$$(ARCHFOLDER) << -sig3-: @type << >>$(MAKEFILE) SUBSYSTEM = windowsce,4.1 INCLUDE = $$(CE_TOOLS4_DIR)/wce410/sigmarionIII SDK/include/$$(ARCHFOLDER) LIB = $$(CE_TOOLS4_DIR)/wce410/sigmarionIII SDK/lib/$$(ARCHFOLDER) << -epilogue-: nul @type << >>$(MAKEFILE) !ifdef RUBY_INSTALL_NAME RUBY_INSTALL_NAME = $(RUBY_INSTALL_NAME) !else ifdef RUBY_SUFFIX RUBY_INSTALL_NAME = ruby$(RUBY_SUFFIX) !endif !ifdef RUBY_SO_NAME RUBY_SO_NAME = $(RUBY_SO_NAME) !else # RUBY_SO_NAME = $$(RT)-$$(RUBY_INSTALL_NAME)$$(MAJOR)$$(MINOR) !endif # CFLAGS = -nologo $$(DEBUGFLAGS) $$(OPTFLAGS) $$(PROCESSOR_FLAG) CPPFLAGS = -I. -I$$(srcdir) -I$$(srcdir)/missing -I$$(srcdir)/wince \ $$(CECPUDEF) -DUNDER_CE -D_WIN32_WCE=$$(SUBSYSVERSION:.=) \ -DFILENAME_MAX=MAX_PATH -DTLS_OUT_OF_INDEXES=0xFFFFFFFF \ -DBUFSIZ=512 -D_UNICODE -DUNICODE $$(QSH4) # STACK = 0x10000,0x1000 # LDFLAGS = $$(CFLAGS) -Fm # XLDFLAGS = # RFLAGS = -r # EXTLIBS = $(INCLUDE) $$(srcdir)/wince/Makefile.sub << @$(srcdir:/=\)\win32\rm.bat config.h config.status @echo type `$(MAKE)' to make ruby for $(OS). ================================================ FILE: wince/signal.h ================================================ #ifndef SIGNAL_H #define SIGNAL_H 1 #include #define SIGHUP 1 #define SIGINT 2 #define SIGQUIT 3 #define SIGILL 4 #define SIGPIPE 5 #define SIGFPE 8 #define SIGUSR1 10 #define SIGSEGV 11 #define SIGUSR2 12 #define SIGTERM 15 #define SIGCHLD 17 #define SIGTSTP 20 #define SIGBREAK 21 #define SIGABRT 22 #define NSIG 22 #define SA_NOCLDSTOP 1 #define SA_SHIRQ 0x04000000 #define SA_STACK 0x08000000 #define SA_RESTART 0x10000000 #define SA_INTERRUPT 0x20000000 #define SA_NOMASK 0x40000000 #define SA_ONESHOT 0x80000000 /* signal action codes */ #define SIG_DFL (void (*)(int))0 /* default signal action */ #define SIG_IGN (void (*)(int))1 /* ignore signal */ #define SIG_SGE (void (*)(int))3 /* signal gets error */ #define SIG_ACK (void (*)(int))4 /* acknowledge */ #define SIG_ERR (void (*)(int))-1 /* signal error value */ #define SIG_BLOCK 0 /* for blocking signals */ #define SIG_UNBLOCK 1 /* for unblocking signals */ #define SIG_SETMASK 2 /* for setting the signal mask */ #ifdef __cplusplus extern "C" { #endif typedef void (* SIGHANDLER)(int); typedef void (* sighandler_t)(int); typedef int sig_atomic_t; typedef unsigned int sigset_t; struct sigaction{ sighandler_t sa_handler; sigset_t sa_mask; unsigned long sa_flags; void (*sa_restorer)(void); }; int raise(int sig); //#ifndef _WIN32_WCE_EMULATION void (* signal(int sig, void (__cdecl *func)(int)))(int); //#else // void (* signal(int sig, void (*func))); //#endif #ifdef __cplusplus }; #endif #endif ================================================ FILE: wince/signal_wce.c ================================================ /*************************************************************** signal.c ***************************************************************/ #include #include "signal.h" /* lazy replacement... (^^; */ int raise(int sig) { return 0; } //#ifdef _WIN32_WCE //#ifdef _WIN32_WCE_EMULATION //void (* signal(int sig, void (*func))) //{ // return sig; //} //#else void (* signal(int sig, void (__cdecl *func)(int)))(int) { return sig; } //#endif //#endif ================================================ FILE: wince/stddef.h ================================================ #ifndef _STDDEF_H_ #define _STDDEF_H_ #endif ================================================ FILE: wince/stdio.c ================================================ /*************************************************************** stdio.c ***************************************************************/ #include #include "wince.h" /* for wce_mbtowc */ FILE *freopen(const char *filename, const char *mode, FILE *file) { wchar_t *wfilename, *wmode; FILE *fp; wfilename = wce_mbtowc(filename); wmode = wce_mbtowc(mode); fp = _wfreopen(wfilename, wmode, file); free(wfilename); free(wmode); return fp; } FILE *fdopen( int handle, const char *mode ) { wchar_t *wmode; FILE* fp; wmode = wce_mbtowc(mode); fp = _wfdopen( (void*)handle, wmode ); free(wmode); return fp; } ================================================ FILE: wince/stdlib.c ================================================ /*************************************************************** stdlib.c ***************************************************************/ #include char **environ; extern char * rb_w32_getenv(const char *); /* getenv should replace with rb_w32_getenv. */ char *getenv(const char *env) { return rb_w32_getenv(env); } char *_fullpath(char *absPath, const char *relPath, size_t maxLength) { strcpy( absPath, relPath ); return absPath; } int mblen(const char *mbstr, size_t count) { const char *p = mbstr; size_t i; int n=0; for( i=0; i #include "wince.h" /* for wce_mbtowc */ /* _strdup already exists in stdlib.h? */ char *strdup(const char * str) { char *p; p = malloc( strlen(str)+1 ); strcpy( p, str ); return p; } char* strerror(int errno) { static char buf[32]="wince::strerror called."; return buf; } /* strnicmp already exists in stdlib.h? */ int strnicmp( const char *s1, const char *s2, size_t count ) { wchar_t *w1, *w2; int n; w1 = wce_mbtowc(s1); w2 = wce_mbtowc(s2); n = wcsnicmp(w1, w2, count); free(w1); free(w2); return n; } #if _WIN32_WCE < 300 #include "..\missing\strtoul.c" char *strrchr( const char *p, int c ) { char *pp; for( pp=(char*)p+strlen(p); pp!=p; pp-- ) { if( *pp==c ) break; } return pp==p ? NULL : pp; } int stricmp( const char *s1, const char *s2 ) { wchar_t *w1, *w2; int n; w1 = wce_mbtowc(s1); w2 = wce_mbtowc(s2); n = wcsicmp(w1, w2); free(w1); free(w2); return n; } char *strpbrk(const char *str, const char *cs) { wchar_t *wstr, *wcs, *w; char *s = NULL; wstr = wce_mbtowc(str); wcs = wce_mbtowc(cs); w = wcspbrk(wstr, wcs); if( w!=NULL ) s = str + (wcs-wstr)/sizeof(wchar_t); free(wstr); free(wcs); return s; } #endif ================================================ FILE: wince/sys/stat.c ================================================ /*************************************************************** stat.c author : uema2 date : Nov 30, 2002 You can freely use, copy, modify, and redistribute the whole contents. ***************************************************************/ #include #include #include #include "..\wince.h" /* for wce_mbtowc */ int _stat(const char *filename, struct _stat *st) { DWORD dwAttribute; HANDLE h; DWORD dwSizeLow=0, dwSizeHigh=0, dwError=0; WIN32_FIND_DATAW fd; wchar_t *wfilename; // wfilename = wce_mbtowc(filename); wfilename = wce_replaceRelativeDir(filename); dwAttribute = GetFileAttributesW(wfilename); if(dwAttribute==0xFFFFFFFF) { free(wfilename); return -1; } st->st_mode = 0; if((dwAttribute & FILE_ATTRIBUTE_DIRECTORY) != 0) st->st_mode += S_IFDIR; else st->st_mode += S_IFREG; /* initialize */ st->st_atime = 0; st->st_mtime = 0; st->st_ctime = 0; st->st_size = 0; st->st_dev = 0; h = FindFirstFileW(wfilename, &fd); if(h == INVALID_HANDLE_VALUE) { if(wfilename[wcslen(wfilename)-1] == L'\\') { wfilename[wcslen(wfilename)-1] = L'\0'; h = FindFirstFileW(wfilename, &fd); if(h == INVALID_HANDLE_VALUE) { free(wfilename); return 0; } } else { free(wfilename); return 0; } } /* FILETIME -> time_t */ st->st_atime = wce_FILETIME2time_t(&fd.ftLastAccessTime); st->st_mtime = wce_FILETIME2time_t(&fd.ftLastWriteTime); st->st_ctime = wce_FILETIME2time_t(&fd.ftCreationTime); st->st_size = fd.nFileSizeLow; FindClose( h ); free(wfilename); return 0; } int fstat(int file, struct stat *sbuf) { /* GetFileSize & GetFileTime */ DWORD dwSize; FILETIME ctime, atime, mtime; dwSize = GetFileSize( (HANDLE)file, NULL ); if( dwSize == 0xFFFFFFFF ) return -1; sbuf->st_size = dwSize; sbuf->st_dev = 0; sbuf->st_rdev = 0; sbuf->st_mode = _S_IFREG; sbuf->st_nlink= 1; GetFileTime( (HANDLE)file, &ctime, &atime, &mtime ); sbuf->st_ctime = wce_FILETIME2time_t(&ctime); sbuf->st_atime = wce_FILETIME2time_t(&atime); sbuf->st_mtime = wce_FILETIME2time_t(&mtime); return 0; } ================================================ FILE: wince/sys/stat.h ================================================ #ifndef SYS_STAT_H #define SYS_STAT_H 1 #include #define _S_IFMT 0170000 /* file type mask */ #define _S_IFDIR 0040000 /* directory */ #define _S_IFCHR 0020000 /* character special */ #define _S_IFIFO 0010000 /* pipe */ #define _S_IFREG 0100000 /* regular */ #define _S_IREAD 0000400 /* read permission, owner */ #define _S_IWRITE 0000200 /* write permission, owner */ #define _S_IEXEC 0000100 /* execute/search permission, owner */ #define S_IFMT _S_IFMT #define S_IFREG _S_IFREG #define S_IFCHR _S_IFCHR #define S_IFDIR _S_IFDIR #define S_IREAD _S_IREAD #define S_IWRITE _S_IWRITE #define S_IEXEC _S_IEXEC #ifndef S_ISDIR #define S_ISDIR(X) (((X) & S_IFMT) == S_IFDIR) #endif #ifndef S_ISREG #define S_ISREG(X) (((X) & S_IFMT) == S_IFREG) #endif #ifdef __cplusplus extern "C" { #endif // in sys/types.h //typedef unsigned int _dev_t; //typedef long _off_t; //typedef unsigned short _ino_t; #ifndef _STAT_DEFINED struct stat { dev_t st_dev; ino_t st_ino; unsigned short st_mode; short st_nlink; short st_uid; short st_gid; dev_t st_rdev; off_t st_size; time_t st_atime; time_t st_mtime; time_t st_ctime; }; #define _STAT_DEFINED #endif /* _STAT_DEFINED */ #define _stat stat int _stat(const char *filename, struct _stat *stat); int fstat(int file, struct stat *sbuf); #ifdef __cplusplus }; #endif #endif ================================================ FILE: wince/sys/timeb.c ================================================ /*************************************************************** timeb.c ***************************************************************/ #include #include #include int ftime(struct timeb *tp) { SYSTEMTIME s; FILETIME f; GetLocalTime(&s); SystemTimeToFileTime( &s, &f ); tp->dstflag = 0; tp->timezone = _timezone/60; tp->time = wce_FILETIME2time_t(&f); tp->millitm = s.wMilliseconds; return 0; } ================================================ FILE: wince/sys/timeb.h ================================================ #ifndef SYS_TIMEB_H #define SYS_TIMEB_H 1 #include struct _timeb { time_t time; unsigned short millitm; short timezone; short dstflag; }; #define timeb _timeb #ifdef __cplusplus extern "C" { #endif int ftime(struct timeb *tp); #ifdef __cplusplus }; #endif #endif ================================================ FILE: wince/sys/types.h ================================================ #ifndef SYS_TYPES_H #define SYS_TYPES_H 1 #define BIG_ENDIAN 1234 #define LITTLE_ENDIAN 4321 #ifdef MIPS #define BYTE_ORDER LITTLE_ENDIAN #endif //#if UNDER_CE > 201 // typedef unsigned long time_t; // #define _TIME_T_DEFINED_ //#endif typedef unsigned long dev_t; typedef unsigned long ino_t; #ifndef _MODE_T_DEFINED_ typedef unsigned long mode_t; #define _MODE_T_DEFINED_ #endif typedef long clock_t; #ifndef _PTRDIFF_T_DEFINED typedef long ptrdiff_t; #define _PTRDIFF_T_DEFINED #endif typedef long off_t; //typedef unsigned char u_char; //typedef unsigned short u_short; #ifndef _CADDR_T_DEFINED_ typedef unsigned char * caddr_t; #define _CADDR_T_DEFINED_ #endif #ifndef _SIZE_T_DEFINED_ typedef unsigned int size_t; #define _SIZE_T_DEFINED_ #endif //typedef unsigned char u_int8_t; //typedef short int16_t; //typedef unsigned short u_int16_t; //typedef int int32_t; //typedef unsigned int u_int32_t; //typedef unsigned long u_long; //typedef unsigned int u_int; //#ifndef _TIME_T_DEFINED_ //typedef unsigned long time_t; //#define _TIME_T_DEFINED_ //#endif #endif ================================================ FILE: wince/sys/utime.c ================================================ /*************************************************************** utime.c ***************************************************************/ #include #include #include "..\wince.h" /* for wce_mbtowc */ #ifdef _WIN32_WCE #if _WIN32_WCE < 300 #define Int32x32To64(a, b) ((LONGLONG)((LONG)(a)) * (LONGLONG)((LONG)(b))) /* #define Int32x32To64(a, b) ((__int64)((LONG)(a)) * (__int64)((LONG)(b))) */ #endif #endif int utime(const char *f, struct utimbuf *t) { HANDLE h; FILETIME atime={0}, mtime={0}; __int64 time64; BOOL rc; wchar_t *w; w = wce_mbtowc(f); h = CreateFileW(w, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); free(w); if( h==INVALID_HANDLE_VALUE ) return -1; time64 = Int32x32To64(t->actime, 10000000) + 116444736000000000; atime.dwLowDateTime = (DWORD)time64; atime.dwHighDateTime = (DWORD)(time64 >> 32); time64 = Int32x32To64(t->modtime, 10000000) + 116444736000000000; mtime.dwLowDateTime = (DWORD)time64; mtime.dwHighDateTime = (DWORD)(time64 >> 32); rc = SetFileTime(h, NULL, &atime, &mtime); return rc==TRUE ? 0 : -1; } ================================================ FILE: wince/sys/utime.h ================================================ #ifndef SYS_UTIME_H #define SYS_UTIME_H 1 #include struct utimbuf { time_t actime; time_t modtime; }; #define _utimbuf utimbuf #ifdef __cplusplus extern "C" { #endif int utime(const char *f, struct utimbuf *t); #ifdef __cplusplus }; #endif //#define utime _utime #endif ================================================ FILE: wince/time.h ================================================ #ifndef _TIME_WINCE_H #define _TIME_WINCE_H 1 #include #include #ifdef __cplusplus extern "C" { #endif extern int daylight; extern int _timezone, timezone; extern char *tzname[2]; #if 0 #define _DAY_SEC (24L * 60L * 60L) /* secs in a day */ #define _YEAR_SEC (365L * _DAY_SEC) /* secs in a year */ #define _FOUR_YEAR_SEC (1461L * _DAY_SEC) /* secs in a 4 year interval */ #define _DEC_SEC 315532800L /* secs in 1970-1979 */ #define _BASE_YEAR 70L /* 1970 is the base year */ #define _BASE_DOW 4 /* 01-01-70 was a Thursday */ #define _LEAP_YEAR_ADJUST 17L /* Leap years 1900 - 1970 */ #define _MAX_YEAR 138L /* 2038 is the max year */ #endif #ifndef _TM_DEFINED struct tm { int tm_sec; /* seconds after the minute - [0,59] */ int tm_min; /* minutes after the hour - [0,59] */ int tm_hour; /* hours since midnight - [0,23] */ int tm_mday; /* day of the month - [1,31] */ int tm_mon; /* months since January - [0,11] */ int tm_year; /* years since 1900 */ int tm_wday; /* days since Sunday - [0,6] */ int tm_yday; /* days since January 1 - [0,365] */ int tm_isdst; /* daylight savings time flag */ }; #define _TM_DEFINED #endif typedef struct { int yr; // year of interest int yd; // day of year long ms; // milli-seconds in the day } transitionTime; time_t mktime(struct tm* pt); time_t time( time_t *timer ); struct tm *localtime(const time_t *ptime); struct tm *gmtime(const time_t *tod); char* ctime( const time_t *t ); char* asctime(const struct tm *tptr); void tzset(); int clock(void); time_t wce_FILETIME2time_t(const FILETIME* pf); #ifdef __cplusplus }; #endif #endif ================================================ FILE: wince/time_wce.c ================================================ /*************************************************************** time.c author : uema2 date : Nov 30, 2002 You can freely use, copy, modify, and redistribute the whole contents. ***************************************************************/ /*#define __SCRATCH_TIMEC_DEBUG__ */ #include #include #include /* globals */ const __int64 _onesec_in100ns = (__int64)10000000; int timezone, _timezone, altzone; int daylight; char *tzname[2]; /* __int64 <--> FILETIME */ static __int64 wce_FILETIME2int64(FILETIME f) { __int64 t; t = f.dwHighDateTime; t <<= 32; t |= f.dwLowDateTime; return t; } static FILETIME wce_int642FILETIME(__int64 t) { FILETIME f; f.dwHighDateTime = (DWORD)((t >> 32) & 0x00000000FFFFFFFF); f.dwLowDateTime = (DWORD)( t & 0x00000000FFFFFFFF); return f; } /* FILETIME utility */ static FILETIME wce_getFILETIMEFromYear(WORD year) { SYSTEMTIME s={0}; FILETIME f; s.wYear = year; s.wMonth = 1; s.wDayOfWeek = 1; s.wDay = 1; SystemTimeToFileTime( &s, &f ); return f; } static time_t wce_getYdayFromSYSTEMTIME(const SYSTEMTIME* s) { __int64 t; FILETIME f1, f2; f1 = wce_getFILETIMEFromYear( s->wYear ); SystemTimeToFileTime( s, &f2 ); t = wce_FILETIME2int64(f2)-wce_FILETIME2int64(f1); return (time_t)((t/_onesec_in100ns)/(60*60*24)); } /* tm <--> SYSTEMTIME */ static SYSTEMTIME wce_tm2SYSTEMTIME(struct tm *t) { SYSTEMTIME s; s.wYear = t->tm_year + 1900; s.wMonth = t->tm_mon + 1; s.wDayOfWeek = t->tm_wday; s.wDay = t->tm_mday; s.wHour = t->tm_hour; s.wMinute = t->tm_min; s.wSecond = t->tm_sec; s.wMilliseconds = 0; return s; } static struct tm wce_SYSTEMTIME2tm(SYSTEMTIME *s) { struct tm t; t.tm_year = s->wYear - 1900; t.tm_mon = s->wMonth- 1; t.tm_wday = s->wDayOfWeek; t.tm_mday = s->wDay; t.tm_yday = wce_getYdayFromSYSTEMTIME(s); t.tm_hour = s->wHour; t.tm_min = s->wMinute; t.tm_sec = s->wSecond; t.tm_isdst = 0; return t; } /* FILETIME <--> time_t */ time_t wce_FILETIME2time_t(const FILETIME* f) { FILETIME f1601, f1970; __int64 t, offset; f1601 = wce_getFILETIMEFromYear(1601); f1970 = wce_getFILETIMEFromYear(1970); offset = wce_FILETIME2int64(f1970) - wce_FILETIME2int64(f1601); t = wce_FILETIME2int64(*f); t -= offset; return (time_t)(t / _onesec_in100ns); } FILETIME wce_time_t2FILETIME(const time_t t) { FILETIME f, f1970; __int64 time; f1970 = wce_getFILETIMEFromYear(1970); time = t; time *= _onesec_in100ns; time += wce_FILETIME2int64(f1970); f = wce_int642FILETIME(time); return f; } /* time.h difinition */ time_t time( time_t *timer ) { SYSTEMTIME s; FILETIME f; if( timer==NULL ) return 0; GetSystemTime( &s ); SystemTimeToFileTime( &s, &f ); *timer = wce_FILETIME2time_t(&f); return *timer; } struct tm *localtime( const time_t *timer ) { SYSTEMTIME ss, ls, s; FILETIME sf, lf, f; __int64 t, diff; static struct tm tms; GetSystemTime(&ss); GetLocalTime(&ls); SystemTimeToFileTime( &ss, &sf ); SystemTimeToFileTime( &ls, &lf ); diff = wce_FILETIME2int64(sf) - wce_FILETIME2int64(lf); f = wce_time_t2FILETIME(*timer); t = wce_FILETIME2int64(f) - diff; f = wce_int642FILETIME(t); FileTimeToSystemTime( &f, &s ); tms = wce_SYSTEMTIME2tm(&s); return &tms; } time_t mktime(struct tm* pt) { SYSTEMTIME ss, ls, s; FILETIME sf, lf, f; __int64 diff; GetSystemTime(&ss); GetLocalTime(&ls); SystemTimeToFileTime( &ss, &sf ); SystemTimeToFileTime( &ls, &lf ); diff = (wce_FILETIME2int64(lf)-wce_FILETIME2int64(sf))/_onesec_in100ns; s = wce_tm2SYSTEMTIME(pt); SystemTimeToFileTime( &s, &f ); return wce_FILETIME2time_t(&f) - (time_t)diff; } struct tm *gmtime(const time_t *t) { FILETIME f; SYSTEMTIME s; static struct tm tms; f = wce_time_t2FILETIME(*t); FileTimeToSystemTime(&f, &s); tms = wce_SYSTEMTIME2tm(&s); return &tms; } char* ctime( const time_t *t ) { // Wed Jan 02 02:03:55 1980\n\0 static char buf[30]={0}; char week[] = "Sun Mon Tue Wed Thr Fri Sat "; char month[]= "Jan Feb Mar Apl May Jun Jul Aug Sep Oct Nov Dec "; struct tm tms; tms = *localtime(t); strncpy( buf, week+tms.tm_wday*4, 4 ); strncpy( buf+4, month+tms.tm_mon*4, 4 ); sprintf( buf+8, "%02d ", tms.tm_mday ); sprintf( buf+11, "%02d:%02d:%02d %d\n", tms.tm_hour, tms.tm_min, tms.tm_sec, tms.tm_year+1900 ); return buf; } char *asctime(const struct tm *pt) { static char buf[30]={0}; char week[] = "Sun Mon Tue Wed Thr Fri Sat "; char month[]= "Jan Feb Mar Apl May Jun Jul Aug Sep Oct Nov Dec "; strncpy( buf, week+pt->tm_wday*4, 4 ); strncpy( buf+4, month+pt->tm_mon*4, 4 ); sprintf( buf+8, "%02d ", pt->tm_mday ); sprintf( buf+11, "%02d:%02d:%02d %d\n", pt->tm_hour, pt->tm_min, pt->tm_sec, pt->tm_year+1900 ); return buf; } void tzset() { daylight = 1; _timezone = 28800; timezone = 28800; } int clock(void) { return 1; } //--------------------------------------------------------------- #ifdef __SCRATCH_TIMEC_DEBUG__ int main() { time_t t1, t2; struct tm tm1, tm2; time( &t1 ); tm1 = *localtime(&t1); t1 = mktime(&tm1); tm1 = *gmtime(&t1); _time( &t2 ); tm2 = *_localtime(&t2); t2 = _mktime(&tm2); tm2 = *_gmtime(&t2); // time, mktime if( t1==t2 ) OutputDebugString( "ok\n" ); else { static char buf[128]; wsprintf( buf, "ng : %d, %d\n", t1, t2 ); OutputDebugString( buf ); } // localtime, gmtime if( 0==memcmp( &tm1, &tm2, sizeof(struct tm) ) ) OutputDebugString( "ok\n" ); else OutputDebugString( "ng\n" ); // ctime OutputDebugString( ctime(&t1) ); OutputDebugString( _ctime(&t2) ); // asctime OutputDebugString( asctime(&tm1) ); OutputDebugString( _asctime(&tm2) ); return 0; } #endif ================================================ FILE: wince/varargs.h ================================================ #ifndef VARARGS_H #define VARARGS_H 1 #ifdef __cplusplus extern "C" { #endif #ifndef _VA_LIST_DEFINED typedef char *va_list; #define _VA_LIST_DEFINED #endif //#ifdef MIPS #define va_alist __va_alist, __va_alist2, __va_alist3, __va_alist4 #define va_dcl int __va_alist, __va_alist2, __va_alist3, __va_alist4; #define va_start(list) list = (char *) &__va_alist #define va_end(list) #define va_arg(list, mode) ((mode *)(list =\ (char *) ((((int)list + (__builtin_alignof(mode)<=4?3:7)) &\ (__builtin_alignof(mode)<=4?-4:-8))+sizeof(mode))))[-1] #else #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) #define va_dcl va_list va_alist; #define va_start(ap) ap = (va_list)&va_alist #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) #define va_end(ap) ap = (va_list)0 //#endif #ifdef __cplusplus } #endif #endif ================================================ FILE: wince/wince.c ================================================ /*************************************************************** wince.c author : uema2 date : Nov 30, 2002 You can freely use, copy, modify, and redistribute the whole contents. ***************************************************************/ #include #include #include "wince.h" /* global for GetCommandLineA */ char *_commandLine; extern char _currentdir[]; /* make up Win32API except wce_* functions. */ DWORD GetModuleFileNameA( HMODULE hModule, LPSTR lpFileName, DWORD size ) { LPWSTR lpFileNameW; LPSTR mb; size_t ret; if( size==0 ) return 0; lpFileNameW = (LPWSTR)malloc( size*sizeof(wchar_t) ); ret = GetModuleFileNameW( hModule, lpFileNameW, size ); mb = wce_wctomb(lpFileNameW); strcpy(lpFileName, mb); free(mb); free(lpFileNameW); return ret; } #if _WIN32_WCE < 300 FARPROC GetProcAddressA(HMODULE hModule, LPCSTR lpProcName) { FARPROC p; LPWSTR lpwProcName; lpwProcName = wce_mbtowc( lpProcName ); p = GetProcAddressW( hModule, lpwProcName ); free( lpwProcName ); return p; } #endif char * GetCommandLineA(void) { return _commandLine; } /* this is not Win32API. GetCommandLineA helper. */ void wce_SetCommandLine(LPCWSTR wcmd) { char* acmd; acmd = wce_wctomb( wcmd ); _commandLine = (char*)malloc( strlen(acmd)+5 ); sprintf( _commandLine, "ruby %s", acmd ); free(acmd); } /* this is not Win32API. GetCommandLineA helper. */ void wce_FreeCommandLine(void) { free(_commandLine); _commandLine = NULL; } /* I have no idea how to replace this. */ BOOL GetProcessTimes(HANDLE hprocess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime) { return 0; } /* -------------- file attributes functions. ------------------- */ DWORD GetFileAttributesA(LPCSTR lpFileName) { LPWSTR lpwFileName; DWORD dw; lpwFileName = wce_mbtowc(lpFileName); dw = GetFileAttributesW(lpwFileName); free(lpwFileName); return dw; } BOOL SetFileAttributesA( LPCSTR lpFileName, DWORD attributes) { LPWSTR lpwFileName; BOOL b; lpwFileName = wce_mbtowc(lpFileName); b = SetFileAttributesW(lpwFileName, attributes); free(lpwFileName); return b; } /* --------------- move and remove functions. ------------------- */ BOOL MoveFileA(LPCSTR fn1, LPCSTR fn2) { LPWSTR wfn1, wfn2; BOOL b; wfn1 = wce_mbtowc(fn1); wfn2 = wce_mbtowc(fn2); b = MoveFileW(wfn1, wfn2); free(wfn1); free(wfn2); return 0; } BOOL MoveFileEx(LPCSTR oldname, LPCSTR newname, DWORD dwFlags) { LPWSTR woldname, wnewname; BOOL b; woldname = wce_mbtowc(oldname); wnewname = wce_mbtowc(newname); if( (dwFlags&MOVEFILE_REPLACE_EXISTING)!=0 ) DeleteFileW( wnewname ); b = MoveFileW( woldname, wnewname ); free(woldname); free(wnewname); return b; } BOOL DeleteFileA(LPCSTR path) { LPWSTR wpath; BOOL b; wpath = wce_mbtowc(path); b = DeleteFileW(wpath); free(wpath); return 0; } /* --------------- EnvironmentVariable functions. ----------------- */ DWORD GetEnvironmentVariable( LPCSTR name, LPSTR value, DWORD size) { /* use registry instead of "environment valuable". */ HKEY hk; LONG lret; LPBYTE lpData; DWORD dwType=REG_SZ, cbData; TCHAR buf[MAX_PATH]={0}; LPWSTR wname; LPSTR avalue; lret = RegOpenKeyEx( HKEY_LOCAL_MACHINE, _T("Software\\ruby_mswince"), 0, KEY_QUERY_VALUE, &hk ); if ( lret != ERROR_SUCCESS ) { strcpy( value, "" ); return 0; } lpData = (LPBYTE)buf; cbData = MAX_PATH*sizeof(*buf); wname = wce_mbtowc( name ); lret = RegQueryValueEx( hk, wname, NULL, &dwType, lpData, &cbData ); RegCloseKey( hk ); if ( lret != ERROR_SUCCESS ) { strcpy( value, "" ); free( wname ); return 0; } avalue = wce_wctomb( (LPCTSTR)lpData ); strcpy( value, avalue ); free( avalue ); free( wname ); return strlen(value); } BOOL SetEnvironmentVariable(LPCSTR name, LPCSTR value) { /* use registry instead of "environment valuable". */ HKEY hk; LONG lret; LPBYTE lpData; DWORD ret, dwType=REG_SZ, cbData; LPWSTR wname, wvalue; lret = RegCreateKeyEx( HKEY_LOCAL_MACHINE, _T("Software\\ruby_mswince"), 0, _T(""), 0, 0, NULL, &hk, &ret ); if( lret != ERROR_SUCCESS ) return FALSE; wname = wce_mbtowc(name); wvalue = wce_mbtowc(value); lpData = (LPBYTE)wvalue; cbData = (wcslen(wvalue) + 1) * sizeof(*wvalue); lret = RegSetValueEx( hk, wname, 0, dwType, lpData, cbData ); RegCloseKey( hk ); free(wname); free(wvalue); return lret == ERROR_SUCCESS; } LPVOID GetEnvironmentStrings(VOID) { return NULL; } BOOL FreeEnvironmentStrings(LPSTR lpszEnvironmentBlock) { return FALSE; } /* DuplicateHandle, LockFile, etc... */ /* I have no idea... */ BOOL GenerateConsoleCtrlEvent(DWORD dwCtrlEvent, DWORD dwProcessGroupID) { return 0; } BOOL DuplicateHandle( HANDLE source_process, HANDLE source, HANDLE dest_process, HANDLE *dest, DWORD access, BOOL inherit, DWORD options) { return 0; } BOOL LockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh) { return FALSE; } BOOL LockFileEx(HANDLE hFile, DWORD dwFlags, DWORD dwReserved, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped) { return FALSE; } BOOL UnlockFile( HFILE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh) { return FALSE; } BOOL UnlockFileEx(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped) { return FALSE; } /* --------------------- etc, etc, etc... ----------------------- */ BOOL GetVersionExA(OSVERSIONINFOA *v) { OSVERSIONINFOW wv; BOOL b; LPSTR mb; b = GetVersionExW(&wv); mb = wce_wctomb(wv.szCSDVersion); strcpy( v->szCSDVersion, mb ); free(mb); return b; } DWORD WaitForMultipleObjectsEx(DWORD count, const HANDLE *handles, BOOL wait_all, DWORD timeout, BOOL alertable) { return WaitForMultipleObjects( count, handles, wait_all, timeout ); } BOOL CreateProcessA(LPCSTR appname, LPCSTR commandline, LPSECURITY_ATTRIBUTES att, LPSECURITY_ATTRIBUTES threadatt, BOOL bOpt, DWORD dwFlag, LPVOID lpEnv, LPSTR dir, LPSTARTUPINFO lpsi, LPPROCESS_INFORMATION lppi) { LPWSTR wappname, wcommandline, wdir; BOOL b; wappname = wce_mbtowc(appname); wcommandline = wce_mbtowc(commandline); wdir = wce_mbtowc(dir); b = CreateProcessW(wappname, wcommandline, att, threadatt, bOpt, dwFlag, lpEnv, wdir, lpsi, lppi); free(wappname); free(wcommandline); free(wdir); return b; } HANDLE CreateEventA(SECURITY_ATTRIBUTES *sa, BOOL manual_reset, BOOL initial_state, LPCSTR name) { HANDLE h; LPWSTR wname; wname = wce_mbtowc(name); h = CreateEventW(sa, manual_reset, initial_state, wname); free(wname); return h; } DWORD FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer, DWORD nSize, va_list* args) { DWORD dw; LPWSTR lpWBuffer; lpWBuffer = wce_mbtowc(lpBuffer); dw = FormatMessageW( dwFlags, lpSource, dwMessageId, dwLanguageId, lpWBuffer, nSize, (va_list*)args ); free(lpWBuffer); return dw; } /*---------------- FindFirstFile, FindNextFile ------------------ */ HANDLE FindFirstFileA(LPCSTR path, WIN32_FIND_DATAA *data) { LPWSTR wpath; LPSTR mb; HANDLE h; WIN32_FIND_DATAW wdata; wpath = wce_mbtowc(path); h = FindFirstFileW( wpath, &wdata ); free(wpath); mb = wce_wctomb( wdata.cFileName ); strcpy( data->cFileName, mb ); free(mb); return h; } BOOL FindNextFileA(HANDLE handle, WIN32_FIND_DATAA *data) { BOOL b; WIN32_FIND_DATAW wdata; LPSTR mb1; b = FindNextFileW(handle, &wdata); mb1 = wce_wctomb( wdata.cFileName ); strcpy( data->cFileName, mb1 ); free(mb1); return b; } /* CreateFile doesn't support SECURITY_ATTRIBUTES in WinCE. */ /* it must be NULL. */ HANDLE CreateFileA(LPCSTR filename, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa, DWORD creation, DWORD attributes, HANDLE template) { LPWSTR wfilename; HANDLE h; wfilename = wce_mbtowc(filename); h = CreateFileW(wfilename, access, sharing, NULL, creation, 0, NULL); free(wfilename); return 0; } /* ---------------- CharNext, CharPrev. ---------------------*/ LPSTR CharNextA(LPCSTR a) { char *p=(char *)a; if( TRUE==IsDBCSLeadByteEx(CP_ACP, (BYTE)*a) ) p+=2; else p++; return p; } LPSTR CharPrevA(LPCSTR start, LPCSTR ptr) { if( start==ptr ) return (LPSTR)start; else if( start+1==ptr ) return (LPSTR)start; else if( TRUE==IsDBCSLeadByteEx(CP_ACP, (BYTE)*(ptr-2)) ) return (LPSTR)(ptr-2); else return (LPSTR)(ptr-1); } /* WinCE doesn't have "drives". */ DWORD GetLogicalDrives(VOID) { return 0; } /* WinCE doesn't have "user name". */ BOOL GetUserName(LPSTR lpBuffer, LPDWORD nSize) { return 0; } /*------------------- LoadLibrary -----------------------*/ HINSTANCE LoadLibraryA(LPCSTR libname) { HINSTANCE h; LPWSTR wlibname; // if starts ".\", replace current directory. // wlibname = wce_replaceRelativeDir(libname); wlibname = wce_mbtowc(libname); h = LoadLibraryW(wlibname); free(wlibname); return h; } HINSTANCE LoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) { HINSTANCE h; LPWSTR wlibname; wlibname = wce_mbtowc(lpLibFileName); // wlibname = wce_replaceRelativeDir(lpLibFileName); #if _WIN32_WCE < 300 h = LoadLibraryW(wlibname); #else h = LoadLibraryExW(wlibname, hFile, dwFlags); #endif free(wlibname); return h; } /* WinCE doesn't have "CreatePipe". */ BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize) { return FALSE; } /* WinCE doesn't have "Standard Devices". */ HANDLE GetStdHandle(DWORD nStdHandle) { return NULL; } BOOL SetStdHandle(DWORD nStdHandle, HANDLE h) { return FALSE; } #if _WIN32_WCE < 300 VOID ZeroMemory(PVOID p, DWORD length) { memset(p,0,length); } #endif /* need in ruby/io.c. */ int ReadDataPending() { return 0; } /*---------------- helper functions. ---------------------------- */ FILE *wce_fopen( const char *fname, const char *mode ) { TCHAR* tfname = wce_replaceRelativeDir(fname); TCHAR* tmode = wce_mbtowc(mode); FILE* fp = _tfopen(tfname, tmode); free(tfname); free(tmode); return fp; } void wce_SetCurrentDir() { WCHAR tbuf[MAX_PATH+1]={0}; WCHAR *tp; char *buf; GetModuleFileNameW( NULL, tbuf, MAX_PATH ); tp = _tcsrchr( tbuf, '\\' ); if( tp!=NULL ) *tp=_T('\0'); buf = wce_wctomb(tbuf); strcpy( _currentdir, buf ); free(buf); } TCHAR *wce_replaceRelativeDir(const char* str) { TCHAR *tbuf; if( 2<=strlen(str) && str[0]=='.' && (str[1]=='/' || str[1]=='\\') ) { char *buf; int len = strlen(str) + strlen(_currentdir); buf = malloc( len+1 ); sprintf(buf, "%s%s", _currentdir, &str[1]); tbuf = wce_mbtowc(buf); free(buf); } else tbuf = wce_mbtowc(str); return tbuf; } /* char -> wchar_t */ wchar_t* wce_mbtowc(const char* a) { int length; wchar_t *wbuf; length = MultiByteToWideChar(CP_ACP, 0, a, -1, NULL, 0); wbuf = (wchar_t*)malloc( (length+1)*sizeof(wchar_t) ); MultiByteToWideChar(CP_ACP, 0, a, -1, wbuf, length); return wbuf; } /* wchar_t -> char */ char* wce_wctomb(const wchar_t* w) { DWORD charlength; char* pChar; charlength = WideCharToMultiByte(CP_ACP, 0, w, -1, NULL, 0, NULL, NULL); pChar = (char*)malloc(charlength+1); WideCharToMultiByte(CP_ACP, 0, w, -1, pChar, charlength, NULL, NULL); return pChar; } ================================================ FILE: wince/wince.h ================================================ #ifndef _EXT_CE_ #define _EXT_CE_ /* unique difinition in wince platform. */ #ifndef _MIPS_ #define CONTEXT_FLOATING_POINT 0x00000002L #endif /* LockFile difinition. */ #define LOCKFILE_FAIL_IMMEDIATELY 0x00000001 #define LOCKFILE_EXCLUSIVE_LOCK 0x00000002 /* Dual Mode difinition. */ #define STARTF_USESHOWWINDOW 0x00000001 #define STARTF_USESIZE 0x00000002 #define STARTF_USEPOSITION 0x00000004 #define STARTF_USECOUNTCHARS 0x00000008 #define STARTF_USEFILLATTRIBUTE 0x00000010 #define STARTF_RUNFULLSCREEN 0x00000020 #define STARTF_FORCEONFEEDBACK 0x00000040 #define STARTF_FORCEOFFFEEDBACK 0x00000080 #define STARTF_USESTDHANDLES 0x00000100 /* #define STARTF_USEHOTKEY 0x00000200 */ #define STD_INPUT_HANDLE (DWORD)-10 #define STD_OUTPUT_HANDLE (DWORD)-11 #define STD_ERROR_HANDLE (DWORD)-12 #define NORMAL_PRIORITY_CLASS 0x00000020 #define IDLE_PRIORITY_CLASS 0x00000040 #define HIGH_PRIORITY_CLASS 0x00000080 #define REALTIME_PRIORITY_CLASS 0x00000100 /* WINSOCK.H? */ #define SO_SYNCHRONOUS_NONALERT 0x20 /* MoveFileEx definition. */ #define MOVEFILE_REPLACE_EXISTING 0x00000001 /* #define MOVEFILE_COPY_ALLOWED 0x00000002 #define MOVEFILE_DELAY_UNTIL_REBOOT 0x00000004 #define MOVEFILE_WRITE_THROUGH 0x00000008 #define MOVEFILE_CREATE_HARDLINK 0x00000010 #define MOVEFILE_FAIL_IF_NOT_TRACKABLE 0x00000020 */ #define _fgetc fgetc #define _fputc fputc #ifdef __cplusplus extern "C" { #endif /* Win32 API redifinition. */ #undef GetCommandLine #define GetCommandLine GetCommandLineA #undef SetFileAttributes #define SetFileAttributes SetFileAttributesA #undef GetFileAttributes #define GetFileAttributes GetFileAttributesA #undef FormatMessage #define FormatMessage FormatMessageA #undef GetModuleFileName #define GetModuleFileName GetModuleFileNameA #undef CreateFile #define CreateFile CreateFileA #undef MoveFile #define MoveFile MoveFileA #undef DeleteFile #define DeleteFile DeleteFileA #undef CreateProcess #define CreateProcess CreateProcessA #undef CharNext #define CharNext CharNextA #undef CharPrev #define CharPrev CharPrevA #undef WIN32_FIND_DATA #define WIN32_FIND_DATA WIN32_FIND_DATAA #undef FindFirstFile #define FindFirstFile FindFirstFileA #undef FindNextFile #define FindNextFile FindNextFileA /* stdio.c */ FILE *freopen(const char *filename, const char *mode, FILE *file); FILE *fdopen( int handle, const char *mode ); //#define fdopen _fdopen /* stdlib.c */ char *getenv(const char *charstuff); char *_fullpath(char *absPath, const char *relPath, size_t maxLength); /* string.c */ char *strdup(const char * str); /* char *strerror(int errno); */ int strnicmp( const char *s1, const char *s2, size_t count ); //#define strnicmp _strnicmp #define stricmp _stricmp /* for win32.c */ FARPROC GetProcAddressX(HMODULE hModule, LPCSTR lpProcName); BOOL MoveFileEx(LPCSTR oldname, LPCSTR newname, DWORD dwFlags); BOOL DuplicateHandle( HANDLE source_process, HANDLE source, HANDLE dest_process, HANDLE *dest, DWORD access, BOOL inherit, DWORD options); BOOL LockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh); BOOL LockFileEx(HANDLE hFile, DWORD dwFlags, DWORD dwReserved, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped); BOOL UnlockFile( HFILE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh); BOOL UnlockFileEx(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped); BOOL GetUserName(LPSTR lpBuffer, LPDWORD nSize); BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize); HANDLE GetStdHandle(DWORD nStdHandle); BOOL SetStdHandle(DWORD nStdHandle, HANDLE h); DWORD GetLogicalDrives(VOID); DWORD WaitForMultipleObjectsEx(DWORD count, const HANDLE *handles, BOOL wait_all, DWORD timeout, BOOL alertable); DWORD GetEnvironmentVariable(LPCSTR name, LPSTR value, DWORD size); LPVOID GetEnvironmentStrings(VOID); BOOL FreeEnvironmentStrings(LPSTR lpszEnvironmentBlock); BOOL GenerateConsoleCtrlEvent(DWORD dwCtrlEvent, DWORD dwProcessGroupID); BOOL GetProcessTimes(HANDLE hprocess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime); /* char -> wchar_t, wchar_t -> char */ wchar_t* wce_mbtowc(const char* a); char* wce_wctomb(const wchar_t* w); /* other helpers. */ void wce_SetCommandLine(LPCWSTR wcmd); void wce_FreeCommandLine(void); TCHAR *wce_replaceRelativeDir(const char* str); void wce_SetCurrentDir(); #if _WIN32_WCE < 300 /* for Handheld PC Pro. */ char *strrchr( const char *p, int c ); int stricmp( const char *p1, const char *p2 ); VOID ZeroMemory(PVOID p, DWORD length); #define isascii(c) ( (c>=0x00&&c<=0x7f)?1:0 ) #define isspace(c) ( ((c>=0x09&&c<=0x0d)||c==0x20)?1:0 ) #define isdigit(c) ( (c>=0x00&&c<=0x09)?1:0 ) #define isupper(c) ( (c>='A'&&c<='Z')?1:0 ) #define isalpha(c) ( ((c>='A'&&c<='Z')||(c>='a'&&c<='z'))?1:0 ) #define isprint(c) ( (c>=0x20&&c<=0x7e)?1:0 ) #define isalnum(c) ( (isalpha(c)||isdigit(c))?1:0 ) #define iscntrl(c) ( ((c>=0x00&&c<=0x1f)||c==0x7f)?1:0 ) #define islower(c) ( (c>='a'&&c<='z')?1:0 ) #define ispunct(c) ( !(isalnum(c)||isspace(c))?1:0 ) #define isxdigit(c) ( ((c>=0&&c<=9)||(c>='A'&&c<='F')||(c>='a'&&c<='f'))?1:0 ) #endif #ifdef __cplusplus }; #endif #endif /* _EXT_CE_ */ ================================================ FILE: wince/wincemain.c ================================================ #include #include #include "wince.h" extern int main(int, char**, char**); int WINAPI WinMain(HINSTANCE current, HINSTANCE prev, LPWSTR wcmd, int showcmd) { /* wchar_t -> char */ wce_SetCommandLine(wcmd); wce_SetCurrentDir(); /* main. */ return main(0, NULL, NULL); } ================================================ FILE: wince/wincon.h ================================================ #ifndef _WINCON_H_ #define _WINCON_H_ #define CTRL_C_EVENT 0 #endif ================================================ FILE: wince/winsock2.c ================================================ /*************************************************************** winsock2.c ***************************************************************/ //#define _WINSOCK2_C_DEBUG_MAIN_ #include #include "wince.h" #ifdef _WINSOCK2_C_DEBUG_MAIN_ #include #endif #ifndef _WINSOCK2_C_DEBUG_MAIN_ struct servent{ char* s_name; /* official service name */ char** s_aliases; /* alias list */ short s_port; /* port # */ char* s_proto; /* protocol to use */ }; struct protoent{ char* p_name; /* official protocol name */ char** p_aliases; /* alias list */ short p_proto; /* protocol # */ }; #endif struct sproto{ short num; char name[10]; }; struct sserv{ short num; char protoname[10]; char servname[20]; }; static struct sproto _proto_table[11]={ 0, "ip", 1, "icmp", 3, "ggp", 6, "tcp", 8, "egp", 12, "pup", 17, "udp", 20, "hmp", 22, "xns-idp", 27, "rdp", 66, "rvd", }; static struct sserv _serv_table[142]={ 7, "tcp", "echo", 7, "udp", "echo", 9, "tcp", "discard", 9, "udp", "discard", 11, "tcp", "systat", 11, "udp", "systat", 13, "tcp", "daytime", 13, "udp", "daytime", 15, "tcp", "netstat", 17, "tcp", "qotd", 17, "udp", "qotd", 19, "tcp", "chargen", 19, "udp", "chargen", 20, "tcp", "ftp-data", 21, "tcp", "ftp", 23, "tcp", "telnet", 25, "tcp", "smtp", 37, "tcp", "time", 37, "udp", "time", 39, "udp", "rlp", 42, "tcp", "name", 42, "udp", "name", 43, "tcp", "whois", 53, "tcp", "domain", 53, "udp", "domain", 53, "tcp", "nameserver", 53, "udp", "nameserver", 57, "tcp", "mtp", 67, "udp", "bootp", 69, "udp", "tftp", 77, "tcp", "rje", 79, "tcp", "finger", 87, "tcp", "link", 95, "tcp", "supdup", 101, "tcp", "hostnames", 102, "tcp", "iso-tsap", 103, "tcp", "dictionary", 103, "tcp", "x400", 104, "tcp", "x400-snd", 105, "tcp", "csnet-ns", 109, "tcp", "pop", 109, "tcp", "pop2", 110, "tcp", "pop3", 111, "tcp", "portmap", 111, "udp", "portmap", 111, "tcp", "sunrpc", 111, "udp", "sunrpc", 113, "tcp", "auth", 115, "tcp", "sftp", 117, "tcp", "path", 117, "tcp", "uucp-path", 119, "tcp", "nntp", 123, "udp", "ntp", 137, "udp", "nbname", 138, "udp", "nbdatagram", 139, "tcp", "nbsession", 144, "tcp", "NeWS", 153, "tcp", "sgmp", 158, "tcp", "tcprepo", 161, "tcp", "snmp", 162, "tcp", "snmp-trap", 170, "tcp", "print-srv", 175, "tcp", "vmnet", 315, "udp", "load", 400, "tcp", "vmnet0", 500, "udp", "sytek", 512, "udp", "biff", 512, "tcp", "exec", 513, "tcp", "login", 513, "udp", "who", 514, "tcp", "shell", 514, "udp", "syslog", 515, "tcp", "printer", 517, "udp", "talk", 518, "udp", "ntalk", 520, "tcp", "efs", 520, "udp", "route", 525, "udp", "timed", 526, "tcp", "tempo", 530, "tcp", "courier", 531, "tcp", "conference", 531, "udp", "rvd-control", 532, "tcp", "netnews", 533, "udp", "netwall", 540, "tcp", "uucp", 543, "tcp", "klogin", 544, "tcp", "kshell", 550, "udp", "new-rwho", 556, "tcp", "remotefs", 560, "udp", "rmonitor", 561, "udp", "monitor", 600, "tcp", "garcon", 601, "tcp", "maitrd", 602, "tcp", "busboy", 700, "udp", "acctmaster", 701, "udp", "acctslave", 702, "udp", "acct", 703, "udp", "acctlogin", 704, "udp", "acctprinter", 704, "udp", "elcsd", 705, "udp", "acctinfo", 706, "udp", "acctslave2", 707, "udp", "acctdisk", 750, "tcp", "kerberos", 750, "udp", "kerberos", 751, "tcp", "kerberos_master", 751, "udp", "kerberos_master", 752, "udp", "passwd_server", 753, "udp", "userreg_server", 754, "tcp", "krb_prop", 888, "tcp", "erlogin", 1109, "tcp", "kpop", 1167, "udp", "phone", 1524, "tcp", "ingreslock", 1666, "udp", "maze", 2049, "udp", "nfs", 2053, "tcp", "knetd", 2105, "tcp", "eklogin", 5555, "tcp", "rmt", 5556, "tcp", "mtb", 9535, "tcp", "man", 9536, "tcp", "w", 9537, "tcp", "mantst", 10000, "tcp", "bnews", 10000, "udp", "rscs0", 10001, "tcp", "queue", 10001, "udp", "rscs1", 10002, "tcp", "poker", 10002, "udp", "rscs2", 10003, "tcp", "gateway", 10003, "udp", "rscs3", 10004, "tcp", "remp", 10004, "udp", "rscs4", 10005, "udp", "rscs5", 10006, "udp", "rscs6", 10007, "udp", "rscs7", 10008, "udp", "rscs8", 10009, "udp", "rscs9", 10010, "udp", "rscsa", 10011, "udp", "rscsb", 10012, "tcp", "qmaster", 10012, "udp", "qmaster", }; /* WinCE doesn't have /etc/protocols. */ struct protoent* getprotobyname(const char* name) { static struct protoent pe; int i; int len = strlen(name); memset( &pe, 0, sizeof(struct protoent) ); for(i=0; i<9; i++) { if( 0==strnicmp(_proto_table[i].name, name, len) ) { pe.p_name = _proto_table[i].name; pe.p_proto= _proto_table[i].num; break; } } return &pe; } struct protoent* getprotobynumber(int proto) { static struct protoent pe={0}; int i; memset( &pe, 0, sizeof(struct protoent) ); for(i=0; i<9; i++) { if( proto == _proto_table[i].num ) { pe.p_name = _proto_table[i].name; pe.p_proto= _proto_table[i].num; break; } } return &pe; } /* WinCE doesn't have /etc/services. */ struct servent* getservbyname(const char* name, const char* proto) { static struct servent se; int i; int slen = strlen(name), plen = strlen(proto); memset( &se, 0, sizeof(struct servent) ); if( proto==NULL ) return NULL; if( 0!=strnicmp( proto, "tcp", 3 ) && 0!=strnicmp( proto, "udp", 3 ) ) return NULL; for( i=0; i<142; i++ ) { if( 0==strnicmp( name, _serv_table[i].servname, slen ) && 0==strnicmp( proto, _serv_table[i].protoname, plen ) ) { char hc, lc; se.s_name = _serv_table[i].servname; se.s_proto= _serv_table[i].protoname; hc = (_serv_table[i].num&0xFF00)>>8; lc = _serv_table[i].num&0xFF; se.s_port = (lc<<8) + hc; break; } } return &se; } struct servent* getservbyport(int port, const char* proto) { static struct servent se; int i; int plen = strlen(proto); short sport; char lc, hc; hc = (port&0xFF00)>>8; lc = port&0xFF; sport = (lc<<8) + hc; memset( &se, 0, sizeof(struct servent) ); if( proto==NULL ) return NULL; if( 0!=strnicmp( proto, "tcp", 3 ) && 0!=strnicmp( proto, "udp", 3 ) ) return NULL; for( i=0; i<142; i++ ) { if( sport == _serv_table[i].num && 0==strnicmp( proto, _serv_table[i].protoname, plen ) ) { se.s_name = _serv_table[i].servname; se.s_proto= _serv_table[i].protoname; se.s_port = port; break; } } return &se; } #ifdef _WINSOCK2_C_DEBUG_MAIN_ int main() { WORD wVersionRequested = MAKEWORD(1,1); WSADATA wsaData; int nErrorStatus; struct protoent pe1, pe2; struct servent se1, se2; nErrorStatus = WSAStartup(wVersionRequested, &wsaData); if(nErrorStatus != 0) return -1; pe1 = *getprotobyname("UDP"); pe2 = *_getprotobyname("UDP"); // pe1 = *getprotobynumber(17); // pe2 = *_getprotobynumber(17); // se1 = *getservbyname("gateway", "tcp"); // se2 = *_getservbyname("gateway", "tcp"); se1 = *getservbyport(0x1327, "tcp"); se2 = *_getservbyport(0x1327, "tcp"); WSACleanup(); return 0; } #endif ================================================ FILE: x68/_dtos18.c ================================================ /* * PROJECT C Library, X68000 PROGRAMMING INTERFACE DEFINITION * -------------------------------------------------------------------- * This file is written by the Project C Library Group, and completely * in public domain. You can freely use, copy, modify, and redistribute * the whole contents, without this notice. * -------------------------------------------------------------------- * $Id$ */ /* System headers */ #include #include /* ** ܴؿưѴƤʸˤ뤿ᡢŪˤ ** ˳ǼǤޤǤȤǤʤäƺǹ ** 18Ǥ롣 */ /* File scope variables */ static double _pos1[32] = { 1.0e+17, /* + 0 */ 1.0e+18, /* + 1 */ 1.0e+19, /* + 2 */ 1.0e+20, /* + 3 */ 1.0e+21, /* + 4 */ 1.0e+22, /* + 5 */ 1.0e+23, /* + 6 */ 1.0e+24, /* + 7 */ 1.0e+25, /* + 8 */ 1.0e+26, /* + 9 */ 1.0e+27, /* +10 */ 1.0e+28, /* +11 */ 1.0e+29, /* +12 */ 1.0e+30, /* +13 */ 1.0e+31, /* +14 */ 1.0e+32, /* +15 */ 1.0e+33, /* +16 */ 1.0e+34, /* +17 */ 1.0e+35, /* +18 */ 1.0e+36, /* +19 */ 1.0e+37, /* +20 */ 1.0e+38, /* +21 */ 1.0e+39, /* +22 */ 1.0e+40, /* +23 */ 1.0e+41, /* +24 */ 1.0e+42, /* +25 */ 1.0e+43, /* +26 */ 1.0e+44, /* +27 */ 1.0e+45, /* +28 */ 1.0e+46, /* +29 */ 1.0e+47, /* +30 */ 1.0e+48, /* +31 */ }; /* File scope variables */ static double _neg1[32] = { 1.0e+17, /* - 0 */ 1.0e+16, /* - 1 */ 1.0e+15, /* - 2 */ 1.0e+14, /* - 3 */ 1.0e+13, /* - 4 */ 1.0e+12, /* - 5 */ 1.0e+11, /* - 6 */ 1.0e+10, /* - 7 */ 1.0e+9, /* - 8 */ 1.0e+8, /* - 9 */ 1.0e+7, /* -10 */ 1.0e+6, /* -11 */ 1.0e+5, /* -12 */ 1.0e+4, /* -13 */ 1.0e+3, /* -14 */ 1.0e+2, /* -15 */ 1.0e+1, /* -16 */ 1.0e+0, /* -17 */ 1.0e-1, /* -18 */ 1.0e-2, /* -19 */ 1.0e-3, /* -20 */ 1.0e-4, /* -21 */ 1.0e-5, /* -22 */ 1.0e-6, /* -23 */ 1.0e-7, /* -24 */ 1.0e-8, /* -25 */ 1.0e-9, /* -26 */ 1.0e-10, /* -27 */ 1.0e-11, /* -28 */ 1.0e-12, /* -29 */ 1.0e-13, /* -30 */ 1.0e-14, /* -31 */ }; /* File scope variables */ static double _pos2[10] = { 1.0e+0, /* 000 */ 1.0e+32, /* 001 */ 1.0e+64, /* 010 */ 1.0e+96, /* 011 */ 1.0e+128, /* 100 */ 1.0e+160, /* 101 */ 1.0e+192, /* 110 */ 1.0e+224, /* 111 */ 1.0e+256, /* 1000 */ 1.0e+288, /* 1001 */ }; /* File scope variables */ static double _neg2[10] = { 1.0e-0, /* 000 */ 1.0e-32, /* 001 */ 1.0e-64, /* 010 */ 1.0e-96, /* 011 */ 1.0e-128, /* 100 */ 1.0e-160, /* 101 */ 1.0e-192, /* 110 */ 1.0e-224, /* 111 */ 1.0e-256, /* 1000 */ 1.0e-288, /* 1001 */ }; /* File scope functions */ static int _cmpd (double x, double y) { unsigned long vx, vy, rc; unsigned long *x_ptr = (unsigned long *) &x; unsigned long *y_ptr = (unsigned long *) &y; /* xλؿӥåȤФ */ vx = x_ptr[0] & 0x7FF00000; /* yλؿӥåȤФ */ vy = y_ptr[0] & 0x7FF00000; /* ؿӥåȤȽǤ */ if ((rc = vy - vx) != 0) return rc; /* xͭξ̥ӥåȤФ */ vx = x_ptr[0] & 0x000FFFFF; /* yͭξ̥ӥåȤФ */ vy = y_ptr[0] & 0x000FFFFF; /* ̥ӥåȤȽǤ */ if ((rc = vy - vx) != 0) return rc; /* xͭβ̥ӥåȤФ */ vx = x_ptr[1]; /* yͭβ̥ӥåȤФ */ vy = y_ptr[1]; /* ǽȽ */ return vy - vx; } /* Functions */ void _dtos18 (double x, int *decpt, int *sign, char *buffer) { short e2; int e, n; /* 2λؿ(Хʤξ) */ e2 = (((unsigned short *) &x)[0] & 0x7FF0U) >> 4; /* ؿ0ξϡ0.0å */ if (e2 == 0) { unsigned long hi = ((unsigned long *) &x)[0] & 0xFFFFF; unsigned long lo = ((unsigned long *) &x)[1]; /* ͭ0ɤ */ if (hi == 0 && lo == 0) { /* ʸ */ buffer[0] = '0'; /* NUL */ buffer[1] = '\0'; /* ֤׻ */ *decpt = 1; /* ׻ */ /* *sign = hi & 0x80000000UL; */ *sign = 0; /* */ return; } } /* 2λؿ˥Х򤫤Ƥ10λؿ򳵻 (approx. log10(2)) */ e = ((int) ((e2 - 1023) * 77)) >> 8; /* ؿξ */ if (e >= 0) { /* ؿ32꾮ϥơ֥1 */ if (e < 32) x *= _neg1[e]; /* ؿ32礭ϥơ֥1,2 */ else x *= _neg1[e & 31] * _neg2[e >> 5]; } /* ؿξ */ else { /* ͤ׻ */ n = -e; /* ͤ32꾮ϥơ֥1 */ if (n < 32) x *= _pos1[n]; /* ͤ32礭ϥơ֥1,2 */ else { x *= _pos1[n & 31]; x *= _pos2[n >> 5]; } } /* 󥰤᤹ */ if (_cmpd (1.0e+18, x) >= 0) { e++; x *= 1.0e-1; } /* 󥰤­ʤɲ */ else if (_cmpd (1.0e+17, x) < 0) { e--; x *= 1.0e+1; } /* ֤׻ */ *decpt = e + 1; /* ׻ */ *sign = ((unsigned char *) &x)[0] & 0x80U; /* ʸѴ */ _ulltoa ((unsigned long long) x, buffer); } ================================================ FILE: x68/_round.c ================================================ /* * PROJECT C Library, X68000 PROGRAMMING INTERFACE DEFINITION * -------------------------------------------------------------------- * This file is written by the Project C Library Group, and completely * in public domain. You can freely use, copy, modify, and redistribute * the whole contents, without this notice. * -------------------------------------------------------------------- * $Id$ */ /* changed 1997.2.2 by K.Okabe */ /* System headers */ #include #include /* Functions */ int _round (char *top, char *cur, int undig) { char *ptr; /* Ǹ夬5̤ʤݤɬפʤ */ if (undig < '5') return 0; /* ݥ */ ptr = cur - 1; /* Ƭޤʤݤ */ while (ptr >= top) { /* 夬ʤФǽ */ if (++(*ptr) <= '9') return 0; /* η0᤹ */ *ptr-- = '0'; } /* Ƭ1ˤ */ *++ptr = '1'; /* 夬򤷤餻 */ return 1; } ================================================ FILE: x68/fconvert.c ================================================ /* * PROJECT C Library, X68000 PROGRAMMING INTERFACE DEFINITION * -------------------------------------------------------------------- * This file is written by the Project C Library Group, and completely * in public domain. You can freely use, copy, modify, and redistribute * the whole contents, without this notice. * -------------------------------------------------------------------- * $Id$ */ /* changed 1997.2.3 by K.Okabe */ /* System headers */ #include #include /* Functions */ char *fconvert (double x, int ndigit, int *decpt, int *sign, char *buffer) { int pos, n; char *src, *dst; char string[24]; int figup; /* 18ʸѴ */ _dtos18 (x, decpt, sign, string); /* ԡɥ쥹 */ src = string; /* ԡ襢ɥ쥹 */ dst = buffer; /* ֤ */ pos = *decpt; /* ֤ʤ */ if (pos < 0) { /* ׻ */ n = min (-pos, ndigit); /* Ƭ0 */ while (n-- > 0) *dst++ = '0'; /* ֤0ˤʤ */ *decpt = 0; } /* ĤΥԡ */ n = ndigit + pos; /* Ǽ˥ԡ */ while (n-- > 0) { /* ­ʤʬ0 */ if (*src == '\0') { while (n-- >= 0) *dst++ = '0'; break; } /* Ѵʸ󤫤饳ԡ */ *dst++ = *src++; } /* ݤ */ *decpt += (figup = _round (buffer, dst, *src)); /* 夬꤬0ɲä */ if (figup) *dst++ = '0'; /* ü NUL Ǥ */ *dst = '\0'; /* ɥ쥹֤ */ return buffer; } ================================================ FILE: x68/select.c ================================================ /* * PROJECT C Library, X68000 PROGRAMMING INTERFACE DEFINITION * -------------------------------------------------------------------- * This file is written by the Project C Library Group, and completely * in public domain. You can freely use, copy, modify, and redistribute * the whole contents, without this notice. * -------------------------------------------------------------------- * $Id$ */ #ifndef __IOCS_INLINE__ #define __IOCS_INLINE__ #define __DOS_INLINE__ #define __DOS_DOSCALL__ #endif /* System headers */ #include #include #include #include #include #include #include #if 0 #include #include #endif #include /* Macros */ #define XFD_ISSET(fd,fds) ((fds) && FD_ISSET ((fd), (fds))) #define isreadable(mode) ((mode) == O_RDONLY || (mode) == O_RDWR) #define iswritable(mode) ((mode) == O_WRONLY || (mode) == O_RDWR) #ifndef _POSIX_FD_SETSIZE #define _POSIX_FD_SETSIZE OPEN_MAX #endif /* Functions */ int select (int fds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) { fd_set oread, owrite, oexcept; int ticks, start; int nfds; if (fds > _POSIX_FD_SETSIZE) { errno = EINVAL; return -1; } FD_ZERO (&oread); FD_ZERO (&owrite); FD_ZERO (&oexcept); nfds = 0; ticks = -1; if (timeout) { ticks = timeout->tv_sec * 100 + timeout->tv_usec / 10000; if (ticks < 0) { errno = EINVAL; return -1; } } start = _iocs_ontime (); for (;;) { { int fd; for (fd = 0; fd < fds; fd++) { int accmode; if (_fddb[fd].inuse == _FD_NOTUSED) continue; accmode = _fddb[fd].oflag & O_ACCMODE; if (isatty (fd)) { if (XFD_ISSET (fd, rfds) && isreadable (accmode) && _dos_k_keysns ()) { FD_SET (fd, &oread); nfds++; } if (XFD_ISSET (fd, wfds) && iswritable (accmode)) { FD_SET (fd, &owrite); nfds++; } } #if 0 else if (_fddb[fd].sockno >= 0) { if (XFD_ISSET (fd, rfds) && _socklen (_fddb[fd].sockno, 0)) { FD_SET (fd, &oread); nfds++; } if (XFD_ISSET (fd, wfds) /* && _socklen (_fddb[fd].sockno, 1) == 0 */) { FD_SET (fd, &owrite); nfds++; } } #endif else { if (XFD_ISSET (fd, rfds) && isreadable (accmode) && _dos_ioctrlis (fd)) { FD_SET (fd, &oread); nfds++; } if (XFD_ISSET (fd, wfds) && iswritable (accmode) && _dos_ioctrlos (fd)) { FD_SET (fd, &owrite); nfds++; } } } } { int rest; if ((rest = (_iocs_ontime () - start) % 8640000) < 0) rest += 8640000; if (nfds != 0) { if (ticks >= 0) { int left; if ((left = ticks - rest) < 0) left = 0; timeout->tv_sec = left / 100; timeout->tv_usec = (left % 100) * 10000; } if (rfds) *rfds = oread; if (wfds) *wfds = owrite; if (efds) *efds = oexcept; return nfds; } if (ticks >= 0 && rest > ticks) return 0; } _dos_change_pr (); } }